diff --git a/Doxyfile b/Doxyfile new file mode 100644 index 000000000..a294fe0ff --- /dev/null +++ b/Doxyfile @@ -0,0 +1,1844 @@ +# Doxyfile 1.8.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 = acl + +# 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 = 1.0.0.0 + +# 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 = + +# 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 = help + +# 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 = Chinese + +# 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 = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# 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. Note that you specify absolute paths here, but also +# relative paths, which will be relative from the directory where doxygen is +# started. + +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 = YES + +# 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 = NO + +# 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 = YES + +# 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 + +# When enabled doxygen tries to link words that correspond to documented classes, +# or namespaces to their corresponding documentation. Such a link can be +# prevented in individual cases by by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. + +AUTOLINK_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 = YES + +# 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 = YES + +# 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 = NO + +# 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. + +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 = *.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 + +# 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 = YES + +# 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 = YES + +# 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 = NO + +# 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 = YES + +# 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 = YES + +# 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 left blank doxygen will +# generate a default style sheet. Note that it is recommended to use +# HTML_EXTRA_STYLESHEET instead of this one, as it is more robust and this +# tag will in the future become obsolete. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional +# user-defined cascading style sheet that is included after the standard +# style sheets created by doxygen. Using this option one can overrule +# certain style aspects. This is preferred over using HTML_STYLESHEET +# since it does not replace the standard style sheet and is therefor more +# robust against future updates. Doxygen will copy the style sheet file to +# the output directory. + +HTML_EXTRA_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 = YES + +# 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 = acl_cpp_help.chm + +# 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 = YES + +# 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://www.mathjax.org/mathjax + +# 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 = YES + +#--------------------------------------------------------------------------- +# 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 = NO + +# 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 = NO + +# 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 = NO + +# 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 = YES + +#--------------------------------------------------------------------------- +# 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 = YES + +# 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 = YES + +# 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 = YES + +# 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 = NO + +# 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/Doxyfile_acl_protocol b/Doxyfile_acl_protocol new file mode 100644 index 000000000..4af9a37e2 --- /dev/null +++ b/Doxyfile_acl_protocol @@ -0,0 +1,1754 @@ +# Doxyfile 1.7.4 + +# 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 a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = acl + +# 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 = 2.1.2_5 + +# 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 = + +# 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 = E:\work\online_help\acl + +# 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 = Chinese + +# 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 = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# 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 = YES + +# 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 = NO + +# 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 = YES + +# 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 = + +# 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 = YES + +# 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 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 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 + +#--------------------------------------------------------------------------- +# 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_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 = NO + +# 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 = YES + +# 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 + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = 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. The 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 = + +#--------------------------------------------------------------------------- +# 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 = E:\work\online_help\acl\source\acl \ + E:\work\online_help\acl\source\protocol \ + E:\work\online_help\acl\source\samples \ + E:\work\online_help\acl\source\tls \ + E:\work\online_help\acl\source\dict \ + E:\work\online_help\acl\source\unit_test + +# 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. + +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 = *.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 + +# 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 +# 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. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used 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 = YES + +# 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 and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = NO + +# 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 adviced 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 +# stylesheet 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 stylesheet 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_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = 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. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = YES + +# 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 at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = 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 + +# 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. + +GENERATE_TREEVIEW = YES + +# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, +# and Class Hierarchy pages using a tree view instead of an ordered list. + +USE_INLINE_TREES = YES + +# 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 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.org site, so you can quickly see the result without installing +# MathJax, but it is strongly recommended to install a local copy of MathJax +# before deployment. + +MATHJAX_RELPATH = http://www.mathjax.org/mathjax + +# 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 = YES + +#--------------------------------------------------------------------------- +# 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 = NO + +# 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 + +#--------------------------------------------------------------------------- +# 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 stylesheet 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 = NO + +# 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. +# Optionally an initial location of the external documentation +# can be added for each tagfile. 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. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# 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 write a font called Helvetica to the output +# directory and reference it in 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 output directory to look for the +# FreeSans.ttf font (which doxygen will put there itself). If you specify a +# different font using DOT_FONTNAME you can set the path where dot +# can find it using this tag. + +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 +# 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 = YES + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = YES + +# 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 = YES + +# 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, SHOW_DIRECTORIES 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. + +DOT_IMAGE_FORMAT = png + +# 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 = YES + +# 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/Makefile b/Makefile new file mode 100644 index 000000000..f27eedb0d --- /dev/null +++ b/Makefile @@ -0,0 +1,184 @@ +SHELL = /bin/sh +OSNAME = $(shell uname -sm) +OSTYPE = $(shell uname -p) + +LIB_PATH = ./dist/lib +ACL_LIB = $(LIB_PATH) +PROTO_LIB = $(LIB_PATH) +DICT_LIB = $(LIB_PATH) +TLS_LIB = $(LIB_PATH) + +INC_PATH = ./dist/include +ACL_INC = $(INC_PATH)/acl +PROTO_INC = $(INC_PATH)/protocol +DICT_INC = $(INC_PATH)/dict +TLS_INC = $(INC_PATH)/tls + +RPATH = +DATE_NOW = 20`date +%y`.`date +%m`.`date +%d` +MAKE_ARGS = + +ifeq ($(findstring FreeBSD, $(OSNAME)), FreeBSD) + RPATH = freebsd +endif + +ifeq ($(findstring Linux, $(OSNAME)), Linux) + ifeq ($(findstring i686, $(OSTYPE)), i686) + RPATH = linux32 + endif + ifeq ($(findstring x86_64, $(OSTYPE)), x86_64) + RPATH = linux64 + endif + n = `cat /proc/cpuinfo | grep processor | wc -l` + MAKE_ARGS = -j $(n) +endif +ifeq ($(findstring SunOS, $(OSNAME)), SunOS) + ifeq ($(findstring i386, $(OSTYPE)), i386) + RPATH = sunos_x86 + endif +endif +############################################################################## + +.PHONY = check help all clean install uninstall uninstall_all build_bin build_src +VERSION = 2.1.2.8 + +help: + @(echo "usage: make help|all|clean|install|uninstall|uninstall_all|build_bin|build_src") +all: + @(cd lib_acl; make $(MAKE_ARGS)) + @(cd lib_protocol; make $(MAKE_ARGS)) + @(cd lib_acl_cpp; make $(MAKE_ARGS)) + @(cd lib_rpc; make $(MAKE_ARGS)) + @(cd unit_test; make $(MAKE_ARGS)) + @(cd samples; make) +# @(cd lib_dict; make $(MAKE_ARGS)) +# @(cd lib_tls; make $(MAKE_ARGS)) +clean: + @(cd lib_acl; make clean) + @(cd lib_protocol; make clean) + @(cd lib_acl_cpp; make clean) + @(cd lib_rpc; make clean) + @(cd unit_test; make clean) + @(cd samples; make clean) +# @(cd lib_dict; make clean) +# @(cd lib_tls; make clean) + +install: + @(echo "") + @(echo "begin copy file...") + cp -f lib_acl/master/acl_master ./dist/master/libexec/$(RPATH)/ + cp -f lib_acl/lib/lib_acl.a $(ACL_LIB)/$(RPATH)/ + cp -Rf lib_acl/include/* $(ACL_INC)/ + cp -f lib_protocol/lib/lib_protocol.a $(PROTO_LIB)/$(RPATH)/ + cp -Rf lib_protocol/include/* $(PROTO_INC)/ + cp -f lib_acl_cpp/lib/lib_acl_cpp.a $(ACL_LIB)/$(RPATH)/ + cp -Rf lib_acl_cpp/include/acl_cpp/* $(INC_PATH)/acl_cpp/ +# cp -f lib_dict/lib/lib_dict.a $(DICT_LIB)/$(RPATH)/ +# cp -Rf lib_dict/include/* $(DICT_INC)/ +# cp -f lib_tls/lib/lib_tls.a $(TLS_LIB)/$(RPATH)/ +# cp -Rf lib_tls/include/* $(TLS_INC)/ +uninstall: + @(echo "") + @(echo "begin remove file...") + rm -f ./dist/master/libexec/$(RPATH)/* + rm -f $(ACL_LIB)/$(RPATH)/lib_acl.a + rm -Rf $(ACL_INC)/* + rm -f $(PROTO_LIB)/$(RPATH)/lib_protocol.a + rm -Rf $(PROTO_INC)/* + rm -f $(ACL_LIB)/$(RPATH)/lib_acl_cpp.a + rm -Rf $(INC_PATH)/acl_cpp/* + rm -f $(DICT_LIB)/$(RPATH)/lib_dict.a + rm -Rf $(DICT_INC)/* + rm -f $(TLS_LIB)/$(RPATH)/lib_tls.a + rm -Rf $(TLS_INC)/* +uninstall_all: + @(echo "") + @(echo "begin remove all dist files ...") + rm -Rf $(ACL_INC)/* + rm -Rf $(PROTO_INC)/* + rm -Rf $(DICT_INC)/* + rm -Rf $(TLS_INC)/* + rm -f ./dist/master/libexec/linux32/* + rm -f ./dist/master/libexec/linux64/* + rm -f ./dist/master/libexec/sunos_x86/* + rm -f ./dist/master/libexec/freebsd/* + rm -f $(ACL_LIB)/linux32/*.a + rm -f $(ACL_LIB)/linux64/*.a + rm -f $(ACL_LIB)/sunos_x86/*.a + rm -f $(ACL_LIB)/freebsd/*.a + rm -f $(ACL_LIB)/win32/*.lib + rm -f $(ACL_LIB)/win32/*.dll + rm -f $(PROTO_LIB)/linux32/*.a + rm -f $(PROTO_LIB)/linux64/*.a + rm -f $(PROTO_LIB)/sunos_x86/*.a + rm -f $(PROTO_LIB)/freebsd/*.a + rm -f $(PROTO_LIB)/win32/*.lib + rm -f $(PROTO_LIB)/win32/*.dll + rm -f $(DICT_LIB)/linux32/*.a + rm -f $(DICT_LIB)/linux64/*.a + rm -f $(DICT_LIB)/sunos_x86/*.a + rm -f $(DICT_LIB)/freebsd/*.a + rm -f $(DICT_LIB)/win32/*.lib + rm -f $(DICT_LIB)/win32/*.dll + rm -f $(TLS_LIB)/linux32/*.a + rm -f $(TLS_LIB)/linux64/*.a + rm -f $(TLS_LIB)/sunos_x86/*.a + rm -f $(TLS_LIB)/freebsd/*.a + rm -f $(TLS_LIB)/win32/*.lib + rm -f $(TLS_LIB)/win32/*.dll + rm -f win32_build/vc/lib_acl/*.map + rm -f win32_build/vc/lib_acl/*.ilk + rm -f win32_build/vc/lib_protocol/*.map + rm -f win32_build/vc/lib_protocol/*.ilk +build_bin: + @(echo "please waiting ...") + @(echo "begin building bin release...") + @(rm -rf acl.bin) + @(echo "copy files ...") + @(cp -R dist acl.bin) + @(cp lib_acl/changes.txt acl.bin/include/acl/) + @(cp lib_protocol/changes.txt acl.bin/include/protocol/) + @(cp lib_dict/changes.txt acl.bin/include/dict/) + @(cp lib_tls/changes.txt acl.bin/include/tls/) + @(cp changes.txt acl.bin/) + @(echo "make tar package ...") + @(tar -cf acl.bin.tar acl.bin) + @(echo "make gzip package ...") + @(gzip -c acl.bin.tar > acl.bin.tgz) + @(rm acl.bin.tar) + @(rm -rf acl.bin) + @(echo "move acl.bin.tgz to ../acl$(VERSION).bin.$(DATE_NOW).tgz") + @(mv acl.bin.tgz ../acl$(VERSION).bin.$(DATE_NOW).tgz) +# @(echo "move acl.bin.tgz to ../acl$(VERSION).bin.tgz") +# @(mv acl.bin.tgz ../acl$(VERSION).bin.tgz) +build_src: clean uninstall_all + @(echo "begin building src release...") + @(rm -rf acl) + @(echo "copy files ...") + @(mkdir acl) + @(cp -R dist acl/) + @(cp -R lib_acl acl/) + @(cp -R lib_protocol acl/) + @(cp -R lib_dict acl/) + @(cp -R lib_tls acl/) + @(cp -R samples acl/) + @(cp -R unit_test acl/) + @(cp -R win32_build acl/) + @(cp -R lib acl/) + @(cp -R doc acl/) + @(cp Makefile acl/) + @(cp changes.txt acl/) + @(cp readme.txt acl/) + @(cp Doxyfile acl/) + @(echo "make tar package ...") + @(tar -cf acl.src.tar acl) + @(echo "make gzip package ...") + @(gzip -c acl.src.tar > acl.src.tgz) + @(rm acl.src.tar) + @(rm -rf acl) + @(echo "move acl.src.tgz to ../acl$(VERSION).src.$(DATE_NOW).tgz") + @(mv acl.src.tgz ../acl$(VERSION).src.$(DATE_NOW).tgz) +# @(echo "move acl.src.tgz to ../acl$(VERSION).src.tgz") +# @(mv acl.src.tgz ../acl$(VERSION).src.tgz) +check: + echo "TYPE=$(OSTYPE), OSNAME=$(OSNAME), RPATH=$(RPATH)" diff --git a/acl_cpp_vc2003.sln b/acl_cpp_vc2003.sln new file mode 100644 index 000000000..228b33e55 --- /dev/null +++ b/acl_cpp_vc2003.sln @@ -0,0 +1,700 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "socket_stream", "lib_acl_cpp\samples\socket_stream\socket_stream.vcproj", "{41FA5224-3315-4CDA-9C44-19085049F179}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mime", "lib_acl_cpp\samples\mime\mime.vcproj", "{52AA7352-CE48-4F60-B92D-1EB16A79FE54}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xml", "lib_acl_cpp\samples\xml\xml.vcproj", "{2DABFAD1-114B-4F96-9185-DC0C56A3662D}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "string", "lib_acl_cpp\samples\string\string.vcproj", "{C94BEF01-706C-49A7-9FF1-9D87FA5BB8E7}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fstream", "lib_acl_cpp\samples\fstream\fstream.vcproj", "{7680672C-4C9B-4BE8-8BAE-BB23B951AAA0}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mime_base64", "lib_acl_cpp\samples\mime_base64\mime_base64.vcproj", "{19CB30E5-2672-4A8B-96FB-9C42970CCF69}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mime_qp", "lib_acl_cpp\samples\mime_qp\mime_qp.vcproj", "{5DC79C83-9DE8-46B3-A172-8A4E3371878B}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "flock", "lib_acl_cpp\samples\flock\flock.vcproj", "{5F4063AD-B591-4C64-ADEA-609968A83550}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rfc2047", "lib_acl_cpp\samples\rfc2047\rfc2047.vcproj", "{503AFD46-DF2F-4D2B-8584-60AD2007D2BE}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "aio_server", "lib_acl_cpp\samples\aio_server\aio_server.vcproj", "{225D0BFA-64D7-4F8F-951E-36A494CF6178}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "aio_client", "lib_acl_cpp\samples\aio_client\aio_client.vcproj", "{9A04F86E-D4CB-45ED-9BB6-9939B9400B6F}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "winaio", "lib_acl_cpp\samples\winaio\winaio.vcproj", "{ADE6F714-BD52-432D-AB86-62FA59AB6746}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "aio_ipc", "lib_acl_cpp\samples\aio_ipc\aio_ipc.vcproj", "{956FA905-A77F-41FE-A4BE-C3BD3B5B3E83}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "aio_dns", "lib_acl_cpp\samples\aio_dns\aio_dns.vcproj", "{BE2DF8B2-2DCD-4F32-99B9-0B0CA24BFAD9}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "socket_client", "lib_acl_cpp\samples\socket_client\socket_client.vcproj", "{7DA0AC89-62E4-4D02-9BC5-C32E6846E168}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "http_client", "lib_acl_cpp\samples\http_client\http_client.vcproj", "{82B65DCB-D910-4B92-BFDF-15896A575861}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + {FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HttpClient", "lib_acl_cpp\samples\HttpClient\HttpClient.vcproj", "{C0A7DB86-EF13-4A3E-9F34-8950521C9675}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + {FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ssl_client", "lib_acl_cpp\samples\ssl_client\ssl_client.vcproj", "{B14C93A6-DABE-48F9-A78C-C94049B69984}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + {FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ssl_aio_client", "lib_acl_cpp\samples\ssl_aio_client\ssl_aio_client.vcproj", "{8CF882F1-3D3C-4233-BCA6-7F90E49B80BE}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "final_class", "lib_acl_cpp\samples\final_class\final_class.vcproj", "{840C2263-DF87-4FD2-8964-EF81B74695FE}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sqlite", "lib_acl_cpp\samples\sqlite\sqlite.vcproj", "{20013703-57CC-4821-BF24-129A12490435}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "db_service", "lib_acl_cpp\samples\db_service\db_service.vcproj", "{82C00ED0-AEF5-4E5B-9581-1EA052CBEA01}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "win_dbservice", "lib_acl_cpp\samples\win_dbservice\win_dbservice.vcproj", "{DC7E75E5-FE42-4529-9D9A-19D240B8727B}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "lib_acl_cpp\samples\zlib\zlib.vcproj", "{F6292B2C-2C57-40E1-805F-86D9FB1C3251}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mysql", "lib_acl_cpp\samples\mysql\mysql.vcproj", "{A804ECF6-59F0-4CCF-8D71-6E44CBCA2796}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "master_threads", "lib_acl_cpp\samples\master_threads\master_threads.vcproj", "{FA0EEABF-CC21-4A99-89AA-D0379175E55A}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "master_aio", "lib_acl_cpp\samples\master_aio\master_aio.vcproj", "{4B7C83E5-C34F-4C42-9A37-E5F33FBA2EA3}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "master_trigger", "lib_acl_cpp\samples\master_trigger\master_trigger.vcproj", "{80F0213B-A053-4420-BAF9-4657AD8473DA}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "master_proc", "lib_acl_cpp\samples\master_proc\master_proc.vcproj", "{B7EE43F4-7541-48A7-A066-DA60A55E67ED}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "http_client2", "lib_acl_cpp\samples\http_client2\http_client2.vcproj", "{BC32C5A1-CDE1-4872-9CE8-5F3A65D39680}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + {FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "json", "lib_acl_cpp\samples\json\json.vcproj", "{56199633-C345-4733-8292-A4F2D86AA847}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rfc822", "lib_acl_cpp\samples\rfc822\rfc822.vcproj", "{1B51538E-859A-46FE-B423-592D79DEEF63}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "http_servlet", "lib_acl_cpp\samples\http_servlet\http_servlet.vcproj", "{5A189A92-9AF4-49FC-ABF4-8220A26E46D0}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "http_mime", "lib_acl_cpp\samples\http_mime\http_mime.vcproj", "{A1BA7D3E-5434-4F98-87F2-78673B3EEEF1}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cgi", "lib_acl_cpp\samples\cgi\cgi.vcproj", "{864A7341-756C-4BF9-A16F-059FDD972D79}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cgi_upload", "lib_acl_cpp\samples\cgi_upload\cgi_upload.vcproj", "{A28B19ED-291C-47C8-BDD5-10BB038C371E}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rpc_download", "lib_acl_cpp\samples\rpc_download\rpc_download.vcproj", "{349F7822-A752-42F0-BB13-4A28497D68DF}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + {FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gui_rpc", "lib_acl_cpp\samples\gui_rpc\gui_rpc.vcproj", "{F37E8828-252D-4F3E-A5B6-E3770750042F}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "acl_cpp_test", "lib_acl_cpp\samples\acl_cpp_test\acl_cpp_test.vcproj", "{C8CED6EB-DCC8-4CEE-921F-3190C879B116}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "md5", "lib_acl_cpp\samples\md5\md5.vcproj", "{B8029C89-9870-4EE4-ADD0-E7852E0D1810}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "http_server", "lib_acl_cpp\samples\http_server\http_server.vcproj", "{8B7A7746-C678-4205-8EA7-492A097F524B}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + {FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lib_acl", "lib_acl\lib_acl_vc2003.vcproj", "{B40213C2-507C-4C7F-A6E1-B850C9BDC27B}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lib_protocol", "lib_protocol\lib_protocol_vc2003.vcproj", "{FE724EF7-3763-4E78-BDF5-BCBC075719FD}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lib_acl_cpp", "lib_acl_cpp\lib_acl_cpp_vc2003.vcproj", "{6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "singleton", "lib_acl_cpp\samples\singleton\singleton.vcproj", "{128791D9-6787-471C-9A0C-0DCAE53F4911}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "session", "lib_acl_cpp\samples\session\session.vcproj", "{90D013A0-4813-4BAB-8155-D175631A695E}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + {FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "beanstalk", "lib_acl_cpp\samples\beanstalk\beanstalk.vcproj", "{1509DA30-29B0-4B73-921A-BBBD9E5608BE}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + {FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "url_coder", "lib_acl_cpp\samples\url_coder\url_coder.vcproj", "{143ED97E-1EC6-4821-A5FA-A6728B69273E}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + {FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fs_benchmark", "lib_acl_cpp\samples\fs_benchmark\fs_benchmark.vcproj", "{02B1C8C9-0B52-491D-89D3-8B37CE3A4FE9}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + {FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "memcache_pool", "lib_acl_cpp\samples\memcache_pool\memcache_pool.vcproj", "{58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + {FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD} + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + DebugDll = DebugDll + Release = Release + Releasedll = Releasedll + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {41FA5224-3315-4CDA-9C44-19085049F179}.Debug.ActiveCfg = Debug|Win32 + {41FA5224-3315-4CDA-9C44-19085049F179}.Debug.Build.0 = Debug|Win32 + {41FA5224-3315-4CDA-9C44-19085049F179}.DebugDll.ActiveCfg = DebugDll|Win32 + {41FA5224-3315-4CDA-9C44-19085049F179}.DebugDll.Build.0 = DebugDll|Win32 + {41FA5224-3315-4CDA-9C44-19085049F179}.Release.ActiveCfg = Release|Win32 + {41FA5224-3315-4CDA-9C44-19085049F179}.Release.Build.0 = Release|Win32 + {41FA5224-3315-4CDA-9C44-19085049F179}.Releasedll.ActiveCfg = Releasedll|Win32 + {41FA5224-3315-4CDA-9C44-19085049F179}.Releasedll.Build.0 = Releasedll|Win32 + {52AA7352-CE48-4F60-B92D-1EB16A79FE54}.Debug.ActiveCfg = Debug|Win32 + {52AA7352-CE48-4F60-B92D-1EB16A79FE54}.Debug.Build.0 = Debug|Win32 + {52AA7352-CE48-4F60-B92D-1EB16A79FE54}.DebugDll.ActiveCfg = DebugDll|Win32 + {52AA7352-CE48-4F60-B92D-1EB16A79FE54}.DebugDll.Build.0 = DebugDll|Win32 + {52AA7352-CE48-4F60-B92D-1EB16A79FE54}.Release.ActiveCfg = Release|Win32 + {52AA7352-CE48-4F60-B92D-1EB16A79FE54}.Release.Build.0 = Release|Win32 + {52AA7352-CE48-4F60-B92D-1EB16A79FE54}.Releasedll.ActiveCfg = Releasedll|Win32 + {52AA7352-CE48-4F60-B92D-1EB16A79FE54}.Releasedll.Build.0 = Releasedll|Win32 + {2DABFAD1-114B-4F96-9185-DC0C56A3662D}.Debug.ActiveCfg = Debug|Win32 + {2DABFAD1-114B-4F96-9185-DC0C56A3662D}.Debug.Build.0 = Debug|Win32 + {2DABFAD1-114B-4F96-9185-DC0C56A3662D}.DebugDll.ActiveCfg = DebugDll|Win32 + {2DABFAD1-114B-4F96-9185-DC0C56A3662D}.DebugDll.Build.0 = DebugDll|Win32 + {2DABFAD1-114B-4F96-9185-DC0C56A3662D}.Release.ActiveCfg = Release|Win32 + {2DABFAD1-114B-4F96-9185-DC0C56A3662D}.Release.Build.0 = Release|Win32 + {2DABFAD1-114B-4F96-9185-DC0C56A3662D}.Releasedll.ActiveCfg = Releasedll|Win32 + {2DABFAD1-114B-4F96-9185-DC0C56A3662D}.Releasedll.Build.0 = Releasedll|Win32 + {C94BEF01-706C-49A7-9FF1-9D87FA5BB8E7}.Debug.ActiveCfg = Debug|Win32 + {C94BEF01-706C-49A7-9FF1-9D87FA5BB8E7}.Debug.Build.0 = Debug|Win32 + {C94BEF01-706C-49A7-9FF1-9D87FA5BB8E7}.DebugDll.ActiveCfg = DebugDll|Win32 + {C94BEF01-706C-49A7-9FF1-9D87FA5BB8E7}.DebugDll.Build.0 = DebugDll|Win32 + {C94BEF01-706C-49A7-9FF1-9D87FA5BB8E7}.Release.ActiveCfg = Release|Win32 + {C94BEF01-706C-49A7-9FF1-9D87FA5BB8E7}.Release.Build.0 = Release|Win32 + {C94BEF01-706C-49A7-9FF1-9D87FA5BB8E7}.Releasedll.ActiveCfg = Releasedll|Win32 + {C94BEF01-706C-49A7-9FF1-9D87FA5BB8E7}.Releasedll.Build.0 = Releasedll|Win32 + {7680672C-4C9B-4BE8-8BAE-BB23B951AAA0}.Debug.ActiveCfg = Debug|Win32 + {7680672C-4C9B-4BE8-8BAE-BB23B951AAA0}.Debug.Build.0 = Debug|Win32 + {7680672C-4C9B-4BE8-8BAE-BB23B951AAA0}.DebugDll.ActiveCfg = DebugDll|Win32 + {7680672C-4C9B-4BE8-8BAE-BB23B951AAA0}.DebugDll.Build.0 = DebugDll|Win32 + {7680672C-4C9B-4BE8-8BAE-BB23B951AAA0}.Release.ActiveCfg = Release|Win32 + {7680672C-4C9B-4BE8-8BAE-BB23B951AAA0}.Release.Build.0 = Release|Win32 + {7680672C-4C9B-4BE8-8BAE-BB23B951AAA0}.Releasedll.ActiveCfg = Releasedll|Win32 + {7680672C-4C9B-4BE8-8BAE-BB23B951AAA0}.Releasedll.Build.0 = Releasedll|Win32 + {19CB30E5-2672-4A8B-96FB-9C42970CCF69}.Debug.ActiveCfg = Debug|Win32 + {19CB30E5-2672-4A8B-96FB-9C42970CCF69}.Debug.Build.0 = Debug|Win32 + {19CB30E5-2672-4A8B-96FB-9C42970CCF69}.DebugDll.ActiveCfg = DebugDll|Win32 + {19CB30E5-2672-4A8B-96FB-9C42970CCF69}.DebugDll.Build.0 = DebugDll|Win32 + {19CB30E5-2672-4A8B-96FB-9C42970CCF69}.Release.ActiveCfg = Release|Win32 + {19CB30E5-2672-4A8B-96FB-9C42970CCF69}.Release.Build.0 = Release|Win32 + {19CB30E5-2672-4A8B-96FB-9C42970CCF69}.Releasedll.ActiveCfg = Releasedll|Win32 + {19CB30E5-2672-4A8B-96FB-9C42970CCF69}.Releasedll.Build.0 = Releasedll|Win32 + {5DC79C83-9DE8-46B3-A172-8A4E3371878B}.Debug.ActiveCfg = Debug|Win32 + {5DC79C83-9DE8-46B3-A172-8A4E3371878B}.Debug.Build.0 = Debug|Win32 + {5DC79C83-9DE8-46B3-A172-8A4E3371878B}.DebugDll.ActiveCfg = DebugDll|Win32 + {5DC79C83-9DE8-46B3-A172-8A4E3371878B}.DebugDll.Build.0 = DebugDll|Win32 + {5DC79C83-9DE8-46B3-A172-8A4E3371878B}.Release.ActiveCfg = Release|Win32 + {5DC79C83-9DE8-46B3-A172-8A4E3371878B}.Release.Build.0 = Release|Win32 + {5DC79C83-9DE8-46B3-A172-8A4E3371878B}.Releasedll.ActiveCfg = Releasedll|Win32 + {5DC79C83-9DE8-46B3-A172-8A4E3371878B}.Releasedll.Build.0 = Releasedll|Win32 + {5F4063AD-B591-4C64-ADEA-609968A83550}.Debug.ActiveCfg = Debug|Win32 + {5F4063AD-B591-4C64-ADEA-609968A83550}.Debug.Build.0 = Debug|Win32 + {5F4063AD-B591-4C64-ADEA-609968A83550}.DebugDll.ActiveCfg = DebugDll|Win32 + {5F4063AD-B591-4C64-ADEA-609968A83550}.DebugDll.Build.0 = DebugDll|Win32 + {5F4063AD-B591-4C64-ADEA-609968A83550}.Release.ActiveCfg = Release|Win32 + {5F4063AD-B591-4C64-ADEA-609968A83550}.Release.Build.0 = Release|Win32 + {5F4063AD-B591-4C64-ADEA-609968A83550}.Releasedll.ActiveCfg = Releasedll|Win32 + {5F4063AD-B591-4C64-ADEA-609968A83550}.Releasedll.Build.0 = Releasedll|Win32 + {503AFD46-DF2F-4D2B-8584-60AD2007D2BE}.Debug.ActiveCfg = Debug|Win32 + {503AFD46-DF2F-4D2B-8584-60AD2007D2BE}.Debug.Build.0 = Debug|Win32 + {503AFD46-DF2F-4D2B-8584-60AD2007D2BE}.DebugDll.ActiveCfg = DebugDll|Win32 + {503AFD46-DF2F-4D2B-8584-60AD2007D2BE}.DebugDll.Build.0 = DebugDll|Win32 + {503AFD46-DF2F-4D2B-8584-60AD2007D2BE}.Release.ActiveCfg = Release|Win32 + {503AFD46-DF2F-4D2B-8584-60AD2007D2BE}.Release.Build.0 = Release|Win32 + {503AFD46-DF2F-4D2B-8584-60AD2007D2BE}.Releasedll.ActiveCfg = Releasedll|Win32 + {503AFD46-DF2F-4D2B-8584-60AD2007D2BE}.Releasedll.Build.0 = Releasedll|Win32 + {225D0BFA-64D7-4F8F-951E-36A494CF6178}.Debug.ActiveCfg = Debug|Win32 + {225D0BFA-64D7-4F8F-951E-36A494CF6178}.Debug.Build.0 = Debug|Win32 + {225D0BFA-64D7-4F8F-951E-36A494CF6178}.DebugDll.ActiveCfg = DebugDll|Win32 + {225D0BFA-64D7-4F8F-951E-36A494CF6178}.DebugDll.Build.0 = DebugDll|Win32 + {225D0BFA-64D7-4F8F-951E-36A494CF6178}.Release.ActiveCfg = Release|Win32 + {225D0BFA-64D7-4F8F-951E-36A494CF6178}.Release.Build.0 = Release|Win32 + {225D0BFA-64D7-4F8F-951E-36A494CF6178}.Releasedll.ActiveCfg = Releasedll|Win32 + {225D0BFA-64D7-4F8F-951E-36A494CF6178}.Releasedll.Build.0 = Releasedll|Win32 + {9A04F86E-D4CB-45ED-9BB6-9939B9400B6F}.Debug.ActiveCfg = Debug|Win32 + {9A04F86E-D4CB-45ED-9BB6-9939B9400B6F}.Debug.Build.0 = Debug|Win32 + {9A04F86E-D4CB-45ED-9BB6-9939B9400B6F}.DebugDll.ActiveCfg = DebugDll|Win32 + {9A04F86E-D4CB-45ED-9BB6-9939B9400B6F}.DebugDll.Build.0 = DebugDll|Win32 + {9A04F86E-D4CB-45ED-9BB6-9939B9400B6F}.Release.ActiveCfg = Release|Win32 + {9A04F86E-D4CB-45ED-9BB6-9939B9400B6F}.Release.Build.0 = Release|Win32 + {9A04F86E-D4CB-45ED-9BB6-9939B9400B6F}.Releasedll.ActiveCfg = Releasedll|Win32 + {9A04F86E-D4CB-45ED-9BB6-9939B9400B6F}.Releasedll.Build.0 = Releasedll|Win32 + {ADE6F714-BD52-432D-AB86-62FA59AB6746}.Debug.ActiveCfg = Debug|Win32 + {ADE6F714-BD52-432D-AB86-62FA59AB6746}.Debug.Build.0 = Debug|Win32 + {ADE6F714-BD52-432D-AB86-62FA59AB6746}.DebugDll.ActiveCfg = DebugDll|Win32 + {ADE6F714-BD52-432D-AB86-62FA59AB6746}.DebugDll.Build.0 = DebugDll|Win32 + {ADE6F714-BD52-432D-AB86-62FA59AB6746}.Release.ActiveCfg = Release|Win32 + {ADE6F714-BD52-432D-AB86-62FA59AB6746}.Release.Build.0 = Release|Win32 + {ADE6F714-BD52-432D-AB86-62FA59AB6746}.Releasedll.ActiveCfg = Releasedll|Win32 + {ADE6F714-BD52-432D-AB86-62FA59AB6746}.Releasedll.Build.0 = Releasedll|Win32 + {956FA905-A77F-41FE-A4BE-C3BD3B5B3E83}.Debug.ActiveCfg = Debug|Win32 + {956FA905-A77F-41FE-A4BE-C3BD3B5B3E83}.Debug.Build.0 = Debug|Win32 + {956FA905-A77F-41FE-A4BE-C3BD3B5B3E83}.DebugDll.ActiveCfg = DebugDll|Win32 + {956FA905-A77F-41FE-A4BE-C3BD3B5B3E83}.DebugDll.Build.0 = DebugDll|Win32 + {956FA905-A77F-41FE-A4BE-C3BD3B5B3E83}.Release.ActiveCfg = Release|Win32 + {956FA905-A77F-41FE-A4BE-C3BD3B5B3E83}.Release.Build.0 = Release|Win32 + {956FA905-A77F-41FE-A4BE-C3BD3B5B3E83}.Releasedll.ActiveCfg = Releasedll|Win32 + {956FA905-A77F-41FE-A4BE-C3BD3B5B3E83}.Releasedll.Build.0 = Releasedll|Win32 + {BE2DF8B2-2DCD-4F32-99B9-0B0CA24BFAD9}.Debug.ActiveCfg = Debug|Win32 + {BE2DF8B2-2DCD-4F32-99B9-0B0CA24BFAD9}.Debug.Build.0 = Debug|Win32 + {BE2DF8B2-2DCD-4F32-99B9-0B0CA24BFAD9}.DebugDll.ActiveCfg = DebugDll|Win32 + {BE2DF8B2-2DCD-4F32-99B9-0B0CA24BFAD9}.DebugDll.Build.0 = DebugDll|Win32 + {BE2DF8B2-2DCD-4F32-99B9-0B0CA24BFAD9}.Release.ActiveCfg = Release|Win32 + {BE2DF8B2-2DCD-4F32-99B9-0B0CA24BFAD9}.Release.Build.0 = Release|Win32 + {BE2DF8B2-2DCD-4F32-99B9-0B0CA24BFAD9}.Releasedll.ActiveCfg = Releasedll|Win32 + {BE2DF8B2-2DCD-4F32-99B9-0B0CA24BFAD9}.Releasedll.Build.0 = Releasedll|Win32 + {7DA0AC89-62E4-4D02-9BC5-C32E6846E168}.Debug.ActiveCfg = Debug|Win32 + {7DA0AC89-62E4-4D02-9BC5-C32E6846E168}.Debug.Build.0 = Debug|Win32 + {7DA0AC89-62E4-4D02-9BC5-C32E6846E168}.DebugDll.ActiveCfg = DebugDll|Win32 + {7DA0AC89-62E4-4D02-9BC5-C32E6846E168}.DebugDll.Build.0 = DebugDll|Win32 + {7DA0AC89-62E4-4D02-9BC5-C32E6846E168}.Release.ActiveCfg = Release|Win32 + {7DA0AC89-62E4-4D02-9BC5-C32E6846E168}.Release.Build.0 = Release|Win32 + {7DA0AC89-62E4-4D02-9BC5-C32E6846E168}.Releasedll.ActiveCfg = ReleaseDll|Win32 + {7DA0AC89-62E4-4D02-9BC5-C32E6846E168}.Releasedll.Build.0 = ReleaseDll|Win32 + {82B65DCB-D910-4B92-BFDF-15896A575861}.Debug.ActiveCfg = Debug|Win32 + {82B65DCB-D910-4B92-BFDF-15896A575861}.Debug.Build.0 = Debug|Win32 + {82B65DCB-D910-4B92-BFDF-15896A575861}.DebugDll.ActiveCfg = DebugDll|Win32 + {82B65DCB-D910-4B92-BFDF-15896A575861}.DebugDll.Build.0 = DebugDll|Win32 + {82B65DCB-D910-4B92-BFDF-15896A575861}.Release.ActiveCfg = Release|Win32 + {82B65DCB-D910-4B92-BFDF-15896A575861}.Release.Build.0 = Release|Win32 + {82B65DCB-D910-4B92-BFDF-15896A575861}.Releasedll.ActiveCfg = ReleaseDll|Win32 + {82B65DCB-D910-4B92-BFDF-15896A575861}.Releasedll.Build.0 = ReleaseDll|Win32 + {C0A7DB86-EF13-4A3E-9F34-8950521C9675}.Debug.ActiveCfg = Debug|Win32 + {C0A7DB86-EF13-4A3E-9F34-8950521C9675}.Debug.Build.0 = Debug|Win32 + {C0A7DB86-EF13-4A3E-9F34-8950521C9675}.DebugDll.ActiveCfg = DebugDll|Win32 + {C0A7DB86-EF13-4A3E-9F34-8950521C9675}.DebugDll.Build.0 = DebugDll|Win32 + {C0A7DB86-EF13-4A3E-9F34-8950521C9675}.Release.ActiveCfg = Release|Win32 + {C0A7DB86-EF13-4A3E-9F34-8950521C9675}.Release.Build.0 = Release|Win32 + {C0A7DB86-EF13-4A3E-9F34-8950521C9675}.Releasedll.ActiveCfg = ReleaseDll|Win32 + {C0A7DB86-EF13-4A3E-9F34-8950521C9675}.Releasedll.Build.0 = ReleaseDll|Win32 + {B14C93A6-DABE-48F9-A78C-C94049B69984}.Debug.ActiveCfg = Debug|Win32 + {B14C93A6-DABE-48F9-A78C-C94049B69984}.Debug.Build.0 = Debug|Win32 + {B14C93A6-DABE-48F9-A78C-C94049B69984}.DebugDll.ActiveCfg = DebugDll|Win32 + {B14C93A6-DABE-48F9-A78C-C94049B69984}.DebugDll.Build.0 = DebugDll|Win32 + {B14C93A6-DABE-48F9-A78C-C94049B69984}.Release.ActiveCfg = Release|Win32 + {B14C93A6-DABE-48F9-A78C-C94049B69984}.Release.Build.0 = Release|Win32 + {B14C93A6-DABE-48F9-A78C-C94049B69984}.Releasedll.ActiveCfg = ReleaseDll|Win32 + {B14C93A6-DABE-48F9-A78C-C94049B69984}.Releasedll.Build.0 = ReleaseDll|Win32 + {8CF882F1-3D3C-4233-BCA6-7F90E49B80BE}.Debug.ActiveCfg = Debug|Win32 + {8CF882F1-3D3C-4233-BCA6-7F90E49B80BE}.Debug.Build.0 = Debug|Win32 + {8CF882F1-3D3C-4233-BCA6-7F90E49B80BE}.DebugDll.ActiveCfg = DebugDll|Win32 + {8CF882F1-3D3C-4233-BCA6-7F90E49B80BE}.DebugDll.Build.0 = DebugDll|Win32 + {8CF882F1-3D3C-4233-BCA6-7F90E49B80BE}.Release.ActiveCfg = Release|Win32 + {8CF882F1-3D3C-4233-BCA6-7F90E49B80BE}.Release.Build.0 = Release|Win32 + {8CF882F1-3D3C-4233-BCA6-7F90E49B80BE}.Releasedll.ActiveCfg = ReleaseDll|Win32 + {8CF882F1-3D3C-4233-BCA6-7F90E49B80BE}.Releasedll.Build.0 = ReleaseDll|Win32 + {840C2263-DF87-4FD2-8964-EF81B74695FE}.Debug.ActiveCfg = Debug|Win32 + {840C2263-DF87-4FD2-8964-EF81B74695FE}.Debug.Build.0 = Debug|Win32 + {840C2263-DF87-4FD2-8964-EF81B74695FE}.DebugDll.ActiveCfg = DebugDll|Win32 + {840C2263-DF87-4FD2-8964-EF81B74695FE}.DebugDll.Build.0 = DebugDll|Win32 + {840C2263-DF87-4FD2-8964-EF81B74695FE}.Release.ActiveCfg = Release|Win32 + {840C2263-DF87-4FD2-8964-EF81B74695FE}.Release.Build.0 = Release|Win32 + {840C2263-DF87-4FD2-8964-EF81B74695FE}.Releasedll.ActiveCfg = ReleaseDll|Win32 + {840C2263-DF87-4FD2-8964-EF81B74695FE}.Releasedll.Build.0 = ReleaseDll|Win32 + {20013703-57CC-4821-BF24-129A12490435}.Debug.ActiveCfg = Debug|Win32 + {20013703-57CC-4821-BF24-129A12490435}.Debug.Build.0 = Debug|Win32 + {20013703-57CC-4821-BF24-129A12490435}.DebugDll.ActiveCfg = DebugDll|Win32 + {20013703-57CC-4821-BF24-129A12490435}.DebugDll.Build.0 = DebugDll|Win32 + {20013703-57CC-4821-BF24-129A12490435}.Release.ActiveCfg = Release|Win32 + {20013703-57CC-4821-BF24-129A12490435}.Release.Build.0 = Release|Win32 + {20013703-57CC-4821-BF24-129A12490435}.Releasedll.ActiveCfg = ReleaseDll|Win32 + {20013703-57CC-4821-BF24-129A12490435}.Releasedll.Build.0 = ReleaseDll|Win32 + {82C00ED0-AEF5-4E5B-9581-1EA052CBEA01}.Debug.ActiveCfg = Debug|Win32 + {82C00ED0-AEF5-4E5B-9581-1EA052CBEA01}.Debug.Build.0 = Debug|Win32 + {82C00ED0-AEF5-4E5B-9581-1EA052CBEA01}.DebugDll.ActiveCfg = DebugDll|Win32 + {82C00ED0-AEF5-4E5B-9581-1EA052CBEA01}.DebugDll.Build.0 = DebugDll|Win32 + {82C00ED0-AEF5-4E5B-9581-1EA052CBEA01}.Release.ActiveCfg = Release|Win32 + {82C00ED0-AEF5-4E5B-9581-1EA052CBEA01}.Release.Build.0 = Release|Win32 + {82C00ED0-AEF5-4E5B-9581-1EA052CBEA01}.Releasedll.ActiveCfg = ReleaseDll|Win32 + {82C00ED0-AEF5-4E5B-9581-1EA052CBEA01}.Releasedll.Build.0 = ReleaseDll|Win32 + {DC7E75E5-FE42-4529-9D9A-19D240B8727B}.Debug.ActiveCfg = Debug|Win32 + {DC7E75E5-FE42-4529-9D9A-19D240B8727B}.Debug.Build.0 = Debug|Win32 + {DC7E75E5-FE42-4529-9D9A-19D240B8727B}.DebugDll.ActiveCfg = DebugDll|Win32 + {DC7E75E5-FE42-4529-9D9A-19D240B8727B}.DebugDll.Build.0 = DebugDll|Win32 + {DC7E75E5-FE42-4529-9D9A-19D240B8727B}.Release.ActiveCfg = Release|Win32 + {DC7E75E5-FE42-4529-9D9A-19D240B8727B}.Release.Build.0 = Release|Win32 + {DC7E75E5-FE42-4529-9D9A-19D240B8727B}.Releasedll.ActiveCfg = ReleaseDll|Win32 + {DC7E75E5-FE42-4529-9D9A-19D240B8727B}.Releasedll.Build.0 = ReleaseDll|Win32 + {F6292B2C-2C57-40E1-805F-86D9FB1C3251}.Debug.ActiveCfg = Debug|Win32 + {F6292B2C-2C57-40E1-805F-86D9FB1C3251}.Debug.Build.0 = Debug|Win32 + {F6292B2C-2C57-40E1-805F-86D9FB1C3251}.DebugDll.ActiveCfg = DebugDll|Win32 + {F6292B2C-2C57-40E1-805F-86D9FB1C3251}.DebugDll.Build.0 = DebugDll|Win32 + {F6292B2C-2C57-40E1-805F-86D9FB1C3251}.Release.ActiveCfg = Release|Win32 + {F6292B2C-2C57-40E1-805F-86D9FB1C3251}.Release.Build.0 = Release|Win32 + {F6292B2C-2C57-40E1-805F-86D9FB1C3251}.Releasedll.ActiveCfg = ReleaseDll|Win32 + {F6292B2C-2C57-40E1-805F-86D9FB1C3251}.Releasedll.Build.0 = ReleaseDll|Win32 + {A804ECF6-59F0-4CCF-8D71-6E44CBCA2796}.Debug.ActiveCfg = Debug|Win32 + {A804ECF6-59F0-4CCF-8D71-6E44CBCA2796}.Debug.Build.0 = Debug|Win32 + {A804ECF6-59F0-4CCF-8D71-6E44CBCA2796}.DebugDll.ActiveCfg = DebugDll|Win32 + {A804ECF6-59F0-4CCF-8D71-6E44CBCA2796}.DebugDll.Build.0 = DebugDll|Win32 + {A804ECF6-59F0-4CCF-8D71-6E44CBCA2796}.Release.ActiveCfg = Release|Win32 + {A804ECF6-59F0-4CCF-8D71-6E44CBCA2796}.Release.Build.0 = Release|Win32 + {A804ECF6-59F0-4CCF-8D71-6E44CBCA2796}.Releasedll.ActiveCfg = ReleaseDll|Win32 + {A804ECF6-59F0-4CCF-8D71-6E44CBCA2796}.Releasedll.Build.0 = ReleaseDll|Win32 + {FA0EEABF-CC21-4A99-89AA-D0379175E55A}.Debug.ActiveCfg = Debug|Win32 + {FA0EEABF-CC21-4A99-89AA-D0379175E55A}.Debug.Build.0 = Debug|Win32 + {FA0EEABF-CC21-4A99-89AA-D0379175E55A}.DebugDll.ActiveCfg = DebugDll|Win32 + {FA0EEABF-CC21-4A99-89AA-D0379175E55A}.DebugDll.Build.0 = DebugDll|Win32 + {FA0EEABF-CC21-4A99-89AA-D0379175E55A}.Release.ActiveCfg = Release|Win32 + {FA0EEABF-CC21-4A99-89AA-D0379175E55A}.Release.Build.0 = Release|Win32 + {FA0EEABF-CC21-4A99-89AA-D0379175E55A}.Releasedll.ActiveCfg = ReleaseDll|Win32 + {FA0EEABF-CC21-4A99-89AA-D0379175E55A}.Releasedll.Build.0 = ReleaseDll|Win32 + {4B7C83E5-C34F-4C42-9A37-E5F33FBA2EA3}.Debug.ActiveCfg = Debug|Win32 + {4B7C83E5-C34F-4C42-9A37-E5F33FBA2EA3}.Debug.Build.0 = Debug|Win32 + {4B7C83E5-C34F-4C42-9A37-E5F33FBA2EA3}.DebugDll.ActiveCfg = DebugDll|Win32 + {4B7C83E5-C34F-4C42-9A37-E5F33FBA2EA3}.DebugDll.Build.0 = DebugDll|Win32 + {4B7C83E5-C34F-4C42-9A37-E5F33FBA2EA3}.Release.ActiveCfg = Release|Win32 + {4B7C83E5-C34F-4C42-9A37-E5F33FBA2EA3}.Release.Build.0 = Release|Win32 + {4B7C83E5-C34F-4C42-9A37-E5F33FBA2EA3}.Releasedll.ActiveCfg = ReleaseDll|Win32 + {4B7C83E5-C34F-4C42-9A37-E5F33FBA2EA3}.Releasedll.Build.0 = ReleaseDll|Win32 + {80F0213B-A053-4420-BAF9-4657AD8473DA}.Debug.ActiveCfg = Debug|Win32 + {80F0213B-A053-4420-BAF9-4657AD8473DA}.Debug.Build.0 = Debug|Win32 + {80F0213B-A053-4420-BAF9-4657AD8473DA}.DebugDll.ActiveCfg = DebugDll|Win32 + {80F0213B-A053-4420-BAF9-4657AD8473DA}.DebugDll.Build.0 = DebugDll|Win32 + {80F0213B-A053-4420-BAF9-4657AD8473DA}.Release.ActiveCfg = Release|Win32 + {80F0213B-A053-4420-BAF9-4657AD8473DA}.Release.Build.0 = Release|Win32 + {80F0213B-A053-4420-BAF9-4657AD8473DA}.Releasedll.ActiveCfg = ReleaseDll|Win32 + {80F0213B-A053-4420-BAF9-4657AD8473DA}.Releasedll.Build.0 = ReleaseDll|Win32 + {B7EE43F4-7541-48A7-A066-DA60A55E67ED}.Debug.ActiveCfg = Debug|Win32 + {B7EE43F4-7541-48A7-A066-DA60A55E67ED}.Debug.Build.0 = Debug|Win32 + {B7EE43F4-7541-48A7-A066-DA60A55E67ED}.DebugDll.ActiveCfg = DebugDll|Win32 + {B7EE43F4-7541-48A7-A066-DA60A55E67ED}.DebugDll.Build.0 = DebugDll|Win32 + {B7EE43F4-7541-48A7-A066-DA60A55E67ED}.Release.ActiveCfg = Release|Win32 + {B7EE43F4-7541-48A7-A066-DA60A55E67ED}.Release.Build.0 = Release|Win32 + {B7EE43F4-7541-48A7-A066-DA60A55E67ED}.Releasedll.ActiveCfg = ReleaseDll|Win32 + {B7EE43F4-7541-48A7-A066-DA60A55E67ED}.Releasedll.Build.0 = ReleaseDll|Win32 + {BC32C5A1-CDE1-4872-9CE8-5F3A65D39680}.Debug.ActiveCfg = Debug|Win32 + {BC32C5A1-CDE1-4872-9CE8-5F3A65D39680}.Debug.Build.0 = Debug|Win32 + {BC32C5A1-CDE1-4872-9CE8-5F3A65D39680}.DebugDll.ActiveCfg = DebugDll|Win32 + {BC32C5A1-CDE1-4872-9CE8-5F3A65D39680}.DebugDll.Build.0 = DebugDll|Win32 + {BC32C5A1-CDE1-4872-9CE8-5F3A65D39680}.Release.ActiveCfg = Release|Win32 + {BC32C5A1-CDE1-4872-9CE8-5F3A65D39680}.Release.Build.0 = Release|Win32 + {BC32C5A1-CDE1-4872-9CE8-5F3A65D39680}.Releasedll.ActiveCfg = ReleaseDll|Win32 + {BC32C5A1-CDE1-4872-9CE8-5F3A65D39680}.Releasedll.Build.0 = ReleaseDll|Win32 + {56199633-C345-4733-8292-A4F2D86AA847}.Debug.ActiveCfg = Debug|Win32 + {56199633-C345-4733-8292-A4F2D86AA847}.Debug.Build.0 = Debug|Win32 + {56199633-C345-4733-8292-A4F2D86AA847}.DebugDll.ActiveCfg = DebugDll|Win32 + {56199633-C345-4733-8292-A4F2D86AA847}.DebugDll.Build.0 = DebugDll|Win32 + {56199633-C345-4733-8292-A4F2D86AA847}.Release.ActiveCfg = Release|Win32 + {56199633-C345-4733-8292-A4F2D86AA847}.Release.Build.0 = Release|Win32 + {56199633-C345-4733-8292-A4F2D86AA847}.Releasedll.ActiveCfg = ReleaseDll|Win32 + {56199633-C345-4733-8292-A4F2D86AA847}.Releasedll.Build.0 = ReleaseDll|Win32 + {1B51538E-859A-46FE-B423-592D79DEEF63}.Debug.ActiveCfg = Debug|Win32 + {1B51538E-859A-46FE-B423-592D79DEEF63}.Debug.Build.0 = Debug|Win32 + {1B51538E-859A-46FE-B423-592D79DEEF63}.DebugDll.ActiveCfg = DebugDll|Win32 + {1B51538E-859A-46FE-B423-592D79DEEF63}.DebugDll.Build.0 = DebugDll|Win32 + {1B51538E-859A-46FE-B423-592D79DEEF63}.Release.ActiveCfg = Release|Win32 + {1B51538E-859A-46FE-B423-592D79DEEF63}.Release.Build.0 = Release|Win32 + {1B51538E-859A-46FE-B423-592D79DEEF63}.Releasedll.ActiveCfg = ReleaseDll|Win32 + {1B51538E-859A-46FE-B423-592D79DEEF63}.Releasedll.Build.0 = ReleaseDll|Win32 + {5A189A92-9AF4-49FC-ABF4-8220A26E46D0}.Debug.ActiveCfg = Debug|Win32 + {5A189A92-9AF4-49FC-ABF4-8220A26E46D0}.Debug.Build.0 = Debug|Win32 + {5A189A92-9AF4-49FC-ABF4-8220A26E46D0}.DebugDll.ActiveCfg = DebugDll|Win32 + {5A189A92-9AF4-49FC-ABF4-8220A26E46D0}.DebugDll.Build.0 = DebugDll|Win32 + {5A189A92-9AF4-49FC-ABF4-8220A26E46D0}.Release.ActiveCfg = Release|Win32 + {5A189A92-9AF4-49FC-ABF4-8220A26E46D0}.Release.Build.0 = Release|Win32 + {5A189A92-9AF4-49FC-ABF4-8220A26E46D0}.Releasedll.ActiveCfg = ReleaseDll|Win32 + {5A189A92-9AF4-49FC-ABF4-8220A26E46D0}.Releasedll.Build.0 = ReleaseDll|Win32 + {A1BA7D3E-5434-4F98-87F2-78673B3EEEF1}.Debug.ActiveCfg = Debug|Win32 + {A1BA7D3E-5434-4F98-87F2-78673B3EEEF1}.Debug.Build.0 = Debug|Win32 + {A1BA7D3E-5434-4F98-87F2-78673B3EEEF1}.DebugDll.ActiveCfg = DebugDll|Win32 + {A1BA7D3E-5434-4F98-87F2-78673B3EEEF1}.DebugDll.Build.0 = DebugDll|Win32 + {A1BA7D3E-5434-4F98-87F2-78673B3EEEF1}.Release.ActiveCfg = Release|Win32 + {A1BA7D3E-5434-4F98-87F2-78673B3EEEF1}.Release.Build.0 = Release|Win32 + {A1BA7D3E-5434-4F98-87F2-78673B3EEEF1}.Releasedll.ActiveCfg = ReleaseDll|Win32 + {A1BA7D3E-5434-4F98-87F2-78673B3EEEF1}.Releasedll.Build.0 = ReleaseDll|Win32 + {864A7341-756C-4BF9-A16F-059FDD972D79}.Debug.ActiveCfg = Debug|Win32 + {864A7341-756C-4BF9-A16F-059FDD972D79}.Debug.Build.0 = Debug|Win32 + {864A7341-756C-4BF9-A16F-059FDD972D79}.DebugDll.ActiveCfg = DebugDll|Win32 + {864A7341-756C-4BF9-A16F-059FDD972D79}.DebugDll.Build.0 = DebugDll|Win32 + {864A7341-756C-4BF9-A16F-059FDD972D79}.Release.ActiveCfg = Release|Win32 + {864A7341-756C-4BF9-A16F-059FDD972D79}.Release.Build.0 = Release|Win32 + {864A7341-756C-4BF9-A16F-059FDD972D79}.Releasedll.ActiveCfg = ReleaseDll|Win32 + {864A7341-756C-4BF9-A16F-059FDD972D79}.Releasedll.Build.0 = ReleaseDll|Win32 + {A28B19ED-291C-47C8-BDD5-10BB038C371E}.Debug.ActiveCfg = Debug|Win32 + {A28B19ED-291C-47C8-BDD5-10BB038C371E}.Debug.Build.0 = Debug|Win32 + {A28B19ED-291C-47C8-BDD5-10BB038C371E}.DebugDll.ActiveCfg = DebugDll|Win32 + {A28B19ED-291C-47C8-BDD5-10BB038C371E}.DebugDll.Build.0 = DebugDll|Win32 + {A28B19ED-291C-47C8-BDD5-10BB038C371E}.Release.ActiveCfg = Release|Win32 + {A28B19ED-291C-47C8-BDD5-10BB038C371E}.Release.Build.0 = Release|Win32 + {A28B19ED-291C-47C8-BDD5-10BB038C371E}.Releasedll.ActiveCfg = ReleaseDll|Win32 + {A28B19ED-291C-47C8-BDD5-10BB038C371E}.Releasedll.Build.0 = ReleaseDll|Win32 + {349F7822-A752-42F0-BB13-4A28497D68DF}.Debug.ActiveCfg = Debug|Win32 + {349F7822-A752-42F0-BB13-4A28497D68DF}.Debug.Build.0 = Debug|Win32 + {349F7822-A752-42F0-BB13-4A28497D68DF}.DebugDll.ActiveCfg = DebugDll|Win32 + {349F7822-A752-42F0-BB13-4A28497D68DF}.DebugDll.Build.0 = DebugDll|Win32 + {349F7822-A752-42F0-BB13-4A28497D68DF}.Release.ActiveCfg = Release|Win32 + {349F7822-A752-42F0-BB13-4A28497D68DF}.Release.Build.0 = Release|Win32 + {349F7822-A752-42F0-BB13-4A28497D68DF}.Releasedll.ActiveCfg = ReleaseDll|Win32 + {349F7822-A752-42F0-BB13-4A28497D68DF}.Releasedll.Build.0 = ReleaseDll|Win32 + {F37E8828-252D-4F3E-A5B6-E3770750042F}.Debug.ActiveCfg = Debug|Win32 + {F37E8828-252D-4F3E-A5B6-E3770750042F}.Debug.Build.0 = Debug|Win32 + {F37E8828-252D-4F3E-A5B6-E3770750042F}.DebugDll.ActiveCfg = Debug|Win32 + {F37E8828-252D-4F3E-A5B6-E3770750042F}.DebugDll.Build.0 = Debug|Win32 + {F37E8828-252D-4F3E-A5B6-E3770750042F}.Release.ActiveCfg = Release|Win32 + {F37E8828-252D-4F3E-A5B6-E3770750042F}.Release.Build.0 = Release|Win32 + {F37E8828-252D-4F3E-A5B6-E3770750042F}.Releasedll.ActiveCfg = Release|Win32 + {F37E8828-252D-4F3E-A5B6-E3770750042F}.Releasedll.Build.0 = Release|Win32 + {C8CED6EB-DCC8-4CEE-921F-3190C879B116}.Debug.ActiveCfg = Debug|Win32 + {C8CED6EB-DCC8-4CEE-921F-3190C879B116}.Debug.Build.0 = Debug|Win32 + {C8CED6EB-DCC8-4CEE-921F-3190C879B116}.DebugDll.ActiveCfg = DebugDll|Win32 + {C8CED6EB-DCC8-4CEE-921F-3190C879B116}.DebugDll.Build.0 = DebugDll|Win32 + {C8CED6EB-DCC8-4CEE-921F-3190C879B116}.Release.ActiveCfg = Release|Win32 + {C8CED6EB-DCC8-4CEE-921F-3190C879B116}.Release.Build.0 = Release|Win32 + {C8CED6EB-DCC8-4CEE-921F-3190C879B116}.Releasedll.ActiveCfg = ReleaseDll|Win32 + {C8CED6EB-DCC8-4CEE-921F-3190C879B116}.Releasedll.Build.0 = ReleaseDll|Win32 + {B8029C89-9870-4EE4-ADD0-E7852E0D1810}.Debug.ActiveCfg = Debug|Win32 + {B8029C89-9870-4EE4-ADD0-E7852E0D1810}.Debug.Build.0 = Debug|Win32 + {B8029C89-9870-4EE4-ADD0-E7852E0D1810}.DebugDll.ActiveCfg = DebugDll|Win32 + {B8029C89-9870-4EE4-ADD0-E7852E0D1810}.DebugDll.Build.0 = DebugDll|Win32 + {B8029C89-9870-4EE4-ADD0-E7852E0D1810}.Release.ActiveCfg = Release|Win32 + {B8029C89-9870-4EE4-ADD0-E7852E0D1810}.Release.Build.0 = Release|Win32 + {B8029C89-9870-4EE4-ADD0-E7852E0D1810}.Releasedll.ActiveCfg = ReleaseDll|Win32 + {B8029C89-9870-4EE4-ADD0-E7852E0D1810}.Releasedll.Build.0 = ReleaseDll|Win32 + {8B7A7746-C678-4205-8EA7-492A097F524B}.Debug.ActiveCfg = Debug|Win32 + {8B7A7746-C678-4205-8EA7-492A097F524B}.Debug.Build.0 = Debug|Win32 + {8B7A7746-C678-4205-8EA7-492A097F524B}.DebugDll.ActiveCfg = DebugDll|Win32 + {8B7A7746-C678-4205-8EA7-492A097F524B}.DebugDll.Build.0 = DebugDll|Win32 + {8B7A7746-C678-4205-8EA7-492A097F524B}.Release.ActiveCfg = Release|Win32 + {8B7A7746-C678-4205-8EA7-492A097F524B}.Release.Build.0 = Release|Win32 + {8B7A7746-C678-4205-8EA7-492A097F524B}.Releasedll.ActiveCfg = ReleaseDll|Win32 + {8B7A7746-C678-4205-8EA7-492A097F524B}.Releasedll.Build.0 = ReleaseDll|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Debug.ActiveCfg = Debug|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Debug.Build.0 = Debug|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.DebugDll.ActiveCfg = DebugDll|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.DebugDll.Build.0 = DebugDll|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Release.ActiveCfg = Release|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Release.Build.0 = Release|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Releasedll.ActiveCfg = ReleaseDll|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Releasedll.Build.0 = ReleaseDll|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Debug.ActiveCfg = Debug|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Debug.Build.0 = Debug|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.DebugDll.ActiveCfg = DebugDll|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.DebugDll.Build.0 = DebugDll|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Release.ActiveCfg = Release|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Release.Build.0 = Release|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Releasedll.ActiveCfg = ReleaseDll|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Releasedll.Build.0 = ReleaseDll|Win32 + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.Debug.ActiveCfg = Debug|Win32 + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.Debug.Build.0 = Debug|Win32 + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.DebugDll.ActiveCfg = DebugDll|Win32 + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.DebugDll.Build.0 = DebugDll|Win32 + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.Release.ActiveCfg = Release|Win32 + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.Release.Build.0 = Release|Win32 + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.Releasedll.ActiveCfg = Releasedll|Win32 + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.Releasedll.Build.0 = Releasedll|Win32 + {128791D9-6787-471C-9A0C-0DCAE53F4911}.Debug.ActiveCfg = Debug|Win32 + {128791D9-6787-471C-9A0C-0DCAE53F4911}.Debug.Build.0 = Debug|Win32 + {128791D9-6787-471C-9A0C-0DCAE53F4911}.DebugDll.ActiveCfg = DebugDll|Win32 + {128791D9-6787-471C-9A0C-0DCAE53F4911}.DebugDll.Build.0 = DebugDll|Win32 + {128791D9-6787-471C-9A0C-0DCAE53F4911}.Release.ActiveCfg = Release|Win32 + {128791D9-6787-471C-9A0C-0DCAE53F4911}.Release.Build.0 = Release|Win32 + {128791D9-6787-471C-9A0C-0DCAE53F4911}.Releasedll.ActiveCfg = ReleaseDll|Win32 + {128791D9-6787-471C-9A0C-0DCAE53F4911}.Releasedll.Build.0 = ReleaseDll|Win32 + {90D013A0-4813-4BAB-8155-D175631A695E}.Debug.ActiveCfg = Debug|Win32 + {90D013A0-4813-4BAB-8155-D175631A695E}.Debug.Build.0 = Debug|Win32 + {90D013A0-4813-4BAB-8155-D175631A695E}.DebugDll.ActiveCfg = DebugDll|Win32 + {90D013A0-4813-4BAB-8155-D175631A695E}.DebugDll.Build.0 = DebugDll|Win32 + {90D013A0-4813-4BAB-8155-D175631A695E}.Release.ActiveCfg = Release|Win32 + {90D013A0-4813-4BAB-8155-D175631A695E}.Release.Build.0 = Release|Win32 + {90D013A0-4813-4BAB-8155-D175631A695E}.Releasedll.ActiveCfg = ReleaseDll|Win32 + {90D013A0-4813-4BAB-8155-D175631A695E}.Releasedll.Build.0 = ReleaseDll|Win32 + {1509DA30-29B0-4B73-921A-BBBD9E5608BE}.Debug.ActiveCfg = Debug|Win32 + {1509DA30-29B0-4B73-921A-BBBD9E5608BE}.Debug.Build.0 = Debug|Win32 + {1509DA30-29B0-4B73-921A-BBBD9E5608BE}.DebugDll.ActiveCfg = DebugDll|Win32 + {1509DA30-29B0-4B73-921A-BBBD9E5608BE}.DebugDll.Build.0 = DebugDll|Win32 + {1509DA30-29B0-4B73-921A-BBBD9E5608BE}.Release.ActiveCfg = Release|Win32 + {1509DA30-29B0-4B73-921A-BBBD9E5608BE}.Release.Build.0 = Release|Win32 + {1509DA30-29B0-4B73-921A-BBBD9E5608BE}.Releasedll.ActiveCfg = ReleaseDll|Win32 + {1509DA30-29B0-4B73-921A-BBBD9E5608BE}.Releasedll.Build.0 = ReleaseDll|Win32 + {143ED97E-1EC6-4821-A5FA-A6728B69273E}.Debug.ActiveCfg = Debug|Win32 + {143ED97E-1EC6-4821-A5FA-A6728B69273E}.Debug.Build.0 = Debug|Win32 + {143ED97E-1EC6-4821-A5FA-A6728B69273E}.DebugDll.ActiveCfg = DebugDll|Win32 + {143ED97E-1EC6-4821-A5FA-A6728B69273E}.DebugDll.Build.0 = DebugDll|Win32 + {143ED97E-1EC6-4821-A5FA-A6728B69273E}.Release.ActiveCfg = Release|Win32 + {143ED97E-1EC6-4821-A5FA-A6728B69273E}.Release.Build.0 = Release|Win32 + {143ED97E-1EC6-4821-A5FA-A6728B69273E}.Releasedll.ActiveCfg = ReleaseDll|Win32 + {143ED97E-1EC6-4821-A5FA-A6728B69273E}.Releasedll.Build.0 = ReleaseDll|Win32 + {02B1C8C9-0B52-491D-89D3-8B37CE3A4FE9}.Debug.ActiveCfg = Debug|Win32 + {02B1C8C9-0B52-491D-89D3-8B37CE3A4FE9}.Debug.Build.0 = Debug|Win32 + {02B1C8C9-0B52-491D-89D3-8B37CE3A4FE9}.DebugDll.ActiveCfg = DebugDll|Win32 + {02B1C8C9-0B52-491D-89D3-8B37CE3A4FE9}.DebugDll.Build.0 = DebugDll|Win32 + {02B1C8C9-0B52-491D-89D3-8B37CE3A4FE9}.Release.ActiveCfg = Release|Win32 + {02B1C8C9-0B52-491D-89D3-8B37CE3A4FE9}.Release.Build.0 = Release|Win32 + {02B1C8C9-0B52-491D-89D3-8B37CE3A4FE9}.Releasedll.ActiveCfg = ReleaseDll|Win32 + {02B1C8C9-0B52-491D-89D3-8B37CE3A4FE9}.Releasedll.Build.0 = ReleaseDll|Win32 + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.Debug.ActiveCfg = Debug|Win32 + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.Debug.Build.0 = Debug|Win32 + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.DebugDll.ActiveCfg = DebugDll|Win32 + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.DebugDll.Build.0 = DebugDll|Win32 + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.Release.ActiveCfg = Release|Win32 + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.Release.Build.0 = Release|Win32 + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.Releasedll.ActiveCfg = ReleaseDll|Win32 + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.Releasedll.Build.0 = ReleaseDll|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/acl_cpp_vc2010.sln b/acl_cpp_vc2010.sln new file mode 100644 index 000000000..156b1a139 --- /dev/null +++ b/acl_cpp_vc2010.sln @@ -0,0 +1,416 @@ +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "socket_stream", "lib_acl_cpp\samples\socket_stream\socket_stream.vcxproj", "{41FA5224-3315-4CDA-9C44-19085049F179}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + {FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mime", "lib_acl_cpp\samples\mime\mime.vcxproj", "{52AA7352-CE48-4F60-B92D-1EB16A79FE54}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xml", "lib_acl_cpp\samples\xml\xml.vcxproj", "{2DABFAD1-114B-4F96-9185-DC0C56A3662D}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + {FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "string", "lib_acl_cpp\samples\string\string.vcxproj", "{C94BEF01-706C-49A7-9FF1-9D87FA5BB8E7}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + {FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fstream", "lib_acl_cpp\samples\fstream\fstream.vcxproj", "{7680672C-4C9B-4BE8-8BAE-BB23B951AAA0}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + {FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mime_base64", "lib_acl_cpp\samples\mime_base64\mime_base64.vcxproj", "{19CB30E5-2672-4A8B-96FB-9C42970CCF69}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + {FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mime_qp", "lib_acl_cpp\samples\mime_qp\mime_qp.vcxproj", "{5DC79C83-9DE8-46B3-A172-8A4E3371878B}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + {FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "flock", "lib_acl_cpp\samples\flock\flock.vcxproj", "{5F4063AD-B591-4C64-ADEA-609968A83550}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + {FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rfc2047", "lib_acl_cpp\samples\rfc2047\rfc2047.vcxproj", "{503AFD46-DF2F-4D2B-8584-60AD2007D2BE}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + {FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "aio_server", "lib_acl_cpp\samples\aio_server\aio_server.vcxproj", "{225D0BFA-64D7-4F8F-951E-36A494CF6178}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + {FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "aio_client", "lib_acl_cpp\samples\aio_client\aio_client.vcxproj", "{9A04F86E-D4CB-45ED-9BB6-9939B9400B6F}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + {FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "winaio", "lib_acl_cpp\samples\winaio\winaio.vcxproj", "{ADE6F714-BD52-432D-AB86-62FA59AB6746}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "aio_ipc", "lib_acl_cpp\samples\aio_ipc\aio_ipc.vcxproj", "{956FA905-A77F-41FE-A4BE-C3BD3B5B3E83}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + {FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "aio_dns", "lib_acl_cpp\samples\aio_dns\aio_dns.vcxproj", "{BE2DF8B2-2DCD-4F32-99B9-0B0CA24BFAD9}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + {FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HttpClient", "lib_acl_cpp\samples\HttpClient\HttpClient.vcxproj", "{C0A7DB86-EF13-4A3E-9F34-8950521C9675}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "http_client", "lib_acl_cpp\samples\http_client\http_client.vcxproj", "{467619C7-C100-47B9-9A3B-7246A542EDC9}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + {FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "final_class", "lib_acl_cpp\samples\final_class\final_class.vcxproj", "{840C2263-DF87-4FD2-8964-EF81B74695FE}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "win_dbservice", "lib_acl_cpp\samples\win_dbservice\win_dbservice.vcxproj", "{DC7E75E5-FE42-4529-9D9A-19D240B8727B}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "md5", "lib_acl_cpp\samples\md5\md5.vcxproj", "{B8029C89-9870-4EE4-ADD0-E7852E0D1810}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + {FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lib_acl", "lib_acl\lib_acl_vc2010.vcxproj", "{B40213C2-507C-4C7F-A6E1-B850C9BDC27B}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lib_protocol", "lib_protocol\lib_protocol_vc2010.vcxproj", "{FE724EF7-3763-4E78-BDF5-BCBC075719FD}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lib_acl_cpp", "lib_acl_cpp\lib_acl_cpp_vc2010.vcxproj", "{6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "singleton", "lib_acl_cpp\samples\singleton\singleton.vcxproj", "{128791D9-6787-471C-9A0C-0DCAE53F4911}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lib_rpc", "lib_rpc\lib_rpc.vcxproj", "{2B0C9A86-6C14-4CEF-BD7A-4A6752386A44}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "protobuf_fstream", "lib_rpc\samples\fstream\protobuf_fstream.vcxproj", "{E8A3F4F4-0217-4775-9AC4-BD10E12298D4}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "http_rpc_client", "lib_rpc\samples\http_rpc_client\http_rpc_client.vcxproj", "{48ACE73F-73AD-43CC-99FB-35DFF71B8E9E}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "http_rpc_server", "lib_rpc\samples\http_rpc_server\http_rpc_server.vcxproj", "{8D69EA4C-C980-4168-85B6-BAC9CB99E0DC}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + DebugDll|Win32 = DebugDll|Win32 + Release|Win32 = Release|Win32 + Releasedll|Win32 = Releasedll|Win32 + Template|Win32 = Template|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {41FA5224-3315-4CDA-9C44-19085049F179}.Debug|Win32.ActiveCfg = Debug|Win32 + {41FA5224-3315-4CDA-9C44-19085049F179}.Debug|Win32.Build.0 = Debug|Win32 + {41FA5224-3315-4CDA-9C44-19085049F179}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {41FA5224-3315-4CDA-9C44-19085049F179}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {41FA5224-3315-4CDA-9C44-19085049F179}.Release|Win32.ActiveCfg = Release|Win32 + {41FA5224-3315-4CDA-9C44-19085049F179}.Release|Win32.Build.0 = Release|Win32 + {41FA5224-3315-4CDA-9C44-19085049F179}.Releasedll|Win32.ActiveCfg = Releasedll|Win32 + {41FA5224-3315-4CDA-9C44-19085049F179}.Releasedll|Win32.Build.0 = Releasedll|Win32 + {41FA5224-3315-4CDA-9C44-19085049F179}.Template|Win32.ActiveCfg = Release|Win32 + {41FA5224-3315-4CDA-9C44-19085049F179}.Template|Win32.Build.0 = Release|Win32 + {52AA7352-CE48-4F60-B92D-1EB16A79FE54}.Debug|Win32.ActiveCfg = Debug|Win32 + {52AA7352-CE48-4F60-B92D-1EB16A79FE54}.Debug|Win32.Build.0 = Debug|Win32 + {52AA7352-CE48-4F60-B92D-1EB16A79FE54}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {52AA7352-CE48-4F60-B92D-1EB16A79FE54}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {52AA7352-CE48-4F60-B92D-1EB16A79FE54}.Release|Win32.ActiveCfg = Release|Win32 + {52AA7352-CE48-4F60-B92D-1EB16A79FE54}.Release|Win32.Build.0 = Release|Win32 + {52AA7352-CE48-4F60-B92D-1EB16A79FE54}.Releasedll|Win32.ActiveCfg = Releasedll|Win32 + {52AA7352-CE48-4F60-B92D-1EB16A79FE54}.Releasedll|Win32.Build.0 = Releasedll|Win32 + {52AA7352-CE48-4F60-B92D-1EB16A79FE54}.Template|Win32.ActiveCfg = Release|Win32 + {52AA7352-CE48-4F60-B92D-1EB16A79FE54}.Template|Win32.Build.0 = Release|Win32 + {2DABFAD1-114B-4F96-9185-DC0C56A3662D}.Debug|Win32.ActiveCfg = Debug|Win32 + {2DABFAD1-114B-4F96-9185-DC0C56A3662D}.Debug|Win32.Build.0 = Debug|Win32 + {2DABFAD1-114B-4F96-9185-DC0C56A3662D}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {2DABFAD1-114B-4F96-9185-DC0C56A3662D}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {2DABFAD1-114B-4F96-9185-DC0C56A3662D}.Release|Win32.ActiveCfg = Release|Win32 + {2DABFAD1-114B-4F96-9185-DC0C56A3662D}.Release|Win32.Build.0 = Release|Win32 + {2DABFAD1-114B-4F96-9185-DC0C56A3662D}.Releasedll|Win32.ActiveCfg = Releasedll|Win32 + {2DABFAD1-114B-4F96-9185-DC0C56A3662D}.Releasedll|Win32.Build.0 = Releasedll|Win32 + {2DABFAD1-114B-4F96-9185-DC0C56A3662D}.Template|Win32.ActiveCfg = Release|Win32 + {2DABFAD1-114B-4F96-9185-DC0C56A3662D}.Template|Win32.Build.0 = Release|Win32 + {C94BEF01-706C-49A7-9FF1-9D87FA5BB8E7}.Debug|Win32.ActiveCfg = Debug|Win32 + {C94BEF01-706C-49A7-9FF1-9D87FA5BB8E7}.Debug|Win32.Build.0 = Debug|Win32 + {C94BEF01-706C-49A7-9FF1-9D87FA5BB8E7}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {C94BEF01-706C-49A7-9FF1-9D87FA5BB8E7}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {C94BEF01-706C-49A7-9FF1-9D87FA5BB8E7}.Release|Win32.ActiveCfg = Release|Win32 + {C94BEF01-706C-49A7-9FF1-9D87FA5BB8E7}.Release|Win32.Build.0 = Release|Win32 + {C94BEF01-706C-49A7-9FF1-9D87FA5BB8E7}.Releasedll|Win32.ActiveCfg = Releasedll|Win32 + {C94BEF01-706C-49A7-9FF1-9D87FA5BB8E7}.Releasedll|Win32.Build.0 = Releasedll|Win32 + {C94BEF01-706C-49A7-9FF1-9D87FA5BB8E7}.Template|Win32.ActiveCfg = Release|Win32 + {C94BEF01-706C-49A7-9FF1-9D87FA5BB8E7}.Template|Win32.Build.0 = Release|Win32 + {7680672C-4C9B-4BE8-8BAE-BB23B951AAA0}.Debug|Win32.ActiveCfg = Debug|Win32 + {7680672C-4C9B-4BE8-8BAE-BB23B951AAA0}.Debug|Win32.Build.0 = Debug|Win32 + {7680672C-4C9B-4BE8-8BAE-BB23B951AAA0}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {7680672C-4C9B-4BE8-8BAE-BB23B951AAA0}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {7680672C-4C9B-4BE8-8BAE-BB23B951AAA0}.Release|Win32.ActiveCfg = Release|Win32 + {7680672C-4C9B-4BE8-8BAE-BB23B951AAA0}.Release|Win32.Build.0 = Release|Win32 + {7680672C-4C9B-4BE8-8BAE-BB23B951AAA0}.Releasedll|Win32.ActiveCfg = Releasedll|Win32 + {7680672C-4C9B-4BE8-8BAE-BB23B951AAA0}.Releasedll|Win32.Build.0 = Releasedll|Win32 + {7680672C-4C9B-4BE8-8BAE-BB23B951AAA0}.Template|Win32.ActiveCfg = Release|Win32 + {7680672C-4C9B-4BE8-8BAE-BB23B951AAA0}.Template|Win32.Build.0 = Release|Win32 + {19CB30E5-2672-4A8B-96FB-9C42970CCF69}.Debug|Win32.ActiveCfg = Debug|Win32 + {19CB30E5-2672-4A8B-96FB-9C42970CCF69}.Debug|Win32.Build.0 = Debug|Win32 + {19CB30E5-2672-4A8B-96FB-9C42970CCF69}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {19CB30E5-2672-4A8B-96FB-9C42970CCF69}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {19CB30E5-2672-4A8B-96FB-9C42970CCF69}.Release|Win32.ActiveCfg = Release|Win32 + {19CB30E5-2672-4A8B-96FB-9C42970CCF69}.Release|Win32.Build.0 = Release|Win32 + {19CB30E5-2672-4A8B-96FB-9C42970CCF69}.Releasedll|Win32.ActiveCfg = Releasedll|Win32 + {19CB30E5-2672-4A8B-96FB-9C42970CCF69}.Releasedll|Win32.Build.0 = Releasedll|Win32 + {19CB30E5-2672-4A8B-96FB-9C42970CCF69}.Template|Win32.ActiveCfg = Release|Win32 + {19CB30E5-2672-4A8B-96FB-9C42970CCF69}.Template|Win32.Build.0 = Release|Win32 + {5DC79C83-9DE8-46B3-A172-8A4E3371878B}.Debug|Win32.ActiveCfg = Debug|Win32 + {5DC79C83-9DE8-46B3-A172-8A4E3371878B}.Debug|Win32.Build.0 = Debug|Win32 + {5DC79C83-9DE8-46B3-A172-8A4E3371878B}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {5DC79C83-9DE8-46B3-A172-8A4E3371878B}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {5DC79C83-9DE8-46B3-A172-8A4E3371878B}.Release|Win32.ActiveCfg = Release|Win32 + {5DC79C83-9DE8-46B3-A172-8A4E3371878B}.Release|Win32.Build.0 = Release|Win32 + {5DC79C83-9DE8-46B3-A172-8A4E3371878B}.Releasedll|Win32.ActiveCfg = Releasedll|Win32 + {5DC79C83-9DE8-46B3-A172-8A4E3371878B}.Releasedll|Win32.Build.0 = Releasedll|Win32 + {5DC79C83-9DE8-46B3-A172-8A4E3371878B}.Template|Win32.ActiveCfg = Release|Win32 + {5DC79C83-9DE8-46B3-A172-8A4E3371878B}.Template|Win32.Build.0 = Release|Win32 + {5F4063AD-B591-4C64-ADEA-609968A83550}.Debug|Win32.ActiveCfg = Debug|Win32 + {5F4063AD-B591-4C64-ADEA-609968A83550}.Debug|Win32.Build.0 = Debug|Win32 + {5F4063AD-B591-4C64-ADEA-609968A83550}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {5F4063AD-B591-4C64-ADEA-609968A83550}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {5F4063AD-B591-4C64-ADEA-609968A83550}.Release|Win32.ActiveCfg = Release|Win32 + {5F4063AD-B591-4C64-ADEA-609968A83550}.Release|Win32.Build.0 = Release|Win32 + {5F4063AD-B591-4C64-ADEA-609968A83550}.Releasedll|Win32.ActiveCfg = Releasedll|Win32 + {5F4063AD-B591-4C64-ADEA-609968A83550}.Releasedll|Win32.Build.0 = Releasedll|Win32 + {5F4063AD-B591-4C64-ADEA-609968A83550}.Template|Win32.ActiveCfg = Release|Win32 + {5F4063AD-B591-4C64-ADEA-609968A83550}.Template|Win32.Build.0 = Release|Win32 + {503AFD46-DF2F-4D2B-8584-60AD2007D2BE}.Debug|Win32.ActiveCfg = Debug|Win32 + {503AFD46-DF2F-4D2B-8584-60AD2007D2BE}.Debug|Win32.Build.0 = Debug|Win32 + {503AFD46-DF2F-4D2B-8584-60AD2007D2BE}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {503AFD46-DF2F-4D2B-8584-60AD2007D2BE}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {503AFD46-DF2F-4D2B-8584-60AD2007D2BE}.Release|Win32.ActiveCfg = Release|Win32 + {503AFD46-DF2F-4D2B-8584-60AD2007D2BE}.Release|Win32.Build.0 = Release|Win32 + {503AFD46-DF2F-4D2B-8584-60AD2007D2BE}.Releasedll|Win32.ActiveCfg = Releasedll|Win32 + {503AFD46-DF2F-4D2B-8584-60AD2007D2BE}.Releasedll|Win32.Build.0 = Releasedll|Win32 + {503AFD46-DF2F-4D2B-8584-60AD2007D2BE}.Template|Win32.ActiveCfg = Release|Win32 + {503AFD46-DF2F-4D2B-8584-60AD2007D2BE}.Template|Win32.Build.0 = Release|Win32 + {225D0BFA-64D7-4F8F-951E-36A494CF6178}.Debug|Win32.ActiveCfg = Debug|Win32 + {225D0BFA-64D7-4F8F-951E-36A494CF6178}.Debug|Win32.Build.0 = Debug|Win32 + {225D0BFA-64D7-4F8F-951E-36A494CF6178}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {225D0BFA-64D7-4F8F-951E-36A494CF6178}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {225D0BFA-64D7-4F8F-951E-36A494CF6178}.Release|Win32.ActiveCfg = Release|Win32 + {225D0BFA-64D7-4F8F-951E-36A494CF6178}.Release|Win32.Build.0 = Release|Win32 + {225D0BFA-64D7-4F8F-951E-36A494CF6178}.Releasedll|Win32.ActiveCfg = Releasedll|Win32 + {225D0BFA-64D7-4F8F-951E-36A494CF6178}.Releasedll|Win32.Build.0 = Releasedll|Win32 + {225D0BFA-64D7-4F8F-951E-36A494CF6178}.Template|Win32.ActiveCfg = Release|Win32 + {225D0BFA-64D7-4F8F-951E-36A494CF6178}.Template|Win32.Build.0 = Release|Win32 + {9A04F86E-D4CB-45ED-9BB6-9939B9400B6F}.Debug|Win32.ActiveCfg = Debug|Win32 + {9A04F86E-D4CB-45ED-9BB6-9939B9400B6F}.Debug|Win32.Build.0 = Debug|Win32 + {9A04F86E-D4CB-45ED-9BB6-9939B9400B6F}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {9A04F86E-D4CB-45ED-9BB6-9939B9400B6F}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {9A04F86E-D4CB-45ED-9BB6-9939B9400B6F}.Release|Win32.ActiveCfg = Release|Win32 + {9A04F86E-D4CB-45ED-9BB6-9939B9400B6F}.Release|Win32.Build.0 = Release|Win32 + {9A04F86E-D4CB-45ED-9BB6-9939B9400B6F}.Releasedll|Win32.ActiveCfg = Releasedll|Win32 + {9A04F86E-D4CB-45ED-9BB6-9939B9400B6F}.Releasedll|Win32.Build.0 = Releasedll|Win32 + {9A04F86E-D4CB-45ED-9BB6-9939B9400B6F}.Template|Win32.ActiveCfg = Release|Win32 + {9A04F86E-D4CB-45ED-9BB6-9939B9400B6F}.Template|Win32.Build.0 = Release|Win32 + {ADE6F714-BD52-432D-AB86-62FA59AB6746}.Debug|Win32.ActiveCfg = Debug|Win32 + {ADE6F714-BD52-432D-AB86-62FA59AB6746}.Debug|Win32.Build.0 = Debug|Win32 + {ADE6F714-BD52-432D-AB86-62FA59AB6746}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {ADE6F714-BD52-432D-AB86-62FA59AB6746}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {ADE6F714-BD52-432D-AB86-62FA59AB6746}.Release|Win32.ActiveCfg = Release|Win32 + {ADE6F714-BD52-432D-AB86-62FA59AB6746}.Release|Win32.Build.0 = Release|Win32 + {ADE6F714-BD52-432D-AB86-62FA59AB6746}.Releasedll|Win32.ActiveCfg = Releasedll|Win32 + {ADE6F714-BD52-432D-AB86-62FA59AB6746}.Releasedll|Win32.Build.0 = Releasedll|Win32 + {ADE6F714-BD52-432D-AB86-62FA59AB6746}.Template|Win32.ActiveCfg = Template|Win32 + {ADE6F714-BD52-432D-AB86-62FA59AB6746}.Template|Win32.Build.0 = Template|Win32 + {956FA905-A77F-41FE-A4BE-C3BD3B5B3E83}.Debug|Win32.ActiveCfg = Debug|Win32 + {956FA905-A77F-41FE-A4BE-C3BD3B5B3E83}.Debug|Win32.Build.0 = Debug|Win32 + {956FA905-A77F-41FE-A4BE-C3BD3B5B3E83}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {956FA905-A77F-41FE-A4BE-C3BD3B5B3E83}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {956FA905-A77F-41FE-A4BE-C3BD3B5B3E83}.Release|Win32.ActiveCfg = Release|Win32 + {956FA905-A77F-41FE-A4BE-C3BD3B5B3E83}.Release|Win32.Build.0 = Release|Win32 + {956FA905-A77F-41FE-A4BE-C3BD3B5B3E83}.Releasedll|Win32.ActiveCfg = Releasedll|Win32 + {956FA905-A77F-41FE-A4BE-C3BD3B5B3E83}.Releasedll|Win32.Build.0 = Releasedll|Win32 + {956FA905-A77F-41FE-A4BE-C3BD3B5B3E83}.Template|Win32.ActiveCfg = Release|Win32 + {956FA905-A77F-41FE-A4BE-C3BD3B5B3E83}.Template|Win32.Build.0 = Release|Win32 + {BE2DF8B2-2DCD-4F32-99B9-0B0CA24BFAD9}.Debug|Win32.ActiveCfg = Debug|Win32 + {BE2DF8B2-2DCD-4F32-99B9-0B0CA24BFAD9}.Debug|Win32.Build.0 = Debug|Win32 + {BE2DF8B2-2DCD-4F32-99B9-0B0CA24BFAD9}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {BE2DF8B2-2DCD-4F32-99B9-0B0CA24BFAD9}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {BE2DF8B2-2DCD-4F32-99B9-0B0CA24BFAD9}.Release|Win32.ActiveCfg = Release|Win32 + {BE2DF8B2-2DCD-4F32-99B9-0B0CA24BFAD9}.Release|Win32.Build.0 = Release|Win32 + {BE2DF8B2-2DCD-4F32-99B9-0B0CA24BFAD9}.Releasedll|Win32.ActiveCfg = Releasedll|Win32 + {BE2DF8B2-2DCD-4F32-99B9-0B0CA24BFAD9}.Releasedll|Win32.Build.0 = Releasedll|Win32 + {BE2DF8B2-2DCD-4F32-99B9-0B0CA24BFAD9}.Template|Win32.ActiveCfg = Release|Win32 + {BE2DF8B2-2DCD-4F32-99B9-0B0CA24BFAD9}.Template|Win32.Build.0 = Release|Win32 + {C0A7DB86-EF13-4A3E-9F34-8950521C9675}.Debug|Win32.ActiveCfg = Debug|Win32 + {C0A7DB86-EF13-4A3E-9F34-8950521C9675}.Debug|Win32.Build.0 = Debug|Win32 + {C0A7DB86-EF13-4A3E-9F34-8950521C9675}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {C0A7DB86-EF13-4A3E-9F34-8950521C9675}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {C0A7DB86-EF13-4A3E-9F34-8950521C9675}.Release|Win32.ActiveCfg = Release|Win32 + {C0A7DB86-EF13-4A3E-9F34-8950521C9675}.Release|Win32.Build.0 = Release|Win32 + {C0A7DB86-EF13-4A3E-9F34-8950521C9675}.Releasedll|Win32.ActiveCfg = Releasedll|Win32 + {C0A7DB86-EF13-4A3E-9F34-8950521C9675}.Releasedll|Win32.Build.0 = Releasedll|Win32 + {C0A7DB86-EF13-4A3E-9F34-8950521C9675}.Template|Win32.ActiveCfg = Template|Win32 + {C0A7DB86-EF13-4A3E-9F34-8950521C9675}.Template|Win32.Build.0 = Template|Win32 + {467619C7-C100-47B9-9A3B-7246A542EDC9}.Debug|Win32.ActiveCfg = Debug|Win32 + {467619C7-C100-47B9-9A3B-7246A542EDC9}.Debug|Win32.Build.0 = Debug|Win32 + {467619C7-C100-47B9-9A3B-7246A542EDC9}.DebugDll|Win32.ActiveCfg = Debugdll|Win32 + {467619C7-C100-47B9-9A3B-7246A542EDC9}.DebugDll|Win32.Build.0 = Debugdll|Win32 + {467619C7-C100-47B9-9A3B-7246A542EDC9}.Release|Win32.ActiveCfg = Release|Win32 + {467619C7-C100-47B9-9A3B-7246A542EDC9}.Release|Win32.Build.0 = Release|Win32 + {467619C7-C100-47B9-9A3B-7246A542EDC9}.Releasedll|Win32.ActiveCfg = Releasedll|Win32 + {467619C7-C100-47B9-9A3B-7246A542EDC9}.Releasedll|Win32.Build.0 = Releasedll|Win32 + {467619C7-C100-47B9-9A3B-7246A542EDC9}.Template|Win32.ActiveCfg = Release|Win32 + {467619C7-C100-47B9-9A3B-7246A542EDC9}.Template|Win32.Build.0 = Release|Win32 + {840C2263-DF87-4FD2-8964-EF81B74695FE}.Debug|Win32.ActiveCfg = Debug|Win32 + {840C2263-DF87-4FD2-8964-EF81B74695FE}.Debug|Win32.Build.0 = Debug|Win32 + {840C2263-DF87-4FD2-8964-EF81B74695FE}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {840C2263-DF87-4FD2-8964-EF81B74695FE}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {840C2263-DF87-4FD2-8964-EF81B74695FE}.Release|Win32.ActiveCfg = Release|Win32 + {840C2263-DF87-4FD2-8964-EF81B74695FE}.Release|Win32.Build.0 = Release|Win32 + {840C2263-DF87-4FD2-8964-EF81B74695FE}.Releasedll|Win32.ActiveCfg = ReleaseDll|Win32 + {840C2263-DF87-4FD2-8964-EF81B74695FE}.Releasedll|Win32.Build.0 = ReleaseDll|Win32 + {840C2263-DF87-4FD2-8964-EF81B74695FE}.Template|Win32.ActiveCfg = Release|Win32 + {840C2263-DF87-4FD2-8964-EF81B74695FE}.Template|Win32.Build.0 = Release|Win32 + {DC7E75E5-FE42-4529-9D9A-19D240B8727B}.Debug|Win32.ActiveCfg = Debug|Win32 + {DC7E75E5-FE42-4529-9D9A-19D240B8727B}.Debug|Win32.Build.0 = Debug|Win32 + {DC7E75E5-FE42-4529-9D9A-19D240B8727B}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {DC7E75E5-FE42-4529-9D9A-19D240B8727B}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {DC7E75E5-FE42-4529-9D9A-19D240B8727B}.Release|Win32.ActiveCfg = Release|Win32 + {DC7E75E5-FE42-4529-9D9A-19D240B8727B}.Release|Win32.Build.0 = Release|Win32 + {DC7E75E5-FE42-4529-9D9A-19D240B8727B}.Releasedll|Win32.ActiveCfg = ReleaseDll|Win32 + {DC7E75E5-FE42-4529-9D9A-19D240B8727B}.Releasedll|Win32.Build.0 = ReleaseDll|Win32 + {DC7E75E5-FE42-4529-9D9A-19D240B8727B}.Template|Win32.ActiveCfg = Template|Win32 + {DC7E75E5-FE42-4529-9D9A-19D240B8727B}.Template|Win32.Build.0 = Template|Win32 + {B8029C89-9870-4EE4-ADD0-E7852E0D1810}.Debug|Win32.ActiveCfg = Debug|Win32 + {B8029C89-9870-4EE4-ADD0-E7852E0D1810}.Debug|Win32.Build.0 = Debug|Win32 + {B8029C89-9870-4EE4-ADD0-E7852E0D1810}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {B8029C89-9870-4EE4-ADD0-E7852E0D1810}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {B8029C89-9870-4EE4-ADD0-E7852E0D1810}.Release|Win32.ActiveCfg = Release|Win32 + {B8029C89-9870-4EE4-ADD0-E7852E0D1810}.Release|Win32.Build.0 = Release|Win32 + {B8029C89-9870-4EE4-ADD0-E7852E0D1810}.Releasedll|Win32.ActiveCfg = ReleaseDll|Win32 + {B8029C89-9870-4EE4-ADD0-E7852E0D1810}.Releasedll|Win32.Build.0 = ReleaseDll|Win32 + {B8029C89-9870-4EE4-ADD0-E7852E0D1810}.Template|Win32.ActiveCfg = Release|Win32 + {B8029C89-9870-4EE4-ADD0-E7852E0D1810}.Template|Win32.Build.0 = Release|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Debug|Win32.ActiveCfg = Debug|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Debug|Win32.Build.0 = Debug|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Release|Win32.ActiveCfg = Release|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Release|Win32.Build.0 = Release|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Releasedll|Win32.ActiveCfg = ReleaseDll|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Releasedll|Win32.Build.0 = ReleaseDll|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Template|Win32.ActiveCfg = Release|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Template|Win32.Build.0 = Release|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Debug|Win32.ActiveCfg = Debug|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Debug|Win32.Build.0 = Debug|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Release|Win32.ActiveCfg = Release|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Release|Win32.Build.0 = Release|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Releasedll|Win32.ActiveCfg = ReleaseDll|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Releasedll|Win32.Build.0 = ReleaseDll|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Template|Win32.ActiveCfg = Release|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Template|Win32.Build.0 = Release|Win32 + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.Debug|Win32.ActiveCfg = Debug|Win32 + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.Debug|Win32.Build.0 = Debug|Win32 + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.Release|Win32.ActiveCfg = Release|Win32 + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.Release|Win32.Build.0 = Release|Win32 + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.Releasedll|Win32.ActiveCfg = Releasedll|Win32 + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.Releasedll|Win32.Build.0 = Releasedll|Win32 + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.Template|Win32.ActiveCfg = Release|Win32 + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.Template|Win32.Build.0 = Release|Win32 + {128791D9-6787-471C-9A0C-0DCAE53F4911}.Debug|Win32.ActiveCfg = Debug|Win32 + {128791D9-6787-471C-9A0C-0DCAE53F4911}.Debug|Win32.Build.0 = Debug|Win32 + {128791D9-6787-471C-9A0C-0DCAE53F4911}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {128791D9-6787-471C-9A0C-0DCAE53F4911}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {128791D9-6787-471C-9A0C-0DCAE53F4911}.Release|Win32.ActiveCfg = Release|Win32 + {128791D9-6787-471C-9A0C-0DCAE53F4911}.Release|Win32.Build.0 = Release|Win32 + {128791D9-6787-471C-9A0C-0DCAE53F4911}.Releasedll|Win32.ActiveCfg = ReleaseDll|Win32 + {128791D9-6787-471C-9A0C-0DCAE53F4911}.Releasedll|Win32.Build.0 = ReleaseDll|Win32 + {128791D9-6787-471C-9A0C-0DCAE53F4911}.Template|Win32.ActiveCfg = Release|Win32 + {128791D9-6787-471C-9A0C-0DCAE53F4911}.Template|Win32.Build.0 = Release|Win32 + {2B0C9A86-6C14-4CEF-BD7A-4A6752386A44}.Debug|Win32.ActiveCfg = Debug|Win32 + {2B0C9A86-6C14-4CEF-BD7A-4A6752386A44}.Debug|Win32.Build.0 = Debug|Win32 + {2B0C9A86-6C14-4CEF-BD7A-4A6752386A44}.DebugDll|Win32.ActiveCfg = Debug|Win32 + {2B0C9A86-6C14-4CEF-BD7A-4A6752386A44}.DebugDll|Win32.Build.0 = Debug|Win32 + {2B0C9A86-6C14-4CEF-BD7A-4A6752386A44}.Release|Win32.ActiveCfg = Release|Win32 + {2B0C9A86-6C14-4CEF-BD7A-4A6752386A44}.Release|Win32.Build.0 = Release|Win32 + {2B0C9A86-6C14-4CEF-BD7A-4A6752386A44}.Releasedll|Win32.ActiveCfg = Release|Win32 + {2B0C9A86-6C14-4CEF-BD7A-4A6752386A44}.Releasedll|Win32.Build.0 = Release|Win32 + {2B0C9A86-6C14-4CEF-BD7A-4A6752386A44}.Template|Win32.ActiveCfg = Release|Win32 + {2B0C9A86-6C14-4CEF-BD7A-4A6752386A44}.Template|Win32.Build.0 = Release|Win32 + {E8A3F4F4-0217-4775-9AC4-BD10E12298D4}.Debug|Win32.ActiveCfg = Debug|Win32 + {E8A3F4F4-0217-4775-9AC4-BD10E12298D4}.Debug|Win32.Build.0 = Debug|Win32 + {E8A3F4F4-0217-4775-9AC4-BD10E12298D4}.DebugDll|Win32.ActiveCfg = Debug|Win32 + {E8A3F4F4-0217-4775-9AC4-BD10E12298D4}.DebugDll|Win32.Build.0 = Debug|Win32 + {E8A3F4F4-0217-4775-9AC4-BD10E12298D4}.Release|Win32.ActiveCfg = Release|Win32 + {E8A3F4F4-0217-4775-9AC4-BD10E12298D4}.Release|Win32.Build.0 = Release|Win32 + {E8A3F4F4-0217-4775-9AC4-BD10E12298D4}.Releasedll|Win32.ActiveCfg = Release|Win32 + {E8A3F4F4-0217-4775-9AC4-BD10E12298D4}.Releasedll|Win32.Build.0 = Release|Win32 + {E8A3F4F4-0217-4775-9AC4-BD10E12298D4}.Template|Win32.ActiveCfg = Release|Win32 + {E8A3F4F4-0217-4775-9AC4-BD10E12298D4}.Template|Win32.Build.0 = Release|Win32 + {48ACE73F-73AD-43CC-99FB-35DFF71B8E9E}.Debug|Win32.ActiveCfg = Debug|Win32 + {48ACE73F-73AD-43CC-99FB-35DFF71B8E9E}.Debug|Win32.Build.0 = Debug|Win32 + {48ACE73F-73AD-43CC-99FB-35DFF71B8E9E}.DebugDll|Win32.ActiveCfg = Debug|Win32 + {48ACE73F-73AD-43CC-99FB-35DFF71B8E9E}.DebugDll|Win32.Build.0 = Debug|Win32 + {48ACE73F-73AD-43CC-99FB-35DFF71B8E9E}.Release|Win32.ActiveCfg = Release|Win32 + {48ACE73F-73AD-43CC-99FB-35DFF71B8E9E}.Release|Win32.Build.0 = Release|Win32 + {48ACE73F-73AD-43CC-99FB-35DFF71B8E9E}.Releasedll|Win32.ActiveCfg = Release|Win32 + {48ACE73F-73AD-43CC-99FB-35DFF71B8E9E}.Releasedll|Win32.Build.0 = Release|Win32 + {48ACE73F-73AD-43CC-99FB-35DFF71B8E9E}.Template|Win32.ActiveCfg = Release|Win32 + {48ACE73F-73AD-43CC-99FB-35DFF71B8E9E}.Template|Win32.Build.0 = Release|Win32 + {8D69EA4C-C980-4168-85B6-BAC9CB99E0DC}.Debug|Win32.ActiveCfg = Debug|Win32 + {8D69EA4C-C980-4168-85B6-BAC9CB99E0DC}.Debug|Win32.Build.0 = Debug|Win32 + {8D69EA4C-C980-4168-85B6-BAC9CB99E0DC}.DebugDll|Win32.ActiveCfg = Debug|Win32 + {8D69EA4C-C980-4168-85B6-BAC9CB99E0DC}.DebugDll|Win32.Build.0 = Debug|Win32 + {8D69EA4C-C980-4168-85B6-BAC9CB99E0DC}.Release|Win32.ActiveCfg = Release|Win32 + {8D69EA4C-C980-4168-85B6-BAC9CB99E0DC}.Release|Win32.Build.0 = Release|Win32 + {8D69EA4C-C980-4168-85B6-BAC9CB99E0DC}.Releasedll|Win32.ActiveCfg = Release|Win32 + {8D69EA4C-C980-4168-85B6-BAC9CB99E0DC}.Releasedll|Win32.Build.0 = Release|Win32 + {8D69EA4C-C980-4168-85B6-BAC9CB99E0DC}.Template|Win32.ActiveCfg = Release|Win32 + {8D69EA4C-C980-4168-85B6-BAC9CB99E0DC}.Template|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/acl_cpp_vc2012.sln b/acl_cpp_vc2012.sln new file mode 100644 index 000000000..183757dca --- /dev/null +++ b/acl_cpp_vc2012.sln @@ -0,0 +1,410 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lib_acl", "lib_acl\lib_acl_vc2012.vcxproj", "{B40213C2-507C-4C7F-A6E1-B850C9BDC27B}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lib_protocol", "lib_protocol\lib_protocol_vc2012.vcxproj", "{FE724EF7-3763-4E78-BDF5-BCBC075719FD}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lib_acl_cpp", "lib_acl_cpp\lib_acl_cpp_vc2012.vcxproj", "{6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lib_rpc", "lib_rpc\lib_rpc.vcxproj", "{2B0C9A86-6C14-4CEF-BD7A-4A6752386A44}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "aio_client", "lib_acl_cpp\samples\aio_client\aio_client_vc2012.vcxproj", "{9A04F86E-D4CB-45ED-9BB6-9939B9400B6F}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + {FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "aio_dns", "lib_acl_cpp\samples\aio_dns\aio_dns_vc2012.vcxproj", "{BE2DF8B2-2DCD-4F32-99B9-0B0CA24BFAD9}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + {FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "aio_ipc", "lib_acl_cpp\samples\aio_ipc\aio_ipc_vc2012.vcxproj", "{956FA905-A77F-41FE-A4BE-C3BD3B5B3E83}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + {FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "aio_server", "lib_acl_cpp\samples\aio_server\aio_server_vc2012.vcxproj", "{225D0BFA-64D7-4F8F-951E-36A494CF6178}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + {FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "final_class", "lib_acl_cpp\samples\final_class\final_class_vc2012.vcxproj", "{840C2263-DF87-4FD2-8964-EF81B74695FE}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "flock", "lib_acl_cpp\samples\flock\flock_vc2012.vcxproj", "{5F4063AD-B591-4C64-ADEA-609968A83550}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + {FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fstream", "lib_acl_cpp\samples\fstream\fstream_vc2012.vcxproj", "{7680672C-4C9B-4BE8-8BAE-BB23B951AAA0}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + {FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "http_client", "lib_acl_cpp\samples\http_client\http_client_vc2012.vcxproj", "{467619C7-C100-47B9-9A3B-7246A542EDC9}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + {FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HttpClient", "lib_acl_cpp\samples\HttpClient\HttpClient_vc2012.vcxproj", "{C0A7DB86-EF13-4A3E-9F34-8950521C9675}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "md5", "lib_acl_cpp\samples\md5\md5_vc2012.vcxproj", "{B8029C89-9870-4EE4-ADD0-E7852E0D1810}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mime", "lib_acl_cpp\samples\mime\mime_vc2012.vcxproj", "{52AA7352-CE48-4F60-B92D-1EB16A79FE54}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + {FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mime_base64", "lib_acl_cpp\samples\mime_base64\mime_base64_vc2012.vcxproj", "{19CB30E5-2672-4A8B-96FB-9C42970CCF69}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mime_qp", "lib_acl_cpp\samples\mime_qp\mime_qp_vc2012.vcxproj", "{5DC79C83-9DE8-46B3-A172-8A4E3371878B}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rfc2047", "lib_acl_cpp\samples\rfc2047\rfc2047_vc2012.vcxproj", "{503AFD46-DF2F-4D2B-8584-60AD2007D2BE}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "singleton", "lib_acl_cpp\samples\singleton\singleton_vc2012.vcxproj", "{128791D9-6787-471C-9A0C-0DCAE53F4911}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "socket_stream", "lib_acl_cpp\samples\socket_stream\socket_stream_vc2012.vcxproj", "{41FA5224-3315-4CDA-9C44-19085049F179}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "string", "lib_acl_cpp\samples\string\string_vc2012.vcxproj", "{C94BEF01-706C-49A7-9FF1-9D87FA5BB8E7}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "win_dbservice", "lib_acl_cpp\samples\win_dbservice\win_dbservice_vc2012.vcxproj", "{DC7E75E5-FE42-4529-9D9A-19D240B8727B}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "winaio", "lib_acl_cpp\samples\winaio\winaio_vc2012.vcxproj", "{ADE6F714-BD52-432D-AB86-62FA59AB6746}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xml", "lib_acl_cpp\samples\xml\xml_vc2012.vcxproj", "{2DABFAD1-114B-4F96-9185-DC0C56A3662D}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "http_request_pool", "lib_acl_cpp\samples\http_request_pool\http_request_pool_vc2012.vcxproj", "{58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + {FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "memcache_pool", "lib_acl_cpp\samples\memcache_pool\memcache_pool_vc2012.vcxproj", "{1F3F3884-7F9B-4BA1-8CA3-61E6758A7193}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + {FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD} + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + DebugDll|Win32 = DebugDll|Win32 + Release|Win32 = Release|Win32 + Releasedll|Win32 = Releasedll|Win32 + Template|Win32 = Template|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Debug|Win32.ActiveCfg = Debug|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Debug|Win32.Build.0 = Debug|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Release|Win32.ActiveCfg = Release|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Release|Win32.Build.0 = Release|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Releasedll|Win32.ActiveCfg = ReleaseDll|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Releasedll|Win32.Build.0 = ReleaseDll|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Template|Win32.ActiveCfg = Release|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Template|Win32.Build.0 = Release|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Debug|Win32.ActiveCfg = Debug|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Debug|Win32.Build.0 = Debug|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Release|Win32.ActiveCfg = Release|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Release|Win32.Build.0 = Release|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Releasedll|Win32.ActiveCfg = ReleaseDll|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Releasedll|Win32.Build.0 = ReleaseDll|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Template|Win32.ActiveCfg = Release|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Template|Win32.Build.0 = Release|Win32 + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.Debug|Win32.ActiveCfg = Debug|Win32 + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.Debug|Win32.Build.0 = Debug|Win32 + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.Release|Win32.ActiveCfg = Release|Win32 + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.Release|Win32.Build.0 = Release|Win32 + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.Releasedll|Win32.ActiveCfg = Releasedll|Win32 + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.Releasedll|Win32.Build.0 = Releasedll|Win32 + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.Template|Win32.ActiveCfg = Release|Win32 + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.Template|Win32.Build.0 = Release|Win32 + {2B0C9A86-6C14-4CEF-BD7A-4A6752386A44}.Debug|Win32.ActiveCfg = Debug|Win32 + {2B0C9A86-6C14-4CEF-BD7A-4A6752386A44}.Debug|Win32.Build.0 = Debug|Win32 + {2B0C9A86-6C14-4CEF-BD7A-4A6752386A44}.DebugDll|Win32.ActiveCfg = Debug|Win32 + {2B0C9A86-6C14-4CEF-BD7A-4A6752386A44}.DebugDll|Win32.Build.0 = Debug|Win32 + {2B0C9A86-6C14-4CEF-BD7A-4A6752386A44}.Release|Win32.ActiveCfg = Release|Win32 + {2B0C9A86-6C14-4CEF-BD7A-4A6752386A44}.Release|Win32.Build.0 = Release|Win32 + {2B0C9A86-6C14-4CEF-BD7A-4A6752386A44}.Releasedll|Win32.ActiveCfg = Release|Win32 + {2B0C9A86-6C14-4CEF-BD7A-4A6752386A44}.Releasedll|Win32.Build.0 = Release|Win32 + {2B0C9A86-6C14-4CEF-BD7A-4A6752386A44}.Template|Win32.ActiveCfg = Release|Win32 + {2B0C9A86-6C14-4CEF-BD7A-4A6752386A44}.Template|Win32.Build.0 = Release|Win32 + {9A04F86E-D4CB-45ED-9BB6-9939B9400B6F}.Debug|Win32.ActiveCfg = Debug|Win32 + {9A04F86E-D4CB-45ED-9BB6-9939B9400B6F}.Debug|Win32.Build.0 = Debug|Win32 + {9A04F86E-D4CB-45ED-9BB6-9939B9400B6F}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {9A04F86E-D4CB-45ED-9BB6-9939B9400B6F}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {9A04F86E-D4CB-45ED-9BB6-9939B9400B6F}.Release|Win32.ActiveCfg = Release|Win32 + {9A04F86E-D4CB-45ED-9BB6-9939B9400B6F}.Release|Win32.Build.0 = Release|Win32 + {9A04F86E-D4CB-45ED-9BB6-9939B9400B6F}.Releasedll|Win32.ActiveCfg = Releasedll|Win32 + {9A04F86E-D4CB-45ED-9BB6-9939B9400B6F}.Releasedll|Win32.Build.0 = Releasedll|Win32 + {9A04F86E-D4CB-45ED-9BB6-9939B9400B6F}.Template|Win32.ActiveCfg = DebugDll|Win32 + {9A04F86E-D4CB-45ED-9BB6-9939B9400B6F}.Template|Win32.Build.0 = DebugDll|Win32 + {BE2DF8B2-2DCD-4F32-99B9-0B0CA24BFAD9}.Debug|Win32.ActiveCfg = Debug|Win32 + {BE2DF8B2-2DCD-4F32-99B9-0B0CA24BFAD9}.Debug|Win32.Build.0 = Debug|Win32 + {BE2DF8B2-2DCD-4F32-99B9-0B0CA24BFAD9}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {BE2DF8B2-2DCD-4F32-99B9-0B0CA24BFAD9}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {BE2DF8B2-2DCD-4F32-99B9-0B0CA24BFAD9}.Release|Win32.ActiveCfg = Release|Win32 + {BE2DF8B2-2DCD-4F32-99B9-0B0CA24BFAD9}.Release|Win32.Build.0 = Release|Win32 + {BE2DF8B2-2DCD-4F32-99B9-0B0CA24BFAD9}.Releasedll|Win32.ActiveCfg = Releasedll|Win32 + {BE2DF8B2-2DCD-4F32-99B9-0B0CA24BFAD9}.Releasedll|Win32.Build.0 = Releasedll|Win32 + {BE2DF8B2-2DCD-4F32-99B9-0B0CA24BFAD9}.Template|Win32.ActiveCfg = DebugDll|Win32 + {BE2DF8B2-2DCD-4F32-99B9-0B0CA24BFAD9}.Template|Win32.Build.0 = DebugDll|Win32 + {956FA905-A77F-41FE-A4BE-C3BD3B5B3E83}.Debug|Win32.ActiveCfg = Debug|Win32 + {956FA905-A77F-41FE-A4BE-C3BD3B5B3E83}.Debug|Win32.Build.0 = Debug|Win32 + {956FA905-A77F-41FE-A4BE-C3BD3B5B3E83}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {956FA905-A77F-41FE-A4BE-C3BD3B5B3E83}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {956FA905-A77F-41FE-A4BE-C3BD3B5B3E83}.Release|Win32.ActiveCfg = Release|Win32 + {956FA905-A77F-41FE-A4BE-C3BD3B5B3E83}.Release|Win32.Build.0 = Release|Win32 + {956FA905-A77F-41FE-A4BE-C3BD3B5B3E83}.Releasedll|Win32.ActiveCfg = Releasedll|Win32 + {956FA905-A77F-41FE-A4BE-C3BD3B5B3E83}.Releasedll|Win32.Build.0 = Releasedll|Win32 + {956FA905-A77F-41FE-A4BE-C3BD3B5B3E83}.Template|Win32.ActiveCfg = DebugDll|Win32 + {956FA905-A77F-41FE-A4BE-C3BD3B5B3E83}.Template|Win32.Build.0 = DebugDll|Win32 + {225D0BFA-64D7-4F8F-951E-36A494CF6178}.Debug|Win32.ActiveCfg = Debug|Win32 + {225D0BFA-64D7-4F8F-951E-36A494CF6178}.Debug|Win32.Build.0 = Debug|Win32 + {225D0BFA-64D7-4F8F-951E-36A494CF6178}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {225D0BFA-64D7-4F8F-951E-36A494CF6178}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {225D0BFA-64D7-4F8F-951E-36A494CF6178}.Release|Win32.ActiveCfg = Release|Win32 + {225D0BFA-64D7-4F8F-951E-36A494CF6178}.Release|Win32.Build.0 = Release|Win32 + {225D0BFA-64D7-4F8F-951E-36A494CF6178}.Releasedll|Win32.ActiveCfg = Releasedll|Win32 + {225D0BFA-64D7-4F8F-951E-36A494CF6178}.Releasedll|Win32.Build.0 = Releasedll|Win32 + {225D0BFA-64D7-4F8F-951E-36A494CF6178}.Template|Win32.ActiveCfg = DebugDll|Win32 + {225D0BFA-64D7-4F8F-951E-36A494CF6178}.Template|Win32.Build.0 = DebugDll|Win32 + {840C2263-DF87-4FD2-8964-EF81B74695FE}.Debug|Win32.ActiveCfg = Debug|Win32 + {840C2263-DF87-4FD2-8964-EF81B74695FE}.Debug|Win32.Build.0 = Debug|Win32 + {840C2263-DF87-4FD2-8964-EF81B74695FE}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {840C2263-DF87-4FD2-8964-EF81B74695FE}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {840C2263-DF87-4FD2-8964-EF81B74695FE}.Release|Win32.ActiveCfg = Release|Win32 + {840C2263-DF87-4FD2-8964-EF81B74695FE}.Release|Win32.Build.0 = Release|Win32 + {840C2263-DF87-4FD2-8964-EF81B74695FE}.Releasedll|Win32.ActiveCfg = ReleaseDll|Win32 + {840C2263-DF87-4FD2-8964-EF81B74695FE}.Releasedll|Win32.Build.0 = ReleaseDll|Win32 + {840C2263-DF87-4FD2-8964-EF81B74695FE}.Template|Win32.ActiveCfg = DebugDll|Win32 + {840C2263-DF87-4FD2-8964-EF81B74695FE}.Template|Win32.Build.0 = DebugDll|Win32 + {5F4063AD-B591-4C64-ADEA-609968A83550}.Debug|Win32.ActiveCfg = Debug|Win32 + {5F4063AD-B591-4C64-ADEA-609968A83550}.Debug|Win32.Build.0 = Debug|Win32 + {5F4063AD-B591-4C64-ADEA-609968A83550}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {5F4063AD-B591-4C64-ADEA-609968A83550}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {5F4063AD-B591-4C64-ADEA-609968A83550}.Release|Win32.ActiveCfg = Release|Win32 + {5F4063AD-B591-4C64-ADEA-609968A83550}.Release|Win32.Build.0 = Release|Win32 + {5F4063AD-B591-4C64-ADEA-609968A83550}.Releasedll|Win32.ActiveCfg = Releasedll|Win32 + {5F4063AD-B591-4C64-ADEA-609968A83550}.Releasedll|Win32.Build.0 = Releasedll|Win32 + {5F4063AD-B591-4C64-ADEA-609968A83550}.Template|Win32.ActiveCfg = DebugDll|Win32 + {5F4063AD-B591-4C64-ADEA-609968A83550}.Template|Win32.Build.0 = DebugDll|Win32 + {7680672C-4C9B-4BE8-8BAE-BB23B951AAA0}.Debug|Win32.ActiveCfg = Debug|Win32 + {7680672C-4C9B-4BE8-8BAE-BB23B951AAA0}.Debug|Win32.Build.0 = Debug|Win32 + {7680672C-4C9B-4BE8-8BAE-BB23B951AAA0}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {7680672C-4C9B-4BE8-8BAE-BB23B951AAA0}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {7680672C-4C9B-4BE8-8BAE-BB23B951AAA0}.Release|Win32.ActiveCfg = Release|Win32 + {7680672C-4C9B-4BE8-8BAE-BB23B951AAA0}.Release|Win32.Build.0 = Release|Win32 + {7680672C-4C9B-4BE8-8BAE-BB23B951AAA0}.Releasedll|Win32.ActiveCfg = Releasedll|Win32 + {7680672C-4C9B-4BE8-8BAE-BB23B951AAA0}.Releasedll|Win32.Build.0 = Releasedll|Win32 + {7680672C-4C9B-4BE8-8BAE-BB23B951AAA0}.Template|Win32.ActiveCfg = DebugDll|Win32 + {7680672C-4C9B-4BE8-8BAE-BB23B951AAA0}.Template|Win32.Build.0 = DebugDll|Win32 + {467619C7-C100-47B9-9A3B-7246A542EDC9}.Debug|Win32.ActiveCfg = Debug|Win32 + {467619C7-C100-47B9-9A3B-7246A542EDC9}.Debug|Win32.Build.0 = Debug|Win32 + {467619C7-C100-47B9-9A3B-7246A542EDC9}.DebugDll|Win32.ActiveCfg = Debugdll|Win32 + {467619C7-C100-47B9-9A3B-7246A542EDC9}.DebugDll|Win32.Build.0 = Debugdll|Win32 + {467619C7-C100-47B9-9A3B-7246A542EDC9}.Release|Win32.ActiveCfg = Release|Win32 + {467619C7-C100-47B9-9A3B-7246A542EDC9}.Release|Win32.Build.0 = Release|Win32 + {467619C7-C100-47B9-9A3B-7246A542EDC9}.Releasedll|Win32.ActiveCfg = Releasedll|Win32 + {467619C7-C100-47B9-9A3B-7246A542EDC9}.Releasedll|Win32.Build.0 = Releasedll|Win32 + {467619C7-C100-47B9-9A3B-7246A542EDC9}.Template|Win32.ActiveCfg = Debugdll|Win32 + {467619C7-C100-47B9-9A3B-7246A542EDC9}.Template|Win32.Build.0 = Debugdll|Win32 + {C0A7DB86-EF13-4A3E-9F34-8950521C9675}.Debug|Win32.ActiveCfg = Debug|Win32 + {C0A7DB86-EF13-4A3E-9F34-8950521C9675}.Debug|Win32.Build.0 = Debug|Win32 + {C0A7DB86-EF13-4A3E-9F34-8950521C9675}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {C0A7DB86-EF13-4A3E-9F34-8950521C9675}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {C0A7DB86-EF13-4A3E-9F34-8950521C9675}.Release|Win32.ActiveCfg = Release|Win32 + {C0A7DB86-EF13-4A3E-9F34-8950521C9675}.Release|Win32.Build.0 = Release|Win32 + {C0A7DB86-EF13-4A3E-9F34-8950521C9675}.Releasedll|Win32.ActiveCfg = Releasedll|Win32 + {C0A7DB86-EF13-4A3E-9F34-8950521C9675}.Releasedll|Win32.Build.0 = Releasedll|Win32 + {C0A7DB86-EF13-4A3E-9F34-8950521C9675}.Template|Win32.ActiveCfg = Template|Win32 + {C0A7DB86-EF13-4A3E-9F34-8950521C9675}.Template|Win32.Build.0 = Template|Win32 + {B8029C89-9870-4EE4-ADD0-E7852E0D1810}.Debug|Win32.ActiveCfg = Debug|Win32 + {B8029C89-9870-4EE4-ADD0-E7852E0D1810}.Debug|Win32.Build.0 = Debug|Win32 + {B8029C89-9870-4EE4-ADD0-E7852E0D1810}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {B8029C89-9870-4EE4-ADD0-E7852E0D1810}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {B8029C89-9870-4EE4-ADD0-E7852E0D1810}.Release|Win32.ActiveCfg = Release|Win32 + {B8029C89-9870-4EE4-ADD0-E7852E0D1810}.Release|Win32.Build.0 = Release|Win32 + {B8029C89-9870-4EE4-ADD0-E7852E0D1810}.Releasedll|Win32.ActiveCfg = ReleaseDll|Win32 + {B8029C89-9870-4EE4-ADD0-E7852E0D1810}.Releasedll|Win32.Build.0 = ReleaseDll|Win32 + {B8029C89-9870-4EE4-ADD0-E7852E0D1810}.Template|Win32.ActiveCfg = DebugDll|Win32 + {B8029C89-9870-4EE4-ADD0-E7852E0D1810}.Template|Win32.Build.0 = DebugDll|Win32 + {52AA7352-CE48-4F60-B92D-1EB16A79FE54}.Debug|Win32.ActiveCfg = Debug|Win32 + {52AA7352-CE48-4F60-B92D-1EB16A79FE54}.Debug|Win32.Build.0 = Debug|Win32 + {52AA7352-CE48-4F60-B92D-1EB16A79FE54}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {52AA7352-CE48-4F60-B92D-1EB16A79FE54}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {52AA7352-CE48-4F60-B92D-1EB16A79FE54}.Release|Win32.ActiveCfg = Release|Win32 + {52AA7352-CE48-4F60-B92D-1EB16A79FE54}.Release|Win32.Build.0 = Release|Win32 + {52AA7352-CE48-4F60-B92D-1EB16A79FE54}.Releasedll|Win32.ActiveCfg = Releasedll|Win32 + {52AA7352-CE48-4F60-B92D-1EB16A79FE54}.Releasedll|Win32.Build.0 = Releasedll|Win32 + {52AA7352-CE48-4F60-B92D-1EB16A79FE54}.Template|Win32.ActiveCfg = DebugDll|Win32 + {52AA7352-CE48-4F60-B92D-1EB16A79FE54}.Template|Win32.Build.0 = DebugDll|Win32 + {19CB30E5-2672-4A8B-96FB-9C42970CCF69}.Debug|Win32.ActiveCfg = Debug|Win32 + {19CB30E5-2672-4A8B-96FB-9C42970CCF69}.Debug|Win32.Build.0 = Debug|Win32 + {19CB30E5-2672-4A8B-96FB-9C42970CCF69}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {19CB30E5-2672-4A8B-96FB-9C42970CCF69}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {19CB30E5-2672-4A8B-96FB-9C42970CCF69}.Release|Win32.ActiveCfg = Release|Win32 + {19CB30E5-2672-4A8B-96FB-9C42970CCF69}.Release|Win32.Build.0 = Release|Win32 + {19CB30E5-2672-4A8B-96FB-9C42970CCF69}.Releasedll|Win32.ActiveCfg = Releasedll|Win32 + {19CB30E5-2672-4A8B-96FB-9C42970CCF69}.Releasedll|Win32.Build.0 = Releasedll|Win32 + {19CB30E5-2672-4A8B-96FB-9C42970CCF69}.Template|Win32.ActiveCfg = DebugDll|Win32 + {19CB30E5-2672-4A8B-96FB-9C42970CCF69}.Template|Win32.Build.0 = DebugDll|Win32 + {5DC79C83-9DE8-46B3-A172-8A4E3371878B}.Debug|Win32.ActiveCfg = Debug|Win32 + {5DC79C83-9DE8-46B3-A172-8A4E3371878B}.Debug|Win32.Build.0 = Debug|Win32 + {5DC79C83-9DE8-46B3-A172-8A4E3371878B}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {5DC79C83-9DE8-46B3-A172-8A4E3371878B}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {5DC79C83-9DE8-46B3-A172-8A4E3371878B}.Release|Win32.ActiveCfg = Release|Win32 + {5DC79C83-9DE8-46B3-A172-8A4E3371878B}.Release|Win32.Build.0 = Release|Win32 + {5DC79C83-9DE8-46B3-A172-8A4E3371878B}.Releasedll|Win32.ActiveCfg = Releasedll|Win32 + {5DC79C83-9DE8-46B3-A172-8A4E3371878B}.Releasedll|Win32.Build.0 = Releasedll|Win32 + {5DC79C83-9DE8-46B3-A172-8A4E3371878B}.Template|Win32.ActiveCfg = DebugDll|Win32 + {5DC79C83-9DE8-46B3-A172-8A4E3371878B}.Template|Win32.Build.0 = DebugDll|Win32 + {503AFD46-DF2F-4D2B-8584-60AD2007D2BE}.Debug|Win32.ActiveCfg = Debug|Win32 + {503AFD46-DF2F-4D2B-8584-60AD2007D2BE}.Debug|Win32.Build.0 = Debug|Win32 + {503AFD46-DF2F-4D2B-8584-60AD2007D2BE}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {503AFD46-DF2F-4D2B-8584-60AD2007D2BE}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {503AFD46-DF2F-4D2B-8584-60AD2007D2BE}.Release|Win32.ActiveCfg = Release|Win32 + {503AFD46-DF2F-4D2B-8584-60AD2007D2BE}.Release|Win32.Build.0 = Release|Win32 + {503AFD46-DF2F-4D2B-8584-60AD2007D2BE}.Releasedll|Win32.ActiveCfg = Releasedll|Win32 + {503AFD46-DF2F-4D2B-8584-60AD2007D2BE}.Releasedll|Win32.Build.0 = Releasedll|Win32 + {503AFD46-DF2F-4D2B-8584-60AD2007D2BE}.Template|Win32.ActiveCfg = DebugDll|Win32 + {503AFD46-DF2F-4D2B-8584-60AD2007D2BE}.Template|Win32.Build.0 = DebugDll|Win32 + {128791D9-6787-471C-9A0C-0DCAE53F4911}.Debug|Win32.ActiveCfg = Debug|Win32 + {128791D9-6787-471C-9A0C-0DCAE53F4911}.Debug|Win32.Build.0 = Debug|Win32 + {128791D9-6787-471C-9A0C-0DCAE53F4911}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {128791D9-6787-471C-9A0C-0DCAE53F4911}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {128791D9-6787-471C-9A0C-0DCAE53F4911}.Release|Win32.ActiveCfg = Release|Win32 + {128791D9-6787-471C-9A0C-0DCAE53F4911}.Release|Win32.Build.0 = Release|Win32 + {128791D9-6787-471C-9A0C-0DCAE53F4911}.Releasedll|Win32.ActiveCfg = ReleaseDll|Win32 + {128791D9-6787-471C-9A0C-0DCAE53F4911}.Releasedll|Win32.Build.0 = ReleaseDll|Win32 + {128791D9-6787-471C-9A0C-0DCAE53F4911}.Template|Win32.ActiveCfg = DebugDll|Win32 + {128791D9-6787-471C-9A0C-0DCAE53F4911}.Template|Win32.Build.0 = DebugDll|Win32 + {41FA5224-3315-4CDA-9C44-19085049F179}.Debug|Win32.ActiveCfg = Debug|Win32 + {41FA5224-3315-4CDA-9C44-19085049F179}.Debug|Win32.Build.0 = Debug|Win32 + {41FA5224-3315-4CDA-9C44-19085049F179}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {41FA5224-3315-4CDA-9C44-19085049F179}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {41FA5224-3315-4CDA-9C44-19085049F179}.Release|Win32.ActiveCfg = Release|Win32 + {41FA5224-3315-4CDA-9C44-19085049F179}.Release|Win32.Build.0 = Release|Win32 + {41FA5224-3315-4CDA-9C44-19085049F179}.Releasedll|Win32.ActiveCfg = Releasedll|Win32 + {41FA5224-3315-4CDA-9C44-19085049F179}.Releasedll|Win32.Build.0 = Releasedll|Win32 + {41FA5224-3315-4CDA-9C44-19085049F179}.Template|Win32.ActiveCfg = DebugDll|Win32 + {41FA5224-3315-4CDA-9C44-19085049F179}.Template|Win32.Build.0 = DebugDll|Win32 + {C94BEF01-706C-49A7-9FF1-9D87FA5BB8E7}.Debug|Win32.ActiveCfg = Debug|Win32 + {C94BEF01-706C-49A7-9FF1-9D87FA5BB8E7}.Debug|Win32.Build.0 = Debug|Win32 + {C94BEF01-706C-49A7-9FF1-9D87FA5BB8E7}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {C94BEF01-706C-49A7-9FF1-9D87FA5BB8E7}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {C94BEF01-706C-49A7-9FF1-9D87FA5BB8E7}.Release|Win32.ActiveCfg = Release|Win32 + {C94BEF01-706C-49A7-9FF1-9D87FA5BB8E7}.Release|Win32.Build.0 = Release|Win32 + {C94BEF01-706C-49A7-9FF1-9D87FA5BB8E7}.Releasedll|Win32.ActiveCfg = Releasedll|Win32 + {C94BEF01-706C-49A7-9FF1-9D87FA5BB8E7}.Releasedll|Win32.Build.0 = Releasedll|Win32 + {C94BEF01-706C-49A7-9FF1-9D87FA5BB8E7}.Template|Win32.ActiveCfg = DebugDll|Win32 + {C94BEF01-706C-49A7-9FF1-9D87FA5BB8E7}.Template|Win32.Build.0 = DebugDll|Win32 + {DC7E75E5-FE42-4529-9D9A-19D240B8727B}.Debug|Win32.ActiveCfg = Debug|Win32 + {DC7E75E5-FE42-4529-9D9A-19D240B8727B}.Debug|Win32.Build.0 = Debug|Win32 + {DC7E75E5-FE42-4529-9D9A-19D240B8727B}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {DC7E75E5-FE42-4529-9D9A-19D240B8727B}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {DC7E75E5-FE42-4529-9D9A-19D240B8727B}.Release|Win32.ActiveCfg = Release|Win32 + {DC7E75E5-FE42-4529-9D9A-19D240B8727B}.Release|Win32.Build.0 = Release|Win32 + {DC7E75E5-FE42-4529-9D9A-19D240B8727B}.Releasedll|Win32.ActiveCfg = ReleaseDll|Win32 + {DC7E75E5-FE42-4529-9D9A-19D240B8727B}.Releasedll|Win32.Build.0 = ReleaseDll|Win32 + {DC7E75E5-FE42-4529-9D9A-19D240B8727B}.Template|Win32.ActiveCfg = Template|Win32 + {DC7E75E5-FE42-4529-9D9A-19D240B8727B}.Template|Win32.Build.0 = Template|Win32 + {ADE6F714-BD52-432D-AB86-62FA59AB6746}.Debug|Win32.ActiveCfg = Debug|Win32 + {ADE6F714-BD52-432D-AB86-62FA59AB6746}.Debug|Win32.Build.0 = Debug|Win32 + {ADE6F714-BD52-432D-AB86-62FA59AB6746}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {ADE6F714-BD52-432D-AB86-62FA59AB6746}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {ADE6F714-BD52-432D-AB86-62FA59AB6746}.Release|Win32.ActiveCfg = Release|Win32 + {ADE6F714-BD52-432D-AB86-62FA59AB6746}.Release|Win32.Build.0 = Release|Win32 + {ADE6F714-BD52-432D-AB86-62FA59AB6746}.Releasedll|Win32.ActiveCfg = Releasedll|Win32 + {ADE6F714-BD52-432D-AB86-62FA59AB6746}.Releasedll|Win32.Build.0 = Releasedll|Win32 + {ADE6F714-BD52-432D-AB86-62FA59AB6746}.Template|Win32.ActiveCfg = Template|Win32 + {ADE6F714-BD52-432D-AB86-62FA59AB6746}.Template|Win32.Build.0 = Template|Win32 + {2DABFAD1-114B-4F96-9185-DC0C56A3662D}.Debug|Win32.ActiveCfg = Debug|Win32 + {2DABFAD1-114B-4F96-9185-DC0C56A3662D}.Debug|Win32.Build.0 = Debug|Win32 + {2DABFAD1-114B-4F96-9185-DC0C56A3662D}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {2DABFAD1-114B-4F96-9185-DC0C56A3662D}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {2DABFAD1-114B-4F96-9185-DC0C56A3662D}.Release|Win32.ActiveCfg = Release|Win32 + {2DABFAD1-114B-4F96-9185-DC0C56A3662D}.Release|Win32.Build.0 = Release|Win32 + {2DABFAD1-114B-4F96-9185-DC0C56A3662D}.Releasedll|Win32.ActiveCfg = Releasedll|Win32 + {2DABFAD1-114B-4F96-9185-DC0C56A3662D}.Releasedll|Win32.Build.0 = Releasedll|Win32 + {2DABFAD1-114B-4F96-9185-DC0C56A3662D}.Template|Win32.ActiveCfg = DebugDll|Win32 + {2DABFAD1-114B-4F96-9185-DC0C56A3662D}.Template|Win32.Build.0 = DebugDll|Win32 + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.Debug|Win32.ActiveCfg = Debug|Win32 + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.Debug|Win32.Build.0 = Debug|Win32 + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.Release|Win32.ActiveCfg = Release|Win32 + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.Release|Win32.Build.0 = Release|Win32 + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.Releasedll|Win32.ActiveCfg = ReleaseDll|Win32 + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.Releasedll|Win32.Build.0 = ReleaseDll|Win32 + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.Template|Win32.ActiveCfg = DebugDll|Win32 + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.Template|Win32.Build.0 = DebugDll|Win32 + {1F3F3884-7F9B-4BA1-8CA3-61E6758A7193}.Debug|Win32.ActiveCfg = Debug|Win32 + {1F3F3884-7F9B-4BA1-8CA3-61E6758A7193}.Debug|Win32.Build.0 = Debug|Win32 + {1F3F3884-7F9B-4BA1-8CA3-61E6758A7193}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {1F3F3884-7F9B-4BA1-8CA3-61E6758A7193}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {1F3F3884-7F9B-4BA1-8CA3-61E6758A7193}.Release|Win32.ActiveCfg = Release|Win32 + {1F3F3884-7F9B-4BA1-8CA3-61E6758A7193}.Release|Win32.Build.0 = Release|Win32 + {1F3F3884-7F9B-4BA1-8CA3-61E6758A7193}.Releasedll|Win32.ActiveCfg = ReleaseDll|Win32 + {1F3F3884-7F9B-4BA1-8CA3-61E6758A7193}.Releasedll|Win32.Build.0 = ReleaseDll|Win32 + {1F3F3884-7F9B-4BA1-8CA3-61E6758A7193}.Template|Win32.ActiveCfg = DebugDll|Win32 + {1F3F3884-7F9B-4BA1-8CA3-61E6758A7193}.Template|Win32.Build.0 = DebugDll|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/acl_vc2003.sln b/acl_vc2003.sln new file mode 100644 index 000000000..bf2bf5109 --- /dev/null +++ b/acl_vc2003.sln @@ -0,0 +1,66 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lib_acl", "lib_acl\lib_acl_vc2003.vcproj", "{B40213C2-507C-4C7F-A6E1-B850C9BDC27B}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lib_protocol", "lib_protocol\lib_protocol_vc2003.vcproj", "{FE724EF7-3763-4E78-BDF5-BCBC075719FD}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lib_dict", "lib_dict\lib_dict.vcproj", "{9E6E9FE9-EAAC-44BA-B463-70DE0233822E}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lib_tls", "lib_tls\lib_tls.vcproj", "{389FDE47-7F16-4DD4-B37A-27918BE745B6}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + DebugDll = DebugDll + Release = Release + ReleaseDll = ReleaseDll + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Debug.ActiveCfg = Debug|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Debug.Build.0 = Debug|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.DebugDll.ActiveCfg = DebugDll|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.DebugDll.Build.0 = DebugDll|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Release.ActiveCfg = Release|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Release.Build.0 = Release|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.ReleaseDll.ActiveCfg = ReleaseDll|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.ReleaseDll.Build.0 = ReleaseDll|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Debug.ActiveCfg = Debug|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Debug.Build.0 = Debug|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.DebugDll.ActiveCfg = DebugDll|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.DebugDll.Build.0 = DebugDll|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Release.ActiveCfg = Release|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Release.Build.0 = Release|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.ReleaseDll.ActiveCfg = ReleaseDll|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.ReleaseDll.Build.0 = ReleaseDll|Win32 + {9E6E9FE9-EAAC-44BA-B463-70DE0233822E}.Debug.ActiveCfg = Debug|Win32 + {9E6E9FE9-EAAC-44BA-B463-70DE0233822E}.Debug.Build.0 = Debug|Win32 + {9E6E9FE9-EAAC-44BA-B463-70DE0233822E}.DebugDll.ActiveCfg = DebugDll|Win32 + {9E6E9FE9-EAAC-44BA-B463-70DE0233822E}.DebugDll.Build.0 = DebugDll|Win32 + {9E6E9FE9-EAAC-44BA-B463-70DE0233822E}.Release.ActiveCfg = Release|Win32 + {9E6E9FE9-EAAC-44BA-B463-70DE0233822E}.Release.Build.0 = Release|Win32 + {9E6E9FE9-EAAC-44BA-B463-70DE0233822E}.ReleaseDll.ActiveCfg = ReleaseDll|Win32 + {9E6E9FE9-EAAC-44BA-B463-70DE0233822E}.ReleaseDll.Build.0 = ReleaseDll|Win32 + {389FDE47-7F16-4DD4-B37A-27918BE745B6}.Debug.ActiveCfg = Debug|Win32 + {389FDE47-7F16-4DD4-B37A-27918BE745B6}.Debug.Build.0 = Debug|Win32 + {389FDE47-7F16-4DD4-B37A-27918BE745B6}.DebugDll.ActiveCfg = DebugDll|Win32 + {389FDE47-7F16-4DD4-B37A-27918BE745B6}.DebugDll.Build.0 = DebugDll|Win32 + {389FDE47-7F16-4DD4-B37A-27918BE745B6}.Release.ActiveCfg = Release|Win32 + {389FDE47-7F16-4DD4-B37A-27918BE745B6}.Release.Build.0 = Release|Win32 + {389FDE47-7F16-4DD4-B37A-27918BE745B6}.ReleaseDll.ActiveCfg = ReleaseDll|Win32 + {389FDE47-7F16-4DD4-B37A-27918BE745B6}.ReleaseDll.Build.0 = ReleaseDll|Win32 + EndGlobalSection + GlobalSection(SolutionItems) = postSolution + changes.txt = changes.txt + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/acl_vc2010.sln b/acl_vc2010.sln new file mode 100644 index 000000000..c8a02c4b9 --- /dev/null +++ b/acl_vc2010.sln @@ -0,0 +1,60 @@ +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lib_acl", "lib_acl\lib_acl_vc2010.vcxproj", "{B40213C2-507C-4C7F-A6E1-B850C9BDC27B}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lib_protocol", "lib_protocol\lib_protocol_vc2010.vcxproj", "{FE724EF7-3763-4E78-BDF5-BCBC075719FD}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lib_dict", "lib_dict\lib_dict.vcxproj", "{9E6E9FE9-EAAC-44BA-B463-70DE0233822E}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lib_tls", "lib_tls\lib_tls.vcxproj", "{389FDE47-7F16-4DD4-B37A-27918BE745B6}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{2597AF7B-516E-478A-B72E-0BC8A59E8965}" + ProjectSection(SolutionItems) = preProject + ..\changes.txt = ..\changes.txt + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + DebugDll|Win32 = DebugDll|Win32 + Release|Win32 = Release|Win32 + ReleaseDll|Win32 = ReleaseDll|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Debug|Win32.ActiveCfg = Debug|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Debug|Win32.Build.0 = Debug|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Release|Win32.ActiveCfg = Release|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Release|Win32.Build.0 = Release|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.ReleaseDll|Win32.ActiveCfg = ReleaseDll|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.ReleaseDll|Win32.Build.0 = ReleaseDll|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Debug|Win32.ActiveCfg = Debug|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Debug|Win32.Build.0 = Debug|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Release|Win32.ActiveCfg = Release|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Release|Win32.Build.0 = Release|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.ReleaseDll|Win32.ActiveCfg = ReleaseDll|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.ReleaseDll|Win32.Build.0 = ReleaseDll|Win32 + {9E6E9FE9-EAAC-44BA-B463-70DE0233822E}.Debug|Win32.ActiveCfg = Debug|Win32 + {9E6E9FE9-EAAC-44BA-B463-70DE0233822E}.Debug|Win32.Build.0 = Debug|Win32 + {9E6E9FE9-EAAC-44BA-B463-70DE0233822E}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {9E6E9FE9-EAAC-44BA-B463-70DE0233822E}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {9E6E9FE9-EAAC-44BA-B463-70DE0233822E}.Release|Win32.ActiveCfg = Release|Win32 + {9E6E9FE9-EAAC-44BA-B463-70DE0233822E}.Release|Win32.Build.0 = Release|Win32 + {9E6E9FE9-EAAC-44BA-B463-70DE0233822E}.ReleaseDll|Win32.ActiveCfg = ReleaseDll|Win32 + {9E6E9FE9-EAAC-44BA-B463-70DE0233822E}.ReleaseDll|Win32.Build.0 = ReleaseDll|Win32 + {389FDE47-7F16-4DD4-B37A-27918BE745B6}.Debug|Win32.ActiveCfg = Debug|Win32 + {389FDE47-7F16-4DD4-B37A-27918BE745B6}.Debug|Win32.Build.0 = Debug|Win32 + {389FDE47-7F16-4DD4-B37A-27918BE745B6}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {389FDE47-7F16-4DD4-B37A-27918BE745B6}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {389FDE47-7F16-4DD4-B37A-27918BE745B6}.Release|Win32.ActiveCfg = Release|Win32 + {389FDE47-7F16-4DD4-B37A-27918BE745B6}.Release|Win32.Build.0 = Release|Win32 + {389FDE47-7F16-4DD4-B37A-27918BE745B6}.ReleaseDll|Win32.ActiveCfg = ReleaseDll|Win32 + {389FDE47-7F16-4DD4-B37A-27918BE745B6}.ReleaseDll|Win32.Build.0 = ReleaseDll|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/acl_vc2012.sln b/acl_vc2012.sln new file mode 100644 index 000000000..65683b677 --- /dev/null +++ b/acl_vc2012.sln @@ -0,0 +1,37 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lib_acl", "lib_acl\lib_acl_vc2012.vcxproj", "{B40213C2-507C-4C7F-A6E1-B850C9BDC27B}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lib_protocol", "lib_protocol\lib_protocol_vc2012.vcxproj", "{FE724EF7-3763-4E78-BDF5-BCBC075719FD}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{2597AF7B-516E-478A-B72E-0BC8A59E8965}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + DebugDll|Win32 = DebugDll|Win32 + Release|Win32 = Release|Win32 + ReleaseDll|Win32 = ReleaseDll|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Debug|Win32.ActiveCfg = Debug|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Debug|Win32.Build.0 = Debug|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Release|Win32.ActiveCfg = Release|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Release|Win32.Build.0 = Release|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.ReleaseDll|Win32.ActiveCfg = ReleaseDll|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.ReleaseDll|Win32.Build.0 = ReleaseDll|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Debug|Win32.ActiveCfg = Debug|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Debug|Win32.Build.0 = Debug|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Release|Win32.ActiveCfg = Release|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Release|Win32.Build.0 = Release|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.ReleaseDll|Win32.ActiveCfg = ReleaseDll|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.ReleaseDll|Win32.Build.0 = ReleaseDll|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/app/Makefile.in b/app/Makefile.in new file mode 100644 index 000000000..e9b1edaa1 --- /dev/null +++ b/app/Makefile.in @@ -0,0 +1,93 @@ +CC = g++ + +CFLAGS = -c -g -W -Wall -Wcast-qual -Wcast-align \ +-Waggregate-return -Wno-long-long \ +-Wpointer-arith -Werror -Wshadow -O3 \ +-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO + +########################################################### +#Check system: +# Linux, SunOS, Solaris, BSD variants, AIX, HP-UX +SYSLIB = -lpthread -lcrypt -lz +CHECKSYSRES = @echo "Unknow system type!";exit 1 +UNIXNAME = $(shell uname -sm) + +ifeq ($(CC),) + CC = gcc +endif + +# For FreeBSD +ifeq ($(findstring FreeBSD, $(UNIXNAME)), FreeBSD) + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DFREEBSD -D_REENTRANT + SYSLIB = -lcrypt -lpthread +endif + +#Path for Linux +ifeq ($(findstring Linux, $(UNIXNAME)), Linux) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DLINUX2 -D_REENTRANT +endif + +#Path for SunOS +ifeq ($(findstring SunOS, $(UNIXNAME)), SunOS) + ifeq ($(findstring 86, $(UNIXNAME)), 86) + SYSLIB += -lsocket -lnsl -lrt + endif + ifeq ($(findstring sun4u, $(UNIXNAME)), sun4u) + SYSLIB += -lsocket -lnsl -lrt + endif + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DSUNOS5 -D_REENTRANT +endif + +#Path for HP-UX +ifeq ($(findstring HP-UX, $(UNIXNAME)), HP-UX) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DHP_UX -DHPUX11 + PLAT_NAME=hp-ux +endif + +#Find system type. +ifneq ($(SYSPATH),) + CHECKSYSRES = @echo "System is $(shell uname -sm)" +endif +########################################################### + +CFLAGS += -I../../lib_acl/include -I../../lib_protocol/include -I../../lib_acl_cpp/include +EXTLIBS = +LDFLAGS = -L../../lib_acl_cpp/lib -l_acl_cpp -L../../lib_protocol/lib -l_protocol -L../../lib_acl/lib -l_acl \ + $(EXTLIBS) $(SYSLIB) + +COMPILE = $(CC) $(CFLAGS) +LINK = $(CC) $(OBJ) $(LDFLAGS) +########################################################### +OBJ_PATH = . + +#Project's objs +SRC = $(wildcard *.cpp) +OBJ = $(patsubst %.cpp, $(OBJ_PATH)/%.o, $(notdir $(SRC))) + +$(OBJ_PATH)/%.o: %.cpp + $(COMPILE) $< -o $@ + +.PHONY = all clean +all: RM $(OBJ) + $(LINK) -o $(PROG) + @echo "" + @echo "All ok! Output:$(PROG)" + @echo "" +RM: + rm -f $(PROG) +clean: + rm -f $(PROG) + rm -f $(OBJ) +########################################################### diff --git a/app/gid/gid_client/c/Makefile b/app/gid/gid_client/c/Makefile new file mode 100644 index 000000000..974e6a2a4 --- /dev/null +++ b/app/gid/gid_client/c/Makefile @@ -0,0 +1,97 @@ +SHELL = /bin/sh +CC = gcc +AR = ar +ARFL = rv +#ARFL = cru +RANLIB = ranlib + +CFLAGS = -c -g -W -Wall -Wcast-qual -Wcast-align \ +-Wpointer-arith -Werror -Wshadow -O3 \ +-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS \ +-Wno-long-long \ +-Wno-unused-parameter \ +-fPIC -Wno-unknown-pragmas \ +-DUSE_SERVICE_CLIENT +########################################################### +#Check system: +# Linux, SunOS, Solaris, BSD variants, AIX, HP-UX +SYSLIB = +CHECKSYSRES = @echo "Unknow system type!";exit 1 +UNIXNAME = $(shell uname -sm) + +ifeq ($(CC),) + CC = g++ +endif + +# For FreeBSD +ifeq ($(findstring FreeBSD, $(UNIXNAME)), FreeBSD) + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DFREEBSD -D_REENTRANT +endif + +# For Linux +ifeq ($(findstring Linux, $(UNIXNAME)), Linux) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DLINUX2 -D_REENTRANT +endif + +# For SunOS +ifeq ($(findstring SunOS, $(UNIXNAME)), SunOS) + ifeq ($(findstring 86, $(UNIXNAME)), 86) + SYSLIB = -lsocket -lnsl -lrt + endif + ifeq ($(findstring sun4u, $(UNIXNAME)), sun4u) + SYSLIB = -lsocket -lnsl -lrt + endif + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DSUNOS5 -D_REENTRANT +endif + +# For HP-UX +ifeq ($(findstring HP-UX, $(UNIXNAME)), HP-UX) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DHP_UX -DHPUX11 + PLAT_NAME=hp-ux +endif + +#Find system type. +ifneq ($(SYSPATH),) + CHECKSYSRES = @echo "System is $(shell uname -sm)" +endif +########################################################### + +OBJ_PATH_DST = ./debug +LIB_PATH_DST = ./lib + +INC_COMPILE = -I./include \ + -I../../../../lib_protocol/include \ + -I../../../../lib_acl/include +CFLAGS += $(INC_COMPILE) + +#Project's objs +OBJS_DST = $(patsubst %.c, $(OBJ_PATH_DST)/%.o, $(notdir $(wildcard src/*.c))) +########################################################### + +LIB_NAME = lib_gid.a + +.PHONY = clean +COMPILE = $(CC) $(CFLAGS) + +$(LIB_NAME): $(OBJS_DST) + $(AR) $(ARFL) $(LIB_PATH_DST)/$(LIB_NAME) $(OBJS_DST) + $(RANLIB) $(LIB_PATH_DST)/$(LIB_NAME) + +# src +$(OBJ_PATH_DST)/%.o: src/%.c + $(COMPILE) $< -o $@ +clean: + rm -f $(LIB_PATH_DST)/$(LIB_NAME) + rm -f $(OBJS_DST) diff --git a/app/gid/gid_client/c/include/lib_gid.h b/app/gid/gid_client/c/include/lib_gid.h new file mode 100644 index 000000000..b8de2320a --- /dev/null +++ b/app/gid/gid_client/c/include/lib_gid.h @@ -0,0 +1,122 @@ +#ifndef __LIB_GID_INCLUDE_H__ +#define __LIB_GID_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* 通讯协议方式 */ +#define GID_PROTO_CMDLINE 0 /* 命令行方式 */ +#define GID_PROTO_JSON 1 /* http 方式,数据格式为 json 格式 */ +#define GID_PROTO_XML 2 /* http 方式,数据格式为 xml 格式 */ + +/* 操作命令 */ +#define GID_CMD_NEXT "new_gid" /* 获取下一个唯一 gid */ + +/* 出错码 */ + +/* 客户端相关的错误码 */ +#define GID_OK 200 /* 正常 */ +#define GID_ERR_INIT 400 /* 库未初始化,应用应在程序初始化时调用初始化函数 gid_client_init */ +#define GID_ERR_CONN 401 /* 连接服务器失败 */ +#define GID_ERR_IO 402 /* 与服务器通信失败 */ +#define GID_ERR_PROTO 403 /* 协议格式错误 */ +#define GID_ERR_SERVER 404 /* 服务器内部出错 */ + +/* 服务端相关的错误码 */ +#define GID_ERR_SID 500 /* 会话 ID 号不对 */ +#define GID_ERR_OVERRIDE 501 /* 达到最大分配值 */ +#define GID_ERR_SAVE 502 /* 存储至磁盘时出错 */ + +/** + * 库初始化函数,使用者在程序启动后应该调用该函数初始化库 + * @param proto {int} 通信协议格式,参见上面:GID_PROTO_XXX + * @param server_addr {const char*} gid 服务器地址,格式:ip:port 或 + * domain:port 或 unix 域 /xxx/xxx/xxx + */ +void gid_client_init(int proto, const char *server_addr); + +/** + * 根据错误号获得错误描述 + * @param errnum {int} 错误号,参见上面:GID_ERR_XXX + * @return {const char*} 错误描述信息 + */ +const char *gid_client_serror(int errnum); + +/** + * 设置 HTTP 请求中的 URL,内部有缺省值,可不直接调用此函数 + * @param url {const char*} URL 字符串 + */ +void gid_client_set_url(const char *url); + +/** + * 设置 HTTP 请求是否保持长连接,缺省情况下保持长连接 + * @param keepalive {int} 是否保持长连接 + */ +void gid_client_set_keepalive(int keepalive); + +/** + * 在长连接情况下,如果连接中间意外中断,设置重试次数,缺省值为 1 + * @param nretry {int} 最大重试次数 + */ +void gid_client_set_retry_limit(int nretry); + +/** + * 设置连接 gid 服务器的连接超时时间(秒),缺省值为 20 秒 + * @param timeout {int} 超时时间(秒) + */ +void gid_client_set_conn_timeout(int timeout); + +/** + * 设置网络通信的读写超时时间(秒),缺省值为 20 秒 + * @param timeout {int} 超时时间(秒) + */ +void gid_client_set_rw_timeout(int timeout); + +/** + * 获得下一个 gid 号 + * @param tag {const char*} 标识名称,如果为空,则内部缺省使用 default 标签, + * 该值的格式为:tag_name[:sid],其中的 tag_name 为真正的标识名,sid 为访问 + * 该标识对象的授权ID号,如果该值与服务端的 sid 不匹配,则禁止访问并返回错误, + * 当访问一个新的标识对象并产生第一个 gid 值时,其中如果设置了 sid 则该 sid + * 自动做为该标识对象的授权ID号,其它程序若想访问该标识对象的 gid 则必须提供 + * 该授权 ID 号 + * @param errnum {int*} 该指针非空时用来记录出错时的错误号 + * @return {long long int} 获得的下一个唯一 gid 号,如果该值 < 0 则表示出错 + */ +long long int gid_next(const char *tag, int *errnum); + +/* 如果获取 gid 的函数使用用户提供的连接描述符 */ + +/** + * 采用命令行方式从服务端获取 gid 号 + * @param fd {int} 与服务器连接的套接字 + * @param tag {const char*} 标识名称,若为空则内部缺省使用default + * @param errnum {int*} 该指针非空时用来记录出错时的错误号 + * @return {long long int} 获得的下一个唯一 gid 号, * 如果该值为 < 0 则表示出错 + */ +long long int gid_cmdline_get(int fd, const char *tag, int *errnum); + +/** + * 采用 http 协议且数据格式为 json 格式,从服务端获取 gid 号 + * @param fd {int} 与服务器连接的套接字 + * @param tag {const char*} 标识名称,若为空则内部缺省使用default + * @param errnum {int*} 该指针非空时用来记录出错时的错误号 + * @return {long long int} 获得的下一个唯一 gid 号,如果该值 < 0 则表示出错 + */ +long long int gid_json_get(int fd, const char *tag, int *errnum); + +/** + * 采用 http 协议且数据格式为 xml 格式,从服务端获取 gid 号 + * @param fd {int} 与服务器连接的套接字 + * @param tag {const char*} 标识名称,若为空则内部缺省使用default + * @param errnum {int*} 该指针非空时用来记录出错时的错误号 + * @return {long long int} 获得的下一个唯一 gid 号,如果该值 < 0 则表示出错 + */ +long long int gid_xml_get(int fd, const char *tag, int *errnum); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/app/gid/gid_client/c/src/gid.h b/app/gid/gid_client/c/src/gid.h new file mode 100644 index 000000000..dad126f0d --- /dev/null +++ b/app/gid/gid_client/c/src/gid.h @@ -0,0 +1,10 @@ +#ifndef __GID_INCLUDE_H__ +#define __GID_INCLUDE_H__ + +#include "lib_acl.h" + +acl_int64 gid_cmdline_next(ACL_VSTREAM *client, const char *tag, int *errnum); +acl_int64 gid_json_next(ACL_VSTREAM *client, const char *tag, int *errnum); +acl_int64 gid_xml_next(ACL_VSTREAM *client, const char *tag, int *errnum); + +#endif diff --git a/app/gid/gid_client/c/src/gid_cmdline.c b/app/gid/gid_client/c/src/gid_cmdline.c new file mode 100644 index 000000000..d77bf85e4 --- /dev/null +++ b/app/gid/gid_client/c/src/gid_cmdline.c @@ -0,0 +1,82 @@ +#include "lib_acl.h" + +#include "global.h" +#include "lib_gid.h" +#include "gid.h" + +acl_int64 gid_cmdline_get(int fd, const char *tag, int *errnum) +{ + acl_int64 gid; + ACL_VSTREAM *client = acl_vstream_fdopen(fd, 0, 1024, + var_gid_rw_timeout, ACL_VSTREAM_TYPE_SOCK); + + gid = gid_cmdline_next(client, tag, errnum); + acl_vstream_free(client); + return (gid); +} + +acl_int64 gid_cmdline_next(ACL_VSTREAM *client, const char *tag, int *errnum) +{ + char buf[1204]; + ACL_ARGV *tokens; + ACL_ITER iter; + const char *status = NULL, *gid = NULL, *tag_ptr = NULL, *msg = NULL, *err = NULL; + + if (tag && *tag) + snprintf(buf, sizeof(buf), "CMD^%s|TAG^%s\r\n", GID_CMD_NEXT, tag); + else + snprintf(buf, sizeof(buf), "CMD^%s\r\n", GID_CMD_NEXT); + + if (acl_vstream_writen(client, buf, strlen(buf)) == ACL_VSTREAM_EOF) { + if (errnum) + *errnum = GID_ERR_IO; + return (-1); + } else if (acl_vstream_gets_nonl(client, buf, sizeof(buf)) == ACL_VSTREAM_EOF) + { + if (errnum) + *errnum = GID_ERR_IO; + return (-1); + } + + tokens = acl_argv_split(buf, "|"); + acl_foreach(iter, tokens) { + const char *ptr = (const char*) iter.data; + + if (strncasecmp(ptr, "STATUS^", sizeof("STATUS^") - 1) == 0) { + status = ptr + sizeof("STATUS^") - 1; + } else if (strncasecmp(ptr, "GID^", sizeof("GID^") - 1) == 0) { + gid = ptr + sizeof("GID^") - 1; + } else if (strncasecmp(ptr, "TAG^", sizeof("TAG^") - 1) == 0) { + tag_ptr = ptr + sizeof("TAG^") - 1; + } else if (strncasecmp(ptr, "MSG^", sizeof("MSG^") - 1) == 0) { + msg = ptr + sizeof("MSG^") - 1; + } else if (strncasecmp(ptr, "ERR^", sizeof("ERR^") - 1) == 0) { + err = ptr + sizeof("ERR^"); + } + } + + if (status == NULL) { + if (errnum) + *errnum = GID_ERR_PROTO; + acl_argv_free(tokens); + return (-1); + } else if (strcasecmp(status, "OK") != 0) { + if (errnum) { + if (err) + *errnum = atoi(err); + else + *errnum = GID_ERR_SERVER; + } + acl_argv_free(tokens); + return (-1); + } else if (gid == NULL) { + if (errnum) + *errnum = GID_ERR_PROTO; + acl_argv_free(tokens); + return (-1); + } else { + acl_int64 ngid = atoll(gid); + acl_argv_free(tokens); + return (ngid); + } +} diff --git a/app/gid/gid_client/c/src/gid_json.c b/app/gid/gid_client/c/src/gid_json.c new file mode 100644 index 000000000..be5713cdf --- /dev/null +++ b/app/gid/gid_client/c/src/gid_json.c @@ -0,0 +1,98 @@ +#include "lib_acl.h" + +#include "global.h" +#include "http_client.h" +#include "lib_gid.h" +#include "gid.h" + +acl_int64 gid_json_get(int fd, const char *tag, int *errnum) +{ + ACL_VSTREAM *client = acl_vstream_fdopen(fd, 0, 1024, + var_gid_rw_timeout, ACL_VSTREAM_TYPE_SOCK); + acl_int64 gid; + + gid = gid_json_next(client, tag, errnum); + acl_vstream_free(client); + return (gid); +} + +acl_int64 gid_json_next(ACL_VSTREAM *client, const char *tag, int *errnum) +{ + char buf[1204]; + ACL_ITER iter; + ACL_JSON *json; + const char *status = NULL, *gid = NULL, *tag_ptr = NULL, *msg = NULL, *err = NULL; + + if (tag && *tag) + snprintf(buf, sizeof(buf), "{ cmd: '%s', tag: '%s' }\r\n", + GID_CMD_NEXT, tag); + else + snprintf(buf, sizeof(buf), "{ cmd: '%s' }\r\n", GID_CMD_NEXT); + + /* 发送 HTTP JSON 请求 */ + if (http_client_post_request(client, var_gid_url, 1, + "json", buf, (int) strlen(buf), errnum) < 0) + { + if (errnum) + *errnum = GID_ERR_IO; + return (-1); + } + + json = acl_json_alloc(); /* 分配 JSON 对象 */ + + /* 接收 HTTP JSON 响应 */ + if (http_client_get_respond(client, json, NULL, errnum, NULL) < 0) + { + if (errnum) + *errnum = GID_ERR_IO; + acl_json_free(json); + return (-1); + } + +#define STR acl_vstring_str + + /* 数据格式: { status: 'ok|error', gid: xxx, tag: 'xxx', msg: 'xxx', err: 'xxx' } */ + + acl_foreach(iter, json) { + ACL_JSON_NODE *node = (ACL_JSON_NODE*) iter.data; + + if (STR(node->ltag) == 0 || STR(node->text) == 0) + continue; + if (strcasecmp(STR(node->ltag), "STATUS") == 0) { + status = STR(node->text); + } else if (strcasecmp(STR(node->ltag), "GID") == 0) { + gid = STR(node->text); + } else if (strcasecmp(STR(node->ltag), "TAG") == 0) { + tag_ptr = STR(node->text); + } else if (strcasecmp(STR(node->ltag), "MSG") == 0) { + msg = STR(node->text); + } else if (strcasecmp(STR(node->ltag), "ERR") == 0) { + err = STR(node->text); + } + } + + if (status == NULL) { + if (errnum) + *errnum = GID_ERR_PROTO; + acl_json_free(json); + return (-1); + } else if (strcasecmp(status, "OK") != 0) { + if (errnum) { + if (err) + *errnum = atoi(err); + else + *errnum = GID_ERR_SERVER; + } + acl_json_free(json); + return (-1); + } else if (gid == NULL) { + if (errnum) + *errnum = GID_ERR_PROTO; + acl_json_free(json); + return (-1); + } else { + acl_int64 ngid = atoll(gid); + acl_json_free(json); + return (ngid); + } +} diff --git a/app/gid/gid_client/c/src/gid_xml.c b/app/gid/gid_client/c/src/gid_xml.c new file mode 100644 index 000000000..c01b6a60d --- /dev/null +++ b/app/gid/gid_client/c/src/gid_xml.c @@ -0,0 +1,123 @@ +#include "lib_acl.h" + +#include "global.h" +#include "http_client.h" +#include "lib_gid.h" +#include "gid.h" + +acl_int64 gid_xml_get(int fd, const char *tag, int *errnum) +{ + ACL_VSTREAM *client = acl_vstream_fdopen(fd, 0, 1024, + var_gid_rw_timeout, ACL_VSTREAM_TYPE_SOCK); + acl_int64 gid; + + gid = gid_xml_next(client, tag, errnum); + acl_vstream_free(client); + return (gid); +} + +acl_int64 gid_xml_next(ACL_VSTREAM *client, const char *tag, int *errnum) +{ + char buf[1204]; + ACL_ITER iter; + ACL_XML *xml; + const char *status = NULL, *gid = NULL, *tag_ptr = NULL, *msg = NULL, *err = NULL; + static __thread ACL_VSTRING *tt = NULL; + + if (tag && *tag) + snprintf(buf, sizeof(buf), "\r\n", + GID_CMD_NEXT, tag); + else + snprintf(buf, sizeof(buf), "\r\n", GID_CMD_NEXT); + + /* 发送 HTTP JSON 请求 */ + if (http_client_post_request(client, var_gid_url, 1, + "xml", buf, (int) strlen(buf), errnum) < 0) + { + if (errnum) + *errnum = GID_ERR_IO; + return (-1); + } + + xml = acl_xml_alloc(); /* 分配 JSON 对象 */ + + if (tt == NULL) + tt = acl_vstring_alloc(100); + else + ACL_VSTRING_RESET(tt); + + /* 接收 HTTP JSON 响应 */ + if (http_client_get_respond(client, NULL, xml, errnum, tt) < 0) + { + if (errnum) + *errnum = GID_ERR_IO; + acl_xml_free(xml); + return (-1); + } + +#define STR acl_vstring_str + + /* + { + ACL_VSTRING *tmp = acl_vstring_alloc(128); + acl_xml_dump2(xml, tmp); + printf("xml: %s\r\n", STR(tmp)); + acl_vstring_free(tmp); + } + */ + + /* 数据格式: */ + + acl_foreach(iter, xml) { + ACL_XML_NODE *node = (ACL_XML_NODE*) iter.data; + + /* 找到 respond 结点 */ + if (strcasecmp(STR(node->ltag), "respond") == 0 + && node->attr_list != NULL) + { + ACL_ITER attr_iter; + + /* 遍历结点属性 */ + acl_foreach(attr_iter, node->attr_list) { + ACL_XML_ATTR *attr = (ACL_XML_ATTR*) attr_iter.data; + + if (strcasecmp(STR(attr->name), "STATUS") == 0) { + status = STR(attr->value); + } else if (strcasecmp(STR(attr->name), "GID") == 0) { + gid = STR(attr->value); + } else if (strcasecmp(STR(attr->name), "TAG") == 0) { + tag_ptr = STR(attr->value); + } else if (strcasecmp(STR(attr->name), "MSG") == 0) { + msg = STR(attr->value); + } else if (strcasecmp(STR(attr->name), "ERR") == 0) { + err = STR(attr->value); + } + } + } + } + + if (status == NULL) { + if (errnum) + *errnum = GID_ERR_PROTO; + acl_xml_free(xml); + return (-1); + } else if (strcasecmp(status, "OK") != 0) { + if (errnum) { + if (err) + *errnum = atoi(err); + else + *errnum = GID_ERR_SERVER; + } + acl_xml_free(xml); + return (-1); + } else if (gid == NULL) { + if (errnum) + *errnum = GID_ERR_PROTO; + acl_xml_free(xml); + return (-1); + } else { + acl_int64 ngid = atoll(gid); + acl_xml_free(xml); + return (ngid); + } +} diff --git a/app/gid/gid_client/c/src/global.c b/app/gid/gid_client/c/src/global.c new file mode 100644 index 000000000..409d4bb68 --- /dev/null +++ b/app/gid/gid_client/c/src/global.c @@ -0,0 +1,61 @@ +#include "lib_acl.h" + +#include "global.h" +#include "lib_gid.h" + +char var_gid_server_addr[64] = ""; +int var_gid_conn_timeout; +int var_gid_rw_timeout; +int var_gid_retry_limit; +int var_gid_keepalive; +int var_gid_proto; +char var_gid_url[1024]; + +void gid_client_init(int proto, const char *server_addr) +{ + acl_assert(server_addr && *server_addr); + + ACL_SAFE_STRNCPY(var_gid_server_addr, server_addr, + sizeof(var_gid_server_addr)); + if (proto == GID_PROTO_JSON) + ACL_SAFE_STRNCPY(var_gid_url, GID_JSON_URL, + sizeof(var_gid_url)); + else if (proto == GID_PROTO_XML) + ACL_SAFE_STRNCPY(var_gid_url, GID_XML_URL, + sizeof(var_gid_url)); + else if (proto != GID_PROTO_CMDLINE) + acl_assert(0); + + var_gid_proto = proto; + var_gid_conn_timeout = 20; + var_gid_rw_timeout = 20; + var_gid_retry_limit = 1; + var_gid_keepalive = 1; +} + +void gid_client_set_url(const char *url) +{ + if (url == NULL || *url == 0) + return; + ACL_SAFE_STRNCPY(var_gid_url, url, sizeof(var_gid_url)); +} + +void gid_client_set_keepalive(int keepalive) +{ + var_gid_keepalive = keepalive; +} + +void gid_client_set_retry_limit(int nretry) +{ + var_gid_retry_limit = nretry; +} + +void gid_client_set_conn_timeout(int timeout) +{ + var_gid_conn_timeout = timeout; +} + +void gid_client_set_rw_timeout(int timeout) +{ + var_gid_rw_timeout = timeout; +} diff --git a/app/gid/gid_client/c/src/global.h b/app/gid/gid_client/c/src/global.h new file mode 100644 index 000000000..8360e1cec --- /dev/null +++ b/app/gid/gid_client/c/src/global.h @@ -0,0 +1,15 @@ +#ifndef __GLOBAL_INCLUDE_H__ +#define __GLOBAL_INCLUDE_H__ + +extern char var_gid_server_addr[]; +extern int var_gid_conn_timeout; +extern int var_gid_rw_timeout; +extern int var_gid_retry_limit; +extern int var_gid_proto; +extern int var_gid_keepalive; +extern char var_gid_url[]; + +#define GID_JSON_URL "/gid_json" +#define GID_XML_URL "/gid_xml" + +#endif diff --git a/app/gid/gid_client/c/src/http_client.c b/app/gid/gid_client/c/src/http_client.c new file mode 100644 index 000000000..eed216fc8 --- /dev/null +++ b/app/gid/gid_client/c/src/http_client.c @@ -0,0 +1,99 @@ +#include "lib_acl.h" +#include "lib_protocol.h" + +#include "lib_gid.h" +#include "global.h" +#include "http_client.h" + +int http_client_post_request(ACL_VSTREAM *client, const char *url, int keepalive, + const char *gid_fmt, char* body, int len, int *errnum) +{ + HTTP_HDR_REQ* hdr_req = http_hdr_req_create(url, "POST", "HTTP/1.1"); + ACL_VSTRING* buf = acl_vstring_alloc(256); + struct iovec vector[2]; /* 数据数组 */ + int ret; + + /* 在请求头中设置请求体的数据长度 */ + http_hdr_put_int(&hdr_req->hdr, "Content-Length", len); + if (keepalive) + http_hdr_put_str(&hdr_req->hdr, "Connection", "keep-alive"); + if (gid_fmt && *gid_fmt) + http_hdr_put_str(&hdr_req->hdr, "x-gid-format", gid_fmt); + http_hdr_build_request(hdr_req, buf); /* 构建 HTTP 请求头数据 */ + + /* 设置 HTTP 头 */ + vector[0].iov_base = acl_vstring_str(buf); + vector[0].iov_len = ACL_VSTRING_LEN(buf); + + /* 设置 HTTP 体 */ + vector[1].iov_base = (char*) body; + vector[1].iov_len = len; + + ret = acl_vstream_writevn(client, vector, 2); /* 发送请求头及请求体 */ + http_hdr_req_free(hdr_req); /* 释放 HTTP 请求头对象 */ + acl_vstring_free(buf); /* 释放缓冲区 */ + + if (ret == ACL_VSTREAM_EOF) { + if (errnum) + *errnum = GID_ERR_IO; + return -1; + } + + /* 发送HTTP请求成功 */ + return (0); +} + +int http_client_get_respond(ACL_VSTREAM* client, ACL_JSON *json, + ACL_XML *xml, int *errnum, ACL_VSTRING *dump) +{ + HTTP_HDR_RES* hdr_res; + HTTP_RES* res; + char buf[1024]; + int ret; + + acl_assert(json != NULL || xml != NULL); + + hdr_res = http_hdr_res_new(); /* 创建HTTP 响应头对象 */ + /* 读取 HTTP 服务器响应头 */ + ret = http_hdr_res_get_sync(hdr_res, client, var_gid_rw_timeout); + if (ret < 0) { + http_hdr_res_free(hdr_res); /* 释放 HTTP 响应头对象 */ + return -1; + } + /* 解析 HTTP 响应头 */ + if (http_hdr_res_parse(hdr_res) < 0) { /* 解析出错 */ + http_hdr_res_free(hdr_res); + return -1; + } + + /* + http_hdr_print(&hdr_res->hdr, "---respond---"); + */ + + /* 需要先根据 HTTP 响应头判断是否有数据体 */ + if (hdr_res->hdr.content_length == 0 || + (hdr_res->hdr.content_length == -1 && !hdr_res->hdr.chunked + && hdr_res->reply_status > 300 && hdr_res->reply_status < 400)) + { + http_hdr_res_free(hdr_res); + return 0; + } + res = http_res_new(hdr_res); /* 创建 HTTP 响应体对象 */ + while (1) { + /* 读数据体数据 */ + ret = http_res_body_get_sync(res, client, buf, sizeof(buf) - 1); + if (ret <= 0) + break; + buf[ret] = 0; + if (json) + acl_json_update(json, buf); + else + acl_xml_update(xml, buf); + if (dump) + acl_vstring_strcat(dump, buf); + } + + /* 因为 res 中含有 hdr_res 所以会一同连 hdr_res 释放 */ + http_res_free(res); + return (0); +} diff --git a/app/gid/gid_client/c/src/http_client.h b/app/gid/gid_client/c/src/http_client.h new file mode 100644 index 000000000..b6677ab40 --- /dev/null +++ b/app/gid/gid_client/c/src/http_client.h @@ -0,0 +1,31 @@ +#ifndef __HTTP_CLIENT_INCLUDE_H__ +#define __HTTP_CLIENT_INCLUDE_H__ + +/** + * 向服务器按 POST 方式发送请求 + * @param client {ACL_VSTREAM*} 连接流 + * @param url {const char*} URL 字符串 + * @param keepalive {int} 是否与服务端保持长连接 + * @param gid_fmt {const char*} 数据格式:xml 或 json + * @param body {char*} 数据体地址 + * @param len {int} 数据体长度 + * @param errnum {int*} 若非空则记录出错时的原因 + * @return {int} 0 表示成功,否则表示失败 + */ +int http_client_post_request(ACL_VSTREAM *client, const char *url, int keepalive, + const char *gid_fmt, char* body, int len, int *errnum); + +/** + * 从服务器读取响应数据 + * @param client {ACL_VSTREAM*} 连接流 + * @param json {ACL_JSON*} 若非空,则采用 json 格式进行解析 + * @param xml {ACL_XML*} 若非空,则采用 xml 格式进行解析 + * @param errnum {int*} 若非空则记录出错时的原因 + * @param dump {ACL_VSTRING*} 非空则存储响应数据 + * @return {int} 0 表示成功,否则表示失败 + * 注:ACL_JSON* 和 ACL_XML* 必须有且只有一个非空 + */ +int http_client_get_respond(ACL_VSTREAM* client, ACL_JSON *json, + ACL_XML *xml, int *errnum, ACL_VSTRING *dump); + +#endif diff --git a/app/gid/gid_client/c/src/lib_gid.c b/app/gid/gid_client/c/src/lib_gid.c new file mode 100644 index 000000000..a3bd125f3 --- /dev/null +++ b/app/gid/gid_client/c/src/lib_gid.c @@ -0,0 +1,107 @@ +#include "lib_acl.h" +#include "lib_protocol.h" + +#include "global.h" +#include "gid.h" +#include "lib_gid.h" + +/* 使用线程局部变量,但注意此库不得编译成动态库XXX */ + +static __thread ACL_VSTREAM *__client = NULL; + +acl_int64 gid_next(const char *tag, int *errnum) +{ + acl_int64 gid = 0; + int err, nretry = 0; + + if (var_gid_server_addr[0] == 0) { + if (errnum) + *errnum = GID_ERR_INIT; + return (-1); + } + + while (1) { + if (__client == NULL) + __client = acl_vstream_connect(var_gid_server_addr, + ACL_BLOCKING, var_gid_conn_timeout, + var_gid_rw_timeout, 1024); + if (__client == NULL) { + if (errnum) + *errnum = GID_ERR_CONN; + return (-1); + } + + if (var_gid_proto == GID_PROTO_JSON) { + gid = gid_json_next(__client, tag, &err); + } else if (var_gid_proto == GID_PROTO_XML) { + gid = gid_xml_next(__client, tag, &err); + } else { + gid = gid_cmdline_next(__client, tag, &err); + } + + if (gid >= 0) { + if (errnum) + *errnum = GID_OK; + break; + } else if (err != GID_ERR_IO) { + if (errnum) + *errnum = err; + break; + } else if (nretry++ >= var_gid_retry_limit) { + if (errnum) + *errnum = err; + break; + } + } + + if (var_gid_keepalive == 0) { + acl_vstream_close(__client); + __client = NULL; + } + + return (gid); +} + +/* +#define GID_OK 200 +#define GID_ERR_INIT 400 +#define GID_ERR_CONN 401 +#define GID_ERR_IO 402 +#define GID_ERR_PROTO 403 +#define GID_ERR_SERVER 404 + +#define GID_ERR_SID 500 +#define GID_ERR_OVERRIDE 501 +#define GID_ERR_SAVE 502 +*/ + +const char *gid_client_serror(int errnum) +{ + static const struct { + int err; + const char *str; + } errors[] = { + { GID_OK, "ok" }, + + /* 客户端相关错误 */ + { GID_ERR_INIT, "gid_client_init should called first" }, + { GID_ERR_CONN, "connect server error" }, + { GID_ERR_IO, "readwrite from server error" }, + { GID_ERR_PROTO, "gid protocol error" }, + { GID_ERR_SERVER, "gid server internal error" }, + + /* 服务端返回的错误 */ + { GID_ERR_SID, "sid invalid" }, + { GID_ERR_OVERRIDE, "gid override" }, + { GID_ERR_SAVE, "gid save error" }, + { 0, 0 } + }; + static const char *unknown = "unknown error number"; + int i; + + for (i = 0; errors[i].str != NULL; i++) { + if (errnum == errors[i].err) + return (errors[i].str); + } + return (unknown); +} diff --git a/app/gid/gid_client/c/test/Makefile b/app/gid/gid_client/c/test/Makefile new file mode 100644 index 000000000..8603b1f76 --- /dev/null +++ b/app/gid/gid_client/c/test/Makefile @@ -0,0 +1,114 @@ +SHELL = /bin/sh +CC = g++ +CC = gcc +#CC = ${MY_ENV_CC} +AR = ar +ARFL = rv +#ARFL = cru +RANLIB = ranlib + +CFLAGS = -c -g -W -Wall -Wcast-qual -Wcast-align \ +-Waggregate-return \ +-Wno-long-long \ +-Wpointer-arith -Werror -Wshadow -O2 \ +-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO + +#CFLAGS = -c -g -W -Wall -Wcast-qual -Wcast-align \ +#-Waggregate-return -Wmissing-prototypes \ +#-Wpointer-arith -Werror -Wshadow -O2 \ +#-D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO +########################################################### +#Check system: +# Linux, SunOS, Solaris, BSD variants, AIX, HP-UX +SYSLIB = -lpthread -lcrypt -lz +CHECKSYSRES = @echo "Unknow system type!";exit 1 +UNIXNAME = $(shell uname -sm) +OSTYPE = $(shell uname -p) +RPATH = + +ifeq ($(CC),) + CC = gcc +endif + +#Path for Linux +ifeq ($(findstring Linux, $(UNIXNAME)), Linux) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DLINUX2 -D_REENTRANT -pedantic + + ifeq ($(findstring i686, $(OSTYPE)), i686) + RPATH = linux32 + FLAG_OS = LINUX32 + endif + ifeq ($(findstring x86_64, $(OSTYPE)), x86_64) + RPATH = linux64 + FLAG_OS = LINUX64 + endif +endif + +#Path for SunOS +ifeq ($(findstring SunOS, $(UNIXNAME)), SunOS) + ifeq ($(findstring 86, $(UNIXNAME)), 86) + SYSLIB += -lsocket -lnsl -lrt + endif + ifeq ($(findstring sun4u, $(UNIXNAME)), sun4u) + SYSLIB += -lsocket -lnsl -lrt + endif + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DSUNOS5 -D_REENTRANT -pedantic +endif + +#Path for HP-UX +ifeq ($(findstring HP-UX, $(UNIXNAME)), HP-UX) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DHP_UX -DHPUX11 + PLAT_NAME=hp-ux +endif + +#Find system type. +ifneq ($(SYSPATH),) + CHECKSYSRES = @echo "System is $(shell uname -sm)" +endif +########################################################### +BASE_PATH = ../../../build + +INC_COMPILE = -I../include -I../../../../../lib_acl/include +LIB_COMPILE = -L../lib -l_gid -L../../../../../lib_acl/lib -L../../../../../lib_protocol/lib -l_protocol -l_acl + +CFLAGS += $(INC_COMPILE) + +########################################################### +OUT_PATH = . +OBJ_PATH = $(OUT_PATH) + +#Project's objs +SRC = $(wildcard *.c) +OBJ = $(patsubst %.c, $(OBJ_PATH)/%.o, $(notdir $(SRC))) +########################################################### + +PROG = gid_client + +all: rm gid_client +.PHONY = gid_client clean +COMPILE = $(CC) $(CFLAGS) + +$(PROG): $(OBJ) + $(CC) $(OBJ) $(LIB_COMPILE) $(SYSLIB) -o $(PROG) +# cp $(OBJ_PATH)/$(PROG) $(BASE_PATH)/dist/master/libexec + @echo "" + @echo "All ok! Output:$(PROG)" + @echo "" + +$(OBJ_PATH)/%.o: %.c + $(COMPILE) $< -o $@ + +rm: + rm -f $(PROG) +clean: + rm -f $(PROG) + rm -f $(OBJ) diff --git a/app/gid/gid_client/c/test/main.c b/app/gid/gid_client/c/test/main.c new file mode 100644 index 000000000..cd7845e7c --- /dev/null +++ b/app/gid/gid_client/c/test/main.c @@ -0,0 +1,153 @@ +#include "lib_acl.h" +#include +#include +#include +#include "lib_gid.h" + +static double stamp_sub(const struct timeval *from, const struct timeval *sub_by) +{ + struct timeval res; + + memcpy(&res, from, sizeof(struct timeval)); + + res.tv_usec -= sub_by->tv_usec; + if (res.tv_usec < 0) { + --res.tv_sec; + res.tv_usec += 1000000; + } + res.tv_sec -= sub_by->tv_sec; + + return (res.tv_sec * 1000.0 + res.tv_usec/1000.0); +} + +static void test_get_gid(const char *tag, int n) +{ + int i, errnum; + acl_int64 gid = 0; + struct timeval begin, end; + double spent; + + gettimeofday(&begin, NULL); + + for (i = 0; i < n; i++) { + /* 获得唯一 gid 号 */ + gid = gid_next(tag, &errnum); + if (gid < 0) { + printf("error: %d, %s, gid: %lld\r\n", + errnum, gid_client_serror(errnum), gid); + break; + } + if (n <= 100) + printf("get gid: %lld\r\n", gid); + else if (i > 0 && i % 10000 == 0) { + printf(">> i: %d, gid: %llu\r\n", i, gid); + ACL_METER_TIME("---------"); + } + } + + gettimeofday(&end, NULL); + + spent = stamp_sub(&end, &begin); + printf("total count: %d, curr gid: %lld, spent: %.2f, speed: %.2f\r\n", + n, gid, spent, (n * 1000) / (spent < 1 ? 1 : spent)); +} + +static const char *__tag = NULL; +static int __n = 0; + +static void thread_main(void *ctx acl_unused) +{ + test_get_gid(__tag, __n); +} + +static void test_gets_gid(const char *tag, int n) +{ + acl_pthread_pool_t *thrpool = acl_thread_pool_create(10, 30); + int i; + + __tag = tag; + __n = n; + + for (i = 0; i < 5; i++) + acl_pthread_pool_add(thrpool, thread_main, NULL); + acl_pthread_pool_destroy(thrpool); +} + +static void usage(const char *progname) +{ + printf("usage: %s -h[help] -s server_addr[127.0.0.1:7072]" + " -p protocol[cmdline|json|xml|]" + " -n count[100] -c cmd[get] -m[use mempool]" + " -t tag[default:sid] -P[use thread pool]\r\n", progname); +} + +int main(int argc, char *argv[]) +{ + int ch, n = 100, proto = GID_PROTO_JSON; + int use_mempool = 0, use_concurrent = 0; + char addr[64], cmd[32], tag[32]; + + snprintf(addr, sizeof(addr), "127.0.0.1:7072"); + snprintf(cmd, sizeof(cmd), "get"); + snprintf(tag, sizeof(tag), "default"); + + while ((ch = getopt(argc, argv, "hs:p:n:c:t:mP")) > 0) { + switch (ch) { + case 'h': + usage(argv[0]); + return (0); + case 's': + snprintf(addr, sizeof(addr), "%s", optarg); + break; + case 'p': + if (strcasecmp(optarg, "cmdline") == 0) + proto = GID_PROTO_CMDLINE; + else if (strcasecmp(optarg, "json") == 0) + proto = GID_PROTO_JSON; + else if (strcasecmp(optarg, "xml") == 0) + proto = GID_PROTO_XML; + else { + printf("invalid proto: %s\r\n", optarg); + usage(argv[0]); + return (0); + } + break; + case 'n': + n = atoi(optarg); + break; + case 'c': + snprintf(cmd, sizeof(cmd), "%s", optarg); + break; + case 't': + snprintf(tag, sizeof(tag), "%s", optarg); + break; + case 'm': + use_mempool = 1; + break; + case 'P': + use_concurrent = 1; + break; + default: + break; + } + } + if (use_mempool) + acl_mem_slice_init(8, 1024, 100000, + ACL_SLICE_FLAG_GC2 | + ACL_SLICE_FLAG_RTGC_OFF | + ACL_SLICE_FLAG_LP64_ALIGN); + + /* 初始化 */ + printf("proto: %d, addr: %s\n", proto, addr); + gid_client_init(proto, addr); + + if (strcasecmp(cmd, "get") == 0) { + if (use_concurrent) + test_gets_gid(tag, n); + else + test_get_gid(tag, n); + } else + usage(argv[0]); + + return (0); +} diff --git a/app/gid/gid_client/java/.classpath b/app/gid/gid_client/java/.classpath new file mode 100644 index 000000000..ae9ffdb82 --- /dev/null +++ b/app/gid/gid_client/java/.classpath @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/app/gid/gid_client/java/.project b/app/gid/gid_client/java/.project new file mode 100644 index 000000000..68b16a42f --- /dev/null +++ b/app/gid/gid_client/java/.project @@ -0,0 +1,17 @@ + + + GidClient + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/app/gid/gid_client/java/.settings/org.eclipse.core.resources.prefs b/app/gid/gid_client/java/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 000000000..04ac95146 --- /dev/null +++ b/app/gid/gid_client/java/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,3 @@ +#Fri Dec 02 10:23:44 CST 2011 +eclipse.preferences.version=1 +encoding/=UTF-8 diff --git a/app/gid/gid_client/java/doc/allclasses-frame.html b/app/gid/gid_client/java/doc/allclasses-frame.html new file mode 100644 index 000000000..fd3cf758d --- /dev/null +++ b/app/gid/gid_client/java/doc/allclasses-frame.html @@ -0,0 +1,23 @@ + + + + + + +鎵鏈夌被 + + + + +

鎵鏈夌被

+ + + diff --git a/app/gid/gid_client/java/doc/allclasses-noframe.html b/app/gid/gid_client/java/doc/allclasses-noframe.html new file mode 100644 index 000000000..f8b67b218 --- /dev/null +++ b/app/gid/gid_client/java/doc/allclasses-noframe.html @@ -0,0 +1,23 @@ + + + + + + +鎵鏈夌被 + + + + +

鎵鏈夌被

+ + + diff --git a/app/gid/gid_client/java/doc/com/iker/gid/GidClient.html b/app/gid/gid_client/java/doc/com/iker/gid/GidClient.html new file mode 100644 index 000000000..385b5f136 --- /dev/null +++ b/app/gid/gid_client/java/doc/com/iker/gid/GidClient.html @@ -0,0 +1,306 @@ + + + + + + +GidClient + + + + + + + + + + + +
+
com.iker.gid
+

绫 GidClient

+
+
+
    +
  • java.lang.Object
  • +
  • +
      +
    • com.iker.gid.GidClient
    • +
    +
  • +
+
+ +
+
+
    +
  • + +
      +
    • + + +

      鏋勯犲櫒姒傝

      + + + + + + + + +
      鏋勯犲櫒 
      鏋勯犲櫒鍜岃鏄
      GidClient(java.lang.String ip, + int port, + java.lang.String tag) 
      +
    • +
    + +
      +
    • + + +

      鏂规硶姒傝

      + + + + + + + + + + + + + + + + + + +
      鏂规硶 
      闄愬畾绗﹀拰绫诲瀷鏂规硶鍜岃鏄
      abstract longgidNext() +
      鑾峰緱涓嬩竴涓敮涓ID鍙
      +
      voidsetConnectTimeout(int timeout) +
      璁剧疆缁滆繛鎺ユ椂闂
      +
      voidsetRdTimeout(int timeout) +
      璁剧疆IO璇昏秴鏃舵椂闂
      +
      +
        +
      • + + +

        浠庣被缁ф壙鐨勬柟娉 java.lang.Object

        +equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
      • +
      +
    • +
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      鏋勯犲櫒璇︾粏璧勬枡

      + + + +
        +
      • +

        GidClient

        +
        public GidClient(java.lang.String ip,
        +         int port,
        +         java.lang.String tag)
        +
      • +
      +
    • +
    + +
      +
    • + + +

      鏂规硶璇︾粏璧勬枡

      + + + +
        +
      • +

        gidNext

        +
        public abstract long gidNext()
        +
        鑾峰緱涓嬩竴涓敮涓ID鍙
        +
        杩斿洖:
        杩斿洖鍞竴鐨64浣嶆暣鏁帮紝濡傛灉杩斿洖鍊 < 0 鍒欒〃绀哄嚭閿
        +
      • +
      + + + +
        +
      • +

        setRdTimeout

        +
        public void setRdTimeout(int timeout)
        +
        璁剧疆IO璇昏秴鏃舵椂闂
        +
        鍙傛暟:
        timeout - 瓒呮椂鏃堕棿锛堝崟浣嶄负绉掞級锛屽鏋滀笉璁剧疆姝ゆ椂闂达紝 + 鍒欏唴閮ㄧ己鐪佸间负30绉
        +
      • +
      + + + +
        +
      • +

        setConnectTimeout

        +
        public void setConnectTimeout(int timeout)
        +
        璁剧疆缁滆繛鎺ユ椂闂
        +
        鍙傛暟:
        timeout - 瓒呮椂鏃堕棿锛堝崟浣嶄负绉掞級锛屽鏋滀笉璁剧疆姝ゆ椂闂达紝 + 鍒欏唴閮ㄧ己鐪佸间负10绉
        +
      • +
      +
    • +
    +
  • +
+
+
+ + + + + + + diff --git a/app/gid/gid_client/java/doc/com/iker/gid/GidClientCmdLine.NameValue.html b/app/gid/gid_client/java/doc/com/iker/gid/GidClientCmdLine.NameValue.html new file mode 100644 index 000000000..2ad2dc427 --- /dev/null +++ b/app/gid/gid_client/java/doc/com/iker/gid/GidClientCmdLine.NameValue.html @@ -0,0 +1,234 @@ + + + + + + +GidClientCmdLine.NameValue + + + + + + + + + + + +
+
com.iker.gid
+

绫 GidClientCmdLine.NameValue

+
+
+
    +
  • java.lang.Object
  • +
  • +
      +
    • com.iker.gid.GidClientCmdLine.NameValue
    • +
    +
  • +
+
+
    +
  • +
    +
    灏侀棴绫:
    +
    GidClientCmdLine
    +
    +
    +
    +
    public final class GidClientCmdLine.NameValue
    +extends java.lang.Object
    +
    name-value 瀵圭被鍨嬬被
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      鏋勯犲櫒姒傝

      + + + + + + + + +
      鏋勯犲櫒 
      鏋勯犲櫒鍜岃鏄
      GidClientCmdLine.NameValue(java.lang.String name, + java.lang.String value) 
      +
    • +
    + +
      +
    • + + +

      鏂规硶姒傝

      +
        +
      • + + +

        浠庣被缁ф壙鐨勬柟娉 java.lang.Object

        +equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
      • +
      +
    • +
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      鏋勯犲櫒璇︾粏璧勬枡

      + + + +
        +
      • +

        GidClientCmdLine.NameValue

        +
        public GidClientCmdLine.NameValue(java.lang.String name,
        +                          java.lang.String value)
        +
      • +
      +
    • +
    +
  • +
+
+
+ + + + + + + diff --git a/app/gid/gid_client/java/doc/com/iker/gid/GidClientCmdLine.Tokens.html b/app/gid/gid_client/java/doc/com/iker/gid/GidClientCmdLine.Tokens.html new file mode 100644 index 000000000..1b2da26fb --- /dev/null +++ b/app/gid/gid_client/java/doc/com/iker/gid/GidClientCmdLine.Tokens.html @@ -0,0 +1,287 @@ + + + + + + +GidClientCmdLine.Tokens + + + + + + + + + + + +
+
com.iker.gid
+

绫 GidClientCmdLine.Tokens

+
+
+
    +
  • java.lang.Object
  • +
  • +
      +
    • com.iker.gid.GidClientCmdLine.Tokens
    • +
    +
  • +
+
+
    +
  • +
    +
    灏侀棴绫:
    +
    GidClientCmdLine
    +
    +
    +
    +
    public final class GidClientCmdLine.Tokens
    +extends java.lang.Object
    +
    鎷嗗垎瀛楃涓茬殑绫伙紝璇ョ被灏嗏滃悕鍊尖濆杩涜鎷嗗垎锛屾暟鎹牸寮忎负锛 + name1^value1|name2^value2|...
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      鏋勯犲櫒姒傝

      + + + + + + + + +
      鏋勯犲櫒 
      鏋勯犲櫒鍜岃鏄
      GidClientCmdLine.Tokens(java.lang.String content) 
      +
    • +
    + +
      +
    • + + +

      鏂规硶姒傝

      + + + + + + + + + + + + + + + + + + +
      鏂规硶 
      闄愬畾绗﹀拰绫诲瀷鏂规硶鍜岃鏄
      intgetInt(java.lang.String name) 
      longgetLong(java.lang.String name) 
      java.lang.StringgetString(java.lang.String name) 
      +
        +
      • + + +

        浠庣被缁ф壙鐨勬柟娉 java.lang.Object

        +equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
      • +
      +
    • +
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      鏋勯犲櫒璇︾粏璧勬枡

      + + + +
        +
      • +

        GidClientCmdLine.Tokens

        +
        public GidClientCmdLine.Tokens(java.lang.String content)
        +
      • +
      +
    • +
    + +
      +
    • + + +

      鏂规硶璇︾粏璧勬枡

      + + + +
        +
      • +

        getString

        +
        public java.lang.String getString(java.lang.String name)
        +
      • +
      + + + +
        +
      • +

        getLong

        +
        public long getLong(java.lang.String name)
        +
      • +
      + + + +
        +
      • +

        getInt

        +
        public int getInt(java.lang.String name)
        +
      • +
      +
    • +
    +
  • +
+
+
+ + + + + + + diff --git a/app/gid/gid_client/java/doc/com/iker/gid/GidClientCmdLine.html b/app/gid/gid_client/java/doc/com/iker/gid/GidClientCmdLine.html new file mode 100644 index 000000000..608cbee48 --- /dev/null +++ b/app/gid/gid_client/java/doc/com/iker/gid/GidClientCmdLine.html @@ -0,0 +1,324 @@ + + + + + + +GidClientCmdLine + + + + + + + + + + + +
+
com.iker.gid
+

绫 GidClientCmdLine

+
+
+ +
+
    +
  • +
    +
    +
    public final class GidClientCmdLine
    +extends GidClient
    +
    鍛戒护琛屾柟寮忎粠GID鏈嶅姟鍣ㄥ彇寰楀敮涓ID鍙凤紝鏄惁搴旇浣跨敤璇ユ柟寮忓彇寰楀敮涓ID鍙凤紝 + 搴旇鍙栧喅浜庢湇鍔″櫒鐨勯厤缃夐」
    +
    浣滆:
    +
    zsx
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      宓屽绫绘瑕

      + + + + + + + + + + + + + + +
      宓屽绫 
      闄愬畾绗﹀拰绫诲瀷绫诲拰璇存槑
      class GidClientCmdLine.NameValue +
      name-value 瀵圭被鍨嬬被
      +
      class GidClientCmdLine.Tokens +
      鎷嗗垎瀛楃涓茬殑绫伙紝璇ョ被灏嗏滃悕鍊尖濆杩涜鎷嗗垎锛屾暟鎹牸寮忎负锛 + name1^value1|name2^value2|...
      +
      +
    • +
    + +
      +
    • + + +

      鏋勯犲櫒姒傝

      + + + + + + + + +
      鏋勯犲櫒 
      鏋勯犲櫒鍜岃鏄
      GidClientCmdLine(java.lang.String ip, + int port, + java.lang.String tag) 
      +
    • +
    + +
      +
    • + + +

      鏂规硶姒傝

      + + + + + + + + + + + + + + +
      鏂规硶 
      闄愬畾绗﹀拰绫诲瀷鏂规硶鍜岃鏄
      longgidNext() +
      鑾峰緱涓嬩竴涓敮涓ID鍙
      +
      static voidmain(java.lang.String[] args) 
      + +
        +
      • + + +

        浠庣被缁ф壙鐨勬柟娉 java.lang.Object

        +equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
      • +
      +
    • +
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      鏋勯犲櫒璇︾粏璧勬枡

      + + + +
        +
      • +

        GidClientCmdLine

        +
        public GidClientCmdLine(java.lang.String ip,
        +                int port,
        +                java.lang.String tag)
        +
      • +
      +
    • +
    + +
      +
    • + + +

      鏂规硶璇︾粏璧勬枡

      + + + +
        +
      • +

        gidNext

        +
        public long gidNext()
        +
        浠庣被澶嶅埗鐨勮鏄: GidClient
        +
        鑾峰緱涓嬩竴涓敮涓ID鍙
        +
        +
        鎸囧畾鑰:
        +
        gidNext 鍦ㄧ被涓 GidClient
        +
        杩斿洖:
        杩斿洖鍞竴鐨64浣嶆暣鏁帮紝濡傛灉杩斿洖鍊 < 0 鍒欒〃绀哄嚭閿
        +
      • +
      + + + +
        +
      • +

        main

        +
        public static void main(java.lang.String[] args)
        +
      • +
      +
    • +
    +
  • +
+
+
+ + + + + + + diff --git a/app/gid/gid_client/java/doc/com/iker/gid/GidClientJson.html b/app/gid/gid_client/java/doc/com/iker/gid/GidClientJson.html new file mode 100644 index 000000000..5618817a9 --- /dev/null +++ b/app/gid/gid_client/java/doc/com/iker/gid/GidClientJson.html @@ -0,0 +1,296 @@ + + + + + + +GidClientJson + + + + + + + + + + + +
+
com.iker.gid
+

绫 GidClientJson

+
+
+ +
+
    +
  • +
    +
    +
    public final class GidClientJson
    +extends GidClient
    +
    鎸 JSON 鏁版嵁鏍煎紡鑾峰緱GID锛岃嫢瑕佷娇鐢ㄦ鏂瑰紡鍙栧緱鍞竴ID锛屽垯鏈嶅姟鍣 + 蹇呴』鏄惎鐢ㄤ簡HTTP鍗忚璁块棶鏂瑰紡
    +
    浣滆:
    +
    zsx
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      鏋勯犲櫒姒傝

      + + + + + + + + +
      鏋勯犲櫒 
      鏋勯犲櫒鍜岃鏄
      GidClientJson(java.lang.String ip, + int port, + java.lang.String tag) 
      +
    • +
    + +
      +
    • + + +

      鏂规硶姒傝

      + + + + + + + + + + + + + + +
      鏂规硶 
      闄愬畾绗﹀拰绫诲瀷鏂规硶鍜岃鏄
      longgidNext() +
      鑾峰緱涓嬩竴涓敮涓ID鍙
      +
      static voidmain(java.lang.String[] args) 
      + +
        +
      • + + +

        浠庣被缁ф壙鐨勬柟娉 java.lang.Object

        +equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
      • +
      +
    • +
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      鏋勯犲櫒璇︾粏璧勬枡

      + + + +
        +
      • +

        GidClientJson

        +
        public GidClientJson(java.lang.String ip,
        +             int port,
        +             java.lang.String tag)
        +
      • +
      +
    • +
    + +
      +
    • + + +

      鏂规硶璇︾粏璧勬枡

      + + + +
        +
      • +

        gidNext

        +
        public long gidNext()
        +
        浠庣被澶嶅埗鐨勮鏄: GidClient
        +
        鑾峰緱涓嬩竴涓敮涓ID鍙
        +
        +
        鎸囧畾鑰:
        +
        gidNext 鍦ㄧ被涓 GidClient
        +
        杩斿洖:
        杩斿洖鍞竴鐨64浣嶆暣鏁帮紝濡傛灉杩斿洖鍊 < 0 鍒欒〃绀哄嚭閿
        +
      • +
      + + + +
        +
      • +

        main

        +
        public static void main(java.lang.String[] args)
        +
      • +
      +
    • +
    +
  • +
+
+
+ + + + + + + diff --git a/app/gid/gid_client/java/doc/com/iker/gid/GidClientXml.html b/app/gid/gid_client/java/doc/com/iker/gid/GidClientXml.html new file mode 100644 index 000000000..b0b8b4148 --- /dev/null +++ b/app/gid/gid_client/java/doc/com/iker/gid/GidClientXml.html @@ -0,0 +1,296 @@ + + + + + + +GidClientXml + + + + + + + + + + + +
+
com.iker.gid
+

绫 GidClientXml

+
+
+ +
+
    +
  • +
    +
    +
    public final class GidClientXml
    +extends GidClient
    +
    鎸塜ML鏍煎紡鑾峰緱GID鏁版嵁锛岃嫢瑕佷娇鐢ㄦ鏂瑰紡鍙栧緱鍞竴ID锛屽垯鏈嶅姟鍣 + 蹇呴』鏄惎鐢ㄤ簡HTTP鍗忚璁块棶鏂瑰紡
    +
    浣滆:
    +
    zsx
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      鏋勯犲櫒姒傝

      + + + + + + + + +
      鏋勯犲櫒 
      鏋勯犲櫒鍜岃鏄
      GidClientXml(java.lang.String ip, + int port, + java.lang.String tag) 
      +
    • +
    + +
      +
    • + + +

      鏂规硶姒傝

      + + + + + + + + + + + + + + +
      鏂规硶 
      闄愬畾绗﹀拰绫诲瀷鏂规硶鍜岃鏄
      longgidNext() +
      鑾峰緱涓嬩竴涓敮涓ID鍙
      +
      static voidmain(java.lang.String[] args) 
      + +
        +
      • + + +

        浠庣被缁ф壙鐨勬柟娉 java.lang.Object

        +equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
      • +
      +
    • +
    +
  • +
+
+
+
    +
  • + +
      +
    • + + +

      鏋勯犲櫒璇︾粏璧勬枡

      + + + +
        +
      • +

        GidClientXml

        +
        public GidClientXml(java.lang.String ip,
        +            int port,
        +            java.lang.String tag)
        +
      • +
      +
    • +
    + +
      +
    • + + +

      鏂规硶璇︾粏璧勬枡

      + + + +
        +
      • +

        gidNext

        +
        public long gidNext()
        +
        浠庣被澶嶅埗鐨勮鏄: GidClient
        +
        鑾峰緱涓嬩竴涓敮涓ID鍙
        +
        +
        鎸囧畾鑰:
        +
        gidNext 鍦ㄧ被涓 GidClient
        +
        杩斿洖:
        杩斿洖鍞竴鐨64浣嶆暣鏁帮紝濡傛灉杩斿洖鍊 < 0 鍒欒〃绀哄嚭閿
        +
      • +
      + + + +
        +
      • +

        main

        +
        public static void main(java.lang.String[] args)
        +
      • +
      +
    • +
    +
  • +
+
+
+ + + + + + + diff --git a/app/gid/gid_client/java/doc/com/iker/gid/GidStatus.html b/app/gid/gid_client/java/doc/com/iker/gid/GidStatus.html new file mode 100644 index 000000000..d18ed3d3d --- /dev/null +++ b/app/gid/gid_client/java/doc/com/iker/gid/GidStatus.html @@ -0,0 +1,412 @@ + + + + + + +GidStatus + + + + + + + + + + + +
+
com.iker.gid
+

绫 GidStatus

+
+
+
    +
  • java.lang.Object
  • +
  • +
      +
    • com.iker.gid.GidStatus
    • +
    +
  • +
+
+
    +
  • +
    +
    +
    public final class GidStatus
    +extends java.lang.Object
    +
    浣滆:
    +
    zsx + 璇ョ被涓昏瀹氫箟浜咷ID鐨勯敊璇彿浠ュ強灏嗛敊璇彿杞负瀛楃涓叉弿杩颁俊鎭殑鍐呭
    +
  • +
+
+
+
    +
  • + + + +
      +
    • + + +

      鏋勯犲櫒姒傝

      + + + + + + + + +
      鏋勯犲櫒 
      鏋勯犲櫒鍜岃鏄
      GidStatus() 
      +
    • +
    + +
      +
    • + + +

      鏂规硶姒傝

      + + + + + + + + + + +
      鏂规硶 
      闄愬畾绗﹀拰绫诲瀷鏂规硶鍜岃鏄
      static java.lang.StringtoString(int gidStatus) +
      灏嗛敊璇彿杞负瀛楃涓叉弿杩颁俊鎭
      +
      +
        +
      • + + +

        浠庣被缁ф壙鐨勬柟娉 java.lang.Object

        +equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
      • +
      +
    • +
    +
  • +
+
+
+
    +
  • + + + +
      +
    • + + +

      鏋勯犲櫒璇︾粏璧勬枡

      + + + +
        +
      • +

        GidStatus

        +
        public GidStatus()
        +
      • +
      +
    • +
    + +
      +
    • + + +

      鏂规硶璇︾粏璧勬枡

      + + + +
        +
      • +

        toString

        +
        public static java.lang.String toString(int gidStatus)
        +
        灏嗛敊璇彿杞负瀛楃涓叉弿杩颁俊鎭
        +
        鍙傛暟:
        gidStatus -
        +
        杩斿洖:
        String
        +
      • +
      +
    • +
    +
  • +
+
+
+ + + + + + + diff --git a/app/gid/gid_client/java/doc/com/iker/gid/class-use/GidClient.html b/app/gid/gid_client/java/doc/com/iker/gid/class-use/GidClient.html new file mode 100644 index 000000000..dff3edad3 --- /dev/null +++ b/app/gid/gid_client/java/doc/com/iker/gid/class-use/GidClient.html @@ -0,0 +1,156 @@ + + + + + + +绫 com.iker.gid.GidClient鐨勪娇鐢 + + + + + + + + + + +
+

绫 com.iker.gid.GidClient
鐨勪娇鐢

+
+
+
    +
  • +
      +
    • + + +

      com.iker.gidGidClient鐨勪娇鐢

      + + + + + + + + + + + + + + + + + + + + +
      com.iker.gidGidClient鐨勫瓙绫 
      闄愬畾绗﹀拰绫诲瀷绫诲拰璇存槑
      class GidClientCmdLine +
      鍛戒护琛屾柟寮忎粠GID鏈嶅姟鍣ㄥ彇寰楀敮涓ID鍙凤紝鏄惁搴旇浣跨敤璇ユ柟寮忓彇寰楀敮涓ID鍙凤紝 + 搴旇鍙栧喅浜庢湇鍔″櫒鐨勯厤缃夐」
      +
      class GidClientJson +
      鎸 JSON 鏁版嵁鏍煎紡鑾峰緱GID锛岃嫢瑕佷娇鐢ㄦ鏂瑰紡鍙栧緱鍞竴ID锛屽垯鏈嶅姟鍣 + 蹇呴』鏄惎鐢ㄤ簡HTTP鍗忚璁块棶鏂瑰紡
      +
      class GidClientXml +
      鎸塜ML鏍煎紡鑾峰緱GID鏁版嵁锛岃嫢瑕佷娇鐢ㄦ鏂瑰紡鍙栧緱鍞竴ID锛屽垯鏈嶅姟鍣 + 蹇呴』鏄惎鐢ㄤ簡HTTP鍗忚璁块棶鏂瑰紡
      +
      +
    • +
    +
  • +
+
+ + + + + + diff --git a/app/gid/gid_client/java/doc/com/iker/gid/class-use/GidClientCmdLine.NameValue.html b/app/gid/gid_client/java/doc/com/iker/gid/class-use/GidClientCmdLine.NameValue.html new file mode 100644 index 000000000..0c1e878dc --- /dev/null +++ b/app/gid/gid_client/java/doc/com/iker/gid/class-use/GidClientCmdLine.NameValue.html @@ -0,0 +1,114 @@ + + + + + + +绫 com.iker.gid.GidClientCmdLine.NameValue鐨勪娇鐢 + + + + + + + + + + +
+

绫 com.iker.gid.GidClientCmdLine.NameValue
鐨勪娇鐢

+
+
娌℃湁com.iker.gid.GidClientCmdLine.NameValue鐨勭敤娉
+ + + + + + diff --git a/app/gid/gid_client/java/doc/com/iker/gid/class-use/GidClientCmdLine.Tokens.html b/app/gid/gid_client/java/doc/com/iker/gid/class-use/GidClientCmdLine.Tokens.html new file mode 100644 index 000000000..119f5446e --- /dev/null +++ b/app/gid/gid_client/java/doc/com/iker/gid/class-use/GidClientCmdLine.Tokens.html @@ -0,0 +1,114 @@ + + + + + + +绫 com.iker.gid.GidClientCmdLine.Tokens鐨勪娇鐢 + + + + + + + + + + +
+

绫 com.iker.gid.GidClientCmdLine.Tokens
鐨勪娇鐢

+
+
娌℃湁com.iker.gid.GidClientCmdLine.Tokens鐨勭敤娉
+ + + + + + diff --git a/app/gid/gid_client/java/doc/com/iker/gid/class-use/GidClientCmdLine.html b/app/gid/gid_client/java/doc/com/iker/gid/class-use/GidClientCmdLine.html new file mode 100644 index 000000000..ba5a69699 --- /dev/null +++ b/app/gid/gid_client/java/doc/com/iker/gid/class-use/GidClientCmdLine.html @@ -0,0 +1,114 @@ + + + + + + +绫 com.iker.gid.GidClientCmdLine鐨勪娇鐢 + + + + + + + + + + +
+

绫 com.iker.gid.GidClientCmdLine
鐨勪娇鐢

+
+
娌℃湁com.iker.gid.GidClientCmdLine鐨勭敤娉
+ + + + + + diff --git a/app/gid/gid_client/java/doc/com/iker/gid/class-use/GidClientJson.html b/app/gid/gid_client/java/doc/com/iker/gid/class-use/GidClientJson.html new file mode 100644 index 000000000..d7e88e6b2 --- /dev/null +++ b/app/gid/gid_client/java/doc/com/iker/gid/class-use/GidClientJson.html @@ -0,0 +1,114 @@ + + + + + + +绫 com.iker.gid.GidClientJson鐨勪娇鐢 + + + + + + + + + + +
+

绫 com.iker.gid.GidClientJson
鐨勪娇鐢

+
+
娌℃湁com.iker.gid.GidClientJson鐨勭敤娉
+ + + + + + diff --git a/app/gid/gid_client/java/doc/com/iker/gid/class-use/GidClientXml.html b/app/gid/gid_client/java/doc/com/iker/gid/class-use/GidClientXml.html new file mode 100644 index 000000000..044e0235f --- /dev/null +++ b/app/gid/gid_client/java/doc/com/iker/gid/class-use/GidClientXml.html @@ -0,0 +1,114 @@ + + + + + + +绫 com.iker.gid.GidClientXml鐨勪娇鐢 + + + + + + + + + + +
+

绫 com.iker.gid.GidClientXml
鐨勪娇鐢

+
+
娌℃湁com.iker.gid.GidClientXml鐨勭敤娉
+ + + + + + diff --git a/app/gid/gid_client/java/doc/com/iker/gid/class-use/GidStatus.html b/app/gid/gid_client/java/doc/com/iker/gid/class-use/GidStatus.html new file mode 100644 index 000000000..40388bb5a --- /dev/null +++ b/app/gid/gid_client/java/doc/com/iker/gid/class-use/GidStatus.html @@ -0,0 +1,114 @@ + + + + + + +绫 com.iker.gid.GidStatus鐨勪娇鐢 + + + + + + + + + + +
+

绫 com.iker.gid.GidStatus
鐨勪娇鐢

+
+
娌℃湁com.iker.gid.GidStatus鐨勭敤娉
+ + + + + + diff --git a/app/gid/gid_client/java/doc/com/iker/gid/package-frame.html b/app/gid/gid_client/java/doc/com/iker/gid/package-frame.html new file mode 100644 index 000000000..575bc9819 --- /dev/null +++ b/app/gid/gid_client/java/doc/com/iker/gid/package-frame.html @@ -0,0 +1,24 @@ + + + + + + +com.iker.gid + + + + +

com.iker.gid

+ + + diff --git a/app/gid/gid_client/java/doc/com/iker/gid/package-summary.html b/app/gid/gid_client/java/doc/com/iker/gid/package-summary.html new file mode 100644 index 000000000..f4c7d4413 --- /dev/null +++ b/app/gid/gid_client/java/doc/com/iker/gid/package-summary.html @@ -0,0 +1,159 @@ + + + + + + +com.iker.gid + + + + + + + + + + +
+

绋嬪簭鍖 com.iker.gid

+
+
+
    +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    绫绘瑕 
    璇存槑
    GidClient +
    鎶借薄鎺ュ彛
    +
    GidClientCmdLine +
    鍛戒护琛屾柟寮忎粠GID鏈嶅姟鍣ㄥ彇寰楀敮涓ID鍙凤紝鏄惁搴旇浣跨敤璇ユ柟寮忓彇寰楀敮涓ID鍙凤紝 + 搴旇鍙栧喅浜庢湇鍔″櫒鐨勯厤缃夐」
    +
    GidClientJson +
    鎸 JSON 鏁版嵁鏍煎紡鑾峰緱GID锛岃嫢瑕佷娇鐢ㄦ鏂瑰紡鍙栧緱鍞竴ID锛屽垯鏈嶅姟鍣 + 蹇呴』鏄惎鐢ㄤ簡HTTP鍗忚璁块棶鏂瑰紡
    +
    GidClientXml +
    鎸塜ML鏍煎紡鑾峰緱GID鏁版嵁锛岃嫢瑕佷娇鐢ㄦ鏂瑰紡鍙栧緱鍞竴ID锛屽垯鏈嶅姟鍣 + 蹇呴』鏄惎鐢ㄤ簡HTTP鍗忚璁块棶鏂瑰紡
    +
    GidStatus 
    +
  • +
+
+ + + + + + diff --git a/app/gid/gid_client/java/doc/com/iker/gid/package-tree.html b/app/gid/gid_client/java/doc/com/iker/gid/package-tree.html new file mode 100644 index 000000000..218e6f77e --- /dev/null +++ b/app/gid/gid_client/java/doc/com/iker/gid/package-tree.html @@ -0,0 +1,132 @@ + + + + + + +com.iker.gid 绫诲垎灞傜粨鏋 + + + + + + + +
+ + + + + +
+ + +
+

绋嬪簭鍖卌om.iker.gid鐨勫垎灞傜粨鏋

+
+
+

绫诲垎灞傜粨鏋

+ +
+ +
+ + + + + +
+ + + + diff --git a/app/gid/gid_client/java/doc/com/iker/gid/package-use.html b/app/gid/gid_client/java/doc/com/iker/gid/package-use.html new file mode 100644 index 000000000..bb03e208d --- /dev/null +++ b/app/gid/gid_client/java/doc/com/iker/gid/package-use.html @@ -0,0 +1,134 @@ + + + + + + +绋嬪簭鍖 com.iker.gid鐨勪娇鐢 + + + + + + + + + + +
+

绋嬪簭鍖 com.iker.gid
鐨勪娇鐢

+
+
+ +
+ + + + + + diff --git a/app/gid/gid_client/java/doc/constant-values.html b/app/gid/gid_client/java/doc/constant-values.html new file mode 100644 index 000000000..21e08ee43 --- /dev/null +++ b/app/gid/gid_client/java/doc/constant-values.html @@ -0,0 +1,199 @@ + + + + + + +甯搁噺瀛楁鍊 + + + + + + + + + + +
+

甯搁噺瀛楁鍊

+

鐩綍

+ +
+
+ + +

com.iker.*

+ +
+ + + + + + diff --git a/app/gid/gid_client/java/doc/deprecated-list.html b/app/gid/gid_client/java/doc/deprecated-list.html new file mode 100644 index 000000000..410a74f83 --- /dev/null +++ b/app/gid/gid_client/java/doc/deprecated-list.html @@ -0,0 +1,114 @@ + + + + + + +宸茶繃鏃剁殑鍒楄〃 + + + + + + + +
+ + + + + +
+ + +
+

宸茶繃鏃剁殑 API

+

鐩綍

+
+ +
+ + + + + +
+ + + + diff --git a/app/gid/gid_client/java/doc/help-doc.html b/app/gid/gid_client/java/doc/help-doc.html new file mode 100644 index 000000000..a3b57d661 --- /dev/null +++ b/app/gid/gid_client/java/doc/help-doc.html @@ -0,0 +1,215 @@ + + + + + + +API 甯姪 + + + + + + + +
+ + + + + +
+ + +
+

姝 API 鏂囨。鐨勭粍缁囨柟寮

+
姝 API (搴旂敤绋嬪簭缂栫▼鎺ュ彛) 鏂囨。鍖呭惈瀵瑰簲浜庡鑸爮涓殑椤圭洰鐨勯〉闈, 濡備笅鎵杩般
+
+
+
    +
  • +

    绋嬪簭鍖

    +

    姣忎釜绋嬪簭鍖呴兘鏈変竴涓〉闈, 鍏朵腑鍖呭惈瀹冪殑绫诲拰鎺ュ彛鐨勫垪琛ㄥ強鍏舵瑕併傛椤甸潰鍙互鍖呭惈鍏釜绫诲埆:

    +
      +
    • 鎺ュ彛 (鏂滀綋)
    • +
    • +
    • 鏋氫妇
    • +
    • 寮傚父閿欒
    • +
    • 閿欒
    • +
    • 娉ㄩ噴绫诲瀷
    • +
    +
  • +
  • +

    绫/鎺ュ彛

    +

    姣忎釜绫, 鎺ュ彛, 宓屽绫诲拰宓屽鎺ュ彛閮芥湁鍚勮嚜鐨勯〉闈€傚叾涓瘡涓〉闈㈤兘鐢变笁閮ㄥ垎 (绫/鎺ュ彛璇存槑, 姒傝琛, 浠ュ強璇︾粏鐨勬垚鍛樿鏄) 缁勬垚:

    +
      +
    • 绫荤户鎵垮浘
    • +
    • 鐩存帴瀛愮被
    • +
    • 鎵鏈夊凡鐭ュ瓙鎺ュ彛
    • +
    • 鎵鏈夊凡鐭ュ疄鐜扮被
    • +
    • 绫/鎺ュ彛澹版槑
    • +
    • 绫/鎺ュ彛璇存槑
    • +
    +
      +
    • 宓屽绫绘瑕
    • +
    • 瀛楁姒傝
    • +
    • 鏋勯犲櫒姒傝
    • +
    • 鏂规硶姒傝
    • +
    +
      +
    • 瀛楁璇︾粏璧勬枡
    • +
    • 鏋勯犲櫒璇︾粏璧勬枡
    • +
    • 鏂规硶璇︾粏璧勬枡
    • +
    +

    姣忎釜姒傝鏉$洰閮藉寘鍚椤圭洰鐨勮缁嗚鏄庣殑绗竴鍙ャ傛瑕佹潯鐩寜瀛楁瘝椤哄簭鎺掑垪, 鑰岃缁嗚鏄庡垯鎸夊叾鍦ㄦ簮浠g爜涓嚭鐜扮殑椤哄簭鎺掑垪銆傝繖鏍蜂繚鎸佷簡绋嬪簭鍛樻墍寤虹珛鐨勯昏緫鍒嗙粍銆

    +
  • +
  • +

    娉ㄩ噴绫诲瀷

    +

    姣忎釜娉ㄩ噴绫诲瀷閮芥湁鍚勮嚜鐨勯〉闈, 鍏朵腑鍖呭惈浠ヤ笅閮ㄥ垎:

    +
      +
    • 娉ㄩ噴绫诲瀷澹版槑
    • +
    • 娉ㄩ噴绫诲瀷璇存槑
    • +
    • 蹇呴渶鍏冪礌姒傝
    • +
    • 鍙夊厓绱犳瑕
    • +
    • 鍏冪礌璇︾粏璧勬枡
    • +
    +
  • +
  • +

    鏋氫妇

    +

    姣忎釜鏋氫妇閮芥湁鍚勮嚜鐨勯〉闈, 鍏朵腑鍖呭惈浠ヤ笅閮ㄥ垎:

    +
      +
    • 鏋氫妇澹版槑
    • +
    • 鏋氫妇璇存槑
    • +
    • 鏋氫妇甯搁噺姒傝
    • +
    • 鏋氫妇甯搁噺璇︾粏璧勬枡
    • +
    +
  • +
  • +

    浣跨敤

    +

    姣忎釜宸叉枃妗e寲鐨勭▼搴忓寘, 绫诲拰鎺ュ彛閮芥湁鍚勮嚜鐨勨滀娇鐢ㄢ濋〉闈€傛椤甸潰浠嬬粛浜嗕娇鐢ㄧ粰瀹氱被鎴栫▼搴忓寘鐨勪换浣曢儴鍒嗙殑绋嬪簭鍖, 绫, 鏂规硶, 鏋勯犲櫒鍜屽瓧娈点傚浜庣粰瀹氱殑绫绘垨鎺ュ彛 A, 鍏垛滀娇鐢ㄢ濋〉闈㈠寘鍚 A 鐨勫瓙绫, 澹版槑涓 A 鐨勫瓧娈, 杩斿洖 A 鐨勬柟娉, 浠ュ強甯︽湁绫诲瀷涓 A 鐨勫弬鏁扮殑鏂规硶鍜屾瀯閫犲櫒銆傝闂椤甸潰鐨勬柟娉曟槸: 棣栧厛杞嚦绋嬪簭鍖, 绫绘垨鎺ュ彛, 鐒跺悗鍗曞嚮瀵艰埅鏍忎腑鐨 "浣跨敤" 閾炬帴銆

    +
  • +
  • +

    鏍 (绫诲垎灞傜粨鏋)

    +

    瀵逛簬鎵鏈夌▼搴忓寘, 鏈変竴涓 绫诲垎灞傜粨鏋 椤甸潰, 浠ュ強姣忎釜绋嬪簭鍖呯殑鍒嗗眰缁撴瀯銆傛瘡涓垎灞傜粨鏋勯〉闈㈤兘鍖呭惈绫荤殑鍒楄〃鍜屾帴鍙g殑鍒楄〃銆備粠 java.lang.Object 寮濮, 鎸夌户鎵跨粨鏋勫绫昏繘琛屾帓鍒椼傛帴鍙d笉浠 java.lang.Object 缁ф壙銆

    +
      +
    • 鏌ョ湅鈥滄瑙堚濋〉闈㈡椂, 鍗曞嚮 "鏍" 灏嗘樉绀烘墍鏈夌▼搴忓寘鐨勫垎灞傜粨鏋勩
    • +
    • 鏌ョ湅鐗瑰畾绋嬪簭鍖, 绫绘垨鎺ュ彛椤甸潰鏃, 鍗曞嚮 "鏍" 灏嗕粎鏄剧ず璇ョ▼搴忓寘鐨勫垎灞傜粨鏋勩
    • +
    +
  • +
  • +

    宸茶繃鏃剁殑 API

    +

    宸茶繃鏃剁殑 API 椤甸潰鍒楀嚭浜嗘墍鏈夊凡杩囨椂鐨 API銆備竴鑸敱浜庤繘琛屼簡鏀硅繘骞朵笖閫氬父鎻愪緵浜嗘浛浠g殑 API, 鎵浠ュ缓璁笉瑕佷娇鐢ㄥ凡杩囨椂鐨 API銆傚湪灏嗘潵鐨勫疄鐜拌繃绋嬩腑, 鍙兘浼氬垹闄ゅ凡杩囨椂鐨 API銆

    +
  • +
  • +

    绱㈠紩

    +

    绱㈠紩 鍖呭惈鎸夊瓧姣嶉『搴忔帓鍒楃殑鎵鏈夌被, 鎺ュ彛, 鏋勯犲櫒, 鏂规硶鍜屽瓧娈电殑鍒楄〃銆

    +
  • +
  • +

    涓婁竴涓/涓嬩竴涓

    +

    杩欎簺閾炬帴浣挎偍鍙互杞嚦涓嬩竴涓垨涓婁竴涓被, 鎺ュ彛, 绋嬪簭鍖呮垨鐩稿叧椤甸潰銆

    +
  • +
  • +

    妗嗘灦/鏃犳鏋

    +

    杩欎簺閾炬帴鐢ㄤ簬鏄剧ず鍜岄殣钘 HTML 妗嗘灦銆傛墍鏈夐〉闈㈠潎鍏锋湁鏈夋鏋跺拰鏃犳鏋朵袱绉嶆樉绀烘柟寮忋

    +
  • +
  • +

    鎵鏈夌被

    +

    鎵鏈夌被閾炬帴鏄剧ず鎵鏈夌被鍜屾帴鍙 (闄や簡闈為潤鎬佸祵濂楃被鍨)銆

    +
  • +
  • +

    搴忓垪鍖栬〃鏍

    +

    姣忎釜鍙簭鍒楀寲鎴栧彲澶栭儴鍖栫殑绫婚兘鏈夊叾搴忓垪鍖栧瓧娈靛拰鏂规硶鐨勮鏄庛傛淇℃伅瀵归噸鏂板疄鐜拌呮湁鐢, 鑰屽浣跨敤 API 鐨勫紑鍙戣呭垯娌℃湁浠涔堢敤澶勩傚敖绠″鑸爮涓病鏈夐摼鎺, 浣嗘偍鍙互閫氳繃涓嬪垪鏂瑰紡鑾峰彇姝や俊鎭: 杞嚦浠讳綍搴忓垪鍖栫被, 鐒跺悗鍗曞嚮绫昏鏄庣殑 "鍙﹁鍙傞槄" 閮ㄥ垎涓殑 "搴忓垪鍖栬〃鏍"銆

    +
  • +
  • +

    甯搁噺瀛楁鍊

    +

    <a href="constant-values.html">甯搁噺瀛楁鍊</a>椤甸潰鍒楀嚭浜嗛潤鎬佹渶缁堝瓧娈靛強鍏跺笺

    +
  • +
+姝ゅ府鍔╂枃浠堕傜敤浜庝娇鐢ㄦ爣鍑 doclet 鐢熸垚鐨 API 鏂囨。銆
+ +
+ + + + + +
+ + + + diff --git a/app/gid/gid_client/java/doc/index-files/index-1.html b/app/gid/gid_client/java/doc/index-files/index-1.html new file mode 100644 index 000000000..283ead23e --- /dev/null +++ b/app/gid/gid_client/java/doc/index-files/index-1.html @@ -0,0 +1,119 @@ + + + + + + +C - 绱㈠紩 + + + + + + + +
+ + + + + +
+ + +
C G M S T  + + +

C

+
+
com.iker.gid - 绋嬪簭鍖 com.iker.gid
+
 
+
+C G M S T 
+ +
+ + + + + +
+ + + + diff --git a/app/gid/gid_client/java/doc/index-files/index-2.html b/app/gid/gid_client/java/doc/index-files/index-2.html new file mode 100644 index 000000000..952c0ba8d --- /dev/null +++ b/app/gid/gid_client/java/doc/index-files/index-2.html @@ -0,0 +1,195 @@ + + + + + + +G - 绱㈠紩 + + + + + + + +
+ + + + + +
+ + +
C G M S T  + + +

G

+
+
getInt(String) - 绫 涓殑鏂规硶com.iker.gid.GidClientCmdLine.Tokens
+
 
+
getLong(String) - 绫 涓殑鏂规硶com.iker.gid.GidClientCmdLine.Tokens
+
 
+
getString(String) - 绫 涓殑鏂规硶com.iker.gid.GidClientCmdLine.Tokens
+
 
+
GidClient - com.iker.gid涓殑绫
+
+
鎶借薄鎺ュ彛
+
+
GidClient(String, int, String) - 绫 鐨勬瀯閫犲櫒com.iker.gid.GidClient
+
 
+
GidClientCmdLine - com.iker.gid涓殑绫
+
+
鍛戒护琛屾柟寮忎粠GID鏈嶅姟鍣ㄥ彇寰楀敮涓ID鍙凤紝鏄惁搴旇浣跨敤璇ユ柟寮忓彇寰楀敮涓ID鍙凤紝 + 搴旇鍙栧喅浜庢湇鍔″櫒鐨勯厤缃夐」
+
+
GidClientCmdLine(String, int, String) - 绫 鐨勬瀯閫犲櫒com.iker.gid.GidClientCmdLine
+
 
+
GidClientCmdLine.NameValue - com.iker.gid涓殑绫
+
+
name-value 瀵圭被鍨嬬被
+
+
GidClientCmdLine.NameValue(String, String) - 绫 鐨勬瀯閫犲櫒com.iker.gid.GidClientCmdLine.NameValue
+
 
+
GidClientCmdLine.Tokens - com.iker.gid涓殑绫
+
+
鎷嗗垎瀛楃涓茬殑绫伙紝璇ョ被灏嗏滃悕鍊尖濆杩涜鎷嗗垎锛屾暟鎹牸寮忎负锛 + name1^value1|name2^value2|...
+
+
GidClientCmdLine.Tokens(String) - 绫 鐨勬瀯閫犲櫒com.iker.gid.GidClientCmdLine.Tokens
+
 
+
GidClientJson - com.iker.gid涓殑绫
+
+
鎸 JSON 鏁版嵁鏍煎紡鑾峰緱GID锛岃嫢瑕佷娇鐢ㄦ鏂瑰紡鍙栧緱鍞竴ID锛屽垯鏈嶅姟鍣 + 蹇呴』鏄惎鐢ㄤ簡HTTP鍗忚璁块棶鏂瑰紡
+
+
GidClientJson(String, int, String) - 绫 鐨勬瀯閫犲櫒com.iker.gid.GidClientJson
+
 
+
GidClientXml - com.iker.gid涓殑绫
+
+
鎸塜ML鏍煎紡鑾峰緱GID鏁版嵁锛岃嫢瑕佷娇鐢ㄦ鏂瑰紡鍙栧緱鍞竴ID锛屽垯鏈嶅姟鍣 + 蹇呴』鏄惎鐢ㄤ簡HTTP鍗忚璁块棶鏂瑰紡
+
+
GidClientXml(String, int, String) - 绫 鐨勬瀯閫犲櫒com.iker.gid.GidClientXml
+
 
+
gidErrConn - 绫 涓殑闈欐佸彉閲廲om.iker.gid.GidStatus
+
 
+
gidErrInit - 绫 涓殑闈欐佸彉閲廲om.iker.gid.GidStatus
+
 
+
gidErrIo - 绫 涓殑闈欐佸彉閲廲om.iker.gid.GidStatus
+
 
+
gidErrOverride - 绫 涓殑闈欐佸彉閲廲om.iker.gid.GidStatus
+
 
+
gidErrProto - 绫 涓殑闈欐佸彉閲廲om.iker.gid.GidStatus
+
 
+
gidErrSave - 绫 涓殑闈欐佸彉閲廲om.iker.gid.GidStatus
+
 
+
gidErrServer - 绫 涓殑闈欐佸彉閲廲om.iker.gid.GidStatus
+
 
+
gidErrSid - 绫 涓殑闈欐佸彉閲廲om.iker.gid.GidStatus
+
 
+
gidNext() - 绫 涓殑鏂规硶com.iker.gid.GidClient
+
+
鑾峰緱涓嬩竴涓敮涓ID鍙
+
+
gidNext() - 绫 涓殑鏂规硶com.iker.gid.GidClientCmdLine
+
 
+
gidNext() - 绫 涓殑鏂规硶com.iker.gid.GidClientJson
+
 
+
gidNext() - 绫 涓殑鏂规硶com.iker.gid.GidClientXml
+
 
+
gidOk - 绫 涓殑闈欐佸彉閲廲om.iker.gid.GidStatus
+
 
+
GidStatus - com.iker.gid涓殑绫
+
 
+
GidStatus() - 绫 鐨勬瀯閫犲櫒com.iker.gid.GidStatus
+
 
+
+C G M S T 
+ +
+ + + + + +
+ + + + diff --git a/app/gid/gid_client/java/doc/index-files/index-3.html b/app/gid/gid_client/java/doc/index-files/index-3.html new file mode 100644 index 000000000..a05125833 --- /dev/null +++ b/app/gid/gid_client/java/doc/index-files/index-3.html @@ -0,0 +1,123 @@ + + + + + + +M - 绱㈠紩 + + + + + + + +
+ + + + + +
+ + +
C G M S T  + + +

M

+
+
main(String[]) - 绫 涓殑闈欐佹柟娉昪om.iker.gid.GidClientCmdLine
+
 
+
main(String[]) - 绫 涓殑闈欐佹柟娉昪om.iker.gid.GidClientJson
+
 
+
main(String[]) - 绫 涓殑闈欐佹柟娉昪om.iker.gid.GidClientXml
+
 
+
+C G M S T 
+ +
+ + + + + +
+ + + + diff --git a/app/gid/gid_client/java/doc/index-files/index-4.html b/app/gid/gid_client/java/doc/index-files/index-4.html new file mode 100644 index 000000000..1e76d08db --- /dev/null +++ b/app/gid/gid_client/java/doc/index-files/index-4.html @@ -0,0 +1,125 @@ + + + + + + +S - 绱㈠紩 + + + + + + + +
+ + + + + +
+ + +
C G M S T  + + +

S

+
+
setConnectTimeout(int) - 绫 涓殑鏂规硶com.iker.gid.GidClient
+
+
璁剧疆缁滆繛鎺ユ椂闂
+
+
setRdTimeout(int) - 绫 涓殑鏂规硶com.iker.gid.GidClient
+
+
璁剧疆IO璇昏秴鏃舵椂闂
+
+
+C G M S T 
+ +
+ + + + + +
+ + + + diff --git a/app/gid/gid_client/java/doc/index-files/index-5.html b/app/gid/gid_client/java/doc/index-files/index-5.html new file mode 100644 index 000000000..bbd9e667a --- /dev/null +++ b/app/gid/gid_client/java/doc/index-files/index-5.html @@ -0,0 +1,121 @@ + + + + + + +T - 绱㈠紩 + + + + + + + +
+ + + + + +
+ + +
C G M S T  + + +

T

+
+
toString(int) - 绫 涓殑闈欐佹柟娉昪om.iker.gid.GidStatus
+
+
灏嗛敊璇彿杞负瀛楃涓叉弿杩颁俊鎭
+
+
+C G M S T 
+ +
+ + + + + +
+ + + + diff --git a/app/gid/gid_client/java/doc/index.html b/app/gid/gid_client/java/doc/index.html new file mode 100644 index 000000000..53a18a33d --- /dev/null +++ b/app/gid/gid_client/java/doc/index.html @@ -0,0 +1,31 @@ + + + + + + +鐢熸垚鐨勬枃妗 (鏃犳爣棰) + + + + + + +<noscript> +<div>鎮ㄧ殑娴忚鍣ㄥ凡绂佺敤 JavaScript銆</div> +</noscript> +<h2>妗嗘灦棰勮</h2> +<p>璇蜂娇鐢ㄦ鏋跺姛鑳芥煡鐪嬫鏂囨。銆傚鏋滅湅鍒版娑堟伅, 鍒欒〃鏄庢偍浣跨敤鐨勬槸涓嶆敮鎸佹鏋剁殑 Web 瀹㈡埛鏈恒傞摼鎺ュ埌<a href="com/iker/gid/package-summary.html">闈炴鏋剁増鏈</a>銆</p> + + + diff --git a/app/gid/gid_client/java/doc/overview-tree.html b/app/gid/gid_client/java/doc/overview-tree.html new file mode 100644 index 000000000..847a3d210 --- /dev/null +++ b/app/gid/gid_client/java/doc/overview-tree.html @@ -0,0 +1,136 @@ + + + + + + +绫诲垎灞傜粨鏋 + + + + + + + +
+ + + + + +
+ + +
+

鎵鏈夌▼搴忓寘鐨勫垎灞傜粨鏋

+绋嬪簭鍖呭垎灞傜粨鏋: + +
+
+

绫诲垎灞傜粨鏋

+ +
+ +
+ + + + + +
+ + + + diff --git a/app/gid/gid_client/java/doc/package-list b/app/gid/gid_client/java/doc/package-list new file mode 100644 index 000000000..fa0ce737e --- /dev/null +++ b/app/gid/gid_client/java/doc/package-list @@ -0,0 +1 @@ +com.iker.gid diff --git a/app/gid/gid_client/java/doc/resources/background.gif b/app/gid/gid_client/java/doc/resources/background.gif new file mode 100644 index 000000000..f471940fd Binary files /dev/null and b/app/gid/gid_client/java/doc/resources/background.gif differ diff --git a/app/gid/gid_client/java/doc/resources/tab.gif b/app/gid/gid_client/java/doc/resources/tab.gif new file mode 100644 index 000000000..1a73a83be Binary files /dev/null and b/app/gid/gid_client/java/doc/resources/tab.gif differ diff --git a/app/gid/gid_client/java/doc/resources/titlebar.gif b/app/gid/gid_client/java/doc/resources/titlebar.gif new file mode 100644 index 000000000..17443b3e1 Binary files /dev/null and b/app/gid/gid_client/java/doc/resources/titlebar.gif differ diff --git a/app/gid/gid_client/java/doc/resources/titlebar_end.gif b/app/gid/gid_client/java/doc/resources/titlebar_end.gif new file mode 100644 index 000000000..3ad78d461 Binary files /dev/null and b/app/gid/gid_client/java/doc/resources/titlebar_end.gif differ diff --git a/app/gid/gid_client/java/doc/stylesheet.css b/app/gid/gid_client/java/doc/stylesheet.css new file mode 100644 index 000000000..0aeaa97fe --- /dev/null +++ b/app/gid/gid_client/java/doc/stylesheet.css @@ -0,0 +1,474 @@ +/* Javadoc style sheet */ +/* +Overall document style +*/ +body { + background-color:#ffffff; + color:#353833; + font-family:Arial, Helvetica, sans-serif; + font-size:76%; + margin:0; +} +a:link, a:visited { + text-decoration:none; + color:#4c6b87; +} +a:hover, a:focus { + text-decoration:none; + color:#bb7a2a; +} +a:active { + text-decoration:none; + color:#4c6b87; +} +a[name] { + color:#353833; +} +a[name]:hover { + text-decoration:none; + color:#353833; +} +pre { + font-size:1.3em; +} +h1 { + font-size:1.8em; +} +h2 { + font-size:1.5em; +} +h3 { + font-size:1.4em; +} +h4 { + font-size:1.3em; +} +h5 { + font-size:1.2em; +} +h6 { + font-size:1.1em; +} +ul { + list-style-type:disc; +} +code, tt { + font-size:1.2em; +} +dt code { + font-size:1.2em; +} +table tr td dt code { + font-size:1.2em; + vertical-align:top; +} +sup { + font-size:.6em; +} +/* +Document title and Copyright styles +*/ +.clear { + clear:both; + height:0px; + overflow:hidden; +} +.aboutLanguage { + float:right; + padding:0px 21px; + font-size:.8em; + z-index:200; + margin-top:-7px; +} +.legalCopy { + margin-left:.5em; +} +.bar a, .bar a:link, .bar a:visited, .bar a:active { + color:#FFFFFF; + text-decoration:none; +} +.bar a:hover, .bar a:focus { + color:#bb7a2a; +} +.tab { + background-color:#0066FF; + background-image:url(resources/titlebar.gif); + background-position:left top; + background-repeat:no-repeat; + color:#ffffff; + padding:8px; + width:5em; + font-weight:bold; +} +/* +Navigation bar styles +*/ +.bar { + background-image:url(resources/background.gif); + background-repeat:repeat-x; + color:#FFFFFF; + padding:.8em .5em .4em .8em; + height:auto;/*height:1.8em;*/ + font-size:1em; + margin:0; +} +.topNav { + background-image:url(resources/background.gif); + background-repeat:repeat-x; + color:#FFFFFF; + float:left; + padding:0; + width:100%; + clear:right; + height:2.8em; + padding-top:10px; + overflow:hidden; +} +.bottomNav { + margin-top:10px; + background-image:url(resources/background.gif); + background-repeat:repeat-x; + color:#FFFFFF; + float:left; + padding:0; + width:100%; + clear:right; + height:2.8em; + padding-top:10px; + overflow:hidden; +} +.subNav { + background-color:#dee3e9; + border-bottom:1px solid #9eadc0; + float:left; + width:100%; + overflow:hidden; +} +.subNav div { + clear:left; + float:left; + padding:0 0 5px 6px; +} +ul.navList, ul.subNavList { + float:left; + margin:0 25px 0 0; + padding:0; +} +ul.navList li{ + list-style:none; + float:left; + padding:3px 6px; +} +ul.subNavList li{ + list-style:none; + float:left; + font-size:90%; +} +.topNav a:link, .topNav a:active, .topNav a:visited, .bottomNav a:link, .bottomNav a:active, .bottomNav a:visited { + color:#FFFFFF; + text-decoration:none; +} +.topNav a:hover, .bottomNav a:hover { + text-decoration:none; + color:#bb7a2a; +} +.navBarCell1Rev { + background-image:url(resources/tab.gif); + background-color:#a88834; + color:#FFFFFF; + margin: auto 5px; + border:1px solid #c9aa44; +} +/* +Page header and footer styles +*/ +.header, .footer { + clear:both; + margin:0 20px; + padding:5px 0 0 0; +} +.indexHeader { + margin:10px; + position:relative; +} +.indexHeader h1 { + font-size:1.3em; +} +.title { + color:#2c4557; + margin:10px 0; +} +.subTitle { + margin:5px 0 0 0; +} +.header ul { + margin:0 0 25px 0; + padding:0; +} +.footer ul { + margin:20px 0 5px 0; +} +.header ul li, .footer ul li { + list-style:none; + font-size:1.2em; +} +/* +Heading styles +*/ +div.details ul.blockList ul.blockList ul.blockList li.blockList h4, div.details ul.blockList ul.blockList ul.blockListLast li.blockList h4 { + background-color:#dee3e9; + border-top:1px solid #9eadc0; + border-bottom:1px solid #9eadc0; + margin:0 0 6px -8px; + padding:2px 5px; +} +ul.blockList ul.blockList ul.blockList li.blockList h3 { + background-color:#dee3e9; + border-top:1px solid #9eadc0; + border-bottom:1px solid #9eadc0; + margin:0 0 6px -8px; + padding:2px 5px; +} +ul.blockList ul.blockList li.blockList h3 { + padding:0; + margin:15px 0; +} +ul.blockList li.blockList h2 { + padding:0px 0 20px 0; +} +/* +Page layout container styles +*/ +.contentContainer, .sourceContainer, .classUseContainer, .serializedFormContainer, .constantValuesContainer { + clear:both; + padding:10px 20px; + position:relative; +} +.indexContainer { + margin:10px; + position:relative; + font-size:1.0em; +} +.indexContainer h2 { + font-size:1.1em; + padding:0 0 3px 0; +} +.indexContainer ul { + margin:0; + padding:0; +} +.indexContainer ul li { + list-style:none; +} +.contentContainer .description dl dt, .contentContainer .details dl dt, .serializedFormContainer dl dt { + font-size:1.1em; + font-weight:bold; + margin:10px 0 0 0; + color:#4E4E4E; +} +.contentContainer .description dl dd, .contentContainer .details dl dd, .serializedFormContainer dl dd { + margin:10px 0 10px 20px; +} +.serializedFormContainer dl.nameValue dt { + margin-left:1px; + font-size:1.1em; + display:inline; + font-weight:bold; +} +.serializedFormContainer dl.nameValue dd { + margin:0 0 0 1px; + font-size:1.1em; + display:inline; +} +/* +List styles +*/ +ul.horizontal li { + display:inline; + font-size:0.9em; +} +ul.inheritance { + margin:0; + padding:0; +} +ul.inheritance li { + display:inline; + list-style:none; +} +ul.inheritance li ul.inheritance { + margin-left:15px; + padding-left:15px; + padding-top:1px; +} +ul.blockList, ul.blockListLast { + margin:10px 0 10px 0; + padding:0; +} +ul.blockList li.blockList, ul.blockListLast li.blockList { + list-style:none; + margin-bottom:25px; +} +ul.blockList ul.blockList li.blockList, ul.blockList ul.blockListLast li.blockList { + padding:0px 20px 5px 10px; + border:1px solid #9eadc0; + background-color:#f9f9f9; +} +ul.blockList ul.blockList ul.blockList li.blockList, ul.blockList ul.blockList ul.blockListLast li.blockList { + padding:0 0 5px 8px; + background-color:#ffffff; + border:1px solid #9eadc0; + border-top:none; +} +ul.blockList ul.blockList ul.blockList ul.blockList li.blockList { + margin-left:0; + padding-left:0; + padding-bottom:15px; + border:none; + border-bottom:1px solid #9eadc0; +} +ul.blockList ul.blockList ul.blockList ul.blockList li.blockListLast { + list-style:none; + border-bottom:none; + padding-bottom:0; +} +table tr td dl, table tr td dl dt, table tr td dl dd { + margin-top:0; + margin-bottom:1px; +} +/* +Table styles +*/ +.contentContainer table, .classUseContainer table, .constantValuesContainer table { + border-bottom:1px solid #9eadc0; + width:100%; +} +.contentContainer ul li table, .classUseContainer ul li table, .constantValuesContainer ul li table { + width:100%; +} +.contentContainer .description table, .contentContainer .details table { + border-bottom:none; +} +.contentContainer ul li table th.colOne, .contentContainer ul li table th.colFirst, .contentContainer ul li table th.colLast, .classUseContainer ul li table th, .constantValuesContainer ul li table th, .contentContainer ul li table td.colOne, .contentContainer ul li table td.colFirst, .contentContainer ul li table td.colLast, .classUseContainer ul li table td, .constantValuesContainer ul li table td{ + vertical-align:top; + padding-right:20px; +} +.contentContainer ul li table th.colLast, .classUseContainer ul li table th.colLast,.constantValuesContainer ul li table th.colLast, +.contentContainer ul li table td.colLast, .classUseContainer ul li table td.colLast,.constantValuesContainer ul li table td.colLast, +.contentContainer ul li table th.colOne, .classUseContainer ul li table th.colOne, +.contentContainer ul li table td.colOne, .classUseContainer ul li table td.colOne { + padding-right:3px; +} +.overviewSummary caption, .packageSummary caption, .contentContainer ul.blockList li.blockList caption, .summary caption, .classUseContainer caption, .constantValuesContainer caption { + position:relative; + text-align:left; + background-repeat:no-repeat; + color:#FFFFFF; + font-weight:bold; + clear:none; + overflow:hidden; + padding:0px; + margin:0px; +} +caption a:link, caption a:hover, caption a:active, caption a:visited { + color:#FFFFFF; +} +.overviewSummary caption span, .packageSummary caption span, .contentContainer ul.blockList li.blockList caption span, .summary caption span, .classUseContainer caption span, .constantValuesContainer caption span { + white-space:nowrap; + padding-top:8px; + padding-left:8px; + display:block; + float:left; + background-image:url(resources/titlebar.gif); + height:18px; +} +.overviewSummary .tabEnd, .packageSummary .tabEnd, .contentContainer ul.blockList li.blockList .tabEnd, .summary .tabEnd, .classUseContainer .tabEnd, .constantValuesContainer .tabEnd { + width:10px; + background-image:url(resources/titlebar_end.gif); + background-repeat:no-repeat; + background-position:top right; + position:relative; + float:left; +} +ul.blockList ul.blockList li.blockList table { + margin:0 0 12px 0px; + width:100%; +} +.tableSubHeadingColor { + background-color: #EEEEFF; +} +.altColor { + background-color:#eeeeef; +} +.rowColor { + background-color:#ffffff; +} +.overviewSummary td, .packageSummary td, .contentContainer ul.blockList li.blockList td, .summary td, .classUseContainer td, .constantValuesContainer td { + text-align:left; + padding:3px 3px 3px 7px; +} +th.colFirst, th.colLast, th.colOne, .constantValuesContainer th { + background:#dee3e9; + border-top:1px solid #9eadc0; + border-bottom:1px solid #9eadc0; + text-align:left; + padding:3px 3px 3px 7px; +} +td.colOne a:link, td.colOne a:active, td.colOne a:visited, td.colOne a:hover, td.colFirst a:link, td.colFirst a:active, td.colFirst a:visited, td.colFirst a:hover, td.colLast a:link, td.colLast a:active, td.colLast a:visited, td.colLast a:hover, .constantValuesContainer td a:link, .constantValuesContainer td a:active, .constantValuesContainer td a:visited, .constantValuesContainer td a:hover { + font-weight:bold; +} +td.colFirst, th.colFirst { + border-left:1px solid #9eadc0; + white-space:nowrap; +} +td.colLast, th.colLast { + border-right:1px solid #9eadc0; +} +td.colOne, th.colOne { + border-right:1px solid #9eadc0; + border-left:1px solid #9eadc0; +} +table.overviewSummary { + padding:0px; + margin-left:0px; +} +table.overviewSummary td.colFirst, table.overviewSummary th.colFirst, +table.overviewSummary td.colOne, table.overviewSummary th.colOne { + width:25%; + vertical-align:middle; +} +table.packageSummary td.colFirst, table.overviewSummary th.colFirst { + width:25%; + vertical-align:middle; +} +/* +Content styles +*/ +.description pre { + margin-top:0; +} +.deprecatedContent { + margin:0; + padding:10px 0; +} +.docSummary { + padding:0; +} +/* +Formatting effect styles +*/ +.sourceLineNo { + color:green; + padding:0 30px 0 0; +} +h1.hidden { + visibility:hidden; + overflow:hidden; + font-size:.9em; +} +.block { + display:block; + margin:3px 0 0 0; +} +.strong { + font-weight:bold; +} diff --git a/app/gid/gid_client/java/jar/commons-beanutils-1.8.3.jar b/app/gid/gid_client/java/jar/commons-beanutils-1.8.3.jar new file mode 100644 index 000000000..218510bc5 Binary files /dev/null and b/app/gid/gid_client/java/jar/commons-beanutils-1.8.3.jar differ diff --git a/app/gid/gid_client/java/jar/commons-collections-3.2.1.jar b/app/gid/gid_client/java/jar/commons-collections-3.2.1.jar new file mode 100644 index 000000000..c35fa1fee Binary files /dev/null and b/app/gid/gid_client/java/jar/commons-collections-3.2.1.jar differ diff --git a/app/gid/gid_client/java/jar/commons-lang-2.6.jar b/app/gid/gid_client/java/jar/commons-lang-2.6.jar new file mode 100644 index 000000000..98467d3a6 Binary files /dev/null and b/app/gid/gid_client/java/jar/commons-lang-2.6.jar differ diff --git a/app/gid/gid_client/java/jar/commons-logging-1.1.1.jar b/app/gid/gid_client/java/jar/commons-logging-1.1.1.jar new file mode 100644 index 000000000..1deef144c Binary files /dev/null and b/app/gid/gid_client/java/jar/commons-logging-1.1.1.jar differ diff --git a/app/gid/gid_client/java/jar/ezmorph-1.0.6.jar b/app/gid/gid_client/java/jar/ezmorph-1.0.6.jar new file mode 100644 index 000000000..30fad12d8 Binary files /dev/null and b/app/gid/gid_client/java/jar/ezmorph-1.0.6.jar differ diff --git a/app/gid/gid_client/java/jar/json-lib-2.4-jdk15.jar b/app/gid/gid_client/java/jar/json-lib-2.4-jdk15.jar new file mode 100644 index 000000000..68d4f3b09 Binary files /dev/null and b/app/gid/gid_client/java/jar/json-lib-2.4-jdk15.jar differ diff --git a/app/gid/gid_client/java/src/com/iker/gid/GidClient.java b/app/gid/gid_client/java/src/com/iker/gid/GidClient.java new file mode 100644 index 000000000..567ba1ef1 --- /dev/null +++ b/app/gid/gid_client/java/src/com/iker/gid/GidClient.java @@ -0,0 +1,125 @@ +package com.iker.gid; + +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.InetSocketAddress; +import java.net.MalformedURLException; +import java.net.Socket; +import java.net.SocketAddress; +import java.net.URL; +import java.net.UnknownHostException; + +/** + * 鎶借薄鎺ュ彛 + * @author zsx + * + */ +public abstract class GidClient { + protected int errnum = 0; + protected String serverIp = "192.168.1.251"; + protected int serverPort = 7072; + protected String tagName = "default"; + protected int connTimeout = 10000; /* 杩炴帴瓒呮椂鏃堕棿涓10绉 */ + protected int rdTimeout = 30000; /* 璇昏秴鏃舵椂闂翠负30绉 */ + + public GidClient(String ip, int port, String tag) + { + if (ip.isEmpty() == false) + this.serverIp = ip; + if (port > 0) + this.serverPort = port; + if (tag != "") + this.tagName = tag; + } + + /** + * 鑾峰緱涓嬩竴涓敮涓ID鍙 + * @return 杩斿洖鍞竴鐨64浣嶆暣鏁帮紝濡傛灉杩斿洖鍊 < 0 鍒欒〃绀哄嚭閿 + */ + abstract public long gidNext(); + + protected HttpURLConnection OpenUrl(String gidFmt) + { + String urlAddr = "http://" + serverIp + ":" + serverPort + "/"; + HttpURLConnection urlConnection = null; + + try { + URL url = new URL(urlAddr); + urlConnection = (HttpURLConnection) url.openConnection(); + urlConnection.setConnectTimeout(connTimeout); + urlConnection.setReadTimeout(rdTimeout); + + // 璁剧疆鏄惁浠巋ttpUrlConnection璇诲叆锛岄粯璁ゆ儏鍐典笅鏄痶rue; + urlConnection.setDoInput(true); + + // 璁剧疆鏄惁鍚慼ttpUrlConnection杈撳嚭锛屽洜涓鸿繖涓槸post璇锋眰锛 + // 鍙傛暟瑕佹斁鍦 http姝f枃鍐咃紝鍥犳闇瑕佽涓簍rue, 榛樿鎯呭喌涓嬫槸false; + urlConnection.setDoOutput(true); + + // 璁剧疆涓 POST 璇锋眰鏂瑰紡 + urlConnection.setRequestMethod("POST"); + + // Post 璇锋眰涓嶈兘浣跨敤缂撳瓨 + urlConnection.setUseCaches(false); + urlConnection.setInstanceFollowRedirects(false); + urlConnection.setRequestProperty("User-Agent", + "ESite JAVA Agent"); + urlConnection.setRequestProperty("Content-Type", + "text/plain;charset=utf8"); + urlConnection.setRequestProperty("x-gid-format", gidFmt); + } catch (MalformedURLException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + + return (urlConnection); + } + + /** + * 璁剧疆IO璇昏秴鏃舵椂闂 + * @param timeout 瓒呮椂鏃堕棿锛堝崟浣嶄负绉掞級锛屽鏋滀笉璁剧疆姝ゆ椂闂达紝 + * 鍒欏唴閮ㄧ己鐪佸间负30绉 + */ + public void setRdTimeout(int timeout) + { + // 灏嗙杞负姣 + rdTimeout = timeout * 1000; + } + + /** + * 璁剧疆缁滆繛鎺ユ椂闂 + * @param timeout 瓒呮椂鏃堕棿锛堝崟浣嶄负绉掞級锛屽鏋滀笉璁剧疆姝ゆ椂闂达紝 + * 鍒欏唴閮ㄧ己鐪佸间负10绉 + */ + public void setConnectTimeout(int timeout) + { + // 灏嗙杞负姣 + connTimeout = timeout * 1000; + } + + protected Socket OpenTcp() { + Socket socket = null; + try { + socket = new Socket(); + socket.setSoTimeout(rdTimeout); + SocketAddress socketAddress = + new InetSocketAddress(serverIp, serverPort); + // 甯﹁繛鎺ヨ秴鏃舵柟寮忚繛鎺ユ湇鍔″櫒 + socket.connect(socketAddress, connTimeout); + } catch (UnknownHostException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + return socket; + } + + /** + * 杩斿洖鍑洪敊鍙 + * @return 閿欒鍙 + */ + int getLastError() { + return errnum; + } +} diff --git a/app/gid/gid_client/java/src/com/iker/gid/GidClientCmdLine.java b/app/gid/gid_client/java/src/com/iker/gid/GidClientCmdLine.java new file mode 100644 index 000000000..3238f404a --- /dev/null +++ b/app/gid/gid_client/java/src/com/iker/gid/GidClientCmdLine.java @@ -0,0 +1,156 @@ +package com.iker.gid; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.Socket; +import java.util.StringTokenizer; +import java.util.Vector; + +/** + * 鍛戒护琛屾柟寮忎粠GID鏈嶅姟鍣ㄥ彇寰楀敮涓ID鍙凤紝鏄惁搴旇浣跨敤璇ユ柟寮忓彇寰楀敮涓ID鍙凤紝 + * 搴旇鍙栧喅浜庢湇鍔″櫒鐨勯厤缃夐」 + * @author zsx + * + */ +public final class GidClientCmdLine extends GidClient { + public GidClientCmdLine(String ip, int port, String tag) + { + super(ip, port, tag); + } + + /** + * name-value 瀵圭被鍨嬬被 + */ + public final class NameValue { + private String name; + private String value; + + public NameValue(String name, String value) { + this.name = name; + this.value = value; + } + + String getName() + { + return name; + } + + String getValue() + { + return value; + } + } + + /** + * 鎷嗗垎瀛楃涓茬殑绫伙紝璇ョ被灏嗏滃悕鍊尖濆杩涜鎷嗗垎锛屾暟鎹牸寮忎负锛 + * name1^value1|name2^value2|... + */ + public final class Tokens { + private static final String spliter1 = "|"; + private static final String spliter2 = "\\^"; + + private Vector tokens = new Vector();; + + public Tokens(String content) { + StringTokenizer sk = new StringTokenizer(content, spliter1); + while (sk.hasMoreTokens()) { + String str = sk.nextToken(); + String[] nv = str.split(spliter2); + if (nv.length != 2) + continue; + tokens.add(new NameValue(nv[0], nv[1])); + } + } + + public String getString(String name) + { + for (int i = 0; i < tokens.size(); i++) { + NameValue token = tokens.get(i); + if (token.getName().equalsIgnoreCase(name)) + return token.getValue(); + } + + return ""; + } + + public long getLong(String name) + { + for (int i = 0; i < tokens.size(); i++) { + NameValue token = tokens.get(i); + if (token.getName().equalsIgnoreCase(name)) + return Long.parseLong(token.getValue()); + } + + return -1; + } + + public int getInt(String name) + { + for (int i = 0; i < tokens.size(); i++) { + NameValue token = tokens.get(i); + if (token.getName().equalsIgnoreCase(name)) + return Integer.parseInt(token.getValue()); + } + + return -1; + } + } + + @Override + public long gidNext() { + Socket socket = null; + try { + socket = OpenTcp(); + + OutputStream out = socket.getOutputStream(); + /* 璇锋眰鐨勬暟鎹牸寮忥細CMD^new_gid|TAG^default */ + String buf = "CMD^new_gid|TAG^" + tagName + "\r\n"; + out.write(buf.getBytes()); + out.flush(); + //out.close(); + + /* 鍝嶅簲鏁版嵁鏍煎紡锛歴tatus^ok[|error]|gid^xxx[|tag^xxx|err^xxx|msg^xxx] */ + InputStream in = socket.getInputStream(); + BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + buf = reader.readLine(); + + out.close(); + in.close(); + + Tokens tokens = new Tokens(buf); + String status = tokens.getString("status"); + if (status.equalsIgnoreCase("ok") == false) { + errnum = tokens.getInt("err"); + return -1; + } + return tokens.getLong("gid"); + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + if (socket != null) + socket.close(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + return -1; + } + + public static void main(String[] args) { + final String ip = "192.168.1.251"; + final int port = 7072; + final String tag = "default"; + + GidClient gidClient = new GidClientCmdLine(ip, port, tag); + + for (int i = 0; i < 100; i++) { + long gid = gidClient.gidNext(); + System.out.print(">>cmdline gid: " + gid + "\r"); + } + } +} diff --git a/app/gid/gid_client/java/src/com/iker/gid/GidClientJson.java b/app/gid/gid_client/java/src/com/iker/gid/GidClientJson.java new file mode 100644 index 000000000..619798448 --- /dev/null +++ b/app/gid/gid_client/java/src/com/iker/gid/GidClientJson.java @@ -0,0 +1,87 @@ +package com.iker.gid; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.HttpURLConnection; + +import net.sf.json.JSONObject; + +/** + * 鎸 JSON 鏁版嵁鏍煎紡鑾峰緱GID锛岃嫢瑕佷娇鐢ㄦ鏂瑰紡鍙栧緱鍞竴ID锛屽垯鏈嶅姟鍣 + * 蹇呴』鏄惎鐢ㄤ簡HTTP鍗忚璁块棶鏂瑰紡 + * @author zsx + * + */ +public final class GidClientJson extends GidClient { + + public GidClientJson(String ip, int port, String tag) + { + super(ip, port, tag); + } + + @Override + public long gidNext() { + // TODO Auto-generated method stub + HttpURLConnection urlConnection = null; + try { + urlConnection = OpenUrl("json"); + OutputStream os = urlConnection.getOutputStream(); + + /* 璇锋眰鐨勬暟鎹牸寮忥細{ cmd: 'new_gid'; tag: 'xxx'; } */ + JSONObject json = new JSONObject(); + json.put("cmd", "new_gid"); + json.put("tag", tagName); + + os.write(json.toString().getBytes()); + os.flush(); + //os.close(); + + /* 杩斿洖鐨勬暟鎹牸寮: { status: 'ok|error'; gid: xxx; tag: 'xxx'; msg: 'xxx'; err: 'xxx'; } */ + InputStream in = urlConnection.getInputStream(); + BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + String buf=""; + char[] tmp = new char[128]; + while (true) { + + if (reader.read(tmp) == -1) + break; + buf += new String(tmp); + } + buf.toLowerCase(); // 鍏堣浆涓哄皬鍐 + + JSONObject jsonRet = JSONObject.fromObject(buf); + String status = jsonRet.getString("status"); + if (status.equals("ok") == false) { + String err = jsonRet.getString("err"); + if (err.equals("") == false) + errnum = Integer.parseInt(err); + return -1; + } + long gid = jsonRet.getLong("gid"); + return gid; + } catch (IOException e) { + e.printStackTrace(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (urlConnection != null) + urlConnection.disconnect(); + } + return -1; + } + + public static void main(String[] args) { + final String ip = "192.168.1.251"; + final int port = 7072; + final String tag = "default"; + + GidClient gidClient = new GidClientJson(ip, port, tag); + for (int i = 0; i < 100; i++) { + long gid = gidClient.gidNext(); + System.out.print(">>json gid: " + gid + "\r\n"); + } + } +} diff --git a/app/gid/gid_client/java/src/com/iker/gid/GidClientXml.java b/app/gid/gid_client/java/src/com/iker/gid/GidClientXml.java new file mode 100644 index 000000000..1b98919ea --- /dev/null +++ b/app/gid/gid_client/java/src/com/iker/gid/GidClientXml.java @@ -0,0 +1,82 @@ +package com.iker.gid; +import java.io.IOException; +import java.io.OutputStream; +import java.net.HttpURLConnection; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.xml.sax.SAXException; + +/** + * 鎸塜ML鏍煎紡鑾峰緱GID鏁版嵁锛岃嫢瑕佷娇鐢ㄦ鏂瑰紡鍙栧緱鍞竴ID锛屽垯鏈嶅姟鍣 + * 蹇呴』鏄惎鐢ㄤ簡HTTP鍗忚璁块棶鏂瑰紡 + * @author zsx + * + */ +public final class GidClientXml extends GidClient { + + public GidClientXml(String ip, int port, String tag) + { + super(ip, port, tag); + } + + @Override + public long gidNext() { + // TODO Auto-generated method stub + HttpURLConnection urlConnection = null; + try { + urlConnection = OpenUrl("xml"); // 杩炴帴鏈嶅姟鍣 + OutputStream os = urlConnection.getOutputStream(); + String body = ""; + os.write(body.getBytes()); + os.flush(); + //os.close(); + + /* 杩斿洖鐨勬暟鎹牸寮: */ + + try { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + DocumentBuilder db = dbf.newDocumentBuilder(); + Document document = db.parse(urlConnection.getInputStream()); + Element root = document.getDocumentElement(); + + String status = root.getAttribute("status"); + String gidStr = root.getAttribute("gid"); + if (status.equals("ok") == false || gidStr.equals("")) { + String err = root.getAttribute("err"); + if (err.equals("") == false) + errnum = Integer.parseInt(err); + return -1; + } + long gid = Long.parseLong(gidStr); + return gid; + } catch (ParserConfigurationException e) { + e.printStackTrace(); + } catch(SAXException e) { + e.printStackTrace(); + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + if (urlConnection != null) + urlConnection.disconnect(); + } + return -1; + } + + public static void main(String[] args) { + final String ip = "192.168.1.251"; + final int port = 7072; + final String tag = "default"; + + GidClient gidClient = new GidClientXml(ip, port, tag); + for (int i = 0; i < 100; i++) { + long gid = gidClient.gidNext(); + System.out.print(">>xml gid: " + gid + "\r\n"); + } + } +} diff --git a/app/gid/gid_client/java/src/com/iker/gid/GidStatus.java b/app/gid/gid_client/java/src/com/iker/gid/GidStatus.java new file mode 100644 index 000000000..f695e3a0b --- /dev/null +++ b/app/gid/gid_client/java/src/com/iker/gid/GidStatus.java @@ -0,0 +1,49 @@ +package com.iker.gid; + +/** + * @author zsx + * 璇ョ被涓昏瀹氫箟浜咷ID鐨勯敊璇彿浠ュ強灏嗛敊璇彿杞负瀛楃涓叉弿杩颁俊鎭殑鍐呭 + */ +public final class GidStatus { + public static final int gidOk = 200; + public static final int gidErrInit = 400; + public static final int gidErrConn = 401; + public static final int gidErrIo = 402; + public static final int gidErrProto = 403; + public static final int gidErrServer = 404; + public static final int gidErrSid = 500; + public static final int gidErrOverride = 501; + public static final int gidErrSave = 502; + + /** + * 灏嗛敊璇彿杞负瀛楃涓叉弿杩颁俊鎭 + * @param gidStatus + * @return String + */ + public static String toString(int gidStatus) + { + switch (gidStatus) + { + case gidOk: + return "ok"; + case gidErrInit: + return "gid_client_init should called first"; + case gidErrConn: + return "connect server error"; + case gidErrIo: + return "readwrite from server error"; + case gidErrProto: + return "gid protocol error"; + case gidErrServer: + return "gid server internal error"; + case gidErrSid: + return "sid invalid"; + case gidErrOverride: + return "gid override"; + case gidErrSave: + return "gid save error"; + default: + return "unknown error number"; + } + } +} diff --git a/app/gid/gid_server/Makefile b/app/gid/gid_server/Makefile new file mode 100644 index 000000000..9ecbc10e2 --- /dev/null +++ b/app/gid/gid_server/Makefile @@ -0,0 +1,117 @@ +SHELL = /bin/sh +CC = g++ +CC = gcc +#CC = ${MY_ENV_CC} +AR = ar +ARFL = rv +#ARFL = cru +RANLIB = ranlib + +CFLAGS = -c -g -W -Wall -Wcast-qual -Wcast-align \ +-Waggregate-return \ +-Wno-long-long \ +-Wpointer-arith -Werror -Wshadow -O2 \ +-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO + +#CFLAGS = -c -g -W -Wall -Wcast-qual -Wcast-align \ +#-Waggregate-return -Wmissing-prototypes \ +#-Wpointer-arith -Werror -Wshadow -O2 \ +#-D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO +########################################################### +#Check system: +# Linux, SunOS, Solaris, BSD variants, AIX, HP-UX +SYSLIB = -lpthread -lcrypt -lz +CHECKSYSRES = @echo "Unknow system type!";exit 1 +UNIXNAME = $(shell uname -sm) +OSTYPE = $(shell uname -p) +RPATH = + +ifeq ($(CC),) + CC = gcc +endif + +#Path for Linux +ifeq ($(findstring Linux, $(UNIXNAME)), Linux) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DLINUX2 -D_REENTRANT -pedantic + + ifeq ($(findstring i686, $(OSTYPE)), i686) + RPATH = linux32 + FLAG_OS = LINUX32 + endif + ifeq ($(findstring x86_64, $(OSTYPE)), x86_64) + RPATH = linux64 + FLAG_OS = LINUX64 + endif +endif + +#Path for SunOS +ifeq ($(findstring SunOS, $(UNIXNAME)), SunOS) + ifeq ($(findstring 86, $(UNIXNAME)), 86) + SYSLIB += -lsocket -lnsl -lrt + endif + ifeq ($(findstring sun4u, $(UNIXNAME)), sun4u) + SYSLIB += -lsocket -lnsl -lrt + endif + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DSUNOS5 -D_REENTRANT -pedantic +endif + +#Path for HP-UX +ifeq ($(findstring HP-UX, $(UNIXNAME)), HP-UX) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DHP_UX -DHPUX11 + PLAT_NAME=hp-ux +endif + +#Find system type. +ifneq ($(SYSPATH),) + CHECKSYSRES = @echo "System is $(shell uname -sm)" +endif +########################################################### +BASE_PATH = ../../../build + +INC_COMPILE = -I./include -I../../../lib_acl/include \ + -I../../../lib_protocol/include +LIB_COMPILE = -L../../../lib_acl/lib -L../../../lib_protocol/lib -l_protocol -l_acl + +CFLAGS += $(INC_COMPILE) + +########################################################### +OUT_PATH = . +OBJ_PATH = $(OUT_PATH)/debug + +#Project's objs +SRC = $(wildcard src/*.c) $(wildcard unix/*.c) +OBJ = $(patsubst %.c, $(OBJ_PATH)/%.o, $(notdir $(SRC))) +########################################################### + +PROG = gid_server + +all: rm gid_server +.PHONY = gid_server clean +COMPILE = $(CC) $(CFLAGS) + +$(PROG): $(OBJ) + $(CC) $(OBJ) $(LIB_COMPILE) $(SYSLIB) -o $(PROG) +# cp $(OBJ_PATH)/$(PROG) $(BASE_PATH)/dist/master/libexec + @echo "" + @echo "All ok! Output:$(PROG)" + @echo "" + +$(OBJ_PATH)/%.o: src/%.c + $(COMPILE) $< -o $@ +$(OBJ_PATH)/%.o: unix/%.c + $(COMPILE) $< -o $@ + +rm: + rm -f $(PROG) +clean: + rm -f $(PROG) + rm -f $(OBJ) diff --git a/app/gid/gid_server/Makefile.test b/app/gid/gid_server/Makefile.test new file mode 100644 index 000000000..96e10834d --- /dev/null +++ b/app/gid/gid_server/Makefile.test @@ -0,0 +1,108 @@ +SHELL = /bin/sh +CC = g++ +CC = gcc +#CC = ${MY_ENV_CC} +AR = ar +ARFL = rv +#ARFL = cru +RANLIB = ranlib + +CFLAGS = -c -g -W -Wall -Wcast-qual -Wcast-align \ +-Waggregate-return -Wno-long-long \ +-Wpointer-arith -Werror -Wshadow -O2 \ +-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO + +#CFLAGS = -c -g -W -Wall -Wcast-qual -Wcast-align \ +#-Waggregate-return -Wmissing-prototypes \ +#-Wpointer-arith -Werror -Wshadow -O2 \ +#-D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO +########################################################### +#Check system: +# Linux, SunOS, Solaris, BSD variants, AIX, HP-UX +SYSLIB = -lpthread -lcrypt -lz +CHECKSYSRES = @echo "Unknow system type!";exit 1 +UNIXNAME = $(shell uname -sm) + +ifeq ($(CC),) + CC = gcc +endif + +#Path for Linux +ifeq ($(findstring Linux, $(UNIXNAME)), Linux) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DLINUX2 -D_REENTRANT -pedantic +endif + +#Path for SunOS +ifeq ($(findstring SunOS, $(UNIXNAME)), SunOS) + ifeq ($(findstring 86, $(UNIXNAME)), 86) + SYSLIB += -lsocket -lnsl -lrt + endif + ifeq ($(findstring sun4u, $(UNIXNAME)), sun4u) + SYSLIB += -lsocket -lnsl -lrt + endif + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DSUNOS5 -D_REENTRANT -pedantic +endif + +#Path for HP-UX +ifeq ($(findstring HP-UX, $(UNIXNAME)), HP-UX) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DHP_UX -DHPUX11 + PLAT_NAME=hp-ux +endif + +#Find system type. +ifneq ($(SYSPATH),) + CHECKSYSRES = @echo "System is $(shell uname -sm)" +endif +########################################################### +BASE_PATH = ../.. + +BASE_LIB_PATH = $(BASE_PATH)/lib/linux +BASE_INC_PATH = $(BASE_PATH)/include + +ACL_INC = $(BASE_PATH)/include/acl +P2P_INC = $(BASE_PATH)/include/p2p +P2P_CHAT_INC = $(BASE_PATH)/include/p2p_chat + +CFLAGS += $(INC_COMPILE) + +INC_COMPILE = -I$(P2P_CHAT_INC) -I$(P2P_INC) -I$(ACL_INC) -I$(BASE_INC_PATH) -I./include +LIB_COMPILE = -L$(BASE_LIB_PATH) -l_chat -l_acl + +########################################################### +OUT_PATH = . +OBJ_PATH = $(OUT_PATH)/debug + +#Project's objs +SRC = $(wildcard src/*.c) $(wildcard win32/*.c) +OBJ = $(patsubst %.c, $(OBJ_PATH)/%.o, $(notdir $(SRC))) +########################################################### + +PROG = regsvr_test + +.PHONY = all clean +COMPILE = $(CC) $(CFLAGS) + +$(PROG): $(OBJ) + $(CC) $(OBJ) $(LIB_COMPILE) $(SYSLIB) -o $(OBJ_PATH)/$(PROG) + @echo "" + @echo "All ok! Output:$(PROG)" + @echo "" + +$(OBJ_PATH)/%.o: src/%.c + $(COMPILE) $< -o $@ +$(OBJ_PATH)/%.o: win32/%.c + $(COMPILE) $< -o $@ + +clean: + rm -f $(OBJ_PATH)/$(PROG) + rm -f $(OBJ) + diff --git a/app/gid/gid_server/change.txtt b/app/gid/gid_server/change.txtt new file mode 100644 index 000000000..24fd6fdff --- /dev/null +++ b/app/gid/gid_server/change.txtt @@ -0,0 +1,2 @@ +1) 2013.7.17 +1.1) feature: 鏀寔鍚屾椂鐩戝惉澶氫釜绔彛锛屾瘡涓鍙e鐞嗕笉鍚岀殑鍗忚鏍煎紡 diff --git a/app/gid/gid_server/doc/test.txt b/app/gid/gid_server/doc/test.txt new file mode 100644 index 000000000..c3b4bf784 --- /dev/null +++ b/app/gid/gid_server/doc/test.txt @@ -0,0 +1,32 @@ +POST / HTTP/1.1 +Connection: keep-alive +Content-Length: 26 + +{cmd: "new_gid", seq: 1 } + + +POST / HTTP/1.1 +Content-Length: 26 + +{cmd: "new_gid", seq: 1 } + + +POST / HTTP/1.1 +Connection: keep-alive +Content-Length: 32 + +{cmd: "new_gid", seq: "label" } + + +POST / HTTP/1.1 +Content-Length: 32 + +{cmd: "new_gid", seq: "label" } + + +POST / HTTP/1.1 +Content-Length: 19 + +{cmd: "new_gid" } + +CMD^new_gid|LABEL^default diff --git a/app/gid/gid_server/gid_server.cf b/app/gid/gid_server/gid_server.cf new file mode 100644 index 000000000..af29f7939 --- /dev/null +++ b/app/gid/gid_server/gid_server.cf @@ -0,0 +1,106 @@ + +service server { +# 进程是否禁止运行 + master_disable = no +# 服务地址及端口号 +# master_service = 127.0.0.1:6010 + master_service = 127.0.0.1:7070, 127.0.0.1:7071, 127.0.0.1:7072, 127.0.0.1:7073 + +# 服务监听为域套接口 +# master_service = aio_echo.sock +# 服务类型 +# master_type = inet +# master_type = unix + master_type = sock + +# 当子进程异常退出时,如果该值非空,则将子进程异常退出的消息通知该服务 +# master_notify_addr = 127.0.0.1:5801 + +# 是否允许延迟接受客户端连接,如果为0则表示关闭该功能,如果大于0则表示打开此功能 +# 并且此值代表延迟接受连接的超时值,超过此值时如果客户端依然没有发来数据,则操作 +# 系统会在系统层直接关闭该连接 +# master_defer_accept = 0 +# 是否只允许私有访问, 如果为 y, 则域套接口创建在 /opt/analyse/var/log/private/ 目录下, +# 如果为 n, 则域套接口创建在 /opt/analyse/var/log/public/ 目录下, + master_private = n + master_unpriv = n +# 是否需要 chroot: n -- no, y -- yes + master_chroot = n +# 每隔多长时间触发一次,单位为秒(仅对 trigger 模式有效) + master_wakeup = - +# 最大进程数 + master_maxproc = 1 +# 进程程序名 + master_command = gid_server +# 进程日志记录文件 + master_log = {install_path}/var/gid_server.log +# 进程启动参数,只能为: -u [是否允许以某普通用户的身份运行] +# master_args = -u +# 传递给服务子进程的环境变量, 可以通过 getenv("SERVICE_ENV") 获得此值 +# master_env = mempool_limit:512000000 +# master_env = logme:FALSE, priority:E_LOG_INFO, action:E_LOG_PER_DAY, flush:sync_flush, imit_size:512,\ +# sync_action:E_LOG_SEM, sem_name:/tmp/ioctl_echo.sem + +# 每个进程实例处理连接数的最大次数,超过此值后进程实例主动退出 + ioctl_use_limit = 0 +# 每个进程实例的空闲超时时间,超过此值后进程实例主动退出 + ioctl_idle_limit = 0 +# 记录进程PID的位置(对于多进程实例来说没有意义) + ioctl_pid_dir = ./var +# 进程运行时所在的路径 +# ioctl_queue_dir = /home/guozhaohui/opt/analyse/var + ioctl_queue_dir = {install_path}/var +# 读写超时时间, 单位为秒 + ioctl_rw_timeout = 120 +# 读缓冲区的缓冲区大小 + ioctl_buf_size = 8192 +# 每次 accept 时的循环接收的最大次数 + ioctl_max_accept = 25 +# 在并发访问量非常低的情况下,如访问量在 10 次/秒 以下时,可以找开此值(即赋为1),以加速事件循环过程, +# 从而防止服务进程阻塞在 select 上的时间过长而影响访问速度 +# ioctl_enable_dog = 1 +# 进程运行时的用户身份 + ioctl_owner = root +# ioctl_owner = guozhaohui + +# 用 select 进行循环时的时间间隔 +# 单位为秒 + ioctl_delay_sec = 0 +# 单位为微秒 + ioctl_delay_usec = 500 + +# 采用事件循环的方式: select(default), poll, kernel(epoll/devpoll/kqueue) + ioctl_event_mode = select + +# 线程池的最大线程数 + ioctl_max_threads = 250 +# 线程的堆栈空间大小,单位为字节,0表示使用系统缺省值 + ioctl_stacksize = 0 +# 允许访问 udserver 的客户端IP地址范围 + ioctl_access_allow = 0.0.0.0:255.255.255.255 + + +## app_main.c 需要的参数项 +# 客户端连接的最大空闲时间阀值 + app_client_idle_limit = 120 + +############################################################################ +# 应用自己的配置选项 + +# 是否调试内存状态 +# debug_mem = 0 +# 存储的根目录 + gid_path = {install_path}/var/gid +# 是否立刻同步至磁盘 + sync_gid = 1 +# 步进值 + gid_step = 1 +# 是否循环读取请求命令 + loop_enable = 1 +# 缺省的服务协议 + proto_default = http +# 协议与端口的对照表 + proto_list = http|127.0.0.1:7070|127.0.0.1:7071, cmdline|127.0.0.1:7072|127.0.0.1:7073 +# 测试用 + test_user_id = 10001 +} diff --git a/app/gid/gid_server/include/cmdline_service.h b/app/gid/gid_server/include/cmdline_service.h new file mode 100644 index 000000000..3e885be10 --- /dev/null +++ b/app/gid/gid_server/include/cmdline_service.h @@ -0,0 +1,21 @@ +#ifndef __PROTO_CMD_INCLUDE_H__ +#define __PROTO_CMD_INCLUDE_H__ + +#include "lib_acl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * 命令行方式的协议处理方式 + * @param client {ACL_VSTREAM*} 客户端流 + * @return {int} 0:表示正常,1:表示正常且保持长连接,-1:表示出错 + */ +int cmdline_service(ACL_VSTREAM *client); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/app/gid/gid_server/include/gid_oper.h b/app/gid/gid_server/include/gid_oper.h new file mode 100644 index 000000000..f6081c953 --- /dev/null +++ b/app/gid/gid_server/include/gid_oper.h @@ -0,0 +1,51 @@ +#ifndef __GID_OPER_INCLUDE_H__ +#define __GID_OPER_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lib_acl.h" + +#define GID_OK 200 /* 正常 */ +#define GID_ERR_SID 500 /* 会话 ID 号不对 */ +#define GID_ERR_OVERRIDE 501 /* 达到最大分配值 */ +#define GID_ERR_SAVE 502 /* 存储至磁盘时出错 */ + +/** + * 根据错误号获得字符串描述 + * @param errnum {int} 错误号 + * @return {const char*} 错误描述 + */ +const char *gid_serror(int errnum); + +/** + * 获取下一个GID号 + * @param path {const char*} 文件存储路径 + * @param tag {const char*} ID标识号 + * @param step {unsigned int} 每次的步进值 + * @param errnum {int*} 若非空,则记录出错原因 + * @return {acl_int64}, 如果返回值 < 0,则表示分配失败, + * 出错原因参考 errnum 的返回值 + */ +acl_int64 gid_next(const char *path, const char *tag, + unsigned int step, int *errnum); + +/** + * 初始化,程序启动后应调用此函数初始化内部库 + * @param fh_limit {int} 缓存的文件句柄的最大个数 + * @param sync_gid {int} 每产生一个新的 gid 后是否同时同步至磁盘 + * @param debug_section {int} 调用用的标签值 + */ +void gid_init(int fh_limit, int sync_gid, int debug_section); + +/** + * 程序退出前必须调用此函数,以使内存中数据刷新至磁盘 + */ +void gid_finish(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/app/gid/gid_server/include/global.h b/app/gid/gid_server/include/global.h new file mode 100644 index 000000000..592aa9d97 --- /dev/null +++ b/app/gid/gid_server/include/global.h @@ -0,0 +1,26 @@ +#ifndef __GLOBAL_INCLUDE_H__ +#define __GLOBAL_INCLUDE_H__ + +/* 配置文件项 */ + +extern int var_cfg_debug_mem; +extern int var_cfg_loop_enable; +extern int var_cfg_sync_gid; +extern ACL_CONFIG_BOOL_TABLE service_conf_bool_tab[]; + +extern int var_cfg_debug_section; +extern int var_cfg_gid_step; +extern int var_cfg_gid_test; +extern int var_cfg_fh_limit; +extern int var_cfg_io_timeout; +extern ACL_CONFIG_INT_TABLE service_conf_int_tab[]; + +extern char *var_cfg_gid_path; +extern char *var_cfg_proto_list; +extern ACL_CONFIG_STR_TABLE service_conf_str_tab[]; + +/* 服务器之间传输的命令字定义 */ +#define CMD_NEW_GID "new_gid" +#define CMD_TEST_GID "test_gid" + +#endif diff --git a/app/gid/gid_server/include/http_service.h b/app/gid/gid_server/include/http_service.h new file mode 100644 index 000000000..93bf11173 --- /dev/null +++ b/app/gid/gid_server/include/http_service.h @@ -0,0 +1,59 @@ +#ifndef __HTTP_SERVICE_INCLUDE_H__ +#define __HTTP_SERVICE_INCLUDE_H__ + +#include "lib_acl.h" +#include "lib_protocol.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* in http_service.c */ + +/** + * HTTP 协议方式处理方法 + * @param client {ACL_VSTREAM*} 客户端流 + * @return {int} 0:表示正常,1:表示正常且保持长连接,-1:表示出错 + */ +int http_service(ACL_VSTREAM *client); + +/** + * 服务端返回 HTTP 响应给客户端 + * @param client {ACL_VSTREAM*} 客户端流 + * @param status {int} HTTP 响应状态码,1xx, 2xx, 3xx, 4xx, 5xx + * @param keep_alive {int} 是否与客户端保持长连接 + * @param body {const char*} 数据体内容 + * @param len {int} 数据体长度 + */ +int http_server_send_respond(ACL_VSTREAM* client, int status, + int keep_alive, char* body, int len); + +/* in http_json.c */ + +/** + * 请求数据的格式为 JSON 格式的处理 + * @param client {ACL_VSTREAM*} + * @param hdr_req {HTTP_HDR_REQ*} HTTP 请求协议头对象 + * @param json {ACL_JSON*} json 解析器对象 + * @return {int} 0:表示正常,1:表示正常且保持长连接,-1:表示出错 + */ +int http_json_service(ACL_VSTREAM *client, + HTTP_HDR_REQ *hdr_req, ACL_JSON *json); + +/* in http_xml.c */ + +/** + * 请求数据的格式为 XML 格式的处理 + * @param client {ACL_VSTREAM*} + * @param hdr_req {HTTP_HDR_REQ*} HTTP 请求协议头对象 + * @param xml {ACL_XML*} xml 解析器对象 + * @return {int} 0:表示正常,1:表示正常且保持长连接,-1:表示出错 + */ +int http_xml_service(ACL_VSTREAM *client, + HTTP_HDR_REQ *hdr_req, ACL_XML *xml); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/app/gid/gid_server/include/service_main.h b/app/gid/gid_server/include/service_main.h new file mode 100644 index 000000000..7faa18236 --- /dev/null +++ b/app/gid/gid_server/include/service_main.h @@ -0,0 +1,29 @@ + +#ifndef __SERVICE_MAIN_INCLUDE_H__ +#define __SERVICE_MAIN_INCLUDE_H__ + +#include "lib_acl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * 初始化函数,服务器模板框架启动后仅调用该函数一次 + * @param ctx {void*} 用户自定义类型指针 + */ +extern void service_init(void *ctx); +extern void service_exit(void *ctx); + +/** + * 协议处理函数入口 + * @param stream {ACL_VSTREAM*} 客户端数据连接流 + * @param ctx {void*} 用户自定义类型指针 + */ +extern int service_main(ACL_VSTREAM *stream, void *ctx); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/app/gid/gid_server/src/cmdline_service.c b/app/gid/gid_server/src/cmdline_service.c new file mode 100644 index 000000000..72f057997 --- /dev/null +++ b/app/gid/gid_server/src/cmdline_service.c @@ -0,0 +1,128 @@ +#include "lib_acl.h" +#include +#include "gid_oper.h" +#include "global.h" +#include "cmdline_service.h" + +static int send_respond_gid(ACL_VSTREAM *stream, + const char *tag, acl_int64 gid) +{ +#if 0 + if (acl_vstream_fprintf(stream, "STATUS^OK|GID^%lld|TAG^%s\r\n", + gid, tag) == ACL_VSTREAM_EOF) +#else + char buf[1024]; + + snprintf(buf, sizeof(buf), "STATUS^OK|GID^%lld|TAG^%s\r\n", gid, tag); + if (acl_vstream_writen(stream, buf, strlen(buf)) == ACL_VSTREAM_EOF) +#endif + { + acl_msg_info("%s(%d): respond to client error", + __FILE__, __LINE__); + return (-1); + } + else + return (1); /* 返回1表示保持长连接 */ +} + +static int send_respond_error(ACL_VSTREAM *stream, + const char *tag, const char *msg) +{ + if (acl_vstream_fprintf(stream, "STATUS^ERR|TAG^%s|MSG^%s\r\n", + tag, msg) == ACL_VSTREAM_EOF) + { + acl_msg_info("%s(%d): respond to client error", + __FILE__, __LINE__); + return (-1); + } + else + return (0); +} + +static int proto_new_gid(ACL_VSTREAM *stream, const char *tag) +{ + acl_int64 gid; + int errnum = 0; + + gid = gid_next(var_cfg_gid_path, tag, var_cfg_gid_step, &errnum); + if (gid >= 0) + return (send_respond_gid(stream, tag, gid)); + else + return (send_respond_error(stream, tag, gid_serror(errnum))); +} + +static int proto_test_gid(ACL_VSTREAM *stream, + const char *tag, acl_int64 test_id) +{ + return (send_respond_gid(stream, tag, test_id)); +} + +static int proto_get_test_gid(ACL_VSTREAM *stream, const char *tag) +{ + return (proto_test_gid(stream, tag, (acl_int64) var_cfg_gid_test)); +} + +/*--------------------------------------------------------------------------*/ + +typedef struct PROTO_CMDLINE { + const char *cmd; /* 命令字 */ + int (*handle)(ACL_VSTREAM *, const char*); /* 协议处理函数句柄 */ +} PROTO_CMDLINE; + +/* 协议命令处理函数映射表 */ +static PROTO_CMDLINE __proto_cmdline_tab[] = { + { CMD_NEW_GID, proto_new_gid }, + { CMD_TEST_GID, proto_get_test_gid }, + { NULL, NULL }, +}; + +/* 解析数据头 */ + +/* 协议格式: + * 请求格式: CMD^xxx|tag^xxx:sid\r\n + * 响应格式: STATUS^[OK|ERR]|[GID^xxx|INFO^xxx]|tag^%s\r\n + */ +int cmdline_service(ACL_VSTREAM *client) +{ + const char *myname = "parse_req_hdr"; + const char *cmd = NULL, *tag = "default"; + char buf[1024]; + ACL_ARGV *argv; + int i, ret; + ACL_ITER iter; + + /* 先读取数据头 */ + ret = acl_vstream_gets_nonl(client, buf, sizeof(buf) - 1); + if (ret == ACL_VSTREAM_EOF) + return (-1); + + argv = acl_argv_split(buf, "|"); + acl_foreach(iter, argv) { + const char *ptr = (const char*) iter.data; + if (strncasecmp(ptr, "CMD^", sizeof("CMD^") - 1) == 0) + cmd = ptr + sizeof("CMD^") - 1; + else if (strncasecmp(ptr, "TAG^", sizeof("TAG^") - 1) == 0) + tag = ptr + sizeof("TAG^") - 1; + } + + if (cmd == NULL || *tag == 0) { + acl_msg_error("%s(%d): invalid request(%s)", + myname, __LINE__, buf); + acl_argv_free(argv); + return (-1); + } + + for (i = 0; __proto_cmdline_tab[i].cmd != NULL; i++) { + if (strcasecmp(cmd, __proto_cmdline_tab[i].cmd) == 0) { + ret = __proto_cmdline_tab[i].handle(client, tag); + acl_argv_free(argv); + return (ret); + } + } + + acl_msg_error("%s(%d): invalid request cmd(%s), no cmd found.", + myname, __LINE__, cmd); + + acl_argv_free(argv); + return (-1); +} diff --git a/app/gid/gid_server/src/gid_oper.c b/app/gid/gid_server/src/gid_oper.c new file mode 100644 index 000000000..61d352636 --- /dev/null +++ b/app/gid/gid_server/src/gid_oper.c @@ -0,0 +1,317 @@ +#include "lib_acl.h" +#include +#include +#include + +#include "gid_oper.h" + +typedef struct GID_STORE { + ACL_FHANDLE fh; /* 文件句柄 */ + ACL_VSTREAM *logger; /* 日志句柄 */ + char tag[64]; /* 文件标识号 */ + char sid[64]; /* 会话ID号,相当于密码 */ + unsigned int step; /* 步进值 */ + acl_int64 cur_gid; /* 当前的ID值 */ + acl_int64 min_gid; /* 最小的ID值 */ + acl_int64 max_gid; /* 最大的ID值 */ +} GID_STORE; + +typedef struct { + char tag[64]; /* 文件标识号 */ + char sid[64]; /* 会话ID号,相当于密码 */ + unsigned int step; /* 步进值 */ + acl_int64 cur_gid; /* 当前的ID值 */ + acl_int64 min_gid; /* 最小的ID值 */ + acl_int64 max_gid; /* 最大的ID值 */ +} GID_STORE_CTX; + +static int __sync_gid = 1; + +/* 同步内存数据至磁盘 */ + +static int gid_store_sync(GID_STORE *store) +{ + char buf[1024]; + + /* 需要先将文件内容清空 */ +#if 0 + if (acl_file_ftruncate(store->fh.fp, 0) < 0) { + acl_msg_error("%s(%d), %s: ftruncate %s error(%s)", + __FILE__, __LINE__, __FUNCTION__, + ACL_VSTREAM_PATH(store->fh.fp), acl_last_serror()); + return (-1); + } +#endif + if (acl_vstream_fseek(store->fh.fp, SEEK_SET, 0) < 0) { + acl_msg_error("%s(%d), %s: fseek %s error(%s)", + __FILE__, __LINE__, __FUNCTION__, + ACL_VSTREAM_PATH(store->fh.fp), acl_last_serror()); + } + + snprintf(buf, sizeof(buf), "%s:%s %d %lld %lld %lld\r\n", + store->tag, store->sid, store->step, store->cur_gid, + store->min_gid, store->max_gid); + + /* 初始化文件内容: tag:sid step cur_gid min_gid max_gid\r\n */ + if (acl_vstream_writen(store->fh.fp, + buf, strlen(buf)) == ACL_VSTREAM_EOF) + { + acl_msg_error("%s(%d), %s: write to %s error(%s)", + __FILE__, __LINE__, __FUNCTION__, + ACL_VSTREAM_PATH(store->fh.fp), acl_last_serror()); + return (-1); + } + + return (0); +} + +/* 文件打开时的回调函数,有可能是打开了缓存句柄对象 */ + +static int gid_store_on_open(ACL_FHANDLE *fh, void *ctx) +{ + GID_STORE *store = (GID_STORE*) fh; + GID_STORE_CTX *sc = (GID_STORE_CTX*) ctx; + ACL_ARGV *argv; + char buf[512], *ptr; + int ret; + + /* 检查是否有问题 */ + if (fh->size != sizeof(GID_STORE)) + acl_msg_fatal("%s(%d), %s: size(%d) != GID_STORE's size(%d)", + __FILE__, __LINE__, __FUNCTION__, + (int) fh->size, (int) sizeof(GID_STORE)); + + /* 如果是新文件则初始化 */ + if (fh->fsize == 0) { + ACL_SAFE_STRNCPY(store->tag, sc->tag, sizeof(store->tag)); + ACL_SAFE_STRNCPY(store->sid, sc->sid, sizeof(store->sid)); + store->step = sc->step; + store->cur_gid = sc->cur_gid; + store->min_gid = sc->min_gid; + store->max_gid = sc->max_gid; + + return (gid_store_sync(store)); + } + + /* 数据格式:tag:sid step cur_gid min_gid max_gid\r\n */ + + /* 从文件中获得数据 */ + ret = acl_vstream_gets_nonl(fh->fp, buf, sizeof(buf)); + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d), %s: gets from %s error(%s)", + __FILE__, __LINE__, __FUNCTION__, + ACL_VSTREAM_PATH(fh->fp), acl_last_serror()); + return (-1); + } + + /* 拆分字符串 */ + argv = acl_argv_split(buf, ",\t "); + if (argv->argc < 5) { + acl_msg_error("%s(%d), %s: invalid line(%s) from %s", + __FILE__, __LINE__, __FUNCTION__, + buf, ACL_VSTREAM_PATH(fh->fp)); + acl_argv_free(argv); + return (-1); + } + + ACL_SAFE_STRNCPY(store->tag, argv->argv[0], sizeof(store->tag)); + ptr = strchr(store->tag, ':'); + if (ptr) { + *ptr++ = 0; + ACL_SAFE_STRNCPY(store->sid, ptr, sizeof(store->sid)); + } + store->step = atoi(argv->argv[1]); + + /* 如果存储的步进值与参数中的步进值不一致,则优先采用参数步进值 */ + if (store->step != sc->step) { + acl_msg_warn("%s(%d), %s: change step from %d to %d for %s", + __FILE__, __LINE__, __FUNCTION__, + store->step, sc->step, ACL_VSTREAM_PATH(fh->fp)); + store->step = sc->step; + } + store->cur_gid = atoll(argv->argv[2]); + store->min_gid = atoll(argv->argv[3]); + store->max_gid = atoll(argv->argv[4]); + + acl_argv_free(argv); + return (0); +} + +/* 文件句柄真正关闭时的回调函数 */ + +static void gid_store_on_close(ACL_FHANDLE *fh acl_unused) +{ + GID_STORE *store = (GID_STORE*) fh; + + /* 当设置了非实时同步标记时才需要在文件句柄关闭时同步磁盘 */ + if (__sync_gid == 0 && gid_store_sync(store) < 0) + acl_msg_fatal("%s(%d), %s: save %s error(%s)", + __FILE__, __LINE__, __FUNCTION__, + ACL_VSTREAM_PATH(store->fh.fp), acl_last_serror()); +} + +/* 打开文件,如果文件不存在则创建新的文件,如果文件句柄已经存在则直接返回 */ + +static GID_STORE *gid_store_open(const char *path, const char *tag, + const char *sid, unsigned int step) +{ + char filepath[1024]; + unsigned int oflags = ACL_FHANDLE_O_NOATIME + | ACL_FHANDLE_O_MLOCK + | ACL_FHANDLE_O_EXCL; + GID_STORE *store; + GID_STORE_CTX ctx; + + ACL_SAFE_STRNCPY(ctx.tag, tag, sizeof(ctx.tag)); + ACL_SAFE_STRNCPY(ctx.sid, sid, sizeof(ctx.sid)); + ctx.step = step; + ctx.cur_gid = 0; + ctx.min_gid = 1; + ctx.max_gid = 0x7FFFFFFFFFFFFFFFllu; + + snprintf(filepath, sizeof(filepath), "%s/%s", path, tag); + store = (GID_STORE*) acl_fhandle_open(sizeof(GID_STORE), oflags, + filepath, gid_store_on_open, &ctx, gid_store_on_close); + if (store == NULL) + acl_msg_fatal("%s(%d), %s: open %s error(%s)", + __FILE__, __LINE__, __FUNCTION__, + filepath, acl_last_serror()); + return (store); +} + +/* 获得当前本地时间 */ + +static void logtime_fmt(char *buf, size_t size) +{ + time_t now; + struct tm local_time; + + (void) time (&now); + (void) localtime_r(&now, &local_time); + strftime(buf, size, "%Y/%m/%d %H:%M:%S", &local_time); +} + +/* 记录日志 */ + +static void gid_logger(GID_STORE *store) +{ + char buf[128]; + + if (store->logger == NULL) + return; + + logtime_fmt(buf, sizeof(buf)); + if (acl_vstream_fprintf(store->logger, "%s|%s %lld\r\n", + buf, store->tag, store->cur_gid) == ACL_VSTREAM_EOF) + { + acl_msg_error("%s(%d), %s: fprintf to %s error(%s)", + __FILE__, __LINE__, __FUNCTION__, + ACL_VSTREAM_PATH(store->logger), acl_last_serror()); + store->logger = NULL; + } +} + +acl_int64 gid_next(const char *path, const char *tag_in, + unsigned int step, int *errnum) +{ + acl_int64 gid; + char tag[128], *sid; + GID_STORE *store; + + /* 需要从 tag 串中分离出 sid 串 */ + ACL_SAFE_STRNCPY(tag, tag_in, sizeof(tag)); + sid = strchr(tag, ':'); + if (sid) + *sid++ = 0; + else + sid = ""; + store = gid_store_open(path, tag, sid, step); + + if (store->sid[0] != 0) { + if (sid == NULL || strcmp(sid, store->sid) != 0) { + acl_msg_error("%s(%d), %s: input sid(%s) invalid", + __FILE__, __LINE__, __FUNCTION__, + sid && *sid ? sid : "null"); + if (errnum) + *errnum = GID_ERR_SID; + + /* 关闭文件句柄,延迟 60 秒后关闭 */ + acl_fhandle_close(&store->fh, 60); + return (-1); + } + } + + /* 如果已经达到最大值,则崩溃了! */ + if (store->max_gid - (unsigned int) store->step <= store->cur_gid) { + acl_msg_error("%s(%d), %s: %s Override!!, max_gid: %lld," + " step: %d, cur_gid: %lld", __FILE__, __LINE__, + __FUNCTION__, ACL_VSTREAM_PATH(store->fh.fp), + store->max_gid, store->step, store->cur_gid); + + if (errnum) + *errnum = GID_ERR_OVERRIDE; + /* 关闭文件句柄,延迟 60 秒后关闭 */ + acl_fhandle_close(&store->fh, 60); + return (-1); + } + + store->cur_gid += store->step; + gid = store->cur_gid; + + if (__sync_gid && gid_store_sync(store) < 0) { + if (errnum) + *errnum = GID_ERR_SAVE; + acl_msg_error("%s(%d), %s: save %s error(%s)", + __FILE__, __LINE__, __FUNCTION__, + ACL_VSTREAM_PATH(store->fh.fp), + acl_last_serror()); + + /* 关闭文件句柄,延迟 60 秒后关闭 */ + acl_fhandle_close(&store->fh, 60); + return (-1); + } + + /* 记日志 */ + if (store->logger) + gid_logger(store); + + /* 关闭文件句柄,延迟 60 秒后关闭 */ + acl_fhandle_close(&store->fh, 60); + + if (errnum) + *errnum = GID_OK; + return (gid); +} + +const char *gid_serror(int errnum) +{ + static const struct { + int err; + const char *str; + } errors[] = { + { GID_OK, "ok" }, + { GID_ERR_SID, "sid invalid" }, + { GID_ERR_OVERRIDE, "gid override" }, + { GID_ERR_SAVE, "gid save error" }, + { 0, 0 } + }; + static const char *unknown = "unkown error"; + int i; + + for (i = 0; errors[i].str != NULL; i++) { + if (errnum == errors[i].err) + return (errors[i].str); + } + return (unknown); +} + +void gid_init(int fh_limit, int sync_gid, int debug_section) +{ + __sync_gid = sync_gid; + acl_fhandle_init(fh_limit, debug_section, ACL_FHANDLE_F_LOCK); +} + +void gid_finish() +{ + acl_fhandle_end(); +} diff --git a/app/gid/gid_server/src/http_json.c b/app/gid/gid_server/src/http_json.c new file mode 100644 index 000000000..1df396246 --- /dev/null +++ b/app/gid/gid_server/src/http_json.c @@ -0,0 +1,121 @@ +#include "lib_acl.h" +#include "lib_protocol.h" +#include "gid_oper.h" +#include "global.h" +#include "http_service.h" + +static int json_new_gid(ACL_VSTREAM *client, int keep_alive, ACL_JSON *json) +{ + acl_int64 gid; + char buf[256], tag[64]; + int errnum; + ACL_ARRAY *a; + +#define STR acl_vstring_str + + ACL_SAFE_STRNCPY(tag, "default:", sizeof(tag)); + a = acl_json_getElementsByTagName(json, "tag"); + if (a != NULL) { + ACL_ITER iter; + acl_foreach(iter, a) { + ACL_JSON_NODE *node = (ACL_JSON_NODE*) iter.data; + if (ACL_VSTRING_LEN(node->text) == 0) + continue; + ACL_SAFE_STRNCPY(tag, STR(node->text), sizeof(tag)); + break; + } + acl_json_free_array(a); + } + + errnum = 0; + gid = gid_next(var_cfg_gid_path, tag, var_cfg_gid_step, &errnum); + if (gid >= 0) + snprintf(buf, sizeof(buf), + "{ status: 'ok', gid: '%lld', tag: '%s' }\r\n", + gid, tag); + else + snprintf(buf, sizeof(buf), "{ status: 'error'," + " gid: '%lld', tag: '%s', err: '%d', msg: '%s' }\r\n", + gid, tag, errnum, gid_serror(errnum)); + + return (http_server_send_respond(client, 200, keep_alive, + buf, (int) strlen(buf))); +} + +/*--------------------------------------------------------------------------*/ + +typedef struct PROTO_JSON { + /* 命令字 */ + const char *cmd; + + /* 协议处理函数句柄 */ + int (*handle)(ACL_VSTREAM *client, int keep_alive, ACL_JSON*); +} PROTO_JSON; + +/* 协议命令处理函数映射表 */ +static PROTO_JSON __proto_json_tab[] = { + { CMD_NEW_GID, json_new_gid }, + { NULL, NULL }, +}; + +/* 处理 json 数据格式的请求 */ + +int http_json_service(ACL_VSTREAM *client, + HTTP_HDR_REQ *hdr_req, ACL_JSON *json) +{ + ACL_ARRAY *a; + ACL_ITER iter; + char cmd[128]; + int ret, i, keep_alive = 0; + + /* json 数据格式要求: { cmd: xxx, tag: xxx:sid } */ + + /* 获得 cmd 命令字 */ + + a = acl_json_getElementsByTagName(json, "cmd"); + if (a == NULL) { + acl_msg_error("%s(%d), %s: json error", + __FILE__, __LINE__, __FUNCTION__); + return (-1); + } + + /* 从 JSON 对象获得命令字 */ + cmd[0] = 0; + acl_foreach(iter, a) { + ACL_JSON_NODE *node = (ACL_JSON_NODE*) iter.data; + if (ACL_VSTRING_LEN(node->text) == 0) + continue; + ACL_SAFE_STRNCPY(cmd, acl_vstring_str(node->text), sizeof(cmd)); + break; + } + acl_json_free_array(a); + + if (cmd[0] == 0) { + acl_msg_error("%s(%d), %s: no cmd", + __FILE__, __LINE__, __FUNCTION__); + return (-1); + } + + /* 客户端是否要求保持长连接 */ + keep_alive = hdr_req->hdr.keep_alive; + + /* 查询对应命令的处理函数对象 */ + ret = -1; + for (i = 0; __proto_json_tab[i].cmd != NULL; i++) { + if (strcasecmp(cmd, __proto_json_tab[i].cmd) == 0) { + ret = __proto_json_tab[i].handle( + client, keep_alive, json); + break; + } + } + if (__proto_json_tab[i].cmd == NULL) + acl_msg_error("%s(%d), %s: cmd(%s) invalid", + __FILE__, __LINE__, __FUNCTION__, cmd); + + if (ret < 0) + return (-1); /* 出错 */ + else if (keep_alive) + return (1); /* 正常且需要保持长连接 */ + else + return (0); /* 正常便是短连接 */ +} diff --git a/app/gid/gid_server/src/http_service.c b/app/gid/gid_server/src/http_service.c new file mode 100644 index 000000000..504cff429 --- /dev/null +++ b/app/gid/gid_server/src/http_service.c @@ -0,0 +1,131 @@ +#include "lib_acl.h" +#include "lib_protocol.h" + +#include "global.h" +#include "http_service.h" + +/* 将数据返回给 HTTP 客户端 */ + +int http_server_send_respond(ACL_VSTREAM* client, int status, + int keep_alive, char* body, int len) +{ + int ret; + struct iovec vector[2]; /* 数据数组 */ + ACL_VSTRING* buf = acl_vstring_alloc(256); + HTTP_HDR_RES* hdr_res = http_hdr_res_static(status); + + /* 在请求头中设置请求体的数据长度 */ + http_hdr_put_int(&hdr_res->hdr, "Content-Length", len); + /* 设置长连接选项 */ + http_hdr_put_str(&hdr_res->hdr, "Connection", + keep_alive ? "keep-alive" : "close"); + + /* 构建 HTTP 响应头数据 */ + http_hdr_build(&hdr_res->hdr, buf); + + /* 设置 HTTP 头 */ + vector[0].iov_base = acl_vstring_str(buf); + vector[0].iov_len = ACL_VSTRING_LEN(buf); + /* 设置 HTTP 体 */ + vector[1].iov_base = body; + vector[1].iov_len = len; + + /* 发送响应头及响应体 */ + ret = acl_vstream_writevn(client, vector, 2); + /* 释放 HTTP 响应头对象 */ + http_hdr_res_free(hdr_res); + /* 释放缓冲区 */ + acl_vstring_free(buf); + + if (ret == ACL_VSTREAM_EOF) + return -1; + + /* 发送HTTP响应成功 */ + return 0; +} + +/* HTTP 协议处理过程入口 */ + +int http_service(ACL_VSTREAM *client) +{ + HTTP_HDR_REQ *hdr_req = http_hdr_req_new(); + HTTP_REQ *req; + char buf[4096]; + int ret, json_fmt; + const char *ptr; + + /* 读取HTTP请求头 */ + ret = http_hdr_req_get_sync(hdr_req, client, var_cfg_io_timeout); + if (ret < 0) { + http_hdr_req_free(hdr_req); + return (-1); + } + + /* 分析HTTP请求头 */ + if (http_hdr_req_parse(hdr_req) < 0) { + http_hdr_req_free(hdr_req); + acl_msg_error("%s(%d), %s: http request header invalid", + __FILE__, __LINE__, __FUNCTION__); + return (-1); + } + + /* 必须保证数据体长度 > 0 */ + if (hdr_req->hdr.content_length <= 0) { + http_hdr_req_free(hdr_req); + acl_msg_error("%s(%d), %s: http request header invalid", + __FILE__, __LINE__, __FUNCTION__); + return (-1); + } + + /* 从 HTTP 请求头中获取请求体中的数据格式:XML 或 JSON 格式 */ + ptr = http_hdr_entry_value(&hdr_req->hdr, "x-gid-format"); + if (ptr != NULL && strcasecmp(ptr, "xml") == 0) + json_fmt = 0; + else + json_fmt = 1; + + req = http_req_new(hdr_req); /* 创建HTTP请求对象 */ + + if (json_fmt) { + ACL_JSON *json = acl_json_alloc(); /* 创建JSON解析器对象 */ + + /* 不断从客户端连接中读取数据,并放入JSON解析器中进行解析 */ + while (1) { + ret = http_req_body_get_sync(req, client, + buf, sizeof(buf) - 1); + if (ret < 0) { + /* 说明没有读到所要求的数据长度,表明出错 */ + http_req_free(req); + acl_json_free(json); + return (-1); + } else if (ret == 0) /* 表明已经读完了所有的数据 */ + break; + buf[ret] = 0; + acl_json_update(json, buf); + } + + ret = http_json_service(client, hdr_req, json); + acl_json_free(json); + } else { + ACL_XML *xml = acl_xml_alloc(); /* 创建XML解析器对象 */ + + while (1) { + ret = http_req_body_get_sync(req, client, + buf, sizeof(buf) - 1); + if (ret < 0) { + http_req_free(req); + acl_xml_free(xml); + return (-1); + } else if (ret == 0) + break; + buf[ret] = 0; + acl_xml_update(xml, buf); + } + + ret = http_xml_service(client, hdr_req, xml); + acl_xml_free(xml); + } + + http_req_free(req); + return (ret); +} diff --git a/app/gid/gid_server/src/http_xml.c b/app/gid/gid_server/src/http_xml.c new file mode 100644 index 000000000..c449581ce --- /dev/null +++ b/app/gid/gid_server/src/http_xml.c @@ -0,0 +1,128 @@ +#include "lib_acl.h" +#include "lib_protocol.h" + +#include "gid_oper.h" +#include "global.h" +#include "http_service.h" + +static int xml_new_gid(ACL_VSTREAM *client, int keep_alive, ACL_XML_NODE *node) +{ + acl_int64 gid; + char buf[256], tag[64]; + const char *ptr; + int errnum = 0; + +#define STR acl_vstring_str + + ACL_SAFE_STRNCPY(tag, "default:", sizeof(tag)); + ptr = acl_xml_getElementAttrVal(node, "tag"); + if (ptr && *ptr) { + ACL_SAFE_STRNCPY(tag, ptr, sizeof(tag)); + } + + gid = gid_next(var_cfg_gid_path, tag, var_cfg_gid_step, &errnum); + if (gid >= 0) + snprintf(buf, sizeof(buf), + "\r\n", gid, tag); + else + snprintf(buf, sizeof(buf), + "\r\n", + gid, tag, errnum, gid_serror(errnum)); + + return (http_server_send_respond(client, 200, keep_alive, + buf, (int) strlen(buf))); +} + +/*--------------------------------------------------------------------------*/ + +typedef struct PROTO_XML { + /* 命令字 */ + const char *cmd; + + /* 协议处理函数句柄 */ + int (*handle)(ACL_VSTREAM *client, int keep_alive, ACL_XML_NODE*); +} PROTO_XML; + +/* 协议命令处理函数映射表 */ +static PROTO_XML __proto_xml_tab[] = { + { CMD_NEW_GID, xml_new_gid }, + { NULL, NULL }, +}; + +/* 处理 xml 数据格式的请求 */ + +int http_xml_service(ACL_VSTREAM *client, + HTTP_HDR_REQ *hdr_req, ACL_XML *xml) +{ + ACL_ARRAY *a; + ACL_ITER iter; + char cmd[128]; + const char *ptr; + ACL_XML_NODE *node; + int ret, i, keep_alive = 0; + + /* xml 数据格式要求: */ + + /* 获得 cmd 命令字 */ + + a = acl_xml_getElementsByTagName(xml, "request"); + if (a == NULL) { + acl_msg_error("%s(%d), %s: xml error", + __FILE__, __LINE__, __FUNCTION__); + return (-1); + } + + /* 找到第一个结点即可 */ + + node = NULL; + acl_foreach(iter, a) { + node = (ACL_XML_NODE*) iter.data; + break; + } + + /* 从 xml 对象获得命令字 */ + + ptr = acl_xml_getElementAttrVal(node, "cmd"); + if (ptr == NULL || *ptr == 0) { + acl_msg_error("%s(%d), %s: no cmd attr", + __FILE__, __LINE__, __FUNCTION__); + acl_xml_free_array(a); + return (-1); + } + + ACL_SAFE_STRNCPY(cmd, ptr, sizeof(cmd)); + if (cmd[0] == 0) { + acl_xml_free_array(a); + acl_msg_error("%s(%d), %s: no cmd", + __FILE__, __LINE__, __FUNCTION__); + return (-1); + } + + /* 客户端是否要求保持长连接 */ + keep_alive = hdr_req->hdr.keep_alive; + + /* 查询对应命令的处理函数对象 */ + ret = -1; + for (i = 0; __proto_xml_tab[i].cmd != NULL; i++) { + if (strcasecmp(cmd, __proto_xml_tab[i].cmd) == 0) { + ret = __proto_xml_tab[i].handle( + client, keep_alive, node); + break; + } + } + + /* 必须是在不用 node 时才可以释放该数组对象 */ + acl_xml_free_array(a); + + if (__proto_xml_tab[i].cmd == NULL) + acl_msg_error("%s(%d), %s: cmd(%s) invalid", + __FILE__, __LINE__, __FUNCTION__, cmd); + + if (ret < 0) + return (-1); /* 出错 */ + else if (keep_alive) + return (1); /* 正常且需要保持长连接 */ + else + return (0); /* 正常便是短连接 */ +} diff --git a/app/gid/gid_server/src/service_main.c b/app/gid/gid_server/src/service_main.c new file mode 100644 index 000000000..0fe3faf85 --- /dev/null +++ b/app/gid/gid_server/src/service_main.c @@ -0,0 +1,173 @@ +#include "lib_acl.h" +#include "lib_protocol.h" + +#include "global.h" +#include "gid_oper.h" +#include "cmdline_service.h" +#include "http_service.h" +#include "service_main.h" + +/* 配置文件项 */ + +/* TODO: you can add configure items here */ + +int var_cfg_debug_mem; +int var_cfg_loop_enable; +int var_cfg_sync_gid; + +ACL_CONFIG_BOOL_TABLE service_conf_bool_tab[] = { + /* TODO: you can add configure variables of (bool) type here */ + { "debug_mem", 0, &var_cfg_debug_mem }, + { "loop_enable", 0, &var_cfg_loop_enable }, + { "sync_gid", 1, &var_cfg_sync_gid }, + { 0, 0, 0 }, +}; + +int var_cfg_debug_section; +int var_cfg_gid_step; +int var_cfg_gid_test; +int var_cfg_fh_limit; +int var_cfg_io_timeout; + +ACL_CONFIG_INT_TABLE service_conf_int_tab[] = { + /* TODO: you can add configure variables of int type here */ + { "debug_section", 120, &var_cfg_fh_limit, 0, 0 }, + { "gid_step", 1, &var_cfg_gid_step, 0, 0 }, + { "gid_test", 50000, &var_cfg_gid_test, 0, 0 }, + { "fh_limit", 100, &var_cfg_fh_limit, 0, 0 }, + { "io_timeout", 30, &var_cfg_io_timeout, 0, 0 }, + { 0, 0, 0, 0, 0 }, +}; + +char *var_cfg_gid_path; +char *var_cfg_proto_list; +char *var_cfg_proto_default; + +ACL_CONFIG_STR_TABLE service_conf_str_tab[] = { + /* TODO: you can add configure variables of (char *) type here */ + { "gid_path", "./var", &var_cfg_gid_path }, + { "proto_list", "http|127.0.0.1:7070|127.0.0.1:7071, cmdline|127.0.0.1:7072|127.0.0.1:7073", &var_cfg_proto_list }, + { "proto_default", "http", &var_cfg_proto_default }, + { 0, 0, 0 }, +}; + +typedef struct PROTO { + char name[32]; + char addr[256]; + size_t len; + int (*service)(ACL_VSTREAM*); +} PROTO; + +static ACL_ARRAY *__proto_map = NULL; +static int (*__default_service)(ACL_VSTREAM*) = NULL; + +static void proto_add(const char *data) +{ + int (*service)(ACL_VSTREAM*) = NULL; + ACL_ARGV *tokens = acl_argv_split(data, "|"); + PROTO *proto; + int i; + + if (tokens->argc < 2) { + acl_msg_error("invalid proto: %s", data); + acl_argv_free(tokens); + return; + } + + if (strcasecmp(tokens->argv[0], "cmdline") == 0) + service = cmdline_service; + else if (strcasecmp(tokens->argv[0], "http") == 0) + service = http_service; + else { + acl_msg_error("invalid service name: %s", tokens->argv[0]); + acl_argv_free(tokens); + return; + } + + for (i = 1; i < tokens->argc; i++) { + proto = (struct PROTO*) acl_mymalloc(sizeof(struct PROTO)); + proto->service = service; + snprintf(proto->name, sizeof(proto->name), "%s", tokens->argv[0]); + snprintf(proto->addr, sizeof(proto->addr), "%s", tokens->argv[i]); + proto->len = strlen(proto->addr); + acl_array_append(__proto_map, proto); + } + + acl_argv_free(tokens); +} + +static void parse_proto_list(void) +{ + ACL_ARGV *tokens = acl_argv_split(var_cfg_proto_list, ",; \t"); + ACL_ITER iter; + + __proto_map = acl_array_create(1); + acl_foreach(iter, tokens) { + proto_add((const char*) iter.data); + } + + acl_argv_free(tokens); +} + +/* 初始化函数 */ +void service_init(void *ctx acl_unused) +{ + if (var_cfg_debug_mem) { + acl_memory_debug_start(); + acl_memory_debug_stack(1); + } + + if (strcasecmp(var_cfg_proto_default, "cmdline") == 0) + __default_service = cmdline_service; + else + __default_service = http_service; + + parse_proto_list(); + gid_init(var_cfg_fh_limit, var_cfg_sync_gid, var_cfg_debug_section); +} + +void service_exit(void *ctx acl_unused) +{ + if (__proto_map != NULL) + acl_array_free(__proto_map, acl_myfree_fn); + + gid_finish(); +} + +int service_main(ACL_VSTREAM *client, void *ctx acl_unused) +{ + int (*service)(ACL_VSTREAM*) = NULL; + int ret; + char addr[256]; + ACL_ITER iter; + PROTO *proto; + + if (acl_getsockname(ACL_VSTREAM_SOCK(client), addr, sizeof(addr)) < 0) { + acl_msg_error("can't get local addr from fd: %d", + ACL_VSTREAM_SOCK(client)); + return -1; + } + + acl_foreach(iter, __proto_map) { + proto = (PROTO*) iter.data; + if (acl_strrncasecmp(proto->addr, addr, proto->len) == 0) { + service = proto->service; + break; + } + } + + if (service == NULL) { + service = __default_service; + acl_msg_info("user default service for %s", var_cfg_proto_default); + } + + if (var_cfg_loop_enable) { + while (1) { + if ((ret = service(client)) != 1) + return (-1); + } + } else if (service(client) != 1) + return (-1); + else + return (0); +} diff --git a/app/gid/gid_server/test/Makefile b/app/gid/gid_server/test/Makefile new file mode 100644 index 000000000..c96ba33cc --- /dev/null +++ b/app/gid/gid_server/test/Makefile @@ -0,0 +1,116 @@ +SHELL = /bin/sh +CC = g++ +CC = gcc +#CC = ${MY_ENV_CC} +AR = ar +ARFL = rv +#ARFL = cru +RANLIB = ranlib + +CFLAGS = -c -g -W -Wall -Wcast-qual -Wcast-align \ +-Waggregate-return \ +-Wno-long-long \ +-Wpointer-arith -Werror -Wshadow -O2 \ +-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO + +#CFLAGS = -c -g -W -Wall -Wcast-qual -Wcast-align \ +#-Waggregate-return -Wmissing-prototypes \ +#-Wpointer-arith -Werror -Wshadow -O2 \ +#-D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO +########################################################### +#Check system: +# Linux, SunOS, Solaris, BSD variants, AIX, HP-UX +SYSLIB = -lpthread -lcrypt -lz +CHECKSYSRES = @echo "Unknow system type!";exit 1 +UNIXNAME = $(shell uname -sm) +OSTYPE = $(shell uname -p) +RPATH = + +ifeq ($(CC),) + CC = gcc +endif + +#Path for Linux +ifeq ($(findstring Linux, $(UNIXNAME)), Linux) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DLINUX2 -D_REENTRANT -pedantic + + ifeq ($(findstring i686, $(OSTYPE)), i686) + RPATH = linux32 + FLAG_OS = LINUX32 + endif + ifeq ($(findstring x86_64, $(OSTYPE)), x86_64) + RPATH = linux64 + FLAG_OS = LINUX64 + endif +endif + +#Path for SunOS +ifeq ($(findstring SunOS, $(UNIXNAME)), SunOS) + ifeq ($(findstring 86, $(UNIXNAME)), 86) + SYSLIB += -lsocket -lnsl -lrt + endif + ifeq ($(findstring sun4u, $(UNIXNAME)), sun4u) + SYSLIB += -lsocket -lnsl -lrt + endif + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DSUNOS5 -D_REENTRANT -pedantic +endif + +#Path for HP-UX +ifeq ($(findstring HP-UX, $(UNIXNAME)), HP-UX) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DHP_UX -DHPUX11 + PLAT_NAME=hp-ux +endif + +#Find system type. +ifneq ($(SYSPATH),) + CHECKSYSRES = @echo "System is $(shell uname -sm)" +endif +########################################################### +BASE_PATH = /opt/import_lib + +BASE_LIB_PATH = $(BASE_PATH)/lib +BASE_INC_PATH = $(BASE_PATH)/include + +ACL_LIB = $(BASE_LIB_PATH) +ACL_INC = $(BASE_INC_PATH)/acl + +CFLAGS += $(INC_COMPILE) + +INC_COMPILE = -I$(ACL_INC) -I$(BASE_INC_PATH) -I./include +LIB_COMPILE = -L$(ACL_LIB) -l_acl + +########################################################### +OUT_PATH = . +OBJ_PATH = $(OUT_PATH) + +#Project's objs +SRC = $(wildcard ./*.c) +OBJ = $(patsubst %.c, $(OBJ_PATH)/%.o, $(notdir $(SRC))) +########################################################### + +PROG = test + +.PHONY = all clean +COMPILE = $(CC) $(CFLAGS) + +$(PROG): $(OBJ) + $(CC) $(OBJ) $(LIB_COMPILE) $(SYSLIB) -o $(PROG) + @echo "" + @echo "All ok! Output:$(PROG)" + @echo "" + +$(OBJ_PATH)/%.o: ./%.c + $(COMPILE) $< -o $@ + +clean: + rm -f $(PROG) + rm -f $(OBJ) diff --git a/app/gid/gid_server/test/main.c b/app/gid/gid_server/test/main.c new file mode 100644 index 000000000..7a93ed2aa --- /dev/null +++ b/app/gid/gid_server/test/main.c @@ -0,0 +1,120 @@ +#include "lib_acl.h" +#include +#include +#include +#include +#include +#include +#include + +static int request(ACL_VSTREAM *client, int cmd_num, int out) +{ + const char cmd1[] = "CMD^new_gid|TAG^default:hello\r\n"; + const char cmd2[] = "CMD^test_gid\r\n"; + const char *cmd; + char buf[256]; + int ret; + + if (cmd_num == 1) + cmd = cmd1; + else + cmd = cmd2; + ret = acl_vstream_writen(client, cmd, strlen(cmd)); + if (ret == ACL_VSTREAM_EOF) { + printf("write cmd to server error\n"); + return (-1); + } + ret = acl_vstream_gets(client, buf, sizeof(buf)); + if (ret == ACL_VSTREAM_EOF) { + printf("gets error\n"); + return (-1); + } + + if (out) + printf(">>gets: %s\n", buf); + return (0); +} + +static void run(const char *addr, int n, int keep_alive, int cmd_num) +{ + ACL_VSTREAM *client = NULL; + int i, ret, out; + time_t begin, end; + + time(&begin); + + for (i = 0; i < n; i++) { + if (client == NULL) { + client = acl_vstream_connect(addr, ACL_BLOCKING, 0, 0, 0); + if (client == NULL) { + printf("connect to %s error %s\n", + addr, acl_last_serror()); + break; + } + acl_tcp_so_linger(ACL_VSTREAM_SOCK(client), 1, 0); + } + if ((i > 0 && i % 10000 == 0) || n <= 20) + out = 1; + else + out = 0; + ret = request(client, cmd_num, out); + if (ret < 0) + break; + + if (!keep_alive) { + acl_vstream_close(client); + client = NULL; + } + + if (out) { + printf(">>>i: %d\n", i); + ACL_METER_TIME("----------"); + } + } + + time(&end); + printf("ok, total: %d, time spent: %ld\n", i, end - begin); + if (client) + acl_vstream_close(client); +} + +static void usage(const char *procname) +{ + printf("usage: %s -h [help] -s server_addr[127.0.0.1:7072] -n loop_count -k -i cmd_number\n", procname); +} + +int main(int argc, char *argv[]) +{ + char ch, addr[32]; + int n = 1, keep_alive = 0, cmd_num = 0; + + addr[0] = 0; + while ((ch = getopt(argc, argv, "hks:n:i:")) > 0) { + switch (ch) { + case 's': + ACL_SAFE_STRNCPY(addr, optarg, sizeof(addr)); + break; + case 'n': + n = atoi(optarg); + break; + case 'k': + keep_alive = 1; + break; + case 'i': + cmd_num = atoi(optarg); + break; + case 'h': + default: + usage(argv[0]); + return (0); + } + } + + if (addr[0] == 0 || n <= 0) { + usage(argv[0]); + return (0); + } + + run(addr, n, keep_alive, cmd_num); + return (0); +} diff --git a/app/gid/gid_server/unix/main.c b/app/gid/gid_server/unix/main.c new file mode 100644 index 000000000..1115a69b8 --- /dev/null +++ b/app/gid/gid_server/unix/main.c @@ -0,0 +1,174 @@ +#include "lib_acl.h" +#include +#include +#include +#include +#include +#include +#include + +#include "global.h" +#include "service_main.h" + +static acl_pthread_pool_t *__thr_pool = NULL; +static int __run_once = 0; + +static void app_run(void *arg) +{ + ACL_VSTREAM *client = (ACL_VSTREAM*) arg; + + while (1) { + if (service_main(client, NULL) < 0) + break; + if (__run_once) + break; + } + + printf("close client stream now\n"); + acl_vstream_close(client); +} + +static void on_sigint(int signum acl_unused) +{ + signal(SIGINT, SIG_DFL); + if (__thr_pool) + acl_pthread_pool_destroy(__thr_pool); + exit (0); +} + +static ACL_VSTREAM *init(const char *filepath) +{ + ACL_VSTREAM *sstream; + char addr[] = ":7072"; + ACL_XINETD_CFG_PARSER *cfg = NULL; + + acl_init(); + /* + acl_debug_malloc_init(NULL, "log.txt"); + */ + + sstream = acl_vstream_listen(addr, 60); + assert(sstream != NULL); + printf("listen on: %s\n", addr); + + if (filepath) + cfg = acl_xinetd_cfg_load(filepath); + + acl_xinetd_params_int_table(cfg, service_conf_int_tab); + acl_xinetd_params_bool_table(cfg, service_conf_bool_tab); + acl_xinetd_params_str_table(cfg, service_conf_str_tab); + if (cfg) + acl_xinetd_cfg_free(cfg); + + signal(SIGINT, on_sigint); /* 注册程序退出回调函数 */ + service_init(NULL); + + return (sstream); +} + +static void end(void) +{ + service_exit(NULL); + acl_myfree(var_cfg_gid_path); + acl_end(); +} + +static void app_test_thrpool(const char *filepath) +{ + ACL_VSTREAM *sstream; + + sstream = init(filepath); + __thr_pool = acl_thread_pool_create(10, 120); + + while (1) { + ACL_VSTREAM *client = acl_vstream_accept(sstream, NULL, 0); + + if (client == NULL) { + printf("accept error: %s\n", acl_last_serror()); + break; + } else { + printf("accept one\n"); + } + acl_pthread_pool_add(__thr_pool, app_run, client); + } + + acl_vstream_close(sstream); +} + +static void app_test_once(const char *filepath) +{ + ACL_VSTREAM *client, *sstream; + + __run_once = 1; + sstream = init(filepath); + client = acl_vstream_accept(sstream, NULL, 0); + app_run(client); + printf("close sstream now\n"); + acl_vstream_close(sstream); + end(); +} + +static void usage(const char *procname) +{ + printf("usage: %s help\n", procname); + printf("usage: %s test -f conf_file -m[use mempool]\n", procname); +} + +static void app_test(const char *procname, int argc, char **argv) +{ + char filepath[256]; + int ch, use_mempool = 0, use_concurrent = 0; + + filepath[0] = 0; + while ((ch = getopt(argc, argv, "f:mP")) > 0) { + switch (ch) { + case 'f': + snprintf(filepath, sizeof(filepath), "%s", optarg); + break; + case 'm': + use_mempool = 1; + break; + case 'P': + use_concurrent = 1; + break; + default: + break; + } + } + + if (filepath[0] == 0) { + usage(procname); + return; + } + if (use_mempool) + acl_mem_slice_init(8, 1024, 100000, + ACL_SLICE_FLAG_GC2 | + ACL_SLICE_FLAG_RTGC_OFF | + ACL_SLICE_FLAG_LP64_ALIGN); + + acl_msg_stdout_enable(1); + + if (use_concurrent) + app_test_thrpool(filepath); + else + app_test_once(filepath); +} + +int main(int argc, char **argv) +{ + if (argc == 2 && strcmp(argv[1], "help") == 0) { + usage(argv[0]); + } else if (argc >= 3 && strcmp(argv[1], "test") == 0) { + app_test(argv[0], argc - 1, argv + 1); + } else { + acl_ioctl_app_main(argc, argv, service_main, NULL, + ACL_APP_CTL_INIT_FN, service_init, + ACL_APP_CTL_EXIT_FN, service_exit, + ACL_APP_CTL_CFG_INT, service_conf_int_tab, + ACL_APP_CTL_CFG_STR, service_conf_str_tab, + ACL_APP_CTL_CFG_BOOL, service_conf_bool_tab, + ACL_APP_CTL_END); + } + + return (0); +} diff --git a/app/gid/gid_server/valgrind.sh b/app/gid/gid_server/valgrind.sh new file mode 100644 index 000000000..7aa1cf89e --- /dev/null +++ b/app/gid/gid_server/valgrind.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +valgrind --tool=memcheck --leak-check=yes -v ./gid_server test -f gid_server.cf diff --git a/app/gid/gid_server/win32/main.c b/app/gid/gid_server/win32/main.c new file mode 100644 index 000000000..c037b1735 --- /dev/null +++ b/app/gid/gid_server/win32/main.c @@ -0,0 +1,73 @@ +#include "lib_acl.h" +#include +#include +#include +#include +#include +#include + +#include "service_main.h" + +static void client_thread(int event_type acl_unused, void* arg) +{ + ACL_WORKER_ATTR* attr = (ACL_WORKER_ATTR*) arg; + ACL_VSTREAM *client = (ACL_VSTREAM*) attr->run_data; + time_t last, cost; + + while (1) { + last = time(NULL); + if (service_main(client, NULL) < 0) + break; + cost = time(NULL) - last; + if (cost >= 1) + printf("%s: >>> time cost = %ld\r\n", __FILE__, cost); + } + acl_vstream_close(client); +} + +static void usage(const char *progname) +{ + printf("usage: %s -[help]\r\n" + "-s server_addr\r\n" + "-f regnum\r\n", progname); + getchar(); +} + +int main(int argc, char *argv[]) +{ + ACL_VSTREAM *sstream, *client; + ACL_WORK_QUEUE* wq = acl_workq_create(100, 60, NULL, NULL); + char ch, *addr = "127.0.0.1:8889"; + char *regnum = "regnum"; + + while ((ch = getopt(argc, argv, "hs:f:")) > 0) { + switch (ch) { + default: + case 'h': + usage(argv[0]); + exit (0); + case 's': + addr = acl_mystrdup(optarg); + break; + case 'f': + regnum = optarg; + break; + } + } + + var_cfg_cache_file = acl_mystrdup(regnum); + acl_socket_init(); + service_init(NULL); + + sstream = acl_vstream_listen(addr, 32); + if (sstream == NULL) + acl_msg_fatal("can't listen on addr(%s)", addr); + + printf("started, listen on %s ...\r\n", addr); + while (1) { + client = acl_vstream_accept(sstream, NULL, 0); + acl_workq_add(wq, client_thread, 0, client); + } + + exit (0); +} diff --git a/app/gid/readme.txt b/app/gid/readme.txt new file mode 100644 index 000000000..53382b677 --- /dev/null +++ b/app/gid/readme.txt @@ -0,0 +1,3 @@ +本模块主要提供唯一ID号的功能,服务器启动后,客户端可以通过 +三种协议方式连接服务器获得唯一ID,目前提供了C和JAVA版本的 +客户端API。 diff --git a/app/jaws/JawsCtrl/HttpService.cpp b/app/jaws/JawsCtrl/HttpService.cpp new file mode 100644 index 000000000..908f73639 --- /dev/null +++ b/app/jaws/JawsCtrl/HttpService.cpp @@ -0,0 +1,58 @@ +#include "StdAfx.h" +#include ".\httpservice.h" + +static char *tag_addr = "--addr"; +static char *tag_http_vhost_path = "--http_vhost_path"; +static char *tag_http_vhost_default = "--http_vhost_default"; +static char *tag_http_tmpl_path = "--http_tmpl_path"; +static char *tag_http_filter_info = "--http_filter_info"; + +CHttpService::CHttpService( + const char * procname, + const char * addr, + const char * vhostPath, + const char * vhostDefault, + const char * tmplPath, + const char * filterInfo) +: m_addr(_T(addr)) +, m_vhostPath(_T(vhostPath)) +, m_vhostDefault(_T(vhostDefault)) +, m_tmplPath(_T(tmplPath)) +, m_filterInfo(_T(filterInfo)) +{ + int i; + + m_argc = 10; + m_argv = (char **) calloc(m_argc, sizeof(char*)); + + i = 0; + + m_argv[i++] = strdup(tag_addr); + m_argv[i++] = strdup(addr); + + m_argv[i++] = strdup(tag_http_vhost_path); + m_argv[i++] = strdup(vhostPath); + + m_argv[i++] = strdup(tag_http_vhost_default); + m_argv[i++] = strdup(vhostDefault); + + m_argv[i++] = strdup(tag_http_tmpl_path); + m_argv[i++] = strdup(tmplPath); + + m_argv[i++] = strdup(tag_http_filter_info); + m_argv[i++] = strdup(filterInfo); + + ASSERT(i == m_argc); + CProcService::Init(_T(procname)); +} + +CHttpService::~CHttpService(void) +{ + int i; + + for (i = 0; i < m_argc; i++) + { + free(m_argv[i]); + } + free(m_argv); +} diff --git a/app/jaws/JawsCtrl/HttpService.h b/app/jaws/JawsCtrl/HttpService.h new file mode 100644 index 000000000..2c70b595f --- /dev/null +++ b/app/jaws/JawsCtrl/HttpService.h @@ -0,0 +1,21 @@ +#pragma once +#include "procservice.h" + +class CHttpService : public CProcService +{ +public: + CHttpService( + const char *procname, + const char *addr, + const char * vhostPath, + const char * vhostDefault, + const char * tmplPath, + const char * filterInfo); + ~CHttpService(void); +private: + CString m_addr; + CString m_vhostPath; + CString m_vhostDefault; + CString m_tmplPath; + CString m_filterInfo; +}; diff --git a/app/jaws/JawsCtrl/JawsCtrl.cpp b/app/jaws/JawsCtrl/JawsCtrl.cpp new file mode 100644 index 000000000..45f4f4d7b --- /dev/null +++ b/app/jaws/JawsCtrl/JawsCtrl.cpp @@ -0,0 +1,83 @@ +// JawsCtrl.cpp : 定义应用程序的类行为。 +// + +#include "stdafx.h" +#include "JawsCtrl.h" +#include "JawsCtrlDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#endif + + +// CJawsCtrlApp + +BEGIN_MESSAGE_MAP(CJawsCtrlApp, CWinApp) + ON_COMMAND(ID_HELP, CWinApp::OnHelp) +END_MESSAGE_MAP() + + +// CJawsCtrlApp 构造 + +CJawsCtrlApp::CJawsCtrlApp() +: m_singleCtrl("Jaws") +{ + // TODO: 在此处添加构造代码, + // 将所有重要的初始化放置在 InitInstance 中 +} + + +// 唯一的一个 CJawsCtrlApp 对象 + +CJawsCtrlApp theApp; + + +// CJawsCtrlApp 初始化 + +BOOL CJawsCtrlApp::InitInstance() +{ + // 如果一个运行在 Windows XP 上的应用程序清单指定要 + // 使用 ComCtl32.dll 版本 6 或更高版本来启用可视化方式, + //则需要 InitCommonControls()。否则,将无法创建窗口。 + InitCommonControls(); + + CWinApp::InitInstance(); + + if (!m_singleCtrl.Check()) + return FALSE; + + if (!AfxSocketInit()) + { + AfxMessageBox(IDP_SOCKETS_INIT_FAILED); + return FALSE; + } + + AfxEnableControlContainer(); + + // 标准初始化 + // 如果未使用这些功能并希望减小 + // 最终可执行文件的大小,则应移除下列 + // 不需要的特定初始化例程 + // 更改用于存储设置的注册表项 + // TODO: 应适当修改该字符串, + // 例如修改为公司或组织名 + SetRegistryKey(_T("应用程序向导生成的本地应用程序")); + + CJawsCtrlDlg dlg; + m_pMainWnd = &dlg; + INT_PTR nResponse = dlg.DoModal(); + if (nResponse == IDOK) + { + // TODO: 在此放置处理何时用“确定”来关闭 + //对话框的代码 + } + else if (nResponse == IDCANCEL) + { + // TODO: 在此放置处理何时用“取消”来关闭 + //对话框的代码 + } + + // 由于对话框已关闭,所以将返回 FALSE 以便退出应用程序, + // 而不是启动应用程序的消息泵。 + return FALSE; +} diff --git a/app/jaws/JawsCtrl/JawsCtrl.h b/app/jaws/JawsCtrl/JawsCtrl.h new file mode 100644 index 000000000..e3d05cf0e --- /dev/null +++ b/app/jaws/JawsCtrl/JawsCtrl.h @@ -0,0 +1,33 @@ +// JawsCtrl.h : PROJECT_NAME 应用程序的主头文件 +// + +#pragma once + +#ifndef __AFXWIN_H__ + #error 在包含用于 PCH 的此文件之前包含“stdafx.h” +#endif +#include "SingleCtrl.h" +#include "resource.h" // 主符号 + + +// CJawsCtrlApp: +// 有关此类的实现,请参阅 JawsCtrl.cpp +// + +class CJawsCtrlApp : public CWinApp +{ +public: + CJawsCtrlApp(); + +// 重写 + public: + virtual BOOL InitInstance(); + + CSingleCtrl m_singleCtrl; + +// 实现 + + DECLARE_MESSAGE_MAP() +}; + +extern CJawsCtrlApp theApp; diff --git a/app/jaws/JawsCtrl/JawsCtrl.rc b/app/jaws/JawsCtrl/JawsCtrl.rc new file mode 100644 index 000000000..eb71cb290 --- /dev/null +++ b/app/jaws/JawsCtrl/JawsCtrl.rc @@ -0,0 +1,233 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// 中文(中华人民共和国) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) +#ifdef _WIN32 +LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED +#pragma code_page(936) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "#define _AFX_NO_SPLITTER_RESOURCES\r\n" + "#define _AFX_NO_OLE_RESOURCES\r\n" + "#define _AFX_NO_TRACKER_RESOURCES\r\n" + "#define _AFX_NO_PROPERTY_RESOURCES\r\n" + "\r\n" + "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)\r\n" + "LANGUAGE 4, 2\r\n" + "#pragma code_page(936)\r\n" + "#include ""res\\JawsCtrl.rc2"" // 非 Microsoft Visual C++ 编辑过的资源\r\n" + "#include ""afxres.rc"" // 标准组件\r\n" + "#endif\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDR_MAINFRAME ICON "res\\JawsCtrl.ico" +IDI_MIN_ICON ICON "res\\min_icon.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_ABOUTBOX DIALOGEX 0, 0, 235, 55 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | + WS_SYSMENU +CAPTION "关于 JawsCtrl" +FONT 9, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + ICON IDR_MAINFRAME,IDC_STATIC,11,17,20,20 + LTEXT "JawsCtrl Version 1.0",IDC_STATIC,40,10,119,8, + SS_NOPREFIX + LTEXT "Copyright (C) 2008",IDC_STATIC,40,25,119,8 + DEFPUSHBUTTON "确定",IDOK,178,7,50,16,WS_GROUP +END + +IDD_JAWSCTRL_DIALOG DIALOGEX 0, 0, 183, 175 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_POPUP | + WS_VISIBLE | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_APPWINDOW +CAPTION "JawsCtrl" +FONT 9, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + LTEXT "IP地址:",IDC_STATIC,24,118,28,12 + LTEXT "端口号:",IDC_STATIC,24,138,28,8 + EDITTEXT IDC_EDIT_PORT,57,137,37,14,ES_AUTOHSCROLL + GROUPBOX "本地监听",IDC_STATIC,16,93,152,65 + CONTROL "",IDC_IPADDRESS_LISTEN,"SysIPAddress32",WS_TABSTOP,57, + 117,100,15 + PUSHBUTTON "启动",IDC_BUTTON_START,116,13,50,14 + PUSHBUTTON "停止",IDC_BUTTON_STOP,116,28,50,14 + CONTROL "Webserver",IDC_RADIO_HTTPD,"Button",BS_AUTORADIOBUTTON | + WS_GROUP,23,27,50,10 + CONTROL "http proxy",IDC_RADIO_HTTP_PROXY,"Button", + BS_AUTORADIOBUTTON,23,39,49,10 + PUSHBUTTON "退出",IDC_BUTTON_QUIT,116,44,50,14 + GROUPBOX "运行模式",IDC_STATIC,18,17,55,37 + CONTROL "",IDC_DIVIDER,"Static",SS_BLACKRECT,3,86,176,1, + WS_EX_STATICEDGE + PUSHBUTTON "&M更多>>",IDC_MORE,116,66,50,14 + CONTROL "开机启动",IDC_AUTO_RUN,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,19,68,43,10 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "080403a8" + BEGIN + VALUE "CompanyName", "TODO: <公司名>" + VALUE "FileDescription", "TODO: <文件说明>" + VALUE "FileVersion", "1.0.0.1" + VALUE "InternalName", "JawsCtrl.exe" + VALUE "LegalCopyright", "TODO: (C) <公司名>。保留所有权利。" + VALUE "OriginalFilename", "JawsCtrl.exe" + VALUE "ProductName", "TODO: <产品名>" + VALUE "ProductVersion", "1.0.0.1" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "翻译", 0x804, 936 + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_ABOUTBOX, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 228 + TOPMARGIN, 7 + BOTTOMMARGIN, 48 + END + + IDD_JAWSCTRL_DIALOG, DIALOG + BEGIN + LEFTMARGIN, 3 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 168 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDR_MENU_ICON MENU +BEGIN + POPUP "托盘菜单" + BEGIN + MENUITEM "打开主窗口", ID_OPEN_MAIN + MENUITEM "退出程序", ID_QUIT + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + IDS_ABOUTBOX "关于 JawsCtrl(&A)..." + IDP_SOCKETS_INIT_FAILED "Windows 套接字初始化失败。" +END + +#endif // 中文(中华人民共和国) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +#define _AFX_NO_SPLITTER_RESOURCES +#define _AFX_NO_OLE_RESOURCES +#define _AFX_NO_TRACKER_RESOURCES +#define _AFX_NO_PROPERTY_RESOURCES + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) +LANGUAGE 4, 2 +#pragma code_page(936) +#include "res\JawsCtrl.rc2" // 非 Microsoft Visual C++ 编辑过的资源 +#include "afxres.rc" // 标准组件 +#endif + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/app/jaws/JawsCtrl/JawsCtrl.vcproj b/app/jaws/JawsCtrl/JawsCtrl.vcproj new file mode 100644 index 000000000..493dc5c67 --- /dev/null +++ b/app/jaws/JawsCtrl/JawsCtrl.vcproj @@ -0,0 +1,231 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/jaws/JawsCtrl/JawsCtrlDlg.cpp b/app/jaws/JawsCtrl/JawsCtrlDlg.cpp new file mode 100644 index 000000000..2affb062d --- /dev/null +++ b/app/jaws/JawsCtrl/JawsCtrlDlg.cpp @@ -0,0 +1,365 @@ +// JawsCtrlDlg.cpp : 实现文件 +// + +#include "stdafx.h" +#include "lib_acl.h" +#include "JawsCtrl.h" +#include "JawsCtrlDlg.h" +#include ".\jawsctrldlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#endif + + +// 用于应用程序“关于”菜单项的 CAboutDlg 对话框 + +class CAboutDlg : public CDialog +{ +public: + CAboutDlg(); + +// 对话框数据 + enum { IDD = IDD_ABOUTBOX }; + + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 + +// 实现 +protected: + DECLARE_MESSAGE_MAP() +}; + +CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) +{ +} + +void CAboutDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); +} + +BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) +END_MESSAGE_MAP() + + +// CJawsCtrlDlg 对话框 + +CJawsCtrlDlg::CJawsCtrlDlg(CWnd* pParent /*=NULL*/) + : CDialog(CJawsCtrlDlg::IDD, pParent) + , m_trayIcon(IDR_MENU_ICON) + , m_bShutdown(FALSE) + , m_sJawsName(_T("")) + , m_sJawsCtrlName(_T("")) + , m_listenPort(8080) + , m_listenIp(_T("127.0.0.1")) + , m_httpVhostPath(_T("")) + , m_httpVhostDefault(_T("")) + , m_httpTmplPath(_T("")) + , m_httpFilter(_T("HTTP_FILTER_HTTPD")) + , m_nHttpFilter(IDC_RADIO_HTTPD) + , m_pService(NULL) + , m_regRun(_T("JawsCtrl")) +{ + char buf[MAX_PATH]; + + acl_proctl_daemon_path(buf, sizeof(buf)); + m_sJawsName.Format("%s\\Jaws.exe", buf); + m_sJawsCtrlName.Format("%s\\JawsCtrl.exe", buf); + + //m_sJawsName.Format("C:\\\"Program Files\"\\\"Acl Project\"\\Jaws\\Jaws.exe"); + m_httpVhostPath.Format("%s\\conf\\www\\vhost", buf); + m_httpVhostDefault.Format("%s\\conf\\www\\defaults.cf", buf); + m_httpTmplPath.Format("%s\\conf\\www\\tmpl", buf); + + m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); + m_procCtrl.RunThread(); +} + +void CJawsCtrlDlg::DoDataExchange(CDataExchange* pDX) +{ + BYTE field1, field2, field3, field4; + + CDialog::DoDataExchange(pDX); + DDX_Control(pDX, IDC_IPADDRESS_LISTEN, m_listenIpCtrl); + if (pDX->m_bSaveAndValidate) { + m_listenIpCtrl.GetAddress(field1, field2, field3, field4); + m_listenIp.Format("%d.%d.%d.%d", field1, field2, field3, field4); + } + DDX_Text(pDX, IDC_EDIT_PORT, m_listenPort); + DDV_MinMaxLong(pDX, m_listenPort, 0, 65535); +} + +BEGIN_MESSAGE_MAP(CJawsCtrlDlg, CDialog) + ON_WM_SYSCOMMAND() + ON_WM_PAINT() + ON_WM_QUERYDRAGICON() + //}}AFX_MSG_MAP + ON_WM_CREATE() + ON_COMMAND(ID_OPEN_MAIN, OnOpenMain) + ON_COMMAND(ID_QUIT, OnQuit) + ON_MESSAGE(WM_MY_TRAY_NOTIFICATION, OnTrayNotification) + ON_WM_NCPAINT() + ON_WM_CLOSE() + ON_WM_DESTROY() + ON_BN_CLICKED(IDC_BUTTON_START, OnBnClickedButtonStart) + ON_BN_CLICKED(IDC_BUTTON_STOP, OnBnClickedButtonStop) + ON_BN_CLICKED(IDC_BUTTON_QUIT, OnBnClickedButtonQuit) + ON_BN_CLICKED(IDC_MORE, OnBnClickedMore) + ON_BN_CLICKED(IDC_AUTO_RUN, OnBnClickedAutoRun) +END_MESSAGE_MAP() + + +// CJawsCtrlDlg 消息处理程序 + +BOOL CJawsCtrlDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + // 将\“关于...\”菜单项添加到系统菜单中。 + + // IDM_ABOUTBOX 必须在系统命令范围内。 + ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); + ASSERT(IDM_ABOUTBOX < 0xF000); + + CMenu* pSysMenu = GetSystemMenu(FALSE); + if (pSysMenu != NULL) + { + CString strAboutMenu; + strAboutMenu.LoadString(IDS_ABOUTBOX); + if (!strAboutMenu.IsEmpty()) + { + pSysMenu->AppendMenu(MF_SEPARATOR); + pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); + } + } + + // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动 + // 执行此操作 + SetIcon(m_hIcon, TRUE); // 设置大图标 + SetIcon(m_hIcon, FALSE); // 设置小图标 + + // TODO: 在此添加额外的初始化代码 + m_dVerticalExpand.Init(this, IDC_DIVIDER, TRUE); + ExpandDialog(FALSE); + + theApp.m_singleCtrl.Register(); + m_listenIpCtrl.SetAddress(127, 0, 0, 1); + CheckRadioButton(IDC_RADIO_HTTPD, IDC_RADIO_HTTP_PROXY, IDC_RADIO_HTTP_PROXY); + GetDlgItem(IDC_BUTTON_STOP)->EnableWindow(FALSE); + + // 启动 Jaws.exe + if (m_regRun.IfAutoRun()) { + OnBnClickedButtonStart(); + CheckDlgButton(IDC_AUTO_RUN, 1); + } else + CheckDlgButton(IDC_AUTO_RUN, 0); + + return TRUE; // 除非设置了控件的焦点,否则返回 TRUE +} + +void CJawsCtrlDlg::OnSysCommand(UINT nID, LPARAM lParam) +{ + if ((nID & 0xFFF0) == IDM_ABOUTBOX) + { + CAboutDlg dlgAbout; + dlgAbout.DoModal(); + } + else + { + CDialog::OnSysCommand(nID, lParam); + } +} + +// 如果向对话框添加最小化按钮,则需要下面的代码 +// 来绘制该图标。对于使用文档/视图模型的 MFC 应用程序, +// 这将由框架自动完成。 + +void CJawsCtrlDlg::OnPaint() +{ + if (IsIconic()) + { + CPaintDC dc(this); // 用于绘制的设备上下文 + + SendMessage(WM_ICONERASEBKGND, reinterpret_cast(dc.GetSafeHdc()), 0); + + // 使图标在工作矩形中居中 + int cxIcon = GetSystemMetrics(SM_CXICON); + int cyIcon = GetSystemMetrics(SM_CYICON); + CRect rect; + GetClientRect(&rect); + int x = (rect.Width() - cxIcon + 1) / 2; + int y = (rect.Height() - cyIcon + 1) / 2; + + // 绘制图标 + dc.DrawIcon(x, y, m_hIcon); + } + else + { + CDialog::OnPaint(); + } +} + +//当用户拖动最小化窗口时系统调用此函数取得光标显示。 +HCURSOR CJawsCtrlDlg::OnQueryDragIcon() +{ + return static_cast(m_hIcon); +} + +int CJawsCtrlDlg::OnCreate(LPCREATESTRUCT lpCreateStruct) +{ + if (CDialog::OnCreate(lpCreateStruct) == -1) + return -1; + + // TODO: 在此添加您专用的创建代码 + m_trayIcon.SetNotificationWnd(this, WM_MY_TRAY_NOTIFICATION); + m_trayIcon.SetIcon(IDI_MIN_ICON); + return 0; +} + +void CJawsCtrlDlg::OnOpenMain() +{ + // TODO: 在此添加命令处理程序代码 + ShowWindow(SW_NORMAL); +} + +void CJawsCtrlDlg::OnQuit() +{ + // TODO: 在此添加命令处理程序代码 + m_bShutdown = TRUE; // really exit + SendMessage(WM_CLOSE); +} + +afx_msg LRESULT CJawsCtrlDlg::OnTrayNotification(WPARAM uID, LPARAM lEvent) +{ + // let tray icon do default stuff + return m_trayIcon.OnTrayNotification(uID, lEvent); +} +void CJawsCtrlDlg::OnNcPaint() +{ + // TODO: 在此处添加消息处理程序代码 + // 不为绘图消息调用 CDialog::OnNcPaint() + static int i = 2; + if(i > 0) + { + i --; + ShowWindow(SW_HIDE); + } else + { + CDialog::OnNcPaint(); + } +} + +void CJawsCtrlDlg::OnClose() +{ + // TODO: 在此添加消息处理程序代码和/或调用默认值 + + if (m_bShutdown) { + if (m_pService) { + m_procCtrl.StopOne(*m_pService); + + delete m_pService; + m_pService = NULL; + } + CDialog::OnClose(); + } else { + ShowWindow(SW_HIDE); + } +} + +void CJawsCtrlDlg::OnDestroy() +{ + CDialog::OnDestroy(); + + // TODO: 在此处添加消息处理程序代码 + theApp.m_singleCtrl.Remove(); +} + +void CJawsCtrlDlg::OnBnClickedButtonStart() +{ + // TODO: 在此添加控件通知处理程序代码 + CString addr; + + addr.Format("%s:%d", m_listenIp, m_listenPort); + m_nHttpFilter = GetCheckedRadioButton(IDC_RADIO_HTTPD, IDC_RADIO_HTTP_PROXY); + switch (m_nHttpFilter) { + case IDC_RADIO_HTTPD: + m_httpFilter.Format("HTTP_FILTER_HTTPD"); + break; + case IDC_RADIO_HTTP_PROXY: + m_httpFilter.Format("HTTP_FILTER_PROXY"); + break; + default: + m_httpFilter.Format("HTTP_FILTER_HTTPD"); + break; + } + + ASSERT(m_pService == NULL); + m_pService = new CHttpService( + m_sJawsName.GetString(), + addr.GetString(), + m_httpVhostPath.GetString(), + m_httpVhostDefault.GetString(), + m_httpTmplPath.GetString(), + m_httpFilter.GetString()); + + m_pService->DebugArgv(); + m_procCtrl.StartOne(*m_pService); + GetDlgItem(IDC_BUTTON_START)->EnableWindow(FALSE); + GetDlgItem(IDC_BUTTON_STOP)->EnableWindow(TRUE); + GetDlgItem(IDC_RADIO_HTTPD)->EnableWindow(FALSE); + GetDlgItem(IDC_RADIO_HTTP_PROXY)->EnableWindow(FALSE); +} + +void CJawsCtrlDlg::OnBnClickedButtonStop() +{ + // TODO: 在此添加控件通知处理程序代码 + ASSERT(m_pService != NULL); + GetDlgItem(IDC_BUTTON_START)->EnableWindow(TRUE); + GetDlgItem(IDC_BUTTON_STOP)->EnableWindow(FALSE); + m_procCtrl.StopOne(*m_pService); + GetDlgItem(IDC_RADIO_HTTPD)->EnableWindow(TRUE); + GetDlgItem(IDC_RADIO_HTTP_PROXY)->EnableWindow(TRUE); + + delete m_pService; + m_pService = NULL; +} + +void CJawsCtrlDlg::OnBnClickedButtonQuit() +{ + // TODO: 在此添加控件通知处理程序代码 + m_bShutdown = TRUE; // really exit + SendMessage(WM_CLOSE); +} + +void CJawsCtrlDlg::OnBnClickedMore() +{ + // TODO: 在此添加控件通知处理程序代码 + static BOOL bExpand = TRUE; + + ExpandDialog(bExpand); + bExpand = !bExpand; +} + +void CJawsCtrlDlg::ExpandDialog(BOOL bExpand) +{ + CString sExpand; + + m_dVerticalExpand.Expand(bExpand); + if (bExpand) { + sExpand = "<<(&L)更少"; + } else { + sExpand = "(&M)更多>>"; + } + + SetDlgItemText(IDC_MORE, sExpand); +} + +void CJawsCtrlDlg::OnBnClickedAutoRun() +{ + // TODO: 在此添加控件通知处理程序代码 + if (IsDlgButtonChecked(IDC_AUTO_RUN)) + m_regRun.AutoRun(TRUE, m_sJawsCtrlName.GetString()); + else + m_regRun.AutoRun(FALSE, m_sJawsCtrlName.GetString()); +} diff --git a/app/jaws/JawsCtrl/JawsCtrlDlg.h b/app/jaws/JawsCtrl/JawsCtrlDlg.h new file mode 100644 index 000000000..1ab697503 --- /dev/null +++ b/app/jaws/JawsCtrl/JawsCtrlDlg.h @@ -0,0 +1,79 @@ +// JawsCtrlDlg.h : 头文件 +// + +#pragma once +#include "Trayicon.h" +#include "ProcCtrl.h" +#include "HttpService.h" +#include "DialogExpand.h" +#include "RegRun.h" +#include "afxcmn.h" + +// CJawsCtrlDlg 对话框 +class CJawsCtrlDlg : public CDialog +{ +// 构造 +public: + CJawsCtrlDlg(CWnd* pParent = NULL); // 标准构造函数 + +// 对话框数据 + enum { IDD = IDD_JAWSCTRL_DIALOG }; + + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 + + +// 实现 +protected: + HICON m_hIcon; + CTrayIcon m_trayIcon; + + // 生成的消息映射函数 + virtual BOOL OnInitDialog(); + afx_msg void OnSysCommand(UINT nID, LPARAM lParam); + afx_msg void OnPaint(); + afx_msg HCURSOR OnQueryDragIcon(); + afx_msg LRESULT OnTrayNotification(WPARAM uID, LPARAM lEvent); + DECLARE_MESSAGE_MAP() +public: + afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); + afx_msg void OnOpenMain(); + afx_msg void OnQuit(); + afx_msg void OnNcPaint(); + afx_msg void OnClose(); +private: + BOOL m_bShutdown; +public: + afx_msg void OnDestroy(); +private: + CIPAddressCtrl m_listenIpCtrl; + CString m_listenIp; + long m_listenPort; + + CProcCtrl m_procCtrl; +public: + afx_msg void OnBnClickedButtonStart(); + afx_msg void OnBnClickedButtonStop(); + afx_msg void OnBnClickedButtonQuit(); +private: + CString m_sJawsName; + CString m_sJawsCtrlName; + CString m_httpVhostPath; + CString m_httpVhostDefault; + CString m_httpTmplPath; +private: + CString m_httpFilter; + UINT m_nHttpFilter; + + CHttpService *m_pService; +public: + afx_msg void OnBnClickedMore(); +private: + CDialogExpand m_dVerticalExpand; + CDialogExpand m_dHorizontalExpand; + void ExpandDialog(BOOL bExpand); + + CRegRun m_regRun; +public: + afx_msg void OnBnClickedAutoRun(); +}; diff --git a/app/jaws/JawsCtrl/ProcCtl.cpp b/app/jaws/JawsCtrl/ProcCtl.cpp new file mode 100644 index 000000000..74e06f813 --- /dev/null +++ b/app/jaws/JawsCtrl/ProcCtl.cpp @@ -0,0 +1,45 @@ +// ProcCtl.cpp : 实现文件 +// + +#include "stdafx.h" +#include "JawsCtrl.h" +#include "ProcCtl.h" +#include ".\procctl.h" + + +// CProcCtl + +IMPLEMENT_DYNCREATE(CProcCtl, CWinThread) + +CProcCtl::CProcCtl() +{ +} + +CProcCtl::~CProcCtl() +{ +} + +BOOL CProcCtl::InitInstance() +{ + // TODO: 在此执行任意逐线程初始化 + return TRUE; +} + +int CProcCtl::ExitInstance() +{ + // TODO: 在此执行任意逐线程清理 + return CWinThread::ExitInstance(); +} + +BEGIN_MESSAGE_MAP(CProcCtl, CWinThread) +END_MESSAGE_MAP() + + +// CProcCtl 消息处理程序 + +int CProcCtl::Run() +{ + // TODO: 在此添加专用代码和/或调用基类 + + return CWinThread::Run(); +} diff --git a/app/jaws/JawsCtrl/ProcCtl.h b/app/jaws/JawsCtrl/ProcCtl.h new file mode 100644 index 000000000..3a7834ab8 --- /dev/null +++ b/app/jaws/JawsCtrl/ProcCtl.h @@ -0,0 +1,25 @@ +#pragma once + +#include "lib_acl.h" + +// CProcCtl + +class CProcCtl : public CWinThread +{ + DECLARE_DYNCREATE(CProcCtl) + +protected: + CProcCtl(); // 动态创建所使用的受保护的构造函数 + virtual ~CProcCtl(); + +public: + virtual BOOL InitInstance(); + virtual int ExitInstance(); + +protected: + DECLARE_MESSAGE_MAP() +public: + virtual int Run(); +}; + + diff --git a/app/jaws/JawsCtrl/ProcCtrl.cpp b/app/jaws/JawsCtrl/ProcCtrl.cpp new file mode 100644 index 000000000..28bd3dcfc --- /dev/null +++ b/app/jaws/JawsCtrl/ProcCtrl.cpp @@ -0,0 +1,71 @@ +#include "StdAfx.h" +#include ".\procctrl.h" + +CProcCtrl::CProcCtrl(void) +{ + char logfile[MAX_PATH], *ptr; + + acl_proctl_daemon_path(m_exePath, sizeof(m_exePath)); + ptr = strrchr(m_exePath, '\\'); + if (ptr == NULL) + ptr = strrchr(m_exePath, '/'); + + if (ptr == NULL) + ptr = m_exePath; + else + ptr++; + + snprintf(logfile, sizeof(logfile), "%s/JawsCtrl.log", m_exePath); + acl_msg_open(logfile, "daemon"); + acl_debug_init("all:2"); +} + +CProcCtrl::~CProcCtrl(void) +{ +} + +static void *daemon_loop(void *arg) +{ + acl_proctl_daemon_loop(); + /* not reached */ + return (NULL); +} + +void CProcCtrl::RunThread() +{ + acl_pthread_t tid; + acl_pthread_attr_t attr; + + acl_proctl_deamon_init(m_exePath); + acl_pthread_attr_init(&attr); + acl_pthread_create(&tid, &attr, daemon_loop, NULL); +} + +void *CProcCtrl::StartThread(void *arg) +{ + CProcCtrl *ctrl = (CProcCtrl*) arg; + + acl_proctl_start_one(ctrl->m_exePath, ctrl->m_procName, + ctrl->m_service.m_argc, ctrl->m_service.m_argv); + return (NULL); +} + +void CProcCtrl::StartOne(CProcService& service) +{ +#undef USE_THREAD_CTRL + +#ifdef USE_THREAD_CTRL + m_service = service; + ACL_SAFE_STRNCPY(m_procName, service.m_procName, sizeof(m_procName)); + acl_pthread_t tid; + acl_pthread_create(&tid, NULL, StartThread, this); +#else + acl_proctl_deamon_start_one(service.m_procName, + service.m_argc, service.m_argv); +#endif +} + +void CProcCtrl::StopOne(CProcService& service) +{ + acl_proctl_stop_one(m_exePath, service.m_procName, 0, NULL); +} \ No newline at end of file diff --git a/app/jaws/JawsCtrl/ProcCtrl.h b/app/jaws/JawsCtrl/ProcCtrl.h new file mode 100644 index 000000000..c3739ee9c --- /dev/null +++ b/app/jaws/JawsCtrl/ProcCtrl.h @@ -0,0 +1,20 @@ +#pragma once +#include "lib_acl.h" +#include "ProcService.h" + +class CProcCtrl +{ +public: + CProcCtrl(void); + ~CProcCtrl(void); + void RunThread(void); +private: + char m_exePath[MAX_PATH]; + char m_logPath[MAX_PATH]; + char m_procName[MAX_PATH]; + CProcService m_service; + static void *StartThread(void*); +public: + void StartOne(CProcService&); + void StopOne(CProcService&); +}; diff --git a/app/jaws/JawsCtrl/ProcService.cpp b/app/jaws/JawsCtrl/ProcService.cpp new file mode 100644 index 000000000..4b8bc05d6 --- /dev/null +++ b/app/jaws/JawsCtrl/ProcService.cpp @@ -0,0 +1,24 @@ +#include "StdAfx.h" +#include "lib_acl.h" +#include ".\procservice.h" + +void CProcService::Init(const char *procname) +{ + m_procName = strdup(procname); +} + +CProcService::~CProcService(void) +{ + if (m_procName) + free(m_procName); +} + +void CProcService::DebugArgv(void) +{ + int i; + + for (i = 0; i < m_argc; i++) + { + acl_msg_info("argv[%d]: %s", i, m_argv[i]); + } +} \ No newline at end of file diff --git a/app/jaws/JawsCtrl/ProcService.h b/app/jaws/JawsCtrl/ProcService.h new file mode 100644 index 000000000..7ed85c8ae --- /dev/null +++ b/app/jaws/JawsCtrl/ProcService.h @@ -0,0 +1,14 @@ +#pragma once + +class CProcService +{ +public: + CProcService(void) : m_procName(NULL) {} + void Init(const char *procname); + virtual ~CProcService(void); + void DebugArgv(void); +public: + int m_argc; + char **m_argv; + char *m_procName; +}; diff --git a/app/jaws/JawsCtrl/ReadMe.txt b/app/jaws/JawsCtrl/ReadMe.txt new file mode 100644 index 000000000..b2ac3f433 --- /dev/null +++ b/app/jaws/JawsCtrl/ReadMe.txt @@ -0,0 +1,85 @@ +================================================================================ + MICROSOFT 基础类库: JawsCtrl 项目概述 +=============================================================================== + +应用程序向导已为您创建了此 JawsCtrl 应用程序。此应用程序 +不仅介绍了使用 Microsoft 基础类的基本知识, +而且是编写应用程序的起点。 + +此文件包含组成 JawsCtrl 应用程序的每个文件的内容摘要。 + +JawsCtrl.vcproj + 这是使用“应用程序向导”生成的 VC++ 项目的主项目文件。 + 它包含有关生成文件的 Visual C++ 版本的信息,以及 + 有关用“应用程序向导”所选择的平台、配置和 + 项目功能的信息。 + +JawsCtrl.h + 这是应用程序的主头文件。 它包含其他 + 项目特定的头文件(包括 Resource.h),并声明 + CJawsCtrlApp 应用程序类。 + +JawsCtrl.cpp + 这是包含应用程序 + 类 CJawsCtrlApp 的主应用程序源文件。 + +JawsCtrl.rc + 这是程序使用的所有 Microsoft Windows 资源 + 的列表。 它包含存储在 RES 子目录中 + 的图标、位图和光标。 可直接在 Microsoft + Visual C++ 中编辑此文件。 项目资源包含在 2052 中。 + +res\JawsCtrl.ico + 这是一个图标文件,用作应用程序的图标。 此 + 图标包含在主资源文件 JawsCtrl.rc 中。 + +res\JawsCtrl.rc2 + 此文件包含不由 Microsoft + Visual C++ 编辑的资源。 应将所有不能由 + 资源编辑器编辑的资源放在此文件中。 + +///////////////////////////////////////////////////////////////////////////// + +应用程序向导将创建一个对话框类: +JawsCtrlDlg.h、JawsCtrlDlg.cpp - 对话框 + 这些文件包含 CJawsCtrlDlg 类。 此类定义 + 应用程序主对话框的行为。 此对话框的模板包含在 + JawsCtrl.rc 中,而此文件可以在 Microsoft Visual C++ 中进行编辑。 +///////////////////////////////////////////////////////////////////////////// + +其他功能: + +ActiveX 控件 + 应用程序支持使用 ActiveX 控件。 + +Windows 套接字 + 应用程序支持在 TCP/IP 网络上建立通讯。 +///////////////////////////////////////////////////////////////////////////// + +其他标准文件: + +StdAfx.h、StdAfx.cpp + 这些文件用于生成名为 JawsCtrl.pch 的预编译头文件 (PCH) + 和名为 StdAfx.obj 的预编译类型文件。 + +Resource.h + 这是标准头文件,它定义新资源 ID。 + Microsoft Visual C++ 将读取并更新此文件。 + +///////////////////////////////////////////////////////////////////////////// + +其他说明: + +应用程序向导使用“TODO:” 来指示 +应添加或自定义的源代码部分。 + +如果应用程序在共享 DLL 中使用 MFC,且应用程序使用的语言不是 +操作系统的当前语言,则需要从 Microsoft Visual C++ 光盘上 +Win\System 目录下将相应的本地化资源 MFC70XXX.DLL +复制到计算机的 system 或 system32 目录下, +并将其重命名为 MFCLOC.DLL。 (“XXX”代表 +语言缩写。 例如,MFC70DEU.DLL 包含翻译成 +德语的资源。) 如果不这样做,应用程序的某些 UI 元素 +将保留为操作系统的语言。 + +///////////////////////////////////////////////////////////////////////////// diff --git a/app/jaws/JawsCtrl/Release/BuildLog.htm b/app/jaws/JawsCtrl/Release/BuildLog.htm new file mode 100644 index 000000000..708f0ddbe --- /dev/null +++ b/app/jaws/JawsCtrl/Release/BuildLog.htm @@ -0,0 +1,65 @@ + + + + + +
+
+生成日志 +
  
+

------- 已启动生成: 项目: JawsCtrl,配置: Release|Win32 ------- +

+
+命令行 +
  
正在创建临时文件“d:\工作目录\项目管理\jaws\jaws\JawsCtrl\Release\RSP00000F.rsp”,其内容为
+[
+/O2 /I "..\include\ctrl" /I "..\include\acl" /D "WIN32" /D "_WINDOWS" /D "NDEBUG" /D "ACL_DLL" /D "_AFXDLL" /D "_MBCS" /FD /EHsc /MD /GS /Zc:wchar_t /Yu"stdafx.h" /Fp"Release/JawsCtrl.pch" /Fo"Release/" /Fd"Release/vc70.pdb" /W3 /c /Wp64 /Zi /TP
+.\ProcService.cpp
+.\ProcCtrl.cpp
+.\ProcCtl.cpp
+.\JawsCtrlDlg.cpp
+.\JawsCtrl.cpp
+.\HttpService.cpp
+]
+正在创建命令行“cl.exe @d:\工作目录\项目管理\jaws\jaws\JawsCtrl\Release\RSP00000F.rsp /nologo”
+正在创建临时文件“d:\工作目录\项目管理\jaws\jaws\JawsCtrl\Release\RSP000010.rsp”,其内容为
+[
+/O2 /I "..\include\ctrl" /I "..\include\acl" /D "WIN32" /D "_WINDOWS" /D "NDEBUG" /D "ACL_DLL" /D "_AFXDLL" /D "_MBCS" /FD /EHsc /MD /GS /Zc:wchar_t /Yc"stdafx.h" /Fp"Release/JawsCtrl.pch" /Fo"Release/" /Fd"Release/vc70.pdb" /W3 /c /Wp64 /Zi /TP
+.\stdafx.cpp
+]
+正在创建命令行“cl.exe @d:\工作目录\项目管理\jaws\jaws\JawsCtrl\Release\RSP000010.rsp /nologo”
+正在创建命令行“rc.exe /d "NDEBUG" /d "_AFXDLL" /l 0x804 /I "Release" /fo"Release/JawsCtrl.res" .\JawsCtrl.rc”
+正在创建临时文件“d:\工作目录\项目管理\jaws\jaws\JawsCtrl\Release\RSP000011.rsp”,其内容为
+[
+/OUT:"../build/JawsCtrl.exe" /INCREMENTAL:NO /NOLOGO /LIBPATH:"..\lib\win32" /NODEFAULTLIB:"libcmt" /SUBSYSTEM:WINDOWS /OPT:REF /OPT:ICF /MACHINE:X86 lib_ctrl.lib lib_acl.lib .\lib_ctrl\Release\lib_ctrl.lib
+.\Release\HttpService.obj
+.\Release\JawsCtrl.obj
+.\Release\JawsCtrlDlg.obj
+.\Release\ProcCtl.obj
+.\Release\ProcCtrl.obj
+.\Release\ProcService.obj
+.\Release\stdafx.obj
+.\Release\JawsCtrl.res
+]
+正在创建命令行“link.exe @d:\工作目录\项目管理\jaws\jaws\JawsCtrl\Release\RSP000011.rsp”
+
+输出窗口 +
  
正在编译...
+stdafx.cpp
+正在编译...
+ProcService.cpp
+ProcCtrl.cpp
+ProcCtl.cpp
+JawsCtrlDlg.cpp
+JawsCtrl.cpp
+HttpService.cpp
+正在生成代码...
+正在编译资源...
+正在链接...
+LINK : warning LNK4089: /OPT:REF 已丢弃所有对“OLEAUT32.dll”的引用
+
+结果 +
  
+生成日志保存在“file://d:\工作目录\项目管理\jaws\jaws\JawsCtrl\Release\BuildLog.htm”中
+JawsCtrl - 0 错误,1 警告
+
\ No newline at end of file diff --git a/app/jaws/JawsCtrl/lib_ctrl/Debug/BuildLog.htm b/app/jaws/JawsCtrl/lib_ctrl/Debug/BuildLog.htm new file mode 100644 index 000000000..d70001cdb --- /dev/null +++ b/app/jaws/JawsCtrl/lib_ctrl/Debug/BuildLog.htm @@ -0,0 +1,90 @@ + + + + + +
+
+生成日志 +
  
+

------- 已启动生成: 项目: lib_ctrl,配置: Debug|Win32 ------- +

+
+命令行 +
  
正在创建临时文件“e:\work\projects\sourceforge\acl\trunk\app\jaws\JawsCtrl\lib_ctrl\Debug\RSP000001.rsp”,其内容为
+[
+/Od /D "WIN32" /D "_WINDOWS" /D "_DEBUG" /D "_AFXEXT" /D "_WINDLL" /D "_AFXDLL" /D "_MBCS" /Gm /EHsc /RTC1 /MDd /Zc:wchar_t /Yu"stdafx.h" /Fp"Debug/lib_ctrl.pch" /Fo"Debug/" /Fd"Debug/vc70.pdb" /W3 /c /Wp64 /ZI /TP
+.\TrayIcon.cpp
+.\SingleCtrl.cpp
+.\RegRun.cpp
+.\lib_ctrl.cpp
+.\DialogExpand.cpp
+]
+正在创建命令行“cl.exe @e:\work\projects\sourceforge\acl\trunk\app\jaws\JawsCtrl\lib_ctrl\Debug\RSP000001.rsp /nologo”
+正在创建临时文件“e:\work\projects\sourceforge\acl\trunk\app\jaws\JawsCtrl\lib_ctrl\Debug\RSP000002.rsp”,其内容为
+[
+/Od /D "WIN32" /D "_WINDOWS" /D "_DEBUG" /D "_AFXEXT" /D "_WINDLL" /D "_AFXDLL" /D "_MBCS" /Gm /EHsc /RTC1 /MDd /Zc:wchar_t /Yc"stdafx.h" /Fp"Debug/lib_ctrl.pch" /Fo"Debug/" /Fd"Debug/vc70.pdb" /W3 /c /Wp64 /ZI /TP
+.\stdafx.cpp
+]
+正在创建命令行“cl.exe @e:\work\projects\sourceforge\acl\trunk\app\jaws\JawsCtrl\lib_ctrl\Debug\RSP000002.rsp /nologo”
+正在创建命令行“rc.exe /d "_DEBUG" /d "_AFXDLL" /l 0x804 /I "Debug" /fo"Debug/lib_ctrl.res" .\lib_ctrl.rc”
+正在创建临时文件“e:\work\projects\sourceforge\acl\trunk\app\jaws\JawsCtrl\lib_ctrl\Debug\RSP000003.rsp”,其内容为
+[
+/OUT:"Debug/lib_ctrl.dll" /INCREMENTAL:NO /NOLOGO /DLL /DEF:".\lib_ctrl.def" /DEBUG /PDB:"Debug/lib_ctrl.pdb" /SUBSYSTEM:WINDOWS /IMPLIB:"Debug/lib_ctrl.lib" /MACHINE:X86
+.\Debug\DialogExpand.obj
+.\Debug\lib_ctrl.obj
+.\Debug\RegRun.obj
+.\Debug\SingleCtrl.obj
+.\Debug\stdafx.obj
+.\Debug\TrayIcon.obj
+.\Debug\lib_ctrl.res
+]
+正在创建命令行“link.exe @e:\work\projects\sourceforge\acl\trunk\app\jaws\JawsCtrl\lib_ctrl\Debug\RSP000003.rsp”
+正在创建临时文件“e:\work\projects\sourceforge\acl\trunk\app\jaws\JawsCtrl\lib_ctrl\Debug\BAT000004.bat”,其内容为
+[
+@echo off
+copy DialogExpand.h ..\..\include\ctrl /Y
+copy SingleCtrl.h ..\..\include\ctrl /Y
+copy TrayIcon.h ..\..\include\ctrl /Y
+copy RegRun.h ..\..\include\ctrl /Y
+copy Debug\lib_ctrl.dll ..\..\build\lib_ctrl.dll  /Y
+copy Debug\lib_ctrl.lib ..\..\lib\win32\lib_ctrl.lib  /Y
+
+if errorlevel 1 goto VCReportError
+goto VCEnd
+:VCReportError
+echo Project : error PRJ0019: 工具从"正在执行生成后事件..."
+exit 1
+:VCEnd
+]
+正在创建命令行“e:\work\projects\sourceforge\acl\trunk\app\jaws\JawsCtrl\lib_ctrl\Debug\BAT000004.bat”
+
+输出窗口 +
  
正在编译...
+stdafx.cpp
+正在编译...
+TrayIcon.cpp
+SingleCtrl.cpp
+RegRun.cpp
+lib_ctrl.cpp
+DialogExpand.cpp
+正在生成代码...
+正在编译资源...
+正在链接...
+LINK : warning LNK4075: 忽略“/EDITANDCONTINUE”(由于“/INCREMENTAL:NO”规范)
+   正在创建库 Debug/lib_ctrl.lib 和对象 Debug/lib_ctrl.exp
+正在执行生成后事件...
+已复制         1 个文件。
+已复制         1 个文件。
+已复制         1 个文件。
+已复制         1 个文件。
+已复制         1 个文件。
+系统找不到指定的路径。
+已复制         0 个文件。
+Project : error PRJ0019: 工具从"正在执行生成后事件..."
+
+结果 +
  
+生成日志保存在“file://e:\work\projects\sourceforge\acl\trunk\app\jaws\JawsCtrl\lib_ctrl\Debug\BuildLog.htm”中
+lib_ctrl - 1 错误,1 警告
+
\ No newline at end of file diff --git a/app/jaws/JawsCtrl/lib_ctrl/DialogExpand.cpp b/app/jaws/JawsCtrl/lib_ctrl/DialogExpand.cpp new file mode 100644 index 000000000..b468271d2 --- /dev/null +++ b/app/jaws/JawsCtrl/lib_ctrl/DialogExpand.cpp @@ -0,0 +1,123 @@ +#include "StdAfx.h" +#include ".\dialogexpand.h" + +CDialogExpand::CDialogExpand(void) +: m_pDialog(NULL) +, m_nResourceID(0) +, m_bVertical(FALSE) +{ + m_rcVerticalLarge.SetRectEmpty(); + m_rcHorizontalLarge.SetRectEmpty(); +} + +CDialogExpand::CDialogExpand(CDialog *pDialog, int nResourceID, BOOL bVertical) +: m_pDialog(pDialog) +, m_bVertical(FALSE) +{ + Init(pDialog, nResourceID, bVertical); +} + +CDialogExpand::~CDialogExpand(void) +{ +} + +void CDialogExpand::Init(CDialog *pDialog, int nResourceID, BOOL bVertical) +{ + ASSERT(pDialog); + ASSERT(nResourceID); + + m_pDialog = pDialog; + m_nResourceID = nResourceID; + m_bVertical = bVertical; + if (bVertical) { + CRect rcLandmark; + CWnd *pWndLandmark = m_pDialog->GetDlgItem(nResourceID); + ASSERT(pWndLandmark); + + m_pDialog->GetClientRect(m_rcVerticalLarge); + pWndLandmark->GetWindowRect(rcLandmark); + + m_rcVerticalSmall = m_rcVerticalLarge; + m_rcVerticalLarge.bottom += 32; + m_rcVerticalSmall.bottom = rcLandmark.top; + } else { + CRect rcLandmark; + CWnd *pWndLandmark = m_pDialog->GetDlgItem(nResourceID); + ASSERT(pWndLandmark); + + m_pDialog->GetClientRect(m_rcHorizontalLarge); + pWndLandmark->GetWindowRect(rcLandmark); + + m_rcHorizontalLarge.bottom += 32; + m_rcHorizontalSmall = m_rcHorizontalLarge; + //m_rcHorizontalLarge.right += 32; + m_rcHorizontalSmall.right = rcLandmark.left; + } +} + +void CDialogExpand::Expand(BOOL bExpand) +{ + if (m_bVertical) + VerticalExpand(bExpand); + else + HorizontalExpand(bExpand); +} + +void CDialogExpand::VerticalExpand(BOOL bExpand) +{ + if (bExpand) { + m_pDialog->SetWindowPos(NULL, 0, 0, m_rcVerticalLarge.Width(), + m_rcVerticalLarge.Height(), SWP_NOMOVE | SWP_NOZORDER); + EnableVisibleChildren(TRUE, m_rcVerticalSmall.Height()); + } else { + m_pDialog->SetWindowPos(NULL, 0, 0, m_rcVerticalSmall.Width(), + m_rcVerticalSmall.Height(), SWP_NOMOVE | SWP_NOZORDER); + EnableVisibleChildren(TRUE, m_rcVerticalSmall.Height()); + } +} + +void CDialogExpand::HorizontalExpand(BOOL bExpand) +{ + if (bExpand) { + m_pDialog->SetWindowPos(NULL, 0, 0, m_rcHorizontalLarge.Width(), + m_rcHorizontalLarge.Height(), SWP_NOMOVE | SWP_NOZORDER); + EnableVisibleChildren(FALSE, m_rcHorizontalSmall.Width()); + } else { + m_pDialog->SetWindowPos(NULL, 0, 0, m_rcHorizontalSmall.Width(), + m_rcHorizontalSmall.Height(), SWP_NOMOVE | SWP_NOZORDER); + EnableVisibleChildren(FALSE, m_rcHorizontalSmall.Width()); + } +} + +void CDialogExpand::EnableVisibleChildren(BOOL bVertical, int len) +{ + CWnd *pWndCtl = m_pDialog->GetWindow(GW_CHILD); + CRect rcTest; + CRect rcControl; + CRect rcShow; + CRect rcSmall; + + m_pDialog->GetWindowRect(rcShow); + rcSmall = rcShow; + + if (bVertical) { + if (rcSmall.Height() > len) + rcSmall.bottom -= rcSmall.Height() - len; + } else { + if (rcSmall.Width() > len) + rcSmall.right -= rcSmall.Width() - len; + } + + while (pWndCtl != NULL) { + pWndCtl->GetWindowRect(rcControl); + + if (!rcTest.IntersectRect(rcSmall, rcControl)) { + if (rcTest.IntersectRect(rcShow, rcControl)) + pWndCtl->EnableWindow(TRUE); + else + pWndCtl->EnableWindow(FALSE); + } + + pWndCtl = pWndCtl->GetWindow(GW_HWNDNEXT); + } +} diff --git a/app/jaws/JawsCtrl/lib_ctrl/DialogExpand.h b/app/jaws/JawsCtrl/lib_ctrl/DialogExpand.h new file mode 100644 index 000000000..d8bd64a15 --- /dev/null +++ b/app/jaws/JawsCtrl/lib_ctrl/DialogExpand.h @@ -0,0 +1,24 @@ +#pragma once + +class AFX_EXT_CLASS CDialogExpand +{ +public: + CDialogExpand(void); + CDialogExpand(CDialog *pDialog, int nResourceID, BOOL bVertical); + ~CDialogExpand(void); + + void Init(CDialog *pDialog, int nResourceID, BOOL bVertical); + void Expand(BOOL bExpand); +private: + BOOL m_bVertical; + int m_nResourceID; + CRect m_rcHorizontalLarge; + CRect m_rcHorizontalSmall; + CRect m_rcVerticalLarge; + CRect m_rcVerticalSmall; + CDialog *m_pDialog; + + void VerticalExpand(BOOL bExpand); + void HorizontalExpand(BOOL bExpand); + void EnableVisibleChildren(BOOL bVertical, int height); +}; diff --git a/app/jaws/JawsCtrl/lib_ctrl/ReadMe.txt b/app/jaws/JawsCtrl/lib_ctrl/ReadMe.txt new file mode 100644 index 000000000..96a863a20 --- /dev/null +++ b/app/jaws/JawsCtrl/lib_ctrl/ReadMe.txt @@ -0,0 +1,55 @@ +======================================================================== + MICROSOFT 基础类库 : lib_ctrl 项目概况 +======================================================================== + + +应用程序向导已为您创建了此 lib_ctrl DLL。此 DLL 不仅 +说明了使用 Microsoft 基础类的基础,而且 +也是编写 DLL 的起点。 + +此文件包含组成 lib_ctrl DLL +的每个文件的内容摘要。 + +lib_ctrl.vcproj + 这是用应用程序向导生成的 VC++ 项目的主项目文件。 + 它包含有关生成此文件的 Visual C++ 版本的信息,以及 + 有关使用应用程序向导选择的 + 平台、配置和项目功能的信息。 + +lib_ctrl.cpp + 这是包含 DllMain() + 定义的主 DLL 源文件。 +lib_ctrl.rc + 这是程序使用的所有 Microsoft Windows 资源的列表。 + 它包含存储在 RES 子目录下的图标、位图和光标。 + 此文件可在 Microsoft Visual C++ 中直接编辑。 + + +res\lib_ctrl.rc2 + 此文件包含不由 Microsoft + Visual C++ 编辑的资源。您应将不能由 + 资源编辑器编辑的所有资源放置在此文件中。 + +lib_ctrl.def + 此文件包含有关运行 Microsoft Windows + 所需的 DLL 的信息。 + 它定义此 DLL 的名称和说明等参数。 + 它还从此 DLL 导出函数。 + +///////////////////////////////////////////////////////////////////////////// +其他标准文件: + +StdAfx.h、StdAfx.cpp + 这些文件用于生成名为 lib_ctrl.pch + 的预编译头(PCH)文件以及名为 StdAfx.obj 的预编译类型文件。 + +Resource.h + 这是标准的头文件,它定义了新的资源 ID。 + Microsoft Visual C++ 读取和更新此文件。 + +///////////////////////////////////////////////////////////////////////////// +其他注释: + +应用程序向导使用 "TODO:" 注释指示应添加或自定义的源代码部分。 + +///////////////////////////////////////////////////////////////////////////// diff --git a/app/jaws/JawsCtrl/lib_ctrl/RegRun.cpp b/app/jaws/JawsCtrl/lib_ctrl/RegRun.cpp new file mode 100644 index 000000000..915c269d0 --- /dev/null +++ b/app/jaws/JawsCtrl/lib_ctrl/RegRun.cpp @@ -0,0 +1,83 @@ +#include "StdAfx.h" +#include ".\regrun.h" + +CRegRun::CRegRun(void) +: m_nErrno(ERROR_SUCCESS) +{ + +} + +CRegRun::CRegRun(const char *pRegName) +: m_sRegName(pRegName) +, m_nErrno(ERROR_SUCCESS) +{ +} + +CRegRun::~CRegRun(void) +{ +} + +void CRegRun::Init(const char *procname) +{ + m_nErrno = ERROR_SUCCESS; + m_sRegName.Format(procname); +} + +static char sKey[] = "Software\\Microsoft\\Windows\\CurrentVersion\\Run"; + +BOOL CRegRun::AutoRun(BOOL bAutoRun, const char *procname) +{ + CRegKey regRun; + int ret; + + if (bAutoRun) { + if (!IfAutoRun()) { + ret = regRun.Create(HKEY_LOCAL_MACHINE, sKey); + if (ret == ERROR_SUCCESS) { + regRun.SetStringValue(m_sRegName.GetString(), procname, REG_SZ); + regRun.Close(); + } else { + m_sErrMsg.Format("CRegKey::Create sKey(%s) error(%d)", sKey, ret); + m_nErrno = ret; + return FALSE; + } + } + } else { + ret = regRun.Open(HKEY_LOCAL_MACHINE, sKey, KEY_ALL_ACCESS); + if (ret == ERROR_SUCCESS) { + regRun.DeleteValue(m_sRegName.GetString()); + regRun.Close(); + } else { + m_sErrMsg.Format("CRegKey::Open sKey(%s) error(%d)", sKey, ret); + m_nErrno = ret; + return FALSE; + } + } + + return TRUE; +} + +BOOL CRegRun::IfAutoRun() +{ + CRegKey regRun; + int ret; + + ret = regRun.Open(HKEY_LOCAL_MACHINE, sKey, KEY_READ); + if (ret == ERROR_SUCCESS) { + char buf[256]; + DWORD dwCount, dwType; + + dwCount = sizeof(buf); + ret = regRun.QueryValue(m_sRegName.GetString(), &dwType, buf, &dwCount); + regRun.Close(); + if (ret == ERROR_SUCCESS) { + return TRUE; + } else { + return FALSE; + } + } else { + m_sErrMsg.Format("CRegKey::Open sKey(%s) error(%d)", sKey, ret); + m_nErrno = ret; + return FALSE; + } +} \ No newline at end of file diff --git a/app/jaws/JawsCtrl/lib_ctrl/RegRun.h b/app/jaws/JawsCtrl/lib_ctrl/RegRun.h new file mode 100644 index 000000000..836c9ebfb --- /dev/null +++ b/app/jaws/JawsCtrl/lib_ctrl/RegRun.h @@ -0,0 +1,20 @@ +#pragma once +#include + +class AFX_EXT_CLASS CRegRun +{ +public: + CRegRun(void); + CRegRun(const char *procname); + ~CRegRun(void); + void Init(const char *procname); + + BOOL AutoRun(BOOL bAutoRun, const char *procname); + BOOL IfAutoRun(void); + +public: + CString m_sErrMsg; + int m_nErrno; +private: + CString m_sRegName; +}; diff --git a/app/jaws/JawsCtrl/lib_ctrl/Release/BuildLog.htm b/app/jaws/JawsCtrl/lib_ctrl/Release/BuildLog.htm new file mode 100644 index 000000000..6edb11817 --- /dev/null +++ b/app/jaws/JawsCtrl/lib_ctrl/Release/BuildLog.htm @@ -0,0 +1,88 @@ + + + + + +
+
+生成日志 +
  
+

------- 已启动生成: 项目: lib_ctrl,配置: Release|Win32 ------- +

+
+命令行 +
  
正在创建临时文件“d:\工作目录\项目管理\jaws\jaws\JawsCtrl\lib_ctrl\Release\RSP000003.rsp”,其内容为
+[
+/O2 /D "WIN32" /D "_WINDOWS" /D "NDEBUG" /D "_AFXEXT" /D "_WINDLL" /D "_AFXDLL" /D "_MBCS" /FD /EHsc /MD /GS /Zc:wchar_t /Yu"stdafx.h" /Fp"Release/lib_ctrl.pch" /Fo"Release/" /Fd"Release/vc70.pdb" /W3 /c /Wp64 /Zi /TP
+.\TrayIcon.cpp
+.\SingleCtrl.cpp
+.\RegRun.cpp
+.\lib_ctrl.cpp
+.\DialogExpand.cpp
+]
+正在创建命令行“cl.exe @d:\工作目录\项目管理\jaws\jaws\JawsCtrl\lib_ctrl\Release\RSP000003.rsp /nologo”
+正在创建临时文件“d:\工作目录\项目管理\jaws\jaws\JawsCtrl\lib_ctrl\Release\RSP000004.rsp”,其内容为
+[
+/O2 /D "WIN32" /D "_WINDOWS" /D "NDEBUG" /D "_AFXEXT" /D "_WINDLL" /D "_AFXDLL" /D "_MBCS" /FD /EHsc /MD /GS /Zc:wchar_t /Yc"stdafx.h" /Fp"Release/lib_ctrl.pch" /Fo"Release/" /Fd"Release/vc70.pdb" /W3 /c /Wp64 /Zi /TP
+.\stdafx.cpp
+]
+正在创建命令行“cl.exe @d:\工作目录\项目管理\jaws\jaws\JawsCtrl\lib_ctrl\Release\RSP000004.rsp /nologo”
+正在创建命令行“rc.exe /d "NDEBUG" /d "_AFXDLL" /l 0x804 /I "Release" /fo"Release/lib_ctrl.res" .\lib_ctrl.rc”
+正在创建临时文件“d:\工作目录\项目管理\jaws\jaws\JawsCtrl\lib_ctrl\Release\RSP000005.rsp”,其内容为
+[
+/OUT:"Release/lib_ctrl.dll" /INCREMENTAL:NO /NOLOGO /DLL /DEF:".\lib_ctrl.def" /DEBUG /PDB:"Release/lib_ctrl.pdb" /SUBSYSTEM:WINDOWS /OPT:REF /OPT:ICF /IMPLIB:"Release/lib_ctrl.lib" /MACHINE:X86
+.\Release\DialogExpand.obj
+.\Release\lib_ctrl.obj
+.\Release\RegRun.obj
+.\Release\SingleCtrl.obj
+.\Release\stdafx.obj
+.\Release\TrayIcon.obj
+.\Release\lib_ctrl.res
+]
+正在创建命令行“link.exe @d:\工作目录\项目管理\jaws\jaws\JawsCtrl\lib_ctrl\Release\RSP000005.rsp”
+正在创建临时文件“d:\工作目录\项目管理\jaws\jaws\JawsCtrl\lib_ctrl\Release\BAT000006.bat”,其内容为
+[
+@echo off
+copy DialogExpand.h ..\..\include\ctrl /Y
+copy SingleCtrl.h ..\..\include\ctrl /Y
+copy TrayIcon.h ..\..\include\ctrl /Y
+copy RegRun.h ..\..\include\ctrl /Y
+copy Release\lib_ctrl.dll ..\..\build\lib_ctrl.dll  /Y
+copy Release\lib_ctrl.lib ..\..\lib\win32\lib_ctrl.lib  /Y
+
+if errorlevel 1 goto VCReportError
+goto VCEnd
+:VCReportError
+echo Project : error PRJ0019: 工具从"正在执行生成后事件..."
+exit 1
+:VCEnd
+]
+正在创建命令行“d:\工作目录\项目管理\jaws\jaws\JawsCtrl\lib_ctrl\Release\BAT000006.bat”
+
+输出窗口 +
  
正在编译...
+stdafx.cpp
+正在编译...
+TrayIcon.cpp
+SingleCtrl.cpp
+RegRun.cpp
+lib_ctrl.cpp
+DialogExpand.cpp
+正在生成代码...
+正在编译资源...
+正在链接...
+   正在创建库 Release/lib_ctrl.lib 和对象 Release/lib_ctrl.exp
+LINK : warning LNK4089: /OPT:REF 已丢弃所有对“OLEAUT32.dll”的引用
+正在执行生成后事件...
+已复制         1 个文件。
+已复制         1 个文件。
+已复制         1 个文件。
+已复制         1 个文件。
+已复制         1 个文件。
+已复制         1 个文件。
+
+结果 +
  
+生成日志保存在“file://d:\工作目录\项目管理\jaws\jaws\JawsCtrl\lib_ctrl\Release\BuildLog.htm”中
+lib_ctrl - 0 错误,1 警告
+
\ No newline at end of file diff --git a/app/jaws/JawsCtrl/lib_ctrl/Resource.h b/app/jaws/JawsCtrl/lib_ctrl/Resource.h new file mode 100644 index 000000000..c77357cdb --- /dev/null +++ b/app/jaws/JawsCtrl/lib_ctrl/Resource.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by lib_ctrl.RC +// + +// 新对象的下一些默认值 +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS + +#define _APS_NEXT_RESOURCE_VALUE 4000 +#define _APS_NEXT_CONTROL_VALUE 4000 +#define _APS_NEXT_SYMED_VALUE 4000 +#define _APS_NEXT_COMMAND_VALUE 32771 +#endif +#endif diff --git a/app/jaws/JawsCtrl/lib_ctrl/SingleCtrl.cpp b/app/jaws/JawsCtrl/lib_ctrl/SingleCtrl.cpp new file mode 100644 index 000000000..fb873ebf8 --- /dev/null +++ b/app/jaws/JawsCtrl/lib_ctrl/SingleCtrl.cpp @@ -0,0 +1,54 @@ +#include "stdafx.h" +#include "SingleCtrl.h" + +CSingleCtrl::CSingleCtrl(const char *pExeName) +{ + TRACE("%s\r\n", pExeName); + m_sExeName.Format("%s", pExeName); +} + +BOOL CSingleCtrl::Check() +{ + CWnd *pPrevWnd = CWnd::GetDesktopWindow()->GetWindow(GW_CHILD); + + ::CreateMutex(NULL, TRUE, m_sExeName.GetString()); + if (GetLastError() != ERROR_ALREADY_EXISTS) + return TRUE; + + while (pPrevWnd) + { + if (::GetProp(pPrevWnd->GetSafeHwnd(), m_sExeName.GetString())) + { + TRACE("Check: %s found\r\n", m_sExeName.GetString()); + if (pPrevWnd->IsIconic()) { + TRACE("Check: show it now\r\n"); + pPrevWnd->ShowWindow(SW_RESTORE); + } else + pPrevWnd->ShowWindow(SW_NORMAL); + pPrevWnd->SetForegroundWindow(); + pPrevWnd->GetLastActivePopup()->SetForegroundWindow(); + return FALSE; + } + + pPrevWnd = pPrevWnd->GetWindow(GW_HWNDNEXT); + } + + TRACE("Could not find previous instance main window!\r\n"); + return FALSE; +} + +void CSingleCtrl::Register() +{ + HWND hWnd = AfxGetApp()->m_pMainWnd->GetSafeHwnd(); + ASSERT(hWnd); + ::SetProp(hWnd, m_sExeName.GetString(), (HANDLE) 1); + TRACE("Register: %s\r\n", m_sExeName.GetString()); +} + +void CSingleCtrl::Remove() +{ + HWND hWnd = AfxGetApp()->m_pMainWnd->GetSafeHwnd(); + ASSERT(hWnd); + ::RemoveProp(hWnd, m_sExeName.GetString()); + TRACE("Remove: %s\r\n", m_sExeName.GetString()); +} \ No newline at end of file diff --git a/app/jaws/JawsCtrl/lib_ctrl/SingleCtrl.h b/app/jaws/JawsCtrl/lib_ctrl/SingleCtrl.h new file mode 100644 index 000000000..112ec7f9c --- /dev/null +++ b/app/jaws/JawsCtrl/lib_ctrl/SingleCtrl.h @@ -0,0 +1,19 @@ +#ifndef __SINGLECTRL_INCLUDE_H__ +#define __SINGLECTRL_INCLUDE_H__ + +class AFX_EXT_CLASS CSingleCtrl +{ +public: + CSingleCtrl(const char *pExeName); + ~CSingleCtrl() {}; + + BOOL Check(); + void Register(); + void Remove(); +protected: + CSingleCtrl() {}; +private: + CString m_sExeName; +}; + +#endif \ No newline at end of file diff --git a/app/jaws/JawsCtrl/lib_ctrl/TrayIcon.cpp b/app/jaws/JawsCtrl/lib_ctrl/TrayIcon.cpp new file mode 100644 index 000000000..37957ed79 --- /dev/null +++ b/app/jaws/JawsCtrl/lib_ctrl/TrayIcon.cpp @@ -0,0 +1,136 @@ +//////////////////////////////////////////////////////////////// +// If this code works, it was written by Paul DiLascia. +// If not, I don't know who wrote it. +// +#include "stdafx.h" +#include "TrayIcon.h" +#include // for AfxLoadString + +IMPLEMENT_DYNAMIC(CTrayIcon, CCmdTarget) + +CTrayIcon::CTrayIcon(UINT uID) +{ + // Initialize NOTIFYICONDATA + memset(&m_nid, 0 , sizeof(m_nid)); + m_nid.cbSize = sizeof(m_nid); + m_nid.uID = uID; // never changes after construction + + // Use resource string as tip if there is one + AfxLoadString(uID, m_nid.szTip, sizeof(m_nid.szTip)); +} + +CTrayIcon::~CTrayIcon() +{ + SetIcon(0); // remove icon from system tray +} + +////////////////// +// Set notification window. It must created already. +void CTrayIcon::SetNotificationWnd(CWnd* pNotifyWnd, UINT uCbMsg) +{ + // If the following assert fails, you're probably + // calling me before you created your window. Oops. + ASSERT(pNotifyWnd==NULL || ::IsWindow(pNotifyWnd->GetSafeHwnd())); + m_nid.hWnd = pNotifyWnd->GetSafeHwnd(); + + ASSERT(uCbMsg==0 || uCbMsg>=WM_USER); + m_nid.uCallbackMessage = uCbMsg; +} + +////////////////// +// This is the main variant for setting the icon. +// Sets both the icon and tooltip from resource ID +// To remove the icon, call SetIcon(0) +// +BOOL CTrayIcon::SetIcon(UINT uID) +{ + HICON hicon=NULL; + if (uID) { + AfxLoadString(uID, m_nid.szTip, sizeof(m_nid.szTip)); + hicon = AfxGetApp()->LoadIcon(uID); + } + return SetIcon(hicon, NULL); +} + +////////////////// +// Common SetIcon for all overloads. +// +BOOL CTrayIcon::SetIcon(HICON hicon, LPCSTR lpTip) +{ + UINT msg; + m_nid.uFlags = 0; + + // Set the icon + if (hicon) { + // Add or replace icon in system tray + msg = m_nid.hIcon ? NIM_MODIFY : NIM_ADD; + m_nid.hIcon = hicon; + m_nid.uFlags |= NIF_ICON; + } else { // remove icon from tray + if (m_nid.hIcon==NULL) + return TRUE; // already deleted + msg = NIM_DELETE; + } + + // Use the tip, if any + if (lpTip) + strncpy(m_nid.szTip, lpTip, sizeof(m_nid.szTip)); + if (m_nid.szTip[0]) + m_nid.uFlags |= NIF_TIP; + + // Use callback if any + if (m_nid.uCallbackMessage && m_nid.hWnd) + m_nid.uFlags |= NIF_MESSAGE; + + // Do it + BOOL bRet = Shell_NotifyIcon(msg, &m_nid); + if (msg==NIM_DELETE || !bRet) + m_nid.hIcon = NULL; // failed + return bRet; +} + +///////////////// +// Default event handler handles right-menu and doubleclick. +// Call this function from your own notification handler. +// +LRESULT CTrayIcon::OnTrayNotification(WPARAM wID, LPARAM lEvent) +{ + static LPCSTR MouseMessages[] = { "WM_MOUSEMOVE", + "WM_LBUTTONDOWN", "WM_LBUTTONUP", "WM_LBUTTONDBLCLK", + "WM_RBUTTONDOWN", "WM_RBUTTONUP", "WM_RBUTTONDBLCLK", + "WM_MBUTTONDOWN", "WM_MBUTTONUP", "WM_MBUTTONDBLCLK" }; + + if (wID!=m_nid.uID || (lEvent!=WM_RBUTTONUP && lEvent!=WM_LBUTTONDBLCLK)) + return 0; + + // If there's a resource menu with the same ID as the icon, use it as + // the right-button popup menu. CTrayIcon will interprets the first + // item in the menu as the default command for WM_LBUTTONDBLCLK + // + CMenu menu; + if (!menu.LoadMenu(m_nid.uID)) + return 0; + CMenu* pSubMenu = menu.GetSubMenu(0); + if (!pSubMenu) + return 0; + + if (lEvent==WM_RBUTTONUP) { + + // Make first menu item the default (bold font) + ::SetMenuDefaultItem(pSubMenu->m_hMenu, 0, TRUE); + + // Display the menu at the current mouse location. There's a "bug" + // (Microsoft calls it a feature) in Windows 95 that requires calling + // SetForegroundWindow. To find out more, search for Q135788 in MSDN. + // + CPoint mouse; + GetCursorPos(&mouse); + ::SetForegroundWindow(m_nid.hWnd); + ::TrackPopupMenu(pSubMenu->m_hMenu, 0, mouse.x, mouse.y, 0, + m_nid.hWnd, NULL); + + } else // double click: execute first menu item + ::SendMessage(m_nid.hWnd, WM_COMMAND, pSubMenu->GetMenuItemID(0), 0); + + return 1; // handled +} diff --git a/app/jaws/JawsCtrl/lib_ctrl/TrayIcon.h b/app/jaws/JawsCtrl/lib_ctrl/TrayIcon.h new file mode 100644 index 000000000..04a629beb --- /dev/null +++ b/app/jaws/JawsCtrl/lib_ctrl/TrayIcon.h @@ -0,0 +1,38 @@ +//////////////////////////////////////////////////////////////// +// CTrayIcon Copyright 1996 Microsoft Systems Journal. +// +// If this code works, it was written by Paul DiLascia. +// If not, I don't know who wrote it. + +#ifndef _TRAYICON_H +#define _TRAYICON_H + +//////////////// +// CTrayIcon manages an icon in the Windows 95 system tray. +// +class AFX_EXT_CLASS CTrayIcon : public CCmdTarget { +protected: + DECLARE_DYNAMIC(CTrayIcon) + NOTIFYICONDATA m_nid; // struct for Shell_NotifyIcon args + +public: + CTrayIcon(UINT uID); + ~CTrayIcon(); + + // Call this to receive tray notifications + void SetNotificationWnd(CWnd* pNotifyWnd, UINT uCbMsg); + + // SetIcon functions. To remove icon, call SetIcon(0) + // + BOOL SetIcon(UINT uID); // main variant you want to use + BOOL SetIcon(HICON hicon, LPCSTR lpTip); + BOOL SetIcon(LPCTSTR lpResName, LPCSTR lpTip) + { return SetIcon(lpResName ? + AfxGetApp()->LoadIcon(lpResName) : NULL, lpTip); } + BOOL SetStandardIcon(LPCTSTR lpszIconName, LPCSTR lpTip) + { return SetIcon(::LoadIcon(NULL, lpszIconName), lpTip); } + + virtual LRESULT OnTrayNotification(WPARAM uID, LPARAM lEvent); +}; + +#endif diff --git a/app/jaws/JawsCtrl/lib_ctrl/lib_ctrl.cpp b/app/jaws/JawsCtrl/lib_ctrl/lib_ctrl.cpp new file mode 100644 index 000000000..1368f8df3 --- /dev/null +++ b/app/jaws/JawsCtrl/lib_ctrl/lib_ctrl.cpp @@ -0,0 +1,50 @@ +// lib_ctrl.cpp : 定义 DLL 的初始化例程。 +// + +#include "stdafx.h" +#include + +#ifdef _DEBUG +#define new DEBUG_NEW +#endif + +static AFX_EXTENSION_MODULE lib_ctrlDLL = { NULL, NULL }; + +extern "C" int APIENTRY +DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) +{ + // 如果使用 lpReserved,请将此移除 + UNREFERENCED_PARAMETER(lpReserved); + + if (dwReason == DLL_PROCESS_ATTACH) + { + TRACE0("lib_ctrl.DLL 正在初始化!\n"); + + // 扩展 DLL 一次性初始化 + if (!AfxInitExtensionModule(lib_ctrlDLL, hInstance)) + return 0; + + // 将此 DLL 插入到资源链中 + // 注意: 如果此扩展 DLL 由 + // MFC 规则 DLL(如 ActiveX 控件)隐式链接到 + // 而不是由 MFC 应用程序链接到,则需要 + // 将此行从 DllMain 中移除并将其放置在一个 + // 从此扩展 DLL 导出的单独的函数中。使用此扩展 DLL 的 + // 规则 DLL 然后应显式 + // 调用该函数以初始化此扩展 DLL。否则, + // CDynLinkLibrary 对象不会附加到 + // 规则 DLL 的资源链,并将导致严重的 + // 问题。 + + new CDynLinkLibrary(lib_ctrlDLL); + + } + else if (dwReason == DLL_PROCESS_DETACH) + { + TRACE0("lib_ctrl.DLL 正在终止!\n"); + + // 在调用析构函数之前终止该库 + AfxTermExtensionModule(lib_ctrlDLL); + } + return 1; // 确定 +} diff --git a/app/jaws/JawsCtrl/lib_ctrl/lib_ctrl.def b/app/jaws/JawsCtrl/lib_ctrl/lib_ctrl.def new file mode 100644 index 000000000..5f80c6b60 --- /dev/null +++ b/app/jaws/JawsCtrl/lib_ctrl/lib_ctrl.def @@ -0,0 +1,6 @@ +; lib_ctrl.def : 声明 DLL 的模块参数。 + +LIBRARY "lib_ctrl" + +EXPORTS + ; 此处可以是显式导出 diff --git a/app/jaws/JawsCtrl/lib_ctrl/lib_ctrl.rc b/app/jaws/JawsCtrl/lib_ctrl/lib_ctrl.rc new file mode 100644 index 000000000..4fe02e9b7 --- /dev/null +++ b/app/jaws/JawsCtrl/lib_ctrl/lib_ctrl.rc @@ -0,0 +1,115 @@ +// Microsoft Visual C++ 生成的资源脚本。 +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// 从 TEXTINCLUDE 2 资源生成。 +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "#define _AFX_NO_SPLITTER_RESOURCES\r\n" + "#define _AFX_NO_OLE_RESOURCES\r\n" + "#define _AFX_NO_TRACKER_RESOURCES\r\n" + "#define _AFX_NO_PROPERTY_RESOURCES\r\n" + "\r\n" + "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)\r\n" + "LANGUAGE 4, 2\r\n" + "#pragma code_page(936)\r\n" + "#include ""res\\lib_ctrl.rc2"" // 不是由 Microsoft Visual C++ 编辑过的资源\r\n" + "#include ""afxres.rc"" // 标准组件\r\n" + "#endif\r\n" + "\0" +END + +///////////////////////////////////////////////////////////////////////////// +#endif // APSTUDIO_INVOKED + + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) +LANGUAGE 4, 2 +#pragma code_page(936) + +///////////////////////////////////////////////////////////////////////////// +// +// 版本 +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "080403a8" + BEGIN + VALUE "CompanyName", "TODO: <公司名>" + VALUE "FileDescription", "TODO: <文件说明>" + VALUE "FileVersion", "1.0.0.1" + VALUE "InternalName", "lib_ctrl.dll" + VALUE "LegalCopyright", "TODO: (C) <公司名>。保留所有权利。" + VALUE "OriginalFilename","lib_ctrl.dll" + VALUE "ProductName", "TODO: <产品名>" + VALUE "ProductVersion", "1.0.0.1" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0804, 936 + END +END + +#endif +#ifndef APSTUDIO_INVOKED + +///////////////////////////////////////////////////////////////////////////// +// +// 从 TEXTINCLUDE 3 资源生成。 +// +#define _AFX_NO_SPLITTER_RESOURCES +#define _AFX_NO_OLE_RESOURCES +#define _AFX_NO_TRACKER_RESOURCES +#define _AFX_NO_PROPERTY_RESOURCES + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) +LANGUAGE 4, 2 +#pragma code_page(936) +#include "res\\lib_ctrl.rc2" // 不是由 Microsoft Visual C++ 编辑过的资源 +#include "afxres.rc" // 标准组件 +#endif + +///////////////////////////////////////////////////////////////////////////// +#endif // 不是 APSTUDIO_INVOKED + diff --git a/app/jaws/JawsCtrl/lib_ctrl/lib_ctrl.vcproj b/app/jaws/JawsCtrl/lib_ctrl/lib_ctrl.vcproj new file mode 100644 index 000000000..af55bb3de --- /dev/null +++ b/app/jaws/JawsCtrl/lib_ctrl/lib_ctrl.vcproj @@ -0,0 +1,226 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/jaws/JawsCtrl/lib_ctrl/res/lib_ctrl.rc2 b/app/jaws/JawsCtrl/lib_ctrl/res/lib_ctrl.rc2 new file mode 100644 index 000000000..1ab57dd73 --- /dev/null +++ b/app/jaws/JawsCtrl/lib_ctrl/res/lib_ctrl.rc2 @@ -0,0 +1,13 @@ +// +// lib_ctrl.RC2 - Microsoft Visual C++ 不会直接编辑的资源 +// + +#ifdef APSTUDIO_INVOKED +#error this file is not editable by Microsoft Visual C++ +#endif //APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// 在此处添加手动编辑的资源... + +///////////////////////////////////////////////////////////////////////////// diff --git a/app/jaws/JawsCtrl/lib_ctrl/stdafx.cpp b/app/jaws/JawsCtrl/lib_ctrl/stdafx.cpp new file mode 100644 index 000000000..9ffeebcb4 --- /dev/null +++ b/app/jaws/JawsCtrl/lib_ctrl/stdafx.cpp @@ -0,0 +1,7 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// lib_ctrl.pch 将成为预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + + diff --git a/app/jaws/JawsCtrl/lib_ctrl/stdafx.h b/app/jaws/JawsCtrl/lib_ctrl/stdafx.h new file mode 100644 index 000000000..499f8362b --- /dev/null +++ b/app/jaws/JawsCtrl/lib_ctrl/stdafx.h @@ -0,0 +1,52 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是常用但不常更改的项目特定的包含文件 +// + +#pragma once + +#ifndef VC_EXTRALEAN +#define VC_EXTRALEAN // 从 Windows 头中排除极少使用的资料 +#endif + +// 如果您必须使用下列所指定的平台之前的平台,则修改下面的定义。 +// 有关不同平台的相应值的最新信息,请参考 MSDN。 +#ifndef WINVER // 允许使用特定于 Windows 95 和 Windows NT 4 或更高版本的功能。 +#define WINVER 0x0400 // 将此更改为针对于 Windows 98 和 Windows 2000 或更高版本的合适的值。 +#endif + +#ifndef _WIN32_WINNT // 允许使用特定于 Windows NT 4 或更高版本的功能。 +#define _WIN32_WINNT 0x0400 // 将此更改为针对于 Windows 2000 或更高版本的合适的值。 +#endif + +#ifndef _WIN32_WINDOWS // 允许使用特定于 Windows 98 或更高版本的功能。 +#define _WIN32_WINDOWS 0x0410 // 将此更改为针对于 Windows Me 或更高版本的合适的值。 +#endif + +#ifndef _WIN32_IE // 允许使用特定于 IE 4.0 或更高版本的功能。 +#define _WIN32_IE 0x0400 // 将此更改为针对于 IE 5.0 或更高版本的合适的值。 +#endif + +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // 某些 CString 构造函数将为显式的 + +#include // MFC 核心组件和标准组件 +#include // MFC 扩展 + +#ifndef _AFX_NO_OLE_SUPPORT +#include // MFC OLE 类 +#include // MFC OLE 对话框类 +#include // MFC 自动化类 +#endif // _AFX_NO_OLE_SUPPORT + +#ifndef _AFX_NO_DB_SUPPORT +#include // MFC ODBC 数据库类 +#endif // _AFX_NO_DB_SUPPORT + +#ifndef _AFX_NO_DAO_SUPPORT +#include // MFC DAO 数据库类 +#endif // _AFX_NO_DAO_SUPPORT + +#include // MFC 对 Internet Explorer 4 公共控件的支持 +#ifndef _AFX_NO_AFXCMN_SUPPORT +#include // MFC 对 Windows 公共控件的支持 +#endif // _AFX_NO_AFXCMN_SUPPORT + diff --git a/app/jaws/JawsCtrl/res/JawsCtrl.ico b/app/jaws/JawsCtrl/res/JawsCtrl.ico new file mode 100644 index 000000000..a9feccf6c Binary files /dev/null and b/app/jaws/JawsCtrl/res/JawsCtrl.ico differ diff --git a/app/jaws/JawsCtrl/res/JawsCtrl.manifest b/app/jaws/JawsCtrl/res/JawsCtrl.manifest new file mode 100644 index 000000000..3f04517da --- /dev/null +++ b/app/jaws/JawsCtrl/res/JawsCtrl.manifest @@ -0,0 +1,22 @@ + + + +鍦ㄦ璇存槑搴旂敤绋嬪簭 + + + + + + diff --git a/app/jaws/JawsCtrl/res/JawsCtrl.rc2 b/app/jaws/JawsCtrl/res/JawsCtrl.rc2 new file mode 100644 index 000000000..30cecb953 --- /dev/null +++ b/app/jaws/JawsCtrl/res/JawsCtrl.rc2 @@ -0,0 +1,13 @@ +// +// JawsCtrl.RC2 - Microsoft Visual C++ 不会直接编辑的资源 +// + +#ifdef APSTUDIO_INVOKED +#error 此文件不能由 Microsoft Visual C++ 编辑 +#endif //APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// 在此处添加手动编辑的资源... + +///////////////////////////////////////////////////////////////////////////// diff --git a/app/jaws/JawsCtrl/res/min_icon.ico b/app/jaws/JawsCtrl/res/min_icon.ico new file mode 100644 index 000000000..a9feccf6c Binary files /dev/null and b/app/jaws/JawsCtrl/res/min_icon.ico differ diff --git a/app/jaws/JawsCtrl/resource.h b/app/jaws/JawsCtrl/resource.h new file mode 100644 index 000000000..035775d4c --- /dev/null +++ b/app/jaws/JawsCtrl/resource.h @@ -0,0 +1,37 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by JawsCtrl.rc +// +#define IDM_ABOUTBOX 0x0010 +#define IDD_ABOUTBOX 100 +#define IDS_ABOUTBOX 101 +#define IDD_JAWSCTRL_DIALOG 102 +#define IDP_SOCKETS_INIT_FAILED 103 +#define IDR_MAINFRAME 128 +#define IDR_MENU_ICON 129 +#define IDI_MIN_ICON 130 +#define IDC_EDIT_PORT 1001 +#define IDC_IPADDRESS_LISTEN 1002 +#define IDC_BUTTON_START 1003 +#define IDC_BUTTON_STOP 1004 +#define IDC_RADIO_HTTPD 1005 +#define IDC_RADIO_HTTP_PROXY 1006 +#define IDC_BUTTON_QUIT 1007 +#define IDC_DIVIDER 1009 +#define IDC_MORE 1010 +#define IDC_DIVIDER_HOR 1011 +#define IDC__AUTO_RUN 1013 +#define IDC_AUTO_RUN 1013 +#define ID_OPEN_MAIN 32773 +#define ID_QUIT 32774 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 135 +#define _APS_NEXT_COMMAND_VALUE 32775 +#define _APS_NEXT_CONTROL_VALUE 1014 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/app/jaws/JawsCtrl/stdafx.cpp b/app/jaws/JawsCtrl/stdafx.cpp new file mode 100644 index 000000000..9021920cf --- /dev/null +++ b/app/jaws/JawsCtrl/stdafx.cpp @@ -0,0 +1,7 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// JawsCtrl.pch 将是预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + + diff --git a/app/jaws/JawsCtrl/stdafx.h b/app/jaws/JawsCtrl/stdafx.h new file mode 100644 index 000000000..70abd6390 --- /dev/null +++ b/app/jaws/JawsCtrl/stdafx.h @@ -0,0 +1,46 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是经常使用但不常更改的 +// 项目特定的包含文件 + +#pragma once + +#ifndef VC_EXTRALEAN +#define VC_EXTRALEAN // 从 Windows 标头中排除不常使用的资料 +#endif + +// 如果您必须使用下列所指定的平台之前的平台,则修改下面的定义。 +// 有关不同平台的相应值的最新信息,请参考 MSDN。 +#ifndef WINVER // 允许使用 Windows 95 和 Windows NT 4 或更高版本的特定功能。 +#define WINVER 0x0400 //为 Windows98 和 Windows 2000 及更新版本改变为适当的值。 +#endif + +#ifndef _WIN32_WINNT // 允许使用 Windows NT 4 或更高版本的特定功能。 +#define _WIN32_WINNT 0x0400 //为 Windows98 和 Windows 2000 及更新版本改变为适当的值。 +#endif + +#ifndef _WIN32_WINDOWS // 允许使用 Windows 98 或更高版本的特定功能。 +#define _WIN32_WINDOWS 0x0410 //为 Windows Me 及更新版本改变为适当的值。 +#endif + +#ifndef _WIN32_IE // 允许使用 IE 4.0 或更高版本的特定功能。 +#define _WIN32_IE 0x0400 //为 IE 5.0 及更新版本改变为适当的值。 +#endif + +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // 某些 CString 构造函数将是显式的 + +// 关闭 MFC 对某些常见但经常被安全忽略的警告消息的隐藏 +#define _AFX_ALL_WARNINGS + +#include // MFC 核心和标准组件 +#include // MFC 扩展 +#include // MFC 自动化类 + +#include // Internet Explorer 4 公共控件的 MFC 支持 +#ifndef _AFX_NO_AFXCMN_SUPPORT +#include // Windows 公共控件的 MFC 支持 +#endif // _AFX_NO_AFXCMN_SUPPORT + +#include // MFC 套接字扩展 +#include + +#define WM_MY_TRAY_NOTIFICATION WM_USER + 1 \ No newline at end of file diff --git a/app/jaws/Makefile b/app/jaws/Makefile new file mode 100644 index 000000000..48bd952d9 --- /dev/null +++ b/app/jaws/Makefile @@ -0,0 +1,17 @@ + +.PHONY = all clean + +all: + @(cd global; make) + @(cd master_main; make) + @(cd module; make) + @(cd plugin; make) + @(cd main; make) + @(cd tools; make) +clean: + @(cd global; make clean) + @(cd master_main; make clean) + @(cd module; make clean) + @(cd plugin; make clean) + @(cd main; make clean) + @(cd tools; make clean) diff --git a/app/jaws/Makefile.elib b/app/jaws/Makefile.elib new file mode 100644 index 000000000..bbd29f704 --- /dev/null +++ b/app/jaws/Makefile.elib @@ -0,0 +1,136 @@ +SHELL = /bin/sh +CC = gcc +#CC = g++ +AR = ar +ARFL = rv +RANLIB = ranlib + +CFLAGS = -c -g -W -Wall -Wcast-qual -Wcast-align \ +-Waggregate-return -Wmissing-prototypes \ +-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO \ +-Wno-long-long -DHAS_ELIG -DUSE_LIBCORE_LOG \ +-Wpointer-arith -Werror -Wshadow -O2 +#-Wpointer-arith -Werror -Wshadow -pedantic -O2 + +########################################################### +#Check system: +# Linux, SunOS, Solaris, BSD variants, AIX, HP-UX +SYSLIB = +RPATH = + +CHECKSYSRES = @echo "Unknow system type!";exit 1 +UNIXNAME = $(shell uname -sm) +OSTYPE = $(shell uname -p) + +#Path for Linux +ifeq ($(findstring Linux, $(UNIXNAME)), Linux) +# ifeq ($CC, "gcc") + ifeq ($(findstring i686, $(OSTYPE)), i686) + RPATH = linux32 + endif + ifeq ($(findstring x86_64, $(OSTYPE)), x86_64) + RPATH = linux64 + endif + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DLINUX2 + SYSLIB = -lcrypt -lpthread +endif + +#Path for SunOS +ifeq ($(findstring SunOS, $(UNIXNAME)), SunOS) + ifeq ($(findstring i386, $(OSTYPE)), i386) + RPATH = sunos_x86 + endif + ifeq ($(findstring 86, $(UNIXNAME)), 86) + SYSLIB = -lsocket -lnsl -lrt + endif + ifeq ($(findstring sun4u, $(UNIXNAME)), sun4u) + SYSLIB = -lsocket -lnsl -lrt + endif +# ifeq ($CC, "gcc") + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DSUNOS5 +endif + +#Path for HP-UX +ifeq ($(findstring HP-UX, $(UNIXNAME)), HP-UX) +# ifeq ($CC, "gcc") + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + SYSLIB = -lpthread + CFLAGS += -DHP_UX -DHPUX11 + PLAT_NAME=hp-ux +endif + +#Find system type. +ifneq ($(SYSPATH),) + CHECKSYSRES = @echo "System is $(shell uname -sm)" +endif +########################################################### +ELIG_PATH = /opt/import_lib/elib/$(RPATH) +GLIB_PATH = /opt/import_lib/glib/$(RPATH) + +ACL_PATH = ../lib_all/lib_acl +ACL_LIB = $(ACL_PATH)/lib/$(RPATH) +ACL_INC = $(ACL_PATH)/include + +PROTO_PATH = ../lib_all/lib_protocol +PROTO_LIB = $(PROTO_PATH)/lib/$(RPATH) +PROTO_INC = $(PROTO_PATH)/include + +LD_RUN_PATH=-Wl,-rpath,$(ELIG_PATH)/lib,-rpath,$(GLIB_PATH)/lib + +ALL_LIBS = -L$(PROTO_LIB) -l_http -L$(ACL_LIB) -l_acl \ + -L$(ELIG_PATH)/lib -l_elib \ + -L$(GLIB_PATH)/lib -lglib-2.0 \ + $(SYSLIB) + +INCLUDE = -I./http -I./global -I./util \ + -I$(PROTO_INC) \ + -I$(ACL_INC) \ + -I$(ELIG_PATH)/include \ + -I$(GLIB_PATH)/include/glib-2.0 -I$(GLIB_PATH)/lib/glib-2.0/include +CFLAGS += $(INCLUDE) + +OBJ_OUTPATH = ./debug + +#Project's objs +SOURCES = $(wildcard util/*.c) \ + $(wildcard http/*.c) \ + $(wildcard global/*.c) \ + $(wildcard master_main/*.c) +OBJS = $(patsubst %.c, $(OBJ_OUTPATH)/%.o, $(notdir $(SOURCES))) + +########################################################### + +PROG_NAME = jaws + +.PHONY = clean +COMPILE = $(CC) $(CFLAGS) + +all: RM $(PROG_NAME) + +RM: + rm -f $(PROG_NAME) + +$(PROG_NAME): $(OBJS) + $(CC) -o $(PROG_NAME) $(OBJS) $(LD_RUN_PATH) $(ALL_LIBS) + +$(OBJ_OUTPATH)/%.o: util/%.c + $(COMPILE) -o $@ $< +$(OBJ_OUTPATH)/%.o: global/%.c + $(COMPILE) -o $@ $< +$(OBJ_OUTPATH)/%.o: http/%.c + $(COMPILE) -o $@ $< +$(OBJ_OUTPATH)/%.o: master_main/%.c + $(COMPILE) -o $@ $< + +clean: + rm -f $(OBJS) $(PROG_NAME) + +rebuild: clean all diff --git a/app/jaws/Makefile.static b/app/jaws/Makefile.static new file mode 100644 index 000000000..f4fe11d7b --- /dev/null +++ b/app/jaws/Makefile.static @@ -0,0 +1,121 @@ +SHELL = /bin/sh +CC = gcc +#CC = g++ +AR = ar +ARFL = rv +RANLIB = ranlib + +CFLAGS = -c -g -W -Wall -Wcast-align \ +-Waggregate-return -Wmissing-prototypes \ +-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO \ +-Wno-long-long \ +-Wpointer-arith -Werror -Wshadow -pedantic -O3 \ +-fPIC -DJAWS_STATIC +#-Wcast-qual +########################################################### +#Check system: +# Linux, SunOS, Solaris, BSD variants, AIX, HP-UX +SYSLIB = -ldl +RPATH = + +CHECKSYSRES = @echo "Unknow system type!";exit 1 +UNIXNAME = $(shell uname -sm) +OSTYPE = $(shell uname -p) + +#Path for Linux +ifeq ($(findstring Linux, $(UNIXNAME)), Linux) +# ifeq ($CC, "gcc") + ifeq ($(findstring i686, $(OSTYPE)), i686) + RPATH = linux32 + endif + ifeq ($(findstring x86_64, $(OSTYPE)), x86_64) + RPATH = linux64 + endif + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DLINUX2 + SYSLIB += -lcrypt -lpthread +endif + +#Path for SunOS +ifeq ($(findstring SunOS, $(UNIXNAME)), SunOS) + ifeq ($(findstring i386, $(OSTYPE)), i386) + RPATH = sunos_x86 + endif + ifeq ($(findstring 86, $(UNIXNAME)), 86) + SYSLIB += -lsocket -lnsl -lrt + endif + ifeq ($(findstring sun4u, $(UNIXNAME)), sun4u) + SYSLIB += -lsocket -lnsl -lrt + endif +# ifeq ($CC, "gcc") + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DSUNOS5 +endif + +#Path for HP-UX +ifeq ($(findstring HP-UX, $(UNIXNAME)), HP-UX) +# ifeq ($CC, "gcc") + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + SYSLIB += -lpthread + CFLAGS += -DHP_UX -DHPUX11 + PLAT_NAME=hp-ux +endif + +#Find system type. +ifneq ($(SYSPATH),) + CHECKSYSRES = @echo "System is $(shell uname -sm)" +endif +########################################################### +ACL_PATH = . +ACL_LIB = $(ACL_PATH)/lib/$(RPATH) +ACL_INC = $(ACL_PATH)/include/acl + +PROTO_PATH = . +PROTO_LIB = $(PROTO_PATH)/lib/$(RPATH) +PROTO_INC = $(PROTO_PATH)/include/protocol + +ALL_LIBS = -L$(PROTO_LIB) -l_protocol -L$(ACL_LIB) -l_acl $(SYSLIB) + +INCLUDE = -I./module/mod_http -I./global -I$(PROTO_INC) -I$(ACL_INC) +CFLAGS += $(INCLUDE) -DHAVE_NO_STRCASESTR + +OBJ_OUTPATH = ./debug + +#Project's objs +SOURCES = $(wildcard ./global/*.c) \ + $(wildcard ./module/mod_http/*.c) \ + $(wildcard ./main/*.c) +OBJS = $(patsubst %.c, $(OBJ_OUTPATH)/%.o, $(notdir $(SOURCES))) + +########################################################### +NAME = jaws_static + +.PHONY = RM all clean +COMPILE = $(CC) $(CFLAGS) + +all: RM $(NAME) + +RM: + rm -f $(NAME) + +$(NAME): $(OBJS) + $(CC) -o $(NAME) $(OBJS) $(ALL_LIBS) + cp $(NAME) main/ + +$(OBJ_OUTPATH)/%.o: ./main/%.c + $(COMPILE) -o $@ $< +$(OBJ_OUTPATH)/%.o: ./global/%.c + $(COMPILE) -o $@ $< +$(OBJ_OUTPATH)/%.o: ./module/mod_http/%.c + $(COMPILE) -o $@ $< + +clean: + rm -f $(OBJS) $(NAME) + +rebuild: clean all diff --git a/app/jaws/Makefile.test b/app/jaws/Makefile.test new file mode 100644 index 000000000..6f298244d --- /dev/null +++ b/app/jaws/Makefile.test @@ -0,0 +1,127 @@ +SHELL = /bin/sh +CC = gcc +#CC = g++ +AR = ar +ARFL = rv +RANLIB = ranlib + +CFLAGS = -c -g -W -Wall -Wcast-qual -Wcast-align \ +-Waggregate-return -Wmissing-prototypes \ +-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO \ +-Wno-long-long \ +-Wpointer-arith -Werror -Wshadow -pedantic -O2 + +########################################################### +#Check system: +# Linux, SunOS, Solaris, BSD variants, AIX, HP-UX +SYSLIB = -ldl +RPATH = + +CHECKSYSRES = @echo "Unknow system type!";exit 1 +UNIXNAME = $(shell uname -sm) +OSTYPE = $(shell uname -p) + +#Path for Linux +ifeq ($(findstring Linux, $(UNIXNAME)), Linux) +# ifeq ($CC, "gcc") + ifeq ($(findstring i686, $(OSTYPE)), i686) + RPATH = linux32 + endif + ifeq ($(findstring x86_64, $(OSTYPE)), x86_64) + RPATH = linux64 + endif + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DLINUX2 + SYSLIB += -lcrypt -lpthread +endif + +#Path for SunOS +ifeq ($(findstring SunOS, $(UNIXNAME)), SunOS) + ifeq ($(findstring i386, $(OSTYPE)), i386) + RPATH = sunos_x86 + endif + ifeq ($(findstring 86, $(UNIXNAME)), 86) + SYSLIB += -lsocket -lnsl -lrt + endif + ifeq ($(findstring sun4u, $(UNIXNAME)), sun4u) + SYSLIB += -lsocket -lnsl -lrt + endif +# ifeq ($CC, "gcc") + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DSUNOS5 +endif + +#Path for HP-UX +ifeq ($(findstring HP-UX, $(UNIXNAME)), HP-UX) +# ifeq ($CC, "gcc") + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + SYSLIB += -lpthread + CFLAGS += -DHP_UX -DHPUX11 + PLAT_NAME=hp-ux +endif + +#Find system type. +ifneq ($(SYSPATH),) + CHECKSYSRES = @echo "System is $(shell uname -sm)" +endif +########################################################### +ACL_PATH = . +ACL_LIB = $(ACL_PATH)/lib/$(RPATH) +ACL_INC = $(ACL_PATH)/include/acl + +PROTO_PATH = . +PROTO_LIB = $(PROTO_PATH)/lib/$(RPATH) +PROTO_INC = $(PROTO_PATH)/include/protocol + +GLOBAL_PATH = ./global +GLOBAL_INC = $(GLOBAL_PATH) + +ALL_LIBS = -L$(PROTO_LIB) -l_protocol -L$(ACL_LIB) -l_acl $(SYSLIB) + +INCLUDE = -I$(GLOBAL_INC) -I$(PROTO_INC) -I$(ACL_INC) +CFLAGS += $(INCLUDE) -DHAVE_NO_STRCASESTR + +OBJ_OUTPATH = ./debug + +#Project's objs +SOURCES = $(wildcard ./global/*.c) $(wildcard ./moudle/mod_http/*.c) $(wildcard ./main_test/*.c) +OBJS = $(patsubst %.c, $(OBJ_OUTPATH)/%.o, $(notdir $(SOURCES))) + +########################################################### +DIST_PATH = ./dist/unix_setup/libexec/$(RPATH) +PROG_NAME = jaws + +.PHONY = RM all clean +COMPILE = $(CC) $(CFLAGS) + +all: RM $(PROG_NAME) + +RM: + rm -f $(PROG_NAME) + rm -f $(DIST_PATH)/$(PROG_NAME) + +PLUGIN: + @(cd plugin; make) + +$(PROG_NAME): $(OBJS) + $(CC) -o $(PROG_NAME) $(OBJS) $(LIB_NAME_PATH) $(ALL_LIBS) + cp $(PROG_NAME) $(DIST_PATH)/$(PROG_NAME) + +$(OBJ_OUTPATH)/%.o: ./global/%.c + $(COMPILE) -o $@ $< +$(OBJ_OUTPATH)/%.o: ./module/mod_http/%.c + $(COMPILE) -o $@ $< +$(OBJ_OUTPATH)/%.o: ./main_test/%.c + $(COMPILE) -o $@ $< + +clean: + rm -f $(OBJS) $(PROG_NAME) + rm -f $(DIST_PATH)/$(PROG_NAME) + +rebuild: clean all diff --git a/app/jaws/Release/BuildLog.htm b/app/jaws/Release/BuildLog.htm new file mode 100644 index 000000000..5bfdbcefc --- /dev/null +++ b/app/jaws/Release/BuildLog.htm @@ -0,0 +1,29 @@ + + + + + +
+
+生成日志 +
  
+

------- 已启动生成: 项目: jaws,配置: Release|Win32 ------- +

+
+命令行 +
  
正在创建临时文件“d:\工作目录\项目管理\jaws\jaws\Release\RSP00001A.rsp”,其内容为
+[
+/OUT:"build/jaws.exe" /INCREMENTAL:NO /NOLOGO /LIBPATH:"lib\win32" /SUBSYSTEM:CONSOLE /OPT:REF /OPT:ICF /MACHINE:X86 lib_global.lib lib_protocol.lib lib_acl.lib ws2_32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib
+.\Release\main.obj
+.\Release\jaws.res
+]
+正在创建命令行“link.exe @d:\工作目录\项目管理\jaws\jaws\Release\RSP00001A.rsp”
+
+输出窗口 +
  
正在链接...
+
+结果 +
  
+生成日志保存在“file://d:\工作目录\项目管理\jaws\jaws\Release\BuildLog.htm”中
+jaws - 0 错误,0 警告
+
\ No newline at end of file diff --git a/app/jaws/build/JawsCtrl.iss b/app/jaws/build/JawsCtrl.iss new file mode 100644 index 000000000..0dd206bb7 --- /dev/null +++ b/app/jaws/build/JawsCtrl.iss @@ -0,0 +1,56 @@ +; Script generated by the Inno Setup Script Wizard. +; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! + +[Setup] +; NOTE: The value of AppId uniquely identifies this application. +; Do not use the same AppId value in installers for other applications. +; (To generate a new GUID, click Tools | Generate GUID inside the IDE.) +AppId={{F6D742EB-A6D0-4205-A04E-F4396F83055B} +AppName=JawsCtrl +AppVerName=JawsCtrl(1.5) +AppPublisher=zsx. +AppPublisherURL=http://sourceforge.net/projects/acl-jaws/ +AppSupportURL=http://sourceforge.net/projects/acl-jaws/ +AppUpdatesURL=http://sourceforge.net/projects/acl-jaws/ +DefaultDirName={pf}\Acl Project +DefaultGroupName=Acl Project +AllowNoIcons=yes +OutputDir=..\dist\win32_setup +OutputBaseFilename=Jaws setup +SetupIconFile=.\jaws_icon.ico +Compression=lzma +SolidCompression=yes + +[Languages] +Name: "chinese"; MessagesFile: "compiler:Languages\Chinese.isl" + +[Tasks] +Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked +Name: "quicklaunchicon"; Description: "{cm:CreateQuickLaunchIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked + +[Files] +Source: ".\jaws_icon.ico"; DestDir: "{app}"; Flags: ignoreversion +Source: ".\mfc71.dll"; DestDir: "{app}"; Flags: ignoreversion +Source: ".\msvcr71.dll"; DestDir: "{app}"; Flags: ignoreversion +Source: ".\conf\*"; DestDir: "{app}\conf\"; Flags: ignoreversion recursesubdirs createallsubdirs +Source: ".\var"; DestDir: "{app}\var\"; Flags: ignoreversion recursesubdirs createallsubdirs +Source: ".\JawsCtrl.exe"; DestDir: "{app}"; Flags: ignoreversion +Source: ".\jaws.exe"; DestDir: "{app}"; Flags: ignoreversion +Source: ".\http_access.dll"; DestDir: "{app}"; Flags: ignoreversion +Source: ".\gbfilter.dll"; DestDir: "{app}"; Flags: ignoreversion +Source: ".\mod_http.dll"; DestDir: "{app}"; Flags: ignoreversion +Source: ".\lib_ctrl.dll"; DestDir: "{app}"; Flags: ignoreversion +Source: ".\lib_protocol.dll"; DestDir: "{app}"; Flags: ignoreversion +Source: ".\lib_acl.dll"; DestDir: "{app}"; Flags: ignoreversion +; NOTE: Don't use "Flags: ignoreversion" on any shared system files + +[Icons] +Name: "{group}\JawsCtrl"; Filename: "{app}\JawsCtrl.exe" +Name: "{group}\{cm:ProgramOnTheWeb,JawsCtrl}"; Filename: "http://sourceforge.net/projects/acl-jaws/" +Name: "{group}\{cm:UninstallProgram,JawsCtrl}"; Filename: "{uninstallexe}" +Name: "{commondesktop}\JawsCtrl"; Filename: "{app}\JawsCtrl.exe"; Tasks: desktopicon +Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\JawsCtrl"; Filename: "{app}\JawsCtrl.exe"; Tasks: quicklaunchicon + +[Run] +Filename: "{app}\JawsCtrl.exe"; Description: "{cm:LaunchProgram,JawsCtrl}"; Flags: nowait postinstall skipifsilent + diff --git a/app/jaws/build/conf/gbfilter.cf b/app/jaws/build/conf/gbfilter.cf new file mode 100644 index 000000000..ce95afd8d --- /dev/null +++ b/app/jaws/build/conf/gbfilter.cf @@ -0,0 +1,8 @@ +# configure + +service gbfilter { + debug_mem = 0 + logpath = ./var/gbfilter.log + data_clone = 0 + rewrite_enable = 1 +} diff --git a/app/jaws/build/conf/http.cf b/app/jaws/build/conf/http.cf new file mode 100644 index 000000000..1027a1dc5 --- /dev/null +++ b/app/jaws/build/conf/http.cf @@ -0,0 +1,37 @@ + +service http_mod { +############################################################################ +# 应用自己的配置选项 +# 是否调试内存分配情况 + debug_mem = 0 +# 每个客户端连接的空闲时间. +# client_idle_limit = 60 +## 与HTTP服务相关的配置项 +# http_filter_proxy = HTTP_FILTER_HTTPD + http_filter_proxy = HTTP_FILTER_PROXY +# 是否与客户端保持长连接 + http_client_keepalive = 1 +# 代理模式下,是否与服务端保持长连接 + http_server_keepalive = 1 + +# HTML错误模板存放目录 + http_tmpl_path = ./var/www/tmpl +# 虚拟主机配置文件存放目录 + http_vhost_path = ./conf/www/vhost +# 缺省域的配置文件名 + http_vhost_default = ./conf/www/default.cf + +# 外挂动态库集合 +# http_plugin_dlnames = /opt/jaws/plugin/cgi.so; /opt/jaws/plugin/gbfilter.so +# http_plugin_dlnames = /opt/jaws/plugin/cgi.so +# http_plugin_dlnames = /opt/jaws/plugin/gbfilter.so +# http_plugin_dlnames = /opt/jaws/plugin/gb_jt2ft.so +# http_plugin_dlnames = /opt/jaws/plugin/gb_jt2ft32.so + http_plugin_dlnames = ./http_access.dll; ./gbfilter.dll +# 外挂动态库的配置文件所在目录 + http_plugin_cfgdir = ./conf +# 与服务端的连接池的最大连接限制 + http_server_conn_limit = 1000 +# HTTP 通信过程中的缓冲区大小 + http_buf_size = 8192 +} diff --git a/app/jaws/build/conf/http_access.cf b/app/jaws/build/conf/http_access.cf new file mode 100644 index 000000000..69a7e14f8 --- /dev/null +++ b/app/jaws/build/conf/http_access.cf @@ -0,0 +1,6 @@ +service http_plugin_access { +# 以下域名列表是否允许访问 + http_domain_allow = hexun.com, hexun.com.tw +# 是否允许访问其它所有域名 + http_domain_allow_all = 1 +} diff --git a/app/jaws/build/conf/jaws.cf b/app/jaws/build/conf/jaws.cf new file mode 100644 index 000000000..38e51ea1d --- /dev/null +++ b/app/jaws/build/conf/jaws.cf @@ -0,0 +1,87 @@ + +service server { +# 进程是否禁止运行 + master_disable = no +# 服务地址及端口号 + master_service = 8283 +# 服务监听为域套接口 +# master_service = jaws.sock +# 服务类型 + master_type = inet +# master_type = unix +# 是否允许延迟接受客户端连接,如果为0则表示关闭该功能,如果大于0则表示打开此功能 +# 并且此值代表延迟接受连接的超时值,超过此值时如果客户端依然没有发来数据,则操作 +# 系统会在系统层直接关闭该连接 +# master_defer_accept = 0 +# 是否只允许私有访问, 如果为 y, 则域套接口创建在 /opt/jaws/var/log/private/ 目录下, +# 如果为 n, 则域套接口创建在 /opt/jaws/var/log/public/ 目录下, + master_private = n + master_unpriv = n +# 是否需要 chroot: n -- no, y -- yes + master_chroot = n +# 每隔多长时间触发一次,单位为秒(仅对 trigger 模式有效) + master_wakeup = - +# 最大进程数 + master_maxproc = 4 +# 进程程序名 + master_command = jaws +# 进程启动参数,只能为: -u [是否允许以某普通用户的身份运行] +# master_args = -u +# 传递给服务子进程的环境变量, 可以通过 getenv("SERVICE_ENV") 获得此值 +# master_env = mempool_limit:512000000, mempool_use_mutex:true +# master_env = logme:FALSE, priority:E_LOG_INFO, action:E_LOG_PER_DAY, flush:sync_flush, imit_size:512,\ +# sync_action:E_LOG_SEM, sem_name:/tmp/jaws.sem +# 进程日志记录文件 + master_log = ./var/jaws.log + +# 每个进程实例处理连接数的最大次数,超过此值后进程实例主动退出 + aio_use_limit = 0 +# 每个进程实例的空闲超时时间,超过此值后进程实例主动退出 + aio_idle_limit = 0 +# 记录进程PID的位置(对于多进程实例来说没有意义) + aio_pid_dir = ./var +# 进程运行时所在的路径 + aio_queue_dir = ./var +# 读写超时时间, 单位为秒 + aio_rw_timeout = 120 +# 读缓冲区的缓冲区大小 + aio_buf_size = 8192 +# 每次 accept 时的循环接收的最大次数 + aio_max_accept = 10 +# 进程运行时的用户身份 + aio_owner = nobody + +# 是否由单独的线程接受客户端连接 + aio_accept_alone = no +# 用 select 进行循环时的时间间隔 +# 单位为秒 + aio_delay_sec = 100 +# 单位为微秒 + aio_delay_usec = 5000 +# 采用事件循环的方式: select(default), poll, kernel(epoll/devpoll/kqueue) +# aio_event_mode = kernel + aio_event_mode = select +# 线程池的最大线程数, 如果该值为0则表示采用单线程非阻塞模式. +# aio_max_threads = 0 +# 每个线程的空闲时间. +# aio_thread_idle_limit = 60 + +# 允许访问的客户端IP地址范围 +# aio_access_allow = 202.99.16.0:202.99.16.255, 127.0.0.1:127.0.0.1, 10.0.250.0:10.0.250.255 + aio_access_allow = 0.0.0.0:255.255.255.255, 127.0.0.1:127.0.0.1 + +############################################################################ +# 应用自己的配置选项 + +# 每个客户端连接的空闲时间. +# client_idle_limit = 60 +# 是否输出当前的内存状态信息 + debug_mem = 0 +# 服务协议名称 + proto_name = http +# 需要动态加载的服务模块 + service_dlnames = ./mod_http.dll +# 动态加载的服务模块的配置文件所在路径 + service_cfgdir = ./conf + nthreads = 2 +} diff --git a/app/jaws/build/conf/www/default.cf b/app/jaws/build/conf/www/default.cf new file mode 100644 index 000000000..e3fbd1076 --- /dev/null +++ b/app/jaws/build/conf/www/default.cf @@ -0,0 +1,5 @@ +service test { + host = localhost + root_path = /opt/acl/var/www/htdocs/ +# vpath_map = / /opt/acl/var/www/htdocs/ 0 +} diff --git a/app/jaws/build/conf/www/vhost/test.cf b/app/jaws/build/conf/www/vhost/test.cf new file mode 100644 index 000000000..16ab4eb12 --- /dev/null +++ b/app/jaws/build/conf/www/vhost/test.cf @@ -0,0 +1,7 @@ +service test { + host = test.com.cn + root_path = /opt/acl/var/www/htdocs/test.domain/html/ + vpath_map = / /opt/acl/var/www/htdocs/test.domain/html/ 0 + vpath_map = /test2/ /opt/acl/var/www/htdocs/test.domain/test2/html/ 0 + vpath_map = /test3/ /opt/acl/var/www/htdocs/test.domain/test3/html/ 0 +} diff --git a/app/jaws/build/jaws_icon.ico b/app/jaws/build/jaws_icon.ico new file mode 100644 index 000000000..a9feccf6c Binary files /dev/null and b/app/jaws/build/jaws_icon.ico differ diff --git a/app/jaws/build/mfc71.dll b/app/jaws/build/mfc71.dll new file mode 100644 index 000000000..ebfbc3246 Binary files /dev/null and b/app/jaws/build/mfc71.dll differ diff --git a/app/jaws/build/msvcr71.dll b/app/jaws/build/msvcr71.dll new file mode 100644 index 000000000..9d9e0286c Binary files /dev/null and b/app/jaws/build/msvcr71.dll differ diff --git a/app/jaws/change.txt b/app/jaws/change.txt new file mode 100644 index 000000000..bfaf3696c --- /dev/null +++ b/app/jaws/change.txt @@ -0,0 +1,133 @@ + +37) 2010.3.5 +37.1) bugfix: jaws 动态加载 mod_http.so 时,在做DNS查询时可能会因为 +jaws 的运行空间与 mod_http.so 运行空间的不同而产生问题 +37.2) bugfix: 在win32下运行时,自动启动时 jaws 因为的运行路径问题而 +不能正常启动 + +36) 2010.2.25 +36.1) http_proxy.c: 增加了 Proxy-Connection 选项关闭功能 + +35) 2010.2.24 +35.1) 使用最新的 acl 库编译 + +34) 2010.2.8-2.9 +34.1) feature: 域名解析支持泛域名(即域名组)的动、静态解析功能 + +33) 2010.2.4 +33.1) 使用最新的 acl 库及 protocol 库编译 + +32) 2010.2.3 +32.1) 使用最新的 acl 库及 protocol 库编译 +32.2) http_proxy.c: fix some bugs + +31) 2010.1.25 +31.1) 使用最新的 acl 库及 protocol 库编译 + +30) 2010.1.24 +30.1) bugfix: http_proxy.c, http_client.c 修订了与过滤器相关的BUG + +29) 2010.1.22 +29.1) 增加了对 /etc/hosts 类型文件的支持,并且进行了扩展,可以支持 +"ip1;ip2;ip3 domain" 格式 +29.2) bugfix: http_client.c 在过滤器表示要接管连接请求时有一处内存越界 + +28) 2010.1.20 +28.1) 将 service_main.c 模块移至 global/ 目录 + +27) 2010.1.16-18 +27.1) 增加了直接发送DNS协议包进行DNS查询的功能 + +26) 2010.1.14 +26.1) http_proxy.c: 修订已知的几处 bugs + +25) 2010.1.10 +25.1) http_proxy.c: 修订了几处可能会产生问题的地方; 整理了一下代码 + +24) 2010.1.8 +24.1) bugfix: http_proxy.c 有一些设计上的问题,现在已经修复 + +23) 2010.1.7 +23.1) plugin/: 整理了一下模块划分及接口注释说明 + +22) 2010.1.6 +22.1) http_proxy.c: 修改了几处bugs + +21) 2010.1.1 +21.1) http_proxy.c: 整理了一些代码并修改了几处 bugs +20) 2009.12.30 +20.1) http_proxy.c 修订了几处可能出问题的 bugs + +19) 2009.12.16 +19.1) module/mod_http: http_proxy.c 整理了代码 +19.2) performance: 因为 acl_vstream.c 内部性能优化导致 acl_aio.c 的读性能 +大大提高,从而 mod_http 的代理大文件性能也大大提高 + +18) 2009.12.8 +18.1) 可以支持 win32 平台了 + +17) 2009.12.7 +17.1) mod_http.so: 修改了动态插件的初始化调用方式,以便于配合主程序在同一 +进程内可以同时启动多个线程实例 + +16) 2009.12.6 +16.1) 为了更好地支持在一个进程内启动多个非阻塞线程实例,调整了模块加载接口 + +15) 2009.12.5 +15.1) bugfix: http_proxy.c 中 http_proxy_complete() 因为原来对 +client_entry_detach() 的提前调用导致 http_client 被释放而后面又会有引用 +http_client 的地址,从而导致内存非法访问 +15.2) feature: Jaws 服务器可以在一个进程里同时启动多个线程实例,而每个 +线程实例又是一个单独的非阻塞服务器,从而可以更有效地利用多核 + +14) 2009.11.23 +14.1) 去掉了一些无用的文件及库 + +13) 2009.11.16-22 +13.1) 修复了一些BUG +13.2) http_proxy.c: 支持HTTP响应头随同响应体在一个 write 中发送,从而减少 +了一次系统IO次数 + +12) 2009.11.15 +12.1) 已经可以支持 cgi 程序了 + +11) 2009.11.14 +11.1) jaws 成为一个通用的非阻塞的服务框架,通过动态加载服务模块 +来提供服务; 因此,HTTP服务就做为一项单独的服务模块动态被 jaws 加载 + +10) 2009.11.12 +10.1) compile: LINUX64 平台下动态库增加编译参数 -fPIC + +9) 2009.11.11 +9.1) feature: 增加了HTTP响应数据体的过滤功能 +9.2) 重新整理了一些安装包 + +8) 2009.11.8 +8.1) features: linux 下支持动态加载过滤器库功能 + +7) 2009.11.6 +7.1) 在最新版的ACL库基础上进行了编译 + +6) 2009.3.9 +6.1) 在最新版的ACL库基础上进行了编译 + +5) 2009.1.23 +5.1) 在最新版的ACL库基础上进行了编译 +5.2) bug need to be fixed: 在请求对象首次建立后,如果在取得请求数据前 +关闭了,则有可能造成内存泄漏 + +4) 2008.10.7 +4.1) 去掉编译选项中的增加链接功能 + +3) 2008.10.6 +3.1) 整理了编译工程,将 acl】饧?protocol 库移至本工程中 +3.2) 将WIN32下的可执行程序生成目录重新调整了一下,创建了 build 目录 +及 dist/win32_setup 目录作为WIN32的生成目录;dist/unix_setup 为UNIX +的生成目录 + +2) 2008.10.4 +2.1) 将 lib_ctrl 形成 MFC 动态库 +2.2) 制做了安装包 + +1) 2008.9.17 +1.1) 0.1 version release diff --git a/app/jaws/clean.sh b/app/jaws/clean.sh new file mode 100644 index 000000000..876140780 --- /dev/null +++ b/app/jaws/clean.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +rm -f dist/unix_setup/libexec/linux64/jaws +rm -f dist/unix_setup/libexec/linux32/jaws +rm -f dist/unix_setup/module/linux64/*.so +rm -f dist/unix_setup/module/linux32/*.so +rm -f dist/unix_setup/plugin/linux64/*.so +rm -f dist/unix_setup/plugin/linux32/*.so diff --git a/app/jaws/copy.sh b/app/jaws/copy.sh new file mode 100644 index 000000000..d22a00f42 --- /dev/null +++ b/app/jaws/copy.sh @@ -0,0 +1,7 @@ +#!/bin/sh +make clean +make +cp master_main/jaws /opt/jaws/libexec/ +cp module/mod_http/mod_http.so /opt/jaws/module/ +cp plugin/cgi/cgi.so /opt/jaws/plugin/ +cp plugin/gbfilter/gbfilter.so /opt/jaws/plugin/ diff --git a/app/jaws/debug/BuildLog.htm b/app/jaws/debug/BuildLog.htm new file mode 100644 index 000000000..df6c792ec --- /dev/null +++ b/app/jaws/debug/BuildLog.htm @@ -0,0 +1,27 @@ + + + + + +
+
+生成日志 +
  
+

------- 已启动生成: 项目: jaws,配置: Debug|Win32 ------- +

+
+命令行 +
  
正在创建临时文件“d:\工作目录\项目管理\jaws\jaws\Debug\RSP0000AC.rsp”,其内容为
+[
+/Od /I ".\global" /I "include\protocol" /I "include\acl" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "ACL_DLL" /D "_MBCS" /Gm /EHsc /RTC1 /MTd /Fo"Debug/" /Fd"Debug/vc70.pdb" /W3 /c /Wp64 /ZI /TC
+.\main\service_main.c
+.\main\main.c
+]
+正在创建命令行“cl.exe @d:\工作目录\项目管理\jaws\jaws\Debug\RSP0000AC.rsp /nologo”
+正在编译...
+service_main.c
+main.c
+
+生成日志保存在“file://d:\工作目录\项目管理\jaws\jaws\Debug\BuildLog.htm”中
+jaws - 0 错误,0 警告
+
\ No newline at end of file diff --git a/app/jaws/dist/unix_setup/bin/.keep b/app/jaws/dist/unix_setup/bin/.keep new file mode 100644 index 000000000..533667ccd --- /dev/null +++ b/app/jaws/dist/unix_setup/bin/.keep @@ -0,0 +1,2 @@ +keepme + diff --git a/app/jaws/dist/unix_setup/conf/main.cf b/app/jaws/dist/unix_setup/conf/main.cf new file mode 100644 index 000000000..e0300233d --- /dev/null +++ b/app/jaws/dist/unix_setup/conf/main.cf @@ -0,0 +1,35 @@ + +#inet_interfaces = all +# 默认的每个服务的最大进程数 +default_process_limit = 250 +# 用户属主 +owner_user = root +master_owner = root +# 组主 +owner_group = root +# 如果子进程服务异常退出,重启该子进程服务的时间间隔(秒) +service_throttle_time = 60 +# 父进程进程名 +process_name = acl_master +#daemon_timeout = 18000 +buf_size = 81920 +# 父进程与子进程通信时的读写超时时间(秒) +rw_timeout = 60 +#max_use = 100 +#max_idle = 100 +#in_flow_delay = 1 +# 调用 select 循环时的等待秒级值 +event_delay_sec = 1 +# 调用 select 循环时的等待微秒级值 +event_delay_usec = 5000 +# 所有服务进程程序所在的目录 +daemon_directory = {install_path}/libexec +# acl_master 进程运行时的日志记录文件 +log_file = {install_path}/var/log/acl_master +# 所有服务进程的服务配置文件所在的目录 +service_directory = {install_path}/conf/service +queue_directory = {install_path}/var +# 记录 acl_master 运行时的进程号 +pid_file = {install_path}/var/pid/acl_master.pid +# 是否扫描并行 {install_path}/conf/service/ 目录下的子目录服务配置文件,0 -- 否,1 -- 是 +scan_subdir = 0 diff --git a/app/jaws/dist/unix_setup/conf/module/http.cf b/app/jaws/dist/unix_setup/conf/module/http.cf new file mode 100644 index 000000000..47604bf4b --- /dev/null +++ b/app/jaws/dist/unix_setup/conf/module/http.cf @@ -0,0 +1,34 @@ + +service http_mod { +############################################################################ +# 应用自己的配置选项 + +# 每个客户端连接的空闲时间. +# client_idle_limit = 60 +## 与HTTP服务相关的配置项 +# http_filter_proxy = HTTP_FILTER_HTTPD + http_filter_proxy = HTTP_FILTER_PROXY +# 是否与客户端保持长连接 + http_client_keepalive = 1 +# 代理模式下,是否与服务端保持长连接 + http_server_keepalive = 1 + +# HTML错误模板存放目录 + http_tmpl_path = {install_path}/var/www/tmpl +# 虚拟主机配置文件存放目录 + http_vhost_path = {install_path}/conf/www/vhost +# 缺省域的配置文件名 + http_vhost_default = {install_path}/conf/www/default.cf + +# 外挂动态库集合 +# http_plugin_dlnames = {install_path}/plugin/gbfilter.so; \ +# {install_path}/plugin/gbfilter.so +# 外挂动态库的配置文件所在目录 + http_plugin_cfgdir = {install_path}/conf/plugin + +# 与服务端的连接池的最大连接限制 + http_server_conn_limit = 1000 + +# HTTP 通信过程中的缓冲区大小 + http_buf_size = 8192 +} diff --git a/app/jaws/dist/unix_setup/conf/plugin/cgi.cf b/app/jaws/dist/unix_setup/conf/plugin/cgi.cf new file mode 100644 index 000000000..3e9bd77ba --- /dev/null +++ b/app/jaws/dist/unix_setup/conf/plugin/cgi.cf @@ -0,0 +1,8 @@ +# configure + +service http_cgi { + debug_mem = 0 + logpath = {install_path}/var/log/cgi.log + cgi-bin = {install_path}/www/cgi-bin + cgi-map = /cgi-bin/hello {install_path}/www/cgi-bin/hello.cgi +} diff --git a/app/jaws/dist/unix_setup/conf/plugin/gbfilter.cf b/app/jaws/dist/unix_setup/conf/plugin/gbfilter.cf new file mode 100644 index 000000000..40790955a --- /dev/null +++ b/app/jaws/dist/unix_setup/conf/plugin/gbfilter.cf @@ -0,0 +1,8 @@ +# configure + +service gbfilter { + debug_mem = 0 + logpath = {install_path}/var/log/gbfilter.log + data_clone = 0 + rewrite_enable = 1 +} diff --git a/app/jaws/dist/unix_setup/conf/plugin/http_access.cf b/app/jaws/dist/unix_setup/conf/plugin/http_access.cf new file mode 100644 index 000000000..123844921 --- /dev/null +++ b/app/jaws/dist/unix_setup/conf/plugin/http_access.cf @@ -0,0 +1,8 @@ +service http_plugin_access { +# 以下域名列表是否允许访问 + http_domain_allow = hexun.com, hexun.com.tw +# 域名重定向 + http_domain_redirect = hexun.tw=hexun.com.tw; test.tw=test.com.tw +# 是否允许访问其它所有域名 + http_domain_allow_all = 1 +} diff --git a/app/jaws/dist/unix_setup/conf/service/jaws.cf b/app/jaws/dist/unix_setup/conf/service/jaws.cf new file mode 100644 index 000000000..2afa98c06 --- /dev/null +++ b/app/jaws/dist/unix_setup/conf/service/jaws.cf @@ -0,0 +1,98 @@ + +service server { +# 进程是否禁止运行 + master_disable = no +# 服务地址及端口号 + master_service = 8283 +# 服务监听为域套接口 +# master_service = jaws.sock +# 服务类型 + master_type = inet +# master_type = unix +# 是否允许延迟接受客户端连接,如果为0则表示关闭该功能,如果大于0则表示打开此功能 +# 并且此值代表延迟接受连接的超时值,超过此值时如果客户端依然没有发来数据,则操作 +# 系统会在系统层直接关闭该连接 +# master_defer_accept = 0 +# 是否只允许私有访问, 如果为 y, 则域套接口创建在 {install_path}/var/log/private/ 目录下, +# 如果为 n, 则域套接口创建在 {install_path}/var/log/public/ 目录下, + master_private = n + master_unpriv = n +# 是否需要 chroot: n -- no, y -- yes + master_chroot = n +# 每隔多长时间触发一次,单位为秒(仅对 trigger 模式有效) + master_wakeup = - +# 最大进程数 + master_maxproc = 1 +# 进程程序名 + master_command = jaws +# 进程启动参数,只能为: -u [是否允许以某普通用户的身份运行] +# master_args = -u +# 传递给服务子进程的环境变量, 可以通过 getenv("SERVICE_ENV") 获得此值 +# master_env = mempool_limit:512000000, mempool_use_mutex:true +# master_env = logme:FALSE, priority:E_LOG_INFO, action:E_LOG_PER_DAY, flush:sync_flush, imit_size:512,\ +# sync_action:E_LOG_SEM, sem_name:/tmp/jaws.sem +# 是否启用内存池 +# master_env = use_slice:true, slice_base:8, nslice:1024, nalloc_gc:100000, \ +# slice_gc:gc2, rtgc_off:true +# 进程日志记录文件 + master_log = {install_path}/var/log/jaws.log + +# 每个进程实例处理连接数的最大次数,超过此值后进程实例主动退出 + aio_use_limit = 0 +# 每个进程实例的空闲超时时间,超过此值后进程实例主动退出 + aio_idle_limit = 0 +# 记录进程PID的位置(对于多进程实例来说没有意义) + aio_pid_dir = {install_path}/var/pid +# 进程运行时所在的路径 + aio_queue_dir = {install_path}/var/run +# 读写超时时间, 单位为秒 + aio_rw_timeout = 120 +# 读缓冲区的缓冲区大小 + aio_buf_size = 8192 +# 每次 accept 时的循环接收的最大次数 + aio_max_accept = 25 +# 进程运行时的用户身份 + aio_owner = nobody + +# 采用事件循环的方式: select(default), poll, kernel(epoll/devpoll/kqueue) + aio_event_mode = kernel +# 用 select 进行循环时的时间间隔 +# 单位为秒 + aio_delay_sec = 1 +# 单位为微秒 + aio_delay_usec = 10 + +# 线程池的最大线程数, 如果该值为0则表示采用单线程非阻塞模式. + aio_max_threads = 0 +# 每个线程的空闲时间. + aio_thread_idle_limit = 60 + +# 允许访问的客户端IP地址范围 +# aio_access_allow = 202.99.16.0:202.99.16.255, 127.0.0.1:127.0.0.1, 10.0.250.0:10.0.250.255 + aio_access_allow = 0.0.0.0:255.255.255.255, 127.0.0.1:127.0.0.1 + +############################################################################ +# 应用自己的配置选项 + +# 每个客户端连接的空闲时间. +# client_idle_limit = 60 +# 是否输出当前的内存状态信息 + debug_mem = 0 +# 服务协议名称 + proto_name = http +# 需要动态加载的服务模块 + service_dlnames = {install_path}/module/mod_http.so +# 动态加载的服务模块的配置文件所在路径 + service_cfgdir = {install_path}/conf/module +# 连接池的连接数限制 + http_server_conn_limit = 10240 +# 每个进程最多启动的线程个数 + nthreads = 1 +# 本机可以绑定的IP地址列表 +# bind_ip_list = 127.0.0.1, 10.0.251.93, 60.28.251.93 +# DNS服务器地址列表 +# dns_list = xxx.xxx.xxx.xxx:port, xxx.xxx.xxx.xxx:port + dns_list = 8.8.8.8:53 +# hosts_list 配置文件集合列表, 如:/etc/hosts, /etc/myhosts + hosts_list = /etc/hosts +} diff --git a/app/jaws/dist/unix_setup/conf/www/default.cf b/app/jaws/dist/unix_setup/conf/www/default.cf new file mode 100644 index 000000000..858da104d --- /dev/null +++ b/app/jaws/dist/unix_setup/conf/www/default.cf @@ -0,0 +1,5 @@ +service test { + host = localhost + root_path = {install_path}/www/htdocs/ +# vpath_map = / {install_path}/www/htdocs/ 0 +} diff --git a/app/jaws/dist/unix_setup/conf/www/vhost/test.cf b/app/jaws/dist/unix_setup/conf/www/vhost/test.cf new file mode 100644 index 000000000..b82408275 --- /dev/null +++ b/app/jaws/dist/unix_setup/conf/www/vhost/test.cf @@ -0,0 +1,7 @@ +service test { + host = test.com.cn + root_path = {install_path}/www/htdocs/test.domain/ + vpath_map = / {install_path}/www/htdocs/test.domain/ 0 +# vpath_map = /test2/ {install_path}/www/htdocs/test.domain/test2/ 0 +# vpath_map = /test3/ {install_path}/www/htdocs/test.domain/test3/ 0 +} diff --git a/app/jaws/dist/unix_setup/libexec/.keep b/app/jaws/dist/unix_setup/libexec/.keep new file mode 100644 index 000000000..533667ccd --- /dev/null +++ b/app/jaws/dist/unix_setup/libexec/.keep @@ -0,0 +1,2 @@ +keepme + diff --git a/app/jaws/dist/unix_setup/sbin/.keep b/app/jaws/dist/unix_setup/sbin/.keep new file mode 100644 index 000000000..533667ccd --- /dev/null +++ b/app/jaws/dist/unix_setup/sbin/.keep @@ -0,0 +1,2 @@ +keepme + diff --git a/app/jaws/dist/unix_setup/setup.sh b/app/jaws/dist/unix_setup/setup.sh new file mode 100644 index 000000000..73684940c --- /dev/null +++ b/app/jaws/dist/unix_setup/setup.sh @@ -0,0 +1,196 @@ +#!/bin/sh + +############################################################################### +PATH=/bin:/usr/bin:/usr/sbin:/usr/etc:/sbin:/etc +tempdir="/tmp" + +umask 022 + +censored_ls() { + ls "$@" | egrep -v '^\.|/\.|CVS|RCS|SCCS|linux\.d|solaris\.d|hp_ux\.d|example|service' +} + +compare_or_replace() { + (cmp $2 $3 >/dev/null 2>&1 && echo Skipping $3...) || { + echo Updating $3... + rm -f $tempdir/junk || exit 1 + cp $2 $tempdir/junk || exit 1 + chmod $1 $tempdir/junk || exit 1 + mv -f $tempdir/junk $3 || exit 1 + chmod $1 $3 || exit 1 + } +} +############################################################################### +RPATH= +guess_os() { + os_name=`uname -s` + os_type=`uname -p` + case $os_name in + Linux) + case $os_type in + x86_64) + RPATH="linux64" + ;; + i686) + RPATH="linux32" + ;; + *) + echo "unknown OS - $os_name $os_type" + exit 1 + ;; + esac + ;; + SunOS) + case $os_type in + i386) + RPATH="sunos_x86" + ;; + *) + echo "unknown OS - $os_name $os_type" + exit 1 + ;; + esac + ;; + *) + echo "unknown OS - $os_name $os_type" + exit 1 + ;; + esac +} + +create_path() +{ + test -d $1 || mkdir -p $1 || { + echo "can't mkdir $1" + exit 1 + } +} + +copy_file() +{ + for file in `censored_ls $2` + do + test -f $2/$file && { + compare_or_replace $1 $2/$file $3/$file || { + echo "copy file: $2/$file error" + exit 1 + } + } + done +} + +install_file() +{ + for file in `censored_ls $2` + do + rm -f $tempdir/junk2 || { + echo "can't remove file: $tempdir/junk2" + exit 1 + } + test -f $2/$file && { + cat $2/$file | sed -e 's;{install_path};'$INSTALL_PATH';;' >$tempdir/junk2 || { + echo "can't create file: $tempdir/junk2" + exit 1 + } + compare_or_replace $1 $tempdir/junk2 $3/$file || { + echo "can't move to file: $3/$file" + exit 1 + } + } + rm -f $tempdir/junk2 || { + echo "can't remove file: $tempdir/junk2" + exit 1 + } + done +} + +############################################################################### +INSTALL_PATH= + +if [ $# -lt 1 ] +then + echo "parameter not enougth($#)" + echo "usage:$0 install_path" + exit 1 +fi + +INSTALL_PATH=$1 + +case $INSTALL_PATH in +/*) ;; +no) ;; +*) echo Error: $INSTALL_PATH should be an absolute path name. 1>&2; exit 1;; +esac + +echo Installing to $INSTALL_PATH... + +BIN_PATH=$INSTALL_PATH/bin +SBIN_PATH=$INSTALL_PATH/sbin +CONF_PATH=$INSTALL_PATH/conf +SERVICE_PATH=$CONF_PATH/service +WWW_CONF=$CONF_PATH/www +MODULE_CONF=$CONF_PATH/module +PLUGIN_CONF=$CONF_PATH/plugin +LIBEXEC_PATH=$INSTALL_PATH/libexec +SH_PATH=$INSTALL_PATH/sh +VAR_PATH=$INSTALL_PATH/var +WWW_PATH=$INSTALL_PATH/www +MODULE_PATH=$INSTALL_PATH/module +PLUGIN_PATH=$INSTALL_PATH/plugin + +############################################################################### +create_all_path() +{ + create_path $INSTALL_PATH + create_path $BIN_PATH + create_path $SBIN_PATH + create_path $LIBEXEC_PATH + create_path $SH_PATH + create_path $CONF_PATH + create_path $SERVICE_PATH + + create_path $WWW_CONF + create_path $WWW_CONF/vhost + create_path $WWW_PATH + create_path $WWW_PATH/htdocs + create_path $WWW_PATH/htdocs/test.domain + create_path $VAR_PATH + create_path $VAR_PATH/log + create_path $VAR_PATH/pid + create_path $VAR_PATH/private + create_path $VAR_PATH/public + create_path $VAR_PATH/run + + create_path $MODULE_PATH + create_path $MODULE_CONF + + create_path $PLUGIN_PATH + create_path $PLUGIN_CONF + + chmod 700 $VAR_PATH/private + chmod 1777 $VAR_PATH/log + chmod 1777 $VAR_PATH/run +} + +copy_all_file() +{ + copy_file a+x,go+rx bin $BIN_PATH + copy_file a+x,go+rx sbin $SBIN_PATH + copy_file a+x,go+rx libexec/$RPATH $LIBEXEC_PATH + copy_file a+x,go+rx module/$RPATH $MODULE_PATH + copy_file a+x,go+rx plugin/$RPATH $PLUGIN_PATH + install_file a+x,go-wrx sh $SH_PATH + install_file a+x,go-wrx conf $CONF_PATH + install_file a+x,go-wrx conf/service $SERVICE_PATH + install_file a+x,go-wrx conf/www $WWW_CONF + install_file a+x,go-wrx conf/www/vhost $WWW_CONF/vhost + install_file a+x,go-wrx www $WWW_PATH/htdocs + install_file a+x,go-wrx conf/module $MODULE_CONF + install_file a+x,go-wrx conf/plugin $PLUGIN_CONF +} + +guess_os +create_all_path +copy_all_file + +############################################################################### diff --git a/app/jaws/dist/unix_setup/sh/start.sh b/app/jaws/dist/unix_setup/sh/start.sh new file mode 100644 index 000000000..05fa007fd --- /dev/null +++ b/app/jaws/dist/unix_setup/sh/start.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +HOME_PATH={install_path} +trap '' 1 + +ulimit -c 10240 +#$HOME_PATH/libexec/acl_master -v -c $HOME_PATH/conf -l $HOME_PATH/var/log/acl_master& +$HOME_PATH/libexec/acl_master -c $HOME_PATH/conf -l $HOME_PATH/var/log/acl_master& diff --git a/app/jaws/dist/unix_setup/sh/stop.sh b/app/jaws/dist/unix_setup/sh/stop.sh new file mode 100644 index 000000000..4bb9a06a1 --- /dev/null +++ b/app/jaws/dist/unix_setup/sh/stop.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +HOME_PATH={install_path} +PID_FILE=$HOME_PATH/var/pid/acl_master.pid +kill `sed 1q $PID_FILE` +rm -f $PID_FILE + diff --git a/app/jaws/dist/unix_setup/var/.keep b/app/jaws/dist/unix_setup/var/.keep new file mode 100644 index 000000000..533667ccd --- /dev/null +++ b/app/jaws/dist/unix_setup/var/.keep @@ -0,0 +1,2 @@ +keepme + diff --git a/app/jaws/dist/unix_setup/www/10k.html b/app/jaws/dist/unix_setup/www/10k.html new file mode 100644 index 000000000..fa60777b5 --- /dev/null +++ b/app/jaws/dist/unix_setup/www/10k.html @@ -0,0 +1,217 @@ + + +hello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html + + diff --git a/app/jaws/dist/unix_setup/www/128k.html b/app/jaws/dist/unix_setup/www/128k.html new file mode 100644 index 000000000..7f33a5870 --- /dev/null +++ b/app/jaws/dist/unix_setup/www/128k.html @@ -0,0 +1,2579 @@ +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +ello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html + +hello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +ello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html + +hello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +ello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html + +hello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html + +hello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html + +hello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html + +hello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html + +hello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html + +hello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html + +hello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html + + diff --git a/app/jaws/dist/unix_setup/www/20k.html b/app/jaws/dist/unix_setup/www/20k.html new file mode 100644 index 000000000..2bf3aede0 --- /dev/null +++ b/app/jaws/dist/unix_setup/www/20k.html @@ -0,0 +1,431 @@ + + +hello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html + +hello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html + + diff --git a/app/jaws/dist/unix_setup/www/256k.html b/app/jaws/dist/unix_setup/www/256k.html new file mode 100644 index 000000000..7cf6d8b9d --- /dev/null +++ b/app/jaws/dist/unix_setup/www/256k.html @@ -0,0 +1,5079 @@ +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html + +hello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +ello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html + +hello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +ello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html + +hello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +ello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html + +hello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +ello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html + +hello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +ello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html + +hello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +ello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html + +hello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +ello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html + +hello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +ello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html + +hello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html + +hello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html + +hello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html + +hello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html + +hello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html + +hello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html + +hello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html + + diff --git a/app/jaws/dist/unix_setup/www/4k.html b/app/jaws/dist/unix_setup/www/4k.html new file mode 100644 index 000000000..e3e17c4fa --- /dev/null +++ b/app/jaws/dist/unix_setup/www/4k.html @@ -0,0 +1,85 @@ + + +hello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html + + diff --git a/app/jaws/dist/unix_setup/www/500k.html b/app/jaws/dist/unix_setup/www/500k.html new file mode 100644 index 000000000..99b9c3e7a --- /dev/null +++ b/app/jaws/dist/unix_setup/www/500k.html @@ -0,0 +1,10079 @@ + + +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html + +hello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +ello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html + +hello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +ello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html + +hello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +ello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html + +hello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +ello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html + +hello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +ello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html + +hello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +ello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html + +hello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +ello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html + +hello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +ello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html + +hello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +ello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html + +hello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +ello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html + +hello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +ello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html + +hello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +ello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html + +hello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +ello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html + +hello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +ello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html + +hello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +ello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html + +hello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +ello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html + +hello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +ello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html + +hello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +ello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html + +hello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html + +hello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html + +hello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html + +hello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html + +hello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html + +hello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html + +hello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html + + diff --git a/app/jaws/dist/unix_setup/www/8k.html b/app/jaws/dist/unix_setup/www/8k.html new file mode 100644 index 000000000..7ce1d5ee1 --- /dev/null +++ b/app/jaws/dist/unix_setup/www/8k.html @@ -0,0 +1,165 @@ + + +hello world! +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.nowok.net/Music/065e7676db7ea057.shtml +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html +http://www.1ting.com/player/d3/player_103557.html + + diff --git a/app/jaws/dist/unix_setup/www/index.html b/app/jaws/dist/unix_setup/www/index.html new file mode 100644 index 000000000..a43f23ebe --- /dev/null +++ b/app/jaws/dist/unix_setup/www/index.html @@ -0,0 +1,5 @@ + + +hello world! + + diff --git a/app/jaws/global/Makefile b/app/jaws/global/Makefile new file mode 100644 index 000000000..63497518d --- /dev/null +++ b/app/jaws/global/Makefile @@ -0,0 +1,115 @@ +SHELL = /bin/sh +CC = gcc +#CC = g++ +AR = ar +ARFL = rv +RANLIB = ranlib + +CFLAGS = -c -g -W -Wall -Wcast-qual -Wcast-align \ +-Waggregate-return -Wmissing-prototypes \ +-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO \ +-Wno-long-long \ +-Wpointer-arith -Werror -Wshadow -pedantic -O3 \ +-fPIC + +########################################################### +#Check system: +# Linux, SunOS, Solaris, BSD variants, AIX, HP-UX +SYSLIB = -ldl +RPATH = + +CHECKSYSRES = @echo "Unknow system type!";exit 1 +UNIXNAME = $(shell uname -sm) +OSTYPE = $(shell uname -p) + +#Path for Linux +ifeq ($(findstring Linux, $(UNIXNAME)), Linux) +# ifeq ($CC, "gcc") + ifeq ($(findstring i686, $(OSTYPE)), i686) + RPATH = linux32 + endif + ifeq ($(findstring x86_64, $(OSTYPE)), x86_64) + RPATH = linux64 + endif + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DLINUX2 + SYSLIB += -lcrypt -lpthread +endif + +#Path for SunOS +ifeq ($(findstring SunOS, $(UNIXNAME)), SunOS) + ifeq ($(findstring i386, $(OSTYPE)), i386) + RPATH = sunos_x86 + endif + ifeq ($(findstring 86, $(UNIXNAME)), 86) + SYSLIB += -lsocket -lnsl -lrt + endif + ifeq ($(findstring sun4u, $(UNIXNAME)), sun4u) + SYSLIB += -lsocket -lnsl -lrt + endif +# ifeq ($CC, "gcc") + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DSUNOS5 +endif + +#Path for HP-UX +ifeq ($(findstring HP-UX, $(UNIXNAME)), HP-UX) +# ifeq ($CC, "gcc") + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + SYSLIB += -lpthread + CFLAGS += -DHP_UX -DHPUX11 + PLAT_NAME=hp-ux +endif + +#Find system type. +ifneq ($(SYSPATH),) + CHECKSYSRES = @echo "System is $(shell uname -sm)" +endif +########################################################### +ACL_PATH = ../../../lib_acl +ACL_LIB = $(ACL_PATH)/lib +ACL_INC = $(ACL_PATH)/include + +PROTO_PATH = ../../../lib_protocol +PROTO_LIB = $(PROTO_PATH)/lib +PROTO_INC = $(PROTO_PATH)/include + +ALL_LIBS = -L$(PROTO_LIB) -l_protocol -L$(ACL_LIB) -l_acl $(SYSLIB) + +INCLUDE = -I. -I$(PROTO_INC) -I$(ACL_INC) +CFLAGS += $(INCLUDE) -DHAVE_NO_STRCASESTR + +OBJ_OUTPATH = ./debug + +#Project's objs +SOURCES = $(wildcard ./*.c) +OBJS = $(patsubst %.c, $(OBJ_OUTPATH)/%.o, $(notdir $(SOURCES))) + +########################################################### +LIB_NAME = lib_global.a + +.PHONY = RM all clean +COMPILE = $(CC) $(CFLAGS) + +all: RM $(LIB_NAME) + +RM: + rm -f $(LIB_NAME) + +$(LIB_NAME): $(OBJS) + $(AR) $(ARFL) $(LIB_NAME) $(OBJS) + $(RANLIB) $(LIB_NAME) + +$(OBJ_OUTPATH)/%.o: ./%.c + $(COMPILE) -o $@ $< + +clean: + rm -f $(OBJS) $(LIB_NAME) + +rebuild: clean all diff --git a/app/jaws/global/client_entry.c b/app/jaws/global/client_entry.c new file mode 100644 index 000000000..9ddc7c124 --- /dev/null +++ b/app/jaws/global/client_entry.c @@ -0,0 +1,145 @@ +#include "lib_acl.h" +#include "service.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +void client_entry_free(CLIENT_ENTRY *entry) +{ + acl_myfree(entry); +} + +/* 当客户端异步流被关闭时的回调函数 */ + +static void onclose_client_stream(ACL_VSTREAM *stream, void *arg) +{ + const char *myname = "onclose_client_stream"; + CLIENT_ENTRY *entry = (CLIENT_ENTRY*) arg; + + acl_msg_info("%s(%d), fd: %d, nrefer: %d, nrefer: %d, addr: %lx, %lx, domain(%s)", + __FUNCTION__, __LINE__, ACL_VSTREAM_SOCK(stream), + stream->nrefer, entry->nrefer, + (long) entry, (long) entry->client, entry->domain_key); + + if (stream->nrefer != 0) + acl_msg_fatal("%s: stream->nrefer(%d) != 0", myname, stream->nrefer); + + /* 需要提前设置为空, 以防在调用 acl_aio_iocp_close 后又要操作该流指针 */ + entry->client = NULL; + + if (entry->server) + acl_aio_iocp_close(entry->server); + + /* 需要放在 acl_aio_iocp_lose() 后面,以防止 entry 对象提前释放 */ + entry->nrefer--; + if (entry->nrefer > 0) + return; + if (entry->server != NULL) + acl_msg_fatal("%s(%d): server not null", myname, __LINE__); + + entry->free_fn(entry); +} + +CLIENT_ENTRY *client_entry_new(SERVICE *service, size_t size, ACL_ASTREAM *client) +{ + const char *myname = "client_entry_new"; + CLIENT_ENTRY *entry; + ACL_VSTREAM *stream; + + if (size < sizeof(CLIENT_ENTRY)) + acl_msg_fatal("%s(%d): size(%d) invalid", myname, __LINE__, size); + + entry = (CLIENT_ENTRY* ) acl_mycalloc(1, size); + entry->service = service; + + entry->client = client; + entry->nrefer++; + + stream = acl_aio_vstream(client); + acl_vstream_add_close_handle(stream, onclose_client_stream, entry); + + return (entry); +} + +/* 当服务端异步流被关闭时的回调函数 */ + +static void onclose_server_stream(ACL_VSTREAM *stream, void *arg) +{ + const char *myname = "onclose_server_stream"; + CLIENT_ENTRY *entry = (CLIENT_ENTRY*) arg; + + acl_msg_info("%s(%d), nrefer: %d", __FUNCTION__, __LINE__, stream->nrefer); + + if (stream->nrefer != 0) + acl_msg_fatal("%s: stream->nrefer(%d) != 0", myname, stream->nrefer); + + /* 需要提前设置为空, 以防在调用 acl_aio_iocp_close 后又要操作该流指针 */ + entry->server = NULL; + + if (entry->client) { + acl_aio_iocp_close(entry->client); + } + + /* 需要放在 acl_aio_iocp_lose() 后面,以防止 entry 对象提前释放 */ + entry->nrefer--; + if (entry->nrefer > 0) + return; + if (entry->client != NULL) + acl_msg_fatal("%s(%d): client not null", myname, __LINE__); + + entry->free_fn(entry); +} + +void client_entry_set_server(CLIENT_ENTRY *entry, ACL_ASTREAM *server) +{ + const char *myname = "client_entry_set_server"; + ACL_VSTREAM *stream; + + if (entry->server != NULL) + acl_msg_fatal("%s(%d): entry->server not null", myname, __LINE__); + entry->server = server; + entry->nrefer++; + stream = acl_aio_vstream(server); + acl_vstream_add_close_handle(stream, onclose_server_stream, entry); +} + +int client_entry_detach(CLIENT_ENTRY *entry, ACL_VSTREAM *stream) +{ + return (client_entry_detach3(entry, stream, 1)); +} + +int client_entry_detach3(CLIENT_ENTRY *entry, ACL_VSTREAM *stream, int auto_free) +{ + const char *myname = "client_entry_detach"; + + /* 必须取消在关闭流时的回调函数 */ + if (entry->client && acl_aio_vstream(entry->client) == stream) { + /* 删除流的关闭回调函数句柄,这样仅清除与该应用相关的删除回调 */ + acl_vstream_delete_close_handle(stream, onclose_client_stream, entry); + entry->client = NULL; + entry->nrefer--; + } else if (entry->server && acl_aio_vstream(entry->server) == stream) { + /* 删除流的关闭回调函数句柄,这样仅清除与该应用相关的删除回调 */ + acl_vstream_delete_close_handle(stream, onclose_server_stream, entry); + entry->server = NULL; + entry->nrefer--; + } else { + acl_msg_fatal("%s(%d): unknown stream", myname, __LINE__); + } + + /* 如果 entry 引用对象计数为0则需要释放掉该对象 */ + if (entry->nrefer == 0) { + if (auto_free) + entry->free_fn(entry); + /* 告诉调用者, entry 资源已经被释放,不能再使用 */ + return (1); + } else if (entry->client == NULL && entry->server == NULL) { + acl_msg_warn("%s(%d): nrefer=%d, client %s, server %s\n", + myname, __LINE__, entry->nrefer, + entry->client ? "not null" : "null", + entry->server ? "not null" : "null"); + } + + return (0); +} diff --git a/app/jaws/global/conn_cache.c b/app/jaws/global/conn_cache.c new file mode 100644 index 000000000..b0cd98935 --- /dev/null +++ b/app/jaws/global/conn_cache.c @@ -0,0 +1,340 @@ +#include "lib_acl.h" +#include "conn_cache.h" + +/* 对应某个 IP:PORT 键值的连接池结构类型定义 */ + +typedef struct CONN_POOL { + CONN_CACHE *conn_cache; /* 所从属的某个连接池缓存对象 */ + ACL_AIO *aio; /* 该连接池所从属的异步IO对象 */ + ACL_FIFO conns; /* 该连接池中的连接对象(CONN)队列 */ + char key[256]; /* 该连接池对象所对应的存储于连接池缓存中的存储键 */ +} CONN_POOL; + +/* 连接池中的某个连接对象类型定义 */ + +struct CONN { + CONN_POOL *conn_pool; /* 所从属的的连接池对象 */ + ACL_ASTREAM *stream; /* 该连接的异步流对象 */ + void (*free_fn)(ACL_ASTREAM *stream, void*); /* 释放该连接时的回调函数 */ + void *ctx; /* free_fn 对参数之一 */ + ACL_FIFO_INFO *info; /* 该连接对象存储于连接池(conn_pool)的队列中的对象指针 */ +}; + +/* 仅释放连接对象所占用的内存,但并不关闭连接流 */ + +static void conn_free(CONN *conn) +{ + CONN_POOL *conns = conn->conn_pool; + + /* 先从连接池队列中删除 */ + if (conn->info) + acl_fifo_delete_info(&conns->conns, conn->info); + /* 调用用户自定义回调函数 */ + if (conn->free_fn) + conn->free_fn(conn->stream, conn->ctx); + /* 释放内存空间 */ + acl_myfree(conn); +} + +/* 释放连接对象并关闭连接流 */ + +static void conn_close(CONN *conn) +{ + /* 必须首先禁止异步流的读监听 */ + acl_aio_disable_read(conn->stream); + + /* 异步关闭该连接, 然后由异步框架自动触发 read_close_callback */ + acl_aio_iocp_close(conn->stream); +} + +/* 当连接池对象被释放时调用此回调函数 */ + +static void conn_pool_free(CONN_POOL *conns) +{ + CONN *conn; + + /* 需要把连接池中的所有连接都释放 */ + + while ((conn = acl_fifo_pop(&conns->conns)) != NULL) { + if (conn->stream) { + if (conn->free_fn) + conn->free_fn(conn->stream, conn->ctx); + acl_aio_clean_hooks(conn->stream); + acl_aio_iocp_close(conn->stream); + } + acl_myfree(conn); + } + acl_myfree(conns); +} + +/* 释放连接池定时器回调函数 */ + +static void conn_pool_free_timer(int event_type acl_unused, void *context) +{ + CONN_POOL *conns = (CONN_POOL*) context; + + conn_pool_free(conns); +} + +/* 设置释放连接池的定时器, 之所以采用定时器来释放连接池对象是为了 + * 使释放过程不在事务的递归处理过程中被提前释放 + */ + +static void set_conn_pool_free_timer(CONN_POOL *conns) +{ + acl_aio_request_timer(conns->aio, conn_pool_free_timer, conns, 1); +} + +static void conn_pool_stat_timer(int event_type acl_unused, void *context) +{ + const char *myname = "conn_pool_stat_timer"; + CONN_CACHE *cache = (CONN_CACHE*) context; + + /* only for test */ + if (0) + acl_msg_info("%s(%d): nset: %d, nget: %d, nclose: %d, inter: %d", + myname, __LINE__, cache->nset, cache->nget, + cache->nclose, cache->nset - cache->nget - cache->nclose); + + /* 再次设置定时器 */ + acl_aio_request_timer(cache->aio, conn_pool_stat_timer, cache, 2); +} + +static void set_conn_pool_stat_timer(CONN_CACHE *cache) +{ + /* 设置定时器 */ + acl_aio_request_timer(cache->aio, conn_pool_stat_timer, cache, 2); +} + +CONN_CACHE *conn_cache_create(ACL_AIO *aio, int conn_limit) +{ + const char *myname = "conn_cache_create"; + CONN_CACHE *cache = (CONN_CACHE*) acl_mycalloc(1, sizeof(CONN_CACHE)); + + cache->aio = aio; + cache->conn_limit = conn_limit; + cache->cache = acl_htable_create(1024, 0); + acl_msg_info("%s(%d): ok, conn_limit: %d", myname, __LINE__, conn_limit); + + /* 设置连接池缓存状态信息的定时器 */ + set_conn_pool_stat_timer(cache); + return (cache); +} + +/* 流可读时的回调函数 */ + +static int read_callback(ACL_ASTREAM *stream acl_unused, void *ctx acl_unused, + char *data acl_unused, int dlen acl_unused) +{ + const char *myname = "read_callback"; + + acl_msg_info("%s(%d), %s: can read connection from server, dlen(%d), data(%s)", + __FILE__, __LINE__, myname, dlen, data); + + /* 因为该连接为空闲连接,不应有数据可读,如果有数据可读,则因为 + * 无法知道如何处理这些数据而需要关闭该连接 + */ + + /* 返回 -1 从而触发关闭回调函数 */ + return (-1); +} + +/* 流关闭时的回调函数 */ + +static int read_close_callback(ACL_ASTREAM *stream acl_unused, void *ctx) +{ + CONN *conn = (CONN*) ctx; + CONN_POOL *conns = conn->conn_pool; + + /* 释放该连接对象的内存空间,但并不关闭该连接, + * 关闭过程由异步框架自动关闭 + */ + conn_free(conn); + + /* 如果连接池为空则释放该连接池 */ + if (acl_fifo_size(&conns->conns) == 0) { + acl_htable_delete(conns->conn_cache->cache, conns->key, NULL); + set_conn_pool_free_timer(conns); + } + + conns->conn_cache->nclose++; + + /* 触发 acl_aio_iocp_close 过程 */ + return (-1); +} + +/* 流读超时时的回调函数 */ + +static int read_timeout_callback(ACL_ASTREAM *stream acl_unused, void *ctx acl_unused) +{ + /* 返回 -1 从而触发关闭回调函数 */ + return (-1); +} + +void conn_cache_push_stream(CONN_CACHE *cache, ACL_ASTREAM *stream, + int timeout, void (*free_fn)(ACL_ASTREAM*, void*), void *ctx) +{ + const char *key = ACL_VSTREAM_PEER(acl_aio_vstream(stream)); + CONN_POOL *conns; + CONN *conn; + +#if 0 + acl_aio_clean_hooks(stream); +#endif + + /* 查看该KEY的连接池句柄是否存在,如果存在则复用,否则创建新的 */ + + conns = (CONN_POOL*) acl_htable_find(cache->cache, key); + if (conns == NULL) { + conns = (CONN_POOL*) acl_mymalloc(sizeof(CONN_POOL)); + conns->conn_cache = cache; + conns->aio = acl_aio_handle(stream); + acl_fifo_init(&conns->conns); + ACL_SAFE_STRNCPY(conns->key, key, sizeof(conns->key)); + acl_htable_enter(cache->cache, key, conns); + } + +#if 0 + /* 如果该连接池中的连接流超过限制,则优先释放最旧的连接对象 */ + if (acl_fifo_size(&conns->conns) >= cache->conn_limit) { + conn = acl_fifo_pop(&conns->conns); + if (conn) { + conn->info = NULL; + conn_close(conn); + } + } +#endif + + cache->nset++; + + /* 创建新的异步流连接缓存对象 */ + conn = (CONN*) acl_mymalloc(sizeof(CONN)); + conn->stream = stream; + conn->ctx = ctx; + conn->free_fn = free_fn; + + /* 加入流连接池中 */ + conn->info = acl_fifo_push(&conns->conns, conn); + conn->conn_pool = conns; + + /* 设置该流的回调函数 */ + acl_aio_ctl(stream, + ACL_AIO_CTL_READ_HOOK_ADD, read_callback, conn, + ACL_AIO_CTL_CLOSE_HOOK_ADD, read_close_callback, conn, + ACL_AIO_CTL_TIMEO_HOOK_ADD, read_timeout_callback, conn, + ACL_AIO_CTL_TIMEOUT, timeout, + ACL_AIO_CTL_END); + /* 开始读该流的数据 */ + acl_aio_read(stream); +} + +CONN *conn_cache_get_conn(CONN_CACHE *cache, const char *key) +{ + CONN_POOL *conns; + CONN *conn; + + /* 先查看该KEY的连接池对象是否存在,如果不存在则返回NULL */ + + conns = (CONN_POOL*) acl_htable_find(cache->cache, key); + if (conns == NULL) { + return (NULL); + } + + /* 从该KEY的连接池中取出一个连接,如果取出为NULL则释放该连接池对象 */ + + conn = acl_fifo_pop(&conns->conns); + if (conn == NULL) { + /* 先从连接池缓存中删除 */ + acl_htable_delete(cache->cache, conns->key, NULL); + /* 设置释放空的连接池对象的定时器 */ + set_conn_pool_free_timer(conns); + return (NULL); + } + + /* 先取消该流之前设置的回调函数 */ +#if 1 + acl_aio_del_read_hook(conn->stream, read_callback, conn); + acl_aio_del_close_hook(conn->stream, read_close_callback, conn); + acl_aio_del_timeo_hook(conn->stream, read_timeout_callback, conn); +#else + acl_aio_clean_hooks(conn->stream); +#endif + + if (conn->free_fn) + conn->free_fn(conn->stream, conn->ctx); + /* 取消读监听 */ + acl_aio_disable_read(conn->stream); + + cache->nget++; + return (conn); +} + +ACL_ASTREAM *conn_cache_get_stream(CONN_CACHE *cache, const char *key, void **ctx_pptr) +{ + CONN *conn; + ACL_ASTREAM *stream; + + conn = conn_cache_get_conn(cache, key); + if (conn == NULL) { + if (ctx_pptr) + *ctx_pptr = NULL; + return (NULL); + } + + if (ctx_pptr) + *ctx_pptr = conn->ctx; + stream = conn->stream; + acl_myfree(conn); /* 因为已经取出流对象,所以可以释放 CONN 对象 */ + return (stream); +} + +void conn_cache_delete_key(CONN_CACHE *cache, const char *key) +{ + CONN_POOL *conns; + ACL_ITER iter; + + conns = (CONN_POOL*) acl_htable_find(cache->cache, key); + if (conns == NULL) + return; + + /* 遍历连接池中的连接流并一一关闭 */ + acl_foreach(iter, &conns->conns) { + CONN *conn = (CONN*) iter.data; + if (conn->stream) { + acl_aio_iocp_close(conn->stream); + conn->stream = NULL; + } + } + + /* 将该连接池从连接池缓存中删除 */ + acl_htable_delete(cache->cache, conns->key, NULL); + /* 设置释放池对象的定时器 */ + set_conn_pool_free_timer(conns); +} + +void conn_cache_delete_conn(CONN *conn) +{ + /* 释放并关闭该连接对象 */ + conn_close(conn); +} + +void conn_cache_delete_stream(CONN_CACHE *cache, ACL_ASTREAM *stream) +{ + const char *key = ACL_VSTREAM_PEER(acl_aio_vstream(stream)); + CONN_POOL *conns; + CONN *conn; + ACL_ITER iter; + + conns = acl_htable_find(cache->cache, key); + if (conns == NULL) + return; + /* 遍历连接池队列中的所有连接 */ + acl_foreach(iter, &conns->conns) { + conn = (CONN*) iter.data; + if (conn->stream == stream) { + /* 释放并关闭该连接对象 */ + conn_close(conn); + break; + } + } +} diff --git a/app/jaws/global/conn_cache.h b/app/jaws/global/conn_cache.h new file mode 100644 index 000000000..1bd69fd48 --- /dev/null +++ b/app/jaws/global/conn_cache.h @@ -0,0 +1,81 @@ +#ifndef __CONN_CACHE_INCLUDE_H__ +#define __CONN_CACHE_INCLUDE_H__ + +#include "lib_acl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct CONN_CACHE { + ACL_AIO *aio; + ACL_HTABLE *cache; + int conn_limit; + int nset; + int nget; + int nclose; +} CONN_CACHE; + +typedef struct CONN CONN; + +/** + * 连接池初始化函数, 该函数仅在程序初始化时被调用一次 + * @param aio {ACL_AIO*} 异步流对象 + * @param conn_limit {int} 每一个连接池的数量限制 + * @return {CONN_CACHE*} 创建一个连接池的缓存对象 + */ +CONN_CACHE *conn_cache_create(ACL_AIO *aio, int conn_limit); + +/** + * 向连接池中添加一个连接流 + * @param cache {CONN_CAHCE*} 长连接缓存对象 + * @param timeout {int} 该连接的超时时间 + * @param free_fn {void (*)(ACL_ASTREAM*, void*)} 关闭连接时的回调函数, + * 如果该参数非空,则当该连接被关闭前会自动调用 free_fn + * @param ctx {void*} free_fn 的参数之一 + */ +void conn_cache_push_stream(CONN_CACHE *cache, ACL_ASTREAM *stream, + int timeout, void (*free_fn)(ACL_ASTREAM*, void*), void *ctx); + +/** + * 从连接池取出对应某个键值的连接对象 + * @param cache {CONN_CAHCE*} 长连接缓存对象 + * @param key {const char*} 查询键值,如:192.168.0.1:80 + * @return {CONN*} 连接对象, 若为 NULL 则表示不存在 + */ +CONN *conn_cache_get_conn(CONN_CACHE *cache, const char *key); + +/** + * 从连接池取出对应某个键值的连接流 + * @param cache {CONN_CAHCE*} 长连接缓存对象 + * @param key {const char*} 查询键值,如:192.168.0.1:80 + * @param ctx_pptr {void**} 如果结果非空,则存储用户的自定义变量 + * @return {ACL_ASTREAM*} 连接流 + */ +ACL_ASTREAM *conn_cache_get_stream(CONN_CACHE *cache, const char *key, void **ctx_pptr); + +/** + * 从连接池中删除对应某个键值的连接 + * @param cache {CONN_CAHCE*} 长连接缓存对象 + * @param key {const char*} 查询键值,如:192.168.0.1:80 + */ +void conn_cache_delete_key(CONN_CACHE *cache, const char *key); + +/** + * 从连接池中删除某个连接对象且关闭连接流 + * @param conn {CONN*} 连接对象 + */ +void conn_cache_delete_conn(CONN *conn); + +/** + * 从连接池中删除某个连接流并删除对应的连接对象且关闭连接流 + * @param cache {CONN_CAHCE*} 长连接缓存对象 + * @param stream {ACL_ASTREAM*} 连接流 + */ +void conn_cache_delete_stream(CONN_CACHE *cache, ACL_ASTREAM *stream); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/app/jaws/global/dns.h b/app/jaws/global/dns.h new file mode 100644 index 000000000..60f6cd8fe --- /dev/null +++ b/app/jaws/global/dns.h @@ -0,0 +1,75 @@ + +#ifndef __DNS_SERVER_INCLUDE_H__ +#define __DNS_SERVER_INCLUDE_H__ + +#include "lib_acl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define USE_THREAD_POOL /* 外挂查询DNS模块采用线程池方式 */ + +/* 查询DNS的消息类型定义 */ +#define DNS_MSG_LOOKUP ACL_MSGIO_USER + 100 +#define DNS_MSG_LOOKUP_RESULT ACL_MSGIO_USER + 101 + +#define DNS_IP_MAX 5 + +typedef struct DNS_CTX DNS_CTX; +typedef struct DNS_SERVER DNS_SERVER; +typedef struct DNS_CACHE DNS_CACHE; + +typedef void (*DNS_CALLBACK)(const DNS_CTX *); + +struct DNS_CTX { + /* public */ + char domain_key[256]; /* 域名(小写) */ + char ip[DNS_IP_MAX][64]; /* IP地址数组 */ + int port[DNS_IP_MAX]; /* port 数组 */ + int ip_cnt; /* IP地址数组中的有效IP地址个数 */ + time_t begin; /* 开始查询时的时间截 */ + + /* public */ + DNS_CALLBACK callback; /* 查询返回调用的用户的回调函数 */ + void *context; /* 用户传递的参数 */ + + /* private */ + DNS_SERVER *dns; /* DNS对象句柄,内部变量 */ + ACL_MSGIO *mio; /* IO消息句柄,内部变量 */ + ACL_DNS_DB *dns_db; /* 临时用以传递DNS查询结果,内部变量 */ +}; + +struct DNS_SERVER { + ACL_AIO *aio; /* 异步通信框架 */ + ACL_WORK_QUEUE *wq; /* 线程池句柄 */ + ACL_MSGIO *listener; /* 消息监听者句柄 */ + ACL_MSGIO *mio; /* 消息句柄 */ + char addr[256]; + + DNS_CACHE *dns_cache; /* DNS缓存句柄 */ + acl_pthread_mutex_t lock; /* 线程锁 */ +}; + +/* in dns_server.c */ +DNS_SERVER *dns_server_create(ACL_AIO *aio, int timeout); +void dns_server_close(DNS_SERVER *dns); +void dns_server_static_add(DNS_SERVER *dns, const char *map, const char *delim, int def_port); +int dns_server_lookup(DNS_SERVER *dns, const DNS_CTX *ctx); + +/* in dns_cache.c */ +void dns_cache_push_one(DNS_CACHE *dns_cache, const ACL_DNS_DB *dns_db, int timeout); +void dns_cache_push(DNS_CACHE *dns_cache, const ACL_DNS_DB *dns_db); +void dns_cache_push2(DNS_CACHE *dns_cache, const DNS_CTX *dns_ctx); + +ACL_DNS_DB *dns_cache_lookup(DNS_CACHE *dns_cache, const char *name); +void dns_cache_del_host(DNS_CACHE *dns_cache, const char *name); +DNS_CACHE *dns_cache_create(int timeout, int thread_safe); + +/* in dns_hosts.c */ +void dns_hosts_load(ACL_DNS *dns_handle, const char *filename); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/app/jaws/global/dns_cache.c b/app/jaws/global/dns_cache.c new file mode 100644 index 000000000..ad587b548 --- /dev/null +++ b/app/jaws/global/dns_cache.c @@ -0,0 +1,348 @@ +#include "lib_acl.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "dns.h" + +static int __thread_safe; + +typedef struct CACHE { + ACL_DNS_DB *dns_db; + char name[256]; + time_t tm_timeout; + ACL_RING ring_entry; +} CACHE; + +struct DNS_CACHE { + acl_pthread_mutex_t cache_mutex; + ACL_HTABLE *cache_table; + ACL_RING cache_ring; +}; + +static int __use_trylock = 0; +static int __cache_timeout = 300; /* 300 seconds */ + +static void cache_lock(DNS_CACHE *dns_cache) +{ + const char *myname = "cache_lock"; + char buf[256]; + int status; + + if (__thread_safe == 0) + return; + + status = acl_pthread_mutex_lock(&dns_cache->cache_mutex); + if (status) { + acl_msg_fatal("%s: pthread_mutex_lock error(%s)", + myname, acl_last_strerror(buf, sizeof(buf))); + } +} + +static int cache_trylock(DNS_CACHE *dns_cache) +{ + int status; + + if (__thread_safe == 0) + return (0); + + status = acl_pthread_mutex_trylock(&dns_cache->cache_mutex); + if (status == 0) + return (0); + else { + return (-1); + } +} + +static void cache_unlock(DNS_CACHE *dns_cache) +{ + const char *myname = "cache_unlock"; + char buf[256]; + int status; + + if (__thread_safe == 0) + return; + + status = acl_pthread_mutex_unlock(&dns_cache->cache_mutex); + if (status) { + acl_msg_fatal("%s: pthread_mutex_lock error(%s)", + myname, acl_last_strerror(buf, sizeof(buf))); + } +} + +static void free_cache_fn(DNS_CACHE *dns_cache, CACHE *cache) +{ + if (cache->dns_db) + acl_netdb_free(cache->dns_db); + acl_ring_detach(&cache->ring_entry); + acl_htable_delete(dns_cache->cache_table, cache->name, NULL); + acl_myfree(cache); +} + +static void cache_timer_fn(DNS_CACHE *dns_cache) +{ + CACHE *cache, *tmp; + ACL_RING *iter; + time_t current; + + current = time(NULL); + + for (iter = acl_ring_succ(&dns_cache->cache_ring); + iter != &dns_cache->cache_ring;) + { + cache = acl_ring_to_appl(iter, CACHE, ring_entry); + if (current >= cache->tm_timeout) { + tmp = cache; + iter = acl_ring_succ(iter); + free_cache_fn(dns_cache, tmp); + } else + break; + } +} + +void dns_cache_push_one(DNS_CACHE *dns_cache, const ACL_DNS_DB *dns_db, int timeout) +{ + const char *myname = "dns_cache_push_one"; + CACHE *cache; + + if (dns_db == NULL || dns_db->h_db == NULL) { + acl_msg_error("%s(%d): input invalid", myname, __LINE__); + return; + } + if (dns_db->name[0] == 0) { + acl_msg_error("%s(%d): host name empty", myname, __LINE__); + return; + } + if (dns_db->size <= 0) { + acl_msg_error("%s(%d): size(%d) <= 0", myname, __LINE__, dns_db->size); + return; + } + if (dns_db->size != acl_array_size(dns_db->h_db)) { + acl_msg_fatal("%s(%d): size(%d) != array size(%d)", + myname, __LINE__, dns_db->size, + acl_array_size(dns_db->h_db)); + } + + if (__use_trylock) { + if (cache_trylock(dns_cache) < 0) { + return; + } + } else + cache_lock(dns_cache); + + cache = (CACHE *) acl_htable_find(dns_cache->cache_table, dns_db->name); + if (cache == NULL) { + cache = (CACHE *) acl_mycalloc(1, sizeof(CACHE)); + if (cache == NULL) { + cache_unlock(dns_cache); + acl_msg_error("%s(%d): calloc error(%s)", + myname, __LINE__, acl_last_serror()); + return; + } + + if (acl_htable_enter(dns_cache->cache_table, + dns_db->name, (char *) cache) == NULL) + { + cache_unlock(dns_cache); + acl_myfree(cache); + acl_msg_error("%s(%d): add to htable error(%s)", + myname, __LINE__, acl_last_serror()); + return; + } + + acl_ring_prepend(&dns_cache->cache_ring, &cache->ring_entry); + ACL_SAFE_STRNCPY(cache->name, dns_db->name, sizeof(cache->name)); + } else { + /* override the old cache */ + if (cache->dns_db != NULL) + acl_netdb_free(cache->dns_db); + cache->dns_db = NULL; + acl_ring_detach(&cache->ring_entry); + acl_ring_prepend(&dns_cache->cache_ring, &cache->ring_entry); + } + + cache->tm_timeout = time(NULL) + timeout; + + cache->dns_db = acl_netdb_clone(dns_db); + if (cache->dns_db == NULL) { + free_cache_fn(dns_cache, cache); + } + + cache_unlock(dns_cache); +} + +void dns_cache_push(DNS_CACHE *dns_cache, const ACL_DNS_DB *dns_db) +{ + dns_cache_push_one(dns_cache, dns_db, __cache_timeout); +} + +void dns_cache_push2(DNS_CACHE *dns_cache, const DNS_CTX *dns_ctx) +{ + const char *myname = "dns_cache_push2"; + ACL_DNS_DB *dns_db; + CACHE *cache; + int i; + + if (dns_ctx == NULL) { + acl_msg_error("%s(%d): input invalid", myname, __LINE__); + return; + } + if (dns_ctx->domain_key[0] == 0) { + acl_msg_error("%s(%d): domain_key empty", myname, __LINE__); + return; + } + if (dns_ctx->ip_cnt <= 0) { + acl_msg_error("%s(%d): size(%d) <= 0", + myname, __LINE__, dns_ctx->ip_cnt); + return; + } + + dns_db = acl_netdb_new(dns_ctx->domain_key); + + for (i = 0; i < dns_ctx->ip_cnt; i++) { + acl_netdb_addip(dns_db, dns_ctx->ip[i]); + } + + if (__use_trylock) { + if (cache_trylock(dns_cache) < 0) { + acl_netdb_free(dns_db); + return; + } + } else + cache_lock(dns_cache); + + cache = (CACHE *) acl_htable_find(dns_cache->cache_table, dns_ctx->domain_key); + if (cache == NULL) { + cache = (CACHE *) acl_mycalloc(1, sizeof(CACHE)); + if (cache == NULL) { + cache_unlock(dns_cache); + acl_netdb_free(dns_db); + acl_msg_error("%s(%d): calloc error(%s)", + myname, __LINE__, acl_last_serror()); + return; + } + + if (acl_htable_enter(dns_cache->cache_table, + dns_db->name, (char *) cache) == NULL) + { + cache_unlock(dns_cache); + acl_netdb_free(dns_db); + acl_msg_error("%s(%d): add to htable error(%s)", + myname, __LINE__, acl_last_serror()); + return; + } + + acl_ring_append(&dns_cache->cache_ring, &cache->ring_entry); + + ACL_SAFE_STRNCPY(cache->name, dns_db->name, sizeof(cache->name)); + } else { + /* override the old cache */ + + if (cache->dns_db != NULL) + acl_netdb_free(cache->dns_db); + cache->dns_db = NULL; + acl_ring_detach(&cache->ring_entry); + acl_ring_append(&dns_cache->cache_ring, &cache->ring_entry); + } + + cache->tm_timeout = time(NULL) + __cache_timeout; + cache->dns_db = dns_db; + + cache_unlock(dns_cache); +} + +ACL_DNS_DB *dns_cache_lookup(DNS_CACHE *dns_cache, const char *name) +{ + const char *myname = "dns_cache_lookup"; + CACHE *cache; + char buf[256]; + ACL_DNS_DB *dns_db; + + if (__use_trylock) { + if (cache_trylock(dns_cache) < 0) + return (NULL); + } else + cache_lock(dns_cache); + + cache_timer_fn(dns_cache); /* 先启动定时清理器,将过期的DNS解析去掉 */ + + ACL_SAFE_STRNCPY(buf, name, sizeof(buf)); + acl_lowercase(buf); + + cache = (CACHE *) acl_htable_find(dns_cache->cache_table, buf); + if (cache == NULL) { + cache_unlock(dns_cache); + return (NULL); + } + + if (cache->dns_db == NULL) { /* XXX */ + acl_msg_error("%s, %s(%d): dns_db null", + __FILE__, myname, __LINE__); + free_cache_fn(dns_cache, cache); + cache_unlock(dns_cache); + return (NULL); + } + + /* if the dns cache has been timeout ? */ + + if (time(NULL) >= cache->tm_timeout) { + free_cache_fn(dns_cache, cache); + cache_unlock(dns_cache); + return (NULL); + } + + /* clone the ACL_DNS_DB object */ + + dns_db = acl_netdb_clone(cache->dns_db); + if (dns_db == NULL) { + acl_msg_error("%s, %s(%d): calloc error(%s)", + __FILE__, myname, __LINE__, acl_last_serror()); + cache_unlock(dns_cache); + return (NULL); + } + + cache_unlock(dns_cache); + + return (dns_db); +} + +void dns_cache_del_host(DNS_CACHE *dns_cache, const char *name) +{ + CACHE *cache; + + cache_lock(dns_cache); + cache = (CACHE *) acl_htable_find(dns_cache->cache_table, name); + if (cache) + free_cache_fn(dns_cache, cache); + cache_unlock(dns_cache); +} + +DNS_CACHE *dns_cache_create(int timeout, int thread_safe) +{ + const char *myname = "dns_cache_create"; + int status; + DNS_CACHE *dns_cache = (DNS_CACHE*) acl_mycalloc(1, sizeof(DNS_CACHE)); + + if (timeout > 0) + __cache_timeout = timeout; + + if (thread_safe) { + status = acl_pthread_mutex_init(&dns_cache->cache_mutex, NULL); + if (status) { + acl_msg_fatal("%s: pthread_mutex_init error(%s)", + myname, acl_last_serror()); + } + __use_trylock = 1; + __thread_safe = 1; + } else + __thread_safe = 0; + + dns_cache->cache_table = acl_htable_create(256, 0); + if (dns_cache->cache_table == NULL) + acl_msg_fatal("%s: create htable error(%s)", + myname, acl_last_serror()); + + acl_ring_init(&dns_cache->cache_ring); + return (dns_cache); +} diff --git a/app/jaws/global/dns_hosts.c b/app/jaws/global/dns_hosts.c new file mode 100644 index 000000000..39e56195c --- /dev/null +++ b/app/jaws/global/dns_hosts.c @@ -0,0 +1,146 @@ +#include "lib_acl.h" +#include "dns.h" + +static void group_add(ACL_DNS *dns_handle, ACL_FILE *fp, char *line) +{ + const char *myname = "group_add"; + char *ptr = line, *label, *group, *name; + char buf[1024], refer[256]; + ACL_ARGV *argv_excepts; + ACL_ARGV *argv_ips; + ACL_VSTRING *buf1, *buf2; + char *ip_list, *excepts; + ACL_ITER iter; + + label = acl_mystrtok(&ptr, " \t"); + if (label == NULL) { + acl_msg_warn("%s(%d): data(%s) invalid", + myname, __LINE__, line); + return; + } + group = acl_mystrtok(&ptr, " \t"); + if (group == NULL) { + return; + } + + argv_excepts = acl_argv_alloc(1); + argv_ips = acl_argv_alloc(1); + + ACL_SAFE_STRNCPY(refer, group, sizeof(refer)); + + while ((acl_fgets_nonl(buf, sizeof(buf), fp)) != NULL) { + ptr = buf; + while (*ptr == ' ' || *ptr == '\t') + ptr++; + if (strcasecmp(ptr, "#@group_end") == 0) + break; + label = acl_mystrtok(&ptr, " \t"); + if (label == NULL) { + acl_msg_warn("%s(%d): line(%s) invalid", + myname, __LINE__, buf); + continue; + } + name = acl_mystrtok(&ptr, " \t"); + if (name == NULL) { + acl_msg_warn("%s(%d): line(%s) invalid", + myname, __LINE__, buf); + continue; + } + if (strcasecmp(label, "#@refer") == 0) { + ACL_SAFE_STRNCPY(refer, name, sizeof(refer)); + } else if (strcasecmp(label, "#@except") == 0) { + acl_argv_add(argv_excepts, name, NULL); + } else if (strcasecmp(label, "#@ip") == 0) { + acl_argv_add(argv_ips, name, NULL); + } + } + + buf1 = acl_vstring_alloc(256); + acl_foreach(iter, argv_ips) { + ptr = (char*) iter.data; + if (ACL_VSTRING_LEN(buf1) > 0) + acl_vstring_strcat(buf1, ","); + acl_vstring_strcat(buf1, ptr); + } + if (ACL_VSTRING_LEN(buf1) > 0) + ip_list = acl_vstring_str(buf1); + else + ip_list = NULL; + + buf2 = acl_vstring_alloc(256); + acl_foreach(iter, argv_excepts) { + ptr = (char*) iter.data; + if (ACL_VSTRING_LEN(buf2) > 0) + acl_vstring_strcat(buf2, ","); + acl_vstring_strcat(buf2, ptr); + } + if (ACL_VSTRING_LEN(buf2) > 0) + excepts = acl_vstring_str(buf2); + else + excepts = NULL; + + acl_dns_add_group(dns_handle, group, refer, ip_list, excepts); + acl_argv_free(argv_excepts); +} + +static void host_add(ACL_DNS *dns_handle, char *line) +{ + char *ptr = line, *ip, *name; + + ip = acl_mystrtok(&ptr, " \t"); + if (ip == NULL) + return; + name = acl_mystrtok(&ptr, " \t"); + if (name == NULL) + return; + acl_dns_add_host(dns_handle, name, ip); +} + +static void hosts_load(ACL_DNS *dns_handle, const char *filename) +{ + const char *myname = "hosts_load"; + ACL_FILE *fp; + char buf[1024]; + + fp = acl_fopen(filename, "r"); + if (fp == NULL) { + acl_msg_error("%s(%d): fopen(%s) error(%s)", + myname, __LINE__, filename, acl_last_serror()); + return; + } + + while ((acl_fgets_nonl(buf, sizeof(buf), fp)) != NULL) { + char *ptr; + + ptr = buf; + while (*ptr == ' ' || *ptr == '\t') + ptr++; + if (*ptr == '#') { + ptr++; + if (strncasecmp(ptr, "@group_name", + sizeof("@group_name") - 1) == 0) + { + group_add(dns_handle, fp, ptr); + } + } else { + host_add(dns_handle, ptr); + } + } + + acl_fclose(fp); +} + +void dns_hosts_load(ACL_DNS *dns_handle, const char *hosts_list) +{ + ACL_ARGV *argv; + ACL_ITER iter; + + if (dns_handle == NULL || hosts_list == NULL || *hosts_list == 0) + return; + argv = acl_argv_split(hosts_list, ";, \t"); + acl_foreach(iter, argv) { + const char *filename = (const char*) iter.data; + hosts_load(dns_handle, filename); + } + acl_argv_free(argv); +} diff --git a/app/jaws/global/dns_lookup.c b/app/jaws/global/dns_lookup.c new file mode 100644 index 000000000..90aa50aeb --- /dev/null +++ b/app/jaws/global/dns_lookup.c @@ -0,0 +1,275 @@ +#include "lib_acl.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "dns.h" +#include "dns_lookup.h" + +#define STRNCPY ACL_SAFE_STRNCPY + +/*----------------------------------------------------------------------------*/ + +static void inner_nslookup_error(CLIENT_ENTRY *entry) +{ + if (entry->client == NULL) + acl_msg_fatal("%s(%d): client null", + __FILE__, __LINE__); + /* 采用AIO库中默认的写关闭动作及写超时动作 */ + acl_aio_ctl(entry->client, ACL_AIO_CTL_WRITE_FN, NULL, + ACL_AIO_CTL_TIMEO_FN, NULL, ACL_AIO_CTL_END); + + if (entry->dns_errmsg) { + acl_aio_refer(entry->client); + acl_aio_writen(entry->client, entry->dns_errmsg, + (int) strlen(entry->dns_errmsg)); + /* 恢复refer值 */ + acl_aio_unrefer(entry->client); + } + + entry->nslookup_notify_fn(entry, NSLOOKUP_ERR); +} + +static void inner_nslookup_ok(CLIENT_ENTRY *entry, ACL_DNS_DB *dns_db) +{ + ACL_ITER iter; + int i = 0; + + entry->ip_idx = 0; + entry->dns_ctx.ip_cnt = 0; + acl_foreach(iter, dns_db) { + const ACL_HOST_INFO *info; + + info = (const ACL_HOST_INFO*) iter.data; + ACL_SAFE_STRNCPY(entry->dns_ctx.ip[i], info->ip, + sizeof(entry->dns_ctx.ip[i])); + entry->dns_ctx.port[i++] = info->hport; + entry->dns_ctx.ip_cnt++; + if (entry->dns_ctx.ip_cnt >= DNS_IP_MAX) + break; + } + entry->nslookup_notify_fn(entry, NSLOOKUP_OK); +} + +static void inner_nslookup_complete(ACL_DNS_DB *dns_db, void *ctx, + int errnum acl_unused) +{ + CLIENT_ENTRY *entry = (CLIENT_ENTRY*) ctx; + + if (dns_db != NULL) + inner_nslookup_ok(entry, dns_db); + else + inner_nslookup_error(entry); +} + +/* 查询DNS信息,采用协议发送的方式 */ +static void inner_nslookup(SERVICE *service, CLIENT_ENTRY *entry, + const char *domain, int port) +{ + char *ptr; + + STRNCPY(entry->dns_ctx.domain_key, domain, + sizeof(entry->dns_ctx.domain_key)); + acl_lowercase(entry->dns_ctx.domain_key); + ptr = strchr(entry->dns_ctx.domain_key, ':'); + if (ptr) + *ptr = 0; + entry->server_port = port; + if (entry->server_port <= 0) + entry->server_port = 80; + + STRNCPY(entry->domain_key, entry->dns_ctx.domain_key, + sizeof(entry->domain_key)); + acl_dns_lookup(service->dns_handle, entry->domain_key, + inner_nslookup_complete, entry); +} + +/*----------------------------------------------------------------------------*/ + +/* DNS查询结果之后的回调函数 */ +static void thrpool_nslookup_complete(const DNS_CTX *dns_ctx) +{ + const char *myname = "thrpool_nslookup_complte"; + SERVICE *service = (SERVICE *) dns_ctx->context; + DNS_RING *list; + ACL_RING *ring_ptr; + CLIENT_ENTRY *entry; + time_t inter, now; + + list = (DNS_RING *) acl_htable_find(service->dns_table, + dns_ctx->domain_key); + if (list == NULL) { + acl_msg_warn(NULL, "%s: domain(%s) not found maybe handled", + myname, dns_ctx->domain_key); + return; + } + + time(&now); + inter = now - dns_ctx->begin; + + /* 如果查询时间过长,则给出警告信息 */ + if (inter >= 5) + acl_msg_warn("%s(%d): dns search time=%d, domain(%s)", + myname, __LINE__, time(NULL) - dns_ctx->begin, + dns_ctx->domain_key); + + while (1) { + ring_ptr = acl_ring_pop_head(&list->ring); + if (ring_ptr == NULL) + break; + + list->nrefer--; + + entry = ACL_RING_TO_APPL(ring_ptr, CLIENT_ENTRY, dns_entry); + + entry->tm.dns_lookup = now - entry->tm.stamp; + entry->tm.stamp = now; + + if (dns_ctx->ip_cnt <= 0) { + acl_msg_error("%s(%d): dns not found domain(%s)", + myname, __LINE__, dns_ctx->domain_key); + if (entry->client == NULL) + acl_msg_fatal("%s(%d): client null", + __FILE__, __LINE__); + /* 采用AIO库中默认的写关闭动作及写超时动作 */ + acl_aio_ctl(entry->client, ACL_AIO_CTL_WRITE_FN, NULL, + ACL_AIO_CTL_TIMEO_FN, NULL, ACL_AIO_CTL_END); + + if (entry->dns_errmsg) { + /* XXX: 因为此处可能会有两处关闭 client 流的地方: + * acl_aio_writen 及 forward_complete,为防止重复 + * 关闭造成的内存访问非法,需要 * 在第一个可能关闭 + * 的函数(acl_aio_writen)调用前提升 client 流的 + * 引用值,并且在该函数返回后再恢复引用值 + */ + + acl_aio_refer(entry->client); + acl_aio_writen(entry->client, entry->dns_errmsg, + (int) strlen(entry->dns_errmsg)); + /* 恢复refer值 */ + acl_aio_unrefer(entry->client); + } + + entry->nslookup_notify_fn(entry, NSLOOKUP_ERR); + + continue; + } + + if (acl_do_debug(20, 2)) { + int i; + + for (i = 0; i < dns_ctx->ip_cnt; i++) + acl_msg_info("%s(%d): domain(%s), ip%d(%s)", + myname, __LINE__, dns_ctx->domain_key, + i, dns_ctx->ip[i]); + } + + /* 将查得的所有DNS结果都拷贝至请求对象中 */ + memcpy(&entry->dns_ctx, dns_ctx, sizeof(entry->dns_ctx)); + + /* 下面注释部分被打开,便可以测试连接重试功能:)-- zsx, 2008.2.28 + * strcpy(proxy_entry->dns_ctx.ip[1], proxy_entry->dns_ctx.ip[0]); + * strcpy(proxy_entry->dns_ctx.ip[0], "127.0.0.1"); + * if (proxy_entry->dns_ctx.ip_cnt < 2) + * proxy_entry->dns_ctx.ip_cnt = 2; + */ + entry->ip_idx = 0; + entry->nslookup_notify_fn(entry, NSLOOKUP_OK); + } + + acl_htable_delete(service->dns_table, dns_ctx->domain_key, NULL); + if (list->nrefer <= 0) + acl_myfree(list); + else + acl_msg_fatal("%s(%d): list's nrefer=%d", + myname, __LINE__, list->nrefer); +} + +/* 查询DNS信息,采用外挂模块的方式 */ +static void thrpool_nslookup(SERVICE *service, CLIENT_ENTRY *entry, + const char *domain, int port) +{ + const char *myname = "thrpool_nslookup"; + DNS_CTX dns_ctx; + DNS_RING *list; + char *ptr; + + entry->tm.stamp = time(NULL); + + memset(&dns_ctx, 0, sizeof(dns_ctx)); + dns_ctx.begin = entry->tm.stamp; + STRNCPY(dns_ctx.domain_key, domain, sizeof(dns_ctx.domain_key)); + ptr = strchr(dns_ctx.domain_key, ':'); + /* 仅留下域名部分 */ + if (ptr) + *ptr = 0; + + entry->server_port = port; + if (entry->server_port <= 0) + entry->server_port = 80; + + /* 将域名字符串都转换成小写,以便于进行哈希查询 */ + acl_lowercase(dns_ctx.domain_key); + + dns_ctx.context = service; + dns_ctx.callback = thrpool_nslookup_complete; + + STRNCPY(entry->domain_key, dns_ctx.domain_key, sizeof(entry->domain_key)); + + /* 先查询DNS查询表中是否已经包含本次需要被查询的域名 */ + list = (DNS_RING *) acl_htable_find(service->dns_table, dns_ctx.domain_key); + if (list) { + /* 将本次对同一域名的查询添加进同一个查询链中 */ + acl_ring_prepend(&list->ring, &entry->dns_entry); + /* 将查询链对象的引用计数加1 */ + list->nrefer++; + /* 如果该查询链已经存在,说明有查询任务等待返回,其返回后会一同将 + * 本次任务进行触发,如果此处触发新任务,则会造成内存访问冲突,因为 + * 查询DNS的过程是由一组线程池进行查询的。 + * (void) dns_server_lookup(proxy_entry->aio_proxy->dns_server, &dns_ctx); + */ + return; + } + + /* 创建一个新的查询链对象,并将本次查询任务加入该查询链中及将该查询链加入查询表中 */ + + list = (DNS_RING *) acl_mycalloc(1, sizeof(DNS_RING)); + acl_ring_init(&list->ring); + STRNCPY(list->domain_key, dns_ctx.domain_key, sizeof(list->domain_key)); + + /* 将本次查询任务加入新的查询链中且将查询链的引用计数加1 */ + acl_ring_prepend(&list->ring, &entry->dns_entry); + list->nrefer++; + + /* 将新的查询链加入查询表中 */ + if (acl_htable_enter(service->dns_table, list->domain_key, (char *) list) == NULL) + acl_msg_fatal("%s: add domain(%s) to table error", myname, list->domain_key); + + /* 开始启动DNS查询过程 */ + (void) dns_server_lookup(service->dns_server, &dns_ctx); +} + +/*----------------------------------------------------------------------------*/ + +void dns_lookup(CLIENT_ENTRY *entry, const char *domain, int port) +{ + const char *myname = "dns_lookup"; + SERVICE *service = entry->service; + + if (acl_ipv4_valid(domain)) { + entry->ip_idx = 0; + ACL_SAFE_STRNCPY(entry->dns_ctx.ip[0], domain, + sizeof(entry->dns_ctx.ip[0])); + entry->dns_ctx.port[0] = port; + entry->dns_ctx.ip_cnt = 1; + entry->nslookup_notify_fn(entry, NSLOOKUP_OK); + return; + } else if (service->dns_handle) { + inner_nslookup(service, entry, domain, port); + } else if (service->dns_server) { + thrpool_nslookup(service, entry, domain, port); + } else { + acl_msg_fatal("%s(%d): no dns lookup set", myname, __LINE__); + } +} diff --git a/app/jaws/global/dns_lookup.h b/app/jaws/global/dns_lookup.h new file mode 100644 index 000000000..09ba3eb98 --- /dev/null +++ b/app/jaws/global/dns_lookup.h @@ -0,0 +1,17 @@ +#ifndef __DNS_LOOKUP_INCLUDE_H__ +#define __DNS_LOOKUP_INCLUDE_H__ + +#include "dns.h" +#include "service_struct.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void dns_lookup(CLIENT_ENTRY *entry, const char *domain, int port); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/app/jaws/global/dns_server.c b/app/jaws/global/dns_server.c new file mode 100644 index 000000000..d5c53cbf2 --- /dev/null +++ b/app/jaws/global/dns_server.c @@ -0,0 +1,271 @@ +#include "lib_acl.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "dns.h" + +#define MSG_SEND acl_msgio_send + +/* DNS查询线程向主线程发送IO消息,因为多个线程都要用一个消息句柄发送消息,所以需要加锁 */ + +static void reply_lookup_msg(DNS_CTX *dns_ctx, DNS_SERVER *dns) +{ + const char *myname = "reply_lookup_msg"; + + /* 加锁 */ + acl_pthread_mutex_lock(&dns->lock); + + /* 向主线程发送DNS查询结果消息 */ + if (MSG_SEND(dns_ctx->mio, DNS_MSG_LOOKUP_RESULT, dns_ctx, sizeof(DNS_CTX)) < 0) { + acl_msg_error("%s: send msg error, domain(%s)", myname, dns_ctx->domain_key); + } + + /* 解锁 */ + acl_pthread_mutex_unlock(&dns->lock); + + /* 释放由 msg_lookup 函数分配的内存 */ + acl_myfree(dns_ctx); +} + +/* DNS查询线程,查到DNS结果会通过IO消息将数据传递给非阻塞式主线程的消息队列 */ + +static void lookup_thread(int event_type acl_unused, void *arg) +{ + const char *myname = "lookup_thread"; +#ifdef USE_THREAD_POOL + ACL_WORKER_ATTR *w_attr = (ACL_WORKER_ATTR *) arg; + DNS_CTX *dns_ctx = (DNS_CTX *) w_attr->run_data; + DNS_SERVER *dns = dns_ctx->dns; +#else + DNS_CTX *dns_ctx = (DNS_CTX *) arg; + DNS_SERVER *dns = dns_ctx->dns; +#endif + int error = 0, n, i; + + dns_ctx->dns_db = acl_gethostbyname(dns_ctx->domain_key, &error); + if (dns_ctx->dns_db == NULL) { + acl_msg_error("%s: gethostbyname error(%s), domain(%s)", + myname, acl_netdb_strerror(error), dns_ctx->domain_key); + dns_ctx->ip_cnt = 0; + reply_lookup_msg(dns_ctx, dns); + return; + } + + n = acl_netdb_size(dns_ctx->dns_db); + dns_ctx->ip_cnt = n > DNS_IP_MAX ? DNS_IP_MAX : n; + + for (i = 0; i < dns_ctx->ip_cnt; i++) { + snprintf(dns_ctx->ip[i], sizeof(dns_ctx->ip[i]), "%s", + acl_netdb_index_ip(dns_ctx->dns_db, i)); + dns_ctx->port[i] = 0; /* 对于DNS查询到的结果,采用默认的端口号 */ + } + reply_lookup_msg(dns_ctx, dns); +} + +/* 主线程消息处理函数: 主线程通过此函数创建DNS线程进行DNS查询过程 */ + +static int msg_lookup(int msg_type acl_unused, ACL_MSGIO *mio, + const ACL_MSGIO_INFO *info, void *arg) +{ + DNS_CTX *dns_ctx; + + dns_ctx = (DNS_CTX *) acl_mycalloc(1, sizeof(DNS_CTX)); + memcpy(dns_ctx, acl_vstring_str(info->body.buf), + ACL_VSTRING_LEN(info->body.buf)); + + /* 设置DNS句柄 */ + dns_ctx->dns = (DNS_SERVER *) arg; + /* 设置消息句柄,线程池中的查询线程通过向此句柄发送消息以通知 + * 主线程有关DNS的查询结果 + */ + dns_ctx->mio = mio; + + /* 创建单独的线程进行阻塞式DNS查询过程 */ +#ifdef USE_THREAD_POOL + acl_workq_add(dns_ctx->dns->wq, lookup_thread, 0, dns_ctx); +#else + lookup_thread(0, dns_ctx); +#endif + + return (1); +} + +/* 主线程消息处理函数: 主线程通过此函数接收DNS查询线程发送的DNS查询结果消息 */ + +static int msg_lookup_result(int msg_type acl_unused, ACL_MSGIO *mio acl_unused, + const ACL_MSGIO_INFO *info, void *arg) +{ + DNS_CTX *dns_ctx; + DNS_SERVER *dns = (DNS_SERVER*) arg; + + /* 获得DNS查询线程的结果消息 */ + dns_ctx = (DNS_CTX *) acl_vstring_str(info->body.buf); + + /* 将查询结果放入DNS缓存中 */ + if (dns_ctx->ip_cnt > 0) + dns_cache_push(dns->dns_cache, dns_ctx->dns_db); + + /* 释放由 lookup_thread 分配的 dns_db 对象 */ + if (dns_ctx->dns_db) + acl_netdb_free(dns_ctx->dns_db); + dns_ctx->dns_db = NULL; + + /* 回调请求任务函数 */ + dns_ctx->callback(dns_ctx); + + return (1); +} + +/* 创建DNS查询句柄 */ + +DNS_SERVER *dns_server_create(ACL_AIO *aio, int timeout) +{ + const char *myname = "dns_server_create"; + DNS_SERVER *dns; + int max_threads = 200; + int idle_timeout = 60 /* 此值目前不起作用,需要修改一下ACL库才可 */; + + if (aio == NULL) + acl_msg_fatal("%s(%d): aio null", myname, __LINE__); + + /* acl 库的DNS缓存模块需要加锁,因为查询线程池都要访问该同一资源 + * 仅让 acl 的DNS缓存模块的缓存时间为60秒,因为本程序模块也有缓存控制 + * 因为本代码自己已经实现了DNS缓存,所以不需要ACL库的DNS缓存处理 + * acl_netdb_cache_init(60 , 1); + */ + + dns = (DNS_SERVER *) acl_mycalloc(1, sizeof(DNS_SERVER)); + dns->aio = aio; + /* 本地的DNS缓存模块需要加锁,因为只有一个线程访问其资源 */ + dns->dns_cache = dns_cache_create(timeout, 0); + + + /* 监听 IO 事件消息 */ + dns->listener = acl_msgio_listen(aio, NULL); + if (dns->listener == NULL) + acl_msg_fatal("%s: listen error", myname); + + /* 注册 IO 事件消息及处理函数:用于监听新的查询请求 */ + acl_msgio_listen_reg(dns->listener, DNS_MSG_LOOKUP, msg_lookup, dns, 1); + + acl_msgio_addr(dns->listener, dns->addr, sizeof(dns->addr)); + dns->mio = acl_msgio_connect(aio, dns->addr, 0); + if (dns->mio == NULL) + acl_msg_fatal("%s: connect server(%s) error", myname, dns->addr); + + /* 注册 IO 事件消息及处理函数:用于处理查询线程返回查询结果 */ + acl_msgio_reg(dns->mio, DNS_MSG_LOOKUP_RESULT, msg_lookup_result, dns); + + /* 初始化DNS共享线程锁 */ + acl_pthread_mutex_init(&dns->lock, NULL); + + /* 需要创建独立的线程程查询DNS(因为查询DNS是阻塞式查询) */ +#ifdef USE_THREAD_POOL + dns->wq = acl_workq_create(max_threads, idle_timeout, NULL, dns); +#endif + + return (dns); +} + +/* 关闭DNS查询句柄 */ + +void dns_server_close(DNS_SERVER *dns) +{ + acl_msgio_close(dns->listener); + acl_workq_destroy(dns->wq); + acl_myfree(dns); +} + +void dns_server_static_add(DNS_SERVER *dns, const char *map, const char *delim, int def_port) +{ + ACL_DNS_DB *dns_db = NULL; + ACL_ARGV *argv = NULL; + char *ptr; + int i, port; + +#undef RETURN +#define RETURN do { \ + if (argv != NULL) \ + acl_argv_free(argv); \ + if (dns_db != NULL) \ + acl_netdb_free(dns_db); \ + return; \ +} while (0) + + argv = acl_argv_split(map, delim); + if (argv == NULL) + RETURN; + if (argv->argc < 2) + RETURN; + + dns_db = acl_netdb_new(argv->argv[0]); + for (i = 1; i < argv->argc; i++) { + ptr = strchr(argv->argv[i], ':'); + if (ptr != NULL) { + *ptr++ = 0; + port = atoi(ptr); + if (port <= 0) + port = def_port; + } else { + port = def_port; + } + acl_netdb_add_addr(dns_db, argv->argv[i], port); + } + + /* 设置超时时间为0从而使其永不超时 */ + dns_cache_push_one(dns->dns_cache, dns_db, 0); + RETURN; +} + +/* 开始查询某个域名 */ + +int dns_server_lookup(DNS_SERVER *dns, const DNS_CTX *ctx) +{ + const char *myname = "dns_server_lookup"; + ACL_MSGIO *mio = dns->mio; + DNS_CTX dns_ctx; + ACL_DNS_DB *dns_db; + + /* 只所以采用此方式,是为了保证 dns_server_lookup 参数 ctx为 const 类型 */ + memcpy(&dns_ctx, ctx, sizeof(dns_ctx)); + + /* 先查询DNS缓存表中是否存在本次所查域名 */ + dns_db = dns_cache_lookup(dns->dns_cache, ctx->domain_key); + if (dns_db) { + ACL_ITER iter; + int i = 0; + + acl_foreach(iter, dns_db) { + const ACL_HOST_INFO *info; + + info = (const ACL_HOST_INFO*) iter.data; + ACL_SAFE_STRNCPY(dns_ctx.ip[i], info->ip, + sizeof(dns_ctx.ip[i])); + dns_ctx.port[i++] = info->hport; + dns_ctx.ip_cnt++; + if (dns_ctx.ip_cnt >= DNS_IP_MAX) + break; + } + + /* 对已经DNS缓存表中已经存在的域名直接触发任务回调过程 */ + dns_ctx.callback(&dns_ctx); + + /* 此处之所以需要释放该对象,是因为 dns_cache_lookup 返回的对象为动态 + * 分配的(acl_netdb_clone) + */ + acl_netdb_free(dns_db); + return (0); + } + + /* 向查询线程池发送查询指令 */ + + if (MSG_SEND(mio, DNS_MSG_LOOKUP, &dns_ctx, sizeof(DNS_CTX)) < 0) { + acl_msg_error("%s: send msg error, domain(%s)", + myname, dns_ctx.domain_key); + return (-1); + } + + return (0); +} diff --git a/app/jaws/global/file_cache.c b/app/jaws/global/file_cache.c new file mode 100644 index 000000000..77b4fc672 --- /dev/null +++ b/app/jaws/global/file_cache.c @@ -0,0 +1,89 @@ +#include "lib_acl.h" +#include "lib_protocol.h" +#include +#include +#include +#include +#ifdef ACL_UNIX +#include +#endif +#include "service.h" +#include "file_cache.h" +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +static ACL_HTABLE *__cache_table = NULL; + +void file_cache_init(void) +{ + __cache_table = acl_htable_create(100, 0); +} + +FILE_CACHE *file_cache_new(const char *file_path, time_t last_modified) +{ + FILE_CACHE *cache; + + cache = (FILE_CACHE*) acl_mymalloc(sizeof(FILE_CACHE)); + cache->size = 0; + http_mkrfc1123(cache->tm_mtime, sizeof(cache->tm_mtime), last_modified); + ACL_SAFE_STRNCPY(cache->path, file_path, sizeof(cache->path)); + cache->fifo = acl_fifo_new(); + (void) acl_htable_enter(__cache_table, file_path, (char*) cache); + return (cache); +} + +void file_cache_free(FILE_CACHE *cache) +{ + BUFFER *buffer; + + acl_htable_delete(__cache_table, cache->path, NULL); + + while (1) { + buffer = (BUFFER*) acl_fifo_pop(cache->fifo); + if (buffer == NULL) + break; + acl_myfree(buffer->buf); + acl_myfree(buffer); + } + + acl_fifo_free(cache->fifo, NULL); + acl_myfree(cache); +} + +FILE_CACHE *file_cache_find(const char *file_path) +{ + FILE_CACHE *cache = (FILE_CACHE*) + acl_htable_find(__cache_table, file_path); + return (cache); +} + +void file_cache_push(FILE_CACHE *cache, const void *data, size_t size) +{ + BUFFER *buffer = acl_mymalloc(sizeof(BUFFER)); + + buffer->buf = acl_mymalloc(size); + buffer->size = size; + memcpy(buffer->buf, data, size); + buffer->ptr = buffer->buf; + cache->size += size; + acl_fifo_push(cache->fifo, buffer); +} + +void file_cache_iter(FILE_CACHE *cache, CACHE_ITER *iter) +{ + cache->fifo->iter_head(&iter->iter, cache->fifo); + iter->cache = cache; +} + +BUFFER *file_cache_next_buffer(CACHE_ITER *iter) +{ + BUFFER *buffer; + + if (iter->iter.ptr == NULL) + return (NULL); + buffer = (BUFFER*) iter->iter.data; + iter->cache->fifo->iter_next(&iter->iter, iter->cache->fifo); + return (buffer); +} + diff --git a/app/jaws/global/file_cache.h b/app/jaws/global/file_cache.h new file mode 100644 index 000000000..356cd76b9 --- /dev/null +++ b/app/jaws/global/file_cache.h @@ -0,0 +1,41 @@ +#ifndef __FILE_CACHE_INCLUDE_H__ +#define __FILE_CACHE_INCLUDE_H__ + +#include "lib_acl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct BUFFER { + void *buf; + void *ptr; + size_t size; +} BUFFER; + +typedef struct FILE_CACHE { + char path[1024]; + size_t size; + char tm_mtime[64]; + ACL_FIFO *fifo; +} FILE_CACHE; + +typedef struct CACHE_ITER { + FILE_CACHE *cache; + ACL_ITER iter; +} CACHE_ITER; + +/* in file_cache.c */ +void file_cache_init(void); +FILE_CACHE *file_cache_new(const char *file_path, time_t last_modified); +void file_cache_free(FILE_CACHE *cache); +FILE_CACHE *file_cache_find(const char *file_path); +void file_cache_push(FILE_CACHE *cache, const void *data, size_t size); +void file_cache_iter(FILE_CACHE *cache, CACHE_ITER *iter); +BUFFER *file_cache_next_buffer(CACHE_ITER *iter); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/app/jaws/global/forward.c b/app/jaws/global/forward.c new file mode 100644 index 000000000..47e3bddc0 --- /dev/null +++ b/app/jaws/global/forward.c @@ -0,0 +1,298 @@ +#include "lib_acl.h" +#include "conn_cache.h" +#include "service.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +static int connect_close_callback(ACL_ASTREAM *astream, void *context); +static int connect_timeout_callback(ACL_ASTREAM *astream, void *context); +static int connect_callback(ACL_ASTREAM *server, void *context); + +void forward_complete(CLIENT_ENTRY *entry) +{ + if (entry->server) { + acl_aio_iocp_close(entry->server); + } + if (entry->client) { + acl_aio_iocp_close(entry->client); + } +} + +/* 尝试从连接池中获得一个连接流 */ + +static ACL_ASTREAM *peek_server_conn(CLIENT_ENTRY *entry) +{ + ACL_ASTREAM *stream; + char addr[64]; + int i; + + if (entry->service->conn_cache == NULL) + return (NULL); + for (i = entry->ip_idx; i < entry->dns_ctx.ip_cnt; i++) { + snprintf(addr, sizeof(addr), "%s:%d", entry->dns_ctx.ip[i], + entry->dns_ctx.port[i] > 0 + ? entry->dns_ctx.port[i] : entry->server_port); + stream = conn_cache_get_stream(entry->service->conn_cache, addr, NULL); + if (stream != NULL) + return (stream); + } + + return (NULL); +} + +/* 取得某域名的下一个服务器 IP:PORT 地址 */ + +static const char *next_server_addr(CLIENT_ENTRY *entry, char *buf, size_t size) +{ + const char *myname = "next_server_addr"; + SERVICE *service = entry->service; + int i; + + /* 试着多连一次 */ + if (entry->ip_ntry++ > entry->dns_ctx.ip_cnt) { + acl_msg_error("%s(%d): domain(%s), ip_ntry(%d) >= ip_cnt(%d)", + myname, __LINE__, entry->domain_key, + entry->ip_ntry, entry->dns_ctx.ip_cnt); + return (NULL); + } + if (entry->ip_idx == entry->dns_ctx.ip_cnt) + entry->ip_idx = 0; + for (i = entry->ip_idx; i < entry->dns_ctx.ip_cnt; i++) { + if (service->bind_ip_list) { + snprintf(buf, size, "%s@%s:%d", + service->bind_ip_list[service->bind_ip_index++], + entry->dns_ctx.ip[i], + entry->dns_ctx.port[i] > 0 + ? entry->dns_ctx.port[i] : entry->server_port); + if (service->bind_ip_list[service->bind_ip_index] == NULL) + service->bind_ip_index = 0; + } else { + snprintf(buf, size, "%s:%d", entry->dns_ctx.ip[i], + entry->dns_ctx.port[i] > 0 + ? entry->dns_ctx.port[i] : entry->server_port); + } + entry->ip_idx++; + acl_debug(23, 2) ("%s(%d): domain(%s), addr(%s)", + myname, __LINE__, entry->domain_key, buf); + return (buf); + } + + return (NULL); +} + +static ACL_ASTREAM *forward_connect_next(CLIENT_ENTRY *entry) +{ + const char* myname = "forward_connect_next"; + SERVICE *service = entry->service; + ACL_ASTREAM* server; + int i = 0; + + while (1) { + if (next_server_addr(entry, entry->domain_addr, + sizeof(entry->domain_addr)) == NULL) + break; + server = acl_aio_connect(entry->client->aio, + entry->domain_addr, service->conn_timeout); + if (server != NULL) + return (server); + acl_msg_error("%s: connect server addr(%s), domain(%s), i=%d", + myname, entry->domain_addr, entry->domain_key, i); + i++; + } + + return (NULL); +} + +static int connect_close_callback(ACL_ASTREAM *astream, void *context) +{ + const char* myname = "connect_close_callback"; + CLIENT_ENTRY *entry = (CLIENT_ENTRY *) context; + + /* 卸载回调函数,防止被重复调用 */ + acl_aio_ctl(astream, + ACL_AIO_CTL_CONNECT_FN, NULL, + ACL_AIO_CTL_CLOSE_HOOK_DEL, connect_close_callback, entry, + ACL_AIO_CTL_TIMEO_HOOK_DEL, connect_timeout_callback, entry, + ACL_AIO_CTL_END); + + if (entry->flag_has_replied == 1) + return (-1); + + if (entry->ip_idx < entry->dns_ctx.ip_cnt) { + ACL_ASTREAM* server; + + acl_debug(23, 1) ("%s(%d): begin to connect next ip(%s:%d)", + myname, __LINE__, entry->dns_ctx.ip[entry->ip_idx], + entry->server_port); + + /* 断开与服务端的连接,但保持与浏览器端的连接 + * XXX: 因为该函数将清除一些关闭回调函数,不知是否会造成某些内存泄漏? + * 注,此处并不关闭服务端连接,需要调用者自己来关闭 + */ + if (entry->server && client_entry_detach(entry, acl_aio_vstream(entry->server))) { + acl_debug(23, 1) ("%s(%d): entry's freed", myname, __LINE__); + return (-1); + } + + server = forward_connect_next(entry); + if (server == NULL) + goto CONNECT_ERROR; + + client_entry_set_server(entry, server); + acl_aio_ctl(server, + ACL_AIO_CTL_CONNECT_FN, connect_callback, + ACL_AIO_CTL_CLOSE_HOOK_ADD, connect_close_callback, entry, + ACL_AIO_CTL_TIMEO_HOOK_ADD, connect_timeout_callback, entry, + ACL_AIO_CTL_CTX, entry, + ACL_AIO_CTL_END); + + /* 通过返回-1,使异步流框架关闭服务端连接 */ + return (-1); + } + +CONNECT_ERROR: + + entry->tm.connect = time(NULL) - entry->tm.stamp; + if (entry->ip_idx <= 0) + acl_debug(23, 0) ("%s(%d): internal error, ip_idx=%d, domain(%s:%d)", + myname, __LINE__, entry->ip_idx, + entry->domain_key, entry->server_port); + else + acl_debug(23, 0) ("%s(%d): connect error, addr(%s:%d), domain(%s)", + myname, __LINE__, + entry->dns_ctx.ip[entry->ip_idx - 1], + entry->server_port, + entry->domain_key); + + entry->flag_has_replied = 1; + + if (entry->connect_error_fn) + entry->connect_error_fn(entry); + + return (-1); +} + +static int connect_timeout_callback(ACL_ASTREAM *astream, void *context) +{ + const char* myname = "connect_timeout_callback"; + CLIENT_ENTRY *entry = (CLIENT_ENTRY *) context; + + /* 卸载回调函数,防止被重复调用 */ + acl_aio_ctl(astream, + ACL_AIO_CTL_CONNECT_FN, NULL, + ACL_AIO_CTL_CLOSE_HOOK_DEL, connect_close_callback, entry, + ACL_AIO_CTL_TIMEO_HOOK_DEL, connect_timeout_callback, entry, + ACL_AIO_CTL_END); + + if (entry->flag_has_replied == 1) + return (-1); + + if (entry->ip_idx < entry->dns_ctx.ip_cnt) { + ACL_ASTREAM *server; + + acl_debug(23, 1) ("%s(%d): begin to connect next ip(%s:%d)", + myname, __LINE__, entry->dns_ctx.ip[entry->ip_idx], + entry->server_port); + + /* 断开与服务端的连接,但保持与浏览器端的连接 + * XXX: 因为该函数将清除一些关闭回调函数,不知是否会造成某些内存泄漏? + * 注,此处并不关闭服务端连接,需要调用者自己来关闭 + */ + if (client_entry_detach(entry, acl_aio_vstream(entry->server)) == 1) { + acl_debug(3, 1) ("%s(%d): entry is freed", myname, __LINE__); + return (-1); + } + + server = forward_connect_next(entry); + if (server == NULL) + goto CONNECT_ERROR; + + client_entry_set_server(entry, server); + acl_aio_ctl(server, + ACL_AIO_CTL_CONNECT_FN, connect_callback, + ACL_AIO_CTL_CLOSE_HOOK_ADD, connect_close_callback, entry, + ACL_AIO_CTL_TIMEO_HOOK_ADD, connect_timeout_callback, entry, + ACL_AIO_CTL_CTX, entry, + ACL_AIO_CTL_END); + + /* 通过返回-1,使异步流框架关闭服务端连接 */ + return (-1); + } + +CONNECT_ERROR: + + entry->tm.connect = time(NULL) - entry->tm.stamp; + if (entry->ip_idx <= 0) + acl_debug(23, 0) ("%s(%d): internal error, ip_idx=0, domain(%s:%d)", + myname, __LINE__, entry->domain_key, entry->server_port); + else + acl_debug(23, 0) ("%s(%d): connect timeout, addr(%s:%d)", + myname, __LINE__, + entry->dns_ctx.ip[entry->ip_idx - 1], + entry->server_port); + + entry->flag_has_replied = 1; + + if (entry->connect_timeout_fn) + entry->connect_timeout_fn(entry); + + return (-1); +} + +static int connect_callback(ACL_ASTREAM *server, void *context) +{ + CLIENT_ENTRY *entry = (CLIENT_ENTRY*) context; + + /* 卸载回调函数,防止被重复调用 */ + acl_aio_ctl(server, + ACL_AIO_CTL_CONNECT_FN, NULL, + ACL_AIO_CTL_CLOSE_HOOK_DEL, connect_close_callback, entry, + ACL_AIO_CTL_TIMEO_HOOK_DEL, connect_timeout_callback, entry, + ACL_AIO_CTL_END); + entry->tm.connect = time(NULL) - entry->tm.stamp; + return (entry->connect_notify_fn(entry)); +} + +void forward_start(CLIENT_ENTRY *entry) +{ + const char *myname = "forward_start"; + ACL_ASTREAM *server; + + /* 先从连接池中尝试一个连接流 */ + server = peek_server_conn(entry); + if (server == NULL) { + /* 如果连接池中没有可利用的连接流,则开始连接服务端 */ + server = forward_connect_next(entry); + if (server == NULL) { + acl_msg_error("%s: connect server_addr(%s:%d) error(%s)", + myname, entry->domain_key, entry->server_port, + acl_last_serror()); +#if 1 + if (entry->connect_error_fn) + entry->connect_error_fn(entry); +#else + forward_complete(entry); +#endif + return; + } + entry->flag_conn_reuse = 0; + + client_entry_set_server(entry, server); + acl_aio_ctl(server, + ACL_AIO_CTL_CONNECT_FN, connect_callback, + ACL_AIO_CTL_CTX, entry, + ACL_AIO_CTL_CLOSE_HOOK_ADD, connect_close_callback, entry, + ACL_AIO_CTL_TIMEO_HOOK_ADD, connect_timeout_callback, entry, + ACL_AIO_CTL_END); + + } else { + /* 复用连接池中的连接 */ + + entry->flag_conn_reuse = 1; + client_entry_set_server(entry, server); + acl_aio_ctl(server, ACL_AIO_CTL_CTX, entry, ACL_AIO_CTL_END); + connect_callback(server, entry); + } +} diff --git a/app/jaws/global/logger.c b/app/jaws/global/logger.c new file mode 100644 index 000000000..0ac183b3b --- /dev/null +++ b/app/jaws/global/logger.c @@ -0,0 +1,472 @@ +#include "lib_acl.h" +#include +#ifdef ACL_MS_WINDOWS +#include +typedef int pid_t; +#endif +#include "sys_patch.h" +#include "logger.h" + +typedef struct LOG_WRAP { + char filename[1024]; + ACL_VSTREAM *h_log; + ACL_AIO *aio; + ACL_AQUEUE *logger_queue; +#ifdef HAS_ELIB + E_LOG_T *h_log; +#endif +} LOG_WRAP; + +static LOG_WRAP *__log_wrap = NULL; +static pid_t __pid; + +#ifdef HAS_ELIB +#include "e_config.h" +#include "elib.h" + +static int __log_open(const char *filename, void *ctx) +{ + LOG_WRAP *h_log = (LOG_WRAP *) ctx; + int logme = 0; + char *facility_name = NULL; + E_LOG_PRIORITY_T priority = E_LOG_INFO; + E_LOG_ACTION_T action = E_LOG_PER_DAY; + int flush = 1; + size_t limit_size = 0; + E_LOG_SYNC_ACTION_T sync_action = E_LOG_SEM_WITH_MT; + char *sem_name = NULL; + char *ptr, *pname; + ACL_ARGV *env_argv; + ACL_VSTRING *log_buf; + int i; + + if (filename == NULL || *filename == 0) + return (-1); + + acl_snprintf(h_log->filename, sizeof(h_log->filename), "%s", filename); + + /* env: facility:x, priority:x, action:x, flush:x, limit_size:x, sync_action:x, sem_name:x */ + + ptr = getenv("SERVICE_ENV"); + if (ptr == NULL) + return (-1); + + env_argv = acl_argv_split(ptr, ",\t "); + if (env_argv == NULL) + return (-1); + if (env_argv->argc == 0) { + acl_argv_free(env_argv); + return (-1); + } + + log_buf = acl_vstring_alloc(256); + + for (i = 0; i < env_argv->argc; i++) { + pname = acl_argv_index(env_argv, i); + ptr = strchr(pname, ':'); + if (ptr == NULL) + continue; + *ptr++ = 0; + if (*ptr == 0) + continue; + + if (i == 0) + acl_vstring_sprintf(log_buf, "%s:%s", pname, ptr); + else + acl_vstring_sprintf_append(log_buf, ", %s:%s", pname, ptr); + + if (strcasecmp(pname, "logme") == 0) { + if (strcasecmp(ptr, "TRUE") == 0) + logme = 1; + } else if (strcasecmp(pname, "facility") == 0) { + facility_name = ptr; + } else if (strcasecmp(pname, "priority") == 0) { + if (strcasecmp(ptr, "E_LOG_NOLOG") == 0) + priority = E_LOG_NOLOG; + else if (strcasecmp(ptr, "E_LOG_EMERG") == 0) + priority = E_LOG_EMERG; + else if (strcasecmp(ptr, "E_LOG_ALERT") == 0) + priority = E_LOG_ALERT; + else if (strcasecmp(ptr, "E_LOG_CRIT") == 0) + priority = E_LOG_CRIT; + else if (strcasecmp(ptr, "E_LOG_ERR") == 0) + priority = E_LOG_ERR; + else if (strcasecmp(ptr, "E_LOG_WARNING") == 0) + priority = E_LOG_WARNING; + else if (strcasecmp(ptr, "E_LOG_NOTICE") == 0) + priority = E_LOG_NOTICE; + else if (strcasecmp(ptr, "E_LOG_INFO") == 0) + priority = E_LOG_INFO; + else if (strcasecmp(ptr, "E_LOG_DEBUG") == 0) + priority = E_LOG_DEBUG; + } else if (strcasecmp(pname, "action") == 0) { + if (strcasecmp(ptr, "E_LOG_PER_HOUR") == 0) + action = E_LOG_PER_HOUR; + else if (strcasecmp(ptr, "E_LOG_PER_DAY") == 0) + action = E_LOG_PER_DAY; + else if (strcasecmp(ptr, "E_LOG_PER_WEEK") == 0) + action = E_LOG_PER_WEEK; + else if (strcasecmp(ptr, "E_LOG_PER_MONTH") == 0) + action = E_LOG_PER_MONTH; + else if (strcasecmp(ptr, "E_LOG_PER_YEAR") == 0) + action = E_LOG_PER_YEAR; + else if (strcasecmp(ptr, "E_LOG_LIMIT_SIZE") == 0) + action = E_LOG_LIMIT_SIZE; + else if (strcasecmp(ptr, "E_LOG_SYSLOG") == 0) + action = E_LOG_SYSLOG; + } else if (strcasecmp(pname, "flush") == 0) { + if (strcasecmp(ptr, "sync_flush") == 0) + flush = 1; + else if (strcasecmp(ptr, "async_flush") == 0) + flush = 0; + } else if (strcasecmp(pname, "limit_size") == 0) { + limit_size = atoi(ptr); + } else if (strcasecmp(pname, "sync_action") == 0) { + if (strcasecmp(ptr, "E_LOG_NO_SYNC") == 0) + sync_action = E_LOG_NO_SYNC; + else if (strcasecmp(ptr, "E_LOG_THREAD_MUTEX") == 0) + sync_action = E_LOG_THREAD_MUTEX; + else if (strcasecmp(ptr, "E_LOG_FILE_LOCK") == 0) + sync_action = E_LOG_FILE_LOCK; + else if (strcasecmp(ptr, "E_LOG_SEM_WITH_MT") == 0) + sync_action = E_LOG_SEM_WITH_MT; + else if (strcasecmp(ptr, "E_LOG_FILE_APPEND_WITH_MT") == 0) + sync_action = E_LOG_FILE_APPEND_WITH_MT; + } else if (strcasecmp(pname, "sem_name") == 0) { + sem_name = ptr; + } + } + + if (action == E_LOG_LIMIT_SIZE) { + if (limit_size == 0) + limit_size = 512; /* set default size: 512 MB */ + } else + limit_size = 0; + + if (sync_action == E_LOG_SEM_WITH_MT) { + if (sem_name == NULL || *sem_name == 0) { + sem_name = acl_concatenate("/tmp/", acl_safe_basename(filename), ".sem", NULL); + } else + sem_name = acl_mystrdup(sem_name); + } else if (sem_name) { + sem_name = NULL; + } + + h_log->h_log = e_log_new2(h_log->filename, priority, action, + flush, limit_size, facility_name, sync_action, sem_name); + + if (sem_name) + acl_myfree(sem_name); + + if (logme) { + e_log2(h_log->h_log, "master_env: %s", acl_vstring_str(log_buf)); + } + + e_log2(h_log->h_log, "filename=%s, priority=%d, action=%d, flush=%d, " + "limit_size=%d, facility_name=%s, sync_action=%d, sem_name=%s", + h_log->filename, priority, action, + flush, limit_size, facility_name, sync_action, sem_name); + + if (log_buf) + acl_vstring_free(log_buf); + + return (0); +} + +static void __log_close(void *ctx acl_unused) +{ +} + +static void __log_write(void *ctx, const char *fmt, va_list ap) +{ + LOG_WRAP *h_log = (LOG_WRAP *) ctx; + + if (h_log->h_log) + e_vlog2(h_log->h_log, fmt, ap); +} + +static void elib_logger_set(void) +{ + LOG_WRAP *h_log; + + h_log = acl_mycalloc(1, sizeof(LOG_WRAP)); + if (h_log == NULL) + return; + + acl_msg_register(__log_open, __log_close, __log_write, (void *) h_log); + __log_wrap = h_log; +} + +static void elib_logger_end(void) +{ + if (__log_wrap == NULL) + return; + if (__log_wrap->h_log == NULL) + return; + acl_msg_info("service exit now"); + e_log_free(__log_wrap->h_log); + __log_wrap->h_log = NULL; +} +#endif + +static int logger_open(const char *filename, void *ctx) +{ + LOG_WRAP *h_log = (LOG_WRAP *) ctx; +#ifdef ACL_MS_WINDOWS + int flag = O_RDWR | O_CREAT | O_APPEND | O_BINARY; +#else + int flag = O_RDWR | O_CREAT | O_APPEND; +#endif + int mode = S_IREAD | S_IWRITE; + + if (filename == NULL || *filename == 0) + return (-1); + + acl_snprintf(h_log->filename, sizeof(h_log->filename), "%s", filename); + h_log->h_log = acl_vstream_fopen(h_log->filename, flag, mode, 1024); + if (h_log->h_log == NULL) + return (-1); + __pid = getpid(); + return (0); +} + +/* just for thread logger */ + +static int thread_logger_open(const char *filename, void *ctx) +{ + return (logger_open(filename, ctx)); +} + +static void thread_logger_close(void *ctx acl_unused) +{ +} + +static void thread_logger_write(void *ctx, const char *fmt, va_list ap) +{ + LOG_WRAP *h_log = (LOG_WRAP *) ctx; + char *pbuf; + + if (h_log->h_log) { + pbuf = acl_mymalloc(1024); + vsnprintf(pbuf, 1024, fmt, ap); + acl_aqueue_push(h_log->logger_queue, pbuf); + } +} + +static void *thread_logger_main(void *ctx) +{ + LOG_WRAP *h_log = (LOG_WRAP *) ctx; + ACL_AQUEUE *logger_queue = h_log->logger_queue; + static char pre_buf[256]; + static struct tm local_time; + static time_t now, last; + static int pre_len; + char *pbuf; + + while (1) { + pbuf = acl_aqueue_pop(logger_queue); + assert(pbuf != NULL); + if (h_log->h_log == NULL) + continue; + + time(&now); + if (now - last >= 1) { + last = now; + (void) localtime_r(&now, &local_time); + pre_len = snprintf(pre_buf, sizeof(pre_buf), + "\npid(%d) %d/%d/%d %d:%d:%d| ", __pid, + local_time.tm_year + 1900, local_time.tm_mon + 1, + local_time.tm_mday, local_time.tm_hour, + local_time.tm_min, local_time.tm_sec); + } + acl_vstream_writen(h_log->h_log, pre_buf, pre_len); + acl_vstream_writen(h_log->h_log, pbuf, strlen(pbuf)); + acl_myfree(pbuf); + } + + return (NULL); +} + +static void thread_logger_set(void) +{ + LOG_WRAP *h_log; + acl_pthread_attr_t attr; + acl_pthread_t tid; + + h_log = acl_mycalloc(1, sizeof(LOG_WRAP)); + if (h_log == NULL) + return; + + acl_msg_register(thread_logger_open, thread_logger_close, + thread_logger_write, (void*)h_log); + __log_wrap = h_log; + + h_log->logger_queue = acl_aqueue_new(); + acl_pthread_attr_init(&attr); + acl_pthread_create(&tid, &attr, thread_logger_main, h_log); +} + +static void thread_logger_end(void) +{ +} + +/* just for buffer logger */ + +static int buffer_logger_open(const char *filename, void *ctx) +{ + return (logger_open(filename, ctx)); +} + +static void buffer_logger_close(void *ctx acl_unused) +{ +} + +static void buffer_logger_write(void *ctx, const char *fmt, va_list ap) +{ + LOG_WRAP *h_log = (LOG_WRAP *) ctx; + static char buf[1024], pre_buf[256]; + static struct tm local_time; + static time_t now, last; + static int pre_len; + int n; + + if (h_log->h_log) { + time(&now); + if (now - last >= 1) { + last = now; + (void) localtime_r(&now, &local_time); + pre_len = snprintf(pre_buf, sizeof(pre_buf), + "\npid(%d) %d/%d/%d %d:%d:%d| ", __pid, + local_time.tm_year + 1900, local_time.tm_mon + 1, + local_time.tm_mday, local_time.tm_hour, + local_time.tm_min, local_time.tm_sec); + } + acl_vstream_buffed_writen(h_log->h_log, pre_buf, pre_len); + n = vsnprintf(buf, sizeof(buf), fmt, ap); + acl_vstream_buffed_writen(h_log->h_log, buf, n); + } +} + +static void buffed_logger_fflush(int event_type acl_unused, void *context) +{ + LOG_WRAP *h_log = (LOG_WRAP*) context; + + if (h_log->h_log != NULL) { + acl_vstream_fflush(h_log->h_log); + } + assert(h_log->aio); + (void) acl_aio_request_timer(h_log->aio, buffed_logger_fflush, h_log, 1); +} + +static void buffed_logger_set(ACL_AIO *aio) +{ + LOG_WRAP *h_log; + + assert(aio != NULL); + + h_log = acl_mycalloc(1, sizeof(LOG_WRAP)); + if (h_log == NULL) + return; + h_log->aio = aio; + + acl_msg_register(buffer_logger_open, buffer_logger_close, + buffer_logger_write, (void*)h_log); + (void) acl_aio_request_timer(aio, buffed_logger_fflush, h_log, 1); + __log_wrap = h_log; +} + +static void buffed_logger_end(void) +{ +} + +/* just for default logger */ +static int default_logger_open(const char *filename, void *ctx) +{ + return (logger_open(filename, ctx)); +} + +static void default_logger_close(void *ctx acl_unused) +{ +} + +static void default_logger_write(void *ctx, const char *fmt, va_list ap) +{ + LOG_WRAP *h_log = (LOG_WRAP *) ctx; + static char buf[1024], pre_buf[256]; + static struct tm local_time; + static time_t now, last; + static int pre_len; + int n; + + if (h_log->h_log) { + time(&now); + if (now - last >= 1) { + last = now; + (void) localtime_r(&now, &local_time); + pre_len = snprintf(pre_buf, sizeof(pre_buf), + "\npid(%d) %d/%d/%d %d:%d:%d| ", __pid, + local_time.tm_year + 1900, local_time.tm_mon + 1, + local_time.tm_mday, local_time.tm_hour, + local_time.tm_min, local_time.tm_sec); + } + acl_vstream_writen(h_log->h_log, pre_buf, pre_len); + n = vsnprintf(buf, sizeof(buf), fmt, ap); + acl_vstream_writen(h_log->h_log, buf, n); + } +} + +static void default_logger_set(void) +{ + LOG_WRAP *h_log; + + h_log = acl_mycalloc(1, sizeof(LOG_WRAP)); + if (h_log == NULL) + return; + + acl_msg_register(default_logger_open, default_logger_close, + default_logger_write, (void*)h_log); + __log_wrap = h_log; +} + +static void default_logger_end(void) +{ +} + +/* logger main */ +static char __logger_name[256]; + +void logger_set(const char *logger_name, ACL_AIO *aio) +{ + const char *myname = "logger_set"; + + ACL_SAFE_STRNCPY(__logger_name, logger_name, sizeof(__logger_name)); + if (strcasecmp(logger_name, "buffed_logger") == 0) + buffed_logger_set(aio); + else if (strcasecmp(logger_name, "default_logger") == 0) + default_logger_set(); + else if (strcasecmp(logger_name, "thread_logger") == 0) + thread_logger_set(); +#ifdef HAS_ELIB + else if (strcasecmp(logger_name, "elib_logger") == 0) + elib_logger_set(); +#endif + else { + printf("%s(%d): unknown logger name(%s)\r\n", + myname, __LINE__, logger_name); + return; + } +} + +void logger_end(void) +{ + if (strcasecmp(__logger_name, "buffed_logger") == 0) + buffed_logger_end(); + else if (strcasecmp(__logger_name, "default_logger") == 0) + default_logger_end(); + else if (strcasecmp(__logger_name, "thread_logger") == 0) + thread_logger_end(); +#ifdef HAS_ELIB + else if (strcasecmp(__logger_name, "elib_logger") == 0) + elib_logger_end(); +#endif +} diff --git a/app/jaws/global/logger.h b/app/jaws/global/logger.h new file mode 100644 index 000000000..e2dbc329a --- /dev/null +++ b/app/jaws/global/logger.h @@ -0,0 +1,17 @@ +#ifndef __LOGGER_INCLUDE_H__ +#define __LOGGER_INCLUDE_H__ + +#include "lib_acl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void logger_set(const char *logger_name, ACL_AIO *aio); +void logger_end(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/app/jaws/global/service.c b/app/jaws/global/service.c new file mode 100644 index 000000000..f87bf2576 --- /dev/null +++ b/app/jaws/global/service.c @@ -0,0 +1,104 @@ +#include "lib_acl.h" +#include "service.h" + +void service_free(SERVICE *service) +{ + if (service->dns_server) + dns_server_close(service->dns_server); + if (service->dns_table) + acl_htable_free(service->dns_table, NULL); + acl_myfree(service); +} + +SERVICE *service_alloc(const char *service_name, size_t size) +{ + const char *myname = "service_alloc"; + SERVICE *service; + + if (size < sizeof(SERVICE)) + acl_msg_fatal("%s(%d): size(%d) invalid", + myname, __LINE__, size); + service = (SERVICE *) acl_mycalloc(1, size); + /* 设置服务名称 */ + ACL_SAFE_STRNCPY(service->name, service_name, sizeof(service->name)); + return (service); +} + +void service_set_dns(SERVICE *service, ACL_AIO *aio, + const char *dns_list, int dns_lookup_timeout, + int dns_cache_limit, const char *hosts_list) +{ + const char *myname = "service_set_dns"; + ACL_ARGV *argv; + ACL_ITER iter; + + /* 创建DNS域名查询对象:外挂式查询或非阻塞式查询 */ + + if (!dns_list || !strcmp(dns_list, "")) { + int nthreads = 100, idle = 60; + + /* 创建外挂式DNS查询对象 */ + service->dns_server = dns_server_create(aio, 300); + service->dns_table = acl_htable_create(100, 0); + /* 创建半驻留线程池对象 */ + service->wq = acl_workq_create(nthreads, idle, NULL, NULL); + return; + } + + /* 采用直接发送DNS协议方式进行查询的对象 */ + + argv = acl_argv_split(dns_list, ",; \t"); + + service->dns_handle = acl_dns_create(aio, dns_lookup_timeout); + if (dns_cache_limit > 0) + acl_dns_open_cache(service->dns_handle, dns_cache_limit); + + /* 添加DNS服务器地址 */ + + acl_foreach(iter, argv) { + char *addr = (char*) iter.data; + char *ptr1 = strchr(addr, ':'), *ptr2; + int port, netmask = 24; + + if (ptr1) { + *ptr1++ = 0; + ptr2 = strchr(ptr1, ':'); + if (ptr2) { + *ptr2++ = 0; + netmask = atoi(ptr2); + if (netmask <= 0 || netmask >= 32) + netmask = 24; + } + port = atoi(ptr1); + if (port <= 0 || port >= 65535) + port = 53; + } else + port = 53; + + acl_msg_info("%s(%d): add dns addr (%s:%d)", + myname, __LINE__, addr, port); + acl_dns_add_dns(service->dns_handle, addr, port, netmask); + } + + acl_argv_free(argv); + + /* 添加 hosts 中的静态配置域名 */ + if (hosts_list && *hosts_list) + dns_hosts_load(service->dns_handle, hosts_list); +} + +static int __timer = 10; + +static void service_gc_timer(int event_type acl_unused, void *context) +{ + int n; + ACL_AIO *aio = (ACL_AIO*) context; + n = acl_mem_slice_gc(); + acl_aio_request_timer(aio, service_gc_timer, aio, __timer); +} + +void service_set_gctimer(ACL_AIO *aio, int timer) +{ + __timer = timer; + acl_aio_request_timer(aio, service_gc_timer, aio, timer); +} diff --git a/app/jaws/global/service.h b/app/jaws/global/service.h new file mode 100644 index 000000000..e9c4236f9 --- /dev/null +++ b/app/jaws/global/service.h @@ -0,0 +1,42 @@ +#ifndef __SERVICE_INCLUDE_H__ +#define __SERVICE_INCLUDE_H__ + +#include "service_struct.h" + +#ifdef __cplusplus +extern "C" +#endif + +#define TRACE do { \ + acl_msg_info("%s(%d), %s", __FILE__, __LINE__, __FUNCTION__); \ +} while (0) + +/* in service.c */ +void service_free(SERVICE *service) ; +SERVICE *service_alloc(const char *service_name, size_t size); +void service_set_dns(SERVICE *service, ACL_AIO *aio, + const char *dns_list, int dns_lookup_timeout, + int dns_cache_limit, const char *hosts_list); +void service_set_gctimer(ACL_AIO *aio, int timer); + +/* in service_load.c */ +void service_load(ACL_FIFO *service_modules, const char *dlname); +void service_load_all(ACL_FIFO *service_modules, const char *dlnames); +void service_unload_all(void); + +/* in forward.c */ +void forward_complete(CLIENT_ENTRY *entry); +void forward_start(CLIENT_ENTRY *entry); + +/* in client_entry.c */ +void client_entry_free(CLIENT_ENTRY *entry); +CLIENT_ENTRY *client_entry_new(SERVICE *service, size_t size, ACL_ASTREAM *client); +void client_entry_set_server(CLIENT_ENTRY *entry, ACL_ASTREAM *server); +int client_entry_detach(CLIENT_ENTRY *entry, ACL_VSTREAM *stream); +int client_entry_detach3(CLIENT_ENTRY *entry, ACL_VSTREAM *stream, int auto_free); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/app/jaws/global/service_conf.c b/app/jaws/global/service_conf.c new file mode 100644 index 000000000..2e8932d60 --- /dev/null +++ b/app/jaws/global/service_conf.c @@ -0,0 +1,49 @@ +#include "lib_acl.h" +#include "service_conf.h" + +int var_cfg_debug_mem; + +ACL_CONFIG_BOOL_TABLE service_conf_bool_tab[] = { + /* TODO: you can add configure variables of int type here */ + + { "debug_mem", 0, &var_cfg_debug_mem }, + { 0, 0, 0 } +}; + +int var_cfg_nthreads; +int var_cfg_dns_lookup_timeout; +int var_cfg_dns_cache_limit; +int var_cfg_aio_buf_size; +int var_cfg_server_conn_limit; + +ACL_CONFIG_INT_TABLE service_conf_int_tab[] = { + /* TODO: you can add configure variables of int type here */ + /* example: { "client_idle_limit", 60, &var_cfg_client_idle_limit, 0, 0 }, */ + + { "nthreads", 2, &var_cfg_nthreads, 0, 0 }, + { "dns_lookup_timeout", 5, &var_cfg_dns_lookup_timeout, 0, 0 }, + { "dns_cache_limit", 10000, &var_cfg_dns_cache_limit, 0 , 0 }, + { "aio_buf_size", 8192, &var_cfg_aio_buf_size, 0, 0 }, + { "server_conn_limit", 1024, &var_cfg_server_conn_limit, 0, 0 }, + { 0, 0, 0, 0, 0 } +}; + +char *var_cfg_dns_list; +char *var_cfg_hosts_list; +char *var_cfg_proto_name; +char *var_cfg_service_dlnames; +char *var_cfg_service_cfgdir; +char *var_cfg_bind_ip_list; + +ACL_CFG_STR_TABLE service_conf_str_tab[] = { + /* TODO: you can add configure variables of (char *) type here */ + /* example: { "mysql_dbaddr", "127.0.0.1:3306", &var_cfg_mysql_dbaddr }, */ + + { "dns_list", "", &var_cfg_dns_list }, + { "hosts_list", "", &var_cfg_hosts_list }, + { "proto_name", "http", &var_cfg_proto_name }, + { "service_dlnames", "/opt/jaws/module", &var_cfg_service_dlnames }, + { "service_cfgdir", "/opt/jaws/conf/module", &var_cfg_service_cfgdir }, + { "bind_ip_list", "", &var_cfg_bind_ip_list }, + { 0, 0, 0 } +}; diff --git a/app/jaws/global/service_conf.h b/app/jaws/global/service_conf.h new file mode 100644 index 000000000..79a4034d1 --- /dev/null +++ b/app/jaws/global/service_conf.h @@ -0,0 +1,28 @@ +#ifndef __SERVICE_CONF_INCLUDE_H__ +#define __SERVICE_CONF_INCLUDE_H__ + +/* 配置文件项 */ +/* in service_main.c */ + +extern int var_cfg_debug_mem; + +extern ACL_CONFIG_BOOL_TABLE service_conf_bool_tab[]; + +extern int var_cfg_nthreads; +extern int var_cfg_dns_lookup_timeout; +extern int var_cfg_dns_cache_limit; +extern int var_cfg_aio_buf_size; +extern int var_cfg_server_conn_limit; + +extern ACL_CONFIG_INT_TABLE service_conf_int_tab[]; + +extern char *var_cfg_dns_list; +extern char *var_cfg_hosts_list; +extern char *var_cfg_proto_name; +extern char *var_cfg_service_dlnames; +extern char *var_cfg_service_cfgdir; +extern char *var_cfg_bind_ip_list; + +extern ACL_CONFIG_STR_TABLE service_conf_str_tab[]; + +#endif diff --git a/app/jaws/global/service_ipc.c b/app/jaws/global/service_ipc.c new file mode 100644 index 000000000..e71f3cc08 --- /dev/null +++ b/app/jaws/global/service_ipc.c @@ -0,0 +1,155 @@ +#include "lib_acl.h" +#include "service_struct.h" +#include "service.h" +#include "service_conf.h" +#include "service_ipc.h" + +typedef struct { + acl_pthread_t tid; + ACL_MSGIO *mio; + ACL_AIO *aio; + SERVICE *service; + int n; +} IPC_THREAD; + +typedef struct { + ACL_SOCKET fd; + ACL_AIO *aio; + int i; +} IPC_CTX; + +#define MSG_LISTENER_ACCEPT (ACL_MSGIO_USER + 100) +#define MSG_IPC_ACCEPT (ACL_MSGIO_USER + 101) + +static IPC_THREAD *__ipc_threads = NULL; +static int __ipc_nthread = 0; +static int __ipc_ithread = 0; + +static ACL_MSGIO *__ipc_listener = NULL; +static char __ipc_addr[256]; +static module_service_main_fn __service_callback = NULL; + +/* 某个线程服务实例接收到一个新的远程客户端连接请求 */ + +static int msg_ipc_accept(int msg_type acl_unused, ACL_MSGIO *mio acl_unused, + const ACL_MSGIO_INFO *info, void *arg) +{ + IPC_CTX ctx; + ACL_VSTREAM *stream; + ACL_ASTREAM *client; + SERVICE *service = (SERVICE*) arg; + + memcpy(&ctx, acl_vstring_str(info->body.buf), ACL_VSTRING_LEN(info->body.buf)); + + /* 打开异步流 */ + stream = acl_vstream_fdopen(ctx.fd, O_RDWR, var_cfg_aio_buf_size, + 0, ACL_VSTREAM_TYPE_SOCK); + client = acl_aio_open(ctx.aio, stream); + + /* 开始处理该客户端连接 */ + __service_callback(service, client); + return (0); +} + +/* 单线程实例非阻塞处理过程 */ + +static void *service_thread(void *arg) +{ + ACL_MSGIO *ipc_client = (ACL_MSGIO*) arg; + ACL_AIO *aio = acl_msgio_aio(ipc_client); + + /* 内存垃圾回收定时器 */ + service_set_gctimer(aio, 10); + + /* 进入事件循环 */ + while (1) { + acl_aio_loop(aio); + } + + return (NULL); +} + +/* 主线程收到新的连接到达消息 */ + +void service_ipc_init(ACL_AIO *aio, int nthreads) +{ + const char *myname = "service_ipc_init"; + + __ipc_nthread = nthreads; + __ipc_threads = (IPC_THREAD*) acl_mycalloc(nthreads, sizeof(IPC_THREAD)); + + __ipc_listener = acl_msgio_listen(aio, NULL); + if (__ipc_listener == NULL) + acl_msg_fatal("%s(%d): acl_msgio_listen error(%s)", + myname, __LINE__, acl_last_serror()); + acl_msgio_addr(__ipc_listener, __ipc_addr, sizeof(__ipc_addr)); +} + +void service_ipc_add_service(SERVICE *service, + module_service_main_fn service_callback) +{ + const char *myname = "service_ipc_add_service"; + acl_pthread_attr_t attr; + ACL_AIO *aio = service->aio; + ACL_MSGIO *ipc_client; + + if (service_callback == NULL) + acl_msg_fatal("%s(%d): service_callback null", myname, __LINE__); + __service_callback = service_callback; + + if (__ipc_ithread >= __ipc_nthread) + acl_msg_fatal("%s(%d): __ipc_ithread(%d) >= __ipc_nthread(%d)", + myname, __LINE__, __ipc_ithread, __ipc_nthread); + + /* 创建非阻塞线程池实例,每个线程为一个单独的非阻塞实例 */ + + acl_pthread_attr_init(&attr); + acl_pthread_attr_setdetachstate(&attr, 1); + + /* 连接消息服务器 */ +#if 1 + ipc_client = acl_msgio_connect(aio, __ipc_addr, 0); + if (ipc_client == NULL) + acl_msg_fatal("%s(%d): connect server(%s) error(%s)", + myname, __LINE__, __ipc_addr, acl_last_serror()); +#else + ipc_client = acl_msgio_connect(NULL, __ipc_addr, 0); + if (ipc_client == NULL) + acl_msg_fatal("%s(%d): connect server(%s) error(%s)", + myname, __LINE__, __ipc_addr, acl_last_serror()); + /* 设为非阻塞模式 */ + acl_msgio_set_noblock(aio, ipc_client); +#endif + /* 注册消息事件 */ + acl_msgio_reg(ipc_client, MSG_IPC_ACCEPT, msg_ipc_accept, service); + + /* 记录服务端IPC通道 */ + __ipc_threads[__ipc_ithread].mio = acl_msgio_accept(__ipc_listener); + __ipc_threads[__ipc_ithread].aio = aio; + __ipc_threads[__ipc_ithread].service = service; + acl_non_blocking(ACL_VSTREAM_SOCK(acl_msgio_vstream(__ipc_threads[__ipc_ithread].mio)), ACL_BLOCKING); + /* 创建单线程非阻塞实例 */ + acl_pthread_create(&__ipc_threads[__ipc_ithread].tid, &attr, + service_thread, ipc_client); + __ipc_ithread++; +} + +void service_ipc_add(ACL_SOCKET fd) +{ + IPC_CTX ctx; + + /* 轮循下一个实例线程 */ + if (__ipc_ithread >= __ipc_nthread) + __ipc_ithread = 0; + + /* 构造消息数据 */ + + ctx.fd = fd; + ctx.aio = __ipc_threads[__ipc_ithread].aio; + + /* 发送消息 */ + acl_msgio_send(__ipc_threads[__ipc_ithread].mio, + MSG_IPC_ACCEPT, &ctx, sizeof(IPC_CTX)); + __ipc_threads[__ipc_ithread].n++; + __ipc_ithread++; +} diff --git a/app/jaws/global/service_ipc.h b/app/jaws/global/service_ipc.h new file mode 100644 index 000000000..1753d25a6 --- /dev/null +++ b/app/jaws/global/service_ipc.h @@ -0,0 +1,20 @@ +#ifndef __SERVICE_IPC_INCLUDE_H__ +#define __SERVICE_IPC_INCLUDE_H__ + +#include "lib_acl.h" +#include "service_struct.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void service_ipc_init(ACL_AIO *aio, int nthreads); +void service_ipc_add_service(SERVICE *service, + module_service_main_fn service_callback); +void service_ipc_add(ACL_SOCKET fd); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/app/jaws/global/service_load.c b/app/jaws/global/service_load.c new file mode 100644 index 000000000..84c21347e --- /dev/null +++ b/app/jaws/global/service_load.c @@ -0,0 +1,86 @@ +#include "lib_acl.h" +#include "service.h" + +typedef struct { + ACL_DLL_HANDLE handle; +} DLL_HANDLE; + +static ACL_FIFO *__handles = NULL; + +void service_load(ACL_FIFO *service_modules, const char *dlname) +{ + const char *myname = "service_load"; + DLL_HANDLE *dll_handle; + ACL_DLL_HANDLE handle; + MODULE_SERVICE *module_ptr, module; + + if (dlname == NULL || *dlname == 0) + return; + + acl_msg_info("%s(%d): begin load %s now ...", __FUNCTION__, __LINE__, dlname); + handle = acl_dlopen(dlname); + if (handle == NULL) { + acl_msg_error("%s(%d): load %s error(%s)", + myname, __LINE__, dlname, acl_last_serror()); + return; + } + + acl_msg_info("%s(%d): load %s ok.", __FUNCTION__, __LINE__, dlname); + + /* 添加请求过滤器 */ + + module.mod_init = (module_service_init_fn) (intptr_t) + acl_dlsym(handle, "module_service_init"); + module.mod_create = (module_service_create_fn) (intptr_t) + acl_dlsym(handle, "module_service_create"); + module.mod_main = (module_service_main_fn) (intptr_t) + acl_dlsym(handle, "module_service_main"); + if (module.mod_create && module.mod_main) { + module_ptr = (MODULE_SERVICE*) acl_mycalloc(1, sizeof(MODULE_SERVICE)); + module_ptr->mod_init = module.mod_init; + module_ptr->mod_create = module.mod_create; + module_ptr->mod_main = module.mod_main; + acl_fifo_push(service_modules, module_ptr); + } + + dll_handle = (DLL_HANDLE*) acl_mycalloc(1, sizeof(DLL_HANDLE)); + dll_handle->handle = handle; + if (__handles == NULL) + __handles = acl_fifo_new(); + acl_fifo_push(__handles, dll_handle); +} + +void service_load_all(ACL_FIFO *service_modules, const char *dlnames) +{ + ACL_ARGV *argv; + ACL_ITER iter; + + if (dlnames == NULL || *dlnames == 0) + return; + + argv = acl_argv_split(dlnames, " \t;"); + acl_foreach(iter, argv) { + const char *dlname = (const char*) iter.data; + + service_load(service_modules, dlname); + } + + acl_argv_free(argv); +} + +void service_unload_all() +{ + ACL_ITER iter; + + if (__handles == NULL) + return; + + acl_foreach(iter, __handles) { + DLL_HANDLE *handle = (DLL_HANDLE*) iter.data; + acl_dlclose(handle->handle); + acl_myfree(handle); + } + + acl_fifo_free(__handles, NULL); + __handles = NULL; +} diff --git a/app/jaws/global/service_main.c b/app/jaws/global/service_main.c new file mode 100644 index 000000000..9c866c118 --- /dev/null +++ b/app/jaws/global/service_main.c @@ -0,0 +1,217 @@ +#include "lib_acl.h" +#include "service.h" +#include "service_conf.h" +#include "service_ipc.h" +#include "service_main.h" + +/*----------------------------------------------------------------------------*/ + +static ACL_FIFO *__service_modules = NULL; +static SERVICE *__service = NULL; +static module_service_main_fn __service_callback = NULL; +static ACL_DLL_ENV __dll_env; +ACL_MEM_SLICE *var_mem_slice = NULL; + +static SERVICE *service_create(ACL_AIO *aio, + ACL_FIFO *service_modules, ACL_ARGV *ip_argv) +{ + const char *myname = "service_create"; + ACL_FIFO *services; + SERVICE *service, *curr_service = NULL; + ACL_ITER iter; + + /* 关闭持续读功能 */ + acl_aio_set_keep_read(aio, 0); + + services = acl_fifo_new(); + + /* 加载所有的服务模块 */ + acl_foreach(iter, service_modules) { + MODULE_SERVICE *module = (MODULE_SERVICE*) iter.data; + + service = module->mod_create(); + if (service == NULL) + continue; + service->aio = aio; + service->module = module; + service->rw_timeout = 120; + service->conn_timeout = 10; + service_set_dns(service, aio, + var_cfg_dns_list, + var_cfg_dns_lookup_timeout, + var_cfg_dns_cache_limit, + var_cfg_hosts_list); + /* 创建连接池缓存对象 */ + service->conn_cache = conn_cache_create(aio, var_cfg_server_conn_limit); + + if (ip_argv) { + ACL_ITER iter2; + int i = 0; + + service->bind_ip_list = (char**) + acl_mycalloc(ip_argv->argc + 1, sizeof(char*)); + service->bind_ip_index = 0; + + acl_foreach(iter2, ip_argv) { + char *ip = (char*) iter2.data; + service->bind_ip_list[i++] = acl_mystrdup(ip); + } + service->bind_ip_list[i] = NULL; + } else { + service->bind_ip_list = NULL; + service->bind_ip_index = -1; + } + acl_fifo_push(services, service); + } + + if (acl_fifo_size(service_modules) == 0) + acl_msg_fatal("%s(%d): no service available", myname, __LINE__); + + /* 设置协议处理方式 */ + acl_foreach(iter, services) { + service = (SERVICE*) iter.data; + + if (strcasecmp(var_cfg_proto_name, service->name) == 0) { + curr_service = service; + __service_callback = service->module->mod_main; + break; + } + } + + acl_fifo_free(services, NULL); + + if (curr_service == NULL) + acl_msg_fatal("%s(%d): unknown protocol name(%s)", + myname, __LINE__, var_cfg_proto_name); + if (__service_callback == NULL) + acl_msg_fatal("%s(%d): __service_callback null", + myname, __LINE__); + return (curr_service); +} + +static void gc_timer(int event_type acl_unused, void *context) +{ + ACL_AIO *aio = (ACL_AIO *) context; + + acl_mem_slice_delay_destroy(); + /* 设定定时器定时清理垃圾回收器 */ + acl_aio_request_timer(aio, gc_timer, aio, 2); +} + +void service_init(ACL_AIO *aio, ACL_FIFO *modules) +{ + const char *myname = "service_init"; + ACL_ARGV *ip_argv = NULL; + ACL_ITER iter; + + if (var_cfg_bind_ip_list && strcmp(var_cfg_bind_ip_list, "") != 0) { + ip_argv = acl_argv_split(var_cfg_bind_ip_list, ",\t "); + } + + if (var_cfg_aio_buf_size > 0) + acl_aio_set_rbuf_size(aio, var_cfg_aio_buf_size); + + memset(&__dll_env, 0, sizeof(ACL_DLL_ENV)); + /* + __dll_env.logfp = acl_log_fp(); + */ + __dll_env.mem_slice = var_mem_slice; + if (var_mem_slice) { + /* 设定定时器定时清理垃圾回收器 */ + acl_aio_request_timer(aio, gc_timer, aio, 2); + } + + if (__dll_env.mem_slice) + acl_msg_info("%s(%d): use mem_slice", myname, __LINE__); + else + acl_msg_info("%s(%d): no use mem_slice", myname, __LINE__); + + if (var_cfg_debug_mem == 1) { + acl_memory_debug_start(); + acl_memory_debug_stack(1); + } else if (var_cfg_debug_mem == 2) { + __dll_env.mmd = acl_debug_malloc_init(NULL, "service_log.txt"); + } else if (var_cfg_debug_mem == 3) { + acl_memory_debug_start(); + acl_memory_debug_stack(1); + __dll_env.mmd = acl_debug_malloc_init(NULL, "service_log.txt"); + } + +#ifdef JAWS_STATIC + if (modules == NULL) + acl_msg_fatal("%s(%d): modules null", myname, __LINE__); + __service_modules = modules; +#else + (void) modules; + __service_modules = acl_fifo_new(); + service_load_all(__service_modules, var_cfg_service_dlnames); +#endif + + /* 初始化所有加载模块 */ + acl_foreach(iter, __service_modules) { + MODULE_SERVICE *module = (MODULE_SERVICE*) iter.data; + module->mod_init(&__dll_env, var_cfg_service_cfgdir); + } + + if (var_cfg_nthreads > 1) { + int i, event_mode = acl_aio_event_mode(aio); + SERVICE *service; + + /* 初始化 IPC 通道 */ + service_ipc_init(aio, var_cfg_nthreads); + + for (i = 0; i < var_cfg_nthreads; i++) { + ACL_AIO *aio_thr; + + /* 创建单独运行的线程实例的异步句柄 */ + aio_thr = acl_aio_create(event_mode); + if (var_cfg_aio_buf_size > 0) + acl_aio_set_rbuf_size(aio, var_cfg_aio_buf_size); + service = service_create(aio_thr, __service_modules, ip_argv); + service_ipc_add_service(service, __service_callback); + } + } else { + __service = service_create(aio, __service_modules, ip_argv); + } + + if (ip_argv) + acl_argv_free(ip_argv); + + /* 内存垃圾回收定时器 */ + service_set_gctimer(aio, 10); +} + +void service_exit(void) +{ + const char *myname = "service_exit"; + + /* XXX: 在使用内存切片方式时,如果卸载动态加载的库会出现 core 文件,奇怪:) */ + /* + * service_unload_all(); + */ + acl_msg_info("%s(%d): jaws exit now", myname, __LINE__); +} + +int service_main(ACL_SOCKET fd, ACL_AIO *aio) +{ + if (var_cfg_debug_mem) + acl_msg_info("total alloc: %d", acl_mempool_total_allocated()); + +#ifdef ACL_UNIX + acl_close_on_exec(fd, 1); +#endif + if (var_cfg_nthreads > 1) { + /* 多线程模式下,向各个实例线程发送新的连接 */ + service_ipc_add(fd); + } else { + ACL_VSTREAM *vstream; + ACL_ASTREAM *astream; + + /* 在单线程模式下打开异步流 */ + vstream = acl_vstream_fdopen(fd, O_RDWR, var_cfg_aio_buf_size, + 0, ACL_VSTREAM_TYPE_SOCK); + astream = acl_aio_open(aio, vstream); + __service_callback(__service, astream); + } + return (0); +} diff --git a/app/jaws/global/service_main.h b/app/jaws/global/service_main.h new file mode 100644 index 000000000..7c926cf1c --- /dev/null +++ b/app/jaws/global/service_main.h @@ -0,0 +1,35 @@ +#ifndef __SERVICE_MAIN_INCLUDE_H__ +#define __SERVICE_MAIN_INCLUDE_H__ + +#include "lib_acl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* 全局变量 */ +extern ACL_MEM_SLICE *var_mem_slice; + +/** + * 初始化函数,服务器模板框架启动后仅调用该函数一次 + * @param aio {ACL_AIO*} 异步框架句柄 + */ +extern void service_init(ACL_AIO *aio, ACL_FIFO *modules); + +/** + * 进程退出时的回调函数 + */ +extern void service_exit(void); + +/** + * 协议处理函数入口 + * @param fd {ACL_SOCKET} 客户端数据连接 + * @param aio {ACL_AIO*} 异步框架句柄 + */ +extern int service_main(ACL_SOCKET fd, ACL_AIO *aio); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/app/jaws/global/service_struct.h b/app/jaws/global/service_struct.h new file mode 100644 index 000000000..5df0c3859 --- /dev/null +++ b/app/jaws/global/service_struct.h @@ -0,0 +1,103 @@ +#ifndef __SERVICE_STRUCT_INCLUDE_H__ +#define __SERVICE_STRUCT_INCLUDE_H__ + +#include "lib_acl.h" +#include "conn_cache.h" +#include "dns.h" + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct SERVICE SERVICE; +typedef struct CLIENT_ENTRY CLIENT_ENTRY; + +/* 动态库加载函数类型定义 */ + +/* 服务初始化函数类型定义 */ +typedef void (*module_service_init_fn)(ACL_DLL_ENV *dll_env, const char *cfgdir); +/* 服务创建函数类型定义 */ +typedef SERVICE *(*module_service_create_fn)(void); +/* 服务入口函数类型定义 */ +typedef void (*module_service_main_fn)(SERVICE *service, ACL_ASTREAM *stream); + +typedef struct { + module_service_init_fn mod_init; + module_service_create_fn mod_create; + module_service_main_fn mod_main; +} MODULE_SERVICE; + +struct SERVICE { + char name[256]; /* 服务名称 */ + ACL_AIO *aio; /* 异步IO句柄 */ + ACL_WORK_QUEUE *wq; /* 为了兼容老的外挂模块所需要的线程池句柄 */ + ACL_ASTREAM *sstream; /* 监听套接口 */ + int conn_timeout; /* 默认的连接超时时间 */ + int rw_timeout; /* 默认的IO超时时间 */ + ACL_DNS *dns_handle; /* 采用直接发送DNS协议方式查询 */ + DNS_SERVER *dns_server; /* DNS查询句柄 */ + ACL_HTABLE *dns_table; /* DNS查询对象哈希表 */ + char local_addr[256]; /* 监听的本地地址 */ + char **bind_ip_list; /* 在连接服务器时允许绑定本机的IP地址列表 */ + int bind_ip_index; /* 当前需要绑定的IP */ + + CONN_CACHE *conn_cache; /* 长连接连接池对象 */ + MODULE_SERVICE *module; /* 所属的服务模块 */ +}; + +typedef struct DNS_RING { + char domain_key[256]; + ACL_RING ring; + int nrefer; +} DNS_RING; + +struct CLIENT_ENTRY { + SERVICE *service; /* 指向异步代理句柄 */ + ACL_ASTREAM *client; /* 来自于客户端的连接流 */ + ACL_ASTREAM *server; /* 连接至服务端的连接流 */ + + int nrefer; /* 引用计数 */ + + ACL_RING dns_entry; /* DNS查询表的某个链结点 */ + char domain_key[256]; /* 域名(小写) */ + char domain_addr[64]; /* 域名所对应的一个IP地址 */ + + DNS_CTX dns_ctx; /* 与服务器域名相关的地址信息 */ + int ip_idx; /* 当前所引用的IP地址的索引 */ + int ip_ntry; /* 重试 IP 次数 */ + int server_port; /* 服务端PORT */ + char client_ip[32]; /* 客户端IP地址 */ + int client_port; /* 服务端PORT */ + const char *dns_errmsg; + + struct { + time_t begin; /* 会话开始时间截 */ + time_t stamp; /* 动态改变的时间截 */ + + time_t dns_lookup; /* DNS查询时间(以秒为单位) */ + time_t connect; /* 连接服务器的时间(以秒为单位) */ + } tm; + + int flag_has_replied; + + int flag_conn_reuse; /* 重复利用连接池中的连接 */ + int nretry_on_error; /* 出错重试次数 */ +#define MAX_RETRIED 10 + + void (*free_fn)(CLIENT_ENTRY*); + void (*nslookup_notify_fn)(CLIENT_ENTRY*, int); +#define NSLOOKUP_OK 0 +#define NSLOOKUP_ERR -1 + + int (*connect_notify_fn)(CLIENT_ENTRY*); + void (*connect_timeout_fn)(CLIENT_ENTRY*); + void (*connect_error_fn)(CLIENT_ENTRY*); +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/app/jaws/global/string.c b/app/jaws/global/string.c new file mode 100644 index 000000000..18020ddf7 --- /dev/null +++ b/app/jaws/global/string.c @@ -0,0 +1,25 @@ +#include + +#include "string_patch.h" + +#ifdef HAVE_NO_STRCASESTR +char *strcasestr(char *haystack, char *needle) +{ + char *p, *startn = 0, *np = 0; + + for (p = haystack; *p; p++) { + if (np) { + if (toupper(*p) == toupper(*np)) { + if (!*++np) + return startn; + } else + np = 0; + } else if (toupper(*p) == toupper(*needle)) { + np = needle + 1; + startn = p; + } + } + + return 0; +} +#endif diff --git a/app/jaws/global/string_patch.h b/app/jaws/global/string_patch.h new file mode 100644 index 000000000..f462bb455 --- /dev/null +++ b/app/jaws/global/string_patch.h @@ -0,0 +1,16 @@ +#ifndef __STRING_PATCH_INCLUDE_H__ +#define __STRING_PATCH_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" +#endif + +#ifdef HAVE_NO_STRCASESTR +char *strcasestr(char *haystack, char *needle); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/app/jaws/global/sys_patch.c b/app/jaws/global/sys_patch.c new file mode 100644 index 000000000..7aa9d1310 --- /dev/null +++ b/app/jaws/global/sys_patch.c @@ -0,0 +1,17 @@ +#include "lib_acl.h" +#include +#include "sys_patch.h" + +#ifdef ACL_MS_WINDOWS + +struct tm *localtime_r(const time_t *timep, struct tm *result) +{ + struct tm *tmp; + tmp = localtime(timep); + if (result) + memcpy(result, tmp, sizeof(struct tm)); + return (tmp); +} + +#endif + diff --git a/app/jaws/global/sys_patch.h b/app/jaws/global/sys_patch.h new file mode 100644 index 000000000..db6975eac --- /dev/null +++ b/app/jaws/global/sys_patch.h @@ -0,0 +1,19 @@ +#ifndef __SYS_PATCH_INCLUDE_H__ +#define __SYS_PATCH_INCLUDE_H__ + +#include "lib_acl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef ACL_MS_WINDOWS +struct tm *localtime_r(const time_t *timep, struct tm *result); +#endif + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/app/jaws/include/ctrl/DialogExpand.h b/app/jaws/include/ctrl/DialogExpand.h new file mode 100644 index 000000000..d8bd64a15 --- /dev/null +++ b/app/jaws/include/ctrl/DialogExpand.h @@ -0,0 +1,24 @@ +#pragma once + +class AFX_EXT_CLASS CDialogExpand +{ +public: + CDialogExpand(void); + CDialogExpand(CDialog *pDialog, int nResourceID, BOOL bVertical); + ~CDialogExpand(void); + + void Init(CDialog *pDialog, int nResourceID, BOOL bVertical); + void Expand(BOOL bExpand); +private: + BOOL m_bVertical; + int m_nResourceID; + CRect m_rcHorizontalLarge; + CRect m_rcHorizontalSmall; + CRect m_rcVerticalLarge; + CRect m_rcVerticalSmall; + CDialog *m_pDialog; + + void VerticalExpand(BOOL bExpand); + void HorizontalExpand(BOOL bExpand); + void EnableVisibleChildren(BOOL bVertical, int height); +}; diff --git a/app/jaws/include/ctrl/RegRun.h b/app/jaws/include/ctrl/RegRun.h new file mode 100644 index 000000000..836c9ebfb --- /dev/null +++ b/app/jaws/include/ctrl/RegRun.h @@ -0,0 +1,20 @@ +#pragma once +#include + +class AFX_EXT_CLASS CRegRun +{ +public: + CRegRun(void); + CRegRun(const char *procname); + ~CRegRun(void); + void Init(const char *procname); + + BOOL AutoRun(BOOL bAutoRun, const char *procname); + BOOL IfAutoRun(void); + +public: + CString m_sErrMsg; + int m_nErrno; +private: + CString m_sRegName; +}; diff --git a/app/jaws/include/ctrl/SingleCtrl.h b/app/jaws/include/ctrl/SingleCtrl.h new file mode 100644 index 000000000..112ec7f9c --- /dev/null +++ b/app/jaws/include/ctrl/SingleCtrl.h @@ -0,0 +1,19 @@ +#ifndef __SINGLECTRL_INCLUDE_H__ +#define __SINGLECTRL_INCLUDE_H__ + +class AFX_EXT_CLASS CSingleCtrl +{ +public: + CSingleCtrl(const char *pExeName); + ~CSingleCtrl() {}; + + BOOL Check(); + void Register(); + void Remove(); +protected: + CSingleCtrl() {}; +private: + CString m_sExeName; +}; + +#endif \ No newline at end of file diff --git a/app/jaws/include/ctrl/TrayIcon.h b/app/jaws/include/ctrl/TrayIcon.h new file mode 100644 index 000000000..04a629beb --- /dev/null +++ b/app/jaws/include/ctrl/TrayIcon.h @@ -0,0 +1,38 @@ +//////////////////////////////////////////////////////////////// +// CTrayIcon Copyright 1996 Microsoft Systems Journal. +// +// If this code works, it was written by Paul DiLascia. +// If not, I don't know who wrote it. + +#ifndef _TRAYICON_H +#define _TRAYICON_H + +//////////////// +// CTrayIcon manages an icon in the Windows 95 system tray. +// +class AFX_EXT_CLASS CTrayIcon : public CCmdTarget { +protected: + DECLARE_DYNAMIC(CTrayIcon) + NOTIFYICONDATA m_nid; // struct for Shell_NotifyIcon args + +public: + CTrayIcon(UINT uID); + ~CTrayIcon(); + + // Call this to receive tray notifications + void SetNotificationWnd(CWnd* pNotifyWnd, UINT uCbMsg); + + // SetIcon functions. To remove icon, call SetIcon(0) + // + BOOL SetIcon(UINT uID); // main variant you want to use + BOOL SetIcon(HICON hicon, LPCSTR lpTip); + BOOL SetIcon(LPCTSTR lpResName, LPCSTR lpTip) + { return SetIcon(lpResName ? + AfxGetApp()->LoadIcon(lpResName) : NULL, lpTip); } + BOOL SetStandardIcon(LPCTSTR lpszIconName, LPCSTR lpTip) + { return SetIcon(::LoadIcon(NULL, lpszIconName), lpTip); } + + virtual LRESULT OnTrayNotification(WPARAM uID, LPARAM lEvent); +}; + +#endif diff --git a/app/jaws/jaws.aps b/app/jaws/jaws.aps new file mode 100644 index 000000000..7050b5af8 Binary files /dev/null and b/app/jaws/jaws.aps differ diff --git a/app/jaws/jaws.rc b/app/jaws/jaws.rc new file mode 100644 index 000000000..6a36719c3 --- /dev/null +++ b/app/jaws/jaws.rc @@ -0,0 +1,110 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// 中文(中华人民共和国) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) +#ifdef _WIN32 +LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED +#pragma code_page(936) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x17L +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "080404b0" + BEGIN + VALUE "FileDescription", "jaws 应用程序" + VALUE "FileVersion", "1, 0, 0, 1" + VALUE "InternalName", "jaws" + VALUE "LegalCopyright", "版权所有 (C) 2008" + VALUE "OriginalFilename", "jaws.exe" + VALUE "ProductName", " jaws 应用程序" + VALUE "ProductVersion", "1, 0, 0, 1" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x804, 1200 + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_ICON_JAWS ICON "jaws_icon.ico" +#endif // 中文(中华人民共和国) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/app/jaws/jaws.sln b/app/jaws/jaws.sln new file mode 100644 index 000000000..d28b4cb6e --- /dev/null +++ b/app/jaws/jaws.sln @@ -0,0 +1,82 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jaws", "jaws.vcproj", "{F6BEEB3F-68A6-462D-89BE-F7CF2C04B82F}" + ProjectSection(ProjectDependencies) = postProject + {563B22AE-3249-4882-9388-BBBF2E62CB83} = {563B22AE-3249-4882-9388-BBBF2E62CB83} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "JawsCtrl", "JawsCtrl\JawsCtrl.vcproj", "{C6335BB5-6672-4A89-B1A6-5DA8731A1F0A}" + ProjectSection(ProjectDependencies) = postProject + {3E468E17-1AA2-42CE-9EC8-3B6013D6D46E} = {3E468E17-1AA2-42CE-9EC8-3B6013D6D46E} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lib_ctrl", "JawsCtrl\lib_ctrl\lib_ctrl.vcproj", "{3E468E17-1AA2-42CE-9EC8-3B6013D6D46E}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_http", "module\mod_http\mod_http.vcproj", "{C852445A-DFAB-4BF8-A006-22FC928E8632}" + ProjectSection(ProjectDependencies) = postProject + {563B22AE-3249-4882-9388-BBBF2E62CB83} = {563B22AE-3249-4882-9388-BBBF2E62CB83} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lib_global", "lib_global\lib_global.vcproj", "{563B22AE-3249-4882-9388-BBBF2E62CB83}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "http_access", "plugin\http_access\http_access.vcproj", "{259DAAFC-3920-4908-9322-5573569B49EE}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gbfilter", "plugin\gbfilter\gbfilter.vcproj", "{0708F4B4-48A2-45C0-BC60-A23A1B58653E}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cgi", "plugin\cgi\cgi.vcproj", "{2FEEEE07-1C22-4EC9-A67C-17E302E39C05}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Release = Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {F6BEEB3F-68A6-462D-89BE-F7CF2C04B82F}.Debug.ActiveCfg = Debug|Win32 + {F6BEEB3F-68A6-462D-89BE-F7CF2C04B82F}.Debug.Build.0 = Debug|Win32 + {F6BEEB3F-68A6-462D-89BE-F7CF2C04B82F}.Release.ActiveCfg = Release|Win32 + {F6BEEB3F-68A6-462D-89BE-F7CF2C04B82F}.Release.Build.0 = Release|Win32 + {C6335BB5-6672-4A89-B1A6-5DA8731A1F0A}.Debug.ActiveCfg = Debug|Win32 + {C6335BB5-6672-4A89-B1A6-5DA8731A1F0A}.Debug.Build.0 = Debug|Win32 + {C6335BB5-6672-4A89-B1A6-5DA8731A1F0A}.Release.ActiveCfg = Release|Win32 + {C6335BB5-6672-4A89-B1A6-5DA8731A1F0A}.Release.Build.0 = Release|Win32 + {3E468E17-1AA2-42CE-9EC8-3B6013D6D46E}.Debug.ActiveCfg = Debug|Win32 + {3E468E17-1AA2-42CE-9EC8-3B6013D6D46E}.Debug.Build.0 = Debug|Win32 + {3E468E17-1AA2-42CE-9EC8-3B6013D6D46E}.Release.ActiveCfg = Release|Win32 + {3E468E17-1AA2-42CE-9EC8-3B6013D6D46E}.Release.Build.0 = Release|Win32 + {C852445A-DFAB-4BF8-A006-22FC928E8632}.Debug.ActiveCfg = Debug|Win32 + {C852445A-DFAB-4BF8-A006-22FC928E8632}.Debug.Build.0 = Debug|Win32 + {C852445A-DFAB-4BF8-A006-22FC928E8632}.Release.ActiveCfg = Release|Win32 + {C852445A-DFAB-4BF8-A006-22FC928E8632}.Release.Build.0 = Release|Win32 + {563B22AE-3249-4882-9388-BBBF2E62CB83}.Debug.ActiveCfg = Debug|Win32 + {563B22AE-3249-4882-9388-BBBF2E62CB83}.Debug.Build.0 = Debug|Win32 + {563B22AE-3249-4882-9388-BBBF2E62CB83}.Release.ActiveCfg = Release|Win32 + {563B22AE-3249-4882-9388-BBBF2E62CB83}.Release.Build.0 = Release|Win32 + {259DAAFC-3920-4908-9322-5573569B49EE}.Debug.ActiveCfg = Debug|Win32 + {259DAAFC-3920-4908-9322-5573569B49EE}.Debug.Build.0 = Debug|Win32 + {259DAAFC-3920-4908-9322-5573569B49EE}.Release.ActiveCfg = Release|Win32 + {259DAAFC-3920-4908-9322-5573569B49EE}.Release.Build.0 = Release|Win32 + {0708F4B4-48A2-45C0-BC60-A23A1B58653E}.Debug.ActiveCfg = Debug|Win32 + {0708F4B4-48A2-45C0-BC60-A23A1B58653E}.Debug.Build.0 = Debug|Win32 + {0708F4B4-48A2-45C0-BC60-A23A1B58653E}.Release.ActiveCfg = Release|Win32 + {0708F4B4-48A2-45C0-BC60-A23A1B58653E}.Release.Build.0 = Release|Win32 + {2FEEEE07-1C22-4EC9-A67C-17E302E39C05}.Debug.ActiveCfg = Debug|Win32 + {2FEEEE07-1C22-4EC9-A67C-17E302E39C05}.Debug.Build.0 = Debug|Win32 + {2FEEEE07-1C22-4EC9-A67C-17E302E39C05}.Release.ActiveCfg = Release|Win32 + {2FEEEE07-1C22-4EC9-A67C-17E302E39C05}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/app/jaws/jaws.vcproj b/app/jaws/jaws.vcproj new file mode 100644 index 000000000..3103dba78 --- /dev/null +++ b/app/jaws/jaws.vcproj @@ -0,0 +1,155 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/jaws/jaws_icon.ico b/app/jaws/jaws_icon.ico new file mode 100644 index 000000000..a9feccf6c Binary files /dev/null and b/app/jaws/jaws_icon.ico differ diff --git a/app/jaws/lib_global/Debug/BuildLog.htm b/app/jaws/lib_global/Debug/BuildLog.htm new file mode 100644 index 000000000..527144e7e --- /dev/null +++ b/app/jaws/lib_global/Debug/BuildLog.htm @@ -0,0 +1,76 @@ + + + + + +
+
+生成日志 +
  
+

------- 已启动生成: 项目: lib_global,配置: Debug|Win32 ------- +

+
+命令行 +
  
正在创建临时文件“d:\工作目录\项目管理\jaws\jaws\lib_global\Debug\RSP00009F.rsp”,其内容为
+[
+/Od /I "..\include\acl" /I "..\include\protocol" /D "WIN32" /D "_DEBUG" /D "_LIB" /D "_MBCS" /Gm /EHsc /RTC1 /MTd /Fo"Debug/" /Fd"Debug/vc70.pdb" /W3 /c /Wp64 /ZI /TC
+\工作目录\项目管理\jaws\jaws\global\utf2gb.c
+\工作目录\项目管理\jaws\jaws\global\sys_patch.c
+\工作目录\项目管理\jaws\jaws\global\string.c
+\工作目录\项目管理\jaws\jaws\global\service_load.c
+\工作目录\项目管理\jaws\jaws\global\service_ipc.c
+\工作目录\项目管理\jaws\jaws\global\service.c
+\工作目录\项目管理\jaws\jaws\global\logger.c
+\工作目录\项目管理\jaws\jaws\global\forward.c
+\工作目录\项目管理\jaws\jaws\global\file_cache.c
+\工作目录\项目管理\jaws\jaws\global\dns_server.c
+\工作目录\项目管理\jaws\jaws\global\dns_lookup.c
+\工作目录\项目管理\jaws\jaws\global\dns_cache.c
+\工作目录\项目管理\jaws\jaws\global\conn_cache.c
+\工作目录\项目管理\jaws\jaws\global\client_entry.c
+]
+正在创建命令行“cl.exe @d:\工作目录\项目管理\jaws\jaws\lib_global\Debug\RSP00009F.rsp /nologo”
+正在创建临时文件“d:\工作目录\项目管理\jaws\jaws\lib_global\Debug\RSP0000A0.rsp”,其内容为
+[
+/OUT:"../lib/win32/lib_global.lib" /NOLOGO
+.\Debug\client_entry.obj
+.\Debug\conn_cache.obj
+.\Debug\dns_cache.obj
+.\Debug\dns_lookup.obj
+.\Debug\dns_server.obj
+.\Debug\file_cache.obj
+.\Debug\forward.obj
+.\Debug\logger.obj
+.\Debug\service.obj
+.\Debug\service_ipc.obj
+.\Debug\service_load.obj
+.\Debug\string.obj
+.\Debug\sys_patch.obj
+.\Debug\utf2gb.obj
+]
+正在创建命令行“lib.exe @d:\工作目录\项目管理\jaws\jaws\lib_global\Debug\RSP0000A0.rsp”
+
+输出窗口 +
  
正在编译...
+utf2gb.c
+sys_patch.c
+string.c
+service_load.c
+service_ipc.c
+service.c
+logger.c
+forward.c
+file_cache.c
+dns_server.c
+dns_lookup.c
+dns_cache.c
+conn_cache.c
+client_entry.c
+正在生成代码...
+正在创建库...
+
+结果 +
  
+生成日志保存在“file://d:\工作目录\项目管理\jaws\jaws\lib_global\Debug\BuildLog.htm”中
+lib_global - 0 错误,0 警告
+
\ No newline at end of file diff --git a/app/jaws/lib_global/ReadMe.txt b/app/jaws/lib_global/ReadMe.txt new file mode 100644 index 000000000..7635ae270 --- /dev/null +++ b/app/jaws/lib_global/ReadMe.txt @@ -0,0 +1,20 @@ +======================================================================== + 静态库 : lib_global 项目概况 +======================================================================== + +应用程序向导已为您创建了这个 lib_global 库项目。 +没有任何源文件被创建为项目的一部分。 + + +lib_global.vcproj + 这是用应用程序向导生成的 VC++ 项目的主项目文件。 + 它包含有关生成此文件的 Visual C++ 版本的信息,以及 + 有关用应用程序向导选择的 + 平台、配置和项目功能的信息。 + +///////////////////////////////////////////////////////////////////////////// +其他注释: + +应用程序向导使用 "TODO:" 注释指示应添加或自定义的源代码部分。 + +///////////////////////////////////////////////////////////////////////////// diff --git a/app/jaws/lib_global/Release/BuildLog.htm b/app/jaws/lib_global/Release/BuildLog.htm new file mode 100644 index 000000000..78fe8d332 --- /dev/null +++ b/app/jaws/lib_global/Release/BuildLog.htm @@ -0,0 +1,43 @@ + + + + + +
+
+生成日志 +
  
+

------- 已启动生成: 项目: lib_global,配置: Release|Win32 ------- +

+
+命令行 +
  
正在创建临时文件“d:\工作目录\项目管理\jaws\jaws\lib_global\Release\RSP000017.rsp”,其内容为
+[
+/OUT:"../lib/win32/lib_global.lib" /NOLOGO
+.\Release\client_entry.obj
+.\Release\conn_cache.obj
+.\Release\dns_cache.obj
+.\Release\dns_hosts.obj
+.\Release\dns_lookup.obj
+.\Release\dns_server.obj
+.\Release\file_cache.obj
+.\Release\forward.obj
+.\Release\logger.obj
+.\Release\service.obj
+.\Release\service_conf.obj
+.\Release\service_ipc.obj
+.\Release\service_load.obj
+.\Release\service_main.obj
+.\Release\string.obj
+.\Release\sys_patch.obj
+]
+正在创建命令行“lib.exe @d:\工作目录\项目管理\jaws\jaws\lib_global\Release\RSP000017.rsp”
+
+输出窗口 +
  
正在创建库...
+
+结果 +
  
+生成日志保存在“file://d:\工作目录\项目管理\jaws\jaws\lib_global\Release\BuildLog.htm”中
+lib_global - 0 错误,0 警告
+
\ No newline at end of file diff --git a/app/jaws/lib_global/lib_global.vcproj b/app/jaws/lib_global/lib_global.vcproj new file mode 100644 index 000000000..e6272b568 --- /dev/null +++ b/app/jaws/lib_global/lib_global.vcproj @@ -0,0 +1,203 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/jaws/main/Makefile b/app/jaws/main/Makefile new file mode 100644 index 000000000..48846bc0d --- /dev/null +++ b/app/jaws/main/Makefile @@ -0,0 +1,126 @@ +SHELL = /bin/sh +CC = gcc +#CC = g++ +AR = ar +ARFL = rv +RANLIB = ranlib + +CFLAGS = -c -g -W -Wall -Wcast-qual -Wcast-align \ +-Waggregate-return -Wmissing-prototypes \ +-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO \ +-Wno-long-long \ +-Wpointer-arith -Werror -Wshadow -pedantic -O2 + +########################################################### +#Check system: +# Linux, SunOS, Solaris, BSD variants, AIX, HP-UX +SYSLIB = -ldl +RPATH = + +CHECKSYSRES = @echo "Unknow system type!";exit 1 +UNIXNAME = $(shell uname -sm) +OSTYPE = $(shell uname -p) + +#Path for Linux +ifeq ($(findstring Linux, $(UNIXNAME)), Linux) +# ifeq ($CC, "gcc") + ifeq ($(findstring i686, $(OSTYPE)), i686) + RPATH = linux32 + endif + ifeq ($(findstring x86_64, $(OSTYPE)), x86_64) + RPATH = linux64 + endif + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DLINUX2 + SYSLIB += -lcrypt -lpthread +endif + +#Path for SunOS +ifeq ($(findstring SunOS, $(UNIXNAME)), SunOS) + ifeq ($(findstring i386, $(OSTYPE)), i386) + RPATH = sunos_x86 + endif + ifeq ($(findstring 86, $(UNIXNAME)), 86) + SYSLIB += -lsocket -lnsl -lrt + endif + ifeq ($(findstring sun4u, $(UNIXNAME)), sun4u) + SYSLIB += -lsocket -lnsl -lrt + endif +# ifeq ($CC, "gcc") + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DSUNOS5 +endif + +#Path for HP-UX +ifeq ($(findstring HP-UX, $(UNIXNAME)), HP-UX) +# ifeq ($CC, "gcc") + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + SYSLIB += -lpthread + CFLAGS += -DHP_UX -DHPUX11 + PLAT_NAME=hp-ux +endif + +#Find system type. +ifneq ($(SYSPATH),) + CHECKSYSRES = @echo "System is $(shell uname -sm)" +endif +########################################################### +ACL_PATH = ../../../lib_acl +ACL_LIB = $(ACL_PATH)/lib +ACL_INC = $(ACL_PATH)/include + +PROTO_PATH = ../../../lib_protocol +PROTO_LIB = $(PROTO_PATH)/lib +PROTO_INC = $(PROTO_PATH)/include + +GLOBAL_PATH = ../global +GLOBAL_LIB = $(GLOBAL_PATH) +GLOBAL_INC = $(GLOBAL_PATH) + +ALL_LIBS = -L$(GLOBAL_LIB) -l_global -L$(PROTO_LIB) -l_protocol -L$(ACL_LIB) -l_acl $(SYSLIB) + +INCLUDE = -I../module/mod_http -I$(GLOBAL_INC) -I$(PROTO_INC) -I$(ACL_INC) +CFLAGS += $(INCLUDE) -DHAVE_NO_STRCASESTR + +OBJ_OUTPATH = ./debug + +#Project's objs +SOURCES = $(wildcard ./*.c) +OBJS = $(patsubst %.c, $(OBJ_OUTPATH)/%.o, $(notdir $(SOURCES))) + +########################################################### +DIST_PATH = ../dist/unix_setup/libexec/$(RPATH) +PROG_NAME = jaws + +.PHONY = RM all clean +COMPILE = $(CC) $(CFLAGS) + +all: RM $(PROG_NAME) + +RM: + rm -f $(PROG_NAME) +# rm -f $(DIST_PATH)/$(PROG_NAME) + +PLUGIN: + @(cd plugin; make) + +$(PROG_NAME): $(OBJS) + $(CC) -o $(PROG_NAME) $(OBJS) $(LIB_NAME_PATH) $(ALL_LIBS) +# cp $(PROG_NAME) $(DIST_PATH)/$(PROG_NAME) + cp ../module/mod_http/mod_http.so ./lib + +$(OBJ_OUTPATH)/%.o: ./%.c + $(COMPILE) -o $@ $< + +clean: + rm -f $(OBJS) $(PROG_NAME) + rm -f ./lib/mod_http.so +# rm -f $(DIST_PATH)/$(PROG_NAME) + +rebuild: clean all diff --git a/app/jaws/main/conf/gb_jt2ft.cf b/app/jaws/main/conf/gb_jt2ft.cf new file mode 100644 index 000000000..4231033b1 --- /dev/null +++ b/app/jaws/main/conf/gb_jt2ft.cf @@ -0,0 +1,19 @@ +service server { +#虚拟繁体网站域名前缀 + virtual_domain_prefix = .tw +#包括下列分号分隔子串的域名才需要加前缀 + virtual_domain_list = hexun.com +#下列分号分隔的域名是实际域名,请求时不需要去掉前缀 +# real_domain_list = tw.hxjs.tool.hexun.com +#响应正文中含有下列分号分隔的name/value对中的name时,需要用value替换 + special_replace_list = hexun.com=hexun.com.tw;baidu.com=baidu.com.tw +# special_replace_list = wmail1.mail.hexun.com=wmail1.mail.hexun.com.tw;\ +# http://reg.hexun.com=http://reg.hexun.com.tw;\ +# wmail2.mail.hexun.com=wmail2.mail.hexun.com.tw;\ +# mail.hexun.com=mail.hexun.com.tw +#下列分号隔开的响应类型是需要经过域名转换的 + access_type_list = text/html;text/css;javascript;text/xml;application/x-javascript; +#下列分号隔开的响应类型是需要经过简繁体转换处理的 + trans_type_list = text/html;text/css; +# special_file_need_trans_list = test.js; +} diff --git a/app/jaws/main/conf/gbfilter.cf b/app/jaws/main/conf/gbfilter.cf new file mode 100644 index 000000000..ce95afd8d --- /dev/null +++ b/app/jaws/main/conf/gbfilter.cf @@ -0,0 +1,8 @@ +# configure + +service gbfilter { + debug_mem = 0 + logpath = ./var/gbfilter.log + data_clone = 0 + rewrite_enable = 1 +} diff --git a/app/jaws/main/conf/http.cf b/app/jaws/main/conf/http.cf new file mode 100644 index 000000000..f4e3ac0f9 --- /dev/null +++ b/app/jaws/main/conf/http.cf @@ -0,0 +1,40 @@ + +service http_mod { +############################################################################ +# 应用自己的配置选项 +# 是否调试内存分配情况 + debug_mem = 0 +# 每个客户端连接的空闲时间. +# client_idle_limit = 60 +## 与HTTP服务相关的配置项 +# http_filter_proxy = HTTP_FILTER_HTTPD + http_filter_proxy = HTTP_FILTER_PROXY +# 是否与客户端保持长连接 + http_client_keepalive = 1 +# 代理模式下,是否与服务端保持长连接 + http_server_keepalive = 1 +# 似乎是天津网通的内容过滤网关处理 Proxy-Connection 存在问题,会造成延迟 + http_proxy_connection_off = 1 + +# HTML错误模板存放目录 + http_tmpl_path = ./var/www/tmpl +# 虚拟主机配置文件存放目录 + http_vhost_path = ./conf/www/vhost +# 缺省域的配置文件名 + http_vhost_default = ./conf/www/default.cf + +# 外挂动态库集合 +# http_plugin_dlnames = /opt/jaws/plugin/cgi.so; /opt/jaws/plugin/gbfilter.so +# http_plugin_dlnames = /opt/jaws/plugin/cgi.so +# http_plugin_dlnames = /opt/jaws/plugin/gbfilter.so +# http_plugin_dlnames = /opt/jaws/plugin/gb_jt2ft.so +# http_plugin_dlnames = /opt/jaws/plugin/gb_jt2ft32.so +# http_plugin_dlnames = ./lib/http_access.so +# http_plugin_dlnames = ./lib/gb_jt2ft.so +# 外挂动态库的配置文件所在目录 + http_plugin_cfgdir = ./conf +# 与服务端的连接池的最大连接限制 + http_server_conn_limit = 1000 +# HTTP 通信过程中的缓冲区大小 + http_buf_size = 10240 +} diff --git a/app/jaws/main/conf/http_access.cf b/app/jaws/main/conf/http_access.cf new file mode 100644 index 000000000..69a7e14f8 --- /dev/null +++ b/app/jaws/main/conf/http_access.cf @@ -0,0 +1,6 @@ +service http_plugin_access { +# 以下域名列表是否允许访问 + http_domain_allow = hexun.com, hexun.com.tw +# 是否允许访问其它所有域名 + http_domain_allow_all = 1 +} diff --git a/app/jaws/main/conf/jaws.cf b/app/jaws/main/conf/jaws.cf new file mode 100644 index 000000000..0ea81b767 --- /dev/null +++ b/app/jaws/main/conf/jaws.cf @@ -0,0 +1,100 @@ + +service server { +# 进程是否禁止运行 + master_disable = no +# 服务地址及端口号 + master_service = 8284 +# 服务监听为域套接口 +# master_service = jaws.sock +# 服务类型 + master_type = inet +# master_type = unix +# 是否允许延迟接受客户端连接,如果为0则表示关闭该功能,如果大于0则表示打开此功能 +# 并且此值代表延迟接受连接的超时值,超过此值时如果客户端依然没有发来数据,则操作 +# 系统会在系统层直接关闭该连接 +# master_defer_accept = 0 +# 是否只允许私有访问, 如果为 y, 则域套接口创建在 /opt/jaws/var/log/private/ 目录下, +# 如果为 n, 则域套接口创建在 /opt/jaws/var/log/public/ 目录下, + master_private = n + master_unpriv = n +# 是否需要 chroot: n -- no, y -- yes + master_chroot = n +# 每隔多长时间触发一次,单位为秒(仅对 trigger 模式有效) + master_wakeup = - +# 最大进程数 + master_maxproc = 4 +# 进程程序名 + master_command = jaws +# 进程启动参数,只能为: -u [是否允许以某普通用户的身份运行] +# master_args = -u +# 传递给服务子进程的环境变量, 可以通过 getenv("SERVICE_ENV") 获得此值 +# master_env = mempool_limit:512000000, mempool_use_mutex:true +# master_env = logme:FALSE, priority:E_LOG_INFO, action:E_LOG_PER_DAY, flush:sync_flush, imit_size:512,\ +# sync_action:E_LOG_SEM, sem_name:/tmp/jaws.sem +# master_env = use_slice:true, slice_base:8, nslice:1024, nalloc_gc:100000, \ +# slice_gc:gc2, rtgc_off:true +# 进程日志记录文件 + master_log = ./var/jaws.log + +# 每个进程实例处理连接数的最大次数,超过此值后进程实例主动退出 + aio_use_limit = 0 +# 每个进程实例的空闲超时时间,超过此值后进程实例主动退出 + aio_idle_limit = 0 +# 记录进程PID的位置(对于多进程实例来说没有意义) + aio_pid_dir = ./var +# 进程运行时所在的路径 + aio_queue_dir = ./var +# 读写超时时间, 单位为秒 + aio_rw_timeout = 20 +# 读缓冲区的缓冲区大小 + aio_buf_size = 8192 +# 每次 accept 时的循环接收的最大次数 + aio_max_accept = 10 +# 进程运行时的用户身份 + aio_owner = nobody + +# 采用事件循环的方式: select(default), poll, kernel(epoll/devpoll/kqueue) +# aio_event_mode = select +# aio_event_mode = poll + aio_event_mode = kernel +# 是否由单独的线程接受客户端连接 + aio_accept_alone = no +# 用 select 进行循环时的时间间隔 +# 单位为秒 + aio_delay_sec = 100 +# 单位为微秒 + aio_delay_usec = 5000 +# 线程池的最大线程数, 如果该值为0则表示采用单线程非阻塞模式. +# aio_max_threads = 0 +# 每个线程的空闲时间. +# aio_thread_idle_limit = 60 + +# 允许访问的客户端IP地址范围 + aio_access_allow = 202.99.16.0:202.99.16.255, 127.0.0.1:127.0.0.1 +# aio_access_allow = 0.0.0.0:255.255.255.255, 127.0.0.1:127.0.0.1 + +############################################################################ +# 应用自己的配置选项 + +# 每个客户端连接的空闲时间. +# client_idle_limit = 60 +# 是否输出当前的内存状态信息 + debug_mem = 0 +# 服务协议名称 + proto_name = http +# 需要动态加载的服务模块 + service_dlnames = ./lib/mod_http.so +# 动态加载的服务模块的配置文件所在路径 + service_cfgdir = ./conf +# 连接池的连接数限制 +# http_server_conn_limit = 10240 +# 每个进程最多启动的线程个数 + nthreads = 1 +# 本机可以绑定的IP地址列表 +# bind_ip_list = 127.0.0.1, 10.0.251.93, 60.28.251.93 +# DNS服务器地址列表 +# dns_list = 60.28.250.46:53, 60.28.250.40 + dns_list = 8.8.8.8:53 +# hosts_list 配置文件集合列表, 如:/etc/hosts, /etc/myhosts + hosts_list = /etc/hosts +} diff --git a/app/jaws/main/conf/www/default.cf b/app/jaws/main/conf/www/default.cf new file mode 100644 index 000000000..e3fbd1076 --- /dev/null +++ b/app/jaws/main/conf/www/default.cf @@ -0,0 +1,5 @@ +service test { + host = localhost + root_path = /opt/acl/var/www/htdocs/ +# vpath_map = / /opt/acl/var/www/htdocs/ 0 +} diff --git a/app/jaws/main/conf/www/vhost/test.cf b/app/jaws/main/conf/www/vhost/test.cf new file mode 100644 index 000000000..16ab4eb12 --- /dev/null +++ b/app/jaws/main/conf/www/vhost/test.cf @@ -0,0 +1,7 @@ +service test { + host = test.com.cn + root_path = /opt/acl/var/www/htdocs/test.domain/html/ + vpath_map = / /opt/acl/var/www/htdocs/test.domain/html/ 0 + vpath_map = /test2/ /opt/acl/var/www/htdocs/test.domain/test2/html/ 0 + vpath_map = /test3/ /opt/acl/var/www/htdocs/test.domain/test3/html/ 0 +} diff --git a/app/jaws/main/main.c b/app/jaws/main/main.c new file mode 100644 index 000000000..54beac235 --- /dev/null +++ b/app/jaws/main/main.c @@ -0,0 +1,224 @@ +#include "lib_acl.h" +#include +#include +#include "service_conf.h" +#include "service_main.h" +#include "http_module.h" + +static ACL_AIO *var_aio; +static char *var_cfg_event_mode; +static char *var_cfg_master_log; +static char *var_cfg_listen_addr; + +static ACL_CONFIG_STR_TABLE __service_conf_str_tab[] = { + /* TODO: you can add configure variables of (char *) type here */ + /* example: { "mysql_dbaddr", "127.0.0.1:3306", &var_cfg_mysql_dbaddr }, */ + + { "aio_event_mode", "poll", &var_cfg_event_mode }, + { "master_log", "jaws.log", &var_cfg_master_log }, + { "master_service", "127.0.0.1:8808", &var_cfg_listen_addr }, + + { 0, 0, 0 }, +}; + +static int listen_callback(ACL_ASTREAM *sstream, void *context acl_unused) +{ + ACL_SOCKET fd; + + fd = acl_inet_accept(ACL_VSTREAM_SOCK(acl_aio_vstream(sstream))); + if (fd == ACL_SOCKET_INVALID) { + printf("accept error(%s)\n", acl_last_serror()); + return (-1); + } + service_main(fd, var_aio); + return (0); +} + +static void gc_timer(int event_type acl_unused, void *context) +{ + ACL_AIO *aio = (ACL_AIO *) context; + + acl_mem_slice_delay_destroy(); + /* 设定定时器定时清理垃圾回收器 */ + acl_aio_request_timer(aio, gc_timer, aio, 2); +} + +static void run_loop(ACL_AIO *aio, const char *listen_addr) +{ + const char *myname = "run_loop"; + ACL_VSTREAM *sstream = acl_vstream_listen(listen_addr, 128); + ACL_ASTREAM *astream; + + if (sstream == NULL) + acl_msg_fatal("%s(%d): listen(%s) error(%s)", + myname, __LINE__, listen_addr, acl_last_serror()); + acl_msg_info("%s(%d): listen %s ok, (fd=%d).", + myname, __LINE__, listen_addr, ACL_VSTREAM_SOCK(sstream)); + + astream = acl_aio_open(aio, sstream); + acl_aio_ctl(astream, + ACL_AIO_CTL_LISTEN_FN, listen_callback, + ACL_AIO_CTL_END); + acl_aio_listen(astream); + /* 设定定时器定时清理垃圾回收器 */ + acl_aio_request_timer(aio, gc_timer, aio, 2); + + while (1) { + acl_aio_loop(aio); + } +} + +#ifdef ACL_MS_WINDOWS + +#include + +static void onexit_fn(void *arg) +{ + char *procname = (char*) arg; + + acl_msg_info("%s: exit now", procname); + acl_myfree(procname); +} + +static void exec_path(char *exe_path, int size) +{ + char exeFullPath[MAX_PATH]; + char szDriver[MAX_PATH]; + char szDir[MAX_PATH]; + char szFile[MAX_PATH]; + char szExt[MAX_PATH]; + + GetModuleFileName(NULL, exeFullPath, MAX_PATH); + _splitpath(exeFullPath, szDriver, szDir, szFile, szExt); + snprintf(exe_path, size, "%s%s", szDriver, szDir); +} + +#endif + +static void change_path(void) +{ +#ifdef ACL_MS_WINDOWS + char path[MAX_PATH]; + + exec_path(path, sizeof(path)); + _chdir(path); +#endif +} + +static ACL_FIFO *get_modules(void) +{ + ACL_FIFO *modules = NULL; + +#ifdef JAWS_STATIC + MODULE_SERVICE *module; + + modules = acl_fifo_new(); + + module = (MODULE_SERVICE*) acl_mycalloc(1, sizeof(MODULE_SERVICE)); + module->mod_init = module_service_init; + module->mod_create = module_service_create; + module->mod_main = module_service_main; + acl_fifo_push(modules, module); +#endif + return (modules); +} + +static ACL_AIO *init(const char *procname, int use_slice, int open_log acl_unused, const char *conf) +{ + ACL_AIO *aio; + int event_mode; + ACL_XINETD_CFG_PARSER *cfg; + ACL_FIFO *modules; + + change_path(); + + if (use_slice) + var_mem_slice = acl_mem_slice_init(8, 10240, 100000, + ACL_SLICE_FLAG_GC2 | ACL_SLICE_FLAG_RTGC_OFF | ACL_SLICE_FLAG_LP64_ALIGN); + else + var_mem_slice = NULL; + + /* 初始化 acl 库 */ + acl_init(); + + /* 加载配置文件 */ + cfg = acl_xinetd_cfg_load(conf); + if (cfg == NULL) + acl_msg_warn("load cfg(%s) error(%s)", + conf, acl_last_serror()); + acl_xinetd_params_str_table(cfg, service_conf_str_tab); + acl_xinetd_params_str_table(cfg, __service_conf_str_tab); + acl_xinetd_params_bool_table(cfg, service_conf_bool_tab); + acl_xinetd_params_int_table(cfg, service_conf_int_tab); + acl_xinetd_cfg_free(cfg); + +#ifdef ACL_UNIX + if (open_log) +#endif + { + acl_msg_open(var_cfg_master_log, "jaws"); + } + +#ifdef ACL_UNIX + if (strcasecmp(var_cfg_event_mode, "kernel") == 0) + event_mode = ACL_EVENT_KERNEL; + else if (strcasecmp(var_cfg_event_mode, "poll") == 0) + event_mode = ACL_EVENT_POLL; + else +#endif + event_mode = ACL_EVENT_SELECT; + var_aio = aio = acl_aio_create(event_mode); + + modules = get_modules(); + service_init(aio, modules); + +#ifdef ACL_MS_WINDOWS + acl_proctl_child(procname, onexit_fn, acl_mystrdup(procname)); +#else + (void) procname; +#endif + return (aio); +} + +static void end(void) +{ + service_exit(); + acl_end(); +} + +static void usage(const char *procname) +{ + printf("usage: %s -h[help] -m[use mem slice] -l[open log] -c conf_file\n", procname); +} + +int main(int argc, char *argv[]) +{ + ACL_AIO *aio; + char conf[256] = "conf/jaws.cf"; + int ch, use_slice = 0, open_log = 0; + + while ((ch = getopt(argc, argv, "hc:ml")) > 0) { + switch (ch) { + case 'h': + usage(argv[0]); + return (0); + case 'c': + ACL_SAFE_STRNCPY(conf, optarg, sizeof(conf)); + break; + case 'm': + use_slice = 1; + break; + case 'l': + open_log = 1; + break; + default: + break; + } + } + + aio = init(argv[0], use_slice, open_log, conf); + run_loop(aio, var_cfg_listen_addr); + end(); + return (0); +} + diff --git a/app/jaws/main/valgrind.sh b/app/jaws/main/valgrind.sh new file mode 100644 index 000000000..0c0243b44 --- /dev/null +++ b/app/jaws/main/valgrind.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +valgrind --tool=memcheck --leak-check=yes --show-reachable=yes -v ./jaws diff --git a/app/jaws/master_main/Makefile b/app/jaws/master_main/Makefile new file mode 100644 index 000000000..b1280feac --- /dev/null +++ b/app/jaws/master_main/Makefile @@ -0,0 +1,124 @@ +SHELL = /bin/sh +CC = gcc +#CC = g++ +AR = ar +ARFL = rv +RANLIB = ranlib + +CFLAGS = -c -g -W -Wall -Wcast-qual -Wcast-align \ +-Waggregate-return -Wmissing-prototypes \ +-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO \ +-Wno-long-long \ +-Wpointer-arith -Werror -Wshadow -pedantic -O2 + +########################################################### +#Check system: +# Linux, SunOS, Solaris, BSD variants, AIX, HP-UX +SYSLIB = -ldl +RPATH = + +CHECKSYSRES = @echo "Unknow system type!";exit 1 +UNIXNAME = $(shell uname -sm) +OSTYPE = $(shell uname -p) + +#Path for Linux +ifeq ($(findstring Linux, $(UNIXNAME)), Linux) +# ifeq ($CC, "gcc") + ifeq ($(findstring i686, $(OSTYPE)), i686) + RPATH = linux32 + endif + ifeq ($(findstring x86_64, $(OSTYPE)), x86_64) + RPATH = linux64 + endif + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DLINUX2 + SYSLIB += -lcrypt -lpthread +endif + +#Path for SunOS +ifeq ($(findstring SunOS, $(UNIXNAME)), SunOS) + ifeq ($(findstring i386, $(OSTYPE)), i386) + RPATH = sunos_x86 + endif + ifeq ($(findstring 86, $(UNIXNAME)), 86) + SYSLIB += -lsocket -lnsl -lrt + endif + ifeq ($(findstring sun4u, $(UNIXNAME)), sun4u) + SYSLIB += -lsocket -lnsl -lrt + endif +# ifeq ($CC, "gcc") + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DSUNOS5 +endif + +#Path for HP-UX +ifeq ($(findstring HP-UX, $(UNIXNAME)), HP-UX) +# ifeq ($CC, "gcc") + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + SYSLIB += -lpthread + CFLAGS += -DHP_UX -DHPUX11 + PLAT_NAME=hp-ux +endif + +#Find system type. +ifneq ($(SYSPATH),) + CHECKSYSRES = @echo "System is $(shell uname -sm)" +endif +########################################################### +ACL_PATH = ../../../lib_acl +ACL_LIB = $(ACL_PATH)/lib +ACL_INC = $(ACL_PATH)/include + +PROTO_PATH = ../../../lib_protocol +PROTO_LIB = $(PROTO_PATH)/lib +PROTO_INC = $(PROTO_PATH)/include + +GLOBAL_PATH = ../global +GLOBAL_LIB = $(GLOBAL_PATH) +GLOBAL_INC = $(GLOBAL_PATH) + +ALL_LIBS = -L$(GLOBAL_LIB) -l_global -L$(PROTO_LIB) -l_protocol -L$(ACL_LIB) -l_acl $(SYSLIB) + +INCLUDE = -I../module/mod_http -I$(GLOBAL_INC) -I$(PROTO_INC) -I$(ACL_INC) +CFLAGS += $(INCLUDE) -DHAVE_NO_STRCASESTR + +OBJ_OUTPATH = ./debug + +#Project's objs +SOURCES = $(wildcard ./*.c) +OBJS = $(patsubst %.c, $(OBJ_OUTPATH)/%.o, $(notdir $(SOURCES))) + +########################################################### +DIST_PATH = ../dist/unix_setup/libexec/$(RPATH) +PROG_NAME = jaws + +.PHONY = RM all clean +COMPILE = $(CC) $(CFLAGS) + +all: RM $(PROG_NAME) + +RM: + rm -f $(PROG_NAME) + rm -f $(DIST_PATH)/$(PROG_NAME) + +PLUGIN: + @(cd plugin; make) + +$(PROG_NAME): $(OBJS) + $(CC) -o $(PROG_NAME) $(OBJS) $(LIB_NAME_PATH) $(ALL_LIBS) + cp $(PROG_NAME) $(DIST_PATH)/$(PROG_NAME) + +$(OBJ_OUTPATH)/%.o: ./%.c + $(COMPILE) -o $@ $< + +clean: + rm -f $(OBJS) $(PROG_NAME) + rm -f $(DIST_PATH)/$(PROG_NAME) + +rebuild: clean all diff --git a/app/jaws/master_main/app_log.c b/app/jaws/master_main/app_log.c new file mode 100644 index 000000000..47cd0b30a --- /dev/null +++ b/app/jaws/master_main/app_log.c @@ -0,0 +1,238 @@ + +#include "lib_acl.h" +#include +#include "app_log.h" + +#ifdef HAS_LIB_CORE +#include "e_config.h" +#include "elib.h" + +typedef struct LOG_WRAP { + E_LOG_T *h_log; + char filename[1024]; +} LOG_WRAP; + +static LOG_WRAP *__log_wrap = NULL; + +static int __log_open(const char *filename, void *ctx) +{ + LOG_WRAP *h_log = (LOG_WRAP *) ctx; + int logme = 0; + char *facility_name = NULL; + E_LOG_PRIORITY_T priority = E_LOG_INFO; + E_LOG_ACTION_T action = E_LOG_PER_DAY; + int flush = 1; + size_t limit_size = 0; + E_LOG_SYNC_ACTION_T sync_action = E_LOG_SEM_WITH_MT; + char *sem_name = NULL; + char *ptr, *pname; + ACL_ARGV *env_argv; + ACL_VSTRING *log_buf; + int i; + + if (filename == NULL || *filename == 0) + return (-1); + + acl_snprintf(h_log->filename, sizeof(h_log->filename), "%s", filename); + + /* env: facility:x, priority:x, action:x, flush:x, limit_size:x, sync_action:x, sem_name:x */ + + ptr = getenv("SERVICE_ENV"); + if (ptr == NULL) + return (-1); + + env_argv = acl_argv_split(ptr, ",\t "); + if (env_argv == NULL) + return (-1); + if (env_argv->argc == 0) { + acl_argv_free(env_argv); + return (-1); + } + + log_buf = acl_vstring_alloc(256); + + for (i = 0; i < env_argv->argc; i++) { + pname = acl_argv_index(env_argv, i); + ptr = strchr(pname, ':'); + if (ptr == NULL) + continue; + *ptr++ = 0; + if (*ptr == 0) + continue; + + if (i == 0) + acl_vstring_sprintf(log_buf, "%s:%s", pname, ptr); + else + acl_vstring_sprintf_append(log_buf, ", %s:%s", pname, ptr); + + if (strcasecmp(pname, "logme") == 0) { + if (strcasecmp(ptr, "TRUE") == 0) + logme = 1; + } else if (strcasecmp(pname, "facility") == 0) { + facility_name = ptr; + } else if (strcasecmp(pname, "priority") == 0) { + if (strcasecmp(ptr, "E_LOG_NOLOG") == 0) + priority = E_LOG_NOLOG; + else if (strcasecmp(ptr, "E_LOG_EMERG") == 0) + priority = E_LOG_EMERG; + else if (strcasecmp(ptr, "E_LOG_ALERT") == 0) + priority = E_LOG_ALERT; + else if (strcasecmp(ptr, "E_LOG_CRIT") == 0) + priority = E_LOG_CRIT; + else if (strcasecmp(ptr, "E_LOG_ERR") == 0) + priority = E_LOG_ERR; + else if (strcasecmp(ptr, "E_LOG_WARNING") == 0) + priority = E_LOG_WARNING; + else if (strcasecmp(ptr, "E_LOG_NOTICE") == 0) + priority = E_LOG_NOTICE; + else if (strcasecmp(ptr, "E_LOG_INFO") == 0) + priority = E_LOG_INFO; + else if (strcasecmp(ptr, "E_LOG_DEBUG") == 0) + priority = E_LOG_DEBUG; + } else if (strcasecmp(pname, "action") == 0) { + if (strcasecmp(ptr, "E_LOG_PER_HOUR") == 0) + action = E_LOG_PER_HOUR; + else if (strcasecmp(ptr, "E_LOG_PER_DAY") == 0) + action = E_LOG_PER_DAY; + else if (strcasecmp(ptr, "E_LOG_PER_WEEK") == 0) + action = E_LOG_PER_WEEK; + else if (strcasecmp(ptr, "E_LOG_PER_MONTH") == 0) + action = E_LOG_PER_MONTH; + else if (strcasecmp(ptr, "E_LOG_PER_YEAR") == 0) + action = E_LOG_PER_YEAR; + else if (strcasecmp(ptr, "E_LOG_LIMIT_SIZE") == 0) + action = E_LOG_LIMIT_SIZE; + else if (strcasecmp(ptr, "E_LOG_SYSLOG") == 0) + action = E_LOG_SYSLOG; + } else if (strcasecmp(pname, "flush") == 0) { + if (strcasecmp(ptr, "sync_flush") == 0) + flush = 1; + else if (strcasecmp(ptr, "async_flush") == 0) + flush = 0; + } else if (strcasecmp(pname, "limit_size") == 0) { + limit_size = atoi(ptr); + } else if (strcasecmp(pname, "sync_action") == 0) { + if (strcasecmp(ptr, "E_LOG_NO_SYNC") == 0) + sync_action = E_LOG_NO_SYNC; + else if (strcasecmp(ptr, "E_LOG_THREAD_MUTEX") == 0) + sync_action = E_LOG_THREAD_MUTEX; + else if (strcasecmp(ptr, "E_LOG_FILE_LOCK") == 0) + sync_action = E_LOG_FILE_LOCK; + else if (strcasecmp(ptr, "E_LOG_SEM_WITH_MT") == 0) + sync_action = E_LOG_SEM_WITH_MT; + else if (strcasecmp(ptr, "E_LOG_FILE_APPEND_WITH_MT") == 0) + sync_action = E_LOG_FILE_APPEND_WITH_MT; + } else if (strcasecmp(pname, "sem_name") == 0) { + sem_name = ptr; + } + } + + +#if 0 + LC_SysLogCreate(&h_log->h_log, h_log->filename); +#endif + if (action == E_LOG_LIMIT_SIZE) { + if (limit_size == 0) + limit_size = 512; /* set default size: 512 MB */ + } else + limit_size = 0; + + if (sync_action == E_LOG_SEM_WITH_MT) { + if (sem_name == NULL || *sem_name == 0) { + sem_name = acl_concatenate("/tmp/", acl_safe_basename(filename), ".sem", NULL); + } else + sem_name = acl_mystrdup(sem_name); + } else if (sem_name) { + sem_name = NULL; + } + + h_log->h_log = e_log_new2(h_log->filename, priority, action, + flush, limit_size, facility_name, sync_action, sem_name); + + if (sem_name) + acl_myfree(sem_name); + + if (logme) { + /* + char cmd[1024], buf[512]; + + snprintf(buf, sizeof(buf), "filename=%s, priority=%d, action=%d, flush=%d, " + "limit_size=%d, facility_name=%s, sync_action=%d, sem_name=%s", + h_log->filename, priority, action, + flush, limit_size, facility_name, sync_action, sem_name); + snprintf(cmd, sizeof(cmd), "echo '%s, buf(%s)' >> /tmp/test1.log", acl_vstring_str(log_buf), buf); + system(cmd); + */ + + e_log2(h_log->h_log, "master_env: %s", acl_vstring_str(log_buf)); + } + + e_log2(h_log->h_log, "filename=%s, priority=%d, action=%d, flush=%d, " + "limit_size=%d, facility_name=%s, sync_action=%d, sem_name=%s", + h_log->filename, priority, action, + flush, limit_size, facility_name, sync_action, sem_name); + + if (log_buf) + acl_vstring_free(log_buf); + + return (0); +} + +static void __log_close(void *ctx acl_unused) +{ +} + +static void __log_write(void *ctx, const char *fmt, va_list ap) +{ + LOG_WRAP *h_log = (LOG_WRAP *) ctx; +#if 0 + char buf[1024], cmd[2048]; + + vsnprintf(buf, sizeof(buf), fmt, ap); + + snprintf(cmd, sizeof(cmd), "echo \"%s\" >> /tmp/out.txt", buf); + system(cmd); +#endif + +#if 0 + LC_SysLogFmtWrite2(&h_log->h_log, fmt, ap); +#endif + if (h_log->h_log) + e_vlog2(h_log->h_log, fmt, ap); +} + +void app_set_libcore_log(void) +{ + LOG_WRAP *h_log; + + h_log = acl_mycalloc(1, sizeof(LOG_WRAP)); + if (h_log == NULL) + return; + + acl_msg_register(__log_open, __log_close, __log_write, (void *) h_log); + __log_wrap = h_log; +} + +void app_libcore_log_end(void) +{ + if (__log_wrap == NULL) + return; + if (__log_wrap->h_log == NULL) + return; + acl_msg_info("service exit now"); + e_log_free(__log_wrap->h_log); + __log_wrap->h_log = NULL; +} +#else +void app_set_libcore_log() +{ + const char *myname = "app_set_libcore_log"; + + acl_msg_info("%s(%d): please pre-define HAS_LIB_CORE first", myname, __LINE__); +} + +void app_libcore_log_end(void) +{ +} +#endif + diff --git a/app/jaws/master_main/app_log.h b/app/jaws/master_main/app_log.h new file mode 100644 index 000000000..aa7ec36f6 --- /dev/null +++ b/app/jaws/master_main/app_log.h @@ -0,0 +1,17 @@ + +#ifndef __LOG_WRAP_INCLUDE_H__ +#define __LOG_WRAP_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +extern void app_set_libcore_log(void); +extern void app_libcore_log_end(void); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/app/jaws/master_main/main.c b/app/jaws/master_main/main.c new file mode 100644 index 000000000..a899b1e68 --- /dev/null +++ b/app/jaws/master_main/main.c @@ -0,0 +1,143 @@ +#include "lib_acl.h" +#include "app_log.h" +#include "http_service.h" +#include "service_conf.h" +#include "service_main.h" + +static int __use_slice = 0; +static int __slice_base = 8; +static int __slice_gc = ACL_SLICE_FLAG_GC2; +static int __nslice = 1024; +static int __nalloc_gc = 100000; +static int __rtgc_off = 1; + +static void parse_env(void) +{ + char *ptr, *name; + ACL_ARGV *env_argv; + ACL_ITER iter; + + ptr = getenv("SERVICE_ENV"); + if (ptr == NULL) + return; + + env_argv = acl_argv_split(ptr, ",\t "); + if (env_argv == NULL) + return; + + acl_foreach(iter, env_argv) { + name = (char*) iter.data; + ptr = strchr(name, ':'); + if (ptr == NULL) + continue; + *ptr++ = 0; + if (*ptr == 0) + continue; +#define STREQ !strcasecmp + + if (STREQ(name, "use_slice")) { + if (STREQ(ptr, "true")) + __use_slice = 1; + else + __use_slice = 0; + } else if (STREQ(name, "slice_base")) { + __slice_base = atoi(ptr); + if (__slice_base <= 0) + __slice_base = 8; + } else if (STREQ(name, "nslice")) { + __nslice = atoi(ptr); + if (__nslice <= 0) + __nslice = 1024; + } else if (STREQ(name, "nalloc_gc")) { + __nalloc_gc = atoi(ptr); + if (__nalloc_gc <= 0) + __nalloc_gc = 100000; + } else if (STREQ(name, "slice_gc")) { + if (STREQ(ptr, "gc1")) + __slice_gc = ACL_SLICE_FLAG_GC1; + else if (STREQ(ptr, "gc3")) + __slice_gc = ACL_SLICE_FLAG_GC3; + else + __slice_gc = ACL_SLICE_FLAG_GC2; + } else if (STREQ(name, "rtgc_off")) { + if (STREQ(ptr, "true")) + __rtgc_off = 1; + else + __rtgc_off = 0; + } + } + + if (__slice_gc == 0) + __use_slice = 0; +} + +static ACL_FIFO *get_modules(void) +{ + ACL_FIFO *modules = NULL; + +#ifdef JAWS_STATIC + MODULE_SERVICE *module; + + modules = acl_fifo_new(); + + module = (MODULE_SERVICE*) acl_mycalloc(1, sizeof(MODULE_SERVICE)); + module->mod_init = module_service_init; + module->mod_create = module_service_create; + module->mod_main = module_service_main; + acl_fifo_push(modules, module); +#endif + return (modules); +} + +static void __service_init(void *init_ctx acl_unused) +{ + ACL_AIO *aio = acl_aio_server_handle(); + ACL_FIFO *modules; + + modules = get_modules(); + service_init(aio, NULL); +} + +static void __service_exit(void *exit_ctx acl_unused) +{ + service_exit(); +} + +static int __service_main(ACL_SOCKET fd, void *run_ctx acl_unused) +{ + ACL_AIO *aio = acl_aio_server_handle(); + + return (service_main(fd, aio)); +} + +int main(int argc, char *argv[]) +{ + parse_env(); + + if (__use_slice) { + acl_msg_info("use mem slice, slice_base(%d), nslice(%d)," + " nalloc_gc(%d), rtgc_off(%s)", __slice_base, + __nslice, __nalloc_gc, __rtgc_off ? "yes" : "no"); + var_mem_slice = acl_mem_slice_init(__slice_base, __nslice, + __nalloc_gc, __rtgc_off ? + __slice_gc | ACL_SLICE_FLAG_RTGC_OFF : __slice_gc); + } else { + var_mem_slice = NULL; + } + + /* acl_debug_malloc_init("log.txt"); */ + acl_aio_app2_main(argc, argv, __service_main, NULL, + ACL_APP_CTL_INIT_FN, __service_init, + ACL_APP_CTL_EXIT_FN, __service_exit, + ACL_APP_CTL_CFG_BOOL, service_conf_bool_tab, + ACL_APP_CTL_CFG_INT, service_conf_int_tab, + ACL_APP_CTL_CFG_STR, service_conf_str_tab, +/* + ACL_APP_CTL_OPEN_LOG, app_set_libcore_log, + ACL_APP_CTL_CLOSE_LOG, app_libcore_log_end, +*/ + ACL_APP_CTL_END); + + exit (0); +} + diff --git a/app/jaws/module/Makefile b/app/jaws/module/Makefile new file mode 100644 index 000000000..1d1e1d2e4 --- /dev/null +++ b/app/jaws/module/Makefile @@ -0,0 +1,7 @@ + +.PHONY = all clean + +all: + @(cd mod_http; make) +clean: + @(cd mod_http; make clean) diff --git a/app/jaws/module/mod_http/Makefile b/app/jaws/module/mod_http/Makefile new file mode 100644 index 000000000..b6dfed329 --- /dev/null +++ b/app/jaws/module/mod_http/Makefile @@ -0,0 +1,121 @@ +SHELL = /bin/sh +CC = gcc +#CC = g++ +AR = ar +ARFL = rv +RANLIB = ranlib + +CFLAGS = -c -g -W -Wall \ +-Wcast-align \ +-Wcast-qual \ +-Waggregate-return -Wmissing-prototypes \ +-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO \ +-Wno-long-long \ +-Wpointer-arith -Werror -Wshadow -pedantic -O3 \ +-fPIC +########################################################### +#Check system: +# Linux, SunOS, Solaris, BSD variants, AIX, HP-UX +SYSLIB = +RPATH = + +CHECKSYSRES = @echo "Unknow system type!";exit 1 +UNIXNAME = $(shell uname -sm) +OSTYPE = $(shell uname -p) + +#Path for Linux +ifeq ($(findstring Linux, $(UNIXNAME)), Linux) +# ifeq ($CC, "gcc") + ifeq ($(findstring i686, $(OSTYPE)), i686) + RPATH = linux32 + endif + ifeq ($(findstring x86_64, $(OSTYPE)), x86_64) + RPATH = linux64 + endif + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DLINUX2 + SYSLIB += -lcrypt -lpthread +endif + +#Path for SunOS +ifeq ($(findstring SunOS, $(UNIXNAME)), SunOS) + ifeq ($(findstring i386, $(OSTYPE)), i386) + RPATH = sunos_x86 + endif + ifeq ($(findstring 86, $(UNIXNAME)), 86) + SYSLIB += -lsocket -lnsl -lrt + endif + ifeq ($(findstring sun4u, $(UNIXNAME)), sun4u) + SYSLIB += -lsocket -lnsl -lrt + endif +# ifeq ($CC, "gcc") + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DSUNOS5 +endif + +#Path for HP-UX +ifeq ($(findstring HP-UX, $(UNIXNAME)), HP-UX) +# ifeq ($CC, "gcc") + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + SYSLIB += -lpthread + CFLAGS += -DHP_UX -DHPUX11 + PLAT_NAME=hp-ux +endif + +#Find system type. +ifneq ($(SYSPATH),) + CHECKSYSRES = @echo "System is $(shell uname -sm)" +endif +########################################################### +ACL_PATH = ../../../../lib_acl +ACL_LIB = $(ACL_PATH)/lib +ACL_INC = $(ACL_PATH)/include + +PROTO_PATH = ../../../../lib_protocol +PROTO_LIB = $(PROTO_PATH)/lib +PROTO_INC = $(PROTO_PATH)/include + +GLOBAL_PATH = ../../global +GLOBAL_LIB = $(GLOBAL_PATH) +GLOBAL_INC = $(GLOBAL_PATH) + +ALL_LIBS = -L$(GLOBAL_LIB) -l_global -L$(PROTO_LIB) -l_protocol -L$(ACL_LIB) -l_acl $(SYSLIB) + +INCLUDE = -I$(GLOBAL_INC) -I$(PROTO_INC) -I$(ACL_INC) +CFLAGS += $(INCLUDE) -DHAVE_NO_STRCASESTR + +OBJ_OUTPATH = ./debug + +#Project's objs +SOURCES = $(wildcard ./*.c) +OBJS = $(patsubst %.c, $(OBJ_OUTPATH)/%.o, $(notdir $(SOURCES))) + +########################################################### +LIB_NAME = mod_http.so + +.PHONY = RM all clean +COMPILE = $(CC) $(CFLAGS) + +all: RM $(LIB_NAME) + +RM: + rm -f $(LIB_NAME) + +$(LIB_NAME): $(OBJS) + $(CC) -shared -o $(LIB_NAME) $(OBJS) $(ALL_LIBS) + cp -f $(LIB_NAME) ../../dist/unix_setup/module/$(RPATH)/ + +$(OBJ_OUTPATH)/%.o: ./%.c + $(COMPILE) -o $@ $< + +clean: + rm -f $(OBJS) $(LIB_NAME) + rm -f $(LIB_NAME) ../../dist/unix_setup/module/$(RPATH)/$(LIB_NAME) + +rebuild: clean all diff --git a/app/jaws/module/mod_http/Release/BuildLog.htm b/app/jaws/module/mod_http/Release/BuildLog.htm new file mode 100644 index 000000000..5919fa8fb --- /dev/null +++ b/app/jaws/module/mod_http/Release/BuildLog.htm @@ -0,0 +1,53 @@ + + + + + +
+
+生成日志 +
  
+

------- 已启动生成: 项目: mod_http,配置: Release|Win32 ------- +

+
+命令行 +
  
正在创建临时文件“d:\工作目录\项目管理\jaws\jaws\module\mod_http\Release\RSP000018.rsp”,其内容为
+[
+/OUT:"Release/mod_http.dll" /INCREMENTAL:NO /NOLOGO /LIBPATH:"..\..\lib\win32" /DLL /NODEFAULTLIB:"libcmt" /SUBSYSTEM:WINDOWS /OPT:REF /OPT:ICF /IMPLIB:"Release/mod_http.lib" /MACHINE:X86 lib_global.lib  lib_protocol.lib lib_acl.lib ws2_32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib
+.\Release\html_template.obj
+.\Release\http_client.obj
+.\Release\http_conf.obj
+.\Release\http_filter.obj
+.\Release\http_module.obj
+.\Release\http_plugin.obj
+.\Release\http_proxy.obj
+.\Release\http_server.obj
+.\Release\http_service.obj
+.\Release\http_vhost.obj
+.\Release\tcp_proxy.obj
+]
+正在创建命令行“link.exe @d:\工作目录\项目管理\jaws\jaws\module\mod_http\Release\RSP000018.rsp”
+正在创建临时文件“d:\工作目录\项目管理\jaws\jaws\module\mod_http\Release\BAT000019.bat”,其内容为
+[
+@echo off
+copy Release\mod_http.dll ..\..\build\mod_http.dll  /Y
+if errorlevel 1 goto VCReportError
+goto VCEnd
+:VCReportError
+echo Project : error PRJ0019: 工具从"正在执行生成后事件..."
+exit 1
+:VCEnd
+]
+正在创建命令行“d:\工作目录\项目管理\jaws\jaws\module\mod_http\Release\BAT000019.bat”
+
+输出窗口 +
  
正在链接...
+   正在创建库 Release/mod_http.lib 和对象 Release/mod_http.exp
+正在执行生成后事件...
+已复制         1 个文件。
+
+结果 +
  
+生成日志保存在“file://d:\工作目录\项目管理\jaws\jaws\module\mod_http\Release\BuildLog.htm”中
+mod_http - 0 错误,0 警告
+
\ No newline at end of file diff --git a/app/jaws/module/mod_http/bak/http_proxy.c.inline b/app/jaws/module/mod_http/bak/http_proxy.c.inline new file mode 100644 index 000000000..df52c0d59 --- /dev/null +++ b/app/jaws/module/mod_http/bak/http_proxy.c.inline @@ -0,0 +1,1328 @@ +#include "lib_acl.h" +#include "lib_protocol.h" +#include "assert.h" +#include "dns_lookup.h" +#include "conn_cache.h" +#include "service.h" +#include "http_module.h" +#include "http_service.h" + +#ifdef ACL_MS_WINDOWS +#include +#define getpid _getpid +#endif + +static inline int http_proxy_next(HTTP_CLIENT *http_client); +static inline void http_proxy_req_get(HTTP_CLIENT *http_client); + +/*---------------------------------------------------------------------------*/ + +/* 当前请求处理完毕, 是否继续下一个客户端请求? */ + +static inline void http_proxy_server_complete(HTTP_CLIENT *http_client, int keep_alive) +{ + HTTP_SERVICE *service = (HTTP_SERVICE*) http_client->entry.service; + ACL_ASTREAM *server; + ACL_VSTREAM *sstream; + + if (http_client->res) { + http_res_free(http_client->res); + http_client->res = NULL; + http_client->hdr_res = NULL; + } else if (http_client->hdr_res) { + http_hdr_res_free(http_client->hdr_res); + http_client->hdr_res = NULL; + } + + server = http_client->entry.server; + /* 是否应与服务端保持长连接? */ + if (server == NULL) { + return; + } + + /* 先禁止对该异步流继续监听 */ + acl_aio_disable_readwrite(server); + + /* 清除异步流的所有勾子回调函数,防止在流结束后回调被调用 */ + acl_aio_clean_hooks(server); + + sstream = acl_aio_vstream(server); + + if (keep_alive) { + int timeout = 60; +#if 0 + ACL_ASTREAM *ss; + + /* 重新打开一个异步流 */ + ss = acl_aio_open(acl_aio_handle(server), sstream); + + /* 与服务端流分离 */ + client_entry_detach(&http_client->entry, sstream); + + /* 将服务端异步流的数据流置空 */ + acl_aio_ctl(server, ACL_AIO_CTL_STREAM, NULL, ACL_AIO_CTL_END); + + /* 关闭老的异步流 */ + acl_aio_iocp_close(server); + + /* 将与服务端的连接流置入连接池中 */ + conn_cache_push_stream(service->service.conn_cache, + ss, timeout, NULL, NULL); +#else + /* 与服务端流分离 */ + client_entry_detach(&http_client->entry, sstream); + ACL_VSTRING_RESET(&server->strbuf); + + /* 将与服务端的连接流置入连接池中 */ + conn_cache_push_stream(service->service.conn_cache, + server, timeout, NULL, NULL); +#endif + } else { + client_entry_detach(&http_client->entry, sstream); + /* 关闭异步流 */ + acl_aio_iocp_close(server); + } +} + +static inline void http_proxy_client_complete(HTTP_CLIENT *http_client, int keep_alive) +{ + ACL_ASTREAM *client; + + /* 重置重试次数 */ + http_client->entry.nretry_on_error = 0; + http_client->entry.ip_ntry = 0; + + /* 清除本次会话完成标志位 */ + http_client->flag &= ~HTTP_FLAG_FINISH; + + client = http_client->entry.client; + if (client == NULL) { + return; + } + + /* 清除异步流的所有勾子回调函数,防止在流结束后回调被调用 */ + acl_aio_clean_hooks(client); + + /* 是否应与客户端保持长连接? */ + if (keep_alive) { + if (http_client->req_curr) { + http_client_req_free(http_client->req_curr); + http_client->req_curr = NULL; + } + http_proxy_next(http_client); + } else { + ACL_VSTREAM *cstream = acl_aio_vstream(client); + + if (http_client->req_curr) { + http_client_req_free(http_client->req_curr); + http_client->req_curr = NULL; + } + acl_aio_disable_readwrite(client); + /* 与客户端流分离 */ + client_entry_detach(&http_client->entry, cstream); + /* 关闭老的异步流 */ + acl_aio_iocp_close(client); + } +} + +static inline void http_proxy_complete(HTTP_CLIENT *http_client, int error_happen) +{ + /* 需要提前知道服务端流和客户端流是否已经被分离,因为下面经过 + * http_proxy_server_complete 或 http_proxy_client_complte 后 + * http_client 所占内存可能已经被释放,这样提前知道服务端/客户 + * 端流的状态可以避免内存非法访问 + */ + int server_null = http_client->entry.server == NULL; + int client_null = http_client->entry.client == NULL; + + /* 判定服务端流是否应保持长连接 */ + + if (var_cfg_http_server_keepalive && !error_happen + && http_client->hdr_res + && http_client->hdr_res->hdr.keep_alive) + { + http_client->flag |= HTTP_FLAG_SERVER_KEEP_ALIVE; + } + + /* 判定客户端流是否应保持长连接 */ + + if (var_cfg_http_client_keepalive && !error_happen + && (http_client->flag & HTTP_FLAG_SERVER_KEEP_ALIVE) + && http_client->req_curr + && http_client->req_curr->hdr_req + && http_client->req_curr->hdr_req->hdr.keep_alive) + { + http_client->flag |= HTTP_FLAG_CLIENT_KEEP_ALIVE; + } else { + http_client->flag &= ~HTTP_FLAG_CLIENT_KEEP_ALIVE; + } + + /* 如果服务端流处于锁定状态则不立即关闭服务端流 */ + +#if 1 + if (!server_null && !(http_client->flag & HTTP_FLAG_SERVER_LOCKED)) { + http_proxy_server_complete(http_client, + (http_client->flag & HTTP_FLAG_SERVER_KEEP_ALIVE)); + } +#else + /* 虽然服务端流处于锁定状态, 但此处调用 http_proxy_server_complete 后会清除所 + * 有的服务端流的回调函数(包括关闭回调函数), 如果在 http_proxy_server_complete + * 中对该服务端流保持长连接, 则会在 conn_cache_push_stream 中设置该流的关闭回 + * 调函数, 如果该流出错或有额外数据到达, 则该流便会在连接池中被关闭. + */ + if (!server_null) { + http_proxy_server_complete(http_client, + (http_client->flag & HTTP_FLAG_SERVER_KEEP_ALIVE)); + } +#endif + + /* 如果客户端流处于锁定状态则不立即关闭客户端流 */ + + if (!client_null && !(http_client->flag & HTTP_FLAG_CLIENT_LOCKED)) { + http_proxy_client_complete(http_client, + (http_client->flag & HTTP_FLAG_CLIENT_KEEP_ALIVE)); + } +} + +/*---------------------------------------------------------------------------*/ + +/* 发送响应数据至客户端,为了减少IO次数,合并响应头同响应体数据一起发送 */ + +static inline void send_to_client(HTTP_CLIENT *http_client, const char *data, int dlen) +{ + int hdr_len = (int) LEN(http_client->buf); + + /* 是否连同HTTP响应头一起发送? */ + if (hdr_len > 0) { + /* 将HTTP响应头和一部分数据体一起发送, + * 这样可以减少 IO 写次数 + */ + + struct iovec iov[2]; + + iov[0].iov_base = STR(http_client->buf); + iov[0].iov_len = hdr_len; + iov[1].iov_base = (char*) data; + iov[1].iov_len = dlen; + + /* 必须提交将缓冲区提前复位,但不影响内部数据 */ + ACL_VSTRING_RESET(http_client->buf); + /* 将客户端流加锁,防止被提前关闭 */ + http_client->flag |= HTTP_FLAG_CLIENT_LOCKED; + acl_aio_writev(http_client->entry.client, iov, 2); + } else { + /* 响应头已经发送,此处仅发送响应体部分数据 */ + + /* 将客户端流加锁,防止被提前关闭 */ + http_client->flag |= HTTP_FLAG_CLIENT_LOCKED; + acl_aio_writen(http_client->entry.client, data, dlen); + } +} + +/* 获得服务器HTTP数据体并发送至浏览器 */ + +static inline void forward_respond_body_data(HTTP_CLIENT *http_client, + const char *data, int dlen) +{ + const char *data_saved = data; + const char *data_ptr = data; + char *ptr; + ACL_ITER iter; + plugin_dat_free_fn last_plugin_free = NULL; + char *last_plugin_buf = NULL; + void *plugin_res_ctx = http_client->plugin_res_ctx; + HTTP_SERVICE *service = (HTTP_SERVICE*) http_client->entry.service; + + /* 遍历所有的数据体过滤器 */ + acl_foreach(iter, &service->respond_dat_plugins) { + HTTP_PLUGIN *tmp = (HTTP_PLUGIN*) iter.data; + int stop = 0, ret; + ptr = tmp->data_filter(data_ptr, dlen, &ret, &stop, plugin_res_ctx); + + /* 释放前一个过滤器分配的动态内存 */ + if (last_plugin_buf && last_plugin_buf != data_saved && last_plugin_free) + last_plugin_free(last_plugin_buf, plugin_res_ctx); + + dlen = ret; + data = data_ptr = ptr; + last_plugin_buf = ptr; + last_plugin_free = tmp->data_free; + + if (ret < 0 || ptr == NULL) { + ret = -1; + data = NULL; + break; + } else if (stop) + break; + } + + /* 向客户端写数据 */ + if (dlen > 0 && data) + send_to_client(http_client, data, dlen); + + /* 释放前一个过滤器分配的动态内存 */ + if (last_plugin_buf && last_plugin_buf != data_saved && last_plugin_free) + last_plugin_free(last_plugin_buf, plugin_res_ctx); +} + +/* 成功从服务器读到响应体数据的回调函数 */ + +static inline int read_respond_body_ready(int status, const char *data, int dlen, void *arg) +{ + HTTP_CLIENT *http_client = (HTTP_CLIENT *) arg; + + if (data == NULL || dlen <= 0) { + /* 取消服务端流的锁定状态 */ + http_client->flag &= ~HTTP_FLAG_SERVER_LOCKED; + /* 设置会话完成标志位 */ + http_client->flag |= HTTP_FLAG_FINISH; + http_proxy_complete(http_client, -1); + return (-1); + } + + http_client->total_size += dlen; + + /* client 流有可能被提前关闭了 */ + if (http_client->entry.client == NULL) { + /* 取消服务端流的锁定状态 */ + http_client->flag &= ~HTTP_FLAG_SERVER_LOCKED; + /* 设置会话完成标志位 */ + http_client->flag |= HTTP_FLAG_FINISH; + http_proxy_complete(http_client, -1); + return (-1); + } + + if (status >= HTTP_CHAT_ERR_MIN) { + /* 取消服务端流的锁定状态 */ + http_client->flag &= ~HTTP_FLAG_SERVER_LOCKED; + /* 设置会话完成标志位 */ + http_client->flag |= HTTP_FLAG_FINISH; + http_proxy_complete(http_client, -1); + return (-1); + } else if (status == HTTP_CHAT_OK) { + /* 设置会话完成标志位 */ + http_client->flag |= HTTP_FLAG_FINISH; + /* 取消服务端流的锁定状态 */ + http_client->flag &= ~HTTP_FLAG_SERVER_LOCKED; + } + + /* 如果 HTTP_FLAG_FINISH 标志设置,则会在 forward_respond_body_data 之后 + * 回调函数 send_respond_body_complete 调用 http_proxy_complete + */ + forward_respond_body_data(http_client, data, dlen); +#if 0 + if (status == HTTP_CHAT_OK) { + /* 取消服务端流的锁定状态 */ + http_client->flag &= ~HTTP_FLAG_SERVER_LOCKED; + http_proxy_complete(http_client, 0); + } +#endif + + return (0); +} + +/* 发送响应体数据至客户端, 如果确定已经发送完最后一批数据则触发结束过程 */ + +static inline int send_respond_body_complete(ACL_ASTREAM *client acl_unused, void *ctx) +{ + HTTP_CLIENT *http_client = (HTTP_CLIENT *) ctx; + + /* 取消客户端流的锁定状态, 从而允许当服务流异常关闭时可以在 + * on_close_server 等函数里调用 http_proxy_complete 时里关闭客户流! + */ + http_client->flag &= ~HTTP_FLAG_CLIENT_LOCKED; + +#if 1 + /* 如果是最后的数据则完成本次会话过程 */ + if ((http_client->flag & HTTP_FLAG_FINISH)) { + if ((http_client->flag & HTTP_FLAG_SERVER_CLOSED)) + http_proxy_complete(http_client, -1); + else + http_proxy_complete(http_client, 0); + } +#endif + return (0); +} + +/* 传输服务器响应HTTP数据体至浏览器 + * 调用该过程的函数需要注意流关闭保护措施 + */ + +static inline void forward_respond_hdr_body(HTTP_CLIENT *http_client) +{ + /* 创建HTTP响应体对象 */ + http_client->res = http_res_new(http_client->hdr_res); + + /* 如果向客户流发送响应体失败会自动调用在 send_request_hdr_complete + * 里针对客户流设置的回调函数 on_close_clinet + */ + + /* 设置向客户流发送数据成功的回调函数 */ + acl_aio_add_write_hook(http_client->entry.client, + send_respond_body_complete, http_client); + + /* 将服务端流置于锁定状态, 从而防止被提前关闭 */ + http_client->flag |= HTTP_FLAG_SERVER_LOCKED; + + /* 开始从服务器读取HTTP数据体数据 */ + http_res_body_get_async(http_client->res, + http_client->entry.server, + read_respond_body_ready, + http_client, + http_client->entry.service->rw_timeout); +} + +/* 发送服务器响应头至浏览器 */ + +static inline int send_respond_hdr_complete(ACL_ASTREAM *client acl_unused, void *ctx) +{ + const char *myname = "send_respond_hdr_complete"; + HTTP_CLIENT *http_client = (HTTP_CLIENT *) ctx; + + /* 取消客户端流的锁定状态 */ + http_client->flag &= ~HTTP_FLAG_CLIENT_LOCKED; + + if (http_client->hdr_res == NULL) { + acl_msg_error("%s(%d): http_client->hdr_res null", myname, __LINE__); + http_proxy_complete(http_client, -1); + return (0); + } + + /* 因为进入此函数后 client 的引用值已经被 acl_aio_xxx 自动加1了, + * 所以也许不必担心重复关闭流的现象发生 + */ + http_proxy_complete(http_client, 0); + return (0); +} + +/* 仅 forward 响应头,因为没有响应体 */ + +static inline void forward_respond_hdr(HTTP_CLIENT *http_client) +{ + acl_aio_add_write_hook(http_client->entry.client, + send_respond_hdr_complete, http_client); + + /* 设定客户端流为锁定状态 */ + http_client->flag |= HTTP_FLAG_CLIENT_LOCKED; + + acl_aio_writen(http_client->entry.client, + acl_vstring_str(http_client->buf), + (int) ACL_VSTRING_LEN(http_client->buf)); +} + +static inline void start_forward_respond(HTTP_CLIENT *http_client) +{ + /* 是否与服务端保持长连接? */ + if (!var_cfg_http_client_keepalive) { + http_hdr_entry_replace(&http_client->hdr_res->hdr, + "Connection", "close", 1); + http_hdr_entry_replace(&http_client->hdr_res->hdr, + "Proxy-Connection", "close", 0); + } else if (http_client->req_curr->hdr_req->hdr.keep_alive + && http_client->hdr_res->hdr.keep_alive) + { + http_hdr_entry_replace(&http_client->hdr_res->hdr, + "Connection", "keep-alive", 1); + http_hdr_entry_replace(&http_client->hdr_res->hdr, + "Proxy-Connection", "keep-alive", 0); + } + + /* 重新组成HTTP响应头 */ + http_hdr_build(&http_client->hdr_res->hdr, http_client->buf); + + /* 对于 3xx, 4xx 的服务器响应,不应有数据体部分 */ + + if (http_client->hdr_res->hdr.content_length == 0 + || (http_client->hdr_res->hdr.content_length == -1 + && !http_client->hdr_res->hdr.chunked + && http_client->hdr_res->reply_status > 300 + && http_client->hdr_res->reply_status < 400)) + { + /* 如果没有数据体,则仅返回数据头 */ + forward_respond_hdr(http_client); + return; + } + + /* 将数据头连同一部分数据体一起发送给客户端,从而减少io次数 */ + + /* xxx: 对于没有 content-length 或 content-length > 0 + * 及服务器响应状态码不为 3xx, 4xx 的情况 + */ + forward_respond_hdr_body(http_client); +} + +/** + * 针对HTTP响应头的过滤器处理过程,如果根据该响应头过滤器决定完全接管 + * 该响应则主程序不再处理该服务端流及客户端流 + * 返回 0 表示所有过滤器均不接管该响应, 否则表示接管 + */ +static inline int reply_plugin_takeover(HTTP_CLIENT *http_client) +{ + const char *myname = "reply_plugin_takeover"; + HTTP_SERVICE *service = (HTTP_SERVICE*) http_client->entry.service; + HTTP_PLUGIN *plugin = NULL; + ACL_ITER iter; + + /* xxx: plugin_res_ctx 该参数在每次请求都有可能不一样, 外挂模块应该自行管理 */ + http_client->plugin_res_ctx = NULL; + + /* 遍历所有的插件回调处理函数 */ + + acl_foreach(iter, &service->respond_plugins) { + ACL_ASTREAM *client = http_client->entry.client; + ACL_ASTREAM *server = http_client->entry.server; + ACL_VSTREAM *client_stream = acl_aio_vstream(client); + ACL_VSTREAM *server_stream = acl_aio_vstream(server); + HTTP_PLUGIN *tmp = (HTTP_PLUGIN*) iter.data; + + if (tmp->filter.respond(client_stream, server_stream, + http_client->req_curr->hdr_req, + http_client->hdr_res, + &http_client->plugin_res_ctx)) + { + plugin = tmp; + break; + } + } + + if (plugin && plugin->forward.respond) { + ACL_ASTREAM *client = http_client->entry.client; + ACL_ASTREAM *server = http_client->entry.server; + ACL_VSTREAM *client_stream = acl_aio_vstream(client); + ACL_VSTREAM *server_stream = acl_aio_vstream(server); + HTTP_HDR_REQ *hdr_req; + HTTP_HDR_RES *hdr_res; + void *plugin_res_ctx = http_client->plugin_res_ctx; + + /* 将 http_client 中的 hdr_req/hdr_res 置空 */ + if (http_client->req_curr) { + hdr_req = http_client->req_curr->hdr_req; + http_client->req_curr->hdr_req = NULL; + if (http_client->req_curr->req) + http_client->req_curr->req->hdr_req = NULL; + } else { + acl_msg_fatal("%s(%d): req_curr null", myname, __LINE__); + /* XXX: can't reach here just avoid compiling warning */ + hdr_req = NULL; + } + hdr_res = http_client->hdr_res; + http_client->hdr_res = NULL; + + /* 将客户端数据流与该代理对象分离 */ + client_entry_detach(&http_client->entry, client_stream); + + /* 将服务端数据与该代理对象分离 */ + /* 因为 entry 代理对象的引用计数为0,所以其会在该分离函数 + * 中自动被释放 + */ + client_entry_detach(&http_client->entry, server_stream); + + /* 禁止异步流的读/写监控 */ + acl_aio_disable_readwrite(client); + acl_aio_disable_readwrite(server); + + /* 清除回调函数 */ + acl_aio_clean_hooks(client); + acl_aio_clean_hooks(server); + + /* 将客户端异步流的数据流置空 */ + acl_aio_ctl(client, ACL_AIO_CTL_STREAM, NULL, ACL_AIO_CTL_END); + /* 将服务端异步流的数据流置空 */ + acl_aio_ctl(server, ACL_AIO_CTL_STREAM, NULL, ACL_AIO_CTL_END); + + /* xxx: 异步关闭 client/server 异步流 */ + acl_aio_iocp_close(client); + acl_aio_iocp_close(server); + + /* 必须流由非阻塞模式转换为阻塞模式 */ + acl_non_blocking(ACL_VSTREAM_SOCK(client_stream), ACL_BLOCKING); + acl_non_blocking(ACL_VSTREAM_SOCK(server_stream), ACL_BLOCKING); + + /* 调用在非阻塞通信时设置的关闭回调函数并清除之 */ + acl_vstream_call_close_handles(client_stream); + acl_vstream_call_close_handles(server_stream); + + /* 至此,已经将客户端数据流由非阻塞模式转换为阻塞模式,同时关闭 + * 了与服务端的连接流,将该连接请求转给相关代理模块处理,异步 + * 代理不再代理该客户端的请求及服务端的响应 + * 注意:client_stream, hdr_res, hdr_res 此处并未释放, + * 需要下载代理模块下载完毕后自己单独释放 + */ + plugin->forward.respond(client_stream, server_stream, + hdr_req, hdr_res, plugin_res_ctx); + return (1); + } + + return (0); +} + +static inline int http_request_reforward(HTTP_CLIENT *http_client); +static inline int read_respond_hdr_timeout(ACL_ASTREAM *server, void *ctx); +static inline int read_respond_hdr_error(ACL_ASTREAM *server, void *ctx); + +/* 获得服务器响应头 */ +static inline void begin_read_respond(HTTP_CLIENT *http_client); + +static inline int get_respond_hdr_ready(int status, void *arg) +{ + const char *myname = "get_respond_hdr_ready"; + HTTP_CLIENT *http_client = (HTTP_CLIENT *) arg; + ACL_ASTREAM *client = http_client->entry.client; + ACL_ASTREAM *server = http_client->entry.server; + + /* 取消服务流的锁定状态 */ + http_client->flag &= ~HTTP_FLAG_SERVER_LOCKED; + + /* xxx: sanity check */ + + if (client == NULL) { + acl_msg_warn("%s: client null(%s)", myname, + http_client->flag & HTTP_FLAG_FINISH + ? "finished" : "not finished"); + http_client->flag |= HTTP_FLAG_FINISH; + http_proxy_complete(http_client, -1); + return (0); + } + + /* 需要关闭两个回调函数,防止触发 read_respond_hdr_error + * 和 read_respond_hdr_timeout 过程(read_respond_hdr_timeout 会触发 + * read_respond_hdr_error), 而在 read_respond_hdr_error 里会调用 + * http_request_reforward + */ + acl_aio_ctl(server, + ACL_AIO_CTL_CLOSE_HOOK_DEL, read_respond_hdr_error, http_client, + ACL_AIO_CTL_TIMEO_HOOK_DEL, read_respond_hdr_timeout, http_client, + ACL_AIO_CTL_END); + + if (status != HTTP_CHAT_OK) { + /* 如果读响应头出现错误则需要重试 */ + + /* 进行重试 */ + if (http_request_reforward(http_client) == 0) { + /* 如果已经开始重试过程,则直接返回 */ + return (0); + } + + http_proxy_complete(http_client, -1); + /* xxx: 应该返回 5xx 信息给客户端 */ + return (0); + } + + /* 分析 HTTP 响应头 */ + + if (http_hdr_res_parse(http_client->hdr_res) < 0) { + /* 如果分析响应头失败则需要重试 */ + + acl_msg_error("%s: parse hdr_res error", myname); + /* 进行重试 */ + if (http_request_reforward(http_client) == 0) { + /* 如果已经开始重试过程,则直接返回 */ + return (0); + } + + http_proxy_complete(http_client, -1); + /* xxx: 应该返回 5xx 信息给客户端 */ + return (0); + } + + /* 忽略 100 continue 的回应 */ + if (http_client->hdr_res->reply_status == 100) { + begin_read_respond(http_client); + return (0); + } + + /* 判断是否需要由其它代理模块接管 */ + if (reply_plugin_takeover(http_client)) { + return (0); + } + + /* 开始转发服务器返回的数据给客户端 */ + start_forward_respond(http_client); + return (0); +} + +static inline int read_respond_hdr_timeout(ACL_ASTREAM *server, void *ctx) +{ + const char *myname = "read_respond_hdr_timeout"; + HTTP_CLIENT *http_client = (HTTP_CLIENT *) ctx; + + /* 取消服务流的锁定状态 */ + http_client->flag &= ~HTTP_FLAG_SERVER_LOCKED; + + /* 取消 HTTP 响应头的读关闭回调函数 */ + acl_aio_clean_close_hooks(server); + + if (http_client->entry.client == NULL) { + acl_msg_warn("%s(%d): client null", myname, __LINE__); + http_proxy_complete(http_client, -1); + /* 必须返回 -1, 因为不希望继续调用其它的超时回调函数 */ + return (-1); + } + + /* 进行重试 */ + if (http_request_reforward(http_client) == 0) { + /* 如果已经开始重试过程,则直接返回 */ + /* 必须返回 -1, 因为不希望继续调用其它的超时回调函数 */ + return (-1); + } + + /* 锁定客户端流 */ + http_client->flag |= HTTP_FLAG_CLIENT_LOCKED; + + /* 返回给客户端读服务端响应超时信息 */ + acl_aio_writen(http_client->entry.client, + HTTP_REPLY_TIMEOUT, (int) strlen(HTTP_REPLY_TIMEOUT)); + + /* 解锁客户端流 */ + http_client->flag &= ~HTTP_FLAG_CLIENT_LOCKED; + + http_proxy_complete(http_client, -1); + /* 必须返回 -1, 因为不希望继续调用其它的超时回调函数 */ + return (-1); +} + +static inline int read_respond_hdr_error(ACL_ASTREAM *server acl_unused, void *ctx) +{ + const char *myname = "read_respond_hdr_error"; + HTTP_CLIENT *http_client = (HTTP_CLIENT *) ctx; + + /* 取消服务流的锁定状态 */ + http_client->flag &= ~HTTP_FLAG_SERVER_LOCKED; + + if (http_client->entry.client == NULL) { + acl_msg_warn("%s(%d): client null", myname, __LINE__); + /* 必须返回 -1, 因为不希望继续调用其它的关闭回调函数 */ + http_proxy_complete(http_client, -1); + return (-1); + } + + /* 进行重试 */ + if (http_request_reforward(http_client) == 0) { + /* 如果已经开始重试过程,则直接返回 */ + /* 必须返回 -1, 因为不希望继续调用其它的关闭回调函数 */ + return (-1); + } + + /* 锁定客户端流 */ + http_client->flag |= HTTP_FLAG_CLIENT_LOCKED; + + /* 返回给客户端读服务端响应出错信息 */ + acl_aio_writen(http_client->entry.client, + HTTP_REPLY_ERROR, (int) strlen(HTTP_REPLY_ERROR)); + + /* 解锁客户端流 */ + http_client->flag &= ~HTTP_FLAG_CLIENT_LOCKED; + + http_proxy_complete(http_client, -1); + /* 必须返回 -1, 因为不希望继续调用其它的关闭回调函数 */ + return (-1); +} + +/* XXX: 该函数需要处于关闭保护状态,即调用此函数的函数需要对服务端流加保护措施 */ + +static inline void begin_read_respond(HTTP_CLIENT *http_client) +{ + /* 生成一个 HTTP 响应头 */ + http_client->hdr_res = http_hdr_res_new(); + + /* 设定服务流的锁定状态 */ + http_client->flag |= HTTP_FLAG_SERVER_LOCKED; + + /* 设置从服务器的读错误及读超时的回调函数 */ + acl_aio_ctl(http_client->entry.server, + ACL_AIO_CTL_CLOSE_HOOK_ADD, read_respond_hdr_error, http_client, + ACL_AIO_CTL_TIMEO_HOOK_ADD, read_respond_hdr_timeout, http_client, + ACL_AIO_CTL_END); + + /* 开始读服务端的 HTTP 响应头 */ + http_hdr_res_get_async(http_client->hdr_res, + http_client->entry.server, + get_respond_hdr_ready, + http_client, + http_client->entry.service->rw_timeout); + +#if 0 + /* xxx: 此处可以添加 pipeline 方式读客户端下一个请求 */ + if (var_cfg_http_client_keepalive + && http_client->req_curr + && http_client->req_curr->hdr_req + && http_client->req_curr->hdr_req->hdr.keep_alive) + { + http_proxy_req_get(http_client); + } else + acl_aio_disable_read(http_client->entry.client); +#endif +} + +/*----------------------------------------------------------------------------*/ + +/* 发送最后请求数据至服务器的回调函数, 至此函数,通信方向发生 + * 改变,由原来的从客户流读数据、向服务流写数据变为从服务流读 + * 数据、向客户流写数据 + */ + +static inline int send_request_body_complete(ACL_ASTREAM *server, void *context) +{ + HTTP_CLIENT *http_client = (HTTP_CLIENT*) context; + + /* 取消服务流的锁定状态 */ + http_client->flag &= ~HTTP_FLAG_SERVER_LOCKED; + + /* xxx: sanity check */ + if (http_client->entry.client == NULL) { + http_proxy_complete(http_client, -1); + return (0); + } + + /* 如果请求体数据发送完毕则开始读取服务器响应 */ + if ((http_client->flag & HTTP_FLAG_REQEND)) { + /* 取消之前设置的发送请求体成功的回调函数 */ + acl_aio_del_write_hook(server, send_request_body_complete, + http_client); + http_client->flag &= ~HTTP_FLAG_REQEND; + /* 开始读取服务端的响应数据 */ + begin_read_respond(http_client); + } + return (0); +} + +/* 读到一些HTTP请求体数据 */ + +static inline int read_request_body_ready(int status, const char *data, int dlen, void *arg) +{ + const char *myname = "read_request_body_ready"; + HTTP_CLIENT *http_client = (HTTP_CLIENT *) arg; + + if (data == NULL || dlen <= 0) { + acl_msg_error("%s(%d): data: %s, dlen: %d", + myname, __LINE__, data ? "not null" : "null", dlen); + /* 取消客户流的锁定状态 */ + http_client->flag &= ~HTTP_FLAG_CLIENT_LOCKED; + /* 设置请求过程完毕标志位 */ + http_client->flag |= HTTP_FLAG_REQEND; + http_proxy_complete(http_client, -1); + return (0); + } + + if (http_client->entry.server == NULL) { + /* 有可能在向服务端写数据时出错而触发了 on_close_server 过程, + * 从而导致 http_proxy_complete 过程被调用 + */ + + /* 取消客户流的锁定状态 */ + http_client->flag &= ~HTTP_FLAG_CLIENT_LOCKED; + /* 设置请求过程完毕标志位 */ + http_client->flag |= HTTP_FLAG_REQEND; + http_proxy_complete(http_client, -1); + return (0); + } + + if (status >= HTTP_CHAT_ERR_MIN) { + /* 取消客户端流的锁定状态 */ + http_client->flag &= ~HTTP_FLAG_CLIENT_LOCKED; + /* 设置请求过程完毕标志位 */ + http_client->flag |= HTTP_FLAG_REQEND; + http_proxy_complete(http_client, -1); + return (0); + } else if (status == HTTP_CHAT_OK) { + /* 已经读完了浏览器本次会话的请求数据 */ + + /* 因为已经从客户端读完了本次会话的请求数据,所以此处可以 + * 取消客户端流锁定状态, 以允许当向服务端写数据出错时可以在 + * on_close_server 中关闭客户端流 + */ + http_client->flag &= ~HTTP_FLAG_CLIENT_LOCKED; + /* 设置请求过程完毕标志位 */ + http_client->flag |= HTTP_FLAG_REQEND; + } + + /* 设定服务端流的锁定状态 */ + http_client->flag |= HTTP_FLAG_SERVER_LOCKED; + /* 将来自于浏览器的数据体部分发送至服务器 */ + acl_aio_writen(http_client->entry.server, data, dlen); + return (0); +} + +/* 如果有请求体则转发请求体数据至服务器 */ + +static inline void forward_request_body(HTTP_CLIENT *http_client) +{ + /* 根据请求头对象生成请求体对象 */ + http_client->req_curr->req = http_req_new(http_client->req_curr->hdr_req); + + /* 设置发送请求体成功的回调函数 */ + acl_aio_add_write_hook(http_client->entry.server, + send_request_body_complete, http_client); + + /* 将客户端流置于锁定状态, 从而防止被提前关闭 */ + http_client->flag |= HTTP_FLAG_CLIENT_LOCKED; + + /* 开始读客户端请求体数据 */ + http_req_body_get_async(http_client->req_curr->req, + http_client->entry.client, + read_request_body_ready, + http_client, + http_client->entry.service->rw_timeout); +} + +/* 发送请求头至服务器时出错的回调函数 */ +static int send_request_hdr_complete(ACL_ASTREAM *server, void *ctx); + +static inline int send_request_hdr_error(ACL_ASTREAM *server acl_unused, void *ctx) +{ + HTTP_CLIENT *http_client = (HTTP_CLIENT *) ctx; + + /* 取消服务流的锁定状态 */ + http_client->flag &= ~HTTP_FLAG_SERVER_LOCKED; + + /* 如果仅是传输请求头时出错,则可以进行重试 */ + if (http_request_reforward(http_client) == 0) { + /* 如果已经开始重试过程,则直接返回 */ + /* 必须返回 -1, 因为不希望继续调用其它的关闭回调函数 */ + return (-1); + } + + /* 防止向客户流写数据出错时提前关闭客户流 */ + acl_aio_refer(http_client->entry.client); + + /* 返回给客户端读服务端响应出错信息 */ + acl_aio_writen(http_client->entry.client, + HTTP_SEND_ERROR, (int) strlen(HTTP_SEND_ERROR)); + + /* 恢复客户流为可关闭状态 */ + acl_aio_unrefer(http_client->entry.client); + + /* 该会话完毕 */ + http_proxy_complete(http_client, -1); + /* 必须返回 -1, 因为不希望继续调用其它的关闭回调函数 */ + return (-1); +} + +/* 发送请求头至服务器成功时的回调函数 */ + +static inline int send_request_hdr_complete(ACL_ASTREAM *server acl_unused, void *ctx) +{ + HTTP_CLIENT *http_client = (HTTP_CLIENT *) ctx; + + /* 取消服务流的锁定状态 */ + http_client->flag &= ~HTTP_FLAG_SERVER_LOCKED; + + /* 关闭上次注册的写完成及出错的回调函数 */ + acl_aio_ctl(http_client->entry.server, + ACL_AIO_CTL_WRITE_HOOK_DEL, send_request_hdr_complete, http_client, + ACL_AIO_CTL_CLOSE_HOOK_DEL, send_request_hdr_error, http_client, + ACL_AIO_CTL_END); + + if (http_client->req_curr->hdr_req->hdr.content_length > 0) { + /* 如果有请求体,则读取客户端请求体数据 */ + forward_request_body(http_client); + } else { + /* 没有请求体,则开始读服务端的返回数据 */ + begin_read_respond(http_client); + } + + return (0); +} + +/* 重新构建HTTP请求头 */ + +static inline void rebuild_request(HTTP_HDR_REQ *hdr_req, ACL_VSTRING *buf) +{ + ACL_ITER iter; + HTTP_HDR_ENTRY *entry; + int i = 0; + + /* XXX: nginx 有时对含有 Proxy-Connection 的请求有时会有延迟? */ + http_hdr_entry_off(&hdr_req->hdr, "Proxy-Connection"); + +#if 0 + acl_vstring_sprintf(buf, "%s http://%s%s HTTP/%d.%d\r\n", + hdr_req->method, hdr_req->host, + acl_vstring_str(hdr_req->url_part), + hdr_req->hdr.version.major, + hdr_req->hdr.version.minor); +#else + acl_vstring_sprintf(buf, "%s %s HTTP/%d.%d\r\n", + hdr_req->method, + acl_vstring_str(hdr_req->url_part), + hdr_req->hdr.version.major, + hdr_req->hdr.version.minor); +#endif + + acl_foreach(iter, hdr_req->hdr.entry_lnk) { + if (i++ == 0) + continue; + entry = (HTTP_HDR_ENTRY*) iter.data; + if (entry->off) + continue; + acl_vstring_strcat(buf, entry->name); + acl_vstring_strcat(buf, ": "); + acl_vstring_strcat(buf, entry->value); + acl_vstring_strcat(buf, "\r\n"); + } + acl_vstring_strcat(buf, "\r\n"); +} + +/* 连接服务器成功,开始向服务器发送HTTP请求头 */ +static inline void start_forward_request(HTTP_CLIENT *http_client) +{ + /* 分配动态内存 */ + if (http_client->buf == NULL) { + http_client->buf = acl_vstring_alloc(HTTP_HDRLEN_DEF); + } else { + ACL_VSTRING_RESET(http_client->buf); + } + + /* 重新创建 HTTP 请求头至 http_client->buf 中 */ + rebuild_request(http_client->req_curr->hdr_req, http_client->buf); + + /* 设置回调函数 */ + acl_aio_ctl(http_client->entry.server, + ACL_AIO_CTL_WRITE_HOOK_ADD, send_request_hdr_complete, http_client, + ACL_AIO_CTL_CLOSE_HOOK_ADD, send_request_hdr_error, http_client, + ACL_AIO_CTL_END); + + /* 锁定服务端 */ + http_client->flag |= HTTP_FLAG_SERVER_LOCKED; + + /* 向服务器转发客户端的HTTP请求头数据 */ + acl_aio_writen(http_client->entry.server, + acl_vstring_str(http_client->buf), + (int) ACL_VSTRING_LEN(http_client->buf)); +} + +/*----------------------------------------------------------------------------*/ + +/* 将客户端请求数据重新向后端其它服务器发送 */ + +static inline int http_request_reforward(HTTP_CLIENT *http_client) +{ + const char *myname = "http_request_reforward"; + ACL_ASTREAM *server = http_client->entry.server; + + /* 如果不是从连接池中取得的连接则将重试次数加 1 */ + if (!http_client->entry.flag_conn_reuse) + http_client->entry.nretry_on_error++; + + if (http_client->hdr_res) { + http_hdr_res_free(http_client->hdr_res); + http_client->hdr_res = NULL; + } + + /* 断开与服务端的连接,但保持与浏览器端的连接 */ + if (server) { + /* 使服务流与该会话分离 */ + client_entry_detach(&http_client->entry, acl_aio_vstream(server)); + /* 取消 HTTP 响应头的回调函数 */ + acl_aio_clean_hooks(server); + /* only for test */ + if (acl_aio_iswset(server)) { + acl_msg_info("%s(%d): defer free(%d)\n", myname, __LINE__, ACL_VSTREAM_SOCK(server->stream)); + } else + acl_msg_info("%s(%d): not defer free(%d)\n", myname, __LINE__, ACL_VSTREAM_SOCK(server->stream)); + /* 仅异步关闭服务端流 */ + acl_aio_iocp_close(server); + } + + /* 如果重试次数超过该域名所对应的IP主机个数则返回错误,不再重试 */ + if (http_client->entry.nretry_on_error > http_client->entry.dns_ctx.ip_cnt) { + acl_msg_error("%s(%d): has retried before(%d,%d), reuse connecion %s", + myname, __LINE__, http_client->entry.nretry_on_error, + http_client->entry.dns_ctx.ip_cnt, + http_client->entry.flag_conn_reuse ? "yes" : "no"); + return (-1); + } + + /* 如果重试次数超过阀值,则不再重试直接返回错误 */ + if (http_client->entry.nretry_on_error >= MAX_RETRIED) { + acl_msg_error("%s(%d): has retried before(%d,%d)", + myname, __LINE__, http_client->entry.nretry_on_error, + MAX_RETRIED); + return (-1); + } + + /* 开始重试连接下一个IP */ + forward_start((CLIENT_ENTRY*) http_client); + return (0); +} + +/*----------------------------------------------------------------------------*/ + +static char HTTP_CONNECT_FIRST[] = "HTTP/1.0 200 Connection established\r\n\r\n"; + +/* 当服务端流关闭时的回调函数 */ + +static inline int on_close_server(ACL_ASTREAM *server acl_unused, void *ctx) +{ + HTTP_CLIENT *http_client = (HTTP_CLIENT*) ctx; + + /* 取消服务端流的锁定状态 */ + http_client->flag &= ~HTTP_FLAG_SERVER_LOCKED; + http_client->flag |= HTTP_FLAG_SERVER_CLOSED | HTTP_FLAG_FINISH; + http_proxy_complete(http_client, -1); + /* 必须返回 -1, 因为不希望继续调用其它的关闭回调函数 */ + return (-1); +} + +static inline int http_proxy_connect_complete(CLIENT_ENTRY *entry) +{ + HTTP_CLIENT *http_client = (HTTP_CLIENT*) entry; + const char *method = http_client->req_curr->hdr_req->method; + + /* 添加服务流关闭时的回调函数 */ + acl_aio_add_close_hook(http_client->entry.server, + on_close_server, http_client); + + /* CONNECT 请求, 转向纯 TCP 代理模式, 从而方便支持 SSL */ + if (var_cfg_http_method_connect_enable && strcasecmp(method, "CONNECT") == 0) { + if (entry->client == NULL) { + acl_msg_warn("%s(%d): client null", __FILE__, __LINE__); + http_proxy_complete(http_client, -1); + return (0); + } + + acl_aio_writen(entry->client, HTTP_CONNECT_FIRST, + (int) strlen(HTTP_CONNECT_FIRST)); + if (entry->client && entry->server) { + tcp_start(entry); + return (0); + } else { + http_proxy_complete(http_client, -1); + return (0); + } + } + + if (strcasecmp(method, "GET") != 0 && strcasecmp(method, "POST") != 0) { + if (entry->client == NULL) { + acl_msg_error("%s(%d): client null", __FILE__, __LINE__); + } else + acl_aio_writen(entry->client, HTTP_REQUEST_INVALID, + (int) strlen(HTTP_REQUEST_INVALID)); + acl_msg_error("%s(%d): method(%s) invalid", + __FILE__, __LINE__, method); + http_proxy_complete(http_client, -1); + return (0); /* 返回-1以使异步框架关闭该异步流 */ + } + + /* 处理 GET、POST 请求 */ + start_forward_request(http_client); + return (0); +} + +static inline void http_proxy_connect_timeout(CLIENT_ENTRY *entry) +{ + const char *myname = "http_proxy_connect_timeout"; + + if (entry->client == NULL) { + acl_msg_error("%s(%d): client null", myname, __LINE__); + http_proxy_complete((HTTP_CLIENT*) entry, -1); + } else { + acl_msg_error("%s(%d): connect(%s, %s) timeout", + myname, __LINE__, entry->domain_key, + entry->domain_addr); + acl_aio_refer(entry->client); + acl_aio_writen(entry->client, HTTP_CONNECT_TIMEOUT, + (int) strlen(HTTP_CONNECT_TIMEOUT)); + acl_aio_unrefer(entry->client); + http_proxy_complete((HTTP_CLIENT*) entry, -1); + } +} + +static inline void http_proxy_connect_error(CLIENT_ENTRY *entry) +{ + const char *myname = "http_proxy_connect_error"; + + if (entry->client == NULL) { + acl_msg_error("%s(%d): client null", myname, __LINE__); + http_proxy_complete((HTTP_CLIENT*) entry, -1); + } else { + acl_msg_error("%s(%d): connect(%s, %s) error", + myname, __LINE__, entry->domain_key, + entry->domain_addr); + acl_aio_refer(entry->client); + acl_aio_writen(entry->client, HTTP_CONNECT_ERROR, + (int) strlen(HTTP_CONNECT_ERROR)); + acl_aio_unrefer(entry->client); + http_proxy_complete((HTTP_CLIENT*) entry, -1); + } +} + +static inline void nslookup_complete_fn(CLIENT_ENTRY *entry, int status) +{ + if (status == NSLOOKUP_OK) { + /* 设置连接成功后的回调函数 */ + entry->connect_notify_fn = http_proxy_connect_complete; + entry->connect_timeout_fn = http_proxy_connect_timeout; + entry->connect_error_fn = http_proxy_connect_error; + forward_start(entry); + } else { + acl_aio_refer(entry->client); + acl_aio_writen(entry->client, HTTP_REPLY_DNS_ERR, + (int) strlen(HTTP_REPLY_DNS_ERR)); + acl_aio_unrefer(entry->client); + http_proxy_complete((HTTP_CLIENT*) entry, -1); + } +} + +static inline void handle_one(HTTP_CLIENT *http_client, HTTP_CLIENT_REQ *req) +{ + int ret; + http_client->req_curr = req; /* 设置当前可以处理的请求 */ + + /* 先检查用户自定义过滤器 */ + if ((ret = http_client_req_filter(http_client))) { + /* 如果返回非0值则表示请求过滤器接管了该请求 */ + return; + } + + /* 设置DNS查询回调函数 */ + http_client->entry.nslookup_notify_fn = nslookup_complete_fn; +#if 0 + http_client->entry.dns_errmsg = HTTP_REPLY_DNS_ERR; +#else + http_client->entry.dns_errmsg = NULL; +#endif + + /* 从浏览器的请求头中获取服务端的端口号 */ + dns_lookup(&http_client->entry, req->hdr_req->host, req->hdr_req->port); +} + +/** + * 成功读到HTTP请求头后的回调函数 + */ +static inline int request_header_ready(int status, void *arg) +{ + const char *myname = "request_header_ready"; + HTTP_CLIENT_REQ *req = (HTTP_CLIENT_REQ *) arg; + HTTP_CLIENT *http_client = req->http_client; + const char *via; + static char *via_static = NULL; + static int via_max = 256; + + /* 取消客户端流的锁定状态 */ + http_client->flag &= ~HTTP_FLAG_CLIENT_LOCKED; + + if (status != HTTP_CHAT_OK) { + http_proxy_complete(http_client, -1); + return (0); + } + + if (http_hdr_req_parse3(req->hdr_req, 0 , 0) < 0) { + acl_msg_error("%s: parse hdr_req error", myname); + http_proxy_complete(http_client, -1); + return (0); + } + + if (via_static == NULL) { + via_static = (char*) acl_mycalloc(1, via_max); + snprintf(via_static, via_max, "jaws-%d", getpid()); + } + + /* 检查是否产生回路现象 */ + + via = http_hdr_entry_value(&req->hdr_req->hdr, "x-via-jaws"); + if (via == NULL) { + http_hdr_put_str(&req->hdr_req->hdr, "x-via-jaws", via_static); + } else if (strcasecmp(via, via_static) == 0) { + acl_msg_warn("%s(%d): loop tested, via(%s), url(http://%s%s)", + myname, __LINE__, via, req->hdr_req->host, + acl_vstring_str(req->hdr_req->url_part)); + + /* 锁定客户端流 */ + http_client->flag |= HTTP_FLAG_CLIENT_LOCKED; + + acl_aio_writen(http_client->entry.client, + HTTP_REQUEST_LOOP, + (int) strlen(HTTP_REQUEST_LOOP)); + + /* 取消客户端流的锁定状态 */ + http_client->flag &= ~HTTP_FLAG_CLIENT_LOCKED; + http_proxy_complete(http_client, -1); + return (0); + } + + /* 该请求已经完成,取消其等待状态 */ + req->flag &= ~CLIENT_READ_WAIT; + + if (http_client->req_curr != NULL) { + /* 如果前一个请求还未处理完毕,则返回 */ + return (0); + } + + /* 当前没有正在处理的请求过程,所以开始处理该请求 */ + + /* 从队列中弹出该请求,以免被重复使用 */ + if (acl_fifo_pop(&http_client->req_list) != req) + acl_msg_fatal("%s(%d): request invalid", myname, __LINE__); + + handle_one(http_client, req); + return (0); +} + +static inline int http_proxy_next(HTTP_CLIENT *http_client) +{ + HTTP_CLIENT_REQ *req = acl_fifo_head(&http_client->req_list); + + if (req) { + if (!(req->flag & CLIENT_READ_WAIT)) + handle_one(http_client, req); + } else { + http_proxy_req_get(http_client); + } + + return (0); +} + +/* 发送响应体至客户端失败时的回调函数 */ + +static inline int on_close_client(ACL_ASTREAM *client acl_unused, void *ctx) +{ + HTTP_CLIENT *http_client = (HTTP_CLIENT*) ctx; + +#if 0 + acl_msg_info("%s(%d): close client(%lx, fd=%d) now, server %s", + __FUNCTION__, __LINE__, (long) client, + ACL_VSTREAM_SOCK(client->stream), + http_client->entry.server ? "not null" : "null"); +#endif + /* 取消客户端流的锁定状态 */ + http_client->flag &= ~HTTP_FLAG_CLIENT_LOCKED; + /* 设置客户流的关闭状态 */ + http_client->flag |= HTTP_FLAG_CLIENT_CLOSED | HTTP_FLAG_FINISH; + http_proxy_complete(http_client, -1); + /* 必须返回 -1, 因为不希望继续调用其它的关闭回调函数 */ + return (-1); +} + +static inline void http_proxy_req_get(HTTP_CLIENT *http_client) +{ + HTTP_CLIENT_REQ *req = http_client_req_new(http_client); + + req->flag |= CLIENT_READ_WAIT; + req->hdr_req = http_hdr_req_new(); + acl_fifo_push(&http_client->req_list, req); + + /* 设置从客户流读数据失败或出现其它错误时的回调函数 */ + acl_aio_add_close_hook(http_client->entry.client, + on_close_client, http_client); + + /* 锁定客户端流 */ + http_client->flag |= HTTP_FLAG_CLIENT_LOCKED; + + http_client->total_size = 0; + http_client->flag &= ~HTTP_FLAG_CLIENT_KEEP_ALIVE; + http_client->flag &= ~HTTP_FLAG_SERVER_KEEP_ALIVE; + + /* 开始读取HTTP请求头 */ + http_hdr_req_get_async(req->hdr_req, + http_client->entry.client, + request_header_ready, + req, + http_client->entry.service->rw_timeout); +} + +int http_proxy_start(HTTP_CLIENT *http_client) +{ + http_proxy_req_get(http_client); + return (0); +} diff --git a/app/jaws/module/mod_http/debug/BuildLog.htm b/app/jaws/module/mod_http/debug/BuildLog.htm new file mode 100644 index 000000000..a8c3395dd --- /dev/null +++ b/app/jaws/module/mod_http/debug/BuildLog.htm @@ -0,0 +1,68 @@ + + + + + +
+
+生成日志 +
  
+

------- 已启动生成: 项目: mod_http,配置: Debug|Win32 ------- +

+
+命令行 +
  
正在创建临时文件“d:\工作目录\项目管理\jaws\jaws\module\mod_http\Debug\RSP0000A5.rsp”,其内容为
+[
+/Od /I "..\..\global" /I "..\..\include\protocol" /I "..\..\include\acl" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_USRDLL" /D "ACL_DLL" /D "HTTP_DLL" /D "MOD_HTTP_EXPORTS" /D "_WINDLL" /D "_MBCS" /Gm /EHsc /RTC1 /MDd /Fo"Debug/" /Fd"Debug/vc70.pdb" /W3 /c /Wp64 /ZI /TC
+.\tcp_proxy.c
+.\http_vhost.c
+.\http_service.c
+.\http_server.c
+.\http_proxy.c
+.\http_plugin.c
+.\http_module.c
+.\http_filter.c
+.\http_conf.c
+.\http_client.c
+.\html_template.c
+]
+正在创建命令行“cl.exe @d:\工作目录\项目管理\jaws\jaws\module\mod_http\Debug\RSP0000A5.rsp /nologo”
+正在创建临时文件“d:\工作目录\项目管理\jaws\jaws\module\mod_http\Debug\RSP0000A6.rsp”,其内容为
+[
+/OUT:"Debug/mod_http.dll" /INCREMENTAL /NOLOGO /LIBPATH:"..\..\lib\win32" /DLL /NODEFAULTLIB:"libcmtd" /DEBUG /PDB:"Debug/mod_http.pdb" /SUBSYSTEM:WINDOWS /IMPLIB:"Debug/mod_http.lib" /MACHINE:X86 lib_global.lib lib_protocol_d.lib lib_acl_d.lib ws2_32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib
+.\debug\html_template.obj
+.\debug\http_client.obj
+.\debug\http_conf.obj
+.\debug\http_filter.obj
+.\debug\http_module.obj
+.\debug\http_plugin.obj
+.\debug\http_proxy.obj
+.\debug\http_server.obj
+.\debug\http_service.obj
+.\debug\http_vhost.obj
+.\debug\tcp_proxy.obj
+]
+正在创建命令行“link.exe @d:\工作目录\项目管理\jaws\jaws\module\mod_http\Debug\RSP0000A6.rsp”
+
+输出窗口 +
  
正在编译...
+tcp_proxy.c
+http_vhost.c
+http_service.c
+http_server.c
+http_proxy.c
+http_plugin.c
+http_module.c
+http_filter.c
+http_conf.c
+http_client.c
+html_template.c
+正在生成代码...
+正在链接...
+LINK : fatal error LNK1104: 无法打开文件“lib_protocol_d.lib”
+
+结果 +
  
+生成日志保存在“file://d:\工作目录\项目管理\jaws\jaws\module\mod_http\Debug\BuildLog.htm”中
+mod_http - 1 错误,0 警告
+
\ No newline at end of file diff --git a/app/jaws/module/mod_http/html_template.c b/app/jaws/module/mod_http/html_template.c new file mode 100644 index 000000000..a8ac208fb --- /dev/null +++ b/app/jaws/module/mod_http/html_template.c @@ -0,0 +1,67 @@ +#include "http_service.h" + +char HTTP_REPLY_DNS_ERR[] = \ +"HTTP/1.1 503 DNS lookup error\r\n" \ +"Connection: close\r\n" \ +"\r\n" \ +"DNS LOOKUP error\r\n\r\n"; + +char HTTP_REPLY_TIMEOUT[] = \ +"HTTP/1.1 504 webserver respond timeout\r\n" \ +"Connection: close\r\n" \ +"\r\n" \ +"504 webserver respond timeout\r\n"; + +char HTTP_REPLY_ERROR[] = \ +"HTTP/1.1 500 webserver respond error\r\n" \ +"Connection: close\r\n" \ +"\r\n" \ +" 500 webserver respond error\r\n"; + +char HTTP_SEND_ERROR[] = \ +"HTTP/1.1 500 send to webserver error\r\n" \ +"Connection: close\r\n" \ +"\r\n" \ +" 500 send to webserver error\r\n"; + +char HTTP_CONNECT_ERROR[] = \ +"HTTP/1.1 500 connect webserver error\r\n" \ +"Connection: close\r\n" \ +"\r\n" \ +" 500 connect webserver error\r\n"; + +char HTTP_CONNECT_TIMEOUT[] = \ +"HTTP/1.1 504 connect webserver error\r\n" \ +"Connection: close\r\n" \ +"\r\n" \ +" 504 connect webserver timeout\r\n"; + +char HTTP_REQUEST_INVALID[] = \ +"HTTP/1.1 400 client request invalid\r\n" \ +"Connection: close\r\n" \ +"\r\n" \ +" 400 request invalid\r\n"; + +char HTTP_REQUEST_LOOP[] = \ +"HTTP/1.1 403 request loop test forbidden\r\n" \ +"Connection: close\r\n" \ +"\r\n" \ +" 403 forbidden, request loop tested\r\n"; + +char HTTP_REQUEST_DENY[] = \ +"HTTP/1.1 403 request forbidden\r\n" \ +"Connection: close\r\n" \ +"\r\n" \ +" 403 forbidden, request denied\r\n"; + +char HTTP_REQUEST_NOFOUND[] = \ +"HTTP/1.1 404 request url not found\r\n" \ +"Connection: close\r\n" \ +"\r\n" \ +" 404 forbidden, request url not found\r\n"; + +char HTTP_INTERNAL_ERROR[] = \ +"HTTP/1.1 500 internal error\r\n" \ +"Connection: close\r\n" \ +"\r\n" \ +" 500 internal error\r\n"; diff --git a/app/jaws/module/mod_http/http_client.c b/app/jaws/module/mod_http/http_client.c new file mode 100644 index 000000000..33fdf02c8 --- /dev/null +++ b/app/jaws/module/mod_http/http_client.c @@ -0,0 +1,204 @@ +#include "lib_acl.h" +#include "lib_protocol.h" +#include "service.h" +#include "http_service.h" + +void http_client_free(CLIENT_ENTRY *entry) +{ + HTTP_CLIENT *client = (HTTP_CLIENT*) entry; + + while (1) { + HTTP_CLIENT_REQ *req =(HTTP_CLIENT_REQ*) + acl_fifo_pop(&client->req_list); + if (req == NULL) + break; + http_client_req_free(req); + } + + if (client->req_curr) { + http_client_req_free(client->req_curr); + client->req_curr = NULL; + } + + if (client->res) { + http_res_free(client->res); + client->res = NULL; + client->hdr_res = NULL; + } else if (client->hdr_res) { + http_hdr_res_free(client->hdr_res); + client->hdr_res = NULL; + } + if (client->fp) { + acl_vstream_close(client->fp); + client->fp = NULL; + } + if (client->buf) { + acl_vstring_free(client->buf); + client->buf = NULL; + } + + client_entry_free(entry); +} + +HTTP_CLIENT *http_client_new(HTTP_SERVICE *service, ACL_ASTREAM *stream) +{ + HTTP_CLIENT *client; + + client = (HTTP_CLIENT*) client_entry_new((SERVICE*) service, + sizeof(HTTP_CLIENT), stream); + client->req_curr = NULL; + acl_fifo_init(&client->req_list); + client->entry.free_fn = http_client_free; + client->flag = 0; + + return (client); +} + +void http_client_reset(HTTP_CLIENT *client) +{ + while (1) { + HTTP_CLIENT_REQ *req =(HTTP_CLIENT_REQ*) + acl_fifo_pop(&client->req_list); + if (req == NULL) + break; + http_client_req_free(req); + } + client->req_curr = NULL; + + if (client->hdr_res) { + http_hdr_res_free(client->hdr_res); + client->hdr_res = NULL; + } + if (client->res) { + client->res->hdr_res = NULL; + http_res_free(client->res); + client->res = NULL; + } + if (client->fp) { + acl_vstream_close(client->fp); + client->fp = NULL; + } + if (client->buf) + ACL_VSTRING_RESET(client->buf); + if (client->cache) + client->cache = NULL; + client->flag = 0; +} + +HTTP_CLIENT_REQ *http_client_req_new(HTTP_CLIENT *http_client) +{ + HTTP_CLIENT_REQ *req = (HTTP_CLIENT_REQ*) + acl_mycalloc(1, sizeof(HTTP_CLIENT_REQ)); + req->http_client = http_client; + return (req); +} + +void http_client_req_free(HTTP_CLIENT_REQ *req) +{ + if (req->req) + http_req_free(req->req); + else if (req->hdr_req) + http_hdr_req_free(req->hdr_req); + acl_myfree(req); +} + +int http_client_req_filter(HTTP_CLIENT *http_client) +{ + HTTP_SERVICE *service = (HTTP_SERVICE*) http_client->entry.service; + HTTP_HDR_REQ *hdr_req; + HTTP_PLUGIN *plugin = NULL; + void *plugin_req_ctx; + ACL_ASTREAM *astream; + ACL_VSTREAM *stream; + ACL_ITER iter; + int ret = 0; + + /* xxx: plugin_req_ctx 该参数在每次请求都有可能不一样, 外挂模块应该自行管理 */ + http_client->plugin_req_ctx = NULL; + + /* 检查用户自定义过滤器 */ + + acl_foreach(iter, &service->request_plugins) { + HTTP_PLUGIN *tmp = (HTTP_PLUGIN*) iter.data; + astream = http_client->entry.client; + stream = acl_aio_vstream(astream); + + if ((ret = tmp->filter.request(stream, + http_client->req_curr->hdr_req, + &http_client->plugin_req_ctx)) != 0) + { + plugin = tmp; + break; + } + } + + /* 返回 0 表示用户自定义过滤器不准备接管该请求 */ + if (plugin == NULL || ret == 0) + return (0); + + astream = http_client->entry.client; + stream = acl_aio_vstream(astream); + + if (ret < 0) { + /* 返回负值表示禁止该请求,可以为:-4xx, -5xx */ + + acl_aio_refer(astream); + + switch (-ret) { + case 403: + acl_aio_writen(astream, HTTP_REQUEST_DENY, + (int) strlen(HTTP_REQUEST_DENY)); + break; + case 404: + acl_aio_writen(astream, HTTP_REQUEST_NOFOUND, + (int) strlen(HTTP_REQUEST_NOFOUND)); + break; + case 500: + default: + acl_aio_writen(astream, HTTP_INTERNAL_ERROR, + (int) strlen(HTTP_INTERNAL_ERROR)); + break; + } + + acl_aio_unrefer(astream); + + http_client_req_free(http_client->req_curr); + http_client->req_curr = NULL; + client_entry_detach(&http_client->entry, stream); + acl_aio_disable_readwrite(astream); + acl_aio_clean_hooks(astream); + acl_aio_iocp_close(astream); + return (-1); + } + + hdr_req = http_client->req_curr->hdr_req; + http_client->req_curr->hdr_req = NULL; + + plugin_req_ctx = http_client->plugin_req_ctx; + + /* 释放掉异步流相关的对象, 将客户端数据流与该代理对象分离, + * 因为此时为请求时的过滤器,所以只有请求端没有响应端,则 + * 调用 client_entry_detach 后会因为引用计数为0而自动将 + * http_client 释放 + */ + client_entry_detach(&http_client->entry, stream); + + /* 关闭读监听事件 */ + acl_aio_disable_read(astream); + /* 清除回调函数 */ + acl_aio_clean_hooks(astream); + + /* 将客户端异步流的数据流置空 */ + acl_aio_ctl(astream, ACL_AIO_CTL_STREAM, NULL, ACL_AIO_CTL_END); + + /* xxx: 异步关闭 astream 异步流 */ + acl_aio_iocp_close(astream); + + /* 必须流由非阻塞模式转换为阻塞模式 */ + acl_non_blocking(ACL_VSTREAM_SOCK(stream), ACL_BLOCKING); + + /* 转给用户自定义处理过程 */ + plugin->forward.request(stream, hdr_req, plugin_req_ctx); + return (1); +} + diff --git a/app/jaws/module/mod_http/http_conf.c b/app/jaws/module/mod_http/http_conf.c new file mode 100644 index 000000000..e8f4a413d --- /dev/null +++ b/app/jaws/module/mod_http/http_conf.c @@ -0,0 +1,109 @@ +#include "lib_acl.h" +#include +#include +#include +#include + +#include "http_vhost.h" +#include "http_service.h" + +#define SET_STR(_xcp_, _name_, _value_, _default_) do { \ + ACL_CFG_SET_ITEM_STR(_xcp_, _name_, _value_); \ + if (_value_ == NULL) \ + _value_ = acl_mystrdup(_default_); \ +} while (0) + +#define SET_INT ACL_CFG_SET_ITEM_INT + +static void add_vhost(const char *file_path, int def) +{ + const char *myname = "add_vhost"; + ACL_XINETD_CFG_PARSER *xcp; + char *cf_host = NULL, *cf_root = NULL, *cf_default = NULL; + int i, n; + const ACL_ARRAY *vpath_maps; + char *vpath_map; + ACL_ARGV *map_argv; + HTTP_VHOST *vhost; + char ebuf[256]; + + xcp = acl_xinetd_cfg_load(file_path); + if (xcp == NULL) { + acl_msg_error("%s(%d): load file(%s) error(%s)", + myname, __LINE__, file_path, + acl_last_strerror(ebuf, sizeof(ebuf))); + return; + } + + SET_STR(xcp, "host", cf_host, "localhost"); + SET_STR(xcp, "root_path", cf_root, "/opt/jaws/var/www/htdocs/"); + SET_STR(xcp, "default_page", cf_default, "index.html"); + + if (def) + vhost = http_vhost_add_def(cf_host, cf_root, cf_default); + else + vhost = http_vhost_add(cf_host, cf_root, cf_default); + + vpath_maps = acl_xinetd_cfg_get_ex(xcp, "vpath_map"); + if (vpath_maps) { + n = acl_array_size(vpath_maps); + for (i = 0; i < n; i++) { + vpath_map = (char *) acl_array_index(vpath_maps, i); + if (vpath_map == NULL) + break; + map_argv = acl_argv_split(vpath_map, "\t "); + if (map_argv->argc < 3) { + acl_msg_error("%s(%d): vpath_map(%s) invalid", + myname, __LINE__, vpath_map); + acl_argv_free(map_argv); + continue; + } + + http_vpath_add(vhost, map_argv->argv[0], + map_argv->argv[1], atoi(map_argv->argv[2])); + acl_argv_free(map_argv); + } + } + + acl_myfree(cf_host); + acl_myfree(cf_root); + acl_myfree(cf_default); + + acl_xinetd_cfg_free(xcp); +} + +void http_conf_load(const char *path, const char *default_cf) +{ + const char *myname = "http_conf_load"; + ACL_SCAN_DIR *scan_dir; + const char *file_name; + ACL_VSTRING *file_path; + char ebuf[256]; + + http_vhost_init(); + + add_vhost(default_cf, 1); + + file_path = acl_vstring_alloc(256); + if (file_path == NULL) + acl_msg_fatal("%s(%d): acl_vstring_alloc error(%s)", + myname, __LINE__, + acl_last_strerror(ebuf, sizeof(ebuf))); + + scan_dir = acl_scan_dir_open(path, 1); + if (scan_dir == NULL) + acl_msg_fatal("%s(%d): acl_scan_dir_open error(%s)", + myname, __LINE__, + acl_last_strerror(ebuf, sizeof(ebuf))); + + while (1) { + file_name = acl_scan_dir_next_file(scan_dir); + if (file_name == NULL) + break; + acl_vstring_sprintf(file_path, "%s/%s", path, file_name); + add_vhost(acl_vstring_str(file_path), 0); + } + + acl_scan_dir_close(scan_dir); + acl_vstring_free(file_path); +} diff --git a/app/jaws/module/mod_http/http_filter.c b/app/jaws/module/mod_http/http_filter.c new file mode 100644 index 000000000..9ebb4aa0f --- /dev/null +++ b/app/jaws/module/mod_http/http_filter.c @@ -0,0 +1,24 @@ +#include "lib_acl.h" +#include "http_service.h" + +static int var_http_filter; + +int http_filter_type(void) +{ + return (var_http_filter); +} + +void http_filter_set(const char *filter_info) +{ + const char *myname = "http_filter_set"; + + if (strcasecmp(filter_info, "HTTP_FILTER_PROXY") == 0) + var_http_filter = HTTP_FILTER_PROXY; + else if (strcasecmp(filter_info, "HTTP_FILTER_HTTPD") == 0) + var_http_filter = HTTP_FILTER_HTTPD; + else { + acl_msg_warn("%s(%d): unknown http filter(%s)", + myname, __LINE__, filter_info); + var_http_filter = HTTP_FILTER_HTTPD; + } +} diff --git a/app/jaws/module/mod_http/http_module.c b/app/jaws/module/mod_http/http_module.c new file mode 100644 index 000000000..3f5ae949c --- /dev/null +++ b/app/jaws/module/mod_http/http_module.c @@ -0,0 +1,145 @@ +#include "lib_acl.h" +#include "service.h" +#include "http_service.h" +#include "http_module.h" + +static char *var_cfg_http_plugin_dlnames; +static char *var_cfg_http_plugin_cfgdir; +static char *var_cfg_http_filter_info; +static char *var_cfg_http_tmpl_path; +static char *var_cfg_http_vhost_path; +static char *var_cfg_http_vhost_default; + +static ACL_CFG_STR_TABLE __conf_str_tab[] = { + /* 配置项名称, 配置项缺省值, 存储配置项值的地址 */ + + { "http_filter_proxy", "HTTP_FILTER_PROXY", &var_cfg_http_filter_info }, + { "http_tmpl_path", "/opt/jaws/www/tmpl", &var_cfg_http_tmpl_path }, + { "http_vhost_path", "/opt/jaws/conf/www", &var_cfg_http_vhost_path }, + { "http_vhost_default", "/opt/jaws/conf/default/default.cf", &var_cfg_http_vhost_default }, + + { "http_plugin_dlnames", "", &var_cfg_http_plugin_dlnames }, + { "http_plugin_cfgdir", "/tmp", &var_cfg_http_plugin_cfgdir}, + + { 0, 0, 0 } +}; + +static int var_cfg_http_server_conn_limit; +static int var_cfg_http_buf_size; + +static ACL_CONFIG_INT_TABLE __conf_int_tab[] = { + { "http_server_conn_limit", 1000, &var_cfg_http_server_conn_limit, 0, 0 }, + { "http_buf_size", 8192, &var_cfg_http_buf_size, 0, 0 }, + { 0, 0, 0, 0, 0 }, +}; + +static int var_cfg_http_debug_mem; +static int var_cfg_http_use_cache; +int var_cfg_http_client_keepalive; +int var_cfg_http_server_keepalive; +int var_cfg_http_method_connect_enable; +int var_cfg_http_proxy_connection_off; + +static ACL_CONFIG_BOOL_TABLE __conf_bool_tab[] = { + /* TODO: you can add configure variables of int type here */ + + { "debug_mem", 0, &var_cfg_http_debug_mem }, + { "http_client_keepalive", 1, &var_cfg_http_client_keepalive }, + { "http_server_keepalive", 1, &var_cfg_http_server_keepalive }, + { "http_use_cache", 1, &var_cfg_http_use_cache }, + { "http_method_connect_enable", 0, &var_cfg_http_method_connect_enable }, + { "http_proxy_connection_off", 0, &var_cfg_http_proxy_connection_off }, + { 0, 0, 0 }, +}; + +static ACL_DLL_ENV __dll_env; +ACL_DLL_ENV *var_http_dll_env = NULL; + +void module_service_init(ACL_DLL_ENV *dll_env, const char *cfg_dir) +{ + const char *myname = "module_service_init"; + ACL_XINETD_CFG_PARSER *cfg; + char *filepath; + + if (dll_env) + memcpy(&__dll_env, dll_env, sizeof(ACL_DLL_ENV)); + else + memset(&__dll_env, 0, sizeof(ACL_DLL_ENV)); + + /* 如果 mem_slice 非空则设置内存分配采用切片分配方式 */ + if (__dll_env.mem_slice) { + acl_mem_slice_set(__dll_env.mem_slice); + acl_msg_info("%s(%d): set mem slice now", myname, __LINE__); + } + var_http_dll_env = &__dll_env; + if (var_http_dll_env->logfp) { + acl_msg_open2(var_http_dll_env->logfp, "jaws-http"); + acl_msg_info("%s(%d): logger opened, %s", __FUNCTION__, + __LINE__, ACL_VSTREAM_PATH(var_http_dll_env->logfp)); + /* + var_http_dll_env->logfp = acl_log_fp(); + */ + } + + + filepath = acl_concatenate((cfg_dir && *cfg_dir) + ? cfg_dir : "/tmp", "/http.cf", NULL); + cfg = acl_xinetd_cfg_load(filepath); + if (cfg == NULL) + acl_msg_warn("load cfg(%s) error(%s)", + filepath, acl_last_serror()); + + acl_xinetd_params_str_table(cfg, __conf_str_tab); + acl_xinetd_params_bool_table(cfg, __conf_bool_tab); + acl_xinetd_params_int_table(cfg, __conf_int_tab); + acl_xinetd_cfg_free(cfg); + acl_myfree(filepath); + + /* 是否调试内存的分析状态 */ + if (var_cfg_http_debug_mem == 1) { + acl_memory_debug_start(); + acl_memory_debug_stack(1); + } else if (var_cfg_http_debug_mem == 2) { + var_http_dll_env->mmd = acl_debug_malloc_init( + var_http_dll_env->mmd, "log.txt"); + } else if (var_cfg_http_debug_mem == 3) { + acl_memory_debug_start(); + acl_memory_debug_stack(1); + var_http_dll_env->mmd = acl_debug_malloc_init( + var_http_dll_env->mmd, "log.txt"); + } + + /* 设置HTTP服务运行模式: 服务器模式还是代理模式 */ + http_filter_set(var_cfg_http_filter_info); + /* 服务器模式下加载配置 */ + http_conf_load(var_cfg_http_vhost_path, var_cfg_http_vhost_default); + /* 加载HMTL模板 */ + http_tmpl_load(var_cfg_http_tmpl_path); + + /* 初始化连接池 */ + if (var_cfg_http_server_conn_limit < 10) + var_cfg_http_server_conn_limit = 10; + + /* 设置HTTP缓冲区大小 */ + if (var_cfg_http_buf_size > 0) { + http_buf_size_set(var_cfg_http_buf_size); + } + + /* 加载所有动态插件库并初始化动态库 */ + http_plugin_load_all(dll_env, var_cfg_http_plugin_dlnames, var_cfg_http_plugin_cfgdir); +} + +SERVICE *module_service_create() +{ + HTTP_SERVICE *service; + + /* 创建 HTTP 服务对象 */ + service = http_service_new(); + return ((SERVICE*) service); +} + + +void module_service_main(SERVICE *service, ACL_ASTREAM *stream) +{ + http_service_main((HTTP_SERVICE*) service, stream); +} diff --git a/app/jaws/module/mod_http/http_module.h b/app/jaws/module/mod_http/http_module.h new file mode 100644 index 000000000..7833c5c29 --- /dev/null +++ b/app/jaws/module/mod_http/http_module.h @@ -0,0 +1,55 @@ +#ifndef __HTTP_MODULE_INCLUDE_H__ +#define __HTTP_MODULE_INCLUDE_H__ + +#include "lib_acl.h" +#include "service_struct.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _USRDLL +# ifdef MOD_HTTP_EXPORTS +# define MOD_HTTP_API __declspec(dllexport) +# else +# define MOD_HTTP_API __declspec(dllimport) +# endif +#else +# define MOD_HTTP_API +#endif + +extern ACL_DLL_ENV *var_http_dll_env; +extern char *var_cfg_http_domain_allow; +extern int var_cfg_http_client_keepalive; +extern int var_cfg_http_server_keepalive; +extern int var_cfg_http_domain_allow_all; +extern int var_cfg_http_method_connect_enable; +extern int var_cfg_http_proxy_connection_off; + +/* 动态加载的函数接口 */ + +/** + * 被动态加载的模块的初始化函数,仅被调用一次 + * @param dll_env {ACL_DLL_ENV*} 由加载程序传递过来的环境变量 + * @param cfg_dir {const char*} 该动态模块的配置文件所在路径 + */ +MOD_HTTP_API void module_service_init(ACL_DLL_ENV *dll_env, const char *cfg_dir); + +/** + * 由动态模块创建一个服务实例,可以被加载程序调用多次以产生多个服务实例 + * @return {SERVICE*} 由动态模块创建的服务对象实例 + */ +MOD_HTTP_API SERVICE *module_service_create(void); + +/** + * 当加载程序接收到一个客户端连接后调用此函数 + * @param service {SERVICE*} 由 module_service_create 创建的服务对象 + * @param stream {ACL_ASTREAM*} 由加载程序接收的客户端异步流对象 + */ +MOD_HTTP_API void module_service_main(SERVICE *service, ACL_ASTREAM *stream); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/app/jaws/module/mod_http/http_plugin.c b/app/jaws/module/mod_http/http_plugin.c new file mode 100644 index 000000000..ac4bbbc23 --- /dev/null +++ b/app/jaws/module/mod_http/http_plugin.c @@ -0,0 +1,173 @@ +#include "lib_acl.h" +#include "http_service.h" + +static ACL_FIFO *__handles = NULL; + +static ACL_FIFO __request_plugins; +static ACL_FIFO __request_dat_plugins; +static ACL_FIFO __respond_plugins; +static ACL_FIFO __respond_dat_plugins; + +void http_plugin_load(ACL_DLL_ENV *dll_env, const char *dlname, const char *plugin_cfgdir) +{ + const char *myname = "http_plugin_load"; + ACL_DLL_HANDLE handle; + HTTP_PLUGIN *http_plugin; + HTTP_PLUGIN plugin; + + if (dlname == NULL || *dlname == 0) + return; + + acl_msg_info("%s(%d): begin load %s now ...", __FUNCTION__, __LINE__, dlname); + handle = acl_dlopen(dlname); + if (handle == NULL) { + acl_msg_error("%s(%d): load %s error(%s)", + myname, __LINE__, dlname, acl_last_serror()); + return; + } + + acl_msg_info("%s(%d): load %s ok.", __FUNCTION__, __LINE__, dlname); + + if (__handles == NULL) { + __handles = acl_fifo_new(); + } + + acl_fifo_push(__handles, handle); + + /* 初始化 */ + plugin.init = (plugin_init_fn) (intptr_t) + acl_dlsym(handle, "http_plugin_init"); + if (plugin.init) { + plugin.init(dll_env, plugin_cfgdir); + } + + /* 添加请求头过滤器 */ + + plugin.filter.request = (plugin_filter_request_fn) (intptr_t) + acl_dlsym(handle, "http_request_filter"); + plugin.forward.request = (plugin_forward_request_fn) (intptr_t) + acl_dlsym(handle, "http_request_forward"); + if (plugin.filter.request) { + http_plugin = (HTTP_PLUGIN*) acl_mycalloc(1, sizeof(HTTP_PLUGIN)); + http_plugin->filter.request = plugin.filter.request; + http_plugin->forward.request = plugin.forward.request; + acl_fifo_push(&__request_plugins, http_plugin); + } + + /* 添加请求体过滤器 */ + + plugin.data_free = (plugin_dat_free_fn) (intptr_t) + acl_dlsym(handle, "http_request_dat_free"); + plugin.data_filter = (plugin_dat_filter_fn) (intptr_t) + acl_dlsym(handle, "http_request_dat_filter"); + if (plugin.data_filter) { + http_plugin = (HTTP_PLUGIN*) acl_mycalloc(1, sizeof(HTTP_PLUGIN)); + http_plugin->data_filter = plugin.data_filter; + http_plugin->data_free = plugin.data_free; + acl_fifo_push(&__request_dat_plugins, http_plugin); + } + + /* 添加响应头过滤器 */ + + plugin.filter.respond = (plugin_filter_respond_fn) (intptr_t) + acl_dlsym(handle, "http_respond_filter"); + plugin.forward.respond = (plugin_forward_respond_fn) (intptr_t) + acl_dlsym(handle, "http_respond_forward"); + if (plugin.filter.respond) { + http_plugin = (HTTP_PLUGIN*) acl_mycalloc(1, sizeof(HTTP_PLUGIN)); + http_plugin->filter.respond = plugin.filter.respond; + http_plugin->forward.respond = plugin.forward.respond; + acl_fifo_push(&__respond_plugins, http_plugin); + } + + /* 添加响应体过滤器 */ + + plugin.data_filter = (plugin_dat_filter_fn) (intptr_t) + acl_dlsym(handle, "http_respond_dat_filter"); + plugin.data_free = (plugin_dat_free_fn) (intptr_t) + acl_dlsym(handle, "http_respond_dat_free"); + if (plugin.data_filter) { + http_plugin = (HTTP_PLUGIN*) acl_mycalloc(1, sizeof(HTTP_PLUGIN)); + http_plugin->data_filter = plugin.data_filter; + http_plugin->data_free = plugin.data_free; + acl_fifo_push(&__respond_dat_plugins, http_plugin); + } +} + +void http_plugin_load_all(ACL_DLL_ENV *dll_env, const char *dlnames, const char *plugin_cfgdir) +{ + ACL_ARGV *argv; + ACL_ITER iter; + + acl_fifo_init(&__request_plugins); + acl_fifo_init(&__request_dat_plugins); + acl_fifo_init(&__respond_plugins); + acl_fifo_init(&__respond_dat_plugins); + if (dlnames == NULL || *dlnames == 0) + return; + + argv = acl_argv_split(dlnames, " \t,;"); + acl_foreach(iter, argv) { + const char *dlname = (const char*) iter.data; + + http_plugin_load(dll_env, dlname, plugin_cfgdir); + } + acl_argv_free(argv); +} + +void http_plugin_unload_all() +{ + ACL_ITER iter; + + if (__handles == NULL) + return; + + acl_foreach(iter, __handles) { + void *handle = (void*) iter.data; + acl_dlclose(handle); + } +} + +void http_plugin_set_callback(HTTP_SERVICE *service) +{ + ACL_ITER iter; + HTTP_PLUGIN *http_plugin, *plugin; + + /* 初始化过滤器队列集合 */ + acl_fifo_init(&service->request_plugins); + acl_fifo_init(&service->respond_plugins); + acl_fifo_init(&service->request_dat_plugins); + acl_fifo_init(&service->respond_dat_plugins); + + acl_foreach(iter, &__request_plugins) { + plugin = (HTTP_PLUGIN*) iter.data; + http_plugin = (HTTP_PLUGIN*) acl_mycalloc(1, sizeof(HTTP_PLUGIN)); + http_plugin->filter.request = plugin->filter.request; + http_plugin->forward.request = plugin->forward.request; + acl_fifo_push(&service->request_plugins, http_plugin); + } + + acl_foreach(iter, &__request_dat_plugins) { + plugin = (HTTP_PLUGIN*) iter.data; + http_plugin = (HTTP_PLUGIN*) acl_mycalloc(1, sizeof(HTTP_PLUGIN)); + http_plugin->data_filter = plugin->data_filter; + http_plugin->data_free = plugin->data_free; + acl_fifo_push(&service->request_dat_plugins, http_plugin); + } + + acl_foreach(iter, &__respond_plugins) { + plugin = (HTTP_PLUGIN*) iter.data; + http_plugin = (HTTP_PLUGIN*) acl_mycalloc(1, sizeof(HTTP_PLUGIN)); + http_plugin->filter.respond = plugin->filter.respond; + http_plugin->forward.respond = plugin->forward.respond; + acl_fifo_push(&service->respond_plugins, http_plugin); + } + + acl_foreach(iter, &__respond_dat_plugins) { + plugin = (HTTP_PLUGIN*) iter.data; + http_plugin = (HTTP_PLUGIN*) acl_mycalloc(1, sizeof(HTTP_PLUGIN)); + http_plugin->data_filter = plugin->data_filter; + http_plugin->data_free = plugin->data_free; + acl_fifo_push(&service->respond_dat_plugins, http_plugin); + } +} diff --git a/app/jaws/module/mod_http/http_proxy.c b/app/jaws/module/mod_http/http_proxy.c new file mode 100644 index 000000000..1cf74bcf3 --- /dev/null +++ b/app/jaws/module/mod_http/http_proxy.c @@ -0,0 +1,1291 @@ +#include "lib_acl.h" +#include "lib_protocol.h" +#include "assert.h" +#include "dns_lookup.h" +#include "conn_cache.h" +#include "service.h" +#include "http_module.h" +#include "http_service.h" + +#ifdef ACL_MS_WINDOWS +#include +#define getpid _getpid +#endif + +static int http_proxy_next(HTTP_CLIENT *http_client); +static void http_proxy_req_get(HTTP_CLIENT *http_client); + +/*---------------------------------------------------------------------------*/ + +/* 当前请求处理完毕, 是否继续下一个客户端请求? */ + +static void http_proxy_server_complete(HTTP_CLIENT *http_client, int keep_alive) +{ + HTTP_SERVICE *service = (HTTP_SERVICE*) http_client->entry.service; + ACL_ASTREAM *server; + ACL_VSTREAM *sstream; + + if (http_client->res) { + http_res_free(http_client->res); + http_client->res = NULL; + http_client->hdr_res = NULL; + } else if (http_client->hdr_res) { + http_hdr_res_free(http_client->hdr_res); + http_client->hdr_res = NULL; + } + + server = http_client->entry.server; + /* 是否应与服务端保持长连接? */ + if (server == NULL) { + return; + } + + /* 先禁止对该异步流继续监听 */ + acl_aio_disable_readwrite(server); + + /* 清除异步流的所有勾子回调函数,防止在流结束后回调被调用 */ + acl_aio_clean_hooks(server); + + sstream = acl_aio_vstream(server); + + if (keep_alive) { + int timeout = 60; + /* 与服务端流分离 */ + client_entry_detach(&http_client->entry, sstream); + ACL_VSTRING_RESET(&server->strbuf); + + /* 将与服务端的连接流置入连接池中 */ + conn_cache_push_stream(service->service.conn_cache, + server, timeout, NULL, NULL); + } else { + client_entry_detach(&http_client->entry, sstream); + /* 关闭异步流 */ + acl_aio_iocp_close(server); + } +} + +static void http_proxy_client_complete(HTTP_CLIENT *http_client, int keep_alive) +{ + ACL_ASTREAM *client; + + /* 重置重试次数 */ + http_client->entry.nretry_on_error = 0; + http_client->entry.ip_ntry = 0; + + /* 清除本次会话完成标志位 */ + http_client->flag &= ~HTTP_FLAG_FINISH; + + client = http_client->entry.client; + if (client == NULL) { + return; + } + + /* 清除异步流的所有勾子回调函数,防止在流结束后回调被调用 */ + acl_aio_clean_hooks(client); + + /* 是否应与客户端保持长连接? */ + if (keep_alive) { + if (http_client->req_curr) { + http_client_req_free(http_client->req_curr); + http_client->req_curr = NULL; + } + http_proxy_next(http_client); + } else { + ACL_VSTREAM *cstream = acl_aio_vstream(client); + + if (http_client->req_curr) { + http_client_req_free(http_client->req_curr); + http_client->req_curr = NULL; + } + acl_aio_disable_readwrite(client); + /* 与客户端流分离 */ + client_entry_detach(&http_client->entry, cstream); + /* 关闭老的异步流 */ + acl_aio_iocp_close(client); + } +} + +static void http_proxy_complete(HTTP_CLIENT *http_client, int error_happen) +{ + /* 需要提前知道服务端流和客户端流是否已经被分离,因为下面经过 + * http_proxy_server_complete 或 http_proxy_client_complte 后 + * http_client 所占内存可能已经被释放,这样提前知道服务端/客户 + * 端流的状态可以避免内存非法访问 + */ + int server_null = http_client->entry.server == NULL; + int client_null = http_client->entry.client == NULL; + + /* 判定服务端流是否应保持长连接 */ + + if (var_cfg_http_server_keepalive && !error_happen + && http_client->hdr_res + && http_client->hdr_res->hdr.keep_alive) + { + http_client->flag |= HTTP_FLAG_SERVER_KEEP_ALIVE; + } + + /* 判定客户端流是否应保持长连接 */ + + if (var_cfg_http_client_keepalive && !error_happen + && (http_client->flag & HTTP_FLAG_SERVER_KEEP_ALIVE) + && http_client->req_curr + && http_client->req_curr->hdr_req + && http_client->req_curr->hdr_req->hdr.keep_alive) + { + http_client->flag |= HTTP_FLAG_CLIENT_KEEP_ALIVE; + } else { + http_client->flag &= ~HTTP_FLAG_CLIENT_KEEP_ALIVE; + } + + /* 如果服务端流处于锁定状态则不立即关闭服务端流 */ + + if (!server_null && !(http_client->flag & HTTP_FLAG_SERVER_LOCKED)) { + http_proxy_server_complete(http_client, + (http_client->flag & HTTP_FLAG_SERVER_KEEP_ALIVE)); + } + + /* 如果客户端流处于锁定状态则不立即关闭客户端流 */ + + if (!client_null && !(http_client->flag & HTTP_FLAG_CLIENT_LOCKED)) { + http_proxy_client_complete(http_client, + (http_client->flag & HTTP_FLAG_CLIENT_KEEP_ALIVE)); + } +} + +/*---------------------------------------------------------------------------*/ + +/* 发送响应数据至客户端,为了减少IO次数,合并响应头同响应体数据一起发送 */ + +static void send_to_client(HTTP_CLIENT *http_client, char *data, int dlen) +{ + int hdr_len = (int) LEN(http_client->buf); + + /* 是否连同HTTP响应头一起发送? */ + if (hdr_len > 0) { + /* 将HTTP响应头和一部分数据体一起发送, + * 这样可以减少 IO 写次数 + */ + + struct iovec iov[2]; + + iov[0].iov_base = STR(http_client->buf); + iov[0].iov_len = hdr_len; + iov[1].iov_base = (char*) data; + iov[1].iov_len = dlen; + + /* 必须提交将缓冲区提前复位,但不影响内部数据 */ + ACL_VSTRING_RESET(http_client->buf); + /* 将客户端流加锁,防止被提前关闭 */ + http_client->flag |= HTTP_FLAG_CLIENT_LOCKED; + acl_aio_writev(http_client->entry.client, iov, 2); + } else { + /* 响应头已经发送,此处仅发送响应体部分数据 */ + + /* 将客户端流加锁,防止被提前关闭 */ + http_client->flag |= HTTP_FLAG_CLIENT_LOCKED; + acl_aio_writen(http_client->entry.client, data, dlen); + } +} + +/* 获得服务器HTTP数据体并发送至浏览器 */ + +static void forward_respond_body_data(HTTP_CLIENT *http_client, + char *data, int dlen) +{ + const char *data_saved = data; + char *data_ptr = data; + char *ptr; + ACL_ITER iter; + plugin_dat_free_fn last_plugin_free = NULL; + char *last_plugin_buf = NULL; + void *plugin_res_ctx = http_client->plugin_res_ctx; + HTTP_SERVICE *service = (HTTP_SERVICE*) http_client->entry.service; + + /* 遍历所有的数据体过滤器 */ + acl_foreach(iter, &service->respond_dat_plugins) { + HTTP_PLUGIN *tmp = (HTTP_PLUGIN*) iter.data; + int stop = 0, ret; + ptr = tmp->data_filter(data_ptr, dlen, &ret, &stop, plugin_res_ctx); + + /* 释放前一个过滤器分配的动态内存 */ + if (last_plugin_buf && last_plugin_buf != data_saved && last_plugin_free) + last_plugin_free(last_plugin_buf, plugin_res_ctx); + + dlen = ret; + data = data_ptr = ptr; + last_plugin_buf = ptr; + last_plugin_free = tmp->data_free; + + if (ret < 0 || ptr == NULL) { + ret = -1; + data = NULL; + break; + } else if (stop) + break; + } + + /* 向客户端写数据 */ + if (dlen > 0 && data) + send_to_client(http_client, data, dlen); + + /* 释放前一个过滤器分配的动态内存 */ + if (last_plugin_buf && last_plugin_buf != data_saved && last_plugin_free) + last_plugin_free(last_plugin_buf, plugin_res_ctx); +} + +/* 成功从服务器读到响应体数据的回调函数 */ + +static int read_respond_body_ready(int status, char *data, int dlen, void *arg) +{ + HTTP_CLIENT *http_client = (HTTP_CLIENT *) arg; + +acl_msg_info("%s(%d)", __FUNCTION__, __LINE__); /* only for test */ + if (data == NULL || dlen <= 0) { + /* 取消服务端流的锁定状态 */ + http_client->flag &= ~HTTP_FLAG_SERVER_LOCKED; + /* 设置会话完成标志位 */ + http_client->flag |= HTTP_FLAG_FINISH; + http_proxy_complete(http_client, -1); + return (-1); + } + + http_client->total_size += dlen; + + /* client 流有可能被提前关闭了 */ + if (http_client->entry.client == NULL) { + /* 取消服务端流的锁定状态 */ + http_client->flag &= ~HTTP_FLAG_SERVER_LOCKED; + /* 设置会话完成标志位 */ + http_client->flag |= HTTP_FLAG_FINISH; + http_proxy_complete(http_client, -1); + return (-1); + } + + if (status >= HTTP_CHAT_ERR_MIN) { + /* 取消服务端流的锁定状态 */ + http_client->flag &= ~HTTP_FLAG_SERVER_LOCKED; + /* 设置会话完成标志位 */ + http_client->flag |= HTTP_FLAG_FINISH; + http_proxy_complete(http_client, -1); + return (-1); + } else if (status == HTTP_CHAT_OK) { + /* 设置会话完成标志位 */ + http_client->flag |= HTTP_FLAG_FINISH; +#if 1 + /* 取消服务端流的锁定状态 */ + http_client->flag &= ~HTTP_FLAG_SERVER_LOCKED; +#endif + } + + /* 如果 HTTP_FLAG_FINISH 标志设置,则会在 forward_respond_body_data 之后 + * 回调函数 send_respond_body_complete 调用 http_proxy_complete + */ + forward_respond_body_data(http_client, data, dlen); +#if 0 + if (status == HTTP_CHAT_OK) { + /* 取消服务端流的锁定状态 */ + http_client->flag &= ~HTTP_FLAG_SERVER_LOCKED; + http_proxy_complete(http_client, 0); + } +#endif + + return (0); +} + +/* 发送响应体数据至客户端, 如果确定已经发送完最后一批数据则触发结束过程 */ + +static int send_respond_body_complete(ACL_ASTREAM *client acl_unused, void *ctx) +{ + HTTP_CLIENT *http_client = (HTTP_CLIENT *) ctx; + + /* 取消客户端流的锁定状态, 从而允许当服务流异常关闭时可以在 + * on_close_server 等函数里调用 http_proxy_complete 时里关闭客户流! + */ + http_client->flag &= ~HTTP_FLAG_CLIENT_LOCKED; + + /* 如果是最后的数据则完成本次会话过程 */ + if ((http_client->flag & HTTP_FLAG_FINISH)) { + if ((http_client->flag & HTTP_FLAG_SERVER_CLOSED)) + http_proxy_complete(http_client, -1); + else + http_proxy_complete(http_client, 0); + } + return (0); +} + +/* 传输服务器响应HTTP数据体至浏览器 + * 调用该过程的函数需要注意流关闭保护措施 + */ + +static void forward_respond_hdr_body(HTTP_CLIENT *http_client) +{ + /* 创建HTTP响应体对象 */ + http_client->res = http_res_new(http_client->hdr_res); + + /* 如果向客户流发送响应体失败会自动调用在 send_request_hdr_complete + * 里针对客户流设置的回调函数 on_close_clinet + */ + + /* 设置向客户流发送数据成功的回调函数 */ + acl_aio_add_write_hook(http_client->entry.client, + send_respond_body_complete, http_client); + + /* 将服务端流置于锁定状态, 从而防止被提前关闭 */ + http_client->flag |= HTTP_FLAG_SERVER_LOCKED; + +acl_msg_info("%s(%d)", __FUNCTION__, __LINE__); /* only for test */ + /* 开始从服务器读取HTTP数据体数据 */ + http_res_body_get_async(http_client->res, + http_client->entry.server, + read_respond_body_ready, + http_client, + http_client->entry.service->rw_timeout); +} + +/* 发送服务器响应头至浏览器 */ + +static int send_respond_hdr_complete(ACL_ASTREAM *client acl_unused, void *ctx) +{ + const char *myname = "send_respond_hdr_complete"; + HTTP_CLIENT *http_client = (HTTP_CLIENT *) ctx; + + /* 取消客户端流的锁定状态 */ + http_client->flag &= ~HTTP_FLAG_CLIENT_LOCKED; + + if (http_client->hdr_res == NULL) { + acl_msg_error("%s(%d): http_client->hdr_res null", myname, __LINE__); + http_proxy_complete(http_client, -1); + return (0); + } + + /* 因为进入此函数后 client 的引用值已经被 acl_aio_xxx 自动加1了, + * 所以也许不必担心重复关闭流的现象发生 + */ + http_proxy_complete(http_client, 0); + return (0); +} + +/* 仅 forward 响应头,因为没有响应体 */ + +static void forward_respond_hdr(HTTP_CLIENT *http_client) +{ + acl_aio_add_write_hook(http_client->entry.client, + send_respond_hdr_complete, http_client); + + /* 设定客户端流为锁定状态 */ + http_client->flag |= HTTP_FLAG_CLIENT_LOCKED; + + acl_aio_writen(http_client->entry.client, + acl_vstring_str(http_client->buf), + (int) ACL_VSTRING_LEN(http_client->buf)); +} + +static void start_forward_respond(HTTP_CLIENT *http_client) +{ + /* 是否与服务端保持长连接? */ + if (!var_cfg_http_client_keepalive) { + http_hdr_entry_replace(&http_client->hdr_res->hdr, + "Connection", "close", 1); + http_hdr_entry_replace(&http_client->hdr_res->hdr, + "Proxy-Connection", "close", 0); + } else if (http_client->req_curr->hdr_req->hdr.keep_alive + && http_client->hdr_res->hdr.keep_alive) + { + http_hdr_entry_replace(&http_client->hdr_res->hdr, + "Connection", "keep-alive", 1); + http_hdr_entry_replace(&http_client->hdr_res->hdr, + "Proxy-Connection", "keep-alive", 0); + } + + /* 重新组成HTTP响应头 */ + http_hdr_build(&http_client->hdr_res->hdr, http_client->buf); + + /* 对于 3xx, 4xx 的服务器响应,不应有数据体部分 */ + + if (http_client->hdr_res->hdr.content_length == 0 + || (http_client->hdr_res->hdr.content_length == -1 + && !http_client->hdr_res->hdr.chunked + && http_client->hdr_res->reply_status > 300 + && http_client->hdr_res->reply_status < 400)) + { + /* 如果没有数据体,则仅返回数据头 */ + forward_respond_hdr(http_client); + return; + } + + /* 将数据头连同一部分数据体一起发送给客户端,从而减少io次数 */ + + /* xxx: 对于没有 content-length 或 content-length > 0 + * 及服务器响应状态码不为 3xx, 4xx 的情况 + */ + forward_respond_hdr_body(http_client); +} + +/** + * 针对HTTP响应头的过滤器处理过程,如果根据该响应头过滤器决定完全接管 + * 该响应则主程序不再处理该服务端流及客户端流 + * 返回 0 表示所有过滤器均不接管该响应, 否则表示接管 + */ +static int reply_plugin_takeover(HTTP_CLIENT *http_client) +{ + const char *myname = "reply_plugin_takeover"; + HTTP_SERVICE *service = (HTTP_SERVICE*) http_client->entry.service; + HTTP_PLUGIN *plugin = NULL; + ACL_ITER iter; + + /* xxx: plugin_res_ctx 该参数在每次请求都有可能不一样, 外挂模块应该自行管理 */ + http_client->plugin_res_ctx = NULL; + + /* 遍历所有的插件回调处理函数 */ + + acl_foreach(iter, &service->respond_plugins) { + ACL_ASTREAM *client = http_client->entry.client; + ACL_ASTREAM *server = http_client->entry.server; + ACL_VSTREAM *client_stream = acl_aio_vstream(client); + ACL_VSTREAM *server_stream = acl_aio_vstream(server); + HTTP_PLUGIN *tmp = (HTTP_PLUGIN*) iter.data; + + if (tmp->filter.respond(client_stream, server_stream, + http_client->req_curr->hdr_req, + http_client->hdr_res, + &http_client->plugin_res_ctx)) + { + plugin = tmp; + break; + } + } + + if (plugin && plugin->forward.respond) { + ACL_ASTREAM *client = http_client->entry.client; + ACL_ASTREAM *server = http_client->entry.server; + ACL_VSTREAM *client_stream = acl_aio_vstream(client); + ACL_VSTREAM *server_stream = acl_aio_vstream(server); + HTTP_HDR_REQ *hdr_req; + HTTP_HDR_RES *hdr_res; + void *plugin_res_ctx = http_client->plugin_res_ctx; + + /* 将 http_client 中的 hdr_req/hdr_res 置空 */ + if (http_client->req_curr) { + hdr_req = http_client->req_curr->hdr_req; + http_client->req_curr->hdr_req = NULL; + if (http_client->req_curr->req) + http_client->req_curr->req->hdr_req = NULL; + } else { + acl_msg_fatal("%s(%d): req_curr null", myname, __LINE__); + /* XXX: can't reach here just avoid compiling warning */ + hdr_req = NULL; + } + hdr_res = http_client->hdr_res; + http_client->hdr_res = NULL; + + /* 将客户端数据流与该代理对象分离 */ + client_entry_detach(&http_client->entry, client_stream); + + /* 将服务端数据与该代理对象分离 */ + /* 因为 entry 代理对象的引用计数为0,所以其会在该分离函数 + * 中自动被释放 + */ + client_entry_detach(&http_client->entry, server_stream); + + /* 禁止异步流的读/写监控 */ + acl_aio_disable_readwrite(client); + acl_aio_disable_readwrite(server); + + /* 清除回调函数 */ + acl_aio_clean_hooks(client); + acl_aio_clean_hooks(server); + + /* 将客户端异步流的数据流置空 */ + acl_aio_ctl(client, ACL_AIO_CTL_STREAM, NULL, ACL_AIO_CTL_END); + /* 将服务端异步流的数据流置空 */ + acl_aio_ctl(server, ACL_AIO_CTL_STREAM, NULL, ACL_AIO_CTL_END); + + /* xxx: 异步关闭 client/server 异步流 */ + acl_aio_iocp_close(client); + acl_aio_iocp_close(server); + + /* 必须流由非阻塞模式转换为阻塞模式 */ + acl_non_blocking(ACL_VSTREAM_SOCK(client_stream), ACL_BLOCKING); + acl_non_blocking(ACL_VSTREAM_SOCK(server_stream), ACL_BLOCKING); + + /* 调用在非阻塞通信时设置的关闭回调函数并清除之 */ + acl_vstream_call_close_handles(client_stream); + acl_vstream_call_close_handles(server_stream); + + /* 至此,已经将客户端数据流由非阻塞模式转换为阻塞模式,同时关闭 + * 了与服务端的连接流,将该连接请求转给相关代理模块处理,异步 + * 代理不再代理该客户端的请求及服务端的响应 + * 注意:client_stream, hdr_res, hdr_res 此处并未释放, + * 需要下载代理模块下载完毕后自己单独释放 + */ + plugin->forward.respond(client_stream, server_stream, + hdr_req, hdr_res, plugin_res_ctx); + return (1); + } + + return (0); +} + +static int http_request_reforward(HTTP_CLIENT *http_client); +static int read_respond_hdr_timeout(ACL_ASTREAM *server, void *ctx); +static int read_respond_hdr_error(ACL_ASTREAM *server, void *ctx); + +/* 获得服务器响应头 */ +static void begin_read_respond(HTTP_CLIENT *http_client); + +static int get_respond_hdr_ready(int status, void *arg) +{ + const char *myname = "get_respond_hdr_ready"; + HTTP_CLIENT *http_client = (HTTP_CLIENT *) arg; + ACL_ASTREAM *client = http_client->entry.client; + ACL_ASTREAM *server = http_client->entry.server; + + /* 取消服务流的锁定状态 */ + http_client->flag &= ~HTTP_FLAG_SERVER_LOCKED; + + /* xxx: sanity check */ + + if (client == NULL) { + acl_msg_warn("%s: client null(%s)", myname, + http_client->flag & HTTP_FLAG_FINISH + ? "finished" : "not finished"); + http_client->flag |= HTTP_FLAG_FINISH; + http_proxy_complete(http_client, -1); + return (0); + } + + /* 需要关闭两个回调函数,防止触发 read_respond_hdr_error + * 和 read_respond_hdr_timeout 过程(read_respond_hdr_timeout 会触发 + * read_respond_hdr_error), 而在 read_respond_hdr_error 里会调用 + * http_request_reforward + */ + acl_aio_ctl(server, + ACL_AIO_CTL_CLOSE_HOOK_DEL, read_respond_hdr_error, http_client, + ACL_AIO_CTL_TIMEO_HOOK_DEL, read_respond_hdr_timeout, http_client, + ACL_AIO_CTL_END); + +acl_msg_info("%s(%d)", __FUNCTION__, __LINE__); /* only for test */ + if (status != HTTP_CHAT_OK) { + /* 如果读响应头出现错误则需要重试 */ + + /* 进行重试 */ + if (http_request_reforward(http_client) == 0) { + /* 如果已经开始重试过程,则直接返回 */ + return (0); + } + + http_proxy_complete(http_client, -1); + /* xxx: 应该返回 5xx 信息给客户端 */ + return (0); + } + + /* 分析 HTTP 响应头 */ + + if (http_hdr_res_parse(http_client->hdr_res) < 0) { + /* 如果分析响应头失败则需要重试 */ + + acl_msg_error("%s: parse hdr_res error", myname); + /* 进行重试 */ + if (http_request_reforward(http_client) == 0) { + /* 如果已经开始重试过程,则直接返回 */ + return (0); + } + + http_proxy_complete(http_client, -1); + /* xxx: 应该返回 5xx 信息给客户端 */ + return (0); + } + + /* 忽略 100 continue 的回应 */ + if (http_client->hdr_res->reply_status == 100) { + begin_read_respond(http_client); + return (0); + } + + /* 判断是否需要由其它代理模块接管 */ + if (reply_plugin_takeover(http_client)) { + return (0); + } + + /* 开始转发服务器返回的数据给客户端 */ + start_forward_respond(http_client); + return (0); +} + +static int read_respond_hdr_timeout(ACL_ASTREAM *server, void *ctx) +{ + const char *myname = "read_respond_hdr_timeout"; + HTTP_CLIENT *http_client = (HTTP_CLIENT *) ctx; + + /* 取消服务流的锁定状态 */ + http_client->flag &= ~HTTP_FLAG_SERVER_LOCKED; + + /* 取消 HTTP 响应头的读关闭回调函数 */ + acl_aio_clean_close_hooks(server); + + if (http_client->entry.client == NULL) { + acl_msg_warn("%s(%d): client null", myname, __LINE__); + http_proxy_complete(http_client, -1); + /* 必须返回 -1, 因为不希望继续调用其它的超时回调函数 */ + return (-1); + } + + /* 进行重试 */ + if (http_request_reforward(http_client) == 0) { + /* 如果已经开始重试过程,则直接返回 */ + /* 必须返回 -1, 因为不希望继续调用其它的超时回调函数 */ + return (-1); + } + + /* 锁定客户端流 */ + http_client->flag |= HTTP_FLAG_CLIENT_LOCKED; + + /* 返回给客户端读服务端响应超时信息 */ + acl_aio_writen(http_client->entry.client, + HTTP_REPLY_TIMEOUT, (int) strlen(HTTP_REPLY_TIMEOUT)); + + /* 解锁客户端流 */ + http_client->flag &= ~HTTP_FLAG_CLIENT_LOCKED; + + http_proxy_complete(http_client, -1); + /* 必须返回 -1, 因为不希望继续调用其它的超时回调函数 */ + return (-1); +} + +static int read_respond_hdr_error(ACL_ASTREAM *server acl_unused, void *ctx) +{ + const char *myname = "read_respond_hdr_error"; + HTTP_CLIENT *http_client = (HTTP_CLIENT *) ctx; + + /* 取消服务流的锁定状态 */ + http_client->flag &= ~HTTP_FLAG_SERVER_LOCKED; + + if (http_client->entry.client == NULL) { + acl_msg_warn("%s(%d): client null", myname, __LINE__); + /* 必须返回 -1, 因为不希望继续调用其它的关闭回调函数 */ + http_proxy_complete(http_client, -1); + return (-1); + } + + /* 进行重试 */ + if (http_request_reforward(http_client) == 0) { + /* 如果已经开始重试过程,则直接返回 */ + /* 必须返回 -1, 因为不希望继续调用其它的关闭回调函数 */ + return (-1); + } + + /* 锁定客户端流 */ + http_client->flag |= HTTP_FLAG_CLIENT_LOCKED; + + /* 返回给客户端读服务端响应出错信息 */ + acl_aio_writen(http_client->entry.client, + HTTP_REPLY_ERROR, (int) strlen(HTTP_REPLY_ERROR)); + + /* 解锁客户端流 */ + http_client->flag &= ~HTTP_FLAG_CLIENT_LOCKED; + + http_proxy_complete(http_client, -1); + /* 必须返回 -1, 因为不希望继续调用其它的关闭回调函数 */ + return (-1); +} + +/* XXX: 该函数需要处于关闭保护状态,即调用此函数的函数需要对服务端流加保护措施 */ + +static void begin_read_respond(HTTP_CLIENT *http_client) +{ + /* 生成一个 HTTP 响应头 */ + http_client->hdr_res = http_hdr_res_new(); + + /* 设定服务流的锁定状态 */ + http_client->flag |= HTTP_FLAG_SERVER_LOCKED; + + /* 设置从服务器的读错误及读超时的回调函数 */ + acl_aio_ctl(http_client->entry.server, + ACL_AIO_CTL_CLOSE_HOOK_ADD, read_respond_hdr_error, http_client, + ACL_AIO_CTL_TIMEO_HOOK_ADD, read_respond_hdr_timeout, http_client, + ACL_AIO_CTL_END); + + /* 开始读服务端的 HTTP 响应头 */ + http_hdr_res_get_async(http_client->hdr_res, + http_client->entry.server, + get_respond_hdr_ready, + http_client, + http_client->entry.service->rw_timeout); +} + +/*----------------------------------------------------------------------------*/ + +/* 发送最后请求数据至服务器的回调函数, 至此函数,通信方向发生 + * 改变,由原来的从客户流读数据、向服务流写数据变为从服务流读 + * 数据、向客户流写数据 + */ + +static int send_request_body_complete(ACL_ASTREAM *server, void *context) +{ + HTTP_CLIENT *http_client = (HTTP_CLIENT*) context; + + /* 取消服务流的锁定状态 */ + http_client->flag &= ~HTTP_FLAG_SERVER_LOCKED; + + /* xxx: sanity check */ + if (http_client->entry.client == NULL) { + http_proxy_complete(http_client, -1); + return (0); + } + + /* 如果请求体数据发送完毕则开始读取服务器响应 */ + if ((http_client->flag & HTTP_FLAG_REQEND)) { + /* 取消之前设置的发送请求体成功的回调函数 */ + acl_aio_del_write_hook(server, send_request_body_complete, + http_client); + http_client->flag &= ~HTTP_FLAG_REQEND; + /* 开始读取服务端的响应数据 */ + begin_read_respond(http_client); + } + return (0); +} + +/* 读到一些HTTP请求体数据 */ + +static int read_request_body_ready(int status, char *data, int dlen, void *arg) +{ + const char *myname = "read_request_body_ready"; + HTTP_CLIENT *http_client = (HTTP_CLIENT *) arg; + + if (data == NULL || dlen <= 0) { + acl_msg_error("%s(%d): data: %s, dlen: %d", + myname, __LINE__, data ? "not null" : "null", dlen); + /* 取消客户流的锁定状态 */ + http_client->flag &= ~HTTP_FLAG_CLIENT_LOCKED; + /* 设置请求过程完毕标志位 */ + http_client->flag |= HTTP_FLAG_REQEND; + http_proxy_complete(http_client, -1); + return (0); + } + + if (http_client->entry.server == NULL) { + /* 有可能在向服务端写数据时出错而触发了 on_close_server 过程, + * 从而导致 http_proxy_complete 过程被调用 + */ + + /* 取消客户流的锁定状态 */ + http_client->flag &= ~HTTP_FLAG_CLIENT_LOCKED; + /* 设置请求过程完毕标志位 */ + http_client->flag |= HTTP_FLAG_REQEND; + http_proxy_complete(http_client, -1); + return (0); + } + + if (status >= HTTP_CHAT_ERR_MIN) { + /* 取消客户端流的锁定状态 */ + http_client->flag &= ~HTTP_FLAG_CLIENT_LOCKED; + /* 设置请求过程完毕标志位 */ + http_client->flag |= HTTP_FLAG_REQEND; + http_proxy_complete(http_client, -1); + return (0); + } else if (status == HTTP_CHAT_OK) { + /* 已经读完了浏览器本次会话的请求数据 */ + + /* 因为已经从客户端读完了本次会话的请求数据,所以此处可以 + * 取消客户端流锁定状态, 以允许当向服务端写数据出错时可以在 + * on_close_server 中关闭客户端流 + */ + http_client->flag &= ~HTTP_FLAG_CLIENT_LOCKED; + /* 设置请求过程完毕标志位 */ + http_client->flag |= HTTP_FLAG_REQEND; + } + + /* 设定服务端流的锁定状态 */ + http_client->flag |= HTTP_FLAG_SERVER_LOCKED; + /* 将来自于浏览器的数据体部分发送至服务器 */ + acl_aio_writen(http_client->entry.server, data, dlen); + return (0); +} + +/* 如果有请求体则转发请求体数据至服务器 */ + +static void forward_request_body(HTTP_CLIENT *http_client) +{ + /* 根据请求头对象生成请求体对象 */ + http_client->req_curr->req = http_req_new(http_client->req_curr->hdr_req); + + /* 设置发送请求体成功的回调函数 */ + acl_aio_add_write_hook(http_client->entry.server, + send_request_body_complete, http_client); + + /* 将客户端流置于锁定状态, 从而防止被提前关闭 */ + http_client->flag |= HTTP_FLAG_CLIENT_LOCKED; + + /* 开始读客户端请求体数据 */ + http_req_body_get_async(http_client->req_curr->req, + http_client->entry.client, + read_request_body_ready, + http_client, + http_client->entry.service->rw_timeout); +} + +/* 发送请求头至服务器时出错的回调函数 */ +static int send_request_hdr_complete(ACL_ASTREAM *server, void *ctx); + +static int send_request_hdr_error(ACL_ASTREAM *server acl_unused, void *ctx) +{ + HTTP_CLIENT *http_client = (HTTP_CLIENT *) ctx; + + /* 取消服务流的锁定状态 */ + http_client->flag &= ~HTTP_FLAG_SERVER_LOCKED; + + /* 如果仅是传输请求头时出错,则可以进行重试 */ + if (http_request_reforward(http_client) == 0) { + /* 如果已经开始重试过程,则直接返回 */ + /* 必须返回 -1, 因为不希望继续调用其它的关闭回调函数 */ + return (-1); + } + + /* 防止向客户流写数据出错时提前关闭客户流 */ + acl_aio_refer(http_client->entry.client); + + /* 返回给客户端读服务端响应出错信息 */ + acl_aio_writen(http_client->entry.client, + HTTP_SEND_ERROR, (int) strlen(HTTP_SEND_ERROR)); + + /* 恢复客户流为可关闭状态 */ + acl_aio_unrefer(http_client->entry.client); + + /* 该会话完毕 */ + http_proxy_complete(http_client, -1); + /* 必须返回 -1, 因为不希望继续调用其它的关闭回调函数 */ + return (-1); +} + +/* 发送请求头至服务器成功时的回调函数 */ + +static int send_request_hdr_complete(ACL_ASTREAM *server acl_unused, void *ctx) +{ + HTTP_CLIENT *http_client = (HTTP_CLIENT *) ctx; + + /* 取消服务流的锁定状态 */ + http_client->flag &= ~HTTP_FLAG_SERVER_LOCKED; + + /* 关闭上次注册的写完成及出错的回调函数 */ + acl_aio_ctl(http_client->entry.server, + ACL_AIO_CTL_WRITE_HOOK_DEL, send_request_hdr_complete, http_client, + ACL_AIO_CTL_CLOSE_HOOK_DEL, send_request_hdr_error, http_client, + ACL_AIO_CTL_END); + + if (http_client->req_curr->hdr_req->hdr.content_length > 0) { + /* 如果有请求体,则读取客户端请求体数据 */ + forward_request_body(http_client); + } else { + /* 没有请求体,则开始读服务端的返回数据 */ + begin_read_respond(http_client); + } + + return (0); +} + +/* 重新构建HTTP请求头 */ + +static void rebuild_request(HTTP_HDR_REQ *hdr_req, ACL_VSTRING *buf) +{ + ACL_ITER iter; + HTTP_HDR_ENTRY *entry; + int i = 0; + + /* XXX: nginx 有时对含有 Proxy-Connection 的请求有时会有延迟? */ +#if 0 + http_hdr_entry_off(&hdr_req->hdr, "Proxy-Connection"); +#endif + +#if 0 + acl_vstring_sprintf(buf, "%s http://%s%s HTTP/%d.%d\r\n", + hdr_req->method, hdr_req->host, + acl_vstring_str(hdr_req->url_part), + hdr_req->hdr.version.major, + hdr_req->hdr.version.minor); +#else + acl_vstring_sprintf(buf, "%s %s HTTP/%d.%d\r\n", + hdr_req->method, + acl_vstring_str(hdr_req->url_part), + hdr_req->hdr.version.major, + hdr_req->hdr.version.minor); +#endif + + acl_foreach(iter, hdr_req->hdr.entry_lnk) { + if (i++ == 0) + continue; + entry = (HTTP_HDR_ENTRY*) iter.data; + if (entry->off) + continue; + acl_vstring_strcat(buf, entry->name); + acl_vstring_strcat(buf, ": "); + acl_vstring_strcat(buf, entry->value); + acl_vstring_strcat(buf, "\r\n"); + } + acl_vstring_strcat(buf, "\r\n"); +} + +/* 连接服务器成功,开始向服务器发送HTTP请求头 */ +static void start_forward_request(HTTP_CLIENT *http_client) +{ + /* 分配动态内存 */ + if (http_client->buf == NULL) { + http_client->buf = acl_vstring_alloc(HTTP_HDRLEN_DEF); + } else { + ACL_VSTRING_RESET(http_client->buf); + } + + if (var_cfg_http_proxy_connection_off) { + /* 主要是一些比较弱的类似GFW的东东似乎处理该字段有问题,会有延迟 */ + http_hdr_entry_off(&http_client->req_curr->hdr_req->hdr, "Proxy-Connection"); + } + + /* 重新创建 HTTP 请求头至 http_client->buf 中 */ + rebuild_request(http_client->req_curr->hdr_req, http_client->buf); + + /* 设置回调函数 */ + acl_aio_ctl(http_client->entry.server, + ACL_AIO_CTL_WRITE_HOOK_ADD, send_request_hdr_complete, http_client, + ACL_AIO_CTL_CLOSE_HOOK_ADD, send_request_hdr_error, http_client, + ACL_AIO_CTL_END); + + /* 锁定服务端 */ + http_client->flag |= HTTP_FLAG_SERVER_LOCKED; + + /* 向服务器转发客户端的HTTP请求头数据 */ + acl_aio_writen(http_client->entry.server, + acl_vstring_str(http_client->buf), + (int) ACL_VSTRING_LEN(http_client->buf)); +} + +/*----------------------------------------------------------------------------*/ + +/* 将客户端请求数据重新向后端其它服务器发送 */ + +static int http_request_reforward(HTTP_CLIENT *http_client) +{ + const char *myname = "http_request_reforward"; + ACL_ASTREAM *server = http_client->entry.server; + + /* 如果不是从连接池中取得的连接则将重试次数加 1 */ + if (!http_client->entry.flag_conn_reuse) + http_client->entry.nretry_on_error++; + + if (http_client->hdr_res) { + http_hdr_res_free(http_client->hdr_res); + http_client->hdr_res = NULL; + } + + /* 断开与服务端的连接,但保持与浏览器端的连接 */ + if (server) { + /* 使服务流与该会话分离 */ + client_entry_detach(&http_client->entry, acl_aio_vstream(server)); + /* 取消 HTTP 响应头的回调函数 */ + acl_aio_clean_hooks(server); + /* only for test */ + if (acl_aio_iswset(server)) { + acl_msg_info("%s(%d): defer free(%d)\n", myname, __LINE__, ACL_VSTREAM_SOCK(server->stream)); + } else + acl_msg_info("%s(%d): not defer free(%d)\n", myname, __LINE__, ACL_VSTREAM_SOCK(server->stream)); + /* 仅异步关闭服务端流 */ + acl_aio_iocp_close(server); + } + + /* 如果重试次数超过该域名所对应的IP主机个数则返回错误,不再重试 */ + if (http_client->entry.nretry_on_error > http_client->entry.dns_ctx.ip_cnt) { + acl_msg_error("%s(%d): has retried before(%d,%d), reuse connecion %s", + myname, __LINE__, http_client->entry.nretry_on_error, + http_client->entry.dns_ctx.ip_cnt, + http_client->entry.flag_conn_reuse ? "yes" : "no"); + return (-1); + } + + /* 如果重试次数超过阀值,则不再重试直接返回错误 */ + if (http_client->entry.nretry_on_error >= MAX_RETRIED) { + acl_msg_error("%s(%d): has retried before(%d,%d)", + myname, __LINE__, http_client->entry.nretry_on_error, + MAX_RETRIED); + return (-1); + } + + /* 开始重试连接下一个IP */ + forward_start((CLIENT_ENTRY*) http_client); + return (0); +} + +/*----------------------------------------------------------------------------*/ + +static char HTTP_CONNECT_FIRST[] = "HTTP/1.0 200 Connection established\r\n\r\n"; + +/* 当服务端流关闭时的回调函数 */ + +static int on_close_server(ACL_ASTREAM *server acl_unused, void *ctx) +{ + HTTP_CLIENT *http_client = (HTTP_CLIENT*) ctx; + + /* 取消服务端流的锁定状态 */ + http_client->flag &= ~HTTP_FLAG_SERVER_LOCKED; + http_client->flag |= HTTP_FLAG_SERVER_CLOSED | HTTP_FLAG_FINISH; + http_proxy_complete(http_client, -1); + /* 必须返回 -1, 因为不希望继续调用其它的关闭回调函数 */ + return (-1); +} + +static int http_proxy_connect_complete(CLIENT_ENTRY *entry) +{ + HTTP_CLIENT *http_client = (HTTP_CLIENT*) entry; + const char *method = http_client->req_curr->hdr_req->method; + + /* 添加服务流关闭时的回调函数 */ + acl_aio_add_close_hook(http_client->entry.server, + on_close_server, http_client); + + /* CONNECT 请求, 转向纯 TCP 代理模式, 从而方便支持 SSL */ + if (var_cfg_http_method_connect_enable && strcasecmp(method, "CONNECT") == 0) { + if (entry->client == NULL) { + acl_msg_warn("%s(%d): client null", __FILE__, __LINE__); + http_proxy_complete(http_client, -1); + return (0); + } + + acl_aio_writen(entry->client, HTTP_CONNECT_FIRST, + (int) strlen(HTTP_CONNECT_FIRST)); + if (entry->client && entry->server) { + tcp_start(entry); + return (0); + } else { + http_proxy_complete(http_client, -1); + return (0); + } + } + + if (strcasecmp(method, "GET") != 0 && strcasecmp(method, "POST") != 0) { + if (entry->client == NULL) { + acl_msg_error("%s(%d): client null", __FILE__, __LINE__); + } else + acl_aio_writen(entry->client, HTTP_REQUEST_INVALID, + (int) strlen(HTTP_REQUEST_INVALID)); + acl_msg_error("%s(%d): method(%s) invalid", + __FILE__, __LINE__, method); + http_proxy_complete(http_client, -1); + return (0); /* 返回-1以使异步框架关闭该异步流 */ + } + + /* 处理 GET、POST 请求 */ + start_forward_request(http_client); + return (0); +} + +static void http_proxy_connect_timeout(CLIENT_ENTRY *entry) +{ + const char *myname = "http_proxy_connect_timeout"; + + if (entry->client == NULL) { + acl_msg_error("%s(%d): client null", myname, __LINE__); + http_proxy_complete((HTTP_CLIENT*) entry, -1); + } else { + acl_msg_error("%s(%d): connect(%s, %s) timeout", + myname, __LINE__, entry->domain_key, + entry->domain_addr); + acl_aio_refer(entry->client); + acl_aio_writen(entry->client, HTTP_CONNECT_TIMEOUT, + (int) strlen(HTTP_CONNECT_TIMEOUT)); + acl_aio_unrefer(entry->client); + http_proxy_complete((HTTP_CLIENT*) entry, -1); + } +} + +static void http_proxy_connect_error(CLIENT_ENTRY *entry) +{ + const char *myname = "http_proxy_connect_error"; + + if (entry->client == NULL) { + acl_msg_error("%s(%d): client null", myname, __LINE__); + http_proxy_complete((HTTP_CLIENT*) entry, -1); + } else { + acl_msg_error("%s(%d): connect(%s, %s) error", + myname, __LINE__, entry->domain_key, + entry->domain_addr); + acl_aio_refer(entry->client); + acl_aio_writen(entry->client, HTTP_CONNECT_ERROR, + (int) strlen(HTTP_CONNECT_ERROR)); + acl_aio_unrefer(entry->client); + http_proxy_complete((HTTP_CLIENT*) entry, -1); + } +} + +static void nslookup_complete_fn(CLIENT_ENTRY *entry, int status) +{ + if (status == NSLOOKUP_OK) { + /* 设置连接成功后的回调函数 */ + entry->connect_notify_fn = http_proxy_connect_complete; + entry->connect_timeout_fn = http_proxy_connect_timeout; + entry->connect_error_fn = http_proxy_connect_error; + forward_start(entry); + } else { + acl_aio_refer(entry->client); + acl_aio_writen(entry->client, HTTP_REPLY_DNS_ERR, + (int) strlen(HTTP_REPLY_DNS_ERR)); + acl_aio_unrefer(entry->client); + http_proxy_complete((HTTP_CLIENT*) entry, -1); + } +} + +static void handle_one(HTTP_CLIENT *http_client, HTTP_CLIENT_REQ *req) +{ + int ret; + http_client->req_curr = req; /* 设置当前可以处理的请求 */ + + /* 先检查用户自定义过滤器 */ + if ((ret = http_client_req_filter(http_client))) { + /* 如果返回非0值则表示请求过滤器接管了该请求 */ + return; + } + + /* 设置DNS查询回调函数 */ + http_client->entry.nslookup_notify_fn = nslookup_complete_fn; + http_client->entry.dns_errmsg = NULL; + + /* 从浏览器的请求头中获取服务端的端口号 */ + dns_lookup(&http_client->entry, req->hdr_req->host, req->hdr_req->port); +} + +/** + * 成功读到HTTP请求头后的回调函数 + */ +static int request_header_ready(int status, void *arg) +{ + const char *myname = "request_header_ready"; + HTTP_CLIENT_REQ *req = (HTTP_CLIENT_REQ *) arg; + HTTP_CLIENT *http_client = req->http_client; + const char *via; + static char *via_static = NULL; + static int via_max = 256; + + /* 取消客户端流的锁定状态 */ + http_client->flag &= ~HTTP_FLAG_CLIENT_LOCKED; + + if (status != HTTP_CHAT_OK) { + http_proxy_complete(http_client, -1); + return (0); + } + + if (http_hdr_req_parse3(req->hdr_req, 0 , 0) < 0) { + acl_msg_error("%s: parse hdr_req error", myname); + http_proxy_complete(http_client, -1); + return (0); + } + + if (via_static == NULL) { + via_static = (char*) acl_mycalloc(1, via_max); + snprintf(via_static, via_max, "jaws-%d", getpid()); + } + + /* 检查是否产生回路现象 */ + + via = http_hdr_entry_value(&req->hdr_req->hdr, "x-via-jaws"); + if (via == NULL) { + http_hdr_put_str(&req->hdr_req->hdr, "x-via-jaws", via_static); + } else if (strcasecmp(via, via_static) == 0) { + acl_msg_warn("%s(%d): loop tested, via(%s), url(http://%s%s)", + myname, __LINE__, via, req->hdr_req->host, + acl_vstring_str(req->hdr_req->url_part)); + + /* 锁定客户端流 */ + http_client->flag |= HTTP_FLAG_CLIENT_LOCKED; + + acl_aio_writen(http_client->entry.client, + HTTP_REQUEST_LOOP, + (int) strlen(HTTP_REQUEST_LOOP)); + + /* 取消客户端流的锁定状态 */ + http_client->flag &= ~HTTP_FLAG_CLIENT_LOCKED; + http_proxy_complete(http_client, -1); + return (0); + } + + /* 该请求已经完成,取消其等待状态 */ + req->flag &= ~CLIENT_READ_WAIT; + + if (http_client->req_curr != NULL) { + /* 如果前一个请求还未处理完毕,则返回 */ + return (0); + } + + /* 当前没有正在处理的请求过程,所以开始处理该请求 */ + + /* 从队列中弹出该请求,以免被重复使用 */ + if (acl_fifo_pop(&http_client->req_list) != req) + acl_msg_fatal("%s(%d): request invalid", myname, __LINE__); + + handle_one(http_client, req); + return (0); +} + +static int http_proxy_next(HTTP_CLIENT *http_client) +{ + HTTP_CLIENT_REQ *req = acl_fifo_head(&http_client->req_list); + + if (req) { + if (!(req->flag & CLIENT_READ_WAIT)) + handle_one(http_client, req); + } else { + http_proxy_req_get(http_client); + } + + return (0); +} + +/* 发送响应体至客户端失败时的回调函数 */ + +static int on_close_client(ACL_ASTREAM *client acl_unused, void *ctx) +{ + HTTP_CLIENT *http_client = (HTTP_CLIENT*) ctx; + +#if 0 + acl_msg_info("%s(%d): close client(%lx, fd=%d) now, server %s", + __FUNCTION__, __LINE__, (long) client, + ACL_VSTREAM_SOCK(client->stream), + http_client->entry.server ? "not null" : "null"); +#endif + /* 取消客户端流的锁定状态 */ + http_client->flag &= ~HTTP_FLAG_CLIENT_LOCKED; + /* 设置客户流的关闭状态 */ + http_client->flag |= HTTP_FLAG_CLIENT_CLOSED | HTTP_FLAG_FINISH; + http_proxy_complete(http_client, -1); + /* 必须返回 -1, 因为不希望继续调用其它的关闭回调函数 */ + return (-1); +} + +static void http_proxy_req_get(HTTP_CLIENT *http_client) +{ + HTTP_CLIENT_REQ *req = http_client_req_new(http_client); + + req->flag |= CLIENT_READ_WAIT; + req->hdr_req = http_hdr_req_new(); + acl_fifo_push(&http_client->req_list, req); + + /* 设置从客户流读数据失败或出现其它错误时的回调函数 */ + acl_aio_add_close_hook(http_client->entry.client, + on_close_client, http_client); + + /* 锁定客户端流 */ + http_client->flag |= HTTP_FLAG_CLIENT_LOCKED; + + http_client->total_size = 0; + http_client->flag &= ~HTTP_FLAG_CLIENT_KEEP_ALIVE; + http_client->flag &= ~HTTP_FLAG_SERVER_KEEP_ALIVE; + + /* 开始读取HTTP请求头 */ + http_hdr_req_get_async(req->hdr_req, + http_client->entry.client, + request_header_ready, + req, + http_client->entry.service->rw_timeout); +} + +int http_proxy_start(HTTP_CLIENT *http_client) +{ +acl_msg_info("%s(%d)", __FUNCTION__, __LINE__); /* only for test */ + http_proxy_req_get(http_client); + return (0); +} diff --git a/app/jaws/module/mod_http/http_server.c b/app/jaws/module/mod_http/http_server.c new file mode 100644 index 000000000..40e36d000 --- /dev/null +++ b/app/jaws/module/mod_http/http_server.c @@ -0,0 +1,321 @@ +#include "lib_acl.h" +#include "lib_protocol.h" +#include +#include +#include +#ifdef ACL_UNIX +#include +#endif +#include "service.h" +#include "http_service.h" + +#ifdef ACL_UNIX +#include +#endif + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +static int http_server_keep_alive_next(HTTP_CLIENT *client) +{ + http_client_reset(client); + http_service_start(client); + + return (0); +} + +static int http_reply_error(HTTP_CLIENT *client, int status) +{ + const ACL_VSTRING *tmpl_error = http_tmpl_get(status); + + client->hdr_res = http_hdr_res_error(status); + http_hdr_build(&client->hdr_res->hdr, client->buf); + acl_vstring_strcat(client->buf, STR(tmpl_error)); + WRITE_TO_CLIENT(client, STR(client->buf), LEN(client->buf)); + + return (-1); +} + +static int http_reply_file(HTTP_CLIENT *client) +{ + char buf[8192]; + int n; + + n = acl_vstream_read(client->fp, buf, sizeof(buf)); + if (n == ACL_VSTREAM_EOF) { + /* only for test */ +#if 0 + acl_msg_info("200 http://%s/%s", client->hdr_req->host, + acl_vstring_str(client->hdr_req->url_path)); +#endif + if (client->sent_size != client->total_size) { + if (client->cache) + file_cache_free(client->cache); + client->cache = NULL; + } + if (client->hdr_res->hdr.keep_alive) + return (http_server_keep_alive_next(client)); + return (-1); + } + + if (client->cache) + file_cache_push(client->cache, buf, n); + client->sent_size += n; + + WRITE_TO_CLIENT(client, buf, n); + return (0); +} + +static int send_file_ready(ACL_ASTREAM *stream acl_unused, void *ctx) +{ + HTTP_CLIENT *client = (HTTP_CLIENT*) ctx; + + return (http_reply_file(client)); +} + +static int send_file_hdr_ready(ACL_ASTREAM *stream, void *ctx) +{ + HTTP_CLIENT *client = (HTTP_CLIENT*) ctx; + + acl_aio_ctl(stream, + ACL_AIO_CTL_WRITE_FN, send_file_ready, + ACL_AIO_CTL_END); + return (http_reply_file(client)); +} + +static int http_doc_file(HTTP_CLIENT *client, const char *filepath) +{ + const char *myname = "http_doc_file"; + struct acl_stat sbuf; + + if(client->buf == NULL) + client->buf = acl_vstring_alloc(HTTP_HDRLEN_DEF); + + assert(client->fp == NULL); + client->fp = acl_vstream_fopen(filepath, O_RDONLY, 0600, 4096); + if (client->fp == NULL) { + char ebuf[256]; + + acl_msg_error("%s(%d): file(%s) no exist, error(%s)", + myname, __LINE__, filepath, + acl_last_strerror(ebuf, sizeof(ebuf))); + + if (errno == EACCES) + return (http_reply_error(client, 403)); + else if (errno == ENOENT || errno == EISDIR) + return (http_reply_error(client, 404)); + else + return (http_reply_error(client, 500)); + } + + if (acl_stat(filepath, &sbuf) < 0) { + acl_msg_error("%s(%d): fstat file(%s) error(%s)", + myname, __LINE__, filepath, strerror(errno)); + return (http_reply_error(client, 404)); + } + + client->total_size = (int) sbuf.st_size; + client->sent_size = 0; + if (client->use_cache) + client->cache = file_cache_new(filepath, sbuf.st_mtime); + client->hdr_res = http_hdr_res_static(200); + http_hdr_set_keepalive(client->req_curr->hdr_req, client->hdr_res); + http_hdr_put_int(&client->hdr_res->hdr, "Content-Length", (int) sbuf.st_size); + http_hdr_put_int(&client->hdr_res->hdr, "Last-Modified", (int) sbuf.st_mtime); + + http_hdr_build(&client->hdr_res->hdr, client->buf); + + /* xxx: only for test: ACL_AIO_CTL_CLOSE_FN */ + acl_aio_ctl(client->entry.client, + ACL_AIO_CTL_WRITE_FN, send_file_hdr_ready, + ACL_AIO_CTL_CLOSE_FN, NULL, + ACL_AIO_CTL_TIMEO_FN, NULL, + ACL_AIO_CTL_CTX, client, + ACL_AIO_CTL_END); + + /* write http respond header */ + WRITE_TO_CLIENT(client, STR(client->buf), LEN(client->buf)); + return (0); +} + +static int http_doc_cache_send(HTTP_CLIENT *client, const char *hdr, size_t len) +{ +#ifndef UIO_MAX +#define UIO_MAX 512 +#endif + + struct iovec chunks[UIO_MAX]; + BUFFER *buffer; + int i; + + if (hdr && len > 0) { + chunks[0].iov_base = STR(client->buf); + chunks[0].iov_len = LEN(client->buf); + i = 1; + } else { + i = 0; + } + + for (; i < UIO_MAX - 1; i++) { + buffer = file_cache_next_buffer(&client->cache_iter); + if (buffer == NULL) + break; + chunks[i].iov_base = buffer->buf; + chunks[i].iov_len = buffer->size; + } + chunks[i].iov_base = NULL; + chunks[i].iov_len = 0; + + if (i == 0) { + /* only for test */ +#if 0 + acl_msg_info("200 http://%s/%s", client->hdr_req->host, + acl_vstring_str(client->hdr_req->url_path)); +#endif + if (client->hdr_res->hdr.keep_alive) + return (http_server_keep_alive_next(client)); + return (-1); + } + + WRITEV_TO_CLIENT(client, chunks, i); + return (0); +} + +static int send_cache_ready(ACL_ASTREAM *stream acl_unused, void *ctx) +{ + HTTP_CLIENT *client = (HTTP_CLIENT*) ctx; + + return (http_doc_cache_send(client, NULL, 0)); +} + +static int http_doc_cache(HTTP_CLIENT *client, FILE_CACHE *cache) +{ + client->cache = cache; + file_cache_iter(cache, &client->cache_iter); + + client->hdr_res = http_hdr_res_static(200); + http_hdr_set_keepalive(client->req_curr->hdr_req, client->hdr_res); + http_hdr_put_int(&client->hdr_res->hdr, "Content-Length", (int) cache->size); + http_hdr_put_str(&client->hdr_res->hdr, "Last-Modified", cache->tm_mtime); + + if(client->buf == NULL) + client->buf = acl_vstring_alloc(HTTP_HDRLEN_DEF); + + http_hdr_build(&client->hdr_res->hdr, client->buf); + + /* only for test */ +#if 0 + acl_aio_disable_read(client->entry.client); +#endif + + acl_aio_ctl(client->entry.client, + ACL_AIO_CTL_WRITE_FN, send_cache_ready, + ACL_AIO_CTL_CLOSE_FN, NULL, + ACL_AIO_CTL_TIMEO_FN, NULL, + ACL_AIO_CTL_CTX, client, + ACL_AIO_CTL_END); + + return (http_doc_cache_send(client, STR(client->buf), LEN(client->buf))); +} + +/** + * 成功读到HTTP请求头后的回调函数 + */ +static int request_header_ready(int status, void *arg) +{ + const char *myname = "request_header_ready"; + HTTP_CLIENT_REQ *req = (HTTP_CLIENT_REQ*) arg; + HTTP_CLIENT *http_client = req->http_client; + const HTTP_VHOST *vhost; + const HTTP_VPATH *vpath; + FILE_CACHE *cache; + ACL_VSTRING *file_path = ((HTTP_SERVICE*) + http_client->entry.service)->file_path; + char *ptr; + + /* 先禁止读操作,因为目前还不支持 pipeline 模式 */ + acl_aio_disable_read(http_client->entry.client); + + if (status != HTTP_CHAT_OK) { + acl_debug(20, 2) ("%s: status(%d)", myname, status); + return (-1); + } + + if (http_hdr_req_parse(req->hdr_req) < 0) { + acl_msg_error("%s: parse hdr_req error", myname); + return (-1); + } + + vhost = http_vhost_find(req->hdr_req->host); + if (vhost == NULL) { + acl_msg_error("%s(%d): host(%s) not found", myname, __LINE__, + req->hdr_req->host); + return (-1); + } + vpath = http_vpath_find(vhost, acl_vstring_str(req->hdr_req->url_path)); + if (vpath == NULL) { + acl_msg_error("%s(%d): vpath(%s) not found", myname, __LINE__, + acl_vstring_str(req->hdr_req->url_path)); + return (-1); + } + if (vpath->type != HTTP_TYPE_DOC) { + acl_msg_error("%s(%d): type(%d) not supported yet", + myname, __LINE__, vpath->type); + return (-1); + } + + if (ACL_VSTRING_LEN(req->hdr_req->url_path) <= 0) { + acl_msg_error("%s: url_path(%s)'s len(%d)", + myname, acl_vstring_str(req->hdr_req->url_path), + ACL_VSTRING_LEN(req->hdr_req->url_path)); + return (-1); + } + + if (http_client->req_curr != NULL) { + /* 如果前一个请求还未处理完毕,则返回 */ + return (0); + } + http_client->req_curr = req; /* 设置当前可以处理的请求 */ + + /* 先检查用户自定义过滤器 */ + if (http_client_req_filter(http_client)) { + /* 返回 -1 仅是为了让异步框架自动关闭该异步流对象, + * 因为该异步流已经与数据流分离,所以当关闭异步流 + * 时,并不真正关闭与浏览器之间的数据流,也不关闭 + * 与服务器之间的数据流 + */ + return (-1); + } + + ptr = STR(req->hdr_req->url_path); + if (*ptr == '/') + ptr++; + acl_vstring_strcpy(file_path, STR(vpath->path)); + acl_vstring_strcat(file_path, ptr); + + if (*(acl_vstring_end(req->hdr_req->url_path) - 1) == '/') + acl_vstring_strcat(file_path, vhost->default_page); + + if (http_client->use_cache) { + cache = file_cache_find(STR(file_path)); + if (cache) + return (http_doc_cache(http_client, cache)); + } + return (http_doc_file(http_client, acl_vstring_str(file_path))); +} + +int http_server_start(HTTP_CLIENT *http_client) +{ + HTTP_CLIENT_REQ *req = http_client_req_new(http_client); + + req->hdr_req = http_hdr_req_new(); + acl_fifo_push(&http_client->req_list, req); + + http_hdr_req_get_async(req->hdr_req, + http_client->entry.client, + request_header_ready, + req, + http_client->entry.service->rw_timeout); + return (0); +} diff --git a/app/jaws/module/mod_http/http_service.c b/app/jaws/module/mod_http/http_service.c new file mode 100644 index 000000000..ed53fe3bf --- /dev/null +++ b/app/jaws/module/mod_http/http_service.c @@ -0,0 +1,58 @@ +#include "lib_acl.h" + +#include "dns_lookup.h" +#include "service.h" +#include "http_module.h" +#include "http_vhost.h" +#include "http_service.h" + +#ifdef ACL_MS_WINDOWS +# include +# pragma comment(lib,"ws2_32") +# define getpid _getpid +#endif + +void http_service_start(HTTP_CLIENT *http_client) +{ + switch (http_filter_type()) { + case HTTP_FILTER_PROXY: + http_proxy_start(http_client); + break; + case HTTP_FILTER_HTTPD: + http_server_start(http_client); + break; + default: + forward_complete(&http_client->entry); + break; + } +} + +void http_service_main(HTTP_SERVICE *service, ACL_ASTREAM *stream) +{ + HTTP_CLIENT *client; + + client = http_client_new(service, stream); + http_service_start(client); +} + +void http_service_free(HTTP_SERVICE *service) +{ + http_plugin_unload_all(); + service_free((SERVICE*) service); +} + +HTTP_SERVICE *http_service_new() +{ + HTTP_SERVICE *service; + + service = (HTTP_SERVICE *) service_alloc("http", sizeof(HTTP_SERVICE)); + service->file_path = acl_vstring_alloc(256); + + /* 将动态插件的回调函数赋给服务对象 */ + http_plugin_set_callback(service); + + /* 针对HTTP服务器运行模式,初始化文件缓存 */ + file_cache_init(); + + return (service); +} diff --git a/app/jaws/module/mod_http/http_service.h b/app/jaws/module/mod_http/http_service.h new file mode 100644 index 000000000..a70b0568d --- /dev/null +++ b/app/jaws/module/mod_http/http_service.h @@ -0,0 +1,192 @@ +#ifndef __HTTP_SERVICE_INCLUDE_H__ +#define __HTTP_SERVICE_INCLUDE_H__ + +#include "lib_acl.h" +#include +#include "lib_protocol.h" + +#include "service_struct.h" +#include "file_cache.h" +#include "http_vhost.h" +#include "dns.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define DEBUG_PROXY_BASE 60 +#define DEBUG_HTML_TITLE (DEBUG_PROXY_BASE + 1) + +/* 常量定义 */ +#define STR acl_vstring_str +#define LEN ACL_VSTRING_LEN +#define SCP ACL_SAFE_STRNCPY + +#define HTTP_HDRLEN_DEF 8192 + +#define HTTP_FILTER_ERROR 0 +#define HTTP_FILTER_HTTPD (1<<0) +#define HTTP_FILTER_PROXY (1<<1) + +typedef struct HTTP_SERVICE HTTP_SERVICE; +typedef struct HTTP_CLIENT HTTP_CLIENT; + +/* 过滤器初始化函数类型定义 */ +typedef void (*plugin_init_fn)(ACL_DLL_ENV *dll_env, const char *plugin_cfg_dir); + +/* 过滤器匹配函数类型定义 */ +typedef int (*plugin_filter_request_fn)(ACL_VSTREAM *client, + HTTP_HDR_REQ *hdr_req, + void **ctx_ptr); +typedef int (*plugin_filter_respond_fn)(ACL_VSTREAM *client, + ACL_VSTREAM *server, + HTTP_HDR_REQ *hdr_req, + HTTP_HDR_RES *hdr_res, + void **ctx_ptr); + +/* 过滤器接管函数类型定义 */ +typedef void (*plugin_forward_request_fn)(ACL_VSTREAM *client, + HTTP_HDR_REQ *hdr_req, void *ctx); +typedef void (*plugin_forward_respond_fn)(ACL_VSTREAM *client, ACL_VSTREAM *server, + HTTP_HDR_REQ *hdr_req, HTTP_HDR_RES *hdr_res, void *ctx); + +/* HTTP数据体过滤器函数类型定义 */ +typedef char *(*plugin_dat_filter_fn)(const char *data, int dlen, + int *ret, int *stop, void *ctx); +/* 释放HTTP数据体过滤器分配的内存 */ +typedef void (*plugin_dat_free_fn)(void *buf, void *ctx); + +/* 过滤器结构类型定义 */ +typedef struct HTTP_PLUGIN { + plugin_init_fn init; + union { + plugin_filter_request_fn request; /* 请求过滤器 */ + plugin_filter_respond_fn respond; /* 响应过滤器 */ + } filter; /* 过滤器接口 */ + union { + plugin_forward_request_fn request; /* 请求接管器 */ + plugin_forward_respond_fn respond; /* 响应接管器 */ + } forward; /* 接管器接口 */ + plugin_dat_filter_fn data_filter; /* 数据体过滤器 */ + plugin_dat_free_fn data_free; /* 释放动态内存 */ +} HTTP_PLUGIN; + +struct HTTP_SERVICE { + SERVICE service; + ACL_VSTRING *file_path; + + ACL_FIFO request_plugins; /* 外挂请求过滤器(HTTP_PLUGIN)集合 */ + ACL_FIFO respond_plugins; /* 外挂响应过滤器(HTTP_PLUGIN)集合 */ + ACL_FIFO request_dat_plugins; /* 外挂请求过滤器(HTTP_PLUGIN)集合 */ + ACL_FIFO respond_dat_plugins; /* 外挂响应过滤器(HTTP_PLUGIN)集合 */ +}; + +typedef struct { + HTTP_CLIENT *http_client; + HTTP_HDR_REQ *hdr_req; /* HTTP协议请求头指针 */ + HTTP_REQ *req; /* HTTP协议请求 */ + int flag; +#define CLIENT_READ_WAIT (1 << 2) +#define SERVER_READ_WAIT (1 << 3) +} HTTP_CLIENT_REQ; + +struct HTTP_CLIENT { + CLIENT_ENTRY entry; /* 基本代理对象 */ + HTTP_CLIENT_REQ *req_curr; /* 当前正被处理的请求 */ + ACL_FIFO req_list; /* HTTP请求队列 */ +#define WRITE_TO_CLIENT(x, buff, dlen) acl_aio_writen((x)->entry.client, (buff), (int) (dlen)) +#define WRITEV_TO_CLIENT(x, vect, cnt) acl_aio_writev((x)->entry.client, (vect), (int) (cnt)) +#define WRITE_TO_SERVER(x, buff, dlen) acl_aio_writen((x)->entry.server, (buff), (int) (dlen)) + HTTP_HDR_RES *hdr_res; /* HTTP协议响应头指针 */ + HTTP_RES *res; /* HTTP协议响应 */ + ACL_VSTREAM *fp; + + int use_cache; + ACL_VSTRING *buf; /* 内部用的动态内存 */ + FILE_CACHE *cache; + CACHE_ITER cache_iter; + + unsigned int flag; +#define HTTP_FLAG_CLIENT_LOCKED (1 << 0) +#define HTTP_FLAG_SERVER_LOCKED (1 << 1) +#define HTTP_FLAG_CLIENT_CLOSED (1 << 3) +#define HTTP_FLAG_SERVER_CLOSED (1 << 4) +#define HTTP_FLAG_REQEND (1 << 5) +#define HTTP_FLAG_FINISH (1 << 6) +#define HTTP_FLAG_CLIENT_KEEP_ALIVE (1 << 7) +#define HTTP_FLAG_SERVER_KEEP_ALIVE (1 << 8) + + size_t total_size; + size_t sent_size; + + struct { + time_t read_reqhdr; /* 读HTTP协议请求头时间 */ + time_t read_reqbody; /* 读HTTP协议请求体时间 */ + time_t read_reshdr; /* 读HTTP协议响应头时间 */ + time_t read_resbody; /* 读HTTP协议响应体时间 */ + time_t send_reqhdr; /* 写HTTP协议请求头时间 */ + time_t send_reqbody; /* 写HTTP协议请求体时间 */ + time_t send_reshdr; /* 写HTTP协议响应头时间 */ + time_t send_resbody; /* 写HTTP协议响应体时间 */ + } tm; + + plugin_dat_filter_fn request_filter; /* 外挂模块HTTP请求数据体过滤器 */ + plugin_dat_filter_fn respond_filter; /* 外挂模块HTTP响应数据体过滤器 */ + void *plugin_req_ctx; /* 外挂模块在HTTP请求阶段的动态参数 */ + void *plugin_res_ctx; /* 外挂模块在HTTP响应阶段的动态参数 */ +}; + +/* in html_template.c */ +extern char HTTP_REPLY_DNS_ERR[]; +extern char HTTP_REPLY_TIMEOUT[]; +extern char HTTP_REPLY_ERROR[]; +extern char HTTP_SEND_ERROR[]; +extern char HTTP_REQUEST_INVALID[]; +extern char HTTP_REQUEST_LOOP[]; +extern char HTTP_CONNECT_ERROR[]; +extern char HTTP_CONNECT_TIMEOUT[]; +extern char HTTP_REQUEST_DENY[]; +extern char HTTP_REQUEST_NOFOUND[]; +extern char HTTP_INTERNAL_ERROR[]; + +/* in http_service.c */ +void http_service_main(HTTP_SERVICE *service, ACL_ASTREAM *stream); +void http_service_start(HTTP_CLIENT *client); +void http_service_free(HTTP_SERVICE *service); +HTTP_SERVICE *http_service_new(void); + +/* in http_filter.c */ +int http_filter_type(void); +void http_filter_set(const char *filter_info); + +/* in http_plugin.c */ +void http_plugin_load(ACL_DLL_ENV *dll_env, const char *dlname, const char *plugin_cfgdir); +void http_plugin_load_all(ACL_DLL_ENV *dll_env, const char *dlnames, const char *plugin_cfgdir); +void http_plugin_unload_all(void); +void http_plugin_set_callback(HTTP_SERVICE *service); + +/* in http_conf.c */ +void http_conf_load(const char *path, const char *default_cf); + +/* in http_client.c */ +HTTP_CLIENT *http_client_new(HTTP_SERVICE *service, ACL_ASTREAM *stream); +void http_client_free(CLIENT_ENTRY *entry); +void http_client_reset(HTTP_CLIENT *client); +HTTP_CLIENT_REQ *http_client_req_new(HTTP_CLIENT *http_client); +void http_client_req_free(HTTP_CLIENT_REQ *req); +int http_client_req_filter(HTTP_CLIENT *http_client); + +/* in http_server.c */ +int http_server_start(HTTP_CLIENT *http_client); + +/* in http_proxy.c */ +int http_proxy_start(HTTP_CLIENT *entry); + +/* in tcp_proxy.c */ +void tcp_start(CLIENT_ENTRY *entry); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/app/jaws/module/mod_http/http_vhost.c b/app/jaws/module/mod_http/http_vhost.c new file mode 100644 index 000000000..c4b14812d --- /dev/null +++ b/app/jaws/module/mod_http/http_vhost.c @@ -0,0 +1,258 @@ +#include "lib_acl.h" +#include "lib_protocol.h" + +#include +#include +#include +#include + +#include "http_vhost.h" + +static ACL_HTABLE *__vhost_table = NULL; +static HTTP_VHOST *__vhost_default = NULL; + +static HTTP_VPATH *vpath_new(const char *vpath, const char *path, int type) +{ + const char *myname = "vpath_new"; + HTTP_VPATH *http_vpath; + char ebuf[256]; + + http_vpath = acl_mycalloc(1, sizeof(HTTP_VPATH)); + if (http_vpath == NULL) + acl_msg_fatal("%s, %s(%d): calloc error(%s)", + __FILE__, myname, __LINE__, + acl_last_strerror(ebuf, sizeof(ebuf))); + http_vpath->vpath = acl_vstring_alloc(256); + if (http_vpath->vpath == NULL) + acl_msg_fatal("%s, %s(%d): calloc error(%s)", + __FILE__, myname, __LINE__, + acl_last_strerror(ebuf, sizeof(ebuf))); + http_vpath->path = acl_vstring_alloc(256); + if (http_vpath->path == NULL) + acl_msg_fatal("%s, %s(%d): calloc error(%s)", + __FILE__, myname, __LINE__, + acl_last_strerror(ebuf, sizeof(ebuf))); + + /* make sure path format: "/path/.../" */ + +#define STR_CP(_vstr, _str) do { \ + if (*_str != '/') \ + acl_vstring_strcpy(_vstr, "/"); \ + acl_vstring_strcat(_vstr, _str); \ + if (acl_vstring_charat(_vstr, ACL_VSTRING_LEN(_vstr) - 1) != '/') \ + acl_vstring_strcat(_vstr, "/"); \ + acl_lowercase(acl_vstring_str(_vstr)); \ +} while (0) + + STR_CP(http_vpath->vpath, vpath); + STR_CP(http_vpath->path, path); + http_vpath->type = type; + + return (http_vpath); +} + +static void vpath_free(HTTP_VPATH *http_vpath) +{ + if (http_vpath == NULL) + return; + + if (http_vpath->vpath) + acl_myfree(http_vpath->vpath); + if (http_vpath->path) + acl_myfree(http_vpath->path); + acl_myfree(http_vpath); +} + +static HTTP_VHOST *vhost_new(const char *host, HTTP_VPATH *http_vpath_root, const char *default_page) +{ + const char *myname = "vhost_new"; + HTTP_VHOST *http_vhost; + char ebuf[256]; + + http_vhost = acl_mycalloc(1, sizeof(HTTP_VHOST)); + if (http_vhost == NULL) + acl_msg_fatal("%s, %s(%d): calloc error(%s)", + __FILE__, myname, __LINE__, + acl_last_strerror(ebuf, sizeof(ebuf))); + + ACL_SAFE_STRNCPY(http_vhost->host, host, sizeof(http_vhost->host)); + acl_lowercase(http_vhost->host); + http_vhost->vpath_root = http_vpath_root; + if (default_page && *default_page) + ACL_SAFE_STRNCPY(http_vhost->default_page, default_page, sizeof(http_vhost->default_page)); + else + ACL_SAFE_STRNCPY(http_vhost->default_page, "index.html", sizeof(http_vhost->default_page)); + + http_vhost->vpath_table = acl_htable_create(10, 0); + if (http_vhost->vpath_table == NULL) + acl_msg_fatal("%s, %s(%d): acl_htable_create error(%s)", + __FILE__, myname, __LINE__, + acl_last_strerror(ebuf, sizeof(ebuf))); + return (http_vhost); +} + +static void free_vpath_fn(void *arg) +{ + HTTP_VPATH *http_vpath = (HTTP_VPATH *) arg; + + vpath_free(http_vpath); +} + +static void vhost_free(HTTP_VHOST *http_vhost) +{ + acl_htable_free(http_vhost->vpath_table, free_vpath_fn); + vpath_free(http_vhost->vpath_root); + acl_myfree(http_vhost); +} + +void http_vhost_init(void) +{ + const char *myname = "http_vhost_init"; + char ebuf[256]; + + __vhost_table = acl_htable_create(10, 0); + if (__vhost_table == NULL) + acl_msg_fatal("%s(%d): acl_htable_create error(%s)", + myname, __LINE__, + acl_last_strerror(ebuf, sizeof(ebuf))); +} + +static void free_vhost_fn(void *arg) +{ + HTTP_VHOST *http_vhost = (HTTP_VHOST *) arg; + + vhost_free(http_vhost); +} + +void http_vhost_destroy(void) +{ + if (__vhost_table == NULL) + return; + + acl_htable_free(__vhost_table, free_vhost_fn); + __vhost_table = NULL; +} + +HTTP_VHOST *http_vhost_add_def(const char *host, const char *root_path, const char *default_page) +{ + HTTP_VPATH *http_vpath; + + if (__vhost_default) + return (__vhost_default); + + http_vpath = vpath_new("/", root_path, HTTP_TYPE_DOC); + + __vhost_default = vhost_new(host, http_vpath, default_page); + + return (__vhost_default); +} + +HTTP_VHOST *http_vhost_add(const char *host, const char *root_path, const char *default_page) +{ + const char *myname = "http_vhost_add"; + HTTP_VHOST *http_vhost; + HTTP_VPATH *http_vpath; + char ebuf[256]; + + if (__vhost_default && strcasecmp(__vhost_default->host, host) == 0) + return (__vhost_default); + + http_vhost = (HTTP_VHOST *) acl_htable_find(__vhost_table, host); + + if (http_vhost != NULL) + return (http_vhost); + + http_vpath = vpath_new("/", root_path, HTTP_TYPE_DOC); + http_vhost = vhost_new(host, http_vpath, default_page); + + if (acl_htable_enter(__vhost_table, http_vhost->host, (void *) http_vhost) == NULL) + acl_msg_fatal("%s(%d): acl_htable_enter error(%s)", + myname, __LINE__, + acl_last_strerror(ebuf, sizeof(ebuf))); + + return (http_vhost); +} + +void http_vpath_add(HTTP_VHOST *http_vhost, const char *vpath, const char *path, int type) +{ + const char *myname = "http_vpath_add"; + HTTP_VPATH *http_vpath; + char ebuf[256]; + + http_vpath = (HTTP_VPATH *) acl_htable_find(http_vhost->vpath_table, vpath); + if (http_vpath) + return; + + http_vpath = vpath_new(vpath, path, type); + + if (acl_htable_enter(http_vhost->vpath_table, + acl_vstring_str(http_vpath->vpath), + (void *) http_vpath) == NULL) + acl_msg_fatal(" %s(%d): acl_htable_enter error(%s)", + myname, __LINE__, + acl_last_strerror(ebuf, sizeof(ebuf))); +} + +const HTTP_VHOST *http_vhost_find(const char *host) +{ + HTTP_VHOST *http_vhost; + char buf[1024], *ptr; + + ACL_SAFE_STRNCPY(buf, host, sizeof(buf)); + acl_lowercase(buf); + + ptr = strchr(buf, ':'); + if (ptr) + *ptr = 0; + + http_vhost = (HTTP_VHOST *) acl_htable_find(__vhost_table, buf); + if (http_vhost == NULL) + return (__vhost_default); + + return (http_vhost); +} + +const HTTP_VPATH *http_vpath_find(const HTTP_VHOST *http_vhost, const char *url_path) +{ + const char *myname = "http_vpath_find"; + HTTP_VPATH *http_vpath; + ACL_VSTRING *buf = NULL; + char *ptr, *ptr1; + char ebuf[256]; + +#define RETURN(_x_) do { \ + if (buf) \ + acl_vstring_free(buf); \ + return (_x_); \ +} while (0) + + if (http_vhost == NULL || url_path == NULL) + acl_msg_fatal("%s(%d): input invalid", myname, __LINE__); + + if (*url_path != '/') + RETURN (http_vhost->vpath_root); + + buf = acl_vstring_alloc(512); + if (buf == NULL) + acl_msg_fatal("%s, %s(%d): acl_vstring_alloc error(%s)", + __FILE__, myname, __LINE__, + acl_last_strerror(ebuf, sizeof(ebuf))); + + acl_vstring_strcpy(buf, url_path); + acl_lowercase(acl_vstring_str(buf)); + + ptr = acl_vstring_str(buf); + ptr++; + ptr1 = strchr(ptr, '/'); + if (ptr1) + *(++ptr1) = 0; + else + RETURN (http_vhost->vpath_root); + + http_vpath = (HTTP_VPATH *) acl_htable_find(http_vhost->vpath_table, acl_vstring_str(buf)); + + if (http_vpath == NULL) + RETURN (http_vhost->vpath_root); + + RETURN (http_vpath); +} diff --git a/app/jaws/module/mod_http/http_vhost.h b/app/jaws/module/mod_http/http_vhost.h new file mode 100644 index 000000000..1e6c5acdb --- /dev/null +++ b/app/jaws/module/mod_http/http_vhost.h @@ -0,0 +1,36 @@ +#ifndef __HTTP_VHOST_INCLUDE_H__ +#define __HTTP_VHOST_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct HTTP_VPATH { + ACL_VSTRING *vpath; /* virtual path from url */ + ACL_VSTRING *path; /* local path */ +#define HTTP_TYPE_DOC 0 +#define HTTP_TYPE_CGI 1 +#define HTTP_TYPE_FCGI 2 + int type; +} HTTP_VPATH; + +typedef struct HTTP_VHOST { + char host[256]; + ACL_HTABLE *vpath_table; + HTTP_VPATH *vpath_root; + char default_page[256]; +} HTTP_VHOST; + +void http_vhost_init(void); +void http_vhost_destroy(void); +HTTP_VHOST *http_vhost_add_def(const char *host, const char *root_path, const char *default_page); +HTTP_VHOST *http_vhost_add(const char *host, const char *root_path, const char *default_page); +void http_vpath_add(HTTP_VHOST *http_vhost, const char *vpath, const char *path, int type); +const HTTP_VHOST *http_vhost_find(const char *host); +const HTTP_VPATH *http_vpath_find(const HTTP_VHOST *http_vhost, const char *url_path); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/app/jaws/module/mod_http/mod_http.vcproj b/app/jaws/module/mod_http/mod_http.vcproj new file mode 100644 index 000000000..28b88608a --- /dev/null +++ b/app/jaws/module/mod_http/mod_http.vcproj @@ -0,0 +1,190 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/jaws/module/mod_http/tcp_proxy.c b/app/jaws/module/mod_http/tcp_proxy.c new file mode 100644 index 000000000..2c091f8b1 --- /dev/null +++ b/app/jaws/module/mod_http/tcp_proxy.c @@ -0,0 +1,111 @@ +#include "lib_acl.h" + +#include "service.h" +#include "http_service.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +static int io_close_fn(ACL_ASTREAM *astream, void *context) +{ + const char *myname = "io_close_fn"; + + CLIENT_ENTRY *entry = (CLIENT_ENTRY *) context; + ACL_VSTREAM *stream; + + stream = acl_aio_vstream(astream); + if (stream) + acl_debug(22, 2) ("%s: error to stream", myname); + else + acl_msg_error("not connected"); + + forward_complete(entry); + return (-1); +} + +static int io_timeout_fn(ACL_ASTREAM *astream, void *context acl_unused) +{ + const char *myname = "io_timeout_fn"; + ACL_VSTREAM *stream; + + stream = acl_aio_vstream(astream); + if (stream) + acl_msg_info("%s: timeout to stream", myname); + else + acl_msg_error("not connected"); + return (-1); +} + +#if 0 +static int write_callback(ACL_ASTREAM *stream, void *context) +{ + const char *myname = "write_callback"; + + if (acl_aio_iswset(stream)) { + acl_msg_fatal("%s: acl_aio_iswset return true", myname); + } + + return (0); +} +#endif + +static int read_callback(ACL_ASTREAM *astream, void *context, + const char *data, int dlen) +{ + const char *myname = "read_callback"; + CLIENT_ENTRY *entry = (CLIENT_ENTRY *) context; + +/* + if (acl_aio_isrset(astream)) { + acl_msg_fatal("%s: acl_aio_isrset return true", myname); + } +*/ + + if (dlen <= 0) + acl_msg_fatal("%s: dlen(%d) invalid", myname, dlen); + + if (astream == entry->client) { + if (entry->server == NULL) { + acl_msg_error("%s: server null", myname); + return (-1); + } + acl_aio_writen(entry->server, data, dlen); + } else if (astream == entry->server) { + if (entry->client == NULL) { + acl_msg_error("%s: client null", myname); + return (-1); + } + acl_aio_writen(entry->client, data, dlen); + } else { + acl_msg_error("%s: stream invalid", myname); + } + + acl_aio_read(astream); + + return (0); +} + +void tcp_start(CLIENT_ENTRY *entry) +{ + if (entry->client == NULL || entry->server == NULL) + return; + acl_aio_ctl(entry->client, + ACL_AIO_CTL_READ_FN, read_callback, + ACL_AIO_CTL_CLOSE_HOOK_ADD, io_close_fn, entry, + ACL_AIO_CTL_TIMEO_HOOK_ADD, io_timeout_fn, entry, + ACL_AIO_CTL_TIMEOUT, entry->service->rw_timeout, + ACL_AIO_CTL_CTX, entry, + ACL_AIO_CTL_END); + + acl_aio_ctl(entry->server, + ACL_AIO_CTL_READ_FN, read_callback, + ACL_AIO_CTL_CLOSE_HOOK_ADD, io_close_fn, entry, + ACL_AIO_CTL_TIMEO_HOOK_ADD, io_timeout_fn, entry, + ACL_AIO_CTL_TIMEOUT, entry->service->rw_timeout, + ACL_AIO_CTL_CTX, entry, + ACL_AIO_CTL_END); + + acl_aio_read(entry->client); + acl_aio_read(entry->server); +} diff --git a/app/jaws/plugin/Makefile b/app/jaws/plugin/Makefile new file mode 100644 index 000000000..5e29d4e0e --- /dev/null +++ b/app/jaws/plugin/Makefile @@ -0,0 +1,11 @@ + +.PHONY = all clean + +all: + @(cd gbfilter; make) + @(cd cgi; make) + @(cd http_access; make) +clean: + @(cd gbfilter; make clean) + @(cd cgi; make clean) + @(cd http_access; make clean) diff --git a/app/jaws/plugin/cgi/Makefile b/app/jaws/plugin/cgi/Makefile new file mode 100644 index 000000000..639d23e27 --- /dev/null +++ b/app/jaws/plugin/cgi/Makefile @@ -0,0 +1,117 @@ +SHELL = /bin/sh +CC = gcc +#CC = g++ +AR = ar +ARFL = rv +RANLIB = ranlib + +CFLAGS = -c -g -W -Wall -Wcast-align \ +-Waggregate-return -Wmissing-prototypes \ +-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO \ +-Wno-long-long \ +-Wpointer-arith -Werror -Wshadow -pedantic -O2 \ +-fPIC -DPIC +#-Wcast-qual +########################################################### +#Check system: +# Linux, SunOS, Solaris, BSD variants, AIX, HP-UX +SYSLIB = -ldl +RPATH = + +CHECKSYSRES = @echo "Unknow system type!";exit 1 +UNIXNAME = $(shell uname -sm) +OSTYPE = $(shell uname -p) + +#Path for Linux +ifeq ($(findstring Linux, $(UNIXNAME)), Linux) +# ifeq ($CC, "gcc") + ifeq ($(findstring i686, $(OSTYPE)), i686) + RPATH = linux32 + endif + ifeq ($(findstring x86_64, $(OSTYPE)), x86_64) + RPATH = linux64 + endif + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DLINUX2 + SYSLIB += -lcrypt -lpthread +endif + +#Path for SunOS +ifeq ($(findstring SunOS, $(UNIXNAME)), SunOS) + ifeq ($(findstring i386, $(OSTYPE)), i386) + RPATH = sunos_x86 + endif + ifeq ($(findstring 86, $(UNIXNAME)), 86) + SYSLIB += -lsocket -lnsl -lrt + endif + ifeq ($(findstring sun4u, $(UNIXNAME)), sun4u) + SYSLIB += -lsocket -lnsl -lrt + endif +# ifeq ($CC, "gcc") + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DSUNOS5 +endif + +#Path for HP-UX +ifeq ($(findstring HP-UX, $(UNIXNAME)), HP-UX) +# ifeq ($CC, "gcc") + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + SYSLIB += -lpthread + CFLAGS += -DHP_UX -DHPUX11 + PLAT_NAME=hp-ux +endif + +#Find system type. +ifneq ($(SYSPATH),) + CHECKSYSRES = @echo "System is $(shell uname -sm)" +endif +########################################################### +ACL_PATH = ../../../../lib_acl +ACL_LIB = $(ACL_PATH)/lib +ACL_INC = $(ACL_PATH)/include + +PROTO_PATH = ../../../../lib_protocol +PROTO_LIB = $(PROTO_PATH)/lib +PROTO_INC = $(PROTO_PATH)/include + +ALL_LIBS = -L$(PROTO_LIB) -l_protocol -L$(ACL_LIB) -l_acl $(SYSLIB) + +INCLUDE = -I$(PROTO_INC) -I$(ACL_INC) +CFLAGS += $(INCLUDE) -DHAVE_NO_STRCASESTR + +OBJ_OUTPATH = ./debug + +#Project's objs +SOURCES = $(wildcard *.c) +OBJS = $(patsubst %.c, $(OBJ_OUTPATH)/%.o, $(notdir $(SOURCES))) + +########################################################### +LIB_NAME = cgi.so + +.PHONY = RM all clean +COMPILE = $(CC) $(CFLAGS) + +all: RM $(LIB_NAME) + +RM: + rm -f $(LIB_NAME) + +$(LIB_NAME): $(OBJS) + $(CC) -shared -o $(LIB_NAME) $(OBJS) $(ALL_LIBS) + cp -f $(LIB_NAME) ../../dist/unix_setup/plugin/$(RPATH)/ +# $(CC) -shared -o $(LIB_NAME) $(OBJS) + +$(OBJ_OUTPATH)/%.o: ./%.c + $(COMPILE) -o $@ $< + +clean: + rm -f $(OBJS) $(LIB_NAME) + rm -f $(LIB_NAME) ../../dist/unix_setup/plugin/$(RPATH)/$(LIB_NAME) + +rebuild: clean all diff --git a/app/jaws/plugin/cgi/Release/BuildLog.htm b/app/jaws/plugin/cgi/Release/BuildLog.htm new file mode 100644 index 000000000..a8f0c463c --- /dev/null +++ b/app/jaws/plugin/cgi/Release/BuildLog.htm @@ -0,0 +1,62 @@ + + + + + +
+
+生成日志 +
  
+

------- 已启动生成: 项目: cgi,配置: Release|Win32 ------- +

+
+命令行 +
  
正在创建临时文件“d:\工作目录\项目管理\jaws\jaws\plugin\cgi\Release\RSP000014.rsp”,其内容为
+[
+/O2 /I "..\..\include\protocol" /I "..\..\include\acl" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_USRDLL" /D "CGI_EXPORTS" /D "_WINDLL" /D "_MBCS" /FD /EHsc /MD /GS /Fo"Release/" /Fd"Release/vc70.pdb" /W3 /c /Wp64 /Zi /TC
+.\http_req_filter.c
+.\http_plugin.c
+.\http_conf.c
+.\http_cgi.c
+]
+正在创建命令行“cl.exe @d:\工作目录\项目管理\jaws\jaws\plugin\cgi\Release\RSP000014.rsp /nologo”
+正在创建临时文件“d:\工作目录\项目管理\jaws\jaws\plugin\cgi\Release\RSP000015.rsp”,其内容为
+[
+/OUT:"Release/cgi.dll" /INCREMENTAL:NO /NOLOGO /LIBPATH:"..\..\lib\win32" /DLL /DEBUG /PDB:"Release/cgi.pdb" /SUBSYSTEM:WINDOWS /OPT:REF /OPT:ICF /IMPLIB:"Release/cgi.lib" /MACHINE:X86 lib_protocol.lib lib_acl.lib ws2_32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib
+.\Release\http_cgi.obj
+.\Release\http_conf.obj
+.\Release\http_plugin.obj
+.\Release\http_req_filter.obj
+]
+正在创建命令行“link.exe @d:\工作目录\项目管理\jaws\jaws\plugin\cgi\Release\RSP000015.rsp”
+正在创建临时文件“d:\工作目录\项目管理\jaws\jaws\plugin\cgi\Release\BAT000016.bat”,其内容为
+[
+@echo off
+copy Release\cgi.dll ..\..\build\cgi.dll  /Y
+if errorlevel 1 goto VCReportError
+goto VCEnd
+:VCReportError
+echo Project : error PRJ0019: 工具从"正在执行生成后事件..."
+exit 1
+:VCEnd
+]
+正在创建命令行“d:\工作目录\项目管理\jaws\jaws\plugin\cgi\Release\BAT000016.bat”
+
+输出窗口 +
  
正在编译...
+http_req_filter.c
+http_plugin.c
+http_conf.c
+http_cgi.c
+正在生成代码...
+正在链接...
+LINK : warning LNK4089: /OPT:REF 已丢弃所有对“lib_acl.dll”的引用
+LINK : warning LNK4089: /OPT:REF 已丢弃所有对“lib_protocol.dll”的引用
+正在执行生成后事件...
+已复制         1 个文件。
+
+结果 +
  
+生成日志保存在“file://d:\工作目录\项目管理\jaws\jaws\plugin\cgi\Release\BuildLog.htm”中
+cgi - 0 错误,2 警告
+
\ No newline at end of file diff --git a/app/jaws/plugin/cgi/cgi.cf b/app/jaws/plugin/cgi/cgi.cf new file mode 100644 index 000000000..c5e2696e3 --- /dev/null +++ b/app/jaws/plugin/cgi/cgi.cf @@ -0,0 +1,7 @@ +# configure + +service http_cgi { + logpath = /opt/jaws/var/log/cgifilter.log + cgi-bin = /opt/jaws/www/cgi-bin + cgi-map = /hello /hello.cgi +} diff --git a/app/jaws/plugin/cgi/cgi.vcproj b/app/jaws/plugin/cgi/cgi.vcproj new file mode 100644 index 000000000..2c1913c5f --- /dev/null +++ b/app/jaws/plugin/cgi/cgi.vcproj @@ -0,0 +1,154 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/jaws/plugin/cgi/debug/BuildLog.htm b/app/jaws/plugin/cgi/debug/BuildLog.htm new file mode 100644 index 000000000..069a9c1e9 --- /dev/null +++ b/app/jaws/plugin/cgi/debug/BuildLog.htm @@ -0,0 +1,47 @@ + + + + + +
+
+生成日志 +
  
+

------- 已启动生成: 项目: cgi,配置: Debug|Win32 ------- +

+
+命令行 +
  
正在创建临时文件“d:\工作目录\项目管理\jaws\jaws\plugin\cgi\Debug\RSP0000A3.rsp”,其内容为
+[
+/Od /I "..\..\include\protocol" /I "..\..\include\acl" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_USRDLL" /D "CGI_EXPORTS" /D "_MBCS" /D "_WINDLL" /Gm /EHsc /RTC1 /MTd /Fo"Debug/" /Fd"Debug/vc70.pdb" /W3 /c /Wp64 /ZI /TC
+.\http_cgi.c
+.\http_conf.c
+.\http_plugin.c
+.\http_req_filter.c
+]
+正在创建命令行“cl.exe @d:\工作目录\项目管理\jaws\jaws\plugin\cgi\Debug\RSP0000A3.rsp /nologo”
+正在创建临时文件“d:\工作目录\项目管理\jaws\jaws\plugin\cgi\Debug\RSP0000A4.rsp”,其内容为
+[
+/OUT:"Debug/cgi.dll" /INCREMENTAL /NOLOGO /LIBPATH:"..\..\lib\win32" /DLL /DEBUG /PDB:"Debug/cgi.pdb" /SUBSYSTEM:WINDOWS /IMPLIB:"Debug/cgi.lib" /MACHINE:X86 lib_protocol_d.lib lib_acl_d.lib ws2_32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib
+.\debug\http_req_filter.obj
+.\debug\http_plugin.obj
+.\debug\http_conf.obj
+.\debug\http_cgi.obj
+]
+正在创建命令行“link.exe @d:\工作目录\项目管理\jaws\jaws\plugin\cgi\Debug\RSP0000A4.rsp”
+
+输出窗口 +
  
正在编译...
+http_cgi.c
+http_conf.c
+http_plugin.c
+http_req_filter.c
+正在生成代码...
+正在链接...
+LINK : fatal error LNK1104: 无法打开文件“lib_protocol_d.lib”
+
+结果 +
  
+生成日志保存在“file://d:\工作目录\项目管理\jaws\jaws\plugin\cgi\Debug\BuildLog.htm”中
+cgi - 1 错误,0 警告
+
\ No newline at end of file diff --git a/app/jaws/plugin/cgi/http_cgi.c b/app/jaws/plugin/cgi/http_cgi.c new file mode 100644 index 000000000..97c0ca1ca --- /dev/null +++ b/app/jaws/plugin/cgi/http_cgi.c @@ -0,0 +1,220 @@ +#include "lib_acl.h" +#include "http_plugin.h" + +typedef struct { + ACL_VSTRING *alias; + ACL_VSTRING *cgi; +} CGI_MAP; + +static ACL_HTABLE *__table = NULL; + +static CGI_MAP *cgi_map_new(const char *alias, const char *cgi) +{ + CGI_MAP *map = (CGI_MAP*) acl_mycalloc(1, sizeof(CGI_MAP)); + + map->alias = acl_vstring_alloc(256); + map->cgi = acl_vstring_alloc(256); + acl_vstring_strcpy(map->alias, alias); + acl_vstring_strcpy(map->cgi, var_cfg_cgi_bin); + acl_vstring_strcpy(map->cgi, cgi); + return (map); +} + +static void cgi_map_free(CGI_MAP *map) +{ + acl_vstring_free(map->alias); + acl_vstring_free(map->cgi); + acl_myfree(map); +} + +void http_cgi_init() +{ + __table = acl_htable_create(10, 0); +} + +void http_cgi_end() +{ + acl_htable_free(__table, (void (*)(void*)) cgi_map_free); +} + +void http_cgi_add2(const char *alias, const char *cgi) +{ + CGI_MAP *map; + + map = (CGI_MAP*) acl_htable_find(__table, alias); + if (map != NULL) { + acl_msg_warn("%s(%d): alias(%s) already exist", + __FUNCTION__, __LINE__, alias); + return; + } + map = cgi_map_new(alias, cgi); + acl_htable_enter(__table, alias, map); +} + +void http_cgi_add1(const ACL_ARGV *args) +{ + if (args->argc < 2) { + acl_msg_error("%s(%d): argc(%d) < 2", + __FUNCTION__, __LINE__, args->argc); + return; + } + + http_cgi_add2(args->argv[0], args->argv[1]); +} + +CGI *http_cgi_path(const char *alias) +{ + CGI *cgi; + CGI_MAP *map = (CGI_MAP*) acl_htable_find(__table, alias); + + if (map == NULL) + return (NULL); + + cgi = (CGI*) acl_mycalloc(1, sizeof(CGI)); + cgi->alias = acl_mystrdup(alias); + cgi->cgi = acl_mystrdup(STR(map->cgi)); + return (cgi); +} + +static void cgi_free(CGI *cgi) +{ + if (cgi == NULL) + return; + if (cgi->client) + acl_vstream_close(cgi->client); + if (cgi->hdr_req) + http_hdr_req_free(cgi->hdr_req); + if (cgi->req) { + cgi->req->hdr_req = NULL; + http_req_free(cgi->req); + } + if (cgi->hdr_res) + http_hdr_res_free(cgi->hdr_res); + if (cgi->cgi) + acl_myfree(cgi->cgi); + if (cgi->alias) + acl_myfree(cgi->alias); + acl_myfree(cgi); +} + +static void run_cgi(CGI *cgi, ACL_ARGV *env) +{ + char *command = cgi->cgi; + ACL_VSTREAM *stream; + ACL_VSTRING *vbuf; + ACL_ARGV *cgi_hdrs; + char buf[4096]; + int ret, errnum = 200; + char **cpp; + + /* 打开与CGI程序的管道数据流 */ + stream = acl_vstream_popen(O_RDWR, + ACL_VSTREAM_POPEN_COMMAND, command, + ACL_VSTREAM_POPEN_ENV, env->argv, + ACL_VSTREAM_POPEN_END); + + if (stream == NULL) { + acl_msg_error("%s(%d): open command(%s) error(%s)", + __FUNCTION__, __LINE__, command, acl_last_serror()); + return; + } + + cgi->req = http_req_new(cgi->hdr_req); + if (cgi->hdr_req->hdr.content_length > 0) { + while (1) { + ret = (int) http_req_body_get_sync(cgi->req, cgi->client, + buf, sizeof(buf) - 1); + if (ret <= 0) + break; + if (acl_vstream_writen(stream, buf, ret) == ACL_VSTREAM_EOF) { + acl_vstream_close(stream); + return; + } + } + } + + /* + * http_hdr_set_keepalive(cgi->hdr_req, cgi->hdr_res); + */ + + cgi_hdrs = acl_argv_alloc(10); + + /* 读CGI发送的响应头 */ + while (1) { + char *pname, *ptr; + + ret = acl_vstream_gets_nonl(stream, buf, sizeof(buf)); + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): cgi exit exception", + __FUNCTION__, __LINE__); + errnum = 500; + break; + } + if (ret == 0) { + break; + } + ptr = buf; + pname = acl_mystrtok(&ptr, ":\t "); + if (ptr == NULL) { + acl_msg_warn("%s(%d): cgi reply hdr(%s) invalid", + __FUNCTION__, __LINE__, buf); + continue; + } + acl_argv_add(cgi_hdrs, pname, ptr, NULL); + } + + vbuf = acl_vstring_alloc(256); + + cgi->hdr_res = http_hdr_res_static(errnum); + + for (cpp = cgi_hdrs->argv; *cpp; cpp += 2) { + http_hdr_put_str(&cgi->hdr_res->hdr, cpp[0], cpp[1]); + } + + http_hdr_entry_replace(&cgi->hdr_res->hdr, "Connection", "close", 1); + http_hdr_build(&cgi->hdr_res->hdr, vbuf); + + ret = acl_vstream_writen(cgi->client, STR(vbuf), LEN(vbuf)); + if (ret > 0) { + /* 读CGI的响应数据体并发送至浏览器 */ + while (1) { + ret = acl_vstream_read(stream, buf, sizeof(buf)); + if (ret == ACL_VSTREAM_EOF) + break; + if (acl_vstream_writen(cgi->client, buf, ret) == ACL_VSTREAM_EOF) + break; + } + } + + acl_vstring_free(vbuf); + acl_vstream_pclose(stream); +} + +void http_cgi_thread(void *ctx) +{ + CGI *cgi = (CGI*) ctx; + HTTP_HDR_REQ *hdr_req = cgi->hdr_req; + ACL_ARGV *env = acl_argv_alloc(10); + ACL_ITER iter; + + const char *reply = "HTTP/1.1 200 OK\r\n" + "Date: Sun, 15 Nov 2009 07:06:22 GMT\r\n" + "Server: Apache/2.2.9 (Unix)\r\n" + "Connection: close\r\n" + "Content-Type: text/html\r\n\r\n"; + acl_foreach(iter, hdr_req->hdr.entry_lnk) { + HTTP_HDR_ENTRY *entry = (HTTP_HDR_ENTRY*) iter.data; + + if (entry->off) + continue; + acl_argv_add(env, entry->name, entry->value, NULL); + } + + if (1) + run_cgi(cgi, env); + else { + acl_vstream_writen(cgi->client, reply, sizeof(reply)); + } + acl_argv_free(env); + cgi_free(cgi); +} diff --git a/app/jaws/plugin/cgi/http_conf.c b/app/jaws/plugin/cgi/http_conf.c new file mode 100644 index 000000000..99802b7e6 --- /dev/null +++ b/app/jaws/plugin/cgi/http_conf.c @@ -0,0 +1,89 @@ +#include "lib_acl.h" +#include "http_plugin.h" + +char *var_cfg_log_name; +char *var_cfg_cgi_bin; + +static ACL_CFG_STR_TABLE __conf_str_tab[] = { + /* 配置项名称, 配置项缺省值, 存储配置项值的地址 */ + { "logpath", "/tmp/cgifilter.log", &var_cfg_log_name }, + { "cgi-bin", "/opt/jaws/www/cgi-bin", &var_cfg_cgi_bin }, + + { 0, 0, 0 } +}; + +int var_cfg_data_clone; +static int var_cfg_debug_mem; + +static ACL_CFG_BOOL_TABLE __conf_bool_tab[] = { + /* 配置项名称, 配置项缺省值, 存储配置项值的地址 */ + { "data_clone", 0, &var_cfg_data_clone }, + { "debug_mem", 0, &var_cfg_debug_mem }, + { 0, 0 , 0 } +}; + +static int var_cfg_threads_limit; +static int var_cfg_threads_idle; + +static ACL_CFG_INT_TABLE __conf_int_tab[] = { + /* 配置项名称, 配置项缺省值, 存储配置项值的地址 */ + { "threads_limit", 100, &var_cfg_threads_limit, 0, 0 }, + { "threads_idle", 120, &var_cfg_threads_idle, 0, 0 }, + { 0, 0 , 0, 0, 0 } +}; + +void http_conf_load(const char *cfg_dir) +{ + char *filepath; + ACL_XINETD_CFG_PARSER *cfg; + const ACL_ARRAY *cgi_maps; + + /* 读取配置文件 */ + + filepath = acl_concatenate((cfg_dir && *cfg_dir) + ? cfg_dir : "/tmp", "/cgi.cf", NULL); + cfg = acl_xinetd_cfg_load(filepath); + if (cfg == NULL) + acl_msg_warn("load cfg(%s) error(%s)", + filepath, acl_last_serror()); + + acl_xinetd_params_str_table(cfg, __conf_str_tab); + acl_xinetd_params_int_table(cfg, __conf_int_tab); + acl_xinetd_params_bool_table(cfg, __conf_bool_tab); + + cgi_maps = acl_xinetd_cfg_get_ex(cfg, "cgi-map"); + if (cgi_maps) { + ACL_ITER iter; + + acl_foreach(iter, (ACL_ARRAY*) cgi_maps) { + const char *cgi_map = (const char*) iter.data; + ACL_ARGV *cgi_argv = acl_argv_split(cgi_map, "\t "); + ACL_ITER iter2; + + if (cgi_argv->argc < 2) { + acl_msg_warn("%s(%d): cgi-map(%s) invalid", + __FUNCTION__, __LINE__, cgi_map); + acl_argv_free(cgi_argv); + continue; + } + acl_foreach(iter2, cgi_argv) { + char *ptr = (char*) iter2.data; + acl_lowercase(ptr); + } + http_cgi_add1(cgi_argv); + acl_argv_free(cgi_argv); + } + } + + if (cfg) + acl_xinetd_cfg_free(cfg); + acl_myfree(filepath); + + /* 初始化CGI模块 */ + http_cgi_init(); + + /* 创建线程池 */ + http_plugin_pool_create(var_cfg_threads_limit, var_cfg_threads_idle); + + http_plugin_debug_memory(var_cfg_debug_mem); +} diff --git a/app/jaws/plugin/cgi/http_plugin.c b/app/jaws/plugin/cgi/http_plugin.c new file mode 100644 index 000000000..bb5f74a1d --- /dev/null +++ b/app/jaws/plugin/cgi/http_plugin.c @@ -0,0 +1,72 @@ +#include "lib_acl.h" +#include "http_plugin.h" + +static ACL_DLL_ENV __dll_env; +static acl_pthread_pool_t *__thrpool = NULL; + +/* 初始化该插件的环境 */ + +static void plugin_init(ACL_DLL_ENV *dll_env) +{ + if (dll_env) + memcpy(&__dll_env, dll_env, sizeof(ACL_DLL_ENV)); + else + memset(&__dll_env, 0, sizeof(ACL_DLL_ENV)); + if (__dll_env.logfp) { + acl_msg_open2(__dll_env.logfp, "http-gb"); + acl_msg_info("%s(%d): logger opened, %s", __FUNCTION__, + __LINE__, ACL_VSTREAM_PATH(__dll_env.logfp)); + } + + /* 如果 mem_slice 非空则设置内存分配采用切片分配方式 */ + if (__dll_env.mem_slice) + acl_mem_slice_set(__dll_env.mem_slice); +} + +void http_plugin_init(ACL_DLL_ENV *dll_env, const char *cfg_dir) +{ + plugin_init(dll_env); + http_conf_load(cfg_dir); +} + +void http_plugin_pool_create(int threads_limit, int threads_idle) +{ + const char *myname = "http_plugin_pool_create"; + + if (__thrpool != NULL) { + acl_msg_error("%s(%d): thread pool has been created!", + myname, __LINE__); + return; + } + /* 创建线程池 */ + __thrpool = acl_thread_pool_create(threads_limit, threads_idle); +} + +void http_plugin_pool_append(void (*start_routine)(void *), void *arg) +{ + acl_pthread_pool_add(__thrpool, start_routine, arg); +} + +void http_plugin_debug_memory(int level) +{ + /* 是否调试插件的内存分配情况 */ + + switch (level) { + case 1: + acl_memory_debug_start(); + acl_memory_debug_stack(1); + break; + case 2: + __dll_env.mmd = acl_debug_malloc_init(__dll_env.mmd, + "access_log.txt"); + break; + case 3: + __dll_env.mmd = acl_debug_malloc_init(__dll_env.mmd, + "access_log.txt"); + acl_memory_debug_start(); + acl_memory_debug_stack(1); + break; + default: + break; + } +} diff --git a/app/jaws/plugin/cgi/http_plugin.h b/app/jaws/plugin/cgi/http_plugin.h new file mode 100644 index 000000000..325347002 --- /dev/null +++ b/app/jaws/plugin/cgi/http_plugin.h @@ -0,0 +1,108 @@ +#ifndef __HTTP_PLUGIN_INCLUDE_H__ +#define __HTTP_PLUGIN_INCLUDE_H__ + +#include "lib_acl.h" +#include "lib_protocol.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * HTTP 初始化注册函数, 该函数如果非空,则由主程序在刚开始运行时调用 + * @param dll_env {ACL_DLL_ENV*} DLL 环境变量, dll_env->logfp 日志文件句柄, + * 如果不希望将日志记在主程序日志文件中,则可以将此值置空 + * @param dmptr {ACL_DEBUG_MEM*} 用于内存调试的句柄 + * @param cfg_dir {const char*} 配置文件所在路径,该路径下存放所有动态库的配置文件 + */ +void http_plugin_init(ACL_DLL_ENV *dll_env, const char *cfg_dir); + +/** + * HTTP 请求过滤注册函数,该函数如果非空,则由主程序在收到HTTP请求头时调用 + * @param client {ACL_VSTREAM*} 客户端流 + * @param hdr_req {HTTP_HDR_REQ*} HTTP请求头 + * @param ctx_ptr {void**} 该指针可以用来存储用户的动态数据 + * @return {int} < 0: 表示禁止该HTTP请求, 该值表示错误号,可以为:-5xx/-4xx; + * 0: 表示该HTTP请求继续由主程序处理; > 0: 表示该HTTP请求可以由外挂模块的单独 + * 线程处理 + */ +int http_request_filter(ACL_VSTREAM *client, HTTP_HDR_REQ *hdr_req, void **ctx_ptr); + +/** + * HTTP 请求接管处理注册函数,该函数如果非空,且 http_request_filter() > 0,则由 + * 主程序调用此函数完全接管该HTTP请求及响应,主程序不再处理该HTTP请求及HTTP响应 + * @param client {ACL_VSTREAM*} HTTP客户端数据连接流 + * @param hdr_req {HTTP_HDR_REQ*} 客户端HTTP请求头 + * @param ctx {void*} 过滤器的参数,该动态参数是由 http_request_filter 中的 ctx_ptr + * 参数返回的 + */ +void http_request_forward(ACL_VSTREAM *client, HTTP_HDR_REQ *hdr_req, void *ctx); + +/*----------------------------------------------------------------------------*/ + +#define DEBUG_BASE 500 +#define DBG_REQ (DEBUG_BASE + 1) +#define DBG_RES (DEBUG_BASE + 2) + +#define STR acl_vstring_str +#define LEN ACL_VSTRING_LEN + +typedef struct { + char *alias; + char *cgi; + HTTP_HDR_REQ *hdr_req; + HTTP_REQ *req; + HTTP_HDR_RES *hdr_res; + ACL_VSTREAM *client; +} CGI; + +/* 全局配置变量 */ + +extern char *var_cfg_log_name; +extern char *var_cfg_cgi_bin; +extern int var_cfg_data_clone; + +/* in http_conf.c */ + +/** + * 加载配置文件 + * @param cfg_dir {const char*} 配置文件所在的目录位置 + */ +void http_conf_load(const char *cfg_dir); + +/* in http_plugin.c */ + +/** + * 创建半难留线程池 + * @param threads_limit {int} 线程池中最大线程个数 + * @param threads_idle {int} 线程程中每个线程的最大空闲时间(秒) + */ +void http_plugin_pool_create(int threads_limit, int threads_idle); + +/** + * 向线程池中添加任务,用户添加的任务由线程池中的某个线程接管 + * @param start_routine {void (*)(void*)} 用户添加的任务回调函数 + * @param arg {void*} 线程池中的某个线程回调 start_routine 时的回调参数 + */ +void http_plugin_pool_append(void (*start_routine)(void *), void *arg); + +/** + * 当需要调试内存分配状态时的函数 + * @param level {int} 调试级别,可用的级别为: 1, 2, 3 + */ +void http_plugin_debug_memory(int level); + +/* in http_cgi.c */ + +void http_cgi_init(void); +void http_cgi_end(void); +void http_cgi_add2(const char *alias, const char *cgi); +void http_cgi_add1(const ACL_ARGV *args); +CGI *http_cgi_path(const char *alias); +void http_cgi_thread(void *ctx); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/app/jaws/plugin/cgi/http_req_filter.c b/app/jaws/plugin/cgi/http_req_filter.c new file mode 100644 index 000000000..778c36360 --- /dev/null +++ b/app/jaws/plugin/cgi/http_req_filter.c @@ -0,0 +1,35 @@ +#include "lib_acl.h" +#include "lib_protocol.h" +#include "http_plugin.h" + +int http_request_filter(ACL_VSTREAM *client acl_unused, + HTTP_HDR_REQ *hdr_req, void **ctx_ptr) +{ + const char *url_path = http_hdr_req_url_path(hdr_req); + CGI *cgi; + + /* + acl_msg_info("%s(%d): be called now", __FUNCTION__, __LINE__); + if (__logfp) + http_hdr_fprint(__logfp, &hdr_req->hdr, "http_request_filter"); + */ + + if (url_path == NULL) + return (0); + + cgi = http_cgi_path(url_path); + if (cgi == NULL) + return (0); + + *ctx_ptr = cgi; + return (1); +} + +void http_request_forward(ACL_VSTREAM *client, HTTP_HDR_REQ *hdr_req, void *ctx) +{ + CGI *cgi = (CGI*) ctx; + + cgi->client = client; + cgi->hdr_req = hdr_req; + http_plugin_pool_append(http_cgi_thread, cgi); +} diff --git a/app/jaws/plugin/gbfilter/Makefile b/app/jaws/plugin/gbfilter/Makefile new file mode 100644 index 000000000..a87f0c7a1 --- /dev/null +++ b/app/jaws/plugin/gbfilter/Makefile @@ -0,0 +1,117 @@ +SHELL = /bin/sh +CC = gcc +#CC = g++ +AR = ar +ARFL = rv +RANLIB = ranlib + +CFLAGS = -c -g -W -Wall -Wcast-align \ +-Waggregate-return -Wmissing-prototypes \ +-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO \ +-Wno-long-long \ +-Wpointer-arith -Werror -Wshadow -pedantic -O2 \ +-fPIC -DPIC +#-Wcast-qual +########################################################### +#Check system: +# Linux, SunOS, Solaris, BSD variants, AIX, HP-UX +SYSLIB = -ldl +RPATH = + +CHECKSYSRES = @echo "Unknow system type!";exit 1 +UNIXNAME = $(shell uname -sm) +OSTYPE = $(shell uname -p) + +#Path for Linux +ifeq ($(findstring Linux, $(UNIXNAME)), Linux) +# ifeq ($CC, "gcc") + ifeq ($(findstring i686, $(OSTYPE)), i686) + RPATH = linux32 + endif + ifeq ($(findstring x86_64, $(OSTYPE)), x86_64) + RPATH = linux64 + endif + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DLINUX2 + SYSLIB += -lcrypt -lpthread +endif + +#Path for SunOS +ifeq ($(findstring SunOS, $(UNIXNAME)), SunOS) + ifeq ($(findstring i386, $(OSTYPE)), i386) + RPATH = sunos_x86 + endif + ifeq ($(findstring 86, $(UNIXNAME)), 86) + SYSLIB += -lsocket -lnsl -lrt + endif + ifeq ($(findstring sun4u, $(UNIXNAME)), sun4u) + SYSLIB += -lsocket -lnsl -lrt + endif +# ifeq ($CC, "gcc") + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DSUNOS5 +endif + +#Path for HP-UX +ifeq ($(findstring HP-UX, $(UNIXNAME)), HP-UX) +# ifeq ($CC, "gcc") + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + SYSLIB += -lpthread + CFLAGS += -DHP_UX -DHPUX11 + PLAT_NAME=hp-ux +endif + +#Find system type. +ifneq ($(SYSPATH),) + CHECKSYSRES = @echo "System is $(shell uname -sm)" +endif +########################################################### +ACL_PATH = ../../../../lib_acl +ACL_LIB = $(ACL_PATH)/lib +ACL_INC = $(ACL_PATH)/include + +PROTO_PATH = ../../../../lib_protocol +PROTO_LIB = $(PROTO_PATH)/lib +PROTO_INC = $(PROTO_PATH)/include + +ALL_LIBS = -L$(PROTO_LIB) -l_protocol -L$(ACL_LIB) -l_acl $(SYSLIB) + +INCLUDE = -I$(PROTO_INC) -I$(ACL_INC) +CFLAGS += $(INCLUDE) -DHAVE_NO_STRCASESTR + +OBJ_OUTPATH = ./debug + +#Project's objs +SOURCES = $(wildcard *.c) +OBJS = $(patsubst %.c, $(OBJ_OUTPATH)/%.o, $(notdir $(SOURCES))) + +########################################################### +LIB_NAME = gbfilter.so + +.PHONY = RM all clean +COMPILE = $(CC) $(CFLAGS) + +all: RM $(LIB_NAME) + +RM: + rm -f $(LIB_NAME) + +$(LIB_NAME): $(OBJS) + $(CC) -shared -o $(LIB_NAME) $(OBJS) $(ALL_LIBS) + cp -f $(LIB_NAME) ../../dist/unix_setup/plugin/$(RPATH)/ +# $(CC) -shared -o $(LIB_NAME) $(OBJS) + +$(OBJ_OUTPATH)/%.o: ./%.c + $(COMPILE) -o $@ $< + +clean: + rm -f $(OBJS) $(LIB_NAME) + rm -f $(LIB_NAME) ../../dist/unix_setup/plugin/$(RPATH)/$(LIB_NAME) + +rebuild: clean all diff --git a/app/jaws/plugin/gbfilter/debug/BuildLog.htm b/app/jaws/plugin/gbfilter/debug/BuildLog.htm new file mode 100644 index 000000000..16974ac7f --- /dev/null +++ b/app/jaws/plugin/gbfilter/debug/BuildLog.htm @@ -0,0 +1,47 @@ + + + + + +
+
+生成日志 +
  
+

------- 已启动生成: 项目: gbfilter,配置: Debug|Win32 ------- +

+
+命令行 +
  
正在创建临时文件“d:\工作目录\项目管理\jaws\jaws\plugin\gbfilter\Debug\RSP0000A7.rsp”,其内容为
+[
+/Od /I "..\..\include\protocol" /I "..\..\include\acl" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_USRDLL" /D "GBFILTER_EXPORTS" /D "_WINDLL" /D "_MBCS" /Gm /EHsc /RTC1 /MDd /Fo"Debug/" /Fd"Debug/vc70.pdb" /W3 /c /Wp64 /ZI /TC
+.\http_conf.c
+.\http_res_filter.c
+.\http_req_filter.c
+.\http_plugin.c
+]
+正在创建命令行“cl.exe @d:\工作目录\项目管理\jaws\jaws\plugin\gbfilter\Debug\RSP0000A7.rsp /nologo”
+正在创建临时文件“d:\工作目录\项目管理\jaws\jaws\plugin\gbfilter\Debug\RSP0000A8.rsp”,其内容为
+[
+/OUT:"Debug/gbfilter.dll" /INCREMENTAL /NOLOGO /LIBPATH:"..\..\lib\win32" /DLL /DEBUG /PDB:"Debug/gbfilter.pdb" /SUBSYSTEM:WINDOWS /IMPLIB:"Debug/gbfilter.lib" /MACHINE:X86 lib_protocol_d.lib lib_acl_d.lib ws2_32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib
+.\debug\http_plugin.obj
+.\debug\http_req_filter.obj
+.\debug\http_res_filter.obj
+.\debug\http_conf.obj
+]
+正在创建命令行“link.exe @d:\工作目录\项目管理\jaws\jaws\plugin\gbfilter\Debug\RSP0000A8.rsp”
+
+输出窗口 +
  
正在编译...
+http_conf.c
+http_res_filter.c
+http_req_filter.c
+http_plugin.c
+正在生成代码...
+正在链接...
+LINK : fatal error LNK1104: 无法打开文件“lib_protocol_d.lib”
+
+结果 +
  
+生成日志保存在“file://d:\工作目录\项目管理\jaws\jaws\plugin\gbfilter\Debug\BuildLog.htm”中
+gbfilter - 1 错误,0 警告
+
\ No newline at end of file diff --git a/app/jaws/plugin/gbfilter/gbfilter.cf b/app/jaws/plugin/gbfilter/gbfilter.cf new file mode 100644 index 000000000..b39573416 --- /dev/null +++ b/app/jaws/plugin/gbfilter/gbfilter.cf @@ -0,0 +1,6 @@ +# configure + +service gbfilter { + logpath = /opt/jaws/var/log/gbfilter.log + data_clone = 0 +} diff --git a/app/jaws/plugin/gbfilter/gbfilter.vcproj b/app/jaws/plugin/gbfilter/gbfilter.vcproj new file mode 100644 index 000000000..d573b60d1 --- /dev/null +++ b/app/jaws/plugin/gbfilter/gbfilter.vcproj @@ -0,0 +1,161 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/jaws/plugin/gbfilter/http_conf.c b/app/jaws/plugin/gbfilter/http_conf.c new file mode 100644 index 000000000..e5a0309ce --- /dev/null +++ b/app/jaws/plugin/gbfilter/http_conf.c @@ -0,0 +1,59 @@ +#include "lib_acl.h" +#include "http_plugin.h" + +char *var_cfg_log_name; + +static ACL_CFG_STR_TABLE __conf_str_tab[] = { + /* 配置项名称, 配置项缺省值, 存储配置项值的地址 */ + { "logpath", "/tmp/gbfilter.log", &var_cfg_log_name }, + { 0, 0, 0 } +}; + +int var_cfg_data_clone; +int var_cfg_rewrite_enable; +static int var_cfg_debug_mem; + +static ACL_CFG_BOOL_TABLE __conf_bool_tab[] = { + /* 配置项名称, 配置项缺省值, 存储配置项值的地址 */ + { "data_clone", 0, &var_cfg_data_clone }, + { "debug_mem", 0, &var_cfg_debug_mem }, + { "rewrite_enable", 1, &var_cfg_rewrite_enable }, + { 0, 0 , 0 } +}; + +static int var_cfg_threads_limit; +static int var_cfg_threads_idle; + +static ACL_CFG_INT_TABLE __conf_int_tab[] = { + /* 配置项名称, 配置项缺省值, 存储配置项值的地址 */ + { "threads_limit", 100, &var_cfg_threads_limit, 0, 0 }, + { "threads_idle", 120, &var_cfg_threads_idle, 0, 0 }, + { 0, 0 , 0, 0, 0 } +}; + +void http_conf_load(const char *cfg_dir) +{ + char *filepath; + ACL_XINETD_CFG_PARSER *cfg; + + /* 读取配置文件 */ + + filepath = acl_concatenate((cfg_dir && *cfg_dir) + ? cfg_dir : "/tmp", "/http_gb.cf", NULL); + cfg = acl_xinetd_cfg_load(filepath); + if (cfg == NULL) + acl_msg_warn("load cfg(%s) error(%s)", + filepath, acl_last_serror()); + + acl_xinetd_params_str_table(cfg, __conf_str_tab); + acl_xinetd_params_int_table(cfg, __conf_int_tab); + acl_xinetd_params_bool_table(cfg, __conf_bool_tab); + + if (cfg) + acl_xinetd_cfg_free(cfg); + acl_myfree(filepath); + + /* 创建线程池 */ + + http_plugin_pool_create(var_cfg_threads_limit, var_cfg_threads_idle); +} diff --git a/app/jaws/plugin/gbfilter/http_plugin.c b/app/jaws/plugin/gbfilter/http_plugin.c new file mode 100644 index 000000000..bb5f74a1d --- /dev/null +++ b/app/jaws/plugin/gbfilter/http_plugin.c @@ -0,0 +1,72 @@ +#include "lib_acl.h" +#include "http_plugin.h" + +static ACL_DLL_ENV __dll_env; +static acl_pthread_pool_t *__thrpool = NULL; + +/* 初始化该插件的环境 */ + +static void plugin_init(ACL_DLL_ENV *dll_env) +{ + if (dll_env) + memcpy(&__dll_env, dll_env, sizeof(ACL_DLL_ENV)); + else + memset(&__dll_env, 0, sizeof(ACL_DLL_ENV)); + if (__dll_env.logfp) { + acl_msg_open2(__dll_env.logfp, "http-gb"); + acl_msg_info("%s(%d): logger opened, %s", __FUNCTION__, + __LINE__, ACL_VSTREAM_PATH(__dll_env.logfp)); + } + + /* 如果 mem_slice 非空则设置内存分配采用切片分配方式 */ + if (__dll_env.mem_slice) + acl_mem_slice_set(__dll_env.mem_slice); +} + +void http_plugin_init(ACL_DLL_ENV *dll_env, const char *cfg_dir) +{ + plugin_init(dll_env); + http_conf_load(cfg_dir); +} + +void http_plugin_pool_create(int threads_limit, int threads_idle) +{ + const char *myname = "http_plugin_pool_create"; + + if (__thrpool != NULL) { + acl_msg_error("%s(%d): thread pool has been created!", + myname, __LINE__); + return; + } + /* 创建线程池 */ + __thrpool = acl_thread_pool_create(threads_limit, threads_idle); +} + +void http_plugin_pool_append(void (*start_routine)(void *), void *arg) +{ + acl_pthread_pool_add(__thrpool, start_routine, arg); +} + +void http_plugin_debug_memory(int level) +{ + /* 是否调试插件的内存分配情况 */ + + switch (level) { + case 1: + acl_memory_debug_start(); + acl_memory_debug_stack(1); + break; + case 2: + __dll_env.mmd = acl_debug_malloc_init(__dll_env.mmd, + "access_log.txt"); + break; + case 3: + __dll_env.mmd = acl_debug_malloc_init(__dll_env.mmd, + "access_log.txt"); + acl_memory_debug_start(); + acl_memory_debug_stack(1); + break; + default: + break; + } +} diff --git a/app/jaws/plugin/gbfilter/http_plugin.h b/app/jaws/plugin/gbfilter/http_plugin.h new file mode 100644 index 000000000..300f613a5 --- /dev/null +++ b/app/jaws/plugin/gbfilter/http_plugin.h @@ -0,0 +1,146 @@ +#ifndef __HTTP_PLUGIN_INCLUDE_H__ +#define __HTTP_PLUGIN_INCLUDE_H__ + +#include "lib_acl.h" +#include "lib_protocol.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _USRDLL +# ifdef GBFILTER_EXPORTS +# define HTTP_PLUGIN_API __declspec(dllexport) +# else +# define HTTP_PLUGIN_API __declspec(dllimport) +# endif +#else +# define HTTP_PLUGIN_API +#endif + +/** + * HTTP 初始化注册函数, 该函数如果非空,则由主程序在刚开始运行时调用 + * @param dll_env {ACL_DLL_ENV*} DLL 环境变量, dll_env->logfp 日志文件句柄, + * 如果不希望将日志记在主程序日志文件中,则可以将此值置空 + * @param cfg_dir {const char*} 配置文件所在路径,该路径下存放所有动态库的配置文件 + */ +HTTP_PLUGIN_API void http_plugin_init(ACL_DLL_ENV *dll_env, const char *cfg_dir); + +/** + * HTTP 请求过滤注册函数,该函数如果非空,则由主程序在收到HTTP请求头时调用 + * @param client {ACL_VSTREAM*} 客户端流 + * @param hdr_req {HTTP_HDR_REQ*} HTTP请求头 + * @param ctx_ptr {void**} 该指针可以用来存储用户的动态数据 + * @return {int} < 0: 表示禁止该HTTP请求, 该值表示错误号,可以为:-5xx/-4xx; + * 0: 表示该HTTP请求继续由主程序处理; > 0: 表示该HTTP请求可以由外挂模块的单独 + * 线程处理 + */ +HTTP_PLUGIN_API int http_request_filter(ACL_VSTREAM *client, HTTP_HDR_REQ *hdr_req, void **ctx_ptr); + +/** + * HTTP 请求接管处理注册函数,该函数如果非空,且 http_request_filter() > 0,则由 + * 主程序调用此函数完全接管该HTTP请求及响应,主程序不再处理该HTTP请求及HTTP响应 + * @param client {ACL_VSTREAM*} HTTP客户端数据连接流 + * @param hdr_req {HTTP_HDR_REQ*} 客户端HTTP请求头 + * @param ctx {void*} 过滤器的参数,该动态参数是由 http_request_filter 中的 ctx_ptr + * 参数返回的 + */ +HTTP_PLUGIN_API void http_request_forward(ACL_VSTREAM *client, HTTP_HDR_REQ *hdr_req, void *ctx); + +/** + * HTTP 响应过滤注册函数,该函数如果非空,则由主程序在收到HTTP响应头时调用 + * @param client {ACL_VSTREAM*} HTTP客户端数据连接流 + * @param server {ACL_VSTREAM*} HTTP服务端数据连接流 + * @param hdr_req {HTTP_HDR_REQ*} HTTP请求头 + * @param hdr_res {HTTP_HDR_RES*} HTTP响应头 + * @param ctx_ptr {void**} 该指针可以用来存储用户的动态数据 + * @return {int} 0: 表示该HTTP响应继续由主程序处理; !0: 表示该HTTP响应可以由外 + * 挂模块的单独线程处理 + */ +HTTP_PLUGIN_API int http_respond_filter(ACL_VSTREAM *client, ACL_VSTREAM *server, + HTTP_HDR_REQ *hdr_req, HTTP_HDR_RES *hdr_res, void **ctx_ptr); + +/** + * HTTP 响应接管处理注册函数,该函数如果非空,且 http_respond_filter() > 0, 则由 + * 主程序调用此函数完全接管该HTTP响应处理过程,主程序不再处理该HTTP请求及HTTP响应 + * @param client {ACL_VSTREAM*} HTTP客户端数据连接流 + * @param server {ACL_VSTREAM*} HTTP服务端数据连接流 + * @param hdr_req {HTTP_HDR_REQ*} 客户端HTTP请求头 + * @param hdr_res {HTTP_HDR_RES*} 服务端HTTP响应头 + * @param ctx {void*} 过滤器的参数,该动态参数是由 http_respond_filter 中的 ctx_ptr + * 参数返回的 + */ +HTTP_PLUGIN_API void http_respond_forward(ACL_VSTREAM *client, ACL_VSTREAM *server, + HTTP_HDR_REQ *hdr_req, HTTP_HDR_RES *hdr_res, void *ctx); + +/** + * HTTP 响应数据体过滤注册函数,可以将源数据转换为目标数据 + * @param data {const char*} 源数据 + * @param dlen {int} data 长度 + * @param ret {int*} 返回新数据的长度, < 0 表示出错 + * @param stop {int*} 禁止下一个过滤器处理过程 + * @param ctx {void*} 过滤器的参数,该动态参数是由 http_respond_filter 中的 ctx_ptr + * 参数返回的 + * @return {char*} 新数据, 若为空则表示当前数据暂不可用 + */ +HTTP_PLUGIN_API char *http_respond_dat_filter(const char *data, int dlen, + int *ret, int *stop, void *ctx); + +/** + * 释放由 http_respond_dat_filter 产生的动态数据的注册函数 + * @param buf {void*} 新的动态数据地址 + * @param ctx {void*} 过滤器的参数,该动态参数是由 http_respond_filter 中的 ctx_ptr + * 参数返回的 + */ +HTTP_PLUGIN_API void http_respond_dat_free(void *buf, void *ctx); + +/*---------------------------------------------------------------------------*/ + +#define DEBUG_BASE 500 +#define DBG_REQ (DEBUG_BASE + 1) +#define DBG_RES (DEBUG_BASE + 2) + +#define STR acl_vstring_str +#define LEN ACL_VSTRING_LEN + +/* 全局配置变量 */ + +extern char *var_cfg_log_name; +extern int var_cfg_data_clone; +extern int var_cfg_rewrite_enable; + +/* in http_conf.c */ + +/** + * 加载配置文件 + * @param cfg_dir {const char*} 配置文件所在的目录位置 + */ +void http_conf_load(const char *cfg_dir); + +/* in http_plugin.c */ + +/** + * 创建半难留线程池 + * @param threads_limit {int} 线程池中最大线程个数 + * @param threads_idle {int} 线程程中每个线程的最大空闲时间(秒) + */ +void http_plugin_pool_create(int threads_limit, int threads_idle); + +/** + * 向线程池中添加任务,用户添加的任务由线程池中的某个线程接管 + * @param start_routine {void (*)(void*)} 用户添加的任务回调函数 + * @param arg {void*} 线程池中的某个线程回调 start_routine 时的回调参数 + */ +void http_plugin_pool_append(void (*start_routine)(void *), void *arg); + +/** + * 当需要调试内存分配状态时的函数 + * @param level {int} 调试级别,可用的级别为: 1, 2, 3 + */ +void http_plugin_debug_memory(int level); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/app/jaws/plugin/gbfilter/http_req_filter.c b/app/jaws/plugin/gbfilter/http_req_filter.c new file mode 100644 index 000000000..3998a41fe --- /dev/null +++ b/app/jaws/plugin/gbfilter/http_req_filter.c @@ -0,0 +1,23 @@ +#include "lib_acl.h" +#include "lib_protocol.h" +#include "http_plugin.h" + +int http_request_filter(ACL_VSTREAM *client acl_unused, HTTP_HDR_REQ *hdr_req acl_unused, void **ctx_ptr acl_unused) +{ + /* + acl_msg_info("%s(%d): be called now", __FUNCTION__, __LINE__); + if (__logfp) + http_hdr_fprint(__logfp, &hdr_req->hdr, "http_request_filter"); + */ + + /* 关闭压缩请求 */ + http_hdr_entry_off(&hdr_req->hdr, "Accept-Encoding"); + return (0); +} + +void http_request_forward(ACL_VSTREAM *client, HTTP_HDR_REQ *hdr_req, void *ctx) +{ + (void) client; + (void) hdr_req; + (void) ctx; +} diff --git a/app/jaws/plugin/gbfilter/http_res_filter.c b/app/jaws/plugin/gbfilter/http_res_filter.c new file mode 100644 index 000000000..927ed44ac --- /dev/null +++ b/app/jaws/plugin/gbfilter/http_res_filter.c @@ -0,0 +1,199 @@ +#include "lib_acl.h" +#include +#include "lib_protocol.h" +#include "http_plugin.h" + +typedef struct { + ACL_VSTREAM *client; + ACL_VSTREAM *server; + HTTP_HDR_REQ *hdr_req; + HTTP_HDR_RES *hdr_res; + HTTP_RES *res; + void *ctx; +} FWD_RES; + +int http_respond_filter(ACL_VSTREAM *client acl_unused, ACL_VSTREAM *server acl_unused, + HTTP_HDR_REQ *hdr_req acl_unused, HTTP_HDR_RES *hdr_res, + void **ctx_ptr acl_unused) +{ + char *ptr; + + if (var_cfg_data_clone) + return (0); + + ptr = http_hdr_entry_value(&hdr_res->hdr, "Content-Encoding"); + if (ptr) { + if (acl_strcasestr(ptr, "gzip") != 0) + acl_msg_info("%s(%d)", __FUNCTION__, __LINE__); + else if (acl_strcasestr(ptr, "deflate") != 0) + return (0); + } + + ptr = http_hdr_entry_value(&hdr_res->hdr, "Content-Type"); + if (ptr == NULL) + return (0); + + /* acl_strcasestr(ptr, "javascript") == 0) */ + if (acl_strcasestr(ptr, "text/html") == 0) + return (0); + + return (1); +} + +static void forward_free(FWD_RES *fwd) +{ + acl_vstream_close(fwd->client); + acl_vstream_close(fwd->server); + http_hdr_req_free(fwd->hdr_req); + http_hdr_res_free(fwd->hdr_res); + if (fwd->res) { + fwd->res->hdr_res = NULL; /* 防止 hdr_res 被重复释放 */ + http_res_free(fwd->res); + } + acl_myfree(fwd); +} + +static void forward_thread(void *ctx) +{ + FWD_RES *fwd = (FWD_RES*) ctx; + ACL_VSTRING *vbuf = acl_vstring_alloc(8192); + int ret; + char buf[8192]; + + http_hdr_entry_off(&fwd->hdr_res->hdr, "Content-Length"); + http_hdr_entry_off(&fwd->hdr_res->hdr, "Transfer-Encoding"); + + http_hdr_build(&fwd->hdr_res->hdr, vbuf); + ret = acl_vstream_writen(fwd->client, STR(vbuf), LEN(vbuf)); + if (ret == ACL_VSTREAM_EOF) { + acl_debug(DBG_RES, 2) ("%s(%d): write hdr to client error(%s)", + __FUNCTION__, __LINE__, acl_last_serror()); + forward_free(fwd); + acl_vstring_free(vbuf); + return; + } + + ACL_VSTRING_RESET(vbuf); + fwd->res = http_res_new(fwd->hdr_res); + while (1) { + ret = (int) http_res_body_get_sync(fwd->res, fwd->server, + buf, sizeof(buf) - 1); + if (ret <= 0) + break; + acl_vstring_strncat(vbuf, buf, ret); + + ret = acl_vstream_writen(fwd->client, buf, ret); + if (ret == ACL_VSTREAM_EOF) + acl_debug(DBG_RES, 2) ("%s(%d): write to client error(%s)", + __FUNCTION__, __LINE__, acl_last_serror()); + } + + forward_free(fwd); + acl_vstring_free(vbuf); +} + +static void forward_rewrite_thread(void *ctx) +{ + FWD_RES *fwd = (FWD_RES*) ctx; + ACL_VSTRING *vbuf = acl_vstring_alloc(102400); + int ret; + char buf[8192]; + + http_hdr_entry_off(&fwd->hdr_res->hdr, "Content-Length"); + http_hdr_entry_off(&fwd->hdr_res->hdr, "Transfer-Encoding"); + + http_hdr_build(&fwd->hdr_res->hdr, vbuf); + ret = acl_vstream_writen(fwd->client, STR(vbuf), LEN(vbuf)); + if (ret == ACL_VSTREAM_EOF) { + acl_debug(DBG_RES, 2) ("%s(%d): write hdr to client error(%s)", + __FUNCTION__, __LINE__, acl_last_serror()); + forward_free(fwd); + acl_vstring_free(vbuf); + return; + } + + ACL_VSTRING_RESET(vbuf); + fwd->res = http_res_new(fwd->hdr_res); + + while (1) { + ret = (int) http_res_body_get_sync(fwd->res, fwd->server, + buf, sizeof(buf) - 1); + if (ret <= 0) + break; + acl_vstring_strncat(vbuf, buf, ret); + } + + ACL_VSTRING_TERMINATE(vbuf); + + /* 简体转繁体 */ + acl_gbjt2ft(STR(vbuf), LEN(vbuf), STR(vbuf), LEN(vbuf)); + + ret = acl_vstream_writen(fwd->client, STR(vbuf), LEN(vbuf)); + if (ret == ACL_VSTREAM_EOF) + acl_debug(DBG_RES, 2) ("%s(%d): write to client error(%s)", + __FUNCTION__, __LINE__, acl_last_serror()); + + forward_free(fwd); + acl_vstring_free(vbuf); +} + +void http_respond_forward(ACL_VSTREAM *client, ACL_VSTREAM *server, + HTTP_HDR_REQ *hdr_req, HTTP_HDR_RES *hdr_res, void *ctx) +{ + FWD_RES *fwd = (FWD_RES*) acl_mycalloc(1, sizeof(FWD_RES)); + + fwd->client = client; + fwd->server = server; + fwd->hdr_req = hdr_req; + fwd->hdr_res = hdr_res; + fwd->ctx = ctx; + + if (var_cfg_rewrite_enable) + http_plugin_pool_append(forward_rewrite_thread, fwd); + else + http_plugin_pool_append(forward_thread, fwd); +} + +char *http_respond_dat_filter(const char *data, int dlen, + int *ret, int *stop, void *ctx acl_unused) +{ + const char *filename = var_cfg_log_name; + static ACL_FILE *fp = NULL; + int n; + + if (!var_cfg_data_clone) { + *stop = 1; + *ret = dlen; + return ((char*) data); + } + + if (fp == NULL) { + fp = acl_fopen(filename, "a"); + if (fp == NULL) { + acl_msg_error("open %s error(%s)", + filename, acl_last_serror()); + *stop = 1; + *ret = dlen; + return ((char*) data); + } + } + + n = (int) acl_fwrite(data, dlen, 1, fp); + if (n == EOF) { + acl_msg_error("write to %s error(%s)", + filename, acl_last_serror()); + *stop = 1; + return ((char*) data); + } + + *stop = 0; + *ret = dlen; + return ((char*) data); +} + +void http_respond_dat_free(void *buf, void *ctx acl_unused) +{ + if (!var_cfg_data_clone) + return; + acl_myfree(buf); +} diff --git a/app/jaws/plugin/gbfilter/release/BuildLog.htm b/app/jaws/plugin/gbfilter/release/BuildLog.htm new file mode 100644 index 000000000..839b0972e --- /dev/null +++ b/app/jaws/plugin/gbfilter/release/BuildLog.htm @@ -0,0 +1,61 @@ + + + + + +
+
+生成日志 +
  
+

------- 已启动生成: 项目: gbfilter,配置: Release|Win32 ------- +

+
+命令行 +
  
正在创建临时文件“d:\工作目录\项目管理\jaws\jaws\plugin\gbfilter\Release\RSP00000C.rsp”,其内容为
+[
+/O2 /I "..\..\include\protocol" /I "..\..\include\acl" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_USRDLL" /D "GBFILTER_EXPORTS" /D "_WINDLL" /D "_MBCS" /FD /EHsc /MD /GS /Fo"Release/" /Fd"Release/vc70.pdb" /W3 /c /Wp64 /Zi /TC
+.\http_res_filter.c
+.\http_req_filter.c
+.\http_plugin.c
+.\http_conf.c
+]
+正在创建命令行“cl.exe @d:\工作目录\项目管理\jaws\jaws\plugin\gbfilter\Release\RSP00000C.rsp /nologo”
+正在创建临时文件“d:\工作目录\项目管理\jaws\jaws\plugin\gbfilter\Release\RSP00000D.rsp”,其内容为
+[
+/OUT:"Release/gbfilter.dll" /INCREMENTAL:NO /NOLOGO /LIBPATH:"..\..\lib\win32" /DLL /SUBSYSTEM:WINDOWS /OPT:REF /OPT:ICF /IMPLIB:"Release/gbfilter.lib" /MACHINE:X86 lib_protocol.lib lib_acl.lib ws2_32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib
+.\release\http_conf.obj
+.\release\http_plugin.obj
+.\release\http_req_filter.obj
+.\release\http_res_filter.obj
+]
+正在创建命令行“link.exe @d:\工作目录\项目管理\jaws\jaws\plugin\gbfilter\Release\RSP00000D.rsp”
+正在创建临时文件“d:\工作目录\项目管理\jaws\jaws\plugin\gbfilter\Release\BAT00000E.bat”,其内容为
+[
+@echo off
+copy Release\gbfilter.dll ..\..\build\gbfilter.dll  /Y
+if errorlevel 1 goto VCReportError
+goto VCEnd
+:VCReportError
+echo Project : error PRJ0019: 工具从"正在执行生成后事件..."
+exit 1
+:VCEnd
+]
+正在创建命令行“d:\工作目录\项目管理\jaws\jaws\plugin\gbfilter\Release\BAT00000E.bat”
+
+输出窗口 +
  
正在编译...
+http_res_filter.c
+http_req_filter.c
+http_plugin.c
+http_conf.c
+正在生成代码...
+正在链接...
+   正在创建库 Release/gbfilter.lib 和对象 Release/gbfilter.exp
+正在执行生成后事件...
+已复制         1 个文件。
+
+结果 +
  
+生成日志保存在“file://d:\工作目录\项目管理\jaws\jaws\plugin\gbfilter\Release\BuildLog.htm”中
+gbfilter - 0 错误,0 警告
+
\ No newline at end of file diff --git a/app/jaws/plugin/http_access/Makefile b/app/jaws/plugin/http_access/Makefile new file mode 100644 index 000000000..94cc26076 --- /dev/null +++ b/app/jaws/plugin/http_access/Makefile @@ -0,0 +1,124 @@ +SHELL = /bin/sh +CC = gcc +#CC = g++ +AR = ar +ARFL = rv +RANLIB = ranlib + +CFLAGS = -c -g -W -Wall -Wcast-align \ +-Waggregate-return -Wmissing-prototypes \ +-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO \ +-Wno-long-long \ +-Wpointer-arith -Werror -Wshadow -pedantic -O2 \ +-fPIC -DPIC +#-Wcast-qual +########################################################### +#Check system: +# Linux, SunOS, Solaris, BSD variants, AIX, HP-UX +SYSLIB = -ldl +RPATH = + +CHECKSYSRES = @echo "Unknow system type!";exit 1 +UNIXNAME = $(shell uname -sm) +OSTYPE = $(shell uname -p) + +#Path for Linux +ifeq ($(findstring Linux, $(UNIXNAME)), Linux) +# ifeq ($CC, "gcc") + ifeq ($(findstring i686, $(OSTYPE)), i686) + RPATH = linux32 + endif + ifeq ($(findstring x86_64, $(OSTYPE)), x86_64) + RPATH = linux64 + endif + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DLINUX2 + SYSLIB += -lcrypt -lpthread +endif + +#Path for SunOS +ifeq ($(findstring SunOS, $(UNIXNAME)), SunOS) + ifeq ($(findstring i386, $(OSTYPE)), i386) + RPATH = sunos_x86 + endif + ifeq ($(findstring 86, $(UNIXNAME)), 86) + SYSLIB += -lsocket -lnsl -lrt + endif + ifeq ($(findstring sun4u, $(UNIXNAME)), sun4u) + SYSLIB += -lsocket -lnsl -lrt + endif +# ifeq ($CC, "gcc") + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DSUNOS5 +endif + +#Path for HP-UX +ifeq ($(findstring HP-UX, $(UNIXNAME)), HP-UX) +# ifeq ($CC, "gcc") + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + SYSLIB += -lpthread + CFLAGS += -DHP_UX -DHPUX11 + PLAT_NAME=hp-ux +endif + +#Find system type. +ifneq ($(SYSPATH),) + CHECKSYSRES = @echo "System is $(shell uname -sm)" +endif +########################################################### +ACL_PATH = ../../../../lib_acl +ACL_LIB = $(ACL_PATH)/lib +ACL_INC = $(ACL_PATH)/include + +PROTO_PATH = ../../../../lib_protocol +PROTO_LIB = $(PROTO_PATH)/lib +PROTO_INC = $(PROTO_PATH)/include + +GLOBAL_PATH = ../../global +GLOBAL_LIB = $(GLOBAL_PATH) +GLOBAL_INC = $(GLOBAL_PATH) + + +#ALL_LIBS = -L$(GLOBAL_LIB) -l_global -L$(PROTO_LIB) -l_protocol -L$(ACL_LIB) -l_acl $(SYSLIB) +ALL_LIBS = -L$(PROTO_LIB) -l_protocol -L$(ACL_LIB) -l_acl $(SYSLIB) + +#INCLUDE = -I$(GLOBAL_INC) -I$(PROTO_INC) -I$(ACL_INC) +INCLUDE = -I$(PROTO_INC) -I$(ACL_INC) +CFLAGS += $(INCLUDE) -DHAVE_NO_STRCASESTR + +OBJ_OUTPATH = ./debug + +#Project's objs +SOURCES = $(wildcard *.c) +OBJS = $(patsubst %.c, $(OBJ_OUTPATH)/%.o, $(notdir $(SOURCES))) + +########################################################### +LIB_NAME = http_access.so + +.PHONY = RM all clean +COMPILE = $(CC) $(CFLAGS) + +all: RM $(LIB_NAME) + +RM: + rm -f $(LIB_NAME) + +$(LIB_NAME): $(OBJS) + $(CC) -shared -o $(LIB_NAME) $(OBJS) $(ALL_LIBS) + cp -f $(LIB_NAME) ../../dist/unix_setup/plugin/$(RPATH)/ +# $(CC) -shared -o $(LIB_NAME) $(OBJS) + +$(OBJ_OUTPATH)/%.o: ./%.c + $(COMPILE) -o $@ $< + +clean: + rm -f $(OBJS) $(LIB_NAME) + rm -f $(LIB_NAME) ../../dist/unix_setup/plugin/$(RPATH)/$(LIB_NAME) + +rebuild: clean all diff --git a/app/jaws/plugin/http_access/debug/BuildLog.htm b/app/jaws/plugin/http_access/debug/BuildLog.htm new file mode 100644 index 000000000..774e6a8bc --- /dev/null +++ b/app/jaws/plugin/http_access/debug/BuildLog.htm @@ -0,0 +1,47 @@ + + + + + +
+
+生成日志 +
  
+

------- 已启动生成: 项目: http_access,配置: Debug|Win32 ------- +

+
+命令行 +
  
正在创建临时文件“d:\工作目录\项目管理\jaws\jaws\plugin\http_access\Debug\RSP0000A1.rsp”,其内容为
+[
+/Od /I "..\..\include\protocol" /I "..\..\include\acl" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_USRDLL" /D "HTTP_ACCESS_EXPORTS" /D "_WINDLL" /D "_MBCS" /Gm /EHsc /RTC1 /MDd /Fo"Debug/" /Fd"Debug/vc70.pdb" /W3 /c /Wp64 /ZI /TC
+.\http_conf.c
+.\http_req_filter.c
+.\http_plugin.c
+.\http_access.c
+]
+正在创建命令行“cl.exe @d:\工作目录\项目管理\jaws\jaws\plugin\http_access\Debug\RSP0000A1.rsp /nologo”
+正在创建临时文件“d:\工作目录\项目管理\jaws\jaws\plugin\http_access\Debug\RSP0000A2.rsp”,其内容为
+[
+/OUT:"Debug/http_access.dll" /INCREMENTAL /NOLOGO /LIBPATH:"..\..\lib\win32" /DLL /DEBUG /PDB:"Debug/http_access.pdb" /SUBSYSTEM:WINDOWS /IMPLIB:"Debug/http_access.lib" /MACHINE:X86 lib_protocol_d.lib lib_acl_d.lib ws2_32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib
+.\debug\http_access.obj
+.\debug\http_plugin.obj
+.\debug\http_req_filter.obj
+.\debug\http_conf.obj
+]
+正在创建命令行“link.exe @d:\工作目录\项目管理\jaws\jaws\plugin\http_access\Debug\RSP0000A2.rsp”
+
+输出窗口 +
  
正在编译...
+http_conf.c
+http_req_filter.c
+http_plugin.c
+http_access.c
+正在生成代码...
+正在链接...
+LINK : fatal error LNK1104: 无法打开文件“lib_protocol_d.lib”
+
+结果 +
  
+生成日志保存在“file://d:\工作目录\项目管理\jaws\jaws\plugin\http_access\Debug\BuildLog.htm”中
+http_access - 1 错误,0 警告
+
\ No newline at end of file diff --git a/app/jaws/plugin/http_access/html_template.c b/app/jaws/plugin/http_access/html_template.c new file mode 100644 index 000000000..e2a7e9393 --- /dev/null +++ b/app/jaws/plugin/http_access/html_template.c @@ -0,0 +1,61 @@ +#include "html_template.h" + +char HTTP_REPLY_DNS_ERR[] = \ +"HTTP/1.1 503 DNS lookup error\r\n" \ +"Connection: close\r\n" \ +"\r\n" \ +"DNS LOOKUP error\r\n\r\n"; + +char HTTP_REPLY_TIMEOUT[] = \ +"HTTP/1.1 504 webserver respond timeout\r\n" \ +"Connection: close\r\n" \ +"\r\n" \ +"504 webserver respond timeout\r\n"; + +char HTTP_REPLY_ERROR[] = \ +"HTTP/1.1 500 webserver respond error\r\n" \ +"Connection: close\r\n" \ +"\r\n" \ +" 500 webserver respond error\r\n"; + +char HTTP_CONNECT_ERROR[] = \ +"HTTP/1.1 500 connect webserver error\r\n" \ +"Connection: close\r\n" \ +"\r\n" \ +" 500 connect webserver error\r\n"; + +char HTTP_CONNECT_TIMEOUT[] = \ +"HTTP/1.1 504 connect webserver error\r\n" \ +"Connection: close\r\n" \ +"\r\n" \ +" 504 connect webserver timeout\r\n"; + +char HTTP_REQUEST_INVALID[] = \ +"HTTP/1.1 400 client request invalid\r\n" \ +"Connection: close\r\n" \ +"\r\n" \ +" 400 request invalid\r\n"; + +char HTTP_REQUEST_LOOP[] = \ +"HTTP/1.1 403 request loop test forbidden\r\n" \ +"Connection: close\r\n" \ +"\r\n" \ +" 403 forbidden, request loop tested\r\n"; + +char HTTP_REQUEST_DENY[] = \ +"HTTP/1.1 403 request forbidden\r\n" \ +"Connection: close\r\n" \ +"\r\n" \ +" 403 forbidden, request denied\r\n"; + +char HTTP_REQUEST_NOFOUND[] = \ +"HTTP/1.1 404 request url not found\r\n" \ +"Connection: close\r\n" \ +"\r\n" \ +" 404 forbidden, request url not found\r\n"; + +char HTTP_INTERNAL_ERROR[] = \ +"HTTP/1.1 500 internal error\r\n" \ +"Connection: close\r\n" \ +"\r\n" \ +" 500 internal error\r\n"; diff --git a/app/jaws/plugin/http_access/html_template.h b/app/jaws/plugin/http_access/html_template.h new file mode 100644 index 000000000..7b65984ce --- /dev/null +++ b/app/jaws/plugin/http_access/html_template.h @@ -0,0 +1,16 @@ +#ifndef __HTML_TEMPLATE_INCLUDE_H__ +#define __HTML_TEMPLATE_INCLUDE_H__ + +/* in html_template.c */ +extern char HTTP_REPLY_DNS_ERR[]; +extern char HTTP_REPLY_TIMEOUT[]; +extern char HTTP_REPLY_ERROR[]; +extern char HTTP_REQUEST_INVALID[]; +extern char HTTP_REQUEST_LOOP[]; +extern char HTTP_CONNECT_ERROR[]; +extern char HTTP_CONNECT_TIMEOUT[]; +extern char HTTP_REQUEST_DENY[]; +extern char HTTP_REQUEST_NOFOUND[]; +extern char HTTP_INTERNAL_ERROR[]; + +#endif diff --git a/app/jaws/plugin/http_access/http_access.c b/app/jaws/plugin/http_access/http_access.c new file mode 100644 index 000000000..fdb17c3ba --- /dev/null +++ b/app/jaws/plugin/http_access/http_access.c @@ -0,0 +1,101 @@ +#include "lib_acl.h" +#include "http_plugin.h" +#include "http_access.h" + +static ACL_FIFO *__domains_allow; + +typedef struct { + char *domain; + int dlen; + int permit; + int nocase; +} DOMAIN_ACCESS; + +static int domain_correct(const char *domain) +{ + const char *myname = "domain_correct"; + const char *ptr = domain; + int lastch = 0; + + while (*ptr) { + if (!(ACL_ISALNUM(*ptr) || *ptr == '.' || *ptr == '_' || *ptr == '-')) { + acl_msg_warn("%s(%d): domain(%s) invalid, char(%c, %d)", + myname, __LINE__, domain, *ptr, *ptr); + return (0); + } + lastch = *ptr; + ptr++; + } + + if (!((lastch >= 'a' && lastch <= 'z') || (lastch >= 'A' && lastch <= 'Z'))) { + acl_msg_warn("%s(%d): domain(%s) invalid, last char(%c, %d)", + myname, __LINE__, domain, lastch, lastch); + return (0); + } + return (1); +} + +void http_access_init(void) +{ + const char *myname = "http_access_init"; + ACL_ARGV *argv; + ACL_ITER iter; + + __domains_allow = acl_fifo_new(); + + if (!var_cfg_http_domain_allow || !(*var_cfg_http_domain_allow)) + return; + + argv = acl_argv_split(var_cfg_http_domain_allow, " \t,;"); + acl_foreach(iter, argv) { + DOMAIN_ACCESS *dacc; + char *ptr = (char*) iter.data; + char *ptr1, *ptr2; + int permit = 1, nocase = 1; + + ptr1 = strchr(ptr, ':'); + if (ptr1) { + *ptr1++ = 0; + ptr2 = strchr(ptr, ':'); + if (ptr2) { + *ptr2++ = 0; + nocase = atoi(ptr2); + } + permit = atoi(ptr1); + } + if (!domain_correct(ptr)) + continue; + dacc = (DOMAIN_ACCESS*) acl_mycalloc(1, sizeof(DOMAIN_ACCESS)); + dacc->domain = acl_mystrdup(ptr); + dacc->dlen = strlen(dacc->domain); + dacc->permit = permit; + dacc->nocase = nocase; + acl_fifo_push(__domains_allow, dacc); + acl_msg_info("%s: add domain(%s, %s, %s)", + myname, dacc->domain, permit ? "allow" : "deny", + nocase ? "incaseble" : "caseble"); + } + + acl_argv_free(argv); +} + +int http_access_permit(const char *domain) +{ + ACL_ITER iter; + + acl_foreach(iter, __domains_allow) { + DOMAIN_ACCESS *dacc = (DOMAIN_ACCESS*) iter.data; + + if (dacc->nocase) { + if (acl_strrncasecmp(domain, dacc->domain, dacc->dlen) == 0) { + return (dacc->permit); + } + } else { + if (acl_strrncmp(domain, dacc->domain, dacc->dlen) == 0) { + return (dacc->permit); + } + } + } + + return (var_cfg_http_domain_allow_all); +} diff --git a/app/jaws/plugin/http_access/http_access.cf b/app/jaws/plugin/http_access/http_access.cf new file mode 100644 index 000000000..b3406c7c6 --- /dev/null +++ b/app/jaws/plugin/http_access/http_access.cf @@ -0,0 +1,8 @@ +service http_plugin_access { +# 以下域名列表是否允许访问 + http_domain_allow = www.sina.com, sina.com.cn:0 +# 重定向的域名列表 + http_domain_redirect = test.tw=test.com.tw +# 是否允许访问其它所有域名 + http_domain_allow_all = 0 +} diff --git a/app/jaws/plugin/http_access/http_access.h b/app/jaws/plugin/http_access/http_access.h new file mode 100644 index 000000000..17aa87e4e --- /dev/null +++ b/app/jaws/plugin/http_access/http_access.h @@ -0,0 +1,7 @@ +#ifndef __HTTP_ACCESS_INCLUDE_H__ +#define __HTTP_ACCESS_INCLUDE_H__ + +void http_access_init(void); +int http_access_permit(const char *domain); + +#endif diff --git a/app/jaws/plugin/http_access/http_access.vcproj b/app/jaws/plugin/http_access/http_access.vcproj new file mode 100644 index 000000000..fab52beeb --- /dev/null +++ b/app/jaws/plugin/http_access/http_access.vcproj @@ -0,0 +1,173 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/jaws/plugin/http_access/http_plugin.c b/app/jaws/plugin/http_access/http_plugin.c new file mode 100644 index 000000000..f2a95d900 --- /dev/null +++ b/app/jaws/plugin/http_access/http_plugin.c @@ -0,0 +1,81 @@ +#include "lib_acl.h" +#include "http_access.h" +#include "http_redirect.h" +#include "http_plugin.h" + +char *var_cfg_log_name; +char *var_cfg_http_domain_allow; +char *var_cfg_http_domain_redirect; + +static ACL_CFG_STR_TABLE __conf_str_tab[] = { + /* 配置项名称, 配置项缺省值, 存储配置项值的地址 */ + { "logpath", "/tmp/access_filter.log", &var_cfg_log_name }, + { "http_domain_allow", "", &var_cfg_http_domain_allow }, + { "http_domain_redirect", "", &var_cfg_http_domain_redirect }, + { 0, 0, 0 } +}; + +static int var_cfg_debug_mem; +int var_cfg_http_domain_allow_all; + +static ACL_CFG_BOOL_TABLE __conf_bool_tab[] = { + /* 配置项名称, 配置项缺省值, 存储配置项值的地址 */ + { "debug_mem", 0, &var_cfg_debug_mem }, + { "http_domain_allow_all", 1, &var_cfg_http_domain_allow_all }, + { 0, 0 , 0 } +}; + +static ACL_DLL_ENV __dll_env; + +void http_plugin_init(ACL_DLL_ENV *dll_env, const char *cfg_dir) +{ + ACL_XINETD_CFG_PARSER *cfg; + char *filepath; + + if (dll_env) + memcpy(&__dll_env, dll_env, sizeof(ACL_DLL_ENV)); + else + memset(&__dll_env, 0, sizeof(ACL_DLL_ENV)); + + if (__dll_env.logfp) { + acl_msg_open2(__dll_env.logfp, "http-access"); + acl_msg_info("%s(%d): logger opened, %s", __FUNCTION__, + __LINE__, ACL_VSTREAM_PATH(__dll_env.logfp)); + } + + /* 如果 mem_slice 非空则设置内存分配采用切片分配方式 */ + if (__dll_env.mem_slice) + acl_mem_slice_set(__dll_env.mem_slice); + + filepath = acl_concatenate((cfg_dir && *cfg_dir) + ? cfg_dir : "/tmp", "/http_access.cf", NULL); + cfg = acl_xinetd_cfg_load(filepath); + if (cfg == NULL) + acl_msg_warn("load cfg(%s) error(%s)", + filepath, acl_last_serror()); + + acl_xinetd_params_str_table(cfg, __conf_str_tab); + acl_xinetd_params_bool_table(cfg, __conf_bool_tab); + + if (cfg) + acl_xinetd_cfg_free(cfg); + acl_myfree(filepath); + + /* 针对代理模式,初始化访问列表 */ + http_access_init(); + + /* 初始化有关重定向列表 */ + http_redirect_init(); + + /* 是否调试插件的内存分配情况 */ + if (var_cfg_debug_mem == 1) { + acl_memory_debug_start(); + acl_memory_debug_stack(1); + } else if (var_cfg_debug_mem == 2) { + __dll_env.mmd = acl_debug_malloc_init(__dll_env.mmd, "access_log.txt"); + } else if (var_cfg_debug_mem == 3) { + __dll_env.mmd = acl_debug_malloc_init(__dll_env.mmd, "access_log.txt"); + acl_memory_debug_start(); + acl_memory_debug_stack(1); + } +} diff --git a/app/jaws/plugin/http_access/http_plugin.h b/app/jaws/plugin/http_access/http_plugin.h new file mode 100644 index 000000000..b3c07ff49 --- /dev/null +++ b/app/jaws/plugin/http_access/http_plugin.h @@ -0,0 +1,61 @@ +#ifndef __HTTP_PLUGIN_INCLUDE_H__ +#define __HTTP_PLUGIN_INCLUDE_H__ + +#include "lib_acl.h" +#include "lib_protocol.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------- 动态模块需要的函数接口 ---------------------------*/ + +/** + * HTTP 初始化注册函数, 该函数如果非空,则由主程序在刚开始运行时调用 + * @param dll_env {ACL_DLL_ENV*} DLL 环境变量, dll_env->logfp 日志文件句柄, + * 如果不希望将日志记在主程序日志文件中,则可以将此值置空 + * @param dmptr {ACL_DEBUG_MEM*} 用于内存调试的句柄 + * @param cfg_dir {const char*} 配置文件所在路径,该路径下存放所有动态库的配置文件 + */ +void http_plugin_init(ACL_DLL_ENV *dll_env, const char *cfg_dir); + +/** + * HTTP 请求过滤注册函数,该函数如果非空,则由主程序在收到HTTP请求头时调用 + * @param client {ACL_VSTREAM*} 客户端流 + * @param hdr_req {HTTP_HDR_REQ*} HTTP请求头 + * @param ctx_ptr {void**} 该指针可以用来存储用户的动态数据 + * @return {int} < 0: 表示禁止该HTTP请求, 该值表示错误号,可以为:-5xx/-4xx; + * 0: 表示该HTTP请求继续由主程序处理; > 0: 表示该HTTP请求可以由外挂模块的单独 + * 线程处理 + */ +int http_request_filter(ACL_VSTREAM *client, HTTP_HDR_REQ *hdr_req, void **ctx_ptr); + +/** + * HTTP 请求接管处理注册函数,该函数如果非空,且 http_request_filter() > 0,则由 + * 主程序调用此函数完全接管该HTTP请求及响应,主程序不再处理该HTTP请求及HTTP响应 + * @param client {ACL_VSTREAM*} HTTP客户端数据连接流 + * @param hdr_req {HTTP_HDR_REQ*} 客户端HTTP请求头 + * @param ctx {void*} 过滤器的参数,该动态参数是由 http_request_filter 中的 ctx_ptr + * 参数返回的 + */ +void http_request_forward(ACL_VSTREAM *client, HTTP_HDR_REQ *hdr_req, void *ctx); + +/*------------------------------ 其它函数接口 --------------------------------*/ + +#define DEBUG_BASE 500 +#define DBG_REQ (DEBUG_BASE + 1) +#define DBG_RES (DEBUG_BASE + 2) + +#define STR acl_vstring_str +#define LEN ACL_VSTRING_LEN + +extern char *var_cfg_log_name; +extern char *var_cfg_http_domain_allow; +extern char *var_cfg_http_domain_redirect; +extern int var_cfg_http_domain_allow_all; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/app/jaws/plugin/http_access/http_redirect.c b/app/jaws/plugin/http_access/http_redirect.c new file mode 100644 index 000000000..f9cc6a039 --- /dev/null +++ b/app/jaws/plugin/http_access/http_redirect.c @@ -0,0 +1,84 @@ +#include "lib_acl.h" +#include "lib_protocol.h" +#include "http_plugin.h" +#include "http_redirect.h" + +static ACL_FIFO *__redirect_list = NULL; + +static HTTP_DOMAIN_MAP *http_domain_map_new(const char *from, const char *to) +{ + HTTP_DOMAIN_MAP *hdm = (HTTP_DOMAIN_MAP*) + acl_mymalloc(sizeof(HTTP_DOMAIN_MAP)); + + hdm->domain_from = acl_mystrdup(from); + hdm->domain_to = acl_mystrdup(to); + hdm->size_from = strlen(from); + return (hdm); +} + +static void http_domain_map_free(HTTP_DOMAIN_MAP *hdm) +{ + acl_myfree(hdm->domain_from); + acl_myfree(hdm->domain_to); + acl_myfree(hdm); +} + +void http_redirect_end(void) +{ + if (!__redirect_list) + return; + acl_fifo_free(__redirect_list, (void (*)(void*)) http_domain_map_free); + __redirect_list = NULL; +} + +void http_redirect_init(void) +{ + const char *myname = "http_redirect_init"; + ACL_ARGV *argv; + ACL_ITER iter; + + __redirect_list = acl_fifo_new(); + + if (var_cfg_http_domain_redirect == NULL + || *var_cfg_http_domain_redirect == 0) + return; + + /* 去掉多余的空格和缩近 */ + acl_mystr_trim(var_cfg_http_domain_redirect); + /* 统一转换为小写 */ + acl_lowercase(var_cfg_http_domain_redirect); + argv = acl_argv_split(var_cfg_http_domain_redirect, ";"); + acl_foreach(iter, argv) { + HTTP_DOMAIN_MAP *hdm; + char *ptr = (char*) iter.data; + char *ptr1 = strchr(ptr, '='); + if (ptr1 == NULL || *(ptr1 + 1) == 0) { + acl_msg_warn("%s(%d): invalid redirect(%s)", + myname, __LINE__, ptr); + continue; + } + *ptr1++ = 0; + hdm = http_domain_map_new(ptr, ptr1); + acl_msg_info("%s(%d): add(%s, %s) map", myname, __LINE__, ptr, ptr1); + acl_fifo_push(__redirect_list, hdm); + } +} + +HTTP_DOMAIN_MAP *http_redirect_lookup(const char *domain) +{ + char buf[256]; + ACL_ITER iter; + + if (__redirect_list == NULL) + return (NULL); + + ACL_SAFE_STRNCPY(buf, domain, sizeof(buf)); + acl_lowercase(buf); + + acl_foreach(iter, __redirect_list) { + HTTP_DOMAIN_MAP *hdm = (HTTP_DOMAIN_MAP*) iter.data; + if (acl_strrncmp(domain, hdm->domain_from, hdm->size_from) == 0) + return (hdm); + } + return (NULL); +} diff --git a/app/jaws/plugin/http_access/http_redirect.h b/app/jaws/plugin/http_access/http_redirect.h new file mode 100644 index 000000000..2b813f38b --- /dev/null +++ b/app/jaws/plugin/http_access/http_redirect.h @@ -0,0 +1,14 @@ +#ifndef __HTTP_REDIRECT_INCLUDE_H__ +#define __HTTP_REDIRECT_INCLUDE_H__ + +typedef struct { + char *domain_from; + char *domain_to; + int size_from; +} HTTP_DOMAIN_MAP; + +void http_redirect_init(void); +void http_redirect_end(void); +HTTP_DOMAIN_MAP *http_redirect_lookup(const char *domain); + +#endif diff --git a/app/jaws/plugin/http_access/http_req_filter.c b/app/jaws/plugin/http_access/http_req_filter.c new file mode 100644 index 000000000..31c73780d --- /dev/null +++ b/app/jaws/plugin/http_access/http_req_filter.c @@ -0,0 +1,83 @@ +#include "lib_acl.h" +#include "lib_protocol.h" +#include "http_access.h" +#include "html_template.h" +#include "http_redirect.h" +#include "http_plugin.h" + +int http_request_filter(ACL_VSTREAM *client acl_unused, HTTP_HDR_REQ *hdr_req, void **ctx_ptr) +{ + const char *myname = "http_request_filter"; + const char *domain = http_hdr_req_host(hdr_req); + HTTP_DOMAIN_MAP *hdm; + + if (domain == NULL) { + acl_msg_error("%s(%d): no host in request(%s)", + myname, __LINE__, http_hdr_req_url(hdr_req)); + return (-403); + } + + if (http_access_permit(domain)) { + hdm = http_redirect_lookup(domain); + if (hdm == NULL) + return (0); + *ctx_ptr = hdm; + return (1); + } else { + acl_msg_info("%s(%d): domain(%s) denied!", myname, __LINE__, domain); + return (-403); + } +} + +void http_request_forward(ACL_VSTREAM *client, HTTP_HDR_REQ *hdr_req, void *ctx) +{ + const char *myname = "http_request_forward"; + HTTP_DOMAIN_MAP *hdm = (HTTP_DOMAIN_MAP*) ctx; + ACL_VSTRING *buf; + HTTP_HDR_RES *hdr_res; + const char *host_ptr; + int n; + + if (hdm == NULL) { + acl_msg_error("%s(%d): ctx null", NULL); + acl_vstream_writen(client, HTTP_INTERNAL_ERROR, strlen(HTTP_INTERNAL_ERROR)); + acl_vstream_close(client); + http_hdr_req_free(hdr_req); + return; + } + + host_ptr = http_hdr_req_host(hdr_req); + if (acl_strrncmp(hdm->domain_from, host_ptr, hdm->size_from) != 0) { + acl_msg_error("%s(%d): domain_from(%s) != host(%s)", + myname, __LINE__, hdm->domain_from, host_ptr); + acl_vstream_writen(client, HTTP_INTERNAL_ERROR, strlen(HTTP_INTERNAL_ERROR)); + acl_vstream_close(client); + http_hdr_req_free(hdr_req); + return; + } + + buf = acl_vstring_alloc(256); + + /* 生成新的 url 地址 */ + n = (int) strlen(host_ptr) - hdm->size_from; + acl_vstring_strcpy(buf, "http://"); + if (n > 0) + acl_vstring_strncat(buf, host_ptr, n); + acl_vstring_strcat(buf, hdm->domain_to); + acl_vstring_strcat(buf, acl_vstring_str(hdr_req->url_part)); + + /* 产生重定向头 */ + hdr_res = http_hdr_res_static(302); + http_hdr_put_str(&hdr_res->hdr, "Location", acl_vstring_str(buf)); + http_hdr_put_str(&hdr_res->hdr, "Connection", "close"); + + /* 生成响应数据包 */ + http_hdr_build(&hdr_res->hdr, buf); + + acl_vstream_writen(client, acl_vstring_str(buf), ACL_VSTRING_LEN(buf)); + acl_vstream_close(client); + http_hdr_req_free(hdr_req); + + acl_vstring_free(buf); + http_hdr_res_free(hdr_res); +} diff --git a/app/jaws/plugin/http_access/release/BuildLog.htm b/app/jaws/plugin/http_access/release/BuildLog.htm new file mode 100644 index 000000000..e493c57a2 --- /dev/null +++ b/app/jaws/plugin/http_access/release/BuildLog.htm @@ -0,0 +1,67 @@ + + + + + +
+
+生成日志 +
  
+

------- 已启动生成: 项目: http_access,配置: Release|Win32 ------- +

+
+命令行 +
  
正在创建临时文件“d:\工作目录\项目管理\jaws\jaws\plugin\http_access\Release\RSP000007.rsp”,其内容为
+[
+/O2 /I "..\..\include\protocol" /I "..\..\include\acl" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_USRDLL" /D "HTTP_ACCESS_EXPORTS" /D "_WINDLL" /D "_MBCS" /FD /EHsc /MD /GS /Fo"Release/" /Fd"Release/vc70.pdb" /W3 /c /Wp64 /Zi /TC
+.\http_req_filter.c
+.\http_redirect.c
+.\http_plugin.c
+.\http_access.c
+.\html_template.c
+]
+正在创建命令行“cl.exe @d:\工作目录\项目管理\jaws\jaws\plugin\http_access\Release\RSP000007.rsp /nologo”
+正在创建临时文件“d:\工作目录\项目管理\jaws\jaws\plugin\http_access\Release\RSP000008.rsp”,其内容为
+[
+/OUT:"Release/http_access.dll" /INCREMENTAL:NO /NOLOGO /LIBPATH:"..\..\lib\win32" /DLL /SUBSYSTEM:WINDOWS /OPT:REF /OPT:ICF /IMPLIB:"Release/http_access.lib" /MACHINE:X86 lib_protocol.lib lib_acl.lib ws2_32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib
+.\release\html_template.obj
+.\release\http_access.obj
+.\release\http_plugin.obj
+.\release\http_redirect.obj
+.\release\http_req_filter.obj
+]
+正在创建命令行“link.exe @d:\工作目录\项目管理\jaws\jaws\plugin\http_access\Release\RSP000008.rsp”
+正在创建临时文件“d:\工作目录\项目管理\jaws\jaws\plugin\http_access\Release\BAT000009.bat”,其内容为
+[
+@echo off
+copy Release\http_access.dll ..\..\build\http_access.dll  /Y
+if errorlevel 1 goto VCReportError
+goto VCEnd
+:VCReportError
+echo Project : error PRJ0019: 工具从"正在执行生成后事件..."
+exit 1
+:VCEnd
+]
+正在创建命令行“d:\工作目录\项目管理\jaws\jaws\plugin\http_access\Release\BAT000009.bat”
+
+输出窗口 +
  
正在编译...
+http_req_filter.c
+http_redirect.c
+http_redirect.c(15) : warning C4267: “=” : 从“size_t”转换到“int”,可能丢失数据
+http_plugin.c
+http_access.c
+http_access.c(70) : warning C4267: “=” : 从“size_t”转换到“int”,可能丢失数据
+html_template.c
+正在生成代码...
+正在链接...
+LINK : warning LNK4089: /OPT:REF 已丢弃所有对“lib_acl.dll”的引用
+LINK : warning LNK4089: /OPT:REF 已丢弃所有对“lib_protocol.dll”的引用
+正在执行生成后事件...
+已复制         1 个文件。
+
+结果 +
  
+生成日志保存在“file://d:\工作目录\项目管理\jaws\jaws\plugin\http_access\Release\BuildLog.htm”中
+http_access - 0 错误,4 警告
+
\ No newline at end of file diff --git a/app/jaws/readme.txt b/app/jaws/readme.txt new file mode 100644 index 000000000..74d7e9256 --- /dev/null +++ b/app/jaws/readme.txt @@ -0,0 +1 @@ +Jaws(Just a webserver) can run on Unix/Windows diff --git a/app/jaws/tools/Makefile b/app/jaws/tools/Makefile new file mode 100644 index 000000000..74571099e --- /dev/null +++ b/app/jaws/tools/Makefile @@ -0,0 +1,8 @@ +all: + @(cd connect; make) + @(cd http; make) + @(cd httpd; make) +clean: + @(cd connect; make clean) + @(cd http; make clean) + @(cd httpd; make clean) diff --git a/app/jaws/tools/check_mem/Makefile b/app/jaws/tools/check_mem/Makefile new file mode 100644 index 000000000..145bb67bd --- /dev/null +++ b/app/jaws/tools/check_mem/Makefile @@ -0,0 +1,112 @@ +SHELL = /bin/sh +CC = gcc +#CC = g++ +AR = ar +ARFL = rv +RANLIB = ranlib + +CFLAGS = -c -g -W -Wall -Wcast-qual -Wcast-align \ +-Waggregate-return -Wmissing-prototypes \ +-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO \ +-Wno-long-long \ +-Wpointer-arith -Werror -Wshadow -pedantic -O2 + +########################################################### +#Check system: +# Linux, SunOS, Solaris, BSD variants, AIX, HP-UX +SYSLIB = -ldl +RPATH = + +CHECKSYSRES = @echo "Unknow system type!";exit 1 +UNIXNAME = $(shell uname -sm) +OSTYPE = $(shell uname -p) + +#Path for Linux +ifeq ($(findstring Linux, $(UNIXNAME)), Linux) +# ifeq ($CC, "gcc") + ifeq ($(findstring i686, $(OSTYPE)), i686) + RPATH = linux32 + endif + ifeq ($(findstring x86_64, $(OSTYPE)), x86_64) + RPATH = linux64 + endif + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DLINUX2 + SYSLIB += -lcrypt -lpthread +endif + +#Path for SunOS +ifeq ($(findstring SunOS, $(UNIXNAME)), SunOS) + ifeq ($(findstring i386, $(OSTYPE)), i386) + RPATH = sunos_x86 + endif + ifeq ($(findstring 86, $(UNIXNAME)), 86) + SYSLIB += -lsocket -lnsl -lrt + endif + ifeq ($(findstring sun4u, $(UNIXNAME)), sun4u) + SYSLIB += -lsocket -lnsl -lrt + endif +# ifeq ($CC, "gcc") + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DSUNOS5 +endif + +#Path for HP-UX +ifeq ($(findstring HP-UX, $(UNIXNAME)), HP-UX) +# ifeq ($CC, "gcc") + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + SYSLIB += -lpthread + CFLAGS += -DHP_UX -DHPUX11 + PLAT_NAME=hp-ux +endif + +#Find system type. +ifneq ($(SYSPATH),) + CHECKSYSRES = @echo "System is $(shell uname -sm)" +endif +########################################################### +ACL_PATH = ../../../../lib_acl +ACL_LIB = $(ACL_PATH)/lib +ACL_INC = $(ACL_PATH)/include + +ALL_LIBS = -L$(ACL_LIB) -l_acl $(SYSLIB) + +INCLUDE = -I$(ACL_INC) +CFLAGS += $(INCLUDE) -DHAVE_NO_STRCASESTR + +OBJ_OUTPATH = ./debug + +#Project's objs +SOURCES = $(wildcard ./*.c) +OBJS = $(patsubst %.c, $(OBJ_OUTPATH)/%.o, $(notdir $(SOURCES))) + +########################################################### +PROG_NAME = check_mem + +.PHONY = RM all clean +COMPILE = $(CC) $(CFLAGS) + +all: RM $(PROG_NAME) + +RM: + rm -f $(PROG_NAME) + +PLUGIN: + @(cd plugin; make) + +$(PROG_NAME): $(OBJS) + $(CC) -o $(PROG_NAME) $(OBJS) $(LIB_NAME_PATH) $(ALL_LIBS) + +$(OBJ_OUTPATH)/%.o: ./%.c + $(COMPILE) -o $@ $< + +clean: + rm -f $(OBJS) $(PROG_NAME) + +rebuild: clean all diff --git a/app/jaws/tools/check_mem/check_mem.c b/app/jaws/tools/check_mem/check_mem.c new file mode 100644 index 000000000..486e65996 --- /dev/null +++ b/app/jaws/tools/check_mem/check_mem.c @@ -0,0 +1,137 @@ +#include "lib_acl.h" +#include +#include +#include +#include +#include + +typedef struct { + char name[256]; + int ncalloc; + int nmalloc; + int nstrdup; + int nfree; +} FNAME; + +static ACL_HTABLE *__table = NULL; + +static FNAME *fname_new(const char *name) +{ + FNAME *fname = (FNAME*) acl_mycalloc(1, sizeof(FNAME)); + + ACL_SAFE_STRNCPY(fname->name, name, sizeof(fname->name)); + return (fname); +} + +static void fname_free(FNAME *fname) +{ + acl_myfree(fname); +} + +static void run(const char *path) +{ + ACL_FILE *fp = acl_fopen(path, "r"); + FNAME *fname; + char buf[4096]; + ACL_ITER iter; + int nfree = 0, nmalloc = 0, ncalloc = 0, nstrdup = 0; + + if (fp == NULL) { + printf("open file(%s) error(%s)\n", path, acl_last_serror()); + return; + } + + __table = acl_htable_create(100, 0); + + while (acl_fgets_nonl(buf, sizeof(buf), fp) != NULL) { + ACL_ARGV *argv = acl_argv_split(buf, " "); + const char *oper, *name; + + if (argv->argc != 8) { + acl_argv_free(argv); + continue; + } + oper = argv->argv[5]; + name = argv->argv[6]; + if (strcmp(oper, "free:") == 0) { + fname = (FNAME*) acl_htable_find(__table, name); + if (fname == NULL) { + fname = fname_new(name); + acl_htable_enter(__table, name, fname); + } + fname->nfree++; + } else if (strcmp(oper, "malloc:") == 0) { + fname = (FNAME*) acl_htable_find(__table, name); + if (fname == NULL) { + fname = fname_new(name); + acl_htable_enter(__table, name, fname); + } + fname->nmalloc++; + } else if (strcmp(oper, "calloc:") == 0) { + fname = (FNAME*) acl_htable_find(__table, name); + if (fname == NULL) { + fname = fname_new(name); + acl_htable_enter(__table, name, fname); + } + fname->ncalloc++; + } else if (strcmp(oper, "strdup:") == 0) { + fname = (FNAME*) acl_htable_find(__table, name); + if (fname == NULL) { + fname = fname_new(name); + acl_htable_enter(__table, name, fname); + } + fname->nstrdup++; + } + acl_argv_free(argv); + } + + acl_foreach(iter, __table) { + fname = (FNAME*) iter.data; + nmalloc += fname->nmalloc; + ncalloc += fname->ncalloc; + nstrdup += fname->nstrdup; + nfree += fname->nfree; + if (fname->nmalloc + fname->ncalloc + fname->nstrdup == fname->nfree) + continue; + printf(">>>%s: total free: %d, total alloc: %d (malloc: %d, calloc: %d, strdup: %d)\n", + fname->name, fname->nfree, fname->nmalloc + fname->ncalloc + fname->nstrdup, + fname->nmalloc, fname->ncalloc, fname->nstrdup); + } + + printf(">>> total free: %d, total alloc: %d (malloc: %d, calloc: %d, strdup: %d)\n", + nfree, nmalloc + ncalloc + nstrdup, nmalloc, ncalloc, nstrdup); + + acl_htable_free(__table, (void (*)(void*)) fname_free); + acl_fclose(fp); +} + +static void usage(const char *procname) +{ + printf("usage: %s -h [help] -f log_path\n", procname); +} + +int main(int argc, char *argv[]) +{ + char ch, path[256] = ""; + + while ((ch = getopt(argc, argv, "hf:")) > 0) { + switch (ch) { + case 'f': + snprintf(path, sizeof(path), "%s", optarg); + break; + case 'h': + default: + usage(argv[0]); + return (0); + } + } + + if (path[0] == 0) { + usage(argv[0]); + return (0); + } + + run(path); + + return (0); +} diff --git a/app/jaws/tools/connect/Makefile b/app/jaws/tools/connect/Makefile new file mode 100644 index 000000000..1cc8897c3 --- /dev/null +++ b/app/jaws/tools/connect/Makefile @@ -0,0 +1,108 @@ +SHELL = /bin/sh +CC = gcc +#CC = g++ +AR = ar +ARFL = rv +RANLIB = ranlib + +CFLAGS = -c -g -W -Wcast-qual -Wcast-align \ +-Waggregate-return -Wmissing-prototypes \ +-Wpointer-arith -Werror -Wshadow -O2 \ +-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO \ +-Wno-long-long \ +-pedantic -Wall +########################################################### +#Check system: +# Linux, SunOS, Solaris, BSD variants, AIX, HP-UX +SYSLIB = +CHECKSYSRES = @echo "Unknow system type!";exit 1 +UNIXNAME = $(shell uname -sm) + +# For FreeBSD +ifeq ($(findstring FreeBSD, $(UNIXNAME)), FreeBSD) + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DFREEBSD -D_REENTRANT -pedantic + SYSLIB = -lcrypt -lpthread +endif + +#Path for Linux +ifeq ($(findstring Linux, $(UNIXNAME)), Linux) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DLINUX2 + SYSLIB = -lcrypt -lpthread +endif + +#Path for SunOS +ifeq ($(findstring SunOS, $(UNIXNAME)), SunOS) + ifeq ($(findstring 86, $(UNIXNAME)), 86) + SYSLIB = -lsocket -lnsl -lrt + endif + ifeq ($(findstring sun4u, $(UNIXNAME)), sun4u) + SYSLIB = -lsocket -lnsl -lrt + endif + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DSUNOS5 +endif + +#Path for HP-UX +ifeq ($(findstring HP-UX, $(UNIXNAME)), HP-UX) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + SYSLIB = -lpthread + CFLAGS += -DHP_UX -DHPUX11 + PLAT_NAME=hp-ux +endif + +#Find system type. +ifneq ($(SYSPATH),) + CHECKSYSRES = @echo "System is $(shell uname -sm)" +endif +########################################################### + +ACL_PATH = ../../../../lib_acl +ACL_LIB = $(ACL_PATH)/lib +ACL_INC = $(ACL_PATH)/include + +PROTO_PATH = ../../../../lib_protocol +PROTO_LIB = $(PROTO_PATH)/lib +PROTO_INC = $(PROTO_PATH)/include + +CFLAGS += -I$(ACL_INC) -I$(PROTO_INC) +ALL_LIBS = -L$(PROTO_LIB) -l_protocol -L$(ACL_LIB) -l_acl $(SYSLIB) + +OUTPATH = ./ +OBJ_OUTPATH = $(OUTPATH) + +#Project's objs +SOURCES = $(wildcard *.c) +OBJS = $(patsubst %.c,$(OBJ_OUTPATH)%.o,$(SOURCES)) + +########################################################### + +PROG_NAME = http + +.PHONY = clean +COMPILE = $(CC) $(CFLAGS) + +all: RM $(PROG_NAME) + +RM: + rm -f $(PROG_NAME) + +$(PROG_NAME): $(OBJS) + $(CC) -o $(PROG_NAME) $(OBJS) $(ALL_LIBS) + +$(OBJ_OUTPATH)%.o: %.c *.h + $(COMPILE) -o $@ $< + +clean: + rm -f $(OBJS) $(PROG_NAME) + +rebuild: clean all diff --git a/app/jaws/tools/connect/main.c b/app/jaws/tools/connect/main.c new file mode 100644 index 000000000..c925bdafd --- /dev/null +++ b/app/jaws/tools/connect/main.c @@ -0,0 +1,109 @@ +#include "lib_acl.h" +#include +#include +#include "lib_protocol.h" + +static int connect_callback(ACL_ASTREAM *stream, void *context); + +static int close_callback(ACL_ASTREAM *stream, void *context) +{ + const char *myname = "close_callback"; + ACL_AIO *aio = (ACL_AIO*) context; + const char *addr = ACL_VSTREAM_PATH(stream->stream); + + printf("%s: re-connect %s, aio(%s)\n", myname, addr, aio ? "not null" : "null"); + stream = acl_aio_connect(aio, addr, 0); + if (stream == NULL) { + printf("%s: connect addr(%s) error(%s)\n", + myname, addr, acl_last_serror()); + return (-1); + } + printf("%s: re-connect %s ok\n", myname, addr); + acl_aio_ctl(stream, ACL_AIO_CTL_CONNECT_FN, connect_callback, + ACL_AIO_CTL_CTX, aio, + ACL_AIO_CTL_END); + return (-1); +} + +static int read_callback(ACL_ASTREAM *stream acl_unused, void *context acl_unused) +{ + return (0); +} + +static int connect_callback(ACL_ASTREAM *stream, void *context) +{ + const char *myname = "connect_callback"; + + acl_aio_ctl(stream, ACL_AIO_CTL_READ_HOOK_ADD, read_callback, context, + ACL_AIO_CTL_CLOSE_HOOK_ADD, close_callback, context, + ACL_AIO_CTL_END); + printf("%s: connect %s ok, fd(%d)\n", myname, + ACL_VSTREAM_PATH(stream->stream), + ACL_VSTREAM_SOCK(stream->stream)); + acl_aio_read(stream); + return (0); +} + +static void test_connect(const char *addr, int n) +{ + int i; + ACL_AIO *aio; + ACL_ASTREAM *stream; + +#ifdef ACL_UNIX + aio = acl_aio_create(ACL_EVENT_KERNEL); +#else + aio = acl_aio_create(ACL_EVENT_SELECT); +#endif + + for (i = 0; i < n; i++) { + stream = acl_aio_connect(aio, addr, 0); + if (stream == NULL) { + printf("connect addr(%s) error(%s), i(%d)\n", + addr, acl_last_serror(), i); + break; + } + + acl_aio_ctl(stream, ACL_AIO_CTL_CONNECT_FN, connect_callback, + ACL_AIO_CTL_CTX, aio, + ACL_AIO_CTL_END); + } + + while (1) { + acl_aio_loop(aio); + } +} + +static void usage(const char *procname) +{ + printf("usage: %s -h[help] -s server_addr -n connect_cocurrent\n", procname); +} + +int main(int argc, char *argv[]) +{ + char addr[128] = "127.0.0.1:8284"; + int ch, n = 1000; + + acl_init(); + + while ((ch = getopt(argc, argv, "hs:n:")) > 0) { + switch (ch) { + case 'h': + usage(argv[0]); + return (0); + case 's': + ACL_SAFE_STRNCPY(addr, optarg, sizeof(addr)); + break; + case 'n': + n = atoi(optarg); + if (n <= 0) + n = 100; + break; + default: + break; + } + } + + test_connect(addr, n); + return (0); +} diff --git a/app/jaws/tools/http/Makefile b/app/jaws/tools/http/Makefile new file mode 100644 index 000000000..1cc8897c3 --- /dev/null +++ b/app/jaws/tools/http/Makefile @@ -0,0 +1,108 @@ +SHELL = /bin/sh +CC = gcc +#CC = g++ +AR = ar +ARFL = rv +RANLIB = ranlib + +CFLAGS = -c -g -W -Wcast-qual -Wcast-align \ +-Waggregate-return -Wmissing-prototypes \ +-Wpointer-arith -Werror -Wshadow -O2 \ +-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO \ +-Wno-long-long \ +-pedantic -Wall +########################################################### +#Check system: +# Linux, SunOS, Solaris, BSD variants, AIX, HP-UX +SYSLIB = +CHECKSYSRES = @echo "Unknow system type!";exit 1 +UNIXNAME = $(shell uname -sm) + +# For FreeBSD +ifeq ($(findstring FreeBSD, $(UNIXNAME)), FreeBSD) + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DFREEBSD -D_REENTRANT -pedantic + SYSLIB = -lcrypt -lpthread +endif + +#Path for Linux +ifeq ($(findstring Linux, $(UNIXNAME)), Linux) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DLINUX2 + SYSLIB = -lcrypt -lpthread +endif + +#Path for SunOS +ifeq ($(findstring SunOS, $(UNIXNAME)), SunOS) + ifeq ($(findstring 86, $(UNIXNAME)), 86) + SYSLIB = -lsocket -lnsl -lrt + endif + ifeq ($(findstring sun4u, $(UNIXNAME)), sun4u) + SYSLIB = -lsocket -lnsl -lrt + endif + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DSUNOS5 +endif + +#Path for HP-UX +ifeq ($(findstring HP-UX, $(UNIXNAME)), HP-UX) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + SYSLIB = -lpthread + CFLAGS += -DHP_UX -DHPUX11 + PLAT_NAME=hp-ux +endif + +#Find system type. +ifneq ($(SYSPATH),) + CHECKSYSRES = @echo "System is $(shell uname -sm)" +endif +########################################################### + +ACL_PATH = ../../../../lib_acl +ACL_LIB = $(ACL_PATH)/lib +ACL_INC = $(ACL_PATH)/include + +PROTO_PATH = ../../../../lib_protocol +PROTO_LIB = $(PROTO_PATH)/lib +PROTO_INC = $(PROTO_PATH)/include + +CFLAGS += -I$(ACL_INC) -I$(PROTO_INC) +ALL_LIBS = -L$(PROTO_LIB) -l_protocol -L$(ACL_LIB) -l_acl $(SYSLIB) + +OUTPATH = ./ +OBJ_OUTPATH = $(OUTPATH) + +#Project's objs +SOURCES = $(wildcard *.c) +OBJS = $(patsubst %.c,$(OBJ_OUTPATH)%.o,$(SOURCES)) + +########################################################### + +PROG_NAME = http + +.PHONY = clean +COMPILE = $(CC) $(CFLAGS) + +all: RM $(PROG_NAME) + +RM: + rm -f $(PROG_NAME) + +$(PROG_NAME): $(OBJS) + $(CC) -o $(PROG_NAME) $(OBJS) $(ALL_LIBS) + +$(OBJ_OUTPATH)%.o: %.c *.h + $(COMPILE) -o $@ $< + +clean: + rm -f $(OBJS) $(PROG_NAME) + +rebuild: clean all diff --git a/app/jaws/tools/http/main.c b/app/jaws/tools/http/main.c new file mode 100644 index 000000000..a9eee9ad0 --- /dev/null +++ b/app/jaws/tools/http/main.c @@ -0,0 +1,76 @@ +#include "lib_acl.h" +#include +#include +#include "lib_protocol.h" + +static void test_connect(const char *addr) +{ + ACL_VSTREAM *stream; +#if 1 + const char *request = "GET / HTTP/1.1\nHOST: store.hexun.com\nConnection: keep-alive\n\nGET / HTTP/1.1\nHOST: store.hexun.com\nConnection: close\n\n"; +#else + const char *request = "GET / HTTP/1.1\nHOST: store.hexun.com\nConnection: keep-alive\n\n"; +#endif + + stream = acl_vstream_connect(addr, ACL_BLOCKING, 10, 10, 4096); + if (stream == NULL) { + printf("connect %s error(%s)\n", addr, acl_last_serror()); + return; + } + acl_vstream_fprintf(stream, "%s", request); + printf("request:(%s)\n", request); + + while (1) { + char buf[4096]; + int ret = acl_vstream_read(stream, buf, sizeof(buf) - 1); + if (ret == ACL_VSTREAM_EOF) + break; + buf[ret] = 0; + printf("%s", buf); + } +} + +static void usage(const char *procname) +{ + printf("usage: %s -h[help] -s server_addr\n", procname); +} + +static void test(void) +{ + int i, n = 0; + + ACL_METER_TIME("---begin---"); + for (i = 0; i < 10000; i++) { + if (i % 100 == 0) + n++; + } + ACL_METER_TIME("---end---"); + + exit (0); +} + +int main(int argc, char *argv[]) +{ + char addr[128] = "127.0.0.1:8283"; + int ch; + + acl_init(); + + test(); + + while ((ch = getopt(argc, argv, "hs:")) > 0) { + switch (ch) { + case 'h': + usage(argv[0]); + return (0); + case 's': + ACL_SAFE_STRNCPY(addr, optarg, sizeof(addr)); + break; + default: + break; + } + } + + test_connect(addr); + return (0); +} diff --git a/app/jaws/tools/httpd/Makefile b/app/jaws/tools/httpd/Makefile new file mode 100644 index 000000000..072a07e42 --- /dev/null +++ b/app/jaws/tools/httpd/Makefile @@ -0,0 +1,108 @@ +SHELL = /bin/sh +CC = gcc +#CC = g++ +AR = ar +ARFL = rv +RANLIB = ranlib + +CFLAGS = -c -g -W -Wcast-qual -Wcast-align \ +-Waggregate-return -Wmissing-prototypes \ +-Wpointer-arith -Werror -Wshadow -O2 \ +-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO \ +-Wno-long-long \ +-pedantic -Wall +########################################################### +#Check system: +# Linux, SunOS, Solaris, BSD variants, AIX, HP-UX +SYSLIB = +CHECKSYSRES = @echo "Unknow system type!";exit 1 +UNIXNAME = $(shell uname -sm) + +# For FreeBSD +ifeq ($(findstring FreeBSD, $(UNIXNAME)), FreeBSD) + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DFREEBSD -D_REENTRANT -pedantic + SYSLIB = -lcrypt -lpthread +endif + +#Path for Linux +ifeq ($(findstring Linux, $(UNIXNAME)), Linux) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DLINUX2 + SYSLIB = -lcrypt -lpthread +endif + +#Path for SunOS +ifeq ($(findstring SunOS, $(UNIXNAME)), SunOS) + ifeq ($(findstring 86, $(UNIXNAME)), 86) + SYSLIB = -lsocket -lnsl -lrt + endif + ifeq ($(findstring sun4u, $(UNIXNAME)), sun4u) + SYSLIB = -lsocket -lnsl -lrt + endif + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DSUNOS5 +endif + +#Path for HP-UX +ifeq ($(findstring HP-UX, $(UNIXNAME)), HP-UX) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + SYSLIB = -lpthread + CFLAGS += -DHP_UX -DHPUX11 + PLAT_NAME=hp-ux +endif + +#Find system type. +ifneq ($(SYSPATH),) + CHECKSYSRES = @echo "System is $(shell uname -sm)" +endif +########################################################### + +ACL_PATH = ../../../../lib_acl +ACL_LIB = $(ACL_PATH)/lib +ACL_INC = $(ACL_PATH)/include + +PROTO_PATH = ../../../../lib_protocol +PROTO_LIB = $(PROTO_PATH)/lib +PROTO_INC = $(PROTO_PATH)/include + +CFLAGS += -I$(ACL_INC) -I$(PROTO_INC) +ALL_LIBS = -L$(PROTO_LIB) -l_protocol -L$(ACL_LIB) -l_acl $(SYSLIB) + +OUTPATH = ./ +OBJ_OUTPATH = $(OUTPATH) + +#Project's objs +SOURCES = $(wildcard *.c) +OBJS = $(patsubst %.c,$(OBJ_OUTPATH)%.o,$(SOURCES)) + +########################################################### + +PROG_NAME = httpd + +.PHONY = clean +COMPILE = $(CC) $(CFLAGS) + +all: RM $(PROG_NAME) + +RM: + rm -f $(PROG_NAME) + +$(PROG_NAME): $(OBJS) + $(CC) -o $(PROG_NAME) $(OBJS) $(ALL_LIBS) + +$(OBJ_OUTPATH)%.o: %.c *.h + $(COMPILE) -o $@ $< + +clean: + rm -f $(OBJS) $(PROG_NAME) + +rebuild: clean all diff --git a/app/jaws/tools/httpd/main.c b/app/jaws/tools/httpd/main.c new file mode 100644 index 000000000..6f28ab970 --- /dev/null +++ b/app/jaws/tools/httpd/main.c @@ -0,0 +1,228 @@ +#include "lib_acl.h" +#include "lib_protocol.h" +#include +#include + +typedef struct { + ACL_VSTREAM *stream; + int nconn; +} CONN; + +static void init(void) +{ + acl_init(); +} + +static void end(void) +{ + acl_end(); +} + +static void thread_run(void *arg) +{ + CONN *conn = (CONN*) arg; + ACL_VSTREAM *client = conn->stream; + const char *keep_reply_200 = "HTTP/1.1 200 OK\r\n" + "Server: nginx/0.6.32\r\n" + "Date: Tue, 29 Dec 2009 02:18:25 GMT\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 43\r\n" + "Last-Modified: Mon, 16 Nov 2009 02:18:14 GMT\r\n" + "Connection: keep-alive\r\n" + "Accept-Ranges: bytes\r\n\r\n" + "\n" + "\n" + "hello world!\n" + "\n" + "\n"; + const char *close_reply_200 = "HTTP/1.1 200 OK\r\n" + "Server: nginx/0.6.32\r\n" + "Date: Tue, 29 Dec 2009 02:18:25 GMT\r\n" + "Content-Type: text/html\r\n" + "Last-Modified: Mon, 16 Nov 2009 02:18:14 GMT\r\n" + "Connection: close\r\n" + "Accept-Ranges: bytes\r\n\r\n"; + + int ret, keep_alive; + + /* + if (conn->nconn % 2 == 0) { + acl_vstream_close(client); + acl_myfree(conn); + return; + } + */ + + while (1) { + HTTP_REQ *req; + HTTP_HDR_REQ *hdr_req = http_hdr_req_new(); + char buf[4096]; + + ret = http_hdr_req_get_sync(hdr_req, client, 300); + if (ret < 0) { + http_hdr_req_free(hdr_req); + break; + } + if (http_hdr_req_parse(hdr_req) < 0) { + http_hdr_req_free(hdr_req); + printf("parse error\n"); + break; + } + + keep_alive = hdr_req->hdr.keep_alive; + + if (hdr_req->hdr.content_length > 0) { + req = http_req_new(hdr_req); + ret = (int) http_req_body_get_sync(req, client, buf, sizeof(buf)); + if (ret < 0) { + http_req_free(req); + break; + } + http_req_free(req); + } else { + http_hdr_req_free(hdr_req); + } + + ret = acl_vstream_writen(client, keep_reply_200, strlen(keep_reply_200)); + break; + + if (conn->nconn % 3 == 0) { + ret = acl_vstream_writen(client, close_reply_200, strlen(close_reply_200)); + if (ret == ACL_VSTREAM_EOF) + break; + memset(buf, 'X', sizeof(buf)); + while (1) { + ret = acl_vstream_writen(client, buf, sizeof(buf)); + if (ret == ACL_VSTREAM_EOF) { + printf("write error\n"); + goto END; + } + } + } else { + ret = acl_vstream_writen(client, keep_reply_200, strlen(keep_reply_200)); + if (ret == ACL_VSTREAM_EOF) + break; + if (!keep_alive) + break; + conn->nconn++; + } + } + +END: + acl_vstream_close(client); + acl_myfree(conn); +} + +static void run_server(const char *addr) +{ + ACL_VSTREAM *sstream = acl_vstream_listen(addr, 128); + acl_pthread_pool_t *pool; + CONN *conn; + int n = 0; + + if (sstream == NULL) { + acl_msg_error("listen %s error(%s)", addr, acl_last_serror()); + return; + } + + printf("listening on %s ...\n", addr); + pool = acl_thread_pool_create(100, 120); + while (1) { + ACL_VSTREAM *client = acl_vstream_accept(sstream, NULL, 0); + if (client == NULL) { + acl_msg_error("accept error(%s)", acl_last_serror()); + break; + } +/* +printf("accept one: %d\n", ACL_VSTREAM_SOCK(client)); +shutdown(ACL_VSTREAM_SOCK(client), SHUT_RD | SHUT_WR); +continue; +*/ + conn = acl_mycalloc(1, sizeof(CONN)); + conn->stream = client; + conn->nconn = n++; + acl_pthread_pool_add(pool, thread_run, conn); + } + + acl_vstream_close(sstream); +} + +static void run_client(const char *addr, const char *filename) +{ + char *request = acl_vstream_loadfile(filename); + ACL_VSTREAM *client; + int ret; + char buf[1024]; + + if (request == NULL) { + printf("load file(%s) error(%s)\n", filename, acl_last_serror()); + return; + } + + client = acl_vstream_connect(addr, ACL_BLOCKING, + 0, 0, 4096); + if (client == NULL) { + printf("connect addr(%s) error(%s)\n", addr, acl_last_serror()); + acl_myfree(request); + return; + } + + acl_tcp_set_sndbuf(ACL_VSTREAM_SOCK(client), 10); + if (acl_vstream_writen(client, request, strlen(request)) == ACL_VSTREAM_EOF) { + printf("write to addr(%s) error(%s)\n", addr, acl_last_serror()); + acl_vstream_close(client); + acl_myfree(request); + return; + } + + memset(buf, 0, sizeof(buf)); + + while (1) { + ret = acl_vstream_read(client, buf, sizeof(buf) - 1); + if (ret == ACL_VSTREAM_EOF) + break; + buf[ret] = 0; + usleep(100000); + printf(">>>%s\n", buf); + } + + printf(">>>last data(%s)\n", buf); + acl_vstream_close(client); + acl_myfree(request); +} + +static void usage(const char *procname) +{ + printf("usage: %s -h [help] -s listen_addr[IP:PORT] -c request_hdr\n", procname); +} + +int main(int argc, char *argv[]) +{ + char addr[256] = "0.0.0.0:80", filename[256]; + int ch, client_mode = 0; + + while ((ch = getopt(argc, argv, "hs:c:")) > 0) { + switch (ch) { + case 'h': + usage(argv[0]); + exit (0); + case 's': + ACL_SAFE_STRNCPY(addr, optarg, sizeof(addr)); + break; + case 'c': + client_mode = 1; + ACL_SAFE_STRNCPY(filename, optarg, sizeof(filename)); + break; + default: + break; + } + } + + init(); + if (client_mode) + run_client(addr, filename); + else + run_server(addr); + end(); + return (0); +} diff --git a/app/jaws/tools/httpd/request.txt b/app/jaws/tools/httpd/request.txt new file mode 100644 index 000000000..003ddfa4e --- /dev/null +++ b/app/jaws/tools/httpd/request.txt @@ -0,0 +1,12 @@ +GET http://wmail2.mail.hexun.com/cgi-bin/main/login/1262918837 HTTP/1.1 +Host: wmail2.mail.hexun.com +User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; zh-CN; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 +Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 +Accept-Language: zh-cn,zh;q=0.7,en-us;q=0.3 +Accept-Encoding: gzip,deflate +Accept-Charset: GB2312,utf-8;q=0.7,*;q=0.7 +Keep-Alive: 300 +Proxy-Connection: keep-alive +Referer: http://wmail2.mail.hexun.com/cgi-bin/console/login/1262918836 +Cookie: __utma=27823648.422177696.1262914215.1262916847.1262917901.5; __utmb=27823648;__utmz=27823648.1262914215.1.1.utmccn=(direct)|utmcsr=(direct)|utmcmd=(none); HexunTrack=SID=217163494; hxck_sq_common=LoginStateCookie=md88aDazrp2KwrggnhhMQg%3d%3d&SnapCookie=bonerpMfA2LT9XEbMpY%2fnGYce2%2ffrrRRQHBRqeVvsqs%3d; ys-readmsg-layout-state=o%3Anorth%3Do%253Asize%253Dn%25253A60%5Esouth%3Do%253A%5Eeast%3Do%253A%5Ewest%3Do%253A; __utma=194262068.481558226.1262917014.1262917014.1262917014.1; __utmb=194262068.2.10.1262917014; __utmz=194262068.1262917014.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); __utmc=27823648; userToken=3497499%7c0000%7c0%2cVO50ruL1k6bDxL7WkEqYWUstiyZHXAssMFwHmZbnBsSIY8%2bicqVhh7jy%2bRphjFQrBMa9YBCyyiqim8jYiLoVrxgCiGv%2fsnKzbwZSwa6v3N2N93qSsoJIG7%2f%2bprVJNnVtqdD%2bow0Rqx3tnrD6cl1gQg%3d%3d; MailUserName=whousegodwithme; wmail_login=1; pop_alive=0 + diff --git a/app/jencode/AclTrans.cpp b/app/jencode/AclTrans.cpp new file mode 100644 index 000000000..8f985a39d --- /dev/null +++ b/app/jencode/AclTrans.cpp @@ -0,0 +1,284 @@ +#include "StdAfx.h" +#include "AclTrans.h" + +CAclTrans::CAclTrans(void) +: m_hWnd(0) +, m_sPath(_T("")) +, m_nMsgTransing(0) +, m_nMsgTransEnd(0) +{ +} + +CAclTrans::~CAclTrans(void) +{ +} + +CAclTrans::CAclTrans(HWND hWnd, CString &sPath) +: m_nMsgTransing(0) +, m_nMsgTransEnd(0) +{ + Init(hWnd, sPath); +} + +void CAclTrans::Init(HWND hWnd, CString &sPath) +{ + m_hWnd =hWnd; + m_sPath = sPath; +} + +void CAclTrans::OnTransing(int nMsg) +{ + m_nMsgTransing = nMsg; +} + +void CAclTrans::OnTransEnd(int nMsg) +{ + m_nMsgTransEnd = nMsg; +} + +void *CAclTrans::RunThread(void *arg) +{ + CAclTrans *pAclTrans = (CAclTrans*) arg; + + pAclTrans->ScanPath(&pAclTrans->m_sPath); + ::PostMessage(pAclTrans->m_hWnd, pAclTrans->m_nMsgTransEnd, 0, 0); + return NULL; +} + +void CAclTrans::Run(BOOL bTrans) +{ + acl_pthread_t tid; + + m_bTrans = bTrans; + if (m_sPath.GetLength() == 0) + return; + acl_pthread_create(&tid, NULL, RunThread, this); +} + +void CAclTrans::Restore(char *psBuf) +{ + char *pTagBegin, *ptr, *pBegin; + int len = (int) strlen("_acl"); + + while (1) + { + pTagBegin = strcasestr(psBuf, "_acl"); + if (pTagBegin == NULL) + break; + if (strncmp(pTagBegin, "_acl", len) == 0) + { + if (*(pTagBegin + 1) == '.' && *(pTagBegin + 2) == 'h') + { + // skip "lib_acl.h" + psBuf = pTagBegin + len; + continue; + } + ptr = pTagBegin; + pBegin = NULL; + while (ptr >= psBuf) + { + if (*ptr == '>') { + if (pBegin == NULL) + pBegin = ptr + 1; + break; + } + if (*ptr == '<') { + pBegin = NULL; + break; + } + if (*ptr == ' ' || *ptr == '\t' + || *ptr == '\r' || *ptr == '\n' + || *ptr == '*' || *ptr == '(' + || *ptr == '{') + { + if (pBegin == NULL) + pBegin = ptr + 1; + } + ptr--; + } + if (pBegin == NULL) { + psBuf = pTagBegin + len; + continue; + } + + memcpy(pBegin + len, pBegin, pTagBegin - pBegin); + memcpy(pBegin, "acl_", len); + psBuf = pTagBegin + len; + } + else if (strncmp(pTagBegin, "_ACL", len) == 0) + { + ptr = pTagBegin; + pBegin = NULL; + while (ptr >= psBuf) + { + if (*ptr == '>') { + if (pBegin == NULL) + pBegin = ptr + 1; + break; + } + if (*ptr == '<') { + pBegin = NULL; + break; + } + if (*ptr == ' ' || *ptr == '\t' + || *ptr == '\r' || *ptr == '\n' + || *ptr == '*' || *ptr == '(' + || *ptr == '{') + { + if (pBegin == NULL) + pBegin = ptr + 1; + } + ptr--; + } + if (pBegin == NULL) { + psBuf = pTagBegin + len; + continue; + } + memcpy(pBegin + len, pBegin, pTagBegin - pBegin); + memcpy(pBegin, "ACL_", len); + psBuf = pTagBegin + len; + } + else + psBuf = pTagBegin + len; + } +} + +void CAclTrans::Trans(char *psBuf) +{ + char *pTagBegin, *pTagEnd, *pNextChar; + int len = (int) strlen("acl_"); + long int n; + + while (1) + { +AGAIN_TAG: + pTagBegin = strcasestr(psBuf, "acl_"); + if (pTagBegin == NULL) + break; + if (strncmp(pTagBegin, "acl_", len) == 0) + { + pNextChar = pTagBegin + len; + pTagEnd = pNextChar; + while (*pTagEnd) + { + if (*pTagEnd == '(') + break; + if (*pTagEnd == ' ' || *pTagEnd == '\t' + || *pTagEnd == '\r' || *pTagEnd == '\n' + || *pTagEnd == '.' || *pTagEnd == '\'' + || *pTagEnd == '\"') + { + psBuf = pTagEnd; + goto AGAIN_TAG; + } + pTagEnd++; + } + if (*pTagEnd == 0) { + psBuf = pTagEnd; + continue; + } + n = pTagEnd - pNextChar; + memcpy(pTagBegin, pNextChar, n); + memcpy(pTagBegin + n, "_acl", len); + psBuf = pTagEnd; + } + else if (strncmp(pTagBegin, "ACL_", len) == 0) + { + pNextChar = pTagBegin + len; + pTagEnd = pNextChar; + while (*pTagEnd) + { + if (*pTagEnd == ' ' || *pTagEnd == '\t' + || *pTagEnd == ';' || *pTagEnd == ')' + || *pTagEnd == '}' || *pTagEnd == '*') + break; + if (*pTagEnd == '\r' || *pTagEnd == '\n' + || *pTagEnd == '.' || *pTagEnd == '\'' + || *pTagEnd == '\"' || *pTagEnd == '(') + { + psBuf = pTagEnd; + goto AGAIN_TAG; + } + pTagEnd++; + } + if (*pTagEnd == 0) + { + psBuf = pTagEnd; + continue; + } + n = pTagEnd - pNextChar; + memcpy(pTagBegin, pNextChar, n); + memcpy(pTagBegin + n, "_ACL", len); + psBuf = pTagEnd; + } + else + psBuf += len; + } +} + +int CAclTrans::TransFile(const char *psPath) +{ + char *sBuf = NULL; + size_t iLen; + +#undef RETURN +#define RETURN(_x_) do \ +{ \ + if (sBuf) \ + acl_myfree(sBuf); \ + return(_x_); \ +} while(0); + + sBuf = acl_vstream_loadfile(psPath); + if (sBuf == NULL || *sBuf == 0) + RETURN (-1); + + iLen = strlen(sBuf); + if (m_bTrans) + Trans(sBuf); // 开始转换 + else if (strstr(psPath, ".html") != NULL) + Restore(sBuf); + else + RETURN (0); + + ACL_VSTREAM *fp; + int ret; + + fp = acl_vstream_fopen(psPath, O_RDWR | O_TRUNC | O_BINARY | O_APPEND, 0600, 1024); + if (fp == NULL) + RETURN (-1); + ret = acl_vstream_writen(fp, sBuf, iLen); + acl_vstream_close(fp); + RETURN (ret == ACL_VSTREAM_EOF ? -1 : 0); +} + +int CAclTrans::ScanPath(CString *psPath) +{ + ACL_SCAN_DIR *scan_src; + + scan_src = acl_scan_dir_open(psPath->GetString(), 1); + if (scan_src == NULL) + { + CString msg; + + msg.Format("Open src path %s error", psPath->GetString()); + MessageBox(NULL, msg, "Open path", 0); + return (-1); + } + + while (1) + { + const char *fName; + CString fPath; + + fName = acl_scan_dir_next_file(scan_src); + if (fName == NULL) + break; + fPath = acl_scan_dir_path(scan_src); + fPath += "\\"; + fPath += fName; + TransFile(fPath.GetString()); + } + acl_scan_dir_close(scan_src); + return (0); +} diff --git a/app/jencode/AclTrans.h b/app/jencode/AclTrans.h new file mode 100644 index 000000000..95e9bc43a --- /dev/null +++ b/app/jencode/AclTrans.h @@ -0,0 +1,27 @@ +#pragma once + +class CAclTrans +{ +public: + CAclTrans(void); + ~CAclTrans(void); + CAclTrans(HWND hWnd, CString &sPath); + void Init(HWND hWnd, CString &sPath); + void Run(BOOL bTrans = TRUE); +public: + void OnTransing(int nMsg); + void OnTransEnd(int nMsg); +private: + HWND m_hWnd; + CString m_sPath; + int m_nMsgTransing; + int m_nMsgTransEnd; + BOOL m_bTrans; + + static void *RunThread(void *arg); + + int ScanPath(CString *psPath); + int TransFile(const char *psPath); + void Trans(char *psBuf); + void Restore(char *psBuf); +}; diff --git a/app/jencode/DelBOM.cpp b/app/jencode/DelBOM.cpp new file mode 100644 index 000000000..1a876f978 --- /dev/null +++ b/app/jencode/DelBOM.cpp @@ -0,0 +1,150 @@ +#include "StdAfx.h" +#include "DelBom.h" + +CDelBOM::CDelBOM(void) +: m_nMsgDeleting(0) +, m_nMsgDeleted(0) +, m_hWnd(0) +, m_sPath(_T("")) +{ +} + +CDelBOM::~CDelBOM(void) +{ +} + +void CDelBOM::Init(HWND hWnd, CString &sPath) +{ + m_hWnd = hWnd; + m_sPath = sPath; +} + +void CDelBOM::Run(void) +{ + acl_pthread_t tid; + + if (m_sPath.GetLength() == 0) + { + MessageBox(NULL, "文件路径为空!", "Error", 0); + ::PostMessage(m_hWnd, m_nMsgDeleted, 0, 0); + return; + } + + acl_pthread_create(&tid, NULL, RunThread, this); +} + +void CDelBOM::OnDeleting(int nMsg) +{ + m_nMsgDeleting = nMsg; +} + +void CDelBOM::OnDeleted(int nMsg) +{ + m_nMsgDeleted = nMsg; +} + +bool CDelBOM::DeleteBOM(CString& filePath) +{ + char* sBuf; + + sBuf = acl_vstream_loadfile(filePath); + if (sBuf == NULL) + return false; + size_t len = strlen(sBuf); + if (len < 3) + { + acl_myfree(sBuf); + return false; + } + + // 先判断文件内容前缀是否是BOM格式 + if (sBuf[0] != (char) 0xEF || sBuf[1] != (char) 0xBB || sBuf[2] != (char) 0xBF) + { + acl_myfree(sBuf); + return false; + } + + // 将内容指针偏移 3 个字节,即去掉BOM格式 + len -= 3; + char* ptr = sBuf + 3; + + ACL_VSTREAM* fp = acl_vstream_fopen(filePath, + O_WRONLY | O_APPEND | O_TRUNC, 0600, 4096); + if (fp == NULL) + { + acl_myfree(sBuf); + return false; + } + else if (len == 0) + { + acl_vstream_fclose(fp); + acl_myfree(sBuf); + return true; + } + else if (acl_vstream_writen(fp, ptr, len) == ACL_VSTREAM_EOF) + { + acl_msg_error("write to file: %s error: %s", + filePath.GetString(), acl_last_serror()); + } + + acl_vstream_fclose(fp); + acl_myfree(sBuf); + return true; +} + +void* CDelBOM::RunThread(void *arg) +{ + CDelBOM* pDel = (CDelBOM*) arg; + + ACL_SCAN_DIR *scan = acl_scan_dir_open(pDel->m_sPath.GetString(), 1); + if (scan == NULL) + { + CString msg; + msg.Format("Open path %s error", pDel->m_sPath.GetString()); + MessageBox(NULL, msg, "Open path", 0); + ::PostMessage(pDel->m_hWnd, pDel->m_nMsgDeleted, 0, 0); + return NULL; + } + + while (true) + { + const char* pFile = acl_scan_dir_next_file(scan); + if (pFile == NULL) + break; + + // 过滤掉非纯文本的文件 + if (acl_strrncasecmp(pFile, ".c", 2) && + acl_strrncasecmp(pFile, ".cpp", 4) && + acl_strrncasecmp(pFile, ".cxx", 4) && + acl_strrncasecmp(pFile, ".h", 2) && + acl_strrncasecmp(pFile, ".hpp", 4) && + acl_strrncasecmp(pFile, ".hxx", 4) && + acl_strrncasecmp(pFile, ".java", 5) && + acl_strrncasecmp(pFile, ".txt", 4) && + acl_strrncasecmp(pFile, ".php", 4) && + acl_strrncasecmp(pFile, ".html", 5) && + acl_strrncasecmp(pFile, ".js", 3) && + acl_strrncasecmp(pFile, ".css", 4) && + acl_strrncasecmp(pFile, ".d", 2) && + acl_strrncasecmp(pFile, ".py", 3) && + acl_strrncasecmp(pFile, ".perl", 5) && + acl_strrncasecmp(pFile, ".cs", 3) && + acl_strrncasecmp(pFile, ".as", 3)) + { + acl_msg_info(">>skip file: %s", pFile); + continue; + } + CString filePath = acl_scan_dir_path(scan); + filePath += "\\"; + filePath += pFile; + if (pDel->DeleteBOM(filePath) == true) + acl_msg_info(">>modify file %s", filePath.GetString()); + else + acl_msg_info(">>skip file %s", filePath.GetString()); + } + + acl_scan_dir_close(scan); + ::PostMessage(pDel->m_hWnd, pDel->m_nMsgDeleted, 0, 0); + acl_msg_info(">>scan over, msg: %d", pDel->m_nMsgDeleted); + return NULL; +} diff --git a/app/jencode/DelBOM.h b/app/jencode/DelBOM.h new file mode 100644 index 000000000..7288251d4 --- /dev/null +++ b/app/jencode/DelBOM.h @@ -0,0 +1,23 @@ +#pragma once + +class CDelBOM +{ +public: + CDelBOM(void); + ~CDelBOM(void); + + void Init(HWND hWnd, CString &sPath); + void Run(void); + void OnDeleting(int nMsg); + void OnDeleted(int nMsg); + +private: + HWND m_hWnd; + CString m_sPath; + int m_nMsgDeleting; + int m_nMsgDeleted; + + bool DeleteBOM(CString& filePath); + static void *RunThread(void *arg); +}; + diff --git a/app/jencode/Gb2Utf8.cpp b/app/jencode/Gb2Utf8.cpp new file mode 100644 index 000000000..02153d45d --- /dev/null +++ b/app/jencode/Gb2Utf8.cpp @@ -0,0 +1,128 @@ +#include "StdAfx.h" +#include "Gb2Utf8.h" + +CGb2Utf8::CGb2Utf8(void) +: m_hWnd(0) +, m_sPath(_T("")) +, m_dPath(_T("")) +{ +} + +CGb2Utf8::~CGb2Utf8(void) +{ +} + +CGb2Utf8::CGb2Utf8(HWND hWnd, CString &sPath, CString &dPath) +{ + Init(hWnd, sPath, dPath); +} + +void CGb2Utf8::Init(HWND hWnd, CString &sPath, CString &dPath) +{ + m_hWnd =hWnd; + m_sPath = sPath; + m_dPath = dPath; +} + +void CGb2Utf8::OnTransing(int nMsg) +{ + m_nMsgTransing = nMsg; +} + +void CGb2Utf8::OnTransEnd(int nMsg) +{ + m_nMsgTransEnd = nMsg; +} + +int CGb2Utf8::TransformPath(CString *pFrom, CString *pTo) +{ + ACL_SCAN_DIR *scan_src; //, *scan_dst; + + scan_src = acl_scan_dir_open(pFrom->GetString(), 1); + if (scan_src == NULL) { + CString msg; + + msg.Format("Open src path %s error", pFrom->GetString()); + MessageBox(NULL, msg, "Open path", 0); + return (-1); + } + //scan_dst = acl_scan_dir_open(to.GetString(), 1); + //if (scan_dst == NULL) { + // MessageBox(NULL, "Open path", "Open dst path error", 0); + // return (-1); + //} + + while (1) + { + const char *fName; + CString fPath; + + fName = acl_scan_dir_next_file(scan_src); + if (fName == NULL) + break; + fPath = acl_scan_dir_path(scan_src); + fPath += "\\"; + fPath += fName; + TransformFile(fPath.GetString(), NULL); + } + acl_scan_dir_close(scan_src); + return (0); +} + +int CGb2Utf8::TransformFile(const char *pFrom, const char *pTo) +{ + char *sBuf = NULL; + size_t iLen; + const char *toCode = "utf-8", *fromCode = "gb2312"; + +#undef RETURN +#define RETURN(_x_) do \ +{ \ + if (sBuf) \ + acl_myfree(sBuf); \ + return(_x_); \ +} while(0); + + sBuf = acl_vstream_loadfile(pFrom); + if (sBuf == NULL) + RETURN (-1); + if (*sBuf == 0) + RETURN (-1); + + iLen = strlen(sBuf); + + acl::charset_conv conv; + acl::string buf; + if (conv.convert(fromCode, toCode, sBuf, iLen, &buf) == false) + { + logger_error("conver from %s to %s error: %s", + fromCode, toCode, conv.serror()); + RETURN (-1); + } + + ACL_VSTREAM *fp; + fp = acl_vstream_fopen(pFrom, O_RDWR | O_TRUNC | O_BINARY | O_APPEND, 0600, 1024); + if (fp == NULL) + RETURN (-1); + int ret = acl_vstream_writen(fp, buf.c_str(), buf.length()); + acl_vstream_close(fp); + RETURN (ret == ACL_VSTREAM_EOF ? -1 : 0); +} + +void *CGb2Utf8::RunThread(void *arg) +{ + CGb2Utf8 *pGb2Utf8 = (CGb2Utf8*) arg; + + pGb2Utf8->TransformPath(&pGb2Utf8->m_sPath, &pGb2Utf8->m_dPath); + ::PostMessage(pGb2Utf8->m_hWnd, pGb2Utf8->m_nMsgTransEnd, 0, 0); + return NULL; +} + +void CGb2Utf8::Run(void) +{ + acl_pthread_t tid; + + if (m_dPath.GetLength() == 0 || m_sPath.GetLength() == 0) + return; + acl_pthread_create(&tid, NULL, RunThread, this); +} diff --git a/app/jencode/Gb2Utf8.h b/app/jencode/Gb2Utf8.h new file mode 100644 index 000000000..10280e13b --- /dev/null +++ b/app/jencode/Gb2Utf8.h @@ -0,0 +1,25 @@ +#pragma once + +class CGb2Utf8 +{ +public: + CGb2Utf8(HWND hWnd, CString &sPath, CString &dPath); + CGb2Utf8(void); + void Init(HWND hWnd, CString &sPath, CString &dPath); + ~CGb2Utf8(void); + + void Run(void); + int TransformPath(CString *pFrom, CString *pTo); + int TransformFile(const char *pFrom, const char *pTo); +private: + HWND m_hWnd; + CString m_sPath; + CString m_dPath; + int m_nMsgTransing; + int m_nMsgTransEnd; + + static void *RunThread(void *arg); +public: + void OnTransing(int nMsg); + void OnTransEnd(int nMsg); +}; diff --git a/app/jencode/IdxTrans.cpp b/app/jencode/IdxTrans.cpp new file mode 100644 index 000000000..6901a78c1 --- /dev/null +++ b/app/jencode/IdxTrans.cpp @@ -0,0 +1,177 @@ +#include "StdAfx.h" +#include "IdxTrans.h" + +CIdxTrans::CIdxTrans(void) +: m_nMsgTransing(0) +, m_nMsgTransEnd(0) +, m_hWnd(0) +, m_sPath(_T("")) +{ +} + +CIdxTrans::~CIdxTrans(void) +{ +} + +void CIdxTrans::Init(HWND hWnd, CString &sPath) +{ + m_hWnd = hWnd; + m_sPath = sPath; +} + +void CIdxTrans::Run(void) +{ + acl_pthread_t tid; + + if (m_sPath.GetLength() == 0) + return; + acl_pthread_create(&tid, NULL, RunThread, this); +} + +void CIdxTrans::OnTransing(int nMsg) +{ + m_nMsgTransing = nMsg; +} + +void CIdxTrans::OnTransEnd(int nMsg) +{ + m_nMsgTransEnd = nMsg; +} + +void CIdxTrans::Trans(void) +{ + char *sBuf; + size_t size, size_saved; + struct acl_stat stat_buf; + + if (m_sPath.GetLength() == 0) + { + MessageBox(NULL, "文件路径为空!", "Error", 0); + return; + } + if (acl_stat(m_sPath, &stat_buf) < 0) + { + MessageBox(NULL, "无法获得文件长度!", "Error", 0); + return; + } + size = (size_t) stat_buf.st_size; + size_saved = size; + + sBuf = acl_vstream_loadfile(m_sPath); + if (sBuf == NULL) + return; + + char *ptr, *pBuf = sBuf; + + ptr = pBuf; + while (1) + { + if (size <= 4) + break; + if (*ptr == '_' && *(ptr + 1) == 'a' && *(ptr + 2) == 'c' && *(ptr + 3) == 'l') + { + char *ptr1 = ptr, *pBegin = NULL; + + while (ptr1 > pBuf) + { + char ch = *(ptr1 - 1); + + if (ch == 'p') + { + if (ptr1 - 2 <= pBuf) + break; + ch = *(ptr1 - 2); + if ((ch >= 'a' && ch <= 'z') || ch == '_' || ch == ' ') + { + ptr1--; + } + else + { + pBegin = ptr1; + break; + } + } + else if (ch == 'L' || ch == 'X') + { + pBegin = ptr1; + break; + } + else if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') + || ch == '1' || ch == '2' || ch == '_') + { + ptr1--; + } + else + { + pBegin = ptr1; + break; + } + } + if (pBegin != NULL) + { + memcpy(pBegin + 4, pBegin, ptr - pBegin); + memcpy(pBegin, "acl_", 4); + pBuf = ptr + 4; + } + ptr += 4; + size -= 4; + } + else if (*ptr == '_' && *(ptr + 1) == 'A' && *(ptr + 2) == 'C' && *(ptr + 3) == 'L') + { + char *ptr1 = ptr, *pBegin = NULL; + + while (ptr1 > pBuf) + { + char ch = *(ptr1 - 1); + if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') + || ch == '1' || ch == '2' || ch == '_') + { + ptr1--; + } + else + { + pBegin = ptr1; + break; + } + } + if (pBegin != NULL) + { + memcpy(pBegin + 4, pBegin, ptr - pBegin); + memcpy(pBegin, "ACL_", 4); + pBuf = ptr + 4; + } + ptr += 4; + size -= 4; + } + else + { + ptr++; + size--; + } + } + + ACL_VSTREAM *fp; + + fp = acl_vstream_fopen("result.idx", O_CREAT | O_TRUNC | O_RDWR | O_BINARY, 0600, 1024); + if (fp == NULL) + { + MessageBox(NULL, "创建文件失败!", "Error", 0); + } + else + { + if (acl_vstream_writen(fp, sBuf, size_saved) == ACL_VSTREAM_EOF) { + MessageBox(NULL, "写文件失败!", "Error", 0); + } + acl_vstream_close(fp); + } + acl_myfree(sBuf); +} + +void *CIdxTrans::RunThread(void *arg) +{ + CIdxTrans *pIdxTrans = (CIdxTrans*) arg; + + pIdxTrans->Trans(); + ::PostMessage(pIdxTrans->m_hWnd, pIdxTrans->m_nMsgTransEnd, 0, 0); + return (NULL); +} \ No newline at end of file diff --git a/app/jencode/IdxTrans.h b/app/jencode/IdxTrans.h new file mode 100644 index 000000000..c6d6d4b75 --- /dev/null +++ b/app/jencode/IdxTrans.h @@ -0,0 +1,21 @@ +#pragma once + +class CIdxTrans +{ +public: + CIdxTrans(void); + ~CIdxTrans(void); + void Init(HWND hWnd, CString &sPath); + void Run(void); + void OnTransing(int nMsg); + void OnTransEnd(int nMsg); + +private: + HWND m_hWnd; + CString m_sPath; + int m_nMsgTransing; + int m_nMsgTransEnd; + + void Trans(void); + static void *RunThread(void *arg); +}; diff --git a/app/jencode/Jencode.cpp b/app/jencode/Jencode.cpp new file mode 100644 index 000000000..6d774cedd --- /dev/null +++ b/app/jencode/Jencode.cpp @@ -0,0 +1,73 @@ +// Jencode.cpp : 定义应用程序的类行为。 +// + +#include "stdafx.h" +#include "Jencode.h" +#include "JencodeDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#endif + + +// CJencodeApp + +BEGIN_MESSAGE_MAP(CJencodeApp, CWinApp) + ON_COMMAND(ID_HELP, CWinApp::OnHelp) +END_MESSAGE_MAP() + + +// CJencodeApp 构造 + +CJencodeApp::CJencodeApp() +{ + // TODO: 在此处添加构造代码, + // 将所有重要的初始化放置在 InitInstance 中 +} + + +// 唯一的一个 CJencodeApp 对象 + +CJencodeApp theApp; + + +// CJencodeApp 初始化 + +BOOL CJencodeApp::InitInstance() +{ + // 如果一个运行在 Windows XP 上的应用程序清单指定要 + // 使用 ComCtl32.dll 版本 6 或更高版本来启用可视化方式, + //则需要 InitCommonControls()。否则,将无法创建窗口。 + InitCommonControls(); + + CWinApp::InitInstance(); + + AfxEnableControlContainer(); + + // 标准初始化 + // 如果未使用这些功能并希望减小 + // 最终可执行文件的大小,则应移除下列 + // 不需要的特定初始化例程 + // 更改用于存储设置的注册表项 + // TODO: 应适当修改该字符串, + // 例如修改为公司或组织名 + SetRegistryKey(_T("应用程序向导生成的本地应用程序")); + + CJencodeDlg dlg; + m_pMainWnd = &dlg; + INT_PTR nResponse = dlg.DoModal(); + if (nResponse == IDOK) + { + // TODO: 在此放置处理何时用“确定”来关闭 + //对话框的代码 + } + else if (nResponse == IDCANCEL) + { + // TODO: 在此放置处理何时用“取消”来关闭 + //对话框的代码 + } + + // 由于对话框已关闭,所以将返回 FALSE 以便退出应用程序, + // 而不是启动应用程序的消息泵。 + return FALSE; +} diff --git a/app/jencode/Jencode.h b/app/jencode/Jencode.h new file mode 100644 index 000000000..42619269b --- /dev/null +++ b/app/jencode/Jencode.h @@ -0,0 +1,31 @@ +// Jencode.h : PROJECT_NAME 应用程序的主头文件 +// + +#pragma once + +#ifndef __AFXWIN_H__ + #error 在包含用于 PCH 的此文件之前包含“stdafx.h” +#endif + +#include "resource.h" // 主符号 + + +// CJencodeApp: +// 有关此类的实现,请参阅 Jencode.cpp +// + +class CJencodeApp : public CWinApp +{ +public: + CJencodeApp(); + +// 重写 + public: + virtual BOOL InitInstance(); + +// 实现 + + DECLARE_MESSAGE_MAP() +}; + +extern CJencodeApp theApp; diff --git a/app/jencode/Jencode.rc b/app/jencode/Jencode.rc new file mode 100644 index 000000000..60a6c77e0 --- /dev/null +++ b/app/jencode/Jencode.rc @@ -0,0 +1,210 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// 中文(中华人民共和国) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) +#ifdef _WIN32 +LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED +#pragma code_page(936) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "#define _AFX_NO_SPLITTER_RESOURCES\r\n" + "#define _AFX_NO_OLE_RESOURCES\r\n" + "#define _AFX_NO_TRACKER_RESOURCES\r\n" + "#define _AFX_NO_PROPERTY_RESOURCES\r\n" + "\r\n" + "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)\r\n" + "LANGUAGE 4, 2\r\n" + "#pragma code_page(936)\r\n" + "#include ""res\\Jencode.rc2"" // 非 Microsoft Visual C++ 编辑过的资源\r\n" + "#include ""afxres.rc"" // 标准组件\r\n" + "#endif\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDR_MAINFRAME ICON "res\\Jencode.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_ABOUTBOX DIALOGEX 0, 0, 235, 55 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | + WS_SYSMENU +CAPTION "关于 Jencode" +FONT 9, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + ICON IDR_MAINFRAME,IDC_STATIC,11,17,20,20 + LTEXT "Jencode Version 1.0",IDC_STATIC,40,10,119,8,SS_NOPREFIX + LTEXT "Copyright (C) 2008",IDC_STATIC,40,25,119,8 + DEFPUSHBUTTON "确定",IDOK,178,7,50,16,WS_GROUP +END + +IDD_JENCODE_DIALOG DIALOGEX 0, 0, 319, 189 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_POPUP | + WS_VISIBLE | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_APPWINDOW +CAPTION "Jencode" +FONT 9, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + DEFPUSHBUTTON "退出",IDOK,230,153,50,16 + PUSHBUTTON "转换成UTF8",IDC_BUTTON_TRAN,69,66,50,14 + EDITTEXT IDC_EDIT_SPATH,70,45,151,14,ES_AUTOHSCROLL + PUSHBUTTON "浏览...",IDC_BUTTON2,237,44,31,14 + LTEXT "转换目录:",IDC_STATIC,24,46,39,9 + PUSHBUTTON "ACL转换",IDC_ACL_TRANS,126,67,50,14 + PUSHBUTTON "ACL恢复",IDC_ACL_RESTORE,126,83,50,14 + EDITTEXT IDC_IDX_PATH,73,119,150,14,ES_AUTOHSCROLL + PUSHBUTTON "浏览...",IDC_IDX_SELECT,236,118,31,14 + GROUPBOX "文件转换",IDC_STATIC,17,19,269,84 + PUSHBUTTON "索引转换",IDC_TRANS_IDX,29,119,37,13 + LTEXT "注意:在转换后,源文件数据将会被改变,所以强烈建议在转换前先备份源文件!", + IDC_STATIC,24,31,256,8 + PUSHBUTTON "去掉BOM",IDC_DEL_BOM,69,82,50,14 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "080403a8" + BEGIN + VALUE "CompanyName", "TODO: <公司名>" + VALUE "FileDescription", "TODO: <文件说明>" + VALUE "FileVersion", "1.0.0.1" + VALUE "InternalName", "Jencode.exe" + VALUE "LegalCopyright", "TODO: (C) <公司名>。保留所有权利。" + VALUE "OriginalFilename", "Jencode.exe" + VALUE "ProductName", "TODO: <产品名>" + VALUE "ProductVersion", "1.0.0.1" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "翻译", 0x804, 936 + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_ABOUTBOX, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 228 + TOPMARGIN, 7 + BOTTOMMARGIN, 48 + END + + IDD_JENCODE_DIALOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 312 + TOPMARGIN, 7 + BOTTOMMARGIN, 182 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + IDS_ABOUTBOX "关于 Jencode(&A)..." +END + +#endif // 中文(中华人民共和国) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +#define _AFX_NO_SPLITTER_RESOURCES +#define _AFX_NO_OLE_RESOURCES +#define _AFX_NO_TRACKER_RESOURCES +#define _AFX_NO_PROPERTY_RESOURCES + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) +LANGUAGE 4, 2 +#pragma code_page(936) +#include "res\Jencode.rc2" // 非 Microsoft Visual C++ 编辑过的资源 +#include "afxres.rc" // 标准组件 +#endif + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/app/jencode/Jencode.sln b/app/jencode/Jencode.sln new file mode 100644 index 000000000..5743bed32 --- /dev/null +++ b/app/jencode/Jencode.sln @@ -0,0 +1,48 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Jencode", "Jencode.vcproj", "{5CEAFE4B-8A09-4FFE-8005-CD3131486D05}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + {FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lib_acl_cpp", "..\..\lib_acl_cpp\lib_acl_cpp_vc2003.vcproj", "{6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lib_acl", "..\..\lib_acl\lib_acl_vc2003.vcproj", "{B40213C2-507C-4C7F-A6E1-B850C9BDC27B}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lib_protocol", "..\..\lib_protocol\lib_protocol_vc2003.vcproj", "{FE724EF7-3763-4E78-BDF5-BCBC075719FD}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Release = Release + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {5CEAFE4B-8A09-4FFE-8005-CD3131486D05}.Debug.ActiveCfg = Debug|Win32 + {5CEAFE4B-8A09-4FFE-8005-CD3131486D05}.Debug.Build.0 = Debug|Win32 + {5CEAFE4B-8A09-4FFE-8005-CD3131486D05}.Release.ActiveCfg = Release|Win32 + {5CEAFE4B-8A09-4FFE-8005-CD3131486D05}.Release.Build.0 = Release|Win32 + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.Debug.ActiveCfg = DebugDll|Win32 + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.Debug.Build.0 = DebugDll|Win32 + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.Release.ActiveCfg = Releasedll|Win32 + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.Release.Build.0 = Releasedll|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Debug.ActiveCfg = DebugDll|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Debug.Build.0 = DebugDll|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Release.ActiveCfg = ReleaseDll|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Release.Build.0 = ReleaseDll|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Debug.ActiveCfg = DebugDll|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Debug.Build.0 = DebugDll|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Release.ActiveCfg = ReleaseDll|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Release.Build.0 = ReleaseDll|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/app/jencode/Jencode.vcproj b/app/jencode/Jencode.vcproj new file mode 100644 index 000000000..77894244b --- /dev/null +++ b/app/jencode/Jencode.vcproj @@ -0,0 +1,227 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/jencode/JencodeDlg.cpp b/app/jencode/JencodeDlg.cpp new file mode 100644 index 000000000..0bc0da7cb --- /dev/null +++ b/app/jencode/JencodeDlg.cpp @@ -0,0 +1,396 @@ +// JencodeDlg.cpp : 实现文件 +// + +#include "stdafx.h" +#include "Jencode.h" +#include "Gb2Utf8.h" +#include "AclTrans.h" +#include "IdxTrans.h" +#include "JencodeDlg.h" +#include "DelBOM.h" +#include "JencodeDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#endif + +#define WM_USER_TRANS_OVER WM_USER + 100 +#define WM_USER_TRANS_OVER2 WM_USER + 101 + +// 用于应用程序“关于”菜单项的 CAboutDlg 对话框 + +class CAboutDlg : public CDialog +{ +public: + CAboutDlg(); + +// 对话框数据 + enum { IDD = IDD_ABOUTBOX }; + + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 + +// 实现 +protected: + DECLARE_MESSAGE_MAP() +}; + +CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) +{ +} + +void CAboutDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); +} + +BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) +END_MESSAGE_MAP() + + +// CJencodeDlg 对话框 + + + +CJencodeDlg::CJencodeDlg(CWnd* pParent /*=NULL*/) + : CDialog(CJencodeDlg::IDD, pParent) + , m_sIdxPath(_T("")) + , m_fsPath(_T("")) +{ + m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); +} + +void CJencodeDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); +} + +BEGIN_MESSAGE_MAP(CJencodeDlg, CDialog) + ON_WM_SYSCOMMAND() + ON_WM_PAINT() + ON_WM_QUERYDRAGICON() + //}}AFX_MSG_MAP + ON_BN_CLICKED(IDC_BUTTON_TRAN, OnBnClickedButtonTran) + ON_BN_CLICKED(IDC_BUTTON2, OnBnClickedButton2) + ON_BN_CLICKED(IDC_BUTTON3, OnBnClickedButton3) + ON_MESSAGE(WM_USER_TRANS_OVER, OnTransOver) + ON_MESSAGE(WM_USER_TRANS_OVER2, OnTransOver2) + ON_BN_CLICKED(IDC_ACL_TRANS, OnBnClickedAclTrans) + ON_BN_CLICKED(IDC_ACL_RESTORE, OnBnClickedAclRestore) + ON_BN_CLICKED(IDC_IDX_SELECT, OnBnClickedIdxSelect) + ON_BN_CLICKED(IDC_TRANS_IDX, OnBnClickedTransIdx) + ON_BN_CLICKED(IDC_DEL_BOM, OnBnClickedDelBom) +END_MESSAGE_MAP() + + +// CJencodeDlg 消息处理程序 + +BOOL CJencodeDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + // 将\“关于...\”菜单项添加到系统菜单中。 + + // IDM_ABOUTBOX 必须在系统命令范围内。 + ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); + ASSERT(IDM_ABOUTBOX < 0xF000); + + CMenu* pSysMenu = GetSystemMenu(FALSE); + if (pSysMenu != NULL) + { + CString strAboutMenu; + strAboutMenu.LoadString(IDS_ABOUTBOX); + if (!strAboutMenu.IsEmpty()) + { + pSysMenu->AppendMenu(MF_SEPARATOR); + pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); + } + } + + // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动 + // 执行此操作 + SetIcon(m_hIcon, TRUE); // 设置大图标 + SetIcon(m_hIcon, FALSE); // 设置小图标 + + // TODO: 在此添加额外的初始化代码 + + acl_msg_open("jencode.log", "jencode"); + + // 添加状态栏 + int aWidths[2] = {50, -1}; + m_wndStatus.Create(WS_CHILD | WS_VISIBLE | WS_BORDER + | CCS_BOTTOM | SBARS_SIZEGRIP, + CRect(0,0,0,0), this, 0); + m_wndStatus.SetParts(2, aWidths); + m_wndStatus.SetText("就绪", 0, 0); + m_wndStatus.SetText("", 1, 0); + return TRUE; // 除非设置了控件的焦点,否则返回 TRUE +} + +void CJencodeDlg::OnSysCommand(UINT nID, LPARAM lParam) +{ + if ((nID & 0xFFF0) == IDM_ABOUTBOX) + { + CAboutDlg dlgAbout; + dlgAbout.DoModal(); + } + else + { + CDialog::OnSysCommand(nID, lParam); + } +} + +// 如果向对话框添加最小化按钮,则需要下面的代码 +// 来绘制该图标。对于使用文档/视图模型的 MFC 应用程序, +// 这将由框架自动完成。 + +void CJencodeDlg::OnPaint() +{ + if (IsIconic()) + { + CPaintDC dc(this); // 用于绘制的设备上下文 + + SendMessage(WM_ICONERASEBKGND, reinterpret_cast(dc.GetSafeHdc()), 0); + + // 使图标在工作矩形中居中 + int cxIcon = GetSystemMetrics(SM_CXICON); + int cyIcon = GetSystemMetrics(SM_CYICON); + CRect rect; + GetClientRect(&rect); + int x = (rect.Width() - cxIcon + 1) / 2; + int y = (rect.Height() - cyIcon + 1) / 2; + + // 绘制图标 + dc.DrawIcon(x, y, m_hIcon); + } + else + { + CDialog::OnPaint(); + } +} + +//当用户拖动最小化窗口时系统调用此函数取得光标显示。 +HCURSOR CJencodeDlg::OnQueryDragIcon() +{ + return static_cast(m_hIcon); +} + +void CJencodeDlg::ButtonsEnable(void) +{ + GetDlgItem(IDC_BUTTON_TRAN)->EnableWindow(TRUE); + GetDlgItem(IDC_ACL_TRANS)->EnableWindow(TRUE); + GetDlgItem(IDC_ACL_RESTORE)->EnableWindow(TRUE); + GetDlgItem(IDC_DEL_BOM)->EnableWindow(TRUE); +} + +BOOL CJencodeDlg::CheckPath(void) +{ + UpdateData(TRUE); + GetDlgItem(IDC_EDIT_SPATH)->GetWindowText(m_sPath); + if (m_sPath.GetLength() == 0) + { + MessageBox("请选择源目录..."); + return FALSE; + } + + m_dPath = m_sPath; + + //GetDlgItem(IDC_EDIT_DPATH)->GetWindowText(m_dPath); + //if (m_dPath.GetLength() == 0) + //{ + // MessageBox("请选择目的目录..."); + // return FALSE; + //} + + return TRUE; +} + +void CJencodeDlg::ButtonsDisable(void) +{ + GetDlgItem(IDC_BUTTON_TRAN)->EnableWindow(FALSE); + GetDlgItem(IDC_ACL_TRANS)->EnableWindow(FALSE); + GetDlgItem(IDC_ACL_RESTORE)->EnableWindow(FALSE); + GetDlgItem(IDC_DEL_BOM)->EnableWindow(FALSE); +} + +void CJencodeDlg::OnBnClickedButtonTran() +{ + // TODO: 在此添加控件通知处理程序代码 + if (!CheckPath()) + return; + + static CGb2Utf8 gb2Utf8; + + gb2Utf8.Init(this->GetSafeHwnd(), m_sPath, m_dPath); + gb2Utf8.OnTransEnd(WM_USER_TRANS_OVER); + gb2Utf8.Run(); + m_wndStatus.SetText("运行", 0, 0); + m_nBegin = time(NULL); + ButtonsDisable(); +} + +void CJencodeDlg::OnBnClickedButton2() +{ + // TODO: 在此添加控件通知处理程序代码 + CString sPath; + BROWSEINFO bi; + char name[MAX_PATH]; + ZeroMemory(&bi, sizeof(BROWSEINFO)); + + bi.hwndOwner = GetSafeHwnd(); + bi.pszDisplayName = name; + bi.lpszTitle = "Select folder"; + bi.ulFlags = BIF_RETURNONLYFSDIRS; + LPITEMIDLIST idl = SHBrowseForFolder(&bi); + if(idl == NULL) + return; + SHGetPathFromIDList(idl, sPath.GetBuffer(MAX_PATH)); + + sPath.ReleaseBuffer(); + + if (sPath.Right(1) != "\\") + { + sPath += "\\"; + } + + GetDlgItem(IDC_EDIT_SPATH)->SetWindowText(sPath); +// CFileDialog file(TRUE,"文件","result.txt",OFN_HIDEREADONLY,"FILE(*.*)|*.*||",NULL); +// if(file.DoModal()==IDOK) +// { +// CString pathname; +// +// pathname=file.GetPathName(); +// GetDlgItem(IDC_EDIT_SPATH)->SetWindowText(pathname); +// } +} + +void CJencodeDlg::OnBnClickedButton3() +{ + // TODO: 在此添加控件通知处理程序代码 + CString sPath; + BROWSEINFO bi; + char name[MAX_PATH]; + ZeroMemory(&bi, sizeof(BROWSEINFO)); + + bi.hwndOwner = GetSafeHwnd(); + bi.pszDisplayName = name; + bi.lpszTitle = "Select folder"; + bi.ulFlags = BIF_RETURNONLYFSDIRS; + LPITEMIDLIST idl = SHBrowseForFolder(&bi); + if(idl == NULL) + return; + SHGetPathFromIDList(idl, sPath.GetBuffer(MAX_PATH)); + + sPath.ReleaseBuffer(); + + if (sPath.Right(1) != "\\") + { + sPath += "\\"; + } + + GetDlgItem(IDC_EDIT_DPATH)->SetWindowText(sPath); +} + +afx_msg LRESULT CJencodeDlg::OnTransOver(WPARAM uID, LPARAM lEvent) +{ + CString msg; + + ButtonsEnable(); + msg.Format("耗时:%d 秒", time(NULL) - m_nBegin); + m_wndStatus.SetText("完成", 0, 0); + m_wndStatus.SetText(msg, 1, 0); + return (0); +} + +afx_msg LRESULT CJencodeDlg::OnTransOver2(WPARAM uID, LPARAM lEvent) +{ + CString msg; + + GetDlgItem(IDC_TRANS_IDX)->EnableWindow(TRUE); + msg.Format("耗时:%d 秒", time(NULL) - m_nBegin); + m_wndStatus.SetText("完成!", 0, 0); + m_wndStatus.SetText(msg, 1, 0); + return (0); +} + +void CJencodeDlg::OnBnClickedAclTrans() +{ + // TODO: 在此添加控件通知处理程序代码 + if (!CheckPath()) + return; + + static CAclTrans aclTrans; + + aclTrans.Init(this->GetSafeHwnd(), m_sPath); + aclTrans.OnTransEnd(WM_USER_TRANS_OVER); + aclTrans.Run(); + m_wndStatus.SetText("运行", 0, 0); + m_nBegin = time(NULL); + ButtonsDisable(); +} + +void CJencodeDlg::OnBnClickedAclRestore() +{ + // TODO: 在此添加控件通知处理程序代码 + if (!CheckPath()) + return; + + static CAclTrans aclTrans; + + aclTrans.Init(this->GetSafeHwnd(), m_sPath); + aclTrans.OnTransEnd(WM_USER_TRANS_OVER); + aclTrans.Run(FALSE); + m_wndStatus.SetText("运行", 0, 0); + m_nBegin = time(NULL); + ButtonsDisable(); +} + +void CJencodeDlg::OnBnClickedDelBom() +{ + // TODO: 在此添加控件通知处理程序代码 + if (!CheckPath()) + return; + + static CDelBOM delBom; + + delBom.Init(this->GetSafeHwnd(), m_sPath); + delBom.OnDeleted(WM_USER_TRANS_OVER); + delBom.Run(); + m_wndStatus.SetText("运行", 0, 0); + m_nBegin = time(NULL); + ButtonsDisable(); +} + +void CJencodeDlg::OnBnClickedIdxSelect() +{ + // TODO: 在此添加控件通知处理程序代码 + CFileDialog file(TRUE,"文件","search.idx",OFN_HIDEREADONLY,"FILE(*.*)|*.*||",NULL); + if(file.DoModal()==IDOK) + { + CString pathname; + + pathname=file.GetPathName(); + GetDlgItem(IDC_IDX_PATH)->SetWindowText(pathname); + } +} + +void CJencodeDlg::OnBnClickedTransIdx() +{ + // TODO: 在此添加控件通知处理程序代码 + static CIdxTrans idxTrans; + + UpdateData(TRUE); + GetDlgItem(IDC_IDX_PATH)->GetWindowText(m_fsPath); + if (m_fsPath.GetLength() == 0) + { + MessageBox("请选择索引文件..."); + return; + } + + GetDlgItem(IDC_TRANS_IDX)->EnableWindow(FALSE); + idxTrans.Init(this->GetSafeHwnd(), m_fsPath); + idxTrans.OnTransEnd(WM_USER_TRANS_OVER2); + idxTrans.Run(); + m_wndStatus.SetText("运行", 0, 0); + m_nBegin = time(NULL); +} diff --git a/app/jencode/JencodeDlg.h b/app/jencode/JencodeDlg.h new file mode 100644 index 000000000..badb770ac --- /dev/null +++ b/app/jencode/JencodeDlg.h @@ -0,0 +1,53 @@ +// JencodeDlg.h : 头文件 +// + +#pragma once +#include + +// CJencodeDlg 对话框 +class CJencodeDlg : public CDialog +{ +// 构造 +public: + CJencodeDlg(CWnd* pParent = NULL); // 标准构造函数 + +// 对话框数据 + enum { IDD = IDD_JENCODE_DIALOG }; + + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 + + +// 实现 +protected: + HICON m_hIcon; + + CStatusBarCtrl m_wndStatus; + // 生成的消息映射函数 + virtual BOOL OnInitDialog(); + afx_msg void OnSysCommand(UINT nID, LPARAM lParam); + afx_msg void OnPaint(); + afx_msg HCURSOR OnQueryDragIcon(); + DECLARE_MESSAGE_MAP() +public: + afx_msg void OnBnClickedButtonTran(); + afx_msg void OnBnClickedButton2(); + afx_msg void OnBnClickedButton3(); + afx_msg LRESULT OnTransOver(WPARAM uID, LPARAM lEvent); + afx_msg LRESULT OnTransOver2(WPARAM uID, LPARAM lEvent); +private: + time_t m_nBegin; + BOOL CheckPath(void); + void ButtonsEnable(void); + void ButtonsDisable(void); + CString m_sPath, m_dPath; +public: + afx_msg void OnBnClickedAclTrans(); + afx_msg void OnBnClickedAclRestore(); + afx_msg void OnBnClickedIdxSelect(); + afx_msg void OnBnClickedTransIdx(); +private: + CString m_sIdxPath, m_fsPath; +public: + afx_msg void OnBnClickedDelBom(); +}; diff --git a/app/jencode/ReadMe.txt b/app/jencode/ReadMe.txt new file mode 100644 index 000000000..e26a965e6 --- /dev/null +++ b/app/jencode/ReadMe.txt @@ -0,0 +1,82 @@ +================================================================================ + MICROSOFT 基础类库: Jencode 项目概述 +=============================================================================== + +应用程序向导已为您创建了此 Jencode 应用程序。此应用程序 +不仅介绍了使用 Microsoft 基础类的基本知识, +而且是编写应用程序的起点。 + +此文件包含组成 Jencode 应用程序的每个文件的内容摘要。 + +Jencode.vcproj + 这是使用“应用程序向导”生成的 VC++ 项目的主项目文件。 + 它包含有关生成文件的 Visual C++ 版本的信息,以及 + 有关用“应用程序向导”所选择的平台、配置和 + 项目功能的信息。 + +Jencode.h + 这是应用程序的主头文件。 它包含其他 + 项目特定的头文件(包括 Resource.h),并声明 + CJencodeApp 应用程序类。 + +Jencode.cpp + 这是包含应用程序 + 类 CJencodeApp 的主应用程序源文件。 + +Jencode.rc + 这是程序使用的所有 Microsoft Windows 资源 + 的列表。 它包含存储在 RES 子目录中 + 的图标、位图和光标。 可直接在 Microsoft + Visual C++ 中编辑此文件。 项目资源包含在 2052 中。 + +res\Jencode.ico + 这是一个图标文件,用作应用程序的图标。 此 + 图标包含在主资源文件 Jencode.rc 中。 + +res\Jencode.rc2 + 此文件包含不由 Microsoft + Visual C++ 编辑的资源。 应将所有不能由 + 资源编辑器编辑的资源放在此文件中。 + +///////////////////////////////////////////////////////////////////////////// + +应用程序向导将创建一个对话框类: +JencodeDlg.h、JencodeDlg.cpp - 对话框 + 这些文件包含 CJencodeDlg 类。 此类定义 + 应用程序主对话框的行为。 此对话框的模板包含在 + Jencode.rc 中,而此文件可以在 Microsoft Visual C++ 中进行编辑。 +///////////////////////////////////////////////////////////////////////////// + +其他功能: + +ActiveX 控件 + 应用程序支持使用 ActiveX 控件。 +///////////////////////////////////////////////////////////////////////////// + +其他标准文件: + +StdAfx.h、StdAfx.cpp + 这些文件用于生成名为 Jencode.pch 的预编译头文件 (PCH) + 和名为 StdAfx.obj 的预编译类型文件。 + +Resource.h + 这是标准头文件,它定义新资源 ID。 + Microsoft Visual C++ 将读取并更新此文件。 + +///////////////////////////////////////////////////////////////////////////// + +其他说明: + +应用程序向导使用“TODO:” 来指示 +应添加或自定义的源代码部分。 + +如果应用程序在共享 DLL 中使用 MFC,且应用程序使用的语言不是 +操作系统的当前语言,则需要从 Microsoft Visual C++ 光盘上 +Win\System 目录下将相应的本地化资源 MFC70XXX.DLL +复制到计算机的 system 或 system32 目录下, +并将其重命名为 MFCLOC.DLL。 (“XXX”代表 +语言缩写。 例如,MFC70DEU.DLL 包含翻译成 +德语的资源。) 如果不这样做,应用程序的某些 UI 元素 +将保留为操作系统的语言。 + +///////////////////////////////////////////////////////////////////////////// diff --git a/app/jencode/res/Jencode.ico b/app/jencode/res/Jencode.ico new file mode 100644 index 000000000..8a84ca3d3 Binary files /dev/null and b/app/jencode/res/Jencode.ico differ diff --git a/app/jencode/res/Jencode.rc2 b/app/jencode/res/Jencode.rc2 new file mode 100644 index 000000000..560272445 --- /dev/null +++ b/app/jencode/res/Jencode.rc2 @@ -0,0 +1,13 @@ +// +// Jencode.RC2 - Microsoft Visual C++ 不会直接编辑的资源 +// + +#ifdef APSTUDIO_INVOKED +#error 此文件不能由 Microsoft Visual C++ 编辑 +#endif //APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// 在此处添加手动编辑的资源... + +///////////////////////////////////////////////////////////////////////////// diff --git a/app/jencode/resource.h b/app/jencode/resource.h new file mode 100644 index 000000000..a03b3212e --- /dev/null +++ b/app/jencode/resource.h @@ -0,0 +1,35 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by Jencode.rc +// +#define IDM_ABOUTBOX 0x0010 +#define IDD_ABOUTBOX 100 +#define IDS_ABOUTBOX 101 +#define IDD_JENCODE_DIALOG 102 +#define IDR_MAINFRAME 128 +#define IDC_BUTTON_TRAN 1000 +#define IDC_EDIT_SPATH 1001 +#define IDC_BUTTON2 1002 +#define IDC_BUTTON3 1003 +#define IDC_EDIT2 1004 +#define IDC_EDIT_DPATH 1004 +#define IDC_IDX_SELECT 1005 +#define IDC_ACL_TRANS 1006 +#define IDC_BUTTON4 1007 +#define IDC_ACL_RESTORE 1007 +#define IDC_EDIT1 1008 +#define IDC_IDX_PATH 1008 +#define IDC_TRANS_IDX 1009 +#define IDC_BUTTON1 1010 +#define IDC_DEL_BOM 1010 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 129 +#define _APS_NEXT_COMMAND_VALUE 32771 +#define _APS_NEXT_CONTROL_VALUE 1011 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/app/jencode/stdafx.cpp b/app/jencode/stdafx.cpp new file mode 100644 index 000000000..134ea7c61 --- /dev/null +++ b/app/jencode/stdafx.cpp @@ -0,0 +1,7 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// Jencode.pch 将是预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + + diff --git a/app/jencode/stdafx.h b/app/jencode/stdafx.h new file mode 100644 index 000000000..99bd632fa --- /dev/null +++ b/app/jencode/stdafx.h @@ -0,0 +1,44 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是经常使用但不常更改的 +// 项目特定的包含文件 + +#pragma once + +#ifndef VC_EXTRALEAN +#define VC_EXTRALEAN // 从 Windows 标头中排除不常使用的资料 +#endif + +// 如果您必须使用下列所指定的平台之前的平台,则修改下面的定义。 +// 有关不同平台的相应值的最新信息,请参考 MSDN。 +#ifndef WINVER // 允许使用 Windows 95 和 Windows NT 4 或更高版本的特定功能。 +#define WINVER 0x0400 //为 Windows98 和 Windows 2000 及更新版本改变为适当的值。 +#endif + +#ifndef _WIN32_WINNT // 允许使用 Windows NT 4 或更高版本的特定功能。 +#define _WIN32_WINNT 0x0400 //为 Windows98 和 Windows 2000 及更新版本改变为适当的值。 +#endif + +#ifndef _WIN32_WINDOWS // 允许使用 Windows 98 或更高版本的特定功能。 +#define _WIN32_WINDOWS 0x0410 //为 Windows Me 及更新版本改变为适当的值。 +#endif + +#ifndef _WIN32_IE // 允许使用 IE 4.0 或更高版本的特定功能。 +#define _WIN32_IE 0x0400 //为 IE 5.0 及更新版本改变为适当的值。 +#endif + +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // 某些 CString 构造函数将是显式的 + +// 关闭 MFC 对某些常见但经常被安全忽略的警告消息的隐藏 +#define _AFX_ALL_WARNINGS + +#include // MFC 核心和标准组件 +#include // MFC 扩展 +#include // MFC 自动化类 + +#include // Internet Explorer 4 公共控件的 MFC 支持 +#ifndef _AFX_NO_AFXCMN_SUPPORT +#include // Windows 公共控件的 MFC 支持 +#endif // _AFX_NO_AFXCMN_SUPPORT + +#include "lib_acl.h" +#include "acl_cpp/lib_acl.hpp" diff --git a/app/net_tools/127ip.txt b/app/net_tools/127ip.txt new file mode 100644 index 000000000..7b9ad531d --- /dev/null +++ b/app/net_tools/127ip.txt @@ -0,0 +1 @@ +127.0.0.1 diff --git a/app/net_tools/HttpOption.htm b/app/net_tools/HttpOption.htm new file mode 100644 index 000000000..6602225f4 --- /dev/null +++ b/app/net_tools/HttpOption.htm @@ -0,0 +1,20 @@ + + + + + + + + + + + +
+
+ +
+TODO: 在此放置控件。 +
+ + + \ No newline at end of file diff --git a/app/net_tools/NetOption.cpp b/app/net_tools/NetOption.cpp new file mode 100644 index 000000000..73926b2a2 --- /dev/null +++ b/app/net_tools/NetOption.cpp @@ -0,0 +1,225 @@ +// NetOption.cpp : 实现文件 +// + +#include "stdafx.h" +#include "net_tools.h" +#include "NetOption.h" +#include ".\netoption.h" + + +// CNetOption 对话框 + +IMPLEMENT_DYNAMIC(CNetOption, CDialog) + +CNetOption::CNetOption(CWnd* pParent /*=NULL*/) + : CDialog(CNetOption::IDD, pParent) + , m_smtpPort(25) + , m_pop3Port(110) +{ + +} + +CNetOption::~CNetOption() +{ +} + +void CNetOption::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + DDX_Text(pDX, IDC_SMTP_ADDR, m_smtpAddr); + DDX_Text(pDX, IDC_SMTP_PORT, m_smtpPort); + DDX_Text(pDX, IDC_POP3_ADDR, m_pop3Addr); + DDX_Text(pDX, IDC_POP3_PORT, m_pop3Port); + DDX_Text(pDX, IDC_USER_ACCOUNT, m_userAccount); + DDX_Text(pDX, IDC_USER_PASSWD, m_userPasswd); + DDX_Text(pDX, IDC_RECIPIENTS, m_recipients); +} + +BOOL CNetOption::OnInitDialog() +{ + if (m_smtpAddr.IsEmpty()) + GetDlgItem(IDC_STATIC_SMTP_ADDR)->SetWindowText("X"); + else + GetDlgItem(IDC_STATIC_SMTP_ADDR)->SetWindowText("√"); + if (m_pop3Addr.IsEmpty()) + GetDlgItem(IDC_STATIC_POP3_ADDR)->SetWindowText("X"); + else + GetDlgItem(IDC_STATIC_POP3_ADDR)->SetWindowText("√"); + if (m_userAccount.IsEmpty()) + GetDlgItem(IDC_STATIC_USER)->SetWindowText("X"); + else + GetDlgItem(IDC_STATIC_USER)->SetWindowText("√"); + if (m_userPasswd.IsEmpty()) + GetDlgItem(IDC_STATIC_PASS)->SetWindowText("X"); + else + GetDlgItem(IDC_STATIC_PASS)->SetWindowText("√"); + if (m_recipients.IsEmpty()) + GetDlgItem(IDC_STATIC_RECIPIENTS)->SetWindowText("X"); + else + GetDlgItem(IDC_STATIC_RECIPIENTS)->SetWindowText("√"); + + if (m_smtpAddr.IsEmpty()) + GetDlgItem(IDC_SMTP_ADDR)->SetFocus(); + else if (m_pop3Addr.IsEmpty()) + GetDlgItem(IDC_POP3_ADDR)->SetFocus(); + else if (m_userAccount.IsEmpty()) + GetDlgItem(IDC_USER_ACCOUNT)->SetFocus(); + else if (m_userPasswd.IsEmpty()) + GetDlgItem(IDC_USER_PASSWD)->SetFocus(); + else if (m_recipients.IsEmpty()) + GetDlgItem(IDC_RECIPIENTS)->SetFocus(); + + return FALSE; +} + +BEGIN_MESSAGE_MAP(CNetOption, CDialog) + ON_WM_PAINT() + ON_WM_CREATE() + ON_EN_KILLFOCUS(IDC_USER_ACCOUNT, OnEnKillfocusUserAccount) + ON_EN_KILLFOCUS(IDC_SMTP_ADDR, OnEnKillfocusSmtpAddr) + ON_EN_KILLFOCUS(IDC_POP3_ADDR, OnEnKillfocusPop3Addr) + ON_EN_KILLFOCUS(IDC_USER_PASSWD, OnEnKillfocusUserPasswd) + ON_EN_KILLFOCUS(IDC_RECIPIENTS, OnEnKillfocusRecipients) + ON_BN_CLICKED(IDCANCEL, OnBnClickedCancel) + ON_BN_CLICKED(IDOK, OnBnClickedOk) +END_MESSAGE_MAP() + +CNetOption& CNetOption::SetSmtpAddr(const char* addr, int port) +{ + m_smtpAddr = addr; + m_smtpPort = port; + return *this; +} + +CNetOption& CNetOption::SetPop3Addr(const char* addr, int port) +{ + m_pop3Addr = addr; + m_pop3Port = port; + return *this; +} + +CNetOption& CNetOption::SetUserAccount(const char* s) +{ + m_userAccount = s; + return *this; +} + +CNetOption& CNetOption::SetUserPasswd(const char* s) +{ + m_userPasswd = s; + return *this; +} + +CNetOption& CNetOption::SetRecipients(const char* s) +{ + if (s == NULL || *s == 0) + return *this; + + ACL_ARGV* tokens = acl_argv_split(s, ",;,; \t\r\n"); + ACL_ITER iter; + acl::string buf; + acl_foreach(iter, tokens) + { + if (iter.i > 0) + buf << ";\r\n"; + buf << (char*) iter.data; + } + acl_argv_free(tokens); + m_recipients = buf.c_str(); + return *this; +} + +void CNetOption::OnPaint() +{ + CPaintDC dc(this); // device context for painting + // TODO: 在此处添加消息处理程序代码 + // 不为绘图消息调用 CDialog::OnPaint() + UpdateData(FALSE); +} + +int CNetOption::OnCreate(LPCREATESTRUCT lpCreateStruct) +{ + if (CDialog::OnCreate(lpCreateStruct) == -1) + return -1; + + // TODO: 在此添加您专用的创建代码 + + return 0; +} + +void CNetOption::OnEnKillfocusSmtpAddr() +{ + // TODO: 在此添加控件通知处理程序代码 + UpdateData(TRUE); + if (m_smtpAddr.IsEmpty()) + { + GetDlgItem(IDC_STATIC_SMTP_ADDR)->SetWindowText("X"); + GetDlgItem(IDC_SMTP_ADDR)->SetFocus(); + } + else + GetDlgItem(IDC_STATIC_SMTP_ADDR)->SetWindowText("√"); +} + +void CNetOption::OnEnKillfocusPop3Addr() +{ + // TODO: 在此添加控件通知处理程序代码 + UpdateData(TRUE); + if (m_pop3Addr.IsEmpty()) + { + GetDlgItem(IDC_STATIC_POP3_ADDR)->SetWindowText("X"); + GetDlgItem(IDC_POP3_ADDR)->SetFocus(); + } + else + GetDlgItem(IDC_STATIC_POP3_ADDR)->SetWindowText("√"); +} + +void CNetOption::OnEnKillfocusUserAccount() +{ + // TODO: 在此添加控件通知处理程序代码 + UpdateData(TRUE); + if (m_userAccount.IsEmpty()) + { + GetDlgItem(IDC_STATIC_USER)->SetWindowText("X"); + GetDlgItem(IDC_USER_ACCOUNT)->SetFocus(); + } + else + GetDlgItem(IDC_STATIC_USER)->SetWindowText("√"); +} + +void CNetOption::OnEnKillfocusUserPasswd() +{ + // TODO: 在此添加控件通知处理程序代码 + UpdateData(TRUE); + if (m_userPasswd.IsEmpty()) + { + GetDlgItem(IDC_STATIC_PASS)->SetWindowText("X"); + GetDlgItem(IDC_USER_PASSWD)->SetFocus(); + } + else + GetDlgItem(IDC_STATIC_PASS)->SetWindowText("√"); +} + +void CNetOption::OnEnKillfocusRecipients() +{ + // TODO: 在此添加控件通知处理程序代码 + UpdateData(TRUE); + if (m_userAccount.IsEmpty()) + { + GetDlgItem(IDC_STATIC_USER)->SetWindowText("X"); + GetDlgItem(IDC_RECIPIENTS)->SetFocus(); + } + else + GetDlgItem(IDC_STATIC_USER)->SetWindowText("√"); +} + +void CNetOption::OnBnClickedCancel() +{ + // TODO: 在此添加控件通知处理程序代码 + OnCancel(); +} + +void CNetOption::OnBnClickedOk() +{ + // TODO: 在此添加控件通知处理程序代码 + OnOK(); +} diff --git a/app/net_tools/NetOption.h b/app/net_tools/NetOption.h new file mode 100644 index 000000000..99135f37a --- /dev/null +++ b/app/net_tools/NetOption.h @@ -0,0 +1,78 @@ +#pragma once + + +// CNetOption 对话框 + +class CNetOption : public CDialog +{ + DECLARE_DYNAMIC(CNetOption) + +public: + CNetOption(CWnd* pParent = NULL); // 标准构造函数 + virtual ~CNetOption(); + +// 对话框数据 + enum { IDD = IDD_OPTION }; + +protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 + + // 生成的消息映射函数 + virtual BOOL OnInitDialog(); + + DECLARE_MESSAGE_MAP() + +public: + CNetOption& SetUserPasswd(const char* addr); + CNetOption& SetSmtpAddr(const char* addr, int port); + CNetOption& SetPop3Addr(const char* addr, int port); + CNetOption& SetUserAccount(const char* s); + CNetOption& SetRecipients(const char* s); + + const CString& GetSmtpAddr() const + { + return m_smtpAddr; + } + int getSmtpPort() const + { + return m_smtpPort; + } + const CString& GetPop3Addr() const + { + return m_pop3Addr; + } + int getPop3Port() const + { + return m_pop3Port; + } + const CString& GetUserAccount() const + { + return m_userAccount; + } + const CString& GetUserPasswd() const + { + return m_userPasswd; + } + const CString& GetRecipients() const + { + return m_recipients; + } +//private: + CString m_smtpAddr; + int m_smtpPort; + CString m_pop3Addr; + int m_pop3Port; + CString m_userAccount; + CString m_userPasswd; + CString m_recipients; +public: + afx_msg void OnPaint(); + afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); + afx_msg void OnEnKillfocusUserAccount(); + afx_msg void OnEnKillfocusSmtpAddr(); + afx_msg void OnEnKillfocusPop3Addr(); + afx_msg void OnEnKillfocusUserPasswd(); + afx_msg void OnEnKillfocusRecipients(); + afx_msg void OnBnClickedCancel(); + afx_msg void OnBnClickedOk(); +}; diff --git a/app/net_tools/OptionOnClose.cpp b/app/net_tools/OptionOnClose.cpp new file mode 100644 index 000000000..5920bfb2c --- /dev/null +++ b/app/net_tools/OptionOnClose.cpp @@ -0,0 +1,49 @@ +// OptionOnClose.cpp : 实现文件 +// + +#include "stdafx.h" +#include "net_tools.h" +#include "OptionOnClose.h" + + +// COptionOnClose 对话框 + +IMPLEMENT_DYNCREATE(COptionOnClose, CDialog) + +COptionOnClose::COptionOnClose(CWnd* pParent /*=NULL*/) +: CDialog(COptionOnClose::IDD, pParent) +, m_MinOnClose(TRUE) +, m_QuitClose(!m_MinOnClose) +, m_SaveOption(FALSE) +{ +} + +COptionOnClose::~COptionOnClose() +{ +} + +void COptionOnClose::init(BOOL QuitOnClose) +{ + m_QuitClose = QuitOnClose; + m_MinOnClose = !QuitOnClose; + //UpdateData(FALSE); +} + +void COptionOnClose::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + DDX_Check(pDX, IDC_QUIT_NO, m_MinOnClose); + DDX_Check(pDX, IDC_QUIT_YES, m_QuitClose); + DDX_Check(pDX, IDC_CHECK_SAVE, m_SaveOption); +} + +BOOL COptionOnClose::OnInitDialog() +{ + CDialog::OnInitDialog(); + return TRUE; // 除非将焦点设置到控件,否则返回 TRUE +} + +BEGIN_MESSAGE_MAP(COptionOnClose, CDialog) +END_MESSAGE_MAP() + + diff --git a/app/net_tools/OptionOnClose.h b/app/net_tools/OptionOnClose.h new file mode 100644 index 000000000..034b7ebbf --- /dev/null +++ b/app/net_tools/OptionOnClose.h @@ -0,0 +1,30 @@ +#pragma once +#include "afxwin.h" + + +// COptionOnClose 对话框 + +class COptionOnClose : public CDialog +{ + DECLARE_DYNCREATE(COptionOnClose) + +public: + COptionOnClose(CWnd* pParent = NULL); // 标准构造函数 + virtual ~COptionOnClose(); + + void init(BOOL QuitOnClose); + +// 对话框数据 + enum { IDD = IDD_DIALOG_QUIT}; + +protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 + virtual BOOL OnInitDialog(); + + DECLARE_MESSAGE_MAP() + +public: + BOOL m_QuitClose; + BOOL m_MinOnClose; + BOOL m_SaveOption; +}; diff --git a/app/net_tools/ReadMe.txt b/app/net_tools/ReadMe.txt new file mode 100644 index 000000000..170747a13 --- /dev/null +++ b/app/net_tools/ReadMe.txt @@ -0,0 +1,85 @@ +================================================================================ + MICROSOFT 基础类库: net_tools 项目概述 +=============================================================================== + +应用程序向导已为您创建了此 net_tools 应用程序。此应用程序 +不仅介绍了使用 Microsoft 基础类的基本知识, +而且是编写应用程序的起点。 + +此文件包含组成 net_tools 应用程序的每个文件的内容摘要。 + +net_tools.vcproj + 这是使用“应用程序向导”生成的 VC++ 项目的主项目文件。 + 它包含有关生成文件的 Visual C++ 版本的信息,以及 + 有关用“应用程序向导”所选择的平台、配置和 + 项目功能的信息。 + +net_tools.h + 这是应用程序的主头文件。 它包含其他 + 项目特定的头文件(包括 Resource.h),并声明 + Cnet_toolsApp 应用程序类。 + +net_tools.cpp + 这是包含应用程序 + 类 Cnet_toolsApp 的主应用程序源文件。 + +net_tools.rc + 这是程序使用的所有 Microsoft Windows 资源 + 的列表。 它包含存储在 RES 子目录中 + 的图标、位图和光标。 可直接在 Microsoft + Visual C++ 中编辑此文件。 项目资源包含在 2052 中。 + +res\net_tools.ico + 这是一个图标文件,用作应用程序的图标。 此 + 图标包含在主资源文件 net_tools.rc 中。 + +res\net_tools.rc2 + 此文件包含不由 Microsoft + Visual C++ 编辑的资源。 应将所有不能由 + 资源编辑器编辑的资源放在此文件中。 + +///////////////////////////////////////////////////////////////////////////// + +应用程序向导将创建一个对话框类: +net_toolsDlg.h、net_toolsDlg.cpp - 对话框 + 这些文件包含 Cnet_toolsDlg 类。 此类定义 + 应用程序主对话框的行为。 此对话框的模板包含在 + net_tools.rc 中,而此文件可以在 Microsoft Visual C++ 中进行编辑。 +///////////////////////////////////////////////////////////////////////////// + +其他功能: + +ActiveX 控件 + 应用程序支持使用 ActiveX 控件。 + +Windows 套接字 + 应用程序支持在 TCP/IP 网络上建立通讯。 +///////////////////////////////////////////////////////////////////////////// + +其他标准文件: + +StdAfx.h、StdAfx.cpp + 这些文件用于生成名为 net_tools.pch 的预编译头文件 (PCH) + 和名为 StdAfx.obj 的预编译类型文件。 + +Resource.h + 这是标准头文件,它定义新资源 ID。 + Microsoft Visual C++ 将读取并更新此文件。 + +///////////////////////////////////////////////////////////////////////////// + +其他说明: + +应用程序向导使用“TODO:” 来指示 +应添加或自定义的源代码部分。 + +如果应用程序在共享 DLL 中使用 MFC,且应用程序使用的语言不是 +操作系统的当前语言,则需要从 Microsoft Visual C++ 光盘上 +Win\System 目录下将相应的本地化资源 MFC70XXX.DLL +复制到计算机的 system 或 system32 目录下, +并将其重命名为 MFCLOC.DLL。 (“XXX”代表 +语言缩写。 例如,MFC70DEU.DLL 包含翻译成 +德语的资源。) 如果不这样做,应用程序的某些 UI 元素 +将保留为操作系统的语言。 + +///////////////////////////////////////////////////////////////////////////// diff --git a/app/net_tools/SingleCtrl.cpp b/app/net_tools/SingleCtrl.cpp new file mode 100644 index 000000000..fb873ebf8 --- /dev/null +++ b/app/net_tools/SingleCtrl.cpp @@ -0,0 +1,54 @@ +#include "stdafx.h" +#include "SingleCtrl.h" + +CSingleCtrl::CSingleCtrl(const char *pExeName) +{ + TRACE("%s\r\n", pExeName); + m_sExeName.Format("%s", pExeName); +} + +BOOL CSingleCtrl::Check() +{ + CWnd *pPrevWnd = CWnd::GetDesktopWindow()->GetWindow(GW_CHILD); + + ::CreateMutex(NULL, TRUE, m_sExeName.GetString()); + if (GetLastError() != ERROR_ALREADY_EXISTS) + return TRUE; + + while (pPrevWnd) + { + if (::GetProp(pPrevWnd->GetSafeHwnd(), m_sExeName.GetString())) + { + TRACE("Check: %s found\r\n", m_sExeName.GetString()); + if (pPrevWnd->IsIconic()) { + TRACE("Check: show it now\r\n"); + pPrevWnd->ShowWindow(SW_RESTORE); + } else + pPrevWnd->ShowWindow(SW_NORMAL); + pPrevWnd->SetForegroundWindow(); + pPrevWnd->GetLastActivePopup()->SetForegroundWindow(); + return FALSE; + } + + pPrevWnd = pPrevWnd->GetWindow(GW_HWNDNEXT); + } + + TRACE("Could not find previous instance main window!\r\n"); + return FALSE; +} + +void CSingleCtrl::Register() +{ + HWND hWnd = AfxGetApp()->m_pMainWnd->GetSafeHwnd(); + ASSERT(hWnd); + ::SetProp(hWnd, m_sExeName.GetString(), (HANDLE) 1); + TRACE("Register: %s\r\n", m_sExeName.GetString()); +} + +void CSingleCtrl::Remove() +{ + HWND hWnd = AfxGetApp()->m_pMainWnd->GetSafeHwnd(); + ASSERT(hWnd); + ::RemoveProp(hWnd, m_sExeName.GetString()); + TRACE("Remove: %s\r\n", m_sExeName.GetString()); +} \ No newline at end of file diff --git a/app/net_tools/SingleCtrl.h b/app/net_tools/SingleCtrl.h new file mode 100644 index 000000000..4ad114922 --- /dev/null +++ b/app/net_tools/SingleCtrl.h @@ -0,0 +1,19 @@ +#ifndef __SINGLECTRL_INCLUDE_H__ +#define __SINGLECTRL_INCLUDE_H__ + +class CSingleCtrl +{ +public: + CSingleCtrl(const char *pExeName); + ~CSingleCtrl() {}; + + BOOL Check(); + void Register(); + void Remove(); +protected: + CSingleCtrl() {}; +private: + CString m_sExeName; +}; + +#endif \ No newline at end of file diff --git a/app/net_tools/build/net_tools.iss b/app/net_tools/build/net_tools.iss new file mode 100644 index 000000000..8b088ab19 --- /dev/null +++ b/app/net_tools/build/net_tools.iss @@ -0,0 +1,64 @@ +; Script generated by the Inno Setup Script Wizard. +; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! + +#define MyAppName "net_tools" +#define MyAppVersion "1.0" +#define MyAppPublisher "二六三企业通讯, Inc." +#define MyAppURL "http://www.263.net/" +#define MyAppExeName "net_tools.exe" + +[Setup] +; NOTE: The value of AppId uniquely identifies this application. +; Do not use the same AppId value in installers for other applications. +; (To generate a new GUID, click Tools | Generate GUID inside the IDE.) +AppId={{CE95193B-3C76-4C21-91DE-8FEFED6F32EE} +AppName={#MyAppName} +AppVersion={#MyAppVersion} +;AppVerName={#MyAppName} {#MyAppVersion} +AppPublisher={#MyAppPublisher} +AppPublisherURL={#MyAppURL} +AppSupportURL={#MyAppURL} +AppUpdatesURL={#MyAppURL} +DefaultDirName={pf}\Acl Project\{#MyAppName} +DefaultGroupName= net_tools +AllowNoIcons=yes +PrivilegesRequired=admin +OutputDir=.\ +OutputBaseFilename=net_tools_setup +SetupIconFile=..\res\net_tools.ico +Compression=lzma +SolidCompression=yes + +[Languages] +Name: "chinesesimplified"; MessagesFile: "compiler:Languages\ChineseSimplified.isl" + +[Tasks] +Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked +Name: "quicklaunchicon"; Description: "{cm:CreateQuickLaunchIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked; OnlyBelowVersion: 0,6.1 + +[Files] +Source: "..\Release\net_tools.exe"; DestDir: "{app}"; Flags: ignoreversion +Source: "..\Release\lib_acl.dll"; DestDir: "{app}"; Flags: ignoreversion +Source: "..\Release\lib_acl_cpp.dll"; DestDir: "{app}"; Flags: ignoreversion +Source: "..\Release\lib_protocol.dll"; DestDir: "{app}"; Flags: ignoreversion +Source: "..\Release\net_tools.exe"; DestDir: "{app}"; Flags: ignoreversion +Source: "..\Release\sqlite3.dll"; DestDir: "{app}"; Flags: ignoreversion +Source: "..\Release\zlib.dll"; DestDir: "{app}"; Flags: ignoreversion +Source: "..\Release\263ip.txt"; DestDir: "{app}"; Flags: ignoreversion +Source: "..\Release\263domain.txt"; DestDir: "{app}"; Flags: ignoreversion +Source: "..\Release\ReadMe.txt"; DestDir: "{app}"; Flags: ignoreversion +; Source: "..\lib\IPHLPAPI.DLL"; DestDir: "{app}"; Flags: ignoreversion +Source: "..\lib\MFC71.dll"; DestDir: "{app}"; Flags: ignoreversion +Source: "..\lib\msvcp71.dll"; DestDir: "{app}"; Flags: ignoreversion +Source: "..\lib\msvcr71.dll"; DestDir: "{app}"; Flags: ignoreversion +; NOTE: Don't use "Flags: ignoreversion" on any shared system files + +[Icons] +Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}" +Name: "{group}\{cm:UninstallProgram,{#MyAppName}}"; Filename: "{uninstallexe}" +Name: "{commondesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon +Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: quicklaunchicon + +[Run] +Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent runascurrentuser + diff --git a/app/net_tools/build/net_tools_setup.exe b/app/net_tools/build/net_tools_setup.exe new file mode 100644 index 000000000..9c320914a Binary files /dev/null and b/app/net_tools/build/net_tools_setup.exe differ diff --git a/app/net_tools/dns/dns_store.cpp b/app/net_tools/dns/dns_store.cpp new file mode 100644 index 000000000..9e3331d82 --- /dev/null +++ b/app/net_tools/dns/dns_store.cpp @@ -0,0 +1,105 @@ +#include "StdAfx.h" +#include "global/global.h" +#include "nslookup.h" +#include "dns_store.h" + +dns_store::dns_store(std::vector* domain_list, + nslookup_callback& callback) +: domain_list_(domain_list) +, callback_(callback) +, ok_(false) +{ + +} + +dns_store::~dns_store() +{ + delete domain_list_; +} + +////////////////////////////////////////////////////////////////////////// +// 主线程过程 + +void dns_store::rpc_onover() +{ + logger("store domain lookup results %s!", ok_ ? "OK" : "Failed"); + callback_.nslookup_finish(dbpath_.empty() ? NULL : dbpath_.c_str()); + delete this; +} + +////////////////////////////////////////////////////////////////////////// +// 子线程过程 + +static const char* CREATE_TBL = +"create table dns_tbl\r\n" +"(\r\n" +"domain varchar(128) not null,\r\n" +"ip varchar(32) not null default '',\r\n" +"ttl integer not null default 0,\r\n" +"spent float(10,2) not null default 0.00,\r\n" +"primary key(domain, ip)\r\n" +");"; + +void dns_store::rpc_run() +{ + const char* path = global::get_instance().get_path(); + dbpath_.format("%s/dns_store_%ld.db", path, time(NULL)); + + acl::db_sqlite db(dbpath_.c_str()); + if (db.open() == false) + logger_error("open db: %s failed", dbpath_.c_str()); + else if (create_tbl(db) == false) + logger_error("create table failed for %s", dbpath_.c_str()); + else + { + logger("open db(%s) ok", dbpath_.c_str()); + insert_tbl(db); + ok_ = true; + } +} + +bool dns_store::create_tbl(acl::db_handle& db) +{ + if (db.tbl_exists("dns_tbl")) + { + logger("table exist"); + return (true); + } + else if (db.sql_update(CREATE_TBL) == false) + { + logger_error("sql(%s) error", CREATE_TBL); + return (false); + } + else + { + logger("create table dns_tbl ok"); + return (true); + } +} + +void dns_store::insert_tbl(acl::db_handle& db) +{ + std::vector::const_iterator cit = domain_list_->begin(); + for (; cit != domain_list_->end(); ++cit) + insert_one(db, *cit); +} + +void dns_store::insert_one(acl::db_handle& db, const domain_info* info) +{ + const std::vector& ip_list = info->get_ip_list(); + std::vector::const_iterator cit = ip_list.begin(); + acl::string sql; + for (; cit != ip_list.end(); ++cit) + { + sql.format("insert into dns_tbl(domain, ip, ttl, spent)" + " values('%s', '%s', '%d', '%.2f')", + info->get_domain(), (*cit)->ip, (*cit)->ttl, + info->get_spent()); + if (db.sql_update(sql.c_str()) == false) + logger_error("sql(%s) error", sql.c_str()); + else + logger("add ok, domain: %s, ip: %s, ttl: %d, spent: %0.2f", + info->get_domain(), (*cit)->ip, (*cit)->ttl, + info->get_spent()); + } +} \ No newline at end of file diff --git a/app/net_tools/dns/dns_store.h b/app/net_tools/dns/dns_store.h new file mode 100644 index 000000000..219db12ab --- /dev/null +++ b/app/net_tools/dns/dns_store.h @@ -0,0 +1,29 @@ +#pragma once +#include + +class domain_info; +class nslookup_callback; +class dns_store : public acl::rpc_request +{ +public: + dns_store(std::vector* domain_list, + nslookup_callback& callback); +protected: +private: + ~dns_store(); + + // 基类虚函数:子线程处理函数 + virtual void rpc_run(); + + // 基类虚函数:主线程处理过程,收到子线程任务完成的消息 + virtual void rpc_onover(); + +private: + bool ok_; + std::vector* domain_list_; + nslookup_callback& callback_; + acl::string dbpath_; + bool create_tbl(acl::db_handle& db); + void insert_tbl(acl::db_handle& db); + void insert_one(acl::db_handle& db, const domain_info* info); +}; \ No newline at end of file diff --git a/app/net_tools/dns/nslookup.cpp b/app/net_tools/dns/nslookup.cpp new file mode 100644 index 000000000..f738cc66a --- /dev/null +++ b/app/net_tools/dns/nslookup.cpp @@ -0,0 +1,210 @@ +#include "StdAfx.h" +#include "dns_store.h" +#include "global/util.h" +#include "rpc/rpc_manager.h" +#include "nslookup.h" + +////////////////////////////////////////////////////////////////////////// + +domain_info::domain_info(nslookup& ns, const char* domain) +: ns_(ns) +{ + ACL_SAFE_STRNCPY(domain_, domain, sizeof(domain_)); +} + +domain_info::~domain_info() +{ + std::vector::iterator it = ip_list_.begin(); + for (; it != ip_list_.end(); ++it) + acl_myfree(*it); +} + +void domain_info::add_ip(const char* ip, int ttl) +{ + IP_INFO* info = (IP_INFO*) acl_mycalloc(1, sizeof(IP_INFO)); + ACL_SAFE_STRNCPY(info->ip, ip, sizeof(info->ip)); + info->ttl = ttl; + ip_list_.push_back(info); +} + +void domain_info::set_begin() +{ + gettimeofday(&begin_, NULL); +} + +void domain_info::set_end() +{ + gettimeofday(&end_, NULL); +} + +double domain_info::get_spent() const +{ + return util::stamp_sub(&end_, &begin_); +} +////////////////////////////////////////////////////////////////////////// + +nslookup::nslookup(const char* filepath, nslookup_callback* callback, + const char* dns_ip, int dns_port, int timeout) + : filepath_(filepath) + , callback_(callback) + , dns_ip_(dns_ip) + , dns_port_(dns_port) + , timeout_(timeout) + , nresult_(0) + , domain_list_(NULL) +{ +} + +nslookup::~nslookup() +{ + if (domain_list_) + delete domain_list_; +} + +////////////////////////////////////////////////////////////////////////// +// 主线程运行 + +void nslookup::rpc_onover() +{ + callback_->nslookup_report(domain_list_->size(), + domain_list_->size()); + // 将结果存入数据库,同时将回调接口传入 + dns_store* ds = new dns_store(domain_list_, *callback_); + // 因为该变量已经被接管,所以此处需要置空以免被重复释放 + domain_list_ = NULL; + rpc_manager::get_instance().fork(ds); + delete this; +} + +void nslookup::rpc_wakeup(void*) +{ + callback_->nslookup_report(domain_list_->size(), nresult_); +} + +////////////////////////////////////////////////////////////////////////// +// 子线程运行 + +void nslookup::rpc_run() +{ + if (load_file() == true) + lookup_all(); +} + +bool nslookup::load_file() +{ + acl::ifstream in; + if (in.open_read(filepath_) == false) + { + logger_error("open file(%s) failed: %s", + filepath_.c_str(), acl::last_serror()); + return false; + } + + domain_list_ = new std::vector; + acl::string line; + while (in.eof() == false) + { + if (in.gets(line) == false) + break; + domain_info* di = new domain_info(*this, line.c_str()); + domain_list_->push_back(di); + } + + if (domain_list_->empty()) + { + logger_error("no ip in file %s", filepath_.c_str()); + return false; + } + return true; +} + +void nslookup::lookup_all() +{ + if (domain_list_ == NULL || domain_list_->empty()) + { + logger_error("domain empty"); + return; + } + + ACL_AIO *aio; + /* 创建非阻塞异步通信句柄 */ + aio = acl_aio_create(ACL_EVENT_SELECT); +// acl_aio_set_keep_read(aio, 0); + + // 创建 DNS 查询句柄 + ACL_DNS* dns = acl_dns_create(aio, timeout_); + acl_dns_add_dns(dns, dns_ip_.c_str(), dns_port_, 24); + + rpc_signal(NULL); + + time_t last_signal = time(NULL), t; + + // 添加目标 domain 地址 + std::vector::iterator it = domain_list_->begin(); + for (; it != domain_list_->end(); ++it) + { + (*it)->set_begin(); + acl_dns_lookup(dns, (*it)->get_domain(), dns_result, *it); + } + + while (1) { + /* 异步事件循环过程 */ + acl_aio_loop(aio); + + // 如果所有查询过程都完成,则退出异步事件循环过程 + if (nresult_ >= domain_list_->size()) + { + logger("DNS lookup over: %d, %d", + (int) domain_list_->size(), (int) nresult_); + break; + } + + t = time(NULL); + if (t - last_signal >= 1) + { + last_signal = t; + rpc_signal(NULL); + } + } + + /* 显示域名查询结果 */ + + acl_dns_close(dns); + + /* 销毁非阻塞句柄 */ + acl_aio_free(aio); +} + +void nslookup::dns_result(ACL_DNS_DB *dns_db, void *ctx, int errnum) +{ + domain_info* info = (domain_info*) ctx; + + info->set_end(); + if (dns_db == NULL) { + logger("ERROR: %s, domain: %s, spent: %0.2f", + acl_dns_serror(errnum), info->get_domain(), + info->get_spent()); + info->add_ip("0.0.0.0", 0); + info->get_nslookup().nresult_++; + return; + } + + ACL_ITER iter; + acl::string buf; + buf.format("OK, domain: %s, spent: %0.2f, ip_list: ", + info->get_domain(), info->get_spent()); + + // 遍历该域名的所有查询结果 + const ACL_HOST_INFO *hi; + acl_foreach(iter, dns_db) { + + hi = (const ACL_HOST_INFO*) iter.data; + if (iter.i > 0) + buf << ", "; + buf.format_append("ip=%s, ttl=%d", hi->ip, hi->ttl); + info->add_ip(hi->ip, hi->ttl); + } + + logger("%s", buf.c_str()); + info->get_nslookup().nresult_++; +} diff --git a/app/net_tools/dns/nslookup.h b/app/net_tools/dns/nslookup.h new file mode 100644 index 000000000..1c813c791 --- /dev/null +++ b/app/net_tools/dns/nslookup.h @@ -0,0 +1,94 @@ +#pragma once + +////////////////////////////////////////////////////////////////////////// + +class nslookup_callback +{ +public: + nslookup_callback() {} + virtual ~nslookup_callback() {} + + virtual void nslookup_report(size_t total, size_t curr) = 0; + virtual void nslookup_finish(const char* dbpath) = 0; +protected: +private: +}; + +////////////////////////////////////////////////////////////////////////// + +class nslookup; + +struct IP_INFO +{ + char ip[64]; + int ttl; +}; + +class domain_info +{ +public: + domain_info(nslookup& ns, const char* domain); + ~domain_info(); + + const char* get_domain() const + { + return domain_; + } + + double get_spent() const; + + void set_begin(); + void set_end(); + void add_ip(const char* ip, int ttl); + const std::vector& get_ip_list() const + { + return ip_list_; + } + +private: + // get_nslookup 函数只可以被 nslookup 类实例调用 + friend class nslookup; + nslookup& get_nslookup() const + { + return ns_; + } +private: + nslookup& ns_; + char domain_[256]; + struct timeval begin_; + struct timeval end_; + + std::vector ip_list_; +}; + +class nslookup : public acl::rpc_request +{ +public: + nslookup(const char* filepath, nslookup_callback* callback, + const char* dns_ip, int dns_port, int timeout); +protected: + ~nslookup(); + + // 基类虚函数:子线程处理函数 + virtual void rpc_run(); + + // 基类虚函数:主线程处理过程,收到子线程任务完成的消息 + virtual void rpc_onover(); + + // 基类虚函数:主线程处理过程,收到子线程的通知消息 + virtual void rpc_wakeup(void* ctx); + +private: + acl::string filepath_; + nslookup_callback* callback_; + acl::string dns_ip_; + int dns_port_; + int timeout_; + std::vector* domain_list_; + size_t nresult_; // 已经返回查询结果的个数 + + bool load_file(); + void lookup_all(); + + static void dns_result(ACL_DNS_DB *dns_db, void *ctx, int errnum); +}; diff --git a/app/net_tools/domain.txt b/app/net_tools/domain.txt new file mode 100644 index 000000000..1b063aa51 --- /dev/null +++ b/app/net_tools/domain.txt @@ -0,0 +1,2 @@ +www.263.com +www.sina.com.cn \ No newline at end of file diff --git a/app/net_tools/global/global.cpp b/app/net_tools/global/global.cpp new file mode 100644 index 000000000..365b24c29 --- /dev/null +++ b/app/net_tools/global/global.cpp @@ -0,0 +1,24 @@ +#include "StdAfx.h" +#include "global.h" + +global::global() +{ + const char* filepath = acl_process_path(); + ACL_VSTRING* path = acl_vstring_alloc(256); + acl_sane_dirname(path, filepath); + path_ = acl_vstring_str(path); + acl_vstring_free(path); +} + +global::~global() +{ + +} + +void global::get_filename(const char* filepath, acl::string& buf) +{ + ACL_VSTRING* bp = acl_vstring_alloc(256); + acl_sane_basename(bp, filepath); + buf = acl_vstring_str(bp); + acl_vstring_free(bp); +} \ No newline at end of file diff --git a/app/net_tools/global/global.h b/app/net_tools/global/global.h new file mode 100644 index 000000000..b1b62a896 --- /dev/null +++ b/app/net_tools/global/global.h @@ -0,0 +1,18 @@ +#pragma once + +class global : public acl::singleton +{ +public: + global(); + ~global(); + + const char* get_path() const + { + return path_.c_str(); + } + + static void get_filename(const char* filepath, acl::string& buf); +protected: +private: + acl::string path_; +}; \ No newline at end of file diff --git a/app/net_tools/global/passwd_crypt.cpp b/app/net_tools/global/passwd_crypt.cpp new file mode 100644 index 000000000..333ff0c23 --- /dev/null +++ b/app/net_tools/global/passwd_crypt.cpp @@ -0,0 +1,87 @@ +#include "StdAfx.h" +#include "polarssl/des.h" +#include "passwd_crypt.h" + +static const unsigned char des3_test_keys[24] = +{ + 0x11, 0x43, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, + 0x13, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, + 0x25, 0x47, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23 +}; + +static const unsigned char des3_test_iv[8] = +{ + 0x02, 0x04, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF, +}; + +char* passwd_crypt(const char* in) +{ + const char* myname = "passwd_crypt"; + des3_context ctx; + unsigned char iv[8]; + unsigned char* data, *result; + size_t len; + + if (des3_set3key_enc(&ctx, des3_test_keys) != 0) + { + acl_msg_error("%s: des3_set3key_enc error!", myname); + return NULL; + } + + len = strlen(in); + len += 8 - len % 8 + 8; + data = (unsigned char*) acl_mycalloc(1, len); + memcpy(data, in, len); + + memcpy(iv, des3_test_iv, 8); + + if (des3_crypt_cbc(&ctx, DES_ENCRYPT, len, iv, data, data) != 0) + { + acl_myfree(data); + acl_msg_error("%s: des3_crypt_cbc error!", myname); + return NULL; + } + result = acl_base64_encode((const char*) data, (int) len + 1); + acl_myfree(data); + return (char*) result; +} + +char* passwd_decrypt(const char* in) +{ + const char* myname = "passwd_decrypt"; + des3_context ctx; + unsigned char iv[8]; + unsigned char* buf; + char* data; + int n; + + if (des3_set3key_dec(&ctx, des3_test_keys) != 0) + { + acl_msg_error("%s: des3_set3key_dec error!", myname); + return NULL; + } + + n = acl_base64_decode(in, &data); + if (n < 0) + { + acl_msg_error("%s: acl_base64_decode error!", myname); + return NULL; + } + + memcpy(iv, des3_test_iv, 8); + + n += 8 - n % 8 + 8; + buf = (unsigned char*) acl_mycalloc(1, n); + memcpy(buf, data, n); + acl_myfree(data); + + if (des3_crypt_cbc(&ctx, DES_DECRYPT, n, iv, buf, buf) != 0) + { + acl_myfree(buf); + acl_msg_error("%s: des3_crypt_cbc error!", myname); + printf("n: %d\n", (int) n); + return NULL; + } + + return (char*) buf; +} diff --git a/app/net_tools/global/passwd_crypt.h b/app/net_tools/global/passwd_crypt.h new file mode 100644 index 000000000..efb0a412e --- /dev/null +++ b/app/net_tools/global/passwd_crypt.h @@ -0,0 +1,15 @@ +#ifndef __passwd_crypt_include_h__ +#define __passwd_crypt_include_h__ + +#ifdef __cplusplus +extern "C" { +#endif + +char* passwd_crypt(const char* in); +char* passwd_decrypt(const char* in); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/app/net_tools/global/util.cpp b/app/net_tools/global/util.cpp new file mode 100644 index 000000000..09546a874 --- /dev/null +++ b/app/net_tools/global/util.cpp @@ -0,0 +1,68 @@ +#include "StdAfx.h" +#include +#include +#include "util.h" + +static size_t collect(const FIXED_INFO *fi, std::vector& dns_list) +{ + const IP_ADDR_STRING* next = &fi->DnsServerList; + do + { + dns_list.push_back(next->IpAddress.String); + next = next->Next; + } while (next != NULL); + + return dns_list.size(); +} + +size_t util::get_dns(std::vector& dns_list) +{ + FIXED_INFO *fi; + ULONG n; + + n = sizeof(FIXED_INFO); + fi= (FIXED_INFO*) acl_mycalloc(1, n) ; + + DWORD ret = ::GetNetworkParams(fi, &n); + if (ret == ERROR_SUCCESS) + { + size_t n1 = collect(fi, dns_list); + acl_myfree(fi); + return n1; + } + else if (ret != ERROR_BUFFER_OVERFLOW) + { + acl_myfree(fi); + return 0; + } + + acl_myfree(fi); + fi= (FIXED_INFO*) acl_mycalloc(1, n); + + ret = ::GetNetworkParams(fi, &n); + if (ret != ERROR_SUCCESS) + { + acl_myfree(fi); + return 0; + } + + size_t n2 = collect(fi, dns_list); + acl_myfree(fi); + return n2; +} + +double util::stamp_sub(const struct timeval *from, const struct timeval *sub_by) +{ + struct timeval res; + + memcpy(&res, from, sizeof(struct timeval)); + + res.tv_usec -= sub_by->tv_usec; + if (res.tv_usec < 0) { + --res.tv_sec; + res.tv_usec += 1000000; + } + res.tv_sec -= sub_by->tv_sec; + + return (res.tv_sec * 1000.0 + res.tv_usec/1000.0); +} diff --git a/app/net_tools/global/util.h b/app/net_tools/global/util.h new file mode 100644 index 000000000..45eee7dcd --- /dev/null +++ b/app/net_tools/global/util.h @@ -0,0 +1,14 @@ +#pragma once + +class util +{ +public: + util() {} + ~util() {} + + static size_t get_dns(std::vector& dns_list); + static double stamp_sub(const struct timeval *from, + const struct timeval *sub_by); +protected: +private: +}; \ No newline at end of file diff --git a/app/net_tools/lib/MFC71.dll b/app/net_tools/lib/MFC71.dll new file mode 100644 index 000000000..2bf25e5a2 Binary files /dev/null and b/app/net_tools/lib/MFC71.dll differ diff --git a/app/net_tools/lib/msvcp71.dll b/app/net_tools/lib/msvcp71.dll new file mode 100644 index 000000000..9ed0d17e1 Binary files /dev/null and b/app/net_tools/lib/msvcp71.dll differ diff --git a/app/net_tools/lib/msvcr71.dll b/app/net_tools/lib/msvcr71.dll new file mode 100644 index 000000000..9d9e0286c Binary files /dev/null and b/app/net_tools/lib/msvcr71.dll differ diff --git a/app/net_tools/mail/mime_builder.cpp b/app/net_tools/mail/mime_builder.cpp new file mode 100644 index 000000000..6f626677e --- /dev/null +++ b/app/net_tools/mail/mime_builder.cpp @@ -0,0 +1,251 @@ +#include "StdAfx.h" +#include "global/global.h" +#include "mime_builder.hpp" + +mime_builder::mime_builder() +: body_text_(NULL) +, body_html_(NULL) +{ + +} + +mime_builder::~mime_builder() +{ + std::vector::iterator it = attachs_.begin(); + for (; it != attachs_.end(); ++it) + acl_myfree(*it); + if (body_text_) + acl_myfree(body_text_); + if (body_html_) + acl_myfree(body_html_); +} + +mime_builder& mime_builder::set_body_text(const char* src, size_t len) +{ + body_text_ = (char*) acl_mymemdup(src, len + 1); + body_text_[len] = 0; + return *this; +} + +mime_builder& mime_builder::set_body_html(const char* src, size_t len) +{ + body_text_ = (char*) acl_mymemdup(src, len + 1); + body_text_[len] = 0; + return *this; +} + +mime_builder& mime_builder::add_file(const char* filepath) +{ + attachs_.push_back(acl_mystrdup(filepath)); + return *this; +} + +bool mime_builder::save_as(const char* to) +{ + acl::ofstream fp; + if (fp.open_write(to) == false) + { + logger_error("open file %s failed %s", to, acl::last_serror()); + return false; + } + else if (save_as(fp) == false) + { + fp.close(); + _unlink(to); + return false; + } + else + return true; +} + +bool mime_builder::save_as(acl::ofstream& fp) +{ + acl::string buf; + if (attachs_.empty()) + { + header_.set_type(MIME_CTYPE_TEXT, body_html_ ? + MIME_STYPE_HTML : MIME_STYPE_PLAIN); + header_.add_header("Content-Transfer-Encoding", "base64"); + } + else + { + header_.set_type(MIME_CTYPE_MULTIPART, + MIME_STYPE_MIXED); + delimeter_.format("------=_Part_%d_%ld.%ld", getpid(), + acl_pthread_self(), time(NULL)); + header_.set_boundary(delimeter_.c_str()); + } + header_.build_head(buf, false); + if (fp.write(buf) == -1) + { + logger_error("write head to file %s error %s", + fp.file_path(), acl::last_serror()); + return false; + } + + if (!delimeter_.empty()) + { + if (add_boundary(fp) == false) + return false; + } + if (add_body(fp) == false) + return false; + if (delimeter_.empty()) + return true; + + std::vector::const_iterator cit = attachs_.begin(); + for (; cit != attachs_.end(); ++cit) + { + if (add_boundary(fp) == false) + return false; + if (add_attach(fp, *cit) == false) + return false; + } + + // 添加最后一个分隔符 + return add_boundary(fp, true); +} + +bool mime_builder::add_body(acl::ofstream& fp) +{ + acl::string buf; + const char* ptr; + size_t len; + if (body_html_) + ptr = body_html_; + else + ptr = body_text_; + if (ptr == NULL) + { + logger_error("no body!"); + return false; + } + + int ret = fp.format("Content-Type: text/%s; charset=\"utf-8\"\r\n" + "Content-Transfer-Encoding: base64\r\n\r\n", + body_html_ ? "html" : "plain"); + if (ret == -1) + { + logger_error("write body header to %s error %s", + fp.file_path(), acl::last_serror()); + return false; + } + + len = strlen(ptr); + acl::mime_base64::encode(ptr, (int) len, &buf); + if (fp.write(buf) == -1) + { + logger_error("write body to %s error %s", + fp.file_path(), acl::last_serror()); + return false; + } + else if (fp.format("\r\n") == -1) + { + logger_error("write body endline to %s error %s", + fp.file_path(), acl::last_serror()); + return false; + } + else + return true; +} + +bool mime_builder::add_boundary(acl::ofstream& fp, bool end /* = false */) +{ + if (fp.format("--%s", delimeter_.c_str()) == -1) + { + logger_error("write boundary error(%s) to %s", + acl::last_serror(), fp.file_path()); + return false; + } + else if (end) + { + if (fp.format("--\r\n\r\n") == -1) + { + logger_error("write boundary endline error(%s) to %s", + acl::last_serror(), fp.file_path()); + return false; + } + else + return true; + } + else if (fp.format("\r\n") == -1) + { + logger_error("write boundary end error(%s) to %s", + acl::last_serror(), fp.file_path()); + return false; + } + else + return true; +} + +bool mime_builder::add_attach(acl::ofstream& fp, const char* filepath) +{ + ////////////////////////////////////////////////////////////////////////// + // 创建头部分信息并写入邮件中 + + acl::string filebuf; + global::get_filename(filepath, filebuf); + acl::string filename; + acl::rfc2047::encode(filebuf.c_str(), (int) filebuf.length(), + &filename, "utf-8", 'B', false); + acl::string header; + header.format("Content-Type: application/octet-stream;\r\n" + "\tname=\"%s\r\n" + "Content-Disposition: attachment;\r\n" + "\tfilename=\"%s\"\r\n" + "Content-Transfer-Encoding: base64\r\n\r\n", + filename.c_str(), filename.c_str()); + if (fp.write(header) == -1) + { + logger_error("write header to file %s error %s", + fp.file_path(), acl::last_serror()); + return false; + } + + ////////////////////////////////////////////////////////////////////////// + // 读取附件数据并写入邮件中 + + acl::ifstream in; + if (in.open_read(filepath) == false) + { + logger_error("open file %s error %s", + filepath, acl::last_serror()); + return false; + } + + acl::mime_base64 coder; + + char inbuf[8192]; + acl::string outbuf; + int ret; + while (!in.eof()) + { + ret = in.read(inbuf, sizeof(inbuf) - 1, false); + if (ret == -1) + break; + coder.encode_update(inbuf, ret, &outbuf); + if (!outbuf.empty() && fp.write(outbuf) == -1) + { + logger_error("write to %s error %s", fp.file_path(), + acl::last_serror()); + return false; + } + outbuf.clear(); + } + coder.encode_finish(&outbuf); + if (outbuf.empty() == false && fp.write(outbuf) == -1) + { + logger_error("write to %s error %s", fp.file_path(), + acl::last_serror()); + return false; + } + + if (fp.format("\r\n") == -1) + { + logger_error("write endline to %s error %s", fp.file_path(), + acl::last_serror()); + return false; + } + else + return true; +} diff --git a/app/net_tools/mail/mime_builder.hpp b/app/net_tools/mail/mime_builder.hpp new file mode 100644 index 000000000..2d31e0134 --- /dev/null +++ b/app/net_tools/mail/mime_builder.hpp @@ -0,0 +1,67 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include "acl_cpp/mime/mime_head.hpp" + +class mime_builder +{ +public: + mime_builder(); + ~mime_builder(); + + /** + * 获得邮件头 + * @return {acl::mime_head&} + */ + acl::mime_head& primary_header(void) + { + return (header_); + } + + /** + * 设置邮件正文内容,为纯文本格式 + * @param src {const char*) 正文内容 + * @param len {size_t} src 内容长度 + * @return {mime_builder&} + */ + mime_builder& set_body_text(const char* src, size_t len); + + /** + * 设置邮件正文内容,为 HTML 格式 + * @param src {const char*) 正文内容 + * @param len {size_t} src 内容长度 + * @return {mime_builder&} + */ + mime_builder& set_body_html(const char* src, size_t len); + + /** + * 添加附件 + * @param filepath {const char*} 附件文件路径 + * @return {mime_builder&} + */ + mime_builder& add_file(const char* filepath); + + /** + * 创建邮件内容,并转存至文件中 + * @param to {const char*} 目标文件 + * @return {bool} + */ + bool save_as(const char* to); + + /** + * 创建邮件内容,并转存至文件中 + * @param fp {acl::ofstream&} 目标文件句柄 + * @return {bool} + */ + bool save_as(acl::ofstream& fp); + +private: + acl::mime_head header_; + char* body_text_; + char* body_html_; + std::vector attachs_; + acl::string delimeter_; + + bool add_body(acl::ofstream& fp); + bool add_boundary(acl::ofstream& fp, bool end = false); + bool add_attach(acl::ofstream& fp, const char* filepath); +}; diff --git a/app/net_tools/mail/pop3_client.cpp b/app/net_tools/mail/pop3_client.cpp new file mode 100644 index 000000000..1e32a1d3f --- /dev/null +++ b/app/net_tools/mail/pop3_client.cpp @@ -0,0 +1,633 @@ +#include "StdAfx.h" +#include "rpc/rpc_manager.h" +#include "global/util.h" +#include "pop3_store.h" +#include "pop3_client.h" + +pop3_client::pop3_client() +{ + memset(&meter_, 0, sizeof(meter_)); + meter_.pop3_nslookup_elapsed = 0.00; + meter_.pop3_connect_elapsed = 0.00; + meter_.pop3_banner_elapsed = 0.00; + meter_.pop3_auth_elapsed = 0.00; + meter_.pop3_uidl_elapsed = 0.00; + meter_.pop3_list_elapsed = 0.00; + meter_.pop3_total_elapsed = 0.00; + meter_.pop3_recv_elapsed = 0.00; + meter_.pop3_quit_elapsed = 0.00; + recv_limit_ = 0; +} + +pop3_client::~pop3_client() +{ + +} + +pop3_client& pop3_client::set_callback(pop3_callback* c) +{ + callback_ = c; + return *this; +} + +pop3_client& pop3_client::set_conn_timeout(int n) +{ + connect_timeout_ = n; + return *this; +} + +pop3_client& pop3_client::set_rw_timeout(int n) +{ + rw_timeout_ = n; + return *this; +} + +pop3_client& pop3_client::set_account(const char* s) +{ + auth_account_ = s; + return *this; +} + +pop3_client& pop3_client::set_passwd(const char* s) +{ + auth_passwd_ = s; + return *this; +} + +pop3_client& pop3_client::set_pop3(const char* addr, int port) +{ + pop3_addr_ = addr; + pop3_port_ = port; + pop3_ip_ = addr; + return *this; +} + +pop3_client& pop3_client::set_recv_count(int n) +{ + recv_limit_ = n; + return *this; +} + +////////////////////////////////////////////////////////////////////////// + +struct UP_CTX +{ + acl::string msg; + size_t total; + size_t curr; +}; + +////////////////////////////////////////////////////////////////////////// +// 主线程中运行 + +void pop3_client::rpc_onover() +{ + pop3_store* pop3 = new pop3_store(auth_account_.c_str(), + pop3_ip_.c_str(), meter_, *callback_); + rpc_manager::get_instance().fork(pop3); + delete this; +} + +void pop3_client::rpc_wakeup(void* ctx) +{ + UP_CTX* up = (UP_CTX*) ctx; + + callback_->pop3_report(up->msg.c_str(), + up->total, up->curr, meter_); + delete up; +} + +////////////////////////////////////////////////////////////////////////// +// 子线程中运行 + +void pop3_client::rpc_run() +{ + UP_CTX* up; + struct timeval begin, last, now; + gettimeofday(&begin, NULL); + + ////////////////////////////////////////////////////////////////// + // 域名解析过程 + + gettimeofday(&last, NULL); + if (get_ip() == false) + { + up = new UP_CTX; + up->curr = 0; + up->total = 0; + up->msg.format("解析 pop3 域名:%s 失败!", + pop3_addr_.c_str()); + rpc_signal(up); + return; + } + gettimeofday(&now, NULL); + meter_.pop3_nslookup_elapsed = util::stamp_sub(&now, &last); + acl::string pop3_addr; + pop3_addr.format("%s:%d", pop3_ip_.c_str(), pop3_port_); + + ////////////////////////////////////////////////////////////////// + // 远程连接 SMTP 服务器 + + up = new UP_CTX; + up->curr = 0; + up->total = 0; + up->msg.format("连接 POP3 服务器 ..."); + rpc_signal(up); + + acl::socket_stream conn; + if (conn.open(pop3_addr.c_str(), connect_timeout_, + rw_timeout_) == false) + { + logger_error("connect pop3 server(%s) error", pop3_addr); + up = new UP_CTX; + up->curr = 0; + up->total = 0; + up->msg.format("连接 pop3 服务器:%s 失败!", + pop3_addr.c_str()); + rpc_signal(up); + return; + } + + gettimeofday(&now, NULL); + meter_.pop3_connect_elapsed = util::stamp_sub(&now, &last); + + ////////////////////////////////////////////////////////////////// + // 获得 POP3 服务器的欢迎信息 + + up = new UP_CTX; + up->curr = 0; + up->total = 0; + up->msg.format("接收 POP3 服务器欢迎信息(连接耗时 %.2f 毫秒) ...", + meter_.pop3_connect_elapsed); + rpc_signal(up); + + gettimeofday(&last, NULL); + if (pop3_get_banner(conn) == false) + return; + gettimeofday(&now, NULL); + meter_.pop3_banner_elapsed = util::stamp_sub(&now, &last); + + up = new UP_CTX; + up->curr = 0; + up->total = 0; + up->msg.format("获得 banner 耗时 %.2f 毫秒,开始认证账号信息 ...", + meter_.pop3_banner_elapsed); + rpc_signal(up); + + ////////////////////////////////////////////////////////////////// + // 认证用户的身份 + + gettimeofday(&last, NULL); + if (pop3_auth(conn, auth_account_.c_str(), + auth_passwd_.c_str()) == false) + { + return; + } + gettimeofday(&now, NULL); + meter_.pop3_auth_elapsed = util::stamp_sub(&now, &last); + up = new UP_CTX; + up->curr = 0; + up->total = 0; + up->msg.format("用户认证成功(耗时 %.2f 毫秒)", + meter_.pop3_auth_elapsed); + rpc_signal(up); + + ////////////////////////////////////////////////////////////////// + // uidl 用户收件箱的邮件列表 + + up = new UP_CTX; + up->curr = 0; + up->total = 0; + up->msg.format("列用户收件箱邮件(UIDL) ..."); + rpc_signal(up); + + std::vector uidl_list; + gettimeofday(&last, NULL); + if (pop3_uidl(conn, uidl_list) == false) + return; + gettimeofday(&now, NULL); + meter_.pop3_uidl_elapsed = util::stamp_sub(&now, &last); + + up = new UP_CTX; + up->curr = 0; + up->total = 0; + up->msg.format("用户收件箱邮件列表结束(耗时 %.2f 毫秒)", + meter_.pop3_uidl_elapsed); + rpc_signal(up); + + ////////////////////////////////////////////////////////////////// + // LIST 用户收件箱邮件列表 + + up = new UP_CTX; + up->curr = 0; + up->total = 0; + up->msg.format("列用户收件箱邮件尺寸(LIST) ..."); + rpc_signal(up); + + std::vector size_list_; + gettimeofday(&last, NULL); + if (pop3_list(conn, size_list_) == false) + { + logger_error("pop3_list failed for %s", auth_account_.c_str()); + return; + } + gettimeofday(&now, NULL); + meter_.pop3_list_elapsed = util::stamp_sub(&now, &last); + + up = new UP_CTX; + up->curr = 0; + up->total = 0; + up->msg.format("列用户收件箱邮件尺寸(LIST) 耗时 %.2f", + meter_.pop3_list_elapsed); + rpc_signal(up); + + ////////////////////////////////////////////////////////////////// + // 收取用户收件里的邮件 + + up = new UP_CTX; + up->curr = 0; + up->total = size_list_.size(); + up->msg.format("开始接收收件箱邮件 ..."); + rpc_signal(up); + + gettimeofday(&last, NULL); + if (pop3_retr(conn, size_list_) == false) + { + logger_error("pop3_retr failed for %s", auth_account_.c_str()); + return; + } + gettimeofday(&now, NULL); + meter_.pop3_recv_elapsed = util::stamp_sub(&now, &last); + + up = new UP_CTX; + up->curr = 0; + up->total = size_list_.size(); + up->msg.format("接收收件箱邮件完成,耗时 %0.2f", + meter_.pop3_recv_elapsed); + rpc_signal(up); + + ////////////////////////////////////////////////////////////////// + // 退出邮箱 + + gettimeofday(&last, NULL); + pop3_quit(conn); + gettimeofday(&now, NULL); + meter_.pop3_quit_elapsed = util::stamp_sub(&now, &last); + + ////////////////////////////////////////////////////////////////// + // 统计总共耗费的时间 + + gettimeofday(&now, NULL); + meter_.pop3_total_elapsed = util::stamp_sub(&now, &begin); + + up = new UP_CTX; + up->curr = 0; + up->total = size_list_.size(); + up->msg.format("收件过程共耗时 %0.2f", + meter_.pop3_recv_elapsed); + rpc_signal(up); +} + +bool pop3_client::get_ip() +{ + ACL_DNS_DB* dns_db = acl_gethostbyname(pop3_addr_.c_str(), NULL); + if (dns_db == NULL) + { + logger_error("gethostbyname(%s) failed", pop3_addr_.c_str()); + return false; + } + const char* first_ip = acl_netdb_index_ip(dns_db, 0); + if (first_ip == NULL || *first_ip == 0) + { + logger_error("no ip for domain: %s", pop3_addr_.c_str()); + acl_netdb_free(dns_db); + return false; + } + pop3_ip_ = first_ip; + acl_netdb_free(dns_db); + return true; +} + +bool pop3_client::pop3_get_banner(acl::socket_stream& conn) +{ + acl::string line; + if (conn.gets(line) == false) + { + logger_error("get pop3 banner from %s error", + pop3_ip_.c_str()); + return false; + } + if (line.ncompare("+OK", 3, false) != 0) + { + logger_error("pop3 server(%s) banner error: %s for user: %s", + pop3_ip_.c_str(), line.c_str, auth_account_.c_str()); + return false; + } + logger("banner: %s", line.c_str()); + return true; +} + +bool pop3_client::pop3_auth(acl::socket_stream& conn, + const char* user, const char* pass) +{ + if (conn.format("USER %s\r\n", auth_account_.c_str()) == -1) + { + logger_error("send USER %s to pop3 server(%s) error(%s)", + auth_account_.c_str(), pop3_ip_.c_str(), + acl::last_serror()); + return false; + } + + acl::string line; + + if (conn.gets(line) == false) + { + logger_error("get USER(%s)'s reply error(%s) from server %s", + auth_account_.c_str(), acl::last_serror(), + pop3_ip_.c_str()); + return false; + } + if (line.ncompare("+OK", 3, false) != 0) + { + logger_error("pop3 server(%s) reply error: %s for cmd USER %s", + pop3_ip_.c_str(), line.c_str, auth_account_.c_str()); + return false; + } + + logger("USER's reply: %s", line.c_str()); + + if (conn.format("PASS %s\r\n", auth_passwd_.c_str()) == -1) + { + logger_error("send PASS %s to pop3 server(%s) error(%s)", + auth_passwd_.c_str(), pop3_ip_.c_str(), + acl::last_serror()); + return false; + } + if (conn.gets(line) == false) + { + logger_error("get PASS(%s) reply error(%s) from server %s", + auth_passwd_.c_str(), acl::last_serror(), + pop3_ip_.c_str()); + return false; + } + if (line.ncompare("+OK", 3, false) != 0) + { + logger_error("pop3 server(%s) reply error: %s for cmd PASS %s", + pop3_ip_.c_str(), line.c_str, auth_passwd_.c_str()); + return false; + } + logger("PASS's reply: %s", line.c_str()); + return true; +} + +bool pop3_client::pop3_uidl(acl::socket_stream& conn, + std::vector& out) +{ + if (conn.puts("UIDL") == -1) + { + logger_error("send UIDL to pop3 server(%s) error %s, " + "user: %s", pop3_ip_.c_str(), acl::last_serror(), + auth_account_.c_str()); + return false; + } + + acl::string line; + if (conn.gets(line) == false) + { + logger_error("gets UIDL's reply from server(%s) error(%s), " + "user: %s", pop3_ip_.c_str(), acl::last_serror(), + auth_account_.c_str()); + return false; + } + if (line.ncompare("+OK", 3, false) != 0) + { + logger_error("UIDL's reply(%s) error from server %s, user: %s", + line.c_str(), pop3_ip_.c_str(), auth_account_.c_str()); + return false; + } + + logger("UIDL's first reply: %s", line.c_str()); + + while (true) + { + if (conn.gets(line) == false) + { + logger_error("UIDL's reply error %s, from server %s, " + "user %s", acl::last_serror(), + pop3_ip_.c_str(), auth_account_.c_str()); + return false; + } + logger("UIDL: %s", line.c_str()); + + if (line == ".") + break; + char* ptr = line.c_str(); + char* p1 = acl_mystrtok(&ptr, " \t"); + if (ptr == NULL || *ptr == 0) + { + logger_error("invalid UIDL's reply(%s) from server %s, " + "user %s", p1, pop3_ip_.c_str(), + auth_account_.c_str()); + return false; + } + out.push_back(ptr); + } + + meter_.total_uidl = out.size(); + return true; +} + +bool pop3_client::pop3_list(acl::socket_stream& conn, std::vector& out) +{ + if (conn.puts("LIST") == -1) + { + logger_error("send LIST to pop3 server(%s) error %s, " + "user: %s", pop3_ip_.c_str(), acl::last_serror(), + auth_account_.c_str()); + return false; + } + + acl::string line; + if (conn.gets(line) == false) + { + logger_error("gets LIST's reply from server(%s) error(%s), " + "user: %s", pop3_ip_.c_str(), acl::last_serror(), + auth_account_.c_str()); + return false; + } + if (line.ncompare("+OK", 3, false) != 0) + { + logger_error("LIST's reply(%s) error from server %s, user: %s", + line.c_str(), pop3_ip_.c_str(), auth_account_.c_str()); + return false; + } + + logger("LIST's first reply: %s", line.c_str()); + + while (true) + { + if (conn.gets(line) == false) + { + logger_error("LIST's reply error %s, from server %s, " + "user %s", acl::last_serror(), + pop3_ip_.c_str(), auth_account_.c_str()); + return false; + } + + logger("LIST: %s", line.c_str()); + + if (line == ".") + break; + char* ptr = line.c_str(); + char* p1 = acl_mystrtok(&ptr, " \t"); + if (ptr == NULL || *ptr == 0) + { + logger_error("invalid LIST's reply(%s) from server %s, " + "user %s", p1, pop3_ip_.c_str(), + auth_account_.c_str()); + return false; + } + int len = atoi(ptr); + if (len <= 0) + { + logger_error("invalid LIST size(%d) from server %s, " + "user %s", len, pop3_ip_.c_str(), + auth_account_.c_str()); + return false; + } + out.push_back((size_t) len); + meter_.total_size += len; + } + meter_.total_list = out.size(); + return true; +} + +bool pop3_client::pop3_retr(acl::socket_stream& conn, + const std::vector& size_list) +{ + if (recv_limit_ == 0) + return true; + if (recv_limit_ < 0 || recv_limit_ > (int) size_list.size()) + meter_.recved_limit = size_list.size(); + else + meter_.recved_limit = recv_limit_; + + recv_begin_ = time(NULL); + time_t now, inter; + for (size_t i = 1; i <= meter_.recved_limit; i++) + { + if (pop3_retr_one(conn, i) == false) + return false; + + time(&now); + inter = now - recv_begin_; + if (inter > 0) + meter_.recved_speed = meter_.recved_size / inter; + UP_CTX* up = new UP_CTX; + up->curr = i; + up->total = meter_.recved_limit; + up->msg.format("接收邮件(%d/%d), 收到 %d 字节, %d 字节/秒", + (int) meter_.recved_count, + (int) meter_.recved_limit, + (int) meter_.recved_size, + (int) meter_.recved_speed); + rpc_signal(up); + } + + return true; +} + +bool pop3_client::pop3_retr_one(acl::socket_stream& conn, size_t idx) +{ + if (conn.format("RETR %d\r\n", idx) == -1) + { + logger_error("send RETR %d to pop3 server(%s) error %s, " + "user: %s", pop3_ip_.c_str(), idx, + acl::last_serror(), auth_account_.c_str()); + return false; + } + + acl::string line; + + if (conn.gets(line) == false) + { + logger_error("gets RETR's reply from server(%s) error(%s), " + "user: %s", pop3_ip_.c_str(), acl::last_serror(), + auth_account_.c_str()); + return false; + } + if (line.ncompare("+OK", 3, false) != 0) + { + logger_error("RETR's reply(%s) error from server %s, user: %s", + line.c_str(), pop3_ip_.c_str(), auth_account_.c_str()); + return false; + } + + time_t last, now; + time(&last); + + while (true) + { + if (conn.gets(line) == false) + { + logger_error("gets mail data error(%s) from server %s, " + "user: %s, idx: %d", acl::last_serror(), + pop3_ip_.c_str(), auth_account_.c_str(), idx); + return false; + } + if (line == ".") + break; + + meter_.recved_size += line.length(); + + time(&now); + if (now - last >= 1) + { + UP_CTX* up = new UP_CTX; + up->curr = meter_.recved_count; + up->total = meter_.recved_limit; + meter_.recved_speed = meter_.recved_size + / (int) (now - recv_begin_); + up->msg.format("接收邮件(%d/%d), 收到 %d 字节, " + "%d 字节/秒", + (int) meter_.recved_count, + (int) meter_.recved_limit, + (int) meter_.recved_size, + (int) meter_.recved_speed); + rpc_signal(up); + time(&last); + } + } + + meter_.recved_count++; + return true; +} + +bool pop3_client::pop3_quit(acl::socket_stream& conn) +{ + if (conn.puts("QUIT") == -1) + { + logger_error("send QUIT to pop3 server(%s) error %s, " + "user: %s", pop3_ip_.c_str(), + acl::last_serror(), auth_account_.c_str()); + return false; + } + + acl::string line; + + if (conn.gets(line) == false) + { + logger_error("gets QUIT's reply from server(%s) error(%s), " + "user: %s", pop3_ip_.c_str(), acl::last_serror(), + auth_account_.c_str()); + return false; + } + if (line.ncompare("+OK", 3, false) != 0) + { + logger_error("QUIT's reply(%s) error from server %s, user: %s", + line.c_str(), pop3_ip_.c_str(), auth_account_.c_str()); + return false; + } + return true; +} +////////////////////////////////////////////////////////////////////////// diff --git a/app/net_tools/mail/pop3_client.h b/app/net_tools/mail/pop3_client.h new file mode 100644 index 000000000..b1140e514 --- /dev/null +++ b/app/net_tools/mail/pop3_client.h @@ -0,0 +1,90 @@ +#pragma once + +////////////////////////////////////////////////////////////////////////// + +struct POP3_METER +{ + double pop3_nslookup_elapsed; + double pop3_connect_elapsed; + double pop3_banner_elapsed; + double pop3_auth_elapsed; + double pop3_uidl_elapsed; + double pop3_list_elapsed; + double pop3_recv_elapsed; + double pop3_quit_elapsed; + double pop3_total_elapsed; + size_t total_list; + size_t total_uidl; + size_t total_size; + size_t recved_limit; + size_t recved_count; + size_t recved_size; + size_t recved_speed; +}; + +////////////////////////////////////////////////////////////////////////// + +class pop3_callback +{ +public: + pop3_callback() {} + virtual ~pop3_callback() {} + + virtual void pop3_finish(const char* dbpath) = 0; + virtual void pop3_report(const char* msg, size_t total, + size_t curr, const POP3_METER& meter) = 0; +protected: +private: +}; + +////////////////////////////////////////////////////////////////////////// + +class pop3_client : public acl::rpc_request +{ +public: + pop3_client(); + ~pop3_client(); + + pop3_client& set_callback(pop3_callback*); + pop3_client& set_account(const char*); + pop3_client& set_passwd(const char*); + pop3_client& set_conn_timeout(int); + pop3_client& set_rw_timeout(int); + pop3_client& set_pop3(const char*, int); + pop3_client& set_recv_count(int); +protected: + // 基类虚函数:子线程处理函数 + virtual void rpc_run(); + + // 基类虚函数:主线程处理过程,收到子线程任务完成的消息 + virtual void rpc_onover(); + + // 基类虚函数:主线程处理过程,收到子线程的通知消息 + virtual void rpc_wakeup(void* ctx); +private: + POP3_METER meter_; +private: + pop3_callback* callback_; + int connect_timeout_; + int rw_timeout_; + acl::string auth_account_; + acl::string auth_passwd_; + + acl::string pop3_ip_; + acl::string pop3_addr_; + int pop3_port_; + int recv_limit_; + time_t recv_begin_; + + bool get_ip(); + +private: + bool pop3_get_banner(acl::socket_stream&); + bool pop3_auth(acl::socket_stream&, const char*, const char*); + bool pop3_uidl(acl::socket_stream&, std::vector&); + bool pop3_list(acl::socket_stream&, std::vector&); + bool pop3_retr(acl::socket_stream& conn, + const std::vector& size_list); + bool pop3_retr_one(acl::socket_stream& conn, size_t idx); + bool pop3_quit(acl::socket_stream& conn); +}; \ No newline at end of file diff --git a/app/net_tools/mail/pop3_store.cpp b/app/net_tools/mail/pop3_store.cpp new file mode 100644 index 000000000..ac467ae53 --- /dev/null +++ b/app/net_tools/mail/pop3_store.cpp @@ -0,0 +1,126 @@ +#include "StdAfx.h" +#include "rpc/rpc_manager.h" +#include "global/global.h" +#include "pop3_client.h" +#include "pop3_store.h" + +pop3_store::pop3_store(const char* user, const char* pop3_ip, + const POP3_METER& meter, pop3_callback& callback) +: callback_(callback) +, ok_(false) +{ + user_ = acl_mystrdup(user); + pop3_ip_ = acl_mystrdup(pop3_ip); + + meter_ = (POP3_METER*) acl_mycalloc(1, sizeof(POP3_METER)); + memcpy(meter_, &meter, sizeof(POP3_METER)); +} + +pop3_store::~pop3_store() +{ + acl_myfree(user_); + acl_myfree(pop3_ip_); + acl_myfree(meter_); +} + +////////////////////////////////////////////////////////////////////////// +// 主线程过程 + +void pop3_store::rpc_onover() +{ + logger("store pop3 test results %s!", ok_ ? "OK" : "Failed"); + callback_.pop3_finish(dbpath_.c_str()); + delete this; +} + +////////////////////////////////////////////////////////////////////////// +// 子线程过程 + +static const char* CREATE_TBL = +"create table pop3_tbl\r\n" +"(\r\n" +"user varchar(128) not null,\r\n" +"pop3_ip varchar(32) not null,\r\n" +"nslookup_elapsed float(10,2) not null default 0.00,\r\n" +"connect_elapsed float(10,2) not null default 0.00,\r\n" +"banner_elapsed float(10,2) not null default 0.00,\r\n" +"auth_elapsed float(10,2) not null default 0.00,\r\n" +"uidl_elapsed float(10,2) not null default 0.00,\r\n" +"list_elapsed float(10,2) not null default 0.00,\r\n" +"recv_elapsed fload(10,2) not null default 0.00,\r\n" +"quit_elapsed fload(10,2) not null default 0.00,\r\n" +"total_elapsed float(10,2) not null default 0.00,\r\n" +"total_list int not null default 0,\r\n" +"total_uidl int not null default 0,\r\n" +"total_size int not null default 0,\r\n" +"recved_count int not null default 0,\r\n" +"recved_size int not null default 0,\r\n" +"recved_speed int not null default 0\r\n" +");\r\n" +"create index pop3_user_idx on pop3_tbl(user);\r\n"; + +void pop3_store::rpc_run() +{ + const char* path = global::get_instance().get_path(); + dbpath_.format("%s/pop3_store.db", path); + + acl::db_sqlite db(dbpath_.c_str()); + if (db.open() == false) + logger_error("open db: %s failed", dbpath_.c_str()); + else if (create_tbl(db) == false) + logger_error("create table failed for %s", dbpath_.c_str()); + else + { + logger("open db(%s) ok", dbpath_.c_str()); + insert_tbl(db); + ok_ = true; + } +} + +bool pop3_store::create_tbl(acl::db_handle& db) +{ + if (db.tbl_exists("pop3_tbl")) + { + logger("pop3_tbl table exist"); + return (true); + } + else if (db.sql_update(CREATE_TBL) == false) + { + logger_error("sql(%s) error", CREATE_TBL); + return (false); + } + else + { + logger("create table pop3_tbl ok"); + return (true); + } +} + +void pop3_store::insert_tbl(acl::db_handle& db) +{ + acl::string sql; + + sql.format("insert into pop3_tbl(user, pop3_ip, nslookup_elapsed, " + "connect_elapsed, banner_elapsed, " + "auth_elapsed, uidl_elapsed, " + "list_elapsed, recv_elapsed, " + "quit_elapsed, total_elapsed, " + "total_list, total_uidl, total_size, " + "recved_count, recved_size, recved_speed)" + "values('%s', '%s', %0.2f, %0.2f, %0.2f, %0.2f, " + "%0.2f, %0.2f, %0.2f, %0.2f, %0.2f, %d, %d, %d, " + "%d, %d, %d)", + user_, pop3_ip_, meter_->pop3_nslookup_elapsed, + meter_->pop3_connect_elapsed, meter_->pop3_banner_elapsed, + meter_->pop3_auth_elapsed, meter_->pop3_uidl_elapsed, + meter_->pop3_list_elapsed, meter_->pop3_recv_elapsed, + meter_->pop3_quit_elapsed, meter_->pop3_total_elapsed, + (int) meter_->total_list, (int) meter_->total_uidl, + (int) meter_->total_size, (int) meter_->recved_count, + (int) meter_->recved_size, (int) meter_->recved_speed); + + if (db.sql_update(sql.c_str()) == false) + logger_error("sql(%s) error", sql.c_str()); + else + logger("insert into pop3_tbl OK!"); +} diff --git a/app/net_tools/mail/pop3_store.h b/app/net_tools/mail/pop3_store.h new file mode 100644 index 000000000..8f169cfab --- /dev/null +++ b/app/net_tools/mail/pop3_store.h @@ -0,0 +1,29 @@ +#pragma once + +struct POP3_METER; +class pop3_callback; + +class pop3_store : public acl::rpc_request +{ +public: + pop3_store(const char* user, const char* pop3_ip, + const POP3_METER& meter, pop3_callback& callback); +protected: + ~pop3_store(); + + // 基类虚函数:子线程处理函数 + virtual void rpc_run(); + + // 基类虚函数:主线程处理过程,收到子线程任务完成的消息 + virtual void rpc_onover(); +private: + bool ok_; + char* user_; + char* pop3_ip_; + POP3_METER* meter_; + pop3_callback& callback_; + acl::string dbpath_; + + bool create_tbl(acl::db_handle& db); + void insert_tbl(acl::db_handle& db); +}; \ No newline at end of file diff --git a/app/net_tools/mail/smtp_client.cpp b/app/net_tools/mail/smtp_client.cpp new file mode 100644 index 000000000..1c7680a1b --- /dev/null +++ b/app/net_tools/mail/smtp_client.cpp @@ -0,0 +1,405 @@ +#include "StdAfx.h" +#include "global/global.h" +#include "global/util.h" +#include "rpc/rpc_manager.h" +#include "mime_builder.hpp" +#include "smtp_store.h" +#include "smtp_client.h" + +smtp_client::smtp_client() +{ + memset(&meter_, 0, sizeof(meter_)); +} + +smtp_client::~smtp_client() +{ + +} + +smtp_client& smtp_client::set_callback(smtp_callback* c) +{ + callback_ = c; + return *this; +} + +smtp_client& smtp_client::set_conn_timeout(int n) +{ + connect_timeout_ = n; + return *this; +} + +smtp_client& smtp_client::set_rw_timeout(int n) +{ + rw_timeout_ = n; + return *this; +} + +smtp_client& smtp_client::set_account(const char* s) +{ + auth_account_ = s; + return *this; +} + +smtp_client& smtp_client::set_passwd(const char* s) +{ + auth_passwd_ = s; + return *this; +} + +smtp_client& smtp_client::set_smtp(const char* addr, int port) +{ + smtp_addr_ = addr; + smtp_port_ = port; + smtp_ip_ = addr; + return *this; +} + +smtp_client& smtp_client::set_from(const char* s) +{ + mail_from_ = s; + return *this; +} + +smtp_client& smtp_client::add_to(const char* s) +{ + ACL_ARGV* tokens = acl_argv_split(s, ";,,; \t\r\n"); + ACL_ITER iter; + + acl_foreach(iter, tokens) + { + const char* to = (const char*) iter.data; + recipients_.push_back(to); + } + + acl_argv_free(tokens); + + return *this; +} + +smtp_client& smtp_client::set_subject(const char* s) +{ + acl::string buf; + //acl::charset_conv conv; + //if (conv.convert("gbk", "utf-8", s, strlen(s), &buf) == false) + // logger_error("convert from gbk to utf-8 failed"); + //else + //{ + // acl::string buf2; + // conv.convert("utf-8", "gbk", buf.c_str(), + // (int) buf.length(), &buf2); + // printf(">>>buf: %s, buf2: %s\r\n", buf.c_str(), buf2.c_str()); + //} + buf = s; + acl::rfc2047::encode(s, (int) buf.length(), &subject_, "gbk", 'B', false); + return *this; +} + +smtp_client& smtp_client::add_file(const char* p) +{ + files_.push_back(p); + return *this; +} + +////////////////////////////////////////////////////////////////////////// + +struct UP_CTX +{ + acl::string msg; + size_t total; + size_t curr; +}; + +////////////////////////////////////////////////////////////////////////// +// 主线程中运行 + +void smtp_client::rpc_onover() +{ + smtp_store* smtp = new smtp_store(auth_account_.c_str(), smtp_ip_.c_str(), + meter_, *callback_); + rpc_manager::get_instance().fork(smtp); + delete this; +} + +void smtp_client::rpc_wakeup(void* ctx) +{ + UP_CTX* up = (UP_CTX*) ctx; + + callback_->smtp_report(up->msg.c_str(), + up->total, up->curr, meter_); + delete up; +} + +////////////////////////////////////////////////////////////////////////// +// 子线程中运行 + +void smtp_client::rpc_run() +{ + UP_CTX* up; + + // 创建邮件内容 + acl::ifstream in; + if (create_mail(in) == false) + return; + + + struct timeval begin, last, now; + gettimeofday(&begin, NULL); + + ////////////////////////////////////////////////////////////////////////// + // 域名解析过程 + + gettimeofday(&last, NULL); + if (get_ip() == false) + { + up = new UP_CTX; + up->curr = 0; + up->total = (size_t) in.fsize(); + up->msg.format("解析 smtp 域名:%s 失败!", smtp_addr_.c_str()); + rpc_signal(up); + + return; + } + gettimeofday(&now, NULL); + meter_.smtp_nslookup_elapsed = util::stamp_sub(&now, &last); + acl::string smtp_addr; + smtp_addr.format("%s:%d", smtp_ip_.c_str(), smtp_port_); + + ////////////////////////////////////////////////////////////////////////// + // 远程连接 SMTP 服务器 + + up = new UP_CTX; + up->curr = 0; + up->total = (size_t) in.fsize(); + up->msg.format("连接 SMTP 服务器 ..."); + rpc_signal(up); + + SMTP_CLIENT* conn = smtp_open(smtp_addr.c_str(), connect_timeout_, + rw_timeout_, 1024); + if (conn == NULL) + { + logger_error("connect smtp server(%s) error", smtp_addr); + up = new UP_CTX; + up->curr = 0; + up->total = (size_t) in.fsize(); + up->msg.format("连接 smtp 服务器:%s 失败!", smtp_addr.c_str()); + rpc_signal(up); + return; + } + + gettimeofday(&now, NULL); + meter_.smtp_connect_elapsed = util::stamp_sub(&now, &last); + + ////////////////////////////////////////////////////////////////////////// + struct timeval envelop_begin; + gettimeofday(&envelop_begin, NULL); + + up = new UP_CTX; + up->curr = 0; + up->total = (size_t) in.fsize(); + up->msg.format("接收 SMTP 服务器欢迎信息(连接耗时 %.2f 毫秒) ...", + meter_.smtp_connect_elapsed); + rpc_signal(up); + + gettimeofday(&last, NULL); + if (smtp_get_banner(conn) != 0) + { + logger_error("get smtpd banner error"); + smtp_close(conn); + return; + } + else if (smtp_greet(conn, "localhost", 1) != 0) + { + logger_error("send EHLO error(%d:%s) to server %s", + conn->smtp_code, conn->buf, smtp_addr.c_str()); + smtp_close(conn); + return; + } + gettimeofday(&now, NULL); + meter_.smtp_banner_elapsed = util::stamp_sub(&now, &last); + ////////////////////////////////////////////////////////////////////////// + // 认证用户身份 + + up = new UP_CTX; + up->curr = 0; + up->total = (size_t) in.fsize(); + up->msg.format("认证用户身份 ..."); + rpc_signal(up); + + gettimeofday(&last, NULL); + + if (smtp_auth(conn, auth_account_.c_str(), + auth_passwd_.c_str()) != 0) + { + logger_error("smtp auth error(%d:%s) from server(%s), " + "account: %s, passwd: %s", conn->smtp_code, conn->buf, + smtp_addr.c_str(), auth_account_.c_str(), + auth_passwd_.c_str()); + smtp_close(conn); + return; + } + + gettimeofday(&now, NULL); + meter_.smtp_auth_elapsed = util::stamp_sub(&now, &last); + + up = new UP_CTX; + up->curr = 0; + up->total = (size_t) in.fsize(); + up->msg.format("发送邮件信封(认证耗时 %.2f 毫秒) ...", + meter_.smtp_auth_elapsed); + rpc_signal(up); + + ////////////////////////////////////////////////////////////////////////// + + gettimeofday(&last, NULL); + if (smtp_mail(conn, mail_from_.c_str()) != 0) + { + logger_error("smtp MAIL FROM error(%d:%s), from: %s, server: %s", + mail_from_.c_str(), conn->smtp_code, + conn->buf, smtp_addr.c_str()); + smtp_close(conn); + return; + } + gettimeofday(&now, NULL); + meter_.smtp_mail_elapsed = util::stamp_sub(&now, &last); + + ////////////////////////////////////////////////////////////////////////// + + gettimeofday(&last, NULL); + std::list::const_iterator cit2 = recipients_.begin(); + for (; cit2 != recipients_.end(); ++cit2) + { + if (smtp_rcpt(conn, (*cit2).c_str()) != 0) + { + logger_error("smtp RCPT TO error(%d:%s), to: %s, server: %s", + conn->smtp_code, conn->buf, (*cit2).c_str(), + smtp_addr.c_str()); + smtp_close(conn); + return; + } + else + logger("smtp RCPT TO ok, to: %s, server: %s", + (*cit2).c_str(), smtp_addr.c_str()); + } + gettimeofday(&now, NULL); + meter_.smtp_rcpt_elapsed = util::stamp_sub(&now, &last); + + ////////////////////////////////////////////////////////////////////////// + + gettimeofday(&last, NULL); + + if (smtp_data(conn) != 0) + { + logger_error("smtp DATA to server %s error(%d:%s)", + smtp_addr.c_str(), conn->smtp_code, conn->buf); + smtp_close(conn); + return; + } + gettimeofday(&now, NULL); + meter_.smtp_data_elapsed = util::stamp_sub(&now, &last); + + meter_.smtp_envelope_eplased = util::stamp_sub(&now, &envelop_begin); + + // 发送邮件内容 + + char buf[8192]; + int ret; + int n = 0; + + while (!in.eof()) + { + ret = in.read(buf, sizeof(buf), false); + if (ret == -1) + break; + if (acl_vstream_writen(conn->conn, buf, ret) == ACL_VSTREAM_EOF) + { + logger_error("smtp send data to server %s error(%d:%s)", + smtp_addr.c_str(), conn->smtp_code, conn->buf); + smtp_close(conn); + return; + } + n += ret; + up = new UP_CTX; + up->curr = n; + up->total = (size_t) in.fsize(); + up->msg.format("发送邮件中(%d/%d 字节) ...", up->curr, up->total); + rpc_signal(up); + } + + /* 发送 \r\n.\r\n 表示邮件数据发送完毕 */ + if (smtp_data_end(conn) != 0) + { + logger_error("send . error: %s, code: %d\r\n", + conn->buf, conn->smtp_code); + smtp_close(conn); + } + + gettimeofday(&now, NULL); + meter_.smtp_body_elapsed = util::stamp_sub(&now, &last); + meter_.smtp_total_elapsed = util::stamp_sub(&now, &begin); + meter_.smtp_speed = (int) up->total / (int) meter_.smtp_body_elapsed; + + up = new UP_CTX; + up->curr = (size_t) in.fsize(); + up->total = (size_t) in.fsize(); + up->msg.format("发送邮件成功!(%d/%d 字节, 耗时 %.2f 毫秒)", + up->curr, up->total, meter_.smtp_total_elapsed); + rpc_signal(up); +} + +bool smtp_client::create_mail(acl::ifstream& in) +{ + mime_builder builer; + builer.primary_header() + .set_from(mail_from_.c_str()) + .set_sender(mail_from_.c_str()); + + std::list::const_iterator cit1 = recipients_.begin(); + for (; cit1 != recipients_.end(); ++cit1) + builer.primary_header().add_to((*cit1).c_str()); + builer.primary_header().set_subject(subject_.c_str()); + + acl::string body_text("test"); + builer.set_body_text(body_text.c_str(), body_text.length()); + std::vector::const_iterator cit = files_.begin(); + for (; cit != files_.end(); ++cit) + builer.add_file((*cit).c_str()); + + mailpath_.format("%s/%ld.eml", global::get_instance().get_path(), + time(NULL)); + if (builer.save_as(mailpath_.c_str()) == false) + { + logger_error("build email(%s) error(%s)", + mailpath_.c_str(), acl::last_serror()); + mailpath_.clear(); + return false; + } + + if (in.open_read(mailpath_.c_str()) == false) + { + logger_error("open %s error %s", mailpath_.c_str(), + acl::last_serror()); + mailpath_.clear(); + return false; + } + return true; +} + +bool smtp_client::get_ip() +{ + ACL_DNS_DB* dns_db = acl_gethostbyname(smtp_addr_.c_str(), NULL); + if (dns_db == NULL) + { + logger_error("gethostbyname(%s) failed", smtp_addr_.c_str()); + return false; + } + const char* first_ip = acl_netdb_index_ip(dns_db, 0); + if (first_ip == NULL || *first_ip == 0) + { + logger_error("no ip for domain: %s", smtp_addr_.c_str()); + acl_netdb_free(dns_db); + return false; + } + smtp_ip_ = first_ip; + acl_netdb_free(dns_db); + return true; +} diff --git a/app/net_tools/mail/smtp_client.h b/app/net_tools/mail/smtp_client.h new file mode 100644 index 000000000..8721cbaee --- /dev/null +++ b/app/net_tools/mail/smtp_client.h @@ -0,0 +1,85 @@ +#pragma once + +////////////////////////////////////////////////////////////////////////// + +struct SMTP_METER +{ + double smtp_nslookup_elapsed; + double smtp_connect_elapsed; + double smtp_banner_elapsed; + double smtp_auth_elapsed; + double smtp_mail_elapsed; + double smtp_rcpt_elapsed; + double smtp_envelope_eplased; + double smtp_data_elapsed; + double smtp_body_elapsed; + double smtp_total_elapsed; + int smtp_speed; +}; + +////////////////////////////////////////////////////////////////////////// + +class smtp_callback +{ +public: + smtp_callback() {} + virtual ~smtp_callback() {} + + virtual void smtp_finish(const char* dbpath) = 0; + virtual void smtp_report(const char* msg, size_t total, + size_t curr, const SMTP_METER& meter) = 0; +}; + +////////////////////////////////////////////////////////////////////////// + +class smtp_client : public acl::rpc_request +{ +public: + smtp_client(); + + smtp_client& set_callback(smtp_callback*); + + smtp_client& set_account(const char*); + smtp_client& set_passwd(const char*); + smtp_client& set_conn_timeout(int); + smtp_client& set_rw_timeout(int); + + smtp_client& set_smtp(const char*, int); + smtp_client& set_from(const char*); + smtp_client& add_to(const char*); + smtp_client& set_subject(const char*); + smtp_client& add_file(const char*); + +protected: + ~smtp_client(); + + // 基类虚函数:子线程处理函数 + virtual void rpc_run(); + + // 基类虚函数:主线程处理过程,收到子线程任务完成的消息 + virtual void rpc_onover(); + + // 基类虚函数:主线程处理过程,收到子线程的通知消息 + virtual void rpc_wakeup(void* ctx); +private: + SMTP_METER meter_; +private: + smtp_callback* callback_; + int connect_timeout_; + int rw_timeout_; + acl::string auth_account_; + acl::string auth_passwd_; + + acl::string smtp_ip_; + acl::string smtp_addr_; + int smtp_port_; + acl::string mail_from_; + std::list recipients_; + acl::string subject_; + std::vector files_; + + acl::string mailpath_; + + bool create_mail(acl::ifstream& in); + bool get_ip(); +}; diff --git a/app/net_tools/mail/smtp_store.cpp b/app/net_tools/mail/smtp_store.cpp new file mode 100644 index 000000000..cc1bb8431 --- /dev/null +++ b/app/net_tools/mail/smtp_store.cpp @@ -0,0 +1,121 @@ +#include "StdAfx.h" +#include "global/global.h" +#include "smtp_client.h" +#include "smtp_store.h" + +smtp_store::smtp_store(const char* user, const char* smtp_ip, + const SMTP_METER& meter, smtp_callback& callback) +: callback_(callback) +, ok_(false) +{ + user_ = acl_mystrdup(user); + smtp_ip_ = acl_mystrdup(smtp_ip); + + meter_ = (SMTP_METER*) acl_mycalloc(1, sizeof(SMTP_METER)); + memcpy(meter_, &meter, sizeof(SMTP_METER)); +} + +smtp_store::~smtp_store() +{ + acl_myfree(user_); + acl_myfree(smtp_ip_); + acl_myfree(meter_); +} + +////////////////////////////////////////////////////////////////////////// +// 主线程过程 + +void smtp_store::rpc_onover() +{ + logger("store smtp test results %s!", ok_ ? "OK" : "Failed"); + callback_.smtp_finish(dbpath_.c_str()); + delete this; +} + +////////////////////////////////////////////////////////////////////////// +// 子线程过程 + +static const char* CREATE_TBL = +"create table smtp_tbl\r\n" +"(\r\n" +"user varchar(128) not null,\r\n" +"smtp_ip varchar(32) not null,\r\n" +"nslookup_elapsed float(10,2) not null default 0.00,\r\n" +"connect_elapsed float(10,2) not null default 0.00,\r\n" +"banner_elapsed float(10,2) not null default 0.00,\r\n" +"auth_elapsed float(10,2) not null default 0.00,\r\n" +"mail_elapsed float(10,2) not null default 0.00,\r\n" +"rcpt_elapsed float(10,2) not null default 0.00,\r\n" +"data_elapsed float(10,2) not null default 0.00,\r\n" +"body_elapsed float(10,2) not null default 0.00,\r\n" +"envelope_elapsed float(10,2) not null default 0.00,\r\n" +"total_elapsed float(10,2) not null default 0.00,\r\n" +"smtp_speed int not null default 0\r\n" +");\r\n" +"create index user_idx on smtp_tbl(user);\r\n"; + +void smtp_store::rpc_run() +{ + const char* path = global::get_instance().get_path(); + dbpath_.format("%s/smtp_store2.db", path); + + acl::db_sqlite db(dbpath_.c_str()); + if (db.open() == false) + logger_error("open db: %s failed", dbpath_.c_str()); + else if (create_tbl(db) == false) + logger_error("create table failed for %s", dbpath_.c_str()); + else + { + logger("open db(%s) ok", dbpath_.c_str()); + insert_tbl(db); + ok_ = true; + } +} + +bool smtp_store::create_tbl(acl::db_handle& db) +{ + if (db.tbl_exists("smtp_tbl")) + { + logger("smtp_tbl table exist"); + return (true); + } + else if (db.sql_update(CREATE_TBL) == false) + { + logger_error("sql(%s) error", CREATE_TBL); + return (false); + } + else + { + logger("create table smtp_tbl ok"); + return (true); + } +} + +void smtp_store::insert_tbl(acl::db_handle& db) +{ + acl::string sql; + + sql.format("insert into smtp_tbl(user, smtp_ip, nslookup_elapsed, " + "connect_elapsed, banner_elapsed, auth_elapsed, " + "mail_elapsed, rcpt_elapsed, data_elapsed, " + "body_elapsed, envelope_elapsed, total_elapsed, smtp_speed) " + "values('%s', '%s', %0.2f, %0.2f, %0.2f, %0.2f, %0.2f, " + "%0.2f, %0.2f, %0.2f, %0.2f, %0.2f, %d)", + user_, smtp_ip_, + meter_->smtp_nslookup_elapsed, + meter_->smtp_connect_elapsed, + meter_->smtp_banner_elapsed, + meter_->smtp_auth_elapsed, + meter_->smtp_mail_elapsed, + meter_->smtp_rcpt_elapsed, + meter_->smtp_data_elapsed, + meter_->smtp_envelope_eplased, + meter_->smtp_body_elapsed, + meter_->smtp_total_elapsed, + meter_->smtp_speed); + + if (db.sql_update(sql.c_str()) == false) + logger_error("sql(%s) error", sql.c_str()); + else + logger("insert into smtp_tbl OK!"); +} diff --git a/app/net_tools/mail/smtp_store.h b/app/net_tools/mail/smtp_store.h new file mode 100644 index 000000000..9e207f499 --- /dev/null +++ b/app/net_tools/mail/smtp_store.h @@ -0,0 +1,28 @@ +#pragma once + +struct SMTP_METER; +class smtp_callback; +class smtp_store : public acl::rpc_request +{ +public: + smtp_store(const char* user, const char* smtp_ip, + const SMTP_METER& meter, smtp_callback& callback); +protected: + ~smtp_store(); + + // 基类虚函数:子线程处理函数 + virtual void rpc_run(); + + // 基类虚函数:主线程处理过程,收到子线程任务完成的消息 + virtual void rpc_onover(); + +private: + bool ok_; + char* user_; + char* smtp_ip_; + SMTP_METER* meter_; + smtp_callback& callback_; + acl::string dbpath_; + bool create_tbl(acl::db_handle& db); + void insert_tbl(acl::db_handle& db); +}; \ No newline at end of file diff --git a/app/net_tools/net_store.cpp b/app/net_tools/net_store.cpp new file mode 100644 index 000000000..68f4e9aa5 --- /dev/null +++ b/app/net_tools/net_store.cpp @@ -0,0 +1,293 @@ +#include "StdAfx.h" +#include "global/global.h" +#include "global/passwd_crypt.h" +#include "net_store.h" + +net_store::net_store(const char* smtp_addr, int smtp_port, + const char* pop3_addr, int pop3_port, + const char* user, const char* pass, + const char* recipients, net_store_callback* callback, + bool store /* = false */) + : smtp_addr_(smtp_addr) + , smtp_port_(smtp_port) + , pop3_addr_(pop3_addr) + , pop3_port_(pop3_port) + , user_(user) + , pass_(pass) + , recipients_(recipients) + , callback_(callback) + , store_(store) +{ + +} + +net_store::~net_store() +{ + +} + +////////////////////////////////////////////////////////////////////////// + +bool create_option_tbl(acl::db_handle& db, const char* tbl_name, + const char* sql_create) +{ + if (db.tbl_exists(tbl_name)) + { + logger("table(%s) exist", tbl_name); + return (true); + } + else if (db.sql_update(sql_create) == false) + { + logger_error("sql(%s) error", sql_create); + return (false); + } + else + { + logger("create table %s ok", tbl_name); + return (true); + } +} + +////////////////////////////////////////////////////////////////////////// + +static const char* CREATE_OPT_TBL = +"create table option_tbl" +"(\r\n" +"name varchar(128) not null default '',\r\n" +"value varchar(256) not null default '',\r\n" +"PRIMARY KEY(name)" +")"; + +static acl::db_handle* open_option_tbl() +{ + const char* path = global::get_instance().get_path(); + acl::string dbpath; + dbpath.format("%s/net_store.db", path); + + acl::db_handle* db = new acl::db_sqlite(dbpath.c_str()); + if (db->open() == false) + { + logger_error("open db: %s failed", dbpath.c_str()); + delete db; + return NULL; + } + else if (create_option_tbl(*db, "option_tbl", CREATE_OPT_TBL) == false) + { + delete db; + return NULL; + } + else + return db; +} + +bool net_store::get_key(const char* name, acl::string& out) +{ + acl::db_handle* db = open_option_tbl(); + if (db == NULL) + return false; + acl::string sql; + sql.format("select value from option_tbl where name='%s'", name); + if (db->sql_select(sql.c_str()) == false) + { + delete db; + return false; + } + + const acl::db_row* row = db->get_first_row(); + if (row == NULL) + { + delete db; + return false; + } + const char* value = (*row)["value"]; + if (value == NULL) + { + db->free_result(); + delete db; + return false; + } + out = value; + return true; +} + +bool net_store::set_key(const char* name, const char* value) +{ + acl::db_handle* db = open_option_tbl(); + if (db == NULL) + return false; + + acl::string sql; + sql.format("insert into option_tbl(name, value) values('%s', '%s')", + name, value); + if (db->sql_update(sql.c_str()) == false) + { + sql.format("update option_tbl set value='%s' where name='%s'", + value, name); + db->sql_update(sql.c_str()); + delete db; + return false; + } + else + { + delete db; + return true; + } +} + +////////////////////////////////////////////////////////////////////////// +// 主线程中运行 + +void net_store::rpc_onover() +{ + callback_->load_db_callback(smtp_addr_.c_str(), smtp_port_, + pop3_addr_.c_str(), pop3_port_, user_.c_str(), + pass_.c_str(), recipients_.c_str(), store_); + + delete this; +} + +////////////////////////////////////////////////////////////////////////// +// 子线程中运行 + +static const char* CREATE_MAIL_TBL = +"create table mail_tbl\r\n" +"(\r\n" +"smtp_addr varchar(128) not null,\r\n" +"smtp_port int not null,\r\n" +"pop3_addr varchar(128) not null default '',\r\n" +"pop3_port int not null,\r\n" +"user varchar(128) not null default '',\r\n" +"pass varchar(128) not null default '',\r\n" +"recipients varchar(256) not null default '',\r\n" +"PRIMARY KEY(user)" +")"; + +void net_store::rpc_run() +{ + const char* path = global::get_instance().get_path(); + dbpath_.format("%s/net_store.db", path); + + acl::db_sqlite db(dbpath_.c_str()); + if (db.open() == false) + logger_error("open db: %s failed", dbpath_.c_str()); + else if (create_mail_tbl(db, "mail_tbl", CREATE_MAIL_TBL) == false) + logger_error("create table failed for %s", dbpath_.c_str()); + else if (store_) + save_mail_db(db); + else + load_mail_db(db); +} + +bool net_store::create_mail_tbl(acl::db_handle& db, const char* tbl_name, + const char* sql_create) +{ + if (db.tbl_exists(tbl_name)) + { + logger("table(%s) exist", tbl_name); + return (true); + } + else if (db.sql_update(sql_create) == false) + { + logger_error("sql(%s) error", sql_create); + return (false); + } + else + { + save_mail_db(db); + logger("create table %s ok", tbl_name); + return (true); + } +} + +void net_store::save_mail_db(acl::db_handle& db) +{ + acl::string sql; + + // 先删除原来所有的记录 + sql.format("delete from mail_tbl"); + db.sql_update(sql.c_str()); + + acl::string smtp_addr, pop3_addr, user, pass, recipients; + db.escape_string(smtp_addr_.c_str(), smtp_addr_.length(), smtp_addr); + db.escape_string(pop3_addr_.c_str(), pop3_addr_.length(), pop3_addr); + db.escape_string(user_.c_str(), user_.length(), user); + db.escape_string(pass_.c_str(), pass_.length(), pass); + + ACL_ARGV* tokens = acl_argv_split(recipients_.c_str(), "\t,;\r\n"); + ACL_ITER iter; + acl::string buf; + acl_foreach(iter, tokens) + { + if (iter.i > 0) + buf << ","; + buf << (char*) iter.data; + } + acl_argv_free(tokens); + db.escape_string(buf.c_str(), recipients_.length(), recipients); + + // 密码需要加密存储 + char* pass_crypted = passwd_crypt(pass.c_str()); + sql.format("insert into mail_tbl(smtp_addr, smtp_port, pop3_addr," + " pop3_port, user, pass, recipients)" + " values('%s', %d, '%s', %d, '%s', '%s', '%s')", + smtp_addr.c_str(), smtp_port_, pop3_addr.c_str(), pop3_port_, + user.c_str(), pass_crypted, recipients.c_str()); + acl_myfree(pass_crypted); + + const char* ptr = sql.c_str(); + ptr = pop3_addr.c_str(); + + if (db.sql_update(sql.c_str()) == false) + logger_error("sql(%s) error", sql.c_str()); +} + +void net_store::load_mail_db(acl::db_handle& db) +{ + acl::string sql; + sql.format("select smtp_addr, smtp_port, pop3_addr, pop3_port, user, pass, recipients from mail_tbl"); + if (db.sql_select(sql.c_str()) == false) + { + logger_error("sql(%s) error", sql.c_str()); + return; + } + + const acl::db_row* first_row = db.get_first_row(); + if (first_row == NULL) + return; + const char* ptr = (*first_row)["smtp_addr"]; + if (ptr) + smtp_addr_ = ptr; + ptr = (*first_row)["smtp_port"]; + + int n; + if (ptr && (n = atoi(ptr)) > 0) + smtp_port_ = n; + + ptr = (*first_row)["pop3_addr"]; + if (ptr) + pop3_addr_ = ptr; + + ptr = (*first_row)["pop3_port"]; + if (ptr && (n = atoi(ptr)) > 0) + pop3_port_ = n; + + ptr = (*first_row)["user"]; + if (ptr) + user_ = ptr; + + ptr = (*first_row)["pass"]; + if (ptr) + { + // 对加密的密码需要先解密 + char* pass_plain = passwd_decrypt(ptr); + if (pass_plain) + { + pass_ = pass_plain; + acl_myfree(pass_plain); + } + } + + ptr = (*first_row)["recipients"]; + if (ptr) + recipients_ = ptr; +} \ No newline at end of file diff --git a/app/net_tools/net_store.h b/app/net_tools/net_store.h new file mode 100644 index 000000000..d46fdda54 --- /dev/null +++ b/app/net_tools/net_store.h @@ -0,0 +1,55 @@ +#pragma once + +////////////////////////////////////////////////////////////////////////// + +class net_store_callback +{ +public: + net_store_callback() {} + virtual ~net_store_callback() {} + + virtual void load_db_callback(const char* smtp_addr, int smtp_port, + const char* pop3_addr, int pop3_port, + const char* user, const char* pass, + const char* recipients, bool store) = 0; +private: +}; +////////////////////////////////////////////////////////////////////////// + +class net_store : public acl::rpc_request +{ +public: + net_store(const char* smtp_addr, int smtp_port, + const char* pop3_addr, int pop3_port, + const char* user, const char* pass, + const char* recipients, net_store_callback* callback, + bool store = false); + + static bool get_key(const char* name, acl::string& out); + static bool set_key(const char* name, const char* value); +protected: + ~net_store(); + + // 基类虚函数:子线程处理函数 + virtual void rpc_run(); + + // 基类虚函数:主线程处理过程,收到子线程任务完成的消息 + virtual void rpc_onover(); +private: + acl::string smtp_addr_; + int smtp_port_; + acl::string pop3_addr_; + int pop3_port_; + acl::string user_; + acl::string pass_; + acl::string recipients_; + net_store_callback* callback_; + bool store_; + + acl::string dbpath_; + + void load_mail_db(acl::db_handle& db); + void save_mail_db(acl::db_handle& db); + bool create_mail_tbl(acl::db_handle& db, const char* tbl_name, + const char* sql_create); +}; \ No newline at end of file diff --git a/app/net_tools/net_tools.cpp b/app/net_tools/net_tools.cpp new file mode 100644 index 000000000..f1fa52192 --- /dev/null +++ b/app/net_tools/net_tools.cpp @@ -0,0 +1,84 @@ +// net_tools.cpp : 定义应用程序的类行为。 +// + +#include "stdafx.h" + +#include "net_tools.h" +#include "net_toolsDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#endif + + +// Cnet_toolsApp + +BEGIN_MESSAGE_MAP(Cnet_toolsApp, CWinApp) + ON_COMMAND(ID_HELP, CWinApp::OnHelp) +END_MESSAGE_MAP() + + +// Cnet_toolsApp 构造 + +Cnet_toolsApp::Cnet_toolsApp() +: m_singleCtrl("net_tools_xxxxxxx") +{ + // TODO: 在此处添加构造代码, + // 将所有重要的初始化放置在 InitInstance 中 +} + + +// 唯一的一个 Cnet_toolsApp 对象 + +Cnet_toolsApp theApp; + + +// Cnet_toolsApp 初始化 + +BOOL Cnet_toolsApp::InitInstance() +{ + // 如果一个运行在 Windows XP 上的应用程序清单指定要 + // 使用 ComCtl32.dll 版本 6 或更高版本来启用可视化方式, + //则需要 InitCommonControls()。否则,将无法创建窗口。 + InitCommonControls(); + + CWinApp::InitInstance(); + + if (!m_singleCtrl.Check()) + return FALSE; + + if (!AfxSocketInit()) + { + AfxMessageBox(IDP_SOCKETS_INIT_FAILED); + return FALSE; + } + + AfxEnableControlContainer(); + + // 标准初始化 + // 如果未使用这些功能并希望减小 + // 最终可执行文件的大小,则应移除下列 + // 不需要的特定初始化例程 + // 更改用于存储设置的注册表项 + // TODO: 应适当修改该字符串, + // 例如修改为公司或组织名 + SetRegistryKey(_T("应用程序向导生成的本地应用程序")); + + Cnet_toolsDlg dlg; + m_pMainWnd = &dlg; + INT_PTR nResponse = dlg.DoModal(); + if (nResponse == IDOK) + { + // TODO: 在此放置处理何时用“确定”来关闭 + //对话框的代码 + } + else if (nResponse == IDCANCEL) + { + // TODO: 在此放置处理何时用“取消”来关闭 + //对话框的代码 + } + + // 由于对话框已关闭,所以将返回 FALSE 以便退出应用程序, + // 而不是启动应用程序的消息泵。 + return FALSE; +} diff --git a/app/net_tools/net_tools.h b/app/net_tools/net_tools.h new file mode 100644 index 000000000..b37bb8754 --- /dev/null +++ b/app/net_tools/net_tools.h @@ -0,0 +1,35 @@ +// net_tools.h : PROJECT_NAME 应用程序的主头文件 +// + +#pragma once + +#ifndef __AFXWIN_H__ + #error 在包含用于 PCH 的此文件之前包含“stdafx.h” +#endif + +#include "SingleCtrl.h" +#include "resource.h" // 主符号 + + +// Cnet_toolsApp: +// 有关此类的实现,请参阅 net_tools.cpp +// + +class Cnet_toolsApp : public CWinApp +{ +public: + Cnet_toolsApp(); + +// 重写 +public: + virtual BOOL InitInstance(); + +// 实现 + + DECLARE_MESSAGE_MAP() + +public: + CSingleCtrl m_singleCtrl; +}; + +extern Cnet_toolsApp theApp; diff --git a/app/net_tools/net_tools.manifest b/app/net_tools/net_tools.manifest new file mode 100644 index 000000000..b39907379 --- /dev/null +++ b/app/net_tools/net_tools.manifest @@ -0,0 +1,16 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/net_tools/net_tools.rc b/app/net_tools/net_tools.rc new file mode 100644 index 000000000..6cda4d592 --- /dev/null +++ b/app/net_tools/net_tools.rc @@ -0,0 +1,334 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// 中文(中华人民共和国) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) +#ifdef _WIN32 +LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED +#pragma code_page(936) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "#define _AFX_NO_SPLITTER_RESOURCES\r\n" + "#define _AFX_NO_OLE_RESOURCES\r\n" + "#define _AFX_NO_TRACKER_RESOURCES\r\n" + "#define _AFX_NO_PROPERTY_RESOURCES\r\n" + "\r\n" + "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)\r\n" + "LANGUAGE 4, 2\r\n" + "#pragma code_page(936)\r\n" + "#include ""res\\net_tools.rc2"" // 非 Microsoft Visual C++ 编辑过的资源\r\n" + "#include ""afxres.rc"" // 标准组件\r\n" + "#endif\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDR_MAINFRAME ICON "res\\net_tools.ico" +IDI_ICON_MIN ICON "res\\icon_min.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_ABOUTBOX DIALOGEX 0, 0, 235, 55 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | + WS_SYSMENU +CAPTION "关于 net_tools" +FONT 9, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + ICON IDR_MAINFRAME,IDC_STATIC,11,17,20,20 + LTEXT "net_tools Version 1.0",IDC_STATIC,40,10,119,8, + SS_NOPREFIX + LTEXT "Copyright (C) 2013",IDC_STATIC,40,25,119,8 + DEFPUSHBUTTON "确定",IDOK,178,7,50,16,WS_GROUP +END + +IDD_NET_TOOLS_DIALOG DIALOGEX 0, 0, 461, 243 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_POPUP | + WS_VISIBLE | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_APPWINDOW +CAPTION "net_tools - 二六三企业通讯" +FONT 9, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + DEFPUSHBUTTON "打开DOS窗口",IDC_OPEN_DOS,317,211,52,16 + EDITTEXT IDC_IP_FILE_PATH,87,19,288,15,ES_AUTOHSCROLL + PUSHBUTTON "浏览",IDC_LOAD_IP,388,18,51,15 + EDITTEXT IDC_NPKT,87,37,28,15,ES_AUTOHSCROLL | ES_NUMBER + EDITTEXT IDC_DELAY,162,37,25,15,ES_AUTOHSCROLL | ES_NUMBER + EDITTEXT IDC_TIMEOUT,248,37,22,14,ES_AUTOHSCROLL | ES_NUMBER + EDITTEXT IDC_PKT_SIZE,87,55,28,15,ES_AUTOHSCROLL | ES_NUMBER + PUSHBUTTON "运行",IDC_PING,388,38,50,14 + EDITTEXT IDC_DOMAIN_FILE,102,91,271,15,ES_AUTOHSCROLL + PUSHBUTTON "浏览",IDC_LOAD_DOMAIN,386,91,51,15 + CONTROL "",IDC_DNS_IP,"SysIPAddress32",WS_TABSTOP,102,110,83,13 + EDITTEXT IDC_DNS_PORT,257,110,26,14,ES_AUTOHSCROLL | ES_NUMBER + LTEXT "超时时间:",IDC_STATIC,290,112,37,12 + PUSHBUTTON "运行",IDC_NSLOOKUP,387,111,50,14 + PUSHBUTTON "退出",IDOK,384,211,52,16 + GROUPBOX "PING 测试",IDC_STATIC,26,7,414,68 + GROUPBOX "DNS 测试",IDC_STATIC,26,81,413,53 + CONTROL "IP 配置文件:",IDC_STATIC,"Static",SS_LEFTNOWORDWRAP | + WS_GROUP,37,21,47,14 + LTEXT "域名配置文件:",IDC_STATIC,46,93,53,14 + LTEXT "数据包数量:",IDC_STATIC,39,39,42,8 + LTEXT "时间间隔:",IDC_STATIC,126,39,34,14 + LTEXT "秒",IDC_STATIC,193,39,20,15 + LTEXT "超时时间:",IDC_STATIC,210,38,34,14 + LTEXT "秒",IDC_STATIC,276,39,20,15 + LTEXT "DNS 服务器地址:",IDC_STATIC,37,110,62,14 + LTEXT "DNS 服务器端口:",IDC_STATIC,193,111,60,14 + EDITTEXT IDC_LOOKUP_TIMEOUT,329,110,26,14,ES_AUTOHSCROLL | + ES_NUMBER + LTEXT "秒",IDC_STATIC,363,113,14,14 + LTEXT "数据包大小:",IDC_STATIC,39,56,47,11 + LTEXT "字节",IDC_STATIC,127,57,20,15 + PUSHBUTTON "一键测试",IDC_TESTALL,191,211,48,16 + PUSHBUTTON "配置选项",IDC_OPTION,254,211,48,16 + GROUPBOX "邮件测试",IDC_STATIC,26,141,412,58 + PUSHBUTTON "发信测试",IDC_SEND_MAIL,384,153,52,14 + LTEXT "添加附件:",IDC_STATIC,47,155,38,14 + EDITTEXT IDC_FILE,88,153,216,15,ES_AUTOHSCROLL + PUSHBUTTON "浏览",IDC_LOAD_FILE,319,153,51,15 + PUSHBUTTON "收信测试",IDC_RECV_MAIL,384,176,52,14 + LTEXT "收取邮件数量:",IDC_STATIC,33,178,53,11 + EDITTEXT IDC_RECV_LIMIT,88,177,43,14,ES_AUTOHSCROLL | ES_NUMBER + LTEXT "封",IDC_STATIC,137,180,19,14 + CONTROL "接收所有邮件",IDC_RECV_ALL,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,162,179,57,10 +END + +IDD_OPTION DIALOGEX 0, 0, 309, 337 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_POPUP | + WS_CAPTION | WS_VSCROLL | WS_HSCROLL | WS_SYSMENU +CAPTION "设置" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + EDITTEXT IDC_RECIPIENTS,107,217,121,60,ES_MULTILINE | + ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN | + WS_VSCROLL | WS_HSCROLL + PUSHBUTTON "确定",IDOK,170,298,50,14,NOT WS_TABSTOP + PUSHBUTTON "取消",IDCANCEL,225,297,50,14 + GROUPBOX "SMTP 发送服务器",IDC_STATIC,37,17,239,58 + GROUPBOX "帐号设置",IDC_STATIC,37,144,239,58 + LTEXT "服务器地址:",IDC_STATIC,50,33,52,14 + EDITTEXT IDC_SMTP_ADDR,108,32,121,14,ES_AUTOHSCROLL + EDITTEXT IDC_SMTP_PORT,107,49,37,15,ES_AUTOHSCROLL | ES_NUMBER + LTEXT "服务器端口:",IDC_STATIC,50,50,51,14 + GROUPBOX "POP3 接收服务器",IDC_STATIC,37,80,239,58 + LTEXT "服务器地址:",IDC_STATIC,49,96,52,14 + EDITTEXT IDC_POP3_ADDR,107,95,121,14,ES_AUTOHSCROLL + EDITTEXT IDC_POP3_PORT,107,112,37,15,ES_AUTOHSCROLL | ES_NUMBER + LTEXT "服务器端口:",IDC_STATIC,49,112,51,14 + LTEXT "邮箱帐号:",IDC_STATIC,57,161,42,14 + EDITTEXT IDC_USER_ACCOUNT,108,159,121,14,ES_AUTOHSCROLL + LTEXT "邮箱密码:",IDC_STATIC,57,178,42,14 + EDITTEXT IDC_USER_PASSWD,107,176,121,14,ES_PASSWORD | + ES_AUTOHSCROLL + GROUPBOX "收件人设置",IDC_STATIC,37,206,239,80 + LTEXT "接收者列表:",IDC_STATIC,48,224,51,14 + LTEXT "(多个接收者之间用分号分隔)",IDC_STATIC,48,237,51,19 + LTEXT "√",IDC_STATIC_SMTP_ADDR,237,33,32,15 + LTEXT "√",IDC_STATIC_PASS,236,177,32,15 + LTEXT "√",IDC_STATIC_POP3_ADDR,238,97,36,15 + LTEXT "√",IDC_STATIC_USER,236,161,32,15 + LTEXT "√",IDC_STATIC_RECIPIENTS,236,227,32,15 +END + +IDD_DIALOG_QUIT DIALOGEX 0, 0, 176, 89 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | + WS_SYSMENU +CAPTION "选择" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + DEFPUSHBUTTON "确定",IDOK,119,56,50,14 + CONTROL "记住选择",IDC_CHECK_SAVE,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,26,57,56,10 + CONTROL "退出",IDC_QUIT_YES,"Button",BS_AUTORADIOBUTTON,25,34,28, + 12 + CONTROL "最小化",IDC_QUIT_NO,"Button",BS_AUTORADIOBUTTON,25,17, + 43,11 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "080403a8" + BEGIN + VALUE "CompanyName", "TODO: <公司名>" + VALUE "FileDescription", "TODO: <文件说明>" + VALUE "FileVersion", "1.0.0.1" + VALUE "InternalName", "net_tools.exe" + VALUE "LegalCopyright", "TODO: (C) <公司名>。保留所有权利。" + VALUE "OriginalFilename", "net_tools.exe" + VALUE "ProductName", "TODO: <产品名>" + VALUE "ProductVersion", "1.0.0.1" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "翻译", 0x804, 936 + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_ABOUTBOX, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 228 + TOPMARGIN, 7 + BOTTOMMARGIN, 48 + END + + IDD_NET_TOOLS_DIALOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 453 + TOPMARGIN, 7 + BOTTOMMARGIN, 236 + END + + IDD_OPTION, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 291 + TOPMARGIN, 7 + BOTTOMMARGIN, 319 + END + + IDD_DIALOG_QUIT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 169 + TOPMARGIN, 7 + BOTTOMMARGIN, 82 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// RT_MANIFEST +// + +IDR_241 RT_MANIFEST "net_tools.manifest" + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDR_MENU_ICON MENU +BEGIN + POPUP "托盘菜单" + BEGIN + MENUITEM "打开主面板", ID_OPEN_MAIN + MENUITEM "退出程序", ID_QUIT + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + IDS_ABOUTBOX "关于 net_tools(&A)..." + IDP_SOCKETS_INIT_FAILED "Windows 套接字初始化失败。" +END + +#endif // 中文(中华人民共和国) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +#define _AFX_NO_SPLITTER_RESOURCES +#define _AFX_NO_OLE_RESOURCES +#define _AFX_NO_TRACKER_RESOURCES +#define _AFX_NO_PROPERTY_RESOURCES + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) +LANGUAGE 4, 2 +#pragma code_page(936) +#include "res\net_tools.rc2" // 非 Microsoft Visual C++ 编辑过的资源 +#include "afxres.rc" // 标准组件 +#endif + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/app/net_tools/net_tools.sln b/app/net_tools/net_tools.sln new file mode 100644 index 000000000..5d613978f --- /dev/null +++ b/app/net_tools/net_tools.sln @@ -0,0 +1,48 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "net_tools", "net_tools.vcproj", "{45276293-D169-4D73-8930-F255C09DA976}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + {FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lib_acl", "..\..\lib_acl\lib_acl_vc2003.vcproj", "{B40213C2-507C-4C7F-A6E1-B850C9BDC27B}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lib_protocol", "..\..\lib_protocol\lib_protocol_vc2003.vcproj", "{FE724EF7-3763-4E78-BDF5-BCBC075719FD}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lib_acl_cpp", "..\..\lib_acl_cpp\lib_acl_cpp_vc2003.vcproj", "{6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Release = Release + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {45276293-D169-4D73-8930-F255C09DA976}.Debug.ActiveCfg = Debug|Win32 + {45276293-D169-4D73-8930-F255C09DA976}.Debug.Build.0 = Debug|Win32 + {45276293-D169-4D73-8930-F255C09DA976}.Release.ActiveCfg = Release|Win32 + {45276293-D169-4D73-8930-F255C09DA976}.Release.Build.0 = Release|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Debug.ActiveCfg = DebugDll|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Debug.Build.0 = DebugDll|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Release.ActiveCfg = ReleaseDll|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Release.Build.0 = ReleaseDll|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Debug.ActiveCfg = DebugDll|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Debug.Build.0 = DebugDll|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Release.ActiveCfg = ReleaseDll|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Release.Build.0 = ReleaseDll|Win32 + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.Debug.ActiveCfg = DebugDll|Win32 + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.Debug.Build.0 = DebugDll|Win32 + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.Release.ActiveCfg = Releasedll|Win32 + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.Release.Build.0 = Releasedll|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/app/net_tools/net_tools.txt b/app/net_tools/net_tools.txt new file mode 100644 index 000000000..76b93649d --- /dev/null +++ b/app/net_tools/net_tools.txt @@ -0,0 +1,7 @@ +2013/03/13 10:15:55 net_tools (pid=4052)(info): sqlite3.dll loaded +2013/03/13 10:15:55 net_tools (pid=4052)(info): table(mail_tbl) exist +2013/03/13 10:15:55 net_tools (pid=4052)(error): sqlites_get_table(select smtp_addr, smtp_port, pop3_addr, pop3_port, user, pass, recipients from mail_tbl) error(no such column: smtp_port) +2013/03/13 10:15:55 net_tools (pid=4052)(error): sql(select smtp_addr, smtp_port, pop3_addr, pop3_port, user, pass, recipients from mail_tbl) error +2013/03/13 10:16:06 net_tools (pid=4052)(info): table(mail_tbl) exist +2013/03/13 10:16:06 net_tools (pid=4052)(error): sqlites_get_table(insert into mail_tbl(smtp_addr, smtp_port, pop3_addr, pop3_port, user, pass, recipients) values('smtpcom.263xmail.com', 25, 'popcom.263xmail.com', 110, 'shuxin.zheng@net263.com', 'PiDMbTuA15EkoAcOR4zB9u2eOrpXMg2g/Q==', 'wang.li@net263.com,shuxin.zheng@net263.com,jian.shao@net263.com')) error(table mail_tbl has no column named smtp_port) +2013/03/13 10:16:06 net_tools (pid=4052)(error): sql(insert into mail_tbl(smtp_addr, smtp_port, pop3_addr, pop3_port, user, pass, recipients) values('smtpcom.263xmail.com', 25, 'popcom.263xmail.com', 110, 'shuxin.zheng@net263.com', 'PiDMbTuA15EkoAcOR4zB9u2eOrpXMg2g/Q==', 'wang.li@net263.com,shuxin.zheng@net263.com,jian.shao@net263.com')) error diff --git a/app/net_tools/net_tools.vcproj b/app/net_tools/net_tools.vcproj new file mode 100644 index 000000000..743878429 --- /dev/null +++ b/app/net_tools/net_tools.vcproj @@ -0,0 +1,398 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/net_tools/net_toolsDlg.cpp b/app/net_tools/net_toolsDlg.cpp new file mode 100644 index 000000000..c9cbb99d1 --- /dev/null +++ b/app/net_tools/net_toolsDlg.cpp @@ -0,0 +1,1103 @@ +// net_toolsDlg.cpp : 实现文件 +// + +#include "stdafx.h" +#include "net_tools.h" +#include "ping/ping.h" +#include "dns/nslookup.h" +#include "upload/upload.h" +#include "rpc/rpc_manager.h" +#include "ui/TrayIcon.h" +#include "NetOption.h" +#include "net_store.h" +#include "global/util.h" +#include "OptionOnClose.h" +#include "net_toolsDlg.h" +#include ".\net_toolsdlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#endif + + +// 用于应用程序“关于”菜单项的 CAboutDlg 对话框 + +class CAboutDlg : public CDialog +{ +public: + CAboutDlg(); + +// 对话框数据 + enum { IDD = IDD_ABOUTBOX }; + + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 + +// 实现 +protected: + DECLARE_MESSAGE_MAP() +}; + +CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) +{ +} + +void CAboutDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); +} + +BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) +END_MESSAGE_MAP() + + +// Cnet_toolsDlg 对话框 + + + +Cnet_toolsDlg::Cnet_toolsDlg(CWnd* pParent /*=NULL*/) + : CDialog(Cnet_toolsDlg::IDD, pParent) + , m_nPkt(100) + , m_delay(1) + , m_pingTimeout(5) + , m_pingBusy(FALSE) + , m_dosFp(NULL) + , m_dnsIp("8.8.8.8") + , m_dnsPort(53) + , m_lookupTimeout(10) + , m_pktSize(64) + , m_dnsBusy(FALSE) + , m_smtpAddr("smtpcom.263xmail.com") + , m_smtpPort(25) + , m_connecTimeout(60) + , m_rwTimeout(60) + , m_pop3Addr("popcom.263xmail.com") + , m_pop3Port(110) + , m_recvLimit(1) + , m_recvAll(FALSE) + , m_smtpUser("") + , m_smtpPass("") + , m_recipients("wang.li@net263.com;shuxin.zheng@net263.com;jian.shao@net263.com") + , m_trayIcon(IDR_MENU_ICON) + , m_bShutdown(FALSE) + , m_ipFilePath("263ip.txt") + , m_domainFilePath("263domain.txt") + , m_attachFilePath("ReadMe.txt") +{ + m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); + acl_netdb_cache_init(0, 1); +} + +Cnet_toolsDlg::~Cnet_toolsDlg() +{ + if (m_dosFp) + { + fclose(m_dosFp); + FreeConsole(); + } +} + +void Cnet_toolsDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + DDX_Text(pDX, IDC_NPKT, m_nPkt); + DDX_Text(pDX, IDC_DELAY, m_delay); + DDX_Text(pDX, IDC_TIMEOUT, m_pingTimeout); + DDX_Text(pDX, IDC_DNS_IP, m_dnsIp); + DDX_Text(pDX, IDC_DNS_PORT, m_dnsPort); + DDX_Text(pDX, IDC_LOOKUP_TIMEOUT, m_lookupTimeout); + DDX_Text(pDX, IDC_PKT_SIZE, m_pktSize); + DDX_Text(pDX, IDC_RECV_LIMIT, m_recvLimit); + DDX_Check(pDX, IDC_RECV_ALL, m_recvAll); + DDX_Text(pDX, IDC_IP_FILE_PATH, m_ipFilePath); + DDX_Text(pDX, IDC_DOMAIN_FILE, m_domainFilePath); + DDX_Text(pDX, IDC_FILE, m_attachFilePath); +} + +BEGIN_MESSAGE_MAP(Cnet_toolsDlg, CDialog) + ON_WM_SYSCOMMAND() + ON_WM_PAINT() + ON_WM_QUERYDRAGICON() + //}}AFX_MSG_MAP + ON_BN_CLICKED(IDC_LOAD_IP, OnBnClickedLoadIp) + ON_BN_CLICKED(IDC_PING, OnBnClickedPing) + ON_BN_CLICKED(IDC_LOAD_DOMAIN, OnBnClickedLoadDomain) + ON_BN_CLICKED(IDC_NSLOOKUP, OnBnClickedNslookup) + ON_BN_CLICKED(IDC_OPEN_DOS, OnBnClickedOpenDos) + ON_BN_CLICKED(IDC_OPTION, OnBnClickedOption) + ON_BN_CLICKED(IDC_TESTALL, OnBnClickedTestall) + ON_COMMAND(ID_OPEN_MAIN, OnOpenMain) + ON_COMMAND(ID_QUIT, OnQuit) + ON_WM_CLOSE() + ON_WM_NCPAINT() + ON_MESSAGE(WM_MY_TRAY_NOTIFICATION, OnTrayNotification) + ON_WM_CREATE() + ON_BN_CLICKED(IDC_LOAD_FILE, OnBnClickedLoadFile) + ON_BN_CLICKED(IDC_SEND_MAIL, OnBnClickedSendMail) + ON_BN_CLICKED(IDC_RECV_MAIL, OnBnClickedRecvMail) + ON_EN_SETFOCUS(IDC_IP_FILE_PATH, OnEnSetfocusIpFilePath) + ON_EN_SETFOCUS(IDC_DOMAIN_FILE, OnEnSetfocusDomainFile) + ON_EN_SETFOCUS(IDC_FILE, OnEnSetfocusFile) + ON_BN_CLICKED(IDC_RECV_ALL, OnBnClickedRecvAll) + ON_WM_DESTROY() + ON_EN_KILLFOCUS(IDC_IP_FILE_PATH, OnEnKillfocusIpFilePath) + ON_EN_KILLFOCUS(IDC_NPKT, OnEnKillfocusNpkt) + ON_EN_KILLFOCUS(IDC_DELAY, OnEnKillfocusDelay) + ON_EN_KILLFOCUS(IDC_TIMEOUT, OnEnKillfocusTimeout) + ON_EN_KILLFOCUS(IDC_PKT_SIZE, OnEnKillfocusPktSize) + ON_EN_KILLFOCUS(IDC_DOMAIN_FILE, OnEnKillfocusDomainFile) + ON_EN_KILLFOCUS(IDC_DNS_PORT, OnEnKillfocusDnsPort) + ON_EN_KILLFOCUS(IDC_LOOKUP_TIMEOUT, OnEnKillfocusLookupTimeout) + ON_EN_KILLFOCUS(IDC_FILE, OnEnKillfocusFile) + ON_EN_KILLFOCUS(IDC_RECV_LIMIT, OnEnKillfocusRecvLimit) + ON_BN_KILLFOCUS(IDC_RECV_ALL, OnBnKillfocusRecvAll) +END_MESSAGE_MAP() + + +// Cnet_toolsDlg 消息处理程序 + +BOOL Cnet_toolsDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + // 将\“关于...\”菜单项添加到系统菜单中。 + + // IDM_ABOUTBOX 必须在系统命令范围内。 + ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); + ASSERT(IDM_ABOUTBOX < 0xF000); + + CMenu* pSysMenu = GetSystemMenu(FALSE); + if (pSysMenu != NULL) + { + CString strAboutMenu; + strAboutMenu.LoadString(IDS_ABOUTBOX); + if (!strAboutMenu.IsEmpty()) + { + pSysMenu->AppendMenu(MF_SEPARATOR); + pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); + } + } + + // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动 + // 执行此操作 + SetIcon(m_hIcon, TRUE); // 设置大图标 + SetIcon(m_hIcon, FALSE); // 设置小图标 + + //ShowWindow(SW_MAXIMIZE); + + // TODO: 在此添加额外的初始化代码 + + theApp.m_singleCtrl.Register(); + + // 添加状态栏 + int aWidths[3] = {50, 400, -1}; + m_wndMeterBar.SetParts(3, aWidths); + + m_wndMeterBar.Create(WS_CHILD | WS_VISIBLE | WS_BORDER + | CCS_BOTTOM | SBARS_SIZEGRIP, + CRect(0,0,0,0), this, 0); + m_wndMeterBar.SetText("就绪", 0, 0); + m_wndMeterBar.SetText("", 1, 0); + m_wndMeterBar.SetText("", 2, 0); + + // 取得本机的DNS服务器 + std::vector dns_list; + if (util::get_dns(dns_list) > 0) + { + m_dnsIp = dns_list[0]; + UpdateData(FALSE); + } + + const char* path = acl_getcwd(); + acl::string logpath; + logpath.format("%s/net_tools.txt", path); + logger_open(logpath.c_str(), "net_tools"); + + // 从数据库中读取配置项 + net_store* ns = new net_store(m_smtpAddr, m_smtpPort, m_pop3Addr, m_pop3Port, + m_smtpUser, m_smtpPass, m_recipients, this); + rpc_manager::get_instance().fork(ns); + + //DisableAll(); + if (m_ipFilePath.IsEmpty()) + GetDlgItem(IDC_PING)->EnableWindow(FALSE); + if (m_domainFilePath.IsEmpty()) + GetDlgItem(IDC_NSLOOKUP)->EnableWindow(FALSE); + + return TRUE; // 除非设置了控件的焦点,否则返回 TRUE +} + +void Cnet_toolsDlg::OnSysCommand(UINT nID, LPARAM lParam) +{ + if ((nID & 0xFFF0) == IDM_ABOUTBOX) + { + CAboutDlg dlgAbout; + dlgAbout.DoModal(); + } + else + { + CDialog::OnSysCommand(nID, lParam); + } +} + +// 如果向对话框添加最小化按钮,则需要下面的代码 +// 来绘制该图标。对于使用文档/视图模型的 MFC 应用程序, +// 这将由框架自动完成。 + +void Cnet_toolsDlg::OnPaint() +{ + if (IsIconic()) + { + CPaintDC dc(this); // 用于绘制的设备上下文 + + SendMessage(WM_ICONERASEBKGND, reinterpret_cast(dc.GetSafeHdc()), 0); + + // 使图标在工作矩形中居中 + int cxIcon = GetSystemMetrics(SM_CXICON); + int cyIcon = GetSystemMetrics(SM_CYICON); + CRect rect; + GetClientRect(&rect); + int x = (rect.Width() - cxIcon + 1) / 2; + int y = (rect.Height() - cyIcon + 1) / 2; + + // 绘制图标 + dc.DrawIcon(x, y, m_hIcon); + } + else + { + CDialog::OnPaint(); + } +} + +//当用户拖动最小化窗口时系统调用此函数取得光标显示。 +HCURSOR Cnet_toolsDlg::OnQueryDragIcon() +{ + return static_cast(m_hIcon); +} + +void Cnet_toolsDlg::OnBnClickedOpenDos() +{ + // TODO: 在此添加控件通知处理程序代码 + if (m_dosFp == NULL) + { + //GetDlgItem(IDC_OPEN_DOS)->EnableWindow(FALSE); + AllocConsole(); + m_dosFp = freopen("CONOUT$","w+t",stdout); + printf("DOS opened now!\r\n"); + const char* path = acl_getcwd(); + printf("current path: %s\r\n", path); + GetDlgItem(IDC_OPEN_DOS)->SetWindowText("关闭 DOS 窗口"); + acl::log::stdout_open(true); + logger_close(); + } + else + { + fclose(m_dosFp); + m_dosFp = NULL; + FreeConsole(); + GetDlgItem(IDC_OPEN_DOS)->SetWindowText("打开 DOS 窗口"); + acl::log::stdout_open(false); + const char* path = acl_getcwd(); + acl::string logpath; + logpath.format("%s/net_tools.txt", path); + printf("current path: %s\r\n", path); + logger_open(logpath.c_str(), "net_tools"); + } +} + +void Cnet_toolsDlg::upload_report(const char* msg, size_t total, + size_t curr, const UPLOAD_METER& meter) +{ + if (total > 0) + { + int nStept; + + nStept = (int) ((curr * 100) / total); + m_wndMeterBar.GetProgressCtrl().SetPos(nStept); + } + + m_wndMeterBar.SetText(msg, 1, 0); +} + +void Cnet_toolsDlg::load_db_callback(const char* smtp_addr, int smtp_port, + const char* pop3_addr, int pop3_port, const char* user, + const char* pass, const char* recipients, bool store) +{ + if (smtp_addr && *smtp_addr) + m_smtpAddr = smtp_addr; + m_smtpPort = smtp_port; + if (pop3_addr && *pop3_addr) + m_pop3Addr = pop3_addr; + m_pop3Port = pop3_port; + if (user && *user) + m_smtpUser = user; + if (pass && *pass) + m_smtpPass = pass; + if (recipients && *recipients) + m_recipients = recipients; + + check(); + + // 如果有一个必填的配置项非空,则强制用户填写 + if (m_smtpAddr.IsEmpty() || m_pop3Addr.IsEmpty() + || m_smtpUser.IsEmpty() || m_smtpPass.IsEmpty() + || m_recipients.IsEmpty()) + { + OnBnClickedOption(); + return; + } + + if (store == false) + UpdateData(FALSE); +} + +void Cnet_toolsDlg::OnBnClickedOption() +{ + // TODO: 在此添加控件通知处理程序代码 + //CNetOption option(m_smtpAddr, m_pop3Addr, m_smtpUser, m_smtpPass, + // m_recipients); + CNetOption option; + option.SetSmtpAddr(m_smtpAddr, m_smtpPort) + .SetPop3Addr(m_pop3Addr, m_pop3Port) + .SetUserAccount(m_smtpUser) + .SetUserPasswd(m_smtpPass) + .SetRecipients(m_recipients); + if (option.DoModal() == IDOK) + { + m_smtpAddr = option.GetSmtpAddr(); + m_pop3Addr = option.GetPop3Addr(); + m_smtpPort = option.getSmtpPort(); + m_pop3Port = option.getPop3Port(); + m_smtpUser = option.GetUserAccount(); + m_smtpPass = option.GetUserPasswd(); + CString tmp = option.GetRecipients(); + ACL_ARGV* tokens = acl_argv_split(tmp.GetString(), " \t,;\r\n"); + ACL_ITER iter; + acl::string buf; + acl_foreach(iter, tokens) + { + if (iter.i > 0) + buf << ","; + buf << (char*) iter.data; + } + acl_argv_free(tokens); + m_recipients = buf.c_str(); + + net_store* ns = new net_store(m_smtpAddr.GetString(), m_smtpPort, + m_pop3Addr.GetString(), m_pop3Port, + m_smtpUser.GetString(), m_smtpPass.GetString(), + m_recipients.GetString(), this, true); + rpc_manager::get_instance().fork(ns); + check(); + } + else + { + check(); + } +} + +void Cnet_toolsDlg::OnOpenMain() +{ + // TODO: 在此添加命令处理程序代码 + ShowWindow(SW_NORMAL); +} + +void Cnet_toolsDlg::OnQuit() +{ + // TODO: 在此添加命令处理程序代码 + m_bShutdown = TRUE; + SendMessage(WM_CLOSE); +} + +void Cnet_toolsDlg::OnClose() +{ + // TODO: 在此添加消息处理程序代码和/或调用默认值 + + //__super::OnClose(); + acl::string buf; + + net_store::get_key("QuitOnClose", buf); + if (m_bShutdown || buf.compare("yes", false) == 0) + { + CDialog::OnClose(); + return; + } + else if (buf.compare("no", false) == 0) + { + ShowWindow(SW_HIDE); + return; + } + + COptionOnClose dlg; + dlg.init(FALSE); + if (dlg.DoModal() == IDOK) + { + BOOL quit = dlg.m_QuitClose; + BOOL save = dlg.m_SaveOption; + if (save) + net_store::set_key("QuitOnClose", quit ? "yes" : "no"); + if (quit) + CDialog::OnClose(); + else + ShowWindow(SW_HIDE); + } +} + +void Cnet_toolsDlg::OnNcPaint() +{ + // TODO: 在此处添加消息处理程序代码 + // 不为绘图消息调用 __super::OnNcPaint() + //static int i = 2; + //if(i > 0) + //{ + // i --; + // ShowWindow(SW_HIDE); + //} else + //{ + CDialog::OnNcPaint(); + //} +} + +int Cnet_toolsDlg::OnCreate(LPCREATESTRUCT lpCreateStruct) +{ + if (__super::OnCreate(lpCreateStruct) == -1) + return -1; + + // TODO: 在此添加您专用的创建代码 + + m_trayIcon.SetNotificationWnd(this, WM_MY_TRAY_NOTIFICATION); + m_trayIcon.SetIcon(IDI_ICON_MIN); + + return 0; +} + +afx_msg LRESULT Cnet_toolsDlg::OnTrayNotification(WPARAM uID, LPARAM lEvent) +{ + // let tray icon do default stuff + return m_trayIcon.OnTrayNotification(uID, lEvent); +} + +////////////////////////////////////////////////////////////////////////// + +void Cnet_toolsDlg::OnEnSetfocusDomainFile() +{ + // TODO: 在此添加控件通知处理程序代码 + CString pathname; + + GetDlgItem(IDC_DOMAIN_FILE)->GetWindowText(pathname); + if (pathname.IsEmpty()) + { + GetDlgItem(IDC_LOAD_DOMAIN)->SetFocus(); + OnBnClickedLoadDomain(); + } + check(); +} + +void Cnet_toolsDlg::OnBnClickedLoadDomain() +{ + // TODO: 在此添加控件通知处理程序代码 + CFileDialog file(TRUE,"文件","",OFN_HIDEREADONLY,"FILE(*.*)|*.*||",NULL); + if(file.DoModal()==IDOK) + { + CString pathname; + + pathname=file.GetPathName(); + GetDlgItem(IDC_DOMAIN_FILE)->SetWindowText(pathname); + GetDlgItem(IDC_NSLOOKUP)->EnableWindow(TRUE); + check(); + } +} + +void Cnet_toolsDlg::OnBnClickedNslookup() +{ + // TODO: 在此添加控件通知处理程序代码 + + if (m_dnsBusy) + return; + + UpdateData(); + + GetDlgItem(IDC_NSLOOKUP)->EnableWindow(FALSE); + + CString filePath; + GetDlgItem(IDC_DOMAIN_FILE)->GetWindowText(filePath); + if (filePath.IsEmpty()) + { + MessageBox("请先选择域名列表配置文件!"); + return; + } + + m_dnsBusy = TRUE; + + GetDlgItem(IDC_LOAD_DOMAIN)->EnableWindow(FALSE); + + logger("dns_ip: %s, dns_port: %d, dns_timeout: %d", + m_dnsIp.GetString(), m_dnsPort, m_lookupTimeout); + + nslookup* dns = new nslookup(filePath.GetString(), this, + m_dnsIp.GetString(), m_dnsPort, m_lookupTimeout); + rpc_manager::get_instance().fork(dns); +} + +void Cnet_toolsDlg::nslookup_report(size_t total, size_t curr) +{ + if (total > 0) + { + int nStept; + + nStept = (int) ((curr * 100) / total); + m_wndMeterBar.GetProgressCtrl().SetPos(nStept); + } + + CString msg; + msg.Format("共 %d 个域名, 完成 %d 个域名", total, curr); + m_wndMeterBar.SetText(msg, 1, 0); +} + +void Cnet_toolsDlg::nslookup_finish(const char* dbpath) +{ + m_dnsBusy = FALSE; + + GetDlgItem(IDC_LOAD_DOMAIN)->EnableWindow(TRUE); + CString filePath; + GetDlgItem(IDC_DOMAIN_FILE)->GetWindowText(filePath); + if (filePath.IsEmpty()) + GetDlgItem(IDC_NSLOOKUP)->EnableWindow(FALSE); + else + GetDlgItem(IDC_NSLOOKUP)->EnableWindow(TRUE); + + if (dbpath && *dbpath) + { + // 将数据库文件发邮件至服务器 + upload* up = new upload(); + (*up).set_callback(this) + .add_file(dbpath) + .set_server(m_smtpAddr.GetString(), m_smtpPort) + .set_conn_timeout(m_connecTimeout) + .set_rw_timeout(m_rwTimeout) + .set_account(m_smtpUser.GetString()) + .set_passwd(m_smtpPass.GetString()) + .set_from(m_smtpUser.GetString()) + .set_subject("DNS 查询结果数据") + .add_to(m_recipients.GetString()); + rpc_manager::get_instance().fork(up); + } +} + +////////////////////////////////////////////////////////////////////////// + +void Cnet_toolsDlg::OnEnSetfocusIpFilePath() +{ + // TODO: 在此添加控件通知处理程序代码 + CString pathname; + + GetDlgItem(IDC_IP_FILE_PATH)->GetWindowText(pathname); + if (pathname.IsEmpty()) + { + GetDlgItem(IDC_LOAD_IP)->SetFocus(); + OnBnClickedLoadIp(); + } + check(); +} + +void Cnet_toolsDlg::OnBnClickedLoadIp() +{ + // TODO: 在此添加控件通知处理程序代码 + CFileDialog file(TRUE,"文件","",OFN_HIDEREADONLY,"FILE(*.*)|*.*||",NULL); + if(file.DoModal()==IDOK) + { + CString pathname; + + pathname=file.GetPathName(); + GetDlgItem(IDC_IP_FILE_PATH)->SetWindowText(pathname); + GetDlgItem(IDC_PING)->EnableWindow(TRUE); + check(); + } +} + +void Cnet_toolsDlg::OnBnClickedPing() +{ + // TODO: 在此添加控件通知处理程序代码 + if (m_pingBusy) + return; + + UpdateData(); + + GetDlgItem(IDC_PING)->EnableWindow(FALSE); + + CString filePath; + GetDlgItem(IDC_IP_FILE_PATH)->GetWindowText(filePath); + if (filePath.IsEmpty()) + { + MessageBox("请先选择 ip 列表配置文件!"); + + return; + } + + m_pingBusy = TRUE; + + GetDlgItem(IDC_LOAD_IP)->EnableWindow(FALSE); + logger("npkt: %d, delay: %d, timeout: %d", + m_nPkt, m_delay, m_pingTimeout); + + ping* p = new ping(filePath.GetString(), this, + m_nPkt, m_delay, m_pingTimeout, m_pktSize); + rpc_manager::get_instance().fork(p); +} + +void Cnet_toolsDlg::ping_report(size_t total, size_t curr, size_t nerror) +{ + if (total > 0) + { + int nStept; + + nStept = (int) ((curr * 100) / total); + m_wndMeterBar.GetProgressCtrl().SetPos(nStept); + } + + CString msg; + msg.Format("%d/%d; failed: %d", curr, total, nerror); + m_wndMeterBar.SetText(msg, 1, 0); +} + +void Cnet_toolsDlg::ping_finish(const char* dbpath) +{ + m_pingBusy = FALSE; + + GetDlgItem(IDC_LOAD_IP)->EnableWindow(TRUE); + CString filePath; + GetDlgItem(IDC_IP_FILE_PATH)->GetWindowText(filePath); + if (filePath.IsEmpty()) + GetDlgItem(IDC_PING)->EnableWindow(FALSE); + else + GetDlgItem(IDC_PING)->EnableWindow(TRUE); + + if (dbpath && *dbpath) + { + // 将数据库文件发邮件至服务器 + upload* up = new upload(); + (*up).set_callback(this) + .add_file(dbpath) + .set_server(m_smtpAddr.GetString(), m_smtpPort) + .set_conn_timeout(m_connecTimeout) + .set_rw_timeout(m_rwTimeout) + .set_account(m_smtpUser.GetString()) + .set_passwd(m_smtpPass.GetString()) + .set_from(m_smtpUser.GetString()) + .set_subject("PING 结果数据") + .add_to(m_recipients.GetString()); + rpc_manager::get_instance().fork(up); + } +} + +////////////////////////////////////////////////////////////////////////// + +void Cnet_toolsDlg::OnEnSetfocusFile() +{ + // TODO: 在此添加控件通知处理程序代码 + CString pathname; + + GetDlgItem(IDC_FILE)->GetWindowText(pathname); + if (pathname.IsEmpty()) + { + GetDlgItem(IDC_LOAD_FILE)->SetFocus(); + OnBnClickedLoadFile(); + } + check(); +} + +void Cnet_toolsDlg::OnBnClickedLoadFile() +{ + // TODO: 在此添加控件通知处理程序代码 + CFileDialog file(TRUE,"文件","",OFN_HIDEREADONLY,"FILE(*.*)|*.*||",NULL); + if(file.DoModal()==IDOK) + { + CString pathname; + + pathname=file.GetPathName(); + GetDlgItem(IDC_FILE)->SetWindowText(pathname); + GetDlgItem(IDC_SEND_MAIL)->EnableWindow(TRUE); + check(); + } +} + +void Cnet_toolsDlg::OnBnClickedSendMail() +{ + // TODO: 在此添加控件通知处理程序代码 + // 发邮件至服务器 + + UpdateData(); + + GetDlgItem(IDC_SEND_MAIL)->EnableWindow(FALSE); + + CString filePath; + GetDlgItem(IDC_FILE)->GetWindowText(filePath); + if (filePath.IsEmpty()) + { + MessageBox("请先选择附件!"); + return; + } + + smtp_client* smtp = new smtp_client(); + (*smtp).set_callback(this) + .add_file(filePath.GetString()) + .set_smtp(m_smtpAddr, m_smtpPort) + .set_conn_timeout(m_connecTimeout) + .set_rw_timeout(m_rwTimeout) + .set_account(m_smtpUser.GetString()) + .set_passwd(m_smtpPass.GetString()) + .set_from(m_smtpUser.GetString()) + .set_subject("测试邮件发送过程!") + .add_to(m_recipients.GetString()); + rpc_manager::get_instance().fork(smtp); +} + +void Cnet_toolsDlg::smtp_report(const char* msg, size_t total, + size_t curr, const SMTP_METER&) +{ + if (total > 0) + { + int nStept; + + nStept = (int) ((curr * 100) / total); + m_wndMeterBar.GetProgressCtrl().SetPos(nStept); + } + + m_wndMeterBar.SetText(msg, 1, 0); +} + +void Cnet_toolsDlg::smtp_finish(const char* dbpath) +{ + GetDlgItem(IDC_LOAD_FILE)->EnableWindow(TRUE); + CString filePath; + GetDlgItem(IDC_FILE)->GetWindowText(filePath); + if (filePath.IsEmpty()) + GetDlgItem(IDC_SEND_MAIL)->EnableWindow(FALSE); + else + GetDlgItem(IDC_SEND_MAIL)->EnableWindow(TRUE); + + if (dbpath && *dbpath) + { + // 将数据库文件发邮件至服务器 + upload* up = new upload(); + (*up).set_callback(this) + .add_file(dbpath) + .set_server(m_smtpAddr.GetString(), m_smtpPort) + .set_conn_timeout(m_connecTimeout) + .set_rw_timeout(m_rwTimeout) + .set_account(m_smtpUser.GetString()) + .set_passwd(m_smtpPass.GetString()) + .set_from(m_smtpUser.GetString()) + .set_subject("邮件发送结果数据") + .add_to(m_recipients.GetString()); + rpc_manager::get_instance().fork(up); + } +} + +////////////////////////////////////////////////////////////////////////// + +void Cnet_toolsDlg::OnBnClickedRecvMail() +{ + // TODO: 在此添加控件通知处理程序代码 + UpdateData(); + + GetDlgItem(IDC_RECV_MAIL)->EnableWindow(FALSE); + + pop3_client* pop3 = new pop3_client(); + (*pop3).set_callback(this) + .set_pop3(m_pop3Addr, m_pop3Port) + .set_conn_timeout(m_connecTimeout) + .set_rw_timeout(m_rwTimeout) + .set_account(m_smtpUser.GetString()) + .set_passwd(m_smtpPass.GetString()) + .set_recv_count(m_recvAll ? -1 : m_recvLimit); + rpc_manager::get_instance().fork(pop3); +} + +void Cnet_toolsDlg::pop3_report(const char* msg, size_t total, + size_t curr, const POP3_METER&) +{ + if (total > 0) + { + int nStept; + + nStept = (int) ((curr * 100) / total); + m_wndMeterBar.GetProgressCtrl().SetPos(nStept); + } + + m_wndMeterBar.SetText(msg, 1, 0); +} + +void Cnet_toolsDlg::pop3_finish(const char* dbpath) +{ + GetDlgItem(IDC_RECV_MAIL)->EnableWindow(TRUE); + + if (dbpath && *dbpath) + { + // 将数据库文件发邮件至服务器 + upload* up = new upload(); + (*up).set_callback(this) + .add_file(dbpath) + .set_server(m_smtpAddr.GetString(), m_smtpPort) + .set_conn_timeout(m_connecTimeout) + .set_rw_timeout(m_rwTimeout) + .set_account(m_smtpUser.GetString()) + .set_passwd(m_smtpPass.GetString()) + .set_from(m_smtpUser.GetString()) + .set_subject("邮件接收结果数据") + .add_to(m_recipients.GetString()); + rpc_manager::get_instance().fork(up); + } +} + +////////////////////////////////////////////////////////////////////////// + +void Cnet_toolsDlg::OnBnClickedTestall() +{ + // TODO: 在此添加控件通知处理程序代码 + UpdateData(TRUE); + + CString ipFile; + GetDlgItem(IDC_IP_FILE_PATH)->GetWindowText(ipFile); + CString domainFile; + GetDlgItem(IDC_DOMAIN_FILE)->GetWindowText(domainFile); + CString attach; + GetDlgItem(IDC_FILE)->GetWindowText(attach); + + if (ipFile.IsEmpty() || domainFile.IsEmpty() || attach.IsEmpty()) + { + CString msg; + msg.Format("请保证非空项:IP 配置文件,域名配置文件,添加附件"); + MessageBox(msg); + return; + } + + GetDlgItem(IDC_TESTALL)->EnableWindow(FALSE); + + test_all* test = new test_all(this); + (*test).set_ip_file(ipFile.GetString()) + .set_ping_npkt(m_nPkt) + .set_ping_delay(m_delay) + .set_ping_timeout(m_pingTimeout) + .set_ping_size(m_pktSize) + .set_domain_file(domainFile) + .set_dns_ip(m_dnsIp.GetString()) + .set_dns_port(m_dnsPort) + .set_dns_timeout(m_lookupTimeout) + .set_attach(attach.GetString()) + .set_smtp_addr(m_smtpAddr.GetString()) + .set_smtp_port(m_smtpPort) + .set_conn_timeout(m_connecTimeout) + .set_rw_timeout(m_rwTimeout) + .set_mail_user(m_smtpUser.GetString()) + .set_mail_pass(m_smtpPass.GetString()) + .set_recipients(m_recipients.GetString()) + .set_pop3_addr(m_pop3Addr) + .set_pop3_port(m_pop3Port) + .set_pop3_recv(m_recvAll ? -1 : m_recvLimit); + test->start(); +} + +void Cnet_toolsDlg::test_report(const char* msg, unsigned nstep) +{ + m_wndMeterBar.GetProgressCtrl().SetPos(nstep); + m_wndMeterBar.SetText(msg, 1, 0); +} + +void Cnet_toolsDlg::test_store(const char* dbpath) +{ + if (dbpath && *dbpath) + attaches_.push_back(dbpath); +} + +void Cnet_toolsDlg::test_finish() +{ + GetDlgItem(IDC_TESTALL)->EnableWindow(TRUE); + + if (attaches_.empty()) + return; + + // 将数据库文件发邮件至服务器 + upload* up = new upload(); + (*up).set_callback(this) + .set_server(m_smtpAddr.GetString(), m_smtpPort) + .set_conn_timeout(m_connecTimeout) + .set_rw_timeout(m_rwTimeout) + .set_account(m_smtpUser.GetString()) + .set_passwd(m_smtpPass.GetString()) + .set_from(m_smtpUser.GetString()) + .set_subject("一键测试结果数据") + .add_to(m_recipients.GetString()); + + std::vector::const_iterator cit = attaches_.begin(); + for (; cit != attaches_.end(); ++cit) + (*up).add_file((*cit).c_str()); + rpc_manager::get_instance().fork(up); + + attaches_.clear(); +} + +////////////////////////////////////////////////////////////////////////// + +void Cnet_toolsDlg::OnBnClickedRecvAll() +{ + // TODO: 在此添加控件通知处理程序代码 + UpdateData(TRUE); + if (IsDlgButtonChecked(IDC_RECV_ALL)) + { + GetDlgItem(IDC_RECV_LIMIT)->EnableWindow(FALSE); + GetDlgItem(IDC_RECV_LIMIT)->SetWindowText("0"); + } + else + { + GetDlgItem(IDC_RECV_LIMIT)->EnableWindow(TRUE); + GetDlgItem(IDC_RECV_LIMIT)->SetWindowText("1"); + } + check(); +} + +void Cnet_toolsDlg::OnDestroy() +{ + __super::OnDestroy(); + + // TODO: 在此处添加消息处理程序代码 + theApp.m_singleCtrl.Remove(); +} + +void Cnet_toolsDlg::check() +{ + UpdateData(TRUE); + + if (m_smtpAddr.IsEmpty() || m_pop3Addr.IsEmpty() + || m_smtpUser.IsEmpty() || m_smtpPass.IsEmpty() + || m_recipients.IsEmpty() || m_smtpPort == 0 + || m_connecTimeout == 0 || m_rwTimeout == 0) + { + GetDlgItem(IDC_PING)->EnableWindow(FALSE); + GetDlgItem(IDC_NSLOOKUP)->EnableWindow(FALSE); + GetDlgItem(IDC_SEND_MAIL)->EnableWindow(FALSE); + GetDlgItem(IDC_RECV_MAIL)->EnableWindow(FALSE); + GetDlgItem(IDC_TESTALL)->EnableWindow(FALSE); + return; + } + + int nok = 0; + + if (m_ipFilePath.IsEmpty() || m_nPkt == 0 + || m_delay == 0 || m_pingTimeout == 0 + || m_pktSize == 0) + { + GetDlgItem(IDC_PING)->EnableWindow(FALSE); + GetDlgItem(IDC_TESTALL)->EnableWindow(FALSE); + } + else + { + GetDlgItem(IDC_PING)->EnableWindow(TRUE); + nok++; + } + + if (m_domainFilePath.IsEmpty() || m_dnsIp.IsEmpty() + || m_dnsPort == 0 || m_lookupTimeout == 0) + { + GetDlgItem(IDC_NSLOOKUP)->EnableWindow(FALSE); + GetDlgItem(IDC_TESTALL)->EnableWindow(FALSE); + } + else + { + GetDlgItem(IDC_NSLOOKUP)->EnableWindow(TRUE); + nok++; + } + + if (m_attachFilePath.IsEmpty()) + { + GetDlgItem(IDC_SEND_MAIL)->EnableWindow(FALSE); + GetDlgItem(IDC_TESTALL)->EnableWindow(FALSE); + } + else + { + GetDlgItem(IDC_SEND_MAIL)->EnableWindow(TRUE); + nok++; + } + + if (m_pop3Port == 0 || (m_recvLimit == 0 && !m_recvAll)) + { + GetDlgItem(IDC_RECV_MAIL)->EnableWindow(FALSE); + GetDlgItem(IDC_TESTALL)->EnableWindow(FALSE); + } + else + { + GetDlgItem(IDC_RECV_MAIL)->EnableWindow(TRUE); + nok++; + } + + if (nok < 4) + GetDlgItem(IDC_TESTALL)->EnableWindow(FALSE); + else + GetDlgItem(IDC_TESTALL)->EnableWindow(TRUE); +} + +void Cnet_toolsDlg::OnEnKillfocusIpFilePath() +{ + // TODO: 在此添加控件通知处理程序代码 + check(); +} + +void Cnet_toolsDlg::OnEnKillfocusNpkt() +{ + // TODO: 在此添加控件通知处理程序代码 + check(); +} + +void Cnet_toolsDlg::OnEnKillfocusDelay() +{ + // TODO: 在此添加控件通知处理程序代码 + check(); +} + +void Cnet_toolsDlg::OnEnKillfocusTimeout() +{ + // TODO: 在此添加控件通知处理程序代码 + check(); +} + +void Cnet_toolsDlg::OnEnKillfocusPktSize() +{ + // TODO: 在此添加控件通知处理程序代码 + check(); +} + +void Cnet_toolsDlg::OnEnKillfocusDomainFile() +{ + // TODO: 在此添加控件通知处理程序代码 + check(); +} + +void Cnet_toolsDlg::OnEnKillfocusDnsPort() +{ + // TODO: 在此添加控件通知处理程序代码 + check(); +} + +void Cnet_toolsDlg::OnEnKillfocusLookupTimeout() +{ + // TODO: 在此添加控件通知处理程序代码 + check(); +} + +void Cnet_toolsDlg::OnEnKillfocusFile() +{ + // TODO: 在此添加控件通知处理程序代码 + check(); +} + +void Cnet_toolsDlg::OnEnKillfocusRecvLimit() +{ + // TODO: 在此添加控件通知处理程序代码 + check(); +} + +void Cnet_toolsDlg::OnBnKillfocusRecvAll() +{ + // TODO: 在此添加控件通知处理程序代码 + check(); +} diff --git a/app/net_tools/net_toolsDlg.h b/app/net_tools/net_toolsDlg.h new file mode 100644 index 000000000..7d73a2f95 --- /dev/null +++ b/app/net_tools/net_toolsDlg.h @@ -0,0 +1,151 @@ +// net_toolsDlg.h : 头文件 +// + +#pragma once +#include "ui/MeterBar.h" +#include "ui/TrayIcon.h" +#include "ping/ping.h" +#include "upload/upload.h" +#include "dns/nslookup.h" +#include "mail/smtp_client.h" +#include "mail/pop3_client.h" +#include "test_all.h" +#include "net_store.h" + +// Cnet_toolsDlg 对话框 +class Cnet_toolsDlg : public CDialog + , public ping_callback + , public nslookup_callback + , public upload_callback + , public net_store_callback + , public smtp_callback + , public pop3_callback + , public test_callback +{ +// 构造 +public: + Cnet_toolsDlg(CWnd* pParent = NULL); // 标准构造函数 + ~Cnet_toolsDlg(); +// 对话框数据 + enum { IDD = IDD_NET_TOOLS_DIALOG }; + + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 + + +// 实现 +protected: + HICON m_hIcon; + CMeterBar m_wndMeterBar; + CTrayIcon m_trayIcon; + BOOL m_bShutdown; + + // 生成的消息映射函数 + virtual BOOL OnInitDialog(); + afx_msg void OnSysCommand(UINT nID, LPARAM lParam); + afx_msg void OnPaint(); + afx_msg HCURSOR OnQueryDragIcon(); + DECLARE_MESSAGE_MAP() +public: + afx_msg void OnBnClickedLoadIp(); + afx_msg void OnBnClickedPing(); + afx_msg void OnBnClickedLoadDomain(); + afx_msg void OnBnClickedNslookup(); + +private: + FILE* m_dosFp; + + // ping 相关参数 + UINT m_nPkt; + UINT m_delay; + UINT m_pingTimeout; + UINT m_pktSize; + BOOL m_pingBusy; + CString m_ipFilePath; + CString m_pingDbPath; + + // dns 相关参数 + CString m_dnsIp; + UINT m_dnsPort; + UINT m_lookupTimeout; + BOOL m_dnsBusy; + CString m_domainFilePath; + CString m_dnsDbPath; + + // 上传日志相关参数 + CString m_smtpAddr; + int m_smtpPort; + int m_connecTimeout; + int m_rwTimeout; + CString m_smtpUser; + CString m_smtpPass; + CString m_recipients; + CString m_attachFilePath; + + CString m_pop3Addr; + int m_pop3Port; + UINT m_recvLimit; + BOOL m_recvAll; + +protected: + + virtual void ping_report(size_t total, size_t curr, size_t nerror); + virtual void ping_finish(const char* dbpath); + + virtual void nslookup_report(size_t total, size_t curr); + virtual void nslookup_finish(const char* dbpath); + + virtual void smtp_report(const char* msg, size_t total, + size_t curr, const SMTP_METER& meter); + virtual void smtp_finish(const char* dbpath); + + virtual void pop3_report(const char* msg, size_t total, + size_t curr, const POP3_METER& meter); + virtual void pop3_finish(const char* dbpath); + + virtual void test_report(const char* msg, unsigned nstep); + virtual void test_store(const char* dbpath); + virtual void test_finish(); + + virtual void upload_report(const char* msg, size_t total, + size_t curr, const UPLOAD_METER& meter); + + virtual void load_db_callback(const char* smtp_addr, int smtp_port, + const char* pop3_addr, int pop3_port, + const char* user, const char* pass, + const char* recipients, bool store); +private: + std::vector attaches_; +public: + afx_msg void OnBnClickedOpenDos(); + afx_msg void OnBnClickedOption(); + afx_msg void OnBnClickedTestall(); + afx_msg void OnOpenMain(); + afx_msg void OnQuit(); + afx_msg void OnClose(); + afx_msg void OnNcPaint(); + afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); + afx_msg LRESULT OnTrayNotification(WPARAM uID, LPARAM lEvent); + afx_msg void OnBnClickedLoadFile(); + afx_msg void OnBnClickedSendMail(); + afx_msg void OnBnClickedRecvMail(); + afx_msg void OnEnSetfocusIpFilePath(); + afx_msg void OnEnSetfocusDomainFile(); + afx_msg void OnEnSetfocusFile(); + afx_msg void OnBnClickedRecvAll(); +private: + void check(); +public: + afx_msg void OnDestroy(); + afx_msg void OnEnKillfocusIpFilePath(); + afx_msg void OnEnKillfocusNpkt(); + afx_msg void OnEnKillfocusDelay(); + afx_msg void OnEnKillfocusTimeout(); + afx_msg void OnEnKillfocusPktSize(); + afx_msg void OnEnKillfocusDomainFile(); + afx_msg void OnEnKillfocusDnsPort(); + afx_msg void OnEnKillfocusLookupTimeout(); + afx_msg void OnEnKillfocusFile(); + afx_msg void OnEnKillfocusRecvLimit(); + afx_msg void OnBnKillfocusRecvAll(); +}; diff --git a/app/net_tools/ping/ping.cpp b/app/net_tools/ping/ping.cpp new file mode 100644 index 000000000..6904207e0 --- /dev/null +++ b/app/net_tools/ping/ping.cpp @@ -0,0 +1,246 @@ +#include "StdAfx.h" +#include "rpc/rpc_manager.h" +#include "ping_store.h" +#include "ping.h" + +////////////////////////////////////////////////////////////////////////// + +host_status::host_status(ping& p, const char* ip) +: ping_(p) +, sent_(0) +, received_(0) +, lost_(0) +, loss_(0.00) +, minimum_(0) +, maximum_(0) +, average_(0) +{ + ACL_SAFE_STRNCPY(ip_, ip, sizeof(ip_)); +} + +host_status::~host_status() +{ + std::vector::iterator it = pkt_list_.begin(); + for (; it != pkt_list_.end(); ++it) + acl_myfree(*it); +} + +void host_status::add_status(const ICMP_PKT_STATUS* status) +{ + PING_PKT* pkt = (PING_PKT*) acl_mycalloc(1, sizeof(PING_PKT)); + + pkt->status_ = status->status; + if (pkt->status_ == ICMP_STATUS_OK) + { + pkt->bytes_ = (int) status->reply_len; + pkt->seq_ = status->seq; + pkt->ttl_ = status->ttl; + pkt->rtt_ = status->rtt; + } + //logger("ip: %s, bytes: %d, seq: %d, ttl: %d, rtt: %.2f, status: %d", + // ip_, pkt->bytes_, pkt->seq_, pkt->ttl_, pkt->rtt_, pkt->status_); + pkt_list_.push_back(pkt); +} + +void host_status::set_statistics(const ICMP_STAT* status) +{ + sent_ = (int) status->nsent; + received_ = (int) status->nreceived; + lost_ = sent_ - received_; + loss_ = status->loss; + minimum_ = status->tmin; + maximum_ = status->tmax; + average_ = status->tave; +} + +////////////////////////////////////////////////////////////////////////// + +ping::ping(const char* filepath, ping_callback* callback, + int npkt, int delay, int timeout, int pkt_size) +: filepath_(filepath) +, callback_(callback) +, npkt_(npkt) +, delay_(delay) +, timeout_(timeout) +, pkt_size_(pkt_size) +, host_list_(NULL) +, total_pkt_(0) +, curr_pkt_(0) +, error_pkt_(0) +{ + +} + +ping::~ping() +{ + if (host_list_) + delete host_list_; +} + +////////////////////////////////////////////////////////////////////////// +// 主线程中运行 + +void ping::rpc_onover() +{ + callback_->ping_report(total_pkt_, total_pkt_, error_pkt_); + ping_store* s = new ping_store(host_list_, callback_); + host_list_ = NULL; + rpc_manager::get_instance().fork(s); + delete this; +} + +void ping::rpc_wakeup(void*) +{ + callback_->ping_report(total_pkt_, curr_pkt_, error_pkt_); +} + +////////////////////////////////////////////////////////////////////////// +// 子线程中运行 + +static ICMP_CHAT *__chat = NULL; + +void ping::rpc_run() +{ + if (load_file() == true) + ping_all(); +} + +bool ping::load_file() +{ + acl::ifstream in; + if (in.open_read(filepath_) == false) + { + logger_error("open file(%s) failed: %s", + filepath_.c_str(), acl::last_serror()); + return false; + } + + host_list_ = new std::vector; + acl::string line; + while (in.eof() == false) + { + if (in.gets(line) == false) + break; + host_status* pi = new host_status(*this, line.c_str()); + host_list_->push_back(pi); + } + + if (host_list_->empty()) + { + logger_error("no ip in file %s", filepath_.c_str()); + return false; + } + return true; +} + +static void display_res2(ICMP_CHAT *chat) +{ + if (chat) { + /* 显示 PING 的结果总结 */ + icmp_stat(chat); + logger(">>>max pkts: %d", icmp_chat_seqno(chat)); + } +} + +static void display_res(void) +{ + if (__chat) { + display_res2(__chat); + + /* 释放 ICMP 对象 */ + icmp_chat_free(__chat); + __chat = NULL; + } +} + +void ping::ping_all() +{ + if (host_list_->empty()) + { + logger_error("ip empty"); + return; + } + + ACL_AIO *aio; + /* 创建非阻塞异步通信句柄 */ + aio = acl_aio_create(ACL_EVENT_SELECT); + acl_aio_set_keep_read(aio, 0); + /* 创建 ICMP 对象 */ + __chat = icmp_chat_create(aio, 1); + + // 添加目标 IP 地址 + std::vector::iterator it = host_list_->begin(); + for (; it != host_list_->end(); ++it) + { + //icmp_ping_one(__chat, NULL, (*cit)->get_ip(), + // npkt_, delay_, timeout_); + // 创建一个 PING 的对象,并对该 IP 进行 PING 操作 + ICMP_HOST* host = icmp_host_new(__chat, NULL, + (*it)->get_ip(), npkt_, pkt_size_, delay_, timeout_); + host->enable_log = 1; + icmp_host_set(host, (*it), ping_stat_response, + ping_stat_timeout, ping_stat_unreach, + ping_stat_finish); + icmp_chat(host); + } + + total_pkt_ = npkt_ * host_list_->size(); + rpc_signal(NULL); + + time_t last_signal = time(NULL), t; + + while (1) { + /* 如果 PING 结束,则退出循环 */ + if (icmp_chat_finish(__chat)) { + logger("over now!, hosts' size=%d, count=%d", + icmp_chat_size(__chat), icmp_chat_count(__chat)); + break; + } + + /* 异步事件循环过程 */ + acl_aio_loop(aio); + t = time(NULL); + if (t - last_signal >= 1) + { + rpc_signal(NULL); // 通知主线程 + last_signal = t; + } + } + + /* 显示 PING 结果 */ + display_res(); + + /* 销毁非阻塞句柄 */ + acl_aio_free(aio); +} + +void ping::ping_stat_response(ICMP_PKT_STATUS* status, void* ctx) +{ + host_status* hs = (host_status*) ctx; + hs->get_ping().curr_pkt_++; + hs->add_status(status); +} + +void ping::ping_stat_timeout(ICMP_PKT_STATUS* status, void* ctx) +{ + host_status* hs = (host_status*) ctx; + hs->get_ping().curr_pkt_++; + hs->get_ping().error_pkt_++; + hs->add_status(status); +} + +void ping::ping_stat_unreach(ICMP_PKT_STATUS* status, void* ctx) +{ + host_status* hs = (host_status*) ctx; + hs->get_ping().curr_pkt_++; + hs->get_ping().error_pkt_++; + hs->add_status(status); +} + +void ping::ping_stat_finish(ICMP_HOST* host, void* ctx) +{ + host_status* hs = (host_status*) ctx; + //hs->get_ping().curr_pkt_++; + icmp_stat_host(host, 0); // 需要先计算一下该主机的统计值 + hs->set_statistics(&host->icmp_stat); +} diff --git a/app/net_tools/ping/ping.h b/app/net_tools/ping/ping.h new file mode 100644 index 000000000..99cb8b69c --- /dev/null +++ b/app/net_tools/ping/ping.h @@ -0,0 +1,140 @@ +#pragma once + +////////////////////////////////////////////////////////////////////////// + +// 纯虚类,子类须实现该类中的纯虚接口 +class ping_callback +{ +public: + ping_callback() {} + virtual ~ping_callback() {} + + virtual void ping_report(size_t total, size_t curr, size_t nerr) = 0; + virtual void ping_finish(const char* dbpath) = 0; +}; + +////////////////////////////////////////////////////////////////////////// + +struct PING_PKT +{ + double rtt_; + int ttl_; + int bytes_; + unsigned short seq_; + char status_; +}; + +class ping; + +class host_status +{ +public: + host_status(ping& p, const char* ip); + ~host_status(); + + ping& get_ping() const + { + return ping_; + } + + const std::vector& get_pkt_list() const + { + return pkt_list_; + } + + const char* get_ip() const + { + return ip_; + } + + int get_sent() const + { + return sent_; + } + + int get_received() const + { + return received_; + } + + int get_lost() const + { + return lost_; + } + + double get_loss() const + { + return loss_; + } + + double get_minimum() const + { + return minimum_; + } + + double get_maximum() const + { + return maximum_; + } + + double get_average() const + { + return average_; + } + + void add_status(const ICMP_PKT_STATUS* status); + void set_statistics(const ICMP_STAT* status); +protected: +private: + ping& ping_; + char ip_[32]; + int sent_; + int received_; + int lost_; + double loss_; + double minimum_; + double maximum_; + double average_; + + std::vector pkt_list_; +}; + +class ping : public acl::rpc_request +{ +public: + ping(const char* filepath, ping_callback* callback, + int npkt, int delay, int timeout, int pkt_size); +protected: + ~ping(); + + // 基类虚函数:子线程处理函数 + virtual void rpc_run(); + + // 基类虚函数:主线程处理过程,收到子线程任务完成的消息 + virtual void rpc_onover(); + + // 基类虚函数:主线程处理过程,收到子线程的通知消息 + virtual void rpc_wakeup(void* ctx); + +protected: +private: + acl::string filepath_; + ping_callback* callback_; + int npkt_; + int delay_; + int timeout_; + int pkt_size_; + std::vector* host_list_; + size_t total_pkt_; + size_t curr_pkt_; + size_t error_pkt_; + + bool load_file(); + void ping_all(); + +private: + static void ping_stat_response(ICMP_PKT_STATUS*, void*); + static void ping_stat_timeout(ICMP_PKT_STATUS*, void*); + static void ping_stat_unreach(ICMP_PKT_STATUS*, void*); + static void ping_stat_finish(ICMP_HOST*, void*); +}; diff --git a/app/net_tools/ping/ping_store.cpp b/app/net_tools/ping/ping_store.cpp new file mode 100644 index 000000000..c6a8fa36b --- /dev/null +++ b/app/net_tools/ping/ping_store.cpp @@ -0,0 +1,135 @@ +#include "StdAfx.h" +#include "global/global.h" +#include "ping.h" +#include "ping_store.h" + +ping_store::ping_store(std::vector* host_list, + ping_callback* callback) +: host_list_(host_list) +, callback_(callback) +{ + +} + +ping_store::~ping_store() +{ + delete host_list_; +} + +////////////////////////////////////////////////////////////////////////// +// 主线程运行过程 + +void ping_store::rpc_onover() +{ + logger("store ping results OK!"); + callback_->ping_finish(dbpath_.empty() ? NULL : dbpath_.c_str()); + delete this; +} + +////////////////////////////////////////////////////////////////////////// +// 子线程运行过程 + +static const char* CREATE_HOST_STATUS_TBL = +"create table host_status_tbl\r\n" +"(\r\n" +"ip varchar(32) not null default '',\r\n" +"sent integer not null default 0,\r\n" +"received integer not null default 0,\r\n" +"lost integer not null default 0,\r\n" +"loss float(10,2) not null default 0.00,\r\n" +"minimum float(10,2) not null default 0.00,\r\n" +"maximum float(10,2) not null default 0.00,\r\n" +"average float(10,2) not null default 0.00\r\n" +");\r\n" +"create index host_ip_idx on host_status_tbl(ip);\r\n"; + +const char* CREATE_PING_STATUS_TBL = +"create table ping_status_tbl\r\n" +"(\r\n" +"ip varchar(32) not null default '',\r\n" +"rtt float(10,2) not null default 0.00,\r\n" +"ttl int not null default 0,\r\n" +"bytes int not null default 0,\r\n" +"seq int not null default 0,\r\n" +"status int not null default 0\r\n" +");\r\n" +"create index ping_ip_idx on ping_status_tbl(ip);\r\n"; + +void ping_store::rpc_run() +{ + const char* path = global::get_instance().get_path(); + dbpath_.format("%s/ping_store_%ld.db", path, time(NULL)); + + acl::db_sqlite db(dbpath_.c_str()); + if (db.open() == false) + logger_error("open db: %s failed", dbpath_.c_str()); + else if (create_tbl(db) == false) + logger_error("create table failed for %s", dbpath_.c_str()); + else + { + logger("open db(%s) ok", dbpath_.c_str()); + insert_tbl(db); + } +} + +bool ping_store::create_tbl(acl::db_handle& db) +{ + if (db.tbl_exists("host_status_tbl")) + logger("host_status_tbl exist"); + else if (db.sql_update(CREATE_HOST_STATUS_TBL) == false) + { + logger_error("sql(%s) error", CREATE_HOST_STATUS_TBL); + return (false); + } + else + logger("create table host_status_tbl ok"); + + if (db.tbl_exists("ping_status_tbl")) + logger("ping_status_tbl exist"); + else if (db.sql_update(CREATE_PING_STATUS_TBL) == false) + { + logger_error("sql(%s) error", CREATE_PING_STATUS_TBL); + return (false); + } + else + logger("create table ping_status_tbl ok"); + return (true); +} + +void ping_store::insert_tbl(acl::db_handle& db) +{ + std::vector::const_iterator cit = host_list_->begin(); + for (; cit != host_list_->end(); ++cit) + insert_one(db, *cit); +} + +void ping_store::insert_one(acl::db_handle& db, const host_status* status) +{ + acl::string sql; + + sql.format("insert into host_status_tbl(ip, sent, received, lost," + " loss, minimum, maximum, average) values('%s', %d, %d," + " %d, %0.2f, %0.2f, %0.2f, %0.2f)", + status->get_ip(), status->get_sent(), status->get_received(), + status->get_lost(), status->get_loss(), + status->get_minimum(), status->get_maximum(), + status->get_average()); + if (db.sql_update(sql.c_str()) == false) + logger_error("sql(%s) error", sql.c_str()); + else + logger("insert ip %s to host_status_tbl ok", status->get_ip()); + + const std::vector& pkt_list = status->get_pkt_list(); + std::vector::const_iterator cit = pkt_list.begin(); + for (; cit != pkt_list.end(); ++cit) + { + sql.format("insert into ping_status_tbl(ip, rtt, ttl, bytes," + "seq, status) values('%s', %0.2f, %d, %d, %d, %d)", + status->get_ip(), (*cit)->rtt_, (*cit)->ttl_, + (*cit)->bytes_, (*cit)->seq_, (*cit)->status_); + if (db.sql_update(sql.c_str()) == false) + logger_error("sql(%s) error", sql.c_str()); + } + logger("ok, insert ip %s, pkt count: %d", + status->get_ip(), (int) pkt_list.size()); +} \ No newline at end of file diff --git a/app/net_tools/ping/ping_store.h b/app/net_tools/ping/ping_store.h new file mode 100644 index 000000000..c39ab6418 --- /dev/null +++ b/app/net_tools/ping/ping_store.h @@ -0,0 +1,25 @@ +#pragma once + +class host_status; +class ping_callback; +class ping_store : public acl::rpc_request +{ +public: + ping_store(std::vector* host_list, + ping_callback* callback); + ~ping_store(); +protected: + // 基类虚函数:子线程处理函数 + virtual void rpc_run(); + + // 基类虚函数:主线程处理过程,收到子线程任务完成的消息 + virtual void rpc_onover(); +private: + std::vector* host_list_; + + acl::string dbpath_; + ping_callback* callback_; + bool create_tbl(acl::db_handle& db); + void insert_tbl(acl::db_handle& db); + void insert_one(acl::db_handle& db, const host_status* status); +}; \ No newline at end of file diff --git a/app/net_tools/res/icon_min.ico b/app/net_tools/res/icon_min.ico new file mode 100644 index 000000000..9e9e6b5a2 Binary files /dev/null and b/app/net_tools/res/icon_min.ico differ diff --git a/app/net_tools/res/net_tools.ico b/app/net_tools/res/net_tools.ico new file mode 100644 index 000000000..9e9e6b5a2 Binary files /dev/null and b/app/net_tools/res/net_tools.ico differ diff --git a/app/net_tools/res/net_tools.manifest b/app/net_tools/res/net_tools.manifest new file mode 100644 index 000000000..25dbb84be --- /dev/null +++ b/app/net_tools/res/net_tools.manifest @@ -0,0 +1,22 @@ + + + +鍦ㄦ璇存槑搴旂敤绋嬪簭 + + + + + + diff --git a/app/net_tools/res/net_tools.rc2 b/app/net_tools/res/net_tools.rc2 new file mode 100644 index 000000000..88482f0b3 --- /dev/null +++ b/app/net_tools/res/net_tools.rc2 @@ -0,0 +1,13 @@ +// +// net_tools.RC2 - Microsoft Visual C++ 不会直接编辑的资源 +// + +#ifdef APSTUDIO_INVOKED +#error 此文件不能由 Microsoft Visual C++ 编辑 +#endif //APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// 在此处添加手动编辑的资源... + +///////////////////////////////////////////////////////////////////////////// diff --git a/app/net_tools/resource.h b/app/net_tools/resource.h new file mode 100644 index 000000000..cdd1b214b --- /dev/null +++ b/app/net_tools/resource.h @@ -0,0 +1,72 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by net_tools.rc +// +#define IDR_241 1 +#define IDR_MENU_ICON 4 +#define IDM_ABOUTBOX 0x0010 +#define IDD_ABOUTBOX 100 +#define IDS_ABOUTBOX 101 +#define IDD_NET_TOOLS_DIALOG 102 +#define IDP_SOCKETS_INIT_FAILED 103 +#define IDR_HTML_OPTIONONCLOSE 106 +#define IDR_MAINFRAME 128 +#define IDD_OPTION 131 +#define IDR_RT_MANIFEST1 139 +#define IDI_ICON1 142 +#define IDI_ICON_MIN 142 +#define IDD_DIALOG1 143 +#define IDD_DIALOG_QUIT 143 +#define IDC_PING 1000 +#define IDC_NSLOOKUP 1001 +#define IDC_IP_FILE_PATH 1002 +#define IDC_LOAD_IP 1003 +#define IDC_DOMAIN_FILE 1004 +#define IDC_LOAD_DOMAIN 1005 +#define IDC_NPKT 1006 +#define IDC_DELAY 1007 +#define IDC_TIMEOUT 1008 +#define IDC_BUTTON4 1009 +#define IDC_OPEN_DOS 1009 +#define IDC_NPKT_SIZE 1010 +#define IDC_PKT_SIZE 1010 +#define IDC_DNS_IP 1011 +#define IDC_DNS_PORT 1012 +#define IDC_LOOKUP_TIMEOUT 1013 +#define IDC_UPLOAD 1014 +#define IDC_TESTALL 1015 +#define IDC_OPTION 1016 +#define IDC_SMTP_ADDR 1017 +#define IDC_SMTP_PORT 1018 +#define IDC_POP3_ADDR 1019 +#define IDC_POP3_PORT 1020 +#define IDC_SEND_MAIL 1020 +#define IDC_USER_ACCOUNT 1021 +#define IDC_RECV_MAIL 1021 +#define IDC_USER_PASSWD 1022 +#define IDC_RECIPIENTS 1023 +#define IDC_LOAD_FILE 1023 +#define IDC_FILE 1025 +#define IDC_RECV_LIMIT 1026 +#define IDC_RECV_ALL 1027 +#define IDC_STATIC_SMTP_ADDR 1030 +#define IDC_STATIC_PASS 1031 +#define IDC_CHECK_SAVE 1031 +#define IDC_STATIC_POP3_ADDR 1032 +#define IDC_QUIT_YES 1032 +#define IDC_STATIC_USER 1033 +#define IDC_QUIT_NO 1033 +#define IDC_STATIC_RECIPIENTS 1034 +#define ID_OPEN_MAIN 32773 +#define ID_QUIT 32774 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 144 +#define _APS_NEXT_COMMAND_VALUE 32775 +#define _APS_NEXT_CONTROL_VALUE 1034 +#define _APS_NEXT_SYMED_VALUE 107 +#endif +#endif diff --git a/app/net_tools/rpc/rpc_manager.cpp b/app/net_tools/rpc/rpc_manager.cpp new file mode 100644 index 000000000..45e5f9d01 --- /dev/null +++ b/app/net_tools/rpc/rpc_manager.cpp @@ -0,0 +1,28 @@ +#include "stdafx.h" +#include "rpc_manager.h" + +rpc_manager::rpc_manager(int max_threads /* = 10 */) +{ + // 因为本类实例是单例,会在程序 main 之前被调用, + // 所以需要在此类中打开日志 + // 创建非阻塞框架句柄,并采用 WIN32 消息模式:acl::ENGINE_WINMSG + handle_ = new acl::aio_handle(acl::ENGINE_WINMSG); + // 创建 rpc 服务对象 + service_ = new acl::rpc_service(max_threads); + // 打开消息服务 + if (service_->open(handle_) == false) + logger_fatal("open service error: %s", acl::last_serror()); +} + +rpc_manager::~rpc_manager() +{ + delete service_; + handle_->check(); + delete handle_; + logger("rpc service destroy ok!"); +} + +void rpc_manager::fork(acl::rpc_request* req) +{ + service_->rpc_fork(req); +} diff --git a/app/net_tools/rpc/rpc_manager.h b/app/net_tools/rpc/rpc_manager.h new file mode 100644 index 000000000..77ac016e0 --- /dev/null +++ b/app/net_tools/rpc/rpc_manager.h @@ -0,0 +1,27 @@ +#pragma once + +/** + * 本类对象将阻塞任务交给子线程处理;为了方便使用,将该类声明为单例类 + */ +class rpc_manager : public acl::singleton +{ +public: + /** + * 构造函数 + * @param max_threads {int} 子线程池的最大线程数量 + */ + rpc_manager(int max_threads = 10); + ~rpc_manager(); + + /** + * 发起一个阻塞过程,将该过程交由子线程处理 + * @param req {acl::rpc_request*} 阻塞任务对象 + */ + void fork(acl::rpc_request* req); +protected: +private: + // 异步消息句柄 + acl::aio_handle* handle_; + // 异步 RPC 通信服务句柄 + acl::rpc_service* service_; +}; diff --git a/app/net_tools/sina_domain.txt b/app/net_tools/sina_domain.txt new file mode 100644 index 000000000..58842e611 --- /dev/null +++ b/app/net_tools/sina_domain.txt @@ -0,0 +1 @@ +www.sina.com.cn diff --git a/app/net_tools/stdafx.cpp b/app/net_tools/stdafx.cpp new file mode 100644 index 000000000..15b7e56f9 --- /dev/null +++ b/app/net_tools/stdafx.cpp @@ -0,0 +1,7 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// net_tools.pch 将是预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + + diff --git a/app/net_tools/stdafx.h b/app/net_tools/stdafx.h new file mode 100644 index 000000000..9d70787d5 --- /dev/null +++ b/app/net_tools/stdafx.h @@ -0,0 +1,53 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是经常使用但不常更改的 +// 项目特定的包含文件 + +#pragma once + +#ifndef VC_EXTRALEAN +#define VC_EXTRALEAN // 从 Windows 标头中排除不常使用的资料 +#endif + +// 如果您必须使用下列所指定的平台之前的平台,则修改下面的定义。 +// 有关不同平台的相应值的最新信息,请参考 MSDN。 +#ifndef WINVER // 允许使用 Windows 95 和 Windows NT 4 或更高版本的特定功能。 +#define WINVER 0x0400 //为 Windows98 和 Windows 2000 及更新版本改变为适当的值。 +#endif + +#ifndef _WIN32_WINNT // 允许使用 Windows NT 4 或更高版本的特定功能。 +#define _WIN32_WINNT 0x0400 //为 Windows98 和 Windows 2000 及更新版本改变为适当的值。 +#endif + +#ifndef _WIN32_WINDOWS // 允许使用 Windows 98 或更高版本的特定功能。 +#define _WIN32_WINDOWS 0x0410 //为 Windows Me 及更新版本改变为适当的值。 +#endif + +#ifndef _WIN32_IE // 允许使用 IE 4.0 或更高版本的特定功能。 +#define _WIN32_IE 0x0400 //为 IE 5.0 及更新版本改变为适当的值。 +#endif + +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // 某些 CString 构造函数将是显式的 + +// 关闭 MFC 对某些常见但经常被安全忽略的警告消息的隐藏 +#define _AFX_ALL_WARNINGS + +#include // MFC 核心和标准组件 +#include // MFC 扩展 +#include // MFC 自动化类 + +#include // Internet Explorer 4 公共控件的 MFC 支持 +#ifndef _AFX_NO_AFXCMN_SUPPORT +#include // Windows 公共控件的 MFC 支持 +#endif // _AFX_NO_AFXCMN_SUPPORT + +#include // MFC 套接字扩展 + +////////////////////////////////////////////////////////////////////////// +#include "lib_acl.h" +#include "lib_protocol.h" +#include "acl_cpp/lib_acl.hpp" +#include + +//#include "WndResizer.h" + +#define WM_MY_TRAY_NOTIFICATION WM_USER + 1 diff --git a/app/net_tools/test_all.cpp b/app/net_tools/test_all.cpp new file mode 100644 index 000000000..d8e687b41 --- /dev/null +++ b/app/net_tools/test_all.cpp @@ -0,0 +1,209 @@ +#include "StdAfx.h" +#include "rpc/rpc_manager.h" +#include "ping/ping.h" +#include "dns/nslookup.h" +#include "mail/smtp_client.h" +#include "mail/pop3_client.h" +#include "test_all.h" + +////////////////////////////////////////////////////////////////////////// + +void ping_result::ping_report(size_t total, size_t curr, size_t nerr) +{ + test_.ping_report(total, curr, nerr); +} + +void ping_result::ping_finish(const char* dbpath) +{ + test_.ping_finish(dbpath); +} + +////////////////////////////////////////////////////////////////////////// + +void nslookup_result::nslookup_report(size_t total, size_t curr) +{ + test_.nslookup_report(total, curr); +} + +void nslookup_result::nslookup_finish(const char* dbpath) +{ + test_.nslookup_finish(dbpath); +} + +////////////////////////////////////////////////////////////////////////// + +void smtp_result::smtp_report(const char* msg, size_t total, + size_t curr, const SMTP_METER& meter) +{ + test_.smtp_report(msg, total, curr, meter); +} + +void smtp_result::smtp_finish(const char* dbpath) +{ + test_.smtp_finish(dbpath); +} + +////////////////////////////////////////////////////////////////////////// + +void pop3_result::pop3_report(const char* msg, size_t total, + size_t curr, const POP3_METER& meter) +{ + test_.pop3_report(msg, total, curr, meter); +} + +void pop3_result::pop3_finish(const char* dbpath) +{ + test_.pop3_finish(dbpath); +} + +////////////////////////////////////////////////////////////////////////// + +test_all::test_all(test_callback* callback) +: callback_(callback) +, ping_result_(*this) +, ns_result_(*this) +, smtp_result_(*this) +, pop3_result_(*this) +, ping_ok_(false) +, dns_ok_(false) +, smtp_ok_(false) +, pop3_ok_(false) +, pop3_recv_all_(false) +, pop3_recv_limit_(1) +{ + +} + +test_all::~test_all() +{ + +} + +void test_all::start() +{ + acl::rpc_request* req; + + // 启动 PING 过程 + req = new ping(ip_file_.c_str(), &ping_result_, + ping_npkt_, ping_delay_, ping_timeout_, ping_size_); + rpc_manager::get_instance().fork(req); + + // 启动 DNS 查询过程 + req = new nslookup(domain_file_.c_str(), &ns_result_, + dns_ip_.c_str(), dns_port_, dns_timeout_); + rpc_manager::get_instance().fork(req); + + // 启动邮件发送过程 + smtp_client* smtp = new smtp_client(); + (*smtp).set_callback(&smtp_result_) + .add_file(attach_.c_str()) + .set_smtp(smtp_addr_.c_str(), smtp_port_) + .set_conn_timeout(conn_timeout_) + .set_rw_timeout(rw_timeout_) + .set_account(mail_user_.c_str()) + .set_passwd(mail_pass_.c_str()) + .set_from(mail_user_.c_str()) + .set_subject("邮件发送过程测试!") + .add_to(recipients_.c_str()); + rpc_manager::get_instance().fork(smtp); + + // 启动邮件接收过程 + pop3_client* pop3 = new pop3_client(); + (*pop3).set_callback(&pop3_result_) + .set_pop3(pop3_addr_.c_str(), pop3_port_) + .set_conn_timeout(conn_timeout_) + .set_rw_timeout(rw_timeout_) + .set_account(mail_user_.c_str()) + .set_passwd(mail_pass_.c_str()) + .set_recv_count(pop3_recv_all_ ? -1 : (int) pop3_recv_limit_); + rpc_manager::get_instance().fork(pop3); +} + +void test_all::check_finish() +{ + if (ping_ok_ && dns_ok_ && smtp_ok_ && pop3_ok_) + { + callback_->test_finish(); + delete this; + } +} + +void test_all::ping_report(size_t total, size_t curr, size_t nerr) +{ + unsigned nstep; + if (total > 0) + nstep = (int) ((curr * 100) / total); + else + nstep = 0; + + acl::string msg; + msg.format("ping 过程 %d/%d; failed: %d", curr, total, nerr); + callback_->test_report(msg.c_str(), nstep); +} + +void test_all::ping_finish(const char* dbpath) +{ + callback_->test_store(dbpath); + ping_ok_ = true; + check_finish(); +} + +void test_all::nslookup_report(size_t total, size_t curr) +{ + unsigned nstep; + if (total > 0) + nstep = (unsigned) ((curr * 100) / total); + else + nstep; + + acl::string msg; + msg.format("共 %d 个域名, 完成 %d 个域名", total, curr); + callback_->test_report(msg.c_str(), nstep); +} + +void test_all::nslookup_finish(const char* dbpath) +{ + callback_->test_store(dbpath); + dns_ok_ = true; + check_finish(); +} + +void test_all::smtp_report(const char* msg, size_t total, + size_t curr, const SMTP_METER& meter) +{ + unsigned nstep; + + if (total > 0) + nstep = (int) ((curr * 100) / total); + else + nstep = 0; + callback_->test_report(msg, nstep); +} + +void test_all::smtp_finish(const char* dbpath) +{ + callback_->test_store(dbpath); + smtp_ok_ = true; + check_finish(); +} + +void test_all::pop3_report(const char* msg, size_t total, + size_t curr, const POP3_METER& meter) +{ + unsigned nstep; + + if (total > 0) + nstep = (int) ((curr * 100) / total); + else + nstep = 0; + callback_->test_report(msg, nstep); +} + +void test_all::pop3_finish(const char* dbpath) +{ + callback_->test_store(dbpath); + pop3_ok_ = true; + check_finish(); +} + +////////////////////////////////////////////////////////////////////////// diff --git a/app/net_tools/test_all.h b/app/net_tools/test_all.h new file mode 100644 index 000000000..b5a406495 --- /dev/null +++ b/app/net_tools/test_all.h @@ -0,0 +1,253 @@ +#pragma once + +////////////////////////////////////////////////////////////////////////// + +class test_callback +{ +public: + test_callback() {} + virtual ~test_callback() {} + + virtual void test_report(const char* msg, unsigned nstep) = 0; + virtual void test_store(const char* dbpath) = 0; + virtual void test_finish() = 0; +}; + +////////////////////////////////////////////////////////////////////////// + +class test_all; + +class ping_result : public ping_callback +{ +public: + ping_result(test_all& test) : test_(test) {} + ~ping_result() {} +protected: + virtual void ping_report(size_t total, size_t curr, size_t nerr); + virtual void ping_finish(const char* dbpath); +private: + test_all& test_; +}; + +class nslookup_result : public nslookup_callback +{ +public: + nslookup_result(test_all& test) : test_(test) {} + ~nslookup_result() {} +protected: + virtual void nslookup_report(size_t total, size_t curr); + virtual void nslookup_finish(const char* dbpath); +private: + test_all& test_; +}; + +class smtp_result : public smtp_callback +{ +public: + smtp_result(test_all& test) : test_(test) {} + ~smtp_result() {} +protected: + virtual void smtp_finish(const char* dbpath); + virtual void smtp_report(const char* msg, size_t total, + size_t curr, const SMTP_METER& meter); +private: + test_all& test_; +}; + +class pop3_result : public pop3_callback +{ +public: + pop3_result(test_all& test) : test_(test) {} + ~pop3_result() {} +protected: + virtual void pop3_finish(const char* dbpath); + virtual void pop3_report(const char* msg, size_t total, + size_t curr, const POP3_METER& meter); +private: + test_all& test_; +}; + +////////////////////////////////////////////////////////////////////////// + +class test_all +{ +public: + test_all(test_callback*); + void start(); +protected: + ~test_all(); +public: + void ping_report(size_t total, size_t curr, size_t nerr); + void ping_finish(const char* dbpath); + + void nslookup_report(size_t total, size_t curr); + void nslookup_finish(const char* dbpath); + + void smtp_finish(const char* dbpath); + void smtp_report(const char* msg, size_t total, + size_t curr, const SMTP_METER& meter); + + void pop3_finish(const char* dbpath); + void pop3_report(const char* msg, size_t total, + size_t curr, const POP3_METER& meter); +private: + //friend class ping_result; + //friend class nslookup_result; + //friend class smtp_result; + + test_callback* callback_; + void check_finish(); +private: + acl::string ip_file_; + int ping_npkt_; + int ping_delay_; + int ping_timeout_; + int ping_size_; + bool ping_ok_; + ping_result ping_result_; +private: + acl::string domain_file_; + acl::string dns_ip_; + int dns_port_; + int dns_timeout_; + bool dns_ok_; + nslookup_result ns_result_; +private: + acl::string mail_user_; + acl::string mail_pass_; + int conn_timeout_; + int rw_timeout_; +private: + acl::string smtp_addr_; + int smtp_port_; + acl::string attach_; + acl::string recipients_; + bool smtp_ok_; + smtp_result smtp_result_; +private: + acl::string pop3_addr_; + int pop3_port_; + bool pop3_recv_all_; + size_t pop3_recv_limit_; + bool pop3_ok_; + pop3_result pop3_result_; +public: + test_all& set_ip_file(const char* filename) + { + ip_file_ = filename; + return *this; + } + test_all& set_ping_npkt(int ping_npkt) + { + ping_npkt_ = ping_npkt; + return *this; + } + test_all& set_ping_delay(int ping_delay) + { + ping_delay_ = ping_delay; + return *this; + } + test_all& set_ping_timeout(int ping_timeout) + { + ping_timeout_ = ping_timeout; + return *this; + } + test_all& set_ping_size(int ping_size) + { + ping_size_ = ping_size; + return *this; + } +public: + test_all& set_domain_file(const char* filename) + { + domain_file_ = filename; + return *this; + } + test_all& set_dns_ip(const char* ip) + { + dns_ip_ = ip; + return *this; + } + test_all& set_dns_port(int port) + { + dns_port_ = port; + return *this; + } + test_all& set_dns_timeout(int timeout) + { + dns_timeout_ = timeout; + return *this; + } +public: + test_all& set_attach(const char* attach) + { + attach_ = attach; + return *this; + } + test_all& set_smtp_addr(const char* smtp_addr) + { + smtp_addr_ = smtp_addr; + return *this; + } + test_all& set_smtp_port(int smtp_port) + { + smtp_port_ = smtp_port; + return *this; + } + test_all& set_recipients(const char* recipients) + { + recipients_ = recipients; + return *this; + } +public: + test_all& set_pop3_addr(const char* pop3_addr) + { + pop3_addr_ = pop3_addr; + return *this; + } + test_all& set_pop3_port(int pop3_port) + { + pop3_port_ = pop3_port; + return *this; + } + test_all& set_pop3_recv(int recv_limit) + { + if (recv_limit < 0) + { + pop3_recv_all_ = true; + pop3_recv_limit_ = -1; + } + else if (recv_limit == 0) + { + pop3_recv_all_ = false; + pop3_recv_limit_ = 0; + } + else + { + pop3_recv_all_ = false; + pop3_recv_limit_ = recv_limit; + } + return *this; + } +public: + test_all& set_conn_timeout(int conn_timeout) + { + conn_timeout_ = conn_timeout; + return *this; + } + test_all& set_rw_timeout(int rw_timeout) + { + rw_timeout_ = rw_timeout; + return *this; + } + test_all& set_mail_user(const char* mail_user) + { + mail_user_ = mail_user; + return *this; + } + test_all& set_mail_pass(const char* mail_pass) + { + mail_pass_ = mail_pass; + return *this; + } +}; diff --git a/app/net_tools/ui/MeterBar.cpp b/app/net_tools/ui/MeterBar.cpp new file mode 100644 index 000000000..067c9d241 --- /dev/null +++ b/app/net_tools/ui/MeterBar.cpp @@ -0,0 +1,80 @@ +// MeterBar.cpp : 实现文件 +// + +#include "stdafx.h" +#include "MeterBar.h" + +// CMeterBar + +IMPLEMENT_DYNAMIC(CMeterBar, CStatusBarCtrl) +CMeterBar::CMeterBar() +: m_pWidths(NULL) +{ +} + +CMeterBar::~CMeterBar() +{ + delete m_pWidths; +} + + +BEGIN_MESSAGE_MAP(CMeterBar, CStatusBarCtrl) + ON_WM_CREATE() + ON_WM_SIZE() +END_MESSAGE_MAP() + +BOOL CMeterBar::SetParts(int nParts, int* pWidths) +{ + m_nParts = nParts; + m_pWidths = new int[nParts]; + int i; + for (i = 0; i < nParts; i++) + { + m_pWidths[i] = pWidths[i]; + } + return (TRUE); +} + +// CMeterBar 消息处理程序 + + +int CMeterBar::OnCreate(LPCREATESTRUCT lpCreateStruct) +{ + if (CStatusBarCtrl::OnCreate(lpCreateStruct) == -1) + return -1; + + ASSERT(m_pWidths); + CStatusBarCtrl::SetParts(m_nParts, m_pWidths); + //int tmp; + //int n = GetParts(0, &tmp); + + // TODO: 在此添加您专用的创建代码 + //m_meter.Create(WS_CHILD | WS_VISIBLE, CRect(0, 0, 0, 0), this, 101); + //m_meter.Create("Press start timer to see me go", + // WS_VISIBLE | WS_CHILD | WS_EX_CLIENTEDGE, CRect(0, 0, 0, 0), this, (HMENU) 101); + static CString className = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW); + DWORD dwExStyle = WS_EX_STATICEDGE; //WS_EX_CLIENTEDGE | WS_EX_STATICEDGE; + m_meter.CreateEx(dwExStyle, className, + "Press start timer to see me go", WS_VISIBLE | WS_CHILD, + CRect(0, 0, 0, 0), this, 101); + + m_meter.SetRange(0, 100); + m_meter.SetPos(0); + //m_meter.SetStep(1); + + return 0; +} + +void CMeterBar::OnSize(UINT nType, int cx, int cy) +{ + CStatusBarCtrl::OnSize(nType, cx, cy); + + // TODO: 在此处添加消息处理程序代码 + int nTemp; + int nCount = GetParts(0, &nTemp); + if (nCount > 0) { + CRect r; + GetRect(nCount - 1, r); + m_meter.MoveWindow(r); + } +} diff --git a/app/net_tools/ui/MeterBar.h b/app/net_tools/ui/MeterBar.h new file mode 100644 index 000000000..9dac6109d --- /dev/null +++ b/app/net_tools/ui/MeterBar.h @@ -0,0 +1,33 @@ +#pragma once +#include "afxcmn.h" +#include "MeterCtrl.h" + +// CMeterBar + +class CMeterBar : public CStatusBarCtrl +{ + DECLARE_DYNAMIC(CMeterBar) + +public: + CMeterBar(); + virtual ~CMeterBar(); + + BOOL SetParts(int nParts, int* pWidths); + + CMeterCtrl& GetProgressCtrl() { + return m_meter; + } + +protected: + DECLARE_MESSAGE_MAP() + //CProgressCtrl m_meter; + CMeterCtrl m_meter; +public: + afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); + afx_msg void OnSize(UINT nType, int cx, int cy); +private: + int *m_pWidths; + int m_nParts; +}; + + diff --git a/app/net_tools/ui/MeterCtrl.cpp b/app/net_tools/ui/MeterCtrl.cpp new file mode 100644 index 000000000..ac4f499e4 --- /dev/null +++ b/app/net_tools/ui/MeterCtrl.cpp @@ -0,0 +1,170 @@ +// MeterCtrl.cpp : 实现文件 +// + +#include "stdafx.h" +#pragma warning(disable:4312) +#include ".\Meterctrl.h" + + +// CMeterCtrl + +IMPLEMENT_DYNAMIC(CMeterCtrl, CWnd) +CMeterCtrl::CMeterCtrl() +: m_nLower(0) +, m_nUpper(0) +, m_nPos(0) +{ +} + +CMeterCtrl::~CMeterCtrl() +{ +} + + +BEGIN_MESSAGE_MAP(CMeterCtrl, CWnd) + ON_WM_PAINT() + ON_WM_ERASEBKGND() +END_MESSAGE_MAP() + + + +// CMeterCtrl 消息处理程序 + + +void CMeterCtrl::OnPaint() +{ + CPaintDC dc(this); // device context for painting + // TODO: 在此处添加消息处理程序代码 + // 不为绘图消息调用 CWnd::OnPaint() + CRect rClient; + GetClientRect(rClient); + CRect rLeft = rClient; + CRect rRight = rClient; + UINT nRange = m_nUpper - m_nLower; + + rLeft.right = (LONG)(((m_nPos - m_nLower) * rClient.Width())/ nRange); + rRight.left = rLeft.right; + + CRgn rgnLeft, rgnRight; + rgnLeft.CreateRectRgnIndirect(rLeft); + rgnRight.CreateRectRgnIndirect(rRight); + + CBrush *pBrush = CBrush::FromHandle(GetSysColorBrush(COLOR_HIGHLIGHT)); + dc.FillRect(rLeft, pBrush); + CString msg; + +// msg.Format(">>left=%d, right=%d, top=%d, bottom=%d, nrange=%d, width=%d, npos=%d, nlower=%d", +// rLeft.left, rLeft.right, rLeft.top, rLeft.bottom, +// nRange, rClient.Width(), m_nPos, m_nLower); +// AfxMessageBox(msg); + + //CString strCaption; + //GetWindowText(strCaption); + + //strCaption.Format("%d%% (%d)", ((m_nPos - m_nLower) * 100)/ nRange, m_nPos); + + dc.SelectClipRgn(&rgnLeft); + dc.SetBkMode(TRANSPARENT); + dc.SetTextColor(GetSysColor(COLOR_HIGHLIGHTTEXT)); + dc.DrawText(m_sCaption, rClient, DT_BOTTOM | DT_CENTER); + dc.SelectClipRgn(&rgnRight); + dc.SetTextColor(GetSysColor(COLOR_HIGHLIGHT)); + dc.DrawText(m_sCaption, rClient, DT_BOTTOM | DT_CENTER); +} + +BOOL CMeterCtrl::OnEraseBkgnd(CDC* pDC) +{ + // TODO: 在此添加消息处理程序代码和/或调用默认值 + CRect r; + GetClientRect(r); + CBrush *pBrush = CBrush::FromHandle(GetSysColorBrush(COLOR_BTNFACE)); + pDC->FillRect(r, pBrush); + + return TRUE; +// return CWnd::OnEraseBkgnd(pDC); +} + +BOOL CMeterCtrl::Create(LPCTSTR lpszWindowName, DWORD dwStyle, + const RECT& rect, CWnd* pParentWnd, HMENU nID) +{ + // TODO: 在此添加专用代码和/或调用基类 + static CString className = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW); + + return CWnd::CreateEx(WS_EX_STATICEDGE, //WS_EX_CLIENTEDGE | WS_EX_STATICEDGE, + className, lpszWindowName, dwStyle, + rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, + pParentWnd->GetSafeHwnd(), (HMENU) nID); + +// return CWnd::Create(lpszClassName, lpszWindowName, dwStyle, +// rect, pParentWnd, nID, pContext); +} + +BOOL CMeterCtrl::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName, + LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, + CWnd* pParentWnd, UINT nID, LPVOID lpParam) +{ + // TODO: 在此添加专用代码和/或调用基类 + + static CString className = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW); + + return CWnd::CreateEx(dwExStyle, //WS_EX_CLIENTEDGE | WS_EX_STATICEDGE, + lpszClassName, lpszWindowName, dwStyle, + rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, + pParentWnd->GetSafeHwnd(), (HMENU) nID); + + //return CWnd::CreateEx(dwExStyle, lpszClassName, lpszWindowName, + // dwStyle, rect, pParentWnd, nID, lpParam); +} + +UINT CMeterCtrl::SetPos(UINT nPos) +{ + ASSERT(nPos >= m_nLower && nPos <= m_nUpper); + + UINT nRange = m_nUpper - m_nLower; + UINT nOld = m_nPos; + m_nPos = nPos; + + m_sCaption.Format("%d%% (%d)", ((m_nPos - m_nLower) * 100)/ nRange, m_nPos); + InvalidateMeater(); + + return nOld; +} + +void CMeterCtrl::SetRange(UINT nLower, UINT nUpper) +{ + ASSERT(nLower >= 0 && nLower < 0xffff); + ASSERT(nUpper > nLower && nUpper < 0xffff); + + m_nLower = nLower; + m_nUpper = nUpper; + + InvalidateMeater(); +} + +void CMeterCtrl::StepIt(void) +{ + m_nPos++; + if (m_nPos > m_nUpper) + m_nPos = m_nLower; + + InvalidateMeater(); +} + +void CMeterCtrl::SetText(CString& msg) +{ + m_sCaption = msg; + InvalidateMeater(); +} + +void CMeterCtrl::SetText(const char* pMsg) +{ + m_sCaption = pMsg; + InvalidateMeater(); +} + +void CMeterCtrl::InvalidateMeater(void) +{ + CRect r; + GetClientRect(r); + InvalidateRect(r); +} diff --git a/app/net_tools/ui/MeterCtrl.h b/app/net_tools/ui/MeterCtrl.h new file mode 100644 index 000000000..49cc9dd9a --- /dev/null +++ b/app/net_tools/ui/MeterCtrl.h @@ -0,0 +1,38 @@ +#pragma once + + +// CMeterCtrl + +class CMeterCtrl : public CWnd +{ + DECLARE_DYNAMIC(CMeterCtrl) + +public: + CMeterCtrl(); + virtual ~CMeterCtrl(); + +protected: + DECLARE_MESSAGE_MAP() +public: + afx_msg void OnPaint(); + afx_msg BOOL OnEraseBkgnd(CDC* pDC); + //virtual BOOL Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext = NULL); + virtual BOOL Create(LPCTSTR lpszWindowName, DWORD dwStyle, + const RECT& rect, CWnd* pParentWnd, HMENU nID); + virtual BOOL CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName, + LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, + CWnd* pParentWnd, UINT nID, LPVOID lpParam = NULL); + UINT SetPos(UINT nPos); + void SetRange(UINT nLower, UINT nUpper); + void StepIt(void); + void SetText(CString& msg); + void SetText(const char* pMsg); +protected: + void InvalidateMeater(void); + UINT m_nLower; + UINT m_nUpper; + UINT m_nPos; + CString m_sCaption; +}; + + diff --git a/app/net_tools/ui/TrayIcon.cpp b/app/net_tools/ui/TrayIcon.cpp new file mode 100644 index 000000000..2f2cde96d --- /dev/null +++ b/app/net_tools/ui/TrayIcon.cpp @@ -0,0 +1,139 @@ +//////////////////////////////////////////////////////////////// +// If this code works, it was written by Paul DiLascia. +// If not, I don't know who wrote it. +// +#include "stdafx.h" +#include "TrayIcon.h" +#include // for AfxLoadString + +IMPLEMENT_DYNAMIC(CTrayIcon, CCmdTarget) + +CTrayIcon::CTrayIcon(UINT uID) +{ + // Initialize NOTIFYICONDATA + memset(&m_nid, 0 , sizeof(m_nid)); + m_nid.cbSize = sizeof(m_nid); + m_nid.uID = uID; // never changes after construction + + // Use resource string as tip if there is one + AfxLoadString(uID, m_nid.szTip, sizeof(m_nid.szTip)); +} + +CTrayIcon::~CTrayIcon() +{ + SetIcon(0); // remove icon from system tray +} + +////////////////// +// Set notification window. It must created already. +void CTrayIcon::SetNotificationWnd(CWnd* pNotifyWnd, UINT uCbMsg) +{ + // If the following assert fails, you're probably + // calling me before you created your window. Oops. + ASSERT(pNotifyWnd==NULL || ::IsWindow(pNotifyWnd->GetSafeHwnd())); + m_nid.hWnd = pNotifyWnd->GetSafeHwnd(); + + ASSERT(uCbMsg==0 || uCbMsg>=WM_USER); + m_nid.uCallbackMessage = uCbMsg; +} + +////////////////// +// This is the main variant for setting the icon. +// Sets both the icon and tooltip from resource ID +// To remove the icon, call SetIcon(0) +// +BOOL CTrayIcon::SetIcon(UINT uID) +{ + HICON hicon=NULL; + if (uID) { + AfxLoadString(uID, m_nid.szTip, sizeof(m_nid.szTip)); + hicon = AfxGetApp()->LoadIcon(uID); + } + return SetIcon(hicon, NULL); +} + +////////////////// +// Common SetIcon for all overloads. +// +BOOL CTrayIcon::SetIcon(HICON hicon, LPCSTR lpTip) +{ + UINT msg; + m_nid.uFlags = 0; + + // Set the icon + if (hicon) { + // Add or replace icon in system tray + msg = m_nid.hIcon ? NIM_MODIFY : NIM_ADD; + m_nid.hIcon = hicon; + m_nid.uFlags |= NIF_ICON; + } else { // remove icon from tray + if (m_nid.hIcon==NULL) + return TRUE; // already deleted + msg = NIM_DELETE; + } + + // Use the tip, if any + if (lpTip) + strncpy(m_nid.szTip, lpTip, sizeof(m_nid.szTip)); + if (m_nid.szTip[0]) + m_nid.uFlags |= NIF_TIP; + + // Use callback if any + if (m_nid.uCallbackMessage && m_nid.hWnd) + m_nid.uFlags |= NIF_MESSAGE; + + // Do it + BOOL bRet = Shell_NotifyIcon(msg, &m_nid); + if (msg==NIM_DELETE || !bRet) + m_nid.hIcon = NULL; // failed + return bRet; +} + +///////////////// +// Default event handler handles right-menu and doubleclick. +// Call this function from your own notification handler. +// +LRESULT CTrayIcon::OnTrayNotification(WPARAM wID, LPARAM lEvent) +{ + static LPCSTR MouseMessages[] = { "WM_MOUSEMOVE", + "WM_LBUTTONDOWN", "WM_LBUTTONUP", "WM_LBUTTONDBLCLK", + "WM_RBUTTONDOWN", "WM_RBUTTONUP", "WM_RBUTTONDBLCLK", + "WM_MBUTTONDOWN", "WM_MBUTTONUP", "WM_MBUTTONDBLCLK" }; + + if (wID!=m_nid.uID || (lEvent!=WM_RBUTTONUP + && lEvent!=WM_LBUTTONDBLCLK && lEvent != WM_LBUTTONDOWN)) + { + return 0; + } + + // If there's a resource menu with the same ID as the icon, use it as + // the right-button popup menu. CTrayIcon will interprets the first + // item in the menu as the default command for WM_LBUTTONDBLCLK + // + CMenu menu; + if (!menu.LoadMenu(m_nid.uID)) + return 0; + CMenu* pSubMenu = menu.GetSubMenu(0); + if (!pSubMenu) + return 0; + + if (lEvent==WM_RBUTTONUP) { + + // Make first menu item the default (bold font) + ::SetMenuDefaultItem(pSubMenu->m_hMenu, 0, TRUE); + + // Display the menu at the current mouse location. There's a "bug" + // (Microsoft calls it a feature) in Windows 95 that requires calling + // SetForegroundWindow. To find out more, search for Q135788 in MSDN. + // + CPoint mouse; + GetCursorPos(&mouse); + ::SetForegroundWindow(m_nid.hWnd); + ::TrackPopupMenu(pSubMenu->m_hMenu, 0, mouse.x, mouse.y, 0, + m_nid.hWnd, NULL); + + } else // double click: execute first menu item + ::SendMessage(m_nid.hWnd, WM_COMMAND, pSubMenu->GetMenuItemID(0), 0); + + return 1; // handled +} diff --git a/app/net_tools/ui/TrayIcon.h b/app/net_tools/ui/TrayIcon.h new file mode 100644 index 000000000..3b51013f8 --- /dev/null +++ b/app/net_tools/ui/TrayIcon.h @@ -0,0 +1,38 @@ +//////////////////////////////////////////////////////////////// +// CTrayIcon Copyright 1996 Microsoft Systems Journal. +// +// If this code works, it was written by Paul DiLascia. +// If not, I don't know who wrote it. + +#ifndef _TRAYICON_H +#define _TRAYICON_H + +//////////////// +// CTrayIcon manages an icon in the Windows 95 system tray. +// +class /*AFX_EXT_CLASS*/ CTrayIcon : public CCmdTarget { +protected: + DECLARE_DYNAMIC(CTrayIcon) + NOTIFYICONDATA m_nid; // struct for Shell_NotifyIcon args + +public: + CTrayIcon(UINT uID); + ~CTrayIcon(); + + // Call this to receive tray notifications + void SetNotificationWnd(CWnd* pNotifyWnd, UINT uCbMsg); + + // SetIcon functions. To remove icon, call SetIcon(0) + // + BOOL SetIcon(UINT uID); // main variant you want to use + BOOL SetIcon(HICON hicon, LPCSTR lpTip); + BOOL SetIcon(LPCTSTR lpResName, LPCSTR lpTip) + { return SetIcon(lpResName ? + AfxGetApp()->LoadIcon(lpResName) : NULL, lpTip); } + BOOL SetStandardIcon(LPCTSTR lpszIconName, LPCSTR lpTip) + { return SetIcon(::LoadIcon(NULL, lpszIconName), lpTip); } + + virtual LRESULT OnTrayNotification(WPARAM uID, LPARAM lEvent); +}; + +#endif diff --git a/app/net_tools/ui/WndResizer.cpp b/app/net_tools/ui/WndResizer.cpp new file mode 100644 index 000000000..4788873a2 --- /dev/null +++ b/app/net_tools/ui/WndResizer.cpp @@ -0,0 +1,2695 @@ +/* +DISCLAIMER + +Auther: Mizan Rahman +Original publication location: http://www.codeproject.com/KB/dialog/WndResizer.aspx + +This work is provided under the terms and condition described in The Code Project Open License (CPOL) +(http://www.codeproject.com/info/cpol10.aspx) + +This disclaimer should not be removed and should exist in any reproduction of this work. +*/ + +#include "StdAfx.h" +#include +#include +#include +#include + +#include "WndResizer.h" + + + +static CMap WndResizerData; + + +///////////////////////////// CWndResizer +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +CWndResizer::CWndResizer(void) +{ + m_pHookedWnd = NULL; + m_pfnWndProc = NULL; + root.Name = _T("_root"); + m_pCaptured = NULL; + m_hOldCursor = NULL; + m_splitterOffset = 0; + +} + +CWndResizer::~CWndResizer(void) +{ + +} +void CWndResizer::GetTrueClientRect(CWnd * pWnd, CRect * prc) +{ + int nMin = 0; + int nMax = 0; + int nCur = 0; + + pWnd->GetClientRect(prc); + + if ( (pWnd->GetStyle() & WS_HSCROLL) > 0) + { + pWnd->GetScrollRange(SB_HORZ, &nMin, &nMax); + nCur = pWnd->GetScrollPos(SB_HORZ); + prc->right = prc->left + nMax; + prc->OffsetRect( -nCur , 0); + } + + if ( (pWnd->GetStyle() & WS_VSCROLL) > 0) + { + pWnd->GetScrollRange(SB_VERT, &nMin, &nMax); + nCur = pWnd->GetScrollPos(SB_VERT); + prc->bottom = prc->top + nMax; + prc->OffsetRect(0, -nCur); + } +} +void CWndResizer::EnsureRootMinMax() +{ + if (root.Width() < root.MinSize.cx) + { + root.right = root.left + root.MinSize.cx; + } + if (root.Width() > root.MaxSize.cx) + { + root.right = root.left + root.MaxSize.cx; + } + + if (root.Height() < root.MinSize.cy) + { + root.bottom = root.top + root.MinSize.cy; + } + if (root.Height() > root.MaxSize.cy) + { + root.bottom = root.top + root.MaxSize.cy; + } +} + +void CWndResizer::OnSize(UINT nType, int cx, int cy) +{ + GetTrueClientRect(m_pHookedWnd, &root); + EnsureRootMinMax(); + root.OnResized(); + ResizeUI(&root); +} +void CWndResizer::OnScroll() +{ + GetTrueClientRect(m_pHookedWnd, &root); + EnsureRootMinMax(); + root.OnResized(); + ResizeUI(&root); +} +BOOL CWndResizer::Hook(CWnd * pParent) +{ + ASSERT( m_pHookedWnd == NULL ); + + m_pHookedWnd = pParent; + + GetTrueClientRect(m_pHookedWnd, &root); + + root.m_pHookWnd = m_pHookedWnd; + + // create the resize gripper panel + CRect rcResziGrip(&root); + int cx = ::GetSystemMetrics(SM_CXHSCROLL); + int cy = ::GetSystemMetrics(SM_CYVSCROLL); + rcResziGrip.DeflateRect(root.Width() - cx, root.Height() - cy, 0, 0); + CGripperPanel * pResizeGripper = new CGripperPanel(&rcResziGrip); + pResizeGripper->SetAnchor( ANCHOR_RIGHT | ANCHOR_BOTTOM ); + pResizeGripper->Name = _T("_resizeGrip"); + root.AddChild( pResizeGripper ); + + WndResizerData.SetAt(m_pHookedWnd->m_hWnd, this); + + m_pfnWndProc = (WNDPROC)::SetWindowLongPtr(m_pHookedWnd->m_hWnd, GWLP_WNDPROC, (LONG_PTR)WindowProc); + return TRUE; +} +BOOL CWndResizer::Hook(CWnd * pParent, CSize & size) +{ + ASSERT( m_pHookedWnd == NULL ); + + m_pHookedWnd = pParent; + + GetTrueClientRect(m_pHookedWnd, &root); + root.right = root.left + size.cx; + root.bottom = root.top + size.cy; + root.m_pHookWnd = m_pHookedWnd; + + // create the resize gripper panel + CRect rcResziGrip(&root); + int cx = ::GetSystemMetrics(SM_CXHSCROLL); + int cy = ::GetSystemMetrics(SM_CYVSCROLL); + rcResziGrip.DeflateRect(root.Width() - cx, root.Height() - cy, 0, 0); + CGripperPanel * pResizeGripper = new CGripperPanel(&rcResziGrip); + pResizeGripper->SetAnchor( ANCHOR_RIGHT | ANCHOR_BOTTOM ); + pResizeGripper->Name = _T("_resizeGrip"); + root.AddChild( pResizeGripper ); + + WndResizerData.SetAt(m_pHookedWnd->m_hWnd, this); + + m_pfnWndProc = (WNDPROC)::SetWindowLongPtr(m_pHookedWnd->m_hWnd, GWLP_WNDPROC, (LONG_PTR)WindowProc); + return TRUE; +} + +void CWndResizer::ResizeUI(CPanel * pRoot) +{ + CPanelList panels; + GetUIPanels(pRoot, &panels, FALSE); + + POSITION pos = NULL; + + if (panels.GetCount() > 0) + { + HDWP hDWP = ::BeginDeferWindowPos((int) panels.GetCount()); + ASSERT( hDWP != NULL); + pos = panels.GetHeadPosition(); + while (pos != NULL) + { + CUIPanel * pPanel = (CUIPanel *) panels.GetNext(pos); + + ::DeferWindowPos(hDWP, m_pHookedWnd->GetDlgItem(pPanel->m_uID)->m_hWnd, NULL, + pPanel->left , pPanel->top , pPanel->Width(), pPanel->Height(), + SWP_NOACTIVATE | SWP_NOZORDER ); + + } + BOOL bOk = ::EndDeferWindowPos(hDWP); + ASSERT( bOk ); + m_pHookedWnd->InvalidateRect(pRoot, FALSE); + } + + panels.RemoveAll(); + GetUIPanels(pRoot, &panels, TRUE); + pos = panels.GetHeadPosition(); + while (pos != NULL) + { + CUIPanel * pPanel = (CUIPanel *) panels.GetNext(pos); + m_pHookedWnd->GetDlgItem(pPanel->m_uID)->MoveWindow(pPanel); + } +} + + +void CWndResizer::OnLButtonDown(UINT nFlags, CPoint point) +{ + UpdateSplitterOffset(point); +} +void CWndResizer::OnMouseMove(UINT nFlags, CPoint point) +{ + if (m_pCaptured != NULL ) + { + if ((nFlags & MK_LBUTTON) <= 0) + { + CPoint ptScreen = point; + m_pHookedWnd->ClientToScreen(&ptScreen); + HWND hWndFromPoint = ::WindowFromPoint(ptScreen); + if (m_pCaptured->PtInRect( point ) == FALSE || hWndFromPoint != m_pHookedWnd->m_hWnd) + { + ::ReleaseCapture(); + m_pCaptured = NULL; + HCURSOR hCur = ::SetCursor(m_hOldCursor); + ::DestroyCursor( hCur ); + m_hOldCursor = NULL; + } + } + } + + if (m_pCaptured == NULL ) + { + m_pCaptured = FindSplitterFromPoint(&root, point); + if (m_pCaptured != NULL) + { + m_pHookedWnd->SetCapture(); + LPCTSTR cursor = NULL; + CSplitContainer * pSplitContainer = (CSplitContainer *)m_pCaptured->Parent; + if (pSplitContainer->m_Orientation == SPLIT_CONTAINER_H) + { + cursor = IDC_SIZEWE; + } + else + { + cursor = IDC_SIZENS; + } + HCURSOR hCur = AfxGetApp()->LoadStandardCursor(cursor); + HCURSOR m_hOldCursor = ::SetCursor(hCur); + } + } + + if (m_pCaptured != NULL && (nFlags & MK_LBUTTON) > 0) + { + CSplitContainer * pSplitterContainer = (CSplitContainer *) m_pCaptured->Parent; + + if (pSplitterContainer->m_Orientation == SPLIT_CONTAINER_H) + { + pSplitterContainer->SetSplitterPosition( point.x - m_splitterOffset); + } + else + { + pSplitterContainer->SetSplitterPosition( point.y - m_splitterOffset); + } + UpdateSplitterOffset(point); + + ResizeUI(pSplitterContainer); + + } +} +void CWndResizer::OnLButtonUp(UINT nFlags, CPoint point) +{ + OnMouseMove(nFlags, point); +} +void CWndResizer::UpdateSplitterOffset(CPoint ptCurr) +{ + if (m_pCaptured == NULL ) + { + return; + } + if (((CSplitContainer *)m_pCaptured->Parent)->m_Orientation == SPLIT_CONTAINER_H) + { + if ( ptCurr.x < m_pCaptured->left) + { + m_splitterOffset = 0; + } + else if ( ptCurr.x > m_pCaptured->right) + { + m_splitterOffset = m_pCaptured->Width(); + } + else + { + m_splitterOffset = ptCurr.x - m_pCaptured->left; + } + } + else + { + if ( ptCurr.y < m_pCaptured->top) + { + m_splitterOffset = 0; + } + else if ( ptCurr.y > m_pCaptured->bottom) + { + m_splitterOffset = m_pCaptured->Height(); + } + else + { + m_splitterOffset = ptCurr.y - m_pCaptured->top; + } + } +} +void CWndResizer::OnSizing(UINT fwSide, LPRECT pRect) +{ + + CRect * prc = (CRect *) pRect; + + CRect rcMin(0, 0, root.MinSize.cx, root.MinSize.cy); + CRect rcMax(0, 0, root.MaxSize.cx, root.MaxSize.cy); + + LONG_PTR style = GetWindowLongPtr(m_pHookedWnd->m_hWnd , GWL_STYLE); + LONG_PTR styleEx = GetWindowLongPtr(m_pHookedWnd->m_hWnd, GWL_EXSTYLE); + + ::AdjustWindowRectEx(&rcMin, (DWORD) style, (m_pHookedWnd->GetMenu() != NULL), (DWORD) styleEx); + ::AdjustWindowRectEx(&rcMax, (DWORD) style, (m_pHookedWnd->GetMenu() != NULL), (DWORD) styleEx); + + switch (fwSide) + { + case WMSZ_BOTTOM: + if (prc->Height() < rcMin.Height() ) + { + prc->bottom = prc->top + rcMin.Height(); + } + if (prc->Height() > rcMax.Height() ) + { + prc->bottom = prc->top + rcMax.Height(); + } + break; + case WMSZ_BOTTOMLEFT: + if (prc->Height() < rcMin.Height() ) + { + prc->bottom = prc->top + rcMin.Height(); + } + if (prc->Width() < rcMin.Width() ) + { + prc->left = prc->right - rcMin.Width(); + } + + if (prc->Height() > rcMax.Height() ) + { + prc->bottom = prc->top + rcMax.Height(); + } + if (prc->Width() > rcMax.Width() ) + { + prc->left = prc->right - rcMax.Width(); + } + break; + case WMSZ_BOTTOMRIGHT: + if (prc->Height() < rcMin.Height() ) + { + prc->bottom = prc->top + rcMin.Height(); + } + if (prc->Width() < rcMin.Width() ) + { + prc->right = prc->left + rcMin.Width(); + } + + if (prc->Height() > rcMax.Height() ) + { + prc->bottom = prc->top + rcMax.Height(); + } + if (prc->Width() > rcMax.Width() ) + { + prc->right = prc->left + rcMax.Width(); + } + + break; + case WMSZ_LEFT: + if (prc->Width() < rcMin.Width() ) + { + prc->left = prc->right - rcMin.Width(); + } + + if (prc->Width() > rcMax.Width() ) + { + prc->left = prc->right - rcMax.Width(); + } + break; + case WMSZ_RIGHT: + if (prc->Width() < rcMin.Width() ) + { + prc->right = prc->left + rcMin.Width(); + } + + if (prc->Width() > rcMax.Width() ) + { + prc->right = prc->left + rcMax.Width(); + } + break; + case WMSZ_TOP: + if (prc->Height() < rcMin.Height() ) + { + prc->top = prc->bottom - rcMin.Height(); + } + + if (prc->Height() > rcMax.Height() ) + { + prc->top = prc->bottom - rcMax.Height(); + } + break; + case WMSZ_TOPLEFT: + if (prc->Height() < rcMin.Height() ) + { + prc->top = prc->bottom - rcMin.Height(); + } + if (prc->Width() < rcMin.Width() ) + { + prc->left = prc->right - rcMin.Width(); + } + + + if (prc->Height() > rcMax.Height() ) + { + prc->top = prc->bottom - rcMax.Height(); + } + if (prc->Width() > rcMax.Width() ) + { + prc->left = prc->right - rcMax.Width(); + } + break; + case WMSZ_TOPRIGHT: + if (prc->Height() < rcMin.Height() ) + { + prc->top = prc->bottom - rcMin.Height(); + } + if (prc->Width() < rcMin.Width() ) + { + prc->right = prc->left + rcMin.Width(); + } + + if (prc->Height() > rcMax.Height() ) + { + prc->top = prc->bottom - rcMax.Height(); + } + if (prc->Width() > rcMax.Width() ) + { + prc->right = prc->left + rcMax.Width(); + } + break; + } + +} + +void CWndResizer::OnPaint() +{ + if (m_pHookedWnd == NULL) + { + return; + } + CPaintDC dc(m_pHookedWnd); // device context for painting + + CPanelList panelList; + GetVisualPanels(&root, &panelList); + POSITION pos = panelList.GetHeadPosition(); + while (pos != NULL) + { + CVisualPanel * pPanel = (CVisualPanel *) panelList.GetNext(pos); + if (pPanel->m_bVisible) + { + pPanel->Draw(&dc); + } + } + +} + + +BOOL CWndResizer::SetAnchor(LPCTSTR panelName, UINT uAnchor) +{ + // container must already exist + CPanel * pPanel = NULL; + if ( (pPanel = FindPanelByName(&root, panelName)) == NULL) + { + return FALSE; + } + + return pPanel->SetAnchor(uAnchor); +} + +BOOL CWndResizer::SetAnchor(UINT uID, UINT uAnchor) +{ + ASSERT(m_pHookedWnd != NULL); + + CUIPanel * pPanel = GetUIPanel(uID); + + if (pPanel == NULL) + { + return FALSE; + } + pPanel->SetAnchor(uAnchor); + + return TRUE; +} +BOOL CWndResizer::GetAnchor(LPCTSTR panelName, UINT & anchor) +{ + CPanel * pPanel = NULL; + if ( (pPanel = FindPanelByName(&root, panelName)) == NULL) // name of parent must already exist + { + return FALSE; + } + + anchor = pPanel->Anchor; + return TRUE; +} +BOOL CWndResizer::GetAnchor(UINT uID, UINT & anchor) +{ + CPanel * pPanel = NULL; + if ( (pPanel = FindPanelByName(&root, IdToName(uID))) == NULL) // name of parent must already exist + { + return FALSE; + } + + anchor = pPanel->Anchor; + return TRUE; +} +///////////////////////////////////////////////////////////////////////////////////////////////////////// + +BOOL CWndResizer::SetDock(LPCTSTR panelName, UINT uDock) +{ + // container must already exist + CPanel * pPanel = NULL; + if ( (pPanel = FindPanelByName(&root, panelName)) == NULL) + { + return FALSE; + } + + pPanel->Dock = uDock ; + return TRUE; +} + +BOOL CWndResizer::SetDock(UINT uID, UINT uDock) +{ + ASSERT(m_pHookedWnd != NULL); + + CUIPanel * pPanel = GetUIPanel(uID); + + if (pPanel == NULL) + { + return FALSE; + } + pPanel->Dock = uDock; + + return TRUE; +} +BOOL CWndResizer::GetDock(LPCTSTR panelName, UINT & uDock) +{ + CPanel * pPanel = NULL; + if ( (pPanel = FindPanelByName(&root, panelName)) == NULL) // name of parent must already exist + { + return FALSE; + } + + uDock = pPanel->Dock; + return TRUE; +} +BOOL CWndResizer::GetDock(UINT uID, UINT & uDock) +{ + CPanel * pPanel = NULL; + if ( (pPanel = FindPanelByName(&root, IdToName(uID))) == NULL) // name of parent must already exist + { + return FALSE; + } + + uDock = pPanel->Dock; + return TRUE; +} + + +////////////////////// +BOOL CWndResizer::SetParent(LPCTSTR panelName, LPCTSTR parentName) +{ + ASSERT(m_pHookedWnd != NULL); + + + // now make sure parentName is OK + CPanel * pParent = NULL; + if ( (pParent = FindPanelByName(&root, parentName)) == NULL) // name of parent must already exist + { + return FALSE; + } + + // make sure panelName exist + CPanel * pPanel = NULL; + if ((pPanel = FindPanelByName(&root, panelName)) == NULL) + { + return FALSE; + } + + return pParent->AddChild(pPanel); +} +BOOL CWndResizer::SetParent(UINT uID, LPCTSTR parentName) +{ + ASSERT(m_pHookedWnd != NULL); + + // now make sure parentName is OK + CPanel * pParent = NULL; + if ( (pParent = FindPanelByName(&root, parentName)) == NULL) // name of parent must already exist + { + return FALSE; + } + CPanel * pPanel = NULL; + + // first see if it is already defined + if ((pPanel = FindPanelByName(&root, IdToName(uID))) == NULL) + { + if ((pPanel = CreateUIPanel(uID)) == NULL) + { + return FALSE; + } + } + + return pParent->AddChild(pPanel); + +} + +BOOL CWndResizer::SetParent(LPCTSTR panelName, UINT uParentID) +{ + ASSERT(m_pHookedWnd != NULL); + + // now make sure parentName is OK + CPanel * pParent = GetUIPanel(uParentID); + if ( pParent == NULL) // name of parent must already exist + { + return FALSE; + } + + // make sure panelName exist + CPanel * pPanel = NULL; + if ((pPanel = FindPanelByName(&root, panelName)) == NULL) + { + return FALSE; + } + + return pParent->AddChild(pPanel); + +} +BOOL CWndResizer::SetParent(UINT uID, UINT uParentID) +{ + CPanel * pParent = GetUIPanel(uParentID); + if (pParent == NULL) + { + return FALSE; + } + CPanel * pPanel = GetUIPanel(uID);; + if (pParent == NULL) + { + return FALSE; + } + + return pParent->AddChild( pPanel ); + +} + + +BOOL CWndResizer::GetParent(LPCTSTR panelName, CString & parentName) +{ + CPanel * pPanel = NULL; + if ( (pPanel = FindPanelByName(&root, panelName)) == NULL) + { + return FALSE; + } + + parentName = pPanel->Parent->Name; + return TRUE; +} +BOOL CWndResizer::GetParent(UINT uID, CString & parentName) +{ + CPanel * pPanel = NULL; + if ( (pPanel = FindPanelByName(&root, IdToName(uID))) == NULL) // name of parent must already exist + { + return FALSE; + } + + parentName = pPanel->Parent->Name; + return TRUE; +} + +BOOL CWndResizer::SetFixedPanel(LPCTSTR splitContainerName, short panel) +{ + CPanel * pContainer = FindPanelByName(&root, splitContainerName); + if (pContainer == NULL) + { + return FALSE; + } + CSplitContainer * pSplitContainer = dynamic_cast( pContainer ); + if (pSplitContainer == NULL) + { + return FALSE; + } + + pSplitContainer->SetFixedPanel(panel); + return TRUE; +} +BOOL CWndResizer::GetFixedPanel(LPCTSTR splitContainerName, short & panel) +{ + CPanel * pContainer = FindPanelByName(&root, splitContainerName); + if (pContainer == NULL) + { + return FALSE; + } + CSplitContainer * pSplitContainer = dynamic_cast (pContainer); + if (pSplitContainer == NULL) + { + return FALSE; + } + panel = pSplitContainer->GetFixedPanel(); + return TRUE; + +} + +BOOL CWndResizer::SetIsSplitterFixed(LPCTSTR splitContainerName, BOOL fixed) +{ + CPanel * pContainer = FindPanelByName(&root, splitContainerName); + if (pContainer == NULL) + { + return FALSE; + } + CSplitContainer * pSplitContainer = dynamic_cast (pContainer); + if (pSplitContainer == NULL) + { + return FALSE; + } + pSplitContainer->SetIsSplitterFixed( fixed ); + return TRUE; +} +BOOL CWndResizer::GetIsSplitterFixed(LPCTSTR splitContainerName, BOOL &fixed) +{ + CPanel * pContainer = FindPanelByName(&root, splitContainerName); + if (pContainer == NULL) + { + return FALSE; + } + CSplitContainer * pSplitContainer = dynamic_cast (pContainer); + if (pSplitContainer == NULL) + { + return FALSE; + } + fixed = pSplitContainer->GetIsSplitterFixed(); + return TRUE; +} + + + +BOOL CWndResizer::SetShowSplitterGrip(LPCTSTR splitContainerName, BOOL bShow) +{ + CPanel * pContainer = FindPanelByName(&root, splitContainerName); + if (pContainer == NULL) + { + return FALSE; + } + CSplitContainer * pSplitContainer = dynamic_cast (pContainer); + if (pSplitContainer == NULL) + { + return FALSE; + } + pSplitContainer->SetShowSplitterGrip( bShow ); + return TRUE; +} +BOOL CWndResizer::GetShowSplitterGrip(LPCTSTR splitContainerName, BOOL &bShow) +{ + CPanel * pContainer = FindPanelByName(&root, splitContainerName); + if (pContainer == NULL) + { + return FALSE; + } + CSplitContainer * pSplitContainer = dynamic_cast (pContainer); + if (pSplitContainer == NULL) + { + return FALSE; + } + bShow = pSplitContainer->GetShowSplitterGrip(); + return TRUE; +} + + + + +///////////////////////// +BOOL CWndResizer::SetMinimumSize( LPCTSTR panelName, CSize & size) +{ + CPanel * pPanel = NULL; + + if ( (pPanel = FindPanelByName(&root, panelName)) == NULL) + { + return FALSE; + } + return pPanel->SetMinSize( size ); +} +BOOL CWndResizer::SetMinimumSize(UINT uID, CSize & size) +{ + CPanel * pPanel = NULL; + + if ( (pPanel = FindPanelByName(&root, IdToName(uID))) == NULL) + { + if ((pPanel = CreateUIPanel(uID)) == NULL) + { + return FALSE; + } + } + + return pPanel->SetMinSize( size ); +} + +BOOL CWndResizer::GetMinimumSize(LPCTSTR panelName, CSize & size) +{ + CPanel * pPanel = NULL; + + if ( (pPanel = FindPanelByName(&root, panelName)) == NULL) + { + return FALSE; + } + + size = pPanel->MinSize; + return TRUE; +} +BOOL CWndResizer::GetMinimumSize(UINT uID, CSize & size) +{ + const CPanel * pPanel = NULL; + + if ( (pPanel = FindPanelByName(&root, IdToName(uID))) == NULL) + { + return FALSE; + } + + size = pPanel->MinSize; + return TRUE; +} +BOOL CWndResizer::SetMaximumSize(UINT uID, CSize & size) +{ + CPanel * pPanel = NULL; + + if ( (pPanel = FindPanelByName(&root, IdToName(uID))) == NULL) + { + return FALSE; + } + + return pPanel->SetMaxSize(size); +} + +BOOL CWndResizer::SetMaximumSize( LPCTSTR panelName, CSize & size) +{ + CPanel * pPanel = NULL; + + if ( (pPanel = FindPanelByName(&root, panelName)) == NULL) + { + return FALSE; + } + + return pPanel->SetMaxSize(size); + +} +BOOL CWndResizer::GetMaximumSize( LPCTSTR panelName, CSize & size) +{ + CPanel * pPanel = NULL; + if ( (pPanel = FindPanelByName(&root, panelName)) == NULL) + { + return FALSE; + } + + size = pPanel->MaxSize; + return TRUE; +} +BOOL CWndResizer::GetMaximumSize( UINT uID, CSize & size) +{ + CPanel * pPanel = NULL; + if ( (pPanel = FindPanelByName(&root, IdToName(uID))) == NULL) + { + return FALSE; + } + + size = pPanel->MaxSize; + return TRUE; +} +void CWndResizer::SetShowResizeGrip(BOOL show) +{ + CGripperPanel * pPanel = (CGripperPanel *)FindPanelByName(&root, _T("_resizeGrip")); + ASSERT(pPanel != NULL); + if ( pPanel->m_bVisible != show ) + { + pPanel->m_bVisible = show; + m_pHookedWnd->Invalidate(TRUE); + } +} +BOOL CWndResizer::GetShowResizeGrip() +{ + CGripperPanel * pPanel = (CGripperPanel *)FindPanelByName(&root, _T("_resizeGrip")); + ASSERT(pPanel != NULL); + return pPanel->m_bVisible ; + +} +void CWndResizer::OnDestroy() +{ + if (m_pHookedWnd != NULL) + { + Unhook(); + } +} + +BOOL CWndResizer::Unhook() +{ + ASSERT( m_pHookedWnd != NULL ); + if (m_pHookedWnd == NULL ) + { + return FALSE; //hasent been hooked + } + + WNDPROC pWndProc = (WNDPROC)::SetWindowLongPtr(m_pHookedWnd->m_hWnd, GWLP_WNDPROC, (LONG_PTR)m_pfnWndProc); + WndResizerData.RemoveKey(m_pHookedWnd->m_hWnd); + root.m_pHookWnd = NULL; + m_pHookedWnd = NULL; + + // destroy all chilldren + while(root.Children.GetCount() > 0 ) + { + CPanel * pChild = root.Children.RemoveHead(); + delete pChild; + } + return TRUE; +} + + +LRESULT CALLBACK CWndResizer::WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + CWndResizer * pResizer = NULL; + WndResizerData.Lookup(hWnd, pResizer); + ASSERT( pResizer != NULL); + + + switch (uMsg) + { + case WM_SIZE: + { + int cx = 0; + int cy = 0; + cx = LOWORD(lParam); + cy = HIWORD(lParam); + pResizer->OnSize((UINT) wParam, cx, cy); + } + break; + case WM_SIZING: + pResizer->OnSizing((UINT) wParam, (LPRECT)lParam); + break; + case WM_DESTROY: + pResizer->OnDestroy(); + break; + case WM_MOUSEMOVE: + pResizer->OnMouseMove((UINT) wParam, CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); + break; + case WM_LBUTTONDOWN: + pResizer->OnLButtonDown((UINT) wParam, CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); + break; + case WM_LBUTTONUP: + pResizer->OnLButtonUp((UINT) wParam, CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); + break; + case WM_PAINT: + pResizer->OnPaint(); + break; + case WM_HSCROLL: + case WM_VSCROLL: + pResizer->OnScroll(); + break; + + //case WM_ERASEBKGND: + // return FALSE; + // break; + default: + break; + } + + return ::CallWindowProc(pResizer->m_pfnWndProc, hWnd, uMsg, wParam, lParam); + + +} + + + +BOOL CWndResizer::CreateSplitContainer(LPCTSTR panelName, LPCTSTR panelNameA, LPCTSTR panelNameB) +{ + CPanel * pPanel = NULL; + if ((pPanel = FindPanelByName(&root, panelName)) != NULL) + { + return FALSE; + } + + CPanel * pPanelA = NULL; + if ((pPanelA = FindPanelByName(&root, panelNameA)) == NULL) + { + return FALSE; + } + + + CPanel * pPanelB = NULL; + if ((pPanelB = FindPanelByName(&root, panelNameB)) == NULL) + { + return FALSE; + } + + + if (pPanelA == pPanelB) // two panel cannot be same + { + return FALSE; + } + + + CPanel * pSplitterContainer = CSplitContainer::Create(pPanelA, pPanelB); + if (pSplitterContainer == NULL) + { + return FALSE; + } + pSplitterContainer->Name = panelName; + + return root.AddChild(pSplitterContainer); +} + + + +BOOL CWndResizer::CreateSplitContainer(LPCTSTR panelName, LPCTSTR panelNameA, UINT panelIDB) +{ + CPanel * pPanel = NULL; + if ((pPanel = FindPanelByName(&root, panelName)) != NULL) + { + return FALSE; + } + + CPanel * pPanelA = NULL; + if ((pPanelA = FindPanelByName(&root, panelNameA)) == NULL) + { + return FALSE; + } + + CPanel * pPanelB = GetUIPanel(panelIDB); + if (pPanelB == NULL ) + { + return FALSE; + } + + + if (pPanelA == pPanelB) // two panel cannot be same + { + return FALSE; + } + + // first lets make sure the two CRect are properly set + + CPanel * pSplitterContainer = CSplitContainer::Create(pPanelA, pPanelB); + if (pSplitterContainer == NULL) + { + return FALSE; + } + pSplitterContainer->Name = panelName; + + return root.AddChild(pSplitterContainer); + +} + + +BOOL CWndResizer::CreateSplitContainer(LPCTSTR panelName, UINT panelIDA, LPCTSTR panelNameB) +{ + CPanel * pPanel = NULL; + if ((pPanel = FindPanelByName(&root, panelName)) != NULL) + { + return FALSE; + } + + CPanel * pPanelA = GetUIPanel(panelIDA); + if (pPanelA == NULL ) + { + return FALSE; + } + + + CPanel * pPanelB = NULL; + if ((pPanelB = FindPanelByName(&root, panelNameB)) == NULL) + { + return FALSE; + } + + if (pPanelA == pPanelB) // two panel cannot be same + { + return FALSE; + } + + CPanel * pSplitterContainer = CSplitContainer::Create(pPanelA, pPanelB); + if (pSplitterContainer == NULL) + { + return FALSE; + } + pSplitterContainer->Name.Append(panelName); + + return root.AddChild(pSplitterContainer); + +} + + + +BOOL CWndResizer::CreateSplitContainer(LPCTSTR panelName, UINT panelIDA, UINT panelIDB) +{ + CPanel * pPanel = NULL; + if ((pPanel = FindPanelByName(&root, panelName)) != NULL) + { + return FALSE; + } + + CPanel * pPanelA = GetUIPanel(panelIDA); + if (pPanelA == NULL ) + { + return FALSE; + } + + + CPanel * pPanelB = GetUIPanel(panelIDB); + if (pPanelB == NULL ) + { + return FALSE; + } + + if (pPanelA == pPanelB) // two panel cannot be same + { + return FALSE; + } + + CPanel * pSplitterContainer = CSplitContainer::Create(pPanelA, pPanelB); + if (pSplitterContainer == NULL) + { + return FALSE; + } + pSplitterContainer->Name = panelName; + + return root.AddChild(pSplitterContainer); + +} + +BOOL CWndResizer::SetSplitterPosition(LPCTSTR splitContainerName, UINT position) +{ + ASSERT(m_pHookedWnd != NULL); + CPanel * pPanel = NULL; + if ((pPanel = FindPanelByName(&root, splitContainerName)) == NULL) + { + return FALSE; + } + CSplitContainer * pContainer = dynamic_cast ( pPanel); + if (pContainer == NULL) + { + return FALSE; + } + pContainer->SetSplitterPosition( (int) position); + ResizeUI( pContainer ); + return TRUE; +} +BOOL CWndResizer::GetSplitterPosition(LPCTSTR splitContainerName, UINT & position) +{ + ASSERT(m_pHookedWnd != NULL); + CPanel * pPanel = NULL; + if ((pPanel = FindPanelByName(&root, splitContainerName)) == NULL) + { + return FALSE; + } + CSplitContainer * pContainer = dynamic_cast ( pPanel); + if (pContainer == NULL) + { + return FALSE; + } + position = (UINT) pContainer->GetSplitterPosition(); + return TRUE; +} + +BOOL CWndResizer::CreatePanel(UINT uID) +{ + ASSERT(m_pHookedWnd != NULL); + if (FindPanelByName(&root, IdToName(uID)) != NULL) + { + return FALSE; + } + CUIPanel * pPanel = GetUIPanel(uID); + ASSERT(pPanel != NULL); + + pPanel->m_bOle = TRUE; + + return TRUE; +} + +BOOL CWndResizer::SetFlowDirection(LPCTSTR flowPanelName, short direction) +{ + ASSERT(m_pHookedWnd != NULL); + CPanel * pPanel = NULL; + if ((pPanel = FindPanelByName(&root, flowPanelName)) == NULL) + { + return FALSE; + } + CFlowLayoutPanel * pFlowLayout = dynamic_cast ( pPanel); + if (pFlowLayout == NULL) + { + return FALSE; + } + pFlowLayout->SetFlowDirection( direction == 1 ? LEFT_TO_RIGHT : TOP_TO_BOTTOM); + return TRUE; +} +BOOL CWndResizer::GetFlowDirection(LPCTSTR flowPanelName, short &direction) +{ + ASSERT(m_pHookedWnd != NULL); + CPanel * pPanel = NULL; + if ((pPanel = FindPanelByName(&root, flowPanelName)) == NULL) + { + return FALSE; + } + CFlowLayoutPanel * pFlowLayout = dynamic_cast ( pPanel); + if (pFlowLayout == NULL) + { + return FALSE; + } + direction = (pFlowLayout->GetFlowDirection() == LEFT_TO_RIGHT ? 1 : 2); + return TRUE; +} + +BOOL CWndResizer::SetFlowItemSpacingX(LPCTSTR flowPanelName, int nSpacing) +{ + ASSERT(m_pHookedWnd != NULL); + CPanel * pPanel = NULL; + if ((pPanel = FindPanelByName(&root, flowPanelName)) == NULL) + { + return FALSE; + } + CFlowLayoutPanel * pFlowLayout = dynamic_cast ( pPanel); + if (pFlowLayout == NULL) + { + return FALSE; + } + pFlowLayout->SetItemSpacingX(nSpacing); + return TRUE; +} +BOOL CWndResizer::GetFlowItemSpacingX(LPCTSTR flowPanelName, int &nSpacing) +{ + ASSERT(m_pHookedWnd != NULL); + CPanel * pPanel = NULL; + if ((pPanel = FindPanelByName(&root, flowPanelName)) == NULL) + { + return FALSE; + } + CFlowLayoutPanel * pFlowLayout = dynamic_cast ( pPanel); + if (pFlowLayout == NULL) + { + return FALSE; + } + nSpacing = pFlowLayout->GetItemSpacingX(); + return TRUE; +} + +BOOL CWndResizer::SetFlowItemSpacingY(LPCTSTR flowPanelName, int nSpacing) +{ + ASSERT(m_pHookedWnd != NULL); + CPanel * pPanel = NULL; + if ((pPanel = FindPanelByName(&root, flowPanelName)) == NULL) + { + return FALSE; + } + CFlowLayoutPanel * pFlowLayout = dynamic_cast ( pPanel); + if (pFlowLayout == NULL) + { + return FALSE; + } + pFlowLayout->SetItemSpacingY(nSpacing); + return TRUE; + +} + +BOOL CWndResizer::GetFlowItemSpacingY(LPCTSTR flowPanelName, int &nSpacing) +{ + ASSERT(m_pHookedWnd != NULL); + CPanel * pPanel = NULL; + if ((pPanel = FindPanelByName(&root, flowPanelName)) == NULL) + { + return FALSE; + } + CFlowLayoutPanel * pFlowLayout = dynamic_cast ( pPanel); + if (pFlowLayout == NULL) + { + return FALSE; + } + nSpacing = pFlowLayout->GetItemSpacingY(); + return TRUE; + +} + + +BOOL CWndResizer::CreateFlowLayoutPanel(LPCTSTR panelName, const CRect * prcPanel) +{ + if (FindPanelByName(&root, panelName) != NULL) + { + return FALSE; + } + + CPanel * pPanel = new CFlowLayoutPanel(prcPanel); + pPanel->Name = panelName; + return root.AddChild(pPanel); + +} +BOOL CWndResizer::CreateFlowLayoutPanel(LPCTSTR panelName, const CUIntArray * parrID, BOOL setAsChildren) +{ + ASSERT(m_pHookedWnd != NULL); + + CRect rcFinal(0, 0, 0, 0); + for(int i = 0; i < parrID->GetCount(); i++) + { + CRect rc(0, 0, 0, 0); + m_pHookedWnd->GetDlgItem(parrID->GetAt(i))->GetWindowRect(&rc); + m_pHookedWnd->ScreenToClient(&rc); + rcFinal.UnionRect(&rcFinal, &rc); + } + + BOOL bOk = CreateFlowLayoutPanel(panelName, &rcFinal); + if (bOk == FALSE) + { + return FALSE; + } + + if ( setAsChildren ) + { + CPanel * pPanel = FindPanelByName(&root, panelName); + for(int i = 0; i < parrID->GetCount(); i++) + { + if (FindPanelByName(&root, IdToName(parrID->GetAt(i))) != NULL) + { + bOk = root.RemoveChild(pPanel); + ASSERT( bOk ); + delete pPanel; + return FALSE; + } + CUIPanel * pUIPanel = GetUIPanel(parrID->GetAt(i)); + ASSERT( pUIPanel != NULL); + bOk = pPanel->AddChild( pUIPanel ); + ASSERT( bOk ); + } + } + return TRUE; +} + +BOOL CWndResizer::CreatePanel(LPCTSTR panelName, const CRect * prcPanel) +{ + if (FindPanelByName(&root, panelName) != NULL) + { + return FALSE; + } + + CPanel * pPanel = new CPanel(prcPanel); + pPanel->Name = panelName; + return root.AddChild(pPanel); + +} +BOOL CWndResizer::CreatePanel(LPCTSTR panelName, const CUIntArray * parrID, BOOL setAsChildren) +{ + ASSERT(m_pHookedWnd != NULL); + + CRect rcFinal(0, 0, 0, 0); + for(int i = 0; i < parrID->GetCount(); i++) + { + CRect rc(0, 0, 0, 0); + m_pHookedWnd->GetDlgItem(parrID->GetAt(i))->GetWindowRect(&rc); + m_pHookedWnd->ScreenToClient(&rc); + rcFinal.UnionRect(&rcFinal, &rc); + } + + BOOL bOk = CreatePanel(panelName, &rcFinal); + if (bOk == FALSE) + { + return FALSE; + } + + if ( setAsChildren ) + { + CPanel * pPanel = FindPanelByName(&root, panelName); + for(int i = 0; i < parrID->GetCount(); i++) + { + if (FindPanelByName(&root, IdToName(parrID->GetAt(i))) != NULL) + { + bOk = root.RemoveChild(pPanel); + ASSERT( bOk ); + delete pPanel; + return FALSE; + } + CUIPanel * pUIPanel = GetUIPanel(parrID->GetAt(i)); + ASSERT( pUIPanel != NULL); + bOk = pPanel->AddChild( pUIPanel ); + ASSERT( bOk ); + } + } + return TRUE; +} + +CPanel * CWndResizer::FindPanelByName(CPanel * pRoot, LPCTSTR name) +{ + if (CString(name).GetLength() == 0) + { + return NULL; + } + + if (pRoot == NULL ) + { + return NULL; + } + + if (pRoot->Name.CompareNoCase(name) == 0 ) + { + return pRoot; + } + else + { + POSITION pos = pRoot->Children.GetHeadPosition(); + while(pos != NULL) + { + CPanel * pChild = pRoot->Children.GetNext(pos); + CPanel * pFound = FindPanelByName(pChild, name); + if (pFound != NULL ) + { + return pFound; + } + } + } + + return NULL; +} +void CWndResizer::GetUIPanels(CPanel * pRoot, CPanelList * pList, BOOL bOle) +{ + if (pRoot == NULL ) + { + return ; + } + + CUIPanel * pUIPanel = dynamic_cast ( pRoot); + + if (pUIPanel != NULL && pUIPanel->m_bOle == bOle) + { + pList->AddTail( pRoot ); + } + + // try the childreen + POSITION pos = pRoot->Children.GetHeadPosition(); + while(pos != NULL) + { + CPanel * pChild = pRoot->Children.GetNext(pos); + GetUIPanels(pChild, pList, bOle); + + } + +} + +void CWndResizer::GetVisualPanels(CPanel * pRoot, CPanelList * pList) +{ + if (pRoot == NULL ) + { + return ; + } + + CVisualPanel * pUIPanel = dynamic_cast ( pRoot); + + if (pUIPanel != NULL) + { + pList->AddTail( pRoot ); + } + + // try the childreen + POSITION pos = pRoot->Children.GetHeadPosition(); + while(pos != NULL) + { + CPanel * pChild = pRoot->Children.GetNext(pos); + GetVisualPanels(pChild, pList); + } +} + + +CPanel * CWndResizer::FindSplitterFromPoint(CPanel * pRoot, CPoint point) +{ + if (pRoot == NULL ) + { + return NULL; + } + + CSpitterPanel * pSpitterPanel = dynamic_cast(pRoot); + + if (pSpitterPanel != NULL && pRoot->PtInRect(point) == TRUE ) + { + CSplitContainer * pContainer = (CSplitContainer *)pRoot->Parent; + if (!pContainer->GetIsSplitterFixed()) + { + CPoint ptScreen = point; + m_pHookedWnd->ClientToScreen(&ptScreen); + HWND hWndFromPoint = ::WindowFromPoint(ptScreen); + if (m_pHookedWnd->m_hWnd == hWndFromPoint) + { + return pRoot; + } + } + } + + // try the childreen + POSITION pos = pRoot->Children.GetHeadPosition(); + while(pos != NULL) + { + CPanel * pChild = pRoot->Children.GetNext(pos); + CPanel * pFound = FindSplitterFromPoint(pChild, point); + if (pFound != NULL ) + { + return pFound; + } + } + + + return NULL; +} + +CString CWndResizer::IdToName(UINT uID) +{ + CString sName; + sName.Format(_T("%d"), uID); + return sName; +} + +CUIPanel * CWndResizer::CreateUIPanel(UINT uID) +{ + ASSERT(m_pHookedWnd != NULL); + CWnd * pWnd = m_pHookedWnd->GetDlgItem(uID); + + if ( pWnd == NULL ) + { + return NULL; + } + CRect rc(0, 0, 0, 0); + pWnd->GetWindowRect( &rc ); + m_pHookedWnd->ScreenToClient( &rc ); + + CUIPanel * pPanel = new CUIPanel(&rc, uID); + pPanel->Name = IdToName(uID); + return pPanel ; +} + +CUIPanel * CWndResizer::GetUIPanel(UINT uID) +{ + CUIPanel * pPanel = NULL; + if ((pPanel = (CUIPanel *)FindPanelByName(&root, IdToName(uID))) == NULL) + { + pPanel = CreateUIPanel(uID); + if (pPanel != NULL) + { + root.AddChild( pPanel ); + } + } + return pPanel; +} + +BOOL CWndResizer::InvokeOnResized() +{ + ASSERT(m_pHookedWnd != NULL); + + OnSize(0, 0, 0); + return TRUE; +} + + +CString CWndResizer::GetDebugInfo() +{ + ASSERT(m_pHookedWnd != NULL); + + CString sInfo; + CString sIndent; + + GetDebugInfo(&root, sInfo, sIndent); + + return sInfo; +} +void CWndResizer::GetDebugInfo(CPanel * pRoot, CString & info, CString indent) +{ + if (pRoot == NULL ) + { + return ; + } + + info.Append(_T("\n")); + info.Append(indent); + info.Append(pRoot->ToString() ); + + indent.Append(_T(" ")); + for(int i = 0; i < pRoot->Children.GetCount(); i++) + { + CPanel * pChild = pRoot->Children.GetAt(pRoot->Children.FindIndex(i)); + GetDebugInfo(pChild, info, indent); + } + +} + + +///////////////////////////// CPanel +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +CPanel::CPanel() : CRect(0, 0, 0, 0) +{ + Init(); +} +CPanel::CPanel(const CRect * prc) : CRect(prc) +{ + Init(); +} +void CPanel::Init() +{ + Parent = NULL; + LeftOffset = 0; + TopOffset = 0; + RightOffset = 0; + BottomOffset = 0; + MinSize.SetSize(10, 10); + MaxSize.SetSize(100000, 100000); + Anchor =(ANCHOR_LEFT | ANCHOR_TOP); + Dock = DOCK_NONE; +} + +CPanel::~CPanel() +{ + while(Children.GetCount() > 0 ) + { + delete Children.RemoveHead(); + } +} +void CPanel::OnResized() +{ + BOOL bOk = FALSE; + CRect rcEmpty(this); // available area for docking. ininitally it is the entire area + + POSITION pos = Children.GetHeadPosition(); + while(pos != NULL) + { + CPanel * pChild = Children.GetNext(pos); + + if (pChild->Dock != DOCK_NONE) + { + switch(pChild->Dock) + { + case DOCK_LEFT: + pChild->SetRect(rcEmpty.left, rcEmpty.top, rcEmpty.left + pChild->Width(), rcEmpty.bottom); + bOk = rcEmpty.SubtractRect(&rcEmpty, pChild); + // ASSERT( bOk ); + break; + case DOCK_TOP: + pChild->SetRect(rcEmpty.left, rcEmpty.top, rcEmpty.right, rcEmpty.top + pChild->Height()); + bOk = rcEmpty.SubtractRect(&rcEmpty, pChild); + // ASSERT( bOk ); + break; + case DOCK_RIGHT: + pChild->SetRect(rcEmpty.right - pChild->Width(), rcEmpty.top, rcEmpty.right, rcEmpty.bottom); + bOk = rcEmpty.SubtractRect(&rcEmpty, pChild); + // ASSERT( bOk ); + break; + case DOCK_BOTTOM: + pChild->SetRect(rcEmpty.left, rcEmpty.bottom - pChild->Height(), rcEmpty.right, rcEmpty.bottom); + bOk = rcEmpty.SubtractRect(&rcEmpty, pChild); + // ASSERT( bOk ); + break; + case DOCK_FILL: + pChild->SetRect(rcEmpty.left, rcEmpty.top, rcEmpty.right, rcEmpty.bottom); + break; + } + pChild->OnResized(); + + // if docking is in action, then we igonre anchor, therefore we continue + continue; + } + + CRect rc(0, 0, 0, 0); + if ((pChild->Anchor & ANCHOR_HORIZONTALLY_CENTERED) == ANCHOR_HORIZONTALLY_CENTERED ) + { + rc.left = this->left + ((int)( (this->Width() - pChild->Width()) / 2)); + rc.right = rc.left + pChild->Width(); + + BOOL bReposition = FALSE; + if (pChild->MinSize.cx > rc.Width() ) + { + bReposition = TRUE; + rc.right = rc.left + pChild->MinSize.cx; + } + if (pChild->MaxSize.cx < rc.Width() ) + { + bReposition = TRUE; + rc.right = rc.left + pChild->MaxSize.cx; + } + + if (bReposition) + { + int nWidth = rc.Width(); + rc.left = (int)( (this->Width() - nWidth) / 2) ; + rc.right = rc.left + nWidth; + } + } + else if ((pChild->Anchor & ANCHOR_HORIZONTALLY) == ANCHOR_HORIZONTALLY ) + { + rc.left = this->left + pChild->LeftOffset; + rc.right = this->right - pChild->RightOffset; + + // we will be left anchor if minsize or maxsize does not match + // (giving ANCHOR_LEFT priority over ANCHOR_RIGHT) + if ((pChild->Anchor & ANCHOR_PRIORITY_RIGHT) == ANCHOR_PRIORITY_RIGHT) + { + if (pChild->MinSize.cx > rc.Width() ) + { + rc.left = rc.right - pChild->MinSize.cx; + } + if (pChild->MaxSize.cx < rc.Width() ) + { + rc.left = rc.right - pChild->MaxSize.cx; + } + + } + else + { + if (pChild->MinSize.cx > rc.Width() ) + { + rc.right = rc.left + pChild->MinSize.cx; + } + if (pChild->MaxSize.cx < rc.Width() ) + { + rc.right = rc.left + pChild->MaxSize.cx; + } + } + } + else if ((pChild->Anchor & ANCHOR_RIGHT) == ANCHOR_RIGHT ) + { + rc.right = this->right - pChild->RightOffset; + rc.left = rc.right - pChild->Width(); + + if (pChild->MinSize.cx > rc.Width() ) + { + rc.left = rc.right - pChild->MinSize.cx; + } + if (pChild->MaxSize.cx < rc.Width() ) + { + rc.left = rc.right - pChild->MaxSize.cx; + } + } + else if ((pChild->Anchor & ANCHOR_LEFT) == ANCHOR_LEFT ) + { + rc.left = this->left + pChild->LeftOffset; + rc.right = rc.left + pChild->Width(); + + if (pChild->MinSize.cx > rc.Width() ) + { + rc.right = rc.left + pChild->MinSize.cx; + } + if (pChild->MaxSize.cx < rc.Width() ) + { + rc.right = rc.left + pChild->MaxSize.cx; + } + } + else + { + // it should never be here + ASSERT( FALSE ); + } + + + if ((pChild->Anchor & ANCHOR_VERTICALLY_CENTERED) == ANCHOR_VERTICALLY_CENTERED ) + { + rc.top = this->top + ((int)( (this->Height() - pChild->Height()) / 2)); + rc.bottom = rc.top + pChild->Height(); + + BOOL bReposition = FALSE; + if (pChild->MinSize.cy > rc.Height() ) + { + bReposition = TRUE; + rc.bottom = rc.top + pChild->MinSize.cy; + } + if (pChild->MaxSize.cy < rc.Height() ) + { + bReposition = TRUE; + rc.bottom = rc.top + pChild->MaxSize.cy; + } + + if (bReposition) + { + int nHeight = rc.Height(); + rc.top = (int)( (this->Height() - nHeight) / 2); + rc.bottom = rc.top + nHeight; + } + } + else if ((pChild->Anchor & ANCHOR_VERTICALLY ) == ANCHOR_VERTICALLY ) + { + rc.top = this->top + pChild->TopOffset; + rc.bottom = this->bottom - pChild->BottomOffset; + + if ((pChild->Anchor & ANCHOR_PRIORITY_BOTTOM) == ANCHOR_PRIORITY_BOTTOM) + { + if (pChild->MinSize.cy > rc.Height() ) + { + rc.top = rc.bottom - pChild->MinSize.cy; + } + if (pChild->MaxSize.cy < rc.Height() ) + { + rc.top = rc.bottom - pChild->MaxSize.cy; + } + } + else + { + if (pChild->MinSize.cy > rc.Height() ) + { + rc.bottom = rc.top + pChild->MinSize.cy; + } + if (pChild->MaxSize.cy < rc.Height() ) + { + rc.bottom = rc.top + pChild->MaxSize.cy; + } + } + } + else if ((pChild->Anchor & ANCHOR_BOTTOM) == ANCHOR_BOTTOM ) + { + rc.bottom = this->bottom - pChild->BottomOffset; + rc.top = rc.bottom - pChild->Height(); + + if (pChild->MinSize.cy > rc.Height() ) + { + rc.top = rc.bottom - pChild->MinSize.cy; + } + if (pChild->MaxSize.cy < rc.Height() ) + { + rc.top = rc.bottom - pChild->MaxSize.cy; + } + } + else if ((pChild->Anchor & ANCHOR_TOP) == ANCHOR_TOP ) + { + rc.top = this->top + pChild->TopOffset; + rc.bottom = rc.top + pChild->Height(); + + if (pChild->MinSize.cy > rc.Height() ) + { + rc.bottom = rc.top + pChild->MinSize.cy; + } + if (pChild->MaxSize.cy < rc.Height() ) + { + rc.bottom = rc.top + pChild->MaxSize.cy; + } + } + else + { + // it should never be here + ASSERT( FALSE ); + } + pChild->SetRect(rc.TopLeft(), rc.BottomRight()); + + pChild->OnResized(); + + } +} +BOOL CPanel::AddChild(CPanel * pChild) +{ + if (pChild->Parent != NULL) + { + BOOL bOk = pChild->Parent->RemoveChild(pChild); + if (bOk == FALSE) + { + return FALSE; + } + } + pChild->LeftOffset = pChild->left - this->left; + pChild->TopOffset = pChild->top - this->top; + pChild->RightOffset = this->right - pChild->right; + pChild->BottomOffset = this->bottom - pChild->bottom; + + pChild->Parent = this; + + Children.AddTail( pChild ); + return TRUE; +} + +BOOL CPanel::RemoveChild(CPanel * pChild) +{ + POSITION pos = Children.Find(pChild); + if (pos == NULL) + { + return FALSE; + } + Children.RemoveAt(pos); + return TRUE; + +} + +BOOL CPanel::SetMinSize(CSize & size) +{ + if (MaxSize.cx < size.cx) + { + return FALSE; + } + if (MaxSize.cy < size.cy) + { + return FALSE; + } + + MinSize = size; + return TRUE; +} +BOOL CPanel::SetMaxSize(CSize & size) +{ + if (MinSize.cx > size.cx) + { + return FALSE; + } + if (MinSize.cy > size.cy) + { + return FALSE; + } + + MaxSize = size; + return TRUE; +} + +BOOL CPanel::SetAnchor(UINT anchor) +{ + if ((anchor & ANCHOR_VERTICALLY_CENTERED) <= 0 ) + { + if ((anchor & ANCHOR_TOP) <= 0 ) + { + if ((anchor & ANCHOR_BOTTOM) <= 0 ) + { + anchor |= ANCHOR_TOP; // default + } + } + } + + if ((anchor & ANCHOR_HORIZONTALLY_CENTERED) <= 0 ) + { + if ((anchor & ANCHOR_LEFT) <= 0 ) + { + if ((anchor & ANCHOR_RIGHT) <= 0 ) + { + anchor |= ANCHOR_LEFT; // default + } + } + } + Anchor = anchor; + + return TRUE; +} +CString CPanel::ToString() +{ + CString sFormat(_T("Name(%s), Type(%s), Anchor(%d), Size(w:%d, h:%d), Area(l:%d, t:%d, r:%d, b:%d), MinSize(w:%d, h:%d), MaxSize(w:%d, h:%d), Parent(%s), ChildrenCount(%d)")); + + CString sTo; + sTo.Format(sFormat, Name, GetTypeName(), Anchor, Width(), Height(), left, top, right, bottom, MinSize.cx, MinSize.cy, MaxSize.cx, MaxSize.cy, (Parent == NULL? _T("NULL") : Parent->Name), Children.GetCount()); + return sTo; +} +CString CPanel::GetTypeName() +{ + return _T("CPanel"); +} + +CWnd * CPanel::GetHookedWnd() +{ + if (Parent != NULL) + { + return Parent->GetHookedWnd(); + } + return NULL; +} + +///////////////////////////// CSplitContainer +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +CSplitContainer::CSplitContainer(CSplitPanel * pPanelA, CSplitPanel * pPanelB, SplitterOrientation type) : CPanel() +{ + m_IsSplitterFixed = FALSE; + m_FixedPanel = 0; + + m_pPanelA = NULL; + m_pPanelB = NULL; + m_pSplitter = NULL; + + m_Orientation = type; + m_pPanelA = pPanelA; + m_pPanelB = pPanelB; + UnionRect(m_pPanelA, m_pPanelB); + + CRect rc(0, 0, 0, 0); + GetSplitArea(&rc); + m_pSplitter = new CSpitterPanel(&rc, type); + m_pSplitter->m_pGrippePanel->m_bVisible = FALSE; + + + if (m_Orientation == SPLIT_CONTAINER_H) + { + m_pPanelA->Anchor = (ANCHOR_LEFT | ANCHOR_TOP | ANCHOR_BOTTOM); + m_pPanelB->Anchor = (ANCHOR_RIGHT | ANCHOR_TOP | ANCHOR_BOTTOM); + } + else + { + m_pPanelA->Anchor = (ANCHOR_LEFT | ANCHOR_TOP | ANCHOR_RIGHT); + m_pPanelB->Anchor = (ANCHOR_LEFT | ANCHOR_BOTTOM | ANCHOR_RIGHT); + } + + m_nSplitterSize = GetSplitterSize(m_pPanelA, m_pPanelB); + + BOOL bOk = AddChild(m_pPanelA); + ASSERT( bOk); + + bOk = AddChild(m_pSplitter); + ASSERT( bOk); + + bOk = AddChild(m_pPanelB); + ASSERT( bOk); + + UpdateRatio(); +} + +CSplitContainer::~CSplitContainer() +{ + +} + +void CSplitContainer::OnResized() +{ + CPanel::OnResized(); + + if (m_Orientation == SPLIT_CONTAINER_H) + { + if (Width() < MinSize.cx) + { + return; + } + + if (m_FixedPanel == 1 ) // left panel is fixed + { + m_pPanelB->left = m_pPanelA->right + m_nSplitterSize; + + if (m_pPanelB->MinSize.cx > m_pPanelB->Width() ) + { + m_pPanelB->left = m_pPanelB->right - m_pPanelB->MinSize.cx; + m_pPanelA->right = m_pPanelB->left - m_nSplitterSize; + } + } + else if (m_FixedPanel == 2 ) // right panel is fixed + { + m_pPanelA->right = m_pPanelB->left - m_nSplitterSize; + + if (m_pPanelA->MinSize.cx > m_pPanelA->Width() ) + { + m_pPanelA->right = m_pPanelA->left + m_pPanelA->MinSize.cx; + m_pPanelB->left = m_pPanelA->right + m_nSplitterSize; + } + } + else + { + m_pPanelA->right = (LONG) ((double)m_pPanelA->left + ((double)this->Width() * m_nRatio)); + + if (m_pPanelA->MinSize.cx > m_pPanelA->Width() ) + { + m_pPanelA->right = m_pPanelA->left + m_pPanelA->MinSize.cx; + } + + m_pPanelB->left = m_pPanelA->right + m_nSplitterSize; + + if (m_pPanelB->MinSize.cx > m_pPanelB->Width() ) + { + m_pPanelB->left = m_pPanelB->right - m_pPanelB->MinSize.cx; + m_pPanelA->right = m_pPanelB->left - m_nSplitterSize; + } + } + + } + else /*if (m_Orientation == SPLIT_CONTAINER_V)*/ + { + if (Height() < MinSize.cy) + { + return; + } + + if (m_FixedPanel == 1 ) // top panel is fixed + { + m_pPanelB->top = m_pPanelA->bottom + m_nSplitterSize; + + if (m_pPanelB->MinSize.cy > m_pPanelB->Height() ) + { + m_pPanelB->top = m_pPanelB->bottom - m_pPanelB->MinSize.cy; + m_pPanelA->bottom = m_pPanelB->top - m_nSplitterSize; + } + } + else if (m_FixedPanel == 2 ) // bottom panel is fixed + { + m_pPanelA->bottom = m_pPanelB->top - m_nSplitterSize; + + if (m_pPanelA->MinSize.cy > m_pPanelA->Height() ) + { + m_pPanelA->bottom = m_pPanelA->top + m_pPanelA->MinSize.cy; + m_pPanelB->top = m_pPanelA->bottom + m_nSplitterSize; + } + } + else + { + m_pPanelA->bottom = (LONG) ((double)m_pPanelA->top + ((double)this->Height() * m_nRatio)); + + if (m_pPanelA->MinSize.cy > m_pPanelA->Height() ) + { + m_pPanelA->bottom = m_pPanelA->top + m_pPanelA->MinSize.cy; + } + + m_pPanelB->top = m_pPanelA->bottom + m_nSplitterSize; + + if (m_pPanelB->MinSize.cy > m_pPanelB->Height() ) + { + m_pPanelB->top = m_pPanelB->bottom - m_pPanelB->MinSize.cy; + m_pPanelA->bottom = m_pPanelB->top - m_nSplitterSize; + } + } + + + } + + GetSplitArea(m_pSplitter); + m_pPanelA->OnResized(); + m_pPanelB->OnResized(); + m_pSplitter->OnResized(); + +} +void CSplitContainer::SetSplitterPosition(int leftOfSplitter) +{ + + short nFixedPanel = m_FixedPanel; + m_FixedPanel = 0; + if (m_Orientation == SPLIT_CONTAINER_H ) + { + m_pPanelA->right = leftOfSplitter; + m_pPanelB->left = m_pPanelA->right + m_nSplitterSize; + } + else + { + m_pPanelA->bottom = leftOfSplitter; + m_pPanelB->top = m_pPanelA->bottom + m_nSplitterSize; + } + UpdateRatio(); + + OnResized(); + + UpdateRatio(); + m_FixedPanel = nFixedPanel; + +} +int CSplitContainer::GetSplitterPosition() +{ + if (m_Orientation == SPLIT_CONTAINER_H ) + { + return m_pPanelA->right; + } + else + { + return m_pPanelA->bottom; + } +} +BOOL CSplitContainer::AddChild(CPanel * prc) +{ + if (Children.GetCount() == 3) + { + return FALSE; + } + return CPanel::AddChild(prc); + +} +BOOL CSplitContainer::RemoveChild(CPanel * prc) +{ + return FALSE; // cannot remove child from split container +} + +void CSplitContainer::GetSplitArea(CRect * pSplitterPanel) +{ + + if (m_Orientation == SPLIT_CONTAINER_H) + { + pSplitterPanel->left = m_pPanelA->right; + pSplitterPanel->top = this->top; + pSplitterPanel->right = m_pPanelB->left; + pSplitterPanel->bottom = this->bottom; + } + else // vertical + { + pSplitterPanel->left = this->left; + pSplitterPanel->top = m_pPanelA->bottom; + pSplitterPanel->right = this->right; + pSplitterPanel->bottom = m_pPanelB->top; + } +} +int CSplitContainer::GetSplitterSize(CPanel * m_pPanelA, CPanel * m_pPanelB) +{ + if (m_Orientation == SPLIT_CONTAINER_H) + { + int nWidth = m_pPanelB->left - m_pPanelA->right; + return nWidth; + } + else // vertical + { + int nHeight = m_pPanelB->top - m_pPanelA->bottom; + return nHeight; + } +} + + + + +void CSplitContainer::UpdateRatio() +{ + + if (m_Orientation == SPLIT_CONTAINER_H ) + { + m_nRatio = (double)m_pPanelA->Width() / (double)this->Width(); + } + else + { + m_nRatio = (double)m_pPanelA->Height() / (double)this->Height(); + } + +} + +CSplitContainer * CSplitContainer::Create(CPanel * pPanelA, CPanel * pPanelB) +{ + CSplitPanel * pSplitPanelA = dynamic_cast( pPanelA ); + if (pSplitPanelA != NULL) + { + return NULL; // already a part of a CSplitContainer + } + + CSplitPanel * pSplitPanelB = dynamic_cast( pPanelB ); + if (pSplitPanelB != NULL) + { + return NULL; // already a part of a CSplitContainer + } + + CRect rcDest(0, 0, 0, 0); + SplitterOrientation orien = SPLIT_CONTAINER_H; + + if (::IntersectRect(&rcDest, pPanelA, pPanelB) == TRUE) // invalid spliter container, a spliter continer's two panel cannot intersect each other + { + return NULL; + } + + + if (pPanelA->right < pPanelB->left) + { + orien = SPLIT_CONTAINER_H; + } + else if (pPanelA->bottom < pPanelB->top) + { + orien = SPLIT_CONTAINER_V; + } + else + { + return NULL; + } + if (pPanelA->Parent != NULL) + { + if (pPanelA->Parent->RemoveChild( pPanelA ) == FALSE) + { + return NULL; + } + } + if (pPanelB->Parent != NULL) + { + if (pPanelB->Parent->RemoveChild( pPanelB ) == FALSE) + { + return NULL; + } + } + + pSplitPanelA = new CSplitPanel( pPanelA ); + pSplitPanelB = new CSplitPanel( pPanelB ); + + + CSplitContainer * pSpliter = new CSplitContainer(pSplitPanelA, pSplitPanelB, orien); + return pSpliter; + +} + +CString CSplitContainer::GetTypeName() +{ + return _T("CSplitContainer"); +} + +void CSplitContainer::SetFixedPanel(short nFixedPanel /* 1=left/top; 2=right/bototm; other=no fixed panel */) +{ + m_FixedPanel = nFixedPanel; +} +short CSplitContainer::GetFixedPanel() +{ + return m_FixedPanel; +} +void CSplitContainer::SetIsSplitterFixed(BOOL bFixed) +{ + m_IsSplitterFixed = bFixed; +} +BOOL CSplitContainer::GetIsSplitterFixed() +{ + return m_IsSplitterFixed; +} +void CSplitContainer::SetShowSplitterGrip(BOOL bShow) +{ + m_pSplitter->m_pGrippePanel->m_bVisible = bShow; +} +BOOL CSplitContainer::GetShowSplitterGrip() +{ + return m_pSplitter->m_pGrippePanel->m_bVisible; +} + + +///////////////////////////// CRootPanel +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +CRootPanel::CRootPanel() : CPanel() +{ + m_pHookWnd = NULL; +} +CRootPanel::~CRootPanel() +{ + +} +CWnd * CRootPanel::GetHookedWnd() +{ + return m_pHookWnd; +} +CString CRootPanel::GetTypeName() +{ + return _T("CRootPanel"); +} +///////////////////////////// CUIPanel +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +CUIPanel::CUIPanel(const CRect * prc, UINT uID) : CPanel(prc) +{ + m_uID = uID; + m_bOle = FALSE; +} +CUIPanel::~CUIPanel() +{ + +} +CString CUIPanel::GetTypeName() +{ + return _T("CUIPanel"); +} + +///////////////////////////// CVisualPanel +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +CVisualPanel::CVisualPanel() : CPanel() +{ + m_bVisible = FALSE; + m_rcPrev.SetRect(0, 0, 0, 0); +} +CVisualPanel::CVisualPanel(const CRect * prc) : CPanel(prc) +{ + m_bVisible = FALSE; + m_rcPrev.SetRect(this->left, this->top, this->right, this->bottom); +} +CVisualPanel::~CVisualPanel() +{ + + +} +void CVisualPanel::Draw(CDC * pDC) +{ + +} +CString CVisualPanel::GetTypeName() +{ + return _T("CVisualPanel"); +} +void CVisualPanel::OnResized() +{ + CWnd * pWnd = NULL; + if ((pWnd = GetHookedWnd()) != NULL) + { + pWnd->InvalidateRect( &m_rcPrev, FALSE ); + pWnd->InvalidateRect( this, FALSE ); + } + m_rcPrev.SetRect(this->left, this->top, this->right, this->bottom); +} + +///////////////////////////// CGripperPanel +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +enum SCROLLBARPARTS { + SBP_ARROWBTN = 1, + SBP_THUMBBTNHORZ = 2, + SBP_THUMBBTNVERT = 3, + SBP_LOWERTRACKHORZ = 4, + SBP_UPPERTRACKHORZ = 5, + SBP_LOWERTRACKVERT = 6, + SBP_UPPERTRACKVERT = 7, + SBP_GRIPPERHORZ = 8, + SBP_GRIPPERVERT = 9, + SBP_SIZEBOX = 10, +}; +CGripperPanel::CGripperPanel() : CVisualPanel() +{ + m_hTheme = NULL; + m_iPartId = SBP_SIZEBOX; + m_iStateId = 5; //SZB_HALFBOTTOMRIGHTALIGN; + m_sClassName = _T("SCROLLBAR"); +} +CGripperPanel::CGripperPanel(const CRect * prc) : CVisualPanel(prc) +{ + m_hTheme = NULL; + m_iPartId = SBP_SIZEBOX; + m_iStateId = 5; //SZB_HALFBOTTOMRIGHTALIGN; + m_sClassName = _T("SCROLLBAR"); +} +CGripperPanel::~CGripperPanel() +{ + if (m_hTheme != NULL) + { + HRESULT lres = ::CloseThemeData(m_hTheme); + ASSERT(SUCCEEDED(lres) == TRUE); + m_hTheme = NULL; + } +} +void CGripperPanel::Draw(CDC * pDC) +{ + if (m_hTheme == NULL) + { + CWnd * pHookedWnd = GetHookedWnd(); + if (pHookedWnd == NULL) + { + return; + } + m_hTheme = ::OpenThemeData(pHookedWnd->m_hWnd, m_sClassName.AllocSysString()); + } + + if (m_hTheme == NULL) + { + BOOL bOk = pDC->DrawFrameControl(this, DFC_SCROLL, DFCS_SCROLLSIZEGRIP ); + ASSERT( bOk ); + } + else + { + HRESULT lres = ::DrawThemeBackground(m_hTheme, pDC->m_hDC, m_iPartId, m_iStateId, this, this); + ASSERT(SUCCEEDED(lres) == TRUE); + } +} + +CString CGripperPanel::GetTypeName() +{ + return _T("CGripperPanel"); +} + +///////////////////////////// CSplitterGripperPanel +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +CSplitterGripperPanel::CSplitterGripperPanel(SplitterOrientation type) : CVisualPanel() +{ + m_OrienType = type; +} +CSplitterGripperPanel::~CSplitterGripperPanel() +{ + +} +void CSplitterGripperPanel::Draw(CDC * pDC) +{ + CPen penDark(PS_SOLID, 1, ::GetSysColor(COLOR_3DSHADOW)); + CPen penWhite(PS_SOLID, 1, RGB(255, 255, 255)); + + if (m_OrienType == SPLIT_CONTAINER_H ) + { + CPen * pOrigPen = pDC->SelectObject(&penWhite); + + CRect rc(0, 0, 0, 0); + rc.SetRect(left + 1, top + 1, left + 3, top + 3); + while(rc.bottom <= bottom) + { + pDC->Rectangle(&rc); + rc.OffsetRect(0, 4); + } + + pDC->SelectObject(&penDark); + rc.SetRect(left, top, left + 2, top + 2); + while(rc.bottom <= bottom) + { + pDC->Rectangle(&rc); + rc.OffsetRect(0, 4); + } + + pDC->SelectObject(pOrigPen); + + } + else + { + CPen * pOrigPen = pDC->SelectObject(&penWhite); + + CRect rc(0, 0, 0, 0); + rc.SetRect(left + 1, top + 1, left + 3, top + 3); + while(rc.right <= right) + { + pDC->Rectangle(&rc); + rc.OffsetRect(4, 0); + } + + pDC->SelectObject(&penDark); + rc.SetRect(left, top, left + 2, top + 2); + while(rc.right <= right) + { + pDC->Rectangle(&rc); + rc.OffsetRect(4, 0); + } + + pDC->SelectObject(pOrigPen); + } +} + +CString CSplitterGripperPanel::GetTypeName() +{ + return _T("CSplitterGripperPanel"); +} + + +///////////////////////////// CSpitterPanel +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +CSpitterPanel::CSpitterPanel(const CRect * prc, SplitterOrientation type) : CPanel(prc) +{ + m_OrienType = type; + m_pGrippePanel = NULL; + + if (m_pGrippePanel == NULL) + { + m_pGrippePanel = new CSplitterGripperPanel(type); + if (m_OrienType == SPLIT_CONTAINER_H ) + { + m_pGrippePanel->SetRect(0, 0, 3, 12); + } + else + { + m_pGrippePanel->SetRect(0, 0, 12, 3); + } + m_pGrippePanel->SetAnchor ( ANCHOR_HORIZONTALLY_CENTERED | ANCHOR_VERTICALLY_CENTERED ); + m_pGrippePanel->SetMinSize(CSize(2,2)); + BOOL bOk = AddChild(m_pGrippePanel); + ASSERT( bOk); + } +} +CSpitterPanel::CSpitterPanel(SplitterOrientation type) : CPanel() +{ + m_OrienType = type; + m_pGrippePanel = NULL; + +} + +CSpitterPanel::~CSpitterPanel() +{ + +} + + +CString CSpitterPanel::GetTypeName() +{ + return _T("CSpitterPanel"); +} +///////////////////////////// CSpitPanel +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +CSplitPanel::CSplitPanel(CPanel * pPanel) : CPanel(pPanel) +{ + pPanel->LeftOffset = 0; + pPanel->TopOffset = 0; + pPanel->RightOffset = 0; + pPanel->BottomOffset = 0; + pPanel->Anchor = ANCHOR_ALL; + Name = pPanel->Name; + pPanel->Name = _T(""); + m_pOriginalPanel = pPanel; + MaxSize = pPanel->MaxSize; + MinSize = pPanel->MinSize; + Children.AddTail( pPanel ); +} + +CSplitPanel::~CSplitPanel() +{ + +} + +BOOL CSplitPanel::SetAnchor(UINT anchor) +{ + return FALSE; +} + +BOOL CSplitPanel::AddChild(CPanel * prc) +{ + return m_pOriginalPanel->AddChild(prc); +} +BOOL CSplitPanel::RemoveChild(CPanel * prc) +{ + return m_pOriginalPanel->RemoveChild(prc); +} + + +CString CSplitPanel::GetTypeName() +{ + return _T("CSplitPanel"); +} + +///////////////////////////// CFlowLayoutPanel +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +CFlowLayoutPanel::CFlowLayoutPanel() : CPanel() +{ + m_nItemSpacingX = 0; + m_nItemSpacingY = 0; + m_nFlowDirection = LEFT_TO_RIGHT; +} +CFlowLayoutPanel::CFlowLayoutPanel(const CRect * prc) : CPanel(prc) +{ + m_nItemSpacingX = 0; + m_nItemSpacingY = 0; + m_nFlowDirection = LEFT_TO_RIGHT; +} +CFlowLayoutPanel::~CFlowLayoutPanel() +{ + +} +void CFlowLayoutPanel::OnResized() +{ + int max = 0; // maximimum height of a item in the row in case of left-to-right, otherwise maximum width of a item + int x = left; + int y = top; + POSITION pos = Children.GetHeadPosition(); + + // first one will be at the top-left corner, no matter what + if (pos != NULL) + { + CPanel * pPanel = Children.GetNext(pos); + pPanel->MoveToXY(x, y); + pPanel->OnResized(); + + if (m_nFlowDirection == LEFT_TO_RIGHT) + { + x += pPanel->Width() + m_nItemSpacingX; + max = (pPanel->Height() > max ? pPanel->Height() : max); + } + else + { + y += pPanel->Height() + m_nItemSpacingY; + max = (pPanel->Width() > max ? pPanel->Width() : max); + } + } + + + if (m_nFlowDirection == LEFT_TO_RIGHT) + { + while(pos != NULL) + { + CPanel * pPanel = Children.GetNext(pos); + // check to see if it is to wrap + if (x + pPanel->Width() > right) + { + x = left; + y += (max + m_nItemSpacingY); + max = 0; + } + + pPanel->MoveToXY(x, y); + pPanel->OnResized(); + + x += pPanel->Width() + m_nItemSpacingX; + max = (pPanel->Height() > max ? pPanel->Height() : max); + } + } + else + { + while(pos != NULL) + { + CPanel * pPanel = Children.GetNext(pos); + // check to see if it is to wrap + if (y + pPanel->Height() > bottom) + { + x += (max + m_nItemSpacingX); + y = top; + max = 0; + } + + pPanel->MoveToXY(x, y); + pPanel->OnResized(); + + y += pPanel->Height() + m_nItemSpacingY; + max = (pPanel->Width() > max ? pPanel->Width() : max); + } + + } +} +CString CFlowLayoutPanel::GetTypeName() +{ + return _T("CFlowLayoutPanel"); + +} +void CFlowLayoutPanel::SetFlowDirection(FlowDirection direction) +{ + m_nFlowDirection = direction; +} +FlowDirection CFlowLayoutPanel::GetFlowDirection() +{ + return m_nFlowDirection; +} +void CFlowLayoutPanel::SetItemSpacingX(int nSpace) +{ + m_nItemSpacingX = nSpace; +} +int CFlowLayoutPanel::GetItemSpacingX() +{ + return m_nItemSpacingX; +} +void CFlowLayoutPanel::SetItemSpacingY(int nSpace) +{ + m_nItemSpacingY = nSpace; +} +int CFlowLayoutPanel::GetItemSpacingY() +{ + return m_nItemSpacingY; +} + diff --git a/app/net_tools/ui/WndResizer.h b/app/net_tools/ui/WndResizer.h new file mode 100644 index 000000000..c4e4a00bd --- /dev/null +++ b/app/net_tools/ui/WndResizer.h @@ -0,0 +1,350 @@ +/* +DISCLAIMER + +Auther: Mizan Rahman +Original publication location: http://www.codeproject.com/KB/dialog/WndResizer.aspx + +This work is provided under the terms and condition described in The Code Project Open License (CPOL) +(http://www.codeproject.com/info/cpol10.aspx) + +This disclaimer should not be removed and should exist in any reproduction of this work. +*/ + +#pragma once +#include + + +#define ANCHOR_LEFT 1 +#define ANCHOR_TOP 2 +#define ANCHOR_RIGHT 4 +#define ANCHOR_BOTTOM 8 +#define ANCHOR_HORIZONTALLY_CENTERED 16 +#define ANCHOR_VERTICALLY_CENTERED 32 +#define ANCHOR_PRIORITY_RIGHT 64 // by defualt, left has higher priority +#define ANCHOR_PRIORITY_BOTTOM 128 // by defualt, top has higher priority +#define ANCHOR_VERTICALLY (ANCHOR_TOP | ANCHOR_BOTTOM) +#define ANCHOR_HORIZONTALLY (ANCHOR_LEFT | ANCHOR_RIGHT) +#define ANCHOR_ALL (ANCHOR_VERTICALLY | ANCHOR_HORIZONTALLY) + +#define DOCK_NONE 0 +#define DOCK_LEFT 1 +#define DOCK_TOP 2 +#define DOCK_RIGHT 3 +#define DOCK_BOTTOM 4 +#define DOCK_FILL 5 + +class CPanel; + +typedef CList CPanelList; + +typedef enum tagSplitterOrientation +{ + // a horizontal splitter container panel + SPLIT_CONTAINER_H = 1, + // a vertical splitter contianer panel + SPLIT_CONTAINER_V = 2, + +} SplitterOrientation; + +typedef enum tagFlowDirection +{ + // left to right flow direction + LEFT_TO_RIGHT = 3, + // top to bottom flow direction + TOP_TO_BOTTOM = 4, + +} FlowDirection; + +class CPanel : public CRect +{ +public: + CPanel(); + CPanel(const CRect * prc); + virtual ~CPanel(); + UINT Anchor; + UINT Dock; + CString Name; + CPanel * Parent; + CPanelList Children; + int LeftOffset; + int TopOffset; + int RightOffset; + int BottomOffset; + CSize MinSize; + CSize MaxSize; + virtual void OnResized(); + virtual BOOL AddChild(CPanel * prc); + virtual BOOL RemoveChild(CPanel * prc); + virtual BOOL SetAnchor(UINT anchor); + virtual BOOL SetMinSize(CSize & size); + virtual BOOL SetMaxSize(CSize & size); + virtual CString ToString(); + virtual CString GetTypeName(); + virtual CWnd * GetHookedWnd(); +private: + void Init(); +}; + +class CRootPanel : public CPanel +{ +public: + CRootPanel(); + ~CRootPanel(); + virtual CWnd * GetHookedWnd(); + CWnd * m_pHookWnd; + virtual CString GetTypeName(); +}; + +class CUIPanel : public CPanel +{ +public: + CUIPanel(const CRect * prc, UINT uID); + ~CUIPanel(); + UINT m_uID; // could be a resource ID or a HWND + BOOL m_bOle; // TRUE= m_uID is an ID of an ActiveX or OLE control, FALSE=regular windows control + virtual CString GetTypeName(); +}; + + +class CVisualPanel : public CPanel +{ +public: + CVisualPanel(); + CVisualPanel(const CRect * prc); + ~CVisualPanel(); + virtual void Draw(CDC * pDC); + BOOL m_bVisible; + virtual CString GetTypeName(); + virtual void OnResized(); +private: + CRect m_rcPrev; +}; + +class CGripperPanel : public CVisualPanel +{ +public: + CGripperPanel(); + CGripperPanel(const CRect * prc); + ~CGripperPanel(); + virtual void Draw(CDC * pDC); + virtual CString GetTypeName(); +private: + HTHEME m_hTheme; + int m_iPartId; + int m_iStateId; + CString m_sClassName; +}; + +class CSplitterGripperPanel : public CVisualPanel +{ +public: + CSplitterGripperPanel(SplitterOrientation type); + ~CSplitterGripperPanel(); + virtual void Draw(CDC * pDC); + virtual CString GetTypeName(); +private: + SplitterOrientation m_OrienType; +}; + +class CSplitPanel : public CPanel +{ +public: + CSplitPanel(CPanel * pPanel); + ~CSplitPanel(); + virtual BOOL SetAnchor(UINT anchor); + virtual BOOL AddChild(CPanel * prc); + virtual BOOL RemoveChild(CPanel * prc); + virtual CString GetTypeName(); +private: + CPanel * m_pOriginalPanel; +}; + + +class CSpitterPanel : public CPanel +{ +public: + CSpitterPanel(SplitterOrientation type); + CSpitterPanel(const CRect * prc, SplitterOrientation type); + ~CSpitterPanel(); + virtual CString GetTypeName(); + CSplitterGripperPanel * m_pGrippePanel; +private: + SplitterOrientation m_OrienType; +}; + + +class CSplitContainer : public CPanel +{ +public: + CSplitContainer(CSplitPanel * pPanelA, CSplitPanel * pPanelB, SplitterOrientation type); + ~CSplitContainer(); + virtual void OnResized(); + virtual BOOL AddChild(CPanel * prc); + virtual BOOL RemoveChild(CPanel * prc); + virtual CString GetTypeName(); + void SetSplitterPosition(int leftOfSpliter /* or topOfSpliter if vertical */); + int GetSplitterPosition(); + void SetFixedPanel(short nFixedPanel /* 1=left or top; 2=right or bototm; other=no fixed panel */); + short GetFixedPanel(); + void SetIsSplitterFixed(BOOL bFixed); + BOOL GetIsSplitterFixed(); + void SetShowSplitterGrip(BOOL bShow); + BOOL GetShowSplitterGrip(); + + static CSplitContainer * Create(CPanel * pPanelA, CPanel * pPanelB); + + SplitterOrientation m_Orientation; +private: + BOOL m_IsSplitterFixed; + short m_FixedPanel; // 1=left or top panel; 2=right or bottom panel, otherwise no fixed panel + + double m_nRatio; + int m_nSplitterSize; // for horizontal, it is the splitter width, otherwise it is the splitter height + void GetSplitArea(CRect * pSplitterPanel); + int GetSplitterSize(CPanel * pLeftPanel, CPanel * pRightPanel); + void UpdateRatio(); + + CSplitPanel * m_pPanelA; + CSplitPanel * m_pPanelB; + CSpitterPanel * m_pSplitter; +}; + +class CFlowLayoutPanel : public CPanel +{ +public: + CFlowLayoutPanel(); + CFlowLayoutPanel(const CRect * prc); + ~CFlowLayoutPanel(); + virtual void OnResized(); + virtual CString GetTypeName(); + void SetFlowDirection(FlowDirection direction); + FlowDirection GetFlowDirection(); + void SetItemSpacingX(int nSpace); + int GetItemSpacingX(); + void SetItemSpacingY(int nSpace); + int GetItemSpacingY(); + +private: + int m_nItemSpacingX; + int m_nItemSpacingY; + FlowDirection m_nFlowDirection; +}; + +class CWndResizer +{ +public: + CWndResizer(void); + ~CWndResizer(void); +private: + +public: + BOOL SetAnchor(LPCTSTR panelName, UINT anchor); + BOOL SetAnchor(UINT panelID, UINT anchor); + BOOL GetAnchor(LPCTSTR panelName, UINT & anchor); + BOOL GetAnchor(UINT panelID, UINT & anchor); + + + BOOL SetDock(LPCTSTR panelName, UINT anchor); + BOOL SetDock(UINT panelID, UINT anchor); + BOOL GetDock(LPCTSTR panelName, UINT & anchor); + BOOL GetDock(UINT panelID, UINT & anchor); + + BOOL SetFixedPanel(LPCTSTR splitContainerName, short panel); + BOOL GetFixedPanel(LPCTSTR splitContainerName, short & panel); + + BOOL SetIsSplitterFixed(LPCTSTR splitContainerName, BOOL fixed); + BOOL GetIsSplitterFixed(LPCTSTR splitContainerName, BOOL &fixed); + + BOOL SetFlowDirection(LPCTSTR flowPanelName, short direction); + BOOL GetFlowDirection(LPCTSTR flowPanelName, short &direction); + + BOOL SetFlowItemSpacingX(LPCTSTR flowPanelName, int nSpacing); + BOOL GetFlowItemSpacingX(LPCTSTR flowPanelName, int &nSpacing); + + BOOL SetFlowItemSpacingY(LPCTSTR flowPanelName, int nSpacing); + BOOL GetFlowItemSpacingY(LPCTSTR flowPanelName, int &nSpacing); + + + BOOL SetShowSplitterGrip(LPCTSTR splitContainerName, BOOL bShow); + BOOL GetShowSplitterGrip(LPCTSTR splitContainerName, BOOL & bShow); + + BOOL SetParent(LPCTSTR panelName, LPCTSTR parentName); + BOOL SetParent(UINT panelID, LPCTSTR parentName); + BOOL SetParent(LPCTSTR panelName, UINT parentID); + BOOL SetParent(UINT panelID, UINT parentID); + BOOL GetParent(LPCTSTR panelName, CString & parentName); + BOOL GetParent(UINT panelID, CString & parentName); + + BOOL SetMinimumSize(LPCTSTR panelName, CSize & size); + BOOL SetMinimumSize(UINT panelID, CSize & size); + BOOL GetMinimumSize(LPCTSTR panelName, CSize & size) ; + BOOL GetMinimumSize(UINT panelID, CSize & size) ; + + BOOL SetMaximumSize(LPCTSTR panelName, CSize & size); + BOOL SetMaximumSize(UINT panelID, CSize & size); + BOOL GetMaximumSize(LPCTSTR panelName, CSize & size) ; + BOOL GetMaximumSize(UINT panelID, CSize & size) ; + + void SetShowResizeGrip(BOOL show = TRUE); + BOOL GetShowResizeGrip(); + BOOL Hook(CWnd * pWnd); + BOOL Hook(CWnd * pWnd, CSize & size); + BOOL Unhook(); + + BOOL CreateFlowLayoutPanel(LPCTSTR panelName, const CRect * prcPanel); + BOOL CreateFlowLayoutPanel(LPCTSTR panelName, const CUIntArray * parrID, BOOL setAsChildren = FALSE); + + BOOL CreatePanel(LPCTSTR panelName, const CRect * prcPanel); + BOOL CreatePanel(LPCTSTR panelName, const CUIntArray * parrID, BOOL setAsChildren = FALSE); + + BOOL CreatePanel(UINT uID); + + BOOL CreateSplitContainer(LPCTSTR splitContainerName, LPCTSTR panelNameA, LPCTSTR panelNameB); + BOOL CreateSplitContainer(LPCTSTR splitContainerName, LPCTSTR panelNameA, UINT panelIDB); + BOOL CreateSplitContainer(LPCTSTR splitContainerName, UINT panelIDA, UINT panelIDB); + BOOL CreateSplitContainer(LPCTSTR splitContainerName, UINT panelIDA, LPCTSTR panelNameB); + + // useful for persisting UI layout + BOOL SetSplitterPosition(LPCTSTR splitContainerName, UINT position); + BOOL GetSplitterPosition(LPCTSTR splitContainerName, UINT & position); + + BOOL InvokeOnResized(); + + CString GetDebugInfo(); + +private: + + CWnd * m_pHookedWnd; + CRootPanel root; + CPanel * m_pCaptured; + HCURSOR m_hOldCursor; + int m_splitterOffset; + + void OnPaint(); + void OnSize(UINT nType, int cx, int cy); + void OnSizing(UINT fwSide, LPRECT pRect); + void OnScroll(); + void OnDestroy(); + void OnLButtonDown(UINT nFlags, CPoint point); + void OnMouseMove(UINT nFlags, CPoint point); + void OnLButtonUp(UINT nFlags, CPoint point); + + CWndResizer::CPanel * FindPanelByName(CPanel * pRoot, LPCTSTR name); + CWndResizer::CPanel * FindSplitterFromPoint(CPanel * pRoot, CPoint point); + void GetUIPanels(CPanel * pRoot, CPanelList * pList, BOOL bOle); + void GetVisualPanels(CPanel * pRoot, CPanelList * pList); + + void ResizeUI(CPanel * pRoot); + + CString IdToName(UINT uID); + CWndResizer::CUIPanel * CreateUIPanel(UINT uID); + CWndResizer::CUIPanel * GetUIPanel(UINT uID); + + void UpdateSplitterOffset(CPoint ptCurr); + void GetDebugInfo(CPanel * pRoot, CString & info, CString indent); + void GetTrueClientRect(CWnd * pWnd, CRect * prc); + void EnsureRootMinMax(); + + WNDPROC m_pfnWndProc; + static LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); +}; diff --git a/app/net_tools/upload/upload.cpp b/app/net_tools/upload/upload.cpp new file mode 100644 index 000000000..448e4de4d --- /dev/null +++ b/app/net_tools/upload/upload.cpp @@ -0,0 +1,322 @@ +#include "StdAfx.h" +#include "global/global.h" +#include "global/util.h" +#include "mail/mime_builder.hpp" +#include "upload.h" + +upload::upload() +: callback_(NULL) +{ + memset(&meter_, 0, sizeof(meter_)); +} + +upload::~upload() +{ + //if (!mailpath_.empty()) + // _unlink(mailpath_.c_str()); +} + +upload& upload::set_callback(upload_callback* c) +{ + callback_ = c; + return *this; +} + +upload& upload::add_file(const char* p) +{ + files_.push_back(p); + return *this; +} + +upload& upload::set_server(const char* addr, int port) +{ + smtp_addr_ = addr; + smtp_port_ = port; + return *this; +} + +upload& upload::set_conn_timeout(int n) +{ + connect_timeout_ = n; + return *this; +} + +upload& upload::set_rw_timeout(int n) +{ + rw_timeout_ = n; + return *this; +} + +upload& upload::set_account(const char* s) +{ + auth_account_ = s; + return *this; +} + +upload& upload::set_passwd(const char* s) +{ + auth_passwd_ = s; + return *this; +} + +upload& upload::set_from(const char* s) +{ + mail_from_ = s; + return *this; +} + +upload& upload::add_to(const char* s) +{ + ACL_ARGV* tokens = acl_argv_split(s, ";,,; \t\r\n"); + ACL_ITER iter; + + acl_foreach(iter, tokens) + { + const char* to = (const char*) iter.data; + recipients_.push_back(to); + } + + acl_argv_free(tokens); + + return *this; +} + +upload& upload::set_subject(const char* s) +{ + acl::string buf; + //acl::charset_conv conv; + //if (conv.convert("gbk", "utf-8", s, strlen(s), &buf) == false) + // logger_error("convert from gbk to utf-8 failed"); + //else + //{ + // acl::string buf2; + // conv.convert("utf-8", "gbk", buf.c_str(), + // (int) buf.length(), &buf2); + // printf(">>>buf: %s, buf2: %s\r\n", buf.c_str(), buf2.c_str()); + //} + buf = s; + acl::rfc2047::encode(s, (int) buf.length(), &subject_, "gbk", 'B', false); + return *this; +} + +////////////////////////////////////////////////////////////////////////// + +struct UP_CTX +{ + acl::string msg; + size_t total; + size_t curr; +}; + +////////////////////////////////////////////////////////////////////////// +// 主线程中运行 + +void upload::rpc_onover() +{ + delete this; +} + +void upload::rpc_wakeup(void* ctx) +{ + UP_CTX* up = (UP_CTX*) ctx; + + callback_->upload_report(up->msg.c_str(), + up->total, up->curr, meter_); + delete up; +} + +////////////////////////////////////////////////////////////////////////// +// 子线程中运行 + +void upload::rpc_run() +{ + // 创建邮件内容 + + mime_builder builer; + builer.primary_header() + .set_from(mail_from_.c_str()) + .set_sender(mail_from_.c_str()); + + std::list::const_iterator cit1 = recipients_.begin(); + for (; cit1 != recipients_.end(); ++cit1) + builer.primary_header().add_to((*cit1).c_str()); + builer.primary_header().set_subject(subject_.c_str()); + + acl::string body_text("test"); + builer.set_body_text(body_text.c_str(), body_text.length()); + std::vector::const_iterator cit = files_.begin(); + for (; cit != files_.end(); ++cit) + builer.add_file((*cit).c_str()); + + mailpath_.format("%s/%ld.eml", global::get_instance().get_path(), + time(NULL)); + if (builer.save_as(mailpath_.c_str()) == false) + { + logger_error("build email(%s) error(%s)", + mailpath_.c_str(), acl::last_serror()); + mailpath_.clear(); + return; + } + + acl::ifstream in; + if (in.open_read(mailpath_.c_str()) == false) + { + logger_error("open %s error %s", mailpath_.c_str(), + acl::last_serror()); + mailpath_.clear(); + return; + } + ////////////////////////////////////////////////////////////////////////// + // 远程连接 SMTP 服务器,将本地创建的邮件发送出去 + UP_CTX* up = new UP_CTX; + up->curr = 0; + up->total = (size_t) in.fsize(); + up->msg.format("连接 SMTP 服务器 ..."); + rpc_signal(up); + + acl::string smtp_addr; + smtp_addr.format("%s:%d", smtp_addr_.c_str(), smtp_port_); + + struct timeval begin, last, now; + gettimeofday(&begin, NULL); + gettimeofday(&last, NULL); + + SMTP_CLIENT* conn = smtp_open(smtp_addr.c_str(), connect_timeout_, + rw_timeout_, 1024); + if (conn == NULL) + { + logger_error("connect smtp server(%s) error", smtp_addr); + return; + } + + gettimeofday(&now, NULL); + meter_.connect_cost = util::stamp_sub(&now, &last); + + up = new UP_CTX; + up->curr = 0; + up->total = (size_t) in.fsize(); + up->msg.format("接收 SMTP 服务器欢迎信息(连接耗时 %.2f 毫秒) ...", + meter_.connect_cost); + rpc_signal(up); + + if (smtp_get_banner(conn) != 0) + { + logger_error("get smtpd banner error"); + smtp_close(conn); + return; + } + else if (smtp_greet(conn, "localhost", 1) != 0) + { + logger_error("send EHLO error(%d:%s) to server %s", + conn->smtp_code, conn->buf, smtp_addr.c_str()); + smtp_close(conn); + return; + } + + up = new UP_CTX; + up->curr = 0; + up->total = (size_t) in.fsize(); + up->msg.format("认证用户身份 ..."); + rpc_signal(up); + + gettimeofday(&last, NULL); + + if (smtp_auth(conn, auth_account_.c_str(), + auth_passwd_.c_str()) != 0) + { + logger_error("smtp auth error(%d:%s) from server(%s), " + "account: %s, passwd: %s", conn->smtp_code, conn->buf, + smtp_addr.c_str(), auth_account_.c_str(), + auth_passwd_.c_str()); + smtp_close(conn); + return; + } + + gettimeofday(&now, NULL); + meter_.auth_cost = util::stamp_sub(&now, &last); + + up = new UP_CTX; + up->curr = 0; + up->total = (size_t) in.fsize(); + up->msg.format("发送邮件信封(认证耗时 %.2f 毫秒) ...", meter_.auth_cost); + rpc_signal(up); + + if (smtp_mail(conn, mail_from_.c_str()) != 0) + { + logger_error("smtp MAIL FROM error(%d:%s), from: %s, server: %s", + mail_from_.c_str(), conn->smtp_code, + conn->buf, smtp_addr.c_str()); + smtp_close(conn); + return; + } + + std::list::const_iterator cit2 = recipients_.begin(); + for (; cit2 != recipients_.end(); ++cit2) + { + if (smtp_rcpt(conn, (*cit2).c_str()) != 0) + { + logger_error("smtp RCPT TO error(%d:%s), to: %s, server: %s", + conn->smtp_code, conn->buf, (*cit2).c_str(), + smtp_addr.c_str()); + smtp_close(conn); + return; + } + } + + gettimeofday(&last, NULL); + + if (smtp_data(conn) != 0) + { + logger_error("smtp DATA to server %s error(%d:%s)", + smtp_addr.c_str(), conn->smtp_code, conn->buf); + smtp_close(conn); + return; + } + gettimeofday(&now, NULL); + meter_.envelope_cost = util::stamp_sub(&now, &last); + + // 发送邮件内容 + + char buf[8192]; + int ret; + int n = 0; + + while (!in.eof()) + { + ret = in.read(buf, sizeof(buf), false); + if (ret == -1) + break; + if (acl_vstream_writen(conn->conn, buf, ret) == ACL_VSTREAM_EOF) + { + logger_error("smtp send data to server %s error(%d:%s)", + smtp_addr.c_str(), conn->smtp_code, conn->buf); + smtp_close(conn); + return; + } + n += ret; + up = new UP_CTX; + up->curr = n; + up->total = (size_t) in.fsize(); + up->msg.format("发送邮件中(%d/%d 字节) ...", up->curr, up->total); + rpc_signal(up); + } + + /* 发送 \r\n.\r\n 表示邮件数据发送完毕 */ + if (smtp_data_end(conn) != 0) + { + logger_error("send . error: %s, code: %d\r\n", + conn->buf, conn->smtp_code); + smtp_close(conn); + } + + gettimeofday(&now, NULL); + meter_.data_cost = util::stamp_sub(&now, &last); + meter_.total_cost = util::stamp_sub(&now, &begin); + + up = new UP_CTX; + up->curr = (size_t) in.fsize(); + up->total = (size_t) in.fsize(); + up->msg.format("发送邮件成功!(%d/%d 字节, 耗时 %.2f 毫秒)", + up->curr, up->total, meter_.total_cost); + rpc_signal(up); +} \ No newline at end of file diff --git a/app/net_tools/upload/upload.h b/app/net_tools/upload/upload.h new file mode 100644 index 000000000..65b538d13 --- /dev/null +++ b/app/net_tools/upload/upload.h @@ -0,0 +1,72 @@ +#pragma once + +////////////////////////////////////////////////////////////////////////// + +struct UPLOAD_METER +{ + double nslookup_cost; + double connect_cost; + double envelope_cost; + double auth_cost; + double data_cost; + double total_cost; +}; + +////////////////////////////////////////////////////////////////////////// + +class upload_callback +{ +public: + upload_callback() {} + virtual ~upload_callback() {} + + virtual void upload_report(const char* msg, size_t total, + size_t curr, const UPLOAD_METER& meter) = 0; +protected: +private: +}; + +////////////////////////////////////////////////////////////////////////// + +class upload : public acl::rpc_request +{ +public: + upload(); + upload& set_callback(upload_callback*); + upload& add_file(const char*); + upload& set_server(const char*, int); + upload& set_conn_timeout(int); + upload& set_rw_timeout(int); + upload& set_from(const char*); + upload& set_account(const char*); + upload& set_passwd(const char*); + upload& set_subject(const char*); + upload& add_to(const char*); +protected: + ~upload(); + + // 基类虚函数:子线程处理函数 + virtual void rpc_run(); + + // 基类虚函数:主线程处理过程,收到子线程任务完成的消息 + virtual void rpc_onover(); + + // 基类虚函数:主线程处理过程,收到子线程的通知消息 + virtual void rpc_wakeup(void* ctx); +private: + upload_callback* callback_; + std::vector files_; + acl::string smtp_addr_; + int smtp_port_; + int connect_timeout_; + int rw_timeout_; + acl::string auth_account_; + acl::string auth_passwd_; + acl::string mail_from_; + std::list recipients_; + acl::string subject_; + acl::string mailpath_; +private: + UPLOAD_METER meter_; +}; +////////////////////////////////////////////////////////////////////////// diff --git a/app/wizard/Makefile b/app/wizard/Makefile new file mode 100644 index 000000000..c28f8d1e3 --- /dev/null +++ b/app/wizard/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = wizard diff --git a/app/wizard/changes.txt b/app/wizard/changes.txt new file mode 100644 index 000000000..8f3ca00ff --- /dev/null +++ b/app/wizard/changes.txt @@ -0,0 +1,4 @@ +2) 2013.7.24 +2.1) feature: 鏀寔鍒涘缓鐢 vc2012 宸ョ▼绠$悊鐨 master_server 椤圭洰 +1) 2013.1.24 +1.1) 鍒涘缓 master server 绋嬪簭鏃讹紝鍏佽鐢ㄦ埛杈撳叆鑷繁鐨勭▼搴忓悕 diff --git a/app/wizard/file_copy.cpp b/app/wizard/file_copy.cpp new file mode 100644 index 000000000..c31286a46 --- /dev/null +++ b/app/wizard/file_copy.cpp @@ -0,0 +1,66 @@ +#include "stdafx.h" +#include "file_copy.h" + +bool file_copy(const char* from, const char* to) +{ + if (strcasecmp(from, to) == 0) + { + printf("from(%s) == to(%s)\r\n", from, to); + return false; + } + + ifstream in; + if (in.open_read(from) == false) + { + printf("open %s error: %s\r\n", from, last_serror()); + return false; + } + + ofstream out; + if (out.open_write(to) == false) + { + printf("open %s error: %s\r\n", from, last_serror()); + return false; + } + + string buf; + + while (!in.eof()) + { + if (in.gets(buf, false) == false) + break; + if (out.write(buf) < 0) + { + printf("write to %s error: %s\r\n", to, last_serror()); + return false; + } + } + + printf("create %s ok\r\n", to); + return true; +} + +bool files_copy(const char* name, const FILE_FROM_TO* tab, + const char* from_path, const char* to_path) +{ + string from, to; + + from = "tmpl/Makefile.in"; + to.format("%s/Makefile.in", to_path); + if (file_copy(from.c_str(), to.c_str()) == false) + return false; + + for (size_t i = 0; tab[i].from != NULL; i++) + { + from.format("%s/%s", from_path, tab[i].from); + to.format("%s/%s", to_path, tab[i].to); + if (file_copy(from, to) == false) + { + printf("create %s failed!\r\n", name); + return false; + } + } + + printf("create %s ok!\r\n", name); + return true; +} diff --git a/app/wizard/file_copy.h b/app/wizard/file_copy.h new file mode 100644 index 000000000..62fd1400d --- /dev/null +++ b/app/wizard/file_copy.h @@ -0,0 +1,11 @@ +#pragma once + +struct FILE_FROM_TO +{ + const char* from; + const char* to; +}; + +bool file_copy(const char* from, const char* to); +bool files_copy(const char* name, const FILE_FROM_TO* tab, + const char* from_path, const char* to_path); diff --git a/app/wizard/http_creator.cpp b/app/wizard/http_creator.cpp new file mode 100644 index 000000000..385c0e7ee --- /dev/null +++ b/app/wizard/http_creator.cpp @@ -0,0 +1,151 @@ +#include "stdafx.h" +#include "file_copy.h" +#include "http_creator.h" + +static const char* src_path_ = "tmpl/http"; +static const char* dst_path_ = "http_demo"; + +////////////////////////////////////////////////////////////////////////// + +static void set_charset(tpl_t* tpl) +{ + const char* charset; + printf("select charset: 1: utf-8; 2: gb2312; 3: gbk; 4: gb18030; 5: big5 ?[1]"); + fflush(stdout); + + int ch = getchar(); + switch (ch) + { + case '2': + charset = "gb2312"; + break; + case '3': + charset = "gbk"; + break; + case '4': + charset = "gb18030"; + break; + case '5': + charset = "big5"; + break; + case '1': + default: + charset = "utf-8"; + break; + } + + tpl_set_field_fmt_global(tpl, "CHARSET", "%s", charset); +} + +static void set_memcached(tpl_t* tpl) +{ + printf("Please enter memcached addr[127.0.0.1:11211]: "); + fflush(stdout); + + char buf[256]; + int n = acl_vstream_gets_nonl(ACL_VSTREAM_IN, buf, sizeof(buf)); + if (n == ACL_VSTREAM_EOF || n == 0) + snprintf(buf, sizeof(buf), "127.0.0.1:11211"); + tpl_set_field_fmt_global(tpl, "MEMCACHED_ADDR", "%s", buf); +} + +static bool set_cookies(tpl_t* tpl) +{ + printf("Please enter cookie name: "); fflush(stdout); + char line[256]; + int n = acl_vstream_gets_nonl(ACL_VSTREAM_IN, line, sizeof(line)); + if (n == ACL_VSTREAM_EOF) + { + printf("enter cookie name error!\r\n"); + return false; + } + + string buf; + buf.format("const char* %s = req.getCookieValue(\"%s\");\r\n", line, line); + buf.format_append("\tif (%s == NULL)\r\n\t\tres.addCookie(\"%s\", \"{xxx}\");", line, line); + + tpl_set_field_fmt_global(tpl, "GET_COOKIES", "%s", buf.c_str()); + return true; +} + +static tpl_t* open_tpl(const char* filename) +{ + tpl_t* tpl = tpl_alloc(); + string filepath; + filepath.format("%s/%s", src_path_, filename); + if (tpl_load(tpl, filepath.c_str()) != TPL_OK) + { + printf("load file %s error: %s\r\n", + filepath.c_str(), last_serror()); + tpl_free(tpl); + return NULL; + } + return tpl; +} + +////////////////////////////////////////////////////////////////////////// + +static bool create_http_request() +{ + return true; +} + +static bool create_http_response() +{ + return true; +} + +static bool create_http_servlet() +{ + tpl_t* tpl = open_tpl("http_servlet.cpp"); + if (tpl == NULL) + return false; + + set_charset(tpl); + set_memcached(tpl); + + printf("Do you want add cookie? y[y/n]: "); fflush(stdout); + int ch = getchar(); + if (ch != 'n') + set_cookies(tpl); + + string filepath; + filepath.format("%s/http_servlet.cpp", dst_path_); + if (tpl_save_as(tpl, filepath.c_str()) != TPL_OK) + { + printf("save to %s error: %s\r\n", filepath.c_str(), + last_serror()); + tpl_free(tpl); + return false; + } + + printf("create %s ok.\r\n", filepath.c_str()); + tpl_free(tpl); + return true; +} + +void http_creator() +{ + acl_make_dirs(dst_path_, 0700); + + while (true) + { + printf("please choose one http application type:\r\n"); + printf("c: for http request; r: for http response; s: http servlet\r\n"); + printf(">"); fflush(stdout); + + char buf[256]; + int n = acl_vstream_gets_nonl(ACL_VSTREAM_IN, buf, sizeof(buf)); + if (n == ACL_VSTREAM_EOF) + break; + else if (strcasecmp(buf, "c") == 0) + create_http_request(); + else if (strcasecmp(buf, "r") == 0) + create_http_response(); + else if (strcasecmp(buf, "s") == 0) + create_http_servlet(); + else + printf("unknown flag: %s\r\n", buf); + break; + } +} diff --git a/app/wizard/http_creator.h b/app/wizard/http_creator.h new file mode 100644 index 000000000..67497e457 --- /dev/null +++ b/app/wizard/http_creator.h @@ -0,0 +1,3 @@ +#pragma once + +void http_creator(); diff --git a/app/wizard/lib_tpl.h b/app/wizard/lib_tpl.h new file mode 100644 index 000000000..21e980423 --- /dev/null +++ b/app/wizard/lib_tpl.h @@ -0,0 +1,257 @@ +/* + * tpllib + * + * C library of functions for text template processing. + * Copyright (C) 2003-2007 Niels Wojciech Tadeusz Andersen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __C_TEMPLATE_ENGINE_H__ +#define __C_TEMPLATE_ENGINE_H__ + +#include "lib_acl.h" + +/* + * Markup: + * Field: @@SOMETHING@@ + * Section: + * Content of section + * perhaps with some @@FIELD@@ + * + * + * Sections can be nested to any depth. + */ + +#define DELIMITER_LEFT "$<" +#define DELIMITER_RIGHT ">" +#define SECTIONTAG_HEAD "" + +/* The object, holding template data */ +typedef struct template_s tpl_t; + + +#if defined(__cplusplus) +extern "C" { +#endif + +/* Allocates and initializes new template object */ +tpl_t* tpl_alloc(void); + +/* Releases a template object allocated with tpl_alloc() */ +void tpl_free(tpl_t* tpl); + +/* + * Copy the original template into the clone template + * The clone parameter must be a newly initialized template object + */ +void tpl_copy(tpl_t* c, const tpl_t* original); + +/* Initialize template object */ +void tpl_init(tpl_t* tpl); + +/* Release memory used by data in template strycture */ +void tpl_release(tpl_t* tpl); + +/* + * Constructs template data from specified template file + * returns TPL_OK if successful + */ +int tpl_load(tpl_t* tpl, const char* filename); + +/* + * Construct template from string + * returns TPL_OK if successful + */ +int tpl_from_string(tpl_t* tpl, const char* data, int len); + +/* Clear fields, delete added content */ +void tpl_reset(tpl_t* tpl); + +/* Set field in currently selected section */ +void tpl_set_field(tpl_t* tpl, const char* field, const char* val, int len); + +/* Uses printf() formating */ +void tpl_set_field_fmt(tpl_t* tpl, const char* field, const char* format, ...); + +/* Output a number to a field */ +void tpl_set_field_int(tpl_t* tpl, const char* field, int val); +void tpl_set_field_uint(tpl_t* tpl, const char* field, unsigned int val); +void tpl_set_field_double(tpl_t* tpl, const char* field, double val); + +/* + * Sets field to contents of a file + * returns TPL_OK unless the file cannot be read + */ +int tpl_set_field_from_file(tpl_t* tpl, const char* field, const char* filename); + +/* Sets a field everywhere in the document */ +void tpl_set_field_global(tpl_t* tpl, const char* field, const char* val, int len); +void tpl_set_field_fmt_global(tpl_t* tpl, const char* field, const char* format, ...); +void tpl_set_field_int_global(tpl_t* tpl, const char* field, int val); +void tpl_set_field_uint_global(tpl_t* tpl, const char* field, unsigned int val); +void tpl_set_field_double_global(tpl_t* tpl, const char* field, double val); + +/* + * Selects section in currently selected section or in the document + * if no section is selected yet + * returns TPL_OK if sections is selected successfully + */ +int tpl_select_section(tpl_t* tpl, const char* section); + +/* + * Selects section containing current section (selects parent section) + * returns TPL_OK if successfull. + */ +int tpl_deselect_section(tpl_t* tpl); + +/* + * Sets content of specified section + * returns TPL_OK if successful + */ +int tpl_set_section(tpl_t* tpl, const char* section, const char* val, int len); +int tpl_set_section_from_file(tpl_t* tpl, const char* section, const char* filename); + +/* + * Add a static copy of currently selected section's content + * before beginning tag of this section but after already "appended" content + * returns TPL_OK if successful + */ +int tpl_append_section(tpl_t* tpl); + +/* returns length of current content not including the trailing \0 byte */ +int tpl_length(const tpl_t* tpl); + +/* returns length of currently selected section's content */ +int tpl_section_length(const tpl_t* tpl); + +/* + * Copy content into supplied buffer, which must be large enough + * Use tpl_length() to obtain length and allocate correct buffer + * with the size length + 1 (to include the terminating \0 byte) + */ +void tpl_get_content(const tpl_t* tpl, char* buffer); + +/* + * Same as tpl_get_content() but with the contents of + * the currently selected section. + * If no section is selected then a call to this function is + * equivalent to a call to tpl_get_content() + */ +void tpl_get_section_content(const tpl_t* tpl, char* buffer); + +/* + * Save to file + * returns TPL_OK if succeessful + */ +int tpl_save_as(const tpl_t* tpl, const char* filename); + +/* + * Write content to a file descriptor (might be a socket) + * returns TPL_OK if write succeeds + */ +int tpl_write(const tpl_t* tpl, int fd); + +/* + * Write content as simple HTTP-response, for use in nph- CGI programs + * returns TPL_OK if write succeeds + */ +int tpl_http_write(const tpl_t* tpl, int fd); + +/* + * Write content of the tpl to out stream + */ +void tpl_out(tpl_t *tpl, ACL_VSTREAM *out); + +#if defined(__cplusplus) +} +#endif + + +/* Return values for non-void functions */ +#define TPL_OPEN_ERROR -7 +#define TPL_WRITE_ERROR -6 +#define TPL_READ_ERROR -5 +#define TPL_NOT_FOUND_ERROR -4 +#define TPL_SYNTAX_ERROR -3 +#define TPL_NO_SECTION_SELECTED_ERROR -2 +#define TPL_SECTION_NOT_FOUND_ERROR -1 +#define TPL_OK 0 + + + +/* Header string for a minimalistic HTTP response */ +#define TPL_NPH_HTTP_HEADER_START \ + "HTTP/1.1 200 OK\r\n"\ + "Content-Type: text/html\r\n"\ + "Content-Length: " + +#define TPL_NPH_HTTP_HEADER_END \ + "\r\n\r\n" + + +#define HASH_TABLE_SIZE 29 + +/* Do not set this to less than the number of characters + needed to represent any number you might want to output */ +#define INITIAL_FIELD_LEN 31 + + +/* Hash bucket for field entry */ +typedef struct tpl_fcell_s +{ + char *key; + char *val; + int len; + struct tpl_fcell_s *next; +} tpl_fcell_t; + + +/* Content of template is a linked list of those */ +typedef struct tpl_node_s +{ + char *val; + int len; + struct tpl_fcell_s *fval; + struct tpl_node_s *next; +} tpl_node_t; + + +/* Hash bucket structure for section entry */ +typedef struct tpl_tcell_t +{ + char *key; + tpl_t *tpl; + tpl_node_t **preceding; + struct tpl_tcell_t *_next; + struct tpl_tcell_t *next; +} tpl_tcell_t; + + +/* The template structure definition */ +typedef struct template_s +{ + tpl_node_t *head; + tpl_node_t *added_head; + tpl_node_t **added_tail; + tpl_tcell_t *first; + tpl_fcell_t *fields[HASH_TABLE_SIZE]; + tpl_tcell_t *sections[HASH_TABLE_SIZE]; + tpl_t *tpl; + tpl_t *parent; +} template_t; + +#endif diff --git a/app/wizard/master_creator.cpp b/app/wizard/master_creator.cpp new file mode 100644 index 000000000..fb1dac36a --- /dev/null +++ b/app/wizard/master_creator.cpp @@ -0,0 +1,223 @@ +#include "stdafx.h" +#include "file_copy.h" +#include "master_creator.h" + +static const char* src_path_ = "tmpl/master"; +static char dst_path_[256]; +static char master_name[128]; + +////////////////////////////////////////////////////////////////////////// + +static tpl_t* open_tpl(const char* filename) +{ + tpl_t* tpl = tpl_alloc(); + string filepath; + filepath.format("%s/%s", src_path_, filename); + if (tpl_load(tpl, filepath.c_str()) != TPL_OK) + { + printf("load file %s error: %s\r\n", + filepath.c_str(), last_serror()); + tpl_free(tpl); + return NULL; + } + return tpl; +} + +////////////////////////////////////////////////////////////////////////// + +static bool copy_and_replace(const char* from, const char* to) +{ + tpl_t* tpl = open_tpl(from); + if (tpl == NULL) + return false; + + tpl_set_field_fmt_global(tpl, "PROGRAM", "%s", master_name); + + string filepath; + filepath << dst_path_ << '/' << to; + if (tpl_save_as(tpl, filepath.c_str()) != TPL_OK) + { + printf("save to %s error: %s\r\n", filepath.c_str(), + last_serror()); + tpl_free(tpl); + return false; + } + printf("create %s ok.\r\n", filepath.c_str()); + tpl_free(tpl); + return true; +} + +static bool create_common() +{ + if (copy_and_replace("Makefile", "Makefile") == false) + return false; + string file; + + // for vc2003 + file.format("%s.sln", master_name); + if (copy_and_replace("master_service.sln", file.c_str()) == false) + return false; + file.format("%s.vcproj", master_name); + if (copy_and_replace("master_service.vcproj", file.c_str()) == false) + return false; + + // for vc2012 + file.format("%s_vc2012.sln", master_name); + if (copy_and_replace("master_service_vc2012.sln", file.c_str()) == false) + return false; + file.format("%s_vc2012.vcxproj", master_name); + if (copy_and_replace("master_service_vc2012.vcxproj", file.c_str()) == false) + return false; + file.format("%s_vc2012.vcxproj.filters", master_name); + if (copy_and_replace("master_service_vc2012.vcxproj.filters", file.c_str()) == false) + return false; + + const char* name = "common_files"; + const FILE_FROM_TO tab[] = { + { "stdafx.h", "stdafx.h" }, + { "stdafx.cpp", "stdafx.cpp" }, + { NULL, NULL } + }; + + return files_copy(name, tab, src_path_, dst_path_); +} + +////////////////////////////////////////////////////////////////////////// + +static bool create_master_threads() +{ + create_common(); + + string file(master_name); + file << ".cf"; + if (copy_and_replace("master_threads.cf", file.c_str()) == false) + return false; + + const char* name = "master_threads"; + const FILE_FROM_TO tab[] = { + { "main_threads.cpp", "main.cpp" }, + { "master_threads.h", "master_service.h" }, + { "master_threads.cpp", "master_service.cpp" }, + { NULL, NULL } + }; + + return files_copy(name, tab, src_path_, dst_path_); +} + +static bool create_master_proc() +{ + create_common(); + + string file(master_name); + file << ".cf"; + if (copy_and_replace("master_proc.cf", file.c_str()) == false) + return false; + + const char* name = "master_proc"; + const FILE_FROM_TO tab[] = { + { "main_proc.cpp", "main.cpp" }, + { "master_proc.h", "master_service.h" }, + { "master_proc.cpp", "master_service.cpp" }, + { NULL, NULL } + }; + + return files_copy(name, tab, src_path_, dst_path_); +} + +static bool create_master_aio() +{ + create_common(); + + string file(master_name); + file << ".cf"; + if (copy_and_replace("master_aio.cf", file.c_str()) == false) + return false; + + const char* name = "master_proc"; + const FILE_FROM_TO tab[] = { + { "main_aio.cpp", "main.cpp" }, + { "master_aio.h", "master_service.h" }, + { "master_aio.cpp", "master_service.cpp" }, + { NULL, NULL } + }; + + return files_copy(name, tab, src_path_, dst_path_); +} + +static bool create_master_trigger() +{ + create_common(); + + string file(master_name); + file << ".cf"; + if (copy_and_replace("master_trigger.cf", file.c_str()) == false) + return false; + + const char* name = "master_trigger"; + const FILE_FROM_TO tab[] = { + { "main_trigger.cpp", "main.cpp" }, + { "master_trigger.h", "master_service.h" }, + { "master_trigger.cpp", "master_service.cpp" }, + { NULL, NULL } + }; + + return files_copy(name, tab, src_path_, dst_path_); +} + +void master_creator() +{ + char buf[256]; + int n; + + while (true) + { + printf("please input your program name: "); fflush(stdout); + n = acl_vstream_gets_nonl(ACL_VSTREAM_IN, buf, sizeof(buf)); + if (n == ACL_VSTREAM_EOF) + break; + if (n == 0) + snprintf(master_name, sizeof(master_name), "master_service"); + else + snprintf(master_name, sizeof(master_name), "%s", buf); + + // 创建目录 + snprintf(dst_path_, sizeof(dst_path_), "%s", master_name); + acl_make_dirs(dst_path_, 0755); + + printf("choose master_service type:\r\n"); + printf("t: for master_threads; p: for master_proc; " + "a: for master_aio; g: for master_trigger; s: skip choose\r\n"); + printf(">"); fflush(stdout); + + n = acl_vstream_gets_nonl(ACL_VSTREAM_IN, buf, sizeof(buf)); + if (n == ACL_VSTREAM_EOF) + break; + else if (strcasecmp(buf, "t") == 0) + { + create_master_threads(); + break; + } + else if (strcasecmp(buf, "p") == 0) + { + create_master_proc(); + break; + } + else if (strcasecmp(buf, "a") == 0) + { + create_master_aio(); + break; + } + else if (strcasecmp(buf, "g") == 0) + { + create_master_trigger(); + break; + } + else if (strcasecmp(buf, "s") == 0) + break; + else + printf("unknown ch: %s\r\n", buf); + } + for (int i = 0; i < 78; i++) + putchar('-'); + printf("\r\n"); +} diff --git a/app/wizard/master_creator.h b/app/wizard/master_creator.h new file mode 100644 index 000000000..359a249a1 --- /dev/null +++ b/app/wizard/master_creator.h @@ -0,0 +1,3 @@ +#pragma once + +void master_creator(); diff --git a/app/wizard/stdafx.cpp b/app/wizard/stdafx.cpp new file mode 100644 index 000000000..f506253a0 --- /dev/null +++ b/app/wizard/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// wizard.pch 将成为预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + +// TODO: 在 STDAFX.H 中 +//引用任何所需的附加头文件,而不是在此文件中引用 diff --git a/app/wizard/stdafx.h b/app/wizard/stdafx.h new file mode 100644 index 000000000..ccb0eaca1 --- /dev/null +++ b/app/wizard/stdafx.h @@ -0,0 +1,18 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是常用但不常更改的项目特定的包含文件 +// + +#pragma once + + +//#include +//#include + +// TODO: 在此处引用程序要求的附加头文件 + +#include "lib_acl.h" +#include "acl_cpp/lib_acl.hpp" +#include "lib_protocol.h" +#include "lib_tpl.h" + +using namespace acl; diff --git a/app/wizard/tmpl/Makefile.in b/app/wizard/tmpl/Makefile.in new file mode 100644 index 000000000..a212edb2f --- /dev/null +++ b/app/wizard/tmpl/Makefile.in @@ -0,0 +1,104 @@ +CC = g++ + +CFLAGS = -c -g -W -Wall -Wcast-qual -Wcast-align \ +-Waggregate-return -Wno-long-long \ +-Wpointer-arith -Werror -Wshadow -O3 \ +-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO + +########################################################### +#Check system: +# Linux, SunOS, Solaris, BSD variants, AIX, HP-UX +SYSLIB = -lpthread -lcrypt -lz +CHECKSYSRES = @echo "Unknow system type!";exit 1 +UNIXNAME = $(shell uname -sm) +OSTYPE = $(shell uname -p) +RPATH = linux64 + +ifeq ($(CC),) + CC = gcc +endif + +# For FreeBSD +ifeq ($(findstring FreeBSD, $(UNIXNAME)), FreeBSD) + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DFREEBSD -D_REENTRANT + SYSLIB = -lcrypt -lpthread +endif + +#Path for Linux +ifeq ($(findstring Linux, $(UNIXNAME)), Linux) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + ifeq ($(findstring i686, $(OSTYPE)), i686) + RPATH = linux32 + endif + ifeq ($(findstring x86_64, $(OSTYPE)), x86_64) + RPATH = linux64 + endif + CFLAGS += -DLINUX2 -D_REENTRANT +endif + +#Path for SunOS +ifeq ($(findstring SunOS, $(UNIXNAME)), SunOS) + ifeq ($(findstring 86, $(UNIXNAME)), 86) + SYSLIB += -lsocket -lnsl -lrt + endif + ifeq ($(findstring sun4u, $(UNIXNAME)), sun4u) + SYSLIB += -lsocket -lnsl -lrt + endif + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DSUNOS5 -D_REENTRANT +endif + +#Path for HP-UX +ifeq ($(findstring HP-UX, $(UNIXNAME)), HP-UX) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DHP_UX -DHPUX11 + PLAT_NAME=hp-ux +endif + +#Find system type. +ifneq ($(SYSPATH),) + CHECKSYSRES = @echo "System is $(shell uname -sm)" +endif +########################################################### + +CFLAGS += -I../../../lib_acl/include -I../../../lib_protocol/include -I../../../lib_acl_cpp/include +EXTLIBS = +LDFLAGS = -L../../../lib_acl_cpp/lib -l_acl_cpp -L../../../lib_protocol/lib -l_protocol -L../../../lib_acl/lib -l_acl \ + $(EXTLIBS) $(SYSLIB) + +COMPILE = $(CC) $(CFLAGS) +LINK = $(CC) $(OBJ) $(LDFLAGS) +########################################################### +OBJ_PATH = . + +#Project's objs +SRC = $(wildcard *.cpp) +OBJ = $(patsubst %.cpp, $(OBJ_PATH)/%.o, $(notdir $(SRC))) + +$(OBJ_PATH)/%.o: %.cpp + $(COMPILE) $< -o $@ + +.PHONY = all clean +all: RM $(OBJ) + $(LINK) -o $(PROG) + @echo "" + @echo "All ok! Output:$(PROG)" + @echo "" +RM: + rm -f $(PROG) +clean: + rm -f $(PROG) + rm -f $(OBJ) +install: + cp $(PROG) ../../../dist/master/libexec/$(RPATH)/ + cp $(PROG).cf ../../../dist/master/conf/service/ +########################################################### diff --git a/app/wizard/tmpl/http/http_request.cpp b/app/wizard/tmpl/http/http_request.cpp new file mode 100644 index 000000000..804d0881d --- /dev/null +++ b/app/wizard/tmpl/http/http_request.cpp @@ -0,0 +1,2 @@ +#include "stdafx.h" + diff --git a/app/wizard/tmpl/http/http_servlet.cpp b/app/wizard/tmpl/http/http_servlet.cpp new file mode 100644 index 000000000..4981e7b1a --- /dev/null +++ b/app/wizard/tmpl/http/http_servlet.cpp @@ -0,0 +1,133 @@ +#include "stdafx.h" +#include "http_servlet.h" + +////////////////////////////////////////////////////////////////////////// + +http_servlet::http_servlet(void) +{ + +} + +http_servlet::~http_servlet(void) +{ + +} + +void http_servlet::doUnknown(HttpServletRequest&, HttpServletResponse& res) +{ + res.setStatus(400); + res.setContentType("text/html; charset=$"); + // 发送 http 响应头 + if (res.sendHeader() == false) + return; + // 发送 http 响应体 + string buf("\r\n"); + (void) res.getOutputStream().write(buf); +} + +bool http_servlet::doGet(HttpServletRequest& req, HttpServletResponse& res) +{ + return doPost(req, res); +} + +bool http_servlet::doPost(HttpServletRequest& req, HttpServletResponse& res) +{ + const char* sid = req.getSession().getAttribute("sid"); + if (*sid == 0) + req.getSession().setAttribute("sid", "xxxxxx"); + sid = req.getSession().getAttribute("sid"); + + $ + + // 设置字符集 + res.setContentType("text/xml; charset=$"); + + const char* param1 = req.getParameter("name1"); + const char* param2 = req.getParameter("name2"); + + // 创建 xml 格式的数据体 + xml body; + body.get_root() + .add_child("root", true) + .add_child("sessions", true) + .add_child("session", true) + .add_attr("sid", sid ? sid : "null") + .get_parent() + .get_parent() + .add_child("cookies", true) + .add_child("cookie", true) + .add_attr("name1", cookie1 ? cookie1 : "null") + .get_parent() + .add_child("cookie", true) + .add_attr("name2", cookie2 ? cookie2 : "null") + .get_parent() + .get_parent() + .add_child("params", true) + .add_child("param", true) + .add_attr("name1", param1 ? param1 : "null") + .get_parent() + .add_child("param", true) + .add_attr("name2", param2 ? param2 : "null"); + string buf; + body.build_xml(buf); + + // 发送 http 响应头 + if (res.sendHeader() == false) + return false; + // 发送 http 响应体 + if (res.getOutputStream().write(buf) == -1) + return false; + return true; +} + +////////////////////////////////////////////////////////////////////////// + +static void do_run(socket_stream* stream) +{ + memcache_session session("$"); + http_servlet servlet; + servlet.setLocalCharset("$"); + servlet.doRun(session, stream); +} + +// 服务器方式运行时的服务类 +class master_service : public master_proc +{ +public: + master_service() {} + ~master_service() {} +protected: + virtual void on_accept(socket_stream* stream) + { + do_run(stream); + } +}; + +// WEB 服务模式 +static void do_alone(void) +{ + master_service service; + printf("listen: 0.0.0.0:8888 ...\r\n"); + service.run_alone("0.0.0.0:8888", NULL, 1); // 单独运行方式 +} + +// WEB CGI 模式 +static void do_cgi(void) +{ + do_run(NULL); +} + +int main(int argc, char* argv[]) +{ +#ifdef WIN32 + acl::acl_cpp_init(); +#endif + + // 开始运行 + if (argc >= 2 && strcmp(argv[1], "alone") == 0) + do_alone(); + else + do_cgi(); + + return 0; +} diff --git a/app/wizard/tmpl/http/http_servlet.h b/app/wizard/tmpl/http/http_servlet.h new file mode 100644 index 000000000..15c39714a --- /dev/null +++ b/app/wizard/tmpl/http/http_servlet.h @@ -0,0 +1,20 @@ +#pragma once +#include "acl_cpp/http/HttpServlet.hpp" + +class acl::HttpServletRequest; +class acl::HttpServletResponse; + +class http_servet : public acl::HttpServlet +{ +public: + http_servlet(); + ~http_servlet(); + +protected: + virtual void doUnknown(acl::HttpServletRequest&, + acl::HttpServletResponse& res); + virtual bool doGet(acl::HttpServletRequest& req, + HttpServletResponse& res); + virtual bool doPost(acl::HttpServletRequest& req, + acl::HttpServletResponse& res); +}; diff --git a/app/wizard/tmpl/master/Makefile b/app/wizard/tmpl/master/Makefile new file mode 100644 index 000000000..fc7b436eb --- /dev/null +++ b/app/wizard/tmpl/master/Makefile @@ -0,0 +1,2 @@ +include ./Makefile.in +PROG = $ diff --git a/app/wizard/tmpl/master/main_aio.cpp b/app/wizard/tmpl/master/main_aio.cpp new file mode 100644 index 000000000..d45985007 --- /dev/null +++ b/app/wizard/tmpl/master/main_aio.cpp @@ -0,0 +1,30 @@ +#include "stdafx.h" +#include "master_service.h" + +int main(int argc, char* argv[]) +{ + // 初始化 acl 库 + acl::acl_cpp_init(); + + master_service& ms = acl::singleton2::get_instance(); + + // 设置配置参数表 + ms.set_cfg_int(var_conf_int_tab); + ms.set_cfg_int64(var_conf_int64_tab); + ms.set_cfg_str(var_conf_str_tab); + ms.set_cfg_bool(var_conf_bool_tab); + + // 开始运行 + + if (argc >= 2 && strcmp(argv[1], "alone") == 0) + { + acl::log::stdout_open(true); // 日志输出至标准输出 + const char* addr = "127.0.0.1:8888"; + printf("listen on: %s\r\n", addr); + ms.run_alone(addr, NULL, acl::ENGINE_SELECT); // 单独运行方式 + } + else + ms.run_daemon(argc, argv); // acl_master 控制模式运行 + + return 0; +} diff --git a/app/wizard/tmpl/master/main_proc.cpp b/app/wizard/tmpl/master/main_proc.cpp new file mode 100644 index 000000000..fe8bd581b --- /dev/null +++ b/app/wizard/tmpl/master/main_proc.cpp @@ -0,0 +1,30 @@ +#include "stdafx.h" +#include "master_service.h" + +int main(int argc, char* argv[]) +{ + // 初始化 acl 库 + acl::acl_cpp_init(); + + master_service& ms = acl::singleton2::get_instance(); + + // 设置配置参数表 + ms.set_cfg_int(var_conf_int_tab); + ms.set_cfg_int64(var_conf_int64_tab); + ms.set_cfg_str(var_conf_str_tab); + ms.set_cfg_bool(var_conf_bool_tab); + + // 开始运行 + + if (argc >= 2 && strcmp(argv[1], "alone") == 0) + { + acl::log::stdout_open(true); // 日志输出至标准输出 + const char* addr = "127.0.0.1:8888"; + printf("listen on: %s\r\n", addr); + ms.run_alone(addr, NULL, 5); // 单独运行方式 + } + else + ms.run_daemon(argc, argv); // acl_master 控制模式运行 + + return 0; +} diff --git a/app/wizard/tmpl/master/main_threads.cpp b/app/wizard/tmpl/master/main_threads.cpp new file mode 100644 index 000000000..fe8bd581b --- /dev/null +++ b/app/wizard/tmpl/master/main_threads.cpp @@ -0,0 +1,30 @@ +#include "stdafx.h" +#include "master_service.h" + +int main(int argc, char* argv[]) +{ + // 初始化 acl 库 + acl::acl_cpp_init(); + + master_service& ms = acl::singleton2::get_instance(); + + // 设置配置参数表 + ms.set_cfg_int(var_conf_int_tab); + ms.set_cfg_int64(var_conf_int64_tab); + ms.set_cfg_str(var_conf_str_tab); + ms.set_cfg_bool(var_conf_bool_tab); + + // 开始运行 + + if (argc >= 2 && strcmp(argv[1], "alone") == 0) + { + acl::log::stdout_open(true); // 日志输出至标准输出 + const char* addr = "127.0.0.1:8888"; + printf("listen on: %s\r\n", addr); + ms.run_alone(addr, NULL, 5); // 单独运行方式 + } + else + ms.run_daemon(argc, argv); // acl_master 控制模式运行 + + return 0; +} diff --git a/app/wizard/tmpl/master/main_trigger.cpp b/app/wizard/tmpl/master/main_trigger.cpp new file mode 100644 index 000000000..b826244cf --- /dev/null +++ b/app/wizard/tmpl/master/main_trigger.cpp @@ -0,0 +1,28 @@ +#include "stdafx.h" +#include "master_service.h" + +int main(int argc, char* argv[]) +{ + // 初始化 acl 库 + acl::acl_cpp_init(); + + master_service& ms = acl::singleton2::get_instance(); + + // 设置配置参数表 + ms.set_cfg_int(var_conf_int_tab); + ms.set_cfg_int64(var_conf_int64_tab); + ms.set_cfg_str(var_conf_str_tab); + ms.set_cfg_bool(var_conf_bool_tab); + + // 开始运行 + + if (argc >= 2 && strcmp(argv[1], "alone") == 0) + { + acl::log::stdout_open(true); // 日志输出至标准输出 + ms.run_alone(NULL, 5, 1); // 单独运行方式 + } + else + ms.run_daemon(argc, argv); // acl_master 控制模式运行 + + return 0; +} diff --git a/app/wizard/tmpl/master/master_aio.cf b/app/wizard/tmpl/master/master_aio.cf new file mode 100644 index 000000000..897095f2d --- /dev/null +++ b/app/wizard/tmpl/master/master_aio.cf @@ -0,0 +1,101 @@ + +service $ { +# 进程是否禁止运行 + master_disable = no +# 服务地址及端口号 +# for master_type = inet +# master_service = 5200 +# for master_type = unix +# master_service = aio_echo.sock +# for master_type = sock + master_service = 5200, 127.0.0.1:5100, :5300, aio_echo.sock, aio_echo2.sock + +# 服务监听为域套接口 +# master_service = aio_echo.sock +# 服务类型 +# master_type = inet +# master_type = unix + master_type = sock + +# 当子进程异常退出时,如果该值非空,则将子进程异常退出的消息通知该服务 +# master_notify_addr = 127.0.0.1:5801 +# 邮件通知接收者 +# master_notify_recipients = zhengshuxin@hotmail.com + +# 是否允许延迟接受客户端连接,如果为0则表示关闭该功能,如果大于0则表示打开此功能 +# 并且此值代表延迟接受连接的超时值,超过此值时如果客户端依然没有发来数据,则操作 +# 系统会在系统层直接关闭该连接 +# master_defer_accept = 0 +# master_type = unix +# 是否只允许私有访问, 如果为 y, 则域套接口创建在 {install_path}/var/log/private/ 目录下, +# 如果为 n, 则域套接口创建在 {install_path}/var/log/public/ 目录下, + master_private = n + master_unpriv = n +# 是否需要 chroot: n -- no, y -- yes + master_chroot = n +# 每隔多长时间触发一次,单位为秒(仅对 trigger 模式有效) + master_wakeup = - +# 最大进程数 + master_maxproc = 5 +# 进程程序名 + master_command = $ +# 进程启动参数,只能为: -u [是否允许以某普通用户的身份运行] + master_args = +# 传递给服务子进程的环境变量, 可以通过 getenv("SERVICE_ENV") 获得此值 +# master_env = mempool_limit:512000000, mempool_use_mutex:true +# master_env = logme:FALSE, priority:E_LOG_INFO, action:E_LOG_PER_DAY, flush:sync_flush, imit_size:512,\ +# sync_action:E_LOG_SEM, sem_name:/tmp/aio_echo.sem +# 进程日志记录文件 + master_log = {install_path}/var/log/$ + +# 是否允许产生 core 文件 +# aio_enable_core = 1 +# 每个进程实例处理连接数的最大次数,超过此值后进程实例主动退出 + aio_use_limit = 0 +# 每个进程实例的空闲超时时间,超过此值后进程实例主动退出 + aio_idle_limit = 0 +# 记录进程PID的位置(对于多进程实例来说没有意义) + aio_pid_dir = {install_path}/var/pid +# 进程运行时所在的路径 + aio_queue_dir = {install_path}/var +# 读写超时时间, 单位为秒 + aio_rw_timeout = 120 +# 读缓冲区的缓冲区大小 + aio_buf_size = 8192 +# 每次 accept 时的循环接收的最大次数 + aio_max_accept = 25 +# 每个进程当一次接收的连接数达到此值时需要通知 acl_master 一下 + aio_min_notify = 1 +# 进程运行时的用户身份 + aio_owner = root + +# 用 select 进行循环时的时间间隔 +# 单位为秒 + aio_delay_sec = 1 +# 单位为微秒 + aio_delay_usec = 500 +# 采用事件循环的方式: select(default), poll, kernel(epoll/devpoll/kqueue) + aio_event_mode = select +# 是否将 socket 接收与IO功能分开: yes/no, 如果为 yes 可以大大提高 accept() 速度 + aio_accept_alone = yes +# 线程池的最大线程数, 如果该值为0则表示采用单线程非阻塞模式. + aio_max_threads = 0 +# 每个线程的空闲时间. + aio_thread_idle_limit = 60 + +# 允许访问的客户端IP地址范围 + aio_access_allow = 127.0.0.1:255.255.255.255, 127.0.0.1:127.0.0.1 + +# 当 acl_master 退出时,如果该值置1则该程序不等所有连接处理完毕便立即退出 + aio_quick_abort = 1 +############################################################################ +# 应用自己的配置选项 + +# 每个客户端连接的空闲时间. + client_idle_limit = 60 +# 是否输出当前的内存状态信息 + debug_mem = 1 +# 是否发送欢迎信息 + send_banner = 0 +} + diff --git a/app/wizard/tmpl/master/master_aio.cpp b/app/wizard/tmpl/master/master_aio.cpp new file mode 100644 index 000000000..fe5856424 --- /dev/null +++ b/app/wizard/tmpl/master/master_aio.cpp @@ -0,0 +1,56 @@ +#include "stdafx.h" +#include "master_service.h" + +//////////////////////////////////////////////////////////////////////////////// +// 配置内容项 + +char *var_cfg_str; +acl::master_str_tbl var_conf_str_tab[] = { + { "str", "test_msg", &var_cfg_str }, + + { 0, 0, 0 } +}; + +int var_cfg_bool; +acl::master_bool_tbl var_conf_bool_tab[] = { + { "bool", 1, &var_cfg_bool }, + + { 0, 0, 0 } +}; + +int var_cfg_int; +acl::master_int_tbl var_conf_int_tab[] = { + { "int", 120, &var_cfg_int, 0, 0 }, + + { 0, 0 , 0 , 0, 0 } +}; + +long long int var_cfg_int64; +acl::master_int64_tbl var_conf_int64_tab[] = { + { "int64", 120, &var_cfg_int64, 0, 0 }, + + { 0, 0 , 0 , 0, 0 } +}; + +//////////////////////////////////////////////////////////////////////////////// + +master_service::master_service() +{ +} + +master_service::~master_service() +{ +} + +bool master_service::on_accept(acl::aio_socket_stream*) +{ + return true; +} + +void master_service::proc_on_init() +{ +} + +void master_service::proc_on_exit() +{ +} diff --git a/app/wizard/tmpl/master/master_aio.h b/app/wizard/tmpl/master/master_aio.h new file mode 100644 index 000000000..b0df27cfd --- /dev/null +++ b/app/wizard/tmpl/master/master_aio.h @@ -0,0 +1,47 @@ +#pragma once + +//////////////////////////////////////////////////////////////////////////////// +// 配置内容项 + +extern char *var_cfg_str; +extern acl::master_str_tbl var_conf_str_tab[]; + +extern int var_cfg_bool; +extern acl::master_bool_tbl var_conf_bool_tab[]; + +extern int var_cfg_int; +extern acl::master_int_tbl var_conf_int_tab[]; + +extern long long int var_cfg_int64; +extern acl::master_int64_tbl var_conf_int64_tab[]; + +//////////////////////////////////////////////////////////////////////////////// + +//class acl::aio_socket_stream; + +class master_service : public acl::master_aio +{ +public: + master_service(); + ~master_service(); + +protected: + /** + * 纯虚函数:当接收到一个客户端连接时调用此函数 + * @param stream {aio_socket_stream*} 新接收到的客户端异步流对象 + * @return {bool} 该函数如果返回 false 则通知服务器框架不再接收 + * 远程客户端连接,否则继续接收客户端连接 + */ + bool on_accept(acl::aio_socket_stream* stream); + + /** + * 当进程切换用户身份后调用的回调函数,此函数被调用时,进程 + * 的权限为普通受限级别 + */ + virtual void proc_on_init(); + + /** + * 当进程退出前调用的回调函数 + */ + virtual void proc_on_exit(); +}; diff --git a/app/wizard/tmpl/master/master_proc.cf b/app/wizard/tmpl/master/master_proc.cf new file mode 100644 index 000000000..6c8b4c909 --- /dev/null +++ b/app/wizard/tmpl/master/master_proc.cf @@ -0,0 +1,75 @@ +# service type private unpriv chroot wakeup maxproc command + args + +service $ +{ +# 进程是否禁止运行 + master_disable = no +# 服务地址及端口号 +# for master_type = inet +# master_service = 127.0.0.1:5000 +# for master_type = unix +# master_service = proc_echo.sock +# for master_type = sock + master_service = 127.0.0.1:5000, 5002, :5003 +# 服务监听为域套接口 +# master_service = single_echo.sock +# 服务类型 +# master_type = inet +# master_type = unix + master_type = sock + +# 当子进程异常退出时,如果该值非空,则将子进程异常退出的消息通知该服务 +# master_notify_addr = 127.0.0.1:5801 +# 邮件通知接收者 +# master_notify_recipients = zhengshuxin@hotmail.com + +# 是否允许延迟接受客户端连接,如果为0则表示关闭该功能,如果大于0则表示打开此功能 +# 并且此值代表延迟接受连接的超时值,超过此值时如果客户端依然没有发来数据,则操作 +# 系统会在系统层直接关闭该连接 +# master_defer_accept = 0 +# 是否只允许私有访问, 如果为 y, 则域套接口创建在 {install_path}/var/log/private/ 目录下, +# 如果为 n, 则域套接口创建在 {install_path}/var/log/public/ 目录下, + master_private = n + master_unpriv = n +# 是否需要 chroot: n -- no, y -- yes + master_chroot = n +# 每隔多长时间触发一次,单位为秒(仅对 trigger 模式有效) + master_wakeup = - +# 最大进程数 + master_maxproc = 10 +# 进程程序名 + master_command = $ +# 进程启动参数,只能为: -u [是否允许以某普通用户的身份运行] +# master_args = +# 进程日志记录文件 + master_log = {install_path}/var/log/$ +# 传递给服务子进程的环境变量, 可以通过 getenv("SERVICE_ENV") 获得此值 + master_env = logme:FALSE, priority:E_LOG_INFO, action:E_LOG_PER_DAY, flush:sync_flush, imit_size:512,\ + sync_action:E_LOG_SEM, sem_name:/tmp/single_echo.sem + +# 是否允许产生 core 文件 +# single_enable_core = 1 +# 每个进程实例处理连接数的最大次数,超过此值后进程实例主动退出 + single_use_limit = 250 +# 每个进程实例的空闲超时时间,超过此值后进程实例主动退出 +# single_idle_limit = 180 +# 记录进程PID的位置(对于多进程实例来说没有意义) + single_pid_dir = {install_path}/var/pid +# 进程运行时所在的路径 + single_queue_dir = {install_path}/var +# 读写超时时间, 单位为秒 + single_rw_timeout = 1800 +# 读缓冲区的缓冲区大小 + single_buf_size = 8192 +# 进程运行时的用户身份 + single_owner = root + +# single_in_flow_delay = 1 +# single_owner = owner +# 用 select 进行循环时的时间间隔 +# 单位为秒 +# single_delay_sec = 1 +# 单位为微秒 +# single_delay_usec = 5000 +# single_daemon_timeout = 1800 +} diff --git a/app/wizard/tmpl/master/master_proc.cpp b/app/wizard/tmpl/master/master_proc.cpp new file mode 100644 index 000000000..0e5a04b4b --- /dev/null +++ b/app/wizard/tmpl/master/master_proc.cpp @@ -0,0 +1,55 @@ +#include "stdafx.h" +#include "master_service.h" + +//////////////////////////////////////////////////////////////////////////////// +// 配置内容项 + +char *var_cfg_str; +acl::master_str_tbl var_conf_str_tab[] = { + { "str", "test_msg", &var_cfg_str }, + + { 0, 0, 0 } +}; + +int var_cfg_bool; +acl::master_bool_tbl var_conf_bool_tab[] = { + { "bool", 1, &var_cfg_bool }, + + { 0, 0, 0 } +}; + +int var_cfg_int; +acl::master_int_tbl var_conf_int_tab[] = { + { "int", 120, &var_cfg_int, 0, 0 }, + + { 0, 0 , 0 , 0, 0 } +}; + +long long int var_cfg_int64; +acl::master_int64_tbl var_conf_int64_tab[] = { + { "int64", 120, &var_cfg_int64, 0, 0 }, + + { 0, 0 , 0 , 0, 0 } +}; + +//////////////////////////////////////////////////////////////////////////////// + +master_service::master_service() +{ +} + +master_service::~master_service() +{ +} + +void master_service::on_accept(acl::socket_stream*) +{ +} + +void master_service::proc_on_init() +{ +} + +void master_service::proc_on_exit() +{ +} diff --git a/app/wizard/tmpl/master/master_proc.h b/app/wizard/tmpl/master/master_proc.h new file mode 100644 index 000000000..0fc940e9f --- /dev/null +++ b/app/wizard/tmpl/master/master_proc.h @@ -0,0 +1,46 @@ +#pragma once + +//////////////////////////////////////////////////////////////////////////////// +// 配置内容项 + +extern char *var_cfg_str; +extern acl::master_str_tbl var_conf_str_tab[]; + +extern int var_cfg_bool; +extern acl::master_bool_tbl var_conf_bool_tab[]; + +extern int var_cfg_int; +extern acl::master_int_tbl var_conf_int_tab[]; + +extern long long int var_cfg_int64; +extern acl::master_int64_tbl var_conf_int64_tab[]; + +//////////////////////////////////////////////////////////////////////////////// + +//class acl::socket_stream; + +class master_service : public acl::master_proc +{ +public: + master_service(); + ~master_service(); + +protected: + /** + * 纯虚函数:当接收到一个客户端连接时调用此函数 + * @param stream {aio_socket_stream*} 新接收到的客户端异步流对象 + * 注:该函数返回后,流连接将会被关闭,用户不应主动关闭该流 + */ + virtual void on_accept(acl::socket_stream* stream); + + /** + * 当进程切换用户身份后调用的回调函数,此函数被调用时,进程 + * 的权限为普通受限级别 + */ + virtual void proc_on_init(); + + /** + * 当进程退出前调用的回调函数 + */ + virtual void proc_on_exit(); +}; diff --git a/app/wizard/tmpl/master/master_service.sln b/app/wizard/tmpl/master/master_service.sln new file mode 100644 index 000000000..b7d680996 --- /dev/null +++ b/app/wizard/tmpl/master/master_service.sln @@ -0,0 +1,27 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "$", "$.vcproj", "{58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + DebugDll = DebugDll + Release = Release + ReleaseDll = ReleaseDll + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.Debug.ActiveCfg = Debug|Win32 + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.Debug.Build.0 = Debug|Win32 + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.DebugDll.ActiveCfg = DebugDll|Win32 + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.DebugDll.Build.0 = DebugDll|Win32 + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.Release.ActiveCfg = Release|Win32 + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.Release.Build.0 = Release|Win32 + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.ReleaseDll.ActiveCfg = ReleaseDll|Win32 + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.ReleaseDll.Build.0 = ReleaseDll|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/app/wizard/tmpl/master/master_service.vcproj b/app/wizard/tmpl/master/master_service.vcproj new file mode 100644 index 000000000..ebb5ade43 --- /dev/null +++ b/app/wizard/tmpl/master/master_service.vcproj @@ -0,0 +1,283 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/wizard/tmpl/master/master_service_vc2012.sln b/app/wizard/tmpl/master/master_service_vc2012.sln new file mode 100644 index 000000000..95ca8f06c --- /dev/null +++ b/app/wizard/tmpl/master/master_service_vc2012.sln @@ -0,0 +1,25 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "$", "$_vc2012.vcxproj", "{58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + DebugDll|Win32 = DebugDll|Win32 + Release|Win32 = Release|Win32 + ReleaseDll|Win32 = ReleaseDll|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.Debug|Win32.ActiveCfg = Debug|Win32 + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.Debug|Win32.Build.0 = Debug|Win32 + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.Release|Win32.ActiveCfg = Release|Win32 + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.Release|Win32.Build.0 = Release|Win32 + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.ReleaseDll|Win32.ActiveCfg = ReleaseDll|Win32 + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C}.ReleaseDll|Win32.Build.0 = ReleaseDll|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/app/wizard/tmpl/master/master_service_vc2012.vcxproj b/app/wizard/tmpl/master/master_service_vc2012.vcxproj new file mode 100644 index 000000000..f15414b8b --- /dev/null +++ b/app/wizard/tmpl/master/master_service_vc2012.vcxproj @@ -0,0 +1,201 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + ReleaseDll + Win32 + + + Release + Win32 + + + + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C} + Win32Proj + $ + + + + Application + v110 + MultiByte + + + Application + v110 + MultiByte + + + Application + v110 + MultiByte + + + Application + v110 + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>11.0.50727.1 + + + Debug\ + Debug\ + true + + + Release\ + Release\ + false + + + $(Configuration)\ + $(Configuration)\ + false + + + $(Configuration)\ + $(Configuration)\ + true + + + + Disabled + ..\..\..\lib_acl_cpp\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Use + Level3 + EditAndContinue + + + lib_acl_cpp_vc2012d.lib;lib_acl_vc2012d.lib;lib_protocol_vc2012d.lib;%(AdditionalDependencies) + $(OutDir)$.exe + ..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)$.pdb + Console + MachineX86 + false + + + + + ..\..\..\lib_acl_cpp\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + Use + Level3 + ProgramDatabase + + + lib_acl_cpp_vc2012.lib;lib_acl_vc2012.lib;lib_protocol_vc2012.lib;%(AdditionalDependencies) + $(OutDir)$.exe + ..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + + + + + ..\..\..\lib_acl_cpp\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_CPP_DLL;%(PreprocessorDefinitions) + MultiThreadedDLL + Use + Level3 + ProgramDatabase + + + lib_acl_cpp_dll.lib;lib_acl.lib;lib_protocol.lib;%(AdditionalDependencies) + $(OutDir)$.exe + ..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + + + copy ..\..\..\dist\lib\win32\lib_acl.dll $(OutDir) /Y +copy ..\..\..\dist\lib\win32\lib_acl_cpp_dll.dll $(OutDir) /Y +copy ..\..\..\dist\lib\win32\lib_protocol.dll $(OutDir) /Y + + + + + Disabled + ..\..\..\lib_acl_cpp\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_CPP_DLL;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Use + Level3 + EditAndContinue + + + lib_acl_cppd_dll.lib;lib_acl_d.lib;lib_protocol_d.lib;%(AdditionalDependencies) + $(OutDir)$.exe + ..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)$.pdb + Console + MachineX86 + + + copy ..\..\..\dist\lib\win32\lib_acl_d.dll $(OutDir) /Y +copy ..\..\..\dist\lib\win32\lib_acl_cppd_dll.dll $(OutDir) /Y +copy ..\..\..\dist\lib\win32\lib_protocol_d.dll $(OutDir) /Y + + + + + + + Create + Create + Create + Create + + + + + + + + + + + + + diff --git a/app/wizard/tmpl/master/master_service_vc2012.vcxproj.filters b/app/wizard/tmpl/master/master_service_vc2012.vcxproj.filters new file mode 100644 index 000000000..35df16743 --- /dev/null +++ b/app/wizard/tmpl/master/master_service_vc2012.vcxproj.filters @@ -0,0 +1,39 @@ +锘 + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx + + + + + 婧愭枃浠 + + + 婧愭枃浠 + + + 婧愭枃浠 + + + + + 澶存枃浠 + + + 澶存枃浠 + + + + + + \ No newline at end of file diff --git a/app/wizard/tmpl/master/master_threads.cf b/app/wizard/tmpl/master/master_threads.cf new file mode 100644 index 000000000..abb063a65 --- /dev/null +++ b/app/wizard/tmpl/master/master_threads.cf @@ -0,0 +1,120 @@ + +service $ { +# 进程是否禁止运行 + master_disable = no +# 服务地址及端口号 +# for master_type = inet +# master_service = 127.0.0.1:5001 +# for master_type = unix +# master_service = echo.sock +# for master_type = sock + master_service = 127.0.0.1:5001, 5002, :5003, echo.sock, echo2.sock + +# 服务监听为域套接口 +# master_service = aio_echo.sock +# 服务类型 +# master_type = inet +# master_type = unix + master_type = sock + +# 当子进程异常退出时,如果该值非空,则将子进程异常退出的消息通知该服务 +# master_notify_addr = 127.0.0.1:5801 +# 邮件通知接收者 +# master_notify_recipients = zhengshuxin@hotmail.com + +# 是否允许延迟接受客户端连接,如果为0则表示关闭该功能,如果大于0则表示打开此功能 +# 并且此值代表延迟接受连接的超时值,超过此值时如果客户端依然没有发来数据,则操作 +# 系统会在系统层直接关闭该连接 +# master_defer_accept = 0 +# 是否只允许私有访问, 如果为 y, 则域套接口创建在 {install_path}/var/log/private/ 目录下, +# 如果为 n, 则域套接口创建在 {install_path}/var/log/public/ 目录下, + master_private = n + master_unpriv = n +# 是否需要 chroot: n -- no, y -- yes + master_chroot = n +# 每隔多长时间触发一次,单位为秒(仅对 trigger 模式有效) + master_wakeup = - +# 最大进程数 + master_maxproc = 1 +# 进程程序名 + master_command = $ +# 进程日志记录文件 + master_log = {install_path}/var/log/$ +# 进程启动参数,只能为: -u [是否允许以某普通用户的身份运行] +# master_args = +# 传递给服务子进程的环境变量, 可以通过 getenv("SERVICE_ENV") 获得此值 +# master_env = mempool_limit:512000000 +# master_env = logme:FALSE, priority:E_LOG_INFO, action:E_LOG_PER_DAY, flush:sync_flush, imit_size:512,\ +# sync_action:E_LOG_SEM, sem_name:/tmp/ioctl_echo.sem + +# 是否允许产生 core 文件 +# ioctl_enable_core = 1 +# 每个进程实例处理连接数的最大次数,超过此值后进程实例主动退出 + ioctl_use_limit = 100 +# 每个进程实例的空闲超时时间,超过此值后进程实例主动退出 + ioctl_idle_limit = 120 +# 记录进程PID的位置(对于多进程实例来说没有意义) + ioctl_pid_dir = {install_path}/var/pid +# 进程运行时所在的路径 + ioctl_queue_dir = {install_path}/var +# 读写超时时间, 单位为秒 + ioctl_rw_timeout = 120 +# 读缓冲区的缓冲区大小 + ioctl_buf_size = 8192 +# 每次 accept 时的循环接收的最大次数 + ioctl_max_accept = 25 +# 在并发访问量非常低的情况下,如访问量在 10 次/秒 以下时,可以找开此值(即赋为1),以加速事件循环过程, +# 从而防止服务进程阻塞在 select 上的时间过长而影响访问速度 +# ioctl_enable_dog = 0 +# 进程运行时的用户身份 + ioctl_owner = root + +# 用 select 进行循环时的时间间隔 +# 单位为秒 + ioctl_delay_sec = 0 +# 单位为微秒 + ioctl_delay_usec = 500 + +# 采用事件循环的方式: select(default), poll, kernel(epoll/devpoll/kqueue) + ioctl_event_mode = select + +# 线程池的最大线程数 + ioctl_max_threads = 250 +# 线程的堆栈空间大小,单位为字节,0表示使用系统缺省值 + ioctl_stacksize = 0 +# 允许访问 udserver 的客户端IP地址范围 + ioctl_access_allow = 127.0.0.1:255.255.255.255, 127.0.0.1:127.0.0.1 + +# 当 acl_master 退出时,如果该值置1则该程序不等所有连接处理完毕便立即退出 + ioctl_quick_abort = 1 + +## app_main.c 需要的参数项 +# 客户端连接的最大空闲时间阀值 + app_client_idle_limit = 12 + +############################################################################ +# 应用自己的配置选项 + +# mysql 服务地址 +# mysql_dbaddr = /tmp/mysql.sock +# mysql_dbaddr = 10.0.250.199:3306 +# 连接 mysql 数据库的连接池的最大值 +# mysql_dbmax = 200 +# ping mysql 连接的间隔时间, 以秒为单位 +# mysql_dbping = 10 +# mysql 连接空闲的时间间隔, 以秒为单位 +# mysql_dbtimeout = 30 + +# 数据库名称 +# mysql_dbname = ioctl_db +# 数据库访问用户 +# mysql_dbuser = ioctl_user +# 数据库用户访问密码 +# mysql_dbpass = 111111 + +# 是否输出当前内存的状态信息 +# debug_mem = 1 +# 是否在一个线程中连接读 +# loop_read = 1 +} + diff --git a/app/wizard/tmpl/master/master_threads.cpp b/app/wizard/tmpl/master/master_threads.cpp new file mode 100644 index 000000000..5e10c69c9 --- /dev/null +++ b/app/wizard/tmpl/master/master_threads.cpp @@ -0,0 +1,78 @@ +#include "stdafx.h" +#include "master_service.h" + +//////////////////////////////////////////////////////////////////////////////// +// 配置内容项 + +char *var_cfg_str; +acl::master_str_tbl var_conf_str_tab[] = { + { "str", "test_msg", &var_cfg_str }, + + { 0, 0, 0 } +}; + +int var_cfg_bool; +acl::master_bool_tbl var_conf_bool_tab[] = { + { "bool", 1, &var_cfg_bool }, + + { 0, 0, 0 } +}; + +int var_cfg_int; +acl::master_int_tbl var_conf_int_tab[] = { + { "int", 120, &var_cfg_int, 0, 0 }, + + { 0, 0 , 0 , 0, 0 } +}; + +long long int var_cfg_int64; +acl::master_int64_tbl var_conf_int64_tab[] = { + { "int64", 120, &var_cfg_int64, 0, 0 }, + + { 0, 0 , 0 , 0, 0 } +}; + +//////////////////////////////////////////////////////////////////////////////// + +master_service::master_service() +{ +} + +master_service::~master_service() +{ +} + +bool master_service::thread_on_read(acl::socket_stream*) +{ + return true; +} + +bool master_service::thread_on_accept(acl::socket_stream*) +{ + return true; +} + +bool master_service::thread_on_timeout(acl::socket_stream*) +{ + return false; +} + +void master_service::thread_on_close(acl::socket_stream*) +{ +} + +void master_service::thread_on_init() +{ +} + +void master_service::thread_on_exit() +{ +} + +void master_service::proc_on_init() +{ +} + +void master_service::proc_on_exit() +{ +} diff --git a/app/wizard/tmpl/master/master_threads.h b/app/wizard/tmpl/master/master_threads.h new file mode 100644 index 000000000..b377f9031 --- /dev/null +++ b/app/wizard/tmpl/master/master_threads.h @@ -0,0 +1,81 @@ +#pragma once + +//////////////////////////////////////////////////////////////////////////////// +// 配置内容项 + +extern char *var_cfg_str; +extern acl::master_str_tbl var_conf_str_tab[]; + +extern int var_cfg_bool; +extern acl::master_bool_tbl var_conf_bool_tab[]; + +extern int var_cfg_int; +extern acl::master_int_tbl var_conf_int_tab[]; + +extern long long int var_cfg_int64; +extern acl::master_int64_tbl var_conf_int64_tab[]; + +//////////////////////////////////////////////////////////////////////////////// + +//class acl::socket_stream; + +class master_service : public acl::master_threads +{ +public: + master_service(); + ~master_service(); + +protected: + /** + * 纯虚函数:当某个客户端连接有数据可读或关闭或出错时调用此函数 + * @param stream {socket_stream*} + * @return {bool} 返回 false 则表示当函数返回后需要关闭连接, + * 否则表示需要保持长连接,如果该流出错,则应用应该返回 false + */ + virtual bool thread_on_read(acl::socket_stream* stream); + + /** + * 当线程池中的某个线程获得一个连接时的回调函数, + * 子类可以做一些初始化工作 + * @param stream {socket_stream*} + * @return {bool} 如果返回 false 则表示子类要求关闭连接,而不 + * 必将该连接再传递至 thread_main 过程 + */ + virtual bool thread_on_accept(acl::socket_stream* stream); + + /** + * 当某个网络连接的 IO 读写超时时的回调函数,如果该函数返回 true 则表示继续等待下一次 + * 读写,否则则希望关闭该连接 + * @param stream {socket_stream*} + * @return {bool} 如果返回 false 则表示子类要求关闭连接,而不 + * 必将该连接再传递至 thread_main 过程 + */ + virtual bool thread_on_timeout(acl::socket_stream* stream); + + /** + * 当与某个线程绑定的连接关闭时的回调函数 + * @param stream {socket_stream*} + */ + virtual void thread_on_close(acl::socket_stream* stream); + + /** + * 当线程池中一个新线程被创建时的回调函数 + */ + virtual void thread_on_init(); + + /** + * 当线程池中一个线程退出时的回调函数 + */ + virtual void thread_on_exit(); + + /** + * 当进程切换用户身份后调用的回调函数,此函数被调用时,进程 + * 的权限为普通受限级别 + */ + virtual void proc_on_init(); + + /** + * 当进程退出前调用的回调函数 + */ + virtual void proc_on_exit(); +}; diff --git a/app/wizard/tmpl/master/master_trigger.cf b/app/wizard/tmpl/master/master_trigger.cf new file mode 100644 index 000000000..27429e6e4 --- /dev/null +++ b/app/wizard/tmpl/master/master_trigger.cf @@ -0,0 +1,58 @@ +# service type private unpriv chroot wakeup maxproc command + args + +service $ +{ +# 进程是否禁止运行 + master_disable = no +# 服务监听为域套接口 + master_service = $.sock +# 服务类型 + master_type = unix + +# 当子进程异常退出时,如果该值非空,则将子进程异常退出的消息通知该服务 +# master_notify_addr = 127.0.0.1:5801 +# 邮件通知接收者 +# master_notify_recipients = zhengshuxin@hotmail.com + +# 是否只允许私有访问, 如果为 y, 则域套接口创建在 {install_path}/var/log/private/ 目录下, +# 如果为 n, 则域套接口创建在 {install_path}/var/log/public/ 目录下, + master_private = y + master_unpriv = n +# 是否需要 chroot: n -- no, y -- yes + master_chroot = n +# 每隔多长时间触发一次,单位为秒(仅对 trigger 模式有效) + master_wakeup = 4 +# 最大进程数 + master_maxproc = 10 +# 进程程序名 + master_command = $ +# 进程启动参数,只能为: -u [是否允许以某普通用户的身份运行] +# master_args = +# 进程日志记录文件 + master_log = {install_path}/var/log/$ +# 传递给服务子进程的环境变量, 可以通过 getenv("SERVICE_ENV") 获得此值 +# master_env = logme:FALSE, priority:E_LOG_INFO, action:E_LOG_PER_DAY, flush:sync_flush, imit_size:512,\ +# sync_action:E_LOG_SEM, sem_name:/tmp/trigger.sem + +# 是否允许产生 core 文件 +# trigger_enable_core = 1 +# 每个进程实例处理连接数的最大次数,超过此值后进程实例主动退出 + trigger_use_limit = 250 +# 记录进程PID的位置(对于多进程实例来说没有意义) + trigger_pid_dir = {install_path}/var/pid +# 进程运行时所在的路径 + trigger_queue_dir = {install_path}/var +# 读写超时时间, 单位为秒 + trigger_rw_timeout = 1800 +# 读缓冲区的缓冲区大小 + trigger_buf_size = 8192 + +# 进程运行时的用户身份 + trigger_owner = owner +# 用 select 进行循环时的时间间隔 +# 单位为秒 +# trigger_delay_sec = 1 +# 单位为微秒 +# trigger_delay_usec = 5000 +# trigger_daemon_timeout = 1800 +} diff --git a/app/wizard/tmpl/master/master_trigger.cpp b/app/wizard/tmpl/master/master_trigger.cpp new file mode 100644 index 000000000..225c4e135 --- /dev/null +++ b/app/wizard/tmpl/master/master_trigger.cpp @@ -0,0 +1,55 @@ +#include "stdafx.h" +#include "master_service.h" + +//////////////////////////////////////////////////////////////////////////////// +// 配置内容项 + +char *var_cfg_str; +acl::master_str_tbl var_conf_str_tab[] = { + { "str", "test_msg", &var_cfg_str }, + + { 0, 0, 0 } +}; + +int var_cfg_bool; +acl::master_bool_tbl var_conf_bool_tab[] = { + { "bool", 1, &var_cfg_bool }, + + { 0, 0, 0 } +}; + +int var_cfg_int; +acl::master_int_tbl var_conf_int_tab[] = { + { "int", 120, &var_cfg_int, 0, 0 }, + + { 0, 0 , 0 , 0, 0 } +}; + +long long int var_cfg_int64; +acl::master_int64_tbl var_conf_int64_tab[] = { + { "int64", 120, &var_cfg_int64, 0, 0 }, + + { 0, 0 , 0 , 0, 0 } +}; + +//////////////////////////////////////////////////////////////////////////////// + +master_service::master_service() +{ +} + +master_service::~master_service() +{ +} + +void master_service::on_trigger() +{ +} + +void master_service::proc_on_init() +{ +} + +void master_service::proc_on_exit() +{ +} diff --git a/app/wizard/tmpl/master/master_trigger.h b/app/wizard/tmpl/master/master_trigger.h new file mode 100644 index 000000000..d58169324 --- /dev/null +++ b/app/wizard/tmpl/master/master_trigger.h @@ -0,0 +1,42 @@ +#pragma once + +//////////////////////////////////////////////////////////////////////////////// +// 配置内容项 + +extern char *var_cfg_str; +extern acl::master_str_tbl var_conf_str_tab[]; + +extern int var_cfg_bool; +extern acl::master_bool_tbl var_conf_bool_tab[]; + +extern int var_cfg_int; +extern acl::master_int_tbl var_conf_int_tab[]; + +extern long long int var_cfg_int64; +extern acl::master_int64_tbl var_conf_int64_tab[]; + +//////////////////////////////////////////////////////////////////////////////// + +class master_service : public acl::master_trigger +{ +public: + master_service(); + ~master_service(); + +protected: + /** + * 当触发器时间到时调用此函数 + */ + virtual void on_trigger(); + + /** + * 当进程切换用户身份后调用的回调函数,此函数被调用时,进程 + * 的权限为普通受限级别 + */ + virtual void proc_on_init(); + + /** + * 当进程退出前调用的回调函数 + */ + virtual void proc_on_exit(); +}; diff --git a/app/wizard/tmpl/master/stdafx.cpp b/app/wizard/tmpl/master/stdafx.cpp new file mode 100644 index 000000000..3a8a20e11 --- /dev/null +++ b/app/wizard/tmpl/master/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// master_threads.pch 将成为预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + +// TODO: 在 STDAFX.H 中 +//引用任何所需的附加头文件,而不是在此文件中引用 diff --git a/app/wizard/tmpl/master/stdafx.h b/app/wizard/tmpl/master/stdafx.h new file mode 100644 index 000000000..8db4bc808 --- /dev/null +++ b/app/wizard/tmpl/master/stdafx.h @@ -0,0 +1,18 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是常用但不常更改的项目特定的包含文件 +// + +#pragma once + + +//#include +//#include + +// TODO: 在此处引用程序要求的附加头文件 + +#include "acl_cpp/lib_acl.hpp" + +#ifdef WIN32 +#define snprintf _snprintf +#endif + diff --git a/app/wizard/tpllib.cpp b/app/wizard/tpllib.cpp new file mode 100644 index 000000000..dc659c7f4 --- /dev/null +++ b/app/wizard/tpllib.cpp @@ -0,0 +1,1281 @@ +/* + * tpllib + * + * C library of functions for text template processing. + * Copyright (C) 2003-2007 Niels Wojciech Tadeusz Andersen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "stdafx.h" +#include "lib_acl.h" + +#ifdef WIN32 +#include /* write() */ +#else +#include /* write() */ +#endif + +#include /* exit() */ +#include /* fopen(), sprintf() ... */ +#include /* va_start(), va_end() */ +#include /* memset(), memcmp() ... */ + +/* Define ZTS when building a PHP extension */ +/* Define WIN32 when compiling under MS Windows */ + +#ifdef WIN32 +# define snprintf _snprintf +# define vsnprintf _vsnprintf +#endif + +#include "lib_tpl.h" + +/* Length defines for markup elements */ +#define DELIM_LEN_LEFT (sizeof(DELIMITER_LEFT) - 1) +#define DELIM_LEN_RIGHT (sizeof(DELIMITER_RIGHT) - 1) +#define SEC_HEAD_LEN (sizeof(SECTIONTAG_HEAD) - 1) +#define SEC_TAIL_LEN (sizeof(SECTIONTAG_TAIL) - 1) + + +#define M_MIN(a, b) (((a) < (b)) ? (a) : (b)) +#define M_MAX(a, b) (((a) > (b)) ? (a) : (b)) + +#define M_NODE_LEN(n) (((n)->val) ? (n)->len : (n)->fval->len) +#define M_NODE_TEXT(n) (((n)->val) ? (n)->val : (n)->fval->val) + +#define M_INT_TO_STRING(buffer, buffer_len, val, signed_v) \ + do \ + { \ + char rev[5 * sizeof(int) / 2]; \ + int i = 0, digits = 0; \ + if ((signed_v) && (val) < 0) \ + { \ + buffer[i] = '-'; \ + i++; \ + } \ + do \ + { \ + rev[digits++] = '0' + abs((val) % 10); \ + (val) /= 10; \ + } \ + while ((val) != 0); \ + for (; digits > 0 && i < (buffer_len); i++) \ + buffer[i] = rev[--digits]; \ + buffer[i] = 0; \ + (buffer_len) = i; \ + } while (0) + + +/* Binary safe string search */ +static const char *tpl_strstr(register const char *haystack, + ssize_t haystack_len, + const char *needle, + int needle_len) +{ + ssize_t i; + const char *p_toofar = haystack + haystack_len - needle_len + 1; + + if (p_toofar <= haystack) + return NULL; + + do + { + if (*haystack == *needle) + { + for (i = 1; i != needle_len && haystack[i] == needle[i]; i++); + + if (i == needle_len) + return haystack; + } + + haystack++; + } + while (haystack != p_toofar); + + return NULL; +} + + +static tpl_node_t* create_node(int len) +{ + tpl_node_t* node = (tpl_node_t*)acl_mymalloc(len+1+sizeof(tpl_node_t)); + node->len = len; + node->val = (char*)(node + 1); + node->next = NULL; + return node; +} + + +static void destroy_node(tpl_node_t* node) +{ + acl_myfree(node); +} + + +static tpl_fcell_t* create_fcell(const char *key, int key_len, int data_len) +{ + tpl_fcell_t* field = (tpl_fcell_t*)acl_mymalloc(key_len + 1 + + sizeof(tpl_fcell_t)); + + field->key = (char *)(field + 1); + + (void)memcpy(field->key, key, key_len); + field->key[key_len] = 0; + field->val = (char *)acl_mymalloc(M_MAX(data_len, INITIAL_FIELD_LEN) + 1); + field->len = 0; + field->val[0] = 0; + field->next = NULL; + return field; +} + + +static void destroy_fcell(tpl_fcell_t* field) +{ + acl_myfree(field->val); + acl_myfree(field); +} + + +static tpl_tcell_t* create_tcell(const char *key, int key_len) +{ + tpl_tcell_t* section = (tpl_tcell_t*)acl_mymalloc(key_len + 1 + + sizeof(tpl_tcell_t) + + sizeof(tpl_t)); + section->tpl = (tpl_t *)(section + 1); + tpl_init(section->tpl); + + section->key = (char *)(section->tpl + 1); + (void)memcpy(section->key, key, key_len); + + section->key[key_len] = 0; + section->next = NULL; + section->_next = NULL; + return section; +} + + +static void destroy_tcell(tpl_tcell_t* section) +{ + tpl_release(section->tpl); + acl_myfree(section); +} + + +/* Hash function using multipy by 31 */ +static unsigned int tpl_hash(const char *key, int key_len) +{ + const char *p_key_end = key + key_len; + register unsigned int h = *key++; + + while (key != p_key_end && *key != 0) + { + unsigned int g; + h = (h << 5) + *key++; + if ((g = h & 0xf0000000) != 0) + h = (h ^ (g >> 24) ^ g); + } + return h % HASH_TABLE_SIZE; +} + +static tpl_fcell_t* tpl_produce_field(tpl_t *tpl, + const char* key, + int key_len, + int data_len, + int may_create) +{ + tpl_fcell_t **pfield = &tpl->fields[tpl_hash(key, key_len)]; + + while (*pfield != NULL) + { + if (memcmp((*pfield)->key, key, key_len) == 0) + { + if (data_len > INITIAL_FIELD_LEN && data_len > (*pfield)->len) + (*pfield)->val = (char*) acl_myrealloc((*pfield)->val, data_len); + + return *pfield; + } + + pfield = &(*pfield)->next; + } + + if (*pfield == NULL && may_create != 0) + { + *pfield = create_fcell(key, key_len, data_len); + return *pfield; + } + + return NULL; +} + +#define tpl_get_field(tpl, key) \ + tpl_produce_field((tpl), (key), strlen((key)), 0, 0) + +#define tpl_new_field(tpl, key, key_len) \ + tpl_produce_field((tpl), (key), (key_len), 0, 1) + +#define tpl_cpy_field(field, tpl, key, key_len, data, data_len) \ + do \ + { \ + (field) = tpl_produce_field((tpl), (key), (key_len), (data_len), 1); \ + if ((field)->len == 0 && (data_len) != 0) \ + { \ + (void)memcpy((field)->val, (data), (data_len));\ + (field)->val[(data_len)] = 0; \ + (field)->len = (data_len); \ + } \ + } while (0) + + +static tpl_tcell_t* tpl_produce_section(tpl_t *tpl, + const char* key, + int key_len, + int must_create) +{ + tpl_tcell_t **psection = &tpl->sections[tpl_hash(key, key_len)]; + + while (*psection != NULL) + { + if (memcmp((*psection)->key, key, key_len) == 0) + return (must_create) ? NULL : *psection; + + psection = &(*psection)->_next; + } + if (*psection == NULL && must_create) + { + *psection = create_tcell(key, key_len); + (*psection)->tpl->parent = tpl; + return *psection; + } + + return NULL; +} + +#define tpl_get_section(tpl, key) \ + tpl_produce_section(tpl, key, strlen(key), 0) + +#define tpl_make_section(tpl, key, key_len) \ + tpl_produce_section(tpl, key, key_len, 1) + + +/* Big, ugly, horrible, quite possibly buggy... + live with it or correct it and let me know */ +static int tpl_construct(tpl_t *tpl, const char *p_last, const char *p_end) +{ + const char *p_begin = p_last, *p_curr, *p_next; + tpl_node_t **tail = &tpl->head; + tpl_tcell_t **last_section = &tpl->first; + + /* While a field delimiter can be found in what is left */ + while ((p_curr = tpl_strstr(p_last, p_end - p_last, + DELIMITER_LEFT, DELIM_LEN_LEFT)) != NULL) + { + /* Advance to beginning of field/section name */ + p_curr += DELIM_LEN_LEFT; + + /* Find end delimiter of identifier or fail with syntax error */ + p_next = tpl_strstr(p_curr, p_end - p_curr, DELIMITER_RIGHT, DELIM_LEN_RIGHT); + + if (p_next == NULL) + { + *last_section = NULL; + *tail = NULL; + return TPL_SYNTAX_ERROR; + } + + /* Section */ + if (p_curr + 1 >= p_begin + SEC_HEAD_LEN + && p_end - p_next >= (int) SEC_TAIL_LEN + && memcmp(SECTIONTAG_HEAD, p_curr - SEC_HEAD_LEN, + SEC_HEAD_LEN) == 0 + && memcmp(SECTIONTAG_TAIL, p_next, SEC_TAIL_LEN) == 0) + { + tpl_tcell_t *section; + + if ((p_curr - SEC_HEAD_LEN - p_last) != 0) + { + int val_len = p_curr - SEC_HEAD_LEN - p_last; + *tail = create_node(val_len); + (*tail)->val[val_len] = 0; + (void)memcpy((*tail)->val, p_last, val_len); + tail = &(*tail)->next; + } + + /* Create and chain in entry for section */ + section = tpl_make_section(tpl, p_curr, p_next - p_curr); + + if (section != NULL) + { + int code; + const char *beginning, *ending; + + *last_section = section; + last_section = §ion->next; + section->preceding = tail; + + /* Advance past the section tag */ + p_last = p_next + SEC_TAIL_LEN; + beginning = p_next + SEC_TAIL_LEN; + + /* Find next occurrence of this section tag */ + ending = tpl_strstr(beginning, + p_end - beginning, + p_curr - SEC_HEAD_LEN, + beginning - p_curr + SEC_HEAD_LEN); + + p_last = ending + (SEC_HEAD_LEN + p_last - p_curr); + + /* If found and found before p_end */ + if (ending != NULL && p_last <= p_end) + { + /* Construct recursively */ + code = tpl_construct(section->tpl, beginning, ending); + } + else + code = TPL_SYNTAX_ERROR; + + if (code != TPL_OK) + { + tpl_release(section->tpl); + tpl_init(section->tpl); + *last_section = NULL; + *tail = NULL; + return TPL_SYNTAX_ERROR; + } + } + else + { + *last_section = NULL; + *tail = NULL; + return TPL_SYNTAX_ERROR; + } + } + /* Field */ + else + { + if ((p_curr - DELIM_LEN_LEFT - p_last) != 0) + { + int val_len = p_curr - DELIM_LEN_LEFT - p_last; + *tail = create_node(val_len); + (*tail)->val[val_len] = 0; + (void)memcpy((*tail)->val, p_last, val_len); + tail = &(*tail)->next; + } + + p_last = p_next + DELIM_LEN_RIGHT; + + /* Create node and set fval to new field cell */ + *tail = create_node(0); + (*tail)->val = NULL; + (*tail)->fval = tpl_new_field(tpl, p_curr, p_next - p_curr); + tail = &(*tail)->next; + } + } + + /* Store rest of the text */ + if (p_last < p_end) + { + int val_len = p_end - p_last; + *tail = create_node(val_len); + (void)memcpy((*tail)->val, p_last, val_len); + (*tail)->val[val_len] = 0; + tail = &(*tail)->next; + } + *tail = NULL; + *last_section = NULL; + + return TPL_OK; +} + +void tpl_init(tpl_t *tpl) +{ + /* Set everything to NULL */ + (void)memset(tpl, 0, sizeof(tpl_t)); + + tpl->tpl = tpl; + tpl->added_tail = &tpl->added_head; +} + +void tpl_release(tpl_t *tpl) +{ + register int i; + + /* Free nodes */ + while (tpl->head != NULL) + { + tpl_node_t *deleted = tpl->head; + tpl->head = tpl->head->next; + destroy_node(deleted); + } + + /* Free any added content */ + while (tpl->added_head != NULL) + { + tpl_node_t *deleted = tpl->added_head; + tpl->added_head = tpl->added_head->next; + destroy_node(deleted); + } + /* Free field cells */ + for (i = 0; i < HASH_TABLE_SIZE; i++) + { + tpl_fcell_t *fc = tpl->fields[i]; + + while (fc != NULL) + { + tpl_fcell_t *deleted = fc; + fc = fc->next; + destroy_fcell(deleted); + } + } + /* Free sections including added content */ + while (tpl->first != NULL) + { + tpl_tcell_t *deleted = tpl->first; + tpl->first = tpl->first->next; + + /* This will call tpl_release() recursively */ + destroy_tcell(deleted); + } +} + +tpl_t* tpl_alloc(void) +{ + tpl_t *tpl = (tpl_t*)acl_mymalloc(sizeof(tpl_t)); + tpl_init(tpl); + return tpl; +} + +void tpl_free(tpl_t *tpl) +{ + tpl_release(tpl); + acl_myfree(tpl); +} + +/* Load template file */ +int tpl_load(tpl_t *tpl, const char *filename) +{ + char *buffer; + int len; + FILE *fp = fopen(filename, "rb"); + + if (fp == NULL) + return TPL_OPEN_ERROR; + + /* Find length of file content */ + (void)fseek(fp, 0, SEEK_END); + len = ftell(fp); + (void) rewind(fp); + + /* Allocate buffer for data + 0 byte */ + buffer = (char*)acl_mymalloc(len+1); + + if (fread(buffer, 1, len, fp) < (unsigned)len) + { + (void)fclose(fp); + acl_myfree(buffer); + return TPL_READ_ERROR; + } + (void)fclose(fp); + buffer[len] = 0; + + /* Use data in buffer to construct template */ + len = tpl_construct(tpl, buffer, buffer + len); + if (len != TPL_OK) + { + tpl_release(tpl); + tpl_init(tpl); + } + acl_myfree(buffer); + return len; +} + +/* Load from a string */ +int tpl_from_string(tpl_t *tpl, const char *buffer, int len) +{ + return tpl_construct(tpl, buffer, buffer + len); +} + +/* Recursively clear added content */ +void tpl_reset(tpl_t* tpl) +{ + int i = HASH_TABLE_SIZE; + tpl_tcell_t* section; + + /* Clear fields */ + while (i != 0) + { + tpl_fcell_t* field = tpl->fields[--i]; + while (field != NULL) + { + field->len = 0; + *field->val = 0; + field = field->next; + } + } + /* Clear sections */ + for (section = tpl->first; section != NULL; section = section->next) + { + /* Clear added content */ + while (section->tpl->added_head != NULL) + { + tpl_node_t* n = section->tpl->added_head; + section->tpl->added_head = section->tpl->added_head->next; + destroy_node(n); + } + section->tpl->added_tail = §ion->tpl->added_head; + + /* Clear this section */ + tpl_reset(section->tpl); + } +} + + +/* Set up the selected section pointer to correspond to + that of the copied template */ +static void tpl_adjust_selection(tpl_t* tpl, + const tpl_t* srctpl, + tpl_tcell_t* sec, + const tpl_tcell_t* srcsec) +{ + const tpl_tcell_t *sec1 = srcsec; + tpl_tcell_t *sec2 = sec; + + if (srctpl->tpl != srctpl) + { + for (; tpl->tpl == tpl && sec1 != NULL; + sec1 = sec1->next, sec2 = sec2->next) + { + if (srctpl->tpl == sec1->tpl) + tpl->tpl = sec2->tpl; + else + { + tpl_adjust_selection(tpl, + srctpl, + sec2->tpl->first, + sec1->tpl->first); + } + } + } +} + + +/* Recursive copy */ +void tpl_copy(tpl_t* tpl, const tpl_t* srctpl) +{ + tpl_node_t **tail = &tpl->head; + tpl_node_t *curr_node = srctpl->head; + tpl_tcell_t **last_section = &tpl->first; + tpl_tcell_t *curr_section = srctpl->first; + + for (; curr_section != NULL; curr_section = curr_section->next) + { + /* Copy text and fields until the current section's position */ + while (curr_node != *curr_section->preceding) + { + /* Text */ + if (curr_node->val != NULL) + { + *tail = create_node(curr_node->len); + (void)memcpy((*tail)->val, curr_node->val, curr_node->len); + (*tail)->val[curr_node->len] = 0; + } + /* Field */ + else + { + /* Create node and set fval to field cell */ + *tail = create_node(0); + (*tail)->val = NULL; + + tpl_cpy_field((*tail)->fval, + tpl, + curr_node->fval->key, + strlen(curr_node->fval->key), + curr_node->fval->val, + curr_node->fval->len); + + } + + tail = &(*tail)->next; + curr_node = curr_node->next; + } + + /* Create emtpy section entry for current section */ + *last_section = tpl_make_section(tpl, + curr_section->key, + strlen(curr_section->key)); + + (*last_section)->preceding = tail; + + + /* Consolidate added content into a single node in newly created + section entry so that only one memory allocation is needed */ + if (curr_section->tpl->added_head != NULL) + { + tpl_node_t *some_node = curr_section->tpl->added_head; + char *buffer; + int len = 0; + + /* Get length of added content */ + for (; some_node!=NULL; some_node=some_node->next) + len += some_node->len; + + /* Create node for added content */ + (*last_section)->tpl->added_head = create_node(len); + (*last_section)->tpl->added_head->next = NULL; + (*last_section)->tpl->added_tail = + &(*last_section)->tpl->added_head->next; + + /* Copy added content into new node */ + + buffer = (*last_section)->tpl->added_head->val; + + for (some_node = curr_section->tpl->added_head; + some_node != NULL; + some_node = some_node->next) + { + (void)memcpy(buffer, some_node->val, some_node->len); + buffer += some_node->len; + } + *buffer = 0; + } + + + /* Recursively copy section */ + tpl_copy((*last_section)->tpl, curr_section->tpl); + + last_section = &(*last_section)->next; + } + + /* Copy the rest */ + while (curr_node != NULL) + { + /* Text */ + if (curr_node->val != NULL) + { + *tail = create_node(curr_node->len); + (void)memcpy((*tail)->val, curr_node->val, curr_node->len + 1); + } + /* Field */ + else + { + *tail = create_node(0); + (*tail)->val = NULL; + + tpl_cpy_field((*tail)->fval, + tpl, + curr_node->fval->key, + strlen(curr_node->fval->key), + curr_node->fval->val, + curr_node->fval->len); + } + + tail = &(*tail)->next; + curr_node = curr_node->next; + } + + *tail = NULL; + *last_section = NULL; + tpl->tpl = tpl; + + tpl_adjust_selection(tpl, srctpl, tpl->first, srctpl->first); +} + + +void tpl_set_field(tpl_t* tpl, const char* key, const char* val, int len) +{ + tpl_fcell_t *field = tpl_get_field(tpl->tpl, key); + if (field != NULL) + { + if (len > INITIAL_FIELD_LEN && len > field->len) + field->val = (char*) acl_myrealloc(field->val, len + 1); + + field->len = len; + (void)memcpy(field->val, val, len); + field->val[len] = 0; + } +} + +void tpl_set_field_fmt(tpl_t* tpl, const char* key, const char* fmt, ...) +{ + tpl_fcell_t *field = tpl_get_field(tpl->tpl, key); + + if (field != NULL) + { + int n; + + if (field->len < INITIAL_FIELD_LEN) + field->len = INITIAL_FIELD_LEN; + + while (1) + { + va_list ap; + + va_start(ap, fmt); + n = vsnprintf(field->val, field->len + 1, fmt, ap); + va_end(ap); + + if (n > -1 && n <= field->len) + break; + + field->len *= 2; + field->val = (char*) acl_myrealloc(field->val, field->len + 1); + } + field->len = n; + } +} + +void tpl_set_field_int(tpl_t* tpl, const char* key, int val) +{ + tpl_fcell_t *field = tpl_get_field(tpl->tpl, key); + + if (field != NULL) + { + if (field->len < INITIAL_FIELD_LEN) + field->len = INITIAL_FIELD_LEN; + + M_INT_TO_STRING(field->val, field->len, val, 1); + } +} + +void tpl_set_field_uint(tpl_t* tpl, const char* key, unsigned int val) +{ + tpl_fcell_t *field = tpl_get_field(tpl->tpl, key); + + if (field != NULL) + { + int v = (int) val; + + if (field->len < INITIAL_FIELD_LEN) + field->len = INITIAL_FIELD_LEN; + + M_INT_TO_STRING(field->val, field->len, v, 0); + } +} + +void tpl_set_field_double(tpl_t* tpl, const char* key, double val) +{ + tpl_fcell_t *field = tpl_get_field(tpl->tpl, key); + + if (field != NULL) + { + if (field->len < INITIAL_FIELD_LEN) + field->len = INITIAL_FIELD_LEN; + + field->len = snprintf(field->val, field->len, "%.2f", val); + } +} + +int tpl_set_field_from_file(tpl_t* tpl, const char* key, const char* filename) +{ + tpl_fcell_t *field = tpl_get_field(tpl->tpl, key); + + if (field != NULL) + { + int len; + FILE *fp = fopen(filename, "rb"); + + if (fp == NULL) + return TPL_OPEN_ERROR; + + /* Find length of file content */ + (void)fseek(fp, 0, SEEK_END); + len = ftell(fp); + (void)rewind(fp); + + if (len > INITIAL_FIELD_LEN && len > field->len) + field->val = (char*) acl_myrealloc(field->val, len + 1); + + if (fread(field->val, 1, len, fp) < (unsigned)len) + { + (void)fclose(fp); + return TPL_READ_ERROR; + } + (void)fclose(fp); + + field->len = len; + field->val[len] = 0; + } + return TPL_OK; +} + +void tpl_set_field_global(tpl_t* tpl, const char* key, const char* val, int len) +{ + tpl_tcell_t *section = tpl->first; + tpl_set_field(tpl, key, val, len); + while (section != NULL) + { + /* Recursively set in all sections */ + tpl_set_field_global(section->tpl, key, val, len); + section = section->next; + } +} + +void tpl_set_field_fmt_global(tpl_t* tpl, const char* key, const char* fmt, ...) +{ + int n; + int len = 256; + char *buf = (char*)acl_mymalloc(len); + + while (1) + { + va_list ap; + + va_start(ap, fmt); + n = vsnprintf(buf, len, fmt, ap); + va_end(ap); + + if (n > -1 && n < len) + break; + + len *= 2; + buf = (char*) acl_myrealloc(buf, len); + } + tpl_set_field_global(tpl, key, buf, n); + acl_myfree(buf); +} + +void tpl_set_field_int_global(tpl_t* tpl, const char* key, int val) +{ + tpl_tcell_t *section = tpl->first; + tpl_set_field_int(tpl, key, val); + while (section != NULL) + { + /* Recursively set in all sections */ + tpl_set_field_int_global(section->tpl, key, val); + section = section->next; + } +} + +void tpl_set_field_uint_global(tpl_t* tpl, const char* key, unsigned int val) +{ + tpl_tcell_t *section = tpl->first; + tpl_set_field_uint(tpl, key, val); + while (section != NULL) + { + /* Recursively set in all sections */ + tpl_set_field_uint_global(section->tpl, key, val); + section = section->next; + } +} + +void tpl_set_field_double_global(tpl_t* tpl, const char* key, double val) +{ + tpl_tcell_t *section = tpl->first; + tpl_set_field_double(tpl, key, val); + while (section != NULL) + { + /* Recursively set in all sections */ + tpl_set_field_double_global(section->tpl, key, val); + section = section->next; + } +} + +int tpl_select_section(tpl_t *tpl, const char* key) +{ + tpl_tcell_t *section = tpl_get_section(tpl->tpl, key); + if (section != NULL) + { + tpl->tpl->tpl = section->tpl; + tpl->tpl = tpl->tpl->tpl; + return TPL_OK; + } + return TPL_SECTION_NOT_FOUND_ERROR; +} + +int tpl_deselect_section(tpl_t *tpl) +{ + if (tpl->tpl != tpl) + { + tpl->tpl = tpl->tpl->parent; + tpl->tpl->tpl = tpl->tpl; + return TPL_OK; + } + return TPL_NO_SECTION_SELECTED_ERROR; +} + + +/* Set or replace added content in section with supplied value */ +static int tpl_set_section_ex(tpl_t* tpl, + const char* key, + const char* val, + int len, + tpl_node_t *existing_node) +{ + tpl_tcell_t *section = tpl_get_section(tpl->tpl, key); + + if (section != NULL) + { + if (section->tpl->first != NULL + || section->tpl->head == NULL + || section->tpl->head->next != NULL + || section->tpl->head->len != len) + { + /* Destroy the contents of this section */ + tpl_release(section->tpl); + tpl_init(section->tpl); + + section->tpl->parent = tpl->tpl; + section->tpl->head = create_node(len); + } + + (void)memcpy(section->tpl->head->val, val, len); + section->tpl->head->val[len] = 0; + + if (existing_node != NULL) + { + existing_node->next = section->tpl->added_head; + section->tpl->added_head = existing_node; + } + else + { + if (section->tpl->added_head != NULL + && section->tpl->added_head->len != len) + { + tpl_node_t *node = create_node(len); + node->next = section->tpl->added_head; + section->tpl->added_head = node; + } + else if (section->tpl->added_head == NULL) + section->tpl->added_head = create_node(len); + + (void)memcpy(section->tpl->added_head->val, val, len); + section->tpl->added_head->val[len] = 0; + } + + while (section->tpl->added_head->next != NULL) + { + tpl_node_t *deleted = section->tpl->added_head->next; + section->tpl->added_head->next = deleted->next; + destroy_node(deleted); + } + + section->tpl->added_tail = §ion->tpl->added_head->next; + + return TPL_OK; + } + + return TPL_SECTION_NOT_FOUND_ERROR; +} + +int tpl_set_section(tpl_t* tpl, const char* key, const char* val, int len) +{ + return tpl_set_section_ex(tpl, key, val, len, NULL); +} + +int tpl_set_section_from_file(tpl_t* tpl, const char* key, const char* filename) +{ + int len, status; + tpl_node_t *node; + FILE *fp = fopen(filename, "rb"); + + if (fp == NULL) + return TPL_OPEN_ERROR; + + /* Find length of file content */ + (void)fseek(fp, 0, SEEK_END); + len = ftell(fp); + (void)rewind(fp); + + node = create_node(len); + + if (fread(node->val, 1, len, fp) < (unsigned)len) + status = TPL_READ_ERROR; + else + status = tpl_set_section_ex(tpl, key, node->val, len, node); + + (void)fclose(fp); + + if (status != TPL_OK) + destroy_node(node); + + return status; +} + + +int tpl_append_section(tpl_t* tpl) +{ + if (tpl->tpl != tpl) + { + tpl_tcell_t *curr_sect = tpl->tpl->first; + tpl_node_t *curr_node = tpl->tpl->head; + tpl_node_t *some_node; + int len; + char *buffer; + + for (; curr_sect != NULL; curr_sect = curr_sect->next) + { + if (curr_sect->tpl->added_head != NULL) + { + + for (len = 0, some_node = curr_node; + some_node != *curr_sect->preceding; + some_node = some_node->next) + { + len += M_NODE_LEN(some_node); + } + + *tpl->tpl->added_tail = create_node(len); + buffer = (*tpl->tpl->added_tail)->val; + tpl->tpl->added_tail = &(*tpl->tpl->added_tail)->next; + + for (; + curr_node != *curr_sect->preceding; + curr_node = curr_node->next) + { + if (curr_node->val) + { + (void)memcpy(buffer, curr_node->val, curr_node->len); + buffer += curr_node->len; + } + else + { + (void)memcpy(buffer, + curr_node->fval->val, + curr_node->fval->len); + buffer += curr_node->fval->len; + } + } + + *buffer = 0; + + /* Cut 'n paste added content chain from section */ + *tpl->tpl->added_tail = curr_sect->tpl->added_head; + tpl->tpl->added_tail = curr_sect->tpl->added_tail; + curr_sect->tpl->added_tail = &curr_sect->tpl->added_head; + curr_sect->tpl->added_head = NULL; + } + } + + for (len = 0, some_node = curr_node; + some_node != NULL; + some_node = some_node->next) + { + len += M_NODE_LEN(some_node); + } + + + *tpl->tpl->added_tail = create_node(len); + buffer = (*tpl->tpl->added_tail)->val; + tpl->tpl->added_tail = &(*tpl->tpl->added_tail)->next; + + for (; curr_node != NULL; curr_node = curr_node->next) + { + if (curr_node->val) + { + (void)memcpy(buffer, curr_node->val, curr_node->len); + buffer += curr_node->len; + } + else + { + (void)memcpy(buffer, + curr_node->fval->val, + curr_node->fval->len); + + buffer += curr_node->fval->len; + } + } + *buffer = 0; + *tpl->tpl->added_tail = NULL; + + return TPL_OK; + } + return TPL_NO_SECTION_SELECTED_ERROR; +} + + +int tpl_length(const tpl_t* tpl) +{ + tpl_node_t *n = tpl->head; + tpl_tcell_t *s = tpl->first; + int len; + + for (len = 0; n != NULL; n = n->next) + len += (n->val) ? n->len : n->fval->len; + + for (; s != NULL; s = s->next) + { + for (n = s->tpl->added_head; n != NULL; n = n->next) + len += n->len; + } + + return len; +} + + +int tpl_section_length(const tpl_t* tpl) +{ + return tpl_length(tpl->tpl); +} + +void tpl_get_content(const tpl_t* tpl, char* buffer) +{ + tpl_node_t *n = tpl->head; + tpl_tcell_t *s = tpl->first; + + for (; s != NULL; s = s->next) + { + tpl_node_t *an = s->tpl->added_head; + + /* Copy part until beginning of section */ + for (; n != *s->preceding; n = n->next) + { + if (n->val) + { + (void)memcpy(buffer, n->val, n->len); + buffer += n->len; + } + else + { + (void)memcpy(buffer, n->fval->val, n->fval->len); + buffer += n->fval->len; + } + } + + /* Copy content appended in section */ + for (; an != NULL; an = an->next) + { + (void)memcpy(buffer, an->val, an->len); + buffer += an->len; + } + } + + /* Copy the rest */ + for (; n != NULL; n = n->next) + { + if (n->val) + { + (void)memcpy(buffer, n->val, n->len); + buffer += n->len; + } + else + { + (void)memcpy(buffer, n->fval->val, n->fval->len); + buffer += n->fval->len; + } + } + *buffer = 0; +} + +void tpl_get_section_content(const tpl_t* tpl, char* buffer) +{ + tpl_get_content(tpl->tpl, buffer); +} + +int tpl_save_as(const tpl_t* tpl, const char* filename) +{ + FILE *fp = fopen(filename, "wb"); + + if (fp != NULL) + { + int len = tpl_length(tpl); + int n; + char *content = (char *)acl_mymalloc(len + 1); + + tpl_get_content(tpl, content); + + n = fwrite(content, len, 1, fp); + if (n != 1) + { + (void)fclose(fp); + acl_myfree(content); + return TPL_WRITE_ERROR; + } + (void)fclose(fp); + + acl_myfree(content); + return TPL_OK; + } + return TPL_OPEN_ERROR; +} + +#ifdef WIN32 +#define write _write +#endif + +int tpl_write(const tpl_t* tpl, int fd) +{ + int len = tpl_length(tpl); + char *content = (char *)acl_mymalloc(len + 1); + + tpl_get_content(tpl, content); + len = write(fd, content, len); + acl_myfree(content); + + if (len < 0) + return TPL_WRITE_ERROR; + + return TPL_OK; +} + + +int tpl_http_write(const tpl_t* tpl, int fd) +{ + /* Assumption: the content length can be max a 10 digit number */ + int length_digits = 10; + + int header_len = sizeof(TPL_NPH_HTTP_HEADER_START) + + sizeof(TPL_NPH_HTTP_HEADER_END) + + length_digits; + + int content_len = tpl_length(tpl); + int tmp_len = content_len; + + /* Long enough for both the HTTP header and content */ + char *response = (char*)acl_mymalloc(content_len + header_len + 1); + + char *str_p = response; + + (void)memcpy(str_p, + TPL_NPH_HTTP_HEADER_START, + sizeof(TPL_NPH_HTTP_HEADER_START) - 1); + + str_p += sizeof(TPL_NPH_HTTP_HEADER_START) - 1; + + M_INT_TO_STRING(str_p, length_digits, tmp_len, 0); + str_p += length_digits; + + (void)memcpy(str_p, + TPL_NPH_HTTP_HEADER_END, + sizeof(TPL_NPH_HTTP_HEADER_END) - 1); + + str_p += sizeof(TPL_NPH_HTTP_HEADER_END) - 1; + + tpl_get_content(tpl, str_p); + content_len = write(fd, response, content_len + (str_p - response)); + acl_myfree(response); + + if (content_len < 0) + return TPL_WRITE_ERROR; + + return TPL_OK; +} + +void tpl_out(tpl_t *tpl, ACL_VSTREAM *out) +{ + char *buf; + int n; + + if (tpl == NULL) + return; + if (out == NULL) + out = ACL_VSTREAM_OUT; + + n = tpl_length(tpl); + if (n <= 0) + return; + buf = (char*) acl_mymalloc(n + 1); + tpl_get_content(tpl, buf); + acl_vstream_writen(out, buf, n); + acl_myfree(buf); +} diff --git a/app/wizard/wizard.cpp b/app/wizard/wizard.cpp new file mode 100644 index 000000000..b787ef199 --- /dev/null +++ b/app/wizard/wizard.cpp @@ -0,0 +1,44 @@ +// wizard.cpp : 定义控制台应用程序的入口点。 +// + +#include "stdafx.h" +#include +#include "master_creator.h" +#include "http_creator.h" + +static void create_db() +{ + +} + +int main(int argc, char* argv[]) +{ + (void) argc, (void) argv; + + acl::acl_cpp_init(); + + while (true) + { + printf("select one below:\r\n"); + printf("m: master_service; d: db; h: http; q: exit\r\n"); + printf(">"); fflush(stdout); + + char buf[256]; + int n = acl_vstream_gets_nonl(ACL_VSTREAM_IN, buf, sizeof(buf)); + if (n == ACL_VSTREAM_EOF) + break; + else if (strcasecmp(buf, "m") == 0) + master_creator(); + else if (strcasecmp(buf, "d") == 0) + create_db(); + else if (strcasecmp(buf, "h") == 0) + http_creator(); + else if (strcasecmp(buf, "q") == 0) + break; + else + printf("unknown %s\r\n", buf); + } + + printf("Bye!\r\n"); + return 0; +} diff --git a/app/wizard/wizard.sln b/app/wizard/wizard.sln new file mode 100644 index 000000000..99ba5a188 --- /dev/null +++ b/app/wizard/wizard.sln @@ -0,0 +1,66 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wizard", "wizard.vcproj", "{84376B60-FF20-4FD0-967E-C568FC2FBC53}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + {FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lib_acl_cpp", "..\..\lib_acl_cpp\lib_acl_cpp_vc2003.vcproj", "{6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lib_acl", "..\..\lib_acl\lib_acl_vc2003.vcproj", "{B40213C2-507C-4C7F-A6E1-B850C9BDC27B}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lib_protocol", "..\..\lib_protocol\lib_protocol_vc2003.vcproj", "{FE724EF7-3763-4E78-BDF5-BCBC075719FD}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + DebugDll = DebugDll + Release = Release + Releasedll = Releasedll + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {84376B60-FF20-4FD0-967E-C568FC2FBC53}.Debug.ActiveCfg = Debug|Win32 + {84376B60-FF20-4FD0-967E-C568FC2FBC53}.Debug.Build.0 = Debug|Win32 + {84376B60-FF20-4FD0-967E-C568FC2FBC53}.DebugDll.ActiveCfg = Debug|Win32 + {84376B60-FF20-4FD0-967E-C568FC2FBC53}.DebugDll.Build.0 = Debug|Win32 + {84376B60-FF20-4FD0-967E-C568FC2FBC53}.Release.ActiveCfg = Release|Win32 + {84376B60-FF20-4FD0-967E-C568FC2FBC53}.Release.Build.0 = Release|Win32 + {84376B60-FF20-4FD0-967E-C568FC2FBC53}.Releasedll.ActiveCfg = Release|Win32 + {84376B60-FF20-4FD0-967E-C568FC2FBC53}.Releasedll.Build.0 = Release|Win32 + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.Debug.ActiveCfg = Debug|Win32 + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.Debug.Build.0 = Debug|Win32 + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.DebugDll.ActiveCfg = DebugDll|Win32 + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.DebugDll.Build.0 = DebugDll|Win32 + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.Release.ActiveCfg = Release|Win32 + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.Release.Build.0 = Release|Win32 + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.Releasedll.ActiveCfg = Releasedll|Win32 + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.Releasedll.Build.0 = Releasedll|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Debug.ActiveCfg = Debug|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Debug.Build.0 = Debug|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.DebugDll.ActiveCfg = DebugDll|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.DebugDll.Build.0 = DebugDll|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Release.ActiveCfg = Release|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Release.Build.0 = Release|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Releasedll.ActiveCfg = ReleaseDll|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Releasedll.Build.0 = ReleaseDll|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Debug.ActiveCfg = Debug|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Debug.Build.0 = Debug|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.DebugDll.ActiveCfg = DebugDll|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.DebugDll.Build.0 = DebugDll|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Release.ActiveCfg = Release|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Release.Build.0 = Release|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Releasedll.ActiveCfg = ReleaseDll|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Releasedll.Build.0 = ReleaseDll|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/app/wizard/wizard.vcproj b/app/wizard/wizard.vcproj new file mode 100644 index 000000000..6914e2b15 --- /dev/null +++ b/app/wizard/wizard.vcproj @@ -0,0 +1,179 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/wizard/wizard_vc2012.sln b/app/wizard/wizard_vc2012.sln new file mode 100644 index 000000000..d8f1d71e0 --- /dev/null +++ b/app/wizard/wizard_vc2012.sln @@ -0,0 +1,60 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wizard", "wizard_vc2012.vcxproj", "{84376B60-FF20-4FD0-967E-C568FC2FBC53}" + ProjectSection(ProjectDependencies) = postProject + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + {FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lib_acl", "..\..\lib_acl\lib_acl_vc2012.vcxproj", "{B40213C2-507C-4C7F-A6E1-B850C9BDC27B}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lib_protocol", "..\..\lib_protocol\lib_protocol_vc2012.vcxproj", "{FE724EF7-3763-4E78-BDF5-BCBC075719FD}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lib_acl_cpp", "..\..\lib_acl_cpp\lib_acl_cpp_vc2012.vcxproj", "{6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + DebugDll|Win32 = DebugDll|Win32 + Release|Win32 = Release|Win32 + Releasedll|Win32 = Releasedll|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {84376B60-FF20-4FD0-967E-C568FC2FBC53}.Debug|Win32.ActiveCfg = Debug|Win32 + {84376B60-FF20-4FD0-967E-C568FC2FBC53}.Debug|Win32.Build.0 = Debug|Win32 + {84376B60-FF20-4FD0-967E-C568FC2FBC53}.DebugDll|Win32.ActiveCfg = Debug|Win32 + {84376B60-FF20-4FD0-967E-C568FC2FBC53}.DebugDll|Win32.Build.0 = Debug|Win32 + {84376B60-FF20-4FD0-967E-C568FC2FBC53}.Release|Win32.ActiveCfg = Release|Win32 + {84376B60-FF20-4FD0-967E-C568FC2FBC53}.Release|Win32.Build.0 = Release|Win32 + {84376B60-FF20-4FD0-967E-C568FC2FBC53}.Releasedll|Win32.ActiveCfg = Release|Win32 + {84376B60-FF20-4FD0-967E-C568FC2FBC53}.Releasedll|Win32.Build.0 = Release|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Debug|Win32.ActiveCfg = Debug|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Debug|Win32.Build.0 = Debug|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Release|Win32.ActiveCfg = Release|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Release|Win32.Build.0 = Release|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Releasedll|Win32.ActiveCfg = ReleaseDll|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Releasedll|Win32.Build.0 = ReleaseDll|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Debug|Win32.ActiveCfg = Debug|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Debug|Win32.Build.0 = Debug|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Release|Win32.ActiveCfg = Release|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Release|Win32.Build.0 = Release|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Releasedll|Win32.ActiveCfg = ReleaseDll|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Releasedll|Win32.Build.0 = ReleaseDll|Win32 + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.Debug|Win32.ActiveCfg = Debug|Win32 + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.Debug|Win32.Build.0 = Debug|Win32 + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.Release|Win32.ActiveCfg = Release|Win32 + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.Release|Win32.Build.0 = Release|Win32 + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.Releasedll|Win32.ActiveCfg = Releasedll|Win32 + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.Releasedll|Win32.Build.0 = Releasedll|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/app/wizard/wizard_vc2012.vcxproj b/app/wizard/wizard_vc2012.vcxproj new file mode 100644 index 000000000..3857634a8 --- /dev/null +++ b/app/wizard/wizard_vc2012.vcxproj @@ -0,0 +1,115 @@ +锘 + + + + Debug + Win32 + + + Release + Win32 + + + + {84376B60-FF20-4FD0-967E-C568FC2FBC53} + Win32Proj + wizard + + + + Application + v110 + MultiByte + + + Application + v110 + MultiByte + + + + + + + + + + + + + <_ProjectFileVersion>11.0.50727.1 + + + .\ + Debug\ + true + + + Release\ + Release\ + false + + + + Disabled + ..\..\lib_acl\include;..\..\lib_protocol\include;..\..\lib_acl_cpp\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Use + Level3 + ProgramDatabase + + + $(OutDir)$(TargetName)$(TargetExt) + ..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)wizard.pdb + Console + MachineX86 + lib_acl_cpp_vc2012d.lib;lib_acl_vc2012d.lib;lib_protocol_vc2012d.lib;%(AdditionalDependencies) + + + + + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + Use + Level3 + ProgramDatabase + + + $(OutDir)wizard.exe + true + Console + true + true + MachineX86 + + + + + + + + Create + Create + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/wizard/wizard_vc2012.vcxproj.filters b/app/wizard/wizard_vc2012.vcxproj.filters new file mode 100644 index 000000000..2dbe44b94 --- /dev/null +++ b/app/wizard/wizard_vc2012.vcxproj.filters @@ -0,0 +1,57 @@ +锘 + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx + + + + + 婧愭枃浠 + + + 婧愭枃浠 + + + 婧愭枃浠 + + + 婧愭枃浠 + + + 婧愭枃浠 + + + 婧愭枃浠 + + + + + 澶存枃浠 + + + 澶存枃浠 + + + 澶存枃浠 + + + 澶存枃浠 + + + 澶存枃浠 + + + + + + \ No newline at end of file diff --git a/changes.txt b/changes.txt new file mode 100644 index 000000000..1199d0bfe --- /dev/null +++ b/changes.txt @@ -0,0 +1,179 @@ + +52) 2013.6.25 --- acl 3.0.10 版本发布! + +51) 2013.7.1 +51.1) compile: unit_test 在 gcc4.6.3 上存在一些编译警告 + +50) 2013.6.25 --- acl 3.0.8 版本发布! +49) 2013.5.13 --- acl 3.0.7 版本发布! +48) 2013.3.22 --- acl 3.0.6 版本发布! + +47) 2013.3.2 +47.1) 将 lib_acl_cpp 目录下的 lib 和 bin 两个目录下的库移至上级目录下 +47.2) 调整了 lib_acl_cpp/samples 下的示例在用 VC 编译时的工程文件 +47.3) 在 app 目录下增加了 net_tools 工程 + +46) 2013.2.19 +46.1) app: 增加了 gid 应用,该应用主要用于产生全局唯一 64 位长整型 ID,不仅 +提供了 gid 服务器模块,同时还提供了 gid 客户端库(包含C/JAVA两个版本) + +45) 2013.2.8 --- acl 3.0.5 版本发布! + +44) 2012.12.31 +44.1) app/wizard: 调整了一下 tmpl/master/ 下的接口方式 + +45) 2012.12.30 +45.1) sample: 增加了 smtp_client 邮件发送客户端例子 + +44) 2012.12.26 +44.1) 把 win32_build 目录下的内容移到 samples/ 目录下了。 + +43) 2012.7.17 +43.1) compile: WIN32 下的编程环境可以支持 VC2010 + +42) 2012.7.10 +42.1) compile: 用 VC2003 编译时,可以在 Debug/DebugDll/Release/ReleaseDll 下 +使所有的例子编译通过 + +41) 2012.6.26 +41.1) unit_test: stdlib/test_htable.c 编译有错 + +40) 2012.4.9 +40.1) samples: 因为 lib_acl 的头文件中增加了针对变参类型匹配的编译开关, +由此检查出一些例子中存在的问题 + +39) !!!!!!!!!!!!!!!!! 2012.3.31 !!!!!!!!!!!!!!!!! +39.1) 将 acl_project 重新命名为 acl + +38) 2012.3.26 +38.1) samples: 在 samples/ 目录下增加了两个文件 Makefile.in 和 +Makefile.in.cpp, 同时修改了各个示例的 Makefile + +37) 2011.10.23 +37.1) samples: 增加了 json 解析库的测试用例,参见 samples/json + +36) +36.1) 为了与 VC 编辑器兼容,将所有的源文件和头文件都转成 DOS 方式,即回车 +换行采用 \r\n,主要是 VIM 比较智能,它能根据文件的换行格式自动选取,而VC +就比较弱,虽然VC识别\n,但添加换行时只会添加\r\n + +35) 2011.5.17 +35.1) 版本号更新为 2.1.2_5 + +34) 2011.3.14: 2.1.2 版本正式发布 + +33) 2011.2.9 +33.1) sample: 增加了 log/ 测试新的日志功能 + +32) 2010.9.30 +32.1) sample: 增加了 resolve/ 测试DNS解析的例子以及 connect/ 进行远程 +连接的例子 + +31) 2010.7.19 +31.1) bugfix: master/aio_proxy/service_main.c, 释放异步流对象时有误 +31.2) feature: master/aio_proxy/service_main.c, 可以配置是否按行读 + +30) 2010.7.6: 2.1.2 beta 1 发布 +30.1) 增加了 xml/html 解析库 +30.2) 增加了 xml 库的测试例子 + +29) 2010.6.8 +29.1) samples: 增加了例子 vstream_unread 用于测试 acl_vstream_unread +及 acl_vstream_ungetc + +28) 2010.4.27 +28.1) samples: 增加了例子 master/aio_proxy + +27) 2010.4.11: 2.1.1 正式版本发布 + +26) 2010.3.27 +26.1) samples: aio/client, aio/server 增加了内存池选项 + +25) 2.1.1 rc1 +因为ACL的event模块支持WIN32平台的IOCP接口,所以准备发布一个小版本, +这样在WIN32下就可以编写高并发的高效非阻塞服务器了 + +24) 2.1.0 版本正式发布了! + +23) 2010.1.3 +23.1) 整理 win32 平台下的工程,在VC6,VC2003,VC2008 下编译通过 + +22) 2010.1.1 +22.1) 准备为发布 2.1.0 的正式稳定版本 + +21) 2009.11.13 +21.1) 所有库的编译过程都加上 -fPIC 选项,从面便于动态链接及动态加载 + +20) 2009.11.12 +20.1) 将版本号定为: 2.1.0.rc3 + +19) 2009.9.29 +19.1) 将版本号定为: 2.1.0.rc2 + +18) 2009.9.21 +18.1) 将版本号定为: 2.1.0.rc1 + +17) 2009.9.14 +17.1) lib_tls/lib_dict: 均支持WIN32平台 +17.2) 调整了VC的编译工程 + +16) 2009.8.16 +16.1) samples: master/, 增加了一个例子 ioctl_echo3 + +15) 2009.7.30 +15.1) lib_dict 增加了 tokyocabinet 的支持 + +14) 2009.7.24 +14.1) 将版本号定为了 2.1.0.beta3 + +13) 2009.7.24 +13.1) 将版本号定为了 2.1.0.beta2 + +12) 2009.7.14 +12.1) lib_tls: 经过数周工作,lib_tls 终于可以工作了, 例子参见 +samples/tls/ +12.2) lib_tls 是完全从 Postfix 移植过来,相关 license 请参见 +Postfix 的 license + +11) 2009.7.3 +11.1) 将 lib_dict, lib_tls 两个库并入 acl_project 中,这样 +acl_project 将会支持以BDB/CDB, etc 为存储的快速查询,同时 +acl_vstream 模块及以其为基础的通信模块将会方便地支持 ssl 协议 +11.2) 因为本版本增加的内容较多,所以版本将会有个较大的提高, +本版本将会提升为 2.1.0 +11.3) 因为随着 acl_project 中各个功能库的增加,在发布目录里将 +会进行重新调整, 所以在 dist/ 目录下将不再有单独的 lib_acl, +lib_project 两个目录,而是合而为一个存储目录,新的库也将统一 +存储在该目录下 + +10) 2009.6.16 +10.1) acl_project2.0.4 release now + +9) 2009.5.27 +9.1) 增加了 Makefile.glib 从而支持将 glib 编译进去 + +8) 2009.4.16 +8.1) 因为CVS对上传文件名的限制,将所有的 .keep 文件修改为 keep + +7) 2009.4.14 +7.1) prepare for acl_project2.0.4 + +6) 2009.1.4 +6.1) acl_project.2.02 版本发布, 主要是因为 acl_master +服务器框架现在支持配置重读功能 +6.2) compile: 用VC编译动态库时报错误, 需要包含 ws2_32.lib + +5) 2009.1.3 +5.1) samples/ping: 增加了 ping 的一个实现 + +4) 2008.12.22 +4.1) acl_project.2.01 版本发布 + +3) 2008.10.13 +3.1) samples/http_client: 支持了重定向功能 + +2) 2008.10.10 +2.1) samples/http_client: 完善了该例子 + +1) 2008.10.9 +1.1) 正式将ACL工程命名为 acl_project.2.00 版本发布 diff --git a/dist/lib/win32/vld.lib b/dist/lib/win32/vld.lib new file mode 100644 index 000000000..f9524d403 Binary files /dev/null and b/dist/lib/win32/vld.lib differ diff --git a/dist/master/bin/keep b/dist/master/bin/keep new file mode 100644 index 000000000..533667ccd --- /dev/null +++ b/dist/master/bin/keep @@ -0,0 +1,2 @@ +keepme + diff --git a/dist/master/conf/main.cf b/dist/master/conf/main.cf new file mode 100644 index 000000000..e0300233d --- /dev/null +++ b/dist/master/conf/main.cf @@ -0,0 +1,35 @@ + +#inet_interfaces = all +# 默认的每个服务的最大进程数 +default_process_limit = 250 +# 用户属主 +owner_user = root +master_owner = root +# 组主 +owner_group = root +# 如果子进程服务异常退出,重启该子进程服务的时间间隔(秒) +service_throttle_time = 60 +# 父进程进程名 +process_name = acl_master +#daemon_timeout = 18000 +buf_size = 81920 +# 父进程与子进程通信时的读写超时时间(秒) +rw_timeout = 60 +#max_use = 100 +#max_idle = 100 +#in_flow_delay = 1 +# 调用 select 循环时的等待秒级值 +event_delay_sec = 1 +# 调用 select 循环时的等待微秒级值 +event_delay_usec = 5000 +# 所有服务进程程序所在的目录 +daemon_directory = {install_path}/libexec +# acl_master 进程运行时的日志记录文件 +log_file = {install_path}/var/log/acl_master +# 所有服务进程的服务配置文件所在的目录 +service_directory = {install_path}/conf/service +queue_directory = {install_path}/var +# 记录 acl_master 运行时的进程号 +pid_file = {install_path}/var/pid/acl_master.pid +# 是否扫描并行 {install_path}/conf/service/ 目录下的子目录服务配置文件,0 -- 否,1 -- 是 +scan_subdir = 0 diff --git a/dist/master/conf/service/samples/aio_echo.cf b/dist/master/conf/service/samples/aio_echo.cf new file mode 100644 index 000000000..1d49939b5 --- /dev/null +++ b/dist/master/conf/service/samples/aio_echo.cf @@ -0,0 +1,92 @@ + +service server { +# 进程是否禁止运行 + master_disable = yes +# 服务地址及端口号 + master_service = 5200 + +# 服务监听为域套接口 +# master_service = aio_echo.sock +# 服务类型 + master_type = inet + +# 当子进程异常退出时,如果该值非空,则将子进程异常退出的消息通知该服务 +# master_notify_addr = 127.0.0.1:5801 +# 邮件通知接收者 +# master_notify_recipients = zhengshuxin@hotmail.com + +# 是否允许延迟接受客户端连接,如果为0则表示关闭该功能,如果大于0则表示打开此功能 +# 并且此值代表延迟接受连接的超时值,超过此值时如果客户端依然没有发来数据,则操作 +# 系统会在系统层直接关闭该连接 +# master_defer_accept = 0 +# master_type = unix +# 是否只允许私有访问, 如果为 y, 则域套接口创建在 {install_path}/var/log/private/ 目录下, +# 如果为 n, 则域套接口创建在 {install_path}/var/log/public/ 目录下, + master_private = n + master_unpriv = n +# 是否需要 chroot: n -- no, y -- yes + master_chroot = n +# 每隔多长时间触发一次,单位为秒(仅对 trigger 模式有效) + master_wakeup = - +# 最大进程数 + master_maxproc = 5 +# 需要预先启动的进程数,该值不应大于 master_maxproc + master_prefork = 2 +# 进程程序名 + master_command = aio_echo +# 进程启动参数,只能为: -u [是否允许以某普通用户的身份运行] + master_args = +# 传递给服务子进程的环境变量, 可以通过 getenv("SERVICE_ENV") 获得此值 + master_env = mempool_limit:512000000, mempool_use_mutex:true +# master_env = logme:FALSE, priority:E_LOG_INFO, action:E_LOG_PER_DAY, flush:sync_flush, imit_size:512,\ +# sync_action:E_LOG_SEM, sem_name:/tmp/aio_echo.sem +# 进程日志记录文件 + master_log = {install_path}/var/log/aio_echo.log + +# 是否允许产生 core 文件 +# aio_enable_core = 1 +# 每个进程实例处理连接数的最大次数,超过此值后进程实例主动退出 + aio_use_limit = 0 +# 每个进程实例的空闲超时时间,超过此值后进程实例主动退出 + aio_idle_limit = 0 +# 记录进程PID的位置(对于多进程实例来说没有意义) + aio_pid_dir = {install_path}/var/pid +# 进程运行时所在的路径 + aio_queue_dir = {install_path}/var +# 读写超时时间, 单位为秒 + aio_rw_timeout = 120 +# 读缓冲区的缓冲区大小 + aio_buf_size = 8192 +# 每次 accept 时的循环接收的最大次数 + aio_max_accept = 25 +# 进程运行时的用户身份 + aio_owner = root + +# 用 select 进行循环时的时间间隔 +# 单位为秒 + aio_delay_sec = 1 +# 单位为微秒 + aio_delay_usec = 500 +# 采用事件循环的方式: select(default), poll, kernel(epoll/devpoll/kqueue) + aio_event_mode = select +# 是否将 socket 接收与IO功能分开: yes/no, 如果为 yes 可以大大提高 accept() 速度 + aio_accept_alone = yes +# 线程池的最大线程数, 如果该值为0则表示采用单线程非阻塞模式. + aio_max_threads = 0 +# 每个线程的空闲时间. + aio_thread_idle_limit = 60 + +# 允许访问的客户端IP地址范围 + aio_access_allow = 127.0.0.1:255.255.255.255, 127.0.0.1:127.0.0.1 + +# 当 acl_master 退出时,如果该值置1则该程序不等所有连接处理完毕便立即退出 + aio_quick_abort = 1 +############################################################################ +# 应用自己的配置选项 + +# 每个客户端连接的空闲时间. + client_idle_limit = 60 +# 是否输出当前的内存状态信息 + debug_mem = 1 +} + diff --git a/dist/master/conf/service/samples/aio_proxy.cf b/dist/master/conf/service/samples/aio_proxy.cf new file mode 100644 index 000000000..88817dbd1 --- /dev/null +++ b/dist/master/conf/service/samples/aio_proxy.cf @@ -0,0 +1,100 @@ + +service server { +# 进程是否禁止运行 + master_disable = yes +# 服务地址及端口号 + master_service = 16667 + +# 服务监听为域套接口 +# master_service = aio_echo.sock +# 服务类型 + master_type = inet + +# 当子进程异常退出时,如果该值非空,则将子进程异常退出的消息通知该服务 +# master_notify_addr = 127.0.0.1:5801 +# 邮件通知接收者 +# master_notify_recipients = zhengshuxin@hotmail.com + +# 是否允许延迟接受客户端连接,如果为0则表示关闭该功能,如果大于0则表示打开此功能 +# 并且此值代表延迟接受连接的超时值,超过此值时如果客户端依然没有发来数据,则操作 +# 系统会在系统层直接关闭该连接 +# master_defer_accept = 0 +# master_type = unix +# 是否只允许私有访问, 如果为 y, 则域套接口创建在 {install_path}/var/log/private/ 目录下, +# 如果为 n, 则域套接口创建在 {install_path}/var/log/public/ 目录下, + master_private = n + master_unpriv = n +# 是否需要 chroot: n -- no, y -- yes + master_chroot = n +# 每隔多长时间触发一次,单位为秒(仅对 trigger 模式有效) + master_wakeup = - +# 最大进程数 + master_maxproc = 5 +# 需要预先启动的进程数,该值不应大于 master_maxproc + master_prefork = 0 +# 进程程序名 + master_command = aio_proxy +# 进程启动参数,只能为: -u [是否允许以某普通用户的身份运行] + master_args = +# 传递给服务子进程的环境变量, 可以通过 getenv("SERVICE_ENV") 获得此值 +# master_env = mempool_limit:512000000, mempool_use_mutex:true +# master_env = logme:FALSE, priority:E_LOG_INFO, action:E_LOG_PER_DAY, flush:sync_flush, imit_size:512,\ +# sync_action:E_LOG_SEM, sem_name:/tmp/aio_echo.sem +# 进程日志记录文件 + master_log = {install_path}/var/log/aio_proxy.log + +# 是否允许产生 core 文件 +# aio_enable_core = 1 +# 每个进程实例处理连接数的最大次数,超过此值后进程实例主动退出 + aio_use_limit = 0 +# 每个进程实例的空闲超时时间,超过此值后进程实例主动退出 + aio_idle_limit = 0 +# 记录进程PID的位置(对于多进程实例来说没有意义) + aio_pid_dir = {install_path}/var/pid +# 进程运行时所在的路径 + aio_queue_dir = {install_path}/var +# 读写超时时间, 单位为秒 + aio_rw_timeout = 120 +# 读缓冲区的缓冲区大小 + aio_buf_size = 8192 +# 每次 accept 时的循环接收的最大次数 + aio_max_accept = 25 +# 进程运行时的用户身份 + aio_owner = root + +# 用 select 进行循环时的时间间隔 +# 单位为秒 + aio_delay_sec = 1 +# 单位为微秒 + aio_delay_usec = 500 +# 采用事件循环的方式: select(default), poll, kernel(epoll/devpoll/kqueue) + aio_event_mode = select +# 是否将 socket 接收与IO功能分开: yes/no, 如果为 yes 可以大大提高 accept() 速度 + aio_accept_alone = yes +# 线程池的最大线程数, 如果该值为0则表示采用单线程非阻塞模式. + aio_max_threads = 0 +# 每个线程的空闲时间. + aio_thread_idle_limit = 60 + +# 允许访问的客户端IP地址范围 + aio_access_allow = 127.0.0.1:255.255.255.255, 127.0.0.1:127.0.0.1 + +# 当 acl_master 退出时,如果该值置1则该程序不等所有连接处理完毕便立即退出 + aio_quick_abort = 1 +############################################################################ +# 应用自己的配置选项 + +# 每个客户端连接的空闲时间. + io_idle_limit = 60 +# 是否输出当前的内存状态信息 + debug_mem = 1 +# 是否以行为单位读数据 + read_line = 1 +# 后端服务器地址 + backend_addr = 127.0.0.1:6667 +# 请求数据转存文件 + request_file = {install_path}/var/log/irc.txt +# 响应数据转存文件 + respond_file = {install_path}/var/log/irc.txt +} + diff --git a/dist/master/conf/service/samples/ioctl_echo.cf b/dist/master/conf/service/samples/ioctl_echo.cf new file mode 100644 index 000000000..6882566c7 --- /dev/null +++ b/dist/master/conf/service/samples/ioctl_echo.cf @@ -0,0 +1,114 @@ + +service server { +# 进程是否禁止运行 + master_disable = yes +# 服务地址及端口号 + master_service = 127.0.0.1:5001 + +# 服务监听为域套接口 +# master_service = aio_echo.sock +# 服务类型 + master_type = inet +# master_type = unix + +# 当子进程异常退出时,如果该值非空,则将子进程异常退出的消息通知该服务 +# master_notify_addr = 127.0.0.1:5801 +# 邮件通知接收者 +# master_notify_recipients = zhengshuxin@hotmail.com:13910404316 + +# 是否允许延迟接受客户端连接,如果为0则表示关闭该功能,如果大于0则表示打开此功能 +# 并且此值代表延迟接受连接的超时值,超过此值时如果客户端依然没有发来数据,则操作 +# 系统会在系统层直接关闭该连接 +# master_defer_accept = 0 +# 是否只允许私有访问, 如果为 y, 则域套接口创建在 {install_path}/var/log/private/ 目录下, +# 如果为 n, 则域套接口创建在 {install_path}/var/log/public/ 目录下, + master_private = n + master_unpriv = n +# 是否需要 chroot: n -- no, y -- yes + master_chroot = n +# 每隔多长时间触发一次,单位为秒(仅对 trigger 模式有效) + master_wakeup = - +# 最大进程数 + master_maxproc = 2 +# 需要预先启动的进程数,该值不应大于 master_maxproc + master_prefork = 2 +# 进程程序名 + master_command = ioctl_echo +# 进程日志记录文件 + master_log = {install_path}/var/log/ioctl_echo.log +# 进程启动参数,只能为: -u [是否允许以某普通用户的身份运行] +# master_args = +# 传递给服务子进程的环境变量, 可以通过 getenv("SERVICE_ENV") 获得此值 + master_env = mempool_limit:512000000 +# master_env = logme:FALSE, priority:E_LOG_INFO, action:E_LOG_PER_DAY, flush:sync_flush, imit_size:512,\ +# sync_action:E_LOG_SEM, sem_name:/tmp/ioctl_echo.sem + +# 是否允许产生 core 文件 +# ioctl_enable_core = 1 +# 每个进程实例处理连接数的最大次数,超过此值后进程实例主动退出 + ioctl_use_limit = 100 +# 每个进程实例的空闲超时时间,超过此值后进程实例主动退出 + ioctl_idle_limit = 120 +# 记录进程PID的位置(对于多进程实例来说没有意义) + ioctl_pid_dir = {install_path}/var/pid +# 进程运行时所在的路径 + ioctl_queue_dir = {install_path}/var +# 读写超时时间, 单位为秒 + ioctl_rw_timeout = 120 +# 读缓冲区的缓冲区大小 + ioctl_buf_size = 8192 +# 每次 accept 时的循环接收的最大次数 + ioctl_max_accept = 25 +# 在并发访问量非常低的情况下,如访问量在 10 次/秒 以下时,可以找开此值(即赋为1),以加速事件循环过程, +# 从而防止服务进程阻塞在 select 上的时间过长而影响访问速度 +# ioctl_enable_dog = 0 +# 进程运行时的用户身份 + ioctl_owner = root + +# 用 select 进行循环时的时间间隔 +# 单位为秒 + ioctl_delay_sec = 0 +# 单位为微秒 + ioctl_delay_usec = 500 + +# 采用事件循环的方式: select(default), poll, kernel(epoll/devpoll/kqueue) + ioctl_event_mode = select + +# 线程池的最大线程数 + ioctl_max_threads = 250 +# 线程的堆栈空间大小,单位为字节,0表示使用系统缺省值 + ioctl_stacksize = 0 +# 允许访问 udserver 的客户端IP地址范围 + ioctl_access_allow = 127.0.0.1:255.255.255.255, 127.0.0.1:127.0.0.1 + +# 当 acl_master 退出时,如果该值置1则该程序不等所有连接处理完毕便立即退出 + ioctl_quick_abort = 1 + +## app_main.c 需要的参数项 +# 客户端连接的最大空闲时间阀值 + app_client_idle_limit = 12 + +############################################################################ +# 应用自己的配置选项 + +# mysql 服务地址 +# mysql_dbaddr = /tmp/mysql.sock +# mysql_dbaddr = 10.0.250.199:3306 +# 连接 mysql 数据库的连接池的最大值 +# mysql_dbmax = 200 +# ping mysql 连接的间隔时间, 以秒为单位 +# mysql_dbping = 10 +# mysql 连接空闲的时间间隔, 以秒为单位 +# mysql_dbtimeout = 30 + +# 数据库名称 +# mysql_dbname = ioctl_db +# 数据库访问用户 +# mysql_dbuser = ioctl_user +# 数据库用户访问密码 +# mysql_dbpass = 111111 + +# 是否输出当前内存的状态信息 + debug_mem = 1 +} + diff --git a/dist/master/conf/service/samples/multi_echo.cf b/dist/master/conf/service/samples/multi_echo.cf new file mode 100644 index 000000000..f94c7d232 --- /dev/null +++ b/dist/master/conf/service/samples/multi_echo.cf @@ -0,0 +1,72 @@ +# service type private unpriv chroot wakeup maxproc command + args + +service multi +{ +# 进程是否禁止运行 + master_disable = yes +# 服务地址及端口号 + master_service = 5004 +# 服务监听为域套接口 +# master_service = multi_echo.sock +# 服务类型 +# tcp/ip 套接口 + master_type = inet +# 域套接口 +# master_type = unix + +# 当子进程异常退出时,如果该值非空,则将子进程异常退出的消息通知该服务 +# master_notify_addr = 127.0.0.1:5801 +# 邮件通知接收者 +# master_notify_recipients = zhengshuxin@hotmail.com + +# 是否允许延迟接受客户端连接,如果为0则表示关闭该功能,如果大于0则表示打开此功能 +# 并且此值代表延迟接受连接的超时值,超过此值时如果客户端依然没有发来数据,则操作 +# 系统会在系统层直接关闭该连接 +# master_defer_accept = 0 +# 是否只允许私有访问, 如果为 y, 则域套接口创建在 {install_path}/var/log/private/ 目录下, +# 如果为 n, 则域套接口创建在 {install_path}/var/log/public/ 目录下, + master_private = n + master_unpriv = n +# 是否需要 chroot: n -- no, y -- yes + master_chroot = n +# 每隔多长时间触发一次,单位为秒(仅对 trigger 模式有效) + master_wakeup = - +# 最大进程数 + master_maxproc = 10 +# 需要预先启动的进程数,该值不应大于 master_maxproc + master_prefork = 2 +# 进程程序名 + master_command = multi_echo +# 进程日志记录文件 + master_log = {install_path}/var/log/multi_echo.log +# 进程启动参数,只能为: -u [是否允许以某普通用户的身份运行] +# master_args = +# 传递给服务子进程的环境变量, 可以通过 getenv("SERVICE_ENV") 获得此值 + master_env = logme:FALSE, priority:E_LOG_INFO, action:E_LOG_PER_DAY, flush:sync_flush, imit_size:512,\ + sync_action:E_LOG_SEM, sem_name:/tmp/multi_echo.sem + +# 是否允许产生 core 文件 +# multi_enable_core = 1 +# 每个进程实例处理连接数的最大次数,超过此值后进程实例主动退出 + multi_use_limit = 250 +# 每个进程实例的空闲超时时间,超过此值后进程实例主动退出 +# multi_idle_limit = 180 +# 记录进程PID的位置(对于多进程实例来说没有意义) + multi_pid_dir = {install_path}/var/pid +# 进程运行时所在的路径 + multi_queue_dir = {install_path}/var +# 读写超时时间, 单位为秒 + multi_rw_timeout = 1800 +# 读缓冲区的缓冲区大小 + multi_buf_size = 8192 + +# multi_in_flow_delay = 1 +# 进程运行时的用户身份 +# multi_owner = root +# 用 select 进行循环时的时间间隔 +# 单位为秒 +# multi_delay_sec = 1 +# 单位为微秒 +# multi_delay_usec = 5000 +# multi_daemon_timeout = 1800 +} diff --git a/dist/master/conf/service/samples/multi_proxy.cf b/dist/master/conf/service/samples/multi_proxy.cf new file mode 100644 index 000000000..4500147df --- /dev/null +++ b/dist/master/conf/service/samples/multi_proxy.cf @@ -0,0 +1,39 @@ +# service type private unpriv chroot wakeup maxproc command + args + +service proxy +{ + master_disable = yes + master_service = 5002 + master_type = inet + master_private = n + master_unpriv = n + master_chroot = n + master_wakeup = - + master_maxproc = 1 +# 需要预先启动的进程数,该值不应大于 master_maxproc + master_prefork = 2 + master_command = multi_proxy + master_log = {install_path}/var/log/multi_proxy.log +# master_args = + + multi_use_limit = 0 + multi_pid_dir = {install_path}/var/pid + multi_queue_dir = {install_path}/var + multi_rw_timeout = 0 + multi_buf_size = 8192 + +# multi_in_flow_delay = 1 + multi_idle_limit = 600 +# multi_owner = owner + multi_delay_sec = 1 + multi_delay_usec = 5000 +# multi_daemon_timeout = 1800 + + proxy_debug_request = 1 + proxy_request_file = {install_path}/var/log/request.log + proxy_debug_respond = 1 + proxy_respond_file = {install_path}/var/log/respond.log + proxy_backend_addr = 127.0.0.1:80 +# proxy_timeout = 60 + proxy_bufsize = 8192 +} diff --git a/dist/master/conf/service/samples/single_echo.cf b/dist/master/conf/service/samples/single_echo.cf new file mode 100644 index 000000000..e846b905c --- /dev/null +++ b/dist/master/conf/service/samples/single_echo.cf @@ -0,0 +1,71 @@ +# service type private unpriv chroot wakeup maxproc command + args + +service single +{ +# 进程是否禁止运行 + master_disable = yes +# 服务地址及端口号 + master_service = :5003 +# 服务监听为域套接口 +# master_service = single_echo.sock +# 服务类型 + master_type = inet +# master_type = unix + +# 当子进程异常退出时,如果该值非空,则将子进程异常退出的消息通知该服务 +# master_notify_addr = 127.0.0.1:5801 +# 邮件通知接收者 +# master_notify_recipients = zhengshuxin@hotmail.com + +# 是否允许延迟接受客户端连接,如果为0则表示关闭该功能,如果大于0则表示打开此功能 +# 并且此值代表延迟接受连接的超时值,超过此值时如果客户端依然没有发来数据,则操作 +# 系统会在系统层直接关闭该连接 +# master_defer_accept = 0 +# 是否只允许私有访问, 如果为 y, 则域套接口创建在 {install_path}/var/log/private/ 目录下, +# 如果为 n, 则域套接口创建在 {install_path}/var/log/public/ 目录下, + master_private = n + master_unpriv = n +# 是否需要 chroot: n -- no, y -- yes + master_chroot = n +# 每隔多长时间触发一次,单位为秒(仅对 trigger 模式有效) + master_wakeup = - +# 最大进程数 + master_maxproc = 10 +# 需要预先启动的进程数,该值不应大于 master_maxproc + master_prefork = 2 +# 进程程序名 + master_command = single_echo +# 进程启动参数,只能为: -u [是否允许以某普通用户的身份运行] +# master_args = +# 进程日志记录文件 + master_log = {install_path}/var/log/single_echo.log +# 传递给服务子进程的环境变量, 可以通过 getenv("SERVICE_ENV") 获得此值 + master_env = logme:FALSE, priority:E_LOG_INFO, action:E_LOG_PER_DAY, flush:sync_flush, imit_size:512,\ + sync_action:E_LOG_SEM, sem_name:/tmp/single_echo.sem + +# 是否允许产生 core 文件 +# single_enable_core = 1 +# 每个进程实例处理连接数的最大次数,超过此值后进程实例主动退出 + single_use_limit = 250 +# 每个进程实例的空闲超时时间,超过此值后进程实例主动退出 +# single_idle_limit = 180 +# 记录进程PID的位置(对于多进程实例来说没有意义) + single_pid_dir = {install_path}/var/pid +# 进程运行时所在的路径 + single_queue_dir = {install_path}/var +# 读写超时时间, 单位为秒 + single_rw_timeout = 1800 +# 读缓冲区的缓冲区大小 + single_buf_size = 8192 +# 进程运行时的用户身份 + single_owner = root + +# single_in_flow_delay = 1 +# single_owner = owner +# 用 select 进行循环时的时间间隔 +# 单位为秒 +# single_delay_sec = 1 +# 单位为微秒 +# single_delay_usec = 5000 +# single_daemon_timeout = 1800 +} diff --git a/dist/master/conf/service/samples/single_proxy.cf b/dist/master/conf/service/samples/single_proxy.cf new file mode 100644 index 000000000..4f2950507 --- /dev/null +++ b/dist/master/conf/service/samples/single_proxy.cf @@ -0,0 +1,40 @@ +# service type private unpriv chroot wakeup maxproc command + args + +service proxy +{ + master_disable = yes + master_service = 5006 + master_type = inet + master_private = n + master_unpriv = n + master_chroot = n + master_wakeup = - + master_maxproc = 20 +# 需要预先启动的进程数,该值不应大于 master_maxproc + master_prefork = 2 + master_command = single_proxy + master_log = {install_path}/var/log/single_proxy.log +# master_args = + + single_use_limit = 0 + single_pid_dir = {install_path}/var/pid + single_queue_dir = {install_path}/var + single_rw_timeout = 180 + single_buf_size = 8192 + +# single_in_flow_delay = 1 +# single_idle_limit = 600 +# single_owner = owner +# single_delay_sec = 1 +# single_delay_usec = 5000 +# single_daemon_timeout = 1800 +# single_use_limit = 10 + + proxy_backend_addr = 127.0.0.1:80 + proxy_host_allow = [127.0.0.1, 127.0.0.1], \ + [10.0.0.0, 10.0.255.255], \ + [202.99.16.0, 202.99.16.255], \ + [60.28.250.0, 60.28.250.255], \ + [60.28.251.0, 60.28.261.255] +# proxy_timeout = 60 +} diff --git a/dist/master/conf/service/samples/trigger.cf b/dist/master/conf/service/samples/trigger.cf new file mode 100644 index 000000000..6181bf9d2 --- /dev/null +++ b/dist/master/conf/service/samples/trigger.cf @@ -0,0 +1,60 @@ +# service type private unpriv chroot wakeup maxproc command + args + +service trigger +{ +# 进程是否禁止运行 + master_disable = yes +# 服务监听为域套接口 + master_service = trigger.sock +# 服务类型 + master_type = unix + +# 当子进程异常退出时,如果该值非空,则将子进程异常退出的消息通知该服务 +# master_notify_addr = 127.0.0.1:5801 +# 邮件通知接收者 +# master_notify_recipients = zhengshuxin@hotmail.com + +# 是否只允许私有访问, 如果为 y, 则域套接口创建在 {install_path}/var/log/private/ 目录下, +# 如果为 n, 则域套接口创建在 {install_path}/var/log/public/ 目录下, + master_private = y + master_unpriv = n +# 是否需要 chroot: n -- no, y -- yes + master_chroot = n +# 每隔多长时间触发一次,单位为秒(仅对 trigger 模式有效) + master_wakeup = 4 +# 最大进程数 + master_maxproc = 10 +# 需要预先启动的进程数,该值不应大于 master_maxproc + master_prefork = 2 +# 进程程序名 + master_command = trigger +# 进程启动参数,只能为: -u [是否允许以某普通用户的身份运行] +# master_args = +# 进程日志记录文件 + master_log = {install_path}/var/log/trigger.log +# 传递给服务子进程的环境变量, 可以通过 getenv("SERVICE_ENV") 获得此值 +# master_env = logme:FALSE, priority:E_LOG_INFO, action:E_LOG_PER_DAY, flush:sync_flush, imit_size:512,\ +# sync_action:E_LOG_SEM, sem_name:/tmp/trigger.sem + +# 是否允许产生 core 文件 +# trigger_enable_core = 1 +# 每个进程实例处理连接数的最大次数,超过此值后进程实例主动退出 + trigger_use_limit = 250 +# 记录进程PID的位置(对于多进程实例来说没有意义) + trigger_pid_dir = {install_path}/var/pid +# 进程运行时所在的路径 + trigger_queue_dir = {install_path}/var +# 读写超时时间, 单位为秒 + trigger_rw_timeout = 1800 +# 读缓冲区的缓冲区大小 + trigger_buf_size = 8192 + +# 进程运行时的用户身份 + trigger_owner = owner +# 用 select 进行循环时的时间间隔 +# 单位为秒 +# trigger_delay_sec = 1 +# 单位为微秒 +# trigger_delay_usec = 5000 +# trigger_daemon_timeout = 1800 +} diff --git a/dist/master/sbin/keep b/dist/master/sbin/keep new file mode 100644 index 000000000..533667ccd --- /dev/null +++ b/dist/master/sbin/keep @@ -0,0 +1,2 @@ +keepme + diff --git a/dist/master/setup.sh b/dist/master/setup.sh new file mode 100644 index 000000000..a9565f2de --- /dev/null +++ b/dist/master/setup.sh @@ -0,0 +1,174 @@ +#!/bin/sh + +############################################################################### +PATH=/bin:/usr/bin:/usr/sbin:/usr/etc:/sbin:/etc +tempdir="/tmp" + +umask 022 + +censored_ls() { + ls "$@" | egrep -v '^\.|/\.|CVS|RCS|SCCS|linux\.d|solaris\.d|hp_ux\.d|example|service' +} + +compare_or_replace() { + (cmp $2 $3 >/dev/null 2>&1 && echo Skipping $3...) || { + echo Updating $3... + rm -f $tempdir/junk || exit 1 + cp $2 $tempdir/junk || exit 1 + chmod $1 $tempdir/junk || exit 1 + mv -f $tempdir/junk $3 || exit 1 + chmod $1 $3 || exit 1 + } +} +############################################################################### +RPATH= +guess_os() { + os_name=`uname -s` + os_type=`uname -p` + case $os_name in + Linux) + case $os_type in + x86_64) + RPATH="linux64" + ;; + i686) + RPATH="linux32" + ;; + *) + echo "unknown OS - $os_name $os_type" + exit 1 + ;; + esac + ;; + SunOS) + case $os_type in + i386) + RPATH="sunos_x86" + ;; + *) + echo "unknown OS - $os_name $os_type" + exit 1 + ;; + esac + ;; + FreeBSD) + RPATH="freebsd" + ;; + *) + echo "unknown OS - $os_name $os_type" + exit 1 + ;; + esac +} + +create_path() +{ + test -d $1 || mkdir -p $1 || { + echo "can't mkdir $1" + exit 1 + } +} + +copy_file() +{ + for file in `censored_ls $2` + do + test -f $2/$file && { + compare_or_replace $1 $2/$file $3/$file || { + echo "copy file: $2/$file error" + exit 1 + } + } + done +} + +install_file() +{ + for file in `censored_ls $2` + do + rm -f $tempdir/junk2 || { + echo "can't remove file: $tempdir/junk2" + exit 1 + } + test -f $2/$file && { + cat $2/$file | sed -e 's;{install_path};'$INSTALL_PATH';;' >$tempdir/junk2 || { + echo "can't create file: $tempdir/junk2" + exit 1 + } + compare_or_replace $1 $tempdir/junk2 $3/$file || { + echo "can't move to file: $3/$file" + exit 1 + } + } + rm -f $tempdir/junk2 || { + echo "can't remove file: $tempdir/junk2" + exit 1 + } + done +} + +############################################################################### +INSTALL_PATH= + +if [ $# -lt 1 ] +then + echo "parameter not enougth($#)" + echo "usage:$0 install_path" + exit 1 +fi + +INSTALL_PATH=$1 + +case $INSTALL_PATH in +/*) ;; +no) ;; +*) echo Error: $INSTALL_PATH should be an absolute path name. 1>&2; exit 1;; +esac + +echo Installing to $INSTALL_PATH... + +BIN_PATH=$INSTALL_PATH/bin +SBIN_PATH=$INSTALL_PATH/sbin +CONF_PATH=$INSTALL_PATH/conf +SERVICE_PATH=$CONF_PATH/service +LIBEXEC_PATH=$INSTALL_PATH/libexec +SH_PATH=$INSTALL_PATH/sh +VAR_PATH=$INSTALL_PATH/var + +############################################################################### +create_all_path() +{ + create_path $INSTALL_PATH + create_path $BIN_PATH + create_path $SBIN_PATH + create_path $LIBEXEC_PATH + create_path $SH_PATH + create_path $CONF_PATH + create_path $SERVICE_PATH + create_path $SERVICE_PATH/samples + create_path $VAR_PATH + create_path $VAR_PATH/log + create_path $VAR_PATH/pid + create_path $VAR_PATH/private + create_path $VAR_PATH/public + + chmod 700 $VAR_PATH/private + chmod 1777 $VAR_PATH/log +} + +copy_all_file() +{ + copy_file a+x,go+rx bin $BIN_PATH + copy_file a+x,go+rx sbin $SBIN_PATH + copy_file a+x,go+rx libexec/$RPATH $LIBEXEC_PATH + install_file a+x,go-wrx sh $SH_PATH + install_file a+x,go-wrx conf $CONF_PATH + install_file a+x,go-wrx conf/service $SERVICE_PATH + install_file a+x,go-wrx conf/service/samples $SERVICE_PATH/samples +} + +guess_os +create_all_path +copy_all_file + +############################################################################### diff --git a/dist/master/sh/reload.sh b/dist/master/sh/reload.sh new file mode 100644 index 000000000..70deda21f --- /dev/null +++ b/dist/master/sh/reload.sh @@ -0,0 +1,6 @@ +#!/bin/sh + +HOME_PATH={install_path} +PID_FILE=$HOME_PATH/var/pid/acl_master.pid +kill -HUP `sed 1q $PID_FILE` + diff --git a/dist/master/sh/start.sh b/dist/master/sh/start.sh new file mode 100644 index 000000000..964d9d78b --- /dev/null +++ b/dist/master/sh/start.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +HOME_PATH={install_path} +trap '' 1 +ulimit -c unlimited +#$HOME_PATH/libexec/acl_master -v -c $HOME_PATH/conf -l $HOME_PATH/var/log/acl_master& +$HOME_PATH/libexec/acl_master -c $HOME_PATH/conf -l $HOME_PATH/var/log/acl_master& diff --git a/dist/master/sh/stop.sh b/dist/master/sh/stop.sh new file mode 100644 index 000000000..1982413fd --- /dev/null +++ b/dist/master/sh/stop.sh @@ -0,0 +1,13 @@ +#!/bin/sh + +HOME_PATH={install_path} +PID_FILE=$HOME_PATH/var/pid/acl_master.pid +if [ -f $PID_FILE ]; then + echo "stoping master service now ..." + kill `sed 1q $PID_FILE` + rm -f $PID_FILE + echo "master serivce stoped!" +else + echo "master service not running!" +fi + diff --git a/dist/master/var/keep b/dist/master/var/keep new file mode 100644 index 000000000..533667ccd --- /dev/null +++ b/dist/master/var/keep @@ -0,0 +1,2 @@ +keepme + diff --git a/doc/acl.pptx b/doc/acl.pptx new file mode 100644 index 000000000..e70b0ecde Binary files /dev/null and b/doc/acl.pptx differ diff --git a/doc/acl_api.ppt b/doc/acl_api.ppt new file mode 100644 index 000000000..3c1c7dc64 Binary files /dev/null and b/doc/acl_api.ppt differ diff --git a/doc/acl_cpp_help.ppt b/doc/acl_cpp_help.ppt new file mode 100644 index 000000000..87985127d Binary files /dev/null and b/doc/acl_cpp_help.ppt differ diff --git a/doc/acl_samples.pdf b/doc/acl_samples.pdf new file mode 100644 index 000000000..f280db0e4 Binary files /dev/null and b/doc/acl_samples.pdf differ diff --git a/doc/beanstalk_cn.pdf b/doc/beanstalk_cn.pdf new file mode 100644 index 000000000..9466d1b64 Binary files /dev/null and b/doc/beanstalk_cn.pdf differ diff --git a/doc/beanstalk_en.txt b/doc/beanstalk_en.txt new file mode 100644 index 000000000..ec37d9b03 --- /dev/null +++ b/doc/beanstalk_en.txt @@ -0,0 +1,631 @@ += Beanstalk Protocol = + +Protocol +-------- + +The beanstalk protocol runs over TCP using ASCII encoding. Clients connect, +send commands and data, wait for responses, and close the connection. For each +connection, the server processes commands serially in the order in which they +were received and sends responses in the same order. All integers in the +protocol are formatted in decimal and (unless otherwise indicated) +nonnegative. + +Names, in this protocol, are ASCII strings. They may contain letters (A-Z and +a-z), numerals (0-9), hyphen ("-"), plus ("+"), slash ("/"), semicolon (";"), +dot ("."), dollar-sign ("$"), and parentheses ("(" and ")"), but they may not +begin with a hyphen. They are terminated by white space (either a space char or +end of line). Each name must be at least one character long. + +The protocol contains two kinds of data: text lines and unstructured chunks of +data. Text lines are used for client commands and server responses. Chunks are +used to transfer job bodies and stats information. Each job body is an opaque +sequence of bytes. The server never inspects or modifies a job body and always +sends it back in its original form. It is up to the clients to agree on a +meaningful interpretation of job bodies. + +There is no command to close the connection -- the client may simply close the +TCP connection when it no longer has use for the server. However, beanstalkd +performs very well with a large number of open connections, so it is usually +better for the client to keep its connection open and reuse it as much as +possible. This also avoids the overhead of establishing new TCP connections. + +If a client violates the protocol (such as by sending a request that is not +well-formed or a command that does not exist) or if the server has an error, +the server will reply with one of the following error messages: + + - "OUT_OF_MEMORY\r\n" The server cannot allocate enough memory for the job. + The client should try again later. + + - "INTERNAL_ERROR\r\n" This indicates a bug in the server. It should never + happen. If it does happen, please report it at + http://groups.google.com/group/beanstalk-talk. + + - "DRAINING\r\n" This means that the server has been put into "drain mode" + and is no longer accepting new jobs. The client should try another server + or disconnect and try again later. + + - "BAD_FORMAT\r\n" The client sent a command line that was not well-formed. + This can happen if the line does not end with \r\n, if non-numeric + characters occur where an integer is expected, if the wrong number of + arguments are present, or if the command line is mal-formed in any other + way. + + - "UNKNOWN_COMMAND\r\n" The client sent a command that the server does not + know. + +These error responses will not be listed in this document for individual +commands in the following sections, but they are implicitly included in the +description of all commands. Clients should be prepared to receive an error +response after any command. + +As a last resort, if the server has a serious error that prevents it from +continuing service to the current client, the server will close the +connection. + +Job Lifecycle +------------- + +A job in beanstalk gets created by a client with the "put" command. During its +life it can be in one of four states: "ready", "reserved", "delayed", or +"buried". After the put command, a job typically starts out ready. It waits in +the ready queue until a worker comes along and runs the "reserve" command. If +this job is next in the queue, it will be reserved for the worker. The worker +will execute the job; when it is finished the worker will send a "delete" +command to delete the job. + +Here is a picture of the typical job lifecycle: + + + put reserve delete + -----> [READY] ---------> [RESERVED] --------> *poof* + + + +Here is a picture with more possibilities: + + + + put with delay release with delay + ----------------> [DELAYED] <------------. + | | + | (time passes) | + | | + put v reserve | delete + -----------------> [READY] ---------> [RESERVED] --------> *poof* + ^ ^ | | + | \ release | | + | `-------------' | + | | + | kick | + | | + | bury | + [BURIED] <---------------' + | + | delete + `--------> *poof* + + +The system has one or more tubes. Each tube consists of a ready queue and a +delay queue. Each job spends its entire life in one tube. Consumers can show +interest in tubes by sending the "watch" command; they can show disinterest by +sending the "ignore" command. This set of interesting tubes is said to be a +consumer's "watch list". When a client reserves a job, it may come from any of +the tubes in its watch list. + +When a client connects, its watch list is initially just the tube named +"default". If it submits jobs without having sent a "use" command, they will +live in the tube named "default". + +Tubes are created on demand whenever they are referenced. If a tube is empty +(that is, it contains no ready, delayed, or buried jobs) and no client refers +to it, it will be deleted. + +Producer Commands +----------------- + +The "put" command is for any process that wants to insert a job into the queue. +It comprises a command line followed by the job body: + +put \r\n +\r\n + +It inserts a job into the client's currently used tube (see the "use" command +below). + + - is an integer < 2**32. Jobs with smaller priority values will be + scheduled before jobs with larger priorities. The most urgent priority is 0; + the least urgent priority is 4294967295. + + - is an integer number of seconds to wait before putting the job in + the ready queue. The job will be in the "delayed" state during this time. + + - -- time to run -- is an integer number of seconds to allow a worker + to run this job. This time is counted from the moment a worker reserves + this job. If the worker does not delete, release, or bury the job within + seconds, the job will time out and the server will release the job. + The minimum ttr is 1. If the client sends 0, the server will silently + increase the ttr to 1. + + - is an integer indicating the size of the job body, not including the + trailing "\r\n". This value must be less than max-job-size (default: 2**16). + + - is the job body -- a sequence of bytes of length from the + previous line. + +After sending the command line and body, the client waits for a reply, which +may be: + + - "INSERTED \r\n" to indicate success. + + - is the integer id of the new job + + - "BURIED \r\n" if the server ran out of memory trying to grow the + priority queue data structure. + + - is the integer id of the new job + + - "EXPECTED_CRLF\r\n" The job body must be followed by a CR-LF pair, that is, + "\r\n". These two bytes are not counted in the job size given by the client + in the put command line. + + - "JOB_TOO_BIG\r\n" The client has requested to put a job with a body larger + than max-job-size bytes. + +The "use" command is for producers. Subsequent put commands will put jobs into +the tube specified by this command. If no use command has been issued, jobs +will be put into the tube named "default". + +use \r\n + + - is a name at most 200 bytes. It specifies the tube to use. If the + tube does not exist, it will be created. + +The only reply is: + +USING \r\n + + - is the name of the tube now being used. + +Worker Commands +--------------- + +A process that wants to consume jobs from the queue uses "reserve", "delete", +"release", and "bury". The first worker command, "reserve", looks like this: + +reserve\r\n + +Alternatively, you can specify a timeout as follows: + +reserve-with-timeout \r\n + +This will return a newly-reserved job. If no job is available to be reserved, +beanstalkd will wait to send a response until one becomes available. Once a +job is reserved for the client, the client has limited time to run (TTR) the +job before the job times out. When the job times out, the server will put the +job back into the ready queue. Both the TTR and the actual time left can be +found in response to the stats-job command. + +A timeout value of 0 will cause the server to immediately return either a +response or TIMED_OUT. A positive value of timeout will limit the amount of +time the client will block on the reserve request until a job becomes +available. + +During the TTR of a reserved job, the last second is kept by the server as a +safety margin, during which the client will not be made to wait for another +job. If the client issues a reserve command during the safety margin, or if +the safety margin arrives while the client is waiting on a reserve command, +the server will respond with: + +DEADLINE_SOON\r\n + +This gives the client a chance to delete or release its reserved job before +the server automatically releases it. + +TIMED_OUT\r\n + +If a non-negative timeout was specified and the timeout exceeded before a job +became available, the server will respond with TIMED_OUT. + +Otherwise, the only other response to this command is a successful reservation +in the form of a text line followed by the job body: + +RESERVED \r\n +\r\n + + - is the job id -- an integer unique to this job in this instance of + beanstalkd. + + - is an integer indicating the size of the job body, not including + the trailing "\r\n". + + - is the job body -- a sequence of bytes of length from the + previous line. This is a verbatim copy of the bytes that were originally + sent to the server in the put command for this job. + +The delete command removes a job from the server entirely. It is normally used +by the client when the job has successfully run to completion. A client can +delete jobs that it has reserved, ready jobs, and jobs that are buried. The +delete command looks like this: + +delete \r\n + + - is the job id to delete. + +The client then waits for one line of response, which may be: + + - "DELETED\r\n" to indicate success. + + - "NOT_FOUND\r\n" if the job does not exist or is not either reserved by the + client, ready, or buried. This could happen if the job timed out before the + client sent the delete command. + +The release command puts a reserved job back into the ready queue (and marks +its state as "ready") to be run by any client. It is normally used when the job +fails because of a transitory error. It looks like this: + +release \r\n + + - is the job id to release. + + - is a new priority to assign to the job. + + - is an integer number of seconds to wait before putting the job in + the ready queue. The job will be in the "delayed" state during this time. + +The client expects one line of response, which may be: + + - "RELEASED\r\n" to indicate success. + + - "BURIED\r\n" if the server ran out of memory trying to grow the priority + queue data structure. + + - "NOT_FOUND\r\n" if the job does not exist or is not reserved by the client. + +The bury command puts a job into the "buried" state. Buried jobs are put into a +FIFO linked list and will not be touched by the server again until a client +kicks them with the "kick" command. + +The bury command looks like this: + +bury \r\n + + - is the job id to release. + + - is a new priority to assign to the job. + +There are two possible responses: + + - "BURIED\r\n" to indicate success. + + - "NOT_FOUND\r\n" if the job does not exist or is not reserved by the client. + +The "touch" command allows a worker to request more time to work on a job. +This is useful for jobs that potentially take a long time, but you still want +the benefits of a TTR pulling a job away from an unresponsive worker. A worker +may periodically tell the server that it's still alive and processing a job +(e.g. it may do this on DEADLINE_SOON). + +The touch command looks like this: + +touch \r\n + + - is the ID of a job reserved by the current connection. + +There are two possible responses: + + - "TOUCHED\r\n" to indicate success. + + - "NOT_FOUND\r\n" if the job does not exist or is not reserved by the client. + +The "watch" command adds the named tube to the watch list for the current +connection. A reserve command will take a job from any of the tubes in the +watch list. For each new connection, the watch list initially consists of one +tube, named "default". + +watch \r\n + + - is a name at most 200 bytes. It specifies a tube to add to the watch + list. If the tube doesn't exist, it will be created. + +The reply is: + +WATCHING \r\n + + - is the integer number of tubes currently in the watch list. + +The "ignore" command is for consumers. It removes the named tube from the +watch list for the current connection. + +ignore \r\n + +The reply is one of: + + - "WATCHING \r\n" to indicate success. + + - is the integer number of tubes currently in the watch list. + + - "NOT_IGNORED\r\n" if the client attempts to ignore the only tube in its + watch list. + +Other Commands +-------------- + +The peek commands let the client inspect a job in the system. There are four +variations. All but the first operate only on the currently used tube. + + - "peek \r\n" - return job . + + - "peek-ready\r\n" - return the next ready job. + + - "peek-delayed\r\n" - return the delayed job with the shortest delay left. + + - "peek-buried\r\n" - return the next job in the list of buried jobs. + +There are two possible responses, either a single line: + + - "NOT_FOUND\r\n" if the requested job doesn't exist or there are no jobs in + the requested state. + +Or a line followed by a chunk of data, if the command was successful: + +FOUND \r\n +\r\n + + - is the job id. + + - is an integer indicating the size of the job body, not including + the trailing "\r\n". + + - is the job body -- a sequence of bytes of length from the + previous line. + +The kick command applies only to the currently used tube. It moves jobs into +the ready queue. If there are any buried jobs, it will only kick buried jobs. +Otherwise it will kick delayed jobs. It looks like: + +kick \r\n + + - is an integer upper bound on the number of jobs to kick. The server + will kick no more than jobs. + +The response is of the form: + +KICKED \r\n + + - is an integer indicating the number of jobs actually kicked. + +The stats-job command gives statistical information about the specified job if +it exists. Its form is: + +stats-job \r\n + + - is a job id. + +The response is one of: + + - "NOT_FOUND\r\n" if the job does not exist. + + - "OK \r\n\r\n" + + - is the size of the following data section in bytes. + + - is a sequence of bytes of length from the previous line. It + is a YAML file with statistical information represented a dictionary. + +The stats-job data is a YAML file representing a single dictionary of strings +to scalars. It contains these keys: + + - "id" is the job id + + - "tube" is the name of the tube that contains this job + + - "state" is "ready" or "delayed" or "reserved" or "buried" + + - "pri" is the priority value set by the put, release, or bury commands. + + - "age" is the time in seconds since the put command that created this job. + + - "time-left" is the number of seconds left until the server puts this job + into the ready queue. This number is only meaningful if the job is + reserved or delayed. If the job is reserved and this amount of time + elapses before its state changes, it is considered to have timed out. + + - "timeouts" is the number of times this job has timed out during a + reservation. + + - "releases" is the number of times a client has released this job from a + reservation. + + - "buries" is the number of times this job has been buried. + + - "kicks" is the number of times this job has been kicked. + +The stats-tube command gives statistical information about the specified tube +if it exists. Its form is: + +stats-tube \r\n + + - is a name at most 200 bytes. Stats will be returned for this tube. + +The response is one of: + + - "NOT_FOUND\r\n" if the tube does not exist. + + - "OK \r\n\r\n" + + - is the size of the following data section in bytes. + + - is a sequence of bytes of length from the previous line. It + is a YAML file with statistical information represented a dictionary. + +The stats-tube data is a YAML file representing a single dictionary of strings +to scalars. It contains these keys: + + - "name" is the tube's name. + + - "current-jobs-urgent" is the number of ready jobs with priority < 1024 in + this tube. + + - "current-jobs-ready" is the number of jobs in the ready queue in this tube. + + - "current-jobs-reserved" is the number of jobs reserved by all clients in + this tube. + + - "current-jobs-delayed" is the number of delayed jobs in this tube. + + - "current-jobs-buried" is the number of buried jobs in this tube. + + - "total-jobs" is the cumulative count of jobs created in this tube. + + - "current-waiting" is the number of open connections that have issued a + reserve command while watching this tube but not yet received a response. + +The stats command gives statistical information about the system as a whole. +Its form is: + +stats\r\n + +The server will respond: + +OK \r\n +\r\n + + - is the size of the following data section in bytes. + + - is a sequence of bytes of length from the previous line. It + is a YAML file with statistical information represented a dictionary. + +The stats data for the system is a YAML file representing a single dictionary +of strings to scalars. It contains these keys: + + - "current-jobs-urgent" is the number of ready jobs with priority < 1024. + + - "current-jobs-ready" is the number of jobs in the ready queue. + + - "current-jobs-reserved" is the number of jobs reserved by all clients. + + - "current-jobs-delayed" is the number of delayed jobs. + + - "current-jobs-buried" is the number of buried jobs. + + - "cmd-put" is the cumulative number of put commands. + + - "cmd-peek" is the cumulative number of peek commands. + + - "cmd-peek-ready" is the cumulative number of peek-ready commands. + + - "cmd-peek-delayed" is the cumulative number of peek-delayed commands. + + - "cmd-peek-buried" is the cumulative number of peek-buried commands. + + - "cmd-reserve" is the cumulative number of reserve commands. + + - "cmd-use" is the cumulative number of use commands. + + - "cmd-watch" is the cumulative number of watch commands. + + - "cmd-ignore" is the cumulative number of ignore commands. + + - "cmd-delete" is the cumulative number of delete commands. + + - "cmd-release" is the cumulative number of release commands. + + - "cmd-bury" is the cumulative number of bury commands. + + - "cmd-kick" is the cumulative number of kick commands. + + - "cmd-stats" is the cumulative number of stats commands. + + - "cmd-stats-job" is the cumulative number of stats-job commands. + + - "cmd-stats-tube" is the cumulative number of stats-tube commands. + + - "cmd-list-tubes" is the cumulative number of list-tubes commands. + + - "cmd-list-tube-used" is the cumulative number of list-tube-used commands. + + - "cmd-list-tubes-watched" is the cumulative number of list-tubes-watched + commands. + + - "job-timeouts" is the cumulative count of times a job has timed out. + + - "total-jobs" is the cumulative count of jobs created. + + - "max-job-size" is the maximum number of bytes in a job. + + - "current-tubes" is the number of currently-existing tubes. + + - "current-connections" is the number of currently open connections. + + - "current-producers" is the number of open connections that have each + issued at least one put command. + + - "current-workers" is the number of open connections that have each issued + at least one reserve command. + + - "current-waiting" is the number of open connections that have issued a + reserve command but not yet received a response. + + - "total-connections" is the cumulative count of connections. + + - "pid" is the process id of the server. + + - "version" is the version string of the server. + + - "rusage-utime" is the accumulated user CPU time of this process in seconds + and microseconds. + + - "rusage-stime" is the accumulated system CPU time of this process in + seconds and microseconds. + + - "uptime" is the number of seconds since this server started running. + + - "binlog-oldest-index" is the index of the oldest binlog file needed to + store the current jobs + + - "binlog-current-index" is the index of the current binlog file being + written to. If binlog is not active this value will be 0 + + - "binlog-max-size" is the maximum size in bytes a binlog file is allowed + to get before a new binlog file is opened + +The list-tubes command returns a list of all existing tubes. Its form is: + +list-tubes\r\n + +The response is: + +OK \r\n +\r\n + + - is the size of the following data section in bytes. + + - is a sequence of bytes of length from the previous line. It + is a YAML file containing all tube names as a list of strings. + +The list-tube-used command returns the tube currently being used by the +client. Its form is: + +list-tube-used\r\n + +The response is: + +USING \r\n + + - is the name of the tube being used. + +The list-tubes-watched command returns a list tubes currently being watched by +the client. Its form is: + +list-tubes-watched\r\n + +The response is: + +OK \r\n +\r\n + + - is the size of the following data section in bytes. + + - is a sequence of bytes of length from the previous line. It + is a YAML file containing watched tube names as a list of strings. + diff --git a/doc/core.txt b/doc/core.txt new file mode 100644 index 000000000..a649bbd66 --- /dev/null +++ b/doc/core.txt @@ -0,0 +1 @@ +echo 'core.%e.%t.%p' > /proc/sys/kernel/core_pattern diff --git a/doc/handlersocket_en.txt b/doc/handlersocket_en.txt new file mode 100644 index 000000000..ee00ab352 --- /dev/null +++ b/doc/handlersocket_en.txt @@ -0,0 +1,148 @@ + +---------------------------------------------------------------------------- +The HandlerSocket protocol + +---------------------------------------------------------------------------- +Basic syntax + +- The HandlerSocket protocol is line-based. Each line ends with LF(0x0a). +- Each line consists a concatenation of tokens separated by HT(0x09). +- A token is either NULL or an encoded string. Note that you need to + distinguish NULL from an empty string, as most DBMs does so. +- NULL is expressed as a single NUL(0x00). +- An encoded string is a string with the following encoding rules. + - Characters in the range [0x10 - 0xff] are not encoded. + - A character in the range [0x00 - 0x0f] is prefixed by 0x01 and + shifted by 0x40. For example, 0x03 is encoded as 0x01 0x43. +- Note that a string can be empty. A continuation of 0x09 0x09 means that + there is an empty string between them. A continuation of 0x09 0x0a means + that there is an empty string at the end of the line. + +---------------------------------------------------------------------------- +Request and Response + +- The HandlerSocket protocol is a simple request/response protocol. After a + connection is established, the client side sends a request, and then the + server side sends a response. +- A request/response consists of a single line. +- Requests can be pipelined; That is, you can send multiple requests (ie. + lines) at one time, and receive responses for them at one time. + +---------------------------------------------------------------------------- +'open_index' request + +The 'open_index' request has the following syntax. + + P + +- is a number in decimal. +- , , and are strings. To open the primary + key, use PRIMARY as . +- is a comma-separated list of column names. + +Once an 'open_index' request is issued, the HandlerSocket plugin opens the +specified index and keep it open until the client connection is closed. Each +open index is identified by . If is already open, the old +open index is closed. You can open the same combination of + multple times, possibly with different . +For efficiency, keep small as far as possible. + +---------------------------------------------------------------------------- +Getting data + +The 'find' request has the following syntax. + + ... + +- is a number. This number must be an specified by a + 'open_index' request executed previously on the same connection. +- specifies the comparison operation to use. The current version of + HandlerSocket supports '=', '>', '>=', '<', and '<='. +- indicates the length of the trailing parameters ... . This + must be smaller than or equal to the number of index columns specified by + specified by the corresponding 'open_index' request. +- ... specify the index column values to fetch. +- and are numbers. These parameters can be omitted. When + omitted, it works as if 1 and 0 are specified. + +---------------------------------------------------------------------------- +Updating/Deleting data + +The 'find_modify' request has the following syntax. + + ... ... + +- is either 'U' (update) or 'D' (delete). +- ... specifies the column values to set. The length of ... + must be smaller than or equal to the length of specified by + the corresponding 'open_index' request. If is 'D', these parameters + are ignored. + +---------------------------------------------------------------------------- +Inserting data + +The 'insert' request has the following syntax. + + '+' ... + +- indicates the length of the trailing parameters ... . This + must be smaller than or equal to the length of specified by the + corresponding 'open_index' request. +- ... specify the column values to set. For columns not in + , the default values for each column are set. + +---------------------------------------------------------------------------- +Response syntax + +HandlerSocket returns a response of the following syntax for each request. + + ... + +- indicates whether the request has successfully executed or not. + '0' means success. Non-zero means an error. +- indicates the number of columns of the result set. +- ... is the result set. The length of ... is always a + multiple of . It is possible that ... is empty. + +If is non-zero, is always 1 and indicates a +human-readable error message, though sometimes is not provided. + +---------------------------------------------------------------------------- +Response for 'open_index' + +If 'open_index' is succeeded, HandlerSocket returns a line of the following +syntax. + + 0 1 + +---------------------------------------------------------------------------- +Response for 'find' + +If 'find' is succeeded, HandlerSocket returns a line of the following +syntax. + + 0 ... + +- always equals to the length of of the corresponding + 'open_index' request. +- ... is the result set. If N rows are found, the length of + ... becomes ( * N ). + +---------------------------------------------------------------------------- +Response for 'find_modify' + +If 'find_modify' is succeeded, HandlerSocket returns a line of the following +syntax. + + 0 1 + +- is the number of modified rows. + +---------------------------------------------------------------------------- +Response for 'insert' + +If 'insert' is succeeded, HanderSocket returns a line of the following +syntax. + + 0 1 + diff --git a/doc/log.txt b/doc/log.txt new file mode 100644 index 000000000..3992af7f0 --- /dev/null +++ b/doc/log.txt @@ -0,0 +1,9 @@ + +1) 2011.4.18 +1.1) 为了更好地以 UDP 方式与 syslog-ng 通信,应在 syslog-ng.conf +中的 source 中添加选项: so_rcvbuf(xxx),如: +source s_udp { + udp(ip(0.0.0.0) port(12345) so_rcvbuf(81920000)); +}; + +同时配置 net.core.rmem_max, 如: /sbin/sysctl -w net.core.rmem_max=81920000 diff --git a/doc/rfc3492.txt b/doc/rfc3492.txt new file mode 100644 index 000000000..e72ad81a2 --- /dev/null +++ b/doc/rfc3492.txt @@ -0,0 +1,1963 @@ + + + + + + +Network Working Group A. Costello +Request for Comments: 3492 Univ. of California, Berkeley +Category: Standards Track March 2003 + + + Punycode: A Bootstring encoding of Unicode + for Internationalized Domain Names in Applications (IDNA) + +Status of this Memo + + This document specifies an Internet standards track protocol for the + Internet community, and requests discussion and suggestions for + improvements. Please refer to the current edition of the "Internet + Official Protocol Standards" (STD 1) for the standardization state + and status of this protocol. Distribution of this memo is unlimited. + +Copyright Notice + + Copyright (C) The Internet Society (2003). All Rights Reserved. + +Abstract + + Punycode is a simple and efficient transfer encoding syntax designed + for use with Internationalized Domain Names in Applications (IDNA). + It uniquely and reversibly transforms a Unicode string into an ASCII + string. ASCII characters in the Unicode string are represented + literally, and non-ASCII characters are represented by ASCII + characters that are allowed in host name labels (letters, digits, and + hyphens). This document defines a general algorithm called + Bootstring that allows a string of basic code points to uniquely + represent any string of code points drawn from a larger set. + Punycode is an instance of Bootstring that uses particular parameter + values specified by this document, appropriate for IDNA. + +Table of Contents + + 1. Introduction...............................................2 + 1.1 Features..............................................2 + 1.2 Interaction of protocol parts.........................3 + 2. Terminology................................................3 + 3. Bootstring description.....................................4 + 3.1 Basic code point segregation..........................4 + 3.2 Insertion unsort coding...............................4 + 3.3 Generalized variable-length integers..................5 + 3.4 Bias adaptation.......................................7 + 4. Bootstring parameters......................................8 + 5. Parameter values for Punycode..............................8 + 6. Bootstring algorithms......................................9 + + + +Costello Standards Track [Page 1] + +RFC 3492 IDNA Punycode March 2003 + + + 6.1 Bias adaptation function.............................10 + 6.2 Decoding procedure...................................11 + 6.3 Encoding procedure...................................12 + 6.4 Overflow handling....................................13 + 7. Punycode examples.........................................14 + 7.1 Sample strings.......................................14 + 7.2 Decoding traces......................................17 + 7.3 Encoding traces......................................19 + 8. Security Considerations...................................20 + 9. References................................................21 + 9.1 Normative References.................................21 + 9.2 Informative References...............................21 + A. Mixed-case annotation.....................................22 + B. Disclaimer and license....................................22 + C. Punycode sample implementation............................23 + Author's Address.............................................34 + Full Copyright Statement.....................................35 + +1. Introduction + + [IDNA] describes an architecture for supporting internationalized + domain names. Labels containing non-ASCII characters can be + represented by ACE labels, which begin with a special ACE prefix and + contain only ASCII characters. The remainder of the label after the + prefix is a Punycode encoding of a Unicode string satisfying certain + constraints. For the details of the prefix and constraints, see + [IDNA] and [NAMEPREP]. + + Punycode is an instance of a more general algorithm called + Bootstring, which allows strings composed from a small set of "basic" + code points to uniquely represent any string of code points drawn + from a larger set. Punycode is Bootstring with particular parameter + values appropriate for IDNA. + +1.1 Features + + Bootstring has been designed to have the following features: + + * Completeness: Every extended string (sequence of arbitrary code + points) can be represented by a basic string (sequence of basic + code points). Restrictions on what strings are allowed, and on + length, can be imposed by higher layers. + + * Uniqueness: There is at most one basic string that represents a + given extended string. + + * Reversibility: Any extended string mapped to a basic string can + be recovered from that basic string. + + + +Costello Standards Track [Page 2] + +RFC 3492 IDNA Punycode March 2003 + + + * Efficient encoding: The ratio of basic string length to extended + string length is small. This is important in the context of + domain names because RFC 1034 [RFC1034] restricts the length of a + domain label to 63 characters. + + * Simplicity: The encoding and decoding algorithms are reasonably + simple to implement. The goals of efficiency and simplicity are + at odds; Bootstring aims at a good balance between them. + + * Readability: Basic code points appearing in the extended string + are represented as themselves in the basic string (although the + main purpose is to improve efficiency, not readability). + + Punycode can also support an additional feature that is not used by + the ToASCII and ToUnicode operations of [IDNA]. When extended + strings are case-folded prior to encoding, the basic string can use + mixed case to tell how to convert the folded string into a mixed-case + string. See appendix A "Mixed-case annotation". + +1.2 Interaction of protocol parts + + Punycode is used by the IDNA protocol [IDNA] for converting domain + labels into ASCII; it is not designed for any other purpose. It is + explicitly not designed for processing arbitrary free text. + +2. Terminology + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in BCP 14, RFC 2119 + [RFC2119]. + + A code point is an integral value associated with a character in a + coded character set. + + As in the Unicode Standard [UNICODE], Unicode code points are denoted + by "U+" followed by four to six hexadecimal digits, while a range of + code points is denoted by two hexadecimal numbers separated by "..", + with no prefixes. + + The operators div and mod perform integer division; (x div y) is the + quotient of x divided by y, discarding the remainder, and (x mod y) + is the remainder, so (x div y) * y + (x mod y) == x. Bootstring uses + these operators only with nonnegative operands, so the quotient and + remainder are always nonnegative. + + The break statement jumps out of the innermost loop (as in C). + + + + +Costello Standards Track [Page 3] + +RFC 3492 IDNA Punycode March 2003 + + + An overflow is an attempt to compute a value that exceeds the maximum + value of an integer variable. + +3. Bootstring description + + Bootstring represents an arbitrary sequence of code points (the + "extended string") as a sequence of basic code points (the "basic + string"). This section describes the representation. Section 6 + "Bootstring algorithms" presents the algorithms as pseudocode. + Sections 7.1 "Decoding traces" and 7.2 "Encoding traces" trace the + algorithms for sample inputs. + + The following sections describe the four techniques used in + Bootstring. "Basic code point segregation" is a very simple and + efficient encoding for basic code points occurring in the extended + string: they are simply copied all at once. "Insertion unsort + coding" encodes the non-basic code points as deltas, and processes + the code points in numerical order rather than in order of + appearance, which typically results in smaller deltas. The deltas + are represented as "generalized variable-length integers", which use + basic code points to represent nonnegative integers. The parameters + of this integer representation are dynamically adjusted using "bias + adaptation", to improve efficiency when consecutive deltas have + similar magnitudes. + +3.1 Basic code point segregation + + All basic code points appearing in the extended string are + represented literally at the beginning of the basic string, in their + original order, followed by a delimiter if (and only if) the number + of basic code points is nonzero. The delimiter is a particular basic + code point, which never appears in the remainder of the basic string. + The decoder can therefore find the end of the literal portion (if + there is one) by scanning for the last delimiter. + +3.2 Insertion unsort coding + + The remainder of the basic string (after the last delimiter if there + is one) represents a sequence of nonnegative integral deltas as + generalized variable-length integers, described in section 3.3. The + meaning of the deltas is best understood in terms of the decoder. + + The decoder builds the extended string incrementally. Initially, the + extended string is a copy of the literal portion of the basic string + (excluding the last delimiter). The decoder inserts non-basic code + points, one for each delta, into the extended string, ultimately + arriving at the final decoded string. + + + + +Costello Standards Track [Page 4] + +RFC 3492 IDNA Punycode March 2003 + + + At the heart of this process is a state machine with two state + variables: an index i and a counter n. The index i refers to a + position in the extended string; it ranges from 0 (the first + position) to the current length of the extended string (which refers + to a potential position beyond the current end). If the current + state is , the next state is if i is less than the + length of the extended string, or if i equals the length of + the extended string. In other words, each state change causes i to + increment, wrapping around to zero if necessary, and n counts the + number of wrap-arounds. + + Notice that the state always advances monotonically (there is no way + for the decoder to return to an earlier state). At each state, an + insertion is either performed or not performed. At most one + insertion is performed in a given state. An insertion inserts the + value of n at position i in the extended string. The deltas are a + run-length encoding of this sequence of events: they are the lengths + of the runs of non-insertion states preceeding the insertion states. + Hence, for each delta, the decoder performs delta state changes, then + an insertion, and then one more state change. (An implementation + need not perform each state change individually, but can instead use + division and remainder calculations to compute the next insertion + state directly.) It is an error if the inserted code point is a + basic code point (because basic code points were supposed to be + segregated as described in section 3.1). + + The encoder's main task is to derive the sequence of deltas that will + cause the decoder to construct the desired string. It can do this by + repeatedly scanning the extended string for the next code point that + the decoder would need to insert, and counting the number of state + changes the decoder would need to perform, mindful of the fact that + the decoder's extended string will include only those code points + that have already been inserted. Section 6.3 "Encoding procedure" + gives a precise algorithm. + +3.3 Generalized variable-length integers + + In a conventional integer representation the base is the number of + distinct symbols for digits, whose values are 0 through base-1. Let + digit_0 denote the least significant digit, digit_1 the next least + significant, and so on. The value represented is the sum over j of + digit_j * w(j), where w(j) = base^j is the weight (scale factor) for + position j. For example, in the base 8 integer 437, the digits are + 7, 3, and 4, and the weights are 1, 8, and 64, so the value is 7 + + 3*8 + 4*64 = 287. This representation has two disadvantages: First, + there are multiple encodings of each value (because there can be + extra zeros in the most significant positions), which is inconvenient + + + + +Costello Standards Track [Page 5] + +RFC 3492 IDNA Punycode March 2003 + + + when unique encodings are needed. Second, the integer is not self- + delimiting, so if multiple integers are concatenated the boundaries + between them are lost. + + The generalized variable-length representation solves these two + problems. The digit values are still 0 through base-1, but now the + integer is self-delimiting by means of thresholds t(j), each of which + is in the range 0 through base-1. Exactly one digit, the most + significant, satisfies digit_j < t(j). Therefore, if several + integers are concatenated, it is easy to separate them, starting with + the first if they are little-endian (least significant digit first), + or starting with the last if they are big-endian (most significant + digit first). As before, the value is the sum over j of digit_j * + w(j), but the weights are different: + + w(0) = 1 + w(j) = w(j-1) * (base - t(j-1)) for j > 0 + + For example, consider the little-endian sequence of base 8 digits + 734251... Suppose the thresholds are 2, 3, 5, 5, 5, 5... This + implies that the weights are 1, 1*(8-2) = 6, 6*(8-3) = 30, 30*(8-5) = + 90, 90*(8-5) = 270, and so on. 7 is not less than 2, and 3 is not + less than 3, but 4 is less than 5, so 4 is the last digit. The value + of 734 is 7*1 + 3*6 + 4*30 = 145. The next integer is 251, with + value 2*1 + 5*6 + 1*30 = 62. Decoding this representation is very + similar to decoding a conventional integer: Start with a current + value of N = 0 and a weight w = 1. Fetch the next digit d and + increase N by d * w. If d is less than the current threshold (t) + then stop, otherwise increase w by a factor of (base - t), update t + for the next position, and repeat. + + Encoding this representation is similar to encoding a conventional + integer: If N < t then output one digit for N and stop, otherwise + output the digit for t + ((N - t) mod (base - t)), then replace N + with (N - t) div (base - t), update t for the next position, and + repeat. + + For any particular set of values of t(j), there is exactly one + generalized variable-length representation of each nonnegative + integral value. + + Bootstring uses little-endian ordering so that the deltas can be + separated starting with the first. The t(j) values are defined in + terms of the constants base, tmin, and tmax, and a state variable + called bias: + + t(j) = base * (j + 1) - bias, + clamped to the range tmin through tmax + + + +Costello Standards Track [Page 6] + +RFC 3492 IDNA Punycode March 2003 + + + The clamping means that if the formula yields a value less than tmin + or greater than tmax, then t(j) = tmin or tmax, respectively. (In + the pseudocode in section 6 "Bootstring algorithms", the expression + base * (j + 1) is denoted by k for performance reasons.) These t(j) + values cause the representation to favor integers within a particular + range determined by the bias. + +3.4 Bias adaptation + + After each delta is encoded or decoded, bias is set for the next + delta as follows: + + 1. Delta is scaled in order to avoid overflow in the next step: + + let delta = delta div 2 + + But when this is the very first delta, the divisor is not 2, but + instead a constant called damp. This compensates for the fact + that the second delta is usually much smaller than the first. + + 2. Delta is increased to compensate for the fact that the next delta + will be inserting into a longer string: + + let delta = delta + (delta div numpoints) + + numpoints is the total number of code points encoded/decoded so + far (including the one corresponding to this delta itself, and + including the basic code points). + + 3. Delta is repeatedly divided until it falls within a threshold, to + predict the minimum number of digits needed to represent the next + delta: + + while delta > ((base - tmin) * tmax) div 2 + do let delta = delta div (base - tmin) + + 4. The bias is set: + + let bias = + (base * the number of divisions performed in step 3) + + (((base - tmin + 1) * delta) div (delta + skew)) + + The motivation for this procedure is that the current delta + provides a hint about the likely size of the next delta, and so + t(j) is set to tmax for the more significant digits starting with + the one expected to be last, tmin for the less significant digits + up through the one expected to be third-last, and somewhere + between tmin and tmax for the digit expected to be second-last + + + +Costello Standards Track [Page 7] + +RFC 3492 IDNA Punycode March 2003 + + + (balancing the hope of the expected-last digit being unnecessary + against the danger of it being insufficient). + +4. Bootstring parameters + + Given a set of basic code points, one needs to be designated as the + delimiter. The base cannot be greater than the number of + distinguishable basic code points remaining. The digit-values in the + range 0 through base-1 need to be associated with distinct non- + delimiter basic code points. In some cases multiple code points need + to have the same digit-value; for example, uppercase and lowercase + versions of the same letter need to be equivalent if basic strings + are case-insensitive. + + The initial value of n cannot be greater than the minimum non-basic + code point that could appear in extended strings. + + The remaining five parameters (tmin, tmax, skew, damp, and the + initial value of bias) need to satisfy the following constraints: + + 0 <= tmin <= tmax <= base-1 + skew >= 1 + damp >= 2 + initial_bias mod base <= base - tmin + + Provided the constraints are satisfied, these five parameters affect + efficiency but not correctness. They are best chosen empirically. + + If support for mixed-case annotation is desired (see appendix A), + make sure that the code points corresponding to 0 through tmax-1 all + have both uppercase and lowercase forms. + +5. Parameter values for Punycode + + Punycode uses the following Bootstring parameter values: + + base = 36 + tmin = 1 + tmax = 26 + skew = 38 + damp = 700 + initial_bias = 72 + initial_n = 128 = 0x80 + + Although the only restriction Punycode imposes on the input integers + is that they be nonnegative, these parameters are especially designed + to work well with Unicode [UNICODE] code points, which are integers + in the range 0..10FFFF (but not D800..DFFF, which are reserved for + + + +Costello Standards Track [Page 8] + +RFC 3492 IDNA Punycode March 2003 + + + use by the UTF-16 encoding of Unicode). The basic code points are + the ASCII [ASCII] code points (0..7F), of which U+002D (-) is the + delimiter, and some of the others have digit-values as follows: + + code points digit-values + ------------ ---------------------- + 41..5A (A-Z) = 0 to 25, respectively + 61..7A (a-z) = 0 to 25, respectively + 30..39 (0-9) = 26 to 35, respectively + + Using hyphen-minus as the delimiter implies that the encoded string + can end with a hyphen-minus only if the Unicode string consists + entirely of basic code points, but IDNA forbids such strings from + being encoded. The encoded string can begin with a hyphen-minus, but + IDNA prepends a prefix. Therefore IDNA using Punycode conforms to + the RFC 952 rule that host name labels neither begin nor end with a + hyphen-minus [RFC952]. + + A decoder MUST recognize the letters in both uppercase and lowercase + forms (including mixtures of both forms). An encoder SHOULD output + only uppercase forms or only lowercase forms, unless it uses mixed- + case annotation (see appendix A). + + Presumably most users will not manually write or type encoded strings + (as opposed to cutting and pasting them), but those who do will need + to be alert to the potential visual ambiguity between the following + sets of characters: + + G 6 + I l 1 + O 0 + S 5 + U V + Z 2 + + Such ambiguities are usually resolved by context, but in a Punycode + encoded string there is no context apparent to humans. + +6. Bootstring algorithms + + Some parts of the pseudocode can be omitted if the parameters satisfy + certain conditions (for which Punycode qualifies). These parts are + enclosed in {braces}, and notes immediately following the pseudocode + explain the conditions under which they can be omitted. + + + + + + + +Costello Standards Track [Page 9] + +RFC 3492 IDNA Punycode March 2003 + + + Formally, code points are integers, and hence the pseudocode assumes + that arithmetic operations can be performed directly on code points. + In some programming languages, explicit conversion between code + points and integers might be necessary. + +6.1 Bias adaptation function + + function adapt(delta,numpoints,firsttime): + if firsttime then let delta = delta div damp + else let delta = delta div 2 + let delta = delta + (delta div numpoints) + let k = 0 + while delta > ((base - tmin) * tmax) div 2 do begin + let delta = delta div (base - tmin) + let k = k + base + end + return k + (((base - tmin + 1) * delta) div (delta + skew)) + + It does not matter whether the modifications to delta and k inside + adapt() affect variables of the same name inside the + encoding/decoding procedures, because after calling adapt() the + caller does not read those variables before overwriting them. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Costello Standards Track [Page 10] + +RFC 3492 IDNA Punycode March 2003 + + +6.2 Decoding procedure + + let n = initial_n + let i = 0 + let bias = initial_bias + let output = an empty string indexed from 0 + consume all code points before the last delimiter (if there is one) + and copy them to output, fail on any non-basic code point + if more than zero code points were consumed then consume one more + (which will be the last delimiter) + while the input is not exhausted do begin + let oldi = i + let w = 1 + for k = base to infinity in steps of base do begin + consume a code point, or fail if there was none to consume + let digit = the code point's digit-value, fail if it has none + let i = i + digit * w, fail on overflow + let t = tmin if k <= bias {+ tmin}, or + tmax if k >= bias + tmax, or k - bias otherwise + if digit < t then break + let w = w * (base - t), fail on overflow + end + let bias = adapt(i - oldi, length(output) + 1, test oldi is 0?) + let n = n + i div (length(output) + 1), fail on overflow + let i = i mod (length(output) + 1) + {if n is a basic code point then fail} + insert n into output at position i + increment i + end + + The full statement enclosed in braces (checking whether n is a basic + code point) can be omitted if initial_n exceeds all basic code points + (which is true for Punycode), because n is never less than initial_n. + + In the assignment of t, where t is clamped to the range tmin through + tmax, "+ tmin" can always be omitted. This makes the clamping + calculation incorrect when bias < k < bias + tmin, but that cannot + happen because of the way bias is computed and because of the + constraints on the parameters. + + Because the decoder state can only advance monotonically, and there + is only one representation of any delta, there is therefore only one + encoded string that can represent a given sequence of integers. The + only error conditions are invalid code points, unexpected end-of- + input, overflow, and basic code points encoded using deltas instead + of appearing literally. If the decoder fails on these errors as + shown above, then it cannot produce the same output for two distinct + inputs. Without this property it would have been necessary to re- + + + +Costello Standards Track [Page 11] + +RFC 3492 IDNA Punycode March 2003 + + + encode the output and verify that it matches the input in order to + guarantee the uniqueness of the encoding. + +6.3 Encoding procedure + + let n = initial_n + let delta = 0 + let bias = initial_bias + let h = b = the number of basic code points in the input + copy them to the output in order, followed by a delimiter if b > 0 + {if the input contains a non-basic code point < n then fail} + while h < length(input) do begin + let m = the minimum {non-basic} code point >= n in the input + let delta = delta + (m - n) * (h + 1), fail on overflow + let n = m + for each code point c in the input (in order) do begin + if c < n {or c is basic} then increment delta, fail on overflow + if c == n then begin + let q = delta + for k = base to infinity in steps of base do begin + let t = tmin if k <= bias {+ tmin}, or + tmax if k >= bias + tmax, or k - bias otherwise + if q < t then break + output the code point for digit t + ((q - t) mod (base - t)) + let q = (q - t) div (base - t) + end + output the code point for digit q + let bias = adapt(delta, h + 1, test h equals b?) + let delta = 0 + increment h + end + end + increment delta and n + end + + The full statement enclosed in braces (checking whether the input + contains a non-basic code point less than n) can be omitted if all + code points less than initial_n are basic code points (which is true + for Punycode if code points are unsigned). + + The brace-enclosed conditions "non-basic" and "or c is basic" can be + omitted if initial_n exceeds all basic code points (which is true for + Punycode), because the code point being tested is never less than + initial_n. + + In the assignment of t, where t is clamped to the range tmin through + tmax, "+ tmin" can always be omitted. This makes the clamping + calculation incorrect when bias < k < bias + tmin, but that cannot + + + +Costello Standards Track [Page 12] + +RFC 3492 IDNA Punycode March 2003 + + + happen because of the way bias is computed and because of the + constraints on the parameters. + + The checks for overflow are necessary to avoid producing invalid + output when the input contains very large values or is very long. + + The increment of delta at the bottom of the outer loop cannot + overflow because delta < length(input) before the increment, and + length(input) is already assumed to be representable. The increment + of n could overflow, but only if h == length(input), in which case + the procedure is finished anyway. + +6.4 Overflow handling + + For IDNA, 26-bit unsigned integers are sufficient to handle all valid + IDNA labels without overflow, because any string that needed a 27-bit + delta would have to exceed either the code point limit (0..10FFFF) or + the label length limit (63 characters). However, overflow handling + is necessary because the inputs are not necessarily valid IDNA + labels. + + If the programming language does not provide overflow detection, the + following technique can be used. Suppose A, B, and C are + representable nonnegative integers and C is nonzero. Then A + B + overflows if and only if B > maxint - A, and A + (B * C) overflows if + and only if B > (maxint - A) div C, where maxint is the greatest + integer for which maxint + 1 cannot be represented. Refer to + appendix C "Punycode sample implementation" for demonstrations of + this technique in the C language. + + The decoding and encoding algorithms shown in sections 6.2 and 6.3 + handle overflow by detecting it whenever it happens. Another + approach is to enforce limits on the inputs that prevent overflow + from happening. For example, if the encoder were to verify that no + input code points exceed M and that the input length does not exceed + L, then no delta could ever exceed (M - initial_n) * (L + 1), and + hence no overflow could occur if integer variables were capable of + representing values that large. This prevention approach would + impose more restrictions on the input than the detection approach + does, but might be considered simpler in some programming languages. + + In theory, the decoder could use an analogous approach, limiting the + number of digits in a variable-length integer (that is, limiting the + number of iterations in the innermost loop). However, the number of + digits that suffice to represent a given delta can sometimes + represent much larger deltas (because of the adaptation), and hence + this approach would probably need integers wider than 32 bits. + + + + +Costello Standards Track [Page 13] + +RFC 3492 IDNA Punycode March 2003 + + + Yet another approach for the decoder is to allow overflow to occur, + but to check the final output string by re-encoding it and comparing + to the decoder input. If and only if they do not match (using a + case-insensitive ASCII comparison) overflow has occurred. This + delayed-detection approach would not impose any more restrictions on + the input than the immediate-detection approach does, and might be + considered simpler in some programming languages. + + In fact, if the decoder is used only inside the IDNA ToUnicode + operation [IDNA], then it need not check for overflow at all, because + ToUnicode performs a higher level re-encoding and comparison, and a + mismatch has the same consequence as if the Punycode decoder had + failed. + +7. Punycode examples + +7.1 Sample strings + + In the Punycode encodings below, the ACE prefix is not shown. + Backslashes show where line breaks have been inserted in strings too + long for one line. + + The first several examples are all translations of the sentence "Why + can't they just speak in ?" (courtesy of Michael Kaplan's + "provincial" page [PROVINCIAL]). Word breaks and punctuation have + been removed, as is often done in domain names. + + (A) Arabic (Egyptian): + u+0644 u+064A u+0647 u+0645 u+0627 u+0628 u+062A u+0643 u+0644 + u+0645 u+0648 u+0634 u+0639 u+0631 u+0628 u+064A u+061F + Punycode: egbpdaj6bu4bxfgehfvwxn + + (B) Chinese (simplified): + u+4ED6 u+4EEC u+4E3A u+4EC0 u+4E48 u+4E0D u+8BF4 u+4E2D u+6587 + Punycode: ihqwcrb4cv8a8dqg056pqjye + + (C) Chinese (traditional): + u+4ED6 u+5011 u+7232 u+4EC0 u+9EBD u+4E0D u+8AAA u+4E2D u+6587 + Punycode: ihqwctvzc91f659drss3x8bo0yb + + (D) Czech: Proprostnemluvesky + U+0050 u+0072 u+006F u+010D u+0070 u+0072 u+006F u+0073 u+0074 + u+011B u+006E u+0065 u+006D u+006C u+0075 u+0076 u+00ED u+010D + u+0065 u+0073 u+006B u+0079 + Punycode: Proprostnemluvesky-uyb24dma41a + + + + + + +Costello Standards Track [Page 14] + +RFC 3492 IDNA Punycode March 2003 + + + (E) Hebrew: + u+05DC u+05DE u+05D4 u+05D4 u+05DD u+05E4 u+05E9 u+05D5 u+05D8 + u+05DC u+05D0 u+05DE u+05D3 u+05D1 u+05E8 u+05D9 u+05DD u+05E2 + u+05D1 u+05E8 u+05D9 u+05EA + Punycode: 4dbcagdahymbxekheh6e0a7fei0b + + (F) Hindi (Devanagari): + u+092F u+0939 u+0932 u+094B u+0917 u+0939 u+093F u+0928 u+094D + u+0926 u+0940 u+0915 u+094D u+092F u+094B u+0902 u+0928 u+0939 + u+0940 u+0902 u+092C u+094B u+0932 u+0938 u+0915 u+0924 u+0947 + u+0939 u+0948 u+0902 + Punycode: i1baa7eci9glrd9b2ae1bj0hfcgg6iyaf8o0a1dig0cd + + (G) Japanese (kanji and hiragana): + u+306A u+305C u+307F u+3093 u+306A u+65E5 u+672C u+8A9E u+3092 + u+8A71 u+3057 u+3066 u+304F u+308C u+306A u+3044 u+306E u+304B + Punycode: n8jok5ay5dzabd5bym9f0cm5685rrjetr6pdxa + + (H) Korean (Hangul syllables): + u+C138 u+ACC4 u+C758 u+BAA8 u+B4E0 u+C0AC u+B78C u+B4E4 u+C774 + u+D55C u+AD6D u+C5B4 u+B97C u+C774 u+D574 u+D55C u+B2E4 u+BA74 + u+C5BC u+B9C8 u+B098 u+C88B u+C744 u+AE4C + Punycode: 989aomsvi5e83db1d2a355cv1e0vak1dwrv93d5xbh15a0dt30a5j\ + psd879ccm6fea98c + + (I) Russian (Cyrillic): + U+043F u+043E u+0447 u+0435 u+043C u+0443 u+0436 u+0435 u+043E + u+043D u+0438 u+043D u+0435 u+0433 u+043E u+0432 u+043E u+0440 + u+044F u+0442 u+043F u+043E u+0440 u+0443 u+0441 u+0441 u+043A + u+0438 + Punycode: b1abfaaepdrnnbgefbaDotcwatmq2g4l + + (J) Spanish: PorqunopuedensimplementehablarenEspaol + U+0050 u+006F u+0072 u+0071 u+0075 u+00E9 u+006E u+006F u+0070 + u+0075 u+0065 u+0064 u+0065 u+006E u+0073 u+0069 u+006D u+0070 + u+006C u+0065 u+006D u+0065 u+006E u+0074 u+0065 u+0068 u+0061 + u+0062 u+006C u+0061 u+0072 u+0065 u+006E U+0045 u+0073 u+0070 + u+0061 u+00F1 u+006F u+006C + Punycode: PorqunopuedensimplementehablarenEspaol-fmd56a + + (K) Vietnamese: + Tisaohkhngthch\ + nitingVit + U+0054 u+1EA1 u+0069 u+0073 u+0061 u+006F u+0068 u+1ECD u+006B + u+0068 u+00F4 u+006E u+0067 u+0074 u+0068 u+1EC3 u+0063 u+0068 + u+1EC9 u+006E u+00F3 u+0069 u+0074 u+0069 u+1EBF u+006E u+0067 + U+0056 u+0069 u+1EC7 u+0074 + Punycode: TisaohkhngthchnitingVit-kjcr8268qyxafd2f1b9g + + + +Costello Standards Track [Page 15] + +RFC 3492 IDNA Punycode March 2003 + + + The next several examples are all names of Japanese music artists, + song titles, and TV programs, just because the author happens to have + them handy (but Japanese is useful for providing examples of single- + row text, two-row text, ideographic text, and various mixtures + thereof). + + (L) 3B + u+0033 u+5E74 U+0042 u+7D44 u+91D1 u+516B u+5148 u+751F + Punycode: 3B-ww4c5e180e575a65lsy2b + + (M) -with-SUPER-MONKEYS + u+5B89 u+5BA4 u+5948 u+7F8E u+6075 u+002D u+0077 u+0069 u+0074 + u+0068 u+002D U+0053 U+0055 U+0050 U+0045 U+0052 u+002D U+004D + U+004F U+004E U+004B U+0045 U+0059 U+0053 + Punycode: -with-SUPER-MONKEYS-pc58ag80a8qai00g7n9n + + (N) Hello-Another-Way- + U+0048 u+0065 u+006C u+006C u+006F u+002D U+0041 u+006E u+006F + u+0074 u+0068 u+0065 u+0072 u+002D U+0057 u+0061 u+0079 u+002D + u+305D u+308C u+305E u+308C u+306E u+5834 u+6240 + Punycode: Hello-Another-Way--fc4qua05auwb3674vfr0b + + (O) 2 + u+3072 u+3068 u+3064 u+5C4B u+6839 u+306E u+4E0B u+0032 + Punycode: 2-u9tlzr9756bt3uc0v + + (P) MajiKoi5 + U+004D u+0061 u+006A u+0069 u+3067 U+004B u+006F u+0069 u+3059 + u+308B u+0035 u+79D2 u+524D + Punycode: MajiKoi5-783gue6qz075azm5e + + (Q) de + u+30D1 u+30D5 u+30A3 u+30FC u+0064 u+0065 u+30EB u+30F3 u+30D0 + Punycode: de-jg4avhby1noc0d + + (R) + u+305D u+306E u+30B9 u+30D4 u+30FC u+30C9 u+3067 + Punycode: d9juau41awczczp + + The last example is an ASCII string that breaks the existing rules + for host name labels. (It is not a realistic example for IDNA, + because IDNA never encodes pure ASCII labels.) + + (S) -> $1.00 <- + u+002D u+003E u+0020 u+0024 u+0031 u+002E u+0030 u+0030 u+0020 + u+003C u+002D + Punycode: -> $1.00 <-- + + + + +Costello Standards Track [Page 16] + +RFC 3492 IDNA Punycode March 2003 + + +7.2 Decoding traces + + In the following traces, the evolving state of the decoder is shown + as a sequence of hexadecimal values, representing the code points in + the extended string. An asterisk appears just after the most + recently inserted code point, indicating both n (the value preceeding + the asterisk) and i (the position of the value just after the + asterisk). Other numerical values are decimal. + + Decoding trace of example B from section 7.1: + + n is 128, i is 0, bias is 72 + input is "ihqwcrb4cv8a8dqg056pqjye" + there is no delimiter, so extended string starts empty + delta "ihq" decodes to 19853 + bias becomes 21 + 4E0D * + delta "wc" decodes to 64 + bias becomes 20 + 4E0D 4E2D * + delta "rb" decodes to 37 + bias becomes 13 + 4E3A * 4E0D 4E2D + delta "4c" decodes to 56 + bias becomes 17 + 4E3A 4E48 * 4E0D 4E2D + delta "v8a" decodes to 599 + bias becomes 32 + 4E3A 4EC0 * 4E48 4E0D 4E2D + delta "8d" decodes to 130 + bias becomes 23 + 4ED6 * 4E3A 4EC0 4E48 4E0D 4E2D + delta "qg" decodes to 154 + bias becomes 25 + 4ED6 4EEC * 4E3A 4EC0 4E48 4E0D 4E2D + delta "056p" decodes to 46301 + bias becomes 84 + 4ED6 4EEC 4E3A 4EC0 4E48 4E0D 4E2D 6587 * + delta "qjye" decodes to 88531 + bias becomes 90 + 4ED6 4EEC 4E3A 4EC0 4E48 4E0D 8BF4 * 4E2D 6587 + + + + + + + + + + +Costello Standards Track [Page 17] + +RFC 3492 IDNA Punycode March 2003 + + + Decoding trace of example L from section 7.1: + + n is 128, i is 0, bias is 72 + input is "3B-ww4c5e180e575a65lsy2b" + literal portion is "3B-", so extended string starts as: + 0033 0042 + delta "ww4c" decodes to 62042 + bias becomes 27 + 0033 0042 5148 * + delta "5e" decodes to 139 + bias becomes 24 + 0033 0042 516B * 5148 + delta "180e" decodes to 16683 + bias becomes 67 + 0033 5E74 * 0042 516B 5148 + delta "575a" decodes to 34821 + bias becomes 82 + 0033 5E74 0042 516B 5148 751F * + delta "65l" decodes to 14592 + bias becomes 67 + 0033 5E74 0042 7D44 * 516B 5148 751F + delta "sy2b" decodes to 42088 + bias becomes 84 + 0033 5E74 0042 7D44 91D1 * 516B 5148 751F + + + + + + + + + + + + + + + + + + + + + + + + + + + +Costello Standards Track [Page 18] + +RFC 3492 IDNA Punycode March 2003 + + +7.3 Encoding traces + + In the following traces, code point values are hexadecimal, while + other numerical values are decimal. + + Encoding trace of example B from section 7.1: + + bias is 72 + input is: + 4ED6 4EEC 4E3A 4EC0 4E48 4E0D 8BF4 4E2D 6587 + there are no basic code points, so no literal portion + next code point to insert is 4E0D + needed delta is 19853, encodes as "ihq" + bias becomes 21 + next code point to insert is 4E2D + needed delta is 64, encodes as "wc" + bias becomes 20 + next code point to insert is 4E3A + needed delta is 37, encodes as "rb" + bias becomes 13 + next code point to insert is 4E48 + needed delta is 56, encodes as "4c" + bias becomes 17 + next code point to insert is 4EC0 + needed delta is 599, encodes as "v8a" + bias becomes 32 + next code point to insert is 4ED6 + needed delta is 130, encodes as "8d" + bias becomes 23 + next code point to insert is 4EEC + needed delta is 154, encodes as "qg" + bias becomes 25 + next code point to insert is 6587 + needed delta is 46301, encodes as "056p" + bias becomes 84 + next code point to insert is 8BF4 + needed delta is 88531, encodes as "qjye" + bias becomes 90 + output is "ihqwcrb4cv8a8dqg056pqjye" + + + + + + + + + + + + +Costello Standards Track [Page 19] + +RFC 3492 IDNA Punycode March 2003 + + + Encoding trace of example L from section 7.1: + + bias is 72 + input is: + 0033 5E74 0042 7D44 91D1 516B 5148 751F + basic code points (0033, 0042) are copied to literal portion: "3B-" + next code point to insert is 5148 + needed delta is 62042, encodes as "ww4c" + bias becomes 27 + next code point to insert is 516B + needed delta is 139, encodes as "5e" + bias becomes 24 + next code point to insert is 5E74 + needed delta is 16683, encodes as "180e" + bias becomes 67 + next code point to insert is 751F + needed delta is 34821, encodes as "575a" + bias becomes 82 + next code point to insert is 7D44 + needed delta is 14592, encodes as "65l" + bias becomes 67 + next code point to insert is 91D1 + needed delta is 42088, encodes as "sy2b" + bias becomes 84 + output is "3B-ww4c5e180e575a65lsy2b" + +8. Security Considerations + + Users expect each domain name in DNS to be controlled by a single + authority. If a Unicode string intended for use as a domain label + could map to multiple ACE labels, then an internationalized domain + name could map to multiple ASCII domain names, each controlled by a + different authority, some of which could be spoofs that hijack + service requests intended for another. Therefore Punycode is + designed so that each Unicode string has a unique encoding. + + However, there can still be multiple Unicode representations of the + "same" text, for various definitions of "same". This problem is + addressed to some extent by the Unicode standard under the topic of + canonicalization, and this work is leveraged for domain names by + Nameprep [NAMEPREP]. + + + + + + + + + + +Costello Standards Track [Page 20] + +RFC 3492 IDNA Punycode March 2003 + + +9. References + +9.1 Normative References + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + +9.2 Informative References + + [RFC952] Harrenstien, K., Stahl, M. and E. Feinler, "DOD Internet + Host Table Specification", RFC 952, October 1985. + + [RFC1034] Mockapetris, P., "Domain Names - Concepts and + Facilities", STD 13, RFC 1034, November 1987. + + [IDNA] Faltstrom, P., Hoffman, P. and A. Costello, + "Internationalizing Domain Names in Applications + (IDNA)", RFC 3490, March 2003. + + [NAMEPREP] Hoffman, P. and M. Blanchet, "Nameprep: A Stringprep + Profile for Internationalized Domain Names (IDN)", RFC + 3491, March 2003. + + [ASCII] Cerf, V., "ASCII format for Network Interchange", RFC + 20, October 1969. + + [PROVINCIAL] Kaplan, M., "The 'anyone can be provincial!' page", + http://www.trigeminal.com/samples/provincial.html. + + [UNICODE] The Unicode Consortium, "The Unicode Standard", + http://www.unicode.org/unicode/standard/standard.html. + + + + + + + + + + + + + + + + + + + + +Costello Standards Track [Page 21] + +RFC 3492 IDNA Punycode March 2003 + + +A. Mixed-case annotation + + In order to use Punycode to represent case-insensitive strings, + higher layers need to case-fold the strings prior to Punycode + encoding. The encoded string can use mixed case as an annotation + telling how to convert the folded string into a mixed-case string for + display purposes. Note, however, that mixed-case annotation is not + used by the ToASCII and ToUnicode operations specified in [IDNA], and + therefore implementors of IDNA can disregard this appendix. + + Basic code points can use mixed case directly, because the decoder + copies them verbatim, leaving lowercase code points lowercase, and + leaving uppercase code points uppercase. Each non-basic code point + is represented by a delta, which is represented by a sequence of + basic code points, the last of which provides the annotation. If it + is uppercase, it is a suggestion to map the non-basic code point to + uppercase (if possible); if it is lowercase, it is a suggestion to + map the non-basic code point to lowercase (if possible). + + These annotations do not alter the code points returned by decoders; + the annotations are returned separately, for the caller to use or + ignore. Encoders can accept annotations in addition to code points, + but the annotations do not alter the output, except to influence the + uppercase/lowercase form of ASCII letters. + + Punycode encoders and decoders need not support these annotations, + and higher layers need not use them. + +B. Disclaimer and license + + Regarding this entire document or any portion of it (including the + pseudocode and C code), the author makes no guarantees and is not + responsible for any damage resulting from its use. The author grants + irrevocable permission to anyone to use, modify, and distribute it in + any way that does not diminish the rights of anyone else to use, + modify, and distribute it, provided that redistributed derivative + works do not contain misleading author or version information. + Derivative works need not be licensed under similar terms. + + + + + + + + + + + + + +Costello Standards Track [Page 22] + +RFC 3492 IDNA Punycode March 2003 + + +C. Punycode sample implementation + +/* +punycode.c from RFC 3492 +http://www.nicemice.net/idn/ +Adam M. Costello +http://www.nicemice.net/amc/ + +This is ANSI C code (C89) implementing Punycode (RFC 3492). + +*/ + + +/************************************************************/ +/* Public interface (would normally go in its own .h file): */ + +#include + +enum punycode_status { + punycode_success, + punycode_bad_input, /* Input is invalid. */ + punycode_big_output, /* Output would exceed the space provided. */ + punycode_overflow /* Input needs wider integers to process. */ +}; + +#if UINT_MAX >= (1 << 26) - 1 +typedef unsigned int punycode_uint; +#else +typedef unsigned long punycode_uint; +#endif + +enum punycode_status punycode_encode( + punycode_uint input_length, + const punycode_uint input[], + const unsigned char case_flags[], + punycode_uint *output_length, + char output[] ); + + /* punycode_encode() converts Unicode to Punycode. The input */ + /* is represented as an array of Unicode code points (not code */ + /* units; surrogate pairs are not allowed), and the output */ + /* will be represented as an array of ASCII code points. The */ + /* output string is *not* null-terminated; it will contain */ + /* zeros if and only if the input contains zeros. (Of course */ + /* the caller can leave room for a terminator and add one if */ + /* needed.) The input_length is the number of code points in */ + /* the input. The output_length is an in/out argument: the */ + /* caller passes in the maximum number of code points that it */ + + + +Costello Standards Track [Page 23] + +RFC 3492 IDNA Punycode March 2003 + + + /* can receive, and on successful return it will contain the */ + /* number of code points actually output. The case_flags array */ + /* holds input_length boolean values, where nonzero suggests that */ + /* the corresponding Unicode character be forced to uppercase */ + /* after being decoded (if possible), and zero suggests that */ + /* it be forced to lowercase (if possible). ASCII code points */ + /* are encoded literally, except that ASCII letters are forced */ + /* to uppercase or lowercase according to the corresponding */ + /* uppercase flags. If case_flags is a null pointer then ASCII */ + /* letters are left as they are, and other code points are */ + /* treated as if their uppercase flags were zero. The return */ + /* value can be any of the punycode_status values defined above */ + /* except punycode_bad_input; if not punycode_success, then */ + /* output_size and output might contain garbage. */ + +enum punycode_status punycode_decode( + punycode_uint input_length, + const char input[], + punycode_uint *output_length, + punycode_uint output[], + unsigned char case_flags[] ); + + /* punycode_decode() converts Punycode to Unicode. The input is */ + /* represented as an array of ASCII code points, and the output */ + /* will be represented as an array of Unicode code points. The */ + /* input_length is the number of code points in the input. The */ + /* output_length is an in/out argument: the caller passes in */ + /* the maximum number of code points that it can receive, and */ + /* on successful return it will contain the actual number of */ + /* code points output. The case_flags array needs room for at */ + /* least output_length values, or it can be a null pointer if the */ + /* case information is not needed. A nonzero flag suggests that */ + /* the corresponding Unicode character be forced to uppercase */ + /* by the caller (if possible), while zero suggests that it be */ + /* forced to lowercase (if possible). ASCII code points are */ + /* output already in the proper case, but their flags will be set */ + /* appropriately so that applying the flags would be harmless. */ + /* The return value can be any of the punycode_status values */ + /* defined above; if not punycode_success, then output_length, */ + /* output, and case_flags might contain garbage. On success, the */ + /* decoder will never need to write an output_length greater than */ + /* input_length, because of how the encoding is defined. */ + +/**********************************************************/ +/* Implementation (would normally go in its own .c file): */ + +#include + + + + +Costello Standards Track [Page 24] + +RFC 3492 IDNA Punycode March 2003 + + +/*** Bootstring parameters for Punycode ***/ + +enum { base = 36, tmin = 1, tmax = 26, skew = 38, damp = 700, + initial_bias = 72, initial_n = 0x80, delimiter = 0x2D }; + +/* basic(cp) tests whether cp is a basic code point: */ +#define basic(cp) ((punycode_uint)(cp) < 0x80) + +/* delim(cp) tests whether cp is a delimiter: */ +#define delim(cp) ((cp) == delimiter) + +/* decode_digit(cp) returns the numeric value of a basic code */ +/* point (for use in representing integers) in the range 0 to */ +/* base-1, or base if cp is does not represent a value. */ + +static punycode_uint decode_digit(punycode_uint cp) +{ + return cp - 48 < 10 ? cp - 22 : cp - 65 < 26 ? cp - 65 : + cp - 97 < 26 ? cp - 97 : base; +} + +/* encode_digit(d,flag) returns the basic code point whose value */ +/* (when used for representing integers) is d, which needs to be in */ +/* the range 0 to base-1. The lowercase form is used unless flag is */ +/* nonzero, in which case the uppercase form is used. The behavior */ +/* is undefined if flag is nonzero and digit d has no uppercase form. */ + +static char encode_digit(punycode_uint d, int flag) +{ + return d + 22 + 75 * (d < 26) - ((flag != 0) << 5); + /* 0..25 map to ASCII a..z or A..Z */ + /* 26..35 map to ASCII 0..9 */ +} + +/* flagged(bcp) tests whether a basic code point is flagged */ +/* (uppercase). The behavior is undefined if bcp is not a */ +/* basic code point. */ + +#define flagged(bcp) ((punycode_uint)(bcp) - 65 < 26) + +/* encode_basic(bcp,flag) forces a basic code point to lowercase */ +/* if flag is zero, uppercase if flag is nonzero, and returns */ +/* the resulting code point. The code point is unchanged if it */ +/* is caseless. The behavior is undefined if bcp is not a basic */ +/* code point. */ + +static char encode_basic(punycode_uint bcp, int flag) +{ + + + +Costello Standards Track [Page 25] + +RFC 3492 IDNA Punycode March 2003 + + + bcp -= (bcp - 97 < 26) << 5; + return bcp + ((!flag && (bcp - 65 < 26)) << 5); +} + +/*** Platform-specific constants ***/ + +/* maxint is the maximum value of a punycode_uint variable: */ +static const punycode_uint maxint = -1; +/* Because maxint is unsigned, -1 becomes the maximum value. */ + +/*** Bias adaptation function ***/ + +static punycode_uint adapt( + punycode_uint delta, punycode_uint numpoints, int firsttime ) +{ + punycode_uint k; + + delta = firsttime ? delta / damp : delta >> 1; + /* delta >> 1 is a faster way of doing delta / 2 */ + delta += delta / numpoints; + + for (k = 0; delta > ((base - tmin) * tmax) / 2; k += base) { + delta /= base - tmin; + } + + return k + (base - tmin + 1) * delta / (delta + skew); +} + +/*** Main encode function ***/ + +enum punycode_status punycode_encode( + punycode_uint input_length, + const punycode_uint input[], + const unsigned char case_flags[], + punycode_uint *output_length, + char output[] ) +{ + punycode_uint n, delta, h, b, out, max_out, bias, j, m, q, k, t; + + /* Initialize the state: */ + + n = initial_n; + delta = out = 0; + max_out = *output_length; + bias = initial_bias; + + /* Handle the basic code points: */ + + + + +Costello Standards Track [Page 26] + +RFC 3492 IDNA Punycode March 2003 + + + for (j = 0; j < input_length; ++j) { + if (basic(input[j])) { + if (max_out - out < 2) return punycode_big_output; + output[out++] = + case_flags ? encode_basic(input[j], case_flags[j]) : input[j]; + } + /* else if (input[j] < n) return punycode_bad_input; */ + /* (not needed for Punycode with unsigned code points) */ + } + + h = b = out; + + /* h is the number of code points that have been handled, b is the */ + /* number of basic code points, and out is the number of characters */ + /* that have been output. */ + + if (b > 0) output[out++] = delimiter; + + /* Main encoding loop: */ + + while (h < input_length) { + /* All non-basic code points < n have been */ + /* handled already. Find the next larger one: */ + + for (m = maxint, j = 0; j < input_length; ++j) { + /* if (basic(input[j])) continue; */ + /* (not needed for Punycode) */ + if (input[j] >= n && input[j] < m) m = input[j]; + } + + /* Increase delta enough to advance the decoder's */ + /* state to , but guard against overflow: */ + + if (m - n > (maxint - delta) / (h + 1)) return punycode_overflow; + delta += (m - n) * (h + 1); + n = m; + + for (j = 0; j < input_length; ++j) { + /* Punycode does not need to check whether input[j] is basic: */ + if (input[j] < n /* || basic(input[j]) */ ) { + if (++delta == 0) return punycode_overflow; + } + + if (input[j] == n) { + /* Represent delta as a generalized variable-length integer: */ + + for (q = delta, k = base; ; k += base) { + if (out >= max_out) return punycode_big_output; + + + +Costello Standards Track [Page 27] + +RFC 3492 IDNA Punycode March 2003 + + + t = k <= bias /* + tmin */ ? tmin : /* +tmin not needed */ + k >= bias + tmax ? tmax : k - bias; + if (q < t) break; + output[out++] = encode_digit(t + (q - t) % (base - t), 0); + q = (q - t) / (base - t); + } + + output[out++] = encode_digit(q, case_flags && case_flags[j]); + bias = adapt(delta, h + 1, h == b); + delta = 0; + ++h; + } + } + + ++delta, ++n; + } + + *output_length = out; + return punycode_success; +} + +/*** Main decode function ***/ + +enum punycode_status punycode_decode( + punycode_uint input_length, + const char input[], + punycode_uint *output_length, + punycode_uint output[], + unsigned char case_flags[] ) +{ + punycode_uint n, out, i, max_out, bias, + b, j, in, oldi, w, k, digit, t; + + /* Initialize the state: */ + + n = initial_n; + out = i = 0; + max_out = *output_length; + bias = initial_bias; + + /* Handle the basic code points: Let b be the number of input code */ + /* points before the last delimiter, or 0 if there is none, then */ + /* copy the first b code points to the output. */ + + for (b = j = 0; j < input_length; ++j) if (delim(input[j])) b = j; + if (b > max_out) return punycode_big_output; + + for (j = 0; j < b; ++j) { + + + +Costello Standards Track [Page 28] + +RFC 3492 IDNA Punycode March 2003 + + + if (case_flags) case_flags[out] = flagged(input[j]); + if (!basic(input[j])) return punycode_bad_input; + output[out++] = input[j]; + } + + /* Main decoding loop: Start just after the last delimiter if any */ + /* basic code points were copied; start at the beginning otherwise. */ + + for (in = b > 0 ? b + 1 : 0; in < input_length; ++out) { + + /* in is the index of the next character to be consumed, and */ + /* out is the number of code points in the output array. */ + + /* Decode a generalized variable-length integer into delta, */ + /* which gets added to i. The overflow checking is easier */ + /* if we increase i as we go, then subtract off its starting */ + /* value at the end to obtain delta. */ + + for (oldi = i, w = 1, k = base; ; k += base) { + if (in >= input_length) return punycode_bad_input; + digit = decode_digit(input[in++]); + if (digit >= base) return punycode_bad_input; + if (digit > (maxint - i) / w) return punycode_overflow; + i += digit * w; + t = k <= bias /* + tmin */ ? tmin : /* +tmin not needed */ + k >= bias + tmax ? tmax : k - bias; + if (digit < t) break; + if (w > maxint / (base - t)) return punycode_overflow; + w *= (base - t); + } + + bias = adapt(i - oldi, out + 1, oldi == 0); + + /* i was supposed to wrap around from out+1 to 0, */ + /* incrementing n each time, so we'll fix that now: */ + + if (i / (out + 1) > maxint - n) return punycode_overflow; + n += i / (out + 1); + i %= (out + 1); + + /* Insert n at position i of the output: */ + + /* not needed for Punycode: */ + /* if (decode_digit(n) <= base) return punycode_invalid_input; */ + if (out >= max_out) return punycode_big_output; + + if (case_flags) { + memmove(case_flags + i + 1, case_flags + i, out - i); + + + +Costello Standards Track [Page 29] + +RFC 3492 IDNA Punycode March 2003 + + + /* Case of last character determines uppercase flag: */ + case_flags[i] = flagged(input[in - 1]); + } + + memmove(output + i + 1, output + i, (out - i) * sizeof *output); + output[i++] = n; + } + + *output_length = out; + return punycode_success; +} + +/******************************************************************/ +/* Wrapper for testing (would normally go in a separate .c file): */ + +#include +#include +#include +#include + +/* For testing, we'll just set some compile-time limits rather than */ +/* use malloc(), and set a compile-time option rather than using a */ +/* command-line option. */ + +enum { + unicode_max_length = 256, + ace_max_length = 256 +}; + +static void usage(char **argv) +{ + fprintf(stderr, + "\n" + "%s -e reads code points and writes a Punycode string.\n" + "%s -d reads a Punycode string and writes code points.\n" + "\n" + "Input and output are plain text in the native character set.\n" + "Code points are in the form u+hex separated by whitespace.\n" + "Although the specification allows Punycode strings to contain\n" + "any characters from the ASCII repertoire, this test code\n" + "supports only the printable characters, and needs the Punycode\n" + "string to be followed by a newline.\n" + "The case of the u in u+hex is the force-to-uppercase flag.\n" + , argv[0], argv[0]); + exit(EXIT_FAILURE); +} + +static void fail(const char *msg) + + + +Costello Standards Track [Page 30] + +RFC 3492 IDNA Punycode March 2003 + + +{ + fputs(msg,stderr); + exit(EXIT_FAILURE); +} + +static const char too_big[] = + "input or output is too large, recompile with larger limits\n"; +static const char invalid_input[] = "invalid input\n"; +static const char overflow[] = "arithmetic overflow\n"; +static const char io_error[] = "I/O error\n"; + +/* The following string is used to convert printable */ +/* characters between ASCII and the native charset: */ + +static const char print_ascii[] = + "\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" + " !\"#$%&'()*+,-./" + "0123456789:;<=>?" + "@ABCDEFGHIJKLMNO" + "PQRSTUVWXYZ[\\]^_" + "`abcdefghijklmno" + "pqrstuvwxyz{|}~\n"; + +int main(int argc, char **argv) +{ + enum punycode_status status; + int r; + unsigned int input_length, output_length, j; + unsigned char case_flags[unicode_max_length]; + + if (argc != 2) usage(argv); + if (argv[1][0] != '-') usage(argv); + if (argv[1][2] != 0) usage(argv); + + if (argv[1][1] == 'e') { + punycode_uint input[unicode_max_length]; + unsigned long codept; + char output[ace_max_length+1], uplus[3]; + int c; + + /* Read the input code points: */ + + input_length = 0; + + for (;;) { + r = scanf("%2s%lx", uplus, &codept); + if (ferror(stdin)) fail(io_error); + + + +Costello Standards Track [Page 31] + +RFC 3492 IDNA Punycode March 2003 + + + if (r == EOF || r == 0) break; + + if (r != 2 || uplus[1] != '+' || codept > (punycode_uint)-1) { + fail(invalid_input); + } + + if (input_length == unicode_max_length) fail(too_big); + + if (uplus[0] == 'u') case_flags[input_length] = 0; + else if (uplus[0] == 'U') case_flags[input_length] = 1; + else fail(invalid_input); + + input[input_length++] = codept; + } + + /* Encode: */ + + output_length = ace_max_length; + status = punycode_encode(input_length, input, case_flags, + &output_length, output); + if (status == punycode_bad_input) fail(invalid_input); + if (status == punycode_big_output) fail(too_big); + if (status == punycode_overflow) fail(overflow); + assert(status == punycode_success); + + /* Convert to native charset and output: */ + + for (j = 0; j < output_length; ++j) { + c = output[j]; + assert(c >= 0 && c <= 127); + if (print_ascii[c] == 0) fail(invalid_input); + output[j] = print_ascii[c]; + } + + output[j] = 0; + r = puts(output); + if (r == EOF) fail(io_error); + return EXIT_SUCCESS; + } + + if (argv[1][1] == 'd') { + char input[ace_max_length+2], *p, *pp; + punycode_uint output[unicode_max_length]; + + /* Read the Punycode input string and convert to ASCII: */ + + fgets(input, ace_max_length+2, stdin); + if (ferror(stdin)) fail(io_error); + + + +Costello Standards Track [Page 32] + +RFC 3492 IDNA Punycode March 2003 + + + if (feof(stdin)) fail(invalid_input); + input_length = strlen(input) - 1; + if (input[input_length] != '\n') fail(too_big); + input[input_length] = 0; + + for (p = input; *p != 0; ++p) { + pp = strchr(print_ascii, *p); + if (pp == 0) fail(invalid_input); + *p = pp - print_ascii; + } + + /* Decode: */ + + output_length = unicode_max_length; + status = punycode_decode(input_length, input, &output_length, + output, case_flags); + if (status == punycode_bad_input) fail(invalid_input); + if (status == punycode_big_output) fail(too_big); + if (status == punycode_overflow) fail(overflow); + assert(status == punycode_success); + + /* Output the result: */ + + for (j = 0; j < output_length; ++j) { + r = printf("%s+%04lX\n", + case_flags[j] ? "U" : "u", + (unsigned long) output[j] ); + if (r < 0) fail(io_error); + } + + return EXIT_SUCCESS; + } + + usage(argv); + return EXIT_SUCCESS; /* not reached, but quiets compiler warning */ +} + + + + + + + + + + + + + + + +Costello Standards Track [Page 33] + +RFC 3492 IDNA Punycode March 2003 + + +Author's Address + + Adam M. Costello + University of California, Berkeley + http://www.nicemice.net/amc/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Costello Standards Track [Page 34] + +RFC 3492 IDNA Punycode March 2003 + + +Full Copyright Statement + + Copyright (C) The Internet Society (2003). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + +Costello Standards Track [Page 35] + diff --git a/include/google/protobuf/compiler/code_generator.h b/include/google/protobuf/compiler/code_generator.h new file mode 100644 index 000000000..252f68d1d --- /dev/null +++ b/include/google/protobuf/compiler/code_generator.h @@ -0,0 +1,142 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// Defines the abstract interface implemented by each of the language-specific +// code generators. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CODE_GENERATOR_H__ +#define GOOGLE_PROTOBUF_COMPILER_CODE_GENERATOR_H__ + +#include +#include +#include +#include + +namespace google { +namespace protobuf { + +namespace io { class ZeroCopyOutputStream; } +class FileDescriptor; + +namespace compiler { + +// Defined in this file. +class CodeGenerator; +class GeneratorContext; + +// The abstract interface to a class which generates code implementing a +// particular proto file in a particular language. A number of these may +// be registered with CommandLineInterface to support various languages. +class LIBPROTOC_EXPORT CodeGenerator { + public: + inline CodeGenerator() {} + virtual ~CodeGenerator(); + + // Generates code for the given proto file, generating one or more files in + // the given output directory. + // + // A parameter to be passed to the generator can be specified on the + // command line. This is intended to be used by Java and similar languages + // to specify which specific class from the proto file is to be generated, + // though it could have other uses as well. It is empty if no parameter was + // given. + // + // Returns true if successful. Otherwise, sets *error to a description of + // the problem (e.g. "invalid parameter") and returns false. + virtual bool Generate(const FileDescriptor* file, + const string& parameter, + GeneratorContext* generator_context, + string* error) const = 0; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CodeGenerator); +}; + +// CodeGenerators generate one or more files in a given directory. This +// abstract interface represents the directory to which the CodeGenerator is +// to write and other information about the context in which the Generator +// runs. +class LIBPROTOC_EXPORT GeneratorContext { + public: + inline GeneratorContext() {} + virtual ~GeneratorContext(); + + // Opens the given file, truncating it if it exists, and returns a + // ZeroCopyOutputStream that writes to the file. The caller takes ownership + // of the returned object. This method never fails (a dummy stream will be + // returned instead). + // + // The filename given should be relative to the root of the source tree. + // E.g. the C++ generator, when generating code for "foo/bar.proto", will + // generate the files "foo/bar.pb.h" and "foo/bar.pb.cc"; note that + // "foo/" is included in these filenames. The filename is not allowed to + // contain "." or ".." components. + virtual io::ZeroCopyOutputStream* Open(const string& filename) = 0; + + // Creates a ZeroCopyOutputStream which will insert code into the given file + // at the given insertion point. See plugin.proto (plugin.pb.h) for more + // information on insertion points. The default implementation + // assert-fails -- it exists only for backwards-compatibility. + // + // WARNING: This feature is currently EXPERIMENTAL and is subject to change. + virtual io::ZeroCopyOutputStream* OpenForInsert( + const string& filename, const string& insertion_point); + + // Returns a vector of FileDescriptors for all the files being compiled + // in this run. Useful for languages, such as Go, that treat files + // differently when compiled as a set rather than individually. + virtual void ListParsedFiles(vector* output); + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(GeneratorContext); +}; + +// The type GeneratorContext was once called OutputDirectory. This typedef +// provides backward compatibility. +typedef GeneratorContext OutputDirectory; + +// Several code generators treat the parameter argument as holding a +// list of options separated by commas. This helper function parses +// a set of comma-delimited name/value pairs: e.g., +// "foo=bar,baz,qux=corge" +// parses to the pairs: +// ("foo", "bar"), ("baz", ""), ("qux", "corge") +extern void ParseGeneratorParameter(const string&, + vector >*); + +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_CODE_GENERATOR_H__ diff --git a/include/google/protobuf/compiler/command_line_interface.h b/include/google/protobuf/compiler/command_line_interface.h new file mode 100644 index 000000000..86ea9bde2 --- /dev/null +++ b/include/google/protobuf/compiler/command_line_interface.h @@ -0,0 +1,353 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// Implements the Protocol Compiler front-end such that it may be reused by +// custom compilers written to support other languages. + +#ifndef GOOGLE_PROTOBUF_COMPILER_COMMAND_LINE_INTERFACE_H__ +#define GOOGLE_PROTOBUF_COMPILER_COMMAND_LINE_INTERFACE_H__ + +#include +#include +#include +#include +#include +#include + +namespace google { +namespace protobuf { + +class FileDescriptor; // descriptor.h +class DescriptorPool; // descriptor.h +class FileDescriptorProto; // descriptor.pb.h +template class RepeatedPtrField; // repeated_field.h + +namespace compiler { + +class CodeGenerator; // code_generator.h +class GeneratorContext; // code_generator.h +class DiskSourceTree; // importer.h + +// This class implements the command-line interface to the protocol compiler. +// It is designed to make it very easy to create a custom protocol compiler +// supporting the languages of your choice. For example, if you wanted to +// create a custom protocol compiler binary which includes both the regular +// C++ support plus support for your own custom output "Foo", you would +// write a class "FooGenerator" which implements the CodeGenerator interface, +// then write a main() procedure like this: +// +// int main(int argc, char* argv[]) { +// google::protobuf::compiler::CommandLineInterface cli; +// +// // Support generation of C++ source and headers. +// google::protobuf::compiler::cpp::CppGenerator cpp_generator; +// cli.RegisterGenerator("--cpp_out", &cpp_generator, +// "Generate C++ source and header."); +// +// // Support generation of Foo code. +// FooGenerator foo_generator; +// cli.RegisterGenerator("--foo_out", &foo_generator, +// "Generate Foo file."); +// +// return cli.Run(argc, argv); +// } +// +// The compiler is invoked with syntax like: +// protoc --cpp_out=outdir --foo_out=outdir --proto_path=src src/foo.proto +// +// For a full description of the command-line syntax, invoke it with --help. +class LIBPROTOC_EXPORT CommandLineInterface { + public: + CommandLineInterface(); + ~CommandLineInterface(); + + // Register a code generator for a language. + // + // Parameters: + // * flag_name: The command-line flag used to specify an output file of + // this type. The name must start with a '-'. If the name is longer + // than one letter, it must start with two '-'s. + // * generator: The CodeGenerator which will be called to generate files + // of this type. + // * help_text: Text describing this flag in the --help output. + // + // Some generators accept extra parameters. You can specify this parameter + // on the command-line by placing it before the output directory, separated + // by a colon: + // protoc --foo_out=enable_bar:outdir + // The text before the colon is passed to CodeGenerator::Generate() as the + // "parameter". + void RegisterGenerator(const string& flag_name, + CodeGenerator* generator, + const string& help_text); + + // Register a code generator for a language. + // Besides flag_name you can specify another option_flag_name that could be + // used to pass extra parameters to the registered code generator. + // Suppose you have registered a generator by calling: + // command_line_interface.RegisterGenerator("--foo_out", "--foo_opt", ...) + // Then you could invoke the compiler with a command like: + // protoc --foo_out=enable_bar:outdir --foo_opt=enable_baz + // This will pass "enable_bar,enable_baz" as the parameter to the generator. + void RegisterGenerator(const string& flag_name, + const string& option_flag_name, + CodeGenerator* generator, + const string& help_text); + + // Enables "plugins". In this mode, if a command-line flag ends with "_out" + // but does not match any registered generator, the compiler will attempt to + // find a "plugin" to implement the generator. Plugins are just executables. + // They should live somewhere in the PATH. + // + // The compiler determines the executable name to search for by concatenating + // exe_name_prefix with the unrecognized flag name, removing "_out". So, for + // example, if exe_name_prefix is "protoc-" and you pass the flag --foo_out, + // the compiler will try to run the program "protoc-foo". + // + // The plugin program should implement the following usage: + // plugin [--out=OUTDIR] [--parameter=PARAMETER] PROTO_FILES < DESCRIPTORS + // --out indicates the output directory (as passed to the --foo_out + // parameter); if omitted, the current directory should be used. --parameter + // gives the generator parameter, if any was provided. The PROTO_FILES list + // the .proto files which were given on the compiler command-line; these are + // the files for which the plugin is expected to generate output code. + // Finally, DESCRIPTORS is an encoded FileDescriptorSet (as defined in + // descriptor.proto). This is piped to the plugin's stdin. The set will + // include descriptors for all the files listed in PROTO_FILES as well as + // all files that they import. The plugin MUST NOT attempt to read the + // PROTO_FILES directly -- it must use the FileDescriptorSet. + // + // The plugin should generate whatever files are necessary, as code generators + // normally do. It should write the names of all files it generates to + // stdout. The names should be relative to the output directory, NOT absolute + // names or relative to the current directory. If any errors occur, error + // messages should be written to stderr. If an error is fatal, the plugin + // should exit with a non-zero exit code. + void AllowPlugins(const string& exe_name_prefix); + + // Run the Protocol Compiler with the given command-line parameters. + // Returns the error code which should be returned by main(). + // + // It may not be safe to call Run() in a multi-threaded environment because + // it calls strerror(). I'm not sure why you'd want to do this anyway. + int Run(int argc, const char* const argv[]); + + // Call SetInputsAreCwdRelative(true) if the input files given on the command + // line should be interpreted relative to the proto import path specified + // using --proto_path or -I flags. Otherwise, input file names will be + // interpreted relative to the current working directory (or as absolute + // paths if they start with '/'), though they must still reside inside + // a directory given by --proto_path or the compiler will fail. The latter + // mode is generally more intuitive and easier to use, especially e.g. when + // defining implicit rules in Makefiles. + void SetInputsAreProtoPathRelative(bool enable) { + inputs_are_proto_path_relative_ = enable; + } + + // Provides some text which will be printed when the --version flag is + // used. The version of libprotoc will also be printed on the next line + // after this text. + void SetVersionInfo(const string& text) { + version_info_ = text; + } + + + private: + // ----------------------------------------------------------------- + + class ErrorPrinter; + class GeneratorContextImpl; + class MemoryOutputStream; + + // Clear state from previous Run(). + void Clear(); + + // Remaps each file in input_files_ so that it is relative to one of the + // directories in proto_path_. Returns false if an error occurred. This + // is only used if inputs_are_proto_path_relative_ is false. + bool MakeInputsBeProtoPathRelative( + DiskSourceTree* source_tree); + + // Return status for ParseArguments() and InterpretArgument(). + enum ParseArgumentStatus { + PARSE_ARGUMENT_DONE_AND_CONTINUE, + PARSE_ARGUMENT_DONE_AND_EXIT, + PARSE_ARGUMENT_FAIL + }; + + // Parse all command-line arguments. + ParseArgumentStatus ParseArguments(int argc, const char* const argv[]); + + // Parses a command-line argument into a name/value pair. Returns + // true if the next argument in the argv should be used as the value, + // false otherwise. + // + // Exmaples: + // "-Isrc/protos" -> + // name = "-I", value = "src/protos" + // "--cpp_out=src/foo.pb2.cc" -> + // name = "--cpp_out", value = "src/foo.pb2.cc" + // "foo.proto" -> + // name = "", value = "foo.proto" + bool ParseArgument(const char* arg, string* name, string* value); + + // Interprets arguments parsed with ParseArgument. + ParseArgumentStatus InterpretArgument(const string& name, + const string& value); + + // Print the --help text to stderr. + void PrintHelpText(); + + // Generate the given output file from the given input. + struct OutputDirective; // see below + bool GenerateOutput(const vector& parsed_files, + const OutputDirective& output_directive, + GeneratorContext* generator_context); + bool GeneratePluginOutput(const vector& parsed_files, + const string& plugin_name, + const string& parameter, + GeneratorContext* generator_context, + string* error); + + // Implements --encode and --decode. + bool EncodeOrDecode(const DescriptorPool* pool); + + // Implements the --descriptor_set_out option. + bool WriteDescriptorSet(const vector parsed_files); + + // Get all transitive dependencies of the given file (including the file + // itself), adding them to the given list of FileDescriptorProtos. The + // protos will be ordered such that every file is listed before any file that + // depends on it, so that you can call DescriptorPool::BuildFile() on them + // in order. Any files in *already_seen will not be added, and each file + // added will be inserted into *already_seen. If include_source_code_info is + // true then include the source code information in the FileDescriptorProtos. + static void GetTransitiveDependencies( + const FileDescriptor* file, + bool include_source_code_info, + set* already_seen, + RepeatedPtrField* output); + + // ----------------------------------------------------------------- + + // The name of the executable as invoked (i.e. argv[0]). + string executable_name_; + + // Version info set with SetVersionInfo(). + string version_info_; + + // Registered generators. + struct GeneratorInfo { + string flag_name; + string option_flag_name; + CodeGenerator* generator; + string help_text; + }; + typedef map GeneratorMap; + GeneratorMap generators_by_flag_name_; + GeneratorMap generators_by_option_name_; + // A map from generator names to the parameters specified using the option + // flag. For example, if the user invokes the compiler with: + // protoc --foo_out=outputdir --foo_opt=enable_bar ... + // Then there will be an entry ("--foo_out", "enable_bar") in this map. + map generator_parameters_; + + // See AllowPlugins(). If this is empty, plugins aren't allowed. + string plugin_prefix_; + + // Maps specific plugin names to files. When executing a plugin, this map + // is searched first to find the plugin executable. If not found here, the + // PATH (or other OS-specific search strategy) is searched. + map plugins_; + + // Stuff parsed from command line. + enum Mode { + MODE_COMPILE, // Normal mode: parse .proto files and compile them. + MODE_ENCODE, // --encode: read text from stdin, write binary to stdout. + MODE_DECODE // --decode: read binary from stdin, write text to stdout. + }; + + Mode mode_; + + enum ErrorFormat { + ERROR_FORMAT_GCC, // GCC error output format (default). + ERROR_FORMAT_MSVS // Visual Studio output (--error_format=msvs). + }; + + ErrorFormat error_format_; + + vector > proto_path_; // Search path for proto files. + vector input_files_; // Names of the input proto files. + + // output_directives_ lists all the files we are supposed to output and what + // generator to use for each. + struct OutputDirective { + string name; // E.g. "--foo_out" + CodeGenerator* generator; // NULL for plugins + string parameter; + string output_location; + }; + vector output_directives_; + + // When using --encode or --decode, this names the type we are encoding or + // decoding. (Empty string indicates --decode_raw.) + string codec_type_; + + // If --descriptor_set_out was given, this is the filename to which the + // FileDescriptorSet should be written. Otherwise, empty. + string descriptor_set_name_; + + // True if --include_imports was given, meaning that we should + // write all transitive dependencies to the DescriptorSet. Otherwise, only + // the .proto files listed on the command-line are added. + bool imports_in_descriptor_set_; + + // True if --include_source_info was given, meaning that we should not strip + // SourceCodeInfo from the DescriptorSet. + bool source_info_in_descriptor_set_; + + // Was the --disallow_services flag used? + bool disallow_services_; + + // See SetInputsAreProtoPathRelative(). + bool inputs_are_proto_path_relative_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CommandLineInterface); +}; + +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_COMMAND_LINE_INTERFACE_H__ diff --git a/include/google/protobuf/compiler/cpp/cpp_generator.h b/include/google/protobuf/compiler/cpp/cpp_generator.h new file mode 100644 index 000000000..a90e84d7b --- /dev/null +++ b/include/google/protobuf/compiler/cpp/cpp_generator.h @@ -0,0 +1,72 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// Generates C++ code for a given .proto file. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_GENERATOR_H__ +#define GOOGLE_PROTOBUF_COMPILER_CPP_GENERATOR_H__ + +#include +#include + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +// CodeGenerator implementation which generates a C++ source file and +// header. If you create your own protocol compiler binary and you want +// it to support C++ output, you can do so by registering an instance of this +// CodeGenerator with the CommandLineInterface in your main() function. +class LIBPROTOC_EXPORT CppGenerator : public CodeGenerator { + public: + CppGenerator(); + ~CppGenerator(); + + // implements CodeGenerator ---------------------------------------- + bool Generate(const FileDescriptor* file, + const string& parameter, + GeneratorContext* generator_context, + string* error) const; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CppGenerator); +}; + +} // namespace cpp +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_CPP_GENERATOR_H__ diff --git a/include/google/protobuf/compiler/importer.h b/include/google/protobuf/compiler/importer.h new file mode 100644 index 000000000..7a62fa0e6 --- /dev/null +++ b/include/google/protobuf/compiler/importer.h @@ -0,0 +1,304 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// This file is the public interface to the .proto file parser. + +#ifndef GOOGLE_PROTOBUF_COMPILER_IMPORTER_H__ +#define GOOGLE_PROTOBUF_COMPILER_IMPORTER_H__ + +#include +#include +#include +#include +#include +#include +#include + +namespace google { +namespace protobuf { + +namespace io { class ZeroCopyInputStream; } + +namespace compiler { + +// Defined in this file. +class Importer; +class MultiFileErrorCollector; +class SourceTree; +class DiskSourceTree; + +// TODO(kenton): Move all SourceTree stuff to a separate file? + +// An implementation of DescriptorDatabase which loads files from a SourceTree +// and parses them. +// +// Note: This class is not thread-safe since it maintains a table of source +// code locations for error reporting. However, when a DescriptorPool wraps +// a DescriptorDatabase, it uses mutex locking to make sure only one method +// of the database is called at a time, even if the DescriptorPool is used +// from multiple threads. Therefore, there is only a problem if you create +// multiple DescriptorPools wrapping the same SourceTreeDescriptorDatabase +// and use them from multiple threads. +// +// Note: This class does not implement FindFileContainingSymbol() or +// FindFileContainingExtension(); these will always return false. +class LIBPROTOBUF_EXPORT SourceTreeDescriptorDatabase : public DescriptorDatabase { + public: + SourceTreeDescriptorDatabase(SourceTree* source_tree); + ~SourceTreeDescriptorDatabase(); + + // Instructs the SourceTreeDescriptorDatabase to report any parse errors + // to the given MultiFileErrorCollector. This should be called before + // parsing. error_collector must remain valid until either this method + // is called again or the SourceTreeDescriptorDatabase is destroyed. + void RecordErrorsTo(MultiFileErrorCollector* error_collector) { + error_collector_ = error_collector; + } + + // Gets a DescriptorPool::ErrorCollector which records errors to the + // MultiFileErrorCollector specified with RecordErrorsTo(). This collector + // has the ability to determine exact line and column numbers of errors + // from the information given to it by the DescriptorPool. + DescriptorPool::ErrorCollector* GetValidationErrorCollector() { + using_validation_error_collector_ = true; + return &validation_error_collector_; + } + + // implements DescriptorDatabase ----------------------------------- + bool FindFileByName(const string& filename, FileDescriptorProto* output); + bool FindFileContainingSymbol(const string& symbol_name, + FileDescriptorProto* output); + bool FindFileContainingExtension(const string& containing_type, + int field_number, + FileDescriptorProto* output); + + private: + class SingleFileErrorCollector; + + SourceTree* source_tree_; + MultiFileErrorCollector* error_collector_; + + class LIBPROTOBUF_EXPORT ValidationErrorCollector : public DescriptorPool::ErrorCollector { + public: + ValidationErrorCollector(SourceTreeDescriptorDatabase* owner); + ~ValidationErrorCollector(); + + // implements ErrorCollector --------------------------------------- + void AddError(const string& filename, + const string& element_name, + const Message* descriptor, + ErrorLocation location, + const string& message); + + private: + SourceTreeDescriptorDatabase* owner_; + }; + friend class ValidationErrorCollector; + + bool using_validation_error_collector_; + SourceLocationTable source_locations_; + ValidationErrorCollector validation_error_collector_; +}; + +// Simple interface for parsing .proto files. This wraps the process +// of opening the file, parsing it with a Parser, recursively parsing all its +// imports, and then cross-linking the results to produce a FileDescriptor. +// +// This is really just a thin wrapper around SourceTreeDescriptorDatabase. +// You may find that SourceTreeDescriptorDatabase is more flexible. +// +// TODO(kenton): I feel like this class is not well-named. +class LIBPROTOBUF_EXPORT Importer { + public: + Importer(SourceTree* source_tree, + MultiFileErrorCollector* error_collector); + ~Importer(); + + // Import the given file and build a FileDescriptor representing it. If + // the file is already in the DescriptorPool, the existing FileDescriptor + // will be returned. The FileDescriptor is property of the DescriptorPool, + // and will remain valid until it is destroyed. If any errors occur, they + // will be reported using the error collector and Import() will return NULL. + // + // A particular Importer object will only report errors for a particular + // file once. All future attempts to import the same file will return NULL + // without reporting any errors. The idea is that you might want to import + // a lot of files without seeing the same errors over and over again. If + // you want to see errors for the same files repeatedly, you can use a + // separate Importer object to import each one (but use the same + // DescriptorPool so that they can be cross-linked). + const FileDescriptor* Import(const string& filename); + + // The DescriptorPool in which all imported FileDescriptors and their + // contents are stored. + inline const DescriptorPool* pool() const { + return &pool_; + } + + private: + SourceTreeDescriptorDatabase database_; + DescriptorPool pool_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Importer); +}; + +// If the importer encounters problems while trying to import the proto files, +// it reports them to a MultiFileErrorCollector. +class LIBPROTOBUF_EXPORT MultiFileErrorCollector { + public: + inline MultiFileErrorCollector() {} + virtual ~MultiFileErrorCollector(); + + // Line and column numbers are zero-based. A line number of -1 indicates + // an error with the entire file (e.g. "not found"). + virtual void AddError(const string& filename, int line, int column, + const string& message) = 0; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MultiFileErrorCollector); +}; + +// Abstract interface which represents a directory tree containing proto files. +// Used by the default implementation of Importer to resolve import statements +// Most users will probably want to use the DiskSourceTree implementation, +// below. +class LIBPROTOBUF_EXPORT SourceTree { + public: + inline SourceTree() {} + virtual ~SourceTree(); + + // Open the given file and return a stream that reads it, or NULL if not + // found. The caller takes ownership of the returned object. The filename + // must be a path relative to the root of the source tree and must not + // contain "." or ".." components. + virtual io::ZeroCopyInputStream* Open(const string& filename) = 0; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(SourceTree); +}; + +// An implementation of SourceTree which loads files from locations on disk. +// Multiple mappings can be set up to map locations in the DiskSourceTree to +// locations in the physical filesystem. +class LIBPROTOBUF_EXPORT DiskSourceTree : public SourceTree { + public: + DiskSourceTree(); + ~DiskSourceTree(); + + // Map a path on disk to a location in the SourceTree. The path may be + // either a file or a directory. If it is a directory, the entire tree + // under it will be mapped to the given virtual location. To map a directory + // to the root of the source tree, pass an empty string for virtual_path. + // + // If multiple mapped paths apply when opening a file, they will be searched + // in order. For example, if you do: + // MapPath("bar", "foo/bar"); + // MapPath("", "baz"); + // and then you do: + // Open("bar/qux"); + // the DiskSourceTree will first try to open foo/bar/qux, then baz/bar/qux, + // returning the first one that opens successfuly. + // + // disk_path may be an absolute path or relative to the current directory, + // just like a path you'd pass to open(). + void MapPath(const string& virtual_path, const string& disk_path); + + // Return type for DiskFileToVirtualFile(). + enum DiskFileToVirtualFileResult { + SUCCESS, + SHADOWED, + CANNOT_OPEN, + NO_MAPPING + }; + + // Given a path to a file on disk, find a virtual path mapping to that + // file. The first mapping created with MapPath() whose disk_path contains + // the filename is used. However, that virtual path may not actually be + // usable to open the given file. Possible return values are: + // * SUCCESS: The mapping was found. *virtual_file is filled in so that + // calling Open(*virtual_file) will open the file named by disk_file. + // * SHADOWED: A mapping was found, but using Open() to open this virtual + // path will end up returning some different file. This is because some + // other mapping with a higher precedence also matches this virtual path + // and maps it to a different file that exists on disk. *virtual_file + // is filled in as it would be in the SUCCESS case. *shadowing_disk_file + // is filled in with the disk path of the file which would be opened if + // you were to call Open(*virtual_file). + // * CANNOT_OPEN: The mapping was found and was not shadowed, but the + // file specified cannot be opened. When this value is returned, + // errno will indicate the reason the file cannot be opened. *virtual_file + // will be set to the virtual path as in the SUCCESS case, even though + // it is not useful. + // * NO_MAPPING: Indicates that no mapping was found which contains this + // file. + DiskFileToVirtualFileResult + DiskFileToVirtualFile(const string& disk_file, + string* virtual_file, + string* shadowing_disk_file); + + // Given a virtual path, find the path to the file on disk. + // Return true and update disk_file with the on-disk path if the file exists. + // Return false and leave disk_file untouched if the file doesn't exist. + bool VirtualFileToDiskFile(const string& virtual_file, string* disk_file); + + // implements SourceTree ------------------------------------------- + io::ZeroCopyInputStream* Open(const string& filename); + + private: + struct Mapping { + string virtual_path; + string disk_path; + + inline Mapping(const string& virtual_path_param, + const string& disk_path_param) + : virtual_path(virtual_path_param), disk_path(disk_path_param) {} + }; + vector mappings_; + + // Like Open(), but returns the on-disk path in disk_file if disk_file is + // non-NULL and the file could be successfully opened. + io::ZeroCopyInputStream* OpenVirtualFile(const string& virtual_file, + string* disk_file); + + // Like Open() but given the actual on-disk path. + io::ZeroCopyInputStream* OpenDiskFile(const string& filename); + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DiskSourceTree); +}; + +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_IMPORTER_H__ diff --git a/include/google/protobuf/compiler/java/java_generator.h b/include/google/protobuf/compiler/java/java_generator.h new file mode 100644 index 000000000..888b8d85e --- /dev/null +++ b/include/google/protobuf/compiler/java/java_generator.h @@ -0,0 +1,72 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// Generates Java code for a given .proto file. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_GENERATOR_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_GENERATOR_H__ + +#include +#include + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +// CodeGenerator implementation which generates Java code. If you create your +// own protocol compiler binary and you want it to support Java output, you +// can do so by registering an instance of this CodeGenerator with the +// CommandLineInterface in your main() function. +class LIBPROTOC_EXPORT JavaGenerator : public CodeGenerator { + public: + JavaGenerator(); + ~JavaGenerator(); + + // implements CodeGenerator ---------------------------------------- + bool Generate(const FileDescriptor* file, + const string& parameter, + GeneratorContext* context, + string* error) const; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(JavaGenerator); +}; + +} // namespace java +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_GENERATOR_H__ diff --git a/include/google/protobuf/compiler/parser.h b/include/google/protobuf/compiler/parser.h new file mode 100644 index 000000000..cfd3649be --- /dev/null +++ b/include/google/protobuf/compiler/parser.h @@ -0,0 +1,477 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// Implements parsing of .proto files to FileDescriptorProtos. + +#ifndef GOOGLE_PROTOBUF_COMPILER_PARSER_H__ +#define GOOGLE_PROTOBUF_COMPILER_PARSER_H__ + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace google { +namespace protobuf { class Message; } + +namespace protobuf { +namespace compiler { + +// Defined in this file. +class Parser; +class SourceLocationTable; + +// Implements parsing of protocol definitions (such as .proto files). +// +// Note that most users will be more interested in the Importer class. +// Parser is a lower-level class which simply converts a single .proto file +// to a FileDescriptorProto. It does not resolve import directives or perform +// many other kinds of validation needed to construct a complete +// FileDescriptor. +class LIBPROTOBUF_EXPORT Parser { + public: + Parser(); + ~Parser(); + + // Parse the entire input and construct a FileDescriptorProto representing + // it. Returns true if no errors occurred, false otherwise. + bool Parse(io::Tokenizer* input, FileDescriptorProto* file); + + // Optional fetaures: + + // DEPRECATED: New code should use the SourceCodeInfo embedded in the + // FileDescriptorProto. + // + // Requests that locations of certain definitions be recorded to the given + // SourceLocationTable while parsing. This can be used to look up exact line + // and column numbers for errors reported by DescriptorPool during validation. + // Set to NULL (the default) to discard source location information. + void RecordSourceLocationsTo(SourceLocationTable* location_table) { + source_location_table_ = location_table; + } + + // Requests that errors be recorded to the given ErrorCollector while + // parsing. Set to NULL (the default) to discard error messages. + void RecordErrorsTo(io::ErrorCollector* error_collector) { + error_collector_ = error_collector; + } + + // Returns the identifier used in the "syntax = " declaration, if one was + // seen during the last call to Parse(), or the empty string otherwise. + const string& GetSyntaxIdentifier() { return syntax_identifier_; } + + // If set true, input files will be required to begin with a syntax + // identifier. Otherwise, files may omit this. If a syntax identifier + // is provided, it must be 'syntax = "proto2";' and must appear at the + // top of this file regardless of whether or not it was required. + void SetRequireSyntaxIdentifier(bool value) { + require_syntax_identifier_ = value; + } + + // Call SetStopAfterSyntaxIdentifier(true) to tell the parser to stop + // parsing as soon as it has seen the syntax identifier, or lack thereof. + // This is useful for quickly identifying the syntax of the file without + // parsing the whole thing. If this is enabled, no error will be recorded + // if the syntax identifier is something other than "proto2" (since + // presumably the caller intends to deal with that), but other kinds of + // errors (e.g. parse errors) will still be reported. When this is enabled, + // you may pass a NULL FileDescriptorProto to Parse(). + void SetStopAfterSyntaxIdentifier(bool value) { + stop_after_syntax_identifier_ = value; + } + + private: + class LocationRecorder; + + // ================================================================= + // Error recovery helpers + + // Consume the rest of the current statement. This consumes tokens + // until it sees one of: + // ';' Consumes the token and returns. + // '{' Consumes the brace then calls SkipRestOfBlock(). + // '}' Returns without consuming. + // EOF Returns (can't consume). + // The Parser often calls SkipStatement() after encountering a syntax + // error. This allows it to go on parsing the following lines, allowing + // it to report more than just one error in the file. + void SkipStatement(); + + // Consume the rest of the current block, including nested blocks, + // ending after the closing '}' is encountered and consumed, or at EOF. + void SkipRestOfBlock(); + + // ----------------------------------------------------------------- + // Single-token consuming helpers + // + // These make parsing code more readable. + + // True if the current token is TYPE_END. + inline bool AtEnd(); + + // True if the next token matches the given text. + inline bool LookingAt(const char* text); + // True if the next token is of the given type. + inline bool LookingAtType(io::Tokenizer::TokenType token_type); + + // If the next token exactly matches the text given, consume it and return + // true. Otherwise, return false without logging an error. + bool TryConsume(const char* text); + + // These attempt to read some kind of token from the input. If successful, + // they return true. Otherwise they return false and add the given error + // to the error list. + + // Consume a token with the exact text given. + bool Consume(const char* text, const char* error); + // Same as above, but automatically generates the error "Expected \"text\".", + // where "text" is the expected token text. + bool Consume(const char* text); + // Consume a token of type IDENTIFIER and store its text in "output". + bool ConsumeIdentifier(string* output, const char* error); + // Consume an integer and store its value in "output". + bool ConsumeInteger(int* output, const char* error); + // Consume a signed integer and store its value in "output". + bool ConsumeSignedInteger(int* output, const char* error); + // Consume a 64-bit integer and store its value in "output". If the value + // is greater than max_value, an error will be reported. + bool ConsumeInteger64(uint64 max_value, uint64* output, const char* error); + // Consume a number and store its value in "output". This will accept + // tokens of either INTEGER or FLOAT type. + bool ConsumeNumber(double* output, const char* error); + // Consume a string literal and store its (unescaped) value in "output". + bool ConsumeString(string* output, const char* error); + + // Consume a token representing the end of the statement. Comments between + // this token and the next will be harvested for documentation. The given + // LocationRecorder should refer to the declaration that was just parsed; + // it will be populated with these comments. + // + // TODO(kenton): The LocationRecorder is const because historically locations + // have been passed around by const reference, for no particularly good + // reason. We should probably go through and change them all to mutable + // pointer to make this more intuitive. + bool TryConsumeEndOfDeclaration(const char* text, + const LocationRecorder* location); + bool ConsumeEndOfDeclaration(const char* text, + const LocationRecorder* location); + + // ----------------------------------------------------------------- + // Error logging helpers + + // Invokes error_collector_->AddError(), if error_collector_ is not NULL. + void AddError(int line, int column, const string& error); + + // Invokes error_collector_->AddError() with the line and column number + // of the current token. + void AddError(const string& error); + + // Records a location in the SourceCodeInfo.location table (see + // descriptor.proto). We use RAII to ensure that the start and end locations + // are recorded -- the constructor records the start location and the + // destructor records the end location. Since the parser is + // recursive-descent, this works out beautifully. + class LIBPROTOBUF_EXPORT LocationRecorder { + public: + // Construct the file's "root" location. + LocationRecorder(Parser* parser); + + // Construct a location that represents a declaration nested within the + // given parent. E.g. a field's location is nested within the location + // for a message type. The parent's path will be copied, so you should + // call AddPath() only to add the path components leading from the parent + // to the child (as opposed to leading from the root to the child). + LocationRecorder(const LocationRecorder& parent); + + // Convenience constructors that call AddPath() one or two times. + LocationRecorder(const LocationRecorder& parent, int path1); + LocationRecorder(const LocationRecorder& parent, int path1, int path2); + + ~LocationRecorder(); + + // Add a path component. See SourceCodeInfo.Location.path in + // descriptor.proto. + void AddPath(int path_component); + + // By default the location is considered to start at the current token at + // the time the LocationRecorder is created. StartAt() sets the start + // location to the given token instead. + void StartAt(const io::Tokenizer::Token& token); + + // By default the location is considered to end at the previous token at + // the time the LocationRecorder is destroyed. EndAt() sets the end + // location to the given token instead. + void EndAt(const io::Tokenizer::Token& token); + + // Records the start point of this location to the SourceLocationTable that + // was passed to RecordSourceLocationsTo(), if any. SourceLocationTable + // is an older way of keeping track of source locations which is still + // used in some places. + void RecordLegacyLocation(const Message* descriptor, + DescriptorPool::ErrorCollector::ErrorLocation location); + + // Attaches leading and trailing comments to the location. The two strings + // will be swapped into place, so after this is called *leading and + // *trailing will be empty. + // + // TODO(kenton): See comment on TryConsumeEndOfDeclaration(), above, for + // why this is const. + void AttachComments(string* leading, string* trailing) const; + + private: + Parser* parser_; + SourceCodeInfo::Location* location_; + + void Init(const LocationRecorder& parent); + }; + + // ================================================================= + // Parsers for various language constructs + + // Parses the "syntax = \"proto2\";" line at the top of the file. Returns + // false if it failed to parse or if the syntax identifier was not + // recognized. + bool ParseSyntaxIdentifier(); + + // These methods parse various individual bits of code. They return + // false if they completely fail to parse the construct. In this case, + // it is probably necessary to skip the rest of the statement to recover. + // However, if these methods return true, it does NOT mean that there + // were no errors; only that there were no *syntax* errors. For instance, + // if a service method is defined using proper syntax but uses a primitive + // type as its input or output, ParseMethodField() still returns true + // and only reports the error by calling AddError(). In practice, this + // makes logic much simpler for the caller. + + // Parse a top-level message, enum, service, etc. + bool ParseTopLevelStatement(FileDescriptorProto* file, + const LocationRecorder& root_location); + + // Parse various language high-level language construrcts. + bool ParseMessageDefinition(DescriptorProto* message, + const LocationRecorder& message_location); + bool ParseEnumDefinition(EnumDescriptorProto* enum_type, + const LocationRecorder& enum_location); + bool ParseServiceDefinition(ServiceDescriptorProto* service, + const LocationRecorder& service_location); + bool ParsePackage(FileDescriptorProto* file, + const LocationRecorder& root_location); + bool ParseImport(RepeatedPtrField* dependency, + RepeatedField* public_dependency, + RepeatedField* weak_dependency, + const LocationRecorder& root_location); + bool ParseOption(Message* options, + const LocationRecorder& options_location); + + // These methods parse the contents of a message, enum, or service type and + // add them to the given object. They consume the entire block including + // the beginning and ending brace. + bool ParseMessageBlock(DescriptorProto* message, + const LocationRecorder& message_location); + bool ParseEnumBlock(EnumDescriptorProto* enum_type, + const LocationRecorder& enum_location); + bool ParseServiceBlock(ServiceDescriptorProto* service, + const LocationRecorder& service_location); + + // Parse one statement within a message, enum, or service block, inclunding + // final semicolon. + bool ParseMessageStatement(DescriptorProto* message, + const LocationRecorder& message_location); + bool ParseEnumStatement(EnumDescriptorProto* message, + const LocationRecorder& enum_location); + bool ParseServiceStatement(ServiceDescriptorProto* message, + const LocationRecorder& service_location); + + // Parse a field of a message. If the field is a group, its type will be + // added to "messages". + // + // parent_location and location_field_number_for_nested_type are needed when + // parsing groups -- we need to generate a nested message type within the + // parent and record its location accordingly. Since the parent could be + // either a FileDescriptorProto or a DescriptorProto, we must pass in the + // correct field number to use. + bool ParseMessageField(FieldDescriptorProto* field, + RepeatedPtrField* messages, + const LocationRecorder& parent_location, + int location_field_number_for_nested_type, + const LocationRecorder& field_location); + + // Parse an "extensions" declaration. + bool ParseExtensions(DescriptorProto* message, + const LocationRecorder& extensions_location); + + // Parse an "extend" declaration. (See also comments for + // ParseMessageField().) + bool ParseExtend(RepeatedPtrField* extensions, + RepeatedPtrField* messages, + const LocationRecorder& parent_location, + int location_field_number_for_nested_type, + const LocationRecorder& extend_location); + + // Parse a single enum value within an enum block. + bool ParseEnumConstant(EnumValueDescriptorProto* enum_value, + const LocationRecorder& enum_value_location); + + // Parse enum constant options, i.e. the list in square brackets at the end + // of the enum constant value definition. + bool ParseEnumConstantOptions(EnumValueDescriptorProto* value, + const LocationRecorder& enum_value_location); + + // Parse a single method within a service definition. + bool ParseServiceMethod(MethodDescriptorProto* method, + const LocationRecorder& method_location); + + + // Parse options of a single method or stream. + bool ParseOptions(const LocationRecorder& parent_location, + const int optionsFieldNumber, + Message* mutable_options); + + // Parse "required", "optional", or "repeated" and fill in "label" + // with the value. + bool ParseLabel(FieldDescriptorProto::Label* label); + + // Parse a type name and fill in "type" (if it is a primitive) or + // "type_name" (if it is not) with the type parsed. + bool ParseType(FieldDescriptorProto::Type* type, + string* type_name); + // Parse a user-defined type and fill in "type_name" with the name. + // If a primitive type is named, it is treated as an error. + bool ParseUserDefinedType(string* type_name); + + // Parses field options, i.e. the stuff in square brackets at the end + // of a field definition. Also parses default value. + bool ParseFieldOptions(FieldDescriptorProto* field, + const LocationRecorder& field_location); + + // Parse the "default" option. This needs special handling because its + // type is the field's type. + bool ParseDefaultAssignment(FieldDescriptorProto* field, + const LocationRecorder& field_location); + + enum OptionStyle { + OPTION_ASSIGNMENT, // just "name = value" + OPTION_STATEMENT // "option name = value;" + }; + + // Parse a single option name/value pair, e.g. "ctype = CORD". The name + // identifies a field of the given Message, and the value of that field + // is set to the parsed value. + bool ParseOption(Message* options, + const LocationRecorder& options_location, + OptionStyle style); + + // Parses a single part of a multipart option name. A multipart name consists + // of names separated by dots. Each name is either an identifier or a series + // of identifiers separated by dots and enclosed in parentheses. E.g., + // "foo.(bar.baz).qux". + bool ParseOptionNamePart(UninterpretedOption* uninterpreted_option, + const LocationRecorder& part_location); + + // Parses a string surrounded by balanced braces. Strips off the outer + // braces and stores the enclosed string in *value. + // E.g., + // { foo } *value gets 'foo' + // { foo { bar: box } } *value gets 'foo { bar: box }' + // {} *value gets '' + // + // REQUIRES: LookingAt("{") + // When finished successfully, we are looking at the first token past + // the ending brace. + bool ParseUninterpretedBlock(string* value); + + // ================================================================= + + io::Tokenizer* input_; + io::ErrorCollector* error_collector_; + SourceCodeInfo* source_code_info_; + SourceLocationTable* source_location_table_; // legacy + bool had_errors_; + bool require_syntax_identifier_; + bool stop_after_syntax_identifier_; + string syntax_identifier_; + + // Leading doc comments for the next declaration. These are not complete + // yet; use ConsumeEndOfDeclaration() to get the complete comments. + string upcoming_doc_comments_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Parser); +}; + +// A table mapping (descriptor, ErrorLocation) pairs -- as reported by +// DescriptorPool when validating descriptors -- to line and column numbers +// within the original source code. +// +// This is semi-obsolete: FileDescriptorProto.source_code_info now contains +// far more complete information about source locations. However, as of this +// writing you still need to use SourceLocationTable when integrating with +// DescriptorPool. +class LIBPROTOBUF_EXPORT SourceLocationTable { + public: + SourceLocationTable(); + ~SourceLocationTable(); + + // Finds the precise location of the given error and fills in *line and + // *column with the line and column numbers. If not found, sets *line to + // -1 and *column to 0 (since line = -1 is used to mean "error has no exact + // location" in the ErrorCollector interface). Returns true if found, false + // otherwise. + bool Find(const Message* descriptor, + DescriptorPool::ErrorCollector::ErrorLocation location, + int* line, int* column) const; + + // Adds a location to the table. + void Add(const Message* descriptor, + DescriptorPool::ErrorCollector::ErrorLocation location, + int line, int column); + + // Clears the contents of the table. + void Clear(); + + private: + typedef map< + pair, + pair > LocationMap; + LocationMap location_map_; +}; + +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_PARSER_H__ diff --git a/include/google/protobuf/compiler/plugin.h b/include/google/protobuf/compiler/plugin.h new file mode 100644 index 000000000..6fa2de127 --- /dev/null +++ b/include/google/protobuf/compiler/plugin.h @@ -0,0 +1,72 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// +// Front-end for protoc code generator plugins written in C++. +// +// To implement a protoc plugin in C++, simply write an implementation of +// CodeGenerator, then create a main() function like: +// int main(int argc, char* argv[]) { +// MyCodeGenerator generator; +// return google::protobuf::compiler::PluginMain(argc, argv, &generator); +// } +// You must link your plugin against libprotobuf and libprotoc. +// +// To get protoc to use the plugin, do one of the following: +// * Place the plugin binary somewhere in the PATH and give it the name +// "protoc-gen-NAME" (replacing "NAME" with the name of your plugin). If you +// then invoke protoc with the parameter --NAME_out=OUT_DIR (again, replace +// "NAME" with your plugin's name), protoc will invoke your plugin to generate +// the output, which will be placed in OUT_DIR. +// * Place the plugin binary anywhere, with any name, and pass the --plugin +// parameter to protoc to direct it to your plugin like so: +// protoc --plugin=protoc-gen-NAME=path/to/mybinary --NAME_out=OUT_DIR +// On Windows, make sure to include the .exe suffix: +// protoc --plugin=protoc-gen-NAME=path/to/mybinary.exe --NAME_out=OUT_DIR + +#ifndef GOOGLE_PROTOBUF_COMPILER_PLUGIN_H__ +#define GOOGLE_PROTOBUF_COMPILER_PLUGIN_H__ + +#include +namespace google { +namespace protobuf { +namespace compiler { + +class CodeGenerator; // code_generator.h + +// Implements main() for a protoc plugin exposing the given code generator. +LIBPROTOC_EXPORT int PluginMain(int argc, char* argv[], const CodeGenerator* generator); + +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_PLUGIN_H__ diff --git a/include/google/protobuf/compiler/plugin.pb.h b/include/google/protobuf/compiler/plugin.pb.h new file mode 100644 index 000000000..68cc21c7f --- /dev/null +++ b/include/google/protobuf/compiler/plugin.pb.h @@ -0,0 +1,856 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: google/protobuf/compiler/plugin.proto + +#ifndef PROTOBUF_google_2fprotobuf_2fcompiler_2fplugin_2eproto__INCLUDED +#define PROTOBUF_google_2fprotobuf_2fcompiler_2fplugin_2eproto__INCLUDED + +#include + +#include + +#if GOOGLE_PROTOBUF_VERSION < 2005000 +#error This file was generated by a newer version of protoc which is +#error incompatible with your Protocol Buffer headers. Please update +#error your headers. +#endif +#if 2005000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION +#error This file was generated by an older version of protoc which is +#error incompatible with your Protocol Buffer headers. Please +#error regenerate this file with a newer version of protoc. +#endif + +#include +#include +#include +#include +#include +#include "google/protobuf/descriptor.pb.h" +// @@protoc_insertion_point(includes) + +namespace google { +namespace protobuf { +namespace compiler { + +// Internal implementation detail -- do not call these. +void LIBPROTOC_EXPORT protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); +void protobuf_AssignDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); +void protobuf_ShutdownFile_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); + +class CodeGeneratorRequest; +class CodeGeneratorResponse; +class CodeGeneratorResponse_File; + +// =================================================================== + +class LIBPROTOC_EXPORT CodeGeneratorRequest : public ::google::protobuf::Message { + public: + CodeGeneratorRequest(); + virtual ~CodeGeneratorRequest(); + + CodeGeneratorRequest(const CodeGeneratorRequest& from); + + inline CodeGeneratorRequest& operator=(const CodeGeneratorRequest& from) { + CopyFrom(from); + return *this; + } + + inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { + return _unknown_fields_; + } + + inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { + return &_unknown_fields_; + } + + static const ::google::protobuf::Descriptor* descriptor(); + static const CodeGeneratorRequest& default_instance(); + + void Swap(CodeGeneratorRequest* other); + + // implements Message ---------------------------------------------- + + CodeGeneratorRequest* New() const; + void CopyFrom(const ::google::protobuf::Message& from); + void MergeFrom(const ::google::protobuf::Message& from); + void CopyFrom(const CodeGeneratorRequest& from); + void MergeFrom(const CodeGeneratorRequest& from); + void Clear(); + bool IsInitialized() const; + + int ByteSize() const; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input); + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const; + ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const; + int GetCachedSize() const { return _cached_size_; } + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + public: + + ::google::protobuf::Metadata GetMetadata() const; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + // repeated string file_to_generate = 1; + inline int file_to_generate_size() const; + inline void clear_file_to_generate(); + static const int kFileToGenerateFieldNumber = 1; + inline const ::std::string& file_to_generate(int index) const; + inline ::std::string* mutable_file_to_generate(int index); + inline void set_file_to_generate(int index, const ::std::string& value); + inline void set_file_to_generate(int index, const char* value); + inline void set_file_to_generate(int index, const char* value, size_t size); + inline ::std::string* add_file_to_generate(); + inline void add_file_to_generate(const ::std::string& value); + inline void add_file_to_generate(const char* value); + inline void add_file_to_generate(const char* value, size_t size); + inline const ::google::protobuf::RepeatedPtrField< ::std::string>& file_to_generate() const; + inline ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_file_to_generate(); + + // optional string parameter = 2; + inline bool has_parameter() const; + inline void clear_parameter(); + static const int kParameterFieldNumber = 2; + inline const ::std::string& parameter() const; + inline void set_parameter(const ::std::string& value); + inline void set_parameter(const char* value); + inline void set_parameter(const char* value, size_t size); + inline ::std::string* mutable_parameter(); + inline ::std::string* release_parameter(); + inline void set_allocated_parameter(::std::string* parameter); + + // repeated .google.protobuf.FileDescriptorProto proto_file = 15; + inline int proto_file_size() const; + inline void clear_proto_file(); + static const int kProtoFileFieldNumber = 15; + inline const ::google::protobuf::FileDescriptorProto& proto_file(int index) const; + inline ::google::protobuf::FileDescriptorProto* mutable_proto_file(int index); + inline ::google::protobuf::FileDescriptorProto* add_proto_file(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >& + proto_file() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >* + mutable_proto_file(); + + // @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorRequest) + private: + inline void set_has_parameter(); + inline void clear_has_parameter(); + + ::google::protobuf::UnknownFieldSet _unknown_fields_; + + ::google::protobuf::RepeatedPtrField< ::std::string> file_to_generate_; + ::std::string* parameter_; + ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto > proto_file_; + + mutable int _cached_size_; + ::google::protobuf::uint32 _has_bits_[(3 + 31) / 32]; + + friend void LIBPROTOC_EXPORT protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); + friend void protobuf_ShutdownFile_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); + + void InitAsDefaultInstance(); + static CodeGeneratorRequest* default_instance_; +}; +// ------------------------------------------------------------------- + +class LIBPROTOC_EXPORT CodeGeneratorResponse_File : public ::google::protobuf::Message { + public: + CodeGeneratorResponse_File(); + virtual ~CodeGeneratorResponse_File(); + + CodeGeneratorResponse_File(const CodeGeneratorResponse_File& from); + + inline CodeGeneratorResponse_File& operator=(const CodeGeneratorResponse_File& from) { + CopyFrom(from); + return *this; + } + + inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { + return _unknown_fields_; + } + + inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { + return &_unknown_fields_; + } + + static const ::google::protobuf::Descriptor* descriptor(); + static const CodeGeneratorResponse_File& default_instance(); + + void Swap(CodeGeneratorResponse_File* other); + + // implements Message ---------------------------------------------- + + CodeGeneratorResponse_File* New() const; + void CopyFrom(const ::google::protobuf::Message& from); + void MergeFrom(const ::google::protobuf::Message& from); + void CopyFrom(const CodeGeneratorResponse_File& from); + void MergeFrom(const CodeGeneratorResponse_File& from); + void Clear(); + bool IsInitialized() const; + + int ByteSize() const; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input); + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const; + ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const; + int GetCachedSize() const { return _cached_size_; } + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + public: + + ::google::protobuf::Metadata GetMetadata() const; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + // optional string name = 1; + inline bool has_name() const; + inline void clear_name(); + static const int kNameFieldNumber = 1; + inline const ::std::string& name() const; + inline void set_name(const ::std::string& value); + inline void set_name(const char* value); + inline void set_name(const char* value, size_t size); + inline ::std::string* mutable_name(); + inline ::std::string* release_name(); + inline void set_allocated_name(::std::string* name); + + // optional string insertion_point = 2; + inline bool has_insertion_point() const; + inline void clear_insertion_point(); + static const int kInsertionPointFieldNumber = 2; + inline const ::std::string& insertion_point() const; + inline void set_insertion_point(const ::std::string& value); + inline void set_insertion_point(const char* value); + inline void set_insertion_point(const char* value, size_t size); + inline ::std::string* mutable_insertion_point(); + inline ::std::string* release_insertion_point(); + inline void set_allocated_insertion_point(::std::string* insertion_point); + + // optional string content = 15; + inline bool has_content() const; + inline void clear_content(); + static const int kContentFieldNumber = 15; + inline const ::std::string& content() const; + inline void set_content(const ::std::string& value); + inline void set_content(const char* value); + inline void set_content(const char* value, size_t size); + inline ::std::string* mutable_content(); + inline ::std::string* release_content(); + inline void set_allocated_content(::std::string* content); + + // @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorResponse.File) + private: + inline void set_has_name(); + inline void clear_has_name(); + inline void set_has_insertion_point(); + inline void clear_has_insertion_point(); + inline void set_has_content(); + inline void clear_has_content(); + + ::google::protobuf::UnknownFieldSet _unknown_fields_; + + ::std::string* name_; + ::std::string* insertion_point_; + ::std::string* content_; + + mutable int _cached_size_; + ::google::protobuf::uint32 _has_bits_[(3 + 31) / 32]; + + friend void LIBPROTOC_EXPORT protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); + friend void protobuf_ShutdownFile_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); + + void InitAsDefaultInstance(); + static CodeGeneratorResponse_File* default_instance_; +}; +// ------------------------------------------------------------------- + +class LIBPROTOC_EXPORT CodeGeneratorResponse : public ::google::protobuf::Message { + public: + CodeGeneratorResponse(); + virtual ~CodeGeneratorResponse(); + + CodeGeneratorResponse(const CodeGeneratorResponse& from); + + inline CodeGeneratorResponse& operator=(const CodeGeneratorResponse& from) { + CopyFrom(from); + return *this; + } + + inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { + return _unknown_fields_; + } + + inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { + return &_unknown_fields_; + } + + static const ::google::protobuf::Descriptor* descriptor(); + static const CodeGeneratorResponse& default_instance(); + + void Swap(CodeGeneratorResponse* other); + + // implements Message ---------------------------------------------- + + CodeGeneratorResponse* New() const; + void CopyFrom(const ::google::protobuf::Message& from); + void MergeFrom(const ::google::protobuf::Message& from); + void CopyFrom(const CodeGeneratorResponse& from); + void MergeFrom(const CodeGeneratorResponse& from); + void Clear(); + bool IsInitialized() const; + + int ByteSize() const; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input); + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const; + ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const; + int GetCachedSize() const { return _cached_size_; } + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + public: + + ::google::protobuf::Metadata GetMetadata() const; + + // nested types ---------------------------------------------------- + + typedef CodeGeneratorResponse_File File; + + // accessors ------------------------------------------------------- + + // optional string error = 1; + inline bool has_error() const; + inline void clear_error(); + static const int kErrorFieldNumber = 1; + inline const ::std::string& error() const; + inline void set_error(const ::std::string& value); + inline void set_error(const char* value); + inline void set_error(const char* value, size_t size); + inline ::std::string* mutable_error(); + inline ::std::string* release_error(); + inline void set_allocated_error(::std::string* error); + + // repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15; + inline int file_size() const; + inline void clear_file(); + static const int kFileFieldNumber = 15; + inline const ::google::protobuf::compiler::CodeGeneratorResponse_File& file(int index) const; + inline ::google::protobuf::compiler::CodeGeneratorResponse_File* mutable_file(int index); + inline ::google::protobuf::compiler::CodeGeneratorResponse_File* add_file(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >& + file() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >* + mutable_file(); + + // @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorResponse) + private: + inline void set_has_error(); + inline void clear_has_error(); + + ::google::protobuf::UnknownFieldSet _unknown_fields_; + + ::std::string* error_; + ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File > file_; + + mutable int _cached_size_; + ::google::protobuf::uint32 _has_bits_[(2 + 31) / 32]; + + friend void LIBPROTOC_EXPORT protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); + friend void protobuf_ShutdownFile_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); + + void InitAsDefaultInstance(); + static CodeGeneratorResponse* default_instance_; +}; +// =================================================================== + + +// =================================================================== + +// CodeGeneratorRequest + +// repeated string file_to_generate = 1; +inline int CodeGeneratorRequest::file_to_generate_size() const { + return file_to_generate_.size(); +} +inline void CodeGeneratorRequest::clear_file_to_generate() { + file_to_generate_.Clear(); +} +inline const ::std::string& CodeGeneratorRequest::file_to_generate(int index) const { + return file_to_generate_.Get(index); +} +inline ::std::string* CodeGeneratorRequest::mutable_file_to_generate(int index) { + return file_to_generate_.Mutable(index); +} +inline void CodeGeneratorRequest::set_file_to_generate(int index, const ::std::string& value) { + file_to_generate_.Mutable(index)->assign(value); +} +inline void CodeGeneratorRequest::set_file_to_generate(int index, const char* value) { + file_to_generate_.Mutable(index)->assign(value); +} +inline void CodeGeneratorRequest::set_file_to_generate(int index, const char* value, size_t size) { + file_to_generate_.Mutable(index)->assign( + reinterpret_cast(value), size); +} +inline ::std::string* CodeGeneratorRequest::add_file_to_generate() { + return file_to_generate_.Add(); +} +inline void CodeGeneratorRequest::add_file_to_generate(const ::std::string& value) { + file_to_generate_.Add()->assign(value); +} +inline void CodeGeneratorRequest::add_file_to_generate(const char* value) { + file_to_generate_.Add()->assign(value); +} +inline void CodeGeneratorRequest::add_file_to_generate(const char* value, size_t size) { + file_to_generate_.Add()->assign(reinterpret_cast(value), size); +} +inline const ::google::protobuf::RepeatedPtrField< ::std::string>& +CodeGeneratorRequest::file_to_generate() const { + return file_to_generate_; +} +inline ::google::protobuf::RepeatedPtrField< ::std::string>* +CodeGeneratorRequest::mutable_file_to_generate() { + return &file_to_generate_; +} + +// optional string parameter = 2; +inline bool CodeGeneratorRequest::has_parameter() const { + return (_has_bits_[0] & 0x00000002u) != 0; +} +inline void CodeGeneratorRequest::set_has_parameter() { + _has_bits_[0] |= 0x00000002u; +} +inline void CodeGeneratorRequest::clear_has_parameter() { + _has_bits_[0] &= ~0x00000002u; +} +inline void CodeGeneratorRequest::clear_parameter() { + if (parameter_ != &::google::protobuf::internal::kEmptyString) { + parameter_->clear(); + } + clear_has_parameter(); +} +inline const ::std::string& CodeGeneratorRequest::parameter() const { + return *parameter_; +} +inline void CodeGeneratorRequest::set_parameter(const ::std::string& value) { + set_has_parameter(); + if (parameter_ == &::google::protobuf::internal::kEmptyString) { + parameter_ = new ::std::string; + } + parameter_->assign(value); +} +inline void CodeGeneratorRequest::set_parameter(const char* value) { + set_has_parameter(); + if (parameter_ == &::google::protobuf::internal::kEmptyString) { + parameter_ = new ::std::string; + } + parameter_->assign(value); +} +inline void CodeGeneratorRequest::set_parameter(const char* value, size_t size) { + set_has_parameter(); + if (parameter_ == &::google::protobuf::internal::kEmptyString) { + parameter_ = new ::std::string; + } + parameter_->assign(reinterpret_cast(value), size); +} +inline ::std::string* CodeGeneratorRequest::mutable_parameter() { + set_has_parameter(); + if (parameter_ == &::google::protobuf::internal::kEmptyString) { + parameter_ = new ::std::string; + } + return parameter_; +} +inline ::std::string* CodeGeneratorRequest::release_parameter() { + clear_has_parameter(); + if (parameter_ == &::google::protobuf::internal::kEmptyString) { + return NULL; + } else { + ::std::string* temp = parameter_; + parameter_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + return temp; + } +} +inline void CodeGeneratorRequest::set_allocated_parameter(::std::string* parameter) { + if (parameter_ != &::google::protobuf::internal::kEmptyString) { + delete parameter_; + } + if (parameter) { + set_has_parameter(); + parameter_ = parameter; + } else { + clear_has_parameter(); + parameter_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + } +} + +// repeated .google.protobuf.FileDescriptorProto proto_file = 15; +inline int CodeGeneratorRequest::proto_file_size() const { + return proto_file_.size(); +} +inline void CodeGeneratorRequest::clear_proto_file() { + proto_file_.Clear(); +} +inline const ::google::protobuf::FileDescriptorProto& CodeGeneratorRequest::proto_file(int index) const { + return proto_file_.Get(index); +} +inline ::google::protobuf::FileDescriptorProto* CodeGeneratorRequest::mutable_proto_file(int index) { + return proto_file_.Mutable(index); +} +inline ::google::protobuf::FileDescriptorProto* CodeGeneratorRequest::add_proto_file() { + return proto_file_.Add(); +} +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >& +CodeGeneratorRequest::proto_file() const { + return proto_file_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >* +CodeGeneratorRequest::mutable_proto_file() { + return &proto_file_; +} + +// ------------------------------------------------------------------- + +// CodeGeneratorResponse_File + +// optional string name = 1; +inline bool CodeGeneratorResponse_File::has_name() const { + return (_has_bits_[0] & 0x00000001u) != 0; +} +inline void CodeGeneratorResponse_File::set_has_name() { + _has_bits_[0] |= 0x00000001u; +} +inline void CodeGeneratorResponse_File::clear_has_name() { + _has_bits_[0] &= ~0x00000001u; +} +inline void CodeGeneratorResponse_File::clear_name() { + if (name_ != &::google::protobuf::internal::kEmptyString) { + name_->clear(); + } + clear_has_name(); +} +inline const ::std::string& CodeGeneratorResponse_File::name() const { + return *name_; +} +inline void CodeGeneratorResponse_File::set_name(const ::std::string& value) { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + name_->assign(value); +} +inline void CodeGeneratorResponse_File::set_name(const char* value) { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + name_->assign(value); +} +inline void CodeGeneratorResponse_File::set_name(const char* value, size_t size) { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + name_->assign(reinterpret_cast(value), size); +} +inline ::std::string* CodeGeneratorResponse_File::mutable_name() { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + return name_; +} +inline ::std::string* CodeGeneratorResponse_File::release_name() { + clear_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + return NULL; + } else { + ::std::string* temp = name_; + name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + return temp; + } +} +inline void CodeGeneratorResponse_File::set_allocated_name(::std::string* name) { + if (name_ != &::google::protobuf::internal::kEmptyString) { + delete name_; + } + if (name) { + set_has_name(); + name_ = name; + } else { + clear_has_name(); + name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + } +} + +// optional string insertion_point = 2; +inline bool CodeGeneratorResponse_File::has_insertion_point() const { + return (_has_bits_[0] & 0x00000002u) != 0; +} +inline void CodeGeneratorResponse_File::set_has_insertion_point() { + _has_bits_[0] |= 0x00000002u; +} +inline void CodeGeneratorResponse_File::clear_has_insertion_point() { + _has_bits_[0] &= ~0x00000002u; +} +inline void CodeGeneratorResponse_File::clear_insertion_point() { + if (insertion_point_ != &::google::protobuf::internal::kEmptyString) { + insertion_point_->clear(); + } + clear_has_insertion_point(); +} +inline const ::std::string& CodeGeneratorResponse_File::insertion_point() const { + return *insertion_point_; +} +inline void CodeGeneratorResponse_File::set_insertion_point(const ::std::string& value) { + set_has_insertion_point(); + if (insertion_point_ == &::google::protobuf::internal::kEmptyString) { + insertion_point_ = new ::std::string; + } + insertion_point_->assign(value); +} +inline void CodeGeneratorResponse_File::set_insertion_point(const char* value) { + set_has_insertion_point(); + if (insertion_point_ == &::google::protobuf::internal::kEmptyString) { + insertion_point_ = new ::std::string; + } + insertion_point_->assign(value); +} +inline void CodeGeneratorResponse_File::set_insertion_point(const char* value, size_t size) { + set_has_insertion_point(); + if (insertion_point_ == &::google::protobuf::internal::kEmptyString) { + insertion_point_ = new ::std::string; + } + insertion_point_->assign(reinterpret_cast(value), size); +} +inline ::std::string* CodeGeneratorResponse_File::mutable_insertion_point() { + set_has_insertion_point(); + if (insertion_point_ == &::google::protobuf::internal::kEmptyString) { + insertion_point_ = new ::std::string; + } + return insertion_point_; +} +inline ::std::string* CodeGeneratorResponse_File::release_insertion_point() { + clear_has_insertion_point(); + if (insertion_point_ == &::google::protobuf::internal::kEmptyString) { + return NULL; + } else { + ::std::string* temp = insertion_point_; + insertion_point_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + return temp; + } +} +inline void CodeGeneratorResponse_File::set_allocated_insertion_point(::std::string* insertion_point) { + if (insertion_point_ != &::google::protobuf::internal::kEmptyString) { + delete insertion_point_; + } + if (insertion_point) { + set_has_insertion_point(); + insertion_point_ = insertion_point; + } else { + clear_has_insertion_point(); + insertion_point_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + } +} + +// optional string content = 15; +inline bool CodeGeneratorResponse_File::has_content() const { + return (_has_bits_[0] & 0x00000004u) != 0; +} +inline void CodeGeneratorResponse_File::set_has_content() { + _has_bits_[0] |= 0x00000004u; +} +inline void CodeGeneratorResponse_File::clear_has_content() { + _has_bits_[0] &= ~0x00000004u; +} +inline void CodeGeneratorResponse_File::clear_content() { + if (content_ != &::google::protobuf::internal::kEmptyString) { + content_->clear(); + } + clear_has_content(); +} +inline const ::std::string& CodeGeneratorResponse_File::content() const { + return *content_; +} +inline void CodeGeneratorResponse_File::set_content(const ::std::string& value) { + set_has_content(); + if (content_ == &::google::protobuf::internal::kEmptyString) { + content_ = new ::std::string; + } + content_->assign(value); +} +inline void CodeGeneratorResponse_File::set_content(const char* value) { + set_has_content(); + if (content_ == &::google::protobuf::internal::kEmptyString) { + content_ = new ::std::string; + } + content_->assign(value); +} +inline void CodeGeneratorResponse_File::set_content(const char* value, size_t size) { + set_has_content(); + if (content_ == &::google::protobuf::internal::kEmptyString) { + content_ = new ::std::string; + } + content_->assign(reinterpret_cast(value), size); +} +inline ::std::string* CodeGeneratorResponse_File::mutable_content() { + set_has_content(); + if (content_ == &::google::protobuf::internal::kEmptyString) { + content_ = new ::std::string; + } + return content_; +} +inline ::std::string* CodeGeneratorResponse_File::release_content() { + clear_has_content(); + if (content_ == &::google::protobuf::internal::kEmptyString) { + return NULL; + } else { + ::std::string* temp = content_; + content_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + return temp; + } +} +inline void CodeGeneratorResponse_File::set_allocated_content(::std::string* content) { + if (content_ != &::google::protobuf::internal::kEmptyString) { + delete content_; + } + if (content) { + set_has_content(); + content_ = content; + } else { + clear_has_content(); + content_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + } +} + +// ------------------------------------------------------------------- + +// CodeGeneratorResponse + +// optional string error = 1; +inline bool CodeGeneratorResponse::has_error() const { + return (_has_bits_[0] & 0x00000001u) != 0; +} +inline void CodeGeneratorResponse::set_has_error() { + _has_bits_[0] |= 0x00000001u; +} +inline void CodeGeneratorResponse::clear_has_error() { + _has_bits_[0] &= ~0x00000001u; +} +inline void CodeGeneratorResponse::clear_error() { + if (error_ != &::google::protobuf::internal::kEmptyString) { + error_->clear(); + } + clear_has_error(); +} +inline const ::std::string& CodeGeneratorResponse::error() const { + return *error_; +} +inline void CodeGeneratorResponse::set_error(const ::std::string& value) { + set_has_error(); + if (error_ == &::google::protobuf::internal::kEmptyString) { + error_ = new ::std::string; + } + error_->assign(value); +} +inline void CodeGeneratorResponse::set_error(const char* value) { + set_has_error(); + if (error_ == &::google::protobuf::internal::kEmptyString) { + error_ = new ::std::string; + } + error_->assign(value); +} +inline void CodeGeneratorResponse::set_error(const char* value, size_t size) { + set_has_error(); + if (error_ == &::google::protobuf::internal::kEmptyString) { + error_ = new ::std::string; + } + error_->assign(reinterpret_cast(value), size); +} +inline ::std::string* CodeGeneratorResponse::mutable_error() { + set_has_error(); + if (error_ == &::google::protobuf::internal::kEmptyString) { + error_ = new ::std::string; + } + return error_; +} +inline ::std::string* CodeGeneratorResponse::release_error() { + clear_has_error(); + if (error_ == &::google::protobuf::internal::kEmptyString) { + return NULL; + } else { + ::std::string* temp = error_; + error_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + return temp; + } +} +inline void CodeGeneratorResponse::set_allocated_error(::std::string* error) { + if (error_ != &::google::protobuf::internal::kEmptyString) { + delete error_; + } + if (error) { + set_has_error(); + error_ = error; + } else { + clear_has_error(); + error_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + } +} + +// repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15; +inline int CodeGeneratorResponse::file_size() const { + return file_.size(); +} +inline void CodeGeneratorResponse::clear_file() { + file_.Clear(); +} +inline const ::google::protobuf::compiler::CodeGeneratorResponse_File& CodeGeneratorResponse::file(int index) const { + return file_.Get(index); +} +inline ::google::protobuf::compiler::CodeGeneratorResponse_File* CodeGeneratorResponse::mutable_file(int index) { + return file_.Mutable(index); +} +inline ::google::protobuf::compiler::CodeGeneratorResponse_File* CodeGeneratorResponse::add_file() { + return file_.Add(); +} +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >& +CodeGeneratorResponse::file() const { + return file_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >* +CodeGeneratorResponse::mutable_file() { + return &file_; +} + + +// @@protoc_insertion_point(namespace_scope) + +} // namespace compiler +} // namespace protobuf +} // namespace google + +#ifndef SWIG +namespace google { +namespace protobuf { + + +} // namespace google +} // namespace protobuf +#endif // SWIG + +// @@protoc_insertion_point(global_scope) + +#endif // PROTOBUF_google_2fprotobuf_2fcompiler_2fplugin_2eproto__INCLUDED diff --git a/include/google/protobuf/compiler/plugin.proto b/include/google/protobuf/compiler/plugin.proto new file mode 100644 index 000000000..77b888f37 --- /dev/null +++ b/include/google/protobuf/compiler/plugin.proto @@ -0,0 +1,147 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// +// WARNING: The plugin interface is currently EXPERIMENTAL and is subject to +// change. +// +// protoc (aka the Protocol Compiler) can be extended via plugins. A plugin is +// just a program that reads a CodeGeneratorRequest from stdin and writes a +// CodeGeneratorResponse to stdout. +// +// Plugins written using C++ can use google/protobuf/compiler/plugin.h instead +// of dealing with the raw protocol defined here. +// +// A plugin executable needs only to be placed somewhere in the path. The +// plugin should be named "protoc-gen-$NAME", and will then be used when the +// flag "--${NAME}_out" is passed to protoc. + +package google.protobuf.compiler; +option java_package = "com.google.protobuf.compiler"; +option java_outer_classname = "PluginProtos"; + +import "google/protobuf/descriptor.proto"; + +// An encoded CodeGeneratorRequest is written to the plugin's stdin. +message CodeGeneratorRequest { + // The .proto files that were explicitly listed on the command-line. The + // code generator should generate code only for these files. Each file's + // descriptor will be included in proto_file, below. + repeated string file_to_generate = 1; + + // The generator parameter passed on the command-line. + optional string parameter = 2; + + // FileDescriptorProtos for all files in files_to_generate and everything + // they import. The files will appear in topological order, so each file + // appears before any file that imports it. + // + // protoc guarantees that all proto_files will be written after + // the fields above, even though this is not technically guaranteed by the + // protobuf wire format. This theoretically could allow a plugin to stream + // in the FileDescriptorProtos and handle them one by one rather than read + // the entire set into memory at once. However, as of this writing, this + // is not similarly optimized on protoc's end -- it will store all fields in + // memory at once before sending them to the plugin. + repeated FileDescriptorProto proto_file = 15; +} + +// The plugin writes an encoded CodeGeneratorResponse to stdout. +message CodeGeneratorResponse { + // Error message. If non-empty, code generation failed. The plugin process + // should exit with status code zero even if it reports an error in this way. + // + // This should be used to indicate errors in .proto files which prevent the + // code generator from generating correct code. Errors which indicate a + // problem in protoc itself -- such as the input CodeGeneratorRequest being + // unparseable -- should be reported by writing a message to stderr and + // exiting with a non-zero status code. + optional string error = 1; + + // Represents a single generated file. + message File { + // The file name, relative to the output directory. The name must not + // contain "." or ".." components and must be relative, not be absolute (so, + // the file cannot lie outside the output directory). "/" must be used as + // the path separator, not "\". + // + // If the name is omitted, the content will be appended to the previous + // file. This allows the generator to break large files into small chunks, + // and allows the generated text to be streamed back to protoc so that large + // files need not reside completely in memory at one time. Note that as of + // this writing protoc does not optimize for this -- it will read the entire + // CodeGeneratorResponse before writing files to disk. + optional string name = 1; + + // If non-empty, indicates that the named file should already exist, and the + // content here is to be inserted into that file at a defined insertion + // point. This feature allows a code generator to extend the output + // produced by another code generator. The original generator may provide + // insertion points by placing special annotations in the file that look + // like: + // @@protoc_insertion_point(NAME) + // The annotation can have arbitrary text before and after it on the line, + // which allows it to be placed in a comment. NAME should be replaced with + // an identifier naming the point -- this is what other generators will use + // as the insertion_point. Code inserted at this point will be placed + // immediately above the line containing the insertion point (thus multiple + // insertions to the same point will come out in the order they were added). + // The double-@ is intended to make it unlikely that the generated code + // could contain things that look like insertion points by accident. + // + // For example, the C++ code generator places the following line in the + // .pb.h files that it generates: + // // @@protoc_insertion_point(namespace_scope) + // This line appears within the scope of the file's package namespace, but + // outside of any particular class. Another plugin can then specify the + // insertion_point "namespace_scope" to generate additional classes or + // other declarations that should be placed in this scope. + // + // Note that if the line containing the insertion point begins with + // whitespace, the same whitespace will be added to every line of the + // inserted text. This is useful for languages like Python, where + // indentation matters. In these languages, the insertion point comment + // should be indented the same amount as any inserted code will need to be + // in order to work correctly in that context. + // + // The code generator that generates the initial file and the one which + // inserts into it must both run as part of a single invocation of protoc. + // Code generators are executed in the order in which they appear on the + // command line. + // + // If |insertion_point| is present, |name| must also be present. + optional string insertion_point = 2; + + // The file contents. + optional string content = 15; + } + repeated File file = 15; +} diff --git a/include/google/protobuf/compiler/python/python_generator.h b/include/google/protobuf/compiler/python/python_generator.h new file mode 100644 index 000000000..a3f22cee6 --- /dev/null +++ b/include/google/protobuf/compiler/python/python_generator.h @@ -0,0 +1,161 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: robinson@google.com (Will Robinson) +// +// Generates Python code for a given .proto file. + +#ifndef GOOGLE_PROTOBUF_COMPILER_PYTHON_GENERATOR_H__ +#define GOOGLE_PROTOBUF_COMPILER_PYTHON_GENERATOR_H__ + +#include + +#include +#include + +namespace google { +namespace protobuf { + +class Descriptor; +class EnumDescriptor; +class EnumValueDescriptor; +class FieldDescriptor; +class ServiceDescriptor; + +namespace io { class Printer; } + +namespace compiler { +namespace python { + +// CodeGenerator implementation for generated Python protocol buffer classes. +// If you create your own protocol compiler binary and you want it to support +// Python output, you can do so by registering an instance of this +// CodeGenerator with the CommandLineInterface in your main() function. +class LIBPROTOC_EXPORT Generator : public CodeGenerator { + public: + Generator(); + virtual ~Generator(); + + // CodeGenerator methods. + virtual bool Generate(const FileDescriptor* file, + const string& parameter, + GeneratorContext* generator_context, + string* error) const; + + private: + void PrintImports() const; + void PrintFileDescriptor() const; + void PrintTopLevelEnums() const; + void PrintAllNestedEnumsInFile() const; + void PrintNestedEnums(const Descriptor& descriptor) const; + void PrintEnum(const EnumDescriptor& enum_descriptor) const; + + void PrintTopLevelExtensions() const; + + void PrintFieldDescriptor( + const FieldDescriptor& field, bool is_extension) const; + void PrintFieldDescriptorsInDescriptor( + const Descriptor& message_descriptor, + bool is_extension, + const string& list_variable_name, + int (Descriptor::*CountFn)() const, + const FieldDescriptor* (Descriptor::*GetterFn)(int) const) const; + void PrintFieldsInDescriptor(const Descriptor& message_descriptor) const; + void PrintExtensionsInDescriptor(const Descriptor& message_descriptor) const; + void PrintMessageDescriptors() const; + void PrintDescriptor(const Descriptor& message_descriptor) const; + void PrintNestedDescriptors(const Descriptor& containing_descriptor) const; + + void PrintMessages() const; + void PrintMessage(const Descriptor& message_descriptor) const; + void PrintNestedMessages(const Descriptor& containing_descriptor) const; + + void FixForeignFieldsInDescriptors() const; + void FixForeignFieldsInDescriptor( + const Descriptor& descriptor, + const Descriptor* containing_descriptor) const; + void FixForeignFieldsInField(const Descriptor* containing_type, + const FieldDescriptor& field, + const string& python_dict_name) const; + void AddMessageToFileDescriptor(const Descriptor& descriptor) const; + string FieldReferencingExpression(const Descriptor* containing_type, + const FieldDescriptor& field, + const string& python_dict_name) const; + template + void FixContainingTypeInDescriptor( + const DescriptorT& descriptor, + const Descriptor* containing_descriptor) const; + + void FixForeignFieldsInExtensions() const; + void FixForeignFieldsInExtension( + const FieldDescriptor& extension_field) const; + void FixForeignFieldsInNestedExtensions(const Descriptor& descriptor) const; + + void PrintServices() const; + void PrintServiceDescriptor(const ServiceDescriptor& descriptor) const; + void PrintServiceClass(const ServiceDescriptor& descriptor) const; + void PrintServiceStub(const ServiceDescriptor& descriptor) const; + + void PrintEnumValueDescriptor(const EnumValueDescriptor& descriptor) const; + string OptionsValue(const string& class_name, + const string& serialized_options) const; + bool GeneratingDescriptorProto() const; + + template + string ModuleLevelDescriptorName(const DescriptorT& descriptor) const; + string ModuleLevelMessageName(const Descriptor& descriptor) const; + string ModuleLevelServiceDescriptorName( + const ServiceDescriptor& descriptor) const; + + template + void PrintSerializedPbInterval( + const DescriptorT& descriptor, DescriptorProtoT& proto) const; + + void FixAllDescriptorOptions() const; + void FixOptionsForField(const FieldDescriptor& field) const; + void FixOptionsForEnum(const EnumDescriptor& descriptor) const; + void FixOptionsForMessage(const Descriptor& descriptor) const; + + // Very coarse-grained lock to ensure that Generate() is reentrant. + // Guards file_, printer_ and file_descriptor_serialized_. + mutable Mutex mutex_; + mutable const FileDescriptor* file_; // Set in Generate(). Under mutex_. + mutable string file_descriptor_serialized_; + mutable io::Printer* printer_; // Set in Generate(). Under mutex_. + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Generator); +}; + +} // namespace python +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_PYTHON_GENERATOR_H__ diff --git a/include/google/protobuf/descriptor.h b/include/google/protobuf/descriptor.h new file mode 100644 index 000000000..d28098813 --- /dev/null +++ b/include/google/protobuf/descriptor.h @@ -0,0 +1,1521 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// This file contains classes which describe a type of protocol message. +// You can use a message's descriptor to learn at runtime what fields +// it contains and what the types of those fields are. The Message +// interface also allows you to dynamically access and modify individual +// fields by passing the FieldDescriptor of the field you are interested +// in. +// +// Most users will not care about descriptors, because they will write +// code specific to certain protocol types and will simply use the classes +// generated by the protocol compiler directly. Advanced users who want +// to operate on arbitrary types (not known at compile time) may want to +// read descriptors in order to learn about the contents of a message. +// A very small number of users will want to construct their own +// Descriptors, either because they are implementing Message manually or +// because they are writing something like the protocol compiler. +// +// For an example of how you might use descriptors, see the code example +// at the top of message.h. + +#ifndef GOOGLE_PROTOBUF_DESCRIPTOR_H__ +#define GOOGLE_PROTOBUF_DESCRIPTOR_H__ + +#include +#include +#include + +// TYPE_BOOL is defined in the MacOS's ConditionalMacros.h. +#ifdef TYPE_BOOL +#undef TYPE_BOOL +#endif // TYPE_BOOL + +namespace google { +namespace protobuf { + +// Defined in this file. +class Descriptor; +class FieldDescriptor; +class EnumDescriptor; +class EnumValueDescriptor; +class ServiceDescriptor; +class MethodDescriptor; +class FileDescriptor; +class DescriptorDatabase; +class DescriptorPool; + +// Defined in descriptor.proto +class DescriptorProto; +class FieldDescriptorProto; +class EnumDescriptorProto; +class EnumValueDescriptorProto; +class ServiceDescriptorProto; +class MethodDescriptorProto; +class FileDescriptorProto; +class MessageOptions; +class FieldOptions; +class EnumOptions; +class EnumValueOptions; +class ServiceOptions; +class MethodOptions; +class FileOptions; +class UninterpretedOption; +class SourceCodeInfo; + +// Defined in message.h +class Message; + +// Defined in descriptor.cc +class DescriptorBuilder; +class FileDescriptorTables; + +// Defined in unknown_field_set.h. +class UnknownField; + +// NB, all indices are zero-based. +struct SourceLocation { + int start_line; + int end_line; + int start_column; + int end_column; + + // Doc comments found at the source location. + // TODO(kenton): Maybe this struct should have been named SourceInfo or + // something instead. Oh well. + string leading_comments; + string trailing_comments; +}; + +// Describes a type of protocol message, or a particular group within a +// message. To obtain the Descriptor for a given message object, call +// Message::GetDescriptor(). Generated message classes also have a +// static method called descriptor() which returns the type's descriptor. +// Use DescriptorPool to construct your own descriptors. +class LIBPROTOBUF_EXPORT Descriptor { + public: + // The name of the message type, not including its scope. + const string& name() const; + + // The fully-qualified name of the message type, scope delimited by + // periods. For example, message type "Foo" which is declared in package + // "bar" has full name "bar.Foo". If a type "Baz" is nested within + // Foo, Baz's full_name is "bar.Foo.Baz". To get only the part that + // comes after the last '.', use name(). + const string& full_name() const; + + // Index of this descriptor within the file or containing type's message + // type array. + int index() const; + + // The .proto file in which this message type was defined. Never NULL. + const FileDescriptor* file() const; + + // If this Descriptor describes a nested type, this returns the type + // in which it is nested. Otherwise, returns NULL. + const Descriptor* containing_type() const; + + // Get options for this message type. These are specified in the .proto file + // by placing lines like "option foo = 1234;" in the message definition. + // Allowed options are defined by MessageOptions in + // google/protobuf/descriptor.proto, and any available extensions of that + // message. + const MessageOptions& options() const; + + // Write the contents of this Descriptor into the given DescriptorProto. + // The target DescriptorProto must be clear before calling this; if it + // isn't, the result may be garbage. + void CopyTo(DescriptorProto* proto) const; + + // Write the contents of this decriptor in a human-readable form. Output + // will be suitable for re-parsing. + string DebugString() const; + + // Field stuff ----------------------------------------------------- + + // The number of fields in this message type. + int field_count() const; + // Gets a field by index, where 0 <= index < field_count(). + // These are returned in the order they were defined in the .proto file. + const FieldDescriptor* field(int idx) const; + + // Looks up a field by declared tag number. Returns NULL if no such field + // exists. + const FieldDescriptor* FindFieldByNumber(int number) const; + // Looks up a field by name. Returns NULL if no such field exists. + const FieldDescriptor* FindFieldByName(const string& name) const; + + // Looks up a field by lowercased name (as returned by lowercase_name()). + // This lookup may be ambiguous if multiple field names differ only by case, + // in which case the field returned is chosen arbitrarily from the matches. + const FieldDescriptor* FindFieldByLowercaseName( + const string& lowercase_name) const; + + // Looks up a field by camel-case name (as returned by camelcase_name()). + // This lookup may be ambiguous if multiple field names differ in a way that + // leads them to have identical camel-case names, in which case the field + // returned is chosen arbitrarily from the matches. + const FieldDescriptor* FindFieldByCamelcaseName( + const string& camelcase_name) const; + + // Nested type stuff ----------------------------------------------- + + // The number of nested types in this message type. + int nested_type_count() const; + // Gets a nested type by index, where 0 <= index < nested_type_count(). + // These are returned in the order they were defined in the .proto file. + const Descriptor* nested_type(int idx) const; + + // Looks up a nested type by name. Returns NULL if no such nested type + // exists. + const Descriptor* FindNestedTypeByName(const string& name) const; + + // Enum stuff ------------------------------------------------------ + + // The number of enum types in this message type. + int enum_type_count() const; + // Gets an enum type by index, where 0 <= index < enum_type_count(). + // These are returned in the order they were defined in the .proto file. + const EnumDescriptor* enum_type(int idx) const; + + // Looks up an enum type by name. Returns NULL if no such enum type exists. + const EnumDescriptor* FindEnumTypeByName(const string& name) const; + + // Looks up an enum value by name, among all enum types in this message. + // Returns NULL if no such value exists. + const EnumValueDescriptor* FindEnumValueByName(const string& name) const; + + // Extensions ------------------------------------------------------ + + // A range of field numbers which are designated for third-party + // extensions. + struct ExtensionRange { + int start; // inclusive + int end; // exclusive + }; + + // The number of extension ranges in this message type. + int extension_range_count() const; + // Gets an extension range by index, where 0 <= index < + // extension_range_count(). These are returned in the order they were defined + // in the .proto file. + const ExtensionRange* extension_range(int idx) const; + + // Returns true if the number is in one of the extension ranges. + bool IsExtensionNumber(int number) const; + + // The number of extensions -- extending *other* messages -- that were + // defined nested within this message type's scope. + int extension_count() const; + // Get an extension by index, where 0 <= index < extension_count(). + // These are returned in the order they were defined in the .proto file. + const FieldDescriptor* extension(int idx) const; + + // Looks up a named extension (which extends some *other* message type) + // defined within this message type's scope. + const FieldDescriptor* FindExtensionByName(const string& name) const; + + // Similar to FindFieldByLowercaseName(), but finds extensions defined within + // this message type's scope. + const FieldDescriptor* FindExtensionByLowercaseName(const string& name) const; + + // Similar to FindFieldByCamelcaseName(), but finds extensions defined within + // this message type's scope. + const FieldDescriptor* FindExtensionByCamelcaseName(const string& name) const; + + // Source Location --------------------------------------------------- + + // Updates |*out_location| to the source location of the complete + // extent of this message declaration. Returns false and leaves + // |*out_location| unchanged iff location information was not available. + bool GetSourceLocation(SourceLocation* out_location) const; + + private: + typedef MessageOptions OptionsType; + + // Internal version of DebugString; controls the level of indenting for + // correct depth + void DebugString(int depth, string *contents) const; + + // Walks up the descriptor tree to generate the source location path + // to this descriptor from the file root. + void GetLocationPath(vector* output) const; + + const string* name_; + const string* full_name_; + const FileDescriptor* file_; + const Descriptor* containing_type_; + const MessageOptions* options_; + + // True if this is a placeholder for an unknown type. + bool is_placeholder_; + // True if this is a placeholder and the type name wasn't fully-qualified. + bool is_unqualified_placeholder_; + + int field_count_; + FieldDescriptor* fields_; + int nested_type_count_; + Descriptor* nested_types_; + int enum_type_count_; + EnumDescriptor* enum_types_; + int extension_range_count_; + ExtensionRange* extension_ranges_; + int extension_count_; + FieldDescriptor* extensions_; + // IMPORTANT: If you add a new field, make sure to search for all instances + // of Allocate() and AllocateArray() in descriptor.cc + // and update them to initialize the field. + + // Must be constructed using DescriptorPool. + Descriptor() {} + friend class DescriptorBuilder; + friend class EnumDescriptor; + friend class FieldDescriptor; + friend class MethodDescriptor; + friend class FileDescriptor; + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Descriptor); +}; + +// Describes a single field of a message. To get the descriptor for a given +// field, first get the Descriptor for the message in which it is defined, +// then call Descriptor::FindFieldByName(). To get a FieldDescriptor for +// an extension, do one of the following: +// - Get the Descriptor or FileDescriptor for its containing scope, then +// call Descriptor::FindExtensionByName() or +// FileDescriptor::FindExtensionByName(). +// - Given a DescriptorPool, call DescriptorPool::FindExtensionByNumber(). +// - Given a Reflection for a message object, call +// Reflection::FindKnownExtensionByName() or +// Reflection::FindKnownExtensionByNumber(). +// Use DescriptorPool to construct your own descriptors. +class LIBPROTOBUF_EXPORT FieldDescriptor { + public: + // Identifies a field type. 0 is reserved for errors. The order is weird + // for historical reasons. Types 12 and up are new in proto2. + enum Type { + TYPE_DOUBLE = 1, // double, exactly eight bytes on the wire. + TYPE_FLOAT = 2, // float, exactly four bytes on the wire. + TYPE_INT64 = 3, // int64, varint on the wire. Negative numbers + // take 10 bytes. Use TYPE_SINT64 if negative + // values are likely. + TYPE_UINT64 = 4, // uint64, varint on the wire. + TYPE_INT32 = 5, // int32, varint on the wire. Negative numbers + // take 10 bytes. Use TYPE_SINT32 if negative + // values are likely. + TYPE_FIXED64 = 6, // uint64, exactly eight bytes on the wire. + TYPE_FIXED32 = 7, // uint32, exactly four bytes on the wire. + TYPE_BOOL = 8, // bool, varint on the wire. + TYPE_STRING = 9, // UTF-8 text. + TYPE_GROUP = 10, // Tag-delimited message. Deprecated. + TYPE_MESSAGE = 11, // Length-delimited message. + + TYPE_BYTES = 12, // Arbitrary byte array. + TYPE_UINT32 = 13, // uint32, varint on the wire + TYPE_ENUM = 14, // Enum, varint on the wire + TYPE_SFIXED32 = 15, // int32, exactly four bytes on the wire + TYPE_SFIXED64 = 16, // int64, exactly eight bytes on the wire + TYPE_SINT32 = 17, // int32, ZigZag-encoded varint on the wire + TYPE_SINT64 = 18, // int64, ZigZag-encoded varint on the wire + + MAX_TYPE = 18, // Constant useful for defining lookup tables + // indexed by Type. + }; + + // Specifies the C++ data type used to represent the field. There is a + // fixed mapping from Type to CppType where each Type maps to exactly one + // CppType. 0 is reserved for errors. + enum CppType { + CPPTYPE_INT32 = 1, // TYPE_INT32, TYPE_SINT32, TYPE_SFIXED32 + CPPTYPE_INT64 = 2, // TYPE_INT64, TYPE_SINT64, TYPE_SFIXED64 + CPPTYPE_UINT32 = 3, // TYPE_UINT32, TYPE_FIXED32 + CPPTYPE_UINT64 = 4, // TYPE_UINT64, TYPE_FIXED64 + CPPTYPE_DOUBLE = 5, // TYPE_DOUBLE + CPPTYPE_FLOAT = 6, // TYPE_FLOAT + CPPTYPE_BOOL = 7, // TYPE_BOOL + CPPTYPE_ENUM = 8, // TYPE_ENUM + CPPTYPE_STRING = 9, // TYPE_STRING, TYPE_BYTES + CPPTYPE_MESSAGE = 10, // TYPE_MESSAGE, TYPE_GROUP + + MAX_CPPTYPE = 10, // Constant useful for defining lookup tables + // indexed by CppType. + }; + + // Identifies whether the field is optional, required, or repeated. 0 is + // reserved for errors. + enum Label { + LABEL_OPTIONAL = 1, // optional + LABEL_REQUIRED = 2, // required + LABEL_REPEATED = 3, // repeated + + MAX_LABEL = 3, // Constant useful for defining lookup tables + // indexed by Label. + }; + + // Valid field numbers are positive integers up to kMaxNumber. + static const int kMaxNumber = (1 << 29) - 1; + + // First field number reserved for the protocol buffer library implementation. + // Users may not declare fields that use reserved numbers. + static const int kFirstReservedNumber = 19000; + // Last field number reserved for the protocol buffer library implementation. + // Users may not declare fields that use reserved numbers. + static const int kLastReservedNumber = 19999; + + const string& name() const; // Name of this field within the message. + const string& full_name() const; // Fully-qualified name of the field. + const FileDescriptor* file() const;// File in which this field was defined. + bool is_extension() const; // Is this an extension field? + int number() const; // Declared tag number. + + // Same as name() except converted to lower-case. This (and especially the + // FindFieldByLowercaseName() method) can be useful when parsing formats + // which prefer to use lowercase naming style. (Although, technically + // field names should be lowercased anyway according to the protobuf style + // guide, so this only makes a difference when dealing with old .proto files + // which do not follow the guide.) + const string& lowercase_name() const; + + // Same as name() except converted to camel-case. In this conversion, any + // time an underscore appears in the name, it is removed and the next + // letter is capitalized. Furthermore, the first letter of the name is + // lower-cased. Examples: + // FooBar -> fooBar + // foo_bar -> fooBar + // fooBar -> fooBar + // This (and especially the FindFieldByCamelcaseName() method) can be useful + // when parsing formats which prefer to use camel-case naming style. + const string& camelcase_name() const; + + Type type() const; // Declared type of this field. + const char* type_name() const; // Name of the declared type. + CppType cpp_type() const; // C++ type of this field. + const char* cpp_type_name() const; // Name of the C++ type. + Label label() const; // optional/required/repeated + + bool is_required() const; // shorthand for label() == LABEL_REQUIRED + bool is_optional() const; // shorthand for label() == LABEL_OPTIONAL + bool is_repeated() const; // shorthand for label() == LABEL_REPEATED + bool is_packable() const; // shorthand for is_repeated() && + // IsTypePackable(type()) + bool is_packed() const; // shorthand for is_packable() && + // options().packed() + + // Index of this field within the message's field array, or the file or + // extension scope's extensions array. + int index() const; + + // Does this field have an explicitly-declared default value? + bool has_default_value() const; + + // Get the field default value if cpp_type() == CPPTYPE_INT32. If no + // explicit default was defined, the default is 0. + int32 default_value_int32() const; + // Get the field default value if cpp_type() == CPPTYPE_INT64. If no + // explicit default was defined, the default is 0. + int64 default_value_int64() const; + // Get the field default value if cpp_type() == CPPTYPE_UINT32. If no + // explicit default was defined, the default is 0. + uint32 default_value_uint32() const; + // Get the field default value if cpp_type() == CPPTYPE_UINT64. If no + // explicit default was defined, the default is 0. + uint64 default_value_uint64() const; + // Get the field default value if cpp_type() == CPPTYPE_FLOAT. If no + // explicit default was defined, the default is 0.0. + float default_value_float() const; + // Get the field default value if cpp_type() == CPPTYPE_DOUBLE. If no + // explicit default was defined, the default is 0.0. + double default_value_double() const; + // Get the field default value if cpp_type() == CPPTYPE_BOOL. If no + // explicit default was defined, the default is false. + bool default_value_bool() const; + // Get the field default value if cpp_type() == CPPTYPE_ENUM. If no + // explicit default was defined, the default is the first value defined + // in the enum type (all enum types are required to have at least one value). + // This never returns NULL. + const EnumValueDescriptor* default_value_enum() const; + // Get the field default value if cpp_type() == CPPTYPE_STRING. If no + // explicit default was defined, the default is the empty string. + const string& default_value_string() const; + + // The Descriptor for the message of which this is a field. For extensions, + // this is the extended type. Never NULL. + const Descriptor* containing_type() const; + + // An extension may be declared within the scope of another message. If this + // field is an extension (is_extension() is true), then extension_scope() + // returns that message, or NULL if the extension was declared at global + // scope. If this is not an extension, extension_scope() is undefined (may + // assert-fail). + const Descriptor* extension_scope() const; + + // If type is TYPE_MESSAGE or TYPE_GROUP, returns a descriptor for the + // message or the group type. Otherwise, undefined. + const Descriptor* message_type() const; + // If type is TYPE_ENUM, returns a descriptor for the enum. Otherwise, + // undefined. + const EnumDescriptor* enum_type() const; + + // EXPERIMENTAL; DO NOT USE. + // If this field is a map field, experimental_map_key() is the field + // that is the key for this map. + // experimental_map_key()->containing_type() is the same as message_type(). + const FieldDescriptor* experimental_map_key() const; + + // Get the FieldOptions for this field. This includes things listed in + // square brackets after the field definition. E.g., the field: + // optional string text = 1 [ctype=CORD]; + // has the "ctype" option set. Allowed options are defined by FieldOptions + // in google/protobuf/descriptor.proto, and any available extensions of that + // message. + const FieldOptions& options() const; + + // See Descriptor::CopyTo(). + void CopyTo(FieldDescriptorProto* proto) const; + + // See Descriptor::DebugString(). + string DebugString() const; + + // Helper method to get the CppType for a particular Type. + static CppType TypeToCppType(Type type); + + // Return true iff [packed = true] is valid for fields of this type. + static inline bool IsTypePackable(Type field_type); + + // Source Location --------------------------------------------------- + + // Updates |*out_location| to the source location of the complete + // extent of this field declaration. Returns false and leaves + // |*out_location| unchanged iff location information was not available. + bool GetSourceLocation(SourceLocation* out_location) const; + + private: + typedef FieldOptions OptionsType; + + // See Descriptor::DebugString(). + void DebugString(int depth, string *contents) const; + + // formats the default value appropriately and returns it as a string. + // Must have a default value to call this. If quote_string_type is true, then + // types of CPPTYPE_STRING whill be surrounded by quotes and CEscaped. + string DefaultValueAsString(bool quote_string_type) const; + + // Walks up the descriptor tree to generate the source location path + // to this descriptor from the file root. + void GetLocationPath(vector* output) const; + + const string* name_; + const string* full_name_; + const string* lowercase_name_; + const string* camelcase_name_; + const FileDescriptor* file_; + int number_; + Type type_; + Label label_; + bool is_extension_; + const Descriptor* containing_type_; + const Descriptor* extension_scope_; + const Descriptor* message_type_; + const EnumDescriptor* enum_type_; + const FieldDescriptor* experimental_map_key_; + const FieldOptions* options_; + // IMPORTANT: If you add a new field, make sure to search for all instances + // of Allocate() and AllocateArray() in + // descriptor.cc and update them to initialize the field. + + bool has_default_value_; + union { + int32 default_value_int32_; + int64 default_value_int64_; + uint32 default_value_uint32_; + uint64 default_value_uint64_; + float default_value_float_; + double default_value_double_; + bool default_value_bool_; + + const EnumValueDescriptor* default_value_enum_; + const string* default_value_string_; + }; + + static const CppType kTypeToCppTypeMap[MAX_TYPE + 1]; + + static const char * const kTypeToName[MAX_TYPE + 1]; + + static const char * const kCppTypeToName[MAX_CPPTYPE + 1]; + + static const char * const kLabelToName[MAX_LABEL + 1]; + + // Must be constructed using DescriptorPool. + FieldDescriptor() {} + friend class DescriptorBuilder; + friend class FileDescriptor; + friend class Descriptor; + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldDescriptor); +}; + +// Describes an enum type defined in a .proto file. To get the EnumDescriptor +// for a generated enum type, call TypeName_descriptor(). Use DescriptorPool +// to construct your own descriptors. +class LIBPROTOBUF_EXPORT EnumDescriptor { + public: + // The name of this enum type in the containing scope. + const string& name() const; + + // The fully-qualified name of the enum type, scope delimited by periods. + const string& full_name() const; + + // Index of this enum within the file or containing message's enum array. + int index() const; + + // The .proto file in which this enum type was defined. Never NULL. + const FileDescriptor* file() const; + + // The number of values for this EnumDescriptor. Guaranteed to be greater + // than zero. + int value_count() const; + // Gets a value by index, where 0 <= index < value_count(). + // These are returned in the order they were defined in the .proto file. + const EnumValueDescriptor* value(int idx) const; + + // Looks up a value by name. Returns NULL if no such value exists. + const EnumValueDescriptor* FindValueByName(const string& name) const; + // Looks up a value by number. Returns NULL if no such value exists. If + // multiple values have this number, the first one defined is returned. + const EnumValueDescriptor* FindValueByNumber(int number) const; + + // If this enum type is nested in a message type, this is that message type. + // Otherwise, NULL. + const Descriptor* containing_type() const; + + // Get options for this enum type. These are specified in the .proto file by + // placing lines like "option foo = 1234;" in the enum definition. Allowed + // options are defined by EnumOptions in google/protobuf/descriptor.proto, + // and any available extensions of that message. + const EnumOptions& options() const; + + // See Descriptor::CopyTo(). + void CopyTo(EnumDescriptorProto* proto) const; + + // See Descriptor::DebugString(). + string DebugString() const; + + // Source Location --------------------------------------------------- + + // Updates |*out_location| to the source location of the complete + // extent of this enum declaration. Returns false and leaves + // |*out_location| unchanged iff location information was not available. + bool GetSourceLocation(SourceLocation* out_location) const; + + private: + typedef EnumOptions OptionsType; + + // See Descriptor::DebugString(). + void DebugString(int depth, string *contents) const; + + // Walks up the descriptor tree to generate the source location path + // to this descriptor from the file root. + void GetLocationPath(vector* output) const; + + const string* name_; + const string* full_name_; + const FileDescriptor* file_; + const Descriptor* containing_type_; + const EnumOptions* options_; + + // True if this is a placeholder for an unknown type. + bool is_placeholder_; + // True if this is a placeholder and the type name wasn't fully-qualified. + bool is_unqualified_placeholder_; + + int value_count_; + EnumValueDescriptor* values_; + // IMPORTANT: If you add a new field, make sure to search for all instances + // of Allocate() and AllocateArray() in + // descriptor.cc and update them to initialize the field. + + // Must be constructed using DescriptorPool. + EnumDescriptor() {} + friend class DescriptorBuilder; + friend class Descriptor; + friend class FieldDescriptor; + friend class EnumValueDescriptor; + friend class FileDescriptor; + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumDescriptor); +}; + +// Describes an individual enum constant of a particular type. To get the +// EnumValueDescriptor for a given enum value, first get the EnumDescriptor +// for its type, then use EnumDescriptor::FindValueByName() or +// EnumDescriptor::FindValueByNumber(). Use DescriptorPool to construct +// your own descriptors. +class LIBPROTOBUF_EXPORT EnumValueDescriptor { + public: + const string& name() const; // Name of this enum constant. + int index() const; // Index within the enums's Descriptor. + int number() const; // Numeric value of this enum constant. + + // The full_name of an enum value is a sibling symbol of the enum type. + // e.g. the full name of FieldDescriptorProto::TYPE_INT32 is actually + // "google.protobuf.FieldDescriptorProto.TYPE_INT32", NOT + // "google.protobuf.FieldDescriptorProto.Type.TYPE_INT32". This is to conform + // with C++ scoping rules for enums. + const string& full_name() const; + + // The type of this value. Never NULL. + const EnumDescriptor* type() const; + + // Get options for this enum value. These are specified in the .proto file + // by adding text like "[foo = 1234]" after an enum value definition. + // Allowed options are defined by EnumValueOptions in + // google/protobuf/descriptor.proto, and any available extensions of that + // message. + const EnumValueOptions& options() const; + + // See Descriptor::CopyTo(). + void CopyTo(EnumValueDescriptorProto* proto) const; + + // See Descriptor::DebugString(). + string DebugString() const; + + // Source Location --------------------------------------------------- + + // Updates |*out_location| to the source location of the complete + // extent of this enum value declaration. Returns false and leaves + // |*out_location| unchanged iff location information was not available. + bool GetSourceLocation(SourceLocation* out_location) const; + + private: + typedef EnumValueOptions OptionsType; + + // See Descriptor::DebugString(). + void DebugString(int depth, string *contents) const; + + // Walks up the descriptor tree to generate the source location path + // to this descriptor from the file root. + void GetLocationPath(vector* output) const; + + const string* name_; + const string* full_name_; + int number_; + const EnumDescriptor* type_; + const EnumValueOptions* options_; + // IMPORTANT: If you add a new field, make sure to search for all instances + // of Allocate() and AllocateArray() + // in descriptor.cc and update them to initialize the field. + + // Must be constructed using DescriptorPool. + EnumValueDescriptor() {} + friend class DescriptorBuilder; + friend class EnumDescriptor; + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumValueDescriptor); +}; + +// Describes an RPC service. To get the ServiceDescriptor for a service, +// call Service::GetDescriptor(). Generated service classes also have a +// static method called descriptor() which returns the type's +// ServiceDescriptor. Use DescriptorPool to construct your own descriptors. +class LIBPROTOBUF_EXPORT ServiceDescriptor { + public: + // The name of the service, not including its containing scope. + const string& name() const; + // The fully-qualified name of the service, scope delimited by periods. + const string& full_name() const; + // Index of this service within the file's services array. + int index() const; + + // The .proto file in which this service was defined. Never NULL. + const FileDescriptor* file() const; + + // Get options for this service type. These are specified in the .proto file + // by placing lines like "option foo = 1234;" in the service definition. + // Allowed options are defined by ServiceOptions in + // google/protobuf/descriptor.proto, and any available extensions of that + // message. + const ServiceOptions& options() const; + + // The number of methods this service defines. + int method_count() const; + // Gets a MethodDescriptor by index, where 0 <= index < method_count(). + // These are returned in the order they were defined in the .proto file. + const MethodDescriptor* method(int idx) const; + + // Look up a MethodDescriptor by name. + const MethodDescriptor* FindMethodByName(const string& name) const; + // See Descriptor::CopyTo(). + void CopyTo(ServiceDescriptorProto* proto) const; + + // See Descriptor::DebugString(). + string DebugString() const; + + // Source Location --------------------------------------------------- + + // Updates |*out_location| to the source location of the complete + // extent of this service declaration. Returns false and leaves + // |*out_location| unchanged iff location information was not available. + bool GetSourceLocation(SourceLocation* out_location) const; + + private: + typedef ServiceOptions OptionsType; + + // See Descriptor::DebugString(). + void DebugString(string *contents) const; + + // Walks up the descriptor tree to generate the source location path + // to this descriptor from the file root. + void GetLocationPath(vector* output) const; + + const string* name_; + const string* full_name_; + const FileDescriptor* file_; + const ServiceOptions* options_; + int method_count_; + MethodDescriptor* methods_; + // IMPORTANT: If you add a new field, make sure to search for all instances + // of Allocate() and AllocateArray() in + // descriptor.cc and update them to initialize the field. + + // Must be constructed using DescriptorPool. + ServiceDescriptor() {} + friend class DescriptorBuilder; + friend class FileDescriptor; + friend class MethodDescriptor; + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ServiceDescriptor); +}; + +// Describes an individual service method. To obtain a MethodDescriptor given +// a service, first get its ServiceDescriptor, then call +// ServiceDescriptor::FindMethodByName(). Use DescriptorPool to construct your +// own descriptors. +class LIBPROTOBUF_EXPORT MethodDescriptor { + public: + // Name of this method, not including containing scope. + const string& name() const; + // The fully-qualified name of the method, scope delimited by periods. + const string& full_name() const; + // Index within the service's Descriptor. + int index() const; + + // Gets the service to which this method belongs. Never NULL. + const ServiceDescriptor* service() const; + + // Gets the type of protocol message which this method accepts as input. + const Descriptor* input_type() const; + // Gets the type of protocol message which this message produces as output. + const Descriptor* output_type() const; + + // Get options for this method. These are specified in the .proto file by + // placing lines like "option foo = 1234;" in curly-braces after a method + // declaration. Allowed options are defined by MethodOptions in + // google/protobuf/descriptor.proto, and any available extensions of that + // message. + const MethodOptions& options() const; + + // See Descriptor::CopyTo(). + void CopyTo(MethodDescriptorProto* proto) const; + + // See Descriptor::DebugString(). + string DebugString() const; + + // Source Location --------------------------------------------------- + + // Updates |*out_location| to the source location of the complete + // extent of this method declaration. Returns false and leaves + // |*out_location| unchanged iff location information was not available. + bool GetSourceLocation(SourceLocation* out_location) const; + + private: + typedef MethodOptions OptionsType; + + // See Descriptor::DebugString(). + void DebugString(int depth, string *contents) const; + + // Walks up the descriptor tree to generate the source location path + // to this descriptor from the file root. + void GetLocationPath(vector* output) const; + + const string* name_; + const string* full_name_; + const ServiceDescriptor* service_; + const Descriptor* input_type_; + const Descriptor* output_type_; + const MethodOptions* options_; + // IMPORTANT: If you add a new field, make sure to search for all instances + // of Allocate() and AllocateArray() in + // descriptor.cc and update them to initialize the field. + + // Must be constructed using DescriptorPool. + MethodDescriptor() {} + friend class DescriptorBuilder; + friend class ServiceDescriptor; + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MethodDescriptor); +}; + + +// Describes a whole .proto file. To get the FileDescriptor for a compiled-in +// file, get the descriptor for something defined in that file and call +// descriptor->file(). Use DescriptorPool to construct your own descriptors. +class LIBPROTOBUF_EXPORT FileDescriptor { + public: + // The filename, relative to the source tree. + // e.g. "google/protobuf/descriptor.proto" + const string& name() const; + + // The package, e.g. "google.protobuf.compiler". + const string& package() const; + + // The DescriptorPool in which this FileDescriptor and all its contents were + // allocated. Never NULL. + const DescriptorPool* pool() const; + + // The number of files imported by this one. + int dependency_count() const; + // Gets an imported file by index, where 0 <= index < dependency_count(). + // These are returned in the order they were defined in the .proto file. + const FileDescriptor* dependency(int idx) const; + + // The number of files public imported by this one. + // The public dependency list is a subset of the dependency list. + int public_dependency_count() const; + // Gets a public imported file by index, where 0 <= index < + // public_dependency_count(). + // These are returned in the order they were defined in the .proto file. + const FileDescriptor* public_dependency(int idx) const; + + // The number of files that are imported for weak fields. + // The weak dependency list is a subset of the dependency list. + int weak_dependency_count() const; + // Gets a weak imported file by index, where 0 <= index < + // weak_dependency_count(). + // These are returned in the order they were defined in the .proto file. + const FileDescriptor* weak_dependency(int idx) const; + + // Number of top-level message types defined in this file. (This does not + // include nested types.) + int message_type_count() const; + // Gets a top-level message type, where 0 <= index < message_type_count(). + // These are returned in the order they were defined in the .proto file. + const Descriptor* message_type(int idx) const; + + // Number of top-level enum types defined in this file. (This does not + // include nested types.) + int enum_type_count() const; + // Gets a top-level enum type, where 0 <= index < enum_type_count(). + // These are returned in the order they were defined in the .proto file. + const EnumDescriptor* enum_type(int idx) const; + + // Number of services defined in this file. + int service_count() const; + // Gets a service, where 0 <= index < service_count(). + // These are returned in the order they were defined in the .proto file. + const ServiceDescriptor* service(int idx) const; + + // Number of extensions defined at file scope. (This does not include + // extensions nested within message types.) + int extension_count() const; + // Gets an extension's descriptor, where 0 <= index < extension_count(). + // These are returned in the order they were defined in the .proto file. + const FieldDescriptor* extension(int idx) const; + + // Get options for this file. These are specified in the .proto file by + // placing lines like "option foo = 1234;" at the top level, outside of any + // other definitions. Allowed options are defined by FileOptions in + // google/protobuf/descriptor.proto, and any available extensions of that + // message. + const FileOptions& options() const; + + // Find a top-level message type by name. Returns NULL if not found. + const Descriptor* FindMessageTypeByName(const string& name) const; + // Find a top-level enum type by name. Returns NULL if not found. + const EnumDescriptor* FindEnumTypeByName(const string& name) const; + // Find an enum value defined in any top-level enum by name. Returns NULL if + // not found. + const EnumValueDescriptor* FindEnumValueByName(const string& name) const; + // Find a service definition by name. Returns NULL if not found. + const ServiceDescriptor* FindServiceByName(const string& name) const; + // Find a top-level extension definition by name. Returns NULL if not found. + const FieldDescriptor* FindExtensionByName(const string& name) const; + // Similar to FindExtensionByName(), but searches by lowercased-name. See + // Descriptor::FindFieldByLowercaseName(). + const FieldDescriptor* FindExtensionByLowercaseName(const string& name) const; + // Similar to FindExtensionByName(), but searches by camelcased-name. See + // Descriptor::FindFieldByCamelcaseName(). + const FieldDescriptor* FindExtensionByCamelcaseName(const string& name) const; + + // See Descriptor::CopyTo(). + // Notes: + // - This method does NOT copy source code information since it is relatively + // large and rarely needed. See CopySourceCodeInfoTo() below. + void CopyTo(FileDescriptorProto* proto) const; + // Write the source code information of this FileDescriptor into the given + // FileDescriptorProto. See CopyTo() above. + void CopySourceCodeInfoTo(FileDescriptorProto* proto) const; + + // See Descriptor::DebugString(). + string DebugString() const; + + private: + // Source Location --------------------------------------------------- + + // Updates |*out_location| to the source location of the complete + // extent of the declaration or declaration-part denoted by |path|. + // Returns false and leaves |*out_location| unchanged iff location + // information was not available. (See SourceCodeInfo for + // description of path encoding.) + bool GetSourceLocation(const vector& path, + SourceLocation* out_location) const; + + typedef FileOptions OptionsType; + + const string* name_; + const string* package_; + const DescriptorPool* pool_; + int dependency_count_; + const FileDescriptor** dependencies_; + int public_dependency_count_; + int* public_dependencies_; + int weak_dependency_count_; + int* weak_dependencies_; + int message_type_count_; + Descriptor* message_types_; + int enum_type_count_; + EnumDescriptor* enum_types_; + int service_count_; + ServiceDescriptor* services_; + int extension_count_; + FieldDescriptor* extensions_; + const FileOptions* options_; + + const FileDescriptorTables* tables_; + const SourceCodeInfo* source_code_info_; + // IMPORTANT: If you add a new field, make sure to search for all instances + // of Allocate() and AllocateArray() in + // descriptor.cc and update them to initialize the field. + + FileDescriptor() {} + friend class DescriptorBuilder; + friend class Descriptor; + friend class FieldDescriptor; + friend class EnumDescriptor; + friend class EnumValueDescriptor; + friend class MethodDescriptor; + friend class ServiceDescriptor; + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileDescriptor); +}; + +// =================================================================== + +// Used to construct descriptors. +// +// Normally you won't want to build your own descriptors. Message classes +// constructed by the protocol compiler will provide them for you. However, +// if you are implementing Message on your own, or if you are writing a +// program which can operate on totally arbitrary types and needs to load +// them from some sort of database, you might need to. +// +// Since Descriptors are composed of a whole lot of cross-linked bits of +// data that would be a pain to put together manually, the +// DescriptorPool class is provided to make the process easier. It can +// take a FileDescriptorProto (defined in descriptor.proto), validate it, +// and convert it to a set of nicely cross-linked Descriptors. +// +// DescriptorPool also helps with memory management. Descriptors are +// composed of many objects containing static data and pointers to each +// other. In all likelihood, when it comes time to delete this data, +// you'll want to delete it all at once. In fact, it is not uncommon to +// have a whole pool of descriptors all cross-linked with each other which +// you wish to delete all at once. This class represents such a pool, and +// handles the memory management for you. +// +// You can also search for descriptors within a DescriptorPool by name, and +// extensions by number. +class LIBPROTOBUF_EXPORT DescriptorPool { + public: + // Create a normal, empty DescriptorPool. + DescriptorPool(); + + // Constructs a DescriptorPool that, when it can't find something among the + // descriptors already in the pool, looks for it in the given + // DescriptorDatabase. + // Notes: + // - If a DescriptorPool is constructed this way, its BuildFile*() methods + // must not be called (they will assert-fail). The only way to populate + // the pool with descriptors is to call the Find*By*() methods. + // - The Find*By*() methods may block the calling thread if the + // DescriptorDatabase blocks. This in turn means that parsing messages + // may block if they need to look up extensions. + // - The Find*By*() methods will use mutexes for thread-safety, thus making + // them slower even when they don't have to fall back to the database. + // In fact, even the Find*By*() methods of descriptor objects owned by + // this pool will be slower, since they will have to obtain locks too. + // - An ErrorCollector may optionally be given to collect validation errors + // in files loaded from the database. If not given, errors will be printed + // to GOOGLE_LOG(ERROR). Remember that files are built on-demand, so this + // ErrorCollector may be called from any thread that calls one of the + // Find*By*() methods. + class ErrorCollector; + explicit DescriptorPool(DescriptorDatabase* fallback_database, + ErrorCollector* error_collector = NULL); + + ~DescriptorPool(); + + // Get a pointer to the generated pool. Generated protocol message classes + // which are compiled into the binary will allocate their descriptors in + // this pool. Do not add your own descriptors to this pool. + static const DescriptorPool* generated_pool(); + + // Find a FileDescriptor in the pool by file name. Returns NULL if not + // found. + const FileDescriptor* FindFileByName(const string& name) const; + + // Find the FileDescriptor in the pool which defines the given symbol. + // If any of the Find*ByName() methods below would succeed, then this is + // equivalent to calling that method and calling the result's file() method. + // Otherwise this returns NULL. + const FileDescriptor* FindFileContainingSymbol( + const string& symbol_name) const; + + // Looking up descriptors ------------------------------------------ + // These find descriptors by fully-qualified name. These will find both + // top-level descriptors and nested descriptors. They return NULL if not + // found. + + const Descriptor* FindMessageTypeByName(const string& name) const; + const FieldDescriptor* FindFieldByName(const string& name) const; + const FieldDescriptor* FindExtensionByName(const string& name) const; + const EnumDescriptor* FindEnumTypeByName(const string& name) const; + const EnumValueDescriptor* FindEnumValueByName(const string& name) const; + const ServiceDescriptor* FindServiceByName(const string& name) const; + const MethodDescriptor* FindMethodByName(const string& name) const; + + // Finds an extension of the given type by number. The extendee must be + // a member of this DescriptorPool or one of its underlays. + const FieldDescriptor* FindExtensionByNumber(const Descriptor* extendee, + int number) const; + + // Finds extensions of extendee. The extensions will be appended to + // out in an undefined order. Only extensions defined directly in + // this DescriptorPool or one of its underlays are guaranteed to be + // found: extensions defined in the fallback database might not be found + // depending on the database implementation. + void FindAllExtensions(const Descriptor* extendee, + vector* out) const; + + // Building descriptors -------------------------------------------- + + // When converting a FileDescriptorProto to a FileDescriptor, various + // errors might be detected in the input. The caller may handle these + // programmatically by implementing an ErrorCollector. + class LIBPROTOBUF_EXPORT ErrorCollector { + public: + inline ErrorCollector() {} + virtual ~ErrorCollector(); + + // These constants specify what exact part of the construct is broken. + // This is useful e.g. for mapping the error back to an exact location + // in a .proto file. + enum ErrorLocation { + NAME, // the symbol name, or the package name for files + NUMBER, // field or extension range number + TYPE, // field type + EXTENDEE, // field extendee + DEFAULT_VALUE, // field default value + INPUT_TYPE, // method input type + OUTPUT_TYPE, // method output type + OPTION_NAME, // name in assignment + OPTION_VALUE, // value in option assignment + OTHER // some other problem + }; + + // Reports an error in the FileDescriptorProto. + virtual void AddError( + const string& filename, // File name in which the error occurred. + const string& element_name, // Full name of the erroneous element. + const Message* descriptor, // Descriptor of the erroneous element. + ErrorLocation location, // One of the location constants, above. + const string& message // Human-readable error message. + ) = 0; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ErrorCollector); + }; + + // Convert the FileDescriptorProto to real descriptors and place them in + // this DescriptorPool. All dependencies of the file must already be in + // the pool. Returns the resulting FileDescriptor, or NULL if there were + // problems with the input (e.g. the message was invalid, or dependencies + // were missing). Details about the errors are written to GOOGLE_LOG(ERROR). + const FileDescriptor* BuildFile(const FileDescriptorProto& proto); + + // Same as BuildFile() except errors are sent to the given ErrorCollector. + const FileDescriptor* BuildFileCollectingErrors( + const FileDescriptorProto& proto, + ErrorCollector* error_collector); + + // By default, it is an error if a FileDescriptorProto contains references + // to types or other files that are not found in the DescriptorPool (or its + // backing DescriptorDatabase, if any). If you call + // AllowUnknownDependencies(), however, then unknown types and files + // will be replaced by placeholder descriptors. This can allow you to + // perform some useful operations with a .proto file even if you do not + // have access to other .proto files on which it depends. However, some + // heuristics must be used to fill in the gaps in information, and these + // can lead to descriptors which are inaccurate. For example, the + // DescriptorPool may be forced to guess whether an unknown type is a message + // or an enum, as well as what package it resides in. Furthermore, + // placeholder types will not be discoverable via FindMessageTypeByName() + // and similar methods, which could confuse some descriptor-based algorithms. + // Generally, the results of this option should only be relied upon for + // debugging purposes. + void AllowUnknownDependencies() { allow_unknown_ = true; } + + // Internal stuff -------------------------------------------------- + // These methods MUST NOT be called from outside the proto2 library. + // These methods may contain hidden pitfalls and may be removed in a + // future library version. + + // Create a DescriptorPool which is overlaid on top of some other pool. + // If you search for a descriptor in the overlay and it is not found, the + // underlay will be searched as a backup. If the underlay has its own + // underlay, that will be searched next, and so on. This also means that + // files built in the overlay will be cross-linked with the underlay's + // descriptors if necessary. The underlay remains property of the caller; + // it must remain valid for the lifetime of the newly-constructed pool. + // + // Example: Say you want to parse a .proto file at runtime in order to use + // its type with a DynamicMessage. Say this .proto file has dependencies, + // but you know that all the dependencies will be things that are already + // compiled into the binary. For ease of use, you'd like to load the types + // right out of generated_pool() rather than have to parse redundant copies + // of all these .protos and runtime. But, you don't want to add the parsed + // types directly into generated_pool(): this is not allowed, and would be + // bad design anyway. So, instead, you could use generated_pool() as an + // underlay for a new DescriptorPool in which you add only the new file. + // + // WARNING: Use of underlays can lead to many subtle gotchas. Instead, + // try to formulate what you want to do in terms of DescriptorDatabases. + explicit DescriptorPool(const DescriptorPool* underlay); + + // Called by generated classes at init time to add their descriptors to + // generated_pool. Do NOT call this in your own code! filename must be a + // permanent string (e.g. a string literal). + static void InternalAddGeneratedFile( + const void* encoded_file_descriptor, int size); + + + // For internal use only: Gets a non-const pointer to the generated pool. + // This is called at static-initialization time only, so thread-safety is + // not a concern. If both an underlay and a fallback database are present, + // the underlay takes precedence. + static DescriptorPool* internal_generated_pool(); + + // For internal use only: Changes the behavior of BuildFile() such that it + // allows the file to make reference to message types declared in other files + // which it did not officially declare as dependencies. + void InternalDontEnforceDependencies(); + + // For internal use only. + void internal_set_underlay(const DescriptorPool* underlay) { + underlay_ = underlay; + } + + // For internal (unit test) use only: Returns true if a FileDescriptor has + // been constructed for the given file, false otherwise. Useful for testing + // lazy descriptor initialization behavior. + bool InternalIsFileLoaded(const string& filename) const; + + private: + friend class Descriptor; + friend class FieldDescriptor; + friend class EnumDescriptor; + friend class ServiceDescriptor; + friend class FileDescriptor; + friend class DescriptorBuilder; + + // Return true if the given name is a sub-symbol of any non-package + // descriptor that already exists in the descriptor pool. (The full + // definition of such types is already known.) + bool IsSubSymbolOfBuiltType(const string& name) const; + + // Tries to find something in the fallback database and link in the + // corresponding proto file. Returns true if successful, in which case + // the caller should search for the thing again. These are declared + // const because they are called by (semantically) const methods. + bool TryFindFileInFallbackDatabase(const string& name) const; + bool TryFindSymbolInFallbackDatabase(const string& name) const; + bool TryFindExtensionInFallbackDatabase(const Descriptor* containing_type, + int field_number) const; + + // Like BuildFile() but called internally when the file has been loaded from + // fallback_database_. Declared const because it is called by (semantically) + // const methods. + const FileDescriptor* BuildFileFromDatabase( + const FileDescriptorProto& proto) const; + + // If fallback_database_ is NULL, this is NULL. Otherwise, this is a mutex + // which must be locked while accessing tables_. + Mutex* mutex_; + + // See constructor. + DescriptorDatabase* fallback_database_; + ErrorCollector* default_error_collector_; + const DescriptorPool* underlay_; + + // This class contains a lot of hash maps with complicated types that + // we'd like to keep out of the header. + class Tables; + scoped_ptr tables_; + + bool enforce_dependencies_; + bool allow_unknown_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DescriptorPool); +}; + +// inline methods ==================================================== + +// These macros makes this repetitive code more readable. +#define PROTOBUF_DEFINE_ACCESSOR(CLASS, FIELD, TYPE) \ + inline TYPE CLASS::FIELD() const { return FIELD##_; } + +// Strings fields are stored as pointers but returned as const references. +#define PROTOBUF_DEFINE_STRING_ACCESSOR(CLASS, FIELD) \ + inline const string& CLASS::FIELD() const { return *FIELD##_; } + +// Arrays take an index parameter, obviously. +#define PROTOBUF_DEFINE_ARRAY_ACCESSOR(CLASS, FIELD, TYPE) \ + inline TYPE CLASS::FIELD(int idx) const { return FIELD##s_ + idx; } + +#define PROTOBUF_DEFINE_OPTIONS_ACCESSOR(CLASS, TYPE) \ + inline const TYPE& CLASS::options() const { return *options_; } + +PROTOBUF_DEFINE_STRING_ACCESSOR(Descriptor, name) +PROTOBUF_DEFINE_STRING_ACCESSOR(Descriptor, full_name) +PROTOBUF_DEFINE_ACCESSOR(Descriptor, file, const FileDescriptor*) +PROTOBUF_DEFINE_ACCESSOR(Descriptor, containing_type, const Descriptor*) + +PROTOBUF_DEFINE_ACCESSOR(Descriptor, field_count, int) +PROTOBUF_DEFINE_ACCESSOR(Descriptor, nested_type_count, int) +PROTOBUF_DEFINE_ACCESSOR(Descriptor, enum_type_count, int) + +PROTOBUF_DEFINE_ARRAY_ACCESSOR(Descriptor, field, const FieldDescriptor*) +PROTOBUF_DEFINE_ARRAY_ACCESSOR(Descriptor, nested_type, const Descriptor*) +PROTOBUF_DEFINE_ARRAY_ACCESSOR(Descriptor, enum_type, const EnumDescriptor*) + +PROTOBUF_DEFINE_ACCESSOR(Descriptor, extension_range_count, int) +PROTOBUF_DEFINE_ACCESSOR(Descriptor, extension_count, int) +PROTOBUF_DEFINE_ARRAY_ACCESSOR(Descriptor, extension_range, + const Descriptor::ExtensionRange*) +PROTOBUF_DEFINE_ARRAY_ACCESSOR(Descriptor, extension, + const FieldDescriptor*) +PROTOBUF_DEFINE_OPTIONS_ACCESSOR(Descriptor, MessageOptions) + +PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, name) +PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, full_name) +PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, lowercase_name) +PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, camelcase_name) +PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, file, const FileDescriptor*) +PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, number, int) +PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, is_extension, bool) +PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, type, FieldDescriptor::Type) +PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, label, FieldDescriptor::Label) +PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, containing_type, const Descriptor*) +PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, extension_scope, const Descriptor*) +PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, message_type, const Descriptor*) +PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, enum_type, const EnumDescriptor*) +PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, experimental_map_key, + const FieldDescriptor*) +PROTOBUF_DEFINE_OPTIONS_ACCESSOR(FieldDescriptor, FieldOptions) +PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, has_default_value, bool) +PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, default_value_int32 , int32 ) +PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, default_value_int64 , int64 ) +PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, default_value_uint32, uint32) +PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, default_value_uint64, uint64) +PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, default_value_float , float ) +PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, default_value_double, double) +PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, default_value_bool , bool ) +PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, default_value_enum, + const EnumValueDescriptor*) +PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, default_value_string) + +PROTOBUF_DEFINE_STRING_ACCESSOR(EnumDescriptor, name) +PROTOBUF_DEFINE_STRING_ACCESSOR(EnumDescriptor, full_name) +PROTOBUF_DEFINE_ACCESSOR(EnumDescriptor, file, const FileDescriptor*) +PROTOBUF_DEFINE_ACCESSOR(EnumDescriptor, containing_type, const Descriptor*) +PROTOBUF_DEFINE_ACCESSOR(EnumDescriptor, value_count, int) +PROTOBUF_DEFINE_ARRAY_ACCESSOR(EnumDescriptor, value, + const EnumValueDescriptor*) +PROTOBUF_DEFINE_OPTIONS_ACCESSOR(EnumDescriptor, EnumOptions) + +PROTOBUF_DEFINE_STRING_ACCESSOR(EnumValueDescriptor, name) +PROTOBUF_DEFINE_STRING_ACCESSOR(EnumValueDescriptor, full_name) +PROTOBUF_DEFINE_ACCESSOR(EnumValueDescriptor, number, int) +PROTOBUF_DEFINE_ACCESSOR(EnumValueDescriptor, type, const EnumDescriptor*) +PROTOBUF_DEFINE_OPTIONS_ACCESSOR(EnumValueDescriptor, EnumValueOptions) + +PROTOBUF_DEFINE_STRING_ACCESSOR(ServiceDescriptor, name) +PROTOBUF_DEFINE_STRING_ACCESSOR(ServiceDescriptor, full_name) +PROTOBUF_DEFINE_ACCESSOR(ServiceDescriptor, file, const FileDescriptor*) +PROTOBUF_DEFINE_ACCESSOR(ServiceDescriptor, method_count, int) +PROTOBUF_DEFINE_ARRAY_ACCESSOR(ServiceDescriptor, method, + const MethodDescriptor*) +PROTOBUF_DEFINE_OPTIONS_ACCESSOR(ServiceDescriptor, ServiceOptions) + +PROTOBUF_DEFINE_STRING_ACCESSOR(MethodDescriptor, name) +PROTOBUF_DEFINE_STRING_ACCESSOR(MethodDescriptor, full_name) +PROTOBUF_DEFINE_ACCESSOR(MethodDescriptor, service, const ServiceDescriptor*) +PROTOBUF_DEFINE_ACCESSOR(MethodDescriptor, input_type, const Descriptor*) +PROTOBUF_DEFINE_ACCESSOR(MethodDescriptor, output_type, const Descriptor*) +PROTOBUF_DEFINE_OPTIONS_ACCESSOR(MethodDescriptor, MethodOptions) +PROTOBUF_DEFINE_STRING_ACCESSOR(FileDescriptor, name) +PROTOBUF_DEFINE_STRING_ACCESSOR(FileDescriptor, package) +PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, pool, const DescriptorPool*) +PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, dependency_count, int) +PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, public_dependency_count, int) +PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, weak_dependency_count, int) +PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, message_type_count, int) +PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, enum_type_count, int) +PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, service_count, int) +PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, extension_count, int) +PROTOBUF_DEFINE_OPTIONS_ACCESSOR(FileDescriptor, FileOptions) + +PROTOBUF_DEFINE_ARRAY_ACCESSOR(FileDescriptor, message_type, const Descriptor*) +PROTOBUF_DEFINE_ARRAY_ACCESSOR(FileDescriptor, enum_type, const EnumDescriptor*) +PROTOBUF_DEFINE_ARRAY_ACCESSOR(FileDescriptor, service, + const ServiceDescriptor*) +PROTOBUF_DEFINE_ARRAY_ACCESSOR(FileDescriptor, extension, + const FieldDescriptor*) + +#undef PROTOBUF_DEFINE_ACCESSOR +#undef PROTOBUF_DEFINE_STRING_ACCESSOR +#undef PROTOBUF_DEFINE_ARRAY_ACCESSOR + +// A few accessors differ from the macros... + +inline bool FieldDescriptor::is_required() const { + return label() == LABEL_REQUIRED; +} + +inline bool FieldDescriptor::is_optional() const { + return label() == LABEL_OPTIONAL; +} + +inline bool FieldDescriptor::is_repeated() const { + return label() == LABEL_REPEATED; +} + +inline bool FieldDescriptor::is_packable() const { + return is_repeated() && IsTypePackable(type()); +} + +// To save space, index() is computed by looking at the descriptor's position +// in the parent's array of children. +inline int FieldDescriptor::index() const { + if (!is_extension_) { + return this - containing_type_->fields_; + } else if (extension_scope_ != NULL) { + return this - extension_scope_->extensions_; + } else { + return this - file_->extensions_; + } +} + +inline int Descriptor::index() const { + if (containing_type_ == NULL) { + return this - file_->message_types_; + } else { + return this - containing_type_->nested_types_; + } +} + +inline int EnumDescriptor::index() const { + if (containing_type_ == NULL) { + return this - file_->enum_types_; + } else { + return this - containing_type_->enum_types_; + } +} + +inline int EnumValueDescriptor::index() const { + return this - type_->values_; +} + +inline int ServiceDescriptor::index() const { + return this - file_->services_; +} + +inline int MethodDescriptor::index() const { + return this - service_->methods_; +} + +inline const char* FieldDescriptor::type_name() const { + return kTypeToName[type_]; +} + +inline FieldDescriptor::CppType FieldDescriptor::cpp_type() const { + return kTypeToCppTypeMap[type_]; +} + +inline const char* FieldDescriptor::cpp_type_name() const { + return kCppTypeToName[kTypeToCppTypeMap[type_]]; +} + +inline FieldDescriptor::CppType FieldDescriptor::TypeToCppType(Type type) { + return kTypeToCppTypeMap[type]; +} + +inline bool FieldDescriptor::IsTypePackable(Type field_type) { + return (field_type != FieldDescriptor::TYPE_STRING && + field_type != FieldDescriptor::TYPE_GROUP && + field_type != FieldDescriptor::TYPE_MESSAGE && + field_type != FieldDescriptor::TYPE_BYTES); +} + +inline const FileDescriptor* FileDescriptor::dependency(int index) const { + return dependencies_[index]; +} + +inline const FileDescriptor* FileDescriptor::public_dependency( + int index) const { + return dependencies_[public_dependencies_[index]]; +} + +inline const FileDescriptor* FileDescriptor::weak_dependency( + int index) const { + return dependencies_[weak_dependencies_[index]]; +} + +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_DESCRIPTOR_H__ diff --git a/include/google/protobuf/descriptor.pb.h b/include/google/protobuf/descriptor.pb.h new file mode 100644 index 000000000..07cf8077c --- /dev/null +++ b/include/google/protobuf/descriptor.pb.h @@ -0,0 +1,5992 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: google/protobuf/descriptor.proto + +#ifndef PROTOBUF_google_2fprotobuf_2fdescriptor_2eproto__INCLUDED +#define PROTOBUF_google_2fprotobuf_2fdescriptor_2eproto__INCLUDED + +#include + +#include + +#if GOOGLE_PROTOBUF_VERSION < 2005000 +#error This file was generated by a newer version of protoc which is +#error incompatible with your Protocol Buffer headers. Please update +#error your headers. +#endif +#if 2005000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION +#error This file was generated by an older version of protoc which is +#error incompatible with your Protocol Buffer headers. Please +#error regenerate this file with a newer version of protoc. +#endif + +#include +#include +#include +#include +#include +#include +// @@protoc_insertion_point(includes) + +namespace google { +namespace protobuf { + +// Internal implementation detail -- do not call these. +void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); +void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); +void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto(); + +class FileDescriptorSet; +class FileDescriptorProto; +class DescriptorProto; +class DescriptorProto_ExtensionRange; +class FieldDescriptorProto; +class EnumDescriptorProto; +class EnumValueDescriptorProto; +class ServiceDescriptorProto; +class MethodDescriptorProto; +class FileOptions; +class MessageOptions; +class FieldOptions; +class EnumOptions; +class EnumValueOptions; +class ServiceOptions; +class MethodOptions; +class UninterpretedOption; +class UninterpretedOption_NamePart; +class SourceCodeInfo; +class SourceCodeInfo_Location; + +enum FieldDescriptorProto_Type { + FieldDescriptorProto_Type_TYPE_DOUBLE = 1, + FieldDescriptorProto_Type_TYPE_FLOAT = 2, + FieldDescriptorProto_Type_TYPE_INT64 = 3, + FieldDescriptorProto_Type_TYPE_UINT64 = 4, + FieldDescriptorProto_Type_TYPE_INT32 = 5, + FieldDescriptorProto_Type_TYPE_FIXED64 = 6, + FieldDescriptorProto_Type_TYPE_FIXED32 = 7, + FieldDescriptorProto_Type_TYPE_BOOL = 8, + FieldDescriptorProto_Type_TYPE_STRING = 9, + FieldDescriptorProto_Type_TYPE_GROUP = 10, + FieldDescriptorProto_Type_TYPE_MESSAGE = 11, + FieldDescriptorProto_Type_TYPE_BYTES = 12, + FieldDescriptorProto_Type_TYPE_UINT32 = 13, + FieldDescriptorProto_Type_TYPE_ENUM = 14, + FieldDescriptorProto_Type_TYPE_SFIXED32 = 15, + FieldDescriptorProto_Type_TYPE_SFIXED64 = 16, + FieldDescriptorProto_Type_TYPE_SINT32 = 17, + FieldDescriptorProto_Type_TYPE_SINT64 = 18 +}; +LIBPROTOBUF_EXPORT bool FieldDescriptorProto_Type_IsValid(int value); +const FieldDescriptorProto_Type FieldDescriptorProto_Type_Type_MIN = FieldDescriptorProto_Type_TYPE_DOUBLE; +const FieldDescriptorProto_Type FieldDescriptorProto_Type_Type_MAX = FieldDescriptorProto_Type_TYPE_SINT64; +const int FieldDescriptorProto_Type_Type_ARRAYSIZE = FieldDescriptorProto_Type_Type_MAX + 1; + +LIBPROTOBUF_EXPORT const ::google::protobuf::EnumDescriptor* FieldDescriptorProto_Type_descriptor(); +inline const ::std::string& FieldDescriptorProto_Type_Name(FieldDescriptorProto_Type value) { + return ::google::protobuf::internal::NameOfEnum( + FieldDescriptorProto_Type_descriptor(), value); +} +inline bool FieldDescriptorProto_Type_Parse( + const ::std::string& name, FieldDescriptorProto_Type* value) { + return ::google::protobuf::internal::ParseNamedEnum( + FieldDescriptorProto_Type_descriptor(), name, value); +} +enum FieldDescriptorProto_Label { + FieldDescriptorProto_Label_LABEL_OPTIONAL = 1, + FieldDescriptorProto_Label_LABEL_REQUIRED = 2, + FieldDescriptorProto_Label_LABEL_REPEATED = 3 +}; +LIBPROTOBUF_EXPORT bool FieldDescriptorProto_Label_IsValid(int value); +const FieldDescriptorProto_Label FieldDescriptorProto_Label_Label_MIN = FieldDescriptorProto_Label_LABEL_OPTIONAL; +const FieldDescriptorProto_Label FieldDescriptorProto_Label_Label_MAX = FieldDescriptorProto_Label_LABEL_REPEATED; +const int FieldDescriptorProto_Label_Label_ARRAYSIZE = FieldDescriptorProto_Label_Label_MAX + 1; + +LIBPROTOBUF_EXPORT const ::google::protobuf::EnumDescriptor* FieldDescriptorProto_Label_descriptor(); +inline const ::std::string& FieldDescriptorProto_Label_Name(FieldDescriptorProto_Label value) { + return ::google::protobuf::internal::NameOfEnum( + FieldDescriptorProto_Label_descriptor(), value); +} +inline bool FieldDescriptorProto_Label_Parse( + const ::std::string& name, FieldDescriptorProto_Label* value) { + return ::google::protobuf::internal::ParseNamedEnum( + FieldDescriptorProto_Label_descriptor(), name, value); +} +enum FileOptions_OptimizeMode { + FileOptions_OptimizeMode_SPEED = 1, + FileOptions_OptimizeMode_CODE_SIZE = 2, + FileOptions_OptimizeMode_LITE_RUNTIME = 3 +}; +LIBPROTOBUF_EXPORT bool FileOptions_OptimizeMode_IsValid(int value); +const FileOptions_OptimizeMode FileOptions_OptimizeMode_OptimizeMode_MIN = FileOptions_OptimizeMode_SPEED; +const FileOptions_OptimizeMode FileOptions_OptimizeMode_OptimizeMode_MAX = FileOptions_OptimizeMode_LITE_RUNTIME; +const int FileOptions_OptimizeMode_OptimizeMode_ARRAYSIZE = FileOptions_OptimizeMode_OptimizeMode_MAX + 1; + +LIBPROTOBUF_EXPORT const ::google::protobuf::EnumDescriptor* FileOptions_OptimizeMode_descriptor(); +inline const ::std::string& FileOptions_OptimizeMode_Name(FileOptions_OptimizeMode value) { + return ::google::protobuf::internal::NameOfEnum( + FileOptions_OptimizeMode_descriptor(), value); +} +inline bool FileOptions_OptimizeMode_Parse( + const ::std::string& name, FileOptions_OptimizeMode* value) { + return ::google::protobuf::internal::ParseNamedEnum( + FileOptions_OptimizeMode_descriptor(), name, value); +} +enum FieldOptions_CType { + FieldOptions_CType_STRING = 0, + FieldOptions_CType_CORD = 1, + FieldOptions_CType_STRING_PIECE = 2 +}; +LIBPROTOBUF_EXPORT bool FieldOptions_CType_IsValid(int value); +const FieldOptions_CType FieldOptions_CType_CType_MIN = FieldOptions_CType_STRING; +const FieldOptions_CType FieldOptions_CType_CType_MAX = FieldOptions_CType_STRING_PIECE; +const int FieldOptions_CType_CType_ARRAYSIZE = FieldOptions_CType_CType_MAX + 1; + +LIBPROTOBUF_EXPORT const ::google::protobuf::EnumDescriptor* FieldOptions_CType_descriptor(); +inline const ::std::string& FieldOptions_CType_Name(FieldOptions_CType value) { + return ::google::protobuf::internal::NameOfEnum( + FieldOptions_CType_descriptor(), value); +} +inline bool FieldOptions_CType_Parse( + const ::std::string& name, FieldOptions_CType* value) { + return ::google::protobuf::internal::ParseNamedEnum( + FieldOptions_CType_descriptor(), name, value); +} +// =================================================================== + +class LIBPROTOBUF_EXPORT FileDescriptorSet : public ::google::protobuf::Message { + public: + FileDescriptorSet(); + virtual ~FileDescriptorSet(); + + FileDescriptorSet(const FileDescriptorSet& from); + + inline FileDescriptorSet& operator=(const FileDescriptorSet& from) { + CopyFrom(from); + return *this; + } + + inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { + return _unknown_fields_; + } + + inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { + return &_unknown_fields_; + } + + static const ::google::protobuf::Descriptor* descriptor(); + static const FileDescriptorSet& default_instance(); + + void Swap(FileDescriptorSet* other); + + // implements Message ---------------------------------------------- + + FileDescriptorSet* New() const; + void CopyFrom(const ::google::protobuf::Message& from); + void MergeFrom(const ::google::protobuf::Message& from); + void CopyFrom(const FileDescriptorSet& from); + void MergeFrom(const FileDescriptorSet& from); + void Clear(); + bool IsInitialized() const; + + int ByteSize() const; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input); + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const; + ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const; + int GetCachedSize() const { return _cached_size_; } + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + public: + + ::google::protobuf::Metadata GetMetadata() const; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + // repeated .google.protobuf.FileDescriptorProto file = 1; + inline int file_size() const; + inline void clear_file(); + static const int kFileFieldNumber = 1; + inline const ::google::protobuf::FileDescriptorProto& file(int index) const; + inline ::google::protobuf::FileDescriptorProto* mutable_file(int index); + inline ::google::protobuf::FileDescriptorProto* add_file(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >& + file() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >* + mutable_file(); + + // @@protoc_insertion_point(class_scope:google.protobuf.FileDescriptorSet) + private: + + ::google::protobuf::UnknownFieldSet _unknown_fields_; + + ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto > file_; + + mutable int _cached_size_; + ::google::protobuf::uint32 _has_bits_[(1 + 31) / 32]; + + friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto(); + + void InitAsDefaultInstance(); + static FileDescriptorSet* default_instance_; +}; +// ------------------------------------------------------------------- + +class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Message { + public: + FileDescriptorProto(); + virtual ~FileDescriptorProto(); + + FileDescriptorProto(const FileDescriptorProto& from); + + inline FileDescriptorProto& operator=(const FileDescriptorProto& from) { + CopyFrom(from); + return *this; + } + + inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { + return _unknown_fields_; + } + + inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { + return &_unknown_fields_; + } + + static const ::google::protobuf::Descriptor* descriptor(); + static const FileDescriptorProto& default_instance(); + + void Swap(FileDescriptorProto* other); + + // implements Message ---------------------------------------------- + + FileDescriptorProto* New() const; + void CopyFrom(const ::google::protobuf::Message& from); + void MergeFrom(const ::google::protobuf::Message& from); + void CopyFrom(const FileDescriptorProto& from); + void MergeFrom(const FileDescriptorProto& from); + void Clear(); + bool IsInitialized() const; + + int ByteSize() const; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input); + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const; + ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const; + int GetCachedSize() const { return _cached_size_; } + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + public: + + ::google::protobuf::Metadata GetMetadata() const; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + // optional string name = 1; + inline bool has_name() const; + inline void clear_name(); + static const int kNameFieldNumber = 1; + inline const ::std::string& name() const; + inline void set_name(const ::std::string& value); + inline void set_name(const char* value); + inline void set_name(const char* value, size_t size); + inline ::std::string* mutable_name(); + inline ::std::string* release_name(); + inline void set_allocated_name(::std::string* name); + + // optional string package = 2; + inline bool has_package() const; + inline void clear_package(); + static const int kPackageFieldNumber = 2; + inline const ::std::string& package() const; + inline void set_package(const ::std::string& value); + inline void set_package(const char* value); + inline void set_package(const char* value, size_t size); + inline ::std::string* mutable_package(); + inline ::std::string* release_package(); + inline void set_allocated_package(::std::string* package); + + // repeated string dependency = 3; + inline int dependency_size() const; + inline void clear_dependency(); + static const int kDependencyFieldNumber = 3; + inline const ::std::string& dependency(int index) const; + inline ::std::string* mutable_dependency(int index); + inline void set_dependency(int index, const ::std::string& value); + inline void set_dependency(int index, const char* value); + inline void set_dependency(int index, const char* value, size_t size); + inline ::std::string* add_dependency(); + inline void add_dependency(const ::std::string& value); + inline void add_dependency(const char* value); + inline void add_dependency(const char* value, size_t size); + inline const ::google::protobuf::RepeatedPtrField< ::std::string>& dependency() const; + inline ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_dependency(); + + // repeated int32 public_dependency = 10; + inline int public_dependency_size() const; + inline void clear_public_dependency(); + static const int kPublicDependencyFieldNumber = 10; + inline ::google::protobuf::int32 public_dependency(int index) const; + inline void set_public_dependency(int index, ::google::protobuf::int32 value); + inline void add_public_dependency(::google::protobuf::int32 value); + inline const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >& + public_dependency() const; + inline ::google::protobuf::RepeatedField< ::google::protobuf::int32 >* + mutable_public_dependency(); + + // repeated int32 weak_dependency = 11; + inline int weak_dependency_size() const; + inline void clear_weak_dependency(); + static const int kWeakDependencyFieldNumber = 11; + inline ::google::protobuf::int32 weak_dependency(int index) const; + inline void set_weak_dependency(int index, ::google::protobuf::int32 value); + inline void add_weak_dependency(::google::protobuf::int32 value); + inline const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >& + weak_dependency() const; + inline ::google::protobuf::RepeatedField< ::google::protobuf::int32 >* + mutable_weak_dependency(); + + // repeated .google.protobuf.DescriptorProto message_type = 4; + inline int message_type_size() const; + inline void clear_message_type(); + static const int kMessageTypeFieldNumber = 4; + inline const ::google::protobuf::DescriptorProto& message_type(int index) const; + inline ::google::protobuf::DescriptorProto* mutable_message_type(int index); + inline ::google::protobuf::DescriptorProto* add_message_type(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >& + message_type() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >* + mutable_message_type(); + + // repeated .google.protobuf.EnumDescriptorProto enum_type = 5; + inline int enum_type_size() const; + inline void clear_enum_type(); + static const int kEnumTypeFieldNumber = 5; + inline const ::google::protobuf::EnumDescriptorProto& enum_type(int index) const; + inline ::google::protobuf::EnumDescriptorProto* mutable_enum_type(int index); + inline ::google::protobuf::EnumDescriptorProto* add_enum_type(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >& + enum_type() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >* + mutable_enum_type(); + + // repeated .google.protobuf.ServiceDescriptorProto service = 6; + inline int service_size() const; + inline void clear_service(); + static const int kServiceFieldNumber = 6; + inline const ::google::protobuf::ServiceDescriptorProto& service(int index) const; + inline ::google::protobuf::ServiceDescriptorProto* mutable_service(int index); + inline ::google::protobuf::ServiceDescriptorProto* add_service(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >& + service() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >* + mutable_service(); + + // repeated .google.protobuf.FieldDescriptorProto extension = 7; + inline int extension_size() const; + inline void clear_extension(); + static const int kExtensionFieldNumber = 7; + inline const ::google::protobuf::FieldDescriptorProto& extension(int index) const; + inline ::google::protobuf::FieldDescriptorProto* mutable_extension(int index); + inline ::google::protobuf::FieldDescriptorProto* add_extension(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& + extension() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* + mutable_extension(); + + // optional .google.protobuf.FileOptions options = 8; + inline bool has_options() const; + inline void clear_options(); + static const int kOptionsFieldNumber = 8; + inline const ::google::protobuf::FileOptions& options() const; + inline ::google::protobuf::FileOptions* mutable_options(); + inline ::google::protobuf::FileOptions* release_options(); + inline void set_allocated_options(::google::protobuf::FileOptions* options); + + // optional .google.protobuf.SourceCodeInfo source_code_info = 9; + inline bool has_source_code_info() const; + inline void clear_source_code_info(); + static const int kSourceCodeInfoFieldNumber = 9; + inline const ::google::protobuf::SourceCodeInfo& source_code_info() const; + inline ::google::protobuf::SourceCodeInfo* mutable_source_code_info(); + inline ::google::protobuf::SourceCodeInfo* release_source_code_info(); + inline void set_allocated_source_code_info(::google::protobuf::SourceCodeInfo* source_code_info); + + // @@protoc_insertion_point(class_scope:google.protobuf.FileDescriptorProto) + private: + inline void set_has_name(); + inline void clear_has_name(); + inline void set_has_package(); + inline void clear_has_package(); + inline void set_has_options(); + inline void clear_has_options(); + inline void set_has_source_code_info(); + inline void clear_has_source_code_info(); + + ::google::protobuf::UnknownFieldSet _unknown_fields_; + + ::std::string* name_; + ::std::string* package_; + ::google::protobuf::RepeatedPtrField< ::std::string> dependency_; + ::google::protobuf::RepeatedField< ::google::protobuf::int32 > public_dependency_; + ::google::protobuf::RepeatedField< ::google::protobuf::int32 > weak_dependency_; + ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto > message_type_; + ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto > enum_type_; + ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto > service_; + ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto > extension_; + ::google::protobuf::FileOptions* options_; + ::google::protobuf::SourceCodeInfo* source_code_info_; + + mutable int _cached_size_; + ::google::protobuf::uint32 _has_bits_[(11 + 31) / 32]; + + friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto(); + + void InitAsDefaultInstance(); + static FileDescriptorProto* default_instance_; +}; +// ------------------------------------------------------------------- + +class LIBPROTOBUF_EXPORT DescriptorProto_ExtensionRange : public ::google::protobuf::Message { + public: + DescriptorProto_ExtensionRange(); + virtual ~DescriptorProto_ExtensionRange(); + + DescriptorProto_ExtensionRange(const DescriptorProto_ExtensionRange& from); + + inline DescriptorProto_ExtensionRange& operator=(const DescriptorProto_ExtensionRange& from) { + CopyFrom(from); + return *this; + } + + inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { + return _unknown_fields_; + } + + inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { + return &_unknown_fields_; + } + + static const ::google::protobuf::Descriptor* descriptor(); + static const DescriptorProto_ExtensionRange& default_instance(); + + void Swap(DescriptorProto_ExtensionRange* other); + + // implements Message ---------------------------------------------- + + DescriptorProto_ExtensionRange* New() const; + void CopyFrom(const ::google::protobuf::Message& from); + void MergeFrom(const ::google::protobuf::Message& from); + void CopyFrom(const DescriptorProto_ExtensionRange& from); + void MergeFrom(const DescriptorProto_ExtensionRange& from); + void Clear(); + bool IsInitialized() const; + + int ByteSize() const; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input); + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const; + ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const; + int GetCachedSize() const { return _cached_size_; } + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + public: + + ::google::protobuf::Metadata GetMetadata() const; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + // optional int32 start = 1; + inline bool has_start() const; + inline void clear_start(); + static const int kStartFieldNumber = 1; + inline ::google::protobuf::int32 start() const; + inline void set_start(::google::protobuf::int32 value); + + // optional int32 end = 2; + inline bool has_end() const; + inline void clear_end(); + static const int kEndFieldNumber = 2; + inline ::google::protobuf::int32 end() const; + inline void set_end(::google::protobuf::int32 value); + + // @@protoc_insertion_point(class_scope:google.protobuf.DescriptorProto.ExtensionRange) + private: + inline void set_has_start(); + inline void clear_has_start(); + inline void set_has_end(); + inline void clear_has_end(); + + ::google::protobuf::UnknownFieldSet _unknown_fields_; + + ::google::protobuf::int32 start_; + ::google::protobuf::int32 end_; + + mutable int _cached_size_; + ::google::protobuf::uint32 _has_bits_[(2 + 31) / 32]; + + friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto(); + + void InitAsDefaultInstance(); + static DescriptorProto_ExtensionRange* default_instance_; +}; +// ------------------------------------------------------------------- + +class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message { + public: + DescriptorProto(); + virtual ~DescriptorProto(); + + DescriptorProto(const DescriptorProto& from); + + inline DescriptorProto& operator=(const DescriptorProto& from) { + CopyFrom(from); + return *this; + } + + inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { + return _unknown_fields_; + } + + inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { + return &_unknown_fields_; + } + + static const ::google::protobuf::Descriptor* descriptor(); + static const DescriptorProto& default_instance(); + + void Swap(DescriptorProto* other); + + // implements Message ---------------------------------------------- + + DescriptorProto* New() const; + void CopyFrom(const ::google::protobuf::Message& from); + void MergeFrom(const ::google::protobuf::Message& from); + void CopyFrom(const DescriptorProto& from); + void MergeFrom(const DescriptorProto& from); + void Clear(); + bool IsInitialized() const; + + int ByteSize() const; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input); + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const; + ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const; + int GetCachedSize() const { return _cached_size_; } + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + public: + + ::google::protobuf::Metadata GetMetadata() const; + + // nested types ---------------------------------------------------- + + typedef DescriptorProto_ExtensionRange ExtensionRange; + + // accessors ------------------------------------------------------- + + // optional string name = 1; + inline bool has_name() const; + inline void clear_name(); + static const int kNameFieldNumber = 1; + inline const ::std::string& name() const; + inline void set_name(const ::std::string& value); + inline void set_name(const char* value); + inline void set_name(const char* value, size_t size); + inline ::std::string* mutable_name(); + inline ::std::string* release_name(); + inline void set_allocated_name(::std::string* name); + + // repeated .google.protobuf.FieldDescriptorProto field = 2; + inline int field_size() const; + inline void clear_field(); + static const int kFieldFieldNumber = 2; + inline const ::google::protobuf::FieldDescriptorProto& field(int index) const; + inline ::google::protobuf::FieldDescriptorProto* mutable_field(int index); + inline ::google::protobuf::FieldDescriptorProto* add_field(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& + field() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* + mutable_field(); + + // repeated .google.protobuf.FieldDescriptorProto extension = 6; + inline int extension_size() const; + inline void clear_extension(); + static const int kExtensionFieldNumber = 6; + inline const ::google::protobuf::FieldDescriptorProto& extension(int index) const; + inline ::google::protobuf::FieldDescriptorProto* mutable_extension(int index); + inline ::google::protobuf::FieldDescriptorProto* add_extension(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& + extension() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* + mutable_extension(); + + // repeated .google.protobuf.DescriptorProto nested_type = 3; + inline int nested_type_size() const; + inline void clear_nested_type(); + static const int kNestedTypeFieldNumber = 3; + inline const ::google::protobuf::DescriptorProto& nested_type(int index) const; + inline ::google::protobuf::DescriptorProto* mutable_nested_type(int index); + inline ::google::protobuf::DescriptorProto* add_nested_type(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >& + nested_type() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >* + mutable_nested_type(); + + // repeated .google.protobuf.EnumDescriptorProto enum_type = 4; + inline int enum_type_size() const; + inline void clear_enum_type(); + static const int kEnumTypeFieldNumber = 4; + inline const ::google::protobuf::EnumDescriptorProto& enum_type(int index) const; + inline ::google::protobuf::EnumDescriptorProto* mutable_enum_type(int index); + inline ::google::protobuf::EnumDescriptorProto* add_enum_type(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >& + enum_type() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >* + mutable_enum_type(); + + // repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5; + inline int extension_range_size() const; + inline void clear_extension_range(); + static const int kExtensionRangeFieldNumber = 5; + inline const ::google::protobuf::DescriptorProto_ExtensionRange& extension_range(int index) const; + inline ::google::protobuf::DescriptorProto_ExtensionRange* mutable_extension_range(int index); + inline ::google::protobuf::DescriptorProto_ExtensionRange* add_extension_range(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >& + extension_range() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >* + mutable_extension_range(); + + // optional .google.protobuf.MessageOptions options = 7; + inline bool has_options() const; + inline void clear_options(); + static const int kOptionsFieldNumber = 7; + inline const ::google::protobuf::MessageOptions& options() const; + inline ::google::protobuf::MessageOptions* mutable_options(); + inline ::google::protobuf::MessageOptions* release_options(); + inline void set_allocated_options(::google::protobuf::MessageOptions* options); + + // @@protoc_insertion_point(class_scope:google.protobuf.DescriptorProto) + private: + inline void set_has_name(); + inline void clear_has_name(); + inline void set_has_options(); + inline void clear_has_options(); + + ::google::protobuf::UnknownFieldSet _unknown_fields_; + + ::std::string* name_; + ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto > field_; + ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto > extension_; + ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto > nested_type_; + ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto > enum_type_; + ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange > extension_range_; + ::google::protobuf::MessageOptions* options_; + + mutable int _cached_size_; + ::google::protobuf::uint32 _has_bits_[(7 + 31) / 32]; + + friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto(); + + void InitAsDefaultInstance(); + static DescriptorProto* default_instance_; +}; +// ------------------------------------------------------------------- + +class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Message { + public: + FieldDescriptorProto(); + virtual ~FieldDescriptorProto(); + + FieldDescriptorProto(const FieldDescriptorProto& from); + + inline FieldDescriptorProto& operator=(const FieldDescriptorProto& from) { + CopyFrom(from); + return *this; + } + + inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { + return _unknown_fields_; + } + + inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { + return &_unknown_fields_; + } + + static const ::google::protobuf::Descriptor* descriptor(); + static const FieldDescriptorProto& default_instance(); + + void Swap(FieldDescriptorProto* other); + + // implements Message ---------------------------------------------- + + FieldDescriptorProto* New() const; + void CopyFrom(const ::google::protobuf::Message& from); + void MergeFrom(const ::google::protobuf::Message& from); + void CopyFrom(const FieldDescriptorProto& from); + void MergeFrom(const FieldDescriptorProto& from); + void Clear(); + bool IsInitialized() const; + + int ByteSize() const; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input); + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const; + ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const; + int GetCachedSize() const { return _cached_size_; } + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + public: + + ::google::protobuf::Metadata GetMetadata() const; + + // nested types ---------------------------------------------------- + + typedef FieldDescriptorProto_Type Type; + static const Type TYPE_DOUBLE = FieldDescriptorProto_Type_TYPE_DOUBLE; + static const Type TYPE_FLOAT = FieldDescriptorProto_Type_TYPE_FLOAT; + static const Type TYPE_INT64 = FieldDescriptorProto_Type_TYPE_INT64; + static const Type TYPE_UINT64 = FieldDescriptorProto_Type_TYPE_UINT64; + static const Type TYPE_INT32 = FieldDescriptorProto_Type_TYPE_INT32; + static const Type TYPE_FIXED64 = FieldDescriptorProto_Type_TYPE_FIXED64; + static const Type TYPE_FIXED32 = FieldDescriptorProto_Type_TYPE_FIXED32; + static const Type TYPE_BOOL = FieldDescriptorProto_Type_TYPE_BOOL; + static const Type TYPE_STRING = FieldDescriptorProto_Type_TYPE_STRING; + static const Type TYPE_GROUP = FieldDescriptorProto_Type_TYPE_GROUP; + static const Type TYPE_MESSAGE = FieldDescriptorProto_Type_TYPE_MESSAGE; + static const Type TYPE_BYTES = FieldDescriptorProto_Type_TYPE_BYTES; + static const Type TYPE_UINT32 = FieldDescriptorProto_Type_TYPE_UINT32; + static const Type TYPE_ENUM = FieldDescriptorProto_Type_TYPE_ENUM; + static const Type TYPE_SFIXED32 = FieldDescriptorProto_Type_TYPE_SFIXED32; + static const Type TYPE_SFIXED64 = FieldDescriptorProto_Type_TYPE_SFIXED64; + static const Type TYPE_SINT32 = FieldDescriptorProto_Type_TYPE_SINT32; + static const Type TYPE_SINT64 = FieldDescriptorProto_Type_TYPE_SINT64; + static inline bool Type_IsValid(int value) { + return FieldDescriptorProto_Type_IsValid(value); + } + static const Type Type_MIN = + FieldDescriptorProto_Type_Type_MIN; + static const Type Type_MAX = + FieldDescriptorProto_Type_Type_MAX; + static const int Type_ARRAYSIZE = + FieldDescriptorProto_Type_Type_ARRAYSIZE; + static inline const ::google::protobuf::EnumDescriptor* + Type_descriptor() { + return FieldDescriptorProto_Type_descriptor(); + } + static inline const ::std::string& Type_Name(Type value) { + return FieldDescriptorProto_Type_Name(value); + } + static inline bool Type_Parse(const ::std::string& name, + Type* value) { + return FieldDescriptorProto_Type_Parse(name, value); + } + + typedef FieldDescriptorProto_Label Label; + static const Label LABEL_OPTIONAL = FieldDescriptorProto_Label_LABEL_OPTIONAL; + static const Label LABEL_REQUIRED = FieldDescriptorProto_Label_LABEL_REQUIRED; + static const Label LABEL_REPEATED = FieldDescriptorProto_Label_LABEL_REPEATED; + static inline bool Label_IsValid(int value) { + return FieldDescriptorProto_Label_IsValid(value); + } + static const Label Label_MIN = + FieldDescriptorProto_Label_Label_MIN; + static const Label Label_MAX = + FieldDescriptorProto_Label_Label_MAX; + static const int Label_ARRAYSIZE = + FieldDescriptorProto_Label_Label_ARRAYSIZE; + static inline const ::google::protobuf::EnumDescriptor* + Label_descriptor() { + return FieldDescriptorProto_Label_descriptor(); + } + static inline const ::std::string& Label_Name(Label value) { + return FieldDescriptorProto_Label_Name(value); + } + static inline bool Label_Parse(const ::std::string& name, + Label* value) { + return FieldDescriptorProto_Label_Parse(name, value); + } + + // accessors ------------------------------------------------------- + + // optional string name = 1; + inline bool has_name() const; + inline void clear_name(); + static const int kNameFieldNumber = 1; + inline const ::std::string& name() const; + inline void set_name(const ::std::string& value); + inline void set_name(const char* value); + inline void set_name(const char* value, size_t size); + inline ::std::string* mutable_name(); + inline ::std::string* release_name(); + inline void set_allocated_name(::std::string* name); + + // optional int32 number = 3; + inline bool has_number() const; + inline void clear_number(); + static const int kNumberFieldNumber = 3; + inline ::google::protobuf::int32 number() const; + inline void set_number(::google::protobuf::int32 value); + + // optional .google.protobuf.FieldDescriptorProto.Label label = 4; + inline bool has_label() const; + inline void clear_label(); + static const int kLabelFieldNumber = 4; + inline ::google::protobuf::FieldDescriptorProto_Label label() const; + inline void set_label(::google::protobuf::FieldDescriptorProto_Label value); + + // optional .google.protobuf.FieldDescriptorProto.Type type = 5; + inline bool has_type() const; + inline void clear_type(); + static const int kTypeFieldNumber = 5; + inline ::google::protobuf::FieldDescriptorProto_Type type() const; + inline void set_type(::google::protobuf::FieldDescriptorProto_Type value); + + // optional string type_name = 6; + inline bool has_type_name() const; + inline void clear_type_name(); + static const int kTypeNameFieldNumber = 6; + inline const ::std::string& type_name() const; + inline void set_type_name(const ::std::string& value); + inline void set_type_name(const char* value); + inline void set_type_name(const char* value, size_t size); + inline ::std::string* mutable_type_name(); + inline ::std::string* release_type_name(); + inline void set_allocated_type_name(::std::string* type_name); + + // optional string extendee = 2; + inline bool has_extendee() const; + inline void clear_extendee(); + static const int kExtendeeFieldNumber = 2; + inline const ::std::string& extendee() const; + inline void set_extendee(const ::std::string& value); + inline void set_extendee(const char* value); + inline void set_extendee(const char* value, size_t size); + inline ::std::string* mutable_extendee(); + inline ::std::string* release_extendee(); + inline void set_allocated_extendee(::std::string* extendee); + + // optional string default_value = 7; + inline bool has_default_value() const; + inline void clear_default_value(); + static const int kDefaultValueFieldNumber = 7; + inline const ::std::string& default_value() const; + inline void set_default_value(const ::std::string& value); + inline void set_default_value(const char* value); + inline void set_default_value(const char* value, size_t size); + inline ::std::string* mutable_default_value(); + inline ::std::string* release_default_value(); + inline void set_allocated_default_value(::std::string* default_value); + + // optional .google.protobuf.FieldOptions options = 8; + inline bool has_options() const; + inline void clear_options(); + static const int kOptionsFieldNumber = 8; + inline const ::google::protobuf::FieldOptions& options() const; + inline ::google::protobuf::FieldOptions* mutable_options(); + inline ::google::protobuf::FieldOptions* release_options(); + inline void set_allocated_options(::google::protobuf::FieldOptions* options); + + // @@protoc_insertion_point(class_scope:google.protobuf.FieldDescriptorProto) + private: + inline void set_has_name(); + inline void clear_has_name(); + inline void set_has_number(); + inline void clear_has_number(); + inline void set_has_label(); + inline void clear_has_label(); + inline void set_has_type(); + inline void clear_has_type(); + inline void set_has_type_name(); + inline void clear_has_type_name(); + inline void set_has_extendee(); + inline void clear_has_extendee(); + inline void set_has_default_value(); + inline void clear_has_default_value(); + inline void set_has_options(); + inline void clear_has_options(); + + ::google::protobuf::UnknownFieldSet _unknown_fields_; + + ::std::string* name_; + ::google::protobuf::int32 number_; + int label_; + ::std::string* type_name_; + ::std::string* extendee_; + ::std::string* default_value_; + ::google::protobuf::FieldOptions* options_; + int type_; + + mutable int _cached_size_; + ::google::protobuf::uint32 _has_bits_[(8 + 31) / 32]; + + friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto(); + + void InitAsDefaultInstance(); + static FieldDescriptorProto* default_instance_; +}; +// ------------------------------------------------------------------- + +class LIBPROTOBUF_EXPORT EnumDescriptorProto : public ::google::protobuf::Message { + public: + EnumDescriptorProto(); + virtual ~EnumDescriptorProto(); + + EnumDescriptorProto(const EnumDescriptorProto& from); + + inline EnumDescriptorProto& operator=(const EnumDescriptorProto& from) { + CopyFrom(from); + return *this; + } + + inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { + return _unknown_fields_; + } + + inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { + return &_unknown_fields_; + } + + static const ::google::protobuf::Descriptor* descriptor(); + static const EnumDescriptorProto& default_instance(); + + void Swap(EnumDescriptorProto* other); + + // implements Message ---------------------------------------------- + + EnumDescriptorProto* New() const; + void CopyFrom(const ::google::protobuf::Message& from); + void MergeFrom(const ::google::protobuf::Message& from); + void CopyFrom(const EnumDescriptorProto& from); + void MergeFrom(const EnumDescriptorProto& from); + void Clear(); + bool IsInitialized() const; + + int ByteSize() const; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input); + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const; + ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const; + int GetCachedSize() const { return _cached_size_; } + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + public: + + ::google::protobuf::Metadata GetMetadata() const; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + // optional string name = 1; + inline bool has_name() const; + inline void clear_name(); + static const int kNameFieldNumber = 1; + inline const ::std::string& name() const; + inline void set_name(const ::std::string& value); + inline void set_name(const char* value); + inline void set_name(const char* value, size_t size); + inline ::std::string* mutable_name(); + inline ::std::string* release_name(); + inline void set_allocated_name(::std::string* name); + + // repeated .google.protobuf.EnumValueDescriptorProto value = 2; + inline int value_size() const; + inline void clear_value(); + static const int kValueFieldNumber = 2; + inline const ::google::protobuf::EnumValueDescriptorProto& value(int index) const; + inline ::google::protobuf::EnumValueDescriptorProto* mutable_value(int index); + inline ::google::protobuf::EnumValueDescriptorProto* add_value(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >& + value() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >* + mutable_value(); + + // optional .google.protobuf.EnumOptions options = 3; + inline bool has_options() const; + inline void clear_options(); + static const int kOptionsFieldNumber = 3; + inline const ::google::protobuf::EnumOptions& options() const; + inline ::google::protobuf::EnumOptions* mutable_options(); + inline ::google::protobuf::EnumOptions* release_options(); + inline void set_allocated_options(::google::protobuf::EnumOptions* options); + + // @@protoc_insertion_point(class_scope:google.protobuf.EnumDescriptorProto) + private: + inline void set_has_name(); + inline void clear_has_name(); + inline void set_has_options(); + inline void clear_has_options(); + + ::google::protobuf::UnknownFieldSet _unknown_fields_; + + ::std::string* name_; + ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto > value_; + ::google::protobuf::EnumOptions* options_; + + mutable int _cached_size_; + ::google::protobuf::uint32 _has_bits_[(3 + 31) / 32]; + + friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto(); + + void InitAsDefaultInstance(); + static EnumDescriptorProto* default_instance_; +}; +// ------------------------------------------------------------------- + +class LIBPROTOBUF_EXPORT EnumValueDescriptorProto : public ::google::protobuf::Message { + public: + EnumValueDescriptorProto(); + virtual ~EnumValueDescriptorProto(); + + EnumValueDescriptorProto(const EnumValueDescriptorProto& from); + + inline EnumValueDescriptorProto& operator=(const EnumValueDescriptorProto& from) { + CopyFrom(from); + return *this; + } + + inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { + return _unknown_fields_; + } + + inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { + return &_unknown_fields_; + } + + static const ::google::protobuf::Descriptor* descriptor(); + static const EnumValueDescriptorProto& default_instance(); + + void Swap(EnumValueDescriptorProto* other); + + // implements Message ---------------------------------------------- + + EnumValueDescriptorProto* New() const; + void CopyFrom(const ::google::protobuf::Message& from); + void MergeFrom(const ::google::protobuf::Message& from); + void CopyFrom(const EnumValueDescriptorProto& from); + void MergeFrom(const EnumValueDescriptorProto& from); + void Clear(); + bool IsInitialized() const; + + int ByteSize() const; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input); + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const; + ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const; + int GetCachedSize() const { return _cached_size_; } + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + public: + + ::google::protobuf::Metadata GetMetadata() const; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + // optional string name = 1; + inline bool has_name() const; + inline void clear_name(); + static const int kNameFieldNumber = 1; + inline const ::std::string& name() const; + inline void set_name(const ::std::string& value); + inline void set_name(const char* value); + inline void set_name(const char* value, size_t size); + inline ::std::string* mutable_name(); + inline ::std::string* release_name(); + inline void set_allocated_name(::std::string* name); + + // optional int32 number = 2; + inline bool has_number() const; + inline void clear_number(); + static const int kNumberFieldNumber = 2; + inline ::google::protobuf::int32 number() const; + inline void set_number(::google::protobuf::int32 value); + + // optional .google.protobuf.EnumValueOptions options = 3; + inline bool has_options() const; + inline void clear_options(); + static const int kOptionsFieldNumber = 3; + inline const ::google::protobuf::EnumValueOptions& options() const; + inline ::google::protobuf::EnumValueOptions* mutable_options(); + inline ::google::protobuf::EnumValueOptions* release_options(); + inline void set_allocated_options(::google::protobuf::EnumValueOptions* options); + + // @@protoc_insertion_point(class_scope:google.protobuf.EnumValueDescriptorProto) + private: + inline void set_has_name(); + inline void clear_has_name(); + inline void set_has_number(); + inline void clear_has_number(); + inline void set_has_options(); + inline void clear_has_options(); + + ::google::protobuf::UnknownFieldSet _unknown_fields_; + + ::std::string* name_; + ::google::protobuf::EnumValueOptions* options_; + ::google::protobuf::int32 number_; + + mutable int _cached_size_; + ::google::protobuf::uint32 _has_bits_[(3 + 31) / 32]; + + friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto(); + + void InitAsDefaultInstance(); + static EnumValueDescriptorProto* default_instance_; +}; +// ------------------------------------------------------------------- + +class LIBPROTOBUF_EXPORT ServiceDescriptorProto : public ::google::protobuf::Message { + public: + ServiceDescriptorProto(); + virtual ~ServiceDescriptorProto(); + + ServiceDescriptorProto(const ServiceDescriptorProto& from); + + inline ServiceDescriptorProto& operator=(const ServiceDescriptorProto& from) { + CopyFrom(from); + return *this; + } + + inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { + return _unknown_fields_; + } + + inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { + return &_unknown_fields_; + } + + static const ::google::protobuf::Descriptor* descriptor(); + static const ServiceDescriptorProto& default_instance(); + + void Swap(ServiceDescriptorProto* other); + + // implements Message ---------------------------------------------- + + ServiceDescriptorProto* New() const; + void CopyFrom(const ::google::protobuf::Message& from); + void MergeFrom(const ::google::protobuf::Message& from); + void CopyFrom(const ServiceDescriptorProto& from); + void MergeFrom(const ServiceDescriptorProto& from); + void Clear(); + bool IsInitialized() const; + + int ByteSize() const; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input); + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const; + ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const; + int GetCachedSize() const { return _cached_size_; } + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + public: + + ::google::protobuf::Metadata GetMetadata() const; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + // optional string name = 1; + inline bool has_name() const; + inline void clear_name(); + static const int kNameFieldNumber = 1; + inline const ::std::string& name() const; + inline void set_name(const ::std::string& value); + inline void set_name(const char* value); + inline void set_name(const char* value, size_t size); + inline ::std::string* mutable_name(); + inline ::std::string* release_name(); + inline void set_allocated_name(::std::string* name); + + // repeated .google.protobuf.MethodDescriptorProto method = 2; + inline int method_size() const; + inline void clear_method(); + static const int kMethodFieldNumber = 2; + inline const ::google::protobuf::MethodDescriptorProto& method(int index) const; + inline ::google::protobuf::MethodDescriptorProto* mutable_method(int index); + inline ::google::protobuf::MethodDescriptorProto* add_method(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >& + method() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >* + mutable_method(); + + // optional .google.protobuf.ServiceOptions options = 3; + inline bool has_options() const; + inline void clear_options(); + static const int kOptionsFieldNumber = 3; + inline const ::google::protobuf::ServiceOptions& options() const; + inline ::google::protobuf::ServiceOptions* mutable_options(); + inline ::google::protobuf::ServiceOptions* release_options(); + inline void set_allocated_options(::google::protobuf::ServiceOptions* options); + + // @@protoc_insertion_point(class_scope:google.protobuf.ServiceDescriptorProto) + private: + inline void set_has_name(); + inline void clear_has_name(); + inline void set_has_options(); + inline void clear_has_options(); + + ::google::protobuf::UnknownFieldSet _unknown_fields_; + + ::std::string* name_; + ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto > method_; + ::google::protobuf::ServiceOptions* options_; + + mutable int _cached_size_; + ::google::protobuf::uint32 _has_bits_[(3 + 31) / 32]; + + friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto(); + + void InitAsDefaultInstance(); + static ServiceDescriptorProto* default_instance_; +}; +// ------------------------------------------------------------------- + +class LIBPROTOBUF_EXPORT MethodDescriptorProto : public ::google::protobuf::Message { + public: + MethodDescriptorProto(); + virtual ~MethodDescriptorProto(); + + MethodDescriptorProto(const MethodDescriptorProto& from); + + inline MethodDescriptorProto& operator=(const MethodDescriptorProto& from) { + CopyFrom(from); + return *this; + } + + inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { + return _unknown_fields_; + } + + inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { + return &_unknown_fields_; + } + + static const ::google::protobuf::Descriptor* descriptor(); + static const MethodDescriptorProto& default_instance(); + + void Swap(MethodDescriptorProto* other); + + // implements Message ---------------------------------------------- + + MethodDescriptorProto* New() const; + void CopyFrom(const ::google::protobuf::Message& from); + void MergeFrom(const ::google::protobuf::Message& from); + void CopyFrom(const MethodDescriptorProto& from); + void MergeFrom(const MethodDescriptorProto& from); + void Clear(); + bool IsInitialized() const; + + int ByteSize() const; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input); + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const; + ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const; + int GetCachedSize() const { return _cached_size_; } + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + public: + + ::google::protobuf::Metadata GetMetadata() const; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + // optional string name = 1; + inline bool has_name() const; + inline void clear_name(); + static const int kNameFieldNumber = 1; + inline const ::std::string& name() const; + inline void set_name(const ::std::string& value); + inline void set_name(const char* value); + inline void set_name(const char* value, size_t size); + inline ::std::string* mutable_name(); + inline ::std::string* release_name(); + inline void set_allocated_name(::std::string* name); + + // optional string input_type = 2; + inline bool has_input_type() const; + inline void clear_input_type(); + static const int kInputTypeFieldNumber = 2; + inline const ::std::string& input_type() const; + inline void set_input_type(const ::std::string& value); + inline void set_input_type(const char* value); + inline void set_input_type(const char* value, size_t size); + inline ::std::string* mutable_input_type(); + inline ::std::string* release_input_type(); + inline void set_allocated_input_type(::std::string* input_type); + + // optional string output_type = 3; + inline bool has_output_type() const; + inline void clear_output_type(); + static const int kOutputTypeFieldNumber = 3; + inline const ::std::string& output_type() const; + inline void set_output_type(const ::std::string& value); + inline void set_output_type(const char* value); + inline void set_output_type(const char* value, size_t size); + inline ::std::string* mutable_output_type(); + inline ::std::string* release_output_type(); + inline void set_allocated_output_type(::std::string* output_type); + + // optional .google.protobuf.MethodOptions options = 4; + inline bool has_options() const; + inline void clear_options(); + static const int kOptionsFieldNumber = 4; + inline const ::google::protobuf::MethodOptions& options() const; + inline ::google::protobuf::MethodOptions* mutable_options(); + inline ::google::protobuf::MethodOptions* release_options(); + inline void set_allocated_options(::google::protobuf::MethodOptions* options); + + // @@protoc_insertion_point(class_scope:google.protobuf.MethodDescriptorProto) + private: + inline void set_has_name(); + inline void clear_has_name(); + inline void set_has_input_type(); + inline void clear_has_input_type(); + inline void set_has_output_type(); + inline void clear_has_output_type(); + inline void set_has_options(); + inline void clear_has_options(); + + ::google::protobuf::UnknownFieldSet _unknown_fields_; + + ::std::string* name_; + ::std::string* input_type_; + ::std::string* output_type_; + ::google::protobuf::MethodOptions* options_; + + mutable int _cached_size_; + ::google::protobuf::uint32 _has_bits_[(4 + 31) / 32]; + + friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto(); + + void InitAsDefaultInstance(); + static MethodDescriptorProto* default_instance_; +}; +// ------------------------------------------------------------------- + +class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message { + public: + FileOptions(); + virtual ~FileOptions(); + + FileOptions(const FileOptions& from); + + inline FileOptions& operator=(const FileOptions& from) { + CopyFrom(from); + return *this; + } + + inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { + return _unknown_fields_; + } + + inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { + return &_unknown_fields_; + } + + static const ::google::protobuf::Descriptor* descriptor(); + static const FileOptions& default_instance(); + + void Swap(FileOptions* other); + + // implements Message ---------------------------------------------- + + FileOptions* New() const; + void CopyFrom(const ::google::protobuf::Message& from); + void MergeFrom(const ::google::protobuf::Message& from); + void CopyFrom(const FileOptions& from); + void MergeFrom(const FileOptions& from); + void Clear(); + bool IsInitialized() const; + + int ByteSize() const; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input); + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const; + ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const; + int GetCachedSize() const { return _cached_size_; } + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + public: + + ::google::protobuf::Metadata GetMetadata() const; + + // nested types ---------------------------------------------------- + + typedef FileOptions_OptimizeMode OptimizeMode; + static const OptimizeMode SPEED = FileOptions_OptimizeMode_SPEED; + static const OptimizeMode CODE_SIZE = FileOptions_OptimizeMode_CODE_SIZE; + static const OptimizeMode LITE_RUNTIME = FileOptions_OptimizeMode_LITE_RUNTIME; + static inline bool OptimizeMode_IsValid(int value) { + return FileOptions_OptimizeMode_IsValid(value); + } + static const OptimizeMode OptimizeMode_MIN = + FileOptions_OptimizeMode_OptimizeMode_MIN; + static const OptimizeMode OptimizeMode_MAX = + FileOptions_OptimizeMode_OptimizeMode_MAX; + static const int OptimizeMode_ARRAYSIZE = + FileOptions_OptimizeMode_OptimizeMode_ARRAYSIZE; + static inline const ::google::protobuf::EnumDescriptor* + OptimizeMode_descriptor() { + return FileOptions_OptimizeMode_descriptor(); + } + static inline const ::std::string& OptimizeMode_Name(OptimizeMode value) { + return FileOptions_OptimizeMode_Name(value); + } + static inline bool OptimizeMode_Parse(const ::std::string& name, + OptimizeMode* value) { + return FileOptions_OptimizeMode_Parse(name, value); + } + + // accessors ------------------------------------------------------- + + // optional string java_package = 1; + inline bool has_java_package() const; + inline void clear_java_package(); + static const int kJavaPackageFieldNumber = 1; + inline const ::std::string& java_package() const; + inline void set_java_package(const ::std::string& value); + inline void set_java_package(const char* value); + inline void set_java_package(const char* value, size_t size); + inline ::std::string* mutable_java_package(); + inline ::std::string* release_java_package(); + inline void set_allocated_java_package(::std::string* java_package); + + // optional string java_outer_classname = 8; + inline bool has_java_outer_classname() const; + inline void clear_java_outer_classname(); + static const int kJavaOuterClassnameFieldNumber = 8; + inline const ::std::string& java_outer_classname() const; + inline void set_java_outer_classname(const ::std::string& value); + inline void set_java_outer_classname(const char* value); + inline void set_java_outer_classname(const char* value, size_t size); + inline ::std::string* mutable_java_outer_classname(); + inline ::std::string* release_java_outer_classname(); + inline void set_allocated_java_outer_classname(::std::string* java_outer_classname); + + // optional bool java_multiple_files = 10 [default = false]; + inline bool has_java_multiple_files() const; + inline void clear_java_multiple_files(); + static const int kJavaMultipleFilesFieldNumber = 10; + inline bool java_multiple_files() const; + inline void set_java_multiple_files(bool value); + + // optional bool java_generate_equals_and_hash = 20 [default = false]; + inline bool has_java_generate_equals_and_hash() const; + inline void clear_java_generate_equals_and_hash(); + static const int kJavaGenerateEqualsAndHashFieldNumber = 20; + inline bool java_generate_equals_and_hash() const; + inline void set_java_generate_equals_and_hash(bool value); + + // optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED]; + inline bool has_optimize_for() const; + inline void clear_optimize_for(); + static const int kOptimizeForFieldNumber = 9; + inline ::google::protobuf::FileOptions_OptimizeMode optimize_for() const; + inline void set_optimize_for(::google::protobuf::FileOptions_OptimizeMode value); + + // optional string go_package = 11; + inline bool has_go_package() const; + inline void clear_go_package(); + static const int kGoPackageFieldNumber = 11; + inline const ::std::string& go_package() const; + inline void set_go_package(const ::std::string& value); + inline void set_go_package(const char* value); + inline void set_go_package(const char* value, size_t size); + inline ::std::string* mutable_go_package(); + inline ::std::string* release_go_package(); + inline void set_allocated_go_package(::std::string* go_package); + + // optional bool cc_generic_services = 16 [default = false]; + inline bool has_cc_generic_services() const; + inline void clear_cc_generic_services(); + static const int kCcGenericServicesFieldNumber = 16; + inline bool cc_generic_services() const; + inline void set_cc_generic_services(bool value); + + // optional bool java_generic_services = 17 [default = false]; + inline bool has_java_generic_services() const; + inline void clear_java_generic_services(); + static const int kJavaGenericServicesFieldNumber = 17; + inline bool java_generic_services() const; + inline void set_java_generic_services(bool value); + + // optional bool py_generic_services = 18 [default = false]; + inline bool has_py_generic_services() const; + inline void clear_py_generic_services(); + static const int kPyGenericServicesFieldNumber = 18; + inline bool py_generic_services() const; + inline void set_py_generic_services(bool value); + + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; + inline int uninterpreted_option_size() const; + inline void clear_uninterpreted_option(); + static const int kUninterpretedOptionFieldNumber = 999; + inline const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const; + inline ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index); + inline ::google::protobuf::UninterpretedOption* add_uninterpreted_option(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& + uninterpreted_option() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* + mutable_uninterpreted_option(); + + GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(FileOptions) + // @@protoc_insertion_point(class_scope:google.protobuf.FileOptions) + private: + inline void set_has_java_package(); + inline void clear_has_java_package(); + inline void set_has_java_outer_classname(); + inline void clear_has_java_outer_classname(); + inline void set_has_java_multiple_files(); + inline void clear_has_java_multiple_files(); + inline void set_has_java_generate_equals_and_hash(); + inline void clear_has_java_generate_equals_and_hash(); + inline void set_has_optimize_for(); + inline void clear_has_optimize_for(); + inline void set_has_go_package(); + inline void clear_has_go_package(); + inline void set_has_cc_generic_services(); + inline void clear_has_cc_generic_services(); + inline void set_has_java_generic_services(); + inline void clear_has_java_generic_services(); + inline void set_has_py_generic_services(); + inline void clear_has_py_generic_services(); + + ::google::protobuf::internal::ExtensionSet _extensions_; + + ::google::protobuf::UnknownFieldSet _unknown_fields_; + + ::std::string* java_package_; + ::std::string* java_outer_classname_; + int optimize_for_; + bool java_multiple_files_; + bool java_generate_equals_and_hash_; + bool cc_generic_services_; + bool java_generic_services_; + ::std::string* go_package_; + ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_; + bool py_generic_services_; + + mutable int _cached_size_; + ::google::protobuf::uint32 _has_bits_[(10 + 31) / 32]; + + friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto(); + + void InitAsDefaultInstance(); + static FileOptions* default_instance_; +}; +// ------------------------------------------------------------------- + +class LIBPROTOBUF_EXPORT MessageOptions : public ::google::protobuf::Message { + public: + MessageOptions(); + virtual ~MessageOptions(); + + MessageOptions(const MessageOptions& from); + + inline MessageOptions& operator=(const MessageOptions& from) { + CopyFrom(from); + return *this; + } + + inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { + return _unknown_fields_; + } + + inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { + return &_unknown_fields_; + } + + static const ::google::protobuf::Descriptor* descriptor(); + static const MessageOptions& default_instance(); + + void Swap(MessageOptions* other); + + // implements Message ---------------------------------------------- + + MessageOptions* New() const; + void CopyFrom(const ::google::protobuf::Message& from); + void MergeFrom(const ::google::protobuf::Message& from); + void CopyFrom(const MessageOptions& from); + void MergeFrom(const MessageOptions& from); + void Clear(); + bool IsInitialized() const; + + int ByteSize() const; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input); + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const; + ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const; + int GetCachedSize() const { return _cached_size_; } + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + public: + + ::google::protobuf::Metadata GetMetadata() const; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + // optional bool message_set_wire_format = 1 [default = false]; + inline bool has_message_set_wire_format() const; + inline void clear_message_set_wire_format(); + static const int kMessageSetWireFormatFieldNumber = 1; + inline bool message_set_wire_format() const; + inline void set_message_set_wire_format(bool value); + + // optional bool no_standard_descriptor_accessor = 2 [default = false]; + inline bool has_no_standard_descriptor_accessor() const; + inline void clear_no_standard_descriptor_accessor(); + static const int kNoStandardDescriptorAccessorFieldNumber = 2; + inline bool no_standard_descriptor_accessor() const; + inline void set_no_standard_descriptor_accessor(bool value); + + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; + inline int uninterpreted_option_size() const; + inline void clear_uninterpreted_option(); + static const int kUninterpretedOptionFieldNumber = 999; + inline const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const; + inline ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index); + inline ::google::protobuf::UninterpretedOption* add_uninterpreted_option(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& + uninterpreted_option() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* + mutable_uninterpreted_option(); + + GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(MessageOptions) + // @@protoc_insertion_point(class_scope:google.protobuf.MessageOptions) + private: + inline void set_has_message_set_wire_format(); + inline void clear_has_message_set_wire_format(); + inline void set_has_no_standard_descriptor_accessor(); + inline void clear_has_no_standard_descriptor_accessor(); + + ::google::protobuf::internal::ExtensionSet _extensions_; + + ::google::protobuf::UnknownFieldSet _unknown_fields_; + + ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_; + bool message_set_wire_format_; + bool no_standard_descriptor_accessor_; + + mutable int _cached_size_; + ::google::protobuf::uint32 _has_bits_[(3 + 31) / 32]; + + friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto(); + + void InitAsDefaultInstance(); + static MessageOptions* default_instance_; +}; +// ------------------------------------------------------------------- + +class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message { + public: + FieldOptions(); + virtual ~FieldOptions(); + + FieldOptions(const FieldOptions& from); + + inline FieldOptions& operator=(const FieldOptions& from) { + CopyFrom(from); + return *this; + } + + inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { + return _unknown_fields_; + } + + inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { + return &_unknown_fields_; + } + + static const ::google::protobuf::Descriptor* descriptor(); + static const FieldOptions& default_instance(); + + void Swap(FieldOptions* other); + + // implements Message ---------------------------------------------- + + FieldOptions* New() const; + void CopyFrom(const ::google::protobuf::Message& from); + void MergeFrom(const ::google::protobuf::Message& from); + void CopyFrom(const FieldOptions& from); + void MergeFrom(const FieldOptions& from); + void Clear(); + bool IsInitialized() const; + + int ByteSize() const; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input); + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const; + ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const; + int GetCachedSize() const { return _cached_size_; } + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + public: + + ::google::protobuf::Metadata GetMetadata() const; + + // nested types ---------------------------------------------------- + + typedef FieldOptions_CType CType; + static const CType STRING = FieldOptions_CType_STRING; + static const CType CORD = FieldOptions_CType_CORD; + static const CType STRING_PIECE = FieldOptions_CType_STRING_PIECE; + static inline bool CType_IsValid(int value) { + return FieldOptions_CType_IsValid(value); + } + static const CType CType_MIN = + FieldOptions_CType_CType_MIN; + static const CType CType_MAX = + FieldOptions_CType_CType_MAX; + static const int CType_ARRAYSIZE = + FieldOptions_CType_CType_ARRAYSIZE; + static inline const ::google::protobuf::EnumDescriptor* + CType_descriptor() { + return FieldOptions_CType_descriptor(); + } + static inline const ::std::string& CType_Name(CType value) { + return FieldOptions_CType_Name(value); + } + static inline bool CType_Parse(const ::std::string& name, + CType* value) { + return FieldOptions_CType_Parse(name, value); + } + + // accessors ------------------------------------------------------- + + // optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING]; + inline bool has_ctype() const; + inline void clear_ctype(); + static const int kCtypeFieldNumber = 1; + inline ::google::protobuf::FieldOptions_CType ctype() const; + inline void set_ctype(::google::protobuf::FieldOptions_CType value); + + // optional bool packed = 2; + inline bool has_packed() const; + inline void clear_packed(); + static const int kPackedFieldNumber = 2; + inline bool packed() const; + inline void set_packed(bool value); + + // optional bool lazy = 5 [default = false]; + inline bool has_lazy() const; + inline void clear_lazy(); + static const int kLazyFieldNumber = 5; + inline bool lazy() const; + inline void set_lazy(bool value); + + // optional bool deprecated = 3 [default = false]; + inline bool has_deprecated() const; + inline void clear_deprecated(); + static const int kDeprecatedFieldNumber = 3; + inline bool deprecated() const; + inline void set_deprecated(bool value); + + // optional string experimental_map_key = 9; + inline bool has_experimental_map_key() const; + inline void clear_experimental_map_key(); + static const int kExperimentalMapKeyFieldNumber = 9; + inline const ::std::string& experimental_map_key() const; + inline void set_experimental_map_key(const ::std::string& value); + inline void set_experimental_map_key(const char* value); + inline void set_experimental_map_key(const char* value, size_t size); + inline ::std::string* mutable_experimental_map_key(); + inline ::std::string* release_experimental_map_key(); + inline void set_allocated_experimental_map_key(::std::string* experimental_map_key); + + // optional bool weak = 10 [default = false]; + inline bool has_weak() const; + inline void clear_weak(); + static const int kWeakFieldNumber = 10; + inline bool weak() const; + inline void set_weak(bool value); + + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; + inline int uninterpreted_option_size() const; + inline void clear_uninterpreted_option(); + static const int kUninterpretedOptionFieldNumber = 999; + inline const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const; + inline ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index); + inline ::google::protobuf::UninterpretedOption* add_uninterpreted_option(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& + uninterpreted_option() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* + mutable_uninterpreted_option(); + + GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(FieldOptions) + // @@protoc_insertion_point(class_scope:google.protobuf.FieldOptions) + private: + inline void set_has_ctype(); + inline void clear_has_ctype(); + inline void set_has_packed(); + inline void clear_has_packed(); + inline void set_has_lazy(); + inline void clear_has_lazy(); + inline void set_has_deprecated(); + inline void clear_has_deprecated(); + inline void set_has_experimental_map_key(); + inline void clear_has_experimental_map_key(); + inline void set_has_weak(); + inline void clear_has_weak(); + + ::google::protobuf::internal::ExtensionSet _extensions_; + + ::google::protobuf::UnknownFieldSet _unknown_fields_; + + int ctype_; + bool packed_; + bool lazy_; + bool deprecated_; + bool weak_; + ::std::string* experimental_map_key_; + ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_; + + mutable int _cached_size_; + ::google::protobuf::uint32 _has_bits_[(7 + 31) / 32]; + + friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto(); + + void InitAsDefaultInstance(); + static FieldOptions* default_instance_; +}; +// ------------------------------------------------------------------- + +class LIBPROTOBUF_EXPORT EnumOptions : public ::google::protobuf::Message { + public: + EnumOptions(); + virtual ~EnumOptions(); + + EnumOptions(const EnumOptions& from); + + inline EnumOptions& operator=(const EnumOptions& from) { + CopyFrom(from); + return *this; + } + + inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { + return _unknown_fields_; + } + + inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { + return &_unknown_fields_; + } + + static const ::google::protobuf::Descriptor* descriptor(); + static const EnumOptions& default_instance(); + + void Swap(EnumOptions* other); + + // implements Message ---------------------------------------------- + + EnumOptions* New() const; + void CopyFrom(const ::google::protobuf::Message& from); + void MergeFrom(const ::google::protobuf::Message& from); + void CopyFrom(const EnumOptions& from); + void MergeFrom(const EnumOptions& from); + void Clear(); + bool IsInitialized() const; + + int ByteSize() const; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input); + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const; + ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const; + int GetCachedSize() const { return _cached_size_; } + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + public: + + ::google::protobuf::Metadata GetMetadata() const; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + // optional bool allow_alias = 2 [default = true]; + inline bool has_allow_alias() const; + inline void clear_allow_alias(); + static const int kAllowAliasFieldNumber = 2; + inline bool allow_alias() const; + inline void set_allow_alias(bool value); + + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; + inline int uninterpreted_option_size() const; + inline void clear_uninterpreted_option(); + static const int kUninterpretedOptionFieldNumber = 999; + inline const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const; + inline ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index); + inline ::google::protobuf::UninterpretedOption* add_uninterpreted_option(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& + uninterpreted_option() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* + mutable_uninterpreted_option(); + + GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(EnumOptions) + // @@protoc_insertion_point(class_scope:google.protobuf.EnumOptions) + private: + inline void set_has_allow_alias(); + inline void clear_has_allow_alias(); + + ::google::protobuf::internal::ExtensionSet _extensions_; + + ::google::protobuf::UnknownFieldSet _unknown_fields_; + + ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_; + bool allow_alias_; + + mutable int _cached_size_; + ::google::protobuf::uint32 _has_bits_[(2 + 31) / 32]; + + friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto(); + + void InitAsDefaultInstance(); + static EnumOptions* default_instance_; +}; +// ------------------------------------------------------------------- + +class LIBPROTOBUF_EXPORT EnumValueOptions : public ::google::protobuf::Message { + public: + EnumValueOptions(); + virtual ~EnumValueOptions(); + + EnumValueOptions(const EnumValueOptions& from); + + inline EnumValueOptions& operator=(const EnumValueOptions& from) { + CopyFrom(from); + return *this; + } + + inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { + return _unknown_fields_; + } + + inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { + return &_unknown_fields_; + } + + static const ::google::protobuf::Descriptor* descriptor(); + static const EnumValueOptions& default_instance(); + + void Swap(EnumValueOptions* other); + + // implements Message ---------------------------------------------- + + EnumValueOptions* New() const; + void CopyFrom(const ::google::protobuf::Message& from); + void MergeFrom(const ::google::protobuf::Message& from); + void CopyFrom(const EnumValueOptions& from); + void MergeFrom(const EnumValueOptions& from); + void Clear(); + bool IsInitialized() const; + + int ByteSize() const; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input); + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const; + ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const; + int GetCachedSize() const { return _cached_size_; } + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + public: + + ::google::protobuf::Metadata GetMetadata() const; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; + inline int uninterpreted_option_size() const; + inline void clear_uninterpreted_option(); + static const int kUninterpretedOptionFieldNumber = 999; + inline const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const; + inline ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index); + inline ::google::protobuf::UninterpretedOption* add_uninterpreted_option(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& + uninterpreted_option() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* + mutable_uninterpreted_option(); + + GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(EnumValueOptions) + // @@protoc_insertion_point(class_scope:google.protobuf.EnumValueOptions) + private: + + ::google::protobuf::internal::ExtensionSet _extensions_; + + ::google::protobuf::UnknownFieldSet _unknown_fields_; + + ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_; + + mutable int _cached_size_; + ::google::protobuf::uint32 _has_bits_[(1 + 31) / 32]; + + friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto(); + + void InitAsDefaultInstance(); + static EnumValueOptions* default_instance_; +}; +// ------------------------------------------------------------------- + +class LIBPROTOBUF_EXPORT ServiceOptions : public ::google::protobuf::Message { + public: + ServiceOptions(); + virtual ~ServiceOptions(); + + ServiceOptions(const ServiceOptions& from); + + inline ServiceOptions& operator=(const ServiceOptions& from) { + CopyFrom(from); + return *this; + } + + inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { + return _unknown_fields_; + } + + inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { + return &_unknown_fields_; + } + + static const ::google::protobuf::Descriptor* descriptor(); + static const ServiceOptions& default_instance(); + + void Swap(ServiceOptions* other); + + // implements Message ---------------------------------------------- + + ServiceOptions* New() const; + void CopyFrom(const ::google::protobuf::Message& from); + void MergeFrom(const ::google::protobuf::Message& from); + void CopyFrom(const ServiceOptions& from); + void MergeFrom(const ServiceOptions& from); + void Clear(); + bool IsInitialized() const; + + int ByteSize() const; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input); + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const; + ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const; + int GetCachedSize() const { return _cached_size_; } + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + public: + + ::google::protobuf::Metadata GetMetadata() const; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; + inline int uninterpreted_option_size() const; + inline void clear_uninterpreted_option(); + static const int kUninterpretedOptionFieldNumber = 999; + inline const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const; + inline ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index); + inline ::google::protobuf::UninterpretedOption* add_uninterpreted_option(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& + uninterpreted_option() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* + mutable_uninterpreted_option(); + + GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(ServiceOptions) + // @@protoc_insertion_point(class_scope:google.protobuf.ServiceOptions) + private: + + ::google::protobuf::internal::ExtensionSet _extensions_; + + ::google::protobuf::UnknownFieldSet _unknown_fields_; + + ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_; + + mutable int _cached_size_; + ::google::protobuf::uint32 _has_bits_[(1 + 31) / 32]; + + friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto(); + + void InitAsDefaultInstance(); + static ServiceOptions* default_instance_; +}; +// ------------------------------------------------------------------- + +class LIBPROTOBUF_EXPORT MethodOptions : public ::google::protobuf::Message { + public: + MethodOptions(); + virtual ~MethodOptions(); + + MethodOptions(const MethodOptions& from); + + inline MethodOptions& operator=(const MethodOptions& from) { + CopyFrom(from); + return *this; + } + + inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { + return _unknown_fields_; + } + + inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { + return &_unknown_fields_; + } + + static const ::google::protobuf::Descriptor* descriptor(); + static const MethodOptions& default_instance(); + + void Swap(MethodOptions* other); + + // implements Message ---------------------------------------------- + + MethodOptions* New() const; + void CopyFrom(const ::google::protobuf::Message& from); + void MergeFrom(const ::google::protobuf::Message& from); + void CopyFrom(const MethodOptions& from); + void MergeFrom(const MethodOptions& from); + void Clear(); + bool IsInitialized() const; + + int ByteSize() const; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input); + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const; + ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const; + int GetCachedSize() const { return _cached_size_; } + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + public: + + ::google::protobuf::Metadata GetMetadata() const; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; + inline int uninterpreted_option_size() const; + inline void clear_uninterpreted_option(); + static const int kUninterpretedOptionFieldNumber = 999; + inline const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const; + inline ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index); + inline ::google::protobuf::UninterpretedOption* add_uninterpreted_option(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& + uninterpreted_option() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* + mutable_uninterpreted_option(); + + GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(MethodOptions) + // @@protoc_insertion_point(class_scope:google.protobuf.MethodOptions) + private: + + ::google::protobuf::internal::ExtensionSet _extensions_; + + ::google::protobuf::UnknownFieldSet _unknown_fields_; + + ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_; + + mutable int _cached_size_; + ::google::protobuf::uint32 _has_bits_[(1 + 31) / 32]; + + friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto(); + + void InitAsDefaultInstance(); + static MethodOptions* default_instance_; +}; +// ------------------------------------------------------------------- + +class LIBPROTOBUF_EXPORT UninterpretedOption_NamePart : public ::google::protobuf::Message { + public: + UninterpretedOption_NamePart(); + virtual ~UninterpretedOption_NamePart(); + + UninterpretedOption_NamePart(const UninterpretedOption_NamePart& from); + + inline UninterpretedOption_NamePart& operator=(const UninterpretedOption_NamePart& from) { + CopyFrom(from); + return *this; + } + + inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { + return _unknown_fields_; + } + + inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { + return &_unknown_fields_; + } + + static const ::google::protobuf::Descriptor* descriptor(); + static const UninterpretedOption_NamePart& default_instance(); + + void Swap(UninterpretedOption_NamePart* other); + + // implements Message ---------------------------------------------- + + UninterpretedOption_NamePart* New() const; + void CopyFrom(const ::google::protobuf::Message& from); + void MergeFrom(const ::google::protobuf::Message& from); + void CopyFrom(const UninterpretedOption_NamePart& from); + void MergeFrom(const UninterpretedOption_NamePart& from); + void Clear(); + bool IsInitialized() const; + + int ByteSize() const; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input); + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const; + ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const; + int GetCachedSize() const { return _cached_size_; } + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + public: + + ::google::protobuf::Metadata GetMetadata() const; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + // required string name_part = 1; + inline bool has_name_part() const; + inline void clear_name_part(); + static const int kNamePartFieldNumber = 1; + inline const ::std::string& name_part() const; + inline void set_name_part(const ::std::string& value); + inline void set_name_part(const char* value); + inline void set_name_part(const char* value, size_t size); + inline ::std::string* mutable_name_part(); + inline ::std::string* release_name_part(); + inline void set_allocated_name_part(::std::string* name_part); + + // required bool is_extension = 2; + inline bool has_is_extension() const; + inline void clear_is_extension(); + static const int kIsExtensionFieldNumber = 2; + inline bool is_extension() const; + inline void set_is_extension(bool value); + + // @@protoc_insertion_point(class_scope:google.protobuf.UninterpretedOption.NamePart) + private: + inline void set_has_name_part(); + inline void clear_has_name_part(); + inline void set_has_is_extension(); + inline void clear_has_is_extension(); + + ::google::protobuf::UnknownFieldSet _unknown_fields_; + + ::std::string* name_part_; + bool is_extension_; + + mutable int _cached_size_; + ::google::protobuf::uint32 _has_bits_[(2 + 31) / 32]; + + friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto(); + + void InitAsDefaultInstance(); + static UninterpretedOption_NamePart* default_instance_; +}; +// ------------------------------------------------------------------- + +class LIBPROTOBUF_EXPORT UninterpretedOption : public ::google::protobuf::Message { + public: + UninterpretedOption(); + virtual ~UninterpretedOption(); + + UninterpretedOption(const UninterpretedOption& from); + + inline UninterpretedOption& operator=(const UninterpretedOption& from) { + CopyFrom(from); + return *this; + } + + inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { + return _unknown_fields_; + } + + inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { + return &_unknown_fields_; + } + + static const ::google::protobuf::Descriptor* descriptor(); + static const UninterpretedOption& default_instance(); + + void Swap(UninterpretedOption* other); + + // implements Message ---------------------------------------------- + + UninterpretedOption* New() const; + void CopyFrom(const ::google::protobuf::Message& from); + void MergeFrom(const ::google::protobuf::Message& from); + void CopyFrom(const UninterpretedOption& from); + void MergeFrom(const UninterpretedOption& from); + void Clear(); + bool IsInitialized() const; + + int ByteSize() const; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input); + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const; + ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const; + int GetCachedSize() const { return _cached_size_; } + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + public: + + ::google::protobuf::Metadata GetMetadata() const; + + // nested types ---------------------------------------------------- + + typedef UninterpretedOption_NamePart NamePart; + + // accessors ------------------------------------------------------- + + // repeated .google.protobuf.UninterpretedOption.NamePart name = 2; + inline int name_size() const; + inline void clear_name(); + static const int kNameFieldNumber = 2; + inline const ::google::protobuf::UninterpretedOption_NamePart& name(int index) const; + inline ::google::protobuf::UninterpretedOption_NamePart* mutable_name(int index); + inline ::google::protobuf::UninterpretedOption_NamePart* add_name(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >& + name() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >* + mutable_name(); + + // optional string identifier_value = 3; + inline bool has_identifier_value() const; + inline void clear_identifier_value(); + static const int kIdentifierValueFieldNumber = 3; + inline const ::std::string& identifier_value() const; + inline void set_identifier_value(const ::std::string& value); + inline void set_identifier_value(const char* value); + inline void set_identifier_value(const char* value, size_t size); + inline ::std::string* mutable_identifier_value(); + inline ::std::string* release_identifier_value(); + inline void set_allocated_identifier_value(::std::string* identifier_value); + + // optional uint64 positive_int_value = 4; + inline bool has_positive_int_value() const; + inline void clear_positive_int_value(); + static const int kPositiveIntValueFieldNumber = 4; + inline ::google::protobuf::uint64 positive_int_value() const; + inline void set_positive_int_value(::google::protobuf::uint64 value); + + // optional int64 negative_int_value = 5; + inline bool has_negative_int_value() const; + inline void clear_negative_int_value(); + static const int kNegativeIntValueFieldNumber = 5; + inline ::google::protobuf::int64 negative_int_value() const; + inline void set_negative_int_value(::google::protobuf::int64 value); + + // optional double double_value = 6; + inline bool has_double_value() const; + inline void clear_double_value(); + static const int kDoubleValueFieldNumber = 6; + inline double double_value() const; + inline void set_double_value(double value); + + // optional bytes string_value = 7; + inline bool has_string_value() const; + inline void clear_string_value(); + static const int kStringValueFieldNumber = 7; + inline const ::std::string& string_value() const; + inline void set_string_value(const ::std::string& value); + inline void set_string_value(const char* value); + inline void set_string_value(const void* value, size_t size); + inline ::std::string* mutable_string_value(); + inline ::std::string* release_string_value(); + inline void set_allocated_string_value(::std::string* string_value); + + // optional string aggregate_value = 8; + inline bool has_aggregate_value() const; + inline void clear_aggregate_value(); + static const int kAggregateValueFieldNumber = 8; + inline const ::std::string& aggregate_value() const; + inline void set_aggregate_value(const ::std::string& value); + inline void set_aggregate_value(const char* value); + inline void set_aggregate_value(const char* value, size_t size); + inline ::std::string* mutable_aggregate_value(); + inline ::std::string* release_aggregate_value(); + inline void set_allocated_aggregate_value(::std::string* aggregate_value); + + // @@protoc_insertion_point(class_scope:google.protobuf.UninterpretedOption) + private: + inline void set_has_identifier_value(); + inline void clear_has_identifier_value(); + inline void set_has_positive_int_value(); + inline void clear_has_positive_int_value(); + inline void set_has_negative_int_value(); + inline void clear_has_negative_int_value(); + inline void set_has_double_value(); + inline void clear_has_double_value(); + inline void set_has_string_value(); + inline void clear_has_string_value(); + inline void set_has_aggregate_value(); + inline void clear_has_aggregate_value(); + + ::google::protobuf::UnknownFieldSet _unknown_fields_; + + ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart > name_; + ::std::string* identifier_value_; + ::google::protobuf::uint64 positive_int_value_; + ::google::protobuf::int64 negative_int_value_; + double double_value_; + ::std::string* string_value_; + ::std::string* aggregate_value_; + + mutable int _cached_size_; + ::google::protobuf::uint32 _has_bits_[(7 + 31) / 32]; + + friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto(); + + void InitAsDefaultInstance(); + static UninterpretedOption* default_instance_; +}; +// ------------------------------------------------------------------- + +class LIBPROTOBUF_EXPORT SourceCodeInfo_Location : public ::google::protobuf::Message { + public: + SourceCodeInfo_Location(); + virtual ~SourceCodeInfo_Location(); + + SourceCodeInfo_Location(const SourceCodeInfo_Location& from); + + inline SourceCodeInfo_Location& operator=(const SourceCodeInfo_Location& from) { + CopyFrom(from); + return *this; + } + + inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { + return _unknown_fields_; + } + + inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { + return &_unknown_fields_; + } + + static const ::google::protobuf::Descriptor* descriptor(); + static const SourceCodeInfo_Location& default_instance(); + + void Swap(SourceCodeInfo_Location* other); + + // implements Message ---------------------------------------------- + + SourceCodeInfo_Location* New() const; + void CopyFrom(const ::google::protobuf::Message& from); + void MergeFrom(const ::google::protobuf::Message& from); + void CopyFrom(const SourceCodeInfo_Location& from); + void MergeFrom(const SourceCodeInfo_Location& from); + void Clear(); + bool IsInitialized() const; + + int ByteSize() const; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input); + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const; + ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const; + int GetCachedSize() const { return _cached_size_; } + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + public: + + ::google::protobuf::Metadata GetMetadata() const; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + // repeated int32 path = 1 [packed = true]; + inline int path_size() const; + inline void clear_path(); + static const int kPathFieldNumber = 1; + inline ::google::protobuf::int32 path(int index) const; + inline void set_path(int index, ::google::protobuf::int32 value); + inline void add_path(::google::protobuf::int32 value); + inline const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >& + path() const; + inline ::google::protobuf::RepeatedField< ::google::protobuf::int32 >* + mutable_path(); + + // repeated int32 span = 2 [packed = true]; + inline int span_size() const; + inline void clear_span(); + static const int kSpanFieldNumber = 2; + inline ::google::protobuf::int32 span(int index) const; + inline void set_span(int index, ::google::protobuf::int32 value); + inline void add_span(::google::protobuf::int32 value); + inline const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >& + span() const; + inline ::google::protobuf::RepeatedField< ::google::protobuf::int32 >* + mutable_span(); + + // optional string leading_comments = 3; + inline bool has_leading_comments() const; + inline void clear_leading_comments(); + static const int kLeadingCommentsFieldNumber = 3; + inline const ::std::string& leading_comments() const; + inline void set_leading_comments(const ::std::string& value); + inline void set_leading_comments(const char* value); + inline void set_leading_comments(const char* value, size_t size); + inline ::std::string* mutable_leading_comments(); + inline ::std::string* release_leading_comments(); + inline void set_allocated_leading_comments(::std::string* leading_comments); + + // optional string trailing_comments = 4; + inline bool has_trailing_comments() const; + inline void clear_trailing_comments(); + static const int kTrailingCommentsFieldNumber = 4; + inline const ::std::string& trailing_comments() const; + inline void set_trailing_comments(const ::std::string& value); + inline void set_trailing_comments(const char* value); + inline void set_trailing_comments(const char* value, size_t size); + inline ::std::string* mutable_trailing_comments(); + inline ::std::string* release_trailing_comments(); + inline void set_allocated_trailing_comments(::std::string* trailing_comments); + + // @@protoc_insertion_point(class_scope:google.protobuf.SourceCodeInfo.Location) + private: + inline void set_has_leading_comments(); + inline void clear_has_leading_comments(); + inline void set_has_trailing_comments(); + inline void clear_has_trailing_comments(); + + ::google::protobuf::UnknownFieldSet _unknown_fields_; + + ::google::protobuf::RepeatedField< ::google::protobuf::int32 > path_; + mutable int _path_cached_byte_size_; + ::google::protobuf::RepeatedField< ::google::protobuf::int32 > span_; + mutable int _span_cached_byte_size_; + ::std::string* leading_comments_; + ::std::string* trailing_comments_; + + mutable int _cached_size_; + ::google::protobuf::uint32 _has_bits_[(4 + 31) / 32]; + + friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto(); + + void InitAsDefaultInstance(); + static SourceCodeInfo_Location* default_instance_; +}; +// ------------------------------------------------------------------- + +class LIBPROTOBUF_EXPORT SourceCodeInfo : public ::google::protobuf::Message { + public: + SourceCodeInfo(); + virtual ~SourceCodeInfo(); + + SourceCodeInfo(const SourceCodeInfo& from); + + inline SourceCodeInfo& operator=(const SourceCodeInfo& from) { + CopyFrom(from); + return *this; + } + + inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { + return _unknown_fields_; + } + + inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { + return &_unknown_fields_; + } + + static const ::google::protobuf::Descriptor* descriptor(); + static const SourceCodeInfo& default_instance(); + + void Swap(SourceCodeInfo* other); + + // implements Message ---------------------------------------------- + + SourceCodeInfo* New() const; + void CopyFrom(const ::google::protobuf::Message& from); + void MergeFrom(const ::google::protobuf::Message& from); + void CopyFrom(const SourceCodeInfo& from); + void MergeFrom(const SourceCodeInfo& from); + void Clear(); + bool IsInitialized() const; + + int ByteSize() const; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input); + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const; + ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const; + int GetCachedSize() const { return _cached_size_; } + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + public: + + ::google::protobuf::Metadata GetMetadata() const; + + // nested types ---------------------------------------------------- + + typedef SourceCodeInfo_Location Location; + + // accessors ------------------------------------------------------- + + // repeated .google.protobuf.SourceCodeInfo.Location location = 1; + inline int location_size() const; + inline void clear_location(); + static const int kLocationFieldNumber = 1; + inline const ::google::protobuf::SourceCodeInfo_Location& location(int index) const; + inline ::google::protobuf::SourceCodeInfo_Location* mutable_location(int index); + inline ::google::protobuf::SourceCodeInfo_Location* add_location(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::SourceCodeInfo_Location >& + location() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::SourceCodeInfo_Location >* + mutable_location(); + + // @@protoc_insertion_point(class_scope:google.protobuf.SourceCodeInfo) + private: + + ::google::protobuf::UnknownFieldSet _unknown_fields_; + + ::google::protobuf::RepeatedPtrField< ::google::protobuf::SourceCodeInfo_Location > location_; + + mutable int _cached_size_; + ::google::protobuf::uint32 _has_bits_[(1 + 31) / 32]; + + friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto(); + + void InitAsDefaultInstance(); + static SourceCodeInfo* default_instance_; +}; +// =================================================================== + + +// =================================================================== + +// FileDescriptorSet + +// repeated .google.protobuf.FileDescriptorProto file = 1; +inline int FileDescriptorSet::file_size() const { + return file_.size(); +} +inline void FileDescriptorSet::clear_file() { + file_.Clear(); +} +inline const ::google::protobuf::FileDescriptorProto& FileDescriptorSet::file(int index) const { + return file_.Get(index); +} +inline ::google::protobuf::FileDescriptorProto* FileDescriptorSet::mutable_file(int index) { + return file_.Mutable(index); +} +inline ::google::protobuf::FileDescriptorProto* FileDescriptorSet::add_file() { + return file_.Add(); +} +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >& +FileDescriptorSet::file() const { + return file_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >* +FileDescriptorSet::mutable_file() { + return &file_; +} + +// ------------------------------------------------------------------- + +// FileDescriptorProto + +// optional string name = 1; +inline bool FileDescriptorProto::has_name() const { + return (_has_bits_[0] & 0x00000001u) != 0; +} +inline void FileDescriptorProto::set_has_name() { + _has_bits_[0] |= 0x00000001u; +} +inline void FileDescriptorProto::clear_has_name() { + _has_bits_[0] &= ~0x00000001u; +} +inline void FileDescriptorProto::clear_name() { + if (name_ != &::google::protobuf::internal::kEmptyString) { + name_->clear(); + } + clear_has_name(); +} +inline const ::std::string& FileDescriptorProto::name() const { + return *name_; +} +inline void FileDescriptorProto::set_name(const ::std::string& value) { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + name_->assign(value); +} +inline void FileDescriptorProto::set_name(const char* value) { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + name_->assign(value); +} +inline void FileDescriptorProto::set_name(const char* value, size_t size) { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + name_->assign(reinterpret_cast(value), size); +} +inline ::std::string* FileDescriptorProto::mutable_name() { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + return name_; +} +inline ::std::string* FileDescriptorProto::release_name() { + clear_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + return NULL; + } else { + ::std::string* temp = name_; + name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + return temp; + } +} +inline void FileDescriptorProto::set_allocated_name(::std::string* name) { + if (name_ != &::google::protobuf::internal::kEmptyString) { + delete name_; + } + if (name) { + set_has_name(); + name_ = name; + } else { + clear_has_name(); + name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + } +} + +// optional string package = 2; +inline bool FileDescriptorProto::has_package() const { + return (_has_bits_[0] & 0x00000002u) != 0; +} +inline void FileDescriptorProto::set_has_package() { + _has_bits_[0] |= 0x00000002u; +} +inline void FileDescriptorProto::clear_has_package() { + _has_bits_[0] &= ~0x00000002u; +} +inline void FileDescriptorProto::clear_package() { + if (package_ != &::google::protobuf::internal::kEmptyString) { + package_->clear(); + } + clear_has_package(); +} +inline const ::std::string& FileDescriptorProto::package() const { + return *package_; +} +inline void FileDescriptorProto::set_package(const ::std::string& value) { + set_has_package(); + if (package_ == &::google::protobuf::internal::kEmptyString) { + package_ = new ::std::string; + } + package_->assign(value); +} +inline void FileDescriptorProto::set_package(const char* value) { + set_has_package(); + if (package_ == &::google::protobuf::internal::kEmptyString) { + package_ = new ::std::string; + } + package_->assign(value); +} +inline void FileDescriptorProto::set_package(const char* value, size_t size) { + set_has_package(); + if (package_ == &::google::protobuf::internal::kEmptyString) { + package_ = new ::std::string; + } + package_->assign(reinterpret_cast(value), size); +} +inline ::std::string* FileDescriptorProto::mutable_package() { + set_has_package(); + if (package_ == &::google::protobuf::internal::kEmptyString) { + package_ = new ::std::string; + } + return package_; +} +inline ::std::string* FileDescriptorProto::release_package() { + clear_has_package(); + if (package_ == &::google::protobuf::internal::kEmptyString) { + return NULL; + } else { + ::std::string* temp = package_; + package_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + return temp; + } +} +inline void FileDescriptorProto::set_allocated_package(::std::string* package) { + if (package_ != &::google::protobuf::internal::kEmptyString) { + delete package_; + } + if (package) { + set_has_package(); + package_ = package; + } else { + clear_has_package(); + package_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + } +} + +// repeated string dependency = 3; +inline int FileDescriptorProto::dependency_size() const { + return dependency_.size(); +} +inline void FileDescriptorProto::clear_dependency() { + dependency_.Clear(); +} +inline const ::std::string& FileDescriptorProto::dependency(int index) const { + return dependency_.Get(index); +} +inline ::std::string* FileDescriptorProto::mutable_dependency(int index) { + return dependency_.Mutable(index); +} +inline void FileDescriptorProto::set_dependency(int index, const ::std::string& value) { + dependency_.Mutable(index)->assign(value); +} +inline void FileDescriptorProto::set_dependency(int index, const char* value) { + dependency_.Mutable(index)->assign(value); +} +inline void FileDescriptorProto::set_dependency(int index, const char* value, size_t size) { + dependency_.Mutable(index)->assign( + reinterpret_cast(value), size); +} +inline ::std::string* FileDescriptorProto::add_dependency() { + return dependency_.Add(); +} +inline void FileDescriptorProto::add_dependency(const ::std::string& value) { + dependency_.Add()->assign(value); +} +inline void FileDescriptorProto::add_dependency(const char* value) { + dependency_.Add()->assign(value); +} +inline void FileDescriptorProto::add_dependency(const char* value, size_t size) { + dependency_.Add()->assign(reinterpret_cast(value), size); +} +inline const ::google::protobuf::RepeatedPtrField< ::std::string>& +FileDescriptorProto::dependency() const { + return dependency_; +} +inline ::google::protobuf::RepeatedPtrField< ::std::string>* +FileDescriptorProto::mutable_dependency() { + return &dependency_; +} + +// repeated int32 public_dependency = 10; +inline int FileDescriptorProto::public_dependency_size() const { + return public_dependency_.size(); +} +inline void FileDescriptorProto::clear_public_dependency() { + public_dependency_.Clear(); +} +inline ::google::protobuf::int32 FileDescriptorProto::public_dependency(int index) const { + return public_dependency_.Get(index); +} +inline void FileDescriptorProto::set_public_dependency(int index, ::google::protobuf::int32 value) { + public_dependency_.Set(index, value); +} +inline void FileDescriptorProto::add_public_dependency(::google::protobuf::int32 value) { + public_dependency_.Add(value); +} +inline const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >& +FileDescriptorProto::public_dependency() const { + return public_dependency_; +} +inline ::google::protobuf::RepeatedField< ::google::protobuf::int32 >* +FileDescriptorProto::mutable_public_dependency() { + return &public_dependency_; +} + +// repeated int32 weak_dependency = 11; +inline int FileDescriptorProto::weak_dependency_size() const { + return weak_dependency_.size(); +} +inline void FileDescriptorProto::clear_weak_dependency() { + weak_dependency_.Clear(); +} +inline ::google::protobuf::int32 FileDescriptorProto::weak_dependency(int index) const { + return weak_dependency_.Get(index); +} +inline void FileDescriptorProto::set_weak_dependency(int index, ::google::protobuf::int32 value) { + weak_dependency_.Set(index, value); +} +inline void FileDescriptorProto::add_weak_dependency(::google::protobuf::int32 value) { + weak_dependency_.Add(value); +} +inline const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >& +FileDescriptorProto::weak_dependency() const { + return weak_dependency_; +} +inline ::google::protobuf::RepeatedField< ::google::protobuf::int32 >* +FileDescriptorProto::mutable_weak_dependency() { + return &weak_dependency_; +} + +// repeated .google.protobuf.DescriptorProto message_type = 4; +inline int FileDescriptorProto::message_type_size() const { + return message_type_.size(); +} +inline void FileDescriptorProto::clear_message_type() { + message_type_.Clear(); +} +inline const ::google::protobuf::DescriptorProto& FileDescriptorProto::message_type(int index) const { + return message_type_.Get(index); +} +inline ::google::protobuf::DescriptorProto* FileDescriptorProto::mutable_message_type(int index) { + return message_type_.Mutable(index); +} +inline ::google::protobuf::DescriptorProto* FileDescriptorProto::add_message_type() { + return message_type_.Add(); +} +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >& +FileDescriptorProto::message_type() const { + return message_type_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >* +FileDescriptorProto::mutable_message_type() { + return &message_type_; +} + +// repeated .google.protobuf.EnumDescriptorProto enum_type = 5; +inline int FileDescriptorProto::enum_type_size() const { + return enum_type_.size(); +} +inline void FileDescriptorProto::clear_enum_type() { + enum_type_.Clear(); +} +inline const ::google::protobuf::EnumDescriptorProto& FileDescriptorProto::enum_type(int index) const { + return enum_type_.Get(index); +} +inline ::google::protobuf::EnumDescriptorProto* FileDescriptorProto::mutable_enum_type(int index) { + return enum_type_.Mutable(index); +} +inline ::google::protobuf::EnumDescriptorProto* FileDescriptorProto::add_enum_type() { + return enum_type_.Add(); +} +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >& +FileDescriptorProto::enum_type() const { + return enum_type_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >* +FileDescriptorProto::mutable_enum_type() { + return &enum_type_; +} + +// repeated .google.protobuf.ServiceDescriptorProto service = 6; +inline int FileDescriptorProto::service_size() const { + return service_.size(); +} +inline void FileDescriptorProto::clear_service() { + service_.Clear(); +} +inline const ::google::protobuf::ServiceDescriptorProto& FileDescriptorProto::service(int index) const { + return service_.Get(index); +} +inline ::google::protobuf::ServiceDescriptorProto* FileDescriptorProto::mutable_service(int index) { + return service_.Mutable(index); +} +inline ::google::protobuf::ServiceDescriptorProto* FileDescriptorProto::add_service() { + return service_.Add(); +} +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >& +FileDescriptorProto::service() const { + return service_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >* +FileDescriptorProto::mutable_service() { + return &service_; +} + +// repeated .google.protobuf.FieldDescriptorProto extension = 7; +inline int FileDescriptorProto::extension_size() const { + return extension_.size(); +} +inline void FileDescriptorProto::clear_extension() { + extension_.Clear(); +} +inline const ::google::protobuf::FieldDescriptorProto& FileDescriptorProto::extension(int index) const { + return extension_.Get(index); +} +inline ::google::protobuf::FieldDescriptorProto* FileDescriptorProto::mutable_extension(int index) { + return extension_.Mutable(index); +} +inline ::google::protobuf::FieldDescriptorProto* FileDescriptorProto::add_extension() { + return extension_.Add(); +} +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& +FileDescriptorProto::extension() const { + return extension_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* +FileDescriptorProto::mutable_extension() { + return &extension_; +} + +// optional .google.protobuf.FileOptions options = 8; +inline bool FileDescriptorProto::has_options() const { + return (_has_bits_[0] & 0x00000200u) != 0; +} +inline void FileDescriptorProto::set_has_options() { + _has_bits_[0] |= 0x00000200u; +} +inline void FileDescriptorProto::clear_has_options() { + _has_bits_[0] &= ~0x00000200u; +} +inline void FileDescriptorProto::clear_options() { + if (options_ != NULL) options_->::google::protobuf::FileOptions::Clear(); + clear_has_options(); +} +inline const ::google::protobuf::FileOptions& FileDescriptorProto::options() const { + return options_ != NULL ? *options_ : *default_instance_->options_; +} +inline ::google::protobuf::FileOptions* FileDescriptorProto::mutable_options() { + set_has_options(); + if (options_ == NULL) options_ = new ::google::protobuf::FileOptions; + return options_; +} +inline ::google::protobuf::FileOptions* FileDescriptorProto::release_options() { + clear_has_options(); + ::google::protobuf::FileOptions* temp = options_; + options_ = NULL; + return temp; +} +inline void FileDescriptorProto::set_allocated_options(::google::protobuf::FileOptions* options) { + delete options_; + options_ = options; + if (options) { + set_has_options(); + } else { + clear_has_options(); + } +} + +// optional .google.protobuf.SourceCodeInfo source_code_info = 9; +inline bool FileDescriptorProto::has_source_code_info() const { + return (_has_bits_[0] & 0x00000400u) != 0; +} +inline void FileDescriptorProto::set_has_source_code_info() { + _has_bits_[0] |= 0x00000400u; +} +inline void FileDescriptorProto::clear_has_source_code_info() { + _has_bits_[0] &= ~0x00000400u; +} +inline void FileDescriptorProto::clear_source_code_info() { + if (source_code_info_ != NULL) source_code_info_->::google::protobuf::SourceCodeInfo::Clear(); + clear_has_source_code_info(); +} +inline const ::google::protobuf::SourceCodeInfo& FileDescriptorProto::source_code_info() const { + return source_code_info_ != NULL ? *source_code_info_ : *default_instance_->source_code_info_; +} +inline ::google::protobuf::SourceCodeInfo* FileDescriptorProto::mutable_source_code_info() { + set_has_source_code_info(); + if (source_code_info_ == NULL) source_code_info_ = new ::google::protobuf::SourceCodeInfo; + return source_code_info_; +} +inline ::google::protobuf::SourceCodeInfo* FileDescriptorProto::release_source_code_info() { + clear_has_source_code_info(); + ::google::protobuf::SourceCodeInfo* temp = source_code_info_; + source_code_info_ = NULL; + return temp; +} +inline void FileDescriptorProto::set_allocated_source_code_info(::google::protobuf::SourceCodeInfo* source_code_info) { + delete source_code_info_; + source_code_info_ = source_code_info; + if (source_code_info) { + set_has_source_code_info(); + } else { + clear_has_source_code_info(); + } +} + +// ------------------------------------------------------------------- + +// DescriptorProto_ExtensionRange + +// optional int32 start = 1; +inline bool DescriptorProto_ExtensionRange::has_start() const { + return (_has_bits_[0] & 0x00000001u) != 0; +} +inline void DescriptorProto_ExtensionRange::set_has_start() { + _has_bits_[0] |= 0x00000001u; +} +inline void DescriptorProto_ExtensionRange::clear_has_start() { + _has_bits_[0] &= ~0x00000001u; +} +inline void DescriptorProto_ExtensionRange::clear_start() { + start_ = 0; + clear_has_start(); +} +inline ::google::protobuf::int32 DescriptorProto_ExtensionRange::start() const { + return start_; +} +inline void DescriptorProto_ExtensionRange::set_start(::google::protobuf::int32 value) { + set_has_start(); + start_ = value; +} + +// optional int32 end = 2; +inline bool DescriptorProto_ExtensionRange::has_end() const { + return (_has_bits_[0] & 0x00000002u) != 0; +} +inline void DescriptorProto_ExtensionRange::set_has_end() { + _has_bits_[0] |= 0x00000002u; +} +inline void DescriptorProto_ExtensionRange::clear_has_end() { + _has_bits_[0] &= ~0x00000002u; +} +inline void DescriptorProto_ExtensionRange::clear_end() { + end_ = 0; + clear_has_end(); +} +inline ::google::protobuf::int32 DescriptorProto_ExtensionRange::end() const { + return end_; +} +inline void DescriptorProto_ExtensionRange::set_end(::google::protobuf::int32 value) { + set_has_end(); + end_ = value; +} + +// ------------------------------------------------------------------- + +// DescriptorProto + +// optional string name = 1; +inline bool DescriptorProto::has_name() const { + return (_has_bits_[0] & 0x00000001u) != 0; +} +inline void DescriptorProto::set_has_name() { + _has_bits_[0] |= 0x00000001u; +} +inline void DescriptorProto::clear_has_name() { + _has_bits_[0] &= ~0x00000001u; +} +inline void DescriptorProto::clear_name() { + if (name_ != &::google::protobuf::internal::kEmptyString) { + name_->clear(); + } + clear_has_name(); +} +inline const ::std::string& DescriptorProto::name() const { + return *name_; +} +inline void DescriptorProto::set_name(const ::std::string& value) { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + name_->assign(value); +} +inline void DescriptorProto::set_name(const char* value) { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + name_->assign(value); +} +inline void DescriptorProto::set_name(const char* value, size_t size) { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + name_->assign(reinterpret_cast(value), size); +} +inline ::std::string* DescriptorProto::mutable_name() { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + return name_; +} +inline ::std::string* DescriptorProto::release_name() { + clear_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + return NULL; + } else { + ::std::string* temp = name_; + name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + return temp; + } +} +inline void DescriptorProto::set_allocated_name(::std::string* name) { + if (name_ != &::google::protobuf::internal::kEmptyString) { + delete name_; + } + if (name) { + set_has_name(); + name_ = name; + } else { + clear_has_name(); + name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + } +} + +// repeated .google.protobuf.FieldDescriptorProto field = 2; +inline int DescriptorProto::field_size() const { + return field_.size(); +} +inline void DescriptorProto::clear_field() { + field_.Clear(); +} +inline const ::google::protobuf::FieldDescriptorProto& DescriptorProto::field(int index) const { + return field_.Get(index); +} +inline ::google::protobuf::FieldDescriptorProto* DescriptorProto::mutable_field(int index) { + return field_.Mutable(index); +} +inline ::google::protobuf::FieldDescriptorProto* DescriptorProto::add_field() { + return field_.Add(); +} +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& +DescriptorProto::field() const { + return field_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* +DescriptorProto::mutable_field() { + return &field_; +} + +// repeated .google.protobuf.FieldDescriptorProto extension = 6; +inline int DescriptorProto::extension_size() const { + return extension_.size(); +} +inline void DescriptorProto::clear_extension() { + extension_.Clear(); +} +inline const ::google::protobuf::FieldDescriptorProto& DescriptorProto::extension(int index) const { + return extension_.Get(index); +} +inline ::google::protobuf::FieldDescriptorProto* DescriptorProto::mutable_extension(int index) { + return extension_.Mutable(index); +} +inline ::google::protobuf::FieldDescriptorProto* DescriptorProto::add_extension() { + return extension_.Add(); +} +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& +DescriptorProto::extension() const { + return extension_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* +DescriptorProto::mutable_extension() { + return &extension_; +} + +// repeated .google.protobuf.DescriptorProto nested_type = 3; +inline int DescriptorProto::nested_type_size() const { + return nested_type_.size(); +} +inline void DescriptorProto::clear_nested_type() { + nested_type_.Clear(); +} +inline const ::google::protobuf::DescriptorProto& DescriptorProto::nested_type(int index) const { + return nested_type_.Get(index); +} +inline ::google::protobuf::DescriptorProto* DescriptorProto::mutable_nested_type(int index) { + return nested_type_.Mutable(index); +} +inline ::google::protobuf::DescriptorProto* DescriptorProto::add_nested_type() { + return nested_type_.Add(); +} +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >& +DescriptorProto::nested_type() const { + return nested_type_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >* +DescriptorProto::mutable_nested_type() { + return &nested_type_; +} + +// repeated .google.protobuf.EnumDescriptorProto enum_type = 4; +inline int DescriptorProto::enum_type_size() const { + return enum_type_.size(); +} +inline void DescriptorProto::clear_enum_type() { + enum_type_.Clear(); +} +inline const ::google::protobuf::EnumDescriptorProto& DescriptorProto::enum_type(int index) const { + return enum_type_.Get(index); +} +inline ::google::protobuf::EnumDescriptorProto* DescriptorProto::mutable_enum_type(int index) { + return enum_type_.Mutable(index); +} +inline ::google::protobuf::EnumDescriptorProto* DescriptorProto::add_enum_type() { + return enum_type_.Add(); +} +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >& +DescriptorProto::enum_type() const { + return enum_type_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >* +DescriptorProto::mutable_enum_type() { + return &enum_type_; +} + +// repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5; +inline int DescriptorProto::extension_range_size() const { + return extension_range_.size(); +} +inline void DescriptorProto::clear_extension_range() { + extension_range_.Clear(); +} +inline const ::google::protobuf::DescriptorProto_ExtensionRange& DescriptorProto::extension_range(int index) const { + return extension_range_.Get(index); +} +inline ::google::protobuf::DescriptorProto_ExtensionRange* DescriptorProto::mutable_extension_range(int index) { + return extension_range_.Mutable(index); +} +inline ::google::protobuf::DescriptorProto_ExtensionRange* DescriptorProto::add_extension_range() { + return extension_range_.Add(); +} +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >& +DescriptorProto::extension_range() const { + return extension_range_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >* +DescriptorProto::mutable_extension_range() { + return &extension_range_; +} + +// optional .google.protobuf.MessageOptions options = 7; +inline bool DescriptorProto::has_options() const { + return (_has_bits_[0] & 0x00000040u) != 0; +} +inline void DescriptorProto::set_has_options() { + _has_bits_[0] |= 0x00000040u; +} +inline void DescriptorProto::clear_has_options() { + _has_bits_[0] &= ~0x00000040u; +} +inline void DescriptorProto::clear_options() { + if (options_ != NULL) options_->::google::protobuf::MessageOptions::Clear(); + clear_has_options(); +} +inline const ::google::protobuf::MessageOptions& DescriptorProto::options() const { + return options_ != NULL ? *options_ : *default_instance_->options_; +} +inline ::google::protobuf::MessageOptions* DescriptorProto::mutable_options() { + set_has_options(); + if (options_ == NULL) options_ = new ::google::protobuf::MessageOptions; + return options_; +} +inline ::google::protobuf::MessageOptions* DescriptorProto::release_options() { + clear_has_options(); + ::google::protobuf::MessageOptions* temp = options_; + options_ = NULL; + return temp; +} +inline void DescriptorProto::set_allocated_options(::google::protobuf::MessageOptions* options) { + delete options_; + options_ = options; + if (options) { + set_has_options(); + } else { + clear_has_options(); + } +} + +// ------------------------------------------------------------------- + +// FieldDescriptorProto + +// optional string name = 1; +inline bool FieldDescriptorProto::has_name() const { + return (_has_bits_[0] & 0x00000001u) != 0; +} +inline void FieldDescriptorProto::set_has_name() { + _has_bits_[0] |= 0x00000001u; +} +inline void FieldDescriptorProto::clear_has_name() { + _has_bits_[0] &= ~0x00000001u; +} +inline void FieldDescriptorProto::clear_name() { + if (name_ != &::google::protobuf::internal::kEmptyString) { + name_->clear(); + } + clear_has_name(); +} +inline const ::std::string& FieldDescriptorProto::name() const { + return *name_; +} +inline void FieldDescriptorProto::set_name(const ::std::string& value) { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + name_->assign(value); +} +inline void FieldDescriptorProto::set_name(const char* value) { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + name_->assign(value); +} +inline void FieldDescriptorProto::set_name(const char* value, size_t size) { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + name_->assign(reinterpret_cast(value), size); +} +inline ::std::string* FieldDescriptorProto::mutable_name() { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + return name_; +} +inline ::std::string* FieldDescriptorProto::release_name() { + clear_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + return NULL; + } else { + ::std::string* temp = name_; + name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + return temp; + } +} +inline void FieldDescriptorProto::set_allocated_name(::std::string* name) { + if (name_ != &::google::protobuf::internal::kEmptyString) { + delete name_; + } + if (name) { + set_has_name(); + name_ = name; + } else { + clear_has_name(); + name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + } +} + +// optional int32 number = 3; +inline bool FieldDescriptorProto::has_number() const { + return (_has_bits_[0] & 0x00000002u) != 0; +} +inline void FieldDescriptorProto::set_has_number() { + _has_bits_[0] |= 0x00000002u; +} +inline void FieldDescriptorProto::clear_has_number() { + _has_bits_[0] &= ~0x00000002u; +} +inline void FieldDescriptorProto::clear_number() { + number_ = 0; + clear_has_number(); +} +inline ::google::protobuf::int32 FieldDescriptorProto::number() const { + return number_; +} +inline void FieldDescriptorProto::set_number(::google::protobuf::int32 value) { + set_has_number(); + number_ = value; +} + +// optional .google.protobuf.FieldDescriptorProto.Label label = 4; +inline bool FieldDescriptorProto::has_label() const { + return (_has_bits_[0] & 0x00000004u) != 0; +} +inline void FieldDescriptorProto::set_has_label() { + _has_bits_[0] |= 0x00000004u; +} +inline void FieldDescriptorProto::clear_has_label() { + _has_bits_[0] &= ~0x00000004u; +} +inline void FieldDescriptorProto::clear_label() { + label_ = 1; + clear_has_label(); +} +inline ::google::protobuf::FieldDescriptorProto_Label FieldDescriptorProto::label() const { + return static_cast< ::google::protobuf::FieldDescriptorProto_Label >(label_); +} +inline void FieldDescriptorProto::set_label(::google::protobuf::FieldDescriptorProto_Label value) { + assert(::google::protobuf::FieldDescriptorProto_Label_IsValid(value)); + set_has_label(); + label_ = value; +} + +// optional .google.protobuf.FieldDescriptorProto.Type type = 5; +inline bool FieldDescriptorProto::has_type() const { + return (_has_bits_[0] & 0x00000008u) != 0; +} +inline void FieldDescriptorProto::set_has_type() { + _has_bits_[0] |= 0x00000008u; +} +inline void FieldDescriptorProto::clear_has_type() { + _has_bits_[0] &= ~0x00000008u; +} +inline void FieldDescriptorProto::clear_type() { + type_ = 1; + clear_has_type(); +} +inline ::google::protobuf::FieldDescriptorProto_Type FieldDescriptorProto::type() const { + return static_cast< ::google::protobuf::FieldDescriptorProto_Type >(type_); +} +inline void FieldDescriptorProto::set_type(::google::protobuf::FieldDescriptorProto_Type value) { + assert(::google::protobuf::FieldDescriptorProto_Type_IsValid(value)); + set_has_type(); + type_ = value; +} + +// optional string type_name = 6; +inline bool FieldDescriptorProto::has_type_name() const { + return (_has_bits_[0] & 0x00000010u) != 0; +} +inline void FieldDescriptorProto::set_has_type_name() { + _has_bits_[0] |= 0x00000010u; +} +inline void FieldDescriptorProto::clear_has_type_name() { + _has_bits_[0] &= ~0x00000010u; +} +inline void FieldDescriptorProto::clear_type_name() { + if (type_name_ != &::google::protobuf::internal::kEmptyString) { + type_name_->clear(); + } + clear_has_type_name(); +} +inline const ::std::string& FieldDescriptorProto::type_name() const { + return *type_name_; +} +inline void FieldDescriptorProto::set_type_name(const ::std::string& value) { + set_has_type_name(); + if (type_name_ == &::google::protobuf::internal::kEmptyString) { + type_name_ = new ::std::string; + } + type_name_->assign(value); +} +inline void FieldDescriptorProto::set_type_name(const char* value) { + set_has_type_name(); + if (type_name_ == &::google::protobuf::internal::kEmptyString) { + type_name_ = new ::std::string; + } + type_name_->assign(value); +} +inline void FieldDescriptorProto::set_type_name(const char* value, size_t size) { + set_has_type_name(); + if (type_name_ == &::google::protobuf::internal::kEmptyString) { + type_name_ = new ::std::string; + } + type_name_->assign(reinterpret_cast(value), size); +} +inline ::std::string* FieldDescriptorProto::mutable_type_name() { + set_has_type_name(); + if (type_name_ == &::google::protobuf::internal::kEmptyString) { + type_name_ = new ::std::string; + } + return type_name_; +} +inline ::std::string* FieldDescriptorProto::release_type_name() { + clear_has_type_name(); + if (type_name_ == &::google::protobuf::internal::kEmptyString) { + return NULL; + } else { + ::std::string* temp = type_name_; + type_name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + return temp; + } +} +inline void FieldDescriptorProto::set_allocated_type_name(::std::string* type_name) { + if (type_name_ != &::google::protobuf::internal::kEmptyString) { + delete type_name_; + } + if (type_name) { + set_has_type_name(); + type_name_ = type_name; + } else { + clear_has_type_name(); + type_name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + } +} + +// optional string extendee = 2; +inline bool FieldDescriptorProto::has_extendee() const { + return (_has_bits_[0] & 0x00000020u) != 0; +} +inline void FieldDescriptorProto::set_has_extendee() { + _has_bits_[0] |= 0x00000020u; +} +inline void FieldDescriptorProto::clear_has_extendee() { + _has_bits_[0] &= ~0x00000020u; +} +inline void FieldDescriptorProto::clear_extendee() { + if (extendee_ != &::google::protobuf::internal::kEmptyString) { + extendee_->clear(); + } + clear_has_extendee(); +} +inline const ::std::string& FieldDescriptorProto::extendee() const { + return *extendee_; +} +inline void FieldDescriptorProto::set_extendee(const ::std::string& value) { + set_has_extendee(); + if (extendee_ == &::google::protobuf::internal::kEmptyString) { + extendee_ = new ::std::string; + } + extendee_->assign(value); +} +inline void FieldDescriptorProto::set_extendee(const char* value) { + set_has_extendee(); + if (extendee_ == &::google::protobuf::internal::kEmptyString) { + extendee_ = new ::std::string; + } + extendee_->assign(value); +} +inline void FieldDescriptorProto::set_extendee(const char* value, size_t size) { + set_has_extendee(); + if (extendee_ == &::google::protobuf::internal::kEmptyString) { + extendee_ = new ::std::string; + } + extendee_->assign(reinterpret_cast(value), size); +} +inline ::std::string* FieldDescriptorProto::mutable_extendee() { + set_has_extendee(); + if (extendee_ == &::google::protobuf::internal::kEmptyString) { + extendee_ = new ::std::string; + } + return extendee_; +} +inline ::std::string* FieldDescriptorProto::release_extendee() { + clear_has_extendee(); + if (extendee_ == &::google::protobuf::internal::kEmptyString) { + return NULL; + } else { + ::std::string* temp = extendee_; + extendee_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + return temp; + } +} +inline void FieldDescriptorProto::set_allocated_extendee(::std::string* extendee) { + if (extendee_ != &::google::protobuf::internal::kEmptyString) { + delete extendee_; + } + if (extendee) { + set_has_extendee(); + extendee_ = extendee; + } else { + clear_has_extendee(); + extendee_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + } +} + +// optional string default_value = 7; +inline bool FieldDescriptorProto::has_default_value() const { + return (_has_bits_[0] & 0x00000040u) != 0; +} +inline void FieldDescriptorProto::set_has_default_value() { + _has_bits_[0] |= 0x00000040u; +} +inline void FieldDescriptorProto::clear_has_default_value() { + _has_bits_[0] &= ~0x00000040u; +} +inline void FieldDescriptorProto::clear_default_value() { + if (default_value_ != &::google::protobuf::internal::kEmptyString) { + default_value_->clear(); + } + clear_has_default_value(); +} +inline const ::std::string& FieldDescriptorProto::default_value() const { + return *default_value_; +} +inline void FieldDescriptorProto::set_default_value(const ::std::string& value) { + set_has_default_value(); + if (default_value_ == &::google::protobuf::internal::kEmptyString) { + default_value_ = new ::std::string; + } + default_value_->assign(value); +} +inline void FieldDescriptorProto::set_default_value(const char* value) { + set_has_default_value(); + if (default_value_ == &::google::protobuf::internal::kEmptyString) { + default_value_ = new ::std::string; + } + default_value_->assign(value); +} +inline void FieldDescriptorProto::set_default_value(const char* value, size_t size) { + set_has_default_value(); + if (default_value_ == &::google::protobuf::internal::kEmptyString) { + default_value_ = new ::std::string; + } + default_value_->assign(reinterpret_cast(value), size); +} +inline ::std::string* FieldDescriptorProto::mutable_default_value() { + set_has_default_value(); + if (default_value_ == &::google::protobuf::internal::kEmptyString) { + default_value_ = new ::std::string; + } + return default_value_; +} +inline ::std::string* FieldDescriptorProto::release_default_value() { + clear_has_default_value(); + if (default_value_ == &::google::protobuf::internal::kEmptyString) { + return NULL; + } else { + ::std::string* temp = default_value_; + default_value_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + return temp; + } +} +inline void FieldDescriptorProto::set_allocated_default_value(::std::string* default_value) { + if (default_value_ != &::google::protobuf::internal::kEmptyString) { + delete default_value_; + } + if (default_value) { + set_has_default_value(); + default_value_ = default_value; + } else { + clear_has_default_value(); + default_value_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + } +} + +// optional .google.protobuf.FieldOptions options = 8; +inline bool FieldDescriptorProto::has_options() const { + return (_has_bits_[0] & 0x00000080u) != 0; +} +inline void FieldDescriptorProto::set_has_options() { + _has_bits_[0] |= 0x00000080u; +} +inline void FieldDescriptorProto::clear_has_options() { + _has_bits_[0] &= ~0x00000080u; +} +inline void FieldDescriptorProto::clear_options() { + if (options_ != NULL) options_->::google::protobuf::FieldOptions::Clear(); + clear_has_options(); +} +inline const ::google::protobuf::FieldOptions& FieldDescriptorProto::options() const { + return options_ != NULL ? *options_ : *default_instance_->options_; +} +inline ::google::protobuf::FieldOptions* FieldDescriptorProto::mutable_options() { + set_has_options(); + if (options_ == NULL) options_ = new ::google::protobuf::FieldOptions; + return options_; +} +inline ::google::protobuf::FieldOptions* FieldDescriptorProto::release_options() { + clear_has_options(); + ::google::protobuf::FieldOptions* temp = options_; + options_ = NULL; + return temp; +} +inline void FieldDescriptorProto::set_allocated_options(::google::protobuf::FieldOptions* options) { + delete options_; + options_ = options; + if (options) { + set_has_options(); + } else { + clear_has_options(); + } +} + +// ------------------------------------------------------------------- + +// EnumDescriptorProto + +// optional string name = 1; +inline bool EnumDescriptorProto::has_name() const { + return (_has_bits_[0] & 0x00000001u) != 0; +} +inline void EnumDescriptorProto::set_has_name() { + _has_bits_[0] |= 0x00000001u; +} +inline void EnumDescriptorProto::clear_has_name() { + _has_bits_[0] &= ~0x00000001u; +} +inline void EnumDescriptorProto::clear_name() { + if (name_ != &::google::protobuf::internal::kEmptyString) { + name_->clear(); + } + clear_has_name(); +} +inline const ::std::string& EnumDescriptorProto::name() const { + return *name_; +} +inline void EnumDescriptorProto::set_name(const ::std::string& value) { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + name_->assign(value); +} +inline void EnumDescriptorProto::set_name(const char* value) { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + name_->assign(value); +} +inline void EnumDescriptorProto::set_name(const char* value, size_t size) { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + name_->assign(reinterpret_cast(value), size); +} +inline ::std::string* EnumDescriptorProto::mutable_name() { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + return name_; +} +inline ::std::string* EnumDescriptorProto::release_name() { + clear_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + return NULL; + } else { + ::std::string* temp = name_; + name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + return temp; + } +} +inline void EnumDescriptorProto::set_allocated_name(::std::string* name) { + if (name_ != &::google::protobuf::internal::kEmptyString) { + delete name_; + } + if (name) { + set_has_name(); + name_ = name; + } else { + clear_has_name(); + name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + } +} + +// repeated .google.protobuf.EnumValueDescriptorProto value = 2; +inline int EnumDescriptorProto::value_size() const { + return value_.size(); +} +inline void EnumDescriptorProto::clear_value() { + value_.Clear(); +} +inline const ::google::protobuf::EnumValueDescriptorProto& EnumDescriptorProto::value(int index) const { + return value_.Get(index); +} +inline ::google::protobuf::EnumValueDescriptorProto* EnumDescriptorProto::mutable_value(int index) { + return value_.Mutable(index); +} +inline ::google::protobuf::EnumValueDescriptorProto* EnumDescriptorProto::add_value() { + return value_.Add(); +} +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >& +EnumDescriptorProto::value() const { + return value_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >* +EnumDescriptorProto::mutable_value() { + return &value_; +} + +// optional .google.protobuf.EnumOptions options = 3; +inline bool EnumDescriptorProto::has_options() const { + return (_has_bits_[0] & 0x00000004u) != 0; +} +inline void EnumDescriptorProto::set_has_options() { + _has_bits_[0] |= 0x00000004u; +} +inline void EnumDescriptorProto::clear_has_options() { + _has_bits_[0] &= ~0x00000004u; +} +inline void EnumDescriptorProto::clear_options() { + if (options_ != NULL) options_->::google::protobuf::EnumOptions::Clear(); + clear_has_options(); +} +inline const ::google::protobuf::EnumOptions& EnumDescriptorProto::options() const { + return options_ != NULL ? *options_ : *default_instance_->options_; +} +inline ::google::protobuf::EnumOptions* EnumDescriptorProto::mutable_options() { + set_has_options(); + if (options_ == NULL) options_ = new ::google::protobuf::EnumOptions; + return options_; +} +inline ::google::protobuf::EnumOptions* EnumDescriptorProto::release_options() { + clear_has_options(); + ::google::protobuf::EnumOptions* temp = options_; + options_ = NULL; + return temp; +} +inline void EnumDescriptorProto::set_allocated_options(::google::protobuf::EnumOptions* options) { + delete options_; + options_ = options; + if (options) { + set_has_options(); + } else { + clear_has_options(); + } +} + +// ------------------------------------------------------------------- + +// EnumValueDescriptorProto + +// optional string name = 1; +inline bool EnumValueDescriptorProto::has_name() const { + return (_has_bits_[0] & 0x00000001u) != 0; +} +inline void EnumValueDescriptorProto::set_has_name() { + _has_bits_[0] |= 0x00000001u; +} +inline void EnumValueDescriptorProto::clear_has_name() { + _has_bits_[0] &= ~0x00000001u; +} +inline void EnumValueDescriptorProto::clear_name() { + if (name_ != &::google::protobuf::internal::kEmptyString) { + name_->clear(); + } + clear_has_name(); +} +inline const ::std::string& EnumValueDescriptorProto::name() const { + return *name_; +} +inline void EnumValueDescriptorProto::set_name(const ::std::string& value) { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + name_->assign(value); +} +inline void EnumValueDescriptorProto::set_name(const char* value) { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + name_->assign(value); +} +inline void EnumValueDescriptorProto::set_name(const char* value, size_t size) { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + name_->assign(reinterpret_cast(value), size); +} +inline ::std::string* EnumValueDescriptorProto::mutable_name() { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + return name_; +} +inline ::std::string* EnumValueDescriptorProto::release_name() { + clear_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + return NULL; + } else { + ::std::string* temp = name_; + name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + return temp; + } +} +inline void EnumValueDescriptorProto::set_allocated_name(::std::string* name) { + if (name_ != &::google::protobuf::internal::kEmptyString) { + delete name_; + } + if (name) { + set_has_name(); + name_ = name; + } else { + clear_has_name(); + name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + } +} + +// optional int32 number = 2; +inline bool EnumValueDescriptorProto::has_number() const { + return (_has_bits_[0] & 0x00000002u) != 0; +} +inline void EnumValueDescriptorProto::set_has_number() { + _has_bits_[0] |= 0x00000002u; +} +inline void EnumValueDescriptorProto::clear_has_number() { + _has_bits_[0] &= ~0x00000002u; +} +inline void EnumValueDescriptorProto::clear_number() { + number_ = 0; + clear_has_number(); +} +inline ::google::protobuf::int32 EnumValueDescriptorProto::number() const { + return number_; +} +inline void EnumValueDescriptorProto::set_number(::google::protobuf::int32 value) { + set_has_number(); + number_ = value; +} + +// optional .google.protobuf.EnumValueOptions options = 3; +inline bool EnumValueDescriptorProto::has_options() const { + return (_has_bits_[0] & 0x00000004u) != 0; +} +inline void EnumValueDescriptorProto::set_has_options() { + _has_bits_[0] |= 0x00000004u; +} +inline void EnumValueDescriptorProto::clear_has_options() { + _has_bits_[0] &= ~0x00000004u; +} +inline void EnumValueDescriptorProto::clear_options() { + if (options_ != NULL) options_->::google::protobuf::EnumValueOptions::Clear(); + clear_has_options(); +} +inline const ::google::protobuf::EnumValueOptions& EnumValueDescriptorProto::options() const { + return options_ != NULL ? *options_ : *default_instance_->options_; +} +inline ::google::protobuf::EnumValueOptions* EnumValueDescriptorProto::mutable_options() { + set_has_options(); + if (options_ == NULL) options_ = new ::google::protobuf::EnumValueOptions; + return options_; +} +inline ::google::protobuf::EnumValueOptions* EnumValueDescriptorProto::release_options() { + clear_has_options(); + ::google::protobuf::EnumValueOptions* temp = options_; + options_ = NULL; + return temp; +} +inline void EnumValueDescriptorProto::set_allocated_options(::google::protobuf::EnumValueOptions* options) { + delete options_; + options_ = options; + if (options) { + set_has_options(); + } else { + clear_has_options(); + } +} + +// ------------------------------------------------------------------- + +// ServiceDescriptorProto + +// optional string name = 1; +inline bool ServiceDescriptorProto::has_name() const { + return (_has_bits_[0] & 0x00000001u) != 0; +} +inline void ServiceDescriptorProto::set_has_name() { + _has_bits_[0] |= 0x00000001u; +} +inline void ServiceDescriptorProto::clear_has_name() { + _has_bits_[0] &= ~0x00000001u; +} +inline void ServiceDescriptorProto::clear_name() { + if (name_ != &::google::protobuf::internal::kEmptyString) { + name_->clear(); + } + clear_has_name(); +} +inline const ::std::string& ServiceDescriptorProto::name() const { + return *name_; +} +inline void ServiceDescriptorProto::set_name(const ::std::string& value) { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + name_->assign(value); +} +inline void ServiceDescriptorProto::set_name(const char* value) { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + name_->assign(value); +} +inline void ServiceDescriptorProto::set_name(const char* value, size_t size) { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + name_->assign(reinterpret_cast(value), size); +} +inline ::std::string* ServiceDescriptorProto::mutable_name() { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + return name_; +} +inline ::std::string* ServiceDescriptorProto::release_name() { + clear_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + return NULL; + } else { + ::std::string* temp = name_; + name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + return temp; + } +} +inline void ServiceDescriptorProto::set_allocated_name(::std::string* name) { + if (name_ != &::google::protobuf::internal::kEmptyString) { + delete name_; + } + if (name) { + set_has_name(); + name_ = name; + } else { + clear_has_name(); + name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + } +} + +// repeated .google.protobuf.MethodDescriptorProto method = 2; +inline int ServiceDescriptorProto::method_size() const { + return method_.size(); +} +inline void ServiceDescriptorProto::clear_method() { + method_.Clear(); +} +inline const ::google::protobuf::MethodDescriptorProto& ServiceDescriptorProto::method(int index) const { + return method_.Get(index); +} +inline ::google::protobuf::MethodDescriptorProto* ServiceDescriptorProto::mutable_method(int index) { + return method_.Mutable(index); +} +inline ::google::protobuf::MethodDescriptorProto* ServiceDescriptorProto::add_method() { + return method_.Add(); +} +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >& +ServiceDescriptorProto::method() const { + return method_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >* +ServiceDescriptorProto::mutable_method() { + return &method_; +} + +// optional .google.protobuf.ServiceOptions options = 3; +inline bool ServiceDescriptorProto::has_options() const { + return (_has_bits_[0] & 0x00000004u) != 0; +} +inline void ServiceDescriptorProto::set_has_options() { + _has_bits_[0] |= 0x00000004u; +} +inline void ServiceDescriptorProto::clear_has_options() { + _has_bits_[0] &= ~0x00000004u; +} +inline void ServiceDescriptorProto::clear_options() { + if (options_ != NULL) options_->::google::protobuf::ServiceOptions::Clear(); + clear_has_options(); +} +inline const ::google::protobuf::ServiceOptions& ServiceDescriptorProto::options() const { + return options_ != NULL ? *options_ : *default_instance_->options_; +} +inline ::google::protobuf::ServiceOptions* ServiceDescriptorProto::mutable_options() { + set_has_options(); + if (options_ == NULL) options_ = new ::google::protobuf::ServiceOptions; + return options_; +} +inline ::google::protobuf::ServiceOptions* ServiceDescriptorProto::release_options() { + clear_has_options(); + ::google::protobuf::ServiceOptions* temp = options_; + options_ = NULL; + return temp; +} +inline void ServiceDescriptorProto::set_allocated_options(::google::protobuf::ServiceOptions* options) { + delete options_; + options_ = options; + if (options) { + set_has_options(); + } else { + clear_has_options(); + } +} + +// ------------------------------------------------------------------- + +// MethodDescriptorProto + +// optional string name = 1; +inline bool MethodDescriptorProto::has_name() const { + return (_has_bits_[0] & 0x00000001u) != 0; +} +inline void MethodDescriptorProto::set_has_name() { + _has_bits_[0] |= 0x00000001u; +} +inline void MethodDescriptorProto::clear_has_name() { + _has_bits_[0] &= ~0x00000001u; +} +inline void MethodDescriptorProto::clear_name() { + if (name_ != &::google::protobuf::internal::kEmptyString) { + name_->clear(); + } + clear_has_name(); +} +inline const ::std::string& MethodDescriptorProto::name() const { + return *name_; +} +inline void MethodDescriptorProto::set_name(const ::std::string& value) { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + name_->assign(value); +} +inline void MethodDescriptorProto::set_name(const char* value) { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + name_->assign(value); +} +inline void MethodDescriptorProto::set_name(const char* value, size_t size) { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + name_->assign(reinterpret_cast(value), size); +} +inline ::std::string* MethodDescriptorProto::mutable_name() { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + return name_; +} +inline ::std::string* MethodDescriptorProto::release_name() { + clear_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + return NULL; + } else { + ::std::string* temp = name_; + name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + return temp; + } +} +inline void MethodDescriptorProto::set_allocated_name(::std::string* name) { + if (name_ != &::google::protobuf::internal::kEmptyString) { + delete name_; + } + if (name) { + set_has_name(); + name_ = name; + } else { + clear_has_name(); + name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + } +} + +// optional string input_type = 2; +inline bool MethodDescriptorProto::has_input_type() const { + return (_has_bits_[0] & 0x00000002u) != 0; +} +inline void MethodDescriptorProto::set_has_input_type() { + _has_bits_[0] |= 0x00000002u; +} +inline void MethodDescriptorProto::clear_has_input_type() { + _has_bits_[0] &= ~0x00000002u; +} +inline void MethodDescriptorProto::clear_input_type() { + if (input_type_ != &::google::protobuf::internal::kEmptyString) { + input_type_->clear(); + } + clear_has_input_type(); +} +inline const ::std::string& MethodDescriptorProto::input_type() const { + return *input_type_; +} +inline void MethodDescriptorProto::set_input_type(const ::std::string& value) { + set_has_input_type(); + if (input_type_ == &::google::protobuf::internal::kEmptyString) { + input_type_ = new ::std::string; + } + input_type_->assign(value); +} +inline void MethodDescriptorProto::set_input_type(const char* value) { + set_has_input_type(); + if (input_type_ == &::google::protobuf::internal::kEmptyString) { + input_type_ = new ::std::string; + } + input_type_->assign(value); +} +inline void MethodDescriptorProto::set_input_type(const char* value, size_t size) { + set_has_input_type(); + if (input_type_ == &::google::protobuf::internal::kEmptyString) { + input_type_ = new ::std::string; + } + input_type_->assign(reinterpret_cast(value), size); +} +inline ::std::string* MethodDescriptorProto::mutable_input_type() { + set_has_input_type(); + if (input_type_ == &::google::protobuf::internal::kEmptyString) { + input_type_ = new ::std::string; + } + return input_type_; +} +inline ::std::string* MethodDescriptorProto::release_input_type() { + clear_has_input_type(); + if (input_type_ == &::google::protobuf::internal::kEmptyString) { + return NULL; + } else { + ::std::string* temp = input_type_; + input_type_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + return temp; + } +} +inline void MethodDescriptorProto::set_allocated_input_type(::std::string* input_type) { + if (input_type_ != &::google::protobuf::internal::kEmptyString) { + delete input_type_; + } + if (input_type) { + set_has_input_type(); + input_type_ = input_type; + } else { + clear_has_input_type(); + input_type_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + } +} + +// optional string output_type = 3; +inline bool MethodDescriptorProto::has_output_type() const { + return (_has_bits_[0] & 0x00000004u) != 0; +} +inline void MethodDescriptorProto::set_has_output_type() { + _has_bits_[0] |= 0x00000004u; +} +inline void MethodDescriptorProto::clear_has_output_type() { + _has_bits_[0] &= ~0x00000004u; +} +inline void MethodDescriptorProto::clear_output_type() { + if (output_type_ != &::google::protobuf::internal::kEmptyString) { + output_type_->clear(); + } + clear_has_output_type(); +} +inline const ::std::string& MethodDescriptorProto::output_type() const { + return *output_type_; +} +inline void MethodDescriptorProto::set_output_type(const ::std::string& value) { + set_has_output_type(); + if (output_type_ == &::google::protobuf::internal::kEmptyString) { + output_type_ = new ::std::string; + } + output_type_->assign(value); +} +inline void MethodDescriptorProto::set_output_type(const char* value) { + set_has_output_type(); + if (output_type_ == &::google::protobuf::internal::kEmptyString) { + output_type_ = new ::std::string; + } + output_type_->assign(value); +} +inline void MethodDescriptorProto::set_output_type(const char* value, size_t size) { + set_has_output_type(); + if (output_type_ == &::google::protobuf::internal::kEmptyString) { + output_type_ = new ::std::string; + } + output_type_->assign(reinterpret_cast(value), size); +} +inline ::std::string* MethodDescriptorProto::mutable_output_type() { + set_has_output_type(); + if (output_type_ == &::google::protobuf::internal::kEmptyString) { + output_type_ = new ::std::string; + } + return output_type_; +} +inline ::std::string* MethodDescriptorProto::release_output_type() { + clear_has_output_type(); + if (output_type_ == &::google::protobuf::internal::kEmptyString) { + return NULL; + } else { + ::std::string* temp = output_type_; + output_type_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + return temp; + } +} +inline void MethodDescriptorProto::set_allocated_output_type(::std::string* output_type) { + if (output_type_ != &::google::protobuf::internal::kEmptyString) { + delete output_type_; + } + if (output_type) { + set_has_output_type(); + output_type_ = output_type; + } else { + clear_has_output_type(); + output_type_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + } +} + +// optional .google.protobuf.MethodOptions options = 4; +inline bool MethodDescriptorProto::has_options() const { + return (_has_bits_[0] & 0x00000008u) != 0; +} +inline void MethodDescriptorProto::set_has_options() { + _has_bits_[0] |= 0x00000008u; +} +inline void MethodDescriptorProto::clear_has_options() { + _has_bits_[0] &= ~0x00000008u; +} +inline void MethodDescriptorProto::clear_options() { + if (options_ != NULL) options_->::google::protobuf::MethodOptions::Clear(); + clear_has_options(); +} +inline const ::google::protobuf::MethodOptions& MethodDescriptorProto::options() const { + return options_ != NULL ? *options_ : *default_instance_->options_; +} +inline ::google::protobuf::MethodOptions* MethodDescriptorProto::mutable_options() { + set_has_options(); + if (options_ == NULL) options_ = new ::google::protobuf::MethodOptions; + return options_; +} +inline ::google::protobuf::MethodOptions* MethodDescriptorProto::release_options() { + clear_has_options(); + ::google::protobuf::MethodOptions* temp = options_; + options_ = NULL; + return temp; +} +inline void MethodDescriptorProto::set_allocated_options(::google::protobuf::MethodOptions* options) { + delete options_; + options_ = options; + if (options) { + set_has_options(); + } else { + clear_has_options(); + } +} + +// ------------------------------------------------------------------- + +// FileOptions + +// optional string java_package = 1; +inline bool FileOptions::has_java_package() const { + return (_has_bits_[0] & 0x00000001u) != 0; +} +inline void FileOptions::set_has_java_package() { + _has_bits_[0] |= 0x00000001u; +} +inline void FileOptions::clear_has_java_package() { + _has_bits_[0] &= ~0x00000001u; +} +inline void FileOptions::clear_java_package() { + if (java_package_ != &::google::protobuf::internal::kEmptyString) { + java_package_->clear(); + } + clear_has_java_package(); +} +inline const ::std::string& FileOptions::java_package() const { + return *java_package_; +} +inline void FileOptions::set_java_package(const ::std::string& value) { + set_has_java_package(); + if (java_package_ == &::google::protobuf::internal::kEmptyString) { + java_package_ = new ::std::string; + } + java_package_->assign(value); +} +inline void FileOptions::set_java_package(const char* value) { + set_has_java_package(); + if (java_package_ == &::google::protobuf::internal::kEmptyString) { + java_package_ = new ::std::string; + } + java_package_->assign(value); +} +inline void FileOptions::set_java_package(const char* value, size_t size) { + set_has_java_package(); + if (java_package_ == &::google::protobuf::internal::kEmptyString) { + java_package_ = new ::std::string; + } + java_package_->assign(reinterpret_cast(value), size); +} +inline ::std::string* FileOptions::mutable_java_package() { + set_has_java_package(); + if (java_package_ == &::google::protobuf::internal::kEmptyString) { + java_package_ = new ::std::string; + } + return java_package_; +} +inline ::std::string* FileOptions::release_java_package() { + clear_has_java_package(); + if (java_package_ == &::google::protobuf::internal::kEmptyString) { + return NULL; + } else { + ::std::string* temp = java_package_; + java_package_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + return temp; + } +} +inline void FileOptions::set_allocated_java_package(::std::string* java_package) { + if (java_package_ != &::google::protobuf::internal::kEmptyString) { + delete java_package_; + } + if (java_package) { + set_has_java_package(); + java_package_ = java_package; + } else { + clear_has_java_package(); + java_package_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + } +} + +// optional string java_outer_classname = 8; +inline bool FileOptions::has_java_outer_classname() const { + return (_has_bits_[0] & 0x00000002u) != 0; +} +inline void FileOptions::set_has_java_outer_classname() { + _has_bits_[0] |= 0x00000002u; +} +inline void FileOptions::clear_has_java_outer_classname() { + _has_bits_[0] &= ~0x00000002u; +} +inline void FileOptions::clear_java_outer_classname() { + if (java_outer_classname_ != &::google::protobuf::internal::kEmptyString) { + java_outer_classname_->clear(); + } + clear_has_java_outer_classname(); +} +inline const ::std::string& FileOptions::java_outer_classname() const { + return *java_outer_classname_; +} +inline void FileOptions::set_java_outer_classname(const ::std::string& value) { + set_has_java_outer_classname(); + if (java_outer_classname_ == &::google::protobuf::internal::kEmptyString) { + java_outer_classname_ = new ::std::string; + } + java_outer_classname_->assign(value); +} +inline void FileOptions::set_java_outer_classname(const char* value) { + set_has_java_outer_classname(); + if (java_outer_classname_ == &::google::protobuf::internal::kEmptyString) { + java_outer_classname_ = new ::std::string; + } + java_outer_classname_->assign(value); +} +inline void FileOptions::set_java_outer_classname(const char* value, size_t size) { + set_has_java_outer_classname(); + if (java_outer_classname_ == &::google::protobuf::internal::kEmptyString) { + java_outer_classname_ = new ::std::string; + } + java_outer_classname_->assign(reinterpret_cast(value), size); +} +inline ::std::string* FileOptions::mutable_java_outer_classname() { + set_has_java_outer_classname(); + if (java_outer_classname_ == &::google::protobuf::internal::kEmptyString) { + java_outer_classname_ = new ::std::string; + } + return java_outer_classname_; +} +inline ::std::string* FileOptions::release_java_outer_classname() { + clear_has_java_outer_classname(); + if (java_outer_classname_ == &::google::protobuf::internal::kEmptyString) { + return NULL; + } else { + ::std::string* temp = java_outer_classname_; + java_outer_classname_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + return temp; + } +} +inline void FileOptions::set_allocated_java_outer_classname(::std::string* java_outer_classname) { + if (java_outer_classname_ != &::google::protobuf::internal::kEmptyString) { + delete java_outer_classname_; + } + if (java_outer_classname) { + set_has_java_outer_classname(); + java_outer_classname_ = java_outer_classname; + } else { + clear_has_java_outer_classname(); + java_outer_classname_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + } +} + +// optional bool java_multiple_files = 10 [default = false]; +inline bool FileOptions::has_java_multiple_files() const { + return (_has_bits_[0] & 0x00000004u) != 0; +} +inline void FileOptions::set_has_java_multiple_files() { + _has_bits_[0] |= 0x00000004u; +} +inline void FileOptions::clear_has_java_multiple_files() { + _has_bits_[0] &= ~0x00000004u; +} +inline void FileOptions::clear_java_multiple_files() { + java_multiple_files_ = false; + clear_has_java_multiple_files(); +} +inline bool FileOptions::java_multiple_files() const { + return java_multiple_files_; +} +inline void FileOptions::set_java_multiple_files(bool value) { + set_has_java_multiple_files(); + java_multiple_files_ = value; +} + +// optional bool java_generate_equals_and_hash = 20 [default = false]; +inline bool FileOptions::has_java_generate_equals_and_hash() const { + return (_has_bits_[0] & 0x00000008u) != 0; +} +inline void FileOptions::set_has_java_generate_equals_and_hash() { + _has_bits_[0] |= 0x00000008u; +} +inline void FileOptions::clear_has_java_generate_equals_and_hash() { + _has_bits_[0] &= ~0x00000008u; +} +inline void FileOptions::clear_java_generate_equals_and_hash() { + java_generate_equals_and_hash_ = false; + clear_has_java_generate_equals_and_hash(); +} +inline bool FileOptions::java_generate_equals_and_hash() const { + return java_generate_equals_and_hash_; +} +inline void FileOptions::set_java_generate_equals_and_hash(bool value) { + set_has_java_generate_equals_and_hash(); + java_generate_equals_and_hash_ = value; +} + +// optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED]; +inline bool FileOptions::has_optimize_for() const { + return (_has_bits_[0] & 0x00000010u) != 0; +} +inline void FileOptions::set_has_optimize_for() { + _has_bits_[0] |= 0x00000010u; +} +inline void FileOptions::clear_has_optimize_for() { + _has_bits_[0] &= ~0x00000010u; +} +inline void FileOptions::clear_optimize_for() { + optimize_for_ = 1; + clear_has_optimize_for(); +} +inline ::google::protobuf::FileOptions_OptimizeMode FileOptions::optimize_for() const { + return static_cast< ::google::protobuf::FileOptions_OptimizeMode >(optimize_for_); +} +inline void FileOptions::set_optimize_for(::google::protobuf::FileOptions_OptimizeMode value) { + assert(::google::protobuf::FileOptions_OptimizeMode_IsValid(value)); + set_has_optimize_for(); + optimize_for_ = value; +} + +// optional string go_package = 11; +inline bool FileOptions::has_go_package() const { + return (_has_bits_[0] & 0x00000020u) != 0; +} +inline void FileOptions::set_has_go_package() { + _has_bits_[0] |= 0x00000020u; +} +inline void FileOptions::clear_has_go_package() { + _has_bits_[0] &= ~0x00000020u; +} +inline void FileOptions::clear_go_package() { + if (go_package_ != &::google::protobuf::internal::kEmptyString) { + go_package_->clear(); + } + clear_has_go_package(); +} +inline const ::std::string& FileOptions::go_package() const { + return *go_package_; +} +inline void FileOptions::set_go_package(const ::std::string& value) { + set_has_go_package(); + if (go_package_ == &::google::protobuf::internal::kEmptyString) { + go_package_ = new ::std::string; + } + go_package_->assign(value); +} +inline void FileOptions::set_go_package(const char* value) { + set_has_go_package(); + if (go_package_ == &::google::protobuf::internal::kEmptyString) { + go_package_ = new ::std::string; + } + go_package_->assign(value); +} +inline void FileOptions::set_go_package(const char* value, size_t size) { + set_has_go_package(); + if (go_package_ == &::google::protobuf::internal::kEmptyString) { + go_package_ = new ::std::string; + } + go_package_->assign(reinterpret_cast(value), size); +} +inline ::std::string* FileOptions::mutable_go_package() { + set_has_go_package(); + if (go_package_ == &::google::protobuf::internal::kEmptyString) { + go_package_ = new ::std::string; + } + return go_package_; +} +inline ::std::string* FileOptions::release_go_package() { + clear_has_go_package(); + if (go_package_ == &::google::protobuf::internal::kEmptyString) { + return NULL; + } else { + ::std::string* temp = go_package_; + go_package_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + return temp; + } +} +inline void FileOptions::set_allocated_go_package(::std::string* go_package) { + if (go_package_ != &::google::protobuf::internal::kEmptyString) { + delete go_package_; + } + if (go_package) { + set_has_go_package(); + go_package_ = go_package; + } else { + clear_has_go_package(); + go_package_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + } +} + +// optional bool cc_generic_services = 16 [default = false]; +inline bool FileOptions::has_cc_generic_services() const { + return (_has_bits_[0] & 0x00000040u) != 0; +} +inline void FileOptions::set_has_cc_generic_services() { + _has_bits_[0] |= 0x00000040u; +} +inline void FileOptions::clear_has_cc_generic_services() { + _has_bits_[0] &= ~0x00000040u; +} +inline void FileOptions::clear_cc_generic_services() { + cc_generic_services_ = false; + clear_has_cc_generic_services(); +} +inline bool FileOptions::cc_generic_services() const { + return cc_generic_services_; +} +inline void FileOptions::set_cc_generic_services(bool value) { + set_has_cc_generic_services(); + cc_generic_services_ = value; +} + +// optional bool java_generic_services = 17 [default = false]; +inline bool FileOptions::has_java_generic_services() const { + return (_has_bits_[0] & 0x00000080u) != 0; +} +inline void FileOptions::set_has_java_generic_services() { + _has_bits_[0] |= 0x00000080u; +} +inline void FileOptions::clear_has_java_generic_services() { + _has_bits_[0] &= ~0x00000080u; +} +inline void FileOptions::clear_java_generic_services() { + java_generic_services_ = false; + clear_has_java_generic_services(); +} +inline bool FileOptions::java_generic_services() const { + return java_generic_services_; +} +inline void FileOptions::set_java_generic_services(bool value) { + set_has_java_generic_services(); + java_generic_services_ = value; +} + +// optional bool py_generic_services = 18 [default = false]; +inline bool FileOptions::has_py_generic_services() const { + return (_has_bits_[0] & 0x00000100u) != 0; +} +inline void FileOptions::set_has_py_generic_services() { + _has_bits_[0] |= 0x00000100u; +} +inline void FileOptions::clear_has_py_generic_services() { + _has_bits_[0] &= ~0x00000100u; +} +inline void FileOptions::clear_py_generic_services() { + py_generic_services_ = false; + clear_has_py_generic_services(); +} +inline bool FileOptions::py_generic_services() const { + return py_generic_services_; +} +inline void FileOptions::set_py_generic_services(bool value) { + set_has_py_generic_services(); + py_generic_services_ = value; +} + +// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; +inline int FileOptions::uninterpreted_option_size() const { + return uninterpreted_option_.size(); +} +inline void FileOptions::clear_uninterpreted_option() { + uninterpreted_option_.Clear(); +} +inline const ::google::protobuf::UninterpretedOption& FileOptions::uninterpreted_option(int index) const { + return uninterpreted_option_.Get(index); +} +inline ::google::protobuf::UninterpretedOption* FileOptions::mutable_uninterpreted_option(int index) { + return uninterpreted_option_.Mutable(index); +} +inline ::google::protobuf::UninterpretedOption* FileOptions::add_uninterpreted_option() { + return uninterpreted_option_.Add(); +} +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& +FileOptions::uninterpreted_option() const { + return uninterpreted_option_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* +FileOptions::mutable_uninterpreted_option() { + return &uninterpreted_option_; +} + +// ------------------------------------------------------------------- + +// MessageOptions + +// optional bool message_set_wire_format = 1 [default = false]; +inline bool MessageOptions::has_message_set_wire_format() const { + return (_has_bits_[0] & 0x00000001u) != 0; +} +inline void MessageOptions::set_has_message_set_wire_format() { + _has_bits_[0] |= 0x00000001u; +} +inline void MessageOptions::clear_has_message_set_wire_format() { + _has_bits_[0] &= ~0x00000001u; +} +inline void MessageOptions::clear_message_set_wire_format() { + message_set_wire_format_ = false; + clear_has_message_set_wire_format(); +} +inline bool MessageOptions::message_set_wire_format() const { + return message_set_wire_format_; +} +inline void MessageOptions::set_message_set_wire_format(bool value) { + set_has_message_set_wire_format(); + message_set_wire_format_ = value; +} + +// optional bool no_standard_descriptor_accessor = 2 [default = false]; +inline bool MessageOptions::has_no_standard_descriptor_accessor() const { + return (_has_bits_[0] & 0x00000002u) != 0; +} +inline void MessageOptions::set_has_no_standard_descriptor_accessor() { + _has_bits_[0] |= 0x00000002u; +} +inline void MessageOptions::clear_has_no_standard_descriptor_accessor() { + _has_bits_[0] &= ~0x00000002u; +} +inline void MessageOptions::clear_no_standard_descriptor_accessor() { + no_standard_descriptor_accessor_ = false; + clear_has_no_standard_descriptor_accessor(); +} +inline bool MessageOptions::no_standard_descriptor_accessor() const { + return no_standard_descriptor_accessor_; +} +inline void MessageOptions::set_no_standard_descriptor_accessor(bool value) { + set_has_no_standard_descriptor_accessor(); + no_standard_descriptor_accessor_ = value; +} + +// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; +inline int MessageOptions::uninterpreted_option_size() const { + return uninterpreted_option_.size(); +} +inline void MessageOptions::clear_uninterpreted_option() { + uninterpreted_option_.Clear(); +} +inline const ::google::protobuf::UninterpretedOption& MessageOptions::uninterpreted_option(int index) const { + return uninterpreted_option_.Get(index); +} +inline ::google::protobuf::UninterpretedOption* MessageOptions::mutable_uninterpreted_option(int index) { + return uninterpreted_option_.Mutable(index); +} +inline ::google::protobuf::UninterpretedOption* MessageOptions::add_uninterpreted_option() { + return uninterpreted_option_.Add(); +} +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& +MessageOptions::uninterpreted_option() const { + return uninterpreted_option_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* +MessageOptions::mutable_uninterpreted_option() { + return &uninterpreted_option_; +} + +// ------------------------------------------------------------------- + +// FieldOptions + +// optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING]; +inline bool FieldOptions::has_ctype() const { + return (_has_bits_[0] & 0x00000001u) != 0; +} +inline void FieldOptions::set_has_ctype() { + _has_bits_[0] |= 0x00000001u; +} +inline void FieldOptions::clear_has_ctype() { + _has_bits_[0] &= ~0x00000001u; +} +inline void FieldOptions::clear_ctype() { + ctype_ = 0; + clear_has_ctype(); +} +inline ::google::protobuf::FieldOptions_CType FieldOptions::ctype() const { + return static_cast< ::google::protobuf::FieldOptions_CType >(ctype_); +} +inline void FieldOptions::set_ctype(::google::protobuf::FieldOptions_CType value) { + assert(::google::protobuf::FieldOptions_CType_IsValid(value)); + set_has_ctype(); + ctype_ = value; +} + +// optional bool packed = 2; +inline bool FieldOptions::has_packed() const { + return (_has_bits_[0] & 0x00000002u) != 0; +} +inline void FieldOptions::set_has_packed() { + _has_bits_[0] |= 0x00000002u; +} +inline void FieldOptions::clear_has_packed() { + _has_bits_[0] &= ~0x00000002u; +} +inline void FieldOptions::clear_packed() { + packed_ = false; + clear_has_packed(); +} +inline bool FieldOptions::packed() const { + return packed_; +} +inline void FieldOptions::set_packed(bool value) { + set_has_packed(); + packed_ = value; +} + +// optional bool lazy = 5 [default = false]; +inline bool FieldOptions::has_lazy() const { + return (_has_bits_[0] & 0x00000004u) != 0; +} +inline void FieldOptions::set_has_lazy() { + _has_bits_[0] |= 0x00000004u; +} +inline void FieldOptions::clear_has_lazy() { + _has_bits_[0] &= ~0x00000004u; +} +inline void FieldOptions::clear_lazy() { + lazy_ = false; + clear_has_lazy(); +} +inline bool FieldOptions::lazy() const { + return lazy_; +} +inline void FieldOptions::set_lazy(bool value) { + set_has_lazy(); + lazy_ = value; +} + +// optional bool deprecated = 3 [default = false]; +inline bool FieldOptions::has_deprecated() const { + return (_has_bits_[0] & 0x00000008u) != 0; +} +inline void FieldOptions::set_has_deprecated() { + _has_bits_[0] |= 0x00000008u; +} +inline void FieldOptions::clear_has_deprecated() { + _has_bits_[0] &= ~0x00000008u; +} +inline void FieldOptions::clear_deprecated() { + deprecated_ = false; + clear_has_deprecated(); +} +inline bool FieldOptions::deprecated() const { + return deprecated_; +} +inline void FieldOptions::set_deprecated(bool value) { + set_has_deprecated(); + deprecated_ = value; +} + +// optional string experimental_map_key = 9; +inline bool FieldOptions::has_experimental_map_key() const { + return (_has_bits_[0] & 0x00000010u) != 0; +} +inline void FieldOptions::set_has_experimental_map_key() { + _has_bits_[0] |= 0x00000010u; +} +inline void FieldOptions::clear_has_experimental_map_key() { + _has_bits_[0] &= ~0x00000010u; +} +inline void FieldOptions::clear_experimental_map_key() { + if (experimental_map_key_ != &::google::protobuf::internal::kEmptyString) { + experimental_map_key_->clear(); + } + clear_has_experimental_map_key(); +} +inline const ::std::string& FieldOptions::experimental_map_key() const { + return *experimental_map_key_; +} +inline void FieldOptions::set_experimental_map_key(const ::std::string& value) { + set_has_experimental_map_key(); + if (experimental_map_key_ == &::google::protobuf::internal::kEmptyString) { + experimental_map_key_ = new ::std::string; + } + experimental_map_key_->assign(value); +} +inline void FieldOptions::set_experimental_map_key(const char* value) { + set_has_experimental_map_key(); + if (experimental_map_key_ == &::google::protobuf::internal::kEmptyString) { + experimental_map_key_ = new ::std::string; + } + experimental_map_key_->assign(value); +} +inline void FieldOptions::set_experimental_map_key(const char* value, size_t size) { + set_has_experimental_map_key(); + if (experimental_map_key_ == &::google::protobuf::internal::kEmptyString) { + experimental_map_key_ = new ::std::string; + } + experimental_map_key_->assign(reinterpret_cast(value), size); +} +inline ::std::string* FieldOptions::mutable_experimental_map_key() { + set_has_experimental_map_key(); + if (experimental_map_key_ == &::google::protobuf::internal::kEmptyString) { + experimental_map_key_ = new ::std::string; + } + return experimental_map_key_; +} +inline ::std::string* FieldOptions::release_experimental_map_key() { + clear_has_experimental_map_key(); + if (experimental_map_key_ == &::google::protobuf::internal::kEmptyString) { + return NULL; + } else { + ::std::string* temp = experimental_map_key_; + experimental_map_key_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + return temp; + } +} +inline void FieldOptions::set_allocated_experimental_map_key(::std::string* experimental_map_key) { + if (experimental_map_key_ != &::google::protobuf::internal::kEmptyString) { + delete experimental_map_key_; + } + if (experimental_map_key) { + set_has_experimental_map_key(); + experimental_map_key_ = experimental_map_key; + } else { + clear_has_experimental_map_key(); + experimental_map_key_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + } +} + +// optional bool weak = 10 [default = false]; +inline bool FieldOptions::has_weak() const { + return (_has_bits_[0] & 0x00000020u) != 0; +} +inline void FieldOptions::set_has_weak() { + _has_bits_[0] |= 0x00000020u; +} +inline void FieldOptions::clear_has_weak() { + _has_bits_[0] &= ~0x00000020u; +} +inline void FieldOptions::clear_weak() { + weak_ = false; + clear_has_weak(); +} +inline bool FieldOptions::weak() const { + return weak_; +} +inline void FieldOptions::set_weak(bool value) { + set_has_weak(); + weak_ = value; +} + +// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; +inline int FieldOptions::uninterpreted_option_size() const { + return uninterpreted_option_.size(); +} +inline void FieldOptions::clear_uninterpreted_option() { + uninterpreted_option_.Clear(); +} +inline const ::google::protobuf::UninterpretedOption& FieldOptions::uninterpreted_option(int index) const { + return uninterpreted_option_.Get(index); +} +inline ::google::protobuf::UninterpretedOption* FieldOptions::mutable_uninterpreted_option(int index) { + return uninterpreted_option_.Mutable(index); +} +inline ::google::protobuf::UninterpretedOption* FieldOptions::add_uninterpreted_option() { + return uninterpreted_option_.Add(); +} +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& +FieldOptions::uninterpreted_option() const { + return uninterpreted_option_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* +FieldOptions::mutable_uninterpreted_option() { + return &uninterpreted_option_; +} + +// ------------------------------------------------------------------- + +// EnumOptions + +// optional bool allow_alias = 2 [default = true]; +inline bool EnumOptions::has_allow_alias() const { + return (_has_bits_[0] & 0x00000001u) != 0; +} +inline void EnumOptions::set_has_allow_alias() { + _has_bits_[0] |= 0x00000001u; +} +inline void EnumOptions::clear_has_allow_alias() { + _has_bits_[0] &= ~0x00000001u; +} +inline void EnumOptions::clear_allow_alias() { + allow_alias_ = true; + clear_has_allow_alias(); +} +inline bool EnumOptions::allow_alias() const { + return allow_alias_; +} +inline void EnumOptions::set_allow_alias(bool value) { + set_has_allow_alias(); + allow_alias_ = value; +} + +// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; +inline int EnumOptions::uninterpreted_option_size() const { + return uninterpreted_option_.size(); +} +inline void EnumOptions::clear_uninterpreted_option() { + uninterpreted_option_.Clear(); +} +inline const ::google::protobuf::UninterpretedOption& EnumOptions::uninterpreted_option(int index) const { + return uninterpreted_option_.Get(index); +} +inline ::google::protobuf::UninterpretedOption* EnumOptions::mutable_uninterpreted_option(int index) { + return uninterpreted_option_.Mutable(index); +} +inline ::google::protobuf::UninterpretedOption* EnumOptions::add_uninterpreted_option() { + return uninterpreted_option_.Add(); +} +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& +EnumOptions::uninterpreted_option() const { + return uninterpreted_option_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* +EnumOptions::mutable_uninterpreted_option() { + return &uninterpreted_option_; +} + +// ------------------------------------------------------------------- + +// EnumValueOptions + +// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; +inline int EnumValueOptions::uninterpreted_option_size() const { + return uninterpreted_option_.size(); +} +inline void EnumValueOptions::clear_uninterpreted_option() { + uninterpreted_option_.Clear(); +} +inline const ::google::protobuf::UninterpretedOption& EnumValueOptions::uninterpreted_option(int index) const { + return uninterpreted_option_.Get(index); +} +inline ::google::protobuf::UninterpretedOption* EnumValueOptions::mutable_uninterpreted_option(int index) { + return uninterpreted_option_.Mutable(index); +} +inline ::google::protobuf::UninterpretedOption* EnumValueOptions::add_uninterpreted_option() { + return uninterpreted_option_.Add(); +} +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& +EnumValueOptions::uninterpreted_option() const { + return uninterpreted_option_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* +EnumValueOptions::mutable_uninterpreted_option() { + return &uninterpreted_option_; +} + +// ------------------------------------------------------------------- + +// ServiceOptions + +// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; +inline int ServiceOptions::uninterpreted_option_size() const { + return uninterpreted_option_.size(); +} +inline void ServiceOptions::clear_uninterpreted_option() { + uninterpreted_option_.Clear(); +} +inline const ::google::protobuf::UninterpretedOption& ServiceOptions::uninterpreted_option(int index) const { + return uninterpreted_option_.Get(index); +} +inline ::google::protobuf::UninterpretedOption* ServiceOptions::mutable_uninterpreted_option(int index) { + return uninterpreted_option_.Mutable(index); +} +inline ::google::protobuf::UninterpretedOption* ServiceOptions::add_uninterpreted_option() { + return uninterpreted_option_.Add(); +} +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& +ServiceOptions::uninterpreted_option() const { + return uninterpreted_option_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* +ServiceOptions::mutable_uninterpreted_option() { + return &uninterpreted_option_; +} + +// ------------------------------------------------------------------- + +// MethodOptions + +// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; +inline int MethodOptions::uninterpreted_option_size() const { + return uninterpreted_option_.size(); +} +inline void MethodOptions::clear_uninterpreted_option() { + uninterpreted_option_.Clear(); +} +inline const ::google::protobuf::UninterpretedOption& MethodOptions::uninterpreted_option(int index) const { + return uninterpreted_option_.Get(index); +} +inline ::google::protobuf::UninterpretedOption* MethodOptions::mutable_uninterpreted_option(int index) { + return uninterpreted_option_.Mutable(index); +} +inline ::google::protobuf::UninterpretedOption* MethodOptions::add_uninterpreted_option() { + return uninterpreted_option_.Add(); +} +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& +MethodOptions::uninterpreted_option() const { + return uninterpreted_option_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* +MethodOptions::mutable_uninterpreted_option() { + return &uninterpreted_option_; +} + +// ------------------------------------------------------------------- + +// UninterpretedOption_NamePart + +// required string name_part = 1; +inline bool UninterpretedOption_NamePart::has_name_part() const { + return (_has_bits_[0] & 0x00000001u) != 0; +} +inline void UninterpretedOption_NamePart::set_has_name_part() { + _has_bits_[0] |= 0x00000001u; +} +inline void UninterpretedOption_NamePart::clear_has_name_part() { + _has_bits_[0] &= ~0x00000001u; +} +inline void UninterpretedOption_NamePart::clear_name_part() { + if (name_part_ != &::google::protobuf::internal::kEmptyString) { + name_part_->clear(); + } + clear_has_name_part(); +} +inline const ::std::string& UninterpretedOption_NamePart::name_part() const { + return *name_part_; +} +inline void UninterpretedOption_NamePart::set_name_part(const ::std::string& value) { + set_has_name_part(); + if (name_part_ == &::google::protobuf::internal::kEmptyString) { + name_part_ = new ::std::string; + } + name_part_->assign(value); +} +inline void UninterpretedOption_NamePart::set_name_part(const char* value) { + set_has_name_part(); + if (name_part_ == &::google::protobuf::internal::kEmptyString) { + name_part_ = new ::std::string; + } + name_part_->assign(value); +} +inline void UninterpretedOption_NamePart::set_name_part(const char* value, size_t size) { + set_has_name_part(); + if (name_part_ == &::google::protobuf::internal::kEmptyString) { + name_part_ = new ::std::string; + } + name_part_->assign(reinterpret_cast(value), size); +} +inline ::std::string* UninterpretedOption_NamePart::mutable_name_part() { + set_has_name_part(); + if (name_part_ == &::google::protobuf::internal::kEmptyString) { + name_part_ = new ::std::string; + } + return name_part_; +} +inline ::std::string* UninterpretedOption_NamePart::release_name_part() { + clear_has_name_part(); + if (name_part_ == &::google::protobuf::internal::kEmptyString) { + return NULL; + } else { + ::std::string* temp = name_part_; + name_part_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + return temp; + } +} +inline void UninterpretedOption_NamePart::set_allocated_name_part(::std::string* name_part) { + if (name_part_ != &::google::protobuf::internal::kEmptyString) { + delete name_part_; + } + if (name_part) { + set_has_name_part(); + name_part_ = name_part; + } else { + clear_has_name_part(); + name_part_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + } +} + +// required bool is_extension = 2; +inline bool UninterpretedOption_NamePart::has_is_extension() const { + return (_has_bits_[0] & 0x00000002u) != 0; +} +inline void UninterpretedOption_NamePart::set_has_is_extension() { + _has_bits_[0] |= 0x00000002u; +} +inline void UninterpretedOption_NamePart::clear_has_is_extension() { + _has_bits_[0] &= ~0x00000002u; +} +inline void UninterpretedOption_NamePart::clear_is_extension() { + is_extension_ = false; + clear_has_is_extension(); +} +inline bool UninterpretedOption_NamePart::is_extension() const { + return is_extension_; +} +inline void UninterpretedOption_NamePart::set_is_extension(bool value) { + set_has_is_extension(); + is_extension_ = value; +} + +// ------------------------------------------------------------------- + +// UninterpretedOption + +// repeated .google.protobuf.UninterpretedOption.NamePart name = 2; +inline int UninterpretedOption::name_size() const { + return name_.size(); +} +inline void UninterpretedOption::clear_name() { + name_.Clear(); +} +inline const ::google::protobuf::UninterpretedOption_NamePart& UninterpretedOption::name(int index) const { + return name_.Get(index); +} +inline ::google::protobuf::UninterpretedOption_NamePart* UninterpretedOption::mutable_name(int index) { + return name_.Mutable(index); +} +inline ::google::protobuf::UninterpretedOption_NamePart* UninterpretedOption::add_name() { + return name_.Add(); +} +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >& +UninterpretedOption::name() const { + return name_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >* +UninterpretedOption::mutable_name() { + return &name_; +} + +// optional string identifier_value = 3; +inline bool UninterpretedOption::has_identifier_value() const { + return (_has_bits_[0] & 0x00000002u) != 0; +} +inline void UninterpretedOption::set_has_identifier_value() { + _has_bits_[0] |= 0x00000002u; +} +inline void UninterpretedOption::clear_has_identifier_value() { + _has_bits_[0] &= ~0x00000002u; +} +inline void UninterpretedOption::clear_identifier_value() { + if (identifier_value_ != &::google::protobuf::internal::kEmptyString) { + identifier_value_->clear(); + } + clear_has_identifier_value(); +} +inline const ::std::string& UninterpretedOption::identifier_value() const { + return *identifier_value_; +} +inline void UninterpretedOption::set_identifier_value(const ::std::string& value) { + set_has_identifier_value(); + if (identifier_value_ == &::google::protobuf::internal::kEmptyString) { + identifier_value_ = new ::std::string; + } + identifier_value_->assign(value); +} +inline void UninterpretedOption::set_identifier_value(const char* value) { + set_has_identifier_value(); + if (identifier_value_ == &::google::protobuf::internal::kEmptyString) { + identifier_value_ = new ::std::string; + } + identifier_value_->assign(value); +} +inline void UninterpretedOption::set_identifier_value(const char* value, size_t size) { + set_has_identifier_value(); + if (identifier_value_ == &::google::protobuf::internal::kEmptyString) { + identifier_value_ = new ::std::string; + } + identifier_value_->assign(reinterpret_cast(value), size); +} +inline ::std::string* UninterpretedOption::mutable_identifier_value() { + set_has_identifier_value(); + if (identifier_value_ == &::google::protobuf::internal::kEmptyString) { + identifier_value_ = new ::std::string; + } + return identifier_value_; +} +inline ::std::string* UninterpretedOption::release_identifier_value() { + clear_has_identifier_value(); + if (identifier_value_ == &::google::protobuf::internal::kEmptyString) { + return NULL; + } else { + ::std::string* temp = identifier_value_; + identifier_value_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + return temp; + } +} +inline void UninterpretedOption::set_allocated_identifier_value(::std::string* identifier_value) { + if (identifier_value_ != &::google::protobuf::internal::kEmptyString) { + delete identifier_value_; + } + if (identifier_value) { + set_has_identifier_value(); + identifier_value_ = identifier_value; + } else { + clear_has_identifier_value(); + identifier_value_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + } +} + +// optional uint64 positive_int_value = 4; +inline bool UninterpretedOption::has_positive_int_value() const { + return (_has_bits_[0] & 0x00000004u) != 0; +} +inline void UninterpretedOption::set_has_positive_int_value() { + _has_bits_[0] |= 0x00000004u; +} +inline void UninterpretedOption::clear_has_positive_int_value() { + _has_bits_[0] &= ~0x00000004u; +} +inline void UninterpretedOption::clear_positive_int_value() { + positive_int_value_ = GOOGLE_ULONGLONG(0); + clear_has_positive_int_value(); +} +inline ::google::protobuf::uint64 UninterpretedOption::positive_int_value() const { + return positive_int_value_; +} +inline void UninterpretedOption::set_positive_int_value(::google::protobuf::uint64 value) { + set_has_positive_int_value(); + positive_int_value_ = value; +} + +// optional int64 negative_int_value = 5; +inline bool UninterpretedOption::has_negative_int_value() const { + return (_has_bits_[0] & 0x00000008u) != 0; +} +inline void UninterpretedOption::set_has_negative_int_value() { + _has_bits_[0] |= 0x00000008u; +} +inline void UninterpretedOption::clear_has_negative_int_value() { + _has_bits_[0] &= ~0x00000008u; +} +inline void UninterpretedOption::clear_negative_int_value() { + negative_int_value_ = GOOGLE_LONGLONG(0); + clear_has_negative_int_value(); +} +inline ::google::protobuf::int64 UninterpretedOption::negative_int_value() const { + return negative_int_value_; +} +inline void UninterpretedOption::set_negative_int_value(::google::protobuf::int64 value) { + set_has_negative_int_value(); + negative_int_value_ = value; +} + +// optional double double_value = 6; +inline bool UninterpretedOption::has_double_value() const { + return (_has_bits_[0] & 0x00000010u) != 0; +} +inline void UninterpretedOption::set_has_double_value() { + _has_bits_[0] |= 0x00000010u; +} +inline void UninterpretedOption::clear_has_double_value() { + _has_bits_[0] &= ~0x00000010u; +} +inline void UninterpretedOption::clear_double_value() { + double_value_ = 0; + clear_has_double_value(); +} +inline double UninterpretedOption::double_value() const { + return double_value_; +} +inline void UninterpretedOption::set_double_value(double value) { + set_has_double_value(); + double_value_ = value; +} + +// optional bytes string_value = 7; +inline bool UninterpretedOption::has_string_value() const { + return (_has_bits_[0] & 0x00000020u) != 0; +} +inline void UninterpretedOption::set_has_string_value() { + _has_bits_[0] |= 0x00000020u; +} +inline void UninterpretedOption::clear_has_string_value() { + _has_bits_[0] &= ~0x00000020u; +} +inline void UninterpretedOption::clear_string_value() { + if (string_value_ != &::google::protobuf::internal::kEmptyString) { + string_value_->clear(); + } + clear_has_string_value(); +} +inline const ::std::string& UninterpretedOption::string_value() const { + return *string_value_; +} +inline void UninterpretedOption::set_string_value(const ::std::string& value) { + set_has_string_value(); + if (string_value_ == &::google::protobuf::internal::kEmptyString) { + string_value_ = new ::std::string; + } + string_value_->assign(value); +} +inline void UninterpretedOption::set_string_value(const char* value) { + set_has_string_value(); + if (string_value_ == &::google::protobuf::internal::kEmptyString) { + string_value_ = new ::std::string; + } + string_value_->assign(value); +} +inline void UninterpretedOption::set_string_value(const void* value, size_t size) { + set_has_string_value(); + if (string_value_ == &::google::protobuf::internal::kEmptyString) { + string_value_ = new ::std::string; + } + string_value_->assign(reinterpret_cast(value), size); +} +inline ::std::string* UninterpretedOption::mutable_string_value() { + set_has_string_value(); + if (string_value_ == &::google::protobuf::internal::kEmptyString) { + string_value_ = new ::std::string; + } + return string_value_; +} +inline ::std::string* UninterpretedOption::release_string_value() { + clear_has_string_value(); + if (string_value_ == &::google::protobuf::internal::kEmptyString) { + return NULL; + } else { + ::std::string* temp = string_value_; + string_value_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + return temp; + } +} +inline void UninterpretedOption::set_allocated_string_value(::std::string* string_value) { + if (string_value_ != &::google::protobuf::internal::kEmptyString) { + delete string_value_; + } + if (string_value) { + set_has_string_value(); + string_value_ = string_value; + } else { + clear_has_string_value(); + string_value_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + } +} + +// optional string aggregate_value = 8; +inline bool UninterpretedOption::has_aggregate_value() const { + return (_has_bits_[0] & 0x00000040u) != 0; +} +inline void UninterpretedOption::set_has_aggregate_value() { + _has_bits_[0] |= 0x00000040u; +} +inline void UninterpretedOption::clear_has_aggregate_value() { + _has_bits_[0] &= ~0x00000040u; +} +inline void UninterpretedOption::clear_aggregate_value() { + if (aggregate_value_ != &::google::protobuf::internal::kEmptyString) { + aggregate_value_->clear(); + } + clear_has_aggregate_value(); +} +inline const ::std::string& UninterpretedOption::aggregate_value() const { + return *aggregate_value_; +} +inline void UninterpretedOption::set_aggregate_value(const ::std::string& value) { + set_has_aggregate_value(); + if (aggregate_value_ == &::google::protobuf::internal::kEmptyString) { + aggregate_value_ = new ::std::string; + } + aggregate_value_->assign(value); +} +inline void UninterpretedOption::set_aggregate_value(const char* value) { + set_has_aggregate_value(); + if (aggregate_value_ == &::google::protobuf::internal::kEmptyString) { + aggregate_value_ = new ::std::string; + } + aggregate_value_->assign(value); +} +inline void UninterpretedOption::set_aggregate_value(const char* value, size_t size) { + set_has_aggregate_value(); + if (aggregate_value_ == &::google::protobuf::internal::kEmptyString) { + aggregate_value_ = new ::std::string; + } + aggregate_value_->assign(reinterpret_cast(value), size); +} +inline ::std::string* UninterpretedOption::mutable_aggregate_value() { + set_has_aggregate_value(); + if (aggregate_value_ == &::google::protobuf::internal::kEmptyString) { + aggregate_value_ = new ::std::string; + } + return aggregate_value_; +} +inline ::std::string* UninterpretedOption::release_aggregate_value() { + clear_has_aggregate_value(); + if (aggregate_value_ == &::google::protobuf::internal::kEmptyString) { + return NULL; + } else { + ::std::string* temp = aggregate_value_; + aggregate_value_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + return temp; + } +} +inline void UninterpretedOption::set_allocated_aggregate_value(::std::string* aggregate_value) { + if (aggregate_value_ != &::google::protobuf::internal::kEmptyString) { + delete aggregate_value_; + } + if (aggregate_value) { + set_has_aggregate_value(); + aggregate_value_ = aggregate_value; + } else { + clear_has_aggregate_value(); + aggregate_value_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + } +} + +// ------------------------------------------------------------------- + +// SourceCodeInfo_Location + +// repeated int32 path = 1 [packed = true]; +inline int SourceCodeInfo_Location::path_size() const { + return path_.size(); +} +inline void SourceCodeInfo_Location::clear_path() { + path_.Clear(); +} +inline ::google::protobuf::int32 SourceCodeInfo_Location::path(int index) const { + return path_.Get(index); +} +inline void SourceCodeInfo_Location::set_path(int index, ::google::protobuf::int32 value) { + path_.Set(index, value); +} +inline void SourceCodeInfo_Location::add_path(::google::protobuf::int32 value) { + path_.Add(value); +} +inline const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >& +SourceCodeInfo_Location::path() const { + return path_; +} +inline ::google::protobuf::RepeatedField< ::google::protobuf::int32 >* +SourceCodeInfo_Location::mutable_path() { + return &path_; +} + +// repeated int32 span = 2 [packed = true]; +inline int SourceCodeInfo_Location::span_size() const { + return span_.size(); +} +inline void SourceCodeInfo_Location::clear_span() { + span_.Clear(); +} +inline ::google::protobuf::int32 SourceCodeInfo_Location::span(int index) const { + return span_.Get(index); +} +inline void SourceCodeInfo_Location::set_span(int index, ::google::protobuf::int32 value) { + span_.Set(index, value); +} +inline void SourceCodeInfo_Location::add_span(::google::protobuf::int32 value) { + span_.Add(value); +} +inline const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >& +SourceCodeInfo_Location::span() const { + return span_; +} +inline ::google::protobuf::RepeatedField< ::google::protobuf::int32 >* +SourceCodeInfo_Location::mutable_span() { + return &span_; +} + +// optional string leading_comments = 3; +inline bool SourceCodeInfo_Location::has_leading_comments() const { + return (_has_bits_[0] & 0x00000004u) != 0; +} +inline void SourceCodeInfo_Location::set_has_leading_comments() { + _has_bits_[0] |= 0x00000004u; +} +inline void SourceCodeInfo_Location::clear_has_leading_comments() { + _has_bits_[0] &= ~0x00000004u; +} +inline void SourceCodeInfo_Location::clear_leading_comments() { + if (leading_comments_ != &::google::protobuf::internal::kEmptyString) { + leading_comments_->clear(); + } + clear_has_leading_comments(); +} +inline const ::std::string& SourceCodeInfo_Location::leading_comments() const { + return *leading_comments_; +} +inline void SourceCodeInfo_Location::set_leading_comments(const ::std::string& value) { + set_has_leading_comments(); + if (leading_comments_ == &::google::protobuf::internal::kEmptyString) { + leading_comments_ = new ::std::string; + } + leading_comments_->assign(value); +} +inline void SourceCodeInfo_Location::set_leading_comments(const char* value) { + set_has_leading_comments(); + if (leading_comments_ == &::google::protobuf::internal::kEmptyString) { + leading_comments_ = new ::std::string; + } + leading_comments_->assign(value); +} +inline void SourceCodeInfo_Location::set_leading_comments(const char* value, size_t size) { + set_has_leading_comments(); + if (leading_comments_ == &::google::protobuf::internal::kEmptyString) { + leading_comments_ = new ::std::string; + } + leading_comments_->assign(reinterpret_cast(value), size); +} +inline ::std::string* SourceCodeInfo_Location::mutable_leading_comments() { + set_has_leading_comments(); + if (leading_comments_ == &::google::protobuf::internal::kEmptyString) { + leading_comments_ = new ::std::string; + } + return leading_comments_; +} +inline ::std::string* SourceCodeInfo_Location::release_leading_comments() { + clear_has_leading_comments(); + if (leading_comments_ == &::google::protobuf::internal::kEmptyString) { + return NULL; + } else { + ::std::string* temp = leading_comments_; + leading_comments_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + return temp; + } +} +inline void SourceCodeInfo_Location::set_allocated_leading_comments(::std::string* leading_comments) { + if (leading_comments_ != &::google::protobuf::internal::kEmptyString) { + delete leading_comments_; + } + if (leading_comments) { + set_has_leading_comments(); + leading_comments_ = leading_comments; + } else { + clear_has_leading_comments(); + leading_comments_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + } +} + +// optional string trailing_comments = 4; +inline bool SourceCodeInfo_Location::has_trailing_comments() const { + return (_has_bits_[0] & 0x00000008u) != 0; +} +inline void SourceCodeInfo_Location::set_has_trailing_comments() { + _has_bits_[0] |= 0x00000008u; +} +inline void SourceCodeInfo_Location::clear_has_trailing_comments() { + _has_bits_[0] &= ~0x00000008u; +} +inline void SourceCodeInfo_Location::clear_trailing_comments() { + if (trailing_comments_ != &::google::protobuf::internal::kEmptyString) { + trailing_comments_->clear(); + } + clear_has_trailing_comments(); +} +inline const ::std::string& SourceCodeInfo_Location::trailing_comments() const { + return *trailing_comments_; +} +inline void SourceCodeInfo_Location::set_trailing_comments(const ::std::string& value) { + set_has_trailing_comments(); + if (trailing_comments_ == &::google::protobuf::internal::kEmptyString) { + trailing_comments_ = new ::std::string; + } + trailing_comments_->assign(value); +} +inline void SourceCodeInfo_Location::set_trailing_comments(const char* value) { + set_has_trailing_comments(); + if (trailing_comments_ == &::google::protobuf::internal::kEmptyString) { + trailing_comments_ = new ::std::string; + } + trailing_comments_->assign(value); +} +inline void SourceCodeInfo_Location::set_trailing_comments(const char* value, size_t size) { + set_has_trailing_comments(); + if (trailing_comments_ == &::google::protobuf::internal::kEmptyString) { + trailing_comments_ = new ::std::string; + } + trailing_comments_->assign(reinterpret_cast(value), size); +} +inline ::std::string* SourceCodeInfo_Location::mutable_trailing_comments() { + set_has_trailing_comments(); + if (trailing_comments_ == &::google::protobuf::internal::kEmptyString) { + trailing_comments_ = new ::std::string; + } + return trailing_comments_; +} +inline ::std::string* SourceCodeInfo_Location::release_trailing_comments() { + clear_has_trailing_comments(); + if (trailing_comments_ == &::google::protobuf::internal::kEmptyString) { + return NULL; + } else { + ::std::string* temp = trailing_comments_; + trailing_comments_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + return temp; + } +} +inline void SourceCodeInfo_Location::set_allocated_trailing_comments(::std::string* trailing_comments) { + if (trailing_comments_ != &::google::protobuf::internal::kEmptyString) { + delete trailing_comments_; + } + if (trailing_comments) { + set_has_trailing_comments(); + trailing_comments_ = trailing_comments; + } else { + clear_has_trailing_comments(); + trailing_comments_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + } +} + +// ------------------------------------------------------------------- + +// SourceCodeInfo + +// repeated .google.protobuf.SourceCodeInfo.Location location = 1; +inline int SourceCodeInfo::location_size() const { + return location_.size(); +} +inline void SourceCodeInfo::clear_location() { + location_.Clear(); +} +inline const ::google::protobuf::SourceCodeInfo_Location& SourceCodeInfo::location(int index) const { + return location_.Get(index); +} +inline ::google::protobuf::SourceCodeInfo_Location* SourceCodeInfo::mutable_location(int index) { + return location_.Mutable(index); +} +inline ::google::protobuf::SourceCodeInfo_Location* SourceCodeInfo::add_location() { + return location_.Add(); +} +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::SourceCodeInfo_Location >& +SourceCodeInfo::location() const { + return location_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::SourceCodeInfo_Location >* +SourceCodeInfo::mutable_location() { + return &location_; +} + + +// @@protoc_insertion_point(namespace_scope) + +} // namespace protobuf +} // namespace google + +#ifndef SWIG +namespace google { +namespace protobuf { + +template <> +inline const EnumDescriptor* GetEnumDescriptor< ::google::protobuf::FieldDescriptorProto_Type>() { + return ::google::protobuf::FieldDescriptorProto_Type_descriptor(); +} +template <> +inline const EnumDescriptor* GetEnumDescriptor< ::google::protobuf::FieldDescriptorProto_Label>() { + return ::google::protobuf::FieldDescriptorProto_Label_descriptor(); +} +template <> +inline const EnumDescriptor* GetEnumDescriptor< ::google::protobuf::FileOptions_OptimizeMode>() { + return ::google::protobuf::FileOptions_OptimizeMode_descriptor(); +} +template <> +inline const EnumDescriptor* GetEnumDescriptor< ::google::protobuf::FieldOptions_CType>() { + return ::google::protobuf::FieldOptions_CType_descriptor(); +} + +} // namespace google +} // namespace protobuf +#endif // SWIG + +// @@protoc_insertion_point(global_scope) + +#endif // PROTOBUF_google_2fprotobuf_2fdescriptor_2eproto__INCLUDED diff --git a/include/google/protobuf/descriptor.proto b/include/google/protobuf/descriptor.proto new file mode 100644 index 000000000..a785f79fa --- /dev/null +++ b/include/google/protobuf/descriptor.proto @@ -0,0 +1,620 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// The messages in this file describe the definitions found in .proto files. +// A valid .proto file can be translated directly to a FileDescriptorProto +// without any other information (e.g. without reading its imports). + + + +package google.protobuf; +option java_package = "com.google.protobuf"; +option java_outer_classname = "DescriptorProtos"; + +// descriptor.proto must be optimized for speed because reflection-based +// algorithms don't work during bootstrapping. +option optimize_for = SPEED; + +// The protocol compiler can output a FileDescriptorSet containing the .proto +// files it parses. +message FileDescriptorSet { + repeated FileDescriptorProto file = 1; +} + +// Describes a complete .proto file. +message FileDescriptorProto { + optional string name = 1; // file name, relative to root of source tree + optional string package = 2; // e.g. "foo", "foo.bar", etc. + + // Names of files imported by this file. + repeated string dependency = 3; + // Indexes of the public imported files in the dependency list above. + repeated int32 public_dependency = 10; + // Indexes of the weak imported files in the dependency list. + // For Google-internal migration only. Do not use. + repeated int32 weak_dependency = 11; + + // All top-level definitions in this file. + repeated DescriptorProto message_type = 4; + repeated EnumDescriptorProto enum_type = 5; + repeated ServiceDescriptorProto service = 6; + repeated FieldDescriptorProto extension = 7; + + optional FileOptions options = 8; + + // This field contains optional information about the original source code. + // You may safely remove this entire field whithout harming runtime + // functionality of the descriptors -- the information is needed only by + // development tools. + optional SourceCodeInfo source_code_info = 9; +} + +// Describes a message type. +message DescriptorProto { + optional string name = 1; + + repeated FieldDescriptorProto field = 2; + repeated FieldDescriptorProto extension = 6; + + repeated DescriptorProto nested_type = 3; + repeated EnumDescriptorProto enum_type = 4; + + message ExtensionRange { + optional int32 start = 1; + optional int32 end = 2; + } + repeated ExtensionRange extension_range = 5; + + optional MessageOptions options = 7; +} + +// Describes a field within a message. +message FieldDescriptorProto { + enum Type { + // 0 is reserved for errors. + // Order is weird for historical reasons. + TYPE_DOUBLE = 1; + TYPE_FLOAT = 2; + // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT64 if + // negative values are likely. + TYPE_INT64 = 3; + TYPE_UINT64 = 4; + // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT32 if + // negative values are likely. + TYPE_INT32 = 5; + TYPE_FIXED64 = 6; + TYPE_FIXED32 = 7; + TYPE_BOOL = 8; + TYPE_STRING = 9; + TYPE_GROUP = 10; // Tag-delimited aggregate. + TYPE_MESSAGE = 11; // Length-delimited aggregate. + + // New in version 2. + TYPE_BYTES = 12; + TYPE_UINT32 = 13; + TYPE_ENUM = 14; + TYPE_SFIXED32 = 15; + TYPE_SFIXED64 = 16; + TYPE_SINT32 = 17; // Uses ZigZag encoding. + TYPE_SINT64 = 18; // Uses ZigZag encoding. + }; + + enum Label { + // 0 is reserved for errors + LABEL_OPTIONAL = 1; + LABEL_REQUIRED = 2; + LABEL_REPEATED = 3; + // TODO(sanjay): Should we add LABEL_MAP? + }; + + optional string name = 1; + optional int32 number = 3; + optional Label label = 4; + + // If type_name is set, this need not be set. If both this and type_name + // are set, this must be either TYPE_ENUM or TYPE_MESSAGE. + optional Type type = 5; + + // For message and enum types, this is the name of the type. If the name + // starts with a '.', it is fully-qualified. Otherwise, C++-like scoping + // rules are used to find the type (i.e. first the nested types within this + // message are searched, then within the parent, on up to the root + // namespace). + optional string type_name = 6; + + // For extensions, this is the name of the type being extended. It is + // resolved in the same manner as type_name. + optional string extendee = 2; + + // For numeric types, contains the original text representation of the value. + // For booleans, "true" or "false". + // For strings, contains the default text contents (not escaped in any way). + // For bytes, contains the C escaped value. All bytes >= 128 are escaped. + // TODO(kenton): Base-64 encode? + optional string default_value = 7; + + optional FieldOptions options = 8; +} + +// Describes an enum type. +message EnumDescriptorProto { + optional string name = 1; + + repeated EnumValueDescriptorProto value = 2; + + optional EnumOptions options = 3; +} + +// Describes a value within an enum. +message EnumValueDescriptorProto { + optional string name = 1; + optional int32 number = 2; + + optional EnumValueOptions options = 3; +} + +// Describes a service. +message ServiceDescriptorProto { + optional string name = 1; + repeated MethodDescriptorProto method = 2; + + optional ServiceOptions options = 3; +} + +// Describes a method of a service. +message MethodDescriptorProto { + optional string name = 1; + + // Input and output type names. These are resolved in the same way as + // FieldDescriptorProto.type_name, but must refer to a message type. + optional string input_type = 2; + optional string output_type = 3; + + optional MethodOptions options = 4; +} + + +// =================================================================== +// Options + +// Each of the definitions above may have "options" attached. These are +// just annotations which may cause code to be generated slightly differently +// or may contain hints for code that manipulates protocol messages. +// +// Clients may define custom options as extensions of the *Options messages. +// These extensions may not yet be known at parsing time, so the parser cannot +// store the values in them. Instead it stores them in a field in the *Options +// message called uninterpreted_option. This field must have the same name +// across all *Options messages. We then use this field to populate the +// extensions when we build a descriptor, at which point all protos have been +// parsed and so all extensions are known. +// +// Extension numbers for custom options may be chosen as follows: +// * For options which will only be used within a single application or +// organization, or for experimental options, use field numbers 50000 +// through 99999. It is up to you to ensure that you do not use the +// same number for multiple options. +// * For options which will be published and used publicly by multiple +// independent entities, e-mail protobuf-global-extension-registry@google.com +// to reserve extension numbers. Simply provide your project name (e.g. +// Object-C plugin) and your porject website (if available) -- there's no need +// to explain how you intend to use them. Usually you only need one extension +// number. You can declare multiple options with only one extension number by +// putting them in a sub-message. See the Custom Options section of the docs +// for examples: +// http://code.google.com/apis/protocolbuffers/docs/proto.html#options +// If this turns out to be popular, a web service will be set up +// to automatically assign option numbers. + + +message FileOptions { + + // Sets the Java package where classes generated from this .proto will be + // placed. By default, the proto package is used, but this is often + // inappropriate because proto packages do not normally start with backwards + // domain names. + optional string java_package = 1; + + + // If set, all the classes from the .proto file are wrapped in a single + // outer class with the given name. This applies to both Proto1 + // (equivalent to the old "--one_java_file" option) and Proto2 (where + // a .proto always translates to a single class, but you may want to + // explicitly choose the class name). + optional string java_outer_classname = 8; + + // If set true, then the Java code generator will generate a separate .java + // file for each top-level message, enum, and service defined in the .proto + // file. Thus, these types will *not* be nested inside the outer class + // named by java_outer_classname. However, the outer class will still be + // generated to contain the file's getDescriptor() method as well as any + // top-level extensions defined in the file. + optional bool java_multiple_files = 10 [default=false]; + + // If set true, then the Java code generator will generate equals() and + // hashCode() methods for all messages defined in the .proto file. This is + // purely a speed optimization, as the AbstractMessage base class includes + // reflection-based implementations of these methods. + optional bool java_generate_equals_and_hash = 20 [default=false]; + + // Generated classes can be optimized for speed or code size. + enum OptimizeMode { + SPEED = 1; // Generate complete code for parsing, serialization, + // etc. + CODE_SIZE = 2; // Use ReflectionOps to implement these methods. + LITE_RUNTIME = 3; // Generate code using MessageLite and the lite runtime. + } + optional OptimizeMode optimize_for = 9 [default=SPEED]; + + // Sets the Go package where structs generated from this .proto will be + // placed. There is no default. + optional string go_package = 11; + + + + // Should generic services be generated in each language? "Generic" services + // are not specific to any particular RPC system. They are generated by the + // main code generators in each language (without additional plugins). + // Generic services were the only kind of service generation supported by + // early versions of proto2. + // + // Generic services are now considered deprecated in favor of using plugins + // that generate code specific to your particular RPC system. Therefore, + // these default to false. Old code which depends on generic services should + // explicitly set them to true. + optional bool cc_generic_services = 16 [default=false]; + optional bool java_generic_services = 17 [default=false]; + optional bool py_generic_services = 18 [default=false]; + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +message MessageOptions { + // Set true to use the old proto1 MessageSet wire format for extensions. + // This is provided for backwards-compatibility with the MessageSet wire + // format. You should not use this for any other reason: It's less + // efficient, has fewer features, and is more complicated. + // + // The message must be defined exactly as follows: + // message Foo { + // option message_set_wire_format = true; + // extensions 4 to max; + // } + // Note that the message cannot have any defined fields; MessageSets only + // have extensions. + // + // All extensions of your type must be singular messages; e.g. they cannot + // be int32s, enums, or repeated messages. + // + // Because this is an option, the above two restrictions are not enforced by + // the protocol compiler. + optional bool message_set_wire_format = 1 [default=false]; + + // Disables the generation of the standard "descriptor()" accessor, which can + // conflict with a field of the same name. This is meant to make migration + // from proto1 easier; new code should avoid fields named "descriptor". + optional bool no_standard_descriptor_accessor = 2 [default=false]; + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +message FieldOptions { + // The ctype option instructs the C++ code generator to use a different + // representation of the field than it normally would. See the specific + // options below. This option is not yet implemented in the open source + // release -- sorry, we'll try to include it in a future version! + optional CType ctype = 1 [default = STRING]; + enum CType { + // Default mode. + STRING = 0; + + CORD = 1; + + STRING_PIECE = 2; + } + // The packed option can be enabled for repeated primitive fields to enable + // a more efficient representation on the wire. Rather than repeatedly + // writing the tag and type for each element, the entire array is encoded as + // a single length-delimited blob. + optional bool packed = 2; + + + + // Should this field be parsed lazily? Lazy applies only to message-type + // fields. It means that when the outer message is initially parsed, the + // inner message's contents will not be parsed but instead stored in encoded + // form. The inner message will actually be parsed when it is first accessed. + // + // This is only a hint. Implementations are free to choose whether to use + // eager or lazy parsing regardless of the value of this option. However, + // setting this option true suggests that the protocol author believes that + // using lazy parsing on this field is worth the additional bookkeeping + // overhead typically needed to implement it. + // + // This option does not affect the public interface of any generated code; + // all method signatures remain the same. Furthermore, thread-safety of the + // interface is not affected by this option; const methods remain safe to + // call from multiple threads concurrently, while non-const methods continue + // to require exclusive access. + // + // + // Note that implementations may choose not to check required fields within + // a lazy sub-message. That is, calling IsInitialized() on the outher message + // may return true even if the inner message has missing required fields. + // This is necessary because otherwise the inner message would have to be + // parsed in order to perform the check, defeating the purpose of lazy + // parsing. An implementation which chooses not to check required fields + // must be consistent about it. That is, for any particular sub-message, the + // implementation must either *always* check its required fields, or *never* + // check its required fields, regardless of whether or not the message has + // been parsed. + optional bool lazy = 5 [default=false]; + + // Is this field deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for accessors, or it will be completely ignored; in the very least, this + // is a formalization for deprecating fields. + optional bool deprecated = 3 [default=false]; + + // EXPERIMENTAL. DO NOT USE. + // For "map" fields, the name of the field in the enclosed type that + // is the key for this map. For example, suppose we have: + // message Item { + // required string name = 1; + // required string value = 2; + // } + // message Config { + // repeated Item items = 1 [experimental_map_key="name"]; + // } + // In this situation, the map key for Item will be set to "name". + // TODO: Fully-implement this, then remove the "experimental_" prefix. + optional string experimental_map_key = 9; + + // For Google-internal migration only. Do not use. + optional bool weak = 10 [default=false]; + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +message EnumOptions { + + // Set this option to false to disallow mapping different tag names to a same + // value. + optional bool allow_alias = 2 [default=true]; + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +message EnumValueOptions { + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +message ServiceOptions { + + // Note: Field numbers 1 through 32 are reserved for Google's internal RPC + // framework. We apologize for hoarding these numbers to ourselves, but + // we were already using them long before we decided to release Protocol + // Buffers. + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +message MethodOptions { + + // Note: Field numbers 1 through 32 are reserved for Google's internal RPC + // framework. We apologize for hoarding these numbers to ourselves, but + // we were already using them long before we decided to release Protocol + // Buffers. + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + + +// A message representing a option the parser does not recognize. This only +// appears in options protos created by the compiler::Parser class. +// DescriptorPool resolves these when building Descriptor objects. Therefore, +// options protos in descriptor objects (e.g. returned by Descriptor::options(), +// or produced by Descriptor::CopyTo()) will never have UninterpretedOptions +// in them. +message UninterpretedOption { + // The name of the uninterpreted option. Each string represents a segment in + // a dot-separated name. is_extension is true iff a segment represents an + // extension (denoted with parentheses in options specs in .proto files). + // E.g.,{ ["foo", false], ["bar.baz", true], ["qux", false] } represents + // "foo.(bar.baz).qux". + message NamePart { + required string name_part = 1; + required bool is_extension = 2; + } + repeated NamePart name = 2; + + // The value of the uninterpreted option, in whatever type the tokenizer + // identified it as during parsing. Exactly one of these should be set. + optional string identifier_value = 3; + optional uint64 positive_int_value = 4; + optional int64 negative_int_value = 5; + optional double double_value = 6; + optional bytes string_value = 7; + optional string aggregate_value = 8; +} + +// =================================================================== +// Optional source code info + +// Encapsulates information about the original source file from which a +// FileDescriptorProto was generated. +message SourceCodeInfo { + // A Location identifies a piece of source code in a .proto file which + // corresponds to a particular definition. This information is intended + // to be useful to IDEs, code indexers, documentation generators, and similar + // tools. + // + // For example, say we have a file like: + // message Foo { + // optional string foo = 1; + // } + // Let's look at just the field definition: + // optional string foo = 1; + // ^ ^^ ^^ ^ ^^^ + // a bc de f ghi + // We have the following locations: + // span path represents + // [a,i) [ 4, 0, 2, 0 ] The whole field definition. + // [a,b) [ 4, 0, 2, 0, 4 ] The label (optional). + // [c,d) [ 4, 0, 2, 0, 5 ] The type (string). + // [e,f) [ 4, 0, 2, 0, 1 ] The name (foo). + // [g,h) [ 4, 0, 2, 0, 3 ] The number (1). + // + // Notes: + // - A location may refer to a repeated field itself (i.e. not to any + // particular index within it). This is used whenever a set of elements are + // logically enclosed in a single code segment. For example, an entire + // extend block (possibly containing multiple extension definitions) will + // have an outer location whose path refers to the "extensions" repeated + // field without an index. + // - Multiple locations may have the same path. This happens when a single + // logical declaration is spread out across multiple places. The most + // obvious example is the "extend" block again -- there may be multiple + // extend blocks in the same scope, each of which will have the same path. + // - A location's span is not always a subset of its parent's span. For + // example, the "extendee" of an extension declaration appears at the + // beginning of the "extend" block and is shared by all extensions within + // the block. + // - Just because a location's span is a subset of some other location's span + // does not mean that it is a descendent. For example, a "group" defines + // both a type and a field in a single declaration. Thus, the locations + // corresponding to the type and field and their components will overlap. + // - Code which tries to interpret locations should probably be designed to + // ignore those that it doesn't understand, as more types of locations could + // be recorded in the future. + repeated Location location = 1; + message Location { + // Identifies which part of the FileDescriptorProto was defined at this + // location. + // + // Each element is a field number or an index. They form a path from + // the root FileDescriptorProto to the place where the definition. For + // example, this path: + // [ 4, 3, 2, 7, 1 ] + // refers to: + // file.message_type(3) // 4, 3 + // .field(7) // 2, 7 + // .name() // 1 + // This is because FileDescriptorProto.message_type has field number 4: + // repeated DescriptorProto message_type = 4; + // and DescriptorProto.field has field number 2: + // repeated FieldDescriptorProto field = 2; + // and FieldDescriptorProto.name has field number 1: + // optional string name = 1; + // + // Thus, the above path gives the location of a field name. If we removed + // the last element: + // [ 4, 3, 2, 7 ] + // this path refers to the whole field declaration (from the beginning + // of the label to the terminating semicolon). + repeated int32 path = 1 [packed=true]; + + // Always has exactly three or four elements: start line, start column, + // end line (optional, otherwise assumed same as start line), end column. + // These are packed into a single field for efficiency. Note that line + // and column numbers are zero-based -- typically you will want to add + // 1 to each before displaying to a user. + repeated int32 span = 2 [packed=true]; + + // If this SourceCodeInfo represents a complete declaration, these are any + // comments appearing before and after the declaration which appear to be + // attached to the declaration. + // + // A series of line comments appearing on consecutive lines, with no other + // tokens appearing on those lines, will be treated as a single comment. + // + // Only the comment content is provided; comment markers (e.g. //) are + // stripped out. For block comments, leading whitespace and an asterisk + // will be stripped from the beginning of each line other than the first. + // Newlines are included in the output. + // + // Examples: + // + // optional int32 foo = 1; // Comment attached to foo. + // // Comment attached to bar. + // optional int32 bar = 2; + // + // optional string baz = 3; + // // Comment attached to baz. + // // Another line attached to baz. + // + // // Comment attached to qux. + // // + // // Another line attached to qux. + // optional double qux = 4; + // + // optional string corge = 5; + // /* Block comment attached + // * to corge. Leading asterisks + // * will be removed. */ + // /* Block comment attached to + // * grault. */ + // optional int32 grault = 6; + optional string leading_comments = 3; + optional string trailing_comments = 4; + } +} diff --git a/include/google/protobuf/descriptor_database.h b/include/google/protobuf/descriptor_database.h new file mode 100644 index 000000000..2ccb14583 --- /dev/null +++ b/include/google/protobuf/descriptor_database.h @@ -0,0 +1,367 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// Interface for manipulating databases of descriptors. + +#ifndef GOOGLE_PROTOBUF_DESCRIPTOR_DATABASE_H__ +#define GOOGLE_PROTOBUF_DESCRIPTOR_DATABASE_H__ + +#include +#include +#include +#include +#include +#include + +namespace google { +namespace protobuf { + +// Defined in this file. +class DescriptorDatabase; +class SimpleDescriptorDatabase; +class EncodedDescriptorDatabase; +class DescriptorPoolDatabase; +class MergedDescriptorDatabase; + +// Abstract interface for a database of descriptors. +// +// This is useful if you want to create a DescriptorPool which loads +// descriptors on-demand from some sort of large database. If the database +// is large, it may be inefficient to enumerate every .proto file inside it +// calling DescriptorPool::BuildFile() for each one. Instead, a DescriptorPool +// can be created which wraps a DescriptorDatabase and only builds particular +// descriptors when they are needed. +class LIBPROTOBUF_EXPORT DescriptorDatabase { + public: + inline DescriptorDatabase() {} + virtual ~DescriptorDatabase(); + + // Find a file by file name. Fills in in *output and returns true if found. + // Otherwise, returns false, leaving the contents of *output undefined. + virtual bool FindFileByName(const string& filename, + FileDescriptorProto* output) = 0; + + // Find the file that declares the given fully-qualified symbol name. + // If found, fills in *output and returns true, otherwise returns false + // and leaves *output undefined. + virtual bool FindFileContainingSymbol(const string& symbol_name, + FileDescriptorProto* output) = 0; + + // Find the file which defines an extension extending the given message type + // with the given field number. If found, fills in *output and returns true, + // otherwise returns false and leaves *output undefined. containing_type + // must be a fully-qualified type name. + virtual bool FindFileContainingExtension(const string& containing_type, + int field_number, + FileDescriptorProto* output) = 0; + + // Finds the tag numbers used by all known extensions of + // extendee_type, and appends them to output in an undefined + // order. This method is best-effort: it's not guaranteed that the + // database will find all extensions, and it's not guaranteed that + // FindFileContainingExtension will return true on all of the found + // numbers. Returns true if the search was successful, otherwise + // returns false and leaves output unchanged. + // + // This method has a default implementation that always returns + // false. + virtual bool FindAllExtensionNumbers(const string& extendee_type, + vector* output) { + return false; + } + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DescriptorDatabase); +}; + +// A DescriptorDatabase into which you can insert files manually. +// +// FindFileContainingSymbol() is fully-implemented. When you add a file, its +// symbols will be indexed for this purpose. Note that the implementation +// may return false positives, but only if it isn't possible for the symbol +// to be defined in any other file. In particular, if a file defines a symbol +// "Foo", then searching for "Foo.[anything]" will match that file. This way, +// the database does not need to aggressively index all children of a symbol. +// +// FindFileContainingExtension() is mostly-implemented. It works if and only +// if the original FieldDescriptorProto defining the extension has a +// fully-qualified type name in its "extendee" field (i.e. starts with a '.'). +// If the extendee is a relative name, SimpleDescriptorDatabase will not +// attempt to resolve the type, so it will not know what type the extension is +// extending. Therefore, calling FindFileContainingExtension() with the +// extension's containing type will never actually find that extension. Note +// that this is an unlikely problem, as all FileDescriptorProtos created by the +// protocol compiler (as well as ones created by calling +// FileDescriptor::CopyTo()) will always use fully-qualified names for all +// types. You only need to worry if you are constructing FileDescriptorProtos +// yourself, or are calling compiler::Parser directly. +class LIBPROTOBUF_EXPORT SimpleDescriptorDatabase : public DescriptorDatabase { + public: + SimpleDescriptorDatabase(); + ~SimpleDescriptorDatabase(); + + // Adds the FileDescriptorProto to the database, making a copy. The object + // can be deleted after Add() returns. Returns false if the file conflicted + // with a file already in the database, in which case an error will have + // been written to GOOGLE_LOG(ERROR). + bool Add(const FileDescriptorProto& file); + + // Adds the FileDescriptorProto to the database and takes ownership of it. + bool AddAndOwn(const FileDescriptorProto* file); + + // implements DescriptorDatabase ----------------------------------- + bool FindFileByName(const string& filename, + FileDescriptorProto* output); + bool FindFileContainingSymbol(const string& symbol_name, + FileDescriptorProto* output); + bool FindFileContainingExtension(const string& containing_type, + int field_number, + FileDescriptorProto* output); + bool FindAllExtensionNumbers(const string& extendee_type, + vector* output); + + private: + // So that it can use DescriptorIndex. + friend class EncodedDescriptorDatabase; + + // An index mapping file names, symbol names, and extension numbers to + // some sort of values. + template + class DescriptorIndex { + public: + // Helpers to recursively add particular descriptors and all their contents + // to the index. + bool AddFile(const FileDescriptorProto& file, + Value value); + bool AddSymbol(const string& name, Value value); + bool AddNestedExtensions(const DescriptorProto& message_type, + Value value); + bool AddExtension(const FieldDescriptorProto& field, + Value value); + + Value FindFile(const string& filename); + Value FindSymbol(const string& name); + Value FindExtension(const string& containing_type, int field_number); + bool FindAllExtensionNumbers(const string& containing_type, + vector* output); + + private: + map by_name_; + map by_symbol_; + map, Value> by_extension_; + + // Invariant: The by_symbol_ map does not contain any symbols which are + // prefixes of other symbols in the map. For example, "foo.bar" is a + // prefix of "foo.bar.baz" (but is not a prefix of "foo.barbaz"). + // + // This invariant is important because it means that given a symbol name, + // we can find a key in the map which is a prefix of the symbol in O(lg n) + // time, and we know that there is at most one such key. + // + // The prefix lookup algorithm works like so: + // 1) Find the last key in the map which is less than or equal to the + // search key. + // 2) If the found key is a prefix of the search key, then return it. + // Otherwise, there is no match. + // + // I am sure this algorithm has been described elsewhere, but since I + // wasn't able to find it quickly I will instead prove that it works + // myself. The key to the algorithm is that if a match exists, step (1) + // will find it. Proof: + // 1) Define the "search key" to be the key we are looking for, the "found + // key" to be the key found in step (1), and the "match key" to be the + // key which actually matches the serach key (i.e. the key we're trying + // to find). + // 2) The found key must be less than or equal to the search key by + // definition. + // 3) The match key must also be less than or equal to the search key + // (because it is a prefix). + // 4) The match key cannot be greater than the found key, because if it + // were, then step (1) of the algorithm would have returned the match + // key instead (since it finds the *greatest* key which is less than or + // equal to the search key). + // 5) Therefore, the found key must be between the match key and the search + // key, inclusive. + // 6) Since the search key must be a sub-symbol of the match key, if it is + // not equal to the match key, then search_key[match_key.size()] must + // be '.'. + // 7) Since '.' sorts before any other character that is valid in a symbol + // name, then if the found key is not equal to the match key, then + // found_key[match_key.size()] must also be '.', because any other value + // would make it sort after the search key. + // 8) Therefore, if the found key is not equal to the match key, then the + // found key must be a sub-symbol of the match key. However, this would + // contradict our map invariant which says that no symbol in the map is + // a sub-symbol of any other. + // 9) Therefore, the found key must match the match key. + // + // The above proof assumes the match key exists. In the case that the + // match key does not exist, then step (1) will return some other symbol. + // That symbol cannot be a super-symbol of the search key since if it were, + // then it would be a match, and we're assuming the match key doesn't exist. + // Therefore, step 2 will correctly return no match. + + // Find the last entry in the by_symbol_ map whose key is less than or + // equal to the given name. + typename map::iterator FindLastLessOrEqual( + const string& name); + + // True if either the arguments are equal or super_symbol identifies a + // parent symbol of sub_symbol (e.g. "foo.bar" is a parent of + // "foo.bar.baz", but not a parent of "foo.barbaz"). + bool IsSubSymbol(const string& sub_symbol, const string& super_symbol); + + // Returns true if and only if all characters in the name are alphanumerics, + // underscores, or periods. + bool ValidateSymbolName(const string& name); + }; + + + DescriptorIndex index_; + vector files_to_delete_; + + // If file is non-NULL, copy it into *output and return true, otherwise + // return false. + bool MaybeCopy(const FileDescriptorProto* file, + FileDescriptorProto* output); + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(SimpleDescriptorDatabase); +}; + +// Very similar to SimpleDescriptorDatabase, but stores all the descriptors +// as raw bytes and generally tries to use as little memory as possible. +// +// The same caveats regarding FindFileContainingExtension() apply as with +// SimpleDescriptorDatabase. +class LIBPROTOBUF_EXPORT EncodedDescriptorDatabase : public DescriptorDatabase { + public: + EncodedDescriptorDatabase(); + ~EncodedDescriptorDatabase(); + + // Adds the FileDescriptorProto to the database. The descriptor is provided + // in encoded form. The database does not make a copy of the bytes, nor + // does it take ownership; it's up to the caller to make sure the bytes + // remain valid for the life of the database. Returns false and logs an error + // if the bytes are not a valid FileDescriptorProto or if the file conflicted + // with a file already in the database. + bool Add(const void* encoded_file_descriptor, int size); + + // Like Add(), but makes a copy of the data, so that the caller does not + // need to keep it around. + bool AddCopy(const void* encoded_file_descriptor, int size); + + // Like FindFileContainingSymbol but returns only the name of the file. + bool FindNameOfFileContainingSymbol(const string& symbol_name, + string* output); + + // implements DescriptorDatabase ----------------------------------- + bool FindFileByName(const string& filename, + FileDescriptorProto* output); + bool FindFileContainingSymbol(const string& symbol_name, + FileDescriptorProto* output); + bool FindFileContainingExtension(const string& containing_type, + int field_number, + FileDescriptorProto* output); + bool FindAllExtensionNumbers(const string& extendee_type, + vector* output); + + private: + SimpleDescriptorDatabase::DescriptorIndex > index_; + vector files_to_delete_; + + // If encoded_file.first is non-NULL, parse the data into *output and return + // true, otherwise return false. + bool MaybeParse(pair encoded_file, + FileDescriptorProto* output); + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EncodedDescriptorDatabase); +}; + +// A DescriptorDatabase that fetches files from a given pool. +class LIBPROTOBUF_EXPORT DescriptorPoolDatabase : public DescriptorDatabase { + public: + DescriptorPoolDatabase(const DescriptorPool& pool); + ~DescriptorPoolDatabase(); + + // implements DescriptorDatabase ----------------------------------- + bool FindFileByName(const string& filename, + FileDescriptorProto* output); + bool FindFileContainingSymbol(const string& symbol_name, + FileDescriptorProto* output); + bool FindFileContainingExtension(const string& containing_type, + int field_number, + FileDescriptorProto* output); + bool FindAllExtensionNumbers(const string& extendee_type, + vector* output); + + private: + const DescriptorPool& pool_; + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DescriptorPoolDatabase); +}; + +// A DescriptorDatabase that wraps two or more others. It first searches the +// first database and, if that fails, tries the second, and so on. +class LIBPROTOBUF_EXPORT MergedDescriptorDatabase : public DescriptorDatabase { + public: + // Merge just two databases. The sources remain property of the caller. + MergedDescriptorDatabase(DescriptorDatabase* source1, + DescriptorDatabase* source2); + // Merge more than two databases. The sources remain property of the caller. + // The vector may be deleted after the constructor returns but the + // DescriptorDatabases need to stick around. + MergedDescriptorDatabase(const vector& sources); + ~MergedDescriptorDatabase(); + + // implements DescriptorDatabase ----------------------------------- + bool FindFileByName(const string& filename, + FileDescriptorProto* output); + bool FindFileContainingSymbol(const string& symbol_name, + FileDescriptorProto* output); + bool FindFileContainingExtension(const string& containing_type, + int field_number, + FileDescriptorProto* output); + // Merges the results of calling all databases. Returns true iff any + // of the databases returned true. + bool FindAllExtensionNumbers(const string& extendee_type, + vector* output); + + private: + vector sources_; + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MergedDescriptorDatabase); +}; + +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_DESCRIPTOR_DATABASE_H__ diff --git a/include/google/protobuf/dynamic_message.h b/include/google/protobuf/dynamic_message.h new file mode 100644 index 000000000..b3d1e5d28 --- /dev/null +++ b/include/google/protobuf/dynamic_message.h @@ -0,0 +1,136 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// Defines an implementation of Message which can emulate types which are not +// known at compile-time. + +#ifndef GOOGLE_PROTOBUF_DYNAMIC_MESSAGE_H__ +#define GOOGLE_PROTOBUF_DYNAMIC_MESSAGE_H__ + +#include +#include + +namespace google { +namespace protobuf { + +// Defined in other files. +class Descriptor; // descriptor.h +class DescriptorPool; // descriptor.h + +// Constructs implementations of Message which can emulate types which are not +// known at compile-time. +// +// Sometimes you want to be able to manipulate protocol types that you don't +// know about at compile time. It would be nice to be able to construct +// a Message object which implements the message type given by any arbitrary +// Descriptor. DynamicMessage provides this. +// +// As it turns out, a DynamicMessage needs to construct extra +// information about its type in order to operate. Most of this information +// can be shared between all DynamicMessages of the same type. But, caching +// this information in some sort of global map would be a bad idea, since +// the cached information for a particular descriptor could outlive the +// descriptor itself. To avoid this problem, DynamicMessageFactory +// encapsulates this "cache". All DynamicMessages of the same type created +// from the same factory will share the same support data. Any Descriptors +// used with a particular factory must outlive the factory. +class LIBPROTOBUF_EXPORT DynamicMessageFactory : public MessageFactory { + public: + // Construct a DynamicMessageFactory that will search for extensions in + // the DescriptorPool in which the extendee is defined. + DynamicMessageFactory(); + + // Construct a DynamicMessageFactory that will search for extensions in + // the given DescriptorPool. + // + // DEPRECATED: Use CodedInputStream::SetExtensionRegistry() to tell the + // parser to look for extensions in an alternate pool. However, note that + // this is almost never what you want to do. Almost all users should use + // the zero-arg constructor. + DynamicMessageFactory(const DescriptorPool* pool); + + ~DynamicMessageFactory(); + + // Call this to tell the DynamicMessageFactory that if it is given a + // Descriptor d for which: + // d->file()->pool() == DescriptorPool::generated_pool(), + // then it should delegate to MessageFactory::generated_factory() instead + // of constructing a dynamic implementation of the message. In theory there + // is no down side to doing this, so it may become the default in the future. + void SetDelegateToGeneratedFactory(bool enable) { + delegate_to_generated_factory_ = enable; + } + + // implements MessageFactory --------------------------------------- + + // Given a Descriptor, constructs the default (prototype) Message of that + // type. You can then call that message's New() method to construct a + // mutable message of that type. + // + // Calling this method twice with the same Descriptor returns the same + // object. The returned object remains property of the factory and will + // be destroyed when the factory is destroyed. Also, any objects created + // by calling the prototype's New() method share some data with the + // prototype, so these must be destroyed before the DynamicMessageFactory + // is destroyed. + // + // The given descriptor must outlive the returned message, and hence must + // outlive the DynamicMessageFactory. + // + // The method is thread-safe. + const Message* GetPrototype(const Descriptor* type); + + private: + const DescriptorPool* pool_; + bool delegate_to_generated_factory_; + + // This struct just contains a hash_map. We can't #include from + // this header due to hacks needed for hash_map portability in the open source + // release. Namely, stubs/hash.h, which defines hash_map portably, is not a + // public header (for good reason), but dynamic_message.h is, and public + // headers may only #include other public headers. + struct PrototypeMap; + scoped_ptr prototypes_; + mutable Mutex prototypes_mutex_; + + friend class DynamicMessage; + const Message* GetPrototypeNoLock(const Descriptor* type); + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DynamicMessageFactory); +}; + +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_DYNAMIC_MESSAGE_H__ diff --git a/include/google/protobuf/extension_set.h b/include/google/protobuf/extension_set.h new file mode 100644 index 000000000..4ab560c5b --- /dev/null +++ b/include/google/protobuf/extension_set.h @@ -0,0 +1,1007 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// This header is logically internal, but is made public because it is used +// from protocol-compiler-generated code, which may reside in other components. + +#ifndef GOOGLE_PROTOBUF_EXTENSION_SET_H__ +#define GOOGLE_PROTOBUF_EXTENSION_SET_H__ + +#include +#include +#include +#include + + +#include + +namespace google { + +namespace protobuf { + class Descriptor; // descriptor.h + class FieldDescriptor; // descriptor.h + class DescriptorPool; // descriptor.h + class MessageLite; // message_lite.h + class Message; // message.h + class MessageFactory; // message.h + class UnknownFieldSet; // unknown_field_set.h + namespace io { + class CodedInputStream; // coded_stream.h + class CodedOutputStream; // coded_stream.h + } + namespace internal { + class FieldSkipper; // wire_format_lite.h + class RepeatedPtrFieldBase; // repeated_field.h + } + template class RepeatedField; // repeated_field.h + template class RepeatedPtrField; // repeated_field.h +} + +namespace protobuf { +namespace internal { + +// Used to store values of type WireFormatLite::FieldType without having to +// #include wire_format_lite.h. Also, ensures that we use only one byte to +// store these values, which is important to keep the layout of +// ExtensionSet::Extension small. +typedef uint8 FieldType; + +// A function which, given an integer value, returns true if the number +// matches one of the defined values for the corresponding enum type. This +// is used with RegisterEnumExtension, below. +typedef bool EnumValidityFunc(int number); + +// Version of the above which takes an argument. This is needed to deal with +// extensions that are not compiled in. +typedef bool EnumValidityFuncWithArg(const void* arg, int number); + +// Information about a registered extension. +struct ExtensionInfo { + inline ExtensionInfo() {} + inline ExtensionInfo(FieldType type_param, bool isrepeated, bool ispacked) + : type(type_param), is_repeated(isrepeated), is_packed(ispacked), + descriptor(NULL) {} + + FieldType type; + bool is_repeated; + bool is_packed; + + struct EnumValidityCheck { + EnumValidityFuncWithArg* func; + const void* arg; + }; + + union { + EnumValidityCheck enum_validity_check; + const MessageLite* message_prototype; + }; + + // The descriptor for this extension, if one exists and is known. May be + // NULL. Must not be NULL if the descriptor for the extension does not + // live in the same pool as the descriptor for the containing type. + const FieldDescriptor* descriptor; +}; + +// Abstract interface for an object which looks up extension definitions. Used +// when parsing. +class LIBPROTOBUF_EXPORT ExtensionFinder { + public: + virtual ~ExtensionFinder(); + + // Find the extension with the given containing type and number. + virtual bool Find(int number, ExtensionInfo* output) = 0; +}; + +// Implementation of ExtensionFinder which finds extensions defined in .proto +// files which have been compiled into the binary. +class LIBPROTOBUF_EXPORT GeneratedExtensionFinder : public ExtensionFinder { + public: + GeneratedExtensionFinder(const MessageLite* containing_type) + : containing_type_(containing_type) {} + virtual ~GeneratedExtensionFinder() {} + + // Returns true and fills in *output if found, otherwise returns false. + virtual bool Find(int number, ExtensionInfo* output); + + private: + const MessageLite* containing_type_; +}; + +// Note: extension_set_heavy.cc defines DescriptorPoolExtensionFinder for +// finding extensions from a DescriptorPool. + +// This is an internal helper class intended for use within the protocol buffer +// library and generated classes. Clients should not use it directly. Instead, +// use the generated accessors such as GetExtension() of the class being +// extended. +// +// This class manages extensions for a protocol message object. The +// message's HasExtension(), GetExtension(), MutableExtension(), and +// ClearExtension() methods are just thin wrappers around the embedded +// ExtensionSet. When parsing, if a tag number is encountered which is +// inside one of the message type's extension ranges, the tag is passed +// off to the ExtensionSet for parsing. Etc. +class LIBPROTOBUF_EXPORT ExtensionSet { + public: + ExtensionSet(); + ~ExtensionSet(); + + // These are called at startup by protocol-compiler-generated code to + // register known extensions. The registrations are used by ParseField() + // to look up extensions for parsed field numbers. Note that dynamic parsing + // does not use ParseField(); only protocol-compiler-generated parsing + // methods do. + static void RegisterExtension(const MessageLite* containing_type, + int number, FieldType type, + bool is_repeated, bool is_packed); + static void RegisterEnumExtension(const MessageLite* containing_type, + int number, FieldType type, + bool is_repeated, bool is_packed, + EnumValidityFunc* is_valid); + static void RegisterMessageExtension(const MessageLite* containing_type, + int number, FieldType type, + bool is_repeated, bool is_packed, + const MessageLite* prototype); + + // ================================================================= + + // Add all fields which are currently present to the given vector. This + // is useful to implement Reflection::ListFields(). + void AppendToList(const Descriptor* containing_type, + const DescriptorPool* pool, + vector* output) const; + + // ================================================================= + // Accessors + // + // Generated message classes include type-safe templated wrappers around + // these methods. Generally you should use those rather than call these + // directly, unless you are doing low-level memory management. + // + // When calling any of these accessors, the extension number requested + // MUST exist in the DescriptorPool provided to the constructor. Otheriwse, + // the method will fail an assert. Normally, though, you would not call + // these directly; you would either call the generated accessors of your + // message class (e.g. GetExtension()) or you would call the accessors + // of the reflection interface. In both cases, it is impossible to + // trigger this assert failure: the generated accessors only accept + // linked-in extension types as parameters, while the Reflection interface + // requires you to provide the FieldDescriptor describing the extension. + // + // When calling any of these accessors, a protocol-compiler-generated + // implementation of the extension corresponding to the number MUST + // be linked in, and the FieldDescriptor used to refer to it MUST be + // the one generated by that linked-in code. Otherwise, the method will + // die on an assert failure. The message objects returned by the message + // accessors are guaranteed to be of the correct linked-in type. + // + // These methods pretty much match Reflection except that: + // - They're not virtual. + // - They identify fields by number rather than FieldDescriptors. + // - They identify enum values using integers rather than descriptors. + // - Strings provide Mutable() in addition to Set() accessors. + + bool Has(int number) const; + int ExtensionSize(int number) const; // Size of a repeated extension. + int NumExtensions() const; // The number of extensions + FieldType ExtensionType(int number) const; + void ClearExtension(int number); + + // singular fields ------------------------------------------------- + + int32 GetInt32 (int number, int32 default_value) const; + int64 GetInt64 (int number, int64 default_value) const; + uint32 GetUInt32(int number, uint32 default_value) const; + uint64 GetUInt64(int number, uint64 default_value) const; + float GetFloat (int number, float default_value) const; + double GetDouble(int number, double default_value) const; + bool GetBool (int number, bool default_value) const; + int GetEnum (int number, int default_value) const; + const string & GetString (int number, const string& default_value) const; + const MessageLite& GetMessage(int number, + const MessageLite& default_value) const; + const MessageLite& GetMessage(int number, const Descriptor* message_type, + MessageFactory* factory) const; + + // |descriptor| may be NULL so long as it is known that the descriptor for + // the extension lives in the same pool as the descriptor for the containing + // type. +#define desc const FieldDescriptor* descriptor // avoid line wrapping + void SetInt32 (int number, FieldType type, int32 value, desc); + void SetInt64 (int number, FieldType type, int64 value, desc); + void SetUInt32(int number, FieldType type, uint32 value, desc); + void SetUInt64(int number, FieldType type, uint64 value, desc); + void SetFloat (int number, FieldType type, float value, desc); + void SetDouble(int number, FieldType type, double value, desc); + void SetBool (int number, FieldType type, bool value, desc); + void SetEnum (int number, FieldType type, int value, desc); + void SetString(int number, FieldType type, const string& value, desc); + string * MutableString (int number, FieldType type, desc); + MessageLite* MutableMessage(int number, FieldType type, + const MessageLite& prototype, desc); + MessageLite* MutableMessage(const FieldDescriptor* decsriptor, + MessageFactory* factory); + // Adds the given message to the ExtensionSet, taking ownership of the + // message object. Existing message with the same number will be deleted. + // If "message" is NULL, this is equivalent to "ClearExtension(number)". + void SetAllocatedMessage(int number, FieldType type, + const FieldDescriptor* descriptor, + MessageLite* message); + MessageLite* ReleaseMessage(int number, const MessageLite& prototype); + MessageLite* ReleaseMessage(const FieldDescriptor* descriptor, + MessageFactory* factory); +#undef desc + + // repeated fields ------------------------------------------------- + + void* MutableRawRepeatedField(int number); + + int32 GetRepeatedInt32 (int number, int index) const; + int64 GetRepeatedInt64 (int number, int index) const; + uint32 GetRepeatedUInt32(int number, int index) const; + uint64 GetRepeatedUInt64(int number, int index) const; + float GetRepeatedFloat (int number, int index) const; + double GetRepeatedDouble(int number, int index) const; + bool GetRepeatedBool (int number, int index) const; + int GetRepeatedEnum (int number, int index) const; + const string & GetRepeatedString (int number, int index) const; + const MessageLite& GetRepeatedMessage(int number, int index) const; + + void SetRepeatedInt32 (int number, int index, int32 value); + void SetRepeatedInt64 (int number, int index, int64 value); + void SetRepeatedUInt32(int number, int index, uint32 value); + void SetRepeatedUInt64(int number, int index, uint64 value); + void SetRepeatedFloat (int number, int index, float value); + void SetRepeatedDouble(int number, int index, double value); + void SetRepeatedBool (int number, int index, bool value); + void SetRepeatedEnum (int number, int index, int value); + void SetRepeatedString(int number, int index, const string& value); + string * MutableRepeatedString (int number, int index); + MessageLite* MutableRepeatedMessage(int number, int index); + +#define desc const FieldDescriptor* descriptor // avoid line wrapping + void AddInt32 (int number, FieldType type, bool packed, int32 value, desc); + void AddInt64 (int number, FieldType type, bool packed, int64 value, desc); + void AddUInt32(int number, FieldType type, bool packed, uint32 value, desc); + void AddUInt64(int number, FieldType type, bool packed, uint64 value, desc); + void AddFloat (int number, FieldType type, bool packed, float value, desc); + void AddDouble(int number, FieldType type, bool packed, double value, desc); + void AddBool (int number, FieldType type, bool packed, bool value, desc); + void AddEnum (int number, FieldType type, bool packed, int value, desc); + void AddString(int number, FieldType type, const string& value, desc); + string * AddString (int number, FieldType type, desc); + MessageLite* AddMessage(int number, FieldType type, + const MessageLite& prototype, desc); + MessageLite* AddMessage(const FieldDescriptor* descriptor, + MessageFactory* factory); +#undef desc + + void RemoveLast(int number); + MessageLite* ReleaseLast(int number); + void SwapElements(int number, int index1, int index2); + + // ----------------------------------------------------------------- + // TODO(kenton): Hardcore memory management accessors + + // ================================================================= + // convenience methods for implementing methods of Message + // + // These could all be implemented in terms of the other methods of this + // class, but providing them here helps keep the generated code size down. + + void Clear(); + void MergeFrom(const ExtensionSet& other); + void Swap(ExtensionSet* other); + bool IsInitialized() const; + + // Parses a single extension from the input. The input should start out + // positioned immediately after the tag. + bool ParseField(uint32 tag, io::CodedInputStream* input, + ExtensionFinder* extension_finder, + FieldSkipper* field_skipper); + + // Specific versions for lite or full messages (constructs the appropriate + // FieldSkipper automatically). |containing_type| is the default + // instance for the containing message; it is used only to look up the + // extension by number. See RegisterExtension(), above. Unlike the other + // methods of ExtensionSet, this only works for generated message types -- + // it looks up extensions registered using RegisterExtension(). + bool ParseField(uint32 tag, io::CodedInputStream* input, + const MessageLite* containing_type); + bool ParseField(uint32 tag, io::CodedInputStream* input, + const Message* containing_type, + UnknownFieldSet* unknown_fields); + + // Parse an entire message in MessageSet format. Such messages have no + // fields, only extensions. + bool ParseMessageSet(io::CodedInputStream* input, + ExtensionFinder* extension_finder, + FieldSkipper* field_skipper); + + // Specific versions for lite or full messages (constructs the appropriate + // FieldSkipper automatically). + bool ParseMessageSet(io::CodedInputStream* input, + const MessageLite* containing_type); + bool ParseMessageSet(io::CodedInputStream* input, + const Message* containing_type, + UnknownFieldSet* unknown_fields); + + // Write all extension fields with field numbers in the range + // [start_field_number, end_field_number) + // to the output stream, using the cached sizes computed when ByteSize() was + // last called. Note that the range bounds are inclusive-exclusive. + void SerializeWithCachedSizes(int start_field_number, + int end_field_number, + io::CodedOutputStream* output) const; + + // Same as SerializeWithCachedSizes, but without any bounds checking. + // The caller must ensure that target has sufficient capacity for the + // serialized extensions. + // + // Returns a pointer past the last written byte. + uint8* SerializeWithCachedSizesToArray(int start_field_number, + int end_field_number, + uint8* target) const; + + // Like above but serializes in MessageSet format. + void SerializeMessageSetWithCachedSizes(io::CodedOutputStream* output) const; + uint8* SerializeMessageSetWithCachedSizesToArray(uint8* target) const; + + // Returns the total serialized size of all the extensions. + int ByteSize() const; + + // Like ByteSize() but uses MessageSet format. + int MessageSetByteSize() const; + + // Returns (an estimate of) the total number of bytes used for storing the + // extensions in memory, excluding sizeof(*this). If the ExtensionSet is + // for a lite message (and thus possibly contains lite messages), the results + // are undefined (might work, might crash, might corrupt data, might not even + // be linked in). It's up to the protocol compiler to avoid calling this on + // such ExtensionSets (easy enough since lite messages don't implement + // SpaceUsed()). + int SpaceUsedExcludingSelf() const; + + private: + + // Interface of a lazily parsed singular message extension. + class LIBPROTOBUF_EXPORT LazyMessageExtension { + public: + LazyMessageExtension() {} + virtual ~LazyMessageExtension() {} + + virtual LazyMessageExtension* New() const = 0; + virtual const MessageLite& GetMessage( + const MessageLite& prototype) const = 0; + virtual MessageLite* MutableMessage(const MessageLite& prototype) = 0; + virtual void SetAllocatedMessage(MessageLite *message) = 0; + virtual MessageLite* ReleaseMessage(const MessageLite& prototype) = 0; + + virtual bool IsInitialized() const = 0; + virtual int ByteSize() const = 0; + virtual int SpaceUsed() const = 0; + + virtual void MergeFrom(const LazyMessageExtension& other) = 0; + virtual void Clear() = 0; + + virtual bool ReadMessage(const MessageLite& prototype, + io::CodedInputStream* input) = 0; + virtual void WriteMessage(int number, + io::CodedOutputStream* output) const = 0; + virtual uint8* WriteMessageToArray(int number, uint8* target) const = 0; + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(LazyMessageExtension); + }; + struct Extension { + // The order of these fields packs Extension into 24 bytes when using 8 + // byte alignment. Consider this when adding or removing fields here. + union { + int32 int32_value; + int64 int64_value; + uint32 uint32_value; + uint64 uint64_value; + float float_value; + double double_value; + bool bool_value; + int enum_value; + string* string_value; + MessageLite* message_value; + LazyMessageExtension* lazymessage_value; + + RepeatedField * repeated_int32_value; + RepeatedField * repeated_int64_value; + RepeatedField * repeated_uint32_value; + RepeatedField * repeated_uint64_value; + RepeatedField * repeated_float_value; + RepeatedField * repeated_double_value; + RepeatedField * repeated_bool_value; + RepeatedField * repeated_enum_value; + RepeatedPtrField* repeated_string_value; + RepeatedPtrField* repeated_message_value; + }; + + FieldType type; + bool is_repeated; + + // For singular types, indicates if the extension is "cleared". This + // happens when an extension is set and then later cleared by the caller. + // We want to keep the Extension object around for reuse, so instead of + // removing it from the map, we just set is_cleared = true. This has no + // meaning for repeated types; for those, the size of the RepeatedField + // simply becomes zero when cleared. + bool is_cleared : 4; + + // For singular message types, indicates whether lazy parsing is enabled + // for this extension. This field is only valid when type == TYPE_MESSAGE + // and !is_repeated because we only support lazy parsing for singular + // message types currently. If is_lazy = true, the extension is stored in + // lazymessage_value. Otherwise, the extension will be message_value. + bool is_lazy : 4; + + // For repeated types, this indicates if the [packed=true] option is set. + bool is_packed; + + // For packed fields, the size of the packed data is recorded here when + // ByteSize() is called then used during serialization. + // TODO(kenton): Use atomic when C++ supports it. + mutable int cached_size; + + // The descriptor for this extension, if one exists and is known. May be + // NULL. Must not be NULL if the descriptor for the extension does not + // live in the same pool as the descriptor for the containing type. + const FieldDescriptor* descriptor; + + // Some helper methods for operations on a single Extension. + void SerializeFieldWithCachedSizes( + int number, + io::CodedOutputStream* output) const; + uint8* SerializeFieldWithCachedSizesToArray( + int number, + uint8* target) const; + void SerializeMessageSetItemWithCachedSizes( + int number, + io::CodedOutputStream* output) const; + uint8* SerializeMessageSetItemWithCachedSizesToArray( + int number, + uint8* target) const; + int ByteSize(int number) const; + int MessageSetItemByteSize(int number) const; + void Clear(); + int GetSize() const; + void Free(); + int SpaceUsedExcludingSelf() const; + }; + + + // Returns true and fills field_number and extension if extension is found. + bool FindExtensionInfoFromTag(uint32 tag, ExtensionFinder* extension_finder, + int* field_number, ExtensionInfo* extension); + + // Parses a single extension from the input. The input should start out + // positioned immediately after the wire tag. This method is called in + // ParseField() after field number is extracted from the wire tag and + // ExtensionInfo is found by the field number. + bool ParseFieldWithExtensionInfo(int field_number, + const ExtensionInfo& extension, + io::CodedInputStream* input, + FieldSkipper* field_skipper); + + // Like ParseField(), but this method may parse singular message extensions + // lazily depending on the value of FLAGS_eagerly_parse_message_sets. + bool ParseFieldMaybeLazily(uint32 tag, io::CodedInputStream* input, + ExtensionFinder* extension_finder, + FieldSkipper* field_skipper); + + // Gets the extension with the given number, creating it if it does not + // already exist. Returns true if the extension did not already exist. + bool MaybeNewExtension(int number, const FieldDescriptor* descriptor, + Extension** result); + + // Parse a single MessageSet item -- called just after the item group start + // tag has been read. + bool ParseMessageSetItem(io::CodedInputStream* input, + ExtensionFinder* extension_finder, + FieldSkipper* field_skipper); + + + // Hack: RepeatedPtrFieldBase declares ExtensionSet as a friend. This + // friendship should automatically extend to ExtensionSet::Extension, but + // unfortunately some older compilers (e.g. GCC 3.4.4) do not implement this + // correctly. So, we must provide helpers for calling methods of that + // class. + + // Defined in extension_set_heavy.cc. + static inline int RepeatedMessage_SpaceUsedExcludingSelf( + RepeatedPtrFieldBase* field); + + // The Extension struct is small enough to be passed by value, so we use it + // directly as the value type in the map rather than use pointers. We use + // a map rather than hash_map here because we expect most ExtensionSets will + // only contain a small number of extensions whereas hash_map is optimized + // for 100 elements or more. Also, we want AppendToList() to order fields + // by field number. + std::map extensions_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ExtensionSet); +}; + +// These are just for convenience... +inline void ExtensionSet::SetString(int number, FieldType type, + const string& value, + const FieldDescriptor* descriptor) { + MutableString(number, type, descriptor)->assign(value); +} +inline void ExtensionSet::SetRepeatedString(int number, int index, + const string& value) { + MutableRepeatedString(number, index)->assign(value); +} +inline void ExtensionSet::AddString(int number, FieldType type, + const string& value, + const FieldDescriptor* descriptor) { + AddString(number, type, descriptor)->assign(value); +} + +// =================================================================== +// Glue for generated extension accessors + +// ------------------------------------------------------------------- +// Template magic + +// First we have a set of classes representing "type traits" for different +// field types. A type traits class knows how to implement basic accessors +// for extensions of a particular type given an ExtensionSet. The signature +// for a type traits class looks like this: +// +// class TypeTraits { +// public: +// typedef ? ConstType; +// typedef ? MutableType; +// +// static inline ConstType Get(int number, const ExtensionSet& set); +// static inline void Set(int number, ConstType value, ExtensionSet* set); +// static inline MutableType Mutable(int number, ExtensionSet* set); +// +// // Variants for repeated fields. +// static inline ConstType Get(int number, const ExtensionSet& set, +// int index); +// static inline void Set(int number, int index, +// ConstType value, ExtensionSet* set); +// static inline MutableType Mutable(int number, int index, +// ExtensionSet* set); +// static inline void Add(int number, ConstType value, ExtensionSet* set); +// static inline MutableType Add(int number, ExtensionSet* set); +// }; +// +// Not all of these methods make sense for all field types. For example, the +// "Mutable" methods only make sense for strings and messages, and the +// repeated methods only make sense for repeated types. So, each type +// traits class implements only the set of methods from this signature that it +// actually supports. This will cause a compiler error if the user tries to +// access an extension using a method that doesn't make sense for its type. +// For example, if "foo" is an extension of type "optional int32", then if you +// try to write code like: +// my_message.MutableExtension(foo) +// you will get a compile error because PrimitiveTypeTraits does not +// have a "Mutable()" method. + +// ------------------------------------------------------------------- +// PrimitiveTypeTraits + +// Since the ExtensionSet has different methods for each primitive type, +// we must explicitly define the methods of the type traits class for each +// known type. +template +class PrimitiveTypeTraits { + public: + typedef Type ConstType; + + static inline ConstType Get(int number, const ExtensionSet& set, + ConstType default_value); + static inline void Set(int number, FieldType field_type, + ConstType value, ExtensionSet* set); +}; + +template +class RepeatedPrimitiveTypeTraits { + public: + typedef Type ConstType; + + static inline Type Get(int number, const ExtensionSet& set, int index); + static inline void Set(int number, int index, Type value, ExtensionSet* set); + static inline void Add(int number, FieldType field_type, + bool is_packed, Type value, ExtensionSet* set); +}; + +#define PROTOBUF_DEFINE_PRIMITIVE_TYPE(TYPE, METHOD) \ +template<> inline TYPE PrimitiveTypeTraits::Get( \ + int number, const ExtensionSet& set, TYPE default_value) { \ + return set.Get##METHOD(number, default_value); \ +} \ +template<> inline void PrimitiveTypeTraits::Set( \ + int number, FieldType field_type, TYPE value, ExtensionSet* set) { \ + set->Set##METHOD(number, field_type, value, NULL); \ +} \ + \ +template<> inline TYPE RepeatedPrimitiveTypeTraits::Get( \ + int number, const ExtensionSet& set, int index) { \ + return set.GetRepeated##METHOD(number, index); \ +} \ +template<> inline void RepeatedPrimitiveTypeTraits::Set( \ + int number, int index, TYPE value, ExtensionSet* set) { \ + set->SetRepeated##METHOD(number, index, value); \ +} \ +template<> inline void RepeatedPrimitiveTypeTraits::Add( \ + int number, FieldType field_type, bool is_packed, \ + TYPE value, ExtensionSet* set) { \ + set->Add##METHOD(number, field_type, is_packed, value, NULL); \ +} + +PROTOBUF_DEFINE_PRIMITIVE_TYPE( int32, Int32) +PROTOBUF_DEFINE_PRIMITIVE_TYPE( int64, Int64) +PROTOBUF_DEFINE_PRIMITIVE_TYPE(uint32, UInt32) +PROTOBUF_DEFINE_PRIMITIVE_TYPE(uint64, UInt64) +PROTOBUF_DEFINE_PRIMITIVE_TYPE( float, Float) +PROTOBUF_DEFINE_PRIMITIVE_TYPE(double, Double) +PROTOBUF_DEFINE_PRIMITIVE_TYPE( bool, Bool) + +#undef PROTOBUF_DEFINE_PRIMITIVE_TYPE + +// ------------------------------------------------------------------- +// StringTypeTraits + +// Strings support both Set() and Mutable(). +class LIBPROTOBUF_EXPORT StringTypeTraits { + public: + typedef const string& ConstType; + typedef string* MutableType; + + static inline const string& Get(int number, const ExtensionSet& set, + ConstType default_value) { + return set.GetString(number, default_value); + } + static inline void Set(int number, FieldType field_type, + const string& value, ExtensionSet* set) { + set->SetString(number, field_type, value, NULL); + } + static inline string* Mutable(int number, FieldType field_type, + ExtensionSet* set) { + return set->MutableString(number, field_type, NULL); + } +}; + +class LIBPROTOBUF_EXPORT RepeatedStringTypeTraits { + public: + typedef const string& ConstType; + typedef string* MutableType; + + static inline const string& Get(int number, const ExtensionSet& set, + int index) { + return set.GetRepeatedString(number, index); + } + static inline void Set(int number, int index, + const string& value, ExtensionSet* set) { + set->SetRepeatedString(number, index, value); + } + static inline string* Mutable(int number, int index, ExtensionSet* set) { + return set->MutableRepeatedString(number, index); + } + static inline void Add(int number, FieldType field_type, + bool /*is_packed*/, const string& value, + ExtensionSet* set) { + set->AddString(number, field_type, value, NULL); + } + static inline string* Add(int number, FieldType field_type, + ExtensionSet* set) { + return set->AddString(number, field_type, NULL); + } +}; + +// ------------------------------------------------------------------- +// EnumTypeTraits + +// ExtensionSet represents enums using integers internally, so we have to +// static_cast around. +template +class EnumTypeTraits { + public: + typedef Type ConstType; + + static inline ConstType Get(int number, const ExtensionSet& set, + ConstType default_value) { + return static_cast(set.GetEnum(number, default_value)); + } + static inline void Set(int number, FieldType field_type, + ConstType value, ExtensionSet* set) { + GOOGLE_DCHECK(IsValid(value)); + set->SetEnum(number, field_type, value, NULL); + } +}; + +template +class RepeatedEnumTypeTraits { + public: + typedef Type ConstType; + + static inline ConstType Get(int number, const ExtensionSet& set, int index) { + return static_cast(set.GetRepeatedEnum(number, index)); + } + static inline void Set(int number, int index, + ConstType value, ExtensionSet* set) { + GOOGLE_DCHECK(IsValid(value)); + set->SetRepeatedEnum(number, index, value); + } + static inline void Add(int number, FieldType field_type, + bool is_packed, ConstType value, ExtensionSet* set) { + GOOGLE_DCHECK(IsValid(value)); + set->AddEnum(number, field_type, is_packed, value, NULL); + } +}; + +// ------------------------------------------------------------------- +// MessageTypeTraits + +// ExtensionSet guarantees that when manipulating extensions with message +// types, the implementation used will be the compiled-in class representing +// that type. So, we can static_cast down to the exact type we expect. +template +class MessageTypeTraits { + public: + typedef const Type& ConstType; + typedef Type* MutableType; + + static inline ConstType Get(int number, const ExtensionSet& set, + ConstType default_value) { + return static_cast( + set.GetMessage(number, default_value)); + } + static inline MutableType Mutable(int number, FieldType field_type, + ExtensionSet* set) { + return static_cast( + set->MutableMessage(number, field_type, Type::default_instance(), NULL)); + } + static inline void SetAllocated(int number, FieldType field_type, + MutableType message, ExtensionSet* set) { + set->SetAllocatedMessage(number, field_type, NULL, message); + } + static inline MutableType Release(int number, FieldType field_type, + ExtensionSet* set) { + return static_cast(set->ReleaseMessage( + number, Type::default_instance())); + } +}; + +template +class RepeatedMessageTypeTraits { + public: + typedef const Type& ConstType; + typedef Type* MutableType; + + static inline ConstType Get(int number, const ExtensionSet& set, int index) { + return static_cast(set.GetRepeatedMessage(number, index)); + } + static inline MutableType Mutable(int number, int index, ExtensionSet* set) { + return static_cast(set->MutableRepeatedMessage(number, index)); + } + static inline MutableType Add(int number, FieldType field_type, + ExtensionSet* set) { + return static_cast( + set->AddMessage(number, field_type, Type::default_instance(), NULL)); + } +}; + +// ------------------------------------------------------------------- +// ExtensionIdentifier + +// This is the type of actual extension objects. E.g. if you have: +// extends Foo with optional int32 bar = 1234; +// then "bar" will be defined in C++ as: +// ExtensionIdentifier, 1, false> bar(1234); +// +// Note that we could, in theory, supply the field number as a template +// parameter, and thus make an instance of ExtensionIdentifier have no +// actual contents. However, if we did that, then using at extension +// identifier would not necessarily cause the compiler to output any sort +// of reference to any simple defined in the extension's .pb.o file. Some +// linkers will actually drop object files that are not explicitly referenced, +// but that would be bad because it would cause this extension to not be +// registered at static initialization, and therefore using it would crash. + +template +class ExtensionIdentifier { + public: + typedef TypeTraitsType TypeTraits; + typedef ExtendeeType Extendee; + + ExtensionIdentifier(int _number, typename TypeTraits::ConstType _default_value) + : number_(_number), default_value_(_default_value) {} + inline int number() const { return number_; } + typename TypeTraits::ConstType default_value() const { + return default_value_; + } + + private: + const int number_; + typename TypeTraits::ConstType default_value_; +}; + +// ------------------------------------------------------------------- +// Generated accessors + +// This macro should be expanded in the context of a generated type which +// has extensions. +// +// We use "_proto_TypeTraits" as a type name below because "TypeTraits" +// causes problems if the class has a nested message or enum type with that +// name and "_TypeTraits" is technically reserved for the C++ library since +// it starts with an underscore followed by a capital letter. +// +// For similar reason, we use "_field_type" and "_is_packed" as parameter names +// below, so that "field_type" and "is_packed" can be used as field names. +#define GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(CLASSNAME) \ + /* Has, Size, Clear */ \ + template \ + inline bool HasExtension( \ + const ::google::protobuf::internal::ExtensionIdentifier< \ + CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id) const { \ + return _extensions_.Has(id.number()); \ + } \ + \ + template \ + inline void ClearExtension( \ + const ::google::protobuf::internal::ExtensionIdentifier< \ + CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id) { \ + _extensions_.ClearExtension(id.number()); \ + } \ + \ + template \ + inline int ExtensionSize( \ + const ::google::protobuf::internal::ExtensionIdentifier< \ + CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id) const { \ + return _extensions_.ExtensionSize(id.number()); \ + } \ + \ + /* Singular accessors */ \ + template \ + inline typename _proto_TypeTraits::ConstType GetExtension( \ + const ::google::protobuf::internal::ExtensionIdentifier< \ + CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id) const { \ + return _proto_TypeTraits::Get(id.number(), _extensions_, \ + id.default_value()); \ + } \ + \ + template \ + inline typename _proto_TypeTraits::MutableType MutableExtension( \ + const ::google::protobuf::internal::ExtensionIdentifier< \ + CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id) { \ + return _proto_TypeTraits::Mutable(id.number(), _field_type, \ + &_extensions_); \ + } \ + \ + template \ + inline void SetExtension( \ + const ::google::protobuf::internal::ExtensionIdentifier< \ + CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id, \ + typename _proto_TypeTraits::ConstType value) { \ + _proto_TypeTraits::Set(id.number(), _field_type, value, &_extensions_); \ + } \ + \ + template \ + inline void SetAllocatedExtension( \ + const ::google::protobuf::internal::ExtensionIdentifier< \ + CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id, \ + typename _proto_TypeTraits::MutableType value) { \ + _proto_TypeTraits::SetAllocated(id.number(), _field_type, \ + value, &_extensions_); \ + } \ + template \ + inline typename _proto_TypeTraits::MutableType ReleaseExtension( \ + const ::google::protobuf::internal::ExtensionIdentifier< \ + CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id) { \ + return _proto_TypeTraits::Release(id.number(), _field_type, \ + &_extensions_); \ + } \ + \ + /* Repeated accessors */ \ + template \ + inline typename _proto_TypeTraits::ConstType GetExtension( \ + const ::google::protobuf::internal::ExtensionIdentifier< \ + CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id, \ + int index) const { \ + return _proto_TypeTraits::Get(id.number(), _extensions_, index); \ + } \ + \ + template \ + inline typename _proto_TypeTraits::MutableType MutableExtension( \ + const ::google::protobuf::internal::ExtensionIdentifier< \ + CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id, \ + int index) { \ + return _proto_TypeTraits::Mutable(id.number(), index, &_extensions_); \ + } \ + \ + template \ + inline void SetExtension( \ + const ::google::protobuf::internal::ExtensionIdentifier< \ + CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id, \ + int index, typename _proto_TypeTraits::ConstType value) { \ + _proto_TypeTraits::Set(id.number(), index, value, &_extensions_); \ + } \ + \ + template \ + inline typename _proto_TypeTraits::MutableType AddExtension( \ + const ::google::protobuf::internal::ExtensionIdentifier< \ + CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id) { \ + return _proto_TypeTraits::Add(id.number(), _field_type, &_extensions_); \ + } \ + \ + template \ + inline void AddExtension( \ + const ::google::protobuf::internal::ExtensionIdentifier< \ + CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id, \ + typename _proto_TypeTraits::ConstType value) { \ + _proto_TypeTraits::Add(id.number(), _field_type, _is_packed, \ + value, &_extensions_); \ + } + +} // namespace internal +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_EXTENSION_SET_H__ diff --git a/include/google/protobuf/generated_enum_reflection.h b/include/google/protobuf/generated_enum_reflection.h new file mode 100644 index 000000000..a09a540bf --- /dev/null +++ b/include/google/protobuf/generated_enum_reflection.h @@ -0,0 +1,85 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: jasonh@google.com (Jason Hsueh) +// +// This header is logically internal, but is made public because it is used +// from protocol-compiler-generated code, which may reside in other components. +// It provides reflection support for generated enums, and is included in +// generated .pb.h files and should have minimal dependencies. The methods are +// implemented in generated_message_reflection.cc. + +#ifndef GOOGLE_PROTOBUF_GENERATED_ENUM_REFLECTION_H__ +#define GOOGLE_PROTOBUF_GENERATED_ENUM_REFLECTION_H__ + +#include + +namespace google { +namespace protobuf { + class EnumDescriptor; +} // namespace protobuf + +namespace protobuf { + +// Returns the EnumDescriptor for enum type E, which must be a +// proto-declared enum type. Code generated by the protocol compiler +// will include specializations of this template for each enum type declared. +template +const EnumDescriptor* GetEnumDescriptor(); + +namespace internal { + +// Helper for EnumType_Parse functions: try to parse the string 'name' as an +// enum name of the given type, returning true and filling in value on success, +// or returning false and leaving value unchanged on failure. +LIBPROTOBUF_EXPORT bool ParseNamedEnum(const EnumDescriptor* descriptor, + const string& name, + int* value); + +template +bool ParseNamedEnum(const EnumDescriptor* descriptor, + const string& name, + EnumType* value) { + int tmp; + if (!ParseNamedEnum(descriptor, name, &tmp)) return false; + *value = static_cast(tmp); + return true; +} + +// Just a wrapper around printing the name of a value. The main point of this +// function is not to be inlined, so that you can do this without including +// descriptor.h. +LIBPROTOBUF_EXPORT const string& NameOfEnum(const EnumDescriptor* descriptor, int value); + +} // namespace internal +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_GENERATED_ENUM_REFLECTION_H__ diff --git a/include/google/protobuf/generated_message_reflection.h b/include/google/protobuf/generated_message_reflection.h new file mode 100644 index 000000000..c1c142fa8 --- /dev/null +++ b/include/google/protobuf/generated_message_reflection.h @@ -0,0 +1,419 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// This header is logically internal, but is made public because it is used +// from protocol-compiler-generated code, which may reside in other components. + +#ifndef GOOGLE_PROTOBUF_GENERATED_MESSAGE_REFLECTION_H__ +#define GOOGLE_PROTOBUF_GENERATED_MESSAGE_REFLECTION_H__ + +#include +#include +#include +// TODO(jasonh): Remove this once the compiler change to directly include this +// is released to components. +#include +#include +#include + + +namespace google { +namespace upb { +namespace google_opensource { +class GMR_Handlers; +} // namespace google_opensource +} // namespace upb + +namespace protobuf { + class DescriptorPool; +} + +namespace protobuf { +namespace internal { + +// Defined in this file. +class GeneratedMessageReflection; + +// Defined in other files. +class ExtensionSet; // extension_set.h + +// THIS CLASS IS NOT INTENDED FOR DIRECT USE. It is intended for use +// by generated code. This class is just a big hack that reduces code +// size. +// +// A GeneratedMessageReflection is an implementation of Reflection +// which expects all fields to be backed by simple variables located in +// memory. The locations are given using a base pointer and a set of +// offsets. +// +// It is required that the user represents fields of each type in a standard +// way, so that GeneratedMessageReflection can cast the void* pointer to +// the appropriate type. For primitive fields and string fields, each field +// should be represented using the obvious C++ primitive type. Enums and +// Messages are different: +// - Singular Message fields are stored as a pointer to a Message. These +// should start out NULL, except for in the default instance where they +// should start out pointing to other default instances. +// - Enum fields are stored as an int. This int must always contain +// a valid value, such that EnumDescriptor::FindValueByNumber() would +// not return NULL. +// - Repeated fields are stored as RepeatedFields or RepeatedPtrFields +// of whatever type the individual field would be. Strings and +// Messages use RepeatedPtrFields while everything else uses +// RepeatedFields. +class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection { + public: + // Constructs a GeneratedMessageReflection. + // Parameters: + // descriptor: The descriptor for the message type being implemented. + // default_instance: The default instance of the message. This is only + // used to obtain pointers to default instances of embedded + // messages, which GetMessage() will return if the particular + // sub-message has not been initialized yet. (Thus, all + // embedded message fields *must* have non-NULL pointers + // in the default instance.) + // offsets: An array of ints giving the byte offsets, relative to + // the start of the message object, of each field. These can + // be computed at compile time using the + // GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET() macro, defined + // below. + // has_bits_offset: Offset in the message of an array of uint32s of size + // descriptor->field_count()/32, rounded up. This is a + // bitfield where each bit indicates whether or not the + // corresponding field of the message has been initialized. + // The bit for field index i is obtained by the expression: + // has_bits[i / 32] & (1 << (i % 32)) + // unknown_fields_offset: Offset in the message of the UnknownFieldSet for + // the message. + // extensions_offset: Offset in the message of the ExtensionSet for the + // message, or -1 if the message type has no extension + // ranges. + // pool: DescriptorPool to search for extension definitions. Only + // used by FindKnownExtensionByName() and + // FindKnownExtensionByNumber(). + // factory: MessageFactory to use to construct extension messages. + // object_size: The size of a message object of this type, as measured + // by sizeof(). + GeneratedMessageReflection(const Descriptor* descriptor, + const Message* default_instance, + const int offsets[], + int has_bits_offset, + int unknown_fields_offset, + int extensions_offset, + const DescriptorPool* pool, + MessageFactory* factory, + int object_size); + ~GeneratedMessageReflection(); + + // implements Reflection ------------------------------------------- + + const UnknownFieldSet& GetUnknownFields(const Message& message) const; + UnknownFieldSet* MutableUnknownFields(Message* message) const; + + int SpaceUsed(const Message& message) const; + + bool HasField(const Message& message, const FieldDescriptor* field) const; + int FieldSize(const Message& message, const FieldDescriptor* field) const; + void ClearField(Message* message, const FieldDescriptor* field) const; + void RemoveLast(Message* message, const FieldDescriptor* field) const; + Message* ReleaseLast(Message* message, const FieldDescriptor* field) const; + void Swap(Message* message1, Message* message2) const; + void SwapElements(Message* message, const FieldDescriptor* field, + int index1, int index2) const; + void ListFields(const Message& message, + vector* output) const; + + int32 GetInt32 (const Message& message, + const FieldDescriptor* field) const; + int64 GetInt64 (const Message& message, + const FieldDescriptor* field) const; + uint32 GetUInt32(const Message& message, + const FieldDescriptor* field) const; + uint64 GetUInt64(const Message& message, + const FieldDescriptor* field) const; + float GetFloat (const Message& message, + const FieldDescriptor* field) const; + double GetDouble(const Message& message, + const FieldDescriptor* field) const; + bool GetBool (const Message& message, + const FieldDescriptor* field) const; + string GetString(const Message& message, + const FieldDescriptor* field) const; + const string& GetStringReference(const Message& message, + const FieldDescriptor* field, + string* scratch) const; + const EnumValueDescriptor* GetEnum(const Message& message, + const FieldDescriptor* field) const; + const Message& GetMessage(const Message& message, + const FieldDescriptor* field, + MessageFactory* factory = NULL) const; + + void SetInt32 (Message* message, + const FieldDescriptor* field, int32 value) const; + void SetInt64 (Message* message, + const FieldDescriptor* field, int64 value) const; + void SetUInt32(Message* message, + const FieldDescriptor* field, uint32 value) const; + void SetUInt64(Message* message, + const FieldDescriptor* field, uint64 value) const; + void SetFloat (Message* message, + const FieldDescriptor* field, float value) const; + void SetDouble(Message* message, + const FieldDescriptor* field, double value) const; + void SetBool (Message* message, + const FieldDescriptor* field, bool value) const; + void SetString(Message* message, + const FieldDescriptor* field, + const string& value) const; + void SetEnum (Message* message, const FieldDescriptor* field, + const EnumValueDescriptor* value) const; + Message* MutableMessage(Message* message, const FieldDescriptor* field, + MessageFactory* factory = NULL) const; + Message* ReleaseMessage(Message* message, const FieldDescriptor* field, + MessageFactory* factory = NULL) const; + + int32 GetRepeatedInt32 (const Message& message, + const FieldDescriptor* field, int index) const; + int64 GetRepeatedInt64 (const Message& message, + const FieldDescriptor* field, int index) const; + uint32 GetRepeatedUInt32(const Message& message, + const FieldDescriptor* field, int index) const; + uint64 GetRepeatedUInt64(const Message& message, + const FieldDescriptor* field, int index) const; + float GetRepeatedFloat (const Message& message, + const FieldDescriptor* field, int index) const; + double GetRepeatedDouble(const Message& message, + const FieldDescriptor* field, int index) const; + bool GetRepeatedBool (const Message& message, + const FieldDescriptor* field, int index) const; + string GetRepeatedString(const Message& message, + const FieldDescriptor* field, int index) const; + const string& GetRepeatedStringReference(const Message& message, + const FieldDescriptor* field, + int index, string* scratch) const; + const EnumValueDescriptor* GetRepeatedEnum(const Message& message, + const FieldDescriptor* field, + int index) const; + const Message& GetRepeatedMessage(const Message& message, + const FieldDescriptor* field, + int index) const; + + // Set the value of a field. + void SetRepeatedInt32 (Message* message, + const FieldDescriptor* field, int index, int32 value) const; + void SetRepeatedInt64 (Message* message, + const FieldDescriptor* field, int index, int64 value) const; + void SetRepeatedUInt32(Message* message, + const FieldDescriptor* field, int index, uint32 value) const; + void SetRepeatedUInt64(Message* message, + const FieldDescriptor* field, int index, uint64 value) const; + void SetRepeatedFloat (Message* message, + const FieldDescriptor* field, int index, float value) const; + void SetRepeatedDouble(Message* message, + const FieldDescriptor* field, int index, double value) const; + void SetRepeatedBool (Message* message, + const FieldDescriptor* field, int index, bool value) const; + void SetRepeatedString(Message* message, + const FieldDescriptor* field, int index, + const string& value) const; + void SetRepeatedEnum(Message* message, const FieldDescriptor* field, + int index, const EnumValueDescriptor* value) const; + // Get a mutable pointer to a field with a message type. + Message* MutableRepeatedMessage(Message* message, + const FieldDescriptor* field, + int index) const; + + void AddInt32 (Message* message, + const FieldDescriptor* field, int32 value) const; + void AddInt64 (Message* message, + const FieldDescriptor* field, int64 value) const; + void AddUInt32(Message* message, + const FieldDescriptor* field, uint32 value) const; + void AddUInt64(Message* message, + const FieldDescriptor* field, uint64 value) const; + void AddFloat (Message* message, + const FieldDescriptor* field, float value) const; + void AddDouble(Message* message, + const FieldDescriptor* field, double value) const; + void AddBool (Message* message, + const FieldDescriptor* field, bool value) const; + void AddString(Message* message, + const FieldDescriptor* field, const string& value) const; + void AddEnum(Message* message, + const FieldDescriptor* field, + const EnumValueDescriptor* value) const; + Message* AddMessage(Message* message, const FieldDescriptor* field, + MessageFactory* factory = NULL) const; + + const FieldDescriptor* FindKnownExtensionByName(const string& name) const; + const FieldDescriptor* FindKnownExtensionByNumber(int number) const; + + protected: + virtual void* MutableRawRepeatedField( + Message* message, const FieldDescriptor* field, FieldDescriptor::CppType, + int ctype, const Descriptor* desc) const; + + private: + friend class GeneratedMessage; + + // To parse directly into a proto2 generated class, the class GMR_Handlers + // needs access to member offsets and hasbits. + friend class LIBPROTOBUF_EXPORT upb::google_opensource::GMR_Handlers; + + const Descriptor* descriptor_; + const Message* default_instance_; + const int* offsets_; + + int has_bits_offset_; + int unknown_fields_offset_; + int extensions_offset_; + int object_size_; + + const DescriptorPool* descriptor_pool_; + MessageFactory* message_factory_; + + template + inline const Type& GetRaw(const Message& message, + const FieldDescriptor* field) const; + template + inline Type* MutableRaw(Message* message, + const FieldDescriptor* field) const; + template + inline const Type& DefaultRaw(const FieldDescriptor* field) const; + + inline const uint32* GetHasBits(const Message& message) const; + inline uint32* MutableHasBits(Message* message) const; + inline const ExtensionSet& GetExtensionSet(const Message& message) const; + inline ExtensionSet* MutableExtensionSet(Message* message) const; + + inline bool HasBit(const Message& message, + const FieldDescriptor* field) const; + inline void SetBit(Message* message, + const FieldDescriptor* field) const; + inline void ClearBit(Message* message, + const FieldDescriptor* field) const; + + template + inline const Type& GetField(const Message& message, + const FieldDescriptor* field) const; + template + inline void SetField(Message* message, + const FieldDescriptor* field, const Type& value) const; + template + inline Type* MutableField(Message* message, + const FieldDescriptor* field) const; + template + inline const Type& GetRepeatedField(const Message& message, + const FieldDescriptor* field, + int index) const; + template + inline const Type& GetRepeatedPtrField(const Message& message, + const FieldDescriptor* field, + int index) const; + template + inline void SetRepeatedField(Message* message, + const FieldDescriptor* field, int index, + Type value) const; + template + inline Type* MutableRepeatedField(Message* message, + const FieldDescriptor* field, + int index) const; + template + inline void AddField(Message* message, + const FieldDescriptor* field, const Type& value) const; + template + inline Type* AddField(Message* message, + const FieldDescriptor* field) const; + + int GetExtensionNumberOrDie(const Descriptor* type) const; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(GeneratedMessageReflection); +}; + +// Returns the offset of the given field within the given aggregate type. +// This is equivalent to the ANSI C offsetof() macro. However, according +// to the C++ standard, offsetof() only works on POD types, and GCC +// enforces this requirement with a warning. In practice, this rule is +// unnecessarily strict; there is probably no compiler or platform on +// which the offsets of the direct fields of a class are non-constant. +// Fields inherited from superclasses *can* have non-constant offsets, +// but that's not what this macro will be used for. +// +// Note that we calculate relative to the pointer value 16 here since if we +// just use zero, GCC complains about dereferencing a NULL pointer. We +// choose 16 rather than some other number just in case the compiler would +// be confused by an unaligned pointer. +#define GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(TYPE, FIELD) \ + static_cast( \ + reinterpret_cast( \ + &reinterpret_cast(16)->FIELD) - \ + reinterpret_cast(16)) + +// There are some places in proto2 where dynamic_cast would be useful as an +// optimization. For example, take Message::MergeFrom(const Message& other). +// For a given generated message FooMessage, we generate these two methods: +// void MergeFrom(const FooMessage& other); +// void MergeFrom(const Message& other); +// The former method can be implemented directly in terms of FooMessage's +// inline accessors, but the latter method must work with the reflection +// interface. However, if the parameter to the latter method is actually of +// type FooMessage, then we'd like to be able to just call the other method +// as an optimization. So, we use dynamic_cast to check this. +// +// That said, dynamic_cast requires RTTI, which many people like to disable +// for performance and code size reasons. When RTTI is not available, we +// still need to produce correct results. So, in this case we have to fall +// back to using reflection, which is what we would have done anyway if the +// objects were not of the exact same class. +// +// dynamic_cast_if_available() implements this logic. If RTTI is +// enabled, it does a dynamic_cast. If RTTI is disabled, it just returns +// NULL. +// +// If you need to compile without RTTI, simply #define GOOGLE_PROTOBUF_NO_RTTI. +// On MSVC, this should be detected automatically. +template +inline To dynamic_cast_if_available(From from) { +#if defined(GOOGLE_PROTOBUF_NO_RTTI) || (defined(_MSC_VER)&&!defined(_CPPRTTI)) + return NULL; +#else + return dynamic_cast(from); +#endif +} + +} // namespace internal +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_GENERATED_MESSAGE_REFLECTION_H__ diff --git a/include/google/protobuf/generated_message_util.h b/include/google/protobuf/generated_message_util.h new file mode 100644 index 000000000..b2fb8f0be --- /dev/null +++ b/include/google/protobuf/generated_message_util.h @@ -0,0 +1,77 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// This file contains miscellaneous helper code used by generated code -- +// including lite types -- but which should not be used directly by users. + +#ifndef GOOGLE_PROTOBUF_GENERATED_MESSAGE_UTIL_H__ +#define GOOGLE_PROTOBUF_GENERATED_MESSAGE_UTIL_H__ + +#include + +#include +namespace google { +namespace protobuf { +namespace internal { + +// Annotation for the compiler to emit a deprecation message if a field marked +// with option 'deprecated=true' is used in the code, or for other things in +// generated code which are deprecated. +// +// For internal use in the pb.cc files, deprecation warnings are suppressed +// there. +#undef DEPRECATED_PROTOBUF_FIELD +#define PROTOBUF_DEPRECATED + + +// Constants for special floating point values. +LIBPROTOBUF_EXPORT double Infinity(); +LIBPROTOBUF_EXPORT double NaN(); + +// Constant used for empty default strings. +LIBPROTOBUF_EXPORT extern const ::std::string kEmptyString; + +// Defined in generated_message_reflection.cc -- not actually part of the lite +// library. +// +// TODO(jasonh): The various callers get this declaration from a variety of +// places: probably in most cases repeated_field.h. Clean these up so they all +// get the declaration from this file. +LIBPROTOBUF_EXPORT int StringSpaceUsedExcludingSelf(const string& str); + +} // namespace internal +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_GENERATED_MESSAGE_UTIL_H__ diff --git a/include/google/protobuf/io/coded_stream.h b/include/google/protobuf/io/coded_stream.h new file mode 100644 index 000000000..66cbee003 --- /dev/null +++ b/include/google/protobuf/io/coded_stream.h @@ -0,0 +1,1136 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// This file contains the CodedInputStream and CodedOutputStream classes, +// which wrap a ZeroCopyInputStream or ZeroCopyOutputStream, respectively, +// and allow you to read or write individual pieces of data in various +// formats. In particular, these implement the varint encoding for +// integers, a simple variable-length encoding in which smaller numbers +// take fewer bytes. +// +// Typically these classes will only be used internally by the protocol +// buffer library in order to encode and decode protocol buffers. Clients +// of the library only need to know about this class if they wish to write +// custom message parsing or serialization procedures. +// +// CodedOutputStream example: +// // Write some data to "myfile". First we write a 4-byte "magic number" +// // to identify the file type, then write a length-delimited string. The +// // string is composed of a varint giving the length followed by the raw +// // bytes. +// int fd = open("myfile", O_WRONLY); +// ZeroCopyOutputStream* raw_output = new FileOutputStream(fd); +// CodedOutputStream* coded_output = new CodedOutputStream(raw_output); +// +// int magic_number = 1234; +// char text[] = "Hello world!"; +// coded_output->WriteLittleEndian32(magic_number); +// coded_output->WriteVarint32(strlen(text)); +// coded_output->WriteRaw(text, strlen(text)); +// +// delete coded_output; +// delete raw_output; +// close(fd); +// +// CodedInputStream example: +// // Read a file created by the above code. +// int fd = open("myfile", O_RDONLY); +// ZeroCopyInputStream* raw_input = new FileInputStream(fd); +// CodedInputStream coded_input = new CodedInputStream(raw_input); +// +// coded_input->ReadLittleEndian32(&magic_number); +// if (magic_number != 1234) { +// cerr << "File not in expected format." << endl; +// return; +// } +// +// uint32 size; +// coded_input->ReadVarint32(&size); +// +// char* text = new char[size + 1]; +// coded_input->ReadRaw(buffer, size); +// text[size] = '\0'; +// +// delete coded_input; +// delete raw_input; +// close(fd); +// +// cout << "Text is: " << text << endl; +// delete [] text; +// +// For those who are interested, varint encoding is defined as follows: +// +// The encoding operates on unsigned integers of up to 64 bits in length. +// Each byte of the encoded value has the format: +// * bits 0-6: Seven bits of the number being encoded. +// * bit 7: Zero if this is the last byte in the encoding (in which +// case all remaining bits of the number are zero) or 1 if +// more bytes follow. +// The first byte contains the least-significant 7 bits of the number, the +// second byte (if present) contains the next-least-significant 7 bits, +// and so on. So, the binary number 1011000101011 would be encoded in two +// bytes as "10101011 00101100". +// +// In theory, varint could be used to encode integers of any length. +// However, for practicality we set a limit at 64 bits. The maximum encoded +// length of a number is thus 10 bytes. + +#ifndef GOOGLE_PROTOBUF_IO_CODED_STREAM_H__ +#define GOOGLE_PROTOBUF_IO_CODED_STREAM_H__ + +#include +#ifdef _MSC_VER + #if defined(_M_IX86) && \ + !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST) + #define PROTOBUF_LITTLE_ENDIAN 1 + #endif + #if _MSC_VER >= 1300 + // If MSVC has "/RTCc" set, it will complain about truncating casts at + // runtime. This file contains some intentional truncating casts. + #pragma runtime_checks("c", off) + #endif +#else + #include // __BYTE_ORDER + #if defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN && \ + !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST) + #define PROTOBUF_LITTLE_ENDIAN 1 + #endif +#endif +#include + + +namespace google { +namespace protobuf { + +class DescriptorPool; +class MessageFactory; + +namespace io { + +// Defined in this file. +class CodedInputStream; +class CodedOutputStream; + +// Defined in other files. +class ZeroCopyInputStream; // zero_copy_stream.h +class ZeroCopyOutputStream; // zero_copy_stream.h + +// Class which reads and decodes binary data which is composed of varint- +// encoded integers and fixed-width pieces. Wraps a ZeroCopyInputStream. +// Most users will not need to deal with CodedInputStream. +// +// Most methods of CodedInputStream that return a bool return false if an +// underlying I/O error occurs or if the data is malformed. Once such a +// failure occurs, the CodedInputStream is broken and is no longer useful. +class LIBPROTOBUF_EXPORT CodedInputStream { + public: + // Create a CodedInputStream that reads from the given ZeroCopyInputStream. + explicit CodedInputStream(ZeroCopyInputStream* input); + + // Create a CodedInputStream that reads from the given flat array. This is + // faster than using an ArrayInputStream. PushLimit(size) is implied by + // this constructor. + explicit CodedInputStream(const uint8* buffer, int size); + + // Destroy the CodedInputStream and position the underlying + // ZeroCopyInputStream at the first unread byte. If an error occurred while + // reading (causing a method to return false), then the exact position of + // the input stream may be anywhere between the last value that was read + // successfully and the stream's byte limit. + ~CodedInputStream(); + + // Return true if this CodedInputStream reads from a flat array instead of + // a ZeroCopyInputStream. + inline bool IsFlat() const; + + // Skips a number of bytes. Returns false if an underlying read error + // occurs. + bool Skip(int count); + + // Sets *data to point directly at the unread part of the CodedInputStream's + // underlying buffer, and *size to the size of that buffer, but does not + // advance the stream's current position. This will always either produce + // a non-empty buffer or return false. If the caller consumes any of + // this data, it should then call Skip() to skip over the consumed bytes. + // This may be useful for implementing external fast parsing routines for + // types of data not covered by the CodedInputStream interface. + bool GetDirectBufferPointer(const void** data, int* size); + + // Like GetDirectBufferPointer, but this method is inlined, and does not + // attempt to Refresh() if the buffer is currently empty. + inline void GetDirectBufferPointerInline(const void** data, + int* size) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + + // Read raw bytes, copying them into the given buffer. + bool ReadRaw(void* buffer, int size); + + // Like ReadRaw, but reads into a string. + // + // Implementation Note: ReadString() grows the string gradually as it + // reads in the data, rather than allocating the entire requested size + // upfront. This prevents denial-of-service attacks in which a client + // could claim that a string is going to be MAX_INT bytes long in order to + // crash the server because it can't allocate this much space at once. + bool ReadString(string* buffer, int size); + // Like the above, with inlined optimizations. This should only be used + // by the protobuf implementation. + inline bool InternalReadStringInline(string* buffer, + int size) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + + + // Read a 32-bit little-endian integer. + bool ReadLittleEndian32(uint32* value); + // Read a 64-bit little-endian integer. + bool ReadLittleEndian64(uint64* value); + + // These methods read from an externally provided buffer. The caller is + // responsible for ensuring that the buffer has sufficient space. + // Read a 32-bit little-endian integer. + static const uint8* ReadLittleEndian32FromArray(const uint8* buffer, + uint32* value); + // Read a 64-bit little-endian integer. + static const uint8* ReadLittleEndian64FromArray(const uint8* buffer, + uint64* value); + + // Read an unsigned integer with Varint encoding, truncating to 32 bits. + // Reading a 32-bit value is equivalent to reading a 64-bit one and casting + // it to uint32, but may be more efficient. + bool ReadVarint32(uint32* value); + // Read an unsigned integer with Varint encoding. + bool ReadVarint64(uint64* value); + + // Read a tag. This calls ReadVarint32() and returns the result, or returns + // zero (which is not a valid tag) if ReadVarint32() fails. Also, it updates + // the last tag value, which can be checked with LastTagWas(). + // Always inline because this is only called in once place per parse loop + // but it is called for every iteration of said loop, so it should be fast. + // GCC doesn't want to inline this by default. + uint32 ReadTag() GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + + // Usually returns true if calling ReadVarint32() now would produce the given + // value. Will always return false if ReadVarint32() would not return the + // given value. If ExpectTag() returns true, it also advances past + // the varint. For best performance, use a compile-time constant as the + // parameter. + // Always inline because this collapses to a small number of instructions + // when given a constant parameter, but GCC doesn't want to inline by default. + bool ExpectTag(uint32 expected) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + + // Like above, except this reads from the specified buffer. The caller is + // responsible for ensuring that the buffer is large enough to read a varint + // of the expected size. For best performance, use a compile-time constant as + // the expected tag parameter. + // + // Returns a pointer beyond the expected tag if it was found, or NULL if it + // was not. + static const uint8* ExpectTagFromArray( + const uint8* buffer, + uint32 expected) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + + // Usually returns true if no more bytes can be read. Always returns false + // if more bytes can be read. If ExpectAtEnd() returns true, a subsequent + // call to LastTagWas() will act as if ReadTag() had been called and returned + // zero, and ConsumedEntireMessage() will return true. + bool ExpectAtEnd(); + + // If the last call to ReadTag() returned the given value, returns true. + // Otherwise, returns false; + // + // This is needed because parsers for some types of embedded messages + // (with field type TYPE_GROUP) don't actually know that they've reached the + // end of a message until they see an ENDGROUP tag, which was actually part + // of the enclosing message. The enclosing message would like to check that + // tag to make sure it had the right number, so it calls LastTagWas() on + // return from the embedded parser to check. + bool LastTagWas(uint32 expected); + + // When parsing message (but NOT a group), this method must be called + // immediately after MergeFromCodedStream() returns (if it returns true) + // to further verify that the message ended in a legitimate way. For + // example, this verifies that parsing did not end on an end-group tag. + // It also checks for some cases where, due to optimizations, + // MergeFromCodedStream() can incorrectly return true. + bool ConsumedEntireMessage(); + + // Limits ---------------------------------------------------------- + // Limits are used when parsing length-delimited embedded messages. + // After the message's length is read, PushLimit() is used to prevent + // the CodedInputStream from reading beyond that length. Once the + // embedded message has been parsed, PopLimit() is called to undo the + // limit. + + // Opaque type used with PushLimit() and PopLimit(). Do not modify + // values of this type yourself. The only reason that this isn't a + // struct with private internals is for efficiency. + typedef int Limit; + + // Places a limit on the number of bytes that the stream may read, + // starting from the current position. Once the stream hits this limit, + // it will act like the end of the input has been reached until PopLimit() + // is called. + // + // As the names imply, the stream conceptually has a stack of limits. The + // shortest limit on the stack is always enforced, even if it is not the + // top limit. + // + // The value returned by PushLimit() is opaque to the caller, and must + // be passed unchanged to the corresponding call to PopLimit(). + Limit PushLimit(int byte_limit); + + // Pops the last limit pushed by PushLimit(). The input must be the value + // returned by that call to PushLimit(). + void PopLimit(Limit limit); + + // Returns the number of bytes left until the nearest limit on the + // stack is hit, or -1 if no limits are in place. + int BytesUntilLimit() const; + + // Returns current position relative to the beginning of the input stream. + int CurrentPosition() const; + + // Total Bytes Limit ----------------------------------------------- + // To prevent malicious users from sending excessively large messages + // and causing integer overflows or memory exhaustion, CodedInputStream + // imposes a hard limit on the total number of bytes it will read. + + // Sets the maximum number of bytes that this CodedInputStream will read + // before refusing to continue. To prevent integer overflows in the + // protocol buffers implementation, as well as to prevent servers from + // allocating enormous amounts of memory to hold parsed messages, the + // maximum message length should be limited to the shortest length that + // will not harm usability. The theoretical shortest message that could + // cause integer overflows is 512MB. The default limit is 64MB. Apps + // should set shorter limits if possible. If warning_threshold is not -1, + // a warning will be printed to stderr after warning_threshold bytes are + // read. For backwards compatibility all negative values get squached to -1, + // as other negative values might have special internal meanings. + // An error will always be printed to stderr if the limit is reached. + // + // This is unrelated to PushLimit()/PopLimit(). + // + // Hint: If you are reading this because your program is printing a + // warning about dangerously large protocol messages, you may be + // confused about what to do next. The best option is to change your + // design such that excessively large messages are not necessary. + // For example, try to design file formats to consist of many small + // messages rather than a single large one. If this is infeasible, + // you will need to increase the limit. Chances are, though, that + // your code never constructs a CodedInputStream on which the limit + // can be set. You probably parse messages by calling things like + // Message::ParseFromString(). In this case, you will need to change + // your code to instead construct some sort of ZeroCopyInputStream + // (e.g. an ArrayInputStream), construct a CodedInputStream around + // that, then call Message::ParseFromCodedStream() instead. Then + // you can adjust the limit. Yes, it's more work, but you're doing + // something unusual. + void SetTotalBytesLimit(int total_bytes_limit, int warning_threshold); + + // Recursion Limit ------------------------------------------------- + // To prevent corrupt or malicious messages from causing stack overflows, + // we must keep track of the depth of recursion when parsing embedded + // messages and groups. CodedInputStream keeps track of this because it + // is the only object that is passed down the stack during parsing. + + // Sets the maximum recursion depth. The default is 100. + void SetRecursionLimit(int limit); + + + // Increments the current recursion depth. Returns true if the depth is + // under the limit, false if it has gone over. + bool IncrementRecursionDepth(); + + // Decrements the recursion depth. + void DecrementRecursionDepth(); + + // Extension Registry ---------------------------------------------- + // ADVANCED USAGE: 99.9% of people can ignore this section. + // + // By default, when parsing extensions, the parser looks for extension + // definitions in the pool which owns the outer message's Descriptor. + // However, you may call SetExtensionRegistry() to provide an alternative + // pool instead. This makes it possible, for example, to parse a message + // using a generated class, but represent some extensions using + // DynamicMessage. + + // Set the pool used to look up extensions. Most users do not need to call + // this as the correct pool will be chosen automatically. + // + // WARNING: It is very easy to misuse this. Carefully read the requirements + // below. Do not use this unless you are sure you need it. Almost no one + // does. + // + // Let's say you are parsing a message into message object m, and you want + // to take advantage of SetExtensionRegistry(). You must follow these + // requirements: + // + // The given DescriptorPool must contain m->GetDescriptor(). It is not + // sufficient for it to simply contain a descriptor that has the same name + // and content -- it must be the *exact object*. In other words: + // assert(pool->FindMessageTypeByName(m->GetDescriptor()->full_name()) == + // m->GetDescriptor()); + // There are two ways to satisfy this requirement: + // 1) Use m->GetDescriptor()->pool() as the pool. This is generally useless + // because this is the pool that would be used anyway if you didn't call + // SetExtensionRegistry() at all. + // 2) Use a DescriptorPool which has m->GetDescriptor()->pool() as an + // "underlay". Read the documentation for DescriptorPool for more + // information about underlays. + // + // You must also provide a MessageFactory. This factory will be used to + // construct Message objects representing extensions. The factory's + // GetPrototype() MUST return non-NULL for any Descriptor which can be found + // through the provided pool. + // + // If the provided factory might return instances of protocol-compiler- + // generated (i.e. compiled-in) types, or if the outer message object m is + // a generated type, then the given factory MUST have this property: If + // GetPrototype() is given a Descriptor which resides in + // DescriptorPool::generated_pool(), the factory MUST return the same + // prototype which MessageFactory::generated_factory() would return. That + // is, given a descriptor for a generated type, the factory must return an + // instance of the generated class (NOT DynamicMessage). However, when + // given a descriptor for a type that is NOT in generated_pool, the factory + // is free to return any implementation. + // + // The reason for this requirement is that generated sub-objects may be + // accessed via the standard (non-reflection) extension accessor methods, + // and these methods will down-cast the object to the generated class type. + // If the object is not actually of that type, the results would be undefined. + // On the other hand, if an extension is not compiled in, then there is no + // way the code could end up accessing it via the standard accessors -- the + // only way to access the extension is via reflection. When using reflection, + // DynamicMessage and generated messages are indistinguishable, so it's fine + // if these objects are represented using DynamicMessage. + // + // Using DynamicMessageFactory on which you have called + // SetDelegateToGeneratedFactory(true) should be sufficient to satisfy the + // above requirement. + // + // If either pool or factory is NULL, both must be NULL. + // + // Note that this feature is ignored when parsing "lite" messages as they do + // not have descriptors. + void SetExtensionRegistry(const DescriptorPool* pool, + MessageFactory* factory); + + // Get the DescriptorPool set via SetExtensionRegistry(), or NULL if no pool + // has been provided. + const DescriptorPool* GetExtensionPool(); + + // Get the MessageFactory set via SetExtensionRegistry(), or NULL if no + // factory has been provided. + MessageFactory* GetExtensionFactory(); + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CodedInputStream); + + ZeroCopyInputStream* input_; + const uint8* buffer_; + const uint8* buffer_end_; // pointer to the end of the buffer. + int total_bytes_read_; // total bytes read from input_, including + // the current buffer + + // If total_bytes_read_ surpasses INT_MAX, we record the extra bytes here + // so that we can BackUp() on destruction. + int overflow_bytes_; + + // LastTagWas() stuff. + uint32 last_tag_; // result of last ReadTag(). + + // This is set true by ReadTag{Fallback/Slow}() if it is called when exactly + // at EOF, or by ExpectAtEnd() when it returns true. This happens when we + // reach the end of a message and attempt to read another tag. + bool legitimate_message_end_; + + // See EnableAliasing(). + bool aliasing_enabled_; + + // Limits + Limit current_limit_; // if position = -1, no limit is applied + + // For simplicity, if the current buffer crosses a limit (either a normal + // limit created by PushLimit() or the total bytes limit), buffer_size_ + // only tracks the number of bytes before that limit. This field + // contains the number of bytes after it. Note that this implies that if + // buffer_size_ == 0 and buffer_size_after_limit_ > 0, we know we've + // hit a limit. However, if both are zero, it doesn't necessarily mean + // we aren't at a limit -- the buffer may have ended exactly at the limit. + int buffer_size_after_limit_; + + // Maximum number of bytes to read, period. This is unrelated to + // current_limit_. Set using SetTotalBytesLimit(). + int total_bytes_limit_; + + // If positive/0: Limit for bytes read after which a warning due to size + // should be logged. + // If -1: Printing of warning disabled. Can be set by client. + // If -2: Internal: Limit has been reached, print full size when destructing. + int total_bytes_warning_threshold_; + + // Current recursion depth, controlled by IncrementRecursionDepth() and + // DecrementRecursionDepth(). + int recursion_depth_; + // Recursion depth limit, set by SetRecursionLimit(). + int recursion_limit_; + + // See SetExtensionRegistry(). + const DescriptorPool* extension_pool_; + MessageFactory* extension_factory_; + + // Private member functions. + + // Advance the buffer by a given number of bytes. + void Advance(int amount); + + // Back up input_ to the current buffer position. + void BackUpInputToCurrentPosition(); + + // Recomputes the value of buffer_size_after_limit_. Must be called after + // current_limit_ or total_bytes_limit_ changes. + void RecomputeBufferLimits(); + + // Writes an error message saying that we hit total_bytes_limit_. + void PrintTotalBytesLimitError(); + + // Called when the buffer runs out to request more data. Implies an + // Advance(BufferSize()). + bool Refresh(); + + // When parsing varints, we optimize for the common case of small values, and + // then optimize for the case when the varint fits within the current buffer + // piece. The Fallback method is used when we can't use the one-byte + // optimization. The Slow method is yet another fallback when the buffer is + // not large enough. Making the slow path out-of-line speeds up the common + // case by 10-15%. The slow path is fairly uncommon: it only triggers when a + // message crosses multiple buffers. + bool ReadVarint32Fallback(uint32* value); + bool ReadVarint64Fallback(uint64* value); + bool ReadVarint32Slow(uint32* value); + bool ReadVarint64Slow(uint64* value); + bool ReadLittleEndian32Fallback(uint32* value); + bool ReadLittleEndian64Fallback(uint64* value); + // Fallback/slow methods for reading tags. These do not update last_tag_, + // but will set legitimate_message_end_ if we are at the end of the input + // stream. + uint32 ReadTagFallback(); + uint32 ReadTagSlow(); + bool ReadStringFallback(string* buffer, int size); + + // Return the size of the buffer. + int BufferSize() const; + + static const int kDefaultTotalBytesLimit = 64 << 20; // 64MB + + static const int kDefaultTotalBytesWarningThreshold = 32 << 20; // 32MB + + static int default_recursion_limit_; // 100 by default. +}; + +// Class which encodes and writes binary data which is composed of varint- +// encoded integers and fixed-width pieces. Wraps a ZeroCopyOutputStream. +// Most users will not need to deal with CodedOutputStream. +// +// Most methods of CodedOutputStream which return a bool return false if an +// underlying I/O error occurs. Once such a failure occurs, the +// CodedOutputStream is broken and is no longer useful. The Write* methods do +// not return the stream status, but will invalidate the stream if an error +// occurs. The client can probe HadError() to determine the status. +// +// Note that every method of CodedOutputStream which writes some data has +// a corresponding static "ToArray" version. These versions write directly +// to the provided buffer, returning a pointer past the last written byte. +// They require that the buffer has sufficient capacity for the encoded data. +// This allows an optimization where we check if an output stream has enough +// space for an entire message before we start writing and, if there is, we +// call only the ToArray methods to avoid doing bound checks for each +// individual value. +// i.e., in the example above: +// +// CodedOutputStream coded_output = new CodedOutputStream(raw_output); +// int magic_number = 1234; +// char text[] = "Hello world!"; +// +// int coded_size = sizeof(magic_number) + +// CodedOutputStream::VarintSize32(strlen(text)) + +// strlen(text); +// +// uint8* buffer = +// coded_output->GetDirectBufferForNBytesAndAdvance(coded_size); +// if (buffer != NULL) { +// // The output stream has enough space in the buffer: write directly to +// // the array. +// buffer = CodedOutputStream::WriteLittleEndian32ToArray(magic_number, +// buffer); +// buffer = CodedOutputStream::WriteVarint32ToArray(strlen(text), buffer); +// buffer = CodedOutputStream::WriteRawToArray(text, strlen(text), buffer); +// } else { +// // Make bound-checked writes, which will ask the underlying stream for +// // more space as needed. +// coded_output->WriteLittleEndian32(magic_number); +// coded_output->WriteVarint32(strlen(text)); +// coded_output->WriteRaw(text, strlen(text)); +// } +// +// delete coded_output; +class LIBPROTOBUF_EXPORT CodedOutputStream { + public: + // Create an CodedOutputStream that writes to the given ZeroCopyOutputStream. + explicit CodedOutputStream(ZeroCopyOutputStream* output); + + // Destroy the CodedOutputStream and position the underlying + // ZeroCopyOutputStream immediately after the last byte written. + ~CodedOutputStream(); + + // Skips a number of bytes, leaving the bytes unmodified in the underlying + // buffer. Returns false if an underlying write error occurs. This is + // mainly useful with GetDirectBufferPointer(). + bool Skip(int count); + + // Sets *data to point directly at the unwritten part of the + // CodedOutputStream's underlying buffer, and *size to the size of that + // buffer, but does not advance the stream's current position. This will + // always either produce a non-empty buffer or return false. If the caller + // writes any data to this buffer, it should then call Skip() to skip over + // the consumed bytes. This may be useful for implementing external fast + // serialization routines for types of data not covered by the + // CodedOutputStream interface. + bool GetDirectBufferPointer(void** data, int* size); + + // If there are at least "size" bytes available in the current buffer, + // returns a pointer directly into the buffer and advances over these bytes. + // The caller may then write directly into this buffer (e.g. using the + // *ToArray static methods) rather than go through CodedOutputStream. If + // there are not enough bytes available, returns NULL. The return pointer is + // invalidated as soon as any other non-const method of CodedOutputStream + // is called. + inline uint8* GetDirectBufferForNBytesAndAdvance(int size); + + // Write raw bytes, copying them from the given buffer. + void WriteRaw(const void* buffer, int size); + // Like WriteRaw() but writing directly to the target array. + // This is _not_ inlined, as the compiler often optimizes memcpy into inline + // copy loops. Since this gets called by every field with string or bytes + // type, inlining may lead to a significant amount of code bloat, with only a + // minor performance gain. + static uint8* WriteRawToArray(const void* buffer, int size, uint8* target); + + // Equivalent to WriteRaw(str.data(), str.size()). + void WriteString(const string& str); + // Like WriteString() but writing directly to the target array. + static uint8* WriteStringToArray(const string& str, uint8* target); + + + // Write a 32-bit little-endian integer. + void WriteLittleEndian32(uint32 value); + // Like WriteLittleEndian32() but writing directly to the target array. + static uint8* WriteLittleEndian32ToArray(uint32 value, uint8* target); + // Write a 64-bit little-endian integer. + void WriteLittleEndian64(uint64 value); + // Like WriteLittleEndian64() but writing directly to the target array. + static uint8* WriteLittleEndian64ToArray(uint64 value, uint8* target); + + // Write an unsigned integer with Varint encoding. Writing a 32-bit value + // is equivalent to casting it to uint64 and writing it as a 64-bit value, + // but may be more efficient. + void WriteVarint32(uint32 value); + // Like WriteVarint32() but writing directly to the target array. + static uint8* WriteVarint32ToArray(uint32 value, uint8* target); + // Write an unsigned integer with Varint encoding. + void WriteVarint64(uint64 value); + // Like WriteVarint64() but writing directly to the target array. + static uint8* WriteVarint64ToArray(uint64 value, uint8* target); + + // Equivalent to WriteVarint32() except when the value is negative, + // in which case it must be sign-extended to a full 10 bytes. + void WriteVarint32SignExtended(int32 value); + // Like WriteVarint32SignExtended() but writing directly to the target array. + static uint8* WriteVarint32SignExtendedToArray(int32 value, uint8* target); + + // This is identical to WriteVarint32(), but optimized for writing tags. + // In particular, if the input is a compile-time constant, this method + // compiles down to a couple instructions. + // Always inline because otherwise the aformentioned optimization can't work, + // but GCC by default doesn't want to inline this. + void WriteTag(uint32 value); + // Like WriteTag() but writing directly to the target array. + static uint8* WriteTagToArray( + uint32 value, uint8* target) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + + // Returns the number of bytes needed to encode the given value as a varint. + static int VarintSize32(uint32 value); + // Returns the number of bytes needed to encode the given value as a varint. + static int VarintSize64(uint64 value); + + // If negative, 10 bytes. Otheriwse, same as VarintSize32(). + static int VarintSize32SignExtended(int32 value); + + // Compile-time equivalent of VarintSize32(). + template + struct StaticVarintSize32 { + static const int value = + (Value < (1 << 7)) + ? 1 + : (Value < (1 << 14)) + ? 2 + : (Value < (1 << 21)) + ? 3 + : (Value < (1 << 28)) + ? 4 + : 5; + }; + + // Returns the total number of bytes written since this object was created. + inline int ByteCount() const; + + // Returns true if there was an underlying I/O error since this object was + // created. + bool HadError() const { return had_error_; } + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CodedOutputStream); + + ZeroCopyOutputStream* output_; + uint8* buffer_; + int buffer_size_; + int total_bytes_; // Sum of sizes of all buffers seen so far. + bool had_error_; // Whether an error occurred during output. + + // Advance the buffer by a given number of bytes. + void Advance(int amount); + + // Called when the buffer runs out to request more data. Implies an + // Advance(buffer_size_). + bool Refresh(); + + static uint8* WriteVarint32FallbackToArray(uint32 value, uint8* target); + + // Always-inlined versions of WriteVarint* functions so that code can be + // reused, while still controlling size. For instance, WriteVarint32ToArray() + // should not directly call this: since it is inlined itself, doing so + // would greatly increase the size of generated code. Instead, it should call + // WriteVarint32FallbackToArray. Meanwhile, WriteVarint32() is already + // out-of-line, so it should just invoke this directly to avoid any extra + // function call overhead. + static uint8* WriteVarint32FallbackToArrayInline( + uint32 value, uint8* target) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + static uint8* WriteVarint64ToArrayInline( + uint64 value, uint8* target) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + + static int VarintSize32Fallback(uint32 value); +}; + +// inline methods ==================================================== +// The vast majority of varints are only one byte. These inline +// methods optimize for that case. + +inline bool CodedInputStream::ReadVarint32(uint32* value) { + if (GOOGLE_PREDICT_TRUE(buffer_ < buffer_end_) && *buffer_ < 0x80) { + *value = *buffer_; + Advance(1); + return true; + } else { + return ReadVarint32Fallback(value); + } +} + +inline bool CodedInputStream::ReadVarint64(uint64* value) { + if (GOOGLE_PREDICT_TRUE(buffer_ < buffer_end_) && *buffer_ < 0x80) { + *value = *buffer_; + Advance(1); + return true; + } else { + return ReadVarint64Fallback(value); + } +} + +// static +inline const uint8* CodedInputStream::ReadLittleEndian32FromArray( + const uint8* buffer, + uint32* value) { +#if defined(PROTOBUF_LITTLE_ENDIAN) + memcpy(value, buffer, sizeof(*value)); + return buffer + sizeof(*value); +#else + *value = (static_cast(buffer[0]) ) | + (static_cast(buffer[1]) << 8) | + (static_cast(buffer[2]) << 16) | + (static_cast(buffer[3]) << 24); + return buffer + sizeof(*value); +#endif +} +// static +inline const uint8* CodedInputStream::ReadLittleEndian64FromArray( + const uint8* buffer, + uint64* value) { +#if defined(PROTOBUF_LITTLE_ENDIAN) + memcpy(value, buffer, sizeof(*value)); + return buffer + sizeof(*value); +#else + uint32 part0 = (static_cast(buffer[0]) ) | + (static_cast(buffer[1]) << 8) | + (static_cast(buffer[2]) << 16) | + (static_cast(buffer[3]) << 24); + uint32 part1 = (static_cast(buffer[4]) ) | + (static_cast(buffer[5]) << 8) | + (static_cast(buffer[6]) << 16) | + (static_cast(buffer[7]) << 24); + *value = static_cast(part0) | + (static_cast(part1) << 32); + return buffer + sizeof(*value); +#endif +} + +inline bool CodedInputStream::ReadLittleEndian32(uint32* value) { +#if defined(PROTOBUF_LITTLE_ENDIAN) + if (GOOGLE_PREDICT_TRUE(BufferSize() >= static_cast(sizeof(*value)))) { + memcpy(value, buffer_, sizeof(*value)); + Advance(sizeof(*value)); + return true; + } else { + return ReadLittleEndian32Fallback(value); + } +#else + return ReadLittleEndian32Fallback(value); +#endif +} + +inline bool CodedInputStream::ReadLittleEndian64(uint64* value) { +#if defined(PROTOBUF_LITTLE_ENDIAN) + if (GOOGLE_PREDICT_TRUE(BufferSize() >= static_cast(sizeof(*value)))) { + memcpy(value, buffer_, sizeof(*value)); + Advance(sizeof(*value)); + return true; + } else { + return ReadLittleEndian64Fallback(value); + } +#else + return ReadLittleEndian64Fallback(value); +#endif +} + +inline uint32 CodedInputStream::ReadTag() { + if (GOOGLE_PREDICT_TRUE(buffer_ < buffer_end_) && buffer_[0] < 0x80) { + last_tag_ = buffer_[0]; + Advance(1); + return last_tag_; + } else { + last_tag_ = ReadTagFallback(); + return last_tag_; + } +} + +inline bool CodedInputStream::LastTagWas(uint32 expected) { + return last_tag_ == expected; +} + +inline bool CodedInputStream::ConsumedEntireMessage() { + return legitimate_message_end_; +} + +inline bool CodedInputStream::ExpectTag(uint32 expected) { + if (expected < (1 << 7)) { + if (GOOGLE_PREDICT_TRUE(buffer_ < buffer_end_) && buffer_[0] == expected) { + Advance(1); + return true; + } else { + return false; + } + } else if (expected < (1 << 14)) { + if (GOOGLE_PREDICT_TRUE(BufferSize() >= 2) && + buffer_[0] == static_cast(expected | 0x80) && + buffer_[1] == static_cast(expected >> 7)) { + Advance(2); + return true; + } else { + return false; + } + } else { + // Don't bother optimizing for larger values. + return false; + } +} + +inline const uint8* CodedInputStream::ExpectTagFromArray( + const uint8* buffer, uint32 expected) { + if (expected < (1 << 7)) { + if (buffer[0] == expected) { + return buffer + 1; + } + } else if (expected < (1 << 14)) { + if (buffer[0] == static_cast(expected | 0x80) && + buffer[1] == static_cast(expected >> 7)) { + return buffer + 2; + } + } + return NULL; +} + +inline void CodedInputStream::GetDirectBufferPointerInline(const void** data, + int* size) { + *data = buffer_; + *size = buffer_end_ - buffer_; +} + +inline bool CodedInputStream::ExpectAtEnd() { + // If we are at a limit we know no more bytes can be read. Otherwise, it's + // hard to say without calling Refresh(), and we'd rather not do that. + + if (buffer_ == buffer_end_ && + ((buffer_size_after_limit_ != 0) || + (total_bytes_read_ == current_limit_))) { + last_tag_ = 0; // Pretend we called ReadTag()... + legitimate_message_end_ = true; // ... and it hit EOF. + return true; + } else { + return false; + } +} + +inline int CodedInputStream::CurrentPosition() const { + return total_bytes_read_ - (BufferSize() + buffer_size_after_limit_); +} + +inline uint8* CodedOutputStream::GetDirectBufferForNBytesAndAdvance(int size) { + if (buffer_size_ < size) { + return NULL; + } else { + uint8* result = buffer_; + Advance(size); + return result; + } +} + +inline uint8* CodedOutputStream::WriteVarint32ToArray(uint32 value, + uint8* target) { + if (value < 0x80) { + *target = value; + return target + 1; + } else { + return WriteVarint32FallbackToArray(value, target); + } +} + +inline void CodedOutputStream::WriteVarint32SignExtended(int32 value) { + if (value < 0) { + WriteVarint64(static_cast(value)); + } else { + WriteVarint32(static_cast(value)); + } +} + +inline uint8* CodedOutputStream::WriteVarint32SignExtendedToArray( + int32 value, uint8* target) { + if (value < 0) { + return WriteVarint64ToArray(static_cast(value), target); + } else { + return WriteVarint32ToArray(static_cast(value), target); + } +} + +inline uint8* CodedOutputStream::WriteLittleEndian32ToArray(uint32 value, + uint8* target) { +#if defined(PROTOBUF_LITTLE_ENDIAN) + memcpy(target, &value, sizeof(value)); +#else + target[0] = static_cast(value); + target[1] = static_cast(value >> 8); + target[2] = static_cast(value >> 16); + target[3] = static_cast(value >> 24); +#endif + return target + sizeof(value); +} + +inline uint8* CodedOutputStream::WriteLittleEndian64ToArray(uint64 value, + uint8* target) { +#if defined(PROTOBUF_LITTLE_ENDIAN) + memcpy(target, &value, sizeof(value)); +#else + uint32 part0 = static_cast(value); + uint32 part1 = static_cast(value >> 32); + + target[0] = static_cast(part0); + target[1] = static_cast(part0 >> 8); + target[2] = static_cast(part0 >> 16); + target[3] = static_cast(part0 >> 24); + target[4] = static_cast(part1); + target[5] = static_cast(part1 >> 8); + target[6] = static_cast(part1 >> 16); + target[7] = static_cast(part1 >> 24); +#endif + return target + sizeof(value); +} + +inline void CodedOutputStream::WriteTag(uint32 value) { + WriteVarint32(value); +} + +inline uint8* CodedOutputStream::WriteTagToArray( + uint32 value, uint8* target) { + if (value < (1 << 7)) { + target[0] = value; + return target + 1; + } else if (value < (1 << 14)) { + target[0] = static_cast(value | 0x80); + target[1] = static_cast(value >> 7); + return target + 2; + } else { + return WriteVarint32FallbackToArray(value, target); + } +} + +inline int CodedOutputStream::VarintSize32(uint32 value) { + if (value < (1 << 7)) { + return 1; + } else { + return VarintSize32Fallback(value); + } +} + +inline int CodedOutputStream::VarintSize32SignExtended(int32 value) { + if (value < 0) { + return 10; // TODO(kenton): Make this a symbolic constant. + } else { + return VarintSize32(static_cast(value)); + } +} + +inline void CodedOutputStream::WriteString(const string& str) { + WriteRaw(str.data(), static_cast(str.size())); +} + +inline uint8* CodedOutputStream::WriteStringToArray( + const string& str, uint8* target) { + return WriteRawToArray(str.data(), static_cast(str.size()), target); +} + +inline int CodedOutputStream::ByteCount() const { + return total_bytes_ - buffer_size_; +} + +inline void CodedInputStream::Advance(int amount) { + buffer_ += amount; +} + +inline void CodedOutputStream::Advance(int amount) { + buffer_ += amount; + buffer_size_ -= amount; +} + +inline void CodedInputStream::SetRecursionLimit(int limit) { + recursion_limit_ = limit; +} + +inline bool CodedInputStream::IncrementRecursionDepth() { + ++recursion_depth_; + return recursion_depth_ <= recursion_limit_; +} + +inline void CodedInputStream::DecrementRecursionDepth() { + if (recursion_depth_ > 0) --recursion_depth_; +} + +inline void CodedInputStream::SetExtensionRegistry(const DescriptorPool* pool, + MessageFactory* factory) { + extension_pool_ = pool; + extension_factory_ = factory; +} + +inline const DescriptorPool* CodedInputStream::GetExtensionPool() { + return extension_pool_; +} + +inline MessageFactory* CodedInputStream::GetExtensionFactory() { + return extension_factory_; +} + +inline int CodedInputStream::BufferSize() const { + return buffer_end_ - buffer_; +} + +inline CodedInputStream::CodedInputStream(ZeroCopyInputStream* input) + : input_(input), + buffer_(NULL), + buffer_end_(NULL), + total_bytes_read_(0), + overflow_bytes_(0), + last_tag_(0), + legitimate_message_end_(false), + aliasing_enabled_(false), + current_limit_(kint32max), + buffer_size_after_limit_(0), + total_bytes_limit_(kDefaultTotalBytesLimit), + total_bytes_warning_threshold_(kDefaultTotalBytesWarningThreshold), + recursion_depth_(0), + recursion_limit_(default_recursion_limit_), + extension_pool_(NULL), + extension_factory_(NULL) { + // Eagerly Refresh() so buffer space is immediately available. + Refresh(); +} + +inline CodedInputStream::CodedInputStream(const uint8* buffer, int size) + : input_(NULL), + buffer_(buffer), + buffer_end_(buffer + size), + total_bytes_read_(size), + overflow_bytes_(0), + last_tag_(0), + legitimate_message_end_(false), + aliasing_enabled_(false), + current_limit_(size), + buffer_size_after_limit_(0), + total_bytes_limit_(kDefaultTotalBytesLimit), + total_bytes_warning_threshold_(kDefaultTotalBytesWarningThreshold), + recursion_depth_(0), + recursion_limit_(default_recursion_limit_), + extension_pool_(NULL), + extension_factory_(NULL) { + // Note that setting current_limit_ == size is important to prevent some + // code paths from trying to access input_ and segfaulting. +} + +inline bool CodedInputStream::IsFlat() const { + return input_ == NULL; +} + +} // namespace io +} // namespace protobuf + + +#if defined(_MSC_VER) && _MSC_VER >= 1300 + #pragma runtime_checks("c", restore) +#endif // _MSC_VER + +} // namespace google +#endif // GOOGLE_PROTOBUF_IO_CODED_STREAM_H__ diff --git a/include/google/protobuf/io/gzip_stream.h b/include/google/protobuf/io/gzip_stream.h new file mode 100644 index 000000000..365e9ea5f --- /dev/null +++ b/include/google/protobuf/io/gzip_stream.h @@ -0,0 +1,209 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: brianolson@google.com (Brian Olson) +// +// This file contains the definition for classes GzipInputStream and +// GzipOutputStream. +// +// GzipInputStream decompresses data from an underlying +// ZeroCopyInputStream and provides the decompressed data as a +// ZeroCopyInputStream. +// +// GzipOutputStream is an ZeroCopyOutputStream that compresses data to +// an underlying ZeroCopyOutputStream. + +#ifndef GOOGLE_PROTOBUF_IO_GZIP_STREAM_H__ +#define GOOGLE_PROTOBUF_IO_GZIP_STREAM_H__ + +#include + +#include +#include + +namespace google { +namespace protobuf { +namespace io { + +// A ZeroCopyInputStream that reads compressed data through zlib +class LIBPROTOBUF_EXPORT GzipInputStream : public ZeroCopyInputStream { + public: + // Format key for constructor + enum Format { + // zlib will autodetect gzip header or deflate stream + AUTO = 0, + + // GZIP streams have some extra header data for file attributes. + GZIP = 1, + + // Simpler zlib stream format. + ZLIB = 2, + }; + + // buffer_size and format may be -1 for default of 64kB and GZIP format + explicit GzipInputStream( + ZeroCopyInputStream* sub_stream, + Format format = AUTO, + int buffer_size = -1); + virtual ~GzipInputStream(); + + // Return last error message or NULL if no error. + inline const char* ZlibErrorMessage() const { + return zcontext_.msg; + } + inline int ZlibErrorCode() const { + return zerror_; + } + + // implements ZeroCopyInputStream ---------------------------------- + bool Next(const void** data, int* size); + void BackUp(int count); + bool Skip(int count); + int64 ByteCount() const; + + private: + Format format_; + + ZeroCopyInputStream* sub_stream_; + + z_stream zcontext_; + int zerror_; + + void* output_buffer_; + void* output_position_; + size_t output_buffer_length_; + + int Inflate(int flush); + void DoNextOutput(const void** data, int* size); + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(GzipInputStream); +}; + + +class LIBPROTOBUF_EXPORT GzipOutputStream : public ZeroCopyOutputStream { + public: + // Format key for constructor + enum Format { + // GZIP streams have some extra header data for file attributes. + GZIP = 1, + + // Simpler zlib stream format. + ZLIB = 2, + }; + + struct LIBPROTOBUF_EXPORT Options { + // Defaults to GZIP. + Format format; + + // What size buffer to use internally. Defaults to 64kB. + int buffer_size; + + // A number between 0 and 9, where 0 is no compression and 9 is best + // compression. Defaults to Z_DEFAULT_COMPRESSION (see zlib.h). + int compression_level; + + // Defaults to Z_DEFAULT_STRATEGY. Can also be set to Z_FILTERED, + // Z_HUFFMAN_ONLY, or Z_RLE. See the documentation for deflateInit2 in + // zlib.h for definitions of these constants. + int compression_strategy; + + Options(); // Initializes with default values. + }; + + // Create a GzipOutputStream with default options. + explicit GzipOutputStream(ZeroCopyOutputStream* sub_stream); + + // Create a GzipOutputStream with the given options. + GzipOutputStream( + ZeroCopyOutputStream* sub_stream, + const Options& options); + + virtual ~GzipOutputStream(); + + // Return last error message or NULL if no error. + inline const char* ZlibErrorMessage() const { + return zcontext_.msg; + } + inline int ZlibErrorCode() const { + return zerror_; + } + + // Flushes data written so far to zipped data in the underlying stream. + // It is the caller's responsibility to flush the underlying stream if + // necessary. + // Compression may be less efficient stopping and starting around flushes. + // Returns true if no error. + // + // Please ensure that block size is > 6. Here is an excerpt from the zlib + // doc that explains why: + // + // In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that avail_out + // is greater than six to avoid repeated flush markers due to + // avail_out == 0 on return. + bool Flush(); + + // Writes out all data and closes the gzip stream. + // It is the caller's responsibility to close the underlying stream if + // necessary. + // Returns true if no error. + bool Close(); + + // implements ZeroCopyOutputStream --------------------------------- + bool Next(void** data, int* size); + void BackUp(int count); + int64 ByteCount() const; + + private: + ZeroCopyOutputStream* sub_stream_; + // Result from calling Next() on sub_stream_ + void* sub_data_; + int sub_data_size_; + + z_stream zcontext_; + int zerror_; + void* input_buffer_; + size_t input_buffer_length_; + + // Shared constructor code. + void Init(ZeroCopyOutputStream* sub_stream, const Options& options); + + // Do some compression. + // Takes zlib flush mode. + // Returns zlib error code. + int Deflate(int flush); + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(GzipOutputStream); +}; + +} // namespace io +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_IO_GZIP_STREAM_H__ diff --git a/include/google/protobuf/io/printer.h b/include/google/protobuf/io/printer.h new file mode 100644 index 000000000..5be48543a --- /dev/null +++ b/include/google/protobuf/io/printer.h @@ -0,0 +1,136 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// Utility class for writing text to a ZeroCopyOutputStream. + +#ifndef GOOGLE_PROTOBUF_IO_PRINTER_H__ +#define GOOGLE_PROTOBUF_IO_PRINTER_H__ + +#include +#include +#include + +namespace google { +namespace protobuf { +namespace io { + +class ZeroCopyOutputStream; // zero_copy_stream.h + +// This simple utility class assists in code generation. It basically +// allows the caller to define a set of variables and then output some +// text with variable substitutions. Example usage: +// +// Printer printer(output, '$'); +// map vars; +// vars["name"] = "Bob"; +// printer.Print(vars, "My name is $name$."); +// +// The above writes "My name is Bob." to the output stream. +// +// Printer aggressively enforces correct usage, crashing (with assert failures) +// in the case of undefined variables in debug builds. This helps greatly in +// debugging code which uses it. +class LIBPROTOBUF_EXPORT Printer { + public: + // Create a printer that writes text to the given output stream. Use the + // given character as the delimiter for variables. + Printer(ZeroCopyOutputStream* output, char variable_delimiter); + ~Printer(); + + // Print some text after applying variable substitutions. If a particular + // variable in the text is not defined, this will crash. Variables to be + // substituted are identified by their names surrounded by delimiter + // characters (as given to the constructor). The variable bindings are + // defined by the given map. + void Print(const map& variables, const char* text); + + // Like the first Print(), except the substitutions are given as parameters. + void Print(const char* text); + // Like the first Print(), except the substitutions are given as parameters. + void Print(const char* text, const char* variable, const string& value); + // Like the first Print(), except the substitutions are given as parameters. + void Print(const char* text, const char* variable1, const string& value1, + const char* variable2, const string& value2); + // Like the first Print(), except the substitutions are given as parameters. + void Print(const char* text, const char* variable1, const string& value1, + const char* variable2, const string& value2, + const char* variable3, const string& value3); + // TODO(kenton): Overloaded versions with more variables? Three seems + // to be enough. + + // Indent text by two spaces. After calling Indent(), two spaces will be + // inserted at the beginning of each line of text. Indent() may be called + // multiple times to produce deeper indents. + void Indent(); + + // Reduces the current indent level by two spaces, or crashes if the indent + // level is zero. + void Outdent(); + + // Write a string to the output buffer. + // This method does not look for newlines to add indentation. + void PrintRaw(const string& data); + + // Write a zero-delimited string to output buffer. + // This method does not look for newlines to add indentation. + void PrintRaw(const char* data); + + // Write some bytes to the output buffer. + // This method does not look for newlines to add indentation. + void WriteRaw(const char* data, int size); + + // True if any write to the underlying stream failed. (We don't just + // crash in this case because this is an I/O failure, not a programming + // error.) + bool failed() const { return failed_; } + + private: + const char variable_delimiter_; + + ZeroCopyOutputStream* const output_; + char* buffer_; + int buffer_size_; + + string indent_; + bool at_start_of_line_; + bool failed_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Printer); +}; + +} // namespace io +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_IO_PRINTER_H__ diff --git a/include/google/protobuf/io/tokenizer.h b/include/google/protobuf/io/tokenizer.h new file mode 100644 index 000000000..d85b82f9d --- /dev/null +++ b/include/google/protobuf/io/tokenizer.h @@ -0,0 +1,384 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// Class for parsing tokenized text from a ZeroCopyInputStream. + +#ifndef GOOGLE_PROTOBUF_IO_TOKENIZER_H__ +#define GOOGLE_PROTOBUF_IO_TOKENIZER_H__ + +#include +#include +#include + +namespace google { +namespace protobuf { +namespace io { + +class ZeroCopyInputStream; // zero_copy_stream.h + +// Defined in this file. +class ErrorCollector; +class Tokenizer; + +// Abstract interface for an object which collects the errors that occur +// during parsing. A typical implementation might simply print the errors +// to stdout. +class LIBPROTOBUF_EXPORT ErrorCollector { + public: + inline ErrorCollector() {} + virtual ~ErrorCollector(); + + // Indicates that there was an error in the input at the given line and + // column numbers. The numbers are zero-based, so you may want to add + // 1 to each before printing them. + virtual void AddError(int line, int column, const string& message) = 0; + + // Indicates that there was a warning in the input at the given line and + // column numbers. The numbers are zero-based, so you may want to add + // 1 to each before printing them. + virtual void AddWarning(int line, int column, const string& message) { } + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ErrorCollector); +}; + +// This class converts a stream of raw text into a stream of tokens for +// the protocol definition parser to parse. The tokens recognized are +// similar to those that make up the C language; see the TokenType enum for +// precise descriptions. Whitespace and comments are skipped. By default, +// C- and C++-style comments are recognized, but other styles can be used by +// calling set_comment_style(). +class LIBPROTOBUF_EXPORT Tokenizer { + public: + // Construct a Tokenizer that reads and tokenizes text from the given + // input stream and writes errors to the given error_collector. + // The caller keeps ownership of input and error_collector. + Tokenizer(ZeroCopyInputStream* input, ErrorCollector* error_collector); + ~Tokenizer(); + + enum TokenType { + TYPE_START, // Next() has not yet been called. + TYPE_END, // End of input reached. "text" is empty. + + TYPE_IDENTIFIER, // A sequence of letters, digits, and underscores, not + // starting with a digit. It is an error for a number + // to be followed by an identifier with no space in + // between. + TYPE_INTEGER, // A sequence of digits representing an integer. Normally + // the digits are decimal, but a prefix of "0x" indicates + // a hex number and a leading zero indicates octal, just + // like with C numeric literals. A leading negative sign + // is NOT included in the token; it's up to the parser to + // interpret the unary minus operator on its own. + TYPE_FLOAT, // A floating point literal, with a fractional part and/or + // an exponent. Always in decimal. Again, never + // negative. + TYPE_STRING, // A quoted sequence of escaped characters. Either single + // or double quotes can be used, but they must match. + // A string literal cannot cross a line break. + TYPE_SYMBOL, // Any other printable character, like '!' or '+'. + // Symbols are always a single character, so "!+$%" is + // four tokens. + }; + + // Structure representing a token read from the token stream. + struct Token { + TokenType type; + string text; // The exact text of the token as it appeared in + // the input. e.g. tokens of TYPE_STRING will still + // be escaped and in quotes. + + // "line" and "column" specify the position of the first character of + // the token within the input stream. They are zero-based. + int line; + int column; + int end_column; + }; + + // Get the current token. This is updated when Next() is called. Before + // the first call to Next(), current() has type TYPE_START and no contents. + const Token& current(); + + // Return the previous token -- i.e. what current() returned before the + // previous call to Next(). + const Token& previous(); + + // Advance to the next token. Returns false if the end of the input is + // reached. + bool Next(); + + // Like Next(), but also collects comments which appear between the previous + // and next tokens. + // + // Comments which appear to be attached to the previous token are stored + // in *prev_tailing_comments. Comments which appear to be attached to the + // next token are stored in *next_leading_comments. Comments appearing in + // between which do not appear to be attached to either will be added to + // detached_comments. Any of these parameters can be NULL to simply discard + // the comments. + // + // A series of line comments appearing on consecutive lines, with no other + // tokens appearing on those lines, will be treated as a single comment. + // + // Only the comment content is returned; comment markers (e.g. //) are + // stripped out. For block comments, leading whitespace and an asterisk will + // be stripped from the beginning of each line other than the first. Newlines + // are included in the output. + // + // Examples: + // + // optional int32 foo = 1; // Comment attached to foo. + // // Comment attached to bar. + // optional int32 bar = 2; + // + // optional string baz = 3; + // // Comment attached to baz. + // // Another line attached to baz. + // + // // Comment attached to qux. + // // + // // Another line attached to qux. + // optional double qux = 4; + // + // // Detached comment. This is not attached to qux or corge + // // because there are blank lines separating it from both. + // + // optional string corge = 5; + // /* Block comment attached + // * to corge. Leading asterisks + // * will be removed. */ + // /* Block comment attached to + // * grault. */ + // optional int32 grault = 6; + bool NextWithComments(string* prev_trailing_comments, + vector* detached_comments, + string* next_leading_comments); + + // Parse helpers --------------------------------------------------- + + // Parses a TYPE_FLOAT token. This never fails, so long as the text actually + // comes from a TYPE_FLOAT token parsed by Tokenizer. If it doesn't, the + // result is undefined (possibly an assert failure). + static double ParseFloat(const string& text); + + // Parses a TYPE_STRING token. This never fails, so long as the text actually + // comes from a TYPE_STRING token parsed by Tokenizer. If it doesn't, the + // result is undefined (possibly an assert failure). + static void ParseString(const string& text, string* output); + + // Identical to ParseString, but appends to output. + static void ParseStringAppend(const string& text, string* output); + + // Parses a TYPE_INTEGER token. Returns false if the result would be + // greater than max_value. Otherwise, returns true and sets *output to the + // result. If the text is not from a Token of type TYPE_INTEGER originally + // parsed by a Tokenizer, the result is undefined (possibly an assert + // failure). + static bool ParseInteger(const string& text, uint64 max_value, + uint64* output); + + // Options --------------------------------------------------------- + + // Set true to allow floats to be suffixed with the letter 'f'. Tokens + // which would otherwise be integers but which have the 'f' suffix will be + // forced to be interpreted as floats. For all other purposes, the 'f' is + // ignored. + void set_allow_f_after_float(bool value) { allow_f_after_float_ = value; } + + // Valid values for set_comment_style(). + enum CommentStyle { + // Line comments begin with "//", block comments are delimited by "/*" and + // "*/". + CPP_COMMENT_STYLE, + // Line comments begin with "#". No way to write block comments. + SH_COMMENT_STYLE + }; + + // Sets the comment style. + void set_comment_style(CommentStyle style) { comment_style_ = style; } + + // ----------------------------------------------------------------- + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Tokenizer); + + Token current_; // Returned by current(). + Token previous_; // Returned by previous(). + + ZeroCopyInputStream* input_; + ErrorCollector* error_collector_; + + char current_char_; // == buffer_[buffer_pos_], updated by NextChar(). + const char* buffer_; // Current buffer returned from input_. + int buffer_size_; // Size of buffer_. + int buffer_pos_; // Current position within the buffer. + bool read_error_; // Did we previously encounter a read error? + + // Line and column number of current_char_ within the whole input stream. + int line_; + int column_; + + // String to which text should be appended as we advance through it. + // Call RecordTo(&str) to start recording and StopRecording() to stop. + // E.g. StartToken() calls RecordTo(¤t_.text). record_start_ is the + // position within the current buffer where recording started. + string* record_target_; + int record_start_; + + // Options. + bool allow_f_after_float_; + CommentStyle comment_style_; + + // Since we count columns we need to interpret tabs somehow. We'll take + // the standard 8-character definition for lack of any way to do better. + static const int kTabWidth = 8; + + // ----------------------------------------------------------------- + // Helper methods. + + // Consume this character and advance to the next one. + void NextChar(); + + // Read a new buffer from the input. + void Refresh(); + + inline void RecordTo(string* target); + inline void StopRecording(); + + // Called when the current character is the first character of a new + // token (not including whitespace or comments). + inline void StartToken(); + // Called when the current character is the first character after the + // end of the last token. After this returns, current_.text will + // contain all text consumed since StartToken() was called. + inline void EndToken(); + + // Convenience method to add an error at the current line and column. + void AddError(const string& message) { + error_collector_->AddError(line_, column_, message); + } + + // ----------------------------------------------------------------- + // The following four methods are used to consume tokens of specific + // types. They are actually used to consume all characters *after* + // the first, since the calling function consumes the first character + // in order to decide what kind of token is being read. + + // Read and consume a string, ending when the given delimiter is + // consumed. + void ConsumeString(char delimiter); + + // Read and consume a number, returning TYPE_FLOAT or TYPE_INTEGER + // depending on what was read. This needs to know if the first + // character was a zero in order to correctly recognize hex and octal + // numbers. + // It also needs to know if the first characted was a . to parse floating + // point correctly. + TokenType ConsumeNumber(bool started_with_zero, bool started_with_dot); + + // Consume the rest of a line. + void ConsumeLineComment(string* content); + // Consume until "*/". + void ConsumeBlockComment(string* content); + + enum NextCommentStatus { + // Started a line comment. + LINE_COMMENT, + + // Started a block comment. + BLOCK_COMMENT, + + // Consumed a slash, then realized it wasn't a comment. current_ has + // been filled in with a slash token. The caller should return it. + SLASH_NOT_COMMENT, + + // We do not appear to be starting a comment here. + NO_COMMENT + }; + + // If we're at the start of a new comment, consume it and return what kind + // of comment it is. + NextCommentStatus TryConsumeCommentStart(); + + // ----------------------------------------------------------------- + // These helper methods make the parsing code more readable. The + // "character classes" refered to are defined at the top of the .cc file. + // Basically it is a C++ class with one method: + // static bool InClass(char c); + // The method returns true if c is a member of this "class", like "Letter" + // or "Digit". + + // Returns true if the current character is of the given character + // class, but does not consume anything. + template + inline bool LookingAt(); + + // If the current character is in the given class, consume it and return + // true. Otherwise return false. + // e.g. TryConsumeOne() + template + inline bool TryConsumeOne(); + + // Like above, but try to consume the specific character indicated. + inline bool TryConsume(char c); + + // Consume zero or more of the given character class. + template + inline void ConsumeZeroOrMore(); + + // Consume one or more of the given character class or log the given + // error message. + // e.g. ConsumeOneOrMore("Expected digits."); + template + inline void ConsumeOneOrMore(const char* error); +}; + +// inline methods ==================================================== +inline const Tokenizer::Token& Tokenizer::current() { + return current_; +} + +inline const Tokenizer::Token& Tokenizer::previous() { + return previous_; +} + +inline void Tokenizer::ParseString(const string& text, string* output) { + output->clear(); + ParseStringAppend(text, output); +} + +} // namespace io +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_IO_TOKENIZER_H__ diff --git a/include/google/protobuf/io/zero_copy_stream.h b/include/google/protobuf/io/zero_copy_stream.h new file mode 100644 index 000000000..db5326f70 --- /dev/null +++ b/include/google/protobuf/io/zero_copy_stream.h @@ -0,0 +1,238 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// This file contains the ZeroCopyInputStream and ZeroCopyOutputStream +// interfaces, which represent abstract I/O streams to and from which +// protocol buffers can be read and written. For a few simple +// implementations of these interfaces, see zero_copy_stream_impl.h. +// +// These interfaces are different from classic I/O streams in that they +// try to minimize the amount of data copying that needs to be done. +// To accomplish this, responsibility for allocating buffers is moved to +// the stream object, rather than being the responsibility of the caller. +// So, the stream can return a buffer which actually points directly into +// the final data structure where the bytes are to be stored, and the caller +// can interact directly with that buffer, eliminating an intermediate copy +// operation. +// +// As an example, consider the common case in which you are reading bytes +// from an array that is already in memory (or perhaps an mmap()ed file). +// With classic I/O streams, you would do something like: +// char buffer[BUFFER_SIZE]; +// input->Read(buffer, BUFFER_SIZE); +// DoSomething(buffer, BUFFER_SIZE); +// Then, the stream basically just calls memcpy() to copy the data from +// the array into your buffer. With a ZeroCopyInputStream, you would do +// this instead: +// const void* buffer; +// int size; +// input->Next(&buffer, &size); +// DoSomething(buffer, size); +// Here, no copy is performed. The input stream returns a pointer directly +// into the backing array, and the caller ends up reading directly from it. +// +// If you want to be able to read the old-fashion way, you can create +// a CodedInputStream or CodedOutputStream wrapping these objects and use +// their ReadRaw()/WriteRaw() methods. These will, of course, add a copy +// step, but Coded*Stream will handle buffering so at least it will be +// reasonably efficient. +// +// ZeroCopyInputStream example: +// // Read in a file and print its contents to stdout. +// int fd = open("myfile", O_RDONLY); +// ZeroCopyInputStream* input = new FileInputStream(fd); +// +// const void* buffer; +// int size; +// while (input->Next(&buffer, &size)) { +// cout.write(buffer, size); +// } +// +// delete input; +// close(fd); +// +// ZeroCopyOutputStream example: +// // Copy the contents of "infile" to "outfile", using plain read() for +// // "infile" but a ZeroCopyOutputStream for "outfile". +// int infd = open("infile", O_RDONLY); +// int outfd = open("outfile", O_WRONLY); +// ZeroCopyOutputStream* output = new FileOutputStream(outfd); +// +// void* buffer; +// int size; +// while (output->Next(&buffer, &size)) { +// int bytes = read(infd, buffer, size); +// if (bytes < size) { +// // Reached EOF. +// output->BackUp(size - bytes); +// break; +// } +// } +// +// delete output; +// close(infd); +// close(outfd); + +#ifndef GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_H__ +#define GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_H__ + +#include +#include + +namespace google { + +namespace protobuf { +namespace io { + +// Defined in this file. +class ZeroCopyInputStream; +class ZeroCopyOutputStream; + +// Abstract interface similar to an input stream but designed to minimize +// copying. +class LIBPROTOBUF_EXPORT ZeroCopyInputStream { + public: + inline ZeroCopyInputStream() {} + virtual ~ZeroCopyInputStream(); + + // Obtains a chunk of data from the stream. + // + // Preconditions: + // * "size" and "data" are not NULL. + // + // Postconditions: + // * If the returned value is false, there is no more data to return or + // an error occurred. All errors are permanent. + // * Otherwise, "size" points to the actual number of bytes read and "data" + // points to a pointer to a buffer containing these bytes. + // * Ownership of this buffer remains with the stream, and the buffer + // remains valid only until some other method of the stream is called + // or the stream is destroyed. + // * It is legal for the returned buffer to have zero size, as long + // as repeatedly calling Next() eventually yields a buffer with non-zero + // size. + virtual bool Next(const void** data, int* size) = 0; + + // Backs up a number of bytes, so that the next call to Next() returns + // data again that was already returned by the last call to Next(). This + // is useful when writing procedures that are only supposed to read up + // to a certain point in the input, then return. If Next() returns a + // buffer that goes beyond what you wanted to read, you can use BackUp() + // to return to the point where you intended to finish. + // + // Preconditions: + // * The last method called must have been Next(). + // * count must be less than or equal to the size of the last buffer + // returned by Next(). + // + // Postconditions: + // * The last "count" bytes of the last buffer returned by Next() will be + // pushed back into the stream. Subsequent calls to Next() will return + // the same data again before producing new data. + virtual void BackUp(int count) = 0; + + // Skips a number of bytes. Returns false if the end of the stream is + // reached or some input error occurred. In the end-of-stream case, the + // stream is advanced to the end of the stream (so ByteCount() will return + // the total size of the stream). + virtual bool Skip(int count) = 0; + + // Returns the total number of bytes read since this object was created. + virtual int64 ByteCount() const = 0; + + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ZeroCopyInputStream); +}; + +// Abstract interface similar to an output stream but designed to minimize +// copying. +class LIBPROTOBUF_EXPORT ZeroCopyOutputStream { + public: + inline ZeroCopyOutputStream() {} + virtual ~ZeroCopyOutputStream(); + + // Obtains a buffer into which data can be written. Any data written + // into this buffer will eventually (maybe instantly, maybe later on) + // be written to the output. + // + // Preconditions: + // * "size" and "data" are not NULL. + // + // Postconditions: + // * If the returned value is false, an error occurred. All errors are + // permanent. + // * Otherwise, "size" points to the actual number of bytes in the buffer + // and "data" points to the buffer. + // * Ownership of this buffer remains with the stream, and the buffer + // remains valid only until some other method of the stream is called + // or the stream is destroyed. + // * Any data which the caller stores in this buffer will eventually be + // written to the output (unless BackUp() is called). + // * It is legal for the returned buffer to have zero size, as long + // as repeatedly calling Next() eventually yields a buffer with non-zero + // size. + virtual bool Next(void** data, int* size) = 0; + + // Backs up a number of bytes, so that the end of the last buffer returned + // by Next() is not actually written. This is needed when you finish + // writing all the data you want to write, but the last buffer was bigger + // than you needed. You don't want to write a bunch of garbage after the + // end of your data, so you use BackUp() to back up. + // + // Preconditions: + // * The last method called must have been Next(). + // * count must be less than or equal to the size of the last buffer + // returned by Next(). + // * The caller must not have written anything to the last "count" bytes + // of that buffer. + // + // Postconditions: + // * The last "count" bytes of the last buffer returned by Next() will be + // ignored. + virtual void BackUp(int count) = 0; + + // Returns the total number of bytes written since this object was created. + virtual int64 ByteCount() const = 0; + + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ZeroCopyOutputStream); +}; + +} // namespace io +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_H__ diff --git a/include/google/protobuf/io/zero_copy_stream_impl.h b/include/google/protobuf/io/zero_copy_stream_impl.h new file mode 100644 index 000000000..9fedb0057 --- /dev/null +++ b/include/google/protobuf/io/zero_copy_stream_impl.h @@ -0,0 +1,357 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// This file contains common implementations of the interfaces defined in +// zero_copy_stream.h which are only included in the full (non-lite) +// protobuf library. These implementations include Unix file descriptors +// and C++ iostreams. See also: zero_copy_stream_impl_lite.h + +#ifndef GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_H__ +#define GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_H__ + +#include +#include +#include +#include +#include + + +namespace google { +namespace protobuf { +namespace io { + + +// =================================================================== + +// A ZeroCopyInputStream which reads from a file descriptor. +// +// FileInputStream is preferred over using an ifstream with IstreamInputStream. +// The latter will introduce an extra layer of buffering, harming performance. +// Also, it's conceivable that FileInputStream could someday be enhanced +// to use zero-copy file descriptors on OSs which support them. +class LIBPROTOBUF_EXPORT FileInputStream : public ZeroCopyInputStream { + public: + // Creates a stream that reads from the given Unix file descriptor. + // If a block_size is given, it specifies the number of bytes that + // should be read and returned with each call to Next(). Otherwise, + // a reasonable default is used. + explicit FileInputStream(int file_descriptor, int block_size = -1); + ~FileInputStream(); + + // Flushes any buffers and closes the underlying file. Returns false if + // an error occurs during the process; use GetErrno() to examine the error. + // Even if an error occurs, the file descriptor is closed when this returns. + bool Close(); + + // By default, the file descriptor is not closed when the stream is + // destroyed. Call SetCloseOnDelete(true) to change that. WARNING: + // This leaves no way for the caller to detect if close() fails. If + // detecting close() errors is important to you, you should arrange + // to close the descriptor yourself. + void SetCloseOnDelete(bool value) { copying_input_.SetCloseOnDelete(value); } + + // If an I/O error has occurred on this file descriptor, this is the + // errno from that error. Otherwise, this is zero. Once an error + // occurs, the stream is broken and all subsequent operations will + // fail. + int GetErrno() { return copying_input_.GetErrno(); } + + // implements ZeroCopyInputStream ---------------------------------- + bool Next(const void** data, int* size); + void BackUp(int count); + bool Skip(int count); + int64 ByteCount() const; + + private: + class LIBPROTOBUF_EXPORT CopyingFileInputStream : public CopyingInputStream { + public: + CopyingFileInputStream(int file_descriptor); + ~CopyingFileInputStream(); + + bool Close(); + void SetCloseOnDelete(bool value) { close_on_delete_ = value; } + int GetErrno() { return errno_; } + + // implements CopyingInputStream --------------------------------- + int Read(void* buffer, int size); + int Skip(int count); + + private: + // The file descriptor. + const int file_; + bool close_on_delete_; + bool is_closed_; + + // The errno of the I/O error, if one has occurred. Otherwise, zero. + int errno_; + + // Did we try to seek once and fail? If so, we assume this file descriptor + // doesn't support seeking and won't try again. + bool previous_seek_failed_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CopyingFileInputStream); + }; + + CopyingFileInputStream copying_input_; + CopyingInputStreamAdaptor impl_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileInputStream); +}; + +// =================================================================== + +// A ZeroCopyOutputStream which writes to a file descriptor. +// +// FileOutputStream is preferred over using an ofstream with +// OstreamOutputStream. The latter will introduce an extra layer of buffering, +// harming performance. Also, it's conceivable that FileOutputStream could +// someday be enhanced to use zero-copy file descriptors on OSs which +// support them. +class LIBPROTOBUF_EXPORT FileOutputStream : public ZeroCopyOutputStream { + public: + // Creates a stream that writes to the given Unix file descriptor. + // If a block_size is given, it specifies the size of the buffers + // that should be returned by Next(). Otherwise, a reasonable default + // is used. + explicit FileOutputStream(int file_descriptor, int block_size = -1); + ~FileOutputStream(); + + // Flushes any buffers and closes the underlying file. Returns false if + // an error occurs during the process; use GetErrno() to examine the error. + // Even if an error occurs, the file descriptor is closed when this returns. + bool Close(); + + // Flushes FileOutputStream's buffers but does not close the + // underlying file. No special measures are taken to ensure that + // underlying operating system file object is synchronized to disk. + bool Flush(); + + // By default, the file descriptor is not closed when the stream is + // destroyed. Call SetCloseOnDelete(true) to change that. WARNING: + // This leaves no way for the caller to detect if close() fails. If + // detecting close() errors is important to you, you should arrange + // to close the descriptor yourself. + void SetCloseOnDelete(bool value) { copying_output_.SetCloseOnDelete(value); } + + // If an I/O error has occurred on this file descriptor, this is the + // errno from that error. Otherwise, this is zero. Once an error + // occurs, the stream is broken and all subsequent operations will + // fail. + int GetErrno() { return copying_output_.GetErrno(); } + + // implements ZeroCopyOutputStream --------------------------------- + bool Next(void** data, int* size); + void BackUp(int count); + int64 ByteCount() const; + + private: + class LIBPROTOBUF_EXPORT CopyingFileOutputStream : public CopyingOutputStream { + public: + CopyingFileOutputStream(int file_descriptor); + ~CopyingFileOutputStream(); + + bool Close(); + void SetCloseOnDelete(bool value) { close_on_delete_ = value; } + int GetErrno() { return errno_; } + + // implements CopyingOutputStream -------------------------------- + bool Write(const void* buffer, int size); + + private: + // The file descriptor. + const int file_; + bool close_on_delete_; + bool is_closed_; + + // The errno of the I/O error, if one has occurred. Otherwise, zero. + int errno_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CopyingFileOutputStream); + }; + + CopyingFileOutputStream copying_output_; + CopyingOutputStreamAdaptor impl_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileOutputStream); +}; + +// =================================================================== + +// A ZeroCopyInputStream which reads from a C++ istream. +// +// Note that for reading files (or anything represented by a file descriptor), +// FileInputStream is more efficient. +class LIBPROTOBUF_EXPORT IstreamInputStream : public ZeroCopyInputStream { + public: + // Creates a stream that reads from the given C++ istream. + // If a block_size is given, it specifies the number of bytes that + // should be read and returned with each call to Next(). Otherwise, + // a reasonable default is used. + explicit IstreamInputStream(istream* stream, int block_size = -1); + ~IstreamInputStream(); + + // implements ZeroCopyInputStream ---------------------------------- + bool Next(const void** data, int* size); + void BackUp(int count); + bool Skip(int count); + int64 ByteCount() const; + + private: + class LIBPROTOBUF_EXPORT CopyingIstreamInputStream : public CopyingInputStream { + public: + CopyingIstreamInputStream(istream* input); + ~CopyingIstreamInputStream(); + + // implements CopyingInputStream --------------------------------- + int Read(void* buffer, int size); + // (We use the default implementation of Skip().) + + private: + // The stream. + istream* input_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CopyingIstreamInputStream); + }; + + CopyingIstreamInputStream copying_input_; + CopyingInputStreamAdaptor impl_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(IstreamInputStream); +}; + +// =================================================================== + +// A ZeroCopyOutputStream which writes to a C++ ostream. +// +// Note that for writing files (or anything represented by a file descriptor), +// FileOutputStream is more efficient. +class LIBPROTOBUF_EXPORT OstreamOutputStream : public ZeroCopyOutputStream { + public: + // Creates a stream that writes to the given C++ ostream. + // If a block_size is given, it specifies the size of the buffers + // that should be returned by Next(). Otherwise, a reasonable default + // is used. + explicit OstreamOutputStream(ostream* stream, int block_size = -1); + ~OstreamOutputStream(); + + // implements ZeroCopyOutputStream --------------------------------- + bool Next(void** data, int* size); + void BackUp(int count); + int64 ByteCount() const; + + private: + class LIBPROTOBUF_EXPORT CopyingOstreamOutputStream : public CopyingOutputStream { + public: + CopyingOstreamOutputStream(ostream* output); + ~CopyingOstreamOutputStream(); + + // implements CopyingOutputStream -------------------------------- + bool Write(const void* buffer, int size); + + private: + // The stream. + ostream* output_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CopyingOstreamOutputStream); + }; + + CopyingOstreamOutputStream copying_output_; + CopyingOutputStreamAdaptor impl_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(OstreamOutputStream); +}; + +// =================================================================== + +// A ZeroCopyInputStream which reads from several other streams in sequence. +// ConcatenatingInputStream is unable to distinguish between end-of-stream +// and read errors in the underlying streams, so it assumes any errors mean +// end-of-stream. So, if the underlying streams fail for any other reason, +// ConcatenatingInputStream may do odd things. It is suggested that you do +// not use ConcatenatingInputStream on streams that might produce read errors +// other than end-of-stream. +class LIBPROTOBUF_EXPORT ConcatenatingInputStream : public ZeroCopyInputStream { + public: + // All streams passed in as well as the array itself must remain valid + // until the ConcatenatingInputStream is destroyed. + ConcatenatingInputStream(ZeroCopyInputStream* const streams[], int count); + ~ConcatenatingInputStream(); + + // implements ZeroCopyInputStream ---------------------------------- + bool Next(const void** data, int* size); + void BackUp(int count); + bool Skip(int count); + int64 ByteCount() const; + + + private: + // As streams are retired, streams_ is incremented and count_ is + // decremented. + ZeroCopyInputStream* const* streams_; + int stream_count_; + int64 bytes_retired_; // Bytes read from previous streams. + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ConcatenatingInputStream); +}; + +// =================================================================== + +// A ZeroCopyInputStream which wraps some other stream and limits it to +// a particular byte count. +class LIBPROTOBUF_EXPORT LimitingInputStream : public ZeroCopyInputStream { + public: + LimitingInputStream(ZeroCopyInputStream* input, int64 limit); + ~LimitingInputStream(); + + // implements ZeroCopyInputStream ---------------------------------- + bool Next(const void** data, int* size); + void BackUp(int count); + bool Skip(int count); + int64 ByteCount() const; + + + private: + ZeroCopyInputStream* input_; + int64 limit_; // Decreases as we go, becomes negative if we overshoot. + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(LimitingInputStream); +}; + +// =================================================================== + +} // namespace io +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_H__ diff --git a/include/google/protobuf/io/zero_copy_stream_impl_lite.h b/include/google/protobuf/io/zero_copy_stream_impl_lite.h new file mode 100644 index 000000000..153f543ee --- /dev/null +++ b/include/google/protobuf/io/zero_copy_stream_impl_lite.h @@ -0,0 +1,340 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// This file contains common implementations of the interfaces defined in +// zero_copy_stream.h which are included in the "lite" protobuf library. +// These implementations cover I/O on raw arrays and strings, as well as +// adaptors which make it easy to implement streams based on traditional +// streams. Of course, many users will probably want to write their own +// implementations of these interfaces specific to the particular I/O +// abstractions they prefer to use, but these should cover the most common +// cases. + +#ifndef GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_LITE_H__ +#define GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_LITE_H__ + +#include +#include +#include +#include + + +namespace google { +namespace protobuf { +namespace io { + +// =================================================================== + +// A ZeroCopyInputStream backed by an in-memory array of bytes. +class LIBPROTOBUF_EXPORT ArrayInputStream : public ZeroCopyInputStream { + public: + // Create an InputStream that returns the bytes pointed to by "data". + // "data" remains the property of the caller but must remain valid until + // the stream is destroyed. If a block_size is given, calls to Next() + // will return data blocks no larger than the given size. Otherwise, the + // first call to Next() returns the entire array. block_size is mainly + // useful for testing; in production you would probably never want to set + // it. + ArrayInputStream(const void* data, int size, int block_size = -1); + ~ArrayInputStream(); + + // implements ZeroCopyInputStream ---------------------------------- + bool Next(const void** data, int* size); + void BackUp(int count); + bool Skip(int count); + int64 ByteCount() const; + + + private: + const uint8* const data_; // The byte array. + const int size_; // Total size of the array. + const int block_size_; // How many bytes to return at a time. + + int position_; + int last_returned_size_; // How many bytes we returned last time Next() + // was called (used for error checking only). + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ArrayInputStream); +}; + +// =================================================================== + +// A ZeroCopyOutputStream backed by an in-memory array of bytes. +class LIBPROTOBUF_EXPORT ArrayOutputStream : public ZeroCopyOutputStream { + public: + // Create an OutputStream that writes to the bytes pointed to by "data". + // "data" remains the property of the caller but must remain valid until + // the stream is destroyed. If a block_size is given, calls to Next() + // will return data blocks no larger than the given size. Otherwise, the + // first call to Next() returns the entire array. block_size is mainly + // useful for testing; in production you would probably never want to set + // it. + ArrayOutputStream(void* data, int size, int block_size = -1); + ~ArrayOutputStream(); + + // implements ZeroCopyOutputStream --------------------------------- + bool Next(void** data, int* size); + void BackUp(int count); + int64 ByteCount() const; + + private: + uint8* const data_; // The byte array. + const int size_; // Total size of the array. + const int block_size_; // How many bytes to return at a time. + + int position_; + int last_returned_size_; // How many bytes we returned last time Next() + // was called (used for error checking only). + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ArrayOutputStream); +}; + +// =================================================================== + +// A ZeroCopyOutputStream which appends bytes to a string. +class LIBPROTOBUF_EXPORT StringOutputStream : public ZeroCopyOutputStream { + public: + // Create a StringOutputStream which appends bytes to the given string. + // The string remains property of the caller, but it MUST NOT be accessed + // in any way until the stream is destroyed. + // + // Hint: If you call target->reserve(n) before creating the stream, + // the first call to Next() will return at least n bytes of buffer + // space. + explicit StringOutputStream(string* target); + ~StringOutputStream(); + + // implements ZeroCopyOutputStream --------------------------------- + bool Next(void** data, int* size); + void BackUp(int count); + int64 ByteCount() const; + + private: + static const int kMinimumSize = 16; + + string* target_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StringOutputStream); +}; + +// Note: There is no StringInputStream. Instead, just create an +// ArrayInputStream as follows: +// ArrayInputStream input(str.data(), str.size()); + +// =================================================================== + +// A generic traditional input stream interface. +// +// Lots of traditional input streams (e.g. file descriptors, C stdio +// streams, and C++ iostreams) expose an interface where every read +// involves copying bytes into a buffer. If you want to take such an +// interface and make a ZeroCopyInputStream based on it, simply implement +// CopyingInputStream and then use CopyingInputStreamAdaptor. +// +// CopyingInputStream implementations should avoid buffering if possible. +// CopyingInputStreamAdaptor does its own buffering and will read data +// in large blocks. +class LIBPROTOBUF_EXPORT CopyingInputStream { + public: + virtual ~CopyingInputStream(); + + // Reads up to "size" bytes into the given buffer. Returns the number of + // bytes read. Read() waits until at least one byte is available, or + // returns zero if no bytes will ever become available (EOF), or -1 if a + // permanent read error occurred. + virtual int Read(void* buffer, int size) = 0; + + // Skips the next "count" bytes of input. Returns the number of bytes + // actually skipped. This will always be exactly equal to "count" unless + // EOF was reached or a permanent read error occurred. + // + // The default implementation just repeatedly calls Read() into a scratch + // buffer. + virtual int Skip(int count); +}; + +// A ZeroCopyInputStream which reads from a CopyingInputStream. This is +// useful for implementing ZeroCopyInputStreams that read from traditional +// streams. Note that this class is not really zero-copy. +// +// If you want to read from file descriptors or C++ istreams, this is +// already implemented for you: use FileInputStream or IstreamInputStream +// respectively. +class LIBPROTOBUF_EXPORT CopyingInputStreamAdaptor : public ZeroCopyInputStream { + public: + // Creates a stream that reads from the given CopyingInputStream. + // If a block_size is given, it specifies the number of bytes that + // should be read and returned with each call to Next(). Otherwise, + // a reasonable default is used. The caller retains ownership of + // copying_stream unless SetOwnsCopyingStream(true) is called. + explicit CopyingInputStreamAdaptor(CopyingInputStream* copying_stream, + int block_size = -1); + ~CopyingInputStreamAdaptor(); + + // Call SetOwnsCopyingStream(true) to tell the CopyingInputStreamAdaptor to + // delete the underlying CopyingInputStream when it is destroyed. + void SetOwnsCopyingStream(bool value) { owns_copying_stream_ = value; } + + // implements ZeroCopyInputStream ---------------------------------- + bool Next(const void** data, int* size); + void BackUp(int count); + bool Skip(int count); + int64 ByteCount() const; + + private: + // Insures that buffer_ is not NULL. + void AllocateBufferIfNeeded(); + // Frees the buffer and resets buffer_used_. + void FreeBuffer(); + + // The underlying copying stream. + CopyingInputStream* copying_stream_; + bool owns_copying_stream_; + + // True if we have seen a permenant error from the underlying stream. + bool failed_; + + // The current position of copying_stream_, relative to the point where + // we started reading. + int64 position_; + + // Data is read into this buffer. It may be NULL if no buffer is currently + // in use. Otherwise, it points to an array of size buffer_size_. + scoped_array buffer_; + const int buffer_size_; + + // Number of valid bytes currently in the buffer (i.e. the size last + // returned by Next()). 0 <= buffer_used_ <= buffer_size_. + int buffer_used_; + + // Number of bytes in the buffer which were backed up over by a call to + // BackUp(). These need to be returned again. + // 0 <= backup_bytes_ <= buffer_used_ + int backup_bytes_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CopyingInputStreamAdaptor); +}; + +// =================================================================== + +// A generic traditional output stream interface. +// +// Lots of traditional output streams (e.g. file descriptors, C stdio +// streams, and C++ iostreams) expose an interface where every write +// involves copying bytes from a buffer. If you want to take such an +// interface and make a ZeroCopyOutputStream based on it, simply implement +// CopyingOutputStream and then use CopyingOutputStreamAdaptor. +// +// CopyingOutputStream implementations should avoid buffering if possible. +// CopyingOutputStreamAdaptor does its own buffering and will write data +// in large blocks. +class LIBPROTOBUF_EXPORT CopyingOutputStream { + public: + virtual ~CopyingOutputStream(); + + // Writes "size" bytes from the given buffer to the output. Returns true + // if successful, false on a write error. + virtual bool Write(const void* buffer, int size) = 0; +}; + +// A ZeroCopyOutputStream which writes to a CopyingOutputStream. This is +// useful for implementing ZeroCopyOutputStreams that write to traditional +// streams. Note that this class is not really zero-copy. +// +// If you want to write to file descriptors or C++ ostreams, this is +// already implemented for you: use FileOutputStream or OstreamOutputStream +// respectively. +class LIBPROTOBUF_EXPORT CopyingOutputStreamAdaptor : public ZeroCopyOutputStream { + public: + // Creates a stream that writes to the given Unix file descriptor. + // If a block_size is given, it specifies the size of the buffers + // that should be returned by Next(). Otherwise, a reasonable default + // is used. + explicit CopyingOutputStreamAdaptor(CopyingOutputStream* copying_stream, + int block_size = -1); + ~CopyingOutputStreamAdaptor(); + + // Writes all pending data to the underlying stream. Returns false if a + // write error occurred on the underlying stream. (The underlying + // stream itself is not necessarily flushed.) + bool Flush(); + + // Call SetOwnsCopyingStream(true) to tell the CopyingOutputStreamAdaptor to + // delete the underlying CopyingOutputStream when it is destroyed. + void SetOwnsCopyingStream(bool value) { owns_copying_stream_ = value; } + + // implements ZeroCopyOutputStream --------------------------------- + bool Next(void** data, int* size); + void BackUp(int count); + int64 ByteCount() const; + + private: + // Write the current buffer, if it is present. + bool WriteBuffer(); + // Insures that buffer_ is not NULL. + void AllocateBufferIfNeeded(); + // Frees the buffer. + void FreeBuffer(); + + // The underlying copying stream. + CopyingOutputStream* copying_stream_; + bool owns_copying_stream_; + + // True if we have seen a permenant error from the underlying stream. + bool failed_; + + // The current position of copying_stream_, relative to the point where + // we started writing. + int64 position_; + + // Data is written from this buffer. It may be NULL if no buffer is + // currently in use. Otherwise, it points to an array of size buffer_size_. + scoped_array buffer_; + const int buffer_size_; + + // Number of valid bytes currently in the buffer (i.e. the size last + // returned by Next()). When BackUp() is called, we just reduce this. + // 0 <= buffer_used_ <= buffer_size_. + int buffer_used_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CopyingOutputStreamAdaptor); +}; + +// =================================================================== + +} // namespace io +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_LITE_H__ diff --git a/include/google/protobuf/message.h b/include/google/protobuf/message.h new file mode 100644 index 000000000..0f90bc1a1 --- /dev/null +++ b/include/google/protobuf/message.h @@ -0,0 +1,837 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// Defines Message, the abstract interface implemented by non-lite +// protocol message objects. Although it's possible to implement this +// interface manually, most users will use the protocol compiler to +// generate implementations. +// +// Example usage: +// +// Say you have a message defined as: +// +// message Foo { +// optional string text = 1; +// repeated int32 numbers = 2; +// } +// +// Then, if you used the protocol compiler to generate a class from the above +// definition, you could use it like so: +// +// string data; // Will store a serialized version of the message. +// +// { +// // Create a message and serialize it. +// Foo foo; +// foo.set_text("Hello World!"); +// foo.add_numbers(1); +// foo.add_numbers(5); +// foo.add_numbers(42); +// +// foo.SerializeToString(&data); +// } +// +// { +// // Parse the serialized message and check that it contains the +// // correct data. +// Foo foo; +// foo.ParseFromString(data); +// +// assert(foo.text() == "Hello World!"); +// assert(foo.numbers_size() == 3); +// assert(foo.numbers(0) == 1); +// assert(foo.numbers(1) == 5); +// assert(foo.numbers(2) == 42); +// } +// +// { +// // Same as the last block, but do it dynamically via the Message +// // reflection interface. +// Message* foo = new Foo; +// const Descriptor* descriptor = foo->GetDescriptor(); +// +// // Get the descriptors for the fields we're interested in and verify +// // their types. +// const FieldDescriptor* text_field = descriptor->FindFieldByName("text"); +// assert(text_field != NULL); +// assert(text_field->type() == FieldDescriptor::TYPE_STRING); +// assert(text_field->label() == FieldDescriptor::LABEL_OPTIONAL); +// const FieldDescriptor* numbers_field = descriptor-> +// FindFieldByName("numbers"); +// assert(numbers_field != NULL); +// assert(numbers_field->type() == FieldDescriptor::TYPE_INT32); +// assert(numbers_field->label() == FieldDescriptor::LABEL_REPEATED); +// +// // Parse the message. +// foo->ParseFromString(data); +// +// // Use the reflection interface to examine the contents. +// const Reflection* reflection = foo->GetReflection(); +// assert(reflection->GetString(foo, text_field) == "Hello World!"); +// assert(reflection->FieldSize(foo, numbers_field) == 3); +// assert(reflection->GetRepeatedInt32(foo, numbers_field, 0) == 1); +// assert(reflection->GetRepeatedInt32(foo, numbers_field, 1) == 5); +// assert(reflection->GetRepeatedInt32(foo, numbers_field, 2) == 42); +// +// delete foo; +// } + +#ifndef GOOGLE_PROTOBUF_MESSAGE_H__ +#define GOOGLE_PROTOBUF_MESSAGE_H__ + +#include +#include + +#ifdef __DECCXX +// HP C++'s iosfwd doesn't work. +#include +#else +#include +#endif + +#include + +#include +#include + + +namespace google { +namespace protobuf { + +// Defined in this file. +class Message; +class Reflection; +class MessageFactory; + +// Defined in other files. +class UnknownFieldSet; // unknown_field_set.h +namespace io { + class ZeroCopyInputStream; // zero_copy_stream.h + class ZeroCopyOutputStream; // zero_copy_stream.h + class CodedInputStream; // coded_stream.h + class CodedOutputStream; // coded_stream.h +} + + +template +class RepeatedField; // repeated_field.h + +template +class RepeatedPtrField; // repeated_field.h + +// A container to hold message metadata. +struct Metadata { + const Descriptor* descriptor; + const Reflection* reflection; +}; + +// Abstract interface for protocol messages. +// +// See also MessageLite, which contains most every-day operations. Message +// adds descriptors and reflection on top of that. +// +// The methods of this class that are virtual but not pure-virtual have +// default implementations based on reflection. Message classes which are +// optimized for speed will want to override these with faster implementations, +// but classes optimized for code size may be happy with keeping them. See +// the optimize_for option in descriptor.proto. +class LIBPROTOBUF_EXPORT Message : public MessageLite { + public: + inline Message() {} + virtual ~Message(); + + // Basic Operations ------------------------------------------------ + + // Construct a new instance of the same type. Ownership is passed to the + // caller. (This is also defined in MessageLite, but is defined again here + // for return-type covariance.) + virtual Message* New() const = 0; + + // Make this message into a copy of the given message. The given message + // must have the same descriptor, but need not necessarily be the same class. + // By default this is just implemented as "Clear(); MergeFrom(from);". + virtual void CopyFrom(const Message& from); + + // Merge the fields from the given message into this message. Singular + // fields will be overwritten, except for embedded messages which will + // be merged. Repeated fields will be concatenated. The given message + // must be of the same type as this message (i.e. the exact same class). + virtual void MergeFrom(const Message& from); + + // Verifies that IsInitialized() returns true. GOOGLE_CHECK-fails otherwise, with + // a nice error message. + void CheckInitialized() const; + + // Slowly build a list of all required fields that are not set. + // This is much, much slower than IsInitialized() as it is implemented + // purely via reflection. Generally, you should not call this unless you + // have already determined that an error exists by calling IsInitialized(). + void FindInitializationErrors(vector* errors) const; + + // Like FindInitializationErrors, but joins all the strings, delimited by + // commas, and returns them. + string InitializationErrorString() const; + + // Clears all unknown fields from this message and all embedded messages. + // Normally, if unknown tag numbers are encountered when parsing a message, + // the tag and value are stored in the message's UnknownFieldSet and + // then written back out when the message is serialized. This allows servers + // which simply route messages to other servers to pass through messages + // that have new field definitions which they don't yet know about. However, + // this behavior can have security implications. To avoid it, call this + // method after parsing. + // + // See Reflection::GetUnknownFields() for more on unknown fields. + virtual void DiscardUnknownFields(); + + // Computes (an estimate of) the total number of bytes currently used for + // storing the message in memory. The default implementation calls the + // Reflection object's SpaceUsed() method. + virtual int SpaceUsed() const; + + // Debugging & Testing---------------------------------------------- + + // Generates a human readable form of this message, useful for debugging + // and other purposes. + string DebugString() const; + // Like DebugString(), but with less whitespace. + string ShortDebugString() const; + // Like DebugString(), but do not escape UTF-8 byte sequences. + string Utf8DebugString() const; + // Convenience function useful in GDB. Prints DebugString() to stdout. + void PrintDebugString() const; + + // Heavy I/O ------------------------------------------------------- + // Additional parsing and serialization methods not implemented by + // MessageLite because they are not supported by the lite library. + + // Parse a protocol buffer from a file descriptor. If successful, the entire + // input will be consumed. + bool ParseFromFileDescriptor(int file_descriptor); + // Like ParseFromFileDescriptor(), but accepts messages that are missing + // required fields. + bool ParsePartialFromFileDescriptor(int file_descriptor); + // Parse a protocol buffer from a C++ istream. If successful, the entire + // input will be consumed. + bool ParseFromIstream(istream* input); + // Like ParseFromIstream(), but accepts messages that are missing + // required fields. + bool ParsePartialFromIstream(istream* input); + + // Serialize the message and write it to the given file descriptor. All + // required fields must be set. + bool SerializeToFileDescriptor(int file_descriptor) const; + // Like SerializeToFileDescriptor(), but allows missing required fields. + bool SerializePartialToFileDescriptor(int file_descriptor) const; + // Serialize the message and write it to the given C++ ostream. All + // required fields must be set. + bool SerializeToOstream(ostream* output) const; + // Like SerializeToOstream(), but allows missing required fields. + bool SerializePartialToOstream(ostream* output) const; + + + // Reflection-based methods ---------------------------------------- + // These methods are pure-virtual in MessageLite, but Message provides + // reflection-based default implementations. + + virtual string GetTypeName() const; + virtual void Clear(); + virtual bool IsInitialized() const; + virtual void CheckTypeAndMergeFrom(const MessageLite& other); + virtual bool MergePartialFromCodedStream(io::CodedInputStream* input); + virtual int ByteSize() const; + virtual void SerializeWithCachedSizes(io::CodedOutputStream* output) const; + + private: + // This is called only by the default implementation of ByteSize(), to + // update the cached size. If you override ByteSize(), you do not need + // to override this. If you do not override ByteSize(), you MUST override + // this; the default implementation will crash. + // + // The method is private because subclasses should never call it; only + // override it. Yes, C++ lets you do that. Crazy, huh? + virtual void SetCachedSize(int size) const; + + public: + + // Introspection --------------------------------------------------- + + // Typedef for backwards-compatibility. + typedef google::protobuf::Reflection Reflection; + + // Get a Descriptor for this message's type. This describes what + // fields the message contains, the types of those fields, etc. + const Descriptor* GetDescriptor() const { return GetMetadata().descriptor; } + + // Get the Reflection interface for this Message, which can be used to + // read and modify the fields of the Message dynamically (in other words, + // without knowing the message type at compile time). This object remains + // property of the Message. + // + // This method remains virtual in case a subclass does not implement + // reflection and wants to override the default behavior. + virtual const Reflection* GetReflection() const { + return GetMetadata().reflection; + } + + protected: + // Get a struct containing the metadata for the Message. Most subclasses only + // need to implement this method, rather than the GetDescriptor() and + // GetReflection() wrappers. + virtual Metadata GetMetadata() const = 0; + + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Message); +}; + +// This interface contains methods that can be used to dynamically access +// and modify the fields of a protocol message. Their semantics are +// similar to the accessors the protocol compiler generates. +// +// To get the Reflection for a given Message, call Message::GetReflection(). +// +// This interface is separate from Message only for efficiency reasons; +// the vast majority of implementations of Message will share the same +// implementation of Reflection (GeneratedMessageReflection, +// defined in generated_message.h), and all Messages of a particular class +// should share the same Reflection object (though you should not rely on +// the latter fact). +// +// There are several ways that these methods can be used incorrectly. For +// example, any of the following conditions will lead to undefined +// results (probably assertion failures): +// - The FieldDescriptor is not a field of this message type. +// - The method called is not appropriate for the field's type. For +// each field type in FieldDescriptor::TYPE_*, there is only one +// Get*() method, one Set*() method, and one Add*() method that is +// valid for that type. It should be obvious which (except maybe +// for TYPE_BYTES, which are represented using strings in C++). +// - A Get*() or Set*() method for singular fields is called on a repeated +// field. +// - GetRepeated*(), SetRepeated*(), or Add*() is called on a non-repeated +// field. +// - The Message object passed to any method is not of the right type for +// this Reflection object (i.e. message.GetReflection() != reflection). +// +// You might wonder why there is not any abstract representation for a field +// of arbitrary type. E.g., why isn't there just a "GetField()" method that +// returns "const Field&", where "Field" is some class with accessors like +// "GetInt32Value()". The problem is that someone would have to deal with +// allocating these Field objects. For generated message classes, having to +// allocate space for an additional object to wrap every field would at least +// double the message's memory footprint, probably worse. Allocating the +// objects on-demand, on the other hand, would be expensive and prone to +// memory leaks. So, instead we ended up with this flat interface. +// +// TODO(kenton): Create a utility class which callers can use to read and +// write fields from a Reflection without paying attention to the type. +class LIBPROTOBUF_EXPORT Reflection { + public: + inline Reflection() {} + virtual ~Reflection(); + + // Get the UnknownFieldSet for the message. This contains fields which + // were seen when the Message was parsed but were not recognized according + // to the Message's definition. + virtual const UnknownFieldSet& GetUnknownFields( + const Message& message) const = 0; + // Get a mutable pointer to the UnknownFieldSet for the message. This + // contains fields which were seen when the Message was parsed but were not + // recognized according to the Message's definition. + virtual UnknownFieldSet* MutableUnknownFields(Message* message) const = 0; + + // Estimate the amount of memory used by the message object. + virtual int SpaceUsed(const Message& message) const = 0; + + // Check if the given non-repeated field is set. + virtual bool HasField(const Message& message, + const FieldDescriptor* field) const = 0; + + // Get the number of elements of a repeated field. + virtual int FieldSize(const Message& message, + const FieldDescriptor* field) const = 0; + + // Clear the value of a field, so that HasField() returns false or + // FieldSize() returns zero. + virtual void ClearField(Message* message, + const FieldDescriptor* field) const = 0; + + // Removes the last element of a repeated field. + // We don't provide a way to remove any element other than the last + // because it invites inefficient use, such as O(n^2) filtering loops + // that should have been O(n). If you want to remove an element other + // than the last, the best way to do it is to re-arrange the elements + // (using Swap()) so that the one you want removed is at the end, then + // call RemoveLast(). + virtual void RemoveLast(Message* message, + const FieldDescriptor* field) const = 0; + // Removes the last element of a repeated message field, and returns the + // pointer to the caller. Caller takes ownership of the returned pointer. + virtual Message* ReleaseLast(Message* message, + const FieldDescriptor* field) const = 0; + + // Swap the complete contents of two messages. + virtual void Swap(Message* message1, Message* message2) const = 0; + + // Swap two elements of a repeated field. + virtual void SwapElements(Message* message, + const FieldDescriptor* field, + int index1, + int index2) const = 0; + + // List all fields of the message which are currently set. This includes + // extensions. Singular fields will only be listed if HasField(field) would + // return true and repeated fields will only be listed if FieldSize(field) + // would return non-zero. Fields (both normal fields and extension fields) + // will be listed ordered by field number. + virtual void ListFields(const Message& message, + vector* output) const = 0; + + // Singular field getters ------------------------------------------ + // These get the value of a non-repeated field. They return the default + // value for fields that aren't set. + + virtual int32 GetInt32 (const Message& message, + const FieldDescriptor* field) const = 0; + virtual int64 GetInt64 (const Message& message, + const FieldDescriptor* field) const = 0; + virtual uint32 GetUInt32(const Message& message, + const FieldDescriptor* field) const = 0; + virtual uint64 GetUInt64(const Message& message, + const FieldDescriptor* field) const = 0; + virtual float GetFloat (const Message& message, + const FieldDescriptor* field) const = 0; + virtual double GetDouble(const Message& message, + const FieldDescriptor* field) const = 0; + virtual bool GetBool (const Message& message, + const FieldDescriptor* field) const = 0; + virtual string GetString(const Message& message, + const FieldDescriptor* field) const = 0; + virtual const EnumValueDescriptor* GetEnum( + const Message& message, const FieldDescriptor* field) const = 0; + // See MutableMessage() for the meaning of the "factory" parameter. + virtual const Message& GetMessage(const Message& message, + const FieldDescriptor* field, + MessageFactory* factory = NULL) const = 0; + + // Get a string value without copying, if possible. + // + // GetString() necessarily returns a copy of the string. This can be + // inefficient when the string is already stored in a string object in the + // underlying message. GetStringReference() will return a reference to the + // underlying string in this case. Otherwise, it will copy the string into + // *scratch and return that. + // + // Note: It is perfectly reasonable and useful to write code like: + // str = reflection->GetStringReference(field, &str); + // This line would ensure that only one copy of the string is made + // regardless of the field's underlying representation. When initializing + // a newly-constructed string, though, it's just as fast and more readable + // to use code like: + // string str = reflection->GetString(field); + virtual const string& GetStringReference(const Message& message, + const FieldDescriptor* field, + string* scratch) const = 0; + + + // Singular field mutators ----------------------------------------- + // These mutate the value of a non-repeated field. + + virtual void SetInt32 (Message* message, + const FieldDescriptor* field, int32 value) const = 0; + virtual void SetInt64 (Message* message, + const FieldDescriptor* field, int64 value) const = 0; + virtual void SetUInt32(Message* message, + const FieldDescriptor* field, uint32 value) const = 0; + virtual void SetUInt64(Message* message, + const FieldDescriptor* field, uint64 value) const = 0; + virtual void SetFloat (Message* message, + const FieldDescriptor* field, float value) const = 0; + virtual void SetDouble(Message* message, + const FieldDescriptor* field, double value) const = 0; + virtual void SetBool (Message* message, + const FieldDescriptor* field, bool value) const = 0; + virtual void SetString(Message* message, + const FieldDescriptor* field, + const string& value) const = 0; + virtual void SetEnum (Message* message, + const FieldDescriptor* field, + const EnumValueDescriptor* value) const = 0; + // Get a mutable pointer to a field with a message type. If a MessageFactory + // is provided, it will be used to construct instances of the sub-message; + // otherwise, the default factory is used. If the field is an extension that + // does not live in the same pool as the containing message's descriptor (e.g. + // it lives in an overlay pool), then a MessageFactory must be provided. + // If you have no idea what that meant, then you probably don't need to worry + // about it (don't provide a MessageFactory). WARNING: If the + // FieldDescriptor is for a compiled-in extension, then + // factory->GetPrototype(field->message_type() MUST return an instance of the + // compiled-in class for this type, NOT DynamicMessage. + virtual Message* MutableMessage(Message* message, + const FieldDescriptor* field, + MessageFactory* factory = NULL) const = 0; + // Releases the message specified by 'field' and returns the pointer, + // ReleaseMessage() will return the message the message object if it exists. + // Otherwise, it may or may not return NULL. In any case, if the return value + // is non-NULL, the caller takes ownership of the pointer. + // If the field existed (HasField() is true), then the returned pointer will + // be the same as the pointer returned by MutableMessage(). + // This function has the same effect as ClearField(). + virtual Message* ReleaseMessage(Message* message, + const FieldDescriptor* field, + MessageFactory* factory = NULL) const = 0; + + + // Repeated field getters ------------------------------------------ + // These get the value of one element of a repeated field. + + virtual int32 GetRepeatedInt32 (const Message& message, + const FieldDescriptor* field, + int index) const = 0; + virtual int64 GetRepeatedInt64 (const Message& message, + const FieldDescriptor* field, + int index) const = 0; + virtual uint32 GetRepeatedUInt32(const Message& message, + const FieldDescriptor* field, + int index) const = 0; + virtual uint64 GetRepeatedUInt64(const Message& message, + const FieldDescriptor* field, + int index) const = 0; + virtual float GetRepeatedFloat (const Message& message, + const FieldDescriptor* field, + int index) const = 0; + virtual double GetRepeatedDouble(const Message& message, + const FieldDescriptor* field, + int index) const = 0; + virtual bool GetRepeatedBool (const Message& message, + const FieldDescriptor* field, + int index) const = 0; + virtual string GetRepeatedString(const Message& message, + const FieldDescriptor* field, + int index) const = 0; + virtual const EnumValueDescriptor* GetRepeatedEnum( + const Message& message, + const FieldDescriptor* field, int index) const = 0; + virtual const Message& GetRepeatedMessage( + const Message& message, + const FieldDescriptor* field, int index) const = 0; + + // See GetStringReference(), above. + virtual const string& GetRepeatedStringReference( + const Message& message, const FieldDescriptor* field, + int index, string* scratch) const = 0; + + + // Repeated field mutators ----------------------------------------- + // These mutate the value of one element of a repeated field. + + virtual void SetRepeatedInt32 (Message* message, + const FieldDescriptor* field, + int index, int32 value) const = 0; + virtual void SetRepeatedInt64 (Message* message, + const FieldDescriptor* field, + int index, int64 value) const = 0; + virtual void SetRepeatedUInt32(Message* message, + const FieldDescriptor* field, + int index, uint32 value) const = 0; + virtual void SetRepeatedUInt64(Message* message, + const FieldDescriptor* field, + int index, uint64 value) const = 0; + virtual void SetRepeatedFloat (Message* message, + const FieldDescriptor* field, + int index, float value) const = 0; + virtual void SetRepeatedDouble(Message* message, + const FieldDescriptor* field, + int index, double value) const = 0; + virtual void SetRepeatedBool (Message* message, + const FieldDescriptor* field, + int index, bool value) const = 0; + virtual void SetRepeatedString(Message* message, + const FieldDescriptor* field, + int index, const string& value) const = 0; + virtual void SetRepeatedEnum(Message* message, + const FieldDescriptor* field, int index, + const EnumValueDescriptor* value) const = 0; + // Get a mutable pointer to an element of a repeated field with a message + // type. + virtual Message* MutableRepeatedMessage( + Message* message, const FieldDescriptor* field, int index) const = 0; + + + // Repeated field adders ------------------------------------------- + // These add an element to a repeated field. + + virtual void AddInt32 (Message* message, + const FieldDescriptor* field, int32 value) const = 0; + virtual void AddInt64 (Message* message, + const FieldDescriptor* field, int64 value) const = 0; + virtual void AddUInt32(Message* message, + const FieldDescriptor* field, uint32 value) const = 0; + virtual void AddUInt64(Message* message, + const FieldDescriptor* field, uint64 value) const = 0; + virtual void AddFloat (Message* message, + const FieldDescriptor* field, float value) const = 0; + virtual void AddDouble(Message* message, + const FieldDescriptor* field, double value) const = 0; + virtual void AddBool (Message* message, + const FieldDescriptor* field, bool value) const = 0; + virtual void AddString(Message* message, + const FieldDescriptor* field, + const string& value) const = 0; + virtual void AddEnum (Message* message, + const FieldDescriptor* field, + const EnumValueDescriptor* value) const = 0; + // See MutableMessage() for comments on the "factory" parameter. + virtual Message* AddMessage(Message* message, + const FieldDescriptor* field, + MessageFactory* factory = NULL) const = 0; + + + // Repeated field accessors ------------------------------------------------- + // The methods above, e.g. GetRepeatedInt32(msg, fd, index), provide singular + // access to the data in a RepeatedField. The methods below provide aggregate + // access by exposing the RepeatedField object itself with the Message. + // Applying these templates to inappropriate types will lead to an undefined + // reference at link time (e.g. GetRepeatedField<***double>), or possibly a + // template matching error at compile time (e.g. GetRepeatedPtrField). + // + // Usage example: my_doubs = refl->GetRepeatedField(msg, fd); + + // for T = Cord and all protobuf scalar types except enums. + template + const RepeatedField& GetRepeatedField( + const Message&, const FieldDescriptor*) const; + + // for T = Cord and all protobuf scalar types except enums. + template + RepeatedField* MutableRepeatedField( + Message*, const FieldDescriptor*) const; + + // for T = string, google::protobuf::internal::StringPieceField + // google::protobuf::Message & descendants. + template + const RepeatedPtrField& GetRepeatedPtrField( + const Message&, const FieldDescriptor*) const; + + // for T = string, google::protobuf::internal::StringPieceField + // google::protobuf::Message & descendants. + template + RepeatedPtrField* MutableRepeatedPtrField( + Message*, const FieldDescriptor*) const; + + // Extensions ---------------------------------------------------------------- + + // Try to find an extension of this message type by fully-qualified field + // name. Returns NULL if no extension is known for this name or number. + virtual const FieldDescriptor* FindKnownExtensionByName( + const string& name) const = 0; + + // Try to find an extension of this message type by field number. + // Returns NULL if no extension is known for this name or number. + virtual const FieldDescriptor* FindKnownExtensionByNumber( + int number) const = 0; + + // --------------------------------------------------------------------------- + + protected: + // Obtain a pointer to a Repeated Field Structure and do some type checking: + // on field->cpp_type(), + // on field->field_option().ctype() (if ctype >= 0) + // of field->message_type() (if message_type != NULL). + // We use 1 routine rather than 4 (const vs mutable) x (scalar vs pointer). + virtual void* MutableRawRepeatedField( + Message* message, const FieldDescriptor* field, FieldDescriptor::CppType, + int ctype, const Descriptor* message_type) const = 0; + + private: + // Special version for specialized implementations of string. We can't call + // MutableRawRepeatedField directly here because we don't have access to + // FieldOptions::* which are defined in descriptor.pb.h. Including that + // file here is not possible because it would cause a circular include cycle. + void* MutableRawRepeatedString( + Message* message, const FieldDescriptor* field, bool is_string) const; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Reflection); +}; + +// Abstract interface for a factory for message objects. +class LIBPROTOBUF_EXPORT MessageFactory { + public: + inline MessageFactory() {} + virtual ~MessageFactory(); + + // Given a Descriptor, gets or constructs the default (prototype) Message + // of that type. You can then call that message's New() method to construct + // a mutable message of that type. + // + // Calling this method twice with the same Descriptor returns the same + // object. The returned object remains property of the factory. Also, any + // objects created by calling the prototype's New() method share some data + // with the prototype, so these must be destoyed before the MessageFactory + // is destroyed. + // + // The given descriptor must outlive the returned message, and hence must + // outlive the MessageFactory. + // + // Some implementations do not support all types. GetPrototype() will + // return NULL if the descriptor passed in is not supported. + // + // This method may or may not be thread-safe depending on the implementation. + // Each implementation should document its own degree thread-safety. + virtual const Message* GetPrototype(const Descriptor* type) = 0; + + // Gets a MessageFactory which supports all generated, compiled-in messages. + // In other words, for any compiled-in type FooMessage, the following is true: + // MessageFactory::generated_factory()->GetPrototype( + // FooMessage::descriptor()) == FooMessage::default_instance() + // This factory supports all types which are found in + // DescriptorPool::generated_pool(). If given a descriptor from any other + // pool, GetPrototype() will return NULL. (You can also check if a + // descriptor is for a generated message by checking if + // descriptor->file()->pool() == DescriptorPool::generated_pool().) + // + // This factory is 100% thread-safe; calling GetPrototype() does not modify + // any shared data. + // + // This factory is a singleton. The caller must not delete the object. + static MessageFactory* generated_factory(); + + // For internal use only: Registers a .proto file at static initialization + // time, to be placed in generated_factory. The first time GetPrototype() + // is called with a descriptor from this file, |register_messages| will be + // called, with the file name as the parameter. It must call + // InternalRegisterGeneratedMessage() (below) to register each message type + // in the file. This strange mechanism is necessary because descriptors are + // built lazily, so we can't register types by their descriptor until we + // know that the descriptor exists. |filename| must be a permanent string. + static void InternalRegisterGeneratedFile( + const char* filename, void (*register_messages)(const string&)); + + // For internal use only: Registers a message type. Called only by the + // functions which are registered with InternalRegisterGeneratedFile(), + // above. + static void InternalRegisterGeneratedMessage(const Descriptor* descriptor, + const Message* prototype); + + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageFactory); +}; + +#define DECLARE_GET_REPEATED_FIELD(TYPE) \ +template<> \ +LIBPROTOBUF_EXPORT \ +const RepeatedField& Reflection::GetRepeatedField( \ + const Message& message, const FieldDescriptor* field) const; \ + \ +template<> \ +LIBPROTOBUF_EXPORT \ +RepeatedField* Reflection::MutableRepeatedField( \ + Message* message, const FieldDescriptor* field) const; + +DECLARE_GET_REPEATED_FIELD(int32) +DECLARE_GET_REPEATED_FIELD(int64) +DECLARE_GET_REPEATED_FIELD(uint32) +DECLARE_GET_REPEATED_FIELD(uint64) +DECLARE_GET_REPEATED_FIELD(float) +DECLARE_GET_REPEATED_FIELD(double) +DECLARE_GET_REPEATED_FIELD(bool) + +#undef DECLARE_GET_REPEATED_FIELD + +// ============================================================================= +// Implementation details for {Get,Mutable}RawRepeatedPtrField. We provide +// specializations for , and and handle +// everything else with the default template which will match any type having +// a method with signature "static const google::protobuf::Descriptor* descriptor()". +// Such a type presumably is a descendant of google::protobuf::Message. + +template<> +inline const RepeatedPtrField& Reflection::GetRepeatedPtrField( + const Message& message, const FieldDescriptor* field) const { + return *static_cast* >( + MutableRawRepeatedString(const_cast(&message), field, true)); +} + +template<> +inline RepeatedPtrField* Reflection::MutableRepeatedPtrField( + Message* message, const FieldDescriptor* field) const { + return static_cast* >( + MutableRawRepeatedString(message, field, true)); +} + + +// ----- + +template<> +inline const RepeatedPtrField& Reflection::GetRepeatedPtrField( + const Message& message, const FieldDescriptor* field) const { + return *static_cast* >( + MutableRawRepeatedField(const_cast(&message), field, + FieldDescriptor::CPPTYPE_MESSAGE, -1, + NULL)); +} + +template<> +inline RepeatedPtrField* Reflection::MutableRepeatedPtrField( + Message* message, const FieldDescriptor* field) const { + return static_cast* >( + MutableRawRepeatedField(message, field, + FieldDescriptor::CPPTYPE_MESSAGE, -1, + NULL)); +} + +template +inline const RepeatedPtrField& Reflection::GetRepeatedPtrField( + const Message& message, const FieldDescriptor* field) const { + return *static_cast* >( + MutableRawRepeatedField(const_cast(&message), field, + FieldDescriptor::CPPTYPE_MESSAGE, -1, + PB::default_instance().GetDescriptor())); +} + +template +inline RepeatedPtrField* Reflection::MutableRepeatedPtrField( + Message* message, const FieldDescriptor* field) const { + return static_cast* >( + MutableRawRepeatedField(message, field, + FieldDescriptor::CPPTYPE_MESSAGE, -1, + PB::default_instance().GetDescriptor())); +} + +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_MESSAGE_H__ diff --git a/include/google/protobuf/message_lite.h b/include/google/protobuf/message_lite.h new file mode 100644 index 000000000..1ec3068cf --- /dev/null +++ b/include/google/protobuf/message_lite.h @@ -0,0 +1,246 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Authors: wink@google.com (Wink Saville), +// kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// Defines MessageLite, the abstract interface implemented by all (lite +// and non-lite) protocol message objects. + +#ifndef GOOGLE_PROTOBUF_MESSAGE_LITE_H__ +#define GOOGLE_PROTOBUF_MESSAGE_LITE_H__ + +#include + +namespace google { +namespace protobuf { + +namespace io { + class CodedInputStream; + class CodedOutputStream; + class ZeroCopyInputStream; + class ZeroCopyOutputStream; +} + +// Interface to light weight protocol messages. +// +// This interface is implemented by all protocol message objects. Non-lite +// messages additionally implement the Message interface, which is a +// subclass of MessageLite. Use MessageLite instead when you only need +// the subset of features which it supports -- namely, nothing that uses +// descriptors or reflection. You can instruct the protocol compiler +// to generate classes which implement only MessageLite, not the full +// Message interface, by adding the following line to the .proto file: +// +// option optimize_for = LITE_RUNTIME; +// +// This is particularly useful on resource-constrained systems where +// the full protocol buffers runtime library is too big. +// +// Note that on non-constrained systems (e.g. servers) when you need +// to link in lots of protocol definitions, a better way to reduce +// total code footprint is to use optimize_for = CODE_SIZE. This +// will make the generated code smaller while still supporting all the +// same features (at the expense of speed). optimize_for = LITE_RUNTIME +// is best when you only have a small number of message types linked +// into your binary, in which case the size of the protocol buffers +// runtime itself is the biggest problem. +class LIBPROTOBUF_EXPORT MessageLite { + public: + inline MessageLite() {} + virtual ~MessageLite(); + + // Basic Operations ------------------------------------------------ + + // Get the name of this message type, e.g. "foo.bar.BazProto". + virtual string GetTypeName() const = 0; + + // Construct a new instance of the same type. Ownership is passed to the + // caller. + virtual MessageLite* New() const = 0; + + // Clear all fields of the message and set them to their default values. + // Clear() avoids freeing memory, assuming that any memory allocated + // to hold parts of the message will be needed again to hold the next + // message. If you actually want to free the memory used by a Message, + // you must delete it. + virtual void Clear() = 0; + + // Quickly check if all required fields have values set. + virtual bool IsInitialized() const = 0; + + // This is not implemented for Lite messages -- it just returns "(cannot + // determine missing fields for lite message)". However, it is implemented + // for full messages. See message.h. + virtual string InitializationErrorString() const; + + // If |other| is the exact same class as this, calls MergeFrom(). Otherwise, + // results are undefined (probably crash). + virtual void CheckTypeAndMergeFrom(const MessageLite& other) = 0; + + // Parsing --------------------------------------------------------- + // Methods for parsing in protocol buffer format. Most of these are + // just simple wrappers around MergeFromCodedStream(). + + // Fill the message with a protocol buffer parsed from the given input + // stream. Returns false on a read error or if the input is in the + // wrong format. + bool ParseFromCodedStream(io::CodedInputStream* input); + // Like ParseFromCodedStream(), but accepts messages that are missing + // required fields. + bool ParsePartialFromCodedStream(io::CodedInputStream* input); + // Read a protocol buffer from the given zero-copy input stream. If + // successful, the entire input will be consumed. + bool ParseFromZeroCopyStream(io::ZeroCopyInputStream* input); + // Like ParseFromZeroCopyStream(), but accepts messages that are missing + // required fields. + bool ParsePartialFromZeroCopyStream(io::ZeroCopyInputStream* input); + // Read a protocol buffer from the given zero-copy input stream, expecting + // the message to be exactly "size" bytes long. If successful, exactly + // this many bytes will have been consumed from the input. + bool ParseFromBoundedZeroCopyStream(io::ZeroCopyInputStream* input, int size); + // Like ParseFromBoundedZeroCopyStream(), but accepts messages that are + // missing required fields. + bool ParsePartialFromBoundedZeroCopyStream(io::ZeroCopyInputStream* input, + int size); + // Parse a protocol buffer contained in a string. + bool ParseFromString(const string& data); + // Like ParseFromString(), but accepts messages that are missing + // required fields. + bool ParsePartialFromString(const string& data); + // Parse a protocol buffer contained in an array of bytes. + bool ParseFromArray(const void* data, int size); + // Like ParseFromArray(), but accepts messages that are missing + // required fields. + bool ParsePartialFromArray(const void* data, int size); + + + // Reads a protocol buffer from the stream and merges it into this + // Message. Singular fields read from the input overwrite what is + // already in the Message and repeated fields are appended to those + // already present. + // + // It is the responsibility of the caller to call input->LastTagWas() + // (for groups) or input->ConsumedEntireMessage() (for non-groups) after + // this returns to verify that the message's end was delimited correctly. + // + // ParsefromCodedStream() is implemented as Clear() followed by + // MergeFromCodedStream(). + bool MergeFromCodedStream(io::CodedInputStream* input); + + // Like MergeFromCodedStream(), but succeeds even if required fields are + // missing in the input. + // + // MergeFromCodedStream() is just implemented as MergePartialFromCodedStream() + // followed by IsInitialized(). + virtual bool MergePartialFromCodedStream(io::CodedInputStream* input) = 0; + + + // Serialization --------------------------------------------------- + // Methods for serializing in protocol buffer format. Most of these + // are just simple wrappers around ByteSize() and SerializeWithCachedSizes(). + + // Write a protocol buffer of this message to the given output. Returns + // false on a write error. If the message is missing required fields, + // this may GOOGLE_CHECK-fail. + bool SerializeToCodedStream(io::CodedOutputStream* output) const; + // Like SerializeToCodedStream(), but allows missing required fields. + bool SerializePartialToCodedStream(io::CodedOutputStream* output) const; + // Write the message to the given zero-copy output stream. All required + // fields must be set. + bool SerializeToZeroCopyStream(io::ZeroCopyOutputStream* output) const; + // Like SerializeToZeroCopyStream(), but allows missing required fields. + bool SerializePartialToZeroCopyStream(io::ZeroCopyOutputStream* output) const; + // Serialize the message and store it in the given string. All required + // fields must be set. + bool SerializeToString(string* output) const; + // Like SerializeToString(), but allows missing required fields. + bool SerializePartialToString(string* output) const; + // Serialize the message and store it in the given byte array. All required + // fields must be set. + bool SerializeToArray(void* data, int size) const; + // Like SerializeToArray(), but allows missing required fields. + bool SerializePartialToArray(void* data, int size) const; + + // Make a string encoding the message. Is equivalent to calling + // SerializeToString() on a string and using that. Returns the empty + // string if SerializeToString() would have returned an error. + // Note: If you intend to generate many such strings, you may + // reduce heap fragmentation by instead re-using the same string + // object with calls to SerializeToString(). + string SerializeAsString() const; + // Like SerializeAsString(), but allows missing required fields. + string SerializePartialAsString() const; + + // Like SerializeToString(), but appends to the data to the string's existing + // contents. All required fields must be set. + bool AppendToString(string* output) const; + // Like AppendToString(), but allows missing required fields. + bool AppendPartialToString(string* output) const; + + // Computes the serialized size of the message. This recursively calls + // ByteSize() on all embedded messages. If a subclass does not override + // this, it MUST override SetCachedSize(). + virtual int ByteSize() const = 0; + + // Serializes the message without recomputing the size. The message must + // not have changed since the last call to ByteSize(); if it has, the results + // are undefined. + virtual void SerializeWithCachedSizes( + io::CodedOutputStream* output) const = 0; + + // Like SerializeWithCachedSizes, but writes directly to *target, returning + // a pointer to the byte immediately after the last byte written. "target" + // must point at a byte array of at least ByteSize() bytes. + virtual uint8* SerializeWithCachedSizesToArray(uint8* target) const; + + // Returns the result of the last call to ByteSize(). An embedded message's + // size is needed both to serialize it (because embedded messages are + // length-delimited) and to compute the outer message's size. Caching + // the size avoids computing it multiple times. + // + // ByteSize() does not automatically use the cached size when available + // because this would require invalidating it every time the message was + // modified, which would be too hard and expensive. (E.g. if a deeply-nested + // sub-message is changed, all of its parents' cached sizes would need to be + // invalidated, which is too much work for an otherwise inlined setter + // method.) + virtual int GetCachedSize() const = 0; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageLite); +}; + +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_MESSAGE_LITE_H__ diff --git a/include/google/protobuf/reflection_ops.h b/include/google/protobuf/reflection_ops.h new file mode 100644 index 000000000..60165c2a6 --- /dev/null +++ b/include/google/protobuf/reflection_ops.h @@ -0,0 +1,81 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// This header is logically internal, but is made public because it is used +// from protocol-compiler-generated code, which may reside in other components. + +#ifndef GOOGLE_PROTOBUF_REFLECTION_OPS_H__ +#define GOOGLE_PROTOBUF_REFLECTION_OPS_H__ + +#include +#include + +namespace google { +namespace protobuf { +namespace internal { + +// Basic operations that can be performed using reflection. +// These can be used as a cheap way to implement the corresponding +// methods of the Message interface, though they are likely to be +// slower than implementations tailored for the specific message type. +// +// This class should stay limited to operations needed to implement +// the Message interface. +// +// This class is really a namespace that contains only static methods. +class LIBPROTOBUF_EXPORT ReflectionOps { + public: + static void Copy(const Message& from, Message* to); + static void Merge(const Message& from, Message* to); + static void Clear(Message* message); + static bool IsInitialized(const Message& message); + static void DiscardUnknownFields(Message* message); + + // Finds all unset required fields in the message and adds their full + // paths (e.g. "foo.bar[5].baz") to *names. "prefix" will be attached to + // the front of each name. + static void FindInitializationErrors(const Message& message, + const string& prefix, + vector* errors); + + private: + // All methods are static. No need to construct. + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ReflectionOps); +}; + +} // namespace internal +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_REFLECTION_OPS_H__ diff --git a/include/google/protobuf/repeated_field.h b/include/google/protobuf/repeated_field.h new file mode 100644 index 000000000..bbf1daefd --- /dev/null +++ b/include/google/protobuf/repeated_field.h @@ -0,0 +1,1519 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// RepeatedField and RepeatedPtrField are used by generated protocol message +// classes to manipulate repeated fields. These classes are very similar to +// STL's vector, but include a number of optimizations found to be useful +// specifically in the case of Protocol Buffers. RepeatedPtrField is +// particularly different from STL vector as it manages ownership of the +// pointers that it contains. +// +// Typically, clients should not need to access RepeatedField objects directly, +// but should instead use the accessor functions generated automatically by the +// protocol compiler. + +#ifndef GOOGLE_PROTOBUF_REPEATED_FIELD_H__ +#define GOOGLE_PROTOBUF_REPEATED_FIELD_H__ + +#include +#include +#include +#include +#include +#include +#include + +namespace google { + +namespace upb { +namespace google_opensource { +class GMR_Handlers; +} // namespace google_opensource +} // namespace upb + +namespace protobuf { + +class Message; + +namespace internal { + +static const int kMinRepeatedFieldAllocationSize = 4; + +// A utility function for logging that doesn't need any template types. +void LogIndexOutOfBounds(int index, int size); +} // namespace internal + + +// RepeatedField is used to represent repeated fields of a primitive type (in +// other words, everything except strings and nested Messages). Most users will +// not ever use a RepeatedField directly; they will use the get-by-index, +// set-by-index, and add accessors that are generated for all repeated fields. +template +class RepeatedField { + public: + RepeatedField(); + RepeatedField(const RepeatedField& other); + template + RepeatedField(Iter begin, const Iter& end); + ~RepeatedField(); + + RepeatedField& operator=(const RepeatedField& other); + + int size() const; + + const Element& Get(int index) const; + Element* Mutable(int index); + void Set(int index, const Element& value); + void Add(const Element& value); + Element* Add(); + // Remove the last element in the array. + void RemoveLast(); + + // Extract elements with indices in "[start .. start+num-1]". + // Copy them into "elements[0 .. num-1]" if "elements" is not NULL. + // Caution: implementation also moves elements with indices [start+num ..]. + // Calling this routine inside a loop can cause quadratic behavior. + void ExtractSubrange(int start, int num, Element* elements); + + void Clear(); + void MergeFrom(const RepeatedField& other); + void CopyFrom(const RepeatedField& other); + + // Reserve space to expand the field to at least the given size. If the + // array is grown, it will always be at least doubled in size. + void Reserve(int new_size); + + // Resize the RepeatedField to a new, smaller size. This is O(1). + void Truncate(int new_size); + + void AddAlreadyReserved(const Element& value); + Element* AddAlreadyReserved(); + int Capacity() const; + + // Gets the underlying array. This pointer is possibly invalidated by + // any add or remove operation. + Element* mutable_data(); + const Element* data() const; + + // Swap entire contents with "other". + void Swap(RepeatedField* other); + + // Swap two elements. + void SwapElements(int index1, int index2); + + // STL-like iterator support + typedef Element* iterator; + typedef const Element* const_iterator; + typedef Element value_type; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef int size_type; + typedef ptrdiff_t difference_type; + + iterator begin(); + const_iterator begin() const; + iterator end(); + const_iterator end() const; + + // Reverse iterator support + typedef std::reverse_iterator const_reverse_iterator; + typedef std::reverse_iterator reverse_iterator; + reverse_iterator rbegin() { + return reverse_iterator(end()); + } + const_reverse_iterator rbegin() const { + return const_reverse_iterator(end()); + } + reverse_iterator rend() { + return reverse_iterator(begin()); + } + const_reverse_iterator rend() const { + return const_reverse_iterator(begin()); + } + + // Returns the number of bytes used by the repeated field, excluding + // sizeof(*this) + int SpaceUsedExcludingSelf() const; + + private: + static const int kInitialSize = 0; + + Element* elements_; + int current_size_; + int total_size_; + + // Move the contents of |from| into |to|, possibly clobbering |from| in the + // process. For primitive types this is just a memcpy(), but it could be + // specialized for non-primitive types to, say, swap each element instead. + void MoveArray(Element to[], Element from[], int size); + + // Copy the elements of |from| into |to|. + void CopyArray(Element to[], const Element from[], int size); +}; + +namespace internal { +template class RepeatedPtrIterator; +template class RepeatedPtrOverPtrsIterator; +} // namespace internal + +namespace internal { + +// This is a helper template to copy an array of elements effeciently when they +// have a trivial copy constructor, and correctly otherwise. This really +// shouldn't be necessary, but our compiler doesn't optimize std::copy very +// effectively. +template ::value> +struct ElementCopier { + void operator()(Element to[], const Element from[], int array_size); +}; + +} // namespace internal + +namespace internal { + +// This is the common base class for RepeatedPtrFields. It deals only in void* +// pointers. Users should not use this interface directly. +// +// The methods of this interface correspond to the methods of RepeatedPtrField, +// but may have a template argument called TypeHandler. Its signature is: +// class TypeHandler { +// public: +// typedef MyType Type; +// static Type* New(); +// static void Delete(Type*); +// static void Clear(Type*); +// static void Merge(const Type& from, Type* to); +// +// // Only needs to be implemented if SpaceUsedExcludingSelf() is called. +// static int SpaceUsed(const Type&); +// }; +class LIBPROTOBUF_EXPORT RepeatedPtrFieldBase { + protected: + // The reflection implementation needs to call protected methods directly, + // reinterpreting pointers as being to Message instead of a specific Message + // subclass. + friend class GeneratedMessageReflection; + + // ExtensionSet stores repeated message extensions as + // RepeatedPtrField, but non-lite ExtensionSets need to + // implement SpaceUsed(), and thus need to call SpaceUsedExcludingSelf() + // reinterpreting MessageLite as Message. ExtensionSet also needs to make + // use of AddFromCleared(), which is not part of the public interface. + friend class ExtensionSet; + + // To parse directly into a proto2 generated class, the upb class GMR_Handlers + // needs to be able to modify a RepeatedPtrFieldBase directly. + friend class LIBPROTOBUF_EXPORT upb::google_opensource::GMR_Handlers; + + RepeatedPtrFieldBase(); + + // Must be called from destructor. + template + void Destroy(); + + int size() const; + + template + const typename TypeHandler::Type& Get(int index) const; + template + typename TypeHandler::Type* Mutable(int index); + template + typename TypeHandler::Type* Add(); + template + void RemoveLast(); + template + void Clear(); + template + void MergeFrom(const RepeatedPtrFieldBase& other); + template + void CopyFrom(const RepeatedPtrFieldBase& other); + + void CloseGap(int start, int num) { + // Close up a gap of "num" elements starting at offset "start". + for (int i = start + num; i < allocated_size_; ++i) + elements_[i - num] = elements_[i]; + current_size_ -= num; + allocated_size_ -= num; + } + + void Reserve(int new_size); + + int Capacity() const; + + // Used for constructing iterators. + void* const* raw_data() const; + void** raw_mutable_data() const; + + template + typename TypeHandler::Type** mutable_data(); + template + const typename TypeHandler::Type* const* data() const; + + void Swap(RepeatedPtrFieldBase* other); + + void SwapElements(int index1, int index2); + + template + int SpaceUsedExcludingSelf() const; + + + // Advanced memory management -------------------------------------- + + // Like Add(), but if there are no cleared objects to use, returns NULL. + template + typename TypeHandler::Type* AddFromCleared(); + + template + void AddAllocated(typename TypeHandler::Type* value); + template + typename TypeHandler::Type* ReleaseLast(); + + int ClearedCount() const; + template + void AddCleared(typename TypeHandler::Type* value); + template + typename TypeHandler::Type* ReleaseCleared(); + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedPtrFieldBase); + + static const int kInitialSize = 0; + + void** elements_; + int current_size_; + int allocated_size_; + int total_size_; + + template + static inline typename TypeHandler::Type* cast(void* element) { + return reinterpret_cast(element); + } + template + static inline const typename TypeHandler::Type* cast(const void* element) { + return reinterpret_cast(element); + } +}; + +template +class GenericTypeHandler { + public: + typedef GenericType Type; + static GenericType* New() { return new GenericType; } + static void Delete(GenericType* value) { delete value; } + static void Clear(GenericType* value) { value->Clear(); } + static void Merge(const GenericType& from, GenericType* to) { + to->MergeFrom(from); + } + static int SpaceUsed(const GenericType& value) { return value.SpaceUsed(); } + static const Type& default_instance() { return Type::default_instance(); } +}; + +template <> +inline void GenericTypeHandler::Merge( + const MessageLite& from, MessageLite* to) { + to->CheckTypeAndMergeFrom(from); +} + +template <> +inline const MessageLite& GenericTypeHandler::default_instance() { + // Yes, the behavior of the code is undefined, but this function is only + // called when we're already deep into the world of undefined, because the + // caller called Get(index) out of bounds. + MessageLite* null = NULL; + return *null; +} + +template <> +inline const Message& GenericTypeHandler::default_instance() { + // Yes, the behavior of the code is undefined, but this function is only + // called when we're already deep into the world of undefined, because the + // caller called Get(index) out of bounds. + Message* null = NULL; + return *null; +} + + +// HACK: If a class is declared as DLL-exported in MSVC, it insists on +// generating copies of all its methods -- even inline ones -- to include +// in the DLL. But SpaceUsed() calls StringSpaceUsedExcludingSelf() which +// isn't in the lite library, therefore the lite library cannot link if +// StringTypeHandler is exported. So, we factor out StringTypeHandlerBase, +// export that, then make StringTypeHandler be a subclass which is NOT +// exported. +// TODO(kenton): There has to be a better way. +class LIBPROTOBUF_EXPORT StringTypeHandlerBase { + public: + typedef string Type; + static string* New(); + static void Delete(string* value); + static void Clear(string* value) { value->clear(); } + static void Merge(const string& from, string* to) { *to = from; } + static const Type& default_instance() { + return ::google::protobuf::internal::kEmptyString; + } +}; + +class StringTypeHandler : public StringTypeHandlerBase { + public: + static int SpaceUsed(const string& value) { + return sizeof(value) + StringSpaceUsedExcludingSelf(value); + } +}; + + +} // namespace internal + +// RepeatedPtrField is like RepeatedField, but used for repeated strings or +// Messages. +template +class RepeatedPtrField : public internal::RepeatedPtrFieldBase { + public: + RepeatedPtrField(); + RepeatedPtrField(const RepeatedPtrField& other); + template + RepeatedPtrField(Iter begin, const Iter& end); + ~RepeatedPtrField(); + + RepeatedPtrField& operator=(const RepeatedPtrField& other); + + int size() const; + + const Element& Get(int index) const; + Element* Mutable(int index); + Element* Add(); + + // Remove the last element in the array. + // Ownership of the element is retained by the array. + void RemoveLast(); + + // Delete elements with indices in the range [start .. start+num-1]. + // Caution: implementation moves all elements with indices [start+num .. ]. + // Calling this routine inside a loop can cause quadratic behavior. + void DeleteSubrange(int start, int num); + + void Clear(); + void MergeFrom(const RepeatedPtrField& other); + void CopyFrom(const RepeatedPtrField& other); + + // Reserve space to expand the field to at least the given size. This only + // resizes the pointer array; it doesn't allocate any objects. If the + // array is grown, it will always be at least doubled in size. + void Reserve(int new_size); + + int Capacity() const; + + // Gets the underlying array. This pointer is possibly invalidated by + // any add or remove operation. + Element** mutable_data(); + const Element* const* data() const; + + // Swap entire contents with "other". + void Swap(RepeatedPtrField* other); + + // Swap two elements. + void SwapElements(int index1, int index2); + + // STL-like iterator support + typedef internal::RepeatedPtrIterator iterator; + typedef internal::RepeatedPtrIterator const_iterator; + typedef Element value_type; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef int size_type; + typedef ptrdiff_t difference_type; + + iterator begin(); + const_iterator begin() const; + iterator end(); + const_iterator end() const; + + // Reverse iterator support + typedef std::reverse_iterator const_reverse_iterator; + typedef std::reverse_iterator reverse_iterator; + reverse_iterator rbegin() { + return reverse_iterator(end()); + } + const_reverse_iterator rbegin() const { + return const_reverse_iterator(end()); + } + reverse_iterator rend() { + return reverse_iterator(begin()); + } + const_reverse_iterator rend() const { + return const_reverse_iterator(begin()); + } + + // Custom STL-like iterator that iterates over and returns the underlying + // pointers to Element rather than Element itself. + typedef internal::RepeatedPtrOverPtrsIterator + pointer_iterator; + typedef internal::RepeatedPtrOverPtrsIterator + const_pointer_iterator; + pointer_iterator pointer_begin(); + const_pointer_iterator pointer_begin() const; + pointer_iterator pointer_end(); + const_pointer_iterator pointer_end() const; + + // Returns (an estimate of) the number of bytes used by the repeated field, + // excluding sizeof(*this). + int SpaceUsedExcludingSelf() const; + + // Advanced memory management -------------------------------------- + // When hardcore memory management becomes necessary -- as it sometimes + // does here at Google -- the following methods may be useful. + + // Add an already-allocated object, passing ownership to the + // RepeatedPtrField. + void AddAllocated(Element* value); + // Remove the last element and return it, passing ownership to the caller. + // Requires: size() > 0 + Element* ReleaseLast(); + + // Extract elements with indices in the range "[start .. start+num-1]". + // The caller assumes ownership of the extracted elements and is responsible + // for deleting them when they are no longer needed. + // If "elements" is non-NULL, then pointers to the extracted elements + // are stored in "elements[0 .. num-1]" for the convenience of the caller. + // If "elements" is NULL, then the caller must use some other mechanism + // to perform any further operations (like deletion) on these elements. + // Caution: implementation also moves elements with indices [start+num ..]. + // Calling this routine inside a loop can cause quadratic behavior. + void ExtractSubrange(int start, int num, Element** elements); + + // When elements are removed by calls to RemoveLast() or Clear(), they + // are not actually freed. Instead, they are cleared and kept so that + // they can be reused later. This can save lots of CPU time when + // repeatedly reusing a protocol message for similar purposes. + // + // Hardcore programs may choose to manipulate these cleared objects + // to better optimize memory management using the following routines. + + // Get the number of cleared objects that are currently being kept + // around for reuse. + int ClearedCount() const; + // Add an element to the pool of cleared objects, passing ownership to + // the RepeatedPtrField. The element must be cleared prior to calling + // this method. + void AddCleared(Element* value); + // Remove a single element from the cleared pool and return it, passing + // ownership to the caller. The element is guaranteed to be cleared. + // Requires: ClearedCount() > 0 + Element* ReleaseCleared(); + + protected: + // Note: RepeatedPtrField SHOULD NOT be subclassed by users. We only + // subclass it in one place as a hack for compatibility with proto1. The + // subclass needs to know about TypeHandler in order to call protected + // methods on RepeatedPtrFieldBase. + class TypeHandler; + +}; + +// implementation ==================================================== + +template +inline RepeatedField::RepeatedField() + : elements_(NULL), + current_size_(0), + total_size_(kInitialSize) { +} + +template +inline RepeatedField::RepeatedField(const RepeatedField& other) + : elements_(NULL), + current_size_(0), + total_size_(kInitialSize) { + CopyFrom(other); +} + +template +template +inline RepeatedField::RepeatedField(Iter _begin, const Iter& _end) + : elements_(NULL), + current_size_(0), + total_size_(kInitialSize) { + for (; _begin != _end; ++_begin) { + Add(*_begin); + } +} + +template +RepeatedField::~RepeatedField() { + delete [] elements_; +} + +template +inline RepeatedField& +RepeatedField::operator=(const RepeatedField& other) { + if (this != &other) + CopyFrom(other); + return *this; +} + +template +inline int RepeatedField::size() const { + return current_size_; +} + +template +inline int RepeatedField::Capacity() const { + return total_size_; +} + +template +inline void RepeatedField::AddAlreadyReserved(const Element& value) { + GOOGLE_DCHECK_LT(size(), Capacity()); + elements_[current_size_++] = value; +} + +template +inline Element* RepeatedField::AddAlreadyReserved() { + GOOGLE_DCHECK_LT(size(), Capacity()); + return &elements_[current_size_++]; +} + +template +inline const Element& RepeatedField::Get(int index) const { + GOOGLE_DCHECK_LT(index, size()); + return elements_[index]; +} + +template +inline Element* RepeatedField::Mutable(int index) { + GOOGLE_DCHECK_LT(index, size()); + return elements_ + index; +} + +template +inline void RepeatedField::Set(int index, const Element& value) { + GOOGLE_DCHECK_LT(index, size()); + elements_[index] = value; +} + +template +inline void RepeatedField::Add(const Element& value) { + if (current_size_ == total_size_) Reserve(total_size_ + 1); + elements_[current_size_++] = value; +} + +template +inline Element* RepeatedField::Add() { + if (current_size_ == total_size_) Reserve(total_size_ + 1); + return &elements_[current_size_++]; +} + +template +inline void RepeatedField::RemoveLast() { + GOOGLE_DCHECK_GT(current_size_, 0); + --current_size_; +} + +template +void RepeatedField::ExtractSubrange( + int start, int num, Element* elements) { + GOOGLE_DCHECK_GE(start, 0); + GOOGLE_DCHECK_GE(num, 0); + GOOGLE_DCHECK_LE(start + num, this->size()); + + // Save the values of the removed elements if requested. + if (elements != NULL) { + for (int i = 0; i < num; ++i) + elements[i] = this->Get(i + start); + } + + // Slide remaining elements down to fill the gap. + if (num > 0) { + for (int i = start + num; i < this->size(); ++i) + this->Set(i - num, this->Get(i)); + this->Truncate(this->size() - num); + } +} + +template +inline void RepeatedField::Clear() { + current_size_ = 0; +} + +template +inline void RepeatedField::MergeFrom(const RepeatedField& other) { + if (other.current_size_ != 0) { + Reserve(current_size_ + other.current_size_); + CopyArray(elements_ + current_size_, other.elements_, other.current_size_); + current_size_ += other.current_size_; + } +} + +template +inline void RepeatedField::CopyFrom(const RepeatedField& other) { + Clear(); + MergeFrom(other); +} + +template +inline Element* RepeatedField::mutable_data() { + return elements_; +} + +template +inline const Element* RepeatedField::data() const { + return elements_; +} + + +template +void RepeatedField::Swap(RepeatedField* other) { + if (this == other) return; + Element* swap_elements = elements_; + int swap_current_size = current_size_; + int swap_total_size = total_size_; + + elements_ = other->elements_; + current_size_ = other->current_size_; + total_size_ = other->total_size_; + + other->elements_ = swap_elements; + other->current_size_ = swap_current_size; + other->total_size_ = swap_total_size; +} + +template +void RepeatedField::SwapElements(int index1, int index2) { + std::swap(elements_[index1], elements_[index2]); +} + +template +inline typename RepeatedField::iterator +RepeatedField::begin() { + return elements_; +} +template +inline typename RepeatedField::const_iterator +RepeatedField::begin() const { + return elements_; +} +template +inline typename RepeatedField::iterator +RepeatedField::end() { + return elements_ + current_size_; +} +template +inline typename RepeatedField::const_iterator +RepeatedField::end() const { + return elements_ + current_size_; +} + +template +inline int RepeatedField::SpaceUsedExcludingSelf() const { + return (elements_ != NULL) ? total_size_ * sizeof(elements_[0]) : 0; +} + +// Avoid inlining of Reserve(): new, copy, and delete[] lead to a significant +// amount of code bloat. +template +void RepeatedField::Reserve(int new_size) { + if (total_size_ >= new_size) return; + + Element* old_elements = elements_; + total_size_ = max(google::protobuf::internal::kMinRepeatedFieldAllocationSize, + max(total_size_ * 2, new_size)); + elements_ = new Element[total_size_]; + if (old_elements != NULL) { + MoveArray(elements_, old_elements, current_size_); + delete [] old_elements; + } +} + +template +inline void RepeatedField::Truncate(int new_size) { + GOOGLE_DCHECK_LE(new_size, current_size_); + current_size_ = new_size; +} + +template +inline void RepeatedField::MoveArray( + Element to[], Element from[], int array_size) { + CopyArray(to, from, array_size); +} + +template +inline void RepeatedField::CopyArray( + Element to[], const Element from[], int array_size) { + internal::ElementCopier()(to, from, array_size); +} + +namespace internal { + +template +void ElementCopier::operator()( + Element to[], const Element from[], int array_size) { + std::copy(from, from + array_size, to); +} + +template +struct ElementCopier { + void operator()(Element to[], const Element from[], int array_size) { + memcpy(to, from, array_size * sizeof(Element)); + } +}; + +} // namespace internal + + +// ------------------------------------------------------------------- + +namespace internal { + +inline RepeatedPtrFieldBase::RepeatedPtrFieldBase() + : elements_(NULL), + current_size_(0), + allocated_size_(0), + total_size_(kInitialSize) { +} + +template +void RepeatedPtrFieldBase::Destroy() { + for (int i = 0; i < allocated_size_; i++) { + TypeHandler::Delete(cast(elements_[i])); + } + delete [] elements_; +} + +inline int RepeatedPtrFieldBase::size() const { + return current_size_; +} + +template +inline const typename TypeHandler::Type& +RepeatedPtrFieldBase::Get(int index) const { + GOOGLE_DCHECK_LT(index, size()); + return *cast(elements_[index]); +} + + +template +inline typename TypeHandler::Type* +RepeatedPtrFieldBase::Mutable(int index) { + GOOGLE_DCHECK_LT(index, size()); + return cast(elements_[index]); +} + +template +inline typename TypeHandler::Type* RepeatedPtrFieldBase::Add() { + if (current_size_ < allocated_size_) { + return cast(elements_[current_size_++]); + } + if (allocated_size_ == total_size_) Reserve(total_size_ + 1); + ++allocated_size_; + typename TypeHandler::Type* result = TypeHandler::New(); + elements_[current_size_++] = result; + return result; +} + +template +inline void RepeatedPtrFieldBase::RemoveLast() { + GOOGLE_DCHECK_GT(current_size_, 0); + TypeHandler::Clear(cast(elements_[--current_size_])); +} + +template +void RepeatedPtrFieldBase::Clear() { + for (int i = 0; i < current_size_; i++) { + TypeHandler::Clear(cast(elements_[i])); + } + current_size_ = 0; +} + +template +inline void RepeatedPtrFieldBase::MergeFrom(const RepeatedPtrFieldBase& other) { + Reserve(current_size_ + other.current_size_); + for (int i = 0; i < other.current_size_; i++) { + TypeHandler::Merge(other.template Get(i), Add()); + } +} + +template +inline void RepeatedPtrFieldBase::CopyFrom(const RepeatedPtrFieldBase& other) { + RepeatedPtrFieldBase::Clear(); + RepeatedPtrFieldBase::MergeFrom(other); +} + +inline int RepeatedPtrFieldBase::Capacity() const { + return total_size_; +} + +inline void* const* RepeatedPtrFieldBase::raw_data() const { + return elements_; +} + +inline void** RepeatedPtrFieldBase::raw_mutable_data() const { + return elements_; +} + +template +inline typename TypeHandler::Type** RepeatedPtrFieldBase::mutable_data() { + // TODO(kenton): Breaks C++ aliasing rules. We should probably remove this + // method entirely. + return reinterpret_cast(elements_); +} + +template +inline const typename TypeHandler::Type* const* +RepeatedPtrFieldBase::data() const { + // TODO(kenton): Breaks C++ aliasing rules. We should probably remove this + // method entirely. + return reinterpret_cast(elements_); +} + +inline void RepeatedPtrFieldBase::SwapElements(int index1, int index2) { + std::swap(elements_[index1], elements_[index2]); +} + +template +inline int RepeatedPtrFieldBase::SpaceUsedExcludingSelf() const { + int allocated_bytes = + (elements_ != NULL) ? total_size_ * sizeof(elements_[0]) : 0; + for (int i = 0; i < allocated_size_; ++i) { + allocated_bytes += TypeHandler::SpaceUsed(*cast(elements_[i])); + } + return allocated_bytes; +} + +template +inline typename TypeHandler::Type* RepeatedPtrFieldBase::AddFromCleared() { + if (current_size_ < allocated_size_) { + return cast(elements_[current_size_++]); + } else { + return NULL; + } +} + +template +void RepeatedPtrFieldBase::AddAllocated( + typename TypeHandler::Type* value) { + // Make room for the new pointer. + if (current_size_ == total_size_) { + // The array is completely full with no cleared objects, so grow it. + Reserve(total_size_ + 1); + ++allocated_size_; + } else if (allocated_size_ == total_size_) { + // There is no more space in the pointer array because it contains some + // cleared objects awaiting reuse. We don't want to grow the array in this + // case because otherwise a loop calling AddAllocated() followed by Clear() + // would leak memory. + TypeHandler::Delete(cast(elements_[current_size_])); + } else if (current_size_ < allocated_size_) { + // We have some cleared objects. We don't care about their order, so we + // can just move the first one to the end to make space. + elements_[allocated_size_] = elements_[current_size_]; + ++allocated_size_; + } else { + // There are no cleared objects. + ++allocated_size_; + } + + elements_[current_size_++] = value; +} + +template +inline typename TypeHandler::Type* RepeatedPtrFieldBase::ReleaseLast() { + GOOGLE_DCHECK_GT(current_size_, 0); + typename TypeHandler::Type* result = + cast(elements_[--current_size_]); + --allocated_size_; + if (current_size_ < allocated_size_) { + // There are cleared elements on the end; replace the removed element + // with the last allocated element. + elements_[current_size_] = elements_[allocated_size_]; + } + return result; +} + +inline int RepeatedPtrFieldBase::ClearedCount() const { + return allocated_size_ - current_size_; +} + +template +inline void RepeatedPtrFieldBase::AddCleared( + typename TypeHandler::Type* value) { + if (allocated_size_ == total_size_) Reserve(total_size_ + 1); + elements_[allocated_size_++] = value; +} + +template +inline typename TypeHandler::Type* RepeatedPtrFieldBase::ReleaseCleared() { + GOOGLE_DCHECK_GT(allocated_size_, current_size_); + return cast(elements_[--allocated_size_]); +} + +} // namespace internal + +// ------------------------------------------------------------------- + +template +class RepeatedPtrField::TypeHandler + : public internal::GenericTypeHandler { +}; + +template <> +class RepeatedPtrField::TypeHandler + : public internal::StringTypeHandler { +}; + + +template +inline RepeatedPtrField::RepeatedPtrField() {} + +template +inline RepeatedPtrField::RepeatedPtrField( + const RepeatedPtrField& other) { + CopyFrom(other); +} + +template +template +inline RepeatedPtrField::RepeatedPtrField( + Iter _begin, const Iter& _end) { + for (; _begin != _end; ++_begin) { + *Add() = *_begin; + } +} + +template +RepeatedPtrField::~RepeatedPtrField() { + Destroy(); +} + +template +inline RepeatedPtrField& RepeatedPtrField::operator=( + const RepeatedPtrField& other) { + if (this != &other) + CopyFrom(other); + return *this; +} + +template +inline int RepeatedPtrField::size() const { + return RepeatedPtrFieldBase::size(); +} + +template +inline const Element& RepeatedPtrField::Get(int index) const { + return RepeatedPtrFieldBase::Get(index); +} + + +template +inline Element* RepeatedPtrField::Mutable(int index) { + return RepeatedPtrFieldBase::Mutable(index); +} + +template +inline Element* RepeatedPtrField::Add() { + return RepeatedPtrFieldBase::Add(); +} + +template +inline void RepeatedPtrField::RemoveLast() { + RepeatedPtrFieldBase::RemoveLast(); +} + +template +inline void RepeatedPtrField::DeleteSubrange(int start, int num) { + GOOGLE_DCHECK_GE(start, 0); + GOOGLE_DCHECK_GE(num, 0); + GOOGLE_DCHECK_LE(start + num, size()); + for (int i = 0; i < num; ++i) + delete RepeatedPtrFieldBase::Mutable(start + i); + ExtractSubrange(start, num, NULL); +} + +template +inline void RepeatedPtrField::ExtractSubrange( + int start, int num, Element** elements) { + GOOGLE_DCHECK_GE(start, 0); + GOOGLE_DCHECK_GE(num, 0); + GOOGLE_DCHECK_LE(start + num, size()); + + if (num > 0) { + // Save the values of the removed elements if requested. + if (elements != NULL) { + for (int i = 0; i < num; ++i) + elements[i] = RepeatedPtrFieldBase::Mutable(i + start); + } + CloseGap(start, num); + } +} + +template +inline void RepeatedPtrField::Clear() { + RepeatedPtrFieldBase::Clear(); +} + +template +inline void RepeatedPtrField::MergeFrom( + const RepeatedPtrField& other) { + RepeatedPtrFieldBase::MergeFrom(other); +} + +template +inline void RepeatedPtrField::CopyFrom( + const RepeatedPtrField& other) { + RepeatedPtrFieldBase::CopyFrom(other); +} + +template +inline Element** RepeatedPtrField::mutable_data() { + return RepeatedPtrFieldBase::mutable_data(); +} + +template +inline const Element* const* RepeatedPtrField::data() const { + return RepeatedPtrFieldBase::data(); +} + +template +void RepeatedPtrField::Swap(RepeatedPtrField* other) { + RepeatedPtrFieldBase::Swap(other); +} + +template +void RepeatedPtrField::SwapElements(int index1, int index2) { + RepeatedPtrFieldBase::SwapElements(index1, index2); +} + +template +inline int RepeatedPtrField::SpaceUsedExcludingSelf() const { + return RepeatedPtrFieldBase::SpaceUsedExcludingSelf(); +} + +template +inline void RepeatedPtrField::AddAllocated(Element* value) { + RepeatedPtrFieldBase::AddAllocated(value); +} + +template +inline Element* RepeatedPtrField::ReleaseLast() { + return RepeatedPtrFieldBase::ReleaseLast(); +} + + +template +inline int RepeatedPtrField::ClearedCount() const { + return RepeatedPtrFieldBase::ClearedCount(); +} + +template +inline void RepeatedPtrField::AddCleared(Element* value) { + return RepeatedPtrFieldBase::AddCleared(value); +} + +template +inline Element* RepeatedPtrField::ReleaseCleared() { + return RepeatedPtrFieldBase::ReleaseCleared(); +} + +template +inline void RepeatedPtrField::Reserve(int new_size) { + return RepeatedPtrFieldBase::Reserve(new_size); +} + +template +inline int RepeatedPtrField::Capacity() const { + return RepeatedPtrFieldBase::Capacity(); +} + +// ------------------------------------------------------------------- + +namespace internal { + +// STL-like iterator implementation for RepeatedPtrField. You should not +// refer to this class directly; use RepeatedPtrField::iterator instead. +// +// The iterator for RepeatedPtrField, RepeatedPtrIterator, is +// very similar to iterator_ptr in util/gtl/iterator_adaptors.h, +// but adds random-access operators and is modified to wrap a void** base +// iterator (since RepeatedPtrField stores its array as a void* array and +// casting void** to T** would violate C++ aliasing rules). +// +// This code based on net/proto/proto-array-internal.h by Jeffrey Yasskin +// (jyasskin@google.com). +template +class RepeatedPtrIterator + : public std::iterator< + std::random_access_iterator_tag, Element> { + public: + typedef RepeatedPtrIterator iterator; + typedef std::iterator< + std::random_access_iterator_tag, Element> superclass; + + // Let the compiler know that these are type names, so we don't have to + // write "typename" in front of them everywhere. + typedef typename superclass::reference reference; + typedef typename superclass::pointer pointer; + typedef typename superclass::difference_type difference_type; + + RepeatedPtrIterator() : it_(NULL) {} + explicit RepeatedPtrIterator(void* const* it) : it_(it) {} + + // Allow "upcasting" from RepeatedPtrIterator to + // RepeatedPtrIterator. + template + RepeatedPtrIterator(const RepeatedPtrIterator& other) + : it_(other.it_) { + // Force a compiler error if the other type is not convertible to ours. + if (false) { + implicit_cast(0); + } + } + + // dereferenceable + reference operator*() const { return *reinterpret_cast(*it_); } + pointer operator->() const { return &(operator*()); } + + // {inc,dec}rementable + iterator& operator++() { ++it_; return *this; } + iterator operator++(int) { return iterator(it_++); } + iterator& operator--() { --it_; return *this; } + iterator operator--(int) { return iterator(it_--); } + + // equality_comparable + bool operator==(const iterator& x) const { return it_ == x.it_; } + bool operator!=(const iterator& x) const { return it_ != x.it_; } + + // less_than_comparable + bool operator<(const iterator& x) const { return it_ < x.it_; } + bool operator<=(const iterator& x) const { return it_ <= x.it_; } + bool operator>(const iterator& x) const { return it_ > x.it_; } + bool operator>=(const iterator& x) const { return it_ >= x.it_; } + + // addable, subtractable + iterator& operator+=(difference_type d) { + it_ += d; + return *this; + } + friend iterator operator+(iterator it, difference_type d) { + it += d; + return it; + } + friend iterator operator+(difference_type d, iterator it) { + it += d; + return it; + } + iterator& operator-=(difference_type d) { + it_ -= d; + return *this; + } + friend iterator operator-(iterator it, difference_type d) { + it -= d; + return it; + } + + // indexable + reference operator[](difference_type d) const { return *(*this + d); } + + // random access iterator + difference_type operator-(const iterator& x) const { return it_ - x.it_; } + + private: + template + friend class RepeatedPtrIterator; + + // The internal iterator. + void* const* it_; +}; + +// Provide an iterator that operates on pointers to the underlying objects +// rather than the objects themselves as RepeatedPtrIterator does. +// Consider using this when working with stl algorithms that change +// the array. +// The VoidPtr template parameter holds the type-agnostic pointer value +// referenced by the iterator. It should either be "void *" for a mutable +// iterator, or "const void *" for a constant iterator. +template +class RepeatedPtrOverPtrsIterator + : public std::iterator { + public: + typedef RepeatedPtrOverPtrsIterator iterator; + typedef std::iterator< + std::random_access_iterator_tag, Element*> superclass; + + // Let the compiler know that these are type names, so we don't have to + // write "typename" in front of them everywhere. + typedef typename superclass::reference reference; + typedef typename superclass::pointer pointer; + typedef typename superclass::difference_type difference_type; + + RepeatedPtrOverPtrsIterator() : it_(NULL) {} + explicit RepeatedPtrOverPtrsIterator(VoidPtr* it) : it_(it) {} + + // dereferenceable + reference operator*() const { return *reinterpret_cast(it_); } + pointer operator->() const { return &(operator*()); } + + // {inc,dec}rementable + iterator& operator++() { ++it_; return *this; } + iterator operator++(int) { return iterator(it_++); } + iterator& operator--() { --it_; return *this; } + iterator operator--(int) { return iterator(it_--); } + + // equality_comparable + bool operator==(const iterator& x) const { return it_ == x.it_; } + bool operator!=(const iterator& x) const { return it_ != x.it_; } + + // less_than_comparable + bool operator<(const iterator& x) const { return it_ < x.it_; } + bool operator<=(const iterator& x) const { return it_ <= x.it_; } + bool operator>(const iterator& x) const { return it_ > x.it_; } + bool operator>=(const iterator& x) const { return it_ >= x.it_; } + + // addable, subtractable + iterator& operator+=(difference_type d) { + it_ += d; + return *this; + } + friend iterator operator+(iterator it, difference_type d) { + it += d; + return it; + } + friend iterator operator+(difference_type d, iterator it) { + it += d; + return it; + } + iterator& operator-=(difference_type d) { + it_ -= d; + return *this; + } + friend iterator operator-(iterator it, difference_type d) { + it -= d; + return it; + } + + // indexable + reference operator[](difference_type d) const { return *(*this + d); } + + // random access iterator + difference_type operator-(const iterator& x) const { return it_ - x.it_; } + + private: + template + friend class RepeatedPtrIterator; + + // The internal iterator. + VoidPtr* it_; +}; + +} // namespace internal + +template +inline typename RepeatedPtrField::iterator +RepeatedPtrField::begin() { + return iterator(raw_data()); +} +template +inline typename RepeatedPtrField::const_iterator +RepeatedPtrField::begin() const { + return iterator(raw_data()); +} +template +inline typename RepeatedPtrField::iterator +RepeatedPtrField::end() { + return iterator(raw_data() + size()); +} +template +inline typename RepeatedPtrField::const_iterator +RepeatedPtrField::end() const { + return iterator(raw_data() + size()); +} + +template +inline typename RepeatedPtrField::pointer_iterator +RepeatedPtrField::pointer_begin() { + return pointer_iterator(raw_mutable_data()); +} +template +inline typename RepeatedPtrField::const_pointer_iterator +RepeatedPtrField::pointer_begin() const { + return const_pointer_iterator(const_cast(raw_mutable_data())); +} +template +inline typename RepeatedPtrField::pointer_iterator +RepeatedPtrField::pointer_end() { + return pointer_iterator(raw_mutable_data() + size()); +} +template +inline typename RepeatedPtrField::const_pointer_iterator +RepeatedPtrField::pointer_end() const { + return const_pointer_iterator( + const_cast(raw_mutable_data() + size())); +} + + +// Iterators and helper functions that follow the spirit of the STL +// std::back_insert_iterator and std::back_inserter but are tailor-made +// for RepeatedField and RepatedPtrField. Typical usage would be: +// +// std::copy(some_sequence.begin(), some_sequence.end(), +// google::protobuf::RepeatedFieldBackInserter(proto.mutable_sequence())); +// +// Ported by johannes from util/gtl/proto-array-iterators.h + +namespace internal { +// A back inserter for RepeatedField objects. +template class RepeatedFieldBackInsertIterator + : public std::iterator { + public: + explicit RepeatedFieldBackInsertIterator( + RepeatedField* const mutable_field) + : field_(mutable_field) { + } + RepeatedFieldBackInsertIterator& operator=(const T& value) { + field_->Add(value); + return *this; + } + RepeatedFieldBackInsertIterator& operator*() { + return *this; + } + RepeatedFieldBackInsertIterator& operator++() { + return *this; + } + RepeatedFieldBackInsertIterator& operator++(int /* unused */) { + return *this; + } + + private: + RepeatedField* field_; +}; + +// A back inserter for RepeatedPtrField objects. +template class RepeatedPtrFieldBackInsertIterator + : public std::iterator { + public: + RepeatedPtrFieldBackInsertIterator( + RepeatedPtrField* const mutable_field) + : field_(mutable_field) { + } + RepeatedPtrFieldBackInsertIterator& operator=(const T& value) { + *field_->Add() = value; + return *this; + } + RepeatedPtrFieldBackInsertIterator& operator=( + const T* const ptr_to_value) { + *field_->Add() = *ptr_to_value; + return *this; + } + RepeatedPtrFieldBackInsertIterator& operator*() { + return *this; + } + RepeatedPtrFieldBackInsertIterator& operator++() { + return *this; + } + RepeatedPtrFieldBackInsertIterator& operator++(int /* unused */) { + return *this; + } + + private: + RepeatedPtrField* field_; +}; + +// A back inserter for RepeatedPtrFields that inserts by transfering ownership +// of a pointer. +template class AllocatedRepeatedPtrFieldBackInsertIterator + : public std::iterator { + public: + explicit AllocatedRepeatedPtrFieldBackInsertIterator( + RepeatedPtrField* const mutable_field) + : field_(mutable_field) { + } + AllocatedRepeatedPtrFieldBackInsertIterator& operator=( + T* const ptr_to_value) { + field_->AddAllocated(ptr_to_value); + return *this; + } + AllocatedRepeatedPtrFieldBackInsertIterator& operator*() { + return *this; + } + AllocatedRepeatedPtrFieldBackInsertIterator& operator++() { + return *this; + } + AllocatedRepeatedPtrFieldBackInsertIterator& operator++( + int /* unused */) { + return *this; + } + + private: + RepeatedPtrField* field_; +}; +} // namespace internal + +// Provides a back insert iterator for RepeatedField instances, +// similar to std::back_inserter(). +template internal::RepeatedFieldBackInsertIterator +RepeatedFieldBackInserter(RepeatedField* const mutable_field) { + return internal::RepeatedFieldBackInsertIterator(mutable_field); +} + +// Provides a back insert iterator for RepeatedPtrField instances, +// similar to std::back_inserter(). +template internal::RepeatedPtrFieldBackInsertIterator +RepeatedPtrFieldBackInserter(RepeatedPtrField* const mutable_field) { + return internal::RepeatedPtrFieldBackInsertIterator(mutable_field); +} + +// Special back insert iterator for RepeatedPtrField instances, just in +// case someone wants to write generic template code that can access both +// RepeatedFields and RepeatedPtrFields using a common name. +template internal::RepeatedPtrFieldBackInsertIterator +RepeatedFieldBackInserter(RepeatedPtrField* const mutable_field) { + return internal::RepeatedPtrFieldBackInsertIterator(mutable_field); +} + +// Provides a back insert iterator for RepeatedPtrField instances +// similar to std::back_inserter() which transfers the ownership while +// copying elements. +template internal::AllocatedRepeatedPtrFieldBackInsertIterator +AllocatedRepeatedPtrFieldBackInserter( + RepeatedPtrField* const mutable_field) { + return internal::AllocatedRepeatedPtrFieldBackInsertIterator( + mutable_field); +} + +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_REPEATED_FIELD_H__ diff --git a/include/google/protobuf/service.h b/include/google/protobuf/service.h new file mode 100644 index 000000000..a6a7d16de --- /dev/null +++ b/include/google/protobuf/service.h @@ -0,0 +1,291 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// DEPRECATED: This module declares the abstract interfaces underlying proto2 +// RPC services. These are intented to be independent of any particular RPC +// implementation, so that proto2 services can be used on top of a variety +// of implementations. Starting with version 2.3.0, RPC implementations should +// not try to build on these, but should instead provide code generator plugins +// which generate code specific to the particular RPC implementation. This way +// the generated code can be more appropriate for the implementation in use +// and can avoid unnecessary layers of indirection. +// +// +// When you use the protocol compiler to compile a service definition, it +// generates two classes: An abstract interface for the service (with +// methods matching the service definition) and a "stub" implementation. +// A stub is just a type-safe wrapper around an RpcChannel which emulates a +// local implementation of the service. +// +// For example, the service definition: +// service MyService { +// rpc Foo(MyRequest) returns(MyResponse); +// } +// will generate abstract interface "MyService" and class "MyService::Stub". +// You could implement a MyService as follows: +// class MyServiceImpl : public MyService { +// public: +// MyServiceImpl() {} +// ~MyServiceImpl() {} +// +// // implements MyService --------------------------------------- +// +// void Foo(google::protobuf::RpcController* controller, +// const MyRequest* request, +// MyResponse* response, +// Closure* done) { +// // ... read request and fill in response ... +// done->Run(); +// } +// }; +// You would then register an instance of MyServiceImpl with your RPC server +// implementation. (How to do that depends on the implementation.) +// +// To call a remote MyServiceImpl, first you need an RpcChannel connected to it. +// How to construct a channel depends, again, on your RPC implementation. +// Here we use a hypothentical "MyRpcChannel" as an example: +// MyRpcChannel channel("rpc:hostname:1234/myservice"); +// MyRpcController controller; +// MyServiceImpl::Stub stub(&channel); +// FooRequest request; +// FooRespnose response; +// +// // ... fill in request ... +// +// stub.Foo(&controller, request, &response, NewCallback(HandleResponse)); +// +// On Thread-Safety: +// +// Different RPC implementations may make different guarantees about what +// threads they may run callbacks on, and what threads the application is +// allowed to use to call the RPC system. Portable software should be ready +// for callbacks to be called on any thread, but should not try to call the +// RPC system from any thread except for the ones on which it received the +// callbacks. Realistically, though, simple software will probably want to +// use a single-threaded RPC system while high-end software will want to +// use multiple threads. RPC implementations should provide multiple +// choices. + +#ifndef GOOGLE_PROTOBUF_SERVICE_H__ +#define GOOGLE_PROTOBUF_SERVICE_H__ + +#include +#include + +namespace google { +namespace protobuf { + +// Defined in this file. +class Service; +class RpcController; +class RpcChannel; + +// Defined in other files. +class Descriptor; // descriptor.h +class ServiceDescriptor; // descriptor.h +class MethodDescriptor; // descriptor.h +class Message; // message.h + +// Abstract base interface for protocol-buffer-based RPC services. Services +// themselves are abstract interfaces (implemented either by servers or as +// stubs), but they subclass this base interface. The methods of this +// interface can be used to call the methods of the Service without knowing +// its exact type at compile time (analogous to Reflection). +class LIBPROTOBUF_EXPORT Service { + public: + inline Service() {} + virtual ~Service(); + + // When constructing a stub, you may pass STUB_OWNS_CHANNEL as the second + // parameter to the constructor to tell it to delete its RpcChannel when + // destroyed. + enum ChannelOwnership { + STUB_OWNS_CHANNEL, + STUB_DOESNT_OWN_CHANNEL + }; + + // Get the ServiceDescriptor describing this service and its methods. + virtual const ServiceDescriptor* GetDescriptor() = 0; + + // Call a method of the service specified by MethodDescriptor. This is + // normally implemented as a simple switch() that calls the standard + // definitions of the service's methods. + // + // Preconditions: + // * method->service() == GetDescriptor() + // * request and response are of the exact same classes as the objects + // returned by GetRequestPrototype(method) and + // GetResponsePrototype(method). + // * After the call has started, the request must not be modified and the + // response must not be accessed at all until "done" is called. + // * "controller" is of the correct type for the RPC implementation being + // used by this Service. For stubs, the "correct type" depends on the + // RpcChannel which the stub is using. Server-side Service + // implementations are expected to accept whatever type of RpcController + // the server-side RPC implementation uses. + // + // Postconditions: + // * "done" will be called when the method is complete. This may be + // before CallMethod() returns or it may be at some point in the future. + // * If the RPC succeeded, "response" contains the response returned by + // the server. + // * If the RPC failed, "response"'s contents are undefined. The + // RpcController can be queried to determine if an error occurred and + // possibly to get more information about the error. + virtual void CallMethod(const MethodDescriptor* method, + RpcController* controller, + const Message* request, + Message* response, + Closure* done) = 0; + + // CallMethod() requires that the request and response passed in are of a + // particular subclass of Message. GetRequestPrototype() and + // GetResponsePrototype() get the default instances of these required types. + // You can then call Message::New() on these instances to construct mutable + // objects which you can then pass to CallMethod(). + // + // Example: + // const MethodDescriptor* method = + // service->GetDescriptor()->FindMethodByName("Foo"); + // Message* request = stub->GetRequestPrototype (method)->New(); + // Message* response = stub->GetResponsePrototype(method)->New(); + // request->ParseFromString(input); + // service->CallMethod(method, *request, response, callback); + virtual const Message& GetRequestPrototype( + const MethodDescriptor* method) const = 0; + virtual const Message& GetResponsePrototype( + const MethodDescriptor* method) const = 0; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Service); +}; + +// An RpcController mediates a single method call. The primary purpose of +// the controller is to provide a way to manipulate settings specific to the +// RPC implementation and to find out about RPC-level errors. +// +// The methods provided by the RpcController interface are intended to be a +// "least common denominator" set of features which we expect all +// implementations to support. Specific implementations may provide more +// advanced features (e.g. deadline propagation). +class LIBPROTOBUF_EXPORT RpcController { + public: + inline RpcController() {} + virtual ~RpcController(); + + // Client-side methods --------------------------------------------- + // These calls may be made from the client side only. Their results + // are undefined on the server side (may crash). + + // Resets the RpcController to its initial state so that it may be reused in + // a new call. Must not be called while an RPC is in progress. + virtual void Reset() = 0; + + // After a call has finished, returns true if the call failed. The possible + // reasons for failure depend on the RPC implementation. Failed() must not + // be called before a call has finished. If Failed() returns true, the + // contents of the response message are undefined. + virtual bool Failed() const = 0; + + // If Failed() is true, returns a human-readable description of the error. + virtual string ErrorText() const = 0; + + // Advises the RPC system that the caller desires that the RPC call be + // canceled. The RPC system may cancel it immediately, may wait awhile and + // then cancel it, or may not even cancel the call at all. If the call is + // canceled, the "done" callback will still be called and the RpcController + // will indicate that the call failed at that time. + virtual void StartCancel() = 0; + + // Server-side methods --------------------------------------------- + // These calls may be made from the server side only. Their results + // are undefined on the client side (may crash). + + // Causes Failed() to return true on the client side. "reason" will be + // incorporated into the message returned by ErrorText(). If you find + // you need to return machine-readable information about failures, you + // should incorporate it into your response protocol buffer and should + // NOT call SetFailed(). + virtual void SetFailed(const string& reason) = 0; + + // If true, indicates that the client canceled the RPC, so the server may + // as well give up on replying to it. The server should still call the + // final "done" callback. + virtual bool IsCanceled() const = 0; + + // Asks that the given callback be called when the RPC is canceled. The + // callback will always be called exactly once. If the RPC completes without + // being canceled, the callback will be called after completion. If the RPC + // has already been canceled when NotifyOnCancel() is called, the callback + // will be called immediately. + // + // NotifyOnCancel() must be called no more than once per request. + virtual void NotifyOnCancel(Closure* callback) = 0; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RpcController); +}; + +// Abstract interface for an RPC channel. An RpcChannel represents a +// communication line to a Service which can be used to call that Service's +// methods. The Service may be running on another machine. Normally, you +// should not call an RpcChannel directly, but instead construct a stub Service +// wrapping it. Example: +// RpcChannel* channel = new MyRpcChannel("remotehost.example.com:1234"); +// MyService* service = new MyService::Stub(channel); +// service->MyMethod(request, &response, callback); +class LIBPROTOBUF_EXPORT RpcChannel { + public: + inline RpcChannel() {} + virtual ~RpcChannel(); + + // Call the given method of the remote service. The signature of this + // procedure looks the same as Service::CallMethod(), but the requirements + // are less strict in one important way: the request and response objects + // need not be of any specific class as long as their descriptors are + // method->input_type() and method->output_type(). + virtual void CallMethod(const MethodDescriptor* method, + RpcController* controller, + const Message* request, + Message* response, + Closure* done) = 0; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RpcChannel); +}; + +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_SERVICE_H__ diff --git a/include/google/protobuf/stubs/atomicops.h b/include/google/protobuf/stubs/atomicops.h new file mode 100644 index 000000000..b8581fa27 --- /dev/null +++ b/include/google/protobuf/stubs/atomicops.h @@ -0,0 +1,206 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2012 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// The routines exported by this module are subtle. If you use them, even if +// you get the code right, it will depend on careful reasoning about atomicity +// and memory ordering; it will be less readable, and harder to maintain. If +// you plan to use these routines, you should have a good reason, such as solid +// evidence that performance would otherwise suffer, or there being no +// alternative. You should assume only properties explicitly guaranteed by the +// specifications in this file. You are almost certainly _not_ writing code +// just for the x86; if you assume x86 semantics, x86 hardware bugs and +// implementations on other archtectures will cause your code to break. If you +// do not know what you are doing, avoid these routines, and use a Mutex. +// +// It is incorrect to make direct assignments to/from an atomic variable. +// You should use one of the Load or Store routines. The NoBarrier +// versions are provided when no barriers are needed: +// NoBarrier_Store() +// NoBarrier_Load() +// Although there are currently no compiler enforcement, you are encouraged +// to use these. + +// This header and the implementations for each platform (located in +// atomicops_internals_*) must be kept in sync with the upstream code (V8). + +#ifndef GOOGLE_PROTOBUF_ATOMICOPS_H_ +#define GOOGLE_PROTOBUF_ATOMICOPS_H_ + +// Don't include this file for people not concerned about thread safety. +#ifndef GOOGLE_PROTOBUF_NO_THREAD_SAFETY + +#include + +namespace google { +namespace protobuf { +namespace internal { + +typedef int32 Atomic32; +#ifdef GOOGLE_PROTOBUF_ARCH_64_BIT +// We need to be able to go between Atomic64 and AtomicWord implicitly. This +// means Atomic64 and AtomicWord should be the same type on 64-bit. +#if defined(GOOGLE_PROTOBUF_OS_NACL) +// NaCl's intptr_t is not actually 64-bits on 64-bit! +// http://code.google.com/p/nativeclient/issues/detail?id=1162 +typedef int64 Atomic64; +#else +typedef intptr_t Atomic64; +#endif +#endif + +// Use AtomicWord for a machine-sized pointer. It will use the Atomic32 or +// Atomic64 routines below, depending on your architecture. +typedef intptr_t AtomicWord; + +// Atomically execute: +// result = *ptr; +// if (*ptr == old_value) +// *ptr = new_value; +// return result; +// +// I.e., replace "*ptr" with "new_value" if "*ptr" used to be "old_value". +// Always return the old value of "*ptr" +// +// This routine implies no memory barriers. +Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr, + Atomic32 old_value, + Atomic32 new_value); + +// Atomically store new_value into *ptr, returning the previous value held in +// *ptr. This routine implies no memory barriers. +Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr, Atomic32 new_value); + +// Atomically increment *ptr by "increment". Returns the new value of +// *ptr with the increment applied. This routine implies no memory barriers. +Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr, Atomic32 increment); + +Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr, + Atomic32 increment); + +// These following lower-level operations are typically useful only to people +// implementing higher-level synchronization operations like spinlocks, +// mutexes, and condition-variables. They combine CompareAndSwap(), a load, or +// a store with appropriate memory-ordering instructions. "Acquire" operations +// ensure that no later memory access can be reordered ahead of the operation. +// "Release" operations ensure that no previous memory access can be reordered +// after the operation. "Barrier" operations have both "Acquire" and "Release" +// semantics. A MemoryBarrier() has "Barrier" semantics, but does no memory +// access. +Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr, + Atomic32 old_value, + Atomic32 new_value); +Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr, + Atomic32 old_value, + Atomic32 new_value); + +void MemoryBarrier(); +void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value); +void Acquire_Store(volatile Atomic32* ptr, Atomic32 value); +void Release_Store(volatile Atomic32* ptr, Atomic32 value); + +Atomic32 NoBarrier_Load(volatile const Atomic32* ptr); +Atomic32 Acquire_Load(volatile const Atomic32* ptr); +Atomic32 Release_Load(volatile const Atomic32* ptr); + +// 64-bit atomic operations (only available on 64-bit processors). +#ifdef GOOGLE_PROTOBUF_ARCH_64_BIT +Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr, + Atomic64 old_value, + Atomic64 new_value); +Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr, Atomic64 new_value); +Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr, Atomic64 increment); +Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr, Atomic64 increment); + +Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr, + Atomic64 old_value, + Atomic64 new_value); +Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr, + Atomic64 old_value, + Atomic64 new_value); +void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value); +void Acquire_Store(volatile Atomic64* ptr, Atomic64 value); +void Release_Store(volatile Atomic64* ptr, Atomic64 value); +Atomic64 NoBarrier_Load(volatile const Atomic64* ptr); +Atomic64 Acquire_Load(volatile const Atomic64* ptr); +Atomic64 Release_Load(volatile const Atomic64* ptr); +#endif // GOOGLE_PROTOBUF_ARCH_64_BIT + +} // namespace internal +} // namespace protobuf +} // namespace google + +// Include our platform specific implementation. +#define GOOGLE_PROTOBUF_ATOMICOPS_ERROR \ +#error "Atomic operations are not supported on your platform" + +// MSVC. +#if defined(_MSC_VER) +#if defined(GOOGLE_PROTOBUF_ARCH_IA32) || defined(GOOGLE_PROTOBUF_ARCH_X64) +#include +#else +GOOGLE_PROTOBUF_ATOMICOPS_ERROR +#endif + +// Apple. +#elif defined(GOOGLE_PROTOBUF_OS_APPLE) +#include + +// GCC. +#elif defined(__GNUC__) +#if defined(GOOGLE_PROTOBUF_ARCH_IA32) || defined(GOOGLE_PROTOBUF_ARCH_X64) +#include +#elif defined(GOOGLE_PROTOBUF_ARCH_ARM) +#include +#elif defined(GOOGLE_PROTOBUF_ARCH_ARM_QNX) +#include +#elif defined(GOOGLE_PROTOBUF_ARCH_MIPS) +#include +#elif defined(__pnacl__) +#include +#else +GOOGLE_PROTOBUF_ATOMICOPS_ERROR +#endif + +// Unknown. +#else +GOOGLE_PROTOBUF_ATOMICOPS_ERROR +#endif + +// On some platforms we need additional declarations to make AtomicWord +// compatible with our other Atomic* types. +#if defined(GOOGLE_PROTOBUF_OS_APPLE) +#include +#endif + +#undef GOOGLE_PROTOBUF_ATOMICOPS_ERROR + +#endif // GOOGLE_PROTOBUF_NO_THREAD_SAFETY + +#endif // GOOGLE_PROTOBUF_ATOMICOPS_H_ diff --git a/include/google/protobuf/stubs/atomicops_internals_arm_gcc.h b/include/google/protobuf/stubs/atomicops_internals_arm_gcc.h new file mode 100644 index 000000000..1f4dedc0f --- /dev/null +++ b/include/google/protobuf/stubs/atomicops_internals_arm_gcc.h @@ -0,0 +1,151 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2012 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// This file is an internal atomic implementation, use atomicops.h instead. +// +// LinuxKernelCmpxchg and Barrier_AtomicIncrement are from Google Gears. + +#ifndef GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_ARM_GCC_H_ +#define GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_ARM_GCC_H_ + +namespace google { +namespace protobuf { +namespace internal { + +// 0xffff0fc0 is the hard coded address of a function provided by +// the kernel which implements an atomic compare-exchange. On older +// ARM architecture revisions (pre-v6) this may be implemented using +// a syscall. This address is stable, and in active use (hard coded) +// by at least glibc-2.7 and the Android C library. +typedef Atomic32 (*LinuxKernelCmpxchgFunc)(Atomic32 old_value, + Atomic32 new_value, + volatile Atomic32* ptr); +LinuxKernelCmpxchgFunc pLinuxKernelCmpxchg __attribute__((weak)) = + (LinuxKernelCmpxchgFunc) 0xffff0fc0; + +typedef void (*LinuxKernelMemoryBarrierFunc)(void); +LinuxKernelMemoryBarrierFunc pLinuxKernelMemoryBarrier __attribute__((weak)) = + (LinuxKernelMemoryBarrierFunc) 0xffff0fa0; + + +inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr, + Atomic32 old_value, + Atomic32 new_value) { + Atomic32 prev_value = *ptr; + do { + if (!pLinuxKernelCmpxchg(old_value, new_value, + const_cast(ptr))) { + return old_value; + } + prev_value = *ptr; + } while (prev_value == old_value); + return prev_value; +} + +inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr, + Atomic32 new_value) { + Atomic32 old_value; + do { + old_value = *ptr; + } while (pLinuxKernelCmpxchg(old_value, new_value, + const_cast(ptr))); + return old_value; +} + +inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr, + Atomic32 increment) { + return Barrier_AtomicIncrement(ptr, increment); +} + +inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr, + Atomic32 increment) { + for (;;) { + // Atomic exchange the old value with an incremented one. + Atomic32 old_value = *ptr; + Atomic32 new_value = old_value + increment; + if (pLinuxKernelCmpxchg(old_value, new_value, + const_cast(ptr)) == 0) { + // The exchange took place as expected. + return new_value; + } + // Otherwise, *ptr changed mid-loop and we need to retry. + } +} + +inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr, + Atomic32 old_value, + Atomic32 new_value) { + return NoBarrier_CompareAndSwap(ptr, old_value, new_value); +} + +inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr, + Atomic32 old_value, + Atomic32 new_value) { + return NoBarrier_CompareAndSwap(ptr, old_value, new_value); +} + +inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) { + *ptr = value; +} + +inline void MemoryBarrier() { + pLinuxKernelMemoryBarrier(); +} + +inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) { + *ptr = value; + MemoryBarrier(); +} + +inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) { + MemoryBarrier(); + *ptr = value; +} + +inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) { + return *ptr; +} + +inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) { + Atomic32 value = *ptr; + MemoryBarrier(); + return value; +} + +inline Atomic32 Release_Load(volatile const Atomic32* ptr) { + MemoryBarrier(); + return *ptr; +} + +} // namespace internal +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_ARM_GCC_H_ diff --git a/include/google/protobuf/stubs/atomicops_internals_arm_qnx.h b/include/google/protobuf/stubs/atomicops_internals_arm_qnx.h new file mode 100644 index 000000000..f05076978 --- /dev/null +++ b/include/google/protobuf/stubs/atomicops_internals_arm_qnx.h @@ -0,0 +1,146 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2012 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// This file is an internal atomic implementation, use atomicops.h instead. + +#ifndef GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_ARM_QNX_H_ +#define GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_ARM_QNX_H_ + +// For _smp_cmpxchg() +#include + +namespace google { +namespace protobuf { +namespace internal { + +inline Atomic32 QNXCmpxchg(Atomic32 old_value, + Atomic32 new_value, + volatile Atomic32* ptr) { + return static_cast( + _smp_cmpxchg((volatile unsigned *)ptr, + (unsigned)old_value, + (unsigned)new_value)); +} + + +inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr, + Atomic32 old_value, + Atomic32 new_value) { + Atomic32 prev_value = *ptr; + do { + if (!QNXCmpxchg(old_value, new_value, + const_cast(ptr))) { + return old_value; + } + prev_value = *ptr; + } while (prev_value == old_value); + return prev_value; +} + +inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr, + Atomic32 new_value) { + Atomic32 old_value; + do { + old_value = *ptr; + } while (QNXCmpxchg(old_value, new_value, + const_cast(ptr))); + return old_value; +} + +inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr, + Atomic32 increment) { + return Barrier_AtomicIncrement(ptr, increment); +} + +inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr, + Atomic32 increment) { + for (;;) { + // Atomic exchange the old value with an incremented one. + Atomic32 old_value = *ptr; + Atomic32 new_value = old_value + increment; + if (QNXCmpxchg(old_value, new_value, + const_cast(ptr)) == 0) { + // The exchange took place as expected. + return new_value; + } + // Otherwise, *ptr changed mid-loop and we need to retry. + } +} + +inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr, + Atomic32 old_value, + Atomic32 new_value) { + return NoBarrier_CompareAndSwap(ptr, old_value, new_value); +} + +inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr, + Atomic32 old_value, + Atomic32 new_value) { + return NoBarrier_CompareAndSwap(ptr, old_value, new_value); +} + +inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) { + *ptr = value; +} + +inline void MemoryBarrier() { + __sync_synchronize(); +} + +inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) { + *ptr = value; + MemoryBarrier(); +} + +inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) { + MemoryBarrier(); + *ptr = value; +} + +inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) { + return *ptr; +} + +inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) { + Atomic32 value = *ptr; + MemoryBarrier(); + return value; +} + +inline Atomic32 Release_Load(volatile const Atomic32* ptr) { + MemoryBarrier(); + return *ptr; +} + +} // namespace internal +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_ARM_QNX_H_ diff --git a/include/google/protobuf/stubs/atomicops_internals_atomicword_compat.h b/include/google/protobuf/stubs/atomicops_internals_atomicword_compat.h new file mode 100644 index 000000000..e9d86797b --- /dev/null +++ b/include/google/protobuf/stubs/atomicops_internals_atomicword_compat.h @@ -0,0 +1,122 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2012 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// This file is an internal atomic implementation, use atomicops.h instead. + +#ifndef GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_ATOMICWORD_COMPAT_H_ +#define GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_ATOMICWORD_COMPAT_H_ + +// AtomicWord is a synonym for intptr_t, and Atomic32 is a synonym for int32, +// which in turn means int. On some LP32 platforms, intptr_t is an int, but +// on others, it's a long. When AtomicWord and Atomic32 are based on different +// fundamental types, their pointers are incompatible. +// +// This file defines function overloads to allow both AtomicWord and Atomic32 +// data to be used with this interface. +// +// On LP64 platforms, AtomicWord and Atomic64 are both always long, +// so this problem doesn't occur. + +#if !defined(GOOGLE_PROTOBUF_ARCH_64_BIT) + +namespace google { +namespace protobuf { +namespace internal { + +inline AtomicWord NoBarrier_CompareAndSwap(volatile AtomicWord* ptr, + AtomicWord old_value, + AtomicWord new_value) { + return NoBarrier_CompareAndSwap( + reinterpret_cast(ptr), old_value, new_value); +} + +inline AtomicWord NoBarrier_AtomicExchange(volatile AtomicWord* ptr, + AtomicWord new_value) { + return NoBarrier_AtomicExchange( + reinterpret_cast(ptr), new_value); +} + +inline AtomicWord NoBarrier_AtomicIncrement(volatile AtomicWord* ptr, + AtomicWord increment) { + return NoBarrier_AtomicIncrement( + reinterpret_cast(ptr), increment); +} + +inline AtomicWord Barrier_AtomicIncrement(volatile AtomicWord* ptr, + AtomicWord increment) { + return Barrier_AtomicIncrement( + reinterpret_cast(ptr), increment); +} + +inline AtomicWord Acquire_CompareAndSwap(volatile AtomicWord* ptr, + AtomicWord old_value, + AtomicWord new_value) { + return Acquire_CompareAndSwap( + reinterpret_cast(ptr), old_value, new_value); +} + +inline AtomicWord Release_CompareAndSwap(volatile AtomicWord* ptr, + AtomicWord old_value, + AtomicWord new_value) { + return Release_CompareAndSwap( + reinterpret_cast(ptr), old_value, new_value); +} + +inline void NoBarrier_Store(volatile AtomicWord *ptr, AtomicWord value) { + NoBarrier_Store(reinterpret_cast(ptr), value); +} + +inline void Acquire_Store(volatile AtomicWord* ptr, AtomicWord value) { + return Acquire_Store(reinterpret_cast(ptr), value); +} + +inline void Release_Store(volatile AtomicWord* ptr, AtomicWord value) { + return Release_Store(reinterpret_cast(ptr), value); +} + +inline AtomicWord NoBarrier_Load(volatile const AtomicWord *ptr) { + return NoBarrier_Load(reinterpret_cast(ptr)); +} + +inline AtomicWord Acquire_Load(volatile const AtomicWord* ptr) { + return Acquire_Load(reinterpret_cast(ptr)); +} + +inline AtomicWord Release_Load(volatile const AtomicWord* ptr) { + return Release_Load(reinterpret_cast(ptr)); +} + +} // namespace internal +} // namespace protobuf +} // namespace google + +#endif // !defined(GOOGLE_PROTOBUF_ARCH_64_BIT) + +#endif // GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_ATOMICWORD_COMPAT_H_ diff --git a/include/google/protobuf/stubs/atomicops_internals_macosx.h b/include/google/protobuf/stubs/atomicops_internals_macosx.h new file mode 100644 index 000000000..f9b7581ad --- /dev/null +++ b/include/google/protobuf/stubs/atomicops_internals_macosx.h @@ -0,0 +1,225 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2012 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// This file is an internal atomic implementation, use atomicops.h instead. + +#ifndef GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_MACOSX_H_ +#define GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_MACOSX_H_ + +#include + +namespace google { +namespace protobuf { +namespace internal { + +inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr, + Atomic32 old_value, + Atomic32 new_value) { + Atomic32 prev_value; + do { + if (OSAtomicCompareAndSwap32(old_value, new_value, + const_cast(ptr))) { + return old_value; + } + prev_value = *ptr; + } while (prev_value == old_value); + return prev_value; +} + +inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr, + Atomic32 new_value) { + Atomic32 old_value; + do { + old_value = *ptr; + } while (!OSAtomicCompareAndSwap32(old_value, new_value, + const_cast(ptr))); + return old_value; +} + +inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr, + Atomic32 increment) { + return OSAtomicAdd32(increment, const_cast(ptr)); +} + +inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr, + Atomic32 increment) { + return OSAtomicAdd32Barrier(increment, const_cast(ptr)); +} + +inline void MemoryBarrier() { + OSMemoryBarrier(); +} + +inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr, + Atomic32 old_value, + Atomic32 new_value) { + Atomic32 prev_value; + do { + if (OSAtomicCompareAndSwap32Barrier(old_value, new_value, + const_cast(ptr))) { + return old_value; + } + prev_value = *ptr; + } while (prev_value == old_value); + return prev_value; +} + +inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr, + Atomic32 old_value, + Atomic32 new_value) { + return Acquire_CompareAndSwap(ptr, old_value, new_value); +} + +inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) { + *ptr = value; +} + +inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) { + *ptr = value; + MemoryBarrier(); +} + +inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) { + MemoryBarrier(); + *ptr = value; +} + +inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) { + return *ptr; +} + +inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) { + Atomic32 value = *ptr; + MemoryBarrier(); + return value; +} + +inline Atomic32 Release_Load(volatile const Atomic32* ptr) { + MemoryBarrier(); + return *ptr; +} + +#ifdef __LP64__ + +// 64-bit implementation on 64-bit platform + +inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr, + Atomic64 old_value, + Atomic64 new_value) { + Atomic64 prev_value; + do { + if (OSAtomicCompareAndSwap64(old_value, new_value, + reinterpret_cast(ptr))) { + return old_value; + } + prev_value = *ptr; + } while (prev_value == old_value); + return prev_value; +} + +inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr, + Atomic64 new_value) { + Atomic64 old_value; + do { + old_value = *ptr; + } while (!OSAtomicCompareAndSwap64(old_value, new_value, + reinterpret_cast(ptr))); + return old_value; +} + +inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr, + Atomic64 increment) { + return OSAtomicAdd64(increment, reinterpret_cast(ptr)); +} + +inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr, + Atomic64 increment) { + return OSAtomicAdd64Barrier(increment, + reinterpret_cast(ptr)); +} + +inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr, + Atomic64 old_value, + Atomic64 new_value) { + Atomic64 prev_value; + do { + if (OSAtomicCompareAndSwap64Barrier( + old_value, new_value, reinterpret_cast(ptr))) { + return old_value; + } + prev_value = *ptr; + } while (prev_value == old_value); + return prev_value; +} + +inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr, + Atomic64 old_value, + Atomic64 new_value) { + // The lib kern interface does not distinguish between + // Acquire and Release memory barriers; they are equivalent. + return Acquire_CompareAndSwap(ptr, old_value, new_value); +} + +inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) { + *ptr = value; +} + +inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) { + *ptr = value; + MemoryBarrier(); +} + +inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) { + MemoryBarrier(); + *ptr = value; +} + +inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) { + return *ptr; +} + +inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) { + Atomic64 value = *ptr; + MemoryBarrier(); + return value; +} + +inline Atomic64 Release_Load(volatile const Atomic64* ptr) { + MemoryBarrier(); + return *ptr; +} + +#endif // defined(__LP64__) + +} // namespace internal +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_MACOSX_H_ diff --git a/include/google/protobuf/stubs/atomicops_internals_mips_gcc.h b/include/google/protobuf/stubs/atomicops_internals_mips_gcc.h new file mode 100644 index 000000000..dc468517a --- /dev/null +++ b/include/google/protobuf/stubs/atomicops_internals_mips_gcc.h @@ -0,0 +1,187 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2012 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// This file is an internal atomic implementation, use atomicops.h instead. + +#ifndef GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_MIPS_GCC_H_ +#define GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_MIPS_GCC_H_ + +#define ATOMICOPS_COMPILER_BARRIER() __asm__ __volatile__("" : : : "memory") + +namespace google { +namespace protobuf { +namespace internal { + +// Atomically execute: +// result = *ptr; +// if (*ptr == old_value) +// *ptr = new_value; +// return result; +// +// I.e., replace "*ptr" with "new_value" if "*ptr" used to be "old_value". +// Always return the old value of "*ptr" +// +// This routine implies no memory barriers. +inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr, + Atomic32 old_value, + Atomic32 new_value) { + Atomic32 prev, tmp; + __asm__ __volatile__(".set push\n" + ".set noreorder\n" + "1:\n" + "ll %0, %5\n" // prev = *ptr + "bne %0, %3, 2f\n" // if (prev != old_value) goto 2 + "move %2, %4\n" // tmp = new_value + "sc %2, %1\n" // *ptr = tmp (with atomic check) + "beqz %2, 1b\n" // start again on atomic error + "nop\n" // delay slot nop + "2:\n" + ".set pop\n" + : "=&r" (prev), "=m" (*ptr), "=&r" (tmp) + : "Ir" (old_value), "r" (new_value), "m" (*ptr) + : "memory"); + return prev; +} + +// Atomically store new_value into *ptr, returning the previous value held in +// *ptr. This routine implies no memory barriers. +inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr, + Atomic32 new_value) { + Atomic32 temp, old; + __asm__ __volatile__(".set push\n" + ".set noreorder\n" + "1:\n" + "ll %1, %2\n" // old = *ptr + "move %0, %3\n" // temp = new_value + "sc %0, %2\n" // *ptr = temp (with atomic check) + "beqz %0, 1b\n" // start again on atomic error + "nop\n" // delay slot nop + ".set pop\n" + : "=&r" (temp), "=&r" (old), "=m" (*ptr) + : "r" (new_value), "m" (*ptr) + : "memory"); + + return old; +} + +// Atomically increment *ptr by "increment". Returns the new value of +// *ptr with the increment applied. This routine implies no memory barriers. +inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr, + Atomic32 increment) { + Atomic32 temp, temp2; + + __asm__ __volatile__(".set push\n" + ".set noreorder\n" + "1:\n" + "ll %0, %2\n" // temp = *ptr + "addu %1, %0, %3\n" // temp2 = temp + increment + "sc %1, %2\n" // *ptr = temp2 (with atomic check) + "beqz %1, 1b\n" // start again on atomic error + "addu %1, %0, %3\n" // temp2 = temp + increment + ".set pop\n" + : "=&r" (temp), "=&r" (temp2), "=m" (*ptr) + : "Ir" (increment), "m" (*ptr) + : "memory"); + // temp2 now holds the final value. + return temp2; +} + +inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr, + Atomic32 increment) { + ATOMICOPS_COMPILER_BARRIER(); + Atomic32 res = NoBarrier_AtomicIncrement(ptr, increment); + ATOMICOPS_COMPILER_BARRIER(); + return res; +} + +// "Acquire" operations +// ensure that no later memory access can be reordered ahead of the operation. +// "Release" operations ensure that no previous memory access can be reordered +// after the operation. "Barrier" operations have both "Acquire" and "Release" +// semantics. A MemoryBarrier() has "Barrier" semantics, but does no memory +// access. +inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr, + Atomic32 old_value, + Atomic32 new_value) { + ATOMICOPS_COMPILER_BARRIER(); + Atomic32 res = NoBarrier_CompareAndSwap(ptr, old_value, new_value); + ATOMICOPS_COMPILER_BARRIER(); + return res; +} + +inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr, + Atomic32 old_value, + Atomic32 new_value) { + ATOMICOPS_COMPILER_BARRIER(); + Atomic32 res = NoBarrier_CompareAndSwap(ptr, old_value, new_value); + ATOMICOPS_COMPILER_BARRIER(); + return res; +} + +inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) { + *ptr = value; +} + +inline void MemoryBarrier() { + __asm__ __volatile__("sync" : : : "memory"); +} + +inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) { + *ptr = value; + MemoryBarrier(); +} + +inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) { + MemoryBarrier(); + *ptr = value; +} + +inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) { + return *ptr; +} + +inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) { + Atomic32 value = *ptr; + MemoryBarrier(); + return value; +} + +inline Atomic32 Release_Load(volatile const Atomic32* ptr) { + MemoryBarrier(); + return *ptr; +} + +} // namespace internal +} // namespace protobuf +} // namespace google + +#undef ATOMICOPS_COMPILER_BARRIER + +#endif // GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_MIPS_GCC_H_ diff --git a/include/google/protobuf/stubs/atomicops_internals_pnacl.h b/include/google/protobuf/stubs/atomicops_internals_pnacl.h new file mode 100644 index 000000000..04a91a83f --- /dev/null +++ b/include/google/protobuf/stubs/atomicops_internals_pnacl.h @@ -0,0 +1,73 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2012 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// This file is an internal atomic implementation, use atomicops.h instead. + +#ifndef GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_PNACL_H_ +#define GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_PNACL_H_ + +namespace google { +namespace protobuf { +namespace internal { + +inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr, + Atomic32 old_value, + Atomic32 new_value) { + return __sync_val_compare_and_swap(ptr, old_value, new_value); +} + +inline void MemoryBarrier() { + __sync_synchronize(); +} + +inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr, + Atomic32 old_value, + Atomic32 new_value) { + Atomic32 ret = NoBarrier_CompareAndSwap(ptr, old_value, new_value); + MemoryBarrier(); + return ret; +} + +inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) { + MemoryBarrier(); + *ptr = value; +} + +inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) { + Atomic32 value = *ptr; + MemoryBarrier(); + return value; +} + +} // namespace internal +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_PNACL_H_ diff --git a/include/google/protobuf/stubs/atomicops_internals_x86_gcc.h b/include/google/protobuf/stubs/atomicops_internals_x86_gcc.h new file mode 100644 index 000000000..5324dfbcb --- /dev/null +++ b/include/google/protobuf/stubs/atomicops_internals_x86_gcc.h @@ -0,0 +1,293 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2012 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// This file is an internal atomic implementation, use atomicops.h instead. + +#ifndef GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_X86_GCC_H_ +#define GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_X86_GCC_H_ + +namespace google { +namespace protobuf { +namespace internal { + +// This struct is not part of the public API of this module; clients may not +// use it. +// Features of this x86. Values may not be correct before main() is run, +// but are set conservatively. +struct AtomicOps_x86CPUFeatureStruct { + bool has_amd_lock_mb_bug; // Processor has AMD memory-barrier bug; do lfence + // after acquire compare-and-swap. + bool has_sse2; // Processor has SSE2. +}; +extern struct AtomicOps_x86CPUFeatureStruct AtomicOps_Internalx86CPUFeatures; + +#define ATOMICOPS_COMPILER_BARRIER() __asm__ __volatile__("" : : : "memory") + +// 32-bit low-level operations on any platform. + +inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr, + Atomic32 old_value, + Atomic32 new_value) { + Atomic32 prev; + __asm__ __volatile__("lock; cmpxchgl %1,%2" + : "=a" (prev) + : "q" (new_value), "m" (*ptr), "0" (old_value) + : "memory"); + return prev; +} + +inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr, + Atomic32 new_value) { + __asm__ __volatile__("xchgl %1,%0" // The lock prefix is implicit for xchg. + : "=r" (new_value) + : "m" (*ptr), "0" (new_value) + : "memory"); + return new_value; // Now it's the previous value. +} + +inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr, + Atomic32 increment) { + Atomic32 temp = increment; + __asm__ __volatile__("lock; xaddl %0,%1" + : "+r" (temp), "+m" (*ptr) + : : "memory"); + // temp now holds the old value of *ptr + return temp + increment; +} + +inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr, + Atomic32 increment) { + Atomic32 temp = increment; + __asm__ __volatile__("lock; xaddl %0,%1" + : "+r" (temp), "+m" (*ptr) + : : "memory"); + // temp now holds the old value of *ptr + if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) { + __asm__ __volatile__("lfence" : : : "memory"); + } + return temp + increment; +} + +inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr, + Atomic32 old_value, + Atomic32 new_value) { + Atomic32 x = NoBarrier_CompareAndSwap(ptr, old_value, new_value); + if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) { + __asm__ __volatile__("lfence" : : : "memory"); + } + return x; +} + +inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr, + Atomic32 old_value, + Atomic32 new_value) { + return NoBarrier_CompareAndSwap(ptr, old_value, new_value); +} + +inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) { + *ptr = value; +} + +#if defined(__x86_64__) + +// 64-bit implementations of memory barrier can be simpler, because it +// "mfence" is guaranteed to exist. +inline void MemoryBarrier() { + __asm__ __volatile__("mfence" : : : "memory"); +} + +inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) { + *ptr = value; + MemoryBarrier(); +} + +#else + +inline void MemoryBarrier() { + if (AtomicOps_Internalx86CPUFeatures.has_sse2) { + __asm__ __volatile__("mfence" : : : "memory"); + } else { // mfence is faster but not present on PIII + Atomic32 x = 0; + NoBarrier_AtomicExchange(&x, 0); // acts as a barrier on PIII + } +} + +inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) { + if (AtomicOps_Internalx86CPUFeatures.has_sse2) { + *ptr = value; + __asm__ __volatile__("mfence" : : : "memory"); + } else { + NoBarrier_AtomicExchange(ptr, value); + // acts as a barrier on PIII + } +} +#endif + +inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) { + ATOMICOPS_COMPILER_BARRIER(); + *ptr = value; // An x86 store acts as a release barrier. + // See comments in Atomic64 version of Release_Store(), below. +} + +inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) { + return *ptr; +} + +inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) { + Atomic32 value = *ptr; // An x86 load acts as a acquire barrier. + // See comments in Atomic64 version of Release_Store(), below. + ATOMICOPS_COMPILER_BARRIER(); + return value; +} + +inline Atomic32 Release_Load(volatile const Atomic32* ptr) { + MemoryBarrier(); + return *ptr; +} + +#if defined(__x86_64__) + +// 64-bit low-level operations on 64-bit platform. + +inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr, + Atomic64 old_value, + Atomic64 new_value) { + Atomic64 prev; + __asm__ __volatile__("lock; cmpxchgq %1,%2" + : "=a" (prev) + : "q" (new_value), "m" (*ptr), "0" (old_value) + : "memory"); + return prev; +} + +inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr, + Atomic64 new_value) { + __asm__ __volatile__("xchgq %1,%0" // The lock prefix is implicit for xchg. + : "=r" (new_value) + : "m" (*ptr), "0" (new_value) + : "memory"); + return new_value; // Now it's the previous value. +} + +inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr, + Atomic64 increment) { + Atomic64 temp = increment; + __asm__ __volatile__("lock; xaddq %0,%1" + : "+r" (temp), "+m" (*ptr) + : : "memory"); + // temp now contains the previous value of *ptr + return temp + increment; +} + +inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr, + Atomic64 increment) { + Atomic64 temp = increment; + __asm__ __volatile__("lock; xaddq %0,%1" + : "+r" (temp), "+m" (*ptr) + : : "memory"); + // temp now contains the previous value of *ptr + if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) { + __asm__ __volatile__("lfence" : : : "memory"); + } + return temp + increment; +} + +inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) { + *ptr = value; +} + +inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) { + *ptr = value; + MemoryBarrier(); +} + +inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) { + ATOMICOPS_COMPILER_BARRIER(); + + *ptr = value; // An x86 store acts as a release barrier + // for current AMD/Intel chips as of Jan 2008. + // See also Acquire_Load(), below. + + // When new chips come out, check: + // IA-32 Intel Architecture Software Developer's Manual, Volume 3: + // System Programming Guide, Chatper 7: Multiple-processor management, + // Section 7.2, Memory Ordering. + // Last seen at: + // http://developer.intel.com/design/pentium4/manuals/index_new.htm + // + // x86 stores/loads fail to act as barriers for a few instructions (clflush + // maskmovdqu maskmovq movntdq movnti movntpd movntps movntq) but these are + // not generated by the compiler, and are rare. Users of these instructions + // need to know about cache behaviour in any case since all of these involve + // either flushing cache lines or non-temporal cache hints. +} + +inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) { + return *ptr; +} + +inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) { + Atomic64 value = *ptr; // An x86 load acts as a acquire barrier, + // for current AMD/Intel chips as of Jan 2008. + // See also Release_Store(), above. + ATOMICOPS_COMPILER_BARRIER(); + return value; +} + +inline Atomic64 Release_Load(volatile const Atomic64* ptr) { + MemoryBarrier(); + return *ptr; +} + +inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr, + Atomic64 old_value, + Atomic64 new_value) { + Atomic64 x = NoBarrier_CompareAndSwap(ptr, old_value, new_value); + if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) { + __asm__ __volatile__("lfence" : : : "memory"); + } + return x; +} + +inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr, + Atomic64 old_value, + Atomic64 new_value) { + return NoBarrier_CompareAndSwap(ptr, old_value, new_value); +} + +#endif // defined(__x86_64__) + +} // namespace internal +} // namespace protobuf +} // namespace google + +#undef ATOMICOPS_COMPILER_BARRIER + +#endif // GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_X86_GCC_H_ diff --git a/include/google/protobuf/stubs/atomicops_internals_x86_msvc.h b/include/google/protobuf/stubs/atomicops_internals_x86_msvc.h new file mode 100644 index 000000000..6f9869d1f --- /dev/null +++ b/include/google/protobuf/stubs/atomicops_internals_x86_msvc.h @@ -0,0 +1,150 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2012 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// This file is an internal atomic implementation, use atomicops.h instead. + +#ifndef GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_X86_MSVC_H_ +#define GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_X86_MSVC_H_ + +namespace google { +namespace protobuf { +namespace internal { + +inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr, + Atomic32 increment) { + return Barrier_AtomicIncrement(ptr, increment); +} + +#if !(defined(_MSC_VER) && _MSC_VER >= 1400) +#error "We require at least vs2005 for MemoryBarrier" +#endif + +inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr, + Atomic32 old_value, + Atomic32 new_value) { + return NoBarrier_CompareAndSwap(ptr, old_value, new_value); +} + +inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr, + Atomic32 old_value, + Atomic32 new_value) { + return NoBarrier_CompareAndSwap(ptr, old_value, new_value); +} + +inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) { + *ptr = value; +} + +inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) { + NoBarrier_AtomicExchange(ptr, value); + // acts as a barrier in this implementation +} + +inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) { + *ptr = value; // works w/o barrier for current Intel chips as of June 2005 + // See comments in Atomic64 version of Release_Store() below. +} + +inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) { + return *ptr; +} + +inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) { + Atomic32 value = *ptr; + return value; +} + +inline Atomic32 Release_Load(volatile const Atomic32* ptr) { + MemoryBarrier(); + return *ptr; +} + +#if defined(_WIN64) + +// 64-bit low-level operations on 64-bit platform. + +inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr, + Atomic64 increment) { + return Barrier_AtomicIncrement(ptr, increment); +} + +inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) { + *ptr = value; +} + +inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) { + NoBarrier_AtomicExchange(ptr, value); + // acts as a barrier in this implementation +} + +inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) { + *ptr = value; // works w/o barrier for current Intel chips as of June 2005 + + // When new chips come out, check: + // IA-32 Intel Architecture Software Developer's Manual, Volume 3: + // System Programming Guide, Chatper 7: Multiple-processor management, + // Section 7.2, Memory Ordering. + // Last seen at: + // http://developer.intel.com/design/pentium4/manuals/index_new.htm +} + +inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) { + return *ptr; +} + +inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) { + Atomic64 value = *ptr; + return value; +} + +inline Atomic64 Release_Load(volatile const Atomic64* ptr) { + MemoryBarrier(); + return *ptr; +} + +inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr, + Atomic64 old_value, + Atomic64 new_value) { + return NoBarrier_CompareAndSwap(ptr, old_value, new_value); +} + +inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr, + Atomic64 old_value, + Atomic64 new_value) { + return NoBarrier_CompareAndSwap(ptr, old_value, new_value); +} + +#endif // defined(_WIN64) + +} // namespace internal +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_X86_MSVC_H_ diff --git a/include/google/protobuf/stubs/common.h b/include/google/protobuf/stubs/common.h new file mode 100644 index 000000000..b47017dff --- /dev/null +++ b/include/google/protobuf/stubs/common.h @@ -0,0 +1,1223 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) and others +// +// Contains basic types and utilities used by the rest of the library. + +#ifndef GOOGLE_PROTOBUF_COMMON_H__ +#define GOOGLE_PROTOBUF_COMMON_H__ + +#include +#include +#include +#include +#include +#if defined(__osf__) +// Tru64 lacks stdint.h, but has inttypes.h which defines a superset of +// what stdint.h would define. +#include +#elif !defined(_MSC_VER) +#include +#endif + +#ifndef PROTOBUF_USE_EXCEPTIONS +#if defined(_MSC_VER) && defined(_CPPUNWIND) + #define PROTOBUF_USE_EXCEPTIONS 1 +#elif defined(__EXCEPTIONS) + #define PROTOBUF_USE_EXCEPTIONS 1 +#else + #define PROTOBUF_USE_EXCEPTIONS 0 +#endif +#endif + +#if PROTOBUF_USE_EXCEPTIONS +#include +#endif + +#if defined(_WIN32) && defined(GetMessage) +// Allow GetMessage to be used as a valid method name in protobuf classes. +// windows.h defines GetMessage() as a macro. Let's re-define it as an inline +// function. The inline function should be equivalent for C++ users. +inline BOOL GetMessage_Win32( + LPMSG lpMsg, HWND hWnd, + UINT wMsgFilterMin, UINT wMsgFilterMax) { + return GetMessage(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax); +} +#undef GetMessage +inline BOOL GetMessage( + LPMSG lpMsg, HWND hWnd, + UINT wMsgFilterMin, UINT wMsgFilterMax) { + return GetMessage_Win32(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax); +} +#endif + + +namespace std {} + +namespace google { +namespace protobuf { + +#undef GOOGLE_DISALLOW_EVIL_CONSTRUCTORS +#define GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(TypeName) \ + TypeName(const TypeName&); \ + void operator=(const TypeName&) + +#if defined(_MSC_VER) && defined(PROTOBUF_USE_DLLS) + #ifdef LIBPROTOBUF_EXPORTS + #define LIBPROTOBUF_EXPORT __declspec(dllexport) + #else + #define LIBPROTOBUF_EXPORT __declspec(dllimport) + #endif + #ifdef LIBPROTOC_EXPORTS + #define LIBPROTOC_EXPORT __declspec(dllexport) + #else + #define LIBPROTOC_EXPORT __declspec(dllimport) + #endif +#else + #define LIBPROTOBUF_EXPORT + #define LIBPROTOC_EXPORT +#endif + +namespace internal { + +// Some of these constants are macros rather than const ints so that they can +// be used in #if directives. + +// The current version, represented as a single integer to make comparison +// easier: major * 10^6 + minor * 10^3 + micro +#define GOOGLE_PROTOBUF_VERSION 2005000 + +// The minimum library version which works with the current version of the +// headers. +#define GOOGLE_PROTOBUF_MIN_LIBRARY_VERSION 2005000 + +// The minimum header version which works with the current version of +// the library. This constant should only be used by protoc's C++ code +// generator. +static const int kMinHeaderVersionForLibrary = 2005000; + +// The minimum protoc version which works with the current version of the +// headers. +#define GOOGLE_PROTOBUF_MIN_PROTOC_VERSION 2005000 + +// The minimum header version which works with the current version of +// protoc. This constant should only be used in VerifyVersion(). +static const int kMinHeaderVersionForProtoc = 2005000; + +// Verifies that the headers and libraries are compatible. Use the macro +// below to call this. +void LIBPROTOBUF_EXPORT VerifyVersion(int headerVersion, int minLibraryVersion, + const char* filename); + +// Converts a numeric version number to a string. +std::string LIBPROTOBUF_EXPORT VersionString(int version); + +} // namespace internal + +// Place this macro in your main() function (or somewhere before you attempt +// to use the protobuf library) to verify that the version you link against +// matches the headers you compiled against. If a version mismatch is +// detected, the process will abort. +#define GOOGLE_PROTOBUF_VERIFY_VERSION \ + ::google::protobuf::internal::VerifyVersion( \ + GOOGLE_PROTOBUF_VERSION, GOOGLE_PROTOBUF_MIN_LIBRARY_VERSION, \ + __FILE__) + +// =================================================================== +// from google3/base/port.h + +typedef unsigned int uint; + +#ifdef _MSC_VER +typedef __int8 int8; +typedef __int16 int16; +typedef __int32 int32; +typedef __int64 int64; + +typedef unsigned __int8 uint8; +typedef unsigned __int16 uint16; +typedef unsigned __int32 uint32; +typedef unsigned __int64 uint64; +#else +typedef int8_t int8; +typedef int16_t int16; +typedef int32_t int32; +typedef int64_t int64; + +typedef uint8_t uint8; +typedef uint16_t uint16; +typedef uint32_t uint32; +typedef uint64_t uint64; +#endif + +// long long macros to be used because gcc and vc++ use different suffixes, +// and different size specifiers in format strings +#undef GOOGLE_LONGLONG +#undef GOOGLE_ULONGLONG +#undef GOOGLE_LL_FORMAT + +#ifdef _MSC_VER +#define GOOGLE_LONGLONG(x) x##I64 +#define GOOGLE_ULONGLONG(x) x##UI64 +#define GOOGLE_LL_FORMAT "I64" // As in printf("%I64d", ...) +#else +#define GOOGLE_LONGLONG(x) x##LL +#define GOOGLE_ULONGLONG(x) x##ULL +#define GOOGLE_LL_FORMAT "ll" // As in "%lld". Note that "q" is poor form also. +#endif + +static const int32 kint32max = 0x7FFFFFFF; +static const int32 kint32min = -kint32max - 1; +static const int64 kint64max = GOOGLE_LONGLONG(0x7FFFFFFFFFFFFFFF); +static const int64 kint64min = -kint64max - 1; +static const uint32 kuint32max = 0xFFFFFFFFu; +static const uint64 kuint64max = GOOGLE_ULONGLONG(0xFFFFFFFFFFFFFFFF); + +// ------------------------------------------------------------------- +// Annotations: Some parts of the code have been annotated in ways that might +// be useful to some compilers or tools, but are not supported universally. +// You can #define these annotations yourself if the default implementation +// is not right for you. + +#ifndef GOOGLE_ATTRIBUTE_ALWAYS_INLINE +#if defined(__GNUC__) && (__GNUC__ > 3 ||(__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) +// For functions we want to force inline. +// Introduced in gcc 3.1. +#define GOOGLE_ATTRIBUTE_ALWAYS_INLINE __attribute__ ((always_inline)) +#else +// Other compilers will have to figure it out for themselves. +#define GOOGLE_ATTRIBUTE_ALWAYS_INLINE +#endif +#endif + +#ifndef GOOGLE_ATTRIBUTE_DEPRECATED +#ifdef __GNUC__ +// If the method/variable/type is used anywhere, produce a warning. +#define GOOGLE_ATTRIBUTE_DEPRECATED __attribute__((deprecated)) +#else +#define GOOGLE_ATTRIBUTE_DEPRECATED +#endif +#endif + +#ifndef GOOGLE_PREDICT_TRUE +#ifdef __GNUC__ +// Provided at least since GCC 3.0. +#define GOOGLE_PREDICT_TRUE(x) (__builtin_expect(!!(x), 1)) +#else +#define GOOGLE_PREDICT_TRUE +#endif +#endif + +// Delimits a block of code which may write to memory which is simultaneously +// written by other threads, but which has been determined to be thread-safe +// (e.g. because it is an idempotent write). +#ifndef GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN +#define GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN() +#endif +#ifndef GOOGLE_SAFE_CONCURRENT_WRITES_END +#define GOOGLE_SAFE_CONCURRENT_WRITES_END() +#endif + +// =================================================================== +// from google3/base/basictypes.h + +// The GOOGLE_ARRAYSIZE(arr) macro returns the # of elements in an array arr. +// The expression is a compile-time constant, and therefore can be +// used in defining new arrays, for example. +// +// GOOGLE_ARRAYSIZE catches a few type errors. If you see a compiler error +// +// "warning: division by zero in ..." +// +// when using GOOGLE_ARRAYSIZE, you are (wrongfully) giving it a pointer. +// You should only use GOOGLE_ARRAYSIZE on statically allocated arrays. +// +// The following comments are on the implementation details, and can +// be ignored by the users. +// +// ARRAYSIZE(arr) works by inspecting sizeof(arr) (the # of bytes in +// the array) and sizeof(*(arr)) (the # of bytes in one array +// element). If the former is divisible by the latter, perhaps arr is +// indeed an array, in which case the division result is the # of +// elements in the array. Otherwise, arr cannot possibly be an array, +// and we generate a compiler error to prevent the code from +// compiling. +// +// Since the size of bool is implementation-defined, we need to cast +// !(sizeof(a) & sizeof(*(a))) to size_t in order to ensure the final +// result has type size_t. +// +// This macro is not perfect as it wrongfully accepts certain +// pointers, namely where the pointer size is divisible by the pointee +// size. Since all our code has to go through a 32-bit compiler, +// where a pointer is 4 bytes, this means all pointers to a type whose +// size is 3 or greater than 4 will be (righteously) rejected. +// +// Kudos to Jorg Brown for this simple and elegant implementation. + +#undef GOOGLE_ARRAYSIZE +#define GOOGLE_ARRAYSIZE(a) \ + ((sizeof(a) / sizeof(*(a))) / \ + static_cast(!(sizeof(a) % sizeof(*(a))))) + +namespace internal { + +// Use implicit_cast as a safe version of static_cast or const_cast +// for upcasting in the type hierarchy (i.e. casting a pointer to Foo +// to a pointer to SuperclassOfFoo or casting a pointer to Foo to +// a const pointer to Foo). +// When you use implicit_cast, the compiler checks that the cast is safe. +// Such explicit implicit_casts are necessary in surprisingly many +// situations where C++ demands an exact type match instead of an +// argument type convertable to a target type. +// +// The From type can be inferred, so the preferred syntax for using +// implicit_cast is the same as for static_cast etc.: +// +// implicit_cast(expr) +// +// implicit_cast would have been part of the C++ standard library, +// but the proposal was submitted too late. It will probably make +// its way into the language in the future. +template +inline To implicit_cast(From const &f) { + return f; +} + +// When you upcast (that is, cast a pointer from type Foo to type +// SuperclassOfFoo), it's fine to use implicit_cast<>, since upcasts +// always succeed. When you downcast (that is, cast a pointer from +// type Foo to type SubclassOfFoo), static_cast<> isn't safe, because +// how do you know the pointer is really of type SubclassOfFoo? It +// could be a bare Foo, or of type DifferentSubclassOfFoo. Thus, +// when you downcast, you should use this macro. In debug mode, we +// use dynamic_cast<> to double-check the downcast is legal (we die +// if it's not). In normal mode, we do the efficient static_cast<> +// instead. Thus, it's important to test in debug mode to make sure +// the cast is legal! +// This is the only place in the code we should use dynamic_cast<>. +// In particular, you SHOULDN'T be using dynamic_cast<> in order to +// do RTTI (eg code like this: +// if (dynamic_cast(foo)) HandleASubclass1Object(foo); +// if (dynamic_cast(foo)) HandleASubclass2Object(foo); +// You should design the code some other way not to need this. + +template // use like this: down_cast(foo); +inline To down_cast(From* f) { // so we only accept pointers + // Ensures that To is a sub-type of From *. This test is here only + // for compile-time type checking, and has no overhead in an + // optimized build at run-time, as it will be optimized away + // completely. + if (false) { + implicit_cast(0); + } + +#if !defined(NDEBUG) && !defined(GOOGLE_PROTOBUF_NO_RTTI) + assert(f == NULL || dynamic_cast(f) != NULL); // RTTI: debug mode only! +#endif + return static_cast(f); +} + +} // namespace internal + +// We made these internal so that they would show up as such in the docs, +// but we don't want to stick "internal::" in front of them everywhere. +using internal::implicit_cast; +using internal::down_cast; + +// The COMPILE_ASSERT macro can be used to verify that a compile time +// expression is true. For example, you could use it to verify the +// size of a static array: +// +// COMPILE_ASSERT(ARRAYSIZE(content_type_names) == CONTENT_NUM_TYPES, +// content_type_names_incorrect_size); +// +// or to make sure a struct is smaller than a certain size: +// +// COMPILE_ASSERT(sizeof(foo) < 128, foo_too_large); +// +// The second argument to the macro is the name of the variable. If +// the expression is false, most compilers will issue a warning/error +// containing the name of the variable. + +namespace internal { + +template +struct CompileAssert { +}; + +} // namespace internal + +#undef GOOGLE_COMPILE_ASSERT +#define GOOGLE_COMPILE_ASSERT(expr, msg) \ + typedef ::google::protobuf::internal::CompileAssert<(bool(expr))> \ + msg[bool(expr) ? 1 : -1] + + +// Implementation details of COMPILE_ASSERT: +// +// - COMPILE_ASSERT works by defining an array type that has -1 +// elements (and thus is invalid) when the expression is false. +// +// - The simpler definition +// +// #define COMPILE_ASSERT(expr, msg) typedef char msg[(expr) ? 1 : -1] +// +// does not work, as gcc supports variable-length arrays whose sizes +// are determined at run-time (this is gcc's extension and not part +// of the C++ standard). As a result, gcc fails to reject the +// following code with the simple definition: +// +// int foo; +// COMPILE_ASSERT(foo, msg); // not supposed to compile as foo is +// // not a compile-time constant. +// +// - By using the type CompileAssert<(bool(expr))>, we ensures that +// expr is a compile-time constant. (Template arguments must be +// determined at compile-time.) +// +// - The outter parentheses in CompileAssert<(bool(expr))> are necessary +// to work around a bug in gcc 3.4.4 and 4.0.1. If we had written +// +// CompileAssert +// +// instead, these compilers will refuse to compile +// +// COMPILE_ASSERT(5 > 0, some_message); +// +// (They seem to think the ">" in "5 > 0" marks the end of the +// template argument list.) +// +// - The array size is (bool(expr) ? 1 : -1), instead of simply +// +// ((expr) ? 1 : -1). +// +// This is to avoid running into a bug in MS VC 7.1, which +// causes ((0.0) ? 1 : -1) to incorrectly evaluate to 1. + +// =================================================================== +// from google3/base/scoped_ptr.h + +namespace internal { + +// This is an implementation designed to match the anticipated future TR2 +// implementation of the scoped_ptr class, and its closely-related brethren, +// scoped_array, scoped_ptr_malloc, and make_scoped_ptr. + +template class scoped_ptr; +template class scoped_array; + +// A scoped_ptr is like a T*, except that the destructor of scoped_ptr +// automatically deletes the pointer it holds (if any). +// That is, scoped_ptr owns the T object that it points to. +// Like a T*, a scoped_ptr may hold either NULL or a pointer to a T object. +// +// The size of a scoped_ptr is small: +// sizeof(scoped_ptr) == sizeof(C*) +template +class scoped_ptr { + public: + + // The element type + typedef C element_type; + + // Constructor. Defaults to intializing with NULL. + // There is no way to create an uninitialized scoped_ptr. + // The input parameter must be allocated with new. + explicit scoped_ptr(C* p = NULL) : ptr_(p) { } + + // Destructor. If there is a C object, delete it. + // We don't need to test ptr_ == NULL because C++ does that for us. + ~scoped_ptr() { + enum { type_must_be_complete = sizeof(C) }; + delete ptr_; + } + + // Reset. Deletes the current owned object, if any. + // Then takes ownership of a new object, if given. + // this->reset(this->get()) works. + void reset(C* p = NULL) { + if (p != ptr_) { + enum { type_must_be_complete = sizeof(C) }; + delete ptr_; + ptr_ = p; + } + } + + // Accessors to get the owned object. + // operator* and operator-> will assert() if there is no current object. + C& operator*() const { + assert(ptr_ != NULL); + return *ptr_; + } + C* operator->() const { + assert(ptr_ != NULL); + return ptr_; + } + C* get() const { return ptr_; } + + // Comparison operators. + // These return whether two scoped_ptr refer to the same object, not just to + // two different but equal objects. + bool operator==(C* p) const { return ptr_ == p; } + bool operator!=(C* p) const { return ptr_ != p; } + + // Swap two scoped pointers. + void swap(scoped_ptr& p2) { + C* tmp = ptr_; + ptr_ = p2.ptr_; + p2.ptr_ = tmp; + } + + // Release a pointer. + // The return value is the current pointer held by this object. + // If this object holds a NULL pointer, the return value is NULL. + // After this operation, this object will hold a NULL pointer, + // and will not own the object any more. + C* release() { + C* retVal = ptr_; + ptr_ = NULL; + return retVal; + } + + private: + C* ptr_; + + // Forbid comparison of scoped_ptr types. If C2 != C, it totally doesn't + // make sense, and if C2 == C, it still doesn't make sense because you should + // never have the same object owned by two different scoped_ptrs. + template bool operator==(scoped_ptr const& p2) const; + template bool operator!=(scoped_ptr const& p2) const; + + // Disallow evil constructors + scoped_ptr(const scoped_ptr&); + void operator=(const scoped_ptr&); +}; + +// scoped_array is like scoped_ptr, except that the caller must allocate +// with new [] and the destructor deletes objects with delete []. +// +// As with scoped_ptr, a scoped_array either points to an object +// or is NULL. A scoped_array owns the object that it points to. +// +// Size: sizeof(scoped_array) == sizeof(C*) +template +class scoped_array { + public: + + // The element type + typedef C element_type; + + // Constructor. Defaults to intializing with NULL. + // There is no way to create an uninitialized scoped_array. + // The input parameter must be allocated with new []. + explicit scoped_array(C* p = NULL) : array_(p) { } + + // Destructor. If there is a C object, delete it. + // We don't need to test ptr_ == NULL because C++ does that for us. + ~scoped_array() { + enum { type_must_be_complete = sizeof(C) }; + delete[] array_; + } + + // Reset. Deletes the current owned object, if any. + // Then takes ownership of a new object, if given. + // this->reset(this->get()) works. + void reset(C* p = NULL) { + if (p != array_) { + enum { type_must_be_complete = sizeof(C) }; + delete[] array_; + array_ = p; + } + } + + // Get one element of the current object. + // Will assert() if there is no current object, or index i is negative. + C& operator[](std::ptrdiff_t i) const { + assert(i >= 0); + assert(array_ != NULL); + return array_[i]; + } + + // Get a pointer to the zeroth element of the current object. + // If there is no current object, return NULL. + C* get() const { + return array_; + } + + // Comparison operators. + // These return whether two scoped_array refer to the same object, not just to + // two different but equal objects. + bool operator==(C* p) const { return array_ == p; } + bool operator!=(C* p) const { return array_ != p; } + + // Swap two scoped arrays. + void swap(scoped_array& p2) { + C* tmp = array_; + array_ = p2.array_; + p2.array_ = tmp; + } + + // Release an array. + // The return value is the current pointer held by this object. + // If this object holds a NULL pointer, the return value is NULL. + // After this operation, this object will hold a NULL pointer, + // and will not own the object any more. + C* release() { + C* retVal = array_; + array_ = NULL; + return retVal; + } + + private: + C* array_; + + // Forbid comparison of different scoped_array types. + template bool operator==(scoped_array const& p2) const; + template bool operator!=(scoped_array const& p2) const; + + // Disallow evil constructors + scoped_array(const scoped_array&); + void operator=(const scoped_array&); +}; + +} // namespace internal + +// We made these internal so that they would show up as such in the docs, +// but we don't want to stick "internal::" in front of them everywhere. +using internal::scoped_ptr; +using internal::scoped_array; + +// =================================================================== +// emulates google3/base/logging.h + +enum LogLevel { + LOGLEVEL_INFO, // Informational. This is never actually used by + // libprotobuf. + LOGLEVEL_WARNING, // Warns about issues that, although not technically a + // problem now, could cause problems in the future. For + // example, a // warning will be printed when parsing a + // message that is near the message size limit. + LOGLEVEL_ERROR, // An error occurred which should never happen during + // normal use. + LOGLEVEL_FATAL, // An error occurred from which the library cannot + // recover. This usually indicates a programming error + // in the code which calls the library, especially when + // compiled in debug mode. + +#ifdef NDEBUG + LOGLEVEL_DFATAL = LOGLEVEL_ERROR +#else + LOGLEVEL_DFATAL = LOGLEVEL_FATAL +#endif +}; + +namespace internal { + +class LogFinisher; + +class LIBPROTOBUF_EXPORT LogMessage { + public: + LogMessage(LogLevel level, const char* filename, int line); + ~LogMessage(); + + LogMessage& operator<<(const std::string& value); + LogMessage& operator<<(const char* value); + LogMessage& operator<<(char value); + LogMessage& operator<<(int value); + LogMessage& operator<<(uint value); + LogMessage& operator<<(long value); + LogMessage& operator<<(unsigned long value); + LogMessage& operator<<(double value); + + private: + friend class LogFinisher; + void Finish(); + + LogLevel level_; + const char* filename_; + int line_; + std::string message_; +}; + +// Used to make the entire "LOG(BLAH) << etc." expression have a void return +// type and print a newline after each message. +class LIBPROTOBUF_EXPORT LogFinisher { + public: + void operator=(LogMessage& other); +}; + +} // namespace internal + +// Undef everything in case we're being mixed with some other Google library +// which already defined them itself. Presumably all Google libraries will +// support the same syntax for these so it should not be a big deal if they +// end up using our definitions instead. +#undef GOOGLE_LOG +#undef GOOGLE_LOG_IF + +#undef GOOGLE_CHECK +#undef GOOGLE_CHECK_EQ +#undef GOOGLE_CHECK_NE +#undef GOOGLE_CHECK_LT +#undef GOOGLE_CHECK_LE +#undef GOOGLE_CHECK_GT +#undef GOOGLE_CHECK_GE +#undef GOOGLE_CHECK_NOTNULL + +#undef GOOGLE_DLOG +#undef GOOGLE_DCHECK +#undef GOOGLE_DCHECK_EQ +#undef GOOGLE_DCHECK_NE +#undef GOOGLE_DCHECK_LT +#undef GOOGLE_DCHECK_LE +#undef GOOGLE_DCHECK_GT +#undef GOOGLE_DCHECK_GE + +#define GOOGLE_LOG(LEVEL) \ + ::google::protobuf::internal::LogFinisher() = \ + ::google::protobuf::internal::LogMessage( \ + ::google::protobuf::LOGLEVEL_##LEVEL, __FILE__, __LINE__) +#define GOOGLE_LOG_IF(LEVEL, CONDITION) \ + !(CONDITION) ? (void)0 : GOOGLE_LOG(LEVEL) + +#define GOOGLE_CHECK(EXPRESSION) \ + GOOGLE_LOG_IF(FATAL, !(EXPRESSION)) << "CHECK failed: " #EXPRESSION ": " +#define GOOGLE_CHECK_EQ(A, B) GOOGLE_CHECK((A) == (B)) +#define GOOGLE_CHECK_NE(A, B) GOOGLE_CHECK((A) != (B)) +#define GOOGLE_CHECK_LT(A, B) GOOGLE_CHECK((A) < (B)) +#define GOOGLE_CHECK_LE(A, B) GOOGLE_CHECK((A) <= (B)) +#define GOOGLE_CHECK_GT(A, B) GOOGLE_CHECK((A) > (B)) +#define GOOGLE_CHECK_GE(A, B) GOOGLE_CHECK((A) >= (B)) + +namespace internal { +template +T* CheckNotNull(const char *file, int line, const char *name, T* val) { + if (val == NULL) { + GOOGLE_LOG(FATAL) << name; + } + return val; +} +} // namespace internal +#define GOOGLE_CHECK_NOTNULL(A) \ + internal::CheckNotNull(__FILE__, __LINE__, "'" #A "' must not be NULL", (A)) + +#ifdef NDEBUG + +#define GOOGLE_DLOG GOOGLE_LOG_IF(INFO, false) + +#define GOOGLE_DCHECK(EXPRESSION) while(false) GOOGLE_CHECK(EXPRESSION) +#define GOOGLE_DCHECK_EQ(A, B) GOOGLE_DCHECK((A) == (B)) +#define GOOGLE_DCHECK_NE(A, B) GOOGLE_DCHECK((A) != (B)) +#define GOOGLE_DCHECK_LT(A, B) GOOGLE_DCHECK((A) < (B)) +#define GOOGLE_DCHECK_LE(A, B) GOOGLE_DCHECK((A) <= (B)) +#define GOOGLE_DCHECK_GT(A, B) GOOGLE_DCHECK((A) > (B)) +#define GOOGLE_DCHECK_GE(A, B) GOOGLE_DCHECK((A) >= (B)) + +#else // NDEBUG + +#define GOOGLE_DLOG GOOGLE_LOG + +#define GOOGLE_DCHECK GOOGLE_CHECK +#define GOOGLE_DCHECK_EQ GOOGLE_CHECK_EQ +#define GOOGLE_DCHECK_NE GOOGLE_CHECK_NE +#define GOOGLE_DCHECK_LT GOOGLE_CHECK_LT +#define GOOGLE_DCHECK_LE GOOGLE_CHECK_LE +#define GOOGLE_DCHECK_GT GOOGLE_CHECK_GT +#define GOOGLE_DCHECK_GE GOOGLE_CHECK_GE + +#endif // !NDEBUG + +typedef void LogHandler(LogLevel level, const char* filename, int line, + const std::string& message); + +// The protobuf library sometimes writes warning and error messages to +// stderr. These messages are primarily useful for developers, but may +// also help end users figure out a problem. If you would prefer that +// these messages be sent somewhere other than stderr, call SetLogHandler() +// to set your own handler. This returns the old handler. Set the handler +// to NULL to ignore log messages (but see also LogSilencer, below). +// +// Obviously, SetLogHandler is not thread-safe. You should only call it +// at initialization time, and probably not from library code. If you +// simply want to suppress log messages temporarily (e.g. because you +// have some code that tends to trigger them frequently and you know +// the warnings are not important to you), use the LogSilencer class +// below. +LIBPROTOBUF_EXPORT LogHandler* SetLogHandler(LogHandler* new_func); + +// Create a LogSilencer if you want to temporarily suppress all log +// messages. As long as any LogSilencer objects exist, non-fatal +// log messages will be discarded (the current LogHandler will *not* +// be called). Constructing a LogSilencer is thread-safe. You may +// accidentally suppress log messages occurring in another thread, but +// since messages are generally for debugging purposes only, this isn't +// a big deal. If you want to intercept log messages, use SetLogHandler(). +class LIBPROTOBUF_EXPORT LogSilencer { + public: + LogSilencer(); + ~LogSilencer(); +}; + +// =================================================================== +// emulates google3/base/callback.h + +// Abstract interface for a callback. When calling an RPC, you must provide +// a Closure to call when the procedure completes. See the Service interface +// in service.h. +// +// To automatically construct a Closure which calls a particular function or +// method with a particular set of parameters, use the NewCallback() function. +// Example: +// void FooDone(const FooResponse* response) { +// ... +// } +// +// void CallFoo() { +// ... +// // When done, call FooDone() and pass it a pointer to the response. +// Closure* callback = NewCallback(&FooDone, response); +// // Make the call. +// service->Foo(controller, request, response, callback); +// } +// +// Example that calls a method: +// class Handler { +// public: +// ... +// +// void FooDone(const FooResponse* response) { +// ... +// } +// +// void CallFoo() { +// ... +// // When done, call FooDone() and pass it a pointer to the response. +// Closure* callback = NewCallback(this, &Handler::FooDone, response); +// // Make the call. +// service->Foo(controller, request, response, callback); +// } +// }; +// +// Currently NewCallback() supports binding zero, one, or two arguments. +// +// Callbacks created with NewCallback() automatically delete themselves when +// executed. They should be used when a callback is to be called exactly +// once (usually the case with RPC callbacks). If a callback may be called +// a different number of times (including zero), create it with +// NewPermanentCallback() instead. You are then responsible for deleting the +// callback (using the "delete" keyword as normal). +// +// Note that NewCallback() is a bit touchy regarding argument types. Generally, +// the values you provide for the parameter bindings must exactly match the +// types accepted by the callback function. For example: +// void Foo(string s); +// NewCallback(&Foo, "foo"); // WON'T WORK: const char* != string +// NewCallback(&Foo, string("foo")); // WORKS +// Also note that the arguments cannot be references: +// void Foo(const string& s); +// string my_str; +// NewCallback(&Foo, my_str); // WON'T WORK: Can't use referecnes. +// However, correctly-typed pointers will work just fine. +class LIBPROTOBUF_EXPORT Closure { + public: + Closure() {} + virtual ~Closure(); + + virtual void Run() = 0; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Closure); +}; + +namespace internal { + +class LIBPROTOBUF_EXPORT FunctionClosure0 : public Closure { + public: + typedef void (*FunctionType)(); + + FunctionClosure0(FunctionType function, bool self_deleting) + : function_(function), self_deleting_(self_deleting) {} + ~FunctionClosure0(); + + void Run() { + bool needs_delete = self_deleting_; // read in case callback deletes + function_(); + if (needs_delete) delete this; + } + + private: + FunctionType function_; + bool self_deleting_; +}; + +template +class MethodClosure0 : public Closure { + public: + typedef void (Class::*MethodType)(); + + MethodClosure0(Class* object, MethodType method, bool self_deleting) + : object_(object), method_(method), self_deleting_(self_deleting) {} + ~MethodClosure0() {} + + void Run() { + bool needs_delete = self_deleting_; // read in case callback deletes + (object_->*method_)(); + if (needs_delete) delete this; + } + + private: + Class* object_; + MethodType method_; + bool self_deleting_; +}; + +template +class FunctionClosure1 : public Closure { + public: + typedef void (*FunctionType)(Arg1 arg1); + + FunctionClosure1(FunctionType function, bool self_deleting, + Arg1 arg1) + : function_(function), self_deleting_(self_deleting), + arg1_(arg1) {} + ~FunctionClosure1() {} + + void Run() { + bool needs_delete = self_deleting_; // read in case callback deletes + function_(arg1_); + if (needs_delete) delete this; + } + + private: + FunctionType function_; + bool self_deleting_; + Arg1 arg1_; +}; + +template +class MethodClosure1 : public Closure { + public: + typedef void (Class::*MethodType)(Arg1 arg1); + + MethodClosure1(Class* object, MethodType method, bool self_deleting, + Arg1 arg1) + : object_(object), method_(method), self_deleting_(self_deleting), + arg1_(arg1) {} + ~MethodClosure1() {} + + void Run() { + bool needs_delete = self_deleting_; // read in case callback deletes + (object_->*method_)(arg1_); + if (needs_delete) delete this; + } + + private: + Class* object_; + MethodType method_; + bool self_deleting_; + Arg1 arg1_; +}; + +template +class FunctionClosure2 : public Closure { + public: + typedef void (*FunctionType)(Arg1 arg1, Arg2 arg2); + + FunctionClosure2(FunctionType function, bool self_deleting, + Arg1 arg1, Arg2 arg2) + : function_(function), self_deleting_(self_deleting), + arg1_(arg1), arg2_(arg2) {} + ~FunctionClosure2() {} + + void Run() { + bool needs_delete = self_deleting_; // read in case callback deletes + function_(arg1_, arg2_); + if (needs_delete) delete this; + } + + private: + FunctionType function_; + bool self_deleting_; + Arg1 arg1_; + Arg2 arg2_; +}; + +template +class MethodClosure2 : public Closure { + public: + typedef void (Class::*MethodType)(Arg1 arg1, Arg2 arg2); + + MethodClosure2(Class* object, MethodType method, bool self_deleting, + Arg1 arg1, Arg2 arg2) + : object_(object), method_(method), self_deleting_(self_deleting), + arg1_(arg1), arg2_(arg2) {} + ~MethodClosure2() {} + + void Run() { + bool needs_delete = self_deleting_; // read in case callback deletes + (object_->*method_)(arg1_, arg2_); + if (needs_delete) delete this; + } + + private: + Class* object_; + MethodType method_; + bool self_deleting_; + Arg1 arg1_; + Arg2 arg2_; +}; + +} // namespace internal + +// See Closure. +inline Closure* NewCallback(void (*function)()) { + return new internal::FunctionClosure0(function, true); +} + +// See Closure. +inline Closure* NewPermanentCallback(void (*function)()) { + return new internal::FunctionClosure0(function, false); +} + +// See Closure. +template +inline Closure* NewCallback(Class* object, void (Class::*method)()) { + return new internal::MethodClosure0(object, method, true); +} + +// See Closure. +template +inline Closure* NewPermanentCallback(Class* object, void (Class::*method)()) { + return new internal::MethodClosure0(object, method, false); +} + +// See Closure. +template +inline Closure* NewCallback(void (*function)(Arg1), + Arg1 arg1) { + return new internal::FunctionClosure1(function, true, arg1); +} + +// See Closure. +template +inline Closure* NewPermanentCallback(void (*function)(Arg1), + Arg1 arg1) { + return new internal::FunctionClosure1(function, false, arg1); +} + +// See Closure. +template +inline Closure* NewCallback(Class* object, void (Class::*method)(Arg1), + Arg1 arg1) { + return new internal::MethodClosure1(object, method, true, arg1); +} + +// See Closure. +template +inline Closure* NewPermanentCallback(Class* object, void (Class::*method)(Arg1), + Arg1 arg1) { + return new internal::MethodClosure1(object, method, false, arg1); +} + +// See Closure. +template +inline Closure* NewCallback(void (*function)(Arg1, Arg2), + Arg1 arg1, Arg2 arg2) { + return new internal::FunctionClosure2( + function, true, arg1, arg2); +} + +// See Closure. +template +inline Closure* NewPermanentCallback(void (*function)(Arg1, Arg2), + Arg1 arg1, Arg2 arg2) { + return new internal::FunctionClosure2( + function, false, arg1, arg2); +} + +// See Closure. +template +inline Closure* NewCallback(Class* object, void (Class::*method)(Arg1, Arg2), + Arg1 arg1, Arg2 arg2) { + return new internal::MethodClosure2( + object, method, true, arg1, arg2); +} + +// See Closure. +template +inline Closure* NewPermanentCallback( + Class* object, void (Class::*method)(Arg1, Arg2), + Arg1 arg1, Arg2 arg2) { + return new internal::MethodClosure2( + object, method, false, arg1, arg2); +} + +// A function which does nothing. Useful for creating no-op callbacks, e.g.: +// Closure* nothing = NewCallback(&DoNothing); +void LIBPROTOBUF_EXPORT DoNothing(); + +// =================================================================== +// emulates google3/base/mutex.h + +namespace internal { + +// A Mutex is a non-reentrant (aka non-recursive) mutex. At most one thread T +// may hold a mutex at a given time. If T attempts to Lock() the same Mutex +// while holding it, T will deadlock. +class LIBPROTOBUF_EXPORT Mutex { + public: + // Create a Mutex that is not held by anybody. + Mutex(); + + // Destructor + ~Mutex(); + + // Block if necessary until this Mutex is free, then acquire it exclusively. + void Lock(); + + // Release this Mutex. Caller must hold it exclusively. + void Unlock(); + + // Crash if this Mutex is not held exclusively by this thread. + // May fail to crash when it should; will never crash when it should not. + void AssertHeld(); + + private: + struct Internal; + Internal* mInternal; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Mutex); +}; + +// MutexLock(mu) acquires mu when constructed and releases it when destroyed. +class LIBPROTOBUF_EXPORT MutexLock { + public: + explicit MutexLock(Mutex *mu) : mu_(mu) { this->mu_->Lock(); } + ~MutexLock() { this->mu_->Unlock(); } + private: + Mutex *const mu_; + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MutexLock); +}; + +// TODO(kenton): Implement these? Hard to implement portably. +typedef MutexLock ReaderMutexLock; +typedef MutexLock WriterMutexLock; + +// MutexLockMaybe is like MutexLock, but is a no-op when mu is NULL. +class LIBPROTOBUF_EXPORT MutexLockMaybe { + public: + explicit MutexLockMaybe(Mutex *mu) : + mu_(mu) { if (this->mu_ != NULL) { this->mu_->Lock(); } } + ~MutexLockMaybe() { if (this->mu_ != NULL) { this->mu_->Unlock(); } } + private: + Mutex *const mu_; + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MutexLockMaybe); +}; + +} // namespace internal + +// We made these internal so that they would show up as such in the docs, +// but we don't want to stick "internal::" in front of them everywhere. +using internal::Mutex; +using internal::MutexLock; +using internal::ReaderMutexLock; +using internal::WriterMutexLock; +using internal::MutexLockMaybe; + +// =================================================================== +// from google3/util/utf8/public/unilib.h + +namespace internal { + +// Checks if the buffer contains structurally-valid UTF-8. Implemented in +// structurally_valid.cc. +LIBPROTOBUF_EXPORT bool IsStructurallyValidUTF8(const char* buf, int len); + +} // namespace internal + +// =================================================================== +// from google3/util/endian/endian.h +LIBPROTOBUF_EXPORT uint32 ghtonl(uint32 x); + +// =================================================================== +// Shutdown support. + +// Shut down the entire protocol buffers library, deleting all static-duration +// objects allocated by the library or by generated .pb.cc files. +// +// There are two reasons you might want to call this: +// * You use a draconian definition of "memory leak" in which you expect +// every single malloc() to have a corresponding free(), even for objects +// which live until program exit. +// * You are writing a dynamically-loaded library which needs to clean up +// after itself when the library is unloaded. +// +// It is safe to call this multiple times. However, it is not safe to use +// any other part of the protocol buffers library after +// ShutdownProtobufLibrary() has been called. +LIBPROTOBUF_EXPORT void ShutdownProtobufLibrary(); + +namespace internal { + +// Register a function to be called when ShutdownProtocolBuffers() is called. +LIBPROTOBUF_EXPORT void OnShutdown(void (*func)()); + +} // namespace internal + +#if PROTOBUF_USE_EXCEPTIONS +class FatalException : public std::exception { + public: + FatalException(const char* f, int l, const std::string& m) + : filename_(f), line_(l), message_(m) {} + virtual ~FatalException() throw(); + + virtual const char* what() const throw(); + + const char* filename() const { return filename_; } + int line() const { return line_; } + const std::string& message() const { return message_; } + + private: + const char* filename_; + const int line_; + const std::string message_; +}; +#endif + +// This is at the end of the file instead of the beginning to work around a bug +// in some versions of MSVC. +using namespace std; // Don't do this at home, kids. + +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMMON_H__ diff --git a/include/google/protobuf/stubs/once.h b/include/google/protobuf/stubs/once.h new file mode 100644 index 000000000..7fbc117fe --- /dev/null +++ b/include/google/protobuf/stubs/once.h @@ -0,0 +1,148 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// +// emulates google3/base/once.h +// +// This header is intended to be included only by internal .cc files and +// generated .pb.cc files. Users should not use this directly. +// +// This is basically a portable version of pthread_once(). +// +// This header declares: +// * A type called ProtobufOnceType. +// * A macro GOOGLE_PROTOBUF_DECLARE_ONCE() which declares a variable of type +// ProtobufOnceType. This is the only legal way to declare such a variable. +// The macro may only be used at the global scope (you cannot create local or +// class member variables of this type). +// * A function GoogleOnceInit(ProtobufOnceType* once, void (*init_func)()). +// This function, when invoked multiple times given the same ProtobufOnceType +// object, will invoke init_func on the first call only, and will make sure +// none of the calls return before that first call to init_func has finished. +// * The user can provide a parameter which GoogleOnceInit() forwards to the +// user-provided function when it is called. Usage example: +// int a = 10; +// GoogleOnceInit(&my_once, &MyFunctionExpectingIntArgument, &a); +// * This implementation guarantees that ProtobufOnceType is a POD (i.e. no +// static initializer generated). +// +// This implements a way to perform lazy initialization. It's more efficient +// than using mutexes as no lock is needed if initialization has already +// happened. +// +// Example usage: +// void Init(); +// GOOGLE_PROTOBUF_DECLARE_ONCE(once_init); +// +// // Calls Init() exactly once. +// void InitOnce() { +// GoogleOnceInit(&once_init, &Init); +// } +// +// Note that if GoogleOnceInit() is called before main() has begun, it must +// only be called by the thread that will eventually call main() -- that is, +// the thread that performs dynamic initialization. In general this is a safe +// assumption since people don't usually construct threads before main() starts, +// but it is technically not guaranteed. Unfortunately, Win32 provides no way +// whatsoever to statically-initialize its synchronization primitives, so our +// only choice is to assume that dynamic initialization is single-threaded. + +#ifndef GOOGLE_PROTOBUF_STUBS_ONCE_H__ +#define GOOGLE_PROTOBUF_STUBS_ONCE_H__ + +#include +#include + +namespace google { +namespace protobuf { + +#ifdef GOOGLE_PROTOBUF_NO_THREAD_SAFETY + +typedef bool ProtobufOnceType; + +#define GOOGLE_PROTOBUF_ONCE_INIT false + +inline void GoogleOnceInit(ProtobufOnceType* once, void (*init_func)()) { + if (!*once) { + *once = true; + init_func(); + } +} + +template +inline void GoogleOnceInit(ProtobufOnceType* once, void (*init_func)(Arg), + Arg arg) { + if (!*once) { + *once = true; + init_func(arg); + } +} + +#else + +enum { + ONCE_STATE_UNINITIALIZED = 0, + ONCE_STATE_EXECUTING_CLOSURE = 1, + ONCE_STATE_DONE = 2 +}; + +typedef internal::AtomicWord ProtobufOnceType; + +#define GOOGLE_PROTOBUF_ONCE_INIT ::google::protobuf::ONCE_STATE_UNINITIALIZED + +LIBPROTOBUF_EXPORT +void GoogleOnceInitImpl(ProtobufOnceType* once, Closure* closure); + +inline void GoogleOnceInit(ProtobufOnceType* once, void (*init_func)()) { + if (internal::Acquire_Load(once) != ONCE_STATE_DONE) { + internal::FunctionClosure0 func(init_func, false); + GoogleOnceInitImpl(once, &func); + } +} + +template +inline void GoogleOnceInit(ProtobufOnceType* once, void (*init_func)(Arg*), + Arg* arg) { + if (internal::Acquire_Load(once) != ONCE_STATE_DONE) { + internal::FunctionClosure1 func(init_func, false, arg); + GoogleOnceInitImpl(once, &func); + } +} + +#endif // GOOGLE_PROTOBUF_NO_THREAD_SAFETY + +#define GOOGLE_PROTOBUF_DECLARE_ONCE(NAME) \ + ::google::protobuf::ProtobufOnceType NAME = GOOGLE_PROTOBUF_ONCE_INIT + +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_STUBS_ONCE_H__ diff --git a/include/google/protobuf/stubs/platform_macros.h b/include/google/protobuf/stubs/platform_macros.h new file mode 100644 index 000000000..b1df60e46 --- /dev/null +++ b/include/google/protobuf/stubs/platform_macros.h @@ -0,0 +1,70 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2012 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef GOOGLE_PROTOBUF_PLATFORM_MACROS_H_ +#define GOOGLE_PROTOBUF_PLATFORM_MACROS_H_ + +#include + +// Processor architecture detection. For more info on what's defined, see: +// http://msdn.microsoft.com/en-us/library/b0084kay.aspx +// http://www.agner.org/optimize/calling_conventions.pdf +// or with gcc, run: "echo | gcc -E -dM -" +#if defined(_M_X64) || defined(__x86_64__) +#define GOOGLE_PROTOBUF_ARCH_X64 1 +#define GOOGLE_PROTOBUF_ARCH_64_BIT 1 +#elif defined(_M_IX86) || defined(__i386__) +#define GOOGLE_PROTOBUF_ARCH_IA32 1 +#define GOOGLE_PROTOBUF_ARCH_32_BIT 1 +#elif defined(__QNX__) +#define GOOGLE_PROTOBUF_ARCH_ARM_QNX 1 +#define GOOGLE_PROTOBUF_ARCH_32_BIT 1 +#elif defined(__ARMEL__) +#define GOOGLE_PROTOBUF_ARCH_ARM 1 +#define GOOGLE_PROTOBUF_ARCH_32_BIT 1 +#elif defined(__MIPSEL__) +#define GOOGLE_PROTOBUF_ARCH_MIPS 1 +#define GOOGLE_PROTOBUF_ARCH_32_BIT 1 +#elif defined(__pnacl__) +#define GOOGLE_PROTOBUF_ARCH_32_BIT 1 +#elif defined(__ppc__) +#define GOOGLE_PROTOBUF_ARCH_PPC 1 +#define GOOGLE_PROTOBUF_ARCH_32_BIT 1 +#else +#error Host architecture was not detected as supported by protobuf +#endif + +#if defined(__APPLE__) +#define GOOGLE_PROTOBUF_OS_APPLE +#elif defined(__native_client__) +#define GOOGLE_PROTOBUF_OS_NACL +#endif + +#endif // GOOGLE_PROTOBUF_PLATFORM_MACROS_H_ diff --git a/include/google/protobuf/stubs/template_util.h b/include/google/protobuf/stubs/template_util.h new file mode 100644 index 000000000..4f30ffa3b --- /dev/null +++ b/include/google/protobuf/stubs/template_util.h @@ -0,0 +1,138 @@ +// Copyright 2005 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// ---- +// Author: lar@google.com (Laramie Leavitt) +// +// Template metaprogramming utility functions. +// +// This code is compiled directly on many platforms, including client +// platforms like Windows, Mac, and embedded systems. Before making +// any changes here, make sure that you're not breaking any platforms. +// +// +// The names choosen here reflect those used in tr1 and the boost::mpl +// library, there are similar operations used in the Loki library as +// well. I prefer the boost names for 2 reasons: +// 1. I think that portions of the Boost libraries are more likely to +// be included in the c++ standard. +// 2. It is not impossible that some of the boost libraries will be +// included in our own build in the future. +// Both of these outcomes means that we may be able to directly replace +// some of these with boost equivalents. +// +#ifndef GOOGLE_PROTOBUF_TEMPLATE_UTIL_H_ +#define GOOGLE_PROTOBUF_TEMPLATE_UTIL_H_ + +namespace google { +namespace protobuf { +namespace internal { + +// Types small_ and big_ are guaranteed such that sizeof(small_) < +// sizeof(big_) +typedef char small_; + +struct big_ { + char dummy[2]; +}; + +// Identity metafunction. +template +struct identity_ { + typedef T type; +}; + +// integral_constant, defined in tr1, is a wrapper for an integer +// value. We don't really need this generality; we could get away +// with hardcoding the integer type to bool. We use the fully +// general integer_constant for compatibility with tr1. + +template +struct integral_constant { + static const T value = v; + typedef T value_type; + typedef integral_constant type; +}; + +template const T integral_constant::value; + + +// Abbreviations: true_type and false_type are structs that represent boolean +// true and false values. Also define the boost::mpl versions of those names, +// true_ and false_. +typedef integral_constant true_type; +typedef integral_constant false_type; +typedef true_type true_; +typedef false_type false_; + +// if_ is a templatized conditional statement. +// if_ is a compile time evaluation of cond. +// if_<>::type contains A if cond is true, B otherwise. +template +struct if_{ + typedef A type; +}; + +template +struct if_ { + typedef B type; +}; + + +// type_equals_ is a template type comparator, similar to Loki IsSameType. +// type_equals_::value is true iff "A" is the same type as "B". +// +// New code should prefer base::is_same, defined in base/type_traits.h. +// It is functionally identical, but is_same is the standard spelling. +template +struct type_equals_ : public false_ { +}; + +template +struct type_equals_ : public true_ { +}; + +// and_ is a template && operator. +// and_::value evaluates "A::value && B::value". +template +struct and_ : public integral_constant { +}; + +// or_ is a template || operator. +// or_::value evaluates "A::value || B::value". +template +struct or_ : public integral_constant { +}; + + +} // namespace internal +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_TEMPLATE_UTIL_H_ diff --git a/include/google/protobuf/stubs/type_traits.h b/include/google/protobuf/stubs/type_traits.h new file mode 100644 index 000000000..e41f5e6f6 --- /dev/null +++ b/include/google/protobuf/stubs/type_traits.h @@ -0,0 +1,336 @@ +// Copyright (c) 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// ---- +// Author: Matt Austern +// +// This code is compiled directly on many platforms, including client +// platforms like Windows, Mac, and embedded systems. Before making +// any changes here, make sure that you're not breaking any platforms. +// +// Define a small subset of tr1 type traits. The traits we define are: +// is_integral +// is_floating_point +// is_pointer +// is_enum +// is_reference +// is_pod +// has_trivial_constructor +// has_trivial_copy +// has_trivial_assign +// has_trivial_destructor +// remove_const +// remove_volatile +// remove_cv +// remove_reference +// add_reference +// remove_pointer +// is_same +// is_convertible +// We can add more type traits as required. + +#ifndef GOOGLE_PROTOBUF_TYPE_TRAITS_H_ +#define GOOGLE_PROTOBUF_TYPE_TRAITS_H_ + +#include // For pair + +#include // For true_type and false_type + +namespace google { +namespace protobuf { +namespace internal { + +template struct is_integral; +template struct is_floating_point; +template struct is_pointer; +// MSVC can't compile this correctly, and neither can gcc 3.3.5 (at least) +#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3) +// is_enum uses is_convertible, which is not available on MSVC. +template struct is_enum; +#endif +template struct is_reference; +template struct is_pod; +template struct has_trivial_constructor; +template struct has_trivial_copy; +template struct has_trivial_assign; +template struct has_trivial_destructor; +template struct remove_const; +template struct remove_volatile; +template struct remove_cv; +template struct remove_reference; +template struct add_reference; +template struct remove_pointer; +template struct is_same; +#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3) +template struct is_convertible; +#endif + +// is_integral is false except for the built-in integer types. A +// cv-qualified type is integral if and only if the underlying type is. +template struct is_integral : false_type { }; +template<> struct is_integral : true_type { }; +template<> struct is_integral : true_type { }; +template<> struct is_integral : true_type { }; +template<> struct is_integral : true_type { }; +#if defined(_MSC_VER) +// wchar_t is not by default a distinct type from unsigned short in +// Microsoft C. +// See http://msdn2.microsoft.com/en-us/library/dh8che7s(VS.80).aspx +template<> struct is_integral<__wchar_t> : true_type { }; +#else +template<> struct is_integral : true_type { }; +#endif +template<> struct is_integral : true_type { }; +template<> struct is_integral : true_type { }; +template<> struct is_integral : true_type { }; +template<> struct is_integral : true_type { }; +template<> struct is_integral : true_type { }; +template<> struct is_integral : true_type { }; +#ifdef HAVE_LONG_LONG +template<> struct is_integral : true_type { }; +template<> struct is_integral : true_type { }; +#endif +template struct is_integral : is_integral { }; +template struct is_integral : is_integral { }; +template struct is_integral : is_integral { }; + +// is_floating_point is false except for the built-in floating-point types. +// A cv-qualified type is integral if and only if the underlying type is. +template struct is_floating_point : false_type { }; +template<> struct is_floating_point : true_type { }; +template<> struct is_floating_point : true_type { }; +template<> struct is_floating_point : true_type { }; +template struct is_floating_point + : is_floating_point { }; +template struct is_floating_point + : is_floating_point { }; +template struct is_floating_point + : is_floating_point { }; + +// is_pointer is false except for pointer types. A cv-qualified type (e.g. +// "int* const", as opposed to "int const*") is cv-qualified if and only if +// the underlying type is. +template struct is_pointer : false_type { }; +template struct is_pointer : true_type { }; +template struct is_pointer : is_pointer { }; +template struct is_pointer : is_pointer { }; +template struct is_pointer : is_pointer { }; + +#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3) + +namespace internal { + +template struct is_class_or_union { + template static small_ tester(void (U::*)()); + template static big_ tester(...); + static const bool value = sizeof(tester(0)) == sizeof(small_); +}; + +// is_convertible chokes if the first argument is an array. That's why +// we use add_reference here. +template struct is_enum_impl + : is_convertible::type, int> { }; + +template struct is_enum_impl : false_type { }; + +} // namespace internal + +// Specified by TR1 [4.5.1] primary type categories. + +// Implementation note: +// +// Each type is either void, integral, floating point, array, pointer, +// reference, member object pointer, member function pointer, enum, +// union or class. Out of these, only integral, floating point, reference, +// class and enum types are potentially convertible to int. Therefore, +// if a type is not a reference, integral, floating point or class and +// is convertible to int, it's a enum. Adding cv-qualification to a type +// does not change whether it's an enum. +// +// Is-convertible-to-int check is done only if all other checks pass, +// because it can't be used with some types (e.g. void or classes with +// inaccessible conversion operators). +template struct is_enum + : internal::is_enum_impl< + is_same::value || + is_integral::value || + is_floating_point::value || + is_reference::value || + internal::is_class_or_union::value, + T> { }; + +template struct is_enum : is_enum { }; +template struct is_enum : is_enum { }; +template struct is_enum : is_enum { }; + +#endif + +// is_reference is false except for reference types. +template struct is_reference : false_type {}; +template struct is_reference : true_type {}; + + +// We can't get is_pod right without compiler help, so fail conservatively. +// We will assume it's false except for arithmetic types, enumerations, +// pointers and cv-qualified versions thereof. Note that std::pair +// is not a POD even if T and U are PODs. +template struct is_pod + : integral_constant::value || + is_floating_point::value || +#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3) + // is_enum is not available on MSVC. + is_enum::value || +#endif + is_pointer::value)> { }; +template struct is_pod : is_pod { }; +template struct is_pod : is_pod { }; +template struct is_pod : is_pod { }; + + +// We can't get has_trivial_constructor right without compiler help, so +// fail conservatively. We will assume it's false except for: (1) types +// for which is_pod is true. (2) std::pair of types with trivial +// constructors. (3) array of a type with a trivial constructor. +// (4) const versions thereof. +template struct has_trivial_constructor : is_pod { }; +template struct has_trivial_constructor > + : integral_constant::value && + has_trivial_constructor::value)> { }; +template struct has_trivial_constructor + : has_trivial_constructor { }; +template struct has_trivial_constructor + : has_trivial_constructor { }; + +// We can't get has_trivial_copy right without compiler help, so fail +// conservatively. We will assume it's false except for: (1) types +// for which is_pod is true. (2) std::pair of types with trivial copy +// constructors. (3) array of a type with a trivial copy constructor. +// (4) const versions thereof. +template struct has_trivial_copy : is_pod { }; +template struct has_trivial_copy > + : integral_constant::value && + has_trivial_copy::value)> { }; +template struct has_trivial_copy + : has_trivial_copy { }; +template struct has_trivial_copy : has_trivial_copy { }; + +// We can't get has_trivial_assign right without compiler help, so fail +// conservatively. We will assume it's false except for: (1) types +// for which is_pod is true. (2) std::pair of types with trivial copy +// constructors. (3) array of a type with a trivial assign constructor. +template struct has_trivial_assign : is_pod { }; +template struct has_trivial_assign > + : integral_constant::value && + has_trivial_assign::value)> { }; +template struct has_trivial_assign + : has_trivial_assign { }; + +// We can't get has_trivial_destructor right without compiler help, so +// fail conservatively. We will assume it's false except for: (1) types +// for which is_pod is true. (2) std::pair of types with trivial +// destructors. (3) array of a type with a trivial destructor. +// (4) const versions thereof. +template struct has_trivial_destructor : is_pod { }; +template struct has_trivial_destructor > + : integral_constant::value && + has_trivial_destructor::value)> { }; +template struct has_trivial_destructor + : has_trivial_destructor { }; +template struct has_trivial_destructor + : has_trivial_destructor { }; + +// Specified by TR1 [4.7.1] +template struct remove_const { typedef T type; }; +template struct remove_const { typedef T type; }; +template struct remove_volatile { typedef T type; }; +template struct remove_volatile { typedef T type; }; +template struct remove_cv { + typedef typename remove_const::type>::type type; +}; + + +// Specified by TR1 [4.7.2] Reference modifications. +template struct remove_reference { typedef T type; }; +template struct remove_reference { typedef T type; }; + +template struct add_reference { typedef T& type; }; +template struct add_reference { typedef T& type; }; + +// Specified by TR1 [4.7.4] Pointer modifications. +template struct remove_pointer { typedef T type; }; +template struct remove_pointer { typedef T type; }; +template struct remove_pointer { typedef T type; }; +template struct remove_pointer { typedef T type; }; +template struct remove_pointer { + typedef T type; }; + +// Specified by TR1 [4.6] Relationships between types +template struct is_same : public false_type { }; +template struct is_same : public true_type { }; + +// Specified by TR1 [4.6] Relationships between types +#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3) +namespace internal { + +// This class is an implementation detail for is_convertible, and you +// don't need to know how it works to use is_convertible. For those +// who care: we declare two different functions, one whose argument is +// of type To and one with a variadic argument list. We give them +// return types of different size, so we can use sizeof to trick the +// compiler into telling us which function it would have chosen if we +// had called it with an argument of type From. See Alexandrescu's +// _Modern C++ Design_ for more details on this sort of trick. + +template +struct ConvertHelper { + static small_ Test(To); + static big_ Test(...); + static From Create(); +}; +} // namespace internal + +// Inherits from true_type if From is convertible to To, false_type otherwise. +template +struct is_convertible + : integral_constant::Test( + internal::ConvertHelper::Create())) + == sizeof(small_)> { +}; +#endif + +} // namespace internal +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_TYPE_TRAITS_H_ diff --git a/include/google/protobuf/text_format.h b/include/google/protobuf/text_format.h new file mode 100644 index 000000000..01f3ffb08 --- /dev/null +++ b/include/google/protobuf/text_format.h @@ -0,0 +1,369 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: jschorr@google.com (Joseph Schorr) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// Utilities for printing and parsing protocol messages in a human-readable, +// text-based format. + +#ifndef GOOGLE_PROTOBUF_TEXT_FORMAT_H__ +#define GOOGLE_PROTOBUF_TEXT_FORMAT_H__ + +#include +#include +#include +#include +#include +#include + +namespace google { +namespace protobuf { + +namespace io { + class ErrorCollector; // tokenizer.h +} + +// This class implements protocol buffer text format. Printing and parsing +// protocol messages in text format is useful for debugging and human editing +// of messages. +// +// This class is really a namespace that contains only static methods. +class LIBPROTOBUF_EXPORT TextFormat { + public: + // Outputs a textual representation of the given message to the given + // output stream. + static bool Print(const Message& message, io::ZeroCopyOutputStream* output); + + // Print the fields in an UnknownFieldSet. They are printed by tag number + // only. Embedded messages are heuristically identified by attempting to + // parse them. + static bool PrintUnknownFields(const UnknownFieldSet& unknown_fields, + io::ZeroCopyOutputStream* output); + + // Like Print(), but outputs directly to a string. + static bool PrintToString(const Message& message, string* output); + + // Like PrintUnknownFields(), but outputs directly to a string. + static bool PrintUnknownFieldsToString(const UnknownFieldSet& unknown_fields, + string* output); + + // Outputs a textual representation of the value of the field supplied on + // the message supplied. For non-repeated fields, an index of -1 must + // be supplied. Note that this method will print the default value for a + // field if it is not set. + static void PrintFieldValueToString(const Message& message, + const FieldDescriptor* field, + int index, + string* output); + + // Class for those users which require more fine-grained control over how + // a protobuffer message is printed out. + class LIBPROTOBUF_EXPORT Printer { + public: + Printer(); + ~Printer(); + + // Like TextFormat::Print + bool Print(const Message& message, io::ZeroCopyOutputStream* output) const; + // Like TextFormat::PrintUnknownFields + bool PrintUnknownFields(const UnknownFieldSet& unknown_fields, + io::ZeroCopyOutputStream* output) const; + // Like TextFormat::PrintToString + bool PrintToString(const Message& message, string* output) const; + // Like TextFormat::PrintUnknownFieldsToString + bool PrintUnknownFieldsToString(const UnknownFieldSet& unknown_fields, + string* output) const; + // Like TextFormat::PrintFieldValueToString + void PrintFieldValueToString(const Message& message, + const FieldDescriptor* field, + int index, + string* output) const; + + // Adjust the initial indent level of all output. Each indent level is + // equal to two spaces. + void SetInitialIndentLevel(int indent_level) { + initial_indent_level_ = indent_level; + } + + // If printing in single line mode, then the entire message will be output + // on a single line with no line breaks. + void SetSingleLineMode(bool single_line_mode) { + single_line_mode_ = single_line_mode; + } + + // Set true to print repeated primitives in a format like: + // field_name: [1, 2, 3, 4] + // instead of printing each value on its own line. Short format applies + // only to primitive values -- i.e. everything except strings and + // sub-messages/groups. + void SetUseShortRepeatedPrimitives(bool use_short_repeated_primitives) { + use_short_repeated_primitives_ = use_short_repeated_primitives; + } + + // Set true to output UTF-8 instead of ASCII. The only difference + // is that bytes >= 0x80 in string fields will not be escaped, + // because they are assumed to be part of UTF-8 multi-byte + // sequences. + void SetUseUtf8StringEscaping(bool as_utf8) { + utf8_string_escaping_ = as_utf8; + } + + private: + // Forward declaration of an internal class used to print the text + // output to the OutputStream (see text_format.cc for implementation). + class TextGenerator; + + // Internal Print method, used for writing to the OutputStream via + // the TextGenerator class. + void Print(const Message& message, + TextGenerator& generator) const; + + // Print a single field. + void PrintField(const Message& message, + const Reflection* reflection, + const FieldDescriptor* field, + TextGenerator& generator) const; + + // Print a repeated primitive field in short form. + void PrintShortRepeatedField(const Message& message, + const Reflection* reflection, + const FieldDescriptor* field, + TextGenerator& generator) const; + + // Print the name of a field -- i.e. everything that comes before the + // ':' for a single name/value pair. + void PrintFieldName(const Message& message, + const Reflection* reflection, + const FieldDescriptor* field, + TextGenerator& generator) const; + + // Outputs a textual representation of the value of the field supplied on + // the message supplied or the default value if not set. + void PrintFieldValue(const Message& message, + const Reflection* reflection, + const FieldDescriptor* field, + int index, + TextGenerator& generator) const; + + // Print the fields in an UnknownFieldSet. They are printed by tag number + // only. Embedded messages are heuristically identified by attempting to + // parse them. + void PrintUnknownFields(const UnknownFieldSet& unknown_fields, + TextGenerator& generator) const; + + int initial_indent_level_; + + bool single_line_mode_; + + bool use_short_repeated_primitives_; + + bool utf8_string_escaping_; + }; + + // Parses a text-format protocol message from the given input stream to + // the given message object. This function parses the format written + // by Print(). + static bool Parse(io::ZeroCopyInputStream* input, Message* output); + // Like Parse(), but reads directly from a string. + static bool ParseFromString(const string& input, Message* output); + + // Like Parse(), but the data is merged into the given message, as if + // using Message::MergeFrom(). + static bool Merge(io::ZeroCopyInputStream* input, Message* output); + // Like Merge(), but reads directly from a string. + static bool MergeFromString(const string& input, Message* output); + + // Parse the given text as a single field value and store it into the + // given field of the given message. If the field is a repeated field, + // the new value will be added to the end + static bool ParseFieldValueFromString(const string& input, + const FieldDescriptor* field, + Message* message); + + // Interface that TextFormat::Parser can use to find extensions. + // This class may be extended in the future to find more information + // like fields, etc. + class LIBPROTOBUF_EXPORT Finder { + public: + virtual ~Finder(); + + // Try to find an extension of *message by fully-qualified field + // name. Returns NULL if no extension is known for this name or number. + virtual const FieldDescriptor* FindExtension( + Message* message, + const string& name) const = 0; + }; + + // A location in the parsed text. + struct ParseLocation { + int line; + int column; + + ParseLocation() : line(-1), column(-1) {} + ParseLocation(int line_param, int column_param) + : line(line_param), column(column_param) {} + }; + + // Data structure which is populated with the locations of each field + // value parsed from the text. + class LIBPROTOBUF_EXPORT ParseInfoTree { + public: + ParseInfoTree(); + ~ParseInfoTree(); + + // Returns the parse location for index-th value of the field in the parsed + // text. If none exists, returns a location with line = -1. Index should be + // -1 for not-repeated fields. + ParseLocation GetLocation(const FieldDescriptor* field, int index) const; + + // Returns the parse info tree for the given field, which must be a message + // type. The nested information tree is owned by the root tree and will be + // deleted when it is deleted. + ParseInfoTree* GetTreeForNested(const FieldDescriptor* field, + int index) const; + + private: + // Allow the text format parser to record information into the tree. + friend class TextFormat; + + // Records the starting location of a single value for a field. + void RecordLocation(const FieldDescriptor* field, ParseLocation location); + + // Create and records a nested tree for a nested message field. + ParseInfoTree* CreateNested(const FieldDescriptor* field); + + // Defines the map from the index-th field descriptor to its parse location. + typedef map > LocationMap; + + // Defines the map from the index-th field descriptor to the nested parse + // info tree. + typedef map > NestedMap; + + LocationMap locations_; + NestedMap nested_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ParseInfoTree); + }; + + // For more control over parsing, use this class. + class LIBPROTOBUF_EXPORT Parser { + public: + Parser(); + ~Parser(); + + // Like TextFormat::Parse(). + bool Parse(io::ZeroCopyInputStream* input, Message* output); + // Like TextFormat::ParseFromString(). + bool ParseFromString(const string& input, Message* output); + // Like TextFormat::Merge(). + bool Merge(io::ZeroCopyInputStream* input, Message* output); + // Like TextFormat::MergeFromString(). + bool MergeFromString(const string& input, Message* output); + + // Set where to report parse errors. If NULL (the default), errors will + // be printed to stderr. + void RecordErrorsTo(io::ErrorCollector* error_collector) { + error_collector_ = error_collector; + } + + // Set how parser finds extensions. If NULL (the default), the + // parser will use the standard Reflection object associated with + // the message being parsed. + void SetFinder(Finder* finder) { + finder_ = finder; + } + + // Sets where location information about the parse will be written. If NULL + // (the default), then no location will be written. + void WriteLocationsTo(ParseInfoTree* tree) { + parse_info_tree_ = tree; + } + + // Normally parsing fails if, after parsing, output->IsInitialized() + // returns false. Call AllowPartialMessage(true) to skip this check. + void AllowPartialMessage(bool allow) { + allow_partial_ = allow; + } + + // Like TextFormat::ParseFieldValueFromString + bool ParseFieldValueFromString(const string& input, + const FieldDescriptor* field, + Message* output); + + + private: + // Forward declaration of an internal class used to parse text + // representations (see text_format.cc for implementation). + class ParserImpl; + + // Like TextFormat::Merge(). The provided implementation is used + // to do the parsing. + bool MergeUsingImpl(io::ZeroCopyInputStream* input, + Message* output, + ParserImpl* parser_impl); + + io::ErrorCollector* error_collector_; + Finder* finder_; + ParseInfoTree* parse_info_tree_; + bool allow_partial_; + bool allow_unknown_field_; + }; + + private: + // Hack: ParseInfoTree declares TextFormat as a friend which should extend + // the friendship to TextFormat::Parser::ParserImpl, but unfortunately some + // old compilers (e.g. GCC 3.4.6) don't implement this correctly. We provide + // helpers for ParserImpl to call methods of ParseInfoTree. + static inline void RecordLocation(ParseInfoTree* info_tree, + const FieldDescriptor* field, + ParseLocation location); + static inline ParseInfoTree* CreateNested(ParseInfoTree* info_tree, + const FieldDescriptor* field); + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(TextFormat); +}; + +inline void TextFormat::RecordLocation(ParseInfoTree* info_tree, + const FieldDescriptor* field, + ParseLocation location) { + info_tree->RecordLocation(field, location); +} + +inline TextFormat::ParseInfoTree* TextFormat::CreateNested( + ParseInfoTree* info_tree, const FieldDescriptor* field) { + return info_tree->CreateNested(field); +} + +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_TEXT_FORMAT_H__ diff --git a/include/google/protobuf/unknown_field_set.h b/include/google/protobuf/unknown_field_set.h new file mode 100644 index 000000000..825bba83a --- /dev/null +++ b/include/google/protobuf/unknown_field_set.h @@ -0,0 +1,311 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// Contains classes used to keep track of unrecognized fields seen while +// parsing a protocol message. + +#ifndef GOOGLE_PROTOBUF_UNKNOWN_FIELD_SET_H__ +#define GOOGLE_PROTOBUF_UNKNOWN_FIELD_SET_H__ + +#include +#include +#include +#include +// TODO(jasonh): some people seem to rely on protobufs to include this for them! + +namespace google { +namespace protobuf { + namespace io { + class CodedInputStream; // coded_stream.h + class CodedOutputStream; // coded_stream.h + class ZeroCopyInputStream; // zero_copy_stream.h + } + namespace internal { + class WireFormat; // wire_format.h + class UnknownFieldSetFieldSkipperUsingCord; + // extension_set_heavy.cc + } + +class Message; // message.h +class UnknownField; // below + +// An UnknownFieldSet contains fields that were encountered while parsing a +// message but were not defined by its type. Keeping track of these can be +// useful, especially in that they may be written if the message is serialized +// again without being cleared in between. This means that software which +// simply receives messages and forwards them to other servers does not need +// to be updated every time a new field is added to the message definition. +// +// To get the UnknownFieldSet attached to any message, call +// Reflection::GetUnknownFields(). +// +// This class is necessarily tied to the protocol buffer wire format, unlike +// the Reflection interface which is independent of any serialization scheme. +class LIBPROTOBUF_EXPORT UnknownFieldSet { + public: + UnknownFieldSet(); + ~UnknownFieldSet(); + + // Remove all fields. + inline void Clear(); + + // Remove all fields and deallocate internal data objects + void ClearAndFreeMemory(); + + // Is this set empty? + inline bool empty() const; + + // Merge the contents of some other UnknownFieldSet with this one. + void MergeFrom(const UnknownFieldSet& other); + + // Swaps the contents of some other UnknownFieldSet with this one. + inline void Swap(UnknownFieldSet* x); + + // Computes (an estimate of) the total number of bytes currently used for + // storing the unknown fields in memory. Does NOT include + // sizeof(*this) in the calculation. + int SpaceUsedExcludingSelf() const; + + // Version of SpaceUsed() including sizeof(*this). + int SpaceUsed() const; + + // Returns the number of fields present in the UnknownFieldSet. + inline int field_count() const; + // Get a field in the set, where 0 <= index < field_count(). The fields + // appear in the order in which they were added. + inline const UnknownField& field(int index) const; + // Get a mutable pointer to a field in the set, where + // 0 <= index < field_count(). The fields appear in the order in which + // they were added. + inline UnknownField* mutable_field(int index); + + // Adding fields --------------------------------------------------- + + void AddVarint(int number, uint64 value); + void AddFixed32(int number, uint32 value); + void AddFixed64(int number, uint64 value); + void AddLengthDelimited(int number, const string& value); + string* AddLengthDelimited(int number); + UnknownFieldSet* AddGroup(int number); + + // Adds an unknown field from another set. + void AddField(const UnknownField& field); + + // Delete fields with indices in the range [start .. start+num-1]. + // Caution: implementation moves all fields with indices [start+num .. ]. + void DeleteSubrange(int start, int num); + + // Delete all fields with a specific field number. The order of left fields + // is preserved. + // Caution: implementation moves all fields after the first deleted field. + void DeleteByNumber(int number); + + // Parsing helpers ------------------------------------------------- + // These work exactly like the similarly-named methods of Message. + + bool MergeFromCodedStream(io::CodedInputStream* input); + bool ParseFromCodedStream(io::CodedInputStream* input); + bool ParseFromZeroCopyStream(io::ZeroCopyInputStream* input); + bool ParseFromArray(const void* data, int size); + inline bool ParseFromString(const string& data) { + return ParseFromArray(data.data(), data.size()); + } + + private: + + void ClearFallback(); + + vector* fields_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(UnknownFieldSet); +}; + +// Represents one field in an UnknownFieldSet. +class LIBPROTOBUF_EXPORT UnknownField { + public: + enum Type { + TYPE_VARINT, + TYPE_FIXED32, + TYPE_FIXED64, + TYPE_LENGTH_DELIMITED, + TYPE_GROUP + }; + + // The field's tag number, as seen on the wire. + inline int number() const; + + // The field type. + inline Type type() const; + + // Accessors ------------------------------------------------------- + // Each method works only for UnknownFields of the corresponding type. + + inline uint64 varint() const; + inline uint32 fixed32() const; + inline uint64 fixed64() const; + inline const string& length_delimited() const; + inline const UnknownFieldSet& group() const; + + inline void set_varint(uint64 value); + inline void set_fixed32(uint32 value); + inline void set_fixed64(uint64 value); + inline void set_length_delimited(const string& value); + inline string* mutable_length_delimited(); + inline UnknownFieldSet* mutable_group(); + + // Serialization API. + // These methods can take advantage of the underlying implementation and may + // archieve a better performance than using getters to retrieve the data and + // do the serialization yourself. + void SerializeLengthDelimitedNoTag(io::CodedOutputStream* output) const; + uint8* SerializeLengthDelimitedNoTagToArray(uint8* target) const; + + inline int GetLengthDelimitedSize() const; + + private: + friend class UnknownFieldSet; + + // If this UnknownField contains a pointer, delete it. + void Delete(); + + // Make a deep copy of any pointers in this UnknownField. + void DeepCopy(); + + + unsigned int number_ : 29; + unsigned int type_ : 3; + union { + uint64 varint_; + uint32 fixed32_; + uint64 fixed64_; + mutable union { + string* string_value_; + } length_delimited_; + UnknownFieldSet* group_; + }; +}; + +// =================================================================== +// inline implementations + +inline void UnknownFieldSet::Clear() { + if (fields_ != NULL) { + ClearFallback(); + } +} + +inline bool UnknownFieldSet::empty() const { + return fields_ == NULL || fields_->empty(); +} + +inline void UnknownFieldSet::Swap(UnknownFieldSet* x) { + std::swap(fields_, x->fields_); +} + +inline int UnknownFieldSet::field_count() const { + return (fields_ == NULL) ? 0 : fields_->size(); +} +inline const UnknownField& UnknownFieldSet::field(int index) const { + return (*fields_)[index]; +} +inline UnknownField* UnknownFieldSet::mutable_field(int index) { + return &(*fields_)[index]; +} + +inline void UnknownFieldSet::AddLengthDelimited( + int number, const string& value) { + AddLengthDelimited(number)->assign(value); +} + + +inline int UnknownField::number() const { return number_; } +inline UnknownField::Type UnknownField::type() const { + return static_cast(type_); +} + +inline uint64 UnknownField::varint () const { + assert(type_ == TYPE_VARINT); + return varint_; +} +inline uint32 UnknownField::fixed32() const { + assert(type_ == TYPE_FIXED32); + return fixed32_; +} +inline uint64 UnknownField::fixed64() const { + assert(type_ == TYPE_FIXED64); + return fixed64_; +} +inline const string& UnknownField::length_delimited() const { + assert(type_ == TYPE_LENGTH_DELIMITED); + return *length_delimited_.string_value_; +} +inline const UnknownFieldSet& UnknownField::group() const { + assert(type_ == TYPE_GROUP); + return *group_; +} + +inline void UnknownField::set_varint(uint64 value) { + assert(type_ == TYPE_VARINT); + varint_ = value; +} +inline void UnknownField::set_fixed32(uint32 value) { + assert(type_ == TYPE_FIXED32); + fixed32_ = value; +} +inline void UnknownField::set_fixed64(uint64 value) { + assert(type_ == TYPE_FIXED64); + fixed64_ = value; +} +inline void UnknownField::set_length_delimited(const string& value) { + assert(type_ == TYPE_LENGTH_DELIMITED); + length_delimited_.string_value_->assign(value); +} +inline string* UnknownField::mutable_length_delimited() { + assert(type_ == TYPE_LENGTH_DELIMITED); + return length_delimited_.string_value_; +} +inline UnknownFieldSet* UnknownField::mutable_group() { + assert(type_ == TYPE_GROUP); + return group_; +} + +inline int UnknownField::GetLengthDelimitedSize() const { + GOOGLE_DCHECK_EQ(TYPE_LENGTH_DELIMITED, type_); + return length_delimited_.string_value_->size(); +} + +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_UNKNOWN_FIELD_SET_H__ diff --git a/include/google/protobuf/wire_format.h b/include/google/protobuf/wire_format.h new file mode 100644 index 000000000..6cc900299 --- /dev/null +++ b/include/google/protobuf/wire_format.h @@ -0,0 +1,308 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// atenasio@google.com (Chris Atenasio) (ZigZag transform) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// This header is logically internal, but is made public because it is used +// from protocol-compiler-generated code, which may reside in other components. + +#ifndef GOOGLE_PROTOBUF_WIRE_FORMAT_H__ +#define GOOGLE_PROTOBUF_WIRE_FORMAT_H__ + +#include +#include +#include +#include +#include +#include + +// Do UTF-8 validation on string type in Debug build only +#ifndef NDEBUG +#define GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED +#endif + +namespace google { +namespace protobuf { + namespace io { + class CodedInputStream; // coded_stream.h + class CodedOutputStream; // coded_stream.h + } + class UnknownFieldSet; // unknown_field_set.h +} + +namespace protobuf { +namespace internal { + +// This class is for internal use by the protocol buffer library and by +// protocol-complier-generated message classes. It must not be called +// directly by clients. +// +// This class contains code for implementing the binary protocol buffer +// wire format via reflection. The WireFormatLite class implements the +// non-reflection based routines. +// +// This class is really a namespace that contains only static methods +class LIBPROTOBUF_EXPORT WireFormat { + public: + + // Given a field return its WireType + static inline WireFormatLite::WireType WireTypeForField( + const FieldDescriptor* field); + + // Given a FieldSescriptor::Type return its WireType + static inline WireFormatLite::WireType WireTypeForFieldType( + FieldDescriptor::Type type); + + // Compute the byte size of a tag. For groups, this includes both the start + // and end tags. + static inline int TagSize(int field_number, FieldDescriptor::Type type); + + // These procedures can be used to implement the methods of Message which + // handle parsing and serialization of the protocol buffer wire format + // using only the Reflection interface. When you ask the protocol + // compiler to optimize for code size rather than speed, it will implement + // those methods in terms of these procedures. Of course, these are much + // slower than the specialized implementations which the protocol compiler + // generates when told to optimize for speed. + + // Read a message in protocol buffer wire format. + // + // This procedure reads either to the end of the input stream or through + // a WIRETYPE_END_GROUP tag ending the message, whichever comes first. + // It returns false if the input is invalid. + // + // Required fields are NOT checked by this method. You must call + // IsInitialized() on the resulting message yourself. + static bool ParseAndMergePartial(io::CodedInputStream* input, + Message* message); + + // Serialize a message in protocol buffer wire format. + // + // Any embedded messages within the message must have their correct sizes + // cached. However, the top-level message need not; its size is passed as + // a parameter to this procedure. + // + // These return false iff the underlying stream returns a write error. + static void SerializeWithCachedSizes( + const Message& message, + int size, io::CodedOutputStream* output); + + // Implements Message::ByteSize() via reflection. WARNING: The result + // of this method is *not* cached anywhere. However, all embedded messages + // will have their ByteSize() methods called, so their sizes will be cached. + // Therefore, calling this method is sufficient to allow you to call + // WireFormat::SerializeWithCachedSizes() on the same object. + static int ByteSize(const Message& message); + + // ----------------------------------------------------------------- + // Helpers for dealing with unknown fields + + // Skips a field value of the given WireType. The input should start + // positioned immediately after the tag. If unknown_fields is non-NULL, + // the contents of the field will be added to it. + static bool SkipField(io::CodedInputStream* input, uint32 tag, + UnknownFieldSet* unknown_fields); + + // Reads and ignores a message from the input. If unknown_fields is non-NULL, + // the contents will be added to it. + static bool SkipMessage(io::CodedInputStream* input, + UnknownFieldSet* unknown_fields); + + // Write the contents of an UnknownFieldSet to the output. + static void SerializeUnknownFields(const UnknownFieldSet& unknown_fields, + io::CodedOutputStream* output); + // Same as above, except writing directly to the provided buffer. + // Requires that the buffer have sufficient capacity for + // ComputeUnknownFieldsSize(unknown_fields). + // + // Returns a pointer past the last written byte. + static uint8* SerializeUnknownFieldsToArray( + const UnknownFieldSet& unknown_fields, + uint8* target); + + // Same thing except for messages that have the message_set_wire_format + // option. + static void SerializeUnknownMessageSetItems( + const UnknownFieldSet& unknown_fields, + io::CodedOutputStream* output); + // Same as above, except writing directly to the provided buffer. + // Requires that the buffer have sufficient capacity for + // ComputeUnknownMessageSetItemsSize(unknown_fields). + // + // Returns a pointer past the last written byte. + static uint8* SerializeUnknownMessageSetItemsToArray( + const UnknownFieldSet& unknown_fields, + uint8* target); + + // Compute the size of the UnknownFieldSet on the wire. + static int ComputeUnknownFieldsSize(const UnknownFieldSet& unknown_fields); + + // Same thing except for messages that have the message_set_wire_format + // option. + static int ComputeUnknownMessageSetItemsSize( + const UnknownFieldSet& unknown_fields); + + + // Helper functions for encoding and decoding tags. (Inlined below and in + // _inl.h) + // + // This is different from MakeTag(field->number(), field->type()) in the case + // of packed repeated fields. + static uint32 MakeTag(const FieldDescriptor* field); + + // Parse a single field. The input should start out positioned immidately + // after the tag. + static bool ParseAndMergeField( + uint32 tag, + const FieldDescriptor* field, // May be NULL for unknown + Message* message, + io::CodedInputStream* input); + + // Serialize a single field. + static void SerializeFieldWithCachedSizes( + const FieldDescriptor* field, // Cannot be NULL + const Message& message, + io::CodedOutputStream* output); + + // Compute size of a single field. If the field is a message type, this + // will call ByteSize() for the embedded message, insuring that it caches + // its size. + static int FieldByteSize( + const FieldDescriptor* field, // Cannot be NULL + const Message& message); + + // Parse/serialize a MessageSet::Item group. Used with messages that use + // opion message_set_wire_format = true. + static bool ParseAndMergeMessageSetItem( + io::CodedInputStream* input, + Message* message); + static void SerializeMessageSetItemWithCachedSizes( + const FieldDescriptor* field, + const Message& message, + io::CodedOutputStream* output); + static int MessageSetItemByteSize( + const FieldDescriptor* field, + const Message& message); + + // Computes the byte size of a field, excluding tags. For packed fields, it + // only includes the size of the raw data, and not the size of the total + // length, but for other length-delimited types, the size of the length is + // included. + static int FieldDataOnlyByteSize( + const FieldDescriptor* field, // Cannot be NULL + const Message& message); + + enum Operation { + PARSE, + SERIALIZE, + }; + + // Verifies that a string field is valid UTF8, logging an error if not. + static void VerifyUTF8String(const char* data, int size, Operation op); + + private: + // Verifies that a string field is valid UTF8, logging an error if not. + static void VerifyUTF8StringFallback( + const char* data, + int size, + Operation op); + + + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(WireFormat); +}; + +// Subclass of FieldSkipper which saves skipped fields to an UnknownFieldSet. +class LIBPROTOBUF_EXPORT UnknownFieldSetFieldSkipper : public FieldSkipper { + public: + UnknownFieldSetFieldSkipper(UnknownFieldSet* unknown_fields) + : unknown_fields_(unknown_fields) {} + virtual ~UnknownFieldSetFieldSkipper() {} + + // implements FieldSkipper ----------------------------------------- + virtual bool SkipField(io::CodedInputStream* input, uint32 tag); + virtual bool SkipMessage(io::CodedInputStream* input); + virtual void SkipUnknownEnum(int field_number, int value); + + protected: + UnknownFieldSet* unknown_fields_; +}; + +// inline methods ==================================================== + +inline WireFormatLite::WireType WireFormat::WireTypeForField( + const FieldDescriptor* field) { + if (field->options().packed()) { + return WireFormatLite::WIRETYPE_LENGTH_DELIMITED; + } else { + return WireTypeForFieldType(field->type()); + } +} + +inline WireFormatLite::WireType WireFormat::WireTypeForFieldType( + FieldDescriptor::Type type) { + // Some compilers don't like enum -> enum casts, so we implicit_cast to + // int first. + return WireFormatLite::WireTypeForFieldType( + static_cast( + implicit_cast(type))); +} + +inline uint32 WireFormat::MakeTag(const FieldDescriptor* field) { + return WireFormatLite::MakeTag(field->number(), WireTypeForField(field)); +} + +inline int WireFormat::TagSize(int field_number, FieldDescriptor::Type type) { + // Some compilers don't like enum -> enum casts, so we implicit_cast to + // int first. + return WireFormatLite::TagSize(field_number, + static_cast( + implicit_cast(type))); +} + +inline void WireFormat::VerifyUTF8String(const char* data, int size, + WireFormat::Operation op) { +#ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED + WireFormat::VerifyUTF8StringFallback(data, size, op); +#else + // Avoid the compiler warning about unsued variables. + (void)data; (void)size; (void)op; +#endif +} + + +} // namespace internal +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_WIRE_FORMAT_H__ diff --git a/include/google/protobuf/wire_format_lite.h b/include/google/protobuf/wire_format_lite.h new file mode 100644 index 000000000..cb4fc918b --- /dev/null +++ b/include/google/protobuf/wire_format_lite.h @@ -0,0 +1,622 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// atenasio@google.com (Chris Atenasio) (ZigZag transform) +// wink@google.com (Wink Saville) (refactored from wire_format.h) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// This header is logically internal, but is made public because it is used +// from protocol-compiler-generated code, which may reside in other components. + +#ifndef GOOGLE_PROTOBUF_WIRE_FORMAT_LITE_H__ +#define GOOGLE_PROTOBUF_WIRE_FORMAT_LITE_H__ + +#include +#include +#include +#include // for CodedOutputStream::Varint32Size + +namespace google { + +namespace protobuf { + template class RepeatedField; // repeated_field.h +} + +namespace protobuf { +namespace internal { + +class StringPieceField; + +// This class is for internal use by the protocol buffer library and by +// protocol-complier-generated message classes. It must not be called +// directly by clients. +// +// This class contains helpers for implementing the binary protocol buffer +// wire format without the need for reflection. Use WireFormat when using +// reflection. +// +// This class is really a namespace that contains only static methods. +class LIBPROTOBUF_EXPORT WireFormatLite { + public: + + // ----------------------------------------------------------------- + // Helper constants and functions related to the format. These are + // mostly meant for internal and generated code to use. + + // The wire format is composed of a sequence of tag/value pairs, each + // of which contains the value of one field (or one element of a repeated + // field). Each tag is encoded as a varint. The lower bits of the tag + // identify its wire type, which specifies the format of the data to follow. + // The rest of the bits contain the field number. Each type of field (as + // declared by FieldDescriptor::Type, in descriptor.h) maps to one of + // these wire types. Immediately following each tag is the field's value, + // encoded in the format specified by the wire type. Because the tag + // identifies the encoding of this data, it is possible to skip + // unrecognized fields for forwards compatibility. + + enum WireType { + WIRETYPE_VARINT = 0, + WIRETYPE_FIXED64 = 1, + WIRETYPE_LENGTH_DELIMITED = 2, + WIRETYPE_START_GROUP = 3, + WIRETYPE_END_GROUP = 4, + WIRETYPE_FIXED32 = 5, + }; + + // Lite alternative to FieldDescriptor::Type. Must be kept in sync. + enum FieldType { + TYPE_DOUBLE = 1, + TYPE_FLOAT = 2, + TYPE_INT64 = 3, + TYPE_UINT64 = 4, + TYPE_INT32 = 5, + TYPE_FIXED64 = 6, + TYPE_FIXED32 = 7, + TYPE_BOOL = 8, + TYPE_STRING = 9, + TYPE_GROUP = 10, + TYPE_MESSAGE = 11, + TYPE_BYTES = 12, + TYPE_UINT32 = 13, + TYPE_ENUM = 14, + TYPE_SFIXED32 = 15, + TYPE_SFIXED64 = 16, + TYPE_SINT32 = 17, + TYPE_SINT64 = 18, + MAX_FIELD_TYPE = 18, + }; + + // Lite alternative to FieldDescriptor::CppType. Must be kept in sync. + enum CppType { + CPPTYPE_INT32 = 1, + CPPTYPE_INT64 = 2, + CPPTYPE_UINT32 = 3, + CPPTYPE_UINT64 = 4, + CPPTYPE_DOUBLE = 5, + CPPTYPE_FLOAT = 6, + CPPTYPE_BOOL = 7, + CPPTYPE_ENUM = 8, + CPPTYPE_STRING = 9, + CPPTYPE_MESSAGE = 10, + MAX_CPPTYPE = 10, + }; + + // Helper method to get the CppType for a particular Type. + static CppType FieldTypeToCppType(FieldType type); + + // Given a FieldSescriptor::Type return its WireType + static inline WireFormatLite::WireType WireTypeForFieldType( + WireFormatLite::FieldType type) { + return kWireTypeForFieldType[type]; + } + + // Number of bits in a tag which identify the wire type. + static const int kTagTypeBits = 3; + // Mask for those bits. + static const uint32 kTagTypeMask = (1 << kTagTypeBits) - 1; + + // Helper functions for encoding and decoding tags. (Inlined below and in + // _inl.h) + // + // This is different from MakeTag(field->number(), field->type()) in the case + // of packed repeated fields. + static uint32 MakeTag(int field_number, WireType type); + static WireType GetTagWireType(uint32 tag); + static int GetTagFieldNumber(uint32 tag); + + // Compute the byte size of a tag. For groups, this includes both the start + // and end tags. + static inline int TagSize(int field_number, WireFormatLite::FieldType type); + + // Skips a field value with the given tag. The input should start + // positioned immediately after the tag. Skipped values are simply discarded, + // not recorded anywhere. See WireFormat::SkipField() for a version that + // records to an UnknownFieldSet. + static bool SkipField(io::CodedInputStream* input, uint32 tag); + + // Reads and ignores a message from the input. Skipped values are simply + // discarded, not recorded anywhere. See WireFormat::SkipMessage() for a + // version that records to an UnknownFieldSet. + static bool SkipMessage(io::CodedInputStream* input); + +// This macro does the same thing as WireFormatLite::MakeTag(), but the +// result is usable as a compile-time constant, which makes it usable +// as a switch case or a template input. WireFormatLite::MakeTag() is more +// type-safe, though, so prefer it if possible. +#define GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(FIELD_NUMBER, TYPE) \ + static_cast( \ + ((FIELD_NUMBER) << ::google::protobuf::internal::WireFormatLite::kTagTypeBits) \ + | (TYPE)) + + // These are the tags for the old MessageSet format, which was defined as: + // message MessageSet { + // repeated group Item = 1 { + // required int32 type_id = 2; + // required string message = 3; + // } + // } + static const int kMessageSetItemNumber = 1; + static const int kMessageSetTypeIdNumber = 2; + static const int kMessageSetMessageNumber = 3; + static const int kMessageSetItemStartTag = + GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(kMessageSetItemNumber, + WireFormatLite::WIRETYPE_START_GROUP); + static const int kMessageSetItemEndTag = + GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(kMessageSetItemNumber, + WireFormatLite::WIRETYPE_END_GROUP); + static const int kMessageSetTypeIdTag = + GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(kMessageSetTypeIdNumber, + WireFormatLite::WIRETYPE_VARINT); + static const int kMessageSetMessageTag = + GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(kMessageSetMessageNumber, + WireFormatLite::WIRETYPE_LENGTH_DELIMITED); + + // Byte size of all tags of a MessageSet::Item combined. + static const int kMessageSetItemTagsSize; + + // Helper functions for converting between floats/doubles and IEEE-754 + // uint32s/uint64s so that they can be written. (Assumes your platform + // uses IEEE-754 floats.) + static uint32 EncodeFloat(float value); + static float DecodeFloat(uint32 value); + static uint64 EncodeDouble(double value); + static double DecodeDouble(uint64 value); + + // Helper functions for mapping signed integers to unsigned integers in + // such a way that numbers with small magnitudes will encode to smaller + // varints. If you simply static_cast a negative number to an unsigned + // number and varint-encode it, it will always take 10 bytes, defeating + // the purpose of varint. So, for the "sint32" and "sint64" field types, + // we ZigZag-encode the values. + static uint32 ZigZagEncode32(int32 n); + static int32 ZigZagDecode32(uint32 n); + static uint64 ZigZagEncode64(int64 n); + static int64 ZigZagDecode64(uint64 n); + + // ================================================================= + // Methods for reading/writing individual field. The implementations + // of these methods are defined in wire_format_lite_inl.h; you must #include + // that file to use these. + +// Avoid ugly line wrapping +#define input io::CodedInputStream* input +#define output io::CodedOutputStream* output +#define field_number int field_number +#define INL GOOGLE_ATTRIBUTE_ALWAYS_INLINE + + // Read fields, not including tags. The assumption is that you already + // read the tag to determine what field to read. + + // For primitive fields, we just use a templatized routine parameterized by + // the represented type and the FieldType. These are specialized with the + // appropriate definition for each declared type. + template + static inline bool ReadPrimitive(input, CType* value) INL; + + // Reads repeated primitive values, with optimizations for repeats. + // tag_size and tag should both be compile-time constants provided by the + // protocol compiler. + template + static inline bool ReadRepeatedPrimitive(int tag_size, + uint32 tag, + input, + RepeatedField* value) INL; + + // Identical to ReadRepeatedPrimitive, except will not inline the + // implementation. + template + static bool ReadRepeatedPrimitiveNoInline(int tag_size, + uint32 tag, + input, + RepeatedField* value); + + // Reads a primitive value directly from the provided buffer. It returns a + // pointer past the segment of data that was read. + // + // This is only implemented for the types with fixed wire size, e.g. + // float, double, and the (s)fixed* types. + template + static inline const uint8* ReadPrimitiveFromArray(const uint8* buffer, + CType* value) INL; + + // Reads a primitive packed field. + // + // This is only implemented for packable types. + template + static inline bool ReadPackedPrimitive(input, + RepeatedField* value) INL; + + // Identical to ReadPackedPrimitive, except will not inline the + // implementation. + template + static bool ReadPackedPrimitiveNoInline(input, RepeatedField* value); + + // Read a packed enum field. Values for which is_valid() returns false are + // dropped. + static bool ReadPackedEnumNoInline(input, + bool (*is_valid)(int), + RepeatedField* value); + + static bool ReadString(input, string* value); + static bool ReadBytes (input, string* value); + + static inline bool ReadGroup (field_number, input, MessageLite* value); + static inline bool ReadMessage(input, MessageLite* value); + + // Like above, but de-virtualize the call to MergePartialFromCodedStream(). + // The pointer must point at an instance of MessageType, *not* a subclass (or + // the subclass must not override MergePartialFromCodedStream()). + template + static inline bool ReadGroupNoVirtual(field_number, input, + MessageType* value); + template + static inline bool ReadMessageNoVirtual(input, MessageType* value); + + // Write a tag. The Write*() functions typically include the tag, so + // normally there's no need to call this unless using the Write*NoTag() + // variants. + static inline void WriteTag(field_number, WireType type, output) INL; + + // Write fields, without tags. + static inline void WriteInt32NoTag (int32 value, output) INL; + static inline void WriteInt64NoTag (int64 value, output) INL; + static inline void WriteUInt32NoTag (uint32 value, output) INL; + static inline void WriteUInt64NoTag (uint64 value, output) INL; + static inline void WriteSInt32NoTag (int32 value, output) INL; + static inline void WriteSInt64NoTag (int64 value, output) INL; + static inline void WriteFixed32NoTag (uint32 value, output) INL; + static inline void WriteFixed64NoTag (uint64 value, output) INL; + static inline void WriteSFixed32NoTag(int32 value, output) INL; + static inline void WriteSFixed64NoTag(int64 value, output) INL; + static inline void WriteFloatNoTag (float value, output) INL; + static inline void WriteDoubleNoTag (double value, output) INL; + static inline void WriteBoolNoTag (bool value, output) INL; + static inline void WriteEnumNoTag (int value, output) INL; + + // Write fields, including tags. + static void WriteInt32 (field_number, int32 value, output); + static void WriteInt64 (field_number, int64 value, output); + static void WriteUInt32 (field_number, uint32 value, output); + static void WriteUInt64 (field_number, uint64 value, output); + static void WriteSInt32 (field_number, int32 value, output); + static void WriteSInt64 (field_number, int64 value, output); + static void WriteFixed32 (field_number, uint32 value, output); + static void WriteFixed64 (field_number, uint64 value, output); + static void WriteSFixed32(field_number, int32 value, output); + static void WriteSFixed64(field_number, int64 value, output); + static void WriteFloat (field_number, float value, output); + static void WriteDouble (field_number, double value, output); + static void WriteBool (field_number, bool value, output); + static void WriteEnum (field_number, int value, output); + + static void WriteString(field_number, const string& value, output); + static void WriteBytes (field_number, const string& value, output); + + static void WriteGroup( + field_number, const MessageLite& value, output); + static void WriteMessage( + field_number, const MessageLite& value, output); + // Like above, but these will check if the output stream has enough + // space to write directly to a flat array. + static void WriteGroupMaybeToArray( + field_number, const MessageLite& value, output); + static void WriteMessageMaybeToArray( + field_number, const MessageLite& value, output); + + // Like above, but de-virtualize the call to SerializeWithCachedSizes(). The + // pointer must point at an instance of MessageType, *not* a subclass (or + // the subclass must not override SerializeWithCachedSizes()). + template + static inline void WriteGroupNoVirtual( + field_number, const MessageType& value, output); + template + static inline void WriteMessageNoVirtual( + field_number, const MessageType& value, output); + +#undef output +#define output uint8* target + + // Like above, but use only *ToArray methods of CodedOutputStream. + static inline uint8* WriteTagToArray(field_number, WireType type, output) INL; + + // Write fields, without tags. + static inline uint8* WriteInt32NoTagToArray (int32 value, output) INL; + static inline uint8* WriteInt64NoTagToArray (int64 value, output) INL; + static inline uint8* WriteUInt32NoTagToArray (uint32 value, output) INL; + static inline uint8* WriteUInt64NoTagToArray (uint64 value, output) INL; + static inline uint8* WriteSInt32NoTagToArray (int32 value, output) INL; + static inline uint8* WriteSInt64NoTagToArray (int64 value, output) INL; + static inline uint8* WriteFixed32NoTagToArray (uint32 value, output) INL; + static inline uint8* WriteFixed64NoTagToArray (uint64 value, output) INL; + static inline uint8* WriteSFixed32NoTagToArray(int32 value, output) INL; + static inline uint8* WriteSFixed64NoTagToArray(int64 value, output) INL; + static inline uint8* WriteFloatNoTagToArray (float value, output) INL; + static inline uint8* WriteDoubleNoTagToArray (double value, output) INL; + static inline uint8* WriteBoolNoTagToArray (bool value, output) INL; + static inline uint8* WriteEnumNoTagToArray (int value, output) INL; + + // Write fields, including tags. + static inline uint8* WriteInt32ToArray( + field_number, int32 value, output) INL; + static inline uint8* WriteInt64ToArray( + field_number, int64 value, output) INL; + static inline uint8* WriteUInt32ToArray( + field_number, uint32 value, output) INL; + static inline uint8* WriteUInt64ToArray( + field_number, uint64 value, output) INL; + static inline uint8* WriteSInt32ToArray( + field_number, int32 value, output) INL; + static inline uint8* WriteSInt64ToArray( + field_number, int64 value, output) INL; + static inline uint8* WriteFixed32ToArray( + field_number, uint32 value, output) INL; + static inline uint8* WriteFixed64ToArray( + field_number, uint64 value, output) INL; + static inline uint8* WriteSFixed32ToArray( + field_number, int32 value, output) INL; + static inline uint8* WriteSFixed64ToArray( + field_number, int64 value, output) INL; + static inline uint8* WriteFloatToArray( + field_number, float value, output) INL; + static inline uint8* WriteDoubleToArray( + field_number, double value, output) INL; + static inline uint8* WriteBoolToArray( + field_number, bool value, output) INL; + static inline uint8* WriteEnumToArray( + field_number, int value, output) INL; + + static inline uint8* WriteStringToArray( + field_number, const string& value, output) INL; + static inline uint8* WriteBytesToArray( + field_number, const string& value, output) INL; + + static inline uint8* WriteGroupToArray( + field_number, const MessageLite& value, output) INL; + static inline uint8* WriteMessageToArray( + field_number, const MessageLite& value, output) INL; + + // Like above, but de-virtualize the call to SerializeWithCachedSizes(). The + // pointer must point at an instance of MessageType, *not* a subclass (or + // the subclass must not override SerializeWithCachedSizes()). + template + static inline uint8* WriteGroupNoVirtualToArray( + field_number, const MessageType& value, output) INL; + template + static inline uint8* WriteMessageNoVirtualToArray( + field_number, const MessageType& value, output) INL; + +#undef output +#undef input +#undef INL + +#undef field_number + + // Compute the byte size of a field. The XxSize() functions do NOT include + // the tag, so you must also call TagSize(). (This is because, for repeated + // fields, you should only call TagSize() once and multiply it by the element + // count, but you may have to call XxSize() for each individual element.) + static inline int Int32Size ( int32 value); + static inline int Int64Size ( int64 value); + static inline int UInt32Size (uint32 value); + static inline int UInt64Size (uint64 value); + static inline int SInt32Size ( int32 value); + static inline int SInt64Size ( int64 value); + static inline int EnumSize ( int value); + + // These types always have the same size. + static const int kFixed32Size = 4; + static const int kFixed64Size = 8; + static const int kSFixed32Size = 4; + static const int kSFixed64Size = 8; + static const int kFloatSize = 4; + static const int kDoubleSize = 8; + static const int kBoolSize = 1; + + static inline int StringSize(const string& value); + static inline int BytesSize (const string& value); + + static inline int GroupSize (const MessageLite& value); + static inline int MessageSize(const MessageLite& value); + + // Like above, but de-virtualize the call to ByteSize(). The + // pointer must point at an instance of MessageType, *not* a subclass (or + // the subclass must not override ByteSize()). + template + static inline int GroupSizeNoVirtual (const MessageType& value); + template + static inline int MessageSizeNoVirtual(const MessageType& value); + + // Given the length of data, calculate the byte size of the data on the + // wire if we encode the data as a length delimited field. + static inline int LengthDelimitedSize(int length); + + private: + // A helper method for the repeated primitive reader. This method has + // optimizations for primitive types that have fixed size on the wire, and + // can be read using potentially faster paths. + template + static inline bool ReadRepeatedFixedSizePrimitive( + int tag_size, + uint32 tag, + google::protobuf::io::CodedInputStream* input, + RepeatedField* value) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + + static const CppType kFieldTypeToCppTypeMap[]; + static const WireFormatLite::WireType kWireTypeForFieldType[]; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(WireFormatLite); +}; + +// A class which deals with unknown values. The default implementation just +// discards them. WireFormat defines a subclass which writes to an +// UnknownFieldSet. This class is used by ExtensionSet::ParseField(), since +// ExtensionSet is part of the lite library but UnknownFieldSet is not. +class LIBPROTOBUF_EXPORT FieldSkipper { + public: + FieldSkipper() {} + virtual ~FieldSkipper() {} + + // Skip a field whose tag has already been consumed. + virtual bool SkipField(io::CodedInputStream* input, uint32 tag); + + // Skip an entire message or group, up to an end-group tag (which is consumed) + // or end-of-stream. + virtual bool SkipMessage(io::CodedInputStream* input); + + // Deal with an already-parsed unrecognized enum value. The default + // implementation does nothing, but the UnknownFieldSet-based implementation + // saves it as an unknown varint. + virtual void SkipUnknownEnum(int field_number, int value); +}; + +// inline methods ==================================================== + +inline WireFormatLite::CppType +WireFormatLite::FieldTypeToCppType(FieldType type) { + return kFieldTypeToCppTypeMap[type]; +} + +inline uint32 WireFormatLite::MakeTag(int field_number, WireType type) { + return GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(field_number, type); +} + +inline WireFormatLite::WireType WireFormatLite::GetTagWireType(uint32 tag) { + return static_cast(tag & kTagTypeMask); +} + +inline int WireFormatLite::GetTagFieldNumber(uint32 tag) { + return static_cast(tag >> kTagTypeBits); +} + +inline int WireFormatLite::TagSize(int field_number, + WireFormatLite::FieldType type) { + int result = io::CodedOutputStream::VarintSize32( + field_number << kTagTypeBits); + if (type == TYPE_GROUP) { + // Groups have both a start and an end tag. + return result * 2; + } else { + return result; + } +} + +inline uint32 WireFormatLite::EncodeFloat(float value) { + union {float f; uint32 i;}; + f = value; + return i; +} + +inline float WireFormatLite::DecodeFloat(uint32 value) { + union {float f; uint32 i;}; + i = value; + return f; +} + +inline uint64 WireFormatLite::EncodeDouble(double value) { + union {double f; uint64 i;}; + f = value; + return i; +} + +inline double WireFormatLite::DecodeDouble(uint64 value) { + union {double f; uint64 i;}; + i = value; + return f; +} + +// ZigZag Transform: Encodes signed integers so that they can be +// effectively used with varint encoding. +// +// varint operates on unsigned integers, encoding smaller numbers into +// fewer bytes. If you try to use it on a signed integer, it will treat +// this number as a very large unsigned integer, which means that even +// small signed numbers like -1 will take the maximum number of bytes +// (10) to encode. ZigZagEncode() maps signed integers to unsigned +// in such a way that those with a small absolute value will have smaller +// encoded values, making them appropriate for encoding using varint. +// +// int32 -> uint32 +// ------------------------- +// 0 -> 0 +// -1 -> 1 +// 1 -> 2 +// -2 -> 3 +// ... -> ... +// 2147483647 -> 4294967294 +// -2147483648 -> 4294967295 +// +// >> encode >> +// << decode << + +inline uint32 WireFormatLite::ZigZagEncode32(int32 n) { + // Note: the right-shift must be arithmetic + return (n << 1) ^ (n >> 31); +} + +inline int32 WireFormatLite::ZigZagDecode32(uint32 n) { + return (n >> 1) ^ -static_cast(n & 1); +} + +inline uint64 WireFormatLite::ZigZagEncode64(int64 n) { + // Note: the right-shift must be arithmetic + return (n << 1) ^ (n >> 63); +} + +inline int64 WireFormatLite::ZigZagDecode64(uint64 n) { + return (n >> 1) ^ -static_cast(n & 1); +} + +} // namespace internal +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_WIRE_FORMAT_LITE_H__ diff --git a/include/google/protobuf/wire_format_lite_inl.h b/include/google/protobuf/wire_format_lite_inl.h new file mode 100644 index 000000000..641cc92f6 --- /dev/null +++ b/include/google/protobuf/wire_format_lite_inl.h @@ -0,0 +1,776 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// wink@google.com (Wink Saville) (refactored from wire_format.h) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_WIRE_FORMAT_LITE_INL_H__ +#define GOOGLE_PROTOBUF_WIRE_FORMAT_LITE_INL_H__ + +#include +#include +#include +#include +#include +#include + + +namespace google { +namespace protobuf { +namespace internal { + +// Implementation details of ReadPrimitive. + +template <> +inline bool WireFormatLite::ReadPrimitive( + io::CodedInputStream* input, + int32* value) { + uint32 temp; + if (!input->ReadVarint32(&temp)) return false; + *value = static_cast(temp); + return true; +} +template <> +inline bool WireFormatLite::ReadPrimitive( + io::CodedInputStream* input, + int64* value) { + uint64 temp; + if (!input->ReadVarint64(&temp)) return false; + *value = static_cast(temp); + return true; +} +template <> +inline bool WireFormatLite::ReadPrimitive( + io::CodedInputStream* input, + uint32* value) { + return input->ReadVarint32(value); +} +template <> +inline bool WireFormatLite::ReadPrimitive( + io::CodedInputStream* input, + uint64* value) { + return input->ReadVarint64(value); +} +template <> +inline bool WireFormatLite::ReadPrimitive( + io::CodedInputStream* input, + int32* value) { + uint32 temp; + if (!input->ReadVarint32(&temp)) return false; + *value = ZigZagDecode32(temp); + return true; +} +template <> +inline bool WireFormatLite::ReadPrimitive( + io::CodedInputStream* input, + int64* value) { + uint64 temp; + if (!input->ReadVarint64(&temp)) return false; + *value = ZigZagDecode64(temp); + return true; +} +template <> +inline bool WireFormatLite::ReadPrimitive( + io::CodedInputStream* input, + uint32* value) { + return input->ReadLittleEndian32(value); +} +template <> +inline bool WireFormatLite::ReadPrimitive( + io::CodedInputStream* input, + uint64* value) { + return input->ReadLittleEndian64(value); +} +template <> +inline bool WireFormatLite::ReadPrimitive( + io::CodedInputStream* input, + int32* value) { + uint32 temp; + if (!input->ReadLittleEndian32(&temp)) return false; + *value = static_cast(temp); + return true; +} +template <> +inline bool WireFormatLite::ReadPrimitive( + io::CodedInputStream* input, + int64* value) { + uint64 temp; + if (!input->ReadLittleEndian64(&temp)) return false; + *value = static_cast(temp); + return true; +} +template <> +inline bool WireFormatLite::ReadPrimitive( + io::CodedInputStream* input, + float* value) { + uint32 temp; + if (!input->ReadLittleEndian32(&temp)) return false; + *value = DecodeFloat(temp); + return true; +} +template <> +inline bool WireFormatLite::ReadPrimitive( + io::CodedInputStream* input, + double* value) { + uint64 temp; + if (!input->ReadLittleEndian64(&temp)) return false; + *value = DecodeDouble(temp); + return true; +} +template <> +inline bool WireFormatLite::ReadPrimitive( + io::CodedInputStream* input, + bool* value) { + uint32 temp; + if (!input->ReadVarint32(&temp)) return false; + *value = temp != 0; + return true; +} +template <> +inline bool WireFormatLite::ReadPrimitive( + io::CodedInputStream* input, + int* value) { + uint32 temp; + if (!input->ReadVarint32(&temp)) return false; + *value = static_cast(temp); + return true; +} + +template <> +inline const uint8* WireFormatLite::ReadPrimitiveFromArray< + uint32, WireFormatLite::TYPE_FIXED32>( + const uint8* buffer, + uint32* value) { + return io::CodedInputStream::ReadLittleEndian32FromArray(buffer, value); +} +template <> +inline const uint8* WireFormatLite::ReadPrimitiveFromArray< + uint64, WireFormatLite::TYPE_FIXED64>( + const uint8* buffer, + uint64* value) { + return io::CodedInputStream::ReadLittleEndian64FromArray(buffer, value); +} +template <> +inline const uint8* WireFormatLite::ReadPrimitiveFromArray< + int32, WireFormatLite::TYPE_SFIXED32>( + const uint8* buffer, + int32* value) { + uint32 temp; + buffer = io::CodedInputStream::ReadLittleEndian32FromArray(buffer, &temp); + *value = static_cast(temp); + return buffer; +} +template <> +inline const uint8* WireFormatLite::ReadPrimitiveFromArray< + int64, WireFormatLite::TYPE_SFIXED64>( + const uint8* buffer, + int64* value) { + uint64 temp; + buffer = io::CodedInputStream::ReadLittleEndian64FromArray(buffer, &temp); + *value = static_cast(temp); + return buffer; +} +template <> +inline const uint8* WireFormatLite::ReadPrimitiveFromArray< + float, WireFormatLite::TYPE_FLOAT>( + const uint8* buffer, + float* value) { + uint32 temp; + buffer = io::CodedInputStream::ReadLittleEndian32FromArray(buffer, &temp); + *value = DecodeFloat(temp); + return buffer; +} +template <> +inline const uint8* WireFormatLite::ReadPrimitiveFromArray< + double, WireFormatLite::TYPE_DOUBLE>( + const uint8* buffer, + double* value) { + uint64 temp; + buffer = io::CodedInputStream::ReadLittleEndian64FromArray(buffer, &temp); + *value = DecodeDouble(temp); + return buffer; +} + +template +inline bool WireFormatLite::ReadRepeatedPrimitive(int, // tag_size, unused. + uint32 tag, + io::CodedInputStream* input, + RepeatedField* values) { + CType value; + if (!ReadPrimitive(input, &value)) return false; + values->Add(value); + int elements_already_reserved = values->Capacity() - values->size(); + while (elements_already_reserved > 0 && input->ExpectTag(tag)) { + if (!ReadPrimitive(input, &value)) return false; + values->AddAlreadyReserved(value); + elements_already_reserved--; + } + return true; +} + +template +inline bool WireFormatLite::ReadRepeatedFixedSizePrimitive( + int tag_size, + uint32 tag, + io::CodedInputStream* input, + RepeatedField* values) { + GOOGLE_DCHECK_EQ(UInt32Size(tag), tag_size); + CType value; + if (!ReadPrimitive(input, &value)) + return false; + values->Add(value); + + // For fixed size values, repeated values can be read more quickly by + // reading directly from a raw array. + // + // We can get a tight loop by only reading as many elements as can be + // added to the RepeatedField without having to do any resizing. Additionally, + // we only try to read as many elements as are available from the current + // buffer space. Doing so avoids having to perform boundary checks when + // reading the value: the maximum number of elements that can be read is + // known outside of the loop. + const void* void_pointer; + int size; + input->GetDirectBufferPointerInline(&void_pointer, &size); + if (size > 0) { + const uint8* buffer = reinterpret_cast(void_pointer); + // The number of bytes each type occupies on the wire. + const int per_value_size = tag_size + sizeof(value); + + int elements_available = min(values->Capacity() - values->size(), + size / per_value_size); + int num_read = 0; + while (num_read < elements_available && + (buffer = io::CodedInputStream::ExpectTagFromArray( + buffer, tag)) != NULL) { + buffer = ReadPrimitiveFromArray(buffer, &value); + values->AddAlreadyReserved(value); + ++num_read; + } + const int read_bytes = num_read * per_value_size; + if (read_bytes > 0) { + input->Skip(read_bytes); + } + } + return true; +} + +// Specializations of ReadRepeatedPrimitive for the fixed size types, which use +// the optimized code path. +#define READ_REPEATED_FIXED_SIZE_PRIMITIVE(CPPTYPE, DECLARED_TYPE) \ +template <> \ +inline bool WireFormatLite::ReadRepeatedPrimitive< \ + CPPTYPE, WireFormatLite::DECLARED_TYPE>( \ + int tag_size, \ + uint32 tag, \ + io::CodedInputStream* input, \ + RepeatedField* values) { \ + return ReadRepeatedFixedSizePrimitive< \ + CPPTYPE, WireFormatLite::DECLARED_TYPE>( \ + tag_size, tag, input, values); \ +} + +READ_REPEATED_FIXED_SIZE_PRIMITIVE(uint32, TYPE_FIXED32) +READ_REPEATED_FIXED_SIZE_PRIMITIVE(uint64, TYPE_FIXED64) +READ_REPEATED_FIXED_SIZE_PRIMITIVE(int32, TYPE_SFIXED32) +READ_REPEATED_FIXED_SIZE_PRIMITIVE(int64, TYPE_SFIXED64) +READ_REPEATED_FIXED_SIZE_PRIMITIVE(float, TYPE_FLOAT) +READ_REPEATED_FIXED_SIZE_PRIMITIVE(double, TYPE_DOUBLE) + +#undef READ_REPEATED_FIXED_SIZE_PRIMITIVE + +template +bool WireFormatLite::ReadRepeatedPrimitiveNoInline( + int tag_size, + uint32 tag, + io::CodedInputStream* input, + RepeatedField* value) { + return ReadRepeatedPrimitive( + tag_size, tag, input, value); +} + +template +inline bool WireFormatLite::ReadPackedPrimitive(io::CodedInputStream* input, + RepeatedField* values) { + uint32 length; + if (!input->ReadVarint32(&length)) return false; + io::CodedInputStream::Limit limit = input->PushLimit(length); + while (input->BytesUntilLimit() > 0) { + CType value; + if (!ReadPrimitive(input, &value)) return false; + values->Add(value); + } + input->PopLimit(limit); + return true; +} + +template +bool WireFormatLite::ReadPackedPrimitiveNoInline(io::CodedInputStream* input, + RepeatedField* values) { + return ReadPackedPrimitive(input, values); +} + + +inline bool WireFormatLite::ReadGroup(int field_number, + io::CodedInputStream* input, + MessageLite* value) { + if (!input->IncrementRecursionDepth()) return false; + if (!value->MergePartialFromCodedStream(input)) return false; + input->DecrementRecursionDepth(); + // Make sure the last thing read was an end tag for this group. + if (!input->LastTagWas(MakeTag(field_number, WIRETYPE_END_GROUP))) { + return false; + } + return true; +} +inline bool WireFormatLite::ReadMessage(io::CodedInputStream* input, + MessageLite* value) { + uint32 length; + if (!input->ReadVarint32(&length)) return false; + if (!input->IncrementRecursionDepth()) return false; + io::CodedInputStream::Limit limit = input->PushLimit(length); + if (!value->MergePartialFromCodedStream(input)) return false; + // Make sure that parsing stopped when the limit was hit, not at an endgroup + // tag. + if (!input->ConsumedEntireMessage()) return false; + input->PopLimit(limit); + input->DecrementRecursionDepth(); + return true; +} + +// We name the template parameter something long and extremely unlikely to occur +// elsewhere because a *qualified* member access expression designed to avoid +// virtual dispatch, C++03 [basic.lookup.classref] 3.4.5/4 requires that the +// name of the qualifying class to be looked up both in the context of the full +// expression (finding the template parameter) and in the context of the object +// whose member we are accessing. This could potentially find a nested type +// within that object. The standard goes on to require these names to refer to +// the same entity, which this collision would violate. The lack of a safe way +// to avoid this collision appears to be a defect in the standard, but until it +// is corrected, we choose the name to avoid accidental collisions. +template +inline bool WireFormatLite::ReadGroupNoVirtual( + int field_number, io::CodedInputStream* input, + MessageType_WorkAroundCppLookupDefect* value) { + if (!input->IncrementRecursionDepth()) return false; + if (!value-> + MessageType_WorkAroundCppLookupDefect::MergePartialFromCodedStream(input)) + return false; + input->DecrementRecursionDepth(); + // Make sure the last thing read was an end tag for this group. + if (!input->LastTagWas(MakeTag(field_number, WIRETYPE_END_GROUP))) { + return false; + } + return true; +} +template +inline bool WireFormatLite::ReadMessageNoVirtual( + io::CodedInputStream* input, MessageType_WorkAroundCppLookupDefect* value) { + uint32 length; + if (!input->ReadVarint32(&length)) return false; + if (!input->IncrementRecursionDepth()) return false; + io::CodedInputStream::Limit limit = input->PushLimit(length); + if (!value-> + MessageType_WorkAroundCppLookupDefect::MergePartialFromCodedStream(input)) + return false; + // Make sure that parsing stopped when the limit was hit, not at an endgroup + // tag. + if (!input->ConsumedEntireMessage()) return false; + input->PopLimit(limit); + input->DecrementRecursionDepth(); + return true; +} + +// =================================================================== + +inline void WireFormatLite::WriteTag(int field_number, WireType type, + io::CodedOutputStream* output) { + output->WriteTag(MakeTag(field_number, type)); +} + +inline void WireFormatLite::WriteInt32NoTag(int32 value, + io::CodedOutputStream* output) { + output->WriteVarint32SignExtended(value); +} +inline void WireFormatLite::WriteInt64NoTag(int64 value, + io::CodedOutputStream* output) { + output->WriteVarint64(static_cast(value)); +} +inline void WireFormatLite::WriteUInt32NoTag(uint32 value, + io::CodedOutputStream* output) { + output->WriteVarint32(value); +} +inline void WireFormatLite::WriteUInt64NoTag(uint64 value, + io::CodedOutputStream* output) { + output->WriteVarint64(value); +} +inline void WireFormatLite::WriteSInt32NoTag(int32 value, + io::CodedOutputStream* output) { + output->WriteVarint32(ZigZagEncode32(value)); +} +inline void WireFormatLite::WriteSInt64NoTag(int64 value, + io::CodedOutputStream* output) { + output->WriteVarint64(ZigZagEncode64(value)); +} +inline void WireFormatLite::WriteFixed32NoTag(uint32 value, + io::CodedOutputStream* output) { + output->WriteLittleEndian32(value); +} +inline void WireFormatLite::WriteFixed64NoTag(uint64 value, + io::CodedOutputStream* output) { + output->WriteLittleEndian64(value); +} +inline void WireFormatLite::WriteSFixed32NoTag(int32 value, + io::CodedOutputStream* output) { + output->WriteLittleEndian32(static_cast(value)); +} +inline void WireFormatLite::WriteSFixed64NoTag(int64 value, + io::CodedOutputStream* output) { + output->WriteLittleEndian64(static_cast(value)); +} +inline void WireFormatLite::WriteFloatNoTag(float value, + io::CodedOutputStream* output) { + output->WriteLittleEndian32(EncodeFloat(value)); +} +inline void WireFormatLite::WriteDoubleNoTag(double value, + io::CodedOutputStream* output) { + output->WriteLittleEndian64(EncodeDouble(value)); +} +inline void WireFormatLite::WriteBoolNoTag(bool value, + io::CodedOutputStream* output) { + output->WriteVarint32(value ? 1 : 0); +} +inline void WireFormatLite::WriteEnumNoTag(int value, + io::CodedOutputStream* output) { + output->WriteVarint32SignExtended(value); +} + +// See comment on ReadGroupNoVirtual to understand the need for this template +// parameter name. +template +inline void WireFormatLite::WriteGroupNoVirtual( + int field_number, const MessageType_WorkAroundCppLookupDefect& value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_START_GROUP, output); + value.MessageType_WorkAroundCppLookupDefect::SerializeWithCachedSizes(output); + WriteTag(field_number, WIRETYPE_END_GROUP, output); +} +template +inline void WireFormatLite::WriteMessageNoVirtual( + int field_number, const MessageType_WorkAroundCppLookupDefect& value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output); + output->WriteVarint32( + value.MessageType_WorkAroundCppLookupDefect::GetCachedSize()); + value.MessageType_WorkAroundCppLookupDefect::SerializeWithCachedSizes(output); +} + +// =================================================================== + +inline uint8* WireFormatLite::WriteTagToArray(int field_number, + WireType type, + uint8* target) { + return io::CodedOutputStream::WriteTagToArray(MakeTag(field_number, type), + target); +} + +inline uint8* WireFormatLite::WriteInt32NoTagToArray(int32 value, + uint8* target) { + return io::CodedOutputStream::WriteVarint32SignExtendedToArray(value, target); +} +inline uint8* WireFormatLite::WriteInt64NoTagToArray(int64 value, + uint8* target) { + return io::CodedOutputStream::WriteVarint64ToArray( + static_cast(value), target); +} +inline uint8* WireFormatLite::WriteUInt32NoTagToArray(uint32 value, + uint8* target) { + return io::CodedOutputStream::WriteVarint32ToArray(value, target); +} +inline uint8* WireFormatLite::WriteUInt64NoTagToArray(uint64 value, + uint8* target) { + return io::CodedOutputStream::WriteVarint64ToArray(value, target); +} +inline uint8* WireFormatLite::WriteSInt32NoTagToArray(int32 value, + uint8* target) { + return io::CodedOutputStream::WriteVarint32ToArray(ZigZagEncode32(value), + target); +} +inline uint8* WireFormatLite::WriteSInt64NoTagToArray(int64 value, + uint8* target) { + return io::CodedOutputStream::WriteVarint64ToArray(ZigZagEncode64(value), + target); +} +inline uint8* WireFormatLite::WriteFixed32NoTagToArray(uint32 value, + uint8* target) { + return io::CodedOutputStream::WriteLittleEndian32ToArray(value, target); +} +inline uint8* WireFormatLite::WriteFixed64NoTagToArray(uint64 value, + uint8* target) { + return io::CodedOutputStream::WriteLittleEndian64ToArray(value, target); +} +inline uint8* WireFormatLite::WriteSFixed32NoTagToArray(int32 value, + uint8* target) { + return io::CodedOutputStream::WriteLittleEndian32ToArray( + static_cast(value), target); +} +inline uint8* WireFormatLite::WriteSFixed64NoTagToArray(int64 value, + uint8* target) { + return io::CodedOutputStream::WriteLittleEndian64ToArray( + static_cast(value), target); +} +inline uint8* WireFormatLite::WriteFloatNoTagToArray(float value, + uint8* target) { + return io::CodedOutputStream::WriteLittleEndian32ToArray(EncodeFloat(value), + target); +} +inline uint8* WireFormatLite::WriteDoubleNoTagToArray(double value, + uint8* target) { + return io::CodedOutputStream::WriteLittleEndian64ToArray(EncodeDouble(value), + target); +} +inline uint8* WireFormatLite::WriteBoolNoTagToArray(bool value, + uint8* target) { + return io::CodedOutputStream::WriteVarint32ToArray(value ? 1 : 0, target); +} +inline uint8* WireFormatLite::WriteEnumNoTagToArray(int value, + uint8* target) { + return io::CodedOutputStream::WriteVarint32SignExtendedToArray(value, target); +} + +inline uint8* WireFormatLite::WriteInt32ToArray(int field_number, + int32 value, + uint8* target) { + target = WriteTagToArray(field_number, WIRETYPE_VARINT, target); + return WriteInt32NoTagToArray(value, target); +} +inline uint8* WireFormatLite::WriteInt64ToArray(int field_number, + int64 value, + uint8* target) { + target = WriteTagToArray(field_number, WIRETYPE_VARINT, target); + return WriteInt64NoTagToArray(value, target); +} +inline uint8* WireFormatLite::WriteUInt32ToArray(int field_number, + uint32 value, + uint8* target) { + target = WriteTagToArray(field_number, WIRETYPE_VARINT, target); + return WriteUInt32NoTagToArray(value, target); +} +inline uint8* WireFormatLite::WriteUInt64ToArray(int field_number, + uint64 value, + uint8* target) { + target = WriteTagToArray(field_number, WIRETYPE_VARINT, target); + return WriteUInt64NoTagToArray(value, target); +} +inline uint8* WireFormatLite::WriteSInt32ToArray(int field_number, + int32 value, + uint8* target) { + target = WriteTagToArray(field_number, WIRETYPE_VARINT, target); + return WriteSInt32NoTagToArray(value, target); +} +inline uint8* WireFormatLite::WriteSInt64ToArray(int field_number, + int64 value, + uint8* target) { + target = WriteTagToArray(field_number, WIRETYPE_VARINT, target); + return WriteSInt64NoTagToArray(value, target); +} +inline uint8* WireFormatLite::WriteFixed32ToArray(int field_number, + uint32 value, + uint8* target) { + target = WriteTagToArray(field_number, WIRETYPE_FIXED32, target); + return WriteFixed32NoTagToArray(value, target); +} +inline uint8* WireFormatLite::WriteFixed64ToArray(int field_number, + uint64 value, + uint8* target) { + target = WriteTagToArray(field_number, WIRETYPE_FIXED64, target); + return WriteFixed64NoTagToArray(value, target); +} +inline uint8* WireFormatLite::WriteSFixed32ToArray(int field_number, + int32 value, + uint8* target) { + target = WriteTagToArray(field_number, WIRETYPE_FIXED32, target); + return WriteSFixed32NoTagToArray(value, target); +} +inline uint8* WireFormatLite::WriteSFixed64ToArray(int field_number, + int64 value, + uint8* target) { + target = WriteTagToArray(field_number, WIRETYPE_FIXED64, target); + return WriteSFixed64NoTagToArray(value, target); +} +inline uint8* WireFormatLite::WriteFloatToArray(int field_number, + float value, + uint8* target) { + target = WriteTagToArray(field_number, WIRETYPE_FIXED32, target); + return WriteFloatNoTagToArray(value, target); +} +inline uint8* WireFormatLite::WriteDoubleToArray(int field_number, + double value, + uint8* target) { + target = WriteTagToArray(field_number, WIRETYPE_FIXED64, target); + return WriteDoubleNoTagToArray(value, target); +} +inline uint8* WireFormatLite::WriteBoolToArray(int field_number, + bool value, + uint8* target) { + target = WriteTagToArray(field_number, WIRETYPE_VARINT, target); + return WriteBoolNoTagToArray(value, target); +} +inline uint8* WireFormatLite::WriteEnumToArray(int field_number, + int value, + uint8* target) { + target = WriteTagToArray(field_number, WIRETYPE_VARINT, target); + return WriteEnumNoTagToArray(value, target); +} + +inline uint8* WireFormatLite::WriteStringToArray(int field_number, + const string& value, + uint8* target) { + // String is for UTF-8 text only + // WARNING: In wire_format.cc, both strings and bytes are handled by + // WriteString() to avoid code duplication. If the implementations become + // different, you will need to update that usage. + target = WriteTagToArray(field_number, WIRETYPE_LENGTH_DELIMITED, target); + target = io::CodedOutputStream::WriteVarint32ToArray(value.size(), target); + return io::CodedOutputStream::WriteStringToArray(value, target); +} +inline uint8* WireFormatLite::WriteBytesToArray(int field_number, + const string& value, + uint8* target) { + target = WriteTagToArray(field_number, WIRETYPE_LENGTH_DELIMITED, target); + target = io::CodedOutputStream::WriteVarint32ToArray(value.size(), target); + return io::CodedOutputStream::WriteStringToArray(value, target); +} + + +inline uint8* WireFormatLite::WriteGroupToArray(int field_number, + const MessageLite& value, + uint8* target) { + target = WriteTagToArray(field_number, WIRETYPE_START_GROUP, target); + target = value.SerializeWithCachedSizesToArray(target); + return WriteTagToArray(field_number, WIRETYPE_END_GROUP, target); +} +inline uint8* WireFormatLite::WriteMessageToArray(int field_number, + const MessageLite& value, + uint8* target) { + target = WriteTagToArray(field_number, WIRETYPE_LENGTH_DELIMITED, target); + target = io::CodedOutputStream::WriteVarint32ToArray( + value.GetCachedSize(), target); + return value.SerializeWithCachedSizesToArray(target); +} + +// See comment on ReadGroupNoVirtual to understand the need for this template +// parameter name. +template +inline uint8* WireFormatLite::WriteGroupNoVirtualToArray( + int field_number, const MessageType_WorkAroundCppLookupDefect& value, + uint8* target) { + target = WriteTagToArray(field_number, WIRETYPE_START_GROUP, target); + target = value.MessageType_WorkAroundCppLookupDefect + ::SerializeWithCachedSizesToArray(target); + return WriteTagToArray(field_number, WIRETYPE_END_GROUP, target); +} +template +inline uint8* WireFormatLite::WriteMessageNoVirtualToArray( + int field_number, const MessageType_WorkAroundCppLookupDefect& value, + uint8* target) { + target = WriteTagToArray(field_number, WIRETYPE_LENGTH_DELIMITED, target); + target = io::CodedOutputStream::WriteVarint32ToArray( + value.MessageType_WorkAroundCppLookupDefect::GetCachedSize(), target); + return value.MessageType_WorkAroundCppLookupDefect + ::SerializeWithCachedSizesToArray(target); +} + +// =================================================================== + +inline int WireFormatLite::Int32Size(int32 value) { + return io::CodedOutputStream::VarintSize32SignExtended(value); +} +inline int WireFormatLite::Int64Size(int64 value) { + return io::CodedOutputStream::VarintSize64(static_cast(value)); +} +inline int WireFormatLite::UInt32Size(uint32 value) { + return io::CodedOutputStream::VarintSize32(value); +} +inline int WireFormatLite::UInt64Size(uint64 value) { + return io::CodedOutputStream::VarintSize64(value); +} +inline int WireFormatLite::SInt32Size(int32 value) { + return io::CodedOutputStream::VarintSize32(ZigZagEncode32(value)); +} +inline int WireFormatLite::SInt64Size(int64 value) { + return io::CodedOutputStream::VarintSize64(ZigZagEncode64(value)); +} +inline int WireFormatLite::EnumSize(int value) { + return io::CodedOutputStream::VarintSize32SignExtended(value); +} + +inline int WireFormatLite::StringSize(const string& value) { + return io::CodedOutputStream::VarintSize32(value.size()) + + value.size(); +} +inline int WireFormatLite::BytesSize(const string& value) { + return io::CodedOutputStream::VarintSize32(value.size()) + + value.size(); +} + + +inline int WireFormatLite::GroupSize(const MessageLite& value) { + return value.ByteSize(); +} +inline int WireFormatLite::MessageSize(const MessageLite& value) { + return LengthDelimitedSize(value.ByteSize()); +} + +// See comment on ReadGroupNoVirtual to understand the need for this template +// parameter name. +template +inline int WireFormatLite::GroupSizeNoVirtual( + const MessageType_WorkAroundCppLookupDefect& value) { + return value.MessageType_WorkAroundCppLookupDefect::ByteSize(); +} +template +inline int WireFormatLite::MessageSizeNoVirtual( + const MessageType_WorkAroundCppLookupDefect& value) { + return LengthDelimitedSize( + value.MessageType_WorkAroundCppLookupDefect::ByteSize()); +} + +inline int WireFormatLite::LengthDelimitedSize(int length) { + return io::CodedOutputStream::VarintSize32(length) + length; +} + +} // namespace internal +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_WIRE_FORMAT_LITE_INL_H__ diff --git a/include/iconv/iconv.h b/include/iconv/iconv.h new file mode 100644 index 000000000..7f8c024d0 --- /dev/null +++ b/include/iconv/iconv.h @@ -0,0 +1,205 @@ +/* Copyright (C) 1999-2003, 2005-2006 Free Software Foundation, Inc. + This file is part of the GNU LIBICONV Library. + + The GNU LIBICONV Library is free software; you can redistribute it + and/or modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + The GNU LIBICONV Library is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU LIBICONV Library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, Inc., 51 Franklin Street, + Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* When installed, this file is called "iconv.h". */ + +#ifndef _LIBICONV_H +#define _LIBICONV_H + +#define _LIBICONV_VERSION 0x010B /* version number: (major<<8) + minor */ +extern int _libiconv_version; /* Likewise */ + +/* We would like to #include any system header file which could define + iconv_t, 1. in order to eliminate the risk that the user gets compilation + errors because some other system header file includes /usr/include/iconv.h + which defines iconv_t or declares iconv after this file, 2. when compiling + for LIBICONV_PLUG, we need the proper iconv_t type in order to produce + binary compatible code. + But gcc's #include_next is not portable. Thus, once libiconv's iconv.h + has been installed in /usr/local/include, there is no way any more to + include the original /usr/include/iconv.h. We simply have to get away + without it. + Ad 1. The risk that a system header file does + #include "iconv.h" or #include_next "iconv.h" + is small. They all do #include . + Ad 2. The iconv_t type is a pointer type in all cases I have seen. (It + has to be a scalar type because (iconv_t)(-1) is a possible return value + from iconv_open().) */ + +/* Define iconv_t ourselves. */ +#undef iconv_t +#define iconv_t libiconv_t +typedef void* iconv_t; + +/* Get size_t declaration. + Get wchar_t declaration if it exists. */ +#include + +/* Get errno declaration and values. */ +#include +/* Some systems, like SunOS 4, don't have EILSEQ. Some systems, like BSD/OS, + have EILSEQ in a different header. On these systems, define EILSEQ + ourselves. */ +#ifndef EILSEQ +#define EILSEQ @EILSEQ@ +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + + +/* Allocates descriptor for code conversion from encoding `fromcode' to + encoding `tocode'. */ +#ifndef LIBICONV_PLUG +#define iconv_open libiconv_open +#endif +extern iconv_t iconv_open (const char* tocode, const char* fromcode); + +/* Converts, using conversion descriptor `cd', at most `*inbytesleft' bytes + starting at `*inbuf', writing at most `*outbytesleft' bytes starting at + `*outbuf'. + Decrements `*inbytesleft' and increments `*inbuf' by the same amount. + Decrements `*outbytesleft' and increments `*outbuf' by the same amount. */ +#ifndef LIBICONV_PLUG +#define iconv libiconv +#endif +extern size_t iconv (iconv_t cd, const char* * inbuf, size_t *inbytesleft, char* * outbuf, size_t *outbytesleft, int *errnum); + +/* Frees resources allocated for conversion descriptor `cd'. */ +#ifndef LIBICONV_PLUG +#define iconv_close libiconv_close +#endif +extern int iconv_close (iconv_t cd); + + +#ifndef LIBICONV_PLUG + +/* Nonstandard extensions. */ + +/* Control of attributes. */ +#define iconvctl libiconvctl +extern int iconvctl (iconv_t cd, int request, void* argument); + +/* Hook performed after every successful conversion of a Unicode character. */ +typedef void (*iconv_unicode_char_hook) (unsigned int uc, void* data); +/* Hook performed after every successful conversion of a wide character. */ +typedef void (*iconv_wide_char_hook) (wchar_t wc, void* data); +/* Set of hooks. */ +struct iconv_hooks { + iconv_unicode_char_hook uc_hook; + iconv_wide_char_hook wc_hook; + void* data; +}; + +/* Fallback function. Invoked when a small number of bytes could not be + converted to a Unicode character. This function should process all + bytes from inbuf and may produce replacement Unicode characters by calling + the write_replacement callback repeatedly. */ +typedef void (*iconv_unicode_mb_to_uc_fallback) + (const char* inbuf, size_t inbufsize, + void (*write_replacement) (const unsigned int *buf, size_t buflen, + void* callback_arg), + void* callback_arg, + void* data); +/* Fallback function. Invoked when a Unicode character could not be converted + to the target encoding. This function should process the character and + may produce replacement bytes (in the target encoding) by calling the + write_replacement callback repeatedly. */ +typedef void (*iconv_unicode_uc_to_mb_fallback) + (unsigned int code, + void (*write_replacement) (const char *buf, size_t buflen, + void* callback_arg), + void* callback_arg, + void* data); +#if 1 +/* Fallback function. Invoked when a number of bytes could not be converted to + a wide character. This function should process all bytes from inbuf and may + produce replacement wide characters by calling the write_replacement + callback repeatedly. */ +typedef void (*iconv_wchar_mb_to_wc_fallback) + (const char* inbuf, size_t inbufsize, + void (*write_replacement) (const wchar_t *buf, size_t buflen, + void* callback_arg), + void* callback_arg, + void* data); +/* Fallback function. Invoked when a wide character could not be converted to + the target encoding. This function should process the character and may + produce replacement bytes (in the target encoding) by calling the + write_replacement callback repeatedly. */ +typedef void (*iconv_wchar_wc_to_mb_fallback) + (wchar_t code, + void (*write_replacement) (const char *buf, size_t buflen, + void* callback_arg), + void* callback_arg, + void* data); +#else +/* If the wchar_t type does not exist, these two fallback functions are never + invoked. Their argument list therefore does not matter. */ +typedef void (*iconv_wchar_mb_to_wc_fallback) (); +typedef void (*iconv_wchar_wc_to_mb_fallback) (); +#endif +/* Set of fallbacks. */ +struct iconv_fallbacks { + iconv_unicode_mb_to_uc_fallback mb_to_uc_fallback; + iconv_unicode_uc_to_mb_fallback uc_to_mb_fallback; + iconv_wchar_mb_to_wc_fallback mb_to_wc_fallback; + iconv_wchar_wc_to_mb_fallback wc_to_mb_fallback; + void* data; +}; + +/* Requests for iconvctl. */ +#define ICONV_TRIVIALP 0 /* int *argument */ +#define ICONV_GET_TRANSLITERATE 1 /* int *argument */ +#define ICONV_SET_TRANSLITERATE 2 /* const int *argument */ +#define ICONV_GET_DISCARD_ILSEQ 3 /* int *argument */ +#define ICONV_SET_DISCARD_ILSEQ 4 /* const int *argument */ +#define ICONV_SET_HOOKS 5 /* const struct iconv_hooks *argument */ +#define ICONV_SET_FALLBACKS 6 /* const struct iconv_fallbacks *argument */ + +/* Listing of locale independent encodings. */ +#define iconvlist libiconvlist +extern void iconvlist (int (*do_one) (unsigned int namescount, + const char * const * names, + void* data), + void* data); + +/* Canonicalize an encoding name. + The result is either a canonical encoding name, or name itself. */ +extern const char * iconv_canonicalize (const char * name); + +/* Support for relocatable packages. */ + +/* Sets the original and the current installation prefix of the package. + Relocation simply replaces a pathname starting with the original prefix + by the corresponding pathname with the current prefix instead. Both + prefixes should be directory names without trailing slash (i.e. use "" + instead of "/"). */ +extern void libiconv_set_relocation_prefix (const char *orig_prefix, + const char *curr_prefix); + +#endif + + +#ifdef __cplusplus +} +#endif + + +#endif /* _LIBICONV_H */ diff --git a/include/iconv/libcharset.h b/include/iconv/libcharset.h new file mode 100644 index 000000000..1a81ced31 --- /dev/null +++ b/include/iconv/libcharset.h @@ -0,0 +1,56 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU CHARSET Library. + + The GNU CHARSET Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU CHARSET Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with the GNU CHARSET Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef _LIBCHARSET_H +#define _LIBCHARSET_H + +#ifdef LIBCHARSET_STATIC +#define LIBCHARSET_DLL_EXPORTED +#else /* LIBCHARSET_STATIC */ +#ifdef BUILDING_LIBCHARSET +#define LIBCHARSET_DLL_EXPORTED __declspec(dllexport) +#else +#define LIBCHARSET_DLL_EXPORTED __declspec(dllimport) +#endif +#endif /* LIBCHARSET_STATIC */ + +#include + + +#ifdef __cplusplus +extern "C" { +#endif + + +/* Support for relocatable packages. */ + +/* Sets the original and the current installation prefix of the package. + Relocation simply replaces a pathname starting with the original prefix + by the corresponding pathname with the current prefix instead. Both + prefixes should be directory names without trailing slash (i.e. use "" + instead of "/"). */ +extern LIBCHARSET_DLL_EXPORTED void libcharset_set_relocation_prefix (const char *orig_prefix, + const char *curr_prefix); + + +#ifdef __cplusplus +} +#endif + + +#endif /* _LIBCHARSET_H */ diff --git a/include/iconv/localcharset.h b/include/iconv/localcharset.h new file mode 100644 index 000000000..25d21ebfb --- /dev/null +++ b/include/iconv/localcharset.h @@ -0,0 +1,51 @@ +/* Determine a canonical name for the current locale's character encoding. + Copyright (C) 2000-2003 Free Software Foundation, Inc. + This file is part of the GNU CHARSET Library. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +#ifndef _LOCALCHARSET_H +#define _LOCALCHARSET_H + +#ifdef LIBCHARSET_STATIC +#define LIBCHARSET_DLL_EXPORTED +#else /* LIBCHARSET_STATIC */ +#ifdef BUILDING_LIBCHARSET +#define LIBCHARSET_DLL_EXPORTED __declspec(dllexport) +#else +#define LIBCHARSET_DLL_EXPORTED __declspec(dllimport) +#endif +#endif /* LIBCHARSET_STATIC */ + +#ifdef __cplusplus +extern "C" { +#endif + + +/* Determine the current locale's character encoding, and canonicalize it + into one of the canonical names listed in config.charset. + The result must not be freed; it is statically allocated. + If the canonical name cannot be determined, the result is a non-canonical + name. */ +extern LIBCHARSET_DLL_EXPORTED const char * locale_charset (void); + + +#ifdef __cplusplus +} +#endif + + +#endif /* _LOCALCHARSET_H */ diff --git a/include/mysql/client_plugin.h b/include/mysql/client_plugin.h new file mode 100644 index 000000000..cc3f46804 --- /dev/null +++ b/include/mysql/client_plugin.h @@ -0,0 +1,163 @@ +#ifndef MYSQL_CLIENT_PLUGIN_INCLUDED +/* Copyright (C) 2010 Sun Microsystems, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/** + @file + + MySQL Client Plugin API + + This file defines the API for plugins that work on the client side +*/ +#define MYSQL_CLIENT_PLUGIN_INCLUDED + +#ifndef MYSQL_ABI_CHECK +#include +#include +#endif + +/* known plugin types */ +#define MYSQL_CLIENT_reserved1 0 +#define MYSQL_CLIENT_reserved2 1 +#define MYSQL_CLIENT_AUTHENTICATION_PLUGIN 2 + +#define MYSQL_CLIENT_AUTHENTICATION_PLUGIN_INTERFACE_VERSION 0x0100 + +#define MYSQL_CLIENT_MAX_PLUGINS 3 + +#define mysql_declare_client_plugin(X) \ + MYSQL_PLUGIN_EXPORT struct st_mysql_client_plugin_ ## X \ + _mysql_client_plugin_declaration_ = { \ + MYSQL_CLIENT_ ## X ## _PLUGIN, \ + MYSQL_CLIENT_ ## X ## _PLUGIN_INTERFACE_VERSION, +#define mysql_end_client_plugin } + +/* generic plugin header structure */ +#define MYSQL_CLIENT_PLUGIN_HEADER \ + int type; \ + unsigned int interface_version; \ + const char *name; \ + const char *author; \ + const char *desc; \ + unsigned int version[3]; \ + const char *license; \ + void *mysql_api; \ + int (*init)(char *, size_t, int, va_list); \ + int (*deinit)(); \ + int (*options)(const char *option, const void *); + +struct st_mysql_client_plugin +{ + MYSQL_CLIENT_PLUGIN_HEADER +}; + +struct st_mysql; + +/******** authentication plugin specific declarations *********/ +#include + +struct st_mysql_client_plugin_AUTHENTICATION +{ + MYSQL_CLIENT_PLUGIN_HEADER + int (*authenticate_user)(MYSQL_PLUGIN_VIO *vio, struct st_mysql *mysql); +}; + +/******** using plugins ************/ + +/** + loads a plugin and initializes it + + @param mysql MYSQL structure. + @param name a name of the plugin to load + @param type type of plugin that should be loaded, -1 to disable type check + @param argc number of arguments to pass to the plugin initialization + function + @param ... arguments for the plugin initialization function + + @retval + a pointer to the loaded plugin, or NULL in case of a failure +*/ +struct st_mysql_client_plugin * +mysql_load_plugin(struct st_mysql *mysql, const char *name, int type, + int argc, ...); + +/** + loads a plugin and initializes it, taking va_list as an argument + + This is the same as mysql_load_plugin, but take va_list instead of + a list of arguments. + + @param mysql MYSQL structure. + @param name a name of the plugin to load + @param type type of plugin that should be loaded, -1 to disable type check + @param argc number of arguments to pass to the plugin initialization + function + @param args arguments for the plugin initialization function + + @retval + a pointer to the loaded plugin, or NULL in case of a failure +*/ +struct st_mysql_client_plugin * +mysql_load_plugin_v(struct st_mysql *mysql, const char *name, int type, + int argc, va_list args); + +/** + finds an already loaded plugin by name, or loads it, if necessary + + @param mysql MYSQL structure. + @param name a name of the plugin to load + @param type type of plugin that should be loaded + + @retval + a pointer to the plugin, or NULL in case of a failure +*/ +struct st_mysql_client_plugin * +mysql_client_find_plugin(struct st_mysql *mysql, const char *name, int type); + +/** + adds a plugin structure to the list of loaded plugins + + This is useful if an application has the necessary functionality + (for example, a special load data handler) statically linked into + the application binary. It can use this function to register the plugin + directly, avoiding the need to factor it out into a shared object. + + @param mysql MYSQL structure. It is only used for error reporting + @param plugin an st_mysql_client_plugin structure to register + + @retval + a pointer to the plugin, or NULL in case of a failure +*/ +struct st_mysql_client_plugin * +mysql_client_register_plugin(struct st_mysql *mysql, + struct st_mysql_client_plugin *plugin); + +/** + set plugin options + + Can be used to set extra options and affect behavior for a plugin. + This function may be called multiple times to set several options + + @param plugin an st_mysql_client_plugin structure + @param option a string which specifies the option to set + @param value value for the option. + + @retval 0 on success, 1 in case of failure +**/ +int STDCALL mysql_plugin_options(struct st_mysql_client_plugin *plugin, + const char *option, + const void *value); +#endif + diff --git a/include/mysql/decimal.h b/include/mysql/decimal.h new file mode 100644 index 000000000..530ed9e17 --- /dev/null +++ b/include/mysql/decimal.h @@ -0,0 +1,107 @@ +/* Copyright (C) 2000 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifndef _decimal_h +#define _decimal_h + +typedef enum +{TRUNCATE=0, HALF_EVEN, HALF_UP, CEILING, FLOOR} + decimal_round_mode; +typedef int32 decimal_digit_t; + +typedef struct st_decimal_t { + int intg, frac, len; + my_bool sign; + decimal_digit_t *buf; +} decimal_t; + +int internal_str2dec(const char *from, decimal_t *to, char **end, + my_bool fixed); +int decimal2string(decimal_t *from, char *to, int *to_len, + int fixed_precision, int fixed_decimals, + char filler); +int decimal2ulonglong(decimal_t *from, ulonglong *to); +int ulonglong2decimal(ulonglong from, decimal_t *to); +int decimal2longlong(decimal_t *from, longlong *to); +int longlong2decimal(longlong from, decimal_t *to); +int decimal2double(decimal_t *from, double *to); +int double2decimal(double from, decimal_t *to); +int decimal_actual_fraction(decimal_t *from); +int decimal2bin(decimal_t *from, uchar *to, int precision, int scale); +int bin2decimal(const uchar *from, decimal_t *to, int precision, int scale); + +int decimal_size(int precision, int scale); +int decimal_bin_size(int precision, int scale); +int decimal_result_size(decimal_t *from1, decimal_t *from2, char op, + int param); + +int decimal_intg(decimal_t *from); +int decimal_add(decimal_t *from1, decimal_t *from2, decimal_t *to); +int decimal_sub(decimal_t *from1, decimal_t *from2, decimal_t *to); +int decimal_cmp(decimal_t *from1, decimal_t *from2); +int decimal_mul(decimal_t *from1, decimal_t *from2, decimal_t *to); +int decimal_div(decimal_t *from1, decimal_t *from2, decimal_t *to, + int scale_incr); +int decimal_mod(decimal_t *from1, decimal_t *from2, decimal_t *to); +int decimal_round(decimal_t *from, decimal_t *to, int new_scale, + decimal_round_mode mode); +int decimal_is_zero(decimal_t *from); +void max_decimal(int precision, int frac, decimal_t *to); + +#define string2decimal(A,B,C) internal_str2dec((A), (B), (C), 0) +#define string2decimal_fixed(A,B,C) internal_str2dec((A), (B), (C), 1) + +/* set a decimal_t to zero */ + +#define decimal_make_zero(dec) do { \ + (dec)->buf[0]=0; \ + (dec)->intg=1; \ + (dec)->frac=0; \ + (dec)->sign=0; \ + } while(0) + +/* + returns the length of the buffer to hold string representation + of the decimal (including decimal dot, possible sign and \0) +*/ + +#define decimal_string_size(dec) (((dec)->intg ? (dec)->intg : 1) + \ + (dec)->frac + ((dec)->frac > 0) + 2) + +/* negate a decimal */ +#define decimal_neg(dec) do { (dec)->sign^=1; } while(0) + +/* + conventions: + + decimal_smth() == 0 -- everything's ok + decimal_smth() <= 1 -- result is usable, but precision loss is possible + decimal_smth() <= 2 -- result can be unusable, most significant digits + could've been lost + decimal_smth() > 2 -- no result was generated +*/ + +#define E_DEC_OK 0 +#define E_DEC_TRUNCATED 1 +#define E_DEC_OVERFLOW 2 +#define E_DEC_DIV_ZERO 4 +#define E_DEC_BAD_NUM 8 +#define E_DEC_OOM 16 + +#define E_DEC_ERROR 31 +#define E_DEC_FATAL_ERROR 30 + +#endif + diff --git a/include/mysql/errmsg.h b/include/mysql/errmsg.h new file mode 100644 index 000000000..f1d7dd65f --- /dev/null +++ b/include/mysql/errmsg.h @@ -0,0 +1,108 @@ +#ifndef ERRMSG_INCLUDED +#define ERRMSG_INCLUDED + +/* Copyright (C) 2000 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/* Error messages for MySQL clients */ +/* (Error messages for the daemon are in sql/share/errmsg.txt) */ + +#ifdef __cplusplus +extern "C" { +#endif +void init_client_errs(void); +void finish_client_errs(void); +extern const char *client_errors[]; /* Error messages */ +#ifdef __cplusplus +} +#endif + +#define CR_MIN_ERROR 2000 /* For easier client code */ +#define CR_MAX_ERROR 2999 +#if !defined(ER) +#define ER(X) client_errors[(X)-CR_MIN_ERROR] +#endif +#define CLIENT_ERRMAP 2 /* Errormap used by my_error() */ + +/* Do not add error numbers before CR_ERROR_FIRST. */ +/* If necessary to add lower numbers, change CR_ERROR_FIRST accordingly. */ +#define CR_ERROR_FIRST 2000 /*Copy first error nr.*/ +#define CR_UNKNOWN_ERROR 2000 +#define CR_SOCKET_CREATE_ERROR 2001 +#define CR_CONNECTION_ERROR 2002 +#define CR_CONN_HOST_ERROR 2003 +#define CR_IPSOCK_ERROR 2004 +#define CR_UNKNOWN_HOST 2005 +#define CR_SERVER_GONE_ERROR 2006 +#define CR_VERSION_ERROR 2007 +#define CR_OUT_OF_MEMORY 2008 +#define CR_WRONG_HOST_INFO 2009 +#define CR_LOCALHOST_CONNECTION 2010 +#define CR_TCP_CONNECTION 2011 +#define CR_SERVER_HANDSHAKE_ERR 2012 +#define CR_SERVER_LOST 2013 +#define CR_COMMANDS_OUT_OF_SYNC 2014 +#define CR_NAMEDPIPE_CONNECTION 2015 +#define CR_NAMEDPIPEWAIT_ERROR 2016 +#define CR_NAMEDPIPEOPEN_ERROR 2017 +#define CR_NAMEDPIPESETSTATE_ERROR 2018 +#define CR_CANT_READ_CHARSET 2019 +#define CR_NET_PACKET_TOO_LARGE 2020 +#define CR_EMBEDDED_CONNECTION 2021 +#define CR_PROBE_SLAVE_STATUS 2022 +#define CR_PROBE_SLAVE_HOSTS 2023 +#define CR_PROBE_SLAVE_CONNECT 2024 +#define CR_PROBE_MASTER_CONNECT 2025 +#define CR_SSL_CONNECTION_ERROR 2026 +#define CR_MALFORMED_PACKET 2027 +#define CR_WRONG_LICENSE 2028 + +/* new 4.1 error codes */ +#define CR_NULL_POINTER 2029 +#define CR_NO_PREPARE_STMT 2030 +#define CR_PARAMS_NOT_BOUND 2031 +#define CR_DATA_TRUNCATED 2032 +#define CR_NO_PARAMETERS_EXISTS 2033 +#define CR_INVALID_PARAMETER_NO 2034 +#define CR_INVALID_BUFFER_USE 2035 +#define CR_UNSUPPORTED_PARAM_TYPE 2036 + +#define CR_SHARED_MEMORY_CONNECTION 2037 +#define CR_SHARED_MEMORY_CONNECT_REQUEST_ERROR 2038 +#define CR_SHARED_MEMORY_CONNECT_ANSWER_ERROR 2039 +#define CR_SHARED_MEMORY_CONNECT_FILE_MAP_ERROR 2040 +#define CR_SHARED_MEMORY_CONNECT_MAP_ERROR 2041 +#define CR_SHARED_MEMORY_FILE_MAP_ERROR 2042 +#define CR_SHARED_MEMORY_MAP_ERROR 2043 +#define CR_SHARED_MEMORY_EVENT_ERROR 2044 +#define CR_SHARED_MEMORY_CONNECT_ABANDONED_ERROR 2045 +#define CR_SHARED_MEMORY_CONNECT_SET_ERROR 2046 +#define CR_CONN_UNKNOW_PROTOCOL 2047 +#define CR_INVALID_CONN_HANDLE 2048 +#define CR_SECURE_AUTH 2049 +#define CR_FETCH_CANCELED 2050 +#define CR_NO_DATA 2051 +#define CR_NO_STMT_METADATA 2052 +#define CR_NO_RESULT_SET 2053 +#define CR_NOT_IMPLEMENTED 2054 +#define CR_SERVER_LOST_EXTENDED 2055 +#define CR_STMT_CLOSED 2056 +#define CR_NEW_STMT_METADATA 2057 +#define CR_ALREADY_CONNECTED 2058 +#define CR_AUTH_PLUGIN_CANNOT_LOAD 2059 +#define CR_ERROR_LAST /*Copy last error nr:*/ 2059 +/* Add error numbers before CR_ERROR_LAST and change it accordingly. */ + +#endif /* ERRMSG_INCLUDED */ diff --git a/include/mysql/innodb_priv.h b/include/mysql/innodb_priv.h new file mode 100644 index 000000000..993dad7cf --- /dev/null +++ b/include/mysql/innodb_priv.h @@ -0,0 +1,37 @@ +/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifndef INNODB_PRIV_INCLUDED +#define INNODB_PRIV_INCLUDED + +/** @file Declaring server-internal functions that are used by InnoDB. */ + +#include + +class THD; + +uint filename_to_tablename(const char *from, char *to, uint to_length); +int get_quote_char_for_identifier(THD *thd, const char *name, uint length); +bool schema_table_store_record(THD *thd, TABLE *table); +void localtime_to_TIME(MYSQL_TIME *to, struct tm *from); +bool check_global_access(THD *thd, ulong want_access); +uint strconvert(CHARSET_INFO *from_cs, const char *from, + CHARSET_INFO *to_cs, char *to, uint to_length, + uint *errors); +void sql_print_error(const char *format, ...); + + + +#endif /* INNODB_PRIV_INCLUDED */ diff --git a/include/mysql/keycache.h b/include/mysql/keycache.h new file mode 100644 index 000000000..fefa31afd --- /dev/null +++ b/include/mysql/keycache.h @@ -0,0 +1,146 @@ +/* Copyright (C) 2003 MySQL AB, 2009 Sun Microsystems, Inc + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/* Key cache variable structures */ + +#ifndef _keycache_h +#define _keycache_h + +#include "my_sys.h" /* flush_type */ + +C_MODE_START + +/* declare structures that is used by st_key_cache */ + +struct st_block_link; +typedef struct st_block_link BLOCK_LINK; +struct st_keycache_page; +typedef struct st_keycache_page KEYCACHE_PAGE; +struct st_hash_link; +typedef struct st_hash_link HASH_LINK; + +/* info about requests in a waiting queue */ +typedef struct st_keycache_wqueue +{ + struct st_my_thread_var *last_thread; /* circular list of waiting threads */ +} KEYCACHE_WQUEUE; + +#define CHANGED_BLOCKS_HASH 128 /* must be power of 2 */ + +/* + The key cache structure + It also contains read-only statistics parameters. +*/ + +typedef struct st_key_cache +{ + my_bool key_cache_inited; + my_bool in_resize; /* true during resize operation */ + my_bool resize_in_flush; /* true during flush of resize operation */ + my_bool can_be_used; /* usage of cache for read/write is allowed */ + size_t key_cache_mem_size; /* specified size of the cache memory */ + uint key_cache_block_size; /* size of the page buffer of a cache block */ + ulong min_warm_blocks; /* min number of warm blocks; */ + ulong age_threshold; /* age threshold for hot blocks */ + ulonglong keycache_time; /* total number of block link operations */ + uint hash_entries; /* max number of entries in the hash table */ + int hash_links; /* max number of hash links */ + int hash_links_used; /* number of hash links currently used */ + int disk_blocks; /* max number of blocks in the cache */ + ulong blocks_used; /* maximum number of concurrently used blocks */ + ulong blocks_unused; /* number of currently unused blocks */ + ulong blocks_changed; /* number of currently dirty blocks */ + ulong warm_blocks; /* number of blocks in warm sub-chain */ + ulong cnt_for_resize_op; /* counter to block resize operation */ + long blocks_available; /* number of blocks available in the LRU chain */ + HASH_LINK **hash_root; /* arr. of entries into hash table buckets */ + HASH_LINK *hash_link_root; /* memory for hash table links */ + HASH_LINK *free_hash_list; /* list of free hash links */ + BLOCK_LINK *free_block_list; /* list of free blocks */ + BLOCK_LINK *block_root; /* memory for block links */ + uchar *block_mem; /* memory for block buffers */ + BLOCK_LINK *used_last; /* ptr to the last block of the LRU chain */ + BLOCK_LINK *used_ins; /* ptr to the insertion block in LRU chain */ + mysql_mutex_t cache_lock; /* to lock access to the cache structure */ + KEYCACHE_WQUEUE resize_queue; /* threads waiting during resize operation */ + /* + Waiting for a zero resize count. Using a queue for symmetry though + only one thread can wait here. + */ + KEYCACHE_WQUEUE waiting_for_resize_cnt; + KEYCACHE_WQUEUE waiting_for_hash_link; /* waiting for a free hash link */ + KEYCACHE_WQUEUE waiting_for_block; /* requests waiting for a free block */ + BLOCK_LINK *changed_blocks[CHANGED_BLOCKS_HASH]; /* hash for dirty file bl.*/ + BLOCK_LINK *file_blocks[CHANGED_BLOCKS_HASH]; /* hash for other file bl.*/ + + /* + The following variables are and variables used to hold parameters for + initializing the key cache. + */ + + ulonglong param_buff_size; /* size the memory allocated for the cache */ + ulonglong param_block_size; /* size of the blocks in the key cache */ + ulonglong param_division_limit; /* min. percentage of warm blocks */ + ulonglong param_age_threshold; /* determines when hot block is downgraded */ + + /* Statistics variables. These are reset in reset_key_cache_counters(). */ + ulong global_blocks_changed; /* number of currently dirty blocks */ + ulonglong global_cache_w_requests;/* number of write requests (write hits) */ + ulonglong global_cache_write; /* number of writes from cache to files */ + ulonglong global_cache_r_requests;/* number of read requests (read hits) */ + ulonglong global_cache_read; /* number of reads from files to cache */ + + int blocks; /* max number of blocks in the cache */ + my_bool in_init; /* Set to 1 in MySQL during init/resize */ +} KEY_CACHE; + +/* The default key cache */ +extern KEY_CACHE dflt_key_cache_var, *dflt_key_cache; + +extern int init_key_cache(KEY_CACHE *keycache, uint key_cache_block_size, + size_t use_mem, uint division_limit, + uint age_threshold); +extern int resize_key_cache(KEY_CACHE *keycache, uint key_cache_block_size, + size_t use_mem, uint division_limit, + uint age_threshold); +extern void change_key_cache_param(KEY_CACHE *keycache, uint division_limit, + uint age_threshold); +extern uchar *key_cache_read(KEY_CACHE *keycache, + File file, my_off_t filepos, int level, + uchar *buff, uint length, + uint block_length,int return_buffer); +extern int key_cache_insert(KEY_CACHE *keycache, + File file, my_off_t filepos, int level, + uchar *buff, uint length); +extern int key_cache_write(KEY_CACHE *keycache, + File file, my_off_t filepos, int level, + uchar *buff, uint length, + uint block_length,int force_write); +extern int flush_key_blocks(KEY_CACHE *keycache, + int file, enum flush_type type); +extern void end_key_cache(KEY_CACHE *keycache, my_bool cleanup); + +/* Functions to handle multiple key caches */ +extern my_bool multi_keycache_init(void); +extern void multi_keycache_free(void); +extern KEY_CACHE *multi_key_cache_search(uchar *key, uint length); +extern my_bool multi_key_cache_set(const uchar *key, uint length, + KEY_CACHE *key_cache); +extern void multi_key_cache_change(KEY_CACHE *old_data, + KEY_CACHE *new_data); +extern int reset_key_cache_counters(const char *name, + KEY_CACHE *key_cache); +C_MODE_END +#endif /* _keycache_h */ diff --git a/include/mysql/m_ctype.h b/include/mysql/m_ctype.h new file mode 100644 index 000000000..42e8f88cc --- /dev/null +++ b/include/mysql/m_ctype.h @@ -0,0 +1,643 @@ +/* Copyright (C) 2000 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/* + A better inplementation of the UNIX ctype(3) library. +*/ + +#ifndef _m_ctype_h +#define _m_ctype_h + +#include +#include "my_global.h" /* uint16, uchar */ + +#ifdef __cplusplus +extern "C" { +#endif + +#define MY_CS_NAME_SIZE 32 +#define MY_CS_CTYPE_TABLE_SIZE 257 +#define MY_CS_TO_LOWER_TABLE_SIZE 256 +#define MY_CS_TO_UPPER_TABLE_SIZE 256 +#define MY_CS_SORT_ORDER_TABLE_SIZE 256 +#define MY_CS_TO_UNI_TABLE_SIZE 256 + +#define CHARSET_DIR "charsets/" + +#define my_wc_t ulong + +#define MY_CS_REPLACEMENT_CHARACTER 0xFFFD + +/* + On i386 we store Unicode->CS conversion tables for + some character sets using Big-endian order, + to copy two bytes at onces. + This gives some performance improvement. +*/ +#ifdef __i386__ +#define MB2(x) (((x) >> 8) + (((x) & 0xFF) << 8)) +#define MY_PUT_MB2(s, code) { *((uint16*)(s))= (code); } +#else +#define MB2(x) (x) +#define MY_PUT_MB2(s, code) { (s)[0]= code >> 8; (s)[1]= code & 0xFF; } +#endif + + + +typedef struct unicase_info_st +{ + uint32 toupper; + uint32 tolower; + uint32 sort; +} MY_UNICASE_INFO; + + +extern MY_UNICASE_INFO *my_unicase_default[256]; +extern MY_UNICASE_INFO *my_unicase_turkish[256]; + +typedef struct uni_ctype_st +{ + uchar pctype; + uchar *ctype; +} MY_UNI_CTYPE; + +extern MY_UNI_CTYPE my_uni_ctype[256]; + +/* wm_wc and wc_mb return codes */ +#define MY_CS_ILSEQ 0 /* Wrong by sequence: wb_wc */ +#define MY_CS_ILUNI 0 /* Cannot encode Unicode to charset: wc_mb */ +#define MY_CS_TOOSMALL -101 /* Need at least one byte: wc_mb and mb_wc */ +#define MY_CS_TOOSMALL2 -102 /* Need at least two bytes: wc_mb and mb_wc */ +#define MY_CS_TOOSMALL3 -103 /* Need at least three bytes: wc_mb and mb_wc */ +/* These following three are currently not really used */ +#define MY_CS_TOOSMALL4 -104 /* Need at least 4 bytes: wc_mb and mb_wc */ +#define MY_CS_TOOSMALL5 -105 /* Need at least 5 bytes: wc_mb and mb_wc */ +#define MY_CS_TOOSMALL6 -106 /* Need at least 6 bytes: wc_mb and mb_wc */ +/* A helper macros for "need at least n bytes" */ +#define MY_CS_TOOSMALLN(n) (-100-(n)) + +#define MY_SEQ_INTTAIL 1 +#define MY_SEQ_SPACES 2 + + /* My charsets_list flags */ +#define MY_CS_COMPILED 1 /* compiled-in sets */ +#define MY_CS_CONFIG 2 /* sets that have a *.conf file */ +#define MY_CS_INDEX 4 /* sets listed in the Index file */ +#define MY_CS_LOADED 8 /* sets that are currently loaded */ +#define MY_CS_BINSORT 16 /* if binary sort order */ +#define MY_CS_PRIMARY 32 /* if primary collation */ +#define MY_CS_STRNXFRM 64 /* if strnxfrm is used for sort */ +#define MY_CS_UNICODE 128 /* is a charset is BMP Unicode */ +#define MY_CS_READY 256 /* if a charset is initialized */ +#define MY_CS_AVAILABLE 512 /* If either compiled-in or loaded*/ +#define MY_CS_CSSORT 1024 /* if case sensitive sort order */ +#define MY_CS_HIDDEN 2048 /* don't display in SHOW */ +#define MY_CS_PUREASCII 4096 /* if a charset is pure ascii */ +#define MY_CS_NONASCII 8192 /* if not ASCII-compatible */ +#define MY_CS_UNICODE_SUPPLEMENT 16384 /* Non-BMP Unicode characters */ +#define MY_CHARSET_UNDEFINED 0 + +/* Character repertoire flags */ +#define MY_REPERTOIRE_ASCII 1 /* Pure ASCII U+0000..U+007F */ +#define MY_REPERTOIRE_EXTENDED 2 /* Extended characters: U+0080..U+FFFF */ +#define MY_REPERTOIRE_UNICODE30 3 /* ASCII | EXTENDED: U+0000..U+FFFF */ + +typedef struct my_uni_idx_st +{ + uint16 from; + uint16 to; + uchar *tab; +} MY_UNI_IDX; + +typedef struct +{ + uint beg; + uint end; + uint mb_len; +} my_match_t; + +enum my_lex_states +{ + MY_LEX_START, MY_LEX_CHAR, MY_LEX_IDENT, + MY_LEX_IDENT_SEP, MY_LEX_IDENT_START, + MY_LEX_REAL, MY_LEX_HEX_NUMBER, MY_LEX_BIN_NUMBER, + MY_LEX_CMP_OP, MY_LEX_LONG_CMP_OP, MY_LEX_STRING, MY_LEX_COMMENT, MY_LEX_END, + MY_LEX_OPERATOR_OR_IDENT, MY_LEX_NUMBER_IDENT, MY_LEX_INT_OR_REAL, + MY_LEX_REAL_OR_POINT, MY_LEX_BOOL, MY_LEX_EOL, MY_LEX_ESCAPE, + MY_LEX_LONG_COMMENT, MY_LEX_END_LONG_COMMENT, MY_LEX_SEMICOLON, + MY_LEX_SET_VAR, MY_LEX_USER_END, MY_LEX_HOSTNAME, MY_LEX_SKIP, + MY_LEX_USER_VARIABLE_DELIMITER, MY_LEX_SYSTEM_VAR, + MY_LEX_IDENT_OR_KEYWORD, + MY_LEX_IDENT_OR_HEX, MY_LEX_IDENT_OR_BIN, MY_LEX_IDENT_OR_NCHAR, + MY_LEX_STRING_OR_DELIMITER +}; + +struct charset_info_st; + + +/* See strings/CHARSET_INFO.txt for information about this structure */ +typedef struct my_collation_handler_st +{ + my_bool (*init)(struct charset_info_st *, void *(*alloc)(size_t)); + /* Collation routines */ + int (*strnncoll)(struct charset_info_st *, + const uchar *, size_t, const uchar *, size_t, my_bool); + int (*strnncollsp)(struct charset_info_st *, + const uchar *, size_t, const uchar *, size_t, + my_bool diff_if_only_endspace_difference); + size_t (*strnxfrm)(struct charset_info_st *, + uchar *, size_t, const uchar *, size_t); + size_t (*strnxfrmlen)(struct charset_info_st *, size_t); + my_bool (*like_range)(struct charset_info_st *, + const char *s, size_t s_length, + pchar w_prefix, pchar w_one, pchar w_many, + size_t res_length, + char *min_str, char *max_str, + size_t *min_len, size_t *max_len); + int (*wildcmp)(struct charset_info_st *, + const char *str,const char *str_end, + const char *wildstr,const char *wildend, + int escape,int w_one, int w_many); + + int (*strcasecmp)(struct charset_info_st *, const char *, const char *); + + uint (*instr)(struct charset_info_st *, + const char *b, size_t b_length, + const char *s, size_t s_length, + my_match_t *match, uint nmatch); + + /* Hash calculation */ + void (*hash_sort)(struct charset_info_st *cs, const uchar *key, size_t len, + ulong *nr1, ulong *nr2); + my_bool (*propagate)(struct charset_info_st *cs, const uchar *str, size_t len); +} MY_COLLATION_HANDLER; + +extern MY_COLLATION_HANDLER my_collation_mb_bin_handler; +extern MY_COLLATION_HANDLER my_collation_8bit_bin_handler; +extern MY_COLLATION_HANDLER my_collation_8bit_simple_ci_handler; +extern MY_COLLATION_HANDLER my_collation_ucs2_uca_handler; + +/* Some typedef to make it easy for C++ to make function pointers */ +typedef int (*my_charset_conv_mb_wc)(struct charset_info_st *, my_wc_t *, + const uchar *, const uchar *); +typedef int (*my_charset_conv_wc_mb)(struct charset_info_st *, my_wc_t, + uchar *, uchar *); +typedef size_t (*my_charset_conv_case)(struct charset_info_st *, + char *, size_t, char *, size_t); + + +/* See strings/CHARSET_INFO.txt about information on this structure */ +typedef struct my_charset_handler_st +{ + my_bool (*init)(struct charset_info_st *, void *(*alloc)(size_t)); + /* Multibyte routines */ + uint (*ismbchar)(struct charset_info_st *, const char *, const char *); + uint (*mbcharlen)(struct charset_info_st *, uint c); + size_t (*numchars)(struct charset_info_st *, const char *b, const char *e); + size_t (*charpos)(struct charset_info_st *, const char *b, const char *e, + size_t pos); + size_t (*well_formed_len)(struct charset_info_st *, + const char *b,const char *e, + size_t nchars, int *error); + size_t (*lengthsp)(struct charset_info_st *, const char *ptr, size_t length); + size_t (*numcells)(struct charset_info_st *, const char *b, const char *e); + + /* Unicode conversion */ + my_charset_conv_mb_wc mb_wc; + my_charset_conv_wc_mb wc_mb; + + /* CTYPE scanner */ + int (*ctype)(struct charset_info_st *cs, int *ctype, + const uchar *s, const uchar *e); + + /* Functions for case and sort conversion */ + size_t (*caseup_str)(struct charset_info_st *, char *); + size_t (*casedn_str)(struct charset_info_st *, char *); + + my_charset_conv_case caseup; + my_charset_conv_case casedn; + + /* Charset dependant snprintf() */ + size_t (*snprintf)(struct charset_info_st *, char *to, size_t n, + const char *fmt, + ...) ATTRIBUTE_FORMAT_FPTR(printf, 4, 5); + size_t (*long10_to_str)(struct charset_info_st *, char *to, size_t n, + int radix, long int val); + size_t (*longlong10_to_str)(struct charset_info_st *, char *to, size_t n, + int radix, longlong val); + + void (*fill)(struct charset_info_st *, char *to, size_t len, int fill); + + /* String-to-number conversion routines */ + long (*strntol)(struct charset_info_st *, const char *s, size_t l, + int base, char **e, int *err); + ulong (*strntoul)(struct charset_info_st *, const char *s, size_t l, + int base, char **e, int *err); + longlong (*strntoll)(struct charset_info_st *, const char *s, size_t l, + int base, char **e, int *err); + ulonglong (*strntoull)(struct charset_info_st *, const char *s, size_t l, + int base, char **e, int *err); + double (*strntod)(struct charset_info_st *, char *s, size_t l, char **e, + int *err); + longlong (*strtoll10)(struct charset_info_st *cs, + const char *nptr, char **endptr, int *error); + ulonglong (*strntoull10rnd)(struct charset_info_st *cs, + const char *str, size_t length, + int unsigned_fl, + char **endptr, int *error); + size_t (*scan)(struct charset_info_st *, const char *b, const char *e, + int sq); +} MY_CHARSET_HANDLER; + +extern MY_CHARSET_HANDLER my_charset_8bit_handler; +extern MY_CHARSET_HANDLER my_charset_ucs2_handler; + + +/* + We define this CHARSET_INFO_DEFINED here to prevent a repeat of the + typedef in hash.c, which will cause a compiler error. +*/ +#define CHARSET_INFO_DEFINED + +/* See strings/CHARSET_INFO.txt about information on this structure */ +typedef struct charset_info_st +{ + uint number; + uint primary_number; + uint binary_number; + uint state; + const char *csname; + const char *name; + const char *comment; + const char *tailoring; + uchar *ctype; + uchar *to_lower; + uchar *to_upper; + uchar *sort_order; + uint16 *contractions; + uint16 **sort_order_big; + uint16 *tab_to_uni; + MY_UNI_IDX *tab_from_uni; + MY_UNICASE_INFO **caseinfo; + uchar *state_map; + uchar *ident_map; + uint strxfrm_multiply; + uchar caseup_multiply; + uchar casedn_multiply; + uint mbminlen; + uint mbmaxlen; + uint16 min_sort_char; + uint16 max_sort_char; /* For LIKE optimization */ + uchar pad_char; + my_bool escape_with_backslash_is_dangerous; + + MY_CHARSET_HANDLER *cset; + MY_COLLATION_HANDLER *coll; + +} CHARSET_INFO; +#define ILLEGAL_CHARSET_INFO_NUMBER (~0U) + + +extern MYSQL_PLUGIN_IMPORT CHARSET_INFO my_charset_bin; +extern MYSQL_PLUGIN_IMPORT CHARSET_INFO my_charset_latin1; +extern MYSQL_PLUGIN_IMPORT CHARSET_INFO my_charset_filename; + +extern CHARSET_INFO my_charset_big5_chinese_ci; +extern CHARSET_INFO my_charset_big5_bin; +extern CHARSET_INFO my_charset_cp932_japanese_ci; +extern CHARSET_INFO my_charset_cp932_bin; +extern CHARSET_INFO my_charset_cp1250_czech_ci; +extern CHARSET_INFO my_charset_eucjpms_japanese_ci; +extern CHARSET_INFO my_charset_eucjpms_bin; +extern CHARSET_INFO my_charset_euckr_korean_ci; +extern CHARSET_INFO my_charset_euckr_bin; +extern CHARSET_INFO my_charset_gb2312_chinese_ci; +extern CHARSET_INFO my_charset_gb2312_bin; +extern CHARSET_INFO my_charset_gbk_chinese_ci; +extern CHARSET_INFO my_charset_gbk_bin; +extern CHARSET_INFO my_charset_latin1_german2_ci; +extern CHARSET_INFO my_charset_latin1_bin; +extern CHARSET_INFO my_charset_latin2_czech_ci; +extern CHARSET_INFO my_charset_sjis_japanese_ci; +extern CHARSET_INFO my_charset_sjis_bin; +extern CHARSET_INFO my_charset_tis620_thai_ci; +extern CHARSET_INFO my_charset_tis620_bin; +extern CHARSET_INFO my_charset_ucs2_general_ci; +extern CHARSET_INFO my_charset_ucs2_bin; +extern CHARSET_INFO my_charset_ucs2_unicode_ci; +extern CHARSET_INFO my_charset_ujis_japanese_ci; +extern CHARSET_INFO my_charset_ujis_bin; +extern CHARSET_INFO my_charset_utf16_bin; +extern CHARSET_INFO my_charset_utf16_general_ci; +extern CHARSET_INFO my_charset_utf16_unicode_ci; +extern CHARSET_INFO my_charset_utf32_bin; +extern CHARSET_INFO my_charset_utf32_general_ci; +extern CHARSET_INFO my_charset_utf32_unicode_ci; + +extern CHARSET_INFO my_charset_utf8_general_ci; +extern CHARSET_INFO my_charset_utf8_unicode_ci; +extern CHARSET_INFO my_charset_utf8_bin; +extern CHARSET_INFO my_charset_utf8mb4_bin; +extern CHARSET_INFO my_charset_utf8mb4_general_ci; +extern CHARSET_INFO my_charset_utf8mb4_unicode_ci; +#define MY_UTF8MB3 "utf8" +#define MY_UTF8MB4 "utf8mb4" + + +/* declarations for simple charsets */ +extern size_t my_strnxfrm_simple(CHARSET_INFO *, uchar *, size_t, + const uchar *, size_t); +size_t my_strnxfrmlen_simple(CHARSET_INFO *, size_t); +extern int my_strnncoll_simple(CHARSET_INFO *, const uchar *, size_t, + const uchar *, size_t, my_bool); + +extern int my_strnncollsp_simple(CHARSET_INFO *, const uchar *, size_t, + const uchar *, size_t, + my_bool diff_if_only_endspace_difference); + +extern void my_hash_sort_simple(CHARSET_INFO *cs, + const uchar *key, size_t len, + ulong *nr1, ulong *nr2); + +extern size_t my_lengthsp_8bit(CHARSET_INFO *cs, const char *ptr, size_t length); + +extern uint my_instr_simple(struct charset_info_st *, + const char *b, size_t b_length, + const char *s, size_t s_length, + my_match_t *match, uint nmatch); + + +/* Functions for 8bit */ +extern size_t my_caseup_str_8bit(CHARSET_INFO *, char *); +extern size_t my_casedn_str_8bit(CHARSET_INFO *, char *); +extern size_t my_caseup_8bit(CHARSET_INFO *, char *src, size_t srclen, + char *dst, size_t dstlen); +extern size_t my_casedn_8bit(CHARSET_INFO *, char *src, size_t srclen, + char *dst, size_t dstlen); + +extern int my_strcasecmp_8bit(CHARSET_INFO * cs, const char *, const char *); + +int my_mb_wc_8bit(CHARSET_INFO *cs,my_wc_t *wc, const uchar *s,const uchar *e); +int my_wc_mb_8bit(CHARSET_INFO *cs,my_wc_t wc, uchar *s, uchar *e); + +int my_mb_ctype_8bit(CHARSET_INFO *,int *, const uchar *,const uchar *); +int my_mb_ctype_mb(CHARSET_INFO *,int *, const uchar *,const uchar *); + +size_t my_scan_8bit(CHARSET_INFO *cs, const char *b, const char *e, int sq); + +size_t my_snprintf_8bit(struct charset_info_st *, char *to, size_t n, + const char *fmt, ...) + ATTRIBUTE_FORMAT(printf, 4, 5); + +long my_strntol_8bit(CHARSET_INFO *, const char *s, size_t l, int base, + char **e, int *err); +ulong my_strntoul_8bit(CHARSET_INFO *, const char *s, size_t l, int base, + char **e, int *err); +longlong my_strntoll_8bit(CHARSET_INFO *, const char *s, size_t l, int base, + char **e, int *err); +ulonglong my_strntoull_8bit(CHARSET_INFO *, const char *s, size_t l, int base, + char **e, int *err); +double my_strntod_8bit(CHARSET_INFO *, char *s, size_t l,char **e, + int *err); +size_t my_long10_to_str_8bit(CHARSET_INFO *, char *to, size_t l, int radix, + long int val); +size_t my_longlong10_to_str_8bit(CHARSET_INFO *, char *to, size_t l, int radix, + longlong val); + +longlong my_strtoll10_8bit(CHARSET_INFO *cs, + const char *nptr, char **endptr, int *error); +longlong my_strtoll10_ucs2(CHARSET_INFO *cs, + const char *nptr, char **endptr, int *error); + +ulonglong my_strntoull10rnd_8bit(CHARSET_INFO *cs, + const char *str, size_t length, int + unsigned_fl, char **endptr, int *error); +ulonglong my_strntoull10rnd_ucs2(CHARSET_INFO *cs, + const char *str, size_t length, + int unsigned_fl, char **endptr, int *error); + +void my_fill_8bit(CHARSET_INFO *cs, char* to, size_t l, int fill); + +my_bool my_like_range_simple(CHARSET_INFO *cs, + const char *ptr, size_t ptr_length, + pbool escape, pbool w_one, pbool w_many, + size_t res_length, + char *min_str, char *max_str, + size_t *min_length, size_t *max_length); + +my_bool my_like_range_mb(CHARSET_INFO *cs, + const char *ptr, size_t ptr_length, + pbool escape, pbool w_one, pbool w_many, + size_t res_length, + char *min_str, char *max_str, + size_t *min_length, size_t *max_length); + +my_bool my_like_range_ucs2(CHARSET_INFO *cs, + const char *ptr, size_t ptr_length, + pbool escape, pbool w_one, pbool w_many, + size_t res_length, + char *min_str, char *max_str, + size_t *min_length, size_t *max_length); + +my_bool my_like_range_utf16(CHARSET_INFO *cs, + const char *ptr, size_t ptr_length, + pbool escape, pbool w_one, pbool w_many, + size_t res_length, + char *min_str, char *max_str, + size_t *min_length, size_t *max_length); + +my_bool my_like_range_utf32(CHARSET_INFO *cs, + const char *ptr, size_t ptr_length, + pbool escape, pbool w_one, pbool w_many, + size_t res_length, + char *min_str, char *max_str, + size_t *min_length, size_t *max_length); + +int my_wildcmp_8bit(CHARSET_INFO *, + const char *str,const char *str_end, + const char *wildstr,const char *wildend, + int escape, int w_one, int w_many); + +int my_wildcmp_bin(CHARSET_INFO *, + const char *str,const char *str_end, + const char *wildstr,const char *wildend, + int escape, int w_one, int w_many); + +size_t my_numchars_8bit(CHARSET_INFO *, const char *b, const char *e); +size_t my_numcells_8bit(CHARSET_INFO *, const char *b, const char *e); +size_t my_charpos_8bit(CHARSET_INFO *, const char *b, const char *e, size_t pos); +size_t my_well_formed_len_8bit(CHARSET_INFO *, const char *b, const char *e, + size_t pos, int *error); +uint my_mbcharlen_8bit(CHARSET_INFO *, uint c); + + +/* Functions for multibyte charsets */ +extern size_t my_caseup_str_mb(CHARSET_INFO *, char *); +extern size_t my_casedn_str_mb(CHARSET_INFO *, char *); +extern size_t my_caseup_mb(CHARSET_INFO *, char *src, size_t srclen, + char *dst, size_t dstlen); +extern size_t my_casedn_mb(CHARSET_INFO *, char *src, size_t srclen, + char *dst, size_t dstlen); +extern size_t my_caseup_mb_varlen(CHARSET_INFO *, char *src, size_t srclen, + char *dst, size_t dstlen); +extern size_t my_casedn_mb_varlen(CHARSET_INFO *, char *src, size_t srclen, + char *dst, size_t dstlen); +extern size_t my_caseup_ujis(CHARSET_INFO *, char *src, size_t srclen, + char *dst, size_t dstlen); +extern size_t my_casedn_ujis(CHARSET_INFO *, char *src, size_t srclen, + char *dst, size_t dstlen); +extern int my_strcasecmp_mb(CHARSET_INFO * cs,const char *, const char *); + +int my_wildcmp_mb(CHARSET_INFO *, + const char *str,const char *str_end, + const char *wildstr,const char *wildend, + int escape, int w_one, int w_many); +size_t my_numchars_mb(CHARSET_INFO *, const char *b, const char *e); +size_t my_numcells_mb(CHARSET_INFO *, const char *b, const char *e); +size_t my_charpos_mb(CHARSET_INFO *, const char *b, const char *e, size_t pos); +size_t my_well_formed_len_mb(CHARSET_INFO *, const char *b, const char *e, + size_t pos, int *error); +uint my_instr_mb(struct charset_info_st *, + const char *b, size_t b_length, + const char *s, size_t s_length, + my_match_t *match, uint nmatch); + +int my_strnncoll_mb_bin(CHARSET_INFO * cs, + const uchar *s, size_t slen, + const uchar *t, size_t tlen, + my_bool t_is_prefix); + +int my_strnncollsp_mb_bin(CHARSET_INFO *cs, + const uchar *a, size_t a_length, + const uchar *b, size_t b_length, + my_bool diff_if_only_endspace_difference); + +int my_wildcmp_mb_bin(CHARSET_INFO *cs, + const char *str,const char *str_end, + const char *wildstr,const char *wildend, + int escape, int w_one, int w_many); + +int my_strcasecmp_mb_bin(CHARSET_INFO * cs __attribute__((unused)), + const char *s, const char *t); + +void my_hash_sort_mb_bin(CHARSET_INFO *cs __attribute__((unused)), + const uchar *key, size_t len,ulong *nr1, ulong *nr2); + +size_t my_strnxfrm_unicode(CHARSET_INFO *, + uchar *dst, size_t dstlen, + const uchar *src, size_t srclen); + +size_t my_strnxfrm_unicode_full_bin(CHARSET_INFO *, + uchar *dst, size_t dstlen, + const uchar *src, size_t srclen); +size_t my_strnxfrmlen_unicode_full_bin(CHARSET_INFO *, size_t); + +int my_wildcmp_unicode(CHARSET_INFO *cs, + const char *str, const char *str_end, + const char *wildstr, const char *wildend, + int escape, int w_one, int w_many, + MY_UNICASE_INFO **weights); + +extern my_bool my_parse_charset_xml(const char *bug, size_t len, + int (*add)(CHARSET_INFO *cs)); +extern char *my_strchr(CHARSET_INFO *cs, const char *str, const char *end, + pchar c); + +my_bool my_propagate_simple(CHARSET_INFO *cs, const uchar *str, size_t len); +my_bool my_propagate_complex(CHARSET_INFO *cs, const uchar *str, size_t len); + + +uint my_string_repertoire(CHARSET_INFO *cs, const char *str, ulong len); +my_bool my_charset_is_ascii_based(CHARSET_INFO *cs); +my_bool my_charset_is_8bit_pure_ascii(CHARSET_INFO *cs); +uint my_charset_repertoire(CHARSET_INFO *cs); + +my_bool my_charset_is_ascii_compatible(CHARSET_INFO *cs); + +extern size_t my_vsnprintf_ex(CHARSET_INFO *cs, char *to, size_t n, + const char* fmt, va_list ap); + +#define _MY_U 01 /* Upper case */ +#define _MY_L 02 /* Lower case */ +#define _MY_NMR 04 /* Numeral (digit) */ +#define _MY_SPC 010 /* Spacing character */ +#define _MY_PNT 020 /* Punctuation */ +#define _MY_CTR 040 /* Control character */ +#define _MY_B 0100 /* Blank */ +#define _MY_X 0200 /* heXadecimal digit */ + + +#define my_isascii(c) (!((c) & ~0177)) +#define my_toascii(c) ((c) & 0177) +#define my_tocntrl(c) ((c) & 31) +#define my_toprint(c) ((c) | 64) +#define my_toupper(s,c) (char) ((s)->to_upper[(uchar) (c)]) +#define my_tolower(s,c) (char) ((s)->to_lower[(uchar) (c)]) +#define my_isalpha(s, c) (((s)->ctype+1)[(uchar) (c)] & (_MY_U | _MY_L)) +#define my_isupper(s, c) (((s)->ctype+1)[(uchar) (c)] & _MY_U) +#define my_islower(s, c) (((s)->ctype+1)[(uchar) (c)] & _MY_L) +#define my_isdigit(s, c) (((s)->ctype+1)[(uchar) (c)] & _MY_NMR) +#define my_isxdigit(s, c) (((s)->ctype+1)[(uchar) (c)] & _MY_X) +#define my_isalnum(s, c) (((s)->ctype+1)[(uchar) (c)] & (_MY_U | _MY_L | _MY_NMR)) +#define my_isspace(s, c) (((s)->ctype+1)[(uchar) (c)] & _MY_SPC) +#define my_ispunct(s, c) (((s)->ctype+1)[(uchar) (c)] & _MY_PNT) +#define my_isprint(s, c) (((s)->ctype+1)[(uchar) (c)] & (_MY_PNT | _MY_U | _MY_L | _MY_NMR | _MY_B)) +#define my_isgraph(s, c) (((s)->ctype+1)[(uchar) (c)] & (_MY_PNT | _MY_U | _MY_L | _MY_NMR)) +#define my_iscntrl(s, c) (((s)->ctype+1)[(uchar) (c)] & _MY_CTR) + +/* Some macros that should be cleaned up a little */ +#define my_isvar(s,c) (my_isalnum(s,c) || (c) == '_') +#define my_isvar_start(s,c) (my_isalpha(s,c) || (c) == '_') + +#define my_binary_compare(s) ((s)->state & MY_CS_BINSORT) +#define use_strnxfrm(s) ((s)->state & MY_CS_STRNXFRM) +#define my_strnxfrm(s, a, b, c, d) ((s)->coll->strnxfrm((s), (a), (b), (c), (d))) +#define my_strnncoll(s, a, b, c, d) ((s)->coll->strnncoll((s), (a), (b), (c), (d), 0)) +#define my_like_range(s, a, b, c, d, e, f, g, h, i, j) \ + ((s)->coll->like_range((s), (a), (b), (c), (d), (e), (f), (g), (h), (i), (j))) +#define my_wildcmp(cs,s,se,w,we,e,o,m) ((cs)->coll->wildcmp((cs),(s),(se),(w),(we),(e),(o),(m))) +#define my_strcasecmp(s, a, b) ((s)->coll->strcasecmp((s), (a), (b))) +#define my_charpos(cs, b, e, num) (cs)->cset->charpos((cs), (const char*) (b), (const char *)(e), (num)) + + +#define use_mb(s) ((s)->cset->ismbchar != NULL) +#define my_ismbchar(s, a, b) ((s)->cset->ismbchar((s), (a), (b))) +#ifdef USE_MB +#define my_mbcharlen(s, a) ((s)->cset->mbcharlen((s),(a))) +#else +#define my_mbcharlen(s, a) 1 +#endif + +#define my_caseup_str(s, a) ((s)->cset->caseup_str((s), (a))) +#define my_casedn_str(s, a) ((s)->cset->casedn_str((s), (a))) +#define my_strntol(s, a, b, c, d, e) ((s)->cset->strntol((s),(a),(b),(c),(d),(e))) +#define my_strntoul(s, a, b, c, d, e) ((s)->cset->strntoul((s),(a),(b),(c),(d),(e))) +#define my_strntoll(s, a, b, c, d, e) ((s)->cset->strntoll((s),(a),(b),(c),(d),(e))) +#define my_strntoull(s, a, b, c,d, e) ((s)->cset->strntoull((s),(a),(b),(c),(d),(e))) +#define my_strntod(s, a, b, c, d) ((s)->cset->strntod((s),(a),(b),(c),(d))) + + +/* XXX: still need to take care of this one */ +#ifdef MY_CHARSET_TIS620 +#error The TIS620 charset is broken at the moment. Tell tim to fix it. +#define USE_TIS620 +#include "t_ctype.h" +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _m_ctype_h */ diff --git a/include/mysql/m_string.h b/include/mysql/m_string.h new file mode 100644 index 000000000..d21948585 --- /dev/null +++ b/include/mysql/m_string.h @@ -0,0 +1,295 @@ +/* Copyright (C) 2000 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/* There may be prolems include all of theese. Try to test in + configure with ones are needed? */ + +/* This is needed for the definitions of strchr... on solaris */ + +#ifndef _m_string_h +#define _m_string_h + +#include "my_global.h" /* HAVE_* */ + +#ifndef __USE_GNU +#define __USE_GNU /* We want to use stpcpy */ +#endif +#if defined(HAVE_STRINGS_H) +#include +#endif +#if defined(HAVE_STRING_H) +#include +#endif + +/* need by my_vsnprintf */ +#include + +/* This is needed for the definitions of bzero... on solaris */ +#if defined(HAVE_STRINGS_H) +#include +#endif + +/* This is needed for the definitions of memcpy... on solaris */ +#if defined(HAVE_MEMORY_H) && !defined(__cplusplus) +#include +#endif + +#if !defined(HAVE_MEMCPY) && !defined(HAVE_MEMMOVE) +# define memcpy(d, s, n) bcopy ((s), (d), (n)) +# define memset(A,C,B) bfill((A),(B),(C)) +# define memmove(d, s, n) bmove ((d), (s), (n)) +#elif defined(HAVE_MEMMOVE) +# define bmove(d, s, n) memmove((d), (s), (n)) +#endif + +/* Unixware 7 */ +#if !defined(HAVE_BFILL) +# define bfill(A,B,C) memset((A),(C),(B)) +#endif + +#if !defined(bzero) && !defined(HAVE_BZERO) +# define bzero(A,B) memset((A),0,(B)) +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + +/* + my_str_malloc() and my_str_free() are assigned to implementations in + strings/alloc.c, but can be overridden in the calling program. + */ +extern void *(*my_str_malloc)(size_t); +extern void (*my_str_free)(void *); + +#if defined(HAVE_STPCPY) && MY_GNUC_PREREQ(3, 4) && !defined(__INTEL_COMPILER) +#define strmov(A,B) __builtin_stpcpy((A),(B)) +#elif defined(HAVE_STPCPY) +#define strmov(A,B) stpcpy((A),(B)) +#ifndef stpcpy +extern char *stpcpy(char *, const char *); /* For AIX with gcc 2.95.3 */ +#endif +#endif + +/* Declared in int2str() */ +extern char _dig_vec_upper[]; +extern char _dig_vec_lower[]; + +#ifndef strmov +#define strmov_overlapp(A,B) strmov(A,B) +#define strmake_overlapp(A,B,C) strmake(A,B,C) +#endif + + /* Prototypes for string functions */ + +extern void bmove_upp(uchar *dst,const uchar *src,size_t len); +extern void bchange(uchar *dst,size_t old_len,const uchar *src, + size_t new_len,size_t tot_len); +extern void strappend(char *s,size_t len,pchar fill); +extern char *strend(const char *s); +extern char *strcend(const char *, pchar); +extern char *strfill(char * s,size_t len,pchar fill); +extern char *strmake(char *dst,const char *src,size_t length); + +#ifndef strmov +extern char *strmov(char *dst,const char *src); +#else +extern char *strmov_overlapp(char *dst,const char *src); +#endif +extern char *strnmov(char *dst, const char *src, size_t n); +extern char *strcont(const char *src, const char *set); +extern char *strxmov(char *dst, const char *src, ...); +extern char *strxnmov(char *dst, size_t len, const char *src, ...); + +/* Prototypes of normal stringfunctions (with may ours) */ +#ifndef HAVE_STRNLEN +extern size_t strnlen(const char *s, size_t n); +#endif + +extern int is_prefix(const char *, const char *); + +/* Conversion routines */ +typedef enum { + MY_GCVT_ARG_FLOAT, + MY_GCVT_ARG_DOUBLE +} my_gcvt_arg_type; + +double my_strtod(const char *str, char **end, int *error); +double my_atof(const char *nptr); +size_t my_fcvt(double x, int precision, char *to, my_bool *error); +size_t my_gcvt(double x, my_gcvt_arg_type type, int width, char *to, + my_bool *error); + +#define NOT_FIXED_DEC 31 + +/* + The longest string my_fcvt can return is 311 + "precision" bytes. + Here we assume that we never cal my_fcvt() with precision >= NOT_FIXED_DEC + (+ 1 byte for the terminating '\0'). +*/ +#define FLOATING_POINT_BUFFER (311 + NOT_FIXED_DEC) + +/* + We want to use the 'e' format in some cases even if we have enough space + for the 'f' one just to mimic sprintf("%.15g") behavior for large integers, + and to improve it for numbers < 10^(-4). + That is, for |x| < 1 we require |x| >= 10^(-15), and for |x| > 1 we require + it to be integer and be <= 10^DBL_DIG for the 'f' format to be used. + We don't lose precision, but make cases like "1e200" or "0.00001" look nicer. +*/ +#define MAX_DECPT_FOR_F_FORMAT DBL_DIG + +/* + The maximum possible field width for my_gcvt() conversion. + (DBL_DIG + 2) significant digits + sign + "." + ("e-NNN" or + MAX_DECPT_FOR_F_FORMAT zeros for cases when |x|<1 and the 'f' format is used). +*/ +#define MY_GCVT_MAX_FIELD_WIDTH (DBL_DIG + 4 + max(5, MAX_DECPT_FOR_F_FORMAT)) \ + +extern char *llstr(longlong value,char *buff); +extern char *ullstr(longlong value,char *buff); +#ifndef HAVE_STRTOUL +extern long strtol(const char *str, char **ptr, int base); +extern ulong strtoul(const char *str, char **ptr, int base); +#endif + +extern char *int2str(long val, char *dst, int radix, int upcase); +extern char *int10_to_str(long val,char *dst,int radix); +extern char *str2int(const char *src,int radix,long lower,long upper, + long *val); +longlong my_strtoll10(const char *nptr, char **endptr, int *error); +#if SIZEOF_LONG == SIZEOF_LONG_LONG +#define ll2str(A,B,C,D) int2str((A),(B),(C),(D)) +#define longlong10_to_str(A,B,C) int10_to_str((A),(B),(C)) +#undef strtoll +#define strtoll(A,B,C) strtol((A),(B),(C)) +#define strtoull(A,B,C) strtoul((A),(B),(C)) +#ifndef HAVE_STRTOULL +#define HAVE_STRTOULL +#endif +#ifndef HAVE_STRTOLL +#define HAVE_STRTOLL +#endif +#else +#ifdef HAVE_LONG_LONG +extern char *ll2str(longlong val,char *dst,int radix, int upcase); +extern char *longlong10_to_str(longlong val,char *dst,int radix); +#if (!defined(HAVE_STRTOULL) || defined(NO_STRTOLL_PROTO)) +extern longlong strtoll(const char *str, char **ptr, int base); +extern ulonglong strtoull(const char *str, char **ptr, int base); +#endif +#endif +#endif +#define longlong2str(A,B,C) ll2str((A),(B),(C),1) + +#if defined(__cplusplus) +} +#endif + +/* + LEX_STRING -- a pair of a C-string and its length. + (it's part of the plugin API as a MYSQL_LEX_STRING) +*/ + +#include +typedef struct st_mysql_lex_string LEX_STRING; + +#define STRING_WITH_LEN(X) (X), ((size_t) (sizeof(X) - 1)) +#define USTRING_WITH_LEN(X) ((uchar*) X), ((size_t) (sizeof(X) - 1)) +#define C_STRING_WITH_LEN(X) ((char *) (X)), ((size_t) (sizeof(X) - 1)) + +struct st_mysql_const_lex_string +{ + const char *str; + size_t length; +}; +typedef struct st_mysql_const_lex_string LEX_CSTRING; + +/* SPACE_INT is a word that contains only spaces */ +#if SIZEOF_INT == 4 +#define SPACE_INT 0x20202020 +#elif SIZEOF_INT == 8 +#define SPACE_INT 0x2020202020202020 +#else +#error define the appropriate constant for a word full of spaces +#endif + +/** + Skip trailing space. + + On most systems reading memory in larger chunks (ideally equal to the size of + the chinks that the machine physically reads from memory) causes fewer memory + access loops and hence increased performance. + This is why the 'int' type is used : it's closest to that (according to how + it's defined in C). + So when we determine the amount of whitespace at the end of a string we do + the following : + 1. We divide the string into 3 zones : + a) from the start of the string (__start) to the first multiple + of sizeof(int) (__start_words) + b) from the end of the string (__end) to the last multiple of sizeof(int) + (__end_words) + c) a zone that is aligned to sizeof(int) and can be safely accessed + through an int * + 2. We start comparing backwards from (c) char-by-char. If all we find is + space then we continue + 3. If there are elements in zone (b) we compare them as unsigned ints to a + int mask (SPACE_INT) consisting of all spaces + 4. Finally we compare the remaining part (a) of the string char by char. + This covers for the last non-space unsigned int from 3. (if any) + + This algorithm works well for relatively larger strings, but it will slow + the things down for smaller strings (because of the additional calculations + and checks compared to the naive method). Thus the barrier of length 20 + is added. + + @param ptr pointer to the input string + @param len the length of the string + @return the last non-space character +*/ + +static inline const uchar *skip_trailing_space(const uchar *ptr,size_t len) +{ + const uchar *end= ptr + len; + + if (len > 20) + { + const uchar *end_words= (const uchar *)(intptr) + (((ulonglong)(intptr)end) / SIZEOF_INT * SIZEOF_INT); + const uchar *start_words= (const uchar *)(intptr) + ((((ulonglong)(intptr)ptr) + SIZEOF_INT - 1) / SIZEOF_INT * SIZEOF_INT); + + DBUG_ASSERT(((ulonglong)(intptr)ptr) >= SIZEOF_INT); + if (end_words > ptr) + { + while (end > end_words && end[-1] == 0x20) + end--; + if (end[-1] == 0x20 && start_words < end_words) + while (end > start_words && ((unsigned *)end)[-1] == SPACE_INT) + end -= SIZEOF_INT; + } + } + while (end > ptr && end[-1] == 0x20) + end--; + return (end); +} + +static inline void lex_string_set(LEX_STRING *lex_str, const char *c_str) +{ + lex_str->str= (char *) c_str; + lex_str->length= strlen(c_str); +} + +#endif diff --git a/include/mysql/my_alloc.h b/include/mysql/my_alloc.h new file mode 100644 index 000000000..4b1ffd3d4 --- /dev/null +++ b/include/mysql/my_alloc.h @@ -0,0 +1,60 @@ +/* Copyright (C) 2000 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/* + Data structures for mysys/my_alloc.c (root memory allocator) +*/ + +#ifndef _my_alloc_h +#define _my_alloc_h + +#define ALLOC_MAX_BLOCK_TO_DROP 4096 +#define ALLOC_MAX_BLOCK_USAGE_BEFORE_DROP 10 + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct st_used_mem +{ /* struct for once_alloc (block) */ + struct st_used_mem *next; /* Next block in use */ + unsigned int left; /* memory left in block */ + unsigned int size; /* size of block */ +} USED_MEM; + + +typedef struct st_mem_root +{ + USED_MEM *free; /* blocks with free memory in it */ + USED_MEM *used; /* blocks almost without free memory */ + USED_MEM *pre_alloc; /* preallocated block */ + /* if block have less memory it will be put in 'used' list */ + size_t min_malloc; + size_t block_size; /* initial block size */ + unsigned int block_num; /* allocated blocks counter */ + /* + first free block in queue test counter (if it exceed + MAX_BLOCK_USAGE_BEFORE_DROP block will be dropped in 'used' list) + */ + unsigned int first_block_usage; + + void (*error_handler)(void); +} MEM_ROOT; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/mysql/my_attribute.h b/include/mysql/my_attribute.h new file mode 100644 index 000000000..d35b3013b --- /dev/null +++ b/include/mysql/my_attribute.h @@ -0,0 +1,69 @@ +/* Copyright (C) 2000-2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/* + Helper macros used for setting different __attributes__ + on functions in a portable fashion +*/ + +#ifndef _my_attribute_h +#define _my_attribute_h + +#if defined(__GNUC__) +# ifndef GCC_VERSION +# define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__) +# endif +#endif + +/* + Disable __attribute__() on gcc < 2.7, g++ < 3.4, and non-gcc compilers. + Some forms of __attribute__ are actually supported in earlier versions of + g++, but we just disable them all because we only use them to generate + compilation warnings. +*/ +#ifndef __attribute__ +# if !defined(__GNUC__) +# define __attribute__(A) +# elif GCC_VERSION < 2008 +# define __attribute__(A) +# elif defined(__cplusplus) && GCC_VERSION < 3004 +# define __attribute__(A) +# endif +#endif + +/* + __attribute__((format(...))) is only supported in gcc >= 2.8 and g++ >= 3.4 + But that's already covered by the __attribute__ tests above, so this is + just a convenience macro. +*/ +#ifndef ATTRIBUTE_FORMAT +# define ATTRIBUTE_FORMAT(style, m, n) __attribute__((format(style, m, n))) +#endif + +/* + + __attribute__((format(...))) on a function pointer is not supported + until gcc 3.1 +*/ +#ifndef ATTRIBUTE_FORMAT_FPTR +# if (GCC_VERSION >= 3001) +# define ATTRIBUTE_FORMAT_FPTR(style, m, n) ATTRIBUTE_FORMAT(style, m, n) +# else +# define ATTRIBUTE_FORMAT_FPTR(style, m, n) +# endif /* GNUC >= 3.1 */ +#endif + + +#endif diff --git a/include/mysql/my_compiler.h b/include/mysql/my_compiler.h new file mode 100644 index 000000000..5f8986211 --- /dev/null +++ b/include/mysql/my_compiler.h @@ -0,0 +1,145 @@ +#ifndef MY_COMPILER_INCLUDED +#define MY_COMPILER_INCLUDED + +/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +/** + Header for compiler-dependent features. + + Intended to contain a set of reusable wrappers for preprocessor + macros, attributes, pragmas, and any other features that are + specific to a target compiler. +*/ + +#include /* stddef.h offsetof */ + +/** + Compiler-dependent internal convenience macros. +*/ + +/* GNU C/C++ */ +#if defined __GNUC__ +/* Convenience macro to test the minimum required GCC version. */ +# define MY_GNUC_PREREQ(maj, min) \ + ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) +/* Any after 2.95... */ +# define MY_ALIGN_EXT +/* Comunicate to the compiler the unreachability of the code. */ +# if MY_GNUC_PREREQ(4,5) +# define MY_ASSERT_UNREACHABLE() __builtin_unreachable() +# endif + +/* Microsoft Visual C++ */ +#elif defined _MSC_VER +# define MY_ALIGNOF(type) __alignof(type) +# define MY_ALIGNED(n) __declspec(align(n)) + +/* Oracle Solaris Studio */ +#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) +# if __SUNPRO_C >= 0x590 +# define MY_ALIGN_EXT +# endif + +/* IBM XL C/C++ */ +#elif defined __xlC__ +# if __xlC__ >= 0x0600 +# define MY_ALIGN_EXT +# endif + +/* HP aCC */ +#elif defined(__HP_aCC) || defined(__HP_cc) +# if (__HP_aCC >= 60000) || (__HP_cc >= 60000) +# define MY_ALIGN_EXT +# endif +#endif + +#ifdef MY_ALIGN_EXT +/** Specifies the minimum alignment of a type. */ +# define MY_ALIGNOF(type) __alignof__(type) +/** Determine the alignment requirement of a type. */ +# define MY_ALIGNED(n) __attribute__((__aligned__((n)))) +#endif + +/** + Generic (compiler-independent) features. +*/ + +#ifndef MY_GNUC_PREREQ +# define MY_GNUC_PREREQ(maj, min) (0) +#endif + +#ifndef MY_ALIGNOF +# ifdef __cplusplus + template struct my_alignof_helper { char m1; type m2; }; + /* Invalid for non-POD types, but most compilers give the right answer. */ +# define MY_ALIGNOF(type) offsetof(my_alignof_helper, m2) +# else +# define MY_ALIGNOF(type) offsetof(struct { char m1; type m2; }, m2) +# endif +#endif + +#ifndef MY_ASSERT_UNREACHABLE +# define MY_ASSERT_UNREACHABLE() do { assert(0); } while (0) +#endif + +/** + C++ Type Traits +*/ + +#ifdef __cplusplus + +/** + Opaque storage with a particular alignment. +*/ +# if defined(MY_ALIGNED) +/* Partial specialization used due to MSVC++. */ +template struct my_alignment_imp; +template<> struct MY_ALIGNED(1) my_alignment_imp<1> {}; +template<> struct MY_ALIGNED(2) my_alignment_imp<2> {}; +template<> struct MY_ALIGNED(4) my_alignment_imp<4> {}; +template<> struct MY_ALIGNED(8) my_alignment_imp<8> {}; +template<> struct MY_ALIGNED(16) my_alignment_imp<16> {}; +/* ... expand as necessary. */ +# else +template +struct my_alignment_imp { double m1; }; +# endif + +/** + A POD type with a given size and alignment. + + @remark If the compiler does not support a alignment attribute + (MY_ALIGN macro), the default alignment of a double is + used instead. + + @tparam size The minimum size. + @tparam alignment The desired alignment: 1, 2, 4, 8 or 16. +*/ +template +struct my_aligned_storage +{ + union + { + char data[size]; + my_alignment_imp align; + }; +}; + +#endif /* __cplusplus */ + +#include + +#endif /* MY_COMPILER_INCLUDED */ diff --git a/include/mysql/my_config.h b/include/mysql/my_config.h new file mode 100644 index 000000000..a63d23cb0 --- /dev/null +++ b/include/mysql/my_config.h @@ -0,0 +1,617 @@ +/* Copyright (C) 2009 Sun Microsystems, Inc + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#ifndef MY_CONFIG_H +#define MY_CONFIG_H +#define DOT_FRM_VERSION 6 +/* Headers we may want to use. */ +#define STDC_HEADERS 1 +#define _GNU_SOURCE 1 +#define HAVE_ALLOCA_H 1 +#define HAVE_AIO_H 1 +#define HAVE_ARPA_INET_H 1 +#define HAVE_ASM_MSR_H 1 +#define HAVE_ASM_TERMBITS_H 1 +#define HAVE_BSEARCH 1 +#define HAVE_CRYPT_H 1 +#define HAVE_CURSES_H 1 +/* #undef HAVE_CXXABI_H */ +/* #undef HAVE_NCURSES_H */ +/* #undef HAVE_NDIR_H */ +#define HAVE_DIRENT_H 1 +#define HAVE_DLFCN_H 1 +#define HAVE_EXECINFO_H 1 +#define HAVE_FCNTL_H 1 +#define HAVE_FENV_H 1 +#define HAVE_FLOAT_H 1 +/* #undef HAVE_FLOATINGPOINT_H */ +#define HAVE_FNMATCH_H 1 +#define HAVE_FPU_CONTROL_H 1 +#define HAVE_GRP_H 1 +#define HAVE_EXPLICIT_TEMPLATE_INSTANTIATION 1 +/* #undef HAVE_IA64INTRIN_H */ +/* #undef HAVE_IEEEFP_H */ +#define HAVE_INTTYPES_H 1 +#define HAVE_LIMITS_H 1 +#define HAVE_LOCALE_H 1 +#define HAVE_MALLOC_H 1 +#define HAVE_MEMORY_H 1 +#define HAVE_NETINET_IN_H 1 +#define HAVE_PATHS_H 1 +#define HAVE_POLL_H 1 +/* #undef HAVE_PORT_H */ +#define HAVE_PWD_H 1 +#define HAVE_SCHED_H 1 +/* #undef HAVE_SELECT_H */ +/* #undef HAVE_SOLARIS_LARGE_PAGES */ +#define HAVE_STDDEF_H 1 +#define HAVE_STDLIB_H 1 +#define HAVE_STDARG_H 1 +#define HAVE_STRINGS_H 1 +#define HAVE_STRING_H 1 +#define HAVE_STDINT_H 1 +#define HAVE_SEMAPHORE_H 1 +/* #undef HAVE_SYNCH_H */ +/* #undef HAVE_SYSENT_H */ +#define HAVE_SYS_DIR_H 1 +#define HAVE_SYS_CDEFS_H 1 +#define HAVE_SYS_FILE_H 1 +/* #undef HAVE_SYS_FPU_H */ +#define HAVE_SYS_IOCTL_H 1 +#define HAVE_SYS_IPC_H 1 +/* #undef HAVE_SYS_MALLOC_H */ +#define HAVE_SYS_MMAN_H 1 +/* #undef HAVE_SYS_NDIR_H */ +/* #undef HAVE_SYS_PTE_H */ +/* #undef HAVE_SYS_PTEM_H */ +#define HAVE_SYS_PRCTL_H 1 +#define HAVE_SYS_RESOURCE_H 1 +#define HAVE_SYS_SELECT_H 1 +#define HAVE_SYS_SHM_H 1 +#define HAVE_SYS_SOCKET_H 1 +#define HAVE_SYS_STAT_H 1 +/* #undef HAVE_SYS_STREAM_H */ +/* #undef HAVE_SYS_TERMCAP_H */ +#define HAVE_SYS_TIMEB_H 1 +#define HAVE_SYS_TIMES_H 1 +#define HAVE_SYS_TIME_H 1 +#define HAVE_SYS_TYPES_H 1 +#define HAVE_SYS_UN_H 1 +/* #undef HAVE_SYS_VADVISE_H */ +#define HAVE_TERM_H 1 +/* #undef HAVE_TERMBITS_H */ +#define HAVE_TERMIOS_H 1 +#define HAVE_TERMIO_H 1 +#define HAVE_TERMCAP_H 1 +#define HAVE_TIME_H 1 +#define HAVE_UNISTD_H 1 +#define HAVE_UTIME_H 1 +/* #undef HAVE_VARARGS_H */ +/* #undef HAVE_VIS_H */ +/* #undef HAVE_SYS_UTIME_H */ +#define HAVE_SYS_WAIT_H 1 +#define HAVE_SYS_PARAM_H 1 + +/* Libraries */ +/* #undef HAVE_LIBPTHREAD */ +#define HAVE_LIBM 1 +#define HAVE_LIBDL 1 +#define HAVE_LIBRT 1 +/* #undef HAVE_LIBSOCKET */ +/* #undef HAVE_LIBNSL */ +#define HAVE_LIBCRYPT 1 +/* #undef HAVE_LIBMTMALLOC */ +/* #undef HAVE_LIBWRAP */ +/* Does "struct timespec" have a "sec" and "nsec" field? */ +/* #undef HAVE_TIMESPEC_TS_SEC */ + +/* Readline */ +#define HAVE_HIST_ENTRY 1 +#define USE_LIBEDIT_INTERFACE 1 +/* #undef USE_NEW_READLINE_INTERFACE */ + +#define FIONREAD_IN_SYS_IOCTL 1 +#define GWINSZ_IN_SYS_IOCTL 1 +/* #undef TIOCSTAT_IN_SYS_IOCTL */ + +/* Functions we may want to use. */ +/* #undef HAVE_AIOWAIT */ +#define HAVE_ALARM 1 +#define HAVE_ALLOCA 1 +/* #undef HAVE_BFILL */ +/* #undef HAVE_BMOVE */ +#define HAVE_BZERO 1 +#define HAVE_INDEX 1 +#define HAVE_CHOWN 1 +#define HAVE_CLOCK_GETTIME 1 +#define HAVE_CRYPT 1 +#define HAVE_CUSERID 1 +#define HAVE_CXX_NEW 1 +/* #undef HAVE_DIRECTIO */ +#define HAVE_DLERROR 1 +#define HAVE_DLOPEN 1 +/* #undef HAVE_DOPRNT */ +#define HAVE_FCHMOD 1 +#define HAVE_FCNTL 1 +/* #undef HAVE_FCONVERT */ +#define HAVE_FDATASYNC 1 +#define HAVE_FESETROUND 1 +#define HAVE_FINITE 1 +/* #undef HAVE_FP_EXCEPT */ +/* #undef HAVE_FPSETMASK */ +#define HAVE_FSEEKO 1 +#define HAVE_FSYNC 1 +#define HAVE_FTIME 1 +#define HAVE_GETADDRINFO 1 +#define HAVE_GETCWD 1 +#define HAVE_GETHOSTBYADDR_R 1 +#define HAVE_GETHOSTBYNAME_R 1 +/* #undef HAVE_GETHRTIME */ +#define HAVE_GETLINE 1 +#define HAVE_GETNAMEINFO 1 +#define HAVE_GETPAGESIZE 1 +#define HAVE_GETPASS 1 +/* #undef HAVE_GETPASSPHRASE */ +#define HAVE_GETPWNAM 1 +#define HAVE_GETPWUID 1 +#define HAVE_GETRLIMIT 1 +#define HAVE_GETRUSAGE 1 +#define HAVE_GETTIMEOFDAY 1 +#define HAVE_GETWD 1 +#define HAVE_GMTIME_R 1 +/* #undef gmtime_r */ +#define HAVE_INITGROUPS 1 +/* #undef HAVE_ISSETUGID */ +#define HAVE_ISNAN 1 +#define HAVE_ISINF 1 +#define HAVE_LARGE_PAGE_OPTION 1 +#define HAVE_LDIV 1 +#define HAVE_LRAND48 1 +#define HAVE_LOCALTIME_R 1 +/* #undef HAVE_LOG2 */ +#define HAVE_LONGJMP 1 +#define HAVE_LSTAT 1 +#define HAVE_MEMALIGN 1 +/* #define HAVE_MLOCK 1 see Bug#54662 */ +#define HAVE_NPTL 1 +#define HAVE_NL_LANGINFO 1 +#define HAVE_MADVISE 1 +#define HAVE_DECL_MADVISE 1 +#define HAVE_DECL_TGOTO 1 +/* #undef HAVE_DECL_MHA_MAPSIZE_VA */ +#define HAVE_MALLINFO 1 +#define HAVE_MEMCPY 1 +#define HAVE_MEMMOVE 1 +#define HAVE_MKSTEMP 1 +#define HAVE_MLOCKALL 1 +#define HAVE_MMAP 1 +#define HAVE_MMAP64 1 +#define HAVE_PERROR 1 +#define HAVE_POLL 1 +/* #undef HAVE_PORT_CREATE */ +#define HAVE_POSIX_FALLOCATE 1 +#define HAVE_PREAD 1 +#define HAVE_PAUSE_INSTRUCTION 1 +/* #undef HAVE_FAKE_PAUSE_INSTRUCTION */ +/* #undef HAVE_RDTSCLL */ +/* #undef HAVE_READ_REAL_TIME */ +/* #undef HAVE_PTHREAD_ATTR_CREATE */ +#define HAVE_PTHREAD_ATTR_GETSTACKSIZE 1 +/* #undef HAVE_PTHREAD_ATTR_SETPRIO */ +/* #undef HAVE_PTHREAD_ATTR_SETSCHEDPARAM */ +#define HAVE_PTHREAD_ATTR_SETSCOPE 1 +#define HAVE_PTHREAD_ATTR_SETSTACKSIZE 1 +/* #undef HAVE_PTHREAD_CONDATTR_CREATE */ +#define HAVE_PTHREAD_CONDATTR_SETCLOCK 1 +/* #undef HAVE_PTHREAD_INIT */ +#define HAVE_PTHREAD_KEY_DELETE 1 +#define HAVE_PTHREAD_KEY_DELETE 1 +/* #undef HAVE_PTHREAD_KILL */ +#define HAVE_PTHREAD_RWLOCK_RDLOCK 1 +/* #undef HAVE_PTHREAD_SETPRIO_NP */ +/* #undef HAVE_PTHREAD_SETSCHEDPARAM */ +#define HAVE_PTHREAD_SIGMASK 1 +/* #undef HAVE_PTHREAD_THREADMASK */ +/* #undef HAVE_PTHREAD_YIELD_NP */ +#define HAVE_PTHREAD_YIELD_ZERO_ARG 1 +#define HAVE_PUTENV 1 +#define HAVE_RE_COMP 1 +#define HAVE_REGCOMP 1 +#define HAVE_READDIR_R 1 +#define HAVE_READLINK 1 +#define HAVE_REALPATH 1 +#define HAVE_RENAME 1 +#define HAVE_RINT 1 +/* #undef HAVE_RWLOCK_INIT */ +#define HAVE_SCHED_YIELD 1 +#define HAVE_SELECT 1 +/* #undef HAVE_SETFD */ +#define HAVE_SETENV 1 +#define HAVE_SETLOCALE 1 +#define HAVE_SIGADDSET 1 +#define HAVE_SIGEMPTYSET 1 +#define HAVE_SIGHOLD 1 +#define HAVE_SIGSET 1 +#define HAVE_SIGSET_T 1 +#define HAVE_SIGACTION 1 +/* #undef HAVE_SIGTHREADMASK */ +#define HAVE_SIGWAIT 1 +#define HAVE_SLEEP 1 +#define HAVE_SNPRINTF 1 +#define HAVE_STPCPY 1 +#define HAVE_STRERROR 1 +#define HAVE_STRCOLL 1 +#define HAVE_STRSIGNAL 1 +/* #undef HAVE_STRLCPY */ +/* #undef HAVE_STRLCAT */ +/* #undef HAVE_FGETLN */ +#define HAVE_STRNLEN 1 +#define HAVE_STRPBRK 1 +#define HAVE_STRSEP 1 +#define HAVE_STRSTR 1 +#define HAVE_STRTOK_R 1 +#define HAVE_STRTOL 1 +#define HAVE_STRTOLL 1 +#define HAVE_STRTOUL 1 +#define HAVE_STRTOULL 1 +#define HAVE_SHMAT 1 +#define HAVE_SHMCTL 1 +#define HAVE_SHMDT 1 +#define HAVE_SHMGET 1 +/* #undef HAVE_TELL */ +#define HAVE_TEMPNAM 1 +/* #undef HAVE_THR_SETCONCURRENCY */ +/* #undef HAVE_THR_YIELD */ +#define HAVE_TIME 1 +#define HAVE_TIMES 1 +#define HAVE_VALLOC 1 +#define HAVE_VIO_READ_BUFF 1 +#define HAVE_VASPRINTF 1 +#define HAVE_VPRINTF 1 +#define HAVE_VSNPRINTF 1 +#define HAVE_FTRUNCATE 1 +#define HAVE_TZNAME 1 +#define HAVE_AIO_READ 1 +/* Symbols we may use */ +#define HAVE_SYS_ERRLIST 1 +/* used by stacktrace functions */ +#define HAVE_BSS_START 1 +#define HAVE_BACKTRACE 1 +#define HAVE_BACKTRACE_SYMBOLS 1 +#define HAVE_BACKTRACE_SYMBOLS_FD 1 +/* #undef HAVE_PRINTSTACK */ +#define HAVE_STRUCT_SOCKADDR_IN6 1 +#define HAVE_STRUCT_IN6_ADDR 1 +/* #undef HAVE_NETINET_IN6_H */ +#define HAVE_IPV6 1 +/* #undef ss_family */ +/* #undef HAVE_SOCKADDR_IN_SIN_LEN */ +/* #undef HAVE_SOCKADDR_IN6_SIN6_LEN */ +/* #undef HAVE_TIMESPEC_TS_SEC */ +#define STRUCT_DIRENT_HAS_D_INO 1 +/* #undef STRUCT_DIRENT_HAS_D_NAMLEN */ +#define SPRINTF_RETURNS_INT 1 + +#define USE_MB 1 +#define USE_MB_IDENT 1 + +/* #undef HAVE_VALGRIND */ + +/* Types we may use */ +#ifdef __APPLE__ + /* + Special handling required for OSX to support universal binaries that + mix 32 and 64 bit architectures. + */ + #if(__LP64__) + #define SIZEOF_LONG 8 + #else + #define SIZEOF_LONG 4 + #endif + #define SIZEOF_VOIDP SIZEOF_LONG + #define SIZEOF_CHARP SIZEOF_LONG + #define SIZEOF_SIZE_T SIZEOF_LONG +#else +/* No indentation, to fetch the lines from verification scripts */ +#define SIZEOF_LONG 8 +#define SIZEOF_VOIDP 8 +#define SIZEOF_CHARP 8 +#define SIZEOF_SIZE_T 8 +#endif + +#define SIZEOF_CHAR 1 +#define HAVE_CHAR 1 +#define HAVE_LONG 1 +#define HAVE_CHARP 1 +#define SIZEOF_SHORT 2 +#define HAVE_SHORT 1 +#define SIZEOF_INT 4 +#define HAVE_INT 1 +#define SIZEOF_LONG_LONG 8 +#define HAVE_LONG_LONG 1 +#define SIZEOF_OFF_T 8 +#define HAVE_OFF_T 1 +#define SIZEOF_SIGSET_T 128 +#define HAVE_SIGSET_T 1 +#define HAVE_SIZE_T 1 +/* #undef SIZEOF_UCHAR */ +/* #undef HAVE_UCHAR */ +#define SIZEOF_UINT 4 +#define HAVE_UINT 1 +#define SIZEOF_ULONG 8 +#define HAVE_ULONG 1 +/* #undef SIZEOF_INT8 */ +/* #undef HAVE_INT8 */ +/* #undef SIZEOF_UINT8 */ +/* #undef HAVE_UINT8 */ +/* #undef SIZEOF_INT16 */ +/* #undef HAVE_INT16 */ +/* #undef SIZEOF_UINT16 */ +/* #undef HAVE_UINT16 */ +/* #undef SIZEOF_INT32 */ +/* #undef HAVE_INT32 */ +/* #undef SIZEOF_UINT32 */ +/* #undef HAVE_UINT32 */ +#define SIZEOF_U_INT32_T 4 +#define HAVE_U_INT32_T 1 +/* #undef SIZEOF_INT64 */ +/* #undef HAVE_INT64 */ +/* #undef SIZEOF_UINT64 */ +/* #undef HAVE_UINT64 */ +/* #undef SIZEOF_BOOL */ +/* #undef HAVE_BOOL */ + +#define SOCKET_SIZE_TYPE socklen_t + +#define HAVE_MBSTATE_T + +#define MAX_INDEXES 64 + +#define QSORT_TYPE_IS_VOID 1 +#define RETQSORTTYPE void + +#define SIGNAL_RETURN_TYPE_IS_VOID 1 +#define RETSIGTYPE void +#define VOID_SIGHANDLER 1 +#define STRUCT_RLIMIT struct rlimit + +#ifdef __APPLE__ + #if __BIG_ENDIAN + #define WORDS_BIGENDIAN 1 + #endif +#else +/* #undef WORDS_BIGENDIAN */ +#endif + +/* Define to `__inline__' or `__inline' if that's what the C compiler calls + it, or to nothing if 'inline' is not supported under any name. */ +#define C_HAS_inline 1 +#if !(C_HAS_inline) +#ifndef __cplusplus +# define inline +#endif +#endif + + +#define TARGET_OS_LINUX 1 +/* #undef TARGET_OS_SOLARIS */ + +#define HAVE_WCTYPE_H 1 +#define HAVE_WCHAR_H 1 +#define HAVE_LANGINFO_H 1 +#define HAVE_MBRLEN +/* #undef HAVE_MBSCMP */ +#define HAVE_MBSRTOWCS +#define HAVE_WCRTOMB +#define HAVE_MBRTOWC +#define HAVE_WCSCOLL +#define HAVE_WCSDUP +#define HAVE_WCWIDTH +#define HAVE_WCTYPE +#define HAVE_ISWLOWER 1 +#define HAVE_ISWUPPER 1 +#define HAVE_TOWLOWER 1 +#define HAVE_TOWUPPER 1 +#define HAVE_ISWCTYPE 1 +#define HAVE_WCHAR_T 1 +#define HAVE_WCTYPE_T 1 +#define HAVE_WINT_T 1 + + +#define HAVE_STRCASECMP 1 +#define HAVE_STRNCASECMP 1 +#define HAVE_STRDUP 1 +#define HAVE_LANGINFO_CODESET +#define HAVE_TCGETATTR 1 +#define HAVE_FLOCKFILE 1 + +#define HAVE_WEAK_SYMBOL 1 +/* #undef HAVE_ABI_CXA_DEMANGLE */ + + +#define HAVE_POSIX_SIGNALS 1 +/* #undef HAVE_BSD_SIGNALS */ +/* #undef HAVE_SVR3_SIGNALS */ +/* #undef HAVE_V7_SIGNALS */ + + +/* #undef HAVE_SOLARIS_STYLE_GETHOST */ +#define HAVE_GETHOSTBYNAME_R_GLIBC2_STYLE 1 +/* #undef HAVE_GETHOSTBYNAME_R_RETURN_INT */ + +/* #undef MY_ATOMIC_MODE_DUMMY */ +/* #undef MY_ATOMIC_MODE_RWLOCKS */ +#define HAVE_GCC_ATOMIC_BUILTINS 1 +/* #undef HAVE_SOLARIS_ATOMIC */ +#define HAVE_DECL_SHM_HUGETLB 1 +#define HAVE_LARGE_PAGES 1 +#define HUGETLB_USE_PROC_MEMINFO 1 +/* #undef NO_FCNTL_NONBLOCK */ +#define NO_ALARM 1 + +/* #undef _LARGE_FILES */ +#define _LARGEFILE_SOURCE 1 +/* #undef _LARGEFILE64_SOURCE */ +#define _FILE_OFFSET_BITS 64 + +#define TIME_WITH_SYS_TIME 1 + +#define STACK_DIRECTION -1 + +#define THREAD 1 +#define THREAD_SAFE_CLIENT 1 + +#define SYSTEM_TYPE "Linux" +#define MACHINE_TYPE "x86_64" +/* #undef HAVE_DTRACE */ + +#define SIGNAL_WITH_VIO_CLOSE 1 + +/* Windows stuff, mostly functions, that have Posix analogs but named differently */ +/* #undef S_IROTH */ +/* #undef S_IFIFO */ +/* #undef IPPROTO_IPV6 */ +/* #undef IPV6_V6ONLY */ +/* #undef sigset_t */ +/* #undef mode_t */ +/* #undef SIGQUIT */ +/* #undef SIGPIPE */ +/* #undef isnan */ +/* #undef finite */ +/* #undef popen */ +/* #undef pclose */ +/* #undef ssize_t */ +/* #undef strcasecmp */ +/* #undef strncasecmp */ +/* #undef snprintf */ +/* #undef strtok_r */ +/* #undef strtoll */ +/* #undef strtoull */ +/* #undef vsnprintf */ +#if (_MSC_VER > 1310) +# define HAVE_SETENV +#define setenv(a,b,c) _putenv_s(a,b) +#endif + + + + +/* + MySQL features +*/ +/* #undef ENABLED_LOCAL_INFILE */ +#define ENABLED_PROFILING 1 +/* #undef EXTRA_DEBUG */ +/* #undef BACKUP_TEST */ +/* #undef CYBOZU */ + +/* Character sets and collations */ +#define MYSQL_DEFAULT_CHARSET_NAME "latin1" +#define MYSQL_DEFAULT_COLLATION_NAME "latin1_swedish_ci" + +#define USE_MB 1 +#define USE_MB_IDENT 1 +/* #undef USE_STRCOLL */ + +/* This should mean case insensitive file system */ +/* #undef FN_NO_CASE_SENSE */ + +#define HAVE_CHARSET_armscii8 1 +#define HAVE_CHARSET_ascii 1 +#define HAVE_CHARSET_big5 1 +#define HAVE_CHARSET_cp1250 1 +#define HAVE_CHARSET_cp1251 1 +#define HAVE_CHARSET_cp1256 1 +#define HAVE_CHARSET_cp1257 1 +#define HAVE_CHARSET_cp850 1 +#define HAVE_CHARSET_cp852 1 +#define HAVE_CHARSET_cp866 1 +#define HAVE_CHARSET_cp932 1 +#define HAVE_CHARSET_dec8 1 +#define HAVE_CHARSET_eucjpms 1 +#define HAVE_CHARSET_euckr 1 +#define HAVE_CHARSET_gb2312 1 +#define HAVE_CHARSET_gbk 1 +#define HAVE_CHARSET_geostd8 1 +#define HAVE_CHARSET_greek 1 +#define HAVE_CHARSET_hebrew 1 +#define HAVE_CHARSET_hp8 1 +#define HAVE_CHARSET_keybcs2 1 +#define HAVE_CHARSET_koi8r 1 +#define HAVE_CHARSET_koi8u 1 +#define HAVE_CHARSET_latin1 1 +#define HAVE_CHARSET_latin2 1 +#define HAVE_CHARSET_latin5 1 +#define HAVE_CHARSET_latin7 1 +#define HAVE_CHARSET_macce 1 +#define HAVE_CHARSET_macroman 1 +#define HAVE_CHARSET_sjis 1 +#define HAVE_CHARSET_swe7 1 +#define HAVE_CHARSET_tis620 1 +#define HAVE_CHARSET_ucs2 1 +#define HAVE_CHARSET_ujis 1 +#define HAVE_CHARSET_utf8mb4 1 +/* #undef HAVE_CHARSET_utf8mb3 */ +#define HAVE_CHARSET_utf8 1 +#define HAVE_CHARSET_utf16 1 +#define HAVE_CHARSET_utf32 1 +#define HAVE_UCA_COLLATIONS 1 +#define HAVE_COMPRESS 1 + + +/* + Stuff that always need to be defined (compile breaks without it) +*/ +#define HAVE_SPATIAL 1 +#define HAVE_RTREE_KEYS 1 +#define HAVE_QUERY_CACHE 1 +#define BIG_TABLES 1 + +/* + Important storage engines (those that really need define + WITH__STORAGE_ENGINE for the whole server) +*/ +#define WITH_MYISAM_STORAGE_ENGINE 1 +#define WITH_MYISAMMRG_STORAGE_ENGINE 1 +#define WITH_HEAP_STORAGE_ENGINE 1 +#define WITH_CSV_STORAGE_ENGINE 1 +#define WITH_PARTITION_STORAGE_ENGINE 1 +#define WITH_PERFSCHEMA_STORAGE_ENGINE 1 +/* #undef WITH_NDBCLUSTER_STORAGE_ENGINE */ +#if (WITH_NDBCLUSTER_STORAGE_ENGINE) && !defined(EMBEDDED_LIBRARY) +# define HAVE_NDB_BINLOG 1 +#endif + +#define DEFAULT_MYSQL_HOME "/usr/local/mysql" +#define SHAREDIR "/usr/local/mysql/share" +#define DEFAULT_BASEDIR "/usr/local/mysql" +#define MYSQL_DATADIR "/usr/local/mysql/data" +#define DEFAULT_CHARSET_HOME "/usr/local/mysql" +#define PLUGINDIR "/usr/local/mysql/lib/plugin" +#define DEFAULT_SYSCONFDIR "/usr/local/mysql/etc" + +/* #undef SO_EXT */ + +#define PACKAGE "mysql" +#define PACKAGE_BUGREPORT "" +#define PACKAGE_NAME "MySQL Server" +#define PACKAGE_STRING "MySQL Server 5.5.8" +#define PACKAGE_TARNAME "mysql" +#define PACKAGE_VERSION "5.5.8" +#define VERSION "5.5.8" +#define PROTOCOL_VERSION 10 + + +#endif diff --git a/include/mysql/my_dbug.h b/include/mysql/my_dbug.h new file mode 100644 index 000000000..e1cb32526 --- /dev/null +++ b/include/mysql/my_dbug.h @@ -0,0 +1,193 @@ +/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifndef MY_DBUG_INCLUDED +#define MY_DBUG_INCLUDED + +#ifndef __WIN__ +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#endif /* not __WIN__ */ + +#ifdef __cplusplus +extern "C" { +#endif +#if !defined(DBUG_OFF) && !defined(_lint) + +struct _db_stack_frame_ { + const char *func; /* function name of the previous stack frame */ + const char *file; /* filename of the function of previous frame */ + uint level; /* this nesting level, highest bit enables tracing */ + struct _db_stack_frame_ *prev; /* pointer to the previous frame */ +}; + +struct _db_code_state_; +extern my_bool _dbug_on_; +extern my_bool _db_keyword_(struct _db_code_state_ *, const char *, int); +extern int _db_explain_(struct _db_code_state_ *cs, char *buf, size_t len); +extern int _db_explain_init_(char *buf, size_t len); +extern int _db_is_pushed_(void); +extern void _db_setjmp_(void); +extern void _db_longjmp_(void); +extern void _db_process_(const char *name); +extern void _db_push_(const char *control); +extern void _db_pop_(void); +extern void _db_set_(const char *control); +extern void _db_set_init_(const char *control); +extern void _db_enter_(const char *_func_, const char *_file_, uint _line_, + struct _db_stack_frame_ *_stack_frame_); +extern void _db_return_(uint _line_, struct _db_stack_frame_ *_stack_frame_); +extern void _db_pargs_(uint _line_,const char *keyword); +extern void _db_doprnt_(const char *format,...) + ATTRIBUTE_FORMAT(printf, 1, 2); +extern void _db_dump_(uint _line_,const char *keyword, + const unsigned char *memory, size_t length); +extern void _db_end_(void); +extern void _db_lock_file_(void); +extern void _db_unlock_file_(void); +extern FILE *_db_fp_(void); +extern void _db_flush_(); +extern const char* _db_get_func_(void); + +#define DBUG_ENTER(a) struct _db_stack_frame_ _db_stack_frame_; \ + _db_enter_ (a,__FILE__,__LINE__,&_db_stack_frame_) +#define DBUG_LEAVE _db_return_ (__LINE__, &_db_stack_frame_) +#define DBUG_RETURN(a1) do {DBUG_LEAVE; return(a1);} while(0) +#define DBUG_VOID_RETURN do {DBUG_LEAVE; return;} while(0) +#define DBUG_EXECUTE(keyword,a1) \ + do {if (_db_keyword_(0, (keyword), 0)) { a1 }} while(0) +#define DBUG_EXECUTE_IF(keyword,a1) \ + do {if (_db_keyword_(0, (keyword), 1)) { a1 }} while(0) +#define DBUG_EVALUATE(keyword,a1,a2) \ + (_db_keyword_(0,(keyword), 0) ? (a1) : (a2)) +#define DBUG_EVALUATE_IF(keyword,a1,a2) \ + (_db_keyword_(0,(keyword), 1) ? (a1) : (a2)) +#define DBUG_PRINT(keyword,arglist) \ + do {_db_pargs_(__LINE__,keyword); _db_doprnt_ arglist;} while(0) +#define DBUG_PUSH(a1) _db_push_ (a1) +#define DBUG_POP() _db_pop_ () +#define DBUG_SET(a1) _db_set_ (a1) +#define DBUG_SET_INITIAL(a1) _db_set_init_ (a1) +#define DBUG_PROCESS(a1) _db_process_(a1) +#define DBUG_FILE _db_fp_() +#define DBUG_SETJMP(a1) (_db_setjmp_ (), setjmp (a1)) +#define DBUG_LONGJMP(a1,a2) (_db_longjmp_ (), longjmp (a1, a2)) +#define DBUG_DUMP(keyword,a1,a2) _db_dump_(__LINE__,keyword,a1,a2) +#define DBUG_END() _db_end_ () +#define DBUG_LOCK_FILE _db_lock_file_() +#define DBUG_UNLOCK_FILE _db_unlock_file_() +#define DBUG_ASSERT(A) assert(A) +#define DBUG_EXPLAIN(buf,len) _db_explain_(0, (buf),(len)) +#define DBUG_EXPLAIN_INITIAL(buf,len) _db_explain_init_((buf),(len)) +#define DEBUGGER_OFF do { _dbug_on_= 0; } while(0) +#define DEBUGGER_ON do { _dbug_on_= 1; } while(0) +#ifndef __WIN__ +#define DBUG_ABORT() (_db_flush_(), abort()) +#else +/* + Avoid popup with abort/retry/ignore buttons. When BUG#31745 is fixed we can + call abort() instead of _exit(3) (now it would cause a "test signal" popup). +*/ +#include +#define DBUG_ABORT() (_db_flush_(),\ + (void)_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE),\ + (void)_CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR),\ + _exit(3)) +#endif +#define DBUG_CHECK_CRASH(func, op) \ + do { char _dbuf_[255]; strxnmov(_dbuf_, sizeof(_dbuf_)-1, (func), (op)); \ + DBUG_EXECUTE_IF(_dbuf_, DBUG_ABORT()); } while(0) +#define DBUG_CRASH_ENTER(func) \ + DBUG_ENTER(func); DBUG_CHECK_CRASH(func, "_crash_enter") +#define DBUG_CRASH_RETURN(val) \ + DBUG_CHECK_CRASH(_db_get_func_(), "_crash_return") +#define DBUG_CRASH_VOID_RETURN \ + DBUG_CHECK_CRASH (_db_get_func_(), "_crash_return") + +/* + Make the program fail, without creating a core file. + abort() will send SIGABRT which (most likely) generates core. + Use SIGKILL instead, which cannot be caught. + We also pause the current thread, until the signal is actually delivered. + An alternative would be to use _exit(EXIT_FAILURE), + but then valgrind would report lots of memory leaks. + */ +#ifdef __WIN__ +#define DBUG_SUICIDE() DBUG_ABORT() +#else +#define DBUG_SUICIDE() (_db_flush_(), kill(getpid(), SIGKILL), pause()) +#endif + +#else /* No debugger */ + +#define DBUG_ENTER(a1) +#define DBUG_LEAVE +#define DBUG_RETURN(a1) do { return(a1); } while(0) +#define DBUG_VOID_RETURN do { return; } while(0) +#define DBUG_EXECUTE(keyword,a1) do { } while(0) +#define DBUG_EXECUTE_IF(keyword,a1) do { } while(0) +#define DBUG_EVALUATE(keyword,a1,a2) (a2) +#define DBUG_EVALUATE_IF(keyword,a1,a2) (a2) +#define DBUG_PRINT(keyword,arglist) do { } while(0) +#define DBUG_PUSH(a1) do { } while(0) +#define DBUG_SET(a1) do { } while(0) +#define DBUG_SET_INITIAL(a1) do { } while(0) +#define DBUG_POP() do { } while(0) +#define DBUG_PROCESS(a1) do { } while(0) +#define DBUG_SETJMP(a1) setjmp(a1) +#define DBUG_LONGJMP(a1) longjmp(a1) +#define DBUG_DUMP(keyword,a1,a2) do { } while(0) +#define DBUG_END() do { } while(0) +#define DBUG_ASSERT(A) do { } while(0) +#define DBUG_LOCK_FILE do { } while(0) +#define DBUG_FILE (stderr) +#define DBUG_UNLOCK_FILE do { } while(0) +#define DBUG_EXPLAIN(buf,len) +#define DBUG_EXPLAIN_INITIAL(buf,len) +#define DEBUGGER_OFF do { } while(0) +#define DEBUGGER_ON do { } while(0) +#define DBUG_ABORT() do { } while(0) +#define DBUG_CRASH_ENTER(func) +#define DBUG_CRASH_RETURN(val) do { return(val); } while(0) +#define DBUG_CRASH_VOID_RETURN do { return; } while(0) +#define DBUG_SUICIDE() do { } while(0) + +#endif + +#ifdef EXTRA_DEBUG +/** + Sync points allow us to force the server to reach a certain line of code + and block there until the client tells the server it is ok to go on. + The client tells the server to block with SELECT GET_LOCK() + and unblocks it with SELECT RELEASE_LOCK(). Used for debugging difficult + concurrency problems +*/ +#define DBUG_SYNC_POINT(lock_name,lock_timeout) \ + debug_sync_point(lock_name,lock_timeout) +void debug_sync_point(const char* lock_name, uint lock_timeout); +#else +#define DBUG_SYNC_POINT(lock_name,lock_timeout) +#endif /* EXTRA_DEBUG */ + +#ifdef __cplusplus +} +#endif + +#endif /* MY_DBUG_INCLUDED */ diff --git a/include/mysql/my_dir.h b/include/mysql/my_dir.h new file mode 100644 index 000000000..de21bee73 --- /dev/null +++ b/include/mysql/my_dir.h @@ -0,0 +1,109 @@ +/* Copyright (C) 2000 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifndef MY_DIR_H +#define MY_DIR_H + +#include "my_global.h" + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + /* Defines for my_dir and my_stat */ + +#define MY_S_IFMT S_IFMT /* type of file */ +#define MY_S_IFDIR S_IFDIR /* directory */ +#define MY_S_IFCHR S_IFCHR /* character special */ +#define MY_S_IFBLK S_IFBLK /* block special */ +#define MY_S_IFREG S_IFREG /* regular */ +#define MY_S_IFIFO S_IFIFO /* fifo */ +#define MY_S_ISUID S_ISUID /* set user id on execution */ +#define MY_S_ISGID S_ISGID /* set group id on execution */ +#define MY_S_ISVTX S_ISVTX /* save swapped text even after use */ +#define MY_S_IREAD S_IREAD /* read permission, owner */ +#define MY_S_IWRITE S_IWRITE /* write permission, owner */ +#define MY_S_IEXEC S_IEXEC /* execute/search permission, owner */ + +#define MY_S_ISDIR(m) (((m) & MY_S_IFMT) == MY_S_IFDIR) +#define MY_S_ISCHR(m) (((m) & MY_S_IFMT) == MY_S_IFCHR) +#define MY_S_ISBLK(m) (((m) & MY_S_IFMT) == MY_S_IFBLK) +#define MY_S_ISREG(m) (((m) & MY_S_IFMT) == MY_S_IFREG) +#define MY_S_ISFIFO(m) (((m) & MY_S_IFMT) == MY_S_IFIFO) + +#define MY_DONT_SORT 512 /* my_lib; Don't sort files */ +#define MY_WANT_STAT 1024 /* my_lib; stat files */ + + /* typedefs for my_dir & my_stat */ + +#ifdef USE_MY_STAT_STRUCT + +typedef struct my_stat +{ + dev_t st_dev; /* major & minor device numbers */ + ino_t st_ino; /* inode number */ + ushort st_mode; /* file permissons (& suid sgid .. bits) */ + short st_nlink; /* number of links to file */ + ushort st_uid; /* user id */ + ushort st_gid; /* group id */ + dev_t st_rdev; /* more major & minor device numbers (???) */ + off_t st_size; /* size of file */ + time_t st_atime; /* time for last read */ + time_t st_mtime; /* time for last contens modify */ + time_t st_ctime; /* time for last inode or contents modify */ +} MY_STAT; + +#else + +#if(_MSC_VER) +#define MY_STAT struct _stati64 /* 64 bit file size */ +#else +#define MY_STAT struct stat /* Orginal struct have what we need */ +#endif + +#endif /* USE_MY_STAT_STRUCT */ + +/* Struct describing one file returned from my_dir */ +typedef struct fileinfo +{ + char *name; + MY_STAT *mystat; +} FILEINFO; + +typedef struct st_my_dir /* Struct returned from my_dir */ +{ + /* + These members are just copies of parts of DYNAMIC_ARRAY structure, + which is allocated right after the end of MY_DIR structure (MEM_ROOT + for storing names is also resides there). We've left them here because + we don't want to change code that uses my_dir. + */ + struct fileinfo *dir_entry; + uint number_off_files; +} MY_DIR; + +extern MY_DIR *my_dir(const char *path,myf MyFlags); +extern void my_dirend(MY_DIR *buffer); +extern MY_STAT *my_stat(const char *path, MY_STAT *stat_area, myf my_flags); +extern int my_fstat(int filenr, MY_STAT *stat_area, myf MyFlags); + +#ifdef __cplusplus +} +#endif + +#endif /* MY_DIR_H */ + diff --git a/include/mysql/my_getopt.h b/include/mysql/my_getopt.h new file mode 100644 index 000000000..47feb21d8 --- /dev/null +++ b/include/mysql/my_getopt.h @@ -0,0 +1,123 @@ +/* Copyright (C) 2002-2004 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifndef _my_getopt_h +#define _my_getopt_h + +#include "my_sys.h" /* loglevel */ + +C_MODE_START + +#define GET_NO_ARG 1 +#define GET_BOOL 2 +#define GET_INT 3 +#define GET_UINT 4 +#define GET_LONG 5 +#define GET_ULONG 6 +#define GET_LL 7 +#define GET_ULL 8 +#define GET_STR 9 +#define GET_STR_ALLOC 10 +#define GET_DISABLED 11 +#define GET_ENUM 12 +#define GET_SET 13 +#define GET_DOUBLE 14 +#define GET_FLAGSET 15 + +#define GET_ASK_ADDR 128 +#define GET_TYPE_MASK 127 + +/** + Enumeration of the my_option::arg_type attributes. + It should be noted that for historical reasons variables with the combination + arg_type=NO_ARG, my_option::var_type=GET_BOOL still accepts + arguments. This is someone counter intuitive and care should be taken + if the code is refactored. +*/ +enum get_opt_arg_type { NO_ARG, OPT_ARG, REQUIRED_ARG }; + +struct st_typelib; + +struct my_option +{ + const char *name; /**< Name of the option. name=NULL + marks the end of the my_option[] + array. + */ + int id; /**< For 0255 no short option + is created, but a long option still + can be identified uniquely in the + my_get_one_option() callback. + If an opton needs neither special + treatment in the my_get_one_option() + nor one-letter short equivalent + use id=0 + */ + const char *comment; /**< option comment, for autom. --help. + if it's NULL the option is not + visible in --help. + */ + void *value; /**< A pointer to the variable value */ + void *u_max_value; /**< The user def. max variable value */ + struct st_typelib *typelib; /**< Pointer to possible values */ + ulong var_type; /**< GET_BOOL, GET_ULL, etc */ + enum get_opt_arg_type arg_type; /**< e.g. REQUIRED_ARG or OPT_ARG */ + longlong def_value; /**< Default value */ + longlong min_value; /**< Min allowed value (for numbers) */ + longlong max_value; /**< Max allowed value (for numbers) */ + longlong sub_size; /**< Unused */ + long block_size; /**< Value should be a mult. of this (for numbers) */ + void *app_type; /**< To be used by an application */ +}; + + +typedef my_bool (*my_get_one_option)(int, const struct my_option *, char *); +typedef void (*my_error_reporter)(enum loglevel level, const char *format, ...); +/** + Used to retrieve a reference to the object (variable) that holds the value + for the given option. For example, if var_type is GET_UINT, the function + must return a pointer to a variable of type uint. A argument is stored in + the location pointed to by the returned pointer. +*/ +typedef void *(*my_getopt_value)(const char *, uint, const struct my_option *, + int *); + + +extern char *disabled_my_option; +extern my_bool my_getopt_print_errors; +extern my_bool my_getopt_skip_unknown; +extern my_error_reporter my_getopt_error_reporter; + +extern int handle_options (int *argc, char ***argv, + const struct my_option *longopts, my_get_one_option); +extern void my_cleanup_options(const struct my_option *options); +extern void my_print_help(const struct my_option *options); +extern void my_print_variables(const struct my_option *options); +extern void my_getopt_register_get_addr(my_getopt_value); + +ulonglong getopt_ull_limit_value(ulonglong num, const struct my_option *optp, + my_bool *fix); +longlong getopt_ll_limit_value(longlong, const struct my_option *, + my_bool *fix); +double getopt_double_limit_value(double num, const struct my_option *optp, + my_bool *fix); +my_bool getopt_compare_strings(const char *s, const char *t, uint length); + +C_MODE_END + +#endif /* _my_getopt_h */ + diff --git a/include/mysql/my_global.h b/include/mysql/my_global.h new file mode 100644 index 000000000..8540c3f10 --- /dev/null +++ b/include/mysql/my_global.h @@ -0,0 +1,1499 @@ +/* Copyright (C) 2000-2003 MySQL AB, 2009 Sun Microsystems, Inc + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/* This is the include file that should be included 'first' in every C file. */ + +#ifndef _global_h +#define _global_h + +/* Client library users on Windows need this macro defined here. */ +#if !defined(__WIN__) && defined(_WIN32) +#define __WIN__ +#endif + +/* + InnoDB depends on some MySQL internals which other plugins should not + need. This is because of InnoDB's foreign key support, "safe" binlog + truncation, and other similar legacy features. + + We define accessors for these internals unconditionally, but do not + expose them in mysql/plugin.h. They are declared in ha_innodb.h for + InnoDB's use. +*/ +#define INNODB_COMPATIBILITY_HOOKS + +#ifdef __CYGWIN__ +/* We use a Unix API, so pretend it's not Windows */ +#undef WIN +#undef WIN32 +#undef _WIN +#undef _WIN32 +#undef _WIN64 +#undef __WIN__ +#undef __WIN32__ +#define HAVE_ERRNO_AS_DEFINE +#endif /* __CYGWIN__ */ + +/* to make command line shorter we'll define USE_PRAGMA_INTERFACE here */ +#ifdef USE_PRAGMA_IMPLEMENTATION +#define USE_PRAGMA_INTERFACE +#endif + +#if defined(__OpenBSD__) && (OpenBSD >= 200411) +#define HAVE_ERRNO_AS_DEFINE +#endif + +#if defined(i386) && !defined(__i386__) +#define __i386__ +#endif + +/* Macros to make switching between C and C++ mode easier */ +#ifdef __cplusplus +#define C_MODE_START extern "C" { +#define C_MODE_END } +#else +#define C_MODE_START +#define C_MODE_END +#endif + +#ifdef __cplusplus +#define CPP_UNNAMED_NS_START namespace { +#define CPP_UNNAMED_NS_END } +#endif + +#include + +#ifdef WITH_PERFSCHEMA_STORAGE_ENGINE +#define HAVE_PSI_INTERFACE +#endif /* WITH_PERFSCHEMA_STORAGE_ENGINE */ + +/* Make it easier to add conditional code in _expressions_ */ +#ifdef __WIN__ +#define IF_WIN(A,B) A +#else +#define IF_WIN(A,B) B +#endif + +#ifdef HAVE_purify +#define IF_PURIFY(A,B) A +#else +#define IF_PURIFY(A,B) B +#endif + +#ifndef EMBEDDED_LIBRARY +#ifdef WITH_NDB_BINLOG +#define HAVE_NDB_BINLOG 1 +#endif +#endif /* !EMBEDDED_LIBRARY */ + +#ifndef EMBEDDED_LIBRARY +#define HAVE_REPLICATION +#define HAVE_EXTERNAL_CLIENT +#endif + +#if defined (_WIN32) +/* + off_t is 32 bit long. We do not use C runtime functions + with off_t but native Win32 file IO APIs, that work with + 64 bit offsets. +*/ +#undef SIZEOF_OFF_T +#define SIZEOF_OFF_T 8 + +/* + Prevent inclusion of Windows GDI headers - they define symbol + ERROR that conflicts with mysql headers. +*/ +#ifndef NOGDI +#define NOGDI +#endif + +/* Include common headers.*/ +#include +#include /* SOCKET */ +#include /* access(), chmod() */ +#include /* getpid() */ + +#define sleep(a) Sleep((a)*1000) + +/* Define missing access() modes. */ +#define F_OK 0 +#define W_OK 2 + +/* Define missing file locking constants. */ +#define F_RDLCK 1 +#define F_WRLCK 2 +#define F_UNLCK 3 +#define F_TO_EOF 0x3FFFFFFF + +/* Shared memory and named pipe connections are supported. */ +#define HAVE_SMEM 1 +#define HAVE_NAMED_PIPE 1 +#define shared_memory_buffer_length 16000 +#define default_shared_memory_base_name "MYSQL" +#endif /* _WIN32*/ + + +/* Workaround for _LARGE_FILES and _LARGE_FILE_API incompatibility on AIX */ +#if defined(_AIX) && defined(_LARGE_FILE_API) +#undef _LARGE_FILE_API +#endif + +/* + The macros below are used to allow build of Universal/fat binaries of + MySQL and MySQL applications under darwin. +*/ +#if defined(__APPLE__) && defined(__MACH__) +# undef SIZEOF_CHARP +# undef SIZEOF_SHORT +# undef SIZEOF_INT +# undef SIZEOF_LONG +# undef SIZEOF_LONG_LONG +# undef SIZEOF_OFF_T +# undef WORDS_BIGENDIAN +# define SIZEOF_SHORT 2 +# define SIZEOF_INT 4 +# define SIZEOF_LONG_LONG 8 +# define SIZEOF_OFF_T 8 +# if defined(__i386__) || defined(__ppc__) +# define SIZEOF_CHARP 4 +# define SIZEOF_LONG 4 +# elif defined(__x86_64__) || defined(__ppc64__) +# define SIZEOF_CHARP 8 +# define SIZEOF_LONG 8 +# else +# error Building FAT binary for an unknown architecture. +# endif +# if defined(__ppc__) || defined(__ppc64__) +# define WORDS_BIGENDIAN +# endif +#endif /* defined(__APPLE__) && defined(__MACH__) */ + + +/* + The macros below are borrowed from include/linux/compiler.h in the + Linux kernel. Use them to indicate the likelyhood of the truthfulness + of a condition. This serves two purposes - newer versions of gcc will be + able to optimize for branch predication, which could yield siginficant + performance gains in frequently executed sections of the code, and the + other reason to use them is for documentation +*/ + +#if !defined(__GNUC__) || (__GNUC__ == 2 && __GNUC_MINOR__ < 96) +#define __builtin_expect(x, expected_value) (x) +#endif + +#define likely(x) __builtin_expect((x),1) +#define unlikely(x) __builtin_expect((x),0) + +/* Fix problem with S_ISLNK() on Linux */ +#if defined(TARGET_OS_LINUX) || defined(__GLIBC__) +#undef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif + +/* + Temporary solution to solve bug#7156. Include "sys/types.h" before + the thread headers, else the function madvise() will not be defined +*/ +#if defined(HAVE_SYS_TYPES_H) && ( defined(sun) || defined(__sun) ) +#include +#endif + +/* The client defines this to avoid all thread code */ +#if defined(MYSQL_CLIENT_NO_THREADS) || defined(UNDEF_THREADS_HACK) +#undef THREAD +#undef HAVE_LINUXTHREADS +#undef HAVE_NPTL +#endif + +#ifdef HAVE_THREADS_WITHOUT_SOCKETS +/* MIT pthreads does not work with unix sockets */ +#undef HAVE_SYS_UN_H +#endif + +#define __EXTENSIONS__ 1 /* We want some extension */ +#ifndef __STDC_EXT__ +#define __STDC_EXT__ 1 /* To get large file support on hpux */ +#endif + +/* + Solaris 9 include file refers to X/Open document + + System Interfaces and Headers, Issue 5 + + saying we should define _XOPEN_SOURCE=500 to get POSIX.1c prototypes, + but apparently other systems (namely FreeBSD) don't agree. + + On a newer Solaris 10, the above file recognizes also _XOPEN_SOURCE=600. + Furthermore, it tests that if a program requires older standard + (_XOPEN_SOURCE<600 or _POSIX_C_SOURCE<200112L) it cannot be + run on a new compiler (that defines _STDC_C99) and issues an #error. + It's also an #error if a program requires new standard (_XOPEN_SOURCE=600 + or _POSIX_C_SOURCE=200112L) and a compiler does not define _STDC_C99. + + To add more to this mess, Sun Studio C compiler defines _STDC_C99 while + C++ compiler does not! + + So, in a desperate attempt to get correct prototypes for both + C and C++ code, we define either _XOPEN_SOURCE=600 or _XOPEN_SOURCE=500 + depending on the compiler's announced C standard support. + + Cleaner solutions are welcome. +*/ +#ifdef __sun +#if __STDC_VERSION__ - 0 >= 199901L +#define _XOPEN_SOURCE 600 +#else +#define _XOPEN_SOURCE 500 +#endif +#endif + +#if defined(THREAD) && !defined(__WIN__) +#ifndef _POSIX_PTHREAD_SEMANTICS +#define _POSIX_PTHREAD_SEMANTICS /* We want posix threads */ +#endif + +#if !defined(SCO) +#define _REENTRANT 1 /* Some thread libraries require this */ +#endif +#if !defined(_THREAD_SAFE) && !defined(_AIX) +#define _THREAD_SAFE /* Required for OSF1 */ +#endif +#if defined(HPUX10) || defined(HPUX11) +C_MODE_START /* HPUX needs this, signal.h bug */ +#include +C_MODE_END +#else +#include /* AIX must have this included first */ +#endif +#if !defined(SCO) && !defined(_REENTRANT) +#define _REENTRANT 1 /* Threads requires reentrant code */ +#endif +#endif /* THREAD */ + +/* Go around some bugs in different OS and compilers */ +#ifdef _AIX /* By soren@t.dk */ +#define _H_STRINGS +#define _SYS_STREAM_H +/* #define _AIX32_CURSES */ /* XXX: this breaks AIX 4.3.3 (others?). */ +#define ulonglong2double(A) my_ulonglong2double(A) +#define my_off_t2double(A) my_ulonglong2double(A) +C_MODE_START +double my_ulonglong2double(unsigned long long A); +C_MODE_END +#endif /* _AIX */ + +#ifdef HAVE_BROKEN_SNPRINTF /* HPUX 10.20 don't have this defined */ +#undef HAVE_SNPRINTF +#endif +#ifdef HAVE_BROKEN_PREAD +/* + pread()/pwrite() are not 64 bit safe on HP-UX 11.0 without + installing the kernel patch PHKL_20349 or greater +*/ +#undef HAVE_PREAD +#undef HAVE_PWRITE +#endif + +#ifdef UNDEF_HAVE_GETHOSTBYNAME_R /* For OSF4.x */ +#undef HAVE_GETHOSTBYNAME_R +#endif +#ifdef UNDEF_HAVE_INITGROUPS /* For AIX 4.3 */ +#undef HAVE_INITGROUPS +#endif + +/* gcc/egcs issues */ + +#if defined(__GNUC) && defined(__EXCEPTIONS) +#error "Please add -fno-exceptions to CXXFLAGS and reconfigure/recompile" +#endif + +#if defined(_lint) && !defined(lint) +#define lint +#endif +#if SIZEOF_LONG_LONG > 4 && !defined(_LONG_LONG) +#define _LONG_LONG 1 /* For AIX string library */ +#endif + +#ifndef stdin +#include +#endif +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STDDEF_H +#include +#endif + +#include +#ifdef HAVE_LIMITS_H +#include +#endif +#ifdef HAVE_FLOAT_H +#include +#endif +#ifdef HAVE_FENV_H +#include /* For fesetround() */ +#endif + +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif +#ifdef HAVE_SYS_TIMEB_H +#include /* Avoid warnings on SCO */ +#endif +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif /* TIME_WITH_SYS_TIME */ +#ifdef HAVE_UNISTD_H +#include +#endif +#if defined(__cplusplus) && defined(NO_CPLUSPLUS_ALLOCA) +#undef HAVE_ALLOCA +#undef HAVE_ALLOCA_H +#endif +#ifdef HAVE_ALLOCA_H +#include +#endif + +#include /* Recommended by debian */ +/* We need the following to go around a problem with openssl on solaris */ +#if defined(HAVE_CRYPT_H) +#include +#endif + +/* + A lot of our programs uses asserts, so better to always include it + This also fixes a problem when people uses DBUG_ASSERT without including + assert.h +*/ +#include + +/* an assert that works at compile-time. only for constant expression */ +#ifndef __GNUC__ +#define compile_time_assert(X) do { } while(0) +#else +#define compile_time_assert(X) \ + do \ + { \ + typedef char compile_time_assert[(X) ? 1 : -1]; \ + } while(0) +#endif + +/* Go around some bugs in different OS and compilers */ +#if defined (HPUX11) && defined(_LARGEFILE_SOURCE) +#ifndef _LARGEFILE64_SOURCE +#define _LARGEFILE64_SOURCE +#endif +#endif + +#if defined(_HPUX_SOURCE) && defined(HAVE_SYS_STREAM_H) +#include /* HPUX 10.20 defines ulong here. UGLY !!! */ +#define HAVE_ULONG +#endif +#if defined(HPUX10) && defined(_LARGEFILE64_SOURCE) && defined(THREAD) +/* Fix bug in setrlimit */ +#undef setrlimit +#define setrlimit cma_setrlimit64 +#endif +/* Declare madvise where it is not declared for C++, like Solaris */ +#if HAVE_MADVISE && !HAVE_DECL_MADVISE && defined(__cplusplus) +extern "C" int madvise(void *addr, size_t len, int behav); +#endif + +#define QUOTE_ARG(x) #x /* Quote argument (before cpp) */ +#define STRINGIFY_ARG(x) QUOTE_ARG(x) /* Quote argument, after cpp */ + +/* Paranoid settings. Define I_AM_PARANOID if you are paranoid */ +#ifdef I_AM_PARANOID +#define DONT_ALLOW_USER_CHANGE 1 +#define DONT_USE_MYSQL_PWD 1 +#endif + +/* Does the system remember a signal handler after a signal ? */ +#if !defined(HAVE_BSD_SIGNALS) && !defined(HAVE_SIGACTION) +#define SIGNAL_HANDLER_RESET_ON_DELIVERY +#endif + +/* + Deprecated workaround for false-positive uninitialized variables + warnings. Those should be silenced using tool-specific heuristics. + + Enabled by default for g++ due to the bug referenced below. +*/ +#if defined(_lint) || defined(FORCE_INIT_OF_VARS) || \ + (defined(__GNUC__) && defined(__cplusplus)) +#define LINT_INIT(var) var= 0 +#else +#define LINT_INIT(var) +#endif + +#ifndef SO_EXT +#ifdef _WIN32 +#define SO_EXT ".dll" +#elif defined(__APPLE__) +#define SO_EXT ".dylib" +#else +#define SO_EXT ".so" +#endif +#endif + +/* + Suppress uninitialized variable warning without generating code. + + The _cplusplus is a temporary workaround for C++ code pending a fix + for a g++ bug (http://gcc.gnu.org/bugzilla/show_bug.cgi?id=34772). +*/ +#if defined(_lint) || defined(FORCE_INIT_OF_VARS) || \ + defined(__cplusplus) || !defined(__GNUC__) +#define UNINIT_VAR(x) x= 0 +#else +/* GCC specific self-initialization which inhibits the warning. */ +#define UNINIT_VAR(x) x= x +#endif + +#if !defined(HAVE_UINT) +#undef HAVE_UINT +#define HAVE_UINT +typedef unsigned int uint; +typedef unsigned short ushort; +#endif + +#define swap_variables(t, a, b) { t dummy; dummy= a; a= b; b= dummy; } +#define test(a) ((a) ? 1 : 0) +#define set_if_bigger(a,b) do { if ((a) < (b)) (a)=(b); } while(0) +#define set_if_smaller(a,b) do { if ((a) > (b)) (a)=(b); } while(0) +#define test_all_bits(a,b) (((a) & (b)) == (b)) +#define array_elements(A) ((uint) (sizeof(A)/sizeof(A[0]))) + +/* Define some general constants */ +#ifndef TRUE +#define TRUE (1) /* Logical true */ +#define FALSE (0) /* Logical false */ +#endif + +#include + +/* + Wen using the embedded library, users might run into link problems, + duplicate declaration of __cxa_pure_virtual, solved by declaring it a + weak symbol. +*/ +#if defined(USE_MYSYS_NEW) && ! defined(DONT_DECLARE_CXA_PURE_VIRTUAL) +C_MODE_START +int __cxa_pure_virtual () __attribute__ ((weak)); +C_MODE_END +#endif + +/* The DBUG_ON flag always takes precedence over default DBUG_OFF */ +#if defined(DBUG_ON) && defined(DBUG_OFF) +#undef DBUG_OFF +#endif + +/* We might be forced to turn debug off, if not turned off already */ +#if (defined(FORCE_DBUG_OFF) || defined(_lint)) && !defined(DBUG_OFF) +# define DBUG_OFF +# ifdef DBUG_ON +# undef DBUG_ON +# endif +#endif + +/* Some types that is different between systems */ + +typedef int File; /* File descriptor */ +#ifdef _WIN32 +typedef SOCKET my_socket; +#else +typedef int my_socket; /* File descriptor for sockets */ +#define INVALID_SOCKET -1 +#endif +/* Type for fuctions that handles signals */ +#define sig_handler RETSIGTYPE +C_MODE_START +typedef void (*sig_return)();/* Returns type from signal */ +C_MODE_END +#if defined(__GNUC__) && !defined(_lint) +typedef char pchar; /* Mixed prototypes can take char */ +typedef char puchar; /* Mixed prototypes can take char */ +typedef char pbool; /* Mixed prototypes can take char */ +typedef short pshort; /* Mixed prototypes can take short int */ +typedef float pfloat; /* Mixed prototypes can take float */ +#else +typedef int pchar; /* Mixed prototypes can't take char */ +typedef uint puchar; /* Mixed prototypes can't take char */ +typedef int pbool; /* Mixed prototypes can't take char */ +typedef int pshort; /* Mixed prototypes can't take short int */ +typedef double pfloat; /* Mixed prototypes can't take float */ +#endif +C_MODE_START +typedef int (*qsort_cmp)(const void *,const void *); +typedef int (*qsort_cmp2)(void*, const void *,const void *); +C_MODE_END +#define qsort_t RETQSORTTYPE /* Broken GCC cant handle typedef !!!! */ +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +typedef SOCKET_SIZE_TYPE size_socket; + +#ifndef SOCKOPT_OPTLEN_TYPE +#define SOCKOPT_OPTLEN_TYPE size_socket +#endif + +/* file create flags */ + +#ifndef O_SHARE /* Probably not windows */ +#define O_SHARE 0 /* Flag to my_open for shared files */ +#ifndef O_BINARY +#define O_BINARY 0 /* Flag to my_open for binary files */ +#endif +#ifndef FILE_BINARY +#define FILE_BINARY O_BINARY /* Flag to my_fopen for binary streams */ +#endif +#ifdef HAVE_FCNTL +#define HAVE_FCNTL_LOCK +#define F_TO_EOF 0L /* Param to lockf() to lock rest of file */ +#endif +#endif /* O_SHARE */ + +#ifndef O_TEMPORARY +#define O_TEMPORARY 0 +#endif +#ifndef O_SHORT_LIVED +#define O_SHORT_LIVED 0 +#endif +#ifndef O_NOFOLLOW +#define O_NOFOLLOW 0 +#endif + +/* additional file share flags for win32 */ +#ifdef __WIN__ +#define _SH_DENYRWD 0x110 /* deny read/write mode & delete */ +#define _SH_DENYWRD 0x120 /* deny write mode & delete */ +#define _SH_DENYRDD 0x130 /* deny read mode & delete */ +#define _SH_DENYDEL 0x140 /* deny delete only */ +#endif /* __WIN__ */ + + +/* General constants */ +#define FN_LEN 256 /* Max file name len */ +#define FN_HEADLEN 253 /* Max length of filepart of file name */ +#define FN_EXTLEN 20 /* Max length of extension (part of FN_LEN) */ +#define FN_REFLEN 512 /* Max length of full path-name */ +#define FN_EXTCHAR '.' +#define FN_HOMELIB '~' /* ~/ is used as abbrev for home dir */ +#define FN_CURLIB '.' /* ./ is used as abbrev for current dir */ +#define FN_PARENTDIR ".." /* Parent directory; Must be a string */ + +#ifdef _WIN32 +#define FN_LIBCHAR '\\' +#define FN_LIBCHAR2 '/' +#define FN_ROOTDIR "\\" +#define FN_DEVCHAR ':' +#define FN_NETWORK_DRIVES /* Uses \\ to indicate network drives */ +#define FN_NO_CASE_SENCE /* Files are not case-sensitive */ +#else +#define FN_LIBCHAR '/' +#define FN_LIBCHAR2 '/' +#define FN_ROOTDIR "/" +#endif + +/* + MY_FILE_MIN is Windows speciality and is used to quickly detect + the mismatch of CRT and mysys file IO usage on Windows at runtime. + CRT file descriptors can be in the range 0-2047, whereas descriptors returned + by my_open() will start with 2048. If a file descriptor with value less then + MY_FILE_MIN is passed to mysys IO function, chances are it stemms from + open()/fileno() and not my_open()/my_fileno. + + For Posix, mysys functions are light wrappers around libc, and MY_FILE_MIN + is logically 0. +*/ + +#ifdef _WIN32 +#define MY_FILE_MIN 2048 +#else +#define MY_FILE_MIN 0 +#endif + +/* + MY_NFILE is the default size of my_file_info array. + + It is larger on Windows, because it all file handles are stored in my_file_info + Default size is 16384 and this should be enough for most cases.If it is not + enough, --max-open-files with larger value can be used. + + For Posix , my_file_info array is only used to store filenames for + error reporting and its size is not a limitation for number of open files. +*/ +#ifdef _WIN32 +#define MY_NFILE (16384 + MY_FILE_MIN) +#else +#define MY_NFILE 64 +#endif + +#ifndef OS_FILE_LIMIT +#define OS_FILE_LIMIT UINT_MAX +#endif + +/* + Io buffer size; Must be a power of 2 and a multiple of 512. May be + smaller what the disk page size. This influences the speed of the + isam btree library. eg to big to slow. +*/ +#define IO_SIZE 4096 +/* + How much overhead does malloc have. The code often allocates + something like 1024-MALLOC_OVERHEAD bytes +*/ +#define MALLOC_OVERHEAD 8 + + /* get memory in huncs */ +#define ONCE_ALLOC_INIT (uint) (4096-MALLOC_OVERHEAD) + /* Typical record cash */ +#define RECORD_CACHE_SIZE (uint) (64*1024-MALLOC_OVERHEAD) + /* Typical key cash */ +#define KEY_CACHE_SIZE (uint) (8*1024*1024) + /* Default size of a key cache block */ +#define KEY_CACHE_BLOCK_SIZE (uint) 1024 + + + /* Some things that this system doesn't have */ + +#ifdef _WIN32 +#define NO_DIR_LIBRARY /* Not standard dir-library */ +#endif + +/* Some defines of functions for portability */ + +#undef remove /* Crashes MySQL on SCO 5.0.0 */ +#ifndef __WIN__ +#define closesocket(A) close(A) +#endif + +#if (_MSC_VER) +#if !defined(_WIN64) +inline double my_ulonglong2double(unsigned long long value) +{ + long long nr=(long long) value; + if (nr >= 0) + return (double) nr; + return (18446744073709551616.0 + (double) nr); +} +#define ulonglong2double my_ulonglong2double +#define my_off_t2double my_ulonglong2double +#endif /* _WIN64 */ +inline unsigned long long my_double2ulonglong(double d) +{ + double t= d - (double) 0x8000000000000000ULL; + + if (t >= 0) + return ((unsigned long long) t) + 0x8000000000000000ULL; + return (unsigned long long) d; +} +#define double2ulonglong my_double2ulonglong +#endif + +#ifndef ulonglong2double +#define ulonglong2double(A) ((double) (ulonglong) (A)) +#define my_off_t2double(A) ((double) (my_off_t) (A)) +#endif +#ifndef double2ulonglong +#define double2ulonglong(A) ((ulonglong) (double) (A)) +#endif + +#ifndef offsetof +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +#endif +#define ulong_to_double(X) ((double) (ulong) (X)) + +#ifndef STACK_DIRECTION +#error "please add -DSTACK_DIRECTION=1 or -1 to your CPPFLAGS" +#endif + +#if !defined(HAVE_STRTOK_R) +#define strtok_r(A,B,C) strtok((A),(B)) +#endif + +/* This is from the old m-machine.h file */ + +#if SIZEOF_LONG_LONG > 4 +#define HAVE_LONG_LONG 1 +#endif + +/* + Some pre-ANSI-C99 systems like AIX 5.1 and Linux/GCC 2.95 define + ULONGLONG_MAX, LONGLONG_MIN, LONGLONG_MAX; we use them if they're defined. +*/ + +#if defined(HAVE_LONG_LONG) && !defined(LONGLONG_MIN) +#define LONGLONG_MIN ((long long) 0x8000000000000000LL) +#define LONGLONG_MAX ((long long) 0x7FFFFFFFFFFFFFFFLL) +#endif + +#if defined(HAVE_LONG_LONG) && !defined(ULONGLONG_MAX) +/* First check for ANSI C99 definition: */ +#ifdef ULLONG_MAX +#define ULONGLONG_MAX ULLONG_MAX +#else +#define ULONGLONG_MAX ((unsigned long long)(~0ULL)) +#endif +#endif /* defined (HAVE_LONG_LONG) && !defined(ULONGLONG_MAX)*/ + +#define INT_MIN64 (~0x7FFFFFFFFFFFFFFFLL) +#define INT_MAX64 0x7FFFFFFFFFFFFFFFLL +#define INT_MIN32 (~0x7FFFFFFFL) +#define INT_MAX32 0x7FFFFFFFL +#define UINT_MAX32 0xFFFFFFFFL +#define INT_MIN24 (~0x007FFFFF) +#define INT_MAX24 0x007FFFFF +#define UINT_MAX24 0x00FFFFFF +#define INT_MIN16 (~0x7FFF) +#define INT_MAX16 0x7FFF +#define UINT_MAX16 0xFFFF +#define INT_MIN8 (~0x7F) +#define INT_MAX8 0x7F +#define UINT_MAX8 0xFF + +/* From limits.h instead */ +#ifndef DBL_MIN +#define DBL_MIN 4.94065645841246544e-324 +#define FLT_MIN ((float)1.40129846432481707e-45) +#endif +#ifndef DBL_MAX +#define DBL_MAX 1.79769313486231470e+308 +#define FLT_MAX ((float)3.40282346638528860e+38) +#endif +#ifndef SIZE_T_MAX +#define SIZE_T_MAX (~((size_t) 0)) +#endif + +#ifndef isfinite +#ifdef HAVE_FINITE +#define isfinite(x) finite(x) +#else +#define finite(x) (1.0 / fabs(x) > 0.0) +#endif /* HAVE_FINITE */ +#endif /* isfinite */ + +#ifndef HAVE_ISNAN +#define isnan(x) ((x) != (x)) +#endif + +#ifdef HAVE_ISINF +/* Check if C compiler is affected by GCC bug #39228 */ +#if !defined(__cplusplus) && defined(HAVE_BROKEN_ISINF) +/* Force store/reload of the argument to/from a 64-bit double */ +static inline double my_isinf(double x) +{ + volatile double t= x; + return isinf(t); +} +#else +/* System-provided isinf() is available and safe to use */ +#define my_isinf(X) isinf(X) +#endif +#else /* !HAVE_ISINF */ +#define my_isinf(X) (!finite(X) && !isnan(X)) +#endif + +/* Define missing math constants. */ +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif +#ifndef M_E +#define M_E 2.7182818284590452354 +#endif +#ifndef M_LN2 +#define M_LN2 0.69314718055994530942 +#endif + +/* + Max size that must be added to a so that we know Size to make + adressable obj. +*/ +#if SIZEOF_CHARP == 4 +typedef long my_ptrdiff_t; +#else +typedef long long my_ptrdiff_t; +#endif + +#define MY_ALIGN(A,L) (((A) + (L) - 1) & ~((L) - 1)) +#define ALIGN_SIZE(A) MY_ALIGN((A),sizeof(double)) +/* Size to make adressable obj. */ +#define ADD_TO_PTR(ptr,size,type) (type) ((uchar*) (ptr)+size) +#define PTR_BYTE_DIFF(A,B) (my_ptrdiff_t) ((uchar*) (A) - (uchar*) (B)) + +/* + Custom version of standard offsetof() macro which can be used to get + offsets of members in class for non-POD types (according to the current + version of C++ standard offsetof() macro can't be used in such cases and + attempt to do so causes warnings to be emitted, OTOH in many cases it is + still OK to assume that all instances of the class has the same offsets + for the same members). + + This is temporary solution which should be removed once File_parser class + and related routines are refactored. +*/ + +#define my_offsetof(TYPE, MEMBER) \ + ((size_t)((char *)&(((TYPE *)0x10)->MEMBER) - (char*)0x10)) + +#define NullS (char *) 0 + +#ifdef STDCALL +#undef STDCALL +#endif + +#ifdef _WIN32 +#define STDCALL __stdcall +#else +#define STDCALL +#endif + +/* Typdefs for easyier portability */ + +#ifndef HAVE_UCHAR +typedef unsigned char uchar; /* Short for unsigned char */ +#endif + +#ifndef HAVE_INT8 +typedef signed char int8; /* Signed integer >= 8 bits */ +#endif +#ifndef HAVE_UINT8 +typedef unsigned char uint8; /* Unsigned integer >= 8 bits */ +#endif +#ifndef HAVE_INT16 +typedef short int16; +#endif +#ifndef HAVE_UINT16 +typedef unsigned short uint16; +#endif +#if SIZEOF_INT == 4 +#ifndef HAVE_INT32 +typedef int int32; +#endif +#ifndef HAVE_UINT32 +typedef unsigned int uint32; +#endif +#elif SIZEOF_LONG == 4 +#ifndef HAVE_INT32 +typedef long int32; +#endif +#ifndef HAVE_UINT32 +typedef unsigned long uint32; +#endif +#else +#error Neither int or long is of 4 bytes width +#endif + +#if !defined(HAVE_ULONG) && !defined(__USE_MISC) +typedef unsigned long ulong; /* Short for unsigned long */ +#endif +#ifndef longlong_defined +/* + Using [unsigned] long long is preferable as [u]longlong because we use + [unsigned] long long unconditionally in many places, + for example in constants with [U]LL suffix. +*/ +#if defined(HAVE_LONG_LONG) && SIZEOF_LONG_LONG == 8 +typedef unsigned long long int ulonglong; /* ulong or unsigned long long */ +typedef long long int longlong; +#else +typedef unsigned long ulonglong; /* ulong or unsigned long long */ +typedef long longlong; +#endif +#endif +#ifndef HAVE_INT64 +typedef longlong int64; +#endif +#ifndef HAVE_UINT64 +typedef ulonglong uint64; +#endif + +#if defined(NO_CLIENT_LONG_LONG) +typedef unsigned long my_ulonglong; +#elif defined (__WIN__) +typedef unsigned __int64 my_ulonglong; +#else +typedef unsigned long long my_ulonglong; +#endif + +#if SIZEOF_CHARP == SIZEOF_INT +typedef int intptr; +#elif SIZEOF_CHARP == SIZEOF_LONG +typedef long intptr; +#elif SIZEOF_CHARP == SIZEOF_LONG_LONG +typedef long long intptr; +#else +#error sizeof(void *) is neither sizeof(int) nor sizeof(long) nor sizeof(long long) +#endif + +#define MY_ERRPTR ((void*)(intptr)1) + +#if defined(_WIN32) +typedef unsigned long long my_off_t; +typedef unsigned long long os_off_t; +#else +typedef off_t os_off_t; +#if SIZEOF_OFF_T > 4 +typedef ulonglong my_off_t; +#else +typedef unsigned long my_off_t; +#endif +#endif /*_WIN32*/ +#define MY_FILEPOS_ERROR (~(my_off_t) 0) + +/* + TODO Convert these to use Bitmap class. + */ +typedef ulonglong table_map; /* Used for table bits in join */ +typedef ulong nesting_map; /* Used for flags of nesting constructs */ + +#if defined(__WIN__) +#define socket_errno WSAGetLastError() +#define SOCKET_EINTR WSAEINTR +#define SOCKET_EAGAIN WSAEINPROGRESS +#define SOCKET_ETIMEDOUT WSAETIMEDOUT +#define SOCKET_EWOULDBLOCK WSAEWOULDBLOCK +#define SOCKET_EADDRINUSE WSAEADDRINUSE +#define SOCKET_ENFILE ENFILE +#define SOCKET_EMFILE EMFILE +#else /* Unix */ +#define socket_errno errno +#define closesocket(A) close(A) +#define SOCKET_EINTR EINTR +#define SOCKET_EAGAIN EAGAIN +#define SOCKET_ETIMEDOUT SOCKET_EINTR +#define SOCKET_EWOULDBLOCK EWOULDBLOCK +#define SOCKET_EADDRINUSE EADDRINUSE +#define SOCKET_ENFILE ENFILE +#define SOCKET_EMFILE EMFILE +#endif + +typedef int myf; /* Type of MyFlags in my_funcs */ +typedef char my_bool; /* Small bool */ + +/* Macros for converting *constants* to the right type */ +#define MYF(v) (myf) (v) + +#ifndef LL +#ifdef HAVE_LONG_LONG +#define LL(A) A ## LL +#else +#define LL(A) A ## L +#endif +#endif + +#ifndef ULL +#ifdef HAVE_LONG_LONG +#define ULL(A) A ## ULL +#else +#define ULL(A) A ## UL +#endif +#endif + +/* + Defines to make it possible to prioritize register assignments. No + longer that important with modern compilers. +*/ +#ifndef USING_X +#define reg1 register +#define reg2 register +#define reg3 register +#define reg4 register +#define reg5 register +#define reg6 register +#define reg7 register +#define reg8 register +#define reg9 register +#define reg10 register +#define reg11 register +#define reg12 register +#define reg13 register +#define reg14 register +#define reg15 register +#define reg16 register +#endif + +#include + +/* Some helper macros */ +#define YESNO(X) ((X) ? "yes" : "no") + +#define MY_HOW_OFTEN_TO_ALARM 2 /* How often we want info on screen */ +#define MY_HOW_OFTEN_TO_WRITE 1000 /* How often we want info on screen */ + + + +/* + Define-funktions for reading and storing in machine independent format + (low byte first) +*/ + +/* Optimized store functions for Intel x86 */ +#if defined(__i386__) || defined(_WIN32) +#define sint2korr(A) (*((int16 *) (A))) +#define sint3korr(A) ((int32) ((((uchar) (A)[2]) & 128) ? \ + (((uint32) 255L << 24) | \ + (((uint32) (uchar) (A)[2]) << 16) |\ + (((uint32) (uchar) (A)[1]) << 8) | \ + ((uint32) (uchar) (A)[0])) : \ + (((uint32) (uchar) (A)[2]) << 16) |\ + (((uint32) (uchar) (A)[1]) << 8) | \ + ((uint32) (uchar) (A)[0]))) +#define sint4korr(A) (*((long *) (A))) +#define uint2korr(A) (*((uint16 *) (A))) +#if defined(HAVE_purify) && !defined(_WIN32) +#define uint3korr(A) (uint32) (((uint32) ((uchar) (A)[0])) +\ + (((uint32) ((uchar) (A)[1])) << 8) +\ + (((uint32) ((uchar) (A)[2])) << 16)) +#else +/* + ATTENTION ! + + Please, note, uint3korr reads 4 bytes (not 3) ! + It means, that you have to provide enough allocated space ! +*/ +#define uint3korr(A) (long) (*((unsigned int *) (A)) & 0xFFFFFF) +#endif /* HAVE_purify && !_WIN32 */ +#define uint4korr(A) (*((uint32 *) (A))) +#define uint5korr(A) ((ulonglong)(((uint32) ((uchar) (A)[0])) +\ + (((uint32) ((uchar) (A)[1])) << 8) +\ + (((uint32) ((uchar) (A)[2])) << 16) +\ + (((uint32) ((uchar) (A)[3])) << 24)) +\ + (((ulonglong) ((uchar) (A)[4])) << 32)) +#define uint6korr(A) ((ulonglong)(((uint32) ((uchar) (A)[0])) + \ + (((uint32) ((uchar) (A)[1])) << 8) + \ + (((uint32) ((uchar) (A)[2])) << 16) + \ + (((uint32) ((uchar) (A)[3])) << 24)) + \ + (((ulonglong) ((uchar) (A)[4])) << 32) + \ + (((ulonglong) ((uchar) (A)[5])) << 40)) +#define uint8korr(A) (*((ulonglong *) (A))) +#define sint8korr(A) (*((longlong *) (A))) +#define int2store(T,A) *((uint16*) (T))= (uint16) (A) +#define int3store(T,A) do { *(T)= (uchar) ((A));\ + *(T+1)=(uchar) (((uint) (A) >> 8));\ + *(T+2)=(uchar) (((A) >> 16)); } while (0) +#define int4store(T,A) *((long *) (T))= (long) (A) +#define int5store(T,A) do { *(T)= (uchar)((A));\ + *((T)+1)=(uchar) (((A) >> 8));\ + *((T)+2)=(uchar) (((A) >> 16));\ + *((T)+3)=(uchar) (((A) >> 24)); \ + *((T)+4)=(uchar) (((A) >> 32)); } while(0) +#define int6store(T,A) do { *(T)= (uchar)((A)); \ + *((T)+1)=(uchar) (((A) >> 8)); \ + *((T)+2)=(uchar) (((A) >> 16)); \ + *((T)+3)=(uchar) (((A) >> 24)); \ + *((T)+4)=(uchar) (((A) >> 32)); \ + *((T)+5)=(uchar) (((A) >> 40)); } while(0) +#define int8store(T,A) *((ulonglong *) (T))= (ulonglong) (A) + +typedef union { + double v; + long m[2]; +} doubleget_union; +#define doubleget(V,M) \ +do { doubleget_union _tmp; \ + _tmp.m[0] = *((long*)(M)); \ + _tmp.m[1] = *(((long*) (M))+1); \ + (V) = _tmp.v; } while(0) +#define doublestore(T,V) do { *((long *) T) = ((doubleget_union *)&V)->m[0]; \ + *(((long *) T)+1) = ((doubleget_union *)&V)->m[1]; \ + } while (0) +#define float4get(V,M) do { *((float *) &(V)) = *((float*) (M)); } while(0) +#define float8get(V,M) doubleget((V),(M)) +#define float4store(V,M) memcpy((uchar*) V,(uchar*) (&M),sizeof(float)) +#define floatstore(T,V) memcpy((uchar*)(T), (uchar*)(&V),sizeof(float)) +#define floatget(V,M) memcpy((uchar*) &V,(uchar*) (M),sizeof(float)) +#define float8store(V,M) doublestore((V),(M)) +#else + +/* + We're here if it's not a IA-32 architecture (Win32 and UNIX IA-32 defines + were done before) +*/ +#define sint2korr(A) (int16) (((int16) ((uchar) (A)[0])) +\ + ((int16) ((int16) (A)[1]) << 8)) +#define sint3korr(A) ((int32) ((((uchar) (A)[2]) & 128) ? \ + (((uint32) 255L << 24) | \ + (((uint32) (uchar) (A)[2]) << 16) |\ + (((uint32) (uchar) (A)[1]) << 8) | \ + ((uint32) (uchar) (A)[0])) : \ + (((uint32) (uchar) (A)[2]) << 16) |\ + (((uint32) (uchar) (A)[1]) << 8) | \ + ((uint32) (uchar) (A)[0]))) +#define sint4korr(A) (int32) (((int32) ((uchar) (A)[0])) +\ + (((int32) ((uchar) (A)[1]) << 8)) +\ + (((int32) ((uchar) (A)[2]) << 16)) +\ + (((int32) ((int16) (A)[3]) << 24))) +#define sint8korr(A) (longlong) uint8korr(A) +#define uint2korr(A) (uint16) (((uint16) ((uchar) (A)[0])) +\ + ((uint16) ((uchar) (A)[1]) << 8)) +#define uint3korr(A) (uint32) (((uint32) ((uchar) (A)[0])) +\ + (((uint32) ((uchar) (A)[1])) << 8) +\ + (((uint32) ((uchar) (A)[2])) << 16)) +#define uint4korr(A) (uint32) (((uint32) ((uchar) (A)[0])) +\ + (((uint32) ((uchar) (A)[1])) << 8) +\ + (((uint32) ((uchar) (A)[2])) << 16) +\ + (((uint32) ((uchar) (A)[3])) << 24)) +#define uint5korr(A) ((ulonglong)(((uint32) ((uchar) (A)[0])) +\ + (((uint32) ((uchar) (A)[1])) << 8) +\ + (((uint32) ((uchar) (A)[2])) << 16) +\ + (((uint32) ((uchar) (A)[3])) << 24)) +\ + (((ulonglong) ((uchar) (A)[4])) << 32)) +#define uint6korr(A) ((ulonglong)(((uint32) ((uchar) (A)[0])) + \ + (((uint32) ((uchar) (A)[1])) << 8) + \ + (((uint32) ((uchar) (A)[2])) << 16) + \ + (((uint32) ((uchar) (A)[3])) << 24)) + \ + (((ulonglong) ((uchar) (A)[4])) << 32) + \ + (((ulonglong) ((uchar) (A)[5])) << 40)) +#define uint8korr(A) ((ulonglong)(((uint32) ((uchar) (A)[0])) +\ + (((uint32) ((uchar) (A)[1])) << 8) +\ + (((uint32) ((uchar) (A)[2])) << 16) +\ + (((uint32) ((uchar) (A)[3])) << 24)) +\ + (((ulonglong) (((uint32) ((uchar) (A)[4])) +\ + (((uint32) ((uchar) (A)[5])) << 8) +\ + (((uint32) ((uchar) (A)[6])) << 16) +\ + (((uint32) ((uchar) (A)[7])) << 24))) <<\ + 32)) +#define int2store(T,A) do { uint def_temp= (uint) (A) ;\ + *((uchar*) (T))= (uchar)(def_temp); \ + *((uchar*) (T)+1)=(uchar)((def_temp >> 8)); \ + } while(0) +#define int3store(T,A) do { /*lint -save -e734 */\ + *((uchar*)(T))=(uchar) ((A));\ + *((uchar*) (T)+1)=(uchar) (((A) >> 8));\ + *((uchar*)(T)+2)=(uchar) (((A) >> 16)); \ + /*lint -restore */} while(0) +#define int4store(T,A) do { *((char *)(T))=(char) ((A));\ + *(((char *)(T))+1)=(char) (((A) >> 8));\ + *(((char *)(T))+2)=(char) (((A) >> 16));\ + *(((char *)(T))+3)=(char) (((A) >> 24)); } while(0) +#define int5store(T,A) do { *((char *)(T))= (char)((A)); \ + *(((char *)(T))+1)= (char)(((A) >> 8)); \ + *(((char *)(T))+2)= (char)(((A) >> 16)); \ + *(((char *)(T))+3)= (char)(((A) >> 24)); \ + *(((char *)(T))+4)= (char)(((A) >> 32)); \ + } while(0) +#define int6store(T,A) do { *((char *)(T))= (char)((A)); \ + *(((char *)(T))+1)= (char)(((A) >> 8)); \ + *(((char *)(T))+2)= (char)(((A) >> 16)); \ + *(((char *)(T))+3)= (char)(((A) >> 24)); \ + *(((char *)(T))+4)= (char)(((A) >> 32)); \ + *(((char *)(T))+5)= (char)(((A) >> 40)); \ + } while(0) +#define int8store(T,A) do { uint def_temp= (uint) (A), def_temp2= (uint) ((A) >> 32); \ + int4store((T),def_temp); \ + int4store((T+4),def_temp2); } while(0) +#ifdef WORDS_BIGENDIAN +#define float4store(T,A) do { *(T)= ((uchar *) &A)[3];\ + *((T)+1)=(char) ((uchar *) &A)[2];\ + *((T)+2)=(char) ((uchar *) &A)[1];\ + *((T)+3)=(char) ((uchar *) &A)[0]; } while(0) + +#define float4get(V,M) do { float def_temp;\ + ((uchar*) &def_temp)[0]=(M)[3];\ + ((uchar*) &def_temp)[1]=(M)[2];\ + ((uchar*) &def_temp)[2]=(M)[1];\ + ((uchar*) &def_temp)[3]=(M)[0];\ + (V)=def_temp; } while(0) +#define float8store(T,V) do { *(T)= ((uchar *) &V)[7];\ + *((T)+1)=(char) ((uchar *) &V)[6];\ + *((T)+2)=(char) ((uchar *) &V)[5];\ + *((T)+3)=(char) ((uchar *) &V)[4];\ + *((T)+4)=(char) ((uchar *) &V)[3];\ + *((T)+5)=(char) ((uchar *) &V)[2];\ + *((T)+6)=(char) ((uchar *) &V)[1];\ + *((T)+7)=(char) ((uchar *) &V)[0]; } while(0) + +#define float8get(V,M) do { double def_temp;\ + ((uchar*) &def_temp)[0]=(M)[7];\ + ((uchar*) &def_temp)[1]=(M)[6];\ + ((uchar*) &def_temp)[2]=(M)[5];\ + ((uchar*) &def_temp)[3]=(M)[4];\ + ((uchar*) &def_temp)[4]=(M)[3];\ + ((uchar*) &def_temp)[5]=(M)[2];\ + ((uchar*) &def_temp)[6]=(M)[1];\ + ((uchar*) &def_temp)[7]=(M)[0];\ + (V) = def_temp; } while(0) +#else +#define float4get(V,M) memcpy(&V, (M), sizeof(float)) +#define float4store(V,M) memcpy(V, (&M), sizeof(float)) + +#if defined(__FLOAT_WORD_ORDER) && (__FLOAT_WORD_ORDER == __BIG_ENDIAN) +#define doublestore(T,V) do { *(((char*)T)+0)=(char) ((uchar *) &V)[4];\ + *(((char*)T)+1)=(char) ((uchar *) &V)[5];\ + *(((char*)T)+2)=(char) ((uchar *) &V)[6];\ + *(((char*)T)+3)=(char) ((uchar *) &V)[7];\ + *(((char*)T)+4)=(char) ((uchar *) &V)[0];\ + *(((char*)T)+5)=(char) ((uchar *) &V)[1];\ + *(((char*)T)+6)=(char) ((uchar *) &V)[2];\ + *(((char*)T)+7)=(char) ((uchar *) &V)[3]; }\ + while(0) +#define doubleget(V,M) do { double def_temp;\ + ((uchar*) &def_temp)[0]=(M)[4];\ + ((uchar*) &def_temp)[1]=(M)[5];\ + ((uchar*) &def_temp)[2]=(M)[6];\ + ((uchar*) &def_temp)[3]=(M)[7];\ + ((uchar*) &def_temp)[4]=(M)[0];\ + ((uchar*) &def_temp)[5]=(M)[1];\ + ((uchar*) &def_temp)[6]=(M)[2];\ + ((uchar*) &def_temp)[7]=(M)[3];\ + (V) = def_temp; } while(0) +#endif /* __FLOAT_WORD_ORDER */ + +#define float8get(V,M) doubleget((V),(M)) +#define float8store(V,M) doublestore((V),(M)) +#endif /* WORDS_BIGENDIAN */ + +#endif /* __i386__ OR _WIN32 */ + +/* + Macro for reading 32-bit integer from network byte order (big-endian) + from unaligned memory location. +*/ +#define int4net(A) (int32) (((uint32) ((uchar) (A)[3])) |\ + (((uint32) ((uchar) (A)[2])) << 8) |\ + (((uint32) ((uchar) (A)[1])) << 16) |\ + (((uint32) ((uchar) (A)[0])) << 24)) +/* + Define-funktions for reading and storing in machine format from/to + short/long to/from some place in memory V should be a (not + register) variable, M is a pointer to byte +*/ + +#ifdef WORDS_BIGENDIAN + +#define ushortget(V,M) do { V = (uint16) (((uint16) ((uchar) (M)[1]))+\ + ((uint16) ((uint16) (M)[0]) << 8)); } while(0) +#define shortget(V,M) do { V = (short) (((short) ((uchar) (M)[1]))+\ + ((short) ((short) (M)[0]) << 8)); } while(0) +#define longget(V,M) do { int32 def_temp;\ + ((uchar*) &def_temp)[0]=(M)[0];\ + ((uchar*) &def_temp)[1]=(M)[1];\ + ((uchar*) &def_temp)[2]=(M)[2];\ + ((uchar*) &def_temp)[3]=(M)[3];\ + (V)=def_temp; } while(0) +#define ulongget(V,M) do { uint32 def_temp;\ + ((uchar*) &def_temp)[0]=(M)[0];\ + ((uchar*) &def_temp)[1]=(M)[1];\ + ((uchar*) &def_temp)[2]=(M)[2];\ + ((uchar*) &def_temp)[3]=(M)[3];\ + (V)=def_temp; } while(0) +#define shortstore(T,A) do { uint def_temp=(uint) (A) ;\ + *(((char*)T)+1)=(char)(def_temp); \ + *(((char*)T)+0)=(char)(def_temp >> 8); } while(0) +#define longstore(T,A) do { *(((char*)T)+3)=((A));\ + *(((char*)T)+2)=(((A) >> 8));\ + *(((char*)T)+1)=(((A) >> 16));\ + *(((char*)T)+0)=(((A) >> 24)); } while(0) + +#define floatget(V,M) memcpy(&V, (M), sizeof(float)) +#define floatstore(T,V) memcpy((T), (void*) (&V), sizeof(float)) +#define doubleget(V,M) memcpy(&V, (M), sizeof(double)) +#define doublestore(T,V) memcpy((T), (void *) &V, sizeof(double)) +#define longlongget(V,M) memcpy(&V, (M), sizeof(ulonglong)) +#define longlongstore(T,V) memcpy((T), &V, sizeof(ulonglong)) + +#else + +#define ushortget(V,M) do { V = uint2korr(M); } while(0) +#define shortget(V,M) do { V = sint2korr(M); } while(0) +#define longget(V,M) do { V = sint4korr(M); } while(0) +#define ulongget(V,M) do { V = uint4korr(M); } while(0) +#define shortstore(T,V) int2store(T,V) +#define longstore(T,V) int4store(T,V) +#ifndef floatstore +#define floatstore(T,V) memcpy((T), (void *) (&V), sizeof(float)) +#define floatget(V,M) memcpy(&V, (M), sizeof(float)) +#endif +#ifndef doubleget +#define doubleget(V,M) memcpy(&V, (M), sizeof(double)) +#define doublestore(T,V) memcpy((T), (void *) &V, sizeof(double)) +#endif /* doubleget */ +#define longlongget(V,M) memcpy(&V, (M), sizeof(ulonglong)) +#define longlongstore(T,V) memcpy((T), &V, sizeof(ulonglong)) + +#endif /* WORDS_BIGENDIAN */ + +#ifndef THREAD +#define thread_safe_increment(V,L) (V)++ +#define thread_safe_decrement(V,L) (V)-- +#define thread_safe_add(V,C,L) (V)+=(C) +#define thread_safe_sub(V,C,L) (V)-=(C) +#define statistic_increment(V,L) (V)++ +#define statistic_decrement(V,L) (V)-- +#define statistic_add(V,C,L) (V)+=(C) +#define statistic_sub(V,C,L) (V)-=(C) +#endif + +#ifdef HAVE_CHARSET_utf8 +#define MYSQL_UNIVERSAL_CLIENT_CHARSET "utf8" +#else +#define MYSQL_UNIVERSAL_CLIENT_CHARSET MYSQL_DEFAULT_CHARSET_NAME +#endif + +#if defined(EMBEDDED_LIBRARY) && !defined(HAVE_EMBEDDED_PRIVILEGE_CONTROL) +#define NO_EMBEDDED_ACCESS_CHECKS +#endif + +#if defined(_WIN32) +#define dlsym(lib, name) (void*)GetProcAddress((HMODULE)lib, name) +#define dlopen(libname, unused) LoadLibraryEx(libname, NULL, 0) +#define dlclose(lib) FreeLibrary((HMODULE)lib) +#ifndef HAVE_DLOPEN +#define HAVE_DLOPEN +#endif +#endif + +#ifdef HAVE_DLOPEN +#if defined(HAVE_DLFCN_H) +#include +#endif +#endif + +#ifndef HAVE_DLERROR +#ifdef _WIN32 +#define dlerror() "" +#else +#define dlerror() "No support for dynamic loading (static build?)" +#endif +#endif + + +/* + * Include standard definitions of operator new and delete. + */ +#ifdef __cplusplus +#include +#endif + +/* Length of decimal number represented by INT32. */ +#define MY_INT32_NUM_DECIMAL_DIGITS 11 + +/* Length of decimal number represented by INT64. */ +#define MY_INT64_NUM_DECIMAL_DIGITS 21 + +/* Define some useful general macros (should be done after all headers). */ +#if !defined(max) +#define max(a, b) ((a) > (b) ? (a) : (b)) +#define min(a, b) ((a) < (b) ? (a) : (b)) +#endif + +/* + Only Linux is known to need an explicit sync of the directory to make sure a + file creation/deletion/renaming in(from,to) this directory durable. +*/ +#ifdef TARGET_OS_LINUX +#define NEED_EXPLICIT_SYNC_DIR 1 +#endif + +#if !defined(__cplusplus) && !defined(bool) +#define bool In_C_you_should_use_my_bool_instead() +#endif + +/* Provide __func__ macro definition for platforms that miss it. */ +#if __STDC_VERSION__ < 199901L +# if __GNUC__ >= 2 +# define __func__ __FUNCTION__ +# else +# define __func__ "" +# endif +#elif defined(_MSC_VER) +# if _MSC_VER < 1300 +# define __func__ "" +# else +# define __func__ __FUNCTION__ +# endif +#elif defined(__BORLANDC__) +# define __func__ __FUNC__ +#else +# define __func__ "" +#endif + +#ifndef HAVE_RINT +/** + All integers up to this number can be represented exactly as double precision + values (DBL_MANT_DIG == 53 for IEEE 754 hardware). +*/ +#define MAX_EXACT_INTEGER ((1LL << DBL_MANT_DIG) - 1) + +/** + rint(3) implementation for platforms that do not have it. + Always rounds to the nearest integer with ties being rounded to the nearest + even integer to mimic glibc's rint() behavior in the "round-to-nearest" + FPU mode. Hardware-specific optimizations are possible (frndint on x86). + Unlike this implementation, hardware will also honor the FPU rounding mode. +*/ + +static inline double rint(double x) +{ + double f, i; + f = modf(x, &i); + /* + All doubles with absolute values > MAX_EXACT_INTEGER are even anyway, + no need to check it. + */ + if (x > 0.0) + i += (double) ((f > 0.5) || (f == 0.5 && + i <= (double) MAX_EXACT_INTEGER && + (longlong) i % 2)); + else + i -= (double) ((f < -0.5) || (f == -0.5 && + i >= (double) -MAX_EXACT_INTEGER && + (longlong) i % 2)); + return i; +} +#endif /* HAVE_RINT */ + +/* + MYSQL_PLUGIN_IMPORT macro is used to export mysqld data + (i.e variables) for usage in storage engine loadable plugins. + Outside of Windows, it is dummy. +*/ +#ifndef MYSQL_PLUGIN_IMPORT +#if (defined(_WIN32) && defined(MYSQL_DYNAMIC_PLUGIN)) +#define MYSQL_PLUGIN_IMPORT __declspec(dllimport) +#else +#define MYSQL_PLUGIN_IMPORT +#endif +#endif + +/* Defines that are unique to the embedded version of MySQL */ + +#ifdef EMBEDDED_LIBRARY + +/* Things we don't need in the embedded version of MySQL */ +/* TODO HF add #undef HAVE_VIO if we don't want client in embedded library */ + +#undef HAVE_OPENSSL +#undef HAVE_SMEM /* No shared memory */ +#undef HAVE_NDBCLUSTER_DB /* No NDB cluster */ + +#endif /* EMBEDDED_LIBRARY */ + +#endif /* my_global_h */ diff --git a/include/mysql/my_list.h b/include/mysql/my_list.h new file mode 100644 index 000000000..ff086e172 --- /dev/null +++ b/include/mysql/my_list.h @@ -0,0 +1,45 @@ +/* Copyright (C) 2000 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifndef _list_h_ +#define _list_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct st_list { + struct st_list *prev,*next; + void *data; +} LIST; + +typedef int (*list_walk_action)(void *,void *); + +extern LIST *list_add(LIST *root,LIST *element); +extern LIST *list_delete(LIST *root,LIST *element); +extern LIST *list_cons(void *data,LIST *root); +extern LIST *list_reverse(LIST *root); +extern void list_free(LIST *root,unsigned int free_data); +extern unsigned int list_length(LIST *); +extern int list_walk(LIST *,list_walk_action action,unsigned char * argument); + +#define list_rest(a) ((a)->next) +#define list_push(a,b) (a)=list_cons((b),(a)) +#define list_pop(A) {LIST *old=(A); (A)=list_delete(old,old); my_free(old); } + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/mysql/my_net.h b/include/mysql/my_net.h new file mode 100644 index 000000000..5762f5da0 --- /dev/null +++ b/include/mysql/my_net.h @@ -0,0 +1,110 @@ +/* Copyright (C) 2000 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/* + This file is also used to make handling of sockets and ioctl() + portable accross systems. + +*/ + +#ifndef _my_net_h +#define _my_net_h + +#include "my_global.h" /* C_MODE_START, C_MODE_END */ + +C_MODE_START + +#include +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_POLL +#include +#endif +#ifdef HAVE_SYS_IOCTL_H +#include +#endif + +#if !defined(__WIN__) && !defined(HAVE_BROKEN_NETINET_INCLUDES) +#include +#include +#include +#if !defined(alpha_linux_port) +#include +#endif +#endif + +#if defined(__WIN__) +#define O_NONBLOCK 1 /* For emulation of fcntl() */ + +/* + SHUT_RDWR is called SD_BOTH in windows and + is defined to 2 in winsock2.h + #define SD_BOTH 0x02 +*/ +#define SHUT_RDWR 0x02 + +#endif + +/* + On OSes which don't have the in_addr_t, we guess that using uint32 is the best + possible choice. We guess this from the fact that on HP-UX64bit & FreeBSD64bit + & Solaris64bit, in_addr_t is equivalent to uint32. And on Linux32bit too. +*/ +#ifndef HAVE_IN_ADDR_T +#define in_addr_t uint32 +#endif + +/* + Handling of gethostbyname_r() +*/ + +#if !defined(HAVE_GETHOSTBYNAME_R) +struct hostent *my_gethostbyname_r(const char *name, + struct hostent *result, char *buffer, + int buflen, int *h_errnop); +void my_gethostbyname_r_free(); +#elif defined(HAVE_PTHREAD_ATTR_CREATE) || defined(_AIX) || defined(HAVE_GETHOSTBYNAME_R_GLIBC2_STYLE) +struct hostent *my_gethostbyname_r(const char *name, + struct hostent *result, char *buffer, + int buflen, int *h_errnop); +#define my_gethostbyname_r_free() +#if !defined(HAVE_GETHOSTBYNAME_R_GLIBC2_STYLE) && !defined(HPUX10) +#define GETHOSTBYNAME_BUFF_SIZE sizeof(struct hostent_data) +#endif /* !defined(HAVE_GETHOSTBYNAME_R_GLIBC2_STYLE) */ + +#elif defined(HAVE_GETHOSTBYNAME_R_RETURN_INT) +#define GETHOSTBYNAME_BUFF_SIZE sizeof(struct hostent_data) +struct hostent *my_gethostbyname_r(const char *name, + struct hostent *result, char *buffer, + int buflen, int *h_errnop); +#define my_gethostbyname_r_free() +#else +#define my_gethostbyname_r(A,B,C,D,E) gethostbyname_r((A),(B),(C),(D),(E)) +#define my_gethostbyname_r_free() +#endif /* !defined(HAVE_GETHOSTBYNAME_R) */ + +#ifndef GETHOSTBYNAME_BUFF_SIZE +#define GETHOSTBYNAME_BUFF_SIZE 2048 +#endif + +C_MODE_END +#endif diff --git a/include/mysql/my_no_pthread.h b/include/mysql/my_no_pthread.h new file mode 100644 index 000000000..633a5b94a --- /dev/null +++ b/include/mysql/my_no_pthread.h @@ -0,0 +1,72 @@ +#ifndef MY_NO_PTHREAD_INCLUDED +#define MY_NO_PTHREAD_INCLUDED + +/* Copyright (C) 2000 MySQL AB, 2008-2009 Sun Microsystems, Inc + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + + +#ifndef THREAD + +/* + This block is to access some thread-related type definitions + even in builds which do not need thread functions, + as some variables (based on these types) are declared + even in non-threaded builds. + Case in point: 'mf_keycache.c' +*/ +#if defined(__WIN__) +#else /* Normal threads */ +#include + +#endif /* defined(__WIN__) */ + + +/* + This undefs some pthread mutex locks when one isn't using threads + to make thread safe code, that should also work in single thread + environment, easier to use. +*/ +#define pthread_mutex_init(A,B) +#define pthread_mutex_lock(A) +#define pthread_mutex_unlock(A) +#define pthread_mutex_destroy(A) +#define my_rwlock_init(A,B) +#define rw_rdlock(A) +#define rw_wrlock(A) +#define rw_unlock(A) +#define rwlock_destroy(A) +#define safe_mutex_assert_owner(mp) + +#define mysql_mutex_init(A, B, C) do {} while (0) +#define mysql_mutex_lock(A) do {} while (0) +#define mysql_mutex_unlock(A) do {} while (0) +#define mysql_mutex_destroy(A) do {} while (0) + +#define mysql_rwlock_init(A, B, C) do {} while (0) +#define mysql_rwlock_rdlock(A) do {} while (0) +#define mysql_rwlock_wrlock(A) do {} while (0) +#define mysql_rwlock_unlock(A) do {} while (0) +#define mysql_rwlock_destroy(A) do {} while (0) + +typedef int my_pthread_once_t; +#define MY_PTHREAD_ONCE_INIT 0 +#define MY_PTHREAD_ONCE_DONE 1 + +#define my_pthread_once(C,F) do { \ + if (*(C) != MY_PTHREAD_ONCE_DONE) { F(); *(C)= MY_PTHREAD_ONCE_DONE; } \ + } while(0) + +#endif +#endif /* MY_NO_PTHREAD_INCLUDED */ diff --git a/include/mysql/my_pthread.h b/include/mysql/my_pthread.h new file mode 100644 index 000000000..bec88a716 --- /dev/null +++ b/include/mysql/my_pthread.h @@ -0,0 +1,945 @@ +/* Copyright (C) 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/* Defines to make different thread packages compatible */ + +#ifndef _my_pthread_h +#define _my_pthread_h + +#include "my_global.h" /* myf */ + +#ifndef ETIME +#define ETIME ETIMEDOUT /* For FreeBSD */ +#endif + +#ifdef __cplusplus +#define EXTERNC extern "C" +extern "C" { +#else +#define EXTERNC +#endif /* __cplusplus */ + +#if defined(__WIN__) +typedef CRITICAL_SECTION pthread_mutex_t; +typedef DWORD pthread_t; +typedef struct thread_attr { + DWORD dwStackSize ; + DWORD dwCreatingFlag ; +} pthread_attr_t ; + +typedef struct { int dummy; } pthread_condattr_t; + +/* Implementation of posix conditions */ + +typedef struct st_pthread_link { + DWORD thread_id; + struct st_pthread_link *next; +} pthread_link; + +/** + Implementation of Windows condition variables. + We use native conditions on Vista and later, and fallback to own + implementation on earlier OS version. +*/ +typedef union +{ + /* Native condition (used on Vista and later) */ + CONDITION_VARIABLE native_cond; + + /* Own implementation (used on XP) */ + struct + { + uint32 waiting; + CRITICAL_SECTION lock_waiting; + enum + { + SIGNAL= 0, + BROADCAST= 1, + MAX_EVENTS= 2 + } EVENTS; + HANDLE events[MAX_EVENTS]; + HANDLE broadcast_block_event; + }; +} pthread_cond_t; + + +typedef int pthread_mutexattr_t; +#define pthread_self() GetCurrentThreadId() +#define pthread_handler_t EXTERNC void * __cdecl +typedef void * (__cdecl *pthread_handler)(void *); + +typedef volatile LONG my_pthread_once_t; +#define MY_PTHREAD_ONCE_INIT 0 +#define MY_PTHREAD_ONCE_INPROGRESS 1 +#define MY_PTHREAD_ONCE_DONE 2 + +/* + Struct and macros to be used in combination with the + windows implementation of pthread_cond_timedwait +*/ + +/* + Declare a union to make sure FILETIME is properly aligned + so it can be used directly as a 64 bit value. The value + stored is in 100ns units. + */ + union ft64 { + FILETIME ft; + __int64 i64; + }; +struct timespec { + union ft64 tv; + /* The max timeout value in millisecond for pthread_cond_timedwait */ + long max_timeout_msec; +}; +#define set_timespec(ABSTIME,SEC) { \ + GetSystemTimeAsFileTime(&((ABSTIME).tv.ft)); \ + (ABSTIME).tv.i64+= (__int64)(SEC)*10000000; \ + (ABSTIME).max_timeout_msec= (long)((SEC)*1000); \ +} +#define set_timespec_nsec(ABSTIME,NSEC) { \ + GetSystemTimeAsFileTime(&((ABSTIME).tv.ft)); \ + (ABSTIME).tv.i64+= (__int64)(NSEC)/100; \ + (ABSTIME).max_timeout_msec= (long)((NSEC)/1000000); \ +} + +/** + Compare two timespec structs. + + @retval 1 If TS1 ends after TS2. + + @retval 0 If TS1 is equal to TS2. + + @retval -1 If TS1 ends before TS2. +*/ +#define cmp_timespec(TS1, TS2) \ + ((TS1.tv.i64 > TS2.tv.i64) ? 1 : \ + ((TS1.tv.i64 < TS2.tv.i64) ? -1 : 0)) + + +int win_pthread_mutex_trylock(pthread_mutex_t *mutex); +int pthread_create(pthread_t *, const pthread_attr_t *, pthread_handler, void *); +int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr); +int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); +int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, + struct timespec *abstime); +int pthread_cond_signal(pthread_cond_t *cond); +int pthread_cond_broadcast(pthread_cond_t *cond); +int pthread_cond_destroy(pthread_cond_t *cond); +int pthread_attr_init(pthread_attr_t *connect_att); +int pthread_attr_setstacksize(pthread_attr_t *connect_att,DWORD stack); +int pthread_attr_destroy(pthread_attr_t *connect_att); +int my_pthread_once(my_pthread_once_t *once_control,void (*init_routine)(void)); +struct tm *localtime_r(const time_t *timep,struct tm *tmp); +struct tm *gmtime_r(const time_t *timep,struct tm *tmp); + +void pthread_exit(void *a); +int pthread_join(pthread_t thread, void **value_ptr); +int pthread_cancel(pthread_t thread); + +#ifndef ETIMEDOUT +#define ETIMEDOUT 145 /* Win32 doesn't have this */ +#endif +#define HAVE_LOCALTIME_R 1 +#define _REENTRANT 1 +#define HAVE_PTHREAD_ATTR_SETSTACKSIZE 1 + + +#undef SAFE_MUTEX /* This will cause conflicts */ +#define pthread_key(T,V) DWORD V +#define pthread_key_create(A,B) ((*A=TlsAlloc())==0xFFFFFFFF) +#define pthread_key_delete(A) TlsFree(A) +#define my_pthread_setspecific_ptr(T,V) (!TlsSetValue((T),(V))) +#define pthread_setspecific(A,B) (!TlsSetValue((A),(B))) +#define pthread_getspecific(A) (TlsGetValue(A)) +#define my_pthread_getspecific(T,A) ((T) TlsGetValue(A)) +#define my_pthread_getspecific_ptr(T,V) ((T) TlsGetValue(V)) + +#define pthread_equal(A,B) ((A) == (B)) +#define pthread_mutex_init(A,B) (InitializeCriticalSection(A),0) +#define pthread_mutex_lock(A) (EnterCriticalSection(A),0) +#define pthread_mutex_trylock(A) win_pthread_mutex_trylock((A)) +#define pthread_mutex_unlock(A) (LeaveCriticalSection(A), 0) +#define pthread_mutex_destroy(A) (DeleteCriticalSection(A), 0) +#define pthread_kill(A,B) pthread_dummy((A) ? 0 : ESRCH) + + +/* Dummy defines for easier code */ +#define pthread_attr_setdetachstate(A,B) pthread_dummy(0) +#define pthread_attr_setscope(A,B) +#define pthread_detach_this_thread() +#define pthread_condattr_init(A) +#define pthread_condattr_destroy(A) +#define pthread_yield() SwitchToThread() +#define my_sigset(A,B) signal(A,B) + +#else /* Normal threads */ + +#ifdef HAVE_rts_threads +#define sigwait org_sigwait +#include +#undef sigwait +#endif +#include +#ifndef _REENTRANT +#define _REENTRANT +#endif +#ifdef HAVE_THR_SETCONCURRENCY +#include /* Probably solaris */ +#endif +#ifdef HAVE_SCHED_H +#include +#endif +#ifdef HAVE_SYNCH_H +#include +#endif + +#define pthread_key(T,V) pthread_key_t V +#define my_pthread_getspecific_ptr(T,V) my_pthread_getspecific(T,(V)) +#define my_pthread_setspecific_ptr(T,V) pthread_setspecific(T,(void*) (V)) +#define pthread_detach_this_thread() +#define pthread_handler_t EXTERNC void * +typedef void *(* pthread_handler)(void *); + +#define my_pthread_once_t pthread_once_t +#define MY_PTHREAD_ONCE_INIT PTHREAD_ONCE_INIT +#define my_pthread_once(C,F) pthread_once(C,F) + +/* Test first for RTS or FSU threads */ + +#if defined(PTHREAD_SCOPE_GLOBAL) && !defined(PTHREAD_SCOPE_SYSTEM) +#define HAVE_rts_threads +extern int my_pthread_create_detached; +#define pthread_sigmask(A,B,C) sigprocmask((A),(B),(C)) +#define PTHREAD_CREATE_DETACHED &my_pthread_create_detached +#define PTHREAD_SCOPE_SYSTEM PTHREAD_SCOPE_GLOBAL +#define PTHREAD_SCOPE_PROCESS PTHREAD_SCOPE_LOCAL +#define USE_ALARM_THREAD +#endif /* defined(PTHREAD_SCOPE_GLOBAL) && !defined(PTHREAD_SCOPE_SYSTEM) */ + +#if defined(_BSDI_VERSION) && _BSDI_VERSION < 199910 +int sigwait(sigset_t *set, int *sig); +#endif + +#ifndef HAVE_NONPOSIX_SIGWAIT +#define my_sigwait(A,B) sigwait((A),(B)) +#else +int my_sigwait(const sigset_t *set,int *sig); +#endif + +#ifdef HAVE_NONPOSIX_PTHREAD_MUTEX_INIT +#ifndef SAFE_MUTEX +#define pthread_mutex_init(a,b) my_pthread_mutex_init((a),(b)) +extern int my_pthread_mutex_init(pthread_mutex_t *mp, + const pthread_mutexattr_t *attr); +#endif /* SAFE_MUTEX */ +#define pthread_cond_init(a,b) my_pthread_cond_init((a),(b)) +extern int my_pthread_cond_init(pthread_cond_t *mp, + const pthread_condattr_t *attr); +#endif /* HAVE_NONPOSIX_PTHREAD_MUTEX_INIT */ + +#if defined(HAVE_SIGTHREADMASK) && !defined(HAVE_PTHREAD_SIGMASK) +#define pthread_sigmask(A,B,C) sigthreadmask((A),(B),(C)) +#endif + +#if !defined(HAVE_SIGWAIT) && !defined(HAVE_rts_threads) && !defined(sigwait) && !defined(alpha_linux_port) && !defined(HAVE_NONPOSIX_SIGWAIT) && !defined(HAVE_DEC_3_2_THREADS) && !defined(_AIX) +int sigwait(sigset_t *setp, int *sigp); /* Use our implemention */ +#endif + + +/* + We define my_sigset() and use that instead of the system sigset() so that + we can favor an implementation based on sigaction(). On some systems, such + as Mac OS X, sigset() results in flags such as SA_RESTART being set, and + we want to make sure that no such flags are set. +*/ +#if defined(HAVE_SIGACTION) && !defined(my_sigset) +#define my_sigset(A,B) do { struct sigaction l_s; sigset_t l_set; \ + DBUG_ASSERT((A) != 0); \ + sigemptyset(&l_set); \ + l_s.sa_handler = (B); \ + l_s.sa_mask = l_set; \ + l_s.sa_flags = 0; \ + sigaction((A), &l_s, NULL); \ + } while (0) +#elif defined(HAVE_SIGSET) && !defined(my_sigset) +#define my_sigset(A,B) sigset((A),(B)) +#elif !defined(my_sigset) +#define my_sigset(A,B) signal((A),(B)) +#endif + +#if !defined(HAVE_PTHREAD_ATTR_SETSCOPE) || defined(HAVE_DEC_3_2_THREADS) +#define pthread_attr_setscope(A,B) +#undef HAVE_GETHOSTBYADDR_R /* No definition */ +#endif + +#if defined(HAVE_BROKEN_PTHREAD_COND_TIMEDWAIT) && !defined(SAFE_MUTEX) +extern int my_pthread_cond_timedwait(pthread_cond_t *cond, + pthread_mutex_t *mutex, + struct timespec *abstime); +#define pthread_cond_timedwait(A,B,C) my_pthread_cond_timedwait((A),(B),(C)) +#endif + +#if !defined( HAVE_NONPOSIX_PTHREAD_GETSPECIFIC) +#define my_pthread_getspecific(A,B) ((A) pthread_getspecific(B)) +#else +#define my_pthread_getspecific(A,B) ((A) my_pthread_getspecific_imp(B)) +void *my_pthread_getspecific_imp(pthread_key_t key); +#endif + +#ifndef HAVE_LOCALTIME_R +struct tm *localtime_r(const time_t *clock, struct tm *res); +#endif + +#ifndef HAVE_GMTIME_R +struct tm *gmtime_r(const time_t *clock, struct tm *res); +#endif + +#ifdef HAVE_PTHREAD_CONDATTR_CREATE +/* DCE threads on HPUX 10.20 */ +#define pthread_condattr_init pthread_condattr_create +#define pthread_condattr_destroy pthread_condattr_delete +#endif + +/* FSU THREADS */ +#if !defined(HAVE_PTHREAD_KEY_DELETE) && !defined(pthread_key_delete) +#define pthread_key_delete(A) pthread_dummy(0) +#endif + +#ifdef HAVE_CTHREADS_WRAPPER /* For MacOSX */ +#define pthread_cond_destroy(A) pthread_dummy(0) +#define pthread_mutex_destroy(A) pthread_dummy(0) +#define pthread_attr_delete(A) pthread_dummy(0) +#define pthread_condattr_delete(A) pthread_dummy(0) +#define pthread_attr_setstacksize(A,B) pthread_dummy(0) +#define pthread_equal(A,B) ((A) == (B)) +#define pthread_cond_timedwait(a,b,c) pthread_cond_wait((a),(b)) +#define pthread_attr_init(A) pthread_attr_create(A) +#define pthread_attr_destroy(A) pthread_attr_delete(A) +#define pthread_attr_setdetachstate(A,B) pthread_dummy(0) +#define pthread_create(A,B,C,D) pthread_create((A),*(B),(C),(D)) +#define pthread_sigmask(A,B,C) sigprocmask((A),(B),(C)) +#define pthread_kill(A,B) pthread_dummy((A) ? 0 : ESRCH) +#undef pthread_detach_this_thread +#define pthread_detach_this_thread() { pthread_t tmp=pthread_self() ; pthread_detach(&tmp); } +#endif + +#ifdef HAVE_DARWIN5_THREADS +#define pthread_sigmask(A,B,C) sigprocmask((A),(B),(C)) +#define pthread_kill(A,B) pthread_dummy((A) ? 0 : ESRCH) +#define pthread_condattr_init(A) pthread_dummy(0) +#define pthread_condattr_destroy(A) pthread_dummy(0) +#undef pthread_detach_this_thread +#define pthread_detach_this_thread() { pthread_t tmp=pthread_self() ; pthread_detach(tmp); } +#endif + +#if ((defined(HAVE_PTHREAD_ATTR_CREATE) && !defined(HAVE_SIGWAIT)) || defined(HAVE_DEC_3_2_THREADS)) && !defined(HAVE_CTHREADS_WRAPPER) +/* This is set on AIX_3_2 and Siemens unix (and DEC OSF/1 3.2 too) */ +#define pthread_key_create(A,B) \ + pthread_keycreate(A,(B) ?\ + (pthread_destructor_t) (B) :\ + (pthread_destructor_t) pthread_dummy) +#define pthread_attr_init(A) pthread_attr_create(A) +#define pthread_attr_destroy(A) pthread_attr_delete(A) +#define pthread_attr_setdetachstate(A,B) pthread_dummy(0) +#define pthread_create(A,B,C,D) pthread_create((A),*(B),(C),(D)) +#ifndef pthread_sigmask +#define pthread_sigmask(A,B,C) sigprocmask((A),(B),(C)) +#endif +#define pthread_kill(A,B) pthread_dummy((A) ? 0 : ESRCH) +#undef pthread_detach_this_thread +#define pthread_detach_this_thread() { pthread_t tmp=pthread_self() ; pthread_detach(&tmp); } +#else /* HAVE_PTHREAD_ATTR_CREATE && !HAVE_SIGWAIT */ +#define HAVE_PTHREAD_KILL +#endif + +#endif /* defined(__WIN__) */ + +#if defined(HPUX10) && !defined(DONT_REMAP_PTHREAD_FUNCTIONS) +#undef pthread_cond_timedwait +#define pthread_cond_timedwait(a,b,c) my_pthread_cond_timedwait((a),(b),(c)) +int my_pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, + struct timespec *abstime); +#endif + +#if defined(HPUX10) +#define pthread_attr_getstacksize(A,B) my_pthread_attr_getstacksize(A,B) +void my_pthread_attr_getstacksize(pthread_attr_t *attrib, size_t *size); +#endif + +#if defined(HAVE_POSIX1003_4a_MUTEX) && !defined(DONT_REMAP_PTHREAD_FUNCTIONS) +#undef pthread_mutex_trylock +#define pthread_mutex_trylock(a) my_pthread_mutex_trylock((a)) +int my_pthread_mutex_trylock(pthread_mutex_t *mutex); +#endif + +#if !defined(HAVE_PTHREAD_YIELD_ONE_ARG) && !defined(HAVE_PTHREAD_YIELD_ZERO_ARG) +/* no pthread_yield() available */ +#ifdef HAVE_SCHED_YIELD +#define pthread_yield() sched_yield() +#elif defined(HAVE_PTHREAD_YIELD_NP) /* can be Mac OS X */ +#define pthread_yield() pthread_yield_np() +#elif defined(HAVE_THR_YIELD) +#define pthread_yield() thr_yield() +#endif +#endif + +/* + The defines set_timespec and set_timespec_nsec should be used + for calculating an absolute time at which + pthread_cond_timedwait should timeout +*/ +#ifdef HAVE_TIMESPEC_TS_SEC +#ifndef set_timespec +#define set_timespec(ABSTIME,SEC) \ +{ \ + (ABSTIME).ts_sec=time(0) + (time_t) (SEC); \ + (ABSTIME).ts_nsec=0; \ +} +#endif /* !set_timespec */ +#ifndef set_timespec_nsec +#define set_timespec_nsec(ABSTIME,NSEC) \ +{ \ + ulonglong now= my_getsystime() + (NSEC/100); \ + (ABSTIME).ts_sec= (now / ULL(10000000)); \ + (ABSTIME).ts_nsec= (now % ULL(10000000) * 100 + ((NSEC) % 100)); \ +} +#endif /* !set_timespec_nsec */ +#else +#ifndef set_timespec +#define set_timespec(ABSTIME,SEC) \ +{\ + struct timeval tv;\ + gettimeofday(&tv,0);\ + (ABSTIME).tv_sec=tv.tv_sec+(time_t) (SEC);\ + (ABSTIME).tv_nsec=tv.tv_usec*1000;\ +} +#endif /* !set_timespec */ +#ifndef set_timespec_nsec +#define set_timespec_nsec(ABSTIME,NSEC) \ +{\ + ulonglong now= my_getsystime() + (NSEC/100); \ + (ABSTIME).tv_sec= (time_t) (now / ULL(10000000)); \ + (ABSTIME).tv_nsec= (long) (now % ULL(10000000) * 100 + ((NSEC) % 100)); \ +} +#endif /* !set_timespec_nsec */ +#endif /* HAVE_TIMESPEC_TS_SEC */ + +/** + Compare two timespec structs. + + @retval 1 If TS1 ends after TS2. + + @retval 0 If TS1 is equal to TS2. + + @retval -1 If TS1 ends before TS2. +*/ +#ifdef HAVE_TIMESPEC_TS_SEC +#ifndef cmp_timespec +#define cmp_timespec(TS1, TS2) \ + ((TS1.ts_sec > TS2.ts_sec || \ + (TS1.ts_sec == TS2.ts_sec && TS1.ts_nsec > TS2.ts_nsec)) ? 1 : \ + ((TS1.ts_sec < TS2.ts_sec || \ + (TS1.ts_sec == TS2.ts_sec && TS1.ts_nsec < TS2.ts_nsec)) ? -1 : 0)) +#endif /* !cmp_timespec */ +#else +#ifndef cmp_timespec +#define cmp_timespec(TS1, TS2) \ + ((TS1.tv_sec > TS2.tv_sec || \ + (TS1.tv_sec == TS2.tv_sec && TS1.tv_nsec > TS2.tv_nsec)) ? 1 : \ + ((TS1.tv_sec < TS2.tv_sec || \ + (TS1.tv_sec == TS2.tv_sec && TS1.tv_nsec < TS2.tv_nsec)) ? -1 : 0)) +#endif /* !cmp_timespec */ +#endif /* HAVE_TIMESPEC_TS_SEC */ + + /* safe_mutex adds checking to mutex for easier debugging */ + +typedef struct st_safe_mutex_t +{ + pthread_mutex_t global,mutex; + const char *file; + uint line,count; + pthread_t thread; +#ifdef SAFE_MUTEX_DETECT_DESTROY + struct st_safe_mutex_info_t *info; /* to track destroying of mutexes */ +#endif +} safe_mutex_t; + +#ifdef SAFE_MUTEX_DETECT_DESTROY +/* + Used to track the destroying of mutexes. This needs to be a seperate + structure because the safe_mutex_t structure could be freed before + the mutexes are destroyed. +*/ + +typedef struct st_safe_mutex_info_t +{ + struct st_safe_mutex_info_t *next; + struct st_safe_mutex_info_t *prev; + const char *init_file; + uint32 init_line; +} safe_mutex_info_t; +#endif /* SAFE_MUTEX_DETECT_DESTROY */ + +int safe_mutex_init(safe_mutex_t *mp, const pthread_mutexattr_t *attr, + const char *file, uint line); +int safe_mutex_lock(safe_mutex_t *mp, my_bool try_lock, const char *file, uint line); +int safe_mutex_unlock(safe_mutex_t *mp,const char *file, uint line); +int safe_mutex_destroy(safe_mutex_t *mp,const char *file, uint line); +int safe_cond_wait(pthread_cond_t *cond, safe_mutex_t *mp,const char *file, + uint line); +int safe_cond_timedwait(pthread_cond_t *cond, safe_mutex_t *mp, + const struct timespec *abstime, + const char *file, uint line); +void safe_mutex_global_init(void); +void safe_mutex_end(FILE *file); + + /* Wrappers if safe mutex is actually used */ +#ifdef SAFE_MUTEX +#undef pthread_mutex_init +#undef pthread_mutex_lock +#undef pthread_mutex_unlock +#undef pthread_mutex_destroy +#undef pthread_mutex_wait +#undef pthread_mutex_timedwait +#undef pthread_mutex_t +#undef pthread_cond_wait +#undef pthread_cond_timedwait +#undef pthread_mutex_trylock +#define pthread_mutex_init(A,B) safe_mutex_init((A),(B),__FILE__,__LINE__) +#define pthread_mutex_lock(A) safe_mutex_lock((A), FALSE, __FILE__, __LINE__) +#define pthread_mutex_unlock(A) safe_mutex_unlock((A),__FILE__,__LINE__) +#define pthread_mutex_destroy(A) safe_mutex_destroy((A),__FILE__,__LINE__) +#define pthread_cond_wait(A,B) safe_cond_wait((A),(B),__FILE__,__LINE__) +#define pthread_cond_timedwait(A,B,C) safe_cond_timedwait((A),(B),(C),__FILE__,__LINE__) +#define pthread_mutex_trylock(A) safe_mutex_lock((A), TRUE, __FILE__, __LINE__) +#define pthread_mutex_t safe_mutex_t +#define safe_mutex_assert_owner(mp) \ + DBUG_ASSERT((mp)->count > 0 && \ + pthread_equal(pthread_self(), (mp)->thread)) +#define safe_mutex_assert_not_owner(mp) \ + DBUG_ASSERT(! (mp)->count || \ + ! pthread_equal(pthread_self(), (mp)->thread)) +#else +#define safe_mutex_assert_owner(mp) +#define safe_mutex_assert_not_owner(mp) +#endif /* SAFE_MUTEX */ + +#if defined(MY_PTHREAD_FASTMUTEX) && !defined(SAFE_MUTEX) +typedef struct st_my_pthread_fastmutex_t +{ + pthread_mutex_t mutex; + uint spins; + uint rng_state; +} my_pthread_fastmutex_t; +void fastmutex_global_init(void); + +int my_pthread_fastmutex_init(my_pthread_fastmutex_t *mp, + const pthread_mutexattr_t *attr); +int my_pthread_fastmutex_lock(my_pthread_fastmutex_t *mp); + +#undef pthread_mutex_init +#undef pthread_mutex_lock +#undef pthread_mutex_unlock +#undef pthread_mutex_destroy +#undef pthread_mutex_wait +#undef pthread_mutex_timedwait +#undef pthread_mutex_t +#undef pthread_cond_wait +#undef pthread_cond_timedwait +#undef pthread_mutex_trylock +#define pthread_mutex_init(A,B) my_pthread_fastmutex_init((A),(B)) +#define pthread_mutex_lock(A) my_pthread_fastmutex_lock(A) +#define pthread_mutex_unlock(A) pthread_mutex_unlock(&(A)->mutex) +#define pthread_mutex_destroy(A) pthread_mutex_destroy(&(A)->mutex) +#define pthread_cond_wait(A,B) pthread_cond_wait((A),&(B)->mutex) +#define pthread_cond_timedwait(A,B,C) pthread_cond_timedwait((A),&(B)->mutex,(C)) +#define pthread_mutex_trylock(A) pthread_mutex_trylock(&(A)->mutex) +#define pthread_mutex_t my_pthread_fastmutex_t +#endif /* defined(MY_PTHREAD_FASTMUTEX) && !defined(SAFE_MUTEX) */ + + /* READ-WRITE thread locking */ + +#ifdef HAVE_BROKEN_RWLOCK /* For OpenUnix */ +#undef HAVE_PTHREAD_RWLOCK_RDLOCK +#undef HAVE_RWLOCK_INIT +#undef HAVE_RWLOCK_T +#endif + +#if defined(USE_MUTEX_INSTEAD_OF_RW_LOCKS) +/* use these defs for simple mutex locking */ +#define rw_lock_t pthread_mutex_t +#define my_rwlock_init(A,B) pthread_mutex_init((A),(B)) +#define rw_rdlock(A) pthread_mutex_lock((A)) +#define rw_wrlock(A) pthread_mutex_lock((A)) +#define rw_tryrdlock(A) pthread_mutex_trylock((A)) +#define rw_trywrlock(A) pthread_mutex_trylock((A)) +#define rw_unlock(A) pthread_mutex_unlock((A)) +#define rwlock_destroy(A) pthread_mutex_destroy((A)) +#elif defined(HAVE_PTHREAD_RWLOCK_RDLOCK) +#define rw_lock_t pthread_rwlock_t +#define my_rwlock_init(A,B) pthread_rwlock_init((A),(B)) +#define rw_rdlock(A) pthread_rwlock_rdlock(A) +#define rw_wrlock(A) pthread_rwlock_wrlock(A) +#define rw_tryrdlock(A) pthread_rwlock_tryrdlock((A)) +#define rw_trywrlock(A) pthread_rwlock_trywrlock((A)) +#define rw_unlock(A) pthread_rwlock_unlock(A) +#define rwlock_destroy(A) pthread_rwlock_destroy(A) +#elif defined(HAVE_RWLOCK_INIT) +#ifdef HAVE_RWLOCK_T /* For example Solaris 2.6-> */ +#define rw_lock_t rwlock_t +#endif +#define my_rwlock_init(A,B) rwlock_init((A),USYNC_THREAD,0) +#else +/* Use our own version of read/write locks */ +#define NEED_MY_RW_LOCK 1 +#define rw_lock_t my_rw_lock_t +#define my_rwlock_init(A,B) my_rw_init((A)) +#define rw_rdlock(A) my_rw_rdlock((A)) +#define rw_wrlock(A) my_rw_wrlock((A)) +#define rw_tryrdlock(A) my_rw_tryrdlock((A)) +#define rw_trywrlock(A) my_rw_trywrlock((A)) +#define rw_unlock(A) my_rw_unlock((A)) +#define rwlock_destroy(A) my_rw_destroy((A)) +#define rw_lock_assert_write_owner(A) my_rw_lock_assert_write_owner((A)) +#define rw_lock_assert_not_write_owner(A) my_rw_lock_assert_not_write_owner((A)) +#endif /* USE_MUTEX_INSTEAD_OF_RW_LOCKS */ + + +/** + Portable implementation of special type of read-write locks. + + These locks have two properties which are unusual for rwlocks: + 1) They "prefer readers" in the sense that they do not allow + situations in which rwlock is rd-locked and there is a + pending rd-lock which is blocked (e.g. due to pending + request for wr-lock). + This is a stronger guarantee than one which is provided for + PTHREAD_RWLOCK_PREFER_READER_NP rwlocks in Linux. + MDL subsystem deadlock detector relies on this property for + its correctness. + 2) They are optimized for uncontended wr-lock/unlock case. + This is scenario in which they are most oftenly used + within MDL subsystem. Optimizing for it gives significant + performance improvements in some of tests involving many + connections. + + Another important requirement imposed on this type of rwlock + by the MDL subsystem is that it should be OK to destroy rwlock + object which is in unlocked state even though some threads might + have not yet fully left unlock operation for it (of course there + is an external guarantee that no thread will try to lock rwlock + which is destroyed). + Putting it another way the unlock operation should not access + rwlock data after changing its state to unlocked. + + TODO/FIXME: We should consider alleviating this requirement as + it blocks us from doing certain performance optimizations. +*/ + +typedef struct st_rw_pr_lock_t { + /** + Lock which protects the structure. + Also held for the duration of wr-lock. + */ + pthread_mutex_t lock; + /** + Condition variable which is used to wake-up + writers waiting for readers to go away. + */ + pthread_cond_t no_active_readers; + /** Number of active readers. */ + uint active_readers; + /** Number of writers waiting for readers to go away. */ + uint writers_waiting_readers; + /** Indicates whether there is an active writer. */ + my_bool active_writer; +#ifdef SAFE_MUTEX + /** Thread holding wr-lock (for debug purposes only). */ + pthread_t writer_thread; +#endif +} rw_pr_lock_t; + +extern int rw_pr_init(rw_pr_lock_t *); +extern int rw_pr_rdlock(rw_pr_lock_t *); +extern int rw_pr_wrlock(rw_pr_lock_t *); +extern int rw_pr_unlock(rw_pr_lock_t *); +extern int rw_pr_destroy(rw_pr_lock_t *); +#ifdef SAFE_MUTEX +#define rw_pr_lock_assert_write_owner(A) \ + DBUG_ASSERT((A)->active_writer && pthread_equal(pthread_self(), \ + (A)->writer_thread)) +#define rw_pr_lock_assert_not_write_owner(A) \ + DBUG_ASSERT(! (A)->active_writer || ! pthread_equal(pthread_self(), \ + (A)->writer_thread)) +#else +#define rw_pr_lock_assert_write_owner(A) +#define rw_pr_lock_assert_not_write_owner(A) +#endif /* SAFE_MUTEX */ + + +#ifdef NEED_MY_RW_LOCK + +#ifdef _WIN32 + +/** + Implementation of Windows rwlock. + + We use native (slim) rwlocks on Win7 and later, and fallback to portable + implementation on earlier Windows. + + slim rwlock are also available on Vista/WS2008, but we do not use it + ("trylock" APIs are missing on Vista) +*/ +typedef union +{ + /* Native rwlock (is_srwlock == TRUE) */ + struct + { + SRWLOCK srwlock; /* native reader writer lock */ + BOOL have_exclusive_srwlock; /* used for unlock */ + }; + + /* + Portable implementation (is_srwlock == FALSE) + Fields are identical with Unix my_rw_lock_t fields. + */ + struct + { + pthread_mutex_t lock; /* lock for structure */ + pthread_cond_t readers; /* waiting readers */ + pthread_cond_t writers; /* waiting writers */ + int state; /* -1:writer,0:free,>0:readers */ + int waiters; /* number of waiting writers */ +#ifdef SAFE_MUTEX + pthread_t write_thread; +#endif + }; +} my_rw_lock_t; + + +#else /* _WIN32 */ + +/* + On systems which don't support native read/write locks we have + to use own implementation. +*/ +typedef struct st_my_rw_lock_t { + pthread_mutex_t lock; /* lock for structure */ + pthread_cond_t readers; /* waiting readers */ + pthread_cond_t writers; /* waiting writers */ + int state; /* -1:writer,0:free,>0:readers */ + int waiters; /* number of waiting writers */ +#ifdef SAFE_MUTEX + pthread_t write_thread; +#endif +} my_rw_lock_t; + +#endif /*! _WIN32 */ + +extern int my_rw_init(my_rw_lock_t *); +extern int my_rw_destroy(my_rw_lock_t *); +extern int my_rw_rdlock(my_rw_lock_t *); +extern int my_rw_wrlock(my_rw_lock_t *); +extern int my_rw_unlock(my_rw_lock_t *); +extern int my_rw_tryrdlock(my_rw_lock_t *); +extern int my_rw_trywrlock(my_rw_lock_t *); +#ifdef SAFE_MUTEX +#define my_rw_lock_assert_write_owner(A) \ + DBUG_ASSERT((A)->state == -1 && pthread_equal(pthread_self(), \ + (A)->write_thread)) +#define my_rw_lock_assert_not_write_owner(A) \ + DBUG_ASSERT((A)->state >= 0 || ! pthread_equal(pthread_self(), \ + (A)->write_thread)) +#else +#define my_rw_lock_assert_write_owner(A) +#define my_rw_lock_assert_not_write_owner(A) +#endif +#endif /* NEED_MY_RW_LOCK */ + + +#define GETHOSTBYADDR_BUFF_SIZE 2048 + +#ifndef HAVE_THR_SETCONCURRENCY +#define thr_setconcurrency(A) pthread_dummy(0) +#endif +#if !defined(HAVE_PTHREAD_ATTR_SETSTACKSIZE) && ! defined(pthread_attr_setstacksize) +#define pthread_attr_setstacksize(A,B) pthread_dummy(0) +#endif + +/* Define mutex types, see my_thr_init.c */ +#define MY_MUTEX_INIT_SLOW NULL +#ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP +extern pthread_mutexattr_t my_fast_mutexattr; +#define MY_MUTEX_INIT_FAST &my_fast_mutexattr +#else +#define MY_MUTEX_INIT_FAST NULL +#endif +#ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP +extern pthread_mutexattr_t my_errorcheck_mutexattr; +#define MY_MUTEX_INIT_ERRCHK &my_errorcheck_mutexattr +#else +#define MY_MUTEX_INIT_ERRCHK NULL +#endif + +#ifndef ESRCH +/* Define it to something */ +#define ESRCH 1 +#endif + +typedef ulong my_thread_id; + +extern my_bool my_thread_global_init(void); +extern my_bool my_thread_basic_global_init(void); +extern void my_thread_basic_global_reinit(void); +extern void my_thread_global_end(void); +extern my_bool my_thread_init(void); +extern void my_thread_end(void); +extern const char *my_thread_name(void); +extern my_thread_id my_thread_dbug_id(void); +extern int pthread_dummy(int); + +/* All thread specific variables are in the following struct */ + +#define THREAD_NAME_SIZE 10 +#ifndef DEFAULT_THREAD_STACK +#if SIZEOF_CHARP > 4 +/* + MySQL can survive with 32K, but some glibc libraries require > 128K stack + To resolve hostnames. Also recursive stored procedures needs stack. +*/ +#define DEFAULT_THREAD_STACK (256*1024L) +#else +#define DEFAULT_THREAD_STACK (192*1024) +#endif +#endif + +#include + +#define INSTRUMENT_ME 0 + +struct st_my_thread_var +{ + int thr_errno; + mysql_cond_t suspend; + mysql_mutex_t mutex; + mysql_mutex_t * volatile current_mutex; + mysql_cond_t * volatile current_cond; + pthread_t pthread_self; + my_thread_id id; + int cmp_length; + int volatile abort; + my_bool init; + struct st_my_thread_var *next,**prev; + void *opt_info; + void *stack_ends_here; +#ifndef DBUG_OFF + void *dbug; + char name[THREAD_NAME_SIZE+1]; +#endif +}; + +extern struct st_my_thread_var *_my_thread_var(void) __attribute__ ((const)); +extern void **my_thread_var_dbug(); +extern uint my_thread_end_wait_time; +#define my_thread_var (_my_thread_var()) +#define my_errno my_thread_var->thr_errno +/* + Keep track of shutdown,signal, and main threads so that my_end() will not + report errors with them +*/ + +/* Which kind of thread library is in use */ + +#define THD_LIB_OTHER 1 +#define THD_LIB_NPTL 2 +#define THD_LIB_LT 4 + +extern uint thd_lib_detected; + +/* + thread_safe_xxx functions are for critical statistic or counters. + The implementation is guaranteed to be thread safe, on all platforms. + Note that the calling code should *not* assume the counter is protected + by the mutex given, as the implementation of these helpers may change + to use my_atomic operations instead. +*/ + +/* + Warning: + When compiling without threads, this file is not included. + See the *other* declarations of thread_safe_xxx in include/my_global.h +*/ +#ifdef THREAD +#ifndef thread_safe_increment +#ifdef _WIN32 +#define thread_safe_increment(V,L) InterlockedIncrement((long*) &(V)) +#define thread_safe_decrement(V,L) InterlockedDecrement((long*) &(V)) +#else +#define thread_safe_increment(V,L) \ + (mysql_mutex_lock((L)), (V)++, mysql_mutex_unlock((L))) +#define thread_safe_decrement(V,L) \ + (mysql_mutex_lock((L)), (V)--, mysql_mutex_unlock((L))) +#endif +#endif + +#ifndef thread_safe_add +#ifdef _WIN32 +#define thread_safe_add(V,C,L) InterlockedExchangeAdd((long*) &(V),(C)) +#define thread_safe_sub(V,C,L) InterlockedExchangeAdd((long*) &(V),-(long) (C)) +#else +#define thread_safe_add(V,C,L) \ + (mysql_mutex_lock((L)), (V)+=(C), mysql_mutex_unlock((L))) +#define thread_safe_sub(V,C,L) \ + (mysql_mutex_lock((L)), (V)-=(C), mysql_mutex_unlock((L))) +#endif +#endif +#endif + +/* + statistics_xxx functions are for non critical statistic, + maintained in global variables. + When compiling with SAFE_STATISTICS: + - race conditions can not occur. + - some locking occurs, which may cause performance degradation. + + When compiling without SAFE_STATISTICS: + - race conditions can occur, making the result slightly inaccurate. + - the lock given is not honored. +*/ +#ifdef SAFE_STATISTICS +#define statistic_increment(V,L) thread_safe_increment((V),(L)) +#define statistic_decrement(V,L) thread_safe_decrement((V),(L)) +#define statistic_add(V,C,L) thread_safe_add((V),(C),(L)) +#define statistic_sub(V,C,L) thread_safe_sub((V),(C),(L)) +#else +#define statistic_decrement(V,L) (V)-- +#define statistic_increment(V,L) (V)++ +#define statistic_add(V,C,L) (V)+=(C) +#define statistic_sub(V,C,L) (V)-=(C) +#endif /* SAFE_STATISTICS */ + +/* + No locking needed, the counter is owned by the thread +*/ +#define status_var_increment(V) (V)++ +#define status_var_decrement(V) (V)-- +#define status_var_add(V,C) (V)+=(C) +#define status_var_sub(V,C) (V)-=(C) + +#ifdef __cplusplus +} +#endif +#endif /* _my_ptread_h */ diff --git a/include/mysql/my_sys.h b/include/mysql/my_sys.h new file mode 100644 index 000000000..7b437e2a7 --- /dev/null +++ b/include/mysql/my_sys.h @@ -0,0 +1,975 @@ +/* Copyright (C) 2000-2003 MySQL AB, 2008-2009 Sun Microsystems, Inc + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifndef _my_sys_h +#define _my_sys_h + +#include "my_global.h" /* C_MODE_START, C_MODE_END */ + +C_MODE_START + +#ifdef HAVE_AIOWAIT +#include /* Used by record-cache */ +typedef struct my_aio_result { + aio_result_t result; + int pending; +} my_aio_result; +#endif + +#ifdef HAVE_VALGRIND +# include +# define MEM_UNDEFINED(a,len) VALGRIND_MAKE_MEM_UNDEFINED(a,len) +# define MEM_NOACCESS(a,len) VALGRIND_MAKE_MEM_NOACCESS(a,len) +# define MEM_CHECK_ADDRESSABLE(a,len) VALGRIND_CHECK_MEM_IS_ADDRESSABLE(a,len) +# define MEM_CHECK_DEFINED(a,len) VALGRIND_CHECK_MEM_IS_DEFINED(a,len) +#else /* HAVE_VALGRIND */ +# define MEM_UNDEFINED(a,len) ((void) 0) +# define MEM_NOACCESS(a,len) ((void) 0) +# define MEM_CHECK_ADDRESSABLE(a,len) ((void) 0) +# define MEM_CHECK_DEFINED(a,len) ((void) 0) +#endif /* HAVE_VALGRIND */ + +#ifndef THREAD +extern int my_errno; /* Last error in mysys */ +#else +#include +#endif + +#include /* for CHARSET_INFO */ +#include +#include +#ifdef _WIN32 +#include /*for alloca*/ +#endif + +#define MY_INIT(name) { my_progname= name; my_init(); } + +/** + Max length of an error message generated by mysys utilities. + Some mysys functions produce error messages. These mostly go + to stderr. + This constant defines the size of the buffer used to format + the message. It should be kept in sync with MYSQL_ERRMSG_SIZE, + since sometimes mysys errors are stored in the server diagnostics + area, and we would like to avoid unexpected truncation. +*/ +#define MYSYS_ERRMSG_SIZE (512) + +#define MY_FILE_ERROR ((size_t) -1) + + /* General bitmaps for my_func's */ +#define MY_FFNF 1 /* Fatal if file not found */ +#define MY_FNABP 2 /* Fatal if not all bytes read/writen */ +#define MY_NABP 4 /* Error if not all bytes read/writen */ +#define MY_FAE 8 /* Fatal if any error */ +#define MY_WME 16 /* Write message on error */ +#define MY_WAIT_IF_FULL 32 /* Wait and try again if disk full error */ +#define MY_IGNORE_BADFD 32 /* my_sync: ignore 'bad descriptor' errors */ +#define MY_SYNC_DIR 8192 /* my_create/delete/rename: sync directory */ +#define MY_UNUSED 64 /* Unused (was support for RAID) */ +#define MY_FULL_IO 512 /* For my_read - loop intil I/O is complete */ +#define MY_DONT_CHECK_FILESIZE 128 /* Option to init_io_cache() */ +#define MY_LINK_WARNING 32 /* my_redel() gives warning if links */ +#define MY_COPYTIME 64 /* my_redel() copys time */ +#define MY_DELETE_OLD 256 /* my_create_with_symlink() */ +#define MY_RESOLVE_LINK 128 /* my_realpath(); Only resolve links */ +#define MY_HOLD_ORIGINAL_MODES 128 /* my_copy() holds to file modes */ +#define MY_REDEL_MAKE_BACKUP 256 +#define MY_SEEK_NOT_DONE 32 /* my_lock may have to do a seek */ +#define MY_DONT_WAIT 64 /* my_lock() don't wait if can't lock */ +#define MY_ZEROFILL 32 /* my_malloc(), fill array with zero */ +#define MY_ALLOW_ZERO_PTR 64 /* my_realloc() ; zero ptr -> malloc */ +#define MY_FREE_ON_ERROR 128 /* my_realloc() ; Free old ptr on error */ +#define MY_HOLD_ON_ERROR 256 /* my_realloc() ; Return old ptr on error */ +#define MY_DONT_OVERWRITE_FILE 1024 /* my_copy: Don't overwrite file */ +#define MY_THREADSAFE 2048 /* my_seek(): lock fd mutex */ +#define MY_SYNC 4096 /* my_copy(): sync dst file */ + +#define MY_CHECK_ERROR 1 /* Params to my_end; Check open-close */ +#define MY_GIVE_INFO 2 /* Give time info about process*/ +#define MY_DONT_FREE_DBUG 4 /* Do not call DBUG_END() in my_end() */ + +#define ME_HIGHBYTE 8 /* Shift for colours */ +#define ME_NOCUR 1 /* Don't use curses message */ +#define ME_OLDWIN 2 /* Use old window */ +#define ME_BELL 4 /* Ring bell then printing message */ +#define ME_HOLDTANG 8 /* Don't delete last keys */ +#define ME_WAITTOT 16 /* Wait for errtime secs of for a action */ +#define ME_WAITTANG 32 /* Wait for a user action */ +#define ME_NOREFRESH 64 /* Dont refresh screen */ +#define ME_NOINPUT 128 /* Dont use the input libary */ +#define ME_COLOUR1 ((1 << ME_HIGHBYTE)) /* Possibly error-colours */ +#define ME_COLOUR2 ((2 << ME_HIGHBYTE)) +#define ME_COLOUR3 ((3 << ME_HIGHBYTE)) +#define ME_FATALERROR 1024 /* Fatal statement error */ + + /* Bits in last argument to fn_format */ +#define MY_REPLACE_DIR 1 /* replace dir in name with 'dir' */ +#define MY_REPLACE_EXT 2 /* replace extension with 'ext' */ +#define MY_UNPACK_FILENAME 4 /* Unpack name (~ -> home) */ +#define MY_PACK_FILENAME 8 /* Pack name (home -> ~) */ +#define MY_RESOLVE_SYMLINKS 16 /* Resolve all symbolic links */ +#define MY_RETURN_REAL_PATH 32 /* return full path for file */ +#define MY_SAFE_PATH 64 /* Return NULL if too long path */ +#define MY_RELATIVE_PATH 128 /* name is relative to 'dir' */ +#define MY_APPEND_EXT 256 /* add 'ext' as additional extension*/ + + + /* My seek flags */ +#define MY_SEEK_SET 0 +#define MY_SEEK_CUR 1 +#define MY_SEEK_END 2 + + /* Some constants */ +#define MY_WAIT_FOR_USER_TO_FIX_PANIC 60 /* in seconds */ +#define MY_WAIT_GIVE_USER_A_MESSAGE 10 /* Every 10 times of prev */ +#define MIN_COMPRESS_LENGTH 50 /* Don't compress small bl. */ +#define DFLT_INIT_HITS 3 + + /* root_alloc flags */ +#define MY_KEEP_PREALLOC 1 +#define MY_MARK_BLOCKS_FREE 2 /* move used to free list and reuse them */ + + /* Internal error numbers (for assembler functions) */ +#define MY_ERRNO_EDOM 33 +#define MY_ERRNO_ERANGE 34 + + /* Bits for get_date timeflag */ +#define GETDATE_DATE_TIME 1 +#define GETDATE_SHORT_DATE 2 +#define GETDATE_HHMMSSTIME 4 +#define GETDATE_GMT 8 +#define GETDATE_FIXEDLENGTH 16 + + /* defines when allocating data */ +extern void *my_malloc(size_t Size,myf MyFlags); +extern void *my_multi_malloc(myf MyFlags, ...); +extern void *my_realloc(void *oldpoint, size_t Size, myf MyFlags); +extern void my_free(void *ptr); +extern void *my_memdup(const void *from,size_t length,myf MyFlags); +extern char *my_strdup(const char *from,myf MyFlags); +extern char *my_strndup(const char *from, size_t length, + myf MyFlags); +#define TRASH(A,B) do{MEM_CHECK_ADDRESSABLE(A,B);MEM_UNDEFINED(A,B);} while (0) +#if defined(ENABLED_DEBUG_SYNC) +extern void (*debug_sync_C_callback_ptr)(const char *, size_t); +#define DEBUG_SYNC_C(_sync_point_name_) do { \ + if (debug_sync_C_callback_ptr != NULL) \ + (*debug_sync_C_callback_ptr)(STRING_WITH_LEN(_sync_point_name_)); } \ + while(0) +#else +#define DEBUG_SYNC_C(_sync_point_name_) +#endif /* defined(ENABLED_DEBUG_SYNC) */ + +#ifdef HAVE_LARGE_PAGES +extern uint my_get_large_page_size(void); +extern uchar * my_large_malloc(size_t size, myf my_flags); +extern void my_large_free(uchar *ptr); +#else +#define my_get_large_page_size() (0) +#define my_large_malloc(A,B) my_malloc_lock((A),(B)) +#define my_large_free(A) my_free_lock((A)) +#endif /* HAVE_LARGE_PAGES */ + +#ifdef HAVE_ALLOCA +#if defined(_AIX) && !defined(__GNUC__) && !defined(_AIX43) +#pragma alloca +#endif /* _AIX */ +#if defined(__MWERKS__) +#undef alloca +#define alloca _alloca +#endif /* __MWERKS__ */ +#if defined(__GNUC__) && !defined(HAVE_ALLOCA_H) && ! defined(alloca) +#define alloca __builtin_alloca +#endif /* GNUC */ +#define my_alloca(SZ) alloca((size_t) (SZ)) +#define my_afree(PTR) {} +#else +#define my_alloca(SZ) my_malloc(SZ,MYF(MY_FAE)) +#define my_afree(PTR) my_free(PTR) +#endif /* HAVE_ALLOCA */ + +#ifndef errno /* did we already get it? */ +#ifdef HAVE_ERRNO_AS_DEFINE +#include /* errno is a define */ +#else +extern int errno; /* declare errno */ +#endif +#endif /* #ifndef errno */ +extern char *home_dir; /* Home directory for user */ +extern const char *my_progname; /* program-name (printed in errors) */ +extern char curr_dir[]; /* Current directory for user */ +extern void (*error_handler_hook)(uint my_err, const char *str,myf MyFlags); +extern void (*fatal_error_handler_hook)(uint my_err, const char *str, + myf MyFlags); +extern uint my_file_limit; +extern ulong my_thread_stack_size; + +extern const char *(*proc_info_hook)(void *, const char *, const char *, + const char *, const unsigned int); + +#ifdef HAVE_LARGE_PAGES +extern my_bool my_use_large_pages; +extern uint my_large_page_size; +#endif + +/* charsets */ +#define MY_ALL_CHARSETS_SIZE 2048 +extern MYSQL_PLUGIN_IMPORT CHARSET_INFO *default_charset_info; +extern MYSQL_PLUGIN_IMPORT CHARSET_INFO *all_charsets[MY_ALL_CHARSETS_SIZE]; +extern CHARSET_INFO compiled_charsets[]; + +/* statistics */ +extern ulong my_file_opened,my_stream_opened, my_tmp_file_created; +extern ulong my_file_total_opened; +extern uint mysys_usage_id; +extern my_bool my_init_done; + + /* Point to current my_message() */ +extern void (*my_sigtstp_cleanup)(void), + /* Executed before jump to shell */ + (*my_sigtstp_restart)(void), + (*my_abort_hook)(int); + /* Executed when comming from shell */ +extern MYSQL_PLUGIN_IMPORT int my_umask; /* Default creation mask */ +extern int my_umask_dir, + my_recived_signals, /* Signals we have got */ + my_safe_to_handle_signal, /* Set when allowed to SIGTSTP */ + my_dont_interrupt; /* call remember_intr when set */ +extern my_bool my_use_symdir; + +extern ulong my_default_record_cache_size; +extern my_bool my_disable_locking, my_disable_async_io, + my_disable_flush_key_blocks, my_disable_symlinks; +extern char wild_many,wild_one,wild_prefix; +extern const char *charsets_dir; +/* from default.c */ +extern const char *my_defaults_extra_file; +extern const char *my_defaults_group_suffix; +extern const char *my_defaults_file; + +extern my_bool timed_mutexes; + +enum loglevel { + ERROR_LEVEL, + WARNING_LEVEL, + INFORMATION_LEVEL +}; + +enum cache_type +{ + TYPE_NOT_SET= 0, READ_CACHE, WRITE_CACHE, + SEQ_READ_APPEND /* sequential read or append */, + READ_FIFO, READ_NET,WRITE_NET}; + +enum flush_type +{ + FLUSH_KEEP, /* flush block and keep it in the cache */ + FLUSH_RELEASE, /* flush block and remove it from the cache */ + FLUSH_IGNORE_CHANGED, /* remove block from the cache */ + /* + As my_disable_flush_pagecache_blocks is always 0, the following option + is strictly equivalent to FLUSH_KEEP + */ + FLUSH_FORCE_WRITE +}; + +typedef struct st_record_cache /* Used when cacheing records */ +{ + File file; + int rc_seek,error,inited; + uint rc_length,read_length,reclength; + my_off_t rc_record_pos,end_of_file; + uchar *rc_buff,*rc_buff2,*rc_pos,*rc_end,*rc_request_pos; +#ifdef HAVE_AIOWAIT + int use_async_io; + my_aio_result aio_result; +#endif + enum cache_type type; +} RECORD_CACHE; + +enum file_type +{ + UNOPEN = 0, FILE_BY_OPEN, FILE_BY_CREATE, STREAM_BY_FOPEN, STREAM_BY_FDOPEN, + FILE_BY_MKSTEMP, FILE_BY_DUP +}; + +struct st_my_file_info +{ + char *name; +#ifdef _WIN32 + HANDLE fhandle; /* win32 file handle */ + int oflag; /* open flags, e.g O_APPEND */ +#endif + enum file_type type; +#if defined(THREAD) && !defined(HAVE_PREAD) && !defined(_WIN32) + mysql_mutex_t mutex; +#endif +}; + +extern struct st_my_file_info *my_file_info; + +typedef struct st_dynamic_array +{ + uchar *buffer; + uint elements,max_element; + uint alloc_increment; + uint size_of_element; +} DYNAMIC_ARRAY; + +typedef struct st_my_tmpdir +{ + DYNAMIC_ARRAY full_list; + char **list; + uint cur, max; +#ifdef THREAD + mysql_mutex_t mutex; +#endif +} MY_TMPDIR; + +typedef struct st_dynamic_string +{ + char *str; + size_t length,max_length,alloc_increment; +} DYNAMIC_STRING; + +struct st_io_cache; +typedef int (*IO_CACHE_CALLBACK)(struct st_io_cache*); + +#ifdef THREAD +typedef struct st_io_cache_share +{ + mysql_mutex_t mutex; /* To sync on reads into buffer. */ + mysql_cond_t cond; /* To wait for signals. */ + mysql_cond_t cond_writer; /* For a synchronized writer. */ + /* Offset in file corresponding to the first byte of buffer. */ + my_off_t pos_in_file; + /* If a synchronized write cache is the source of the data. */ + struct st_io_cache *source_cache; + uchar *buffer; /* The read buffer. */ + uchar *read_end; /* Behind last valid byte of buffer. */ + int running_threads; /* threads not in lock. */ + int total_threads; /* threads sharing the cache. */ + int error; /* Last error. */ +#ifdef NOT_YET_IMPLEMENTED + /* whether the structure should be free'd */ + my_bool alloced; +#endif +} IO_CACHE_SHARE; +#endif + +typedef struct st_io_cache /* Used when cacheing files */ +{ + /* Offset in file corresponding to the first byte of uchar* buffer. */ + my_off_t pos_in_file; + /* + The offset of end of file for READ_CACHE and WRITE_CACHE. + For SEQ_READ_APPEND it the maximum of the actual end of file and + the position represented by read_end. + */ + my_off_t end_of_file; + /* Points to current read position in the buffer */ + uchar *read_pos; + /* the non-inclusive boundary in the buffer for the currently valid read */ + uchar *read_end; + uchar *buffer; /* The read buffer */ + /* Used in ASYNC_IO */ + uchar *request_pos; + + /* Only used in WRITE caches and in SEQ_READ_APPEND to buffer writes */ + uchar *write_buffer; + /* + Only used in SEQ_READ_APPEND, and points to the current read position + in the write buffer. Note that reads in SEQ_READ_APPEND caches can + happen from both read buffer (uchar* buffer) and write buffer + (uchar* write_buffer). + */ + uchar *append_read_pos; + /* Points to current write position in the write buffer */ + uchar *write_pos; + /* The non-inclusive boundary of the valid write area */ + uchar *write_end; + + /* + Current_pos and current_end are convenience variables used by + my_b_tell() and other routines that need to know the current offset + current_pos points to &write_pos, and current_end to &write_end in a + WRITE_CACHE, and &read_pos and &read_end respectively otherwise + */ + uchar **current_pos, **current_end; +#ifdef THREAD + /* + The lock is for append buffer used in SEQ_READ_APPEND cache + need mutex copying from append buffer to read buffer. + */ + mysql_mutex_t append_buffer_lock; + /* + The following is used when several threads are reading the + same file in parallel. They are synchronized on disk + accesses reading the cached part of the file asynchronously. + It should be set to NULL to disable the feature. Only + READ_CACHE mode is supported. + */ + IO_CACHE_SHARE *share; +#endif + /* + A caller will use my_b_read() macro to read from the cache + if the data is already in cache, it will be simply copied with + memcpy() and internal variables will be accordinging updated with + no functions invoked. However, if the data is not fully in the cache, + my_b_read() will call read_function to fetch the data. read_function + must never be invoked directly. + */ + int (*read_function)(struct st_io_cache *,uchar *,size_t); + /* + Same idea as in the case of read_function, except my_b_write() needs to + be replaced with my_b_append() for a SEQ_READ_APPEND cache + */ + int (*write_function)(struct st_io_cache *,const uchar *,size_t); + /* + Specifies the type of the cache. Depending on the type of the cache + certain operations might not be available and yield unpredicatable + results. Details to be documented later + */ + enum cache_type type; + /* + Callbacks when the actual read I/O happens. These were added and + are currently used for binary logging of LOAD DATA INFILE - when a + block is read from the file, we create a block create/append event, and + when IO_CACHE is closed, we create an end event. These functions could, + of course be used for other things + */ + IO_CACHE_CALLBACK pre_read; + IO_CACHE_CALLBACK post_read; + IO_CACHE_CALLBACK pre_close; + /* + Counts the number of times, when we were forced to use disk. We use it to + increase the binlog_cache_disk_use status variable. + */ + ulong disk_writes; + void* arg; /* for use by pre/post_read */ + char *file_name; /* if used with 'open_cached_file' */ + char *dir,*prefix; + File file; /* file descriptor */ + /* + seek_not_done is set by my_b_seek() to inform the upcoming read/write + operation that a seek needs to be preformed prior to the actual I/O + error is 0 if the cache operation was successful, -1 if there was a + "hard" error, and the actual number of I/O-ed bytes if the read/write was + partial. + */ + int seek_not_done,error; + /* buffer_length is memory size allocated for buffer or write_buffer */ + size_t buffer_length; + /* read_length is the same as buffer_length except when we use async io */ + size_t read_length; + myf myflags; /* Flags used to my_read/my_write */ + /* + alloced_buffer is 1 if the buffer was allocated by init_io_cache() and + 0 if it was supplied by the user. + Currently READ_NET is the only one that will use a buffer allocated + somewhere else + */ + my_bool alloced_buffer; +#ifdef HAVE_AIOWAIT + /* + As inidicated by ifdef, this is for async I/O, which is not currently + used (because it's not reliable on all systems) + */ + uint inited; + my_off_t aio_read_pos; + my_aio_result aio_result; +#endif +} IO_CACHE; + +typedef int (*qsort2_cmp)(const void *, const void *, const void *); + + /* defines for mf_iocache */ + + /* Test if buffer is inited */ +#define my_b_clear(info) (info)->buffer=0 +#define my_b_inited(info) (info)->buffer +#define my_b_EOF INT_MIN + +#define my_b_read(info,Buffer,Count) \ + ((info)->read_pos + (Count) <= (info)->read_end ?\ + (memcpy(Buffer,(info)->read_pos,(size_t) (Count)), \ + ((info)->read_pos+=(Count)),0) :\ + (*(info)->read_function)((info),Buffer,Count)) + +#define my_b_write(info,Buffer,Count) \ + ((info)->write_pos + (Count) <=(info)->write_end ?\ + (memcpy((info)->write_pos, (Buffer), (size_t)(Count)),\ + ((info)->write_pos+=(Count)),0) : \ + (*(info)->write_function)((info),(uchar *)(Buffer),(Count))) + +#define my_b_get(info) \ + ((info)->read_pos != (info)->read_end ?\ + ((info)->read_pos++, (int) (uchar) (info)->read_pos[-1]) :\ + _my_b_get(info)) + + /* my_b_write_byte dosn't have any err-check */ +#define my_b_write_byte(info,chr) \ + (((info)->write_pos < (info)->write_end) ?\ + ((*(info)->write_pos++)=(chr)) :\ + (_my_b_write(info,0,0) , ((*(info)->write_pos++)=(chr)))) + +#define my_b_fill_cache(info) \ + (((info)->read_end=(info)->read_pos),(*(info)->read_function)(info,0,0)) + +#define my_b_tell(info) ((info)->pos_in_file + \ + (size_t) (*(info)->current_pos - (info)->request_pos)) + +#define my_b_get_buffer_start(info) (info)->request_pos +#define my_b_get_bytes_in_buffer(info) (char*) (info)->read_end - \ + (char*) my_b_get_buffer_start(info) +#define my_b_get_pos_in_file(info) (info)->pos_in_file + +/* tell write offset in the SEQ_APPEND cache */ +int my_b_copy_to_file(IO_CACHE *cache, FILE *file); +my_off_t my_b_append_tell(IO_CACHE* info); +my_off_t my_b_safe_tell(IO_CACHE* info); /* picks the correct tell() */ + +#define my_b_bytes_in_cache(info) (size_t) (*(info)->current_end - \ + *(info)->current_pos) + +typedef uint32 ha_checksum; + +/* Define the type of function to be passed to process_default_option_files */ +typedef int (*Process_option_func)(void *ctx, const char *group_name, + const char *option); + +#include + + + /* Prototypes for mysys and my_func functions */ + +extern int my_copy(const char *from,const char *to,myf MyFlags); +extern int my_delete(const char *name,myf MyFlags); +extern int my_getwd(char * buf,size_t size,myf MyFlags); +extern int my_setwd(const char *dir,myf MyFlags); +extern int my_lock(File fd,int op,my_off_t start, my_off_t length,myf MyFlags); +extern void *my_once_alloc(size_t Size,myf MyFlags); +extern void my_once_free(void); +extern char *my_once_strdup(const char *src,myf myflags); +extern void *my_once_memdup(const void *src, size_t len, myf myflags); +extern File my_open(const char *FileName,int Flags,myf MyFlags); +extern File my_register_filename(File fd, const char *FileName, + enum file_type type_of_file, + uint error_message_number, myf MyFlags); +extern File my_create(const char *FileName,int CreateFlags, + int AccessFlags, myf MyFlags); +extern int my_close(File Filedes,myf MyFlags); +extern int my_mkdir(const char *dir, int Flags, myf MyFlags); +extern int my_readlink(char *to, const char *filename, myf MyFlags); +extern int my_is_symlink(const char *filename); +extern int my_realpath(char *to, const char *filename, myf MyFlags); +extern File my_create_with_symlink(const char *linkname, const char *filename, + int createflags, int access_flags, + myf MyFlags); +extern int my_delete_with_symlink(const char *name, myf MyFlags); +extern int my_rename_with_symlink(const char *from,const char *to,myf MyFlags); +extern int my_symlink(const char *content, const char *linkname, myf MyFlags); +extern size_t my_read(File Filedes,uchar *Buffer,size_t Count,myf MyFlags); +extern size_t my_pread(File Filedes,uchar *Buffer,size_t Count,my_off_t offset, + myf MyFlags); +extern int my_rename(const char *from,const char *to,myf MyFlags); +extern my_off_t my_seek(File fd,my_off_t pos,int whence,myf MyFlags); +extern my_off_t my_tell(File fd,myf MyFlags); +extern size_t my_write(File Filedes,const uchar *Buffer,size_t Count, + myf MyFlags); +extern size_t my_pwrite(File Filedes,const uchar *Buffer,size_t Count, + my_off_t offset,myf MyFlags); +extern size_t my_fread(FILE *stream,uchar *Buffer,size_t Count,myf MyFlags); +extern size_t my_fwrite(FILE *stream,const uchar *Buffer,size_t Count, + myf MyFlags); +extern my_off_t my_fseek(FILE *stream,my_off_t pos,int whence,myf MyFlags); +extern my_off_t my_ftell(FILE *stream,myf MyFlags); + +/* implemented in my_memmem.c */ +extern void *my_memmem(const void *haystack, size_t haystacklen, + const void *needle, size_t needlelen); + + +#ifdef _WIN32 +extern int my_access(const char *path, int amode); +#else +#define my_access access +#endif + +extern int check_if_legal_filename(const char *path); +extern int check_if_legal_tablename(const char *path); + +#ifdef _WIN32 +extern int nt_share_delete(const char *name,myf MyFlags); +#define my_delete_allow_opened(fname,flags) nt_share_delete((fname),(flags)) +#else +#define my_delete_allow_opened(fname,flags) my_delete((fname),(flags)) +#endif + +#ifdef _WIN32 +/* Windows-only functions (CRT equivalents)*/ +extern HANDLE my_get_osfhandle(File fd); +extern void my_osmaperr(unsigned long last_error); +#endif + +extern void init_glob_errs(void); +extern const char** get_global_errmsgs(); +extern void wait_for_free_space(const char *filename, int errors); +extern FILE *my_fopen(const char *FileName,int Flags,myf MyFlags); +extern FILE *my_fdopen(File Filedes,const char *name, int Flags,myf MyFlags); +extern int my_fclose(FILE *fd,myf MyFlags); +extern File my_fileno(FILE *fd); +extern int my_chsize(File fd,my_off_t newlength, int filler, myf MyFlags); +extern int my_sync(File fd, myf my_flags); +extern int my_sync_dir(const char *dir_name, myf my_flags); +extern int my_sync_dir_by_file(const char *file_name, myf my_flags); +extern void my_error(int nr,myf MyFlags, ...); +extern void my_printf_error(uint my_err, const char *format, + myf MyFlags, ...) + ATTRIBUTE_FORMAT(printf, 2, 4); +extern void my_printv_error(uint error, const char *format, myf MyFlags, + va_list ap); +extern int my_error_register(const char** (*get_errmsgs) (), + int first, int last); +extern const char **my_error_unregister(int first, int last); +extern void my_message(uint my_err, const char *str,myf MyFlags); +extern void my_message_stderr(uint my_err, const char *str, myf MyFlags); +extern my_bool my_basic_init(void); +extern my_bool my_init(void); +extern void my_end(int infoflag); +extern int my_redel(const char *from, const char *to, int MyFlags); +extern int my_copystat(const char *from, const char *to, int MyFlags); +extern char * my_filename(File fd); + +#ifndef THREAD +extern void dont_break(void); +extern void allow_break(void); +#else +#define dont_break() +#define allow_break() +#endif + +#ifdef EXTRA_DEBUG +void my_print_open_files(void); +#else +#define my_print_open_files() +#endif + +extern my_bool init_tmpdir(MY_TMPDIR *tmpdir, const char *pathlist); +extern char *my_tmpdir(MY_TMPDIR *tmpdir); +extern void free_tmpdir(MY_TMPDIR *tmpdir); + +extern void my_remember_signal(int signal_number,sig_handler (*func)(int)); +extern size_t dirname_part(char * to,const char *name, size_t *to_res_length); +extern size_t dirname_length(const char *name); +#define base_name(A) (A+dirname_length(A)) +extern int test_if_hard_path(const char *dir_name); +extern my_bool has_path(const char *name); +extern char *convert_dirname(char *to, const char *from, const char *from_end); +extern void to_unix_path(char * name); +extern char * fn_ext(const char *name); +extern char * fn_same(char * toname,const char *name,int flag); +extern char * fn_format(char * to,const char *name,const char *dir, + const char *form, uint flag); +extern size_t strlength(const char *str); +extern void pack_dirname(char * to,const char *from); +extern size_t normalize_dirname(char * to, const char *from); +extern size_t unpack_dirname(char * to,const char *from); +extern size_t cleanup_dirname(char * to,const char *from); +extern size_t system_filename(char * to,const char *from); +extern size_t unpack_filename(char * to,const char *from); +extern char * intern_filename(char * to,const char *from); +extern char * directory_file_name(char * dst, const char *src); +extern int pack_filename(char * to, const char *name, size_t max_length); +extern char * my_path(char * to,const char *progname, + const char *own_pathname_part); +extern char * my_load_path(char * to, const char *path, + const char *own_path_prefix); +extern int wild_compare(const char *str,const char *wildstr, + pbool str_is_pattern); +extern my_bool array_append_string_unique(const char *str, + const char **array, size_t size); +extern void get_date(char * to,int timeflag,time_t use_time); +extern void soundex(CHARSET_INFO *, char * out_pntr, char * in_pntr, + pbool remove_garbage); +extern int init_record_cache(RECORD_CACHE *info,size_t cachesize,File file, + size_t reclength,enum cache_type type, + pbool use_async_io); +extern int read_cache_record(RECORD_CACHE *info,uchar *to); +extern int end_record_cache(RECORD_CACHE *info); +extern int write_cache_record(RECORD_CACHE *info,my_off_t filepos, + const uchar *record,size_t length); +extern int flush_write_cache(RECORD_CACHE *info); +extern void handle_recived_signals(void); + +extern sig_handler my_set_alarm_variable(int signo); +extern void my_string_ptr_sort(uchar *base,uint items,size_t size); +extern void radixsort_for_str_ptr(uchar* base[], uint number_of_elements, + size_t size_of_element,uchar *buffer[]); +extern qsort_t my_qsort(void *base_ptr, size_t total_elems, size_t size, + qsort_cmp cmp); +extern qsort_t my_qsort2(void *base_ptr, size_t total_elems, size_t size, + qsort2_cmp cmp, void *cmp_argument); +extern qsort2_cmp get_ptr_compare(size_t); +void my_store_ptr(uchar *buff, size_t pack_length, my_off_t pos); +my_off_t my_get_ptr(uchar *ptr, size_t pack_length); +extern int init_io_cache(IO_CACHE *info,File file,size_t cachesize, + enum cache_type type,my_off_t seek_offset, + pbool use_async_io, myf cache_myflags); +extern my_bool reinit_io_cache(IO_CACHE *info,enum cache_type type, + my_off_t seek_offset,pbool use_async_io, + pbool clear_cache); +extern void setup_io_cache(IO_CACHE* info); +extern int _my_b_read(IO_CACHE *info,uchar *Buffer,size_t Count); +#ifdef THREAD +extern int _my_b_read_r(IO_CACHE *info,uchar *Buffer,size_t Count); +extern void init_io_cache_share(IO_CACHE *read_cache, IO_CACHE_SHARE *cshare, + IO_CACHE *write_cache, uint num_threads); +extern void remove_io_thread(IO_CACHE *info); +#endif +extern int _my_b_seq_read(IO_CACHE *info,uchar *Buffer,size_t Count); +extern int _my_b_net_read(IO_CACHE *info,uchar *Buffer,size_t Count); +extern int _my_b_get(IO_CACHE *info); +extern int _my_b_async_read(IO_CACHE *info,uchar *Buffer,size_t Count); +extern int _my_b_write(IO_CACHE *info,const uchar *Buffer,size_t Count); +extern int my_b_append(IO_CACHE *info,const uchar *Buffer,size_t Count); +extern int my_b_safe_write(IO_CACHE *info,const uchar *Buffer,size_t Count); + +extern int my_block_write(IO_CACHE *info, const uchar *Buffer, + size_t Count, my_off_t pos); +extern int my_b_flush_io_cache(IO_CACHE *info, int need_append_buffer_lock); + +#define flush_io_cache(info) my_b_flush_io_cache((info),1) + +extern int end_io_cache(IO_CACHE *info); +extern size_t my_b_fill(IO_CACHE *info); +extern void my_b_seek(IO_CACHE *info,my_off_t pos); +extern size_t my_b_gets(IO_CACHE *info, char *to, size_t max_length); +extern my_off_t my_b_filelength(IO_CACHE *info); +extern size_t my_b_printf(IO_CACHE *info, const char* fmt, ...); +extern size_t my_b_vprintf(IO_CACHE *info, const char* fmt, va_list ap); +extern my_bool open_cached_file(IO_CACHE *cache,const char *dir, + const char *prefix, size_t cache_size, + myf cache_myflags); +extern my_bool real_open_cached_file(IO_CACHE *cache); +extern void close_cached_file(IO_CACHE *cache); +File create_temp_file(char *to, const char *dir, const char *pfx, + int mode, myf MyFlags); +#define my_init_dynamic_array(A,B,C,D) init_dynamic_array2(A,B,NULL,C,D) +#define my_init_dynamic_array_ci(A,B,C,D) init_dynamic_array2(A,B,NULL,C,D) +#define my_init_dynamic_array2(A,B,C,D,E) init_dynamic_array2(A,B,C,D,E) +#define my_init_dynamic_array2_ci(A,B,C,D,E) init_dynamic_array2(A,B,C,D,E) +extern my_bool init_dynamic_array2(DYNAMIC_ARRAY *array, uint element_size, + void *init_buffer, uint init_alloc, + uint alloc_increment); +/* init_dynamic_array() function is deprecated */ +extern my_bool init_dynamic_array(DYNAMIC_ARRAY *array, uint element_size, + uint init_alloc, uint alloc_increment); +extern my_bool insert_dynamic(DYNAMIC_ARRAY *array,uchar * element); +extern uchar *alloc_dynamic(DYNAMIC_ARRAY *array); +extern uchar *pop_dynamic(DYNAMIC_ARRAY*); +extern my_bool set_dynamic(DYNAMIC_ARRAY *array,uchar * element,uint array_index); +extern my_bool allocate_dynamic(DYNAMIC_ARRAY *array, uint max_elements); +extern void get_dynamic(DYNAMIC_ARRAY *array,uchar * element,uint array_index); +extern void delete_dynamic(DYNAMIC_ARRAY *array); +extern void delete_dynamic_element(DYNAMIC_ARRAY *array, uint array_index); +extern void freeze_size(DYNAMIC_ARRAY *array); +extern int get_index_dynamic(DYNAMIC_ARRAY *array, uchar * element); +#define dynamic_array_ptr(array,array_index) ((array)->buffer+(array_index)*(array)->size_of_element) +#define dynamic_element(array,array_index,type) ((type)((array)->buffer) +(array_index)) +#define push_dynamic(A,B) insert_dynamic((A),(B)) +#define reset_dynamic(array) ((array)->elements= 0) +#define sort_dynamic(A,cmp) my_qsort((A)->buffer, (A)->elements, (A)->size_of_element, (cmp)) + +extern my_bool init_dynamic_string(DYNAMIC_STRING *str, const char *init_str, + size_t init_alloc,size_t alloc_increment); +extern my_bool dynstr_append(DYNAMIC_STRING *str, const char *append); +my_bool dynstr_append_mem(DYNAMIC_STRING *str, const char *append, + size_t length); +extern my_bool dynstr_append_os_quoted(DYNAMIC_STRING *str, const char *append, + ...); +extern my_bool dynstr_set(DYNAMIC_STRING *str, const char *init_str); +extern my_bool dynstr_realloc(DYNAMIC_STRING *str, size_t additional_size); +extern my_bool dynstr_trunc(DYNAMIC_STRING *str, size_t n); +extern void dynstr_free(DYNAMIC_STRING *str); +#ifdef HAVE_MLOCK +extern void *my_malloc_lock(size_t length,myf flags); +extern void my_free_lock(void *ptr); +#else +#define my_malloc_lock(A,B) my_malloc((A),(B)) +#define my_free_lock(A) my_free((A)) +#endif +#define alloc_root_inited(A) ((A)->min_malloc != 0) +#define ALLOC_ROOT_MIN_BLOCK_SIZE (MALLOC_OVERHEAD + sizeof(USED_MEM) + 8) +#define clear_alloc_root(A) do { (A)->free= (A)->used= (A)->pre_alloc= 0; (A)->min_malloc=0;} while(0) +extern void init_alloc_root(MEM_ROOT *mem_root, size_t block_size, + size_t pre_alloc_size); +extern void *alloc_root(MEM_ROOT *mem_root, size_t Size); +extern void *multi_alloc_root(MEM_ROOT *mem_root, ...); +extern void free_root(MEM_ROOT *root, myf MyFLAGS); +extern void set_prealloc_root(MEM_ROOT *root, char *ptr); +extern void reset_root_defaults(MEM_ROOT *mem_root, size_t block_size, + size_t prealloc_size); +extern char *strdup_root(MEM_ROOT *root,const char *str); +static inline char *safe_strdup_root(MEM_ROOT *root, const char *str) +{ + return str ? strdup_root(root, str) : 0; +} +extern char *strmake_root(MEM_ROOT *root,const char *str,size_t len); +extern void *memdup_root(MEM_ROOT *root,const void *str, size_t len); +extern int get_defaults_options(int argc, char **argv, + char **defaults, char **extra_defaults, + char **group_suffix); +extern const char *args_separator; +extern int my_load_defaults(const char *conf_file, const char **groups, + int *argc, char ***argv, const char ***); +extern int load_defaults(const char *conf_file, const char **groups, + int *argc, char ***argv); +extern int my_search_option_files(const char *conf_file, int *argc, + char ***argv, uint *args_used, + Process_option_func func, void *func_ctx, + const char **default_directories); +extern void free_defaults(char **argv); +extern void my_print_default_files(const char *conf_file); +extern void print_defaults(const char *conf_file, const char **groups); +extern my_bool my_compress(uchar *, size_t *, size_t *); +extern my_bool my_uncompress(uchar *, size_t , size_t *); +extern uchar *my_compress_alloc(const uchar *packet, size_t *len, + size_t *complen); +extern int packfrm(uchar *, size_t, uchar **, size_t *); +extern int unpackfrm(uchar **, size_t *, const uchar *); + +extern ha_checksum my_checksum(ha_checksum crc, const uchar *mem, + size_t count); +extern void my_sleep(ulong m_seconds); +extern ulong crc32(ulong crc, const uchar *buf, uint len); +extern uint my_set_max_open_files(uint files); +void my_free_open_file_info(void); + +extern time_t my_time(myf flags); +extern ulonglong my_getsystime(void); +extern ulonglong my_micro_time(); +extern ulonglong my_micro_time_and_time(time_t *time_arg); +time_t my_time_possible_from_micro(ulonglong microtime); +extern my_bool my_gethwaddr(uchar *to); +extern int my_getncpus(); + +#ifdef HAVE_SYS_MMAN_H +#include + +#ifndef MAP_NOSYNC +#define MAP_NOSYNC 0 +#endif +#ifndef MAP_NORESERVE +#define MAP_NORESERVE 0 /* For irix and AIX */ +#endif + +#ifdef HAVE_MMAP64 +#define my_mmap(a,b,c,d,e,f) mmap64(a,b,c,d,e,f) +#else +#define my_mmap(a,b,c,d,e,f) mmap(a,b,c,d,e,f) +#endif +#define my_munmap(a,b) munmap((a),(b)) + +#else +/* not a complete set of mmap() flags, but only those that nesessary */ +#define PROT_READ 1 +#define PROT_WRITE 2 +#define MAP_NORESERVE 0 +#define MAP_SHARED 0x0001 +#define MAP_PRIVATE 0x0002 +#define MAP_NOSYNC 0x0800 +#define MAP_FAILED ((void *)-1) +#define MS_SYNC 0x0000 + +#define HAVE_MMAP +void *my_mmap(void *, size_t, int, int, int, my_off_t); +int my_munmap(void *, size_t); +#endif + +/* my_getpagesize */ +#ifdef HAVE_GETPAGESIZE +#define my_getpagesize() getpagesize() +#else +int my_getpagesize(void); +#endif + +int my_msync(int, void *, size_t, int); + +/* character sets */ +extern uint get_charset_number(const char *cs_name, uint cs_flags); +extern uint get_collation_number(const char *name); +extern const char *get_charset_name(uint cs_number); + +extern CHARSET_INFO *get_charset(uint cs_number, myf flags); +extern CHARSET_INFO *get_charset_by_name(const char *cs_name, myf flags); +extern CHARSET_INFO *get_charset_by_csname(const char *cs_name, + uint cs_flags, myf my_flags); + +extern my_bool resolve_charset(const char *cs_name, + CHARSET_INFO *default_cs, + CHARSET_INFO **cs); +extern my_bool resolve_collation(const char *cl_name, + CHARSET_INFO *default_cl, + CHARSET_INFO **cl); +extern void free_charsets(void); +extern char *get_charsets_dir(char *buf); +extern my_bool my_charset_same(CHARSET_INFO *cs1, CHARSET_INFO *cs2); +extern my_bool init_compiled_charsets(myf flags); +extern void add_compiled_collation(CHARSET_INFO *cs); +extern size_t escape_string_for_mysql(CHARSET_INFO *charset_info, + char *to, size_t to_length, + const char *from, size_t length); +#ifdef __WIN__ +#define BACKSLASH_MBTAIL +/* File system character set */ +extern CHARSET_INFO *fs_character_set(void); +#endif +extern size_t escape_quotes_for_mysql(CHARSET_INFO *charset_info, + char *to, size_t to_length, + const char *from, size_t length); + +extern void thd_increment_bytes_sent(ulong length); +extern void thd_increment_bytes_received(ulong length); +extern void thd_increment_net_big_packet_count(ulong length); + +#ifdef __WIN__ +extern my_bool have_tcpip; /* Is set if tcpip is used */ + +/* implemented in my_windac.c */ + +int my_security_attr_create(SECURITY_ATTRIBUTES **psa, const char **perror, + DWORD owner_rights, DWORD everybody_rights); + +void my_security_attr_free(SECURITY_ATTRIBUTES *sa); + +/* implemented in my_conio.c */ +char* my_cgets(char *string, size_t clen, size_t* plen); + +#endif + +#include + +#ifdef HAVE_PSI_INTERFACE +extern MYSQL_PLUGIN_IMPORT struct PSI_bootstrap *PSI_hook; +void my_init_mysys_psi_keys(void); +#endif + +struct st_mysql_file; +extern struct st_mysql_file *mysql_stdin; + +C_MODE_END +#endif /* _my_sys_h */ diff --git a/include/mysql/my_xml.h b/include/mysql/my_xml.h new file mode 100644 index 000000000..6a453ee90 --- /dev/null +++ b/include/mysql/my_xml.h @@ -0,0 +1,89 @@ +/* Copyright (C) 2000 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + + +#ifndef _my_xml_h +#define _my_xml_h + +#ifdef __cplusplus +extern "C" { +#endif + + +#define MY_XML_OK 0 +#define MY_XML_ERROR 1 + +/* + A flag whether to use absolute tag names in call-back functions, + like "a", "a.b" and "a.b.c" (used in character set file parser), + or relative names like "a", "b" and "c". +*/ +#define MY_XML_FLAG_RELATIVE_NAMES 1 + +/* + A flag whether to skip normilization of text values before calling + call-back functions: i.e. skip leading/trailing spaces, + \r, \n, \t characters. +*/ +#define MY_XML_FLAG_SKIP_TEXT_NORMALIZATION 2 + +enum my_xml_node_type +{ + MY_XML_NODE_TAG, /* can have TAG, ATTR and TEXT children */ + MY_XML_NODE_ATTR, /* can have TEXT children */ + MY_XML_NODE_TEXT /* cannot have children */ +}; + +typedef struct xml_stack_st +{ + int flags; + enum my_xml_node_type current_node_type; + char errstr[128]; + char attr[128]; + char *attrend; + const char *beg; + const char *cur; + const char *end; + void *user_data; + int (*enter)(struct xml_stack_st *st,const char *val, size_t len); + int (*value)(struct xml_stack_st *st,const char *val, size_t len); + int (*leave_xml)(struct xml_stack_st *st,const char *val, size_t len); +} MY_XML_PARSER; + +void my_xml_parser_create(MY_XML_PARSER *st); +void my_xml_parser_free(MY_XML_PARSER *st); +int my_xml_parse(MY_XML_PARSER *st,const char *str, size_t len); + +void my_xml_set_value_handler(MY_XML_PARSER *st, int (*)(MY_XML_PARSER *, + const char *, + size_t len)); +void my_xml_set_enter_handler(MY_XML_PARSER *st, int (*)(MY_XML_PARSER *, + const char *, + size_t len)); +void my_xml_set_leave_handler(MY_XML_PARSER *st, int (*)(MY_XML_PARSER *, + const char *, + size_t len)); +void my_xml_set_user_data(MY_XML_PARSER *st, void *); + +size_t my_xml_error_pos(MY_XML_PARSER *st); +uint my_xml_error_lineno(MY_XML_PARSER *st); + +const char *my_xml_error_string(MY_XML_PARSER *st); + +#ifdef __cplusplus +} +#endif + +#endif /* _my_xml_h */ diff --git a/include/mysql/mysql.h b/include/mysql/mysql.h new file mode 100644 index 000000000..d3b24f019 --- /dev/null +++ b/include/mysql/mysql.h @@ -0,0 +1,713 @@ +/* Copyright (C) 2000-2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/* + This file defines the client API to MySQL and also the ABI of the + dynamically linked libmysqlclient. + + The ABI should never be changed in a released product of MySQL, + thus you need to take great care when changing the file. In case + the file is changed so the ABI is broken, you must also update + the SHARED_LIB_MAJOR_VERSION in cmake/mysql_version.cmake +*/ + +#ifndef _mysql_h +#define _mysql_h + +#ifdef _AIX /* large-file support will break without this */ +#include +#endif + +#ifdef __CYGWIN__ /* CYGWIN implements a UNIX API */ +#undef WIN +#undef _WIN +#undef _WIN32 +#undef _WIN64 +#undef __WIN__ +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _global_h /* If not standard header */ +#ifndef MYSQL_ABI_CHECK +#include +#endif +#ifdef __LCC__ +#include /* For windows */ +#endif +typedef char my_bool; +#if (defined(_WIN32) || defined(_WIN64)) && !defined(__WIN__) +#define __WIN__ +#endif +#if !defined(__WIN__) +#define STDCALL +#else +#define STDCALL __stdcall +#endif + +#ifndef my_socket_defined +#ifdef __WIN__ +#define my_socket SOCKET +#else +typedef int my_socket; +#endif /* __WIN__ */ +#endif /* my_socket_defined */ +#endif /* _global_h */ + +#include "mysql_version.h" +#include "mysql_com.h" +#include "mysql_time.h" + +#include "my_list.h" /* for LISTs used in 'MYSQL' and 'MYSQL_STMT' */ + +extern unsigned int mysql_port; +extern char *mysql_unix_port; + +#define CLIENT_NET_READ_TIMEOUT 365*24*3600 /* Timeout on read */ +#define CLIENT_NET_WRITE_TIMEOUT 365*24*3600 /* Timeout on write */ + +#define IS_PRI_KEY(n) ((n) & PRI_KEY_FLAG) +#define IS_NOT_NULL(n) ((n) & NOT_NULL_FLAG) +#define IS_BLOB(n) ((n) & BLOB_FLAG) +/** + Returns true if the value is a number which does not need quotes for + the sql_lex.cc parser to parse correctly. +*/ +#define IS_NUM(t) (((t) <= MYSQL_TYPE_INT24 && (t) != MYSQL_TYPE_TIMESTAMP) || (t) == MYSQL_TYPE_YEAR || (t) == MYSQL_TYPE_NEWDECIMAL) +#define IS_LONGDATA(t) ((t) >= MYSQL_TYPE_TINY_BLOB && (t) <= MYSQL_TYPE_STRING) + + +typedef struct st_mysql_field { + char *name; /* Name of column */ + char *org_name; /* Original column name, if an alias */ + char *table; /* Table of column if column was a field */ + char *org_table; /* Org table name, if table was an alias */ + char *db; /* Database for table */ + char *catalog; /* Catalog for table */ + char *def; /* Default value (set by mysql_list_fields) */ + unsigned long length; /* Width of column (create length) */ + unsigned long max_length; /* Max width for selected set */ + unsigned int name_length; + unsigned int org_name_length; + unsigned int table_length; + unsigned int org_table_length; + unsigned int db_length; + unsigned int catalog_length; + unsigned int def_length; + unsigned int flags; /* Div flags */ + unsigned int decimals; /* Number of decimals in field */ + unsigned int charsetnr; /* Character set */ + enum enum_field_types type; /* Type of field. See mysql_com.h for types */ + void *extension; +} MYSQL_FIELD; + +typedef char **MYSQL_ROW; /* return data as array of strings */ +typedef unsigned int MYSQL_FIELD_OFFSET; /* offset to current field */ + +#ifndef _global_h +#if defined(NO_CLIENT_LONG_LONG) +typedef unsigned long my_ulonglong; +#elif defined (__WIN__) +typedef unsigned __int64 my_ulonglong; +#else +typedef unsigned long long my_ulonglong; +#endif +#endif + +#include "typelib.h" + +#define MYSQL_COUNT_ERROR (~(my_ulonglong) 0) + +/* backward compatibility define - to be removed eventually */ +#define ER_WARN_DATA_TRUNCATED WARN_DATA_TRUNCATED + +typedef struct st_mysql_rows { + struct st_mysql_rows *next; /* list of rows */ + MYSQL_ROW data; + unsigned long length; +} MYSQL_ROWS; + +typedef MYSQL_ROWS *MYSQL_ROW_OFFSET; /* offset to current row */ + +#include "my_alloc.h" + +typedef struct embedded_query_result EMBEDDED_QUERY_RESULT; +typedef struct st_mysql_data { + MYSQL_ROWS *data; + struct embedded_query_result *embedded_info; + MEM_ROOT alloc; + my_ulonglong rows; + unsigned int fields; + /* extra info for embedded library */ + void *extension; +} MYSQL_DATA; + +enum mysql_option +{ + MYSQL_OPT_CONNECT_TIMEOUT, MYSQL_OPT_COMPRESS, MYSQL_OPT_NAMED_PIPE, + MYSQL_INIT_COMMAND, MYSQL_READ_DEFAULT_FILE, MYSQL_READ_DEFAULT_GROUP, + MYSQL_SET_CHARSET_DIR, MYSQL_SET_CHARSET_NAME, MYSQL_OPT_LOCAL_INFILE, + MYSQL_OPT_PROTOCOL, MYSQL_SHARED_MEMORY_BASE_NAME, MYSQL_OPT_READ_TIMEOUT, + MYSQL_OPT_WRITE_TIMEOUT, MYSQL_OPT_USE_RESULT, + MYSQL_OPT_USE_REMOTE_CONNECTION, MYSQL_OPT_USE_EMBEDDED_CONNECTION, + MYSQL_OPT_GUESS_CONNECTION, MYSQL_SET_CLIENT_IP, MYSQL_SECURE_AUTH, + MYSQL_REPORT_DATA_TRUNCATION, MYSQL_OPT_RECONNECT, + MYSQL_OPT_SSL_VERIFY_SERVER_CERT, MYSQL_PLUGIN_DIR, MYSQL_DEFAULT_AUTH +}; + +/** + @todo remove the "extension", move st_mysql_options completely + out of mysql.h +*/ +struct st_mysql_options_extention; + +struct st_mysql_options { + unsigned int connect_timeout, read_timeout, write_timeout; + unsigned int port, protocol; + unsigned long client_flag; + char *host,*user,*password,*unix_socket,*db; + struct st_dynamic_array *init_commands; + char *my_cnf_file,*my_cnf_group, *charset_dir, *charset_name; + char *ssl_key; /* PEM key file */ + char *ssl_cert; /* PEM cert file */ + char *ssl_ca; /* PEM CA file */ + char *ssl_capath; /* PEM directory of CA-s? */ + char *ssl_cipher; /* cipher to use */ + char *shared_memory_base_name; + unsigned long max_allowed_packet; + my_bool use_ssl; /* if to use SSL or not */ + my_bool compress,named_pipe; + my_bool unused1; + my_bool unused2; + my_bool unused3; + my_bool unused4; + enum mysql_option methods_to_use; + char *client_ip; + /* Refuse client connecting to server if it uses old (pre-4.1.1) protocol */ + my_bool secure_auth; + /* 0 - never report, 1 - always report (default) */ + my_bool report_data_truncation; + + /* function pointers for local infile support */ + int (*local_infile_init)(void **, const char *, void *); + int (*local_infile_read)(void *, char *, unsigned int); + void (*local_infile_end)(void *); + int (*local_infile_error)(void *, char *, unsigned int); + void *local_infile_userdata; + struct st_mysql_options_extention *extension; +}; + +enum mysql_status +{ + MYSQL_STATUS_READY, MYSQL_STATUS_GET_RESULT, MYSQL_STATUS_USE_RESULT, + MYSQL_STATUS_STATEMENT_GET_RESULT +}; + +enum mysql_protocol_type +{ + MYSQL_PROTOCOL_DEFAULT, MYSQL_PROTOCOL_TCP, MYSQL_PROTOCOL_SOCKET, + MYSQL_PROTOCOL_PIPE, MYSQL_PROTOCOL_MEMORY +}; + +typedef struct character_set +{ + unsigned int number; /* character set number */ + unsigned int state; /* character set state */ + const char *csname; /* collation name */ + const char *name; /* character set name */ + const char *comment; /* comment */ + const char *dir; /* character set directory */ + unsigned int mbminlen; /* min. length for multibyte strings */ + unsigned int mbmaxlen; /* max. length for multibyte strings */ +} MY_CHARSET_INFO; + +struct st_mysql_methods; +struct st_mysql_stmt; + +typedef struct st_mysql +{ + NET net; /* Communication parameters */ + unsigned char *connector_fd; /* ConnectorFd for SSL */ + char *host,*user,*passwd,*unix_socket,*server_version,*host_info; + char *info, *db; + struct charset_info_st *charset; + MYSQL_FIELD *fields; + MEM_ROOT field_alloc; + my_ulonglong affected_rows; + my_ulonglong insert_id; /* id if insert on table with NEXTNR */ + my_ulonglong extra_info; /* Not used */ + unsigned long thread_id; /* Id for connection in server */ + unsigned long packet_length; + unsigned int port; + unsigned long client_flag,server_capabilities; + unsigned int protocol_version; + unsigned int field_count; + unsigned int server_status; + unsigned int server_language; + unsigned int warning_count; + struct st_mysql_options options; + enum mysql_status status; + my_bool free_me; /* If free in mysql_close */ + my_bool reconnect; /* set to 1 if automatic reconnect */ + + /* session-wide random string */ + char scramble[SCRAMBLE_LENGTH+1]; + my_bool unused1; + void *unused2, *unused3, *unused4, *unused5; + + LIST *stmts; /* list of all statements */ + const struct st_mysql_methods *methods; + void *thd; + /* + Points to boolean flag in MYSQL_RES or MYSQL_STMT. We set this flag + from mysql_stmt_close if close had to cancel result set of this object. + */ + my_bool *unbuffered_fetch_owner; + /* needed for embedded server - no net buffer to store the 'info' */ + char *info_buffer; + void *extension; +} MYSQL; + + +typedef struct st_mysql_res { + my_ulonglong row_count; + MYSQL_FIELD *fields; + MYSQL_DATA *data; + MYSQL_ROWS *data_cursor; + unsigned long *lengths; /* column lengths of current row */ + MYSQL *handle; /* for unbuffered reads */ + const struct st_mysql_methods *methods; + MYSQL_ROW row; /* If unbuffered read */ + MYSQL_ROW current_row; /* buffer to current row */ + MEM_ROOT field_alloc; + unsigned int field_count, current_field; + my_bool eof; /* Used by mysql_fetch_row */ + /* mysql_stmt_close() had to cancel this result */ + my_bool unbuffered_fetch_cancelled; + void *extension; +} MYSQL_RES; + + +#if !defined(MYSQL_SERVER) && !defined(MYSQL_CLIENT) +#define MYSQL_CLIENT +#endif + + +typedef struct st_mysql_parameters +{ + unsigned long *p_max_allowed_packet; + unsigned long *p_net_buffer_length; + void *extension; +} MYSQL_PARAMETERS; + +#if !defined(MYSQL_SERVER) && !defined(EMBEDDED_LIBRARY) +#define max_allowed_packet (*mysql_get_parameters()->p_max_allowed_packet) +#define net_buffer_length (*mysql_get_parameters()->p_net_buffer_length) +#endif + +/* + Set up and bring down the server; to ensure that applications will + work when linked against either the standard client library or the + embedded server library, these functions should be called. +*/ +int STDCALL mysql_server_init(int argc, char **argv, char **groups); +void STDCALL mysql_server_end(void); + +/* + mysql_server_init/end need to be called when using libmysqld or + libmysqlclient (exactly, mysql_server_init() is called by mysql_init() so + you don't need to call it explicitely; but you need to call + mysql_server_end() to free memory). The names are a bit misleading + (mysql_SERVER* to be used when using libmysqlCLIENT). So we add more general + names which suit well whether you're using libmysqld or libmysqlclient. We + intend to promote these aliases over the mysql_server* ones. +*/ +#define mysql_library_init mysql_server_init +#define mysql_library_end mysql_server_end + +MYSQL_PARAMETERS *STDCALL mysql_get_parameters(void); + +/* + Set up and bring down a thread; these function should be called + for each thread in an application which opens at least one MySQL + connection. All uses of the connection(s) should be between these + function calls. +*/ +my_bool STDCALL mysql_thread_init(void); +void STDCALL mysql_thread_end(void); + +/* + Functions to get information from the MYSQL and MYSQL_RES structures + Should definitely be used if one uses shared libraries. +*/ + +my_ulonglong STDCALL mysql_num_rows(MYSQL_RES *res); +unsigned int STDCALL mysql_num_fields(MYSQL_RES *res); +my_bool STDCALL mysql_eof(MYSQL_RES *res); +MYSQL_FIELD *STDCALL mysql_fetch_field_direct(MYSQL_RES *res, + unsigned int fieldnr); +MYSQL_FIELD * STDCALL mysql_fetch_fields(MYSQL_RES *res); +MYSQL_ROW_OFFSET STDCALL mysql_row_tell(MYSQL_RES *res); +MYSQL_FIELD_OFFSET STDCALL mysql_field_tell(MYSQL_RES *res); + +unsigned int STDCALL mysql_field_count(MYSQL *mysql); +my_ulonglong STDCALL mysql_affected_rows(MYSQL *mysql); +my_ulonglong STDCALL mysql_insert_id(MYSQL *mysql); +unsigned int STDCALL mysql_errno(MYSQL *mysql); +const char * STDCALL mysql_error(MYSQL *mysql); +const char *STDCALL mysql_sqlstate(MYSQL *mysql); +unsigned int STDCALL mysql_warning_count(MYSQL *mysql); +const char * STDCALL mysql_info(MYSQL *mysql); +unsigned long STDCALL mysql_thread_id(MYSQL *mysql); +const char * STDCALL mysql_character_set_name(MYSQL *mysql); +int STDCALL mysql_set_character_set(MYSQL *mysql, const char *csname); + +MYSQL * STDCALL mysql_init(MYSQL *mysql); +my_bool STDCALL mysql_ssl_set(MYSQL *mysql, const char *key, + const char *cert, const char *ca, + const char *capath, const char *cipher); +const char * STDCALL mysql_get_ssl_cipher(MYSQL *mysql); +my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user, + const char *passwd, const char *db); +MYSQL * STDCALL mysql_real_connect(MYSQL *mysql, const char *host, + const char *user, + const char *passwd, + const char *db, + unsigned int port, + const char *unix_socket, + unsigned long clientflag); +int STDCALL mysql_select_db(MYSQL *mysql, const char *db); +int STDCALL mysql_query(MYSQL *mysql, const char *q); +int STDCALL mysql_send_query(MYSQL *mysql, const char *q, + unsigned long length); +int STDCALL mysql_real_query(MYSQL *mysql, const char *q, + unsigned long length); +MYSQL_RES * STDCALL mysql_store_result(MYSQL *mysql); +MYSQL_RES * STDCALL mysql_use_result(MYSQL *mysql); + +void STDCALL mysql_get_character_set_info(MYSQL *mysql, + MY_CHARSET_INFO *charset); + +/* local infile support */ + +#define LOCAL_INFILE_ERROR_LEN 512 + +void +mysql_set_local_infile_handler(MYSQL *mysql, + int (*local_infile_init)(void **, const char *, + void *), + int (*local_infile_read)(void *, char *, + unsigned int), + void (*local_infile_end)(void *), + int (*local_infile_error)(void *, char*, + unsigned int), + void *); + +void +mysql_set_local_infile_default(MYSQL *mysql); + +int STDCALL mysql_shutdown(MYSQL *mysql, + enum mysql_enum_shutdown_level + shutdown_level); +int STDCALL mysql_dump_debug_info(MYSQL *mysql); +int STDCALL mysql_refresh(MYSQL *mysql, + unsigned int refresh_options); +int STDCALL mysql_kill(MYSQL *mysql,unsigned long pid); +int STDCALL mysql_set_server_option(MYSQL *mysql, + enum enum_mysql_set_option + option); +int STDCALL mysql_ping(MYSQL *mysql); +const char * STDCALL mysql_stat(MYSQL *mysql); +const char * STDCALL mysql_get_server_info(MYSQL *mysql); +const char * STDCALL mysql_get_client_info(void); +unsigned long STDCALL mysql_get_client_version(void); +const char * STDCALL mysql_get_host_info(MYSQL *mysql); +unsigned long STDCALL mysql_get_server_version(MYSQL *mysql); +unsigned int STDCALL mysql_get_proto_info(MYSQL *mysql); +MYSQL_RES * STDCALL mysql_list_dbs(MYSQL *mysql,const char *wild); +MYSQL_RES * STDCALL mysql_list_tables(MYSQL *mysql,const char *wild); +MYSQL_RES * STDCALL mysql_list_processes(MYSQL *mysql); +int STDCALL mysql_options(MYSQL *mysql,enum mysql_option option, + const void *arg); +void STDCALL mysql_free_result(MYSQL_RES *result); +void STDCALL mysql_data_seek(MYSQL_RES *result, + my_ulonglong offset); +MYSQL_ROW_OFFSET STDCALL mysql_row_seek(MYSQL_RES *result, + MYSQL_ROW_OFFSET offset); +MYSQL_FIELD_OFFSET STDCALL mysql_field_seek(MYSQL_RES *result, + MYSQL_FIELD_OFFSET offset); +MYSQL_ROW STDCALL mysql_fetch_row(MYSQL_RES *result); +unsigned long * STDCALL mysql_fetch_lengths(MYSQL_RES *result); +MYSQL_FIELD * STDCALL mysql_fetch_field(MYSQL_RES *result); +MYSQL_RES * STDCALL mysql_list_fields(MYSQL *mysql, const char *table, + const char *wild); +unsigned long STDCALL mysql_escape_string(char *to,const char *from, + unsigned long from_length); +unsigned long STDCALL mysql_hex_string(char *to,const char *from, + unsigned long from_length); +unsigned long STDCALL mysql_real_escape_string(MYSQL *mysql, + char *to,const char *from, + unsigned long length); +void STDCALL mysql_debug(const char *debug); +void STDCALL myodbc_remove_escape(MYSQL *mysql,char *name); +unsigned int STDCALL mysql_thread_safe(void); +my_bool STDCALL mysql_embedded(void); +my_bool STDCALL mysql_read_query_result(MYSQL *mysql); + + +/* + The following definitions are added for the enhanced + client-server protocol +*/ + +/* statement state */ +enum enum_mysql_stmt_state +{ + MYSQL_STMT_INIT_DONE= 1, MYSQL_STMT_PREPARE_DONE, MYSQL_STMT_EXECUTE_DONE, + MYSQL_STMT_FETCH_DONE +}; + + +/* + This structure is used to define bind information, and + internally by the client library. + Public members with their descriptions are listed below + (conventionally `On input' refers to the binds given to + mysql_stmt_bind_param, `On output' refers to the binds given + to mysql_stmt_bind_result): + + buffer_type - One of the MYSQL_* types, used to describe + the host language type of buffer. + On output: if column type is different from + buffer_type, column value is automatically converted + to buffer_type before it is stored in the buffer. + buffer - On input: points to the buffer with input data. + On output: points to the buffer capable to store + output data. + The type of memory pointed by buffer must correspond + to buffer_type. See the correspondence table in + the comment to mysql_stmt_bind_param. + + The two above members are mandatory for any kind of bind. + + buffer_length - the length of the buffer. You don't have to set + it for any fixed length buffer: float, double, + int, etc. It must be set however for variable-length + types, such as BLOBs or STRINGs. + + length - On input: in case when lengths of input values + are different for each execute, you can set this to + point at a variable containining value length. This + way the value length can be different in each execute. + If length is not NULL, buffer_length is not used. + Note, length can even point at buffer_length if + you keep bind structures around while fetching: + this way you can change buffer_length before + each execution, everything will work ok. + On output: if length is set, mysql_stmt_fetch will + write column length into it. + + is_null - On input: points to a boolean variable that should + be set to TRUE for NULL values. + This member is useful only if your data may be + NULL in some but not all cases. + If your data is never NULL, is_null should be set to 0. + If your data is always NULL, set buffer_type + to MYSQL_TYPE_NULL, and is_null will not be used. + + is_unsigned - On input: used to signify that values provided for one + of numeric types are unsigned. + On output describes signedness of the output buffer. + If, taking into account is_unsigned flag, column data + is out of range of the output buffer, data for this column + is regarded truncated. Note that this has no correspondence + to the sign of result set column, if you need to find it out + use mysql_stmt_result_metadata. + error - where to write a truncation error if it is present. + possible error value is: + 0 no truncation + 1 value is out of range or buffer is too small + + Please note that MYSQL_BIND also has internals members. +*/ + +typedef struct st_mysql_bind +{ + unsigned long *length; /* output length pointer */ + my_bool *is_null; /* Pointer to null indicator */ + void *buffer; /* buffer to get/put data */ + /* set this if you want to track data truncations happened during fetch */ + my_bool *error; + unsigned char *row_ptr; /* for the current data position */ + void (*store_param_func)(NET *net, struct st_mysql_bind *param); + void (*fetch_result)(struct st_mysql_bind *, MYSQL_FIELD *, + unsigned char **row); + void (*skip_result)(struct st_mysql_bind *, MYSQL_FIELD *, + unsigned char **row); + /* output buffer length, must be set when fetching str/binary */ + unsigned long buffer_length; + unsigned long offset; /* offset position for char/binary fetch */ + unsigned long length_value; /* Used if length is 0 */ + unsigned int param_number; /* For null count and error messages */ + unsigned int pack_length; /* Internal length for packed data */ + enum enum_field_types buffer_type; /* buffer type */ + my_bool error_value; /* used if error is 0 */ + my_bool is_unsigned; /* set if integer type is unsigned */ + my_bool long_data_used; /* If used with mysql_send_long_data */ + my_bool is_null_value; /* Used if is_null is 0 */ + void *extension; +} MYSQL_BIND; + + +/* statement handler */ +typedef struct st_mysql_stmt +{ + MEM_ROOT mem_root; /* root allocations */ + LIST list; /* list to keep track of all stmts */ + MYSQL *mysql; /* connection handle */ + MYSQL_BIND *params; /* input parameters */ + MYSQL_BIND *bind; /* output parameters */ + MYSQL_FIELD *fields; /* result set metadata */ + MYSQL_DATA result; /* cached result set */ + MYSQL_ROWS *data_cursor; /* current row in cached result */ + /* + mysql_stmt_fetch() calls this function to fetch one row (it's different + for buffered, unbuffered and cursor fetch). + */ + int (*read_row_func)(struct st_mysql_stmt *stmt, + unsigned char **row); + /* copy of mysql->affected_rows after statement execution */ + my_ulonglong affected_rows; + my_ulonglong insert_id; /* copy of mysql->insert_id */ + unsigned long stmt_id; /* Id for prepared statement */ + unsigned long flags; /* i.e. type of cursor to open */ + unsigned long prefetch_rows; /* number of rows per one COM_FETCH */ + /* + Copied from mysql->server_status after execute/fetch to know + server-side cursor status for this statement. + */ + unsigned int server_status; + unsigned int last_errno; /* error code */ + unsigned int param_count; /* input parameter count */ + unsigned int field_count; /* number of columns in result set */ + enum enum_mysql_stmt_state state; /* statement state */ + char last_error[MYSQL_ERRMSG_SIZE]; /* error message */ + char sqlstate[SQLSTATE_LENGTH+1]; + /* Types of input parameters should be sent to server */ + my_bool send_types_to_server; + my_bool bind_param_done; /* input buffers were supplied */ + unsigned char bind_result_done; /* output buffers were supplied */ + /* mysql_stmt_close() had to cancel this result */ + my_bool unbuffered_fetch_cancelled; + /* + Is set to true if we need to calculate field->max_length for + metadata fields when doing mysql_stmt_store_result. + */ + my_bool update_max_length; + void *extension; +} MYSQL_STMT; + +enum enum_stmt_attr_type +{ + /* + When doing mysql_stmt_store_result calculate max_length attribute + of statement metadata. This is to be consistent with the old API, + where this was done automatically. + In the new API we do that only by request because it slows down + mysql_stmt_store_result sufficiently. + */ + STMT_ATTR_UPDATE_MAX_LENGTH, + /* + unsigned long with combination of cursor flags (read only, for update, + etc) + */ + STMT_ATTR_CURSOR_TYPE, + /* + Amount of rows to retrieve from server per one fetch if using cursors. + Accepts unsigned long attribute in the range 1 - ulong_max + */ + STMT_ATTR_PREFETCH_ROWS +}; + + +MYSQL_STMT * STDCALL mysql_stmt_init(MYSQL *mysql); +int STDCALL mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, + unsigned long length); +int STDCALL mysql_stmt_execute(MYSQL_STMT *stmt); +int STDCALL mysql_stmt_fetch(MYSQL_STMT *stmt); +int STDCALL mysql_stmt_fetch_column(MYSQL_STMT *stmt, MYSQL_BIND *bind_arg, + unsigned int column, + unsigned long offset); +int STDCALL mysql_stmt_store_result(MYSQL_STMT *stmt); +unsigned long STDCALL mysql_stmt_param_count(MYSQL_STMT * stmt); +my_bool STDCALL mysql_stmt_attr_set(MYSQL_STMT *stmt, + enum enum_stmt_attr_type attr_type, + const void *attr); +my_bool STDCALL mysql_stmt_attr_get(MYSQL_STMT *stmt, + enum enum_stmt_attr_type attr_type, + void *attr); +my_bool STDCALL mysql_stmt_bind_param(MYSQL_STMT * stmt, MYSQL_BIND * bnd); +my_bool STDCALL mysql_stmt_bind_result(MYSQL_STMT * stmt, MYSQL_BIND * bnd); +my_bool STDCALL mysql_stmt_close(MYSQL_STMT * stmt); +my_bool STDCALL mysql_stmt_reset(MYSQL_STMT * stmt); +my_bool STDCALL mysql_stmt_free_result(MYSQL_STMT *stmt); +my_bool STDCALL mysql_stmt_send_long_data(MYSQL_STMT *stmt, + unsigned int param_number, + const char *data, + unsigned long length); +MYSQL_RES *STDCALL mysql_stmt_result_metadata(MYSQL_STMT *stmt); +MYSQL_RES *STDCALL mysql_stmt_param_metadata(MYSQL_STMT *stmt); +unsigned int STDCALL mysql_stmt_errno(MYSQL_STMT * stmt); +const char *STDCALL mysql_stmt_error(MYSQL_STMT * stmt); +const char *STDCALL mysql_stmt_sqlstate(MYSQL_STMT * stmt); +MYSQL_ROW_OFFSET STDCALL mysql_stmt_row_seek(MYSQL_STMT *stmt, + MYSQL_ROW_OFFSET offset); +MYSQL_ROW_OFFSET STDCALL mysql_stmt_row_tell(MYSQL_STMT *stmt); +void STDCALL mysql_stmt_data_seek(MYSQL_STMT *stmt, my_ulonglong offset); +my_ulonglong STDCALL mysql_stmt_num_rows(MYSQL_STMT *stmt); +my_ulonglong STDCALL mysql_stmt_affected_rows(MYSQL_STMT *stmt); +my_ulonglong STDCALL mysql_stmt_insert_id(MYSQL_STMT *stmt); +unsigned int STDCALL mysql_stmt_field_count(MYSQL_STMT *stmt); + +my_bool STDCALL mysql_commit(MYSQL * mysql); +my_bool STDCALL mysql_rollback(MYSQL * mysql); +my_bool STDCALL mysql_autocommit(MYSQL * mysql, my_bool auto_mode); +my_bool STDCALL mysql_more_results(MYSQL *mysql); +int STDCALL mysql_next_result(MYSQL *mysql); +int STDCALL mysql_stmt_next_result(MYSQL_STMT *stmt); +void STDCALL mysql_close(MYSQL *sock); + + +/* status return codes */ +#define MYSQL_NO_DATA 100 +#define MYSQL_DATA_TRUNCATED 101 + +#define mysql_reload(mysql) mysql_refresh((mysql),REFRESH_GRANT) + +#ifdef USE_OLD_FUNCTIONS +MYSQL * STDCALL mysql_connect(MYSQL *mysql, const char *host, + const char *user, const char *passwd); +int STDCALL mysql_create_db(MYSQL *mysql, const char *DB); +int STDCALL mysql_drop_db(MYSQL *mysql, const char *DB); +#endif +#define HAVE_MYSQL_REAL_CONNECT + +#ifdef __cplusplus +} +#endif + +#endif /* _mysql_h */ diff --git a/include/mysql/mysql_com.h b/include/mysql/mysql_com.h new file mode 100644 index 000000000..bc9296a6d --- /dev/null +++ b/include/mysql/mysql_com.h @@ -0,0 +1,572 @@ +/* Copyright (C) 2000 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/* +** Common definition between mysql server & client +*/ + +#ifndef _mysql_com_h +#define _mysql_com_h + +#define HOSTNAME_LENGTH 60 +#define SYSTEM_CHARSET_MBMAXLEN 3 +#define NAME_CHAR_LEN 64 /* Field/table name length */ +#define USERNAME_CHAR_LENGTH 16 +#define NAME_LEN (NAME_CHAR_LEN*SYSTEM_CHARSET_MBMAXLEN) +#define USERNAME_LENGTH (USERNAME_CHAR_LENGTH*SYSTEM_CHARSET_MBMAXLEN) + +#define MYSQL_AUTODETECT_CHARSET_NAME "auto" + +#define SERVER_VERSION_LENGTH 60 +#define SQLSTATE_LENGTH 5 + +/* + Maximum length of comments +*/ +#define TABLE_COMMENT_INLINE_MAXLEN 180 /* pre 6.0: 60 characters */ +#define TABLE_COMMENT_MAXLEN 2048 +#define COLUMN_COMMENT_MAXLEN 1024 +#define INDEX_COMMENT_MAXLEN 1024 + +/* + USER_HOST_BUFF_SIZE -- length of string buffer, that is enough to contain + username and hostname parts of the user identifier with trailing zero in + MySQL standard format: + user_name_part@host_name_part\0 +*/ +#define USER_HOST_BUFF_SIZE HOSTNAME_LENGTH + USERNAME_LENGTH + 2 + +#define LOCAL_HOST "localhost" +#define LOCAL_HOST_NAMEDPIPE "." + + +#if defined(__WIN__) && !defined( _CUSTOMCONFIG_) +#define MYSQL_NAMEDPIPE "MySQL" +#define MYSQL_SERVICENAME "MySQL" +#endif /* __WIN__ */ + +/* + You should add new commands to the end of this list, otherwise old + servers won't be able to handle them as 'unsupported'. +*/ + +enum enum_server_command +{ + COM_SLEEP, COM_QUIT, COM_INIT_DB, COM_QUERY, COM_FIELD_LIST, + COM_CREATE_DB, COM_DROP_DB, COM_REFRESH, COM_SHUTDOWN, COM_STATISTICS, + COM_PROCESS_INFO, COM_CONNECT, COM_PROCESS_KILL, COM_DEBUG, COM_PING, + COM_TIME, COM_DELAYED_INSERT, COM_CHANGE_USER, COM_BINLOG_DUMP, + COM_TABLE_DUMP, COM_CONNECT_OUT, COM_REGISTER_SLAVE, + COM_STMT_PREPARE, COM_STMT_EXECUTE, COM_STMT_SEND_LONG_DATA, COM_STMT_CLOSE, + COM_STMT_RESET, COM_SET_OPTION, COM_STMT_FETCH, COM_DAEMON, + /* don't forget to update const char *command_name[] in sql_parse.cc */ + + /* Must be last */ + COM_END +}; + + +/* + Length of random string sent by server on handshake; this is also length of + obfuscated password, recieved from client +*/ +#define SCRAMBLE_LENGTH 20 +#define SCRAMBLE_LENGTH_323 8 +/* length of password stored in the db: new passwords are preceeded with '*' */ +#define SCRAMBLED_PASSWORD_CHAR_LENGTH (SCRAMBLE_LENGTH*2+1) +#define SCRAMBLED_PASSWORD_CHAR_LENGTH_323 (SCRAMBLE_LENGTH_323*2) + + +#define NOT_NULL_FLAG 1 /* Field can't be NULL */ +#define PRI_KEY_FLAG 2 /* Field is part of a primary key */ +#define UNIQUE_KEY_FLAG 4 /* Field is part of a unique key */ +#define MULTIPLE_KEY_FLAG 8 /* Field is part of a key */ +#define BLOB_FLAG 16 /* Field is a blob */ +#define UNSIGNED_FLAG 32 /* Field is unsigned */ +#define ZEROFILL_FLAG 64 /* Field is zerofill */ +#define BINARY_FLAG 128 /* Field is binary */ + +/* The following are only sent to new clients */ +#define ENUM_FLAG 256 /* field is an enum */ +#define AUTO_INCREMENT_FLAG 512 /* field is a autoincrement field */ +#define TIMESTAMP_FLAG 1024 /* Field is a timestamp */ +#define SET_FLAG 2048 /* field is a set */ +#define NO_DEFAULT_VALUE_FLAG 4096 /* Field doesn't have default value */ +#define ON_UPDATE_NOW_FLAG 8192 /* Field is set to NOW on UPDATE */ +#define NUM_FLAG 32768 /* Field is num (for clients) */ +#define PART_KEY_FLAG 16384 /* Intern; Part of some key */ +#define GROUP_FLAG 32768 /* Intern: Group field */ +#define UNIQUE_FLAG 65536 /* Intern: Used by sql_yacc */ +#define BINCMP_FLAG 131072 /* Intern: Used by sql_yacc */ +#define GET_FIXED_FIELDS_FLAG (1 << 18) /* Used to get fields in item tree */ +#define FIELD_IN_PART_FUNC_FLAG (1 << 19)/* Field part of partition func */ +#define FIELD_IN_ADD_INDEX (1<< 20) /* Intern: Field used in ADD INDEX */ +#define FIELD_IS_RENAMED (1<< 21) /* Intern: Field is being renamed */ + +#define REFRESH_GRANT 1 /* Refresh grant tables */ +#define REFRESH_LOG 2 /* Start on new log file */ +#define REFRESH_TABLES 4 /* close all tables */ +#define REFRESH_HOSTS 8 /* Flush host cache */ +#define REFRESH_STATUS 16 /* Flush status variables */ +#define REFRESH_THREADS 32 /* Flush thread cache */ +#define REFRESH_SLAVE 64 /* Reset master info and restart slave + thread */ +#define REFRESH_MASTER 128 /* Remove all bin logs in the index + and truncate the index */ +#define REFRESH_ERROR_LOG 256 /* Rotate only the erorr log */ +#define REFRESH_ENGINE_LOG 512 /* Flush all storage engine logs */ +#define REFRESH_BINARY_LOG 1024 /* Flush the binary log */ +#define REFRESH_RELAY_LOG 2048 /* Flush the relay log */ +#define REFRESH_GENERAL_LOG 4096 /* Flush the general log */ +#define REFRESH_SLOW_LOG 8192 /* Flush the slow query log */ + +/* The following can't be set with mysql_refresh() */ +#define REFRESH_READ_LOCK 16384 /* Lock tables for read */ +#define REFRESH_FAST 32768 /* Intern flag */ + +/* RESET (remove all queries) from query cache */ +#define REFRESH_QUERY_CACHE 65536 +#define REFRESH_QUERY_CACHE_FREE 0x20000L /* pack query cache */ +#define REFRESH_DES_KEY_FILE 0x40000L +#define REFRESH_USER_RESOURCES 0x80000L + +#define CLIENT_LONG_PASSWORD 1 /* new more secure passwords */ +#define CLIENT_FOUND_ROWS 2 /* Found instead of affected rows */ +#define CLIENT_LONG_FLAG 4 /* Get all column flags */ +#define CLIENT_CONNECT_WITH_DB 8 /* One can specify db on connect */ +#define CLIENT_NO_SCHEMA 16 /* Don't allow database.table.column */ +#define CLIENT_COMPRESS 32 /* Can use compression protocol */ +#define CLIENT_ODBC 64 /* Odbc client */ +#define CLIENT_LOCAL_FILES 128 /* Can use LOAD DATA LOCAL */ +#define CLIENT_IGNORE_SPACE 256 /* Ignore spaces before '(' */ +#define CLIENT_PROTOCOL_41 512 /* New 4.1 protocol */ +#define CLIENT_INTERACTIVE 1024 /* This is an interactive client */ +#define CLIENT_SSL 2048 /* Switch to SSL after handshake */ +#define CLIENT_IGNORE_SIGPIPE 4096 /* IGNORE sigpipes */ +#define CLIENT_TRANSACTIONS 8192 /* Client knows about transactions */ +#define CLIENT_RESERVED 16384 /* Old flag for 4.1 protocol */ +#define CLIENT_SECURE_CONNECTION 32768 /* New 4.1 authentication */ +#define CLIENT_MULTI_STATEMENTS (1UL << 16) /* Enable/disable multi-stmt support */ +#define CLIENT_MULTI_RESULTS (1UL << 17) /* Enable/disable multi-results */ +#define CLIENT_PS_MULTI_RESULTS (1UL << 18) /* Multi-results in PS-protocol */ + +#define CLIENT_PLUGIN_AUTH (1UL << 19) /* Client supports plugin authentication */ + +#define CLIENT_SSL_VERIFY_SERVER_CERT (1UL << 30) +#define CLIENT_REMEMBER_OPTIONS (1UL << 31) + +#ifdef HAVE_COMPRESS +#define CAN_CLIENT_COMPRESS CLIENT_COMPRESS +#else +#define CAN_CLIENT_COMPRESS 0 +#endif + +/* Gather all possible capabilites (flags) supported by the server */ +#define CLIENT_ALL_FLAGS (CLIENT_LONG_PASSWORD | \ + CLIENT_FOUND_ROWS | \ + CLIENT_LONG_FLAG | \ + CLIENT_CONNECT_WITH_DB | \ + CLIENT_NO_SCHEMA | \ + CLIENT_COMPRESS | \ + CLIENT_ODBC | \ + CLIENT_LOCAL_FILES | \ + CLIENT_IGNORE_SPACE | \ + CLIENT_PROTOCOL_41 | \ + CLIENT_INTERACTIVE | \ + CLIENT_SSL | \ + CLIENT_IGNORE_SIGPIPE | \ + CLIENT_TRANSACTIONS | \ + CLIENT_RESERVED | \ + CLIENT_SECURE_CONNECTION | \ + CLIENT_MULTI_STATEMENTS | \ + CLIENT_MULTI_RESULTS | \ + CLIENT_PS_MULTI_RESULTS | \ + CLIENT_SSL_VERIFY_SERVER_CERT | \ + CLIENT_REMEMBER_OPTIONS | \ + CLIENT_PLUGIN_AUTH) + +/* + Switch off the flags that are optional and depending on build flags + If any of the optional flags is supported by the build it will be switched + on before sending to the client during the connection handshake. +*/ +#define CLIENT_BASIC_FLAGS (((CLIENT_ALL_FLAGS & ~CLIENT_SSL) \ + & ~CLIENT_COMPRESS) \ + & ~CLIENT_SSL_VERIFY_SERVER_CERT) + +/** + Is raised when a multi-statement transaction + has been started, either explicitly, by means + of BEGIN or COMMIT AND CHAIN, or + implicitly, by the first transactional + statement, when autocommit=off. +*/ +#define SERVER_STATUS_IN_TRANS 1 +#define SERVER_STATUS_AUTOCOMMIT 2 /* Server in auto_commit mode */ +#define SERVER_MORE_RESULTS_EXISTS 8 /* Multi query - next query exists */ +#define SERVER_QUERY_NO_GOOD_INDEX_USED 16 +#define SERVER_QUERY_NO_INDEX_USED 32 +/** + The server was able to fulfill the clients request and opened a + read-only non-scrollable cursor for a query. This flag comes + in reply to COM_STMT_EXECUTE and COM_STMT_FETCH commands. +*/ +#define SERVER_STATUS_CURSOR_EXISTS 64 +/** + This flag is sent when a read-only cursor is exhausted, in reply to + COM_STMT_FETCH command. +*/ +#define SERVER_STATUS_LAST_ROW_SENT 128 +#define SERVER_STATUS_DB_DROPPED 256 /* A database was dropped */ +#define SERVER_STATUS_NO_BACKSLASH_ESCAPES 512 +/** + Sent to the client if after a prepared statement reprepare + we discovered that the new statement returns a different + number of result set columns. +*/ +#define SERVER_STATUS_METADATA_CHANGED 1024 +#define SERVER_QUERY_WAS_SLOW 2048 + +/** + To mark ResultSet containing output parameter values. +*/ +#define SERVER_PS_OUT_PARAMS 4096 + +/** + Server status flags that must be cleared when starting + execution of a new SQL statement. + Flags from this set are only added to the + current server status by the execution engine, but + never removed -- the execution engine expects them + to disappear automagically by the next command. +*/ +#define SERVER_STATUS_CLEAR_SET (SERVER_QUERY_NO_GOOD_INDEX_USED| \ + SERVER_QUERY_NO_INDEX_USED|\ + SERVER_MORE_RESULTS_EXISTS|\ + SERVER_STATUS_METADATA_CHANGED |\ + SERVER_QUERY_WAS_SLOW |\ + SERVER_STATUS_DB_DROPPED |\ + SERVER_STATUS_CURSOR_EXISTS|\ + SERVER_STATUS_LAST_ROW_SENT) + +#define MYSQL_ERRMSG_SIZE 512 +#define NET_READ_TIMEOUT 30 /* Timeout on read */ +#define NET_WRITE_TIMEOUT 60 /* Timeout on write */ +#define NET_WAIT_TIMEOUT 8*60*60 /* Wait for new query */ + +#define ONLY_KILL_QUERY 1 + + +struct st_vio; /* Only C */ +typedef struct st_vio Vio; + +#define MAX_TINYINT_WIDTH 3 /* Max width for a TINY w.o. sign */ +#define MAX_SMALLINT_WIDTH 5 /* Max width for a SHORT w.o. sign */ +#define MAX_MEDIUMINT_WIDTH 8 /* Max width for a INT24 w.o. sign */ +#define MAX_INT_WIDTH 10 /* Max width for a LONG w.o. sign */ +#define MAX_BIGINT_WIDTH 20 /* Max width for a LONGLONG */ +#define MAX_CHAR_WIDTH 255 /* Max length for a CHAR colum */ +#define MAX_BLOB_WIDTH 16777216 /* Default width for blob */ + +typedef struct st_net { +#if !defined(CHECK_EMBEDDED_DIFFERENCES) || !defined(EMBEDDED_LIBRARY) + Vio *vio; + unsigned char *buff,*buff_end,*write_pos,*read_pos; + my_socket fd; /* For Perl DBI/dbd */ + /* + The following variable is set if we are doing several queries in one + command ( as in LOAD TABLE ... FROM MASTER ), + and do not want to confuse the client with OK at the wrong time + */ + unsigned long remain_in_buf,length, buf_length, where_b; + unsigned long max_packet,max_packet_size; + unsigned int pkt_nr,compress_pkt_nr; + unsigned int write_timeout, read_timeout, retry_count; + int fcntl; + unsigned int *return_status; + unsigned char reading_or_writing; + char save_char; + my_bool unused1; /* Please remove with the next incompatible ABI change. */ + my_bool unused2; /* Please remove with the next incompatible ABI change */ + my_bool compress; + my_bool unused3; /* Please remove with the next incompatible ABI change. */ + /* + Pointer to query object in query cache, do not equal NULL (0) for + queries in cache that have not stored its results yet + */ +#endif + /* + Unused, please remove with the next incompatible ABI change. + */ + unsigned char *unused; + unsigned int last_errno; + unsigned char error; + my_bool unused4; /* Please remove with the next incompatible ABI change. */ + my_bool unused5; /* Please remove with the next incompatible ABI change. */ + /** Client library error message buffer. Actually belongs to struct MYSQL. */ + char last_error[MYSQL_ERRMSG_SIZE]; + /** Client library sqlstate buffer. Set along with the error message. */ + char sqlstate[SQLSTATE_LENGTH+1]; + void *extension; +#if defined(MYSQL_SERVER) && !defined(EMBEDDED_LIBRARY) + /* + Controls whether a big packet should be skipped. + + Initially set to FALSE by default. Unauthenticated sessions must have + this set to FALSE so that the server can't be tricked to read packets + indefinitely. + */ + my_bool skip_big_packet; +#endif +} NET; + + +#define packet_error (~(unsigned long) 0) + +enum enum_field_types { MYSQL_TYPE_DECIMAL, MYSQL_TYPE_TINY, + MYSQL_TYPE_SHORT, MYSQL_TYPE_LONG, + MYSQL_TYPE_FLOAT, MYSQL_TYPE_DOUBLE, + MYSQL_TYPE_NULL, MYSQL_TYPE_TIMESTAMP, + MYSQL_TYPE_LONGLONG,MYSQL_TYPE_INT24, + MYSQL_TYPE_DATE, MYSQL_TYPE_TIME, + MYSQL_TYPE_DATETIME, MYSQL_TYPE_YEAR, + MYSQL_TYPE_NEWDATE, MYSQL_TYPE_VARCHAR, + MYSQL_TYPE_BIT, + MYSQL_TYPE_NEWDECIMAL=246, + MYSQL_TYPE_ENUM=247, + MYSQL_TYPE_SET=248, + MYSQL_TYPE_TINY_BLOB=249, + MYSQL_TYPE_MEDIUM_BLOB=250, + MYSQL_TYPE_LONG_BLOB=251, + MYSQL_TYPE_BLOB=252, + MYSQL_TYPE_VAR_STRING=253, + MYSQL_TYPE_STRING=254, + MYSQL_TYPE_GEOMETRY=255 + +}; + +/* For backward compatibility */ +#define CLIENT_MULTI_QUERIES CLIENT_MULTI_STATEMENTS +#define FIELD_TYPE_DECIMAL MYSQL_TYPE_DECIMAL +#define FIELD_TYPE_NEWDECIMAL MYSQL_TYPE_NEWDECIMAL +#define FIELD_TYPE_TINY MYSQL_TYPE_TINY +#define FIELD_TYPE_SHORT MYSQL_TYPE_SHORT +#define FIELD_TYPE_LONG MYSQL_TYPE_LONG +#define FIELD_TYPE_FLOAT MYSQL_TYPE_FLOAT +#define FIELD_TYPE_DOUBLE MYSQL_TYPE_DOUBLE +#define FIELD_TYPE_NULL MYSQL_TYPE_NULL +#define FIELD_TYPE_TIMESTAMP MYSQL_TYPE_TIMESTAMP +#define FIELD_TYPE_LONGLONG MYSQL_TYPE_LONGLONG +#define FIELD_TYPE_INT24 MYSQL_TYPE_INT24 +#define FIELD_TYPE_DATE MYSQL_TYPE_DATE +#define FIELD_TYPE_TIME MYSQL_TYPE_TIME +#define FIELD_TYPE_DATETIME MYSQL_TYPE_DATETIME +#define FIELD_TYPE_YEAR MYSQL_TYPE_YEAR +#define FIELD_TYPE_NEWDATE MYSQL_TYPE_NEWDATE +#define FIELD_TYPE_ENUM MYSQL_TYPE_ENUM +#define FIELD_TYPE_SET MYSQL_TYPE_SET +#define FIELD_TYPE_TINY_BLOB MYSQL_TYPE_TINY_BLOB +#define FIELD_TYPE_MEDIUM_BLOB MYSQL_TYPE_MEDIUM_BLOB +#define FIELD_TYPE_LONG_BLOB MYSQL_TYPE_LONG_BLOB +#define FIELD_TYPE_BLOB MYSQL_TYPE_BLOB +#define FIELD_TYPE_VAR_STRING MYSQL_TYPE_VAR_STRING +#define FIELD_TYPE_STRING MYSQL_TYPE_STRING +#define FIELD_TYPE_CHAR MYSQL_TYPE_TINY +#define FIELD_TYPE_INTERVAL MYSQL_TYPE_ENUM +#define FIELD_TYPE_GEOMETRY MYSQL_TYPE_GEOMETRY +#define FIELD_TYPE_BIT MYSQL_TYPE_BIT + + +/* Shutdown/kill enums and constants */ + +/* Bits for THD::killable. */ +#define MYSQL_SHUTDOWN_KILLABLE_CONNECT (unsigned char)(1 << 0) +#define MYSQL_SHUTDOWN_KILLABLE_TRANS (unsigned char)(1 << 1) +#define MYSQL_SHUTDOWN_KILLABLE_LOCK_TABLE (unsigned char)(1 << 2) +#define MYSQL_SHUTDOWN_KILLABLE_UPDATE (unsigned char)(1 << 3) + +enum mysql_enum_shutdown_level { + /* + We want levels to be in growing order of hardness (because we use number + comparisons). Note that DEFAULT does not respect the growing property, but + it's ok. + */ + SHUTDOWN_DEFAULT = 0, + /* wait for existing connections to finish */ + SHUTDOWN_WAIT_CONNECTIONS= MYSQL_SHUTDOWN_KILLABLE_CONNECT, + /* wait for existing trans to finish */ + SHUTDOWN_WAIT_TRANSACTIONS= MYSQL_SHUTDOWN_KILLABLE_TRANS, + /* wait for existing updates to finish (=> no partial MyISAM update) */ + SHUTDOWN_WAIT_UPDATES= MYSQL_SHUTDOWN_KILLABLE_UPDATE, + /* flush InnoDB buffers and other storage engines' buffers*/ + SHUTDOWN_WAIT_ALL_BUFFERS= (MYSQL_SHUTDOWN_KILLABLE_UPDATE << 1), + /* don't flush InnoDB buffers, flush other storage engines' buffers*/ + SHUTDOWN_WAIT_CRITICAL_BUFFERS= (MYSQL_SHUTDOWN_KILLABLE_UPDATE << 1) + 1, + /* Now the 2 levels of the KILL command */ +#if MYSQL_VERSION_ID >= 50000 + KILL_QUERY= 254, +#endif + KILL_CONNECTION= 255 +}; + + +enum enum_cursor_type +{ + CURSOR_TYPE_NO_CURSOR= 0, + CURSOR_TYPE_READ_ONLY= 1, + CURSOR_TYPE_FOR_UPDATE= 2, + CURSOR_TYPE_SCROLLABLE= 4 +}; + + +/* options for mysql_set_option */ +enum enum_mysql_set_option +{ + MYSQL_OPTION_MULTI_STATEMENTS_ON, + MYSQL_OPTION_MULTI_STATEMENTS_OFF +}; + +#define net_new_transaction(net) ((net)->pkt_nr=0) + +#ifdef __cplusplus +extern "C" { +#endif + +my_bool my_net_init(NET *net, Vio* vio); +void my_net_local_init(NET *net); +void net_end(NET *net); + void net_clear(NET *net, my_bool clear_buffer); +my_bool net_realloc(NET *net, size_t length); +my_bool net_flush(NET *net); +my_bool my_net_write(NET *net,const unsigned char *packet, size_t len); +my_bool net_write_command(NET *net,unsigned char command, + const unsigned char *header, size_t head_len, + const unsigned char *packet, size_t len); +int net_real_write(NET *net,const unsigned char *packet, size_t len); +unsigned long my_net_read(NET *net); + +#ifdef _global_h +void my_net_set_write_timeout(NET *net, uint timeout); +void my_net_set_read_timeout(NET *net, uint timeout); +#endif + +struct sockaddr; +int my_connect(my_socket s, const struct sockaddr *name, unsigned int namelen, + unsigned int timeout); + +struct rand_struct { + unsigned long seed1,seed2,max_value; + double max_value_dbl; +}; + +#ifdef __cplusplus +} +#endif + + /* The following is for user defined functions */ + +enum Item_result {STRING_RESULT=0, REAL_RESULT, INT_RESULT, ROW_RESULT, + DECIMAL_RESULT}; + +typedef struct st_udf_args +{ + unsigned int arg_count; /* Number of arguments */ + enum Item_result *arg_type; /* Pointer to item_results */ + char **args; /* Pointer to argument */ + unsigned long *lengths; /* Length of string arguments */ + char *maybe_null; /* Set to 1 for all maybe_null args */ + char **attributes; /* Pointer to attribute name */ + unsigned long *attribute_lengths; /* Length of attribute arguments */ + void *extension; +} UDF_ARGS; + + /* This holds information about the result */ + +typedef struct st_udf_init +{ + my_bool maybe_null; /* 1 if function can return NULL */ + unsigned int decimals; /* for real functions */ + unsigned long max_length; /* For string functions */ + char *ptr; /* free pointer for function data */ + my_bool const_item; /* 1 if function always returns the same value */ + void *extension; +} UDF_INIT; +/* + TODO: add a notion for determinism of the UDF. + See Item_udf_func::update_used_tables () +*/ + + /* Constants when using compression */ +#define NET_HEADER_SIZE 4 /* standard header size */ +#define COMP_HEADER_SIZE 3 /* compression header extra size */ + + /* Prototypes to password functions */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + These functions are used for authentication by client and server and + implemented in sql/password.c +*/ + +void randominit(struct rand_struct *, unsigned long seed1, + unsigned long seed2); +double my_rnd(struct rand_struct *); +void create_random_string(char *to, unsigned int length, struct rand_struct *rand_st); + +void hash_password(unsigned long *to, const char *password, unsigned int password_len); +void make_scrambled_password_323(char *to, const char *password); +void scramble_323(char *to, const char *message, const char *password); +my_bool check_scramble_323(const unsigned char *reply, const char *message, + unsigned long *salt); +void get_salt_from_password_323(unsigned long *res, const char *password); +void make_password_from_salt_323(char *to, const unsigned long *salt); + +void make_scrambled_password(char *to, const char *password); +void scramble(char *to, const char *message, const char *password); +my_bool check_scramble(const unsigned char *reply, const char *message, + const unsigned char *hash_stage2); +void get_salt_from_password(unsigned char *res, const char *password); +void make_password_from_salt(char *to, const unsigned char *hash_stage2); +char *octet2hex(char *to, const char *str, unsigned int len); + +/* end of password.c */ + +char *get_tty_password(const char *opt_message); +const char *mysql_errno_to_sqlstate(unsigned int mysql_errno); + +/* Some other useful functions */ + +my_bool my_thread_init(void); +void my_thread_end(void); + +#ifdef _global_h +ulong STDCALL net_field_length(uchar **packet); +my_ulonglong net_field_length_ll(uchar **packet); +uchar *net_store_length(uchar *pkg, ulonglong length); +#endif + +#ifdef __cplusplus +} +#endif + +#define NULL_LENGTH ((unsigned long) ~0) /* For net_store_length */ +#define MYSQL_STMT_HEADER 4 +#define MYSQL_LONG_DATA_HEADER 6 + +#define NOT_FIXED_DEC 31 +#endif diff --git a/include/mysql/mysql_embed.h b/include/mysql/mysql_embed.h new file mode 100644 index 000000000..e860a4486 --- /dev/null +++ b/include/mysql/mysql_embed.h @@ -0,0 +1,31 @@ +#ifndef MYSQL_EMBED_INCLUDED +#define MYSQL_EMBED_INCLUDED + +/* Copyright (C) 2000 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/* Defines that are unique to the embedded version of MySQL */ + +#ifdef EMBEDDED_LIBRARY + +/* Things we don't need in the embedded version of MySQL */ +/* TODO HF add #undef HAVE_VIO if we don't want client in embedded library */ + +#undef HAVE_DLOPEN /* No udf functions */ +#undef HAVE_SMEM /* No shared memory */ +#undef HAVE_NDBCLUSTER_DB /* No NDB cluster */ + +#endif /* EMBEDDED_LIBRARY */ +#endif /* MYSQL_EMBED_INCLUDED */ diff --git a/include/mysql/mysql_time.h b/include/mysql/mysql_time.h new file mode 100644 index 000000000..0a3f17a81 --- /dev/null +++ b/include/mysql/mysql_time.h @@ -0,0 +1,55 @@ +/* Copyright (C) 2004 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifndef _mysql_time_h_ +#define _mysql_time_h_ + +/* + Time declarations shared between the server and client API: + you should not add anything to this header unless it's used + (and hence should be visible) in mysql.h. + If you're looking for a place to add new time-related declaration, + it's most likely my_time.h. See also "C API Handling of Date + and Time Values" chapter in documentation. +*/ + +enum enum_mysql_timestamp_type +{ + MYSQL_TIMESTAMP_NONE= -2, MYSQL_TIMESTAMP_ERROR= -1, + MYSQL_TIMESTAMP_DATE= 0, MYSQL_TIMESTAMP_DATETIME= 1, MYSQL_TIMESTAMP_TIME= 2 +}; + + +/* + Structure which is used to represent datetime values inside MySQL. + + We assume that values in this structure are normalized, i.e. year <= 9999, + month <= 12, day <= 31, hour <= 23, hour <= 59, hour <= 59. Many functions + in server such as my_system_gmt_sec() or make_time() family of functions + rely on this (actually now usage of make_*() family relies on a bit weaker + restriction). Also functions that produce MYSQL_TIME as result ensure this. + There is one exception to this rule though if this structure holds time + value (time_type == MYSQL_TIMESTAMP_TIME) days and hour member can hold + bigger values. +*/ +typedef struct st_mysql_time +{ + unsigned int year, month, day, hour, minute, second; + unsigned long second_part; + my_bool neg; + enum enum_mysql_timestamp_type time_type; +} MYSQL_TIME; + +#endif /* _mysql_time_h_ */ diff --git a/include/mysql/mysql_version.h b/include/mysql/mysql_version.h new file mode 100644 index 000000000..5490e9b9f --- /dev/null +++ b/include/mysql/mysql_version.h @@ -0,0 +1,30 @@ +/* Copyright Abandoned 1996, 1999, 2001 MySQL AB + This file is public domain and comes with NO WARRANTY of any kind */ + +/* Version numbers for protocol & mysqld */ + +#ifndef _mysql_version_h +#define _mysql_version_h +#ifdef _CUSTOMCONFIG_ +#include +#else +#define PROTOCOL_VERSION 10 +#define MYSQL_SERVER_VERSION "5.5.8" +#define MYSQL_BASE_VERSION "mysqld-5.5" +#define MYSQL_SERVER_SUFFIX_DEF "" +#define FRM_VER 6 +#define MYSQL_VERSION_ID 50508 +#define MYSQL_PORT 3306 +#define MYSQL_PORT_DEFAULT 0 +#define MYSQL_UNIX_ADDR "/tmp/mysql.sock" +#define MYSQL_CONFIG_NAME "my" +#define MYSQL_COMPILATION_COMMENT "Source distribution" + +/* mysqld compile time options */ +#endif /* _CUSTOMCONFIG_ */ + +#ifndef LICENSE +#define LICENSE GPL +#endif /* LICENSE */ + +#endif /* _mysql_version_h */ diff --git a/include/mysql/mysqld_ername.h b/include/mysql/mysqld_ername.h new file mode 100644 index 000000000..581c09916 --- /dev/null +++ b/include/mysql/mysqld_ername.h @@ -0,0 +1,707 @@ +/* Autogenerated file, please don't edit */ + +{ "ER_HASHCHK", 1000, "hashchk" }, +{ "ER_NISAMCHK", 1001, "isamchk" }, +{ "ER_NO", 1002, "NO" }, +{ "ER_YES", 1003, "YES" }, +{ "ER_CANT_CREATE_FILE", 1004, "Can\'t create file \'%-.200s\' (errno: %d)" }, +{ "ER_CANT_CREATE_TABLE", 1005, "Can\'t create table \'%-.200s\' (errno: %d)" }, +{ "ER_CANT_CREATE_DB", 1006, "Can\'t create database \'%-.192s\' (errno: %d)" }, +{ "ER_DB_CREATE_EXISTS", 1007, "Can\'t create database \'%-.192s\'; database exists" }, +{ "ER_DB_DROP_EXISTS", 1008, "Can\'t drop database \'%-.192s\'; database doesn\'t exist" }, +{ "ER_DB_DROP_DELETE", 1009, "Error dropping database (can\'t delete \'%-.192s\', errno: %d)" }, +{ "ER_DB_DROP_RMDIR", 1010, "Error dropping database (can\'t rmdir \'%-.192s\', errno: %d)" }, +{ "ER_CANT_DELETE_FILE", 1011, "Error on delete of \'%-.192s\' (errno: %d)" }, +{ "ER_CANT_FIND_SYSTEM_REC", 1012, "Can\'t read record in system table" }, +{ "ER_CANT_GET_STAT", 1013, "Can\'t get status of \'%-.200s\' (errno: %d)" }, +{ "ER_CANT_GET_WD", 1014, "Can\'t get working directory (errno: %d)" }, +{ "ER_CANT_LOCK", 1015, "Can\'t lock file (errno: %d)" }, +{ "ER_CANT_OPEN_FILE", 1016, "Can\'t open file: \'%-.200s\' (errno: %d)" }, +{ "ER_FILE_NOT_FOUND", 1017, "Can\'t find file: \'%-.200s\' (errno: %d)" }, +{ "ER_CANT_READ_DIR", 1018, "Can\'t read dir of \'%-.192s\' (errno: %d)" }, +{ "ER_CANT_SET_WD", 1019, "Can\'t change dir to \'%-.192s\' (errno: %d)" }, +{ "ER_CHECKREAD", 1020, "Record has changed since last read in table \'%-.192s\'" }, +{ "ER_DISK_FULL", 1021, "Disk full (%s); waiting for someone to free some space..." }, +{ "ER_DUP_KEY", 1022, "Can\'t write; duplicate key in table \'%-.192s\'" }, +{ "ER_ERROR_ON_CLOSE", 1023, "Error on close of \'%-.192s\' (errno: %d)" }, +{ "ER_ERROR_ON_READ", 1024, "Error reading file \'%-.200s\' (errno: %d)" }, +{ "ER_ERROR_ON_RENAME", 1025, "Error on rename of \'%-.210s\' to \'%-.210s\' (errno: %d)" }, +{ "ER_ERROR_ON_WRITE", 1026, "Error writing file \'%-.200s\' (errno: %d)" }, +{ "ER_FILE_USED", 1027, "\'%-.192s\' is locked against change" }, +{ "ER_FILSORT_ABORT", 1028, "Sort aborted" }, +{ "ER_FORM_NOT_FOUND", 1029, "View \'%-.192s\' doesn\'t exist for \'%-.192s\'" }, +{ "ER_GET_ERRNO", 1030, "Got error %d from storage engine" }, +{ "ER_ILLEGAL_HA", 1031, "Table storage engine for \'%-.192s\' doesn\'t have this option" }, +{ "ER_KEY_NOT_FOUND", 1032, "Can\'t find record in \'%-.192s\'" }, +{ "ER_NOT_FORM_FILE", 1033, "Incorrect information in file: \'%-.200s\'" }, +{ "ER_NOT_KEYFILE", 1034, "Incorrect key file for table \'%-.200s\'; try to repair it" }, +{ "ER_OLD_KEYFILE", 1035, "Old key file for table \'%-.192s\'; repair it!" }, +{ "ER_OPEN_AS_READONLY", 1036, "Table \'%-.192s\' is read only" }, +{ "ER_OUTOFMEMORY", 1037, "Out of memory; restart server and try again (needed %d bytes)" }, +{ "ER_OUT_OF_SORTMEMORY", 1038, "Out of sort memory; increase server sort buffer size" }, +{ "ER_UNEXPECTED_EOF", 1039, "Unexpected EOF found when reading file \'%-.192s\' (errno: %d)" }, +{ "ER_CON_COUNT_ERROR", 1040, "Too many connections" }, +{ "ER_OUT_OF_RESOURCES", 1041, "Out of memory; check if mysqld or some other process uses all available memory; if not, you may have to use \'ulimit\' to allow mysqld to use more memory or you can add more swap space" }, +{ "ER_BAD_HOST_ERROR", 1042, "Can\'t get hostname for your address" }, +{ "ER_HANDSHAKE_ERROR", 1043, "Bad handshake" }, +{ "ER_DBACCESS_DENIED_ERROR", 1044, "Access denied for user \'%-.48s\'@\'%-.64s\' to database \'%-.192s\'" }, +{ "ER_ACCESS_DENIED_ERROR", 1045, "Access denied for user \'%-.48s\'@\'%-.64s\' (using password: %s)" }, +{ "ER_NO_DB_ERROR", 1046, "No database selected" }, +{ "ER_UNKNOWN_COM_ERROR", 1047, "Unknown command" }, +{ "ER_BAD_NULL_ERROR", 1048, "Column \'%-.192s\' cannot be null" }, +{ "ER_BAD_DB_ERROR", 1049, "Unknown database \'%-.192s\'" }, +{ "ER_TABLE_EXISTS_ERROR", 1050, "Table \'%-.192s\' already exists" }, +{ "ER_BAD_TABLE_ERROR", 1051, "Unknown table \'%-.100s\'" }, +{ "ER_NON_UNIQ_ERROR", 1052, "Column \'%-.192s\' in %-.192s is ambiguous" }, +{ "ER_SERVER_SHUTDOWN", 1053, "Server shutdown in progress" }, +{ "ER_BAD_FIELD_ERROR", 1054, "Unknown column \'%-.192s\' in \'%-.192s\'" }, +{ "ER_WRONG_FIELD_WITH_GROUP", 1055, "\'%-.192s\' isn\'t in GROUP BY" }, +{ "ER_WRONG_GROUP_FIELD", 1056, "Can\'t group on \'%-.192s\'" }, +{ "ER_WRONG_SUM_SELECT", 1057, "Statement has sum functions and columns in same statement" }, +{ "ER_WRONG_VALUE_COUNT", 1058, "Column count doesn\'t match value count" }, +{ "ER_TOO_LONG_IDENT", 1059, "Identifier name \'%-.100s\' is too long" }, +{ "ER_DUP_FIELDNAME", 1060, "Duplicate column name \'%-.192s\'" }, +{ "ER_DUP_KEYNAME", 1061, "Duplicate key name \'%-.192s\'" }, +{ "ER_DUP_ENTRY", 1062, "Duplicate entry \'%-.192s\' for key %d" }, +{ "ER_WRONG_FIELD_SPEC", 1063, "Incorrect column specifier for column \'%-.192s\'" }, +{ "ER_PARSE_ERROR", 1064, "%s near \'%-.80s\' at line %d" }, +{ "ER_EMPTY_QUERY", 1065, "Query was empty" }, +{ "ER_NONUNIQ_TABLE", 1066, "Not unique table/alias: \'%-.192s\'" }, +{ "ER_INVALID_DEFAULT", 1067, "Invalid default value for \'%-.192s\'" }, +{ "ER_MULTIPLE_PRI_KEY", 1068, "Multiple primary key defined" }, +{ "ER_TOO_MANY_KEYS", 1069, "Too many keys specified; max %d keys allowed" }, +{ "ER_TOO_MANY_KEY_PARTS", 1070, "Too many key parts specified; max %d parts allowed" }, +{ "ER_TOO_LONG_KEY", 1071, "Specified key was too long; max key length is %d bytes" }, +{ "ER_KEY_COLUMN_DOES_NOT_EXITS", 1072, "Key column \'%-.192s\' doesn\'t exist in table" }, +{ "ER_BLOB_USED_AS_KEY", 1073, "BLOB column \'%-.192s\' can\'t be used in key specification with the used table type" }, +{ "ER_TOO_BIG_FIELDLENGTH", 1074, "Column length too big for column \'%-.192s\' (max = %lu); use BLOB or TEXT instead" }, +{ "ER_WRONG_AUTO_KEY", 1075, "Incorrect table definition; there can be only one auto column and it must be defined as a key" }, +{ "ER_READY", 1076, "%s: ready for connections.\nVersion: \'%s\' socket: \'%s\' port: %d" }, +{ "ER_NORMAL_SHUTDOWN", 1077, "%s: Normal shutdown\n" }, +{ "ER_GOT_SIGNAL", 1078, "%s: Got signal %d. Aborting!\n" }, +{ "ER_SHUTDOWN_COMPLETE", 1079, "%s: Shutdown complete\n" }, +{ "ER_FORCING_CLOSE", 1080, "%s: Forcing close of thread %ld user: \'%-.48s\'\n" }, +{ "ER_IPSOCK_ERROR", 1081, "Can\'t create IP socket" }, +{ "ER_NO_SUCH_INDEX", 1082, "Table \'%-.192s\' has no index like the one used in CREATE INDEX; recreate the table" }, +{ "ER_WRONG_FIELD_TERMINATORS", 1083, "Field separator argument is not what is expected; check the manual" }, +{ "ER_BLOBS_AND_NO_TERMINATED", 1084, "You can\'t use fixed rowlength with BLOBs; please use \'fields terminated by\'" }, +{ "ER_TEXTFILE_NOT_READABLE", 1085, "The file \'%-.128s\' must be in the database directory or be readable by all" }, +{ "ER_FILE_EXISTS_ERROR", 1086, "File \'%-.200s\' already exists" }, +{ "ER_LOAD_INFO", 1087, "Records: %ld Deleted: %ld Skipped: %ld Warnings: %ld" }, +{ "ER_ALTER_INFO", 1088, "Records: %ld Duplicates: %ld" }, +{ "ER_WRONG_SUB_KEY", 1089, "Incorrect prefix key; the used key part isn\'t a string, the used length is longer than the key part, or the storage engine doesn\'t support unique prefix keys" }, +{ "ER_CANT_REMOVE_ALL_FIELDS", 1090, "You can\'t delete all columns with ALTER TABLE; use DROP TABLE instead" }, +{ "ER_CANT_DROP_FIELD_OR_KEY", 1091, "Can\'t DROP \'%-.192s\'; check that column/key exists" }, +{ "ER_INSERT_INFO", 1092, "Records: %ld Duplicates: %ld Warnings: %ld" }, +{ "ER_UPDATE_TABLE_USED", 1093, "You can\'t specify target table \'%-.192s\' for update in FROM clause" }, +{ "ER_NO_SUCH_THREAD", 1094, "Unknown thread id: %lu" }, +{ "ER_KILL_DENIED_ERROR", 1095, "You are not owner of thread %lu" }, +{ "ER_NO_TABLES_USED", 1096, "No tables used" }, +{ "ER_TOO_BIG_SET", 1097, "Too many strings for column %-.192s and SET" }, +{ "ER_NO_UNIQUE_LOGFILE", 1098, "Can\'t generate a unique log-filename %-.200s.(1-999)\n" }, +{ "ER_TABLE_NOT_LOCKED_FOR_WRITE", 1099, "Table \'%-.192s\' was locked with a READ lock and can\'t be updated" }, +{ "ER_TABLE_NOT_LOCKED", 1100, "Table \'%-.192s\' was not locked with LOCK TABLES" }, +{ "ER_BLOB_CANT_HAVE_DEFAULT", 1101, "BLOB/TEXT column \'%-.192s\' can\'t have a default value" }, +{ "ER_WRONG_DB_NAME", 1102, "Incorrect database name \'%-.100s\'" }, +{ "ER_WRONG_TABLE_NAME", 1103, "Incorrect table name \'%-.100s\'" }, +{ "ER_TOO_BIG_SELECT", 1104, "The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is okay" }, +{ "ER_UNKNOWN_ERROR", 1105, "Unknown error" }, +{ "ER_UNKNOWN_PROCEDURE", 1106, "Unknown procedure \'%-.192s\'" }, +{ "ER_WRONG_PARAMCOUNT_TO_PROCEDURE", 1107, "Incorrect parameter count to procedure \'%-.192s\'" }, +{ "ER_WRONG_PARAMETERS_TO_PROCEDURE", 1108, "Incorrect parameters to procedure \'%-.192s\'" }, +{ "ER_UNKNOWN_TABLE", 1109, "Unknown table \'%-.192s\' in %-.32s" }, +{ "ER_FIELD_SPECIFIED_TWICE", 1110, "Column \'%-.192s\' specified twice" }, +{ "ER_INVALID_GROUP_FUNC_USE", 1111, "Invalid use of group function" }, +{ "ER_UNSUPPORTED_EXTENSION", 1112, "Table \'%-.192s\' uses an extension that doesn\'t exist in this MySQL version" }, +{ "ER_TABLE_MUST_HAVE_COLUMNS", 1113, "A table must have at least 1 column" }, +{ "ER_RECORD_FILE_FULL", 1114, "The table \'%-.192s\' is full" }, +{ "ER_UNKNOWN_CHARACTER_SET", 1115, "Unknown character set: \'%-.64s\'" }, +{ "ER_TOO_MANY_TABLES", 1116, "Too many tables; MySQL can only use %d tables in a join" }, +{ "ER_TOO_MANY_FIELDS", 1117, "Too many columns" }, +{ "ER_TOO_BIG_ROWSIZE", 1118, "Row size too large. The maximum row size for the used table type, not counting BLOBs, is %ld. You have to change some columns to TEXT or BLOBs" }, +{ "ER_STACK_OVERRUN", 1119, "Thread stack overrun: Used: %ld of a %ld stack. Use \'mysqld --thread_stack=#\' to specify a bigger stack if needed" }, +{ "ER_WRONG_OUTER_JOIN", 1120, "Cross dependency found in OUTER JOIN; examine your ON conditions" }, +{ "ER_NULL_COLUMN_IN_INDEX", 1121, "Table handler doesn\'t support NULL in given index. Please change column \'%-.192s\' to be NOT NULL or use another handler" }, +{ "ER_CANT_FIND_UDF", 1122, "Can\'t load function \'%-.192s\'" }, +{ "ER_CANT_INITIALIZE_UDF", 1123, "Can\'t initialize function \'%-.192s\'; %-.80s" }, +{ "ER_UDF_NO_PATHS", 1124, "No paths allowed for shared library" }, +{ "ER_UDF_EXISTS", 1125, "Function \'%-.192s\' already exists" }, +{ "ER_CANT_OPEN_LIBRARY", 1126, "Can\'t open shared library \'%-.192s\' (errno: %d %-.128s)" }, +{ "ER_CANT_FIND_DL_ENTRY", 1127, "Can\'t find symbol \'%-.128s\' in library" }, +{ "ER_FUNCTION_NOT_DEFINED", 1128, "Function \'%-.192s\' is not defined" }, +{ "ER_HOST_IS_BLOCKED", 1129, "Host \'%-.64s\' is blocked because of many connection errors; unblock with \'mysqladmin flush-hosts\'" }, +{ "ER_HOST_NOT_PRIVILEGED", 1130, "Host \'%-.64s\' is not allowed to connect to this MySQL server" }, +{ "ER_PASSWORD_ANONYMOUS_USER", 1131, "You are using MySQL as an anonymous user and anonymous users are not allowed to change passwords" }, +{ "ER_PASSWORD_NOT_ALLOWED", 1132, "You must have privileges to update tables in the mysql database to be able to change passwords for others" }, +{ "ER_PASSWORD_NO_MATCH", 1133, "Can\'t find any matching row in the user table" }, +{ "ER_UPDATE_INFO", 1134, "Rows matched: %ld Changed: %ld Warnings: %ld" }, +{ "ER_CANT_CREATE_THREAD", 1135, "Can\'t create a new thread (errno %d); if you are not out of available memory, you can consult the manual for a possible OS-dependent bug" }, +{ "ER_WRONG_VALUE_COUNT_ON_ROW", 1136, "Column count doesn\'t match value count at row %ld" }, +{ "ER_CANT_REOPEN_TABLE", 1137, "Can\'t reopen table: \'%-.192s\'" }, +{ "ER_INVALID_USE_OF_NULL", 1138, "Invalid use of NULL value" }, +{ "ER_REGEXP_ERROR", 1139, "Got error \'%-.64s\' from regexp" }, +{ "ER_MIX_OF_GROUP_FUNC_AND_FIELDS", 1140, "Mixing of GROUP columns (MIN(),MAX(),COUNT(),...) with no GROUP columns is illegal if there is no GROUP BY clause" }, +{ "ER_NONEXISTING_GRANT", 1141, "There is no such grant defined for user \'%-.48s\' on host \'%-.64s\'" }, +{ "ER_TABLEACCESS_DENIED_ERROR", 1142, "%-.16s command denied to user \'%-.48s\'@\'%-.64s\' for table \'%-.192s\'" }, +{ "ER_COLUMNACCESS_DENIED_ERROR", 1143, "%-.16s command denied to user \'%-.48s\'@\'%-.64s\' for column \'%-.192s\' in table \'%-.192s\'" }, +{ "ER_ILLEGAL_GRANT_FOR_TABLE", 1144, "Illegal GRANT/REVOKE command; please consult the manual to see which privileges can be used" }, +{ "ER_GRANT_WRONG_HOST_OR_USER", 1145, "The host or user argument to GRANT is too long" }, +{ "ER_NO_SUCH_TABLE", 1146, "Table \'%-.192s.%-.192s\' doesn\'t exist" }, +{ "ER_NONEXISTING_TABLE_GRANT", 1147, "There is no such grant defined for user \'%-.48s\' on host \'%-.64s\' on table \'%-.192s\'" }, +{ "ER_NOT_ALLOWED_COMMAND", 1148, "The used command is not allowed with this MySQL version" }, +{ "ER_SYNTAX_ERROR", 1149, "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use" }, +{ "ER_DELAYED_CANT_CHANGE_LOCK", 1150, "Delayed insert thread couldn\'t get requested lock for table %-.192s" }, +{ "ER_TOO_MANY_DELAYED_THREADS", 1151, "Too many delayed threads in use" }, +{ "ER_ABORTING_CONNECTION", 1152, "Aborted connection %ld to db: \'%-.192s\' user: \'%-.48s\' (%-.64s)" }, +{ "ER_NET_PACKET_TOO_LARGE", 1153, "Got a packet bigger than \'max_allowed_packet\' bytes" }, +{ "ER_NET_READ_ERROR_FROM_PIPE", 1154, "Got a read error from the connection pipe" }, +{ "ER_NET_FCNTL_ERROR", 1155, "Got an error from fcntl()" }, +{ "ER_NET_PACKETS_OUT_OF_ORDER", 1156, "Got packets out of order" }, +{ "ER_NET_UNCOMPRESS_ERROR", 1157, "Couldn\'t uncompress communication packet" }, +{ "ER_NET_READ_ERROR", 1158, "Got an error reading communication packets" }, +{ "ER_NET_READ_INTERRUPTED", 1159, "Got timeout reading communication packets" }, +{ "ER_NET_ERROR_ON_WRITE", 1160, "Got an error writing communication packets" }, +{ "ER_NET_WRITE_INTERRUPTED", 1161, "Got timeout writing communication packets" }, +{ "ER_TOO_LONG_STRING", 1162, "Result string is longer than \'max_allowed_packet\' bytes" }, +{ "ER_TABLE_CANT_HANDLE_BLOB", 1163, "The used table type doesn\'t support BLOB/TEXT columns" }, +{ "ER_TABLE_CANT_HANDLE_AUTO_INCREMENT", 1164, "The used table type doesn\'t support AUTO_INCREMENT columns" }, +{ "ER_DELAYED_INSERT_TABLE_LOCKED", 1165, "INSERT DELAYED can\'t be used with table \'%-.192s\' because it is locked with LOCK TABLES" }, +{ "ER_WRONG_COLUMN_NAME", 1166, "Incorrect column name \'%-.100s\'" }, +{ "ER_WRONG_KEY_COLUMN", 1167, "The used storage engine can\'t index column \'%-.192s\'" }, +{ "ER_WRONG_MRG_TABLE", 1168, "Unable to open underlying table which is differently defined or of non-MyISAM type or doesn\'t exist" }, +{ "ER_DUP_UNIQUE", 1169, "Can\'t write, because of unique constraint, to table \'%-.192s\'" }, +{ "ER_BLOB_KEY_WITHOUT_LENGTH", 1170, "BLOB/TEXT column \'%-.192s\' used in key specification without a key length" }, +{ "ER_PRIMARY_CANT_HAVE_NULL", 1171, "All parts of a PRIMARY KEY must be NOT NULL; if you need NULL in a key, use UNIQUE instead" }, +{ "ER_TOO_MANY_ROWS", 1172, "Result consisted of more than one row" }, +{ "ER_REQUIRES_PRIMARY_KEY", 1173, "This table type requires a primary key" }, +{ "ER_NO_RAID_COMPILED", 1174, "This version of MySQL is not compiled with RAID support" }, +{ "ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE", 1175, "You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column" }, +{ "ER_KEY_DOES_NOT_EXITS", 1176, "Key \'%-.192s\' doesn\'t exist in table \'%-.192s\'" }, +{ "ER_CHECK_NO_SUCH_TABLE", 1177, "Can\'t open table" }, +{ "ER_CHECK_NOT_IMPLEMENTED", 1178, "The storage engine for the table doesn\'t support %s" }, +{ "ER_CANT_DO_THIS_DURING_AN_TRANSACTION", 1179, "You are not allowed to execute this command in a transaction" }, +{ "ER_ERROR_DURING_COMMIT", 1180, "Got error %d during COMMIT" }, +{ "ER_ERROR_DURING_ROLLBACK", 1181, "Got error %d during ROLLBACK" }, +{ "ER_ERROR_DURING_FLUSH_LOGS", 1182, "Got error %d during FLUSH_LOGS" }, +{ "ER_ERROR_DURING_CHECKPOINT", 1183, "Got error %d during CHECKPOINT" }, +{ "ER_NEW_ABORTING_CONNECTION", 1184, "Aborted connection %ld to db: \'%-.192s\' user: \'%-.48s\' host: \'%-.64s\' (%-.64s)" }, +{ "ER_DUMP_NOT_IMPLEMENTED", 1185, "The storage engine for the table does not support binary table dump" }, +{ "ER_FLUSH_MASTER_BINLOG_CLOSED", 1186, "Binlog closed, cannot RESET MASTER" }, +{ "ER_INDEX_REBUILD", 1187, "Failed rebuilding the index of dumped table \'%-.192s\'" }, +{ "ER_MASTER", 1188, "Error from master: \'%-.64s\'" }, +{ "ER_MASTER_NET_READ", 1189, "Net error reading from master" }, +{ "ER_MASTER_NET_WRITE", 1190, "Net error writing to master" }, +{ "ER_FT_MATCHING_KEY_NOT_FOUND", 1191, "Can\'t find FULLTEXT index matching the column list" }, +{ "ER_LOCK_OR_ACTIVE_TRANSACTION", 1192, "Can\'t execute the given command because you have active locked tables or an active transaction" }, +{ "ER_UNKNOWN_SYSTEM_VARIABLE", 1193, "Unknown system variable \'%-.64s\'" }, +{ "ER_CRASHED_ON_USAGE", 1194, "Table \'%-.192s\' is marked as crashed and should be repaired" }, +{ "ER_CRASHED_ON_REPAIR", 1195, "Table \'%-.192s\' is marked as crashed and last (automatic?) repair failed" }, +{ "ER_WARNING_NOT_COMPLETE_ROLLBACK", 1196, "Some non-transactional changed tables couldn\'t be rolled back" }, +{ "ER_TRANS_CACHE_FULL", 1197, "Multi-statement transaction required more than \'max_binlog_cache_size\' bytes of storage; increase this mysqld variable and try again" }, +{ "ER_SLAVE_MUST_STOP", 1198, "This operation cannot be performed with a running slave; run STOP SLAVE first" }, +{ "ER_SLAVE_NOT_RUNNING", 1199, "This operation requires a running slave; configure slave and do START SLAVE" }, +{ "ER_BAD_SLAVE", 1200, "The server is not configured as slave; fix in config file or with CHANGE MASTER TO" }, +{ "ER_MASTER_INFO", 1201, "Could not initialize master info structure; more error messages can be found in the MySQL error log" }, +{ "ER_SLAVE_THREAD", 1202, "Could not create slave thread; check system resources" }, +{ "ER_TOO_MANY_USER_CONNECTIONS", 1203, "User %-.64s already has more than \'max_user_connections\' active connections" }, +{ "ER_SET_CONSTANTS_ONLY", 1204, "You may only use constant expressions with SET" }, +{ "ER_LOCK_WAIT_TIMEOUT", 1205, "Lock wait timeout exceeded; try restarting transaction" }, +{ "ER_LOCK_TABLE_FULL", 1206, "The total number of locks exceeds the lock table size" }, +{ "ER_READ_ONLY_TRANSACTION", 1207, "Update locks cannot be acquired during a READ UNCOMMITTED transaction" }, +{ "ER_DROP_DB_WITH_READ_LOCK", 1208, "DROP DATABASE not allowed while thread is holding global read lock" }, +{ "ER_CREATE_DB_WITH_READ_LOCK", 1209, "CREATE DATABASE not allowed while thread is holding global read lock" }, +{ "ER_WRONG_ARGUMENTS", 1210, "Incorrect arguments to %s" }, +{ "ER_NO_PERMISSION_TO_CREATE_USER", 1211, "\'%-.48s\'@\'%-.64s\' is not allowed to create new users" }, +{ "ER_UNION_TABLES_IN_DIFFERENT_DIR", 1212, "Incorrect table definition; all MERGE tables must be in the same database" }, +{ "ER_LOCK_DEADLOCK", 1213, "Deadlock found when trying to get lock; try restarting transaction" }, +{ "ER_TABLE_CANT_HANDLE_FT", 1214, "The used table type doesn\'t support FULLTEXT indexes" }, +{ "ER_CANNOT_ADD_FOREIGN", 1215, "Cannot add foreign key constraint" }, +{ "ER_NO_REFERENCED_ROW", 1216, "Cannot add or update a child row: a foreign key constraint fails" }, +{ "ER_ROW_IS_REFERENCED", 1217, "Cannot delete or update a parent row: a foreign key constraint fails" }, +{ "ER_CONNECT_TO_MASTER", 1218, "Error connecting to master: %-.128s" }, +{ "ER_QUERY_ON_MASTER", 1219, "Error running query on master: %-.128s" }, +{ "ER_ERROR_WHEN_EXECUTING_COMMAND", 1220, "Error when executing command %s: %-.128s" }, +{ "ER_WRONG_USAGE", 1221, "Incorrect usage of %s and %s" }, +{ "ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT", 1222, "The used SELECT statements have a different number of columns" }, +{ "ER_CANT_UPDATE_WITH_READLOCK", 1223, "Can\'t execute the query because you have a conflicting read lock" }, +{ "ER_MIXING_NOT_ALLOWED", 1224, "Mixing of transactional and non-transactional tables is disabled" }, +{ "ER_DUP_ARGUMENT", 1225, "Option \'%s\' used twice in statement" }, +{ "ER_USER_LIMIT_REACHED", 1226, "User \'%-.64s\' has exceeded the \'%s\' resource (current value: %ld)" }, +{ "ER_SPECIFIC_ACCESS_DENIED_ERROR", 1227, "Access denied; you need (at least one of) the %-.128s privilege(s) for this operation" }, +{ "ER_LOCAL_VARIABLE", 1228, "Variable \'%-.64s\' is a SESSION variable and can\'t be used with SET GLOBAL" }, +{ "ER_GLOBAL_VARIABLE", 1229, "Variable \'%-.64s\' is a GLOBAL variable and should be set with SET GLOBAL" }, +{ "ER_NO_DEFAULT", 1230, "Variable \'%-.64s\' doesn\'t have a default value" }, +{ "ER_WRONG_VALUE_FOR_VAR", 1231, "Variable \'%-.64s\' can\'t be set to the value of \'%-.200s\'" }, +{ "ER_WRONG_TYPE_FOR_VAR", 1232, "Incorrect argument type to variable \'%-.64s\'" }, +{ "ER_VAR_CANT_BE_READ", 1233, "Variable \'%-.64s\' can only be set, not read" }, +{ "ER_CANT_USE_OPTION_HERE", 1234, "Incorrect usage/placement of \'%s\'" }, +{ "ER_NOT_SUPPORTED_YET", 1235, "This version of MySQL doesn\'t yet support \'%s\'" }, +{ "ER_MASTER_FATAL_ERROR_READING_BINLOG", 1236, "Got fatal error %d from master when reading data from binary log: \'%-.128s\'" }, +{ "ER_SLAVE_IGNORED_TABLE", 1237, "Slave SQL thread ignored the query because of replicate-*-table rules" }, +{ "ER_INCORRECT_GLOBAL_LOCAL_VAR", 1238, "Variable \'%-.192s\' is a %s variable" }, +{ "ER_WRONG_FK_DEF", 1239, "Incorrect foreign key definition for \'%-.192s\': %s" }, +{ "ER_KEY_REF_DO_NOT_MATCH_TABLE_REF", 1240, "Key reference and table reference don\'t match" }, +{ "ER_OPERAND_COLUMNS", 1241, "Operand should contain %d column(s)" }, +{ "ER_SUBQUERY_NO_1_ROW", 1242, "Subquery returns more than 1 row" }, +{ "ER_UNKNOWN_STMT_HANDLER", 1243, "Unknown prepared statement handler (%.*s) given to %s" }, +{ "ER_CORRUPT_HELP_DB", 1244, "Help database is corrupt or does not exist" }, +{ "ER_CYCLIC_REFERENCE", 1245, "Cyclic reference on subqueries" }, +{ "ER_AUTO_CONVERT", 1246, "Converting column \'%s\' from %s to %s" }, +{ "ER_ILLEGAL_REFERENCE", 1247, "Reference \'%-.64s\' not supported (%s)" }, +{ "ER_DERIVED_MUST_HAVE_ALIAS", 1248, "Every derived table must have its own alias" }, +{ "ER_SELECT_REDUCED", 1249, "Select %u was reduced during optimization" }, +{ "ER_TABLENAME_NOT_ALLOWED_HERE", 1250, "Table \'%-.192s\' from one of the SELECTs cannot be used in %-.32s" }, +{ "ER_NOT_SUPPORTED_AUTH_MODE", 1251, "Client does not support authentication protocol requested by server; consider upgrading MySQL client" }, +{ "ER_SPATIAL_CANT_HAVE_NULL", 1252, "All parts of a SPATIAL index must be NOT NULL" }, +{ "ER_COLLATION_CHARSET_MISMATCH", 1253, "COLLATION \'%s\' is not valid for CHARACTER SET \'%s\'" }, +{ "ER_SLAVE_WAS_RUNNING", 1254, "Slave is already running" }, +{ "ER_SLAVE_WAS_NOT_RUNNING", 1255, "Slave already has been stopped" }, +{ "ER_TOO_BIG_FOR_UNCOMPRESS", 1256, "Uncompressed data size too large; the maximum size is %d (probably, length of uncompressed data was corrupted)" }, +{ "ER_ZLIB_Z_MEM_ERROR", 1257, "ZLIB: Not enough memory" }, +{ "ER_ZLIB_Z_BUF_ERROR", 1258, "ZLIB: Not enough room in the output buffer (probably, length of uncompressed data was corrupted)" }, +{ "ER_ZLIB_Z_DATA_ERROR", 1259, "ZLIB: Input data corrupted" }, +{ "ER_CUT_VALUE_GROUP_CONCAT", 1260, "Row %u was cut by GROUP_CONCAT()" }, +{ "ER_WARN_TOO_FEW_RECORDS", 1261, "Row %ld doesn\'t contain data for all columns" }, +{ "ER_WARN_TOO_MANY_RECORDS", 1262, "Row %ld was truncated; it contained more data than there were input columns" }, +{ "ER_WARN_NULL_TO_NOTNULL", 1263, "Column set to default value; NULL supplied to NOT NULL column \'%s\' at row %ld" }, +{ "ER_WARN_DATA_OUT_OF_RANGE", 1264, "Out of range value for column \'%s\' at row %ld" }, +{ "WARN_DATA_TRUNCATED", 1265, "Data truncated for column \'%s\' at row %ld" }, +{ "ER_WARN_USING_OTHER_HANDLER", 1266, "Using storage engine %s for table \'%s\'" }, +{ "ER_CANT_AGGREGATE_2COLLATIONS", 1267, "Illegal mix of collations (%s,%s) and (%s,%s) for operation \'%s\'" }, +{ "ER_DROP_USER", 1268, "Cannot drop one or more of the requested users" }, +{ "ER_REVOKE_GRANTS", 1269, "Can\'t revoke all privileges for one or more of the requested users" }, +{ "ER_CANT_AGGREGATE_3COLLATIONS", 1270, "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation \'%s\'" }, +{ "ER_CANT_AGGREGATE_NCOLLATIONS", 1271, "Illegal mix of collations for operation \'%s\'" }, +{ "ER_VARIABLE_IS_NOT_STRUCT", 1272, "Variable \'%-.64s\' is not a variable component (can\'t be used as XXXX.variable_name)" }, +{ "ER_UNKNOWN_COLLATION", 1273, "Unknown collation: \'%-.64s\'" }, +{ "ER_SLAVE_IGNORED_SSL_PARAMS", 1274, "SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support; they can be used later if MySQL slave with SSL is started" }, +{ "ER_SERVER_IS_IN_SECURE_AUTH_MODE", 1275, "Server is running in --secure-auth mode, but \'%s\'@\'%s\' has a password in the old format; please change the password to the new format" }, +{ "ER_WARN_FIELD_RESOLVED", 1276, "Field or reference \'%-.192s%s%-.192s%s%-.192s\' of SELECT #%d was resolved in SELECT #%d" }, +{ "ER_BAD_SLAVE_UNTIL_COND", 1277, "Incorrect parameter or combination of parameters for START SLAVE UNTIL" }, +{ "ER_MISSING_SKIP_SLAVE", 1278, "It is recommended to use --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL; otherwise, you will get problems if you get an unexpected slave\'s mysqld restart" }, +{ "ER_UNTIL_COND_IGNORED", 1279, "SQL thread is not to be started so UNTIL options are ignored" }, +{ "ER_WRONG_NAME_FOR_INDEX", 1280, "Incorrect index name \'%-.100s\'" }, +{ "ER_WRONG_NAME_FOR_CATALOG", 1281, "Incorrect catalog name \'%-.100s\'" }, +{ "ER_WARN_QC_RESIZE", 1282, "Query cache failed to set size %lu; new query cache size is %lu" }, +{ "ER_BAD_FT_COLUMN", 1283, "Column \'%-.192s\' cannot be part of FULLTEXT index" }, +{ "ER_UNKNOWN_KEY_CACHE", 1284, "Unknown key cache \'%-.100s\'" }, +{ "ER_WARN_HOSTNAME_WONT_WORK", 1285, "MySQL is started in --skip-name-resolve mode; you must restart it without this switch for this grant to work" }, +{ "ER_UNKNOWN_STORAGE_ENGINE", 1286, "Unknown storage engine \'%s\'" }, +{ "ER_WARN_DEPRECATED_SYNTAX", 1287, "\'%s\' is deprecated and will be removed in a future release. Please use %s instead" }, +{ "ER_NON_UPDATABLE_TABLE", 1288, "The target table %-.100s of the %s is not updatable" }, +{ "ER_FEATURE_DISABLED", 1289, "The \'%s\' feature is disabled; you need MySQL built with \'%s\' to have it working" }, +{ "ER_OPTION_PREVENTS_STATEMENT", 1290, "The MySQL server is running with the %s option so it cannot execute this statement" }, +{ "ER_DUPLICATED_VALUE_IN_TYPE", 1291, "Column \'%-.100s\' has duplicated value \'%-.64s\' in %s" }, +{ "ER_TRUNCATED_WRONG_VALUE", 1292, "Truncated incorrect %-.32s value: \'%-.128s\'" }, +{ "ER_TOO_MUCH_AUTO_TIMESTAMP_COLS", 1293, "Incorrect table definition; there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause" }, +{ "ER_INVALID_ON_UPDATE", 1294, "Invalid ON UPDATE clause for \'%-.192s\' column" }, +{ "ER_UNSUPPORTED_PS", 1295, "This command is not supported in the prepared statement protocol yet" }, +{ "ER_GET_ERRMSG", 1296, "Got error %d \'%-.100s\' from %s" }, +{ "ER_GET_TEMPORARY_ERRMSG", 1297, "Got temporary error %d \'%-.100s\' from %s" }, +{ "ER_UNKNOWN_TIME_ZONE", 1298, "Unknown or incorrect time zone: \'%-.64s\'" }, +{ "ER_WARN_INVALID_TIMESTAMP", 1299, "Invalid TIMESTAMP value in column \'%s\' at row %ld" }, +{ "ER_INVALID_CHARACTER_STRING", 1300, "Invalid %s character string: \'%.64s\'" }, +{ "ER_WARN_ALLOWED_PACKET_OVERFLOWED", 1301, "Result of %s() was larger than max_allowed_packet (%ld) - truncated" }, +{ "ER_CONFLICTING_DECLARATIONS", 1302, "Conflicting declarations: \'%s%s\' and \'%s%s\'" }, +{ "ER_SP_NO_RECURSIVE_CREATE", 1303, "Can\'t create a %s from within another stored routine" }, +{ "ER_SP_ALREADY_EXISTS", 1304, "%s %s already exists" }, +{ "ER_SP_DOES_NOT_EXIST", 1305, "%s %s does not exist" }, +{ "ER_SP_DROP_FAILED", 1306, "Failed to DROP %s %s" }, +{ "ER_SP_STORE_FAILED", 1307, "Failed to CREATE %s %s" }, +{ "ER_SP_LILABEL_MISMATCH", 1308, "%s with no matching label: %s" }, +{ "ER_SP_LABEL_REDEFINE", 1309, "Redefining label %s" }, +{ "ER_SP_LABEL_MISMATCH", 1310, "End-label %s without match" }, +{ "ER_SP_UNINIT_VAR", 1311, "Referring to uninitialized variable %s" }, +{ "ER_SP_BADSELECT", 1312, "PROCEDURE %s can\'t return a result set in the given context" }, +{ "ER_SP_BADRETURN", 1313, "RETURN is only allowed in a FUNCTION" }, +{ "ER_SP_BADSTATEMENT", 1314, "%s is not allowed in stored procedures" }, +{ "ER_UPDATE_LOG_DEPRECATED_IGNORED", 1315, "The update log is deprecated and replaced by the binary log; SET SQL_LOG_UPDATE has been ignored. This option will be removed in MySQL 5.6." }, +{ "ER_UPDATE_LOG_DEPRECATED_TRANSLATED", 1316, "The update log is deprecated and replaced by the binary log; SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN. This option will be removed in MySQL 5.6." }, +{ "ER_QUERY_INTERRUPTED", 1317, "Query execution was interrupted" }, +{ "ER_SP_WRONG_NO_OF_ARGS", 1318, "Incorrect number of arguments for %s %s; expected %u, got %u" }, +{ "ER_SP_COND_MISMATCH", 1319, "Undefined CONDITION: %s" }, +{ "ER_SP_NORETURN", 1320, "No RETURN found in FUNCTION %s" }, +{ "ER_SP_NORETURNEND", 1321, "FUNCTION %s ended without RETURN" }, +{ "ER_SP_BAD_CURSOR_QUERY", 1322, "Cursor statement must be a SELECT" }, +{ "ER_SP_BAD_CURSOR_SELECT", 1323, "Cursor SELECT must not have INTO" }, +{ "ER_SP_CURSOR_MISMATCH", 1324, "Undefined CURSOR: %s" }, +{ "ER_SP_CURSOR_ALREADY_OPEN", 1325, "Cursor is already open" }, +{ "ER_SP_CURSOR_NOT_OPEN", 1326, "Cursor is not open" }, +{ "ER_SP_UNDECLARED_VAR", 1327, "Undeclared variable: %s" }, +{ "ER_SP_WRONG_NO_OF_FETCH_ARGS", 1328, "Incorrect number of FETCH variables" }, +{ "ER_SP_FETCH_NO_DATA", 1329, "No data - zero rows fetched, selected, or processed" }, +{ "ER_SP_DUP_PARAM", 1330, "Duplicate parameter: %s" }, +{ "ER_SP_DUP_VAR", 1331, "Duplicate variable: %s" }, +{ "ER_SP_DUP_COND", 1332, "Duplicate condition: %s" }, +{ "ER_SP_DUP_CURS", 1333, "Duplicate cursor: %s" }, +{ "ER_SP_CANT_ALTER", 1334, "Failed to ALTER %s %s" }, +{ "ER_SP_SUBSELECT_NYI", 1335, "Subquery value not supported" }, +{ "ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG", 1336, "%s is not allowed in stored function or trigger" }, +{ "ER_SP_VARCOND_AFTER_CURSHNDLR", 1337, "Variable or condition declaration after cursor or handler declaration" }, +{ "ER_SP_CURSOR_AFTER_HANDLER", 1338, "Cursor declaration after handler declaration" }, +{ "ER_SP_CASE_NOT_FOUND", 1339, "Case not found for CASE statement" }, +{ "ER_FPARSER_TOO_BIG_FILE", 1340, "Configuration file \'%-.192s\' is too big" }, +{ "ER_FPARSER_BAD_HEADER", 1341, "Malformed file type header in file \'%-.192s\'" }, +{ "ER_FPARSER_EOF_IN_COMMENT", 1342, "Unexpected end of file while parsing comment \'%-.200s\'" }, +{ "ER_FPARSER_ERROR_IN_PARAMETER", 1343, "Error while parsing parameter \'%-.192s\' (line: \'%-.192s\')" }, +{ "ER_FPARSER_EOF_IN_UNKNOWN_PARAMETER", 1344, "Unexpected end of file while skipping unknown parameter \'%-.192s\'" }, +{ "ER_VIEW_NO_EXPLAIN", 1345, "EXPLAIN/SHOW can not be issued; lacking privileges for underlying table" }, +{ "ER_FRM_UNKNOWN_TYPE", 1346, "File \'%-.192s\' has unknown type \'%-.64s\' in its header" }, +{ "ER_WRONG_OBJECT", 1347, "\'%-.192s.%-.192s\' is not %s" }, +{ "ER_NONUPDATEABLE_COLUMN", 1348, "Column \'%-.192s\' is not updatable" }, +{ "ER_VIEW_SELECT_DERIVED", 1349, "View\'s SELECT contains a subquery in the FROM clause" }, +{ "ER_VIEW_SELECT_CLAUSE", 1350, "View\'s SELECT contains a \'%s\' clause" }, +{ "ER_VIEW_SELECT_VARIABLE", 1351, "View\'s SELECT contains a variable or parameter" }, +{ "ER_VIEW_SELECT_TMPTABLE", 1352, "View\'s SELECT refers to a temporary table \'%-.192s\'" }, +{ "ER_VIEW_WRONG_LIST", 1353, "View\'s SELECT and view\'s field list have different column counts" }, +{ "ER_WARN_VIEW_MERGE", 1354, "View merge algorithm can\'t be used here for now (assumed undefined algorithm)" }, +{ "ER_WARN_VIEW_WITHOUT_KEY", 1355, "View being updated does not have complete key of underlying table in it" }, +{ "ER_VIEW_INVALID", 1356, "View \'%-.192s.%-.192s\' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them" }, +{ "ER_SP_NO_DROP_SP", 1357, "Can\'t drop or alter a %s from within another stored routine" }, +{ "ER_SP_GOTO_IN_HNDLR", 1358, "GOTO is not allowed in a stored procedure handler" }, +{ "ER_TRG_ALREADY_EXISTS", 1359, "Trigger already exists" }, +{ "ER_TRG_DOES_NOT_EXIST", 1360, "Trigger does not exist" }, +{ "ER_TRG_ON_VIEW_OR_TEMP_TABLE", 1361, "Trigger\'s \'%-.192s\' is view or temporary table" }, +{ "ER_TRG_CANT_CHANGE_ROW", 1362, "Updating of %s row is not allowed in %strigger" }, +{ "ER_TRG_NO_SUCH_ROW_IN_TRG", 1363, "There is no %s row in %s trigger" }, +{ "ER_NO_DEFAULT_FOR_FIELD", 1364, "Field \'%-.192s\' doesn\'t have a default value" }, +{ "ER_DIVISION_BY_ZERO", 1365, "Division by 0" }, +{ "ER_TRUNCATED_WRONG_VALUE_FOR_FIELD", 1366, "Incorrect %-.32s value: \'%-.128s\' for column \'%.192s\' at row %ld" }, +{ "ER_ILLEGAL_VALUE_FOR_TYPE", 1367, "Illegal %s \'%-.192s\' value found during parsing" }, +{ "ER_VIEW_NONUPD_CHECK", 1368, "CHECK OPTION on non-updatable view \'%-.192s.%-.192s\'" }, +{ "ER_VIEW_CHECK_FAILED", 1369, "CHECK OPTION failed \'%-.192s.%-.192s\'" }, +{ "ER_PROCACCESS_DENIED_ERROR", 1370, "%-.16s command denied to user \'%-.48s\'@\'%-.64s\' for routine \'%-.192s\'" }, +{ "ER_RELAY_LOG_FAIL", 1371, "Failed purging old relay logs: %s" }, +{ "ER_PASSWD_LENGTH", 1372, "Password hash should be a %d-digit hexadecimal number" }, +{ "ER_UNKNOWN_TARGET_BINLOG", 1373, "Target log not found in binlog index" }, +{ "ER_IO_ERR_LOG_INDEX_READ", 1374, "I/O error reading log index file" }, +{ "ER_BINLOG_PURGE_PROHIBITED", 1375, "Server configuration does not permit binlog purge" }, +{ "ER_FSEEK_FAIL", 1376, "Failed on fseek()" }, +{ "ER_BINLOG_PURGE_FATAL_ERR", 1377, "Fatal error during log purge" }, +{ "ER_LOG_IN_USE", 1378, "A purgeable log is in use, will not purge" }, +{ "ER_LOG_PURGE_UNKNOWN_ERR", 1379, "Unknown error during log purge" }, +{ "ER_RELAY_LOG_INIT", 1380, "Failed initializing relay log position: %s" }, +{ "ER_NO_BINARY_LOGGING", 1381, "You are not using binary logging" }, +{ "ER_RESERVED_SYNTAX", 1382, "The \'%-.64s\' syntax is reserved for purposes internal to the MySQL server" }, +{ "ER_WSAS_FAILED", 1383, "WSAStartup Failed" }, +{ "ER_DIFF_GROUPS_PROC", 1384, "Can\'t handle procedures with different groups yet" }, +{ "ER_NO_GROUP_FOR_PROC", 1385, "Select must have a group with this procedure" }, +{ "ER_ORDER_WITH_PROC", 1386, "Can\'t use ORDER clause with this procedure" }, +{ "ER_LOGGING_PROHIBIT_CHANGING_OF", 1387, "Binary logging and replication forbid changing the global server %s" }, +{ "ER_NO_FILE_MAPPING", 1388, "Can\'t map file: %-.200s, errno: %d" }, +{ "ER_WRONG_MAGIC", 1389, "Wrong magic in %-.64s" }, +{ "ER_PS_MANY_PARAM", 1390, "Prepared statement contains too many placeholders" }, +{ "ER_KEY_PART_0", 1391, "Key part \'%-.192s\' length cannot be 0" }, +{ "ER_VIEW_CHECKSUM", 1392, "View text checksum failed" }, +{ "ER_VIEW_MULTIUPDATE", 1393, "Can not modify more than one base table through a join view \'%-.192s.%-.192s\'" }, +{ "ER_VIEW_NO_INSERT_FIELD_LIST", 1394, "Can not insert into join view \'%-.192s.%-.192s\' without fields list" }, +{ "ER_VIEW_DELETE_MERGE_VIEW", 1395, "Can not delete from join view \'%-.192s.%-.192s\'" }, +{ "ER_CANNOT_USER", 1396, "Operation %s failed for %.256s" }, +{ "ER_XAER_NOTA", 1397, "XAER_NOTA: Unknown XID" }, +{ "ER_XAER_INVAL", 1398, "XAER_INVAL: Invalid arguments (or unsupported command)" }, +{ "ER_XAER_RMFAIL", 1399, "XAER_RMFAIL: The command cannot be executed when global transaction is in the %.64s state" }, +{ "ER_XAER_OUTSIDE", 1400, "XAER_OUTSIDE: Some work is done outside global transaction" }, +{ "ER_XAER_RMERR", 1401, "XAER_RMERR: Fatal error occurred in the transaction branch - check your data for consistency" }, +{ "ER_XA_RBROLLBACK", 1402, "XA_RBROLLBACK: Transaction branch was rolled back" }, +{ "ER_NONEXISTING_PROC_GRANT", 1403, "There is no such grant defined for user \'%-.48s\' on host \'%-.64s\' on routine \'%-.192s\'" }, +{ "ER_PROC_AUTO_GRANT_FAIL", 1404, "Failed to grant EXECUTE and ALTER ROUTINE privileges" }, +{ "ER_PROC_AUTO_REVOKE_FAIL", 1405, "Failed to revoke all privileges to dropped routine" }, +{ "ER_DATA_TOO_LONG", 1406, "Data too long for column \'%s\' at row %ld" }, +{ "ER_SP_BAD_SQLSTATE", 1407, "Bad SQLSTATE: \'%s\'" }, +{ "ER_STARTUP", 1408, "%s: ready for connections.\nVersion: \'%s\' socket: \'%s\' port: %d %s" }, +{ "ER_LOAD_FROM_FIXED_SIZE_ROWS_TO_VAR", 1409, "Can\'t load value from file with fixed size rows to variable" }, +{ "ER_CANT_CREATE_USER_WITH_GRANT", 1410, "You are not allowed to create a user with GRANT" }, +{ "ER_WRONG_VALUE_FOR_TYPE", 1411, "Incorrect %-.32s value: \'%-.128s\' for function %-.32s" }, +{ "ER_TABLE_DEF_CHANGED", 1412, "Table definition has changed, please retry transaction" }, +{ "ER_SP_DUP_HANDLER", 1413, "Duplicate handler declared in the same block" }, +{ "ER_SP_NOT_VAR_ARG", 1414, "OUT or INOUT argument %d for routine %s is not a variable or NEW pseudo-variable in BEFORE trigger" }, +{ "ER_SP_NO_RETSET", 1415, "Not allowed to return a result set from a %s" }, +{ "ER_CANT_CREATE_GEOMETRY_OBJECT", 1416, "Cannot get geometry object from data you send to the GEOMETRY field" }, +{ "ER_FAILED_ROUTINE_BREAK_BINLOG", 1417, "A routine failed and has neither NO SQL nor READS SQL DATA in its declaration and binary logging is enabled; if non-transactional tables were updated, the binary log will miss their changes" }, +{ "ER_BINLOG_UNSAFE_ROUTINE", 1418, "This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)" }, +{ "ER_BINLOG_CREATE_ROUTINE_NEED_SUPER", 1419, "You do not have the SUPER privilege and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)" }, +{ "ER_EXEC_STMT_WITH_OPEN_CURSOR", 1420, "You can\'t execute a prepared statement which has an open cursor associated with it. Reset the statement to re-execute it." }, +{ "ER_STMT_HAS_NO_OPEN_CURSOR", 1421, "The statement (%lu) has no open cursor." }, +{ "ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG", 1422, "Explicit or implicit commit is not allowed in stored function or trigger." }, +{ "ER_NO_DEFAULT_FOR_VIEW_FIELD", 1423, "Field of view \'%-.192s.%-.192s\' underlying table doesn\'t have a default value" }, +{ "ER_SP_NO_RECURSION", 1424, "Recursive stored functions and triggers are not allowed." }, +{ "ER_TOO_BIG_SCALE", 1425, "Too big scale %d specified for column \'%-.192s\'. Maximum is %lu." }, +{ "ER_TOO_BIG_PRECISION", 1426, "Too big precision %d specified for column \'%-.192s\'. Maximum is %lu." }, +{ "ER_M_BIGGER_THAN_D", 1427, "For float(M,D), double(M,D) or decimal(M,D), M must be >= D (column \'%-.192s\')." }, +{ "ER_WRONG_LOCK_OF_SYSTEM_TABLE", 1428, "You can\'t combine write-locking of system tables with other tables or lock types" }, +{ "ER_CONNECT_TO_FOREIGN_DATA_SOURCE", 1429, "Unable to connect to foreign data source: %.64s" }, +{ "ER_QUERY_ON_FOREIGN_DATA_SOURCE", 1430, "There was a problem processing the query on the foreign data source. Data source error: %-.64s" }, +{ "ER_FOREIGN_DATA_SOURCE_DOESNT_EXIST", 1431, "The foreign data source you are trying to reference does not exist. Data source error: %-.64s" }, +{ "ER_FOREIGN_DATA_STRING_INVALID_CANT_CREATE", 1432, "Can\'t create federated table. The data source connection string \'%-.64s\' is not in the correct format" }, +{ "ER_FOREIGN_DATA_STRING_INVALID", 1433, "The data source connection string \'%-.64s\' is not in the correct format" }, +{ "ER_CANT_CREATE_FEDERATED_TABLE", 1434, "Can\'t create federated table. Foreign data src error: %-.64s" }, +{ "ER_TRG_IN_WRONG_SCHEMA", 1435, "Trigger in wrong schema" }, +{ "ER_STACK_OVERRUN_NEED_MORE", 1436, "Thread stack overrun: %ld bytes used of a %ld byte stack, and %ld bytes needed. Use \'mysqld --thread_stack=#\' to specify a bigger stack." }, +{ "ER_TOO_LONG_BODY", 1437, "Routine body for \'%-.100s\' is too long" }, +{ "ER_WARN_CANT_DROP_DEFAULT_KEYCACHE", 1438, "Cannot drop default keycache" }, +{ "ER_TOO_BIG_DISPLAYWIDTH", 1439, "Display width out of range for column \'%-.192s\' (max = %lu)" }, +{ "ER_XAER_DUPID", 1440, "XAER_DUPID: The XID already exists" }, +{ "ER_DATETIME_FUNCTION_OVERFLOW", 1441, "Datetime function: %-.32s field overflow" }, +{ "ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG", 1442, "Can\'t update table \'%-.192s\' in stored function/trigger because it is already used by statement which invoked this stored function/trigger." }, +{ "ER_VIEW_PREVENT_UPDATE", 1443, "The definition of table \'%-.192s\' prevents operation %.192s on table \'%-.192s\'." }, +{ "ER_PS_NO_RECURSION", 1444, "The prepared statement contains a stored routine call that refers to that same statement. It\'s not allowed to execute a prepared statement in such a recursive manner" }, +{ "ER_SP_CANT_SET_AUTOCOMMIT", 1445, "Not allowed to set autocommit from a stored function or trigger" }, +{ "ER_MALFORMED_DEFINER", 1446, "Definer is not fully qualified" }, +{ "ER_VIEW_FRM_NO_USER", 1447, "View \'%-.192s\'.\'%-.192s\' has no definer information (old table format). Current user is used as definer. Please recreate the view!" }, +{ "ER_VIEW_OTHER_USER", 1448, "You need the SUPER privilege for creation view with \'%-.192s\'@\'%-.192s\' definer" }, +{ "ER_NO_SUCH_USER", 1449, "The user specified as a definer (\'%-.64s\'@\'%-.64s\') does not exist" }, +{ "ER_FORBID_SCHEMA_CHANGE", 1450, "Changing schema from \'%-.192s\' to \'%-.192s\' is not allowed." }, +{ "ER_ROW_IS_REFERENCED_2", 1451, "Cannot delete or update a parent row: a foreign key constraint fails (%.192s)" }, +{ "ER_NO_REFERENCED_ROW_2", 1452, "Cannot add or update a child row: a foreign key constraint fails (%.192s)" }, +{ "ER_SP_BAD_VAR_SHADOW", 1453, "Variable \'%-.64s\' must be quoted with `...`, or renamed" }, +{ "ER_TRG_NO_DEFINER", 1454, "No definer attribute for trigger \'%-.192s\'.\'%-.192s\'. The trigger will be activated under the authorization of the invoker, which may have insufficient privileges. Please recreate the trigger." }, +{ "ER_OLD_FILE_FORMAT", 1455, "\'%-.192s\' has an old format, you should re-create the \'%s\' object(s)" }, +{ "ER_SP_RECURSION_LIMIT", 1456, "Recursive limit %d (as set by the max_sp_recursion_depth variable) was exceeded for routine %.192s" }, +{ "ER_SP_PROC_TABLE_CORRUPT", 1457, "Failed to load routine %-.192s. The table mysql.proc is missing, corrupt, or contains bad data (internal code %d)" }, +{ "ER_SP_WRONG_NAME", 1458, "Incorrect routine name \'%-.192s\'" }, +{ "ER_TABLE_NEEDS_UPGRADE", 1459, "Table upgrade required. Please do \"REPAIR TABLE `%-.32s`\" or dump/reload to fix it!" }, +{ "ER_SP_NO_AGGREGATE", 1460, "AGGREGATE is not supported for stored functions" }, +{ "ER_MAX_PREPARED_STMT_COUNT_REACHED", 1461, "Can\'t create more than max_prepared_stmt_count statements (current value: %lu)" }, +{ "ER_VIEW_RECURSIVE", 1462, "`%-.192s`.`%-.192s` contains view recursion" }, +{ "ER_NON_GROUPING_FIELD_USED", 1463, "non-grouping field \'%-.192s\' is used in %-.64s clause" }, +{ "ER_TABLE_CANT_HANDLE_SPKEYS", 1464, "The used table type doesn\'t support SPATIAL indexes" }, +{ "ER_NO_TRIGGERS_ON_SYSTEM_SCHEMA", 1465, "Triggers can not be created on system tables" }, +{ "ER_REMOVED_SPACES", 1466, "Leading spaces are removed from name \'%s\'" }, +{ "ER_AUTOINC_READ_FAILED", 1467, "Failed to read auto-increment value from storage engine" }, +{ "ER_USERNAME", 1468, "user name" }, +{ "ER_HOSTNAME", 1469, "host name" }, +{ "ER_WRONG_STRING_LENGTH", 1470, "String \'%-.70s\' is too long for %s (should be no longer than %d)" }, +{ "ER_NON_INSERTABLE_TABLE", 1471, "The target table %-.100s of the %s is not insertable-into" }, +{ "ER_ADMIN_WRONG_MRG_TABLE", 1472, "Table \'%-.64s\' is differently defined or of non-MyISAM type or doesn\'t exist" }, +{ "ER_TOO_HIGH_LEVEL_OF_NESTING_FOR_SELECT", 1473, "Too high level of nesting for select" }, +{ "ER_NAME_BECOMES_EMPTY", 1474, "Name \'%-.64s\' has become \'\'" }, +{ "ER_AMBIGUOUS_FIELD_TERM", 1475, "First character of the FIELDS TERMINATED string is ambiguous; please use non-optional and non-empty FIELDS ENCLOSED BY" }, +{ "ER_FOREIGN_SERVER_EXISTS", 1476, "The foreign server, %s, you are trying to create already exists." }, +{ "ER_FOREIGN_SERVER_DOESNT_EXIST", 1477, "The foreign server name you are trying to reference does not exist. Data source error: %-.64s" }, +{ "ER_ILLEGAL_HA_CREATE_OPTION", 1478, "Table storage engine \'%-.64s\' does not support the create option \'%.64s\'" }, +{ "ER_PARTITION_REQUIRES_VALUES_ERROR", 1479, "Syntax error: %-.64s PARTITIONING requires definition of VALUES %-.64s for each partition" }, +{ "ER_PARTITION_WRONG_VALUES_ERROR", 1480, "Only %-.64s PARTITIONING can use VALUES %-.64s in partition definition" }, +{ "ER_PARTITION_MAXVALUE_ERROR", 1481, "MAXVALUE can only be used in last partition definition" }, +{ "ER_PARTITION_SUBPARTITION_ERROR", 1482, "Subpartitions can only be hash partitions and by key" }, +{ "ER_PARTITION_SUBPART_MIX_ERROR", 1483, "Must define subpartitions on all partitions if on one partition" }, +{ "ER_PARTITION_WRONG_NO_PART_ERROR", 1484, "Wrong number of partitions defined, mismatch with previous setting" }, +{ "ER_PARTITION_WRONG_NO_SUBPART_ERROR", 1485, "Wrong number of subpartitions defined, mismatch with previous setting" }, +{ "ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR", 1486, "Constant, random or timezone-dependent expressions in (sub)partitioning function are not allowed" }, +{ "ER_NO_CONST_EXPR_IN_RANGE_OR_LIST_ERROR", 1487, "Expression in RANGE/LIST VALUES must be constant" }, +{ "ER_FIELD_NOT_FOUND_PART_ERROR", 1488, "Field in list of fields for partition function not found in table" }, +{ "ER_LIST_OF_FIELDS_ONLY_IN_HASH_ERROR", 1489, "List of fields is only allowed in KEY partitions" }, +{ "ER_INCONSISTENT_PARTITION_INFO_ERROR", 1490, "The partition info in the frm file is not consistent with what can be written into the frm file" }, +{ "ER_PARTITION_FUNC_NOT_ALLOWED_ERROR", 1491, "The %-.192s function returns the wrong type" }, +{ "ER_PARTITIONS_MUST_BE_DEFINED_ERROR", 1492, "For %-.64s partitions each partition must be defined" }, +{ "ER_RANGE_NOT_INCREASING_ERROR", 1493, "VALUES LESS THAN value must be strictly increasing for each partition" }, +{ "ER_INCONSISTENT_TYPE_OF_FUNCTIONS_ERROR", 1494, "VALUES value must be of same type as partition function" }, +{ "ER_MULTIPLE_DEF_CONST_IN_LIST_PART_ERROR", 1495, "Multiple definition of same constant in list partitioning" }, +{ "ER_PARTITION_ENTRY_ERROR", 1496, "Partitioning can not be used stand-alone in query" }, +{ "ER_MIX_HANDLER_ERROR", 1497, "The mix of handlers in the partitions is not allowed in this version of MySQL" }, +{ "ER_PARTITION_NOT_DEFINED_ERROR", 1498, "For the partitioned engine it is necessary to define all %-.64s" }, +{ "ER_TOO_MANY_PARTITIONS_ERROR", 1499, "Too many partitions (including subpartitions) were defined" }, +{ "ER_SUBPARTITION_ERROR", 1500, "It is only possible to mix RANGE/LIST partitioning with HASH/KEY partitioning for subpartitioning" }, +{ "ER_CANT_CREATE_HANDLER_FILE", 1501, "Failed to create specific handler file" }, +{ "ER_BLOB_FIELD_IN_PART_FUNC_ERROR", 1502, "A BLOB field is not allowed in partition function" }, +{ "ER_UNIQUE_KEY_NEED_ALL_FIELDS_IN_PF", 1503, "A %-.192s must include all columns in the table\'s partitioning function" }, +{ "ER_NO_PARTS_ERROR", 1504, "Number of %-.64s = 0 is not an allowed value" }, +{ "ER_PARTITION_MGMT_ON_NONPARTITIONED", 1505, "Partition management on a not partitioned table is not possible" }, +{ "ER_FOREIGN_KEY_ON_PARTITIONED", 1506, "Foreign key clause is not yet supported in conjunction with partitioning" }, +{ "ER_DROP_PARTITION_NON_EXISTENT", 1507, "Error in list of partitions to %-.64s" }, +{ "ER_DROP_LAST_PARTITION", 1508, "Cannot remove all partitions, use DROP TABLE instead" }, +{ "ER_COALESCE_ONLY_ON_HASH_PARTITION", 1509, "COALESCE PARTITION can only be used on HASH/KEY partitions" }, +{ "ER_REORG_HASH_ONLY_ON_SAME_NO", 1510, "REORGANIZE PARTITION can only be used to reorganize partitions not to change their numbers" }, +{ "ER_REORG_NO_PARAM_ERROR", 1511, "REORGANIZE PARTITION without parameters can only be used on auto-partitioned tables using HASH PARTITIONs" }, +{ "ER_ONLY_ON_RANGE_LIST_PARTITION", 1512, "%-.64s PARTITION can only be used on RANGE/LIST partitions" }, +{ "ER_ADD_PARTITION_SUBPART_ERROR", 1513, "Trying to Add partition(s) with wrong number of subpartitions" }, +{ "ER_ADD_PARTITION_NO_NEW_PARTITION", 1514, "At least one partition must be added" }, +{ "ER_COALESCE_PARTITION_NO_PARTITION", 1515, "At least one partition must be coalesced" }, +{ "ER_REORG_PARTITION_NOT_EXIST", 1516, "More partitions to reorganize than there are partitions" }, +{ "ER_SAME_NAME_PARTITION", 1517, "Duplicate partition name %-.192s" }, +{ "ER_NO_BINLOG_ERROR", 1518, "It is not allowed to shut off binlog on this command" }, +{ "ER_CONSECUTIVE_REORG_PARTITIONS", 1519, "When reorganizing a set of partitions they must be in consecutive order" }, +{ "ER_REORG_OUTSIDE_RANGE", 1520, "Reorganize of range partitions cannot change total ranges except for last partition where it can extend the range" }, +{ "ER_PARTITION_FUNCTION_FAILURE", 1521, "Partition function not supported in this version for this handler" }, +{ "ER_PART_STATE_ERROR", 1522, "Partition state cannot be defined from CREATE/ALTER TABLE" }, +{ "ER_LIMITED_PART_RANGE", 1523, "The %-.64s handler only supports 32 bit integers in VALUES" }, +{ "ER_PLUGIN_IS_NOT_LOADED", 1524, "Plugin \'%-.192s\' is not loaded" }, +{ "ER_WRONG_VALUE", 1525, "Incorrect %-.32s value: \'%-.128s\'" }, +{ "ER_NO_PARTITION_FOR_GIVEN_VALUE", 1526, "Table has no partition for value %-.64s" }, +{ "ER_FILEGROUP_OPTION_ONLY_ONCE", 1527, "It is not allowed to specify %s more than once" }, +{ "ER_CREATE_FILEGROUP_FAILED", 1528, "Failed to create %s" }, +{ "ER_DROP_FILEGROUP_FAILED", 1529, "Failed to drop %s" }, +{ "ER_TABLESPACE_AUTO_EXTEND_ERROR", 1530, "The handler doesn\'t support autoextend of tablespaces" }, +{ "ER_WRONG_SIZE_NUMBER", 1531, "A size parameter was incorrectly specified, either number or on the form 10M" }, +{ "ER_SIZE_OVERFLOW_ERROR", 1532, "The size number was correct but we don\'t allow the digit part to be more than 2 billion" }, +{ "ER_ALTER_FILEGROUP_FAILED", 1533, "Failed to alter: %s" }, +{ "ER_BINLOG_ROW_LOGGING_FAILED", 1534, "Writing one row to the row-based binary log failed" }, +{ "ER_BINLOG_ROW_WRONG_TABLE_DEF", 1535, "Table definition on master and slave does not match: %s" }, +{ "ER_BINLOG_ROW_RBR_TO_SBR", 1536, "Slave running with --log-slave-updates must use row-based binary logging to be able to replicate row-based binary log events" }, +{ "ER_EVENT_ALREADY_EXISTS", 1537, "Event \'%-.192s\' already exists" }, +{ "ER_EVENT_STORE_FAILED", 1538, "Failed to store event %s. Error code %d from storage engine." }, +{ "ER_EVENT_DOES_NOT_EXIST", 1539, "Unknown event \'%-.192s\'" }, +{ "ER_EVENT_CANT_ALTER", 1540, "Failed to alter event \'%-.192s\'" }, +{ "ER_EVENT_DROP_FAILED", 1541, "Failed to drop %s" }, +{ "ER_EVENT_INTERVAL_NOT_POSITIVE_OR_TOO_BIG", 1542, "INTERVAL is either not positive or too big" }, +{ "ER_EVENT_ENDS_BEFORE_STARTS", 1543, "ENDS is either invalid or before STARTS" }, +{ "ER_EVENT_EXEC_TIME_IN_THE_PAST", 1544, "Event execution time is in the past. Event has been disabled" }, +{ "ER_EVENT_OPEN_TABLE_FAILED", 1545, "Failed to open mysql.event" }, +{ "ER_EVENT_NEITHER_M_EXPR_NOR_M_AT", 1546, "No datetime expression provided" }, +{ "ER_COL_COUNT_DOESNT_MATCH_CORRUPTED", 1547, "Column count of mysql.%s is wrong. Expected %d, found %d. The table is probably corrupted" }, +{ "ER_CANNOT_LOAD_FROM_TABLE", 1548, "Cannot load from mysql.%s. The table is probably corrupted" }, +{ "ER_EVENT_CANNOT_DELETE", 1549, "Failed to delete the event from mysql.event" }, +{ "ER_EVENT_COMPILE_ERROR", 1550, "Error during compilation of event\'s body" }, +{ "ER_EVENT_SAME_NAME", 1551, "Same old and new event name" }, +{ "ER_EVENT_DATA_TOO_LONG", 1552, "Data for column \'%s\' too long" }, +{ "ER_DROP_INDEX_FK", 1553, "Cannot drop index \'%-.192s\': needed in a foreign key constraint" }, +{ "ER_WARN_DEPRECATED_SYNTAX_WITH_VER", 1554, "The syntax \'%s\' is deprecated and will be removed in MySQL %s. Please use %s instead" }, +{ "ER_CANT_WRITE_LOCK_LOG_TABLE", 1555, "You can\'t write-lock a log table. Only read access is possible" }, +{ "ER_CANT_LOCK_LOG_TABLE", 1556, "You can\'t use locks with log tables." }, +{ "ER_FOREIGN_DUPLICATE_KEY", 1557, "Upholding foreign key constraints for table \'%.192s\', entry \'%-.192s\', key %d would lead to a duplicate entry" }, +{ "ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE", 1558, "Column count of mysql.%s is wrong. Expected %d, found %d. Created with MySQL %d, now running %d. Please use mysql_upgrade to fix this error." }, +{ "ER_TEMP_TABLE_PREVENTS_SWITCH_OUT_OF_RBR", 1559, "Cannot switch out of the row-based binary log format when the session has open temporary tables" }, +{ "ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_FORMAT", 1560, "Cannot change the binary logging format inside a stored function or trigger" }, +{ "ER_NDB_CANT_SWITCH_BINLOG_FORMAT", 1561, "The NDB cluster engine does not support changing the binlog format on the fly yet" }, +{ "ER_PARTITION_NO_TEMPORARY", 1562, "Cannot create temporary table with partitions" }, +{ "ER_PARTITION_CONST_DOMAIN_ERROR", 1563, "Partition constant is out of partition function domain" }, +{ "ER_PARTITION_FUNCTION_IS_NOT_ALLOWED", 1564, "This partition function is not allowed" }, +{ "ER_DDL_LOG_ERROR", 1565, "Error in DDL log" }, +{ "ER_NULL_IN_VALUES_LESS_THAN", 1566, "Not allowed to use NULL value in VALUES LESS THAN" }, +{ "ER_WRONG_PARTITION_NAME", 1567, "Incorrect partition name" }, +{ "ER_CANT_CHANGE_TX_ISOLATION", 1568, "Transaction isolation level can\'t be changed while a transaction is in progress" }, +{ "ER_DUP_ENTRY_AUTOINCREMENT_CASE", 1569, "ALTER TABLE causes auto_increment resequencing, resulting in duplicate entry \'%-.192s\' for key \'%-.192s\'" }, +{ "ER_EVENT_MODIFY_QUEUE_ERROR", 1570, "Internal scheduler error %d" }, +{ "ER_EVENT_SET_VAR_ERROR", 1571, "Error during starting/stopping of the scheduler. Error code %u" }, +{ "ER_PARTITION_MERGE_ERROR", 1572, "Engine cannot be used in partitioned tables" }, +{ "ER_CANT_ACTIVATE_LOG", 1573, "Cannot activate \'%-.64s\' log" }, +{ "ER_RBR_NOT_AVAILABLE", 1574, "The server was not built with row-based replication" }, +{ "ER_BASE64_DECODE_ERROR", 1575, "Decoding of base64 string failed" }, +{ "ER_EVENT_RECURSION_FORBIDDEN", 1576, "Recursion of EVENT DDL statements is forbidden when body is present" }, +{ "ER_EVENTS_DB_ERROR", 1577, "Cannot proceed because system tables used by Event Scheduler were found damaged at server start" }, +{ "ER_ONLY_INTEGERS_ALLOWED", 1578, "Only integers allowed as number here" }, +{ "ER_UNSUPORTED_LOG_ENGINE", 1579, "This storage engine cannot be used for log tables\"" }, +{ "ER_BAD_LOG_STATEMENT", 1580, "You cannot \'%s\' a log table if logging is enabled" }, +{ "ER_CANT_RENAME_LOG_TABLE", 1581, "Cannot rename \'%s\'. When logging enabled, rename to/from log table must rename two tables: the log table to an archive table and another table back to \'%s\'" }, +{ "ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT", 1582, "Incorrect parameter count in the call to native function \'%-.192s\'" }, +{ "ER_WRONG_PARAMETERS_TO_NATIVE_FCT", 1583, "Incorrect parameters in the call to native function \'%-.192s\'" }, +{ "ER_WRONG_PARAMETERS_TO_STORED_FCT", 1584, "Incorrect parameters in the call to stored function \'%-.192s\'" }, +{ "ER_NATIVE_FCT_NAME_COLLISION", 1585, "This function \'%-.192s\' has the same name as a native function" }, +{ "ER_DUP_ENTRY_WITH_KEY_NAME", 1586, "Duplicate entry \'%-.64s\' for key \'%-.192s\'" }, +{ "ER_BINLOG_PURGE_EMFILE", 1587, "Too many files opened, please execute the command again" }, +{ "ER_EVENT_CANNOT_CREATE_IN_THE_PAST", 1588, "Event execution time is in the past and ON COMPLETION NOT PRESERVE is set. The event was dropped immediately after creation." }, +{ "ER_EVENT_CANNOT_ALTER_IN_THE_PAST", 1589, "Event execution time is in the past and ON COMPLETION NOT PRESERVE is set. The event was dropped immediately after creation." }, +{ "ER_SLAVE_INCIDENT", 1590, "The incident %s occured on the master. Message: %-.64s" }, +{ "ER_NO_PARTITION_FOR_GIVEN_VALUE_SILENT", 1591, "Table has no partition for some existing values" }, +{ "ER_BINLOG_UNSAFE_STATEMENT", 1592, "Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. %s" }, +{ "ER_SLAVE_FATAL_ERROR", 1593, "Fatal error: %s" }, +{ "ER_SLAVE_RELAY_LOG_READ_FAILURE", 1594, "Relay log read failure: %s" }, +{ "ER_SLAVE_RELAY_LOG_WRITE_FAILURE", 1595, "Relay log write failure: %s" }, +{ "ER_SLAVE_CREATE_EVENT_FAILURE", 1596, "Failed to create %s" }, +{ "ER_SLAVE_MASTER_COM_FAILURE", 1597, "Master command %s failed: %s" }, +{ "ER_BINLOG_LOGGING_IMPOSSIBLE", 1598, "Binary logging not possible. Message: %s" }, +{ "ER_VIEW_NO_CREATION_CTX", 1599, "View `%-.64s`.`%-.64s` has no creation context" }, +{ "ER_VIEW_INVALID_CREATION_CTX", 1600, "Creation context of view `%-.64s`.`%-.64s\' is invalid" }, +{ "ER_SR_INVALID_CREATION_CTX", 1601, "Creation context of stored routine `%-.64s`.`%-.64s` is invalid" }, +{ "ER_TRG_CORRUPTED_FILE", 1602, "Corrupted TRG file for table `%-.64s`.`%-.64s`" }, +{ "ER_TRG_NO_CREATION_CTX", 1603, "Triggers for table `%-.64s`.`%-.64s` have no creation context" }, +{ "ER_TRG_INVALID_CREATION_CTX", 1604, "Trigger creation context of table `%-.64s`.`%-.64s` is invalid" }, +{ "ER_EVENT_INVALID_CREATION_CTX", 1605, "Creation context of event `%-.64s`.`%-.64s` is invalid" }, +{ "ER_TRG_CANT_OPEN_TABLE", 1606, "Cannot open table for trigger `%-.64s`.`%-.64s`" }, +{ "ER_CANT_CREATE_SROUTINE", 1607, "Cannot create stored routine `%-.64s`. Check warnings" }, +{ "ER_NEVER_USED", 1608, "Ambiguous slave modes combination. %s" }, +{ "ER_NO_FORMAT_DESCRIPTION_EVENT_BEFORE_BINLOG_STATEMENT", 1609, "The BINLOG statement of type `%s` was not preceded by a format description BINLOG statement." }, +{ "ER_SLAVE_CORRUPT_EVENT", 1610, "Corrupted replication event was detected" }, +{ "ER_LOAD_DATA_INVALID_COLUMN", 1611, "Invalid column reference (%-.64s) in LOAD DATA" }, +{ "ER_LOG_PURGE_NO_FILE", 1612, "Being purged log %s was not found" }, +{ "ER_XA_RBTIMEOUT", 1613, "XA_RBTIMEOUT: Transaction branch was rolled back: took too long" }, +{ "ER_XA_RBDEADLOCK", 1614, "XA_RBDEADLOCK: Transaction branch was rolled back: deadlock was detected" }, +{ "ER_NEED_REPREPARE", 1615, "Prepared statement needs to be re-prepared" }, +{ "ER_DELAYED_NOT_SUPPORTED", 1616, "DELAYED option not supported for table \'%-.192s\'" }, +{ "WARN_NO_MASTER_INFO", 1617, "The master info structure does not exist" }, +{ "WARN_OPTION_IGNORED", 1618, "<%-.64s> option ignored" }, +{ "WARN_PLUGIN_DELETE_BUILTIN", 1619, "Built-in plugins cannot be deleted" }, +{ "WARN_PLUGIN_BUSY", 1620, "Plugin is busy and will be uninstalled on shutdown" }, +{ "ER_VARIABLE_IS_READONLY", 1621, "%s variable \'%s\' is read-only. Use SET %s to assign the value" }, +{ "ER_WARN_ENGINE_TRANSACTION_ROLLBACK", 1622, "Storage engine %s does not support rollback for this statement. Transaction rolled back and must be restarted" }, +{ "ER_SLAVE_HEARTBEAT_FAILURE", 1623, "Unexpected master\'s heartbeat data: %s" }, +{ "ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE", 1624, "The requested value for the heartbeat period is either negative or exceeds the maximum allowed (%s seconds)." }, +{ "ER_NDB_REPLICATION_SCHEMA_ERROR", 1625, "Bad schema for mysql.ndb_replication table. Message: %-.64s" }, +{ "ER_CONFLICT_FN_PARSE_ERROR", 1626, "Error in parsing conflict function. Message: %-.64s" }, +{ "ER_EXCEPTIONS_WRITE_ERROR", 1627, "Write to exceptions table failed. Message: %-.128s\"" }, +{ "ER_TOO_LONG_TABLE_COMMENT", 1628, "Comment for table \'%-.64s\' is too long (max = %lu)" }, +{ "ER_TOO_LONG_FIELD_COMMENT", 1629, "Comment for field \'%-.64s\' is too long (max = %lu)" }, +{ "ER_FUNC_INEXISTENT_NAME_COLLISION", 1630, "FUNCTION %s does not exist. Check the \'Function Name Parsing and Resolution\' section in the Reference Manual" }, +{ "ER_DATABASE_NAME", 1631, "Database" }, +{ "ER_TABLE_NAME", 1632, "Table" }, +{ "ER_PARTITION_NAME", 1633, "Partition" }, +{ "ER_SUBPARTITION_NAME", 1634, "Subpartition" }, +{ "ER_TEMPORARY_NAME", 1635, "Temporary" }, +{ "ER_RENAMED_NAME", 1636, "Renamed" }, +{ "ER_TOO_MANY_CONCURRENT_TRXS", 1637, "Too many active concurrent transactions" }, +{ "WARN_NON_ASCII_SEPARATOR_NOT_IMPLEMENTED", 1638, "Non-ASCII separator arguments are not fully supported" }, +{ "ER_DEBUG_SYNC_TIMEOUT", 1639, "debug sync point wait timed out" }, +{ "ER_DEBUG_SYNC_HIT_LIMIT", 1640, "debug sync point hit limit reached" }, +{ "ER_DUP_SIGNAL_SET", 1641, "Duplicate condition information item \'%s\'" }, +{ "ER_SIGNAL_WARN", 1642, "Unhandled user-defined warning condition" }, +{ "ER_SIGNAL_NOT_FOUND", 1643, "Unhandled user-defined not found condition" }, +{ "ER_SIGNAL_EXCEPTION", 1644, "Unhandled user-defined exception condition" }, +{ "ER_RESIGNAL_WITHOUT_ACTIVE_HANDLER", 1645, "RESIGNAL when handler not active" }, +{ "ER_SIGNAL_BAD_CONDITION_TYPE", 1646, "SIGNAL/RESIGNAL can only use a CONDITION defined with SQLSTATE" }, +{ "WARN_COND_ITEM_TRUNCATED", 1647, "Data truncated for condition item \'%s\'" }, +{ "ER_COND_ITEM_TOO_LONG", 1648, "Data too long for condition item \'%s\'" }, +{ "ER_UNKNOWN_LOCALE", 1649, "Unknown locale: \'%-.64s\'" }, +{ "ER_SLAVE_IGNORE_SERVER_IDS", 1650, "The requested server id %d clashes with the slave startup option --replicate-same-server-id" }, +{ "ER_QUERY_CACHE_DISABLED", 1651, "Query cache is disabled; restart the server with query_cache_type=1 to enable it" }, +{ "ER_SAME_NAME_PARTITION_FIELD", 1652, "Duplicate partition field name \'%-.192s\'" }, +{ "ER_PARTITION_COLUMN_LIST_ERROR", 1653, "Inconsistency in usage of column lists for partitioning" }, +{ "ER_WRONG_TYPE_COLUMN_VALUE_ERROR", 1654, "Partition column values of incorrect type" }, +{ "ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR", 1655, "Too many fields in \'%-.192s\'" }, +{ "ER_MAXVALUE_IN_VALUES_IN", 1656, "Cannot use MAXVALUE as value in VALUES IN" }, +{ "ER_TOO_MANY_VALUES_ERROR", 1657, "Cannot have more than one value for this type of %-.64s partitioning" }, +{ "ER_ROW_SINGLE_PARTITION_FIELD_ERROR", 1658, "Row expressions in VALUES IN only allowed for multi-field column partitioning" }, +{ "ER_FIELD_TYPE_NOT_ALLOWED_AS_PARTITION_FIELD", 1659, "Field \'%-.192s\' is of a not allowed type for this type of partitioning" }, +{ "ER_PARTITION_FIELDS_TOO_LONG", 1660, "The total length of the partitioning fields is too large" }, +{ "ER_BINLOG_ROW_ENGINE_AND_STMT_ENGINE", 1661, "Cannot execute statement: impossible to write to binary log since both row-incapable engines and statement-incapable engines are involved." }, +{ "ER_BINLOG_ROW_MODE_AND_STMT_ENGINE", 1662, "Cannot execute statement: impossible to write to binary log since BINLOG_FORMAT = ROW and at least one table uses a storage engine limited to statement-based logging." }, +{ "ER_BINLOG_UNSAFE_AND_STMT_ENGINE", 1663, "Cannot execute statement: impossible to write to binary log since statement is unsafe, storage engine is limited to statement-based logging, and BINLOG_FORMAT = MIXED. %s" }, +{ "ER_BINLOG_ROW_INJECTION_AND_STMT_ENGINE", 1664, "Cannot execute statement: impossible to write to binary log since statement is in row format and at least one table uses a storage engine limited to statement-based logging." }, +{ "ER_BINLOG_STMT_MODE_AND_ROW_ENGINE", 1665, "Cannot execute statement: impossible to write to binary log since BINLOG_FORMAT = STATEMENT and at least one table uses a storage engine limited to row-based logging.%s" }, +{ "ER_BINLOG_ROW_INJECTION_AND_STMT_MODE", 1666, "Cannot execute statement: impossible to write to binary log since statement is in row format and BINLOG_FORMAT = STATEMENT." }, +{ "ER_BINLOG_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE", 1667, "Cannot execute statement: impossible to write to binary log since more than one engine is involved and at least one engine is self-logging." }, +{ "ER_BINLOG_UNSAFE_LIMIT", 1668, "The statement is unsafe because it uses a LIMIT clause. This is unsafe because the set of rows included cannot be predicted." }, +{ "ER_BINLOG_UNSAFE_INSERT_DELAYED", 1669, "The statement is unsafe because it uses INSERT DELAYED. This is unsafe because the times when rows are inserted cannot be predicted." }, +{ "ER_BINLOG_UNSAFE_SYSTEM_TABLE", 1670, "The statement is unsafe because it uses the general log, slow query log, or performance_schema table(s). This is unsafe because system tables may differ on slaves." }, +{ "ER_BINLOG_UNSAFE_AUTOINC_COLUMNS", 1671, "Statement is unsafe because it invokes a trigger or a stored function that inserts into an AUTO_INCREMENT column. Inserted values cannot be logged correctly." }, +{ "ER_BINLOG_UNSAFE_UDF", 1672, "Statement is unsafe because it uses a UDF which may not return the same value on the slave." }, +{ "ER_BINLOG_UNSAFE_SYSTEM_VARIABLE", 1673, "Statement is unsafe because it uses a system variable that may have a different value on the slave." }, +{ "ER_BINLOG_UNSAFE_SYSTEM_FUNCTION", 1674, "Statement is unsafe because it uses a system function that may return a different value on the slave." }, +{ "ER_BINLOG_UNSAFE_NONTRANS_AFTER_TRANS", 1675, "Statement is unsafe because it accesses a non-transactional table after accessing a transactional table within the same transaction." }, +{ "ER_MESSAGE_AND_STATEMENT", 1676, "%s Statement: %s" }, +{ "ER_SLAVE_CONVERSION_FAILED", 1677, "Column %d of table \'%-.192s.%-.192s\' cannot be converted from type \'%-.32s\' to type \'%-.32s\'" }, +{ "ER_SLAVE_CANT_CREATE_CONVERSION", 1678, "Can\'t create conversion table for table \'%-.192s.%-.192s\'" }, +{ "ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_FORMAT", 1679, "Cannot modify @@session.binlog_format inside a transaction" }, +{ "ER_PATH_LENGTH", 1680, "The path specified for %.64s is too long." }, +{ "ER_WARN_DEPRECATED_SYNTAX_NO_REPLACEMENT", 1681, "The syntax \'%s\' is deprecated and will be removed in MySQL %s." }, +{ "ER_WRONG_NATIVE_TABLE_STRUCTURE", 1682, "Native table \'%-.64s\'.\'%-.64s\' has the wrong structure" }, +{ "ER_WRONG_PERFSCHEMA_USAGE", 1683, "Invalid performance_schema usage." }, +{ "ER_WARN_I_S_SKIPPED_TABLE", 1684, "Table \'%s\'.\'%s\' was skipped since its definition is being modified by concurrent DDL statement" }, +{ "ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_DIRECT", 1685, "Cannot modify @@session.binlog_direct_non_transactional_updates inside a transaction" }, +{ "ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_DIRECT", 1686, "Cannot change the binlog direct flag inside a stored function or trigger" }, +{ "ER_SPATIAL_MUST_HAVE_GEOM_COL", 1687, "A SPATIAL index may only contain a geometrical type column" }, +{ "ER_TOO_LONG_INDEX_COMMENT", 1688, "Comment for index \'%-.64s\' is too long (max = %lu)" }, +{ "ER_LOCK_ABORTED", 1689, "Wait on a lock was aborted due to a pending exclusive lock" }, +{ "ER_DATA_OUT_OF_RANGE", 1690, "%s value is out of range in \'%s\'" }, +{ "ER_WRONG_SPVAR_TYPE_IN_LIMIT", 1691, "A variable of a non-integer type in LIMIT clause" }, +{ "ER_BINLOG_UNSAFE_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE", 1692, "Mixing self-logging and non-self-logging engines in a statement is unsafe." }, +{ "ER_BINLOG_UNSAFE_MIXED_STATEMENT", 1693, "Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them." }, +{ "ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_SQL_LOG_BIN", 1694, "Cannot modify @@session.sql_log_bin inside a transaction" }, +{ "ER_STORED_FUNCTION_PREVENTS_SWITCH_SQL_LOG_BIN", 1695, "Cannot change the sql_log_bin inside a stored function or trigger" }, +{ "ER_FAILED_READ_FROM_PAR_FILE", 1696, "Failed to read from the .par file" }, +{ "ER_VALUES_IS_NOT_INT_TYPE_ERROR", 1697, "VALUES value for partition \'%-.64s\' must have type INT" }, +{ "ER_ACCESS_DENIED_NO_PASSWORD_ERROR", 1698, "Access denied for user \'%-.48s\'@\'%-.64s\'" }, +{ "ER_SET_PASSWORD_AUTH_PLUGIN", 1699, "SET PASSWORD has no significance for users authenticating via plugins" }, +{ "ER_GRANT_PLUGIN_USER_EXISTS", 1700, "GRANT with IDENTIFIED WITH is illegal because the user %-.*s already exists" }, +{ "ER_TRUNCATE_ILLEGAL_FK", 1701, "Cannot truncate a table referenced in a foreign key constraint (%.192s)" }, +{ "ER_PLUGIN_IS_PERMANENT", 1702, "Plugin \'%s\' is force_plus_permanent and can not be unloaded" }, +{ "ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MIN", 1703, "The requested value for the heartbeat period is less than 1 millisecond. The value is reset to 0, meaning that heartbeating will effectively be disabled." }, +{ "ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MAX", 1704, "The requested value for the heartbeat period exceeds the value of `slave_net_timeout\' seconds. A sensible value for the period should be less than the timeout." }, diff --git a/include/mysql/mysqld_error.h b/include/mysql/mysqld_error.h new file mode 100644 index 000000000..533bf9d1f --- /dev/null +++ b/include/mysql/mysqld_error.h @@ -0,0 +1,709 @@ +/* Autogenerated file, please don't edit */ + +#define ER_ERROR_FIRST 1000 +#define ER_HASHCHK 1000 +#define ER_NISAMCHK 1001 +#define ER_NO 1002 +#define ER_YES 1003 +#define ER_CANT_CREATE_FILE 1004 +#define ER_CANT_CREATE_TABLE 1005 +#define ER_CANT_CREATE_DB 1006 +#define ER_DB_CREATE_EXISTS 1007 +#define ER_DB_DROP_EXISTS 1008 +#define ER_DB_DROP_DELETE 1009 +#define ER_DB_DROP_RMDIR 1010 +#define ER_CANT_DELETE_FILE 1011 +#define ER_CANT_FIND_SYSTEM_REC 1012 +#define ER_CANT_GET_STAT 1013 +#define ER_CANT_GET_WD 1014 +#define ER_CANT_LOCK 1015 +#define ER_CANT_OPEN_FILE 1016 +#define ER_FILE_NOT_FOUND 1017 +#define ER_CANT_READ_DIR 1018 +#define ER_CANT_SET_WD 1019 +#define ER_CHECKREAD 1020 +#define ER_DISK_FULL 1021 +#define ER_DUP_KEY 1022 +#define ER_ERROR_ON_CLOSE 1023 +#define ER_ERROR_ON_READ 1024 +#define ER_ERROR_ON_RENAME 1025 +#define ER_ERROR_ON_WRITE 1026 +#define ER_FILE_USED 1027 +#define ER_FILSORT_ABORT 1028 +#define ER_FORM_NOT_FOUND 1029 +#define ER_GET_ERRNO 1030 +#define ER_ILLEGAL_HA 1031 +#define ER_KEY_NOT_FOUND 1032 +#define ER_NOT_FORM_FILE 1033 +#define ER_NOT_KEYFILE 1034 +#define ER_OLD_KEYFILE 1035 +#define ER_OPEN_AS_READONLY 1036 +#define ER_OUTOFMEMORY 1037 +#define ER_OUT_OF_SORTMEMORY 1038 +#define ER_UNEXPECTED_EOF 1039 +#define ER_CON_COUNT_ERROR 1040 +#define ER_OUT_OF_RESOURCES 1041 +#define ER_BAD_HOST_ERROR 1042 +#define ER_HANDSHAKE_ERROR 1043 +#define ER_DBACCESS_DENIED_ERROR 1044 +#define ER_ACCESS_DENIED_ERROR 1045 +#define ER_NO_DB_ERROR 1046 +#define ER_UNKNOWN_COM_ERROR 1047 +#define ER_BAD_NULL_ERROR 1048 +#define ER_BAD_DB_ERROR 1049 +#define ER_TABLE_EXISTS_ERROR 1050 +#define ER_BAD_TABLE_ERROR 1051 +#define ER_NON_UNIQ_ERROR 1052 +#define ER_SERVER_SHUTDOWN 1053 +#define ER_BAD_FIELD_ERROR 1054 +#define ER_WRONG_FIELD_WITH_GROUP 1055 +#define ER_WRONG_GROUP_FIELD 1056 +#define ER_WRONG_SUM_SELECT 1057 +#define ER_WRONG_VALUE_COUNT 1058 +#define ER_TOO_LONG_IDENT 1059 +#define ER_DUP_FIELDNAME 1060 +#define ER_DUP_KEYNAME 1061 +#define ER_DUP_ENTRY 1062 +#define ER_WRONG_FIELD_SPEC 1063 +#define ER_PARSE_ERROR 1064 +#define ER_EMPTY_QUERY 1065 +#define ER_NONUNIQ_TABLE 1066 +#define ER_INVALID_DEFAULT 1067 +#define ER_MULTIPLE_PRI_KEY 1068 +#define ER_TOO_MANY_KEYS 1069 +#define ER_TOO_MANY_KEY_PARTS 1070 +#define ER_TOO_LONG_KEY 1071 +#define ER_KEY_COLUMN_DOES_NOT_EXITS 1072 +#define ER_BLOB_USED_AS_KEY 1073 +#define ER_TOO_BIG_FIELDLENGTH 1074 +#define ER_WRONG_AUTO_KEY 1075 +#define ER_READY 1076 +#define ER_NORMAL_SHUTDOWN 1077 +#define ER_GOT_SIGNAL 1078 +#define ER_SHUTDOWN_COMPLETE 1079 +#define ER_FORCING_CLOSE 1080 +#define ER_IPSOCK_ERROR 1081 +#define ER_NO_SUCH_INDEX 1082 +#define ER_WRONG_FIELD_TERMINATORS 1083 +#define ER_BLOBS_AND_NO_TERMINATED 1084 +#define ER_TEXTFILE_NOT_READABLE 1085 +#define ER_FILE_EXISTS_ERROR 1086 +#define ER_LOAD_INFO 1087 +#define ER_ALTER_INFO 1088 +#define ER_WRONG_SUB_KEY 1089 +#define ER_CANT_REMOVE_ALL_FIELDS 1090 +#define ER_CANT_DROP_FIELD_OR_KEY 1091 +#define ER_INSERT_INFO 1092 +#define ER_UPDATE_TABLE_USED 1093 +#define ER_NO_SUCH_THREAD 1094 +#define ER_KILL_DENIED_ERROR 1095 +#define ER_NO_TABLES_USED 1096 +#define ER_TOO_BIG_SET 1097 +#define ER_NO_UNIQUE_LOGFILE 1098 +#define ER_TABLE_NOT_LOCKED_FOR_WRITE 1099 +#define ER_TABLE_NOT_LOCKED 1100 +#define ER_BLOB_CANT_HAVE_DEFAULT 1101 +#define ER_WRONG_DB_NAME 1102 +#define ER_WRONG_TABLE_NAME 1103 +#define ER_TOO_BIG_SELECT 1104 +#define ER_UNKNOWN_ERROR 1105 +#define ER_UNKNOWN_PROCEDURE 1106 +#define ER_WRONG_PARAMCOUNT_TO_PROCEDURE 1107 +#define ER_WRONG_PARAMETERS_TO_PROCEDURE 1108 +#define ER_UNKNOWN_TABLE 1109 +#define ER_FIELD_SPECIFIED_TWICE 1110 +#define ER_INVALID_GROUP_FUNC_USE 1111 +#define ER_UNSUPPORTED_EXTENSION 1112 +#define ER_TABLE_MUST_HAVE_COLUMNS 1113 +#define ER_RECORD_FILE_FULL 1114 +#define ER_UNKNOWN_CHARACTER_SET 1115 +#define ER_TOO_MANY_TABLES 1116 +#define ER_TOO_MANY_FIELDS 1117 +#define ER_TOO_BIG_ROWSIZE 1118 +#define ER_STACK_OVERRUN 1119 +#define ER_WRONG_OUTER_JOIN 1120 +#define ER_NULL_COLUMN_IN_INDEX 1121 +#define ER_CANT_FIND_UDF 1122 +#define ER_CANT_INITIALIZE_UDF 1123 +#define ER_UDF_NO_PATHS 1124 +#define ER_UDF_EXISTS 1125 +#define ER_CANT_OPEN_LIBRARY 1126 +#define ER_CANT_FIND_DL_ENTRY 1127 +#define ER_FUNCTION_NOT_DEFINED 1128 +#define ER_HOST_IS_BLOCKED 1129 +#define ER_HOST_NOT_PRIVILEGED 1130 +#define ER_PASSWORD_ANONYMOUS_USER 1131 +#define ER_PASSWORD_NOT_ALLOWED 1132 +#define ER_PASSWORD_NO_MATCH 1133 +#define ER_UPDATE_INFO 1134 +#define ER_CANT_CREATE_THREAD 1135 +#define ER_WRONG_VALUE_COUNT_ON_ROW 1136 +#define ER_CANT_REOPEN_TABLE 1137 +#define ER_INVALID_USE_OF_NULL 1138 +#define ER_REGEXP_ERROR 1139 +#define ER_MIX_OF_GROUP_FUNC_AND_FIELDS 1140 +#define ER_NONEXISTING_GRANT 1141 +#define ER_TABLEACCESS_DENIED_ERROR 1142 +#define ER_COLUMNACCESS_DENIED_ERROR 1143 +#define ER_ILLEGAL_GRANT_FOR_TABLE 1144 +#define ER_GRANT_WRONG_HOST_OR_USER 1145 +#define ER_NO_SUCH_TABLE 1146 +#define ER_NONEXISTING_TABLE_GRANT 1147 +#define ER_NOT_ALLOWED_COMMAND 1148 +#define ER_SYNTAX_ERROR 1149 +#define ER_DELAYED_CANT_CHANGE_LOCK 1150 +#define ER_TOO_MANY_DELAYED_THREADS 1151 +#define ER_ABORTING_CONNECTION 1152 +#define ER_NET_PACKET_TOO_LARGE 1153 +#define ER_NET_READ_ERROR_FROM_PIPE 1154 +#define ER_NET_FCNTL_ERROR 1155 +#define ER_NET_PACKETS_OUT_OF_ORDER 1156 +#define ER_NET_UNCOMPRESS_ERROR 1157 +#define ER_NET_READ_ERROR 1158 +#define ER_NET_READ_INTERRUPTED 1159 +#define ER_NET_ERROR_ON_WRITE 1160 +#define ER_NET_WRITE_INTERRUPTED 1161 +#define ER_TOO_LONG_STRING 1162 +#define ER_TABLE_CANT_HANDLE_BLOB 1163 +#define ER_TABLE_CANT_HANDLE_AUTO_INCREMENT 1164 +#define ER_DELAYED_INSERT_TABLE_LOCKED 1165 +#define ER_WRONG_COLUMN_NAME 1166 +#define ER_WRONG_KEY_COLUMN 1167 +#define ER_WRONG_MRG_TABLE 1168 +#define ER_DUP_UNIQUE 1169 +#define ER_BLOB_KEY_WITHOUT_LENGTH 1170 +#define ER_PRIMARY_CANT_HAVE_NULL 1171 +#define ER_TOO_MANY_ROWS 1172 +#define ER_REQUIRES_PRIMARY_KEY 1173 +#define ER_NO_RAID_COMPILED 1174 +#define ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE 1175 +#define ER_KEY_DOES_NOT_EXITS 1176 +#define ER_CHECK_NO_SUCH_TABLE 1177 +#define ER_CHECK_NOT_IMPLEMENTED 1178 +#define ER_CANT_DO_THIS_DURING_AN_TRANSACTION 1179 +#define ER_ERROR_DURING_COMMIT 1180 +#define ER_ERROR_DURING_ROLLBACK 1181 +#define ER_ERROR_DURING_FLUSH_LOGS 1182 +#define ER_ERROR_DURING_CHECKPOINT 1183 +#define ER_NEW_ABORTING_CONNECTION 1184 +#define ER_DUMP_NOT_IMPLEMENTED 1185 +#define ER_FLUSH_MASTER_BINLOG_CLOSED 1186 +#define ER_INDEX_REBUILD 1187 +#define ER_MASTER 1188 +#define ER_MASTER_NET_READ 1189 +#define ER_MASTER_NET_WRITE 1190 +#define ER_FT_MATCHING_KEY_NOT_FOUND 1191 +#define ER_LOCK_OR_ACTIVE_TRANSACTION 1192 +#define ER_UNKNOWN_SYSTEM_VARIABLE 1193 +#define ER_CRASHED_ON_USAGE 1194 +#define ER_CRASHED_ON_REPAIR 1195 +#define ER_WARNING_NOT_COMPLETE_ROLLBACK 1196 +#define ER_TRANS_CACHE_FULL 1197 +#define ER_SLAVE_MUST_STOP 1198 +#define ER_SLAVE_NOT_RUNNING 1199 +#define ER_BAD_SLAVE 1200 +#define ER_MASTER_INFO 1201 +#define ER_SLAVE_THREAD 1202 +#define ER_TOO_MANY_USER_CONNECTIONS 1203 +#define ER_SET_CONSTANTS_ONLY 1204 +#define ER_LOCK_WAIT_TIMEOUT 1205 +#define ER_LOCK_TABLE_FULL 1206 +#define ER_READ_ONLY_TRANSACTION 1207 +#define ER_DROP_DB_WITH_READ_LOCK 1208 +#define ER_CREATE_DB_WITH_READ_LOCK 1209 +#define ER_WRONG_ARGUMENTS 1210 +#define ER_NO_PERMISSION_TO_CREATE_USER 1211 +#define ER_UNION_TABLES_IN_DIFFERENT_DIR 1212 +#define ER_LOCK_DEADLOCK 1213 +#define ER_TABLE_CANT_HANDLE_FT 1214 +#define ER_CANNOT_ADD_FOREIGN 1215 +#define ER_NO_REFERENCED_ROW 1216 +#define ER_ROW_IS_REFERENCED 1217 +#define ER_CONNECT_TO_MASTER 1218 +#define ER_QUERY_ON_MASTER 1219 +#define ER_ERROR_WHEN_EXECUTING_COMMAND 1220 +#define ER_WRONG_USAGE 1221 +#define ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT 1222 +#define ER_CANT_UPDATE_WITH_READLOCK 1223 +#define ER_MIXING_NOT_ALLOWED 1224 +#define ER_DUP_ARGUMENT 1225 +#define ER_USER_LIMIT_REACHED 1226 +#define ER_SPECIFIC_ACCESS_DENIED_ERROR 1227 +#define ER_LOCAL_VARIABLE 1228 +#define ER_GLOBAL_VARIABLE 1229 +#define ER_NO_DEFAULT 1230 +#define ER_WRONG_VALUE_FOR_VAR 1231 +#define ER_WRONG_TYPE_FOR_VAR 1232 +#define ER_VAR_CANT_BE_READ 1233 +#define ER_CANT_USE_OPTION_HERE 1234 +#define ER_NOT_SUPPORTED_YET 1235 +#define ER_MASTER_FATAL_ERROR_READING_BINLOG 1236 +#define ER_SLAVE_IGNORED_TABLE 1237 +#define ER_INCORRECT_GLOBAL_LOCAL_VAR 1238 +#define ER_WRONG_FK_DEF 1239 +#define ER_KEY_REF_DO_NOT_MATCH_TABLE_REF 1240 +#define ER_OPERAND_COLUMNS 1241 +#define ER_SUBQUERY_NO_1_ROW 1242 +#define ER_UNKNOWN_STMT_HANDLER 1243 +#define ER_CORRUPT_HELP_DB 1244 +#define ER_CYCLIC_REFERENCE 1245 +#define ER_AUTO_CONVERT 1246 +#define ER_ILLEGAL_REFERENCE 1247 +#define ER_DERIVED_MUST_HAVE_ALIAS 1248 +#define ER_SELECT_REDUCED 1249 +#define ER_TABLENAME_NOT_ALLOWED_HERE 1250 +#define ER_NOT_SUPPORTED_AUTH_MODE 1251 +#define ER_SPATIAL_CANT_HAVE_NULL 1252 +#define ER_COLLATION_CHARSET_MISMATCH 1253 +#define ER_SLAVE_WAS_RUNNING 1254 +#define ER_SLAVE_WAS_NOT_RUNNING 1255 +#define ER_TOO_BIG_FOR_UNCOMPRESS 1256 +#define ER_ZLIB_Z_MEM_ERROR 1257 +#define ER_ZLIB_Z_BUF_ERROR 1258 +#define ER_ZLIB_Z_DATA_ERROR 1259 +#define ER_CUT_VALUE_GROUP_CONCAT 1260 +#define ER_WARN_TOO_FEW_RECORDS 1261 +#define ER_WARN_TOO_MANY_RECORDS 1262 +#define ER_WARN_NULL_TO_NOTNULL 1263 +#define ER_WARN_DATA_OUT_OF_RANGE 1264 +#define WARN_DATA_TRUNCATED 1265 +#define ER_WARN_USING_OTHER_HANDLER 1266 +#define ER_CANT_AGGREGATE_2COLLATIONS 1267 +#define ER_DROP_USER 1268 +#define ER_REVOKE_GRANTS 1269 +#define ER_CANT_AGGREGATE_3COLLATIONS 1270 +#define ER_CANT_AGGREGATE_NCOLLATIONS 1271 +#define ER_VARIABLE_IS_NOT_STRUCT 1272 +#define ER_UNKNOWN_COLLATION 1273 +#define ER_SLAVE_IGNORED_SSL_PARAMS 1274 +#define ER_SERVER_IS_IN_SECURE_AUTH_MODE 1275 +#define ER_WARN_FIELD_RESOLVED 1276 +#define ER_BAD_SLAVE_UNTIL_COND 1277 +#define ER_MISSING_SKIP_SLAVE 1278 +#define ER_UNTIL_COND_IGNORED 1279 +#define ER_WRONG_NAME_FOR_INDEX 1280 +#define ER_WRONG_NAME_FOR_CATALOG 1281 +#define ER_WARN_QC_RESIZE 1282 +#define ER_BAD_FT_COLUMN 1283 +#define ER_UNKNOWN_KEY_CACHE 1284 +#define ER_WARN_HOSTNAME_WONT_WORK 1285 +#define ER_UNKNOWN_STORAGE_ENGINE 1286 +#define ER_WARN_DEPRECATED_SYNTAX 1287 +#define ER_NON_UPDATABLE_TABLE 1288 +#define ER_FEATURE_DISABLED 1289 +#define ER_OPTION_PREVENTS_STATEMENT 1290 +#define ER_DUPLICATED_VALUE_IN_TYPE 1291 +#define ER_TRUNCATED_WRONG_VALUE 1292 +#define ER_TOO_MUCH_AUTO_TIMESTAMP_COLS 1293 +#define ER_INVALID_ON_UPDATE 1294 +#define ER_UNSUPPORTED_PS 1295 +#define ER_GET_ERRMSG 1296 +#define ER_GET_TEMPORARY_ERRMSG 1297 +#define ER_UNKNOWN_TIME_ZONE 1298 +#define ER_WARN_INVALID_TIMESTAMP 1299 +#define ER_INVALID_CHARACTER_STRING 1300 +#define ER_WARN_ALLOWED_PACKET_OVERFLOWED 1301 +#define ER_CONFLICTING_DECLARATIONS 1302 +#define ER_SP_NO_RECURSIVE_CREATE 1303 +#define ER_SP_ALREADY_EXISTS 1304 +#define ER_SP_DOES_NOT_EXIST 1305 +#define ER_SP_DROP_FAILED 1306 +#define ER_SP_STORE_FAILED 1307 +#define ER_SP_LILABEL_MISMATCH 1308 +#define ER_SP_LABEL_REDEFINE 1309 +#define ER_SP_LABEL_MISMATCH 1310 +#define ER_SP_UNINIT_VAR 1311 +#define ER_SP_BADSELECT 1312 +#define ER_SP_BADRETURN 1313 +#define ER_SP_BADSTATEMENT 1314 +#define ER_UPDATE_LOG_DEPRECATED_IGNORED 1315 +#define ER_UPDATE_LOG_DEPRECATED_TRANSLATED 1316 +#define ER_QUERY_INTERRUPTED 1317 +#define ER_SP_WRONG_NO_OF_ARGS 1318 +#define ER_SP_COND_MISMATCH 1319 +#define ER_SP_NORETURN 1320 +#define ER_SP_NORETURNEND 1321 +#define ER_SP_BAD_CURSOR_QUERY 1322 +#define ER_SP_BAD_CURSOR_SELECT 1323 +#define ER_SP_CURSOR_MISMATCH 1324 +#define ER_SP_CURSOR_ALREADY_OPEN 1325 +#define ER_SP_CURSOR_NOT_OPEN 1326 +#define ER_SP_UNDECLARED_VAR 1327 +#define ER_SP_WRONG_NO_OF_FETCH_ARGS 1328 +#define ER_SP_FETCH_NO_DATA 1329 +#define ER_SP_DUP_PARAM 1330 +#define ER_SP_DUP_VAR 1331 +#define ER_SP_DUP_COND 1332 +#define ER_SP_DUP_CURS 1333 +#define ER_SP_CANT_ALTER 1334 +#define ER_SP_SUBSELECT_NYI 1335 +#define ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG 1336 +#define ER_SP_VARCOND_AFTER_CURSHNDLR 1337 +#define ER_SP_CURSOR_AFTER_HANDLER 1338 +#define ER_SP_CASE_NOT_FOUND 1339 +#define ER_FPARSER_TOO_BIG_FILE 1340 +#define ER_FPARSER_BAD_HEADER 1341 +#define ER_FPARSER_EOF_IN_COMMENT 1342 +#define ER_FPARSER_ERROR_IN_PARAMETER 1343 +#define ER_FPARSER_EOF_IN_UNKNOWN_PARAMETER 1344 +#define ER_VIEW_NO_EXPLAIN 1345 +#define ER_FRM_UNKNOWN_TYPE 1346 +#define ER_WRONG_OBJECT 1347 +#define ER_NONUPDATEABLE_COLUMN 1348 +#define ER_VIEW_SELECT_DERIVED 1349 +#define ER_VIEW_SELECT_CLAUSE 1350 +#define ER_VIEW_SELECT_VARIABLE 1351 +#define ER_VIEW_SELECT_TMPTABLE 1352 +#define ER_VIEW_WRONG_LIST 1353 +#define ER_WARN_VIEW_MERGE 1354 +#define ER_WARN_VIEW_WITHOUT_KEY 1355 +#define ER_VIEW_INVALID 1356 +#define ER_SP_NO_DROP_SP 1357 +#define ER_SP_GOTO_IN_HNDLR 1358 +#define ER_TRG_ALREADY_EXISTS 1359 +#define ER_TRG_DOES_NOT_EXIST 1360 +#define ER_TRG_ON_VIEW_OR_TEMP_TABLE 1361 +#define ER_TRG_CANT_CHANGE_ROW 1362 +#define ER_TRG_NO_SUCH_ROW_IN_TRG 1363 +#define ER_NO_DEFAULT_FOR_FIELD 1364 +#define ER_DIVISION_BY_ZERO 1365 +#define ER_TRUNCATED_WRONG_VALUE_FOR_FIELD 1366 +#define ER_ILLEGAL_VALUE_FOR_TYPE 1367 +#define ER_VIEW_NONUPD_CHECK 1368 +#define ER_VIEW_CHECK_FAILED 1369 +#define ER_PROCACCESS_DENIED_ERROR 1370 +#define ER_RELAY_LOG_FAIL 1371 +#define ER_PASSWD_LENGTH 1372 +#define ER_UNKNOWN_TARGET_BINLOG 1373 +#define ER_IO_ERR_LOG_INDEX_READ 1374 +#define ER_BINLOG_PURGE_PROHIBITED 1375 +#define ER_FSEEK_FAIL 1376 +#define ER_BINLOG_PURGE_FATAL_ERR 1377 +#define ER_LOG_IN_USE 1378 +#define ER_LOG_PURGE_UNKNOWN_ERR 1379 +#define ER_RELAY_LOG_INIT 1380 +#define ER_NO_BINARY_LOGGING 1381 +#define ER_RESERVED_SYNTAX 1382 +#define ER_WSAS_FAILED 1383 +#define ER_DIFF_GROUPS_PROC 1384 +#define ER_NO_GROUP_FOR_PROC 1385 +#define ER_ORDER_WITH_PROC 1386 +#define ER_LOGGING_PROHIBIT_CHANGING_OF 1387 +#define ER_NO_FILE_MAPPING 1388 +#define ER_WRONG_MAGIC 1389 +#define ER_PS_MANY_PARAM 1390 +#define ER_KEY_PART_0 1391 +#define ER_VIEW_CHECKSUM 1392 +#define ER_VIEW_MULTIUPDATE 1393 +#define ER_VIEW_NO_INSERT_FIELD_LIST 1394 +#define ER_VIEW_DELETE_MERGE_VIEW 1395 +#define ER_CANNOT_USER 1396 +#define ER_XAER_NOTA 1397 +#define ER_XAER_INVAL 1398 +#define ER_XAER_RMFAIL 1399 +#define ER_XAER_OUTSIDE 1400 +#define ER_XAER_RMERR 1401 +#define ER_XA_RBROLLBACK 1402 +#define ER_NONEXISTING_PROC_GRANT 1403 +#define ER_PROC_AUTO_GRANT_FAIL 1404 +#define ER_PROC_AUTO_REVOKE_FAIL 1405 +#define ER_DATA_TOO_LONG 1406 +#define ER_SP_BAD_SQLSTATE 1407 +#define ER_STARTUP 1408 +#define ER_LOAD_FROM_FIXED_SIZE_ROWS_TO_VAR 1409 +#define ER_CANT_CREATE_USER_WITH_GRANT 1410 +#define ER_WRONG_VALUE_FOR_TYPE 1411 +#define ER_TABLE_DEF_CHANGED 1412 +#define ER_SP_DUP_HANDLER 1413 +#define ER_SP_NOT_VAR_ARG 1414 +#define ER_SP_NO_RETSET 1415 +#define ER_CANT_CREATE_GEOMETRY_OBJECT 1416 +#define ER_FAILED_ROUTINE_BREAK_BINLOG 1417 +#define ER_BINLOG_UNSAFE_ROUTINE 1418 +#define ER_BINLOG_CREATE_ROUTINE_NEED_SUPER 1419 +#define ER_EXEC_STMT_WITH_OPEN_CURSOR 1420 +#define ER_STMT_HAS_NO_OPEN_CURSOR 1421 +#define ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG 1422 +#define ER_NO_DEFAULT_FOR_VIEW_FIELD 1423 +#define ER_SP_NO_RECURSION 1424 +#define ER_TOO_BIG_SCALE 1425 +#define ER_TOO_BIG_PRECISION 1426 +#define ER_M_BIGGER_THAN_D 1427 +#define ER_WRONG_LOCK_OF_SYSTEM_TABLE 1428 +#define ER_CONNECT_TO_FOREIGN_DATA_SOURCE 1429 +#define ER_QUERY_ON_FOREIGN_DATA_SOURCE 1430 +#define ER_FOREIGN_DATA_SOURCE_DOESNT_EXIST 1431 +#define ER_FOREIGN_DATA_STRING_INVALID_CANT_CREATE 1432 +#define ER_FOREIGN_DATA_STRING_INVALID 1433 +#define ER_CANT_CREATE_FEDERATED_TABLE 1434 +#define ER_TRG_IN_WRONG_SCHEMA 1435 +#define ER_STACK_OVERRUN_NEED_MORE 1436 +#define ER_TOO_LONG_BODY 1437 +#define ER_WARN_CANT_DROP_DEFAULT_KEYCACHE 1438 +#define ER_TOO_BIG_DISPLAYWIDTH 1439 +#define ER_XAER_DUPID 1440 +#define ER_DATETIME_FUNCTION_OVERFLOW 1441 +#define ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG 1442 +#define ER_VIEW_PREVENT_UPDATE 1443 +#define ER_PS_NO_RECURSION 1444 +#define ER_SP_CANT_SET_AUTOCOMMIT 1445 +#define ER_MALFORMED_DEFINER 1446 +#define ER_VIEW_FRM_NO_USER 1447 +#define ER_VIEW_OTHER_USER 1448 +#define ER_NO_SUCH_USER 1449 +#define ER_FORBID_SCHEMA_CHANGE 1450 +#define ER_ROW_IS_REFERENCED_2 1451 +#define ER_NO_REFERENCED_ROW_2 1452 +#define ER_SP_BAD_VAR_SHADOW 1453 +#define ER_TRG_NO_DEFINER 1454 +#define ER_OLD_FILE_FORMAT 1455 +#define ER_SP_RECURSION_LIMIT 1456 +#define ER_SP_PROC_TABLE_CORRUPT 1457 +#define ER_SP_WRONG_NAME 1458 +#define ER_TABLE_NEEDS_UPGRADE 1459 +#define ER_SP_NO_AGGREGATE 1460 +#define ER_MAX_PREPARED_STMT_COUNT_REACHED 1461 +#define ER_VIEW_RECURSIVE 1462 +#define ER_NON_GROUPING_FIELD_USED 1463 +#define ER_TABLE_CANT_HANDLE_SPKEYS 1464 +#define ER_NO_TRIGGERS_ON_SYSTEM_SCHEMA 1465 +#define ER_REMOVED_SPACES 1466 +#define ER_AUTOINC_READ_FAILED 1467 +#define ER_USERNAME 1468 +#define ER_HOSTNAME 1469 +#define ER_WRONG_STRING_LENGTH 1470 +#define ER_NON_INSERTABLE_TABLE 1471 +#define ER_ADMIN_WRONG_MRG_TABLE 1472 +#define ER_TOO_HIGH_LEVEL_OF_NESTING_FOR_SELECT 1473 +#define ER_NAME_BECOMES_EMPTY 1474 +#define ER_AMBIGUOUS_FIELD_TERM 1475 +#define ER_FOREIGN_SERVER_EXISTS 1476 +#define ER_FOREIGN_SERVER_DOESNT_EXIST 1477 +#define ER_ILLEGAL_HA_CREATE_OPTION 1478 +#define ER_PARTITION_REQUIRES_VALUES_ERROR 1479 +#define ER_PARTITION_WRONG_VALUES_ERROR 1480 +#define ER_PARTITION_MAXVALUE_ERROR 1481 +#define ER_PARTITION_SUBPARTITION_ERROR 1482 +#define ER_PARTITION_SUBPART_MIX_ERROR 1483 +#define ER_PARTITION_WRONG_NO_PART_ERROR 1484 +#define ER_PARTITION_WRONG_NO_SUBPART_ERROR 1485 +#define ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR 1486 +#define ER_NO_CONST_EXPR_IN_RANGE_OR_LIST_ERROR 1487 +#define ER_FIELD_NOT_FOUND_PART_ERROR 1488 +#define ER_LIST_OF_FIELDS_ONLY_IN_HASH_ERROR 1489 +#define ER_INCONSISTENT_PARTITION_INFO_ERROR 1490 +#define ER_PARTITION_FUNC_NOT_ALLOWED_ERROR 1491 +#define ER_PARTITIONS_MUST_BE_DEFINED_ERROR 1492 +#define ER_RANGE_NOT_INCREASING_ERROR 1493 +#define ER_INCONSISTENT_TYPE_OF_FUNCTIONS_ERROR 1494 +#define ER_MULTIPLE_DEF_CONST_IN_LIST_PART_ERROR 1495 +#define ER_PARTITION_ENTRY_ERROR 1496 +#define ER_MIX_HANDLER_ERROR 1497 +#define ER_PARTITION_NOT_DEFINED_ERROR 1498 +#define ER_TOO_MANY_PARTITIONS_ERROR 1499 +#define ER_SUBPARTITION_ERROR 1500 +#define ER_CANT_CREATE_HANDLER_FILE 1501 +#define ER_BLOB_FIELD_IN_PART_FUNC_ERROR 1502 +#define ER_UNIQUE_KEY_NEED_ALL_FIELDS_IN_PF 1503 +#define ER_NO_PARTS_ERROR 1504 +#define ER_PARTITION_MGMT_ON_NONPARTITIONED 1505 +#define ER_FOREIGN_KEY_ON_PARTITIONED 1506 +#define ER_DROP_PARTITION_NON_EXISTENT 1507 +#define ER_DROP_LAST_PARTITION 1508 +#define ER_COALESCE_ONLY_ON_HASH_PARTITION 1509 +#define ER_REORG_HASH_ONLY_ON_SAME_NO 1510 +#define ER_REORG_NO_PARAM_ERROR 1511 +#define ER_ONLY_ON_RANGE_LIST_PARTITION 1512 +#define ER_ADD_PARTITION_SUBPART_ERROR 1513 +#define ER_ADD_PARTITION_NO_NEW_PARTITION 1514 +#define ER_COALESCE_PARTITION_NO_PARTITION 1515 +#define ER_REORG_PARTITION_NOT_EXIST 1516 +#define ER_SAME_NAME_PARTITION 1517 +#define ER_NO_BINLOG_ERROR 1518 +#define ER_CONSECUTIVE_REORG_PARTITIONS 1519 +#define ER_REORG_OUTSIDE_RANGE 1520 +#define ER_PARTITION_FUNCTION_FAILURE 1521 +#define ER_PART_STATE_ERROR 1522 +#define ER_LIMITED_PART_RANGE 1523 +#define ER_PLUGIN_IS_NOT_LOADED 1524 +#define ER_WRONG_VALUE 1525 +#define ER_NO_PARTITION_FOR_GIVEN_VALUE 1526 +#define ER_FILEGROUP_OPTION_ONLY_ONCE 1527 +#define ER_CREATE_FILEGROUP_FAILED 1528 +#define ER_DROP_FILEGROUP_FAILED 1529 +#define ER_TABLESPACE_AUTO_EXTEND_ERROR 1530 +#define ER_WRONG_SIZE_NUMBER 1531 +#define ER_SIZE_OVERFLOW_ERROR 1532 +#define ER_ALTER_FILEGROUP_FAILED 1533 +#define ER_BINLOG_ROW_LOGGING_FAILED 1534 +#define ER_BINLOG_ROW_WRONG_TABLE_DEF 1535 +#define ER_BINLOG_ROW_RBR_TO_SBR 1536 +#define ER_EVENT_ALREADY_EXISTS 1537 +#define ER_EVENT_STORE_FAILED 1538 +#define ER_EVENT_DOES_NOT_EXIST 1539 +#define ER_EVENT_CANT_ALTER 1540 +#define ER_EVENT_DROP_FAILED 1541 +#define ER_EVENT_INTERVAL_NOT_POSITIVE_OR_TOO_BIG 1542 +#define ER_EVENT_ENDS_BEFORE_STARTS 1543 +#define ER_EVENT_EXEC_TIME_IN_THE_PAST 1544 +#define ER_EVENT_OPEN_TABLE_FAILED 1545 +#define ER_EVENT_NEITHER_M_EXPR_NOR_M_AT 1546 +#define ER_COL_COUNT_DOESNT_MATCH_CORRUPTED 1547 +#define ER_CANNOT_LOAD_FROM_TABLE 1548 +#define ER_EVENT_CANNOT_DELETE 1549 +#define ER_EVENT_COMPILE_ERROR 1550 +#define ER_EVENT_SAME_NAME 1551 +#define ER_EVENT_DATA_TOO_LONG 1552 +#define ER_DROP_INDEX_FK 1553 +#define ER_WARN_DEPRECATED_SYNTAX_WITH_VER 1554 +#define ER_CANT_WRITE_LOCK_LOG_TABLE 1555 +#define ER_CANT_LOCK_LOG_TABLE 1556 +#define ER_FOREIGN_DUPLICATE_KEY 1557 +#define ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE 1558 +#define ER_TEMP_TABLE_PREVENTS_SWITCH_OUT_OF_RBR 1559 +#define ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_FORMAT 1560 +#define ER_NDB_CANT_SWITCH_BINLOG_FORMAT 1561 +#define ER_PARTITION_NO_TEMPORARY 1562 +#define ER_PARTITION_CONST_DOMAIN_ERROR 1563 +#define ER_PARTITION_FUNCTION_IS_NOT_ALLOWED 1564 +#define ER_DDL_LOG_ERROR 1565 +#define ER_NULL_IN_VALUES_LESS_THAN 1566 +#define ER_WRONG_PARTITION_NAME 1567 +#define ER_CANT_CHANGE_TX_ISOLATION 1568 +#define ER_DUP_ENTRY_AUTOINCREMENT_CASE 1569 +#define ER_EVENT_MODIFY_QUEUE_ERROR 1570 +#define ER_EVENT_SET_VAR_ERROR 1571 +#define ER_PARTITION_MERGE_ERROR 1572 +#define ER_CANT_ACTIVATE_LOG 1573 +#define ER_RBR_NOT_AVAILABLE 1574 +#define ER_BASE64_DECODE_ERROR 1575 +#define ER_EVENT_RECURSION_FORBIDDEN 1576 +#define ER_EVENTS_DB_ERROR 1577 +#define ER_ONLY_INTEGERS_ALLOWED 1578 +#define ER_UNSUPORTED_LOG_ENGINE 1579 +#define ER_BAD_LOG_STATEMENT 1580 +#define ER_CANT_RENAME_LOG_TABLE 1581 +#define ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT 1582 +#define ER_WRONG_PARAMETERS_TO_NATIVE_FCT 1583 +#define ER_WRONG_PARAMETERS_TO_STORED_FCT 1584 +#define ER_NATIVE_FCT_NAME_COLLISION 1585 +#define ER_DUP_ENTRY_WITH_KEY_NAME 1586 +#define ER_BINLOG_PURGE_EMFILE 1587 +#define ER_EVENT_CANNOT_CREATE_IN_THE_PAST 1588 +#define ER_EVENT_CANNOT_ALTER_IN_THE_PAST 1589 +#define ER_SLAVE_INCIDENT 1590 +#define ER_NO_PARTITION_FOR_GIVEN_VALUE_SILENT 1591 +#define ER_BINLOG_UNSAFE_STATEMENT 1592 +#define ER_SLAVE_FATAL_ERROR 1593 +#define ER_SLAVE_RELAY_LOG_READ_FAILURE 1594 +#define ER_SLAVE_RELAY_LOG_WRITE_FAILURE 1595 +#define ER_SLAVE_CREATE_EVENT_FAILURE 1596 +#define ER_SLAVE_MASTER_COM_FAILURE 1597 +#define ER_BINLOG_LOGGING_IMPOSSIBLE 1598 +#define ER_VIEW_NO_CREATION_CTX 1599 +#define ER_VIEW_INVALID_CREATION_CTX 1600 +#define ER_SR_INVALID_CREATION_CTX 1601 +#define ER_TRG_CORRUPTED_FILE 1602 +#define ER_TRG_NO_CREATION_CTX 1603 +#define ER_TRG_INVALID_CREATION_CTX 1604 +#define ER_EVENT_INVALID_CREATION_CTX 1605 +#define ER_TRG_CANT_OPEN_TABLE 1606 +#define ER_CANT_CREATE_SROUTINE 1607 +#define ER_NEVER_USED 1608 +#define ER_NO_FORMAT_DESCRIPTION_EVENT_BEFORE_BINLOG_STATEMENT 1609 +#define ER_SLAVE_CORRUPT_EVENT 1610 +#define ER_LOAD_DATA_INVALID_COLUMN 1611 +#define ER_LOG_PURGE_NO_FILE 1612 +#define ER_XA_RBTIMEOUT 1613 +#define ER_XA_RBDEADLOCK 1614 +#define ER_NEED_REPREPARE 1615 +#define ER_DELAYED_NOT_SUPPORTED 1616 +#define WARN_NO_MASTER_INFO 1617 +#define WARN_OPTION_IGNORED 1618 +#define WARN_PLUGIN_DELETE_BUILTIN 1619 +#define WARN_PLUGIN_BUSY 1620 +#define ER_VARIABLE_IS_READONLY 1621 +#define ER_WARN_ENGINE_TRANSACTION_ROLLBACK 1622 +#define ER_SLAVE_HEARTBEAT_FAILURE 1623 +#define ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE 1624 +#define ER_NDB_REPLICATION_SCHEMA_ERROR 1625 +#define ER_CONFLICT_FN_PARSE_ERROR 1626 +#define ER_EXCEPTIONS_WRITE_ERROR 1627 +#define ER_TOO_LONG_TABLE_COMMENT 1628 +#define ER_TOO_LONG_FIELD_COMMENT 1629 +#define ER_FUNC_INEXISTENT_NAME_COLLISION 1630 +#define ER_DATABASE_NAME 1631 +#define ER_TABLE_NAME 1632 +#define ER_PARTITION_NAME 1633 +#define ER_SUBPARTITION_NAME 1634 +#define ER_TEMPORARY_NAME 1635 +#define ER_RENAMED_NAME 1636 +#define ER_TOO_MANY_CONCURRENT_TRXS 1637 +#define WARN_NON_ASCII_SEPARATOR_NOT_IMPLEMENTED 1638 +#define ER_DEBUG_SYNC_TIMEOUT 1639 +#define ER_DEBUG_SYNC_HIT_LIMIT 1640 +#define ER_DUP_SIGNAL_SET 1641 +#define ER_SIGNAL_WARN 1642 +#define ER_SIGNAL_NOT_FOUND 1643 +#define ER_SIGNAL_EXCEPTION 1644 +#define ER_RESIGNAL_WITHOUT_ACTIVE_HANDLER 1645 +#define ER_SIGNAL_BAD_CONDITION_TYPE 1646 +#define WARN_COND_ITEM_TRUNCATED 1647 +#define ER_COND_ITEM_TOO_LONG 1648 +#define ER_UNKNOWN_LOCALE 1649 +#define ER_SLAVE_IGNORE_SERVER_IDS 1650 +#define ER_QUERY_CACHE_DISABLED 1651 +#define ER_SAME_NAME_PARTITION_FIELD 1652 +#define ER_PARTITION_COLUMN_LIST_ERROR 1653 +#define ER_WRONG_TYPE_COLUMN_VALUE_ERROR 1654 +#define ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR 1655 +#define ER_MAXVALUE_IN_VALUES_IN 1656 +#define ER_TOO_MANY_VALUES_ERROR 1657 +#define ER_ROW_SINGLE_PARTITION_FIELD_ERROR 1658 +#define ER_FIELD_TYPE_NOT_ALLOWED_AS_PARTITION_FIELD 1659 +#define ER_PARTITION_FIELDS_TOO_LONG 1660 +#define ER_BINLOG_ROW_ENGINE_AND_STMT_ENGINE 1661 +#define ER_BINLOG_ROW_MODE_AND_STMT_ENGINE 1662 +#define ER_BINLOG_UNSAFE_AND_STMT_ENGINE 1663 +#define ER_BINLOG_ROW_INJECTION_AND_STMT_ENGINE 1664 +#define ER_BINLOG_STMT_MODE_AND_ROW_ENGINE 1665 +#define ER_BINLOG_ROW_INJECTION_AND_STMT_MODE 1666 +#define ER_BINLOG_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE 1667 +#define ER_BINLOG_UNSAFE_LIMIT 1668 +#define ER_BINLOG_UNSAFE_INSERT_DELAYED 1669 +#define ER_BINLOG_UNSAFE_SYSTEM_TABLE 1670 +#define ER_BINLOG_UNSAFE_AUTOINC_COLUMNS 1671 +#define ER_BINLOG_UNSAFE_UDF 1672 +#define ER_BINLOG_UNSAFE_SYSTEM_VARIABLE 1673 +#define ER_BINLOG_UNSAFE_SYSTEM_FUNCTION 1674 +#define ER_BINLOG_UNSAFE_NONTRANS_AFTER_TRANS 1675 +#define ER_MESSAGE_AND_STATEMENT 1676 +#define ER_SLAVE_CONVERSION_FAILED 1677 +#define ER_SLAVE_CANT_CREATE_CONVERSION 1678 +#define ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_FORMAT 1679 +#define ER_PATH_LENGTH 1680 +#define ER_WARN_DEPRECATED_SYNTAX_NO_REPLACEMENT 1681 +#define ER_WRONG_NATIVE_TABLE_STRUCTURE 1682 +#define ER_WRONG_PERFSCHEMA_USAGE 1683 +#define ER_WARN_I_S_SKIPPED_TABLE 1684 +#define ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_DIRECT 1685 +#define ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_DIRECT 1686 +#define ER_SPATIAL_MUST_HAVE_GEOM_COL 1687 +#define ER_TOO_LONG_INDEX_COMMENT 1688 +#define ER_LOCK_ABORTED 1689 +#define ER_DATA_OUT_OF_RANGE 1690 +#define ER_WRONG_SPVAR_TYPE_IN_LIMIT 1691 +#define ER_BINLOG_UNSAFE_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE 1692 +#define ER_BINLOG_UNSAFE_MIXED_STATEMENT 1693 +#define ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_SQL_LOG_BIN 1694 +#define ER_STORED_FUNCTION_PREVENTS_SWITCH_SQL_LOG_BIN 1695 +#define ER_FAILED_READ_FROM_PAR_FILE 1696 +#define ER_VALUES_IS_NOT_INT_TYPE_ERROR 1697 +#define ER_ACCESS_DENIED_NO_PASSWORD_ERROR 1698 +#define ER_SET_PASSWORD_AUTH_PLUGIN 1699 +#define ER_GRANT_PLUGIN_USER_EXISTS 1700 +#define ER_TRUNCATE_ILLEGAL_FK 1701 +#define ER_PLUGIN_IS_PERMANENT 1702 +#define ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MIN 1703 +#define ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MAX 1704 +#define ER_ERROR_LAST 1704 diff --git a/include/mysql/plugin.h b/include/mysql/plugin.h new file mode 100644 index 000000000..7ec68ff50 --- /dev/null +++ b/include/mysql/plugin.h @@ -0,0 +1,633 @@ +/* Copyright (C) 2005 MySQL AB, 2009 Sun Microsystems, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifndef _my_plugin_h +#define _my_plugin_h + +/* + On Windows, exports from DLL need to be declared + Also, plugin needs to be declared as extern "C" because MSVC + unlike other compilers, uses C++ mangling for variables not only + for functions. +*/ +#if defined(_MSC_VER) +#if defined(MYSQL_DYNAMIC_PLUGIN) + #ifdef __cplusplus + #define MYSQL_PLUGIN_EXPORT extern "C" __declspec(dllexport) + #else + #define MYSQL_PLUGIN_EXPORT __declspec(dllexport) + #endif +#else /* MYSQL_DYNAMIC_PLUGIN */ + #ifdef __cplusplus + #define MYSQL_PLUGIN_EXPORT extern "C" + #else + #define MYSQL_PLUGIN_EXPORT + #endif +#endif /*MYSQL_DYNAMIC_PLUGIN */ +#else /*_MSC_VER */ +#define MYSQL_PLUGIN_EXPORT +#endif + +#ifdef __cplusplus +class THD; +class Item; +#define MYSQL_THD THD* +#else +#define MYSQL_THD void* +#endif + +#include + +#define MYSQL_XIDDATASIZE 128 +/** + struct st_mysql_xid is binary compatible with the XID structure as + in the X/Open CAE Specification, Distributed Transaction Processing: + The XA Specification, X/Open Company Ltd., 1991. + http://www.opengroup.org/bookstore/catalog/c193.htm + + @see XID in sql/handler.h +*/ +struct st_mysql_xid { + long formatID; + long gtrid_length; + long bqual_length; + char data[MYSQL_XIDDATASIZE]; /* Not \0-terminated */ +}; +typedef struct st_mysql_xid MYSQL_XID; + +/************************************************************************* + Plugin API. Common for all plugin types. +*/ + +#define MYSQL_PLUGIN_INTERFACE_VERSION 0x0102 + +/* + The allowable types of plugins +*/ +#define MYSQL_UDF_PLUGIN 0 /* User-defined function */ +#define MYSQL_STORAGE_ENGINE_PLUGIN 1 /* Storage Engine */ +#define MYSQL_FTPARSER_PLUGIN 2 /* Full-text parser plugin */ +#define MYSQL_DAEMON_PLUGIN 3 /* The daemon/raw plugin type */ +#define MYSQL_INFORMATION_SCHEMA_PLUGIN 4 /* The I_S plugin type */ +#define MYSQL_AUDIT_PLUGIN 5 /* The Audit plugin type */ +#define MYSQL_REPLICATION_PLUGIN 6 /* The replication plugin type */ +#define MYSQL_AUTHENTICATION_PLUGIN 7 /* The authentication plugin type */ +#define MYSQL_MAX_PLUGIN_TYPE_NUM 8 /* The number of plugin types */ + +/* We use the following strings to define licenses for plugins */ +#define PLUGIN_LICENSE_PROPRIETARY 0 +#define PLUGIN_LICENSE_GPL 1 +#define PLUGIN_LICENSE_BSD 2 + +#define PLUGIN_LICENSE_PROPRIETARY_STRING "PROPRIETARY" +#define PLUGIN_LICENSE_GPL_STRING "GPL" +#define PLUGIN_LICENSE_BSD_STRING "BSD" + +/* + Macros for beginning and ending plugin declarations. Between + mysql_declare_plugin and mysql_declare_plugin_end there should + be a st_mysql_plugin struct for each plugin to be declared. +*/ + + +#ifndef MYSQL_DYNAMIC_PLUGIN +#define __MYSQL_DECLARE_PLUGIN(NAME, VERSION, PSIZE, DECLS) \ +MYSQL_PLUGIN_EXPORT int VERSION= MYSQL_PLUGIN_INTERFACE_VERSION; \ +MYSQL_PLUGIN_EXPORT int PSIZE= sizeof(struct st_mysql_plugin); \ +MYSQL_PLUGIN_EXPORT struct st_mysql_plugin DECLS[]= { +#else +#define __MYSQL_DECLARE_PLUGIN(NAME, VERSION, PSIZE, DECLS) \ +MYSQL_PLUGIN_EXPORT int _mysql_plugin_interface_version_= MYSQL_PLUGIN_INTERFACE_VERSION; \ +MYSQL_PLUGIN_EXPORT int _mysql_sizeof_struct_st_plugin_= sizeof(struct st_mysql_plugin); \ +MYSQL_PLUGIN_EXPORT struct st_mysql_plugin _mysql_plugin_declarations_[]= { +#endif + +#define mysql_declare_plugin(NAME) \ +__MYSQL_DECLARE_PLUGIN(NAME, \ + builtin_ ## NAME ## _plugin_interface_version, \ + builtin_ ## NAME ## _sizeof_struct_st_plugin, \ + builtin_ ## NAME ## _plugin) + +#define mysql_declare_plugin_end ,{0,0,0,0,0,0,0,0,0,0,0,0}} + +/* + declarations for SHOW STATUS support in plugins +*/ +enum enum_mysql_show_type +{ + SHOW_UNDEF, SHOW_BOOL, SHOW_INT, SHOW_LONG, + SHOW_LONGLONG, SHOW_CHAR, SHOW_CHAR_PTR, + SHOW_ARRAY, SHOW_FUNC, SHOW_DOUBLE, + SHOW_always_last +}; + +struct st_mysql_show_var { + const char *name; + char *value; + enum enum_mysql_show_type type; +}; + +#define SHOW_VAR_FUNC_BUFF_SIZE 1024 +typedef int (*mysql_show_var_func)(MYSQL_THD, struct st_mysql_show_var*, char *); + + +/* + declarations for server variables and command line options +*/ + + +#define PLUGIN_VAR_BOOL 0x0001 +#define PLUGIN_VAR_INT 0x0002 +#define PLUGIN_VAR_LONG 0x0003 +#define PLUGIN_VAR_LONGLONG 0x0004 +#define PLUGIN_VAR_STR 0x0005 +#define PLUGIN_VAR_ENUM 0x0006 +#define PLUGIN_VAR_SET 0x0007 +#define PLUGIN_VAR_UNSIGNED 0x0080 +#define PLUGIN_VAR_THDLOCAL 0x0100 /* Variable is per-connection */ +#define PLUGIN_VAR_READONLY 0x0200 /* Server variable is read only */ +#define PLUGIN_VAR_NOSYSVAR 0x0400 /* Not a server variable */ +#define PLUGIN_VAR_NOCMDOPT 0x0800 /* Not a command line option */ +#define PLUGIN_VAR_NOCMDARG 0x1000 /* No argument for cmd line */ +#define PLUGIN_VAR_RQCMDARG 0x0000 /* Argument required for cmd line */ +#define PLUGIN_VAR_OPCMDARG 0x2000 /* Argument optional for cmd line */ +#define PLUGIN_VAR_MEMALLOC 0x8000 /* String needs memory allocated */ + +struct st_mysql_sys_var; +struct st_mysql_value; + +/* + SYNOPSIS + (*mysql_var_check_func)() + thd thread handle + var dynamic variable being altered + save pointer to temporary storage + value user provided value + RETURN + 0 user provided value is OK and the update func may be called. + any other value indicates error. + + This function should parse the user provided value and store in the + provided temporary storage any data as required by the update func. + There is sufficient space in the temporary storage to store a double. + Note that the update func may not be called if any other error occurs + so any memory allocated should be thread-local so that it may be freed + automatically at the end of the statement. +*/ + +typedef int (*mysql_var_check_func)(MYSQL_THD thd, + struct st_mysql_sys_var *var, + void *save, struct st_mysql_value *value); + +/* + SYNOPSIS + (*mysql_var_update_func)() + thd thread handle + var dynamic variable being altered + var_ptr pointer to dynamic variable + save pointer to temporary storage + RETURN + NONE + + This function should use the validated value stored in the temporary store + and persist it in the provided pointer to the dynamic variable. + For example, strings may require memory to be allocated. +*/ +typedef void (*mysql_var_update_func)(MYSQL_THD thd, + struct st_mysql_sys_var *var, + void *var_ptr, const void *save); + + +/* the following declarations are for internal use only */ + + +#define PLUGIN_VAR_MASK \ + (PLUGIN_VAR_READONLY | PLUGIN_VAR_NOSYSVAR | \ + PLUGIN_VAR_NOCMDOPT | PLUGIN_VAR_NOCMDARG | \ + PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC) + +#define MYSQL_PLUGIN_VAR_HEADER \ + int flags; \ + const char *name; \ + const char *comment; \ + mysql_var_check_func check; \ + mysql_var_update_func update + +#define MYSQL_SYSVAR_NAME(name) mysql_sysvar_ ## name +#define MYSQL_SYSVAR(name) \ + ((struct st_mysql_sys_var *)&(MYSQL_SYSVAR_NAME(name))) + +/* + for global variables, the value pointer is the first + element after the header, the default value is the second. + for thread variables, the value offset is the first + element after the header, the default value is the second. +*/ + + +#define DECLARE_MYSQL_SYSVAR_BASIC(name, type) struct { \ + MYSQL_PLUGIN_VAR_HEADER; \ + type *value; \ + const type def_val; \ +} MYSQL_SYSVAR_NAME(name) + +#define DECLARE_MYSQL_SYSVAR_SIMPLE(name, type) struct { \ + MYSQL_PLUGIN_VAR_HEADER; \ + type *value; type def_val; \ + type min_val; type max_val; \ + type blk_sz; \ +} MYSQL_SYSVAR_NAME(name) + +#define DECLARE_MYSQL_SYSVAR_TYPELIB(name, type) struct { \ + MYSQL_PLUGIN_VAR_HEADER; \ + type *value; type def_val; \ + TYPELIB *typelib; \ +} MYSQL_SYSVAR_NAME(name) + +#define DECLARE_THDVAR_FUNC(type) \ + type *(*resolve)(MYSQL_THD thd, int offset) + +#define DECLARE_MYSQL_THDVAR_BASIC(name, type) struct { \ + MYSQL_PLUGIN_VAR_HEADER; \ + int offset; \ + const type def_val; \ + DECLARE_THDVAR_FUNC(type); \ +} MYSQL_SYSVAR_NAME(name) + +#define DECLARE_MYSQL_THDVAR_SIMPLE(name, type) struct { \ + MYSQL_PLUGIN_VAR_HEADER; \ + int offset; \ + type def_val; type min_val; \ + type max_val; type blk_sz; \ + DECLARE_THDVAR_FUNC(type); \ +} MYSQL_SYSVAR_NAME(name) + +#define DECLARE_MYSQL_THDVAR_TYPELIB(name, type) struct { \ + MYSQL_PLUGIN_VAR_HEADER; \ + int offset; \ + type def_val; \ + DECLARE_THDVAR_FUNC(type); \ + TYPELIB *typelib; \ +} MYSQL_SYSVAR_NAME(name) + + +/* + the following declarations are for use by plugin implementors +*/ + +#define MYSQL_SYSVAR_BOOL(name, varname, opt, comment, check, update, def) \ +DECLARE_MYSQL_SYSVAR_BASIC(name, char) = { \ + PLUGIN_VAR_BOOL | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, &varname, def} + +#define MYSQL_SYSVAR_STR(name, varname, opt, comment, check, update, def) \ +DECLARE_MYSQL_SYSVAR_BASIC(name, char *) = { \ + PLUGIN_VAR_STR | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, &varname, def} + +#define MYSQL_SYSVAR_INT(name, varname, opt, comment, check, update, def, min, max, blk) \ +DECLARE_MYSQL_SYSVAR_SIMPLE(name, int) = { \ + PLUGIN_VAR_INT | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, &varname, def, min, max, blk } + +#define MYSQL_SYSVAR_UINT(name, varname, opt, comment, check, update, def, min, max, blk) \ +DECLARE_MYSQL_SYSVAR_SIMPLE(name, unsigned int) = { \ + PLUGIN_VAR_INT | PLUGIN_VAR_UNSIGNED | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, &varname, def, min, max, blk } + +#define MYSQL_SYSVAR_LONG(name, varname, opt, comment, check, update, def, min, max, blk) \ +DECLARE_MYSQL_SYSVAR_SIMPLE(name, long) = { \ + PLUGIN_VAR_LONG | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, &varname, def, min, max, blk } + +#define MYSQL_SYSVAR_ULONG(name, varname, opt, comment, check, update, def, min, max, blk) \ +DECLARE_MYSQL_SYSVAR_SIMPLE(name, unsigned long) = { \ + PLUGIN_VAR_LONG | PLUGIN_VAR_UNSIGNED | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, &varname, def, min, max, blk } + +#define MYSQL_SYSVAR_LONGLONG(name, varname, opt, comment, check, update, def, min, max, blk) \ +DECLARE_MYSQL_SYSVAR_SIMPLE(name, long long) = { \ + PLUGIN_VAR_LONGLONG | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, &varname, def, min, max, blk } + +#define MYSQL_SYSVAR_ULONGLONG(name, varname, opt, comment, check, update, def, min, max, blk) \ +DECLARE_MYSQL_SYSVAR_SIMPLE(name, unsigned long long) = { \ + PLUGIN_VAR_LONGLONG | PLUGIN_VAR_UNSIGNED | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, &varname, def, min, max, blk } + +#define MYSQL_SYSVAR_ENUM(name, varname, opt, comment, check, update, def, typelib) \ +DECLARE_MYSQL_SYSVAR_TYPELIB(name, unsigned long) = { \ + PLUGIN_VAR_ENUM | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, &varname, def, typelib } + +#define MYSQL_SYSVAR_SET(name, varname, opt, comment, check, update, def, typelib) \ +DECLARE_MYSQL_SYSVAR_TYPELIB(name, unsigned long long) = { \ + PLUGIN_VAR_SET | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, &varname, def, typelib } + +#define MYSQL_THDVAR_BOOL(name, opt, comment, check, update, def) \ +DECLARE_MYSQL_THDVAR_BASIC(name, char) = { \ + PLUGIN_VAR_BOOL | PLUGIN_VAR_THDLOCAL | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, -1, def, NULL} + +#define MYSQL_THDVAR_STR(name, opt, comment, check, update, def) \ +DECLARE_MYSQL_THDVAR_BASIC(name, char *) = { \ + PLUGIN_VAR_STR | PLUGIN_VAR_THDLOCAL | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, -1, def, NULL} + +#define MYSQL_THDVAR_INT(name, opt, comment, check, update, def, min, max, blk) \ +DECLARE_MYSQL_THDVAR_SIMPLE(name, int) = { \ + PLUGIN_VAR_INT | PLUGIN_VAR_THDLOCAL | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, -1, def, min, max, blk, NULL } + +#define MYSQL_THDVAR_UINT(name, opt, comment, check, update, def, min, max, blk) \ +DECLARE_MYSQL_THDVAR_SIMPLE(name, unsigned int) = { \ + PLUGIN_VAR_INT | PLUGIN_VAR_THDLOCAL | PLUGIN_VAR_UNSIGNED | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, -1, def, min, max, blk, NULL } + +#define MYSQL_THDVAR_LONG(name, opt, comment, check, update, def, min, max, blk) \ +DECLARE_MYSQL_THDVAR_SIMPLE(name, long) = { \ + PLUGIN_VAR_LONG | PLUGIN_VAR_THDLOCAL | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, -1, def, min, max, blk, NULL } + +#define MYSQL_THDVAR_ULONG(name, opt, comment, check, update, def, min, max, blk) \ +DECLARE_MYSQL_THDVAR_SIMPLE(name, unsigned long) = { \ + PLUGIN_VAR_LONG | PLUGIN_VAR_THDLOCAL | PLUGIN_VAR_UNSIGNED | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, -1, def, min, max, blk, NULL } + +#define MYSQL_THDVAR_LONGLONG(name, opt, comment, check, update, def, min, max, blk) \ +DECLARE_MYSQL_THDVAR_SIMPLE(name, long long) = { \ + PLUGIN_VAR_LONGLONG | PLUGIN_VAR_THDLOCAL | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, -1, def, min, max, blk, NULL } + +#define MYSQL_THDVAR_ULONGLONG(name, opt, comment, check, update, def, min, max, blk) \ +DECLARE_MYSQL_THDVAR_SIMPLE(name, unsigned long long) = { \ + PLUGIN_VAR_LONGLONG | PLUGIN_VAR_THDLOCAL | PLUGIN_VAR_UNSIGNED | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, -1, def, min, max, blk, NULL } + +#define MYSQL_THDVAR_ENUM(name, opt, comment, check, update, def, typelib) \ +DECLARE_MYSQL_THDVAR_TYPELIB(name, unsigned long) = { \ + PLUGIN_VAR_ENUM | PLUGIN_VAR_THDLOCAL | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, -1, def, NULL, typelib } + +#define MYSQL_THDVAR_SET(name, opt, comment, check, update, def, typelib) \ +DECLARE_MYSQL_THDVAR_TYPELIB(name, unsigned long long) = { \ + PLUGIN_VAR_SET | PLUGIN_VAR_THDLOCAL | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, -1, def, NULL, typelib } + +/* accessor macros */ + +#define SYSVAR(name) \ + (*(MYSQL_SYSVAR_NAME(name).value)) + +/* when thd == null, result points to global value */ +#define THDVAR(thd, name) \ + (*(MYSQL_SYSVAR_NAME(name).resolve(thd, MYSQL_SYSVAR_NAME(name).offset))) + + +/* + Plugin description structure. +*/ + +struct st_mysql_plugin +{ + int type; /* the plugin type (a MYSQL_XXX_PLUGIN value) */ + void *info; /* pointer to type-specific plugin descriptor */ + const char *name; /* plugin name */ + const char *author; /* plugin author (for I_S.PLUGINS) */ + const char *descr; /* general descriptive text (for I_S.PLUGINS) */ + int license; /* the plugin license (PLUGIN_LICENSE_XXX) */ + int (*init)(void *); /* the function to invoke when plugin is loaded */ + int (*deinit)(void *);/* the function to invoke when plugin is unloaded */ + unsigned int version; /* plugin version (for I_S.PLUGINS) */ + struct st_mysql_show_var *status_vars; + struct st_mysql_sys_var **system_vars; + void * __reserved1; /* reserved for dependency checking */ +}; + +/************************************************************************* + API for Full-text parser plugin. (MYSQL_FTPARSER_PLUGIN) +*/ +#include "plugin_ftparser.h" + +/************************************************************************* + API for Storage Engine plugin. (MYSQL_DAEMON_PLUGIN) +*/ + +/* handlertons of different MySQL releases are incompatible */ +#define MYSQL_DAEMON_INTERFACE_VERSION (MYSQL_VERSION_ID << 8) + +/* + Here we define only the descriptor structure, that is referred from + st_mysql_plugin. +*/ + +struct st_mysql_daemon +{ + int interface_version; +}; + + +/************************************************************************* + API for I_S plugin. (MYSQL_INFORMATION_SCHEMA_PLUGIN) +*/ + +/* handlertons of different MySQL releases are incompatible */ +#define MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION (MYSQL_VERSION_ID << 8) + +/* + Here we define only the descriptor structure, that is referred from + st_mysql_plugin. +*/ + +struct st_mysql_information_schema +{ + int interface_version; +}; + + +/************************************************************************* + API for Storage Engine plugin. (MYSQL_STORAGE_ENGINE_PLUGIN) +*/ + +/* handlertons of different MySQL releases are incompatible */ +#define MYSQL_HANDLERTON_INTERFACE_VERSION (MYSQL_VERSION_ID << 8) + +/* + The real API is in the sql/handler.h + Here we define only the descriptor structure, that is referred from + st_mysql_plugin. +*/ + +struct st_mysql_storage_engine +{ + int interface_version; +}; + +struct handlerton; + + +/* + API for Replication plugin. (MYSQL_REPLICATION_PLUGIN) +*/ + #define MYSQL_REPLICATION_INTERFACE_VERSION 0x0100 + + /** + Replication plugin descriptor + */ + struct Mysql_replication { + int interface_version; + }; + +/************************************************************************* + st_mysql_value struct for reading values from mysqld. + Used by server variables framework to parse user-provided values. + Will be used for arguments when implementing UDFs. + + Note that val_str() returns a string in temporary memory + that will be freed at the end of statement. Copy the string + if you need it to persist. +*/ + +#define MYSQL_VALUE_TYPE_STRING 0 +#define MYSQL_VALUE_TYPE_REAL 1 +#define MYSQL_VALUE_TYPE_INT 2 + +struct st_mysql_value +{ + int (*value_type)(struct st_mysql_value *); + const char *(*val_str)(struct st_mysql_value *, char *buffer, int *length); + int (*val_real)(struct st_mysql_value *, double *realbuf); + int (*val_int)(struct st_mysql_value *, long long *intbuf); + int (*is_unsigned)(struct st_mysql_value *); +}; + + +/************************************************************************* + Miscellaneous functions for plugin implementors +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +int thd_in_lock_tables(const MYSQL_THD thd); +int thd_tablespace_op(const MYSQL_THD thd); +long long thd_test_options(const MYSQL_THD thd, long long test_options); +int thd_sql_command(const MYSQL_THD thd); +const char *thd_proc_info(MYSQL_THD thd, const char *info); +void **thd_ha_data(const MYSQL_THD thd, const struct handlerton *hton); +void thd_storage_lock_wait(MYSQL_THD thd, long long value); +int thd_tx_isolation(const MYSQL_THD thd); +char *thd_security_context(MYSQL_THD thd, char *buffer, unsigned int length, + unsigned int max_query_len); +/* Increments the row counter, see THD::row_count */ +void thd_inc_row_count(MYSQL_THD thd); + +/** + Create a temporary file. + + @details + The temporary file is created in a location specified by the mysql + server configuration (--tmpdir option). The caller does not need to + delete the file, it will be deleted automatically. + + @param prefix prefix for temporary file name + @retval -1 error + @retval >= 0 a file handle that can be passed to dup or my_close +*/ +int mysql_tmpfile(const char *prefix); + +/** + Check the killed state of a connection + + @details + In MySQL support for the KILL statement is cooperative. The KILL + statement only sets a "killed" flag. This function returns the value + of that flag. A thread should check it often, especially inside + time-consuming loops, and gracefully abort the operation if it is + non-zero. + + @param thd user thread connection handle + @retval 0 the connection is active + @retval 1 the connection has been killed +*/ +int thd_killed(const MYSQL_THD thd); + + +/** + Return the thread id of a user thread + + @param thd user thread connection handle + @return thread id +*/ +unsigned long thd_get_thread_id(const MYSQL_THD thd); + +/** + Get the XID for this connection's transaction + + @param thd user thread connection handle + @param xid location where identifier is stored +*/ +void thd_get_xid(const MYSQL_THD thd, MYSQL_XID *xid); + +/** + Invalidate the query cache for a given table. + + @param thd user thread connection handle + @param key databasename\\0tablename\\0 + @param key_length length of key in bytes, including the NUL bytes + @param using_trx flag: TRUE if using transactions, FALSE otherwise +*/ +void mysql_query_cache_invalidate4(MYSQL_THD thd, + const char *key, unsigned int key_length, + int using_trx); + + +/** + Provide a handler data getter to simplify coding +*/ +void *thd_get_ha_data(const MYSQL_THD thd, const struct handlerton *hton); + + +/** + Provide a handler data setter to simplify coding + + @details + Set ha_data pointer (storage engine per-connection information). + + To avoid unclean deactivation (uninstall) of storage engine plugin + in the middle of transaction, additional storage engine plugin + lock is acquired. + + If ha_data is not null and storage engine plugin was not locked + by thd_set_ha_data() in this connection before, storage engine + plugin gets locked. + + If ha_data is null and storage engine plugin was locked by + thd_set_ha_data() in this connection before, storage engine + plugin lock gets released. + + If handlerton::close_connection() didn't reset ha_data, server does + it immediately after calling handlerton::close_connection(). +*/ +void thd_set_ha_data(MYSQL_THD thd, const struct handlerton *hton, + const void *ha_data); +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/include/mysql/plugin_audit.h b/include/mysql/plugin_audit.h new file mode 100644 index 000000000..41505da64 --- /dev/null +++ b/include/mysql/plugin_audit.h @@ -0,0 +1,98 @@ +/* Copyright (C) 2007 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifndef _my_audit_h +#define _my_audit_h + +/************************************************************************* + API for Audit plugin. (MYSQL_AUDIT_PLUGIN) +*/ + +#include "plugin.h" + +#define MYSQL_AUDIT_CLASS_MASK_SIZE 1 + +#define MYSQL_AUDIT_INTERFACE_VERSION 0x0200 + +/* + The first word in every event class struct indicates the specific + class of the event. +*/ +struct mysql_event +{ + unsigned int event_class; +}; + + +/************************************************************************* + AUDIT CLASS : GENERAL + + LOG events occurs before emitting to the general query log. + ERROR events occur before transmitting errors to the user. + RESULT events occur after transmitting a resultset to the user. +*/ + +#define MYSQL_AUDIT_GENERAL_CLASS 0 +#define MYSQL_AUDIT_GENERAL_CLASSMASK (1 << MYSQL_AUDIT_GENERAL_CLASS) +#define MYSQL_AUDIT_GENERAL_LOG 0 +#define MYSQL_AUDIT_GENERAL_ERROR 1 +#define MYSQL_AUDIT_GENERAL_RESULT 2 + +struct mysql_event_general +{ + unsigned int event_class; + unsigned int event_subclass; + int general_error_code; + unsigned long general_thread_id; + const char *general_user; + unsigned int general_user_length; + const char *general_command; + unsigned int general_command_length; + const char *general_query; + unsigned int general_query_length; + struct charset_info_st *general_charset; + unsigned long long general_time; + unsigned long long general_rows; +}; + + +/************************************************************************* + Here we define the descriptor structure, that is referred from + st_mysql_plugin. + + release_thd() event occurs when the event class consumer is to be + disassociated from the specified THD. This would typically occur + before some operation which may require sleeping - such as when + waiting for the next query from the client. + + event_notify() is invoked whenever an event occurs which is of any + class for which the plugin has interest. The first word of the + mysql_event argument indicates the specific event class and the + remainder of the structure is as required for that class. + + class_mask is an array of bits used to indicate what event classes + that this plugin wants to receive. +*/ + +struct st_mysql_audit +{ + int interface_version; + void (*release_thd)(MYSQL_THD); + void (*event_notify)(MYSQL_THD, const struct mysql_event *); + unsigned long class_mask[MYSQL_AUDIT_CLASS_MASK_SIZE]; +}; + + +#endif diff --git a/include/mysql/plugin_auth.h b/include/mysql/plugin_auth.h new file mode 100644 index 000000000..420eb3bb8 --- /dev/null +++ b/include/mysql/plugin_auth.h @@ -0,0 +1,125 @@ +#ifndef MYSQL_PLUGIN_AUTH_INCLUDED +/* Copyright (C) 2010 Sun Microsystems, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/** + @file + + Authentication Plugin API. + + This file defines the API for server authentication plugins. +*/ + +#define MYSQL_PLUGIN_AUTH_INCLUDED + +#include + +#define MYSQL_AUTHENTICATION_INTERFACE_VERSION 0x0100 + +#include + +/* defines for MYSQL_SERVER_AUTH_INFO.password_used */ + +#define PASSWORD_USED_NO 0 +#define PASSWORD_USED_YES 1 +#define PASSWORD_USED_NO_MENTION 2 + + +/** + Provides server plugin access to authentication information +*/ +typedef struct st_mysql_server_auth_info +{ + /** + User name as sent by the client and shown in USER(). + NULL if the client packet with the user name was not received yet. + */ + char *user_name; + + /** + Length of user_name + */ + unsigned int user_name_length; + + /** + A corresponding column value from the mysql.user table for the + matching account name + */ + const char *auth_string; + + /** + Length of auth_string + */ + unsigned long auth_string_length; + + /** + Matching account name as found in the mysql.user table. + A plugin can override it with another name that will be + used by MySQL for authorization, and shown in CURRENT_USER() + */ + char authenticated_as[MYSQL_USERNAME_LENGTH+1]; + + + /** + The unique user name that was used by the plugin to authenticate. + Plugins should put null-terminated UTF-8 here. + Available through the @@EXTERNAL_USER variable. + */ + char external_user[512]; + + /** + This only affects the "Authentication failed. Password used: %s" + error message. has the following values : + 0 : %s will be NO. + 1 : %s will be YES. + 2 : there will be no %s. + Set it as appropriate or ignore at will. + */ + int password_used; + + /** + Set to the name of the connected client host, if it can be resolved, + or to its IP address otherwise. + */ + const char *host_or_ip; + + /** + Length of host_or_ip + */ + unsigned int host_or_ip_length; + +} MYSQL_SERVER_AUTH_INFO; + +/** + Server authentication plugin descriptor +*/ +struct st_mysql_auth +{ + int interface_version; /** version plugin uses */ + /** + A plugin that a client must use for authentication with this server + plugin. Can be NULL to mean "any plugin". + */ + const char *client_auth_plugin; + /** + Function provided by the plugin which should perform authentication (using + the vio functions if necessary) and return 0 if successful. The plugin can + also fill the info.authenticated_as field if a different username should be + used for authorization. + */ + int (*authenticate_user)(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info); +}; +#endif + diff --git a/include/mysql/plugin_auth_common.h b/include/mysql/plugin_auth_common.h new file mode 100644 index 000000000..4ad92d01b --- /dev/null +++ b/include/mysql/plugin_auth_common.h @@ -0,0 +1,105 @@ +#ifndef MYSQL_PLUGIN_AUTH_COMMON_INCLUDED +/* Copyright (C) 2010 Sun Microsystems, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/** + @file + + This file defines constants and data structures that are the same for + both client- and server-side authentication plugins. +*/ +#define MYSQL_PLUGIN_AUTH_COMMON_INCLUDED + +/** the max allowed length for a user name */ +#define MYSQL_USERNAME_LENGTH 48 + +/** + return values of the plugin authenticate_user() method. +*/ + +/** + Authentication failed. Additionally, all other CR_xxx values + (libmysql error code) can be used too. + + The client plugin may set the error code and the error message directly + in the MYSQL structure and return CR_ERROR. If a CR_xxx specific error + code was returned, an error message in the MYSQL structure will be + overwritten. If CR_ERROR is returned without setting the error in MYSQL, + CR_UNKNOWN_ERROR will be user. +*/ +#define CR_ERROR 0 +/** + Authentication (client part) was successful. It does not mean that the + authentication as a whole was successful, usually it only means + that the client was able to send the user name and the password to the + server. If CR_OK is returned, the libmysql reads the next packet expecting + it to be one of OK, ERROR, or CHANGE_PLUGIN packets. +*/ +#define CR_OK -1 +/** + Authentication was successful. + It means that the client has done its part successfully and also that + a plugin has read the last packet (one of OK, ERROR, CHANGE_PLUGIN). + In this case, libmysql will not read a packet from the server, + but it will use the data at mysql->net.read_pos. + + A plugin may return this value if the number of roundtrips in the + authentication protocol is not known in advance, and the client plugin + needs to read one packet more to determine if the authentication is finished + or not. +*/ +#define CR_OK_HANDSHAKE_COMPLETE -2 + +typedef struct st_plugin_vio_info +{ + enum { MYSQL_VIO_INVALID, MYSQL_VIO_TCP, MYSQL_VIO_SOCKET, + MYSQL_VIO_PIPE, MYSQL_VIO_MEMORY } protocol; + int socket; /**< it's set, if the protocol is SOCKET or TCP */ +#ifdef _WIN32 + HANDLE handle; /**< it's set, if the protocol is PIPE or MEMORY */ +#endif +} MYSQL_PLUGIN_VIO_INFO; + +/** + Provides plugin access to communication channel +*/ +typedef struct st_plugin_vio +{ + /** + Plugin provides a pointer reference and this function sets it to the + contents of any incoming packet. Returns the packet length, or -1 if + the plugin should terminate. + */ + int (*read_packet)(struct st_plugin_vio *vio, + unsigned char **buf); + + /** + Plugin provides a buffer with data and the length and this + function sends it as a packet. Returns 0 on success, 1 on failure. + */ + int (*write_packet)(struct st_plugin_vio *vio, + const unsigned char *packet, + int packet_len); + + /** + Fills in a st_plugin_vio_info structure, providing the information + about the connection. + */ + void (*info)(struct st_plugin_vio *vio, struct st_plugin_vio_info *info); + +} MYSQL_PLUGIN_VIO; + +#endif + diff --git a/include/mysql/plugin_ftparser.h b/include/mysql/plugin_ftparser.h new file mode 100644 index 000000000..7f9bde3a6 --- /dev/null +++ b/include/mysql/plugin_ftparser.h @@ -0,0 +1,211 @@ +/* Copyright (C) 2005 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifndef _my_plugin_ftparser_h +#define _my_plugin_ftparser_h +#include "plugin.h" + +/************************************************************************* + API for Full-text parser plugin. (MYSQL_FTPARSER_PLUGIN) +*/ + +#define MYSQL_FTPARSER_INTERFACE_VERSION 0x0100 + +/* Parsing modes. Set in MYSQL_FTPARSER_PARAM::mode */ +enum enum_ftparser_mode +{ +/* + Fast and simple mode. This mode is used for indexing, and natural + language queries. + + The parser is expected to return only those words that go into the + index. Stopwords or too short/long words should not be returned. The + 'boolean_info' argument of mysql_add_word() does not have to be set. +*/ + MYSQL_FTPARSER_SIMPLE_MODE= 0, + +/* + Parse with stopwords mode. This mode is used in boolean searches for + "phrase matching." + + The parser is not allowed to ignore words in this mode. Every word + should be returned, including stopwords and words that are too short + or long. The 'boolean_info' argument of mysql_add_word() does not + have to be set. +*/ + MYSQL_FTPARSER_WITH_STOPWORDS= 1, + +/* + Parse in boolean mode. This mode is used to parse a boolean query string. + + The parser should provide a valid MYSQL_FTPARSER_BOOLEAN_INFO + structure in the 'boolean_info' argument to mysql_add_word(). + Usually that means that the parser should recognize boolean operators + in the parsing stream and set appropriate fields in + MYSQL_FTPARSER_BOOLEAN_INFO structure accordingly. As for + MYSQL_FTPARSER_WITH_STOPWORDS mode, no word should be ignored. + Instead, use FT_TOKEN_STOPWORD for the token type of such a word. +*/ + MYSQL_FTPARSER_FULL_BOOLEAN_INFO= 2 +}; + +/* + Token types for boolean mode searching (used for the type member of + MYSQL_FTPARSER_BOOLEAN_INFO struct) + + FT_TOKEN_EOF: End of data. + FT_TOKEN_WORD: Regular word. + FT_TOKEN_LEFT_PAREN: Left parenthesis (start of group/sub-expression). + FT_TOKEN_RIGHT_PAREN: Right parenthesis (end of group/sub-expression). + FT_TOKEN_STOPWORD: Stopword. +*/ + +enum enum_ft_token_type +{ + FT_TOKEN_EOF= 0, + FT_TOKEN_WORD= 1, + FT_TOKEN_LEFT_PAREN= 2, + FT_TOKEN_RIGHT_PAREN= 3, + FT_TOKEN_STOPWORD= 4 +}; + +/* + This structure is used in boolean search mode only. It conveys + boolean-mode metadata to the MySQL search engine for every word in + the search query. A valid instance of this structure must be filled + in by the plugin parser and passed as an argument in the call to + mysql_add_word (the callback function in the MYSQL_FTPARSER_PARAM + structure) when a query is parsed in boolean mode. + + type: The token type. Should be one of the enum_ft_token_type values. + + yesno: Whether the word must be present for a match to occur: + >0 Must be present + <0 Must not be present + 0 Neither; the word is optional but its presence increases the relevance + With the default settings of the ft_boolean_syntax system variable, + >0 corresponds to the '+' operator, <0 corrresponds to the '-' operator, + and 0 means neither operator was used. + + weight_adjust: A weighting factor that determines how much a match + for the word counts. Positive values increase, negative - decrease the + relative word's importance in the query. + + wasign: The sign of the word's weight in the query. If it's non-negative + the match for the word will increase document relevance, if it's + negative - decrease (the word becomes a "noise word", the less of it the + better). + + trunc: Corresponds to the '*' operator in the default setting of the + ft_boolean_syntax system variable. +*/ + +typedef struct st_mysql_ftparser_boolean_info +{ + enum enum_ft_token_type type; + int yesno; + int weight_adjust; + char wasign; + char trunc; + /* These are parser state and must be removed. */ + char prev; + char *quot; +} MYSQL_FTPARSER_BOOLEAN_INFO; + +/* + The following flag means that buffer with a string (document, word) + may be overwritten by the caller before the end of the parsing (that is + before st_mysql_ftparser::deinit() call). If one needs the string + to survive between two successive calls of the parsing function, she + needs to save a copy of it. The flag may be set by MySQL before calling + st_mysql_ftparser::parse(), or it may be set by a plugin before calling + st_mysql_ftparser_param::mysql_parse() or + st_mysql_ftparser_param::mysql_add_word(). +*/ +#define MYSQL_FTFLAGS_NEED_COPY 1 + +/* + An argument of the full-text parser plugin. This structure is + filled in by MySQL server and passed to the parsing function of the + plugin as an in/out parameter. + + mysql_parse: A pointer to the built-in parser implementation of the + server. It's set by the server and can be used by the parser plugin + to invoke the MySQL default parser. If plugin's role is to extract + textual data from .doc, .pdf or .xml content, it might extract + plaintext from the content, and then pass the text to the default + MySQL parser to be parsed. + + mysql_add_word: A server callback to add a new word. When parsing + a document, the server sets this to point at a function that adds + the word to MySQL full-text index. When parsing a search query, + this function will add the new word to the list of words to search + for. The boolean_info argument can be NULL for all cases except + when mode is MYSQL_FTPARSER_FULL_BOOLEAN_INFO. + + ftparser_state: A generic pointer. The plugin can set it to point + to information to be used internally for its own purposes. + + mysql_ftparam: This is set by the server. It is used by MySQL functions + called via mysql_parse() and mysql_add_word() callback. The plugin + should not modify it. + + cs: Information about the character set of the document or query string. + + doc: A pointer to the document or query string to be parsed. + + length: Length of the document or query string, in bytes. + + flags: See MYSQL_FTFLAGS_* constants above. + + mode: The parsing mode. With boolean operators, with stopwords, or + nothing. See enum_ftparser_mode above. +*/ + +typedef struct st_mysql_ftparser_param +{ + int (*mysql_parse)(struct st_mysql_ftparser_param *, + char *doc, int doc_len); + int (*mysql_add_word)(struct st_mysql_ftparser_param *, + char *word, int word_len, + MYSQL_FTPARSER_BOOLEAN_INFO *boolean_info); + void *ftparser_state; + void *mysql_ftparam; + struct charset_info_st *cs; + char *doc; + int length; + int flags; + enum enum_ftparser_mode mode; +} MYSQL_FTPARSER_PARAM; + +/* + Full-text parser descriptor. + + interface_version is, e.g., MYSQL_FTPARSER_INTERFACE_VERSION. + The parsing, initialization, and deinitialization functions are + invoked per SQL statement for which the parser is used. +*/ + +struct st_mysql_ftparser +{ + int interface_version; + int (*parse)(MYSQL_FTPARSER_PARAM *param); + int (*init)(MYSQL_FTPARSER_PARAM *param); + int (*deinit)(MYSQL_FTPARSER_PARAM *param); +}; + + +#endif + diff --git a/include/mysql/psi/mysql_file.h b/include/mysql/psi/mysql_file.h new file mode 100644 index 000000000..de145f642 --- /dev/null +++ b/include/mysql/psi/mysql_file.h @@ -0,0 +1,1432 @@ +/* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +#ifndef MYSQL_FILE_H +#define MYSQL_FILE_H + +/* For strlen() */ +#include +/* For MY_STAT */ +#include +/* For my_chsize */ +#include + +/** + @file mysql/psi/mysql_file.h + Instrumentation helpers for mysys file io. + This header file provides the necessary declarations + to use the mysys file API with the performance schema instrumentation. + In some compilers (SunStudio), 'static inline' functions, when declared + but not used, are not optimized away (because they are unused) by default, + so that including a static inline function from a header file does + create unwanted dependencies, causing unresolved symbols at link time. + Other compilers, like gcc, optimize these dependencies by default. + + Since the instrumented APIs declared here are wrapper on top + of mysys file io APIs, including mysql/psi/mysql_file.h assumes that + the dependency on my_sys already exists. +*/ + +#include "mysql/psi/psi.h" + +/** + @defgroup File_instrumentation File Instrumentation + @ingroup Instrumentation_interface + @{ +*/ + +/** + @def mysql_file_fgets(P1, P2, F) + Instrumented fgets. + @c mysql_file_fgets is a replacement for @c fgets. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_fgets(P1, P2, F) \ + inline_mysql_file_fgets(__FILE__, __LINE__, P1, P2, F) +#else + #define mysql_file_fgets(P1, P2, F) \ + inline_mysql_file_fgets(P1, P2, F) +#endif + +/** + @def mysql_file_fgetc(F) + Instrumented fgetc. + @c mysql_file_fgetc is a replacement for @c fgetc. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_fgetc(F) inline_mysql_file_fgetc(__FILE__, __LINE__, F) +#else + #define mysql_file_fgetc(F) inline_mysql_file_fgetc(F) +#endif + +/** + @def mysql_file_fputs(P1, F) + Instrumented fputs. + @c mysql_file_fputs is a replacement for @c fputs. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_fputs(P1, F) \ + inline_mysql_file_fputs(__FILE__, __LINE__, P1, F) +#else + #define mysql_file_fputs(P1, F)\ + inline_mysql_file_fputs(P1, F) +#endif + +/** + @def mysql_file_fputc(P1, F) + Instrumented fputc. + @c mysql_file_fputc is a replacement for @c fputc. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_fputc(P1, F) \ + inline_mysql_file_fputc(__FILE__, __LINE__, P1, F) +#else + #define mysql_file_fputc(P1, F) \ + inline_mysql_file_fputc(P1, F) +#endif + +/** + @def mysql_file_fprintf + Instrumented fprintf. + @c mysql_file_fprintf is a replacement for @c fprintf. +*/ +#define mysql_file_fprintf inline_mysql_file_fprintf + +/** + @def mysql_file_vfprintf(F, P1, P2) + Instrumented vfprintf. + @c mysql_file_vfprintf is a replacement for @c vfprintf. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_vfprintf(F, P1, P2) \ + inline_mysql_file_vfprintf(__FILE__, __LINE__, F, P1, P2) +#else + #define mysql_file_vfprintf(F, P1, P2) \ + inline_mysql_file_vfprintf(F, P1, P2) +#endif + +/** + @def mysql_file_fflush(F, P1, P2) + Instrumented fflush. + @c mysql_file_fflush is a replacement for @c fflush. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_fflush(F) \ + inline_mysql_file_fflush(__FILE__, __LINE__, F) +#else + #define mysql_file_fflush(F) \ + inline_mysql_file_fflush(F) +#endif + +/** + @def mysql_file_feof(F) + Instrumented feof. + @c mysql_file_feof is a replacement for @c feof. +*/ +#define mysql_file_feof(F) inline_mysql_file_feof(F) + +/** + @def mysql_file_fstat(FN, S, FL) + Instrumented fstat. + @c mysql_file_fstat is a replacement for @c my_fstat. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_fstat(FN, S, FL) \ + inline_mysql_file_fstat(__FILE__, __LINE__, FN, S, FL) +#else + #define mysql_file_fstat(FN, S, FL) \ + inline_mysql_file_fstat(FN, S, FL) +#endif + +/** + @def mysql_file_stat(K, FN, S, FL) + Instrumented stat. + @c mysql_file_stat is a replacement for @c my_stat. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_stat(K, FN, S, FL) \ + inline_mysql_file_stat(K, __FILE__, __LINE__, FN, S, FL) +#else + #define mysql_file_stat(K, FN, S, FL) \ + inline_mysql_file_stat(FN, S, FL) +#endif + +/** + @def mysql_file_chsize(F, P1, P2, P3) + Instrumented chsize. + @c mysql_file_chsize is a replacement for @c my_chsize. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_chsize(F, P1, P2, P3) \ + inline_mysql_file_chsize(__FILE__, __LINE__, F, P1, P2, P3) +#else + #define mysql_file_chsize(F, P1, P2, P3) \ + inline_mysql_file_chsize(F, P1, P2, P3) +#endif + +/** + @def mysql_file_fopen(K, N, F1, F2) + Instrumented fopen. + @c mysql_file_fopen is a replacement for @c my_fopen. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_fopen(K, N, F1, F2) \ + inline_mysql_file_fopen(K, __FILE__, __LINE__, N, F1, F2) +#else + #define mysql_file_fopen(K, N, F1, F2) \ + inline_mysql_file_fopen(N, F1, F2) +#endif + +/** + @def mysql_file_fclose(FD, FL) + Instrumented fclose. + @c mysql_file_fclose is a replacement for @c my_fclose. + Without the instrumentation, this call will have the same behavior as the + undocumented and possibly platform specific my_fclose(NULL, ...) behavior. + With the instrumentation, mysql_fclose(NULL, ...) will safely return 0, + which is an extension compared to my_fclose and is therefore compliant. + mysql_fclose is on purpose *not* implementing + @code DBUG_ASSERT(file != NULL) @endcode, + since doing so could introduce regressions. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_fclose(FD, FL) \ + inline_mysql_file_fclose(__FILE__, __LINE__, FD, FL) +#else + #define mysql_file_fclose(FD, FL) \ + inline_mysql_file_fclose(FD, FL) +#endif + +/** + @def mysql_file_fread(FD, P1, P2, P3) + Instrumented fread. + @c mysql_file_fread is a replacement for @c my_fread. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_fread(FD, P1, P2, P3) \ + inline_mysql_file_fread(__FILE__, __LINE__, FD, P1, P2, P3) +#else + #define mysql_file_fread(FD, P1, P2, P3) \ + inline_mysql_file_fread(FD, P1, P2, P3) +#endif + +/** + @def mysql_file_fwrite(FD, P1, P2, P3) + Instrumented fwrite. + @c mysql_file_fwrite is a replacement for @c my_fwrite. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_fwrite(FD, P1, P2, P3) \ + inline_mysql_file_fwrite(__FILE__, __LINE__, FD, P1, P2, P3) +#else + #define mysql_file_fwrite(FD, P1, P2, P3) \ + inline_mysql_file_fwrite(FD, P1, P2, P3) +#endif + +/** + @def mysql_file_fseek(FD, P, W, F) + Instrumented fseek. + @c mysql_file_fseek is a replacement for @c my_fseek. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_fseek(FD, P, W, F) \ + inline_mysql_file_fseek(__FILE__, __LINE__, FD, P, W, F) +#else + #define mysql_file_fseek(FD, P, W, F) \ + inline_mysql_file_fseek(FD, P, W, F) +#endif + +/** + @def mysql_file_ftell(FD, F) + Instrumented ftell. + @c mysql_file_ftell is a replacement for @c my_ftell. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_ftell(FD, F) \ + inline_mysql_file_ftell(__FILE__, __LINE__, FD, F) +#else + #define mysql_file_ftell(FD, F) \ + inline_mysql_file_ftell(FD, F) +#endif + +/** + @def mysql_file_create(K, N, F1, F2, F3) + Instrumented create. + @c mysql_file_create is a replacement for @c my_create. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_create(K, N, F1, F2, F3) \ + inline_mysql_file_create(K, __FILE__, __LINE__, N, F1, F2, F3) +#else + #define mysql_file_create(K, N, F1, F2, F3) \ + inline_mysql_file_create(N, F1, F2, F3) +#endif + +/** + @def mysql_file_create_temp(K, T, D, P, M, F) + Instrumented create_temp_file. + @c mysql_file_create_temp is a replacement for @c create_temp_file. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_create_temp(K, T, D, P, M, F) \ + inline_mysql_file_create_temp(K, T, D, P, M, F) +#else + #define mysql_file_create_temp(K, T, D, P, M, F) \ + inline_mysql_file_create_temp(T, D, P, M, F) +#endif + +/** + @def mysql_file_open(K, N, F1, F2) + Instrumented open. + @c mysql_file_open is a replacement for @c my_open. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_open(K, N, F1, F2) \ + inline_mysql_file_open(K, __FILE__, __LINE__, N, F1, F2) +#else + #define mysql_file_open(K, N, F1, F2) \ + inline_mysql_file_open(N, F1, F2) +#endif + +/** + @def mysql_file_close(FD, F) + Instrumented close. + @c mysql_file_close is a replacement for @c my_close. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_close(FD, F) \ + inline_mysql_file_close(__FILE__, __LINE__, FD, F) +#else + #define mysql_file_close(FD, F) \ + inline_mysql_file_close(FD, F) +#endif + +/** + @def mysql_file_read(FD, B, S, F) + Instrumented read. + @c mysql_read is a replacement for @c my_read. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_read(FD, B, S, F) \ + inline_mysql_file_read(__FILE__, __LINE__, FD, B, S, F) +#else + #define mysql_file_read(FD, B, S, F) \ + inline_mysql_file_read(FD, B, S, F) +#endif + +/** + @def mysql_file_write(FD, B, S, F) + Instrumented write. + @c mysql_file_write is a replacement for @c my_write. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_write(FD, B, S, F) \ + inline_mysql_file_write(__FILE__, __LINE__, FD, B, S, F) +#else + #define mysql_file_write(FD, B, S, F) \ + inline_mysql_file_write(FD, B, S, F) +#endif + +/** + @def mysql_file_pread(FD, B, S, O, F) + Instrumented pread. + @c mysql_pread is a replacement for @c my_pread. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_pread(FD, B, S, O, F) \ + inline_mysql_file_pread(__FILE__, __LINE__, FD, B, S, O, F) +#else + #define mysql_file_pread(FD, B, S, O, F) \ + inline_mysql_file_pread(FD, B, S, O, F) +#endif + +/** + @def mysql_file_pwrite(FD, B, S, O, F) + Instrumented pwrite. + @c mysql_file_pwrite is a replacement for @c my_pwrite. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_pwrite(FD, B, S, O, F) \ + inline_mysql_file_pwrite(__FILE__, __LINE__, FD, B, S, O, F) +#else + #define mysql_file_pwrite(FD, B, S, O, F) \ + inline_mysql_file_pwrite(FD, B, S, O, F) +#endif + +/** + @def mysql_file_seek(FD, P, W, F) + Instrumented seek. + @c mysql_file_seek is a replacement for @c my_seek. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_seek(FD, P, W, F) \ + inline_mysql_file_seek(__FILE__, __LINE__, FD, P, W, F) +#else + #define mysql_file_seek(FD, P, W, F) \ + inline_mysql_file_seek(FD, P, W, F) +#endif + +/** + @def mysql_file_tell(FD, F) + Instrumented tell. + @c mysql_file_tell is a replacement for @c my_tell. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_tell(FD, F) \ + inline_mysql_file_tell(__FILE__, __LINE__, FD, F) +#else + #define mysql_file_tell(FD, F) \ + inline_mysql_file_tell(FD, F) +#endif + +/** + @def mysql_file_delete(K, P1, P2) + Instrumented delete. + @c mysql_file_delete is a replacement for @c my_delete. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_delete(K, P1, P2) \ + inline_mysql_file_delete(K, __FILE__, __LINE__, P1, P2) +#else + #define mysql_file_delete(K, P1, P2) \ + inline_mysql_file_delete(P1, P2) +#endif + +/** + @def mysql_file_rename(K, P1, P2, P3) + Instrumented rename. + @c mysql_file_rename is a replacement for @c my_rename. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_rename(K, P1, P2, P3) \ + inline_mysql_file_rename(K, __FILE__, __LINE__, P1, P2, P3) +#else + #define mysql_file_rename(K, P1, P2, P3) \ + inline_mysql_file_rename(P1, P2, P3) +#endif + +/** + @def mysql_file_create_with_symlink(K, P1, P2, P3, P4, P5) + Instrumented create with symbolic link. + @c mysql_file_create_with_symlink is a replacement + for @c my_create_with_symlink. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_create_with_symlink(K, P1, P2, P3, P4, P5) \ + inline_mysql_file_create_with_symlink(K, __FILE__, __LINE__, \ + P1, P2, P3, P4, P5) +#else + #define mysql_file_create_with_symlink(K, P1, P2, P3, P4, P5) \ + inline_mysql_file_create_with_symlink(P1, P2, P3, P4, P5) +#endif + +/** + @def mysql_file_delete_with_symlink(K, P1, P2) + Instrumented delete with symbolic link. + @c mysql_file_delete_with_symlink is a replacement + for @c my_delete_with_symlink. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_delete_with_symlink(K, P1, P2) \ + inline_mysql_file_delete_with_symlink(K, __FILE__, __LINE__, P1, P2) +#else + #define mysql_file_delete_with_symlink(K, P1, P2) \ + inline_mysql_file_delete_with_symlink(P1, P2) +#endif + +/** + @def mysql_file_rename_with_symlink(K, P1, P2, P3) + Instrumented rename with symbolic link. + @c mysql_file_rename_with_symlink is a replacement + for @c my_rename_with_symlink. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_rename_with_symlink(K, P1, P2, P3) \ + inline_mysql_file_rename_with_symlink(K, __FILE__, __LINE__, P1, P2, P3) +#else + #define mysql_file_rename_with_symlink(K, P1, P2, P3) \ + inline_mysql_file_rename_with_symlink(P1, P2, P3) +#endif + +/** + @def mysql_file_sync(P1, P2) + Instrumented file sync. + @c mysql_file_sync is a replacement for @c my_sync. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_file_sync(P1, P2) \ + inline_mysql_file_sync(__FILE__, __LINE__, P1, P2) +#else + #define mysql_file_sync(P1, P2) \ + inline_mysql_file_sync(P1, P2) +#endif + +/** + An instrumented FILE structure. + @sa MYSQL_FILE +*/ +struct st_mysql_file +{ + /** The real file. */ + FILE *m_file; + /** + The instrumentation hook. + Note that this hook is not conditionally defined, + for binary compatibility of the @c MYSQL_FILE interface. + */ + struct PSI_file *m_psi; +}; + +/** + Type of an instrumented file. + @c MYSQL_FILE is a drop-in replacement for @c FILE. + @sa mysql_file_open +*/ +typedef struct st_mysql_file MYSQL_FILE; + +static inline char * +inline_mysql_file_fgets( +#ifdef HAVE_PSI_INTERFACE + const char *src_file, uint src_line, +#endif + char *str, int size, MYSQL_FILE *file) +{ + char *result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + if (likely(PSI_server && file->m_psi)) + { + locker= PSI_server->get_thread_file_stream_locker(&state, file->m_psi, + PSI_FILE_READ); + if (likely(locker != NULL)) + PSI_server->start_file_wait(locker, (size_t) size, src_file, src_line); + } +#endif + result= fgets(str, size, file->m_file); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_file_wait(locker, result ? strlen(result) : 0); +#endif + return result; +} + +static inline int +inline_mysql_file_fgetc( +#ifdef HAVE_PSI_INTERFACE + const char *src_file, uint src_line, +#endif + MYSQL_FILE *file) +{ + int result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + if (likely(PSI_server && file->m_psi)) + { + locker= PSI_server->get_thread_file_stream_locker(&state, file->m_psi, + PSI_FILE_READ); + if (likely(locker != NULL)) + PSI_server->start_file_wait(locker, (size_t) 1, src_file, src_line); + } +#endif + result= fgetc(file->m_file); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_file_wait(locker, (size_t) 1); +#endif + return result; +} + +static inline int +inline_mysql_file_fputs( +#ifdef HAVE_PSI_INTERFACE + const char *src_file, uint src_line, +#endif + const char *str, MYSQL_FILE *file) +{ + int result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + size_t bytes= 0; + if (likely(PSI_server && file->m_psi)) + { + locker= PSI_server->get_thread_file_stream_locker(&state, file->m_psi, + PSI_FILE_WRITE); + if (likely(locker != NULL)) + { + bytes= str ? strlen(str) : 0; + PSI_server->start_file_wait(locker, bytes, src_file, src_line); + } + } +#endif + result= fputs(str, file->m_file); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_file_wait(locker, bytes); +#endif + return result; +} + +static inline int +inline_mysql_file_fputc( +#ifdef HAVE_PSI_INTERFACE + const char *src_file, uint src_line, +#endif + char c, MYSQL_FILE *file) +{ + int result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + if (likely(PSI_server && file->m_psi)) + { + locker= PSI_server->get_thread_file_stream_locker(&state, file->m_psi, + PSI_FILE_WRITE); + if (likely(locker != NULL)) + PSI_server->start_file_wait(locker, (size_t) 1, src_file, src_line); + } +#endif + result= fputc(c, file->m_file); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_file_wait(locker, (size_t) 1); +#endif + return result; +} + +static inline int +inline_mysql_file_fprintf(MYSQL_FILE *file, const char *format, ...) +{ + /* + TODO: figure out how to pass src_file and src_line from the caller. + */ + int result; + va_list args; +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + if (likely(PSI_server && file->m_psi)) + { + locker= PSI_server->get_thread_file_stream_locker(&state, file->m_psi, + PSI_FILE_WRITE); + if (likely(locker != NULL)) + PSI_server->start_file_wait(locker, (size_t) 0, __FILE__, __LINE__); + } +#endif + va_start(args, format); + result= vfprintf(file->m_file, format, args); + va_end(args); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_file_wait(locker, (size_t) result); +#endif + return result; +} + +static inline int +inline_mysql_file_vfprintf( +#ifdef HAVE_PSI_INTERFACE + const char *src_file, uint src_line, +#endif + MYSQL_FILE *file, const char *format, va_list args) +{ + int result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + if (likely(PSI_server && file->m_psi)) + { + locker= PSI_server->get_thread_file_stream_locker(&state, file->m_psi, + PSI_FILE_WRITE); + if (likely(locker != NULL)) + PSI_server->start_file_wait(locker, (size_t) 0, src_file, src_line); + } +#endif + result= vfprintf(file->m_file, format, args); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_file_wait(locker, (size_t) result); +#endif + return result; +} + +static inline int +inline_mysql_file_fflush( +#ifdef HAVE_PSI_INTERFACE + const char *src_file, uint src_line, +#endif + MYSQL_FILE *file) +{ + int result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + if (likely(PSI_server && file->m_psi)) + { + locker= PSI_server->get_thread_file_stream_locker(&state, file->m_psi, + PSI_FILE_FLUSH); + if (likely(locker != NULL)) + PSI_server->start_file_wait(locker, (size_t) 0, src_file, src_line); + } +#endif + result= fflush(file->m_file); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_file_wait(locker, (size_t) 0); +#endif + return result; +} + +static inline int inline_mysql_file_feof(MYSQL_FILE *file) +{ + /* Not instrumented, there is no wait involved */ + return feof(file->m_file); +} + +static inline int +inline_mysql_file_fstat( +#ifdef HAVE_PSI_INTERFACE + const char *src_file, uint src_line, +#endif + int filenr, MY_STAT *stat_area, myf flags) +{ + int result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + if (likely(PSI_server != NULL)) + { + locker= PSI_server->get_thread_file_descriptor_locker(&state, filenr, + PSI_FILE_FSTAT); + if (likely(locker != NULL)) + PSI_server->start_file_wait(locker, (size_t) 0, src_file, src_line); + } +#endif + result= my_fstat(filenr, stat_area, flags); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_file_wait(locker, (size_t) 0); +#endif + return result; +} + +static inline MY_STAT * +inline_mysql_file_stat( +#ifdef HAVE_PSI_INTERFACE + PSI_file_key key, const char *src_file, uint src_line, +#endif + const char *path, MY_STAT *stat_area, myf flags) +{ + MY_STAT *result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + if (likely(PSI_server != NULL)) + { + locker= PSI_server->get_thread_file_name_locker(&state, + key, PSI_FILE_STAT, + path, &locker); + if (likely(locker != NULL)) + PSI_server->start_file_open_wait(locker, src_file, src_line); + } +#endif + result= my_stat(path, stat_area, flags); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_file_wait(locker, (size_t) 0); +#endif + return result; +} + +static inline int +inline_mysql_file_chsize( +#ifdef HAVE_PSI_INTERFACE + const char *src_file, uint src_line, +#endif + File file, my_off_t newlength, int filler, myf flags) +{ + int result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + if (likely(PSI_server != NULL)) + { + locker= PSI_server->get_thread_file_descriptor_locker(&state, file, + PSI_FILE_CHSIZE); + if (likely(locker != NULL)) + PSI_server->start_file_wait(locker, (size_t) newlength, src_file, + src_line); + } +#endif + result= my_chsize(file, newlength, filler, flags); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_file_wait(locker, (size_t) newlength); +#endif + return result; +} + +static inline MYSQL_FILE* +inline_mysql_file_fopen( +#ifdef HAVE_PSI_INTERFACE + PSI_file_key key, const char *src_file, uint src_line, +#endif + const char *filename, int flags, myf myFlags) +{ + MYSQL_FILE *that; + that= (MYSQL_FILE*) my_malloc(sizeof(MYSQL_FILE), MYF(MY_WME)); + if (likely(that != NULL)) + { + that->m_psi= NULL; + { +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + if (likely(PSI_server != NULL)) + { + locker= PSI_server->get_thread_file_name_locker + (&state, key, PSI_FILE_STREAM_OPEN, filename, that); + if (likely(locker != NULL)) + that->m_psi= PSI_server->start_file_open_wait(locker, src_file, + src_line); + } +#endif + that->m_file= my_fopen(filename, flags, myFlags); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_file_open_wait(locker); +#endif + if (unlikely(that->m_file == NULL)) + { + my_free(that); + return NULL; + } + } + } + return that; +} + +static inline int +inline_mysql_file_fclose( +#ifdef HAVE_PSI_INTERFACE + const char *src_file, uint src_line, +#endif + MYSQL_FILE *file, myf flags) +{ + int result= 0; + if (likely(file != NULL)) + { +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + DBUG_ASSERT(file != NULL); + if (likely(PSI_server && file->m_psi)) + { + locker= PSI_server->get_thread_file_stream_locker(&state, file->m_psi, + PSI_FILE_STREAM_CLOSE); + if (likely(locker != NULL)) + PSI_server->start_file_wait(locker, (size_t) 0, src_file, src_line); + } +#endif + result= my_fclose(file->m_file, flags); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_file_wait(locker, (size_t) 0); +#endif + my_free(file); + } + return result; +} + +static inline size_t +inline_mysql_file_fread( +#ifdef HAVE_PSI_INTERFACE + const char *src_file, uint src_line, +#endif + MYSQL_FILE *file, uchar *buffer, size_t count, myf flags) +{ + size_t result= 0; +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + if (likely(PSI_server && file->m_psi)) + { + locker= PSI_server->get_thread_file_stream_locker(&state, file->m_psi, + PSI_FILE_READ); + if (likely(locker != NULL)) + PSI_server->start_file_wait(locker, count, src_file, src_line); + } +#endif + result= my_fread(file->m_file, buffer, count, flags); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + { + size_t bytes_read; + if (flags & (MY_NABP | MY_FNABP)) + bytes_read= (result == 0) ? count : 0; + else + bytes_read= (result != MY_FILE_ERROR) ? result : 0; + PSI_server->end_file_wait(locker, bytes_read); + } +#endif + return result; +} + +static inline size_t +inline_mysql_file_fwrite( +#ifdef HAVE_PSI_INTERFACE + const char *src_file, uint src_line, +#endif + MYSQL_FILE *file, const uchar *buffer, size_t count, myf flags) +{ + size_t result= 0; +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + if (likely(PSI_server && file->m_psi)) + { + locker= PSI_server->get_thread_file_stream_locker(&state, file->m_psi, + PSI_FILE_WRITE); + if (likely(locker != NULL)) + PSI_server->start_file_wait(locker, count, src_file, src_line); + } +#endif + result= my_fwrite(file->m_file, buffer, count, flags); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + { + size_t bytes_written; + if (flags & (MY_NABP | MY_FNABP)) + bytes_written= (result == 0) ? count : 0; + else + bytes_written= (result != MY_FILE_ERROR) ? result : 0; + PSI_server->end_file_wait(locker, bytes_written); + } +#endif + return result; +} + +static inline my_off_t +inline_mysql_file_fseek( +#ifdef HAVE_PSI_INTERFACE + const char *src_file, uint src_line, +#endif + MYSQL_FILE *file, my_off_t pos, int whence, myf flags) +{ + my_off_t result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + if (likely(PSI_server && file->m_psi)) + { + locker= PSI_server->get_thread_file_stream_locker(&state, file->m_psi, + PSI_FILE_SEEK); + if (likely(locker != NULL)) + PSI_server->start_file_wait(locker, (size_t) 0, src_file, src_line); + } +#endif + result= my_fseek(file->m_file, pos, whence, flags); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_file_wait(locker, (size_t) 0); +#endif + return result; +} + +static inline my_off_t +inline_mysql_file_ftell( +#ifdef HAVE_PSI_INTERFACE + const char *src_file, uint src_line, +#endif + MYSQL_FILE *file, myf flags) +{ + my_off_t result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + if (likely(PSI_server && file->m_psi)) + { + locker= PSI_server->get_thread_file_stream_locker(&state, file->m_psi, + PSI_FILE_TELL); + if (likely(locker != NULL)) + PSI_server->start_file_wait(locker, (size_t) 0, src_file, src_line); + } +#endif + result= my_ftell(file->m_file, flags); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_file_wait(locker, (size_t) 0); +#endif + return result; +} + +static inline File +inline_mysql_file_create( +#ifdef HAVE_PSI_INTERFACE + PSI_file_key key, const char *src_file, uint src_line, +#endif + const char *filename, int create_flags, int access_flags, myf myFlags) +{ + File file; +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + if (likely(PSI_server != NULL)) + { + locker= PSI_server->get_thread_file_name_locker(&state, key, PSI_FILE_CREATE, + filename, &locker); + if (likely(locker != NULL)) + PSI_server->start_file_open_wait(locker, src_file, src_line); + } +#endif + file= my_create(filename, create_flags, access_flags, myFlags); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_file_open_wait_and_bind_to_descriptor(locker, file); +#endif + return file; +} + +static inline File +inline_mysql_file_create_temp( +#ifdef HAVE_PSI_INTERFACE + PSI_file_key key, +#endif + char *to, const char *dir, const char *pfx, int mode, myf myFlags) +{ + File file; + /* + TODO: This event is instrumented, but not timed. + The problem is that the file name is now known + before the create_temp_file call. + */ + file= create_temp_file(to, dir, pfx, mode, myFlags); +#ifdef HAVE_PSI_INTERFACE + if (likely(PSI_server != NULL)) + PSI_server->create_file(key, to, file); +#endif + return file; +} + +static inline File +inline_mysql_file_open( +#ifdef HAVE_PSI_INTERFACE + PSI_file_key key, const char *src_file, uint src_line, +#endif + const char *filename, int flags, myf myFlags) +{ + File file; +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + if (likely(PSI_server != NULL)) + { + locker= PSI_server->get_thread_file_name_locker(&state, key, PSI_FILE_OPEN, + filename, &locker); + if (likely(locker != NULL)) + PSI_server->start_file_open_wait(locker, src_file, src_line); + } +#endif + file= my_open(filename, flags, myFlags); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_file_open_wait_and_bind_to_descriptor(locker, file); +#endif + return file; +} + +static inline int +inline_mysql_file_close( +#ifdef HAVE_PSI_INTERFACE + const char *src_file, uint src_line, +#endif + File file, myf flags) +{ + int result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + if (likely(PSI_server != NULL)) + { + locker= PSI_server->get_thread_file_descriptor_locker(&state, file, + PSI_FILE_CLOSE); + if (likely(locker != NULL)) + PSI_server->start_file_wait(locker, (size_t) 0, src_file, src_line); + } +#endif + result= my_close(file, flags); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_file_wait(locker, (size_t) 0); +#endif + return result; +} + +static inline size_t +inline_mysql_file_read( +#ifdef HAVE_PSI_INTERFACE + const char *src_file, uint src_line, +#endif + File file, uchar *buffer, size_t count, myf flags) +{ + size_t result= 0; +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + if (likely(PSI_server != NULL)) + { + locker= PSI_server->get_thread_file_descriptor_locker(&state, file, + PSI_FILE_READ); + if (likely(locker != NULL)) + PSI_server->start_file_wait(locker, count, src_file, src_line); + } +#endif + result= my_read(file, buffer, count, flags); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + { + size_t bytes_read; + if (flags & (MY_NABP | MY_FNABP)) + bytes_read= (result == 0) ? count : 0; + else + bytes_read= (result != MY_FILE_ERROR) ? result : 0; + PSI_server->end_file_wait(locker, bytes_read); + } +#endif + return result; +} + +static inline size_t +inline_mysql_file_write( +#ifdef HAVE_PSI_INTERFACE + const char *src_file, uint src_line, +#endif + File file, const uchar *buffer, size_t count, myf flags) +{ + size_t result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + if (likely(PSI_server != NULL)) + { + locker= PSI_server->get_thread_file_descriptor_locker(&state, file, + PSI_FILE_WRITE); + if (likely(locker != NULL)) + PSI_server->start_file_wait(locker, count, src_file, src_line); + } +#endif + result= my_write(file, buffer, count, flags); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + { + size_t bytes_written; + if (flags & (MY_NABP | MY_FNABP)) + bytes_written= (result == 0) ? count : 0; + else + bytes_written= (result != MY_FILE_ERROR) ? result : 0; + PSI_server->end_file_wait(locker, bytes_written); + } +#endif + return result; +} + +static inline size_t +inline_mysql_file_pread( +#ifdef HAVE_PSI_INTERFACE + const char *src_file, uint src_line, +#endif + File file, uchar *buffer, size_t count, my_off_t offset, myf flags) +{ + size_t result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + if (likely(PSI_server != NULL)) + { + locker= PSI_server->get_thread_file_descriptor_locker(&state, file, PSI_FILE_READ); + if (likely(locker != NULL)) + PSI_server->start_file_wait(locker, count, src_file, src_line); + } +#endif + result= my_pread(file, buffer, count, offset, flags); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + { + size_t bytes_read; + if (flags & (MY_NABP | MY_FNABP)) + bytes_read= (result == 0) ? count : 0; + else + bytes_read= (result != MY_FILE_ERROR) ? result : 0; + PSI_server->end_file_wait(locker, bytes_read); + } +#endif + return result; +} + +static inline size_t +inline_mysql_file_pwrite( +#ifdef HAVE_PSI_INTERFACE + const char *src_file, uint src_line, +#endif + File file, const uchar *buffer, size_t count, my_off_t offset, myf flags) +{ + size_t result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + if (likely(PSI_server != NULL)) + { + locker= PSI_server->get_thread_file_descriptor_locker(&state, file, + PSI_FILE_WRITE); + if (likely(locker != NULL)) + PSI_server->start_file_wait(locker, count, src_file, src_line); + } +#endif + result= my_pwrite(file, buffer, count, offset, flags); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + { + size_t bytes_written; + if (flags & (MY_NABP | MY_FNABP)) + bytes_written= (result == 0) ? count : 0; + else + bytes_written= (result != MY_FILE_ERROR) ? result : 0; + PSI_server->end_file_wait(locker, bytes_written); + } +#endif + return result; +} + +static inline my_off_t +inline_mysql_file_seek( +#ifdef HAVE_PSI_INTERFACE + const char *src_file, uint src_line, +#endif + File file, my_off_t pos, int whence, myf flags) +{ + my_off_t result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + if (likely(PSI_server != NULL)) + { + locker= PSI_server->get_thread_file_descriptor_locker(&state, file, PSI_FILE_SEEK); + if (likely(locker != NULL)) + PSI_server->start_file_wait(locker, (size_t) 0, src_file, src_line); + } +#endif + result= my_seek(file, pos, whence, flags); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_file_wait(locker, (size_t) 0); +#endif + return result; +} + +static inline my_off_t +inline_mysql_file_tell( +#ifdef HAVE_PSI_INTERFACE + const char *src_file, uint src_line, +#endif + File file, myf flags) +{ + my_off_t result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + if (likely(PSI_server != NULL)) + { + locker= PSI_server->get_thread_file_descriptor_locker(&state, file, PSI_FILE_TELL); + if (likely(locker != NULL)) + PSI_server->start_file_wait(locker, (size_t) 0, src_file, src_line); + } +#endif + result= my_tell(file, flags); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_file_wait(locker, (size_t) 0); +#endif + return result; +} + +static inline int +inline_mysql_file_delete( +#ifdef HAVE_PSI_INTERFACE + PSI_file_key key, const char *src_file, uint src_line, +#endif + const char *name, myf flags) +{ + int result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + if (likely(PSI_server != NULL)) + { + locker= PSI_server->get_thread_file_name_locker(&state, key, PSI_FILE_DELETE, + name, &locker); + if (likely(locker != NULL)) + PSI_server->start_file_wait(locker, (size_t) 0, src_file, src_line); + } +#endif + result= my_delete(name, flags); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_file_wait(locker, (size_t) 0); +#endif + return result; +} + +static inline int +inline_mysql_file_rename( +#ifdef HAVE_PSI_INTERFACE + PSI_file_key key, const char *src_file, uint src_line, +#endif + const char *from, const char *to, myf flags) +{ + int result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + if (likely(PSI_server != NULL)) + { + locker= PSI_server->get_thread_file_name_locker(&state, key, PSI_FILE_RENAME, + to, &locker); + if (likely(locker != NULL)) + PSI_server->start_file_wait(locker, (size_t) 0, src_file, src_line); + } +#endif + result= my_rename(from, to, flags); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_file_wait(locker, (size_t) 0); +#endif + return result; +} + +static inline File +inline_mysql_file_create_with_symlink( +#ifdef HAVE_PSI_INTERFACE + PSI_file_key key, const char *src_file, uint src_line, +#endif + const char *linkname, const char *filename, int create_flags, + int access_flags, myf flags) +{ + File file; +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + if (likely(PSI_server != NULL)) + { + locker= PSI_server->get_thread_file_name_locker(&state, key, PSI_FILE_CREATE, + filename, &locker); + if (likely(locker != NULL)) + PSI_server->start_file_open_wait(locker, src_file, src_line); + } +#endif + file= my_create_with_symlink(linkname, filename, create_flags, access_flags, + flags); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_file_open_wait_and_bind_to_descriptor(locker, file); +#endif + return file; +} + +static inline int +inline_mysql_file_delete_with_symlink( +#ifdef HAVE_PSI_INTERFACE + PSI_file_key key, const char *src_file, uint src_line, +#endif + const char *name, myf flags) +{ + int result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + if (likely(PSI_server != NULL)) + { + locker= PSI_server->get_thread_file_name_locker(&state, key, PSI_FILE_DELETE, + name, &locker); + if (likely(locker != NULL)) + PSI_server->start_file_wait(locker, (size_t) 0, src_file, src_line); + } +#endif + result= my_delete_with_symlink(name, flags); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_file_wait(locker, (size_t) 0); +#endif + return result; +} + +static inline int +inline_mysql_file_rename_with_symlink( +#ifdef HAVE_PSI_INTERFACE + PSI_file_key key, const char *src_file, uint src_line, +#endif + const char *from, const char *to, myf flags) +{ + int result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + if (likely(PSI_server != NULL)) + { + locker= PSI_server->get_thread_file_name_locker(&state, key, PSI_FILE_RENAME, + to, &locker); + if (likely(locker != NULL)) + PSI_server->start_file_wait(locker, (size_t) 0, src_file, src_line); + } +#endif + result= my_rename_with_symlink(from, to, flags); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_file_wait(locker, (size_t) 0); +#endif + return result; +} + +static inline int +inline_mysql_file_sync( +#ifdef HAVE_PSI_INTERFACE + const char *src_file, uint src_line, +#endif + File fd, myf flags) +{ + int result= 0; +#ifdef HAVE_PSI_INTERFACE + struct PSI_file_locker *locker= NULL; + PSI_file_locker_state state; + if (likely(PSI_server != NULL)) + { + locker= PSI_server->get_thread_file_descriptor_locker(&state, fd, PSI_FILE_SYNC); + if (likely(locker != NULL)) + PSI_server->start_file_wait(locker, (size_t) 0, src_file, src_line); + } +#endif + result= my_sync(fd, flags); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_file_wait(locker, (size_t) 0); +#endif + return result; +} + +/** @} (end of group File_instrumentation) */ + +#endif + diff --git a/include/mysql/psi/mysql_thread.h b/include/mysql/psi/mysql_thread.h new file mode 100644 index 000000000..5b8ea3dc5 --- /dev/null +++ b/include/mysql/psi/mysql_thread.h @@ -0,0 +1,1071 @@ +/* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +#ifndef MYSQL_THREAD_H +#define MYSQL_THREAD_H + +/** + @file mysql/psi/mysql_thread.h + Instrumentation helpers for mysys threads, mutexes, + read write locks and conditions. + This header file provides the necessary declarations + to use the mysys thread API with the performance schema instrumentation. + In some compilers (SunStudio), 'static inline' functions, when declared + but not used, are not optimized away (because they are unused) by default, + so that including a static inline function from a header file does + create unwanted dependencies, causing unresolved symbols at link time. + Other compilers, like gcc, optimize these dependencies by default. + + Since the instrumented APIs declared here are wrapper on top + of my_pthread / safemutex / etc APIs, + including mysql/psi/mysql_thread.h assumes that + the dependency on my_pthread and safemutex already exists. +*/ +/* + Note: there are several orthogonal dimensions here. + + Dimension 1: Instrumentation + HAVE_PSI_INTERFACE is defined when the instrumentation is compiled in. + This may happen both in debug or production builds. + + Dimension 2: Debug + SAFE_MUTEX is defined when debug is compiled in. + This may happen both with and without instrumentation. + + Dimension 3: Platform + Mutexes are implemented with one of: + - the pthread library + - fast mutexes + - window apis + This is implemented by various macro definitions in my_pthread.h + + This causes complexity with '#ifdef'-ery that can't be avoided. +*/ + +#include "mysql/psi/psi.h" + +/** + @defgroup Thread_instrumentation Thread Instrumentation + @ingroup Instrumentation_interface + @{ +*/ + +/** + An instrumented mutex structure. + @sa mysql_mutex_t +*/ +struct st_mysql_mutex +{ + /** The real mutex. */ + pthread_mutex_t m_mutex; + /** + The instrumentation hook. + Note that this hook is not conditionally defined, + for binary compatibility of the @c mysql_mutex_t interface. + */ + struct PSI_mutex *m_psi; +}; + +/** + Type of an instrumented mutex. + @c mysql_mutex_t is a drop-in replacement for @c pthread_mutex_t. + @sa mysql_mutex_assert_owner + @sa mysql_mutex_assert_not_owner + @sa mysql_mutex_init + @sa mysql_mutex_lock + @sa mysql_mutex_unlock + @sa mysql_mutex_destroy +*/ +typedef struct st_mysql_mutex mysql_mutex_t; + +/** + An instrumented rwlock structure. + @sa mysql_rwlock_t +*/ +struct st_mysql_rwlock +{ + /** The real rwlock */ + rw_lock_t m_rwlock; + /** + The instrumentation hook. + Note that this hook is not conditionally defined, + for binary compatibility of the @c mysql_rwlock_t interface. + */ + struct PSI_rwlock *m_psi; +}; + +/** + An instrumented prlock structure. + @sa mysql_prlock_t +*/ +struct st_mysql_prlock +{ + /** The real prlock */ + rw_pr_lock_t m_prlock; + /** + The instrumentation hook. + Note that this hook is not conditionally defined, + for binary compatibility of the @c mysql_rwlock_t interface. + */ + struct PSI_rwlock *m_psi; +}; + +/** + Type of an instrumented rwlock. + @c mysql_rwlock_t is a drop-in replacement for @c pthread_rwlock_t. + @sa mysql_rwlock_init + @sa mysql_rwlock_rdlock + @sa mysql_rwlock_tryrdlock + @sa mysql_rwlock_wrlock + @sa mysql_rwlock_trywrlock + @sa mysql_rwlock_unlock + @sa mysql_rwlock_destroy +*/ +typedef struct st_mysql_rwlock mysql_rwlock_t; + +/** + Type of an instrumented prlock. + A prlock is a read write lock that 'prefers readers' (pr). + @c mysql_prlock_t is a drop-in replacement for @c rw_pr_lock_t. + @sa mysql_prlock_init + @sa mysql_prlock_rdlock + @sa mysql_prlock_wrlock + @sa mysql_prlock_unlock + @sa mysql_prlock_destroy +*/ +typedef struct st_mysql_prlock mysql_prlock_t; + +/** + An instrumented cond structure. + @sa mysql_cond_t +*/ +struct st_mysql_cond +{ + /** The real condition */ + pthread_cond_t m_cond; + /** + The instrumentation hook. + Note that this hook is not conditionally defined, + for binary compatibility of the @c mysql_cond_t interface. + */ + struct PSI_cond *m_psi; +}; + +/** + Type of an instrumented condition. + @c mysql_cond_t is a drop-in replacement for @c pthread_cond_t. + @sa mysql_cond_init + @sa mysql_cond_wait + @sa mysql_cond_timedwait + @sa mysql_cond_signal + @sa mysql_cond_broadcast + @sa mysql_cond_destroy +*/ +typedef struct st_mysql_cond mysql_cond_t; + +/* + Consider the following code: + static inline void foo() { bar(); } + when foo() is never called. + + With gcc, foo() is a local static function, so the dependencies + are optimized away at compile time, and there is no dependency on bar(). + With other compilers (HP, Sun Studio), the function foo() implementation + is compiled, and bar() needs to be present to link. + + Due to the existing header dependencies in MySQL code, this header file + is sometime used when it is not needed, which in turn cause link failures + on some platforms. + The proper fix would be to cut these extra dependencies in the calling code. + DISABLE_MYSQL_THREAD_H is a work around to limit dependencies. + DISABLE_MYSQL_PRLOCK_H is similar, and is used to disable specifically + the prlock wrappers. +*/ +#ifndef DISABLE_MYSQL_THREAD_H + +/** + @def mysql_mutex_assert_owner(M) + Wrapper, to use safe_mutex_assert_owner with instrumented mutexes. + @c mysql_mutex_assert_owner is a drop-in replacement + for @c safe_mutex_assert_owner. +*/ +#define mysql_mutex_assert_owner(M) \ + safe_mutex_assert_owner(&(M)->m_mutex) + +/** + @def mysql_mutex_assert_not_owner(M) + Wrapper, to use safe_mutex_assert_not_owner with instrumented mutexes. + @c mysql_mutex_assert_not_owner is a drop-in replacement + for @c safe_mutex_assert_not_owner. +*/ +#define mysql_mutex_assert_not_owner(M) \ + safe_mutex_assert_not_owner(&(M)->m_mutex) + +/** Wrappers for instrumented prlock objects. */ + +#define mysql_prlock_assert_write_owner(M) \ + rw_pr_lock_assert_write_owner(&(M)->m_prlock) + +#define mysql_prlock_assert_not_write_owner(M) \ + rw_pr_lock_assert_not_write_owner(&(M)->m_prlock) + +/** + @def mysql_mutex_init(K, M, A) + Instrumented mutex_init. + @c mysql_mutex_init is a replacement for @c pthread_mutex_init. + @param K The PSI_mutex_key for this instrumented mutex + @param M The mutex to initialize + @param A Mutex attributes +*/ + +#ifdef HAVE_PSI_INTERFACE + #ifdef SAFE_MUTEX + #define mysql_mutex_init(K, M, A) \ + inline_mysql_mutex_init(K, M, A, __FILE__, __LINE__) + #else + #define mysql_mutex_init(K, M, A) \ + inline_mysql_mutex_init(K, M, A) + #endif +#else + #ifdef SAFE_MUTEX + #define mysql_mutex_init(K, M, A) \ + inline_mysql_mutex_init(M, A, __FILE__, __LINE__) + #else + #define mysql_mutex_init(K, M, A) \ + inline_mysql_mutex_init(M, A) + #endif +#endif + +/** + @def mysql_mutex_destroy(M) + Instrumented mutex_destroy. + @c mysql_mutex_destroy is a drop-in replacement + for @c pthread_mutex_destroy. +*/ +#ifdef SAFE_MUTEX + #define mysql_mutex_destroy(M) \ + inline_mysql_mutex_destroy(M, __FILE__, __LINE__) +#else + #define mysql_mutex_destroy(M) \ + inline_mysql_mutex_destroy(M) +#endif + +/** + @def mysql_mutex_lock(M) + Instrumented mutex_lock. + @c mysql_mutex_lock is a drop-in replacement for @c pthread_mutex_lock. + @param M The mutex to lock +*/ + +#if defined(SAFE_MUTEX) || defined (HAVE_PSI_INTERFACE) + #define mysql_mutex_lock(M) \ + inline_mysql_mutex_lock(M, __FILE__, __LINE__) +#else + #define mysql_mutex_lock(M) \ + inline_mysql_mutex_lock(M) +#endif + +/** + @def mysql_mutex_trylock(M) + Instrumented mutex_lock. + @c mysql_mutex_trylock is a drop-in replacement + for @c pthread_mutex_trylock. +*/ + +#if defined(SAFE_MUTEX) || defined (HAVE_PSI_INTERFACE) + #define mysql_mutex_trylock(M) \ + inline_mysql_mutex_trylock(M, __FILE__, __LINE__) +#else + #define mysql_mutex_trylock(M) \ + inline_mysql_mutex_trylock(M) +#endif + +/** + @def mysql_mutex_unlock(M) + Instrumented mutex_unlock. + @c mysql_mutex_unlock is a drop-in replacement for @c pthread_mutex_unlock. +*/ +#ifdef SAFE_MUTEX + #define mysql_mutex_unlock(M) \ + inline_mysql_mutex_unlock(M, __FILE__, __LINE__) +#else + #define mysql_mutex_unlock(M) \ + inline_mysql_mutex_unlock(M) +#endif + +/** + @def mysql_rwlock_init(K, RW) + Instrumented rwlock_init. + @c mysql_rwlock_init is a replacement for @c pthread_rwlock_init. + Note that pthread_rwlockattr_t is not supported in MySQL. + @param K The PSI_rwlock_key for this instrumented rwlock + @param RW The rwlock to initialize +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_rwlock_init(K, RW) inline_mysql_rwlock_init(K, RW) +#else + #define mysql_rwlock_init(K, RW) inline_mysql_rwlock_init(RW) +#endif + +/** + @def mysql_prlock_init(K, RW) + Instrumented rw_pr_init. + @c mysql_prlock_init is a replacement for @c rw_pr_init. + @param K The PSI_rwlock_key for this instrumented prlock + @param RW The prlock to initialize +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_prlock_init(K, RW) inline_mysql_prlock_init(K, RW) +#else + #define mysql_prlock_init(K, RW) inline_mysql_prlock_init(RW) +#endif + +/** + @def mysql_rwlock_destroy(RW) + Instrumented rwlock_destroy. + @c mysql_rwlock_destroy is a drop-in replacement + for @c pthread_rwlock_destroy. +*/ +#define mysql_rwlock_destroy(RW) inline_mysql_rwlock_destroy(RW) + +/** + @def mysql_prlock_destroy(RW) + Instrumented rw_pr_destroy. + @c mysql_prlock_destroy is a drop-in replacement + for @c rw_pr_destroy. +*/ +#define mysql_prlock_destroy(RW) inline_mysql_prlock_destroy(RW) + +/** + @def mysql_rwlock_rdlock(RW) + Instrumented rwlock_rdlock. + @c mysql_rwlock_rdlock is a drop-in replacement + for @c pthread_rwlock_rdlock. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_rwlock_rdlock(RW) \ + inline_mysql_rwlock_rdlock(RW, __FILE__, __LINE__) +#else + #define mysql_rwlock_rdlock(RW) \ + inline_mysql_rwlock_rdlock(RW) +#endif + +/** + @def mysql_prlock_rdlock(RW) + Instrumented rw_pr_rdlock. + @c mysql_prlock_rdlock is a drop-in replacement + for @c rw_pr_rdlock. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_prlock_rdlock(RW) \ + inline_mysql_prlock_rdlock(RW, __FILE__, __LINE__) +#else + #define mysql_prlock_rdlock(RW) \ + inline_mysql_prlock_rdlock(RW) +#endif + +/** + @def mysql_rwlock_wrlock(RW) + Instrumented rwlock_wrlock. + @c mysql_rwlock_wrlock is a drop-in replacement + for @c pthread_rwlock_wrlock. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_rwlock_wrlock(RW) \ + inline_mysql_rwlock_wrlock(RW, __FILE__, __LINE__) +#else + #define mysql_rwlock_wrlock(RW) \ + inline_mysql_rwlock_wrlock(RW) +#endif + +/** + @def mysql_prlock_wrlock(RW) + Instrumented rw_pr_wrlock. + @c mysql_prlock_wrlock is a drop-in replacement + for @c rw_pr_wrlock. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_prlock_wrlock(RW) \ + inline_mysql_prlock_wrlock(RW, __FILE__, __LINE__) +#else + #define mysql_prlock_wrlock(RW) \ + inline_mysql_prlock_wrlock(RW) +#endif + +/** + @def mysql_rwlock_tryrdlock(RW) + Instrumented rwlock_tryrdlock. + @c mysql_rwlock_tryrdlock is a drop-in replacement + for @c pthread_rwlock_tryrdlock. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_rwlock_tryrdlock(RW) \ + inline_mysql_rwlock_tryrdlock(RW, __FILE__, __LINE__) +#else + #define mysql_rwlock_tryrdlock(RW) \ + inline_mysql_rwlock_tryrdlock(RW) +#endif + +/** + @def mysql_rwlock_trywrlock(RW) + Instrumented rwlock_trywrlock. + @c mysql_rwlock_trywrlock is a drop-in replacement + for @c pthread_rwlock_trywrlock. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_rwlock_trywrlock(RW) \ + inline_mysql_rwlock_trywrlock(RW, __FILE__, __LINE__) +#else + #define mysql_rwlock_trywrlock(RW) \ + inline_mysql_rwlock_trywrlock(RW) +#endif + +/** + @def mysql_rwlock_unlock(RW) + Instrumented rwlock_unlock. + @c mysql_rwlock_unlock is a drop-in replacement + for @c pthread_rwlock_unlock. +*/ +#define mysql_rwlock_unlock(RW) inline_mysql_rwlock_unlock(RW) + +/** + @def mysql_prlock_unlock(RW) + Instrumented rw_pr_unlock. + @c mysql_prlock_unlock is a drop-in replacement + for @c rw_pr_unlock. +*/ +#define mysql_prlock_unlock(RW) inline_mysql_prlock_unlock(RW) + +/** + @def mysql_cond_init(K, C, A) + Instrumented cond_init. + @c mysql_cond_init is a replacement for @c pthread_cond_init. + @param C The cond to initialize + @param K The PSI_cond_key for this instrumented cond + @param A Condition attributes +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_cond_init(K, C, A) inline_mysql_cond_init(K, C, A) +#else + #define mysql_cond_init(K, C, A) inline_mysql_cond_init(C, A) +#endif + +/** + @def mysql_cond_destroy(C) + Instrumented cond_destroy. + @c mysql_cond_destroy is a drop-in replacement for @c pthread_cond_destroy. +*/ +#define mysql_cond_destroy(C) inline_mysql_cond_destroy(C) + +/** + @def mysql_cond_wait(C) + Instrumented cond_wait. + @c mysql_cond_wait is a drop-in replacement for @c pthread_cond_wait. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_cond_wait(C, M) \ + inline_mysql_cond_wait(C, M, __FILE__, __LINE__) +#else + #define mysql_cond_wait(C, M) \ + inline_mysql_cond_wait(C, M) +#endif + +/** + @def mysql_cond_timedwait(C, M, W) + Instrumented cond_timedwait. + @c mysql_cond_timedwait is a drop-in replacement + for @c pthread_cond_timedwait. +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_cond_timedwait(C, M, W) \ + inline_mysql_cond_timedwait(C, M, W, __FILE__, __LINE__) +#else + #define mysql_cond_timedwait(C, M, W) \ + inline_mysql_cond_timedwait(C, M, W) +#endif + +/** + @def mysql_cond_signal(C) + Instrumented cond_signal. + @c mysql_cond_signal is a drop-in replacement for @c pthread_cond_signal. +*/ +#define mysql_cond_signal(C) inline_mysql_cond_signal(C) + +/** + @def mysql_cond_broadcast(C) + Instrumented cond_broadcast. + @c mysql_cond_broadcast is a drop-in replacement + for @c pthread_cond_broadcast. +*/ +#define mysql_cond_broadcast(C) inline_mysql_cond_broadcast(C) + + +/** + @def mysql_thread_create(K, P1, P2, P3, P4) + Instrumented pthread_create. + This function creates both the thread instrumentation and a thread. + @c mysql_thread_create is a replacement for @c pthread_create. + The parameter P4 (or, if it is NULL, P1) will be used as the + instrumented thread "indentity". + Providing a P1 / P4 parameter with a different value for each call + will on average improve performances, since this thread identity value + is used internally to randomize access to data and prevent contention. + This is optional, and the improvement is not guaranteed, only statistical. + @param K The PSI_thread_key for this instrumented thread + @param P1 pthread_create parameter 1 + @param P2 pthread_create parameter 2 + @param P3 pthread_create parameter 3 + @param P4 pthread_create parameter 4 +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_thread_create(K, P1, P2, P3, P4) \ + inline_mysql_thread_create(K, P1, P2, P3, P4) +#else + #define mysql_thread_create(K, P1, P2, P3, P4) \ + pthread_create(P1, P2, P3, P4) +#endif + +/** + @def mysql_thread_set_psi_id(I) + Set the thread indentifier for the instrumentation. + @param I The thread identifier +*/ +#ifdef HAVE_PSI_INTERFACE + #define mysql_thread_set_psi_id(I) inline_mysql_thread_set_psi_id(I) +#else + #define mysql_thread_set_psi_id(I) do {} while (0) +#endif + +static inline int inline_mysql_mutex_init( +#ifdef HAVE_PSI_INTERFACE + PSI_mutex_key key, +#endif + mysql_mutex_t *that, + const pthread_mutexattr_t *attr +#ifdef SAFE_MUTEX + , const char *src_file, uint src_line +#endif + ) +{ +#ifdef HAVE_PSI_INTERFACE + that->m_psi= PSI_server ? PSI_server->init_mutex(key, &that->m_mutex) + : NULL; +#else + that->m_psi= NULL; +#endif +#ifdef SAFE_MUTEX + return safe_mutex_init(&that->m_mutex, attr, src_file, src_line); +#else + return pthread_mutex_init(&that->m_mutex, attr); +#endif +} + +static inline int inline_mysql_mutex_destroy( + mysql_mutex_t *that +#ifdef SAFE_MUTEX + , const char *src_file, uint src_line +#endif + ) +{ +#ifdef HAVE_PSI_INTERFACE + if (likely(PSI_server && that->m_psi)) + { + PSI_server->destroy_mutex(that->m_psi); + that->m_psi= NULL; + } +#endif +#ifdef SAFE_MUTEX + return safe_mutex_destroy(&that->m_mutex, src_file, src_line); +#else + return pthread_mutex_destroy(&that->m_mutex); +#endif +} + +static inline int inline_mysql_mutex_lock( + mysql_mutex_t *that +#if defined(SAFE_MUTEX) || defined (HAVE_PSI_INTERFACE) + , const char *src_file, uint src_line +#endif + ) +{ + int result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_mutex_locker *locker= NULL; + PSI_mutex_locker_state state; + if (likely(PSI_server && that->m_psi)) + { + locker= PSI_server->get_thread_mutex_locker(&state, that->m_psi, PSI_MUTEX_LOCK); + if (likely(locker != NULL)) + PSI_server->start_mutex_wait(locker, src_file, src_line); + } +#endif +#ifdef SAFE_MUTEX + result= safe_mutex_lock(&that->m_mutex, FALSE, src_file, src_line); +#else + result= pthread_mutex_lock(&that->m_mutex); +#endif +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_mutex_wait(locker, result); +#endif + return result; +} + +static inline int inline_mysql_mutex_trylock( + mysql_mutex_t *that +#if defined(SAFE_MUTEX) || defined (HAVE_PSI_INTERFACE) + , const char *src_file, uint src_line +#endif + ) +{ + int result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_mutex_locker *locker= NULL; + PSI_mutex_locker_state state; + if (likely(PSI_server && that->m_psi)) + { + locker= PSI_server->get_thread_mutex_locker(&state, that->m_psi, PSI_MUTEX_TRYLOCK); + if (likely(locker != NULL)) + PSI_server->start_mutex_wait(locker, src_file, src_line); + } +#endif +#ifdef SAFE_MUTEX + result= safe_mutex_lock(&that->m_mutex, TRUE, src_file, src_line); +#else + result= pthread_mutex_trylock(&that->m_mutex); +#endif +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_mutex_wait(locker, result); +#endif + return result; +} + +static inline int inline_mysql_mutex_unlock( + mysql_mutex_t *that +#ifdef SAFE_MUTEX + , const char *src_file, uint src_line +#endif + ) +{ + int result; +#ifdef HAVE_PSI_INTERFACE + if (likely(PSI_server && that->m_psi)) + PSI_server->unlock_mutex(that->m_psi); +#endif +#ifdef SAFE_MUTEX + result= safe_mutex_unlock(&that->m_mutex, src_file, src_line); +#else + result= pthread_mutex_unlock(&that->m_mutex); +#endif + return result; +} + +static inline int inline_mysql_rwlock_init( +#ifdef HAVE_PSI_INTERFACE + PSI_rwlock_key key, +#endif + mysql_rwlock_t *that) +{ +#ifdef HAVE_PSI_INTERFACE + that->m_psi= (PSI_server ? PSI_server->init_rwlock(key, &that->m_rwlock) + : NULL); +#else + that->m_psi= NULL; +#endif + /* + pthread_rwlockattr_t is not used in MySQL. + */ + return my_rwlock_init(&that->m_rwlock, NULL); +} + +#ifndef DISABLE_MYSQL_PRLOCK_H +static inline int inline_mysql_prlock_init( +#ifdef HAVE_PSI_INTERFACE + PSI_rwlock_key key, +#endif + mysql_prlock_t *that) +{ +#ifdef HAVE_PSI_INTERFACE + that->m_psi= (PSI_server ? PSI_server->init_rwlock(key, &that->m_prlock) + : NULL); +#else + that->m_psi= NULL; +#endif + return rw_pr_init(&that->m_prlock); +} +#endif + +static inline int inline_mysql_rwlock_destroy( + mysql_rwlock_t *that) +{ +#ifdef HAVE_PSI_INTERFACE + if (likely(PSI_server && that->m_psi)) + { + PSI_server->destroy_rwlock(that->m_psi); + that->m_psi= NULL; + } +#endif + return rwlock_destroy(&that->m_rwlock); +} + +#ifndef DISABLE_MYSQL_PRLOCK_H +static inline int inline_mysql_prlock_destroy( + mysql_prlock_t *that) +{ +#ifdef HAVE_PSI_INTERFACE + if (likely(PSI_server && that->m_psi)) + { + PSI_server->destroy_rwlock(that->m_psi); + that->m_psi= NULL; + } +#endif + return rw_pr_destroy(&that->m_prlock); +} +#endif + +static inline int inline_mysql_rwlock_rdlock( + mysql_rwlock_t *that +#ifdef HAVE_PSI_INTERFACE + , const char *src_file, uint src_line +#endif + ) +{ + int result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_rwlock_locker *locker= NULL; + PSI_rwlock_locker_state state; + if (likely(PSI_server && that->m_psi)) + { + locker= PSI_server->get_thread_rwlock_locker(&state, that->m_psi, + PSI_RWLOCK_READLOCK); + if (likely(locker != NULL)) + PSI_server->start_rwlock_rdwait(locker, src_file, src_line); + } +#endif + result= rw_rdlock(&that->m_rwlock); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_rwlock_rdwait(locker, result); +#endif + return result; +} + +#ifndef DISABLE_MYSQL_PRLOCK_H +static inline int inline_mysql_prlock_rdlock( + mysql_prlock_t *that +#ifdef HAVE_PSI_INTERFACE + , const char *src_file, uint src_line +#endif + ) +{ + int result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_rwlock_locker *locker= NULL; + PSI_rwlock_locker_state state; + if (likely(PSI_server && that->m_psi)) + { + locker= PSI_server->get_thread_rwlock_locker(&state, that->m_psi, + PSI_RWLOCK_READLOCK); + if (likely(locker != NULL)) + PSI_server->start_rwlock_rdwait(locker, src_file, src_line); + } +#endif + result= rw_pr_rdlock(&that->m_prlock); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_rwlock_rdwait(locker, result); +#endif + return result; +} +#endif + +static inline int inline_mysql_rwlock_wrlock( + mysql_rwlock_t *that +#ifdef HAVE_PSI_INTERFACE + , const char *src_file, uint src_line +#endif + ) +{ + int result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_rwlock_locker *locker= NULL; + PSI_rwlock_locker_state state; + if (likely(PSI_server && that->m_psi)) + { + locker= PSI_server->get_thread_rwlock_locker(&state, that->m_psi, + PSI_RWLOCK_WRITELOCK); + if (likely(locker != NULL)) + PSI_server->start_rwlock_wrwait(locker, src_file, src_line); + } +#endif + result= rw_wrlock(&that->m_rwlock); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_rwlock_wrwait(locker, result); +#endif + return result; +} + +#ifndef DISABLE_MYSQL_PRLOCK_H +static inline int inline_mysql_prlock_wrlock( + mysql_prlock_t *that +#ifdef HAVE_PSI_INTERFACE + , const char *src_file, uint src_line +#endif + ) +{ + int result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_rwlock_locker *locker= NULL; + PSI_rwlock_locker_state state; + if (likely(PSI_server && that->m_psi)) + { + locker= PSI_server->get_thread_rwlock_locker(&state, that->m_psi, + PSI_RWLOCK_WRITELOCK); + if (likely(locker != NULL)) + PSI_server->start_rwlock_wrwait(locker, src_file, src_line); + } +#endif + result= rw_pr_wrlock(&that->m_prlock); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_rwlock_wrwait(locker, result); +#endif + return result; +} +#endif + +static inline int inline_mysql_rwlock_tryrdlock( + mysql_rwlock_t *that +#ifdef HAVE_PSI_INTERFACE + , const char *src_file, uint src_line +#endif + ) +{ + int result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_rwlock_locker *locker= NULL; + PSI_rwlock_locker_state state; + if (likely(PSI_server && that->m_psi)) + { + locker= PSI_server->get_thread_rwlock_locker(&state, that->m_psi, + PSI_RWLOCK_TRYREADLOCK); + if (likely(locker != NULL)) + PSI_server->start_rwlock_rdwait(locker, src_file, src_line); + } +#endif + result= rw_tryrdlock(&that->m_rwlock); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_rwlock_rdwait(locker, result); +#endif + return result; +} + +static inline int inline_mysql_rwlock_trywrlock( + mysql_rwlock_t *that +#ifdef HAVE_PSI_INTERFACE + , const char *src_file, uint src_line +#endif + ) +{ + int result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_rwlock_locker *locker= NULL; + PSI_rwlock_locker_state state; + if (likely(PSI_server && that->m_psi)) + { + locker= PSI_server->get_thread_rwlock_locker(&state, that->m_psi, + PSI_RWLOCK_TRYWRITELOCK); + if (likely(locker != NULL)) + PSI_server->start_rwlock_wrwait(locker, src_file, src_line); + } +#endif + result= rw_trywrlock(&that->m_rwlock); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_rwlock_wrwait(locker, result); +#endif + return result; +} + +static inline int inline_mysql_rwlock_unlock( + mysql_rwlock_t *that) +{ + int result; +#ifdef HAVE_PSI_INTERFACE + if (likely(PSI_server && that->m_psi)) + PSI_server->unlock_rwlock(that->m_psi); +#endif + result= rw_unlock(&that->m_rwlock); + return result; +} + +#ifndef DISABLE_MYSQL_PRLOCK_H +static inline int inline_mysql_prlock_unlock( + mysql_prlock_t *that) +{ + int result; +#ifdef HAVE_PSI_INTERFACE + if (likely(PSI_server && that->m_psi)) + PSI_server->unlock_rwlock(that->m_psi); +#endif + result= rw_pr_unlock(&that->m_prlock); + return result; +} +#endif + +static inline int inline_mysql_cond_init( +#ifdef HAVE_PSI_INTERFACE + PSI_cond_key key, +#endif + mysql_cond_t *that, + const pthread_condattr_t *attr) +{ +#ifdef HAVE_PSI_INTERFACE + that->m_psi= (PSI_server ? PSI_server->init_cond(key, &that->m_cond) + : NULL); +#else + that->m_psi= NULL; +#endif + return pthread_cond_init(&that->m_cond, attr); +} + +static inline int inline_mysql_cond_destroy( + mysql_cond_t *that) +{ +#ifdef HAVE_PSI_INTERFACE + if (likely(PSI_server && that->m_psi)) + { + PSI_server->destroy_cond(that->m_psi); + that->m_psi= NULL; + } +#endif + return pthread_cond_destroy(&that->m_cond); +} + +static inline int inline_mysql_cond_wait( + mysql_cond_t *that, + mysql_mutex_t *mutex +#ifdef HAVE_PSI_INTERFACE + , const char *src_file, uint src_line +#endif + ) +{ + int result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_cond_locker *locker= NULL; + PSI_cond_locker_state state; + if (likely(PSI_server && that->m_psi)) + { + locker= PSI_server->get_thread_cond_locker(&state, that->m_psi, mutex->m_psi, + PSI_COND_WAIT); + if (likely(locker != NULL)) + PSI_server->start_cond_wait(locker, src_file, src_line); + } +#endif + result= pthread_cond_wait(&that->m_cond, &mutex->m_mutex); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_cond_wait(locker, result); +#endif + return result; +} + +static inline int inline_mysql_cond_timedwait( + mysql_cond_t *that, + mysql_mutex_t *mutex, + struct timespec *abstime +#ifdef HAVE_PSI_INTERFACE + , const char *src_file, uint src_line +#endif + ) +{ + int result; +#ifdef HAVE_PSI_INTERFACE + struct PSI_cond_locker *locker= NULL; + PSI_cond_locker_state state; + if (likely(PSI_server && that->m_psi)) + { + locker= PSI_server->get_thread_cond_locker(&state, that->m_psi, mutex->m_psi, + PSI_COND_TIMEDWAIT); + if (likely(locker != NULL)) + PSI_server->start_cond_wait(locker, src_file, src_line); + } +#endif + result= pthread_cond_timedwait(&that->m_cond, &mutex->m_mutex, abstime); +#ifdef HAVE_PSI_INTERFACE + if (likely(locker != NULL)) + PSI_server->end_cond_wait(locker, result); +#endif + return result; +} + +static inline int inline_mysql_cond_signal( + mysql_cond_t *that) +{ + int result; +#ifdef HAVE_PSI_INTERFACE + if (likely(PSI_server && that->m_psi)) + PSI_server->signal_cond(that->m_psi); +#endif + result= pthread_cond_signal(&that->m_cond); + return result; +} + +static inline int inline_mysql_cond_broadcast( + mysql_cond_t *that) +{ + int result; +#ifdef HAVE_PSI_INTERFACE + if (likely(PSI_server && that->m_psi)) + PSI_server->broadcast_cond(that->m_psi); +#endif + result= pthread_cond_broadcast(&that->m_cond); + return result; +} + +#ifdef HAVE_PSI_INTERFACE +static inline int inline_mysql_thread_create( + PSI_thread_key key, + pthread_t *thread, const pthread_attr_t *attr, + void *(*start_routine)(void*), void *arg) +{ + int result; + if (likely(PSI_server != NULL)) + result= PSI_server->spawn_thread(key, thread, attr, start_routine, arg); + else + result= pthread_create(thread, attr, start_routine, arg); + return result; +} + +static inline void inline_mysql_thread_set_psi_id(ulong id) +{ + if (likely(PSI_server != NULL)) + { + struct PSI_thread *psi= PSI_server->get_thread(); + if (likely(psi != NULL)) + PSI_server->set_thread_id(psi, id); + } +} +#endif + +#endif /* DISABLE_MYSQL_THREAD_H */ + +/** @} (end of group Thread_instrumentation) */ + +#endif + diff --git a/include/mysql/psi/psi.h b/include/mysql/psi/psi.h new file mode 100644 index 000000000..562e4a80f --- /dev/null +++ b/include/mysql/psi/psi.h @@ -0,0 +1,1312 @@ +/* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +#ifndef MYSQL_PERFORMANCE_SCHEMA_INTERFACE_H +#define MYSQL_PERFORMANCE_SCHEMA_INTERFACE_H + +#ifndef _global_h +/* + Make sure a .c or .cc file contains an include to my_global.h first. + When this include is missing, all the #ifdef HAVE_XXX have no effect, + and the resulting binary won't build, or won't link, + or will crash at runtime + since various structures will have different binary definitions. +*/ +#error "You must include my_global.h in the code for the build to be correct." +#endif + +C_MODE_START + +/** + @file mysql/psi/psi.h + Performance schema instrumentation interface. + + @defgroup Instrumentation_interface Instrumentation Interface + @ingroup Performance_schema + @{ +*/ + +/** + Interface for an instrumented mutex. + This is an opaque structure. +*/ +struct PSI_mutex; + +/** + Interface for an instrumented rwlock. + This is an opaque structure. +*/ +struct PSI_rwlock; + +/** + Interface for an instrumented condition. + This is an opaque structure. +*/ +struct PSI_cond; + +/** + Interface for an instrumented table share. + This is an opaque structure. +*/ +struct PSI_table_share; + +/** + Interface for an instrumented table handle. + This is an opaque structure. +*/ +struct PSI_table; + +/** + Interface for an instrumented thread. + This is an opaque structure. +*/ +struct PSI_thread; + +/** + Interface for an instrumented file handle. + This is an opaque structure. +*/ +struct PSI_file; + +/** Entry point for the performance schema interface. */ +struct PSI_bootstrap +{ + /** + ABI interface finder. + Calling this method with an interface version number returns either + an instance of the ABI for this version, or NULL. + @param version the interface version number to find + @return a versioned interface (PSI_v1, PSI_v2 or PSI) + @sa PSI_VERSION_1 + @sa PSI_v1 + @sa PSI_VERSION_2 + @sa PSI_v2 + @sa PSI_CURRENT_VERSION + @sa PSI + */ + void* (*get_interface)(int version); +}; + +#ifdef HAVE_PSI_INTERFACE + +/** + @def PSI_VERSION_1 + Performance Schema Interface number for version 1. + This version is supported. +*/ +#define PSI_VERSION_1 1 + +/** + @def PSI_VERSION_2 + Performance Schema Interface number for version 2. + This version is not implemented, it's a placeholder. +*/ +#define PSI_VERSION_2 2 + +/** + @def PSI_CURRENT_VERSION + Performance Schema Interface number for the most recent version. + The most current version is @c PSI_VERSION_1 +*/ +#define PSI_CURRENT_VERSION 1 + +#ifndef USE_PSI_2 +#ifndef USE_PSI_1 +#define USE_PSI_1 +#endif +#endif + +/** + Interface for an instrumented mutex operation. + This is an opaque structure. +*/ +struct PSI_mutex_locker; + +/** + Interface for an instrumented rwlock operation. + This is an opaque structure. +*/ + +struct PSI_rwlock_locker; +/** + Interface for an instrumented condition operation. + This is an opaque structure. +*/ + +struct PSI_cond_locker; + +/** + Interface for an instrumented file operation. + This is an opaque structure. +*/ +struct PSI_file_locker; + +/** Operation performed on an instrumented mutex. */ +enum PSI_mutex_operation +{ + /** Lock. */ + PSI_MUTEX_LOCK= 0, + /** Lock attempt. */ + PSI_MUTEX_TRYLOCK= 1 +}; + +/** Operation performed on an instrumented rwlock. */ +enum PSI_rwlock_operation +{ + /** Read lock. */ + PSI_RWLOCK_READLOCK= 0, + /** Write lock. */ + PSI_RWLOCK_WRITELOCK= 1, + /** Read lock attempt. */ + PSI_RWLOCK_TRYREADLOCK= 2, + /** Write lock attempt. */ + PSI_RWLOCK_TRYWRITELOCK= 3 +}; + +/** Operation performed on an instrumented condition. */ +enum PSI_cond_operation +{ + /** Wait. */ + PSI_COND_WAIT= 0, + /** Wait, with timeout. */ + PSI_COND_TIMEDWAIT= 1 +}; + +/** Operation performed on an instrumented file. */ +enum PSI_file_operation +{ + /** File creation, as in @c create(). */ + PSI_FILE_CREATE= 0, + /** Temporary file creation, as in @c create_temp_file(). */ + PSI_FILE_CREATE_TMP= 1, + /** File open, as in @c open(). */ + PSI_FILE_OPEN= 2, + /** File open, as in @c fopen(). */ + PSI_FILE_STREAM_OPEN= 3, + /** File close, as in @c close(). */ + PSI_FILE_CLOSE= 4, + /** File close, as in @c fclose(). */ + PSI_FILE_STREAM_CLOSE= 5, + /** + Generic file read, such as @c fgets(), @c fgetc(), @c fread(), @c read(), + @c pread(). + */ + PSI_FILE_READ= 6, + /** + Generic file write, such as @c fputs(), @c fputc(), @c fprintf(), + @c vfprintf(), @c fwrite(), @c write(), @c pwrite(). + */ + PSI_FILE_WRITE= 7, + /** Generic file seek, such as @c fseek() or @c seek(). */ + PSI_FILE_SEEK= 8, + /** Generic file tell, such as @c ftell() or @c tell(). */ + PSI_FILE_TELL= 9, + /** File flush, as in @c fflush(). */ + PSI_FILE_FLUSH= 10, + /** File stat, as in @c stat(). */ + PSI_FILE_STAT= 11, + /** File stat, as in @c fstat(). */ + PSI_FILE_FSTAT= 12, + /** File chsize, as in @c my_chsize(). */ + PSI_FILE_CHSIZE= 13, + /** File delete, such as @c my_delete() or @c my_delete_with_symlink(). */ + PSI_FILE_DELETE= 14, + /** File rename, such as @c my_rename() or @c my_rename_with_symlink(). */ + PSI_FILE_RENAME= 15, + /** File sync, as in @c fsync() or @c my_sync(). */ + PSI_FILE_SYNC= 16 +}; + +/** + Interface for an instrumented table operation. + This is an opaque structure. +*/ +struct PSI_table_locker; + +/** + Instrumented mutex key. + To instrument a mutex, a mutex key must be obtained using @c register_mutex. + Using a zero key always disable the instrumentation. +*/ +typedef unsigned int PSI_mutex_key; + +/** + Instrumented rwlock key. + To instrument a rwlock, a rwlock key must be obtained + using @c register_rwlock. + Using a zero key always disable the instrumentation. +*/ +typedef unsigned int PSI_rwlock_key; + +/** + Instrumented cond key. + To instrument a condition, a condition key must be obtained + using @c register_cond. + Using a zero key always disable the instrumentation. +*/ +typedef unsigned int PSI_cond_key; + +/** + Instrumented thread key. + To instrument a thread, a thread key must be obtained + using @c register_thread. + Using a zero key always disable the instrumentation. +*/ +typedef unsigned int PSI_thread_key; + +/** + Instrumented file key. + To instrument a file, a file key must be obtained using @c register_file. + Using a zero key always disable the instrumentation. +*/ +typedef unsigned int PSI_file_key; + +/** + @def USE_PSI_1 + Define USE_PSI_1 to use the interface version 1. +*/ + +/** + @def USE_PSI_2 + Define USE_PSI_2 to use the interface version 2. +*/ + +/** + @def HAVE_PSI_1 + Define HAVE_PSI_1 if the interface version 1 needs to be compiled in. +*/ + +/** + @def HAVE_PSI_2 + Define HAVE_PSI_2 if the interface version 2 needs to be compiled in. +*/ + +/** + Global flag. + This flag indicate that an instrumentation point is a global variable, + or a singleton. +*/ +#define PSI_FLAG_GLOBAL (1 << 0) + +#ifdef USE_PSI_1 +#define HAVE_PSI_1 +#endif + +#ifdef HAVE_PSI_1 + +/** + @defgroup Group_PSI_v1 Application Binary Interface, version 1 + @ingroup Instrumentation_interface + @{ +*/ + +/** + Mutex information. + @since PSI_VERSION_1 + This structure is used to register an instrumented mutex. +*/ +struct PSI_mutex_info_v1 +{ + /** + Pointer to the key assigned to the registered mutex. + */ + PSI_mutex_key *m_key; + /** + The name of the mutex to register. + */ + const char *m_name; + /** + The flags of the mutex to register. + @sa PSI_FLAG_GLOBAL + */ + int m_flags; +}; + +/** + Rwlock information. + @since PSI_VERSION_1 + This structure is used to register an instrumented rwlock. +*/ +struct PSI_rwlock_info_v1 +{ + /** + Pointer to the key assigned to the registered rwlock. + */ + PSI_rwlock_key *m_key; + /** + The name of the rwlock to register. + */ + const char *m_name; + /** + The flags of the rwlock to register. + @sa PSI_FLAG_GLOBAL + */ + int m_flags; +}; + +/** + Condition information. + @since PSI_VERSION_1 + This structure is used to register an instrumented cond. +*/ +struct PSI_cond_info_v1 +{ + /** + Pointer to the key assigned to the registered cond. + */ + PSI_cond_key *m_key; + /** + The name of the cond to register. + */ + const char *m_name; + /** + The flags of the cond to register. + @sa PSI_FLAG_GLOBAL + */ + int m_flags; +}; + +/** + Thread instrument information. + @since PSI_VERSION_1 + This structure is used to register an instrumented thread. +*/ +struct PSI_thread_info_v1 +{ + /** + Pointer to the key assigned to the registered thread. + */ + PSI_thread_key *m_key; + /** + The name of the thread instrument to register. + */ + const char *m_name; + /** + The flags of the thread to register. + @sa PSI_FLAG_GLOBAL + */ + int m_flags; +}; + +/** + File instrument information. + @since PSI_VERSION_1 + This structure is used to register an instrumented file. +*/ +struct PSI_file_info_v1 +{ + /** + Pointer to the key assigned to the registered file. + */ + PSI_file_key *m_key; + /** + The name of the file instrument to register. + */ + const char *m_name; + /** + The flags of the file instrument to register. + @sa PSI_FLAG_GLOBAL + */ + int m_flags; +}; + +/** + State data storage for @c get_thread_mutex_locker_v1_t. + This structure provide temporary storage to a mutex locker. + The content of this structure is considered opaque, + the fields are only hints of what an implementation + of the psi interface can use. + This memory is provided by the instrumented code for performance reasons. + @sa get_thread_mutex_locker_v1_t +*/ +struct PSI_mutex_locker_state_v1 +{ + /** Internal state. */ + uint m_flags; + /** Current mutex. */ + struct PSI_mutex *m_mutex; + /** Current thread. */ + struct PSI_thread *m_thread; + /** Timer start. */ + ulonglong m_timer_start; + /** Timer function. */ + ulonglong (*m_timer)(void); + /** Current operation. */ + enum PSI_mutex_operation m_operation; + /** Source file. */ + const char* m_src_file; + /** Source line number. */ + int m_src_line; + /** Internal data. */ + void *m_wait; +}; + +/** + State data storage for @c get_thread_rwlock_locker_v1_t. + This structure provide temporary storage to a rwlock locker. + The content of this structure is considered opaque, + the fields are only hints of what an implementation + of the psi interface can use. + This memory is provided by the instrumented code for performance reasons. + @sa get_thread_rwlock_locker_v1_t +*/ +struct PSI_rwlock_locker_state_v1 +{ + /** Internal state. */ + uint m_flags; + /** Current rwlock. */ + struct PSI_rwlock *m_rwlock; + /** Current thread. */ + struct PSI_thread *m_thread; + /** Timer start. */ + ulonglong m_timer_start; + /** Timer function. */ + ulonglong (*m_timer)(void); + /** Current operation. */ + enum PSI_rwlock_operation m_operation; + /** Source file. */ + const char* m_src_file; + /** Source line number. */ + int m_src_line; + /** Internal data. */ + void *m_wait; +}; + +/** + State data storage for @c get_thread_cond_locker_v1_t. + This structure provide temporary storage to a condition locker. + The content of this structure is considered opaque, + the fields are only hints of what an implementation + of the psi interface can use. + This memory is provided by the instrumented code for performance reasons. + @sa get_thread_cond_locker_v1_t +*/ +struct PSI_cond_locker_state_v1 +{ + /** Internal state. */ + uint m_flags; + /** Current condition. */ + struct PSI_cond *m_cond; + /** Current mutex. */ + struct PSI_mutex *m_mutex; + /** Current thread. */ + struct PSI_thread *m_thread; + /** Timer start. */ + ulonglong m_timer_start; + /** Timer function. */ + ulonglong (*m_timer)(void); + /** Current operation. */ + enum PSI_cond_operation m_operation; + /** Source file. */ + const char* m_src_file; + /** Source line number. */ + int m_src_line; + /** Internal data. */ + void *m_wait; +}; + +/** + State data storage for @c get_thread_file_name_locker_v1_t. + This structure provide temporary storage to a file locker. + The content of this structure is considered opaque, + the fields are only hints of what an implementation + of the psi interface can use. + This memory is provided by the instrumented code for performance reasons. + @sa get_thread_file_name_locker_v1_t + @sa get_thread_file_stream_locker_v1_t + @sa get_thread_file_descriptor_locker_v1_t +*/ +struct PSI_file_locker_state_v1 +{ + /** Internal state. */ + uint m_flags; + /** Current file. */ + struct PSI_file *m_file; + /** Current thread. */ + struct PSI_thread *m_thread; + /** Operation number of bytes. */ + size_t m_number_of_bytes; + /** Timer start. */ + ulonglong m_timer_start; + /** Timer function. */ + ulonglong (*m_timer)(void); + /** Current operation. */ + enum PSI_file_operation m_operation; + /** Source file. */ + const char* m_src_file; + /** Source line number. */ + int m_src_line; + /** Internal data. */ + void *m_wait; +}; + +/** + State data storage for @c get_thread_table_locker_v1_t. + This structure provide temporary storage to a table locker. + The content of this structure is considered opaque, + the fields are only hints of what an implementation + of the psi interface can use. + This memory is provided by the instrumented code for performance reasons. + @sa get_thread_table_locker_v1_t +*/ +struct PSI_table_locker_state_v1 +{ + /** Internal state. */ + uint m_flags; + /** Current table handle. */ + struct PSI_table *m_table; + /** Current table share. */ + struct PSI_table_share *m_table_share; + /** Instrumentation class. */ + void *m_class; + /** Current thread. */ + struct PSI_thread *m_thread; + /** Timer start. */ + ulonglong m_timer_start; + /** Timer function. */ + ulonglong (*m_timer)(void); + /* Current operation (waiting for WL#4895). */ + /* enum PSI_table_operation m_operation; */ + /** Current table io index. */ + uint m_index; + /** Current table lock index. */ + uint m_lock_index; + /** Source file. */ + const char* m_src_file; + /** Source line number. */ + int m_src_line; + /** Internal data. */ + void *m_wait; +}; + +/* Using typedef to make reuse between PSI_v1 and PSI_v2 easier later. */ + +/** + Mutex registration API. + @param category a category name (typically a plugin name) + @param info an array of mutex info to register + @param count the size of the info array +*/ +typedef void (*register_mutex_v1_t) + (const char *category, struct PSI_mutex_info_v1 *info, int count); + +/** + Rwlock registration API. + @param category a category name (typically a plugin name) + @param info an array of rwlock info to register + @param count the size of the info array +*/ +typedef void (*register_rwlock_v1_t) + (const char *category, struct PSI_rwlock_info_v1 *info, int count); + +/** + Cond registration API. + @param category a category name (typically a plugin name) + @param info an array of cond info to register + @param count the size of the info array +*/ +typedef void (*register_cond_v1_t) + (const char *category, struct PSI_cond_info_v1 *info, int count); + +/** + Thread registration API. + @param category a category name (typically a plugin name) + @param info an array of thread info to register + @param count the size of the info array +*/ +typedef void (*register_thread_v1_t) + (const char *category, struct PSI_thread_info_v1 *info, int count); + +/** + File registration API. + @param category a category name (typically a plugin name) + @param info an array of file info to register + @param count the size of the info array +*/ +typedef void (*register_file_v1_t) + (const char *category, struct PSI_file_info_v1 *info, int count); + +/** + Mutex instrumentation initialisation API. + @param key the registered mutex key + @param identity the address of the mutex itself + @return an instrumented mutex +*/ +typedef struct PSI_mutex* (*init_mutex_v1_t) + (PSI_mutex_key key, const void *identity); + +/** + Mutex instrumentation destruction API. + @param mutex the mutex to destroy +*/ +typedef void (*destroy_mutex_v1_t)(struct PSI_mutex *mutex); + +/** + Rwlock instrumentation initialisation API. + @param key the registered rwlock key + @param identity the address of the rwlock itself + @return an instrumented rwlock +*/ +typedef struct PSI_rwlock* (*init_rwlock_v1_t) + (PSI_rwlock_key key, const void *identity); + +/** + Rwlock instrumentation destruction API. + @param rwlock the rwlock to destroy +*/ +typedef void (*destroy_rwlock_v1_t)(struct PSI_rwlock *rwlock); + +/** + Cond instrumentation initialisation API. + @param key the registered key + @param identity the address of the rwlock itself + @return an instrumented cond +*/ +typedef struct PSI_cond* (*init_cond_v1_t) + (PSI_cond_key key, const void *identity); + +/** + Cond instrumentation destruction API. + @param cond the rcond to destroy +*/ +typedef void (*destroy_cond_v1_t)(struct PSI_cond *cond); + +/** + Acquire a table info by name. + @param schema_name name of the table schema + @param schema_name_length length of schema_name + @param table_name name of the table + @param table_name_length length of table_name + @param identity table identity pointer, typically the table share + @return a table info, or NULL if the table is not instrumented +*/ +typedef struct PSI_table_share* (*get_table_share_v1_t) + (const char *schema_name, int schema_name_length, const char *table_name, + int table_name_length, const void *identity); + +/** + Release a table share. + @param info the table share to release +*/ +typedef void (*release_table_share_v1_t)(struct PSI_table_share *share); + +/** + Open an instrumentation table handle. + @param share the table to open + @param identity table handle identity + @return a table handle, or NULL +*/ +typedef struct PSI_table* (*open_table_v1_t) + (struct PSI_table_share *share, const void *identity); + +/** + Close an instrumentation table handle. + Note that the table handle is invalid after this call. + @param table the table handle to close +*/ +typedef void (*close_table_v1_t)(struct PSI_table *table); + +/** + Create a file instrumentation for a created file. + This method does not create the file itself, but is used to notify the + instrumentation interface that a file was just created. + @param key the file instrumentation key for this file + @param name the file name + @param file the file handle +*/ +typedef void (*create_file_v1_t)(PSI_file_key key, const char *name, + File file); + +/** + Spawn a thread. + This method creates a new thread, with instrumentation. + @param key the instrumentation key for this thread + @param thread the resulting thread + @param attr the thread attributes + @param start_routine the thread start routine + @param arg the thread start routine argument +*/ +typedef int (*spawn_thread_v1_t)(PSI_thread_key key, + pthread_t *thread, + const pthread_attr_t *attr, + void *(*start_routine)(void*), void *arg); + +/** + Create instrumentation for a thread. + @param key the registered key + @param identity an address typical of the thread + @return an instrumented thread +*/ +typedef struct PSI_thread* (*new_thread_v1_t) + (PSI_thread_key key, const void *identity, ulong thread_id); + +/** + Assign an id to an instrumented thread. + @param thread the instrumented thread + @param id the id to assign +*/ +typedef void (*set_thread_id_v1_t)(struct PSI_thread *thread, + unsigned long id); + +/** + Get the instrumentation for the running thread. + For this function to return a result, + the thread instrumentation must have been attached to the + running thread using @c set_thread() + @return the instrumentation for the running thread +*/ +typedef struct PSI_thread* (*get_thread_v1_t)(void); + +/** + Attach a thread instrumentation to the running thread. + In case of thread pools, this method should be called when + a worker thread picks a work item and runs it. + Also, this method should be called if the instrumented code does not + keep the pointer returned by @c new_thread() and relies on @c get_thread() + instead. + @param thread the thread instrumentation +*/ +typedef void (*set_thread_v1_t)(struct PSI_thread *thread); + +/** Delete the current thread instrumentation. */ +typedef void (*delete_current_thread_v1_t)(void); + +/** Delete a thread instrumentation. */ +typedef void (*delete_thread_v1_t)(struct PSI_thread *thread); + +/** + Get a mutex instrumentation locker. + @param state data storage for the locker + @param mutex the instrumented mutex to lock + @return a mutex locker, or NULL +*/ +typedef struct PSI_mutex_locker* (*get_thread_mutex_locker_v1_t) + (struct PSI_mutex_locker_state_v1 *state, + struct PSI_mutex *mutex, + enum PSI_mutex_operation op); + +/** + Get a rwlock instrumentation locker. + @param state data storage for the locker + @param rwlock the instrumented rwlock to lock + @return a rwlock locker, or NULL +*/ +typedef struct PSI_rwlock_locker* (*get_thread_rwlock_locker_v1_t) + (struct PSI_rwlock_locker_state_v1 *state, + struct PSI_rwlock *rwlock, + enum PSI_rwlock_operation op); + +/** + Get a cond instrumentation locker. + @param state data storage for the locker + @param cond the instrumented condition to wait on + @param mutex the instrumented mutex associated with the condition + @return a condition locker, or NULL +*/ +typedef struct PSI_cond_locker* (*get_thread_cond_locker_v1_t) + (struct PSI_cond_locker_state_v1 *state, + struct PSI_cond *cond, struct PSI_mutex *mutex, + enum PSI_cond_operation op); + +/** + Get a table instrumentation locker. + @param state data storage for the locker + @param table the instrumented table to lock + @return a table locker, or NULL +*/ +typedef struct PSI_table_locker* (*get_thread_table_locker_v1_t) + (struct PSI_table_locker_state_v1 *state, + struct PSI_table *table); + +/** + Get a file instrumentation locker, for opening or creating a file. + @param state data storage for the locker + @param key the file instrumentation key + @param op the operation to perform + @param name the file name + @param identity a pointer representative of this file. + @return a file locker, or NULL +*/ +typedef struct PSI_file_locker* (*get_thread_file_name_locker_v1_t) + (struct PSI_file_locker_state_v1 *state, + PSI_file_key key, enum PSI_file_operation op, const char *name, + const void *identity); + +/** + Get a file stream instrumentation locker. + @param state data storage for the locker + @param file the file stream to access + @param op the operation to perform + @return a file locker, or NULL +*/ +typedef struct PSI_file_locker* (*get_thread_file_stream_locker_v1_t) + (struct PSI_file_locker_state_v1 *state, + struct PSI_file *file, enum PSI_file_operation op); + +/** + Get a file instrumentation locker. + @param state data storage for the locker + @param file the file descriptor to access + @param op the operation to perform + @return a file locker, or NULL +*/ +typedef struct PSI_file_locker* (*get_thread_file_descriptor_locker_v1_t) + (struct PSI_file_locker_state_v1 *state, + File file, enum PSI_file_operation op); + +/** + Record a mutex instrumentation unlock event. + @param mutex the mutex instrumentation +*/ +typedef void (*unlock_mutex_v1_t) + (struct PSI_mutex *mutex); + +/** + Record a rwlock instrumentation unlock event. + @param rwlock the rwlock instrumentation +*/ +typedef void (*unlock_rwlock_v1_t) + (struct PSI_rwlock *rwlock); + +/** + Record a condition instrumentation signal event. + @param cond the cond instrumentation +*/ +typedef void (*signal_cond_v1_t) + (struct PSI_cond *cond); + +/** + Record a condition instrumentation broadcast event. + @param cond the cond instrumentation +*/ +typedef void (*broadcast_cond_v1_t) + (struct PSI_cond *cond); + +/** + Record a mutex instrumentation wait start event. + @param locker a thread locker for the running thread +*/ +typedef void (*start_mutex_wait_v1_t) + (struct PSI_mutex_locker *locker, const char *src_file, uint src_line); + +/** + Record a mutex instrumentation wait end event. + @param locker a thread locker for the running thread + @param rc the wait operation return code +*/ +typedef void (*end_mutex_wait_v1_t) + (struct PSI_mutex_locker *locker, int rc); + +/** + Record a rwlock instrumentation read wait start event. + @param locker a thread locker for the running thread + @param must must block: 1 for lock, 0 for trylock +*/ +typedef void (*start_rwlock_rdwait_v1_t) + (struct PSI_rwlock_locker *locker, const char *src_file, uint src_line); + +/** + Record a rwlock instrumentation read wait end event. + @param locker a thread locker for the running thread + @param rc the wait operation return code +*/ +typedef void (*end_rwlock_rdwait_v1_t) + (struct PSI_rwlock_locker *locker, int rc); + +/** + Record a rwlock instrumentation write wait start event. + @param locker a thread locker for the running thread + @param must must block: 1 for lock, 0 for trylock +*/ +typedef void (*start_rwlock_wrwait_v1_t) + (struct PSI_rwlock_locker *locker, const char *src_file, uint src_line); + +/** + Record a rwlock instrumentation write wait end event. + @param locker a thread locker for the running thread + @param rc the wait operation return code +*/ +typedef void (*end_rwlock_wrwait_v1_t) + (struct PSI_rwlock_locker *locker, int rc); + +/** + Record a condition instrumentation wait start event. + @param locker a thread locker for the running thread + @param must must block: 1 for wait, 0 for timedwait +*/ +typedef void (*start_cond_wait_v1_t) + (struct PSI_cond_locker *locker, const char *src_file, uint src_line); + +/** + Record a condition instrumentation wait end event. + @param locker a thread locker for the running thread + @param rc the wait operation return code +*/ +typedef void (*end_cond_wait_v1_t) + (struct PSI_cond_locker *locker, int rc); + +/** + Record a table instrumentation wait start event. + @param locker a table locker for the running thread + @param file the source file name + @param line the source line number +*/ +typedef void (*start_table_wait_v1_t) + (struct PSI_table_locker *locker, const char *src_file, uint src_line); + +/** + Record a table instrumentation wait end event. + @param locker a table locker for the running thread +*/ +typedef void (*end_table_wait_v1_t)(struct PSI_table_locker *locker); + +/** + Start a file instrumentation open operation. + @param locker the file locker + @param op the operation to perform + @param src_file the source file name + @param src_line the source line number + @return an instrumented file handle +*/ +typedef struct PSI_file* (*start_file_open_wait_v1_t) + (struct PSI_file_locker *locker, const char *src_file, uint src_line); + +/** + End a file instrumentation open operation, for file streams. + @param locker the file locker. +*/ +typedef void (*end_file_open_wait_v1_t)(struct PSI_file_locker *locker); + +/** + End a file instrumentation open operation, for non stream files. + @param locker the file locker. + @param file the file number assigned by open() or create() for this file. +*/ +typedef void (*end_file_open_wait_and_bind_to_descriptor_v1_t) + (struct PSI_file_locker *locker, File file); + +/** + Record a file instrumentation start event. + @param locker a file locker for the running thread + @param op file operation to be performed + @param count the number of bytes requested, or 0 if not applicable + @param src_file the source file name + @param src_line the source line number +*/ +typedef void (*start_file_wait_v1_t) + (struct PSI_file_locker *locker, size_t count, + const char *src_file, uint src_line); + +/** + Record a file instrumentation end event. + Note that for file close operations, the instrumented file handle + associated with the file (which was provided to obtain a locker) + is invalid after this call. + @param locker a file locker for the running thread + @param count the number of bytes actually used in the operation, + or 0 if not applicable, or -1 if the operation failed + @sa get_thread_file_name_locker + @sa get_thread_file_stream_locker + @sa get_thread_file_descriptor_locker +*/ +typedef void (*end_file_wait_v1_t) + (struct PSI_file_locker *locker, size_t count); + +/** + Performance Schema Interface, version 1. + @since PSI_VERSION_1 +*/ +struct PSI_v1 +{ + /** @sa register_mutex_v1_t. */ + register_mutex_v1_t register_mutex; + /** @sa register_rwlock_v1_t. */ + register_rwlock_v1_t register_rwlock; + /** @sa register_cond_v1_t. */ + register_cond_v1_t register_cond; + /** @sa register_thread_v1_t. */ + register_thread_v1_t register_thread; + /** @sa register_file_v1_t. */ + register_file_v1_t register_file; + /** @sa init_mutex_v1_t. */ + init_mutex_v1_t init_mutex; + /** @sa destroy_mutex_v1_t. */ + destroy_mutex_v1_t destroy_mutex; + /** @sa init_rwlock_v1_t. */ + init_rwlock_v1_t init_rwlock; + /** @sa destroy_rwlock_v1_t. */ + destroy_rwlock_v1_t destroy_rwlock; + /** @sa init_cond_v1_t. */ + init_cond_v1_t init_cond; + /** @sa destroy_cond_v1_t. */ + destroy_cond_v1_t destroy_cond; + /** @sa get_table_share_v1_t. */ + get_table_share_v1_t get_table_share; + /** @sa release_table_share_v1_t. */ + release_table_share_v1_t release_table_share; + /** @sa open_table_v1_t. */ + open_table_v1_t open_table; + /** @sa close_table_v1_t. */ + close_table_v1_t close_table; + /** @sa create_file_v1_t. */ + create_file_v1_t create_file; + /** @sa spawn_thread_v1_t. */ + spawn_thread_v1_t spawn_thread; + /** @sa new_thread_v1_t. */ + new_thread_v1_t new_thread; + /** @sa set_thread_id_v1_t. */ + set_thread_id_v1_t set_thread_id; + /** @sa get_thread_v1_t. */ + get_thread_v1_t get_thread; + /** @sa set_thread_v1_t. */ + set_thread_v1_t set_thread; + /** @sa delete_current_thread_v1_t. */ + delete_current_thread_v1_t delete_current_thread; + /** @sa delete_thread_v1_t. */ + delete_thread_v1_t delete_thread; + /** @sa get_thread_mutex_locker_v1_t. */ + get_thread_mutex_locker_v1_t get_thread_mutex_locker; + /** @sa get_thread_rwlock_locker_v1_t. */ + get_thread_rwlock_locker_v1_t get_thread_rwlock_locker; + /** @sa get_thread_cond_locker_v1_t. */ + get_thread_cond_locker_v1_t get_thread_cond_locker; + /** @sa get_thread_table_locker_v1_t. */ + get_thread_table_locker_v1_t get_thread_table_locker; + /** @sa get_thread_file_name_locker_v1_t. */ + get_thread_file_name_locker_v1_t get_thread_file_name_locker; + /** @sa get_thread_file_stream_locker_v1_t. */ + get_thread_file_stream_locker_v1_t get_thread_file_stream_locker; + /** @sa get_thread_file_descriptor_locker_v1_t. */ + get_thread_file_descriptor_locker_v1_t get_thread_file_descriptor_locker; + /** @sa unlock_mutex_v1_t. */ + unlock_mutex_v1_t unlock_mutex; + /** @sa unlock_rwlock_v1_t. */ + unlock_rwlock_v1_t unlock_rwlock; + /** @sa signal_cond_v1_t. */ + signal_cond_v1_t signal_cond; + /** @sa broadcast_cond_v1_t. */ + broadcast_cond_v1_t broadcast_cond; + /** @sa start_mutex_wait_v1_t. */ + start_mutex_wait_v1_t start_mutex_wait; + /** @sa end_mutex_wait_v1_t. */ + end_mutex_wait_v1_t end_mutex_wait; + /** @sa start_rwlock_rdwait_v1_t. */ + start_rwlock_rdwait_v1_t start_rwlock_rdwait; + /** @sa end_rwlock_rdwait_v1_t. */ + end_rwlock_rdwait_v1_t end_rwlock_rdwait; + /** @sa start_rwlock_wrwait_v1_t. */ + start_rwlock_wrwait_v1_t start_rwlock_wrwait; + /** @sa end_rwlock_wrwait_v1_t. */ + end_rwlock_wrwait_v1_t end_rwlock_wrwait; + /** @sa start_cond_wait_v1_t. */ + start_cond_wait_v1_t start_cond_wait; + /** @sa end_cond_wait_v1_t. */ + end_cond_wait_v1_t end_cond_wait; + /** @sa start_table_wait_v1_t. */ + start_table_wait_v1_t start_table_wait; + /** @sa end_table_wait_v1_t. */ + end_table_wait_v1_t end_table_wait; + /** @sa start_file_open_wait_v1_t. */ + start_file_open_wait_v1_t start_file_open_wait; + /** @sa end_file_open_wait_v1_t. */ + end_file_open_wait_v1_t end_file_open_wait; + /** @sa end_file_open_wait_and_bind_to_descriptor_v1_t. */ + end_file_open_wait_and_bind_to_descriptor_v1_t + end_file_open_wait_and_bind_to_descriptor; + /** @sa start_file_wait_v1_t. */ + start_file_wait_v1_t start_file_wait; + /** @sa end_file_wait_v1_t. */ + end_file_wait_v1_t end_file_wait; +}; + +/** @} (end of group Group_PSI_v1) */ + +#endif /* HAVE_PSI_1 */ + +#ifdef USE_PSI_2 +#define HAVE_PSI_2 +#endif + +#ifdef HAVE_PSI_2 + +/** + @defgroup Group_PSI_v2 Application Binary Interface, version 2 + @ingroup Instrumentation_interface + @{ +*/ + +/** + Performance Schema Interface, version 2. + This is a placeholder, this interface is not defined yet. + @since PSI_VERSION_2 +*/ +struct PSI_v2 +{ + /** Placeholder */ + int placeholder; + /* ... extended interface ... */ +}; + +/** Placeholder */ +struct PSI_mutex_info_v2 +{ + /** Placeholder */ + int placeholder; +}; + +/** Placeholder */ +struct PSI_rwlock_info_v2 +{ + /** Placeholder */ + int placeholder; +}; + +/** Placeholder */ +struct PSI_cond_info_v2 +{ + /** Placeholder */ + int placeholder; +}; + +/** Placeholder */ +struct PSI_thread_info_v2 +{ + /** Placeholder */ + int placeholder; +}; + +/** Placeholder */ +struct PSI_file_info_v2 +{ + /** Placeholder */ + int placeholder; +}; + +struct PSI_mutex_locker_state_v2 +{ + /** Placeholder */ + int placeholder; +}; + +struct PSI_rwlock_locker_state_v2 +{ + /** Placeholder */ + int placeholder; +}; + +struct PSI_cond_locker_state_v2 +{ + /** Placeholder */ + int placeholder; +}; + +struct PSI_file_locker_state_v2 +{ + /** Placeholder */ + int placeholder; +}; + +struct PSI_table_locker_state_v2 +{ + /** Placeholder */ + int placeholder; +}; + +/** @} (end of group Group_PSI_v2) */ + +#endif /* HAVE_PSI_2 */ + +/** + @typedef PSI + The instrumentation interface for the current version. + @sa PSI_CURRENT_VERSION +*/ + +/** + @typedef PSI_mutex_info + The mutex information structure for the current version. +*/ + +/** + @typedef PSI_rwlock_info + The rwlock information structure for the current version. +*/ + +/** + @typedef PSI_cond_info + The cond information structure for the current version. +*/ + +/** + @typedef PSI_thread_info + The thread information structure for the current version. +*/ + +/** + @typedef PSI_file_info + The file information structure for the current version. +*/ + +/* Export the required version */ +#ifdef USE_PSI_1 +typedef struct PSI_v1 PSI; +typedef struct PSI_mutex_info_v1 PSI_mutex_info; +typedef struct PSI_rwlock_info_v1 PSI_rwlock_info; +typedef struct PSI_cond_info_v1 PSI_cond_info; +typedef struct PSI_thread_info_v1 PSI_thread_info; +typedef struct PSI_file_info_v1 PSI_file_info; +typedef struct PSI_mutex_locker_state_v1 PSI_mutex_locker_state; +typedef struct PSI_rwlock_locker_state_v1 PSI_rwlock_locker_state; +typedef struct PSI_cond_locker_state_v1 PSI_cond_locker_state; +typedef struct PSI_file_locker_state_v1 PSI_file_locker_state; +typedef struct PSI_table_locker_state_v1 PSI_table_locker_state; +#endif + +#ifdef USE_PSI_2 +typedef struct PSI_v2 PSI; +typedef struct PSI_mutex_info_v2 PSI_mutex_info; +typedef struct PSI_rwlock_info_v2 PSI_rwlock_info; +typedef struct PSI_cond_info_v2 PSI_cond_info; +typedef struct PSI_thread_info_v2 PSI_thread_info; +typedef struct PSI_file_info_v2 PSI_file_info; +typedef struct PSI_mutex_locker_state_v2 PSI_mutex_locker_state; +typedef struct PSI_rwlock_locker_state_v2 PSI_rwlock_locker_state; +typedef struct PSI_cond_locker_state_v2 PSI_cond_locker_state; +typedef struct PSI_file_locker_state_v2 PSI_file_locker_state; +typedef struct PSI_table_locker_state_v2 PSI_table_locker_state; +#endif + +#else /* HAVE_PSI_INTERFACE */ + +/** + Dummy structure, used to declare PSI_server when no instrumentation + is available. + The content does not matter, since PSI_server will be NULL. +*/ +struct PSI_none +{ + int opaque; +}; +typedef struct PSI_none PSI; + +#endif /* HAVE_PSI_INTERFACE */ + +extern MYSQL_PLUGIN_IMPORT PSI *PSI_server; + +/** @} */ + +C_MODE_END +#endif /* MYSQL_PERFORMANCE_SCHEMA_INTERFACE_H */ + diff --git a/include/mysql/psi/psi_abi_v1.h b/include/mysql/psi/psi_abi_v1.h new file mode 100644 index 000000000..0f6229169 --- /dev/null +++ b/include/mysql/psi/psi_abi_v1.h @@ -0,0 +1,26 @@ +/* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +/** + @file mysql/psi/psi_abi_v1.h + ABI check for mysql/psi/psi.h, when using PSI_VERSION_1. + This file is only used to automate detection of changes between versions. + Do not include this file, include mysql/psi/psi.h instead. +*/ +#define USE_PSI_1 +#define HAVE_PSI_INTERFACE +#define _global_h +#include "mysql/psi/psi.h" + diff --git a/include/mysql/psi/psi_abi_v2.h b/include/mysql/psi/psi_abi_v2.h new file mode 100644 index 000000000..08bca609b --- /dev/null +++ b/include/mysql/psi/psi_abi_v2.h @@ -0,0 +1,26 @@ +/* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +/** + @file mysql/psi/psi_abi_v1.h + ABI check for mysql/psi/psi.h, when using PSI_VERSION_2. + This file is only used to automate detection of changes between versions. + Do not include this file, include mysql/psi/psi.h instead. +*/ +#define USE_PSI_2 +#define HAVE_PSI_INTERFACE +#define _global_h +#include "mysql/psi/psi.h" + diff --git a/include/mysql/service_my_snprintf.h b/include/mysql/service_my_snprintf.h new file mode 100644 index 000000000..f6b4aa39d --- /dev/null +++ b/include/mysql/service_my_snprintf.h @@ -0,0 +1,101 @@ +#ifndef MYSQL_SERVICE_MY_SNPRINTF_INCLUDED +/* Copyright (C) 2009 Sun Microsystems, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/** + @file + my_snprintf service + + Portable and limited vsnprintf() implementation. + + This is a portable, limited vsnprintf() implementation, with some + extra features. "Portable" means that it'll produce identical result + on all platforms (for example, on Windows and Linux system printf %e + formats the exponent differently, on different systems %p either + prints leading 0x or not, %s may accept null pointer or crash on + it). "Limited" means that it does not support all the C89 features. + But it supports few extensions, not in any standard. + + my_vsnprintf(to, n, fmt, ap) + + @param[out] to A buffer to store the result in + @param[in] n Store up to n-1 characters, followed by an end 0 + @param[in] fmt printf-like format string + @param[in] ap Arguments + + @return a number of bytes written to a buffer *excluding* terminating '\0' + + @post + The syntax of a format string is generally the same: + % + where everithing but the format is optional. + + Three one-character flags are recognized: + '0' has the standard zero-padding semantics; + '-' is parsed, but silently ignored; + '`' (backtick) is only supported for strings (%s) and means that the + string will be quoted according to MySQL identifier quoting rules. + + Both and can be specified as numbers or '*'. + + can be 'l', 'll', or 'z'. + + Supported formats are 's' (null pointer is accepted, printed as + "(null)"), 'b' (extension, see below), 'c', 'd', 'i', 'u', 'x', 'o', + 'X', 'p' (works as 0x%x). + + Standard syntax for positional arguments $n is supported. + + Extensions: + + Flag '`' (backtick): see above. + + Format 'b': binary buffer, prints exactly bytes from the + argument, without stopping at '\0'. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef MYSQL_ABI_CHECK +#include +#include +#endif + +extern struct my_snprintf_service_st { + size_t (*my_snprintf_type)(char*, size_t, const char*, ...); + size_t (*my_vsnprintf_type)(char *, size_t, const char*, va_list); +} *my_snprintf_service; + +#ifdef MYSQL_DYNAMIC_PLUGIN + +#define my_vsnprintf my_snprintf_service->my_vsnprintf_type +#define my_snprintf my_snprintf_service->my_snprintf_type + +#else + +size_t my_snprintf(char* to, size_t n, const char* fmt, ...); +size_t my_vsnprintf(char *to, size_t n, const char* fmt, va_list ap); + +#endif + +#ifdef __cplusplus +} +#endif + +#define MYSQL_SERVICE_MY_SNPRINTF_INCLUDED +#endif + diff --git a/include/mysql/service_thd_alloc.h b/include/mysql/service_thd_alloc.h new file mode 100644 index 000000000..7061c2bd4 --- /dev/null +++ b/include/mysql/service_thd_alloc.h @@ -0,0 +1,130 @@ +#ifndef MYSQL_SERVICE_THD_ALLOC_INCLUDED +/* Copyright (C) 2009 Sun Microsystems, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/** + @file + This service provdes functions to allocate memory in a connection local + memory pool. The memory allocated there will be automatically freed at the + end of the statement, don't use it for allocations that should live longer + than that. For short living allocations this is more efficient than + using my_malloc and friends, and automatic "garbage collection" allows not + to think about memory leaks. + + The pool is best for small to medium objects, don't use it for large + allocations - they are better served with my_malloc. +*/ + +#ifndef MYSQL_ABI_CHECK +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +struct st_mysql_lex_string +{ + char *str; + size_t length; +}; +typedef struct st_mysql_lex_string MYSQL_LEX_STRING; + +extern struct thd_alloc_service_st { + void *(*thd_alloc_func)(MYSQL_THD, unsigned int); + void *(*thd_calloc_func)(MYSQL_THD, unsigned int); + char *(*thd_strdup_func)(MYSQL_THD, const char *); + char *(*thd_strmake_func)(MYSQL_THD, const char *, unsigned int); + void *(*thd_memdup_func)(MYSQL_THD, const void*, unsigned int); + MYSQL_LEX_STRING *(*thd_make_lex_string_func)(MYSQL_THD, MYSQL_LEX_STRING *, + const char *, unsigned int, int); +} *thd_alloc_service; + +#ifdef MYSQL_DYNAMIC_PLUGIN + +#define thd_alloc(thd,size) (thd_alloc_service->thd_alloc_func((thd), (size))) + +#define thd_calloc(thd,size) (thd_alloc_service->thd_calloc_func((thd), (size))) + +#define thd_strdup(thd,str) (thd_alloc_service->thd_strdup_func((thd), (str))) + +#define thd_strmake(thd,str,size) \ + (thd_alloc_service->thd_strmake_func((thd), (str), (size))) + +#define thd_memdup(thd,str,size) \ + (thd_alloc_service->thd_memdup_func((thd), (str), (size))) + +#define thd_make_lex_string(thd, lex_str, str, size, allocate_lex_string) \ + (thd_alloc_service->thd_make_lex_string_func((thd), (lex_str), (str), \ + (size), (allocate_lex_string))) + +#else + +/** + Allocate memory in the connection's local memory pool + + @details + When properly used in place of @c my_malloc(), this can significantly + improve concurrency. Don't use this or related functions to allocate + large chunks of memory. Use for temporary storage only. The memory + will be freed automatically at the end of the statement; no explicit + code is required to prevent memory leaks. + + @see alloc_root() +*/ +void *thd_alloc(MYSQL_THD thd, unsigned int size); +/** + @see thd_alloc() +*/ +void *thd_calloc(MYSQL_THD thd, unsigned int size); +/** + @see thd_alloc() +*/ +char *thd_strdup(MYSQL_THD thd, const char *str); +/** + @see thd_alloc() +*/ +char *thd_strmake(MYSQL_THD thd, const char *str, unsigned int size); +/** + @see thd_alloc() +*/ +void *thd_memdup(MYSQL_THD thd, const void* str, unsigned int size); + +/** + Create a LEX_STRING in this connection's local memory pool + + @param thd user thread connection handle + @param lex_str pointer to LEX_STRING object to be initialized + @param str initializer to be copied into lex_str + @param size length of str, in bytes + @param allocate_lex_string flag: if TRUE, allocate new LEX_STRING object, + instead of using lex_str value + @return NULL on failure, or pointer to the LEX_STRING object + + @see thd_alloc() +*/ +MYSQL_LEX_STRING *thd_make_lex_string(MYSQL_THD thd, MYSQL_LEX_STRING *lex_str, + const char *str, unsigned int size, + int allocate_lex_string); + +#endif + +#ifdef __cplusplus +} +#endif + +#define MYSQL_SERVICE_THD_ALLOC_INCLUDED +#endif + diff --git a/include/mysql/service_thd_wait.h b/include/mysql/service_thd_wait.h new file mode 100644 index 000000000..2a8f5e610 --- /dev/null +++ b/include/mysql/service_thd_wait.h @@ -0,0 +1,83 @@ +/* Copyright (C) 2010, Oracle and/or its affiliates. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifndef MYSQL_SERVICE_THD_WAIT_INCLUDED +#define MYSQL_SERVICE_THD_WAIT_INCLUDED + +/** + @file include/mysql/service_thd_wait.h + This service provides functions for plugins and storage engines to report + when they are going to sleep/stall. + + SYNOPSIS + thd_wait_begin() - call just before a wait begins + thd Thread object + Use NULL if the thd is NOT known. + wait_type Type of wait + 1 -- short wait (e.g. for mutex) + 2 -- medium wait (e.g. for disk io) + 3 -- large wait (e.g. for locked row/table) + NOTES + This is used by the threadpool to have better knowledge of which + threads that currently are actively running on CPUs. When a thread + reports that it's going to sleep/stall, the threadpool scheduler is + free to start another thread in the pool most likely. The expected wait + time is simply an indication of how long the wait is expected to + become, the real wait time could be very different. + + thd_wait_end() called immediately after the wait is complete + + thd_wait_end() MUST be called if thd_wait_begin() was called. + + Using thd_wait_...() service is optional but recommended. Using it will + improve performance as the thread pool will be more active at managing the + thread workload. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum _thd_wait_type_e { + THD_WAIT_MUTEX= 1, + THD_WAIT_DISKIO= 2, + THD_WAIT_ROW_TABLE_LOCK= 3, + THD_WAIT_GLOBAL_LOCK= 4 +} thd_wait_type; + +extern struct thd_wait_service_st { + void (*thd_wait_begin_func)(MYSQL_THD, thd_wait_type); + void (*thd_wait_end_func)(MYSQL_THD); +} *thd_wait_service; + +#ifdef MYSQL_DYNAMIC_PLUGIN + +#define thd_wait_begin(_THD, _WAIT_TYPE) \ + thd_wait_service->thd_wait_begin_func(_THD, _WAIT_TYPE) +#define thd_wait_end(_THD) thd_wait_service->thd_wait_end_func(_THD) + +#else + +void thd_wait_begin(MYSQL_THD thd, thd_wait_type wait_type); +void thd_wait_end(MYSQL_THD thd); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/include/mysql/service_thread_scheduler.h b/include/mysql/service_thread_scheduler.h new file mode 100644 index 000000000..a4396b721 --- /dev/null +++ b/include/mysql/service_thread_scheduler.h @@ -0,0 +1,65 @@ +/* + Copyright (C) 2010, Oracle and/or its affiliates. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef SERVICE_THREAD_SCHEDULER_INCLUDED +#define SERVICE_THREAD_SCHEDULER_INCLUDED + +#ifdef __cplusplus +extern "C" { +#endif + +struct scheduler_functions; + +extern struct my_thread_scheduler_service { + int (*set)(struct scheduler_functions *scheduler); + int (*reset)(); +} *my_thread_scheduler_service; + +#ifdef MYSQL_DYNAMIC_PLUGIN + +#define my_thread_scheduler_set(F) my_thread_scheduler_service->set((F)) +#define my_thread_scheduler_reset() my_thread_scheduler_service->reset() + +#else + +/** + Set the thread scheduler to use for the server. + + @param scheduler Pointer to scheduler callbacks to use. + @retval 0 Scheduler installed correctly. + @retval 1 Invalid value (NULL) used for scheduler. +*/ +int my_thread_scheduler_set(struct scheduler_functions *scheduler); + +/** + Restore the previous thread scheduler. + + @note If no thread scheduler was installed previously with + thd_set_thread_scheduler, this function will report an error. + + @retval 0 Scheduler installed correctly. + @retval 1 No scheduler installed. +*/ +int my_thread_scheduler_reset(); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* SERVICE_THREAD_SCHEDULER_INCLUDED */ diff --git a/include/mysql/services.h b/include/mysql/services.h new file mode 100644 index 000000000..6c67a582f --- /dev/null +++ b/include/mysql/services.h @@ -0,0 +1,32 @@ +#ifndef MYSQL_SERVICES_INCLUDED +/* Copyright (C) 2009 Sun Microsystems, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include + +#ifdef __cplusplus +} +#endif + +#define MYSQL_SERVICES_INCLUDED +#endif + diff --git a/include/mysql/sql_common.h b/include/mysql/sql_common.h new file mode 100644 index 000000000..a9a3168b6 --- /dev/null +++ b/include/mysql/sql_common.h @@ -0,0 +1,113 @@ +#ifndef SQL_COMMON_INCLUDED +#define SQL_COMMON_INCLUDED + +/* Copyright (C) 2003-2004, 2006 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#define SQL_COMMON_INCLUDED + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +extern const char *unknown_sqlstate; +extern const char *cant_connect_sqlstate; +extern const char *not_error_sqlstate; + +struct st_mysql_options_extention { + char *plugin_dir; + char *default_auth; +}; + +typedef struct st_mysql_methods +{ + my_bool (*read_query_result)(MYSQL *mysql); + my_bool (*advanced_command)(MYSQL *mysql, + enum enum_server_command command, + const unsigned char *header, + unsigned long header_length, + const unsigned char *arg, + unsigned long arg_length, + my_bool skip_check, + MYSQL_STMT *stmt); + MYSQL_DATA *(*read_rows)(MYSQL *mysql,MYSQL_FIELD *mysql_fields, + unsigned int fields); + MYSQL_RES * (*use_result)(MYSQL *mysql); + void (*fetch_lengths)(unsigned long *to, + MYSQL_ROW column, unsigned int field_count); + void (*flush_use_result)(MYSQL *mysql, my_bool flush_all_results); + int (*read_change_user_result)(MYSQL *mysql); +#if !defined(MYSQL_SERVER) || defined(EMBEDDED_LIBRARY) + MYSQL_FIELD * (*list_fields)(MYSQL *mysql); + my_bool (*read_prepare_result)(MYSQL *mysql, MYSQL_STMT *stmt); + int (*stmt_execute)(MYSQL_STMT *stmt); + int (*read_binary_rows)(MYSQL_STMT *stmt); + int (*unbuffered_fetch)(MYSQL *mysql, char **row); + void (*free_embedded_thd)(MYSQL *mysql); + const char *(*read_statistics)(MYSQL *mysql); + my_bool (*next_result)(MYSQL *mysql); + int (*read_rows_from_cursor)(MYSQL_STMT *stmt); +#endif +} MYSQL_METHODS; + +#define simple_command(mysql, command, arg, length, skip_check) \ + (*(mysql)->methods->advanced_command)(mysql, command, 0, \ + 0, arg, length, skip_check, NULL) +#define stmt_command(mysql, command, arg, length, stmt) \ + (*(mysql)->methods->advanced_command)(mysql, command, 0, \ + 0, arg, length, 1, stmt) + +extern CHARSET_INFO *default_client_charset_info; +MYSQL_FIELD *unpack_fields(MYSQL_DATA *data,MEM_ROOT *alloc,uint fields, + my_bool default_value, uint server_capabilities); +void free_rows(MYSQL_DATA *cur); +void free_old_query(MYSQL *mysql); +void end_server(MYSQL *mysql); +my_bool mysql_reconnect(MYSQL *mysql); +void mysql_read_default_options(struct st_mysql_options *options, + const char *filename,const char *group); +my_bool +cli_advanced_command(MYSQL *mysql, enum enum_server_command command, + const unsigned char *header, ulong header_length, + const unsigned char *arg, ulong arg_length, + my_bool skip_check, MYSQL_STMT *stmt); +unsigned long cli_safe_read(MYSQL *mysql); +void net_clear_error(NET *net); +void set_stmt_errmsg(MYSQL_STMT *stmt, NET *net); +void set_stmt_error(MYSQL_STMT *stmt, int errcode, const char *sqlstate, + const char *err); +void set_mysql_error(MYSQL *mysql, int errcode, const char *sqlstate); +void set_mysql_extended_error(MYSQL *mysql, int errcode, const char *sqlstate, + const char *format, ...); + +/* client side of the pluggable authentication */ +struct st_plugin_vio_info; +void mpvio_info(Vio *vio, struct st_plugin_vio_info *info); +int run_plugin_auth(MYSQL *mysql, char *data, uint data_len, + const char *data_plugin, const char *db); +int mysql_client_plugin_init(); +void mysql_client_plugin_deinit(); +struct st_mysql_client_plugin; +extern struct st_mysql_client_plugin *mysql_client_builtins[]; + +#ifdef __cplusplus +} +#endif + +#define protocol_41(A) ((A)->server_capabilities & CLIENT_PROTOCOL_41) + +#endif /* SQL_COMMON_INCLUDED */ diff --git a/include/mysql/sql_state.h b/include/mysql/sql_state.h new file mode 100644 index 000000000..edd6f694b --- /dev/null +++ b/include/mysql/sql_state.h @@ -0,0 +1,220 @@ +/* Autogenerated file, please don't edit */ + +{ ER_DUP_KEY ,"23000", "" }, +{ ER_OUTOFMEMORY ,"HY001", "S1001" }, +{ ER_OUT_OF_SORTMEMORY ,"HY001", "S1001" }, +{ ER_CON_COUNT_ERROR ,"08004", "" }, +{ ER_BAD_HOST_ERROR ,"08S01", "" }, +{ ER_HANDSHAKE_ERROR ,"08S01", "" }, +{ ER_DBACCESS_DENIED_ERROR ,"42000", "" }, +{ ER_ACCESS_DENIED_ERROR ,"28000", "" }, +{ ER_NO_DB_ERROR ,"3D000", "" }, +{ ER_UNKNOWN_COM_ERROR ,"08S01", "" }, +{ ER_BAD_NULL_ERROR ,"23000", "" }, +{ ER_BAD_DB_ERROR ,"42000", "" }, +{ ER_TABLE_EXISTS_ERROR ,"42S01", "" }, +{ ER_BAD_TABLE_ERROR ,"42S02", "" }, +{ ER_NON_UNIQ_ERROR ,"23000", "" }, +{ ER_SERVER_SHUTDOWN ,"08S01", "" }, +{ ER_BAD_FIELD_ERROR ,"42S22", "S0022" }, +{ ER_WRONG_FIELD_WITH_GROUP ,"42000", "S1009" }, +{ ER_WRONG_GROUP_FIELD ,"42000", "S1009" }, +{ ER_WRONG_SUM_SELECT ,"42000", "S1009" }, +{ ER_WRONG_VALUE_COUNT ,"21S01", "" }, +{ ER_TOO_LONG_IDENT ,"42000", "S1009" }, +{ ER_DUP_FIELDNAME ,"42S21", "S1009" }, +{ ER_DUP_KEYNAME ,"42000", "S1009" }, +{ ER_DUP_ENTRY ,"23000", "S1009" }, +{ ER_WRONG_FIELD_SPEC ,"42000", "S1009" }, +{ ER_PARSE_ERROR ,"42000", "s1009" }, +{ ER_EMPTY_QUERY ,"42000", "" }, +{ ER_NONUNIQ_TABLE ,"42000", "S1009" }, +{ ER_INVALID_DEFAULT ,"42000", "S1009" }, +{ ER_MULTIPLE_PRI_KEY ,"42000", "S1009" }, +{ ER_TOO_MANY_KEYS ,"42000", "S1009" }, +{ ER_TOO_MANY_KEY_PARTS ,"42000", "S1009" }, +{ ER_TOO_LONG_KEY ,"42000", "S1009" }, +{ ER_KEY_COLUMN_DOES_NOT_EXITS ,"42000", "S1009" }, +{ ER_BLOB_USED_AS_KEY ,"42000", "S1009" }, +{ ER_TOO_BIG_FIELDLENGTH ,"42000", "S1009" }, +{ ER_WRONG_AUTO_KEY ,"42000", "S1009" }, +{ ER_FORCING_CLOSE ,"08S01", "" }, +{ ER_IPSOCK_ERROR ,"08S01", "" }, +{ ER_NO_SUCH_INDEX ,"42S12", "S1009" }, +{ ER_WRONG_FIELD_TERMINATORS ,"42000", "S1009" }, +{ ER_BLOBS_AND_NO_TERMINATED ,"42000", "S1009" }, +{ ER_CANT_REMOVE_ALL_FIELDS ,"42000", "" }, +{ ER_CANT_DROP_FIELD_OR_KEY ,"42000", "" }, +{ ER_BLOB_CANT_HAVE_DEFAULT ,"42000", "" }, +{ ER_WRONG_DB_NAME ,"42000", "" }, +{ ER_WRONG_TABLE_NAME ,"42000", "" }, +{ ER_TOO_BIG_SELECT ,"42000", "" }, +{ ER_UNKNOWN_PROCEDURE ,"42000", "" }, +{ ER_WRONG_PARAMCOUNT_TO_PROCEDURE ,"42000", "" }, +{ ER_UNKNOWN_TABLE ,"42S02", "" }, +{ ER_FIELD_SPECIFIED_TWICE ,"42000", "" }, +{ ER_UNSUPPORTED_EXTENSION ,"42000", "" }, +{ ER_TABLE_MUST_HAVE_COLUMNS ,"42000", "" }, +{ ER_UNKNOWN_CHARACTER_SET ,"42000", "" }, +{ ER_TOO_BIG_ROWSIZE ,"42000", "" }, +{ ER_WRONG_OUTER_JOIN ,"42000", "" }, +{ ER_NULL_COLUMN_IN_INDEX ,"42000", "" }, +{ ER_PASSWORD_ANONYMOUS_USER ,"42000", "" }, +{ ER_PASSWORD_NOT_ALLOWED ,"42000", "" }, +{ ER_PASSWORD_NO_MATCH ,"42000", "" }, +{ ER_WRONG_VALUE_COUNT_ON_ROW ,"21S01", "" }, +{ ER_INVALID_USE_OF_NULL ,"22004", "" }, +{ ER_REGEXP_ERROR ,"42000", "" }, +{ ER_MIX_OF_GROUP_FUNC_AND_FIELDS ,"42000", "" }, +{ ER_NONEXISTING_GRANT ,"42000", "" }, +{ ER_TABLEACCESS_DENIED_ERROR ,"42000", "" }, +{ ER_COLUMNACCESS_DENIED_ERROR ,"42000", "" }, +{ ER_ILLEGAL_GRANT_FOR_TABLE ,"42000", "" }, +{ ER_GRANT_WRONG_HOST_OR_USER ,"42000", "" }, +{ ER_NO_SUCH_TABLE ,"42S02", "" }, +{ ER_NONEXISTING_TABLE_GRANT ,"42000", "" }, +{ ER_NOT_ALLOWED_COMMAND ,"42000", "" }, +{ ER_SYNTAX_ERROR ,"42000", "" }, +{ ER_ABORTING_CONNECTION ,"08S01", "" }, +{ ER_NET_PACKET_TOO_LARGE ,"08S01", "" }, +{ ER_NET_READ_ERROR_FROM_PIPE ,"08S01", "" }, +{ ER_NET_FCNTL_ERROR ,"08S01", "" }, +{ ER_NET_PACKETS_OUT_OF_ORDER ,"08S01", "" }, +{ ER_NET_UNCOMPRESS_ERROR ,"08S01", "" }, +{ ER_NET_READ_ERROR ,"08S01", "" }, +{ ER_NET_READ_INTERRUPTED ,"08S01", "" }, +{ ER_NET_ERROR_ON_WRITE ,"08S01", "" }, +{ ER_NET_WRITE_INTERRUPTED ,"08S01", "" }, +{ ER_TOO_LONG_STRING ,"42000", "" }, +{ ER_TABLE_CANT_HANDLE_BLOB ,"42000", "" }, +{ ER_TABLE_CANT_HANDLE_AUTO_INCREMENT ,"42000", "" }, +{ ER_WRONG_COLUMN_NAME ,"42000", "" }, +{ ER_WRONG_KEY_COLUMN ,"42000", "" }, +{ ER_DUP_UNIQUE ,"23000", "" }, +{ ER_BLOB_KEY_WITHOUT_LENGTH ,"42000", "" }, +{ ER_PRIMARY_CANT_HAVE_NULL ,"42000", "" }, +{ ER_TOO_MANY_ROWS ,"42000", "" }, +{ ER_REQUIRES_PRIMARY_KEY ,"42000", "" }, +{ ER_KEY_DOES_NOT_EXITS ,"42000", "S1009" }, +{ ER_CHECK_NO_SUCH_TABLE ,"42000", "" }, +{ ER_CHECK_NOT_IMPLEMENTED ,"42000", "" }, +{ ER_CANT_DO_THIS_DURING_AN_TRANSACTION ,"25000", "" }, +{ ER_NEW_ABORTING_CONNECTION ,"08S01", "" }, +{ ER_MASTER_NET_READ ,"08S01", "" }, +{ ER_MASTER_NET_WRITE ,"08S01", "" }, +{ ER_TOO_MANY_USER_CONNECTIONS ,"42000", "" }, +{ ER_READ_ONLY_TRANSACTION ,"25000", "" }, +{ ER_NO_PERMISSION_TO_CREATE_USER ,"42000", "" }, +{ ER_LOCK_DEADLOCK ,"40001", "" }, +{ ER_NO_REFERENCED_ROW ,"23000", "" }, +{ ER_ROW_IS_REFERENCED ,"23000", "" }, +{ ER_CONNECT_TO_MASTER ,"08S01", "" }, +{ ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT ,"21000", "" }, +{ ER_USER_LIMIT_REACHED ,"42000", "" }, +{ ER_SPECIFIC_ACCESS_DENIED_ERROR ,"42000", "" }, +{ ER_NO_DEFAULT ,"42000", "" }, +{ ER_WRONG_VALUE_FOR_VAR ,"42000", "" }, +{ ER_WRONG_TYPE_FOR_VAR ,"42000", "" }, +{ ER_CANT_USE_OPTION_HERE ,"42000", "" }, +{ ER_NOT_SUPPORTED_YET ,"42000", "" }, +{ ER_WRONG_FK_DEF ,"42000", "" }, +{ ER_OPERAND_COLUMNS ,"21000", "" }, +{ ER_SUBQUERY_NO_1_ROW ,"21000", "" }, +{ ER_ILLEGAL_REFERENCE ,"42S22", "" }, +{ ER_DERIVED_MUST_HAVE_ALIAS ,"42000", "" }, +{ ER_SELECT_REDUCED ,"01000", "" }, +{ ER_TABLENAME_NOT_ALLOWED_HERE ,"42000", "" }, +{ ER_NOT_SUPPORTED_AUTH_MODE ,"08004", "" }, +{ ER_SPATIAL_CANT_HAVE_NULL ,"42000", "" }, +{ ER_COLLATION_CHARSET_MISMATCH ,"42000", "" }, +{ ER_WARN_TOO_FEW_RECORDS ,"01000", "" }, +{ ER_WARN_TOO_MANY_RECORDS ,"01000", "" }, +{ ER_WARN_NULL_TO_NOTNULL ,"22004", "" }, +{ ER_WARN_DATA_OUT_OF_RANGE ,"22003", "" }, +{ WARN_DATA_TRUNCATED ,"01000", "" }, +{ ER_WRONG_NAME_FOR_INDEX ,"42000", "" }, +{ ER_WRONG_NAME_FOR_CATALOG ,"42000", "" }, +{ ER_UNKNOWN_STORAGE_ENGINE ,"42000", "" }, +{ ER_TRUNCATED_WRONG_VALUE ,"22007", "" }, +{ ER_SP_NO_RECURSIVE_CREATE ,"2F003", "" }, +{ ER_SP_ALREADY_EXISTS ,"42000", "" }, +{ ER_SP_DOES_NOT_EXIST ,"42000", "" }, +{ ER_SP_LILABEL_MISMATCH ,"42000", "" }, +{ ER_SP_LABEL_REDEFINE ,"42000", "" }, +{ ER_SP_LABEL_MISMATCH ,"42000", "" }, +{ ER_SP_UNINIT_VAR ,"01000", "" }, +{ ER_SP_BADSELECT ,"0A000", "" }, +{ ER_SP_BADRETURN ,"42000", "" }, +{ ER_SP_BADSTATEMENT ,"0A000", "" }, +{ ER_UPDATE_LOG_DEPRECATED_IGNORED ,"42000", "" }, +{ ER_UPDATE_LOG_DEPRECATED_TRANSLATED ,"42000", "" }, +{ ER_QUERY_INTERRUPTED ,"70100", "" }, +{ ER_SP_WRONG_NO_OF_ARGS ,"42000", "" }, +{ ER_SP_COND_MISMATCH ,"42000", "" }, +{ ER_SP_NORETURN ,"42000", "" }, +{ ER_SP_NORETURNEND ,"2F005", "" }, +{ ER_SP_BAD_CURSOR_QUERY ,"42000", "" }, +{ ER_SP_BAD_CURSOR_SELECT ,"42000", "" }, +{ ER_SP_CURSOR_MISMATCH ,"42000", "" }, +{ ER_SP_CURSOR_ALREADY_OPEN ,"24000", "" }, +{ ER_SP_CURSOR_NOT_OPEN ,"24000", "" }, +{ ER_SP_UNDECLARED_VAR ,"42000", "" }, +{ ER_SP_FETCH_NO_DATA ,"02000", "" }, +{ ER_SP_DUP_PARAM ,"42000", "" }, +{ ER_SP_DUP_VAR ,"42000", "" }, +{ ER_SP_DUP_COND ,"42000", "" }, +{ ER_SP_DUP_CURS ,"42000", "" }, +{ ER_SP_SUBSELECT_NYI ,"0A000", "" }, +{ ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG ,"0A000", "" }, +{ ER_SP_VARCOND_AFTER_CURSHNDLR ,"42000", "" }, +{ ER_SP_CURSOR_AFTER_HANDLER ,"42000", "" }, +{ ER_SP_CASE_NOT_FOUND ,"20000", "" }, +{ ER_DIVISION_BY_ZERO ,"22012", "" }, +{ ER_ILLEGAL_VALUE_FOR_TYPE ,"22007", "" }, +{ ER_PROCACCESS_DENIED_ERROR ,"42000", "" }, +{ ER_XAER_NOTA ,"XAE04", "" }, +{ ER_XAER_INVAL ,"XAE05", "" }, +{ ER_XAER_RMFAIL ,"XAE07", "" }, +{ ER_XAER_OUTSIDE ,"XAE09", "" }, +{ ER_XAER_RMERR ,"XAE03", "" }, +{ ER_XA_RBROLLBACK ,"XA100", "" }, +{ ER_NONEXISTING_PROC_GRANT ,"42000", "" }, +{ ER_DATA_TOO_LONG ,"22001", "" }, +{ ER_SP_BAD_SQLSTATE ,"42000", "" }, +{ ER_CANT_CREATE_USER_WITH_GRANT ,"42000", "" }, +{ ER_SP_DUP_HANDLER ,"42000", "" }, +{ ER_SP_NOT_VAR_ARG ,"42000", "" }, +{ ER_SP_NO_RETSET ,"0A000", "" }, +{ ER_CANT_CREATE_GEOMETRY_OBJECT ,"22003", "" }, +{ ER_TOO_BIG_SCALE ,"42000", "S1009" }, +{ ER_TOO_BIG_PRECISION ,"42000", "S1009" }, +{ ER_M_BIGGER_THAN_D ,"42000", "S1009" }, +{ ER_TOO_LONG_BODY ,"42000", "S1009" }, +{ ER_TOO_BIG_DISPLAYWIDTH ,"42000", "S1009" }, +{ ER_XAER_DUPID ,"XAE08", "" }, +{ ER_DATETIME_FUNCTION_OVERFLOW ,"22008", "" }, +{ ER_ROW_IS_REFERENCED_2 ,"23000", "" }, +{ ER_NO_REFERENCED_ROW_2 ,"23000", "" }, +{ ER_SP_BAD_VAR_SHADOW ,"42000", "" }, +{ ER_SP_WRONG_NAME ,"42000", "" }, +{ ER_SP_NO_AGGREGATE ,"42000", "" }, +{ ER_MAX_PREPARED_STMT_COUNT_REACHED ,"42000", "" }, +{ ER_NON_GROUPING_FIELD_USED ,"42000", "" }, +{ ER_FOREIGN_DUPLICATE_KEY ,"23000", "S1009" }, +{ ER_CANT_CHANGE_TX_ISOLATION ,"25001", "" }, +{ ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT ,"42000", "" }, +{ ER_WRONG_PARAMETERS_TO_NATIVE_FCT ,"42000", "" }, +{ ER_WRONG_PARAMETERS_TO_STORED_FCT ,"42000", "" }, +{ ER_DUP_ENTRY_WITH_KEY_NAME ,"23000", "S1009" }, +{ ER_XA_RBTIMEOUT ,"XA106", "" }, +{ ER_XA_RBDEADLOCK ,"XA102", "" }, +{ ER_FUNC_INEXISTENT_NAME_COLLISION ,"42000", "" }, +{ ER_DUP_SIGNAL_SET ,"42000", "" }, +{ ER_SIGNAL_WARN ,"01000", "" }, +{ ER_SIGNAL_NOT_FOUND ,"02000", "" }, +{ ER_SIGNAL_EXCEPTION ,"HY000", "" }, +{ ER_RESIGNAL_WITHOUT_ACTIVE_HANDLER ,"0K000", "" }, +{ ER_SPATIAL_MUST_HAVE_GEOM_COL ,"42000", "" }, +{ ER_DATA_OUT_OF_RANGE ,"22003", "" }, +{ ER_ACCESS_DENIED_NO_PASSWORD_ERROR ,"28000", "" }, +{ ER_TRUNCATE_ILLEGAL_FK ,"42000", "" }, diff --git a/include/mysql/sslopt-case.h b/include/mysql/sslopt-case.h new file mode 100644 index 000000000..3b64a225f --- /dev/null +++ b/include/mysql/sslopt-case.h @@ -0,0 +1,32 @@ +#ifndef SSLOPT_CASE_INCLUDED +#define SSLOPT_CASE_INCLUDED + +/* Copyright (C) 2000 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) + case OPT_SSL_KEY: + case OPT_SSL_CERT: + case OPT_SSL_CA: + case OPT_SSL_CAPATH: + case OPT_SSL_CIPHER: + /* + Enable use of SSL if we are using any ssl option + One can disable SSL later by using --skip-ssl or --ssl=0 + */ + opt_use_ssl= 1; + break; +#endif +#endif /* SSLOPT_CASE_INCLUDED */ diff --git a/include/mysql/sslopt-longopts.h b/include/mysql/sslopt-longopts.h new file mode 100644 index 000000000..5315b2e12 --- /dev/null +++ b/include/mysql/sslopt-longopts.h @@ -0,0 +1,49 @@ +#ifndef SSLOPT_LONGOPTS_INCLUDED +#define SSLOPT_LONGOPTS_INCLUDED + +/* Copyright (C) 2000 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) + + {"ssl", OPT_SSL_SSL, + "Enable SSL for connection (automatically enabled with other flags).", + &opt_use_ssl, &opt_use_ssl, 0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0}, + {"ssl-ca", OPT_SSL_CA, + "CA file in PEM format (check OpenSSL docs, implies --ssl).", + &opt_ssl_ca, &opt_ssl_ca, 0, GET_STR, REQUIRED_ARG, + 0, 0, 0, 0, 0, 0}, + {"ssl-capath", OPT_SSL_CAPATH, + "CA directory (check OpenSSL docs, implies --ssl).", + &opt_ssl_capath, &opt_ssl_capath, 0, GET_STR, REQUIRED_ARG, + 0, 0, 0, 0, 0, 0}, + {"ssl-cert", OPT_SSL_CERT, "X509 cert in PEM format (implies --ssl).", + &opt_ssl_cert, &opt_ssl_cert, 0, GET_STR, REQUIRED_ARG, + 0, 0, 0, 0, 0, 0}, + {"ssl-cipher", OPT_SSL_CIPHER, "SSL cipher to use (implies --ssl).", + &opt_ssl_cipher, &opt_ssl_cipher, 0, GET_STR, REQUIRED_ARG, + 0, 0, 0, 0, 0, 0}, + {"ssl-key", OPT_SSL_KEY, "X509 key in PEM format (implies --ssl).", + &opt_ssl_key, &opt_ssl_key, 0, GET_STR, REQUIRED_ARG, + 0, 0, 0, 0, 0, 0}, +#ifdef MYSQL_CLIENT + {"ssl-verify-server-cert", OPT_SSL_VERIFY_SERVER_CERT, + "Verify server's \"Common Name\" in its cert against hostname used " + "when connecting. This option is disabled by default.", + &opt_ssl_verify_server_cert, &opt_ssl_verify_server_cert, + 0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0}, +#endif +#endif /* HAVE_OPENSSL */ +#endif /* SSLOPT_LONGOPTS_INCLUDED */ diff --git a/include/mysql/sslopt-vars.h b/include/mysql/sslopt-vars.h new file mode 100644 index 000000000..d0eec3b6d --- /dev/null +++ b/include/mysql/sslopt-vars.h @@ -0,0 +1,35 @@ +#ifndef SSLOPT_VARS_INCLUDED +#define SSLOPT_VARS_INCLUDED + +/* Copyright (C) 2000 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) +#ifdef SSL_VARS_NOT_STATIC +#define SSL_STATIC +#else +#define SSL_STATIC static +#endif +SSL_STATIC my_bool opt_use_ssl = 0; +SSL_STATIC char *opt_ssl_ca = 0; +SSL_STATIC char *opt_ssl_capath = 0; +SSL_STATIC char *opt_ssl_cert = 0; +SSL_STATIC char *opt_ssl_cipher = 0; +SSL_STATIC char *opt_ssl_key = 0; +#ifdef MYSQL_CLIENT +SSL_STATIC my_bool opt_ssl_verify_server_cert= 0; +#endif +#endif +#endif /* SSLOPT_VARS_INCLUDED */ diff --git a/include/mysql/typelib.h b/include/mysql/typelib.h new file mode 100644 index 000000000..3badb14c9 --- /dev/null +++ b/include/mysql/typelib.h @@ -0,0 +1,44 @@ +/* Copyright (C) 2000 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + + +#ifndef _typelib_h +#define _typelib_h + +#include "my_alloc.h" + +typedef struct st_typelib { /* Different types saved here */ + unsigned int count; /* How many types */ + const char *name; /* Name of typelib */ + const char **type_names; + unsigned int *type_lengths; +} TYPELIB; + +extern my_ulonglong find_typeset(char *x, TYPELIB *typelib,int *error_position); +extern int find_type_or_exit(const char *x, TYPELIB *typelib, + const char *option); +extern int find_type(char *x, const TYPELIB *typelib, unsigned int full_name); +extern void make_type(char *to,unsigned int nr,TYPELIB *typelib); +extern const char *get_type(TYPELIB *typelib,unsigned int nr); +extern TYPELIB *copy_typelib(MEM_ROOT *root, TYPELIB *from); + +extern TYPELIB sql_protocol_typelib; + +my_ulonglong find_set_from_flags(const TYPELIB *lib, unsigned int default_name, + my_ulonglong cur_set, my_ulonglong default_set, + const char *str, unsigned int length, + char **err_pos, unsigned int *err_len); + +#endif /* _typelib_h */ diff --git a/include/polarssl/aes.h b/include/polarssl/aes.h new file mode 100644 index 000000000..80fd6d932 --- /dev/null +++ b/include/polarssl/aes.h @@ -0,0 +1,176 @@ +/** + * \file aes.h + * + * \brief AES block cipher + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_AES_H +#define POLARSSL_AES_H + +#include + +#define AES_ENCRYPT 1 +#define AES_DECRYPT 0 + +#define POLARSSL_ERR_AES_INVALID_KEY_LENGTH -0x0020 /**< Invalid key length. */ +#define POLARSSL_ERR_AES_INVALID_INPUT_LENGTH -0x0022 /**< Invalid data input length. */ + +/** + * \brief AES context structure + */ +typedef struct +{ + int nr; /*!< number of rounds */ + unsigned long *rk; /*!< AES round keys */ + unsigned long buf[68]; /*!< unaligned data */ +} +aes_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief AES key schedule (encryption) + * + * \param ctx AES context to be initialized + * \param key encryption key + * \param keysize must be 128, 192 or 256 + * + * \return 0 if successful, or POLARSSL_ERR_AES_INVALID_KEY_LENGTH + */ +int aes_setkey_enc( aes_context *ctx, const unsigned char *key, unsigned int keysize ); + +/** + * \brief AES key schedule (decryption) + * + * \param ctx AES context to be initialized + * \param key decryption key + * \param keysize must be 128, 192 or 256 + * + * \return 0 if successful, or POLARSSL_ERR_AES_INVALID_KEY_LENGTH + */ +int aes_setkey_dec( aes_context *ctx, const unsigned char *key, unsigned int keysize ); + +/** + * \brief AES-ECB block encryption/decryption + * + * \param ctx AES context + * \param mode AES_ENCRYPT or AES_DECRYPT + * \param input 16-byte input block + * \param output 16-byte output block + * + * \return 0 if successful + */ +int aes_crypt_ecb( aes_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16] ); + +/** + * \brief AES-CBC buffer encryption/decryption + * Length should be a multiple of the block + * size (16 bytes) + * + * \param ctx AES context + * \param mode AES_ENCRYPT or AES_DECRYPT + * \param length length of the input data + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + * + * \return 0 if successful, or POLARSSL_ERR_AES_INVALID_INPUT_LENGTH + */ +int aes_crypt_cbc( aes_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ); + +/** + * \brief AES-CFB128 buffer encryption/decryption. + * + * Note: Due to the nature of CFB you should use the same key schedule for + * both encryption and decryption. So a context initialized with + * aes_setkey_enc() for both AES_ENCRYPT and AES_DECRYPT. + * + * both + * \param ctx AES context + * \param mode AES_ENCRYPT or AES_DECRYPT + * \param length length of the input data + * \param iv_off offset in IV (updated after use) + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + * + * \return 0 if successful + */ +int aes_crypt_cfb128( aes_context *ctx, + int mode, + size_t length, + size_t *iv_off, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ); + +/* + * \brief AES-CTR buffer encryption/decryption + * + * Warning: You have to keep the maximum use of your counter in mind! + * + * Note: Due to the nature of CTR you should use the same key schedule for + * both encryption and decryption. So a context initialized with + * aes_setkey_enc() for both AES_ENCRYPT and AES_DECRYPT. + * + * \param length The length of the data + * \param nc_off The offset in the current stream_block (for resuming + * within current cipher stream). The offset pointer to + * should be 0 at the start of a stream. + * \param nonce_counter The 128-bit nonce and counter. + * \param stream_block The saved stream-block for resuming. Is overwritten + * by the function. + * \param input The input data stream + * \param output The output data stream + * + * \return 0 if successful + */ +int aes_crypt_ctr( aes_context *ctx, + size_t length, + size_t *nc_off, + unsigned char nonce_counter[16], + unsigned char stream_block[16], + const unsigned char *input, + unsigned char *output ); +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int aes_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* aes.h */ diff --git a/include/polarssl/arc4.h b/include/polarssl/arc4.h new file mode 100644 index 000000000..48ad60b26 --- /dev/null +++ b/include/polarssl/arc4.h @@ -0,0 +1,80 @@ +/** + * \file arc4.h + * + * \brief The ARCFOUR stream cipher + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_ARC4_H +#define POLARSSL_ARC4_H + +#include + +/** + * \brief ARC4 context structure + */ +typedef struct +{ + int x; /*!< permutation index */ + int y; /*!< permutation index */ + unsigned char m[256]; /*!< permutation table */ +} +arc4_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief ARC4 key schedule + * + * \param ctx ARC4 context to be initialized + * \param key the secret key + * \param keylen length of the key + */ +void arc4_setup( arc4_context *ctx, const unsigned char *key, unsigned int keylen ); + +/** + * \brief ARC4 cipher function + * + * \param ctx ARC4 context + * \param length length of the input data + * \param input buffer holding the input data + * \param output buffer for the output data + * + * \return 0 if successful + */ +int arc4_crypt( arc4_context *ctx, size_t length, const unsigned char *input, + unsigned char *output ); + +/* + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int arc4_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* arc4.h */ diff --git a/include/polarssl/asn1.h b/include/polarssl/asn1.h new file mode 100644 index 000000000..bc7b6bba9 --- /dev/null +++ b/include/polarssl/asn1.h @@ -0,0 +1,244 @@ +/** + * \file asn1.h + * + * \brief Generic ASN.1 parsing + * + * Copyright (C) 2006-2011, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_ASN1_H +#define POLARSSL_ASN1_H + +#include "config.h" + +#if defined(POLARSSL_BIGNUM_C) +#include "bignum.h" +#endif + +#include + +/** + * \addtogroup asn1_module + * \{ + */ + +/** + * \name ASN1 Error codes + * These error codes are OR'ed to X509 error codes for + * higher error granularity. + * ASN1 is a standard to specify data structures. + * \{ + */ +#define POLARSSL_ERR_ASN1_OUT_OF_DATA -0x0014 /**< Out of data when parsing an ASN1 data structure. */ +#define POLARSSL_ERR_ASN1_UNEXPECTED_TAG -0x0016 /**< ASN1 tag was of an unexpected value. */ +#define POLARSSL_ERR_ASN1_INVALID_LENGTH -0x0018 /**< Error when trying to determine the length or invalid length. */ +#define POLARSSL_ERR_ASN1_LENGTH_MISMATCH -0x001A /**< Actual length differs from expected length. */ +#define POLARSSL_ERR_ASN1_INVALID_DATA -0x001C /**< Data is invalid. (not used) */ +#define POLARSSL_ERR_ASN1_MALLOC_FAILED -0x001E /**< Memory allocation failed */ +/* \} name */ + +/** + * \name DER constants + * These constants comply with DER encoded the ANS1 type tags. + * DER encoding uses hexadecimal representation. + * An example DER sequence is:\n + * - 0x02 -- tag indicating INTEGER + * - 0x01 -- length in octets + * - 0x05 -- value + * Such sequences are typically read into \c ::x509_buf. + * \{ + */ +#define ASN1_BOOLEAN 0x01 +#define ASN1_INTEGER 0x02 +#define ASN1_BIT_STRING 0x03 +#define ASN1_OCTET_STRING 0x04 +#define ASN1_NULL 0x05 +#define ASN1_OID 0x06 +#define ASN1_UTF8_STRING 0x0C +#define ASN1_SEQUENCE 0x10 +#define ASN1_SET 0x11 +#define ASN1_PRINTABLE_STRING 0x13 +#define ASN1_T61_STRING 0x14 +#define ASN1_IA5_STRING 0x16 +#define ASN1_UTC_TIME 0x17 +#define ASN1_GENERALIZED_TIME 0x18 +#define ASN1_UNIVERSAL_STRING 0x1C +#define ASN1_BMP_STRING 0x1E +#define ASN1_PRIMITIVE 0x00 +#define ASN1_CONSTRUCTED 0x20 +#define ASN1_CONTEXT_SPECIFIC 0x80 +/* \} name */ +/* \} addtogroup asn1_module */ + +/** Returns the size of the binary string, without the trailing \\0 */ +#define OID_SIZE(x) (sizeof(x) - 1) + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \name Functions to parse ASN.1 data structures + * \{ + */ + +/** + * Type-length-value structure that allows for ASN1 using DER. + */ +typedef struct _asn1_buf +{ + int tag; /**< ASN1 type, e.g. ASN1_UTF8_STRING. */ + size_t len; /**< ASN1 length, e.g. in octets. */ + unsigned char *p; /**< ASN1 data, e.g. in ASCII. */ +} +asn1_buf; + +/** + * Container for ASN1 bit strings. + */ +typedef struct _asn1_bitstring +{ + size_t len; /**< ASN1 length, e.g. in octets. */ + unsigned char unused_bits; /**< Number of unused bits at the end of the string */ + unsigned char *p; /**< Raw ASN1 data for the bit string */ +} +asn1_bitstring; + +/** + * Container for a sequence of ASN.1 items + */ +typedef struct _asn1_sequence +{ + asn1_buf buf; /**< Buffer containing the given ASN.1 item. */ + struct _asn1_sequence *next; /**< The next entry in the sequence. */ +} +asn1_sequence; + +/** + * Get the length of an ASN.1 element. + * Updates the pointer to immediately behind the length. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param len The variable that will receive the value + * + * \return 0 if successful, POLARSSL_ERR_ASN1_OUT_OF_DATA on reaching + * end of data, POLARSSL_ERR_ASN1_INVALID_LENGTH if length is + * unparseable. + */ +int asn1_get_len( unsigned char **p, + const unsigned char *end, + size_t *len ); + +/** + * Get the tag and length of the tag. Check for the requested tag. + * Updates the pointer to immediately behind the tag and length. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param len The variable that will receive the length + * \param tag The expected tag + * + * \return 0 if successful, POLARSSL_ERR_ASN1_UNEXPECTED_TAG if tag did + * not match requested tag, or another specific ASN.1 error code. + */ +int asn1_get_tag( unsigned char **p, + const unsigned char *end, + size_t *len, int tag ); + +/** + * Retrieve a boolean ASN.1 tag and its value. + * Updates the pointer to immediately behind the full tag. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param val The variable that will receive the value + * + * \return 0 if successful or a specific ASN.1 error code. + */ +int asn1_get_bool( unsigned char **p, + const unsigned char *end, + int *val ); + +/** + * Retrieve an integer ASN.1 tag and its value. + * Updates the pointer to immediately behind the full tag. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param val The variable that will receive the value + * + * \return 0 if successful or a specific ASN.1 error code. + */ +int asn1_get_int( unsigned char **p, + const unsigned char *end, + int *val ); + +/** + * Retrieve a bitstring ASN.1 tag and its value. + * Updates the pointer to immediately behind the full tag. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param bs The variable that will receive the value + * + * \return 0 if successful or a specific ASN.1 error code. + */ +int asn1_get_bitstring( unsigned char **p, const unsigned char *end, + asn1_bitstring *bs); + +/** + * Parses and splits an ASN.1 "SEQUENCE OF " + * Updated the pointer to immediately behind the full sequence tag. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param cur First variable in the chain to fill + * \param tag Type of sequence + * + * \return 0 if successful or a specific ASN.1 error code. + */ +int asn1_get_sequence_of( unsigned char **p, + const unsigned char *end, + asn1_sequence *cur, + int tag); + +#if defined(POLARSSL_BIGNUM_C) +/** + * Retrieve a MPI value from an integer ASN.1 tag. + * Updates the pointer to immediately behind the full tag. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param X The MPI that will receive the value + * + * \return 0 if successful or a specific ASN.1 or MPI error code. + */ +int asn1_get_mpi( unsigned char **p, + const unsigned char *end, + mpi *X ); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* asn1.h */ diff --git a/include/polarssl/base64.h b/include/polarssl/base64.h new file mode 100644 index 000000000..883215dd4 --- /dev/null +++ b/include/polarssl/base64.h @@ -0,0 +1,87 @@ +/** + * \file base64.h + * + * \brief RFC 1521 base64 encoding/decoding + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_BASE64_H +#define POLARSSL_BASE64_H + +#include + +#define POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL -0x002A /**< Output buffer too small. */ +#define POLARSSL_ERR_BASE64_INVALID_CHARACTER -0x002C /**< Invalid character in input. */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Encode a buffer into base64 format + * + * \param dst destination buffer + * \param dlen size of the buffer + * \param src source buffer + * \param slen amount of data to be encoded + * + * \return 0 if successful, or POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL. + * *dlen is always updated to reflect the amount + * of data that has (or would have) been written. + * + * \note Call this function with *dlen = 0 to obtain the + * required buffer size in *dlen + */ +int base64_encode( unsigned char *dst, size_t *dlen, + const unsigned char *src, size_t slen ); + +/** + * \brief Decode a base64-formatted buffer + * + * \param dst destination buffer + * \param dlen size of the buffer + * \param src source buffer + * \param slen amount of data to be decoded + * + * \return 0 if successful, POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL, or + * POLARSSL_ERR_BASE64_INVALID_DATA if the input data is not + * correct. *dlen is always updated to reflect the amount + * of data that has (or would have) been written. + * + * \note Call this function with *dlen = 0 to obtain the + * required buffer size in *dlen + */ +int base64_decode( unsigned char *dst, size_t *dlen, + const unsigned char *src, size_t slen ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int base64_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* base64.h */ diff --git a/include/polarssl/bignum.h b/include/polarssl/bignum.h new file mode 100644 index 000000000..ad033084c --- /dev/null +++ b/include/polarssl/bignum.h @@ -0,0 +1,632 @@ +/** + * \file bignum.h + * + * \brief Multi-precision integer library + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_BIGNUM_H +#define POLARSSL_BIGNUM_H + +#include +#include + +#include "config.h" + +#define POLARSSL_ERR_MPI_FILE_IO_ERROR -0x0002 /**< An error occurred while reading from or writing to a file. */ +#define POLARSSL_ERR_MPI_BAD_INPUT_DATA -0x0004 /**< Bad input parameters to function. */ +#define POLARSSL_ERR_MPI_INVALID_CHARACTER -0x0006 /**< There is an invalid character in the digit string. */ +#define POLARSSL_ERR_MPI_BUFFER_TOO_SMALL -0x0008 /**< The buffer is too small to write to. */ +#define POLARSSL_ERR_MPI_NEGATIVE_VALUE -0x000A /**< The input arguments are negative or result in illegal output. */ +#define POLARSSL_ERR_MPI_DIVISION_BY_ZERO -0x000C /**< The input argument for division is zero, which is not allowed. */ +#define POLARSSL_ERR_MPI_NOT_ACCEPTABLE -0x000E /**< The input arguments are not acceptable. */ +#define POLARSSL_ERR_MPI_MALLOC_FAILED -0x0010 /**< Memory allocation failed. */ + +#define MPI_CHK(f) if( ( ret = f ) != 0 ) goto cleanup + +/* + * Maximum size MPIs are allowed to grow to in number of limbs. + */ +#define POLARSSL_MPI_MAX_LIMBS 10000 + +/* + * Maximum window size used for modular exponentiation. Default: 6 + * Minimum value: 1. Maximum value: 6. + * + * Result is an array of ( 2 << POLARSSL_MPI_WINDOW_SIZE ) MPIs used + * for the sliding window calculation. (So 64 by default) + * + * Reduction in size, reduces speed. + */ +#define POLARSSL_MPI_WINDOW_SIZE 6 /**< Maximum windows size used. */ + +/* + * Maximum size of MPIs allowed in bits and bytes for user-MPIs. + * ( Default: 512 bytes => 4096 bits ) + * + * Note: Calculations can results temporarily in larger MPIs. So the number + * of limbs required (POLARSSL_MPI_MAX_LIMBS) is higher. + */ +#define POLARSSL_MPI_MAX_SIZE 512 /**< Maximum number of bytes for usable MPIs. */ +#define POLARSSL_MPI_MAX_BITS ( 8 * POLARSSL_MPI_MAX_SIZE ) /**< Maximum number of bits for usable MPIs. */ + +/* + * When reading from files with mpi_read_file() the buffer should have space + * for a (short) label, the MPI (in the provided radix), the newline + * characters and the '\0'. + * + * By default we assume at least a 10 char label, a minimum radix of 10 + * (decimal) and a maximum of 4096 bit numbers (1234 decimal chars). + */ +#define POLARSSL_MPI_READ_BUFFER_SIZE 1250 + +/* + * Define the base integer type, architecture-wise + */ +#if defined(POLARSSL_HAVE_INT8) +typedef signed char t_sint; +typedef unsigned char t_uint; +typedef unsigned short t_udbl; +#else +#if defined(POLARSSL_HAVE_INT16) +typedef signed short t_sint; +typedef unsigned short t_uint; +typedef unsigned long t_udbl; +#else + typedef signed long t_sint; + typedef unsigned long t_uint; + #if defined(_MSC_VER) && defined(_M_IX86) + typedef unsigned __int64 t_udbl; + #else + #if defined(__GNUC__) && ( \ + defined(__amd64__) || defined(__x86_64__) || \ + defined(__ppc64__) || defined(__powerpc64__) || \ + defined(__ia64__) || defined(__alpha__) || \ + (defined(__sparc__) && defined(__arch64__)) || \ + defined(__s390x__) ) + typedef unsigned int t_udbl __attribute__((mode(TI))); + #define POLARSSL_HAVE_LONGLONG + #else + #if defined(POLARSSL_HAVE_LONGLONG) + typedef unsigned long long t_udbl; + #endif + #endif + #endif +#endif +#endif + +/** + * \brief MPI structure + */ +typedef struct +{ + int s; /*!< integer sign */ + size_t n; /*!< total # of limbs */ + t_uint *p; /*!< pointer to limbs */ +} +mpi; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Initialize one MPI + * + * \param X One MPI to initialize. + */ +void mpi_init( mpi *X ); + +/** + * \brief Unallocate one MPI + * + * \param X One MPI to unallocate. + */ +void mpi_free( mpi *X ); + +/** + * \brief Enlarge to the specified number of limbs + * + * \param X MPI to grow + * \param nblimbs The target number of limbs + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed + */ +int mpi_grow( mpi *X, size_t nblimbs ); + +/** + * \brief Copy the contents of Y into X + * + * \param X Destination MPI + * \param Y Source MPI + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed + */ +int mpi_copy( mpi *X, const mpi *Y ); + +/** + * \brief Swap the contents of X and Y + * + * \param X First MPI value + * \param Y Second MPI value + */ +void mpi_swap( mpi *X, mpi *Y ); + +/** + * \brief Set value from integer + * + * \param X MPI to set + * \param z Value to use + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed + */ +int mpi_lset( mpi *X, t_sint z ); + +/* + * \brief Get a specific bit from X + * + * \param X MPI to use + * \param pos Zero-based index of the bit in X + * + * \return Either a 0 or a 1 + */ +int mpi_get_bit( mpi *X, size_t pos ); + +/* + * \brief Set a bit of X to a specific value of 0 or 1 + * + * \note Will grow X if necessary to set a bit to 1 in a not yet + * existing limb. Will not grow if bit should be set to 0 + * + * \param X MPI to use + * \param pos Zero-based index of the bit in X + * \param val The value to set the bit to (0 or 1) + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed, + * POLARSSL_ERR_MPI_BAD_INPUT_DATA if val is not 0 or 1 + */ +int mpi_set_bit( mpi *X, size_t pos, unsigned char val ); + +/** + * \brief Return the number of least significant bits + * + * \param X MPI to use + */ +size_t mpi_lsb( const mpi *X ); + +/** + * \brief Return the number of most significant bits + * + * \param X MPI to use + */ +size_t mpi_msb( const mpi *X ); + +/** + * \brief Return the total size in bytes + * + * \param X MPI to use + */ +size_t mpi_size( const mpi *X ); + +/** + * \brief Import from an ASCII string + * + * \param X Destination MPI + * \param radix Input numeric base + * \param s Null-terminated string buffer + * + * \return 0 if successful, or a POLARSSL_ERR_MPI_XXX error code + */ +int mpi_read_string( mpi *X, int radix, const char *s ); + +/** + * \brief Export into an ASCII string + * + * \param X Source MPI + * \param radix Output numeric base + * \param s String buffer + * \param slen String buffer size + * + * \return 0 if successful, or a POLARSSL_ERR_MPI_XXX error code. + * *slen is always updated to reflect the amount + * of data that has (or would have) been written. + * + * \note Call this function with *slen = 0 to obtain the + * minimum required buffer size in *slen. + */ +int mpi_write_string( const mpi *X, int radix, char *s, size_t *slen ); + +/** + * \brief Read X from an opened file + * + * \param X Destination MPI + * \param radix Input numeric base + * \param fin Input file handle + * + * \return 0 if successful, POLARSSL_ERR_MPI_BUFFER_TOO_SMALL if + * the file read buffer is too small or a + * POLARSSL_ERR_MPI_XXX error code + */ +int mpi_read_file( mpi *X, int radix, FILE *fin ); + +/** + * \brief Write X into an opened file, or stdout if fout is NULL + * + * \param p Prefix, can be NULL + * \param X Source MPI + * \param radix Output numeric base + * \param fout Output file handle (can be NULL) + * + * \return 0 if successful, or a POLARSSL_ERR_MPI_XXX error code + * + * \note Set fout == NULL to print X on the console. + */ +int mpi_write_file( const char *p, const mpi *X, int radix, FILE *fout ); + +/** + * \brief Import X from unsigned binary data, big endian + * + * \param X Destination MPI + * \param buf Input buffer + * \param buflen Input buffer size + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed + */ +int mpi_read_binary( mpi *X, const unsigned char *buf, size_t buflen ); + +/** + * \brief Export X into unsigned binary data, big endian + * + * \param X Source MPI + * \param buf Output buffer + * \param buflen Output buffer size + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_BUFFER_TOO_SMALL if buf isn't large enough + */ +int mpi_write_binary( const mpi *X, unsigned char *buf, size_t buflen ); + +/** + * \brief Left-shift: X <<= count + * + * \param X MPI to shift + * \param count Amount to shift + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed + */ +int mpi_shift_l( mpi *X, size_t count ); + +/** + * \brief Right-shift: X >>= count + * + * \param X MPI to shift + * \param count Amount to shift + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed + */ +int mpi_shift_r( mpi *X, size_t count ); + +/** + * \brief Compare unsigned values + * + * \param X Left-hand MPI + * \param Y Right-hand MPI + * + * \return 1 if |X| is greater than |Y|, + * -1 if |X| is lesser than |Y| or + * 0 if |X| is equal to |Y| + */ +int mpi_cmp_abs( const mpi *X, const mpi *Y ); + +/** + * \brief Compare signed values + * + * \param X Left-hand MPI + * \param Y Right-hand MPI + * + * \return 1 if X is greater than Y, + * -1 if X is lesser than Y or + * 0 if X is equal to Y + */ +int mpi_cmp_mpi( const mpi *X, const mpi *Y ); + +/** + * \brief Compare signed values + * + * \param X Left-hand MPI + * \param z The integer value to compare to + * + * \return 1 if X is greater than z, + * -1 if X is lesser than z or + * 0 if X is equal to z + */ +int mpi_cmp_int( const mpi *X, t_sint z ); + +/** + * \brief Unsigned addition: X = |A| + |B| + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed + */ +int mpi_add_abs( mpi *X, const mpi *A, const mpi *B ); + +/** + * \brief Unsigned substraction: X = |A| - |B| + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_NEGATIVE_VALUE if B is greater than A + */ +int mpi_sub_abs( mpi *X, const mpi *A, const mpi *B ); + +/** + * \brief Signed addition: X = A + B + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed + */ +int mpi_add_mpi( mpi *X, const mpi *A, const mpi *B ); + +/** + * \brief Signed substraction: X = A - B + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed + */ +int mpi_sub_mpi( mpi *X, const mpi *A, const mpi *B ); + +/** + * \brief Signed addition: X = A + b + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param b The integer value to add + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed + */ +int mpi_add_int( mpi *X, const mpi *A, t_sint b ); + +/** + * \brief Signed substraction: X = A - b + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param b The integer value to subtract + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed + */ +int mpi_sub_int( mpi *X, const mpi *A, t_sint b ); + +/** + * \brief Baseline multiplication: X = A * B + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed + */ +int mpi_mul_mpi( mpi *X, const mpi *A, const mpi *B ); + +/** + * \brief Baseline multiplication: X = A * b + * Note: b is an unsigned integer type, thus + * Negative values of b are ignored. + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param b The integer value to multiply with + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed + */ +int mpi_mul_int( mpi *X, const mpi *A, t_sint b ); + +/** + * \brief Division by mpi: A = Q * B + R + * + * \param Q Destination MPI for the quotient + * \param R Destination MPI for the rest value + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed, + * POLARSSL_ERR_MPI_DIVISION_BY_ZERO if B == 0 + * + * \note Either Q or R can be NULL. + */ +int mpi_div_mpi( mpi *Q, mpi *R, const mpi *A, const mpi *B ); + +/** + * \brief Division by int: A = Q * b + R + * + * \param Q Destination MPI for the quotient + * \param R Destination MPI for the rest value + * \param A Left-hand MPI + * \param b Integer to divide by + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed, + * POLARSSL_ERR_MPI_DIVISION_BY_ZERO if b == 0 + * + * \note Either Q or R can be NULL. + */ +int mpi_div_int( mpi *Q, mpi *R, const mpi *A, t_sint b ); + +/** + * \brief Modulo: R = A mod B + * + * \param R Destination MPI for the rest value + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed, + * POLARSSL_ERR_MPI_DIVISION_BY_ZERO if B == 0, + * POLARSSL_ERR_MPI_NEGATIVE_VALUE if B < 0 + */ +int mpi_mod_mpi( mpi *R, const mpi *A, const mpi *B ); + +/** + * \brief Modulo: r = A mod b + * + * \param r Destination t_uint + * \param A Left-hand MPI + * \param b Integer to divide by + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed, + * POLARSSL_ERR_MPI_DIVISION_BY_ZERO if b == 0, + * POLARSSL_ERR_MPI_NEGATIVE_VALUE if b < 0 + */ +int mpi_mod_int( t_uint *r, const mpi *A, t_sint b ); + +/** + * \brief Sliding-window exponentiation: X = A^E mod N + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param E Exponent MPI + * \param N Modular MPI + * \param _RR Speed-up MPI used for recalculations + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed, + * POLARSSL_ERR_MPI_BAD_INPUT_DATA if N is negative or even + * + * \note _RR is used to avoid re-computing R*R mod N across + * multiple calls, which speeds up things a bit. It can + * be set to NULL if the extra performance is unneeded. + */ +int mpi_exp_mod( mpi *X, const mpi *A, const mpi *E, const mpi *N, mpi *_RR ); + +/** + * \brief Fill an MPI X with size bytes of random + * + * \param X Destination MPI + * \param size Size in bytes + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed + */ +int mpi_fill_random( mpi *X, size_t size, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Greatest common divisor: G = gcd(A, B) + * + * \param G Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed + */ +int mpi_gcd( mpi *G, const mpi *A, const mpi *B ); + +/** + * \brief Modular inverse: X = A^-1 mod N + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param N Right-hand MPI + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed, + * POLARSSL_ERR_MPI_BAD_INPUT_DATA if N is negative or nil + POLARSSL_ERR_MPI_NOT_ACCEPTABLE if A has no inverse mod N + */ +int mpi_inv_mod( mpi *X, const mpi *A, const mpi *N ); + +/** + * \brief Miller-Rabin primality test + * + * \param X MPI to check + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successful (probably prime), + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed, + * POLARSSL_ERR_MPI_NOT_ACCEPTABLE if X is not prime + */ +int mpi_is_prime( mpi *X, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Prime number generation + * + * \param X Destination MPI + * \param nbits Required size of X in bits ( 3 <= nbits <= POLARSSL_MPI_MAX_BITS ) + * \param dh_flag If 1, then (X-1)/2 will be prime too + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successful (probably prime), + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed, + * POLARSSL_ERR_MPI_BAD_INPUT_DATA if nbits is < 3 + */ +int mpi_gen_prime( mpi *X, size_t nbits, int dh_flag, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mpi_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* bignum.h */ diff --git a/include/polarssl/bn_mul.h b/include/polarssl/bn_mul.h new file mode 100644 index 000000000..a6a2c65fb --- /dev/null +++ b/include/polarssl/bn_mul.h @@ -0,0 +1,742 @@ +/** + * \file bn_mul.h + * + * \brief Multi-precision integer library + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/* + * Multiply source vector [s] with b, add result + * to destination vector [d] and set carry c. + * + * Currently supports: + * + * . IA-32 (386+) . AMD64 / EM64T + * . IA-32 (SSE2) . Motorola 68000 + * . PowerPC, 32-bit . MicroBlaze + * . PowerPC, 64-bit . TriCore + * . SPARC v8 . ARM v3+ + * . Alpha . MIPS32 + * . C, longlong . C, generic + */ +#ifndef POLARSSL_BN_MUL_H +#define POLARSSL_BN_MUL_H + +#include "bignum.h" + +#if defined(POLARSSL_HAVE_ASM) + +#if defined(__GNUC__) +#if defined(__i386__) + +#define MULADDC_INIT \ + asm( " \ + movl %%ebx, %0; \ + movl %5, %%esi; \ + movl %6, %%edi; \ + movl %7, %%ecx; \ + movl %8, %%ebx; \ + " + +#define MULADDC_CORE \ + " \ + lodsl; \ + mull %%ebx; \ + addl %%ecx, %%eax; \ + adcl $0, %%edx; \ + addl (%%edi), %%eax; \ + adcl $0, %%edx; \ + movl %%edx, %%ecx; \ + stosl; \ + " + +#if defined(POLARSSL_HAVE_SSE2) + +#define MULADDC_HUIT \ + " \ + movd %%ecx, %%mm1; \ + movd %%ebx, %%mm0; \ + movd (%%edi), %%mm3; \ + paddq %%mm3, %%mm1; \ + movd (%%esi), %%mm2; \ + pmuludq %%mm0, %%mm2; \ + movd 4(%%esi), %%mm4; \ + pmuludq %%mm0, %%mm4; \ + movd 8(%%esi), %%mm6; \ + pmuludq %%mm0, %%mm6; \ + movd 12(%%esi), %%mm7; \ + pmuludq %%mm0, %%mm7; \ + paddq %%mm2, %%mm1; \ + movd 4(%%edi), %%mm3; \ + paddq %%mm4, %%mm3; \ + movd 8(%%edi), %%mm5; \ + paddq %%mm6, %%mm5; \ + movd 12(%%edi), %%mm4; \ + paddq %%mm4, %%mm7; \ + movd %%mm1, (%%edi); \ + movd 16(%%esi), %%mm2; \ + pmuludq %%mm0, %%mm2; \ + psrlq $32, %%mm1; \ + movd 20(%%esi), %%mm4; \ + pmuludq %%mm0, %%mm4; \ + paddq %%mm3, %%mm1; \ + movd 24(%%esi), %%mm6; \ + pmuludq %%mm0, %%mm6; \ + movd %%mm1, 4(%%edi); \ + psrlq $32, %%mm1; \ + movd 28(%%esi), %%mm3; \ + pmuludq %%mm0, %%mm3; \ + paddq %%mm5, %%mm1; \ + movd 16(%%edi), %%mm5; \ + paddq %%mm5, %%mm2; \ + movd %%mm1, 8(%%edi); \ + psrlq $32, %%mm1; \ + paddq %%mm7, %%mm1; \ + movd 20(%%edi), %%mm5; \ + paddq %%mm5, %%mm4; \ + movd %%mm1, 12(%%edi); \ + psrlq $32, %%mm1; \ + paddq %%mm2, %%mm1; \ + movd 24(%%edi), %%mm5; \ + paddq %%mm5, %%mm6; \ + movd %%mm1, 16(%%edi); \ + psrlq $32, %%mm1; \ + paddq %%mm4, %%mm1; \ + movd 28(%%edi), %%mm5; \ + paddq %%mm5, %%mm3; \ + movd %%mm1, 20(%%edi); \ + psrlq $32, %%mm1; \ + paddq %%mm6, %%mm1; \ + movd %%mm1, 24(%%edi); \ + psrlq $32, %%mm1; \ + paddq %%mm3, %%mm1; \ + movd %%mm1, 28(%%edi); \ + addl $32, %%edi; \ + addl $32, %%esi; \ + psrlq $32, %%mm1; \ + movd %%mm1, %%ecx; \ + " + +#define MULADDC_STOP \ + " \ + emms; \ + movl %4, %%ebx; \ + movl %%ecx, %1; \ + movl %%edi, %2; \ + movl %%esi, %3; \ + " \ + : "=m" (t), "=m" (c), "=m" (d), "=m" (s) \ + : "m" (t), "m" (s), "m" (d), "m" (c), "m" (b) \ + : "eax", "ecx", "edx", "esi", "edi" \ + ); + +#else + +#define MULADDC_STOP \ + " \ + movl %4, %%ebx; \ + movl %%ecx, %1; \ + movl %%edi, %2; \ + movl %%esi, %3; \ + " \ + : "=m" (t), "=m" (c), "=m" (d), "=m" (s) \ + : "m" (t), "m" (s), "m" (d), "m" (c), "m" (b) \ + : "eax", "ecx", "edx", "esi", "edi" \ + ); +#endif /* SSE2 */ +#endif /* i386 */ + +#if defined(__amd64__) || defined (__x86_64__) + +#define MULADDC_INIT \ + asm( "movq %0, %%rsi " :: "m" (s)); \ + asm( "movq %0, %%rdi " :: "m" (d)); \ + asm( "movq %0, %%rcx " :: "m" (c)); \ + asm( "movq %0, %%rbx " :: "m" (b)); \ + asm( "xorq %r8, %r8 " ); + +#define MULADDC_CORE \ + asm( "movq (%rsi),%rax " ); \ + asm( "mulq %rbx " ); \ + asm( "addq $8, %rsi " ); \ + asm( "addq %rcx, %rax " ); \ + asm( "movq %r8, %rcx " ); \ + asm( "adcq $0, %rdx " ); \ + asm( "nop " ); \ + asm( "addq %rax, (%rdi) " ); \ + asm( "adcq %rdx, %rcx " ); \ + asm( "addq $8, %rdi " ); + +#define MULADDC_STOP \ + asm( "movq %%rcx, %0 " : "=m" (c)); \ + asm( "movq %%rdi, %0 " : "=m" (d)); \ + asm( "movq %%rsi, %0 " : "=m" (s) :: \ + "rax", "rcx", "rdx", "rbx", "rsi", "rdi", "r8" ); + +#endif /* AMD64 */ + +#if defined(__mc68020__) || defined(__mcpu32__) + +#define MULADDC_INIT \ + asm( "movl %0, %%a2 " :: "m" (s)); \ + asm( "movl %0, %%a3 " :: "m" (d)); \ + asm( "movl %0, %%d3 " :: "m" (c)); \ + asm( "movl %0, %%d2 " :: "m" (b)); \ + asm( "moveq #0, %d0 " ); + +#define MULADDC_CORE \ + asm( "movel %a2@+, %d1 " ); \ + asm( "mulul %d2, %d4:%d1 " ); \ + asm( "addl %d3, %d1 " ); \ + asm( "addxl %d0, %d4 " ); \ + asm( "moveq #0, %d3 " ); \ + asm( "addl %d1, %a3@+ " ); \ + asm( "addxl %d4, %d3 " ); + +#define MULADDC_STOP \ + asm( "movl %%d3, %0 " : "=m" (c)); \ + asm( "movl %%a3, %0 " : "=m" (d)); \ + asm( "movl %%a2, %0 " : "=m" (s) :: \ + "d0", "d1", "d2", "d3", "d4", "a2", "a3" ); + +#define MULADDC_HUIT \ + asm( "movel %a2@+, %d1 " ); \ + asm( "mulul %d2, %d4:%d1 " ); \ + asm( "addxl %d3, %d1 " ); \ + asm( "addxl %d0, %d4 " ); \ + asm( "addl %d1, %a3@+ " ); \ + asm( "movel %a2@+, %d1 " ); \ + asm( "mulul %d2, %d3:%d1 " ); \ + asm( "addxl %d4, %d1 " ); \ + asm( "addxl %d0, %d3 " ); \ + asm( "addl %d1, %a3@+ " ); \ + asm( "movel %a2@+, %d1 " ); \ + asm( "mulul %d2, %d4:%d1 " ); \ + asm( "addxl %d3, %d1 " ); \ + asm( "addxl %d0, %d4 " ); \ + asm( "addl %d1, %a3@+ " ); \ + asm( "movel %a2@+, %d1 " ); \ + asm( "mulul %d2, %d3:%d1 " ); \ + asm( "addxl %d4, %d1 " ); \ + asm( "addxl %d0, %d3 " ); \ + asm( "addl %d1, %a3@+ " ); \ + asm( "movel %a2@+, %d1 " ); \ + asm( "mulul %d2, %d4:%d1 " ); \ + asm( "addxl %d3, %d1 " ); \ + asm( "addxl %d0, %d4 " ); \ + asm( "addl %d1, %a3@+ " ); \ + asm( "movel %a2@+, %d1 " ); \ + asm( "mulul %d2, %d3:%d1 " ); \ + asm( "addxl %d4, %d1 " ); \ + asm( "addxl %d0, %d3 " ); \ + asm( "addl %d1, %a3@+ " ); \ + asm( "movel %a2@+, %d1 " ); \ + asm( "mulul %d2, %d4:%d1 " ); \ + asm( "addxl %d3, %d1 " ); \ + asm( "addxl %d0, %d4 " ); \ + asm( "addl %d1, %a3@+ " ); \ + asm( "movel %a2@+, %d1 " ); \ + asm( "mulul %d2, %d3:%d1 " ); \ + asm( "addxl %d4, %d1 " ); \ + asm( "addxl %d0, %d3 " ); \ + asm( "addl %d1, %a3@+ " ); \ + asm( "addxl %d0, %d3 " ); + +#endif /* MC68000 */ + +#if defined(__powerpc__) || defined(__ppc__) +#if defined(__powerpc64__) || defined(__ppc64__) + +#if defined(__MACH__) && defined(__APPLE__) + +#define MULADDC_INIT \ + asm( "ld r3, %0 " :: "m" (s)); \ + asm( "ld r4, %0 " :: "m" (d)); \ + asm( "ld r5, %0 " :: "m" (c)); \ + asm( "ld r6, %0 " :: "m" (b)); \ + asm( "addi r3, r3, -8 " ); \ + asm( "addi r4, r4, -8 " ); \ + asm( "addic r5, r5, 0 " ); + +#define MULADDC_CORE \ + asm( "ldu r7, 8(r3) " ); \ + asm( "mulld r8, r7, r6 " ); \ + asm( "mulhdu r9, r7, r6 " ); \ + asm( "adde r8, r8, r5 " ); \ + asm( "ld r7, 8(r4) " ); \ + asm( "addze r5, r9 " ); \ + asm( "addc r8, r8, r7 " ); \ + asm( "stdu r8, 8(r4) " ); + +#define MULADDC_STOP \ + asm( "addze r5, r5 " ); \ + asm( "addi r4, r4, 8 " ); \ + asm( "addi r3, r3, 8 " ); \ + asm( "std r5, %0 " : "=m" (c)); \ + asm( "std r4, %0 " : "=m" (d)); \ + asm( "std r3, %0 " : "=m" (s) :: \ + "r3", "r4", "r5", "r6", "r7", "r8", "r9" ); + +#else + +#define MULADDC_INIT \ + asm( "ld %%r3, %0 " :: "m" (s)); \ + asm( "ld %%r4, %0 " :: "m" (d)); \ + asm( "ld %%r5, %0 " :: "m" (c)); \ + asm( "ld %%r6, %0 " :: "m" (b)); \ + asm( "addi %r3, %r3, -8 " ); \ + asm( "addi %r4, %r4, -8 " ); \ + asm( "addic %r5, %r5, 0 " ); + +#define MULADDC_CORE \ + asm( "ldu %r7, 8(%r3) " ); \ + asm( "mulld %r8, %r7, %r6 " ); \ + asm( "mulhdu %r9, %r7, %r6 " ); \ + asm( "adde %r8, %r8, %r5 " ); \ + asm( "ld %r7, 8(%r4) " ); \ + asm( "addze %r5, %r9 " ); \ + asm( "addc %r8, %r8, %r7 " ); \ + asm( "stdu %r8, 8(%r4) " ); + +#define MULADDC_STOP \ + asm( "addze %r5, %r5 " ); \ + asm( "addi %r4, %r4, 8 " ); \ + asm( "addi %r3, %r3, 8 " ); \ + asm( "std %%r5, %0 " : "=m" (c)); \ + asm( "std %%r4, %0 " : "=m" (d)); \ + asm( "std %%r3, %0 " : "=m" (s) :: \ + "r3", "r4", "r5", "r6", "r7", "r8", "r9" ); + +#endif + +#else /* PPC32 */ + +#if defined(__MACH__) && defined(__APPLE__) + +#define MULADDC_INIT \ + asm( "lwz r3, %0 " :: "m" (s)); \ + asm( "lwz r4, %0 " :: "m" (d)); \ + asm( "lwz r5, %0 " :: "m" (c)); \ + asm( "lwz r6, %0 " :: "m" (b)); \ + asm( "addi r3, r3, -4 " ); \ + asm( "addi r4, r4, -4 " ); \ + asm( "addic r5, r5, 0 " ); + +#define MULADDC_CORE \ + asm( "lwzu r7, 4(r3) " ); \ + asm( "mullw r8, r7, r6 " ); \ + asm( "mulhwu r9, r7, r6 " ); \ + asm( "adde r8, r8, r5 " ); \ + asm( "lwz r7, 4(r4) " ); \ + asm( "addze r5, r9 " ); \ + asm( "addc r8, r8, r7 " ); \ + asm( "stwu r8, 4(r4) " ); + +#define MULADDC_STOP \ + asm( "addze r5, r5 " ); \ + asm( "addi r4, r4, 4 " ); \ + asm( "addi r3, r3, 4 " ); \ + asm( "stw r5, %0 " : "=m" (c)); \ + asm( "stw r4, %0 " : "=m" (d)); \ + asm( "stw r3, %0 " : "=m" (s) :: \ + "r3", "r4", "r5", "r6", "r7", "r8", "r9" ); + +#else + +#define MULADDC_INIT \ + asm( "lwz %%r3, %0 " :: "m" (s)); \ + asm( "lwz %%r4, %0 " :: "m" (d)); \ + asm( "lwz %%r5, %0 " :: "m" (c)); \ + asm( "lwz %%r6, %0 " :: "m" (b)); \ + asm( "addi %r3, %r3, -4 " ); \ + asm( "addi %r4, %r4, -4 " ); \ + asm( "addic %r5, %r5, 0 " ); + +#define MULADDC_CORE \ + asm( "lwzu %r7, 4(%r3) " ); \ + asm( "mullw %r8, %r7, %r6 " ); \ + asm( "mulhwu %r9, %r7, %r6 " ); \ + asm( "adde %r8, %r8, %r5 " ); \ + asm( "lwz %r7, 4(%r4) " ); \ + asm( "addze %r5, %r9 " ); \ + asm( "addc %r8, %r8, %r7 " ); \ + asm( "stwu %r8, 4(%r4) " ); + +#define MULADDC_STOP \ + asm( "addze %r5, %r5 " ); \ + asm( "addi %r4, %r4, 4 " ); \ + asm( "addi %r3, %r3, 4 " ); \ + asm( "stw %%r5, %0 " : "=m" (c)); \ + asm( "stw %%r4, %0 " : "=m" (d)); \ + asm( "stw %%r3, %0 " : "=m" (s) :: \ + "r3", "r4", "r5", "r6", "r7", "r8", "r9" ); + +#endif + +#endif /* PPC32 */ +#endif /* PPC64 */ + +#if defined(__sparc__) + +#define MULADDC_INIT \ + asm( "ld %0, %%o0 " :: "m" (s)); \ + asm( "ld %0, %%o1 " :: "m" (d)); \ + asm( "ld %0, %%o2 " :: "m" (c)); \ + asm( "ld %0, %%o3 " :: "m" (b)); + +#define MULADDC_CORE \ + asm( "ld [%o0], %o4 " ); \ + asm( "inc 4, %o0 " ); \ + asm( "ld [%o1], %o5 " ); \ + asm( "umul %o3, %o4, %o4 " ); \ + asm( "addcc %o4, %o2, %o4 " ); \ + asm( "rd %y, %g1 " ); \ + asm( "addx %g1, 0, %g1 " ); \ + asm( "addcc %o4, %o5, %o4 " ); \ + asm( "st %o4, [%o1] " ); \ + asm( "addx %g1, 0, %o2 " ); \ + asm( "inc 4, %o1 " ); + +#define MULADDC_STOP \ + asm( "st %%o2, %0 " : "=m" (c)); \ + asm( "st %%o1, %0 " : "=m" (d)); \ + asm( "st %%o0, %0 " : "=m" (s) :: \ + "g1", "o0", "o1", "o2", "o3", "o4", "o5" ); + +#endif /* SPARCv8 */ + +#if defined(__microblaze__) || defined(microblaze) + +#define MULADDC_INIT \ + asm( "lwi r3, %0 " :: "m" (s)); \ + asm( "lwi r4, %0 " :: "m" (d)); \ + asm( "lwi r5, %0 " :: "m" (c)); \ + asm( "lwi r6, %0 " :: "m" (b)); \ + asm( "andi r7, r6, 0xffff" ); \ + asm( "bsrli r6, r6, 16 " ); + +#define MULADDC_CORE \ + asm( "lhui r8, r3, 0 " ); \ + asm( "addi r3, r3, 2 " ); \ + asm( "lhui r9, r3, 0 " ); \ + asm( "addi r3, r3, 2 " ); \ + asm( "mul r10, r9, r6 " ); \ + asm( "mul r11, r8, r7 " ); \ + asm( "mul r12, r9, r7 " ); \ + asm( "mul r13, r8, r6 " ); \ + asm( "bsrli r8, r10, 16 " ); \ + asm( "bsrli r9, r11, 16 " ); \ + asm( "add r13, r13, r8 " ); \ + asm( "add r13, r13, r9 " ); \ + asm( "bslli r10, r10, 16 " ); \ + asm( "bslli r11, r11, 16 " ); \ + asm( "add r12, r12, r10 " ); \ + asm( "addc r13, r13, r0 " ); \ + asm( "add r12, r12, r11 " ); \ + asm( "addc r13, r13, r0 " ); \ + asm( "lwi r10, r4, 0 " ); \ + asm( "add r12, r12, r10 " ); \ + asm( "addc r13, r13, r0 " ); \ + asm( "add r12, r12, r5 " ); \ + asm( "addc r5, r13, r0 " ); \ + asm( "swi r12, r4, 0 " ); \ + asm( "addi r4, r4, 4 " ); + +#define MULADDC_STOP \ + asm( "swi r5, %0 " : "=m" (c)); \ + asm( "swi r4, %0 " : "=m" (d)); \ + asm( "swi r3, %0 " : "=m" (s) :: \ + "r3", "r4" , "r5" , "r6" , "r7" , "r8" , \ + "r9", "r10", "r11", "r12", "r13" ); + +#endif /* MicroBlaze */ + +#if defined(__tricore__) + +#define MULADDC_INIT \ + asm( "ld.a %%a2, %0 " :: "m" (s)); \ + asm( "ld.a %%a3, %0 " :: "m" (d)); \ + asm( "ld.w %%d4, %0 " :: "m" (c)); \ + asm( "ld.w %%d1, %0 " :: "m" (b)); \ + asm( "xor %d5, %d5 " ); + +#define MULADDC_CORE \ + asm( "ld.w %d0, [%a2+] " ); \ + asm( "madd.u %e2, %e4, %d0, %d1 " ); \ + asm( "ld.w %d0, [%a3] " ); \ + asm( "addx %d2, %d2, %d0 " ); \ + asm( "addc %d3, %d3, 0 " ); \ + asm( "mov %d4, %d3 " ); \ + asm( "st.w [%a3+], %d2 " ); + +#define MULADDC_STOP \ + asm( "st.w %0, %%d4 " : "=m" (c)); \ + asm( "st.a %0, %%a3 " : "=m" (d)); \ + asm( "st.a %0, %%a2 " : "=m" (s) :: \ + "d0", "d1", "e2", "d4", "a2", "a3" ); + +#endif /* TriCore */ + +#if defined(__arm__) + +#if !defined(__thumb__) + +#define MULADDC_INIT \ + asm( "ldr r0, %0 " :: "m" (s)); \ + asm( "ldr r1, %0 " :: "m" (d)); \ + asm( "ldr r2, %0 " :: "m" (c)); \ + asm( "ldr r3, %0 " :: "m" (b)); + +#define MULADDC_CORE \ + asm( "ldr r4, [r0], #4 " ); \ + asm( "mov r5, #0 " ); \ + asm( "ldr r6, [r1] " ); \ + asm( "umlal r2, r5, r3, r4 " ); \ + asm( "adds r7, r6, r2 " ); \ + asm( "adc r2, r5, #0 " ); \ + asm( "str r7, [r1], #4 " ); + +#define MULADDC_STOP \ + asm( "str r2, %0 " : "=m" (c)); \ + asm( "str r1, %0 " : "=m" (d)); \ + asm( "str r0, %0 " : "=m" (s) :: \ + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7" ); + +#endif /* Thumb */ + +#endif /* ARMv3 */ + +#if defined(__alpha__) + +#define MULADDC_INIT \ + asm( "ldq $1, %0 " :: "m" (s)); \ + asm( "ldq $2, %0 " :: "m" (d)); \ + asm( "ldq $3, %0 " :: "m" (c)); \ + asm( "ldq $4, %0 " :: "m" (b)); + +#define MULADDC_CORE \ + asm( "ldq $6, 0($1) " ); \ + asm( "addq $1, 8, $1 " ); \ + asm( "mulq $6, $4, $7 " ); \ + asm( "umulh $6, $4, $6 " ); \ + asm( "addq $7, $3, $7 " ); \ + asm( "cmpult $7, $3, $3 " ); \ + asm( "ldq $5, 0($2) " ); \ + asm( "addq $7, $5, $7 " ); \ + asm( "cmpult $7, $5, $5 " ); \ + asm( "stq $7, 0($2) " ); \ + asm( "addq $2, 8, $2 " ); \ + asm( "addq $6, $3, $3 " ); \ + asm( "addq $5, $3, $3 " ); + +#define MULADDC_STOP \ + asm( "stq $3, %0 " : "=m" (c)); \ + asm( "stq $2, %0 " : "=m" (d)); \ + asm( "stq $1, %0 " : "=m" (s) :: \ + "$1", "$2", "$3", "$4", "$5", "$6", "$7" ); + +#endif /* Alpha */ + +#if defined(__mips__) + +#define MULADDC_INIT \ + asm( "lw $10, %0 " :: "m" (s)); \ + asm( "lw $11, %0 " :: "m" (d)); \ + asm( "lw $12, %0 " :: "m" (c)); \ + asm( "lw $13, %0 " :: "m" (b)); + +#define MULADDC_CORE \ + asm( "lw $14, 0($10) " ); \ + asm( "multu $13, $14 " ); \ + asm( "addi $10, $10, 4 " ); \ + asm( "mflo $14 " ); \ + asm( "mfhi $9 " ); \ + asm( "addu $14, $12, $14 " ); \ + asm( "lw $15, 0($11) " ); \ + asm( "sltu $12, $14, $12 " ); \ + asm( "addu $15, $14, $15 " ); \ + asm( "sltu $14, $15, $14 " ); \ + asm( "addu $12, $12, $9 " ); \ + asm( "sw $15, 0($11) " ); \ + asm( "addu $12, $12, $14 " ); \ + asm( "addi $11, $11, 4 " ); + +#define MULADDC_STOP \ + asm( "sw $12, %0 " : "=m" (c)); \ + asm( "sw $11, %0 " : "=m" (d)); \ + asm( "sw $10, %0 " : "=m" (s) :: \ + "$9", "$10", "$11", "$12", "$13", "$14", "$15" ); + +#endif /* MIPS */ +#endif /* GNUC */ + +#if (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__) + +#define MULADDC_INIT \ + __asm mov esi, s \ + __asm mov edi, d \ + __asm mov ecx, c \ + __asm mov ebx, b + +#define MULADDC_CORE \ + __asm lodsd \ + __asm mul ebx \ + __asm add eax, ecx \ + __asm adc edx, 0 \ + __asm add eax, [edi] \ + __asm adc edx, 0 \ + __asm mov ecx, edx \ + __asm stosd + +#if defined(POLARSSL_HAVE_SSE2) + +#define EMIT __asm _emit + +#define MULADDC_HUIT \ + EMIT 0x0F EMIT 0x6E EMIT 0xC9 \ + EMIT 0x0F EMIT 0x6E EMIT 0xC3 \ + EMIT 0x0F EMIT 0x6E EMIT 0x1F \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCB \ + EMIT 0x0F EMIT 0x6E EMIT 0x16 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xD0 \ + EMIT 0x0F EMIT 0x6E EMIT 0x66 EMIT 0x04 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xE0 \ + EMIT 0x0F EMIT 0x6E EMIT 0x76 EMIT 0x08 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xF0 \ + EMIT 0x0F EMIT 0x6E EMIT 0x7E EMIT 0x0C \ + EMIT 0x0F EMIT 0xF4 EMIT 0xF8 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCA \ + EMIT 0x0F EMIT 0x6E EMIT 0x5F EMIT 0x04 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xDC \ + EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x08 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xEE \ + EMIT 0x0F EMIT 0x6E EMIT 0x67 EMIT 0x0C \ + EMIT 0x0F EMIT 0xD4 EMIT 0xFC \ + EMIT 0x0F EMIT 0x7E EMIT 0x0F \ + EMIT 0x0F EMIT 0x6E EMIT 0x56 EMIT 0x10 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xD0 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0x6E EMIT 0x66 EMIT 0x14 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xE0 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCB \ + EMIT 0x0F EMIT 0x6E EMIT 0x76 EMIT 0x18 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xF0 \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x04 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0x6E EMIT 0x5E EMIT 0x1C \ + EMIT 0x0F EMIT 0xF4 EMIT 0xD8 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCD \ + EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x10 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xD5 \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x08 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCF \ + EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x14 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xE5 \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x0C \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCA \ + EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x18 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xF5 \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x10 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCC \ + EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x1C \ + EMIT 0x0F EMIT 0xD4 EMIT 0xDD \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x14 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCE \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x18 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCB \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x1C \ + EMIT 0x83 EMIT 0xC7 EMIT 0x20 \ + EMIT 0x83 EMIT 0xC6 EMIT 0x20 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0x7E EMIT 0xC9 + +#define MULADDC_STOP \ + EMIT 0x0F EMIT 0x77 \ + __asm mov c, ecx \ + __asm mov d, edi \ + __asm mov s, esi \ + +#else + +#define MULADDC_STOP \ + __asm mov c, ecx \ + __asm mov d, edi \ + __asm mov s, esi \ + +#endif /* SSE2 */ +#endif /* MSVC */ + +#endif /* POLARSSL_HAVE_ASM */ + +#if !defined(MULADDC_CORE) +#if defined(POLARSSL_HAVE_LONGLONG) + +#define MULADDC_INIT \ +{ \ + t_udbl r; \ + t_uint r0, r1; + +#define MULADDC_CORE \ + r = *(s++) * (t_udbl) b; \ + r0 = r; \ + r1 = r >> biL; \ + r0 += c; r1 += (r0 < c); \ + r0 += *d; r1 += (r0 < *d); \ + c = r1; *(d++) = r0; + +#define MULADDC_STOP \ +} + +#else +#define MULADDC_INIT \ +{ \ + t_uint s0, s1, b0, b1; \ + t_uint r0, r1, rx, ry; \ + b0 = ( b << biH ) >> biH; \ + b1 = ( b >> biH ); + +#define MULADDC_CORE \ + s0 = ( *s << biH ) >> biH; \ + s1 = ( *s >> biH ); s++; \ + rx = s0 * b1; r0 = s0 * b0; \ + ry = s1 * b0; r1 = s1 * b1; \ + r1 += ( rx >> biH ); \ + r1 += ( ry >> biH ); \ + rx <<= biH; ry <<= biH; \ + r0 += rx; r1 += (r0 < rx); \ + r0 += ry; r1 += (r0 < ry); \ + r0 += c; r1 += (r0 < c); \ + r0 += *d; r1 += (r0 < *d); \ + c = r1; *(d++) = r0; + +#define MULADDC_STOP \ +} + +#endif /* C (generic) */ +#endif /* C (longlong) */ + +#endif /* bn_mul.h */ diff --git a/include/polarssl/camellia.h b/include/polarssl/camellia.h new file mode 100644 index 000000000..b2b12945f --- /dev/null +++ b/include/polarssl/camellia.h @@ -0,0 +1,182 @@ +/** + * \file camellia.h + * + * \brief Camellia block cipher + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_CAMELLIA_H +#define POLARSSL_CAMELLIA_H + +#include + +#ifdef _MSC_VER +#include +typedef UINT32 uint32_t; +#else +#include +#endif + +#define CAMELLIA_ENCRYPT 1 +#define CAMELLIA_DECRYPT 0 + +#define POLARSSL_ERR_CAMELLIA_INVALID_KEY_LENGTH -0x0024 /**< Invalid key length. */ +#define POLARSSL_ERR_CAMELLIA_INVALID_INPUT_LENGTH -0x0026 /**< Invalid data input length. */ + +/** + * \brief CAMELLIA context structure + */ +typedef struct +{ + int nr; /*!< number of rounds */ + uint32_t rk[68]; /*!< CAMELLIA round keys */ +} +camellia_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief CAMELLIA key schedule (encryption) + * + * \param ctx CAMELLIA context to be initialized + * \param key encryption key + * \param keysize must be 128, 192 or 256 + * + * \return 0 if successful, or POLARSSL_ERR_CAMELLIA_INVALID_KEY_LENGTH + */ +int camellia_setkey_enc( camellia_context *ctx, const unsigned char *key, unsigned int keysize ); + +/** + * \brief CAMELLIA key schedule (decryption) + * + * \param ctx CAMELLIA context to be initialized + * \param key decryption key + * \param keysize must be 128, 192 or 256 + * + * \return 0 if successful, or POLARSSL_ERR_CAMELLIA_INVALID_KEY_LENGTH + */ +int camellia_setkey_dec( camellia_context *ctx, const unsigned char *key, unsigned int keysize ); + +/** + * \brief CAMELLIA-ECB block encryption/decryption + * + * \param ctx CAMELLIA context + * \param mode CAMELLIA_ENCRYPT or CAMELLIA_DECRYPT + * \param input 16-byte input block + * \param output 16-byte output block + * + * \return 0 if successful + */ +int camellia_crypt_ecb( camellia_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16] ); + +/** + * \brief CAMELLIA-CBC buffer encryption/decryption + * Length should be a multiple of the block + * size (16 bytes) + * + * \param ctx CAMELLIA context + * \param mode CAMELLIA_ENCRYPT or CAMELLIA_DECRYPT + * \param length length of the input data + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + * + * \return 0 if successful, or POLARSSL_ERR_CAMELLIA_INVALID_INPUT_LENGTH + */ +int camellia_crypt_cbc( camellia_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ); + +/** + * \brief CAMELLIA-CFB128 buffer encryption/decryption + * + * Note: Due to the nature of CFB you should use the same key schedule for + * both encryption and decryption. So a context initialized with + * camellia_setkey_enc() for both CAMELLIA_ENCRYPT and CAMELLIE_DECRYPT. + * + * \param ctx CAMELLIA context + * \param mode CAMELLIA_ENCRYPT or CAMELLIA_DECRYPT + * \param length length of the input data + * \param iv_off offset in IV (updated after use) + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + * + * \return 0 if successful, or POLARSSL_ERR_CAMELLIA_INVALID_INPUT_LENGTH + */ +int camellia_crypt_cfb128( camellia_context *ctx, + int mode, + size_t length, + size_t *iv_off, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ); + +/* + * \brief CAMELLIA-CTR buffer encryption/decryption + * + * Warning: You have to keep the maximum use of your counter in mind! + * + * Note: Due to the nature of CTR you should use the same key schedule for + * both encryption and decryption. So a context initialized with + * camellia_setkey_enc() for both CAMELLIA_ENCRYPT and CAMELLIA_DECRYPT. + * + * \param length The length of the data + * \param nc_off The offset in the current stream_block (for resuming + * within current cipher stream). The offset pointer to + * should be 0 at the start of a stream. + * \param nonce_counter The 128-bit nonce and counter. + * \param stream_block The saved stream-block for resuming. Is overwritten + * by the function. + * \param input The input data stream + * \param output The output data stream + * + * \return 0 if successful + */ +int camellia_crypt_ctr( camellia_context *ctx, + size_t length, + size_t *nc_off, + unsigned char nonce_counter[16], + unsigned char stream_block[16], + const unsigned char *input, + unsigned char *output ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int camellia_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* camellia.h */ diff --git a/include/polarssl/certs.h b/include/polarssl/certs.h new file mode 100644 index 000000000..5399e326d --- /dev/null +++ b/include/polarssl/certs.h @@ -0,0 +1,47 @@ +/** + * \file certs.h + * + * \brief Sample certificates and DHM parameters for testing + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_CERTS_H +#define POLARSSL_CERTS_H + +#ifdef __cplusplus +extern "C" { +#endif + +extern const char test_ca_crt[]; +extern const char test_ca_key[]; +extern const char test_ca_pwd[]; +extern const char test_srv_crt[]; +extern const char test_srv_key[]; +extern const char test_cli_crt[]; +extern const char test_cli_key[]; +extern const char test_dhm_params[]; + +#ifdef __cplusplus +} +#endif + +#endif /* certs.h */ diff --git a/include/polarssl/cipher.h b/include/polarssl/cipher.h new file mode 100644 index 000000000..8c94dd5f9 --- /dev/null +++ b/include/polarssl/cipher.h @@ -0,0 +1,456 @@ +/** + * \file cipher.h + * + * \brief Generic cipher wrapper. + * + * \author Adriaan de Jong + * + * Copyright (C) 2006-2011, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef POLARSSL_CIPHER_H +#define POLARSSL_CIPHER_H + +#include + +#if defined(_MSC_VER) && !defined(inline) +#define inline _inline +#else +#if defined(__ARMCC_VERSION) && !defined(inline) +#define inline __inline +#endif /* __ARMCC_VERSION */ +#endif /*_MSC_VER */ + +#define POLARSSL_ERR_CIPHER_FEATURE_UNAVAILABLE -0x6080 /**< The selected feature is not available. */ +#define POLARSSL_ERR_CIPHER_BAD_INPUT_DATA -0x6100 /**< Bad input parameters to function. */ +#define POLARSSL_ERR_CIPHER_ALLOC_FAILED -0x6180 /**< Failed to allocate memory. */ +#define POLARSSL_ERR_CIPHER_INVALID_PADDING -0x6200 /**< Input data contains invalid padding and is rejected. */ +#define POLARSSL_ERR_CIPHER_FULL_BLOCK_EXPECTED -0x6280 /**< Decryption of block requires a full block. */ + +typedef enum { + POLARSSL_CIPHER_ID_NONE = 0, + POLARSSL_CIPHER_ID_AES, + POLARSSL_CIPHER_ID_DES, + POLARSSL_CIPHER_ID_3DES, + POLARSSL_CIPHER_ID_CAMELLIA, +} cipher_id_t; + +typedef enum { + POLARSSL_CIPHER_NONE = 0, + POLARSSL_CIPHER_AES_128_CBC, + POLARSSL_CIPHER_AES_192_CBC, + POLARSSL_CIPHER_AES_256_CBC, + POLARSSL_CIPHER_AES_128_CFB128, + POLARSSL_CIPHER_AES_192_CFB128, + POLARSSL_CIPHER_AES_256_CFB128, + POLARSSL_CIPHER_AES_128_CTR, + POLARSSL_CIPHER_AES_192_CTR, + POLARSSL_CIPHER_AES_256_CTR, + POLARSSL_CIPHER_CAMELLIA_128_CBC, + POLARSSL_CIPHER_CAMELLIA_192_CBC, + POLARSSL_CIPHER_CAMELLIA_256_CBC, + POLARSSL_CIPHER_CAMELLIA_128_CFB128, + POLARSSL_CIPHER_CAMELLIA_192_CFB128, + POLARSSL_CIPHER_CAMELLIA_256_CFB128, + POLARSSL_CIPHER_CAMELLIA_128_CTR, + POLARSSL_CIPHER_CAMELLIA_192_CTR, + POLARSSL_CIPHER_CAMELLIA_256_CTR, + POLARSSL_CIPHER_DES_CBC, + POLARSSL_CIPHER_DES_EDE_CBC, + POLARSSL_CIPHER_DES_EDE3_CBC +} cipher_type_t; + +typedef enum { + POLARSSL_MODE_NONE = 0, + POLARSSL_MODE_CBC, + POLARSSL_MODE_CFB128, + POLARSSL_MODE_OFB, + POLARSSL_MODE_CTR, +} cipher_mode_t; + +typedef enum { + POLARSSL_OPERATION_NONE = -1, + POLARSSL_DECRYPT = 0, + POLARSSL_ENCRYPT, +} operation_t; + +enum { + /** Undefined key length */ + POLARSSL_KEY_LENGTH_NONE = 0, + /** Key length, in bits (including parity), for DES keys */ + POLARSSL_KEY_LENGTH_DES = 64, + /** Key length, in bits (including parity), for DES in two key EDE */ + POLARSSL_KEY_LENGTH_DES_EDE = 128, + /** Key length, in bits (including parity), for DES in three-key EDE */ + POLARSSL_KEY_LENGTH_DES_EDE3 = 192, + /** Maximum length of any IV, in bytes */ + POLARSSL_MAX_IV_LENGTH = 16, +}; + +/** + * Base cipher information. The non-mode specific functions and values. + */ +typedef struct { + + /** Base Cipher type (e.g. POLARSSL_CIPHER_ID_AES) */ + cipher_id_t cipher; + + /** Encrypt using CBC */ + int (*cbc_func)( void *ctx, operation_t mode, size_t length, unsigned char *iv, + const unsigned char *input, unsigned char *output ); + + /** Encrypt using CFB128 */ + int (*cfb128_func)( void *ctx, operation_t mode, size_t length, size_t *iv_off, + unsigned char *iv, const unsigned char *input, unsigned char *output ); + + /** Encrypt using CTR */ + int (*ctr_func)( void *ctx, size_t length, size_t *nc_off, unsigned char *nonce_counter, + unsigned char *stream_block, const unsigned char *input, unsigned char *output ); + + /** Set key for encryption purposes */ + int (*setkey_enc_func)( void *ctx, const unsigned char *key, unsigned int key_length); + + /** Set key for decryption purposes */ + int (*setkey_dec_func)( void *ctx, const unsigned char *key, unsigned int key_length); + + /** Allocate a new context */ + void * (*ctx_alloc_func)( void ); + + /** Free the given context */ + void (*ctx_free_func)( void *ctx ); + +} cipher_base_t; + +/** + * Cipher information. Allows cipher functions to be called in a generic way. + */ +typedef struct { + /** Full cipher identifier (e.g. POLARSSL_CIPHER_AES_256_CBC) */ + cipher_type_t type; + + /** Cipher mode (e.g. POLARSSL_MODE_CBC) */ + cipher_mode_t mode; + + /** Cipher key length, in bits (default length for variable sized ciphers) + * (Includes parity bits for ciphers like DES) */ + unsigned int key_length; + + /** Name of the cipher */ + const char * name; + + /** IV size, in bytes */ + unsigned int iv_size; + + /** block size, in bytes */ + unsigned int block_size; + + /** Base cipher information and functions */ + const cipher_base_t *base; + +} cipher_info_t; + +/** + * Generic cipher context. + */ +typedef struct { + /** Information about the associated cipher */ + const cipher_info_t *cipher_info; + + /** Key length to use */ + int key_length; + + /** Operation that the context's key has been initialised for */ + operation_t operation; + + /** Buffer for data that hasn't been encrypted yet */ + unsigned char unprocessed_data[POLARSSL_MAX_IV_LENGTH]; + + /** Number of bytes that still need processing */ + size_t unprocessed_len; + + /** Current IV or NONCE_COUNTER for CTR-mode */ + unsigned char iv[POLARSSL_MAX_IV_LENGTH]; + + /** Cipher-specific context */ + void *cipher_ctx; +} cipher_context_t; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Returns the list of ciphers supported by the generic cipher module. + * + * \return a statically allocated array of ciphers, the last entry + * is 0. + */ +const int *cipher_list( void ); + +/** + * \brief Returns the cipher information structure associated + * with the given cipher name. + * + * \param cipher_name Name of the cipher to search for. + * + * \return the cipher information structure associated with the + * given cipher_name, or NULL if not found. + */ +const cipher_info_t *cipher_info_from_string( const char *cipher_name ); + +/** + * \brief Returns the cipher information structure associated + * with the given cipher type. + * + * \param cipher_type Type of the cipher to search for. + * + * \return the cipher information structure associated with the + * given cipher_type, or NULL if not found. + */ +const cipher_info_t *cipher_info_from_type( const cipher_type_t cipher_type ); + +/** + * \brief Initialises and fills the cipher context structure with + * the appropriate values. + * + * \param ctx context to initialise. May not be NULL. + * \param cipher_info cipher to use. + * + * \return \c 0 on success, + * \c POLARSSL_ERR_CIPHER_BAD_INPUT_DATA on parameter failure, + * \c POLARSSL_ERR_CIPHER_ALLOC_FAILED if allocation of the + * cipher-specific context failed. + */ +int cipher_init_ctx( cipher_context_t *ctx, const cipher_info_t *cipher_info ); + +/** + * \brief Free the cipher-specific context of ctx. Freeing ctx + * itself remains the responsibility of the caller. + * + * \param ctx Free the cipher-specific context + * + * \returns 0 on success, POLARSSL_ERR_CIPHER_BAD_INPUT_DATA if + * parameter verification fails. + */ +int cipher_free_ctx( cipher_context_t *ctx ); + +/** + * \brief Returns the block size of the given cipher. + * + * \param ctx cipher's context. Must have been initialised. + * + * \return size of the cipher's blocks, or 0 if ctx has not been + * initialised. + */ +static inline unsigned int cipher_get_block_size( const cipher_context_t *ctx ) +{ + if( NULL == ctx || NULL == ctx->cipher_info ) + return 0; + + return ctx->cipher_info->block_size; +} + +/** + * \brief Returns the mode of operation for the cipher. + * (e.g. POLARSSL_MODE_CBC) + * + * \param ctx cipher's context. Must have been initialised. + * + * \return mode of operation, or POLARSSL_MODE_NONE if ctx + * has not been initialised. + */ +static inline cipher_mode_t cipher_get_cipher_mode( const cipher_context_t *ctx ) +{ + if( NULL == ctx || NULL == ctx->cipher_info ) + return POLARSSL_MODE_NONE; + + return ctx->cipher_info->mode; +} + +/** + * \brief Returns the size of the cipher's IV. + * + * \param ctx cipher's context. Must have been initialised. + * + * \return size of the cipher's IV, or 0 if ctx has not been + * initialised. + */ +static inline int cipher_get_iv_size( const cipher_context_t *ctx ) +{ + if( NULL == ctx || NULL == ctx->cipher_info ) + return 0; + + return ctx->cipher_info->iv_size; +} + +/** + * \brief Returns the type of the given cipher. + * + * \param ctx cipher's context. Must have been initialised. + * + * \return type of the cipher, or POLARSSL_CIPHER_NONE if ctx has + * not been initialised. + */ +static inline cipher_type_t cipher_get_type( const cipher_context_t *ctx ) +{ + if( NULL == ctx || NULL == ctx->cipher_info ) + return 0; + + return ctx->cipher_info->type; +} + +/** + * \brief Returns the name of the given cipher, as a string. + * + * \param ctx cipher's context. Must have been initialised. + * + * \return name of the cipher, or NULL if ctx was not initialised. + */ +static inline const char *cipher_get_name( const cipher_context_t *ctx ) +{ + if( NULL == ctx || NULL == ctx->cipher_info ) + return 0; + + return ctx->cipher_info->name; +} + +/** + * \brief Returns the key length of the cipher. + * + * \param ctx cipher's context. Must have been initialised. + * + * \return cipher's key length, in bits, or + * POLARSSL_KEY_LENGTH_NONE if ctx has not been + * initialised. + */ +static inline int cipher_get_key_size ( const cipher_context_t *ctx ) +{ + if( NULL == ctx ) + return POLARSSL_KEY_LENGTH_NONE; + + return ctx->key_length; +} + +/** + * \brief Returns the operation of the given cipher. + * + * \param ctx cipher's context. Must have been initialised. + * + * \return operation (POLARSSL_ENCRYPT or POLARSSL_DECRYPT), + * or POLARSSL_OPERATION_NONE if ctx has not been + * initialised. + */ +static inline operation_t cipher_get_operation( const cipher_context_t *ctx ) +{ + if( NULL == ctx || NULL == ctx->cipher_info ) + return POLARSSL_OPERATION_NONE; + + return ctx->operation; +} + +/** + * \brief Set the key to use with the given context. + * + * \param ctx generic cipher context. May not be NULL. Must have been + * initialised using cipher_context_from_type or + * cipher_context_from_string. + * \param key The key to use. + * \param key_length key length to use, in bits. + * \param operation Operation that the key will be used for, either + * POLARSSL_ENCRYPT or POLARSSL_DECRYPT. + * + * \returns 0 on success, POLARSSL_ERR_CIPHER_BAD_INPUT_DATA if + * parameter verification fails or a cipher specific + * error code. + */ +int cipher_setkey( cipher_context_t *ctx, const unsigned char *key, int key_length, + const operation_t operation ); + +/** + * \brief Reset the given context, setting the IV to iv + * + * \param ctx generic cipher context + * \param iv IV to use or NONCE_COUNTER in the case of a CTR-mode cipher + * + * \returns 0 on success, POLARSSL_ERR_CIPHER_BAD_INPUT_DATA + * if parameter verification fails. + */ +int cipher_reset( cipher_context_t *ctx, const unsigned char *iv ); + +/** + * \brief Generic cipher update function. Encrypts/decrypts + * using the given cipher context. Writes as many block + * size'd blocks of data as possible to output. Any data + * that cannot be written immediately will either be added + * to the next block, or flushed when cipher_final is + * called. + * + * \param ctx generic cipher context + * \param input buffer holding the input data + * \param ilen length of the input data + * \param output buffer for the output data. Should be able to hold at + * least ilen + block_size. Cannot be the same buffer as + * input! + * \param olen length of the output data, will be filled with the + * actual number of bytes written. + * + * \returns 0 on success, POLARSSL_ERR_CIPHER_BAD_INPUT_DATA if + * parameter verification fails, + * POLARSSL_ERR_CIPHER_FEATURE_UNAVAILABLE on an + * unsupported mode for a cipher or a cipher specific + * error code. + */ +int cipher_update( cipher_context_t *ctx, const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen ); + +/** + * \brief Generic cipher finalisation function. If data still + * needs to be flushed from an incomplete block, data + * contained within it will be padded with the size of + * the last block, and written to the output buffer. + * + * \param ctx Generic cipher context + * \param output buffer to write data to. Needs block_size data available. + * \param olen length of the data written to the output buffer. + * + * \returns 0 on success, POLARSSL_ERR_CIPHER_BAD_INPUT_DATA if + * parameter verification fails, + * POLARSSL_ERR_CIPHER_FULL_BLOCK_EXPECTED if decryption + * expected a full block but was not provided one, + * POLARSSL_ERR_CIPHER_INVALID_PADDING on invalid padding + * while decrypting or a cipher specific error code. + */ +int cipher_finish( cipher_context_t *ctx, unsigned char *output, size_t *olen); + + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int cipher_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* POLARSSL_MD_H */ diff --git a/include/polarssl/cipher_wrap.h b/include/polarssl/cipher_wrap.h new file mode 100644 index 000000000..5df81743b --- /dev/null +++ b/include/polarssl/cipher_wrap.h @@ -0,0 +1,91 @@ +/** + * \file cipher_wrap.h + * + * \brief Cipher wrappers. + * + * \author Adriaan de Jong + * + * Copyright (C) 2006-2011, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_CIPHER_WRAP_H +#define POLARSSL_CIPHER_WRAP_H + +#include "config.h" +#include "cipher.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(POLARSSL_AES_C) + +extern const cipher_info_t aes_128_cbc_info; +extern const cipher_info_t aes_192_cbc_info; +extern const cipher_info_t aes_256_cbc_info; + +#if defined(POLARSSL_CIPHER_MODE_CFB) +extern const cipher_info_t aes_128_cfb128_info; +extern const cipher_info_t aes_192_cfb128_info; +extern const cipher_info_t aes_256_cfb128_info; +#endif /* POLARSSL_CIPHER_MODE_CFB */ + +#if defined(POLARSSL_CIPHER_MODE_CTR) +extern const cipher_info_t aes_128_ctr_info; +extern const cipher_info_t aes_192_ctr_info; +extern const cipher_info_t aes_256_ctr_info; +#endif /* POLARSSL_CIPHER_MODE_CTR */ + +#endif /* defined(POLARSSL_AES_C) */ + +#if defined(POLARSSL_CAMELLIA_C) + +extern const cipher_info_t camellia_128_cbc_info; +extern const cipher_info_t camellia_192_cbc_info; +extern const cipher_info_t camellia_256_cbc_info; + +#if defined(POLARSSL_CIPHER_MODE_CFB) +extern const cipher_info_t camellia_128_cfb128_info; +extern const cipher_info_t camellia_192_cfb128_info; +extern const cipher_info_t camellia_256_cfb128_info; +#endif /* POLARSSL_CIPHER_MODE_CFB */ + +#if defined(POLARSSL_CIPHER_MODE_CTR) +extern const cipher_info_t camellia_128_ctr_info; +extern const cipher_info_t camellia_192_ctr_info; +extern const cipher_info_t camellia_256_ctr_info; +#endif /* POLARSSL_CIPHER_MODE_CTR */ + +#endif /* defined(POLARSSL_CAMELLIA_C) */ + +#if defined(POLARSSL_DES_C) + +extern const cipher_info_t des_cbc_info; +extern const cipher_info_t des_ede_cbc_info; +extern const cipher_info_t des_ede3_cbc_info; + +#endif /* defined(POLARSSL_DES_C) */ + +#ifdef __cplusplus +} +#endif + +#endif /* POLARSSL_CIPHER_WRAP_H */ diff --git a/include/polarssl/config.h b/include/polarssl/config.h new file mode 100644 index 000000000..ea518d77d --- /dev/null +++ b/include/polarssl/config.h @@ -0,0 +1,688 @@ +/** + * \file config.h + * + * \brief Configuration options (set of defines) + * + * Copyright (C) 2006-2011, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This set of compile-time options may be used to enable + * or disable features selectively, and reduce the global + * memory footprint. + */ +#ifndef POLARSSL_CONFIG_H +#define POLARSSL_CONFIG_H + +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE) +#define _CRT_SECURE_NO_DEPRECATE 1 +#endif + +/** + * \name SECTION: System support + * + * This section sets system specific settings. + * \{ + */ + +/** + * \def POLARSSL_HAVE_INT8 + * + * The system uses 8-bit wide native integers. + * + * Uncomment if native integers are 8-bit wide. +#define POLARSSL_HAVE_INT8 + */ + +/** + * \def POLARSSL_HAVE_INT16 + * + * The system uses 16-bit wide native integers. + * + * Uncomment if native integers are 16-bit wide. +#define POLARSSL_HAVE_INT16 + */ + +/** + * \def POLARSSL_HAVE_LONGLONG + * + * The compiler supports the use of long long. + * + * Uncomment if the compiler supports long long. +#define POLARSSL_HAVE_LONGLONG + */ + +/** + * \def POLARSSL_HAVE_ASM + * + * The compiler has support for asm() + * + * Uncomment to enable the use of assembly code. + * + * Requires support for asm() in compiler. + * + * Used in: + * library/timing.c + * library/padlock.c + * include/polarssl/bn_mul.h + * + */ +#define POLARSSL_HAVE_ASM + +/** + * \def POLARSSL_HAVE_SSE2 + * + * CPI supports SSE2 instruction set. + * + * Uncomment if the CPU supports SSE2 (IA-32 specific). + * +#define POLARSSL_HAVE_SSE2 + */ +/* \} name */ + +/** + * \name SECTION: PolarSSL feature support + * + * This section sets support for features that are or are not needed + * within the modules that are enabled. + * \{ + */ + +/** + * \def POLARSSL_AES_ROM_TABLES + * + * Store the AES tables in ROM. + * + * Uncomment this macro to store the AES tables in ROM. + * +#define POLARSSL_AES_ROM_TABLES + */ + +/** + * \def POLARSSL_CIPHER_MODE_CFB + * + * Enable Cipher Feedback mode (CFB) for symmetric ciphers. + */ +#define POLARSSL_CIPHER_MODE_CFB + +/** + * \def POLARSSL_CIPHER_MODE_CTR + * + * Enable Counter Block Cipher mode (CTR) for symmetric ciphers. + */ +#define POLARSSL_CIPHER_MODE_CTR + +/** + * \def POLARSSL_DEBUG_MSG + * + * Requires: POLARSSL_DEBUG_C + * + * Enable all SSL/TLS debugging messages. + */ +#define POLARSSL_DEBUG_MSG + +/** + * \def POLARSSL_GENPRIME + * + * Requires: POLARSSL_BIGNUM_C, POLARSSL_RSA_C + * + * Enable the RSA prime-number generation code. + */ +#define POLARSSL_GENPRIME + +/** + * \def POLARSSL_FS_IO + * + * Enable functions that use the filesystem. + */ +#define POLARSSL_FS_IO + +/** + * \def POLARSSL_NO_DEFAULT_ENTROPY_SOURCES + * + * Do not add default entropy sources. These are the platform specific, + * hardclock and HAVEGE based poll functions. + * + * This is useful to have more control over the added entropy sources in an + * application. + * + * Uncomment this macro to prevent loading of default entropy functions. +#define POLARSSL_NO_DEFAULT_ENTROPY_SOURCES + */ + +/** + * \def POLARSSL_NO_PLATFORM_ENTROPY + * + * Do not use built-in platform entropy functions. + * This is useful if your platform does not support + * standards like the /dev/urandom or Windows CryptoAPI. + * + * Uncomment this macro to disable the built-in platform entropy functions. +#define POLARSSL_NO_PLATFORM_ENTROPY + */ + +/** + * \def POLARSSL_PKCS1_V21 + * + * Requires: POLARSSL_MD_C, POLARSSL_RSA_C + * + * Enable support for PKCS#1 v2.1 encoding. + * This enables support for RSAES-OAEP and RSASSA-PSS operations. + */ +#define POLARSSL_PKCS1_V21 + +/** + * \def POLARSSL_RSA_NO_CRT + * + * Do not use the Chinese Remainder Theorem for the RSA private operation. + * + * Uncomment this macro to disable the use of CRT in RSA. + * +#define POLARSSL_RSA_NO_CRT + */ + +/** + * \def POLARSSL_SELF_TEST + * + * Enable the checkup functions (*_self_test). + */ +#define POLARSSL_SELF_TEST + +/** + * \def POLARSSL_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION + * + * If set, the X509 parser will not break-off when parsing an X509 certificate + * and encountering an unknown critical extension. + * + * Uncomment to prevent an error. + * +#define POLARSSL_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION + */ +/* \} name */ + +/** + * \name SECTION: PolarSSL modules + * + * This section enables or disables entire modules in PolarSSL + * \{ + */ + +/** + * \def POLARSSL_AES_C + * + * Enable the AES block cipher. + * + * Module: library/aes.c + * Caller: library/ssl_tls.c + * library/pem.c + * library/ctr_drbg.c + * + * This module enables the following ciphersuites: + * SSL_RSA_AES_128_SHA + * SSL_RSA_AES_256_SHA + * SSL_EDH_RSA_AES_256_SHA + */ +#define POLARSSL_AES_C + +/** + * \def POLARSSL_ARC4_C + * + * Enable the ARCFOUR stream cipher. + * + * Module: library/arc4.c + * Caller: library/ssl_tls.c + * + * This module enables the following ciphersuites: + * SSL_RSA_RC4_128_MD5 + * SSL_RSA_RC4_128_SHA + */ +#define POLARSSL_ARC4_C + +/** + * \def POLARSSL_ASN1_PARSE_C + * + * Enable the generic ASN1 parser. + * + * Module: library/asn1.c + * Caller: library/x509parse.c + */ +#define POLARSSL_ASN1_PARSE_C + +/** + * \def POLARSSL_BASE64_C + * + * Enable the Base64 module. + * + * Module: library/base64.c + * Caller: library/pem.c + * + * This module is required for PEM support (required by X.509). + */ +#define POLARSSL_BASE64_C + +/** + * \def POLARSSL_BIGNUM_C + * + * Enable the multo-precision integer library. + * + * Module: library/bignum.c + * Caller: library/dhm.c + * library/rsa.c + * library/ssl_tls.c + * library/x509parse.c + * + * This module is required for RSA and DHM support. + */ +#define POLARSSL_BIGNUM_C + +/** + * \def POLARSSL_CAMELLIA_C + * + * Enable the Camellia block cipher. + * + * Module: library/camellia.c + * Caller: library/ssl_tls.c + * + * This module enabled the following cipher suites: + * SSL_RSA_CAMELLIA_128_SHA + * SSL_RSA_CAMELLIA_256_SHA + * SSL_EDH_RSA_CAMELLIA_256_SHA + */ +#define POLARSSL_CAMELLIA_C + +/** + * \def POLARSSL_CERTS_C + * + * Enable the test certificates. + * + * Module: library/certs.c + * Caller: + * + * This module is used for testing (ssl_client/server). + */ +#define POLARSSL_CERTS_C + +/** + * \def POLARSSL_CIPHER_C + * + * Enable the generic cipher layer. + * + * Module: library/cipher.c + * Caller: + * + * Uncomment to enable generic cipher wrappers. + */ +#define POLARSSL_CIPHER_C + +/** + * \def POLARSSL_CTR_DRBG_C + * + * Enable the CTR_DRBG AES-256-based random generator + * + * Module: library/ctr_drbg.c + * Caller: + * + * Requires: POLARSSL_AES_C + * + * This module provides the CTR_DRBG AES-256 random number generator. + */ +#define POLARSSL_CTR_DRBG_C + +/** + * \def POLARSSL_DEBUG_C + * + * Enable the debug functions. + * + * Module: library/debug.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * + * This module provides debugging functions. + */ +#define POLARSSL_DEBUG_C + +/** + * \def POLARSSL_DES_C + * + * Enable the DES block cipher. + * + * Module: library/des.c + * Caller: library/ssl_tls.c + * + * This module enables the following ciphersuites: + * SSL_RSA_DES_168_SHA + * SSL_EDH_RSA_DES_168_SHA + */ +#define POLARSSL_DES_C + +/** + * \def POLARSSL_DHM_C + * + * Enable the Diffie-Hellman-Merkle key exchange. + * + * Module: library/dhm.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * + * This module enables the following ciphersuites: + * SSL_EDH_RSA_DES_168_SHA + * SSL_EDH_RSA_AES_256_SHA + * SSL_EDH_RSA_CAMELLIA_256_SHA + */ +#define POLARSSL_DHM_C + +/** + * \def POLARSSL_ENTROPY_C + * + * Enable the platform-specific entropy code. + * + * Module: library/entropy.c + * Caller: + * + * Requires: POLARSSL_SHA4_C + * + * This module provides a generic entropy pool + */ +#define POLARSSL_ENTROPY_C + +/** + * \def POLARSSL_ERROR_C + * + * Enable error code to error string conversion. + * + * Module: library/error.c + * Caller: + * + * This module enables err_strerror(). + */ +#define POLARSSL_ERROR_C + +/** + * \def POLARSSL_HAVEGE_C + * + * Enable the HAVEGE random generator. + * + * Module: library/havege.c + * Caller: + * + * Requires: POLARSSL_TIMING_C + * + * This module enables the HAVEGE random number generator. + */ +#define POLARSSL_HAVEGE_C + +/** + * \def POLARSSL_MD_C + * + * Enable the generic message digest layer. + * + * Module: library/md.c + * Caller: + * + * Uncomment to enable generic message digest wrappers. + */ +#define POLARSSL_MD_C + +/** + * \def POLARSSL_MD2_C + * + * Enable the MD2 hash algorithm + * + * Module: library/md2.c + * Caller: library/x509parse.c + * + * Uncomment to enable support for (rare) MD2-signed X.509 certs. + * +#define POLARSSL_MD2_C + */ + +/** + * \def POLARSSL_MD4_C + * + * Enable the MD4 hash algorithm + * + * Module: library/md4.c + * Caller: library/x509parse.c + * + * Uncomment to enable support for (rare) MD4-signed X.509 certs. + * +#define POLARSSL_MD4_C + */ + +/** + * \def POLARSSL_MD5_C + * + * Enable the MD5 hash algorithm + * + * Module: library/md5.c + * Caller: library/ssl_tls.c + * library/x509parse.c + * + * This module is required for SSL/TLS and X.509. + */ +#define POLARSSL_MD5_C + +/** + * \def POLARSSL_NET_C + * + * Enable the TCP/IP networking routines. + * + * Module: library/net.c + * Caller: + * + * This module provides TCP/IP networking routines. + */ +#define POLARSSL_NET_C + +/** + * \def POLARSSL_PADLOCK_C + * + * Enable VIA Padlock support on x86. + * + * Module: library/padlock.c + * Caller: library/aes.c + * + * This modules adds support for the VIA PadLock on x86. + */ +#define POLARSSL_PADLOCK_C + +/** + * \def POLARSSL_PEM_C + * + * Enable PEM decoding + * + * Module: library/pem.c + * Caller: library/x509parse.c + * + * Requires: POLARSSL_BASE64_C + * + * This modules adds support for decoding PEM files. + */ +#define POLARSSL_PEM_C + +/** + * \def POLARSSL_PKCS11_C + * + * Enable support for PKCS#11 smartcard support. + * + * Module: library/ssl_srv.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * + * Requires: POLARSSL_SSL_TLS_C + * + * This module is required for SSL/TLS PKCS #11 smartcard support. + * Requires the presence of the PKCS#11 helper library (libpkcs11-helper) +#define POLARSSL_PKCS11_C + */ + +/** + * \def POLARSSL_RSA_C + * + * Enable the RSA public-key cryptosystem. + * + * Module: library/rsa.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * library/x509.c + * + * Requires: POLARSSL_BIGNUM_C + * + * This module is required for SSL/TLS and MD5-signed certificates. + */ +#define POLARSSL_RSA_C + +/** + * \def POLARSSL_SHA1_C + * + * Enable the SHA1 cryptographic hash algorithm. + * + * Module: library/sha1.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * library/x509parse.c + * + * This module is required for SSL/TLS and SHA1-signed certificates. + */ +#define POLARSSL_SHA1_C + +/** + * \def POLARSSL_SHA2_C + * + * Enable the SHA-224 and SHA-256 cryptographic hash algorithms. + * + * Module: library/sha2.c + * Caller: library/md_wrap.c + * library/x509parse.c + * + * This module adds support for SHA-224 and SHA-256. + */ +#define POLARSSL_SHA2_C + +/** + * \def POLARSSL_SHA4_C + * + * Enable the SHA-384 and SHA-512 cryptographic hash algorithms. + * + * Module: library/sha4.c + * Caller: library/md_wrap.c + * library/x509parse.c + * + * This module adds support for SHA-384 and SHA-512. + */ +#define POLARSSL_SHA4_C + +/** + * \def POLARSSL_SSL_CLI_C + * + * Enable the SSL/TLS client code. + * + * Module: library/ssl_cli.c + * Caller: + * + * Requires: POLARSSL_SSL_TLS_C + * + * This module is required for SSL/TLS client support. + */ +#define POLARSSL_SSL_CLI_C + +/* + * \def POLARSSL_SSL_SRV_C + * + * Enable the SSL/TLS server code. + * + * Module: library/ssl_srv.c + * Caller: + * + * Requires: POLARSSL_SSL_TLS_C + * + * This module is required for SSL/TLS server support. + */ +#define POLARSSL_SSL_SRV_C + +/** + * \def POLARSSL_SSL_TLS_C + * + * Enable the generic SSL/TLS code. + * + * Module: library/ssl_tls.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * + * Requires: POLARSSL_MD5_C, POLARSSL_SHA1_C, POLARSSL_X509_PARSE_C + * + * This module is required for SSL/TLS. + */ +#define POLARSSL_SSL_TLS_C + +/** + * \def POLARSSL_TIMING_C + * + * Enable the portable timing interface. + * + * Module: library/timing.c + * Caller: library/havege.c + * + * This module is used by the HAVEGE random number generator. + */ +#define POLARSSL_TIMING_C + +/** + * \def POLARSSL_VERSION_C + * + * Enable run-time version information. + * + * Module: library/version.c + * + * This module provides run-time version information. + */ +#define POLARSSL_VERSION_C + +/** + * \def POLARSSL_X509_PARSE_C + * + * Enable X.509 certificate parsing. + * + * Module: library/x509parse.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * + * Requires: POLARSSL_ASN1_PARSE_C, POLARSSL_BIGNUM_C, POLARSSL_RSA_C + * + * This module is required for X.509 certificate parsing. + */ +#define POLARSSL_X509_PARSE_C + +/** + * \def POLARSSL_XTEA_C + * + * Enable the XTEA block cipher. + * + * Module: library/xtea.c + * Caller: + */ +#define POLARSSL_XTEA_C +/* \} name */ + +#endif /* config.h */ diff --git a/include/polarssl/ctr_drbg.h b/include/polarssl/ctr_drbg.h new file mode 100644 index 000000000..83861a91c --- /dev/null +++ b/include/polarssl/ctr_drbg.h @@ -0,0 +1,228 @@ +/** + * \file ctr_drbg.h + * + * \brief CTR_DRBG based on AES-256 (NIST SP 800-90) + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_CTR_DRBG_H +#define POLARSSL_CTR_DRBG_H + +#include + +#include "aes.h" + +#define POLARSSL_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED -0x0034 /**< The entropy source failed. */ +#define POLARSSL_ERR_CTR_DRBG_REQUEST_TOO_BIG -0x0036 /**< Too many random requested in single call. */ +#define POLARSSL_ERR_CTR_DRBG_INPUT_TOO_BIG -0x0038 /**< Input too large (Entropy + additional). */ +#define POLARSSL_ERR_CTR_DRBG_FILE_IO_ERROR -0x003A /**< Read/write error in file. */ + +#define CTR_DRBG_BLOCKSIZE 16 /**< Block size used by the cipher */ +#define CTR_DRBG_KEYSIZE 32 /**< Key size used by the cipher */ +#define CTR_DRBG_KEYBITS ( CTR_DRBG_KEYSIZE * 8 ) +#define CTR_DRBG_SEEDLEN ( CTR_DRBG_KEYSIZE + CTR_DRBG_BLOCKSIZE ) + /**< The seed length (counter + AES key) */ +#define CTR_DRBG_ENTROPY_LEN 48 /**< Amount of entropy used per seed by default */ +#define CTR_DRBG_RESEED_INTERVAL 10000 /**< Interval before reseed is performed by default */ +#define CTR_DRBG_MAX_INPUT 256 /**< Maximum number of additional input bytes */ +#define CTR_DRBG_MAX_REQUEST 1024 /**< Maximum number of requested bytes per call */ +#define CTR_DRBG_MAX_SEED_INPUT 384 /**< Maximum size of (re)seed buffer */ + +#define CTR_DRBG_PR_OFF 0 /**< No prediction resistance */ +#define CTR_DRBG_PR_ON 1 /**< Prediction resistance enabled */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief CTR_DRBG context structure + */ +typedef struct +{ + unsigned char counter[16]; /*!< counter (V) */ + int reseed_counter; /*!< reseed counter */ + int prediction_resistance; /*!< enable prediction resistance (Automatic + reseed before every random generation) */ + size_t entropy_len; /*!< amount of entropy grabbed on each (re)seed */ + int reseed_interval; /*!< reseed interval */ + + aes_context aes_ctx; /*!< AES context */ + + /* + * Callbacks (Entropy) + */ + int (*f_entropy)(void *, unsigned char *, size_t); + + void *p_entropy; /*!< context for the entropy function */ +} +ctr_drbg_context; + +/** + * \brief CTR_DRBG initialization + * + * Note: Personalization data can be provided in addition to the more generic + * entropy source to make this instantiation as unique as possible. + * + * \param ctx CTR_DRBG context to be initialized + * \param f_entropy Entropy callback (p_entropy, buffer to fill, buffer + * length) + * \param p_entropy Entropy context + * \param custom Personalization data (Device specific identifiers) + * (Can be NULL) + * \param len Length of personalization data + * + * \return 0 if successful, or + * POLARSSL_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED + */ +int ctr_drbg_init( ctr_drbg_context *ctx, + int (*f_entropy)(void *, unsigned char *, size_t), + void *p_entropy, + const unsigned char *custom, + size_t len ); + +/** + * \brief Enable / disable prediction resistance (Default: Off) + * + * Note: If enabled, entropy is used for ctx->entropy_len before each call! + * Only use this if you have ample supply of good entropy! + * + * \param ctx CTR_DRBG context + * \param resistance CTR_DRBG_PR_ON or CTR_DRBG_PR_OFF + */ +void ctr_drbg_set_prediction_resistance( ctr_drbg_context *ctx, + int resistance ); + +/** + * \brief Set the amount of entropy grabbed on each (re)seed + * (Default: CTR_DRBG_ENTROPY_LEN) + * + * \param ctx CTR_DRBG context + * \param len Amount of entropy to grab + */ +void ctr_drbg_set_entropy_len( ctr_drbg_context *ctx, + size_t len ); + +/** + * \brief Set the reseed interval + * (Default: CTR_DRBG_RESEED_INTERVAL) + * + * \param ctx CTR_DRBG context + * \param interval Reseed interval + */ +void ctr_drbg_set_reseed_interval( ctr_drbg_context *ctx, + int interval ); + +/** + * \brief CTR_DRBG reseeding (extracts data from entropy source) + * + * \param ctx CTR_DRBG context + * \param additional Additional data to add to state (Can be NULL) + * \param len Length of additional data + * + * \return 0 if successful, or + * POLARSSL_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED + */ +int ctr_drbg_reseed( ctr_drbg_context *ctx, + const unsigned char *additional, size_t len ); + +/** + * \brief CTR_DRBG update state + * + * \param ctx CTR_DRBG context + * \param additional Additional data to update state with + * \param add_len Length of additional data + */ +void ctr_drbg_update( ctr_drbg_context *ctx, + const unsigned char *additional, size_t add_len ); + +/** + * \brief CTR_DRBG generate random with additional update input + * + * Note: Automatically reseeds if reseed_counter is reached. + * + * \param p_rng CTR_DRBG context + * \param output Buffer to fill + * \param output_len Length of the buffer + * \param additional Additional data to update with (Can be NULL) + * \param add_len Length of additional data + * + * \return 0 if successful, or + * POLARSSL_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED, or + * POLARSSL_ERR_CTR_DRBG_REQUEST_TOO_BIG + */ +int ctr_drbg_random_with_add( void *p_rng, + unsigned char *output, size_t output_len, + const unsigned char *additional, size_t add_len ); + +/** + * \brief CTR_DRBG generate random + * + * Note: Automatically reseeds if reseed_counter is reached. + * + * \param p_rng CTR_DRBG context + * \param output Buffer to fill + * \param output_len Length of the buffer + * + * \return 0 if successful, or + * POLARSSL_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED, or + * POLARSSL_ERR_CTR_DRBG_REQUEST_TOO_BIG + */ +int ctr_drbg_random( void *p_rng, + unsigned char *output, size_t output_len ); + +#if defined(POLARSSL_FS_IO) +/** + * \brief Write a seed file + * + * \param path Name of the file + * + * \return 0 if successful, 1 on file error, or + * POLARSSL_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED + */ +int ctr_drbg_write_seed_file( ctr_drbg_context *ctx, const char *path ); + +/** + * \brief Read and update a seed file. Seed is added to this + * instance + * + * \param path Name of the file + * + * \return 0 if successful, 1 on file error, + * POLARSSL_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED or + * POLARSSL_ERR_CTR_DRBG_INPUT_TOO_BIG + */ +int ctr_drbg_update_seed_file( ctr_drbg_context *ctx, const char *path ); +#endif + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int ctr_drbg_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* ctr_drbg.h */ diff --git a/include/polarssl/debug.h b/include/polarssl/debug.h new file mode 100644 index 000000000..4fb378228 --- /dev/null +++ b/include/polarssl/debug.h @@ -0,0 +1,89 @@ +/** + * \file debug.h + * + * \brief Debug functions + * + * Copyright (C) 2006-2011, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_DEBUG_H +#define POLARSSL_DEBUG_H + +#include "config.h" +#include "ssl.h" + +#if defined(POLARSSL_DEBUG_MSG) && defined(POLARSSL_DEBUG_C) + +#define SSL_DEBUG_MSG( level, args ) \ + debug_print_msg( ssl, level, __FILE__, __LINE__, debug_fmt args ); + +#define SSL_DEBUG_RET( level, text, ret ) \ + debug_print_ret( ssl, level, __FILE__, __LINE__, text, ret ); + +#define SSL_DEBUG_BUF( level, text, buf, len ) \ + debug_print_buf( ssl, level, __FILE__, __LINE__, text, buf, len ); + +#define SSL_DEBUG_MPI( level, text, X ) \ + debug_print_mpi( ssl, level, __FILE__, __LINE__, text, X ); + +#define SSL_DEBUG_CRT( level, text, crt ) \ + debug_print_crt( ssl, level, __FILE__, __LINE__, text, crt ); + +#else + +#define SSL_DEBUG_MSG( level, args ) do { } while( 0 ) +#define SSL_DEBUG_RET( level, text, ret ) do { } while( 0 ) +#define SSL_DEBUG_BUF( level, text, buf, len ) do { } while( 0 ) +#define SSL_DEBUG_MPI( level, text, X ) do { } while( 0 ) +#define SSL_DEBUG_CRT( level, text, crt ) do { } while( 0 ) + +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +char *debug_fmt( const char *format, ... ); + +void debug_print_msg( const ssl_context *ssl, int level, + const char *file, int line, const char *text ); + +void debug_print_ret( const ssl_context *ssl, int level, + const char *file, int line, + const char *text, int ret ); + +void debug_print_buf( const ssl_context *ssl, int level, + const char *file, int line, const char *text, + unsigned char *buf, size_t len ); + +void debug_print_mpi( const ssl_context *ssl, int level, + const char *file, int line, + const char *text, const mpi *X ); + +void debug_print_crt( const ssl_context *ssl, int level, + const char *file, int line, + const char *text, const x509_cert *crt ); + +#ifdef __cplusplus +} +#endif + +#endif /* debug.h */ diff --git a/include/polarssl/des.h b/include/polarssl/des.h new file mode 100644 index 000000000..653e68b38 --- /dev/null +++ b/include/polarssl/des.h @@ -0,0 +1,227 @@ +/** + * \file des.h + * + * \brief DES block cipher + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_DES_H +#define POLARSSL_DES_H + +#include + +#define DES_ENCRYPT 1 +#define DES_DECRYPT 0 + +#define POLARSSL_ERR_DES_INVALID_INPUT_LENGTH -0x0032 /**< The data input has an invalid length. */ + +#define DES_KEY_SIZE 8 + +/** + * \brief DES context structure + */ +typedef struct +{ + int mode; /*!< encrypt/decrypt */ + unsigned long sk[32]; /*!< DES subkeys */ +} +des_context; + +/** + * \brief Triple-DES context structure + */ +typedef struct +{ + int mode; /*!< encrypt/decrypt */ + unsigned long sk[96]; /*!< 3DES subkeys */ +} +des3_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Set key parity on the given key to odd. + * + * DES keys are 56 bits long, but each byte is padded with + * a parity bit to allow verification. + * + * \param key 8-byte secret key + */ +void des_key_set_parity( unsigned char key[DES_KEY_SIZE] ); + +/** + * \brief Check that key parity on the given key is odd. + * + * DES keys are 56 bits long, but each byte is padded with + * a parity bit to allow verification. + * + * \param key 8-byte secret key + * + * \return 0 is parity was ok, 1 if parity was not correct. + */ +int des_key_check_key_parity( const unsigned char key[DES_KEY_SIZE] ); + +/** + * \brief Check that key is not a weak or semi-weak DES key + * + * \param key 8-byte secret key + * + * \return 0 if no weak key was found, 1 if a weak key was identified. + */ +int des_key_check_weak( const unsigned char key[DES_KEY_SIZE] ); + +/** + * \brief DES key schedule (56-bit, encryption) + * + * \param ctx DES context to be initialized + * \param key 8-byte secret key + * + * \return 0 + */ +int des_setkey_enc( des_context *ctx, const unsigned char key[DES_KEY_SIZE] ); + +/** + * \brief DES key schedule (56-bit, decryption) + * + * \param ctx DES context to be initialized + * \param key 8-byte secret key + * + * \return 0 + */ +int des_setkey_dec( des_context *ctx, const unsigned char key[DES_KEY_SIZE] ); + +/** + * \brief Triple-DES key schedule (112-bit, encryption) + * + * \param ctx 3DES context to be initialized + * \param key 16-byte secret key + * + * \return 0 + */ +int des3_set2key_enc( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 2] ); + +/** + * \brief Triple-DES key schedule (112-bit, decryption) + * + * \param ctx 3DES context to be initialized + * \param key 16-byte secret key + * + * \return 0 + */ +int des3_set2key_dec( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 2] ); + +/** + * \brief Triple-DES key schedule (168-bit, encryption) + * + * \param ctx 3DES context to be initialized + * \param key 24-byte secret key + * + * \return 0 + */ +int des3_set3key_enc( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 3] ); + +/** + * \brief Triple-DES key schedule (168-bit, decryption) + * + * \param ctx 3DES context to be initialized + * \param key 24-byte secret key + * + * \return 0 + */ +int des3_set3key_dec( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 3] ); + +/** + * \brief DES-ECB block encryption/decryption + * + * \param ctx DES context + * \param input 64-bit input block + * \param output 64-bit output block + * + * \return 0 if successful + */ +int des_crypt_ecb( des_context *ctx, + const unsigned char input[8], + unsigned char output[8] ); + +/** + * \brief DES-CBC buffer encryption/decryption + * + * \param ctx DES context + * \param mode DES_ENCRYPT or DES_DECRYPT + * \param length length of the input data + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + */ +int des_crypt_cbc( des_context *ctx, + int mode, + size_t length, + unsigned char iv[8], + const unsigned char *input, + unsigned char *output ); + +/** + * \brief 3DES-ECB block encryption/decryption + * + * \param ctx 3DES context + * \param input 64-bit input block + * \param output 64-bit output block + * + * \return 0 if successful + */ +int des3_crypt_ecb( des3_context *ctx, + const unsigned char input[8], + unsigned char output[8] ); + +/** + * \brief 3DES-CBC buffer encryption/decryption + * + * \param ctx 3DES context + * \param mode DES_ENCRYPT or DES_DECRYPT + * \param length length of the input data + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + * + * \return 0 if successful, or POLARSSL_ERR_DES_INVALID_INPUT_LENGTH + */ +int des3_crypt_cbc( des3_context *ctx, + int mode, + size_t length, + unsigned char iv[8], + const unsigned char *input, + unsigned char *output ); + +/* + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int des_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* des.h */ diff --git a/include/polarssl/dhm.h b/include/polarssl/dhm.h new file mode 100644 index 000000000..52b0bf94a --- /dev/null +++ b/include/polarssl/dhm.h @@ -0,0 +1,153 @@ +/** + * \file dhm.h + * + * \brief Diffie-Hellman-Merkle key exchange + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_DHM_H +#define POLARSSL_DHM_H + +#include "bignum.h" + +/* + * DHM Error codes + */ +#define POLARSSL_ERR_DHM_BAD_INPUT_DATA -0x3080 /**< Bad input parameters to function. */ +#define POLARSSL_ERR_DHM_READ_PARAMS_FAILED -0x3100 /**< Reading of the DHM parameters failed. */ +#define POLARSSL_ERR_DHM_MAKE_PARAMS_FAILED -0x3180 /**< Making of the DHM parameters failed. */ +#define POLARSSL_ERR_DHM_READ_PUBLIC_FAILED -0x3200 /**< Reading of the public values failed. */ +#define POLARSSL_ERR_DHM_MAKE_PUBLIC_FAILED -0x3280 /**< Makeing of the public value failed. */ +#define POLARSSL_ERR_DHM_CALC_SECRET_FAILED -0x3300 /**< Calculation of the DHM secret failed. */ + +/** + * \brief DHM context structure + */ +typedef struct +{ + size_t len; /*!< size(P) in chars */ + mpi P; /*!< prime modulus */ + mpi G; /*!< generator */ + mpi X; /*!< secret value */ + mpi GX; /*!< self = G^X mod P */ + mpi GY; /*!< peer = G^Y mod P */ + mpi K; /*!< key = GY^X mod P */ + mpi RP; /*!< cached R^2 mod P */ +} +dhm_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Parse the ServerKeyExchange parameters + * + * \param ctx DHM context + * \param p &(start of input buffer) + * \param end end of buffer + * + * \return 0 if successful, or an POLARSSL_ERR_DHM_XXX error code + */ +int dhm_read_params( dhm_context *ctx, + unsigned char **p, + const unsigned char *end ); + +/** + * \brief Setup and write the ServerKeyExchange parameters + * + * \param ctx DHM context + * \param x_size private value size in bytes + * \param output destination buffer + * \param olen number of chars written + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \note This function assumes that ctx->P and ctx->G + * have already been properly set (for example + * using mpi_read_string or mpi_read_binary). + * + * \return 0 if successful, or an POLARSSL_ERR_DHM_XXX error code + */ +int dhm_make_params( dhm_context *ctx, int x_size, + unsigned char *output, size_t *olen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Import the peer's public value G^Y + * + * \param ctx DHM context + * \param input input buffer + * \param ilen size of buffer + * + * \return 0 if successful, or an POLARSSL_ERR_DHM_XXX error code + */ +int dhm_read_public( dhm_context *ctx, + const unsigned char *input, size_t ilen ); + +/** + * \brief Create own private value X and export G^X + * + * \param ctx DHM context + * \param x_size private value size in bits + * \param output destination buffer + * \param olen must be equal to ctx->P.len + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successful, or an POLARSSL_ERR_DHM_XXX error code + */ +int dhm_make_public( dhm_context *ctx, int x_size, + unsigned char *output, size_t olen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Derive and export the shared secret (G^Y)^X mod P + * + * \param ctx DHM context + * \param output destination buffer + * \param olen number of chars written + * + * \return 0 if successful, or an POLARSSL_ERR_DHM_XXX error code + */ +int dhm_calc_secret( dhm_context *ctx, + unsigned char *output, size_t *olen ); + +/* + * \brief Free the components of a DHM key + */ +void dhm_free( dhm_context *ctx ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int dhm_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/polarssl/entropy.h b/include/polarssl/entropy.h new file mode 100644 index 000000000..53bce41b0 --- /dev/null +++ b/include/polarssl/entropy.h @@ -0,0 +1,150 @@ +/** + * \file entropy.h + * + * \brief Entropy accumulator implementation + * + * Copyright (C) 2006-2011, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_ENTROPY_H +#define POLARSSL_ENTROPY_H + +#include + +#include "config.h" + +#include "sha4.h" +#if defined(POLARSSL_HAVEGE_C) +#include "havege.h" +#endif + +#define POLARSSL_ERR_ENTROPY_SOURCE_FAILED -0x003C /**< Critical entropy source failure. */ +#define POLARSSL_ERR_ENTROPY_MAX_SOURCES -0x003E /**< No more sources can be added. */ +#define POLARSSL_ERR_ENTROPY_NO_SOURCES_DEFINED -0x0040 /**< No sources have been added to poll. */ + +#define ENTROPY_MAX_SOURCES 20 /**< Maximum number of sources supported */ +#define ENTROPY_MAX_GATHER 128 /**< Maximum amount requested from entropy sources */ +#define ENTROPY_BLOCK_SIZE 64 /**< Block size of entropy accumulator (SHA-512) */ + +#define ENTROPY_SOURCE_MANUAL ENTROPY_MAX_SOURCES + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Entropy poll callback pointer + * + * \param data Callback-specific data pointer + * \param output Data to fill + * \param len Maximum size to provide + * \param olen The actual amount of bytes put into the buffer (Can be 0) + * + * \return 0 if no critical failures occurred, + * POLARSSL_ERR_ENTROPY_SOURCE_FAILED otherwise + */ +typedef int (*f_source_ptr)(void *, unsigned char *, size_t, size_t *); + +/** + * \brief Entropy source state + */ +typedef struct +{ + f_source_ptr f_source; /**< The entropy source callback */ + void * p_source; /**< The callback data pointer */ + size_t size; /**< Amount received */ + size_t threshold; /**< Minimum level required before release */ +} +source_state; + +/** + * \brief Entropy context structure + */ +typedef struct +{ + sha4_context accumulator; + int source_count; + source_state source[ENTROPY_MAX_SOURCES]; +#if defined(POLARSSL_HAVEGE_C) + havege_state havege_data; +#endif +} +entropy_context; + +/** + * \brief Initialize the context + * + * \param ctx Entropy context to initialize + */ +void entropy_init( entropy_context *ctx ); + +/** + * \brief Adds an entropy source to poll + * + * \param ctx Entropy context + * \param f_source Entropy function + * \param p_source Function data + * \param threshold Minimum required from source before entropy is released + * ( with entropy_func() ) + * + * \return 0 if successful or POLARSSL_ERR_ENTROPY_MAX_SOURCES + */ +int entropy_add_source( entropy_context *ctx, + f_source_ptr f_source, void *p_source, + size_t threshold ); + +/** + * \brief Trigger an extra gather poll for the accumulator + * + * \param ctx Entropy context + * + * \return 0 if successful, or POLARSSL_ERR_ENTROPY_SOURCE_FAILED + */ +int entropy_gather( entropy_context *ctx ); + +/** + * \brief Retrieve entropy from the accumulator (Max ENTROPY_BLOCK_SIZE) + * + * \param data Entropy context + * \param output Buffer to fill + * \param len Length of buffer + * + * \return 0 if successful, or POLARSSL_ERR_ENTROPY_SOURCE_FAILED + */ +int entropy_func( void *data, unsigned char *output, size_t len ); + +/** + * \brief Add data to the accumulator manually + * + * \param ctx Entropy context + * \param data Data to add + * \param len Length of data + * + * \return 0 if successful + */ +int entropy_update_manual( entropy_context *ctx, + const unsigned char *data, size_t len ); + +#ifdef __cplusplus +} +#endif + +#endif /* entropy.h */ diff --git a/include/polarssl/entropy_poll.h b/include/polarssl/entropy_poll.h new file mode 100644 index 000000000..011659829 --- /dev/null +++ b/include/polarssl/entropy_poll.h @@ -0,0 +1,75 @@ +/** + * \file entropy_poll.h + * + * \brief Platform-specific and custom entropy polling functions + * + * Copyright (C) 2006-2011, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_ENTROPY_POLL_H +#define POLARSSL_ENTROPY_POLL_H + +#include + +#include "config.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Default thresholds for built-in sources + */ +#define ENTROPY_MIN_PLATFORM 128 /**< Minimum for platform source */ +#define ENTROPY_MIN_HAVEGE 128 /**< Minimum for HAVEGE */ +#define ENTROPY_MIN_HARDCLOCK 32 /**< Minimum for hardclock() */ + +#if !defined(POLARSSL_NO_PLATFORM_ENTROPY) +/** + * \brief Platform-specific entropy poll callback + */ +int platform_entropy_poll( void *data, + unsigned char *output, size_t len, size_t *olen ); +#endif + +#if defined(POLARSSL_HAVEGE_C) +/** + * \brief HAVEGE based entropy poll callback + * + * Requires an HAVEGE state as its data pointer. + */ +int havege_poll( void *data, + unsigned char *output, size_t len, size_t *olen ); +#endif + +#if defined(POLARSSL_TIMING_C) +/** + * \brief hardclock-based entropy poll callback + */ +int hardclock_poll( void *data, + unsigned char *output, size_t len, size_t *olen ); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* entropy_poll.h */ diff --git a/include/polarssl/error.h b/include/polarssl/error.h new file mode 100644 index 000000000..9c1707105 --- /dev/null +++ b/include/polarssl/error.h @@ -0,0 +1,101 @@ +/** + * \file error.h + * + * \brief Error to string translation + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_ERROR_H +#define POLARSSL_ERROR_H + +/** + * Error code layout. + * + * Currently we try to keep all error codes within the negative space of 16 + * bytes signed integers to support all platforms (-0x0000 - -0x8000). In + * addition we'd like to give two layers of information on the error if + * possible. + * + * For that purpose the error codes are segmented in the following manner: + * + * 16 bit error code bit-segmentation + * + * 1 bit - Intentionally not used + * 3 bits - High level module ID + * 5 bits - Module-dependent error code + * 6 bits - Low level module errors + * 1 bit - Intentionally not used + * + * Low-level module errors (0x007E-0x0002) + * + * Module Nr Codes assigned + * MPI 7 0x0002-0x0010 + * ASN1 6 0x0014-0x001E + * AES 2 0x0020-0x0022 + * CAMELLIA 2 0x0024-0x0026 + * XTEA 1 0x0028-0x0028 + * BASE64 2 0x002A-0x002C + * PADLOCK 1 0x0030-0x0030 + * DES 1 0x0032-0x0032 + * NET 11 0x0040-0x0054 + * CTR_DBRG 3 0x0034-0x003A + * ENTROPY 3 0x003C-0x0040 + * MD2 1 0x0070-0x0070 + * MD4 1 0x0072-0x0072 + * MD5 1 0x0074-0x0074 + * SHA1 1 0x0076-0x0076 + * SHA2 1 0x0078-0x0078 + * SHA4 1 0x007A-0x007A + * + * High-level module nr (3 bits - 0x1...-0x8...) + * Name ID Nr of Errors + * PEM 1 8 + * X509 2 21 + * DHM 3 6 + * RSA 4 9 + * MD 5 4 + * CIPHER 6 5 + * SSL 7 30 + * + * Module dependent error code (5 bits 0x.08.-0x.F8.) + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Translate a PolarSSL error code into a string representation, + * Result is truncated if necessary and always includes a terminating + * null byte. + * + * \param errnum error code + * \param buffer buffer to place representation in + * \param buflen length of the buffer + */ +void error_strerror( int errnum, char *buffer, size_t buflen ); + +#ifdef __cplusplus +} +#endif + +#endif /* error.h */ diff --git a/include/polarssl/havege.h b/include/polarssl/havege.h new file mode 100644 index 000000000..48d0f162a --- /dev/null +++ b/include/polarssl/havege.h @@ -0,0 +1,71 @@ +/** + * \file havege.h + * + * \brief HAVEGE: HArdware Volatile Entropy Gathering and Expansion + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_HAVEGE_H +#define POLARSSL_HAVEGE_H + +#include + +#define COLLECT_SIZE 1024 + +/** + * \brief HAVEGE state structure + */ +typedef struct +{ + int PT1, PT2, offset[2]; + int pool[COLLECT_SIZE]; + int WALK[8192]; +} +havege_state; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief HAVEGE initialization + * + * \param hs HAVEGE state to be initialized + */ +void havege_init( havege_state *hs ); + +/** + * \brief HAVEGE rand function + * + * \param p_rng A HAVEGE state + * \param output Buffer to fill + * \param len Length of buffer + * + * \return A random int + */ +int havege_random( void *p_rng, unsigned char *output, size_t len ); + +#ifdef __cplusplus +} +#endif + +#endif /* havege.h */ diff --git a/include/polarssl/md.h b/include/polarssl/md.h new file mode 100644 index 000000000..88596cb04 --- /dev/null +++ b/include/polarssl/md.h @@ -0,0 +1,354 @@ +/** + * \file md.h + * + * \brief Generic message digest wrapper + * + * \author Adriaan de Jong + * + * Copyright (C) 2006-2011, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_MD_H +#define POLARSSL_MD_H + +#include + +#if defined(_MSC_VER) && !defined(inline) +#define inline _inline +#else +#if defined(__ARMCC_VERSION) && !defined(inline) +#define inline __inline +#endif /* __ARMCC_VERSION */ +#endif /*_MSC_VER */ + +#define POLARSSL_ERR_MD_FEATURE_UNAVAILABLE -0x5080 /**< The selected feature is not available. */ +#define POLARSSL_ERR_MD_BAD_INPUT_DATA -0x5100 /**< Bad input parameters to function. */ +#define POLARSSL_ERR_MD_ALLOC_FAILED -0x5180 /**< Failed to allocate memory. */ +#define POLARSSL_ERR_MD_FILE_IO_ERROR -0x5200 /**< Opening or reading of file failed. */ + +typedef enum { + POLARSSL_MD_NONE=0, + POLARSSL_MD_MD2, + POLARSSL_MD_MD4, + POLARSSL_MD_MD5, + POLARSSL_MD_SHA1, + POLARSSL_MD_SHA224, + POLARSSL_MD_SHA256, + POLARSSL_MD_SHA384, + POLARSSL_MD_SHA512, +} md_type_t; + +#define POLARSSL_MD_MAX_SIZE 64 /* longest known is SHA512 */ + +/** + * Message digest information. Allows message digest functions to be called + * in a generic way. + */ +typedef struct { + /** Digest identifier */ + md_type_t type; + + /** Name of the message digest */ + const char * name; + + /** Output length of the digest function */ + int size; + + /** Digest initialisation function */ + void (*starts_func)( void *ctx ); + + /** Digest update function */ + void (*update_func)( void *ctx, const unsigned char *input, size_t ilen ); + + /** Digest finalisation function */ + void (*finish_func)( void *ctx, unsigned char *output ); + + /** Generic digest function */ + void (*digest_func)( const unsigned char *input, size_t ilen, + unsigned char *output ); + + /** Generic file digest function */ + int (*file_func)( const char *path, unsigned char *output ); + + /** HMAC Initialisation function */ + void (*hmac_starts_func)( void *ctx, const unsigned char *key, size_t keylen ); + + /** HMAC update function */ + void (*hmac_update_func)( void *ctx, const unsigned char *input, size_t ilen ); + + /** HMAC finalisation function */ + void (*hmac_finish_func)( void *ctx, unsigned char *output); + + /** HMAC context reset function */ + void (*hmac_reset_func)( void *ctx ); + + /** Generic HMAC function */ + void (*hmac_func)( const unsigned char *key, size_t keylen, + const unsigned char *input, size_t ilen, + unsigned char *output ); + + /** Allocate a new context */ + void * (*ctx_alloc_func)( void ); + + /** Free the given context */ + void (*ctx_free_func)( void *ctx ); + +} md_info_t; + +/** + * Generic message digest context. + */ +typedef struct { + /** Information about the associated message digest */ + const md_info_t *md_info; + + /** Digest-specific context */ + void *md_ctx; +} md_context_t; + +#define MD_CONTEXT_T_INIT { \ + NULL, /* md_info */ \ + NULL, /* md_ctx */ \ +} + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Returns the list of digests supported by the generic digest module. + * + * \return a statically allocated array of digests, the last entry + * is 0. + */ +const int *md_list( void ); + +/** + * \brief Returns the message digest information associated with the + * given digest name. + * + * \param md_name Name of the digest to search for. + * + * \return The message digest information associated with md_name or + * NULL if not found. + */ +const md_info_t *md_info_from_string( const char *md_name ); + +/** + * \brief Returns the message digest information associated with the + * given digest type. + * + * \param md_type type of digest to search for. + * + * \return The message digest information associated with md_type or + * NULL if not found. + */ +const md_info_t *md_info_from_type( md_type_t md_type ); + +/** + * \brief Initialises and fills the message digest context structure with + * the appropriate values. + * + * \param ctx context to initialise. May not be NULL. The + * digest-specific context (ctx->md_ctx) must be NULL. It will + * be allocated, and must be freed using md_free_ctx() later. + * \param md_info message digest to use. + * + * \returns \c 0 on success, \c POLARSSL_ERR_MD_BAD_INPUT_DATA on + * parameter failure, \c POLARSSL_ERR_MD_ALLOC_FAILED if + * allocation of the digest-specific context failed. + */ +int md_init_ctx( md_context_t *ctx, const md_info_t *md_info ); + +/** + * \brief Free the message-specific context of ctx. Freeing ctx itself + * remains the responsibility of the caller. + * + * \param ctx Free the message-specific context + * + * \returns 0 on success, POLARSSL_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int md_free_ctx( md_context_t *ctx ); + +/** + * \brief Returns the size of the message digest output. + * + * \param md_info message digest info + * + * \return size of the message digest output. + */ +static inline unsigned char md_get_size( const md_info_t *md_info ) +{ + return md_info->size; +} + +/** + * \brief Returns the type of the message digest output. + * + * \param md_info message digest info + * + * \return type of the message digest output. + */ +static inline md_type_t md_get_type( const md_info_t *md_info ) +{ + return md_info->type; +} + +/** + * \brief Returns the name of the message digest output. + * + * \param md_info message digest info + * + * \return name of the message digest output. + */ +static inline const char *md_get_name( const md_info_t *md_info ) +{ + return md_info->name; +} + +/** + * \brief Set-up the given context for a new message digest + * + * \param ctx generic message digest context. + * + * \returns 0 on success, POLARSSL_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int md_starts( md_context_t *ctx ); + +/** + * \brief Generic message digest process buffer + * + * \param ctx Generic message digest context + * \param input buffer holding the datal + * \param ilen length of the input data + * + * \returns 0 on success, POLARSSL_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int md_update( md_context_t *ctx, const unsigned char *input, size_t ilen ); + +/** + * \brief Generic message digest final digest + * + * \param ctx Generic message digest context + * \param output Generic message digest checksum result + * + * \returns 0 on success, POLARSSL_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int md_finish( md_context_t *ctx, unsigned char *output ); + +/** + * \brief Output = message_digest( input buffer ) + * + * \param md_info message digest info + * \param input buffer holding the data + * \param ilen length of the input data + * \param output Generic message digest checksum result + * + * \returns 0 on success, POLARSSL_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int md( const md_info_t *md_info, const unsigned char *input, size_t ilen, + unsigned char *output ); + +/** + * \brief Output = message_digest( file contents ) + * + * \param md_info message digest info + * \param path input file name + * \param output generic message digest checksum result + * + * \return 0 if successful, POLARSSL_ERR_MD_FILE_OPEN_FAILED if fopen + * failed, POLARSSL_ERR_MD_FILE_READ_FAILED if fread failed, + * POLARSSL_ERR_MD_BAD_INPUT_DATA if md_info was NULL. + */ +int md_file( const md_info_t *md_info, const char *path, unsigned char *output ); + +/** + * \brief Generic HMAC context setup + * + * \param ctx HMAC context to be initialized + * \param key HMAC secret key + * \param keylen length of the HMAC key + * + * \returns 0 on success, POLARSSL_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int md_hmac_starts( md_context_t *ctx, const unsigned char *key, size_t keylen ); + +/** + * \brief Generic HMAC process buffer + * + * \param ctx HMAC context + * \param input buffer holding the data + * \param ilen length of the input data + * + * \returns 0 on success, POLARSSL_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int md_hmac_update( md_context_t *ctx, const unsigned char *input, size_t ilen ); + +/** + * \brief Generic HMAC final digest + * + * \param ctx HMAC context + * \param output Generic HMAC checksum result + * + * \returns 0 on success, POLARSSL_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int md_hmac_finish( md_context_t *ctx, unsigned char *output); + +/** + * \brief Generic HMAC context reset + * + * \param ctx HMAC context to be reset + * + * \returns 0 on success, POLARSSL_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int md_hmac_reset( md_context_t *ctx ); + +/** + * \brief Output = Generic_HMAC( hmac key, input buffer ) + * + * \param md_info message digest info + * \param key HMAC secret key + * \param keylen length of the HMAC key + * \param input buffer holding the data + * \param ilen length of the input data + * \param output Generic HMAC-result + * + * \returns 0 on success, POLARSSL_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int md_hmac( const md_info_t *md_info, const unsigned char *key, size_t keylen, + const unsigned char *input, size_t ilen, + unsigned char *output ); + +#ifdef __cplusplus +} +#endif + +#endif /* POLARSSL_MD_H */ diff --git a/include/polarssl/md2.h b/include/polarssl/md2.h new file mode 100644 index 000000000..1f60470fd --- /dev/null +++ b/include/polarssl/md2.h @@ -0,0 +1,153 @@ +/** + * \file md2.h + * + * \brief MD2 message digest algorithm (hash function) + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_MD2_H +#define POLARSSL_MD2_H + +#include + +#define POLARSSL_ERR_MD2_FILE_IO_ERROR -0x0070 /**< Read/write error in file. */ + +/** + * \brief MD2 context structure + */ +typedef struct +{ + unsigned char cksum[16]; /*!< checksum of the data block */ + unsigned char state[48]; /*!< intermediate digest state */ + unsigned char buffer[16]; /*!< data block being processed */ + + unsigned char ipad[16]; /*!< HMAC: inner padding */ + unsigned char opad[16]; /*!< HMAC: outer padding */ + size_t left; /*!< amount of data in buffer */ +} +md2_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief MD2 context setup + * + * \param ctx context to be initialized + */ +void md2_starts( md2_context *ctx ); + +/** + * \brief MD2 process buffer + * + * \param ctx MD2 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void md2_update( md2_context *ctx, const unsigned char *input, size_t ilen ); + +/** + * \brief MD2 final digest + * + * \param ctx MD2 context + * \param output MD2 checksum result + */ +void md2_finish( md2_context *ctx, unsigned char output[16] ); + +/** + * \brief Output = MD2( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output MD2 checksum result + */ +void md2( const unsigned char *input, size_t ilen, unsigned char output[16] ); + +/** + * \brief Output = MD2( file contents ) + * + * \param path input file name + * \param output MD2 checksum result + * + * \return 0 if successful, or POLARSSL_ERR_MD2_FILE_IO_ERROR + */ +int md2_file( const char *path, unsigned char output[16] ); + +/** + * \brief MD2 HMAC context setup + * + * \param ctx HMAC context to be initialized + * \param key HMAC secret key + * \param keylen length of the HMAC key + */ +void md2_hmac_starts( md2_context *ctx, const unsigned char *key, size_t keylen ); + +/** + * \brief MD2 HMAC process buffer + * + * \param ctx HMAC context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void md2_hmac_update( md2_context *ctx, const unsigned char *input, size_t ilen ); + +/** + * \brief MD2 HMAC final digest + * + * \param ctx HMAC context + * \param output MD2 HMAC checksum result + */ +void md2_hmac_finish( md2_context *ctx, unsigned char output[16] ); + +/** + * \brief MD2 HMAC context reset + * + * \param ctx HMAC context to be reset + */ +void md2_hmac_reset( md2_context *ctx ); + +/** + * \brief Output = HMAC-MD2( hmac key, input buffer ) + * + * \param key HMAC secret key + * \param keylen length of the HMAC key + * \param input buffer holding the data + * \param ilen length of the input data + * \param output HMAC-MD2 result + */ +void md2_hmac( const unsigned char *key, size_t keylen, + const unsigned char *input, size_t ilen, + unsigned char output[16] ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int md2_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* md2.h */ diff --git a/include/polarssl/md4.h b/include/polarssl/md4.h new file mode 100644 index 000000000..2bd35ea16 --- /dev/null +++ b/include/polarssl/md4.h @@ -0,0 +1,152 @@ +/** + * \file md4.h + * + * \brief MD4 message digest algorithm (hash function) + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_MD4_H +#define POLARSSL_MD4_H + +#include + +#define POLARSSL_ERR_MD4_FILE_IO_ERROR -0x0072 /**< Read/write error in file. */ + +/** + * \brief MD4 context structure + */ +typedef struct +{ + unsigned long total[2]; /*!< number of bytes processed */ + unsigned long state[4]; /*!< intermediate digest state */ + unsigned char buffer[64]; /*!< data block being processed */ + + unsigned char ipad[64]; /*!< HMAC: inner padding */ + unsigned char opad[64]; /*!< HMAC: outer padding */ +} +md4_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief MD4 context setup + * + * \param ctx context to be initialized + */ +void md4_starts( md4_context *ctx ); + +/** + * \brief MD4 process buffer + * + * \param ctx MD4 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void md4_update( md4_context *ctx, const unsigned char *input, size_t ilen ); + +/** + * \brief MD4 final digest + * + * \param ctx MD4 context + * \param output MD4 checksum result + */ +void md4_finish( md4_context *ctx, unsigned char output[16] ); + +/** + * \brief Output = MD4( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output MD4 checksum result + */ +void md4( const unsigned char *input, size_t ilen, unsigned char output[16] ); + +/** + * \brief Output = MD4( file contents ) + * + * \param path input file name + * \param output MD4 checksum result + * + * \return 0 if successful, or POLARSSL_ERR_MD4_FILE_IO_ERROR + */ +int md4_file( const char *path, unsigned char output[16] ); + +/** + * \brief MD4 HMAC context setup + * + * \param ctx HMAC context to be initialized + * \param key HMAC secret key + * \param keylen length of the HMAC key + */ +void md4_hmac_starts( md4_context *ctx, const unsigned char *key, size_t keylen ); + +/** + * \brief MD4 HMAC process buffer + * + * \param ctx HMAC context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void md4_hmac_update( md4_context *ctx, const unsigned char *input, size_t ilen ); + +/** + * \brief MD4 HMAC final digest + * + * \param ctx HMAC context + * \param output MD4 HMAC checksum result + */ +void md4_hmac_finish( md4_context *ctx, unsigned char output[16] ); + +/** + * \brief MD4 HMAC context reset + * + * \param ctx HMAC context to be reset + */ +void md4_hmac_reset( md4_context *ctx ); + +/** + * \brief Output = HMAC-MD4( hmac key, input buffer ) + * + * \param key HMAC secret key + * \param keylen length of the HMAC key + * \param input buffer holding the data + * \param ilen length of the input data + * \param output HMAC-MD4 result + */ +void md4_hmac( const unsigned char *key, size_t keylen, + const unsigned char *input, size_t ilen, + unsigned char output[16] ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int md4_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* md4.h */ diff --git a/include/polarssl/md5.h b/include/polarssl/md5.h new file mode 100644 index 000000000..936e9c958 --- /dev/null +++ b/include/polarssl/md5.h @@ -0,0 +1,154 @@ +/** + * \file md5.h + * + * \brief MD5 message digest algorithm (hash function) + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_MD5_H +#define POLARSSL_MD5_H + +#include + +#define POLARSSL_ERR_MD5_FILE_IO_ERROR -0x0074 /**< Read/write error in file. */ + +/** + * \brief MD5 context structure + */ +typedef struct +{ + unsigned long total[2]; /*!< number of bytes processed */ + unsigned long state[4]; /*!< intermediate digest state */ + unsigned char buffer[64]; /*!< data block being processed */ + + unsigned char ipad[64]; /*!< HMAC: inner padding */ + unsigned char opad[64]; /*!< HMAC: outer padding */ +} +md5_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief MD5 context setup + * + * \param ctx context to be initialized + */ +void md5_starts( md5_context *ctx ); + +/** + * \brief MD5 process buffer + * + * \param ctx MD5 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void md5_update( md5_context *ctx, const unsigned char *input, size_t ilen ); + +/** + * \brief MD5 final digest + * + * \param ctx MD5 context + * \param output MD5 checksum result + */ +void md5_finish( md5_context *ctx, unsigned char output[16] ); + +/** + * \brief Output = MD5( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output MD5 checksum result + */ +void md5( const unsigned char *input, size_t ilen, unsigned char output[16] ); + +/** + * \brief Output = MD5( file contents ) + * + * \param path input file name + * \param output MD5 checksum result + * + * \return 0 if successful, or POLARSSL_ERR_MD5_FILE_IO_ERROR + */ +int md5_file( const char *path, unsigned char output[16] ); + +/** + * \brief MD5 HMAC context setup + * + * \param ctx HMAC context to be initialized + * \param key HMAC secret key + * \param keylen length of the HMAC key + */ +void md5_hmac_starts( md5_context *ctx, + const unsigned char *key, size_t keylen ); + +/** + * \brief MD5 HMAC process buffer + * + * \param ctx HMAC context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void md5_hmac_update( md5_context *ctx, + const unsigned char *input, size_t ilen ); + +/** + * \brief MD5 HMAC final digest + * + * \param ctx HMAC context + * \param output MD5 HMAC checksum result + */ +void md5_hmac_finish( md5_context *ctx, unsigned char output[16] ); + +/** + * \brief MD5 HMAC context reset + * + * \param ctx HMAC context to be reset + */ +void md5_hmac_reset( md5_context *ctx ); + +/** + * \brief Output = HMAC-MD5( hmac key, input buffer ) + * + * \param key HMAC secret key + * \param keylen length of the HMAC key + * \param input buffer holding the data + * \param ilen length of the input data + * \param output HMAC-MD5 result + */ +void md5_hmac( const unsigned char *key, size_t keylen, + const unsigned char *input, size_t ilen, + unsigned char output[16] ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int md5_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* md5.h */ diff --git a/include/polarssl/md_wrap.h b/include/polarssl/md_wrap.h new file mode 100644 index 000000000..46849d033 --- /dev/null +++ b/include/polarssl/md_wrap.h @@ -0,0 +1,64 @@ +/** + * \file md_wrap.h + * + * \brief Message digest wrappers. + * + * \author Adriaan de Jong + * + * Copyright (C) 2006-2011, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_MD_WRAP_H +#define POLARSSL_MD_WRAP_H + +#include "config.h" +#include "md.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(POLARSSL_MD2_C) +extern const md_info_t md2_info; +#endif +#if defined(POLARSSL_MD4_C) +extern const md_info_t md4_info; +#endif +#if defined(POLARSSL_MD5_C) +extern const md_info_t md5_info; +#endif +#if defined(POLARSSL_SHA1_C) +extern const md_info_t sha1_info; +#endif +#if defined(POLARSSL_SHA2_C) +extern const md_info_t sha224_info; +extern const md_info_t sha256_info; +#endif +#if defined(POLARSSL_SHA4_C) +extern const md_info_t sha384_info; +extern const md_info_t sha512_info; +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* POLARSSL_MD_WRAP_H */ diff --git a/include/polarssl/net.h b/include/polarssl/net.h new file mode 100644 index 000000000..89e3a00bb --- /dev/null +++ b/include/polarssl/net.h @@ -0,0 +1,159 @@ +/** + * \file net.h + * + * \brief Network communication functions + * + * Copyright (C) 2006-2011, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_NET_H +#define POLARSSL_NET_H + +#include + +#define POLARSSL_ERR_NET_UNKNOWN_HOST -0x0040 /**< Failed to get an IP address for the given hostname. */ +#define POLARSSL_ERR_NET_SOCKET_FAILED -0x0042 /**< Failed to open a socket. */ +#define POLARSSL_ERR_NET_CONNECT_FAILED -0x0044 /**< The connection to the given server / port failed. */ +#define POLARSSL_ERR_NET_BIND_FAILED -0x0046 /**< Binding of the socket failed. */ +#define POLARSSL_ERR_NET_LISTEN_FAILED -0x0048 /**< Could not listen on the socket. */ +#define POLARSSL_ERR_NET_ACCEPT_FAILED -0x004A /**< Could not accept the incoming connection. */ +#define POLARSSL_ERR_NET_RECV_FAILED -0x004C /**< Reading information from the socket failed. */ +#define POLARSSL_ERR_NET_SEND_FAILED -0x004E /**< Sending information through the socket failed. */ +#define POLARSSL_ERR_NET_CONN_RESET -0x0050 /**< Connection was reset by peer. */ +#define POLARSSL_ERR_NET_WANT_READ -0x0052 /**< Connection requires a read call. */ +#define POLARSSL_ERR_NET_WANT_WRITE -0x0054 /**< Connection requires a write call. */ + +#define POLARSSL_NET_LISTEN_BACKLOG 10 /**< The backlog that listen() should use. */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Initiate a TCP connection with host:port + * + * \param fd Socket to use + * \param host Host to connect to + * \param port Port to connect to + * + * \return 0 if successful, or one of: + * POLARSSL_ERR_NET_SOCKET_FAILED, + * POLARSSL_ERR_NET_UNKNOWN_HOST, + * POLARSSL_ERR_NET_CONNECT_FAILED + */ +int net_connect( int *fd, const char *host, int port ); + +/** + * \brief Create a listening socket on bind_ip:port. + * If bind_ip == NULL, all interfaces are binded. + * + * \param fd Socket to use + * \param bind_ip IP to bind to, can be NULL + * \param port Port number to use + * + * \return 0 if successful, or one of: + * POLARSSL_ERR_NET_SOCKET_FAILED, + * POLARSSL_ERR_NET_BIND_FAILED, + * POLARSSL_ERR_NET_LISTEN_FAILED + */ +int net_bind( int *fd, const char *bind_ip, int port ); + +/** + * \brief Accept a connection from a remote client + * + * \param bind_fd Relevant socket + * \param client_fd Will contain the connected client socket + * \param client_ip Will contain the client IP address + * + * \return 0 if successful, POLARSSL_ERR_NET_ACCEPT_FAILED, or + * POLARSSL_ERR_NET_WOULD_BLOCK is bind_fd was set to + * non-blocking and accept() is blocking. + */ +int net_accept( int bind_fd, int *client_fd, void *client_ip ); + +/** + * \brief Set the socket blocking + * + * \param fd Socket to set + * + * \return 0 if successful, or a non-zero error code + */ +int net_set_block( int fd ); + +/** + * \brief Set the socket non-blocking + * + * \param fd Socket to set + * + * \return 0 if successful, or a non-zero error code + */ +int net_set_nonblock( int fd ); + +/** + * \brief Portable usleep helper + * + * \param usec Amount of microseconds to sleep + * + * \note Real amount of time slept will not be less than + * select()'s timeout granularity (typically, 10ms). + */ +void net_usleep( unsigned long usec ); + +/** + * \brief Read at most 'len' characters. If no error occurs, + * the actual amount read is returned. + * + * \param ctx Socket + * \param buf The buffer to write to + * \param len Maximum length of the buffer + * + * \return This function returns the number of bytes received, + * or a non-zero error code; POLARSSL_ERR_NET_WANT_READ + * indicates read() is blocking. + */ +int net_recv( void *ctx, unsigned char *buf, size_t len ); + +/** + * \brief Write at most 'len' characters. If no error occurs, + * the actual amount read is returned. + * + * \param ctx Socket + * \param buf The buffer to read from + * \param len The length of the buffer + * + * \return This function returns the number of bytes sent, + * or a non-zero error code; POLARSSL_ERR_NET_WANT_WRITE + * indicates write() is blocking. + */ +int net_send( void *ctx, const unsigned char *buf, size_t len ); + +/** + * \brief Gracefully shutdown the connection + * + * \param fd The socket to close + */ +void net_close( int fd ); + +#ifdef __cplusplus +} +#endif + +#endif /* net.h */ diff --git a/include/polarssl/openssl.h b/include/polarssl/openssl.h new file mode 100644 index 000000000..62609a297 --- /dev/null +++ b/include/polarssl/openssl.h @@ -0,0 +1,136 @@ +/** + * \file openssl.h + * + * \brief OpenSSL wrapper (definitions, inline functions). + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/* + * OpenSSL wrapper contributed by David Barett + */ +#ifndef POLARSSL_OPENSSL_H +#define POLARSSL_OPENSSL_H + +#include "aes.h" +#include "md5.h" +#include "rsa.h" +#include "sha1.h" + +#define AES_SIZE 16 +#define AES_BLOCK_SIZE 16 +#define AES_KEY aes_context +#define MD5_CTX md5_context +#define SHA_CTX sha1_context + +#define SHA1_Init( CTX ) \ + sha1_starts( (CTX) ) +#define SHA1_Update( CTX, BUF, LEN ) \ + sha1_update( (CTX), (unsigned char *)(BUF), (LEN) ) +#define SHA1_Final( OUT, CTX ) \ + sha1_finish( (CTX), (OUT) ) + +#define MD5_Init( CTX ) \ + md5_starts( (CTX) ) +#define MD5_Update( CTX, BUF, LEN ) \ + md5_update( (CTX), (unsigned char *)(BUF), (LEN) ) +#define MD5_Final( OUT, CTX ) \ + md5_finish( (CTX), (OUT) ) + +#define AES_set_encrypt_key( KEY, KEYSIZE, CTX ) \ + aes_setkey_enc( (CTX), (KEY), (KEYSIZE) ) +#define AES_set_decrypt_key( KEY, KEYSIZE, CTX ) \ + aes_setkey_dec( (CTX), (KEY), (KEYSIZE) ) +#define AES_cbc_encrypt( INPUT, OUTPUT, LEN, CTX, IV, MODE ) \ + aes_crypt_cbc( (CTX), (MODE), (LEN), (IV), (INPUT), (OUTPUT) ) + +/* + * RSA stuff follows. TODO: needs cleanup + */ +inline int __RSA_Passthrough( void *output, void *input, int size ) +{ + memcpy( output, input, size ); + return size; +} + +inline rsa_context* d2i_RSA_PUBKEY( void *ignore, unsigned char **bufptr, + int len ) +{ + unsigned char *buffer = *(unsigned char **) bufptr; + rsa_context *rsa; + + /* + * Not a general-purpose parser: only parses public key from *exactly* + * openssl genrsa -out privkey.pem 512 (or 1024) + * openssl rsa -in privkey.pem -out privatekey.der -outform der + * openssl rsa -in privkey.pem -out pubkey.der -outform der -pubout + * + * TODO: make a general-purpose parse + */ + if( ignore != 0 || ( len != 94 && len != 162 ) ) + return( 0 ); + + rsa = (rsa_context *) malloc( sizeof( rsa_rsa ) ); + if( rsa == NULL ) + return( 0 ); + + memset( rsa, 0, sizeof( rsa_context ) ); + + if( ( len == 94 && + mpi_read_binary( &rsa->N, &buffer[ 25], 64 ) == 0 && + mpi_read_binary( &rsa->E, &buffer[ 91], 3 ) == 0 ) || + ( len == 162 && + mpi_read_binary( &rsa->N, &buffer[ 29], 128 ) == 0 ) && + mpi_read_binary( &rsa->E, &buffer[159], 3 ) == 0 ) + { + /* + * key read successfully + */ + rsa->len = ( mpi_msb( &rsa->N ) + 7 ) >> 3; + return( rsa ); + } + else + { + memset( rsa, 0, sizeof( rsa_context ) ); + free( rsa ); + return( 0 ); + } +} + +#define RSA rsa_context +#define RSA_PKCS1_PADDING 1 /* ignored; always encrypt with this */ +#define RSA_size( CTX ) (CTX)->len +#define RSA_free( CTX ) rsa_free( CTX ) +#define ERR_get_error( ) "ERR_get_error() not supported" +#define RSA_blinding_off( IGNORE ) + +#define d2i_RSAPrivateKey( a, b, c ) new rsa_context /* TODO: C++ bleh */ + +inline int RSA_public_decrypt ( int size, unsigned char* input, unsigned char* output, RSA* key, int ignore ) { int outsize=size; if( !rsa_pkcs1_decrypt( key, RSA_PUBLIC, &outsize, input, output ) ) return outsize; else return -1; } +inline int RSA_private_decrypt( int size, unsigned char* input, unsigned char* output, RSA* key, int ignore ) { int outsize=size; if( !rsa_pkcs1_decrypt( key, RSA_PRIVATE, &outsize, input, output ) ) return outsize; else return -1; } +inline int RSA_public_encrypt ( int size, unsigned char* input, unsigned char* output, RSA* key, int ignore ) { if( !rsa_pkcs1_encrypt( key, RSA_PUBLIC, size, input, output ) ) return RSA_size(key); else return -1; } +inline int RSA_private_encrypt( int size, unsigned char* input, unsigned char* output, RSA* key, int ignore ) { if( !rsa_pkcs1_encrypt( key, RSA_PRIVATE, size, input, output ) ) return RSA_size(key); else return -1; } + +#ifdef __cplusplus +} +#endif + +#endif /* openssl.h */ diff --git a/include/polarssl/padlock.h b/include/polarssl/padlock.h new file mode 100644 index 000000000..ce1357077 --- /dev/null +++ b/include/polarssl/padlock.h @@ -0,0 +1,100 @@ +/** + * \file padlock.h + * + * \brief VIA PadLock ACE for HW encryption/decryption supported by some processors + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_PADLOCK_H +#define POLARSSL_PADLOCK_H + +#include "aes.h" + +#define POLARSSL_ERR_PADLOCK_DATA_MISALIGNED -0x0030 /**< Input data should be aligned. */ + +#if defined(POLARSSL_HAVE_ASM) && defined(__GNUC__) && defined(__i386__) + +#ifndef POLARSSL_HAVE_X86 +#define POLARSSL_HAVE_X86 +#endif + +#define PADLOCK_RNG 0x000C +#define PADLOCK_ACE 0x00C0 +#define PADLOCK_PHE 0x0C00 +#define PADLOCK_PMM 0x3000 + +#define PADLOCK_ALIGN16(x) (unsigned long *) (16 + ((long) x & ~15)) + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief PadLock detection routine + * + * \param The feature to detect + * + * \return 1 if CPU has support for the feature, 0 otherwise + */ +int padlock_supports( int feature ); + +/** + * \brief PadLock AES-ECB block en(de)cryption + * + * \param ctx AES context + * \param mode AES_ENCRYPT or AES_DECRYPT + * \param input 16-byte input block + * \param output 16-byte output block + * + * \return 0 if success, 1 if operation failed + */ +int padlock_xcryptecb( aes_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16] ); + +/** + * \brief PadLock AES-CBC buffer en(de)cryption + * + * \param ctx AES context + * \param mode AES_ENCRYPT or AES_DECRYPT + * \param length length of the input data + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + * + * \return 0 if success, 1 if operation failed + */ +int padlock_xcryptcbc( aes_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ); + +#ifdef __cplusplus +} +#endif + +#endif /* HAVE_X86 */ + +#endif /* padlock.h */ diff --git a/include/polarssl/pem.h b/include/polarssl/pem.h new file mode 100644 index 000000000..1505401c7 --- /dev/null +++ b/include/polarssl/pem.h @@ -0,0 +1,100 @@ +/** + * \file pem.h + * + * \brief Privacy Enhanced Mail (PEM) decoding + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_PEM_H +#define POLARSSL_PEM_H + +#include + +/** + * \name PEM Error codes + * These error codes are returned in case of errors reading the + * PEM data. + * \{ + */ +#define POLARSSL_ERR_PEM_NO_HEADER_PRESENT -0x1080 /**< No PEM header found. */ +#define POLARSSL_ERR_PEM_INVALID_DATA -0x1100 /**< PEM string is not as expected. */ +#define POLARSSL_ERR_PEM_MALLOC_FAILED -0x1180 /**< Failed to allocate memory. */ +#define POLARSSL_ERR_PEM_INVALID_ENC_IV -0x1200 /**< RSA IV is not in hex-format. */ +#define POLARSSL_ERR_PEM_UNKNOWN_ENC_ALG -0x1280 /**< Unsupported key encryption algorithm. */ +#define POLARSSL_ERR_PEM_PASSWORD_REQUIRED -0x1300 /**< Private key password can't be empty. */ +#define POLARSSL_ERR_PEM_PASSWORD_MISMATCH -0x1380 /**< Given private key password does not allow for correct decryption. */ +#define POLARSSL_ERR_PEM_FEATURE_UNAVAILABLE -0x1400 /**< Unavailable feature, e.g. hashing/encryption combination. */ +/* \} name */ + +/** + * \brief PEM context structure + */ +typedef struct +{ + unsigned char *buf; /*!< buffer for decoded data */ + size_t buflen; /*!< length of the buffer */ + unsigned char *info; /*!< buffer for extra header information */ +} +pem_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief PEM context setup + * + * \param ctx context to be initialized + */ +void pem_init( pem_context *ctx ); + +/** + * \brief Read a buffer for PEM information and store the resulting + * data into the specified context buffers. + * + * \param ctx context to use + * \param header header string to seek and expect + * \param footer footer string to seek and expect + * \param data source data to look in + * \param pwd password for decryption (can be NULL) + * \param pwdlen length of password + * \param use_len destination for total length used + * + * \return 0 on success, ior a specific PEM error code + */ +int pem_read_buffer( pem_context *ctx, char *header, char *footer, + const unsigned char *data, + const unsigned char *pwd, + size_t pwdlen, size_t *use_len ); + +/** + * \brief PEM context memory freeing + * + * \param ctx context to be freed + */ +void pem_free( pem_context *ctx ); + +#ifdef __cplusplus +} +#endif + +#endif /* pem.h */ diff --git a/include/polarssl/pkcs11.h b/include/polarssl/pkcs11.h new file mode 100644 index 000000000..a65a72e81 --- /dev/null +++ b/include/polarssl/pkcs11.h @@ -0,0 +1,126 @@ +/** + * \file pkcs11.h + * + * \brief Wrapper for PKCS#11 library libpkcs11-helper + * + * \author Adriaan de Jong + * + * Copyright (C) 2006-2011, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_PKCS11_H +#define POLARSSL_PKCS11_H + +#include "config.h" + +#if defined(POLARSSL_PKCS11_C) + +#include "x509.h" + +#include + +/** + * Context for PKCS #11 private keys. + */ +typedef struct { + pkcs11h_certificate_t pkcs11h_cert; + int len; +} pkcs11_context; + +/** + * Fill in a PolarSSL certificate, based on the given PKCS11 helper certificate. + * + * \param cert X.509 certificate to fill + * \param pkcs11h_cert PKCS #11 helper certificate + * + * \return 0 on success. + */ +int pkcs11_x509_cert_init( x509_cert *cert, pkcs11h_certificate_t pkcs11h_cert ); + +/** + * Initialise a pkcs11_context, storing the given certificate. Note that the + * pkcs11_context will take over control of the certificate, freeing it when + * done. + * + * \param priv_key Private key structure to fill. + * \param pkcs11_cert PKCS #11 helper certificate + * + * \return 0 on success + */ +int pkcs11_priv_key_init( pkcs11_context *priv_key, + pkcs11h_certificate_t pkcs11_cert ); + +/** + * Free the contents of the given private key context. Note that the structure + * itself is not freed. + * + * \param priv_key Private key structure to cleanup + */ +void pkcs11_priv_key_free( pkcs11_context *priv_key ); + +/** + * \brief Do an RSA private key decrypt, then remove the message padding + * + * \param ctx PKCS #11 context + * \param mode must be RSA_PRIVATE, for compatibility with rsa.c's signature + * \param input buffer holding the encrypted data + * \param output buffer that will hold the plaintext + * \param olen will contain the plaintext length + * \param output_max_len maximum length of the output buffer + * + * \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code + * + * \note The output buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used) otherwise + * an error is thrown. + */ +int pkcs11_decrypt( pkcs11_context *ctx, + int mode, size_t *olen, + const unsigned char *input, + unsigned char *output, + unsigned int output_max_len ); + +/** + * \brief Do a private RSA to sign a message digest + * + * \param ctx PKCS #11 context + * \param mode must be RSA_PRIVATE, for compatibility with rsa.c's signature + * \param hash_id SIG_RSA_RAW, SIG_RSA_MD{2,4,5} or SIG_RSA_SHA{1,224,256,384,512} + * \param hashlen message digest length (for SIG_RSA_RAW only) + * \param hash buffer holding the message digest + * \param sig buffer that will hold the ciphertext + * + * \return 0 if the signing operation was successful, + * or an POLARSSL_ERR_RSA_XXX error code + * + * \note The "sig" buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used). + */ +int pkcs11_sign( pkcs11_context *ctx, + int mode, + int hash_id, + unsigned int hashlen, + const unsigned char *hash, + unsigned char *sig ); + +#endif /* POLARSSL_PKCS11_C */ + +#endif /* POLARSSL_PKCS11_H */ diff --git a/include/polarssl/rsa.h b/include/polarssl/rsa.h new file mode 100644 index 000000000..629aa0fab --- /dev/null +++ b/include/polarssl/rsa.h @@ -0,0 +1,372 @@ +/** + * \file rsa.h + * + * \brief The RSA public-key cryptosystem + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_RSA_H +#define POLARSSL_RSA_H + +#include "bignum.h" + +/* + * RSA Error codes + */ +#define POLARSSL_ERR_RSA_BAD_INPUT_DATA -0x4080 /**< Bad input parameters to function. */ +#define POLARSSL_ERR_RSA_INVALID_PADDING -0x4100 /**< Input data contains invalid padding and is rejected. */ +#define POLARSSL_ERR_RSA_KEY_GEN_FAILED -0x4180 /**< Something failed during generation of a key. */ +#define POLARSSL_ERR_RSA_KEY_CHECK_FAILED -0x4200 /**< Key failed to pass the libraries validity check. */ +#define POLARSSL_ERR_RSA_PUBLIC_FAILED -0x4280 /**< The public key operation failed. */ +#define POLARSSL_ERR_RSA_PRIVATE_FAILED -0x4300 /**< The private key operation failed. */ +#define POLARSSL_ERR_RSA_VERIFY_FAILED -0x4380 /**< The PKCS#1 verification failed. */ +#define POLARSSL_ERR_RSA_OUTPUT_TOO_LARGE -0x4400 /**< The output buffer for decryption is not large enough. */ +#define POLARSSL_ERR_RSA_RNG_FAILED -0x4480 /**< The random generator failed to generate non-zeros. */ + +/* + * PKCS#1 constants + */ +#define SIG_RSA_RAW 0 +#define SIG_RSA_MD2 2 +#define SIG_RSA_MD4 3 +#define SIG_RSA_MD5 4 +#define SIG_RSA_SHA1 5 +#define SIG_RSA_SHA224 14 +#define SIG_RSA_SHA256 11 +#define SIG_RSA_SHA384 12 +#define SIG_RSA_SHA512 13 + +#define RSA_PUBLIC 0 +#define RSA_PRIVATE 1 + +#define RSA_PKCS_V15 0 +#define RSA_PKCS_V21 1 + +#define RSA_SIGN 1 +#define RSA_CRYPT 2 + +#define ASN1_STR_CONSTRUCTED_SEQUENCE "\x30" +#define ASN1_STR_NULL "\x05" +#define ASN1_STR_OID "\x06" +#define ASN1_STR_OCTET_STRING "\x04" + +#define OID_DIGEST_ALG_MDX "\x2A\x86\x48\x86\xF7\x0D\x02\x00" +#define OID_HASH_ALG_SHA1 "\x2b\x0e\x03\x02\x1a" +#define OID_HASH_ALG_SHA2X "\x60\x86\x48\x01\x65\x03\x04\x02\x00" + +#define OID_ISO_MEMBER_BODIES "\x2a" +#define OID_ISO_IDENTIFIED_ORG "\x2b" + +/* + * ISO Member bodies OID parts + */ +#define OID_COUNTRY_US "\x86\x48" +#define OID_RSA_DATA_SECURITY "\x86\xf7\x0d" + +/* + * ISO Identified organization OID parts + */ +#define OID_OIW_SECSIG_SHA1 "\x0e\x03\x02\x1a" + +/* + * DigestInfo ::= SEQUENCE { + * digestAlgorithm DigestAlgorithmIdentifier, + * digest Digest } + * + * DigestAlgorithmIdentifier ::= AlgorithmIdentifier + * + * Digest ::= OCTET STRING + */ +#define ASN1_HASH_MDX \ +( \ + ASN1_STR_CONSTRUCTED_SEQUENCE "\x20" \ + ASN1_STR_CONSTRUCTED_SEQUENCE "\x0C" \ + ASN1_STR_OID "\x08" \ + OID_DIGEST_ALG_MDX \ + ASN1_STR_NULL "\x00" \ + ASN1_STR_OCTET_STRING "\x10" \ +) + +#define ASN1_HASH_SHA1 \ + ASN1_STR_CONSTRUCTED_SEQUENCE "\x21" \ + ASN1_STR_CONSTRUCTED_SEQUENCE "\x09" \ + ASN1_STR_OID "\x05" \ + OID_HASH_ALG_SHA1 \ + ASN1_STR_NULL "\x00" \ + ASN1_STR_OCTET_STRING "\x14" + +#define ASN1_HASH_SHA2X \ + ASN1_STR_CONSTRUCTED_SEQUENCE "\x11" \ + ASN1_STR_CONSTRUCTED_SEQUENCE "\x0d" \ + ASN1_STR_OID "\x09" \ + OID_HASH_ALG_SHA2X \ + ASN1_STR_NULL "\x00" \ + ASN1_STR_OCTET_STRING "\x00" + +/** + * \brief RSA context structure + */ +typedef struct +{ + int ver; /*!< always 0 */ + size_t len; /*!< size(N) in chars */ + + mpi N; /*!< public modulus */ + mpi E; /*!< public exponent */ + + mpi D; /*!< private exponent */ + mpi P; /*!< 1st prime factor */ + mpi Q; /*!< 2nd prime factor */ + mpi DP; /*!< D % (P - 1) */ + mpi DQ; /*!< D % (Q - 1) */ + mpi QP; /*!< 1 / (Q % P) */ + + mpi RN; /*!< cached R^2 mod N */ + mpi RP; /*!< cached R^2 mod P */ + mpi RQ; /*!< cached R^2 mod Q */ + + int padding; /*!< RSA_PKCS_V15 for 1.5 padding and + RSA_PKCS_v21 for OAEP/PSS */ + int hash_id; /*!< Hash identifier of md_type_t as + specified in the md.h header file + for the EME-OAEP and EMSA-PSS + encoding */ +} +rsa_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Initialize an RSA context + * + * \param ctx RSA context to be initialized + * \param padding RSA_PKCS_V15 or RSA_PKCS_V21 + * \param hash_id RSA_PKCS_V21 hash identifier + * + * \note The hash_id parameter is actually ignored + * when using RSA_PKCS_V15 padding. + */ +void rsa_init( rsa_context *ctx, + int padding, + int hash_id); + +/** + * \brief Generate an RSA keypair + * + * \param ctx RSA context that will hold the key + * \param f_rng RNG function + * \param p_rng RNG parameter + * \param nbits size of the public key in bits + * \param exponent public exponent (e.g., 65537) + * + * \note rsa_init() must be called beforehand to setup + * the RSA context. + * + * \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code + */ +int rsa_gen_key( rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + unsigned int nbits, int exponent ); + +/** + * \brief Check a public RSA key + * + * \param ctx RSA context to be checked + * + * \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code + */ +int rsa_check_pubkey( const rsa_context *ctx ); + +/** + * \brief Check a private RSA key + * + * \param ctx RSA context to be checked + * + * \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code + */ +int rsa_check_privkey( const rsa_context *ctx ); + +/** + * \brief Do an RSA public key operation + * + * \param ctx RSA context + * \param input input buffer + * \param output output buffer + * + * \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code + * + * \note This function does NOT take care of message + * padding. Also, be sure to set input[0] = 0 or assure that + * input is smaller than N. + * + * \note The input and output buffers must be large + * enough (eg. 128 bytes if RSA-1024 is used). + */ +int rsa_public( rsa_context *ctx, + const unsigned char *input, + unsigned char *output ); + +/** + * \brief Do an RSA private key operation + * + * \param ctx RSA context + * \param input input buffer + * \param output output buffer + * + * \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code + * + * \note The input and output buffers must be large + * enough (eg. 128 bytes if RSA-1024 is used). + */ +int rsa_private( rsa_context *ctx, + const unsigned char *input, + unsigned char *output ); + +/** + * \brief Add the message padding, then do an RSA operation + * + * \param ctx RSA context + * \param f_rng RNG function (Needed for padding and PKCS#1 v2.1 encoding) + * \param p_rng RNG parameter + * \param mode RSA_PUBLIC or RSA_PRIVATE + * \param ilen contains the plaintext length + * \param input buffer holding the data to be encrypted + * \param output buffer that will hold the ciphertext + * + * \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code + * + * \note The output buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used). + */ +int rsa_pkcs1_encrypt( rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, size_t ilen, + const unsigned char *input, + unsigned char *output ); + +/** + * \brief Do an RSA operation, then remove the message padding + * + * \param ctx RSA context + * \param mode RSA_PUBLIC or RSA_PRIVATE + * \param olen will contain the plaintext length + * \param input buffer holding the encrypted data + * \param output buffer that will hold the plaintext + * \param output_max_len maximum length of the output buffer + * + * \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code + * + * \note The output buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used) otherwise + * an error is thrown. + */ +int rsa_pkcs1_decrypt( rsa_context *ctx, + int mode, size_t *olen, + const unsigned char *input, + unsigned char *output, + size_t output_max_len ); + +/** + * \brief Do a private RSA to sign a message digest + * + * \param ctx RSA context + * \param f_rng RNG function (Needed for PKCS#1 v2.1 encoding) + * \param p_rng RNG parameter + * \param mode RSA_PUBLIC or RSA_PRIVATE + * \param hash_id SIG_RSA_RAW, SIG_RSA_MD{2,4,5} or SIG_RSA_SHA{1,224,256,384,512} + * \param hashlen message digest length (for SIG_RSA_RAW only) + * \param hash buffer holding the message digest + * \param sig buffer that will hold the ciphertext + * + * \return 0 if the signing operation was successful, + * or an POLARSSL_ERR_RSA_XXX error code + * + * \note The "sig" buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used). + * + * \note In case of PKCS#1 v2.1 encoding keep in mind that + * the hash_id in the RSA context is the one used for the + * encoding. hash_id in the function call is the type of hash + * that is encoded. According to RFC 3447 it is advised to + * keep both hashes the same. + */ +int rsa_pkcs1_sign( rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + int hash_id, + unsigned int hashlen, + const unsigned char *hash, + unsigned char *sig ); + +/** + * \brief Do a public RSA and check the message digest + * + * \param ctx points to an RSA public key + * \param mode RSA_PUBLIC or RSA_PRIVATE + * \param hash_id SIG_RSA_RAW, SIG_RSA_MD{2,4,5} or SIG_RSA_SHA{1,224,256,384,512} + * \param hashlen message digest length (for SIG_RSA_RAW only) + * \param hash buffer holding the message digest + * \param sig buffer holding the ciphertext + * + * \return 0 if the verify operation was successful, + * or an POLARSSL_ERR_RSA_XXX error code + * + * \note The "sig" buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used). + * + * \note In case of PKCS#1 v2.1 encoding keep in mind that + * the hash_id in the RSA context is the one used for the + * verification. hash_id in the function call is the type of hash + * that is verified. According to RFC 3447 it is advised to + * keep both hashes the same. + */ +int rsa_pkcs1_verify( rsa_context *ctx, + int mode, + int hash_id, + unsigned int hashlen, + const unsigned char *hash, + unsigned char *sig ); + +/** + * \brief Free the components of an RSA key + * + * \param ctx RSA Context to free + */ +void rsa_free( rsa_context *ctx ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int rsa_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* rsa.h */ diff --git a/include/polarssl/sha1.h b/include/polarssl/sha1.h new file mode 100644 index 000000000..0d5e67eb2 --- /dev/null +++ b/include/polarssl/sha1.h @@ -0,0 +1,152 @@ +/** + * \file sha1.h + * + * \brief SHA-1 cryptographic hash function + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_SHA1_H +#define POLARSSL_SHA1_H + +#include + +#define POLARSSL_ERR_SHA1_FILE_IO_ERROR -0x0076 /**< Read/write error in file. */ + +/** + * \brief SHA-1 context structure + */ +typedef struct +{ + unsigned long total[2]; /*!< number of bytes processed */ + unsigned long state[5]; /*!< intermediate digest state */ + unsigned char buffer[64]; /*!< data block being processed */ + + unsigned char ipad[64]; /*!< HMAC: inner padding */ + unsigned char opad[64]; /*!< HMAC: outer padding */ +} +sha1_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief SHA-1 context setup + * + * \param ctx context to be initialized + */ +void sha1_starts( sha1_context *ctx ); + +/** + * \brief SHA-1 process buffer + * + * \param ctx SHA-1 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void sha1_update( sha1_context *ctx, const unsigned char *input, size_t ilen ); + +/** + * \brief SHA-1 final digest + * + * \param ctx SHA-1 context + * \param output SHA-1 checksum result + */ +void sha1_finish( sha1_context *ctx, unsigned char output[20] ); + +/** + * \brief Output = SHA-1( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output SHA-1 checksum result + */ +void sha1( const unsigned char *input, size_t ilen, unsigned char output[20] ); + +/** + * \brief Output = SHA-1( file contents ) + * + * \param path input file name + * \param output SHA-1 checksum result + * + * \return 0 if successful, or POLARSSL_ERR_SHA1_FILE_IO_ERROR + */ +int sha1_file( const char *path, unsigned char output[20] ); + +/** + * \brief SHA-1 HMAC context setup + * + * \param ctx HMAC context to be initialized + * \param key HMAC secret key + * \param keylen length of the HMAC key + */ +void sha1_hmac_starts( sha1_context *ctx, const unsigned char *key, size_t keylen ); + +/** + * \brief SHA-1 HMAC process buffer + * + * \param ctx HMAC context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void sha1_hmac_update( sha1_context *ctx, const unsigned char *input, size_t ilen ); + +/** + * \brief SHA-1 HMAC final digest + * + * \param ctx HMAC context + * \param output SHA-1 HMAC checksum result + */ +void sha1_hmac_finish( sha1_context *ctx, unsigned char output[20] ); + +/** + * \brief SHA-1 HMAC context reset + * + * \param ctx HMAC context to be reset + */ +void sha1_hmac_reset( sha1_context *ctx ); + +/** + * \brief Output = HMAC-SHA-1( hmac key, input buffer ) + * + * \param key HMAC secret key + * \param keylen length of the HMAC key + * \param input buffer holding the data + * \param ilen length of the input data + * \param output HMAC-SHA-1 result + */ +void sha1_hmac( const unsigned char *key, size_t keylen, + const unsigned char *input, size_t ilen, + unsigned char output[20] ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int sha1_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* sha1.h */ diff --git a/include/polarssl/sha2.h b/include/polarssl/sha2.h new file mode 100644 index 000000000..811b0fd61 --- /dev/null +++ b/include/polarssl/sha2.h @@ -0,0 +1,160 @@ +/** + * \file sha2.h + * + * \brief SHA-224 and SHA-256 cryptographic hash function + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_SHA2_H +#define POLARSSL_SHA2_H + +#include + +#define POLARSSL_ERR_SHA2_FILE_IO_ERROR -0x0078 /**< Read/write error in file. */ + +/** + * \brief SHA-256 context structure + */ +typedef struct +{ + unsigned long total[2]; /*!< number of bytes processed */ + unsigned long state[8]; /*!< intermediate digest state */ + unsigned char buffer[64]; /*!< data block being processed */ + + unsigned char ipad[64]; /*!< HMAC: inner padding */ + unsigned char opad[64]; /*!< HMAC: outer padding */ + int is224; /*!< 0 => SHA-256, else SHA-224 */ +} +sha2_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief SHA-256 context setup + * + * \param ctx context to be initialized + * \param is224 0 = use SHA256, 1 = use SHA224 + */ +void sha2_starts( sha2_context *ctx, int is224 ); + +/** + * \brief SHA-256 process buffer + * + * \param ctx SHA-256 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void sha2_update( sha2_context *ctx, const unsigned char *input, size_t ilen ); + +/** + * \brief SHA-256 final digest + * + * \param ctx SHA-256 context + * \param output SHA-224/256 checksum result + */ +void sha2_finish( sha2_context *ctx, unsigned char output[32] ); + +/** + * \brief Output = SHA-256( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output SHA-224/256 checksum result + * \param is224 0 = use SHA256, 1 = use SHA224 + */ +void sha2( const unsigned char *input, size_t ilen, + unsigned char output[32], int is224 ); + +/** + * \brief Output = SHA-256( file contents ) + * + * \param path input file name + * \param output SHA-224/256 checksum result + * \param is224 0 = use SHA256, 1 = use SHA224 + * + * \return 0 if successful, or POLARSSL_ERR_SHA2_FILE_IO_ERROR + */ +int sha2_file( const char *path, unsigned char output[32], int is224 ); + +/** + * \brief SHA-256 HMAC context setup + * + * \param ctx HMAC context to be initialized + * \param key HMAC secret key + * \param keylen length of the HMAC key + * \param is224 0 = use SHA256, 1 = use SHA224 + */ +void sha2_hmac_starts( sha2_context *ctx, const unsigned char *key, size_t keylen, + int is224 ); + +/** + * \brief SHA-256 HMAC process buffer + * + * \param ctx HMAC context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void sha2_hmac_update( sha2_context *ctx, const unsigned char *input, size_t ilen ); + +/** + * \brief SHA-256 HMAC final digest + * + * \param ctx HMAC context + * \param output SHA-224/256 HMAC checksum result + */ +void sha2_hmac_finish( sha2_context *ctx, unsigned char output[32] ); + +/** + * \brief SHA-256 HMAC context reset + * + * \param ctx HMAC context to be reset + */ +void sha2_hmac_reset( sha2_context *ctx ); + +/** + * \brief Output = HMAC-SHA-256( hmac key, input buffer ) + * + * \param key HMAC secret key + * \param keylen length of the HMAC key + * \param input buffer holding the data + * \param ilen length of the input data + * \param output HMAC-SHA-224/256 result + * \param is224 0 = use SHA256, 1 = use SHA224 + */ +void sha2_hmac( const unsigned char *key, size_t keylen, + const unsigned char *input, size_t ilen, + unsigned char output[32], int is224 ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int sha2_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* sha2.h */ diff --git a/include/polarssl/sha4.h b/include/polarssl/sha4.h new file mode 100644 index 000000000..dafebec22 --- /dev/null +++ b/include/polarssl/sha4.h @@ -0,0 +1,168 @@ +/** + * \file sha4.h + * + * \brief SHA-384 and SHA-512 cryptographic hash function + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_SHA4_H +#define POLARSSL_SHA4_H + +#include + +#define POLARSSL_ERR_SHA4_FILE_IO_ERROR -0x007A /**< Read/write error in file. */ + +#if defined(_MSC_VER) || defined(__WATCOMC__) + #define UL64(x) x##ui64 + #define long64 __int64 +#else + #define UL64(x) x##ULL + #define long64 long long +#endif + +/** + * \brief SHA-512 context structure + */ +typedef struct +{ + unsigned long64 total[2]; /*!< number of bytes processed */ + unsigned long64 state[8]; /*!< intermediate digest state */ + unsigned char buffer[128]; /*!< data block being processed */ + + unsigned char ipad[128]; /*!< HMAC: inner padding */ + unsigned char opad[128]; /*!< HMAC: outer padding */ + int is384; /*!< 0 => SHA-512, else SHA-384 */ +} +sha4_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief SHA-512 context setup + * + * \param ctx context to be initialized + * \param is384 0 = use SHA512, 1 = use SHA384 + */ +void sha4_starts( sha4_context *ctx, int is384 ); + +/** + * \brief SHA-512 process buffer + * + * \param ctx SHA-512 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void sha4_update( sha4_context *ctx, const unsigned char *input, size_t ilen ); + +/** + * \brief SHA-512 final digest + * + * \param ctx SHA-512 context + * \param output SHA-384/512 checksum result + */ +void sha4_finish( sha4_context *ctx, unsigned char output[64] ); + +/** + * \brief Output = SHA-512( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output SHA-384/512 checksum result + * \param is384 0 = use SHA512, 1 = use SHA384 + */ +void sha4( const unsigned char *input, size_t ilen, + unsigned char output[64], int is384 ); + +/** + * \brief Output = SHA-512( file contents ) + * + * \param path input file name + * \param output SHA-384/512 checksum result + * \param is384 0 = use SHA512, 1 = use SHA384 + * + * \return 0 if successful, or POLARSSL_ERR_SHA4_FILE_IO_ERROR + */ +int sha4_file( const char *path, unsigned char output[64], int is384 ); + +/** + * \brief SHA-512 HMAC context setup + * + * \param ctx HMAC context to be initialized + * \param is384 0 = use SHA512, 1 = use SHA384 + * \param key HMAC secret key + * \param keylen length of the HMAC key + */ +void sha4_hmac_starts( sha4_context *ctx, const unsigned char *key, size_t keylen, + int is384 ); + +/** + * \brief SHA-512 HMAC process buffer + * + * \param ctx HMAC context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void sha4_hmac_update( sha4_context *ctx, const unsigned char *input, size_t ilen ); + +/** + * \brief SHA-512 HMAC final digest + * + * \param ctx HMAC context + * \param output SHA-384/512 HMAC checksum result + */ +void sha4_hmac_finish( sha4_context *ctx, unsigned char output[64] ); + +/** + * \brief SHA-512 HMAC context reset + * + * \param ctx HMAC context to be reset + */ +void sha4_hmac_reset( sha4_context *ctx ); + +/** + * \brief Output = HMAC-SHA-512( hmac key, input buffer ) + * + * \param key HMAC secret key + * \param keylen length of the HMAC key + * \param input buffer holding the data + * \param ilen length of the input data + * \param output HMAC-SHA-384/512 result + * \param is384 0 = use SHA512, 1 = use SHA384 + */ +void sha4_hmac( const unsigned char *key, size_t keylen, + const unsigned char *input, size_t ilen, + unsigned char output[64], int is384 ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int sha4_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* sha4.h */ diff --git a/include/polarssl/ssl.h b/include/polarssl/ssl.h new file mode 100644 index 000000000..74c5d2df7 --- /dev/null +++ b/include/polarssl/ssl.h @@ -0,0 +1,703 @@ +/** + * \file ssl.h + * + * \brief SSL/TLS functions. + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_SSL_H +#define POLARSSL_SSL_H + +#include + +#include "net.h" +#include "dhm.h" +#include "rsa.h" +#include "md5.h" +#include "sha1.h" +#include "x509.h" +#include "config.h" + +#if defined(POLARSSL_PKCS11_C) +#include "pkcs11.h" +#endif + +#if defined(_MSC_VER) && !defined(inline) +#define inline _inline +#else +#if defined(__ARMCC_VERSION) && !defined(inline) +#define inline __inline +#endif /* __ARMCC_VERSION */ +#endif /*_MSC_VER */ + +/* + * SSL Error codes + */ +#define POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE -0x7080 /**< The requested feature is not available. */ +#define POLARSSL_ERR_SSL_BAD_INPUT_DATA -0x7100 /**< Bad input parameters to function. */ +#define POLARSSL_ERR_SSL_INVALID_MAC -0x7180 /**< Verification of the message MAC failed. */ +#define POLARSSL_ERR_SSL_INVALID_RECORD -0x7200 /**< An invalid SSL record was received. */ +#define POLARSSL_ERR_SSL_CONN_EOF -0x7280 /**< The connection indicated an EOF. */ +#define POLARSSL_ERR_SSL_UNKNOWN_CIPHER -0x7300 /**< An unknown cipher was received. */ +#define POLARSSL_ERR_SSL_NO_CIPHER_CHOSEN -0x7380 /**< The server has no ciphersuites in common with the client. */ +#define POLARSSL_ERR_SSL_NO_SESSION_FOUND -0x7400 /**< No session to recover was found. */ +#define POLARSSL_ERR_SSL_NO_CLIENT_CERTIFICATE -0x7480 /**< No client certification received from the client, but required by the authentication mode. */ +#define POLARSSL_ERR_SSL_CERTIFICATE_TOO_LARGE -0x7500 /**< Our own certificate(s) is/are too large to send in an SSL message.*/ +#define POLARSSL_ERR_SSL_CERTIFICATE_REQUIRED -0x7580 /**< The own certificate is not set, but needed by the server. */ +#define POLARSSL_ERR_SSL_PRIVATE_KEY_REQUIRED -0x7600 /**< The own private key is not set, but needed. */ +#define POLARSSL_ERR_SSL_CA_CHAIN_REQUIRED -0x7680 /**< No CA Chain is set, but required to operate. */ +#define POLARSSL_ERR_SSL_UNEXPECTED_MESSAGE -0x7700 /**< An unexpected message was received from our peer. */ +#define POLARSSL_ERR_SSL_FATAL_ALERT_MESSAGE -0x7780 /**< A fatal alert message was received from our peer. */ +#define POLARSSL_ERR_SSL_PEER_VERIFY_FAILED -0x7800 /**< Verification of our peer failed. */ +#define POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY -0x7880 /**< The peer notified us that the connection is going to be closed. */ +#define POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO -0x7900 /**< Processing of the ClientHello handshake message failed. */ +#define POLARSSL_ERR_SSL_BAD_HS_SERVER_HELLO -0x7980 /**< Processing of the ServerHello handshake message failed. */ +#define POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE -0x7A00 /**< Processing of the Certificate handshake message failed. */ +#define POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST -0x7A80 /**< Processing of the CertificateRequest handshake message failed. */ +#define POLARSSL_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE -0x7B00 /**< Processing of the ServerKeyExchange handshake message failed. */ +#define POLARSSL_ERR_SSL_BAD_HS_SERVER_HELLO_DONE -0x7B80 /**< Processing of the ServerHelloDone handshake message failed. */ +#define POLARSSL_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE -0x7C00 /**< Processing of the ClientKeyExchange handshake message failed. */ +#define POLARSSL_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_DHM_RP -0x7C80 /**< Processing of the ClientKeyExchange handshake message failed in DHM Read Public. */ +#define POLARSSL_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_DHM_CS -0x7D00 /**< Processing of the ClientKeyExchange handshake message failed in DHM Calculate Secret. */ +#define POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY -0x7D80 /**< Processing of the CertificateVerify handshake message failed. */ +#define POLARSSL_ERR_SSL_BAD_HS_CHANGE_CIPHER_SPEC -0x7E00 /**< Processing of the ChangeCipherSpec handshake message failed. */ +#define POLARSSL_ERR_SSL_BAD_HS_FINISHED -0x7E80 /**< Processing of the Finished handshake message failed. */ +#define POLARSSL_ERR_SSL_MALLOC_FAILED -0x7F00 /**< Memory allocation failed */ + +/* + * Various constants + */ +#define SSL_MAJOR_VERSION_3 3 +#define SSL_MINOR_VERSION_0 0 /*!< SSL v3.0 */ +#define SSL_MINOR_VERSION_1 1 /*!< TLS v1.0 */ +#define SSL_MINOR_VERSION_2 2 /*!< TLS v1.1 */ + +#define SSL_IS_CLIENT 0 +#define SSL_IS_SERVER 1 +#define SSL_COMPRESS_NULL 0 + +#define SSL_VERIFY_NONE 0 +#define SSL_VERIFY_OPTIONAL 1 +#define SSL_VERIFY_REQUIRED 2 + +#define SSL_MAX_CONTENT_LEN 16384 + +/* + * Allow an extra 512 bytes for the record header + * and encryption overhead (counter + MAC + padding). + */ +#define SSL_BUFFER_LEN (SSL_MAX_CONTENT_LEN + 512) + +/* + * Supported ciphersuites + */ +#define SSL_RSA_RC4_128_MD5 0x04 +#define SSL_RSA_RC4_128_SHA 0x05 +#define SSL_RSA_DES_168_SHA 0x0A +#define SSL_EDH_RSA_DES_168_SHA 0x16 +#define SSL_RSA_AES_128_SHA 0x2F +#define SSL_EDH_RSA_AES_128_SHA 0x33 +#define SSL_RSA_AES_256_SHA 0x35 +#define SSL_EDH_RSA_AES_256_SHA 0x39 + +#define SSL_RSA_CAMELLIA_128_SHA 0x41 +#define SSL_EDH_RSA_CAMELLIA_128_SHA 0x45 +#define SSL_RSA_CAMELLIA_256_SHA 0x84 +#define SSL_EDH_RSA_CAMELLIA_256_SHA 0x88 + +/* + * Message, alert and handshake types + */ +#define SSL_MSG_CHANGE_CIPHER_SPEC 20 +#define SSL_MSG_ALERT 21 +#define SSL_MSG_HANDSHAKE 22 +#define SSL_MSG_APPLICATION_DATA 23 + +#define SSL_ALERT_LEVEL_WARNING 1 +#define SSL_ALERT_LEVEL_FATAL 2 + +#define SSL_ALERT_MSG_CLOSE_NOTIFY 0 +#define SSL_ALERT_MSG_UNEXPECTED_MESSAGE 10 +#define SSL_ALERT_MSG_BAD_RECORD_MAC 20 +#define SSL_ALERT_MSG_DECRYPTION_FAILED 21 +#define SSL_ALERT_MSG_RECORD_OVERFLOW 22 +#define SSL_ALERT_MSG_DECOMPRESSION_FAILURE 30 +#define SSL_ALERT_MSG_HANDSHAKE_FAILURE 40 +#define SSL_ALERT_MSG_NO_CERT 41 +#define SSL_ALERT_MSG_BAD_CERT 42 +#define SSL_ALERT_MSG_UNSUPPORTED_CERT 43 +#define SSL_ALERT_MSG_CERT_REVOKED 44 +#define SSL_ALERT_MSG_CERT_EXPIRED 45 +#define SSL_ALERT_MSG_CERT_UNKNOWN 46 +#define SSL_ALERT_MSG_ILLEGAL_PARAMETER 47 +#define SSL_ALERT_MSG_UNKNOWN_CA 48 +#define SSL_ALERT_MSG_ACCESS_DENIED 49 +#define SSL_ALERT_MSG_DECODE_ERROR 50 +#define SSL_ALERT_MSG_DECRYPT_ERROR 51 +#define SSL_ALERT_MSG_EXPORT_RESTRICTION 60 +#define SSL_ALERT_MSG_PROTOCOL_VERSION 70 +#define SSL_ALERT_MSG_INSUFFICIENT_SECURITY 71 +#define SSL_ALERT_MSG_INTERNAL_ERROR 80 +#define SSL_ALERT_MSG_USER_CANCELED 90 +#define SSL_ALERT_MSG_NO_RENEGOTIATION 100 + +#define SSL_HS_HELLO_REQUEST 0 +#define SSL_HS_CLIENT_HELLO 1 +#define SSL_HS_SERVER_HELLO 2 +#define SSL_HS_CERTIFICATE 11 +#define SSL_HS_SERVER_KEY_EXCHANGE 12 +#define SSL_HS_CERTIFICATE_REQUEST 13 +#define SSL_HS_SERVER_HELLO_DONE 14 +#define SSL_HS_CERTIFICATE_VERIFY 15 +#define SSL_HS_CLIENT_KEY_EXCHANGE 16 +#define SSL_HS_FINISHED 20 + +/* + * TLS extensions + */ +#define TLS_EXT_SERVERNAME 0 +#define TLS_EXT_SERVERNAME_HOSTNAME 0 + +/* + * SSL state machine + */ +typedef enum +{ + SSL_HELLO_REQUEST, + SSL_CLIENT_HELLO, + SSL_SERVER_HELLO, + SSL_SERVER_CERTIFICATE, + SSL_SERVER_KEY_EXCHANGE, + SSL_CERTIFICATE_REQUEST, + SSL_SERVER_HELLO_DONE, + SSL_CLIENT_CERTIFICATE, + SSL_CLIENT_KEY_EXCHANGE, + SSL_CERTIFICATE_VERIFY, + SSL_CLIENT_CHANGE_CIPHER_SPEC, + SSL_CLIENT_FINISHED, + SSL_SERVER_CHANGE_CIPHER_SPEC, + SSL_SERVER_FINISHED, + SSL_FLUSH_BUFFERS, + SSL_HANDSHAKE_OVER +} +ssl_states; + +typedef struct _ssl_session ssl_session; +typedef struct _ssl_context ssl_context; + +/* + * This structure is used for session resuming. + */ +struct _ssl_session +{ + time_t start; /*!< starting time */ + int ciphersuite; /*!< chosen ciphersuite */ + size_t length; /*!< session id length */ + unsigned char id[32]; /*!< session identifier */ + unsigned char master[48]; /*!< the master secret */ + ssl_session *next; /*!< next session entry */ +}; + +struct _ssl_context +{ + /* + * Miscellaneous + */ + int state; /*!< SSL handshake: current state */ + + int major_ver; /*!< equal to SSL_MAJOR_VERSION_3 */ + int minor_ver; /*!< either 0 (SSL3) or 1 (TLS1.0) */ + + int max_major_ver; /*!< max. major version from client */ + int max_minor_ver; /*!< max. minor version from client */ + + /* + * Callbacks (RNG, debug, I/O, verification) + */ + int (*f_rng)(void *, unsigned char *, size_t); + void (*f_dbg)(void *, int, const char *); + int (*f_recv)(void *, unsigned char *, size_t); + int (*f_send)(void *, const unsigned char *, size_t); + int (*f_vrfy)(void *, x509_cert *, int, int); + + void *p_rng; /*!< context for the RNG function */ + void *p_dbg; /*!< context for the debug function */ + void *p_recv; /*!< context for reading operations */ + void *p_send; /*!< context for writing operations */ + void *p_vrfy; /*!< context for verification */ + + /* + * Session layer + */ + int resume; /*!< session resuming flag */ + int timeout; /*!< sess. expiration time */ + ssl_session *session; /*!< current session data */ + int (*s_get)(ssl_context *); /*!< (server) get callback */ + int (*s_set)(ssl_context *); /*!< (server) set callback */ + + /* + * Record layer (incoming data) + */ + unsigned char *in_ctr; /*!< 64-bit incoming message counter */ + unsigned char *in_hdr; /*!< 5-byte record header (in_ctr+8) */ + unsigned char *in_msg; /*!< the message contents (in_hdr+5) */ + unsigned char *in_offt; /*!< read offset in application data */ + + int in_msgtype; /*!< record header: message type */ + size_t in_msglen; /*!< record header: message length */ + size_t in_left; /*!< amount of data read so far */ + + size_t in_hslen; /*!< current handshake message length */ + int nb_zero; /*!< # of 0-length encrypted messages */ + + /* + * Record layer (outgoing data) + */ + unsigned char *out_ctr; /*!< 64-bit outgoing message counter */ + unsigned char *out_hdr; /*!< 5-byte record header (out_ctr+8) */ + unsigned char *out_msg; /*!< the message contents (out_hdr+5) */ + + int out_msgtype; /*!< record header: message type */ + size_t out_msglen; /*!< record header: message length */ + size_t out_left; /*!< amount of data not yet written */ + + /* + * PKI layer + */ + rsa_context *rsa_key; /*!< own RSA private key */ +#if defined(POLARSSL_PKCS11_C) + pkcs11_context *pkcs11_key; /*!< own PKCS#11 RSA private key */ +#endif + x509_cert *own_cert; /*!< own X.509 certificate */ + x509_cert *ca_chain; /*!< own trusted CA chain */ + x509_crl *ca_crl; /*!< trusted CA CRLs */ + x509_cert *peer_cert; /*!< peer X.509 cert chain */ + const char *peer_cn; /*!< expected peer CN */ + + int endpoint; /*!< 0: client, 1: server */ + int authmode; /*!< verification mode */ + int client_auth; /*!< flag for client auth. */ + int verify_result; /*!< verification result */ + + /* + * Crypto layer + */ + dhm_context dhm_ctx; /*!< DHM key exchange */ + md5_context fin_md5; /*!< Finished MD5 checksum */ + sha1_context fin_sha1; /*!< Finished SHA-1 checksum */ + + int do_crypt; /*!< en(de)cryption flag */ + int *ciphersuites; /*!< allowed ciphersuites */ + size_t pmslen; /*!< premaster length */ + unsigned int keylen; /*!< symmetric key length */ + size_t minlen; /*!< min. ciphertext length */ + size_t ivlen; /*!< IV length */ + size_t maclen; /*!< MAC length */ + + unsigned char randbytes[64]; /*!< random bytes */ + unsigned char premaster[256]; /*!< premaster secret */ + + unsigned char iv_enc[16]; /*!< IV (encryption) */ + unsigned char iv_dec[16]; /*!< IV (decryption) */ + + unsigned char mac_enc[32]; /*!< MAC (encryption) */ + unsigned char mac_dec[32]; /*!< MAC (decryption) */ + + unsigned long ctx_enc[128]; /*!< encryption context */ + unsigned long ctx_dec[128]; /*!< decryption context */ + + /* + * TLS extensions + */ + unsigned char *hostname; + size_t hostname_len; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +extern int ssl_default_ciphersuites[]; + +/** + * \brief Returns the list of ciphersuites supported by the SSL/TLS module. + * + * \return a statically allocated array of ciphersuites, the last + * entry is 0. + */ +static inline const int *ssl_list_ciphersuites( void ) +{ + return ssl_default_ciphersuites; +} + +/** + * \brief Return the name of the ciphersuite associated with the given + * ID + * + * \param ciphersuite_id SSL ciphersuite ID + * + * \return a string containing the ciphersuite name + */ +const char *ssl_get_ciphersuite_name( const int ciphersuite_id ); + +/** + * \brief Return the ID of the ciphersuite associated with the given + * name + * + * \param ciphersuite_name SSL ciphersuite name + * + * \return the ID with the ciphersuite or 0 if not found + */ +int ssl_get_ciphersuite_id( const char *ciphersuite_name ); + +/** + * \brief Initialize an SSL context + * + * \param ssl SSL context + * + * \return 0 if successful, or POLARSSL_ERR_SSL_MALLOC_FAILED if + * memory allocation failed + */ +int ssl_init( ssl_context *ssl ); + +/** + * \brief Reset an already initialized SSL context for re-use + * while retaining application-set variables, function + * pointers and data. + * + * \param ssl SSL context + */ +void ssl_session_reset( ssl_context *ssl ); + +/** + * \brief Set the current endpoint type + * + * \param ssl SSL context + * \param endpoint must be SSL_IS_CLIENT or SSL_IS_SERVER + */ +void ssl_set_endpoint( ssl_context *ssl, int endpoint ); + +/** + * \brief Set the certificate verification mode + * + * \param ssl SSL context + * \param authmode can be: + * + * SSL_VERIFY_NONE: peer certificate is not checked (default), + * this is insecure and SHOULD be avoided. + * + * SSL_VERIFY_OPTIONAL: peer certificate is checked, however the + * handshake continues even if verification failed; + * ssl_get_verify_result() can be called after the + * handshake is complete. + * + * SSL_VERIFY_REQUIRED: peer *must* present a valid certificate, + * handshake is aborted if verification failed. + */ +void ssl_set_authmode( ssl_context *ssl, int authmode ); + +/** + * \brief Set the verification callback (Optional). + * + * If set, the verification callback is called once for every + * certificate in the chain. The verification function has the + * following parameter: (void *parameter, x509_cert certificate, + * int certifcate_depth, int preverify_ok). It should + * return 0 on SUCCESS. + * + * \param ssl SSL context + * \param f_vrfy verification function + * \param p_vrfy verification parameter + */ +void ssl_set_verify( ssl_context *ssl, + int (*f_vrfy)(void *, x509_cert *, int, int), + void *p_vrfy ); + +/** + * \brief Set the random number generator callback + * + * \param ssl SSL context + * \param f_rng RNG function + * \param p_rng RNG parameter + */ +void ssl_set_rng( ssl_context *ssl, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Set the debug callback + * + * \param ssl SSL context + * \param f_dbg debug function + * \param p_dbg debug parameter + */ +void ssl_set_dbg( ssl_context *ssl, + void (*f_dbg)(void *, int, const char *), + void *p_dbg ); + +/** + * \brief Set the underlying BIO read and write callbacks + * + * \param ssl SSL context + * \param f_recv read callback + * \param p_recv read parameter + * \param f_send write callback + * \param p_send write parameter + */ +void ssl_set_bio( ssl_context *ssl, + int (*f_recv)(void *, unsigned char *, size_t), void *p_recv, + int (*f_send)(void *, const unsigned char *, size_t), void *p_send ); + +/** + * \brief Set the session callbacks (server-side only) + * + * \param ssl SSL context + * \param s_get session get callback + * \param s_set session set callback + */ +void ssl_set_scb( ssl_context *ssl, + int (*s_get)(ssl_context *), + int (*s_set)(ssl_context *) ); + +/** + * \brief Set the session resuming flag, timeout and data + * + * \param ssl SSL context + * \param resume if 0 (default), the session will not be resumed + * \param timeout session timeout in seconds, or 0 (no timeout) + * \param session session context + */ +void ssl_set_session( ssl_context *ssl, int resume, int timeout, + ssl_session *session ); + +/** + * \brief Set the list of allowed ciphersuites + * + * \param ssl SSL context + * \param ciphersuites 0-terminated list of allowed ciphersuites + */ +void ssl_set_ciphersuites( ssl_context *ssl, int *ciphersuites ); + +/** + * \brief Set the data required to verify peer certificate + * + * \param ssl SSL context + * \param ca_chain trusted CA chain + * \param ca_crl trusted CA CRLs + * \param peer_cn expected peer CommonName (or NULL) + * + * \note TODO: add two more parameters: depth and crl + */ +void ssl_set_ca_chain( ssl_context *ssl, x509_cert *ca_chain, + x509_crl *ca_crl, const char *peer_cn ); + +/** + * \brief Set own certificate and private key + * + * \param ssl SSL context + * \param own_cert own public certificate + * \param rsa_key own private RSA key + */ +void ssl_set_own_cert( ssl_context *ssl, x509_cert *own_cert, + rsa_context *rsa_key ); + +#if defined(POLARSSL_PKCS11_C) +/** + * \brief Set own certificate and PKCS#11 private key + * + * \param ssl SSL context + * \param own_cert own public certificate + * \param pkcs11_key own PKCS#11 RSA key + */ +void ssl_set_own_cert_pkcs11( ssl_context *ssl, x509_cert *own_cert, + pkcs11_context *pkcs11_key ); +#endif + +/** + * \brief Set the Diffie-Hellman public P and G values, + * read as hexadecimal strings (server-side only) + * + * \param ssl SSL context + * \param dhm_P Diffie-Hellman-Merkle modulus + * \param dhm_G Diffie-Hellman-Merkle generator + * + * \return 0 if successful + */ +int ssl_set_dh_param( ssl_context *ssl, const char *dhm_P, const char *dhm_G ); + +/** + * \brief Set the Diffie-Hellman public P and G values, + * read from existing context (server-side only) + * + * \param ssl SSL context + * \param dhm_ctx Diffie-Hellman-Merkle context + * + * \return 0 if successful + */ +int ssl_set_dh_param_ctx( ssl_context *ssl, dhm_context *dhm_ctx ); + +/** + * \brief Set hostname for ServerName TLS Extension + * + * + * \param ssl SSL context + * \param hostname the server hostname + * + * \return 0 if successful or POLARSSL_ERR_SSL_MALLOC_FAILED + */ +int ssl_set_hostname( ssl_context *ssl, const char *hostname ); + +/** + * \brief Set the maximum supported version sent from the client side + * + * \param ssl SSL context + * \param major Major version number (only SSL_MAJOR_VERSION_3 supported) + * \param minor Minor version number (SSL_MINOR_VERSION_0, + * SSL_MINOR_VERSION_1 and SSL_MINOR_VERSION_2 supported) + */ +void ssl_set_max_version( ssl_context *ssl, int major, int minor ); + +/** + * \brief Return the number of data bytes available to read + * + * \param ssl SSL context + * + * \return how many bytes are available in the read buffer + */ +size_t ssl_get_bytes_avail( const ssl_context *ssl ); + +/** + * \brief Return the result of the certificate verification + * + * \param ssl SSL context + * + * \return 0 if successful, or a combination of: + * BADCERT_EXPIRED + * BADCERT_REVOKED + * BADCERT_CN_MISMATCH + * BADCERT_NOT_TRUSTED + */ +int ssl_get_verify_result( const ssl_context *ssl ); + +/** + * \brief Return the name of the current ciphersuite + * + * \param ssl SSL context + * + * \return a string containing the ciphersuite name + */ +const char *ssl_get_ciphersuite( const ssl_context *ssl ); + +/** + * \brief Return the current SSL version (SSLv3/TLSv1/etc) + * + * \param ssl SSL context + * + * \return a string containing the SSL version + */ +const char *ssl_get_version( const ssl_context *ssl ); + +/** + * \brief Perform the SSL handshake + * + * \param ssl SSL context + * + * \return 0 if successful, POLARSSL_ERR_NET_WANT_READ, + * POLARSSL_ERR_NET_WANT_WRITE, or a specific SSL error code. + */ +int ssl_handshake( ssl_context *ssl ); + +/** + * \brief Read at most 'len' application data bytes + * + * \param ssl SSL context + * \param buf buffer that will hold the data + * \param len how many bytes must be read + * + * \return This function returns the number of bytes read, 0 for EOF, + * or a negative error code. + */ +int ssl_read( ssl_context *ssl, unsigned char *buf, size_t len ); + +/** + * \brief Write exactly 'len' application data bytes + * + * \param ssl SSL context + * \param buf buffer holding the data + * \param len how many bytes must be written + * + * \return This function returns the number of bytes written, + * or a negative error code. + * + * \note When this function returns POLARSSL_ERR_NET_WANT_WRITE, + * it must be called later with the *same* arguments, + * until it returns a positive value. + */ +int ssl_write( ssl_context *ssl, const unsigned char *buf, size_t len ); + +/** + * \brief Notify the peer that the connection is being closed + * + * \param ssl SSL context + */ +int ssl_close_notify( ssl_context *ssl ); + +/** + * \brief Free an SSL context + * + * \param ssl SSL context + */ +void ssl_free( ssl_context *ssl ); + +/* + * Internal functions (do not call directly) + */ +int ssl_handshake_client( ssl_context *ssl ); +int ssl_handshake_server( ssl_context *ssl ); + +int ssl_derive_keys( ssl_context *ssl ); +void ssl_calc_verify( ssl_context *ssl, unsigned char hash[36] ); + +int ssl_read_record( ssl_context *ssl ); +/** + * \return 0 if successful, POLARSSL_ERR_SSL_CONN_EOF on EOF or + * another negative error code. + */ +int ssl_fetch_input( ssl_context *ssl, size_t nb_want ); + +int ssl_write_record( ssl_context *ssl ); +int ssl_flush_output( ssl_context *ssl ); + +int ssl_parse_certificate( ssl_context *ssl ); +int ssl_write_certificate( ssl_context *ssl ); + +int ssl_parse_change_cipher_spec( ssl_context *ssl ); +int ssl_write_change_cipher_spec( ssl_context *ssl ); + +int ssl_parse_finished( ssl_context *ssl ); +int ssl_write_finished( ssl_context *ssl ); + +#ifdef __cplusplus +} +#endif + +#endif /* ssl.h */ diff --git a/include/polarssl/timing.h b/include/polarssl/timing.h new file mode 100644 index 000000000..355c63c77 --- /dev/null +++ b/include/polarssl/timing.h @@ -0,0 +1,75 @@ +/** + * \file timing.h + * + * \brief Portable interface to the CPU cycle counter + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_TIMING_H +#define POLARSSL_TIMING_H + +/** + * \brief timer structure + */ +struct hr_time +{ + unsigned char opaque[32]; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +extern volatile int alarmed; + +/** + * \brief Return the CPU cycle counter value + */ +unsigned long hardclock( void ); + +/** + * \brief Return the elapsed time in milliseconds + * + * \param val points to a timer structure + * \param reset if set to 1, the timer is restarted + */ +unsigned long get_timer( struct hr_time *val, int reset ); + +/** + * \brief Setup an alarm clock + * + * \param seconds delay before the "alarmed" flag is set + */ +void set_alarm( int seconds ); + +/** + * \brief Sleep for a certain amount of time + * + * \param milliseconds delay in milliseconds + */ +void m_sleep( int milliseconds ); + +#ifdef __cplusplus +} +#endif + +#endif /* timing.h */ diff --git a/include/polarssl/version.h b/include/polarssl/version.h new file mode 100644 index 000000000..98eb0b3f1 --- /dev/null +++ b/include/polarssl/version.h @@ -0,0 +1,81 @@ +/** + * \file version.h + * + * \brief Run-time version information + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/* + * This set of compile-time defines and run-time variables can be used to + * determine the version number of the PolarSSL library used. + */ +#ifndef POLARSSL_VERSION_H +#define POLARSSL_VERSION_H + +#include "config.h" + +/** + * The version number x.y.z is split into three parts. + * Major, Minor, Patchlevel + */ +#define POLARSSL_VERSION_MAJOR 1 +#define POLARSSL_VERSION_MINOR 1 +#define POLARSSL_VERSION_PATCH 1 + +/** + * The single version number has the following structure: + * MMNNPP00 + * Major version | Minor version | Patch version + */ +#define POLARSSL_VERSION_NUMBER 0x01010100 +#define POLARSSL_VERSION_STRING "1.1.1" +#define POLARSSL_VERSION_STRING_FULL "PolarSSL 1.1.1" + +#if defined(POLARSSL_VERSION_C) + +/** + * Get the version number. + * + * \return The constructed version number in the format + * MMNNPP00 (Major, Minor, Patch). + */ +unsigned int version_get_number( void ); + +/** + * Get the version string ("x.y.z"). + * + * \param string The string that will receive the value. + * (Should be at least 9 bytes in size) + */ +void version_get_string( char *string ); + +/** + * Get the full version string ("PolarSSL x.y.z"). + * + * \param string The string that will receive the value. + * (Should be at least 18 bytes in size) + */ +void version_get_string_full( char *string ); + +#endif /* POLARSSL_VERSION_C */ + +#endif /* version.h */ diff --git a/include/polarssl/x509.h b/include/polarssl/x509.h new file mode 100644 index 000000000..cd0dc84a6 --- /dev/null +++ b/include/polarssl/x509.h @@ -0,0 +1,726 @@ +/** + * \file x509.h + * + * \brief X.509 certificate and private key decoding + * + * Copyright (C) 2006-2011, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_X509_H +#define POLARSSL_X509_H + +#include "asn1.h" +#include "rsa.h" +#include "dhm.h" + +/** + * \addtogroup x509_module + * \{ + */ + +/** + * \name X509 Error codes + * \{ + */ +#define POLARSSL_ERR_X509_FEATURE_UNAVAILABLE -0x2080 /**< Unavailable feature, e.g. RSA hashing/encryption combination. */ +#define POLARSSL_ERR_X509_CERT_INVALID_PEM -0x2100 /**< The PEM-encoded certificate contains invalid elements, e.g. invalid character. */ +#define POLARSSL_ERR_X509_CERT_INVALID_FORMAT -0x2180 /**< The certificate format is invalid, e.g. different type expected. */ +#define POLARSSL_ERR_X509_CERT_INVALID_VERSION -0x2200 /**< The certificate version element is invalid. */ +#define POLARSSL_ERR_X509_CERT_INVALID_SERIAL -0x2280 /**< The serial tag or value is invalid. */ +#define POLARSSL_ERR_X509_CERT_INVALID_ALG -0x2300 /**< The algorithm tag or value is invalid. */ +#define POLARSSL_ERR_X509_CERT_INVALID_NAME -0x2380 /**< The name tag or value is invalid. */ +#define POLARSSL_ERR_X509_CERT_INVALID_DATE -0x2400 /**< The date tag or value is invalid. */ +#define POLARSSL_ERR_X509_CERT_INVALID_PUBKEY -0x2480 /**< The pubkey tag or value is invalid (only RSA is supported). */ +#define POLARSSL_ERR_X509_CERT_INVALID_SIGNATURE -0x2500 /**< The signature tag or value invalid. */ +#define POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS -0x2580 /**< The extension tag or value is invalid. */ +#define POLARSSL_ERR_X509_CERT_UNKNOWN_VERSION -0x2600 /**< Certificate or CRL has an unsupported version number. */ +#define POLARSSL_ERR_X509_CERT_UNKNOWN_SIG_ALG -0x2680 /**< Signature algorithm (oid) is unsupported. */ +#define POLARSSL_ERR_X509_UNKNOWN_PK_ALG -0x2700 /**< Key algorithm is unsupported (only RSA is supported). */ +#define POLARSSL_ERR_X509_CERT_SIG_MISMATCH -0x2780 /**< Certificate signature algorithms do not match. (see \c ::x509_cert sig_oid) */ +#define POLARSSL_ERR_X509_CERT_VERIFY_FAILED -0x2800 /**< Certificate verification failed, e.g. CRL, CA or signature check failed. */ +#define POLARSSL_ERR_X509_KEY_INVALID_VERSION -0x2880 /**< Unsupported RSA key version */ +#define POLARSSL_ERR_X509_KEY_INVALID_FORMAT -0x2900 /**< Invalid RSA key tag or value. */ +#define POLARSSL_ERR_X509_CERT_UNKNOWN_FORMAT -0x2980 /**< Format not recognized as DER or PEM. */ +#define POLARSSL_ERR_X509_INVALID_INPUT -0x2A00 /**< Input invalid. */ +#define POLARSSL_ERR_X509_MALLOC_FAILED -0x2A80 /**< Allocation of memory failed. */ +#define POLARSSL_ERR_X509_FILE_IO_ERROR -0x2B00 /**< Read/write of file failed. */ +/* \} name */ + + +/** + * \name X509 Verify codes + * \{ + */ +#define BADCERT_EXPIRED 0x01 /**< The certificate validity has expired. */ +#define BADCERT_REVOKED 0x02 /**< The certificate has been revoked (is on a CRL). */ +#define BADCERT_CN_MISMATCH 0x04 /**< The certificate Common Name (CN) does not match with the expected CN. */ +#define BADCERT_NOT_TRUSTED 0x08 /**< The certificate is not correctly signed by the trusted CA. */ +#define BADCRL_NOT_TRUSTED 0x10 /**< CRL is not correctly signed by the trusted CA. */ +#define BADCRL_EXPIRED 0x20 /**< CRL is expired. */ +#define BADCERT_MISSING 0x40 /**< Certificate was missing. */ +#define BADCERT_SKIP_VERIFY 0x80 /**< Certificate verification was skipped. */ +/* \} name */ +/* \} addtogroup x509_module */ + +/* + * various object identifiers + */ +#define X520_COMMON_NAME 3 +#define X520_COUNTRY 6 +#define X520_LOCALITY 7 +#define X520_STATE 8 +#define X520_ORGANIZATION 10 +#define X520_ORG_UNIT 11 +#define PKCS9_EMAIL 1 + +#define X509_OUTPUT_DER 0x01 +#define X509_OUTPUT_PEM 0x02 +#define PEM_LINE_LENGTH 72 +#define X509_ISSUER 0x01 +#define X509_SUBJECT 0x02 + +#define OID_X520 "\x55\x04" +#define OID_CN OID_X520 "\x03" + +#define OID_PKCS1 "\x2A\x86\x48\x86\xF7\x0D\x01\x01" +#define OID_PKCS1_RSA OID_PKCS1 "\x01" + +#define OID_RSA_SHA_OBS "\x2B\x0E\x03\x02\x1D" + +#define OID_PKCS9 "\x2A\x86\x48\x86\xF7\x0D\x01\x09" +#define OID_PKCS9_EMAIL OID_PKCS9 "\x01" + +/** ISO arc for standard certificate and CRL extensions */ +#define OID_ID_CE "\x55\x1D" /**< id-ce OBJECT IDENTIFIER ::= {joint-iso-ccitt(2) ds(5) 29} */ + +/** + * Private Internet Extensions + * { iso(1) identified-organization(3) dod(6) internet(1) + * security(5) mechanisms(5) pkix(7) } + */ +#define OID_PKIX "\x2B\x06\x01\x05\x05\x07" + +/* + * OIDs for standard certificate extensions + */ +#define OID_AUTHORITY_KEY_IDENTIFIER OID_ID_CE "\x23" /**< id-ce-authorityKeyIdentifier OBJECT IDENTIFIER ::= { id-ce 35 } */ +#define OID_SUBJECT_KEY_IDENTIFIER OID_ID_CE "\x0E" /**< id-ce-subjectKeyIdentifier OBJECT IDENTIFIER ::= { id-ce 14 } */ +#define OID_KEY_USAGE OID_ID_CE "\x0F" /**< id-ce-keyUsage OBJECT IDENTIFIER ::= { id-ce 15 } */ +#define OID_CERTIFICATE_POLICIES OID_ID_CE "\x20" /**< id-ce-certificatePolicies OBJECT IDENTIFIER ::= { id-ce 32 } */ +#define OID_POLICY_MAPPINGS OID_ID_CE "\x21" /**< id-ce-policyMappings OBJECT IDENTIFIER ::= { id-ce 33 } */ +#define OID_SUBJECT_ALT_NAME OID_ID_CE "\x11" /**< id-ce-subjectAltName OBJECT IDENTIFIER ::= { id-ce 17 } */ +#define OID_ISSUER_ALT_NAME OID_ID_CE "\x12" /**< id-ce-issuerAltName OBJECT IDENTIFIER ::= { id-ce 18 } */ +#define OID_SUBJECT_DIRECTORY_ATTRS OID_ID_CE "\x09" /**< id-ce-subjectDirectoryAttributes OBJECT IDENTIFIER ::= { id-ce 9 } */ +#define OID_BASIC_CONSTRAINTS OID_ID_CE "\x13" /**< id-ce-basicConstraints OBJECT IDENTIFIER ::= { id-ce 19 } */ +#define OID_NAME_CONSTRAINTS OID_ID_CE "\x1E" /**< id-ce-nameConstraints OBJECT IDENTIFIER ::= { id-ce 30 } */ +#define OID_POLICY_CONSTRAINTS OID_ID_CE "\x24" /**< id-ce-policyConstraints OBJECT IDENTIFIER ::= { id-ce 36 } */ +#define OID_EXTENDED_KEY_USAGE OID_ID_CE "\x25" /**< id-ce-extKeyUsage OBJECT IDENTIFIER ::= { id-ce 37 } */ +#define OID_CRL_DISTRIBUTION_POINTS OID_ID_CE "\x1F" /**< id-ce-cRLDistributionPoints OBJECT IDENTIFIER ::= { id-ce 31 } */ +#define OID_INIHIBIT_ANYPOLICY OID_ID_CE "\x36" /**< id-ce-inhibitAnyPolicy OBJECT IDENTIFIER ::= { id-ce 54 } */ +#define OID_FRESHEST_CRL OID_ID_CE "\x2E" /**< id-ce-freshestCRL OBJECT IDENTIFIER ::= { id-ce 46 } */ + +/* + * X.509 v3 Key Usage Extension flags + */ +#define KU_DIGITAL_SIGNATURE (0x80) /* bit 0 */ +#define KU_NON_REPUDIATION (0x40) /* bit 1 */ +#define KU_KEY_ENCIPHERMENT (0x20) /* bit 2 */ +#define KU_DATA_ENCIPHERMENT (0x10) /* bit 3 */ +#define KU_KEY_AGREEMENT (0x08) /* bit 4 */ +#define KU_KEY_CERT_SIGN (0x04) /* bit 5 */ +#define KU_CRL_SIGN (0x02) /* bit 6 */ + +/* + * X.509 v3 Extended key usage OIDs + */ +#define OID_ANY_EXTENDED_KEY_USAGE OID_EXTENDED_KEY_USAGE "\x00" /**< anyExtendedKeyUsage OBJECT IDENTIFIER ::= { id-ce-extKeyUsage 0 } */ + +#define OID_KP OID_PKIX "\x03" /**< id-kp OBJECT IDENTIFIER ::= { id-pkix 3 } */ +#define OID_SERVER_AUTH OID_KP "\x01" /**< id-kp-serverAuth OBJECT IDENTIFIER ::= { id-kp 1 } */ +#define OID_CLIENT_AUTH OID_KP "\x02" /**< id-kp-clientAuth OBJECT IDENTIFIER ::= { id-kp 2 } */ +#define OID_CODE_SIGNING OID_KP "\x03" /**< id-kp-codeSigning OBJECT IDENTIFIER ::= { id-kp 3 } */ +#define OID_EMAIL_PROTECTION OID_KP "\x04" /**< id-kp-emailProtection OBJECT IDENTIFIER ::= { id-kp 4 } */ +#define OID_TIME_STAMPING OID_KP "\x08" /**< id-kp-timeStamping OBJECT IDENTIFIER ::= { id-kp 8 } */ +#define OID_OCSP_SIGNING OID_KP "\x09" /**< id-kp-OCSPSigning OBJECT IDENTIFIER ::= { id-kp 9 } */ + +#define STRING_SERVER_AUTH "TLS Web Server Authentication" +#define STRING_CLIENT_AUTH "TLS Web Client Authentication" +#define STRING_CODE_SIGNING "Code Signing" +#define STRING_EMAIL_PROTECTION "E-mail Protection" +#define STRING_TIME_STAMPING "Time Stamping" +#define STRING_OCSP_SIGNING "OCSP Signing" + +/* + * OIDs for CRL extensions + */ +#define OID_PRIVATE_KEY_USAGE_PERIOD OID_ID_CE "\x10" +#define OID_CRL_NUMBER OID_ID_CE "\x14" /**< id-ce-cRLNumber OBJECT IDENTIFIER ::= { id-ce 20 } */ + +/* + * Netscape certificate extensions + */ +#define OID_NETSCAPE "\x60\x86\x48\x01\x86\xF8\x42" /**< Netscape OID */ +#define OID_NS_CERT OID_NETSCAPE "\x01" +#define OID_NS_CERT_TYPE OID_NS_CERT "\x01" +#define OID_NS_BASE_URL OID_NS_CERT "\x02" +#define OID_NS_REVOCATION_URL OID_NS_CERT "\x03" +#define OID_NS_CA_REVOCATION_URL OID_NS_CERT "\x04" +#define OID_NS_RENEWAL_URL OID_NS_CERT "\x07" +#define OID_NS_CA_POLICY_URL OID_NS_CERT "\x08" +#define OID_NS_SSL_SERVER_NAME OID_NS_CERT "\x0C" +#define OID_NS_COMMENT OID_NS_CERT "\x0D" +#define OID_NS_DATA_TYPE OID_NETSCAPE "\x02" +#define OID_NS_CERT_SEQUENCE OID_NS_DATA_TYPE "\x05" + +/* + * Netscape certificate types + * (http://www.mozilla.org/projects/security/pki/nss/tech-notes/tn3.html) + */ + +#define NS_CERT_TYPE_SSL_CLIENT (0x80) /* bit 0 */ +#define NS_CERT_TYPE_SSL_SERVER (0x40) /* bit 1 */ +#define NS_CERT_TYPE_EMAIL (0x20) /* bit 2 */ +#define NS_CERT_TYPE_OBJECT_SIGNING (0x10) /* bit 3 */ +#define NS_CERT_TYPE_RESERVED (0x08) /* bit 4 */ +#define NS_CERT_TYPE_SSL_CA (0x04) /* bit 5 */ +#define NS_CERT_TYPE_EMAIL_CA (0x02) /* bit 6 */ +#define NS_CERT_TYPE_OBJECT_SIGNING_CA (0x01) /* bit 7 */ + +#define EXT_AUTHORITY_KEY_IDENTIFIER (1 << 0) +#define EXT_SUBJECT_KEY_IDENTIFIER (1 << 1) +#define EXT_KEY_USAGE (1 << 2) +#define EXT_CERTIFICATE_POLICIES (1 << 3) +#define EXT_POLICY_MAPPINGS (1 << 4) +#define EXT_SUBJECT_ALT_NAME (1 << 5) +#define EXT_ISSUER_ALT_NAME (1 << 6) +#define EXT_SUBJECT_DIRECTORY_ATTRS (1 << 7) +#define EXT_BASIC_CONSTRAINTS (1 << 8) +#define EXT_NAME_CONSTRAINTS (1 << 9) +#define EXT_POLICY_CONSTRAINTS (1 << 10) +#define EXT_EXTENDED_KEY_USAGE (1 << 11) +#define EXT_CRL_DISTRIBUTION_POINTS (1 << 12) +#define EXT_INIHIBIT_ANYPOLICY (1 << 13) +#define EXT_FRESHEST_CRL (1 << 14) + +#define EXT_NS_CERT_TYPE (1 << 16) + +/* + * Storage format identifiers + * Recognized formats: PEM and DER + */ +#define X509_FORMAT_DER 1 +#define X509_FORMAT_PEM 2 + +/** + * \addtogroup x509_module + * \{ */ + +/** + * \name Structures for parsing X.509 certificates and CRLs + * \{ + */ + +/** + * Type-length-value structure that allows for ASN1 using DER. + */ +typedef asn1_buf x509_buf; + +/** + * Container for ASN1 bit strings. + */ +typedef asn1_bitstring x509_bitstring; + +/** + * Container for ASN1 named information objects. + * It allows for Relative Distinguished Names (e.g. cn=polarssl,ou=code,etc.). + */ +typedef struct _x509_name +{ + x509_buf oid; /**< The object identifier. */ + x509_buf val; /**< The named value. */ + struct _x509_name *next; /**< The next named information object. */ +} +x509_name; + +/** + * Container for a sequence of ASN.1 items + */ +typedef asn1_sequence x509_sequence; + +/** Container for date and time (precision in seconds). */ +typedef struct _x509_time +{ + int year, mon, day; /**< Date. */ + int hour, min, sec; /**< Time. */ +} +x509_time; + +/** + * Container for an X.509 certificate. The certificate may be chained. + */ +typedef struct _x509_cert +{ + x509_buf raw; /**< The raw certificate data (DER). */ + x509_buf tbs; /**< The raw certificate body (DER). The part that is To Be Signed. */ + + int version; /**< The X.509 version. (0=v1, 1=v2, 2=v3) */ + x509_buf serial; /**< Unique id for certificate issued by a specific CA. */ + x509_buf sig_oid1; /**< Signature algorithm, e.g. sha1RSA */ + + x509_buf issuer_raw; /**< The raw issuer data (DER). Used for quick comparison. */ + x509_buf subject_raw; /**< The raw subject data (DER). Used for quick comparison. */ + + x509_name issuer; /**< The parsed issuer data (named information object). */ + x509_name subject; /**< The parsed subject data (named information object). */ + + x509_time valid_from; /**< Start time of certificate validity. */ + x509_time valid_to; /**< End time of certificate validity. */ + + x509_buf pk_oid; /**< Subject public key info. Includes the public key algorithm and the key itself. */ + rsa_context rsa; /**< Container for the RSA context. Only RSA is supported for public keys at this time. */ + + x509_buf issuer_id; /**< Optional X.509 v2/v3 issuer unique identifier. */ + x509_buf subject_id; /**< Optional X.509 v2/v3 subject unique identifier. */ + x509_buf v3_ext; /**< Optional X.509 v3 extensions. Only Basic Contraints are supported at this time. */ + + int ext_types; /**< Bit string containing detected and parsed extensions */ + int ca_istrue; /**< Optional Basic Constraint extension value: 1 if this certificate belongs to a CA, 0 otherwise. */ + int max_pathlen; /**< Optional Basic Constraint extension value: The maximum path length to the root certificate. */ + + unsigned char key_usage; /**< Optional key usage extension value: See the values below */ + + x509_sequence ext_key_usage; /**< Optional list of extended key usage OIDs. */ + + unsigned char ns_cert_type; /**< Optional Netscape certificate type extension value: See the values below */ + + x509_buf sig_oid2; /**< Signature algorithm. Must match sig_oid1. */ + x509_buf sig; /**< Signature: hash of the tbs part signed with the private key. */ + int sig_alg; /**< Internal representation of the signature algorithm, e.g. SIG_RSA_MD2 */ + + struct _x509_cert *next; /**< Next certificate in the CA-chain. */ +} +x509_cert; + +/** + * Certificate revocation list entry. + * Contains the CA-specific serial numbers and revocation dates. + */ +typedef struct _x509_crl_entry +{ + x509_buf raw; + + x509_buf serial; + + x509_time revocation_date; + + x509_buf entry_ext; + + struct _x509_crl_entry *next; +} +x509_crl_entry; + +/** + * Certificate revocation list structure. + * Every CRL may have multiple entries. + */ +typedef struct _x509_crl +{ + x509_buf raw; /**< The raw certificate data (DER). */ + x509_buf tbs; /**< The raw certificate body (DER). The part that is To Be Signed. */ + + int version; + x509_buf sig_oid1; + + x509_buf issuer_raw; /**< The raw issuer data (DER). */ + + x509_name issuer; /**< The parsed issuer data (named information object). */ + + x509_time this_update; + x509_time next_update; + + x509_crl_entry entry; /**< The CRL entries containing the certificate revocation times for this CA. */ + + x509_buf crl_ext; + + x509_buf sig_oid2; + x509_buf sig; + int sig_alg; + + struct _x509_crl *next; +} +x509_crl; +/** \} name Structures for parsing X.509 certificates and CRLs */ +/** \} addtogroup x509_module */ + +/** + * \name Structures for writing X.509 certificates. + * XvP: commented out as they are not used. + * - typedef struct _x509_node x509_node; + * - typedef struct _x509_raw x509_raw; + */ +/* +typedef struct _x509_node +{ + unsigned char *data; + unsigned char *p; + unsigned char *end; + + size_t len; +} +x509_node; + +typedef struct _x509_raw +{ + x509_node raw; + x509_node tbs; + + x509_node version; + x509_node serial; + x509_node tbs_signalg; + x509_node issuer; + x509_node validity; + x509_node subject; + x509_node subpubkey; + + x509_node signalg; + x509_node sign; +} +x509_raw; +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \name Functions to read in DHM parameters, a certificate, CRL or private RSA key + * \{ + */ + +/** \ingroup x509_module */ +/** + * \brief Parse one or more certificates and add them + * to the chained list. Parses permissively. If some + * certificates can be parsed, the result is the number + * of failed certificates it encountered. If none complete + * correctly, the first error is returned. + * + * \param chain points to the start of the chain + * \param buf buffer holding the certificate data + * \param buflen size of the buffer + * + * \return 0 if all certificates parsed successfully, a positive number + * if partly successful or a specific X509 or PEM error code + */ +int x509parse_crt( x509_cert *chain, const unsigned char *buf, size_t buflen ); + +/** \ingroup x509_module */ +/** + * \brief Load one or more certificates and add them + * to the chained list. Parses permissively. If some + * certificates can be parsed, the result is the number + * of failed certificates it encountered. If none complete + * correctly, the first error is returned. + * + * \param chain points to the start of the chain + * \param path filename to read the certificates from + * + * \return 0 if all certificates parsed successfully, a positive number + * if partly successful or a specific X509 or PEM error code + */ +int x509parse_crtfile( x509_cert *chain, const char *path ); + +/** \ingroup x509_module */ +/** + * \brief Parse one or more CRLs and add them + * to the chained list + * + * \param chain points to the start of the chain + * \param buf buffer holding the CRL data + * \param buflen size of the buffer + * + * \return 0 if successful, or a specific X509 or PEM error code + */ +int x509parse_crl( x509_crl *chain, const unsigned char *buf, size_t buflen ); + +/** \ingroup x509_module */ +/** + * \brief Load one or more CRLs and add them + * to the chained list + * + * \param chain points to the start of the chain + * \param path filename to read the CRLs from + * + * \return 0 if successful, or a specific X509 or PEM error code + */ +int x509parse_crlfile( x509_crl *chain, const char *path ); + +/** \ingroup x509_module */ +/** + * \brief Parse a private RSA key + * + * \param rsa RSA context to be initialized + * \param key input buffer + * \param keylen size of the buffer + * \param pwd password for decryption (optional) + * \param pwdlen size of the password + * + * \return 0 if successful, or a specific X509 or PEM error code + */ +int x509parse_key( rsa_context *rsa, + const unsigned char *key, size_t keylen, + const unsigned char *pwd, size_t pwdlen ); + +/** \ingroup x509_module */ +/** + * \brief Load and parse a private RSA key + * + * \param rsa RSA context to be initialized + * \param path filename to read the private key from + * \param password password to decrypt the file (can be NULL) + * + * \return 0 if successful, or a specific X509 or PEM error code + */ +int x509parse_keyfile( rsa_context *rsa, const char *path, + const char *password ); + +/** \ingroup x509_module */ +/** + * \brief Parse a public RSA key + * + * \param rsa RSA context to be initialized + * \param key input buffer + * \param keylen size of the buffer + * + * \return 0 if successful, or a specific X509 or PEM error code + */ +int x509parse_public_key( rsa_context *rsa, + const unsigned char *key, size_t keylen ); + +/** \ingroup x509_module */ +/** + * \brief Load and parse a public RSA key + * + * \param rsa RSA context to be initialized + * \param path filename to read the private key from + * + * \return 0 if successful, or a specific X509 or PEM error code + */ +int x509parse_public_keyfile( rsa_context *rsa, const char *path ); + +/** \ingroup x509_module */ +/** + * \brief Parse DHM parameters + * + * \param dhm DHM context to be initialized + * \param dhmin input buffer + * \param dhminlen size of the buffer + * + * \return 0 if successful, or a specific X509 or PEM error code + */ +int x509parse_dhm( dhm_context *dhm, const unsigned char *dhmin, size_t dhminlen ); + +/** \ingroup x509_module */ +/** + * \brief Load and parse DHM parameters + * + * \param dhm DHM context to be initialized + * \param path filename to read the DHM Parameters from + * + * \return 0 if successful, or a specific X509 or PEM error code + */ +int x509parse_dhmfile( dhm_context *dhm, const char *path ); + +/** \} name Functions to read in DHM parameters, a certificate, CRL or private RSA key */ + +/** + * \brief Store the certificate DN in printable form into buf; + * no more than size characters will be written. + * + * \param buf Buffer to write to + * \param size Maximum size of buffer + * \param dn The X509 name to represent + * + * \return The amount of data written to the buffer, or -1 in + * case of an error. + */ +int x509parse_dn_gets( char *buf, size_t size, const x509_name *dn ); + +/** + * \brief Store the certificate serial in printable form into buf; + * no more than size characters will be written. + * + * \param buf Buffer to write to + * \param size Maximum size of buffer + * \param serial The X509 serial to represent + * + * \return The amount of data written to the buffer, or -1 in + * case of an error. + */ +int x509parse_serial_gets( char *buf, size_t size, const x509_buf *serial ); + +/** + * \brief Returns an informational string about the + * certificate. + * + * \param buf Buffer to write to + * \param size Maximum size of buffer + * \param prefix A line prefix + * \param crt The X509 certificate to represent + * + * \return The amount of data written to the buffer, or -1 in + * case of an error. + */ +int x509parse_cert_info( char *buf, size_t size, const char *prefix, + const x509_cert *crt ); + +/** + * \brief Returns an informational string about the + * CRL. + * + * \param buf Buffer to write to + * \param size Maximum size of buffer + * \param prefix A line prefix + * \param crl The X509 CRL to represent + * + * \return The amount of data written to the buffer, or -1 in + * case of an error. + */ +int x509parse_crl_info( char *buf, size_t size, const char *prefix, + const x509_crl *crl ); + +/** + * \brief Give an known OID, return its descriptive string. + * + * \param oid buffer containing the oid + * + * \return Return a string if the OID is known, + * or NULL otherwise. + */ +const char *x509_oid_get_description( x509_buf *oid ); + +/* + * \brief Give an OID, return a string version of its OID number. + * + * \param buf Buffer to write to + * \param size Maximum size of buffer + * \param oid Buffer containing the OID + * + * \return The amount of data written to the buffer, or -1 in + * case of an error. + */ +int x509_oid_get_numeric_string( char *buf, size_t size, x509_buf *oid ); + +/** + * \brief Check a given x509_time against the system time and check + * if it is valid. + * + * \param time x509_time to check + * + * \return Return 0 if the x509_time is still valid, + * or 1 otherwise. + */ +int x509parse_time_expired( const x509_time *time ); + +/** + * \name Functions to verify a certificate + * \{ + */ +/** \ingroup x509_module */ +/** + * \brief Verify the certificate signature + * + * \param crt a certificate to be verified + * \param trust_ca the trusted CA chain + * \param ca_crl the CRL chain for trusted CA's + * \param cn expected Common Name (can be set to + * NULL if the CN must not be verified) + * \param flags result of the verification + * \param f_vrfy verification function + * \param p_vrfy verification parameter + * + * \return 0 if successful or POLARSSL_ERR_X509_SIG_VERIFY_FAILED, + * in which case *flags will have one or more of + * the following values set: + * BADCERT_EXPIRED -- + * BADCERT_REVOKED -- + * BADCERT_CN_MISMATCH -- + * BADCERT_NOT_TRUSTED + * + * \note TODO: add two arguments, depth and crl + */ +int x509parse_verify( x509_cert *crt, + x509_cert *trust_ca, + x509_crl *ca_crl, + const char *cn, int *flags, + int (*f_vrfy)(void *, x509_cert *, int, int), + void *p_vrfy ); + +/** + * \brief Verify the certificate signature + * + * \param crt a certificate to be verified + * \param crl the CRL to verify against + * + * \return 1 if the certificate is revoked, 0 otherwise + * + */ +int x509parse_revoked( const x509_cert *crt, const x509_crl *crl ); + +/** \} name Functions to verify a certificate */ + + + +/** + * \name Functions to clear a certificate, CRL or private RSA key + * \{ + */ +/** \ingroup x509_module */ +/** + * \brief Unallocate all certificate data + * + * \param crt Certificate chain to free + */ +void x509_free( x509_cert *crt ); + +/** \ingroup x509_module */ +/** + * \brief Unallocate all CRL data + * + * \param crl CRL chain to free + */ +void x509_crl_free( x509_crl *crl ); + +/** \} name Functions to clear a certificate, CRL or private RSA key */ + + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int x509_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* x509.h */ diff --git a/include/polarssl/xtea.h b/include/polarssl/xtea.h new file mode 100644 index 000000000..e2adb8788 --- /dev/null +++ b/include/polarssl/xtea.h @@ -0,0 +1,111 @@ +/** + * \file xtea.h + * + * \brief XTEA block cipher (32-bit) + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_XTEA_H +#define POLARSSL_XTEA_H + +#include + +#ifdef _MSC_VER +#include +typedef UINT32 uint32_t; +#else +#include +#endif + +#define XTEA_ENCRYPT 1 +#define XTEA_DECRYPT 0 + +#define POLARSSL_ERR_XTEA_INVALID_INPUT_LENGTH -0x0028 /**< The data input has an invalid length. */ + +/** + * \brief XTEA context structure + */ +typedef struct +{ + uint32_t k[4]; /*!< key */ +} +xtea_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief XTEA key schedule + * + * \param ctx XTEA context to be initialized + * \param key the secret key + */ +void xtea_setup( xtea_context *ctx, unsigned char key[16] ); + +/** + * \brief XTEA cipher function + * + * \param ctx XTEA context + * \param mode XTEA_ENCRYPT or XTEA_DECRYPT + * \param input 8-byte input block + * \param output 8-byte output block + * + * \return 0 if successful + */ +int xtea_crypt_ecb( xtea_context *ctx, + int mode, + unsigned char input[8], + unsigned char output[8] ); + +/** + * \brief XTEA CBC cipher function + * + * \param ctx XTEA context + * \param mode XTEA_ENCRYPT or XTEA_DECRYPT + * \param length the length of input, multiple of 8 + * \param iv initialization vector for CBC mode + * \param input input block + * \param output output block + * + * \return 0 if successful, + * POLARSSL_ERR_XTEA_INVALID_INPUT_LENGTH if the length % 8 != 0 + */ +int xtea_crypt_cbc( xtea_context *ctx, + int mode, + size_t length, + unsigned char iv[8], + unsigned char *input, + unsigned char *output); + +/* + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int xtea_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* xtea.h */ diff --git a/include/sqlite/sqlite3.h b/include/sqlite/sqlite3.h new file mode 100644 index 000000000..ed9edbd20 --- /dev/null +++ b/include/sqlite/sqlite3.h @@ -0,0 +1,6731 @@ +/* +** 2001 September 15 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** This header file defines the interface that the SQLite library +** presents to client programs. If a C-function, structure, datatype, +** or constant definition does not appear in this file, then it is +** not a published API of SQLite, is subject to change without +** notice, and should not be referenced by programs that use SQLite. +** +** Some of the definitions that are in this file are marked as +** "experimental". Experimental interfaces are normally new +** features recently added to SQLite. We do not anticipate changes +** to experimental interfaces but reserve the right to make minor changes +** if experience from use "in the wild" suggest such changes are prudent. +** +** The official C-language API documentation for SQLite is derived +** from comments in this file. This file is the authoritative source +** on how SQLite interfaces are suppose to operate. +** +** The name of this file under configuration management is "sqlite.h.in". +** The makefile makes some minor changes to this file (such as inserting +** the version number) and changes its name to "sqlite3.h" as +** part of the build process. +*/ +#ifndef _SQLITE3_H_ +#define _SQLITE3_H_ +#include /* Needed for the definition of va_list */ + +/* +** Make sure we can call this stuff from C++. +*/ +#ifdef __cplusplus +extern "C" { +#endif + + +/* +** Add the ability to override 'extern' +*/ +#ifndef SQLITE_EXTERN +# define SQLITE_EXTERN extern +#endif + +#ifndef SQLITE_API +# define SQLITE_API +#endif + + +/* +** These no-op macros are used in front of interfaces to mark those +** interfaces as either deprecated or experimental. New applications +** should not use deprecated interfaces - they are support for backwards +** compatibility only. Application writers should be aware that +** experimental interfaces are subject to change in point releases. +** +** These macros used to resolve to various kinds of compiler magic that +** would generate warning messages when they were used. But that +** compiler magic ended up generating such a flurry of bug reports +** that we have taken it all out and gone back to using simple +** noop macros. +*/ +#define SQLITE_DEPRECATED +#define SQLITE_EXPERIMENTAL + +/* +** Ensure these symbols were not defined by some previous header file. +*/ +#ifdef SQLITE_VERSION +# undef SQLITE_VERSION +#endif +#ifdef SQLITE_VERSION_NUMBER +# undef SQLITE_VERSION_NUMBER +#endif + +/* +** CAPI3REF: Compile-Time Library Version Numbers +** +** ^(The [SQLITE_VERSION] C preprocessor macro in the sqlite3.h header +** evaluates to a string literal that is the SQLite version in the +** format "X.Y.Z" where X is the major version number (always 3 for +** SQLite3) and Y is the minor version number and Z is the release number.)^ +** ^(The [SQLITE_VERSION_NUMBER] C preprocessor macro resolves to an integer +** with the value (X*1000000 + Y*1000 + Z) where X, Y, and Z are the same +** numbers used in [SQLITE_VERSION].)^ +** The SQLITE_VERSION_NUMBER for any given release of SQLite will also +** be larger than the release from which it is derived. Either Y will +** be held constant and Z will be incremented or else Y will be incremented +** and Z will be reset to zero. +** +** Since version 3.6.18, SQLite source code has been stored in the +** Fossil configuration management +** system. ^The SQLITE_SOURCE_ID macro evaluates to +** a string which identifies a particular check-in of SQLite +** within its configuration management system. ^The SQLITE_SOURCE_ID +** string contains the date and time of the check-in (UTC) and an SHA1 +** hash of the entire source tree. +** +** See also: [sqlite3_libversion()], +** [sqlite3_libversion_number()], [sqlite3_sourceid()], +** [sqlite_version()] and [sqlite_source_id()]. +*/ +#define SQLITE_VERSION "3.7.7.1" +#define SQLITE_VERSION_NUMBER 3007007 +#define SQLITE_SOURCE_ID "2011-06-28 17:39:05 af0d91adf497f5f36ec3813f04235a6e195a605f" + +/* +** CAPI3REF: Run-Time Library Version Numbers +** KEYWORDS: sqlite3_version, sqlite3_sourceid +** +** These interfaces provide the same information as the [SQLITE_VERSION], +** [SQLITE_VERSION_NUMBER], and [SQLITE_SOURCE_ID] C preprocessor macros +** but are associated with the library instead of the header file. ^(Cautious +** programmers might include assert() statements in their application to +** verify that values returned by these interfaces match the macros in +** the header, and thus insure that the application is +** compiled with matching library and header files. +** +**
+** assert( sqlite3_libversion_number()==SQLITE_VERSION_NUMBER );
+** assert( strcmp(sqlite3_sourceid(),SQLITE_SOURCE_ID)==0 );
+** assert( strcmp(sqlite3_libversion(),SQLITE_VERSION)==0 );
+** 
)^ +** +** ^The sqlite3_version[] string constant contains the text of [SQLITE_VERSION] +** macro. ^The sqlite3_libversion() function returns a pointer to the +** to the sqlite3_version[] string constant. The sqlite3_libversion() +** function is provided for use in DLLs since DLL users usually do not have +** direct access to string constants within the DLL. ^The +** sqlite3_libversion_number() function returns an integer equal to +** [SQLITE_VERSION_NUMBER]. ^The sqlite3_sourceid() function returns +** a pointer to a string constant whose value is the same as the +** [SQLITE_SOURCE_ID] C preprocessor macro. +** +** See also: [sqlite_version()] and [sqlite_source_id()]. +*/ +SQLITE_API SQLITE_EXTERN const char sqlite3_version[]; +SQLITE_API const char *sqlite3_libversion(void); +SQLITE_API const char *sqlite3_sourceid(void); +SQLITE_API int sqlite3_libversion_number(void); + +/* +** CAPI3REF: Run-Time Library Compilation Options Diagnostics +** +** ^The sqlite3_compileoption_used() function returns 0 or 1 +** indicating whether the specified option was defined at +** compile time. ^The SQLITE_ prefix may be omitted from the +** option name passed to sqlite3_compileoption_used(). +** +** ^The sqlite3_compileoption_get() function allows iterating +** over the list of options that were defined at compile time by +** returning the N-th compile time option string. ^If N is out of range, +** sqlite3_compileoption_get() returns a NULL pointer. ^The SQLITE_ +** prefix is omitted from any strings returned by +** sqlite3_compileoption_get(). +** +** ^Support for the diagnostic functions sqlite3_compileoption_used() +** and sqlite3_compileoption_get() may be omitted by specifying the +** [SQLITE_OMIT_COMPILEOPTION_DIAGS] option at compile time. +** +** See also: SQL functions [sqlite_compileoption_used()] and +** [sqlite_compileoption_get()] and the [compile_options pragma]. +*/ +#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS +SQLITE_API int sqlite3_compileoption_used(const char *zOptName); +SQLITE_API const char *sqlite3_compileoption_get(int N); +#endif + +/* +** CAPI3REF: Test To See If The Library Is Threadsafe +** +** ^The sqlite3_threadsafe() function returns zero if and only if +** SQLite was compiled mutexing code omitted due to the +** [SQLITE_THREADSAFE] compile-time option being set to 0. +** +** SQLite can be compiled with or without mutexes. When +** the [SQLITE_THREADSAFE] C preprocessor macro is 1 or 2, mutexes +** are enabled and SQLite is threadsafe. When the +** [SQLITE_THREADSAFE] macro is 0, +** the mutexes are omitted. Without the mutexes, it is not safe +** to use SQLite concurrently from more than one thread. +** +** Enabling mutexes incurs a measurable performance penalty. +** So if speed is of utmost importance, it makes sense to disable +** the mutexes. But for maximum safety, mutexes should be enabled. +** ^The default behavior is for mutexes to be enabled. +** +** This interface can be used by an application to make sure that the +** version of SQLite that it is linking against was compiled with +** the desired setting of the [SQLITE_THREADSAFE] macro. +** +** This interface only reports on the compile-time mutex setting +** of the [SQLITE_THREADSAFE] flag. If SQLite is compiled with +** SQLITE_THREADSAFE=1 or =2 then mutexes are enabled by default but +** can be fully or partially disabled using a call to [sqlite3_config()] +** with the verbs [SQLITE_CONFIG_SINGLETHREAD], [SQLITE_CONFIG_MULTITHREAD], +** or [SQLITE_CONFIG_MUTEX]. ^(The return value of the +** sqlite3_threadsafe() function shows only the compile-time setting of +** thread safety, not any run-time changes to that setting made by +** sqlite3_config(). In other words, the return value from sqlite3_threadsafe() +** is unchanged by calls to sqlite3_config().)^ +** +** See the [threading mode] documentation for additional information. +*/ +SQLITE_API int sqlite3_threadsafe(void); + +/* +** CAPI3REF: Database Connection Handle +** KEYWORDS: {database connection} {database connections} +** +** Each open SQLite database is represented by a pointer to an instance of +** the opaque structure named "sqlite3". It is useful to think of an sqlite3 +** pointer as an object. The [sqlite3_open()], [sqlite3_open16()], and +** [sqlite3_open_v2()] interfaces are its constructors, and [sqlite3_close()] +** is its destructor. There are many other interfaces (such as +** [sqlite3_prepare_v2()], [sqlite3_create_function()], and +** [sqlite3_busy_timeout()] to name but three) that are methods on an +** sqlite3 object. +*/ +typedef struct sqlite3 sqlite3; + +/* +** CAPI3REF: 64-Bit Integer Types +** KEYWORDS: sqlite_int64 sqlite_uint64 +** +** Because there is no cross-platform way to specify 64-bit integer types +** SQLite includes typedefs for 64-bit signed and unsigned integers. +** +** The sqlite3_int64 and sqlite3_uint64 are the preferred type definitions. +** The sqlite_int64 and sqlite_uint64 types are supported for backwards +** compatibility only. +** +** ^The sqlite3_int64 and sqlite_int64 types can store integer values +** between -9223372036854775808 and +9223372036854775807 inclusive. ^The +** sqlite3_uint64 and sqlite_uint64 types can store integer values +** between 0 and +18446744073709551615 inclusive. +*/ +#ifdef SQLITE_INT64_TYPE + typedef SQLITE_INT64_TYPE sqlite_int64; + typedef unsigned SQLITE_INT64_TYPE sqlite_uint64; +#elif defined(_MSC_VER) || defined(__BORLANDC__) + typedef __int64 sqlite_int64; + typedef unsigned __int64 sqlite_uint64; +#else + typedef long long int sqlite_int64; + typedef unsigned long long int sqlite_uint64; +#endif +typedef sqlite_int64 sqlite3_int64; +typedef sqlite_uint64 sqlite3_uint64; + +/* +** If compiling for a processor that lacks floating point support, +** substitute integer for floating-point. +*/ +#ifdef SQLITE_OMIT_FLOATING_POINT +# define double sqlite3_int64 +#endif + +/* +** CAPI3REF: Closing A Database Connection +** +** ^The sqlite3_close() routine is the destructor for the [sqlite3] object. +** ^Calls to sqlite3_close() return SQLITE_OK if the [sqlite3] object is +** successfully destroyed and all associated resources are deallocated. +** +** Applications must [sqlite3_finalize | finalize] all [prepared statements] +** and [sqlite3_blob_close | close] all [BLOB handles] associated with +** the [sqlite3] object prior to attempting to close the object. ^If +** sqlite3_close() is called on a [database connection] that still has +** outstanding [prepared statements] or [BLOB handles], then it returns +** SQLITE_BUSY. +** +** ^If [sqlite3_close()] is invoked while a transaction is open, +** the transaction is automatically rolled back. +** +** The C parameter to [sqlite3_close(C)] must be either a NULL +** pointer or an [sqlite3] object pointer obtained +** from [sqlite3_open()], [sqlite3_open16()], or +** [sqlite3_open_v2()], and not previously closed. +** ^Calling sqlite3_close() with a NULL pointer argument is a +** harmless no-op. +*/ +SQLITE_API int sqlite3_close(sqlite3 *); + +/* +** The type for a callback function. +** This is legacy and deprecated. It is included for historical +** compatibility and is not documented. +*/ +typedef int (*sqlite3_callback)(void*,int,char**, char**); + +/* +** CAPI3REF: One-Step Query Execution Interface +** +** The sqlite3_exec() interface is a convenience wrapper around +** [sqlite3_prepare_v2()], [sqlite3_step()], and [sqlite3_finalize()], +** that allows an application to run multiple statements of SQL +** without having to use a lot of C code. +** +** ^The sqlite3_exec() interface runs zero or more UTF-8 encoded, +** semicolon-separate SQL statements passed into its 2nd argument, +** in the context of the [database connection] passed in as its 1st +** argument. ^If the callback function of the 3rd argument to +** sqlite3_exec() is not NULL, then it is invoked for each result row +** coming out of the evaluated SQL statements. ^The 4th argument to +** sqlite3_exec() is relayed through to the 1st argument of each +** callback invocation. ^If the callback pointer to sqlite3_exec() +** is NULL, then no callback is ever invoked and result rows are +** ignored. +** +** ^If an error occurs while evaluating the SQL statements passed into +** sqlite3_exec(), then execution of the current statement stops and +** subsequent statements are skipped. ^If the 5th parameter to sqlite3_exec() +** is not NULL then any error message is written into memory obtained +** from [sqlite3_malloc()] and passed back through the 5th parameter. +** To avoid memory leaks, the application should invoke [sqlite3_free()] +** on error message strings returned through the 5th parameter of +** of sqlite3_exec() after the error message string is no longer needed. +** ^If the 5th parameter to sqlite3_exec() is not NULL and no errors +** occur, then sqlite3_exec() sets the pointer in its 5th parameter to +** NULL before returning. +** +** ^If an sqlite3_exec() callback returns non-zero, the sqlite3_exec() +** routine returns SQLITE_ABORT without invoking the callback again and +** without running any subsequent SQL statements. +** +** ^The 2nd argument to the sqlite3_exec() callback function is the +** number of columns in the result. ^The 3rd argument to the sqlite3_exec() +** callback is an array of pointers to strings obtained as if from +** [sqlite3_column_text()], one for each column. ^If an element of a +** result row is NULL then the corresponding string pointer for the +** sqlite3_exec() callback is a NULL pointer. ^The 4th argument to the +** sqlite3_exec() callback is an array of pointers to strings where each +** entry represents the name of corresponding result column as obtained +** from [sqlite3_column_name()]. +** +** ^If the 2nd parameter to sqlite3_exec() is a NULL pointer, a pointer +** to an empty string, or a pointer that contains only whitespace and/or +** SQL comments, then no SQL statements are evaluated and the database +** is not changed. +** +** Restrictions: +** +**
    +**
  • The application must insure that the 1st parameter to sqlite3_exec() +** is a valid and open [database connection]. +**
  • The application must not close [database connection] specified by +** the 1st parameter to sqlite3_exec() while sqlite3_exec() is running. +**
  • The application must not modify the SQL statement text passed into +** the 2nd parameter of sqlite3_exec() while sqlite3_exec() is running. +**
+*/ +SQLITE_API int sqlite3_exec( + sqlite3*, /* An open database */ + const char *sql, /* SQL to be evaluated */ + int (*callback)(void*,int,char**,char**), /* Callback function */ + void *, /* 1st argument to callback */ + char **errmsg /* Error msg written here */ +); + +/* +** CAPI3REF: Result Codes +** KEYWORDS: SQLITE_OK {error code} {error codes} +** KEYWORDS: {result code} {result codes} +** +** Many SQLite functions return an integer result code from the set shown +** here in order to indicates success or failure. +** +** New error codes may be added in future versions of SQLite. +** +** See also: [SQLITE_IOERR_READ | extended result codes], +** [sqlite3_vtab_on_conflict()] [SQLITE_ROLLBACK | result codes]. +*/ +#define SQLITE_OK 0 /* Successful result */ +/* beginning-of-error-codes */ +#define SQLITE_ERROR 1 /* SQL error or missing database */ +#define SQLITE_INTERNAL 2 /* Internal logic error in SQLite */ +#define SQLITE_PERM 3 /* Access permission denied */ +#define SQLITE_ABORT 4 /* Callback routine requested an abort */ +#define SQLITE_BUSY 5 /* The database file is locked */ +#define SQLITE_LOCKED 6 /* A table in the database is locked */ +#define SQLITE_NOMEM 7 /* A malloc() failed */ +#define SQLITE_READONLY 8 /* Attempt to write a readonly database */ +#define SQLITE_INTERRUPT 9 /* Operation terminated by sqlite3_interrupt()*/ +#define SQLITE_IOERR 10 /* Some kind of disk I/O error occurred */ +#define SQLITE_CORRUPT 11 /* The database disk image is malformed */ +#define SQLITE_NOTFOUND 12 /* Unknown opcode in sqlite3_file_control() */ +#define SQLITE_FULL 13 /* Insertion failed because database is full */ +#define SQLITE_CANTOPEN 14 /* Unable to open the database file */ +#define SQLITE_PROTOCOL 15 /* Database lock protocol error */ +#define SQLITE_EMPTY 16 /* Database is empty */ +#define SQLITE_SCHEMA 17 /* The database schema changed */ +#define SQLITE_TOOBIG 18 /* String or BLOB exceeds size limit */ +#define SQLITE_CONSTRAINT 19 /* Abort due to constraint violation */ +#define SQLITE_MISMATCH 20 /* Data type mismatch */ +#define SQLITE_MISUSE 21 /* Library used incorrectly */ +#define SQLITE_NOLFS 22 /* Uses OS features not supported on host */ +#define SQLITE_AUTH 23 /* Authorization denied */ +#define SQLITE_FORMAT 24 /* Auxiliary database format error */ +#define SQLITE_RANGE 25 /* 2nd parameter to sqlite3_bind out of range */ +#define SQLITE_NOTADB 26 /* File opened that is not a database file */ +#define SQLITE_ROW 100 /* sqlite3_step() has another row ready */ +#define SQLITE_DONE 101 /* sqlite3_step() has finished executing */ +/* end-of-error-codes */ + +/* +** CAPI3REF: Extended Result Codes +** KEYWORDS: {extended error code} {extended error codes} +** KEYWORDS: {extended result code} {extended result codes} +** +** In its default configuration, SQLite API routines return one of 26 integer +** [SQLITE_OK | result codes]. However, experience has shown that many of +** these result codes are too coarse-grained. They do not provide as +** much information about problems as programmers might like. In an effort to +** address this, newer versions of SQLite (version 3.3.8 and later) include +** support for additional result codes that provide more detailed information +** about errors. The extended result codes are enabled or disabled +** on a per database connection basis using the +** [sqlite3_extended_result_codes()] API. +** +** Some of the available extended result codes are listed here. +** One may expect the number of extended result codes will be expand +** over time. Software that uses extended result codes should expect +** to see new result codes in future releases of SQLite. +** +** The SQLITE_OK result code will never be extended. It will always +** be exactly zero. +*/ +#define SQLITE_IOERR_READ (SQLITE_IOERR | (1<<8)) +#define SQLITE_IOERR_SHORT_READ (SQLITE_IOERR | (2<<8)) +#define SQLITE_IOERR_WRITE (SQLITE_IOERR | (3<<8)) +#define SQLITE_IOERR_FSYNC (SQLITE_IOERR | (4<<8)) +#define SQLITE_IOERR_DIR_FSYNC (SQLITE_IOERR | (5<<8)) +#define SQLITE_IOERR_TRUNCATE (SQLITE_IOERR | (6<<8)) +#define SQLITE_IOERR_FSTAT (SQLITE_IOERR | (7<<8)) +#define SQLITE_IOERR_UNLOCK (SQLITE_IOERR | (8<<8)) +#define SQLITE_IOERR_RDLOCK (SQLITE_IOERR | (9<<8)) +#define SQLITE_IOERR_DELETE (SQLITE_IOERR | (10<<8)) +#define SQLITE_IOERR_BLOCKED (SQLITE_IOERR | (11<<8)) +#define SQLITE_IOERR_NOMEM (SQLITE_IOERR | (12<<8)) +#define SQLITE_IOERR_ACCESS (SQLITE_IOERR | (13<<8)) +#define SQLITE_IOERR_CHECKRESERVEDLOCK (SQLITE_IOERR | (14<<8)) +#define SQLITE_IOERR_LOCK (SQLITE_IOERR | (15<<8)) +#define SQLITE_IOERR_CLOSE (SQLITE_IOERR | (16<<8)) +#define SQLITE_IOERR_DIR_CLOSE (SQLITE_IOERR | (17<<8)) +#define SQLITE_IOERR_SHMOPEN (SQLITE_IOERR | (18<<8)) +#define SQLITE_IOERR_SHMSIZE (SQLITE_IOERR | (19<<8)) +#define SQLITE_IOERR_SHMLOCK (SQLITE_IOERR | (20<<8)) +#define SQLITE_IOERR_SHMMAP (SQLITE_IOERR | (21<<8)) +#define SQLITE_IOERR_SEEK (SQLITE_IOERR | (22<<8)) +#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8)) +#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8)) +#define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8)) +#define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8)) +#define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8)) +#define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8)) + +/* +** CAPI3REF: Flags For File Open Operations +** +** These bit values are intended for use in the +** 3rd parameter to the [sqlite3_open_v2()] interface and +** in the 4th parameter to the [sqlite3_vfs.xOpen] method. +*/ +#define SQLITE_OPEN_READONLY 0x00000001 /* Ok for sqlite3_open_v2() */ +#define SQLITE_OPEN_READWRITE 0x00000002 /* Ok for sqlite3_open_v2() */ +#define SQLITE_OPEN_CREATE 0x00000004 /* Ok for sqlite3_open_v2() */ +#define SQLITE_OPEN_DELETEONCLOSE 0x00000008 /* VFS only */ +#define SQLITE_OPEN_EXCLUSIVE 0x00000010 /* VFS only */ +#define SQLITE_OPEN_AUTOPROXY 0x00000020 /* VFS only */ +#define SQLITE_OPEN_URI 0x00000040 /* Ok for sqlite3_open_v2() */ +#define SQLITE_OPEN_MAIN_DB 0x00000100 /* VFS only */ +#define SQLITE_OPEN_TEMP_DB 0x00000200 /* VFS only */ +#define SQLITE_OPEN_TRANSIENT_DB 0x00000400 /* VFS only */ +#define SQLITE_OPEN_MAIN_JOURNAL 0x00000800 /* VFS only */ +#define SQLITE_OPEN_TEMP_JOURNAL 0x00001000 /* VFS only */ +#define SQLITE_OPEN_SUBJOURNAL 0x00002000 /* VFS only */ +#define SQLITE_OPEN_MASTER_JOURNAL 0x00004000 /* VFS only */ +#define SQLITE_OPEN_NOMUTEX 0x00008000 /* Ok for sqlite3_open_v2() */ +#define SQLITE_OPEN_FULLMUTEX 0x00010000 /* Ok for sqlite3_open_v2() */ +#define SQLITE_OPEN_SHAREDCACHE 0x00020000 /* Ok for sqlite3_open_v2() */ +#define SQLITE_OPEN_PRIVATECACHE 0x00040000 /* Ok for sqlite3_open_v2() */ +#define SQLITE_OPEN_WAL 0x00080000 /* VFS only */ + +/* Reserved: 0x00F00000 */ + +/* +** CAPI3REF: Device Characteristics +** +** The xDeviceCharacteristics method of the [sqlite3_io_methods] +** object returns an integer which is a vector of the these +** bit values expressing I/O characteristics of the mass storage +** device that holds the file that the [sqlite3_io_methods] +** refers to. +** +** The SQLITE_IOCAP_ATOMIC property means that all writes of +** any size are atomic. The SQLITE_IOCAP_ATOMICnnn values +** mean that writes of blocks that are nnn bytes in size and +** are aligned to an address which is an integer multiple of +** nnn are atomic. The SQLITE_IOCAP_SAFE_APPEND value means +** that when data is appended to a file, the data is appended +** first then the size of the file is extended, never the other +** way around. The SQLITE_IOCAP_SEQUENTIAL property means that +** information is written to disk in the same order as calls +** to xWrite(). +*/ +#define SQLITE_IOCAP_ATOMIC 0x00000001 +#define SQLITE_IOCAP_ATOMIC512 0x00000002 +#define SQLITE_IOCAP_ATOMIC1K 0x00000004 +#define SQLITE_IOCAP_ATOMIC2K 0x00000008 +#define SQLITE_IOCAP_ATOMIC4K 0x00000010 +#define SQLITE_IOCAP_ATOMIC8K 0x00000020 +#define SQLITE_IOCAP_ATOMIC16K 0x00000040 +#define SQLITE_IOCAP_ATOMIC32K 0x00000080 +#define SQLITE_IOCAP_ATOMIC64K 0x00000100 +#define SQLITE_IOCAP_SAFE_APPEND 0x00000200 +#define SQLITE_IOCAP_SEQUENTIAL 0x00000400 +#define SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN 0x00000800 + +/* +** CAPI3REF: File Locking Levels +** +** SQLite uses one of these integer values as the second +** argument to calls it makes to the xLock() and xUnlock() methods +** of an [sqlite3_io_methods] object. +*/ +#define SQLITE_LOCK_NONE 0 +#define SQLITE_LOCK_SHARED 1 +#define SQLITE_LOCK_RESERVED 2 +#define SQLITE_LOCK_PENDING 3 +#define SQLITE_LOCK_EXCLUSIVE 4 + +/* +** CAPI3REF: Synchronization Type Flags +** +** When SQLite invokes the xSync() method of an +** [sqlite3_io_methods] object it uses a combination of +** these integer values as the second argument. +** +** When the SQLITE_SYNC_DATAONLY flag is used, it means that the +** sync operation only needs to flush data to mass storage. Inode +** information need not be flushed. If the lower four bits of the flag +** equal SQLITE_SYNC_NORMAL, that means to use normal fsync() semantics. +** If the lower four bits equal SQLITE_SYNC_FULL, that means +** to use Mac OS X style fullsync instead of fsync(). +** +** Do not confuse the SQLITE_SYNC_NORMAL and SQLITE_SYNC_FULL flags +** with the [PRAGMA synchronous]=NORMAL and [PRAGMA synchronous]=FULL +** settings. The [synchronous pragma] determines when calls to the +** xSync VFS method occur and applies uniformly across all platforms. +** The SQLITE_SYNC_NORMAL and SQLITE_SYNC_FULL flags determine how +** energetic or rigorous or forceful the sync operations are and +** only make a difference on Mac OSX for the default SQLite code. +** (Third-party VFS implementations might also make the distinction +** between SQLITE_SYNC_NORMAL and SQLITE_SYNC_FULL, but among the +** operating systems natively supported by SQLite, only Mac OSX +** cares about the difference.) +*/ +#define SQLITE_SYNC_NORMAL 0x00002 +#define SQLITE_SYNC_FULL 0x00003 +#define SQLITE_SYNC_DATAONLY 0x00010 + +/* +** CAPI3REF: OS Interface Open File Handle +** +** An [sqlite3_file] object represents an open file in the +** [sqlite3_vfs | OS interface layer]. Individual OS interface +** implementations will +** want to subclass this object by appending additional fields +** for their own use. The pMethods entry is a pointer to an +** [sqlite3_io_methods] object that defines methods for performing +** I/O operations on the open file. +*/ +typedef struct sqlite3_file sqlite3_file; +struct sqlite3_file { + const struct sqlite3_io_methods *pMethods; /* Methods for an open file */ +}; + +/* +** CAPI3REF: OS Interface File Virtual Methods Object +** +** Every file opened by the [sqlite3_vfs.xOpen] method populates an +** [sqlite3_file] object (or, more commonly, a subclass of the +** [sqlite3_file] object) with a pointer to an instance of this object. +** This object defines the methods used to perform various operations +** against the open file represented by the [sqlite3_file] object. +** +** If the [sqlite3_vfs.xOpen] method sets the sqlite3_file.pMethods element +** to a non-NULL pointer, then the sqlite3_io_methods.xClose method +** may be invoked even if the [sqlite3_vfs.xOpen] reported that it failed. The +** only way to prevent a call to xClose following a failed [sqlite3_vfs.xOpen] +** is for the [sqlite3_vfs.xOpen] to set the sqlite3_file.pMethods element +** to NULL. +** +** The flags argument to xSync may be one of [SQLITE_SYNC_NORMAL] or +** [SQLITE_SYNC_FULL]. The first choice is the normal fsync(). +** The second choice is a Mac OS X style fullsync. The [SQLITE_SYNC_DATAONLY] +** flag may be ORed in to indicate that only the data of the file +** and not its inode needs to be synced. +** +** The integer values to xLock() and xUnlock() are one of +**
    +**
  • [SQLITE_LOCK_NONE], +**
  • [SQLITE_LOCK_SHARED], +**
  • [SQLITE_LOCK_RESERVED], +**
  • [SQLITE_LOCK_PENDING], or +**
  • [SQLITE_LOCK_EXCLUSIVE]. +**
+** xLock() increases the lock. xUnlock() decreases the lock. +** The xCheckReservedLock() method checks whether any database connection, +** either in this process or in some other process, is holding a RESERVED, +** PENDING, or EXCLUSIVE lock on the file. It returns true +** if such a lock exists and false otherwise. +** +** The xFileControl() method is a generic interface that allows custom +** VFS implementations to directly control an open file using the +** [sqlite3_file_control()] interface. The second "op" argument is an +** integer opcode. The third argument is a generic pointer intended to +** point to a structure that may contain arguments or space in which to +** write return values. Potential uses for xFileControl() might be +** functions to enable blocking locks with timeouts, to change the +** locking strategy (for example to use dot-file locks), to inquire +** about the status of a lock, or to break stale locks. The SQLite +** core reserves all opcodes less than 100 for its own use. +** A [SQLITE_FCNTL_LOCKSTATE | list of opcodes] less than 100 is available. +** Applications that define a custom xFileControl method should use opcodes +** greater than 100 to avoid conflicts. VFS implementations should +** return [SQLITE_NOTFOUND] for file control opcodes that they do not +** recognize. +** +** The xSectorSize() method returns the sector size of the +** device that underlies the file. The sector size is the +** minimum write that can be performed without disturbing +** other bytes in the file. The xDeviceCharacteristics() +** method returns a bit vector describing behaviors of the +** underlying device: +** +**
    +**
  • [SQLITE_IOCAP_ATOMIC] +**
  • [SQLITE_IOCAP_ATOMIC512] +**
  • [SQLITE_IOCAP_ATOMIC1K] +**
  • [SQLITE_IOCAP_ATOMIC2K] +**
  • [SQLITE_IOCAP_ATOMIC4K] +**
  • [SQLITE_IOCAP_ATOMIC8K] +**
  • [SQLITE_IOCAP_ATOMIC16K] +**
  • [SQLITE_IOCAP_ATOMIC32K] +**
  • [SQLITE_IOCAP_ATOMIC64K] +**
  • [SQLITE_IOCAP_SAFE_APPEND] +**
  • [SQLITE_IOCAP_SEQUENTIAL] +**
+** +** The SQLITE_IOCAP_ATOMIC property means that all writes of +** any size are atomic. The SQLITE_IOCAP_ATOMICnnn values +** mean that writes of blocks that are nnn bytes in size and +** are aligned to an address which is an integer multiple of +** nnn are atomic. The SQLITE_IOCAP_SAFE_APPEND value means +** that when data is appended to a file, the data is appended +** first then the size of the file is extended, never the other +** way around. The SQLITE_IOCAP_SEQUENTIAL property means that +** information is written to disk in the same order as calls +** to xWrite(). +** +** If xRead() returns SQLITE_IOERR_SHORT_READ it must also fill +** in the unread portions of the buffer with zeros. A VFS that +** fails to zero-fill short reads might seem to work. However, +** failure to zero-fill short reads will eventually lead to +** database corruption. +*/ +typedef struct sqlite3_io_methods sqlite3_io_methods; +struct sqlite3_io_methods { + int iVersion; + int (*xClose)(sqlite3_file*); + int (*xRead)(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst); + int (*xWrite)(sqlite3_file*, const void*, int iAmt, sqlite3_int64 iOfst); + int (*xTruncate)(sqlite3_file*, sqlite3_int64 size); + int (*xSync)(sqlite3_file*, int flags); + int (*xFileSize)(sqlite3_file*, sqlite3_int64 *pSize); + int (*xLock)(sqlite3_file*, int); + int (*xUnlock)(sqlite3_file*, int); + int (*xCheckReservedLock)(sqlite3_file*, int *pResOut); + int (*xFileControl)(sqlite3_file*, int op, void *pArg); + int (*xSectorSize)(sqlite3_file*); + int (*xDeviceCharacteristics)(sqlite3_file*); + /* Methods above are valid for version 1 */ + int (*xShmMap)(sqlite3_file*, int iPg, int pgsz, int, void volatile**); + int (*xShmLock)(sqlite3_file*, int offset, int n, int flags); + void (*xShmBarrier)(sqlite3_file*); + int (*xShmUnmap)(sqlite3_file*, int deleteFlag); + /* Methods above are valid for version 2 */ + /* Additional methods may be added in future releases */ +}; + +/* +** CAPI3REF: Standard File Control Opcodes +** +** These integer constants are opcodes for the xFileControl method +** of the [sqlite3_io_methods] object and for the [sqlite3_file_control()] +** interface. +** +** The [SQLITE_FCNTL_LOCKSTATE] opcode is used for debugging. This +** opcode causes the xFileControl method to write the current state of +** the lock (one of [SQLITE_LOCK_NONE], [SQLITE_LOCK_SHARED], +** [SQLITE_LOCK_RESERVED], [SQLITE_LOCK_PENDING], or [SQLITE_LOCK_EXCLUSIVE]) +** into an integer that the pArg argument points to. This capability +** is used during testing and only needs to be supported when SQLITE_TEST +** is defined. +** +** The [SQLITE_FCNTL_SIZE_HINT] opcode is used by SQLite to give the VFS +** layer a hint of how large the database file will grow to be during the +** current transaction. This hint is not guaranteed to be accurate but it +** is often close. The underlying VFS might choose to preallocate database +** file space based on this hint in order to help writes to the database +** file run faster. +** +** The [SQLITE_FCNTL_CHUNK_SIZE] opcode is used to request that the VFS +** extends and truncates the database file in chunks of a size specified +** by the user. The fourth argument to [sqlite3_file_control()] should +** point to an integer (type int) containing the new chunk-size to use +** for the nominated database. Allocating database file space in large +** chunks (say 1MB at a time), may reduce file-system fragmentation and +** improve performance on some systems. +** +** The [SQLITE_FCNTL_FILE_POINTER] opcode is used to obtain a pointer +** to the [sqlite3_file] object associated with a particular database +** connection. See the [sqlite3_file_control()] documentation for +** additional information. +** +** ^(The [SQLITE_FCNTL_SYNC_OMITTED] opcode is generated internally by +** SQLite and sent to all VFSes in place of a call to the xSync method +** when the database connection has [PRAGMA synchronous] set to OFF.)^ +** Some specialized VFSes need this signal in order to operate correctly +** when [PRAGMA synchronous | PRAGMA synchronous=OFF] is set, but most +** VFSes do not need this signal and should silently ignore this opcode. +** Applications should not call [sqlite3_file_control()] with this +** opcode as doing so may disrupt the operation of the specialized VFSes +** that do require it. +*/ +#define SQLITE_FCNTL_LOCKSTATE 1 +#define SQLITE_GET_LOCKPROXYFILE 2 +#define SQLITE_SET_LOCKPROXYFILE 3 +#define SQLITE_LAST_ERRNO 4 +#define SQLITE_FCNTL_SIZE_HINT 5 +#define SQLITE_FCNTL_CHUNK_SIZE 6 +#define SQLITE_FCNTL_FILE_POINTER 7 +#define SQLITE_FCNTL_SYNC_OMITTED 8 + + +/* +** CAPI3REF: Mutex Handle +** +** The mutex module within SQLite defines [sqlite3_mutex] to be an +** abstract type for a mutex object. The SQLite core never looks +** at the internal representation of an [sqlite3_mutex]. It only +** deals with pointers to the [sqlite3_mutex] object. +** +** Mutexes are created using [sqlite3_mutex_alloc()]. +*/ +typedef struct sqlite3_mutex sqlite3_mutex; + +/* +** CAPI3REF: OS Interface Object +** +** An instance of the sqlite3_vfs object defines the interface between +** the SQLite core and the underlying operating system. The "vfs" +** in the name of the object stands for "virtual file system". See +** the [VFS | VFS documentation] for further information. +** +** The value of the iVersion field is initially 1 but may be larger in +** future versions of SQLite. Additional fields may be appended to this +** object when the iVersion value is increased. Note that the structure +** of the sqlite3_vfs object changes in the transaction between +** SQLite version 3.5.9 and 3.6.0 and yet the iVersion field was not +** modified. +** +** The szOsFile field is the size of the subclassed [sqlite3_file] +** structure used by this VFS. mxPathname is the maximum length of +** a pathname in this VFS. +** +** Registered sqlite3_vfs objects are kept on a linked list formed by +** the pNext pointer. The [sqlite3_vfs_register()] +** and [sqlite3_vfs_unregister()] interfaces manage this list +** in a thread-safe way. The [sqlite3_vfs_find()] interface +** searches the list. Neither the application code nor the VFS +** implementation should use the pNext pointer. +** +** The pNext field is the only field in the sqlite3_vfs +** structure that SQLite will ever modify. SQLite will only access +** or modify this field while holding a particular static mutex. +** The application should never modify anything within the sqlite3_vfs +** object once the object has been registered. +** +** The zName field holds the name of the VFS module. The name must +** be unique across all VFS modules. +** +** [[sqlite3_vfs.xOpen]] +** ^SQLite guarantees that the zFilename parameter to xOpen +** is either a NULL pointer or string obtained +** from xFullPathname() with an optional suffix added. +** ^If a suffix is added to the zFilename parameter, it will +** consist of a single "-" character followed by no more than +** 10 alphanumeric and/or "-" characters. +** ^SQLite further guarantees that +** the string will be valid and unchanged until xClose() is +** called. Because of the previous sentence, +** the [sqlite3_file] can safely store a pointer to the +** filename if it needs to remember the filename for some reason. +** If the zFilename parameter to xOpen is a NULL pointer then xOpen +** must invent its own temporary name for the file. ^Whenever the +** xFilename parameter is NULL it will also be the case that the +** flags parameter will include [SQLITE_OPEN_DELETEONCLOSE]. +** +** The flags argument to xOpen() includes all bits set in +** the flags argument to [sqlite3_open_v2()]. Or if [sqlite3_open()] +** or [sqlite3_open16()] is used, then flags includes at least +** [SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE]. +** If xOpen() opens a file read-only then it sets *pOutFlags to +** include [SQLITE_OPEN_READONLY]. Other bits in *pOutFlags may be set. +** +** ^(SQLite will also add one of the following flags to the xOpen() +** call, depending on the object being opened: +** +**
    +**
  • [SQLITE_OPEN_MAIN_DB] +**
  • [SQLITE_OPEN_MAIN_JOURNAL] +**
  • [SQLITE_OPEN_TEMP_DB] +**
  • [SQLITE_OPEN_TEMP_JOURNAL] +**
  • [SQLITE_OPEN_TRANSIENT_DB] +**
  • [SQLITE_OPEN_SUBJOURNAL] +**
  • [SQLITE_OPEN_MASTER_JOURNAL] +**
  • [SQLITE_OPEN_WAL] +**
)^ +** +** The file I/O implementation can use the object type flags to +** change the way it deals with files. For example, an application +** that does not care about crash recovery or rollback might make +** the open of a journal file a no-op. Writes to this journal would +** also be no-ops, and any attempt to read the journal would return +** SQLITE_IOERR. Or the implementation might recognize that a database +** file will be doing page-aligned sector reads and writes in a random +** order and set up its I/O subsystem accordingly. +** +** SQLite might also add one of the following flags to the xOpen method: +** +**
    +**
  • [SQLITE_OPEN_DELETEONCLOSE] +**
  • [SQLITE_OPEN_EXCLUSIVE] +**
+** +** The [SQLITE_OPEN_DELETEONCLOSE] flag means the file should be +** deleted when it is closed. ^The [SQLITE_OPEN_DELETEONCLOSE] +** will be set for TEMP databases and their journals, transient +** databases, and subjournals. +** +** ^The [SQLITE_OPEN_EXCLUSIVE] flag is always used in conjunction +** with the [SQLITE_OPEN_CREATE] flag, which are both directly +** analogous to the O_EXCL and O_CREAT flags of the POSIX open() +** API. The SQLITE_OPEN_EXCLUSIVE flag, when paired with the +** SQLITE_OPEN_CREATE, is used to indicate that file should always +** be created, and that it is an error if it already exists. +** It is not used to indicate the file should be opened +** for exclusive access. +** +** ^At least szOsFile bytes of memory are allocated by SQLite +** to hold the [sqlite3_file] structure passed as the third +** argument to xOpen. The xOpen method does not have to +** allocate the structure; it should just fill it in. Note that +** the xOpen method must set the sqlite3_file.pMethods to either +** a valid [sqlite3_io_methods] object or to NULL. xOpen must do +** this even if the open fails. SQLite expects that the sqlite3_file.pMethods +** element will be valid after xOpen returns regardless of the success +** or failure of the xOpen call. +** +** [[sqlite3_vfs.xAccess]] +** ^The flags argument to xAccess() may be [SQLITE_ACCESS_EXISTS] +** to test for the existence of a file, or [SQLITE_ACCESS_READWRITE] to +** test whether a file is readable and writable, or [SQLITE_ACCESS_READ] +** to test whether a file is at least readable. The file can be a +** directory. +** +** ^SQLite will always allocate at least mxPathname+1 bytes for the +** output buffer xFullPathname. The exact size of the output buffer +** is also passed as a parameter to both methods. If the output buffer +** is not large enough, [SQLITE_CANTOPEN] should be returned. Since this is +** handled as a fatal error by SQLite, vfs implementations should endeavor +** to prevent this by setting mxPathname to a sufficiently large value. +** +** The xRandomness(), xSleep(), xCurrentTime(), and xCurrentTimeInt64() +** interfaces are not strictly a part of the filesystem, but they are +** included in the VFS structure for completeness. +** The xRandomness() function attempts to return nBytes bytes +** of good-quality randomness into zOut. The return value is +** the actual number of bytes of randomness obtained. +** The xSleep() method causes the calling thread to sleep for at +** least the number of microseconds given. ^The xCurrentTime() +** method returns a Julian Day Number for the current date and time as +** a floating point value. +** ^The xCurrentTimeInt64() method returns, as an integer, the Julian +** Day Number multiplied by 86400000 (the number of milliseconds in +** a 24-hour day). +** ^SQLite will use the xCurrentTimeInt64() method to get the current +** date and time if that method is available (if iVersion is 2 or +** greater and the function pointer is not NULL) and will fall back +** to xCurrentTime() if xCurrentTimeInt64() is unavailable. +** +** ^The xSetSystemCall(), xGetSystemCall(), and xNestSystemCall() interfaces +** are not used by the SQLite core. These optional interfaces are provided +** by some VFSes to facilitate testing of the VFS code. By overriding +** system calls with functions under its control, a test program can +** simulate faults and error conditions that would otherwise be difficult +** or impossible to induce. The set of system calls that can be overridden +** varies from one VFS to another, and from one version of the same VFS to the +** next. Applications that use these interfaces must be prepared for any +** or all of these interfaces to be NULL or for their behavior to change +** from one release to the next. Applications must not attempt to access +** any of these methods if the iVersion of the VFS is less than 3. +*/ +typedef struct sqlite3_vfs sqlite3_vfs; +typedef void (*sqlite3_syscall_ptr)(void); +struct sqlite3_vfs { + int iVersion; /* Structure version number (currently 3) */ + int szOsFile; /* Size of subclassed sqlite3_file */ + int mxPathname; /* Maximum file pathname length */ + sqlite3_vfs *pNext; /* Next registered VFS */ + const char *zName; /* Name of this virtual file system */ + void *pAppData; /* Pointer to application-specific data */ + int (*xOpen)(sqlite3_vfs*, const char *zName, sqlite3_file*, + int flags, int *pOutFlags); + int (*xDelete)(sqlite3_vfs*, const char *zName, int syncDir); + int (*xAccess)(sqlite3_vfs*, const char *zName, int flags, int *pResOut); + int (*xFullPathname)(sqlite3_vfs*, const char *zName, int nOut, char *zOut); + void *(*xDlOpen)(sqlite3_vfs*, const char *zFilename); + void (*xDlError)(sqlite3_vfs*, int nByte, char *zErrMsg); + void (*(*xDlSym)(sqlite3_vfs*,void*, const char *zSymbol))(void); + void (*xDlClose)(sqlite3_vfs*, void*); + int (*xRandomness)(sqlite3_vfs*, int nByte, char *zOut); + int (*xSleep)(sqlite3_vfs*, int microseconds); + int (*xCurrentTime)(sqlite3_vfs*, double*); + int (*xGetLastError)(sqlite3_vfs*, int, char *); + /* + ** The methods above are in version 1 of the sqlite_vfs object + ** definition. Those that follow are added in version 2 or later + */ + int (*xCurrentTimeInt64)(sqlite3_vfs*, sqlite3_int64*); + /* + ** The methods above are in versions 1 and 2 of the sqlite_vfs object. + ** Those below are for version 3 and greater. + */ + int (*xSetSystemCall)(sqlite3_vfs*, const char *zName, sqlite3_syscall_ptr); + sqlite3_syscall_ptr (*xGetSystemCall)(sqlite3_vfs*, const char *zName); + const char *(*xNextSystemCall)(sqlite3_vfs*, const char *zName); + /* + ** The methods above are in versions 1 through 3 of the sqlite_vfs object. + ** New fields may be appended in figure versions. The iVersion + ** value will increment whenever this happens. + */ +}; + +/* +** CAPI3REF: Flags for the xAccess VFS method +** +** These integer constants can be used as the third parameter to +** the xAccess method of an [sqlite3_vfs] object. They determine +** what kind of permissions the xAccess method is looking for. +** With SQLITE_ACCESS_EXISTS, the xAccess method +** simply checks whether the file exists. +** With SQLITE_ACCESS_READWRITE, the xAccess method +** checks whether the named directory is both readable and writable +** (in other words, if files can be added, removed, and renamed within +** the directory). +** The SQLITE_ACCESS_READWRITE constant is currently used only by the +** [temp_store_directory pragma], though this could change in a future +** release of SQLite. +** With SQLITE_ACCESS_READ, the xAccess method +** checks whether the file is readable. The SQLITE_ACCESS_READ constant is +** currently unused, though it might be used in a future release of +** SQLite. +*/ +#define SQLITE_ACCESS_EXISTS 0 +#define SQLITE_ACCESS_READWRITE 1 /* Used by PRAGMA temp_store_directory */ +#define SQLITE_ACCESS_READ 2 /* Unused */ + +/* +** CAPI3REF: Flags for the xShmLock VFS method +** +** These integer constants define the various locking operations +** allowed by the xShmLock method of [sqlite3_io_methods]. The +** following are the only legal combinations of flags to the +** xShmLock method: +** +**
    +**
  • SQLITE_SHM_LOCK | SQLITE_SHM_SHARED +**
  • SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE +**
  • SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED +**
  • SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE +**
+** +** When unlocking, the same SHARED or EXCLUSIVE flag must be supplied as +** was given no the corresponding lock. +** +** The xShmLock method can transition between unlocked and SHARED or +** between unlocked and EXCLUSIVE. It cannot transition between SHARED +** and EXCLUSIVE. +*/ +#define SQLITE_SHM_UNLOCK 1 +#define SQLITE_SHM_LOCK 2 +#define SQLITE_SHM_SHARED 4 +#define SQLITE_SHM_EXCLUSIVE 8 + +/* +** CAPI3REF: Maximum xShmLock index +** +** The xShmLock method on [sqlite3_io_methods] may use values +** between 0 and this upper bound as its "offset" argument. +** The SQLite core will never attempt to acquire or release a +** lock outside of this range +*/ +#define SQLITE_SHM_NLOCK 8 + + +/* +** CAPI3REF: Initialize The SQLite Library +** +** ^The sqlite3_initialize() routine initializes the +** SQLite library. ^The sqlite3_shutdown() routine +** deallocates any resources that were allocated by sqlite3_initialize(). +** These routines are designed to aid in process initialization and +** shutdown on embedded systems. Workstation applications using +** SQLite normally do not need to invoke either of these routines. +** +** A call to sqlite3_initialize() is an "effective" call if it is +** the first time sqlite3_initialize() is invoked during the lifetime of +** the process, or if it is the first time sqlite3_initialize() is invoked +** following a call to sqlite3_shutdown(). ^(Only an effective call +** of sqlite3_initialize() does any initialization. All other calls +** are harmless no-ops.)^ +** +** A call to sqlite3_shutdown() is an "effective" call if it is the first +** call to sqlite3_shutdown() since the last sqlite3_initialize(). ^(Only +** an effective call to sqlite3_shutdown() does any deinitialization. +** All other valid calls to sqlite3_shutdown() are harmless no-ops.)^ +** +** The sqlite3_initialize() interface is threadsafe, but sqlite3_shutdown() +** is not. The sqlite3_shutdown() interface must only be called from a +** single thread. All open [database connections] must be closed and all +** other SQLite resources must be deallocated prior to invoking +** sqlite3_shutdown(). +** +** Among other things, ^sqlite3_initialize() will invoke +** sqlite3_os_init(). Similarly, ^sqlite3_shutdown() +** will invoke sqlite3_os_end(). +** +** ^The sqlite3_initialize() routine returns [SQLITE_OK] on success. +** ^If for some reason, sqlite3_initialize() is unable to initialize +** the library (perhaps it is unable to allocate a needed resource such +** as a mutex) it returns an [error code] other than [SQLITE_OK]. +** +** ^The sqlite3_initialize() routine is called internally by many other +** SQLite interfaces so that an application usually does not need to +** invoke sqlite3_initialize() directly. For example, [sqlite3_open()] +** calls sqlite3_initialize() so the SQLite library will be automatically +** initialized when [sqlite3_open()] is called if it has not be initialized +** already. ^However, if SQLite is compiled with the [SQLITE_OMIT_AUTOINIT] +** compile-time option, then the automatic calls to sqlite3_initialize() +** are omitted and the application must call sqlite3_initialize() directly +** prior to using any other SQLite interface. For maximum portability, +** it is recommended that applications always invoke sqlite3_initialize() +** directly prior to using any other SQLite interface. Future releases +** of SQLite may require this. In other words, the behavior exhibited +** when SQLite is compiled with [SQLITE_OMIT_AUTOINIT] might become the +** default behavior in some future release of SQLite. +** +** The sqlite3_os_init() routine does operating-system specific +** initialization of the SQLite library. The sqlite3_os_end() +** routine undoes the effect of sqlite3_os_init(). Typical tasks +** performed by these routines include allocation or deallocation +** of static resources, initialization of global variables, +** setting up a default [sqlite3_vfs] module, or setting up +** a default configuration using [sqlite3_config()]. +** +** The application should never invoke either sqlite3_os_init() +** or sqlite3_os_end() directly. The application should only invoke +** sqlite3_initialize() and sqlite3_shutdown(). The sqlite3_os_init() +** interface is called automatically by sqlite3_initialize() and +** sqlite3_os_end() is called by sqlite3_shutdown(). Appropriate +** implementations for sqlite3_os_init() and sqlite3_os_end() +** are built into SQLite when it is compiled for Unix, Windows, or OS/2. +** When [custom builds | built for other platforms] +** (using the [SQLITE_OS_OTHER=1] compile-time +** option) the application must supply a suitable implementation for +** sqlite3_os_init() and sqlite3_os_end(). An application-supplied +** implementation of sqlite3_os_init() or sqlite3_os_end() +** must return [SQLITE_OK] on success and some other [error code] upon +** failure. +*/ +SQLITE_API int sqlite3_initialize(void); +SQLITE_API int sqlite3_shutdown(void); +SQLITE_API int sqlite3_os_init(void); +SQLITE_API int sqlite3_os_end(void); + +/* +** CAPI3REF: Configuring The SQLite Library +** +** The sqlite3_config() interface is used to make global configuration +** changes to SQLite in order to tune SQLite to the specific needs of +** the application. The default configuration is recommended for most +** applications and so this routine is usually not necessary. It is +** provided to support rare applications with unusual needs. +** +** The sqlite3_config() interface is not threadsafe. The application +** must insure that no other SQLite interfaces are invoked by other +** threads while sqlite3_config() is running. Furthermore, sqlite3_config() +** may only be invoked prior to library initialization using +** [sqlite3_initialize()] or after shutdown by [sqlite3_shutdown()]. +** ^If sqlite3_config() is called after [sqlite3_initialize()] and before +** [sqlite3_shutdown()] then it will return SQLITE_MISUSE. +** Note, however, that ^sqlite3_config() can be called as part of the +** implementation of an application-defined [sqlite3_os_init()]. +** +** The first argument to sqlite3_config() is an integer +** [configuration option] that determines +** what property of SQLite is to be configured. Subsequent arguments +** vary depending on the [configuration option] +** in the first argument. +** +** ^When a configuration option is set, sqlite3_config() returns [SQLITE_OK]. +** ^If the option is unknown or SQLite is unable to set the option +** then this routine returns a non-zero [error code]. +*/ +SQLITE_API int sqlite3_config(int, ...); + +/* +** CAPI3REF: Configure database connections +** +** The sqlite3_db_config() interface is used to make configuration +** changes to a [database connection]. The interface is similar to +** [sqlite3_config()] except that the changes apply to a single +** [database connection] (specified in the first argument). +** +** The second argument to sqlite3_db_config(D,V,...) is the +** [SQLITE_DBCONFIG_LOOKASIDE | configuration verb] - an integer code +** that indicates what aspect of the [database connection] is being configured. +** Subsequent arguments vary depending on the configuration verb. +** +** ^Calls to sqlite3_db_config() return SQLITE_OK if and only if +** the call is considered successful. +*/ +SQLITE_API int sqlite3_db_config(sqlite3*, int op, ...); + +/* +** CAPI3REF: Memory Allocation Routines +** +** An instance of this object defines the interface between SQLite +** and low-level memory allocation routines. +** +** This object is used in only one place in the SQLite interface. +** A pointer to an instance of this object is the argument to +** [sqlite3_config()] when the configuration option is +** [SQLITE_CONFIG_MALLOC] or [SQLITE_CONFIG_GETMALLOC]. +** By creating an instance of this object +** and passing it to [sqlite3_config]([SQLITE_CONFIG_MALLOC]) +** during configuration, an application can specify an alternative +** memory allocation subsystem for SQLite to use for all of its +** dynamic memory needs. +** +** Note that SQLite comes with several [built-in memory allocators] +** that are perfectly adequate for the overwhelming majority of applications +** and that this object is only useful to a tiny minority of applications +** with specialized memory allocation requirements. This object is +** also used during testing of SQLite in order to specify an alternative +** memory allocator that simulates memory out-of-memory conditions in +** order to verify that SQLite recovers gracefully from such +** conditions. +** +** The xMalloc and xFree methods must work like the +** malloc() and free() functions from the standard C library. +** The xRealloc method must work like realloc() from the standard C library +** with the exception that if the second argument to xRealloc is zero, +** xRealloc must be a no-op - it must not perform any allocation or +** deallocation. ^SQLite guarantees that the second argument to +** xRealloc is always a value returned by a prior call to xRoundup. +** And so in cases where xRoundup always returns a positive number, +** xRealloc can perform exactly as the standard library realloc() and +** still be in compliance with this specification. +** +** xSize should return the allocated size of a memory allocation +** previously obtained from xMalloc or xRealloc. The allocated size +** is always at least as big as the requested size but may be larger. +** +** The xRoundup method returns what would be the allocated size of +** a memory allocation given a particular requested size. Most memory +** allocators round up memory allocations at least to the next multiple +** of 8. Some allocators round up to a larger multiple or to a power of 2. +** Every memory allocation request coming in through [sqlite3_malloc()] +** or [sqlite3_realloc()] first calls xRoundup. If xRoundup returns 0, +** that causes the corresponding memory allocation to fail. +** +** The xInit method initializes the memory allocator. (For example, +** it might allocate any require mutexes or initialize internal data +** structures. The xShutdown method is invoked (indirectly) by +** [sqlite3_shutdown()] and should deallocate any resources acquired +** by xInit. The pAppData pointer is used as the only parameter to +** xInit and xShutdown. +** +** SQLite holds the [SQLITE_MUTEX_STATIC_MASTER] mutex when it invokes +** the xInit method, so the xInit method need not be threadsafe. The +** xShutdown method is only called from [sqlite3_shutdown()] so it does +** not need to be threadsafe either. For all other methods, SQLite +** holds the [SQLITE_MUTEX_STATIC_MEM] mutex as long as the +** [SQLITE_CONFIG_MEMSTATUS] configuration option is turned on (which +** it is by default) and so the methods are automatically serialized. +** However, if [SQLITE_CONFIG_MEMSTATUS] is disabled, then the other +** methods must be threadsafe or else make their own arrangements for +** serialization. +** +** SQLite will never invoke xInit() more than once without an intervening +** call to xShutdown(). +*/ +typedef struct sqlite3_mem_methods sqlite3_mem_methods; +struct sqlite3_mem_methods { + void *(*xMalloc)(int); /* Memory allocation function */ + void (*xFree)(void*); /* Free a prior allocation */ + void *(*xRealloc)(void*,int); /* Resize an allocation */ + int (*xSize)(void*); /* Return the size of an allocation */ + int (*xRoundup)(int); /* Round up request size to allocation size */ + int (*xInit)(void*); /* Initialize the memory allocator */ + void (*xShutdown)(void*); /* Deinitialize the memory allocator */ + void *pAppData; /* Argument to xInit() and xShutdown() */ +}; + +/* +** CAPI3REF: Configuration Options +** KEYWORDS: {configuration option} +** +** These constants are the available integer configuration options that +** can be passed as the first argument to the [sqlite3_config()] interface. +** +** New configuration options may be added in future releases of SQLite. +** Existing configuration options might be discontinued. Applications +** should check the return code from [sqlite3_config()] to make sure that +** the call worked. The [sqlite3_config()] interface will return a +** non-zero [error code] if a discontinued or unsupported configuration option +** is invoked. +** +**
+** [[SQLITE_CONFIG_SINGLETHREAD]]
SQLITE_CONFIG_SINGLETHREAD
+**
There are no arguments to this option. ^This option sets the +** [threading mode] to Single-thread. In other words, it disables +** all mutexing and puts SQLite into a mode where it can only be used +** by a single thread. ^If SQLite is compiled with +** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then +** it is not possible to change the [threading mode] from its default +** value of Single-thread and so [sqlite3_config()] will return +** [SQLITE_ERROR] if called with the SQLITE_CONFIG_SINGLETHREAD +** configuration option.
+** +** [[SQLITE_CONFIG_MULTITHREAD]]
SQLITE_CONFIG_MULTITHREAD
+**
There are no arguments to this option. ^This option sets the +** [threading mode] to Multi-thread. In other words, it disables +** mutexing on [database connection] and [prepared statement] objects. +** The application is responsible for serializing access to +** [database connections] and [prepared statements]. But other mutexes +** are enabled so that SQLite will be safe to use in a multi-threaded +** environment as long as no two threads attempt to use the same +** [database connection] at the same time. ^If SQLite is compiled with +** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then +** it is not possible to set the Multi-thread [threading mode] and +** [sqlite3_config()] will return [SQLITE_ERROR] if called with the +** SQLITE_CONFIG_MULTITHREAD configuration option.
+** +** [[SQLITE_CONFIG_SERIALIZED]]
SQLITE_CONFIG_SERIALIZED
+**
There are no arguments to this option. ^This option sets the +** [threading mode] to Serialized. In other words, this option enables +** all mutexes including the recursive +** mutexes on [database connection] and [prepared statement] objects. +** In this mode (which is the default when SQLite is compiled with +** [SQLITE_THREADSAFE=1]) the SQLite library will itself serialize access +** to [database connections] and [prepared statements] so that the +** application is free to use the same [database connection] or the +** same [prepared statement] in different threads at the same time. +** ^If SQLite is compiled with +** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then +** it is not possible to set the Serialized [threading mode] and +** [sqlite3_config()] will return [SQLITE_ERROR] if called with the +** SQLITE_CONFIG_SERIALIZED configuration option.
+** +** [[SQLITE_CONFIG_MALLOC]]
SQLITE_CONFIG_MALLOC
+**
^(This option takes a single argument which is a pointer to an +** instance of the [sqlite3_mem_methods] structure. The argument specifies +** alternative low-level memory allocation routines to be used in place of +** the memory allocation routines built into SQLite.)^ ^SQLite makes +** its own private copy of the content of the [sqlite3_mem_methods] structure +** before the [sqlite3_config()] call returns.
+** +** [[SQLITE_CONFIG_GETMALLOC]]
SQLITE_CONFIG_GETMALLOC
+**
^(This option takes a single argument which is a pointer to an +** instance of the [sqlite3_mem_methods] structure. The [sqlite3_mem_methods] +** structure is filled with the currently defined memory allocation routines.)^ +** This option can be used to overload the default memory allocation +** routines with a wrapper that simulations memory allocation failure or +** tracks memory usage, for example.
+** +** [[SQLITE_CONFIG_MEMSTATUS]]
SQLITE_CONFIG_MEMSTATUS
+**
^This option takes single argument of type int, interpreted as a +** boolean, which enables or disables the collection of memory allocation +** statistics. ^(When memory allocation statistics are disabled, the +** following SQLite interfaces become non-operational: +**
    +**
  • [sqlite3_memory_used()] +**
  • [sqlite3_memory_highwater()] +**
  • [sqlite3_soft_heap_limit64()] +**
  • [sqlite3_status()] +**
)^ +** ^Memory allocation statistics are enabled by default unless SQLite is +** compiled with [SQLITE_DEFAULT_MEMSTATUS]=0 in which case memory +** allocation statistics are disabled by default. +**
+** +** [[SQLITE_CONFIG_SCRATCH]]
SQLITE_CONFIG_SCRATCH
+**
^This option specifies a static memory buffer that SQLite can use for +** scratch memory. There are three arguments: A pointer an 8-byte +** aligned memory buffer from which the scratch allocations will be +** drawn, the size of each scratch allocation (sz), +** and the maximum number of scratch allocations (N). The sz +** argument must be a multiple of 16. +** The first argument must be a pointer to an 8-byte aligned buffer +** of at least sz*N bytes of memory. +** ^SQLite will use no more than two scratch buffers per thread. So +** N should be set to twice the expected maximum number of threads. +** ^SQLite will never require a scratch buffer that is more than 6 +** times the database page size. ^If SQLite needs needs additional +** scratch memory beyond what is provided by this configuration option, then +** [sqlite3_malloc()] will be used to obtain the memory needed.
+** +** [[SQLITE_CONFIG_PAGECACHE]]
SQLITE_CONFIG_PAGECACHE
+**
^This option specifies a static memory buffer that SQLite can use for +** the database page cache with the default page cache implementation. +** This configuration should not be used if an application-define page +** cache implementation is loaded using the SQLITE_CONFIG_PCACHE option. +** There are three arguments to this option: A pointer to 8-byte aligned +** memory, the size of each page buffer (sz), and the number of pages (N). +** The sz argument should be the size of the largest database page +** (a power of two between 512 and 32768) plus a little extra for each +** page header. ^The page header size is 20 to 40 bytes depending on +** the host architecture. ^It is harmless, apart from the wasted memory, +** to make sz a little too large. The first +** argument should point to an allocation of at least sz*N bytes of memory. +** ^SQLite will use the memory provided by the first argument to satisfy its +** memory needs for the first N pages that it adds to cache. ^If additional +** page cache memory is needed beyond what is provided by this option, then +** SQLite goes to [sqlite3_malloc()] for the additional storage space. +** The pointer in the first argument must +** be aligned to an 8-byte boundary or subsequent behavior of SQLite +** will be undefined.
+** +** [[SQLITE_CONFIG_HEAP]]
SQLITE_CONFIG_HEAP
+**
^This option specifies a static memory buffer that SQLite will use +** for all of its dynamic memory allocation needs beyond those provided +** for by [SQLITE_CONFIG_SCRATCH] and [SQLITE_CONFIG_PAGECACHE]. +** There are three arguments: An 8-byte aligned pointer to the memory, +** the number of bytes in the memory buffer, and the minimum allocation size. +** ^If the first pointer (the memory pointer) is NULL, then SQLite reverts +** to using its default memory allocator (the system malloc() implementation), +** undoing any prior invocation of [SQLITE_CONFIG_MALLOC]. ^If the +** memory pointer is not NULL and either [SQLITE_ENABLE_MEMSYS3] or +** [SQLITE_ENABLE_MEMSYS5] are defined, then the alternative memory +** allocator is engaged to handle all of SQLites memory allocation needs. +** The first pointer (the memory pointer) must be aligned to an 8-byte +** boundary or subsequent behavior of SQLite will be undefined. +** The minimum allocation size is capped at 2^12. Reasonable values +** for the minimum allocation size are 2^5 through 2^8.
+** +** [[SQLITE_CONFIG_MUTEX]]
SQLITE_CONFIG_MUTEX
+**
^(This option takes a single argument which is a pointer to an +** instance of the [sqlite3_mutex_methods] structure. The argument specifies +** alternative low-level mutex routines to be used in place +** the mutex routines built into SQLite.)^ ^SQLite makes a copy of the +** content of the [sqlite3_mutex_methods] structure before the call to +** [sqlite3_config()] returns. ^If SQLite is compiled with +** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then +** the entire mutexing subsystem is omitted from the build and hence calls to +** [sqlite3_config()] with the SQLITE_CONFIG_MUTEX configuration option will +** return [SQLITE_ERROR].
+** +** [[SQLITE_CONFIG_GETMUTEX]]
SQLITE_CONFIG_GETMUTEX
+**
^(This option takes a single argument which is a pointer to an +** instance of the [sqlite3_mutex_methods] structure. The +** [sqlite3_mutex_methods] +** structure is filled with the currently defined mutex routines.)^ +** This option can be used to overload the default mutex allocation +** routines with a wrapper used to track mutex usage for performance +** profiling or testing, for example. ^If SQLite is compiled with +** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then +** the entire mutexing subsystem is omitted from the build and hence calls to +** [sqlite3_config()] with the SQLITE_CONFIG_GETMUTEX configuration option will +** return [SQLITE_ERROR].
+** +** [[SQLITE_CONFIG_LOOKASIDE]]
SQLITE_CONFIG_LOOKASIDE
+**
^(This option takes two arguments that determine the default +** memory allocation for the lookaside memory allocator on each +** [database connection]. The first argument is the +** size of each lookaside buffer slot and the second is the number of +** slots allocated to each database connection.)^ ^(This option sets the +** default lookaside size. The [SQLITE_DBCONFIG_LOOKASIDE] +** verb to [sqlite3_db_config()] can be used to change the lookaside +** configuration on individual connections.)^
+** +** [[SQLITE_CONFIG_PCACHE]]
SQLITE_CONFIG_PCACHE
+**
^(This option takes a single argument which is a pointer to +** an [sqlite3_pcache_methods] object. This object specifies the interface +** to a custom page cache implementation.)^ ^SQLite makes a copy of the +** object and uses it for page cache memory allocations.
+** +** [[SQLITE_CONFIG_GETPCACHE]]
SQLITE_CONFIG_GETPCACHE
+**
^(This option takes a single argument which is a pointer to an +** [sqlite3_pcache_methods] object. SQLite copies of the current +** page cache implementation into that object.)^
+** +** [[SQLITE_CONFIG_LOG]]
SQLITE_CONFIG_LOG
+**
^The SQLITE_CONFIG_LOG option takes two arguments: a pointer to a +** function with a call signature of void(*)(void*,int,const char*), +** and a pointer to void. ^If the function pointer is not NULL, it is +** invoked by [sqlite3_log()] to process each logging event. ^If the +** function pointer is NULL, the [sqlite3_log()] interface becomes a no-op. +** ^The void pointer that is the second argument to SQLITE_CONFIG_LOG is +** passed through as the first parameter to the application-defined logger +** function whenever that function is invoked. ^The second parameter to +** the logger function is a copy of the first parameter to the corresponding +** [sqlite3_log()] call and is intended to be a [result code] or an +** [extended result code]. ^The third parameter passed to the logger is +** log message after formatting via [sqlite3_snprintf()]. +** The SQLite logging interface is not reentrant; the logger function +** supplied by the application must not invoke any SQLite interface. +** In a multi-threaded application, the application-defined logger +** function must be threadsafe.
+** +** [[SQLITE_CONFIG_URI]]
SQLITE_CONFIG_URI +**
This option takes a single argument of type int. If non-zero, then +** URI handling is globally enabled. If the parameter is zero, then URI handling +** is globally disabled. If URI handling is globally enabled, all filenames +** passed to [sqlite3_open()], [sqlite3_open_v2()], [sqlite3_open16()] or +** specified as part of [ATTACH] commands are interpreted as URIs, regardless +** of whether or not the [SQLITE_OPEN_URI] flag is set when the database +** connection is opened. If it is globally disabled, filenames are +** only interpreted as URIs if the SQLITE_OPEN_URI flag is set when the +** database connection is opened. By default, URI handling is globally +** disabled. The default value may be changed by compiling with the +** [SQLITE_USE_URI] symbol defined. +**
+*/ +#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */ +#define SQLITE_CONFIG_MULTITHREAD 2 /* nil */ +#define SQLITE_CONFIG_SERIALIZED 3 /* nil */ +#define SQLITE_CONFIG_MALLOC 4 /* sqlite3_mem_methods* */ +#define SQLITE_CONFIG_GETMALLOC 5 /* sqlite3_mem_methods* */ +#define SQLITE_CONFIG_SCRATCH 6 /* void*, int sz, int N */ +#define SQLITE_CONFIG_PAGECACHE 7 /* void*, int sz, int N */ +#define SQLITE_CONFIG_HEAP 8 /* void*, int nByte, int min */ +#define SQLITE_CONFIG_MEMSTATUS 9 /* boolean */ +#define SQLITE_CONFIG_MUTEX 10 /* sqlite3_mutex_methods* */ +#define SQLITE_CONFIG_GETMUTEX 11 /* sqlite3_mutex_methods* */ +/* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */ +#define SQLITE_CONFIG_LOOKASIDE 13 /* int int */ +#define SQLITE_CONFIG_PCACHE 14 /* sqlite3_pcache_methods* */ +#define SQLITE_CONFIG_GETPCACHE 15 /* sqlite3_pcache_methods* */ +#define SQLITE_CONFIG_LOG 16 /* xFunc, void* */ +#define SQLITE_CONFIG_URI 17 /* int */ + +/* +** CAPI3REF: Database Connection Configuration Options +** +** These constants are the available integer configuration options that +** can be passed as the second argument to the [sqlite3_db_config()] interface. +** +** New configuration options may be added in future releases of SQLite. +** Existing configuration options might be discontinued. Applications +** should check the return code from [sqlite3_db_config()] to make sure that +** the call worked. ^The [sqlite3_db_config()] interface will return a +** non-zero [error code] if a discontinued or unsupported configuration option +** is invoked. +** +**
+**
SQLITE_DBCONFIG_LOOKASIDE
+**
^This option takes three additional arguments that determine the +** [lookaside memory allocator] configuration for the [database connection]. +** ^The first argument (the third parameter to [sqlite3_db_config()] is a +** pointer to a memory buffer to use for lookaside memory. +** ^The first argument after the SQLITE_DBCONFIG_LOOKASIDE verb +** may be NULL in which case SQLite will allocate the +** lookaside buffer itself using [sqlite3_malloc()]. ^The second argument is the +** size of each lookaside buffer slot. ^The third argument is the number of +** slots. The size of the buffer in the first argument must be greater than +** or equal to the product of the second and third arguments. The buffer +** must be aligned to an 8-byte boundary. ^If the second argument to +** SQLITE_DBCONFIG_LOOKASIDE is not a multiple of 8, it is internally +** rounded down to the next smaller multiple of 8. ^(The lookaside memory +** configuration for a database connection can only be changed when that +** connection is not currently using lookaside memory, or in other words +** when the "current value" returned by +** [sqlite3_db_status](D,[SQLITE_CONFIG_LOOKASIDE],...) is zero. +** Any attempt to change the lookaside memory configuration when lookaside +** memory is in use leaves the configuration unchanged and returns +** [SQLITE_BUSY].)^
+** +**
SQLITE_DBCONFIG_ENABLE_FKEY
+**
^This option is used to enable or disable the enforcement of +** [foreign key constraints]. There should be two additional arguments. +** The first argument is an integer which is 0 to disable FK enforcement, +** positive to enable FK enforcement or negative to leave FK enforcement +** unchanged. The second parameter is a pointer to an integer into which +** is written 0 or 1 to indicate whether FK enforcement is off or on +** following this call. The second parameter may be a NULL pointer, in +** which case the FK enforcement setting is not reported back.
+** +**
SQLITE_DBCONFIG_ENABLE_TRIGGER
+**
^This option is used to enable or disable [CREATE TRIGGER | triggers]. +** There should be two additional arguments. +** The first argument is an integer which is 0 to disable triggers, +** positive to enable triggers or negative to leave the setting unchanged. +** The second parameter is a pointer to an integer into which +** is written 0 or 1 to indicate whether triggers are disabled or enabled +** following this call. The second parameter may be a NULL pointer, in +** which case the trigger setting is not reported back.
+** +**
+*/ +#define SQLITE_DBCONFIG_LOOKASIDE 1001 /* void* int int */ +#define SQLITE_DBCONFIG_ENABLE_FKEY 1002 /* int int* */ +#define SQLITE_DBCONFIG_ENABLE_TRIGGER 1003 /* int int* */ + + +/* +** CAPI3REF: Enable Or Disable Extended Result Codes +** +** ^The sqlite3_extended_result_codes() routine enables or disables the +** [extended result codes] feature of SQLite. ^The extended result +** codes are disabled by default for historical compatibility. +*/ +SQLITE_API int sqlite3_extended_result_codes(sqlite3*, int onoff); + +/* +** CAPI3REF: Last Insert Rowid +** +** ^Each entry in an SQLite table has a unique 64-bit signed +** integer key called the [ROWID | "rowid"]. ^The rowid is always available +** as an undeclared column named ROWID, OID, or _ROWID_ as long as those +** names are not also used by explicitly declared columns. ^If +** the table has a column of type [INTEGER PRIMARY KEY] then that column +** is another alias for the rowid. +** +** ^This routine returns the [rowid] of the most recent +** successful [INSERT] into the database from the [database connection] +** in the first argument. ^As of SQLite version 3.7.7, this routines +** records the last insert rowid of both ordinary tables and [virtual tables]. +** ^If no successful [INSERT]s +** have ever occurred on that database connection, zero is returned. +** +** ^(If an [INSERT] occurs within a trigger or within a [virtual table] +** method, then this routine will return the [rowid] of the inserted +** row as long as the trigger or virtual table method is running. +** But once the trigger or virtual table method ends, the value returned +** by this routine reverts to what it was before the trigger or virtual +** table method began.)^ +** +** ^An [INSERT] that fails due to a constraint violation is not a +** successful [INSERT] and does not change the value returned by this +** routine. ^Thus INSERT OR FAIL, INSERT OR IGNORE, INSERT OR ROLLBACK, +** and INSERT OR ABORT make no changes to the return value of this +** routine when their insertion fails. ^(When INSERT OR REPLACE +** encounters a constraint violation, it does not fail. The +** INSERT continues to completion after deleting rows that caused +** the constraint problem so INSERT OR REPLACE will always change +** the return value of this interface.)^ +** +** ^For the purposes of this routine, an [INSERT] is considered to +** be successful even if it is subsequently rolled back. +** +** This function is accessible to SQL statements via the +** [last_insert_rowid() SQL function]. +** +** If a separate thread performs a new [INSERT] on the same +** database connection while the [sqlite3_last_insert_rowid()] +** function is running and thus changes the last insert [rowid], +** then the value returned by [sqlite3_last_insert_rowid()] is +** unpredictable and might not equal either the old or the new +** last insert [rowid]. +*/ +SQLITE_API sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*); + +/* +** CAPI3REF: Count The Number Of Rows Modified +** +** ^This function returns the number of database rows that were changed +** or inserted or deleted by the most recently completed SQL statement +** on the [database connection] specified by the first parameter. +** ^(Only changes that are directly specified by the [INSERT], [UPDATE], +** or [DELETE] statement are counted. Auxiliary changes caused by +** triggers or [foreign key actions] are not counted.)^ Use the +** [sqlite3_total_changes()] function to find the total number of changes +** including changes caused by triggers and foreign key actions. +** +** ^Changes to a view that are simulated by an [INSTEAD OF trigger] +** are not counted. Only real table changes are counted. +** +** ^(A "row change" is a change to a single row of a single table +** caused by an INSERT, DELETE, or UPDATE statement. Rows that +** are changed as side effects of [REPLACE] constraint resolution, +** rollback, ABORT processing, [DROP TABLE], or by any other +** mechanisms do not count as direct row changes.)^ +** +** A "trigger context" is a scope of execution that begins and +** ends with the script of a [CREATE TRIGGER | trigger]. +** Most SQL statements are +** evaluated outside of any trigger. This is the "top level" +** trigger context. If a trigger fires from the top level, a +** new trigger context is entered for the duration of that one +** trigger. Subtriggers create subcontexts for their duration. +** +** ^Calling [sqlite3_exec()] or [sqlite3_step()] recursively does +** not create a new trigger context. +** +** ^This function returns the number of direct row changes in the +** most recent INSERT, UPDATE, or DELETE statement within the same +** trigger context. +** +** ^Thus, when called from the top level, this function returns the +** number of changes in the most recent INSERT, UPDATE, or DELETE +** that also occurred at the top level. ^(Within the body of a trigger, +** the sqlite3_changes() interface can be called to find the number of +** changes in the most recently completed INSERT, UPDATE, or DELETE +** statement within the body of the same trigger. +** However, the number returned does not include changes +** caused by subtriggers since those have their own context.)^ +** +** See also the [sqlite3_total_changes()] interface, the +** [count_changes pragma], and the [changes() SQL function]. +** +** If a separate thread makes changes on the same database connection +** while [sqlite3_changes()] is running then the value returned +** is unpredictable and not meaningful. +*/ +SQLITE_API int sqlite3_changes(sqlite3*); + +/* +** CAPI3REF: Total Number Of Rows Modified +** +** ^This function returns the number of row changes caused by [INSERT], +** [UPDATE] or [DELETE] statements since the [database connection] was opened. +** ^(The count returned by sqlite3_total_changes() includes all changes +** from all [CREATE TRIGGER | trigger] contexts and changes made by +** [foreign key actions]. However, +** the count does not include changes used to implement [REPLACE] constraints, +** do rollbacks or ABORT processing, or [DROP TABLE] processing. The +** count does not include rows of views that fire an [INSTEAD OF trigger], +** though if the INSTEAD OF trigger makes changes of its own, those changes +** are counted.)^ +** ^The sqlite3_total_changes() function counts the changes as soon as +** the statement that makes them is completed (when the statement handle +** is passed to [sqlite3_reset()] or [sqlite3_finalize()]). +** +** See also the [sqlite3_changes()] interface, the +** [count_changes pragma], and the [total_changes() SQL function]. +** +** If a separate thread makes changes on the same database connection +** while [sqlite3_total_changes()] is running then the value +** returned is unpredictable and not meaningful. +*/ +SQLITE_API int sqlite3_total_changes(sqlite3*); + +/* +** CAPI3REF: Interrupt A Long-Running Query +** +** ^This function causes any pending database operation to abort and +** return at its earliest opportunity. This routine is typically +** called in response to a user action such as pressing "Cancel" +** or Ctrl-C where the user wants a long query operation to halt +** immediately. +** +** ^It is safe to call this routine from a thread different from the +** thread that is currently running the database operation. But it +** is not safe to call this routine with a [database connection] that +** is closed or might close before sqlite3_interrupt() returns. +** +** ^If an SQL operation is very nearly finished at the time when +** sqlite3_interrupt() is called, then it might not have an opportunity +** to be interrupted and might continue to completion. +** +** ^An SQL operation that is interrupted will return [SQLITE_INTERRUPT]. +** ^If the interrupted SQL operation is an INSERT, UPDATE, or DELETE +** that is inside an explicit transaction, then the entire transaction +** will be rolled back automatically. +** +** ^The sqlite3_interrupt(D) call is in effect until all currently running +** SQL statements on [database connection] D complete. ^Any new SQL statements +** that are started after the sqlite3_interrupt() call and before the +** running statements reaches zero are interrupted as if they had been +** running prior to the sqlite3_interrupt() call. ^New SQL statements +** that are started after the running statement count reaches zero are +** not effected by the sqlite3_interrupt(). +** ^A call to sqlite3_interrupt(D) that occurs when there are no running +** SQL statements is a no-op and has no effect on SQL statements +** that are started after the sqlite3_interrupt() call returns. +** +** If the database connection closes while [sqlite3_interrupt()] +** is running then bad things will likely happen. +*/ +SQLITE_API void sqlite3_interrupt(sqlite3*); + +/* +** CAPI3REF: Determine If An SQL Statement Is Complete +** +** These routines are useful during command-line input to determine if the +** currently entered text seems to form a complete SQL statement or +** if additional input is needed before sending the text into +** SQLite for parsing. ^These routines return 1 if the input string +** appears to be a complete SQL statement. ^A statement is judged to be +** complete if it ends with a semicolon token and is not a prefix of a +** well-formed CREATE TRIGGER statement. ^Semicolons that are embedded within +** string literals or quoted identifier names or comments are not +** independent tokens (they are part of the token in which they are +** embedded) and thus do not count as a statement terminator. ^Whitespace +** and comments that follow the final semicolon are ignored. +** +** ^These routines return 0 if the statement is incomplete. ^If a +** memory allocation fails, then SQLITE_NOMEM is returned. +** +** ^These routines do not parse the SQL statements thus +** will not detect syntactically incorrect SQL. +** +** ^(If SQLite has not been initialized using [sqlite3_initialize()] prior +** to invoking sqlite3_complete16() then sqlite3_initialize() is invoked +** automatically by sqlite3_complete16(). If that initialization fails, +** then the return value from sqlite3_complete16() will be non-zero +** regardless of whether or not the input SQL is complete.)^ +** +** The input to [sqlite3_complete()] must be a zero-terminated +** UTF-8 string. +** +** The input to [sqlite3_complete16()] must be a zero-terminated +** UTF-16 string in native byte order. +*/ +SQLITE_API int sqlite3_complete(const char *sql); +SQLITE_API int sqlite3_complete16(const void *sql); + +/* +** CAPI3REF: Register A Callback To Handle SQLITE_BUSY Errors +** +** ^This routine sets a callback function that might be invoked whenever +** an attempt is made to open a database table that another thread +** or process has locked. +** +** ^If the busy callback is NULL, then [SQLITE_BUSY] or [SQLITE_IOERR_BLOCKED] +** is returned immediately upon encountering the lock. ^If the busy callback +** is not NULL, then the callback might be invoked with two arguments. +** +** ^The first argument to the busy handler is a copy of the void* pointer which +** is the third argument to sqlite3_busy_handler(). ^The second argument to +** the busy handler callback is the number of times that the busy handler has +** been invoked for this locking event. ^If the +** busy callback returns 0, then no additional attempts are made to +** access the database and [SQLITE_BUSY] or [SQLITE_IOERR_BLOCKED] is returned. +** ^If the callback returns non-zero, then another attempt +** is made to open the database for reading and the cycle repeats. +** +** The presence of a busy handler does not guarantee that it will be invoked +** when there is lock contention. ^If SQLite determines that invoking the busy +** handler could result in a deadlock, it will go ahead and return [SQLITE_BUSY] +** or [SQLITE_IOERR_BLOCKED] instead of invoking the busy handler. +** Consider a scenario where one process is holding a read lock that +** it is trying to promote to a reserved lock and +** a second process is holding a reserved lock that it is trying +** to promote to an exclusive lock. The first process cannot proceed +** because it is blocked by the second and the second process cannot +** proceed because it is blocked by the first. If both processes +** invoke the busy handlers, neither will make any progress. Therefore, +** SQLite returns [SQLITE_BUSY] for the first process, hoping that this +** will induce the first process to release its read lock and allow +** the second process to proceed. +** +** ^The default busy callback is NULL. +** +** ^The [SQLITE_BUSY] error is converted to [SQLITE_IOERR_BLOCKED] +** when SQLite is in the middle of a large transaction where all the +** changes will not fit into the in-memory cache. SQLite will +** already hold a RESERVED lock on the database file, but it needs +** to promote this lock to EXCLUSIVE so that it can spill cache +** pages into the database file without harm to concurrent +** readers. ^If it is unable to promote the lock, then the in-memory +** cache will be left in an inconsistent state and so the error +** code is promoted from the relatively benign [SQLITE_BUSY] to +** the more severe [SQLITE_IOERR_BLOCKED]. ^This error code promotion +** forces an automatic rollback of the changes. See the +** +** CorruptionFollowingBusyError wiki page for a discussion of why +** this is important. +** +** ^(There can only be a single busy handler defined for each +** [database connection]. Setting a new busy handler clears any +** previously set handler.)^ ^Note that calling [sqlite3_busy_timeout()] +** will also set or clear the busy handler. +** +** The busy callback should not take any actions which modify the +** database connection that invoked the busy handler. Any such actions +** result in undefined behavior. +** +** A busy handler must not close the database connection +** or [prepared statement] that invoked the busy handler. +*/ +SQLITE_API int sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*); + +/* +** CAPI3REF: Set A Busy Timeout +** +** ^This routine sets a [sqlite3_busy_handler | busy handler] that sleeps +** for a specified amount of time when a table is locked. ^The handler +** will sleep multiple times until at least "ms" milliseconds of sleeping +** have accumulated. ^After at least "ms" milliseconds of sleeping, +** the handler returns 0 which causes [sqlite3_step()] to return +** [SQLITE_BUSY] or [SQLITE_IOERR_BLOCKED]. +** +** ^Calling this routine with an argument less than or equal to zero +** turns off all busy handlers. +** +** ^(There can only be a single busy handler for a particular +** [database connection] any any given moment. If another busy handler +** was defined (using [sqlite3_busy_handler()]) prior to calling +** this routine, that other busy handler is cleared.)^ +*/ +SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms); + +/* +** CAPI3REF: Convenience Routines For Running Queries +** +** This is a legacy interface that is preserved for backwards compatibility. +** Use of this interface is not recommended. +** +** Definition: A result table is memory data structure created by the +** [sqlite3_get_table()] interface. A result table records the +** complete query results from one or more queries. +** +** The table conceptually has a number of rows and columns. But +** these numbers are not part of the result table itself. These +** numbers are obtained separately. Let N be the number of rows +** and M be the number of columns. +** +** A result table is an array of pointers to zero-terminated UTF-8 strings. +** There are (N+1)*M elements in the array. The first M pointers point +** to zero-terminated strings that contain the names of the columns. +** The remaining entries all point to query results. NULL values result +** in NULL pointers. All other values are in their UTF-8 zero-terminated +** string representation as returned by [sqlite3_column_text()]. +** +** A result table might consist of one or more memory allocations. +** It is not safe to pass a result table directly to [sqlite3_free()]. +** A result table should be deallocated using [sqlite3_free_table()]. +** +** ^(As an example of the result table format, suppose a query result +** is as follows: +** +**
+**        Name        | Age
+**        -----------------------
+**        Alice       | 43
+**        Bob         | 28
+**        Cindy       | 21
+** 
+** +** There are two column (M==2) and three rows (N==3). Thus the +** result table has 8 entries. Suppose the result table is stored +** in an array names azResult. Then azResult holds this content: +** +**
+**        azResult[0] = "Name";
+**        azResult[1] = "Age";
+**        azResult[2] = "Alice";
+**        azResult[3] = "43";
+**        azResult[4] = "Bob";
+**        azResult[5] = "28";
+**        azResult[6] = "Cindy";
+**        azResult[7] = "21";
+** 
)^ +** +** ^The sqlite3_get_table() function evaluates one or more +** semicolon-separated SQL statements in the zero-terminated UTF-8 +** string of its 2nd parameter and returns a result table to the +** pointer given in its 3rd parameter. +** +** After the application has finished with the result from sqlite3_get_table(), +** it must pass the result table pointer to sqlite3_free_table() in order to +** release the memory that was malloced. Because of the way the +** [sqlite3_malloc()] happens within sqlite3_get_table(), the calling +** function must not try to call [sqlite3_free()] directly. Only +** [sqlite3_free_table()] is able to release the memory properly and safely. +** +** The sqlite3_get_table() interface is implemented as a wrapper around +** [sqlite3_exec()]. The sqlite3_get_table() routine does not have access +** to any internal data structures of SQLite. It uses only the public +** interface defined here. As a consequence, errors that occur in the +** wrapper layer outside of the internal [sqlite3_exec()] call are not +** reflected in subsequent calls to [sqlite3_errcode()] or +** [sqlite3_errmsg()]. +*/ +SQLITE_API int sqlite3_get_table( + sqlite3 *db, /* An open database */ + const char *zSql, /* SQL to be evaluated */ + char ***pazResult, /* Results of the query */ + int *pnRow, /* Number of result rows written here */ + int *pnColumn, /* Number of result columns written here */ + char **pzErrmsg /* Error msg written here */ +); +SQLITE_API void sqlite3_free_table(char **result); + +/* +** CAPI3REF: Formatted String Printing Functions +** +** These routines are work-alikes of the "printf()" family of functions +** from the standard C library. +** +** ^The sqlite3_mprintf() and sqlite3_vmprintf() routines write their +** results into memory obtained from [sqlite3_malloc()]. +** The strings returned by these two routines should be +** released by [sqlite3_free()]. ^Both routines return a +** NULL pointer if [sqlite3_malloc()] is unable to allocate enough +** memory to hold the resulting string. +** +** ^(The sqlite3_snprintf() routine is similar to "snprintf()" from +** the standard C library. The result is written into the +** buffer supplied as the second parameter whose size is given by +** the first parameter. Note that the order of the +** first two parameters is reversed from snprintf().)^ This is an +** historical accident that cannot be fixed without breaking +** backwards compatibility. ^(Note also that sqlite3_snprintf() +** returns a pointer to its buffer instead of the number of +** characters actually written into the buffer.)^ We admit that +** the number of characters written would be a more useful return +** value but we cannot change the implementation of sqlite3_snprintf() +** now without breaking compatibility. +** +** ^As long as the buffer size is greater than zero, sqlite3_snprintf() +** guarantees that the buffer is always zero-terminated. ^The first +** parameter "n" is the total size of the buffer, including space for +** the zero terminator. So the longest string that can be completely +** written will be n-1 characters. +** +** ^The sqlite3_vsnprintf() routine is a varargs version of sqlite3_snprintf(). +** +** These routines all implement some additional formatting +** options that are useful for constructing SQL statements. +** All of the usual printf() formatting options apply. In addition, there +** is are "%q", "%Q", and "%z" options. +** +** ^(The %q option works like %s in that it substitutes a null-terminated +** string from the argument list. But %q also doubles every '\'' character. +** %q is designed for use inside a string literal.)^ By doubling each '\'' +** character it escapes that character and allows it to be inserted into +** the string. +** +** For example, assume the string variable zText contains text as follows: +** +**
+**  char *zText = "It's a happy day!";
+** 
+** +** One can use this text in an SQL statement as follows: +** +**
+**  char *zSQL = sqlite3_mprintf("INSERT INTO table VALUES('%q')", zText);
+**  sqlite3_exec(db, zSQL, 0, 0, 0);
+**  sqlite3_free(zSQL);
+** 
+** +** Because the %q format string is used, the '\'' character in zText +** is escaped and the SQL generated is as follows: +** +**
+**  INSERT INTO table1 VALUES('It''s a happy day!')
+** 
+** +** This is correct. Had we used %s instead of %q, the generated SQL +** would have looked like this: +** +**
+**  INSERT INTO table1 VALUES('It's a happy day!');
+** 
+** +** This second example is an SQL syntax error. As a general rule you should +** always use %q instead of %s when inserting text into a string literal. +** +** ^(The %Q option works like %q except it also adds single quotes around +** the outside of the total string. Additionally, if the parameter in the +** argument list is a NULL pointer, %Q substitutes the text "NULL" (without +** single quotes).)^ So, for example, one could say: +** +**
+**  char *zSQL = sqlite3_mprintf("INSERT INTO table VALUES(%Q)", zText);
+**  sqlite3_exec(db, zSQL, 0, 0, 0);
+**  sqlite3_free(zSQL);
+** 
+** +** The code above will render a correct SQL statement in the zSQL +** variable even if the zText variable is a NULL pointer. +** +** ^(The "%z" formatting option works like "%s" but with the +** addition that after the string has been read and copied into +** the result, [sqlite3_free()] is called on the input string.)^ +*/ +SQLITE_API char *sqlite3_mprintf(const char*,...); +SQLITE_API char *sqlite3_vmprintf(const char*, va_list); +SQLITE_API char *sqlite3_snprintf(int,char*,const char*, ...); +SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list); + +/* +** CAPI3REF: Memory Allocation Subsystem +** +** The SQLite core uses these three routines for all of its own +** internal memory allocation needs. "Core" in the previous sentence +** does not include operating-system specific VFS implementation. The +** Windows VFS uses native malloc() and free() for some operations. +** +** ^The sqlite3_malloc() routine returns a pointer to a block +** of memory at least N bytes in length, where N is the parameter. +** ^If sqlite3_malloc() is unable to obtain sufficient free +** memory, it returns a NULL pointer. ^If the parameter N to +** sqlite3_malloc() is zero or negative then sqlite3_malloc() returns +** a NULL pointer. +** +** ^Calling sqlite3_free() with a pointer previously returned +** by sqlite3_malloc() or sqlite3_realloc() releases that memory so +** that it might be reused. ^The sqlite3_free() routine is +** a no-op if is called with a NULL pointer. Passing a NULL pointer +** to sqlite3_free() is harmless. After being freed, memory +** should neither be read nor written. Even reading previously freed +** memory might result in a segmentation fault or other severe error. +** Memory corruption, a segmentation fault, or other severe error +** might result if sqlite3_free() is called with a non-NULL pointer that +** was not obtained from sqlite3_malloc() or sqlite3_realloc(). +** +** ^(The sqlite3_realloc() interface attempts to resize a +** prior memory allocation to be at least N bytes, where N is the +** second parameter. The memory allocation to be resized is the first +** parameter.)^ ^ If the first parameter to sqlite3_realloc() +** is a NULL pointer then its behavior is identical to calling +** sqlite3_malloc(N) where N is the second parameter to sqlite3_realloc(). +** ^If the second parameter to sqlite3_realloc() is zero or +** negative then the behavior is exactly the same as calling +** sqlite3_free(P) where P is the first parameter to sqlite3_realloc(). +** ^sqlite3_realloc() returns a pointer to a memory allocation +** of at least N bytes in size or NULL if sufficient memory is unavailable. +** ^If M is the size of the prior allocation, then min(N,M) bytes +** of the prior allocation are copied into the beginning of buffer returned +** by sqlite3_realloc() and the prior allocation is freed. +** ^If sqlite3_realloc() returns NULL, then the prior allocation +** is not freed. +** +** ^The memory returned by sqlite3_malloc() and sqlite3_realloc() +** is always aligned to at least an 8 byte boundary, or to a +** 4 byte boundary if the [SQLITE_4_BYTE_ALIGNED_MALLOC] compile-time +** option is used. +** +** In SQLite version 3.5.0 and 3.5.1, it was possible to define +** the SQLITE_OMIT_MEMORY_ALLOCATION which would cause the built-in +** implementation of these routines to be omitted. That capability +** is no longer provided. Only built-in memory allocators can be used. +** +** The Windows OS interface layer calls +** the system malloc() and free() directly when converting +** filenames between the UTF-8 encoding used by SQLite +** and whatever filename encoding is used by the particular Windows +** installation. Memory allocation errors are detected, but +** they are reported back as [SQLITE_CANTOPEN] or +** [SQLITE_IOERR] rather than [SQLITE_NOMEM]. +** +** The pointer arguments to [sqlite3_free()] and [sqlite3_realloc()] +** must be either NULL or else pointers obtained from a prior +** invocation of [sqlite3_malloc()] or [sqlite3_realloc()] that have +** not yet been released. +** +** The application must not read or write any part of +** a block of memory after it has been released using +** [sqlite3_free()] or [sqlite3_realloc()]. +*/ +SQLITE_API void *sqlite3_malloc(int); +SQLITE_API void *sqlite3_realloc(void*, int); +SQLITE_API void sqlite3_free(void*); + +/* +** CAPI3REF: Memory Allocator Statistics +** +** SQLite provides these two interfaces for reporting on the status +** of the [sqlite3_malloc()], [sqlite3_free()], and [sqlite3_realloc()] +** routines, which form the built-in memory allocation subsystem. +** +** ^The [sqlite3_memory_used()] routine returns the number of bytes +** of memory currently outstanding (malloced but not freed). +** ^The [sqlite3_memory_highwater()] routine returns the maximum +** value of [sqlite3_memory_used()] since the high-water mark +** was last reset. ^The values returned by [sqlite3_memory_used()] and +** [sqlite3_memory_highwater()] include any overhead +** added by SQLite in its implementation of [sqlite3_malloc()], +** but not overhead added by the any underlying system library +** routines that [sqlite3_malloc()] may call. +** +** ^The memory high-water mark is reset to the current value of +** [sqlite3_memory_used()] if and only if the parameter to +** [sqlite3_memory_highwater()] is true. ^The value returned +** by [sqlite3_memory_highwater(1)] is the high-water mark +** prior to the reset. +*/ +SQLITE_API sqlite3_int64 sqlite3_memory_used(void); +SQLITE_API sqlite3_int64 sqlite3_memory_highwater(int resetFlag); + +/* +** CAPI3REF: Pseudo-Random Number Generator +** +** SQLite contains a high-quality pseudo-random number generator (PRNG) used to +** select random [ROWID | ROWIDs] when inserting new records into a table that +** already uses the largest possible [ROWID]. The PRNG is also used for +** the build-in random() and randomblob() SQL functions. This interface allows +** applications to access the same PRNG for other purposes. +** +** ^A call to this routine stores N bytes of randomness into buffer P. +** +** ^The first time this routine is invoked (either internally or by +** the application) the PRNG is seeded using randomness obtained +** from the xRandomness method of the default [sqlite3_vfs] object. +** ^On all subsequent invocations, the pseudo-randomness is generated +** internally and without recourse to the [sqlite3_vfs] xRandomness +** method. +*/ +SQLITE_API void sqlite3_randomness(int N, void *P); + +/* +** CAPI3REF: Compile-Time Authorization Callbacks +** +** ^This routine registers an authorizer callback with a particular +** [database connection], supplied in the first argument. +** ^The authorizer callback is invoked as SQL statements are being compiled +** by [sqlite3_prepare()] or its variants [sqlite3_prepare_v2()], +** [sqlite3_prepare16()] and [sqlite3_prepare16_v2()]. ^At various +** points during the compilation process, as logic is being created +** to perform various actions, the authorizer callback is invoked to +** see if those actions are allowed. ^The authorizer callback should +** return [SQLITE_OK] to allow the action, [SQLITE_IGNORE] to disallow the +** specific action but allow the SQL statement to continue to be +** compiled, or [SQLITE_DENY] to cause the entire SQL statement to be +** rejected with an error. ^If the authorizer callback returns +** any value other than [SQLITE_IGNORE], [SQLITE_OK], or [SQLITE_DENY] +** then the [sqlite3_prepare_v2()] or equivalent call that triggered +** the authorizer will fail with an error message. +** +** When the callback returns [SQLITE_OK], that means the operation +** requested is ok. ^When the callback returns [SQLITE_DENY], the +** [sqlite3_prepare_v2()] or equivalent call that triggered the +** authorizer will fail with an error message explaining that +** access is denied. +** +** ^The first parameter to the authorizer callback is a copy of the third +** parameter to the sqlite3_set_authorizer() interface. ^The second parameter +** to the callback is an integer [SQLITE_COPY | action code] that specifies +** the particular action to be authorized. ^The third through sixth parameters +** to the callback are zero-terminated strings that contain additional +** details about the action to be authorized. +** +** ^If the action code is [SQLITE_READ] +** and the callback returns [SQLITE_IGNORE] then the +** [prepared statement] statement is constructed to substitute +** a NULL value in place of the table column that would have +** been read if [SQLITE_OK] had been returned. The [SQLITE_IGNORE] +** return can be used to deny an untrusted user access to individual +** columns of a table. +** ^If the action code is [SQLITE_DELETE] and the callback returns +** [SQLITE_IGNORE] then the [DELETE] operation proceeds but the +** [truncate optimization] is disabled and all rows are deleted individually. +** +** An authorizer is used when [sqlite3_prepare | preparing] +** SQL statements from an untrusted source, to ensure that the SQL statements +** do not try to access data they are not allowed to see, or that they do not +** try to execute malicious statements that damage the database. For +** example, an application may allow a user to enter arbitrary +** SQL queries for evaluation by a database. But the application does +** not want the user to be able to make arbitrary changes to the +** database. An authorizer could then be put in place while the +** user-entered SQL is being [sqlite3_prepare | prepared] that +** disallows everything except [SELECT] statements. +** +** Applications that need to process SQL from untrusted sources +** might also consider lowering resource limits using [sqlite3_limit()] +** and limiting database size using the [max_page_count] [PRAGMA] +** in addition to using an authorizer. +** +** ^(Only a single authorizer can be in place on a database connection +** at a time. Each call to sqlite3_set_authorizer overrides the +** previous call.)^ ^Disable the authorizer by installing a NULL callback. +** The authorizer is disabled by default. +** +** The authorizer callback must not do anything that will modify +** the database connection that invoked the authorizer callback. +** Note that [sqlite3_prepare_v2()] and [sqlite3_step()] both modify their +** database connections for the meaning of "modify" in this paragraph. +** +** ^When [sqlite3_prepare_v2()] is used to prepare a statement, the +** statement might be re-prepared during [sqlite3_step()] due to a +** schema change. Hence, the application should ensure that the +** correct authorizer callback remains in place during the [sqlite3_step()]. +** +** ^Note that the authorizer callback is invoked only during +** [sqlite3_prepare()] or its variants. Authorization is not +** performed during statement evaluation in [sqlite3_step()], unless +** as stated in the previous paragraph, sqlite3_step() invokes +** sqlite3_prepare_v2() to reprepare a statement after a schema change. +*/ +SQLITE_API int sqlite3_set_authorizer( + sqlite3*, + int (*xAuth)(void*,int,const char*,const char*,const char*,const char*), + void *pUserData +); + +/* +** CAPI3REF: Authorizer Return Codes +** +** The [sqlite3_set_authorizer | authorizer callback function] must +** return either [SQLITE_OK] or one of these two constants in order +** to signal SQLite whether or not the action is permitted. See the +** [sqlite3_set_authorizer | authorizer documentation] for additional +** information. +** +** Note that SQLITE_IGNORE is also used as a [SQLITE_ROLLBACK | return code] +** from the [sqlite3_vtab_on_conflict()] interface. +*/ +#define SQLITE_DENY 1 /* Abort the SQL statement with an error */ +#define SQLITE_IGNORE 2 /* Don't allow access, but don't generate an error */ + +/* +** CAPI3REF: Authorizer Action Codes +** +** The [sqlite3_set_authorizer()] interface registers a callback function +** that is invoked to authorize certain SQL statement actions. The +** second parameter to the callback is an integer code that specifies +** what action is being authorized. These are the integer action codes that +** the authorizer callback may be passed. +** +** These action code values signify what kind of operation is to be +** authorized. The 3rd and 4th parameters to the authorization +** callback function will be parameters or NULL depending on which of these +** codes is used as the second parameter. ^(The 5th parameter to the +** authorizer callback is the name of the database ("main", "temp", +** etc.) if applicable.)^ ^The 6th parameter to the authorizer callback +** is the name of the inner-most trigger or view that is responsible for +** the access attempt or NULL if this access attempt is directly from +** top-level SQL code. +*/ +/******************************************* 3rd ************ 4th ***********/ +#define SQLITE_CREATE_INDEX 1 /* Index Name Table Name */ +#define SQLITE_CREATE_TABLE 2 /* Table Name NULL */ +#define SQLITE_CREATE_TEMP_INDEX 3 /* Index Name Table Name */ +#define SQLITE_CREATE_TEMP_TABLE 4 /* Table Name NULL */ +#define SQLITE_CREATE_TEMP_TRIGGER 5 /* Trigger Name Table Name */ +#define SQLITE_CREATE_TEMP_VIEW 6 /* View Name NULL */ +#define SQLITE_CREATE_TRIGGER 7 /* Trigger Name Table Name */ +#define SQLITE_CREATE_VIEW 8 /* View Name NULL */ +#define SQLITE_DELETE 9 /* Table Name NULL */ +#define SQLITE_DROP_INDEX 10 /* Index Name Table Name */ +#define SQLITE_DROP_TABLE 11 /* Table Name NULL */ +#define SQLITE_DROP_TEMP_INDEX 12 /* Index Name Table Name */ +#define SQLITE_DROP_TEMP_TABLE 13 /* Table Name NULL */ +#define SQLITE_DROP_TEMP_TRIGGER 14 /* Trigger Name Table Name */ +#define SQLITE_DROP_TEMP_VIEW 15 /* View Name NULL */ +#define SQLITE_DROP_TRIGGER 16 /* Trigger Name Table Name */ +#define SQLITE_DROP_VIEW 17 /* View Name NULL */ +#define SQLITE_INSERT 18 /* Table Name NULL */ +#define SQLITE_PRAGMA 19 /* Pragma Name 1st arg or NULL */ +#define SQLITE_READ 20 /* Table Name Column Name */ +#define SQLITE_SELECT 21 /* NULL NULL */ +#define SQLITE_TRANSACTION 22 /* Operation NULL */ +#define SQLITE_UPDATE 23 /* Table Name Column Name */ +#define SQLITE_ATTACH 24 /* Filename NULL */ +#define SQLITE_DETACH 25 /* Database Name NULL */ +#define SQLITE_ALTER_TABLE 26 /* Database Name Table Name */ +#define SQLITE_REINDEX 27 /* Index Name NULL */ +#define SQLITE_ANALYZE 28 /* Table Name NULL */ +#define SQLITE_CREATE_VTABLE 29 /* Table Name Module Name */ +#define SQLITE_DROP_VTABLE 30 /* Table Name Module Name */ +#define SQLITE_FUNCTION 31 /* NULL Function Name */ +#define SQLITE_SAVEPOINT 32 /* Operation Savepoint Name */ +#define SQLITE_COPY 0 /* No longer used */ + +/* +** CAPI3REF: Tracing And Profiling Functions +** +** These routines register callback functions that can be used for +** tracing and profiling the execution of SQL statements. +** +** ^The callback function registered by sqlite3_trace() is invoked at +** various times when an SQL statement is being run by [sqlite3_step()]. +** ^The sqlite3_trace() callback is invoked with a UTF-8 rendering of the +** SQL statement text as the statement first begins executing. +** ^(Additional sqlite3_trace() callbacks might occur +** as each triggered subprogram is entered. The callbacks for triggers +** contain a UTF-8 SQL comment that identifies the trigger.)^ +** +** ^The callback function registered by sqlite3_profile() is invoked +** as each SQL statement finishes. ^The profile callback contains +** the original statement text and an estimate of wall-clock time +** of how long that statement took to run. ^The profile callback +** time is in units of nanoseconds, however the current implementation +** is only capable of millisecond resolution so the six least significant +** digits in the time are meaningless. Future versions of SQLite +** might provide greater resolution on the profiler callback. The +** sqlite3_profile() function is considered experimental and is +** subject to change in future versions of SQLite. +*/ +SQLITE_API void *sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*); +SQLITE_API SQLITE_EXPERIMENTAL void *sqlite3_profile(sqlite3*, + void(*xProfile)(void*,const char*,sqlite3_uint64), void*); + +/* +** CAPI3REF: Query Progress Callbacks +** +** ^The sqlite3_progress_handler(D,N,X,P) interface causes the callback +** function X to be invoked periodically during long running calls to +** [sqlite3_exec()], [sqlite3_step()] and [sqlite3_get_table()] for +** database connection D. An example use for this +** interface is to keep a GUI updated during a large query. +** +** ^The parameter P is passed through as the only parameter to the +** callback function X. ^The parameter N is the number of +** [virtual machine instructions] that are evaluated between successive +** invocations of the callback X. +** +** ^Only a single progress handler may be defined at one time per +** [database connection]; setting a new progress handler cancels the +** old one. ^Setting parameter X to NULL disables the progress handler. +** ^The progress handler is also disabled by setting N to a value less +** than 1. +** +** ^If the progress callback returns non-zero, the operation is +** interrupted. This feature can be used to implement a +** "Cancel" button on a GUI progress dialog box. +** +** The progress handler callback must not do anything that will modify +** the database connection that invoked the progress handler. +** Note that [sqlite3_prepare_v2()] and [sqlite3_step()] both modify their +** database connections for the meaning of "modify" in this paragraph. +** +*/ +SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); + +/* +** CAPI3REF: Opening A New Database Connection +** +** ^These routines open an SQLite database file as specified by the +** filename argument. ^The filename argument is interpreted as UTF-8 for +** sqlite3_open() and sqlite3_open_v2() and as UTF-16 in the native byte +** order for sqlite3_open16(). ^(A [database connection] handle is usually +** returned in *ppDb, even if an error occurs. The only exception is that +** if SQLite is unable to allocate memory to hold the [sqlite3] object, +** a NULL will be written into *ppDb instead of a pointer to the [sqlite3] +** object.)^ ^(If the database is opened (and/or created) successfully, then +** [SQLITE_OK] is returned. Otherwise an [error code] is returned.)^ ^The +** [sqlite3_errmsg()] or [sqlite3_errmsg16()] routines can be used to obtain +** an English language description of the error following a failure of any +** of the sqlite3_open() routines. +** +** ^The default encoding for the database will be UTF-8 if +** sqlite3_open() or sqlite3_open_v2() is called and +** UTF-16 in the native byte order if sqlite3_open16() is used. +** +** Whether or not an error occurs when it is opened, resources +** associated with the [database connection] handle should be released by +** passing it to [sqlite3_close()] when it is no longer required. +** +** The sqlite3_open_v2() interface works like sqlite3_open() +** except that it accepts two additional parameters for additional control +** over the new database connection. ^(The flags parameter to +** sqlite3_open_v2() can take one of +** the following three values, optionally combined with the +** [SQLITE_OPEN_NOMUTEX], [SQLITE_OPEN_FULLMUTEX], [SQLITE_OPEN_SHAREDCACHE], +** [SQLITE_OPEN_PRIVATECACHE], and/or [SQLITE_OPEN_URI] flags:)^ +** +**
+** ^(
[SQLITE_OPEN_READONLY]
+**
The database is opened in read-only mode. If the database does not +** already exist, an error is returned.
)^ +** +** ^(
[SQLITE_OPEN_READWRITE]
+**
The database is opened for reading and writing if possible, or reading +** only if the file is write protected by the operating system. In either +** case the database must already exist, otherwise an error is returned.
)^ +** +** ^(
[SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE]
+**
The database is opened for reading and writing, and is created if +** it does not already exist. This is the behavior that is always used for +** sqlite3_open() and sqlite3_open16().
)^ +**
+** +** If the 3rd parameter to sqlite3_open_v2() is not one of the +** combinations shown above optionally combined with other +** [SQLITE_OPEN_READONLY | SQLITE_OPEN_* bits] +** then the behavior is undefined. +** +** ^If the [SQLITE_OPEN_NOMUTEX] flag is set, then the database connection +** opens in the multi-thread [threading mode] as long as the single-thread +** mode has not been set at compile-time or start-time. ^If the +** [SQLITE_OPEN_FULLMUTEX] flag is set then the database connection opens +** in the serialized [threading mode] unless single-thread was +** previously selected at compile-time or start-time. +** ^The [SQLITE_OPEN_SHAREDCACHE] flag causes the database connection to be +** eligible to use [shared cache mode], regardless of whether or not shared +** cache is enabled using [sqlite3_enable_shared_cache()]. ^The +** [SQLITE_OPEN_PRIVATECACHE] flag causes the database connection to not +** participate in [shared cache mode] even if it is enabled. +** +** ^The fourth parameter to sqlite3_open_v2() is the name of the +** [sqlite3_vfs] object that defines the operating system interface that +** the new database connection should use. ^If the fourth parameter is +** a NULL pointer then the default [sqlite3_vfs] object is used. +** +** ^If the filename is ":memory:", then a private, temporary in-memory database +** is created for the connection. ^This in-memory database will vanish when +** the database connection is closed. Future versions of SQLite might +** make use of additional special filenames that begin with the ":" character. +** It is recommended that when a database filename actually does begin with +** a ":" character you should prefix the filename with a pathname such as +** "./" to avoid ambiguity. +** +** ^If the filename is an empty string, then a private, temporary +** on-disk database will be created. ^This private database will be +** automatically deleted as soon as the database connection is closed. +** +** [[URI filenames in sqlite3_open()]]

URI Filenames

+** +** ^If [URI filename] interpretation is enabled, and the filename argument +** begins with "file:", then the filename is interpreted as a URI. ^URI +** filename interpretation is enabled if the [SQLITE_OPEN_URI] flag is +** set in the fourth argument to sqlite3_open_v2(), or if it has +** been enabled globally using the [SQLITE_CONFIG_URI] option with the +** [sqlite3_config()] method or by the [SQLITE_USE_URI] compile-time option. +** As of SQLite version 3.7.7, URI filename interpretation is turned off +** by default, but future releases of SQLite might enable URI filename +** interpretation by default. See "[URI filenames]" for additional +** information. +** +** URI filenames are parsed according to RFC 3986. ^If the URI contains an +** authority, then it must be either an empty string or the string +** "localhost". ^If the authority is not an empty string or "localhost", an +** error is returned to the caller. ^The fragment component of a URI, if +** present, is ignored. +** +** ^SQLite uses the path component of the URI as the name of the disk file +** which contains the database. ^If the path begins with a '/' character, +** then it is interpreted as an absolute path. ^If the path does not begin +** with a '/' (meaning that the authority section is omitted from the URI) +** then the path is interpreted as a relative path. +** ^On windows, the first component of an absolute path +** is a drive specification (e.g. "C:"). +** +** [[core URI query parameters]] +** The query component of a URI may contain parameters that are interpreted +** either by SQLite itself, or by a [VFS | custom VFS implementation]. +** SQLite interprets the following three query parameters: +** +**
    +**
  • vfs: ^The "vfs" parameter may be used to specify the name of +** a VFS object that provides the operating system interface that should +** be used to access the database file on disk. ^If this option is set to +** an empty string the default VFS object is used. ^Specifying an unknown +** VFS is an error. ^If sqlite3_open_v2() is used and the vfs option is +** present, then the VFS specified by the option takes precedence over +** the value passed as the fourth parameter to sqlite3_open_v2(). +** +**
  • mode: ^(The mode parameter may be set to either "ro", "rw" or +** "rwc". Attempting to set it to any other value is an error)^. +** ^If "ro" is specified, then the database is opened for read-only +** access, just as if the [SQLITE_OPEN_READONLY] flag had been set in the +** third argument to sqlite3_prepare_v2(). ^If the mode option is set to +** "rw", then the database is opened for read-write (but not create) +** access, as if SQLITE_OPEN_READWRITE (but not SQLITE_OPEN_CREATE) had +** been set. ^Value "rwc" is equivalent to setting both +** SQLITE_OPEN_READWRITE and SQLITE_OPEN_CREATE. ^If sqlite3_open_v2() is +** used, it is an error to specify a value for the mode parameter that is +** less restrictive than that specified by the flags passed as the third +** parameter. +** +**
  • cache: ^The cache parameter may be set to either "shared" or +** "private". ^Setting it to "shared" is equivalent to setting the +** SQLITE_OPEN_SHAREDCACHE bit in the flags argument passed to +** sqlite3_open_v2(). ^Setting the cache parameter to "private" is +** equivalent to setting the SQLITE_OPEN_PRIVATECACHE bit. +** ^If sqlite3_open_v2() is used and the "cache" parameter is present in +** a URI filename, its value overrides any behaviour requested by setting +** SQLITE_OPEN_PRIVATECACHE or SQLITE_OPEN_SHAREDCACHE flag. +**
+** +** ^Specifying an unknown parameter in the query component of a URI is not an +** error. Future versions of SQLite might understand additional query +** parameters. See "[query parameters with special meaning to SQLite]" for +** additional information. +** +** [[URI filename examples]]

URI filename examples

+** +** +**
URI filenames Results +**
file:data.db +** Open the file "data.db" in the current directory. +**
file:/home/fred/data.db
+** file:///home/fred/data.db
+** file://localhost/home/fred/data.db
+** Open the database file "/home/fred/data.db". +**
file://darkstar/home/fred/data.db +** An error. "darkstar" is not a recognized authority. +**
+** file:///C:/Documents%20and%20Settings/fred/Desktop/data.db +** Windows only: Open the file "data.db" on fred's desktop on drive +** C:. Note that the %20 escaping in this example is not strictly +** necessary - space characters can be used literally +** in URI filenames. +**
file:data.db?mode=ro&cache=private +** Open file "data.db" in the current directory for read-only access. +** Regardless of whether or not shared-cache mode is enabled by +** default, use a private cache. +**
file:/home/fred/data.db?vfs=unix-nolock +** Open file "/home/fred/data.db". Use the special VFS "unix-nolock". +**
file:data.db?mode=readonly +** An error. "readonly" is not a valid option for the "mode" parameter. +**
+** +** ^URI hexadecimal escape sequences (%HH) are supported within the path and +** query components of a URI. A hexadecimal escape sequence consists of a +** percent sign - "%" - followed by exactly two hexadecimal digits +** specifying an octet value. ^Before the path or query components of a +** URI filename are interpreted, they are encoded using UTF-8 and all +** hexadecimal escape sequences replaced by a single byte containing the +** corresponding octet. If this process generates an invalid UTF-8 encoding, +** the results are undefined. +** +** Note to Windows users: The encoding used for the filename argument +** of sqlite3_open() and sqlite3_open_v2() must be UTF-8, not whatever +** codepage is currently defined. Filenames containing international +** characters must be converted to UTF-8 prior to passing them into +** sqlite3_open() or sqlite3_open_v2(). +*/ +SQLITE_API int sqlite3_open( + const char *filename, /* Database filename (UTF-8) */ + sqlite3 **ppDb /* OUT: SQLite db handle */ +); +SQLITE_API int sqlite3_open16( + const void *filename, /* Database filename (UTF-16) */ + sqlite3 **ppDb /* OUT: SQLite db handle */ +); +SQLITE_API int sqlite3_open_v2( + const char *filename, /* Database filename (UTF-8) */ + sqlite3 **ppDb, /* OUT: SQLite db handle */ + int flags, /* Flags */ + const char *zVfs /* Name of VFS module to use */ +); + +/* +** CAPI3REF: Obtain Values For URI Parameters +** +** This is a utility routine, useful to VFS implementations, that checks +** to see if a database file was a URI that contained a specific query +** parameter, and if so obtains the value of the query parameter. +** +** The zFilename argument is the filename pointer passed into the xOpen() +** method of a VFS implementation. The zParam argument is the name of the +** query parameter we seek. This routine returns the value of the zParam +** parameter if it exists. If the parameter does not exist, this routine +** returns a NULL pointer. +** +** If the zFilename argument to this function is not a pointer that SQLite +** passed into the xOpen VFS method, then the behavior of this routine +** is undefined and probably undesirable. +*/ +SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam); + + +/* +** CAPI3REF: Error Codes And Messages +** +** ^The sqlite3_errcode() interface returns the numeric [result code] or +** [extended result code] for the most recent failed sqlite3_* API call +** associated with a [database connection]. If a prior API call failed +** but the most recent API call succeeded, the return value from +** sqlite3_errcode() is undefined. ^The sqlite3_extended_errcode() +** interface is the same except that it always returns the +** [extended result code] even when extended result codes are +** disabled. +** +** ^The sqlite3_errmsg() and sqlite3_errmsg16() return English-language +** text that describes the error, as either UTF-8 or UTF-16 respectively. +** ^(Memory to hold the error message string is managed internally. +** The application does not need to worry about freeing the result. +** However, the error string might be overwritten or deallocated by +** subsequent calls to other SQLite interface functions.)^ +** +** When the serialized [threading mode] is in use, it might be the +** case that a second error occurs on a separate thread in between +** the time of the first error and the call to these interfaces. +** When that happens, the second error will be reported since these +** interfaces always report the most recent result. To avoid +** this, each thread can obtain exclusive use of the [database connection] D +** by invoking [sqlite3_mutex_enter]([sqlite3_db_mutex](D)) before beginning +** to use D and invoking [sqlite3_mutex_leave]([sqlite3_db_mutex](D)) after +** all calls to the interfaces listed here are completed. +** +** If an interface fails with SQLITE_MISUSE, that means the interface +** was invoked incorrectly by the application. In that case, the +** error code and message may or may not be set. +*/ +SQLITE_API int sqlite3_errcode(sqlite3 *db); +SQLITE_API int sqlite3_extended_errcode(sqlite3 *db); +SQLITE_API const char *sqlite3_errmsg(sqlite3*); +SQLITE_API const void *sqlite3_errmsg16(sqlite3*); + +/* +** CAPI3REF: SQL Statement Object +** KEYWORDS: {prepared statement} {prepared statements} +** +** An instance of this object represents a single SQL statement. +** This object is variously known as a "prepared statement" or a +** "compiled SQL statement" or simply as a "statement". +** +** The life of a statement object goes something like this: +** +**
    +**
  1. Create the object using [sqlite3_prepare_v2()] or a related +** function. +**
  2. Bind values to [host parameters] using the sqlite3_bind_*() +** interfaces. +**
  3. Run the SQL by calling [sqlite3_step()] one or more times. +**
  4. Reset the statement using [sqlite3_reset()] then go back +** to step 2. Do this zero or more times. +**
  5. Destroy the object using [sqlite3_finalize()]. +**
+** +** Refer to documentation on individual methods above for additional +** information. +*/ +typedef struct sqlite3_stmt sqlite3_stmt; + +/* +** CAPI3REF: Run-time Limits +** +** ^(This interface allows the size of various constructs to be limited +** on a connection by connection basis. The first parameter is the +** [database connection] whose limit is to be set or queried. The +** second parameter is one of the [limit categories] that define a +** class of constructs to be size limited. The third parameter is the +** new limit for that construct.)^ +** +** ^If the new limit is a negative number, the limit is unchanged. +** ^(For each limit category SQLITE_LIMIT_NAME there is a +** [limits | hard upper bound] +** set at compile-time by a C preprocessor macro called +** [limits | SQLITE_MAX_NAME]. +** (The "_LIMIT_" in the name is changed to "_MAX_".))^ +** ^Attempts to increase a limit above its hard upper bound are +** silently truncated to the hard upper bound. +** +** ^Regardless of whether or not the limit was changed, the +** [sqlite3_limit()] interface returns the prior value of the limit. +** ^Hence, to find the current value of a limit without changing it, +** simply invoke this interface with the third parameter set to -1. +** +** Run-time limits are intended for use in applications that manage +** both their own internal database and also databases that are controlled +** by untrusted external sources. An example application might be a +** web browser that has its own databases for storing history and +** separate databases controlled by JavaScript applications downloaded +** off the Internet. The internal databases can be given the +** large, default limits. Databases managed by external sources can +** be given much smaller limits designed to prevent a denial of service +** attack. Developers might also want to use the [sqlite3_set_authorizer()] +** interface to further control untrusted SQL. The size of the database +** created by an untrusted script can be contained using the +** [max_page_count] [PRAGMA]. +** +** New run-time limit categories may be added in future releases. +*/ +SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); + +/* +** CAPI3REF: Run-Time Limit Categories +** KEYWORDS: {limit category} {*limit categories} +** +** These constants define various performance limits +** that can be lowered at run-time using [sqlite3_limit()]. +** The synopsis of the meanings of the various limits is shown below. +** Additional information is available at [limits | Limits in SQLite]. +** +**
+** [[SQLITE_LIMIT_LENGTH]] ^(
SQLITE_LIMIT_LENGTH
+**
The maximum size of any string or BLOB or table row, in bytes.
)^ +** +** [[SQLITE_LIMIT_SQL_LENGTH]] ^(
SQLITE_LIMIT_SQL_LENGTH
+**
The maximum length of an SQL statement, in bytes.
)^ +** +** [[SQLITE_LIMIT_COLUMN]] ^(
SQLITE_LIMIT_COLUMN
+**
The maximum number of columns in a table definition or in the +** result set of a [SELECT] or the maximum number of columns in an index +** or in an ORDER BY or GROUP BY clause.
)^ +** +** [[SQLITE_LIMIT_EXPR_DEPTH]] ^(
SQLITE_LIMIT_EXPR_DEPTH
+**
The maximum depth of the parse tree on any expression.
)^ +** +** [[SQLITE_LIMIT_COMPOUND_SELECT]] ^(
SQLITE_LIMIT_COMPOUND_SELECT
+**
The maximum number of terms in a compound SELECT statement.
)^ +** +** [[SQLITE_LIMIT_VDBE_OP]] ^(
SQLITE_LIMIT_VDBE_OP
+**
The maximum number of instructions in a virtual machine program +** used to implement an SQL statement. This limit is not currently +** enforced, though that might be added in some future release of +** SQLite.
)^ +** +** [[SQLITE_LIMIT_FUNCTION_ARG]] ^(
SQLITE_LIMIT_FUNCTION_ARG
+**
The maximum number of arguments on a function.
)^ +** +** [[SQLITE_LIMIT_ATTACHED]] ^(
SQLITE_LIMIT_ATTACHED
+**
The maximum number of [ATTACH | attached databases].)^
+** +** [[SQLITE_LIMIT_LIKE_PATTERN_LENGTH]] +** ^(
SQLITE_LIMIT_LIKE_PATTERN_LENGTH
+**
The maximum length of the pattern argument to the [LIKE] or +** [GLOB] operators.
)^ +** +** [[SQLITE_LIMIT_VARIABLE_NUMBER]] +** ^(
SQLITE_LIMIT_VARIABLE_NUMBER
+**
The maximum index number of any [parameter] in an SQL statement.)^ +** +** [[SQLITE_LIMIT_TRIGGER_DEPTH]] ^(
SQLITE_LIMIT_TRIGGER_DEPTH
+**
The maximum depth of recursion for triggers.
)^ +**
+*/ +#define SQLITE_LIMIT_LENGTH 0 +#define SQLITE_LIMIT_SQL_LENGTH 1 +#define SQLITE_LIMIT_COLUMN 2 +#define SQLITE_LIMIT_EXPR_DEPTH 3 +#define SQLITE_LIMIT_COMPOUND_SELECT 4 +#define SQLITE_LIMIT_VDBE_OP 5 +#define SQLITE_LIMIT_FUNCTION_ARG 6 +#define SQLITE_LIMIT_ATTACHED 7 +#define SQLITE_LIMIT_LIKE_PATTERN_LENGTH 8 +#define SQLITE_LIMIT_VARIABLE_NUMBER 9 +#define SQLITE_LIMIT_TRIGGER_DEPTH 10 + +/* +** CAPI3REF: Compiling An SQL Statement +** KEYWORDS: {SQL statement compiler} +** +** To execute an SQL query, it must first be compiled into a byte-code +** program using one of these routines. +** +** The first argument, "db", is a [database connection] obtained from a +** prior successful call to [sqlite3_open()], [sqlite3_open_v2()] or +** [sqlite3_open16()]. The database connection must not have been closed. +** +** The second argument, "zSql", is the statement to be compiled, encoded +** as either UTF-8 or UTF-16. The sqlite3_prepare() and sqlite3_prepare_v2() +** interfaces use UTF-8, and sqlite3_prepare16() and sqlite3_prepare16_v2() +** use UTF-16. +** +** ^If the nByte argument is less than zero, then zSql is read up to the +** first zero terminator. ^If nByte is non-negative, then it is the maximum +** number of bytes read from zSql. ^When nByte is non-negative, the +** zSql string ends at either the first '\000' or '\u0000' character or +** the nByte-th byte, whichever comes first. If the caller knows +** that the supplied string is nul-terminated, then there is a small +** performance advantage to be gained by passing an nByte parameter that +** is equal to the number of bytes in the input string including +** the nul-terminator bytes. +** +** ^If pzTail is not NULL then *pzTail is made to point to the first byte +** past the end of the first SQL statement in zSql. These routines only +** compile the first statement in zSql, so *pzTail is left pointing to +** what remains uncompiled. +** +** ^*ppStmt is left pointing to a compiled [prepared statement] that can be +** executed using [sqlite3_step()]. ^If there is an error, *ppStmt is set +** to NULL. ^If the input text contains no SQL (if the input is an empty +** string or a comment) then *ppStmt is set to NULL. +** The calling procedure is responsible for deleting the compiled +** SQL statement using [sqlite3_finalize()] after it has finished with it. +** ppStmt may not be NULL. +** +** ^On success, the sqlite3_prepare() family of routines return [SQLITE_OK]; +** otherwise an [error code] is returned. +** +** The sqlite3_prepare_v2() and sqlite3_prepare16_v2() interfaces are +** recommended for all new programs. The two older interfaces are retained +** for backwards compatibility, but their use is discouraged. +** ^In the "v2" interfaces, the prepared statement +** that is returned (the [sqlite3_stmt] object) contains a copy of the +** original SQL text. This causes the [sqlite3_step()] interface to +** behave differently in three ways: +** +**
    +**
  1. +** ^If the database schema changes, instead of returning [SQLITE_SCHEMA] as it +** always used to do, [sqlite3_step()] will automatically recompile the SQL +** statement and try to run it again. +**
  2. +** +**
  3. +** ^When an error occurs, [sqlite3_step()] will return one of the detailed +** [error codes] or [extended error codes]. ^The legacy behavior was that +** [sqlite3_step()] would only return a generic [SQLITE_ERROR] result code +** and the application would have to make a second call to [sqlite3_reset()] +** in order to find the underlying cause of the problem. With the "v2" prepare +** interfaces, the underlying reason for the error is returned immediately. +**
  4. +** +**
  5. +** ^If the specific value bound to [parameter | host parameter] in the +** WHERE clause might influence the choice of query plan for a statement, +** then the statement will be automatically recompiled, as if there had been +** a schema change, on the first [sqlite3_step()] call following any change +** to the [sqlite3_bind_text | bindings] of that [parameter]. +** ^The specific value of WHERE-clause [parameter] might influence the +** choice of query plan if the parameter is the left-hand side of a [LIKE] +** or [GLOB] operator or if the parameter is compared to an indexed column +** and the [SQLITE_ENABLE_STAT2] compile-time option is enabled. +** the +**
  6. +**
+*/ +SQLITE_API int sqlite3_prepare( + sqlite3 *db, /* Database handle */ + const char *zSql, /* SQL statement, UTF-8 encoded */ + int nByte, /* Maximum length of zSql in bytes. */ + sqlite3_stmt **ppStmt, /* OUT: Statement handle */ + const char **pzTail /* OUT: Pointer to unused portion of zSql */ +); +SQLITE_API int sqlite3_prepare_v2( + sqlite3 *db, /* Database handle */ + const char *zSql, /* SQL statement, UTF-8 encoded */ + int nByte, /* Maximum length of zSql in bytes. */ + sqlite3_stmt **ppStmt, /* OUT: Statement handle */ + const char **pzTail /* OUT: Pointer to unused portion of zSql */ +); +SQLITE_API int sqlite3_prepare16( + sqlite3 *db, /* Database handle */ + const void *zSql, /* SQL statement, UTF-16 encoded */ + int nByte, /* Maximum length of zSql in bytes. */ + sqlite3_stmt **ppStmt, /* OUT: Statement handle */ + const void **pzTail /* OUT: Pointer to unused portion of zSql */ +); +SQLITE_API int sqlite3_prepare16_v2( + sqlite3 *db, /* Database handle */ + const void *zSql, /* SQL statement, UTF-16 encoded */ + int nByte, /* Maximum length of zSql in bytes. */ + sqlite3_stmt **ppStmt, /* OUT: Statement handle */ + const void **pzTail /* OUT: Pointer to unused portion of zSql */ +); + +/* +** CAPI3REF: Retrieving Statement SQL +** +** ^This interface can be used to retrieve a saved copy of the original +** SQL text used to create a [prepared statement] if that statement was +** compiled using either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()]. +*/ +SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt); + +/* +** CAPI3REF: Determine If An SQL Statement Writes The Database +** +** ^The sqlite3_stmt_readonly(X) interface returns true (non-zero) if +** and only if the [prepared statement] X makes no direct changes to +** the content of the database file. +** +** Note that [application-defined SQL functions] or +** [virtual tables] might change the database indirectly as a side effect. +** ^(For example, if an application defines a function "eval()" that +** calls [sqlite3_exec()], then the following SQL statement would +** change the database file through side-effects: +** +**
+**    SELECT eval('DELETE FROM t1') FROM t2;
+** 
+** +** But because the [SELECT] statement does not change the database file +** directly, sqlite3_stmt_readonly() would still return true.)^ +** +** ^Transaction control statements such as [BEGIN], [COMMIT], [ROLLBACK], +** [SAVEPOINT], and [RELEASE] cause sqlite3_stmt_readonly() to return true, +** since the statements themselves do not actually modify the database but +** rather they control the timing of when other statements modify the +** database. ^The [ATTACH] and [DETACH] statements also cause +** sqlite3_stmt_readonly() to return true since, while those statements +** change the configuration of a database connection, they do not make +** changes to the content of the database files on disk. +*/ +SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt); + +/* +** CAPI3REF: Dynamically Typed Value Object +** KEYWORDS: {protected sqlite3_value} {unprotected sqlite3_value} +** +** SQLite uses the sqlite3_value object to represent all values +** that can be stored in a database table. SQLite uses dynamic typing +** for the values it stores. ^Values stored in sqlite3_value objects +** can be integers, floating point values, strings, BLOBs, or NULL. +** +** An sqlite3_value object may be either "protected" or "unprotected". +** Some interfaces require a protected sqlite3_value. Other interfaces +** will accept either a protected or an unprotected sqlite3_value. +** Every interface that accepts sqlite3_value arguments specifies +** whether or not it requires a protected sqlite3_value. +** +** The terms "protected" and "unprotected" refer to whether or not +** a mutex is held. An internal mutex is held for a protected +** sqlite3_value object but no mutex is held for an unprotected +** sqlite3_value object. If SQLite is compiled to be single-threaded +** (with [SQLITE_THREADSAFE=0] and with [sqlite3_threadsafe()] returning 0) +** or if SQLite is run in one of reduced mutex modes +** [SQLITE_CONFIG_SINGLETHREAD] or [SQLITE_CONFIG_MULTITHREAD] +** then there is no distinction between protected and unprotected +** sqlite3_value objects and they can be used interchangeably. However, +** for maximum code portability it is recommended that applications +** still make the distinction between protected and unprotected +** sqlite3_value objects even when not strictly required. +** +** ^The sqlite3_value objects that are passed as parameters into the +** implementation of [application-defined SQL functions] are protected. +** ^The sqlite3_value object returned by +** [sqlite3_column_value()] is unprotected. +** Unprotected sqlite3_value objects may only be used with +** [sqlite3_result_value()] and [sqlite3_bind_value()]. +** The [sqlite3_value_blob | sqlite3_value_type()] family of +** interfaces require protected sqlite3_value objects. +*/ +typedef struct Mem sqlite3_value; + +/* +** CAPI3REF: SQL Function Context Object +** +** The context in which an SQL function executes is stored in an +** sqlite3_context object. ^A pointer to an sqlite3_context object +** is always first parameter to [application-defined SQL functions]. +** The application-defined SQL function implementation will pass this +** pointer through into calls to [sqlite3_result_int | sqlite3_result()], +** [sqlite3_aggregate_context()], [sqlite3_user_data()], +** [sqlite3_context_db_handle()], [sqlite3_get_auxdata()], +** and/or [sqlite3_set_auxdata()]. +*/ +typedef struct sqlite3_context sqlite3_context; + +/* +** CAPI3REF: Binding Values To Prepared Statements +** KEYWORDS: {host parameter} {host parameters} {host parameter name} +** KEYWORDS: {SQL parameter} {SQL parameters} {parameter binding} +** +** ^(In the SQL statement text input to [sqlite3_prepare_v2()] and its variants, +** literals may be replaced by a [parameter] that matches one of following +** templates: +** +**
    +**
  • ? +**
  • ?NNN +**
  • :VVV +**
  • @VVV +**
  • $VVV +**
+** +** In the templates above, NNN represents an integer literal, +** and VVV represents an alphanumeric identifier.)^ ^The values of these +** parameters (also called "host parameter names" or "SQL parameters") +** can be set using the sqlite3_bind_*() routines defined here. +** +** ^The first argument to the sqlite3_bind_*() routines is always +** a pointer to the [sqlite3_stmt] object returned from +** [sqlite3_prepare_v2()] or its variants. +** +** ^The second argument is the index of the SQL parameter to be set. +** ^The leftmost SQL parameter has an index of 1. ^When the same named +** SQL parameter is used more than once, second and subsequent +** occurrences have the same index as the first occurrence. +** ^The index for named parameters can be looked up using the +** [sqlite3_bind_parameter_index()] API if desired. ^The index +** for "?NNN" parameters is the value of NNN. +** ^The NNN value must be between 1 and the [sqlite3_limit()] +** parameter [SQLITE_LIMIT_VARIABLE_NUMBER] (default value: 999). +** +** ^The third argument is the value to bind to the parameter. +** +** ^(In those routines that have a fourth argument, its value is the +** number of bytes in the parameter. To be clear: the value is the +** number of bytes in the value, not the number of characters.)^ +** ^If the fourth parameter is negative, the length of the string is +** the number of bytes up to the first zero terminator. +** +** ^The fifth argument to sqlite3_bind_blob(), sqlite3_bind_text(), and +** sqlite3_bind_text16() is a destructor used to dispose of the BLOB or +** string after SQLite has finished with it. ^The destructor is called +** to dispose of the BLOB or string even if the call to sqlite3_bind_blob(), +** sqlite3_bind_text(), or sqlite3_bind_text16() fails. +** ^If the fifth argument is +** the special value [SQLITE_STATIC], then SQLite assumes that the +** information is in static, unmanaged space and does not need to be freed. +** ^If the fifth argument has the value [SQLITE_TRANSIENT], then +** SQLite makes its own private copy of the data immediately, before +** the sqlite3_bind_*() routine returns. +** +** ^The sqlite3_bind_zeroblob() routine binds a BLOB of length N that +** is filled with zeroes. ^A zeroblob uses a fixed amount of memory +** (just an integer to hold its size) while it is being processed. +** Zeroblobs are intended to serve as placeholders for BLOBs whose +** content is later written using +** [sqlite3_blob_open | incremental BLOB I/O] routines. +** ^A negative value for the zeroblob results in a zero-length BLOB. +** +** ^If any of the sqlite3_bind_*() routines are called with a NULL pointer +** for the [prepared statement] or with a prepared statement for which +** [sqlite3_step()] has been called more recently than [sqlite3_reset()], +** then the call will return [SQLITE_MISUSE]. If any sqlite3_bind_() +** routine is passed a [prepared statement] that has been finalized, the +** result is undefined and probably harmful. +** +** ^Bindings are not cleared by the [sqlite3_reset()] routine. +** ^Unbound parameters are interpreted as NULL. +** +** ^The sqlite3_bind_* routines return [SQLITE_OK] on success or an +** [error code] if anything goes wrong. +** ^[SQLITE_RANGE] is returned if the parameter +** index is out of range. ^[SQLITE_NOMEM] is returned if malloc() fails. +** +** See also: [sqlite3_bind_parameter_count()], +** [sqlite3_bind_parameter_name()], and [sqlite3_bind_parameter_index()]. +*/ +SQLITE_API int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*)); +SQLITE_API int sqlite3_bind_double(sqlite3_stmt*, int, double); +SQLITE_API int sqlite3_bind_int(sqlite3_stmt*, int, int); +SQLITE_API int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64); +SQLITE_API int sqlite3_bind_null(sqlite3_stmt*, int); +SQLITE_API int sqlite3_bind_text(sqlite3_stmt*, int, const char*, int n, void(*)(void*)); +SQLITE_API int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*)); +SQLITE_API int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*); +SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n); + +/* +** CAPI3REF: Number Of SQL Parameters +** +** ^This routine can be used to find the number of [SQL parameters] +** in a [prepared statement]. SQL parameters are tokens of the +** form "?", "?NNN", ":AAA", "$AAA", or "@AAA" that serve as +** placeholders for values that are [sqlite3_bind_blob | bound] +** to the parameters at a later time. +** +** ^(This routine actually returns the index of the largest (rightmost) +** parameter. For all forms except ?NNN, this will correspond to the +** number of unique parameters. If parameters of the ?NNN form are used, +** there may be gaps in the list.)^ +** +** See also: [sqlite3_bind_blob|sqlite3_bind()], +** [sqlite3_bind_parameter_name()], and +** [sqlite3_bind_parameter_index()]. +*/ +SQLITE_API int sqlite3_bind_parameter_count(sqlite3_stmt*); + +/* +** CAPI3REF: Name Of A Host Parameter +** +** ^The sqlite3_bind_parameter_name(P,N) interface returns +** the name of the N-th [SQL parameter] in the [prepared statement] P. +** ^(SQL parameters of the form "?NNN" or ":AAA" or "@AAA" or "$AAA" +** have a name which is the string "?NNN" or ":AAA" or "@AAA" or "$AAA" +** respectively. +** In other words, the initial ":" or "$" or "@" or "?" +** is included as part of the name.)^ +** ^Parameters of the form "?" without a following integer have no name +** and are referred to as "nameless" or "anonymous parameters". +** +** ^The first host parameter has an index of 1, not 0. +** +** ^If the value N is out of range or if the N-th parameter is +** nameless, then NULL is returned. ^The returned string is +** always in UTF-8 encoding even if the named parameter was +** originally specified as UTF-16 in [sqlite3_prepare16()] or +** [sqlite3_prepare16_v2()]. +** +** See also: [sqlite3_bind_blob|sqlite3_bind()], +** [sqlite3_bind_parameter_count()], and +** [sqlite3_bind_parameter_index()]. +*/ +SQLITE_API const char *sqlite3_bind_parameter_name(sqlite3_stmt*, int); + +/* +** CAPI3REF: Index Of A Parameter With A Given Name +** +** ^Return the index of an SQL parameter given its name. ^The +** index value returned is suitable for use as the second +** parameter to [sqlite3_bind_blob|sqlite3_bind()]. ^A zero +** is returned if no matching parameter is found. ^The parameter +** name must be given in UTF-8 even if the original statement +** was prepared from UTF-16 text using [sqlite3_prepare16_v2()]. +** +** See also: [sqlite3_bind_blob|sqlite3_bind()], +** [sqlite3_bind_parameter_count()], and +** [sqlite3_bind_parameter_index()]. +*/ +SQLITE_API int sqlite3_bind_parameter_index(sqlite3_stmt*, const char *zName); + +/* +** CAPI3REF: Reset All Bindings On A Prepared Statement +** +** ^Contrary to the intuition of many, [sqlite3_reset()] does not reset +** the [sqlite3_bind_blob | bindings] on a [prepared statement]. +** ^Use this routine to reset all host parameters to NULL. +*/ +SQLITE_API int sqlite3_clear_bindings(sqlite3_stmt*); + +/* +** CAPI3REF: Number Of Columns In A Result Set +** +** ^Return the number of columns in the result set returned by the +** [prepared statement]. ^This routine returns 0 if pStmt is an SQL +** statement that does not return data (for example an [UPDATE]). +** +** See also: [sqlite3_data_count()] +*/ +SQLITE_API int sqlite3_column_count(sqlite3_stmt *pStmt); + +/* +** CAPI3REF: Column Names In A Result Set +** +** ^These routines return the name assigned to a particular column +** in the result set of a [SELECT] statement. ^The sqlite3_column_name() +** interface returns a pointer to a zero-terminated UTF-8 string +** and sqlite3_column_name16() returns a pointer to a zero-terminated +** UTF-16 string. ^The first parameter is the [prepared statement] +** that implements the [SELECT] statement. ^The second parameter is the +** column number. ^The leftmost column is number 0. +** +** ^The returned string pointer is valid until either the [prepared statement] +** is destroyed by [sqlite3_finalize()] or until the statement is automatically +** reprepared by the first call to [sqlite3_step()] for a particular run +** or until the next call to +** sqlite3_column_name() or sqlite3_column_name16() on the same column. +** +** ^If sqlite3_malloc() fails during the processing of either routine +** (for example during a conversion from UTF-8 to UTF-16) then a +** NULL pointer is returned. +** +** ^The name of a result column is the value of the "AS" clause for +** that column, if there is an AS clause. If there is no AS clause +** then the name of the column is unspecified and may change from +** one release of SQLite to the next. +*/ +SQLITE_API const char *sqlite3_column_name(sqlite3_stmt*, int N); +SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt*, int N); + +/* +** CAPI3REF: Source Of Data In A Query Result +** +** ^These routines provide a means to determine the database, table, and +** table column that is the origin of a particular result column in +** [SELECT] statement. +** ^The name of the database or table or column can be returned as +** either a UTF-8 or UTF-16 string. ^The _database_ routines return +** the database name, the _table_ routines return the table name, and +** the origin_ routines return the column name. +** ^The returned string is valid until the [prepared statement] is destroyed +** using [sqlite3_finalize()] or until the statement is automatically +** reprepared by the first call to [sqlite3_step()] for a particular run +** or until the same information is requested +** again in a different encoding. +** +** ^The names returned are the original un-aliased names of the +** database, table, and column. +** +** ^The first argument to these interfaces is a [prepared statement]. +** ^These functions return information about the Nth result column returned by +** the statement, where N is the second function argument. +** ^The left-most column is column 0 for these routines. +** +** ^If the Nth column returned by the statement is an expression or +** subquery and is not a column value, then all of these functions return +** NULL. ^These routine might also return NULL if a memory allocation error +** occurs. ^Otherwise, they return the name of the attached database, table, +** or column that query result column was extracted from. +** +** ^As with all other SQLite APIs, those whose names end with "16" return +** UTF-16 encoded strings and the other functions return UTF-8. +** +** ^These APIs are only available if the library was compiled with the +** [SQLITE_ENABLE_COLUMN_METADATA] C-preprocessor symbol. +** +** If two or more threads call one or more of these routines against the same +** prepared statement and column at the same time then the results are +** undefined. +** +** If two or more threads call one or more +** [sqlite3_column_database_name | column metadata interfaces] +** for the same [prepared statement] and result column +** at the same time then the results are undefined. +*/ +SQLITE_API const char *sqlite3_column_database_name(sqlite3_stmt*,int); +SQLITE_API const void *sqlite3_column_database_name16(sqlite3_stmt*,int); +SQLITE_API const char *sqlite3_column_table_name(sqlite3_stmt*,int); +SQLITE_API const void *sqlite3_column_table_name16(sqlite3_stmt*,int); +SQLITE_API const char *sqlite3_column_origin_name(sqlite3_stmt*,int); +SQLITE_API const void *sqlite3_column_origin_name16(sqlite3_stmt*,int); + +/* +** CAPI3REF: Declared Datatype Of A Query Result +** +** ^(The first parameter is a [prepared statement]. +** If this statement is a [SELECT] statement and the Nth column of the +** returned result set of that [SELECT] is a table column (not an +** expression or subquery) then the declared type of the table +** column is returned.)^ ^If the Nth column of the result set is an +** expression or subquery, then a NULL pointer is returned. +** ^The returned string is always UTF-8 encoded. +** +** ^(For example, given the database schema: +** +** CREATE TABLE t1(c1 VARIANT); +** +** and the following statement to be compiled: +** +** SELECT c1 + 1, c1 FROM t1; +** +** this routine would return the string "VARIANT" for the second result +** column (i==1), and a NULL pointer for the first result column (i==0).)^ +** +** ^SQLite uses dynamic run-time typing. ^So just because a column +** is declared to contain a particular type does not mean that the +** data stored in that column is of the declared type. SQLite is +** strongly typed, but the typing is dynamic not static. ^Type +** is associated with individual values, not with the containers +** used to hold those values. +*/ +SQLITE_API const char *sqlite3_column_decltype(sqlite3_stmt*,int); +SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int); + +/* +** CAPI3REF: Evaluate An SQL Statement +** +** After a [prepared statement] has been prepared using either +** [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()] or one of the legacy +** interfaces [sqlite3_prepare()] or [sqlite3_prepare16()], this function +** must be called one or more times to evaluate the statement. +** +** The details of the behavior of the sqlite3_step() interface depend +** on whether the statement was prepared using the newer "v2" interface +** [sqlite3_prepare_v2()] and [sqlite3_prepare16_v2()] or the older legacy +** interface [sqlite3_prepare()] and [sqlite3_prepare16()]. The use of the +** new "v2" interface is recommended for new applications but the legacy +** interface will continue to be supported. +** +** ^In the legacy interface, the return value will be either [SQLITE_BUSY], +** [SQLITE_DONE], [SQLITE_ROW], [SQLITE_ERROR], or [SQLITE_MISUSE]. +** ^With the "v2" interface, any of the other [result codes] or +** [extended result codes] might be returned as well. +** +** ^[SQLITE_BUSY] means that the database engine was unable to acquire the +** database locks it needs to do its job. ^If the statement is a [COMMIT] +** or occurs outside of an explicit transaction, then you can retry the +** statement. If the statement is not a [COMMIT] and occurs within an +** explicit transaction then you should rollback the transaction before +** continuing. +** +** ^[SQLITE_DONE] means that the statement has finished executing +** successfully. sqlite3_step() should not be called again on this virtual +** machine without first calling [sqlite3_reset()] to reset the virtual +** machine back to its initial state. +** +** ^If the SQL statement being executed returns any data, then [SQLITE_ROW] +** is returned each time a new row of data is ready for processing by the +** caller. The values may be accessed using the [column access functions]. +** sqlite3_step() is called again to retrieve the next row of data. +** +** ^[SQLITE_ERROR] means that a run-time error (such as a constraint +** violation) has occurred. sqlite3_step() should not be called again on +** the VM. More information may be found by calling [sqlite3_errmsg()]. +** ^With the legacy interface, a more specific error code (for example, +** [SQLITE_INTERRUPT], [SQLITE_SCHEMA], [SQLITE_CORRUPT], and so forth) +** can be obtained by calling [sqlite3_reset()] on the +** [prepared statement]. ^In the "v2" interface, +** the more specific error code is returned directly by sqlite3_step(). +** +** [SQLITE_MISUSE] means that the this routine was called inappropriately. +** Perhaps it was called on a [prepared statement] that has +** already been [sqlite3_finalize | finalized] or on one that had +** previously returned [SQLITE_ERROR] or [SQLITE_DONE]. Or it could +** be the case that the same database connection is being used by two or +** more threads at the same moment in time. +** +** For all versions of SQLite up to and including 3.6.23.1, a call to +** [sqlite3_reset()] was required after sqlite3_step() returned anything +** other than [SQLITE_ROW] before any subsequent invocation of +** sqlite3_step(). Failure to reset the prepared statement using +** [sqlite3_reset()] would result in an [SQLITE_MISUSE] return from +** sqlite3_step(). But after version 3.6.23.1, sqlite3_step() began +** calling [sqlite3_reset()] automatically in this circumstance rather +** than returning [SQLITE_MISUSE]. This is not considered a compatibility +** break because any application that ever receives an SQLITE_MISUSE error +** is broken by definition. The [SQLITE_OMIT_AUTORESET] compile-time option +** can be used to restore the legacy behavior. +** +** Goofy Interface Alert: In the legacy interface, the sqlite3_step() +** API always returns a generic error code, [SQLITE_ERROR], following any +** error other than [SQLITE_BUSY] and [SQLITE_MISUSE]. You must call +** [sqlite3_reset()] or [sqlite3_finalize()] in order to find one of the +** specific [error codes] that better describes the error. +** We admit that this is a goofy design. The problem has been fixed +** with the "v2" interface. If you prepare all of your SQL statements +** using either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()] instead +** of the legacy [sqlite3_prepare()] and [sqlite3_prepare16()] interfaces, +** then the more specific [error codes] are returned directly +** by sqlite3_step(). The use of the "v2" interface is recommended. +*/ +SQLITE_API int sqlite3_step(sqlite3_stmt*); + +/* +** CAPI3REF: Number of columns in a result set +** +** ^The sqlite3_data_count(P) interface returns the number of columns in the +** current row of the result set of [prepared statement] P. +** ^If prepared statement P does not have results ready to return +** (via calls to the [sqlite3_column_int | sqlite3_column_*()] of +** interfaces) then sqlite3_data_count(P) returns 0. +** ^The sqlite3_data_count(P) routine also returns 0 if P is a NULL pointer. +** +** See also: [sqlite3_column_count()] +*/ +SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt); + +/* +** CAPI3REF: Fundamental Datatypes +** KEYWORDS: SQLITE_TEXT +** +** ^(Every value in SQLite has one of five fundamental datatypes: +** +**
    +**
  • 64-bit signed integer +**
  • 64-bit IEEE floating point number +**
  • string +**
  • BLOB +**
  • NULL +**
)^ +** +** These constants are codes for each of those types. +** +** Note that the SQLITE_TEXT constant was also used in SQLite version 2 +** for a completely different meaning. Software that links against both +** SQLite version 2 and SQLite version 3 should use SQLITE3_TEXT, not +** SQLITE_TEXT. +*/ +#define SQLITE_INTEGER 1 +#define SQLITE_FLOAT 2 +#define SQLITE_BLOB 4 +#define SQLITE_NULL 5 +#ifdef SQLITE_TEXT +# undef SQLITE_TEXT +#else +# define SQLITE_TEXT 3 +#endif +#define SQLITE3_TEXT 3 + +/* +** CAPI3REF: Result Values From A Query +** KEYWORDS: {column access functions} +** +** These routines form the "result set" interface. +** +** ^These routines return information about a single column of the current +** result row of a query. ^In every case the first argument is a pointer +** to the [prepared statement] that is being evaluated (the [sqlite3_stmt*] +** that was returned from [sqlite3_prepare_v2()] or one of its variants) +** and the second argument is the index of the column for which information +** should be returned. ^The leftmost column of the result set has the index 0. +** ^The number of columns in the result can be determined using +** [sqlite3_column_count()]. +** +** If the SQL statement does not currently point to a valid row, or if the +** column index is out of range, the result is undefined. +** These routines may only be called when the most recent call to +** [sqlite3_step()] has returned [SQLITE_ROW] and neither +** [sqlite3_reset()] nor [sqlite3_finalize()] have been called subsequently. +** If any of these routines are called after [sqlite3_reset()] or +** [sqlite3_finalize()] or after [sqlite3_step()] has returned +** something other than [SQLITE_ROW], the results are undefined. +** If [sqlite3_step()] or [sqlite3_reset()] or [sqlite3_finalize()] +** are called from a different thread while any of these routines +** are pending, then the results are undefined. +** +** ^The sqlite3_column_type() routine returns the +** [SQLITE_INTEGER | datatype code] for the initial data type +** of the result column. ^The returned value is one of [SQLITE_INTEGER], +** [SQLITE_FLOAT], [SQLITE_TEXT], [SQLITE_BLOB], or [SQLITE_NULL]. The value +** returned by sqlite3_column_type() is only meaningful if no type +** conversions have occurred as described below. After a type conversion, +** the value returned by sqlite3_column_type() is undefined. Future +** versions of SQLite may change the behavior of sqlite3_column_type() +** following a type conversion. +** +** ^If the result is a BLOB or UTF-8 string then the sqlite3_column_bytes() +** routine returns the number of bytes in that BLOB or string. +** ^If the result is a UTF-16 string, then sqlite3_column_bytes() converts +** the string to UTF-8 and then returns the number of bytes. +** ^If the result is a numeric value then sqlite3_column_bytes() uses +** [sqlite3_snprintf()] to convert that value to a UTF-8 string and returns +** the number of bytes in that string. +** ^If the result is NULL, then sqlite3_column_bytes() returns zero. +** +** ^If the result is a BLOB or UTF-16 string then the sqlite3_column_bytes16() +** routine returns the number of bytes in that BLOB or string. +** ^If the result is a UTF-8 string, then sqlite3_column_bytes16() converts +** the string to UTF-16 and then returns the number of bytes. +** ^If the result is a numeric value then sqlite3_column_bytes16() uses +** [sqlite3_snprintf()] to convert that value to a UTF-16 string and returns +** the number of bytes in that string. +** ^If the result is NULL, then sqlite3_column_bytes16() returns zero. +** +** ^The values returned by [sqlite3_column_bytes()] and +** [sqlite3_column_bytes16()] do not include the zero terminators at the end +** of the string. ^For clarity: the values returned by +** [sqlite3_column_bytes()] and [sqlite3_column_bytes16()] are the number of +** bytes in the string, not the number of characters. +** +** ^Strings returned by sqlite3_column_text() and sqlite3_column_text16(), +** even empty strings, are always zero terminated. ^The return +** value from sqlite3_column_blob() for a zero-length BLOB is a NULL pointer. +** +** ^The object returned by [sqlite3_column_value()] is an +** [unprotected sqlite3_value] object. An unprotected sqlite3_value object +** may only be used with [sqlite3_bind_value()] and [sqlite3_result_value()]. +** If the [unprotected sqlite3_value] object returned by +** [sqlite3_column_value()] is used in any other way, including calls +** to routines like [sqlite3_value_int()], [sqlite3_value_text()], +** or [sqlite3_value_bytes()], then the behavior is undefined. +** +** These routines attempt to convert the value where appropriate. ^For +** example, if the internal representation is FLOAT and a text result +** is requested, [sqlite3_snprintf()] is used internally to perform the +** conversion automatically. ^(The following table details the conversions +** that are applied: +** +**
+** +**
Internal
Type
Requested
Type
Conversion +** +**
NULL INTEGER Result is 0 +**
NULL FLOAT Result is 0.0 +**
NULL TEXT Result is NULL pointer +**
NULL BLOB Result is NULL pointer +**
INTEGER FLOAT Convert from integer to float +**
INTEGER TEXT ASCII rendering of the integer +**
INTEGER BLOB Same as INTEGER->TEXT +**
FLOAT INTEGER Convert from float to integer +**
FLOAT TEXT ASCII rendering of the float +**
FLOAT BLOB Same as FLOAT->TEXT +**
TEXT INTEGER Use atoi() +**
TEXT FLOAT Use atof() +**
TEXT BLOB No change +**
BLOB INTEGER Convert to TEXT then use atoi() +**
BLOB FLOAT Convert to TEXT then use atof() +**
BLOB TEXT Add a zero terminator if needed +**
+**
)^ +** +** The table above makes reference to standard C library functions atoi() +** and atof(). SQLite does not really use these functions. It has its +** own equivalent internal routines. The atoi() and atof() names are +** used in the table for brevity and because they are familiar to most +** C programmers. +** +** Note that when type conversions occur, pointers returned by prior +** calls to sqlite3_column_blob(), sqlite3_column_text(), and/or +** sqlite3_column_text16() may be invalidated. +** Type conversions and pointer invalidations might occur +** in the following cases: +** +**
    +**
  • The initial content is a BLOB and sqlite3_column_text() or +** sqlite3_column_text16() is called. A zero-terminator might +** need to be added to the string.
  • +**
  • The initial content is UTF-8 text and sqlite3_column_bytes16() or +** sqlite3_column_text16() is called. The content must be converted +** to UTF-16.
  • +**
  • The initial content is UTF-16 text and sqlite3_column_bytes() or +** sqlite3_column_text() is called. The content must be converted +** to UTF-8.
  • +**
+** +** ^Conversions between UTF-16be and UTF-16le are always done in place and do +** not invalidate a prior pointer, though of course the content of the buffer +** that the prior pointer references will have been modified. Other kinds +** of conversion are done in place when it is possible, but sometimes they +** are not possible and in those cases prior pointers are invalidated. +** +** The safest and easiest to remember policy is to invoke these routines +** in one of the following ways: +** +**
    +**
  • sqlite3_column_text() followed by sqlite3_column_bytes()
  • +**
  • sqlite3_column_blob() followed by sqlite3_column_bytes()
  • +**
  • sqlite3_column_text16() followed by sqlite3_column_bytes16()
  • +**
+** +** In other words, you should call sqlite3_column_text(), +** sqlite3_column_blob(), or sqlite3_column_text16() first to force the result +** into the desired format, then invoke sqlite3_column_bytes() or +** sqlite3_column_bytes16() to find the size of the result. Do not mix calls +** to sqlite3_column_text() or sqlite3_column_blob() with calls to +** sqlite3_column_bytes16(), and do not mix calls to sqlite3_column_text16() +** with calls to sqlite3_column_bytes(). +** +** ^The pointers returned are valid until a type conversion occurs as +** described above, or until [sqlite3_step()] or [sqlite3_reset()] or +** [sqlite3_finalize()] is called. ^The memory space used to hold strings +** and BLOBs is freed automatically. Do not pass the pointers returned +** [sqlite3_column_blob()], [sqlite3_column_text()], etc. into +** [sqlite3_free()]. +** +** ^(If a memory allocation error occurs during the evaluation of any +** of these routines, a default value is returned. The default value +** is either the integer 0, the floating point number 0.0, or a NULL +** pointer. Subsequent calls to [sqlite3_errcode()] will return +** [SQLITE_NOMEM].)^ +*/ +SQLITE_API const void *sqlite3_column_blob(sqlite3_stmt*, int iCol); +SQLITE_API int sqlite3_column_bytes(sqlite3_stmt*, int iCol); +SQLITE_API int sqlite3_column_bytes16(sqlite3_stmt*, int iCol); +SQLITE_API double sqlite3_column_double(sqlite3_stmt*, int iCol); +SQLITE_API int sqlite3_column_int(sqlite3_stmt*, int iCol); +SQLITE_API sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol); +SQLITE_API const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol); +SQLITE_API const void *sqlite3_column_text16(sqlite3_stmt*, int iCol); +SQLITE_API int sqlite3_column_type(sqlite3_stmt*, int iCol); +SQLITE_API sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol); + +/* +** CAPI3REF: Destroy A Prepared Statement Object +** +** ^The sqlite3_finalize() function is called to delete a [prepared statement]. +** ^If the most recent evaluation of the statement encountered no errors +** or if the statement is never been evaluated, then sqlite3_finalize() returns +** SQLITE_OK. ^If the most recent evaluation of statement S failed, then +** sqlite3_finalize(S) returns the appropriate [error code] or +** [extended error code]. +** +** ^The sqlite3_finalize(S) routine can be called at any point during +** the life cycle of [prepared statement] S: +** before statement S is ever evaluated, after +** one or more calls to [sqlite3_reset()], or after any call +** to [sqlite3_step()] regardless of whether or not the statement has +** completed execution. +** +** ^Invoking sqlite3_finalize() on a NULL pointer is a harmless no-op. +** +** The application must finalize every [prepared statement] in order to avoid +** resource leaks. It is a grievous error for the application to try to use +** a prepared statement after it has been finalized. Any use of a prepared +** statement after it has been finalized can result in undefined and +** undesirable behavior such as segfaults and heap corruption. +*/ +SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt); + +/* +** CAPI3REF: Reset A Prepared Statement Object +** +** The sqlite3_reset() function is called to reset a [prepared statement] +** object back to its initial state, ready to be re-executed. +** ^Any SQL statement variables that had values bound to them using +** the [sqlite3_bind_blob | sqlite3_bind_*() API] retain their values. +** Use [sqlite3_clear_bindings()] to reset the bindings. +** +** ^The [sqlite3_reset(S)] interface resets the [prepared statement] S +** back to the beginning of its program. +** +** ^If the most recent call to [sqlite3_step(S)] for the +** [prepared statement] S returned [SQLITE_ROW] or [SQLITE_DONE], +** or if [sqlite3_step(S)] has never before been called on S, +** then [sqlite3_reset(S)] returns [SQLITE_OK]. +** +** ^If the most recent call to [sqlite3_step(S)] for the +** [prepared statement] S indicated an error, then +** [sqlite3_reset(S)] returns an appropriate [error code]. +** +** ^The [sqlite3_reset(S)] interface does not change the values +** of any [sqlite3_bind_blob|bindings] on the [prepared statement] S. +*/ +SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt); + +/* +** CAPI3REF: Create Or Redefine SQL Functions +** KEYWORDS: {function creation routines} +** KEYWORDS: {application-defined SQL function} +** KEYWORDS: {application-defined SQL functions} +** +** ^These functions (collectively known as "function creation routines") +** are used to add SQL functions or aggregates or to redefine the behavior +** of existing SQL functions or aggregates. The only differences between +** these routines are the text encoding expected for +** the second parameter (the name of the function being created) +** and the presence or absence of a destructor callback for +** the application data pointer. +** +** ^The first parameter is the [database connection] to which the SQL +** function is to be added. ^If an application uses more than one database +** connection then application-defined SQL functions must be added +** to each database connection separately. +** +** ^The second parameter is the name of the SQL function to be created or +** redefined. ^The length of the name is limited to 255 bytes in a UTF-8 +** representation, exclusive of the zero-terminator. ^Note that the name +** length limit is in UTF-8 bytes, not characters nor UTF-16 bytes. +** ^Any attempt to create a function with a longer name +** will result in [SQLITE_MISUSE] being returned. +** +** ^The third parameter (nArg) +** is the number of arguments that the SQL function or +** aggregate takes. ^If this parameter is -1, then the SQL function or +** aggregate may take any number of arguments between 0 and the limit +** set by [sqlite3_limit]([SQLITE_LIMIT_FUNCTION_ARG]). If the third +** parameter is less than -1 or greater than 127 then the behavior is +** undefined. +** +** ^The fourth parameter, eTextRep, specifies what +** [SQLITE_UTF8 | text encoding] this SQL function prefers for +** its parameters. Every SQL function implementation must be able to work +** with UTF-8, UTF-16le, or UTF-16be. But some implementations may be +** more efficient with one encoding than another. ^An application may +** invoke sqlite3_create_function() or sqlite3_create_function16() multiple +** times with the same function but with different values of eTextRep. +** ^When multiple implementations of the same function are available, SQLite +** will pick the one that involves the least amount of data conversion. +** If there is only a single implementation which does not care what text +** encoding is used, then the fourth argument should be [SQLITE_ANY]. +** +** ^(The fifth parameter is an arbitrary pointer. The implementation of the +** function can gain access to this pointer using [sqlite3_user_data()].)^ +** +** ^The sixth, seventh and eighth parameters, xFunc, xStep and xFinal, are +** pointers to C-language functions that implement the SQL function or +** aggregate. ^A scalar SQL function requires an implementation of the xFunc +** callback only; NULL pointers must be passed as the xStep and xFinal +** parameters. ^An aggregate SQL function requires an implementation of xStep +** and xFinal and NULL pointer must be passed for xFunc. ^To delete an existing +** SQL function or aggregate, pass NULL pointers for all three function +** callbacks. +** +** ^(If the ninth parameter to sqlite3_create_function_v2() is not NULL, +** then it is destructor for the application data pointer. +** The destructor is invoked when the function is deleted, either by being +** overloaded or when the database connection closes.)^ +** ^The destructor is also invoked if the call to +** sqlite3_create_function_v2() fails. +** ^When the destructor callback of the tenth parameter is invoked, it +** is passed a single argument which is a copy of the application data +** pointer which was the fifth parameter to sqlite3_create_function_v2(). +** +** ^It is permitted to register multiple implementations of the same +** functions with the same name but with either differing numbers of +** arguments or differing preferred text encodings. ^SQLite will use +** the implementation that most closely matches the way in which the +** SQL function is used. ^A function implementation with a non-negative +** nArg parameter is a better match than a function implementation with +** a negative nArg. ^A function where the preferred text encoding +** matches the database encoding is a better +** match than a function where the encoding is different. +** ^A function where the encoding difference is between UTF16le and UTF16be +** is a closer match than a function where the encoding difference is +** between UTF8 and UTF16. +** +** ^Built-in functions may be overloaded by new application-defined functions. +** +** ^An application-defined function is permitted to call other +** SQLite interfaces. However, such calls must not +** close the database connection nor finalize or reset the prepared +** statement in which the function is running. +*/ +SQLITE_API int sqlite3_create_function( + sqlite3 *db, + const char *zFunctionName, + int nArg, + int eTextRep, + void *pApp, + void (*xFunc)(sqlite3_context*,int,sqlite3_value**), + void (*xStep)(sqlite3_context*,int,sqlite3_value**), + void (*xFinal)(sqlite3_context*) +); +SQLITE_API int sqlite3_create_function16( + sqlite3 *db, + const void *zFunctionName, + int nArg, + int eTextRep, + void *pApp, + void (*xFunc)(sqlite3_context*,int,sqlite3_value**), + void (*xStep)(sqlite3_context*,int,sqlite3_value**), + void (*xFinal)(sqlite3_context*) +); +SQLITE_API int sqlite3_create_function_v2( + sqlite3 *db, + const char *zFunctionName, + int nArg, + int eTextRep, + void *pApp, + void (*xFunc)(sqlite3_context*,int,sqlite3_value**), + void (*xStep)(sqlite3_context*,int,sqlite3_value**), + void (*xFinal)(sqlite3_context*), + void(*xDestroy)(void*) +); + +/* +** CAPI3REF: Text Encodings +** +** These constant define integer codes that represent the various +** text encodings supported by SQLite. +*/ +#define SQLITE_UTF8 1 +#define SQLITE_UTF16LE 2 +#define SQLITE_UTF16BE 3 +#define SQLITE_UTF16 4 /* Use native byte order */ +#define SQLITE_ANY 5 /* sqlite3_create_function only */ +#define SQLITE_UTF16_ALIGNED 8 /* sqlite3_create_collation only */ + +/* +** CAPI3REF: Deprecated Functions +** DEPRECATED +** +** These functions are [deprecated]. In order to maintain +** backwards compatibility with older code, these functions continue +** to be supported. However, new applications should avoid +** the use of these functions. To help encourage people to avoid +** using these functions, we are not going to tell you what they do. +*/ +#ifndef SQLITE_OMIT_DEPRECATED +SQLITE_API SQLITE_DEPRECATED int sqlite3_aggregate_count(sqlite3_context*); +SQLITE_API SQLITE_DEPRECATED int sqlite3_expired(sqlite3_stmt*); +SQLITE_API SQLITE_DEPRECATED int sqlite3_transfer_bindings(sqlite3_stmt*, sqlite3_stmt*); +SQLITE_API SQLITE_DEPRECATED int sqlite3_global_recover(void); +SQLITE_API SQLITE_DEPRECATED void sqlite3_thread_cleanup(void); +SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int),void*,sqlite3_int64); +#endif + +/* +** CAPI3REF: Obtaining SQL Function Parameter Values +** +** The C-language implementation of SQL functions and aggregates uses +** this set of interface routines to access the parameter values on +** the function or aggregate. +** +** The xFunc (for scalar functions) or xStep (for aggregates) parameters +** to [sqlite3_create_function()] and [sqlite3_create_function16()] +** define callbacks that implement the SQL functions and aggregates. +** The 3rd parameter to these callbacks is an array of pointers to +** [protected sqlite3_value] objects. There is one [sqlite3_value] object for +** each parameter to the SQL function. These routines are used to +** extract values from the [sqlite3_value] objects. +** +** These routines work only with [protected sqlite3_value] objects. +** Any attempt to use these routines on an [unprotected sqlite3_value] +** object results in undefined behavior. +** +** ^These routines work just like the corresponding [column access functions] +** except that these routines take a single [protected sqlite3_value] object +** pointer instead of a [sqlite3_stmt*] pointer and an integer column number. +** +** ^The sqlite3_value_text16() interface extracts a UTF-16 string +** in the native byte-order of the host machine. ^The +** sqlite3_value_text16be() and sqlite3_value_text16le() interfaces +** extract UTF-16 strings as big-endian and little-endian respectively. +** +** ^(The sqlite3_value_numeric_type() interface attempts to apply +** numeric affinity to the value. This means that an attempt is +** made to convert the value to an integer or floating point. If +** such a conversion is possible without loss of information (in other +** words, if the value is a string that looks like a number) +** then the conversion is performed. Otherwise no conversion occurs. +** The [SQLITE_INTEGER | datatype] after conversion is returned.)^ +** +** Please pay particular attention to the fact that the pointer returned +** from [sqlite3_value_blob()], [sqlite3_value_text()], or +** [sqlite3_value_text16()] can be invalidated by a subsequent call to +** [sqlite3_value_bytes()], [sqlite3_value_bytes16()], [sqlite3_value_text()], +** or [sqlite3_value_text16()]. +** +** These routines must be called from the same thread as +** the SQL function that supplied the [sqlite3_value*] parameters. +*/ +SQLITE_API const void *sqlite3_value_blob(sqlite3_value*); +SQLITE_API int sqlite3_value_bytes(sqlite3_value*); +SQLITE_API int sqlite3_value_bytes16(sqlite3_value*); +SQLITE_API double sqlite3_value_double(sqlite3_value*); +SQLITE_API int sqlite3_value_int(sqlite3_value*); +SQLITE_API sqlite3_int64 sqlite3_value_int64(sqlite3_value*); +SQLITE_API const unsigned char *sqlite3_value_text(sqlite3_value*); +SQLITE_API const void *sqlite3_value_text16(sqlite3_value*); +SQLITE_API const void *sqlite3_value_text16le(sqlite3_value*); +SQLITE_API const void *sqlite3_value_text16be(sqlite3_value*); +SQLITE_API int sqlite3_value_type(sqlite3_value*); +SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*); + +/* +** CAPI3REF: Obtain Aggregate Function Context +** +** Implementations of aggregate SQL functions use this +** routine to allocate memory for storing their state. +** +** ^The first time the sqlite3_aggregate_context(C,N) routine is called +** for a particular aggregate function, SQLite +** allocates N of memory, zeroes out that memory, and returns a pointer +** to the new memory. ^On second and subsequent calls to +** sqlite3_aggregate_context() for the same aggregate function instance, +** the same buffer is returned. Sqlite3_aggregate_context() is normally +** called once for each invocation of the xStep callback and then one +** last time when the xFinal callback is invoked. ^(When no rows match +** an aggregate query, the xStep() callback of the aggregate function +** implementation is never called and xFinal() is called exactly once. +** In those cases, sqlite3_aggregate_context() might be called for the +** first time from within xFinal().)^ +** +** ^The sqlite3_aggregate_context(C,N) routine returns a NULL pointer if N is +** less than or equal to zero or if a memory allocate error occurs. +** +** ^(The amount of space allocated by sqlite3_aggregate_context(C,N) is +** determined by the N parameter on first successful call. Changing the +** value of N in subsequent call to sqlite3_aggregate_context() within +** the same aggregate function instance will not resize the memory +** allocation.)^ +** +** ^SQLite automatically frees the memory allocated by +** sqlite3_aggregate_context() when the aggregate query concludes. +** +** The first parameter must be a copy of the +** [sqlite3_context | SQL function context] that is the first parameter +** to the xStep or xFinal callback routine that implements the aggregate +** function. +** +** This routine must be called from the same thread in which +** the aggregate SQL function is running. +*/ +SQLITE_API void *sqlite3_aggregate_context(sqlite3_context*, int nBytes); + +/* +** CAPI3REF: User Data For Functions +** +** ^The sqlite3_user_data() interface returns a copy of +** the pointer that was the pUserData parameter (the 5th parameter) +** of the [sqlite3_create_function()] +** and [sqlite3_create_function16()] routines that originally +** registered the application defined function. +** +** This routine must be called from the same thread in which +** the application-defined function is running. +*/ +SQLITE_API void *sqlite3_user_data(sqlite3_context*); + +/* +** CAPI3REF: Database Connection For Functions +** +** ^The sqlite3_context_db_handle() interface returns a copy of +** the pointer to the [database connection] (the 1st parameter) +** of the [sqlite3_create_function()] +** and [sqlite3_create_function16()] routines that originally +** registered the application defined function. +*/ +SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*); + +/* +** CAPI3REF: Function Auxiliary Data +** +** The following two functions may be used by scalar SQL functions to +** associate metadata with argument values. If the same value is passed to +** multiple invocations of the same SQL function during query execution, under +** some circumstances the associated metadata may be preserved. This may +** be used, for example, to add a regular-expression matching scalar +** function. The compiled version of the regular expression is stored as +** metadata associated with the SQL value passed as the regular expression +** pattern. The compiled regular expression can be reused on multiple +** invocations of the same function so that the original pattern string +** does not need to be recompiled on each invocation. +** +** ^The sqlite3_get_auxdata() interface returns a pointer to the metadata +** associated by the sqlite3_set_auxdata() function with the Nth argument +** value to the application-defined function. ^If no metadata has been ever +** been set for the Nth argument of the function, or if the corresponding +** function parameter has changed since the meta-data was set, +** then sqlite3_get_auxdata() returns a NULL pointer. +** +** ^The sqlite3_set_auxdata() interface saves the metadata +** pointed to by its 3rd parameter as the metadata for the N-th +** argument of the application-defined function. Subsequent +** calls to sqlite3_get_auxdata() might return this data, if it has +** not been destroyed. +** ^If it is not NULL, SQLite will invoke the destructor +** function given by the 4th parameter to sqlite3_set_auxdata() on +** the metadata when the corresponding function parameter changes +** or when the SQL statement completes, whichever comes first. +** +** SQLite is free to call the destructor and drop metadata on any +** parameter of any function at any time. ^The only guarantee is that +** the destructor will be called before the metadata is dropped. +** +** ^(In practice, metadata is preserved between function calls for +** expressions that are constant at compile time. This includes literal +** values and [parameters].)^ +** +** These routines must be called from the same thread in which +** the SQL function is running. +*/ +SQLITE_API void *sqlite3_get_auxdata(sqlite3_context*, int N); +SQLITE_API void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(void*)); + + +/* +** CAPI3REF: Constants Defining Special Destructor Behavior +** +** These are special values for the destructor that is passed in as the +** final argument to routines like [sqlite3_result_blob()]. ^If the destructor +** argument is SQLITE_STATIC, it means that the content pointer is constant +** and will never change. It does not need to be destroyed. ^The +** SQLITE_TRANSIENT value means that the content will likely change in +** the near future and that SQLite should make its own private copy of +** the content before returning. +** +** The typedef is necessary to work around problems in certain +** C++ compilers. See ticket #2191. +*/ +typedef void (*sqlite3_destructor_type)(void*); +#define SQLITE_STATIC ((sqlite3_destructor_type)0) +#define SQLITE_TRANSIENT ((sqlite3_destructor_type)-1) + +/* +** CAPI3REF: Setting The Result Of An SQL Function +** +** These routines are used by the xFunc or xFinal callbacks that +** implement SQL functions and aggregates. See +** [sqlite3_create_function()] and [sqlite3_create_function16()] +** for additional information. +** +** These functions work very much like the [parameter binding] family of +** functions used to bind values to host parameters in prepared statements. +** Refer to the [SQL parameter] documentation for additional information. +** +** ^The sqlite3_result_blob() interface sets the result from +** an application-defined function to be the BLOB whose content is pointed +** to by the second parameter and which is N bytes long where N is the +** third parameter. +** +** ^The sqlite3_result_zeroblob() interfaces set the result of +** the application-defined function to be a BLOB containing all zero +** bytes and N bytes in size, where N is the value of the 2nd parameter. +** +** ^The sqlite3_result_double() interface sets the result from +** an application-defined function to be a floating point value specified +** by its 2nd argument. +** +** ^The sqlite3_result_error() and sqlite3_result_error16() functions +** cause the implemented SQL function to throw an exception. +** ^SQLite uses the string pointed to by the +** 2nd parameter of sqlite3_result_error() or sqlite3_result_error16() +** as the text of an error message. ^SQLite interprets the error +** message string from sqlite3_result_error() as UTF-8. ^SQLite +** interprets the string from sqlite3_result_error16() as UTF-16 in native +** byte order. ^If the third parameter to sqlite3_result_error() +** or sqlite3_result_error16() is negative then SQLite takes as the error +** message all text up through the first zero character. +** ^If the third parameter to sqlite3_result_error() or +** sqlite3_result_error16() is non-negative then SQLite takes that many +** bytes (not characters) from the 2nd parameter as the error message. +** ^The sqlite3_result_error() and sqlite3_result_error16() +** routines make a private copy of the error message text before +** they return. Hence, the calling function can deallocate or +** modify the text after they return without harm. +** ^The sqlite3_result_error_code() function changes the error code +** returned by SQLite as a result of an error in a function. ^By default, +** the error code is SQLITE_ERROR. ^A subsequent call to sqlite3_result_error() +** or sqlite3_result_error16() resets the error code to SQLITE_ERROR. +** +** ^The sqlite3_result_toobig() interface causes SQLite to throw an error +** indicating that a string or BLOB is too long to represent. +** +** ^The sqlite3_result_nomem() interface causes SQLite to throw an error +** indicating that a memory allocation failed. +** +** ^The sqlite3_result_int() interface sets the return value +** of the application-defined function to be the 32-bit signed integer +** value given in the 2nd argument. +** ^The sqlite3_result_int64() interface sets the return value +** of the application-defined function to be the 64-bit signed integer +** value given in the 2nd argument. +** +** ^The sqlite3_result_null() interface sets the return value +** of the application-defined function to be NULL. +** +** ^The sqlite3_result_text(), sqlite3_result_text16(), +** sqlite3_result_text16le(), and sqlite3_result_text16be() interfaces +** set the return value of the application-defined function to be +** a text string which is represented as UTF-8, UTF-16 native byte order, +** UTF-16 little endian, or UTF-16 big endian, respectively. +** ^SQLite takes the text result from the application from +** the 2nd parameter of the sqlite3_result_text* interfaces. +** ^If the 3rd parameter to the sqlite3_result_text* interfaces +** is negative, then SQLite takes result text from the 2nd parameter +** through the first zero character. +** ^If the 3rd parameter to the sqlite3_result_text* interfaces +** is non-negative, then as many bytes (not characters) of the text +** pointed to by the 2nd parameter are taken as the application-defined +** function result. +** ^If the 4th parameter to the sqlite3_result_text* interfaces +** or sqlite3_result_blob is a non-NULL pointer, then SQLite calls that +** function as the destructor on the text or BLOB result when it has +** finished using that result. +** ^If the 4th parameter to the sqlite3_result_text* interfaces or to +** sqlite3_result_blob is the special constant SQLITE_STATIC, then SQLite +** assumes that the text or BLOB result is in constant space and does not +** copy the content of the parameter nor call a destructor on the content +** when it has finished using that result. +** ^If the 4th parameter to the sqlite3_result_text* interfaces +** or sqlite3_result_blob is the special constant SQLITE_TRANSIENT +** then SQLite makes a copy of the result into space obtained from +** from [sqlite3_malloc()] before it returns. +** +** ^The sqlite3_result_value() interface sets the result of +** the application-defined function to be a copy the +** [unprotected sqlite3_value] object specified by the 2nd parameter. ^The +** sqlite3_result_value() interface makes a copy of the [sqlite3_value] +** so that the [sqlite3_value] specified in the parameter may change or +** be deallocated after sqlite3_result_value() returns without harm. +** ^A [protected sqlite3_value] object may always be used where an +** [unprotected sqlite3_value] object is required, so either +** kind of [sqlite3_value] object can be used with this interface. +** +** If these routines are called from within the different thread +** than the one containing the application-defined function that received +** the [sqlite3_context] pointer, the results are undefined. +*/ +SQLITE_API void sqlite3_result_blob(sqlite3_context*, const void*, int, void(*)(void*)); +SQLITE_API void sqlite3_result_double(sqlite3_context*, double); +SQLITE_API void sqlite3_result_error(sqlite3_context*, const char*, int); +SQLITE_API void sqlite3_result_error16(sqlite3_context*, const void*, int); +SQLITE_API void sqlite3_result_error_toobig(sqlite3_context*); +SQLITE_API void sqlite3_result_error_nomem(sqlite3_context*); +SQLITE_API void sqlite3_result_error_code(sqlite3_context*, int); +SQLITE_API void sqlite3_result_int(sqlite3_context*, int); +SQLITE_API void sqlite3_result_int64(sqlite3_context*, sqlite3_int64); +SQLITE_API void sqlite3_result_null(sqlite3_context*); +SQLITE_API void sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*)); +SQLITE_API void sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*)); +SQLITE_API void sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*)); +SQLITE_API void sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*)); +SQLITE_API void sqlite3_result_value(sqlite3_context*, sqlite3_value*); +SQLITE_API void sqlite3_result_zeroblob(sqlite3_context*, int n); + +/* +** CAPI3REF: Define New Collating Sequences +** +** ^These functions add, remove, or modify a [collation] associated +** with the [database connection] specified as the first argument. +** +** ^The name of the collation is a UTF-8 string +** for sqlite3_create_collation() and sqlite3_create_collation_v2() +** and a UTF-16 string in native byte order for sqlite3_create_collation16(). +** ^Collation names that compare equal according to [sqlite3_strnicmp()] are +** considered to be the same name. +** +** ^(The third argument (eTextRep) must be one of the constants: +**
    +**
  • [SQLITE_UTF8], +**
  • [SQLITE_UTF16LE], +**
  • [SQLITE_UTF16BE], +**
  • [SQLITE_UTF16], or +**
  • [SQLITE_UTF16_ALIGNED]. +**
)^ +** ^The eTextRep argument determines the encoding of strings passed +** to the collating function callback, xCallback. +** ^The [SQLITE_UTF16] and [SQLITE_UTF16_ALIGNED] values for eTextRep +** force strings to be UTF16 with native byte order. +** ^The [SQLITE_UTF16_ALIGNED] value for eTextRep forces strings to begin +** on an even byte address. +** +** ^The fourth argument, pArg, is an application data pointer that is passed +** through as the first argument to the collating function callback. +** +** ^The fifth argument, xCallback, is a pointer to the collating function. +** ^Multiple collating functions can be registered using the same name but +** with different eTextRep parameters and SQLite will use whichever +** function requires the least amount of data transformation. +** ^If the xCallback argument is NULL then the collating function is +** deleted. ^When all collating functions having the same name are deleted, +** that collation is no longer usable. +** +** ^The collating function callback is invoked with a copy of the pArg +** application data pointer and with two strings in the encoding specified +** by the eTextRep argument. The collating function must return an +** integer that is negative, zero, or positive +** if the first string is less than, equal to, or greater than the second, +** respectively. A collating function must always return the same answer +** given the same inputs. If two or more collating functions are registered +** to the same collation name (using different eTextRep values) then all +** must give an equivalent answer when invoked with equivalent strings. +** The collating function must obey the following properties for all +** strings A, B, and C: +** +**
    +**
  1. If A==B then B==A. +**
  2. If A==B and B==C then A==C. +**
  3. If A<B THEN B>A. +**
  4. If A<B and B<C then A<C. +**
+** +** If a collating function fails any of the above constraints and that +** collating function is registered and used, then the behavior of SQLite +** is undefined. +** +** ^The sqlite3_create_collation_v2() works like sqlite3_create_collation() +** with the addition that the xDestroy callback is invoked on pArg when +** the collating function is deleted. +** ^Collating functions are deleted when they are overridden by later +** calls to the collation creation functions or when the +** [database connection] is closed using [sqlite3_close()]. +** +** ^The xDestroy callback is not called if the +** sqlite3_create_collation_v2() function fails. Applications that invoke +** sqlite3_create_collation_v2() with a non-NULL xDestroy argument should +** check the return code and dispose of the application data pointer +** themselves rather than expecting SQLite to deal with it for them. +** This is different from every other SQLite interface. The inconsistency +** is unfortunate but cannot be changed without breaking backwards +** compatibility. +** +** See also: [sqlite3_collation_needed()] and [sqlite3_collation_needed16()]. +*/ +SQLITE_API int sqlite3_create_collation( + sqlite3*, + const char *zName, + int eTextRep, + void *pArg, + int(*xCompare)(void*,int,const void*,int,const void*) +); +SQLITE_API int sqlite3_create_collation_v2( + sqlite3*, + const char *zName, + int eTextRep, + void *pArg, + int(*xCompare)(void*,int,const void*,int,const void*), + void(*xDestroy)(void*) +); +SQLITE_API int sqlite3_create_collation16( + sqlite3*, + const void *zName, + int eTextRep, + void *pArg, + int(*xCompare)(void*,int,const void*,int,const void*) +); + +/* +** CAPI3REF: Collation Needed Callbacks +** +** ^To avoid having to register all collation sequences before a database +** can be used, a single callback function may be registered with the +** [database connection] to be invoked whenever an undefined collation +** sequence is required. +** +** ^If the function is registered using the sqlite3_collation_needed() API, +** then it is passed the names of undefined collation sequences as strings +** encoded in UTF-8. ^If sqlite3_collation_needed16() is used, +** the names are passed as UTF-16 in machine native byte order. +** ^A call to either function replaces the existing collation-needed callback. +** +** ^(When the callback is invoked, the first argument passed is a copy +** of the second argument to sqlite3_collation_needed() or +** sqlite3_collation_needed16(). The second argument is the database +** connection. The third argument is one of [SQLITE_UTF8], [SQLITE_UTF16BE], +** or [SQLITE_UTF16LE], indicating the most desirable form of the collation +** sequence function required. The fourth parameter is the name of the +** required collation sequence.)^ +** +** The callback function should register the desired collation using +** [sqlite3_create_collation()], [sqlite3_create_collation16()], or +** [sqlite3_create_collation_v2()]. +*/ +SQLITE_API int sqlite3_collation_needed( + sqlite3*, + void*, + void(*)(void*,sqlite3*,int eTextRep,const char*) +); +SQLITE_API int sqlite3_collation_needed16( + sqlite3*, + void*, + void(*)(void*,sqlite3*,int eTextRep,const void*) +); + +#ifdef SQLITE_HAS_CODEC +/* +** Specify the key for an encrypted database. This routine should be +** called right after sqlite3_open(). +** +** The code to implement this API is not available in the public release +** of SQLite. +*/ +SQLITE_API int sqlite3_key( + sqlite3 *db, /* Database to be rekeyed */ + const void *pKey, int nKey /* The key */ +); + +/* +** Change the key on an open database. If the current database is not +** encrypted, this routine will encrypt it. If pNew==0 or nNew==0, the +** database is decrypted. +** +** The code to implement this API is not available in the public release +** of SQLite. +*/ +SQLITE_API int sqlite3_rekey( + sqlite3 *db, /* Database to be rekeyed */ + const void *pKey, int nKey /* The new key */ +); + +/* +** Specify the activation key for a SEE database. Unless +** activated, none of the SEE routines will work. +*/ +SQLITE_API void sqlite3_activate_see( + const char *zPassPhrase /* Activation phrase */ +); +#endif + +#ifdef SQLITE_ENABLE_CEROD +/* +** Specify the activation key for a CEROD database. Unless +** activated, none of the CEROD routines will work. +*/ +SQLITE_API void sqlite3_activate_cerod( + const char *zPassPhrase /* Activation phrase */ +); +#endif + +/* +** CAPI3REF: Suspend Execution For A Short Time +** +** The sqlite3_sleep() function causes the current thread to suspend execution +** for at least a number of milliseconds specified in its parameter. +** +** If the operating system does not support sleep requests with +** millisecond time resolution, then the time will be rounded up to +** the nearest second. The number of milliseconds of sleep actually +** requested from the operating system is returned. +** +** ^SQLite implements this interface by calling the xSleep() +** method of the default [sqlite3_vfs] object. If the xSleep() method +** of the default VFS is not implemented correctly, or not implemented at +** all, then the behavior of sqlite3_sleep() may deviate from the description +** in the previous paragraphs. +*/ +SQLITE_API int sqlite3_sleep(int); + +/* +** CAPI3REF: Name Of The Folder Holding Temporary Files +** +** ^(If this global variable is made to point to a string which is +** the name of a folder (a.k.a. directory), then all temporary files +** created by SQLite when using a built-in [sqlite3_vfs | VFS] +** will be placed in that directory.)^ ^If this variable +** is a NULL pointer, then SQLite performs a search for an appropriate +** temporary file directory. +** +** It is not safe to read or modify this variable in more than one +** thread at a time. It is not safe to read or modify this variable +** if a [database connection] is being used at the same time in a separate +** thread. +** It is intended that this variable be set once +** as part of process initialization and before any SQLite interface +** routines have been called and that this variable remain unchanged +** thereafter. +** +** ^The [temp_store_directory pragma] may modify this variable and cause +** it to point to memory obtained from [sqlite3_malloc]. ^Furthermore, +** the [temp_store_directory pragma] always assumes that any string +** that this variable points to is held in memory obtained from +** [sqlite3_malloc] and the pragma may attempt to free that memory +** using [sqlite3_free]. +** Hence, if this variable is modified directly, either it should be +** made NULL or made to point to memory obtained from [sqlite3_malloc] +** or else the use of the [temp_store_directory pragma] should be avoided. +*/ +SQLITE_API SQLITE_EXTERN char *sqlite3_temp_directory; + +/* +** CAPI3REF: Test For Auto-Commit Mode +** KEYWORDS: {autocommit mode} +** +** ^The sqlite3_get_autocommit() interface returns non-zero or +** zero if the given database connection is or is not in autocommit mode, +** respectively. ^Autocommit mode is on by default. +** ^Autocommit mode is disabled by a [BEGIN] statement. +** ^Autocommit mode is re-enabled by a [COMMIT] or [ROLLBACK]. +** +** If certain kinds of errors occur on a statement within a multi-statement +** transaction (errors including [SQLITE_FULL], [SQLITE_IOERR], +** [SQLITE_NOMEM], [SQLITE_BUSY], and [SQLITE_INTERRUPT]) then the +** transaction might be rolled back automatically. The only way to +** find out whether SQLite automatically rolled back the transaction after +** an error is to use this function. +** +** If another thread changes the autocommit status of the database +** connection while this routine is running, then the return value +** is undefined. +*/ +SQLITE_API int sqlite3_get_autocommit(sqlite3*); + +/* +** CAPI3REF: Find The Database Handle Of A Prepared Statement +** +** ^The sqlite3_db_handle interface returns the [database connection] handle +** to which a [prepared statement] belongs. ^The [database connection] +** returned by sqlite3_db_handle is the same [database connection] +** that was the first argument +** to the [sqlite3_prepare_v2()] call (or its variants) that was used to +** create the statement in the first place. +*/ +SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt*); + +/* +** CAPI3REF: Find the next prepared statement +** +** ^This interface returns a pointer to the next [prepared statement] after +** pStmt associated with the [database connection] pDb. ^If pStmt is NULL +** then this interface returns a pointer to the first prepared statement +** associated with the database connection pDb. ^If no prepared statement +** satisfies the conditions of this routine, it returns NULL. +** +** The [database connection] pointer D in a call to +** [sqlite3_next_stmt(D,S)] must refer to an open database +** connection and in particular must not be a NULL pointer. +*/ +SQLITE_API sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt); + +/* +** CAPI3REF: Commit And Rollback Notification Callbacks +** +** ^The sqlite3_commit_hook() interface registers a callback +** function to be invoked whenever a transaction is [COMMIT | committed]. +** ^Any callback set by a previous call to sqlite3_commit_hook() +** for the same database connection is overridden. +** ^The sqlite3_rollback_hook() interface registers a callback +** function to be invoked whenever a transaction is [ROLLBACK | rolled back]. +** ^Any callback set by a previous call to sqlite3_rollback_hook() +** for the same database connection is overridden. +** ^The pArg argument is passed through to the callback. +** ^If the callback on a commit hook function returns non-zero, +** then the commit is converted into a rollback. +** +** ^The sqlite3_commit_hook(D,C,P) and sqlite3_rollback_hook(D,C,P) functions +** return the P argument from the previous call of the same function +** on the same [database connection] D, or NULL for +** the first call for each function on D. +** +** The callback implementation must not do anything that will modify +** the database connection that invoked the callback. Any actions +** to modify the database connection must be deferred until after the +** completion of the [sqlite3_step()] call that triggered the commit +** or rollback hook in the first place. +** Note that [sqlite3_prepare_v2()] and [sqlite3_step()] both modify their +** database connections for the meaning of "modify" in this paragraph. +** +** ^Registering a NULL function disables the callback. +** +** ^When the commit hook callback routine returns zero, the [COMMIT] +** operation is allowed to continue normally. ^If the commit hook +** returns non-zero, then the [COMMIT] is converted into a [ROLLBACK]. +** ^The rollback hook is invoked on a rollback that results from a commit +** hook returning non-zero, just as it would be with any other rollback. +** +** ^For the purposes of this API, a transaction is said to have been +** rolled back if an explicit "ROLLBACK" statement is executed, or +** an error or constraint causes an implicit rollback to occur. +** ^The rollback callback is not invoked if a transaction is +** automatically rolled back because the database connection is closed. +** +** See also the [sqlite3_update_hook()] interface. +*/ +SQLITE_API void *sqlite3_commit_hook(sqlite3*, int(*)(void*), void*); +SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*); + +/* +** CAPI3REF: Data Change Notification Callbacks +** +** ^The sqlite3_update_hook() interface registers a callback function +** with the [database connection] identified by the first argument +** to be invoked whenever a row is updated, inserted or deleted. +** ^Any callback set by a previous call to this function +** for the same database connection is overridden. +** +** ^The second argument is a pointer to the function to invoke when a +** row is updated, inserted or deleted. +** ^The first argument to the callback is a copy of the third argument +** to sqlite3_update_hook(). +** ^The second callback argument is one of [SQLITE_INSERT], [SQLITE_DELETE], +** or [SQLITE_UPDATE], depending on the operation that caused the callback +** to be invoked. +** ^The third and fourth arguments to the callback contain pointers to the +** database and table name containing the affected row. +** ^The final callback parameter is the [rowid] of the row. +** ^In the case of an update, this is the [rowid] after the update takes place. +** +** ^(The update hook is not invoked when internal system tables are +** modified (i.e. sqlite_master and sqlite_sequence).)^ +** +** ^In the current implementation, the update hook +** is not invoked when duplication rows are deleted because of an +** [ON CONFLICT | ON CONFLICT REPLACE] clause. ^Nor is the update hook +** invoked when rows are deleted using the [truncate optimization]. +** The exceptions defined in this paragraph might change in a future +** release of SQLite. +** +** The update hook implementation must not do anything that will modify +** the database connection that invoked the update hook. Any actions +** to modify the database connection must be deferred until after the +** completion of the [sqlite3_step()] call that triggered the update hook. +** Note that [sqlite3_prepare_v2()] and [sqlite3_step()] both modify their +** database connections for the meaning of "modify" in this paragraph. +** +** ^The sqlite3_update_hook(D,C,P) function +** returns the P argument from the previous call +** on the same [database connection] D, or NULL for +** the first call on D. +** +** See also the [sqlite3_commit_hook()] and [sqlite3_rollback_hook()] +** interfaces. +*/ +SQLITE_API void *sqlite3_update_hook( + sqlite3*, + void(*)(void *,int ,char const *,char const *,sqlite3_int64), + void* +); + +/* +** CAPI3REF: Enable Or Disable Shared Pager Cache +** KEYWORDS: {shared cache} +** +** ^(This routine enables or disables the sharing of the database cache +** and schema data structures between [database connection | connections] +** to the same database. Sharing is enabled if the argument is true +** and disabled if the argument is false.)^ +** +** ^Cache sharing is enabled and disabled for an entire process. +** This is a change as of SQLite version 3.5.0. In prior versions of SQLite, +** sharing was enabled or disabled for each thread separately. +** +** ^(The cache sharing mode set by this interface effects all subsequent +** calls to [sqlite3_open()], [sqlite3_open_v2()], and [sqlite3_open16()]. +** Existing database connections continue use the sharing mode +** that was in effect at the time they were opened.)^ +** +** ^(This routine returns [SQLITE_OK] if shared cache was enabled or disabled +** successfully. An [error code] is returned otherwise.)^ +** +** ^Shared cache is disabled by default. But this might change in +** future releases of SQLite. Applications that care about shared +** cache setting should set it explicitly. +** +** See Also: [SQLite Shared-Cache Mode] +*/ +SQLITE_API int sqlite3_enable_shared_cache(int); + +/* +** CAPI3REF: Attempt To Free Heap Memory +** +** ^The sqlite3_release_memory() interface attempts to free N bytes +** of heap memory by deallocating non-essential memory allocations +** held by the database library. Memory used to cache database +** pages to improve performance is an example of non-essential memory. +** ^sqlite3_release_memory() returns the number of bytes actually freed, +** which might be more or less than the amount requested. +** ^The sqlite3_release_memory() routine is a no-op returning zero +** if SQLite is not compiled with [SQLITE_ENABLE_MEMORY_MANAGEMENT]. +*/ +SQLITE_API int sqlite3_release_memory(int); + +/* +** CAPI3REF: Impose A Limit On Heap Size +** +** ^The sqlite3_soft_heap_limit64() interface sets and/or queries the +** soft limit on the amount of heap memory that may be allocated by SQLite. +** ^SQLite strives to keep heap memory utilization below the soft heap +** limit by reducing the number of pages held in the page cache +** as heap memory usages approaches the limit. +** ^The soft heap limit is "soft" because even though SQLite strives to stay +** below the limit, it will exceed the limit rather than generate +** an [SQLITE_NOMEM] error. In other words, the soft heap limit +** is advisory only. +** +** ^The return value from sqlite3_soft_heap_limit64() is the size of +** the soft heap limit prior to the call. ^If the argument N is negative +** then no change is made to the soft heap limit. Hence, the current +** size of the soft heap limit can be determined by invoking +** sqlite3_soft_heap_limit64() with a negative argument. +** +** ^If the argument N is zero then the soft heap limit is disabled. +** +** ^(The soft heap limit is not enforced in the current implementation +** if one or more of following conditions are true: +** +**
    +**
  • The soft heap limit is set to zero. +**
  • Memory accounting is disabled using a combination of the +** [sqlite3_config]([SQLITE_CONFIG_MEMSTATUS],...) start-time option and +** the [SQLITE_DEFAULT_MEMSTATUS] compile-time option. +**
  • An alternative page cache implementation is specified using +** [sqlite3_config]([SQLITE_CONFIG_PCACHE],...). +**
  • The page cache allocates from its own memory pool supplied +** by [sqlite3_config]([SQLITE_CONFIG_PAGECACHE],...) rather than +** from the heap. +**
)^ +** +** Beginning with SQLite version 3.7.3, the soft heap limit is enforced +** regardless of whether or not the [SQLITE_ENABLE_MEMORY_MANAGEMENT] +** compile-time option is invoked. With [SQLITE_ENABLE_MEMORY_MANAGEMENT], +** the soft heap limit is enforced on every memory allocation. Without +** [SQLITE_ENABLE_MEMORY_MANAGEMENT], the soft heap limit is only enforced +** when memory is allocated by the page cache. Testing suggests that because +** the page cache is the predominate memory user in SQLite, most +** applications will achieve adequate soft heap limit enforcement without +** the use of [SQLITE_ENABLE_MEMORY_MANAGEMENT]. +** +** The circumstances under which SQLite will enforce the soft heap limit may +** changes in future releases of SQLite. +*/ +SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 N); + +/* +** CAPI3REF: Deprecated Soft Heap Limit Interface +** DEPRECATED +** +** This is a deprecated version of the [sqlite3_soft_heap_limit64()] +** interface. This routine is provided for historical compatibility +** only. All new applications should use the +** [sqlite3_soft_heap_limit64()] interface rather than this one. +*/ +SQLITE_API SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N); + + +/* +** CAPI3REF: Extract Metadata About A Column Of A Table +** +** ^This routine returns metadata about a specific column of a specific +** database table accessible using the [database connection] handle +** passed as the first function argument. +** +** ^The column is identified by the second, third and fourth parameters to +** this function. ^The second parameter is either the name of the database +** (i.e. "main", "temp", or an attached database) containing the specified +** table or NULL. ^If it is NULL, then all attached databases are searched +** for the table using the same algorithm used by the database engine to +** resolve unqualified table references. +** +** ^The third and fourth parameters to this function are the table and column +** name of the desired column, respectively. Neither of these parameters +** may be NULL. +** +** ^Metadata is returned by writing to the memory locations passed as the 5th +** and subsequent parameters to this function. ^Any of these arguments may be +** NULL, in which case the corresponding element of metadata is omitted. +** +** ^(
+** +**
Parameter Output
Type
Description +** +**
5th const char* Data type +**
6th const char* Name of default collation sequence +**
7th int True if column has a NOT NULL constraint +**
8th int True if column is part of the PRIMARY KEY +**
9th int True if column is [AUTOINCREMENT] +**
+**
)^ +** +** ^The memory pointed to by the character pointers returned for the +** declaration type and collation sequence is valid only until the next +** call to any SQLite API function. +** +** ^If the specified table is actually a view, an [error code] is returned. +** +** ^If the specified column is "rowid", "oid" or "_rowid_" and an +** [INTEGER PRIMARY KEY] column has been explicitly declared, then the output +** parameters are set for the explicitly declared column. ^(If there is no +** explicitly declared [INTEGER PRIMARY KEY] column, then the output +** parameters are set as follows: +** +**
+**     data type: "INTEGER"
+**     collation sequence: "BINARY"
+**     not null: 0
+**     primary key: 1
+**     auto increment: 0
+** 
)^ +** +** ^(This function may load one or more schemas from database files. If an +** error occurs during this process, or if the requested table or column +** cannot be found, an [error code] is returned and an error message left +** in the [database connection] (to be retrieved using sqlite3_errmsg()).)^ +** +** ^This API is only available if the library was compiled with the +** [SQLITE_ENABLE_COLUMN_METADATA] C-preprocessor symbol defined. +*/ +SQLITE_API int sqlite3_table_column_metadata( + sqlite3 *db, /* Connection handle */ + const char *zDbName, /* Database name or NULL */ + const char *zTableName, /* Table name */ + const char *zColumnName, /* Column name */ + char const **pzDataType, /* OUTPUT: Declared data type */ + char const **pzCollSeq, /* OUTPUT: Collation sequence name */ + int *pNotNull, /* OUTPUT: True if NOT NULL constraint exists */ + int *pPrimaryKey, /* OUTPUT: True if column part of PK */ + int *pAutoinc /* OUTPUT: True if column is auto-increment */ +); + +/* +** CAPI3REF: Load An Extension +** +** ^This interface loads an SQLite extension library from the named file. +** +** ^The sqlite3_load_extension() interface attempts to load an +** SQLite extension library contained in the file zFile. +** +** ^The entry point is zProc. +** ^zProc may be 0, in which case the name of the entry point +** defaults to "sqlite3_extension_init". +** ^The sqlite3_load_extension() interface returns +** [SQLITE_OK] on success and [SQLITE_ERROR] if something goes wrong. +** ^If an error occurs and pzErrMsg is not 0, then the +** [sqlite3_load_extension()] interface shall attempt to +** fill *pzErrMsg with error message text stored in memory +** obtained from [sqlite3_malloc()]. The calling function +** should free this memory by calling [sqlite3_free()]. +** +** ^Extension loading must be enabled using +** [sqlite3_enable_load_extension()] prior to calling this API, +** otherwise an error will be returned. +** +** See also the [load_extension() SQL function]. +*/ +SQLITE_API int sqlite3_load_extension( + sqlite3 *db, /* Load the extension into this database connection */ + const char *zFile, /* Name of the shared library containing extension */ + const char *zProc, /* Entry point. Derived from zFile if 0 */ + char **pzErrMsg /* Put error message here if not 0 */ +); + +/* +** CAPI3REF: Enable Or Disable Extension Loading +** +** ^So as not to open security holes in older applications that are +** unprepared to deal with extension loading, and as a means of disabling +** extension loading while evaluating user-entered SQL, the following API +** is provided to turn the [sqlite3_load_extension()] mechanism on and off. +** +** ^Extension loading is off by default. See ticket #1863. +** ^Call the sqlite3_enable_load_extension() routine with onoff==1 +** to turn extension loading on and call it with onoff==0 to turn +** it back off again. +*/ +SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff); + +/* +** CAPI3REF: Automatically Load Statically Linked Extensions +** +** ^This interface causes the xEntryPoint() function to be invoked for +** each new [database connection] that is created. The idea here is that +** xEntryPoint() is the entry point for a statically linked SQLite extension +** that is to be automatically loaded into all new database connections. +** +** ^(Even though the function prototype shows that xEntryPoint() takes +** no arguments and returns void, SQLite invokes xEntryPoint() with three +** arguments and expects and integer result as if the signature of the +** entry point where as follows: +** +**
+**    int xEntryPoint(
+**      sqlite3 *db,
+**      const char **pzErrMsg,
+**      const struct sqlite3_api_routines *pThunk
+**    );
+** 
)^ +** +** If the xEntryPoint routine encounters an error, it should make *pzErrMsg +** point to an appropriate error message (obtained from [sqlite3_mprintf()]) +** and return an appropriate [error code]. ^SQLite ensures that *pzErrMsg +** is NULL before calling the xEntryPoint(). ^SQLite will invoke +** [sqlite3_free()] on *pzErrMsg after xEntryPoint() returns. ^If any +** xEntryPoint() returns an error, the [sqlite3_open()], [sqlite3_open16()], +** or [sqlite3_open_v2()] call that provoked the xEntryPoint() will fail. +** +** ^Calling sqlite3_auto_extension(X) with an entry point X that is already +** on the list of automatic extensions is a harmless no-op. ^No entry point +** will be called more than once for each database connection that is opened. +** +** See also: [sqlite3_reset_auto_extension()]. +*/ +SQLITE_API int sqlite3_auto_extension(void (*xEntryPoint)(void)); + +/* +** CAPI3REF: Reset Automatic Extension Loading +** +** ^This interface disables all automatic extensions previously +** registered using [sqlite3_auto_extension()]. +*/ +SQLITE_API void sqlite3_reset_auto_extension(void); + +/* +** The interface to the virtual-table mechanism is currently considered +** to be experimental. The interface might change in incompatible ways. +** If this is a problem for you, do not use the interface at this time. +** +** When the virtual-table mechanism stabilizes, we will declare the +** interface fixed, support it indefinitely, and remove this comment. +*/ + +/* +** Structures used by the virtual table interface +*/ +typedef struct sqlite3_vtab sqlite3_vtab; +typedef struct sqlite3_index_info sqlite3_index_info; +typedef struct sqlite3_vtab_cursor sqlite3_vtab_cursor; +typedef struct sqlite3_module sqlite3_module; + +/* +** CAPI3REF: Virtual Table Object +** KEYWORDS: sqlite3_module {virtual table module} +** +** This structure, sometimes called a "virtual table module", +** defines the implementation of a [virtual tables]. +** This structure consists mostly of methods for the module. +** +** ^A virtual table module is created by filling in a persistent +** instance of this structure and passing a pointer to that instance +** to [sqlite3_create_module()] or [sqlite3_create_module_v2()]. +** ^The registration remains valid until it is replaced by a different +** module or until the [database connection] closes. The content +** of this structure must not change while it is registered with +** any database connection. +*/ +struct sqlite3_module { + int iVersion; + int (*xCreate)(sqlite3*, void *pAux, + int argc, const char *const*argv, + sqlite3_vtab **ppVTab, char**); + int (*xConnect)(sqlite3*, void *pAux, + int argc, const char *const*argv, + sqlite3_vtab **ppVTab, char**); + int (*xBestIndex)(sqlite3_vtab *pVTab, sqlite3_index_info*); + int (*xDisconnect)(sqlite3_vtab *pVTab); + int (*xDestroy)(sqlite3_vtab *pVTab); + int (*xOpen)(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor); + int (*xClose)(sqlite3_vtab_cursor*); + int (*xFilter)(sqlite3_vtab_cursor*, int idxNum, const char *idxStr, + int argc, sqlite3_value **argv); + int (*xNext)(sqlite3_vtab_cursor*); + int (*xEof)(sqlite3_vtab_cursor*); + int (*xColumn)(sqlite3_vtab_cursor*, sqlite3_context*, int); + int (*xRowid)(sqlite3_vtab_cursor*, sqlite3_int64 *pRowid); + int (*xUpdate)(sqlite3_vtab *, int, sqlite3_value **, sqlite3_int64 *); + int (*xBegin)(sqlite3_vtab *pVTab); + int (*xSync)(sqlite3_vtab *pVTab); + int (*xCommit)(sqlite3_vtab *pVTab); + int (*xRollback)(sqlite3_vtab *pVTab); + int (*xFindFunction)(sqlite3_vtab *pVtab, int nArg, const char *zName, + void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), + void **ppArg); + int (*xRename)(sqlite3_vtab *pVtab, const char *zNew); + /* The methods above are in version 1 of the sqlite_module object. Those + ** below are for version 2 and greater. */ + int (*xSavepoint)(sqlite3_vtab *pVTab, int); + int (*xRelease)(sqlite3_vtab *pVTab, int); + int (*xRollbackTo)(sqlite3_vtab *pVTab, int); +}; + +/* +** CAPI3REF: Virtual Table Indexing Information +** KEYWORDS: sqlite3_index_info +** +** The sqlite3_index_info structure and its substructures is used as part +** of the [virtual table] interface to +** pass information into and receive the reply from the [xBestIndex] +** method of a [virtual table module]. The fields under **Inputs** are the +** inputs to xBestIndex and are read-only. xBestIndex inserts its +** results into the **Outputs** fields. +** +** ^(The aConstraint[] array records WHERE clause constraints of the form: +** +**
column OP expr
+** +** where OP is =, <, <=, >, or >=.)^ ^(The particular operator is +** stored in aConstraint[].op using one of the +** [SQLITE_INDEX_CONSTRAINT_EQ | SQLITE_INDEX_CONSTRAINT_ values].)^ +** ^(The index of the column is stored in +** aConstraint[].iColumn.)^ ^(aConstraint[].usable is TRUE if the +** expr on the right-hand side can be evaluated (and thus the constraint +** is usable) and false if it cannot.)^ +** +** ^The optimizer automatically inverts terms of the form "expr OP column" +** and makes other simplifications to the WHERE clause in an attempt to +** get as many WHERE clause terms into the form shown above as possible. +** ^The aConstraint[] array only reports WHERE clause terms that are +** relevant to the particular virtual table being queried. +** +** ^Information about the ORDER BY clause is stored in aOrderBy[]. +** ^Each term of aOrderBy records a column of the ORDER BY clause. +** +** The [xBestIndex] method must fill aConstraintUsage[] with information +** about what parameters to pass to xFilter. ^If argvIndex>0 then +** the right-hand side of the corresponding aConstraint[] is evaluated +** and becomes the argvIndex-th entry in argv. ^(If aConstraintUsage[].omit +** is true, then the constraint is assumed to be fully handled by the +** virtual table and is not checked again by SQLite.)^ +** +** ^The idxNum and idxPtr values are recorded and passed into the +** [xFilter] method. +** ^[sqlite3_free()] is used to free idxPtr if and only if +** needToFreeIdxPtr is true. +** +** ^The orderByConsumed means that output from [xFilter]/[xNext] will occur in +** the correct order to satisfy the ORDER BY clause so that no separate +** sorting step is required. +** +** ^The estimatedCost value is an estimate of the cost of doing the +** particular lookup. A full scan of a table with N entries should have +** a cost of N. A binary search of a table of N entries should have a +** cost of approximately log(N). +*/ +struct sqlite3_index_info { + /* Inputs */ + int nConstraint; /* Number of entries in aConstraint */ + struct sqlite3_index_constraint { + int iColumn; /* Column on left-hand side of constraint */ + unsigned char op; /* Constraint operator */ + unsigned char usable; /* True if this constraint is usable */ + int iTermOffset; /* Used internally - xBestIndex should ignore */ + } *aConstraint; /* Table of WHERE clause constraints */ + int nOrderBy; /* Number of terms in the ORDER BY clause */ + struct sqlite3_index_orderby { + int iColumn; /* Column number */ + unsigned char desc; /* True for DESC. False for ASC. */ + } *aOrderBy; /* The ORDER BY clause */ + /* Outputs */ + struct sqlite3_index_constraint_usage { + int argvIndex; /* if >0, constraint is part of argv to xFilter */ + unsigned char omit; /* Do not code a test for this constraint */ + } *aConstraintUsage; + int idxNum; /* Number used to identify the index */ + char *idxStr; /* String, possibly obtained from sqlite3_malloc */ + int needToFreeIdxStr; /* Free idxStr using sqlite3_free() if true */ + int orderByConsumed; /* True if output is already ordered */ + double estimatedCost; /* Estimated cost of using this index */ +}; + +/* +** CAPI3REF: Virtual Table Constraint Operator Codes +** +** These macros defined the allowed values for the +** [sqlite3_index_info].aConstraint[].op field. Each value represents +** an operator that is part of a constraint term in the wHERE clause of +** a query that uses a [virtual table]. +*/ +#define SQLITE_INDEX_CONSTRAINT_EQ 2 +#define SQLITE_INDEX_CONSTRAINT_GT 4 +#define SQLITE_INDEX_CONSTRAINT_LE 8 +#define SQLITE_INDEX_CONSTRAINT_LT 16 +#define SQLITE_INDEX_CONSTRAINT_GE 32 +#define SQLITE_INDEX_CONSTRAINT_MATCH 64 + +/* +** CAPI3REF: Register A Virtual Table Implementation +** +** ^These routines are used to register a new [virtual table module] name. +** ^Module names must be registered before +** creating a new [virtual table] using the module and before using a +** preexisting [virtual table] for the module. +** +** ^The module name is registered on the [database connection] specified +** by the first parameter. ^The name of the module is given by the +** second parameter. ^The third parameter is a pointer to +** the implementation of the [virtual table module]. ^The fourth +** parameter is an arbitrary client data pointer that is passed through +** into the [xCreate] and [xConnect] methods of the virtual table module +** when a new virtual table is be being created or reinitialized. +** +** ^The sqlite3_create_module_v2() interface has a fifth parameter which +** is a pointer to a destructor for the pClientData. ^SQLite will +** invoke the destructor function (if it is not NULL) when SQLite +** no longer needs the pClientData pointer. ^The destructor will also +** be invoked if the call to sqlite3_create_module_v2() fails. +** ^The sqlite3_create_module() +** interface is equivalent to sqlite3_create_module_v2() with a NULL +** destructor. +*/ +SQLITE_API int sqlite3_create_module( + sqlite3 *db, /* SQLite connection to register module with */ + const char *zName, /* Name of the module */ + const sqlite3_module *p, /* Methods for the module */ + void *pClientData /* Client data for xCreate/xConnect */ +); +SQLITE_API int sqlite3_create_module_v2( + sqlite3 *db, /* SQLite connection to register module with */ + const char *zName, /* Name of the module */ + const sqlite3_module *p, /* Methods for the module */ + void *pClientData, /* Client data for xCreate/xConnect */ + void(*xDestroy)(void*) /* Module destructor function */ +); + +/* +** CAPI3REF: Virtual Table Instance Object +** KEYWORDS: sqlite3_vtab +** +** Every [virtual table module] implementation uses a subclass +** of this object to describe a particular instance +** of the [virtual table]. Each subclass will +** be tailored to the specific needs of the module implementation. +** The purpose of this superclass is to define certain fields that are +** common to all module implementations. +** +** ^Virtual tables methods can set an error message by assigning a +** string obtained from [sqlite3_mprintf()] to zErrMsg. The method should +** take care that any prior string is freed by a call to [sqlite3_free()] +** prior to assigning a new string to zErrMsg. ^After the error message +** is delivered up to the client application, the string will be automatically +** freed by sqlite3_free() and the zErrMsg field will be zeroed. +*/ +struct sqlite3_vtab { + const sqlite3_module *pModule; /* The module for this virtual table */ + int nRef; /* NO LONGER USED */ + char *zErrMsg; /* Error message from sqlite3_mprintf() */ + /* Virtual table implementations will typically add additional fields */ +}; + +/* +** CAPI3REF: Virtual Table Cursor Object +** KEYWORDS: sqlite3_vtab_cursor {virtual table cursor} +** +** Every [virtual table module] implementation uses a subclass of the +** following structure to describe cursors that point into the +** [virtual table] and are used +** to loop through the virtual table. Cursors are created using the +** [sqlite3_module.xOpen | xOpen] method of the module and are destroyed +** by the [sqlite3_module.xClose | xClose] method. Cursors are used +** by the [xFilter], [xNext], [xEof], [xColumn], and [xRowid] methods +** of the module. Each module implementation will define +** the content of a cursor structure to suit its own needs. +** +** This superclass exists in order to define fields of the cursor that +** are common to all implementations. +*/ +struct sqlite3_vtab_cursor { + sqlite3_vtab *pVtab; /* Virtual table of this cursor */ + /* Virtual table implementations will typically add additional fields */ +}; + +/* +** CAPI3REF: Declare The Schema Of A Virtual Table +** +** ^The [xCreate] and [xConnect] methods of a +** [virtual table module] call this interface +** to declare the format (the names and datatypes of the columns) of +** the virtual tables they implement. +*/ +SQLITE_API int sqlite3_declare_vtab(sqlite3*, const char *zSQL); + +/* +** CAPI3REF: Overload A Function For A Virtual Table +** +** ^(Virtual tables can provide alternative implementations of functions +** using the [xFindFunction] method of the [virtual table module]. +** But global versions of those functions +** must exist in order to be overloaded.)^ +** +** ^(This API makes sure a global version of a function with a particular +** name and number of parameters exists. If no such function exists +** before this API is called, a new function is created.)^ ^The implementation +** of the new function always causes an exception to be thrown. So +** the new function is not good for anything by itself. Its only +** purpose is to be a placeholder function that can be overloaded +** by a [virtual table]. +*/ +SQLITE_API int sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg); + +/* +** The interface to the virtual-table mechanism defined above (back up +** to a comment remarkably similar to this one) is currently considered +** to be experimental. The interface might change in incompatible ways. +** If this is a problem for you, do not use the interface at this time. +** +** When the virtual-table mechanism stabilizes, we will declare the +** interface fixed, support it indefinitely, and remove this comment. +*/ + +/* +** CAPI3REF: A Handle To An Open BLOB +** KEYWORDS: {BLOB handle} {BLOB handles} +** +** An instance of this object represents an open BLOB on which +** [sqlite3_blob_open | incremental BLOB I/O] can be performed. +** ^Objects of this type are created by [sqlite3_blob_open()] +** and destroyed by [sqlite3_blob_close()]. +** ^The [sqlite3_blob_read()] and [sqlite3_blob_write()] interfaces +** can be used to read or write small subsections of the BLOB. +** ^The [sqlite3_blob_bytes()] interface returns the size of the BLOB in bytes. +*/ +typedef struct sqlite3_blob sqlite3_blob; + +/* +** CAPI3REF: Open A BLOB For Incremental I/O +** +** ^(This interfaces opens a [BLOB handle | handle] to the BLOB located +** in row iRow, column zColumn, table zTable in database zDb; +** in other words, the same BLOB that would be selected by: +** +**
+**     SELECT zColumn FROM zDb.zTable WHERE [rowid] = iRow;
+** 
)^ +** +** ^If the flags parameter is non-zero, then the BLOB is opened for read +** and write access. ^If it is zero, the BLOB is opened for read access. +** ^It is not possible to open a column that is part of an index or primary +** key for writing. ^If [foreign key constraints] are enabled, it is +** not possible to open a column that is part of a [child key] for writing. +** +** ^Note that the database name is not the filename that contains +** the database but rather the symbolic name of the database that +** appears after the AS keyword when the database is connected using [ATTACH]. +** ^For the main database file, the database name is "main". +** ^For TEMP tables, the database name is "temp". +** +** ^(On success, [SQLITE_OK] is returned and the new [BLOB handle] is written +** to *ppBlob. Otherwise an [error code] is returned and *ppBlob is set +** to be a null pointer.)^ +** ^This function sets the [database connection] error code and message +** accessible via [sqlite3_errcode()] and [sqlite3_errmsg()] and related +** functions. ^Note that the *ppBlob variable is always initialized in a +** way that makes it safe to invoke [sqlite3_blob_close()] on *ppBlob +** regardless of the success or failure of this routine. +** +** ^(If the row that a BLOB handle points to is modified by an +** [UPDATE], [DELETE], or by [ON CONFLICT] side-effects +** then the BLOB handle is marked as "expired". +** This is true if any column of the row is changed, even a column +** other than the one the BLOB handle is open on.)^ +** ^Calls to [sqlite3_blob_read()] and [sqlite3_blob_write()] for +** an expired BLOB handle fail with a return code of [SQLITE_ABORT]. +** ^(Changes written into a BLOB prior to the BLOB expiring are not +** rolled back by the expiration of the BLOB. Such changes will eventually +** commit if the transaction continues to completion.)^ +** +** ^Use the [sqlite3_blob_bytes()] interface to determine the size of +** the opened blob. ^The size of a blob may not be changed by this +** interface. Use the [UPDATE] SQL command to change the size of a +** blob. +** +** ^The [sqlite3_bind_zeroblob()] and [sqlite3_result_zeroblob()] interfaces +** and the built-in [zeroblob] SQL function can be used, if desired, +** to create an empty, zero-filled blob in which to read or write using +** this interface. +** +** To avoid a resource leak, every open [BLOB handle] should eventually +** be released by a call to [sqlite3_blob_close()]. +*/ +SQLITE_API int sqlite3_blob_open( + sqlite3*, + const char *zDb, + const char *zTable, + const char *zColumn, + sqlite3_int64 iRow, + int flags, + sqlite3_blob **ppBlob +); + +/* +** CAPI3REF: Move a BLOB Handle to a New Row +** +** ^This function is used to move an existing blob handle so that it points +** to a different row of the same database table. ^The new row is identified +** by the rowid value passed as the second argument. Only the row can be +** changed. ^The database, table and column on which the blob handle is open +** remain the same. Moving an existing blob handle to a new row can be +** faster than closing the existing handle and opening a new one. +** +** ^(The new row must meet the same criteria as for [sqlite3_blob_open()] - +** it must exist and there must be either a blob or text value stored in +** the nominated column.)^ ^If the new row is not present in the table, or if +** it does not contain a blob or text value, or if another error occurs, an +** SQLite error code is returned and the blob handle is considered aborted. +** ^All subsequent calls to [sqlite3_blob_read()], [sqlite3_blob_write()] or +** [sqlite3_blob_reopen()] on an aborted blob handle immediately return +** SQLITE_ABORT. ^Calling [sqlite3_blob_bytes()] on an aborted blob handle +** always returns zero. +** +** ^This function sets the database handle error code and message. +*/ +SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64); + +/* +** CAPI3REF: Close A BLOB Handle +** +** ^Closes an open [BLOB handle]. +** +** ^Closing a BLOB shall cause the current transaction to commit +** if there are no other BLOBs, no pending prepared statements, and the +** database connection is in [autocommit mode]. +** ^If any writes were made to the BLOB, they might be held in cache +** until the close operation if they will fit. +** +** ^(Closing the BLOB often forces the changes +** out to disk and so if any I/O errors occur, they will likely occur +** at the time when the BLOB is closed. Any errors that occur during +** closing are reported as a non-zero return value.)^ +** +** ^(The BLOB is closed unconditionally. Even if this routine returns +** an error code, the BLOB is still closed.)^ +** +** ^Calling this routine with a null pointer (such as would be returned +** by a failed call to [sqlite3_blob_open()]) is a harmless no-op. +*/ +SQLITE_API int sqlite3_blob_close(sqlite3_blob *); + +/* +** CAPI3REF: Return The Size Of An Open BLOB +** +** ^Returns the size in bytes of the BLOB accessible via the +** successfully opened [BLOB handle] in its only argument. ^The +** incremental blob I/O routines can only read or overwriting existing +** blob content; they cannot change the size of a blob. +** +** This routine only works on a [BLOB handle] which has been created +** by a prior successful call to [sqlite3_blob_open()] and which has not +** been closed by [sqlite3_blob_close()]. Passing any other pointer in +** to this routine results in undefined and probably undesirable behavior. +*/ +SQLITE_API int sqlite3_blob_bytes(sqlite3_blob *); + +/* +** CAPI3REF: Read Data From A BLOB Incrementally +** +** ^(This function is used to read data from an open [BLOB handle] into a +** caller-supplied buffer. N bytes of data are copied into buffer Z +** from the open BLOB, starting at offset iOffset.)^ +** +** ^If offset iOffset is less than N bytes from the end of the BLOB, +** [SQLITE_ERROR] is returned and no data is read. ^If N or iOffset is +** less than zero, [SQLITE_ERROR] is returned and no data is read. +** ^The size of the blob (and hence the maximum value of N+iOffset) +** can be determined using the [sqlite3_blob_bytes()] interface. +** +** ^An attempt to read from an expired [BLOB handle] fails with an +** error code of [SQLITE_ABORT]. +** +** ^(On success, sqlite3_blob_read() returns SQLITE_OK. +** Otherwise, an [error code] or an [extended error code] is returned.)^ +** +** This routine only works on a [BLOB handle] which has been created +** by a prior successful call to [sqlite3_blob_open()] and which has not +** been closed by [sqlite3_blob_close()]. Passing any other pointer in +** to this routine results in undefined and probably undesirable behavior. +** +** See also: [sqlite3_blob_write()]. +*/ +SQLITE_API int sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset); + +/* +** CAPI3REF: Write Data Into A BLOB Incrementally +** +** ^This function is used to write data into an open [BLOB handle] from a +** caller-supplied buffer. ^N bytes of data are copied from the buffer Z +** into the open BLOB, starting at offset iOffset. +** +** ^If the [BLOB handle] passed as the first argument was not opened for +** writing (the flags parameter to [sqlite3_blob_open()] was zero), +** this function returns [SQLITE_READONLY]. +** +** ^This function may only modify the contents of the BLOB; it is +** not possible to increase the size of a BLOB using this API. +** ^If offset iOffset is less than N bytes from the end of the BLOB, +** [SQLITE_ERROR] is returned and no data is written. ^If N is +** less than zero [SQLITE_ERROR] is returned and no data is written. +** The size of the BLOB (and hence the maximum value of N+iOffset) +** can be determined using the [sqlite3_blob_bytes()] interface. +** +** ^An attempt to write to an expired [BLOB handle] fails with an +** error code of [SQLITE_ABORT]. ^Writes to the BLOB that occurred +** before the [BLOB handle] expired are not rolled back by the +** expiration of the handle, though of course those changes might +** have been overwritten by the statement that expired the BLOB handle +** or by other independent statements. +** +** ^(On success, sqlite3_blob_write() returns SQLITE_OK. +** Otherwise, an [error code] or an [extended error code] is returned.)^ +** +** This routine only works on a [BLOB handle] which has been created +** by a prior successful call to [sqlite3_blob_open()] and which has not +** been closed by [sqlite3_blob_close()]. Passing any other pointer in +** to this routine results in undefined and probably undesirable behavior. +** +** See also: [sqlite3_blob_read()]. +*/ +SQLITE_API int sqlite3_blob_write(sqlite3_blob *, const void *z, int n, int iOffset); + +/* +** CAPI3REF: Virtual File System Objects +** +** A virtual filesystem (VFS) is an [sqlite3_vfs] object +** that SQLite uses to interact +** with the underlying operating system. Most SQLite builds come with a +** single default VFS that is appropriate for the host computer. +** New VFSes can be registered and existing VFSes can be unregistered. +** The following interfaces are provided. +** +** ^The sqlite3_vfs_find() interface returns a pointer to a VFS given its name. +** ^Names are case sensitive. +** ^Names are zero-terminated UTF-8 strings. +** ^If there is no match, a NULL pointer is returned. +** ^If zVfsName is NULL then the default VFS is returned. +** +** ^New VFSes are registered with sqlite3_vfs_register(). +** ^Each new VFS becomes the default VFS if the makeDflt flag is set. +** ^The same VFS can be registered multiple times without injury. +** ^To make an existing VFS into the default VFS, register it again +** with the makeDflt flag set. If two different VFSes with the +** same name are registered, the behavior is undefined. If a +** VFS is registered with a name that is NULL or an empty string, +** then the behavior is undefined. +** +** ^Unregister a VFS with the sqlite3_vfs_unregister() interface. +** ^(If the default VFS is unregistered, another VFS is chosen as +** the default. The choice for the new VFS is arbitrary.)^ +*/ +SQLITE_API sqlite3_vfs *sqlite3_vfs_find(const char *zVfsName); +SQLITE_API int sqlite3_vfs_register(sqlite3_vfs*, int makeDflt); +SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*); + +/* +** CAPI3REF: Mutexes +** +** The SQLite core uses these routines for thread +** synchronization. Though they are intended for internal +** use by SQLite, code that links against SQLite is +** permitted to use any of these routines. +** +** The SQLite source code contains multiple implementations +** of these mutex routines. An appropriate implementation +** is selected automatically at compile-time. ^(The following +** implementations are available in the SQLite core: +** +**
    +**
  • SQLITE_MUTEX_OS2 +**
  • SQLITE_MUTEX_PTHREAD +**
  • SQLITE_MUTEX_W32 +**
  • SQLITE_MUTEX_NOOP +**
)^ +** +** ^The SQLITE_MUTEX_NOOP implementation is a set of routines +** that does no real locking and is appropriate for use in +** a single-threaded application. ^The SQLITE_MUTEX_OS2, +** SQLITE_MUTEX_PTHREAD, and SQLITE_MUTEX_W32 implementations +** are appropriate for use on OS/2, Unix, and Windows. +** +** ^(If SQLite is compiled with the SQLITE_MUTEX_APPDEF preprocessor +** macro defined (with "-DSQLITE_MUTEX_APPDEF=1"), then no mutex +** implementation is included with the library. In this case the +** application must supply a custom mutex implementation using the +** [SQLITE_CONFIG_MUTEX] option of the sqlite3_config() function +** before calling sqlite3_initialize() or any other public sqlite3_ +** function that calls sqlite3_initialize().)^ +** +** ^The sqlite3_mutex_alloc() routine allocates a new +** mutex and returns a pointer to it. ^If it returns NULL +** that means that a mutex could not be allocated. ^SQLite +** will unwind its stack and return an error. ^(The argument +** to sqlite3_mutex_alloc() is one of these integer constants: +** +**
    +**
  • SQLITE_MUTEX_FAST +**
  • SQLITE_MUTEX_RECURSIVE +**
  • SQLITE_MUTEX_STATIC_MASTER +**
  • SQLITE_MUTEX_STATIC_MEM +**
  • SQLITE_MUTEX_STATIC_MEM2 +**
  • SQLITE_MUTEX_STATIC_PRNG +**
  • SQLITE_MUTEX_STATIC_LRU +**
  • SQLITE_MUTEX_STATIC_LRU2 +**
)^ +** +** ^The first two constants (SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE) +** cause sqlite3_mutex_alloc() to create +** a new mutex. ^The new mutex is recursive when SQLITE_MUTEX_RECURSIVE +** is used but not necessarily so when SQLITE_MUTEX_FAST is used. +** The mutex implementation does not need to make a distinction +** between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does +** not want to. ^SQLite will only request a recursive mutex in +** cases where it really needs one. ^If a faster non-recursive mutex +** implementation is available on the host platform, the mutex subsystem +** might return such a mutex in response to SQLITE_MUTEX_FAST. +** +** ^The other allowed parameters to sqlite3_mutex_alloc() (anything other +** than SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE) each return +** a pointer to a static preexisting mutex. ^Six static mutexes are +** used by the current version of SQLite. Future versions of SQLite +** may add additional static mutexes. Static mutexes are for internal +** use by SQLite only. Applications that use SQLite mutexes should +** use only the dynamic mutexes returned by SQLITE_MUTEX_FAST or +** SQLITE_MUTEX_RECURSIVE. +** +** ^Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST +** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc() +** returns a different mutex on every call. ^But for the static +** mutex types, the same mutex is returned on every call that has +** the same type number. +** +** ^The sqlite3_mutex_free() routine deallocates a previously +** allocated dynamic mutex. ^SQLite is careful to deallocate every +** dynamic mutex that it allocates. The dynamic mutexes must not be in +** use when they are deallocated. Attempting to deallocate a static +** mutex results in undefined behavior. ^SQLite never deallocates +** a static mutex. +** +** ^The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt +** to enter a mutex. ^If another thread is already within the mutex, +** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return +** SQLITE_BUSY. ^The sqlite3_mutex_try() interface returns [SQLITE_OK] +** upon successful entry. ^(Mutexes created using +** SQLITE_MUTEX_RECURSIVE can be entered multiple times by the same thread. +** In such cases the, +** mutex must be exited an equal number of times before another thread +** can enter.)^ ^(If the same thread tries to enter any other +** kind of mutex more than once, the behavior is undefined. +** SQLite will never exhibit +** such behavior in its own use of mutexes.)^ +** +** ^(Some systems (for example, Windows 95) do not support the operation +** implemented by sqlite3_mutex_try(). On those systems, sqlite3_mutex_try() +** will always return SQLITE_BUSY. The SQLite core only ever uses +** sqlite3_mutex_try() as an optimization so this is acceptable behavior.)^ +** +** ^The sqlite3_mutex_leave() routine exits a mutex that was +** previously entered by the same thread. ^(The behavior +** is undefined if the mutex is not currently entered by the +** calling thread or is not currently allocated. SQLite will +** never do either.)^ +** +** ^If the argument to sqlite3_mutex_enter(), sqlite3_mutex_try(), or +** sqlite3_mutex_leave() is a NULL pointer, then all three routines +** behave as no-ops. +** +** See also: [sqlite3_mutex_held()] and [sqlite3_mutex_notheld()]. +*/ +SQLITE_API sqlite3_mutex *sqlite3_mutex_alloc(int); +SQLITE_API void sqlite3_mutex_free(sqlite3_mutex*); +SQLITE_API void sqlite3_mutex_enter(sqlite3_mutex*); +SQLITE_API int sqlite3_mutex_try(sqlite3_mutex*); +SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex*); + +/* +** CAPI3REF: Mutex Methods Object +** +** An instance of this structure defines the low-level routines +** used to allocate and use mutexes. +** +** Usually, the default mutex implementations provided by SQLite are +** sufficient, however the user has the option of substituting a custom +** implementation for specialized deployments or systems for which SQLite +** does not provide a suitable implementation. In this case, the user +** creates and populates an instance of this structure to pass +** to sqlite3_config() along with the [SQLITE_CONFIG_MUTEX] option. +** Additionally, an instance of this structure can be used as an +** output variable when querying the system for the current mutex +** implementation, using the [SQLITE_CONFIG_GETMUTEX] option. +** +** ^The xMutexInit method defined by this structure is invoked as +** part of system initialization by the sqlite3_initialize() function. +** ^The xMutexInit routine is called by SQLite exactly once for each +** effective call to [sqlite3_initialize()]. +** +** ^The xMutexEnd method defined by this structure is invoked as +** part of system shutdown by the sqlite3_shutdown() function. The +** implementation of this method is expected to release all outstanding +** resources obtained by the mutex methods implementation, especially +** those obtained by the xMutexInit method. ^The xMutexEnd() +** interface is invoked exactly once for each call to [sqlite3_shutdown()]. +** +** ^(The remaining seven methods defined by this structure (xMutexAlloc, +** xMutexFree, xMutexEnter, xMutexTry, xMutexLeave, xMutexHeld and +** xMutexNotheld) implement the following interfaces (respectively): +** +**
    +**
  • [sqlite3_mutex_alloc()]
  • +**
  • [sqlite3_mutex_free()]
  • +**
  • [sqlite3_mutex_enter()]
  • +**
  • [sqlite3_mutex_try()]
  • +**
  • [sqlite3_mutex_leave()]
  • +**
  • [sqlite3_mutex_held()]
  • +**
  • [sqlite3_mutex_notheld()]
  • +**
)^ +** +** The only difference is that the public sqlite3_XXX functions enumerated +** above silently ignore any invocations that pass a NULL pointer instead +** of a valid mutex handle. The implementations of the methods defined +** by this structure are not required to handle this case, the results +** of passing a NULL pointer instead of a valid mutex handle are undefined +** (i.e. it is acceptable to provide an implementation that segfaults if +** it is passed a NULL pointer). +** +** The xMutexInit() method must be threadsafe. ^It must be harmless to +** invoke xMutexInit() multiple times within the same process and without +** intervening calls to xMutexEnd(). Second and subsequent calls to +** xMutexInit() must be no-ops. +** +** ^xMutexInit() must not use SQLite memory allocation ([sqlite3_malloc()] +** and its associates). ^Similarly, xMutexAlloc() must not use SQLite memory +** allocation for a static mutex. ^However xMutexAlloc() may use SQLite +** memory allocation for a fast or recursive mutex. +** +** ^SQLite will invoke the xMutexEnd() method when [sqlite3_shutdown()] is +** called, but only if the prior call to xMutexInit returned SQLITE_OK. +** If xMutexInit fails in any way, it is expected to clean up after itself +** prior to returning. +*/ +typedef struct sqlite3_mutex_methods sqlite3_mutex_methods; +struct sqlite3_mutex_methods { + int (*xMutexInit)(void); + int (*xMutexEnd)(void); + sqlite3_mutex *(*xMutexAlloc)(int); + void (*xMutexFree)(sqlite3_mutex *); + void (*xMutexEnter)(sqlite3_mutex *); + int (*xMutexTry)(sqlite3_mutex *); + void (*xMutexLeave)(sqlite3_mutex *); + int (*xMutexHeld)(sqlite3_mutex *); + int (*xMutexNotheld)(sqlite3_mutex *); +}; + +/* +** CAPI3REF: Mutex Verification Routines +** +** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routines +** are intended for use inside assert() statements. ^The SQLite core +** never uses these routines except inside an assert() and applications +** are advised to follow the lead of the core. ^The SQLite core only +** provides implementations for these routines when it is compiled +** with the SQLITE_DEBUG flag. ^External mutex implementations +** are only required to provide these routines if SQLITE_DEBUG is +** defined and if NDEBUG is not defined. +** +** ^These routines should return true if the mutex in their argument +** is held or not held, respectively, by the calling thread. +** +** ^The implementation is not required to provided versions of these +** routines that actually work. If the implementation does not provide working +** versions of these routines, it should at least provide stubs that always +** return true so that one does not get spurious assertion failures. +** +** ^If the argument to sqlite3_mutex_held() is a NULL pointer then +** the routine should return 1. This seems counter-intuitive since +** clearly the mutex cannot be held if it does not exist. But +** the reason the mutex does not exist is because the build is not +** using mutexes. And we do not want the assert() containing the +** call to sqlite3_mutex_held() to fail, so a non-zero return is +** the appropriate thing to do. ^The sqlite3_mutex_notheld() +** interface should also return 1 when given a NULL pointer. +*/ +#ifndef NDEBUG +SQLITE_API int sqlite3_mutex_held(sqlite3_mutex*); +SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex*); +#endif + +/* +** CAPI3REF: Mutex Types +** +** The [sqlite3_mutex_alloc()] interface takes a single argument +** which is one of these integer constants. +** +** The set of static mutexes may change from one SQLite release to the +** next. Applications that override the built-in mutex logic must be +** prepared to accommodate additional static mutexes. +*/ +#define SQLITE_MUTEX_FAST 0 +#define SQLITE_MUTEX_RECURSIVE 1 +#define SQLITE_MUTEX_STATIC_MASTER 2 +#define SQLITE_MUTEX_STATIC_MEM 3 /* sqlite3_malloc() */ +#define SQLITE_MUTEX_STATIC_MEM2 4 /* NOT USED */ +#define SQLITE_MUTEX_STATIC_OPEN 4 /* sqlite3BtreeOpen() */ +#define SQLITE_MUTEX_STATIC_PRNG 5 /* sqlite3_random() */ +#define SQLITE_MUTEX_STATIC_LRU 6 /* lru page list */ +#define SQLITE_MUTEX_STATIC_LRU2 7 /* NOT USED */ +#define SQLITE_MUTEX_STATIC_PMEM 7 /* sqlite3PageMalloc() */ + +/* +** CAPI3REF: Retrieve the mutex for a database connection +** +** ^This interface returns a pointer the [sqlite3_mutex] object that +** serializes access to the [database connection] given in the argument +** when the [threading mode] is Serialized. +** ^If the [threading mode] is Single-thread or Multi-thread then this +** routine returns a NULL pointer. +*/ +SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3*); + +/* +** CAPI3REF: Low-Level Control Of Database Files +** +** ^The [sqlite3_file_control()] interface makes a direct call to the +** xFileControl method for the [sqlite3_io_methods] object associated +** with a particular database identified by the second argument. ^The +** name of the database is "main" for the main database or "temp" for the +** TEMP database, or the name that appears after the AS keyword for +** databases that are added using the [ATTACH] SQL command. +** ^A NULL pointer can be used in place of "main" to refer to the +** main database file. +** ^The third and fourth parameters to this routine +** are passed directly through to the second and third parameters of +** the xFileControl method. ^The return value of the xFileControl +** method becomes the return value of this routine. +** +** ^The SQLITE_FCNTL_FILE_POINTER value for the op parameter causes +** a pointer to the underlying [sqlite3_file] object to be written into +** the space pointed to by the 4th parameter. ^The SQLITE_FCNTL_FILE_POINTER +** case is a short-circuit path which does not actually invoke the +** underlying sqlite3_io_methods.xFileControl method. +** +** ^If the second parameter (zDbName) does not match the name of any +** open database file, then SQLITE_ERROR is returned. ^This error +** code is not remembered and will not be recalled by [sqlite3_errcode()] +** or [sqlite3_errmsg()]. The underlying xFileControl method might +** also return SQLITE_ERROR. There is no way to distinguish between +** an incorrect zDbName and an SQLITE_ERROR return from the underlying +** xFileControl method. +** +** See also: [SQLITE_FCNTL_LOCKSTATE] +*/ +SQLITE_API int sqlite3_file_control(sqlite3*, const char *zDbName, int op, void*); + +/* +** CAPI3REF: Testing Interface +** +** ^The sqlite3_test_control() interface is used to read out internal +** state of SQLite and to inject faults into SQLite for testing +** purposes. ^The first parameter is an operation code that determines +** the number, meaning, and operation of all subsequent parameters. +** +** This interface is not for use by applications. It exists solely +** for verifying the correct operation of the SQLite library. Depending +** on how the SQLite library is compiled, this interface might not exist. +** +** The details of the operation codes, their meanings, the parameters +** they take, and what they do are all subject to change without notice. +** Unlike most of the SQLite API, this function is not guaranteed to +** operate consistently from one release to the next. +*/ +SQLITE_API int sqlite3_test_control(int op, ...); + +/* +** CAPI3REF: Testing Interface Operation Codes +** +** These constants are the valid operation code parameters used +** as the first argument to [sqlite3_test_control()]. +** +** These parameters and their meanings are subject to change +** without notice. These values are for testing purposes only. +** Applications should not use any of these parameters or the +** [sqlite3_test_control()] interface. +*/ +#define SQLITE_TESTCTRL_FIRST 5 +#define SQLITE_TESTCTRL_PRNG_SAVE 5 +#define SQLITE_TESTCTRL_PRNG_RESTORE 6 +#define SQLITE_TESTCTRL_PRNG_RESET 7 +#define SQLITE_TESTCTRL_BITVEC_TEST 8 +#define SQLITE_TESTCTRL_FAULT_INSTALL 9 +#define SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS 10 +#define SQLITE_TESTCTRL_PENDING_BYTE 11 +#define SQLITE_TESTCTRL_ASSERT 12 +#define SQLITE_TESTCTRL_ALWAYS 13 +#define SQLITE_TESTCTRL_RESERVE 14 +#define SQLITE_TESTCTRL_OPTIMIZATIONS 15 +#define SQLITE_TESTCTRL_ISKEYWORD 16 +#define SQLITE_TESTCTRL_PGHDRSZ 17 +#define SQLITE_TESTCTRL_SCRATCHMALLOC 18 +#define SQLITE_TESTCTRL_LOCALTIME_FAULT 19 +#define SQLITE_TESTCTRL_LAST 19 + +/* +** CAPI3REF: SQLite Runtime Status +** +** ^This interface is used to retrieve runtime status information +** about the performance of SQLite, and optionally to reset various +** highwater marks. ^The first argument is an integer code for +** the specific parameter to measure. ^(Recognized integer codes +** are of the form [status parameters | SQLITE_STATUS_...].)^ +** ^The current value of the parameter is returned into *pCurrent. +** ^The highest recorded value is returned in *pHighwater. ^If the +** resetFlag is true, then the highest record value is reset after +** *pHighwater is written. ^(Some parameters do not record the highest +** value. For those parameters +** nothing is written into *pHighwater and the resetFlag is ignored.)^ +** ^(Other parameters record only the highwater mark and not the current +** value. For these latter parameters nothing is written into *pCurrent.)^ +** +** ^The sqlite3_status() routine returns SQLITE_OK on success and a +** non-zero [error code] on failure. +** +** This routine is threadsafe but is not atomic. This routine can be +** called while other threads are running the same or different SQLite +** interfaces. However the values returned in *pCurrent and +** *pHighwater reflect the status of SQLite at different points in time +** and it is possible that another thread might change the parameter +** in between the times when *pCurrent and *pHighwater are written. +** +** See also: [sqlite3_db_status()] +*/ +SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag); + + +/* +** CAPI3REF: Status Parameters +** KEYWORDS: {status parameters} +** +** These integer constants designate various run-time status parameters +** that can be returned by [sqlite3_status()]. +** +**
+** [[SQLITE_STATUS_MEMORY_USED]] ^(
SQLITE_STATUS_MEMORY_USED
+**
This parameter is the current amount of memory checked out +** using [sqlite3_malloc()], either directly or indirectly. The +** figure includes calls made to [sqlite3_malloc()] by the application +** and internal memory usage by the SQLite library. Scratch memory +** controlled by [SQLITE_CONFIG_SCRATCH] and auxiliary page-cache +** memory controlled by [SQLITE_CONFIG_PAGECACHE] is not included in +** this parameter. The amount returned is the sum of the allocation +** sizes as reported by the xSize method in [sqlite3_mem_methods].
)^ +** +** [[SQLITE_STATUS_MALLOC_SIZE]] ^(
SQLITE_STATUS_MALLOC_SIZE
+**
This parameter records the largest memory allocation request +** handed to [sqlite3_malloc()] or [sqlite3_realloc()] (or their +** internal equivalents). Only the value returned in the +** *pHighwater parameter to [sqlite3_status()] is of interest. +** The value written into the *pCurrent parameter is undefined.
)^ +** +** [[SQLITE_STATUS_MALLOC_COUNT]] ^(
SQLITE_STATUS_MALLOC_COUNT
+**
This parameter records the number of separate memory allocations +** currently checked out.
)^ +** +** [[SQLITE_STATUS_PAGECACHE_USED]] ^(
SQLITE_STATUS_PAGECACHE_USED
+**
This parameter returns the number of pages used out of the +** [pagecache memory allocator] that was configured using +** [SQLITE_CONFIG_PAGECACHE]. The +** value returned is in pages, not in bytes.
)^ +** +** [[SQLITE_STATUS_PAGECACHE_OVERFLOW]] +** ^(
SQLITE_STATUS_PAGECACHE_OVERFLOW
+**
This parameter returns the number of bytes of page cache +** allocation which could not be satisfied by the [SQLITE_CONFIG_PAGECACHE] +** buffer and where forced to overflow to [sqlite3_malloc()]. The +** returned value includes allocations that overflowed because they +** where too large (they were larger than the "sz" parameter to +** [SQLITE_CONFIG_PAGECACHE]) and allocations that overflowed because +** no space was left in the page cache.
)^ +** +** [[SQLITE_STATUS_PAGECACHE_SIZE]] ^(
SQLITE_STATUS_PAGECACHE_SIZE
+**
This parameter records the largest memory allocation request +** handed to [pagecache memory allocator]. Only the value returned in the +** *pHighwater parameter to [sqlite3_status()] is of interest. +** The value written into the *pCurrent parameter is undefined.
)^ +** +** [[SQLITE_STATUS_SCRATCH_USED]] ^(
SQLITE_STATUS_SCRATCH_USED
+**
This parameter returns the number of allocations used out of the +** [scratch memory allocator] configured using +** [SQLITE_CONFIG_SCRATCH]. The value returned is in allocations, not +** in bytes. Since a single thread may only have one scratch allocation +** outstanding at time, this parameter also reports the number of threads +** using scratch memory at the same time.
)^ +** +** [[SQLITE_STATUS_SCRATCH_OVERFLOW]] ^(
SQLITE_STATUS_SCRATCH_OVERFLOW
+**
This parameter returns the number of bytes of scratch memory +** allocation which could not be satisfied by the [SQLITE_CONFIG_SCRATCH] +** buffer and where forced to overflow to [sqlite3_malloc()]. The values +** returned include overflows because the requested allocation was too +** larger (that is, because the requested allocation was larger than the +** "sz" parameter to [SQLITE_CONFIG_SCRATCH]) and because no scratch buffer +** slots were available. +**
)^ +** +** [[SQLITE_STATUS_SCRATCH_SIZE]] ^(
SQLITE_STATUS_SCRATCH_SIZE
+**
This parameter records the largest memory allocation request +** handed to [scratch memory allocator]. Only the value returned in the +** *pHighwater parameter to [sqlite3_status()] is of interest. +** The value written into the *pCurrent parameter is undefined.
)^ +** +** [[SQLITE_STATUS_PARSER_STACK]] ^(
SQLITE_STATUS_PARSER_STACK
+**
This parameter records the deepest parser stack. It is only +** meaningful if SQLite is compiled with [YYTRACKMAXSTACKDEPTH].
)^ +**
+** +** New status parameters may be added from time to time. +*/ +#define SQLITE_STATUS_MEMORY_USED 0 +#define SQLITE_STATUS_PAGECACHE_USED 1 +#define SQLITE_STATUS_PAGECACHE_OVERFLOW 2 +#define SQLITE_STATUS_SCRATCH_USED 3 +#define SQLITE_STATUS_SCRATCH_OVERFLOW 4 +#define SQLITE_STATUS_MALLOC_SIZE 5 +#define SQLITE_STATUS_PARSER_STACK 6 +#define SQLITE_STATUS_PAGECACHE_SIZE 7 +#define SQLITE_STATUS_SCRATCH_SIZE 8 +#define SQLITE_STATUS_MALLOC_COUNT 9 + +/* +** CAPI3REF: Database Connection Status +** +** ^This interface is used to retrieve runtime status information +** about a single [database connection]. ^The first argument is the +** database connection object to be interrogated. ^The second argument +** is an integer constant, taken from the set of +** [SQLITE_DBSTATUS options], that +** determines the parameter to interrogate. The set of +** [SQLITE_DBSTATUS options] is likely +** to grow in future releases of SQLite. +** +** ^The current value of the requested parameter is written into *pCur +** and the highest instantaneous value is written into *pHiwtr. ^If +** the resetFlg is true, then the highest instantaneous value is +** reset back down to the current value. +** +** ^The sqlite3_db_status() routine returns SQLITE_OK on success and a +** non-zero [error code] on failure. +** +** See also: [sqlite3_status()] and [sqlite3_stmt_status()]. +*/ +SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg); + +/* +** CAPI3REF: Status Parameters for database connections +** KEYWORDS: {SQLITE_DBSTATUS options} +** +** These constants are the available integer "verbs" that can be passed as +** the second argument to the [sqlite3_db_status()] interface. +** +** New verbs may be added in future releases of SQLite. Existing verbs +** might be discontinued. Applications should check the return code from +** [sqlite3_db_status()] to make sure that the call worked. +** The [sqlite3_db_status()] interface will return a non-zero error code +** if a discontinued or unsupported verb is invoked. +** +**
+** [[SQLITE_DBSTATUS_LOOKASIDE_USED]] ^(
SQLITE_DBSTATUS_LOOKASIDE_USED
+**
This parameter returns the number of lookaside memory slots currently +** checked out.
)^ +** +** [[SQLITE_DBSTATUS_LOOKASIDE_HIT]] ^(
SQLITE_DBSTATUS_LOOKASIDE_HIT
+**
This parameter returns the number malloc attempts that were +** satisfied using lookaside memory. Only the high-water value is meaningful; +** the current value is always zero.)^ +** +** [[SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE]] +** ^(
SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE
+**
This parameter returns the number malloc attempts that might have +** been satisfied using lookaside memory but failed due to the amount of +** memory requested being larger than the lookaside slot size. +** Only the high-water value is meaningful; +** the current value is always zero.)^ +** +** [[SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL]] +** ^(
SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL
+**
This parameter returns the number malloc attempts that might have +** been satisfied using lookaside memory but failed due to all lookaside +** memory already being in use. +** Only the high-water value is meaningful; +** the current value is always zero.)^ +** +** [[SQLITE_DBSTATUS_CACHE_USED]] ^(
SQLITE_DBSTATUS_CACHE_USED
+**
This parameter returns the approximate number of of bytes of heap +** memory used by all pager caches associated with the database connection.)^ +** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0. +** +** [[SQLITE_DBSTATUS_SCHEMA_USED]] ^(
SQLITE_DBSTATUS_SCHEMA_USED
+**
This parameter returns the approximate number of of bytes of heap +** memory used to store the schema for all databases associated +** with the connection - main, temp, and any [ATTACH]-ed databases.)^ +** ^The full amount of memory used by the schemas is reported, even if the +** schema memory is shared with other database connections due to +** [shared cache mode] being enabled. +** ^The highwater mark associated with SQLITE_DBSTATUS_SCHEMA_USED is always 0. +** +** [[SQLITE_DBSTATUS_STMT_USED]] ^(
SQLITE_DBSTATUS_STMT_USED
+**
This parameter returns the approximate number of of bytes of heap +** and lookaside memory used by all prepared statements associated with +** the database connection.)^ +** ^The highwater mark associated with SQLITE_DBSTATUS_STMT_USED is always 0. +**
+**
+*/ +#define SQLITE_DBSTATUS_LOOKASIDE_USED 0 +#define SQLITE_DBSTATUS_CACHE_USED 1 +#define SQLITE_DBSTATUS_SCHEMA_USED 2 +#define SQLITE_DBSTATUS_STMT_USED 3 +#define SQLITE_DBSTATUS_LOOKASIDE_HIT 4 +#define SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE 5 +#define SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL 6 +#define SQLITE_DBSTATUS_MAX 6 /* Largest defined DBSTATUS */ + + +/* +** CAPI3REF: Prepared Statement Status +** +** ^(Each prepared statement maintains various +** [SQLITE_STMTSTATUS counters] that measure the number +** of times it has performed specific operations.)^ These counters can +** be used to monitor the performance characteristics of the prepared +** statements. For example, if the number of table steps greatly exceeds +** the number of table searches or result rows, that would tend to indicate +** that the prepared statement is using a full table scan rather than +** an index. +** +** ^(This interface is used to retrieve and reset counter values from +** a [prepared statement]. The first argument is the prepared statement +** object to be interrogated. The second argument +** is an integer code for a specific [SQLITE_STMTSTATUS counter] +** to be interrogated.)^ +** ^The current value of the requested counter is returned. +** ^If the resetFlg is true, then the counter is reset to zero after this +** interface call returns. +** +** See also: [sqlite3_status()] and [sqlite3_db_status()]. +*/ +SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg); + +/* +** CAPI3REF: Status Parameters for prepared statements +** KEYWORDS: {SQLITE_STMTSTATUS counter} {SQLITE_STMTSTATUS counters} +** +** These preprocessor macros define integer codes that name counter +** values associated with the [sqlite3_stmt_status()] interface. +** The meanings of the various counters are as follows: +** +**
+** [[SQLITE_STMTSTATUS_FULLSCAN_STEP]]
SQLITE_STMTSTATUS_FULLSCAN_STEP
+**
^This is the number of times that SQLite has stepped forward in +** a table as part of a full table scan. Large numbers for this counter +** may indicate opportunities for performance improvement through +** careful use of indices.
+** +** [[SQLITE_STMTSTATUS_SORT]]
SQLITE_STMTSTATUS_SORT
+**
^This is the number of sort operations that have occurred. +** A non-zero value in this counter may indicate an opportunity to +** improvement performance through careful use of indices.
+** +** [[SQLITE_STMTSTATUS_AUTOINDEX]]
SQLITE_STMTSTATUS_AUTOINDEX
+**
^This is the number of rows inserted into transient indices that +** were created automatically in order to help joins run faster. +** A non-zero value in this counter may indicate an opportunity to +** improvement performance by adding permanent indices that do not +** need to be reinitialized each time the statement is run.
+** +**
+*/ +#define SQLITE_STMTSTATUS_FULLSCAN_STEP 1 +#define SQLITE_STMTSTATUS_SORT 2 +#define SQLITE_STMTSTATUS_AUTOINDEX 3 + +/* +** CAPI3REF: Custom Page Cache Object +** +** The sqlite3_pcache type is opaque. It is implemented by +** the pluggable module. The SQLite core has no knowledge of +** its size or internal structure and never deals with the +** sqlite3_pcache object except by holding and passing pointers +** to the object. +** +** See [sqlite3_pcache_methods] for additional information. +*/ +typedef struct sqlite3_pcache sqlite3_pcache; + +/* +** CAPI3REF: Application Defined Page Cache. +** KEYWORDS: {page cache} +** +** ^(The [sqlite3_config]([SQLITE_CONFIG_PCACHE], ...) interface can +** register an alternative page cache implementation by passing in an +** instance of the sqlite3_pcache_methods structure.)^ +** In many applications, most of the heap memory allocated by +** SQLite is used for the page cache. +** By implementing a +** custom page cache using this API, an application can better control +** the amount of memory consumed by SQLite, the way in which +** that memory is allocated and released, and the policies used to +** determine exactly which parts of a database file are cached and for +** how long. +** +** The alternative page cache mechanism is an +** extreme measure that is only needed by the most demanding applications. +** The built-in page cache is recommended for most uses. +** +** ^(The contents of the sqlite3_pcache_methods structure are copied to an +** internal buffer by SQLite within the call to [sqlite3_config]. Hence +** the application may discard the parameter after the call to +** [sqlite3_config()] returns.)^ +** +** [[the xInit() page cache method]] +** ^(The xInit() method is called once for each effective +** call to [sqlite3_initialize()])^ +** (usually only once during the lifetime of the process). ^(The xInit() +** method is passed a copy of the sqlite3_pcache_methods.pArg value.)^ +** The intent of the xInit() method is to set up global data structures +** required by the custom page cache implementation. +** ^(If the xInit() method is NULL, then the +** built-in default page cache is used instead of the application defined +** page cache.)^ +** +** [[the xShutdown() page cache method]] +** ^The xShutdown() method is called by [sqlite3_shutdown()]. +** It can be used to clean up +** any outstanding resources before process shutdown, if required. +** ^The xShutdown() method may be NULL. +** +** ^SQLite automatically serializes calls to the xInit method, +** so the xInit method need not be threadsafe. ^The +** xShutdown method is only called from [sqlite3_shutdown()] so it does +** not need to be threadsafe either. All other methods must be threadsafe +** in multithreaded applications. +** +** ^SQLite will never invoke xInit() more than once without an intervening +** call to xShutdown(). +** +** [[the xCreate() page cache methods]] +** ^SQLite invokes the xCreate() method to construct a new cache instance. +** SQLite will typically create one cache instance for each open database file, +** though this is not guaranteed. ^The +** first parameter, szPage, is the size in bytes of the pages that must +** be allocated by the cache. ^szPage will not be a power of two. ^szPage +** will the page size of the database file that is to be cached plus an +** increment (here called "R") of less than 250. SQLite will use the +** extra R bytes on each page to store metadata about the underlying +** database page on disk. The value of R depends +** on the SQLite version, the target platform, and how SQLite was compiled. +** ^(R is constant for a particular build of SQLite. Except, there are two +** distinct values of R when SQLite is compiled with the proprietary +** ZIPVFS extension.)^ ^The second argument to +** xCreate(), bPurgeable, is true if the cache being created will +** be used to cache database pages of a file stored on disk, or +** false if it is used for an in-memory database. The cache implementation +** does not have to do anything special based with the value of bPurgeable; +** it is purely advisory. ^On a cache where bPurgeable is false, SQLite will +** never invoke xUnpin() except to deliberately delete a page. +** ^In other words, calls to xUnpin() on a cache with bPurgeable set to +** false will always have the "discard" flag set to true. +** ^Hence, a cache created with bPurgeable false will +** never contain any unpinned pages. +** +** [[the xCachesize() page cache method]] +** ^(The xCachesize() method may be called at any time by SQLite to set the +** suggested maximum cache-size (number of pages stored by) the cache +** instance passed as the first argument. This is the value configured using +** the SQLite "[PRAGMA cache_size]" command.)^ As with the bPurgeable +** parameter, the implementation is not required to do anything with this +** value; it is advisory only. +** +** [[the xPagecount() page cache methods]] +** The xPagecount() method must return the number of pages currently +** stored in the cache, both pinned and unpinned. +** +** [[the xFetch() page cache methods]] +** The xFetch() method locates a page in the cache and returns a pointer to +** the page, or a NULL pointer. +** A "page", in this context, means a buffer of szPage bytes aligned at an +** 8-byte boundary. The page to be fetched is determined by the key. ^The +** minimum key value is 1. After it has been retrieved using xFetch, the page +** is considered to be "pinned". +** +** If the requested page is already in the page cache, then the page cache +** implementation must return a pointer to the page buffer with its content +** intact. If the requested page is not already in the cache, then the +** cache implementation should use the value of the createFlag +** parameter to help it determined what action to take: +** +** +**
createFlag Behaviour when page is not already in cache +**
0 Do not allocate a new page. Return NULL. +**
1 Allocate a new page if it easy and convenient to do so. +** Otherwise return NULL. +**
2 Make every effort to allocate a new page. Only return +** NULL if allocating a new page is effectively impossible. +**
+** +** ^(SQLite will normally invoke xFetch() with a createFlag of 0 or 1. SQLite +** will only use a createFlag of 2 after a prior call with a createFlag of 1 +** failed.)^ In between the to xFetch() calls, SQLite may +** attempt to unpin one or more cache pages by spilling the content of +** pinned pages to disk and synching the operating system disk cache. +** +** [[the xUnpin() page cache method]] +** ^xUnpin() is called by SQLite with a pointer to a currently pinned page +** as its second argument. If the third parameter, discard, is non-zero, +** then the page must be evicted from the cache. +** ^If the discard parameter is +** zero, then the page may be discarded or retained at the discretion of +** page cache implementation. ^The page cache implementation +** may choose to evict unpinned pages at any time. +** +** The cache must not perform any reference counting. A single +** call to xUnpin() unpins the page regardless of the number of prior calls +** to xFetch(). +** +** [[the xRekey() page cache methods]] +** The xRekey() method is used to change the key value associated with the +** page passed as the second argument. If the cache +** previously contains an entry associated with newKey, it must be +** discarded. ^Any prior cache entry associated with newKey is guaranteed not +** to be pinned. +** +** When SQLite calls the xTruncate() method, the cache must discard all +** existing cache entries with page numbers (keys) greater than or equal +** to the value of the iLimit parameter passed to xTruncate(). If any +** of these pages are pinned, they are implicitly unpinned, meaning that +** they can be safely discarded. +** +** [[the xDestroy() page cache method]] +** ^The xDestroy() method is used to delete a cache allocated by xCreate(). +** All resources associated with the specified cache should be freed. ^After +** calling the xDestroy() method, SQLite considers the [sqlite3_pcache*] +** handle invalid, and will not use it with any other sqlite3_pcache_methods +** functions. +*/ +typedef struct sqlite3_pcache_methods sqlite3_pcache_methods; +struct sqlite3_pcache_methods { + void *pArg; + int (*xInit)(void*); + void (*xShutdown)(void*); + sqlite3_pcache *(*xCreate)(int szPage, int bPurgeable); + void (*xCachesize)(sqlite3_pcache*, int nCachesize); + int (*xPagecount)(sqlite3_pcache*); + void *(*xFetch)(sqlite3_pcache*, unsigned key, int createFlag); + void (*xUnpin)(sqlite3_pcache*, void*, int discard); + void (*xRekey)(sqlite3_pcache*, void*, unsigned oldKey, unsigned newKey); + void (*xTruncate)(sqlite3_pcache*, unsigned iLimit); + void (*xDestroy)(sqlite3_pcache*); +}; + +/* +** CAPI3REF: Online Backup Object +** +** The sqlite3_backup object records state information about an ongoing +** online backup operation. ^The sqlite3_backup object is created by +** a call to [sqlite3_backup_init()] and is destroyed by a call to +** [sqlite3_backup_finish()]. +** +** See Also: [Using the SQLite Online Backup API] +*/ +typedef struct sqlite3_backup sqlite3_backup; + +/* +** CAPI3REF: Online Backup API. +** +** The backup API copies the content of one database into another. +** It is useful either for creating backups of databases or +** for copying in-memory databases to or from persistent files. +** +** See Also: [Using the SQLite Online Backup API] +** +** ^SQLite holds a write transaction open on the destination database file +** for the duration of the backup operation. +** ^The source database is read-locked only while it is being read; +** it is not locked continuously for the entire backup operation. +** ^Thus, the backup may be performed on a live source database without +** preventing other database connections from +** reading or writing to the source database while the backup is underway. +** +** ^(To perform a backup operation: +**
    +**
  1. sqlite3_backup_init() is called once to initialize the +** backup, +**
  2. sqlite3_backup_step() is called one or more times to transfer +** the data between the two databases, and finally +**
  3. sqlite3_backup_finish() is called to release all resources +** associated with the backup operation. +**
)^ +** There should be exactly one call to sqlite3_backup_finish() for each +** successful call to sqlite3_backup_init(). +** +** [[sqlite3_backup_init()]] sqlite3_backup_init() +** +** ^The D and N arguments to sqlite3_backup_init(D,N,S,M) are the +** [database connection] associated with the destination database +** and the database name, respectively. +** ^The database name is "main" for the main database, "temp" for the +** temporary database, or the name specified after the AS keyword in +** an [ATTACH] statement for an attached database. +** ^The S and M arguments passed to +** sqlite3_backup_init(D,N,S,M) identify the [database connection] +** and database name of the source database, respectively. +** ^The source and destination [database connections] (parameters S and D) +** must be different or else sqlite3_backup_init(D,N,S,M) will fail with +** an error. +** +** ^If an error occurs within sqlite3_backup_init(D,N,S,M), then NULL is +** returned and an error code and error message are stored in the +** destination [database connection] D. +** ^The error code and message for the failed call to sqlite3_backup_init() +** can be retrieved using the [sqlite3_errcode()], [sqlite3_errmsg()], and/or +** [sqlite3_errmsg16()] functions. +** ^A successful call to sqlite3_backup_init() returns a pointer to an +** [sqlite3_backup] object. +** ^The [sqlite3_backup] object may be used with the sqlite3_backup_step() and +** sqlite3_backup_finish() functions to perform the specified backup +** operation. +** +** [[sqlite3_backup_step()]] sqlite3_backup_step() +** +** ^Function sqlite3_backup_step(B,N) will copy up to N pages between +** the source and destination databases specified by [sqlite3_backup] object B. +** ^If N is negative, all remaining source pages are copied. +** ^If sqlite3_backup_step(B,N) successfully copies N pages and there +** are still more pages to be copied, then the function returns [SQLITE_OK]. +** ^If sqlite3_backup_step(B,N) successfully finishes copying all pages +** from source to destination, then it returns [SQLITE_DONE]. +** ^If an error occurs while running sqlite3_backup_step(B,N), +** then an [error code] is returned. ^As well as [SQLITE_OK] and +** [SQLITE_DONE], a call to sqlite3_backup_step() may return [SQLITE_READONLY], +** [SQLITE_NOMEM], [SQLITE_BUSY], [SQLITE_LOCKED], or an +** [SQLITE_IOERR_ACCESS | SQLITE_IOERR_XXX] extended error code. +** +** ^(The sqlite3_backup_step() might return [SQLITE_READONLY] if +**
    +**
  1. the destination database was opened read-only, or +**
  2. the destination database is using write-ahead-log journaling +** and the destination and source page sizes differ, or +**
  3. the destination database is an in-memory database and the +** destination and source page sizes differ. +**
)^ +** +** ^If sqlite3_backup_step() cannot obtain a required file-system lock, then +** the [sqlite3_busy_handler | busy-handler function] +** is invoked (if one is specified). ^If the +** busy-handler returns non-zero before the lock is available, then +** [SQLITE_BUSY] is returned to the caller. ^In this case the call to +** sqlite3_backup_step() can be retried later. ^If the source +** [database connection] +** is being used to write to the source database when sqlite3_backup_step() +** is called, then [SQLITE_LOCKED] is returned immediately. ^Again, in this +** case the call to sqlite3_backup_step() can be retried later on. ^(If +** [SQLITE_IOERR_ACCESS | SQLITE_IOERR_XXX], [SQLITE_NOMEM], or +** [SQLITE_READONLY] is returned, then +** there is no point in retrying the call to sqlite3_backup_step(). These +** errors are considered fatal.)^ The application must accept +** that the backup operation has failed and pass the backup operation handle +** to the sqlite3_backup_finish() to release associated resources. +** +** ^The first call to sqlite3_backup_step() obtains an exclusive lock +** on the destination file. ^The exclusive lock is not released until either +** sqlite3_backup_finish() is called or the backup operation is complete +** and sqlite3_backup_step() returns [SQLITE_DONE]. ^Every call to +** sqlite3_backup_step() obtains a [shared lock] on the source database that +** lasts for the duration of the sqlite3_backup_step() call. +** ^Because the source database is not locked between calls to +** sqlite3_backup_step(), the source database may be modified mid-way +** through the backup process. ^If the source database is modified by an +** external process or via a database connection other than the one being +** used by the backup operation, then the backup will be automatically +** restarted by the next call to sqlite3_backup_step(). ^If the source +** database is modified by the using the same database connection as is used +** by the backup operation, then the backup database is automatically +** updated at the same time. +** +** [[sqlite3_backup_finish()]] sqlite3_backup_finish() +** +** When sqlite3_backup_step() has returned [SQLITE_DONE], or when the +** application wishes to abandon the backup operation, the application +** should destroy the [sqlite3_backup] by passing it to sqlite3_backup_finish(). +** ^The sqlite3_backup_finish() interfaces releases all +** resources associated with the [sqlite3_backup] object. +** ^If sqlite3_backup_step() has not yet returned [SQLITE_DONE], then any +** active write-transaction on the destination database is rolled back. +** The [sqlite3_backup] object is invalid +** and may not be used following a call to sqlite3_backup_finish(). +** +** ^The value returned by sqlite3_backup_finish is [SQLITE_OK] if no +** sqlite3_backup_step() errors occurred, regardless or whether or not +** sqlite3_backup_step() completed. +** ^If an out-of-memory condition or IO error occurred during any prior +** sqlite3_backup_step() call on the same [sqlite3_backup] object, then +** sqlite3_backup_finish() returns the corresponding [error code]. +** +** ^A return of [SQLITE_BUSY] or [SQLITE_LOCKED] from sqlite3_backup_step() +** is not a permanent error and does not affect the return value of +** sqlite3_backup_finish(). +** +** [[sqlite3_backup__remaining()]] [[sqlite3_backup_pagecount()]] +** sqlite3_backup_remaining() and sqlite3_backup_pagecount() +** +** ^Each call to sqlite3_backup_step() sets two values inside +** the [sqlite3_backup] object: the number of pages still to be backed +** up and the total number of pages in the source database file. +** The sqlite3_backup_remaining() and sqlite3_backup_pagecount() interfaces +** retrieve these two values, respectively. +** +** ^The values returned by these functions are only updated by +** sqlite3_backup_step(). ^If the source database is modified during a backup +** operation, then the values are not updated to account for any extra +** pages that need to be updated or the size of the source database file +** changing. +** +** Concurrent Usage of Database Handles +** +** ^The source [database connection] may be used by the application for other +** purposes while a backup operation is underway or being initialized. +** ^If SQLite is compiled and configured to support threadsafe database +** connections, then the source database connection may be used concurrently +** from within other threads. +** +** However, the application must guarantee that the destination +** [database connection] is not passed to any other API (by any thread) after +** sqlite3_backup_init() is called and before the corresponding call to +** sqlite3_backup_finish(). SQLite does not currently check to see +** if the application incorrectly accesses the destination [database connection] +** and so no error code is reported, but the operations may malfunction +** nevertheless. Use of the destination database connection while a +** backup is in progress might also also cause a mutex deadlock. +** +** If running in [shared cache mode], the application must +** guarantee that the shared cache used by the destination database +** is not accessed while the backup is running. In practice this means +** that the application must guarantee that the disk file being +** backed up to is not accessed by any connection within the process, +** not just the specific connection that was passed to sqlite3_backup_init(). +** +** The [sqlite3_backup] object itself is partially threadsafe. Multiple +** threads may safely make multiple concurrent calls to sqlite3_backup_step(). +** However, the sqlite3_backup_remaining() and sqlite3_backup_pagecount() +** APIs are not strictly speaking threadsafe. If they are invoked at the +** same time as another thread is invoking sqlite3_backup_step() it is +** possible that they return invalid values. +*/ +SQLITE_API sqlite3_backup *sqlite3_backup_init( + sqlite3 *pDest, /* Destination database handle */ + const char *zDestName, /* Destination database name */ + sqlite3 *pSource, /* Source database handle */ + const char *zSourceName /* Source database name */ +); +SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage); +SQLITE_API int sqlite3_backup_finish(sqlite3_backup *p); +SQLITE_API int sqlite3_backup_remaining(sqlite3_backup *p); +SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p); + +/* +** CAPI3REF: Unlock Notification +** +** ^When running in shared-cache mode, a database operation may fail with +** an [SQLITE_LOCKED] error if the required locks on the shared-cache or +** individual tables within the shared-cache cannot be obtained. See +** [SQLite Shared-Cache Mode] for a description of shared-cache locking. +** ^This API may be used to register a callback that SQLite will invoke +** when the connection currently holding the required lock relinquishes it. +** ^This API is only available if the library was compiled with the +** [SQLITE_ENABLE_UNLOCK_NOTIFY] C-preprocessor symbol defined. +** +** See Also: [Using the SQLite Unlock Notification Feature]. +** +** ^Shared-cache locks are released when a database connection concludes +** its current transaction, either by committing it or rolling it back. +** +** ^When a connection (known as the blocked connection) fails to obtain a +** shared-cache lock and SQLITE_LOCKED is returned to the caller, the +** identity of the database connection (the blocking connection) that +** has locked the required resource is stored internally. ^After an +** application receives an SQLITE_LOCKED error, it may call the +** sqlite3_unlock_notify() method with the blocked connection handle as +** the first argument to register for a callback that will be invoked +** when the blocking connections current transaction is concluded. ^The +** callback is invoked from within the [sqlite3_step] or [sqlite3_close] +** call that concludes the blocking connections transaction. +** +** ^(If sqlite3_unlock_notify() is called in a multi-threaded application, +** there is a chance that the blocking connection will have already +** concluded its transaction by the time sqlite3_unlock_notify() is invoked. +** If this happens, then the specified callback is invoked immediately, +** from within the call to sqlite3_unlock_notify().)^ +** +** ^If the blocked connection is attempting to obtain a write-lock on a +** shared-cache table, and more than one other connection currently holds +** a read-lock on the same table, then SQLite arbitrarily selects one of +** the other connections to use as the blocking connection. +** +** ^(There may be at most one unlock-notify callback registered by a +** blocked connection. If sqlite3_unlock_notify() is called when the +** blocked connection already has a registered unlock-notify callback, +** then the new callback replaces the old.)^ ^If sqlite3_unlock_notify() is +** called with a NULL pointer as its second argument, then any existing +** unlock-notify callback is canceled. ^The blocked connections +** unlock-notify callback may also be canceled by closing the blocked +** connection using [sqlite3_close()]. +** +** The unlock-notify callback is not reentrant. If an application invokes +** any sqlite3_xxx API functions from within an unlock-notify callback, a +** crash or deadlock may be the result. +** +** ^Unless deadlock is detected (see below), sqlite3_unlock_notify() always +** returns SQLITE_OK. +** +** Callback Invocation Details +** +** When an unlock-notify callback is registered, the application provides a +** single void* pointer that is passed to the callback when it is invoked. +** However, the signature of the callback function allows SQLite to pass +** it an array of void* context pointers. The first argument passed to +** an unlock-notify callback is a pointer to an array of void* pointers, +** and the second is the number of entries in the array. +** +** When a blocking connections transaction is concluded, there may be +** more than one blocked connection that has registered for an unlock-notify +** callback. ^If two or more such blocked connections have specified the +** same callback function, then instead of invoking the callback function +** multiple times, it is invoked once with the set of void* context pointers +** specified by the blocked connections bundled together into an array. +** This gives the application an opportunity to prioritize any actions +** related to the set of unblocked database connections. +** +** Deadlock Detection +** +** Assuming that after registering for an unlock-notify callback a +** database waits for the callback to be issued before taking any further +** action (a reasonable assumption), then using this API may cause the +** application to deadlock. For example, if connection X is waiting for +** connection Y's transaction to be concluded, and similarly connection +** Y is waiting on connection X's transaction, then neither connection +** will proceed and the system may remain deadlocked indefinitely. +** +** To avoid this scenario, the sqlite3_unlock_notify() performs deadlock +** detection. ^If a given call to sqlite3_unlock_notify() would put the +** system in a deadlocked state, then SQLITE_LOCKED is returned and no +** unlock-notify callback is registered. The system is said to be in +** a deadlocked state if connection A has registered for an unlock-notify +** callback on the conclusion of connection B's transaction, and connection +** B has itself registered for an unlock-notify callback when connection +** A's transaction is concluded. ^Indirect deadlock is also detected, so +** the system is also considered to be deadlocked if connection B has +** registered for an unlock-notify callback on the conclusion of connection +** C's transaction, where connection C is waiting on connection A. ^Any +** number of levels of indirection are allowed. +** +** The "DROP TABLE" Exception +** +** When a call to [sqlite3_step()] returns SQLITE_LOCKED, it is almost +** always appropriate to call sqlite3_unlock_notify(). There is however, +** one exception. When executing a "DROP TABLE" or "DROP INDEX" statement, +** SQLite checks if there are any currently executing SELECT statements +** that belong to the same connection. If there are, SQLITE_LOCKED is +** returned. In this case there is no "blocking connection", so invoking +** sqlite3_unlock_notify() results in the unlock-notify callback being +** invoked immediately. If the application then re-attempts the "DROP TABLE" +** or "DROP INDEX" query, an infinite loop might be the result. +** +** One way around this problem is to check the extended error code returned +** by an sqlite3_step() call. ^(If there is a blocking connection, then the +** extended error code is set to SQLITE_LOCKED_SHAREDCACHE. Otherwise, in +** the special "DROP TABLE/INDEX" case, the extended error code is just +** SQLITE_LOCKED.)^ +*/ +SQLITE_API int sqlite3_unlock_notify( + sqlite3 *pBlocked, /* Waiting connection */ + void (*xNotify)(void **apArg, int nArg), /* Callback function to invoke */ + void *pNotifyArg /* Argument to pass to xNotify */ +); + + +/* +** CAPI3REF: String Comparison +** +** ^The [sqlite3_strnicmp()] API allows applications and extensions to +** compare the contents of two buffers containing UTF-8 strings in a +** case-independent fashion, using the same definition of case independence +** that SQLite uses internally when comparing identifiers. +*/ +SQLITE_API int sqlite3_strnicmp(const char *, const char *, int); + +/* +** CAPI3REF: Error Logging Interface +** +** ^The [sqlite3_log()] interface writes a message into the error log +** established by the [SQLITE_CONFIG_LOG] option to [sqlite3_config()]. +** ^If logging is enabled, the zFormat string and subsequent arguments are +** used with [sqlite3_snprintf()] to generate the final output string. +** +** The sqlite3_log() interface is intended for use by extensions such as +** virtual tables, collating functions, and SQL functions. While there is +** nothing to prevent an application from calling sqlite3_log(), doing so +** is considered bad form. +** +** The zFormat string must not be NULL. +** +** To avoid deadlocks and other threading problems, the sqlite3_log() routine +** will not use dynamically allocated memory. The log message is stored in +** a fixed-length buffer on the stack. If the log message is longer than +** a few hundred characters, it will be truncated to the length of the +** buffer. +*/ +SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...); + +/* +** CAPI3REF: Write-Ahead Log Commit Hook +** +** ^The [sqlite3_wal_hook()] function is used to register a callback that +** will be invoked each time a database connection commits data to a +** [write-ahead log] (i.e. whenever a transaction is committed in +** [journal_mode | journal_mode=WAL mode]). +** +** ^The callback is invoked by SQLite after the commit has taken place and +** the associated write-lock on the database released, so the implementation +** may read, write or [checkpoint] the database as required. +** +** ^The first parameter passed to the callback function when it is invoked +** is a copy of the third parameter passed to sqlite3_wal_hook() when +** registering the callback. ^The second is a copy of the database handle. +** ^The third parameter is the name of the database that was written to - +** either "main" or the name of an [ATTACH]-ed database. ^The fourth parameter +** is the number of pages currently in the write-ahead log file, +** including those that were just committed. +** +** The callback function should normally return [SQLITE_OK]. ^If an error +** code is returned, that error will propagate back up through the +** SQLite code base to cause the statement that provoked the callback +** to report an error, though the commit will have still occurred. If the +** callback returns [SQLITE_ROW] or [SQLITE_DONE], or if it returns a value +** that does not correspond to any valid SQLite error code, the results +** are undefined. +** +** A single database handle may have at most a single write-ahead log callback +** registered at one time. ^Calling [sqlite3_wal_hook()] replaces any +** previously registered write-ahead log callback. ^Note that the +** [sqlite3_wal_autocheckpoint()] interface and the +** [wal_autocheckpoint pragma] both invoke [sqlite3_wal_hook()] and will +** those overwrite any prior [sqlite3_wal_hook()] settings. +*/ +SQLITE_API void *sqlite3_wal_hook( + sqlite3*, + int(*)(void *,sqlite3*,const char*,int), + void* +); + +/* +** CAPI3REF: Configure an auto-checkpoint +** +** ^The [sqlite3_wal_autocheckpoint(D,N)] is a wrapper around +** [sqlite3_wal_hook()] that causes any database on [database connection] D +** to automatically [checkpoint] +** after committing a transaction if there are N or +** more frames in the [write-ahead log] file. ^Passing zero or +** a negative value as the nFrame parameter disables automatic +** checkpoints entirely. +** +** ^The callback registered by this function replaces any existing callback +** registered using [sqlite3_wal_hook()]. ^Likewise, registering a callback +** using [sqlite3_wal_hook()] disables the automatic checkpoint mechanism +** configured by this function. +** +** ^The [wal_autocheckpoint pragma] can be used to invoke this interface +** from SQL. +** +** ^Every new [database connection] defaults to having the auto-checkpoint +** enabled with a threshold of 1000 or [SQLITE_DEFAULT_WAL_AUTOCHECKPOINT] +** pages. The use of this interface +** is only necessary if the default setting is found to be suboptimal +** for a particular application. +*/ +SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int N); + +/* +** CAPI3REF: Checkpoint a database +** +** ^The [sqlite3_wal_checkpoint(D,X)] interface causes database named X +** on [database connection] D to be [checkpointed]. ^If X is NULL or an +** empty string, then a checkpoint is run on all databases of +** connection D. ^If the database connection D is not in +** [WAL | write-ahead log mode] then this interface is a harmless no-op. +** +** ^The [wal_checkpoint pragma] can be used to invoke this interface +** from SQL. ^The [sqlite3_wal_autocheckpoint()] interface and the +** [wal_autocheckpoint pragma] can be used to cause this interface to be +** run whenever the WAL reaches a certain size threshold. +** +** See also: [sqlite3_wal_checkpoint_v2()] +*/ +SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb); + +/* +** CAPI3REF: Checkpoint a database +** +** Run a checkpoint operation on WAL database zDb attached to database +** handle db. The specific operation is determined by the value of the +** eMode parameter: +** +**
+**
SQLITE_CHECKPOINT_PASSIVE
+** Checkpoint as many frames as possible without waiting for any database +** readers or writers to finish. Sync the db file if all frames in the log +** are checkpointed. This mode is the same as calling +** sqlite3_wal_checkpoint(). The busy-handler callback is never invoked. +** +**
SQLITE_CHECKPOINT_FULL
+** This mode blocks (calls the busy-handler callback) until there is no +** database writer and all readers are reading from the most recent database +** snapshot. It then checkpoints all frames in the log file and syncs the +** database file. This call blocks database writers while it is running, +** but not database readers. +** +**
SQLITE_CHECKPOINT_RESTART
+** This mode works the same way as SQLITE_CHECKPOINT_FULL, except after +** checkpointing the log file it blocks (calls the busy-handler callback) +** until all readers are reading from the database file only. This ensures +** that the next client to write to the database file restarts the log file +** from the beginning. This call blocks database writers while it is running, +** but not database readers. +**
+** +** If pnLog is not NULL, then *pnLog is set to the total number of frames in +** the log file before returning. If pnCkpt is not NULL, then *pnCkpt is set to +** the total number of checkpointed frames (including any that were already +** checkpointed when this function is called). *pnLog and *pnCkpt may be +** populated even if sqlite3_wal_checkpoint_v2() returns other than SQLITE_OK. +** If no values are available because of an error, they are both set to -1 +** before returning to communicate this to the caller. +** +** All calls obtain an exclusive "checkpoint" lock on the database file. If +** any other process is running a checkpoint operation at the same time, the +** lock cannot be obtained and SQLITE_BUSY is returned. Even if there is a +** busy-handler configured, it will not be invoked in this case. +** +** The SQLITE_CHECKPOINT_FULL and RESTART modes also obtain the exclusive +** "writer" lock on the database file. If the writer lock cannot be obtained +** immediately, and a busy-handler is configured, it is invoked and the writer +** lock retried until either the busy-handler returns 0 or the lock is +** successfully obtained. The busy-handler is also invoked while waiting for +** database readers as described above. If the busy-handler returns 0 before +** the writer lock is obtained or while waiting for database readers, the +** checkpoint operation proceeds from that point in the same way as +** SQLITE_CHECKPOINT_PASSIVE - checkpointing as many frames as possible +** without blocking any further. SQLITE_BUSY is returned in this case. +** +** If parameter zDb is NULL or points to a zero length string, then the +** specified operation is attempted on all WAL databases. In this case the +** values written to output parameters *pnLog and *pnCkpt are undefined. If +** an SQLITE_BUSY error is encountered when processing one or more of the +** attached WAL databases, the operation is still attempted on any remaining +** attached databases and SQLITE_BUSY is returned to the caller. If any other +** error occurs while processing an attached database, processing is abandoned +** and the error code returned to the caller immediately. If no error +** (SQLITE_BUSY or otherwise) is encountered while processing the attached +** databases, SQLITE_OK is returned. +** +** If database zDb is the name of an attached database that is not in WAL +** mode, SQLITE_OK is returned and both *pnLog and *pnCkpt set to -1. If +** zDb is not NULL (or a zero length string) and is not the name of any +** attached database, SQLITE_ERROR is returned to the caller. +*/ +SQLITE_API int sqlite3_wal_checkpoint_v2( + sqlite3 *db, /* Database handle */ + const char *zDb, /* Name of attached database (or NULL) */ + int eMode, /* SQLITE_CHECKPOINT_* value */ + int *pnLog, /* OUT: Size of WAL log in frames */ + int *pnCkpt /* OUT: Total number of frames checkpointed */ +); + +/* +** CAPI3REF: Checkpoint operation parameters +** +** These constants can be used as the 3rd parameter to +** [sqlite3_wal_checkpoint_v2()]. See the [sqlite3_wal_checkpoint_v2()] +** documentation for additional information about the meaning and use of +** each of these values. +*/ +#define SQLITE_CHECKPOINT_PASSIVE 0 +#define SQLITE_CHECKPOINT_FULL 1 +#define SQLITE_CHECKPOINT_RESTART 2 + +/* +** CAPI3REF: Virtual Table Interface Configuration +** +** This function may be called by either the [xConnect] or [xCreate] method +** of a [virtual table] implementation to configure +** various facets of the virtual table interface. +** +** If this interface is invoked outside the context of an xConnect or +** xCreate virtual table method then the behavior is undefined. +** +** At present, there is only one option that may be configured using +** this function. (See [SQLITE_VTAB_CONSTRAINT_SUPPORT].) Further options +** may be added in the future. +*/ +SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...); + +/* +** CAPI3REF: Virtual Table Configuration Options +** +** These macros define the various options to the +** [sqlite3_vtab_config()] interface that [virtual table] implementations +** can use to customize and optimize their behavior. +** +**
+**
SQLITE_VTAB_CONSTRAINT_SUPPORT +**
Calls of the form +** [sqlite3_vtab_config](db,SQLITE_VTAB_CONSTRAINT_SUPPORT,X) are supported, +** where X is an integer. If X is zero, then the [virtual table] whose +** [xCreate] or [xConnect] method invoked [sqlite3_vtab_config()] does not +** support constraints. In this configuration (which is the default) if +** a call to the [xUpdate] method returns [SQLITE_CONSTRAINT], then the entire +** statement is rolled back as if [ON CONFLICT | OR ABORT] had been +** specified as part of the users SQL statement, regardless of the actual +** ON CONFLICT mode specified. +** +** If X is non-zero, then the virtual table implementation guarantees +** that if [xUpdate] returns [SQLITE_CONSTRAINT], it will do so before +** any modifications to internal or persistent data structures have been made. +** If the [ON CONFLICT] mode is ABORT, FAIL, IGNORE or ROLLBACK, SQLite +** is able to roll back a statement or database transaction, and abandon +** or continue processing the current SQL statement as appropriate. +** If the ON CONFLICT mode is REPLACE and the [xUpdate] method returns +** [SQLITE_CONSTRAINT], SQLite handles this as if the ON CONFLICT mode +** had been ABORT. +** +** Virtual table implementations that are required to handle OR REPLACE +** must do so within the [xUpdate] method. If a call to the +** [sqlite3_vtab_on_conflict()] function indicates that the current ON +** CONFLICT policy is REPLACE, the virtual table implementation should +** silently replace the appropriate rows within the xUpdate callback and +** return SQLITE_OK. Or, if this is not possible, it may return +** SQLITE_CONSTRAINT, in which case SQLite falls back to OR ABORT +** constraint handling. +**
+*/ +#define SQLITE_VTAB_CONSTRAINT_SUPPORT 1 + +/* +** CAPI3REF: Determine The Virtual Table Conflict Policy +** +** This function may only be called from within a call to the [xUpdate] method +** of a [virtual table] implementation for an INSERT or UPDATE operation. ^The +** value returned is one of [SQLITE_ROLLBACK], [SQLITE_IGNORE], [SQLITE_FAIL], +** [SQLITE_ABORT], or [SQLITE_REPLACE], according to the [ON CONFLICT] mode +** of the SQL statement that triggered the call to the [xUpdate] method of the +** [virtual table]. +*/ +SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *); + +/* +** CAPI3REF: Conflict resolution modes +** +** These constants are returned by [sqlite3_vtab_on_conflict()] to +** inform a [virtual table] implementation what the [ON CONFLICT] mode +** is for the SQL statement being evaluated. +** +** Note that the [SQLITE_IGNORE] constant is also used as a potential +** return value from the [sqlite3_set_authorizer()] callback and that +** [SQLITE_ABORT] is also a [result code]. +*/ +#define SQLITE_ROLLBACK 1 +/* #define SQLITE_IGNORE 2 // Also used by sqlite3_authorizer() callback */ +#define SQLITE_FAIL 3 +/* #define SQLITE_ABORT 4 // Also an error code */ +#define SQLITE_REPLACE 5 + + + +/* +** Undo the hack that converts floating point types to integer for +** builds on processors without floating point support. +*/ +#ifdef SQLITE_OMIT_FLOATING_POINT +# undef double +#endif + +#ifdef __cplusplus +} /* End of the 'extern "C"' block */ +#endif +#endif + +/* +** 2010 August 30 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +*/ + +#ifndef _SQLITE3RTREE_H_ +#define _SQLITE3RTREE_H_ + + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct sqlite3_rtree_geometry sqlite3_rtree_geometry; + +/* +** Register a geometry callback named zGeom that can be used as part of an +** R-Tree geometry query as follows: +** +** SELECT ... FROM WHERE MATCH $zGeom(... params ...) +*/ +SQLITE_API int sqlite3_rtree_geometry_callback( + sqlite3 *db, + const char *zGeom, + int (*xGeom)(sqlite3_rtree_geometry *, int nCoord, double *aCoord, int *pRes), + void *pContext +); + + +/* +** A pointer to a structure of the following type is passed as the first +** argument to callbacks registered using rtree_geometry_callback(). +*/ +struct sqlite3_rtree_geometry { + void *pContext; /* Copy of pContext passed to s_r_g_c() */ + int nParam; /* Size of array aParam[] */ + double *aParam; /* Parameters passed to SQL geom function */ + void *pUser; /* Callback implementation user data */ + void (*xDelUser)(void *); /* Called by SQLite to clean up pUser */ +}; + + +#ifdef __cplusplus +} /* end of the 'extern "C"' block */ +#endif + +#endif /* ifndef _SQLITE3RTREE_H_ */ + diff --git a/include/zlib/zconf.h b/include/zlib/zconf.h new file mode 100644 index 000000000..03a9431c8 --- /dev/null +++ b/include/zlib/zconf.h @@ -0,0 +1,332 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#ifndef ZCONF_H +#define ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + */ +#ifdef Z_PREFIX +# define deflateInit_ z_deflateInit_ +# define deflate z_deflate +# define deflateEnd z_deflateEnd +# define inflateInit_ z_inflateInit_ +# define inflate z_inflate +# define inflateEnd z_inflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateSetDictionary z_deflateSetDictionary +# define deflateCopy z_deflateCopy +# define deflateReset z_deflateReset +# define deflateParams z_deflateParams +# define deflateBound z_deflateBound +# define deflatePrime z_deflatePrime +# define inflateInit2_ z_inflateInit2_ +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateCopy z_inflateCopy +# define inflateReset z_inflateReset +# define inflateBack z_inflateBack +# define inflateBackEnd z_inflateBackEnd +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# define uncompress z_uncompress +# define adler32 z_adler32 +# define crc32 z_crc32 +# define get_crc_table z_get_crc_table +# define zError z_zError + +# define alloc_func z_alloc_func +# define free_func z_free_func +# define in_func z_in_func +# define out_func z_out_func +# define Byte z_Byte +# define uInt z_uInt +# define uLong z_uLong +# define Bytef z_Bytef +# define charf z_charf +# define intf z_intf +# define uIntf z_uIntf +# define uLongf z_uLongf +# define voidpf z_voidpf +# define voidp z_voidp +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) +# ifndef WIN32 +# define WIN32 +# endif +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#if 0 /* HAVE_UNISTD_H -- this line is updated by ./configure */ +# include /* for off_t */ +# include /* for SEEK_* and off_t */ +# ifdef VMS +# include /* for off_t */ +# endif +# define z_off_t off_t +#endif +#ifndef SEEK_SET +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif +#ifndef z_off_t +# define z_off_t long +#endif + +#if defined(__OS400__) +# define NO_vsnprintf +#endif + +#if defined(__MVS__) +# define NO_vsnprintf +# ifdef FAR +# undef FAR +# endif +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) +# pragma map(deflateInit_,"DEIN") +# pragma map(deflateInit2_,"DEIN2") +# pragma map(deflateEnd,"DEEND") +# pragma map(deflateBound,"DEBND") +# pragma map(inflateInit_,"ININ") +# pragma map(inflateInit2_,"ININ2") +# pragma map(inflateEnd,"INEND") +# pragma map(inflateSync,"INSY") +# pragma map(inflateSetDictionary,"INSEDI") +# pragma map(compressBound,"CMBND") +# pragma map(inflate_table,"INTABL") +# pragma map(inflate_fast,"INFA") +# pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/include/zlib/zlib.h b/include/zlib/zlib.h new file mode 100644 index 000000000..022817927 --- /dev/null +++ b/include/zlib/zlib.h @@ -0,0 +1,1357 @@ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.2.3, July 18th, 2005 + + Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt + (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). +*/ + +#ifndef ZLIB_H +#define ZLIB_H + +#include "zconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_VERSION "1.2.3" +#define ZLIB_VERNUM 0x1230 + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed + data. This version of the library supports only one compression method + (deflation) but other algorithms will be added later and will have the same + stream interface. + + Compression can be done in a single step if the buffers are large + enough (for example if an input file is mmap'ed), or can be done by + repeated calls of the compression function. In the latter case, the + application must provide more input and/or consume the output + (providing more output space) before each call. + + The compressed data format used by default by the in-memory functions is + the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped + around a deflate stream, which is itself documented in RFC 1951. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio using the functions that start + with "gz". The gzip format is different from the zlib format. gzip is a + gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. + + This library can optionally read and write gzip streams in memory as well. + + The zlib format was designed to be compact and fast for use in memory + and on communications channels. The gzip format was designed for single- + file compression on file systems, has a larger header than zlib to maintain + directory information, and uses a different, slower check method than zlib. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never + crash even in case of corrupted input. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address)); + +struct internal_state; + +typedef struct z_stream_s { + Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total nb of input bytes read so far */ + + Bytef *next_out; /* next output byte should be put there */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total nb of bytes output so far */ + + char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: binary or text */ + uLong adler; /* adler32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + gzip header information passed to and from zlib routines. See RFC 1952 + for more details on the meanings of these fields. +*/ +typedef struct gz_header_s { + int text; /* true if compressed data believed to be text */ + uLong time; /* modification time */ + int xflags; /* extra flags (not used when writing a gzip file) */ + int os; /* operating system */ + Bytef *extra; /* pointer to extra field or Z_NULL if none */ + uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ + uInt extra_max; /* space at extra (only when reading header) */ + Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ + uInt name_max; /* space at name (only when reading header) */ + Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ + uInt comm_max; /* space at comment (only when reading header) */ + int hcrc; /* true if there was or will be a header crc */ + int done; /* true when done reading gzip header (not used + when writing a gzip file) */ +} gz_header; + +typedef gz_header FAR *gz_headerp; + +/* + The application must update next_in and avail_in when avail_in has + dropped to zero. It must update next_out and avail_out when avail_out + has dropped to zero. The application must initialize zalloc, zfree and + opaque before calling the init function. All other fields are set by the + compression library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this + if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, + pointers returned by zalloc for objects of exactly 65536 bytes *must* + have their offset normalized to zero. The default allocation function + provided by this library ensures this (see zutil.c). To reduce memory + requirements and avoid any allocation of 64K objects, at the expense of + compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or + progress reports. After compression, total_in holds the total size of + the uncompressed data and may be saved for use in the decompressor + (particularly if the decompressor wants to decompress everything in + a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */ +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +#define Z_BLOCK 5 +/* Allowed flush values; see deflate() and inflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative + * values are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_RLE 3 +#define Z_FIXED 4 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_TEXT 1 +#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ +#define Z_UNKNOWN 2 +/* Possible values of the data_type field (though see inflate()) */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + /* basic functions */ + +ZEXTERN const char * ZEXPORT zlibVersion OF((void)); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is + not compatible with the zlib.h header file used by the application. + This check is automatically made by deflateInit and inflateInit. + */ + +/* +ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. + If zalloc and zfree are set to Z_NULL, deflateInit updates them to + use default allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at + all (the input data is simply copied a block at a time). + Z_DEFAULT_COMPRESSION requests a default compromise between speed and + compression (currently equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if level is not a valid compression level, + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). + msg is set to null if there is no error message. deflateInit does not + perform any compression: this will be done by deflate(). +*/ + + +ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce some + output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary (in interactive applications). + Some output may be provided even if flush is not set. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating avail_in or avail_out accordingly; avail_out + should never be zero before the call. The application can consume the + compressed output when it wants, for example when the output buffer is full + (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK + and with zero avail_out, it must be called again after making room in the + output buffer because there might be more output pending. + + Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to + decide how much data to accumualte before producing output, in order to + maximize compression. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In particular + avail_in is zero after the call if enough output space has been provided + before the call.) Flushing may degrade compression for some compression + algorithms and so it should be used only when necessary. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that + avail_out is greater than six to avoid repeated flush markers due to + avail_out == 0 on return. + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there + was enough output space; if deflate returns with Z_OK, this function must be + called again with Z_FINISH and more output space (updated avail_out) but no + more input data, until it returns with Z_STREAM_END or an error. After + deflate has returned Z_STREAM_END, the only possible operations on the + stream are deflateReset or deflateEnd. + + Z_FINISH can be used immediately after deflateInit if all the compression + is to be done in a single step. In this case, avail_out must be at least + the value returned by deflateBound (see below). If deflate does not return + Z_STREAM_END, then it must be called again as described above. + + deflate() sets strm->adler to the adler32 checksum of all input read + so far (that is, total_in bytes). + + deflate() may update strm->data_type if it can make a good guess about + the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered + binary. This field is only for information purposes and does not affect + the compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible + (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not + fatal, and deflate() can be called again with more input and more output + space to continue compressing. +*/ + + +ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, + msg may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. If next_in is not Z_NULL and avail_in is large enough (the exact + value depends on the compression method), inflateInit determines the + compression method from the zlib header and allocates all data structures + accordingly; otherwise the allocation will be deferred to the first call of + inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to + use default allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller. msg is set to null if there is no error + message. inflateInit does not perform any decompression apart from reading + the zlib header if present: this will be done by inflate(). (So next_in and + avail_in may be modified, but next_out and avail_out are unchanged.) +*/ + + +ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in is updated and processing + will resume at this point for the next call of inflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there + is no more input data or no more space in the output buffer (see below + about the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating the next_* and avail_* values accordingly. + The application can consume the uncompressed output when it wants, for + example when the output buffer is full (avail_out == 0), or after each + call of inflate(). If inflate returns Z_OK and with zero avail_out, it + must be called again after making room in the output buffer because there + might be more output pending. + + The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, + Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much + output as possible to the output buffer. Z_BLOCK requests that inflate() stop + if and when it gets to the next deflate block boundary. When decoding the + zlib or gzip format, this will cause inflate() to return immediately after + the header and before the first block. When doing a raw inflate, inflate() + will go ahead and process the first block, and will return when it gets to + the end of that block, or when it runs out of data. + + The Z_BLOCK option assists in appending to or combining deflate streams. + Also to assist in this, on return inflate() will set strm->data_type to the + number of unused bits in the last byte taken from strm->next_in, plus 64 + if inflate() is currently decoding the last block in the deflate stream, + plus 128 if inflate() returned immediately after decoding an end-of-block + code or decoding the complete header up to just before the first byte of the + deflate stream. The end-of-block will not be indicated until all of the + uncompressed data from that block has been written to strm->next_out. The + number of unused bits may in general be greater than seven, except when + bit 7 of data_type is set, in which case the number of unused bits will be + less than eight. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step + (a single call of inflate), the parameter flush should be set to + Z_FINISH. In this case all pending input is processed and all pending + output is flushed; avail_out must be large enough to hold all the + uncompressed data. (The size of the uncompressed data may have been saved + by the compressor for this purpose.) The next operation on this stream must + be inflateEnd to deallocate the decompression state. The use of Z_FINISH + is never required, but can be used to inform inflate that a faster approach + may be used for the single inflate() call. + + In this implementation, inflate() always flushes as much output as + possible to the output buffer, and always uses the faster approach on the + first call. So the only effect of the flush parameter in this implementation + is on the return value of inflate(), as noted below, or when it returns early + because Z_BLOCK is used. + + If a preset dictionary is needed after this call (see inflateSetDictionary + below), inflate sets strm->adler to the adler32 checksum of the dictionary + chosen by the compressor and returns Z_NEED_DICT; otherwise it sets + strm->adler to the adler32 checksum of all output produced so far (that is, + total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described + below. At the end of the stream, inflate() checks that its computed adler32 + checksum is equal to that saved by the compressor and returns Z_STREAM_END + only if the checksum is correct. + + inflate() will decompress and check either zlib-wrapped or gzip-wrapped + deflate data. The header type is detected automatically. Any information + contained in the gzip header is not retained, so applications that need that + information should instead use raw inflate, see inflateInit2() below, or + inflateBack() and perform their own processing of the gzip header and + trailer. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect check + value), Z_STREAM_ERROR if the stream structure was inconsistent (for example + if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory, + Z_BUF_ERROR if no progress is possible or if there was not enough room in the + output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and + inflate() can be called again with more input and more output space to + continue decompressing. If Z_DATA_ERROR is returned, the application may then + call inflateSync() to look for a good compression block if a partial recovery + of the data is desired. +*/ + + +ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state + was inconsistent. In the error case, msg may be set but then points to a + static string (which must not be deallocated). +*/ + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields next_in, zalloc, zfree and opaque must be initialized before by + the caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + windowBits can also be -8..-15 for raw deflate. In this case, -windowBits + determines the window size. deflate() will then generate raw deflate data + with no zlib header or trailer, and will not compute an adler32 check value. + + windowBits can also be greater than 15 for optional gzip encoding. Add + 16 to windowBits to write a simple gzip header and trailer around the + compressed data instead of a zlib wrapper. The gzip header will have no + file name, no extra data, no comment, no modification time (set to zero), + no header crc, and the operating system will be set to 255 (unknown). If a + gzip stream is being written, strm->adler is a crc32 instead of an adler32. + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but + is slow and reduces compression ratio; memLevel=9 uses maximum memory + for optimal speed. The default value is 8. See zconf.h for total memory + usage as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match), or Z_RLE to limit match distances to one (run-length + encoding). Filtered data consists mostly of small values with a somewhat + random distribution. In this case, the compression algorithm is tuned to + compress them better. The effect of Z_FILTERED is to force more Huffman + coding and less string matching; it is somewhat intermediate between + Z_DEFAULT and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as + Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy + parameter only affects the compression ratio but not the correctness of the + compressed output even if it is not set appropriately. Z_FIXED prevents the + use of dynamic Huffman codes, allowing for a simpler decoder for special + applications. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid + method). msg is set to null if there is no error message. deflateInit2 does + not perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. This function must be called + immediately after deflateInit, deflateInit2 or deflateReset, before any + call of deflate. The compressor and decompressor must use exactly the same + dictionary (see inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size in + deflate or deflate2. Thus the strings most likely to be useful should be + put at the end of the dictionary, not at the front. In addition, the + current implementation of deflate will use at most the window size minus + 262 bytes of the provided dictionary. + + Upon return of this function, strm->adler is set to the adler32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The adler32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) If a raw deflate was requested, then the + adler32 value is not computed and strm->adler is not set. + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if the compression method is bsort). deflateSetDictionary does not + perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and + can consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); +/* + This function is equivalent to deflateEnd followed by deflateInit, + but does not free and reallocate all the internal compression state. + The stream will keep the same compression level and any other attributes + that may have been set by deflateInit2. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, + int level, + int strategy)); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2. This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different + strategy. If the compression level is changed, the input available so far + is compressed with the old level (and may be flushed); the new level will + take effect only at the next call of deflate(). + + Before the call of deflateParams, the stream state must be set as for + a call of deflate(), since the currently available input may have to + be compressed and flushed. In particular, strm->avail_out must be non-zero. + + deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source + stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR + if strm->avail_out was zero. +*/ + +ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, + int good_length, + int max_lazy, + int nice_length, + int max_chain)); +/* + Fine tune deflate's internal compression parameters. This should only be + used by someone who understands the algorithm used by zlib's deflate for + searching for the best matching string, and even then only by the most + fanatic optimizer trying to squeeze out the last compressed bit for their + specific input data. Read the deflate.c source code for the meaning of the + max_lazy, good_length, nice_length, and max_chain parameters. + + deflateTune() can be called after deflateInit() or deflateInit2(), and + returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. + */ + +ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, + uLong sourceLen)); +/* + deflateBound() returns an upper bound on the compressed size after + deflation of sourceLen bytes. It must be called after deflateInit() + or deflateInit2(). This would be used to allocate an output buffer + for deflation in a single pass, and so would be called before deflate(). +*/ + +ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + deflatePrime() inserts bits in the deflate output stream. The intent + is that this function is used to start off the deflate output with the + bits leftover from a previous deflate stream when appending to it. As such, + this function can only be used for raw deflate, and must be used before the + first deflate() call after a deflateInit2() or deflateReset(). bits must be + less than or equal to 16, and that many of the least significant bits of + value will be inserted in the output. + + deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, + gz_headerp head)); +/* + deflateSetHeader() provides gzip header information for when a gzip + stream is requested by deflateInit2(). deflateSetHeader() may be called + after deflateInit2() or deflateReset() and before the first call of + deflate(). The text, time, os, extra field, name, and comment information + in the provided gz_header structure are written to the gzip header (xflag is + ignored -- the extra flags are set according to the compression level). The + caller must assure that, if not Z_NULL, name and comment are terminated with + a zero byte, and that if extra is not Z_NULL, that extra_len bytes are + available there. If hcrc is true, a gzip header crc is included. Note that + the current versions of the command-line version of gzip (up through version + 1.3.x) do not support header crc's, and will report that it is a "multi-part + gzip file" and give up. + + If deflateSetHeader is not used, the default gzip header has text false, + the time set to zero, and os set to 255, with no extra, name, or comment + fields. The gzip header is returned to the default state by deflateReset(). + + deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. windowBits must be greater than or equal to the windowBits value + provided to deflateInit2() while compressing, or it must be equal to 15 if + deflateInit2() was not used. If a compressed stream with a larger window + size is given as input, inflate() will return with the error code + Z_DATA_ERROR instead of trying to allocate a larger window. + + windowBits can also be -8..-15 for raw inflate. In this case, -windowBits + determines the window size. inflate() will then process raw deflate data, + not looking for a zlib or gzip header, not generating a check value, and not + looking for any check values for comparison at the end of the stream. This + is for use with other formats that use the deflate compressed data format + such as zip. Those formats provide their own check values. If a custom + format is developed using the raw deflate format for compressed data, it is + recommended that a check value such as an adler32 or a crc32 be applied to + the uncompressed data as is done in the zlib, gzip, and zip formats. For + most applications, the zlib format should be used as is. Note that comments + above on the use in deflateInit2() applies to the magnitude of windowBits. + + windowBits can also be greater than 15 for optional gzip decoding. Add + 32 to windowBits to enable zlib and gzip decoding with automatic header + detection, or add 16 to decode only the gzip format (the zlib format will + return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is + a crc32 instead of an adler32. + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as a null strm). msg + is set to null if there is no error message. inflateInit2 does not perform + any decompression apart from reading the zlib header if present: this will + be done by inflate(). (So next_in and avail_in may be modified, but next_out + and avail_out are unchanged.) +*/ + +ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate, + if that call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the adler32 value returned by that call of inflate. + The compressor and decompressor must use exactly the same dictionary (see + deflateSetDictionary). For raw inflate, this function can be called + immediately after inflateInit2() or inflateReset() and before any call of + inflate() to set the dictionary. The application must insure that the + dictionary that was used for compression is provided. + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect adler32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); +/* + Skips invalid compressed data until a full flush point (see above the + description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR + if no more input was provided, Z_DATA_ERROR if no flush point has been found, + or Z_STREAM_ERROR if the stream structure was inconsistent. In the success + case, the application may save the current current value of total_in which + indicates where valid compressed data was found. In the error case, the + application may repeatedly call inflateSync, providing more input each time, + until success or end of the input data. +*/ + +ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when randomly accessing a large stream. The + first pass through the stream can periodically record the inflate state, + allowing restarting inflate at those points when randomly accessing the + stream. + + inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate all the internal decompression state. + The stream will keep attributes that may have been set by inflateInit2. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + This function inserts bits in the inflate input stream. The intent is + that this function is used to start inflating at a bit position in the + middle of a byte. The provided bits will be used before any bytes are used + from next_in. This function should only be used with raw inflate, and + should be used before the first inflate() call after inflateInit2() or + inflateReset(). bits must be less than or equal to 16, and that many of the + least significant bits of value will be inserted in the input. + + inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, + gz_headerp head)); +/* + inflateGetHeader() requests that gzip header information be stored in the + provided gz_header structure. inflateGetHeader() may be called after + inflateInit2() or inflateReset(), and before the first call of inflate(). + As inflate() processes the gzip stream, head->done is zero until the header + is completed, at which time head->done is set to one. If a zlib stream is + being decoded, then head->done is set to -1 to indicate that there will be + no gzip header information forthcoming. Note that Z_BLOCK can be used to + force inflate() to return immediately after header processing is complete + and before any actual data is decompressed. + + The text, time, xflags, and os fields are filled in with the gzip header + contents. hcrc is set to true if there is a header CRC. (The header CRC + was valid if done is set to one.) If extra is not Z_NULL, then extra_max + contains the maximum number of bytes to write to extra. Once done is true, + extra_len contains the actual extra field length, and extra contains the + extra field, or that field truncated if extra_max is less than extra_len. + If name is not Z_NULL, then up to name_max characters are written there, + terminated with a zero unless the length is greater than name_max. If + comment is not Z_NULL, then up to comm_max characters are written there, + terminated with a zero unless the length is greater than comm_max. When + any of extra, name, or comment are not Z_NULL and the respective field is + not present in the header, then that field is set to Z_NULL to signal its + absence. This allows the use of deflateSetHeader() with the returned + structure to duplicate the header. However if those fields are set to + allocated memory, then the application will need to save those pointers + elsewhere so that they can be eventually freed. + + If inflateGetHeader is not used, then the header information is simply + discarded. The header is always checked for validity, including the header + CRC if present. inflateReset() will reset the process to discard the header + information. The application would need to call inflateGetHeader() again to + retrieve the header from the next gzip stream. + + inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, + unsigned char FAR *window)); + + Initialize the internal stream state for decompression using inflateBack() + calls. The fields zalloc, zfree and opaque in strm must be initialized + before the call. If zalloc and zfree are Z_NULL, then the default library- + derived memory allocation routines are used. windowBits is the base two + logarithm of the window size, in the range 8..15. window is a caller + supplied buffer of that size. Except for special applications where it is + assured that deflate was used with small window sizes, windowBits must be 15 + and a 32K byte window must be supplied to be able to decompress general + deflate streams. + + See inflateBack() for the usage of these routines. + + inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of + the paramaters are invalid, Z_MEM_ERROR if the internal state could not + be allocated, or Z_VERSION_ERROR if the version of the library does not + match the version of the header file. +*/ + +typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *)); +typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); + +ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc)); +/* + inflateBack() does a raw inflate with a single call using a call-back + interface for input and output. This is more efficient than inflate() for + file i/o applications in that it avoids copying between the output and the + sliding window by simply making the window itself the output buffer. This + function trusts the application to not change the output buffer passed by + the output function, at least until inflateBack() returns. + + inflateBackInit() must be called first to allocate the internal state + and to initialize the state with the user-provided window buffer. + inflateBack() may then be used multiple times to inflate a complete, raw + deflate stream with each call. inflateBackEnd() is then called to free + the allocated state. + + A raw deflate stream is one with no zlib or gzip header or trailer. + This routine would normally be used in a utility that reads zip or gzip + files and writes out uncompressed files. The utility would decode the + header and process the trailer on its own, hence this routine expects + only the raw deflate stream to decompress. This is different from the + normal behavior of inflate(), which expects either a zlib or gzip header and + trailer around the deflate stream. + + inflateBack() uses two subroutines supplied by the caller that are then + called by inflateBack() for input and output. inflateBack() calls those + routines until it reads a complete deflate stream and writes out all of the + uncompressed data, or until it encounters an error. The function's + parameters and return types are defined above in the in_func and out_func + typedefs. inflateBack() will call in(in_desc, &buf) which should return the + number of bytes of provided input, and a pointer to that input in buf. If + there is no input available, in() must return zero--buf is ignored in that + case--and inflateBack() will return a buffer error. inflateBack() will call + out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() + should return zero on success, or non-zero on failure. If out() returns + non-zero, inflateBack() will return with an error. Neither in() nor out() + are permitted to change the contents of the window provided to + inflateBackInit(), which is also the buffer that out() uses to write from. + The length written by out() will be at most the window size. Any non-zero + amount of input may be provided by in(). + + For convenience, inflateBack() can be provided input on the first call by + setting strm->next_in and strm->avail_in. If that input is exhausted, then + in() will be called. Therefore strm->next_in must be initialized before + calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called + immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in + must also be initialized, and then if strm->avail_in is not zero, input will + initially be taken from strm->next_in[0 .. strm->avail_in - 1]. + + The in_desc and out_desc parameters of inflateBack() is passed as the + first parameter of in() and out() respectively when they are called. These + descriptors can be optionally used to pass any information that the caller- + supplied in() and out() functions need to do their job. + + On return, inflateBack() will set strm->next_in and strm->avail_in to + pass back any unused input that was provided by the last in() call. The + return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR + if in() or out() returned an error, Z_DATA_ERROR if there was a format + error in the deflate stream (in which case strm->msg is set to indicate the + nature of the error), or Z_STREAM_ERROR if the stream was not properly + initialized. In the case of Z_BUF_ERROR, an input or output error can be + distinguished using strm->next_in which will be Z_NULL only if in() returned + an error. If strm->next is not Z_NULL, then the Z_BUF_ERROR was due to + out() returning non-zero. (in() will always be called before out(), so + strm->next_in is assured to be defined if out() returns non-zero.) Note + that inflateBack() cannot return Z_OK. +*/ + +ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); +/* + All memory allocated by inflateBackInit() is freed. + + inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream + state was inconsistent. +*/ + +ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); +/* Return flags indicating compile-time options. + + Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: + 1.0: size of uInt + 3.2: size of uLong + 5.4: size of voidpf (pointer) + 7.6: size of z_off_t + + Compiler, assembler, and debug options: + 8: DEBUG + 9: ASMV or ASMINF -- use ASM code + 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention + 11: 0 (reserved) + + One-time table building (smaller code, but not thread-safe if true): + 12: BUILDFIXED -- build static block decoding tables when needed + 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed + 14,15: 0 (reserved) + + Library content (indicates missing functionality): + 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking + deflate code when not needed) + 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect + and decode gzip streams (to avoid linking crc code) + 18-19: 0 (reserved) + + Operation variations (changes in library functionality): + 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate + 21: FASTEST -- deflate algorithm with only one, lowest compression level + 22,23: 0 (reserved) + + The sprintf variant used by gzprintf (zero is best): + 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format + 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! + 26: 0 = returns value, 1 = void -- 1 means inferred string length returned + + Remainder: + 27-31: 0 (reserved) + */ + + + /* utility functions */ + +/* + The following utility functions are implemented on top of the + basic stream-oriented functions. To simplify the interface, some + default options are assumed (compression level and memory usage, + standard memory allocation functions). The source code of these + utility functions can easily be modified if you need special options. +*/ + +ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be at least the value returned + by compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + This function can be used to compress a whole file at once if the + input file is mmap'ed. + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen, + int level)); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); +/* + compressBound() returns an upper bound on the compressed size after + compress() or compress2() on sourceLen bytes. It would be used before + a compress() or compress2() call to allocate the destination buffer. +*/ + +ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. +*/ + + +typedef voidp gzFile; + +ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); +/* + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb") but can also include a compression level + ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for + Huffman only compression as in "wb1h", or 'R' for run-length encoding + as in "wb1R". (See the description of deflateInit2 for more information + about the strategy parameter.) + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. + + gzopen returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). */ + +ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); +/* + gzdopen() associates a gzFile with the file descriptor fd. File + descriptors are obtained from calls like open, dup, creat, pipe or + fileno (in the file has been previously opened with fopen). + The mode parameter is as in gzopen. + The next call of gzclose on the returned gzFile will also close the + file descriptor fd, just like fclose(fdopen(fd), mode) closes the file + descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode). + gzdopen returns NULL if there was insufficient memory to allocate + the (de)compression state. +*/ + +ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); +/* + Dynamically update the compression level or strategy. See the description + of deflateInit2 for the meaning of these parameters. + gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not + opened for writing. +*/ + +ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); +/* + Reads the given number of uncompressed bytes from the compressed file. + If the input file was not in gzip format, gzread copies the given number + of bytes into the buffer. + gzread returns the number of uncompressed bytes actually read (0 for + end of file, -1 for error). */ + +ZEXTERN int ZEXPORT gzwrite OF((gzFile file, + voidpc buf, unsigned len)); +/* + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of uncompressed bytes actually written + (0 in case of error). +*/ + +ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); +/* + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). The number of + uncompressed bytes written is limited to 4095. The caller should assure that + this limit is not exceeded. If it is exceeded, then gzprintf() will return + return an error (0) with nothing written. In this case, there may also be a + buffer overflow with unpredictable consequences, which is possible only if + zlib was compiled with the insecure functions sprintf() or vsprintf() + because the secure snprintf() or vsnprintf() functions were not available. +*/ + +ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); +/* + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ + +ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); +/* + Reads bytes from the compressed file until len-1 characters are read, or + a newline character is read and transferred to buf, or an end-of-file + condition is encountered. The string is then terminated with a null + character. + gzgets returns buf, or Z_NULL in case of error. +*/ + +ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); +/* + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ + +ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); +/* + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ + +ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); +/* + Push one character back onto the stream to be read again later. + Only one character of push-back is allowed. gzungetc() returns the + character pushed, or -1 on failure. gzungetc() will fail if a + character has been pushed but not read yet, or if c is -1. The pushed + character will be discarded if the stream is repositioned with gzseek() + or gzrewind(). +*/ + +ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); +/* + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. The return value is the zlib + error number (see function gzerror below). gzflush returns Z_OK if + the flush parameter is Z_FINISH and all output could be flushed. + gzflush should be called only when strictly necessary because it can + degrade compression. +*/ + +ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, + z_off_t offset, int whence)); +/* + Sets the starting position for the next gzread or gzwrite on the + given compressed file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); +/* + Rewinds the given file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) +*/ + +ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); +/* + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +ZEXTERN int ZEXPORT gzeof OF((gzFile file)); +/* + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ + +ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); +/* + Returns 1 if file is being read directly without decompression, otherwise + zero. +*/ + +ZEXTERN int ZEXPORT gzclose OF((gzFile file)); +/* + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. The return value is the zlib + error number (see function gzerror below). +*/ + +ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); +/* + Returns the error message for the last error which occurred on the + given compressed file. errnum is set to zlib error number. If an + error occurred in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ + +ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); +/* + Clears the error and end-of-file flags for file. This is analogous to the + clearerr() function in stdio. This is useful for continuing to read a gzip + file that is being written concurrently. +*/ + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the + compression library. +*/ + +ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. If buf is NULL, this function returns + the required initial value for the checksum. + An Adler-32 checksum is almost as reliable as a CRC32 but can be computed + much faster. Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, + z_off_t len2)); +/* + Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 + and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for + each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of + seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. +*/ + +ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); +/* + Update a running CRC-32 with the bytes buf[0..len-1] and return the + updated CRC-32. If buf is NULL, this function returns the required initial + value for the for the crc. Pre- and post-conditioning (one's complement) is + performed within this function so it shouldn't be done by the application. + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + +ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); + +/* + Combine two CRC-32 check values into one. For two sequences of bytes, + seq1 and seq2 with lengths len1 and len2, CRC-32 check values were + calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 + check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and + len2. +*/ + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, + unsigned char FAR *window, + const char *version, + int stream_size)); +#define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) +#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) +#define inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, sizeof(z_stream)) + + +#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) + struct internal_state {int dummy;}; /* hack for buggy compilers */ +#endif + +ZEXTERN const char * ZEXPORT zError OF((int)); +ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z)); +ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); + +#ifdef __cplusplus +} +#endif + +#endif /* ZLIB_H */ diff --git a/include/zlib/zutil.h b/include/zlib/zutil.h new file mode 100644 index 000000000..b7d5eff81 --- /dev/null +++ b/include/zlib/zutil.h @@ -0,0 +1,269 @@ +/* zutil.h -- internal interface and configuration of the compression library + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id$ */ + +#ifndef ZUTIL_H +#define ZUTIL_H + +#define ZLIB_INTERNAL +#include "zlib.h" + +#ifdef STDC +# ifndef _WIN32_WCE +# include +# endif +# include +# include +#endif +#ifdef NO_ERRNO_H +# ifdef _WIN32_WCE + /* The Microsoft C Run-Time Library for Windows CE doesn't have + * errno. We define it as a global variable to simplify porting. + * Its value is always 0 and should not be used. We rename it to + * avoid conflict with other libraries that use the same workaround. + */ +# define errno z_errno +# endif + extern int errno; +#else +# ifndef _WIN32_WCE +# include +# endif +#endif + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +typedef unsigned char uch; +typedef uch FAR uchf; +typedef unsigned short ush; +typedef ush FAR ushf; +typedef unsigned long ulg; + +extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ +/* (size given to avoid silly warnings with Visual C++) */ + +#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] + +#define ERR_RETURN(strm,err) \ + return (strm->msg = (char*)ERR_MSG(err), (err)) +/* To be used only when the state is known to be valid */ + + /* common constants */ + +#ifndef DEF_WBITS +# define DEF_WBITS MAX_WBITS +#endif +/* default windowBits for decompression. MAX_WBITS is for compression only */ + +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +/* default memLevel */ + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +/* The three kinds of block type */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + +#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ + + /* target dependencies */ + +#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) +# define OS_CODE 0x00 +# if defined(__TURBOC__) || defined(__BORLANDC__) +# if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) + /* Allow compilation with ANSI keywords only enabled */ + void _Cdecl farfree( void *block ); + void *_Cdecl farmalloc( unsigned long nbytes ); +# else +# include +# endif +# else /* MSC or DJGPP */ +# include +# endif +#endif + +#ifdef AMIGA +# define OS_CODE 0x01 +#endif + +#if defined(VAXC) || defined(VMS) +# define OS_CODE 0x02 +# define F_OPEN(name, mode) \ + fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") +#endif + +#if defined(ATARI) || defined(atarist) +# define OS_CODE 0x05 +#endif + +#ifdef OS2 +# define OS_CODE 0x06 +# ifdef M_I86 + #include +# endif +#endif + +#if defined(MACOS) || defined(TARGET_OS_MAC) +# define OS_CODE 0x07 +# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os +# include /* for fdopen */ +# else +# ifndef fdopen +# define fdopen(fd,mode) NULL /* No fdopen() */ +# endif +# endif +#endif + +#ifdef TOPS20 +# define OS_CODE 0x0a +#endif + +#ifdef WIN32 +# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */ +# define OS_CODE 0x0b +# endif +#endif + +#ifdef __50SERIES /* Prime/PRIMOS */ +# define OS_CODE 0x0f +#endif + +#if defined(_BEOS_) || defined(RISCOS) +# define fdopen(fd,mode) NULL /* No fdopen() */ +#endif + +#if (defined(_MSC_VER) && (_MSC_VER > 600)) +# if defined(_WIN32_WCE) +# define fdopen(fd,mode) NULL /* No fdopen() */ +# ifndef _PTRDIFF_T_DEFINED + typedef int ptrdiff_t; +# define _PTRDIFF_T_DEFINED +# endif +# else +# define fdopen(fd,type) _fdopen(fd,type) +# endif +#endif + + /* common defaults */ + +#ifndef OS_CODE +# define OS_CODE 0x03 /* assume Unix */ +#endif + +#ifndef F_OPEN +# define F_OPEN(name, mode) fopen((name), (mode)) +#endif + + /* functions */ + +#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif +#if defined(__CYGWIN__) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif +#ifndef HAVE_VSNPRINTF +# ifdef MSDOS + /* vsnprintf may exist on some MS-DOS compilers (DJGPP?), + but for now we just assume it doesn't. */ +# define NO_vsnprintf +# endif +# ifdef __TURBOC__ +# define NO_vsnprintf +# endif +# ifdef WIN32 + /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ +# if !defined(vsnprintf) && !defined(NO_vsnprintf) +# define vsnprintf _vsnprintf +# endif +# endif +# ifdef __SASC +# define NO_vsnprintf +# endif +#endif +#ifdef VMS +# define NO_vsnprintf +#endif + +#if defined(pyr) +# define NO_MEMCPY +#endif +#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) + /* Use our own functions for small and medium model with MSC <= 5.0. + * You may have to use the same strategy for Borland C (untested). + * The __SC__ check is for Symantec. + */ +# define NO_MEMCPY +#endif +#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) +# define HAVE_MEMCPY +#endif +#ifdef HAVE_MEMCPY +# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ +# define zmemcpy _fmemcpy +# define zmemcmp _fmemcmp +# define zmemzero(dest, len) _fmemset(dest, 0, len) +# else +# define zmemcpy memcpy +# define zmemcmp memcmp +# define zmemzero(dest, len) memset(dest, 0, len) +# endif +#else + extern void zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); + extern int zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); + extern void zmemzero OF((Bytef* dest, uInt len)); +#endif + +/* Diagnostic functions */ +#ifdef DEBUG +# include + extern int z_verbose; + extern void z_error OF((char *m)); +# define Assert(cond,msg) {if(!(cond)) z_error(msg);} +# define Trace(x) {if (z_verbose>=0) fprintf x ;} +# define Tracev(x) {if (z_verbose>0) fprintf x ;} +# define Tracevv(x) {if (z_verbose>1) fprintf x ;} +# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} +# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + + +voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); +void zcfree OF((voidpf opaque, voidpf ptr)); + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) +#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} + +#endif /* ZUTIL_H */ diff --git a/lib/bdb/libdb43.lib b/lib/bdb/libdb43.lib new file mode 100644 index 000000000..82db94f3f Binary files /dev/null and b/lib/bdb/libdb43.lib differ diff --git a/lib/openssl/libeay32.lib b/lib/openssl/libeay32.lib new file mode 100644 index 000000000..b3ed56560 Binary files /dev/null and b/lib/openssl/libeay32.lib differ diff --git a/lib/openssl/ssleay32.lib b/lib/openssl/ssleay32.lib new file mode 100644 index 000000000..46beaa767 Binary files /dev/null and b/lib/openssl/ssleay32.lib differ diff --git a/lib/protobuf/win32/libprotobuf-lite-debug.lib b/lib/protobuf/win32/libprotobuf-lite-debug.lib new file mode 100644 index 000000000..d50cc1706 Binary files /dev/null and b/lib/protobuf/win32/libprotobuf-lite-debug.lib differ diff --git a/lib/protobuf/win32/libprotobuf-lite.lib b/lib/protobuf/win32/libprotobuf-lite.lib new file mode 100644 index 000000000..edb4e5baa Binary files /dev/null and b/lib/protobuf/win32/libprotobuf-lite.lib differ diff --git a/lib/win32/detours.lib b/lib/win32/detours.lib new file mode 100644 index 000000000..22a705664 Binary files /dev/null and b/lib/win32/detours.lib differ diff --git a/lib/win32/iconv.dll b/lib/win32/iconv.dll new file mode 100644 index 000000000..13b8f5d69 Binary files /dev/null and b/lib/win32/iconv.dll differ diff --git a/lib/win32/iconv.lib b/lib/win32/iconv.lib new file mode 100644 index 000000000..3bf100980 Binary files /dev/null and b/lib/win32/iconv.lib differ diff --git a/lib/win32/libdb43.lib b/lib/win32/libdb43.lib new file mode 100644 index 000000000..82db94f3f Binary files /dev/null and b/lib/win32/libdb43.lib differ diff --git a/lib/win32/libeay32.lib b/lib/win32/libeay32.lib new file mode 100644 index 000000000..b3ed56560 Binary files /dev/null and b/lib/win32/libeay32.lib differ diff --git a/lib/win32/libmysql.dll b/lib/win32/libmysql.dll new file mode 100644 index 000000000..6ad84bf61 Binary files /dev/null and b/lib/win32/libmysql.dll differ diff --git a/lib/win32/libmysql.lib b/lib/win32/libmysql.lib new file mode 100644 index 000000000..44d3301bc Binary files /dev/null and b/lib/win32/libmysql.lib differ diff --git a/lib/win32/polarssl.lib b/lib/win32/polarssl.lib new file mode 100644 index 000000000..bb9a50c2c Binary files /dev/null and b/lib/win32/polarssl.lib differ diff --git a/lib/win32/sqlite3.def b/lib/win32/sqlite3.def new file mode 100644 index 000000000..758cb28fb --- /dev/null +++ b/lib/win32/sqlite3.def @@ -0,0 +1,199 @@ +EXPORTS +sqlite3_aggregate_context +sqlite3_aggregate_count +sqlite3_auto_extension +sqlite3_backup_finish +sqlite3_backup_init +sqlite3_backup_pagecount +sqlite3_backup_remaining +sqlite3_backup_step +sqlite3_bind_blob +sqlite3_bind_double +sqlite3_bind_int +sqlite3_bind_int64 +sqlite3_bind_null +sqlite3_bind_parameter_count +sqlite3_bind_parameter_index +sqlite3_bind_parameter_name +sqlite3_bind_text +sqlite3_bind_text16 +sqlite3_bind_value +sqlite3_bind_zeroblob +sqlite3_blob_bytes +sqlite3_blob_close +sqlite3_blob_open +sqlite3_blob_read +sqlite3_blob_reopen +sqlite3_blob_write +sqlite3_busy_handler +sqlite3_busy_timeout +sqlite3_changes +sqlite3_clear_bindings +sqlite3_close +sqlite3_collation_needed +sqlite3_collation_needed16 +sqlite3_column_blob +sqlite3_column_bytes +sqlite3_column_bytes16 +sqlite3_column_count +sqlite3_column_database_name +sqlite3_column_database_name16 +sqlite3_column_decltype +sqlite3_column_decltype16 +sqlite3_column_double +sqlite3_column_int +sqlite3_column_int64 +sqlite3_column_name +sqlite3_column_name16 +sqlite3_column_origin_name +sqlite3_column_origin_name16 +sqlite3_column_table_name +sqlite3_column_table_name16 +sqlite3_column_text +sqlite3_column_text16 +sqlite3_column_type +sqlite3_column_value +sqlite3_commit_hook +sqlite3_compileoption_get +sqlite3_compileoption_used +sqlite3_complete +sqlite3_complete16 +sqlite3_config +sqlite3_context_db_handle +sqlite3_create_collation +sqlite3_create_collation16 +sqlite3_create_collation_v2 +sqlite3_create_function +sqlite3_create_function16 +sqlite3_create_function_v2 +sqlite3_create_module +sqlite3_create_module_v2 +sqlite3_data_count +sqlite3_db_config +sqlite3_db_handle +sqlite3_db_mutex +sqlite3_db_status +sqlite3_declare_vtab +sqlite3_enable_load_extension +sqlite3_enable_shared_cache +sqlite3_errcode +sqlite3_errmsg +sqlite3_errmsg16 +sqlite3_exec +sqlite3_expired +sqlite3_extended_errcode +sqlite3_extended_result_codes +sqlite3_file_control +sqlite3_finalize +sqlite3_free +sqlite3_free_table +sqlite3_get_autocommit +sqlite3_get_auxdata +sqlite3_get_table +sqlite3_global_recover +sqlite3_initialize +sqlite3_interrupt +sqlite3_last_insert_rowid +sqlite3_libversion +sqlite3_libversion_number +sqlite3_limit +sqlite3_load_extension +sqlite3_log +sqlite3_malloc +sqlite3_memory_alarm +sqlite3_memory_highwater +sqlite3_memory_used +sqlite3_mprintf +sqlite3_mutex_alloc +sqlite3_mutex_enter +sqlite3_mutex_free +sqlite3_mutex_leave +sqlite3_mutex_try +sqlite3_next_stmt +sqlite3_open +sqlite3_open16 +sqlite3_open_v2 +sqlite3_os_end +sqlite3_os_init +sqlite3_overload_function +sqlite3_prepare +sqlite3_prepare16 +sqlite3_prepare16_v2 +sqlite3_prepare_v2 +sqlite3_profile +sqlite3_progress_handler +sqlite3_randomness +sqlite3_realloc +sqlite3_release_memory +sqlite3_reset +sqlite3_reset_auto_extension +sqlite3_result_blob +sqlite3_result_double +sqlite3_result_error +sqlite3_result_error16 +sqlite3_result_error_code +sqlite3_result_error_nomem +sqlite3_result_error_toobig +sqlite3_result_int +sqlite3_result_int64 +sqlite3_result_null +sqlite3_result_text +sqlite3_result_text16 +sqlite3_result_text16be +sqlite3_result_text16le +sqlite3_result_value +sqlite3_result_zeroblob +sqlite3_rollback_hook +sqlite3_rtree_geometry_callback +sqlite3_set_authorizer +sqlite3_set_auxdata +sqlite3_shutdown +sqlite3_sleep +sqlite3_snprintf +sqlite3_soft_heap_limit +sqlite3_soft_heap_limit64 +sqlite3_sourceid +sqlite3_sql +sqlite3_status +sqlite3_step +sqlite3_stmt_readonly +sqlite3_stmt_status +sqlite3_strnicmp +sqlite3_table_column_metadata +sqlite3_test_control +sqlite3_thread_cleanup +sqlite3_threadsafe +sqlite3_total_changes +sqlite3_trace +sqlite3_transfer_bindings +sqlite3_update_hook +sqlite3_uri_parameter +sqlite3_user_data +sqlite3_value_blob +sqlite3_value_bytes +sqlite3_value_bytes16 +sqlite3_value_double +sqlite3_value_int +sqlite3_value_int64 +sqlite3_value_numeric_type +sqlite3_value_text +sqlite3_value_text16 +sqlite3_value_text16be +sqlite3_value_text16le +sqlite3_value_type +sqlite3_vfs_find +sqlite3_vfs_register +sqlite3_vfs_unregister +sqlite3_vmprintf +sqlite3_vsnprintf +sqlite3_vtab_config +sqlite3_vtab_on_conflict +sqlite3_wal_autocheckpoint +sqlite3_wal_checkpoint +sqlite3_wal_checkpoint_v2 +sqlite3_wal_hook +sqlite3_win32_mbcs_to_utf8 +sqlite3_win32_utf8_to_mbcs +winCurrentTime +winDlClose +winDlSym diff --git a/lib/win32/sqlite3.dll b/lib/win32/sqlite3.dll new file mode 100644 index 000000000..7c8bbb5f2 Binary files /dev/null and b/lib/win32/sqlite3.dll differ diff --git a/lib/win32/sqlite3.lib b/lib/win32/sqlite3.lib new file mode 100644 index 000000000..833ee6175 Binary files /dev/null and b/lib/win32/sqlite3.lib differ diff --git a/lib/win32/ssleay32.lib b/lib/win32/ssleay32.lib new file mode 100644 index 000000000..46beaa767 Binary files /dev/null and b/lib/win32/ssleay32.lib differ diff --git a/lib/win32/vld.dll b/lib/win32/vld.dll new file mode 100644 index 000000000..381ac17d0 Binary files /dev/null and b/lib/win32/vld.dll differ diff --git a/lib/win32/vld.lib b/lib/win32/vld.lib new file mode 100644 index 000000000..f9524d403 Binary files /dev/null and b/lib/win32/vld.lib differ diff --git a/lib/win32/zlib.dll b/lib/win32/zlib.dll new file mode 100644 index 000000000..0310a6490 Binary files /dev/null and b/lib/win32/zlib.dll differ diff --git a/lib_acl/Doxyfile b/lib_acl/Doxyfile new file mode 100644 index 000000000..02ad6b8a5 --- /dev/null +++ b/lib_acl/Doxyfile @@ -0,0 +1,1844 @@ +# Doxyfile 1.8.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 = acl + +# 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 = 2.1.2_8 + +# 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 = + +# 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 = E:\work\online_help\acl + +# 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 = Chinese + +# 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 = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# 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. Note that you specify absolute paths here, but also +# relative paths, which will be relative from the directory where doxygen is +# started. + +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 = YES + +# 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 = NO + +# 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 = YES + +# 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 = YES + +# 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 + +# When enabled doxygen tries to link words that correspond to documented classes, +# or namespaces to their corresponding documentation. Such a link can be +# prevented in individual cases by by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. + +AUTOLINK_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 = NO + +# 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 = YES + +# 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. + +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 = *.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 + +# 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 = YES + +# 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 = NO + +# 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 left blank doxygen will +# generate a default style sheet. Note that it is recommended to use +# HTML_EXTRA_STYLESHEET instead of this one, as it is more robust and this +# tag will in the future become obsolete. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional +# user-defined cascading style sheet that is included after the standard +# style sheets created by doxygen. Using this option one can overrule +# certain style aspects. This is preferred over using HTML_STYLESHEET +# since it does not replace the standard style sheet and is therefor more +# robust against future updates. Doxygen will copy the style sheet file to +# the output directory. + +HTML_EXTRA_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 = YES + +# 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 = YES + +# 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://www.mathjax.org/mathjax + +# 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 = YES + +#--------------------------------------------------------------------------- +# 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 = NO + +# 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 = NO + +# 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 = YES + +# 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 = YES + +# 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 = YES + +# 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 = YES + +# 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/lib_acl/Makefile b/lib_acl/Makefile new file mode 100644 index 000000000..eab978684 --- /dev/null +++ b/lib_acl/Makefile @@ -0,0 +1,469 @@ +SHELL = /bin/sh +#CC = gcc +#CC = g++ +CC = ${MY_ENV_CC} +AR = ar +ARFL = rv +#ARFL = cru +RANLIB = ranlib + +# default lib name +LIB_NAME = lib_acl.a + +#CFLAGS = -c -g -W -Wall -Wcast-qual -Wcast-align +#-fno-strict-aliasing +CFLAGS = -c -g -W -Wall -Wcast-align \ +-Wpointer-arith \ +-Werror \ +-Wshadow \ +-O3 \ +-Waggregate-return \ +-Wmissing-prototypes \ +-D_REENTRANT \ +-D_USE_FAST_MACRO \ +-Wno-long-long \ +-Wuninitialized \ +-D_POSIX_PTHREAD_SEMANTICS \ +-pedantic \ +-fPIC +#-Winvalid-pch -DACL_PREPARE_COMPILE + +########################################################### +#Check system: +# Linux, SunOS, Solaris, BSD variants, AIX, HP-UX +SYSLIB = -lpthread +CHECKSYSRES = @echo "Unknow system type!";exit 1 +UNIXNAME = $(shell uname -sm) +ifeq ($(CC),) + CC = gcc +endif + +ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes +endif + +# For FreeBSD +ifeq ($(findstring FreeBSD, $(UNIXNAME)), FreeBSD) + CFLAGS += -DFREEBSD +endif + +# For Darwin +ifeq ($(findstring Darwin, $(UNIXNAME)), Darwin) + CFLAGS += -DMACOSX +endif + +# For Linux +ifeq ($(findstring Linux, $(UNIXNAME)), Linux) + CFLAGS += -DLINUX2 +endif + +# For SunOS +ifeq ($(findstring SunOS, $(UNIXNAME)), SunOS) + ifeq ($(findstring 86, $(UNIXNAME)), 86) + SYSLIB += -lsocket -lnsl -lrt + endif + ifeq ($(findstring sun4u, $(UNIXNAME)), sun4u) + SYSLIB += -lsocket -lnsl -lrt + endif + CFLAGS += -DSUNOS5 +endif + +# For HP-UX +ifeq ($(findstring HP-UX, $(UNIXNAME)), HP-UX) + CFLAGS += -DHP_UX -DHPUX11 + PLAT_NAME=hp-ux +endif + +#CCARGS = +#ifeq ($(findstring HAS_MYSQL, $(CCARGS)), HAS_MYSQL) +# CFLAGS += -DHAS_MYSQL +# LIB_NAME = lib_acl.a +#endif + +CFLAGS += -DHAS_MYSQL + +#Find system type. +ifneq ($(SYSPATH),) + CHECKSYSRES = @echo "System is $(shell uname -sm)" +endif +########################################################### + +OUT_PATH = . +OBJ_PATH_DST = $(OUT_PATH)/debug +LIB_PATH_DST = $(OUT_PATH)/lib +DEF_PATH_DST = $(OUT_PATH)/debug + +BASE_PATH = . +INC_PATH_SRC = $(BASE_PATH)/include +SRC_PATH_SRC = $(BASE_PATH)/src + +CFLAGS += -I. -I$(INC_PATH_SRC) -I../include/mysql + +########################################################### + +#Project's objs +INIT_SRC = $(wildcard $(SRC_PATH_SRC)/init/*.c) +PRIV_SRC = $(wildcard $(SRC_PATH_SRC)/private/*.c) +STDLIB_SRC = $(wildcard $(SRC_PATH_SRC)/stdlib/*.c) \ + $(wildcard $(SRC_PATH_SRC)/stdlib/common/*.c) \ + $(wildcard $(SRC_PATH_SRC)/stdlib/iostuff/*.c) \ + $(wildcard $(SRC_PATH_SRC)/stdlib/configure/*.c) \ + $(wildcard $(SRC_PATH_SRC)/stdlib/filedir/*.c) \ + $(wildcard $(SRC_PATH_SRC)/stdlib/string/*.c) \ + $(wildcard $(SRC_PATH_SRC)/stdlib/memory/*.c) \ + $(wildcard $(SRC_PATH_SRC)/stdlib/debug/*.c) \ + $(wildcard $(SRC_PATH_SRC)/stdlib/sys/*.c) \ + $(wildcard $(SRC_PATH_SRC)/stdlib/sys/unix/*.c) +NET_SRC = $(wildcard $(SRC_PATH_SRC)/net/*.c) \ + $(wildcard $(SRC_PATH_SRC)/net/listen/*.c) \ + $(wildcard $(SRC_PATH_SRC)/net/connect/*.c) \ + $(wildcard $(SRC_PATH_SRC)/net/dns/*.c) +ENGINE_SRC = $(wildcard $(SRC_PATH_SRC)/event/*.c) +IOCTL_SRC = $(wildcard $(SRC_PATH_SRC)/ioctl/*.c) +AIO_SRC = $(wildcard $(SRC_PATH_SRC)/aio/*.c) +MSG_SRC = $(wildcard $(SRC_PATH_SRC)/msg/*.c) +THREAD_SRC = $(wildcard $(SRC_PATH_SRC)/thread/*.c) +SVR_SRC = $(wildcard $(SRC_PATH_SRC)/svr/*.c) +DB_SRC = $(wildcard $(SRC_PATH_SRC)/db/*.c) \ + $(wildcard $(SRC_PATH_SRC)/db/mysql/*.c) \ + $(wildcard $(SRC_PATH_SRC)/db/null/*.c) \ + $(wildcard $(SRC_PATH_SRC)/db/memdb/*.c) \ + $(wildcard $(SRC_PATH_SRC)/db/zdb/*.c) +CODE_SRC = $(wildcard $(SRC_PATH_SRC)/code/*.c) +MASTER_SRC = $(wildcard $(SRC_PATH_SRC)/master/*.c) \ + $(wildcard $(SRC_PATH_SRC)/master/framework/*.c) \ + $(wildcard $(SRC_PATH_SRC)/master/framework/trigger/*.c) \ + $(wildcard $(SRC_PATH_SRC)/master/template/*.c) +PROCTL_SRC = $(wildcard $(SRC_PATH_SRC)/proctl/*.c) +XML_SRC = $(wildcard $(SRC_PATH_SRC)/xml/*.c) +JSON_SRC = $(wildcard $(SRC_PATH_SRC)/json/*.c) +UTEST_SRC = $(wildcard $(SRC_PATH_SRC)/unit_test/*.c) +#EXP_SRC = $(wildcard $(SRC_PATH_SRC)/experiment/avl/*.c) + +SOURCES_SRC = $(INIT_SRC) $(STDLIB_SRC) $(NET_SRC) \ + $(ENGINE_SRC) $(IOCTL_SRC) $(AIO_SRC) \ + $(MSG_SRC) $(THREAD_SRC) $(SVR_SRC) \ + $(DB_SRC) $(CODE_SRC) $(MASTER_SRC) \ + $(PROCTL_SRC) $(XML_SRC) $(UTEST_SRC) +#$(EXP_SRC) + +########################################################### +INIT_OBJ = $(patsubst %.c, $(OBJ_PATH_DST)/%.o, $(notdir $(INIT_SRC))) +PRIV_OBJ = $(patsubst %.c, $(OBJ_PATH_DST)/%.o, $(notdir $(PRIV_SRC))) +STDLIB_OBJ = $(patsubst %.c, $(OBJ_PATH_DST)/%.o, $(notdir $(STDLIB_SRC))) +NET_OBJ = $(patsubst %.c, $(OBJ_PATH_DST)/%.o, $(notdir $(NET_SRC))) +ENGINE_OBJ = $(patsubst %.c, $(OBJ_PATH_DST)/%.o, $(notdir $(ENGINE_SRC))) +IOCTL_OBJ = $(patsubst %.c, $(OBJ_PATH_DST)/%.o, $(notdir $(IOCTL_SRC))) +AIO_OBJ = $(patsubst %.c, $(OBJ_PATH_DST)/%.o, $(notdir $(AIO_SRC))) +MSG_OBJ = $(patsubst %.c, $(OBJ_PATH_DST)/%.o, $(notdir $(MSG_SRC))) +THREAD_OBJ = $(patsubst %.c, $(OBJ_PATH_DST)/%.o, $(notdir $(THREAD_SRC))) +SVR_OBJ = $(patsubst %.c, $(OBJ_PATH_DST)/%.o, $(notdir $(SVR_SRC))) +DB_OBJ = $(patsubst %.c, $(OBJ_PATH_DST)/%.o, $(notdir $(DB_SRC))) +CODE_OBJ = $(patsubst %.c, $(OBJ_PATH_DST)/%.o, $(notdir $(CODE_SRC))) +MASTER_OBJ = $(patsubst %.c, $(OBJ_PATH_DST)/%.o, $(notdir $(MASTER_SRC))) +PROCTL_OBJ = $(patsubst %.c, $(OBJ_PATH_DST)/%.o, $(notdir $(PROCTL_SRC))) +XML_OBJ = $(patsubst %.c, $(OBJ_PATH_DST)/%.o, $(notdir $(XML_SRC))) +JSON_OBJ = $(patsubst %.c, $(OBJ_PATH_DST)/%.o, $(notdir $(JSON_SRC))) +UTEST_OBJ = $(patsubst %.c, $(OBJ_PATH_DST)/%.o, $(notdir $(UTEST_SRC))) +#EXP_OBJ = $(patsubst %.c, $(OBJ_PATH_DST)/%.o, $(notdir $(EXP_SRC))) + +OBJS_DST = $(INIT_OBJ) $(PRIV_OBJ) $(STDLIB_OBJ) \ + $(NET_OBJ) $(ENGINE_OBJ) $(IOCTL_OBJ) \ + $(AIO_OBJ) $(MSG_OBJ) $(THREAD_OBJ) \ + $(SVR_OBJ) $(DB_OBJ) $(CODE_OBJ) \ + $(MASTER_OBJ) $(PROCTL_OBJ) $(XML_OBJ) \ + $(JSON_OBJ) $(UTEST_OBJ) +#$(EXP_OBJ) + +########################################################### +INIT_DEF = $(patsubst %.c, $(DEF_PATH_DST)/%.inc, $(notdir $(INIT_SRC))) +PRIV_DEF = $(patsubst %.c, $(DEF_PATH_DST)/%.inc, $(notdir $(PRIV_SRC))) +STDLIB_DEF = $(patsubst %.c, $(DEF_PATH_DST)/%.inc, $(notdir $(STDLIB_SRC))) +NET_DEF = $(patsubst %.c, $(DEF_PATH_DST)/%.inc, $(notdir $(NET_SRC))) +ENGINE_DEF = $(patsubst %.c, $(DEF_PATH_DST)/%.inc, $(notdir $(ENGINE_SRC))) +IOCTL_DEF = $(patsubst %.c, $(DEF_PATH_DST)/%.inc, $(notdir $(IOCTL_SRC))) +AIO_DEF = $(patsubst %.c, $(DEF_PATH_DST)/%.inc, $(notdir $(AIO_SRC))) +MSG_DEF = $(patsubst %.c, $(DEF_PATH_DST)/%.inc, $(notdir $(MSG_SRC))) +THREAD_DEF = $(patsubst %.c, $(DEF_PATH_DST)/%.inc, $(notdir $(THREAD_SRC))) +SVR_DEF = $(patsubst %.c, $(DEF_PATH_DST)/%.inc, $(notdir $(SVR_SRC))) +DB_DEF = $(patsubst %.c, $(DEF_PATH_DST)/%.inc, $(notdir $(DB_SRC))) +CODE_DEF = $(patsubst %.c, $(DEF_PATH_DST)/%.inc, $(notdir $(CODE_SRC))) +MASTER_DEF = $(patsubst %.c, $(DEF_PATH_DST)/%.inc, $(notdir $(MASTER_SRC))) +PROCTL_DEF = $(patsubst %.c, $(DEF_PATH_DST)/%.inc, $(notdir $(PROCTL_SRC))) +XML_DEF = $(patsubst %.c, $(DEF_PATH_DST)/%.inc, $(notdir $(XML_SRC))) +JSON_DEF = $(patsubst %.c, $(DEF_PATH_DST)/%.inc, $(notdir $(JSON_SRC))) +UTEST_DEF = $(patsubst %.c, $(DEF_PATH_DST)/%.inc, $(notdir $(UTEST_SRC))) +#EXP_DEF = $(patsubst %.c, $(DEF_PATH_DST)/%.inc, $(notdir $(EXP_SRC))) + +OBJS_DEF = $(INIT_DEF) $(PRIV_DEF) $(STDLIB_DEF) \ + $(NET_DEF) $(ENGINE_DEF) $(IOCTL_DEF) \ + $(AIO_DEF) $(MSG_DEF) $(THREAD_DEF) \ + $(SVR_DEF) $(DB_DEF) $(CODE_DEF) \ + $(MASTER_DEF) $(PROCTL_DEF) $(XML_DEF) \ + $(JSON_DEF) $(UTEST_DEF) + +########################################################### +.PHONY = all static shared acl_master clean clean_lib clean_master rebuild + +all: static shared acl_master + +$(shell mkdir -p $(DEF_PATH_DST)) +ifneq ($(MAKECMDGOALS),clean) +-include $(OBJS_DEF) +endif + +clean: clean_lib clean_master +rebuild: clean all + +LIB_GCH = StdAfx.h.gch + +########################################################### + +COMPILE = $(CC) $(CFLAGS) +COMPILE_OBJ = @(echo 'building $<'; $(COMPILE) $< -o $@) +CREATE_DEF = @(echo 'creating $@'; rm -f $@; \ + $(COMPILE) -MM $< > $@.$$$$; \ + sed 's,.*.o\( \)*:,$(patsubst %.inc,%.o,$@) $@ :,g' < $@.$$$$ > $@; \ + rm -f $@.$$$$) + +static: depends $(OBJS_DST) + @echo 'creating $(LIB_PATH_DST)/lib_acl.a' + @$(AR) $(ARFL) $(LIB_PATH_DST)/lib_acl.a $(OBJS_DST) + @$(RANLIB) $(LIB_PATH_DST)/lib_acl.a + @echo 'build $(LIB_PATH_DST)/lib_acl.a ok!' + +shared_ldflags = -lmysqlclient -lrt -lpthread -ldl +shared: depends $(OBJS_DST) + @echo '' + @echo 'creating $(LIB_PATH_DST)/lib_acl.so ...' + @if test -n "$(rpath)"; then \ + $(CC) -shared -o $(LIB_PATH_DST)/lib_acl.so $(OBJS_DST) -L$(rpath) \ + $(shared_ldflags) -Wl,-rpath,$(rpath); \ + echo 'build $(LIB_PATH_DST)/lib_acl.so ok!'; \ + else \ + echo 'skip build $(LIB_PATH_DST)/lib_acl.so; usage: make shared rpath=xxx'; \ + fi + +depends: $(OBJS_DEF) + +lib_gch: include/StdAfx.h + $(CC) -o include/$(LIB_GCH) -x c-header $(CFLAGS) include/StdAfx.h + +########################################################### + +# init +$(OBJ_PATH_DST)/%.o: $(SRC_PATH_SRC)/init/%.c + $(COMPILE_OBJ) +$(DEF_PATH_DST)/%.inc: $(SRC_PATH_SRC)/init/%.c + $(CREATE_DEF) +# private +$(OBJ_PATH_DST)/%.o: $(SRC_PATH_SRC)/private/%.c + $(COMPILE_OBJ) +$(DEF_PATH_DST)/%.inc: $(SRC_PATH_SRC)/private/%.c + $(CREATE_DEF) +# stdlib +$(OBJ_PATH_DST)/%.o: $(SRC_PATH_SRC)/stdlib/%.c + $(COMPILE_OBJ) +$(DEF_PATH_DST)/%.inc: $(SRC_PATH_SRC)/stdlib/%.c + $(CREATE_DEF) +$(OBJ_PATH_DST)/%.o: $(SRC_PATH_SRC)/stdlib/common/%.c + $(COMPILE_OBJ) +$(DEF_PATH_DST)/%.inc: $(SRC_PATH_SRC)/stdlib/common/%.c + $(CREATE_DEF) +$(OBJ_PATH_DST)/%.o: $(SRC_PATH_SRC)/stdlib/iostuff/%.c + $(COMPILE_OBJ) +$(DEF_PATH_DST)/%.inc: $(SRC_PATH_SRC)/stdlib/iostuff/%.c + $(CREATE_DEF) +$(OBJ_PATH_DST)/%.o: $(SRC_PATH_SRC)/stdlib/configure/%.c + $(COMPILE_OBJ) +$(DEF_PATH_DST)/%.inc: $(SRC_PATH_SRC)/stdlib/configure/%.c + $(CREATE_DEF) +$(OBJ_PATH_DST)/%.o: $(SRC_PATH_SRC)/stdlib/filedir/%.c + $(COMPILE_OBJ) +$(DEF_PATH_DST)/%.inc: $(SRC_PATH_SRC)/stdlib/filedir/%.c + $(CREATE_DEF) +$(OBJ_PATH_DST)/%.o: $(SRC_PATH_SRC)/stdlib/string/%.c + $(COMPILE_OBJ) +$(DEF_PATH_DST)/%.inc: $(SRC_PATH_SRC)/stdlib/string/%.c + $(CREATE_DEF) +$(OBJ_PATH_DST)/%.o: $(SRC_PATH_SRC)/stdlib/memory/%.c + $(COMPILE_OBJ) +$(DEF_PATH_DST)/%.inc: $(SRC_PATH_SRC)/stdlib/memory/%.c + $(CREATE_DEF) +$(OBJ_PATH_DST)/%.o: $(SRC_PATH_SRC)/stdlib/debug/%.c + $(COMPILE_OBJ) +$(DEF_PATH_DST)/%.inc: $(SRC_PATH_SRC)/stdlib/debug/%.c + $(CREATE_DEF) +$(OBJ_PATH_DST)/%.o: $(SRC_PATH_SRC)/stdlib/sys/%.c + $(COMPILE_OBJ) +$(DEF_PATH_DST)/%.inc: $(SRC_PATH_SRC)/stdlib/sys/%.c + $(CREATE_DEF) +$(OBJ_PATH_DST)/%.o: $(SRC_PATH_SRC)/stdlib/sys/unix/%.c + $(COMPILE_OBJ) +$(DEF_PATH_DST)/%.inc: $(SRC_PATH_SRC)/stdlib/sys/unix/%.c + $(CREATE_DEF) +# net +$(OBJ_PATH_DST)/%.o: $(SRC_PATH_SRC)/net/%.c + $(COMPILE_OBJ) +$(DEF_PATH_DST)/%.inc: $(SRC_PATH_SRC)/net/%.c + $(CREATE_DEF) +$(OBJ_PATH_DST)/%.o: $(SRC_PATH_SRC)/net/listen/%.c + $(COMPILE_OBJ) +$(DEF_PATH_DST)/%.inc: $(SRC_PATH_SRC)/net/listen/%.c + $(CREATE_DEF) +$(OBJ_PATH_DST)/%.o: $(SRC_PATH_SRC)/net/connect/%.c + $(COMPILE_OBJ) +$(DEF_PATH_DST)/%.inc: $(SRC_PATH_SRC)/net/connect/%.c + $(CREATE_DEF) +$(OBJ_PATH_DST)/%.o: $(SRC_PATH_SRC)/net/dns/%.c + $(COMPILE_OBJ) +$(DEF_PATH_DST)/%.inc: $(SRC_PATH_SRC)/net/dns/%.c + $(CREATE_DEF) +# event +$(OBJ_PATH_DST)/%.o: $(SRC_PATH_SRC)/event/%.c + $(COMPILE_OBJ) +$(DEF_PATH_DST)/%.inc: $(SRC_PATH_SRC)/event/%.c + $(CREATE_DEF) + +# ioctl +$(OBJ_PATH_DST)/%.o: $(SRC_PATH_SRC)/ioctl/%.c + $(COMPILE_OBJ) +$(DEF_PATH_DST)/%.inc: $(SRC_PATH_SRC)/ioctl/%.c + $(CREATE_DEF) + +# aio +$(OBJ_PATH_DST)/%.o: $(SRC_PATH_SRC)/aio/%.c + $(COMPILE_OBJ) +$(DEF_PATH_DST)/%.inc: $(SRC_PATH_SRC)/aio/%.c + $(CREATE_DEF) + +# msg +$(OBJ_PATH_DST)/%.o: $(SRC_PATH_SRC)/msg/%.c + $(COMPILE_OBJ) +$(DEF_PATH_DST)/%.inc: $(SRC_PATH_SRC)/msg/%.c + $(CREATE_DEF) + +# thread +$(OBJ_PATH_DST)/%.o: $(SRC_PATH_SRC)/thread/%.c + $(COMPILE_OBJ) +$(DEF_PATH_DST)/%.inc: $(SRC_PATH_SRC)/thread/%.c + $(CREATE_DEF) + +# svr +$(OBJ_PATH_DST)/%.o: $(SRC_PATH_SRC)/svr/%.c + $(COMPILE_OBJ) +$(DEF_PATH_DST)/%.inc: $(SRC_PATH_SRC)/svr/%.c + $(CREATE_DEF) + +# db +$(OBJ_PATH_DST)/%.o: $(SRC_PATH_SRC)/db/%.c + $(COMPILE_OBJ) +$(DEF_PATH_DST)/%.inc: $(SRC_PATH_SRC)/db/%.c + $(CREATE_DEF) +$(OBJ_PATH_DST)/%.o: $(SRC_PATH_SRC)/db/mysql/%.c + $(COMPILE_OBJ) +$(DEF_PATH_DST)/%.inc: $(SRC_PATH_SRC)/db/mysql/%.c + $(CREATE_DEF) +$(OBJ_PATH_DST)/%.o: $(SRC_PATH_SRC)/db/null/%.c + $(COMPILE_OBJ) +$(DEF_PATH_DST)/%.inc: $(SRC_PATH_SRC)/db/null/%.c + $(CREATE_DEF) +$(OBJ_PATH_DST)/%.o: $(SRC_PATH_SRC)/db/memdb/%.c + $(COMPILE_OBJ) +$(DEF_PATH_DST)/%.inc: $(SRC_PATH_SRC)/db/memdb/%.c + $(CREATE_DEF) +$(OBJ_PATH_DST)/%.o: $(SRC_PATH_SRC)/db/zdb/%.c + $(COMPILE_OBJ) +$(DEF_PATH_DST)/%.inc: $(SRC_PATH_SRC)/db/zdb/%.c + $(CREATE_DEF) + +# code +$(OBJ_PATH_DST)/%.o: $(SRC_PATH_SRC)/code/%.c + $(COMPILE_OBJ) +$(DEF_PATH_DST)/%.inc: $(SRC_PATH_SRC)/code/%.c + $(CREATE_DEF) + +# master +$(OBJ_PATH_DST)/%.o: $(SRC_PATH_SRC)/master/%.c + $(COMPILE_OBJ) +$(DEF_PATH_DST)/%.inc: $(SRC_PATH_SRC)/master/%.c + $(CREATE_DEF) +$(OBJ_PATH_DST)/%.o: $(SRC_PATH_SRC)/master/framework/%.c + $(COMPILE_OBJ) +$(DEF_PATH_DST)/%.inc: $(SRC_PATH_SRC)/master/framework/%.c + $(CREATE_DEF) +$(OBJ_PATH_DST)/%.o: $(SRC_PATH_SRC)/master/framework/trigger/%.c + $(COMPILE_OBJ) +$(DEF_PATH_DST)/%.inc: $(SRC_PATH_SRC)/master/framework/trigger/%.c + $(CREATE_DEF) +$(OBJ_PATH_DST)/%.o: $(SRC_PATH_SRC)/master/template/%.c + $(COMPILE_OBJ) +$(DEF_PATH_DST)/%.inc: $(SRC_PATH_SRC)/master/template/%.c + $(CREATE_DEF) + +# proctl +$(OBJ_PATH_DST)/%.o: $(SRC_PATH_SRC)/proctl/%.c + $(COMPILE_OBJ) +$(DEF_PATH_DST)/%.inc: $(SRC_PATH_SRC)/proctl/%.c + $(CREATE_DEF) + +# xml +$(OBJ_PATH_DST)/%.o: $(SRC_PATH_SRC)/xml/%.c + $(COMPILE_OBJ) +$(DEF_PATH_DST)/%.inc: $(SRC_PATH_SRC)/xml/%.c + $(CREATE_DEF) + +# json +$(OBJ_PATH_DST)/%.o: $(SRC_PATH_SRC)/json/%.c + $(COMPILE_OBJ) +$(DEF_PATH_DST)/%.inc: $(SRC_PATH_SRC)/json/%.c + $(CREATE_DEF) + +# unit_test +$(OBJ_PATH_DST)/%.o: $(SRC_PATH_SRC)/unit_test/%.c + $(COMPILE_OBJ) +$(DEF_PATH_DST)/%.inc: $(SRC_PATH_SRC)/unit_test/%.c + $(CREATE_DEF) + +# experiment +#$(OBJ_PATH_DST)/%.o: $(SRC_PATH_SRC)/experiment/%.c +# $(COMPILE_OBJ) +#$(DEF_PATH_DST)/%.inc: $(SRC_PATH_SRC)/experiment/%.c +# $(CREATE_DEF) + +clean_lib: + rm -f $(LIB_PATH_DST)/$(LIB_NAME) + rm -f $(LIB_PATH_DST)/lib_acl.so + rm -f $(OBJS_DST) + rm -f $(OBJS_DEF) + rm -f include/$(LIB_GCH) + +########################################################### + +MASTER = acl_master +MASTER_OBJ_PATH = $(OUT_PATH)/master + +MASTERD_SRC = $(wildcard $(SRC_PATH_SRC)/master/daemon/*.c) +MASTERD_OBJ = $(patsubst %.c, $(MASTER_OBJ_PATH)/%.o, $(notdir $(MASTERD_SRC))) + +# master +acl_master: static $(MASTERD_OBJ) + @echo '' + @echo 'creating acl_master' + @if test -n "$(rpath)"; then \ + $(CC) -o $(MASTER_OBJ_PATH)/$(MASTER) $(MASTERD_OBJ) \ + $(LIB_PATH_DST)/$(LIB_NAME) $(SYSLIB) -Wl,-rpath,$(rpath); \ + else \ + $(CC) -o $(MASTER_OBJ_PATH)/$(MASTER) $(MASTERD_OBJ) \ + $(LIB_PATH_DST)/$(LIB_NAME) $(SYSLIB); \ + fi + @echo 'create acl_master ok!' + +$(MASTER_OBJ_PATH)/%.o: $(SRC_PATH_SRC)/master/daemon/%.c + $(COMPILE_OBJ) + +clean_master: + rm -f $(MASTERD_OBJ) + rm -f $(MASTER_OBJ_PATH)/acl_master + +########################################################### diff --git a/lib_acl/Readme.txt b/lib_acl/Readme.txt new file mode 100644 index 000000000..02fd28db7 --- /dev/null +++ b/lib_acl/Readme.txt @@ -0,0 +1,24 @@ +======================================================================== + STATIC LIBRARY : acl_lib +======================================================================== + + +AppWizard has created this acl_lib library for you. + +This file contains a summary of what you will find in each of the files that +make up your acl_lib application. + +///////////////////////////////////////////////////////////////////////////// + +StdAfx.h, StdAfx.cpp + These files are used to build a precompiled header (PCH) file + named acl_lib.pch and a precompiled types file named StdAfx.obj. + +///////////////////////////////////////////////////////////////////////////// +Other notes: + +AppWizard uses "TODO:" to indicate parts of the source code you +should add to or customize. + + +///////////////////////////////////////////////////////////////////////////// diff --git a/lib_acl/StdAfx.h b/lib_acl/StdAfx.h new file mode 100644 index 000000000..45ef769f5 --- /dev/null +++ b/lib_acl/StdAfx.h @@ -0,0 +1,66 @@ +#ifndef __STD_AFX_INCLUDE_H__ +#define __STD_AFX_INCLUDE_H__ + +#ifdef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#include +#include /* DBL_MAX_10_EXP */ +#include +#include /* CHAR_BIT */ + +# ifdef ACL_MS_WINDOWS +# include +# include +# include +# ifdef __STDC_WANT_SECURE_LIB__ +int acl_secure_snprintf(char *buf, size_t size, const char *fmt, ...); +int acl_secure_vsnprintf(char *buf, size_t size, const char *fmt, va_list ap); +# define snprintf acl_secure_snprintf +# define vsnprintf acl_secure_vsnprintf +# else +# define snprintf _snprintf +# define vsnprintf _vsnprintf +# endif +# endif /* ACL_MS_WINDOWS */ + +#include "stdlib/acl_define.h" + +# ifdef ACL_UNIX +# ifndef __USE_XOPEN2K +# define __USE_XOPEN2K +# endif +# ifndef _GNU_SOURCE +# define _GNU_SOURCE +# endif + +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# ifdef ACL_FREEBSD +# include +# include +# endif +# endif /* ACL_UNIX */ + +# include "lib_acl.h" + +#endif /* ACL_PREPARE_COMPILE */ + +#endif + diff --git a/lib_acl/changes.txt b/lib_acl/changes.txt new file mode 100644 index 000000000..2924184ea --- /dev/null +++ b/lib_acl/changes.txt @@ -0,0 +1,2597 @@ + +380) 2013.8.14 +380.1) event: events_select/events_poll/events_kernel/events_iocp 使事件引擎 +的时钟更为精确 + +379) 2013.8.7 +379.1) bugfix: 在 iocp 方式下不能通过 getpeername/getsockname 获得 +远程/本地的地址,通过在 acl_vstream_accept_ex 中添加 setsockopt 调用, +将监听套接字中的一些属性拷贝至客户端连接中解决了此类问题 + +378) 2013.7.23 +378.1) feature: acl_aio_server.c, aio_accept_timer 添加了一个配置参数: +aio_accept_timer,当该值 > 0 时,内部便启动一个定时器,定时尝试接收客户 +端连接,从而达到提升连接事件优先的目的 + +377) 2013.7.18 +377.1) performance: event/event_kernel_thr.c, 优化多线程方式下事件引擎的 +运行速度;acl_master 框架中,当事件引擎选用 kernel 方式时,不需要打开 +ioctl_enable_dog 选项 +377.2) compile: linux32 gcc4 当打开编译选项 strict-aliasing rules 时, +acl_sane_socket.c 中的声明的 SOCK_ADDR 类型被转换别的类型时会报警告 + +376) 2013.7.15 +376.1) lib_acl: 去掉了 svr 模块,该模块的功能完全由 thread/ 下的线程池模块 +(acl_pthread_pool_xxx) 代替;同时修改了 ioctl/ 模块中对于 svn 模块的依赖, +替换为 threead/ 下的线程池模块 + +375) 2013.7.11 +375.1) feature: acl_sane_socket.c, 增加了 acl_getsocktype 函数,可以获得当前 +socket 句柄类型是 TCP 套接口还是 UNIX 域套接口; +acl_getsockname/acl_getpeername 支持 UNIX 域套接口 +375.2) feature: acl_sane_accept.c, 增加了 acl_accept 函数,比较方便地接收客户 +端连接,同时兼容 TCP 套接口及 UNIX 域套接口 +375.3) master/template: 进一步完善了 acl_aio_server.c, acl_ioctl_server.c, +acl_single_server.c acl_multi_server.c, 内部统一改为 acl_accept 方式 + +374) 2013.7.7 +374.1) bugfix: acl_vstream.h, 因为 ACL_VSTREAM 流对象中的写缓冲 wbuf 采取了 +写时分配的策略,所以会造成宏 ACL_VSTREAM_PUTC 的空指针问题,现在增加了判断 +以预分配 wbuf 空间 +374.2) master 服务器框架:因为支持同一进程同时监听多个地址且允许 TCP 与 UNIX +域套接口混用,所以目前各个服务器模板针对此种情况,均默认调用 UNIX 域套接口的 +accept 过程 + +373) 2013.6.25 +373.1) compile: 消除了在 gcc-4.6.3 下的一些编译警告 + +372) 2013.6.21 +372.1) feature: acl_master 框架支持在一个配置文件中监听多个地址(可以为 TCP +套接口与域套接口混用) + +371) 2013.6.21 +371.1) feature: acl_master 框架支持在 reload 时的 prefork,修改的相关文件有: +master_avail.c, master_service.c, master_spawn.c, master.h +371.2) acl_master_log.c: 将日志输出信息当调试状态对待 + +370) 2013.6.15 +370.1) bugfix: acl_array.c->acl_array_prepend,其中调用的 acl_array_succ_insert, +应该调用 acl_array_pred_insert,该 BUG 会影响到所有调用 acl_dlink, acl_iplink, +acl_access 函数的地方,包括 acl_aio_app_main.c/acl_ioctl_app_main.c 中有关访问 +权限的地方 +370.2) 将 acl_iplink.c 中的函数调用映射为直接调用 acl_dlink.c 中的方法 +370.3) samples/iplink: 该例子用于测试 acl_iplink.c 中的相关函数 + +369) 2013.6.4 +369.1) bugfix: acl_mylog.c->reopen_log 函数中的 RETURN 宏定义中应该是 +thread_mutex_unlock,原来的 thread_mutex_lock 会造成死锁 + +368) 2013.5.27 +368.1) bugfix: acl_json_parse.c: 有些汉字,如“誠”的后半个字节的值正好与转义字符 +相同,即为 92,所以需要兼容此情况,当判断 last_ch < 0 且当前 char 为 92 时,则认为 +汉字情况; acl_xml_parse.c 也存在类似问题,已修复 + +367) 2013.5.23 +367.1) acl_json.c/acl_xml.c: 当启用结点对象缓存策略时,acl_json_node_reset 和 +acl_xml_node_reset 中调用 ACL_VSTRING_RESET 后还应该调用 ACL_VSTRING_TERMINATE + +366) 2013.5.20 +366.1) bugfix: acl_basename.c -> acl_safe_basename 在 3 月份修改的有误 + +365) 2013.5.13 +365.1) acl_ioctl_server.c: 在主函数 acl_ioctl_server_main 中,需要将 acl_ioctl_start +放在 proc_init 之前,以便于应用在 proc_init 回调过程中设置一次性定时器 + +364) 2013.3.26 +364.1) bugfix: acl_xml_parse.c->xml_parse_attr_val() 函数中当 +if (ch == attr->quote) 时应该添加 xml->curr_node->last_ch = ch; + +363) 2013.3.24 +363.1) bugfix: acl_vstream_net.c->acl_vstream_listen_ex() 中针对域套接口地址 +时没有对 local_addr 赋值 + +362) 2013.2.26 +362.1) bugfix: acl_dns.c, acl_dns_serror() 函数中返回字符串描述信息时查询方式有误 +362.2) bugfix: acl_dns.c, acl_dns_lookup() 函数中创建 ACL_DNS_REQ 对象时,部分变量 +未清零 + +361) 2013.2.5 +361.1) bugfix: acl_scan_dir.c, acl_scan_dir_open() 原来采用 acl_mymalloc +分配内存导致一些变量未初始化,现改成 acl_mycalloc + +360) 2013.1.29 +360.1) bugfix: acl_vbuf_print.c, 新改的代码中没有处理格式为 %* 的情形 + +359) 2013.1.26 +359) performance: acl_vbuf_print.c 中的 fmt 内存由原来的动态分配改为固定的堆栈 +内存,使之性能提高大约 80% 左右,由此提升了依赖于该函数的 ACL_VSTRING 中的格式 +串操作的性能;fmt 的内存固定为 128 字节,理论上足够支持现在的机器指令长度,其中 +对于 %{xxx}d 的操作中,{xxx} 为数字,如 123,因为不可能有超过 128 个字节长度的 +数字,所以此固定尺寸的方式是安全有效的,如果用户在使用过程中用到了超过 128 个字 +节长度的数据,则内部会 fatal 以提醒用户有非法操作 + +358) 2013.1.22 +358.1) bugfix: acl_single_server.c 的 single_server_wakeup 函数中没有将网络流的 +远程与本地地址赋予流对象 + +357) 2012.12.31 +357.1) feature: acl_ioctl_app_main.c, 增加了两个回调函数指针: +__app_on_timeout/__app_on_close,这样当套接口连接读超时或关闭时会分别调用 +此两个函数 + +356) 2012.12.30 +356.1) feature: acl_file.h, 增加了几个通用的函数 + +356) 2012.12.28 +356.1) compile: Makefile 的编译开关增加了 -pedantic 选项,挑出几个隐藏的 BUG + +355) 2012.12.27 +355.1) performance: ACL_VSTREAM 结构优化了个别参数,使该结构的尺寸由原来的 9K +多变为现在的只有 800 个字节,即采用了写时分配内存的策略 + +354) 2012.12.3 +354.1) bugfix: acl_events: event_limit() 函数在调用 acl_open_limit() 时传入了 +一个默认的值,导致进程打开的文件句柄数无法扩大。 +354.2) feature: acl_ioctl_server.c/acl_aio_server.c: 当客户端连接数超过系统限制时, +原来的做法是程序退出,现在改为让程序暂时监听,通过定时器再重启监听过程 + +353) 2012.10.12 +353.1) feature: xml/, +增加了三个函数接口:acl_xml_getElementMeta/acl_xml_getEncoding/acl_xml_getType, +用于取得 xml 起始控制字段的相关信息 + +352) 2012.9.29 +352.1) 为了兼容 MAC OS 以及关于线程局部变量在动态库的限制因素,将库中 +带有 __thread 关键字标识的局部变量统一改为通过 acl_pthread_getspecific +等函数获得 + +351) 2012.9.25 +351.1) 在 MAC OS 编译通过,并测试了大部分示例 +351.2) 去掉了 code/ 目录下一些与字符集转换相关的代码 + +350) 2012.8.26 +350.1) feature: ACL_VSTREAM::flag 增加了一个标志位:ACL_VSTREAM_FLAG_PREREAD, +当调用 acl_vstream_can_read 时会判断此标志位,如果设置了此标志位,则当系统提示 +有数据可读时,该函数会预读网络数据 + +349) 2012.8.25 +349.1) bugfix: acl_vstream.c 中将 stream->sys_read_ready = 0; 代码放在 +__vstream_sys_read 函数内,这样可以保证阻塞读与非阻塞读的数据一致性 + +348) 2012.8.1 +348.1) 将所有的定时器接口进行修改,使之更灵活 +原来的定时器有一个自动重启的功能,但这个重启定时器功能被绑定在异步事件框架 +引擎上(这样只有当异步引擎设置了定时器重启功能,所有的定时器才会开户重启机制, +这样做不够灵活),现在将自动重启功能绑定在每个定时器本身上 +影响到的文件有: +a) event: acl_events.c, acl_events.h, events_select.c, events_pool.c, +events_kernel.c, events_kernel2.c, events_kernel3.c, events_iocp.c, +events_wmsg.c, events_timer.c, events_alloc.c, events.c, events_select_thr.c, +events_poll_thr.c, events_kernel_thr.c, events_timer_thr.c +b) aio: acl_aio.c, acl_aio.h +c) master: master_spawn.c, master_wakeup.c, acl_single_server.c, acl_multi_server.c, +d) acl_trigger_server.c, acl_listener_server.c, unix_trigger.c +e) ioctl: acl_ioctl.c, acl_ioctl.h + +347) 2012.7.27 +347.1) acl_aio_read.c: acl_aio_enable_read() 函数中增加了递归层次限制; +can_read_callback() 中增加了 READ_SAFE_DISABLE 宏控制 + +346) 2012.7.25 +346.1) acl_xml_util.c: 增加了对 '<' 和 '>' 的转义支持 +346.2) acl_json_util.c: 增加了对 '{', '}', '[', ']' 的转义支持 + +345) 2012.7.23 +345.1) bugfix: acl_xml_parse.c,当属性值含有转义符 '\' 时,解析不能正常进行,在 +ACL_XML_ATTR 中增加成员 backslash 解决此类问题 +345.2) bugfix: acl_xml_util.c/acl_json_util.c 在创建对象时,也没有处理含有转义符 '\' 的情况 + +344) 2012.7.10 +344.1) compile: 将 snprintf 在 WIN32 的实现做为内部函数使用 + +343) 2012.7.2 +343.1) bugfix: acl_aio_stream.c->close_astream() 中并没有释放在 acl_aio_open +中创建的四个数组对象 +343.2) feature: acl_aio.h, 添加了两个宏 ACL_AIO_SET_TIMEOUT/ACL_AIO_SET_CTX, +可以快速地设置异步流的超时/上下文参数 + +342) 2012.6.6 +342.1) compile: event_epoll.h 添加了 #include 避免编译问题 +--liuhui (liuhui331234958@gmail.com) + +341) 2012.6.4 +341.1) bugfix: acl_ifconf.c 在 win32 下 acl_free_ifaddrs() 函数中有一处隐含的错误 +341.2) feature: acl_env.c 增加了 acl_getenv3()/3 该函数在 win32 下要比 acl_getenv 更安全 +341.3) compile: 在 AS6/CS6 上编译通过 + +340) 2012.5.26 +340.1) bugfix: net/connect/acl_stream_connect.c: acl_stream_connect()/3 仅能支持 +SUNOS5,所以在LINUX下需要将其注释,影响的程序:master/framework/trigger/stream_trigger.c + +340) 2012.5.10 +340.1) bugfix: acl_aio_app_main.c/acl_ioctl_app_main.c 中在调用 +acl_access_permit 时传的是 IP:PORT格式,应该是 IP + +339) 2012.4.17 +339.1) feature: json/, 添加了由 json 对象树构建成字符串的函数接口 + +338) 2012.4.15 +338.1) feature: xml/, 添加了由 xml 对象树构建成字符串的函数接口 +338.2) samples: samples/xml/, 增加了构建 xml 字符串的测试例子: build_xml2() + +337) 2012.4.9 +337.1) bugfix: 修复了许多变参类型不匹配的情况 + +336) 2012.4.5 --- 2.1.2.8 release +336.1) bugfix: events.h 中的宏 SET_TIME 原来的定义为: +#define SET_TIME(x) { \ + struct timeval _tv; \ + gettimeofday(&_tv, NULL); \ + (x) = ((unsigned long) _tv.tv_sec) * 1000000 + ((unsigned long) _tv.tv_usec); +\ +} + +应该改为: +#define SET_TIME(x) { \ + struct timeval _tv; \ + gettimeofday(&_tv, NULL); \ + (x) = ((acl_int64) _tv.tv_sec) * 1000000 + ((acl_int64) _tv.tv_usec); +\ +} +因为在32位机上 unsigned long 也是32位的,所以计算出的 x 值可能已经越界了,这样会 +导致使用该宏的事件引擎中的定时器出现死循环问题 + +335) 2012.4.1 +335.1) bugfix: acl_mem_slice.c 中在 mem_slice_free 调用 +thread_mutex_lock(__mem_slice_list_lock) 时可能是 __mem_slice_list_lock +已经在 free_global_ctx 中被释放了 + +334) 2012.3.31 +334.1) lib_acl/src/master/framework: 多处有未将全局变量未赋初始值的情况,其会 +导致在 AS4/CS4 上出错 +334.2) bugfix: acl_mylog.c->acl_close_log() 内部在释放线程锁时重复释放了线程锁变量 +log->lock 的内存,在调用 thread_mutex_destroy 时已经将该内存自动释放掉了 +334.3) acl_single_server.c: 调整了日志打开的顺序 + +333) 2012.3.27 +333.1) bugfix: acl_mem_slice.c 有一处内存泄露问题,虽然这种问题只是一次性 +的 +333.2) private_thread_mutex.c: 添加了一个 thread_mutex_desotry 函数 + +332) 2012.3.26 +332.1) acl_json.c: 少一个 acl_json_alloc() 函数 + +331) 2012.3.24 +331.1) acl_master: prefork 模式改进,原来是当有连接到达时才会预告 fork +指定的服务进程数,现在改为启动时直接预告启动指定的服务进程数 + +330) 2012.3.17 +330.1) feature: acl_master 服务器模板支持 prefork 模式, 只需要将配置文件 +中的 master_prefork 设置成 > 0 的值即启用了 prefork 模式 +330.2) feature: acl_read_wait/acl_write_wait 支持在 UNIX 下采用 poll 方式 +来判断读写超时,这相对于 select 的优点是描述字可以很容易超过 1024 限制 + +329) 2012.3.14 +329.1) bugfix: 去掉了 acl_ioctl_app_main.c 中的app_client_idle_limit 配置 +选项,使用 acl_ioctl_server.c 中的 ioctl_rw_timeout 配置选项来表明客户端 +连接的读超时和空闲超时时间,避免了当客户端连接连上后的超时时间的不一致问 + +328) 2012.3.7 +328.1) compile: 在编译动态库时可以指定链接路径,用法如下: +make shared rpath=xxx; 仅编译动态库 +或 make rpath=xxx; 同时编译动态库及静态库存 + +327) 2012.2.12 +327.1) performance: acl_json.c, acl_fifo.c, acl_argv.c 通过传入内存池对象 +优化内存分配过程 + +326) 2012.2.11 +326.1) performance: acl_xml.c, 通过内存池方式优化了内存分配与释放过程 +326.2) performance: acl_htable.c, 不再使哈希表对象自身创建内存池对象,改为 +由参数接口传入内存池对象 + +325) 2012.2.6 +325.1) performance: aio/, 优化了非阻塞的读/写过程 + +324) 2012.1.10 +324.1) feature: acl_aio_app_main.c 增加了进程切换身份之前调用的回调函数 + +323) 2012.1.8 +323.1) feature: acl_ioctl_app_main.c 增加了进程切换身份之前调用的回调函数 + +322) 2011.11.28 +322.1) acl_pthread_mutex.c: 其中分配内存的操作用 acl_mymalloc 替换了原来的 +acl_dbuf_pool_alloc 函数,这样可以避免内存在短时间内的堆积问题 + +321) 2011.11.26 +321.1) acl_fhandle.c: 完善了内部一些调用,使之可以在打开文件句柄对象时自动加锁, +这对于 gid_server 非常有用 +321.2) acl_htable.c: 增加了标志位 ACL_HTABLE_FLAG_KEY_LOWER 作为创建哈希表的 +标志之一,如果设置了此标记,则内部自动将键值转为小写,这样便可以实现对键值进行 +增、删、查时不区分键值大小写的功能 + +320) 2011.11.19 +320.1) bugfix: acl_json.c, json 结果集的结点遍历问题修复 +320.2) feature: acl_json_util.c, acl_json_getElementsByTags 查询标签支持模糊方式 +320.3) feature: acl_xml_util.c, acl_xml_getElementsByTags 查询标签支持模糊方式 + +319) 2011.10.23 +319.1) json/: 增加了针对 json 数据格式的流式解析库,以此纪念C语言发明者丹尼斯, +C 语言是如此强大,可以让我们随心所欲地做任何事情。 + +318) 2011.10.8 +318) acl_msg.c: 将未打开日志却调用日志记录的函数时,原来的默认操作是直接输出至 +标准输出上,现在增加了开关设置,且默认操作针对此种情况不做任何操作 + +317) 2011.10.1 +317.1) stdlib/ 目录下的 acl_vstring.h, acl_vbuf.h, acl_vbuf_print.h +头文件定义中的宏定义与 Postfix 的冲突 + +316) 2011.9.12 +316.1) acl_pthread_t 重新定义为 unsigned long 类型 +316.2) acl_mem_slice.c: 针对主线程,增加了内存池释放的机制 + +315) 2011.9.5 +315.1) feature: acl_htmlcode.c 支持 &#xxx; 方式的解码 + +314) 2011.7.19 +314.1) feature: acl_xml.c 增加了 acl_xml_add_tag 允许用户添加自定义的非闭合标签 + +313) 2011.7.18 +313) 增加了 WIN32 平台下的版本资源文件 + +312) 2011.6.29 +312.1) acl_aio_read.c: 对于 acl_aio_gets, acl_aio_gets_nonl, acl_aio_read, +acl_aio_readn 这四个函数,当对于流的读操作是持续读时,如果在用户的回调中取消了 +读监听状态,且当流的用户缓冲区中有数据,当用户再次调用这些读操作时,仅能对这些 +流的用户中的缓冲区数据触发回调,无法继续触发流的系统缓冲区中的数据的回调过程, +所以在这些读操作的开始处针对持续读状态,首先设置流的读监听状态。 + +311) 2011.6.17 +311.1) bugfix: acl_aio_server.c, acl_ioctl_server.c, acl_single_server.c, +acl_multi_server.c, acl_trigger_server.c, 其中的与时间相关的变量都是 int 类型, +为了调用 acl_event_request_timer 等方法时,需要乘 1000000 转成 64 int 整型, +必须在这些变量前加 acl_int64 以提醒编译器在将变量与 1000000 相乘时需要按 64 位 +整型对待 + +310) 2011.6.13 +310.1) bugfix: acl_doze.c, 休眠的时间单位里面实现的并不是毫秒级 + +309) 2011.6.10 +309.1) acl_getopt.c: 因为其中使用了 fprintf,则可能会导致使用 VC2010 编译的工程 +在采用 /MD 方式编译时需要添加如下代码才能通过,现在把其中的 fprintf 改成 printf +后用 VC2010 的工程则就不用添加如下代码了 +#if !defined(VC2003) && !defined(VC6) +extern "C" { FILE _iob[3] = {__iob_func()[0], __iob_func()[1], __iob_func()[2]}; } +#endif + +308) 2011.6.8 +308.1) bugfix: acl_vstream.c, acl_vstream_readn_peek 有问题,已经修复,否则将会 +影响 acl_aio_read.c 中的 acl_aio_readn 函数 + +307) 2011.5.31 +307.1) feature: events/, aio/ 支持定时器任务可以被循环使用,用户只需要调用 +acl_event_keep_timer 即可保证在 acl_event_request_timer 中设置的定时器可以被循环 +使用,默认情况下定时器是只能使用次的 + +306) 2011.5.24 +306.1) bugfix: acl_xml_util.c, acl_xml_getElementsByTags() 中调用 +acl_xml_getElementsByTagName() 创建的动态数组没有被释放 +306.2) bugfix: acl_xml.c, xml_iter_next/xml_iter_prev 遍历函数中在 do-while 循环中 +判断结束的条件是 parent == NULL,该判断条件仅对由 acl_xml_alloc() 创建的 XML 对象 +有效,对于 acl_xml_foreach_init() 使用的 XML 对象无效,所以现在修改一下,在循环开始 +判断 parent == xml->root,以此判断是否该退出循环 + +305) 2011.5.19 +305.1) bugfix: 2011.5.18 对 acl_vstream.c 的修改虽然会使 iocp 引擎工作正常,但 +却会使 win32 消息引擎出现问题,所以恢复 acl_vstream.c 之前的状态,同时为了避免 +iocp 引擎的问题,在 iocp 引擎内部的 stream_on_close 函数中提前对套接口关闭 + +304) 2011.5.18 +304.1) bugfix: acl_vstream.c,修改了 acl_vstream_close() 中关闭套接口连接的 +顺序,因为在使用 iocp 作为事件引擎时,当流关闭时会调用 events_iocp.c 中的 +stream_on_close,该函数会释放掉 fdp->event_read t fdp->event_write 两个对象, +但当套接口未关闭时,这两个对象有可能会被 iocp 使用时,只有当套接口关闭时, +iocp 才不会使用这两个对象中的 IOCP_EVENT->overlapped 等成员 +304.2) feature: acl_aio_connect.c,当事件引擎为 win32 消息时支持连接超时功能键 + +303) 2011.5.17 +303.1) bugfix: 将定时器的精度改成微秒级后,在 events/ 下的事件引擎会因为 +向下取整问题而导致循环过快 + +302) 2011.5.16 +302.1) feature: 将所有与定时器相关的功能函数中的时间精度由秒级改为微秒级 + +301) 2011.5.13 +301.1) compile: 将 StdAfx.h 从 include/ 目录移到 lib_acl/ 目录 + +300) 2011.5.10 +300.1) feature: acl_pthread.c, acl_pthread_tls_get() 可以保证在主线程退出时 +释放主线程的局部变量,从而 valgrind 检查不会出错 +300.2) feature: acl_init.c, 增加了 acl_main_thread_self() 可以用来在子线程中 +获得主线程的线程号 +300.3) bugfix: acl_pthread_mutex.c 中 acl_thread_mutex_init_once() 在创建 +__header_key 和 __pool_key 时有错,再将此二参数地址传入 acl_pthread_key_create() +后再将 acl_pthread_key_create() 返回值给此二参数赋值 + +299) 2011.5.9 +299.1) bugfix: acl_ioctl_server.c, 需要给接收到的客户端流赋远程地址及本地地址 + +298) 2011.5.8 +298.1) feature: acl_xml.c, 增加了 acl_xml_foreach_init, 该函数可以将某个结点 +做为一个新的 xml 树的根结点进行遍历 + +297) 2011.5.7 +297.1) feature: acl_xml.c, 增加了 acl_xml_getElementsByTags, 该函数可以取出 +符合多级标签名的 xml 结点集合 + +296) 2011.5.6 +296.1) bugfix: events_wmsg.c, 在销毁事件引擎对象时需要关闭套接字所依赖的窗口, +应该调用 DestroyWindow(), 而不是 CloseWindow() + +295) 2011.4.28 +295.1) bugfix: 除 UNIX/LINUX 下的 select 和 iocp 系统调用外,其它的调用如: +select(win32), epoll, kqueue, devpoll, WSAAsyncSelect, 它们都可能存在一个 +问题:即使 socket 的系统缓冲区依然有数据,如果操作系统检测到连接关闭,有可 +能先发送关闭的事件通知,所以 acl 的事件通知机制及异步IO部分做了一致调整, +即保证读事件优先,或socket的系统缓冲区中有数据时,也是优先将数据读出,最后 +所有数据都读完后才处理关闭事件,并关闭socket. +影响的文件: +acl_vstream.c: acl_vstream_xxx_peek +acl_aio_read.c: __xxx_notify_callback + +294) 2011.4.22 +294.1) bugfix: acl_aio_read.c, acl_aio_readn() 应该调用 __readn_peek 而 +不是 __read_peek,并且在 __read_peek 中当 acl_vstream_read_peek 返回 0 +时不应该 fatal + +293) 2011.4.20--21 +293.1) feature: acl_xml_code.c, acl_html_code.c, 增加了对 XML 和 HTML +中特殊字符的转码与解码功能 + +392) 2011.4.19 +392.1) bugfix: acl_xml.c, acl_xml_reset() 函数中应该把 xml->curr_node +结点置 NULL,否则会导致内存错误 +392.2) feature: acl_xml_parse.c, 可以兼容单个结点中用 ">" 表示结束而非 +"/>" 结束的情况 +392.3) feature: acl_xml_util.c, 增加了 acl_xml_dump2 用来将 xml 对象转 +储于指定缓冲区中 + +391) 2011.4.18 +391.1) feature: acl_vbuf_print.c, 支持 %zu, %zd 功能 + +390) 2011.4.17 +390.1) acl_mem_slice.c: 将线程局部变量由 acl_pthread_tls_get/set +改为 acl_pthread_get{set}specific,以免应用采用 acl_pthread_tls_xxx +且同时使用线程局部内存池时产生冲突 + +389) 2011.4.12 +389.1) performance: acl_xml.c, 增加了 acl_xml_reset, acl_xml_cache +两个函数,从而可以使 xml 解析器被重复使用,并且大大提高了解析性能 + +388) 2011.4.11 +388.1) Makefile: 当每个源程序所依赖的头文件发生改变时,该 Makefile +会自动进行编译该源文件 +388.2) Makefile: 默认将 mysql 库编译进库中 + +387) 2011.4.8 +387) 修复了几个在高版本GCC上的编译错误 + +386) 2011.3.28 +386.1) acl_aio_read.c: 优化了异步读的代码 +386.2) acl_aio_stream.c: 增加了是否是连续读的功能函数 + +385) 2011.3.25 +385.1) 在 win32 平台下用 VC 编译 release 版本时 assert 会被优化掉, +所以统一将 assert 修改成 acl_assert +385.2) 提供了 acl_aio_create2 接口,允许当采用 ACL_EVENT_WMSG 消息 +异步 IO 时可以指定要绑定的消息值 +385.3) acl_aio_read.c: 当采用 ACL_EVENT_WMSG 时,可能会因为缓冲区有 +数据,而嵌套层数达到限制时,会导致数据无法返回给应用,增加了循环探测 +的功能,将缓冲区中的数据都返回给应用 + +384) 2011.3.19 +384.1) acl_aio_listen.c: 在 acl_aio_listen/acl_aio_accept 中需要设置 +astream->flag |= ACL_AIO_FLAG_ISRD,否则 acl_aio_disable_read 对监听 +流不起作用 + +383) 2011.3.18 +383.1) feature: events_wmsg.c 通过 SetWindowLongPtr/GetWindowLongPtr +两个 API 与给窗口句柄赋私有值及获得私有值,替代了原来的线程局部变量 +的存取方式 + +382) 2011.3.16 +382.1) bugfix: events_select_thr.c 中的流 IO 超时不起作用 + +381) 2011.3.13 +381.1) bugfix: event 针对 WIN32 界面的定时器存在可能耗费CPU的逻辑 +381.2) aio: 对 WIN32 界面的定时器可以采用 event 中的定时器 + +380) 2011.3.12 +381) feature: event/aio 两模块增加了WIN32界面的消息的支持,至此,ACL库 +的异步事件引擎及异步IO框架支持: select, pool, epoll, kqueue, devpoll, +iocp, WIN32 GUI 消息。 +382) feature: event/aio 两模块增加了WIN32界面的定时器支持 + +379) 2011.3.8 +379.1) bugfix: events_kernel.c, events_iocp.c: 在调用 event_disable_xxx +时,需要处理未决状态,如在调用 event_disable_read 时,不仅需要判断 flag +标志位是否设置了 EVENT_FDTABLE_FLAG_WRITE, 还需要判断 flag 是否设置了标志 +EVENT_FDTABLE_FLAG_ADD_WRITE, 以防止当流处于读/写状态时被提前拆除 +380.1) private_vstream.c: 函数名定义与POSTFIX中的冲突,都加了前缀 + +378) 2011.3.1 +378.1) acl_aio_write.c: acl_aio_vfprintf(), 内部调用 acl_vstring_memcpy(), +该函数会导致 valgrind 报错说是内存重叠,所以修改为 acl_vstring_memmove() + +377) 2011.2.26-27 +377.1) acl_aio: 增强了容错性及键壮性 + +376) 2011.2.23 +376.1) feature: acl_ioctl_app_main.c, 增加了当新连接到达时可以预先调用用户 +回调函数的功能 + +375) 2011.2.17 +375.1) feature: acl_mylog.c, 对网络流 (TCP, UNIX) 日志发送器,如果网络出现 +故障,允许重新打开网络流日志 + +374) 2011.2.16 +374.1) bugfix: acl_mylog.c, 当多线程记日志时,因为网络流模式下没有加锁可能 +会造成冲突问题 + +373) 2011.2.15 +373.1) bugfix: acl_mylog.c, 有可能会造成函数循环嵌套调用的情况. +373.2) acl_aio_server.c: 增加了控制参数 aio_quick_abort, 如果该值在 +配置文件中非 0,则当 acl_master 退出时该 aio 程序立刻退出,默认情况下 +该值非 0 +373.3) acl_ioctl_server.c: 将 ioctl_quick_abort 的默认配置值设为 1 + +372) 2011.2.14 +372.1) bugfix: acl_mylog.c, 需要将日志中的前缀与后面字符串用空格分开才能 +支持 syslog-ng 的 $PROGRAM 宏 + +371) 2011.2.9 +371.1) feature: acl_mylog.c, 支持与 syslog-ng 配合记录日志格式 + +370) 2011.1.27 +370.1) bugfix: acl_vstring.c, acl_buffer_gets/acl_buffer_gets_nonl 当 +最后的数据没有包含 \n 时没有将填充的数据补 \0 + +369) 2011.1.26 +369.1) acl_mylog.c: 可以允许用户设置是否在日志中记录线程ID号,默认情况下 +不记录 + +368) 2011.1.25 +368.1) acl_mylog.c: 去掉了日志中 pri(表示权重) 的记录项 + +367) 2011.1.24 +367.1) feature: 增加了 acl_trace.c 用于打印程序运行堆栈信息至目标文件中 +367.2) feature: acl_master 可以允许子进程被切换为普通用户后产生 core 文件, +相应地,五个acl_master的服务器模板增加了 bool 类型的配置选项如下: +ioctl_enable_core/aio_enable_core/trigger_enable_core/single_enable_core +/multi_enable_core +367.3) bugfix: acl_dbpool_mysql.c, 当连接失败时有内存泄露问题 + +366) 2011.1.21 +366.1) acl_init.c: 增加了 acl_version/1 用于说明当前ACL的版本号 +366.2) bugfix: acl_dbpool_mysql.c, 新添加的功能函数db_before_connect处理 +有问题 + +365) 2011.1.18 +365.1) samples: master_notify, 该模块用于接收来自于 acl_master 发出的其它 +服务进程异常退出的消息,并将该消息发送至相关责任人 +365.1) master: 增加了子进程异常退出时的消息参数 + +364) 2011.1.10 +364.1) feature: acl_dbpool.h, 增加了真正连接数据库之前的回调函数调用,方便 +用户的一些特殊设置需求 + +363) 2010.12.31 +363.1) bugfix: acl_dbpool_mysql.c, 在调用 __dbpool_mysql_destroy 时需要调用 +mysql_library_end(), 否则会引起内存泄露 +363.2) sample: 增加了 dbpool 用户测试数据库连接池功能 +363.3) feature: db/mysql: 增加了因MYSQL连接中断而查询失败时的重试功能 + +362) 2010.12.28 +362.1) bugfix: 修复了 src/unit_test 下内存泄露的问题 + +361) 2010.12.13 +361.1) acl_xml_parse.c: acl_xml_parse 更名为 acl_xml_update 从而更能体现流式解析 +的特点 +361.2) acl_base64.c: 输入参数类型略加改变 + +360) 2010.12.7 +360.1) feature: acl_vstring.c, 增加了 acl_vstring_memmove()/3 函数 + +359) 2010.11.29 +359.1) feature: 增加了 acl_utf8_to_big5/acl_big5_to_utf8, +acl_utf8_to_unicode/acl_unicode_to_utf8, +acl_gb2312_to_big5/acl_big5_to_gb2312, +acl_hz_to_gb2312/acl_gb2312_to_hz 字符集转换编码 + +358) 2010.11.16 +358.1) bugfix: acl_array.c, acl_stack.c 在使用 acl_foreach() 宏 +时的内部函数有问题, 当数组为空时依然将第一个元素返回 + +357) 2010.11.15 +357.1) feature: ACL_ARGV(acl_argv.c/acl_argv.h), +ACL_ARRAY(acl_array.c/acl_array.h), +ACL_FIFO(acl_fifo.c/acl_fifo.h), +ACL_STACK(acl_stack.c/acl_stack.h) 增加了 push_back/push_front, +pop_back/pop_front 函数接口 +357.2) aio: 重新构建 + +356) 2010.11.2 +356.1) compile: 在WIN32下编译时配置了每个工程的.pdb文件指定 + +355) 2010.10.28 +355.1) bugfix: acl_base64.c, acl_vstring_base64.c, 其中用到的解码表 +为 128 字节的, 但如果数据中的 char 值超过 128 则可能会出现越界问题 +(这种情况在一些base64的非法编码数据中可能会出现), 所以现在将其修改成 +255 字节的解码表 +355.2) compile: StdAfx.h 将 #include 做为通用的系统头 + +354) 2010.9.19 +354.1) bugfix: acl_vstream.c, acl_vstream_gets_nonl() 没有设置 +ACL_VSTREAM_FLAG_TAGYES / ACL_VSTREAM_FLAG_TAGNO 标志位 + +353) 2010.9.16 +353.1) bugfix: acl_debug.c 中增加了 acl_debug_end() 函数用于程序结束时 +释放内部分配的内存 +353.2) acl_mystring.h: 增加了针对 strcasecmp 等函数的补充宏定义 + +352) 2010.8.4 +352.1) compile: 修复了在 AS3, AS4 上的编译错误 + +351) 2010.7.21 +351.1) bugfix: acl_token_tree.c, acl_token_tree_create() 第 485 行 +创建的 argv 内存没有被释放 + +350) 2010.7.11 +350.1) xml: acl_xml_parse.c xml_parse_left_tag() 修改, 以更好地支持 +

方式 + +349) 2010.6.9 +349.1) 支持 gcc 的预编译方式, 使编译速度大约能提升一倍 + +348) 2010.6.8 +348.1) 支持 vc2003 的预编译方式,使编译速度大大提高 + +347) 2010.6.27-7.6 +347.1) feature: 增加了 xml 目录, 用于解析 xml 及 html 文件, 该解析库采 +用"状态机"解析方式, 对输入流进行完整或部分解析, 从而更方便支持阻塞式或 +非阻塞式通讯; 同时该库还提供类似于 javascript 的简单查询函数. +注: 目前该库还存在的已知问题如下: +a) 对 doctype 类型支持不完善 +b) 对 xml 开始时的内容解析需要增加更多功能 + +347.2) bugfix: acl_vstream.c 340 行调用 snprintf 时发现 ebuf 缓冲区未 +被初始化, 幸亏 valgrind 检查出此错误 + +347.3) acl_ring.c: acl_ring_detach 中, 原来会将某个结点的 ring->succ 及 +ring->pred 均赋 NULL, 现在修改为与调用 acl_ring_init 之后一样的行为, 会 +将 ring->succ, ring->pred, ring->parent 赋为自己, 同时将 ring->len 赋 0 + +346) 2010.6.13 +346.1) feature: code/acl_gbcode.c, 增加了 acl_gb2312_to_utf8()/4 及 +acl_utf8_to_gb2312()/4 函数, 用于字符集的转换 + +345) 2010.6.8 +345.1) feature: acl_vstream.c, acl_vstream_unread 会根据输入数据长度自动 +重新分配空间以保证所给数据能够完全被放回流中; acl_vstream_ungetc 通过内部 +调用 acl_vstream_unread 来保证数据肯定能被回写 + +344) 2010.5.6 +344.1) feature: acl_vstream.c, 增加了 acl_vstream_unread 从而可以方便地 +将已经读到的数据再重新放回流中 + +343) 2010.4.17 +343.1) bugfix: events_poll.c/events_select_thr.c/events_poll_thr.c 存在着 +类似于 342.1 所示问题,统一进行了修复 + +342) 2010.4.11 +342.1) bugfix: events_select.c, event_loop() 中当 event_prepare() 返回 0 +且 eventp->fdcnt_ready > 0 时会因为 goto TAG_DONE 语句直接跳至 后面的 for +循环中,但会因 xmask/rmask/wmask 三个变量未被初始化而造成无法预知的问题, +所以在 goto TAG_DONE 语句前增加了四个语句来分别初始 nready/xmask/rmask/wmask, +这种未初始化的问题编译器很难捕获,可能是因为有 goto 语句的缘故,看来 goto +语句确实应该少用为宜:) + +341) 2010.3.31 +341.1) bugfix: events_epoll.h/events_kernel.c, 在 Linux 下,epoll +的 EPOLL_CTL_DEL 使用有误 + +340) 2010.3.24 +340.1) feature: acl_htable.c, 增加 ACL_HTABLE_FLAG_MSLOOK 标志位, +当用户名在通过 acl_htable_create 创建哈希表时打开此标志位,则在 +进行查询时自动将查询到的结果的位置放在热词位置 +340.2) 在 acl_init.c 增加了针对WIN32平台下的 ws2_32.lib 及 +wsock32.lib 的直接引用,从而方便应用,不必在自身工程里再引用这两个库 + +339) 2010.3.6--2010.3.17 +339.1) feature: 在WIN32平台下,event 事件模块支持 iocp 接口方式, +这样 ACL 的事件驱动模块支持 WIN32(vc2003以上)/LINUX/BSD/SOLARIS +四个平台下的内核级高级IO方式 +339.2) samples: 增加了 http_aio 例子 + +338) 2010.3.5 +338.1) bugfix: acl_dbpool_mysql.c->__dbpool_mysql_destroy() 有一处内存 +泄露(增加了acl_array_destroy(mysql_pool->handles, NULL)),此处问题由 +徐刚辉发现 +338.2) acl_dns.c: 当 jaws 服务器调用 mod_http.so 模块,因为是动态加载, +所以导致 dns_lookup_timeout() 函数地址在 jaws 中和 mod_http.so 是不一致 +的,而在 acl_dns.c 中通过函数 acl_aio_cancel_timer() 取消定时器时,便 +无法取消定时器任务,所以把 dns_lookup_timeout() 对象的地址直接赋给 +ACL_DNS.lookup_timeout 变量,这样就保证了在 mod_http.so 的运行空间内 +调用 acl_aio_request_timer 中的参数之函数地址与在 jaws 的运行空间内调用 +acl_aio_cancel_timer 中的参数之函数地址是一致的 + +337) 2010.3.2 +337.1) bugfix: events_kernel.c/events_kernel2.c/events_kernel3.c 的函数 +event_loop() 函数里增加了 EVENT_TEST_ERROR 检测代码,当描述字出错时 +epoll/devpoll 会设置这些描述字的出错状态,这段检测代码正好可以处理这种情况 + +336) 2010.2.23-2.24 +336.1) performance: events_kernel.c 进一步优化了代码和性能: 对于超时的 +处理采用每隔一秒进行全局扫描的方式; 将读/写任务的添加放置在一个队列中, +而不象以前那样放在一个全局数组里(该方式的问题时当并发慢连接比较多时,每 +个事件循环都要全局扫描整个数组,查看哪些任务需要处理) +336.2) 依然保留原来的 events_kernel.c,只是重命名为 events_kernel2.c, +events_kernel3.c,以备后用(谁知道哪天会重用这些代码呢?) + +335) 2010.2.11 +335.1) acl_aio_read.c: acl_aio_enable_read() 如果判断还有数据则直接回调 +用户的回调函数 + +334) 2010.2.9 +334.1) bugfix: acl_dns.c, acl_add_dns_host() 内部在添加静态域名IP列表时 +有错误 + +333) 2010.2.8 +333.1) feature: acl_dns.c 增加了域名组功能 + +332) 2010.2.5 +332.1) events_select.c, events_poll.c: 采用与 events_kernel.c 中的方式 +重写 + +331) 2010.2.4 +331.1) bugfix: events_kernel.c 修改了一些BUGS, 增加流关闭时的删除监控 +回调函数 +331.2) feature: acl_vstream.c 增加了 acl_vstream_call_close_handles()/1 +可以提前调用关闭回调函数,主要配合 events_kernels.c + +330) 2010.1.25 -- 2010.2.3 +330.1) event/: 增加了支持 epoll/kqueue/devpoll 更为高效的事件引擎,将 +原来的 event_kernel.c 更名为 event_kernel2.c, 新的事件引擎名称为 +event_kernel.c +330.2) bugfix: acl_access.c/acl_access_permit() 传入的地址可以为 +IP:PORT/IP 格式 +330.3) acl_vstream.c: acl_vstream_close() 在 event_kernel.c 的配合下 +支持延迟关闭功能 +330.4) aio/: acl_aio.c, aio_callback.c 完善了一些处理条件,支持 +ACL_ASTREAM.stream 流的延迟关闭; aio_callback.c 当有一个关闭回调返回 +-1 则停止调用下一个关闭回调 + +329) 2010.1.24 +329.1) aio/: acl_aio_disable_readwrite, acl_aio_disable_read, +acl_aio_disable_write 增加了一些判断条件 + +328) 2010.1.22 +328.1) bugfix: acl_vstream.c, acl_vstream_readn_peek() 内部有问题 +328.2) bugfix: acl_aio.c, acl_aio_open() 在对监听流设置读缓冲大小时 +设置条件是错误的,原来是:if ((stream->type ACL_VSTREAM_TYPE_LISTEN)), +应该是 if ((stream->type & ACL_VSTREAM_TYPE_LISTEN));同时当 +stream->read_buf 非空时,stream->read_buf_len 是不能被修改的 + +327) 2010.1.19 +327.1) acl_pthread.h: ACL_PTHREAD_ONCE_INIT 在 solaris 下需要定义为 +{ PTHREAD_ONCE_INIT }, 只有这样才可以在 solaris 下如下使用: +static acl_pthread_once_t once_control = ACL_PTHREAD_ONCE_INIT; +327.2) 在所有平台上编译通过 + +326) 2010.1.18 +326.1) acl_dns.c: 增加了缓存功能(使用了 acl_cache2.c 中的函数接口) + +325) 2010.1.17 +325.1) acl_cache2.c: 完善了一些功能并修复了一些 bugs +325.2) samples: cache2/ + +324) 2010.1.16 +324.1) 将 acl_idns.c 改名为 acl_dns.c, acl_idns.h 改名为 acl_dns.h, 将 +ACL_DNS_EVENT 改名为 ACL_DNS_REQ +324.2) 增加了 acl_cache2.c 模块, 该函数内部采用哈希表加平衡二叉树的组合 +方式来提供比 acl_cahce.c (采用哈希表加双向链表组合方式) 更加灵活高效的 +缓存控制机制 + +323) 2010.1.15 +323.1) feature: acl_idns.c, 增加了异步DNS查询功能及相关功能函数; 该函数库 +支持DNS查询的动态平衡功能及DNS地址有效性校验机制 +323.2) bugfix: rfc1035.c(从squid借鉴的源码) 内部存在一个可能发生内存泄露 +的问题 +323.3) samples: idns/ 该例子使用DNS异步查询来获得DNS结果 + +322) 2010.1.14 +322.1) acl_aio_connect.c: 调整了部分逻辑执行顺序 +322.2) master/template/: 所有模板使用的 argv 参数都修改为小写 + +321) 2010.1.13 +321.1) bugfix: aio_callback.c, 在调用关闭回调函数集时,只要有一个回调函 +数返回 -1 都应该停止继续调用剩余的关闭回调函数 + +320) 2010.1.7 +320.1) bugfix: acl_pthread.c, 当采用线程局部存储方式管理内存池时会出错, +因为其内部用到了的算法中含有 acl_myxxx 类的内存分配方式 +320.2) feature: private_fifo.c 为配合线程局部管理内存池增加了几个接口 +320.3) acl_vstream_popen.h: 为了在 win32 平台下以动态库加载方式使用这些 +接口,前面增加了导入导出标志 ACL_API +320.4) win32 编译工程整理 +320.5) acl_aio_listen.c: 当监听返回错误时,原来的做法直接 fatal, 现在是 +先睡眠 1 秒然后继续监听 + +319) 2010.1.6 +319.1) acl_aio_listen.c: 增加了出错提示功能 + +318) 2010.1.5 +318.1) feature: acl_mem_slice.c 增加了 acl_mem_slice_delay_destroy 接口, +当一个线程退出时发现自己分配的内存片被其它线程占用时,该将退出线程不可 +硬性释放被占用内存而只能释放非占用内存片,同时将剩余被占用内存片置入一 +个进程内全局的待释放区内,由主线程或其它线程调用 acl_mem_slice_delay_destroy +来清理 + +317) 2010.1.4 +317.1) bugfix: +acl_aio_read.c/acl_aio_write.c/acl_aio_connect.c/aio_callback.c, 其中在 +遍历回调函数的句柄时有可能会因为递归嵌套而造成回调函数被重复调用,现在 +采用每次需要回调时重新建立回调队列方式来避免此类问题发生 + +316) 2010.1.2 +316.1) acl_aio.c: 增加了函数接口注释; 修改了部分接口名称,使之更易读懂 +316.2) acl_aio.c: 增加了 acl_aio_enable_write 接口 + +315) 2010.1.1 +315.1) acl_aio.c: 修订了上次修改时在 acl_aio_read.c 中增加的一处BUG +315.2) acl_aio.c: 完善了 acl_aio_enable_read 函数 + +314) 2009.12.31 +314.1) acl_aio.c: 完善了一些接口,增加了出错检查 +314.2) acl_array.c: 调用 acl_array_clean/acl_array_destroy 内部代码略有改动 + +313) 2009.12.25 +313.1) bugfix: acl_vstream.c 针对非阻塞式读应该区分出该出错情形 + +312) 2009.12.23 +312.1) feature: acl_mem_slice.c 增加了自动进行内存垃圾回收机制,当分配计 +数器达到规定的值时自动进行垃圾回收(注:此垃圾回收主要是用来回收其它线程 +释放本线程分配的内存资源) +312.2) compile: BSD 平台编译通过 + +311) 2009.12.19-12.20 +311.1) performance&feature: 增加了针对线程局部变量的内存分配与释放函数库 +接口,这样在多线程进行内存分配时的冲突被降低至最低,从而大大提高了多线程 +程序的内存管理性能 +311.2) acl_aio_server.c/acl_aio_app_main.c: 为了提高效率,接口略作调整 + +310) 2009.12.18 +310.1) feature: acl_slice.c 增加了 acl_slice_pool_xxx 系列功能 + +309) 2009.12.17 +309.1) feature&performance: 增加了 acl_mem_slice.c, 从而可以高效地利用内存 +切片技术分配和释放内存 + +308) 2009.12.16 +308.1) performance: acl_vstream.c 中的 __bfread_cnt_ready 及 __bfread_ready +的数据拷贝由原来的字节拷贝改为块拷贝,效率大大提高,受此影响 acl_aio_read() +和 acl_aio_readn() 的性能也大大提高 + +307) 2009.12.12 +307.1) bugfix: acl_sys_file.c 中的 acl_file_fsize()/1 函数在 win32 平台下, +因为需要兼容64位文件系统,所以其中的 nHigh << 32 操作会因 nHigh 为 DWORD +而可能产生32位整数溢出问题 + +306) 2009.12.10-12.11 +306.1) feature: acl_pthread.c 增加了 acl_pthread_tls_get/acl_pthread_tls_set, +可以更方便地操作线程局部变量, acl_pthread_tls_set_max/acl_pthread_tls_get_max, +可以设置/获得 acl_pthread_tls_get/acl_pthread_tls_set 所用的线程局部变量的键 +值最大个数,因为系统的线程局部变量所对应的键有上限限制,所以可以使用这些函数 +突破这些限制 +306.2) acl 库内部基本上去掉了以 __thread 方式使用线程局部变量的方式,因为此 +使用方式在当应用动态加载 acl 动态库时会发生不确定行为(如果应用是静态链接 acl +库或静态加载 acl 动态库则不会产生此问题); 目前还有几个源文件里还有 __thread +的使用情况: zdb_dat_iter.c, zdb_key.c, acl_aio_app_main.c, acl_aio_server.c, +acl_ioctl_app_main.c, rfc1035.c, acl_meter_time.c, gettimeofday.c, 应用在使用 +这些源文件里的函数时一定注意不要以动态加载 acl 动态库方式使用之 + +305) 2009.12.9 +305.1) feature: acl_pthread.c, 增加了 acl_pthread_tls_get, acl_pthread_tls_set +接口,同时增加了 win32 平台下的 acl_pthread_key_create, acl_pthread_getspecific, +acl_pthread_setspecific 接口,其调用方式与 UNIX 下的 pthread_key_create, +pthread_getspecific, pthread_setspecific 相同, 为了保证跨平台,建议使用 +acl_xxx 方式使用这些函数接口 + +304) 2009.12.7-12.8 +304.1) feature: acl_dll.c, 用于动态库的加载 +304.2) bugifx: acl_netdb.c, acl_res.c res_util.c 内部用到了 inet_ntoa, +而该函数是线程非安全的, 统一换成 acl_inet_ntoa + +303) 2009.12.6 +303.1) acl_fifo.c: 有些代码实现的有点罗嗦 + +302) 2009.12.3 +302.1) bugfix: acl_vstring_sprintf(), 其中的 fmt 64位格式字符(如: llu) +用VC6编译时不能正确识别, 所以在平台上做了区分: UNIX平台用 llu/lld,而在 +WIN32平台则用 I64u/I64d. 但用户在使用 acl_vstring_sprintf() 时则只需要 +使用统一的 llu/lld 即可 +302.2) feature: acl_getenv_list() 函数可以获得本进程的环境变量(以字符串 +表示, 如: name1=value1, name2=value2, name3=value3) + +301) 2009.11.30--12.2 +301.1) feature: acl_vstream_popen.c 可以同时支持UNIX、WIN32平台了 +301.2) feature: acl_env.c 可以同时支持UNIX、WIN32平台 + +300) 2009.11.27 +300.1) feature: acl_sane_inet.c, 增加了 acl_ipv4_addr_valid()/1, +acl_ipv4_valid()/1 函数, 用比判断所给地址是否有效 +300.2) acl_aio_connect.c: 增加了对输入地址的有效性进行判断功能 + +299) 2009.11.25 +299.1) bugfix: acl_aio.c, acl_aio_iocp_close()/1 当 astream->stream = NULL 时, +应该设置 ACL_AIO_FLAG_IOCP_CLOSE 标志位, 否则会造成内存泄露 + +298) 2009.11.24 +298.1) acl_sane_socket.c: 调用 acl_getsockname/acl_getpeername 取得地址时将端口 +号也加进去了 + +297) 2009.11.23 +297) ACL_ITER: 符合通用遍历的容器的接口返回类型的 const 限定属性取消,从而方便 +应用操作返回的对象 +297.2) acl_fifo.c: 允许 acl_fifo_push()/2 返回新创建的队列元素对象, 方便调用者 +缓存并操作该对象 + +296) 2009.11.22 +296.1) bugfix: strcasestr.c, acl_strcasestr()/2 函数有处 bug +296.2) feature: acl_inet_listen.c, acl_inet_accept_ex 中存储客户端地址的内存区 +ipbuf 原来仅存储 IP 地址,现在可以同时存储端口号了,所以正常情况下 ipbuf 里面 +存储的是: ip:port, 如: 192.168.0.1:80 + +295) 2009.11.20 +295.1) 增加了 acl_dll.h 头文件,用于在 dll 之间传递环境变量 +295.2) acl_debug_malloc.c: 调整了一下接口调用 +295.3) bugfix: acl_aio_read.c, acl_aio_write.c, +READ_IOCP_CLOSE/WRITE_IOCP_CLOSE 这两个宏应该增加标志位 ACL_AIO_FLAG_IOCP_CLOSE + +294) 2009.11.19 +294.1) bugfix: acl_inet_listen.c 当监听失败时会有一处内存泄露问题 +294.2) bugfix: events_select_thr.c, event_enable_listen() 函数内部被重复使用 +时,因为没有重复利用 ACL_VSTREAM.fdp, 所以每当对 event_enable_listen() 调用 +一次就会调用一次 event_fdtable_alloc(), 从而造成了内存泄露. 该 bug 会影响到 +acl_ioctl.c, acl_ioctl_server.c 的使用造成内存泄露. 老版本的 acl 的 acl_master +框架下的多线程模板会受到此影响,避免此问题的方法有二:重新用新的 acl 库编译 +服务器程序,或将配置文件中的 ioctl_event_mode 选项改为 poll/kernel 方式,因为 +其只会影响 select 多线程方式. + +293) 2009.11.16-18 +293.1) acl_msgio: 重新设计并修改了一些代码 +293.2) bugfix: master/template/ 目录下,acl_aio_server.c, aio_msg.c 存在一些 +消息传递的 bug + +292) 2009.11.15 +292.1) ACL_VSTREAM 中增加了 pid_t pid 成员 + +291) 2009.11.13 +291.1) compile: 在 Debian Linux 平台下编译通过 + +290) 2009.11.12 +290.1) samples: win32 -- code_map, 主要用于产生字符集的映射表 +290.2) samples: win32 -- connect, 异步连接举例 +290.3) acl_aio: 添加了一些使用接口,同时将 ACL_ITER 迭代器引入,使代码 +更为清晰 + +289) 2009.11.10 +289.1) feature: acl_file 增加了 acl_fprintf, acl_vfprintf +289.2) feature: code/ 增加了GBK字符集内部的简繁体转换函数: acl_gbcode +289.3) samples: jt2ft 用于测试简繁体转换 + +288) 2009.10.26 +288.1) feature: acl_vstring 增加了 acl_buffer_gets_nonl()/3, +acl_buffer_gets()/3; stdlib/common/ 下增加了 acl_token_tree 模块 +288.2) compile: 在 LINUX/FREEBSD/SOLARIS/WIN32 平台编译通过 + +287) 2009.10.20 +287.1) bugfix: acl_bits_map.h 中当 nmax 为 (unsigned int) -1 时,得到的 +(mask)->data_len = 0, 因为在计算长度时产生了整数溢出错误; acl_bits_map.h +的注释不太明确 +287.2) compile: 在 FreeBSD, Solaris, Windows 上编译通过,消除了一些移植性问题 + +286) 2009.10.18 +286.1) bugfix: ACL_CFG_INT64_TABLE.*target 应该为 acl_int64 类型而不是 int 类型 +286.2) compile: 在用VC编译动态库时,lib_acl 库需要依赖 IPHlpApi.Lib + +285) 2009.9.30 +285.1) feature: acl_xinetd_params.c/acl_xinetd_params.h, acl_master 服务器框架 +增加了针对 acl_int64 配置类型的支持 +285.2) bugfix: zdb/zdb_private.h, 其中 KEY_INODE, KEY_OFF 两个宏计算有误 + +284) 2009.9.29 +284.1) bugfix: acl_fhandle.c, 其中在使用线程锁时存在问题,应该是 +acl_thread_mutex_lock/acl_thread_mutex_unlock, +acl_pthread_mutex_lock/acl_pthread_mutex_unlock 配对使用,在一些地方存在混用问题 +284.2) zdb: zdb.h 存储结构规定为4字节对齐 +284.3) acl_cache.c: 增了容错处理,创建时可以允许缓存个数及数据时间为0 + +283) 2009.9.27 +283.1) bugfix: acl_non_blocking() 内部在BSD平台下可能会有问题 + +282) 2009.9.25 +282.1) zdb: 为了保证 zdb 数据结构在32位及64位机上可移植性, 增加了冗余变量以使各 +个存储结构按8字节对齐,将来应该采用其它方式保证这点 +282.2) acl_slice: 优化了 SLICE2 方式的释放速度 + +281) 2009.9.24 +281.1) bugfix: acl_slice.c 中的 ACL_SLICE_FLAG_GC2 算法存在严重 BUG, 导致内存指针越界 + +280) 2009.9.23 +280.1) feature: zdb_key.c, 增加了 zdb_key_init()/3 接口,可以使应用预先初始化键存储 +280.2) 将 win32 平台下的 BDB, OPENSSL 打包进去 + +279) 2009.9.21 +279.1) feature: db/zdb, 该模块是一个非常高效的数字键存储系统 +279.2) bugfix: stdlib/sys/acl_sys_file.c, acl_file_fsize()/1 在win32平台下有一处错误 + +278) 2009.9.20 +278.1) feature: net/acl_ifconf.c, 可以获得UNIX/WIN32下网卡信息 + +277) 2009.9.15 +277.1) bugfix: acl_cache.c, acl_cache_free()/1 在释放缓存对象时如果引用计数 +大于 0 则无法释放而造成死循环,采取的方法是强制将缓存对象的引用计数置 0 +277.2) feature: acl_vbuf_print.c, 支持 "%lld" 格式,从而 acl_vstring.c 也支持 +"%lld" 格式 + +276) 2009.9.11 +276.1) feature: event/acl_timer.c 支持通用的 ACL_ITER 方法 +276.2) feature: ACL_ITER 支持 acl_iter_info()/2 取得与容器相关联的成员对象 + +275) 2009.9.10 +275.1) feature: ACL_DNS_DB 结构增加了对 ACL_ITER 迭代器的支持 +275.2) acl_fhandle.c: acl_fhandle_init()/3 及 acl_fhandle_end() 增加了 +内容判断,防止被调用两次 + +274) 2009.9.9 +274.1) comment: 增加了一些注释 +274.2) acl_mask_addr.c: 增加了单元测试, unit_test/net/test_net_misc.c + +273) 2009.9.8 +273) feature: db/acl_dbsql.c, db/mysql/acl_dbmysql.c 中增加了 +acl_dbmysql_select()/3, acl_dbmysql_free_result()/1, db/acl_dbpool.h 中 +增加了 ACL_SQL_RES 结构,可以使用通用的 ACL_ITER 对查询结果进行遍历 + +272) 2009.9.7 +272.1) acl_iterator.h: ACL_ITER 结构中增加了一个成员变量 dlen, 使用者可以 +设置此值表明数据大小 + +271) 2009.9.5 +271.1) acl_iterator.h: 去掉了 ACL_ITER 中的 iter_init()/2, 而在各个容器本身 +中增加 iter_head()/2, iter_next()/2, iter_tail()/2, iter_prev()/2 四个成员, +这样更加直观,如果容器没有这些函数则便是不支持通用的遍历操作; 这样,任务函数 +库只要包含 iter_head()/2, iter_next()/2 便可支持向后遍历, 若包含 +iter_tail()/2, iter_prev()/2 则支持向前遍历,这更具有通用性 + +270) 2009.9.1 +270.1) bugfix: acl_fhandle.c 中 acl_fhandle_open 若失败在记录错误信息时引用 +了一个空地址 +270.2) bugfix: acl_fseek()/3 没有在 acl_file.h 头文件中声明 + +269) 2009.8.31 +269.1) feature: acl_file.c, 增加了 acl_fseek()/3 接口 + +268) 2009.8.30 +268.1) feature: stdlib/acl_file.c, 增加了专门针对文件流的读写操作, 提供了与 +ANSI 标准相似的接口 + +267) 2009.8.29 +267.1) 将 ACL_ASTREAM 的类型定义从内部移出至公开的 acl_aio.h 头文件中, 因为 +有时需要访问里面的一些参数,如果继续隐藏此类型定义,则势必会需要实现一些函数 +来访问这些参数,实在麻烦,所以将该结构的定义公开从而方便了有些参数的访问,但 +如果提供了访问函数,建议还是用函数访问较好,免得将来该结构定义发生变化 + +266) 2009.8.28 +266.1) feature: acl_iterator.h, 其中定义了更为通用的迭代器处理方式, 这样在 +stdlib/common/ 的数据结构的容器基本都可以以非常简单的方式用此通用迭代器进行 +遍历 +266.2) sample: iterator/, 其中增加了很多使用迭代器进行遍历的例子 + +265) 2009.8.27 +265.1) feature: acl_fhandle.c, acl_fhandle_open()/6 中的参数 oflags 增加了一个标志位 +ACL_FHANDLE_O_MKDIR 用来确定是否自动检查并创建不存在的目录,如果设置该标志位,则当 +第一次打开文件时且目录存在时会有些不必要的性能降低 +265.2) acl_htable/acl_binhash: 在遍历过程中,旧的 foreach() 存在一个问题:当在循环 +过程中需要 break 则不会退出循环, 原因是旧的 foreach() 是嵌套了两个 for() 循环,现在 +进行了修复,增加了 acl_xxx_iter_head/acl_xxx_iter_next/acl_xxx_iter_tail/acl_xxx_iter_prev +几个函数,这样 foreach() 就仅嵌套一个 for() 循环,而使用者便可以在遍历过程中 break 循环 + +264) 2009.8.26 +264.1) bugfix: acl_fhandle.c, acl_fhandle_end() 在关闭所有文件句柄前应该 +回调应用的关闭回调函数 +264.2) acl_cache.c: 允许在调用 acl_cache_create() 时的 free_fn 回调函数为空, +只是给出一个提示告诉使用者 free_fn 为空 +264.3) feature: acl_fhandle.c, acl_fhandle_init() 增加了一个参数,以使内部决定是否加锁; +同时 acl_fhandle_open() 的 oflags 也增加了一个是否启动线程锁的标志位 ACL_FHANDLE_O_MLOCK + +263) 2009.8.24 +263.1) acl_lseek: 支持 Linux/Solaris 平台下的64位操作 +263.2) bugfix: acl_fhandle.c 在记录日志时有一处参数错误 + +262) 2009.8.23 +262.1) acl_mystring.c: acl_ui64toa_radix() 函数没有WIN32的定义 +262.2) db/memdb: 修正了一些对内存高效使用的地方 + +261) 2009.8.20 +261.1) acl_slice: 修复了几处 bug; acl_slice_free()/1 支持 ACL_SLICE_FLAG_GC2, +ACL_SLICE_FLAG_GC3 两类内存的直接释放, 而 acl_slice_free2()/2 则支持所有释放操作 + +260) 2009.8.19 +260.1) bugfix: acl_slice 去掉了 ACL_SLICE_FLAG_GC_TIME2 算法,该算法的设计是有缺陷的 + +259) 2009.8.17--8.18 +259.1) feature: stdlib/memory/acl_slice.c: 增加了一个参数 ACL_SLICE_FLAG_LP64_ALIGN, +可以用来对一些特殊的应用在64位机下进行字节对齐; +259.2) 需进一步改进的地方: acl_slice.c 中的 ACL_SLICE_FLAG_MIN_TIME3 还有内存节省 +的改进空间, 主要是在64位平台上将占8个字节的指针转换为占4个字节的整数,这样当分配 +10240000 个对象时又可以节省39MB + +258) 2009.8.12 +258.1) feature: stdlib/memory/acl_slice.c: 又增加了一个新的内存切片算法,该算法 +的效率更高,同时内存占用更小 +258.2) feature: acl_mystring.c 增加了 acl_i64toa_radix()/4, acl_ui64toa_radix()/4 两个函数, +可以在转换时指定进制类型,在LINUX下测试发现这两个函数的执行效率还不如 snprintf +进行转换时高:) +258.3) stdlib/ 目录下所有与内存分配有关的源文件都移至 stdlib/memory/ 目录下 + +257) 2009.8.10 +257.1) feature: stdlib/acl_fhandle.c, 可以缓存所打开的文件句柄 + +256) 2009.8.7 +256.1) bugfix: acl_vstream.c, 因为将 ACL_VSTREAM.path 做为 +ACL_VSTREAM.remote_addr 的一个引用,从而导致 acl_vstream_free()/1 内部释放 +path 出错,现在将 ACL_VSTREAM.path 定义为 const char*, 以避免非法释放, 该 +bug 影响所有使用 acl_vstream_free()/1 的地方 +如: acl_master/framework/master_spawn.c: acl_master_spawn()->acl_vstream_free()/1, + +255) 2009.8.6 +255.1) acl_ring, acl_htable, acl_binhash, acl_fifo: 统一了遍历的访问方式, +使遍历过程更加简单有效 +255.2) acl_ring: 去掉了没有用的重复定义的宏 + +254) 2009.8.3 +254.1) stdlib: acl_htable/acl_binhash/acl_fifo/acl_ring, 统一了遍历方式 + +253) 2009.7.31 +253.1) stdlib: acl_htable.c, acl_binhash.c, acl_cache.c, acl_btree.c 内部均 +增加了 acl_slice_xxx 功能 +253.2) private: 去掉了 htable.c, binhash.c +253.3) db/memdb: 不再使用私有的 htable.c, binhash.c, 因为 acl_htable.c, +acl_binhash.c 也支持内存切片, 所以 memdb/ 下的函数直接使用公共的 acl_htable.c, +acl_binhash.c. +253.4) 修改了所有与新的 acl_htable.c 中所提供的接口不一致的地方 + +252) 2009.7.28 +252.1) stdlib/acl_slice: 又增加了一个内存分配算法,该算法的实时垃圾回收 +效率更高,且采用了冒泡算法,从而使不用的内存能够尽快被回收,唯一的缺点就是 +稍微增加了一点内存,但这些是微不足道的:) + +251) 2009.7.26 +251.1) private: 增加该模块主要是为了 lib_acl 内部所用的一些常见库 +251.2) 将 stdlib/debug/ 下的 debug_htable.c 的函数及结构定义前增加了 +前缀,从而避免了在VC环境下的编译警告 +251.3) 在 VC6 下编译通过 + +250) 2009.7.24 +250.1) stdlib/acl_slice: 终于修复了所有的BUG:) +为了保证 acl_slice 的通用性,尤其是为了保证在64位机上 AVL 使用 acl_slice +时不会报错, 在内部内存片结构中增加了填充数据 +250.2) lib_acl 已经在 Redhat AS4/AS5(32/64), FreeBSD, VC2003/VC2008 上编译并测试通过 + +249) 2009.7.22 +249.1) stdlib/acl_slice: 可以进行内存片的管理,该函数集在处理固定长度的内存 +的分配与释放时非常有效,而且不会产生内存碎片 + +248) 2009.7.18 +248.1) db/memdb: 重新进行了设计,设计了一个整体的框架,目前基于该框架所用的 +算法有:字符串哈希表、二进制哈希表、平稳二叉树(基于SUN的avl库) +248.2) samples/memdb: 增加了 valgrind 测试,用来检测内存漏洞情况 + +247) 2009.7.3 +247.1) acl_vstream: ACL_VSTREAM 结构中去掉了多余的 rw_arg, 同时将 +ACL_VSTREAM_CTL_RW_ARG 删除, 将 ACL_VSTREAM_CTL_CACHE_SEEK 由原来的 8 改为 7, +增了 ACL_VSTREAM_CTL_CONTEXT 的相同定义 ACL_VSTREAM_CTL_CTX; acl_vstream.c +中所有 rw_arg 的参数都修改为 context. + +246) 2009.6.30 +246.1) aio/, ioctl/, master/template/: 都增加了引出 ACL_EVENT 的函数接口 +246.2) master/template/: 几个服务器模板中将创建事件对象的位置放在 pre_init() +前, 从而便于外部调用获得 ACL_EVENT 句柄 + +245) 2009.6.27 +245.1) acl_vstream: IO 函数类型增加了个 timeout 超时参数 + +244) 2009.6.26 +244.1) acl_vstream.c: 增加了几个方便使用的函数, 同时将缓冲写与非缓冲写结合起来 + +243) 2009.6.23 +243.1) bugfix: acl_ioctl_app_main.c, acl_aio_app_main.c 中的 +__deny_info 没有先赋初始值,会导致 coredump +243.2) 去掉了 acl_define_unix.h, acl_define_linux.h 里包含的头 +文件, 以免应用在引用库时冲突, 如: pthread_spinlock_t 的要求就比较严格 +243.3) performance: +a) linux 平台: +单线程运行时 pthread_spinlock_t 的加锁、解锁速度大约是 pthread_mutex_t 的2倍左右; +双线程运行时 pthread_spinlock_t 的加锁、解锁速度大约是 2-3倍 +b) FreeBsd 平台: +双线程运行时 pthread_spinlock_t 的加锁、解锁速度大约是 7-8倍 + +242) 2009.6.22 +242.1) feature: 增加了一次性释放的内存池函数库 acl_dbuf_pool.c +242.2) feature: acl_pthread_mutex.c, 增加了线程嵌套加锁的函数 +acl_thread_mutex_lock()/1, acl_thread_mutex_unlock()/2, +acl_thread_mutex_nested()/1, 这样当某个线程对某一线程锁进行 +多次加锁时,可以立即返回,防止死锁 +242.3) feature: src/master/template, 增加了 acl_ioctl_app_main.c, +acl_aio_app_main.c, 可以更为方便地使用服务器框架 + +241) 2009.6.19 +241.1) samples/cache/main.c: 在 bsd 环境编译有警告 + +240) 2009.6.16 +240.1) 增加了 gc 的测试例子 +240.2) 增加了字符串比较函数: strrncasecmp()/3, strrncmp()/3 + +239) 2009.5.12 +239.1) bugfix: stdlib/common/acl_array.c, acl_array_clean()/2 当动态数组 +为空时进行释放时有内存空指针被操作 + +238) 2009.4.28 +238.1) feature: stdlib/common/acl_cache.c, 增加了具有容量限制及过期功能 +的缓存池函数库; +238.2) samples: samples/cache/ 增加了一个测试缓存池的例子 + +237) 2009.4.23 +237.1) feature: acl_ring.h 增加了 ACL_RING_FIRST()/1, ACL_RING_LAST()/1, +ACL_RING_LAST_APPL()/3 三个有用的宏; 同时将 ACL_FIRST_APPL()/3 改名为 +ACL_RING_FIRST_APPL()/3 +237.2) feature: acl_xinetd_params.c 中的三个函数 +acl_xinetd_params_int_table()/2, acl_xinetd_params_bool_table()/2, +acl_xinetd_params_str_table()/2 可以允许其中的 cfg 参数为空,在这种情况 +下仅用默认值进行赋值,从而方便于调试工作 + +236) 2009.4.21 +236.1) feature: acl_timer.c 增加了 acl_timer_walk()/3, 从而方便遍历定时器 +里的所有定时任务信息,同时将 ACL_TIMER_INFO 结构引出至 acl_timer.h 文件中 +226.2) bugfix: acl_timer.c 中的 acl_timer_free()/1 有内存泄露问题,现在更 +改为 acl_timer_free()/2, 用户可以用自己的回调函数进行用户数据对象的释放 +226.3) feature: acl_timer.c 增加了 acl_timer_size()/1 可以获得定时器里的 +定时任务个数 + +235) 2009.4.20 +235.1) bugfix: win32 平台下的 acl_pthread_cond_timedwait()/3 实现存在与 +Posix 参数含义不兼容问题,其中的第三个参数: 超时值应该是绝对时间而不是相对 +时间。相关的文件修改有: acl_pthread_cond.c, acl_pthread_pool.c, acl_aqueue.c +acl_workq.c,此BUG由黄奕发现。 + +234) 2009.4.19 +234.1) bugfix: getimeofday()/2, 该函数模拟了在WIN32平台下获得精确时间的功能, +因为其内部由时钟计数来计算的,当开机时间较长时,时钟计数会因为溢出而归零,这 +样就会生产计算的新时间截小于真实时间截的情形,所以增加了每隔1天重新初始化时 +钟校验基准的过程,这样就不会因时钟计数溢出而造成的问题 + +233) 2009.4.14 +233.1) feature: 添加了获得进程运行时程序全路径及程序运行路径的函数: +acl_process_path(), acl_getcwd(), 这两个函数支持: win32, Linux/FreeBsd/Solaris +233.2) samples: process/ 测试新添加的两个函数 +233.3) 在 stdlib/ 目录下增加了 sys/ 目录,将一些与操作系统相关的程序移至该目录下 +233.4) acl_argv_split.c: 添加了 acl_argv_splitn()/3, acl_argv_splitn_append()/4 +两个函数 + +232) 2009.4.9 +232.1) acl_sys_patch.c: 原来在 win32 平台下的 gettimeofday()/2 实现仅依赖于 +win32 API "GetSystemTimeAsFileTime",而该 API 的精度不够细,所以重新实现了 +win32 平台下的 gettimeofday 的函数,通过结合 GetSystemTimeAsFileTime 及系统 +的时钟,使 gettimeofday 获得的时间颗粒度更细 + +231) 2009.4.7 +231.1) events: 抽象出 event_prepare()/1, event_fire()/1, +event_thr_prepare()/1, event_thr_fire()/1 四个函数,由各个事件引擎相同的操作 +抽象而成. + +230) 2009.4.3 +230.1) bugfix: ACL_VSTREAM 结构定义中的字符串缓存空间应为 unsigned char*, +原来定义为 char*, 在某些情况会导致使用该结构的一些函数出错, 如: +ACL_VSTREAM_GETC/acl_vstream_getc, 它们在使用时以返回值为 ACL_VSTREAM_EOF +表示出错或读结束,同时返回值又作为所读到的字符值,按 ACL_VSTREAM->read_buf, +read_ptr 原来的类型(char*) 则如果数据源中含有 (char) -1, 则调用 +int ch = ACL_VSTREAM_GETC(stream)/int ch = acl_vstream_getc(stream) 后, +则 ch = -1 (即由 char 升级为 int 后依然为 -1), 而在源中 (char)-1 其实为 +(unsigned char) 255, 当升级为 int 后依然为 255. +230.2) aio: 存在一些不太合理的定义,进行了修改 + +229) 2009.4.2 +229.1) acl_set_error()/1: 在WIN32平台上,不仅设置了API的错误号,同时将标准C +的 errno 进行了设置 +229.2) bugfix: acl_vstring_strstr/acl_vstring_strcasestr/strcasestr 均存在一 +个明显的bug, 导致在某种条件下查不到结果; +229.3) feature: 增加了 acl_vstring_rstrstr/acl_vstring_rstrcasestr, +acl_rstrstr/acl_rstrcasestr 字符串函数,可以方便地从后向前查找字符串 + +228) 2009.4.1 +228.1) net/connect/acl_timed_connect.c: 修改了一个小bug, 没有初始化变量 err +228.2) net/connect: getsockopt 在不同平台上有不同的语义,所以导致在处理此问题 +时比较麻烦些,在 Solaris 上,针对一个非阻塞调用 getsockopt 时并不设置出错值, +而是通过全局的 errno 来表明套接字的状态; 在 Linux 上,在非阻塞连接时,errno +却被设置为 EINPROGRESS, 需要通过 getsockopt 中的设置出错值来判断; 在 win32平台 +下,如果连接本地一个不存在的监听端口时,却无法立即探测连接失败的情形,其在 +getsockopt 的出错参数设置为0, 而且将全局的错误号置0. 为了解决这些平台差异,需要 +保留一个调用 connect 之后的 errno 号,同时加上 getsockopt 里的错误号,进行判断. + +227) 2009.3.30 +227.1) event: 增加了对 poll 的支持 +227.2) aio: 修改了部分接口 +227.3) net/connect: 修改了部分BUG + +226) 2009.3.11 +226.1) acl_vstream_accept_ex()/4: 有一处BUG,套接字类型应该取 stream->type +226.2) samples: msg/, 增加了测试TCP套接口、UNIX域套接口、管道、异步队列性能 +的例子,在 Linux 平台下 看来UNIX域套接口与线程异步队列性能都是不错的,管道次之, +TCP套接口最低 226.3) samples: dns/, 完善了DNS测试的例子; 在 FreeBSD 测试过程中, +发现线程 异步队列出奇地快,性能是其它基于IO的性能的3-4倍; 在 Solaris10-x86平台下, +线程异步队列的性能也是IO性能的1.5倍左右。看来 Linux 平台下的线程还有待提高:) + +225) 2009.3.10 +225.1) event: kqueue 功能测试; 修改了 events_kernel.c 中的几处 bug +225.2) samples/aio: 测试了该例子在Linux/Solaris/FreeBSD 三个平台的运行状态 + +224) 2009.3.9 +224.1) event: 支持 FreeBSD 平台下的 kqueue +224.2) samepls/aio: 有关AIO操作的两个例子 + +223) 2009.3.6 +223.1) feature: acl_vstream.c, acl_vstream_fopen()/4 针对WIN32平台在 +打开文件时,自动将参数 oflags 添加 O_BINARY 标志 +223.2) feature: acl_vstream.c, 增加了 acl_vstream_fstat()/2 和 +acl_vstream_fsize()/1 两个函数,可以方便获得文件句柄的属性信息和文件大小 +223.3) feature: acl_msg.c, 增加了 acl_last_serror()/0 可以更方便地获得 +出错提示信息,同时该函数内部采用了线程局部变量,所以是线程安全的 +223.4) feature: acl_vstream.c, 增加 acl_vstream_fsync()/1, 可以将文件流缓冲区 +及系统缓冲区中的数据直接同步至硬盘 +223.5) acl_file_fstat()/2: 支持WIN32平台 +223.6) 将 acl_sys_patch.c 拆分为三个文件: acl_sys_patch.c, acl_sys_file.c +和 acl_sys_socket.c +223.7) acl_pthread_pool.c: 将负载高于所启动线程数的10倍时便需报警 + +222) 2009.3.5 +222.1) feature: 增加了 acl_file_size()/1, acl_file_fsize()/1 函数 +222.2) 将 acl_stat_t 用 typedef 进行了类型别名定义,即如果要用此类型, +只需要直接声明:"acl_stat_t sbuf;" 即可,当然也可以这样声明: +"struct acl_stat sbuf;" +222.3) featur: acl_vstream_fflush()/1 当操作文件时可以保证数据写至硬盘, +在WIN32平台下尤为重要 + +221) 2009.3.4 +221.1) event: 支持 Solaris 平台下的 /dev/poll + +220) 2009.3.3 +220.1) event: 修改了 events_kernel.c, events_select.c 中的一处bug +220.2) master/template: acl_aio_server.c 模板增加了 socket 的接收增强功能 + +219) 2009.3.2 +219.1) event: 进一步修改了几处BUG,并且增加了容错机制 + +218) 2009.3.1 +218.1) event: events_select, events_kernel, 修改了几处BUG + +217) 2009.2.28 +217.1) 增加了针对 epoll, devpoll 的支持,同时修改了 event 中的一些BUG + +216) 2009.2.17-2009.2.26 +216.1) 将 engine 目录改名为 event; 重新写了 event 事件循环的底层框架, +借鉴了一部分 nginx 中有关事件处理的方式, 同时保留了 postfix 原来的一部分 +处理方式,使事件循环机制更灵活、更可靠、效率更高,同时扩展性更好. +(目前仅支持 select 方式,很快将会支持 epoll, poll, kqueue, devpoll) +216.2) aio: 模块进行了优化调整,增加了一些方便使用的功能 + +215) 2009.2.16 +215.1) acl_aio_server.c: 优化与子进程与 acl_master 父进程之间的通信机制, +当客户端连接非常频繁时,通过减少与 acl_master 父进程之间的通信,提高了子 +进程的执行效率,并且大大减轻了 acl_master 的通信负载 +215.2) Makefile: 支持 make -j n 方式的编译(n 表示CPU核心数,由 Makefile +自动识别),从而在多核系统上大大提高了编译速度 + +214) 2009.2.12 +214.1) 在WIN32平台下将 acl_project/unit_test/ 的单元测试建立工程文件,这样 +可以对ACL采用单元测试了 + +213) 2009.2.11 +213.1) net/connect/acl_inet_connect: 在连接远程地址时,可以绑定本机的 +某个网卡的地址,对于多网卡机器比较有用 +213.2) include/master/acl_master_type.h: ACL_CONFIG_INT_TABLE, +ACL_CONFIG_STR_TABLE, ACL_CONFIG_BOOL_TABLE 定义成与 +stdlib/acl_xinetd_cfg.h 中的结构类型一致 + +212) 2009.1.18-2009.1.19 +212.1) feature: acl_pthread.c, 增加了 acl_pthread_atexit_add()/2, +acl_pthread_atexit_remove()/2 两个函数,这样用户线程可以通过此两个函数 +添加/删除线程局部变量,当线程退出时,将回调用户的用来释放线程局部 +变量的函数 +212.2) 修改了 thread/ 目录下源程序在分配/释放内存时调用底层内存操作的 +函数集(acl_default_xxx), 而是改为更通用的内存分配 acl_myxxx() 的操作方式; +同时在 stdlib/ 目录下增加了 local/ 模块,仅供ACL库内部使用 +212.3) samples: thread_pool/ 增加了线程局部变量的测试过程 + +211) 2009.1.13 +211.1) acl_myflock: 统一了在UNIX/WIN32平台下接口调用的方式 +211.2) proctl: 去掉了无用的 lockfile.c, lockfile.h, 并修改了调用 +acl_myflock()/3 的参数 +211.3) acl_mystring: 修改了几个字符串处理函数 + +210) 2009.1.12 +210.1) acl_vstream: 整理了头文件,将 ACL_VSTREAM 结构中的某些不用的成员 +去掉 +210.2) acl_aio_server, acl_ioctl_server, acl_single_server, acl_multi_server, +这几个模块允许以手工方式启动,以便于应用进行调试 + +209) 2009.1.10 +209.1) acl_vstream: 改变 acl_vstream_getc()/2 为 acl_vstream_getc()/1, +同时对外提供更高效的宏调用 ACL_VSTREAM_GETC()/1; 提供了标准输出函数 +acl_vstream_printf()/n +209.2) acl_vstring_vstream: 因为 acl_vstream 有些接口的改变而做相应的修改 + +208) 2009.1.9 +208.1) bugfix: acl_ioctl_server.c, 原来当 acl_master 重读配置后, 该服务器 +模板的子进程需要关闭监听流,但采用的是同步关闭方式,因为关闭监听流的线程与 +事件循环的线程的运行空间不同,容易造成冲突,现在将关闭流的操作放在定时器 +里进行,因为定时器的运行与事件循环的运行线程空间是相同的,所以不再会造成 +冲突现象。 +208.2) feature: acl_vstring_vstream.c, 增加了将 ACL_VSTRING, ACL_VSTREAM +结合的操作函数。 + +207) 2009.1.8 +207.1) feature: acl_htable 增加了两个函数接口 acl_htable_capacity() 和 +acl_htable_size() +207.2) feature: 从 Postfix 的代码中拷贝了 readline.c, readline.h, +split_nameval.c 至 acl 库中,命名为: acl_readline.c, readline.h +acl_split_nameval.c +207.3) acl_vstream: acl_vstream_fopen()/4 的参数去掉了最后一个参数(rw_timeo), +变为4个参数,因为对文件流来说读、写超时根本就没有什么意义;此外,在此 +changes.txt 文档中对于函数名的标识今后将采用 acl_xxxx()/n, n 表示参数的个数 +207.4) vc2003, vc2008 工程文件中漏掉的源文件: +proctl/lockfile.c, lockfile.h, stdlib/acl_meter_time.c, stdlib/acl_meter_time.h + +206) 2009.1.7 +206.1) feature: acl_aio_server, acl_multi_server 两个服务器模板现在均 +支持重读配置功能及软件在线升级功能; +206.2) acl_ioctl_server, acl_aio_server, acl_single_server,acl_multi_server +这些服务器模板都支持配置重读功能、软件在线升级功能; +206.3) acl_ioctl_server, acl_aio_server, acl_multi_server: 使用这些服务器 +模板的服务子进程在运行时,acl_master 主服务器可以重启;而如果使用 +acl_single_server 服务器模板的服务子进程在运行时, acl_master 是无法立即重 +启的,需要等待这类服务子进程退出后 acl_master 才可重启 + +205) 2009.1.6 +205.1) feature: acl_master 框架支持子进程崩溃报警机制 +205.2) acl_master: 支持重读配置功能的完善,目前支持该功能的模板有: +acl_ioctl_server, acl_single_server 两个模板,其它的模板需要再测试并完善 + +204) 2009.1.4 +204.1) bugfix: events_proc.c, events_thr.c 中的函数 event_loop() 中的 +wait_ring, ready_ring 两个变量是局部变量, 当调用 acl_event_disable_xxx +的时候会调用 event_fdtable_free, 而 event_fdtable_free 中的在调用函数 +acl_ring_detach 时便对上述两个临时变量进行了改写操作,当这种操作在 +event_loop() 循环外执行时便造成了内存非法访问. +204.2) feature: acl_master 服务器框架现在支持配置文件重读功能,从而可以 +实现所谓的程序热升级功能:) + +203) 2008.12.30 +203.1) doc: 头文件中修改了不符合 doxygen 注释规范的注释方法 + +202) 2008.12.29 +202.1) feature: thread/acl_pthread_pool 中增加了创建线程池的简单函数 +acl_thread_pool_create +202.2) comment: acl_scan_dir.h 中完善了注释 + +201) 2008.12.23 +201.1) compile: acl_pthread_xxx 函数库在 FreeBSD 及 WIN32 平台下编译错误问题 + +200) 2008.12.22 +200.1) 在FreeBSD 6 上编译ACL工程 +200.2) bugfix: master/template/acl_ioctl_server.c: 在使用 getopt() 前因为初始化了 +getopt() 中的全局变量,从而影响了参数传递, 这种情况在BSD上会发生 +200.3) compile: 将 samples/ 目录下的工程文件进行了整理 +200.4) 将 ACL 工程命名为 acl_project.2.0.1 + +199) 2008.12.20-12.21 +199.1) 在 vc2008 上编译通过 +199.2) 重新组织了VC2003的编译工程 +199.3) 重新组织了VC6的编译工程 +199.4) 增加了一些头文件的注释 +199.5) thread: 增加了线程池模块,将用它取代老的线程池模块 (acl_workq) + +198) 2008.12.12-12.16 +198.1) comment: 为了生成 doxygen 文档,增加了许多注释 +198.2) compile: 在 Redhat AS5 上编译通过 +198.3) acl_socket_init 初始化时在UNIX平台下自动调用了 signal(SIGPIPE, SIG_IGN) + +197) 2008.12.8 +197.1) feature: code/acl_urlcode.c, 增加了 url 编解码函数库 +197.2) samples: samples/urlcode/, 增加了 url 编解码的测试用例 + +196) 2008.12.2 +196.1) acl_vstream.c: 为了避免因为缓存 fseek 位置而造成的副作用,提供一 +个开关用于控制是否需要进行 fseek 位置缓存,可以通过调用 acl_vstream_ctl() +并设置标志位 ACL_VSTREAM_CTL_CACHE_SEEK 来达到此目的. + +195) 2008.12.1 +195.1) performance: acl_vstream.c, acl_vstream_fseek() 进一步提高了执行 +效率, 只要读缓冲区数据还在并且未被破坏,就可以在调用 fseek 时,通过移动 +缓冲区的指定位置就能重复利用缓冲区里的数据,从而大大减少调用系统调用的 +次数. + +194) 2008.11.30 +194.1) performance: acl_vstream.c, acl_vstream_fseek() 通过缓冲策略提高 +了执行效率 +194.2) samples: vstream_fseek/, watchdog/, base64/ + +193) 2008.11.28 +193.1) bugfix: proctl/proctl_service.c, proctl_service_exist() +判断服务是否在运行的条件有误, 该库仅在WIN32下有效 + +192) 2008.11.23-11.24 +192.1) feature: acl_chunk_chain.c, 该文件主要实现了数据块连的虚拟连续块 +的功能,内部自动处理数据缓冲、纠错等功能,可以将无序的数据流转为有序的 +数据流 +192.2) samples: chunk_chain, 测试虚拟数据链的例子 + +191) 2008.11.20 +191.1) bugfix: proctl/acl_proctl.c, acl_proctl_child() 及 +acl_proctl_deamon_init() 函数内部在创建线程时应该设置新线程的创建属性为 +detached 状态,否则会引起资源泄漏问题 + +190) 2008.11.19 +190.1) bugfix: proctl/acl_proctl.c, acl_proctl_deamon_init() 函数在创建 +线程时没有初始化 attr 参数,从造成新线程无法正常启动 +190.2) acl_define_win32.h: 为了增加对VC6的兼容性,增了宏“if(_MSC_VER >= 1300)” +以决定是采用 winsock.h, 还是 winsock2.h + +189) 2008.11.18 +189.1) feature: stdlib/debug/, 增加了针对ACL库的内存泄漏与内存越界的访问 +检测 +189.2) samples: debug_malloc/ 内存检测的例子 +189.3) bugfix: acl_aio_read.c 中原来在调用 read_fn() 回调后才清空 strbuf +缓冲区,这样当发生嵌套时,依然可能存在该缓冲区内的数据被重复利用的情形, +现在采用的策略是先取得 strbuf 的缓存地址及缓存数据长度,然后将该 strbuf +复位(但不破坏具体数据内容),然后再调用 read_fn() 并将预先取得的缓存地址 +及缓存数据长度传递进去,从而彻底地避免了在调用 read_fn() 内部的多次递归 +嵌套过程的 strbuf 里的数据被重复利用 + +188) 2008.11.17 +188.1) feature: 增加了 acl_mem_hook.c 函数接口,使调用者可以注册自己的内存 +分配与释放函数 + +187) 2008.11.14 +187.1) bugfix: acl_vstream.c, 其中的 __vstream_sys_readn() 的读超时操作在 +WIN32平台下是被 undef 而关闭的,所以WIN32的超时读不超作用,现在将WIN32平台 +下的读超时功能打开 +187.2) feature: net/acl_tcp_ctl.c, 添加了 acl_tcp_so_linger() 封装,用户 +可以在通过此函数设置当套接口关闭时是否立即关掉,即避免 TIME_WAIT 状态的出现, +这样可以当套接口频繁地打开关闭时有效地节约TCP的端口号,但也可能产生一定的 +副作用 + +186) 2008.11.13 +186.1) thread/acl_pthread.c: WIN32平台下,当没有调用acl_pthread_init()时, +内部在创建线程时采用CREATE_SUSPENDED的创建模式,当在创建线程中必要的初始化 +完成后再ResumeThread()新创建的线程,从而可以保证即使用户没有调用 +acl_pthread_init()的前提下依然保证创建线程的理论安全性;如果用户预先调用了 +acl_pthread_init()函数,则内部会通过线程锁的方式来避免创建线程时理论上的 +安全问题。 + +185) 2008.11.12 +185.1) bugfix: stdlib/string/acl_mystring.c 中的 acl_mystrline() 函数存在bug, +从而会影响使用该函数的 acl_xinetd_cfg.c 以及 master 服务器框架中的读配置文件 +的操作 +185.2) feature: stdlib/common/acl_htable.c 添加了 acl_htable_last_errno() 以 +及 acl_htable_set_errno() 两个函数,使应用可以判断操作完哈希表后的错误状态, +目前仅在哈希表添加时设置了错误状态. 错误号为:ACL_HTABLE_STAT_DUPLEX_KEY + +184) 2008.11.10 +184.1) thread: 增了 acl_pthread_init()/acl_pthread_end() 函数,从而避免了 +理论上在WIN32平台下创建线程时的acl_pthread_creeate句柄赋值与 RunThreadWrap() +内部使用线程句柄的可能存在的冲突问题 +184.2) 添加了 init/ 模块,主要用于ACL库内部的初始化工作, 用户只需要调用一次 +acl_init(), 该函数内部就会自动将有关WIN32下的SOCKET、THREAD以及UNIX下的signal +进行了初始化 + +183) 2008.11.9 +183.1) thread: 进一步完善了WIN32平台下的POSIX函数库 + +182) 2008.11.8 +182.1) thread/: 完善了 acl_pthread_join 函数等POSIX标准的函数,同时添加了 +acl_pthread_detach() + +181) 2008.11.7 +181.1) bugfix: acl_mystring.c->acl_mystrline() 在解析以 "\r\n" 为回车换行符时 +有一处BUG,从而影响使用它来分析配置文件的函数库的分析结果(acl_xinetd_cfg.c) +181.2) performance: acl_mystring.c->acl_mystrline() 内部遇到特殊标志位时会有 +多次数据的移动过程(即调用:memmove()),现在修改成最多只移动一次的方式 + +180) 2008.11.6 +180.1) bugfix: acl_aio_read.c, 在所有的调用 astream->read_fn() 之后都应 +添加 ACL_VSTRING_RESET() 以防止旧数据被重复利用 +180.2) performance: stdlib/charmap.h, 添加了字符串转换映射表,从而使 +strcaseXXX类操作更加快捷 +180.3) net/dns: rfc1035 模块进一步完善功能实现 +180.4) stdlib/configure: 增加了方便读配置文件的操作功能 + +179) 2008.11.5 +179.1) feature: acl_dlink.c, acl_dlink_lookup_larger() 函数,可以查 +出大于等于某个值的所有结点集合; acl_dlink_lookup_lower() 函数,可以查出 +小于等于某个值的所有结点集合;不过这两个函数内部是顺序查找的,如果数据结点 +比较多时,效率会比较低,将来应该都改成二分查找 +179.2) performance: strcasecmp, strcasencmp, 两个函数采用了更高效的做法 +179.3) bugfix: acl_aio_read.c, acl_aio_readn() 中,应该将 +" astream->count = count; " 放在函数开始;__readn_notify_callback() 中 +调用 "astream->read_fn" 后增加 "ACL_VSTRING_RESET(&astream->strbuf);" +以避免 fatal 错误 + +178) 2008.11.3 +178.1) feature: acl_dlink.c, 增加了 acl_dlink_lookup_range()函数,可以方便 +查询某个范围的数据结点是否存在 + +177) 2008.10.31 +177.1) feature: acl_dlink.c, 增加了 acl_dlink_delete_range() 函数,可以方便 +地从数据链中删除某个范围内的数据结点 +177.2) feature: acl_array.c, 增加了 acl_array_delete_range() 函数,可以方便 +地删除某个下标范围之间的数组结点 + +176) 2008.10.27 +176.1) feature: C99标准增加了针对线程局部存储的易用性处理,只要在变量前增加 +宏:__thread 则该变量就被声明为一个线程局部变量,如:函数内部用的线程局部变量 +static __thread int i = 0; 如果是外部可用的线程局部变量,则在 .c 文件中声明为: +__thread int i; 然后在 .h 头文件中声明:extern __thread int i; +windows 下从VC7开始也支持C99标准,但若要在WIN32下用这个特性,需要在变量前增加 +__declspec(thread),为了使用的一致性,在 acl_define_win32.h 中将这个统一声明为 +__thread; 但在UNIX下的Makefile文件用GCC编译时需要把 -pedantic 选项去掉,因为 +它是C89的标准 +176.2) samples: thread/ 下的例子说明了C89关于线程局部变量存储的使用例子 + +175) 2008.10.26 +175.1) feature: acl_dlink.c, 增加了两个接口 acl_dlink_lookup2_by_item, +acl_dlink_lookup2, 可以在查询数据结点时同时取得该结点的下标值 + +174) 2008.10.21 +174.1) feature: acl_sys_patch.c, 增加了 win32 下的 gettimeofday 实现 +174.2) feature: acl_netdb.c, 扩展了一些结构成员,同时增加了如下函数: +acl_netdb_refer_oper, acl_netdb_refer, acl_netdb_unrefer, acl_netdb_add_addr + +173) 2008.10.17 +173.1) feature: 增加了线程堆栈空间大小的设置功能,涉及的文件有: +acl_pthread.c/h, acl_workq.c/h, acl_ioctl.c/h, acl_ioctl_server.c, +acl_ioctl_params.h +acl_pthread.c: acl_pthread_attr_setstacksize +acl_workq.c: acl_workq_set_stacksize +acl_ioctl.c/h: ACL_IOCTL_CTL_THREAD_STACKSIZE +acl_ioctl_server.c: acl_var_ioctl_stacksize +acl_ioctl_params.h: ACL_VAR_IOCTL_STACKSIZE, ACL_DEF_IOCTL_STACKSIZE + +172) 2008.10.10 +172.1) samples: 增加了一个非常有用的HTTP客户请求的例子 http_client/ + +171) 2008.10.9 +171.1) workaround: 重新整理了VC6、VC2003编译环境下的工程组织,将动态库以 +lib_acl.dll, lib_acl.lib, lib_acl_d.dll, lib_acl_d.lib 命名,将静态库以 +lib_acl_vc6.lib, lib_acl_vc6d.lib, lib_acl_vc2003.lib, lib_acl_vc2003d.lib +命名,其中动态库是用VC2003编译的,可以在VC6下使用 +171.2) samples: 增加了VC6环境的 samples 工程,目前为了测试仅添加了两个 +工程(vstream.dsp, vstring.dsp) + +170) 2008.10.8 +170.1) master 框架: 增加了 acl_tcp_defer_accept() 可配置功能,使用者可以 +在配置文件中指定是否针对客户端连接采用无数据延迟接受功能, 修改的文件有 +master.h, master_ent.c, master_listen.c +170.2) acl_inet_listen.c: 去掉了默认的 acl_tcp_defer_accept() 调用,使用 +者若要使用此功能,可以创建监听套接口后手工进行设置 + +169) 2008.10.7 +169.1) 编译:VC 编译动态库的DEBUG版本或编译可执行程序的DEBUG版本时,默认 +的增量链接会增加 *.ilk 文件,但在编译清除时如果设置的最终输出路径不是VC +默认的,则这些 *.ilk 文件,有可能是VC开发环境的一处BUG,所以现在关闭了 +VC的增量链接的功能 +169.2) samples/proctld 模块编译出错,进行了修复 +169.3) 当将ACL库编译成动态链接库时,其它库或程序使用ACL动态库时应该添加 +预定义:ACL_DLL +169.4) include/stdlib/acl_define_win32.h: 因为VC编译器自动在预处理处添加 +预定义选项: WIN32, 所以在该文件中做了默认处理,如果遇到此预定义,也默认 +认为是VC编译器 + +168) 2008.9.29 +168.1) feature: 修改了所有头文件的函数定义,添加了 ACL_API 定义,允许 +以DLL方式引出, 可以方便其它编程语言使用ACL库,当其它应用以DLL方式使用 +ACL库时,需要增加一个预定义宏:ACL_DLL + +167) 2008.9.27 +167.1) bugfix: events_proc.c, 调用 select() 后,如果返回值 -1, 且 error +为 EINTR, 则需要返回,但没有将 eventp->nested 恢复,则造成下一次调用 +event_loop() 时,触发了 "if (eventp->nested++ > 0)" 条件, 该BUG会影响 +acl_master, 基于 master 框架的 aio 框架实例 + +166) 2008.9.26 +166.1) acl_vstream.h: 整理了文档的注释格式,使之更符合 JAVA-DOC 格式 +166.2) acl_vstream.c: 增加了 acl_vstream_fhopen() 接口,从而更加兼容win32 +166.3) acl_myloc.c: 增加了 acl_log_fp() 接口 + +165) 2008.9.22 +165.1) mempool/acl_allocator.c: 增加了接口 acl_allocator_ctl() 以方便 +控制内存池的缓存的最小/大字节数 + +164) 2008.9.19 +164.1) proctl: 调整了 acl_proctl_start_one() 及 acl_proctl_stop_one() +的参数入口,所有参数的轮换工作均内部解决,应用不必在参数里添加双引号 +164.2) compile: 消除了几处在 C++ Builder6 上的编译警告 +164.3) acl_hash.c: 将 crc64 名称修改为 acl_hash_crc64 +164.4) 重新在各个平台及编译器上编译通过 +164.5) acl_aio_read/write: 在调用 XXX_SAFE_IOCP 后不应再对 astream 进行 +任何操作,否则会造成操作非法指针的错误 + +163) 2008.9.18 +163.1) proctl: 该模块在参数处理等方面有些问题 + +162) 2008.9.11 +162.1) acl_vstream: 支持套接字的 writev 模式,且保证全部数据完整写入 +162.2) samples/vstream: 增加了几个测试函数 +162.3) samples/master/: 整理了几个 Makefile 文件 + +161) 2008.9.10 +161.1) 内存池的缓存对象大小最大可以达到1M,也许应该加个开关控制一下 +是否需要大内存的缓存 +161.2) acl_sys_patch.c: 支持套接字的 writev 模式 +161.3) acl_vstream.c: 支持套接字的 writev 模式 +161.4) acl_aio_write.c: 支持套接字的 writev 模式 + +160) 2008.9.9 +160.1) 新版本的 acl 库在各个平台上编译通过 + +159) 2008.9.4-9.8 +159.1) engine/events_proc.c: 修改了几处与 Linux epoll 相关的几处BUG, +从 postfix 中继承了有关 epoll 的相关代码,但 postfix 中对读写事件的要求 +是不能同时将某个套接字置于读写监控集合中,并且其仅实现了 +event_disable_readwrite 接口,但 acl 库中的 events_proc.c 中却允许同时 +对同一套接字进行读写监控,并且增加了 event_disable_read, event_disable_write +两个接口,所以原 postifx 中的有关 epoll 的调用在 acl 中就会出现错误, +现在已经进行了修正,使 acl 库可以非常方便地支持 Linux 下的 epoll 调用, +只需要打开 lib_acl/src/engine/events_define.h 中的 ACL_EVENTS_KERNEL +定义即可 +159.2) aio/: 原来的 acl 库中的非阻塞 IO 即 aio 模块对于读操作的处理方式 +是当某个套接字的读事件满足时,便将其从读监听集合中去除,读操作完成后再 +将该套接字往读监听集合中添加,这样就造成了两个费时的操作(尤其是对采用 +epoll 类似的方法),现在将异步读操作设置为一直可读,真到应用想要关闭该 +套接字或明确禁止继续读为止;acl_aio_write 模块的嵌套处理存在问题,因为 +在一处函数返回时未将嵌套层数减一,导致对一个长连接的套接字来说,在达到 +写嵌套层数限制后,以后的每一次写操作都要通过将写事件进行监听然后通过写 +事件满足时的回调方式完成,这样大大降低了非阻塞写的效率(实践证明,修改 +此BUG的后,基于 acl 库编译的 webserver 性能提高了2000次每秒;在 +acl_aio_listen 中增加循环接收外部连接功能,大大提高并发连接性能; 整理了 aio +模块的相关代码,修改了有关接口 +159.3) acl_aio_create 调用时可以通过将 accept_max 参数设置为大于1的 +值以提升监听套接字接收并发连接的性能,实践证明如果该值为1且acl_vstream_listen +的监听队列比较小时(如小于64),则有可能造成一定的接收延迟 + +158) 2008.9.1-9.3 +158.1) socket performance: 在测试基于 acl_aio_xxx 库编写的HTTP服务器时, +(用Apache 的ab工具测试) 发现长连接的效率反而比断连接的效率低,经过仔细 +排查,发现是因为测试时因为是用了小数据包,则操作系统自动启动 Nagle 算法, +从而造成了一定延迟,为了避免此种情况,修改了 acl_sane_accept, +acl_sane_connect 两个函数,自动启用 TCP_NODELAY 传输策略,避免因 Nagle +可能造成的延迟现象(虽然有可能会降低一些网络性能) +158.2) net/acl_tcp_ctl.c: 增加了acl_tcp_nodelay接口,可以开/关某个套接口 +的 TCP_NODELAY 传输策略 +158.3) feature: 增加了程序效率测试接口,stdlib/acl_meter_time.c, 从而可以 +方便应用通过调用宏 ACL_METER_TIME("your info") 来测试每个执行函数的执行时间, +在测试 158.1) 的因 Nagle 而造成的时间延迟时,该函数库起了非常重要的作用 +158.4) acl_fifo.c: 增加了更多的接口,同时将结构类型定义引出至头文件中, +这样用户可以在栈上分配队列对象 +158.5) acl_aio: 优化了结构设计,将一些需要多次动态分配的对象进程合并,减少 +动态分配内存的操作次数 +158.6) acl_vstring: 为 acl_aio 的优化增加了 acl_vstring_free_buf 函数 +158.7) sample: fifo 增加了测试例子 + +157) 2008.8.27 +157.1) 内存分配:因为将整个 acl 工程基于内存池进行了重新构建,会导致有些 +内存分配计数不准;当采用内存池时,有些函数库可能存在内存泄露问题 +157.2) acl_vstream.c: 将所有的回调释放函数 acl_myfree_fn 去掉,采用直接 +的内存释放方式;将 acl_array_delete_idx 的调用放在 close_fn 调用之前,以 +防止用户在 close_fn 内部调用 acl_vstream_delete_close_handle 时造成内存 +非法重复释放 +157.3) samples/master/ioctl_echo, aio_echo: 所给的例子有一处错误,当配置 +文件里没有 master_env 时,没有判断 getenv() 返回 NULL 的情形 + +156) 2008.8.26 +156.1) 内存分配:重新将一些函数名进行重命名 +156.2) 编译:将整个工程在VC6上成功编译,同时将win32平台下的的库名加后缀, +即 lib_acl_vc6.lib, lib_acl_vc2003.lib, lib_acl_cb6.lib + +155) 2008.8.23-25 +155.1) 内存池:将 acl 库基于内存池进行重新构造, 与之相关的修改文件有 +acl_malloc.c, acl_mylog.c, acl_allocator.c mem_pool.c, squid_allocator.c +vstring_pool.c, etc, 并创建单独的目录 mempool/ 将内存池做为 acl 工程 +中 stdlib/ 下的一个单独模块 +155.2) acl_stack.c: 重新进行了设计与改写, 增加了迭代器等功能 +155.3) unit_test: 增加了针对 acl_stack 模块的单元测试 +155.4) master/aio, iotcl: 服务模板增加了采用内存池的功能 + +154) 2008.8.22 +154.1) acl_mymalloc.c: acl_mymalloc(), acl_myfree() 去掉了 memset() +的操作,该操作当分配的内存比较大时会比较耗时 +154.2) acl_allocator: 内存池模块重新进行了整理 +154.3) samples/mempool: 增加了内存池的测试例子 + +154) 2008.8.21 +154) acl_vstring.c: acl_vstring_sprintf_prepend 存在一处潜在的指针BUG + +153) 2008.8.20 +153.1) acl_mylog.c: 打开文件时,在UNIX平台下对 打开的文件描述符增加了 +acl_close_on_exec 功能,以防止父进程的文件句柄被传递给子进程 +153.2) master 框架: 使子进程可以以普通用户身份运行,并且在子进程切换 +身份前可以先借用 acl_master 主进程的日志文件进行记录,当子进程切换为 +普通用户身份后便使用自己的日志文件进行中记录 +153.3) acl_master 安装包进行中了相应的整理,在安装时为了保证切换为普通 +用户身份的子进程记录日志,将 var/log 目录的权限设置设置为 1777; 将安装 +包中的服务配置例子放置在 conf/service/samples/ 目录下 + +152) 2008.8.18 +152.1) 重新整理了 acl_master 服务器框架,可以无缝地与第三方日志记录库 +进行集成 +152.2) feature: acl_master 可以根据配置文件(main.cf) 中的 scan_subdir +选项来判断是否需要启动配置服务子目录下的服务程序 +152.3) feature: 每个服务的配置文件里增加了 master_env 环境变量配置项, +使得 acl_master 进程可以将该环境变量传递给服务子进程 +152.4) 重新整理了 samples/master/ 下的例子 + +151) 2008.8.14 +151.1) feature: acl_vstream,使 ACL_VSTREAM_IN, ACL_VSTREAM_OUT, +ACL_VSTREAM_ERR 可以在WIN32下正常使用,但如果想要使用这些标准输出、输入, +需要提前调用 acl_vstream_init() 进行初始化 +151.2) samples: 增加了测试 ACL_VSTREAM 流的例子--samples/vstream + +150) 2008.8.12 +150.1) bugfix: acl_ioctl.c 中的 __on_thread_init 及 __on_thread_exit +的参数检验有误,且传递给回调函数的参数有误 + +149) 2008.8.7 +149.1) 工程管理: 重新整理了各个平台下的编译工程 +149.2) experiment: avl 库可以在64位LINUX下编译通过 +149.3) unit_test: 增加了针对 avl 的单元测试用例 +149.4) compile: 重新在SUNOS-X86上编译通过 + +148) 2008.7.30 +148.1) samples: 整理了一下 samples/master/ 下的几个例子,以便于使用 + +147) 2008.7.23 +147.1) samples: 增加并完善了带WIN32界面的 FileDir 例子,该例子即可以统计目录, +又可以测试AVL树(移植于 OpenSolaris) + +146) 2008.7.19 +146.1) feature: acl_scan_dir 模块更加完善化,增加了许多有用的接口,可以方便 +地设置回调,还可以方便数据统计 +146.1) samples: FileDir(win32) 扫描目录的程序,类似于WIN32的统计目录程序 + +145) 2008.7.17 +145.1) feature: proctl 模块增加了服务子进程退出时的回调函数及回调参数功能 +145.2) feature: acl_scan_dir 模块增加了 acl_scan_stat() 函数,可以非常 +方便地(象标准的 stat 函数一样)取得当前所扫描的文件或目录的属性信息 + +144) 2008.7.15 +144.1) feature: proctl/ 增加了在WIN32平台进行父子进程控制的模块,支持 +启动、停止(某个服务或所有服务)、退出、列表、探测功能 +144.2) feature: 完善了WIN32平台下文件锁的功能 +144.3) msg/acl_aqueue.c: acl_aqueue_pop_timedwait() 的时间参数允许均为0 +的情形,以前的做法是如果全为0则无限期等待直至出错或等待某个条件正常返回, +现在可以当队列里无数据时立即返回 +144.4) compile: 重新在 VC2003, CB++, GCC 下编译通过 + +143) 2008.7.4 +143.1) feature: 增加了 engine/acl_timer.c, 该库实现了定时任务的管理功能 + +142) 2008.6.30 +142.1) 增加了二叉树的算法(DEBUG版本): acl_btree.c +142.2) 增加了WIN32平台下的文件锁机制: acl_myflock.c +142.3) acl_vstream.c: 增加了 acl_file_ftruncate(), acl_file_truncate() + +141) 2008.6.25 +141.1) acl_vstring.c: 增加了 acl_vstring_memchr,acl_vstring_strcasestr, +acl_vstring_strstr,acl_vstring_insert,acl_vstring_prepend, +acl_vstring_sprintf_prepend 函数 +141.2) samples: 增加了 vstring 测试函数 + +140) 2008.6.23 +140.1) acl_vstream.c: 针对WIN32平台,因为API不支持APPEND模式,所以在 +ACL_VSTREAM 结构中增加了一个标志位,用于当用户设置O_APPEND后可以保证 +在写时在文件结尾处写(调用__vstream_sys_write时)(但目前还不完全遵守规范 +--加锁移至文件尾) + +139) 2008.6.18 +139.1) acl_mystring.c: 增加了 strcasestr + +138) 2008.6.17 +138.1) acl_fifo.c/acl_fifo.h: 增加了 iterator 功能 +138.2) samples: 测试 ACL_FIFO 的例子 + +137) 2008.6.4 +137.1) 在64位Redhat Linux编译通过 +137.2) 调整了VC下的工程文件 + +136) 2008.6.3 +136.1) acl_mymalloc.h, acl_mymalloc.h: 增加了方便调试的接口, 将函数 +调用统一修改为宏调用,这样可以方便查出调用者真实的文件位置 +136.2) master/, ioctl/: 增加了线程初始化回调函数及线程退出回调函数, +master/template/acl_ioctl_server.c: 模板增加了线程初始化及线程退出 +的回调函数; samples/master/ioctl_echo/app_main.c(.h) 也增加了线程 +初始化及线程退出的回调函数 +136.3) unit_test: stdlib/test_malloc.c, 测试内存分配时如果参数有误 +能否打印出调用者所在的源程序位置 + +135) 2008.5.29 +135.1) acl_make_dirs.c: 完全支持WIN32平台下创建各级目录 + +134) 2008.5.5 +134.1) feature: 针对 master 框架,将读取配置项的功能移至公用接口,这样 +应用可以比较方便地读取自己的数据 +134.2) bugfix: acl_inet_listen() 当监听一个已经被监听的地址时,日志记 +录不下来,原因是在 bind() 后的日志记录语句中的各个参数的顺序不对 + +133) 2008.4.30 +133.1) bugfix: db/memdb/acl_mdt.c 中的 acl_mdt_delete() 函数有一处BUG, +不能正确删除相关联的数据项 + +132) 2008.4.29 +132.1) feature: db/memdb, 增加了 acl_mdt_list 接口可以顺序列出某个范围 +的结果集; acl_mdt_walk 增加了范围遍历参数 + +131) 2008.4.28 +131.1) bugfix: stdlib/acl_vstream.c, acl_vstream_probe_status() 在UNIX +环境下没有将套接口设置为非阻塞模式,所以会导致调用该函数的调用阻塞,因 +为 db/null/ 连接池的缺省探测连接的方式调用了此函数,所以导致了阻塞现象 +131.2) feature: db/ (数据库)连接池模块允许用户自己设置自己的探测模块 +131.3) feature: db/ 增加手工强制检查连接池连接的函数 + +130) 2008.4.24-4.25 +130.1) performance: master 框架中的针对多线程的服务器框架做了优化,避免 +了在多线程事件循环的情况下的延迟现象; 所改动的与之相关的模块有 +engine/, ioctl/, master/template/acl_ioctl_server.c +130.2) feature: stdlib/common,增加了一个新的CRC64的算法,由郭朝辉根据 +相关资料进行修改提供 + +129) 2008.4.23 +129.1) feature: db/memdb,增加了探测某个字段值是否存在于数据表中的函数 + +128) 2008.4.21 +128.1) 在BORLAND CBuilter6 上编译通过 +128.2) db/memdb: 整理了相关接口,使调用更方便,效率更高 +128.3) bugfix: acl_vstream.c 中对 wbuf_size 的初始赋值有误,误取为 +sizeof(stream->wbuf_size) - 1,应该为 sizeof(stream->wbuf),因为此错误 +会大大降低 acl_vstream_buffed_writen 的效率,当连续写很少字节时,因为 +系统默认采用 TCP_NODELAY,所以还可能会造成延迟! +128.4) bugfix: db/ 连接池有几次错误,进行了修改 + +127) 2008.4.19 +127.1) bugfix: acl_sys_patch.c 中的 acl_file_open 在WIN32下的实现有些 +问题,重新进行了修正 + +126) 2008.4.17 +126.1) bugfix: acl_vstream_fileno, ACL_VSTREAM_FILENO 两个调用存在问题, +因为之前将 ACL_VSTREAM 的中的句柄针对套接字及文件句柄做了区分, 而这两 +个宏没有进行区分, 现在已经根据 stream->type 的类型进行了区分, 现在分别 +用 ACL_VSTREAM_SOCK, ACL_VSTREAM_FILE 两个宏来取得套接字或文件句柄 +126.2) stdlib/acl_vstream.c: 重新整理了数据流通信库 + +125) 2008.4.16 +125.1) db/memdb: 将内存数据库的内部使用的ACL_RING修改为自身单独使用 +的 MDB_RING, MDB_RING 中比 ACL_RING 减少两个字段从而减少了内存的占用; +增加了内存检测机制;增加了索引字段的约束性添加功能 + +124) 2008.4.15 +124.1) examples: 增加一个小工具,可以将源程序的格式转换成: +UNIX, DOS, MAC 三种格式 +124.2) 用上述小工具将 acl 工程统一转换成UNIX的文件格式 + +123) 2008.4.9 +123.1) db/null, 利用数据库连接池框架增加了TCP连接池库 + +122) 2008.4.3 +122.1) 修改了内存数据库,增加了数据结点的克隆功能, 即对于用查询 +结果生成一个结果集时调用用户设置的回调函数,避免了线程不安全隐患 + +121) 2008.4.2 +121.2) acl_define_linux.h: 当用 g++ +编译时,_GNU_SOURCE会被自动定义,则出现重复定义 _LARGEFILE64_SOURCE + +120) 2008.3.29-4.1 +120.1) 重新设计了内存数据库模块(db/memdb/),支持更方便的哈希关系查询与添加 +删除,去掉了可能会影响性能的动态数组部分,改用双向链表方式,从而避免了数据 +结点的移动;编写了测试用例 samples/memdb/ +该内存数据库模块的特点: +1、对同一数据采用不同的关键字段进行索引 +2、支持多个数据库句柄,多个数据表句柄 +3、添加、查询、删除都是采用哈希定位方式 +4、大量采用双向链表,取代动态数组,以提高删除、添加时的性能 +5、将影响内存空间的数据结构对象尽量压缩至最小(还有些需要优化压缩的地方) + +119) 2008.3.27 +119.1) compiling: 在LINUX编译通过 + +118) 2008.3.25 +118.1) bugfix: 在 acl_aio_xxx 中,因为异步读写可能会被嵌套调用,这样有可能 +会返回 -1 的值,从而使调用这些函数的应用如:http_chat_async.c 的读误以为出 +了错,现在统一将 acl_aio_read, acl_aio_readn, acl_aio_gets, acl_aio_gets_nonl, +acl_aio_writen, acl_aio_vfprintf, acl_aio_fprintf等函数的返回值为 >=0,调用 +这些函数的过程不应从这些返回值中判断是否读写成功,而应从回调函数中进行判断, +因为异步读写过程都是异步的,为了避免引起混乱,现已经将这些函数的返回值为 void + +117) 2008.3.20 +117.1) 将新版本在LINUX下编译通过 +在Linux下,需要在Makefile文件的编译选项中添加 -Wno-long-long 从而支持 +long long 类型 + +116) 2008.3.19 +116.1) feature: 增加了对64位系统的一些支持,同时支持在32位系统上模拟64位的一些 +特征,修改的相关文件有: +acl_define_linux.h, acl_define_win32.h, acl_mystring.h, acl_sys_patch.h, +acl_vstream.h, acl_define.h, acl_dlink.h, acl_msg.c, squid_allocator_tools.c, +acl_sys_patch.c, acl_vstream.c, acl_dlink.c, acl_mystring.c, acl_vstream_net.c, +116.2) feature: 在WIN32平台下,对文件的操作直接用WIN32的API,从而支持大文件的 +读写等操作;支持LINUX平台下大文件的操作, 需要在 acl_define_linux.h 中提前定义 +# define _LARGEFILE64_SOURCE +# define _FILE_OFFSET_BITS 64 +在 acl_vstream.c 中打开文件时需要指定 O_LARGEFILE 打开参数 +116.3) comment: acl_mystring.h 增加了比较详细的头文件中函数接口注释 +116.4) 内部使用 snprintf 函数时使用系统默认的 snprintf, 在WIN32平台下是 _snprintf + +115) 2008.2.20 +115.1) bugfix: acl_dlink.c, acl_iplink.c, 之前针对 begin = 0 时不能进行插入操作 + +114) 2008.2.19 +114.1) performance: acl_vstream.c 中,之前未启用读字符加速宏定义 + +113) 2008.2.3 +113.1) feature: 增加了类似于 squid 的分级记录日志的函数库 acl_debug.c/acl_debug.h +113.2) 将 acl_argv_split.h 去掉,其中的函数声明合并至 acl_argv.h 中 + +112) 2008.2.2 +112.1) feature: 重新整理了 acl_iplink 库,将其修改为 acl_dlink 从而使二分块查找算法 +更加通用,将来 acl_iplink 将从 acl_dlink 中继承 + +111) 2008.1.29 +111.1) vc 工程文件修改: 将 debug 类的库的名后添加 _d, 如 lib_acl.lib 的 debug 版本名 +为 lib_acl_d.lib,以下是各个版本的DEBUG版本名称: +lib_acl_d.lib, lib_acl_mysql_d.lib, lib_protocol_d.lib +以下是RELEASE版本名称: +lib_acl.lib, lib_acl_mysql.lib, lib_protocol.lib + +110) 2008.1.24 +110.1) Bugfix: acl_ring.c, 在 acl_ring_append(), acl_ring_prepend() 两个函数中, +新插入结点的 parent 不应是 ring, 即 entry->parent 不应是 ring, 而 应是 ring->parent, +这样才能保证所有结点的 parent 都指向同一个 ring header, 否则会造成内存非法越界问题, +该问题是在反复测试 unix_trigger.c 的功能时候检测出来的, 因为在测试触电发器的问题时, +发现如果启用 unix_trigger.c 中的 __USE_TIMER, 则当触发器的触发时间小于每个用于触发器 +的套接口的超时时间时会发生内存越界问题, 用系统工具 valgrind 测试非常容易发现此问题, +为了找出此问题,花费了许多时间,也走了很多弯路,如今,一个偶然的现象才使本人发现问题 +的本质不在于触发器,而在于 acl_ring.c 中对 parent 对象的引用存在问题。呵呵,好难发现 +的BUG,valgrind is very good! + +109) 2008.1.16 +109.1) acl_vstream.c: 全程跟踪某个套接口的总写入字节数及总读出字节数 +109.2) acl_vstream.c: acl_vstream_xxx_ready 类型的函数进行了整理,使逻辑更清晰 +109.3) acl_aio_read.c: 增加了针对非阻塞错误号 ACL_EWOULDBLOCK, ACL_EAGAIN 的处理 +109.4) acl_aio_read.c: 整理函数,使逻辑更清晰 +109.5) acl_aio.c: acl_aio_open() 中强制将套接字转为非阻塞模式 +109.6) acl_inet_listen.c: 增加了延迟接收的功能(TCP_DEFER_ACCEPT),默认的延迟 accept +时间为30秒。 + +108) 2008.1.15 +108.1) acl_dbpool_mysql.c: 一些日志的记录增加了开关设置,即可通过 acl_msg_verbose控制 + +107) 2008.1.10 +107.1) acl_netdb_cache.c: DNS缓存链表的顺序有问题,进行了修复。 + +106) 2008.1.9 +106.1) acl_htable.c: acl_htable_enter, acl_htable_enter_r 中针对添加重复KEY时增加了 +日志警告,用户不应添加重复KEY,否则将会导致内存泄漏现象。 + +105) 2008.1.8 +105.1) bugfix: acl_http_header.c->__add_request_item,__add_cookie_item,中对变量对 +的存储原来未处理重复变量名的情况,会导致内存泄漏,不过该HTTP库将来将被从基础的ACL库 +中去掉,并且该部分函数除了BUG修复外不再做升级,另一个项目:lib_protocol 将提供更加 +好的针对各种协议处理的解决方案。 + +104) 2008.1.7 +104.1) 重新整理了 acl_define.h 文件,将与WIN32相关的定义归为一个单独的文件 +acl_define_win32.h,这样 acl_define.h 就比较清晰了。 +注:由于VC在 extern“C++”方面的限制,会导致编译器出现如下致命错误: +"fatal error C1045: 编译器限制 : 链接规范嵌套太深" +因此,在整理 acl_define_xxx.h 文件时,将 extern "C" 从这些类文件去掉了。 +但GCC与BC++却没有这方面的问题,呵呵。不过BC++也有比较弱的地方,在编译库的时候, +必须保证工程的:option->Tlib->Page size 选项为 0x0020,否则如果该值为 0x0010则 +BC++也会报一个比较弱的编译错误,如下: +[TLib Error] library too large, please restart with library page size 32 +104.2) lib_acl/Makefile, Makefile.mysql: 增加了对MYSQL的编译支持 +104.3) dist: 增加了一个专门针对 acl_master 服务器框架的安装包. + +103) 2008.1.5 +103.1) acl_aio.c: 增加了从异步流中提取异步框架句柄的函数: acl_aio_handle(); +103.2) acl_aio_server.c: 增加了acl_aio_server_handle()函数,方便应用在函数自己 +的post_init()函数中直接通过此函数提取异步框架句柄。 +103.2) acl_aio_server.c: bugfix, 当 acl_master 退出时基于该模板的子进程不退出, +这是与异步流的关闭相关。 + +102) 2007.12.30 +102.1) acl_aio_read.c: 修复了几处错误 +102.2) acl_vstream.c: 为 acl_aio_ 异步库提供了更方便的接口 +102.3) unix_trigger.c, inet_trigger.c, stream_trigger.c: 可能 events_proc.c 的 +定时器与IO事件存在冲突,所以暂时修改了这三个程序,将超时事件的定时器去掉,而是 +直接由IO的超时来处理。 + +101) 2007.12.25 +101.1) master_status.c: master_status_event 函数中将acl_vstream_readn修改为read +101.2) acl_aio.c: 在所有的调用timeo_fn()前用增加引用计数的方法来防止流被提前异常关闭 +101.3) acl_aio.c: 将流关闭的标记位 closing 统一用 nrefer 来代替 +101.4) acl_aio.c: 因为该文件太大了,所以进行了分割,分成几个小模块文件 + +100) 2007.12.16 +100.1) db/acl_dbsql.c, mysql/acl_dbmysql.c: 回调函数的参数my_row 对应于MYSQL_ROW +声明为 const void**, 原来声明为 const void*, 在GCC下编译时报错 +100.2) msg/acl_aqueue.c, acl_aqueue_pop_timedwait 的等待时间做一处理,因为UNIX +与WIN32有不同。 +100.3) protocol/, 因为声明的HTTP_STATUS_状态宏与VC的冲突,所以修改HTTP_STATUS_ +为HTTP_CHAT_。 + +99) 2007.12.13 +99.1) db/acl_dbpool.c: acl_dbpool_destroy函数有一处BUG,在调用子类的销毁函数 +后不应再次重复释放同一块内存。 + +98) 2007.12.7 +98.1) acl_define.h: 增加了 acl_unused 宏定义,方便应用避免一些编译时的警告 + +97) 2007.11.6 +97.1) aio/acl_aio.c: 防止遗漏描述符未被关闭现象,所有重要函数回调返回处 +都需要判断是不是处于IO完成延迟状态 +97.2) aio/acl_aio.c: 增加了许多有用的注释说明,以使该复杂的异步库更加 +容易理解,因为该库的设计确实比较复杂 +97.3) feature: acl_netdb.c, 添加了一个方便生成 ACL_DNS_DB 的函数 +acl_netdb_addip + +96) 2007.11.5 +96.1) aio/acl_aio.c: 保证非阻塞式写失败错误号的处理正确且兼容各平台 +96.2) 整理了所有的 errno, 将其转换为 acl_last_error(), 将 strerror() +转换为 acl_last_strerror(),从而保证平台的移植性 + +96) 2007.11.3 +96.1) net/listen/acl_inet_listen.c: acl_inet_listen(): +if (nport <= 0) --> if (nport < 0), 因为acl_msgio_listen传递过来的地址为 +"127.0.0.1:0" 的格式,目的是让操作系统自动分配监听端口号 + +95) 2007.11.2 +95.1) 修改了 protocol/ 下的部分函数 + +94) 2007.11.28--11.30 +94.1) 整理 master/ 模块 +94.2) 费好大劲才找出 acl_master 无法在 AS3.0 上正常运行的原因: 不能在 +acl_define.h 中定义 HAS_DUPLEX_PIPE, 否则会导致 +master/framework/master_status.c 中的 acl_master_status_init() 函数在 +调用 stdlib/iostuff/acl_duplex_pipe.c 中的 acl_duplex_pipe() 函数时自动 +岂用 pipe() 模式. + +93) 2007.11.27 +93.1) 整理了一下各个模块的位置 +93.2) 对LINUX及WINDOWS的兼容性做调整 + +92) 2007.11.26 +92.1) stdlib/acl_msg.c, acl_mylog.c: 记录了日期, 进程号与线程号 + +91) 2007.11.25 +91.1) db: 将数据库模块进行了整理 +91.2) thread: 当在WIN32下与MYSQL进行整合时, pthread_xxx 的命名与MYSQL的库 +冲突, 所以将 thread/ 下的 pthread_xxx 重新命名为 acl_pthread_xxx + +90) 2007.11.23 +90.1) portable: 经过长期努力, 终于将WINDOWS版本的ACL与UNIX版本的ACL合并了:) + +89) 2007.11.11--11.12 +89.1) feature: add the trigger framework to acl_master. +89.2) example: samples/master/trigger/, add one example for trigger + +88) 2007.9.11 +88.1) example: samples/http_probe, 增加了一个用于探测HTTP服务器状态的例子 + +87) 2007.9.10 +87.1) bugfix: spool/acl_spool.c, 在创建池的时候对参数的判断问题进行修复. +87.2) bugfix: proto/http/http_chat.c, 对HTTP协议的接收处理过程问题进行修复. + +86) 2007.8.30 +86.1) performance: master/acl_master_listen.c: 监听套接口的监听队列依赖于 +main.cf 中的 default_process_limit 值, 当此值比较小时会导致监听套接口的监听 +队列也比较小, 从而严重影响了 accept() 的性能, 通过在 acl_master_listen.c +中限制最小的监听队列来保证 accept() 性能. +87.2) bugfix: master/acl_aio_server.c->aio_server_wakeup() 中的 acl_vstream_fdopen +中的读写超时时间应该为 0, 因为在非阻塞模式下套接口的读写超时时间由事件循环 +机制进行控制, 如果此值大于0, 则在 stdlib/acl_vstream.c 中进行真正的IO读时 +会有一个多余的 select() 系统调用, 这将会影响非阻塞模式的IO性能. + +85) 2007.8.26 +85.1) feature: 增加了 /dev/poll for solaris. +85.2) 进一步完善了 engine/ 的事件接口, 隐藏了一些底层的内部接口, 使调用者 +更加方便地使用事件接口(engine/events_define.h 中打开 ACL_EVENTS_KERNEL 的 +定义, 便可以在 solaris 中使用 /dev/oll 或在 Linux Kernel2.6 以上版本中使用 +epoll). + +84) 2007.8.23 +84.1) portable: rebuilt on solaris. + +83) 2007.8.22 +83.1) feature: 增加了日志记录的注册函数功能, 可以外挂第三方的日志记录函数库, +stdlib/acl_msg.c, acl_msg.h; 例子参见 samples/master/spool_server/app_log.c. + +82) 2007.8.21 +82.1) 完善了 acl_aio_server.c 框架模板 +82.1) performance: master/acl_spool_server.c +82.3) bugfix: engine/events_thr.c, events_proc.c 中关于定时器的错误修复 + +81) 2007.8.19 +81.1) bugfix: engine/events_proc.c, 为了 master/ 的需要, 修改了 events_proc.c, +及 events_thr.c 中的 events_disable_readwrite() 允许空操作. +81.2) experiment: master/acl_aio_server.c, acl_aio_params.h, 增加了非阻塞库到 +master/ 服务框架模型中. + +80) 2007.8.14 +80.1) 重新调整了 engine/ 下的架构, 对于流的定位与查询不再基于数组定位模式, 以 +便于将来移植至 MS Windows 时操作更加方便同时并不会造成性能下降. +80.2) 修改的相关文件: acl_events.c, events_proc.c, events_thr.c, acl_event.h +80.3) 新增的文件: events_fdtable.c, events_fdtable.h +80.4) tagged as milestone + +79) 2007.8.11 +79.1) portable: 成功将 acl 库移植至 Sun Solaris11 for x86. +79.2) bugfix: acl_vstream.c, event_thr.c, 修改了有关异步读的错误 + +78) 2007.8.8 +78.1) performance: acl_spool.c, acl_vstream.h/acl_vstream.c: 通过在 ACL_VSTREAM +中添加 acl_spool.c 中的内部临时变量(ACL_SPOOL_CTX), 减少了 acl_spool_xxx 的每次 +调用过程中的分配与释放内存的次数. (与 acl_aio.c 中的做法类似) +78.2) framework: samples/master/spool_server/, app_main.c/app_main.h, 进一步抽象 +了框架接口的调用模式, 以便于用户更加方便地使用. + +77) 2007.8.7 +77.1) bugfix: engine/event_proc.c + +76) 2007.7.17 +76.1) bugfix: acl_aio.c->acl_aio_connect() 中未预分配 data_buf 的内存空间 +76.2) add on sample: 增加了一个用于高并发测试WEB服务器的例子(samples/http_auto), +该例子可以与WEB服务器一直保持高并发的连接, 如果连接断了会重新建立连接并发送 +连接请求. + +75) 2007.7.12 +75.1) performance: 一定程度上提高了 acl_aio.c 中异步读的性能 + +74) 2007.7.11 +74.1) feature: 增加了针对 Linux2.6 的 epoll 的支持 +74.2) performance: 大大提高了异步IO的性能(acl_aio.c, acl_vstream.c) +74.3) example: 针对HTTP服务器(webstar)做性能压力测试, 可以达到450Mbits/s, +12500 request/sec. (./ab -n 1000000 -c 5000 -k http://ip:8080/postfix/) + +73) 2007.6.7 +73.1) feature: acl_spool.c/acl_spool.h, acl_aio.c/acl_aio.h, 增加了异步 +处理函数库的单线程版本, 发现单线程版本的处理能力大约是多线程版本处理能力 +的1.5倍左右(原因可能是操作系统的线程调试开销及其它锁机制), 测试程序参见: +sample/aio/. 单线程版本: 41002 次/秒; 多线程版本: 26549 次/秒. + +72) 2007.5.29 +72.1) bugfix: acl_htable.c/acl_htable.h, 里面在处理多线程加锁处理机制有 +问题, 现在已经由新的接口函数替代了 + +71) 2007.5.27 +70.1) acl_htable.c/acl_htable.h: 增加了哈希函数的注册功能及线程安全特性 +70.2) 增加了哈希算法函数集于 acl_hash.c, acl_hash.h 中 + +70) 2007.5.21 +70.1) acl_dbpool.c, acl_dbpool.h: 增加了事务自动提交的可配置功能及检测功能 + +69) 2007.5.20 +69.1) acl_spool.c, acl_workq.c: 进一步抽象与完善了任务池的函数接口 + +68) 2007.5.11 +68.1) feature: spool/acl_spool.c, acl_spool.h 增加了任务添加函数接口 +68.2) engine/acl_event.c acl_event.h, event_thr.c, event_proc.c: 修改了内部的 +流程, 更进一步抽象, 同时使 acl_event_request_timer/acl_event_cancel_timer 具备 +多线程工作特性. + +67) 2007.5.7 +67.1) bugfix: aio/acl_aio.c: acl_aio_read() 中传递的已读数据长度有误. + +66) 2007.4.16 +66.1) 注释: aio/acl_aio.h 头文件里增加了使用注释 + +65) 2007.4.14--4.15 +65.1) feature: 整理 http/ 协议库... + +65) 2007.4.11 +65.1) bugfix: aio/acl_aio.c, acl_aio_readn() 的回调函数里有一处漏内存错误. +64.2) feature: 整理 http/ 协议库... + +64) 2007.4.10 +64.1) feature: 整理 http/ 协议库... + +63) 2007.4.9 +63.1) feature: aio/acl_aio.c, stdlib/acl_vstream.c, 增加了异步读N个字节的函数. +63.1) feature: 开始整理 proto/http/ 协议库... + +62) 2007.4.8 +62.1) bugfix: engine/events_thr.c, 去掉了 select() 之后对超时的设定. +62.2) util/aio/: 修改了函数接口的定义方式, 使接口调用方式更加清晰. + +61) 2007.4.7 +61.1) 检验异步AIO的内存泄漏情况, 发布异步包含异步IO的库(util/aio/). +61.2) 提供异步IO的例子: samples/aio/. + +60) 2007.4.6 +60.1) 修定了 master/acl_master_ent.c 中的一处BUG: acl_free_master_ent() 函数中 +acl_array_destroy() 的调用应在 acl_myfree((char *) serv) 之前. + +59) 2007.4.5 +59.1) 增加了 aio/ 用于异步IO操作, net/acl_vstream_aync.c 将被丢弃 + +58) 2007.4.1 +58.1) 增加了 master/acl_spool_server.c, 该服务框架基于 spool/acl_spool.c +58.2) 调整了 engine/event_thr.c 中针对 timer 在 event_loop() 的调用关系, 使监听描述符的处理 +直接在主循环里进行, 从而缓解了多程模式中 select() 调用中时间值的影响 + +57) 2007.3.25 +57.1) 增了数据库连接池的状态记录日志: util/spool/mysql/acl_dbpool_mysql.c +57.2) 将与 mysql 相关的头文件建立连接实现动态编译: depends/ +57.3) bugfix: 修改了几处与编译相关的错误 + +56) 2007.3.24 +56.1) feature: 增加了服务器应用框架及数据库连接池框架 spool/. +56.2) example: 增加了针对 master/listener_server 的例子. +56.3) performance: 修改了 event_thr.c->event_loop() 的事件触发策略, 减少了线程锁的冲突. + +55) 2007.2.15 +55.1) master/, net/ 经过初步测试已经可以用了:) +55.2) 将 app/master/ 归并到 samples/ 下. + +54) 2007.2.14 +54.1) feature: stdlib/acl_vstream.c, stdlib/acl_vstream.h, 增加了 acl_vstream_fprintf, +acl_vstream_vfprintf 两个函数, 大大方便了使用者进行数据流的带格式写操作. + +53) 2007.2.13 +53.1) 对 master/, trigger/, net/ 目录下的一些文件名及函数名重新按 acl/ACL 的命名规范进行了整理 +注: 这部分代码仅能编译通过, 还未充分进行测试. + +52) 2007.2.3--2.4 +52) unit_test: 进行了重大调整, 使其更易用 +52.1) 命名规范进行了统一: 函数名前加 aut_, 类型前加 AUT_ +52.2) 调整了循环过程的调用方法, 使代码更加清晰. + +51) 2007.1.27 +51.1) feature: 增加并完善了 listener_server.c/listener_params.h, 该模块做为 master 半驻留进程池模块的补充, +增加了另外一种服务器模型, 该模型仅用于套接口监听, 可以与线程池的服务器模型很好的结合在一起, 即现在已经可以 +支持半驻留式的多进程多线程服务器模型; 同时该模型还可用于接收一个请求 fork 一个进程的模式。 +51.2) bugfix: event_proc.c/event_thr.c event_XXX_loop 的事件循环中针对 timer 操作的错误. + +50)2006.10.20 +50.1) app/squid/analog: 增加了一个日志分析程序。 + +49)2006.8.29 +49.1) util/net/acl_vstream_async.c: 修订了一处BUG, 以避免造成内存冲突。 +49.2) util/stdlib: acl_mymalloc.c, acl_mymalloc.h, 增加了为了调试内存分配与释放的宏调用(通过在 acl_mymalloc.h +中将宏定义: #define DEBUG_FREE 开关打开即可)。 + +48) 2006.8.28 +48.1) util/stdlib/acl_vstream.c: 增加了acl_vstream_gets_ready()/acl_vstream_gets_nonl_ready(), 使异步通信 +操作更加方便, 并且使之与阻塞式方式读缓冲紧密结合在一起, 即:对于一个ACL_VSTREAM 可以同时对其进行同步、异步 +读操作。 +48.2) util/net: acl_vstream_async.c/acl_vstream_async.h, 因为 acl_vstream.c 从更底层提供了接口,所以该异步 +函数集的操作更加简化了,抛弃了原来异步读行的模式,而采用新的异步读行的模式。 + +47) 2006.8.25 +47.1) util/net: acl_vstream_async.c/acl_vstream_async.h, 修改了一处BUG, 内容见 acl_vstream_async.h 中所述. + +46 ) 2006.8.11 +46.1) util/servtmpl: acl_workq.c/acl_workq.h, 增加了有关连接池功能的调用 + +45) 2006.7.28 +45.1) util/code/, 增加了BASE64编码的两个实现方法 + +44) 2006.7.27 +44.1) util/engine/acl_event.c, 增加了参数入口的判断 +44.2) util/master/master_conf.c, 增加服务数量的检查 + +43) 2006.7.24 +43.1) app/weboe/: 避免了内存泄漏的问题, 并且经过了大规模长时间的压力测试及其它的破坏性测试, 说明非阻塞 +式框架库基本稳定了. + +42) 2006.7.23 +42.1) 性能优化与BUG修复, event_thr.c->event_thr_loop() 中锁的控制, 改变了 dipatch_fn() 的函数接口参数, +从而避免了一些复杂的容易出错的释放操作, 并且减少了加锁次数. +42.2) event_thr.c->event_thr_loop() 中又减少了某一种锁的冲突. + +41) 2006.7.11 +41.1) 调整了参数,使非阻塞服务器的性能得到大幅提高 + +40) 2006.7.5 +40.1) Bugfix: acl_vstream_async.c->__handle_line_data() 中依然有一处错误, 现已经进行了修正 + +39) 2006.7.3 night +39.1) Feature: 通过修改 __handle_line_data(), acl_vstream_async_buf_new() 两个函数进一步提高了执行效率, +减少了数据移动拷贝现象. +39.2) Feature: 通过增加 acl_vstream_async_buf_new() 的参数列表及修改 __handle_line_data() 函数,增加了 +针对一行数据的长度的最大值限制, 从而进一步避免缓存区溢出问题. + +38) 2006.7.2 +38.1) Bugfix: 修改了异步通信库的一个错误, 发生于异步读一行的函数处理中: util/net/acl_vstream_async.c 中 +的 __handle_line_data() 函数. +38.2) 将 util/stdlib/acl_vstream.c, .h 中的 acl_vstream_vstring_readn 改名为:acl_vstream_vstring_append_readn + +37) 2006.6.23 +Feature: 完善了异步通信的接口: util/stdlib/acl_vstream.c, util/engine/acl_events.c, +util/net/acl_vstream_async.c. 在 ACL_VSTREMA 结构类型中增加了注销函数数组: close_handle_lnk, 以保证 +当数据流被关闭前先倒序调用各个已经在该数组中注册的析构函数; 在 ACL_EVENT 结构中增加了线程锁成员 +变量: lock_mutex, 对于处于线程事件的循环中该锁将起作用, 对于进程类型的事件循环该锁不起作用, 因为增加 +了该锁, 从而使 acl_vstream_async.c 中不在存在线程锁的调用, 而是将锁的调用移至 acl_events.c中. + +36) 2006.6.15 +Bugfix: 修订了有关域名解析部分线程不安全的函数: util/net/myaddinfo.c +Bugfix: util/net/acl_vstream_net.c 中的acl_vstream_connect() 函数中在调用 acl_vstream_fdopen() +时参数顺序有错误。 + +35) 2006.6.13 +增加了探测程序: app/squid/probe + +34) 2006.6.8 +完善了线程库部分. +Feature: 增加线程读写锁部分, util/ipc/acl_thread_rwlock.c, acl_thread_rwlock.h +Feature: 将以前的内存DB放置该库中 + +33) 2006.6.7 +Bugfix: 修订了有些函数在调用 acl_vstream_fdopen() 时的各个参数顺序的BUG!!!, 费了好大劲才找出此错误:( +Test: 增加了两个测试线程池库的实例(app/thread_server/server2, server3) + +32) 2006.6.6 +写了一个用来测试线程库的实例(app/thread_server/server1) + +31) 2006.6.4 +为了避免函数的名字空间冲突,修改了大量的函数,将所有函数名及类型名前均增加 ACL_ 前缀,同时将 +源程序名前增加 acl_ 前缀。至此,本函数库的工作被定义为 acl_project 工程. ---zsx +注: acl 是 advanced c library 的英文简写. + 建议使用者尽是使用 ACL_ 开头的函数及类型,其它的函数及类型并不保证将来的兼容性。 + +30) 2006.5.30 +Feature(debug status): 1) 增加了另一个线程池的库: servertmpl/workq.c, workq.h, worker.c, worker.h +Name: 确定以后将本函数库命名为 : ACL(高级的 C 库) + +29) 2006.4.30 +Portable: 查询了所有的Makefile,将其中的所有的编译选项 -gdwarf 都换成 -g,以兼容新的 +编译器要求,折腾了俺一上午时间:( + +28) 2005.12.14 +Feature: 1) 提供了另外一个 vstream_fseek 函数, 该新函数的效率更高, 且把第一版本的 vstream_fseek +重新命名为 vstream_fseek2. 另外加强了测试代码. + +27) 2005.12.13 +Feature: 1) 增加了 vstream_fseek 函数 + +26) 2005.10.24 +Feature: 1) 增加了 util/stdlib/filedir/make_dirs.c 文件, 从而可以创建一级或多级目录 + +25) 2005.10.8 +Bugfix: 1) 在 app/master/multi_proxy/multi_proxy.c 中, 在打开文件数据流时没有将文件指针移至文件 +的结尾, 故增加了 O_APPEND, 使每次打开文件数据流时都使文件指针指向文件的最后. +Feature: 1) 在 app/master/master.c 中增加了写 master 进程的 pid 的功能, 这样可以使诸如 stop.sh +之类的脚本来停止主控进程. + +24) 2005.9.27 +Feature: 1) 针对 multi_server.c 增加了记录信息的功能 + +23) 2005.9.26 +Bugfix: 1) 修复了 __proc(thread)__event_loop() 中的一处错误, 即当 nowait != 0 时, 应该设置指针 tvp +的值而不应设置其为空指针, 否则会导致后面的 select() 调用永远等待; 2) multi_server.c 中有一处错误, +在一个 switch() 条件中缺少一个 break. +Feature: 1) 修改了 multi_proxy.c 文件, 使其变得更加通用:) + +22) 2005.9.25 +Feature: 1) 针对 multi_server.c, 增加了读超时的处理功能, 这对于处理非阻塞模式的读超时非常 有价值. + +21) 2005.9.22 +Bugfix: 1) 通过边界测试(即设置缓冲区分别为2, 4, 4096, 8192)时, 发现代理服务器(multi_proxy)会有异 +常退出的问题, 经过仔细检查, 发现是服务框架事件处理函数(event.c)有问题, 即当外部函数通过调用函数 +event_disable_readwrite()来关闭永久可读写描述集时, 因为 ..._event_loop() 中所用的临时描述集未被清 +除, 这样就产生了不同步清理的问题, 从而造成调用 select() 时报严重的错误: 有非法的描述符存在于描述 +符集合中, 解决方法是在 EVENT 的结构中增加临时描述集, 用来代替 ..._event_loop() 中的局部描述集, +所修改的文件主要有: event.c, event.h + +20) 2005.9.19 +Portable: 20.1) can run on HP-UX + +19) 2005.9.11 +Workaround: 19.1) 增加了使用 multi_server.c 框架的代理服务器, 19.2) 修补了 multi_server.c 中的几 +处 bug + +18) 2005.9.10 +Workaround: 18.1) 归整了一些变量的命名格式, 并去掉了一一些无用的变量 + +17) 2005.9.9 +Bugfix: 17.1) 修改了 events.c 中的一处 bug +Feature: 17.1) 增加了一个测试程序: single_proxy/ + +16) 2005.9.6 +Workaround: 16.1) 移植到了 SUN 平台上, 并修改了几处 + +15) 2005.9.5 +Feature: 15.1) 增加了 VSTREAM_STDIN, VSTREAM_STDOUT, VSTREAM_STDERR 三个标准的数据流 + +14) 2005.9.4 +Workaround: 14.1) 使 multi_server() 服务框架可以正常使用了 +Bugfix: 14.1) 修复了 servtmpl/event.c 中的一个处 bug: 当有可用的描述字中流中有数据时, 则需要将 +select() 所需要的时间等待时间设置为 0. + +13) 2005.8.28 +Workaround: 13.1) 调整了一些程序的书写格式, 同时还明白了 throttle_delay 的真正含义: 即当子进程非 +法退出后, 父进程将停止相应的服务的时间间隔为 throttle_delay. + +12) 2005.8.27 +Workaround: 12.1) 基本调度成功 了 single_server 的服务框架模式:) + +11) 2005.8.24 +Workaround: 11.1) 修改了 events.c/.h, 使之支持进程池的模式, 在进程池模式下不需要检查描述符是否 +处于忙状态; 在线程池模式下需要检查描述符是否处于忙状态; 11.2) 继续完善 util/master/ 下的文件, +基本实现了半驻留服务模式的运行. + +10) 2005.8.21 +Bugfix: 10.1) 修复了 xinetd_cfg.c 中的一处错误 +Feature: 10.1) 针对 xinetd_cfg.c/.h 增加了 xinetd_cfg_index(...) 函数 +Workaround: 10.1) 继续完善了 master/ 库函数 + +9) 2005.8.15 +Workaround: 9.1) 终于使 master 可以运行了:) util/master/: master_vars.c, master_params.c, +master_params.h, master_conf.c, master_service.c, master.h, master_ent.c, master_avail.c, +master_sig.c, master_spawn.c, master_status.c, master_wakeup.c + +8) 2005.8.14 +Workaround: 8.1) 将 master 编译成功:), app/master/: master.c + +7) 2005.8.9 +Bugfic: 7.1) 修补了一处可能会造成内存泄漏的错误, master_ent.c +Workaround: 7.1) 整理了 master/ 目录下的文件, 仅剩余 mail_flow.c 等几个文件未整理. + +6) 2005.8.8 +Workaround: 6.1) 修改了目录结构, 在 stdlib/ 目录下建立了 proc_specific/ 目录, 该目录今后将存放 +仅在进程编程时才用的库函数, 这些库函数是线程不安全的; 6.2) 将测试 watchdog 库的程序移动到专门的 +测试程序目录下(test_util/watchdog/), 还有 test_util/inet/; 6.3) 修改了两个头文件(cgi-rep.h 及 +cgi-util.h), 在其中增加了针对 C++ 编译引用的支持.; 6.4) 继续完善 master 函数库 (master/) + +5) 2005.7.29 +Feature: 5.1) 增加了针对异读、异步连接、异步读行的读超时功能(这是微软的异步SOCKET里所不具备的). +event.h, event.c, vstream_async.c, vstream_async.h, readline_async/, tcp_proxy/. + +4) 2005.7.25 +Feature: 4.1) 在 vstream.c 中, 增加了 vstream_vstring_readn(), 从而可以利用 vstring 的特性来拷贝 +数据; 4.2) 在 vstream_async.c 中增加了 vstream_async_gets(), 从而可以将获得一行作为事件通知条件, +当缓冲区内有一行数据时才会通知应用程序, 即实现了读取行非阻塞的模式. +Test: 4.1) 在 app/ 目录下增加了工程: readline_async/, 用于测试异步读取整行数据的库函数. + +3) 2005.7.18 +Workaround: 3.1) 修改了 vstream_net.c/h 文件, 将 vstream_listen2 修改为 vstream_listen_ex, 并增加 +了一个 block_mode 的参数, 从而使数据流完全遵守非阻塞模式; 3.2) vstream_async.c, 在 vstream_listen_ex +中增加了 NON_BLOCKING 参数. + +2) 2005.7.10 +Workaround: 2.1) 重新改写了各个 Makefile 文件, 可以自动从环境变量中取得用 gcc 编译还是用 g++ 编译; +2.2) 修改各个 .c 及 .h 文件, 消除了在用 g++ 编译时的错误与警告, 以使本函数库可以用方便地应用在一 +些 C++ 的程序中. + +1) 2005.7.9 +Bugfix: 修订了 servtmpl/events.c 中的两处 BUG, 1.1) event_enable_write() 及 event_enable_read() +中增加了防止上一次操作中未将状态设置为空闲的隐患; 1.2) event_loop() 以前在最初设置描述符集合时没 +有将处于忙状态的描述符清除掉. diff --git a/lib_acl/include/aio/acl_aio.h b/lib_acl/include/aio/acl_aio.h new file mode 100644 index 000000000..58cc4d049 --- /dev/null +++ b/lib_acl/include/aio/acl_aio.h @@ -0,0 +1,803 @@ +/** + * @file acl_aio.h + * @author zsx + * @date 2010-1-2 + * @brief 本文件中定义了关于 ACL_ASTREAM 异步通信流操作的类型说明及函数接口. + * @version 1.1 + */ + +#ifndef __ACL_AIO_INCLUDE_H__ +#define __ACL_AIO_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_define.h" +#include +#ifdef ACL_UNIX +#include +#endif + +#include "stdlib/acl_stdlib.h" +#include "event/acl_events.h" + +/*------------------------------- 数据结构类型定义 ---------------------------*/ + +/** + * 异步框架引擎句柄类型定义 + */ +typedef struct ACL_AIO ACL_AIO; + +/** + * 异步流类型定义 + */ +typedef struct ACL_ASTREAM ACL_ASTREAM; + +/** + * 异步流超时回调函数类型定义: void (*)(int event_type, void *context) + * @see ACL_EVENT_NOTIFY_TIME + */ +typedef ACL_EVENT_NOTIFY_TIME ACL_AIO_TIMER_FN; + +/** + * 事件通知函数句柄类型, 当某个受监控的流有数据可读或出错时的回调用户的注册函数, + * 目前用与该类型相关的异步函数有: + * acl_aio_gets, acl_aio_gets_nonl, acl_aio_read, acl_aio_readn. + * @param astream {ACL_ASTREAM*} 异步流指针 + * @param context {void*} 用户级传递的参数 + * @param data {const char*} 从流中读取的数据指针 + * @param dlen {int} data 数据的长度 + * @return {int} 该函数指针调用如果返回-1则表明应用要求关闭异步流 + */ +typedef int (*ACL_AIO_READ_FN)(ACL_ASTREAM *astream, + void *context, + char *data, + int dlen); + +/** + * 事件通知函数句柄类型,当某个异步流可读/可写时调用此类型的用户回调函数 + * @param astream {ACL_ASTREAM*} 异步流指针 + * @param context {void*} 用户级传递的参数 + * @return {int} 如果该函数类型返回 -1 则表明应用要求关闭异步流 + */ +typedef int (*ACL_AIO_NOTIFY_FN)(ACL_ASTREAM *astream, void *context); + +/** + * 事件通知函数句柄类型, 当某个受监控的流将数据写完或出错时的回调用户的注册函数, + * 目前用与该类型相关的异步函数有: + * acl_aio_writen, acl_aio_writev, acl_aio_fprintf, acl_aio_vfprintf. + * @param astream {ACL_ASTREAM*} 异步流指针 + * @param context {void*} 用户级传递的参数 + * @return {int} 该函数指针调用如果返回-1则表明应用要求关闭异步流 + */ +typedef int (*ACL_AIO_WRITE_FN)(ACL_ASTREAM *astream, void *context); + +/** + * 当某个监听描述符有新的客户端连接时, 异步框架接收该连接并传递给用户; 如果出错, + * 若用户设置了该监听流的监听超时值且到达该超时值, 则也会触发该函数类型句柄. 与该函数 + * 类型句柄相关的异步函数有: acl_aio_accept. + * @param cstream {ACL_ASTREAM*} 从 sstream 监听流通过 accept() 获得的客户端连接流 + * @param context {void*} 用户级传递的参数 + * @return {int} 如果该函数调用返回 -1 表示不再继续接收新的客户端连接 + */ +typedef int (*ACL_AIO_ACCEPT_FN)(ACL_ASTREAM *cstream, void *context); + +/** + * 当某个监听描述符上有新的客户端连接时, 异步框架回调用用户的注册函数, 用户需要从 + * 该监听流上 accept 该客户端连接. 与该函数类型相关的异步函数有: acl_aio_listen. + * @param sstream {ACL_ASTREAM*} 监听流句柄 + * @param context {void*} 用户级传递的参数 + * @return {int} 如果该函数的调用返回-1,并不影响监听流继续监听 + * 注: 请注意该函数类型与 ACL_AIO_ACCEPT_FN 的功能差别. + */ +typedef int (*ACL_AIO_LISTEN_FN)(ACL_ASTREAM *sstream, void *context); + +/** + * 异步连接远程服务器时, 当连接失败、超时或成功时的事件通知句柄类型 + * 将回调用户的注册函数. 与该函数类型相关的异步函数有: acl_aio_connect. + * @param cstream {ACL_ASTREAM*} 受监控的正处于连接状态的客户端流 + * @param context {void*} 用户级传递的参数 + * @return {int} 若调用该函数返回-1则需要关闭该异步连接流 + */ +typedef int (*ACL_AIO_CONNECT_FN)(ACL_ASTREAM *cstream, void *context); + +/** + * “读、写、监听”超时的回调函数指针 + * @param astream {ACL_ASTREAM*} 异步流指针 + * @param context {void*} 用户传递的参数 + * @return {int} 当该函数调用返回-1时,对于读写流表示需要关闭该异步读写流, + * 对于监听流表示不再继续接收新的客户端连接;当返回0时,表示继续 + */ +typedef int (*ACL_AIO_TIMEO_FN)(ACL_ASTREAM *astream, void *context); + +/** + * 当需要关闭异步读写流时需要回调用用户注册的函数 + * @param astream {ACL_ASTREAM*} 异步流指针 + * @param context {void*} 用户传递的参数 + * @return {int} 无论该值如何,该异步流都需要被关闭 + */ +typedef int (*ACL_AIO_CLOSE_FN)(ACL_ASTREAM *astream, void *context); + +/* 异步流类型定义 */ + +struct ACL_ASTREAM { + ACL_AIO *aio; /**< 异步流事件句柄 */ + ACL_VSTREAM *stream; /**< 同步流 */ + + ACL_VSTRING strbuf; /**< 内部缓冲区 */ + int timeout; /**< IO超时时间 */ + int nrefer; /**< 通过此引用计数防止流被提前关闭 */ + int flag; /**< 标志位 */ +#define ACL_AIO_FLAG_IOCP_CLOSE (1 << 0) +#define ACL_AIO_FLAG_ISRD (1 << 1) +#define ACL_AIO_FLAG_ISWR (1 << 2) +#define ACL_AIO_FLAG_DELAY_CLOSE (1 << 3) +#define ACL_AIO_FLAG_DEAD (1 << 4) + + ACL_FIFO write_fifo; /**< 异步写时的先进先出队列数据 */ + int write_left; /**< 写缓冲中未写完的数据量 */ + int write_offset; /**< 写缓冲中的下一个位置偏移 */ + int write_nested; /**< 写时的嵌套层数 */ + int write_nested_limit; /**< 写时的嵌套层数限制 */ + + int (*read_ready_fn) (ACL_VSTREAM *, ACL_VSTRING *, int *); + int read_nested; /**< 读时的嵌套层数 */ + int read_nested_limit; /**< 读时的嵌套层数限制 */ + int count; /**< 调用 acl_aio_readn()/2 时设置的第二个参数值 */ + int keep_read; /**< 是否启用持续性读 */ + int accept_nloop; /**< acl_aio_accept 内部循环 accept 的最大次数 */ + int error; /**< 当前套接口的错误号 */ + + ACL_AIO_ACCEPT_FN accept_fn; /**< accept 完成时的回调函数 */ + ACL_AIO_LISTEN_FN listen_fn; /**< 有新连接到达时的回调函数 */ + void *context; /**< 用户设置的参数 */ + + ACL_AIO_NOTIFY_FN can_read_fn; /**< 可以读时的回调函数 */ + void *can_read_ctx; /**< can_read_fn 参数之一 */ + ACL_AIO_NOTIFY_FN can_write_fn; /**< 可以写时的回调函数 */ + void *can_write_ctx; /**< can_write_fn 参数之一 */ + + ACL_ARRAY *read_handles; /**< 读完成时的辅助回调函数 */ + ACL_ARRAY *write_handles; /**< 写完成时的辅助回调函数 */ + ACL_ARRAY *close_handles; /**< 关闭时的辅助回调函数 */ + ACL_ARRAY *timeo_handles; /**< 超时时的辅助回调函数 */ + ACL_ARRAY *connect_handles; /**< 连接成功时辅助回调函数 */ + ACL_FIFO reader_fifo; + ACL_FIFO writer_fifo; + + /* 可读时的回调函数 */ + void (*event_read_callback)(int event_type, ACL_ASTREAM *astream); +}; + +/** + * 设置流的IO超时时间 + */ +#define ACL_AIO_SET_TIMEOUT(stream_ptr, _timeo_) do { \ + ACL_ASTREAM *__stream_ptr = stream_ptr; \ + __stream_ptr->timeout = _timeo_; \ +} while(0) + +/** + * 设置流的 context 参数 + */ +#define ACL_AIO_SET_CTX(stream_ptr, _ctx_) do { \ + ACL_ASTREAM *__stream_ptr = stream_ptr; \ + __stream_ptr->context = _ctx_; \ +} while(0) + +/*--------------------------- 异步操作公共接口 -------------------------------*/ + +/** + * 创建一个异步通信的异步框架实例句柄, 可以指定是否采用 epoll/devpoll + * @param event_mode {int} 事件监听方式: ACL_EVENT_SELECT, ACL_EVENT_POLL + * , ACL_EVENT_KERNEL, ACL_EVENT_WMSG + * @return {ACL_AIO*} 返回一个异步框架引擎句柄. OK: != NULL; ERR: == NULL. + */ +ACL_API ACL_AIO *acl_aio_create(int event_mode); + +/** + * 创建一个异步通信的异步框架实例句柄, 可以指定是否采用 epoll/devpoll/windows message + * @param event_mode {int} 事件监听方式: ACL_EVENT_SELECT, ACL_EVENT_POLL + * , ACL_EVENT_KERNEL, ACL_EVENT_WMSG + * @param nMsg {unsigned int} 当与 WIN32 界面的消息整合时,即 event_mode 设为 + * ACL_EVENT_WMSG 时该值才有效,其表示与异步句柄绑定的消息值 + * @return {ACL_AIO*} 返回一个异步框架引擎句柄. OK: != NULL; ERR: == NULL. + */ +ACL_API ACL_AIO *acl_aio_create2(int event_mode, unsigned int nMsg); + +/** + * 释放一个异步通信异步框架实例句柄 + * @param aio {ACL_AIO*} 异步框架引擎句柄 + */ +ACL_API void acl_aio_free(ACL_AIO *aio); + +/** + * 异步IO消息循环(仅在单线程模式下调用) + * @param aio {ACL_AIO*} 异步框架引擎句柄 + */ +ACL_API void acl_aio_loop(ACL_AIO *aio); + +/** + * 主动检查 ACL_AIO 引擎中待关闭的异步流是否应该关闭,调用此函数后,一些需要 + * 延迟关闭的异步流会被主动关闭 + * @param aio {ACL_AIO*} 异步框架引擎句柄 + */ +ACL_API void acl_aio_check(ACL_AIO *aio); + +/** + * 获得事件引擎的句柄 + * @param aio {ACL_AIO*} 异步框架引擎句柄 + * @return {ACL_EVENT*} + */ +ACL_API ACL_EVENT *acl_aio_event(ACL_AIO *aio); + +/** + * 获得事件所采用的模式 + * @param aio {ACL_AIO*} 异步框架引擎句柄 + * @return {int} ACL_EVENT_KERNEL/ACL_EVENT_SELECT/ACL_EVENT_POLL + */ +ACL_API int acl_aio_event_mode(ACL_AIO *aio); + +/** + * 异步IO框架是否是采用持续读模式 + * @param aio {ACL_AIO*} 异步框架引擎句柄 + * @return {int} != 0: 是; == 0: 否 + */ +ACL_API int acl_aio_get_keep_read(ACL_AIO *aio); + +/** + * 设置异步IO框架的持续读模式 + * @param aio {ACL_AIO*} 异步框架引擎句柄 + * @param onoff {int} 0: 关闭持续读功能; != 0: 打开持续读功能 + */ +ACL_API void acl_aio_set_keep_read(ACL_AIO *aio, int onoff); + +/** + * 获得当前异步引擎循环时的等待时间的秒部分 + * @param aio {ACL_AIO*} 异步框架引擎句柄 + * @return {int} 用 select/poll/epoll/kqueue/devpoll 时的秒级等待时间 + */ +ACL_API int acl_aio_get_delay_sec(ACL_AIO *aio); + +/** + * 获得当前异步引擎循环时的等待时间的微秒部分 + * @param aio {ACL_AIO*} 异步框架引擎句柄 + * @return {int} 用 select/poll/epoll/kqueue/devpoll 时的微秒级等待时间 + */ +ACL_API int acl_aio_get_delay_usec(ACL_AIO *aio); + +/** + * 设置异步引擎循环的等待时间中的秒级部分 + * @param aio {ACL_AIO*} 异步框架引擎句柄 + * @param delay_sec {int} 用 select/poll/epoll/kqueue/devpoll 时的秒级等待时间 + */ +ACL_API void acl_aio_set_delay_sec(ACL_AIO *aio, int delay_sec); + +/** + * 设置异步引擎循环的等待时间中的微秒级部分 + * @param aio {ACL_AIO*} 异步框架引擎句柄 + * @param delay_usec {int} 用 select/poll/epoll/kqueue/devpoll 时的微秒级等待时间 + */ +ACL_API void acl_aio_set_delay_usec(ACL_AIO *aio, int delay_usec); + +/** + * 设置异步流的读缓存区大小 + * @param aio {ACL_AIO*} 异步框架引擎句柄 + * @param rbuf_size {int} 读缓冲区大小 + */ +ACL_API void acl_aio_set_rbuf_size(ACL_AIO *aio, int rbuf_size); + +/** + * 设置监听异步流每次接收客户端连接时循环接收个数 + * @param astream {ACL_ASTREAM*} 监听流 + * @param nloop {int} + */ +ACL_API void acl_aio_set_accept_nloop(ACL_ASTREAM *astream, int nloop); + +/** + * 从异步流中获得异步框架引擎句柄 + * @param stream {ACL_ASTREAM*} 异步IO流 + * @return {ACL_AIO*} 异步框架引擎句柄 + */ +ACL_API ACL_AIO *acl_aio_handle(ACL_ASTREAM *stream); + +/** + * 设置异步流的参数 + * @param stream {ACL_ASTREAM*} 异步IO流 + * @param ctx {void*} 参数 + */ +ACL_API void acl_aio_set_ctx(ACL_ASTREAM *stream, void *ctx); + +/** + * 获得异步流的参数 + * @param stream {ACL_ASTREAM*} 异步IO流 + * @return {void*} 异步流 stream 的参数 + */ +ACL_API void *acl_aio_get_ctx(ACL_ASTREAM *stream); + +/** + * 打开一个异步通信流的句柄 + * @param aio {ACL_AIO*} 异步框架引擎句柄 + * @param stream {ACL_VSTREAM*} 受监控的流, 当该流有完整的一行数据、出错 + * 或读超时时将回调用户的注册函数. + * @return {ACL_ASTREAM*} 异步通信流句柄 + */ +ACL_API ACL_ASTREAM *acl_aio_open(ACL_AIO *aio, ACL_VSTREAM *stream); + +/** + * 异步IO完成后关闭流,否则进行异步关闭动作,即需要等读写都完成时才关闭流 + * @param astream {ACL_ASTREAM*} 异步数据流 + */ +ACL_API void acl_aio_iocp_close(ACL_ASTREAM *astream); + +/** + * 取消异步IO过程,该功能主要是为了将异步IO流转换为同步IO流而写 + * @param astream {ACL_ASTREAM*} 异步IO流 + * @return {ACL_VSTREAM*} 流句柄 + */ +ACL_API ACL_VSTREAM *acl_aio_cancel(ACL_ASTREAM *astream); + +/** + * 获得监听描述符每次接收客户端连接的最大个数 + * @param astream {ACL_ASTREAM *} 监听描述符流 + * @return {int} 每次接收连接的最大个数 + * @return {int} 监听描述符在每次接收过程中可以循环接收的最大连接 + * 个数,此值最小为1 + */ +ACL_API int acl_aio_get_accept_max(ACL_ASTREAM *astream); + +/** + * 设置监听描述符每次接收客户端连接的最大个数 + * @param astream {ACL_ASTREAM *} 监听描述符流 + * @param accept_max {int} 监听描述符在每次接收过程中可以循环接收的最大连接 + * 个数,此值最小为1 + */ +ACL_API void acl_aio_set_accept_max(ACL_ASTREAM *astream, int accept_max); + +/** + * 添加附加读回调函数 + * @param astream {ACL_ASTREAM*} 异步流,不能为空 + * @param callback {ACL_AIO_READ_FN} 回调函数,不能为空 + * @param ctx {void*} callback 回调函数的回调参数,可以为空 + */ +ACL_API void acl_aio_add_read_hook(ACL_ASTREAM *astream, + ACL_AIO_READ_FN callback, void *ctx); + +/** + * 添加附加写回调函数 + * @param astream {ACL_ASTREAM*} 异步流,不能为空 + * @param callback {ACL_AIO_READ_FN} 回调函数,不能为空 + * @param ctx {void*} callback 回调函数的回调参数,可以为空 + */ +ACL_API void acl_aio_add_write_hook(ACL_ASTREAM *astream, + ACL_AIO_WRITE_FN callback, void *ctx); + +/** + * 添加附加关闭回调函数 + * @param astream {ACL_ASTREAM*} 异步流,不能为空 + * @param callback {ACL_AIO_READ_FN} 回调函数,不能为空 + * @param ctx {void*} callback 回调函数的回调参数,可以为空 + */ +ACL_API void acl_aio_add_close_hook(ACL_ASTREAM *astream, + ACL_AIO_CLOSE_FN callback, void *ctx); + +/** + * 添加附加超时回调函数 + * @param astream {ACL_ASTREAM*} 异步流,不能为空 + * @param callback {ACL_AIO_READ_FN} 回调函数,不能为空 + * @param ctx {void*} callback 回调函数的回调参数,可以为空 + */ +ACL_API void acl_aio_add_timeo_hook(ACL_ASTREAM *astream, + ACL_AIO_TIMEO_FN callback, void *ctx); + +/** + * 添加附加连接成功回调函数 + * @param astream {ACL_ASTREAM*} 异步流,不能为空 + * @param callback {ACL_AIO_READ_FN} 回调函数,不能为空 + * @param ctx {void*} callback 回调函数的回调参数,可以为空 + */ +ACL_API void acl_aio_add_connect_hook(ACL_ASTREAM *astream, + ACL_AIO_CONNECT_FN callback, void *ctx); + +/** + * 删除附加读回调函数 + * @param astream {ACL_ASTREAM*} 异步流,不能为空 + * @param callback {ACL_AIO_READ_FN} 回调函数,不能为空 + * @param ctx {void*} callback 回调函数的回调参数,可以为空 + */ +ACL_API void acl_aio_del_read_hook(ACL_ASTREAM *astream, + ACL_AIO_READ_FN callback, void *ctx); + +/** + * 删除附加写回调函数 + * @param astream {ACL_ASTREAM*} 异步流,不能为空 + * @param callback {ACL_AIO_READ_FN} 回调函数,不能为空 + * @param ctx {void*} callback 回调函数的回调参数,可以为空 + */ +ACL_API void acl_aio_del_write_hook(ACL_ASTREAM *astream, + ACL_AIO_WRITE_FN callback, void *ctx); + +/** + * 删除附加关闭回调函数 + * @param astream {ACL_ASTREAM*} 异步流,不能为空 + * @param callback {ACL_AIO_READ_FN} 回调函数,不能为空 + * @param ctx {void*} callback 回调函数的回调参数,可以为空 + */ +ACL_API void acl_aio_del_close_hook(ACL_ASTREAM *astream, + ACL_AIO_CLOSE_FN callback, void *ctx); + +/** + * 删除附加超时回调函数 + * @param astream {ACL_ASTREAM*} 异步流,不能为空 + * @param callback {ACL_AIO_READ_FN} 回调函数,不能为空 + * @param ctx {void*} callback 回调函数的回调参数,可以为空 + */ +ACL_API void acl_aio_del_timeo_hook(ACL_ASTREAM *astream, + ACL_AIO_TIMEO_FN callback, void *ctx); + +/** + * 删除附加连接成功回调函数 + * @param astream {ACL_ASTREAM*} 异步流,不能为空 + * @param callback {ACL_AIO_READ_FN} 回调函数,不能为空 + * @param ctx {void*} callback 回调函数的回调参数,可以为空 + */ +ACL_API void acl_aio_del_connect_hook(ACL_ASTREAM *astream, + ACL_AIO_CONNECT_FN callback, void *ctx); + +/** + * 清除所有的附加读回调函数 + * @param astream {ACL_ASTREAM*} 异步流,不能为空 + */ +ACL_API void acl_aio_clean_read_hooks(ACL_ASTREAM *astream); + +/** + * 清除所有的附加写回调函数 + * @param astream {ACL_ASTREAM*} 异步流,不能为空 + */ +ACL_API void acl_aio_clean_write_hooks(ACL_ASTREAM *astream); + +/** + * 清除所有的附加关闭回调函数 + * @param astream {ACL_ASTREAM*} 异步流,不能为空 + */ +ACL_API void acl_aio_clean_close_hooks(ACL_ASTREAM *astream); + +/** + * 清除所有的附加超时回调函数 + * @param astream {ACL_ASTREAM*} 异步流,不能为空 + */ +ACL_API void acl_aio_clean_timeo_hooks(ACL_ASTREAM *astream); + +/** +* 清除所有的附加连接成功回调函数 +* @param astream {ACL_ASTREAM*} 异步流,不能为空 +*/ +ACL_API void acl_aio_clean_connect_hooks(ACL_ASTREAM *astream); + +/** + * 清除所有的附加回调函数 + * @param astream {ACL_ASTREAM*} 异步流,不能为空 + */ +ACL_API void acl_aio_clean_hooks(ACL_ASTREAM *astream); + +/** + * 设置异步流的属性 + * @param astream {ACL_ASTREAM*} 异步流对象 + * @param name {int} 第一个控制参数 + * @param ... 变参列表,格式为:ACL_AIO_CTL_XXX, xxx, 最后一个控制参数 + * 为 ACL_AIO_CTL_END + */ +ACL_API void acl_aio_ctl(ACL_ASTREAM *astream, int name, ...); +#define ACL_AIO_CTL_END 0 /**< 控制结束标志 */ +#define ACL_AIO_CTL_ACCEPT_FN 1 /**< 设置接收连接后回调函数 */ +#define ACL_AIO_CTL_LISTEN_FN 2 /**< 设置有连接到达时回调函数 */ +#define ACL_AIO_CTL_CTX 3 /**< 设置应用的参数 */ +#define ACL_AIO_CTL_TIMEOUT 4 /**< 设置超时时间 */ +#define ACL_AIO_CTL_STREAM 10 /**< 设置ACL_VSTREAM流指针 */ +#define ACL_AIO_CTL_READ_NESTED 11 /**< 设置最大读嵌套层数 */ +#define ACL_AIO_CTL_WRITE_NESTED 12 /**< 设置最大写嵌套层数 */ +#define ACL_AIO_CTL_KEEP_READ 13 /**< 设置是否连续读标志 */ +#define ACL_AIO_CTL_READ_HOOK_ADD 14 /**< 添加附加读回调函数 */ +#define ACL_AIO_CTL_READ_HOOK_DEL 15 /**< 删除附加读回调函数 */ +#define ACL_AIO_CTL_WRITE_HOOK_ADD 16 /**< 添加附加写回调函数 */ +#define ACL_AIO_CTL_WRITE_HOOK_DEL 17 /**< 删除附加写回调函数 */ +#define ACL_AIO_CTL_CLOSE_HOOK_ADD 18 /**< 添加附加关闭回调函数 */ +#define ACL_AIO_CTL_CLOSE_HOOK_DEL 19 /**< 删除附加关闭回调函数 */ +#define ACL_AIO_CTL_TIMEO_HOOK_ADD 20 /**< 添加附加超时回调函数 */ +#define ACL_AIO_CTL_TIMEO_HOOK_DEL 21 /**< 删除附加超时回调函数 */ +#define ACL_AIO_CTL_CONNECT_HOOK_ADD 22 /**< 添加附加连接回调函数 */ +#define ACL_AIO_CTL_CONNECT_HOOK_DEL 23 /**< 删除附加连接回调函数 */ + +/** + * 从异步流中提取 ACL_VSTREAM 流 + * @param astream {ACL_ASTREAM*} 异步IO流 + * @return {ACL_VSTREAM*} 通信流指针 + */ +ACL_API ACL_VSTREAM *acl_aio_vstream(ACL_ASTREAM *astream); + +/*---------------------------- 异步读操作接口 --------------------------------*/ + +/** + * 异步从流中读取一行数据, 当成功读取一行数据、出错、读超时时将回调用户的 + * 注册函数: notify_fn + * @param astream {ACL_ASTREAM*} 受监控的流, 当该流有完整的一行数据、出错 + * 或读超时时将回调用户的注册函数. + * 注: 读操作发生在异步框架内. + */ +ACL_API void acl_aio_gets(ACL_ASTREAM *astream); + +/** + * 异步从流中读取一行数据, 当成功读取一行数据、出错、读超时时将回调用户的 + * 注册函数: notify_fn, 与 acl_aio_gets 功能类似, 但唯一的区别是返回的数据 data + * 中不包含 "\r\n" 或 "\n", 当读到一个空行时, 则 dlen == 0. + * @param astream {ACL_ASTREAM*} 受监控的流, 当该流有完整的一行数据、出错 + * 或读超时时将回调用户的注册函数. + * 注: 读操作发生在异步框架内. + */ +ACL_API void acl_aio_gets_nonl(ACL_ASTREAM *astream); + +/** + * 异步从流中读取数据, 读取的数据格式及长度没有特殊要求. + * @param astream {ACL_ASTREAM*} 处于读监控的流. 当该流出错、超时或已经读取了一定 + * 长度的数据时将触发事件通知过程 + * 注: 读操作发生在异步框架内. + */ +ACL_API void acl_aio_read(ACL_ASTREAM *astream); + +/** + * 异步从流中读取要求长度的数据, 当流出错、超时或读到了所要求的数据长度时将 + * 触发事件通知过程 + * @param astream {ACL_ASTREAM*} 处于读监控的流. 当该流出错、超时或已经读取了所 + * 要求长度的数据时将触发事件通知过程 + * @param count {int} 所要求的数据的长度, 必须大于 0. + * 注: 读操作发生在异步框架内. + */ +ACL_API void acl_aio_readn(ACL_ASTREAM *astream, int count); + +/** + * 尝试性读取一行数据 + * @param astream {ACL_ASTREM*} 异步流对象 + * @return {ACL_VSTRING*} 若读得完整一行则返回非空对象,用户用完此 ACL_VSTRING + * 数据后应调用 ACL_VSTRING_RESET(s) 清空缓冲区; 若未读得完整行则返回空 + */ +ACL_API ACL_VSTRING *acl_aio_gets_peek(ACL_ASTREAM *astream); + +/** + * 尝试性读取一行数据(不包含 \n 或 \r\n) + * @param astream {ACL_ASTREM*} 异步流对象 + * @return {ACL_VSTRING*} 若读得完整一行则返回非空对象,用户用完此 ACL_VSTRING + * 数据后应调用 ACL_VSTRING_RESET(s) 清空缓冲区, 另外如果读到一个空行,则返回的 + * ACL_VSTRING 的缓冲区的数据长度(ACL_VSTRING_LEN 获得此值) 应为 0; + * 若未读得完整行则返回空 + */ +ACL_API ACL_VSTRING *acl_aio_gets_nonl_peek(ACL_ASTREAM *astream); + +/** + * 尝试性从异步流中读取数据,如果有数据则返回没有则返回空 + * @param astream {ACL_ASTREM*} 异步流对象 + * @return {ACL_VSTRING*} 若读到了数据则返回的缓冲区非空(使用者用完此缓冲区后 + * 需要调用 ACL_VSTRING_RESET(s) 清空此缓冲区), 否则返回空 + */ +ACL_API ACL_VSTRING *acl_aio_read_peek(ACL_ASTREAM *astream); + +/** + * 尝试性从异步流中读给定长度的数据,如果读到的数据满足要求则返回缓冲区 + * @param astream {ACL_ASTREM*} 异步流对象 + * @param count {int} 要求读到的数据长度 + * @return {ACL_VSTRING*} 若读到规定长度则返回非空缓冲区(使用者用完此缓冲区后 + * 需要调用 ACL_VSTRING_RESET(s) 清空此缓冲区), 否则返回空 + */ +ACL_API ACL_VSTRING *acl_aio_readn_peek(ACL_ASTREAM *astream, int count); + +/** + * 设置异步流为读监听状态,当该流可读时则调用用户的回调函数 + * @param astream {ACL_ASTREM*} 异步流对象 + * @param can_read_fn {ACL_AIO_NOTIFY_FN} 用户回调函数 + * @param context {void*} can_read_fn 的参数之一 + */ +ACL_API void acl_aio_enable_read(ACL_ASTREAM *astream, + ACL_AIO_NOTIFY_FN can_read_fn, void *context); + +/** + * 检测异步流有多少数据可读 + * @param astream {ACL_ASTREM*} 异步流对象 + * @return {int} ACL_VSTREAM_EOF 表示出错,应该关闭该流; 0 表示无数据可读; + * > 0 表示有数据可读 + */ +ACL_API int acl_aio_can_read(ACL_ASTREAM *astream); + +/** + * 停止对一个数据流进行IO读操作 + * @param astream {ACL_ASTREAM*} 异步数据流 + */ +ACL_API void acl_aio_disable_read(ACL_ASTREAM *astream); + +/** + * 判断流是否在异步事件的读监听集合中 + * @param astream {ACL_ASTREAM*} 异步数据流 + * @return {int} 0: 否,!= 0: 是 + */ +ACL_API int acl_aio_isrset(ACL_ASTREAM *astream); + +/** + * 单独设置异步流的连续读标记,缺省情况下自动继承 ACL_AIO 中的 keep_read + * 标记(其默认情况下是连续读) + * @param astream {ACL_ASTREAM*} 异步数据流 + * @param onoff {int} 0 表示关闭连续读功能,非0表示打开连续读功能 + */ +ACL_API void acl_aio_stream_set_keep_read(ACL_ASTREAM *astream, int onoff); + +/** + * 获得异步流是否是设置了连续读标记 + * @return {int} 0 表示关闭了连续读功能,非0表示打开了连续读功能 + */ +ACL_API int acl_aio_stream_get_keep_read(ACL_ASTREAM *astream); + +/*---------------------------- 异步写操作接口 --------------------------------*/ + +/** + * 异步向流中写数据, 当流出错、写超时或写成功时将触发事件通知过程 + * @param astream {ACL_ASTREAM*} 处于写监控的流. + * @param data {const char*} 所写数据的内存开始指针位置 + * @param dlen {int} data 中数据长度 + */ +ACL_API void acl_aio_writen(ACL_ASTREAM *astream, const char *data, int dlen); + +/** + * 异步向流中写数据, 当流出错、写超时或写成功时将触发事件通知过程,类似系统的 + * writev + * @param astream {ACL_ASTREAM*} 处于写监控的流. + * @param vector {const struct iovec*} 数据集合数组 + * @param count {int} vector 数组的长度 + */ +ACL_API void acl_aio_writev(ACL_ASTREAM *astream, const struct iovec *vector, int count); + +/** + * 以格式方式异步向流中写数据, 当流出错、写超时或写成功时将触发事件通知过程 + * @param astream {ACL_ASTREAM*} 处于写监控的流 + * @param fmt {const char*} 格式字符串 + * @param ap {va_list} 格式字符串的参数列表 + */ +ACL_API void acl_aio_vfprintf(ACL_ASTREAM *astream, const char *fmt, va_list ap); + +/** + * 以格式方式异步向流中写数据, 当流出错、写超时或写成功时将触发事件通知过程 + * @param astream {ACL_ASTREAM*} 处于写监控的流 + * @param fmt {const char*} 格式字符串 + * @param ... 变参参数表 + */ +#ifdef WIN32 +ACL_API void acl_aio_fprintf(ACL_ASTREAM *astream, const char *fmt, ...); +#else +ACL_API void __attribute__((format(printf,2,3))) + acl_aio_fprintf(ACL_ASTREAM *astream, const char *fmt, ...); +#endif + +/** + * 设置异步流为写监听状态,当该流可写时则调用用户的回调函数 + * @param astream {ACL_ASTREM*} 异步流对象 + * @param can_write_fn {ACL_AIO_NOTIFY_FN} 用户回调函数 + * @param context {void*} can_write_fn 的参数之一 + */ +ACL_API void acl_aio_enable_write(ACL_ASTREAM *astream, + ACL_AIO_NOTIFY_FN can_write_fn, void *context); + +/** + * 停止对一个数据流进行IO写操作 + * @param astream {ACL_ASTREAM*} 异步数据流 + */ +ACL_API void acl_aio_disable_write(ACL_ASTREAM *astream); + +/** + * 判断流是否在异步事件的写监听集合中 + * @param astream {ACL_ASTREAM*} 异步数据流 + * @return {int} 0: 否,!= 0: 是 + */ +ACL_API int acl_aio_iswset(ACL_ASTREAM *astream); + +/*---------------------------- 异步监听操作接口 ------------------------------*/ + +/** + * 异步接收一个客户端连接流, 并将该客户端流回传给用户 + * @param astream {ACL_ASTREAM*} 处于监听状态的流 + */ +ACL_API void acl_aio_accept(ACL_ASTREAM *astream); + +/** + * 异步监听, 当监听流上出错、超时或有新连接到达时将触发监听事件通知过程, 当有新连接时 + * 用户需在自己的注册函数里 accept() 该新连接. + * @param astream {ACL_ASTREAM*} 处于监听状态的流 + */ +ACL_API void acl_aio_listen(ACL_ASTREAM *astream); + +/*---------------------------- 异步连接操作接口 ------------------------------*/ + +/** + * 异步连接一个远程服务器, 当连接流出错、超时或连接成功时将触发事件通知过程. + * @param aio {ACL_AIO*} 异步框架引擎句柄 + * @param saddr {const char*} 远程服务器监听地址, 格式: ip:port, 如: 192.168.0.1:80 + * @param timeout {int} 连接超时的时间值,单位为秒 + * @return {ACL_ASTREAM*} 创建异步连接过程是否成功 + */ +ACL_API ACL_ASTREAM *acl_aio_connect(ACL_AIO *aio, const char *saddr, int timeout); + +/*---------------------------- 其它通用异步操作接口 --------------------------*/ + +/** + * 停止对一个数据流进行IO读写操作 + * @param astream {ACL_ASTREAM*} 异步数据流 + */ +ACL_API void acl_aio_disable_readwrite(ACL_ASTREAM *astream); + +/** + * 判断流是否在异步事件的读或写监听集合中 + * @param astream {ACL_ASTREAM*} 异步数据流 + * @return {int} 0: 否,!= 0: 是 + */ +ACL_API int acl_aio_isset(ACL_ASTREAM *astream); + +/** + * 获得当前异步流的引用计数值 + * @param astream {ACL_ASTREAM*} 异步数据流 + * @return {int} >=0,异步流的引用计数值 + */ +ACL_API int acl_aio_refer_value(ACL_ASTREAM * astream); + +/** + * 将异步流的引用计数值加1 + * @param astream {ACL_ASTREAM*} 异步数据流 + */ +ACL_API void acl_aio_refer(ACL_ASTREAM *astream); + +/** + * 将异步流的引用计数值减1 + * @param astream {ACL_ASTREAM*} 异步数据流 + */ +ACL_API void acl_aio_unrefer(ACL_ASTREAM *astream); + +/** + * 给任务工作池添加一个定时器任务, 该函数仅是 acl_event_request_timer 的简单封装. + * @param aio {ACL_AIO*} 异步通信引擎句柄 + * @param timer_fn {ACL_AIO_TIMER_FN} 定时器任务回调函数. + * @param context {void*} timer_fn 的参数之一. + * @param idle_limit {acl_int64} 启动定时器函数的时间,单位为微秒. + * @param keep {int} 是否重复定时器任务 + * @return {acl_int64} 剩余的时间, 单位为微秒. + */ + ACL_API acl_int64 acl_aio_request_timer(ACL_AIO *aio, ACL_AIO_TIMER_FN timer_fn, + void *context, acl_int64 idle_limit, int keep); + +/** + * 取消某个定时器任务, 该函数仅是 acl_event_cancel_timer 的简单封装. + * @param aio {ACL_AIO*} 异步通信引擎句柄 + * @param timer_fn {ACL_AIO_TIMER_FN} 定时器任务回调函数. + * @param context {void*} timer_fn 的参数之一. + * @return {acl_int64} 剩余的时间, 单位为微秒. + */ +ACL_API acl_int64 acl_aio_cancel_timer(ACL_AIO *aio, ACL_AIO_TIMER_FN timer_fn, void *context); + +/** + * 设置是否需要循环启用通过 acl_aio_request_timer 设置的定时器任务 + * @param aio {ACL_AIO*} 异步通信引擎句柄 + * @param timer_fn {ACL_AIO_TIMER_FN} 定时器任务回调函数. + * @param context {void*} timer_fn 的参数之一. + * @param onoff {int} 是否重复定时器任务 + */ +ACL_API void acl_aio_keep_timer(ACL_AIO *aio, ACL_AIO_TIMER_FN callback, + void *context, int onoff); + +/** + * 判断所设置的定时器都处于重复使用状态 + * @param aio {ACL_AIO*} 异步通信引擎句柄 + * @param timer_fn {ACL_AIO_TIMER_FN} 定时器任务回调函数. + * @param context {void*} timer_fn 的参数之一. + * @return {int} !0 表示所设置的定时器都处于重复使用状态 + */ +ACL_API int acl_aio_timer_ifkeep(ACL_AIO *aio, ACL_AIO_TIMER_FN callback, void *context); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/include/code/acl_base64.h b/lib_acl/include/code/acl_base64.h new file mode 100644 index 000000000..6ec5c0c30 --- /dev/null +++ b/lib_acl/include/code/acl_base64.h @@ -0,0 +1,35 @@ +#ifndef _ACL_BASE64_CODE_INCLUDE_H_ +#define _ACL_BASE64_CODE_INCLUDE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_define.h" + +/** + * BASE64 编码函数 + * @param plain_in {const char*} 输入的源内容数据 + * @param len {int} plain_in 的数据长度 + * @return {unsigned char*} BASE64编码后的数据,需用 acl_myfree 释放 + */ +ACL_API unsigned char *acl_base64_encode(const char *plain_in, int len); + +/** + * BASE64 解码函数 + * @param code_in {const char*} 经BASE64编码后的数据 + * @param ppresult {char**} 如果解码成功,则存储解码结果,且不用时需用 + * acl_myfree 来释放其内存空间 + * @return {int} -1: 表示解码失败且 *ppresult 指向NULL; >0: 表示解码后的数据内容 + * 长度,且 *ppresult 指向一新动态分配的内存区,内部存储解码结果,需用 acl_myfree + * 释放 *ppresult 的动态内存 + */ +ACL_API int acl_base64_decode(const char *code_in, char **ppresult); + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/include/code/acl_code.h b/lib_acl/include/code/acl_code.h new file mode 100644 index 000000000..088b213a4 --- /dev/null +++ b/lib_acl/include/code/acl_code.h @@ -0,0 +1,20 @@ +#ifndef __ACL_CODE_INCLUDE_H__ +#define __ACL_CODE_INCLUDE_H__ + +# ifdef __cplusplus +extern "C" { +# endif + +#include "acl_base64.h" +#include "acl_vstring_base64.h" +#include "acl_urlcode.h" +#include "acl_gbcode.h" +#include "acl_htmlcode.h" +#include "acl_xmlcode.h" + +# ifdef __cplusplus +} +# endif + +#endif + diff --git a/lib_acl/include/code/acl_gbcode.h b/lib_acl/include/code/acl_gbcode.h new file mode 100644 index 000000000..ac41a0c7d --- /dev/null +++ b/lib_acl/include/code/acl_gbcode.h @@ -0,0 +1,32 @@ +#ifndef __ACL_GBCODE_INCLUDE_H__ +#define __ACL_GBCODE_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif +#include "stdlib/acl_define.h" + +/** + * 将GBK字符集中的简体转换为GBK字符集中的繁体 + * @param data {const char*} 简体数据 + * @param dlen {size_t} data 长度 + * @param buf {char*} 存储转换后结果,其中 buf 地址和 data 可以是同一地址 + * @param size {size_t} buf 空间大小 + */ +ACL_API void acl_gbjt2ft(const char *data, size_t dlen, char *buf, size_t size); + + +/** + * 将GBK字符集中的繁体转换为GBK字符集中的简体 + * @param data {const char*} 繁体数据 + * @param dlen {size_t} data 长度 + * @param buf {char*} 存储转换后结果,其中 buf 地址和 data 可以是同一地址 + * @param size {size_t} buf 空间大小 + */ +ACL_API void acl_gbft2jt(const char *data, size_t dlen, char *buf, size_t size); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/include/code/acl_htmlcode.h b/lib_acl/include/code/acl_htmlcode.h new file mode 100644 index 000000000..cc2550ffd --- /dev/null +++ b/lib_acl/include/code/acl_htmlcode.h @@ -0,0 +1,18 @@ +#ifndef __ACL_HTMLCODE_INCLUDE_H__ +#define __ACL_HTMLCODE_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_define.h" +#include "stdlib/acl_vstring.h" + +ACL_API int acl_html_encode(const char *in, ACL_VSTRING *out); +ACL_API int acl_html_decode(const char *in, ACL_VSTRING *out); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/include/code/acl_urlcode.h b/lib_acl/include/code/acl_urlcode.h new file mode 100644 index 000000000..97c9b33c3 --- /dev/null +++ b/lib_acl/include/code/acl_urlcode.h @@ -0,0 +1,27 @@ +#ifndef __ACL_URLCODE_INCLUDE_H__ +#define __ACL_URLCODE_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_define.h" + +/** + * URL 编码函数 + * @param str {const char*} 源字符串 + * @return {char*} 编码后的字符串,返回值不可能为空,需要用 acl_myfree 释放 + */ +ACL_API char *acl_url_encode(const char *str); + +/** + * URL 解码函数 + * @param str {const char*} 经URL编码后的字符串 + * @return {char*} 解码后的字符串,返回值不可能为空,需要用 acl_myfree 释放 + */ +ACL_API char *acl_url_decode(const char *str); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/lib_acl/include/code/acl_vstring_base64.h b/lib_acl/include/code/acl_vstring_base64.h new file mode 100644 index 000000000..bad52e123 --- /dev/null +++ b/lib_acl/include/code/acl_vstring_base64.h @@ -0,0 +1,33 @@ +#ifndef _ACL_VSTRING_BASE64_CODE_H_INCLUDED_ +#define _ACL_VSTRING_BASE64_CODE_H_INCLUDED_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_define.h" +#include "stdlib/acl_vstring.h" + +/** + * BASE64 编码函数 + * @param vp {ACL_VSTRING*} 存储编码后结果 + * @param in {const char*} 源数据 + * @param len {int} in 源数据的长度 + * @return {ACL_VSTRING*} 与 vp 相同 + */ +ACL_API ACL_VSTRING *acl_vstring_base64_encode(ACL_VSTRING *vp, const char *in, int len); + +/** + * BASE64 解码函数 + * @param vp {ACL_VSTRING*} 存储解码后结果 + * @param in {const char*} 编码后的数据 + * @param len {int} in 数据长度 + * @return {ACL_VSTRING*} NULL: 解码失败; !=NULL: 解码成功且与 vp 相同地址 + */ +ACL_API ACL_VSTRING *acl_vstring_base64_decode(ACL_VSTRING *vp, const char *in, int len); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/include/code/acl_xmlcode.h b/lib_acl/include/code/acl_xmlcode.h new file mode 100644 index 000000000..d0442aa18 --- /dev/null +++ b/lib_acl/include/code/acl_xmlcode.h @@ -0,0 +1,18 @@ +#ifndef __ACL_XMLCODE_INCLUDE_H__ +#define __ACL_XMLCODE_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_define.h" +#include "stdlib/acl_vstring.h" + +ACL_API int acl_xml_encode(const char *in, ACL_VSTRING *out); +ACL_API int acl_xml_decode(const char *in, ACL_VSTRING *out); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/include/db/acl_db.h b/lib_acl/include/db/acl_db.h new file mode 100644 index 000000000..a0a176ae2 --- /dev/null +++ b/lib_acl/include/db/acl_db.h @@ -0,0 +1,18 @@ +#ifndef _ACL_MYDB_INCLUDE_H_ +#define _ACL_MYDB_INCLUDE_H_ + +# ifdef __cplusplus +extern "C" { +# endif + +#include "acl_dbpool.h" +#include "acl_dberr.h" +#include "acl_dbsql.h" +#include "acl_mdb.h" + +# ifdef __cplusplus +} +# endif + +#endif + diff --git a/lib_acl/include/db/acl_dberr.h b/lib_acl/include/db/acl_dberr.h new file mode 100644 index 000000000..170a3b03f --- /dev/null +++ b/lib_acl/include/db/acl_dberr.h @@ -0,0 +1,22 @@ +#ifndef __ACL_DBERR_INCLUDE_H__ +#define __ACL_DBERR_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#define ACL_DB_OK 0 /* 成功 */ +#define ACL_DB_ERR_CALLBACK 1 /* 用户的回调函数返回失败 */ +#define ACL_DB_ERR_SELECT 100 /* 用户查询语句失败 */ +#define ACL_DB_ERR_UPDATE 101 /* 用户更新语句失败 */ +#define ACL_DB_ERR_EMPTY 102 /* 查询结果为空 */ +#define ACL_DB_ERR_STORE 103 /* 查询语句获得的结果后存储于本地时失败 */ +#define ACL_DB_ERR_AFFECTED 104 /* 更新语句对数据库无实际更新操作 */ +#define ACL_DB_ERR_ALLOC 105 /* 内部分配内存失败 */ + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/include/db/acl_dbpool.h b/lib_acl/include/db/acl_dbpool.h new file mode 100644 index 000000000..7d35c697a --- /dev/null +++ b/lib_acl/include/db/acl_dbpool.h @@ -0,0 +1,153 @@ +#ifndef __ACL_DBPOOL_INCLUDE_H__ +#define __ACL_DBPOOL_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_define.h" +#include +#include "stdlib/acl_stdlib.h" + +#define ACL_DB_DEBUG_MEM (1<<0) + +typedef struct ACL_DB_HANDLE ACL_DB_HANDLE; +typedef struct ACL_SQL_RES ACL_SQL_RES; +typedef struct ACL_DB_POOL ACL_DB_POOL; + +typedef struct ACL_DB_INFO { + int db_max; /* 连接池最大连接数 */ + char db_addr[256]; /* 数据库服务地址 */ + char db_name[256]; /* 数据库名称 */ + char db_user[256]; /* 数据库帐号 */ + char db_pass[256]; /* 帐号密码 */ + unsigned long db_flags; /* (mysql) 连接标志位 */ + int ping_inter; /* 探测数据库连接的时间间隔 */ + int timeout_inter; /* 数据库连接的空闲超时时间 */ + int auto_commit; /* (mysql) 是否启用自动提交过程 */ + int conn_timeout; /* (mysql/null) 连接超时时间 */ + int rw_timeout; /* (mysql/null) IO读写超时时间 */ + int buf_size; /* (null) IO缓冲区大小 */ + int debug_flag; /* 调试标志位 */ + + /* 在真实连接数据库之前/后调用用户设置的回调函数, 此项可以设为 NULL, + * 如果 db_before_connect/db_after_connect 返回 < 0 则会导致 + * acl_dbpool_peek 返回 NULL + */ + int (*db_before_connect)(ACL_DB_HANDLE* db_handle, void *ctx); + int (*db_after_connect)(ACL_DB_HANDLE* db_handle, void *ctx); + + void *ctx; /* db_before_connect/db_after_connect 参数之一 */ +} ACL_DB_INFO; + +struct ACL_DB_HANDLE { +#define ACL_DBH_STATUS_NULL 0 +#define ACL_DBH_STATUS_READY 1 +#define ACL_DBH_STATUS_INUSE 2 + int status; + time_t timeout; + time_t ping; + + ACL_DB_POOL *parent; + + int (*sql_results)(ACL_DB_HANDLE *handle, const char *sql, int *error, + int (*walk_fn)(const void** result_row, void *arg), void *arg); + int (*sql_result)(ACL_DB_HANDLE *handle, const char *sql, int *error, + int (*callback)(const void** result_row, void *arg), void *arg); + int (*sql_update)(ACL_DB_HANDLE *handle, const char *sql, int *error); + + ACL_SQL_RES *(*sql_select)(ACL_DB_HANDLE *handle, const char *sql, int *error); + void (*free_result)(ACL_SQL_RES *res); +}; + +struct ACL_SQL_RES { + void *res; + int num; + + /* for acl_iterator */ + + /* 取迭代器头函数 */ + const void *(*iter_head)(ACL_ITER*, struct ACL_SQL_RES*); + /* 取迭代器下一个函数 */ + const void *(*iter_next)(ACL_ITER*, struct ACL_SQL_RES*); +}; + +struct ACL_DB_POOL { + ACL_DB_INFO db_info; + + ACL_DB_HANDLE *(*dbh_peek)(ACL_DB_POOL *); + void (*dbh_check)(ACL_DB_POOL *); + void (*dbh_release)(ACL_DB_HANDLE *); + void *(*dbh_export)(ACL_DB_HANDLE *); + void (*dbh_close)(ACL_DB_HANDLE *); + int (*dbh_ping)(ACL_DB_HANDLE *); + + void (*destroy)(ACL_DB_POOL *); + + int db_max; + int db_ready; + int db_inuse; +}; + +/*----------------------------------------------------------------------------*/ +#define ACL_DB_AUTO_COMMIT(_db_pool_) (_db_pool_ ? _db_pool_->db_info.auto_commit : 0) + +/* in acl_dbpool.c */ +/** + * 创建一个数据库连接池 + * @param db_type {const char*} 数据库类型名, 目前仅支持 mysql + * @param db_info {const ACL_DB_INFO*} 记录着有关连接数据所需要的信息 + * @return {ACL_DB_POOL*} 一个数据库连接池 + */ +ACL_API ACL_DB_POOL *acl_dbpool_create(const char *db_type, const ACL_DB_INFO *db_info); + +/** + * 销毁一个数据库连接池 + * @param db_pool 数据库连接池句柄 + */ +ACL_API void acl_dbpool_destroy(ACL_DB_POOL *db_pool); + +/** + * 从连接池中获取一个连接句柄 + * @param db_pool {ACL_DB_POOL*} 数据库连接池句柄 + * @return {ACL_DB_HANDLE*} 数据库连接句柄,如果为空则表示出错或连接池已满 + */ +ACL_API ACL_DB_HANDLE *acl_dbpool_peek(ACL_DB_POOL *db_pool); + +/** + * 手工检查连接池的每个连接?一般连接池内部会定期检查每个连接, + * 也可以通过此函数手工进行强制检查 + * @param db_pool {ACL_DB_POOL*} 数据库连接池句柄 + */ +ACL_API void acl_dbpool_check(ACL_DB_POOL *db_pool); + +/** + * 将数据库连接句柄释放给数据库连接池 + * @param db_handle {ACL_DB_HANDLE*} 数据库连接句柄 + */ +ACL_API void acl_dbpool_release(ACL_DB_HANDLE *db_handle); +/** + * 将数据库连接转换为实际的数据库连接句柄 + * @param db_handle {ACL_DB_HANDLE*} 数据库连接句柄 + * @return void * 使用者需要将其强制转换为自己所用的数据库连接引擎 + */ +ACL_API void *acl_dbpool_export(ACL_DB_HANDLE *db_handle); +/** + * 当使用者自己检测到该数据库连接出错时,可以通过此接口强行关闭该连接 + * @param db_handle {ACL_DB_HANDLE*} 数据库连接句柄 + */ +ACL_API void acl_dbpool_close(ACL_DB_HANDLE *db_handle); + +/** + * 设置连接池的定时PING处理函数,如果不设置此值则内部采用缺省方式 + * @param db_pool {ACL_DB_POOL*} 数据库连接池句柄 + * @param ping_fn {int (*)(ACL_DB_HANDLE*)} 探测连接状态的函数指针 + */ +ACL_API void acl_dbpool_set_ping(ACL_DB_POOL *db_pool, int (*ping_fn)(ACL_DB_HANDLE*)); +/*----------------------------------------------------------------------------*/ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/include/db/acl_dbsql.h b/lib_acl/include/db/acl_dbsql.h new file mode 100644 index 000000000..5744c6d1f --- /dev/null +++ b/lib_acl/include/db/acl_dbsql.h @@ -0,0 +1,106 @@ +#ifndef __ACL_DBSQL_INCLUDE_H__ +#define __ACL_DBSQL_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_define.h" +#include "acl_dbpool.h" + +#ifndef ACL_DB_ATOU +#define ACL_DB_ATOU(_str_) (_str_ ? strtoul(_str_, (char **) NULL, 10) : 0) +#endif + +/** + * 数据库查询语句,根据用户输入的 select SQL 语句从数据库里查询结果 + * @param handle {ACL_DB_HANDLE*} 数据库连接句柄,不能为空 + * @param sql {const char*} select 查询语句,不能为空 + * @param error {int*} 如果返回值 NULL 且该变量非空指针则该指针的地址被 + * 赋予出错的错误号,错误号参见 acl_dberr.h + * @return {ACL_SQL_RES*} 查询结果集,如果查询失败或查询结果为空,则返回 + * NULL,否则返回 ACL_SQL_RES 对象(用完后该结果需要调用 acl_dbsql_free_result + * 释放),示例: + * + * ACL_DB_HANDLE* handle = ...; + * ACL_SQL_RES* res = acl_dbsql_select(...); + * ACL_ITER iter; + * if (res) + * { + * acl_foreach(iter, res) + * { + * const char **my_row = (const char**) iter.data; + * printf("first item: %s\n", my_row[0]); + * ... + * } + * acl_dbsql_free_result(handle, res); + * } + * + */ +ACL_API ACL_SQL_RES *acl_dbsql_select(ACL_DB_HANDLE *handle, + const char *sql, int *error); + +/** + * 释放由 acl_dbsql_select 返回的结果集对象 + * @param handle {ACL_DB_HANDLE*} 数据库连接句柄,不能为空 + * @param res {ACL_SQL_RES*} acl_dbsql_select 返回的结果对象,不能为空 + */ +ACL_API void acl_dbsql_free_result(ACL_DB_HANDLE *handle, ACL_SQL_RES *res); + +/** + * 以回调的方式查询数据库中所有符合条件的结果集,查询结果集合通过用户设置 + * 的回调函数返回给用户 + * @param handle {ACL_DB_HANDLE*} 数据库连接句柄,不能为空 + * @param sql {const char*} select 查询语句,不能为空 + * @param error {int*} 如果返回值 -1 且该变量非空指针则该指针的地址被 + * 赋予出错的错误号,错误号参见 acl_dberr.h + * @param walk_fn {int (*)(const void**, void*)},用户设置的查询结果回调函数, + * 非空,每查一条符合条件的结果都回调用该回调函数,如果查询结果为多条,则会 + * 自动回调多次该回调函数,其中的 result_row 是一个数组指针,用户可以在自己 + * 的回调函数里用 result_row[i] 来取得自己所要求的数据列(必须与 select 语句 + * 中的相匹配) + * @param arg {void*} 用户自定义的参数,该参数会自动传递给 walk_fn 回调函数, + * 作为 walk_fn 的最后一个参数返回 + * @return {int} 查询结果总数,如果返回 -1 则表示查询语句失败,0 表示没有符合 + * 查询条件的结果,> 0 表示查询的结果总数 + */ +ACL_API int acl_dbsql_results(ACL_DB_HANDLE *handle, const char *sql, int *error, + int (*walk_fn)(const void** result_row, void *arg), void *arg); + +/** + * 以回调的方式从数据库中查询一条记录,查询结果通过用户设置的回调函数返回给用户 + * @param handle {ACL_DB_HANDLE*} 数据库连接句柄,不能为空 + * @param sql {const char*} select 查询语句,不能为空 + * @param error {int*} 如果返回值 -1 且该变量非空指针则该指针的地址被 + * 赋予出错的错误号,错误号参见 acl_dberr.h + * @param walk_fn {int (*)(const void**, void*)},用户设置的查询结果回调函数, + * 非空,当查到一条符合条件的结果时便回调用该回调函数,与 acl_dbsql_results 不 + * 同,该回调函数最多只会被调用一次,其中的 result_row 是一个数组指针,用户可 + * 以在自己的回调函数里用 result_row[i] 来取得自己所要求的数据列(必须与 select + * 语句中的相匹配) + * @param arg {void*} 用户自定义的参数,该参数会自动传递给 walk_fn 回调函数, + * 作为 walk_fn 的最后一个参数返回 + * @return {int} 返回值只有三种状态,-1 表示查询语句失败,0 表示查询结果为空, + * 1 表示查到一个结果;如果返回 -1 则 *error 记录着失败原因,参见 acl_dberr.h + */ +ACL_API int acl_dbsql_result(ACL_DB_HANDLE *handle, const char *sql, int *error, + int (*walk_fn)(const void** result_row, void *arg), void *arg); + +/** + * 更新数据库数据,update, insert, delete 等修改数据库的操作可以使用该函数 + * @param handle {ACL_DB_HANDLE*} 数据库连接句柄,不能为空 + * @param sql {const char*} 数据库修改语句,不能为空 + * @param error {int*} 如果返回值 -1 且该变量非空指针则该指针的地址被 + * 赋予出错的错误号,错误号参见 acl_dberr.h + * @return {int} 返回值只有三种状态,-1 表示失败(如果 error 指针非空则其中记录着 + * 出错原因,错误号参见: acl_dberr.h),0 表示更新成功,但并未影响数据库原始信息 + * (原因是本信息与数据库原信息相同),> 0 表示更新了数据库中数据存储条数 + */ +ACL_API int acl_dbsql_update(ACL_DB_HANDLE *handle, const char *sql, int *error); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/include/db/acl_mdb.h b/lib_acl/include/db/acl_mdb.h new file mode 100644 index 000000000..ee311b7bb --- /dev/null +++ b/lib_acl/include/db/acl_mdb.h @@ -0,0 +1,267 @@ + +#ifndef __MEMDB_INCLUDE_H_ +#define __MEMDB_INCLUDE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_define.h" + +typedef struct ACL_MDT_NOD ACL_MDT_NOD; +typedef struct ACL_MDT_RES ACL_MDT_RES; +typedef struct ACL_MDT_REC ACL_MDT_REC; +typedef struct ACL_MDT_REF ACL_MDT_REF; +typedef struct ACL_MDT_IDX ACL_MDT_IDX; +typedef struct ACL_MDT ACL_MDT; +typedef struct ACL_MDB ACL_MDB; + +/* 数据表各索引关键字段的约束标志位 */ +#define ACL_MDT_FLAG_NUL (0) +#define ACL_MDT_FLAG_UNI (1 << 0) /**< 表示唯一 */ +#define ACL_MDT_FLAG_KMR (1 << 1) /**< 表示重用键内存 */ +#define ACL_MDT_FLAG_DMR (1 << 2) /**< 表示重用值内存 */ +#define ACL_MDT_FLAG_SLICE1 (1 << 10) /**< 启用 ACL_SLICE_FLAG_GC1 */ +#define ACL_MDT_FLAG_SLICE2 (1 << 11) /**< 启用 ACL_SLICE_FLAG_GC2 */ +#define ACL_MDT_FLAG_SLICE3 (1 << 12) /**< 启用 ACL_SLICE_FLAG_GC3 */ +#define ACL_MDT_FLAG_SLICE_RTGC_OFF (1 << 13) /**< 关闭内存切片的实时垃圾回收功能 */ + +/************************************************************************/ +/* in acl_mdb.c */ +/************************************************************************/ + +/** + * 创建一个数据库句柄 + * @param dbname {const char*} 数据库名 + * @param dbtype {const char*} 数据库类型: hash/avl + * @return {ACL_MDB*} 数据库句柄 + */ +ACL_API ACL_MDB *acl_mdb_create(const char *dbname, const char *dbtype); + +/** + * 关闭并释放一个内存数据库 + * @param {ACL_MDB*} 数据库句柄 + */ +ACL_API void acl_mdb_free(ACL_MDB *mdb); + +/** + * 在给定数据库上创建一个数据表 + * @param mdb {ACL_MDB*} 数据库句柄 + * @param tbl_name {const char*} 表名 + * @param tlb_flag {unsigned int} 表的属性标志位 + * @param init_capacity {size_t} 数据表内针对每个索引键的内部哈希表的初始化容量 + * @param key_labels {const char *[]} 数据表字段名数组 + * @param flags {unsigned int[]} 与 key_labels 相对应的约束标志位 + * @return {ACL_MDT*} 新建的数据表句柄 + */ +ACL_API ACL_MDT *acl_mdb_tbl_create(ACL_MDB *mdb, const char *tbl_name, + unsigned int tbl_flag, size_t init_capacity, + const char *key_labels[], unsigned int flags[]); + +/** + * 添加一条新的数据记录 + * @param mdb {ACL_MDB*} 数据库句柄 + * @param tbl_name {const char*} 数据表名 + * @param data {void*} 应用数据项 + * @param dlen {unsigned int} data 的数据大小 + * @param key_labels {const char *[]} 数据表字段名数组 + * @param keys {const char *[]} 数据表字段名对应值数组 + * @return {ACL_MDB_NOD*} 新添加的数据在数据表中存储的句柄 + */ +ACL_API ACL_MDT_NOD *acl_mdb_add(ACL_MDB *mdb, const char *tbl_name, + void *data, unsigned int dlen, + const char *key_labels[], const char *keys[]); + +/** + * 探测数据表中对应的字段值是否存在 + * @param mdb {ACL_MDB*} 数据库句柄 + * @param tbl_name {const char*} 数据表名 + * @param key_label {const char*} 数据表索引字段名 + * @param key {const char*} 数据表索引字段键值 + * @return {int} 0: 不存在, != 0: 存在 + */ +ACL_API int acl_mdb_probe(ACL_MDB *mdb, const char *tbl_name, + const char *key_label, const char *key); + +/** + * 从数据库中查询符合条件的结果集 + * @param mdb {ACL_MDB*} 数据库句柄 + * @param tbl_name {const char*} 数据表名 + * @param key_label {const char*} 数据表中的字段名 + * @param key {const char*} 数据表中的字段值 + * @param from {int} 查询的结果希望是从该位置开始进行存储 + * @param limit {int} 查询的结果的最大希望个数 + * @return {ACL_MDT_RES*} 查询结果集,如果为空则表明查询结果为空或出错 + */ +ACL_API ACL_MDT_RES *acl_mdb_find(ACL_MDB *mdb, const char *tbl_name, + const char *key_label, const char *key, int from, int limit); + +/** + * 从数据库中列出某数据表中某个范围的结果集 + * @param mdb {ACL_MDB*} 数据库句柄 + * @param tbl_name {const char*} 数据表名 + * @param from {int} 查询的结果希望是从该位置开始进行存储 + * @param limit {int} 查询的结果的最大希望个数 + * @return {ACL_MDT_RES*} 查询结果集,如果为空则表明查询结果为空或出错 + */ +ACL_API ACL_MDT_RES *acl_mdb_list(ACL_MDB *mdb, const char *tbl_name, + int from, int limit); + +/** + * 从数据库中删除一条数据记录 + * @param mdb {ACL_MDB*} 数据库句柄 + * @param tbl_name {const char*} 数据表名 + * @param key_label {const char*} 数据表字段名 + * @param key {const char*} 数据表字段值 + * @param onfree_fn {void (*)(void*, unsigned int)} + * 释放用户的对象时调用的释放回调函数 + * @return {int} 删除的行数量 + */ +ACL_API int acl_mdb_del(ACL_MDB *mdb, const char *tbl_name, + const char *key_label, const char *key, + void (*onfree_fn)(void*, unsigned int)); + +/** + * 遍历数据库中某个数据表的所有数据结点 + * @param mdb {ACL_MDB*} 数据库句柄 + * @param tbl_name {const char*} 数据表名 + * @param walk_fn 遍历回调函数,如果该函数返回非0值,则停止遍历 + * @param from {int} 查询的结果希望是从该位置开始进行存储 + * @param limit {int} 查询的结果的最大希望个数 + * @return {int} 遍历的数据结点数值 + */ +ACL_API int acl_mdb_walk(ACL_MDB *mdb, const char *tbl_name, + int (*walk_fn)(const void*, unsigned int), + int from, int limit); + +/** + * 数据库中某个数据表中元素总个数 + * @param mdb {ACL_MDB*} 数据库句柄 + * @param tbl_name {const char*} 数据表名 + * @return {int} >=0 + */ +ACL_API int acl_mdb_cnt(ACL_MDB *mdb, const char *tbl_name); + +/************************************************************************/ +/* in acl_mdt.c */ +/************************************************************************/ + +/** + * 创建一个数据表 + * @param dbtype {const char *} 表类型: hash/avl + * @param tbl_name {const char*} 表名 + * @param tlb_flag {unsigned int} 表的属性标志位 + * @param init_capacity {size_t} 每个内部哈希表的初始化容量 + * @param key_labels {const char *[]} 表中的各个字段名数组,最后以NULL结束 + * @param flags {unsigned int[]} 与 key_labels 相对应的约束标志位 + * @return {ACL_MDT*} 新建的数据表的句柄 + */ +ACL_API ACL_MDT *acl_mdt_create(const char *dbtype, const char *tbl_name, + unsigned int tbl_flag, size_t init_capacity, + const char *key_labels[], unsigned int flags[]); + +/** + * 释放一个内存表 + * @param mdt {ACL_MDT*} 内存数据表句柄 + */ +ACL_API void acl_mdt_free(ACL_MDT *mdt); + +/** + * 向数据表中添加一条新的数据记录 + * @param mdt {ACL_MDT*} 数据表句柄 + * @param data {void*} 用户的动态数据, 如果表的 ACL_MDT_FLAG_DMR 标志位 + * 未被设置,则将在内部拷贝一份该动态数据 + * @param dlen {unsigned int} data 的数据长度 + * @param key_labels {const char*[]} 数据表的索引字段名数组,以NULL结束 + * @param keys {const char*[]} 数据表的索引字段值数组,以NULL结束 + * @return {ACL_MDT_NOD*} 新添加的数据结点对象 + */ +ACL_API ACL_MDT_NOD *acl_mdt_add(ACL_MDT *mdt, void *data, + unsigned int dlen, const char *key_labels[], const char *keys[]); + +/** + * 探测数据表中对应的字段值是否存在 + * @param mdt {ACL_MDT*} 数据表句柄 + * @param key_label {const char*} 数据表索引字段名 + * @param key {const char*} 数据表索引字段键值 + * @return {int} 0: 不存在, != 0: 存在 + */ +ACL_API int acl_mdt_probe(ACL_MDT *mdt, const char *key_label, const char *key); + +/** + * 从数据表中查询某个数据表索引键值的结果集合 + * @param mdt {ACL_MDT*} 数据表句柄 + * @param key_label {const char*} 数据表索引字段名 + * @param key {const char*} 数据表索引字段键值 + * @param from {int} 查询的结果希望是从该位置开始进行存储 + * @param limit {int} 查询的结果的最大希望个数 + * @return {ACL_MDT_REC*} 对应某个索引字段值的结果集合 + */ +ACL_API ACL_MDT_RES *acl_mdt_find(ACL_MDT *mdt, const char *key_label, + const char *key, int from, int limit); + +/** + * 从数据表中顺序列出某个范围内的所有数据结点集合 + * @param mdt {ACL_MDT*} 数据表句柄 + * @param from {int} 查询的结果希望是从该位置开始进行存储 + * @param limit {int} 查询的结果的最大希望个数 + * @return {ACL_MDT_REC*} 对应某个索引字段值的结果集合 + */ +ACL_API ACL_MDT_RES *acl_mdt_list(ACL_MDT *mdt, int from, int limit); + +/** + * 从数据表中删除对应某个索引字段键值的结果集合 + * @param mdt {ACL_MDT*} 数据表句柄 + * @param key_label {const char*} 数据表索引字段名 + * @param key {const char*} 数据表索引字段键值 + * @param onfree_fn {void (*)(void*, unsigned int} + * 用户用来释放动态数据的回调函数 + * @return {int} 所释放的数据结点的数目 + */ +ACL_API int acl_mdt_delete(ACL_MDT *mdt, const char *key_label, + const char *key, void (*onfree_fn)(void*, unsigned int)); + +/** + * 遍历数据表的所有数据结点,并回调用户的处理函数 + * @param mdt {ACL_MDT*} 数据表句柄 + * @param walk_fn 回调函数,如果返回0则继续,否则停止遍历 + * @param from {int} 查询的结果希望是从该位置开始进行存储 + * @param len {int} 查询的结果的最大希望个数 + * @return {int} 所遍历的数据长度 + */ +ACL_API int acl_mdt_walk(ACL_MDT *mdt, int (*walk_fn)(const void*, unsigned int), + int from, int len); + +/** + * 从所查询的结果集合中获取下一个数据结果 + * @param res {ACL_MDT_RES*} 数据结果集合 + * @return {void*} 用户自己能够识别的动态数据,若返回NULL表示出错或已经没有数据 + */ +ACL_API const void *acl_mdt_fetch_row(ACL_MDT_RES *res); + +/** + * 获得查询结果集中的记录数 + * @param res {ACL_MDT_RES*} 数据结果集合 + * @return {int} 0: 结果集为空; > 0: 结果集不为空 + */ +ACL_API int acl_mdt_row_count(ACL_MDT_RES *res); + +/** + * 释放查询结果动态内存,但并不释放实际的数据结点 + * @param res {ACL_MDT_RES*} 数据结果集合 + */ +ACL_API void acl_mdt_res_free(ACL_MDT_RES *res); + +/** + * 数据表中所有元素的总数 + * @param mdt {ACL_MDT*} 数据表句柄 + * @return {int} >=0 + */ +ACL_API int acl_mdt_cnt(ACL_MDT *mdt); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/include/db/zdb.h b/lib_acl/include/db/zdb.h new file mode 100644 index 000000000..3e25cb8c1 --- /dev/null +++ b/lib_acl/include/db/zdb.h @@ -0,0 +1,506 @@ +#ifndef __ZDB_INCLUDE_H__ +#define __ZDB_INCLUDE_H__ + +#include "lib_acl.h" + +typedef struct ZDB ZDB; +typedef struct ZDB_KEY_HDR ZDB_KEY_HDR; +typedef struct ZDB_BLK ZDB_BLK; +typedef struct ZDB_BLK_OFF ZDB_BLK_OFF; +typedef struct ZDB_DAT_HDR ZDB_DAT_HDR; +typedef struct ZDB_KEY_STORE ZDB_KEY_STORE; +typedef struct ZDB_DAT_STORE ZDB_DAT_STORE; +typedef struct ZDB_IO ZDB_IO; + +/* 偏移量的长度类型 */ +typedef acl_int64 zdb_off_t; + +/* 键类型定义 */ +typedef acl_int64 zdb_key_t; + +/* 值存储中空闲数据块链接偏移量类型 */ +typedef int zdb_lnk_t; + +/* 磁盘分区信息类型 */ +typedef struct ZDB_DISK { + acl_int64 limit; /* 该分区的总数限制 */ + acl_int64 count; /* 目前该分区已分配数量 */ + char *path; /* 磁盘分区路径 */ + int idisk; /* 该磁盘分区号 */ + int priority; /* 权重优先级 */ + int *dat_ifiles; /* 当前可用的 dat_ifile 值存储文件索引号 */ + int dat_ifiles_size; /* dat_ifiles 的大小 */ +} ZDB_DISK; + +/* 调用 zdb_open() 时的 ZDB 配置对象 */ +typedef struct ZDB_CFG { + const char *key_path; /* 键存储所在的根目录 */ + zdb_key_t key_begin; /* 键值的起始值 */ + zdb_key_t key_limit; /* 每个键存储文件中键的最大个数 */ + acl_int64 dat_limit; /* 每个值存储文件中数据的最大个数 */ + + int key_cache_max; /* 启用键存储 IO 缓存时的最大缓存数据块个数 */ + int key_cache_timeout; /* 启用键存储 IO 缓存时每个缓存块的过期时间 */ + int key_wback_max; /* 启用键存储 IO 缓存时写缓存的最大缓存数据块个数 */ + + int dat_nstep; /* 值存储中增加数据块时的步进值 */ + int blk_dlen; /* 值存储中数据块中数据部分的长度(等于用户数据长度) */ + int dat_cache_max; /* 启用值存储 IO 缓存时的最大缓存数据块个数 */ + int dat_cache_timeout; /* 启用值存储 IO 缓存时每个缓存块的过期时间 */ + int dat_wback_max; /* 启用值存储 IO 缓存时写缓存的最大缓存数据块个数 */ +} ZDB_CFG; + +/* ZDB 结构类型 */ +struct ZDB { + /* public */ + + char *dbname; /* 数据库名 */ + char *key_path; /* ZDB 的key存储路径 */ + unsigned int oflags; /* 打开时的标志位 */ +#define ZDB_FLAG_LINK_BUSY (1 << 0) /* 将值存储中的占用数据块连接起来 */ +#define ZDB_FLAG_OPEN_LOCK (1 << 1) /* 以加锁模式打开存储句柄 */ +#define ZDB_FLAG_CACHE_DAT (1 << 2) /* 是否缓存值存储的数据 */ +#define ZDB_FLAG_CACHE_KEY (1 << 3) /* 是否缓存键存储的数据 */ +#define ZDB_FLAG_SLICE_KEY (1 << 4) /* 启用值存储时是否采用内存切片方式 */ +#define ZDB_FLAG_SLICE_DAT (1 << 5) /* 启用键存储时是否采用内存切片方式 */ + + unsigned int status; /* 状态位 */ +#define ZDB_STAT_KEY_NEW (1 << 0) /* 新键 */ + + /* private */ + + zdb_key_t key_begin; /* 所有键存储的起始值 */ + zdb_key_t key_limit; /* 每个键存储中键的个数的最大值 */ + int key_cache_max; /* 启用键存储 IO 缓存时的最大缓存数据块个数 */ + int key_cache_timeout; /* 启用键存储 IO 缓存时每个缓存块的过期时间 */ + int key_wback_max; /* 启用键存储 IO 缓存时写缓存的最大缓存数据块个数 */ + + acl_int64 dat_limit; /* 值存储中值对象存储个数限制 */ + int blk_dlen; /* 值存储中数据块中每个基础块单元长度 */ + int dat_nstep; /* 值存储中每次增加数据块的个数 */ + int dat_cache_max; /* 启用值存储 IO 缓存时的最大缓存数据块个数 */ + int dat_cache_timeout; /* 启用值存储 IO 缓存时每个缓存块的过期时间 */ + int dat_wback_max; /* 启用值存储 IO 缓存时写缓存的最大缓存数据块个数 */ + + ZDB_DISK *dat_disks; /* 值存储磁盘分区数组 */ + + int (*key_get)(ZDB*, zdb_key_t, ZDB_BLK_OFF*); + int (*key_set) (ZDB*, zdb_key_t, const ZDB_BLK_OFF*); + + ZDB_BLK *(*dat_get)(ZDB*, const ZDB_BLK_OFF*, zdb_key_t*, size_t*); + int (*dat_add)(ZDB*, zdb_key_t, const void*, int); + int (*dat_update)(ZDB*, zdb_key_t, const ZDB_BLK_OFF*, + const void*, size_t); + + /* private */ + + /* 以下为临时变量 */ + + ACL_VSTRING *path_tmp; /* 临时用的存储文件的全路径, 主要为了参数传递 */ + int blk_count_tmp; /* 临时用的块数, 主要为了参数传递 */ + int inode_tmp; /* 临时用的相对路径号,主要为了参数传递 */ +}; + +/* xxx: 为了保证跨平台性,以下结构定义都是4字节对齐的 */ + +#ifdef ACL_SUNOS5 +#pragma pack(4) +#else +#pragma pack(push, 4) +#endif + +/* 值存储头 */ +struct ZDB_DAT_HDR { + acl_int64 limit; /* 值存储中值对象存储个数限制 */ + acl_int64 size; /* 当前值存储文件已经分配的对象存储的个数 */ + acl_int64 count; /* 当前值存储中的总数 */ + acl_int64 reserv1; /* 保留字段 */ + acl_int64 reserv2; /* 保留字段 */ + acl_int64 reserv3; /* 保留字段 */ + acl_int64 reserv4; /* 保留字段 */ + int nstep; /* 每次增加时值存储文件大小时的步进值大小 */ + int blk_hdr_dlen; /* 值存储中每块数据的头部长度: ZDB_BLK_HDR.sizeof */ + int blk_dlen; /* 值存储中数据块中每个基础块单元长度 */ + int blk_count; /* 该值存储中的数据块中基础块个数 */ + + /* 第一个空闲块的位置的真实具体位置的计算公式为: + * zdb_off_t off_head = ZDB_DAT_HDR.sizeof + + * ZDB_DAT_HDR.ihead_idle * (ZDB_DAT_HDR.blk_hdr_dlen + + * ZDB_DAT_HDR.blk_dlen * ZDB_DAT_HDR.blk_count); + */ + zdb_lnk_t ihead_idle; + + /* 第一个数据块的位置的真实具体位置的计算公式为: + * zdb_off_t off_head = ZDB_DAT_HDR.sizeof + + * ZDB_DAT_HDR.ihead_busy * (ZDB_DAT_HDR.blk_hdr_dlen + + * ZDB_DAT_HDR.blk_dlen * ZDB_DAT_HDR.blk_count); + */ + zdb_lnk_t ihead_busy; + zdb_lnk_t itail_busy; + int dummy; /* 保证8字节对齐 */ +}; + +/* 键存储的头 */ +struct ZDB_KEY_HDR { + zdb_key_t key_limit; /* 该键存储的最大容量 */ + zdb_key_t key_count; /* 当前所有键的总数 */ + zdb_key_t key_begin; /* 键的起始值 */ + acl_int64 reserv1; /* 保留字段 */ + acl_int64 reserv2; /* 保留字段 */ + acl_int64 reserv3; /* 保留字段 */ + acl_int64 reserv4; /* 保留字段 */ +}; + +/* 块数据的头结构类型 */ +typedef struct ZDB_BLK_HDR { + zdb_key_t key; /* 对应于键存储中的键 */ + + /* 标识本数据块的索引位置, 校验用, 同时保证了 8 字节对齐 */ + zdb_lnk_t blk_ilnk; + + /* 由 inext_idle 将空闲数据块连接成一个单向链表, 若此值为 -1 则表示 + * 非空闲块, 后一个空闲块位置, 后一个空闲块的真实具体位置的计算公式为: + * zdb_off_t off_next = ZDB_BLK_HDR.sizeof + + * ZDB_BLK_HDR.inext_idle * (ZDB_BLK_HDR.blk_hdr_dlen + + * ZDB_DAT_HDR.blk_dlen * ZDB_DAT_HDR.blk_count); + */ + zdb_lnk_t inext_idle; + +#ifdef ZDB_LINK_BUSY + /* 由 inext_busy/iprev_busy 将占用数据块连接成一个双向链表, 若此值为 -1 + * 则表示非占用块, 后一个占用块位置, 后一个占用块的真实具体位置的计算公式为: + * zdb_off_t off_next = ZDB_BLK_HDR.sizeof + + * ZDB_BLK_HDR.inext_busy * (ZDB_BLK_HDR.blk_hdr_dlen + + * ZDB_DAT_HDR.blk_dlen * ZDB_DAT_HDR.blk_count); + * zdb_off_t off_prev = ZDB_BLK_HDR.sizeof + + * ZDB_BLK_HDR.inext_prev * (ZDB_BLK_HDR.blk_hdr_dlen + + * ZDB_DAT_HDR.blk_dlen * ZDB_DAT_HDR.blk_count); + */ + zdb_lnk_t inext_busy; + zdb_lnk_t iprev_busy; +#endif +} ZDB_BLK_HDR; + +/* 键存储中存储的值存储的偏移量类型 */ +struct ZDB_BLK_OFF { + zdb_off_t offset; /* 偏移量信息 */ + int inode; /* 路径信息 */ +}; + +/* 块数据结构类型 */ +struct ZDB_BLK { + ZDB_BLK_HDR hdr; + char dat[1]; /* 值存储中每块数据的体数据 */ +}; + +#ifdef ACL_SUNOS5 +#pragma pack(0) /* 以下取消4字节对齐限制 */ +#else +#pragma pack(pop) /* 以下取消4字节对齐限制 */ +#endif + +/* 通用存储句柄结构 */ +typedef struct ZDB_STORE { + ACL_FHANDLE fhandle; /* 文件句柄 */ + ZDB *db; /* 引用对象 */ + ZDB_IO *io; /* IO 句柄对象 */ + int cache_max; /* 启用存储 IO 缓存时的最大缓存数据块个数 */ + int cache_timeout; /* 启用存储 IO 缓存时每个缓存块的过期时间 */ + int wback_max; /* 写缓存中数据块的限制 */ + + unsigned int flag; /* 标志位 */ +#define STORE_FLAG_KEY (1 << 0) /* 表示是键存储 */ +#define STORE_FLAG_DAT (1 << 1) /* 表示是值存储 */ +#define STORE_FLAG_IO_SLICE (1 << 2) /* 是否启用 ZDB_IO 的内存切片分配方式 */ + + /* for acl_iterator */ + + /* 取迭代器头函数 */ + const void *(*iter_head)(ACL_ITER*, struct ZDB_STORE*); + /* 取迭代器下一个函数 */ + const void *(*iter_next)(ACL_ITER*, struct ZDB_STORE*); +} ZDB_STORE; + +/* 键存储 */ +struct ZDB_KEY_STORE { + ZDB_STORE store; + ZDB_KEY_HDR hdr; /* 键存储头 */ +}; + + +/* 值存储 */ +struct ZDB_DAT_STORE { + ZDB_STORE store; + ZDB_DAT_HDR hdr; /* 值存储头 */ +}; + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------- in zdb_test.c ----------------------------------*/ + +/** + * zdb 测试函数 + */ +ACL_API void zdb_test(const char *cmd); + +/*---------------------------- in zdb.c ----------------------------------*/ + +/* in zdb.c */ + +/** + * 程序开始运行时需要初始化 zdb + */ +ACL_API void zdb_init(void); + +/** + * 程序退出前需要释放 zdb 内部一些资源 + */ +ACL_API void zdb_end(void); + +/** + * 更新ZDB相关信息至磁盘 + * @param db {ZDB*} + */ +ACL_API void zdb_sync(ZDB *db); + +/** + * 打开或创建一个 ZDB 数据库 + * @param dbname {const char*} ZDB 数据库名称 + * @param oflags {unsigned int} 打开 ZDB 库时的标志位 + * @param cfg {const ZDB_CFG*} 打开 ZDB 时的配置对象 + * @return {ZDB*} ZDB 数据库句柄 + */ +ACL_API ZDB *zdb_open(const char *dbname, unsigned int oflags, const ZDB_CFG *cfg); + +/** + * 关闭 ZDB 数据库句柄 + * @param db {ZDB*} ZDB 数据库句柄 + */ +ACL_API void zdb_close(ZDB *db); + +/** + * 在 ZDB 数据库中查找相应键值的数据 + * @param db {ZDB*} ZDB 数据库句柄 + * @param key {zdb_key_t} 键值 + * @param size {size_t*} 若此指针非空且查询结果也非空则存储查询结果的数据长度, + * 即是 ZDB_BLK.dat 中存储数据的长度 + * @param blk_off_buf {ZDB_BLK_OFF*} 若非空则存储所查值的偏移位置索引号 + * @return {ZDB_BLK*} NULL: 未找到; !NULL: ZDB_BLK->dat 为用户数据的地址, + * 其中 ZDB_BLK 对象可以用 acl_myfree()/1 进行释放 + * 注意: + * 当 size 指针地址非空时,调用者的类型必须是 size_t 类型而非 int 类型,因为在 + * 64位机上 size_t 为8个字节长度,而 int 为4个字节长度,内部在对 size 地址赋值 + * 时,编译器会自动按 size_t 的真实空间长度赋值,如果调用者的 size 为 int 类型, + * 则就会出现空间越办现象,从而会使整个程序出现莫名其妙的问题,并且用 valgrind + * 也查不出这个错误来! + */ +ACL_API ZDB_BLK *zdb_lookup(ZDB *db, zdb_key_t key, size_t *size, ZDB_BLK_OFF *blk_off_buf); + +/** + * 从 ZDB_BLK 中取得用户数据 + * @param b {ZDB_BLK*} + * @return {void*} + */ +#define zdb_blk_data(b) ((b)->dat) + +/** + * 释放由 zdb_lookup()/3 返回的数据空间 + * @param b {ZDB_BLK*} + */ +#define zdb_blk_free(b) acl_myfree((b)) + +/** + * 添加或更新 ZDB 数据库中的数据 + * @param db {ZDB*} ZDB 数据库句柄 + * @param key {zdb_key_t} 键值 + * @param blk_off_saved {const ZDB_BLK_OFF*} 上次调用 zdb_lookup()/4 时的返回结果, + * 从而通过重复利用查询结果来提高效率, 如果在调用 zdb_lookup()/4 时返回结果为空, + * 则调用 zdb_update()/5 时必须将此值置 NULL + * @param dat {const void*} 键 key 所对应的数据地址 + * @param len {size_t} dat 数据长度 + * @return {int} 0: 未更新或添加; -1: 出错; 1: 成功 + */ +ACL_API int zdb_update(ZDB *db, zdb_key_t key, const ZDB_BLK_OFF *blk_off_saved, + const void *dat, size_t len); + +/*--------------------------------- in zdb_key.c -----------------------------*/ + +/** + * 同步键存储头至磁盘 + * @param store {ZDB_KEY_STORE*} 值存储句柄 + * @return {int} -1: error, > 0 ok + */ +ACL_API int key_store_header_sync(ZDB_KEY_STORE *store); + +/** + * 根据键值打开键存储 + * @param db {ZDB*} + * @param key {zdb_key_t} 键值 + * @return {ZDB_KEY_STORE*} !NULL: ok; NULL: error + */ +ACL_API ZDB_KEY_STORE *zdb_key_store_open(ZDB *db, zdb_key_t key); + +/** + * 根据文件名打开键存储 + * @param db {ZDB*} + * @param filepath {const char*} 文件名 + * @return {ZDB_KEY_STORE*} !NULL: ok; NULL: error + */ +ACL_API ZDB_KEY_STORE *zdb_key_store_open2(ZDB *db, const char *filepath); + +/** + * 关闭键存储 + * @param store {ZDB_KEY_STORE*} 键存储句柄 + */ +ACL_API void zdb_key_store_close(ZDB_KEY_STORE *store); + +/** + * 设置键存储中键位置的值位置值 + * @param db {ZDB*} + * @param key {zdb_key_t} + * @param blk_off {const ZDB_BLK_OFF*} + * @return {int} 0: ok; -1: error + */ +ACL_API int zdb_key_set(ZDB *db, zdb_key_t key, const ZDB_BLK_OFF *blk_off); + +/** + * 根据键值从键存储中取得该键所对应的数据索引位置 + * @param db {ZDB*} + * @param key {zdb_key_t} 键值 + * @param blk_off {ZDB_BLK_OFF*} 存储结果的对象 + * @return {int} 1: 表示查到, 0: 表示未查到, -1: 表示出错 + */ +ACL_API int zdb_key_get(ZDB *db, zdb_key_t key, ZDB_BLK_OFF *blk_off); + +/** + * 查询键存储头的状态 + * @param db {ZDB*} + * @param filepath {const char*} 键存储文件全路径 + * @param key_hdr {ZDB_KEY_HDR*} 用来存放键存储头信息的内存地址 + * @return {int} 0: ok; -1: error + */ +ACL_API int zdb_key_status(ZDB *db, const char *filepath, ZDB_KEY_HDR *key_hdr); + +/** + * 遍历键存储中的键的状态 + * @param db {ZDB*} + * @param filepath {const char*} 键存储文件全路径 + * @param key_hdr {ZDB_KEY_HDR*} 若非空则用来存放键存储头信息的内存地址 + * @return {int} 0: ok; -1: error + */ +ACL_API int zdb_key_check3(ZDB *db, const char *filepath, ZDB_KEY_HDR *key_hdr); +ACL_API int zdb_key_check(ZDB_KEY_STORE *store, ZDB_KEY_HDR *key_hdr); + +/** + * 初始化键存储 + * @param db {ZDB*} + * @param key_begin {zdb_key_t} 起始键值 + * @param key_end {zdb_key_t} 结束键值 + * @return {int} 0: ok; -1: error + */ +ACL_API int zdb_key_init(ZDB *db, zdb_key_t key_begin, zdb_key_t key_end); +/*--------------------------------- in zdb_dat.c -----------------------------*/ + +/** + * 同步值存储头至磁盘 + * @param store {ZDB_DAT_STORE*} 值存储句柄 + * @return {int} -1: error, > 0 ok + */ +ACL_API int dat_store_header_sync(ZDB_DAT_STORE *store); + +/** + * 关闭值存储 + * @param store {ZDB_DAT_STORE*} 值存储句柄 + */ +ACL_API void zdb_dat_store_close(ZDB_DAT_STORE *store); + +/** + * 打开或创建值存储 + * @param filepath {const char*} 值存储文件全路径 + * @return {ZDB_DAT_STORE*} !NULL: ok; NULL: error + */ +ACL_API ZDB_DAT_STORE *zdb_dat_store_open(ZDB *db, const char *filepath); + +/** + * 从值存储中取得对应的数据 + * @param db {ZDB*} + * @param blk_off {const ZDB_BLK_OFF*} + * @param key {zdb_key_t*} 存储键的值 + * @param size {size_t*} 存储数据的长度 + * @return {void*} 数据地址,若找到则不为空,找不到或出错则为空, 若不为空, + * 则需要用 zdb_blk_free()/1 进行释放 + * 注意: + * 当 size 指针地址非空时,调用者的类型必须是 size_t 类型而非 int 类型,因为在 + * 64位机上 size_t 为8个字节长度,而 int 为4个字节长度,内部在对 size 地址赋值 + * 时,编译器会自动按 size_t 的真实空间长度赋值,如果调用者的 size 为 int 类型, + * 则就会出现空间越办现象,从而会使整个程序出现莫名其妙的问题,并且用 valgrind + * 也查不出这个错误来! + */ +ACL_API ZDB_BLK *zdb_dat_get(ZDB *db, const ZDB_BLK_OFF *blk_off, + zdb_key_t *key, size_t *size); + +/** + * 向值存储中添加新数据 + * @param db {ZDB*} + * @param key {zdb_key_t} 键值 + * @param dat {const void*} 数据地址 + * @param len {size_t} dat 数据长度 + * @return {int} 0: 数据没有更新; 1: 数据更新; -1: 出错 + */ +ACL_API int zdb_dat_add(ZDB *db, zdb_key_t key, const void *dat, int len); + +/** + * 更新值存储中的数据信息 + * @param db {ZDB*} + * @param key {zdb_key_t} 键 + * @param blk_off {const ZDB_BLK_OFF*} 存储于键存储中相应值的位置信息 + * @param dat {const void*} 数据地址 + * @param len {size_t} dat 数据长度 + * @return {int} 0: 数据没有更新; 1: 数据更新; -1: 出错 + */ +ACL_API int zdb_dat_update(ZDB *db, zdb_key_t key, const ZDB_BLK_OFF *blk_off, + const void *dat, size_t len); + +/** + * 读取值存储的头信息 + * @param db {ZDB*} + * @param filepath {const char*} 值存储文件名 + * @param dat_hdr {ZDB_DAT_HDR*} 存储结果 + * @retur {int} 0: ok; -1: error + */ +ACL_API int zdb_dat_stat(ZDB *db, const char *filepath, ZDB_DAT_HDR *dat_hdr); + +/** + * 检查值存储中的数据块的正确性 + * @param db {ZDB*} + * @param filepath {const char*} 值存储文件名 + * @param dat_hdr {ZDB_DAT_HDR*} 若非空则存储值存储头信息 + * @return {int} 0: ok; -1: error + */ +ACL_API int zdb_dat_check3(ZDB *db, const char *filepath, ZDB_DAT_HDR *dat_hdr); +ACL_API int zdb_dat_check(ZDB_DAT_STORE *store, ZDB_DAT_HDR *dat_hdr); + +/*-------------------- in zdb_key_walk.c -----------------------------------*/ +ACL_API int zdb_key_walk(ZDB *db, int (*walk_fn)(ZDB_KEY_STORE *store)); + +/*-------------------- in zdb_dat_walk.c -----------------------------------*/ +ACL_API int zdb_dat_walk(ZDB *db, int (*walk_fn)(ZDB_DAT_STORE *store)); + +/*-------------------- in zdb_key_iter.c -----------------------------------*/ + +/*-------------------- in zdb_dat_iter.c -----------------------------------*/ +/** + * 设置值存储的迭代器 + * @param store {ZDB_DAT_STORE*} + * @param read_data {int} 是否需要读取数据块中的数据部分, !0: 表示读取数据块中的 + * 数据部分; 0: 仅读取数据块中的头 + */ +ACL_API void zdb_dat_iter_set(ZDB_DAT_STORE *store, int read_data); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/include/event/acl_events.h b/lib_acl/include/event/acl_events.h new file mode 100644 index 000000000..84f791f75 --- /dev/null +++ b/lib_acl/include/event/acl_events.h @@ -0,0 +1,358 @@ +#ifndef __ACL_EVENTS_H_INCLUDED__ +#define __ACL_EVENTS_H_INCLUDED__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_define.h" +#include +#include "stdlib/acl_vstream.h" +#include "acl_timer.h" + +/*+++++++++++++++++++++++++++ 全局宏定义 +++++++++++++++++++++++++++++++++++*/ + /* Event codes. */ +#define ACL_EVENT_READ (1<<0) /**< read event */ +#define ACL_EVENT_WRITE (1<<1) /**< write event */ +#define ACL_EVENT_CONNECT ACL_EVENT_WRITE /**< client has connected the server*/ +#define ACL_EVENT_XCPT (1<<2) /**< exception */ +#define ACL_EVENT_TIME (1<<3) /**< timer event */ +#define ACL_EVENT_RW_TIMEOUT (1<<4) /**< read/write timeout event */ + +#define ACL_EVENT_TIMEOUT ACL_EVENT_RW_TIMEOUT +#define ACL_EVENT_ACCEPT ACL_EVENT_READ +#define ACL_EVENT_CLIENT (ACL_EVENT_ACCEPT) + +#define ACL_EVENT_FD_IDLE 0 +#define ACL_EVENT_FD_BUSY 1 + +#define ACL_EVENT_ERROR ACL_EVENT_XCPT + +#define ACL_EVENT_SELECT 0 +#define ACL_EVENT_POLL 1 +#define ACL_EVENT_KERNEL 2 +#define ACL_EVENT_KERNEL2 3 +#define ACL_EVENT_KERNEL3 4 +#define ACL_EVENT_WMSG 5 + + /* + * Dummies. + */ +#define ACL_EVENT_NULL_TYPE 0 +#define ACL_EVENT_NULL_CONTEXT ((char *) 0) + + +/* in acl_events.c */ +/* + * Timer events. Timer requests are kept sorted, in a circular list. We use + * the RING abstraction, so we get to use a couple ugly macros. + */ +typedef struct ACL_EVENT_TIMER ACL_EVENT_TIMER; + + /* + * External interface. + */ +typedef void (*ACL_EVENT_NOTIFY_FN) (int event_type, void *context); +typedef ACL_EVENT_NOTIFY_FN ACL_EVENT_NOTIFY_RDWR; +typedef ACL_EVENT_NOTIFY_FN ACL_EVENT_NOTIFY_TIME; + +typedef struct ACL_EVENT ACL_EVENT; +typedef struct ACL_EVENT_FDTABLE ACL_EVENT_FDTABLE; + +/*----------------------------------------------------------------------------*/ + +/** + * 创建一个事件循环对象的总入口,此函数会根据用户参数的不同自动调用下面的事件对象创建函数 + * @param event_mode {int} 事件处理方式,目前仅支持: ACL_EVENT_SELECT, ACL_EVENT_KERNEL, + * ACL_EVENT_POLL, ACL_EVENT_WMSG + * @param use_thr {int} 是否采用线程事件方式,非0表示按线程事件方式 + * @param delay_sec {int} 事件循环等待时的最长秒数,当 event_mode 为 ACL_EVENT_WMSG + * 时,且该值大于 0 时,则该值被当作消息值对待传给 acl_event_new_wmsg,用来与异 + * 步消息句柄绑定 + * @param delay_usec {int} 事件循环等待时的最长微秒数(仅 select 方式有用) + * @return {ACL_EVENT*} 事件对象指针,如果为空表示出错 + */ +ACL_API ACL_EVENT *acl_event_new(int event_mode, int use_thr, + int delay_sec, int delay_usec); + +/** + * 创建一个新的事件对象, 该事件不支持多线程 + * @param delay_sec {int} 在调用 select() 函数时休息的秒数 + * @param delay_usec {int} 在调用 select() 函数时休息的微秒数 + * @return {ACL_EVENT*} 事件对象指针,如果为空表示出错 + */ +ACL_API ACL_EVENT *acl_event_new_select(int delay_sec, int delay_usec); + +/** + * 创建一个新的事件对象, 该事件支持线程模式 + * @param delay_sec {int} 在调用 select() 函数时休息的秒数 + * @param delay_usec {int} 在调用 select() 函数时休息的微秒数 + * @return {ACL_EVENT*} 事件对象指针,如果为空表示出错 + */ +ACL_API ACL_EVENT *acl_event_new_select_thr(int delay_sec, int delay_usec); + +/** + * 创建一个支持 poll 的事件对象,不支持多线程 + * @param delay_sec {int} 在调用 poll() 函数时休息的秒数 + * @param delay_usec {int} 在调用 poll() 函数时休息的微秒数 + * @return {ACL_EVENT*} 事件对象指针,如果为空表示出错 + */ +ACL_API ACL_EVENT *acl_event_new_poll(int delay_sec, int delay_usec); + +/** + * 创建一个支持 poll 的事件对象,支持多线程 + * @param delay_sec {int} 在调用 poll() 函数时休息的秒数 + * @param delay_usec {int} 在调用 poll() 函数时休息的微秒数 + * @return {ACL_EVENT*} 事件对象指针,如果为空表示出错 + */ +ACL_API ACL_EVENT *acl_event_new_poll_thr(int delay_sec, int delay_usec); + +/** + * 创建一个新的事件对象, 该事件采用效率高的 epoll/devpoll/kqueue 方式,且不支持多线程 + * @param delay_sec {int} 在调用事件循环函数时休息的秒数 + * @param delay_usec {int} 在调用事件循环函数时休息的微秒数(忽略不计) + * @return {ACL_EVENT*} 事件对象指针,如果为空表示出错 + */ +ACL_API ACL_EVENT *acl_event_new_kernel(int delay_sec, int delay_usec); + +/** + * 创建一个新的事件对象, 该事件采用效率高的 epoll/devpoll/kqueue 方式,且不支持多线程 + * @param delay_sec {int} 在调用事件循环函数时休息的秒数 + * @param delay_usec {int} 在调用事件循环函数时休息的微秒数(忽略不计) + * @return {ACL_EVENT*} 事件对象指针,如果为空表示出错 + */ +ACL_API ACL_EVENT *acl_event_new_kernel2(int delay_sec, int delay_usec); + +/** + * 创建一个新的事件对象, 该事件采用效率高的 epoll/devpoll/kqueue 方式,且不支持多线程 + * @param delay_sec {int} 在调用事件循环函数时休息的秒数 + * @param delay_usec {int} 在调用事件循环函数时休息的微秒数(忽略不计) + * @return {ACL_EVENT*} 事件对象指针,如果为空表示出错 + */ +ACL_API ACL_EVENT *acl_event_new_kernel3(int delay_sec, int delay_usec); + +/** + * 创建一个新的事件对象, 该事件采用效率高的 epoll/devpoll/kqueue 方式,且采用线程方式 + * @param delay_sec {int} 在调用事件循环函数时休息的秒数 + * @param delay_usec {int} 在调用事件循环函数时休息的微秒数(忽略不计) + * @return {ACL_EVENT*} 事件对象指针,如果为空表示出错 + */ +ACL_API ACL_EVENT *acl_event_new_kernel_thr(int delay_sec, int delay_usec); + +/** + * 创建一个能与 Windows 界面消息绑在一起的事件引擎对象 + * @param nMsg {unsigned int} 如果该值大于 0 则将该异步句柄与该消息值绑定, + * 否则将该异步句柄与缺省的消息值绑定 + * @return {ACL_EVENT*} 事件对象指针,如果为空表示出错 + */ +ACL_API ACL_EVENT *acl_event_new_wmsg(unsigned int nMsg); + +#ifdef ACL_MS_WINDOWS +ACL_API HWND acl_event_wmsg_hwnd(ACL_EVENT *eventp); +#endif + +/** + * 为了防止在多线程模式下 select 等事件循环的时间等待,可以添加此项以中断等待, + * 加快事件循环过程 + * @param eventp {ACL_EVENT*} 事件对象指针, 不为能为空 + */ +ACL_API void acl_event_add_dog(ACL_EVENT *eventp); + +/** + * 释放事件结构 + * @param eventp {ACL_EVENT*} 事件对象指针, 不为能为空 + */ +ACL_API void acl_event_free(ACL_EVENT *eventp); + +/** + * 返回事件的时间截 + * @param eventp {ACL_EVENT*} 事件对象指针, 不为能为空 + * @return {acl_int64} 当前事件的时间截(微秒级别) + */ +ACL_API acl_int64 acl_event_time(ACL_EVENT *eventp); + +/** + * 将事件中的所有任务执行完毕 + * @param eventp {ACL_EVENT*} 事件对象指针, 不为能为空 + */ +ACL_API void acl_event_drain(ACL_EVENT *eventp); + +/** + * 设置数据流可读时(指有数据待读或描述符出错或描述符关闭)的回调函数 + * @param eventp {ACL_EVENT*} 事件对象指针, 不为能为空 + * @param stream {ACL_VSTREAM*} 数据流指针, 不能为空, 且其中的描述符必须是有效的 + * @param read_timeout {int} 读超时时间(秒) + * @param callback {ACL_EVENT_NOTIFY_RDWR} 数据流可读时的回调函数 + * @param context {void*} 回调函数 callback 所需要的参数 + */ +ACL_API void acl_event_enable_read(ACL_EVENT *eventp, + ACL_VSTREAM *stream, + int read_timeout, + ACL_EVENT_NOTIFY_RDWR callback, + void *context); + +/** + * 设置数据流可写时(指有空间可以写或描述符出错或描述符关闭)的回调函数 + * @param eventp {ACL_EVENT*} 事件对象指针, 不为能为空 + * @param stream {ACL_VSTREAM*} 数据流指针, 不能为空, 且其中的描述符必须是有效的 + * @param write_timeout {int} 写超时时间(秒) + * @param callback {ACL_EVENT_NOTIFY_RDWR} 数据流可写时的回调函数 + * @param context {void*} 回调函数 callback 所需要的参数 + */ +ACL_API void acl_event_enable_write(ACL_EVENT *eventp, + ACL_VSTREAM *stream, + int write_timeout, + ACL_EVENT_NOTIFY_RDWR callback, + void *context); + +/** + * 设置监听套接口(指有新连接到达/被系统中断/出错时)的回调函数 + * @param eventp {ACL_EVENT*} 事件对象指针, 不为能为空 + * @param stream {ACL_VSTREAM*} 数据流指针, 不能为空, 且其中的描述符必须是有效的 + * @param read_timeout {int} 监听超时时间(秒),可以为0 + * @param callback {ACL_EVENT_NOTIFY_RDWR} 数据流可读时的回调函数 + * @param context {void*} 回调函数 callback 所需要的参数 + */ +ACL_API void acl_event_enable_listen(ACL_EVENT *eventp, + ACL_VSTREAM *stream, + int read_timeout, + ACL_EVENT_NOTIFY_RDWR callback, + void *context); + +/** + * 将数据流从事件的读监听流集合中清除 + * @param eventp {ACL_EVENT*} 事件对象指针, 不为能为空 + * @param stream {ACL_VSTREAM*} 数据流指针, 不能为空, 且其中的描述符必须是有效的 + */ +ACL_API void acl_event_disable_read(ACL_EVENT *eventp, ACL_VSTREAM *stream); + +/** + * 将数据流从事件的写监听流集合中清除 + * @param eventp {ACL_EVENT*} 事件对象指针, 不为能为空 + * @param stream {ACL_VSTREAM*} 数据流指针, 不能为空, 且其中的描述符必须是有效的 + */ +ACL_API void acl_event_disable_write(ACL_EVENT *eventp, ACL_VSTREAM *stream); + +/** + * 将数据流从事件的读写监听流集合中清除 + * @param eventp {ACL_EVENT*} 事件对象指针, 不为能为空 + * @param stream {ACL_VSTREAM*} 数据流指针, 不能为空, 且其中的描述符必须是有效的 + */ +ACL_API void acl_event_disable_readwrite(ACL_EVENT *eventp, ACL_VSTREAM *stream); + +/** + * 检查流中的描述符是否已经置入读、写或异常事件的集合中 + * @param eventp {ACL_EVENT*} 事件对象指针, 不为能为空 + * @param stream {ACL_VSTREAM*} 数据流指针, 不能为空, 且其中的描述符必须是有效的 + */ +ACL_API int acl_event_isset(ACL_EVENT *eventp, ACL_VSTREAM *stream); + +/** + * 检查流中的描述符是否已经置入读事件的集合中 + * @param eventp {ACL_EVENT*} 事件对象指针, 不为能为空 + * @param stream {ACL_VSTREAM*} 数据流指针, 不能为空, 且其中的描述符必须是有效的 + */ +ACL_API int acl_event_isrset(ACL_EVENT *eventp, ACL_VSTREAM *stream); + +/** + * 检查流中的描述符是否已经置入写事件的集合中 + * @param eventp {ACL_EVENT*} 事件对象指针, 不为能为空 + * @param stream {ACL_VSTREAM*} 数据流指针, 不能为空, 且其中的描述符必须是有效的 + */ +ACL_API int acl_event_iswset(ACL_EVENT *eventp, ACL_VSTREAM *stream); + +/** + * 检查流中的描述符是否已经置入异常事件的集合中 + * @param eventp {ACL_EVENT*} 事件对象指针, 不为能为空 + * @param stream {ACL_VSTREAM*} 数据流指针, 不能为空, 且其中的描述符必须是有效的 + */ +ACL_API int acl_event_isxset(ACL_EVENT *eventp, ACL_VSTREAM *stream); + +/** + * 添加一个定时事件 + * @param eventp {ACL_EVENT*} 事件对象指针, 不为能为空 + * @param callback {ACL_EVENT_NOTIFY_TIME} 定时事件的回调函数 + * @param context {void*} callback 所需要的回调参数 + * @param delay {acl_int64} eventp->event_present + delay 为该事件函数开始执行的时间 + * 单位为微秒 + * @param keep {int} 是否重复定时器任务 + * @return {acl_int64} 事件执行的时间截,单位为微秒 + */ +ACL_API acl_int64 acl_event_request_timer(ACL_EVENT *eventp, + ACL_EVENT_NOTIFY_TIME callback, + void *context, + acl_int64 delay, + int keep); + +/** + * 取消一个定时事件 + * @param eventp {ACL_EVENT*} 事件对象指针, 不为能为空 + * @param callback {ACL_EVENT_NOTIFY_TIME} 定时事件的回调函数 + * @param context {void*} callback 所需要的回调参数 + * @return acl_int64 {acl_int64} 距离开始执行事件函数的时间间隔, 以微秒为单位 + */ +ACL_API acl_int64 acl_event_cancel_timer(ACL_EVENT *eventp, + ACL_EVENT_NOTIFY_TIME callback, + void *context); + +/** + * 当定时器处理完毕后,是否需要再次设置该定时器,以方便调用者循环 + * 使用该定时器 + * @param eventp {ACL_EVENT*} 事件对象指针, 不为能为空 + * @param callback {ACL_EVENT_NOTIFY_TIME} 非空 + * @param context {void*} 附属于 callback 的变量 + * @param onoff {int} 是否重复通过 acl_event_request_timer 设置的定时器 + */ +ACL_API void acl_event_keep_timer(ACL_EVENT *eventp, ACL_EVENT_NOTIFY_TIME callback, + void *context, int onoff); + +/** + * 判断所设置的定时器都处于重复使用状态 + * @param eventp {ACL_EVENT*} 事件对象指针, 不为能为空 + * @param callback {ACL_EVENT_NOTIFY_TIME} 非空 + * @param context {void*} 附属于 callback 的变量 + * @return {int} !0 表示所设置的定时器都处于重复使用状态 + */ +ACL_API int acl_event_timer_ifkeep(ACL_EVENT *eventp, ACL_EVENT_NOTIFY_TIME callback, + void *context); + +/** + * 事件循环执行的调度函数 + * @param eventp {ACL_EVENT*} 事件对象指针, 不为能为空 + */ +ACL_API void acl_event_loop(ACL_EVENT *eventp); + +/** + * 设置事件循环的空闲休息时间中的秒级数值 + * @param eventp {ACL_EVENT*} 事件对象指针, 不为能为空 + * @param sec {int} 秒级空闲休息时间值 + */ +ACL_API void acl_event_set_delay_sec(ACL_EVENT *eventp, int sec); + +/** + * 设置事件循环的空闲休息时间中的微秒级数值 + * @param eventp {ACL_EVENT*} 事件对象指针, 不为能为空 + * @param usec {int} 微秒级空闲休息时间值 + */ +ACL_API void acl_event_set_delay_usec(ACL_EVENT *eventp, int usec); + +/** + * 是否采用线程事件方式 + * @param eventp {ACL_EVENT*} 事件对象指针, 不为能为空 + * @return {int} 0: 否; !=0: 是 + */ +ACL_API int acl_event_use_thread(ACL_EVENT *eventp); + +/** + * 获得当前事件引擎的事件模型 + * @param eventp {ACL_EVENT*} 事件对象指针, 不为能为空 + * @return {int} ACL_EVENT_SELECT/ACL_EVENT_KERNEL/ACL_EVENT_POLL + */ +ACL_API int acl_event_mode(ACL_EVENT *eventp); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/include/event/acl_timer.h b/lib_acl/include/event/acl_timer.h new file mode 100644 index 000000000..a1b503e9c --- /dev/null +++ b/lib_acl/include/event/acl_timer.h @@ -0,0 +1,115 @@ +#ifndef __ACL_TIMER_INCLUDE_H__ +#define __ACL_TIMER_INCLUDE_H__ + +#include "stdlib/acl_define.h" +#include +#include "stdlib/acl_iterator.h" +#include "stdlib/acl_ring.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * 定时器类型定义 + */ +typedef struct ACL_TIMER_INFO { + /* public */ + void *obj; /**< 用户的数据对象指针 */ + acl_int64 when; /**< 被触发的时间截(微妙级) */ + + /* private */ + ACL_RING entry; /**< 内部用的定时链 */ +} ACL_TIMER_INFO; + +/* 定时器句柄结构 */ +typedef struct ACL_TIMER ACL_TIMER; + +struct ACL_TIMER { + acl_int64 (*request)(ACL_TIMER *timer, void *obj, acl_int64 delay); + acl_int64 (*cancel)(ACL_TIMER *timer, void *obj); + void* (*popup)(ACL_TIMER* timer); + + ACL_RING timer_header; + acl_int64 present; + acl_int64 time_left; + + /* for acl_iterator */ + + /* 取迭代器头函数 */ + const void *(*iter_head)(ACL_ITER*, struct ACL_TIMER*); + /* 取迭代器下一个函数 */ + const void *(*iter_next)(ACL_ITER*, struct ACL_TIMER*); + /* 取迭代器尾函数 */ + const void *(*iter_tail)(ACL_ITER*, struct ACL_TIMER*); + /* 取迭代器上一个函数 */ + const void *(*iter_prev)(ACL_ITER*, struct ACL_TIMER*); + + /* 获得与当前迭代指针相关联的 ACL_TIMER_INFO 对象 */ + const ACL_TIMER_INFO *(*iter_info)(ACL_ITER*, struct ACL_TIMER*); +}; + +/** + * 添加定时任务 + * @param timer {ACL_TIMER*},定时器句柄 + * @param obj {void*},用户级动态变量 + * @param delay {acl_int64},被触发的时间间隔(微秒级) + * @return {acl_int64} 新的定时任务的解决时间截(微秒级) + */ +ACL_API acl_int64 acl_timer_request(ACL_TIMER* timer, void *obj, acl_int64 delay); + +/** + * 取消定时任务 + * @param timer {ACL_TIMER*},定时器句柄 + * @param obj {void*},用户级动态变量 + * @return {acl_int64},距离下一个定时任务被触发的时间间隔(微秒级) + */ +ACL_API acl_int64 acl_timer_cancel(ACL_TIMER* timer, void *obj); + +/** + * 从定时器中获取到时的定时任务 + * @param timer {ACL_TIMER*},定时器句柄 + * @return {void*},用户级动态变量 + */ +ACL_API void *acl_timer_popup(ACL_TIMER* timer); + +/** + * 距离下一个定时任务被触发的时间间隔 + * @param timer {ACL_TIMER*},定时器句柄 + * @return {acl_int64} 返回值单位为微秒 + */ +ACL_API acl_int64 acl_timer_left(ACL_TIMER* timer); + +/** + * 遍历定时器里的所有定时任务项 + * @param timer {ACL_TIMER*},定时器句柄 + * @param action {void (*)(ACL_TIMER_INFO*, void*)} 用户的遍历回调函数 + * @param arg {void*} action 中的第二个参数 + */ +ACL_API void acl_timer_walk(ACL_TIMER *timer, void (*action)(ACL_TIMER_INFO *, void *), void *arg); + +/** + * 创建定时器句柄 + * @return {ACL_TIMER*} + */ +ACL_API ACL_TIMER *acl_timer_new(void); + +/** + * 释放定时器句柄 + * @param timer {ACL_TIMER*} + * @param free_fn {void (*)(void*)} 释放定时器里的用户对象的回调释放函数 + */ +ACL_API void acl_timer_free(ACL_TIMER* timer, void (*free_fn)(void*)); + +/** + * 获得定时器里定时任务的数量 + * @param timer {ACL_TIMER*} + * @return {int} >= 0 + */ +ACL_API int acl_timer_size(ACL_TIMER *timer); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/include/experiment/experiment.h b/lib_acl/include/experiment/experiment.h new file mode 100644 index 000000000..cec015ea5 --- /dev/null +++ b/lib_acl/include/experiment/experiment.h @@ -0,0 +1,14 @@ +#ifndef __EXPERIMENT_INCLUDE_H__ +#define __EXPERIMENT_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#define EXPERIMENT 1 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/include/init/acl_init.h b/lib_acl/include/init/acl_init.h new file mode 100644 index 000000000..0abfb7788 --- /dev/null +++ b/lib_acl/include/init/acl_init.h @@ -0,0 +1,42 @@ +#ifndef __ACL_INIT_INCLUDE_H__ +#define __ACL_INIT_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_define.h" + +/** + * 初始化整个ACL库 + */ +ACL_API void acl_init(void); + +/** + * 结束整个ACL库 + */ +ACL_API void acl_end(void); + +/** + * 是否优先使用 poll 而非 select + * @param yesno {int} 非 0 时表示优先使用 poll + */ +ACL_API void acl_poll_prefered(int yesno); + +/** + * 获得当前 acl 库的版本信息 + * @return {const char*} 当前 acl 库版本信息 + */ +ACL_API const char *acl_version(void); + + +/** + * 获得主线程的线程号 + * @return {unsigned int} + */ +ACL_API unsigned long acl_main_thread_self(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/lib_acl/include/ioctl/acl_ioctl.h b/lib_acl/include/ioctl/acl_ioctl.h new file mode 100644 index 000000000..602f27d74 --- /dev/null +++ b/lib_acl/include/ioctl/acl_ioctl.h @@ -0,0 +1,313 @@ +#ifndef __ACL_IOCTL_INCLUDE_H__ +#define __ACL_IOCTL_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_define.h" +#include "event/acl_events.h" +#include "stdlib/acl_vstream.h" + +typedef struct ACL_IOCTL ACL_IOCTL; + +/** + * 当数据流可用时的任务回调函数类型定义, 用户需要根据此函数原型实现自己的任务 + * @param event_type {int} 数据流的事件状态, 为下列状态之一: + * ACL_EVENT_READ: 数据流有数据可读; + * ACL_EVENT_WRITE: 数据流有空间可写; + * ACL_EVENT_RW_TIMEOUT: 该数据流读写超时; + * ACL_EVENT_XCPT: 数据流内部出现异常. + * @param ioc {ACL_IOCTL*} io 控制句柄 + * @param stream {ACL_VSTREAM*} 网络流句柄 + * @param context {void*} 用户自定义对象 + */ +typedef void (*ACL_IOCTL_NOTIFY_FN)(int event_type, ACL_IOCTL *ioc, + ACL_VSTREAM *stream, void *context); + +/** + * 超时回调函数类型定义: void (*)(int event_type, void *context) + * @see ACL_EVENT_NOTIFY_TIME + */ +typedef ACL_EVENT_NOTIFY_TIME ACL_IOCTL_TIMER_FN; + +typedef void (*ACL_IOCTL_WORKER_FN)(ACL_IOCTL *ioc, void *arg); +typedef void (*ACL_IOCTL_THREAD_INIT_FN)(void *); +typedef void (*ACL_IOCTL_THREAD_EXIT_FN)(void *); + +/*----------------------------------------------------------------------------*/ +/* in acl_ioctl.c */ +/** + * 创建一个服务器框架 + * @param max_threads {int} 所创建的任务池内的最大线程数 + * @param idle_timeout {int} 每个线程空闲时间, 当某个纯种的空闲时间超过 + * 此值时会自动退出, 单位为秒 + * @return {ACL_IOCTL*} 服务器任务池句柄 + */ +ACL_API ACL_IOCTL *acl_ioctl_create(int max_threads, int idle_timeout); + +/** + * 创建一个服务器框架 + * @param event_mode {int} 事件方式: ACL_EVENT_SELECT/ACL_EVENT_KERNEL + * @param max_threads {int} 所创建的任务池内的最大线程数 + * @param idle_timeout {int} 每个线程空闲时间, 当某个纯种的空闲时间超过 + * 此值时会自动退出, 单位为秒 + * @param delay_sec {int} 在事件循环中的秒值 + * @param delay_usec {int} 在事件循环中的微秒值 + * @return {ACL_IOCTL*} 服务器任务池句柄 + */ +ACL_API ACL_IOCTL *acl_ioctl_create_ex(int event_mode, int max_threads, + int idle_timeout, int delay_sec, int delay_usec); + +/** + * 为了防止在多线程模式下 select 等事件循环的时间等待,可以添加此项以中断等待, + * 加快事件循环过程 + * @param ioc {ACL_IOCTL*} 服务器任务池句柄 + */ +ACL_API void acl_ioctl_add_dog(ACL_IOCTL *ioc); + +/** + * 设置服务器任务池的控制参数 + * @param ioc {ACL_IOCTL*} 服务器任务池句柄 + * @param name {int} 参数列表中的第一个参数, ACL_IOCTL_CTL_ + * @param ... 变参参数序列 + */ +ACL_API void acl_ioctl_ctl(ACL_IOCTL *ioc, int name, ...); +#define ACL_IOCTL_CTL_END 0 /**< 控制结束标志 */ +#define ACL_IOCTL_CTL_THREAD_MAX 1 /**< 设置最大线程数 */ +#define ACL_IOCTL_CTL_THREAD_IDLE 2 /**< 设置线程空闲退出时间 */ +#define ACL_IOCTL_CTL_DELAY_SEC 3 /**< 设置 select 时的秒级休息值 */ +#define ACL_IOCTL_CTL_DELAY_USEC 4 /**< 设置 select 时的微秒级休息值 */ +#define ACL_IOCTL_CTL_INIT_FN 5 /**< 设置线程被创建时的线程初始化函数 */ +#define ACL_IOCTL_CTL_EXIT_FN 6 /**< 设置线程退出时的线程退出回调函数 */ +#define ACL_IOCTL_CTL_INIT_CTX 7 /**< 设置线程初始化时的回调参数 */ +#define ACL_IOCTL_CTL_EXIT_CTX 8 /**< 设置线程退出时的回调参数 */ +#define ACL_IOCTL_CTL_THREAD_STACKSIZE 9 /**< 设置线程的规模尺寸大小(字节) */ + +/** + * 销毁任务池资源 + * @param ioc {ACL_IOCTL*} 服务器任务池句柄 + */ +ACL_API void acl_ioctl_free(ACL_IOCTL *ioc); + +/** + * 启动任务工作池 + * @param ioc {ACL_IOCTL*} 服务器任务池句柄 + * @return {int} 是否启动服务器任务池正常. 0: ok; < 0: err. + */ +ACL_API int acl_ioctl_start(ACL_IOCTL *ioc); + +/** + * 消息循环(仅适用于单线程模式) + * @param ioc {ACL_IOCTL*} 服务器任务池句柄 + */ +ACL_API void acl_ioctl_loop(ACL_IOCTL *ioc); + +/** + * 获得事件引擎句柄 + * @param ioc {ACL_IOCTL*} 服务器任务池句柄 + * @return {ACL_EVENT*} + */ +ACL_API ACL_EVENT *acl_ioctl_event(ACL_IOCTL *ioc); + +/** + * 将数据流从事件的读、写监听中去除 + * @param ioc {ACL_IOCTL*} 服务器任务池句柄 + * @param stream {ACL_VSTREAM*} 客户端数据流指针 + */ +ACL_API void acl_ioctl_disable_readwrite(ACL_IOCTL *ioc, ACL_VSTREAM *stream); + +/** + * 将数据流从事件的读监听中去除 + * @param ioc {ACL_IOCTL*} 服务器任务池句柄 + * @param stream {ACL_VSTREAM*} 客户端数据流指针 + */ +ACL_API void acl_ioctl_disable_read(ACL_IOCTL *ioctl, ACL_VSTREAM *stream); + +/** + * 将数据流从事件的写监听中去除 + * @param ioc {ACL_IOCTL*} 服务器任务池句柄 + * @param stream {ACL_VSTREAM*} 客户端数据流指针 + */ +ACL_API void acl_ioctl_disable_write(ACL_IOCTL *ioc, ACL_VSTREAM *stream); + +/** + * 判断某个流是否处于受监控状态, 只要读或写任何一种状态均返回真 + * @param ioc {ACL_IOCTL*} 服务器任务池句柄 + * @param stream {ACL_VSTREAM*} 客户端数据流指针 + * @return {int} 1:表示是; 0: 表示否 + */ +ACL_API int acl_ioctl_isset(ACL_IOCTL *ioc, ACL_VSTREAM *stream); + +/** + * 判断某个流是否处理于读监控状态 + * @param ioc {ACL_IOCTL*} 服务器任务池句柄 + * @param stream {ACL_VSTREAM*} 客户端数据流指针 + * @return {int} 1:表示是; 0: 表示否 + */ +ACL_API int acl_ioctl_isrset(ACL_IOCTL *ioc, ACL_VSTREAM *stream); + +/** + * 判断某个流是否处于写受监控状态 + * @param ioc {ACL_IOCTL*} 服务器任务池句柄 + * @param stream {ACL_VSTREAM*} 客户端数据流指针 + * @return {int} 1:表示是; 0: 表示否 + */ +ACL_API int acl_ioctl_iswset(ACL_IOCTL *ioc, ACL_VSTREAM *stream); + +/** + * 设置流状, 当流的IO完成时自动关闭流 + * @param ioc {ACL_IOCTL*} 服务器任务池句柄 + * @param stream {ACL_VSTREAM*} 客户端数据流指针 + * @return {int} 是否真正被关闭 + * 0: 表示流中还有数据未处理完, 将进入异步关闭过程; + * 1: 表示流中无未处理数据, 已经被同步关闭 + */ +ACL_API int acl_ioctl_iocp_close(ACL_IOCTL *ioc, ACL_VSTREAM *stream); + +/** + * 向任务池中添加一个读监听工作任务 + * @param ioc {ACL_IOCTL*} 服务器任务池句柄 + * @param stream {ACL_VSTREAM*} 客户端数据流指针 + * @param timeout {int} 流连接空闲超时时间 + * @param callback {ACL_IOCTL_NOTIFY_FN} 当数据流可读或出错或超时时的回调函数 + * @param context {void*} 回调函数 callback 的参数之一, 主要用于传递用户自己的参数, + * 用户需要在 callback 内将该参数转换成自己的可识别类型 + */ +ACL_API void acl_ioctl_enable_read(ACL_IOCTL *ioc, ACL_VSTREAM *stream, + int timeout, ACL_IOCTL_NOTIFY_FN callback, void *context); + +/** + * 向任务池中添加一个写监控工作任务 + * @param ioc {ACL_IOCTL*} 服务器任务池句柄 + * @param stream {ACL_VSTREAM*} 客户端数据流指针 + * @param timeout {int} 流连接空闲超时时间 + * @param callback {ACL_IOCTL_NOTIFY_FN} 当数据流可写或出错或超时时的回调函数 + * @param context {void*} 回调函数 callback 的参数之一, 主要用于传递用户自己的参数, + * 用户需要在 callback 内将该参数转换成自己的可识别类型 + */ +ACL_API void acl_ioctl_enable_write(ACL_IOCTL *ioc, ACL_VSTREAM *stream, + int timeout, ACL_IOCTL_NOTIFY_FN callback, void *context); + +/** + * 异步地连接服务器, 连接成功或连接超时时后调用用户的回调函数 + * @param ioc {ACL_IOCTL*} 服务器任务池句柄 + * @param stream {ACL_VSTREAM*} 处于连接远程服务器状态的本地客户端数据流 + * @param timeout {int} 连接超时时间 + * @param callback {ACL_IOCTL_NOTIFY_FN} 当数据流可写或出错或超时时的回调函数 + * @param context {void*} 回调函数 callback 的参数之一, 主要用于传递用户自己的参数, + * 用户需要在 callback 内将该参数转换成自己的可识别类型 + */ +ACL_API void acl_ioctl_enable_connect(ACL_IOCTL *ioc, ACL_VSTREAM *stream, + int timeout, ACL_IOCTL_NOTIFY_FN callback, void *context); + +/** + * 作为服务端来监听某个待监听地址 + * @param ioc {ACL_IOCTL*} 服务器任务池句柄 + * @param stream {ACL_VSTREAM*} 处于连接远程服务器状态的本地客户端数据流 + * @param timeout {int} 监听套接字监听超时时间, 当此超时时间到达且没有新连接到达时, + * 调用者可以在回调函数里处理其它事件, 如果该值为 0 则一直阻塞 + * 到有新连接到达或出错时用户的回调函数才被调用 + * @param callback {ACL_IOCTL_NOTIFY_FN} 当有新连接到达或监听套接字出错 + * 或监听超时时的回调函数 + * @param context {void*} callback 的参数之一, 参见上面说明 + */ +ACL_API void acl_ioctl_enable_listen(ACL_IOCTL *ioc, ACL_VSTREAM *stream, + int timeout, ACL_IOCTL_NOTIFY_FN callback, void *context); + +/*----------------------------------------------------------------------------*/ +/** + * 连接远程服务器 + * @param addr {const char*} 服务器端服务地址, 格式: ip:port, 如: 192.168.0.1:80 + * @param timeout {int} 连接超时时间, 其含义如下: + * 1) 0: 非阻塞地连接远程服务器 + * 2) -1: 阻塞地连接远程服务器直至连接成功或连接失败为止 + * 3) > 0: 带超时地连接远程服务器 + * @return {ACL_VSTREAM*} 客户端连接流. + * != NULL 表示连接成功或正在连接中; == NULL 连接失败或出错 + * 注: + * 当处于上述情况 1) 时, 需要将返回的 ACL_VSTREAM 句柄置入可连接集合中通过回调 + * 函数来对该流进行读写操作, 即还需要调用 acl_ioctl_enable_connect() 来确保连 + * 接成功. + */ +ACL_API ACL_VSTREAM *acl_ioctl_connect(const char *addr, int timeout); + +/** + * 创建一个监听套接字流 + * @param addr {const char*} 本地被监听的地址, 格式: ip:port, 如: 127.0.0.1:80 + * @param qlen {int} 监听队列长度 + * @return {ACL_VSTREAM*} 监听套接字数据流. != NULL ok; == NULL err. + * 注: 若要异步监听, 则可以调用 acl_ioctl_enable_listen() 来异步地 + * 获得一个客户端连接 + */ +ACL_API ACL_VSTREAM *acl_ioctl_listen(const char *addr, int qlen); + +/** + * 创建一个监听套接字流 + * @param addr {const char*} 本地被监听的地址, 格式: ip:port, 如: 127.0.0.1:80 + * @param qlen {int} 监听队列长度 + * @param block_mode {int} 是否采用非阻塞模式, ACL_BLOCKING: 阻塞模式, + * ACL_NON_BLOCKING: 非阻塞模式 + * @param io_bufsize {int} 获得客户端连接流的缓冲区大小(字节) + * @param io_timeout {int} 客户端流的读写超时时间(秒) + * @return {ACL_VSTREAM*} 监听套接字数据流. != NULL ok; == NULL err. + * 注: 若要异步监听, 则可以调用 acl_ioctl_enable_listen() 来异步地 + * 获得一个客户端连接 + */ +ACL_API ACL_VSTREAM *acl_ioctl_listen_ex(const char *addr, int qlen, + int block_mode, int io_bufsize, int io_timeout); + +/** + * 从监听套口获得一个客户端连接 + * @param sstream {ACL_VSTREAM*} 监听套字流 + * @param ipbuf {char*} 客户端流的地址 + * @param size {int} ipbuf 空间大小 + * @return {ACL_VSTREAM*} 客户端连接流. != NULL 成功获得一个客户端连接的数据流; + * == NULL 可能被系统中断了一下, 调用者应忽略此情况 + */ +ACL_API ACL_VSTREAM *acl_ioctl_accept(ACL_VSTREAM *sstream, + char *ipbuf, int size); + +/** + * 给任务工作池添加一个定时器任务, 该函数仅是 acl_event_request_timer 的简单封装. + * @param ioc {ACL_IOCTL*} 服务器任务池句柄 + * @param timer_fn {ACL_IOCTL_TIMER_FN} 定时器任务回调函数. + * @param context {void*} timer_fn 的参数之一. + * @param idle_limit {acl_int64} 启动定时器函数的时间(微秒级) + * @return {acl_int64} 剩余的时间, 单位为微秒. + */ +ACL_API acl_int64 acl_ioctl_request_timer(ACL_IOCTL *ioc, + ACL_IOCTL_TIMER_FN timer_fn, void *context, acl_int64 idle_limit); + +/** + * 取消某个定时器任务, 该函数仅是 acl_event_cancel_timer 的简单封装. + * @param ioc {ACL_IOCTL*} 服务器任务池句柄 + * @param timer_fn {ACL_IOCTL_TIMER_FN} 定时器任务回调函数. + * @param context {void*} timer_fn 的参数之一. + * @return {acl_int64} 剩余的时间, 单位为微秒. + */ +ACL_API acl_int64 acl_ioctl_cancel_timer(ACL_IOCTL *ioc, + ACL_IOCTL_TIMER_FN timer_fn, void *context); + +/** + * 向当前线程池中增加一个新的任务 + * @param ioc {ACL_IOCTL*} 服务器任务池句柄 + * @param callback {ACL_IOCTL_WORKER_FN} 工作任务的回调函数 + * @param arg {void*} callback 的参数之一 + * @return {int} 0: ok; < 0: error + */ +ACL_API int acl_ioctl_add(ACL_IOCTL *ioc, + ACL_IOCTL_WORKER_FN callback, void *arg); + +/** + * 获得当前线程池中工作线程的数量. + * @param ioc {ACL_IOCTL*} 服务器任务池句柄 + * @return {int} 返回当前工作线程的数量 == -1: error; >= 0: ok. + */ +ACL_API int acl_ioctl_nworker(ACL_IOCTL *ioc); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/include/ioctl/acl_myioctl.h b/lib_acl/include/ioctl/acl_myioctl.h new file mode 100644 index 000000000..d77c4bfea --- /dev/null +++ b/lib_acl/include/ioctl/acl_myioctl.h @@ -0,0 +1,16 @@ +#ifndef __ACL_MYIOCTL_INCLUDE_H__ +#define __ACL_MYIOCTL_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "acl_ioctl.h" +#include "acl_spool.h" + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/include/ioctl/acl_spool.h b/lib_acl/include/ioctl/acl_spool.h new file mode 100644 index 000000000..46a8b0575 --- /dev/null +++ b/lib_acl/include/ioctl/acl_spool.h @@ -0,0 +1,48 @@ +#ifndef __ACL_SPOOL_INCLUDE_H__ +#define __ACL_SPOOL_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "acl_ioctl.h" + +/* 为了保持向后兼容 */ + +#define ACL_SPOOL ACL_IOCTL +#define ACL_SPOOL_NOTIFY_FN ACL_IOCTL_NOTIFY_FN +#define ACL_SPOOL_TIMER_FN ACL_IOCTL_TIMER_FN +#define ACL_SPOOL_WORKER_FN ACL_IOCTL_WORKER_FN +#define acl_spool_create acl_ioctl_create +#define acl_spool_create_ex acl_ioctl_create_ex +#define acl_spool_ctl acl_ioctl_ctl +#define ACL_SPOOL_CTL_END ACL_IOCTL_CTL_END +#define ACL_SPOOL_CTL_THREAD_MAX ACL_IOCTL_CTL_THREAD_MAX +#define ACL_SPOOL_CTL_THREAD_IDLE ACL_IOCTL_CTL_THREAD_IDLE +#define ACL_SPOOL_CTL_DELAY_SEC ACL_IOCTL_CTL_DELAY_SEC +#define ACL_SPOOL_CTL_DELAY_USEC ACL_IOCTL_CTL_DELAY_USEC +#define acl_spool_free acl_ioctl_free +#define acl_spool_start acl_ioctl_start +#define acl_spool_loop acl_ioctl_loop +#define acl_spool_disable_readwrite acl_ioctl_disable_readwrite +#define acl_spool_isset acl_ioctl_isset +#define acl_spool_isrset acl_ioctl_isrset +#define acl_spool_iswset acl_ioctl_iswset +#define acl_spool_enable_read acl_ioctl_enable_read +#define acl_spool_enable_write acl_ioctl_enable_write +#define acl_spool_enable_connect acl_ioctl_enable_connect +#define acl_spool_enable_listen acl_ioctl_enable_listen +#define acl_spool_connect acl_ioctl_connect +#define acl_spool_listen acl_ioctl_listen +#define acl_spool_listen_ex acl_ioctl_listen_ex +#define acl_spool_accept acl_ioctl_accept +#define acl_spool_request_timer acl_ioctl_request_timer +#define acl_spool_cancel_timer acl_ioctl_cancel_timer +#define acl_spool_add acl_ioctl_add +#define acl_spool_nworker acl_ioctl_nworker + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/include/json/acl_json.h b/lib_acl/include/json/acl_json.h new file mode 100644 index 000000000..7fea7cff2 --- /dev/null +++ b/lib_acl/include/json/acl_json.h @@ -0,0 +1,302 @@ +#ifndef __ACL_JSON_INCLUDE_H__ +#define __ACL_JSON_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_iterator.h" +#include "stdlib/acl_vstring.h" +#include "stdlib/acl_ring.h" +#include "stdlib/acl_array.h" + +typedef struct ACL_JSON ACL_JSON; +typedef struct ACL_JSON_NODE ACL_JSON_NODE; + +struct ACL_JSON_NODE { + ACL_VSTRING *ltag; /**< 标签名 */ + ACL_VSTRING *text; /**< 当结点为叶结点时该文本内容非空 */ + ACL_JSON_NODE *tag_node; /**< 当标签值为 json 结点时此项非空 */ + int type; +#define ACL_JSON_T_LEAF 0 /**< 该结点的标签值为叶结点 */ +#define ACL_JSON_T_NODE 1 /**< 该结点的标签值为 json 结点 */ +#define ACL_JSON_T_ARRAY 2 /**< 该结点的标签值为 json 数组 */ +#define ACL_JSON_T_OBJ 3 /**< 该结点为一个 json 对象 */ + + ACL_JSON_NODE *parent; /**< 父结点 */ + ACL_RING children; /**< 子结点集合 */ + int depth; /**< 当前结点的深度 */ + + /* private */ + ACL_JSON *json; /**< json 对象 */ + ACL_RING node; /**< 当前结点 */ + int quote; /**< 非 0 表示 ' 或 " */ + int left_ch; /**< 本结点的第一个字符: { or [ */ + int right_ch; /**< 本结点的最后一个字符: } or ] */ + int backslash; /**< 转义字符 \ */ + int part_word; /**< 半个汉字的情况处理标志位 */ + + int status; /**< 状态机当前解析状态 */ +#define ACL_JSON_S_ROOT 0 /**< 表示是根结点 */ +#define ACL_JSON_S_OBJ 1 /**< 标签对象值 */ +#define ACL_JSON_S_NXT 2 /**< 下一个结点 */ +#define ACL_JSON_S_TAG 3 /**< 标签名 */ +#define ACL_JSON_S_VAL 4 /**< 子结点处理过程 */ +#define ACL_JSON_S_COL 5 /**< 冒号 : */ + + /* public: for acl_iterator, 通过 acl_foreach 列出该结点的一级子结点 */ + + /* 取迭代器头函数 */ + ACL_JSON_NODE *(*iter_head)(ACL_ITER*, ACL_JSON_NODE*); + /* 取迭代器下一个函数 */ + ACL_JSON_NODE *(*iter_next)(ACL_ITER*, ACL_JSON_NODE*); + /* 取迭代器尾函数 */ + ACL_JSON_NODE *(*iter_tail)(ACL_ITER*, ACL_JSON_NODE*); + /* 取迭代器上一个函数 */ + ACL_JSON_NODE *(*iter_prev)(ACL_ITER*, ACL_JSON_NODE*); +}; + +struct ACL_JSON { + int depth; /**< 最大深度 */ + int node_cnt; /**< 结点总数, 包括 root 结点 */ + ACL_JSON_NODE *root; /**< json 根结点 */ + int finish; /**< 是否分析结束 */ + unsigned flag; /**< 标志位 */ +#define ACL_JSON_FLAG_PART_WORD (1 << 0) /**< 是否兼容半个汉字 */ + + /* public: for acl_iterator, 通过 acl_foreach 可以列出所有子结点 */ + + /* 取迭代器头函数 */ + ACL_JSON_NODE *(*iter_head)(ACL_ITER*, ACL_JSON*); + /* 取迭代器下一个函数 */ + ACL_JSON_NODE *(*iter_next)(ACL_ITER*, ACL_JSON*); + /* 取迭代器尾函数 */ + ACL_JSON_NODE *(*iter_tail)(ACL_ITER*, ACL_JSON*); + /* 取迭代器上一个函数 */ + ACL_JSON_NODE *(*iter_prev)(ACL_ITER*, ACL_JSON*); + + /* private */ + ACL_ARRAY *node_cache; /**< json 结点缓存池 */ + int max_cache; /**< json 结点缓存池的最大容量 */ + ACL_JSON_NODE *curr_node; /**< 当前正在处理的 json 结点 */ + ACL_SLICE_POOL *slice; /**< 内存池对象 */ +}; + +/*----------------------------- in acl_json.c -----------------------------*/ + +/** + * 创建一个 json 结点 + * @param json {ACL_JSON*} json 对象 + * @return {ACL_JSON_NODE*} json 结点对象 + */ +ACL_API ACL_JSON_NODE *acl_json_node_alloc(ACL_JSON *json); + +/** + * 将某个 json 结点及其子结点从 json 对象中删除, 并释放该结点及其子结点 + * 所占空间函数来释放该 json 结点所占内存 + * @param node {ACL_JSON_NODE*} json 结点 + * @return {int} 返回删除的结点个数 + */ +ACL_API int acl_json_node_delete(ACL_JSON_NODE *node); + +/** + * 向某个 json 结点添加兄弟结点(该兄弟结点必须是独立的 json 结点) + * @param node1 {ACL_JSON_NODE*} 向本结点添加 json 结点 + * @param node2 {ACL_JSON_NODE*} 新添加的兄弟 json 结点 + */ +ACL_API void acl_json_node_append(ACL_JSON_NODE *node1, ACL_JSON_NODE *node2); + +/** + * 将某个 json 结点作为子结点加入某父 json 结点中 + * @param parent {ACL_JSON_NODE*} 父结点 + * @param child {ACL_JSON_NODE*} 子结点 + */ +ACL_API void acl_json_node_add_child(ACL_JSON_NODE *parent, ACL_JSON_NODE *child); + +/** + * 获得某个 json 结点的父结点 + * @param node {ACL_JSON_NODE*} json 结点 + * @return {ACL_JSON_NODE*} 父结点, 如果为 NULL 则表示其父结点不存在 + */ +ACL_API ACL_JSON_NODE *acl_json_node_parent(ACL_JSON_NODE *node); + +/** + * 获得某个 json 结点的后一个兄弟结点 + * @param node {ACL_JSON_NODE*} json 结点 + * @return {ACL_JSON_NODE*} 给定 json 结点的后一个兄弟结点, 若为NULL则表示不存在 + */ +ACL_API ACL_JSON_NODE *acl_json_node_next(ACL_JSON_NODE *node); + +/** + * 获得某个 json 结点的前一个兄弟结点 + * @param node {ACL_JSON_NODE*} json 结点 + * @return {ACL_JSON_NODE*} 给定 json 结点的前一个兄弟结点, 若为NULL则表示不存在 + */ +ACL_API ACL_JSON_NODE *acl_json_node_prev(ACL_JSON_NODE *node); + +/** + * 输出当前 json 结点的类型字符串 + * @param node {ACL_JSON_NODE*} json 结点对象 + * @return {const char*} json 结点对象类型的描述字符串 + */ +ACL_API const char *acl_json_node_type(const ACL_JSON_NODE *node); + +/** + * 创建一个 json 对象 + * @return {ACL_JSON*} 新创建的 json 对象 + */ +ACL_API ACL_JSON *acl_json_alloc(void); + +/** + * 创建一个 json 对象,该 json 对象及所有的内部内存分配都在该内存池上进行分配 + * @param slice {ACL_SLICE_POOL*} 内存池对象,可以为空指针,表明不用内存池 + * @return {ACL_JSON*} 新创建的 json 对象 + */ +ACL_API ACL_JSON *acl_json_alloc1(ACL_SLICE_POOL *slice); + +/** + * 将某一个 ACL_JSON_NODE 结点作为一个 json 对象的根结点, + * 从而可以方便地遍历出该结点的各级子结点(在遍历过程中的所有 + * 结点不含本结点自身),该遍历方式有别于单独 + * 遍历某一个 ACL_JSON_NODE 结点时仅能遍历其一级子结点的情形 + * @param json {ACL_JSON*} json 对象 + * @param node {ACL_JSON_NODE*} ACL_JSON_NODE 结点 + */ +ACL_API void acl_json_foreach_init(ACL_JSON *json, ACL_JSON_NODE *node); + +/** + * 打开或关闭 json 的缓存功能,当复用 ACL_JSON 对象时打开 + * json 的结点缓存功能有利提高效率 + * @param json {ACL_JSON*} json 对象 + * @param max_cache {int} 缓存的最大值,当该值 > 0 时会打开 json 解析器 + * 对 json 结点的缓存功能,否则会关闭 json 解析器对 json 结点的缓存功能 + */ +ACL_API void acl_json_cache(ACL_JSON *json, int max_cache); + +/** + * 释放 JSON 中缓存的 JSON 结点对象 + * @param json {ACL_JSON*} json 对象 + */ +ACL_API void acl_json_cache_free(ACL_JSON *json); + +/** + * 释放一个 json 对象, 同时释放该对象里容纳的所有 json 结点 + * @param json {ACL_JSON*} json 对象 + */ +ACL_API int acl_json_free(ACL_JSON *json); + +/** + * 重置 json 解析器对象 + * @param json {ACL_JSON*} json 对象 + */ +ACL_API void acl_json_reset(ACL_JSON *json); + +/*------------------------- in acl_json_parse.c ---------------------------*/ + +/** + * 解析 json 数据, 并持续地自动生成 json 结点树 + * @param json {ACL_JSON*} json 对象 + * @param data {const char*} 以 '\0' 结尾的数据字符串, 可以是完整的 json 数据; + * 也可以是不完整的 json 数据, 允许循环调用此函数, 将不完整数据持续地输入 + */ +ACL_API void acl_json_update(ACL_JSON *json, const char *data); + +/*------------------------- in acl_json_util.c ----------------------------*/ + +/** + * 释放由 acl_json_getElementsByTagName, acl_json_getElementsByName, + * 等函数返回的动态数组对象, 因为该动态数组中的 + * 元素都是 ACL_JSON 对象中元素的引用, 所以释放掉该动态数组后, 只要 ACL_JSON + * 对象不释放, 则原来存于该数组中的元素依然可以使用. + * 但并不释放里面的 xml 结点元素 + * @param a {ACL_ARRAY*} 动态数组对象 + */ +ACL_API void acl_json_free_array(ACL_ARRAY *a); + +/** + * 从 json 对象中获得所有的与所给标签名相同的 json 结点的集合 + * @param json {ACL_JSON*} json 对象 + * @param tag {const char*} 标签名称 + * @return {ACL_ARRAY*} 符合条件的 json 结点集合, 存于 动态数组中, 若返回 NULL 则 + * 表示没有符合条件的 json 结点, 非空值需要调用 acl_json_free_array 释放 + */ +ACL_API ACL_ARRAY *acl_json_getElementsByTagName(ACL_JSON *json, const char *tag); + +/** + * 从 json 对象中获得所有的与给定多级标签名相同的 json 结点的集合 + * @param json {ACL_JSON*} json 对象 + * @param tags {const char*} 多级标签名,由 '/' 分隔各级标签名,如针对 json 数据: + * { 'root': [ + * 'first': { 'second': { 'third': 'test1' } }, + * 'first': { 'second': { 'third': 'test2' } }, + * 'first': { 'second': { 'third': 'test3' } } + * ] + * } + * 可以通过多级标签名:root/first/second/third 一次性查出所有符合条件的结点 + * @return {ACL_ARRAY*} 符合条件的 json 结点集合, 存于 动态数组中, 若返回 NULL 则 + * 表示没有符合条件的 json 结点, 非空值需要调用 acl_json_free_array 释放 + */ +ACL_API ACL_ARRAY *acl_json_getElementsByTags(ACL_JSON *json, const char *tags); + +/** + * 构建 json 对象时创建 json 叶结点 + * @param json {ACL_JSON*} 由 acl_json_alloc / acl_json_alloc1 创建 + * @param name {const char*} 标签名,非空 + * @param text {const char*} 标签值,非空 + * @return {ACL_JSON_NODE*} 新创建的结点对象,在释放 ACL_JSON 对象时 + * 一起被释放,所以不需要单独释放 + */ +ACL_API ACL_JSON_NODE *acl_json_create_leaf(ACL_JSON *json, + const char *name, const char *text); + +/** + * 构建 json 对象时创建 json 对象(即仅包含 {} 的对象) + * @param json {ACL_JSON*} 由 acl_json_alloc / acl_json_alloc1 创建 + * @return {ACL_JSON_NODE*} 新创建的结点对象,在释放 ACL_JSON 对象时 + * 一起被释放,所以不需要单独释放 + */ +ACL_API ACL_JSON_NODE *acl_json_create_obj(ACL_JSON *json); + +/** + * 构建 json 对象时创建 json 数组对象(即仅包含 [] 的对象) + * @param json {ACL_JSON*} 由 acl_json_alloc / acl_json_alloc1 创建 + * @return {ACL_JSON_NODE*} 新创建的结点对象,在释放 ACL_JSON 对象时 + * 一起被释放,所以不需要单独释放 + */ +ACL_API ACL_JSON_NODE *acl_json_create_array(ACL_JSON *json); + +/** + * 构建 json 对象时创建 json 结点对象(即 tagname: ACL_JSON_NODE) + * @param json {ACL_JSON*} 由 acl_json_alloc / acl_json_alloc1 创建 + * @param name {const char*} json 结点的标签名 + * @param value {ACL_JSON_NODE*} json 结点对象作为标签值 + * @return {ACL_JSON_NODE*} 新创建的结点对象,在释放 ACL_JSON 对象时 + * 一起被释放,所以不需要单独释放 + */ +ACL_API ACL_JSON_NODE *acl_json_create_node(ACL_JSON *json, + const char *name, ACL_JSON_NODE *value); + +/** + * 构建 json 对象时,向一个由 acl_json_create_obj 或 acl_json_create_array + * 创建的 json 结点添加子结点,该子结点可以是由如下接口创建的结点: + * acl_json_create_leaf, acl_json_create_obj, acl_json_create_array + */ +ACL_API void acl_json_node_append_child(ACL_JSON_NODE *parent, + ACL_JSON_NODE *child); + +/** + * 将 json 对象转成字符串内容 + * @param json {ACL_JSON*} json 对象 + * @param buf {ACL_VSTRING*} 存储结果集的缓冲区,当该参数为空时则函数内部会 + * 自动分配一段缓冲区,应用用完后需要释放掉;非空函数内部会直接将结果存储其中 + * @return {ACL_VSTRING*} json 对象转换成字符串后的存储缓冲区,该返回值永远非空, + * 使用者可以通过 ACL_VSTRING_LEN(x) 宏来判断内容是否为空,返回的 ACL_VSTRING + * 指针如果为该函数内部创建的,则用户名必须用 acl_vstring_free 进行释放 + */ +ACL_API ACL_VSTRING *acl_json_build(ACL_JSON *json, ACL_VSTRING *buf); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/include/lib_acl.h b/lib_acl/include/lib_acl.h new file mode 100644 index 000000000..f7517a9c8 --- /dev/null +++ b/lib_acl/include/lib_acl.h @@ -0,0 +1,30 @@ +#ifndef __LIB_ACL_INCLUDE_H__ +#define __LIB_ACL_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "init/acl_init.h" +#include "stdlib/acl_stdlib.h" +#include "net/acl_net.h" +#include "thread/acl_thread.h" +#include "msg/acl_aqueue.h" +#include "msg/acl_msgio.h" +#include "event/acl_events.h" +#include "ioctl/acl_myioctl.h" +#include "aio/acl_aio.h" +#include "db/acl_db.h" +#include "unit_test/acl_unit_test.h" +#include "code/acl_code.h" +#include "master/acl_master.h" +#include "proctl/acl_proctl.h" +#include "xml/acl_xml.h" +#include "json/acl_json.h" +#include "experiment/experiment.h" + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/include/lib_util.h b/lib_acl/include/lib_util.h new file mode 100644 index 000000000..859ac5671 --- /dev/null +++ b/lib_acl/include/lib_util.h @@ -0,0 +1,15 @@ +#ifndef __LIB_UTIL_INCLUDE_H__ +#define __LIB_UTIL_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lib_acl.h" + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/include/master/acl_aio_params.h b/lib_acl/include/master/acl_aio_params.h new file mode 100644 index 000000000..5e03948ed --- /dev/null +++ b/lib_acl/include/master/acl_aio_params.h @@ -0,0 +1,111 @@ + +#ifndef __ACL_AIO_PARAMS_INCLUDE_H_ +#define __ACL_AIO_PARAMS_INCLUDE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_define.h" +#ifdef ACL_UNIX + +extern int acl_var_aio_pid; +extern char *acl_var_aio_procname; +extern char *acl_var_aio_log_file; + +#define ACL_VAR_AIO_BUF_SIZE "aio_buf_size" +#define ACL_DEF_AIO_BUF_SIZE 81920 +extern int acl_var_aio_buf_size; + +#define ACL_VAR_AIO_RW_TIMEOUT "aio_rw_timeout" +#define ACL_DEF_AIO_RW_TIMEOUT 30 +extern int acl_var_aio_rw_timeout; + +#define ACL_VAR_AIO_IN_FLOW_DELAY "aio_in_flow_delay" +#define ACL_DEF_AIO_IN_FLOW_DELAY 1 +extern int acl_var_aio_in_flow_delay; + +#define ACL_VAR_AIO_MAX_THREADS "aio_max_threads" +#define ACL_DEF_AIO_MAX_THREADS 0 +extern int acl_var_aio_max_threads; + +#define ACL_VAR_AIO_THREAD_IDLE_LIMIT "aio_thread_idle_limit" +#define ACL_DEF_AIO_THREAD_IDLE_LIMIT 0 +extern int acl_var_aio_thread_idle_limit; + +#define ACL_VAR_AIO_IDLE_LIMIT "aio_idle_limit" +#define ACL_DEF_AIO_IDLE_LIMIT 180 +extern int acl_var_aio_idle_limit; + +#define ACL_VAR_AIO_QUEUE_DIR "aio_queue_dir" +#define ACL_DEF_AIO_QUEUE_DIR "/opt/acl_master/var/queue" +extern char *acl_var_aio_queue_dir; + +#define ACL_VAR_AIO_PID_DIR "aio_pid_dir" +#define ACL_DEF_AIO_PID_DIR "/opt/acl_master/var/pid" +extern char *acl_var_aio_pid_dir; + +#define ACL_VAR_AIO_ACCESS_ALLOW "aio_access_allow" +#define ACL_DEF_AIO_ACCESS_ALLOW "0.0.0.0:255.255.255.255" +extern char *acl_var_aio_access_allow; + +#define ACL_VAR_AIO_OWNER "aio_owner" +#define ACL_DEF_AIO_OWNER "aio" +extern char *acl_var_aio_owner; + +#define ACL_VAR_AIO_DELAY_SEC "aio_delay_sec" +#define ACL_DEF_AIO_DELAY_SEC 1 +extern int acl_var_aio_delay_sec; + +#define ACL_VAR_AIO_DELAY_USEC "aio_delay_usec" +#define ACL_DEF_AIO_DELAY_USEC 5000 +extern int acl_var_aio_delay_usec; + +#define ACL_VAR_AIO_EVENT_MODE "aio_event_mode" +#define ACL_DEF_AIO_EVENT_MODE "select" +extern char *acl_var_aio_event_mode; + +#define ACL_VAR_AIO_DAEMON_TIMEOUT "aio_daemon_timeout" +#define ACL_DEF_AIO_DAEMON_TIMEOUT 1800 +extern int acl_var_aio_daemon_timeout; + +#define ACL_VAR_AIO_USE_LIMIT "aio_use_limit" +#define ACL_DEF_AIO_USE_LIMIT 10 +extern int acl_var_aio_use_limit; + +#define ACL_VAR_AIO_MASTER_MAXPROC "master_maxproc" +#define ACL_DEF_AIO_MASTER_MAXPROC 1 +extern int acl_var_aio_master_maxproc; + +#define ACL_VAR_AIO_MAX_ACCEPT "aio_max_accept" +#define ACL_DEF_AIO_MAX_ACCEPT 10 +extern int acl_var_aio_max_accept; + +#define ACL_VAR_AIO_MIN_NOTIFY "aio_min_notify" +#define ACL_DEF_AIO_MIN_NOTIFY 10 +extern int acl_var_aio_min_notify; + +#define ACL_VAR_AIO_ACCEPT_ALONE "aio_accept_alone" +#define ACL_DEF_AIO_ACCEPT_ALONE "yes" +extern char *acl_var_aio_accept_alone; + +#define ACL_VAR_AIO_ENABLE_CORE "aio_enable_core" +#define ACL_DEF_AIO_ENABLE_CORE 1 +extern int acl_var_aio_enable_core; + +#define ACL_VAR_AIO_QUICK_ABORT "aio_quick_abort" +#define ACL_DEF_AIO_QUICK_ABORT 1 +extern int acl_var_aio_quick_abort; + +#define ACL_VAR_AIO_ACCEPT_TIMER "aio_accept_timer" +#define ACL_DEF_AIO_ACCEPT_TIMER 0 +extern int acl_var_aio_accept_timer; + +#endif /* ACL_UNIX */ + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/include/master/acl_app_main.h b/lib_acl/include/master/acl_app_main.h new file mode 100644 index 000000000..508db9fca --- /dev/null +++ b/lib_acl/include/master/acl_app_main.h @@ -0,0 +1,91 @@ +#ifndef __ACL_APP_MAIN_INCLUDE_H__ +#define __ACL_APP_MAIN_INCLUDE_H__ + +#include "lib_acl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef ACL_UNIX + +/* 客户端读写超时时间值 */ +extern int acl_app_var_client_idle_limit; + +/* 用户级的运行函数类型, 当该函数返回值 != 0 时, 框架会自动关闭客户端流 */ +typedef int (*ACL_IOCTL_RUN_FN)(ACL_VSTREAM *stream, void *run_ctx); + +/* 非阻塞IO服务器模板的运行函数类型 */ +typedef int (*ACL_AIO_RUN_FN)(ACL_ASTREAM *stream, void *run_ctx); +typedef int (*ACL_AIO_RUN2_FN)(ACL_SOCKET fd, void *run_ctx); + +/* 用户级的初始化函数类型 */ +typedef void (*ACL_APP_INIT_FN)(void*); +typedef void (*ACL_APP_EXIT_FN)(void*); +typedef void (*ACL_APP_PRE_JAIL)(void*); + +/* 使用用户自己的日志管理函数 */ +typedef void (*ACL_APP_OPEN_LOG)(void); +typedef void (*ACL_APP_CLOSE_LOG)(void); + +typedef ACL_MASTER_SERVER_THREAD_INIT_FN ACL_APP_THREAD_INIT_FN /* void (*)(void*) */; +typedef ACL_MASTER_SERVER_THREAD_EXIT_FN ACL_APP_THREAD_EXIT_FN; /* void (*)(void*) */ + +#define ACL_APP_CTL_END 0 /* 参数控制结束标志 */ +#define ACL_APP_CTL_INIT_FN 1 /* 初始化函数 */ +#define ACL_APP_CTL_INIT_CTX 2 /* 初始化函数所用的参数 */ +#define ACL_APP_CTL_CFG_BOOL 3 /* 整数类型的配置参数表 */ +#define ACL_APP_CTL_CFG_INT 4 /* 整数类型的配置参数表 */ +#define ACL_APP_CTL_CFG_STR 5 /* 字符串类型的配置参数表 */ +#define ACL_APP_CTL_EXIT_FN 6 /* 当进程退出时的回调函数 */ +#define ACL_APP_CTL_EXIT_CTX 7 /* 进程退出时回调函数的参数 */ +#define ACL_APP_CTL_THREAD_INIT 8 /* 每个线程启动时的回调函数 */ +#define ACL_APP_CTL_THREAD_INIT_CTX 9 /* 线程启动时回调函数的参数 */ +#define ACL_APP_CTL_THREAD_EXIT 10 /* 线程退出时的回调函数 */ +#define ACL_APP_CTL_THREAD_EXIT_CTX 11 /* 线程退出时回调函数的参数 */ +#define ACL_APP_CTL_DENY_INFO 12 /* 当非法客户端访问时给出的提示信息 */ +#define ACL_APP_CTL_OPEN_LOG 13 /* 日志初始化,可以通过此参数设置用户自己的日志函数 */ +#define ACL_APP_CTL_CLOSE_LOG 14 /* 关闭用户自己的日志函数 */ +#define ACL_APP_CTL_CFG_INT64 15 /* 64 位整数类型的配置参数表 */ +#define ACL_APP_CTL_ON_ACCEPT 16 /* 设置回调函数来处理新接收到的远程连接 */ +#define ACL_APP_CTL_PRE_JAIL 17 /* 设置进程切换身份前的回调函数 */ +#define ACL_APP_CTL_PRE_JAIL_CTX 18 /* 设置进程切换身份前回调函数的参数 */ +#define ACL_APP_CTL_ON_TIMEOUT 19 /* 当 IO 读写超时时控制的回调函数 */ +#define ACL_APP_CTL_ON_CLOSE 20 /* 当 IO 关闭时控制的回调函数 */ +/*----------------------------------------------------------------------------*/ +/* in app_main.c */ + +/** + * 主函数入口, 用户级的初始化函数指针及运行函数指针通过控制参数进行注册, 主函数内部 + * 会在初始化时自动调用用户级初始化函数(ACL_APP_INIT_FN 类型), 当接收到允许访问的客户端 + * 连接时会自动调用用户(ACL_APP_RUN_FN 类型). + * 级的运行函数. + * @param argc "int main(int argc, char *argv[])" 中的 argc + * @param argv "int main(int argc, char *argv[])" 中的 argv + * @param run_fn 用户级运行主函数 + * @param run_ctx run_fn() 运行时的参数之一 + * @param name 控制参数中的第一个控制类型, 所支持的类型如上定义: ACL_APP_CTL_XXX + * 调用方式: ACL_APP_CTL_XXX, xxx; 其中 ACL_APP_CTL_END 为特殊的控制参数, 表示控制参数 + * 结束. + * @example: + * acl_xxx_app_main(argc, argv, {run_fn}, {run_ctx}, + * ACL_APP_CTL_INIT_FN, {run_init_fn}, + * ACL_APP_CTL_INIT_CTX, {run_init_ctx}, + * ACL_APP_CTL_END); + * 注: acl_xxx_app_main() 的所有参数中, argc, argv, run_fn, run_ctx(可以为NULL), ACL_APP_CTL_END + * 都是必需的. + */ + +void acl_ioctl_app_main(int argc, char *argv[], ACL_IOCTL_RUN_FN run_fn, void *run_ctx, int name, ...); +void acl_aio_app_main(int argc, char *argv[], ACL_AIO_RUN_FN run_fn, void *run_ctx, int name, ...); +void acl_aio_app2_main(int argc, char *argv[], ACL_AIO_RUN2_FN run2_fn, void *run_ctx, int name, ...); + +/*----------------------------------------------------------------------------*/ + +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/include/master/acl_ioctl_params.h b/lib_acl/include/master/acl_ioctl_params.h new file mode 100644 index 000000000..fcb4c9f6c --- /dev/null +++ b/lib_acl/include/master/acl_ioctl_params.h @@ -0,0 +1,107 @@ + +#ifndef __ACL_IOCTL_PARAMS_INCLUDE_H_ +#define __ACL_IOCTL_PARAMS_INCLUDE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_define.h" +#ifdef ACL_UNIX + +extern int acl_var_ioctl_pid; +extern char *acl_var_ioctl_procname; +extern char *acl_var_ioctl_log_file; + +#define ACL_VAR_IOCTL_BUF_SIZE "ioctl_buf_size" +#define ACL_DEF_IOCTL_BUF_SIZE 81920 +extern int acl_var_ioctl_buf_size; + +#define ACL_VAR_IOCTL_RW_TIMEOUT "ioctl_rw_timeout" +#define ACL_DEF_IOCTL_RW_TIMEOUT 30 +extern int acl_var_ioctl_rw_timeout; + +#define ACL_VAR_IOCTL_IN_FLOW_DELAY "ioctl_in_flow_delay" +#define ACL_DEF_IOCTL_IN_FLOW_DELAY 1 +extern int acl_var_ioctl_in_flow_delay; + +#define ACL_VAR_IOCTL_MAX_THREADS "ioctl_max_threads" +#define ACL_DEF_IOCTL_MAX_THREADS 50 +extern int acl_var_ioctl_max_threads; + +#define ACL_VAR_IOCTL_STACKSIZE "ioctl_stacksize" +#define ACL_DEF_IOCTL_STACKSIZE 0 +extern int acl_var_ioctl_stacksize; + +#define ACL_VAR_IOCTL_THREAD_IDLE_LIMIT "ioctl_thread_idle_limit" +#define ACL_DEF_IOCTL_THREAD_IDLE_LIMIT 180 +extern int acl_var_ioctl_thread_idle_limit; + +#define ACL_VAR_IOCTL_IDLE_LIMIT "ioctl_idle_limit" +#define ACL_DEF_IOCTL_IDLE_LIMIT 180 +extern int acl_var_ioctl_idle_limit; + +#define ACL_VAR_IOCTL_QUEUE_DIR "ioctl_queue_dir" +#define ACL_DEF_IOCTL_QUEUE_DIR "/opt/acl_master/var/queue" +extern char *acl_var_ioctl_queue_dir; + +#define ACL_VAR_IOCTL_PID_DIR "ioctl_pid_dir" +#define ACL_DEF_IOCTL_PID_DIR "/opt/acl_master/var/pid" +extern char *acl_var_ioctl_pid_dir; + +#define ACL_VAR_IOCTL_ACCESS_ALLOW "ioctl_access_allow" +#define ACL_DEF_IOCTL_ACCESS_ALLOW "0.0.0.0:255.255.255.255" +extern char *acl_var_ioctl_access_allow; + +#define ACL_VAR_IOCTL_OWNER "ioctl_owner" +#define ACL_DEF_IOCTL_OWNER "ioctl" +extern char *acl_var_ioctl_owner; + +#define ACL_VAR_IOCTL_DELAY_SEC "ioctl_delay_sec" +#define ACL_DEF_IOCTL_DELAY_SEC 1 +extern int acl_var_ioctl_delay_sec; + +#define ACL_VAR_IOCTL_DELAY_USEC "ioctl_delay_usec" +#define ACL_DEF_IOCTL_DELAY_USEC 5000 +extern int acl_var_ioctl_delay_usec; + +#define ACL_VAR_IOCTL_EVENT_MODE "ioctl_event_mode" +#define ACL_DEF_IOCTL_EVENT_MODE "select" +extern char *acl_var_ioctl_event_mode; + +#define ACL_VAR_IOCTL_DAEMON_TIMEOUT "ioctl_daemon_timeout" +#define ACL_DEF_IOCTL_DAEMON_TIMEOUT 1800 +extern int acl_var_ioctl_daemon_timeout; + +#define ACL_VAR_IOCTL_USE_LIMIT "ioctl_use_limit" +#define ACL_DEF_IOCTL_USE_LIMIT 10 +extern int acl_var_ioctl_use_limit; + +#define ACL_VAR_IOCTL_MASTER_MAXPROC "master_maxproc" +#define ACL_DEF_IOCTL_MASTER_MAXPROC 1 +extern int acl_var_ioctl_master_maxproc; + +#define ACL_VAR_IOCTL_MAX_ACCEPT "ioctl_max_accept" +#define ACL_DEF_IOCTL_MAX_ACCEPT 15 +extern int acl_var_ioctl_max_accept; + +#define ACL_VAR_IOCTL_ENABLE_DOG "ioctl_enable_dog" +#define ACL_DEF_IOCTL_ENABLE_DOG 1 +extern int acl_var_ioctl_enable_dog; + +#define ACL_VAR_IOCTL_QUICK_ABORT "ioctl_quick_abort" +#define ACL_DEF_IOCTL_QUICK_ABORT 1 +extern int acl_var_ioctl_quick_abort; + +#define ACL_VAR_IOCTL_ENABLE_CORE "ioctl_enable_core" +#define ACL_DEF_IOCTL_ENABLE_CORE 1 +extern int acl_var_ioctl_enable_core; + +#endif /* ACL_UNIX */ + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/include/master/acl_master.h b/lib_acl/include/master/acl_master.h new file mode 100644 index 000000000..61ac26795 --- /dev/null +++ b/lib_acl/include/master/acl_master.h @@ -0,0 +1,22 @@ +#ifndef __ACL_MYMASTER_INCLUDE_H_ +#define __ACL_MYMASTER_INCLUDE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "acl_master_type.h" +#include "acl_server_api.h" +#include "acl_single_params.h" +#include "acl_multi_params.h" +#include "acl_ioctl_params.h" +#include "acl_aio_params.h" +#include "acl_master_conf.h" +#include "acl_app_main.h" + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/include/master/acl_master_conf.h b/lib_acl/include/master/acl_master_conf.h new file mode 100644 index 000000000..471dcdb4a --- /dev/null +++ b/lib_acl/include/master/acl_master_conf.h @@ -0,0 +1,21 @@ +#ifndef __ACL_MASTER_CONF_INCLUDE_H__ +#define __ACL_MASTER_CONF_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_define.h" +#include "master/acl_master_type.h" + +ACL_API void acl_app_conf_load(const char *pathname); +ACL_API void acl_get_app_conf_int_table(ACL_CONFIG_INT_TABLE *table); +ACL_API void acl_get_app_conf_int64_table(ACL_CONFIG_INT64_TABLE *table); +ACL_API void acl_get_app_conf_str_table(ACL_CONFIG_STR_TABLE *table); +ACL_API void acl_get_app_conf_bool_table(ACL_CONFIG_BOOL_TABLE *table); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/include/master/acl_master_type.h b/lib_acl/include/master/acl_master_type.h new file mode 100644 index 000000000..00a7de72e --- /dev/null +++ b/lib_acl/include/master/acl_master_type.h @@ -0,0 +1,19 @@ +#ifndef __ACL_MASTER_TYPE_INCLUDE_H__ +#define __ACL_MASTER_TYPE_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_xinetd_cfg.h" + +#define ACL_CONFIG_INT_TABLE ACL_CFG_INT_TABLE +#define ACL_CONFIG_INT64_TABLE ACL_CFG_INT64_TABLE +#define ACL_CONFIG_STR_TABLE ACL_CFG_STR_TABLE +#define ACL_CONFIG_BOOL_TABLE ACL_CFG_BOOL_TABLE + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/include/master/acl_multi_params.h b/lib_acl/include/master/acl_multi_params.h new file mode 100644 index 000000000..d5e53c6a8 --- /dev/null +++ b/lib_acl/include/master/acl_multi_params.h @@ -0,0 +1,71 @@ + +#ifndef __ACL_MULTI_PARAMS_INCLUDE_H_ +#define __ACL_MULTI_PARAMS_INCLUDE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_define.h" +#ifdef ACL_UNIX + +extern int acl_var_multi_pid; +extern char *acl_var_multi_procname; +extern char *acl_var_multi_log_file; + +#define ACL_VAR_MULTI_BUF_SIZE "multi_buf_size" +#define ACL_DEF_MULTI_BUF_SIZE 81920 +extern int acl_var_multi_buf_size; + +#define ACL_VAR_MULTI_RW_TIMEOUT "multi_rw_timeout" +#define ACL_DEF_MULTI_RW_TIMEOUT 30 +extern int acl_var_multi_rw_timeout; + +#define ACL_VAR_MULTI_IN_FLOW_DELAY "multi_in_flow_delay" +#define ACL_DEF_MULTI_IN_FLOW_DELAY 1 +extern int acl_var_multi_in_flow_delay; + +#define ACL_VAR_MULTI_IDLE_LIMIT "multi_idle_limit" +#define ACL_DEF_MULTI_IDLE_LIMIT 180 +extern int acl_var_multi_idle_limit; + +#define ACL_VAR_MULTI_QUEUE_DIR "multi_queue_dir" +#define ACL_DEF_MULTI_QUEUE_DIR "/opt/acl_master/var/queue" +extern char *acl_var_multi_queue_dir; + +#define ACL_VAR_MULTI_PID_DIR "multi_pid_dir" +#define ACL_DEF_MULTI_PID_DIR "/opt/acl_master/var/pid" +extern char *acl_var_multi_pid_dir; + +#define ACL_VAR_MULTI_OWNER "multi_owner" +#define ACL_DEF_MULTI_OWNER "multi" +extern char *acl_var_multi_owner; + +#define ACL_VAR_MULTI_DELAY_SEC "multi_delay_sec" +#define ACL_DEF_MULTI_DELAY_SEC 1 +extern int acl_var_multi_delay_sec; + +#define ACL_VAR_MULTI_DELAY_USEC "multi_delay_usec" +#define ACL_DEF_MULTI_DELAY_USEC 5000 +extern int acl_var_multi_delay_usec; + +#define ACL_VAR_MULTI_DAEMON_TIMEOUT "multi_daemon_timeout" +#define ACL_DEF_MULTI_DAEMON_TIMEOUT 1800 +extern int acl_var_multi_daemon_timeout; + +#define ACL_VAR_MULTI_USE_LIMIT "multi_use_limit" +#define ACL_DEF_MULTI_USE_LIMIT 10 +extern int acl_var_multi_use_limit; + +#define ACL_VAR_MULTI_ENABLE_CORE "multi_enable_core" +#define ACL_DEF_MULTI_ENABLE_CORE 1 +extern int acl_var_multi_enable_core; + +#endif /* ACL_UNIX */ + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/include/master/acl_server_api.h b/lib_acl/include/master/acl_server_api.h new file mode 100644 index 000000000..6b77b1c7a --- /dev/null +++ b/lib_acl/include/master/acl_server_api.h @@ -0,0 +1,164 @@ + +#ifndef __ACL_MASTER_SERVER_API_INCLUDE_H_ +#define __ACL_MASTER_SERVER_API_INCLUDE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_define.h" +#ifdef ACL_UNIX + + /* + * Utility library. + */ +#include "stdlib/acl_vstream.h" +#include "ioctl/acl_myioctl.h" +#include "aio/acl_aio.h" +#include "event/acl_events.h" + + /* + * External interface. Tables are defined in mail_conf.h. + */ +#define ACL_MASTER_SERVER_INT_TABLE 1 +#define ACL_MASTER_SERVER_STR_TABLE 2 +#define ACL_MASTER_SERVER_BOOL_TABLE 3 +#define ACL_MASTER_SERVER_TIME_TABLE 4 +#define ACL_MASTER_SERVER_RAW_TABLE 5 +#define ACL_MASTER_SERVER_INT64_TABLE 6 + +#define ACL_MASTER_SERVER_PRE_INIT 10 +#define ACL_MASTER_SERVER_POST_INIT 11 +#define ACL_MASTER_SERVER_LOOP 12 +#define ACL_MASTER_SERVER_EXIT 13 +#define ACL_MASTER_SERVER_PRE_ACCEPT 14 +#define ACL_MASTER_SERVER_SOLITARY 15 +#define ACL_MASTER_SERVER_UNLIMITED 16 +#define ACL_MASTER_SERVER_PRE_DISCONN 17 +#define ACL_MASTER_SERVER_PRIVILEGED 18 +#define ACL_MASTER_SERVER_ON_ACCEPT 19 + +#define ACL_MASTER_SERVER_IN_FLOW_DELAY 20 + +#define ACL_MASTER_SERVER_RW_TIMER 30 + +#define ACL_MASTER_SERVER_THREAD_INIT 50 +#define ACL_MASTER_SERVER_THREAD_INIT_CTX 51 +#define ACL_MASTER_SERVER_THREAD_EXIT 52 +#define ACL_MASTER_SERVER_THREAD_EXIT_CTX 53 + +typedef void (*ACL_MASTER_SERVER_INIT_FN) (char *, char **); +typedef int (*ACL_MASTER_SERVER_LOOP_FN) (char *, char **); +typedef void (*ACL_MASTER_SERVER_EXIT_FN) (char *, char **); +typedef void (*ACL_MASTER_SERVER_ACCEPT_FN) (char *, char **); +typedef void (*ACL_MASTER_SERVER_DISCONN_FN) (ACL_VSTREAM *, char *, char **); +typedef int (*ACL_MASTER_SERVER_ON_ACCEPT_FN) (ACL_VSTREAM *); + +/* see acl_ioctl.h */ +typedef ACL_IOCTL_THREAD_INIT_FN ACL_MASTER_SERVER_THREAD_INIT_FN; +typedef ACL_IOCTL_THREAD_EXIT_FN ACL_MASTER_SERVER_THREAD_EXIT_FN; + +/* add by zsx for rw timeout, 2005.9.25*/ +typedef void (*ACL_MASTER_SERVER_RW_TIMER_FN) (ACL_VSTREAM *); + + /* + * acl_single_server.c + */ +typedef void (*ACL_SINGLE_SERVER_FN) (ACL_VSTREAM *, char *, char **); +extern void acl_single_server_main(int, char **, ACL_SINGLE_SERVER_FN, ...); +extern ACL_EVENT *acl_single_server_event(void); + + /* + * acl_multi_server.c + */ +typedef void (*ACL_MULTI_SERVER_FN) (ACL_VSTREAM *, char *, char **); +/* add by zsx for rw timeout, 2005.9.25*/ +void acl_multi_server_request_rw_timer(ACL_VSTREAM *); +void acl_multi_server_cancel_rw_timer(ACL_VSTREAM *); +/* end add, 2005.9.25 */ +extern void acl_multi_server_main(int, char **, ACL_MULTI_SERVER_FN,...); +extern void acl_multi_server_disconnect(ACL_VSTREAM *); +extern int acl_multi_server_drain(void); +extern ACL_EVENT *acl_multi_server_event(void); +extern void acl_multi_server_enable_read(ACL_VSTREAM *stream); + + /* + * acl_ioctl_server.c + */ +typedef void (*ACL_IOCTL_SERVER_FN) (ACL_IOCTL *, ACL_VSTREAM *, char *, char **); +extern void acl_ioctl_server_request_timer(ACL_IOCTL_TIMER_FN timer_fn, void *arg, int delay); +extern void acl_ioctl_server_cancel_timer(ACL_IOCTL_TIMER_FN timer_fn, void *arg); +extern void acl_ioctl_server_main(int, char **, ACL_IOCTL_SERVER_FN,...); +extern ACL_IOCTL *acl_ioctl_server_handle(void); +extern ACL_EVENT *acl_ioctl_server_event(void); +extern void acl_ioctl_server_enable_read(ACL_IOCTL *h_ioctl, + ACL_VSTREAM *stream, + int timeout, + ACL_IOCTL_NOTIFY_FN notify_fn, + void *context); + + /* + * acl_aio_server.c + */ +typedef void (*ACL_AIO_SERVER_FN) (ACL_SOCKET, char *, char **); +extern void acl_aio_server_request_timer(ACL_AIO_TIMER_FN timer_fn, void *arg, int delay); +extern void acl_aio_server_cancel_timer(ACL_AIO_TIMER_FN timer_fn, void *arg); +extern void acl_aio_server_request_rw_timer(ACL_ASTREAM *); +extern void acl_aio_server_cancel_rw_timer(ACL_ASTREAM *); +extern void acl_aio_server_main(int, char **, ACL_AIO_SERVER_FN,...); +extern ACL_AIO* acl_aio_server_handle(void); +extern ACL_EVENT *acl_aio_server_event(void); +extern int acl_aio_server_read(ACL_ASTREAM *astream, int timeout, + ACL_AIO_READ_FN notify_fn, void *context); +extern int acl_aio_server_readn(ACL_ASTREAM *astream, int count, int timeout, + ACL_AIO_READ_FN notify_fn, void *context); +extern int acl_aio_server_gets(ACL_ASTREAM *astream, int timeout, + ACL_AIO_READ_FN notify_fn, void *context); +extern int acl_aio_server_gets_nonl(ACL_ASTREAM *astream, int timeout, + ACL_AIO_READ_FN notify_fn, void *context); +extern int acl_aio_server_writen(ACL_ASTREAM *astream, + ACL_AIO_WRITE_FN notify_fn, void *context, + const char *data, int dlen); +extern int acl_aio_server_vfprintf(ACL_ASTREAM *astream, + ACL_AIO_WRITE_FN notify_fn, void *context, + const char *fmt, va_list ap); +extern int acl_aio_server_fprintf(ACL_ASTREAM *astream, + ACL_AIO_WRITE_FN notify_fn, void *context, + const char *fmt, ...); +extern int acl_aio_server_connect(const char *saddr, int timeout, + ACL_AIO_CONNECT_FN connect_fn, void *context); + + /* + * acl_listener_server.c + */ +typedef void (*ACL_LISTEN_SERVER_FN) (ACL_VSTREAM *, char *, char **); +/* add by zsx for rw timeout, 2005.9.25*/ +void acl_listener_server_request_rw_timer(ACL_VSTREAM *); +void acl_listener_server_cancel_rw_timer(ACL_VSTREAM *); +/* end add, 2005.9.25 */ +extern void acl_listener_server_main(int, char **, ACL_MULTI_SERVER_FN,...); +extern void acl_listener_server_disconnect(ACL_VSTREAM *); +extern int acl_listener_server_drain(void); + + /* + * acl_trigger_server.c + */ +typedef void (*ACL_TRIGGER_SERVER_FN) (char *, int, char *, char **); +extern void acl_trigger_server_main(int, char **, ACL_TRIGGER_SERVER_FN, ...); +extern ACL_EVENT *acl_trigger_server_event(void); + +/* + * acl_master_log.c + */ +extern void acl_master_log_open(const char *procname); + +#define ACL_TRIGGER_BUF_SIZE 1024 + +#endif /* ACL_UNIX */ + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/include/master/acl_single_params.h b/lib_acl/include/master/acl_single_params.h new file mode 100644 index 000000000..1bc4e56f1 --- /dev/null +++ b/lib_acl/include/master/acl_single_params.h @@ -0,0 +1,83 @@ + +#ifndef __ACL_SINGLE_PARAMS_INCLUDE_H_ +#define __ACL_SINGLE_PARAMS_INCLUDE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_define.h" +#ifdef ACL_UNIX + +extern int acl_var_single_pid; /* get by call getpid() */ +extern char *acl_var_single_procname; /* get from single_main()'s argv[0] */ +extern char *acl_var_single_log_file; /* get from getenv("LOG") */ + +#define ACL_VAR_SINGLE_BUF_SIZE "single_buf_size" +#define ACL_DEF_SINGLE_BUF_SIZE 81920 +extern int acl_var_single_buf_size; + +#define ACL_VAR_SINGLE_RW_TIMEOUT "single_rw_timeout" +#define ACL_DEF_SINGLE_RW_TIMEOUT 30 +extern int acl_var_single_rw_timeout; + +#define ACL_VAR_SINGLE_IN_FLOW_DELAY "single_in_flow_delay" +#define ACL_DEF_SINGLE_IN_FLOW_DELAY 1 +extern int acl_var_single_in_flow_delay; + +/* + * Any subsystem: default amount of time a mail subsystem waits for a client + * connection (except queue manager). + */ +#define ACL_VAR_SINGLE_IDLE_LIMIT "single_idle_limit" +#define ACL_DEF_SINGLE_IDLE_LIMIT 180 +extern int acl_var_single_idle_limit; + +#define ACL_VAR_SINGLE_QUEUE_DIR "single_queue_dir" +#define ACL_DEF_SINGLE_QUEUE_DIR "/opt/acl_master/var/queue" +extern char *acl_var_single_queue_dir; + +#define ACL_VAR_SINGLE_PID_DIR "single_pid_dir" +#define ACL_DEF_SINGLE_PID_DIR "/opt/acl_master/var/pid" +extern char *acl_var_single_pid_dir; + +#define ACL_VAR_SINGLE_OWNER "single_owner" +#define ACL_DEF_SINGLE_OWNER "single" +extern char *acl_var_single_owner; + +#define ACL_VAR_SINGLE_DELAY_SEC "single_delay_sec" +#define ACL_DEF_SINGLE_DELAY_SEC 1 +extern int acl_var_single_delay_sec; + +#define ACL_VAR_SINGLE_DELAY_USEC "single_delay_usec" +#define ACL_DEF_SINGLE_DELAY_USEC 5000 +extern int acl_var_single_delay_usec; + +/* + * How long a daemon command may take to receive or deliver a message etc. + * before we assume it is wegded (should never happen). + */ +#define ACL_VAR_SINGLE_DAEMON_TIMEOUT "single_daemon_timeout" +#define ACL_DEF_SINGLE_DAEMON_TIMEOUT 1800 +extern int acl_var_single_daemon_timeout; + +/* + * Any subsystem: default maximum number of clients serviced before a mail + * subsystem terminates (except queue manager). + */ +#define ACL_VAR_SINGLE_USE_LIMIT "single_use_limit" +#define ACL_DEF_SINGLE_USE_LIMIT 10 +extern int acl_var_single_use_limit; + +#define ACL_VAR_SINGLE_ENABLE_CORE "single_enable_core" +#define ACL_DEF_SINGLE_ENABLE_CORE 1 +extern int acl_var_single_enable_core; + +#endif /* ACL_UNIX*/ + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/include/master/acl_trigger_params.h b/lib_acl/include/master/acl_trigger_params.h new file mode 100644 index 000000000..9848def0d --- /dev/null +++ b/lib_acl/include/master/acl_trigger_params.h @@ -0,0 +1,71 @@ + +#ifndef __ACL_TRIGGER_PARAMS_INCLUDE_H__ +#define __ACL_TRIGGER_PARAMS_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_define.h" +#ifdef ACL_UNIX + +extern int acl_var_trigger_pid; /* get by call getpid() */ +extern char *acl_var_trigger_procname; /* get from trigger_main()'s argv[0] */ +extern char *acl_var_trigger_log_file; /* get from getenv("LOG") */ + +#define ACL_VAR_TRIGGER_BUF_SIZE "trigger_buf_size" +#define ACL_DEF_TRIGGER_BUF_SIZE 81920 +extern int acl_var_trigger_buf_size; + +#define ACL_VAR_TRIGGER_RW_TIMEOUT "trigger_rw_timeout" +#define ACL_DEF_TRIGGER_RW_TIMEOUT 30 +extern int acl_var_trigger_rw_timeout; + +#define ACL_VAR_TRIGGER_IN_FLOW_DELAY "trigger_in_flow_delay" +#define ACL_DEF_TRIGGER_IN_FLOW_DELAY 1 +extern int acl_var_trigger_in_flow_delay; + +#define ACL_VAR_TRIGGER_IDLE_LIMIT "trigger_idle_limit" +#define ACL_DEF_TRIGGER_IDLE_LIMIT 180 +extern int acl_var_trigger_idle_limit; + +#define ACL_VAR_TRIGGER_QUEUE_DIR "trigger_queue_dir" +#define ACL_DEF_TRIGGER_QUEUE_DIR "/opt/acl_master/var/queue" +extern char *acl_var_trigger_queue_dir; + +#define ACL_VAR_TRIGGER_PID_DIR "trigger_pid_dir" +#define ACL_DEF_TRIGGER_PID_DIR "/opt/acl_master/var/pid" +extern char *acl_var_trigger_pid_dir; + +#define ACL_VAR_TRIGGER_OWNER "trigger_owner" +#define ACL_DEF_TRIGGER_OWNER "trigger" +extern char *acl_var_trigger_owner; + +#define ACL_VAR_TRIGGER_DELAY_SEC "trigger_delay_sec" +#define ACL_DEF_TRIGGER_DELAY_SEC 1 +extern int acl_var_trigger_delay_sec; + +#define ACL_VAR_TRIGGER_DELAY_USEC "trigger_delay_usec" +#define ACL_DEF_TRIGGER_DELAY_USEC 5000 +extern int acl_var_trigger_delay_usec; + +#define ACL_VAR_TRIGGER_DAEMON_TIMEOUT "trigger_daemon_timeout" +#define ACL_DEF_TRIGGER_DAEMON_TIMEOUT 1800 +extern int acl_var_trigger_daemon_timeout; + +#define ACL_VAR_TRIGGER_USE_LIMIT "trigger_use_limit" +#define ACL_DEF_TRIGGER_USE_LIMIT 10 +extern int acl_var_trigger_use_limit; + +#define ACL_VAR_TRIGGER_ENABLE_CORE "trigger_enable_core" +#define ACL_DEF_TRIGGER_ENABLE_CORE 1 +extern int acl_var_trigger_enable_core; + +#endif /* ACL_UNIX */ + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/include/msg/acl_aqueue.h b/lib_acl/include/msg/acl_aqueue.h new file mode 100644 index 000000000..b09f2be3d --- /dev/null +++ b/lib_acl/include/msg/acl_aqueue.h @@ -0,0 +1,92 @@ + +#ifndef __ACL_AQUEUE_INCLUDE_H__ +#define __ACL_AQUEUE_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif +#include "stdlib/acl_define.h" +#include "thread/acl_thread.h" + +#define ACL_AQUEUE_ERR_UNKNOWN -1 +#define ACL_AQUEUE_OK 0 +#define ACL_AQUEUE_ERR_LOCK 1 +#define ACL_AQUEUE_ERR_UNLOCK 2 +#define ACL_AQUEUE_ERR_TIMEOUT 3 +#define ACL_AQUEUE_ERR_COND_WAIT 4 +#define ACL_AQUEUE_ERR_COND_SIGNALE 5 + +typedef struct ACL_AQUEUE_ITEM ACL_AQUEUE_ITEM; +typedef struct ACL_AQUEUE ACL_AQUEUE; + +typedef void (*ACL_AQUEUE_FREE_FN)(void *); +/** + * 产生一个新队列对象句柄 + * @return ACL_AQUEUE 结构指针 + */ +ACL_API ACL_AQUEUE *acl_aqueue_new(void); + +/** + * 设置是否严格检查队列的所有者,默认为否,需要进行该检查的有 acl_aqueue_free + * @param queue ACL_AQUEUE 结构指针 + * @param flag 是与否 + */ +ACL_API void acl_aqueue_check_owner(ACL_AQUEUE *queue, char flag); + +/** + * 设置队列的所有者, 只有所有者才有权释放队列, 即调用 acl_aqueue_free() + * @param queue ACL_AQUEUE 结构指针 + * @param owner 由线程号标识的所有者的ID号 + */ +ACL_API void acl_aqueue_set_owner(ACL_AQUEUE *queue, unsigned int owner); + +/** + * 释放队列对象句柄 + * @param queue ACL_AQUEUE 结构指针 + * @param free_fn 当释放队列时, 如果该函数不为空, 则内部通过此函数将队列中的 + * 用户注册的数据队列进行释放 + */ +ACL_API void acl_aqueue_free(ACL_AQUEUE *queue, ACL_AQUEUE_FREE_FN free_fn); + +/** + * 从队列中提取一个元素, 不带超时, 一直等到有元素可用或出错 + * @param queue ACL_AQUEUE 结构指针 + * @return 用户通过 acl_aqueue_push 加入的元素指针 + */ +ACL_API void *acl_aqueue_pop(ACL_AQUEUE *queue); + +/** + * 从队列中提取一个元素, 带超时, 一直等到有元素可用或超时或出错 + * @param queue ACL_AQUEUE 结构指针 + * @param tmo_sec 从队列中提取元素的超时时间, 单位为秒 + * @param tmo_usec 从队列中提取元素的超时时间, 单位为微秒 + * @return 用户通过 acl_aqueue_push 加入的元素指针 + */ +ACL_API void *acl_aqueue_pop_timedwait(ACL_AQUEUE *queue, int tmo_sec, int tmo_usec); + +/** + * 向队列中添加一个元素 + * @param queue ACL_AQUEUE 结构指针 + * @param data 用户的数据指针 + * @return {int} 添加队列元素是否成功, 0: ok; < 0: error + */ +ACL_API int acl_aqueue_push(ACL_AQUEUE *queue, void *data); + +/** + * 获得上一次队列操作的错误号, define as: ACL_AQUEUE_XXX + * @param queue ACL_AQUEUE 结构指针 + * @return 错误号 + */ +ACL_API int acl_aqueue_last_error(const ACL_AQUEUE *queue); + +/** + * 设置队列为退出状态 + * @param queue ACL_AQUEUE 结构指针 + */ +ACL_API void acl_aqueue_set_quit(ACL_AQUEUE *queue); + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/lib_acl/include/msg/acl_msgio.h b/lib_acl/include/msg/acl_msgio.h new file mode 100644 index 000000000..195fa2577 --- /dev/null +++ b/lib_acl/include/msg/acl_msgio.h @@ -0,0 +1,74 @@ +#ifndef __ACL_MSGIO_INCLUDE_H__ +#define __ACL_MSGIO_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_define.h" +#include "stdlib/acl_vstring.h" +#include "stdlib/acl_ring.h" +#include "aio/acl_aio.h" + +typedef struct ACL_MSGIO ACL_MSGIO; +typedef struct ACL_MSGIO_INFO ACL_MSGIO_INFO; + +typedef int (*ACL_MSGIO_NOTIFY_FN)(int msg_type, ACL_MSGIO *peer, + const ACL_MSGIO_INFO *info, void *arg); + +/** + * 消息类型定义 + */ +#define ACL_MSGIO_OK 0 +#define ACL_MSGIO_TIMEOUT 1 /* 超时消息 */ +#define ACL_MSGIO_EXCEPT 2 /* 异常消息 */ +#define ACL_MSGIO_CONNECT 3 /* 连接成功消息 */ +#define ACL_MSGIO_CONNECT_TIMEOUT 4 /* 连接超时消息 */ +#define ACL_MSGIO_QUIT 5 /* 退出消息 */ +#define ACL_MSGIO_OPEN 6 /* 数据流打开消息 */ + +#define ACL_MSGIO_USER 1000 + +struct ACL_MSGIO_INFO { + struct { + int type; + int dlen; + } hdr; + struct { + ACL_VSTRING *buf; + } body; +}; + +ACL_API void acl_msgio_init(void); +ACL_API void acl_msgio_close(ACL_MSGIO *mio); +ACL_API void acl_msgio_reg(ACL_MSGIO *mio, int id, + ACL_MSGIO_NOTIFY_FN callback, void *arg); +ACL_API void acl_msgio_listen_reg(ACL_MSGIO *mio, int id, + ACL_MSGIO_NOTIFY_FN callback, void *arg, int inherit); +ACL_API void acl_msgio_unreg(ACL_MSGIO *mio, int id, ACL_MSGIO_NOTIFY_FN callback); +ACL_API void acl_msgio_unreg_id(ACL_MSGIO *mio, int id); +ACL_API void acl_msgio_unreg_all(ACL_MSGIO *mio); + +ACL_API int acl_msgio_wait(ACL_MSGIO *mio); +ACL_API ACL_MSGIO *acl_msgio_listen(ACL_AIO *aio, const char *addr); +ACL_API ACL_MSGIO *acl_msgio_accept(ACL_MSGIO *listener); +ACL_API ACL_MSGIO *acl_msgio_connect(ACL_AIO *aio, const char *addr, int timeout); +ACL_API void acl_msgio_set_noblock(ACL_AIO *aio, ACL_MSGIO *mio); + +ACL_API int acl_msgio_send(ACL_MSGIO *mio, int type, void *data, int dlen); +/* void acl_msgio_timer(ACL_MSGIO *mio, ACL_MSGIO_NOTIFY_FN callback, void *arg); */ + +ACL_API void acl_msgio_addr(const ACL_MSGIO *mio, char *buf, size_t size); +ACL_API ACL_AIO *acl_msgio_aio(ACL_MSGIO *mio); +ACL_API ACL_VSTREAM *acl_msgio_vstream(ACL_MSGIO *mio); +ACL_API ACL_ASTREAM *acl_msgio_astream(ACL_MSGIO *mio); + +#define ACL_MSGIO_ON_MSG(id, callback, arg) do { \ + acl_msgio_reg(NULL, id, callback, arg); \ +} while(0) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/include/net/acl_access.h b/lib_acl/include/net/acl_access.h new file mode 100644 index 000000000..cc93ab1c8 --- /dev/null +++ b/lib_acl/include/net/acl_access.h @@ -0,0 +1,52 @@ +#ifndef __ACL_ACCESS_INCLUDE_H__ +#define __ACL_ACCESS_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_stdlib.h" + +/** + * 向访问列表中添加一个允许的 ip 地址段 + * @param data 多个 IP 地址段数据字符串. 如: 10.0.0.1:10.0.250.1, 192.168.0.1:192.168.0.255 + * @param sep1 每个 IP 地址段之间的分隔符, 如上例中的 "," 分隔符 + * @param sep2 每个 IP 地址段高地址与低地址之间的分隔符, 如上例中的 ":" 分隔符 + * @return 添加 结果. 0: 成功; < 0: 失败 + * 注: 该函数是线程不安全的 + */ +ACL_API int acl_access_add(const char *data, const char *sep1, const char *sep2); + +/** + * 从配置文件中读取 IP 地址字符串, 并自动生成 IP 地址访问列表 + * @param xcp 已经成功分析了配置文件的结果句柄 + * @param name xcp 结果句柄中与 IP 地址访问相关的变量名 + * @return 是否添加成功. 0: 成功; < 0: 失败. + * 注: 该函数是线程不安全的 + */ +ACL_API int acl_access_cfg(ACL_XINETD_CFG_PARSER *xcp, const char *name); + +/** + * 用户可以设置自己的日志记录函数, 如果不调用此函数, 则本库自动使用 aclMsg.c中的库. + * @param log_fn 用户自己的日志记录函数. + * 注: 该函数是线程不安全的 + */ +ACL_API void acl_access_setup_logfn(void (*log_fn)(const char *fmt, ...)); + +/** + * 判定给定 IP 地址是否在允许的访问 IP 地址列表中. + * @param ip 格式: 192.168.0.1 + * @return 是否在允许的访问列表中, != 0: 是; == 0: 不是. + */ +ACL_API int acl_access_permit(const char *ip); + +/** + * 将访问地址表表打印出来. + */ +ACL_API void acl_access_debug(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/include/net/acl_connect.h b/lib_acl/include/net/acl_connect.h new file mode 100644 index 000000000..05db585a5 --- /dev/null +++ b/lib_acl/include/net/acl_connect.h @@ -0,0 +1,90 @@ + +#ifndef _ACL_CONNECT_INCLUDE_H__ +#define _ACL_CONNECT_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_define.h" + +#ifdef ACL_UNIX +#include +#include +#include +#endif + +/* in acl_sane_connect.c */ +/** + * 远程连接服务器 + * @param sock {ACL_SOCKET} 套接字,在UNIX平台下还可以是域套接字 + * @param sa {const struct sockaddr*} 服务器监听地址 + * @param len {socklen_t} sa 的地址长度 + * @return {int} 0: 连接成功; -1: 连接失败 + */ +ACL_API int acl_sane_connect(ACL_SOCKET sock, const struct sockaddr * sa, + socklen_t len); + +/* in acl_timed_connect.c */ + +/** + * 带超时时间地远程连接服务器 + * @param fd {ACL_SOCKET} 套接字,在UNIX平台下还可以是域套接字 + * @param sa {const struct sockaddr*} 服务器监听地址 + * @param len {socklen_t} sa 的地址长度 + * @param timeout {int} 连接超时时间 + * @return {int} 0: 连接成功; -1: 连接失败 + */ +ACL_API int acl_timed_connect(ACL_SOCKET fd, const struct sockaddr * sa, + socklen_t len, int timeout); + +/* in acl_inet_connect.c */ + +/** + * 远程连接网络服务器地址 + * @param addr {const char*} 远程服务器的监听地址,如:192.168.0.1:80, 如果需要绑定本地 + * 的地址,则格式为: {local_ip}@{remote_addr}, 如: 60.28.250.199@www.sina.com:80 + * @param block_mode {int} 阻塞模式还是非阻塞模式, ACL_BLOCKING 或 ACL_NON_BLOCKING + * @param timeout {int} 连接超时时间,如果 block_mode 为 ACL_NON_BLOCKING 则该值将被忽略 + * @return {ACL_SOCKET} 如果返回 ACL_SOCKET_INVALID 表示连接失败 + */ +ACL_API ACL_SOCKET acl_inet_connect(const char *addr, int block_mode, int timeout); + +/** + * 远程连接网络服务器地址 + * @param addr {const char*} 远程服务器的监听地址,如:192.168.0.1:80, + * 当本机有多个网卡地址且想通过某个指定网卡连接服务器时的地址格式: + local_ip@remote_ip:remote_port,如:192.168.1.1@211.150.111.12:80 + * @param block_mode {int} 阻塞模式还是非阻塞模式, ACL_BLOCKING 或 ACL_NON_BLOCKING + * @param timeout {int} 连接超时时间,如果 block_mode 为 ACL_NON_BLOCKING 则该值将被忽略 + * @param h_error {int*} 当连接失败时存储失败原因错误号 + * @return {ACL_SOCKET} 如果返回 ACL_SOCKET_INVALID 表示连接失败 + */ +ACL_API ACL_SOCKET acl_inet_connect_ex(const char *addr, int block_mode, + int timeout, int *h_error); + +#ifdef ACL_UNIX + +/* in acl_unix_connect.c */ + +/** + * 连接监听域套接字服务器 + * @param addr {const char*} 服务器监听的域套接字全路径, 如: /tmp/test.sock + * @param block_mode {int} 阻塞模式还是非阻塞模式, ACL_BLOCKING 或 ACL_NON_BLOCKING + * @param timeout {int} 连接超时时间,如果 block_mode 为 ACL_NON_BLOCKING 则该值将被忽略 + * @return {ACL_SOCKET} 如果返回 ACL_SOCKET_INVALID 表示连接失败 + */ +ACL_API ACL_SOCKET acl_unix_connect(const char *addr, int block_mode, int timeout); + +/* in acl_stream_connect.c */ +#ifdef SUNOS5 +ACL_API int acl_stream_connect(const char *path, int block_mode, int unused_timeout); +#endif + +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/include/net/acl_dns.h b/lib_acl/include/net/acl_dns.h new file mode 100644 index 000000000..23d64e31d --- /dev/null +++ b/lib_acl/include/net/acl_dns.h @@ -0,0 +1,180 @@ +#ifndef __ACL_DNS_INCLUDE_H__ +#define __ACL_DNS_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_define.h" +#include "stdlib/acl_htable.h" +#include "stdlib/acl_cache2.h" +#ifdef ACL_UNIX +#include +#include +#endif +#include "aio/acl_aio.h" +#include "acl_netdb.h" + +/* DNS 查询时的错误码定义 */ + +#define ACL_DNS_OK 0 +#define ACL_DNS_OK_CACHE 1 +#define ACL_DNS_ERR_FMT -1 +#define ACL_DNS_ERR_SVR -2 +#define ACL_DNS_ERR_NO_EXIST -3 +#define ACL_DNS_ERR_NO_SUPPORT -4 +#define ACL_DNS_ERR_DENY -5 +#define ACL_DNS_ERR_YX -6 +#define ACL_DNS_ERR_YXRR -7 +#define ACL_DNS_ERR_NXRR -8 +#define ACL_DNS_ERR_NO_AUTH -9 +#define ACL_DNS_ERR_NOT_ZONE -10 +#define ACL_DNS_ERR_UNPACK -15 +#define ACL_DNS_ERR_TIMEOUT -16 +#define ACL_DNS_ERR_EXIST -17 +#define ACL_DNS_ERR_BUILD_REQ -18 + +typedef struct ACL_DNS_ADDR { + char ip[64]; /* DNS 服务器地址 */ + unsigned short port; /* DNS 服务器端口 */ + struct sockaddr_in addr; /* DNS 地址 */ + int addr_len; /* addr 大小 */ + int mask_length; /* DNS 服务器所在网络的掩码长度(> 0 && < 32) */ + struct in_addr in; /* addr 的网段地址 */ +} ACL_DNS_ADDR; + +typedef struct ACL_DNS { + ACL_AIO *aio; /* 异步IO句柄 */ + unsigned short qid; /* 发送请求的ID标识号 */ + ACL_ASTREAM *astream; /* 异步流 */ + + ACL_ARRAY *groups; /* 域名组列表 */ + ACL_ARRAY *dns_list; /* DNS 服务器地址列表 */ + int dns_idx; /* 当前使用的 dns_list 数组下标 */ + ACL_DNS_ADDR addr_from; /* 来源 DNS 地址 */ + ACL_HTABLE *lookup_table; /* 查询对象表 */ + ACL_CACHE2 *dns_cache; /* 用于缓存DNS查询结果 */ + int timeout; /* 每次查询的超时时间值(秒) */ + int retry_limit; /* 查询超时时重试的次数限制 */ + unsigned int flag; /* 标志位 */ +#define ACL_DNS_FLAG_ALLOC (1 << 0) /* 该异步句柄是动态分配的 */ +#define ACL_DNS_FLAG_CHECK_DNS_IP (1 << 1) /* 检查DNS地址是否匹配 */ +#define ACL_DNS_FLAG_CHECK_DNS_NET (1 << 2) /* 检查DNS网络是否匹配 */ + + /* 该函数指针用来避免动态加载库的访问地址不一致问题 */ + void (*lookup_timeout) (int event_type, void *context); +} ACL_DNS; + +typedef struct ACL_DNS_REQ ACL_DNS_REQ; + +/** + * 初始化DNS异步查询对象结构 + * @param dns {ACL_DNS*} DNS异步查询句柄 + * @param aio {ACL_AIO*} 异步句柄 + * @param timeout {int} 每次DNS查询时的超时值 + */ +ACL_API void acl_dns_init(ACL_DNS *dns, ACL_AIO *aio, int timeout); + +/** + * 创建一个DNS异步查询对象并同时进行初始化 + * @param aio {ACL_AIO*} 异步句柄 + * @param timeout {int} 每次DNS查询时的超时值 + * @return {ACL_DNS*} DNS异步查询句柄 + */ +ACL_API ACL_DNS *acl_dns_create(ACL_AIO *aio, int timeout); + +/** + * 打开DNS缓存机制 + * @param dns {ACL_DNS*} DNS异步查询句柄 + * @param limit {int} DNS 缓存中最大缓存条目 + */ +ACL_API void acl_dns_open_cache(ACL_DNS *dns, int limit); + +/** + * 添加一个DNS服务器地址 + * @param dns {ACL_DNS*} DNS异步查询句柄 + * @param dns_ip {const char*} DNS服务器IP地址 + * @param dns_port {unsigned short} DNS服务器端口 + * @param mask_length {int} DNS服务器所在的网段掩码长度(0 < && < 32) + */ +ACL_API void acl_dns_add_dns(ACL_DNS *dns, const char *dns_ip, + unsigned short dns_port, int mask_length); +/** + * 关闭异步查询句柄同时释放所有资源 + * @param dns {ACL_DNS*} DNS异步查询句柄 + */ +ACL_API void acl_dns_close(ACL_DNS *dns); + +/** + * 设置标志位,检查DNS来源IP地址是否与目标地址相同,若不同则丢弃所读的 + * 数据包,主要是为了防止DNS查询时的UDP攻击 + * @param dns {ACL_DNS*} DNS异步查询句柄 + */ +ACL_API void acl_dns_check_dns_ip(ACL_DNS *dns); + +/** + * 设置标志位,检查DNS来源IP所在网段是否与目标网段相同,若不同则丢弃 + * 所读的数据包,主要是为了防止DNS查询时的UDP攻击 + * @param dns {ACL_DNS*} DNS异步查询句柄 + */ +ACL_API void acl_dns_check_dns_net(ACL_DNS *dns); + +/** + * 设置DNS查询超时时重试次数 + * @param dns {ACL_DNS*} DNS异步查询句柄 + * @param retry_limit {int} 重试次数 + */ +ACL_API void acl_dns_set_retry_limit(ACL_DNS *dns, int retry_limit); + +/** + * 异步查询一个域所对应的A记录IP地址集合 + * @param dns {ACL_DNS*} DNS异步查询句柄 + * @param domain {const char*} 域名 + * @param callback {void (*)(ACL_DNS_DB*, void*)} 查询成功或失败的回调函数, + * 若返回给 callback 的 ACL_DNS_DB 为空则表示查询失败, 第二个参数为用户设置 + * 的参数, 第三个参数为查询失败时的错误号 + * @param ctx {void*} callback 的参数之一 + * @return {ACL_DNS_REQ*} 返回本次DNS查询的事件对象, 若为NULL则表示出错 + */ +ACL_API ACL_DNS_REQ *acl_dns_lookup(ACL_DNS *dns, const char *domain, + void (*callback)(ACL_DNS_DB *, void *, int), void *ctx); + +/** + * 向DNS查询对象中添加静态主机信息 + * @param dns {ACL_DNS*} DNS异步查询句柄 + * @param domain {const char*} 域名 + * @param ip_list {const char*} IP地址列表,分隔符为 ';',如: 192.168.0.1;192.168.0.2 + */ +ACL_API void acl_dns_add_host(ACL_DNS *dns, const char *domain, const char *ip_list); + +/** + * 向DNS查询对象中添加查询域名组信息 + * @param dns {ACL_DNS*} DNS异步查询句柄 + * @param group {const char*} 域名组名,如: .test.com, 则 a.test.com, b.test.com + * 都属于 .test.com 域名组 + * @param ip_list {const char*} 如果非空则采用静态方式添加IP地址列表 + * @param refer {const char*} 域名组的代表域名, 将会用此域名代表整个域名组去做DNS查询 + * @param excepts {ACL_ARGV*} 虽然这些域名属于 group 的子域名但却不属于其域名组的 + * 成员集合 + */ +ACL_API void acl_dns_add_group(ACL_DNS *dns, const char *group, const char *refer, + const char *ip_list, const char *excepts); +/** + * 取消某个查询事件对象 + * @param handle {ACL_DNS_REQ*} 某次域名查询事件 + */ +ACL_API void acl_dns_cancel(ACL_DNS_REQ *handle); + +/** + * 根据错误号得到错误描述信息 + * @param errnum {int} DNS查询时返回的错误号 + * @return {const char*} 错误描述信息 + */ +ACL_API const char *acl_dns_serror(int errnum); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/include/net/acl_host_port.h b/lib_acl/include/net/acl_host_port.h new file mode 100644 index 000000000..011fe5284 --- /dev/null +++ b/lib_acl/include/net/acl_host_port.h @@ -0,0 +1,25 @@ +#ifndef __ACL_HOST_PORT_H_INCLUDED__ +#define __ACL_HOST_PORT_H_INCLUDED__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_define.h" + + /* External interface. */ + +/** + * [host]:port, [host]:, [host]. + * or + * host:port, host:, host, :port, port. + */ +ACL_API const char *acl_host_port(char *buf, char **host, char *def_host, + char **port, char *def_service); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/include/net/acl_ifconf.h b/lib_acl/include/net/acl_ifconf.h new file mode 100644 index 000000000..346d2bbde --- /dev/null +++ b/lib_acl/include/net/acl_ifconf.h @@ -0,0 +1,51 @@ +#ifndef __ACL_IFCONF_INCLUDE_H__ +#define __ACL_IFCONF_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_define.h" + +typedef struct ACL_IFADDR { + char *name; /* 接口名称 */ +#ifdef ACL_MS_WINDOWS + char *desc; /* 接口描述 */ +#endif + char ip[32]; /* 以字符串表示的IP地址 */ + unsigned int addr; /* 网络字节序的 32 位 IP 地址 */ +} ACL_IFADDR; + +typedef struct ACL_IFCONF { + ACL_IFADDR *addrs; /* ACL_IFADDR 数组 */ + int length; /* ACL_IFADDR 数组长度 */ + + /* for acl_iterator */ + + /* 取迭代器头函数 */ + const ACL_IFADDR *(*iter_head)(ACL_ITER*, struct ACL_IFCONF*); + /* 取迭代器下一个函数 */ + const ACL_IFADDR *(*iter_next)(ACL_ITER*, struct ACL_IFCONF*); + /* 取迭代器尾函数 */ + const ACL_IFADDR *(*iter_tail)(ACL_ITER*, struct ACL_IFCONF*); + /* 取迭代器上一个函数 */ + const ACL_IFADDR *(*iter_prev)(ACL_ITER*, struct ACL_IFCONF*); +} ACL_IFCONF; + +/** + * 获得主机的所有网络地址及网络接口名称 + * @return {ACL_IFCONF*} + */ +ACL_API ACL_IFCONF *acl_get_ifaddrs(void); + +/** + * 释放由 acl_get_ifaddrs() 返回的 ACL_IFCONF 内存 + * @param ifconf {ACL_IFCONF*} + */ +ACL_API void acl_free_ifaddrs(ACL_IFCONF *ifconf); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/include/net/acl_listen.h b/lib_acl/include/net/acl_listen.h new file mode 100644 index 000000000..ad3847fbd --- /dev/null +++ b/lib_acl/include/net/acl_listen.h @@ -0,0 +1,88 @@ +#ifndef __ACL_LISTEN_INCLUDE_H__ +#define __ACL_LISTEN_INCLUDE_H__ +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_define.h" +#ifdef ACL_UNIX +#include +#endif + +/** + * 监听套接字接收外来客户端连接 + * @param sock {ACL_SOCKET} 监听套接字 + * @param sa {struct sockaddr*} 存储客户端的网络地址,不能为空 + * @param len {socklen_t*} sa 内存空间大小,不能为空 + * @return {ACL_SOCKET} 如果返回 ACL_SOCKET_INVALID 表示接收失败 + */ +ACL_API ACL_SOCKET acl_sane_accept(ACL_SOCKET sock, struct sockaddr * sa, socklen_t *len); + +/** + * 方便通用的监听套接字的函数,用来接收客户端连接 + * @param sock {ACL_SOCKET} 监听套接字 + * @param buf {char*} 当成功接收一个客户端连接后,如果该 buf 非空则存放客户端地址,格式: + * ip:port (针对 TCP 套接口), file_path (针对 UNIX 域套接口) + * @param size {size_t} buf 缓冲区大小 + * @param sock_type {int*} 该指针非空时,用来存放客户端连接的 SOCKET 类型,AF_INET/AF_UNIX + * @return {ACL_SOCKET} 客户端连接句柄, 返回值 != ACL_SOCKET_INVALID 则表明成功收到一个客户端连接 + */ +ACL_API ACL_SOCKET acl_accept(ACL_SOCKET sock, char *buf, size_t size, int* sock_type); + +/* in acl_inet_listen.c */ + +/** + * 监听某个网络地址 + * @param addr {const char*} 网络地址, 格式如:127.0.0.1:8080 + * @param backlog {int} 监听套接字系统接收区的队列大小 + * @param block_mode {int} 阻塞模式还是非阻塞模式, ACL_BLOCKING 或 ACL_NON_BLOCKING + * @return {ACL_SOCKET} 返回监听套接字,如果为 ACL_SOCKET_INVALID 表示无法监听该网络地址 + */ +ACL_API ACL_SOCKET acl_inet_listen(const char *addr, int backlog, int block_mode); + +/** + * 接收外来客户端网络连接 + * @param listen_fd {ACL_SOCKET} 监听套接字 + * @return {ACL_SOCKET} 客户端连接,如果返回 ACL_SOCKET_INVALID 表示接收客户端连接出错 + */ +ACL_API ACL_SOCKET acl_inet_accept(ACL_SOCKET listen_fd); + +/** + * 接收外来客户端网络连接 + * @param listen_fd {ACL_SOCKET} 监听套接字 + * @param ipbuf {char*} 如果该指针不为空且接收客户端连接成功,则其存储客户端的网络地址 + * @param size {size_t} 如果 ipbuf 不为空则表示 ipbuf 的内存空间大小 + * @return {ACL_SOCKET} 客户端连接,如果返回 ACL_SOCKET_INVALID 表示接收客户端连接出错 + */ +ACL_API ACL_SOCKET acl_inet_accept_ex(ACL_SOCKET listen_fd, char *ipbuf, size_t size); + +#ifdef ACL_UNIX + +/* in acl_unix_listen.c */ +/** + * 监听域套接字 + * @param addr {const char*} 监听域套接字时所用的全路径 + * @param backlog {int} 监听队列大小 + * @param block_mode {int} 阻塞模式还是非阻塞模式, ACL_BLOCKING 或 ACL_NON_BLOCKING + * @return {ACL_SOCKET} 返回监听套接字,如果为 ACL_SOCKET_INVALID 表示无法监听该网络地址 + */ +ACL_API ACL_SOCKET acl_unix_listen(const char *addr, int backlog, int block_mode); + +/** + * 从域套接字上接收一个客户端连接 + * @param listen_fd {ACL_SOCKET} 监听套接字 + * @return {ACL_SOCKET} 客户端连接,如果返回 ACL_SOCKET_INVALID 表示接收客户端连接出错 + */ +ACL_API ACL_SOCKET acl_unix_accept(ACL_SOCKET fd); + +/* in acl_fifo_listen.c */ + +ACL_API int acl_fifo_listen(const char *path, int permissions, int block_mode); + +#endif + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/lib_acl/include/net/acl_mask_addr.h b/lib_acl/include/net/acl_mask_addr.h new file mode 100644 index 000000000..1da428bea --- /dev/null +++ b/lib_acl/include/net/acl_mask_addr.h @@ -0,0 +1,25 @@ +#ifndef __ACL_MASK_ADDR_H_INCLUDED__ +#define __ACL_MASK_ADDR_H_INCLUDED__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_define.h" + +/** + * 给定网络掩码长度及IP地址,获得其网络地址 + * @param addr_bytes {unsigned char*} 给定的网络字节序 IP 地址, + * (可以为IPv4/IPv6), 该参数为值参型,结果存于该地址中 + * @param addr_type_count {unsigned} addr_bytes 地址长度 + * @param network_bits {unsigned} 网络掩码的长度 + */ +ACL_API void acl_mask_addr(unsigned char *addr_bytes, + unsigned addr_byte_count, unsigned network_bits); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/include/net/acl_net.h b/lib_acl/include/net/acl_net.h new file mode 100644 index 000000000..2b420a7e9 --- /dev/null +++ b/lib_acl/include/net/acl_net.h @@ -0,0 +1,29 @@ + +#ifndef __ACL_NET_INCLUDE_H__ +#define __ACL_NET_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "acl_connect.h" +#include "acl_netdb.h" +#include "acl_sane_socket.h" +#include "acl_sane_inet.h" +#include "acl_tcp_ctl.h" +#include "acl_listen.h" +#include "acl_vstream_net.h" +#include "acl_res.h" +#include "acl_dns.h" +#include "acl_access.h" +#include "acl_mask_addr.h" +#include "acl_valid_hostname.h" +#include "acl_host_port.h" +#include "acl_ifconf.h" + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/include/net/acl_netdb.h b/lib_acl/include/net/acl_netdb.h new file mode 100644 index 000000000..3083b2262 --- /dev/null +++ b/lib_acl/include/net/acl_netdb.h @@ -0,0 +1,183 @@ + +#ifndef __ACL_NETDB_INCLUDE_H__ +#define __ACL_NETDB_INCLUDE_H__ + +#include "stdlib/acl_define.h" + +#ifdef ACL_UNIX +#include +#endif + +#include "stdlib/acl_array.h" + +/** + * 主机地址结构 + */ +typedef struct ACL_HOSTNAME ACL_HOST_INFO; +typedef struct ACL_HOSTNAME { + char ip[64]; /**< the ip addr of the HOST */ + struct sockaddr_in saddr; /**< ip addr in sockaddr_in */ + unsigned int ttl; /**< the HOST's ip timeout(second) */ + int hport; + unsigned int nrefer; /**< refer number to this HOST */ +} ACL_HOSTNAME; + +/** + * DNS查询结果集 + */ +typedef struct ACL_DNS_DB { + ACL_ARRAY *h_db; + int size; + char name[256]; + + /* for acl_iterator */ + + /* 取迭代器头函数 */ + const ACL_HOST_INFO *(*iter_head)(ACL_ITER*, struct ACL_DNS_DB*); + /* 取迭代器下一个函数 */ + const ACL_HOST_INFO *(*iter_next)(ACL_ITER*, struct ACL_DNS_DB*); + /* 取迭代器尾函数 */ + const ACL_HOST_INFO *(*iter_tail)(ACL_ITER*, struct ACL_DNS_DB*); + /* 取迭代器上一个函数 */ + const ACL_HOST_INFO *(*iter_prev)(ACL_ITER*, struct ACL_DNS_DB*); + /* 取迭代器关联的当前容器成员结构对象 */ + const ACL_HOST_INFO *(*iter_info)(ACL_ITER*, struct ACL_DNS_DB*); +} ACL_DNS_DB; + +/* in acl_netdb.c */ + +/** + * 从结果集中取得某个下标位置的主机地址结构 + * @param h_dns_db {const ACL_DNS_DB*} DNS结果集 + * @param i {int} 下标位置 + * @return {const ACL_HOSTNAME*} 返回相应下标的主机地址结构 + */ +ACL_API const ACL_HOSTNAME *acl_netdb_index(const ACL_DNS_DB *h_dns_db, int i); + +/** + * 从结果集中取得某个下标位置的主机IP地址 + * @param h_dns_db {const ACL_DNS_DB*} DNS结果集 + * @param i {int} 下标位置 + * @return {const struct sockaddr_in*} IP地址结构, NULL表示失败 + */ +ACL_API const struct sockaddr_in *acl_netdb_index_saddr(ACL_DNS_DB *h_dns_db, int i); + +/** + * 将结果集中的对应某个下标的主机地址引用增加 + * @param h_dns_db {const ACL_DNS_DB*} DNS结果集 + * @param i {int} 下标位置 + * @param n {int} 需要增加的引用值 + */ +ACL_API void acl_netdb_refer_oper(ACL_DNS_DB *h_dns_db, int i, int n); + +/** + * 将结果集中的对应某个下标的主机地址引用加1 + * @param h_dns_db {const ACL_DNS_DB*} DNS结果集 + * @param i {int} 下标位置 + */ +ACL_API void acl_netdb_refer(ACL_DNS_DB *h_dns_db, int i); + +/** + * 将结果集中的对应某个下标的主机地址引用减1 + * @param h_dns_db {const ACL_DNS_DB*} DNS结果集 + * @param i {int} 下标位置 + */ +ACL_API void acl_netdb_unrefer(ACL_DNS_DB *h_dns_db, int i); + +/** + * 将结果集中的对应某个下标的IP地址,以字符串表示 + * @param h_dns_db {const ACL_DNS_DB*} DNS结果集 + * @param i {int} 下标位置 + * @return {const char*} 查得的结果,NULL 表示失败 + */ +ACL_API const char *acl_netdb_index_ip(const ACL_DNS_DB *h_dns_db, int i); + +/** + * 取得结果集中主机地址的个数 + * @param h_dns_db {const ACL_DNS_DB*} DNS结果集 + * @return {int} 主机地址个数 > 0, -1 表示参数输入有误 + */ +ACL_API int acl_netdb_size(const ACL_DNS_DB *h_dns_db); + +/** + * 释放结果集内存资源 + * @param h_dns_db {ACL_DNS_DB*} DNS结果集 + */ +ACL_API void acl_netdb_free(ACL_DNS_DB *h_dns_db); + +/** + * 根据域名创建一个查询结果集的结构,但并不进行DNS查询 + * @param domain {const char*} 要查询的域名 + * @return {ACL_DNS_DB*} 创建的结果集对象 + */ +ACL_API ACL_DNS_DB *acl_netdb_new(const char *domain); + +/** + * 向结果集中添加IP地址 + * @param h_dns_db {ACL_DNS_DB*} 查询结果集对象 + * @param ip {const char*} 要添加的IP地址 + */ +ACL_API void acl_netdb_addip(ACL_DNS_DB *h_dns_db, const char *ip); + +/** + * 向结果集中添加IP地址及端口号 + * @param h_dns_db {ACL_DNS_DB*} 查询结果集对象 + * @param ip {const char*} 要添加的IP地址 + * @param port {int} 要添加的端口号 + */ +ACL_API void acl_netdb_add_addr(ACL_DNS_DB *h_dns_db, const char *ip, int port); + +/** + * 克隆一个查询结果集对象 + * @param h_dns_db {const ACL_DNS_DB*} 源结果集对象 + * @return {ACL_DNS_DB*} 新克隆的结果集对象 + */ +ACL_API ACL_DNS_DB *acl_netdb_clone(const ACL_DNS_DB *h_dns_db); + +/** + * 查询某个域名的IP地址集 + * @param name {const char*} 域名 + * @param h_error {int*} 如果查询失败存储出错原因 + * @return {ACL_DNS_DB*} 查询结果集, 如果为NULL则查询失败, 另外,即使返回不为空, + * 也得需要通过 acl_netdb_size()/1 获得结果集的数组长度 + */ +ACL_API ACL_DNS_DB *acl_gethostbyname(const char *name, int *h_error); + +/** + * 根据错误号获得出错提示信息 + * @param errnum {int} 错误号 + * @return {const char*} 出错信息 + */ +ACL_API const char *acl_netdb_strerror(int errnum); + +/* in acl_netdb_cache.c */ +/** + * 向DNS缓存中添加缓存数据 + * @param h_dns_db {const ACL_DNS_DB*} DNS查询结果集 + * @param timeout {int} 该结果集被缓存的超时时间,如果 <= 0, 则采用默认的值, + * 该默认值是在 acl_netdb_cache_init()/2 中的设置值, 单位为秒 + */ +ACL_API void acl_netdb_cache_push(const ACL_DNS_DB *h_dns_db, int timeout); + +/** + * 从DNS缓存中取得DNS查询结果集 + * @param name {const char*} 域名 + * @return {ACL_DNS_DB*} DNS查询结果集 + */ +ACL_API ACL_DNS_DB *acl_netdb_cache_lookup(const char *name); + +/** + * 从DNS缓存中删除某个DNS查询结果集 + * @param name {const char*} 域名 + */ +ACL_API void acl_netdb_cache_del_host(const char *name); + +/** + * 初始化DNS缓存区 + * @param timeout {int} DNS结果集的默认缓存时间(秒) + * @param thread_safe {int} 是否需要DNS缓存区线程安全, 0: 表示不需要, + * 1: 表示需要线程安全 + */ +ACL_API void acl_netdb_cache_init(int timeout, int thread_safe); + +#endif diff --git a/lib_acl/include/net/acl_res.h b/lib_acl/include/net/acl_res.h new file mode 100644 index 000000000..2c941ba44 --- /dev/null +++ b/lib_acl/include/net/acl_res.h @@ -0,0 +1,76 @@ +#ifndef __ACL_RES_INCLUDE_H__ +#define __ACL_RES_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_define.h" +#include "acl_netdb.h" +#include + +/** + * DNS返回结果的存储结构 + */ +typedef struct ACL_RES { + char dns_ip[64]; /**< DNS的IP地址 */ + unsigned short dns_port; /**< DNS的Port */ + unsigned short cur_qid; /**< 内部变量,数据包的标识 */ + time_t tm_spent; /**< 查询时间耗费(秒) */ + int errnum; +#define ACL_RES_ERR_SEND -100 /**< 写出错 */ +#define ACL_RES_ERR_READ -101 /**< 读出错 */ +#define ACL_RES_ERR_RTMO -102 /**< 读超时 */ +#define ACL_RES_ERR_NULL -103 /**< 空结果 */ +#define ACL_RES_ERR_CONN -104 /**< TCP方式时连接失败 */ + + int transfer; /**< TCP/UDP 传输模式 */ +#define ACL_RES_USE_UDP 0 /**< UDP 传输模式 */ +#define ACL_RES_USE_TCP 1 /**< TCP 传输模式 */ + + int conn_timeout; /**< TCP 传输时的连接超时时间, 默认为10秒 */ + int rw_timeout; /**< TCP/UDP 传输的IO超时时间, 默认为10秒 */ +} ACL_RES; + +/** + * 创建一个DNS查询对象 + * @param dns_ip {const char*} DNS的IP地址 + * @param dns_port {unsigned short} DNS的Port + * @return {ACL_RES*} 新创建的查询对象 + */ +ACL_API ACL_RES *acl_res_new(const char *dns_ip, unsigned short dns_port); + +/** + * 释放一个DNS查询对象 + * @param res {ACL_RES*} DNS查询对象 + */ +ACL_API void acl_res_free(ACL_RES *res); + +/** + * 查询某个域名的IP地址 + * @param res {ACL_RES*} DNS查询对象 + * @param domain {const char*} 要查询的域名 + * @return {ACL_DNS_DB*} 查询的结果集 + */ +ACL_API ACL_DNS_DB *acl_res_lookup(ACL_RES *res, const char *domain); + +/** + * 根据错误号获得查询失败的原因 + * @param errnum {int} 错误号 + * @return {const char*} 错误信息 + */ +ACL_API const char *acl_res_strerror(int errnum); + +/** + * 获得当前查询的错误信息 + * @param res {ACL_RES*} DNS查询对象 + * @return {const char*} 错误信息 + */ +ACL_API const char *acl_res_errmsg(const ACL_RES *res); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/include/net/acl_sane_inet.h b/lib_acl/include/net/acl_sane_inet.h new file mode 100644 index 000000000..ec0ea5408 --- /dev/null +++ b/lib_acl/include/net/acl_sane_inet.h @@ -0,0 +1,58 @@ + +#ifndef __ACL_SANE_INET_INCLUDE_H__ +#define __ACL_SANE_INET_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_define.h" +#ifdef ACL_UNIX +#include +#endif + +/** + * 将IP地址转换成字符串格式 + * @param src {const unsigned char*} struct in_addr in.s_addr 的连续内存表示 + * @param dst {char *} 存储转换结果 + * @param size {size_t} dst 的空间大小 + * @return {const char*} NULL: error; !NULL: ok + */ +ACL_API const char *acl_inet_ntop4(const unsigned char *src, char *dst, size_t size); + +/** + * 将IP地址转换成字符串格式 + * @param in {struct in_addr} + * @param dst {char *} 存储转换结果 + * @param size {size_t} dst 的空间大小 + * @return {const char*} NULL: error; !NULL: ok + */ +ACL_API const char *acl_inet_ntoa(struct in_addr in, char *dst, size_t size); + +/** + * 判断给定的字符串是否是正确的 ip 地址 + * @param ip {const char *ip} + * @return {int} 0: 是; -1: 否 + */ +ACL_API int acl_is_ip(const char *ip); + +/** + * 判断所给的 ip 地址是否符合 xxx.xxx.xxx.xxx 格式 + * @param addr {const char*} IP 地址 + * @return {int} 1: 符合, 0: 不符合 + */ +ACL_API int acl_ipv4_valid(const char *addr); + +/** + * 判断所给的 ip 地址是否符合 xxx.xxx.xxx.xxx:port 格式 + * @param addr {const char*} IP:PORT 地址 + * @return {int} 1: 符合, 0: 不符合 + */ +ACL_API int acl_ipv4_addr_valid(const char *addr); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/include/net/acl_sane_socket.h b/lib_acl/include/net/acl_sane_socket.h new file mode 100644 index 000000000..a10180009 --- /dev/null +++ b/lib_acl/include/net/acl_sane_socket.h @@ -0,0 +1,48 @@ +/* + * Name: acl_sane_socket.h + * Author: zsx + * Date: 2003-12-18 + * Version: 1.0 + */ + +#ifndef __ACL_SANE_SOCKET_INCLUDE_H__ +#define __ACL_SANE_SOCKET_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_define.h" + +/** + * 取得套接字连接对方的网络地址, 地址格式为: IP:PORT + * @param sockfd {ACL_SOCKET} 网络套接字 + * @param buf {char*} 存储地址的缓冲区,不能为空 + * @param bsize {size_t} buf 空间大小 + * @return {int} 0: ok; -1: error + */ +ACL_API int acl_getpeername(ACL_SOCKET sockfd, char *buf, size_t bsize); + +/** + * 取得套接字连接本地的网络地址, 地址格式为: IP:PORT + * @param sockfd {ACL_SOCKET} 网络套接字 + * @param buf {char*} 存储地址的缓冲区,不能为空 + * @param bsize {size_t} buf 空间大小 + * @return {int} 0: ok; -1: error + */ +ACL_API int acl_getsockname(ACL_SOCKET sockfd, char *buf, size_t bsize); + +/** + * 取得套接字的类型 + * @param sockfd {ACL_SOCKET} 网络套接字 + * @return {int} -1: 表示出错或输入非法或非套接字; >= 0 表示成功获得套接字 + * 类型,返回值有 AF_INET 或 AF_UNIX(仅限 UNIX 平台) + */ +ACL_API int acl_getsocktype(ACL_SOCKET sockfd); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/include/net/acl_tcp_ctl.h b/lib_acl/include/net/acl_tcp_ctl.h new file mode 100644 index 000000000..a676f448c --- /dev/null +++ b/lib_acl/include/net/acl_tcp_ctl.h @@ -0,0 +1,76 @@ +#ifndef __ACL_TCP_CTL_INCLUDE_H__ +#define __ACL_TCP_CTL_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_define.h" + +#define ACL_SOCKET_RBUF_SIZE 204800 /**< 缺省读缓冲区大小 */ +#define ACL_SOCKET_WBUF_SIZE 204800 /**< 缺少写缓冲区大小 */ + +/** + * 设置套接字的读缓冲区大小 + * @param fd {ACL_SOCKET} 套接字 + * @param size {int} 缓冲区设置大小 + */ +ACL_API void acl_tcp_set_rcvbuf(ACL_SOCKET fd, int size); + +/** + * 设置套接字的写缓冲区大小 + * @param fd {ACL_SOCKET} 套接字 + * @param size {int} 缓冲区设置大小 + */ +ACL_API void acl_tcp_set_sndbuf(ACL_SOCKET fd, int size); + +/** + * 获取套接字的读缓冲区大小 + * @param fd {ACL_SOCKET} 套接字 + * @return {int} 缓冲区大小 + */ +ACL_API int acl_tcp_get_rcvbuf(ACL_SOCKET fd); + +/** + * 获取套接字的写缓冲区大小 + * @param fd {ACL_SOCKET} 套接字 + * @return {int} 缓冲区大小 + */ +ACL_API int acl_tcp_get_sndbuf(ACL_SOCKET fd); + +/** + * 打开套接字的 nodelay 功能 + * @param fd {ACL_SOCKET} 套接字 + */ +ACL_API void acl_tcp_set_nodelay(ACL_SOCKET fd); + +/** + * 设置套接字的 nodelay 功能 + * @param fd {ACL_SOCKET} 套接字 + * @param onoff {int} 1 表示打开,0 表示关闭 + */ +ACL_API void acl_tcp_nodelay(ACL_SOCKET fd, int onoff); + +/** + * 设置监听套接字的延迟接收功能,即当客户端连接上有数据时才将该连接返回 + * 给应用,目前该功能仅支持 Linux + * @param fd {ACL_SOCKET} 套接字 + * @param timeout {int} 如果客户端连接在规定的时间内未发来数据,也将该连接返回 + * 给应用 + */ +ACL_API void acl_tcp_defer_accept(ACL_SOCKET fd, int timeout); + +/** + * 设置套接字的 SO_LINGER 选项 + * @param fd {ACL_SOCKET} 套接字 + * @param onoff {int} 是否启用 SO_LINGER 选项 + * @param timeout {int} 当SO_LINGER打开时,取消 timed_wait 的时间,单位为秒 + */ +ACL_API void acl_tcp_so_linger(ACL_SOCKET fd, int onoff, int timeout); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/include/net/acl_valid_hostname.h b/lib_acl/include/net/acl_valid_hostname.h new file mode 100644 index 000000000..8aabee377 --- /dev/null +++ b/lib_acl/include/net/acl_valid_hostname.h @@ -0,0 +1,27 @@ +#ifndef __ACL_VALID_HOSTNAME_H_INCLUDED__ +#define __ACL_VALID_HOSTNAME_H_INCLUDED__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_define.h" + /* External interface */ + +#define ACL_VALID_HOSTNAME_LEN 255 /* RFC 1035 */ +#define ACL_VALID_LABEL_LEN 63 /* RFC 1035 */ + +#define ACL_DONT_GRIPE 0 +#define ACL_DO_GRIPE 1 + +ACL_API int acl_valid_hostname(const char *, int); +ACL_API int acl_valid_hostaddr(const char *, int); +ACL_API int acl_valid_ipv4_hostaddr(const char *, int); +ACL_API int acl_valid_ipv6_hostaddr(const char *, int); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/include/net/acl_vstream_net.h b/lib_acl/include/net/acl_vstream_net.h new file mode 100644 index 000000000..de0024a86 --- /dev/null +++ b/lib_acl/include/net/acl_vstream_net.h @@ -0,0 +1,89 @@ +#ifndef __ACL_VSTREAM_NET_INCLUDE_H__ +#define __ACL_VSTREAM_NET_INCLUDE_H__ +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_define.h" +#include "stdlib/acl_vstream.h" + +/** + * 监听某个地址(对于UNIX,还可以监听域套接字) + * @param addr {const char*} 监听地址, + * 如:127.0.0.1:80; 或域套接字(UNIX平台) 如:/tmp/test.sock + * @param qlen {int} 监听队列的长度 + * @param block_mode {int} 是阻塞监听还是非阻塞监听, ACL_BLOCKING: 阻塞模式, + * ACL_NON_BLOCKING: 非阻塞模式 + * @param bufsize {int} 接收的新的客户端套接字的IO缓冲区大小 + * @param rw_timeout {int} 接收的新的客户端套接字的IO读写超时时间,单位为秒 + * @return {ACL_VSTREAM*} 监听流指针 + */ +ACL_API ACL_VSTREAM *acl_vstream_listen_ex(const char *addr, int qlen, + int block_mode, int io_bufsize, int rw_timeout); + +/** + * 监听某个地址(对于UNIX,还可以监听域套接字) + * @param addr {const char*} 监听地址 + * 如:127.0.0.1:80, 或域套接字, 如:/tmp/test.sock + * @param qlen {int} 监听队列的长度 + * @return {ACL_VSTREAM*} 监听流指针 + */ +ACL_API ACL_VSTREAM *acl_vstream_listen(const char *addr, int qlen); + +/** + * 从监听流中接收一个客户端连接流 + * @param listen_stream {ACL_VSTREAM*} 监听流 + * @param client_stream {ACL_VSTREAM*} 可重复利用的 ACL_VSTREAM 结构, + * 如果为空则内部产生一个新的 ACL_VSTREAM 流,否则复用该结构空间 + * @param ipbuf {char*} 如果不为空则用来存储客户端的IP地址 + * @param bsize {int} 如果 ipbuf 不为空,则表示 ipbuf 的空间大小 + * @return {ACL_VSTREAM*} 如果不为空则表示新接收的客户端流 + */ +ACL_API ACL_VSTREAM *acl_vstream_accept_ex(ACL_VSTREAM *listen_stream, + ACL_VSTREAM *client_stream, char *ipbuf, int bsize); + +/** + * 从监听流中接收一个客户端连接流 + * @param listen_stream {ACL_VSTREAM*} 监听流 + * @param ipbuf {char*} 如果不为空则用来存储客户端的IP地址 + * @param bsize {int} 如果 ipbuf 不为空,则表示 ipbuf 的空间大小 + * @return {ACL_VSTREAM*} 如果不为空则表示新接收的客户端流 + */ +ACL_API ACL_VSTREAM *acl_vstream_accept(ACL_VSTREAM *listen_stream, + char *ipbuf, int bsize); + +/** + * 远程连接服务器 + * @param addr {const char*} 服务器地址, 如果连接一个域套接口服务器(仅UNIX平台), + * 域套接地址:/tmp/test.sock; 如果连接一个TCP服务器,则地址格式为: + * [${local_ip}@]${remote_addr}, 如: 60.28.250.199@www.sina.com:80, 意思是绑定本的 + * 网卡地址为: 60.28.250.199, 远程连接 www.sina.com 的 80 端口, 如果由OS自动绑定本地 + * IP 地址,则可以写为:www.sina.com:80 + * @param block_mode {int} 阻塞连接还是非阻塞连接,ACL_BLOCKING, ACL_NON_BLOCKING + * @param conn_timeout {int} 连接超时时间(秒) + * @param rw_timeout {int} 连接流成功后的读写超时时间,单位为秒 + * @param bufsize {int} 连接流成功后的缓冲区大小 + * @param errorp {int*} 如果不为空,则存储连接失败后的错误号 + * @return {ACL_VSTREAM*} 如果不为空,则表示连接成功后的数据流 + */ +ACL_API ACL_VSTREAM *acl_vstream_connect_ex(const char *addr, int block_mode, + int conn_timeout, int rw_timeout, int bufsize, int *errorp); + +/** + * 远程连接服务器 + * @param addr {const char*} 服务器地址,格式如:127.0.0.1, + * 或 域套接地址:/tmp/test.sock + * @param block_mode {int} 阻塞连接还是非阻塞连接,ACL_BLOCKING, ACL_NON_BLOCKING + * @param connect_timeout {int} 连接超时时间(秒) + * @param rw_timeout {int} 连接流成功后的读写超时时间,单位为秒 + * @param rw_bufsize {int} 连接流成功后的缓冲区大小 + * @return {ACL_VSTREAM*} 如果不为空,则表示连接成功后的数据流 + */ +ACL_API ACL_VSTREAM *acl_vstream_connect(const char *addr, int block_mode, + int connect_timeout, int rw_timeout, int rw_bufsize); + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/lib_acl/include/proctl/acl_proctl.h b/lib_acl/include/proctl/acl_proctl.h new file mode 100644 index 000000000..69357487f --- /dev/null +++ b/lib_acl/include/proctl/acl_proctl.h @@ -0,0 +1,98 @@ +#ifndef __ACL_PROCTL_INCLUDE_H__ +#define __ACL_PROCTL_INCLUDE_H__ + +#include "stdlib/acl_define.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * 获取控制进程的执行程序所在的路径位置 + * @param buf {char*} 存储结果的内存位置, 返回的结果的结尾 + * 不包含 "\" 或 "/", 如:"C:\\test_path\\test1_path", 而不是 + * "C:\\test_path\\test1_path\\" + * @param size {size_t} buf 的空间大小 + */ +ACL_API void acl_proctl_daemon_path(char *buf, size_t size); + +/** + * 初始化进程控制框架(仅 acl_proctl_start 需要) + * @param progname {const char*} 控制进程进程名 + */ +ACL_API void acl_proctl_deamon_init(const char *progname); + +/** + * 控制进程作为后台服务进程运行,监视所有子进程的运行状态, + * 如果子进程异常退出则会重启该子进程 + */ +ACL_API void acl_proctl_daemon_loop(void); + +/** + * 在控制进程启动后,启动一个子进程 + * @param progchild {const char*} 子进程的程序名 + * @param argc {int} argv 数组的长度 + * @param argv {char* []} + * @return 0: ok; -1: error + */ +ACL_API int acl_proctl_deamon_start_one(const char *progchild, int argc, char *argv[]); + +/** + * 以命令方式启动某个子进程 + * @param progname {const char*} 控制进程进程名 + * @param progchild {const char*} 子进程进程名 + * @param argc {int} argv 数组的长度 + * @param argv {char* []} 传递给子进程的参数 + */ +ACL_API void acl_proctl_start_one(const char *progname, + const char *progchild, int argc, char *argv[]); + +/** + * 以命令方式停止某个子进程 + * @param progname {const char*} 控制进程进程名 + * @param progchild {const char*} 子进程进程名 + * @param argc {int} argv 数组的长度 + * @param argv {char* []} 传递给子进程的参数 + */ +ACL_API void acl_proctl_stop_one(const char *progname, + const char *progchild, int argc, char *argv[]); + +/** + * 以命令方式停止所有的子进程 + * @param progname {const char*} 控制进程进程名 + */ +ACL_API void acl_proctl_stop_all(const char *progname); + +/** + * 以命令方式通知控制进程停止所有的子进程,并在子进程退出后控制进程也自动退出 + * @param progname {const char*} 控制进程进程名 + */ +ACL_API void acl_proctl_quit(const char *progname); + +/** + * 列出当前所有正在运行的服务进程 + * @param progname {const char*} 控制进程进程名 + */ +ACL_API void acl_proctl_list(const char *progname); + +/** + * 探测某个服务进程是否在运行 + * @param progname {const char*} 控制进程进程名 + * @param progchild {const char*} 子进程进程名 + */ +ACL_API void acl_proctl_probe(const char *progname, const char *progchild); + +/** + * 子进程调用接口,通过此接口与父进程之间建立控制/被控制关系 + * @param progname {const char*} 子进程进程名 + * @param onexit_fn {void (*)(void*)} 如果非空则当子进程退出时调用的回调函数 + * @param arg {void*} onexit_fn 参数之一 + */ +ACL_API void acl_proctl_child(const char *progname, void (*onexit_fn)(void *), void *arg); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/include/stdlib/acl_allocator.h b/lib_acl/include/stdlib/acl_allocator.h new file mode 100644 index 000000000..9eeb9f5d6 --- /dev/null +++ b/lib_acl/include/stdlib/acl_allocator.h @@ -0,0 +1,189 @@ +#ifndef __ACL_ALLOCATOR_INCLUDE_H__ +#define __ACL_ALLOCATOR_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef ACL_PREPARE_COMPILE +#include "acl_define.h" +#include +#endif + +typedef enum { + ACL_MEM_TYPE_NONE, + ACL_MEM_TYPE_8_BUF, + ACL_MEM_TYPE_16_BUF, + ACL_MEM_TYPE_32_BUF, + ACL_MEM_TYPE_64_BUF, + ACL_MEM_TYPE_128_BUF, + ACL_MEM_TYPE_256_BUF, + ACL_MEM_TYPE_512_BUF, + ACL_MEM_TYPE_1K_BUF, + ACL_MEM_TYPE_2K_BUF, + ACL_MEM_TYPE_4K_BUF, + ACL_MEM_TYPE_8K_BUF, + ACL_MEM_TYPE_16K_BUF, + ACL_MEM_TYPE_32K_BUF, + ACL_MEM_TYPE_64K_BUF, + ACL_MEM_TYPE_128K_BUF, + ACL_MEM_TYPE_256K_BUF, + ACL_MEM_TYPE_512K_BUF, + ACL_MEM_TYPE_1M_BUF, + ACL_MEM_TYPE_VSTRING, + ACL_MEM_TYPE_MAX +} acl_mem_type; + +typedef struct ACL_MEM_POOL ACL_MEM_POOL; +typedef struct ACL_ALLOCATOR ACL_ALLOCATOR; + +/* in acl_mpool.c */ +/** + * 创建一个内存分配池对象 + * @param mem_limit {size_t} 内存池的最大内存,单位为字节 + * @return {ACL_ALLOCATOR *} 内存分配池对象指针 + */ +ACL_API ACL_ALLOCATOR *acl_allocator_create(size_t mem_limit); + +/** + * 控制内存分配池的一些参数 + * @param name {int} 参数列表的第一个参数 + * 调用方式如下: + * acl_allocator_ctl(ACL_ALLOCATOR_CTL_MIN_SIZE, 128, + * ACL_ALLOCATOR_CTL_MAX_SIZE, 1024, + * ACL_ALLOCATOR_CTL_END); + */ +ACL_API void acl_allocator_ctl(int name, ...); + +#define ACL_ALLOCATOR_CTL_END 0 /**< 结束标记 */ +#define ACL_ALLOCATOR_CTL_MIN_SIZE 1 /**< 设置最小字节数 */ +#define ACL_ALLOCATOR_CTL_MAX_SIZE 2 /**< 设置最大字节数 */ + +/** + * 配置内存分配池的容量大小 + * @param allocator {ACL_ALLOCATOR*} + * @param mem_limit {size_t} 内存池的最大值,单位为字节 + */ +ACL_API void acl_allocator_config(ACL_ALLOCATOR *allocator, size_t mem_limit); + +/** + * 释放内存分配池对象及其所管理的内存 + * @param allocator {ACL_ALLOCATOR*} + */ +ACL_API void acl_allocator_free(ACL_ALLOCATOR *allocator); + +/** + * 添加一个新的内存分配类型 + * @param allocator {ACL_ALLOCATOR*} + * @param label {const char*} 该内存分配类型的描述信息 + * @param obj_size {size_t} 每个该内存类型的大小,单位为字节 + * @param type {acl_mem_type} 内存类型 + * @param after_alloc_fn {void (*)(void*, void*)} 分配内存成功后调用的函数,可以为空 + * @param before_free_fn {void (*)(void*, void*)} 释放内存前回调的函数,可以为空 + * @param pool_ctx {void*} 应用自己的私有对象,如果 after_alloc_fn 或 before_free_fn + * 不为空,则回调时将此参数直接传递给应用 + * @return {ACL_MEM_POOL*} 该内存分配类型所对应的对象 + */ +ACL_API ACL_MEM_POOL *acl_allocator_pool_add(ACL_ALLOCATOR *allocator, + const char *label, + size_t obj_size, + acl_mem_type type, + void (*after_alloc_fn)(void *obj, void *pool_ctx), + void (*before_free_fn)(void *obj, void *pool_ctx), + void *pool_ctx); + +/** + * 从内存分配池中移除某种内存分配类型 + * @param allocator {ACL_ALLOCATOR*} + * @param pool {ACL_MEM_POOL*} 由 acl_allocatore_pool_add 返回的对象 + */ +ACL_API void acl_allocator_pool_remove(ACL_ALLOCATOR *allocator, ACL_MEM_POOL *pool); + +/** + * 探测某种分配类型是否存在于内存分配池的内存分配类型中 + * @param allocator {ACL_ALLOCATOR*} + * @param type {acl_mem_type} 内存类型 + * @return {int}, 0: 否,!= 0: 是 + */ +ACL_API int acl_allocator_pool_ifused(ACL_ALLOCATOR *allocator, acl_mem_type type); + +/** + * 某种分配类型的内存对象当前被使用的个数 + * @param allocator {ACL_ALLOCATOR*} + * @param type {acl_mem_type} 内存类型 + * @return {int} 当前正在被使用的某种内存分配类型的内存对象个数 + */ +ACL_API int acl_allocator_pool_inuse_count(ACL_ALLOCATOR *allocator, acl_mem_type type); + +/** + * 某种分配类型所分配的内存中当前正在被使用的内存大小 + * @param allocator {ACL_ALLOCATOR*} + * @param type {acl_mem_type} 内存类型 + * @return {int} 某种分配类型所分配的内存中当前正在被使用的内存大小,单位为字节 + */ +ACL_API int acl_allocator_pool_inuse_size(ACL_ALLOCATOR *allocator, acl_mem_type type); + +/** + * 内存分配池总共分配的且正在被使用的内存的大小 + * @param allocator {ACL_ALLOCATOR*} + * @return {int} 内存大小,单位:字节 + */ +ACL_API int acl_allocator_pool_total_allocated(ACL_ALLOCATOR *allocator); + +/** + * 分配某种内存类型的内存 + * @param allocator {ACL_ALLOCATOR*} + * @param type {acl_mem_type} 内存类型 + * @return {void*} 新分配的内存的地址 + */ +ACL_API void *acl_allocator_mem_alloc(ACL_ALLOCATOR *allocator, acl_mem_type type); + +/** + * 释放某种内存类型的内存空间 + * @param allocator {ACL_ALLOCATOR*} + * @param type {acl_mem_type} 内存类型 + * @param obj {void*} 被释放的内存对象,不能为空 + */ +ACL_API void acl_allocator_mem_free(ACL_ALLOCATOR *allocator, acl_mem_type type, void *obj); + +/** + * 根据所要求的内存大小,自动进行内存分配类型匹配,若找到所匹配的类型,则采用内存池 + * 的内存分配策略,否则直接调用 acl_mymalloc 进行内存分配 + * @param filename {const char*} 调用本函数的当前文件名 + * @param line {int} 调用本函数的当前文件行号 + * @param allocator {ACL_ALLOCATOR*} + * @param size {size_t} 调用者所申请的内存大小 + * @return {void*} 新分配的内存的地址 + */ +ACL_API void *acl_allocator_membuf_alloc(const char *filename, int line, + ACL_ALLOCATOR *allocator, size_t size); + +/** + * 根据所申请的内存大小,重新分配内存空间,若找到所匹配的类型,则采用内存池 + * 内存分配策略,否则直播调用 acl_mymalloc 进行内存分配 + * @param filename {const char*} 调用本函数的当前文件名 + * @param line {int} 调用本函数的当前文件行号 + * @param allocator {ACL_ALLOCATOR*} + * @param oldbuf {void*} 原来分配的内存 + * @param size {size_t} 本次申请的内存大小 + * @return {void*} 新分配的内存的地址 + */ +ACL_API void *acl_allocator_membuf_realloc(const char *filename, int line, + ACL_ALLOCATOR *allocator, void *oldbuf, size_t size); + +/** + * 释放内存, 如果能找到该大小的内存所属的内存分配类型,则进行缓冲,否则直播调用 + * acl_myfree 进行释放 + * @param filename {const char*} 调用本函数的当前文件名 + * @param line {int} 调用本函数的当前文件行号 + * @param allocator {ACL_ALLOCATOR*} + * @param buf {void*} 内存地址 + */ +ACL_API void acl_allocator_membuf_free(const char *filename, int line, + ACL_ALLOCATOR *allocator, void *buf); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/include/stdlib/acl_argv.h b/lib_acl/include/stdlib/acl_argv.h new file mode 100644 index 000000000..97dfc824d --- /dev/null +++ b/lib_acl/include/stdlib/acl_argv.h @@ -0,0 +1,182 @@ +#ifndef __ACL_ARGV_H_INCLUDED_ +#define __ACL_ARGV_H_INCLUDED_ + +# ifdef __cplusplus +extern "C" { +# endif +#include "acl_define.h" +#include +#include "acl_slice.h" +#include "acl_iterator.h" + +/** + * External interface. + */ +typedef struct ACL_ARGV { + int len; /**< number of array elements */ + int argc; /**< array elements in use */ + char **argv; /**< string array */ + + /* 添加及弹出 */ + + /* 向数组尾部添加字符串 (内部动态拷贝该字符串) */ + void (*push_back)(struct ACL_ARGV*, const char*); + /* 向数组头部添加动态对象 (内部动态拷贝该字符串)*/ + void (*push_front)(struct ACL_ARGV*, const char*); + /* 弹出数组尾部字符串 (用完后需调用 acl_myfree 释放) */ + char *(*pop_back)(struct ACL_ARGV*); + /* 弹出数组头部字符串 (用完后需调用 acl_myfree 释放) */ + char *(*pop_front)(struct ACL_ARGV*); + + /* for acl_iterator */ + + /* 取迭代器头函数 */ + void *(*iter_head)(ACL_ITER*, struct ACL_ARGV*); + /* 取迭代器下一个函数 */ + void *(*iter_next)(ACL_ITER*, struct ACL_ARGV*); + /* 取迭代器尾函数 */ + void *(*iter_tail)(ACL_ITER*, struct ACL_ARGV*); + /* 取迭代器上一个函数 */ + void *(*iter_prev)(ACL_ITER*, struct ACL_ARGV*); + + /* private */ + ACL_SLICE_POOL *slice; +} ACL_ARGV; + +/* in acl_argv.c */ +/** + * 分配一个字符串动态数组 + * @param size {int} 动态数组的初始大小 + * @return {ACL_ARGV*} + */ +ACL_API ACL_ARGV *acl_argv_alloc(int size); + +ACL_API ACL_ARGV *acl_argv_alloc2(int size, ACL_SLICE_POOL *slice); + +/** + * 向字符串动态数组中添加一至多个字符串,最后一个NULL字符串表示结束 + * @param argvp {ACL_ARGV*} 字符串动态数组指针 + * @param ... 字符串列表,最后一个为NULL, 格式如:{s1}, {s2}, ..., NULL + */ +ACL_API void acl_argv_add(ACL_ARGV *argvp,...); + +/** + * 向字符串动态数组中添加字符串列表 + * @param argvp {ACL_ARGV*} 字符串动态数组指针 + * @param ap {va_list} 由多个字符串组成的变参列表 + */ +ACL_API void acl_argv_addv(ACL_ARGV *argvp, va_list ap); + +/** + * 向字符串动态数组中添加字段长度有限制的字符串列表 + * @param argvp {ACL_ARGV*} 字符串动态数组指针 + * @param ... 一组有长度限制的字符串列表,如: {s1}, {len1}, {s2}, {len2}, ... NULL + */ +ACL_API void acl_argv_addn(ACL_ARGV *argvp,...); + +/** + * 向字符串动态数组中添加字段长度有限制的字符串列表 + * @param argvp {ACL_ARGV*} 字符串动态数组指针 + * @param ap {va_list} 一组有长度限制的字符串组成的变参列表 + */ +ACL_API void acl_argv_addnv(ACL_ARGV *argvp, va_list ap); + +/** + * 设置字符串动态数组的结束位置 + * @param argvp {ACL_ARGV*} 字符串动态数组指针 + */ +ACL_API void acl_argv_terminate(ACL_ARGV *argvp); + +/** + * 释放字符串动态数组 + * @param argvp {ACL_ARGV*} 字符串动态数组指针 + */ +ACL_API ACL_ARGV *acl_argv_free(ACL_ARGV *argvp); + +/** + * 根据数组下标位置返回相对应的字符串指针 + * @param argvp {ACL_ARGV*} 字符串动态数组指针 + * @param idx {int} 下标位置 + * @return {char*} NULL: 下标越界;!= NULL: 字符串指针位置 + */ +ACL_API char *acl_argv_index(ACL_ARGV *argvp, int idx); + +/** + * 返回当前字符串动态数组中已经存放的字符串个数 + * @param argvp {ACL_ARGV*} 字符串动态数组指针 + * @return {int} + */ +ACL_API int acl_argv_size(ACL_ARGV *argvp); + +/* in acl_argv_split.c */ +/** + * 根据源字符串及分隔字符串生成一个字符串动态数组 + * @param str {const char*} 源字符串 + * @param delim {const char*} 分隔字符串 + * @return {ACL_ARGV*} + */ +ACL_API ACL_ARGV *acl_argv_split(const char *str, const char *delim); + +/** + * 根据源字符串及分隔字符串生成一个字符串动态数组,同时将传入的内存池 + * 对象做为内存分配器 + * @param str {const char*} 源字符串 + * @param delim {const char*} 分隔字符串 + * @param slice {ACL_SLICE_POOL*} 内存池对象,可以为空,当为空时则采用 + * 缺省的内存分配方式 + * @return {ACL_ARGV*} + */ +ACL_API ACL_ARGV *acl_argv_split3(const char *str, const char *delim, + ACL_SLICE_POOL *slice); + +/** + * 根据源字符串及分隔字符串生成一个字符串动态数组, 但限定最大分隔次数 + * @param str {const char*} 源字符串 + * @param delim {const char*} 分隔字符串 + * @param n {size_t} 最大分隔次数 + * @return {ACL_ARGV*} + */ +ACL_API ACL_ARGV *acl_argv_splitn(const char *str, const char *delim, size_t n); + +/** + * 根据源字符串及分隔字符串生成一个字符串动态数组, 但限定最大分隔次数, + * 同时传入内存池对象做为内存分配器 + * @param str {const char*} 源字符串 + * @param delim {const char*} 分隔字符串 + * @param n {size_t} 最大分隔次数 + * @param slice {ACL_SLICE_POOL*} 内存池对象,可以为空,当为空时则采用 + * 缺省的内存分配方式 + * @return {ACL_ARGV*} + */ +ACL_API ACL_ARGV *acl_argv_splitn4(const char *str, const char *delim, + size_t n, ACL_SLICE_POOL *slice); + +/** + * 源字符串经分隔符分解后,其结果被附加至一个字符串动态数组 + * @param argvp {ACL_ARGV*} 字符串动态数组指针 + * @param str {const char*} 源字符串 + * @param delim {const char*} 分隔字符串 + * @return {ACL_ARGV*} + */ +ACL_API ACL_ARGV *acl_argv_split_append(ACL_ARGV *argvp, const char *str, + const char *delim); + +/** + * 源字符串经分隔符分解后,其结果被附加至一个字符串动态数组, 但限定最大分隔次数 + * @param argvp {ACL_ARGV*} 字符串动态数组指针 + * @param str {const char*} 源字符串 + * @param delim {const char*} 分隔字符串 + * @param n {size_t} 最大分隔次数 + * @return {ACL_ARGV*} + */ +ACL_API ACL_ARGV *acl_argv_splitn_append(ACL_ARGV *argvp, const char *str, + const char *delim, size_t n); + +#define ACL_ARGV_END ((char *) 0) + +# ifdef __cplusplus +} +# endif + +#endif + diff --git a/lib_acl/include/stdlib/acl_array.h b/lib_acl/include/stdlib/acl_array.h new file mode 100644 index 000000000..9fe19154e --- /dev/null +++ b/lib_acl/include/stdlib/acl_array.h @@ -0,0 +1,186 @@ +#ifndef __ACL_ARRAY_INCLUDE_H_ +#define __ACL_ARRAY_INCLUDE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "acl_define.h" +#include "acl_iterator.h" + +/** + * 动态数组类型定义 + */ +typedef struct ACL_ARRAY ACL_ARRAY; +struct ACL_ARRAY{ + int capacity; /**< items 数组空间大小 */ + int count; /**< items 中含有元素的个数 */ + void **items; /**< 动态数组 */ + + /* 添加及弹出 */ + + /* 向数组尾部添加动态对象 */ + void (*push_back)(struct ACL_ARRAY*, void*); + /* 向数组头部添加动态对象 */ + void (*push_front)(struct ACL_ARRAY*, void*); + /* 弹出数组尾部动态对象 */ + void *(*pop_back)(struct ACL_ARRAY*); + /* 弹出数组头部动态对象 */ + void *(*pop_front)(struct ACL_ARRAY*); + + /* for acl_iterator */ + + /* 取迭代器头函数 */ + void *(*iter_head)(ACL_ITER*, struct ACL_ARRAY*); + /* 取迭代器下一个函数 */ + void *(*iter_next)(ACL_ITER*, struct ACL_ARRAY*); + /* 取迭代器尾函数 */ + void *(*iter_tail)(ACL_ITER*, struct ACL_ARRAY*); + /* 取迭代器上一个函数 */ + void *(*iter_prev)(ACL_ITER*, struct ACL_ARRAY*); +}; + +/** + * 创建一个动态数组 + * @param init_size {int} 动态数组的初始大小 + * @return {ACL_ARRAY*} 动态数组指针 + */ +ACL_API ACL_ARRAY *acl_array_create(int init_size); + +/** + * 释放掉动态数组内的成员变量,但并不释放动态数组对象 + * @param a {ACL_ARRAY*} 动态数组指针 + * @param free_fn {void (*)(void*)} 用于释放动态数组内成员变量的释放函数指针 + */ +ACL_API void acl_array_clean(ACL_ARRAY *a, void (*free_fn)(void *)); + +/** + * 释放掉动态数组内的成员变量,并释放动态数组对象 + * @param a {ACL_ARRAY*} 动态数组指针 + * @param free_fn {void (*)(void*)} 用于释放动态数组内成员变量的释放函数指针 + */ +ACL_API void acl_array_free(ACL_ARRAY *a, void (*free_fn)(void *)); +#define acl_array_destroy acl_array_free + +/** + * 向动态数组尾部添加动态成员变量 + * @param a {ACL_ARRAY*} 动态数组指针 + * @param obj {void*} 动态成员变量 + * @return {int} >=0: 成功, 返回值为该元素在数组中的下标位置;-1: 失败 + */ +ACL_API int acl_array_append(ACL_ARRAY *a, void *obj); + +/** + * 向动态数组头部添加动态成员变量 + * @param a {ACL_ARRAY*} 动态数组指针 + * @param obj {void*} 动态成员变量 + * @return {int} >=0: 成功, 返回值为该元素在数组中的下标位置;-1: 失败 + */ +ACL_API int acl_array_prepend(ACL_ARRAY *a, void *obj); + +/** + * 向动态数组中指定位置前添加动态成员变量(该结点及以后所有结点都后移一个位置) + * @param a {ACL_ARRAY*} 动态数组指针 + * @param position {int} 某个位置,不得越界 + * @param obj {void*} 动态成员变量 + * @return {int} 0: 成功;-1: 失败 + */ +ACL_API int acl_array_pred_insert(ACL_ARRAY *a, int position, void *obj); + +/** + * 向动态数组中指定位置后添加动态成员变量(该结点以后所有结点都后移一个位置) + * @param a {ACL_ARRAY*} 动态数组指针 + * @param position {int} 某个位置,不得越界 + * @param obj {void*} 动态成员变量 + * @return {int} 0: 成功;-1: 失败 + */ +ACL_API int acl_array_succ_insert(ACL_ARRAY *a, int position, void *obj); +#define acl_array_insert acl_array_succ_insert + +/** + * 从动态数组中的指定位置删除某个动态对象, 删除后数组内元素的先后顺序保持不变, + * 如果被删除位置在中间某个位置,为了保证元素的顺序性,内部将被删除元素后的所有元素 + * 都前移一个位置 + * @param a {ACL_ARRAY*} 动态数组指针 + * @param position {int} 某个位置,不得越界 + * @param free_fn {void (*)(void*)} 用于释放动态数组内成员变量的释放函数指针,如果该 + * 指针为空,则不释放,否则用此函数进行释放动态对象 + * @return {int} 0: 成功;-1: 失败 + */ +ACL_API int acl_array_delete_idx(ACL_ARRAY *a, int position, void (*free_fn)(void *)); + +/** + * 从动态数组中的指定位置删除某个对象,删除后数组内元素的先后顺序有可能发生了改变, + * 因为删除后会自动将数组中最后的元素移至该位置处 + * @param a {ACL_ARRAY*} 动态数组指针 + * @param position {int} 某个位置,不得越界 + * @param free_fn {void (*)(void*)} 用于释放动态数组内成员变量的释放函数指针,如果该 + * 指针为空,则不释放,否则用此函数进行释放动态对象 + * @return {int} 0: 成功;-1: 失败 + */ +ACL_API int acl_array_delete(ACL_ARRAY *a, int position, void (*free_fn)(void*)); + +/** + * 从动态数组中删除指定指针地址的动态对象, 删除后数组内元素的先后顺序保持不变 + * 如果被删除位置在中间某个位置,为了保证元素的顺序性内部,将被删除元素后的所有元素 + * 都前移一个位置 + * @param a {ACL_ARRAY*} 动态数组指针 + * @param obj {void*} 动态对象指针地址 + * @param free_fn {void (*)(void*)} 用于释放动态数组内成员变量的释放函数指针,如果该 + * 指针为空,则不释放,否则用此函数进行释放动态对象 + * @return {int} 0: 成功;-1: 失败 + */ +ACL_API int acl_array_delete_obj(ACL_ARRAY *a, void *obj, void (*free_fn)(void *)); + +/** + * 从动态数组中删除某个下标范围的动态对象 + * @param a {ACL_ARRAY*} 动态数组指针 + * @param ibegin {int} 开始下标位置 + * @param iend {int} 结束下标位置 + * @param free_fn {void (*)(void*)} 用于释放动态数组内成员变量的释放函数指针,如果该 + * 指针为空,则不释放,否则用此函数进行释放动态对象 + * @return {int} 0: 成功;-1: 失败 + */ +ACL_API int acl_array_delete_range(ACL_ARRAY *a, int ibegin, int iend, void (*free_fn)(void*)); + +/** + * 移动动态数组中的对象 + * @param a {ACL_ARRAY*} 动态数组指针 + * @param ito {int} 移动至目标下标位置 + * @param ifrom {int} 从此下标位置开始移动 + * @param free_fn {void (*)(void*)} 用于释放动态数组内成员变量的释放函数指针,如果该 + * 指针为空,则不释放,否则用此函数进行释放动态对象被释放的动态对象区间为 + * [idx_obj_begin, idx_src_begin), 为一半开半闭区间 + * @return {int} 0: 成功;-1: 失败 + */ +ACL_API int acl_array_mv_idx(ACL_ARRAY *a, int ito, int ifrom, void (*free_fn)(void *) ); + +/** + * 预先保证动态数组的空间长度 + * @param a {ACL_ARRAY*} 动态数组指针 + * @param app_count {int} 需要动态数组至少有 app_count 个空闲位置 + * @return {int} 0: 成功;-1: 失败 + */ +ACL_API int acl_array_pre_append(ACL_ARRAY *a, int app_count); + +/** + * 从动态数组中的某个下标位置取出动态对象 + * @param a {ACL_ARRAY*} 动态数组指针 + * @param idx {int} 下标位置,不能越界,否则返回-1 + * @return {void*} != NULL: 成功;== NULL: 不存在或失败 + */ +ACL_API void *acl_array_index(const ACL_ARRAY *a, int idx); + +/** + * 获得当前动态数组中动态对象的个数 + * @param a {ACL_ARRAY*} 动态数组指针 + * @return {int} 动态数组中动态对象的个数 + */ +ACL_API int acl_array_size(const ACL_ARRAY *a); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/include/stdlib/acl_binhash.h b/lib_acl/include/stdlib/acl_binhash.h new file mode 100644 index 000000000..c60d39d2d --- /dev/null +++ b/lib_acl/include/stdlib/acl_binhash.h @@ -0,0 +1,244 @@ +#ifndef _ACL_BINHASH_H_INCLUDED_ +#define _ACL_BINHASH_H_INCLUDED_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "acl_define.h" +#include "acl_hash.h" /* just for ACL_HASH_FN */ +#include "acl_slice.h" +#include "acl_iterator.h" + +typedef struct ACL_BINHASH ACL_BINHASH; +typedef struct ACL_BINHASH_INFO ACL_BINHASH_INFO; + +/** + * Structure of one hash table. + */ +struct ACL_BINHASH { + int size; /**< length of entries array */ + int used; /**< number of entries in table */ + unsigned int flag; /**< the hash table's properties flag */ + int status; /**< the hash tables' operation status */ + ACL_BINHASH_INFO **data; /**< entries array, auto-resized */ + ACL_SLICE *slice; /**< memory slice */ + ACL_HASH_FN hash_fn; /**< hash function */ + + /* for acl_iterator */ + + /* 取迭代器头函数 */ + void *(*iter_head)(ACL_ITER*, struct ACL_BINHASH*); + /* 取迭代器下一个函数 */ + void *(*iter_next)(ACL_ITER*, struct ACL_BINHASH*); + /* 取迭代器尾函数 */ + void *(*iter_tail)(ACL_ITER*, struct ACL_BINHASH*); + /* 取迭代器上一个函数 */ + void *(*iter_prev)(ACL_ITER*, struct ACL_BINHASH*); + /* 取迭代器关联的当前容器成员结构对象 */ + ACL_BINHASH_INFO *(*iter_info)(ACL_ITER*, struct ACL_BINHASH*); +}; + +/** + * Structure of one hash table entry. + */ +struct ACL_BINHASH_INFO { + union { + void *key; + const void *c_key; + } key; /** + * 哈希键, 只所以如此声明,是因为当创建哈希表的标志位为 + * ACL_BINHASH_FLAG_KEY_REUSE 时需要复用输入的键空间 + */ + int key_len; /**< 哈希键长度 */ + void *value; /**< 哈希键所对应的用户数据 */ + struct ACL_BINHASH_INFO *next; /**< colliding entry */ + struct ACL_BINHASH_INFO *prev; /**< colliding entry */ +}; + +/** + * ACL_BINHASH 遍历用类型 + */ +typedef struct ACL_BINHASH_ITER { + /* public */ + ACL_BINHASH_INFO *ptr; + + /* private */ + int i; + int size; + ACL_BINHASH_INFO **h; +} ACL_BINHASH_ITER; + +/** + * 创建一个哈希表 + * @param size {int} 哈希表的初始化大小 + * @param flag {unsigned int} 哈希表属性标志位, ACL_BINHASH_FLAG_xxx + * @return {ACL_BINHASH*} 新创建的哈希表指针 + */ +ACL_API ACL_BINHASH *acl_binhash_create(int size, unsigned int flag); +#define ACL_BINHASH_FLAG_KEY_REUSE (1 << 0) +#define ACL_BINHASH_FLAG_SLICE_RTGC_OFF (1 << 1) +#define ACL_BINHASH_FLAG_SLICE1 (1 << 2) +#define ACL_BINHASH_FLAG_SLICE2 (1 << 3) +#define ACL_BINHASH_FLAG_SLICE3 (1 << 4) + +/** + * 向哈希表中添加对象 + * @param table {ACL_BINHASH*} 哈希表指针 + * @param key {const void*} 哈希键 + * @param key_len {int} key 的长度 + * @param value {void*} 键值 + * @return {ACL_BINHASH_INFO*} 新创建的哈希条目指针 + */ +ACL_API ACL_BINHASH_INFO *acl_binhash_enter(ACL_BINHASH *table, const void *key, int key_len, void *value); + +/** + * 从哈希表中根据键名取得对应的哈希条目 + * @param table {ACL_BINHASH*} 哈希表指针 + * @param key {const void*} 哈希键 + * @param key_len {int} key 的长度 + * @return {ACL_BINHASH_INFO*} 哈希条目指针 + */ +ACL_API ACL_BINHASH_INFO *acl_binhash_locate(ACL_BINHASH *table, const void *key, int key_len); + +/** + * 查询某个哈希键的键值 + * @param table {ACL_BINHASH*} 哈希表指针 + * @param key {const void*} 哈希键 + * @param key_len {int} key 的长度 + * @return {void*} 哈希键值 + */ +ACL_API void *acl_binhash_find(ACL_BINHASH *table, const void *key, int key_len); + +/** + * 删除某个哈希项 + * @param table {ACL_BINHASH*} 哈希表指针 + * @param key {const void*} 哈希键 + * @param key_len {int} key 的长度 + * @param free_fn {void (*)(void*)} 用来释放哈希键值的函数指针,如果为空则不在内部释放键值 + * @return {int} 0: ok, -1: error + */ +ACL_API int acl_binhash_delete(ACL_BINHASH *table, const void *key, int key_len, void (*free_fn) (void *)); + +/** + * 释放哈希表 + * @param table {ACL_BINHASH*} 哈希表指针 + * @param free_fn {void (*)(void*)} 如果不为空,则用此函数来释放哈希表内的所有键值 + */ +ACL_API void acl_binhash_free(ACL_BINHASH *table, void (*free_fn) (void *)); + +/** + * 遍历整个哈希表,并用用户给出的回调函数操作哈希表中的键值 + * @param table {ACL_BINHASH*} 哈希表指针 + * @param walk_fn {void (*)(ACL_BINHASH_INFO*, void*)} 在遍历哈希表中的每个元素时的回调函数 + * @param arg {void*} 用户传递的参数,作为参数在 walk_fn 中传递 + */ +ACL_API void acl_binhash_walk(ACL_BINHASH *table, void (*walk_fn) (ACL_BINHASH_INFO *, void *), void *arg); + +/** + * 列出当前哈希表中的所有元素数组列表 + * @param table {ACL_BINHASH*} 哈希表指针 + * @return {ACL_BINHASH_INFO*} 哈希表中所有元素组成的ACL_BINHASH_INFO数组, + * 该数组中的最后一个指针为 NULL + */ +ACL_API ACL_BINHASH_INFO **acl_binhash_list(ACL_BINHASH *table); + +/** + * 获得哈希表操作时的出错号 + * @param table {ACL_BINHASH*} 哈希表指针 + * @return {int} 错误号 + */ +ACL_API int acl_binhash_errno(ACL_BINHASH *table); +#define ACL_BINHASH_STAT_OK 0 +#define ACL_BINHASH_STAT_INVAL 1 +#define ACL_BINHASH_STAT_DUPLEX_KEY 2 +#define ACL_BINHASH_STAT_NO_KEY 3 + +/** + * 返回哈希表当前的容器空间大小 + * @param table 哈希表指针 + * @return 哈希表的容器空间大小 + */ +ACL_API int acl_binhash_size(const ACL_BINHASH *table); + +/** + * 当前哈希表中对象的个数 + * @param table {ACL_BINHASH*} 哈希表指针 + * @return {int} + */ +ACL_API int acl_binhash_used(ACL_BINHASH *table); + +ACL_API ACL_BINHASH_INFO **acl_binhash_data(ACL_BINHASH *table); +ACL_API const ACL_BINHASH_INFO *acl_binhash_iter_head(ACL_BINHASH *table, ACL_BINHASH_ITER *iter); +ACL_API const ACL_BINHASH_INFO *acl_binhash_iter_next(ACL_BINHASH_ITER *iter); +ACL_API const ACL_BINHASH_INFO *acl_binhash_iter_tail(ACL_BINHASH *table, ACL_BINHASH_ITER *iter); +ACL_API const ACL_BINHASH_INFO *acl_binhash_iter_prev(ACL_BINHASH_ITER *iter); + +/*-------------------- 一些方便快捷的宏操作 --------------------------------*/ + +#define ACL_BINHASH_ITER_KEY(iter) ((iter).ptr->key.c_key) +#define acl_binhash_iter_key ACL_BINHASH_ITER_KEY + +#define ACL_BINHASH_ITER_VALUE(iter) ((iter).ptr->value) +#define acl_binhash_iter_value ACL_BINHASH_ITER_VALUE + +/** + * 遍历 ACL_BINHASH + * @param iter {ACL_BINHASH_ITER} + * @param table_ptr {ACL_BINHASH *} + * @example: + void test() + { + ACL_BINHASH *table = acl_binhash_create(10, 0); + ACL_BINHASH_ITER iter; + char *value, key[32]; + int i; + + for (i = 0; i < 100; i++) { + value = (char*) acl_mystrdup("value"); + snprintf(key, sizeof(key), "key:%d", i); + (void) acl_binhash_enter(table, key, strlen(key), value); + } + + acl_binhash_foreach(iter, table) { + printf("%s=%s\n", iter.ptr->key.c_key, iter.ptr->value); + if (i == 50) + break; + } + + acl_binhash_free(table, acl_myfree_fn); + } + */ +#if 0 +#define ACL_BINHASH_FOREACH(iter, table_ptr) \ + if (table_ptr) \ + for((iter).size = acl_binhash_size((table_ptr)), (iter).i = 0, \ + (iter).h = acl_binhash_data((table_ptr)); (iter).i < (iter).size; (iter).i++) \ + for ((iter).ptr = *(iter).h++; (iter).ptr; (iter).ptr = (iter).ptr->next) +#define ACL_BINHASH_FOREACH_REVERSE(iter, table_ptr) \ + if (table_ptr) \ + for((iter).size = acl_binhash_size((table_ptr)), (iter).i = (iter).size - 1, \ + (iter).h = acl_binhash_data((table_ptr)) + (iter).i; (iter).i >= 0; (iter).i--) \ + for ((iter).ptr = *(iter).h--; (iter).ptr; (iter).ptr = (iter).ptr->next) +#else +#define ACL_BINHASH_FOREACH(iter, table_ptr) \ + if (table_ptr) \ + for((void) acl_binhash_iter_head((table_ptr), &iter); \ + (iter).ptr; \ + (void) acl_binhash_iter_next(&iter)) +#define ACL_BINHASH_FOREACH_REVERSE(iter, table_ptr) \ + if (table_ptr) \ + for((void) acl_binhash_iter_tail((table_ptr), &iter); \ + (iter).ptr; \ + (void) acl_binhash_iter_prev(&iter)) +#endif + +#define acl_binhash_foreach ACL_BINHASH_FOREACH +#define acl_binhash_foreach_reverse ACL_BINHASH_FOREACH_REVERSE + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/include/stdlib/acl_bits_map.h b/lib_acl/include/stdlib/acl_bits_map.h new file mode 100644 index 000000000..6a99dff45 --- /dev/null +++ b/lib_acl/include/stdlib/acl_bits_map.h @@ -0,0 +1,104 @@ +#ifndef __ACL_BITS_MAP_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "acl_define.h" + +/** + * 位映射结构类型定义 + */ +typedef struct ACL_BITS_MASK { + char *data; /**< bit mask */ + size_t data_len; /**< data byte count */ +} ACL_BITS_MASK; + +/** + * Bits per byte, byte in vector, bit offset in byte, bytes perset + */ +#define ACL_BITS_MASK_NBBY (8) +#define ACL_BITS_MASK_FD_BYTE(number, mask) \ + (((unsigned char *) (mask)->data)[(number) / ACL_BITS_MASK_NBBY]) +#define ACL_BITS_MASK_FD_BIT(number) (1 << ((number) % ACL_BITS_MASK_NBBY)) +#define ACL_BITS_MASK_BYTES_NEEDED(len) \ + (size_t) (((acl_int64) (len) + (ACL_BITS_MASK_NBBY - 1)) / ACL_BITS_MASK_NBBY) +#define ACL_BITS_MASK_BYTE_COUNT(mask) ((mask)->data_len) + +/* Memory management. */ +/** + * 分配位映射对象空间 + * @param mask {ACL_BITS_MASK*) ACL_BITS_MASK 指针 + * @param nmax {size_t/unsigned int/unsigned short/unsigned char} 最大值,以此值来 + * 计算 (mask)->data 占的内存空间大小,如:当 nmax=4294967295, 即最大整数值时,则 + * (mask)->data_len=536870912, 即 (mask)->data 占用 536870912 Bytes; 当 nmax=65535, + * 即最大 unsigned short 值时,则 (mask)->data_len=8192, 即 (mask)->data 占用 8192 字节 + */ +#define ACL_BITS_MASK_ALLOC(mask, nmax) do { \ + size_t _byte_len = ACL_BITS_MASK_BYTES_NEEDED(nmax); \ + (mask)->data = (char*) acl_mymalloc(_byte_len); \ + memset((mask)->data, 0, _byte_len); \ + (mask)->data_len = _byte_len; \ +} while (0) + +/** + * 重分配位映射对象空间 + * @param mask {ACL_BITS_MASK*) ACL_BITS_MASK 指针 + * @param nmax {size_t/unsigned int/unsigned short/unsigned char} 最大值,以此值来 + * 计算 (mask)->data 占的内存空间大小,如:当 nmax=4294967295, 即最大整数值时,则 + * (mask)->data_len=536870912, 即 (mask)->data 占用 536870912 Bytes; 当 nmax=65535, + * 即最大 unsigned short 值时,则 (mask)->data_len=8192, 即 (mask)->data 占用 8192 字节 + */ +#define ACL_BITS_MASK_REALLOC(mask, nmax) do { \ + size_t _byte_len = ACL_BITS_MASK_BYTES_NEEDED(nmax); \ + size_t _old_len = (mask)->data_len; \ + (mask)->data = (char*) acl_myrealloc((mask)->data, _byte_len); \ + memset((mask)->data + _old_len, 0, _byte_len - _old_len); \ + (mask)->data_len = _byte_len; \ +} while (0) + +/** + * 释放位映射对象的内部动态空间 + * @param mask {ACL_BITS_MASK*) ACL_BITS_MASK 指针 + */ +#define ACL_BITS_MASK_FREE(mask) acl_myfree((mask)->data) + +/* Set operations, modeled after FD_ZERO/SET/ISSET/CLR. */ + +/** + * 将位映射对象的内部动态空间清零 + * @param mask {ACL_BITS_MASK*) ACL_BITS_MASK 指针 + */ +#define ACL_BITS_MASK_ZERO(mask) \ + memset((mask)->data, 0, (mask)->data_len); + +/** + * 将整数映射为位存储在位映射对象的动态空间中 + * @param number {unsigned int} 整数值 + * @param mask {ACL_BITS_MASK*) ACL_BITS_MASK 指针 + */ +#define ACL_BITS_MASK_SET(number, mask) \ + (ACL_BITS_MASK_FD_BYTE((number), (mask)) |= ACL_BITS_MASK_FD_BIT(number)) + +/** + * 判断某个整数是否存储在位映射对象的动态空间中 + * @param number {unsigned int} 整数值 + * @param mask {ACL_BITS_MASK*) ACL_BITS_MASK 指针 + * @return {int} 0: 不存在;!= 0: 存在 + */ +#define ACL_BITS_MASK_ISSET(number, mask) \ + (ACL_BITS_MASK_FD_BYTE((number), (mask)) & ACL_BITS_MASK_FD_BIT(number)) + +/** + * 将某个整数从位映射对象的动态空间中清除掉 + * @param number {unsigned int} 整数值 + * @param mask {ACL_BITS_MASK*) ACL_BITS_MASK 指针 + */ +#define ACL_BITS_MASK_CLR(number, mask) \ + (ACL_BITS_MASK_FD_BYTE((number), (mask)) &= ~ACL_BITS_MASK_FD_BIT(number)) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/include/stdlib/acl_btree.h b/lib_acl/include/stdlib/acl_btree.h new file mode 100644 index 000000000..d79781bff --- /dev/null +++ b/lib_acl/include/stdlib/acl_btree.h @@ -0,0 +1,91 @@ +#ifndef __ACL_BTREE_INCLUDE_H__ +#define __ACL_BTREE_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "acl_define.h" + +/** + * 二叉树结构类型定义 + */ +typedef struct ACL_BTREE ACL_BTREE; + +/** + * 创建一个二叉树对象 + * @return {ACL_BTREE*} 新创建的二叉树对象 + */ +ACL_API ACL_BTREE *acl_btree_create(void); + +/** + * 释放一个二叉树对象 + * @param tree {ACL_BTREE*} 二叉树对象 + * @return {int} 0: 成功; -1: 失败 + */ +ACL_API int acl_btree_destroy(ACL_BTREE *tree); + +/** + * 从二叉树中查询 + * @param tree {ACL_BTREE*} 二叉树对象 + * @param key {unsigned int} 查询键 + * @return {void*} 查询结果 + */ +ACL_API void *acl_btree_find(ACL_BTREE *tree, unsigned int key); + +/** + * 向二叉树中添加 + * @param tree {ACL_BTREE*} 二叉树对象 + * @param key {unsigned int} 键 + * @param data {void*} 动态对象 + */ +ACL_API int acl_btree_add(ACL_BTREE *tree, unsigned int key, void *data); + +/** + * 从二叉树中删除 + * @param tree {ACL_BTREE*} 二叉树对象 + * @param key {unsigned int} 键 + * @return {void*} 被删除的动态对象地址, 如果不存在则返回NULL + */ +ACL_API void *acl_btree_remove(ACL_BTREE *tree, unsigned int key); + +/** + * 返回二叉树中最小的键 + * @param tree {ACL_BTREE*} 二叉树对象 + * @param key {unsigned int*} 键指针,存储结果,不能为空 + * @return {int} 0: 表示找到最小键; -1: 表示出错或未找到最小键 + */ +ACL_API int acl_btree_get_min_key(ACL_BTREE *tree, unsigned int *key); + +/** + * 返回二叉树中最大的键 + * @param tree {ACL_BTREE*} 二叉树对象 + * @param key {unsigned int*} 键指针,存储结果,不能为空 + * @return {int} 0: 表示找到最大键; -1: 表示出错或未找到最大键 + */ +ACL_API int acl_btree_get_max_key(ACL_BTREE *tree, unsigned int *key); + +/** + * 由给定键,返回其在二叉树中的下一个邻近键 + * @param tree {ACL_BTREE*} 二叉树对象 + * @param cur_key {unsigned int} 当前给定键 + * @param next_key {unsigned int*} 存储结果键的指针地址 + * @return {int} 0: 表示找到; -1: 表示出错或未找到 + */ +ACL_API int acl_btree_get_next_key(ACL_BTREE *tree, + unsigned int cur_key, unsigned int *next_key); + +/** + * 计算当前二叉树的深度 + * @param tree {ACL_BTREE*} 二叉树对象 + * @return {int} 二叉树的深度 + */ +ACL_API int acl_btree_depth(ACL_BTREE *tree); +ACL_API void acl_btree_dump(ACL_BTREE *b); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/include/stdlib/acl_cache.h b/lib_acl/include/stdlib/acl_cache.h new file mode 100644 index 000000000..0a7ccfed7 --- /dev/null +++ b/lib_acl/include/stdlib/acl_cache.h @@ -0,0 +1,200 @@ +#ifndef __ACL_CACHE_INCLUDE_H__ +#define __ACL_CACHE_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif +#include "acl_define.h" +#include "acl_htable.h" +#include "acl_ring.h" +#include + +/** + * 缓存池中存储的缓存对象 + */ +typedef struct ACL_CACHE_INFO { + char *key; /**< 健值 */ + void *value; /**< 用户动态对象 */ + int nrefer; /**< 引用计数 */ + time_t when_timeout; /**< 过期时间截 */ + ACL_RING entry; /**< 内部数据链成员 */ +} ACL_CACHE_INFO; + +/** + * 缓冲池 + */ +typedef struct ACL_CACHE { + ACL_HTABLE *table; /**< 哈希表 */ + ACL_RING ring; /**< 将被删除的对象的数据链表 */ + int max_size; /**< 缓存池容量大小限制值 */ + int size; /**< 当前缓存池中的缓存对象个数 */ + int timeout; /**< 每个缓存对象的生存时长(秒) */ + + /**< 释放用户动态对象的释放回调函数 */ + void (*free_fn)(const ACL_CACHE_INFO*, void *); + acl_pthread_mutex_t lock; /**< 缓存池锁 */ + ACL_SLICE *slice; /**< 内存切片对象 */ + + /* for acl_iterator */ + + /* 取迭代器头函数 */ + void *(*iter_head)(ACL_ITER*, struct ACL_CACHE*); + /* 取迭代器下一个函数 */ + void *(*iter_next)(ACL_ITER*, struct ACL_CACHE*); + /* 取迭代器尾函数 */ + void *(*iter_tail)(ACL_ITER*, struct ACL_CACHE*); + /* 取迭代器上一个函数 */ + void *(*iter_prev)(ACL_ITER*, struct ACL_CACHE*); + /* 取迭代器关联的当前容器成员结构对象 */ + ACL_CACHE_INFO *(*iter_info)(ACL_ITER*, struct ACL_CACHE*); +} ACL_CACHE; + +/** + * 创建一个缓存池,并设置每个缓存对象的最大缓存时长及该缓存池的空间容量限制 + * @param max_size {int} 该缓存池的容量限制 + * @param timeout {int} 每个缓存对象的缓存时长 + * @param free_fn {void (*)(void*)} 用户级的释放缓存对象的函数 + * @return {ACL_CACHE*} 缓存池对象句柄 + */ +ACL_API ACL_CACHE *acl_cache_create(int max_size, int timeout, + void (*free_fn)(const ACL_CACHE_INFO*, void*)); + +/** + * 释放一个缓存池,并自动调用 acl_cache_create()/3 中的释放函数释放缓存对象 + * @param cache {ACL_CACHE*} 缓存池对象句柄 + */ +ACL_API void acl_cache_free(ACL_CACHE *cache); + +/** + * 向缓存池中添加被缓存的对象 + * @param cache {ACL_CACHE*} 缓存池对象句柄 + * @param key {const char*} 缓存对象的健值 + * @param value {void*} 动态缓存对象 + * @return {ACL_CACHE_INFO*} 缓存对象所依附的结构对象,其中的 value 与用户的对象相同, + * 如果返回 NULL 则表示添加失败,失败原因为:缓存池太大溢出或相同健值的对象存在 + * 且引用计数非0; 如果返回非 NULL 则表示添加成功,如果对同一健值的重复添加,会用 + * 新的数据替换旧的数据,且旧数据调用释放函数进行释放 + */ +ACL_API ACL_CACHE_INFO *acl_cache_enter(ACL_CACHE *cache, const char *key, void *value); + +/** + * 从缓存池中查找某个被缓存的对象 + * @param cache {ACL_CACHE*} 缓存池对象句柄 + * @param key {const char*} 查询健 + * @return {void*} 被缓存的用户对象的地址,为NULL时表示未找到 + */ +ACL_API void *acl_cache_find(ACL_CACHE *cache, const char *key); + +/** + * 从缓存池中查找某个被缓存的对象所依附的缓存信息对象 + * @param cache {ACL_CACHE*} 缓存池对象句柄 + * @param key {const char*} 查询健 + * @return {ACL_CACHE_INFO*} 缓存信息对象地址,为NULL时表示未找到 + */ +ACL_API ACL_CACHE_INFO *acl_cache_locate(ACL_CACHE *cache, const char *key); + +/** + * 从缓存池中删除某个缓存对象 + * @param cache {ACL_CACHE*} 缓存池对象句柄 + * @param info {ACL_CACHE_INFO*} 用户对象所依附的缓存信息对象 + * @return {int} 0: 表示删除成功; -1: 表示该对象的引用计数非0或该对象不存在 + */ +ACL_API int acl_cache_delete(ACL_CACHE *cache, ACL_CACHE_INFO *info); + +/** + * 从缓存池中删除某个缓存对象 + * @param cache {ACL_CACHE*} 缓存池对象句柄 + * @param key {const char*} 健值 + * @return {int} 0: 表示删除成功; -1: 表示该对象的引用计数非0或该对象不存在 + */ +ACL_API int acl_cache_delete2(ACL_CACHE *cache, const char *key); + +/** + * 使缓存池中的过期对象被自动删除 + * @param cache {ACL_CACHE*} 缓存池对象句柄 + * @return {int} >= 0: 被自动删除的缓存对象的个数 + */ +ACL_API int acl_cache_timeout(ACL_CACHE *cache); + +/** + * 使某个缓存对象的缓存时间加长 + * @param cache {ACL_CACHE*} 缓存池对象句柄 + * @param info {ACL_CACHE_INFO*} 缓存对象 + * @param timeout {int} 缓存时长(秒) + */ +ACL_API void acl_cache_update2(ACL_CACHE *cache, ACL_CACHE_INFO *info, int timeout); + +/** + * 使某个缓存对象的缓存时间加长 + * @param cache {ACL_CACHE*} 缓存池对象句柄 + * @param key {const char*} 健值 + * @param timeout {int} 缓存时长(秒) + */ +ACL_API void acl_cache_update(ACL_CACHE *cache, const char *key, int timeout); + +/** + * 增加某缓存对象的引用计数,防止被提前删除 + * @param info {ACL_CACHE_INFO*} 用户对象所依附的缓存信息对象 + */ +ACL_API void acl_cache_refer(ACL_CACHE_INFO *info); + +/** + * 增加某缓存对象的引用计数,防止被提前删除 + * @param cache {ACL_CACHE*} 缓存池对象句柄 + * @param key {const char*} + */ +ACL_API void acl_cache_refer2(ACL_CACHE *cache, const char *key); + +/** + * 减少某缓存对象的引用计数 + * @param info {ACL_CACHE_INFO*} 用户对象所依附的缓存信息对象 + */ +ACL_API void acl_cache_unrefer(ACL_CACHE_INFO *info); + +/** + * 减少某缓存对象的引用计数 + * @param cache {ACL_CACHE*} 缓存池对象句柄 + * @param key {const char*} + */ +ACL_API void acl_cache_unrefer2(ACL_CACHE *cache, const char *key); + +/** + * 加锁缓存池对象,在多线程时用 + * @param cache {ACL_CACHE*} 缓存池对象句柄 + */ +ACL_API void acl_cache_lock(ACL_CACHE *cache); + +/** + * 解锁缓存池对象,在多线程时用 + * @param cache {ACL_CACHE*} 缓存池对象句柄 + */ +ACL_API void acl_cache_unlock(ACL_CACHE *cache); + +/** + * 遍历缓存中的所有对象 + * @param cache {ACL_CACHE*} 缓存池对象句柄 + * @param walk_fn {void (*)(ACL_CACHE_INFO*, void*)} 遍历回调函数 + * @param arg {void *} walk_fn()/2 中的第二个参数 + */ +ACL_API void acl_cache_walk(ACL_CACHE *cache, void (*walk_fn)(ACL_CACHE_INFO *, void *), void *arg); + +/** + * 清空缓存池中的缓存对象,如果某个缓存对象依然在被引用且非强制性删除,则将不会被清空 + * @param cache {ACL_CACHE*} 缓存池对象句柄 + * @param force {int} 如果非0,则即使某个缓存对象的引用计数非0也会被删除 + * @return {int} 被清除的缓存对象个数 + */ +ACL_API int acl_cache_clean(ACL_CACHE *cache, int force); + +/** + * 当前缓存池中缓存对象的个数 + * @param cache {ACL_CACHE*} 缓存池对象句柄 + * @return {int} 被缓存的对象个数 + */ +ACL_API int acl_cache_size(ACL_CACHE *cache); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/include/stdlib/acl_cache2.h b/lib_acl/include/stdlib/acl_cache2.h new file mode 100644 index 000000000..34003a6f2 --- /dev/null +++ b/lib_acl/include/stdlib/acl_cache2.h @@ -0,0 +1,194 @@ +#ifndef __ACL_CACHE2_INCLUDE_H__ +#define __ACL_CACHE2_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif +#include "acl_define.h" +#include + +/** + * 缓存池中存储的缓存对象 + */ +typedef struct ACL_CACHE2_INFO { + char *key; /**< 健值 */ + void *value; /**< 用户动态对象 */ + int nrefer; /**< 引用计数 */ + time_t when_timeout; /**< 过期时间截 */ +} ACL_CACHE2_INFO; + +/** + * 缓冲池 + */ +typedef struct ACL_CACHE2 { + int max_size; /**< 缓存池容量大小限制值 */ + int size; /**< 当前缓存池中的缓存对象个数 */ + + /**< 释放用户动态对象的释放回调函数 */ + void (*free_fn)(const ACL_CACHE2_INFO*, void *); + + /* for acl_iterator */ + + /* 取迭代器头函数 */ + void *(*iter_head)(ACL_ITER*, struct ACL_CACHE2*); + /* 取迭代器下一个函数 */ + void *(*iter_next)(ACL_ITER*, struct ACL_CACHE2*); + /* 取迭代器尾函数 */ + void *(*iter_tail)(ACL_ITER*, struct ACL_CACHE2*); + /* 取迭代器上一个函数 */ + void *(*iter_prev)(ACL_ITER*, struct ACL_CACHE2*); + /* 取迭代器关联的当前容器成员结构对象 */ + ACL_CACHE2_INFO *(*iter_info)(ACL_ITER*, struct ACL_CACHE2*); +} ACL_CACHE2; + +/** + * 创建一个缓存池,并设置每个缓存对象的最大缓存时长及该缓存池的空间容量限制 + * @param max_size {int} 该缓存池的容量限制 + * @param free_fn {void (*)(void*)} 用户级的释放缓存对象的函数 + * @return {ACL_CACHE2*} 缓存池对象句柄 + */ +ACL_API ACL_CACHE2 *acl_cache2_create(int max_size, + void (*free_fn)(const ACL_CACHE2_INFO*, void*)); + +/** + * 释放一个缓存池 + * @param cache2 {ACL_CACHE2*} 缓存池对象句柄 + */ +ACL_API void acl_cache2_free(ACL_CACHE2 *cache2); + +/** + * 向缓存池中添加被缓存的对象 + * @param cache2 {ACL_CACHE2*} 缓存池对象句柄 + * @param key {const char*} 缓存对象的健值 + * @param value {void*} 动态缓存对象 + * @param timeout {int} 每个缓存对象的缓存时长 + * @return {ACL_CACHE2_INFO*} 缓存对象所依附的结构对象,其中的 value 与用户的对象相同, + * 如果返回 NULL 则表示添加失败,失败原因为:缓存池太大溢出或相同健值的对象存在 + * 且引用计数非0; 如果返回非 NULL 则表示添加成功,如果对同一健值的重复添加,会用 + * 新的数据替换旧的数据,且旧数据调用释放函数进行释放 + */ +ACL_API ACL_CACHE2_INFO *acl_cache2_enter(ACL_CACHE2 *cache2, + const char *key, void *value, int timeout); + +/** + * 从缓存池中查找某个被缓存的对象 + * @param cache2 {ACL_CACHE2*} 缓存池对象句柄 + * @param key {const char*} 查询健 + * @return {void*} 被缓存的用户对象的地址,为NULL时表示未找到 + */ +ACL_API void *acl_cache2_find(ACL_CACHE2 *cache2, const char *key); + +/** + * 从缓存池中查找某个被缓存的对象所依附的缓存信息对象 + * @param cache2 {ACL_CACHE2*} 缓存池对象句柄 + * @param key {const char*} 查询健 + * @return {ACL_CACHE2_INFO*} 缓存信息对象地址,为NULL时表示未找到 + */ +ACL_API ACL_CACHE2_INFO *acl_cache2_locate(ACL_CACHE2 *cache2, const char *key); + +/** + * 从缓存池中删除某个缓存对象 + * @param cache2 {ACL_CACHE2*} 缓存池对象句柄 + * @param info {ACL_CACHE2_INFO*} 用户对象所依附的缓存信息对象 + * @return {int} 0: 表示删除成功; -1: 表示该对象的引用计数非0或该对象不存在 + */ +ACL_API int acl_cache2_delete(ACL_CACHE2 *cache2, ACL_CACHE2_INFO *info); + +/** + * 从缓存池中删除某个缓存对象 + * @param cache2 {ACL_CACHE2*} 缓存池对象句柄 + * @param key {const char*} 健值 + * @return {int} 0: 表示删除成功; -1: 表示该对象的引用计数非0或该对象不存在 + */ +ACL_API int acl_cache2_delete2(ACL_CACHE2 *cache2, const char *key); + +/** + * 使缓存池中的过期对象被自动删除 + * @param cache2 {ACL_CACHE2*} 缓存池对象句柄 + * @return {int} >= 0: 被自动删除的缓存对象的个数 + */ +ACL_API int acl_cache2_timeout(ACL_CACHE2 *cache2); + +/** + * 使某个缓存对象的缓存时间加长 + * @param cache2 {ACL_CACHE2*} 缓存池对象句柄 + * @param info {ACL_CACHE2_INFO*} 缓存对象 + * @param timeout {int} 缓存时长(秒) + */ +ACL_API void acl_cache2_update2(ACL_CACHE2 *cache2, ACL_CACHE2_INFO *info, int timeout); + +/** + * 使某个缓存对象的缓存时间加长 + * @param cache2 {ACL_CACHE2*} 缓存池对象句柄 + * @param key {const char*} 健值 + * @param timeout {int} 缓存时长(秒) + */ +ACL_API void acl_cache2_update(ACL_CACHE2 *cache2, const char *key, int timeout); + +/** + * 增加某缓存对象的引用计数,防止被提前删除 + * @param info {ACL_CACHE2_INFO*} 用户对象所依附的缓存信息对象 + */ +ACL_API void acl_cache2_refer(ACL_CACHE2_INFO *info); + +/** + * 增加某缓存对象的引用计数,防止被提前删除 + * @param cache2 {ACL_CACHE2*} 缓存池对象句柄 + * @param key {const char*} + */ +ACL_API void acl_cache2_refer2(ACL_CACHE2 *cache2, const char *key); + +/** + * 减少某缓存对象的引用计数 + * @param info {ACL_CACHE2_INFO*} 用户对象所依附的缓存信息对象 + */ +ACL_API void acl_cache2_unrefer(ACL_CACHE2_INFO *info); + +/** + * 减少某缓存对象的引用计数 + * @param cache2 {ACL_CACHE2*} 缓存池对象句柄 + * @param key {const char*} + */ +ACL_API void acl_cache2_unrefer2(ACL_CACHE2 *cache2, const char *key); + +/** + * 加锁缓存池对象,在多线程时用 + * @param cache2 {ACL_CACHE2*} 缓存池对象句柄 + */ +ACL_API void acl_cache2_lock(ACL_CACHE2 *cache2); + +/** + * 解锁缓存池对象,在多线程时用 + * @param cache2 {ACL_CACHE2*} 缓存池对象句柄 + */ +ACL_API void acl_cache2_unlock(ACL_CACHE2 *cache2); + +/** + * 遍历缓存中的所有对象 + * @param cache2 {ACL_CACHE2*} 缓存池对象句柄 + * @param walk_fn {void (*)(ACL_CACHE2_INFO*, void*)} 遍历回调函数 + * @param arg {void *} walk_fn()/2 中的第二个参数 + */ +ACL_API void acl_cache2_walk(ACL_CACHE2 *cache2, + void (*walk_fn)(ACL_CACHE2_INFO *, void *), void *arg); + +/** + * 清空缓存池中的缓存对象,如果某个缓存对象依然在被引用且非强制性删除,则将不会被清空 + * @param cache2 {ACL_CACHE2*} 缓存池对象句柄 + * @param force {int} 如果非0,则即使某个缓存对象的引用计数非0也会被删除 + * @return {int} 被清除的缓存对象个数 + */ +ACL_API int acl_cache2_clean(ACL_CACHE2 *cache2, int force); + +/** + * 当前缓存池中缓存对象的个数 + * @param cache2 {ACL_CACHE2*} 缓存池对象句柄 + * @return {int} 被缓存的对象个数 + */ +ACL_API int acl_cache2_size(ACL_CACHE2 *cache2); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/include/stdlib/acl_cfg_macro.h b/lib_acl/include/stdlib/acl_cfg_macro.h new file mode 100644 index 000000000..003848ebd --- /dev/null +++ b/lib_acl/include/stdlib/acl_cfg_macro.h @@ -0,0 +1,61 @@ + +#ifndef __ACL_CFG_MACRO_INCLUDE_H__ +#define __ACL_CFG_MACRO_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "acl_define.h" + +#include +#include +#include +#include + +#include "acl_msg.h" +#include "acl_xinetd_cfg.h" + +/** + * 从配置对象中取得某个配置项的值 + * @param _xcp_ {ACL_XINETD_CFG_PARSER*} 配置对象 + * @param _name_ {const char*} 配置项名 + * @param _obj_ {char*} 存储配置项的字符串类型的值 + */ +#define ACL_CFG_SET_ITEM_STR(_xcp_, _name_, _obj_) do { \ + ACL_XINETD_CFG_PARSER *_tmp_xcp_ = _xcp_; \ + const char *_ptr_; \ + _ptr_ = acl_xinetd_cfg_get(_tmp_xcp_, _name_); \ + if (_ptr_ && *_ptr_) { \ + _obj_ = acl_mystrdup(_ptr_); \ + if (_obj_ == NULL) \ + acl_msg_fatal("%s(%d): acl_mystrdup error=%s for %s", \ + __FILE__, __LINE__, \ + strerror(errno), _ptr_); \ + } \ +} while (0); + +/** + * 从配置对象中取得某个配置项的值 + * @param _xcp_ {ACL_XINETD_CFG_PARSER*} 配置对象 + * @param _name_ {const char*} 配置项名 + * @param _obj_ {int} 存储配置项的整数类型的值 + * @param _def_ {int} 如果配置项不存在,则用此缺省值 + */ +#define ACL_CFG_SET_ITEM_INT(_xcp_, _name_, _obj_, _def_) do { \ + ACL_XINETD_CFG_PARSER *_tmp_xcp_ = _xcp_; \ + const char *_ptr_; \ + _ptr_ = acl_xinetd_cfg_get(_tmp_xcp_, _name_); \ + if (_ptr_ && *_ptr_) { \ + _obj_ = atoi(_ptr_); \ + if (_obj_ <= 0) \ + _obj_ = _def_; \ + } else \ + _obj_ = _def_; \ +} while (0); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/include/stdlib/acl_chunk_chain.h b/lib_acl/include/stdlib/acl_chunk_chain.h new file mode 100644 index 000000000..eae376a7c --- /dev/null +++ b/lib_acl/include/stdlib/acl_chunk_chain.h @@ -0,0 +1,105 @@ +#ifndef __ACL_CHUNK_CHAIN_INCLUDE_H__ +#define __ACL_CHUNK_CHAIN_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "acl_define.h" + +/** + * 数据链类型定义 + */ +typedef struct ACL_CHAIN ACL_CHAIN; + +/** + * 创建一个数据链对象 + * @param init_size {size_t} 连续数据动态内存的初始尺寸大小 + * @param off_begin {acl_int64} 连续数据块的起始位置 + * @return {ACL_CHAIN*} 数据链对象 + */ +ACL_API ACL_CHAIN *acl_chain_new(size_t init_size, acl_int64 off_begin); + +/** + * 释放数据链对象 + * @param chain {ACL_CHAIN*} 数据链对象 + */ +ACL_API void acl_chain_free(ACL_CHAIN *chain); + +/** + * 设置连续数据块的下一个偏移位置 + * @param chain {ACL_CHAIN*} 数据链对象 + * @param from_next {acl_int64} 连续数据块的下一个偏移位置 + */ +ACL_API void acl_chain_set_from_next(ACL_CHAIN *chain, acl_int64 from_next); + +/** + * 重置数据链对象,并将起始位置重置为给定值 + * @param chain {ACL_CHAIN*} 数据链对象 + * @param off_begin {acl_int64} 给定连接数据块的起始位置 + */ +ACL_API void acl_chain_reset(ACL_CHAIN *chain, acl_int64 off_begin); + +/** + * 获得当前数据链对象中连续数据块中的下一个位置 + * @param chain {ACL_CHAIN*} 数据链对象 + * @return {acl_int64} 连接数据块的下一个位置 + */ +ACL_API acl_int64 acl_chain_from_next(ACL_CHAIN *chain); + +/** + * 获得当前数据链对象的起始位置 + * @param chain {ACL_CHAIN*} 数据链对象 + * @return {acl_int64} 数据链的起始位置 + */ +ACL_API acl_int64 acl_chain_off_begin(ACL_CHAIN *chain); + +/** + * 获得当前数据链中连续数据块的起始存储指针地址 + * @param chain {ACL_CHAIN*} 数据链对象 + * @return {const char*} 连续数据块的起始存储指针地址 + */ +ACL_API const char *acl_chain_data(ACL_CHAIN *chain); + +/** + * 获得当前数据链中连续数据块的数据长度 + * @param chain {ACL_CHAIN*} 数据链对象 + * @return {int} 连续数据块的数据长度 + */ +ACL_API int acl_chain_data_len(ACL_CHAIN *chain); + +/** + * 当前数据链中非连续数据块的个数 + * @param chain {ACL_CHAIN*} 数据链对象 + * @return {int} 非连续数据块的个数 + */ +ACL_API int acl_chain_size(ACL_CHAIN *chain); + +/** + * 获得当前数据链中非连续数据块的所有数据总长度 + * @param chain {ACL_CHAIN*} 数据链对象 + * @return {int} 非连续数据块的总长度 + */ +ACL_API int acl_chain_chunk_data_len(ACL_CHAIN *chain); + +/** + * 向数据链中添加一个数据块,内部自动去掉重叠数据 + * @param chain {ACL_CHAIN*} 数据链对象 + * @param data {const void*} 数据块指针 + * @param from {acl_int64} 该新数据块的起始位置 + * @param dlen {int} 数据块的长度 + */ +ACL_API void acl_chain_add(ACL_CHAIN *chain, const void *data, + acl_int64 from, int dlen); + +/** + * 打印输出当前数据链的连续数据块及非连续数据块的起始位置信息 + * @param chain {ACL_CHAIN*} 数据链对象 + */ +ACL_API void acl_chain_list(ACL_CHAIN *chain); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/include/stdlib/acl_dbuf_pool.h b/lib_acl/include/stdlib/acl_dbuf_pool.h new file mode 100644 index 000000000..eb837fbe3 --- /dev/null +++ b/lib_acl/include/stdlib/acl_dbuf_pool.h @@ -0,0 +1,26 @@ +#ifndef __ACL_DBUF_POOL_INCLUDE_H__ +#define __ACL_DBUF_POOL_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct ACL_DBUF_POOL ACL_DBUF_POOL; + +/* public */ +ACL_API ACL_DBUF_POOL *acl_dbuf_pool_create(int block_size); +ACL_API void acl_dbuf_pool_destroy(ACL_DBUF_POOL *pool); +ACL_API void acl_dbuf_pool_free(ACL_DBUF_POOL *pool, void *ptr, int length); +ACL_API void *acl_dbuf_pool_alloc(ACL_DBUF_POOL *pool, int length); +ACL_API void *acl_dbuf_pool_calloc(ACL_DBUF_POOL *pool, int length); +ACL_API void *acl_dbuf_pool_memdup(ACL_DBUF_POOL *pool, const void *s, size_t len); +ACL_API char *acl_dbuf_pool_strdup(ACL_DBUF_POOL *pool, const char *s); + +/* private */ +ACL_API void acl_dbuf_pool_test(size_t max); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/include/stdlib/acl_debug.h b/lib_acl/include/stdlib/acl_debug.h new file mode 100644 index 000000000..0b1e5fb87 --- /dev/null +++ b/lib_acl/include/stdlib/acl_debug.h @@ -0,0 +1,56 @@ +#ifndef __ACL_DEBUG_INCLUDE_H__ +#define __ACL_DEBUG_INCLUDE_H__ + +#include "acl_define.h" +#include "acl_msg.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ACL_DEBUG_INTER_BASE 0 /**< 最小调试标签值 */ +#define ACL_DEBUG_WQ (ACL_DEBUG_INTER_BASE + 1) /**< ACL_WORKQ 调试标签 */ +#define ACL_DEBUG_PROCTL (ACL_DEBUG_INTER_BASE + 2) /**< ACL_PROCTL 调试标签 */ +#define ACL_DEBUG_THR_POOL (ACL_DEBUG_INTER_BASE + 3) /**< ACL_PTHREAD_POOL 调试标签 */ +#define ACL_DEBUG_EVENT (ACL_DEBUG_INTER_BASE + 4) /**< ACL_EVENT 调度标签 */ + +/** + * 日志调试宏接口 + * @param SECTION {int} 调试标签值 + * @param LEVEL {int} 对应于SECTION调试标签的级别 + */ +#define acl_debug(SECTION, LEVEL) \ + !acl_do_debug((SECTION), (LEVEL)) ? (void) 0 : acl_msg_info + +/** + * 释放内部一些内存等资源 + */ +ACL_API void acl_debug_end(void); + +/** + * 初始化日志调试调用接口 + * @param pStr {const char*} 调试标签及级别字符串, + * 格式: 1,1; 2,10; 3,8... or 1:1; 2:10; 3:8... + */ +ACL_API void acl_debug_init(const char *pStr); + +/** + * 初始化日志调试调用接口 + * @param pStr {const char*} 调试标签及级别字符串, + * 格式: 1,1; 2,10; 3,8... or 1:1; 2:10; 3:8... + * @param max_debug_level {int} 最大调试标签值 + */ +ACL_API void acl_debug_init2(const char *pStr, int max_debug_level); + +/** + * 判断给定标签的级别是否在日志输出条件范围内 + * @param section {int} 标签值 + * @param level {int} 级别值 + */ +ACL_API int acl_do_debug(int section, int level); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/include/stdlib/acl_debug_malloc.h b/lib_acl/include/stdlib/acl_debug_malloc.h new file mode 100644 index 000000000..896267c15 --- /dev/null +++ b/lib_acl/include/stdlib/acl_debug_malloc.h @@ -0,0 +1,20 @@ +#ifndef __ACL_DEBUG_MALLOC_INCLUDE_H__ +#define __ACL_DEBUG_MALLOC_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "acl_define.h" + +typedef struct ACL_DEBUG_MEM ACL_DEBUG_MEM; + +ACL_API void acl_debug_dump(void); +ACL_API ACL_DEBUG_MEM *acl_debug_malloc_init(ACL_DEBUG_MEM *debug_mem_ptr, + const char* dump_file); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/include/stdlib/acl_define.h b/lib_acl/include/stdlib/acl_define.h new file mode 100644 index 000000000..9eb8f8ebe --- /dev/null +++ b/lib_acl/include/stdlib/acl_define.h @@ -0,0 +1,58 @@ +#ifndef __ACL_DEFINE_INCLUDE_H__ +#define __ACL_DEFINE_INCLUDE_H__ + +#include "acl_define_win32.h" +#include "acl_define_unix.h" + +typedef acl_int64 acl_off_t; +typedef struct acl_stat acl_stat_t; + +/* + * Making the ctype.h macros not more expensive than necessary. On some + * systems, ctype.h misbehaves with non-ASCII and/or negative characters. + */ + +#include + +#define _ACL_UCHAR_(c) ((unsigned char)(c)) + +#ifdef UNSAFE_CTYPE +#define ACL_ISASCII(c) isascii(_ACL_UCHAR_(c)) +#define ACL_ISALNUM(c) (ISASCII(c) && isalnum(c)) +#define ACL_ISALPHA(c) (ISASCII(c) && isalpha(c)) +#define ACL_ISCNTRL(c) (ISASCII(c) && iscntrl(c)) +#define ACL_ISDIGIT(c) (ISASCII(c) && isdigit(c)) +#define ACL_ISGRAPH(c) (ISASCII(c) && isgraph(c)) +#define ACL_ISLOWER(c) (ISASCII(c) && islower(c)) +#define ACL_ISPRINT(c) (ISASCII(c) && isprint(c)) +#define ACL_ISPUNCT(c) (ISASCII(c) && ispunct(c)) +#define ACL_ISSPACE(c) (ISASCII(c) && isspace(c)) +#define ACL_ISUPPER(c) (ISASCII(c) && isupper(c)) +#define ACL_TOLOWER(c) (ISUPPER(c) ? tolower(c) : (c)) +#define ACL_TOUPPER(c) (ISLOWER(c) ? toupper(c) : (c)) +#else +#define ACL_ISASCII(c) isascii(_ACL_UCHAR_(c)) +#define ACL_ISALNUM(c) isalnum(_ACL_UCHAR_(c)) +#define ACL_ISALPHA(c) isalpha(_ACL_UCHAR_(c)) +#define ACL_ISCNTRL(c) iscntrl(_ACL_UCHAR_(c)) +#define ACL_ISDIGIT(c) isdigit(_ACL_UCHAR_(c)) +#define ACL_ISGRAPH(c) isgraph(_ACL_UCHAR_(c)) +#define ACL_ISLOWER(c) islower(_ACL_UCHAR_(c)) +#define ACL_ISPRINT(c) isprint(_ACL_UCHAR_(c)) +#define ACL_ISPUNCT(c) ispunct(_ACL_UCHAR_(c)) +#define ACL_ISSPACE(c) isspace(_ACL_UCHAR_(c)) +#define ACL_ISUPPER(c) isupper(_ACL_UCHAR_(c)) +#define ACL_TOLOWER(c) tolower(_ACL_UCHAR_(c)) +#define ACL_TOUPPER(c) toupper(_ACL_UCHAR_(c)) +#endif + +#ifndef acl_unused +# ifdef __GNUC__ +# define acl_unused __attribute__ ((__unused__)) +# else +# define acl_unused /* Ignore */ +# endif +#endif + +#endif /* __ACL_DEFINE_INCLUDE_H__ */ + diff --git a/lib_acl/include/stdlib/acl_define_bsd.h b/lib_acl/include/stdlib/acl_define_bsd.h new file mode 100644 index 000000000..98d424025 --- /dev/null +++ b/lib_acl/include/stdlib/acl_define_bsd.h @@ -0,0 +1,40 @@ +#ifndef __ACL_DEFINE_BSD_INCLUDE_H__ +#define __ACL_DEFINE_BSD_INCLUDE_H__ + +#ifdef FREEBSD +# define ACL_UNIX +# define ACL_FREEBSD + +# include +# define ACL_USE_PATHS_H +# define ACL_HAS_FLOCK_LOCK +# define ACL_HAS_FCNTL_LOCK +# define ACL_INTERNAL_LOCK ACL_MYFLOCK_STYLE_FLOCK +# define ACL_ROOT_PATH "/bin:/usr/bin:/sbin:/usr/sbin" +# define ACL_PATH_MAILDIR "/var/mail" +# define ACL_PATH_BSHELL "/bin/sh" +# define ACL_PATH_DEFPATH "/usr/bin:/usr/bsd" +# define ACL_PATH_STDPATH "/usr/bin:/usr/sbin:/usr/bsd" + +# define ACL_HAVE_NO_STAT64 + +# ifdef ACL_HAVE_NO_STAT64 +# define acl_stat stat +# define acl_fstat fstat +# else +# define acl_stat stat64 +# define acl_fstat fstat64 +# endif + +# ifndef ACL_WAIT_STATUS_T + typedef int ACL_WAIT_STATUS_T; +# define ACL_NORMAL_EXIT_STATUS(status) ((status) == 0) +# endif + +# define ACL_FIONREAD_IN_TERMIOS_H +# define ACL_HAVE_NO_RWLOCK + +#endif + +#endif /* __ACL_DEFINE_BSD_INCLUDE_H__ */ + diff --git a/lib_acl/include/stdlib/acl_define_linux.h b/lib_acl/include/stdlib/acl_define_linux.h new file mode 100644 index 000000000..a7e4a33c5 --- /dev/null +++ b/lib_acl/include/stdlib/acl_define_linux.h @@ -0,0 +1,59 @@ +#ifndef __ACL_DEFINE_LINUX_INCLUDE_H__ +#define __ACL_DEFINE_LINUX_INCLUDE_H__ + +#ifdef LINUX2 +# define ACL_LINUX +# define ACL_UNIX + +#include /* just for size_t */ + +/* for O_LARGEFILE flag define */ +# ifndef _GNU_SOURCE +# ifndef _LARGEFILE64_SOURCE +# define _LARGEFILE64_SOURCE +# endif +# ifndef _FILE_OFFSET_BITS +# define _FILE_OFFSET_BITS 64 +# endif +# endif + +/* +# include +# include +# include +# include +*/ + +# ifndef ACL_HAS_SPINLOCK +# define ACL_HAS_SPINLOCK +# endif +# define ACL_USE_PATHS_H +# define ACL_HAS_FLOCK_LOCK +# define ACL_HAS_FCNTL_LOCK +# define ACL_INTERNAL_LOCK ACL_MYFLOCK_STYLE_FLOCK +# define ACL_ROOT_PATH "/bin:/usr/bin:/sbin:/usr/sbin" +# define ACL_PATH_MAILDIR "/var/mail" +# define ACL_PATH_BSHELL "/bin/sh" +# define ACL_PATH_DEFPATH "/usr/bin" +# define ACL_PATH_STDPATH "/usr/bin:/usr/sbin" + +# ifdef ACL_HAVE_NO_STAT64 +# define acl_stat stat +# define acl_fstat fstat +# else +# define acl_stat stat64 +# define acl_fstat fstat64 +# endif + +# ifndef ACL_WAIT_STATUS_T + typedef int ACL_WAIT_STATUS_T; +# define ACL_NORMAL_EXIT_STATUS(status) ((status) == 0) +# endif + +# define ACL_FIONREAD_IN_TERMIOS_H +# define ACL_HAVE_NO_RWLOCK + +#endif + +#endif /* __ACL_DEFINE_LINUX_INCLUDE_H__ */ + diff --git a/lib_acl/include/stdlib/acl_define_macosx.h b/lib_acl/include/stdlib/acl_define_macosx.h new file mode 100644 index 000000000..e0c8621fd --- /dev/null +++ b/lib_acl/include/stdlib/acl_define_macosx.h @@ -0,0 +1,40 @@ +#ifndef __ACL_DEFINE_MACOSX_INCLUDE_H__ +#define __ACL_DEFINE_MACOSX_INCLUDE_H__ + +#ifdef MACOSX +# define ACL_UNIX +# define ACL_MACOSX + +# include +# define ACL_USE_PATHS_H +# define ACL_HAS_FLOCK_LOCK +# define ACL_HAS_FCNTL_LOCK +# define ACL_INTERNAL_LOCK ACL_MYFLOCK_STYLE_FLOCK +# define ACL_ROOT_PATH "/bin:/usr/bin:/sbin:/usr/sbin" +# define ACL_PATH_MAILDIR "/var/mail" +# define ACL_PATH_BSHELL "/bin/sh" +# define ACL_PATH_DEFPATH "/usr/bin:/usr/bsd" +# define ACL_PATH_STDPATH "/usr/bin:/usr/sbin:/usr/bsd" + +# define ACL_HAVE_NO_STAT64 + +# ifdef ACL_HAVE_NO_STAT64 +# define acl_stat stat +# define acl_fstat fstat +# else +# define acl_stat stat64 +# define acl_fstat fstat64 +# endif + +# ifndef ACL_WAIT_STATUS_T + typedef int ACL_WAIT_STATUS_T; +# define ACL_NORMAL_EXIT_STATUS(status) ((status) == 0) +# endif + +# define ACL_FIONREAD_IN_TERMIOS_H +# define ACL_HAVE_NO_RWLOCK + +#endif + +#endif /* __ACL_DEFINE_MACOSX_INCLUDE_H__ */ + diff --git a/lib_acl/include/stdlib/acl_define_sunx86.h b/lib_acl/include/stdlib/acl_define_sunx86.h new file mode 100644 index 000000000..d46366e4b --- /dev/null +++ b/lib_acl/include/stdlib/acl_define_sunx86.h @@ -0,0 +1,40 @@ +#ifndef __ACL_DEFINE_SUNX86_INCLUDE_H__ +#define __ACL_DEFINE_SUNX86_INCLUDE_H__ + +#ifdef SUNOS5 +# define ACL_SUNOS5 +# define ACL_UNIX + +# include +/* # include */ + +# ifdef ACL_HAVE_NO_STAT64 +# define acl_stat stat +# define acl_fstat fstat +# else +# define acl_stat stat64 +# define acl_fstat fstat64 +# endif + +# define ACL_USE_PATHS_H +/* # define ACL_HAS_FLOCK_LOCK */ + +# define ACL_HAS_FCNTL_LOCK +/*# define ACL_INTERNAL_LOCK ACL_MYFLOCK_STYLE_FLOCK */ +# define ACL_INTERNAL_LOCK ACL_MYFLOCK_STYLE_FCNTL + +# define ACL_ROOT_PATH "/bin:/usr/bin:/sbin:/usr/sbin" +# define ACL_PATH_MAILDIR "/var/mail" +# define ACL_PATH_DEFPATH "/usr/bin:/usr/ucb" +# define ACL_PATH_STDPATH "/usr/bin:/usr/etc:/usr/ucb" + +# ifndef ACL_WAIT_STATUS_T + typedef int ACL_WAIT_STATUS_T; +# define ACL_NORMAL_EXIT_STATUS(status) ((status) == 0) +# endif + +# define ACL_FIONREAD_IN_SYS_FILIO_H + +#endif + +#endif /* __ACL_DEFINE_SUNX86_INCLUDE_H__ */ diff --git a/lib_acl/include/stdlib/acl_define_unix.h b/lib_acl/include/stdlib/acl_define_unix.h new file mode 100644 index 000000000..9caa5351c --- /dev/null +++ b/lib_acl/include/stdlib/acl_define_unix.h @@ -0,0 +1,81 @@ +#ifndef __ACL_DEFINE_UNIX_INCLUDE_H__ +#define __ACL_DEFINE_UNIX_INCLUDE_H__ + +#include "acl_define_linux.h" +#include "acl_define_sunx86.h" +#include "acl_define_bsd.h" +#include "acl_define_macosx.h" + +/* __FreeBSD_version version is major+minor */ + +#if __FreeBSD_version >= 200000 +# define HAS_DUPLEX_PIPE +#endif + +#ifdef __FreeBSD_kernel__ +# define HAS_DUPLEX_PIPE +# define HAS_ISSETUGID +#endif + +#ifdef ACL_UNIX +/* +# include +*/ + +# ifndef c_pathdelim_chr +# define c_pathdelim_chr '/' +# endif + +/* +# include +*/ +# define ACL_HAS_PTHREAD + +#endif /* ACL_UNIX */ + +#ifdef ACL_UNIX + +# include +# ifndef acl_assert +# define acl_assert assert +# endif + +# define ACL_API + +# define ACL_ETIMEDOUT ETIMEDOUT +# define ACL_ENOMEM ENOMEM +# define ACL_EINVAL EINVAL + +# define ACL_ECONNREFUSED ECONNREFUSED +# define ACL_ECONNRESET ECONNRESET +# define ACL_EHOSTDOWN EHOSTDOWN +# define ACL_EHOSTUNREACH EHOSTUNREACH +# define ACL_EINTR EINTR +# define ACL_EAGAIN EAGAIN +# define ACL_ENETDOWN ENETDOWN +# define ACL_ENETUNREACH ENETUNREACH +# define ACL_ENOTCONN ENOTCONN +# define ACL_EISCONN EISCONN +# define ACL_EWOULDBLOCK EWOULDBLOCK +# define ACL_ENOBUFS ENOBUFS +# define ACL_ECONNABORTED ECONNABORTED +# define ACL_EINPROGRESS EINPROGRESS + +# define ACL_SOCKET int +# define ACL_FILEFD int +# define ACL_SOCKET_INVALID (int) -1 +# define ACL_FILE_HANDLE int +# define ACL_FILE_INVALID (int) -1 +# define ACL_DLL_HANDLE void* +# define ACL_DLL_FARPROC void* + +# define acl_int64 long long int +# define acl_uint64 unsigned long long int +# define ACL_FMT_I64D "%lld" +# define ACL_FMT_I64U "%llu" + +# define ACL_PATH_BSHELL "/bin/sh" + +#endif /* ACL_UNIX */ + +#endif diff --git a/lib_acl/include/stdlib/acl_define_win32.h b/lib_acl/include/stdlib/acl_define_win32.h new file mode 100644 index 000000000..d410fd321 --- /dev/null +++ b/lib_acl/include/stdlib/acl_define_win32.h @@ -0,0 +1,139 @@ +#ifndef __ACL_DEFINE_WIN32_INCLUDE_H__ +#define __ACL_DEFINE_WIN32_INCLUDE_H__ + +#if defined (MS_VC) || defined(MS_VC6) +# define ACL_MS_WINDOWS +# define ACL_MS_VC +# ifndef _CRT_SECURE_NO_WARNINGS +# define _CRT_SECURE_NO_WARNINGS +# endif +#elif defined(BORLAND_CB) +# define ACL_MS_WINDOWS +# define ACL_BCB_COMPILER +#elif defined(WIN32) +# define ACL_MS_WINDOWS +# define ACL_MS_VC +#endif + +#ifdef ACL_MS_WINDOWS + +# ifdef acl_assert +# undef acl_assert +# endif +# define acl_assert(x) do \ + { \ + if (!(x)) \ + abort(); \ + } while(0) + +# ifdef ACL_DLL +# ifdef ACL_EXPORTS +# define ACL_API __declspec(dllexport) +# else +# define ACL_API __declspec(dllimport) +# endif +# else +# define ACL_API +# endif + +# include +# include +# include + +# ifndef ACL_WIN32_STDC +# define ACL_WIN32_STDC +# endif +# ifndef FD_SETSIZE +# define FD_SETSIZE 4096 /* see WINSOCK2.H, 用户需要预先定义此值,因其默认值为64 */ +# endif +/* # include */ +/* # include */ +# if(_MSC_VER >= 1300) +# include +# include +# else +# include +# endif + +# ifdef ACL_BCB_COMPILER +# pragma hdrstop +# endif +# define _USE_FAST_MACRO +# define _USE_HTABLE_SEARCH + +# ifndef c_pathdelim_chr +# define c_pathdelim_chr '\\' +# endif + +# undef ACL_HAS_PTHREAD +#endif /* ACL_MS_WINDOWS */ + +/* errno define */ +#ifdef ACL_MS_WINDOWS +# define ACL_ETIMEDOUT WSAETIMEDOUT +# define ACL_ENOMEM WSAENOBUFS +# define ACL_EINVAL WSAEINVAL + +# define ACL_ECONNREFUSED WSAECONNREFUSED +# define ACL_ECONNRESET WSAECONNRESET +# define ACL_EHOSTDOWN WSAEHOSTDOWN +# define ACL_EHOSTUNREACH WSAEHOSTUNREACH +# define ACL_EINTR WSAEINTR +# define ACL_ENETDOWN WSAENETDOWN +# define ACL_ENETUNREACH WSAENETUNREACH +# define ACL_ENOTCONN WSAENOTCONN +# define ACL_EISCONN WSAEISCONN +# define ACL_EWOULDBLOCK WSAEWOULDBLOCK +# define ACL_EAGAIN ACL_EWOULDBLOCK /* xxx */ +# define ACL_ENOBUFS WSAENOBUFS +# define ACL_ECONNABORTED WSAECONNABORTED +# define ACL_EINPROGRESS WSAEINPROGRESS + +# define ACL_SOCKET SOCKET +# define ACL_FILEFD unsigned int +# define socklen_t int +# define ACL_SOCKET_INVALID INVALID_SOCKET +# define ACL_FILE_HANDLE HANDLE +# define ACL_FILE_INVALID INVALID_HANDLE_VALUE +# define ACL_DLL_HANDLE HINSTANCE +# define ACL_DLL_FARPROC FARPROC +# ifndef HAS_SSIZE_T +# define ssize_t long +# endif + +# define ACL_INTERNAL_LOCK ACL_MYFLOCK_STYLE_FLOCK + +# define acl_int64 __int64 +# define acl_uint64 unsigned __int64 +# define ACL_FMT_I64D "%I64d" +# define ACL_FMT_I64U "%I64u" + +# ifdef ACL_BCB_COMPILER +/* # define acl_stat _tstati64 */ +# define acl_stat stati64 +# else +# ifdef ACL_HAVE_NO_STAT64 +# define acl_stat _stat +# define acl_fstat _fstat +# else +# define acl_stat _stati64 +# endif +# endif + +ACL_API int acl_fstat(ACL_FILE_HANDLE fh, struct acl_stat *buf); + +/* 线程局部变量 */ +# if defined(ACL_BCB_COMPILER) +# define __thread +# else +# define __thread __declspec(thread) +# endif + +/* +# ifdef ACL_BCB_COMPILER +# define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +# endif +*/ +#endif /* ACL_MS_WINDOWS */ + +#endif /* __ACL_DEFINE_WIN32_INCLUDE_H__ */ diff --git a/lib_acl/include/stdlib/acl_dir.h b/lib_acl/include/stdlib/acl_dir.h new file mode 100644 index 000000000..c07474c98 --- /dev/null +++ b/lib_acl/include/stdlib/acl_dir.h @@ -0,0 +1,88 @@ +#ifndef __ACL_DIR_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "acl_define.h" + +#ifdef ACL_MS_VC + +#if !defined(_UNICODE) + +/** + * dirent structure returned by readdir(). + */ +struct dirent { + char d_name[260]; +}; + +/** + * DIR type returned by opendir(). The members of this structure + * must not be accessed by application programs. + */ +typedef struct { + unsigned long _d_hdir; /**< directory handle */ + char *_d_dirname; /**< directory name */ + unsigned _d_magic; /**< magic cookie for verifying handle */ + unsigned _d_nfiles; /**< no. of files remaining in buf */ + char _d_buf[sizeof(WIN32_FIND_DATA)]; /**< buffer for a single file */ +} DIR; + +/** + * Prototypes. + */ +ACL_API DIR *opendir(const char *dirname); +ACL_API struct dirent *readdir(DIR *dir); +ACL_API int closedir(DIR *dir); +ACL_API void rewinddir(DIR *dir); + +/* @: directory functions */ + +#define _topendir opendir +#define _treaddir readdir +#define _trewinddir rewinddir +#define _tclosedir closedir +#define _tDIR DIR +#define _tdirent dirent + +#else /* _UNICODE */ + +/* wdirent structure returned by wreaddir(). +*/ +struct wdirent { + wchar_t d_name[260]; +}; + +typedef struct { + unsigned long _d_hdir; /**< directory handle */ + wchar_t *_d_dirname; /**< directory name */ + unsigned _d_magic; /**< magic cookie for verifying handle */ + unsigned _d_nfiles; /**< no. of files remaining in buf */ + char _d_buf[sizeof(WIN32_FIND_DATA)]; /**< buffer for a single file */ +} wDIR; + +ACL_API wDIR *wopendir(const wchar_t *dirname); +ACL_API struct wdirent *wreaddir(wDIR *dir); +ACL_API int wclosedir (wDIR *dir); +ACL_API void wrewinddir(wDIR *dir); + +/* @: directory functions */ + +#define _topendir wopendir +#define _treaddir wreaddir +#define _trewinddir wrewinddir +#define _tclosedir wclosedir +#define _tDIR wDIR +#define _tdirent wdirent + +#endif /* _UNICODE */ + +#endif /* ACL_MS_VC */ + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/include/stdlib/acl_dlink.h b/lib_acl/include/stdlib/acl_dlink.h new file mode 100644 index 000000000..3f5999aa5 --- /dev/null +++ b/lib_acl/include/stdlib/acl_dlink.h @@ -0,0 +1,190 @@ +#ifndef __ACL_DLINK_INCLUDE__ +#define __ACL_DLINK_INCLUDE__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "acl_define.h" +#include "acl_array.h" +#include "acl_iterator.h" + +/** + * 二分块数据链元素类型定义 + */ +typedef struct { + acl_uint64 begin; + acl_uint64 end; + void *pnode; +} ACL_DITEM; + +/** + * 二分块数据链类型定义 + */ +typedef struct ACL_DLINK { + ACL_ARRAY *parray; + void *call_back_data; + + /* for acl_iterator */ + + /* 取迭代器头函数 */ + void *(*iter_head)(ACL_ITER*, struct ACL_DLINK*); + /* 取迭代器下一个函数 */ + void *(*iter_next)(ACL_ITER*, struct ACL_DLINK*); + /* 取迭代器尾函数 */ + void *(*iter_tail)(ACL_ITER*, struct ACL_DLINK*); + /* 取迭代器上一个函数 */ + void *(*iter_prev)(ACL_ITER*, struct ACL_DLINK*); +} ACL_DLINK; + +/** + * 创建一个二分块数据链对象 + * @param nsize {int} 初始数组大小 + * @return {ACL_DLINK*} 二分块数据链对象 + */ +ACL_API ACL_DLINK *acl_dlink_create(int nsize); + +/** + * 释放一个二分块数据链对象 + * @param plink {ACL_DLINK*} 二分块数据链对象指针 + */ +ACL_API void acl_dlink_free(ACL_DLINK *plink); + +/** + * 根据二分块数据元素查找其是否正在于二分块数据链中 + * @param plink {ACL_DLINK*} 二分块数据链对象指针 + * @param pitem {ACL_DITEM*} 数据块元素 + * @return {ACL_DITEM*} 数据块元素 + */ +ACL_API ACL_DITEM *acl_dlink_lookup_by_item(const ACL_DLINK *plink, + ACL_DITEM *pitem); + +/** + * 根据数据元素查找二分块数据链中的数据元素 + * @param plink {const ACL_DLINK*} 二分块数据链对象指针 + * @param pitem {ACL_DITEM*} 数据块元素 + * @param pidx {int*} 存储查询数据元素结果在二分数据链中的下标位置 + * @return {ACL_DITEM*} 数据块元素 + */ +ACL_API ACL_DITEM *acl_dlink_lookup2_by_item(const ACL_DLINK *plink, + ACL_DITEM *pitem, int *pidx); + +/** + * 从二分块数据链中查询某个值所对应的数据块元素地址 + * @param plink {const ACL_DLINK*} 二分块数据链对象指针 + * @param n {acl_uint64} 查询值 + * @return {ACL_DITEM*} 数据块元素 + */ +ACL_API ACL_DITEM *acl_dlink_lookup(const ACL_DLINK *plink, acl_uint64 n); + +/** + * 从二分块数据链中查询某个值所对应的数据块元素地址并记录其下标位置 + * @param plink {const ACL_DLINK*} 二分块数据链对象指针 + * @param n {acl_uint64} 查询值 + * @param pidx {int*} 存储查询数据元素结果在二分数据链中的下标位置 + * @return {ACL_DITEM*} 数据块元素 + */ +ACL_API ACL_DITEM *acl_dlink_lookup2(const ACL_DLINK *plink, + acl_uint64 n, int *pidx); + +/** + * 从二分块数据链中查询某个范围的数据块元素地址并记录其下标位置 + * @param plink {const ACL_DLINK*} 二分块数据链对象指针 + * @param begin {acl_uint64} 查询范围的起始位置值 + * @param end {acl_uint64} 查询范围的结束位置值 + * @param pidx {int*} 存储查询数据元素结果在二分数据链中的下标位置 + * @return {ACL_DITEM*} 数据块元素 + */ +ACL_API ACL_DITEM *acl_dlink_lookup_range(const ACL_DLINK *plink, + acl_uint64 begin, acl_uint64 end, int *pidx); + +/** + * 从二分块数据链中查询第一个大于某个给定值的数据块元素并记录下标位置 + * @param plink {const ACL_DLINK*} 二分块数据链对象指针 + * @param off {acl_uint64} 给定比较值 + * @param pidx {int*} 存储查询数据元素结果在二分数据链中的下标位置 + * @return {ACL_DITEM*} 数据块元素 + */ +ACL_API ACL_DITEM *acl_dlink_lookup_larger(const ACL_DLINK *plink, + acl_uint64 off, int *pidx); + +/** + * 从二分块数据链中查询第一个小于某个给定值的数据块元素并记录下标位置 + * @param plink {const ACL_DLINK*} 二分块数据链对象指针 + * @param off {acl_uint64} 给定比较值 + * @param pidx {int*} 存储查询数据元素结果在二分数据链中的下标位置 + * @return {ACL_DITEM*} 数据块元素 + */ +ACL_API ACL_DITEM *acl_dlink_lookup_lower(const ACL_DLINK *plink, + acl_uint64 off, int *pidx); + +/** + * 向二分块数据链中添加起始、结束数据块 + * @param plink {ACL_DLINK*} 二分块数据链对象指针 + * @param begin {acl_uint64} 给定起始位置值 + * @param end {acl_uint64} 给定结束位置值 + * @return {ACL_DITEM*} 新创建的数据块元素 + */ +ACL_API ACL_DITEM *acl_dlink_insert(ACL_DLINK *plink, + acl_uint64 begin, acl_uint64 end); + +/** + * 从二分块数据链中删除包含某个给定值的数据块元素 + * @param plink {ACL_DLINK*} 二分块数据链对象指针 + * @param n {acl_uint64} 给定位置值 + * @return {int} 0:表示OK,-1: 表示输入参数非法或不存在 + */ +ACL_API int acl_dlink_delete(ACL_DLINK *plink, acl_uint64 n); + +/** + * 根据数据块元素从二分块数据链中删除该数据块元素 + * @param plink {ACL_DLINK*} 二分块数据链对象指针 + * @param pitem {ACL_DITEM*} 数据块元素 + * @return {int} 0:表示OK,-1: 表示输入参数非法 + */ +ACL_API int acl_dlink_delete_by_item(ACL_DLINK *plink, ACL_DITEM *pitem); + +/** + * 功能同 acl_dlink_insert + * @deprecated 此函数将来也许不再提供 + */ +ACL_API ACL_DITEM *acl_dlink_modify(ACL_DLINK *plink, + acl_uint64 begin, acl_uint64 end); + +/** + * 从二分数据链中删除某个数值范围的数据块集合, + * 删除后有可能会在内部增加新的数据块元素 + * @param plink {ACL_DLINK*} 二分块数据链对象指针 + * @param begin {acl_uint64} 需要删除范围的起始位置 + * @param end {acl_uint64} 需要删除范围的结束位置 + * @return {int} 0:表示OK,-1: 表示输入参数非法 + */ +ACL_API int acl_dlink_delete_range(ACL_DLINK *plink, + acl_uint64 begin, acl_uint64 end); + +/** + * 返回某下标位置的数据块元素地址 + * @param plink {const ACL_DLINK*} 二分块数据链对象指针 + * @param idx {int} 下标位置 + * @return {ACL_DITEM*} NULL: 下标越界; != NULL: 数据块元素地址 + */ +ACL_API ACL_DITEM *acl_dlink_index(const ACL_DLINK *plink, int idx); + +/** + * 获得当前二分数据链中所有数据块的个数总和 + * @param plink {const ACL_DLINK*} 二分块数据链对象指针 + * @return {int} 数据块的个数 + */ +ACL_API int acl_dlink_size(const ACL_DLINK *plink); + +/** + * (调试用)打印二分数据链中所有数据块的起始、结束位置等信息 + * @param plink {const ACL_DLINK*} 二分块数据链对象指针 + * @return {int} 0:表示OK,-1: 表示输入参数非法 + */ +ACL_API int acl_dlink_list(const ACL_DLINK *plink); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/lib_acl/include/stdlib/acl_dll.h b/lib_acl/include/stdlib/acl_dll.h new file mode 100644 index 000000000..a0af7f511 --- /dev/null +++ b/lib_acl/include/stdlib/acl_dll.h @@ -0,0 +1,27 @@ +#ifndef __ACL_DLL_INCLUDE_H__ +#define __ACL_DLL_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "acl_define.h" +#include "acl_vstream.h" +#include "acl_debug_malloc.h" +#include "acl_mem_slice.h" + +typedef struct ACL_DLL_ENV { + ACL_VSTREAM *logfp; + ACL_DEBUG_MEM *mmd; + ACL_MEM_SLICE *mem_slice; +} ACL_DLL_ENV; + +ACL_API ACL_DLL_HANDLE acl_dlopen(const char *dlname); +ACL_API void acl_dlclose(ACL_DLL_HANDLE handle); +ACL_API ACL_DLL_FARPROC acl_dlsym(void *handle, const char *name); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/include/stdlib/acl_env.h b/lib_acl/include/stdlib/acl_env.h new file mode 100644 index 000000000..62a892b87 --- /dev/null +++ b/lib_acl/include/stdlib/acl_env.h @@ -0,0 +1,21 @@ +#ifndef __ACL_ENV_INCLUDE_H__ +#define __ACL_ENV_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "acl_define.h" + +ACL_API void acl_clean_env(char **preserve_list); +ACL_API char *acl_getenv(const char *name); +ACL_API char *acl_getenv3(const char *name, char *buf, size_t len); +ACL_API int acl_setenv(const char *name, const char *val, int overwrite); +ACL_API int acl_putenv(char *str); +ACL_API const char *acl_getenv_list(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/include/stdlib/acl_exec_command.h b/lib_acl/include/stdlib/acl_exec_command.h new file mode 100644 index 000000000..c4d1a2e7b --- /dev/null +++ b/lib_acl/include/stdlib/acl_exec_command.h @@ -0,0 +1,16 @@ +#ifndef __ACL_EXEC_COMMAND_INCLUDE_H__ +#define __ACL_EXEC_COMMAND_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "acl_define.h" + +ACL_API void acl_exec_command(const char *command); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/include/stdlib/acl_fhandle.h b/lib_acl/include/stdlib/acl_fhandle.h new file mode 100644 index 000000000..9ebbd2c6d --- /dev/null +++ b/lib_acl/include/stdlib/acl_fhandle.h @@ -0,0 +1,108 @@ +#ifndef __ACL_FHANDLE_INCLUDE_H__ +#define __ACL_FHANDLE_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "acl_define.h" +#include "acl_vstream.h" +#include "acl_vstring.h" +#include "acl_ring.h" +#include "thread/acl_thread.h" +#include + +/** + * 通用的存储文件句柄对象类型定义 + */ + +typedef struct ACL_FHANDLE ACL_FHANDLE; + +struct ACL_FHANDLE { + ACL_VSTREAM *fp; /**< 存储文件句柄 */ + acl_int64 fsize; /**< 存储文件大小 */ + int nrefer; /**< 该存储句柄被引用的计数值 */ + acl_pthread_mutex_t mutex; /**< 线程锁 */ +#ifdef ACL_MS_WINDOWS + unsigned long tid; /**< 打开该存储的线程号 */ + unsigned long lock_mutex_tid; /**< 加线程锁的线程号 */ +#else + acl_pthread_t tid; /**< 打开该存储的线程号 */ + acl_pthread_t lock_mutex_tid; /**< 加线程锁的线程号 */ +#endif + unsigned int oflags; /**< 打开时的标志位 */ +#define ACL_FHANDLE_O_FLOCK (1 << 0) /**< 使用文件锁 */ +#define ACL_FHANDLE_O_MLOCK (1 << 1) /**< 使用线程锁 */ +#define ACL_FHANDLE_O_MKDIR (1 << 2) /**< 是否自动检查并创建不存在的目录 */ +#define ACL_FHANDLE_O_NOATIME (1 << 3) /**< 打开文件时添加 O_NOATIME 标志位 */ +#define ACL_FHANDLE_O_DIRECT (1 << 4) /**< 打开文件时添加 O_DIRECT 标志位 */ +#define ACL_FHANDLE_O_SYNC (1 << 5) /**< 打开文件时添加 O_SYNC 标志位 */ +#define ACL_FHANDLE_O_EXCL (1 << 6) /**< 打开文件时是否是自动加锁 */ + + unsigned int status; /**< 该存储文件句柄的状态 */ +#define ACL_FHANDLE_S_FLOCK_ON (1 << 0) /**< 该存储句柄已经加文件锁 */ +#define ACL_FHANDLE_S_MUTEX_ON (1 << 1) /**< 该存储句柄已经加线程锁 */ + + time_t when_free; /**< 在延迟关闭缓存队列中存活的时间截 */ + ACL_RING ring; /**< 缓存数据结点 */ + size_t size; /**< 该 ACL_FHANDLE 对象的实际大小 >= sizeof(ACL_FHANDLE) */ + void (*on_close)(ACL_FHANDLE*); /**< 当该文件缓存句柄真正关闭时的回调函数,可以为空 */ +}; + +#define ACL_FHANDLE_PATH(x) (ACL_VSTREAM_PATH((x)->fp)) + +/** + * 初始化文件句柄操作,该函数须在程序运行初始化时被调用且只能被调用一次 + * @param cache_size {int} 内部被打开文件句柄的最大个数 + * @param debug_section {int} 调试级别 + * @param flags {unsigned int} + */ +void acl_fhandle_init(int cache_size, int debug_section, unsigned int flags); +#define ACL_FHANDLE_F_LOCK (1 << 0) + +/** + * 当程序退出时需要调用此函数来释放系统资源 + */ +void acl_fhandle_end(void); + +/** + * 打开一个文件 + * @param size {size_t} 分配结构 FS_HANDDLE 需要的空间大小 + * @param oflags {unsigned int} 打开文件句柄时的标志位, ACL_FHANDLE_O_XXX + * @param file_path {const char*} 文件名(包含路径) + * @param on_open {int (*)(ACL_FHANDLE*, void*)} 如果不为空, + * 则当文件句柄被成功打开后便调用此函数 + * @param open_arg {void *} on_open 的回调参数之一 + * @param on_close {void (*)(ACL_FHANDLE*)} 如果不为空, + * 则当文件句柄被正直关闭时便调用此函数 + */ +ACL_FHANDLE *acl_fhandle_open(size_t size, unsigned int oflags, + const char *file_path, + int (*on_open)(ACL_FHANDLE*, void*), void *open_arg, + void (*on_close)(ACL_FHANDLE*)); + +/** + * 关闭一个文件句柄 + * @param fs {ACL_FHANDLE*} + * @param delay_timeout {int} 如果 > 0, 则延迟该时间后才真正关闭, + * 否则,其引用计数为 0 则立即关闭 + */ +void acl_fhandle_close(ACL_FHANDLE *fs, int delay_timeout); + +/** + * 对一个文件句柄加锁(先加线程锁后加文件锁) + * @param fs {ACL_FHANDLE*} + */ +void acl_fhandle_lock(ACL_FHANDLE *fs); + +/** + * 对一个文件句柄解锁(先解文件锁再解线程锁) + * @param fs {ACL_FHANDLE*} + */ +void acl_fhandle_unlock(ACL_FHANDLE *fs); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/include/stdlib/acl_fifo.h b/lib_acl/include/stdlib/acl_fifo.h new file mode 100644 index 000000000..792543c1c --- /dev/null +++ b/lib_acl/include/stdlib/acl_fifo.h @@ -0,0 +1,248 @@ +#ifndef __ACL_FIFO_INCLUDE_H__ +#define __ACL_FIFO_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "acl_define.h" +#include "acl_slice.h" +#include "acl_iterator.h" + +typedef struct ACL_FIFO_INFO ACL_FIFO_INFO; +typedef struct ACL_FIFO_ITER ACL_FIFO_ITER; +typedef struct ACL_FIFO ACL_FIFO; + +struct ACL_FIFO_INFO { + void *data; + ACL_FIFO_INFO *prev; + ACL_FIFO_INFO *next; +}; + +struct ACL_FIFO_ITER { + ACL_FIFO_INFO *ptr; +}; + +struct ACL_FIFO { + ACL_FIFO_INFO *head; + ACL_FIFO_INFO *tail; + int cnt; + + /* 添加及弹出 */ + + /* 向队列尾部添加动态对象 */ + void (*push_back)(struct ACL_FIFO*, void*); + /* 向队列头部添加动态对象 */ + void (*push_front)(struct ACL_FIFO*, void*); + /* 弹出队列尾部动态对象 */ + void *(*pop_back)(struct ACL_FIFO*); + /* 弹出队列头部动态对象 */ + void *(*pop_front)(struct ACL_FIFO*); + + /* for acl_iterator */ + + /* 取迭代器头函数 */ + void *(*iter_head)(ACL_ITER*, struct ACL_FIFO*); + /* 取迭代器下一个函数 */ + void *(*iter_next)(ACL_ITER*, struct ACL_FIFO*); + /* 取迭代器尾函数 */ + void *(*iter_tail)(ACL_ITER*, struct ACL_FIFO*); + /* 取迭代器上一个函数 */ + void *(*iter_prev)(ACL_ITER*, struct ACL_FIFO*); + /* 取迭代器关联的当前容器成员结构对象 */ + ACL_FIFO_INFO *(*iter_info)(ACL_ITER*, struct ACL_FIFO*); + + /* private */ + ACL_SLICE_POOL *slice; +}; + +/** + * 初始化一个给定队列,应用可以在栈上分配队列,而后调用该函数进行初始化 + * @param fifo {ACL_FIFO *} + * @example: + * void test(void) { + ACL_FIFO fifo; + + acl_fifo_init(&fifo); + * } + */ +ACL_API void acl_fifo_init(ACL_FIFO *fifo); + +/** + * 从内存堆中分配一个队列对象 + * @return {ACL_FIFO*} + */ +ACL_API ACL_FIFO *acl_fifo_new(void); + +/** + * 从内存堆中分配一个队列对象并传内存池对象做为分配器 + * @param slice {ACL_SLICE_POOL*} + * @return {ACL_FIFO*} + */ +ACL_API ACL_FIFO *acl_fifo_new1(ACL_SLICE_POOL *slice); + +/** + * 从队列中删除与所给值相同的对象 + * @param fifo {ACL_FIFO*} + * @param data {const void*} + */ +ACL_API int acl_fifo_delete(ACL_FIFO *fifo, const void *data); +ACL_API void acl_fifo_delete_info(ACL_FIFO *fifo, ACL_FIFO_INFO *info); + +/** + * 释放以堆分配的队列对象 + * @param fifo {ACL_FIFO*} + * @param free_fn {void (*)(void*)}, 如果该函数指针不为空则 + * 用来释放队列中动态分配的对象 + */ +ACL_API void acl_fifo_free(ACL_FIFO *fifo, void (*free_fn)(void *)); +ACL_API void acl_fifo_free2(ACL_FIFO *fifo, void (*free_fn)(ACL_FIFO_INFO *)); + +/** + * 向队列中添加一个动态堆对象 + * @param fifo {ACL_FIFO*} + * @param data {void*} 动态对象 + * @return {ACL_FIFO_INFO*} 如果 data 非空则返回队列中的新添加对象, 否则返回 NULL + */ +ACL_API ACL_FIFO_INFO *acl_fifo_push_back(ACL_FIFO *fifo, void *data); +#define acl_fifo_push acl_fifo_push_back +ACL_API void acl_fifo_push_info_back(ACL_FIFO *fifo, ACL_FIFO_INFO *info); +#define acl_fifo_push_info acl_fifo_push_info_back +ACL_API ACL_FIFO_INFO *acl_fifo_push_front(ACL_FIFO *fifo, void *data); + +/** + * 从队列中以先进先出方式弹出一个动态对象, 同时将该对象从队列中删除 + * @param fifo {ACL_FIFO*} + * @return {void*}, 如果为空,则表示队列为空 + */ +ACL_API void *acl_fifo_pop_front(ACL_FIFO *fifo); +#define acl_fifo_pop acl_fifo_pop_front +ACL_API ACL_FIFO_INFO *acl_fifo_pop_info(ACL_FIFO *fifo); + +/** + * 从队列中以后进先出方式弹出一个动态对象, 同时该对象从队列中删除 + * @param fifo {ACL_FIFO*} + * @return {void*}, 如果为空,则表示队列为空 + */ +ACL_API void *acl_fifo_pop_back(ACL_FIFO *fifo); + +/** + * 返回队列中头部(即最新添加的)的动态对象 + * @param fifo {ACL_FIFO*} + * @return {void*}, 如果为空,则表示队列为空 + */ +ACL_API void *acl_fifo_head(ACL_FIFO *fifo); +ACL_API ACL_FIFO_INFO *acl_fifo_head_info(ACL_FIFO *fifo); + +/** + * 返回队列中尾部(即最早添加的)的动态对象 + * @param fifo {ACL_FIFO*} + * @return {void*}, 如果为空,则表示队列为空 + */ +ACL_API void *acl_fifo_tail(ACL_FIFO *fifo); +ACL_API ACL_FIFO_INFO *acl_fifo_tail_info(ACL_FIFO *fifo); + +/** + * 返回队列中动态对象的总个数 + * @param fifo {ACL_FIFO*} + * @return {int}, >= 0 + */ +ACL_API int acl_fifo_size(ACL_FIFO *fifo); + +/*-------------------- 一些方便快捷的宏操作 --------------------------------*/ + +/** + * 获得当前 iter 所包含的对象地址 + * @param iter {ACL_FIFO_ITER} + */ +#define ACL_FIFO_ITER_VALUE(iter) ((iter).ptr->data) +#define acl_fifo_iter_value ACL_FIFO_ITER_VALUE + +/** + * 遍历 ACL_FIFO + * @param iter {ACL_FIFO_ITER} + * @param fifo {ACL_FIFO} + * @example: + -- 仅是本容器支持的遍历方式 + void test() + { + ACL_FIFO *fifo_ptr = acl_fifo_new(); + ACL_FIFO_ITER iter; + char *data; + int i; + + for (i = 0; i < 10; i++) { + data = acl_mymalloc(32); + snprintf(data, 32, "data: %d", i); + acl_fifo_push(fifo_ptr, data); + } + acl_fifo_foreach(iter, fifo_ptr) { + printf("%s\n", (char*) acl_fifo_iter_value(iter)); + } + + acl_fifo_free(fifo_ptr, acl_myfree_fn); + } + + -- 通用容器遍历方式 + void test2() + { + ACL_FIFO *fifo_ptr = acl_fifo_new(); + ACL_ITER iter; + char *data; + int i; + + for (i = 0; i < 10; i++) { + data = acl_mymalloc(32); + snprintf(data, 32, "data: %d", i); + acl_fifo_push(fifo_ptr, data); + } + acl_foreach(iter, fifo) { + printf("%s\n", (char*) iter.data); + } + acl_fifo_free(fifo_ptr, acl_myfree_fn); + } + */ +#define ACL_FIFO_FOREACH(iter, fifo_ptr) \ + for ((iter).ptr = (fifo_ptr)->head; (iter).ptr; (iter).ptr = (iter).ptr->next) +#define acl_fifo_foreach ACL_FIFO_FOREACH + +/** + * 反向遍历 ACL_FIFO + * @param iter {ACL_FIFO_ITER} + * @param fifo {ACL_FIFO} + * @example: + void test() + { + ACL_FIFO fifo; + ACL_FIFO_ITER iter; + char *data; + int i; + + acl_fifo_init(&fifo); + + for (i = 0; i < 10; i++) { + data = acl_mymalloc(32); + snprintf(data, 32, "data: %d", i); + acl_fifo_push(&fifo, data); + } + acl_fifo_foreach_reverse(iter, &fifo) { + printf("%s\n", (char*) iter.ptr->data); + } + + while (1) { + data = acl_fifo_pop(&fifo); + if (data == NULL) + break; + } + } + */ +#define ACL_FIFO_FOREACH_REVERSE(iter, fifo_ptr) \ + for ((iter).ptr = (fifo_ptr)->tail; (iter).ptr; (iter).ptr = (iter).ptr->prev) +#define acl_fifo_foreach_reverse ACL_FIFO_FOREACH_REVERSE + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/include/stdlib/acl_file.h b/lib_acl/include/stdlib/acl_file.h new file mode 100644 index 000000000..a1c4d18d9 --- /dev/null +++ b/lib_acl/include/stdlib/acl_file.h @@ -0,0 +1,212 @@ +#ifndef __ACL_FILE_INCLUDE_H__ +#define __ACL_FILE_INCLUDE_H__ + +#include "acl_vstream.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * 文件流类型定义 + */ +typedef struct ACL_FILE { + ACL_VSTREAM *stream; /**< 流指针 */ + unsigned int status; /**< 文件流状态 */ +#define ACL_FILE_EOF (1 << 0) + int errnum; /**< 文件流的出错错误号 */ +} ACL_FILE; + +#define ACL_FPATH(fp) (ACL_VSTREAM_PATH((fp)->stream) +#define ACL_FSTREAM(fp) ((fp)->stream) + +/** + * 打开或创建一个文件进行读写操作 + * @param filenme {const char*} 文件名 + * @param mode {const char*} 打开标志. + * r or rb: 只读方式打开已经存在文件 + * w or wb: 只写方式打开已存在文件并清空或只写方式创建新文件 + * a or ab: 尾部附加只写方式打开已存在文件或创建新文件 + * r+ or rb+: 以读写方式打开已存在文件 + * w+ or wb+: 以读写方式打开已存在文件并清空或创建新文件 + * a+ or ab+: 以尾部附加读写方式打开已存在文件或创建新文件 + */ +ACL_API ACL_FILE *acl_fopen(const char *filename, const char *mode); + +/** + * 关闭一个文件流 + * @param fp {ACL_FILE*} 文件流 + */ +ACL_API int acl_fclose(ACL_FILE *fp); + +/** + * 清除文件流的错误号 + * @param fp {ACL_FILE*} 文件流 + */ +ACL_API void acl_clearerr(ACL_FILE *fp); + +/** + * 判断是否到达文件尾部 + * @param fp {ACL_FILE*} 文件流 + * @return {int} 0: 否; !0: 是 + */ +ACL_API int acl_feof(ACL_FILE *fp); + +/** + * 从文件流中读取一些固定长度的数据块 + * @param buf {void*} 内存缓冲区地址 + * @param size {size_t} 每个数据块长度 + * @param nitems {size_t} 数据块个数 + * @param fp {ACL_FILE*} 文件流 + * @return {size_t} 数据块个数, 若出错则返回 EOF + */ +ACL_API size_t acl_fread(void *buf, size_t size, size_t nitems, ACL_FILE *fp); + +/** + * 从文件流中读取一行数据 + * @param buf {char*} 缓冲区地址 + * @param size {int} buf 空间大小 + * @param fp {ACL_FILE*} 文件流 + * @return {char*} NULL: 未读到完整行数据; !NULL: 读到完整行数据 + */ +ACL_API char *acl_fgets(char *buf, int size, ACL_FILE *fp); + +/** + * 从文件流中读取一行数据,但返回的数据尾部不包含 "\r\n" + * @param buf {char*} 缓冲区地址 + * @param size {int} buf 空间大小 + * @param fp {ACL_FILE*} 文件流 + * @return {char*} NULL: 未读到完整行数据; !NULL: 读到完整行数据 + */ +ACL_API char *acl_fgets_nonl(char *buf, int size, ACL_FILE *fp); + +/** + * 从文件流中读取一个字符 + * @param fp {ACL_FILE*} 文件流 + * @return {int} EOF: 到达文件尾或出错; !EOF: 正确读到一个字符的 ASCII 码 + */ +ACL_API int acl_fgetc(ACL_FILE *fp); +#define acl_getc acl_fgetc + +/** + * 从标准输入中读取一行数据 + * @param buf {char*} 缓存区地址 + * @param size {int} buf 空间大小 + * @return {char*} NULL: 读结束或出错; !NULL: 应与 buf 相同地址 + */ +ACL_API char *acl_gets(char *buf, size_t size); + +/** + * 从标准输入中读取一行数据, 但数据尾部不包含 "\r\n" + * @param buf {char*} 缓存区地址 + * @param size {int} buf 空间大小 + * @return {char*} NULL: 读结束或出错; !NULL: 应与 buf 相同地址 + */ +ACL_API char *acl_gets_nonl(char *buf, size_t size); + +/** + * 从标准输入中读取一个字符 + * @return {int} EOF: 到达文件尾或出错; !EOF: 正确读到一个字符的 ASCII 码 + */ +ACL_API int acl_getchar(void); + +/** + * 向文件流中写入变参格式数据 + * @param fp {ACL_FILE*} 文件流句柄 + * @param fmt {const char*} 变参格式 + * @param ... 变参 + * @return {size_t} 数据长度, 若出错则返回 EOF + */ +#ifdef WIN32 +ACL_API int acl_fprintf(ACL_FILE *fp, const char *fmt, ...); +#else +ACL_API int __attribute__((format(printf,2,3))) + acl_fprintf(ACL_FILE *fp, const char *fmt, ...); +#endif + +/** + * 向文件流中写入变参格式数据 + * @param fp {ACL_FILE*} 文件流句柄 + * @param fmt {const char*} 变参格式 + * @param ap {va_list} 变参列表 + * @return {size_t} 数据长度, 若出错则返回 EOF + */ +ACL_API int acl_vfprintf(ACL_FILE *fp, const char *fmt, va_list ap); + +/** + * 向文件流中写入一些固定长度的数据块 + * @param ptr {const void*} 数据地址 + * @param size {size_t} 每个数据块长度 + * @param nitems {size_t} 数据块个数 + * @param fp {ACL_FILE*} 文件流指针 + * @return {size_t} 数据块个数, 若出错则返回 EOF + */ +ACL_API size_t acl_fwrite(const void *ptr, size_t size, size_t nitems, ACL_FILE *fp); + +/** + * 向文件流中写入数据并自动在尾部添加 "\r\n" + * @param s {const char*} 字符串地址 + * @param fp {ACL_FILE*} 文件流指针 + * @return {int} 写入的数据量(包含 "\r\n"), 若出错则返回 EOF + */ +ACL_API int acl_fputs(const char *s, ACL_FILE *fp); + +/** + * 向标准输出流中写入变参格式数据 + * @param fmt {const char*} 变参格式 + * @param ... 变参 + * @return {size_t} 数据长度, 若出错则返回 EOF + */ +#ifdef WIN32 +ACL_API int acl_printf(const char *fmt, ...); +#else +ACL_API int __attribute__((format(printf,1,2))) + acl_printf(const char *fmt, ...); +#endif + +/** + * 向标准输出流中写入变参格式数据 + * @param fmt {const char*} 变参格式 + * @param ap {va_list} 变参列表 + * @return {size_t} 数据长度, 若出错则返回 EOF + */ +ACL_API int acl_vprintf(const char *fmt, va_list ap); + +/** + * 向文件流中写入一个字节 + * @param c {int} 一个符的 ASCII 码 + * @param fp {ACL_FILE*} 文件流指针 + * @return {int} 写入的数据量, 若出错则返回 EOF + */ +ACL_API int acl_putc(int c, ACL_FILE *fp); +#define acl_fputc acl_putc + +/** + * 向标准输出中写入数据并自动在尾部添加 "\r\n" + * @param s {const char*} 字符串地址 + * @return {int} 写入的数据量(包含 "\r\n"), 若出错则返回 EOF + */ +ACL_API int acl_puts(const char *s); + +/** + * 向文件流中写入一个字节 + * @param c {int} 一个符的 ASCII 码 + * @return {int} 写入的数据量, 若出错则返回 EOF + */ +ACL_API int acl_putchar(int c); + +/** + * 定位文件位置 + * @param fp {ACL_FILE*} 文件流 + * @param offset {acl_off_t} 偏移位置 + * @param whence {int} 偏移方向, SEEK_SET, SEEK_CUR, SEEK_END + * @return ret {acl_off_t}, ret >= 0: 正确, ret < 0: 出错 + */ +ACL_API acl_off_t acl_fseek(ACL_FILE *fp, acl_off_t offset, int whence); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/include/stdlib/acl_getopt.h b/lib_acl/include/stdlib/acl_getopt.h new file mode 100644 index 000000000..d7ce2eba6 --- /dev/null +++ b/lib_acl/include/stdlib/acl_getopt.h @@ -0,0 +1,26 @@ +#ifndef __ACL_GETOPT_INCLUDE_H__ +#define __ACL_GETOPT_INCLUDE_H__ +#ifdef __cplusplus +extern "C" { +#endif + +#include "acl_define.h" + +extern ACL_API int acl_optind; +extern ACL_API char *acl_optarg; + +ACL_API void acl_getopt_init(void); +ACL_API int acl_getopt(int argc, char **argv, const char *opts); + +#ifdef ACL_MS_WINDOWS +# define optind acl_optind +# define optarg acl_optarg +# define getopt_init acl_getopt_init +# define getopt acl_getopt +#endif + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/lib_acl/include/stdlib/acl_hash.h b/lib_acl/include/stdlib/acl_hash.h new file mode 100644 index 000000000..94d5660e0 --- /dev/null +++ b/lib_acl/include/stdlib/acl_hash.h @@ -0,0 +1,33 @@ +#ifndef __ACL_HASH_INCLUD_H__ +#define __ACL_HASH_INCLUD_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "acl_define.h" +#include + +/** + * 哈希函数类型定义 + * @param buffer 需要被哈希的字符串 + * @param len s 的长度 + */ +typedef unsigned (*ACL_HASH_FN)(const void *buffer, size_t len); + +ACL_API unsigned acl_hash_crc32(const void *key, size_t len); +ACL_API acl_uint64 acl_hash_crc64(const void *key, size_t len); +ACL_API unsigned acl_hash_test(const void *key, size_t len); +ACL_API unsigned acl_hash_bin(const void *key, size_t len); +ACL_API unsigned acl_hash_func2(const void *key, size_t len); +ACL_API unsigned acl_hash_func3(const void *key, size_t len); +ACL_API unsigned acl_hash_func4(const void *key, size_t len); +ACL_API unsigned acl_hash_func5(const void *key, size_t len); +ACL_API unsigned acl_hash_func6(const void *key, size_t len); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/include/stdlib/acl_hex_code.h b/lib_acl/include/stdlib/acl_hex_code.h new file mode 100644 index 000000000..2cbd3abf1 --- /dev/null +++ b/lib_acl/include/stdlib/acl_hex_code.h @@ -0,0 +1,34 @@ +#ifndef __ACL_HEX_CODE_H_INCLUDED__ +#define __ACL_HEX_CODE_H_INCLUDED__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "acl_define.h" +#include "acl_vstring.h" + +/** + * 将二进制数据进行编码,一个字节转换成两个字节后,从而转为文本字符串 + * @param buf {ACL_VSTRING*} 存储转换结果 + * @param ptr {const char*} 二进制数据 + * @param len {int} ptr 数据的长度 + * @return {ACL_VSTRING*} 如果转换成功,则与 buf 相同 + */ +ACL_API ACL_VSTRING *acl_hex_encode(ACL_VSTRING *buf, const char *ptr, int len); + +/** + * 将编码后的数据进行解码 + * @param buf {ACL_VSTRING*} 存储转换结果 + * @param ptr {const char*} 编码数据 + * @param len {int} ptr 数据长度 + * @return {ACL_VSTRING*} 如果解码成功,则与 buf 相同, 否则返回 NULL + */ +ACL_API ACL_VSTRING *acl_hex_decode(ACL_VSTRING *buf, const char *ptr, int len); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/include/stdlib/acl_htable.h b/lib_acl/include/stdlib/acl_htable.h new file mode 100644 index 000000000..a906c5ad0 --- /dev/null +++ b/lib_acl/include/stdlib/acl_htable.h @@ -0,0 +1,327 @@ + +#ifndef _ACL_HTABLE_H_INCLUDED_ +#define _ACL_HTABLE_H_INCLUDED_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "acl_define.h" +#include "thread/acl_thread.h" +#include "acl_hash.h" /* just for ACL_HASH_FN */ +#include "acl_slice.h" +#include "acl_iterator.h" + +/*--------------------------------------------------------------------------*/ +typedef struct ACL_HTABLE ACL_HTABLE; +typedef struct ACL_HTABLE_INFO ACL_HTABLE_INFO; + +/** + * 哈希表对象结构句柄 + */ +struct ACL_HTABLE { + int size; /* length of entries array */ + int init_size; /* length of initial entryies array */ + int used; /* number of entries in table */ + ACL_HTABLE_INFO **data; /* entries array, auto-resized */ + unsigned int flag; /* properties flag */ + int status; /* the operator's status on the htable */ + + ACL_HASH_FN hash_fn; /* hash function */ + ACL_SLICE_POOL *slice; + acl_pthread_mutex_t *rwlock; + + /* for acl_iterator */ + + /* 取迭代器头函数 */ + void *(*iter_head)(ACL_ITER*, struct ACL_HTABLE*); + /* 取迭代器下一个函数 */ + void *(*iter_next)(ACL_ITER*, struct ACL_HTABLE*); + /* 取迭代器尾函数 */ + void *(*iter_tail)(ACL_ITER*, struct ACL_HTABLE*); + /* 取迭代器上一个函数 */ + void *(*iter_prev)(ACL_ITER*, struct ACL_HTABLE*); + /* 取迭代器关联的当前容器成员结构对象 */ + ACL_HTABLE_INFO *(*iter_info)(ACL_ITER*, struct ACL_HTABLE*); +}; + +/** + * 哈希表中每一个哈希项的存储信息类型 + */ +struct ACL_HTABLE_INFO { + union { + char *key; + const char *c_key; + } key; /** + * 哈希键, 只所以如此声明,是因为当创建哈希表的标志位为 + * ACL_BINHASH_FLAG_KEY_REUSE 时需要复用输入的键空间 + */ + void *value; /**< associated value */ + struct ACL_HTABLE_INFO *next; /**< colliding entry */ + struct ACL_HTABLE_INFO *prev; /**< colliding entry */ +}; + +/** + * ACL_HTABLE 遍历用类型 + */ +typedef struct ACL_HTABLE_ITER { + /* public */ + ACL_HTABLE_INFO *ptr; + + /* private */ + int i; + int size; + ACL_HTABLE_INFO **h; +} ACL_HTABLE_ITER; + +/** + * 建立哈希表 + * @param size 哈希表长度 + * @param flag {unsigned int} 哈希表属性标志位, ACL_BINHASH_FLAG_xxx + * @return 所建哈希表的头指针或为空(这时表示出了严重的错误, 主要是内存分配问题) + */ +ACL_API ACL_HTABLE *acl_htable_create(int size, unsigned int flag); +#define ACL_HTABLE_FLAG_KEY_REUSE (1 << 0) /* 添加新的对象时是否直接复用键地址 */ +#define ACL_HTABLE_FLAG_USE_LOCK (1 << 1) /* 是否针对启用多线程互斥方式 */ +#define ACL_HTABLE_FLAG_MSLOOK (1 << 2) /* 每次查询时是否将查询结果对象放在链头 */ +#define ACL_HTABLE_FLAG_KEY_LOWER (1 << 3) /* 统一将键转换为小写,从而实现键查询不区分大小写的功能 */ + +ACL_API ACL_HTABLE *acl_htable_create3(int size, unsigned int flag, ACL_SLICE_POOL *slice); + +/** + * 设置哈希表的控制参数 + * @param table 哈希表对象句柄 + * @param name 控制参数的变参初始值, name 及以后的控制参数如下定义 + * ACL_HTABLE_CTL_END: 变参表结束标志 + * ACL_HTABLE_CTL_RWLOCK: 是否启用读写锁机制 + * ACL_HTABLE_CTL_HASH_FN: 用户自定义的哈希值计算函数 + */ +ACL_API void acl_htable_ctl(ACL_HTABLE *table, int name, ...); +#define ACL_HTABLE_CTL_END 0 /**< 控制结束标志 */ +#define ACL_HTABLE_CTL_RWLOCK 1 /**< 是否加锁 */ +#define ACL_HTABLE_CTL_HASH_FN 2 /**< 设置私有哈希函数 */ + +/** + * 检查上一次哈希表操作后哈希表的状态 + * @param table 哈希表指针 + * @return {int} 操作哈希表后的状态, 参见如下的 ACL_HTABLE_STAT_XXX + */ +ACL_API int acl_htable_errno(ACL_HTABLE *table); +#define ACL_HTABLE_STAT_OK 0 /**< 状态正常 */ +#define ACL_HTABLE_STAT_INVAL 1 /**< 无效参数 */ +#define ACL_HTABLE_STAT_DUPLEX_KEY 2 /**< 重复键 */ + +/** + * 设置哈希表的当前状态, error 取值 ACL_HTABLE_STAT_XXX + * @param table 哈希表指针 + * @param error 设置哈希表的错误状态 + */ +ACL_API void acl_htable_set_errno(ACL_HTABLE *table, int error); + +/** + * 往哈希表里添加新的项 + * @param table 哈希表指针 + * @param key 键, 在函数内部会复制此 key 键 + * @param value 用户自己的特定数据项(可以由类型硬转化而来, 但是此数据项必须不能堆栈变量) + * @return 所分配的哈希表项的指针, == NULL: 表示内部分分配内存出错, 为严重的错误 + * 注:如果在添加时该哈希争键存在,则返回已经存在的哈希项,使用者应该通过调用 + * acl_htable_last_errno() 来查看是否重复添加同一个键值(ACL_HTABLE_STAT_DUPLEX_KEY) + */ +ACL_API ACL_HTABLE_INFO *acl_htable_enter(ACL_HTABLE *table, const char *key, void *value); + +/** + * 往哈希表里添加新的项,当多个线程同时进行此操作时,函数内部会自动保证互斥操作 + * @param table 哈希表指针 + * @param key 键, 在函数内部会复制此 key 键 + * @param value 用户自己的特定数据项(可以由类型硬转化而来, 但是此数据项必须不能堆栈变量) + * @param callback 如果该函数指针不为空,则当添加成功后便调用该函数 + * @param arg callback 的参数之一 + * @return 所分配的哈希表项的指针, == NULL: 表示内部分分配内存出错, 为严重的错误 + * 注:如果在添加时该哈希争键存在,则返回已经存在的哈希项,使用者应该通过调用 + * acl_htable_last_errno() 来查看是否重复添加同一个键值(ACL_HTABLE_STAT_DUPLEX_KEY) + */ +ACL_API int acl_htable_enter_r(ACL_HTABLE *table, const char *key, void *value, + void (*callback)(ACL_HTABLE_INFO *ht, void *arg), void *arg); + +/** + * 由所给的 key 键查寻某一特定哈希项 + * @param table 哈希表指针 + * @param key 键 + * @return 不为空指针: 表示查到了对应于 key 键的哈希项 + * 为空: 表示未查到对应于 key 键的哈希项 + */ +ACL_API ACL_HTABLE_INFO *acl_htable_locate(ACL_HTABLE *table, const char *key); + +/** + * 由所给的 key 键查寻某一特定哈希项,当多个线程同时进行此操作时, + * 函数内部会自动保证互斥操作 + * @param table 哈希表指针 + * @param key 键 + * @param callback 查到所要求的键值后如果该指针非空则调用之 + * @param arg callback 参数之一 + * @return 不为空指针: 表示查到了对应于 key 键的哈希项 + * 为空: 表示未查到对应于 key 键的哈希项 + */ +ACL_API int acl_htable_locate_r(ACL_HTABLE *table, const char *key, + void (*callback)(ACL_HTABLE_INFO *ht, void *arg), void *arg); + +/** + * 由所给的 key 键查寻用户的数据项 + * @param table 哈希表指针 + * @param key 键 + * @return 不为空: 表示查到了对应于 key 键的数据项, 用户可以根据用户自己的 + * 数据类型进行转换; 为空: 表示未查到对应于 key 键的数据项 + */ +ACL_API void *acl_htable_find(ACL_HTABLE *table, const char *key); + +/** + * 由所给的 key 键查寻用户的数据项, 当多个线程同时进行此操作时, + * 函数内部会自动保证互斥操作 + * @param table 哈希表指针 + * @param key 键 + * @param callback 当查到所要求的键值后,如果该函数指针不为空则调用之 + * @param arg callback 的参数之一 + * @return 不为空: 表示查到了对应于 key 键的数据项, 用户可以根据用户自己的 + * 数据类型进行转换; 为空: 表示未查到对应于 key 键的数据项 + */ +ACL_API int acl_htable_find_r(ACL_HTABLE *table, const char *key, + void (*callback)(void *value, void *arg), void *arg); + +/** + * 根据所给的 key 键删除某一哈希项 + * @param table 哈希表指针 + * @param key 键 + * @param free_fn 如果该函数指针不为空并且找到了对应于 key 键的数据项, 则先调用用户 + * 所提供的析构函数做一些清尾工作, 然后再释放该哈希项 + * @return 0: 成功; -1: 未找到该 key 键 + */ +ACL_API int acl_htable_delete(ACL_HTABLE *table, const char *key, void (*free_fn) (void *)); +#define acl_htable_delete_r acl_htable_delete + +/** + * 释放整个哈希表 + * @param table 哈希表指针 + * @param free_fn 如果该指针不为空则对哈希表中的每一项哈希项先用该函数做清尾工作, 然后再释放 + */ +ACL_API void acl_htable_free(ACL_HTABLE *table, void (*free_fn) (void *)); + +/** + * 重置哈希表, 该函数会释放哈希表中的所有内容项, 并重新初始化 + * @param table 哈希表指针 + * @param free_fn 如果该指针不为空则对哈希表中的每一项哈希项先用该函数做清尾工作, 然后再释放 + * @return 是否重置成功. 0: OK; < 0: error. + */ +ACL_API int acl_htable_reset(ACL_HTABLE *table, void (*free_fn) (void *)); +#define acl_htable_reset_r acl_htable_reset + +/** + * 对哈希表中的每一项哈希项进行处理 + * @param table 哈希表指针 + * @param walk_fn 处理每一项哈希项的函数指针, 不能为空 + * @param arg 用户自己类型的数据 + */ +ACL_API void acl_htable_walk(ACL_HTABLE *table, void (*walk_fn) (ACL_HTABLE_INFO *, void *), void *arg); +#define acl_htable_walk_r acl_htable_walk + +/** + * 返回哈希表当前的容器空间大小 + * @param table 哈希表指针 + * @return 哈希表的容器空间大小 + */ +ACL_API int acl_htable_size(const ACL_HTABLE *table); + +/** + * 返回哈希表当前的窗口中所含元素个数 + * @param table 哈希表指针 + * @return 哈希表中元素个数 + */ +ACL_API int acl_htable_used(const ACL_HTABLE *table); + +/** + * 将哈希表里的所有项组合成一个链表 + * @param table 哈希表 + * @return 不为空: 链表指针; 为空: 表示该哈希表里没有哈希项 + */ +ACL_API ACL_HTABLE_INFO **acl_htable_list(const ACL_HTABLE *table); + +/** + * 显示哈希表中 key 键的分布状态 + * @param table 哈希表指针 + */ +ACL_API void acl_htable_stat(const ACL_HTABLE *table); +#define acl_htable_stat_r acl_htable_stat + +ACL_API ACL_HTABLE_INFO **acl_htable_data(ACL_HTABLE *table); +ACL_API const ACL_HTABLE_INFO *acl_htable_iter_head(ACL_HTABLE *table, ACL_HTABLE_ITER *iter); +ACL_API const ACL_HTABLE_INFO *acl_htable_iter_next(ACL_HTABLE_ITER *iter); +ACL_API const ACL_HTABLE_INFO *acl_htable_iter_tail(ACL_HTABLE *table, ACL_HTABLE_ITER *iter); +ACL_API const ACL_HTABLE_INFO *acl_htable_iter_prev(ACL_HTABLE_ITER *iter); + +/*-------------------- 一些方便快捷的宏操作 --------------------------------*/ + +#define ACL_HTABLE_ITER_KEY(iter) ((iter).ptr->key.c_key) +#define acl_htable_iter_key ACL_HTABLE_ITER_KEY + +#define ACL_HTABLE_ITER_VALUE(iter) ((iter).ptr->value) +#define acl_htable_iter_value ACL_HTABLE_ITER_VALUE + +/** + * 遍历 ACL_HTABLE + * @param iter {ACL_HTABLE_ITER} + * @param table_ptr {ACL_HTABLE *} + * @example: + void test() + { + ACL_HTABLE *table = acl_htable_create(10, 0); + ACL_HTABLE_ITER iter; + char *value, key[32]; + int i; + + for (i = 0; i < 100; i++) { + value = (char*) acl_mystrdup("value"); + snprintf(key, sizeof(key), "key:%d", i); + (void) acl_htable_enter(table, key, value); + } + + acl_htable_foreach(iter, table) { + printf("%s=%s\n", acl_htable_iter_key(iter), acl_htable_iter_value(iter)); + if (i == 50) + break; + } + acl_htable_free(table, acl_myfree_fn); + } + */ + +#if 0 +#define ACL_HTABLE_FOREACH(iter, table_ptr) \ + if (table_ptr) \ + for((iter).size = acl_htable_size((table_ptr)), (iter).i = 0, \ + (iter).h = acl_htable_data((table_ptr)); (iter).i < (iter).size; (iter).i++) \ + for ((iter).ptr = *(iter).h++; (iter).ptr; (iter).ptr = (iter).ptr->next) +#define ACL_HTABLE_FOREACH_REVERSE(iter, table_ptr) \ + if (table_ptr) \ + for((iter).size = acl_htable_size((table_ptr)), (iter).i = (iter).size - 1, \ + (iter).h = acl_htable_data((table_ptr)) + (iter).i; (iter).i >= 0; (iter).i--) \ + for ((iter).ptr = *(iter).h--; (iter).ptr; (iter).ptr = (iter).ptr->next) +#else +#define ACL_HTABLE_FOREACH(iter, table_ptr) \ + if (table_ptr) \ + for((void) acl_htable_iter_head((table_ptr), &iter); \ + (iter).ptr; \ + (void) acl_htable_iter_next(&iter)) +#define ACL_HTABLE_FOREACH_REVERSE(iter, table_ptr) \ + if (table_ptr) \ + for((void) acl_htable_iter_tail((table_ptr), &iter); \ + (iter).ptr; \ + (void) acl_htable_iter_prev(&iter)) +#endif + +#define acl_htable_foreach ACL_HTABLE_FOREACH +#define acl_htable_foreach_reverse ACL_HTABLE_FOREACH_REVERSE + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/include/stdlib/acl_iostuff.h b/lib_acl/include/stdlib/acl_iostuff.h new file mode 100644 index 000000000..66bfc7f67 --- /dev/null +++ b/lib_acl/include/stdlib/acl_iostuff.h @@ -0,0 +1,148 @@ + +#ifndef __ACL_IOSTUFF_INCLUDE_H__ +#define __ACL_IOSTUFF_INCLUDE_H__ +#ifdef __cplusplus +extern "C" { +#endif + +#include "acl_define.h" + +#define ACL_CLOSE_ON_EXEC 1 /**< 标志位, 调用 exec 后自动关闭打开的描述字 */ +#define ACL_PASS_ON_EXEC 0 + +#define ACL_BLOCKING 0 /**< 阻塞读写标志位 */ +#define ACL_NON_BLOCKING 1 /**< 非阻塞读写标志位 */ + +/** + * 设置套接口为阻塞或非阻塞 + * @param fd {ACL_SOCKET} SOCKET 套接字 + * @param on {int} 是否设置该套接字为非阻塞, ACL_BLOCKING 或 ACL_NON_BLOCKING + * @return {int} 0: 成功; -1: 失败 + */ +ACL_API int acl_non_blocking(ACL_SOCKET fd, int on); + +/** + * 写等待操作,直到套接字可写、出错或超时 + * @param fd {ACL_SOCKET} SOCKET 套接字 + * @param timeout {int} 超时时间,单位为秒 + * @return {int} 0: 可写; -1: 失败或超时 + */ +ACL_API int acl_write_wait(ACL_SOCKET fd, int timeout); + +/** + * 读等待操作,直到套接字有数据可读、出错或超时 + * @param fd {ACL_SOCKET} SOCKET 套接字 + * @param timeout {int} 超时时间,单位为秒 + * @return {int} 0: 有数据可读; -1: 失败或超时 + */ +ACL_API int acl_read_wait(ACL_SOCKET fd, int timeout); + +/** + * 毫秒级别睡眠 + * @param delay {unsigned} 毫秒值 + */ +ACL_API void acl_doze(unsigned delay); + +/** +* 某个描述符是否可读 +* @param fd {ACL_SOCKET} 描述符 +* @return {int} 0: 不可读; != 0: 可读 +*/ +ACL_API int acl_readable(ACL_SOCKET fd); + +/** +* 超时读数据 +* @param fd {ACL_SOCKET} 描述符 +* @param buf {void*} 存储区,不能为空 +* @param len {unsigned} buf 存储区大小 +* @param timeout {int} 超时时间,单位为秒 +* @return {int} > 0 读的数据; -1: 出错 +*/ +ACL_API int acl_timed_read(ACL_SOCKET fd, void *buf, unsigned len, + int timeout, void *unused_context); + +/** +* 超时写数据 +* @param fd {ACL_SOCKET} 描述符 +* @param buf {void*} 数据存储区,不能为空 +* @param len {unsigned} 数据长度大小 +* @param timeout {int} 超时时间,单位为秒 +* @return {int} > 0 成功写入的数据; -1: 出错 +*/ +ACL_API int acl_timed_write(ACL_SOCKET fd, void *buf, unsigned len, + int timeout, void *unused_context); + +/** +* 向文件描述符中循环写入数据,直到写完、出错或超时为止 +* @param fd {ACL_SOCKET} 文件描述符 +* @param buf {void*} 数据存储区,不能为空 +* @param len {unsigned} 数据长度大小 +* @param timeout {int} 超时时间,单位为秒 +* @param {int} 成功写入的长度 +*/ +ACL_API int acl_write_buf(ACL_SOCKET fd, const char *buf, int len, int timeout); + +/** +* 探测套接字中系统缓存区的数据长度 +* @param fd {ACL_SOCKET} 描述符 +* @return {int} 系统缓存区数据长度 +*/ +ACL_API int acl_peekfd(ACL_SOCKET fd); + +/** + * 创建管道 + * @param fds {ACL_FILE_HANDLE [2]} 存储结果 + * @return {int} 0: ok; -1: error + */ +ACL_API int acl_pipe(ACL_FILE_HANDLE fds[2]); + +/** + * 关闭管道对 + * @param fds {ACL_FILE_HANDLE[2]} 管道对 + * @return {int} 0: ok; -1: error + */ +ACL_API int acl_pipe_close(ACL_FILE_HANDLE fds[2]); + +/** +* 产生一个管道对 +* @param fds {ACL_FILE_HANDLE[2]} 存储产生的管道对地址,不能为空 +* @return 0: ok; -1: error +*/ +ACL_API int acl_duplex_pipe(ACL_FILE_HANDLE fds[2]); + +#ifdef ACL_UNIX +/** + * 设置文件描述符标志位,当调用 exec 后该描述符自动被关闭 + * @param fd {int} 文件描述符 + * @param on {int} ACL_CLOSE_ON_EXEC 或 0 + * @return {int} 0: ok; -1: error + */ +ACL_API int acl_close_on_exec(int fd, int on); + +/** + * 从某个文件描述符开始关闭之后的所有打开的文件描述符 + * @param lowfd {int} 被关闭描述符的最低值 + * @return {int} 0: ok; -1: error + */ +ACL_API int acl_closefrom(int lowfd); + +/** + * 设定当前进程可以打开最大文件描述符值 + * @param limit {int} 设定的最大值 + * @return {int} >=0: ok; -1: error + */ +ACL_API int acl_open_limit(int limit); + +/** + * 判断给定某个文件描述字是否是套接字 + * @param fd {int} 文件描述符 + * @return {int} != 0: 是; 0: 否 + */ +ACL_API int acl_issock(int fd); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/include/stdlib/acl_iplink.h b/lib_acl/include/stdlib/acl_iplink.h new file mode 100644 index 000000000..bed1ac74c --- /dev/null +++ b/lib_acl/include/stdlib/acl_iplink.h @@ -0,0 +1,47 @@ +/* + * Name: iplink.h + * Author: zsx + * Date: 2003/11/30 + * Version: 1.0 + * +*/ +#ifndef _IPLINK_INCLUDE_H_ +#define _IPLINK_INCLUDE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "acl_define.h" +#include "acl_dlink.h" +#include "acl_iterator.h" + +#define ACL_IPITEM ACL_DITEM +#define ACL_IPLINK ACL_DLINK + +ACL_API ACL_IPLINK *acl_iplink_create(int nsize); +ACL_API void acl_iplink_free(ACL_IPLINK *plink); +ACL_API ACL_IPITEM *acl_iplink_lookup_item(const ACL_IPLINK *plink, + ACL_IPITEM *pitem); +ACL_API ACL_IPITEM *acl_iplink_lookup_bin(const ACL_IPLINK *plink, + unsigned int ip); +ACL_API ACL_IPITEM *acl_iplink_lookup_str(const ACL_IPLINK *plink, + const char *ip); +ACL_API ACL_IPITEM *acl_iplink_insert_bin(ACL_IPLINK *plink, + unsigned int ip_begin, unsigned int ip_end); +ACL_API ACL_IPITEM *acl_iplink_insert(ACL_IPLINK *plink, + const char *pstrip_begin, const char *pstrip_end); +ACL_API int acl_iplink_delete_by_ip(ACL_IPLINK *plink, + const char *pstrip_begin); +ACL_API int acl_iplink_delete_by_item(ACL_IPLINK *plink, ACL_IPITEM *pitem); +ACL_API ACL_IPITEM *acl_iplink_modify(ACL_IPLINK *plink, const char *pstrip_id, + const char *pstrip_begin, const char *pstrip_end); +ACL_API int acl_iplink_count_item(ACL_IPLINK *plink); +ACL_API int acl_iplink_list(const ACL_IPLINK *plink); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/include/stdlib/acl_iterator.h b/lib_acl/include/stdlib/acl_iterator.h new file mode 100644 index 000000000..5cf31850f --- /dev/null +++ b/lib_acl/include/stdlib/acl_iterator.h @@ -0,0 +1,53 @@ +#ifndef __ACL_ITERATOR_INCLUDE_H__ +#define __ACL_ITERATOR_INCLUDE_H__ + +typedef struct ACL_ITER ACL_ITER; + +/** + * ACL 库中数据结构用的通用迭代器结构定义 + */ +struct ACL_ITER { + void *ptr; /**< 迭代器指针, 与容器相关 */ + void *data; /**< 用户数据指针 */ + int dlen; /**< 用户数据长度, 实现者可设置此值也可不设置 */ + const char *key; /**< 若为哈希表的迭代器, 则为哈希键值地址 */ + int klen; /**< 若为ACL_BINHASH迭代器, 则为键长度 */ + int i; /**< 当前迭代器在容器中的位置索引 */ + int size; /**< 当前容器中元素总个数 */ +}; + +/** + * 正向遍历容器中元素 + * @param iter {ACL_ITER} + * @param container {void*} 容器地址 + * @examples: samples/iterator/ + */ +#define ACL_FOREACH(iter, container) \ + for ((container)->iter_head(&(iter), (container)); \ + (iter).ptr; \ + (container)->iter_next(&(iter), (container))) + +/** + * 反向遍历容器中元素 + * @param iter {ACL_ITER} + * @param container {void*} 容器地址 + * @examples: samples/iterator/ + */ +#define ACL_FOREACH_REVERSE(iter, container) \ + for ((container)->iter_tail(&(iter), (container)); \ + (iter).ptr; \ + (container)->iter_prev(&(iter), (container))) + +/** + * 获得当前迭代指针与某容器关联的成员结构类型对象 + * @param iter {ACL_ITER} + * @param container {void*} 容器地址 + */ +#define ACL_ITER_INFO(iter, container) \ + (container)->iter_info(&(iter), (container)) + +#define acl_foreach_reverse ACL_FOREACH_REVERSE +#define acl_foreach ACL_FOREACH +#define acl_iter_info ACL_ITER_INFO + +#endif diff --git a/lib_acl/include/stdlib/acl_loadcfg.h b/lib_acl/include/stdlib/acl_loadcfg.h new file mode 100644 index 000000000..24e01847c --- /dev/null +++ b/lib_acl/include/stdlib/acl_loadcfg.h @@ -0,0 +1,48 @@ + +#ifndef _LIB_UTIL_LOADCFG_INCLUDE_H_ +#define _LIB_UTIL_LOADCFG_INCLUDE_H_ + +# ifdef __cplusplus +extern "C" { +# endif + +#include "acl_define.h" +#include "acl_array.h" + +typedef struct ACL_CFG_PARSER ACL_CFG_PARSER; + +typedef struct ACL_CFG_LINE { + char **value; /* store the separated values of the line */ + char *pdata; /* point to the beginning of the line data */ + int ncount; /* how many values in this line data, + * if ncount == 0, then this is an + * invalid line, but still be stored + * here in pdata. + */ + int line_number; /* 该行在配置文件中的行号 */ +} ACL_CFG_LINE; + +typedef struct ACL_CFG_FN { + const char *name; + int (*func)(const ACL_CFG_LINE *); +} ACL_CFG_FN; + +typedef void (*ACL_CFG_WALK_FN)(void *arg); + +ACL_API ACL_CFG_PARSER *acl_cfg_parser_load(const char *pathname, const char *delimiter); +ACL_API void acl_cfg_parser_free(ACL_CFG_PARSER *parser); +ACL_API void acl_cfg_parser_walk(ACL_CFG_PARSER *parser, ACL_CFG_WALK_FN walk_fn); +ACL_API int acl_cfg_line_replace(ACL_CFG_LINE *cfg_line, const char **value, int from, int to); +ACL_API ACL_CFG_LINE *acl_cfg_parser_index(const ACL_CFG_PARSER *parser, int idx); +ACL_API int acl_cfg_parser_size(const ACL_CFG_PARSER *parser); +ACL_API int acl_cfg_parser_dump(const ACL_CFG_PARSER *parser, const char *pathname, const char *delimiter); +ACL_API int acl_cfg_parser_append(ACL_CFG_PARSER *parser, ACL_CFG_LINE *cfg_line); +ACL_API int acl_cfg_parser_delete(ACL_CFG_PARSER *parser, const char *name); +ACL_API ACL_CFG_LINE *acl_cfg_line_new(const char **value, int ncount); + +# ifdef __cplusplus +} +# endif + +#endif + diff --git a/lib_acl/include/stdlib/acl_make_dirs.h b/lib_acl/include/stdlib/acl_make_dirs.h new file mode 100644 index 000000000..c0e7efeda --- /dev/null +++ b/lib_acl/include/stdlib/acl_make_dirs.h @@ -0,0 +1,24 @@ +#ifndef __ACL_MAKE_DIRS_H_INCLUDED__ +#define __ACL_MAKE_DIRS_H_INCLUDED__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "acl_define.h" + +/** + * 功能: 创建多级目录结构 + * 如创建 "/tmp/dir1/dir2" (for unix) 或 "C:\test\test1\test2" (for win32) + * @param path: 一级或多级目录路径 + * @param perms: 创建权限(如: 0755, 0777, 0644 ...) + * @return == 0: OK; == -1, Err + */ +ACL_API int acl_make_dirs(const char *path, int perms); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/include/stdlib/acl_malloc.h b/lib_acl/include/stdlib/acl_malloc.h new file mode 100644 index 000000000..5319ffd45 --- /dev/null +++ b/lib_acl/include/stdlib/acl_malloc.h @@ -0,0 +1,159 @@ +#ifndef __ACL_MALLOC_INCLUDE__ +#define __ACL_MALLOC_INCLUDE__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "acl_define.h" + +/* + * Memory alignment of memory allocator results. + * By default we align for doubles. + */ + +#ifndef ALIGN_TYPE +# if defined(__hpux) && defined(__ia64) +# define ALIGN_TYPE __float80 +# elif defined(__ia64__) +# define ALIGN_TYPE long double +# else +# define ALIGN_TYPE double +# endif +#endif + +ACL_API void acl_memory_debug_start(void); +ACL_API void acl_memory_debug_stop(void); +ACL_API void acl_memory_debug_stack(int onoff); +ACL_API void acl_memory_stat(void); +ACL_API void acl_memory_alloc_stat(void); + +/** + * 打开动态内存池功能 + * @param max_size {size_t} 内存池最大空间大小,单位为字节 + * @param use_mutex {int} 内存池内部是否采用互斥锁,如果是多线程程序则应该 + * 设置 use_mutex 为非0值 + */ +ACL_API void acl_mempool_open(size_t max_size, int use_mutex); + +/** + * 关闭内存池功能 + */ +ACL_API void acl_mempool_close(void); + +/** + * 当内存池打开后,可以通过此函数控制内存池状态 + */ +ACL_API void acl_mempool_ctl(int name, ...); +#define ACL_MEMPOOL_CTL_END 0 /**< 结束标志 */ +#define ACL_MEMPOOL_CTL_MUTEX 1 /**< 控制内存池是否加锁 */ +#define ACL_MEMPOOL_CTL_DISABLE 2 /**< 是否关闭内存池 */ + +/** + * 当前内存池已经分配的内存大小 + * @return {int} 已经分配的内存大小 + */ +ACL_API int acl_mempool_total_allocated(void); + +/*---------------- ACL库中缺省的内存分配、释放等管理接口 ---------------------*/ + +/** + * 获得当前内存指针的一些状态信息,如该内存的实际大小与对外分配大小 + * @param filename {const char*} 调用该函数的文件名,可以为空 + * @param line {int} 调用该函数所在源文件中的行数 + * @param ptr {void*} 动态分配的内存外部地址 + * @param len {size_t*} 存储该内存的外部可用大小 + * @param read_len {size*} 存储该内存的实际大小(因为内部有一些控制字节) + */ +ACL_API void acl_default_memstat(const char *filename, int line, + void *ptr, size_t *len, size_t *real_len); + +/** + * ACL库中缺省的内存分配器接口, 分配内存但并不初始化所分配内存的内容 + * 类似于标准库中的 malloc + * @param filename {const char*} 调用该函数的文件名,可以为空 + * @param line {int} 调用该函数所在源文件中的行数 + * @param size {size_t} 需要的内存大小 + * @return {void*} 分配的可用地址, 如果分配失败,则内部会自动coredump + * 需要调用 acl_default_free 释放 + */ +ACL_API void *acl_default_malloc(const char *filename, int line, size_t size); + +/** + * ACL库中缺省的内存分配器接口, 分配内存并初始化所分配内存的内容为0 + * 类似于标准库中的 calloc + * @param filename {const char*} 调用该函数的文件名,可以为空 + * @param line {int} 调用该函数所在源文件中的行数 + * @param nmemb {size_t} 内存块的个数 + * @param size {size_t} 每个内存块的大小 + * @return {void*} 分配的可用地址, 如果分配失败,则内部会自动coredump + * 需要调用 acl_default_free 释放 + */ +ACL_API void *acl_default_calloc(const char *filename, int line, size_t nmemb, size_t size); + +/** + * ACL库中缺省的内存分配器接口, 类似于标准库的 realloc + * @param filename {const char*} 调用该函数的文件名,可以为空 + * @param line {int} 调用该函数所在源文件中的行数 + * @param ptr {void*} 之前用ACL库所分配的内存地址 + * @param size {size_t} 需要的内存大小 + * @return {void*} 分配的可用地址, 如果分配失败,则内部会自动coredump + * 需要调用 acl_default_free 释放 + */ +ACL_API void *acl_default_realloc(const char *filename, int line, void *ptr, size_t size); + +/** + * 复制字符串,类似于标准库中的 strdup + * @param filename {const char*} 调用该函数的文件名,可以为空 + * @param line {int} 调用该函数所在源文件中的行数 + * @param str {const char*} 源字符串地址 + * @return {char*} 新复制的字符串地址,需要调用 acl_default_free 释放 + */ +ACL_API char *acl_default_strdup(const char *filename, int line, const char *str); + +/** + * 复制字符串,但限制最大字符串长度,类似于标准库中的 strndup + * @param filename {const char*} 调用该函数的文件名,可以为空 + * @param line {int} 调用该函数所在源文件中的行数 + * @param str {const char*} 源字符串地址 + * @param len {size_t} 限制新字符串的最大长度值 + * @return {char*} 新复制的字符串地址,需要调用 acl_default_free 释放 + */ +ACL_API char *acl_default_strndup(const char *filename, int line, const char *str, size_t len); + +/** + * 复制内存数据 + * @param filename {const char*} 调用该函数的文件名,可以为空 + * @param line {int} 调用该函数所在源文件中的行数 + * @param ptr {const void*} 源内存地址 + * @param len {size_t} 源内存区域的长度 + * @return {void*} 新复制的内存地址 + */ +ACL_API void *acl_default_memdup(const char *filename, int line, const void *ptr, size_t len); + +/** + * 释放由 acl_devault_xxx 所分配的内存动态内存 + * @param filename {const char*} 调用该函数的文件名,可以为空 + * @param line {int} 调用该函数所在源文件中的行数 + */ +ACL_API void acl_default_free(const char *filename, int line, void *ptr); + +/*------- acl_mymalloc.h 内存管理接口中的宏调用所使用的内存管理函数接口 ------*/ +/* 该函数接口集其实是调用了其它的内存管理来进行内存的分配与释放等管理操作的,它 + * 提供了高级宏调用的外部使用接口,方便用户操作。 + */ + +ACL_API void *acl_malloc_glue(const char *filename, int line, size_t size); +ACL_API void *acl_calloc_glue(const char *filename, int line, size_t nmemb, size_t size); +ACL_API void *acl_realloc_glue(const char *filename, int line, void *ptr, size_t size); +ACL_API char *acl_strdup_glue(const char *filename, int line, const char *str); +ACL_API char *acl_strndup_glue(const char *filename, int line, const char *str, size_t len); +ACL_API void *acl_memdup_glue(const char *filename, int line, const void *ptr, size_t len); +ACL_API void acl_free_glue(const char *filename, int line, void *ptr); +ACL_API void acl_free_fn_glue(void *ptr); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/include/stdlib/acl_mem_hook.h b/lib_acl/include/stdlib/acl_mem_hook.h new file mode 100644 index 000000000..1aa213e61 --- /dev/null +++ b/lib_acl/include/stdlib/acl_mem_hook.h @@ -0,0 +1,38 @@ +#ifndef __ACL_MEM_HOOK_INCLUDE_H__ +#define __ACL_MEM_HOOK_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "acl_define.h" + +/** + * 设置内存分配、释放的注册函数,当ACL内部分配释放内存时便调用这些注册的函数 + * 在调用此函数进行注册时必须保证这几个函数指针参数均非空 + * @param malloc_hook {void *(*)(const char* fname, int lineno, size_t)} + * @param calloc_hook {void *(*)(const char* fname, int lineno, size_t, size_t)} + * @param realloc_hook {void *(*)(const char* fname, int lineno, void *, size_t)} + * @param strdup_hook {void *(*)(const char* fname, int lineno, const char*)} + * @param strndup_hook {void *(*)(const char* fname, int lineno, const char*, size_t)} + * @param memdup_hook {void *(*)(const char* fname, int lineno, const void *, size_t)} + * @param free_hook {void (*)(const char* fname, int lineno, void*)} + */ +ACL_API void acl_mem_hook(void *(*malloc_hook)(const char*, int, size_t), + void *(*calloc_hook)(const char*, int, size_t, size_t), + void *(*realloc_hook)(const char*, int, void*, size_t), + char *(*strdup_hook)(const char*, int, const char*), + char *(*strndup_hook)(const char*, int, const char*, size_t), + void *(*memdup_hook)(const char*, int, const void*, size_t), + void (*free_hook)(const char*, int, void*)); + +/** + * 取消之前设置的内存勾子函数,恢复为缺省状态 + */ +ACL_API void acl_mem_unhook(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/include/stdlib/acl_mem_slice.h b/lib_acl/include/stdlib/acl_mem_slice.h new file mode 100644 index 000000000..8203dc50b --- /dev/null +++ b/lib_acl/include/stdlib/acl_mem_slice.h @@ -0,0 +1,21 @@ +#ifndef __ACL_MEM_SLICE_INCLUDE_H__ +#define __ACL_MEM_SLICE_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct ACL_MEM_SLICE ACL_MEM_SLICE; + +ACL_API ACL_MEM_SLICE *acl_mem_slice_init(int base, int nslice, + int nalloc_gc, unsigned int slice_flag); +ACL_API void acl_mem_slice_delay_destroy(void); +ACL_API void acl_mem_slice_destroy(void); +ACL_API int acl_mem_slice_gc(void); +ACL_API void acl_mem_slice_set(ACL_MEM_SLICE *mem_slice); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/include/stdlib/acl_meter_time.h b/lib_acl/include/stdlib/acl_meter_time.h new file mode 100644 index 000000000..34c61c36e --- /dev/null +++ b/lib_acl/include/stdlib/acl_meter_time.h @@ -0,0 +1,16 @@ +#ifndef __ACL_METER_TIME_INCLUDE_H__ +#define __ACL_METER_TIME_INCLUDE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +ACL_API double acl_meter_time(const char *filename, int line, const char *info); + +#define ACL_METER_TIME(info) acl_meter_time(__FILE__, __LINE__, info) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/include/stdlib/acl_msg.h b/lib_acl/include/stdlib/acl_msg.h new file mode 100644 index 000000000..b9ce54e84 --- /dev/null +++ b/lib_acl/include/stdlib/acl_msg.h @@ -0,0 +1,313 @@ + +#ifndef _ACL_MSG_H_INCLUDE_ +#define _ACL_MSG_H_INCLUDE_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "acl_define.h" +#include +#include "acl_vstream.h" + +#undef USE_PRINTF_MACRO + +/** + * 在将写日志至日志文件前回调用户自定义的函数,且将日志信息传递给该函数, + * 只有当用户通过 acl_msg_pre_write 进行设置后才生效 + * @param ctx {void*} 用户的自定义参数 + * @param fmt {const char*} 格式参数 + * @param ap {va_list} 格式参数列表 + */ +typedef void (*ACL_MSG_PRE_WRITE_FN)(void *ctx, const char *fmt, va_list ap); + +/** + * 应用通过此函数类型可以自定义日志打开函数,当应用在打开日志前调用 + * acl_msg_register 注册了自定义打开函数,则当应用调用 acl_msg_open + * 时会调用此定义打开日志函数打开日志,否则则用缺省的方法打开日志文件 + * @param file_name {const char*} 回传给自定义日志打开函数的参数,即 + * 将日志文件回传 + * @param ctx {void*} 应用传递进去的参数 + * @return {int} 如果自定义打开日志函数返回 -1 则调用缺省的日志打开函数 + */ +typedef int (*ACL_MSG_OPEN_FN) (const char *file_name, void *ctx); + +/** + * 应用通过此函数类型可以自定义日志关闭函数,当应用在打开日志前调用 + * acl_msg_register 注册了自定义打开函数,则当应用调用 acl_msg_close + * 时会调用此定义关闭日志函数关闭日志,否则则用缺省的方法关闭日志文件 + * @param ctx {void*} 应用传递进去的参数 + */ +typedef void (*ACL_MSG_CLOSE_FN) (void *ctx); + +/** + * 应用通过此函数类型可以自定义日志记录函数,当应用在打开日志前调用 + * acl_msg_register 注册了自定义记录函数,则当应用写日志时便用此自定义 + * 函数记录日志,否则用缺省的日志记录函数 + * @param ctx {void*} 应用传递进去的参数 + * @param fmt {const char*} 格式参数 + * @param ap {va_list} 参数列表 + */ +typedef void (*ACL_MSG_WRITE_FN) (void *ctx, const char *fmt, va_list ap); + +/** + * 在打开日志前调用此函数注册应用自己的日志打开函数、日志关闭函数、日志记录函数 + * @param open_fn {ACL_MSG_OPEN_FN} 自定义日志打开函数 + * @param close_fn {ACL_MSG_CLOSE_FN} 自定义日志关闭函数 + * @param write_fn {ACL_MSG_WRITE_FN} 自定义日志记录函数 + * @param ctx {void*} 自定义参数 + */ +ACL_API void acl_msg_register(ACL_MSG_OPEN_FN open_fn, ACL_MSG_CLOSE_FN close_fn, + ACL_MSG_WRITE_FN write_fn, void *ctx); + +/** + * 将 acl_msg_register 注册自定义函数清除,采用缺省的日志函数集 + */ +ACL_API void acl_msg_unregister(void); + +/** + * 在打开日志前调用此函数注册应用的私有函数,在记录日志前会先记录信息通过 + * 此注册的函数传递给应用 + * @param pre_write {ACL_MSG_PRE_WRITE_FN} 日志记录前调用的函数 + * @param ctx {void*} 自定义参数 + */ +ACL_API void acl_msg_pre_write(ACL_MSG_PRE_WRITE_FN pre_write, void *ctx); + +/** + * 全局变量,表示调试级别 + * @deprecated 将来该参数将只会内部使用,外部应用不应用它 + */ +extern ACL_API int acl_msg_verbose; + +/** + * 当未调用 acl_msg_open 方式打开日志时,调用了 acl_msg_info/error/fatal/warn + * 的操作,是否允许信息输出至标准输出屏幕上,通过此函数来设置该开关,该开关 + * 仅影响是否需要将信息输出至终端屏幕而不影响是否输出至文件中 + * @param onoff {int} 非 0 表示允许输出至屏幕 + */ +ACL_API void acl_msg_stdout_enable(int onoff); + +/** + * 日志打开函数 + * @param log_file {const char*} 日志接收者集合,由 "|" 分隔,接收器 + * 可以是本地文件或远程套接口,如: + * /tmp/test.log|UDP:127.0.0.1:12345|TCP:127.0.0.1:12345|UNIX:/tmp/test.sock + * 该配置要求将所有日志同时发给 /tmp/test.log, UDP:127.0.0.1:12345, + * TCP:127.0.0.1:12345 和 UNIX:/tmp/test.sock 四个日志接收器对象 + * @param plog_pre {const char*} 日志记录信息前的提示信息,建议用进程 + * @param info_pre {const char*} 日志记录信息前的提示信息 + */ +ACL_API void acl_msg_open(const char *log_file, const char *info_pre); + +/** + * 日志打开函数 + * @param fp {ACL_VSTREAM *} 日志文件流句柄 + * @param info_pre {const char*} 日志记录信息前的提示信息 + */ +ACL_API void acl_msg_open2(ACL_VSTREAM *fp, const char *info_pre); + +/** + * 关闭日志函数 + */ +ACL_API void acl_msg_close(void); + +/** + * 当记录日志信息至日志文件时,需要调用如下的日志记录函数 + */ + +#ifndef USE_PRINTF_MACRO + +/** + * 一般级别日志信息记录函数 + * @param fmt {const char*} 参数格式 + * @param ... 变参序列 + */ +#ifdef WIN32 +ACL_API void acl_msg_info(const char *fmt,...); +#else +ACL_API void __attribute__((format(printf,1,2))) + acl_msg_info(const char *fmt,...); +#endif + +/** + * 警告级别日志信息记录函数 + * @param fmt {const char*} 参数格式 + * @param ... 变参序列 + */ +#ifdef WIN32 +ACL_API void acl_msg_warn(const char *fmt,...); +#else +ACL_API void __attribute__((format(printf,1,2))) + acl_msg_warn(const char *fmt,...); +#endif + +/** + * 错误级别日志信息记录函数 + * @param fmt {const char*} 参数格式 + * @param ... 变参序列 + */ +#ifdef WIN32 +ACL_API void acl_msg_error(const char *fmt,...); +#else +ACL_API void __attribute__((format(printf,1,2))) + acl_msg_error(const char *fmt,...); +#endif + +/** + * 致命级别日志信息记录函数 + * @param fmt {const char*} 参数格式 + * @param ... 变参序列 + */ +#ifdef WIN32 +ACL_API void acl_msg_fatal(const char *fmt,...); +#else +ACL_API void __attribute__((format(printf,1,2))) + acl_msg_fatal(const char *fmt,...); +#endif + +/** + * 致命级别日志信息记录函数 + * @param status {int} 当前未用 + * @param fmt {const char*} 参数格式 + * @param ... 变参序列 + */ +#ifdef WIN32 +ACL_API void acl_msg_fatal_status(int status, const char *fmt,...); +#else +ACL_API void __attribute__((format(printf,2,3))) + acl_msg_fatal_status(int status, const char *fmt,...); +#endif + +/** + * 恐慌级别日志信息记录函数 + * @param fmt {const char*} 参数格式 + * @param ... 变参序列 + */ +#ifdef WIN32 +ACL_API void acl_msg_panic(const char *fmt,...); +#else +ACL_API void __attribute__((format(printf,1,2))) + acl_msg_panic(const char *fmt,...); +#endif + +/** + * 一般级别日志信息记录函数 + * @param fmt {const char*} 参数格式 + * @param ap {va_list} 变参列表 + */ +ACL_API void acl_msg_info2(const char *fmt, va_list ap); + + +/** + * 警告级别日志信息记录函数 + * @param fmt {const char*} 参数格式 + * @param ap {va_list} 变参列表 + */ +ACL_API void acl_msg_warn2(const char *fmt, va_list ap); + +/** + * 错误级别日志信息记录函数 + * @param fmt {const char*} 参数格式 + * @param ap {va_list} 变参列表 + */ +ACL_API void acl_msg_error2(const char *fmt, va_list ap); + + +/** + * 致命级别日志信息记录函数 + * @param fmt {const char*} 参数格式 + * @param ap {va_list} 变参列表 + */ +ACL_API void acl_msg_fatal2(const char *fmt, va_list ap); + +/** + * 致命级别日志信息记录函数 + * @param status {int} 当前未用 + * @param fmt {const char*} 参数格式 + * @param ap {va_list} 变参列表 + */ +ACL_API void acl_msg_fatal_status2(int status, const char *fmt, va_list ap); + +/** + * 恐慌级别日志信息记录函数 + * @param fmt {const char*} 参数格式 + * @param ap {va_list} 变参列表 + */ +ACL_API void acl_msg_panic2(const char *fmt, va_list ap); +#else + +/** + * 当记录日志信息至标准输出时,需要调用如下的日志记录函数 + */ + +#include + +#undef acl_msg_info +#undef acl_msg_warn +#undef acl_msg_error +#undef acl_msg_fatal +#undef acl_msg_panic + +#define acl_msg_info acl_msg_printf +#define acl_msg_warn acl_msg_printf +#define acl_msg_error acl_msg_printf +#define acl_msg_fatal acl_msg_printf +#define acl_msg_panic acl_msg_printf + +#endif + +/** + * 类似于标准C的 strerror, 但该函数是跨平台且是线程安全的,获得对应某个错误 + * 号的错误描述信息 + * @param errnum {unsigned int} 错误号 + * @param buffer {char*} 存储错误描述信息的内存缓冲区 + * @param size {int} buffer 缓冲区的大小 + * @return {const char*} 返回的地址应与 buffer 相同 + */ +ACL_API const char *acl_strerror(unsigned int errnum, char *buffer, int size); + +/** + * 获得上次系统调用出错时的错误描述信息 + * @param buffer {char*} 存储错误描述信息的内存缓冲区 + * @param size {int} buffer 的空间大小 + * @return {const char*} 返回的地址应与 buffer 相同 + */ +ACL_API const char *acl_last_strerror(char *buffer, int size); + +/** + * 获得上次系统调用出错时的错误描述信息,该函数内部采用了线程局部变量,所以是线程 + * 安全的,但使用起来更简单些 + * @return {const char *} 返回错误提示信息 + */ +ACL_API const char *acl_last_serror(void); + +/** + * 获得上次系统调用出错时的错误号 + * @return {int} 错误号 + */ +ACL_API int acl_last_error(void); + +/** + * 手工设置错误号 + * @param errnum {int} 错误号 + */ +ACL_API void acl_set_error(int errnum); + +/** + * 输出信息至标准输出 + * @param fmt {const char*} 格式参数 + * @param ... 变参序列 + */ +#ifdef WIN32 +ACL_API void acl_msg_printf(const char *fmt,...); +#else +ACL_API void __attribute__((format(printf,1,2))) + acl_msg_printf(const char *fmt,...); +#endif + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/include/stdlib/acl_myflock.h b/lib_acl/include/stdlib/acl_myflock.h new file mode 100644 index 000000000..4e2915603 --- /dev/null +++ b/lib_acl/include/stdlib/acl_myflock.h @@ -0,0 +1,47 @@ +#ifndef __ACL_MYFLOCK_H_INCLUDED__ +#define __ACL_MYFLOCK_H_INCLUDED__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "acl_define.h" + +/** + * 对打开的文件句柄进行加锁 + * @param fd {ACL_FILE_HANDLE} 文件句柄 + * @param lock_style {int} 系统提供的API加锁类型(仅对UNIX有效) + * ACL_MYFLOCK_STYLE_FLOCK or ACL_MYFLOCK_STYLE_FCNTL + * @param operation {int} 加锁操作方式, ACL_MYFLOCK_OP_XXX + * @return {int} 0: 加锁成功; -1: 加锁失败 + */ +ACL_API int acl_myflock(ACL_FILE_HANDLE fd, int lock_style, int operation); + +/* + * Lock styles. + */ +#define ACL_MYFLOCK_STYLE_FLOCK 1 /**< 调用 flock 函数加锁(unix) */ +#define ACL_MYFLOCK_STYLE_FCNTL 2 /**< 调用 fcntl 函数加锁(unix) */ + +/* + * Lock request types. + */ +#define ACL_MYFLOCK_OP_NONE 0 /**< 解锁 */ +#define ACL_MYFLOCK_OP_SHARED 1 /**< 共享锁 */ +#define ACL_MYFLOCK_OP_EXCLUSIVE 2 /**< 排它独享锁 */ +#define ACL_MYFLOCK_OP_NOWAIT 4 /**< 无等待加锁, 可以与 + ACL_MYFLOCK_OP_SHARED, + 或 ACL_MYFLOCK_OP_EXCLUSIVE 相或 */ + +/** + * 加锁方式的位集合 + */ +#define ACL_MYFLOCK_OP_BITS \ + (ACL_MYFLOCK_OP_SHARED | ACL_MYFLOCK_OP_EXCLUSIVE | ACL_MYFLOCK_OP_NOWAIT) + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/include/stdlib/acl_mylog.h b/lib_acl/include/stdlib/acl_mylog.h new file mode 100644 index 000000000..da01864a7 --- /dev/null +++ b/lib_acl/include/stdlib/acl_mylog.h @@ -0,0 +1,95 @@ +/* +**============================================================================ +** +** +** +** mylog.h, writen by zsx +** +** +** +**============================================================================ +*/ +#ifndef __ACL_MYLOG_INCLUDE_H_ +#define __ACL_MYLOG_INCLUDE_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include "acl_define.h" +#include "acl_vstream.h" + +#ifdef ACL_UNIX +#include +#endif + +typedef struct ACL_LOG ACL_LOG; + +/** + * 将当前的时间转换成日志记录格式的时间格式 + * @param buf {char*} 内存存储区 + * @param size {size_t} buf 的空间大小 + */ +ACL_API void acl_logtime_fmt(char *buf, size_t size); + +/** + * 设置是否记录线程ID号,默认情况下是不记录的 + * @param onoff {int} 非 0 表示记录线程ID,否则不记录 + */ +ACL_API void acl_log_add_tid(int onoff); + +/** + * 设置日志的文件流句柄 + * @param fp {ACL_VSTREAM *} 文件流句柄 + * @param plog_pre {const char*} 日志记录信息前的提示信息,建议用进程 + */ +ACL_API void acl_log_fp_set(ACL_VSTREAM *fp, const char *plog_pre); + +/** + * 打开日志文件 + * @param recipients {const char*} 日志接收器列表,由 "|" 分隔,接收器 + * 可以是本地文件或远程套接口,如: + * /tmp/test.log|UDP:127.0.0.1:12345|TCP:127.0.0.1:12345|UNIX:/tmp/test.sock + * 该配置要求将所有日志同时发给 /tmp/test.log, UDP:127.0.0.1:12345, + * TCP:127.0.0.1:12345 和 UNIX:/tmp/test.sock 四个日志接收器对象 + * @param plog_pre {const char*} 日志记录信息前的提示信息,建议用进程 + * 名填写此值 + */ +ACL_API int acl_open_log(const char *recipients, const char *plog_pre); + +/** + * 写日志 + * @param fmt {const char*} 格式参数 + * @param ... 参数序列 + * @return {int} 写入日志文件的数据量 + */ +#ifdef WIN32 +ACL_API int acl_write_to_log(const char *fmt, ...); +#else +ACL_API int __attribute__((format(printf,1,2))) + acl_write_to_log(const char *fmt, ...); +#endif + +/** + * 写日志 + * @param info {const char*} 日志信息的提示信息 + * @param fmt {const char*} 格式参数 + * @param ap {va_list} 参数列表 + * @return {int} 写入日志文件的数据量 + */ +ACL_API int acl_write_to_log2(const char *info, const char *fmt, va_list ap); + +/** + * 关闭日志文件句柄 + */ +ACL_API void acl_close_log(void); + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/lib_acl/include/stdlib/acl_mymalloc.h b/lib_acl/include/stdlib/acl_mymalloc.h new file mode 100644 index 000000000..6e912b992 --- /dev/null +++ b/lib_acl/include/stdlib/acl_mymalloc.h @@ -0,0 +1,87 @@ +/* + * @file mymalloc.h + * @author zsx + * @date 2003-12-15 + * @version 1.0 + * @brief 本文件为使用ACL库时的高级内存分配接口,用户应该主要使用此接口来 + * 进行内存的分配及释放, 用户可以先行调用 acl_mem_hook.h 中的函数 + * 接口注册自己的内存分配与释放等管理接口,这样再调用 acl_myxxx 类 + * 的宏时便自动切换到用户自己的内存管理接口调用上 + */ + +#ifndef _ACL_MYMALLOC_INCLUDE_H_ +#define _ACL_MYMALLOC_INCLUDE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "acl_define.h" +#include "acl_malloc.h" + +/** + * 动态分配内存的宏定义,不初始化新分配的内存空间 + * @param size {size_t} 分配长度 + * @return {void *} + */ +#define acl_mymalloc(size) acl_malloc_glue(__FILE__, __LINE__, size) + +/** + * 动态分配内存的宏定义,初始化新分配的内存空间为零 + * @param nmemb {size_t} 元素个数 + * @param size {size_t} 每个元素的长度 + * @return {void *} + */ +#define acl_mycalloc(nmemb, size) acl_calloc_glue(__FILE__, __LINE__, nmemb, size) + +/** + * 重新动态分配内存的宏定义 + * @param ptr {void*} 原内存地址 + * @param size {size_t} 新分配内存时要求的长度 + * @return {void *} + */ +#define acl_myrealloc(ptr, size) acl_realloc_glue(__FILE__, __LINE__, (ptr), size) + +/** + * 动态复制字符串宏定义 + * @param str {const char*} 源字符串 + * @return {char*} 新的字符串,需用 acl_myfree 释放 + */ +#define acl_mystrdup(str) acl_strdup_glue(__FILE__, __LINE__, (str)) + +/** + * 动态复制字符串宏定义,并限定最大内存空间大小 + * @param str {const char*} 源字符串 + * @param len {size_t} 新字符串最大内存空间大小限制值 + * @return {char*} 新的字符串,需用 acl_myfree 释放 + */ +#define acl_mystrndup(str, len) acl_strndup_glue(__FILE__, __LINE__, (str), len) + +/** + * 动态复制内存宏定义 + * @param ptr {const void*} 源内存地址 + * @param len {size_t} 源内存大小 + * @return {void*} 新的字符串,需用 acl_myfree 释放 + */ +#define acl_mymemdup(ptr, len) acl_memdup_glue(__FILE__, __LINE__, (ptr), len) + +/** + * 释放动态分配的内存空间 + * @param _ptr_ {void*} 动态内存地址 + */ +#define acl_myfree(_ptr_) do { \ + acl_free_glue(__FILE__, __LINE__, (_ptr_)); \ + (_ptr_) = NULL; \ +} while (0) + +/** + * XXX: 因为该函数用于回调函数,所以无法进行宏定义转换, 将来再完善此函数 + */ +#define acl_myfree_fn acl_free_fn_glue + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/include/stdlib/acl_mystring.h b/lib_acl/include/stdlib/acl_mystring.h new file mode 100644 index 000000000..9aec2820d --- /dev/null +++ b/lib_acl/include/stdlib/acl_mystring.h @@ -0,0 +1,314 @@ + +#ifndef __ACL_MYSTRING_INCLUDE_H__ +#define __ACL_MYSTRING_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "acl_define.h" + +#include + +/** + * 功能: 安全的字符串拷贝宏函数, 可以保证最后一个字节为 "\0" + * @param _obj {char*} 目的内存区指针 + * @param _src {const char*} 源字符串指针 + * @param _size {int} 目的内存区的空间大小 + */ +#ifndef ACL_SAFE_STRNCPY +#ifdef ACL_MS_WINDOWS +#define ACL_SAFE_STRNCPY(_obj, _src, _size) do { \ + size_t _n = strlen(_src); \ + _n = _n > (size_t ) _size - 1? (size_t) _size - 1 : _n; \ + memcpy(_obj, _src, _n); \ + _obj[_n] = 0; \ +} while (0) +#else +#define ACL_SAFE_STRNCPY(_obj, _src, _size) do { \ + if (_obj != NULL && _src != NULL && (int)_size >= 0) { \ + strncpy(_obj, _src, _size); \ + if ((int)_size > 0) \ + _obj[_size - 1] = 0; \ + else \ + _obj[_size] = 0; \ + } \ +} while (0) +#endif +#endif + +/** + * 将字符串转换为小写,直接在原内存空间进行操作 + * @param string {char *} 给定的字符串 + * @return {char*} 成功返回字符串地址,否则返回 NULL + */ +ACL_API char *acl_lowercase(char *string); + +/** + * 将给定字符串的前 n 个字节转换为小写 + * @param string {char *} 给定的字符串 + * @param n {int} 最多仅转换的字节数 + * @return {char*} 成功返回字符串地址,否则返回 NULL + */ +ACL_API char *acl_lowercase2(char *string, size_t n); + +/** + * 将给定字符串转换为小写,结果存储于另一个内存区内 + * @param string {const char*} 源字符串 + * @param buf {char*} 存储转换结果的内存指针 + * @param size {size_t} buf 的空间大小 + * @return {char*} 成功返回字符串地址,否则返回 NULL + */ +ACL_API char *acl_lowercase3(const char *string, char *buf, size_t size); + +/** + * 将字符串转换为大写,直接在原内存空间进行操作 + * @param string {char *} 给定的字符串 + * @return {char*} 成功返回字符串地址,否则返回 NULL + */ +ACL_API char *acl_uppercase(char *string); + +/** + * 将字符串转换为大写,直接在原内存空间进行操作, 最大转换长度有限制 + * @param string {char *} 给定的字符串 + * @param n {int} 最多仅转换的字节数 + * @return {char*} 成功返回字符串地址,否则返回 NULL + */ +ACL_API char *acl_uppercase2(char *string, size_t n); + +/** + * 将给定字符串的前 n 个字节转换为大写 + * @param string {char *} 给定的字符串 + * @param buf {char*} 存储转换结果的内存区 + * @param size {size_t} buf 的空间大小(字节) + * @return {char*} 成功返回字符串地址,否则返回 NULL + */ +ACL_API char *acl_uppercase3(const char *string, char *buf, size_t size); + +/** + * 将给定字符串用另一个分隔符字符串进行分割 + * @param src {char**} 需要被分割的字符串的地址的指针,必须是非空指针, + * 可以是空字符串,此时该函数返回 NULL + * @param sep {const char*} 分隔符,非空字符串 + * @return {char*} 当前被分割的字符串的指针位置,src 指向下一个将要进行 + * 分隔的起始位置; + * 1)当返回 NULL 时,则表示分隔过程结束,此时 src 的指针位置被赋予 '\0'; + * 2)当返回非 NULL 时,则此时 src 指向的字符串可能是或不是空字符串, + * 如果指向空字符串,则再次分隔时函数肯定能返回 NULL,否则,当再次分隔时 + * 函数返回非 NULL 指针 + * 举例: 源字符串:"abcd=|efg=|hijk", 分隔符 "=|",则第一次分隔后 + * src 将指向 "efg",而返回的地址为 "abcd" + */ +ACL_API char *acl_mystrtok(char **src, const char *sep); + +/** + * 获得一个逻辑行, 如果某行的尾部由连接符 "\\" 连接,则将下一行合并至本行, + * 同时将一行字符串中的以及转义字符回车换行("\r\n" or "\n")去掉 + * @param src {char**} 源字符串的地址指针 + * @return {char*} 返回一行数据, 如果返回空则表示没有可用的逻辑行 + */ +ACL_API char *acl_mystrline(char **src); + +/** + * 去掉给定字符串中的 " ", "\t" + * @param str {char*} 源字符串 + * @return {char*} 与源字符串相同的地址 + */ +ACL_API char *acl_mystr_trim(char *str); + +/** + * 从源字符串中去掉给定字符串 + * @param haystack {const char*} 源字符串 + * @param needle {const char*} 需要从源字符串中被整体去掉的字符串 + * @param buf {char*} 存储结果的内存开始位置 + * @param bsize {int} buf 的空间大小 + * @return {int} 拷贝至 buf 中的字符串长度 + */ +ACL_API int acl_mystr_strip(const char *haystack, const char *needle, char *buf, int bsize); + +/** + * 从源字符串中找到一行的结束位置并去掉包含回车换行符及其以后的字符串 + * @param str_src {char*} 源字符串 + * @return {int} 0 表示成功,-1表示失败, 也许应该返回最后转换结果的长度! + */ +ACL_API int acl_mystr_truncate_byln(char *str_src); + +/** + * 从后向前比较两个给定字符串,大小写不敏感且限定最大比较范围 + * @param s1 {const char*} 字符串地址 + * @param s2 {const char*} 字符串地址 + * @param n {size_t} 最大比较范围 + * @return {int} 比较结果. 0: 相等, >0: 第一个字符串大于第二个字符串, + * < 0: 第一个字符串小第二个字符串 + */ +ACL_API int acl_strrncasecmp(const char *s1, const char *s2, size_t n); + +/** + * 从后向前比较两个给定字符串, 大小写敏感且限定最大比较范围 + * @param s1 {const char*} 字符串地址 + * @param s2 {const char*} 字符串地址 + * @param n {size_t} 最大比较范围 + * @return {int} 比较结果. 0: 相等, >0: 第一个字符串大于第二个字符串, + * < 0: 第一个字符串小第二个字符串 + */ +ACL_API int acl_strrncmp(const char *s1, const char *s2, size_t n); + +/** + * 从后向前扫描查找字符串,大小写敏感 + * @param haystack {char *} 源字符串 + * @param needle {const char *} 匹配查找的字符串 + * @return {char *} != NULL: Ok, NULL: 未发现 + */ +ACL_API char *acl_rstrstr(char *haystack, const char *needle); + +/** + * 从前向后扫描查找字符串,大小写不敏感 + * @param haystack {char *} 源字符串 + * @param needle {const char *} 匹配查找的字符串 + * @return {char *} != NULL: Ok, NULL: 未发现 + */ +ACL_API char *acl_strcasestr(char *haystack, const char *needle); + +/** + * 从后向前扫描查找字符串,大小写不敏感 + * @param haystack {char *} 源字符串 + * @param needle {const char *} 匹配查找的字符串 + * @return {char *} != NULL: Ok, NULL: 未发现 + */ +ACL_API char *acl_rstrcasestr(char *haystack, const char *needle); + +/** + * 计算给定字符串的长度,但限制了最大计算长度,以免产生越界现象,要比 strlen + * 安全,如,如果给定字符串没有以 "\0" 结尾,则该函数就不会产生越界 + * @param s {const char*} 字符串 + * @param count {size_t} 最大计算长度 + * @return {size_t} 字符串 s 的实际长度 + */ +ACL_API size_t acl_strnlen(const char * s, size_t count); + +/** + * 比较两个字符串是否相同,大小写不敏感 + * @param s1 {const char*} + * @param s2 {cosnt char*} + * @return {int} 0: 相同; < 0: s1 < s2; > 0: s1 > s2 + */ +ACL_API int acl_strcasecmp(const char *s1, const char *s2); + +/** + * 比较两个字符串是否相同,大小写不敏感,同时限定最大比较长度 + * @param s1 {const char*} + * @param s2 {cosnt char*} + * @param n {size_t} 限定比较的最大长度 + * @return {int} 0: 相同; < 0: s1 < s2; > 0: s1 > s2 + */ +ACL_API int acl_strncasecmp(const char *s1, const char *s2, size_t n); +/** + * WINDOWS下不支持一些字符串比较函数 + */ +#ifdef ACL_MS_WINDOWS +# ifndef strcasestr +# define strcasestr acl_strcasestr +# endif +# ifndef strcasecmp +# define strcasecmp acl_strcasecmp +# endif +# ifndef strncasecmp +# define strncasecmp acl_strncasecmp +# endif +#endif + +#ifndef strrncasecmp +# define strrncasecmp acl_strrncasecmp +#endif +#ifndef strrncmp +# define strrncmp acl_strrncmp +#endif + +/*---------------------------------------------------------------------------- + * 保证结果类似于如下形式: + * /home/avwall/test.txt + * @param psrc_file_path {const char*} 源字符串 + * @param pbuf {char*} 存储结果的内存区 + * @param sizeb {int} pbuf 的空间大小 + * @return {int} 0 成功,-1失败 + */ +ACL_API int acl_file_path_correct(const char *psrc_file_path, char *pbuf, int sizeb); + +/*---------------------------------------------------------------------------- + * 保证路径名经过此函数后都为如下格式: + * 源: /home/avwall/, /home//////avwall/, /home/avwall, /////home/avwall/// + * /home/avwall////, /home///avwall///, ///home///avwall/// + * 结果: /home/avwall/ + * @param psrc_dir {const char*} 源字符串 + * @param pbuf {char*} 存储结果的内存区 + * @param sizeb {int} pbuf 的空间大小 + * @return {int} 0 表示成功,-1表示失败 + */ +ACL_API int acl_dir_correct(const char *psrc_dir, char *pbuf, int sizeb); + +/*---------------------------------------------------------------------------- + * 从类似: /home/avwall/log.txt 中提取 /home/avwall/ 作为结果返回 + * @param pathname {const char*} 源字符串 + * @param pbuf {char*} 存储结果的内存区 + * @param bsize {int} pbuf 的空间大小 + * @return {int} 0 成功,-1失败 + */ +ACL_API int acl_dir_getpath(const char *pathname, char *pbuf, int bsize); + +/** + * 将数据字符串转换为64位无符号长整型 + * @param str {const char*} 字符串指针 + * @return {acl_uint64} 无符号长整型 + */ +ACL_API acl_uint64 acl_atoui64(const char *str); + +/** +* 将数据字符串转换为64位符号长整型 +* @param str {const char*} 字符串指针 +* @return {acl_int64} 无符号长整型 +*/ +ACL_API acl_int64 acl_atoi64(const char *str); + +/** + * 将64位无符号长整型转换为字符串 + * @param value {acl_uint64} 64位无符号长整型 + * @param buf {char*} 用来存取转换结果的内存空间 + * @param size {sizt_t} buf 的空间大小,其中要求其最小为21个字节 + * @return {const char*} 转换的结果,如果转换成功则不为空,否则为空 + */ +ACL_API const char *acl_ui64toa(acl_uint64 value, char *buf, size_t size); + +/** + * 将64位符号长整型转换为字符串 + * @param value {acl_int64} 64位符号长整型 + * @param buf {char*} 用来存取转换结果的内存空间 + * @param size {sizt_t} buf 的空间大小,其中要求其最小为21个字节 + * @return {const char*} 转换的结果,如果转换成功则不为空,否则为空 + */ +ACL_API const char *acl_i64toa(acl_int64 value, char *buf, size_t size); + +/** + * 将64位符号长整型转换为某进制的字符串 + * @param value {acl_int64} 64位符号长整型 + * @param buf {char*} 用来存取转换结果的内存空间 + * @param size {sizt_t} buf 的空间大小,其中要求其最小为21个字节 + * @param radix {int} 进制, 如: 8 表示八进制, 10 表示十进制, 16 表示十六进制 + * @return {const char*} 转换的结果,如果转换成功则不为空,否则为空 + */ +ACL_API const char *acl_i64toa_radix(acl_int64 value, char *buf, size_t size, int radix); + +/** + * 将64位无符号长整型转换为某进制的字符串 + * @param value {acl_int64} 64位符号长整型 + * @param buf {char*} 用来存取转换结果的内存空间 + * @param size {sizt_t} buf 的空间大小,其中要求其最小为21个字节 + * @param radix {int} 进制, 如: 8 表示八进制, 10 表示十进制, 16 表示十六进制 + * @return {const char*} 转换的结果,如果转换成功则不为空,否则为空 + */ +ACL_API const char *acl_ui64toa_radix(acl_uint64 value, char *buf, size_t size, int radix); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/include/stdlib/acl_process.h b/lib_acl/include/stdlib/acl_process.h new file mode 100644 index 000000000..86ae43aad --- /dev/null +++ b/lib_acl/include/stdlib/acl_process.h @@ -0,0 +1,25 @@ +#ifndef __ACL_PROCESS_INCLUDE_H__ +#define __ACL_PROCESS_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * 程序运行过程中获得可执行程序存储于文件系统中的全路径 + * @return {const char*} NULL: 无法获得; != NULL: 返回值即是程序在 + * 文件系统上的存储全路径 + */ +ACL_API const char *acl_process_path(void); + +/** + * 程序运行过程中获得其运行路径 + * @return {const char*} NULL: 无法获得; != NULL: 返回值即为程序的运行路径 + */ +ACL_API const char *acl_getcwd(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/include/stdlib/acl_readline.h b/lib_acl/include/stdlib/acl_readline.h new file mode 100644 index 000000000..ad682ac59 --- /dev/null +++ b/lib_acl/include/stdlib/acl_readline.h @@ -0,0 +1,26 @@ +#ifndef __ACL_READLINE_INCLUDE_H__ +#define __ACL_READLINE_INCLUDE_H__ + +#include "acl_vstream.h" +#include "acl_vstring.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * 从数据流中读取一个逻辑行数据. 空行将被忽略,如果一行的非空格起始字符为 "#" 则 + * 该行也被忽略;一个逻辑行的首个字符必须是非空格、非 "#" 字符,如果该行的后续行 + * 以空格或TAB开始,则该后续属于此逻辑行 + * @param buf {ACL_VSTRING*} 存储结果的缓冲区,不能为空 + * @param fp {ACL_VSTREAM*} 数据流句柄,不能为空 + * @param lineno {int} 如果非空,则记录该逻辑行在流中的真实行号 + * @return {ACL_VSTRING*} 如果未读到逻辑行,则返回空,否则返回输入 buf 的相同地址 + */ +ACL_API ACL_VSTRING *acl_readlline(ACL_VSTRING *buf, ACL_VSTREAM *fp, int *lineno); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/include/stdlib/acl_ring.h b/lib_acl/include/stdlib/acl_ring.h new file mode 100644 index 000000000..8fb66a3f9 --- /dev/null +++ b/lib_acl/include/stdlib/acl_ring.h @@ -0,0 +1,255 @@ + +#ifndef _ACL_RING_H_INCLUDE_ +#define _ACL_RING_H_INCLUDE_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "acl_define.h" +#include + +typedef struct ACL_RING ACL_RING; + +/** + * 数据环结构类型定义 + */ +struct ACL_RING { + ACL_RING *succ; /**< successor */ + ACL_RING *pred; /**< predecessor */ + + ACL_RING *parent; /**< the header of all the rings */ + int len; /**< the count in the ring */ +}; + +typedef struct ACL_RING_ITER { + ACL_RING *ptr; +} ACL_RING_ITER; + +/** + * 初始化数据环 + * @param ring {ACL_RING*} 数据环 + */ +ACL_API void acl_ring_init(ACL_RING *ring); + +/** + * 获得当前数据环内元素个数 + * @param ring {ACL_RING*} 数据环 + * @return {int} 数据环内元素个数 + */ +ACL_API int acl_ring_size(const ACL_RING *ring); + +/** + * 将一个新元素添加进环的头部 + * @param ring {ACL_RING*} 数据环 + * @param entry {ACL_RING*} 新的元素 + */ +ACL_API void acl_ring_prepend(ACL_RING *ring, ACL_RING *entry); + +/** + * 将一个新元素添加进环的尾部 + * @param ring {ACL_RING*} 数据环 + * @param entry {ACL_RING*} 新的元素 + */ +ACL_API void acl_ring_append(ACL_RING *ring, ACL_RING *entry); + +/** + * 将一个环元素从数据环中删除 + * @param entry {ACL_RING*} 环元素 + */ +ACL_API void acl_ring_detach(ACL_RING *entry); + +/** + * 从环中弹出头部环元素 + * @param ring {ACL_RING*} 数据环 + * @return {ACL_RING*} 头部环元素,如果返回空则表示该数据环为空 + */ +ACL_API ACL_RING *acl_ring_pop_head(ACL_RING *ring); + +/** + * 从环中弹出尾部环元素 + * @param ring {ACL_RING*} 数据环 + * @return {ACL_RING*} 尾部环元素,如果返回空则表示该数据环为空 + */ +ACL_API ACL_RING *acl_ring_pop_tail(ACL_RING *ring); + +/*-------------------- 一些方便快捷的宏操作 --------------------------------*/ + +/** + * 返回当前环元素的下一个环元素 + */ +#define ACL_RING_SUCC(c) ((c)->succ) +#define acl_ring_succ ACL_RING_SUCC + +/** + * 返回当前环元素的前一个环元素 + */ +#define ACL_RING_PRED(c) ((c)->pred) +#define acl_ring_pred ACL_RING_PRED + +/** + * 将环元素指针转换成应用的自定义类型的指针地址 + * @param ring_ptr {ACL_RING*} 环元素指针 + * @param app_type 应用自定义类型 + * @param ring_member {ACL_RING*} 环元素在应用自定义结构中的成员名称 + * @return {app_type*} 应用自定义结构类型的对象地址 + */ +#define ACL_RING_TO_APPL(ring_ptr, app_type, ring_member) \ + ((app_type *) (((char *) (ring_ptr)) - offsetof(app_type,ring_member))) + +#define acl_ring_to_appl ACL_RING_TO_APPL + +/** + * 从头部至尾部遍历数据环中的所有环元素 + * @param iter {ACL_RING_ITER} + * @param head_ptr {ACL_RING*} 数据环的头指针 + * @example: + typedef struct { + char name[32]; + ACL_RING entry; + } DUMMY; + + void test() + { + ACL_RING head; + DUMMY *dummy; + ACL_RING_ITER iter; + int i; + + acl_ring_init(&head); + + for (i = 0; i < 10; i++) { + dummy = (DUMMY*) acl_mycalloc(1, sizeof(DUMMY)); + snprintf(dummy->name, sizeof(dummy->name), "dummy:%d", i); + acl_ring_append(&head, &dummy->entry); + } + + acl_ring_foreach(iter, &head) { + dummy = acl_ring_to_appl(iter.ptr, DUMMY, entry); + printf("name: %s\n", dummy->name); + } + + while (1) { + iter.ptr = acl_ring_pop_head(&head); + if (iter.ptr == NULL) + break; + dummy = acl_ring_to_appl(iter.ptr, DUMMY, entry); + acl_myfree(dummy); + } + } + */ +#define ACL_RING_FOREACH(iter, head_ptr) \ + for ((iter).ptr = acl_ring_succ((head_ptr)); (iter).ptr != (head_ptr); \ + (iter).ptr = acl_ring_succ((iter).ptr)) + +#define acl_ring_foreach ACL_RING_FOREACH + +/** + * 从尾部至头部遍历数据环中的所有环元素 + * @param iter {ACL_RING_ITER} + * @param head_ptr {ACL_RING*} 数据环的头指针 + */ +#define ACL_RING_FOREACH_REVERSE(iter, head_ptr) \ + for ((iter).ptr = acl_ring_pred((head_ptr)); (iter).ptr != (head_ptr); \ + (iter).ptr = acl_ring_pred((iter).ptr)) + +#define acl_ring_foreach_reverse ACL_RING_FOREACH_REVERSE + +/** + * 返回数据环中第一个环元素指针 + * @param head {ACL_RING*} 环头指针 + * @return {ACL_RING*} NULL: 环为空 + */ +#define ACL_RING_FIRST(head) \ + (acl_ring_succ(head) != (head) ? acl_ring_succ(head) : 0) + +#define acl_ring_first ACL_RING_FIRST + +/** + * 返回数据环中头第一个环元素指针同时将其转换应用自定义结构类型的对象地址 + * @param head {ACL_RING*} 环头指针 + * @param app_type 应用自定义结构类型 + * @param ring_member {ACL_RING*} 环元素在应用自定义结构中的成员名称 + * @return {app_type*} 应用自定义结构类型的对象地址 + */ +#define ACL_RING_FIRST_APPL(head, app_type, ring_member) \ + (acl_ring_succ(head) != (head) ? \ + ACL_RING_TO_APPL(acl_ring_succ(head), app_type, ring_member) : 0) + +#define acl_ring_first_appl ACL_RING_FIRST_APPL + +/** + * 返回数据环中最后一个环元素指针 + * @param head {ACL_RING*} 环头指针 + * @return {ACL_RING*} NULL: 环为空 + */ +#define ACL_RING_LAST(head) \ + (acl_ring_pred(head) != (head) ? acl_ring_pred(head) : 0) + +#define acl_ring_last ACL_RING_LAST + +/** + * 返回数据环中最后一个环元素指针同时将其转换应用自定义结构类型的对象地址 + * @param head {ACL_RING*} 环头指针 + * @param app_type 应用自定义结构类型 + * @param ring_member {ACL_RING*} 环元素在应用自定义结构中的成员名称 + * @return {app_type*} 应用自定义结构类型的对象地址 + */ +#define ACL_RING_LAST_APPL(head, app_type, ring_member) \ + (acl_ring_pred(head) != (head) ? \ + ACL_RING_TO_APPL(acl_ring_pred(head), app_type, ring_member) : 0) + +#define acl_ring_last_appl ACL_RING_LAST_APPL + +/** + * 将一个新元素添加进环的尾部 + * @param ring {ACL_RING*} 数据环 + * @param entry {ACL_RING*} 新的元素 + */ +#define ACL_RING_APPEND(ring_in, entry_in) do { \ + ACL_RING *ring_ptr = (ring_in), *entry_ptr = (entry_in); \ + entry_ptr->succ = ring_ptr->succ; \ + entry_ptr->pred = ring_ptr; \ + entry_ptr->parent = ring_ptr->parent; \ + ring_ptr->succ->pred = entry_ptr; \ + ring_ptr->succ = entry_ptr; \ + ring_ptr->parent->len++; \ +} while (0) + +/** + * 将一个新元素添加进环的头部 + * @param ring {ACL_RING*} 数据环 + * @param entry {ACL_RING*} 新的元素 + */ +#define ACL_RING_PREPEND(ring_in, entry_in) do { \ + ACL_RING *ring_ptr = (ring_in), *entry_ptr = (entry_in); \ + entry_ptr->pred = ring_ptr->pred; \ + entry_ptr->succ = ring_ptr; \ + entry_ptr->parent = ring_ptr->parent; \ + ring_ptr->pred->succ = entry_ptr; \ + ring_ptr->pred = entry_ptr; \ + ring_ptr->parent->len++; \ +} while (0) + +/** + * 将一个环元素从数据环中删除 + * @param entry {ACL_RING*} 环元素 + */ +#define ACL_RING_DETACH(entry_in) do { \ + ACL_RING *succ, *pred, *entry_ptr = (entry_in); \ + succ = entry_ptr->succ; \ + pred = entry_ptr->pred; \ + if (succ != NULL && pred != NULL) { \ + pred->succ = succ; \ + succ->pred = pred; \ + entry_ptr->parent->len--; \ + entry_ptr->succ = entry_ptr->pred = NULL; \ + } \ +} while (0) + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/include/stdlib/acl_safe.h b/lib_acl/include/stdlib/acl_safe.h new file mode 100644 index 000000000..18efb45d7 --- /dev/null +++ b/lib_acl/include/stdlib/acl_safe.h @@ -0,0 +1,17 @@ +#ifndef __ACL_SAFE_INCLUDE_H__ +#define __ACL_SAFE_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "acl_define.h" + +ACL_API int acl_unsafe(void); +ACL_API char *acl_safe_getenv(const char*name); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/include/stdlib/acl_sane_basename.h b/lib_acl/include/stdlib/acl_sane_basename.h new file mode 100644 index 000000000..21fcfea75 --- /dev/null +++ b/lib_acl/include/stdlib/acl_sane_basename.h @@ -0,0 +1,28 @@ +#ifndef __ACL_SANE_BASENAME_INCLUDE_H__ +#define __ACL_SANE_BASENAME_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "acl_vstring.h" + +/** + * 从文件全路径中提取文件名 + * @parm bp {ACL_VSTRING*} 存储结果的缓冲区,若为 NULL 则引用内部的线程局部存储 + * @return {char*} 永不为空 + */ +ACL_API char *acl_sane_basename(ACL_VSTRING *bp, const char *path); + +/** + * 从文件全路径中提取文件所在目录 + * @parm bp {ACL_VSTRING*} 存储结果的缓冲区,若为 NULL 则引用内部的线程局部存储 + * @return {char*} 永不为空 + */ +ACL_API char *acl_sane_dirname(ACL_VSTRING *bp, const char *path); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/include/stdlib/acl_scan_dir.h b/lib_acl/include/stdlib/acl_scan_dir.h new file mode 100644 index 000000000..e5a690f3a --- /dev/null +++ b/lib_acl/include/stdlib/acl_scan_dir.h @@ -0,0 +1,183 @@ + +#ifndef _ACL_SCAN_DIR_H_INCLUDED_ +#define _ACL_SCAN_DIR_H_INCLUDED_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include "acl_define.h" +/** + * 目录扫描句柄类型定义 + */ +typedef struct ACL_SCAN_DIR ACL_SCAN_DIR; + +/** + * 目录描述过程中用户可以设置的回调函数类型定义 + * @param scan {ACL_SCAN_DIR*} 目录扫描指针 + * @param ctx {void*} 用户参数指针 + */ +typedef int (*ACL_SCAN_DIR_FN)(ACL_SCAN_DIR *scan, void *ctx); + +/** + * 打开扫描路径, 为整个 acl_scan_dir 函数库的初始化函数 + * @param path {const char*} 要打开的路径名称 + * @param recursive {int} 是否需要递归扫描子目录 + * @return {ACL_SCAN_DIR*} NULL: Err; != NULL, OK + */ +ACL_API ACL_SCAN_DIR *acl_scan_dir_open(const char *path, int recursive); + +/** + * 关闭扫描句柄 + * @param scan {ACL_SCAN_DIR*} 类型指针 + */ +ACL_API void acl_scan_dir_close(ACL_SCAN_DIR *scan); + +/** + * 将目录扫描句柄的与统计信息相关的变量置0 + * @param scan {ACL_SCAN_DIR*} 类型指针 + */ +ACL_API void acl_scan_dir_reset(ACL_SCAN_DIR *scan); + +/** + * 通过此接口设置扫描句柄的回调函数、参数等,当最后的一个控制标志 + * 为 ACL_SCAN_CTL_END 时表示控制参数列表结束 + * @param scan {ACL_SCAN_DIR*} 类型指针 + * @param name {int} 第一个控制项, ACL_SCAN_CTL_XXX + */ +ACL_API void acl_scan_dir_ctl(ACL_SCAN_DIR *scan, int name, ...); +#define ACL_SCAN_CTL_END 0 /**< 控制结束标志 */ +#define ACL_SCAN_CTL_FN 1 /**< 设置 ACL_SCAN_DIR_FN 标志 */ +#define ACL_SCAN_CTL_CTX 2 /**< 设置用户参数 */ + +/** + * 获得当前状态下的相对路径(相对于程序调用 acl_scan_dir_open + * 函数时的程序运行路径) + * @param scan {ACL_SCAN_DIR*} 类型指针 + * @return {const char*} 相对路径, == NULL: err; != NULL, OK + */ +ACL_API const char *acl_scan_dir_path(ACL_SCAN_DIR *scan); + +/** + * 当前所扫描的文件名,如果扫描的对象不是文件,则返回 "\0" + * @param scan {ACL_SCAN_DIR*} 类型指针 + * @return {const char*} 文件名 + */ +ACL_API const char *acl_scan_dir_file(ACL_SCAN_DIR *scan); + +/** + * 当前已经扫描的目录总个数 + * @param scan {ACL_SCAN_DIR*} + * @return {int} 目录总个数, < 0 表示出错 + */ +ACL_API int acl_scan_dir_ndirs(ACL_SCAN_DIR *scan); + +/** + * 当前已经扫描的文件总个数 + * @param scan {ACL_SCAN_DIR*} + * @return {int} 文件总个数, < 0 表示出错 + */ +ACL_API int acl_scan_dir_nfiles(ACL_SCAN_DIR *scan); + +/** + * 当前已经扫描的文件大小总和 + * @param scan {ACL_SCAN_DIR*} + * @return {acl_int64} -1: Error; >= 0: Ok + */ +ACL_API acl_int64 acl_scan_dir_nsize(ACL_SCAN_DIR *scan); + +/** + * 取得当前文件或目录的属性信息,类似于标准的 stat() 函数 + * @param scan {ACL_SCAN_DIR*} 类型指针 + * @param sbuf: {struct acl_stat*} 类型指针 + * @return {int} 0: Ok, -1: Error + */ +ACL_API int acl_scan_stat(ACL_SCAN_DIR *scan, struct acl_stat *sbuf); + +/** + * 目录是否扫描完毕 + * @param scan {ACL_SCAN_DIR*} 类型指针 + * @return {int} 0: 表示未扫描完毕; !=0: 表示扫描完毕 + */ +ACL_API int acl_scan_dir_end(ACL_SCAN_DIR *scan); + +/** + * 将需要进行扫描的相对路径压栈 + * @param scan {ACL_SCAN_DIR*} 类型指针 + * @param path {const char*} 需要压栈的相对路径 + * @return {int} 0: OK; -1: Err + */ +ACL_API int acl_scan_dir_push(ACL_SCAN_DIR *scan, const char *path); + +/** + * 弹出下一个路径 + * @param scan {ACL_SCAN_DIR*} 类型指针 + * @return {ACL_SCAN_DIR*} 返回堆栈中的下一个对象, == NULL: 结束; != NULL, OK + */ +ACL_API ACL_SCAN_DIR *acl_scan_dir_pop(ACL_SCAN_DIR *scan); + +/** + * 获得 scan 当前所在路径中下一个路径名或文件名, 注意,该函数内部不会递归扫描, + * 即 acl_scan_dir_open 中的参数 recursive 对该函数无效 + * 1、 ".." 与 "." 不包含在内 + * 2、 仅返回名称, 不包括路径, 路径可以由 acl_scan_dir_path 获得 + * @param scan {ACL_SCAN_DIR*} 指针地址 + * @return {const char*} 为目录名称或文件名称, != NULL: OK; == NULL, 扫描完毕 + */ +ACL_API const char *acl_scan_dir_next(ACL_SCAN_DIR *scan); + +/** + * 获得下一个文件名(不包含路径名, 相对路径名可以通过 acl_scan_dir_path获得), + * 该函数内部支持递归扫描目录功能, acl_scan_dir_open 中的参数 recursive 对该函数有效 + * @param scan {ACL_SCAN_DIR*} 类型指针 + * @return {const char*} 返回下一个扫描的文件名, + * != NULL, OK; == NULL 扫描出错, 应该退出扫描 + */ +ACL_API const char *acl_scan_dir_next_file(ACL_SCAN_DIR *scan); + +/** + * 取得当前目录下所占磁盘空间大小(以字节计算) + * 该函数内部支持递归扫描目录功能, acl_scan_dir_open 中的参数 recursive 对该函数有效 + * @param scan {ACL_SCAN_DIR*} 打开目录时的扫描句柄 + * @return {acl_int64} -1: Error; >= 0: Ok + */ +ACL_API acl_int64 acl_scan_dir_size2(ACL_SCAN_DIR *scan); + +/** +* 取得当前目录下所占磁盘空间大小(以字节计算) +* @param pathname {const char*} 目录路径名 +* @param recursive {int} 是否要递归扫描该目录下的所有子目录 +* @param nfile {int*} 扫描完后记录所扫描的文件总数 +* @param ndir {int*} 扫描完后记录所扫描的目录总数 +* @return {acl_int64} -1: Error, >= 0: Ok +*/ +ACL_API acl_int64 acl_scan_dir_size(const char *pathname, int recursive, + int *nfile, int *ndir); + +/** + * 删除所给路径下所有的文件及目录 + * 该函数内部支持递归扫描目录功能, acl_scan_dir_open 中的参数 recursive 对该函数有效 + * @param scan {ACL_SCAN_DIR*} 打开目录时的扫描句柄 + */ +ACL_API void acl_scan_dir_rm2(ACL_SCAN_DIR *scan); + +/** + * 删除所给路径下所有的文件及目录 + * @param pathname {const char*} 路径名 + * @param recursive {int} 是否递归删除所有子目录及子目录下的文件 + * @param ndir {int*} 若该参数非空,过程结束后 *ndir 等于总共删除的目录数目 + * @param nfile {int*} 若该参数非空,过程结束后 *nfile 等于总共删除的文件数目 + * @return {acl_int64} >= 0: 实际删除的文件数与目录数的尺寸大小之和(字节); < 0: 出错. + */ +ACL_API acl_int64 acl_scan_dir_rm(const char *pathname, int recursive, + int *ndir, int *nfile); + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/lib_acl/include/stdlib/acl_slice.h b/lib_acl/include/stdlib/acl_slice.h new file mode 100644 index 000000000..a2b6ba265 --- /dev/null +++ b/lib_acl/include/stdlib/acl_slice.h @@ -0,0 +1,135 @@ +#ifndef __ACL_SLICE_INCLUDE_H__ +#define __ACL_SLICE_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "acl_define.h" + +#define ACL_SLICE_FLAG_OFF (0) +#define ACL_SLICE_FLAG_GC1 (1 << 0) /**< 空间节省, 但 gc 性能差 */ +#define ACL_SLICE_FLAG_GC2 (1 << 1) /**< 空间中等, gc 比较好 */ +#define ACL_SLICE_FLAG_GC3 (1 << 2) /**< 空间最大, gc 只当顺序时最好 */ +#define ACL_SLICE_FLAG_RTGC_OFF (1 << 10) /**< 关闭实时内存释放 */ +#define ACL_SLICE_FLAG_LP64_ALIGN (1 << 11) /**< 是否针对64位平台需要按8字节对齐 */ + +/** + * 内存分片池的状态结构 + */ +typedef struct ACL_SLICE_STAT { + int nslots; /**< total slice count free in slots */ + int islots; /**< current position of free slots slice */ + int page_nslots; /**< count slice of each page */ + int page_size; /**< length of each malloc */ + int slice_length; /**< length of each slice from user's set */ + int slice_size; /**< length of each slice really allocated */ + int nbuf; /**< count of MEM_BUF allocated */ + acl_uint64 length; /**< total size of all MEM_BUF's buf */ + acl_uint64 used_length; /**< total size of used */ + unsigned int flag; /**< same as the ACL_SLICE's flag been set when created */ +} ACL_SLICE_STAT; + +typedef struct ACL_SLICE ACL_SLICE; + +/** + * 创建内存片池对象 + * @param name {const char*} 标识名称,以便于调试 + * @param page_size {int} 分配内存时的分配内存页大小 + * @param slice_size {int} 每个固定长度内存片的大小 + * @param flag {unsigned int} 标志位,参见上述:ACL_SLICE_FLAG_xxx + * @return {ACL_SLICE*} 内存片池对象句柄 + */ +ACL_API ACL_SLICE *acl_slice_create(const char *name, int page_size, + int slice_size, unsigned int flag); + +/** + * 销毁一个内存片池对象 + * @param slice {ACL_SLICE*} 内存片池对象 + */ +ACL_API void acl_slice_destroy(ACL_SLICE *slice); + +/** + * 该内存片池中有多少个内存片正在被使用 + * @param slice {ACL_SLICE*} 内存片池对象 + * @return {int} >= 0, 正在被使用的内存片个数 + */ +ACL_API int acl_slice_used(ACL_SLICE *slice); + +/** + * 分配一块内存片 + * @param slice {ACL_SLICE*} 内存片池对象 + * @return {void*} 内存片地址 + */ +ACL_API void *acl_slice_alloc(ACL_SLICE *slice); + +/** + * 分配一块内存片,且将内存片内容初始化为0 + * @param slice {ACL_SLICE*} 内存片池对象 + * @return {void*} 内存片地址 + */ +ACL_API void *acl_slice_calloc(ACL_SLICE *slice); + +/** + * 释放一块内存片 + * @param slice {ACL_SLICE*} 内存片池对象 + * @param ptr {void*} 内存片地址, 必须是由 acl_slice_alloc/acl_slice_calloc 所分配 + */ +ACL_API void acl_slice_free2(ACL_SLICE *slice, void *ptr); + +/** + * 释放一块内存片 + * @param ptr {void*} 内存片地址, 必须是由 acl_slice_alloc/acl_slice_calloc 所分配 + */ +ACL_API void acl_slice_free(void *ptr); + +/** + * 查看内存片池的当前状态 + * @param slice {ACL_SLICE*} 内存片池对象 + * @param sbuf {ACL_SLICE_STAT*} 存储结果, 不能为空 + */ +ACL_API void acl_slice_stat(ACL_SLICE *slice, ACL_SLICE_STAT *sbuf); + +/** + * 手工将内存片池不用的内存进行释放 + * @param slice {ACL_SLICE*} 内存片池对象 + * @param {int} 是否已经将所有内存片释放完毕, 0: 否; 1: 是 + */ +ACL_API int acl_slice_gc(ACL_SLICE *slice); + +/*----------------------------------------------------------------------------*/ + +typedef struct ACL_SLICE_POOL { + ACL_SLICE **slices; /* the slice array */ + int base; /* the base byte size */ + int nslice; /* the max number of base size */ + unsigned int slice_flag; /* flag: ACL_SLICE_FLAG_GC2[3] | ACL_SLICE_FLAG_RTGC_OFF */ +} ACL_SLICE_POOL; + +ACL_API void acl_slice_pool_init(ACL_SLICE_POOL *asp); +ACL_API ACL_SLICE_POOL *acl_slice_pool_create(int base, int nslice, + unsigned int slice_flag); +ACL_API void acl_slice_pool_destroy(ACL_SLICE_POOL *asp); +ACL_API int acl_slice_pool_used(ACL_SLICE_POOL *asp); +ACL_API void acl_slice_pool_clean(ACL_SLICE_POOL *asp); +ACL_API void acl_slice_pool_reset(ACL_SLICE_POOL *asp); +ACL_API void acl_slice_pool_free(const char *filename, int line, void *buf); +ACL_API void acl_slice_pool_gc(ACL_SLICE_POOL *asp); +ACL_API void *acl_slice_pool_alloc(const char *filename, int line, + ACL_SLICE_POOL *asp, size_t size); +ACL_API void *acl_slice_pool_calloc(const char *filename, int line, + ACL_SLICE_POOL *asp, size_t nmemb, size_t size); +ACL_API void *acl_slice_pool_realloc(const char *filename, int line, + ACL_SLICE_POOL *asp, void *ptr, size_t size); +ACL_API void *acl_slice_pool_memdup(const char *filename, int line, + ACL_SLICE_POOL *asp, const void *ptr, size_t len); +ACL_API char *acl_slice_pool_strdup(const char *filename, int line, + ACL_SLICE_POOL *asp, const char *str); +ACL_API char *acl_slice_pool_strndup(const char *filename, int line, + ACL_SLICE_POOL *asp, const char *str, size_t len); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/include/stdlib/acl_split_at.h b/lib_acl/include/stdlib/acl_split_at.h new file mode 100644 index 000000000..ea3c07659 --- /dev/null +++ b/lib_acl/include/stdlib/acl_split_at.h @@ -0,0 +1,31 @@ +#ifndef __ACL_SPLIT_AT_H_INCLUDED__ +#define __ACL_SPLIT_AT_H_INCLUDED__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "acl_define.h" + +/** + * 从字符串左边开始将包含给定分隔符在内的右边截断 + * @param string {char*} 源字符串 + * @param delimiter {int} 分隔符 + * @return {char*} 分隔符以右的字符串,当为NULL时表明未找到指定分隔符 + */ +ACL_API char *acl_split_at(char *string, int delimiter); + +/** + * 从字符串右边开始将包含给定分隔符在内的右边截断 + * @param string {char*} 源字符串 + * @param delimiter {int} 分隔符 + * @return {char*} 分隔符以右的字符串,当为NULL时表明未找到指定分隔符 + */ +ACL_API char *acl_split_at_right(char *string, int delimiter); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/include/stdlib/acl_stack.h b/lib_acl/include/stdlib/acl_stack.h new file mode 100644 index 000000000..8c2bfc737 --- /dev/null +++ b/lib_acl/include/stdlib/acl_stack.h @@ -0,0 +1,138 @@ +#ifndef __ACL_STACK_INCLUDE_H__ +#define __ACL_STACK_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "acl_define.h" +#include "acl_iterator.h" + +/* 说明:该函数库内部所用的内存分配未采用内存池方式 */ + +typedef struct ACL_STACK ACL_STACK; + +/** + * 栈类型定义 + */ +struct ACL_STACK { + int capacity; + int count; + void **items; + + /* 添加及弹出 */ + + /* 向栈尾部添加动态对象 */ + void (*push_back)(struct ACL_STACK*, void*); + /* 向栈头部添加动态对象 */ + void (*push_front)(struct ACL_STACK*, void*); + /* 弹出栈尾部动态对象 */ + void *(*pop_back)(struct ACL_STACK*); + /* 弹出栈头部动态对象 */ + void *(*pop_front)(struct ACL_STACK*); + + /* for acl_iterator */ + + /* 取迭代器头函数 */ + void *(*iter_head)(ACL_ITER*, struct ACL_STACK*); + /* 取迭代器下一个函数 */ + void *(*iter_next)(ACL_ITER*, struct ACL_STACK*); + /* 取迭代器尾函数 */ + void *(*iter_tail)(ACL_ITER*, struct ACL_STACK*); + /* 取迭代器上一个函数 */ + void *(*iter_prev)(ACL_ITER*, struct ACL_STACK*); +}; + +/** + * 增加栈空间大小 + * @param s {ACL_STACK*} 创建的栈容器对象 + * @param count {int} 增加的空间大小 + */ +ACL_API void acl_stack_space(ACL_STACK *s, int count); + +/** + * 创建一个栈容器对象 + * @param init_size {int} 栈的初始化空间大小,必须 > 0 + * @return {ACL_STACK*} 新创建的栈容器对象 + */ +ACL_API ACL_STACK *acl_stack_create(int init_size); + +/** + * 清空栈里的对象,但不销毁栈容器对象 + * @param s {ACL_STACK*} 创建的栈容器对象 + * @param free_fn {void (*)(void*)} 如果不为空,则会用此函数回调栈里的每一个对象 + */ +ACL_API void acl_stack_clean(ACL_STACK *s, void (*free_fn)(void *)); + +/** + * 清空栈容器里的对象并销毁栈容器 + * @param s {ACL_STACK*} 创建的栈容器对象 + * @param free_fn {void (*)(void*)} 如果不为空,则会用此函数回调栈里的每一个对象 + */ +ACL_API void acl_stack_destroy(ACL_STACK *s, void (*free_fn)(void *)); + +/** + * 往栈容器尾部添加新的对象 + * @param s {ACL_STACK*} 创建的栈容器对象 + * @param obj {void*} + */ +ACL_API void acl_stack_append(ACL_STACK *s, void *obj); +#define acl_stack_push acl_stack_append + +/** + * 往栈容器的头部添加新的对象 + * @param s {ACL_STACK*} 创建的栈容器对象 + * @param obj {void*} + * 注:此操作的效率要比 acl_stack_append 低,因为其内容需要移动所有的对象位置 + */ +ACL_API void acl_stack_prepend(ACL_STACK *s, void *obj); + +/** + * 从栈容器里删除某个对象 + * @param s {ACL_STACK*} 创建的栈容器对象 + * @param position {int} 栈容器的位置 + * @param free_fn {void (*)(void*)} 如果不为空,则用此函数回调被删除对象 + */ +ACL_API void acl_stack_delete(ACL_STACK *s, int position, void (*free_fn)(void *)); + +/** + * @param s {ACL_STACK*} 创建的栈容器对象 + * @param obj {void*} 被删除对象的地址 + * @param free_fn {void (*)(void*)} 如果不为空,则用此函数回调被删除对象 + */ +ACL_API void acl_stack_delete_obj(ACL_STACK *s, void *obj, void (*free_fn)(void *)); + +/** + * 返回栈容器中某个位置的对象地址 + * @param s {ACL_STACK*} 创建的栈容器对象 + * @param position {int} 栈容器中的位置 + * @return {void*} != NULL: ok; == NULL: error或不存在 + */ +ACL_API void *acl_stack_index(ACL_STACK *s, int position); + +/** + * 返回栈容器中当前的对象个数 + * @param s {ACL_STACK*} 创建的栈容器对象 + * @return {int} 对象个数 + */ +ACL_API int acl_stack_size(const ACL_STACK *s); + +/** + * 返回栈中尾部的对象地址, 同时将该对象从栈中移除 + * @param s {ACL_STACK*} 创建的栈容器对象 + * @return {void*} 对象地址, == NULL 表示当前对象为空 + */ +ACL_API void *acl_stack_pop(ACL_STACK *s); + +/** + * 返回栈中最后添加的对象地址, 但不将该对象从栈中移除 + * @param s {ACL_STACK*} 创建的栈容器对象 + * @return {void*} 对象地址, == NULL 表示当前对象为空 + */ +ACL_API void *acl_stack_top(ACL_STACK *s); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/include/stdlib/acl_stdlib.h b/lib_acl/include/stdlib/acl_stdlib.h new file mode 100644 index 000000000..fcb20817a --- /dev/null +++ b/lib_acl/include/stdlib/acl_stdlib.h @@ -0,0 +1,86 @@ + +#ifndef __ACL_STDLIB_INCLUDE_H__ +#define __ACL_STDLIB_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "acl_define.h" +#include "acl_sys_patch.h" + +#include "acl_argv.h" +#include "acl_array.h" +#include "acl_stack.h" +#include "acl_hash.h" +#include "acl_binhash.h" +#include "acl_htable.h" +#include "acl_ring.h" +#include "acl_fifo.h" +#include "acl_iplink.h" +#include "acl_dlink.h" +#include "acl_btree.h" +#include "acl_cache.h" +#include "acl_cache2.h" +#include "avl.h" +#include "acl_token_tree.h" +#include "acl_iterator.h" + +#include "acl_iostuff.h" +#include "acl_msg.h" +#include "acl_debug.h" +#include "acl_mem_hook.h" +#include "acl_debug_malloc.h" +#include "acl_malloc.h" +#include "acl_mymalloc.h" +#include "acl_mystring.h" +#include "acl_vbuf.h" +#include "acl_vbuf_print.h" +#include "acl_vsprintf.h" +#include "acl_vstream.h" +#include "acl_vstring_vstream.h" +#include "acl_file.h" +#include "acl_readline.h" +#include "acl_vstring.h" +#include "acl_mylog.h" +#include "acl_getopt.h" +#include "acl_allocator.h" +#include "acl_chunk_chain.h" +#include "acl_dbuf_pool.h" +#include "acl_slice.h" +#include "acl_mem_slice.h" + +#include "acl_meter_time.h" + +#include "acl_xinetd_cfg.h" +#include "acl_loadcfg.h" +#include "acl_cfg_macro.h" + +#include "acl_hex_code.h" +#include "acl_split_at.h" +#include "acl_stringops.h" +#include "acl_timeops.h" + +#include "acl_make_dirs.h" +#include "acl_scan_dir.h" +#include "acl_myflock.h" +#include "acl_sane_basename.h" +#include "acl_fhandle.h" + +#include "acl_bits_map.h" +#include "acl_process.h" +#include "unix/acl_unix.h" + +#include "acl_vstream_popen.h" +#include "acl_safe.h" +#include "acl_exec_command.h" +#include "acl_env.h" + +#include "acl_dll.h" + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/include/stdlib/acl_stringops.h b/lib_acl/include/stdlib/acl_stringops.h new file mode 100644 index 000000000..5272141bc --- /dev/null +++ b/lib_acl/include/stdlib/acl_stringops.h @@ -0,0 +1,52 @@ +#ifndef __ACL_STRINGOPS_H_INCLUDED__ +#define __ACL_STRINGOPS_H_INCLUDED__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "acl_define.h" + +/** + * 判断给定字符串是否全为数字 + * @param str {const char*} 字符串 + * @return {int} 0: 否; 1: 是 + */ +ACL_API int acl_alldig(const char *str); + +/** + * 将多个字符串拼接成一个字符串 + * @param arg0 {const char*} 第一个非空字符串 + * @param ... 后续的字符串集合,结束符是 NULL + * @return {char*} 结果字符串,不为空, 该字符串需要调用 acl_myfree 释放 + */ +ACL_API char *acl_concatenate(const char *arg0,...); + +/** + * 从一个全路径的文件名中取得文件名部分,如: + * 从 "/tmp/test.txt" 或 "\\tmp\\test.txt" 中取得 test.txt + * @param path {const char*} 带有路径的文件名,如:"/tmp/test.txt" + * 或 "\\tmp\\test.txt" + * @return {const char*} 文件名,该返回值不需要释放,如果返回的地址 + * 为空串(即第一个字节为 '\0') 则说明所给路径不含文件名 + */ +ACL_API const char *acl_safe_basename(const char *path); + +/** + * 将所给的字符串进行分隔,分别取出 name, value 地址, 输入字符串可以为 + * {sp}{name}{sp}={sp}{value}{sp}, 如果分析成功,则将结果分别进行存储, + * 其中 {sp} 字符可以为: 空格, "\t", "\r", "\n" + * @param buf {char*} 输入的字符串, 不能为空 + * @param name {char**} 存储结果的地址指针,不能为空 + * @param value {char**} 存储结果的地址指针,不能为空 + * @return {const char*} 出错原因,如果为空则表示解析成功,否则表示解析失败并返回 + * 失败原因 + */ +ACL_API const char *acl_split_nameval(char *buf, char **name, char **value); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/include/stdlib/acl_sys_patch.h b/lib_acl/include/stdlib/acl_sys_patch.h new file mode 100644 index 000000000..0bef6058e --- /dev/null +++ b/lib_acl/include/stdlib/acl_sys_patch.h @@ -0,0 +1,185 @@ + +#ifndef __ACL_SYS_PATCH_INCLUDE_H__ +#define __ACL_SYS_PATCH_INCLUDE_H__ + +# ifdef __cplusplus +extern "C" { +# endif + +#include "acl_define.h" + +#ifdef ACL_MS_WINDOWS +struct iovec { + void *iov_base; /**< Starting address */ + size_t iov_len; /**< Number of bytes */ +}; + +#ifdef HAVE_NO_TIMEVAL +struct timeval { + long tv_sec; /**< seconds */ + long tv_usec; /**< microseconds */ +}; +#endif + +struct timezone { + int tz_minuteswest; /**< minutes W of Greenwich */ + int tz_dsttime; /**< type of dst correction */ +}; + +/** + * 睡眠几秒 + * @param sec {int} 睡眠的秒数 + */ +ACL_API void sleep(int sec); + +/** + * 获得当前时间 + * @param tv {struct timeval*} 存储当前时间结果 + * @param tz {struct timezone*} 时区 + */ +ACL_API int gettimeofday(struct timeval *tv, struct timezone *tz); + +#endif /* ACL_MS_WINDOWS */ +#ifdef ACL_UNIX +# include +#endif + +/** + * 套接字初始化,对于WIN32平台:需要调用WSAStartup来初始化SOCKET, + * 而对于UNIX平台:需要通过 signal(SIGPIPE, SIG_IGN) 来忽略信号 + * @return {int} 0: OK; -1: error + */ +ACL_API int acl_socket_init(void); + +/** + * 程序退出前调用此函数释放全局套接字资源(仅WIN32下有效) + * @return {int} 0: OK; -1: error + */ +ACL_API int acl_socket_end(void); + +/** + * 关闭套接字 + * @param fd {ACL_SOCKET} 套接字 + * @return {int} 0: OK; -1: error + */ +ACL_API int acl_socket_close(ACL_SOCKET fd); + +/** + * 从套接字读数据 + * @param fd {ACL_SOCKET} 套接字 + * @param buf {void*} 内存缓冲区地址 + * @param size {size_t} buf 缓冲区大小 + * @param timeout {size_t} 读超时时间(秒) + * @param arg {void*} 用户自已的参数,在回调方式时有用 + * @return {int} 0: OK; -1: error + */ +ACL_API int acl_socket_read(ACL_SOCKET fd, void *buf, size_t size, int timeout, void *arg); + +/** + * 向套接字写数据 + * @param fd {ACL_SOCKET} 套接字 + * @param buf {void*} 数据地址 + * @param size {size_t} buf 数据大小 + * @param timeout {int} 写超时时间(秒) + * @param arg {void*} 用户自已的参数,在回调方式时有用 + * @return {int} 0: OK; -1: error + */ +ACL_API int acl_socket_write(ACL_SOCKET fd, const void *buf, size_t size, int timeout, void *arg); + +/** + * 向套接字写数据 + * @param fd {ACL_SOCKET} 套接字 + * @param vector {const struct iovec*} 数据数组地址 + * @param count {int} vector 数组长度 + * @param timeout {int} 写超时时间(秒) + * @param arg {void*} 用户自已的参数,在回调方式时有用 + * @return {int} 0: OK; -1: error + */ +ACL_API int acl_socket_writev(ACL_SOCKET fd, const struct iovec *vector, int count, int timeout, void *arg); + +/** + * 打开文件句柄 + * @param filepath {cosnt char*} 文件路径 + * @param flags {int} 打开标志位, O_RDONLY | O_WRONLY | O_RDWR, + * O_CREAT | O_EXCL | O_TRUNC, O_APPEND(for UNIX) + * @param mode {int} 打开权限位, 仅对UNIX有效, 如:0700, 0755 + * @return {ACL_FILE_HANDLE} 打开的文件句柄,如果返回 ACL_FILE_INVALID 表示打开失败 + */ +ACL_API ACL_FILE_HANDLE acl_file_open(const char *filepath, int flags, int mode); + +/** + * 关闭打开的文件句柄 + * @param fh {ACL_FILE_HANDLE} 文件句柄 + * @return {int} 0: ok; -1: error + */ +ACL_API int acl_file_close(ACL_FILE_HANDLE fh); + +/** + * 定位文件位置 + * @param fh {ACL_FILE_HANDLE} 文件句柄 + * @param offset {acl_off_t} 偏移位置 + * @param whence {int} 位置标志位:SEEK_CUR, SEEK_SET, SEEK_END + * @return {acl_off_t} 当前的文件偏移位置 + */ +ACL_API acl_off_t acl_lseek(ACL_FILE_HANDLE fh, acl_off_t offset, int whence); + +/** + * 从文件中读数据 + * @param fh {ACL_FILE_HANDLE} 文件句柄 + * @param buf {void*} 存储缓冲区 + * @param size {size_t} buf 缓冲区大小 + * @param timeout {int} 读超时时间(秒) + * @param arg {void*} 用户传递的参数, 以回调方式使用时此参数有效 + * @return {int} 读到的实际数据, 如果返回 ACL_VSTREAM_EOF 表示读结束或出错 + */ +ACL_API int acl_file_read(ACL_FILE_HANDLE fh, void *buf, size_t size, int timeout, void *arg); + +/** + * 向文件中写数据 + * @param fh {ACL_FILE_HANDLE} 文件句柄 + * @param buf {void*} 数据存储缓冲区 + * @param size {size_t} buf 缓冲区中数据长度大小 + * @param timeout {int} 写超时时间(秒) + * @param arg {void*} 用户传递的参数, 以回调方式使用时此参数有效 + * @return {int} 成功写的数据量, 如果返回 ACL_VSTREAM_EOF 表示写出错 + */ +ACL_API int acl_file_write(ACL_FILE_HANDLE fh, const void *buf, size_t size, int timeout, void *arg); + +/** + * 向文件中写一组数据 + * @param fh {ACL_FILE_HANDLE} 文件句柄 + * @param vector {const struct iovec*} 数据存储数组 + * @param count {int} vector 数组中元素个数 + * @param timeout {int} 写超时时间(秒) + * @param arg {void*} 用户传递的参数, 以回调方式使用时此参数有效 + * @return {int} 成功写的数据量, 如果返回 ACL_VSTREAM_EOF 表示写出错 + */ +ACL_API int acl_file_writev(ACL_FILE_HANDLE fh, const struct iovec *vector, int count, int timeout, void *arg); + +/** + * 将文件缓冲区中的数据全部写入硬盘 + * @param fh {ACL_FILE_HANDLE} 文件句柄 + * @return {int} 0: ok; -1: error + */ +ACL_API int acl_file_fflush(ACL_FILE_HANDLE fh); + +/** + * 根据文件名取得该文件的大小 + * @param filename {const char*} 文件名 + * @return {acl_int64} >= 0: ok; -1: error + */ +ACL_API acl_int64 acl_file_size(const char *filename); + +/** + * 根据文件句柄取得该文件的大小 + * @param fh {ACL_FILE_HANDLE} 文件句柄 + * @return {acl_int64} >= 0: ok; -1: error + */ +ACL_API acl_int64 acl_file_fsize(ACL_FILE_HANDLE fh); + +# ifdef __cplusplus +} +# endif + +#endif + diff --git a/lib_acl/include/stdlib/acl_timeops.h b/lib_acl/include/stdlib/acl_timeops.h new file mode 100644 index 000000000..07162094b --- /dev/null +++ b/lib_acl/include/stdlib/acl_timeops.h @@ -0,0 +1,30 @@ +/* + * Name: misc.h + * Author: zsx + * Date: 2003-12-16 + * Version: 1.0 + */ + +#ifndef __ACL_MISC_INCLUDE_H__ +#define __ACL_MISC_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif +#include "acl_define.h" +#include + +/* acl_str2time.c */ +/** + * 将时间字符串转换为 time_t 类型 + * @param str 时间字符串格式为: year-month-mday(如: 2004-1-1) + * @return time_t 类型的值 + */ +ACL_API time_t acl_str2time_t(const char *str); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/include/stdlib/acl_token_tree.h b/lib_acl/include/stdlib/acl_token_tree.h new file mode 100644 index 000000000..e0c407258 --- /dev/null +++ b/lib_acl/include/stdlib/acl_token_tree.h @@ -0,0 +1,141 @@ +#ifndef __ACL_TOKEN_TREE_INCLUDE_H__ +#define __ACL_TOKEN_TREE_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif +#include "acl_define.h" +#include "acl_vstring.h" + +#define ACL_PRINT_CHAR(x) \ + ((((x) >= 'a' && (x) <='z') \ + || ((x) >= 'A' && (x) <= 'Z') \ + || ((x) >= '0' && (x) <= '9') \ + || (x) == ';' || (x) == '!' \ + || (x) == ':' || (x) == ',' \ + || (x) == '.' || (x) == '@' \ + || (x) == '#' || (x) == '$' \ + || (x) == '%' || (x) == '^' \ + || (x) == '&' || (x) == '*' \ + || (x) == '(' || (x) == ')' \ + || (x) == '-' || (x) == '=' \ + || (x) == '|' || (x) == '\\' \ + || (x) == '[' || (x) == ']' \ + || (x) == '{' || (x) == '}' \ + || (x) == '\'' || (x) == '"') \ + ? (x) : '-') + +typedef struct ACL_TOKEN { + unsigned char ch; + unsigned int flag; +#define ACL_TOKEN_F_NONE 0 +#define ACL_TOKEN_F_STOP (1 << 0) +#define ACL_TOKEN_F_PASS (1 << 1) +#define ACL_TOKEN_F_DENY (1 << 2) +#define ACL_TOKEN_F_UTF8 (1 << 3) + +#define ACL_TOKEN_WIDTH 255 + struct ACL_TOKEN *tokens[ACL_TOKEN_WIDTH]; + struct ACL_TOKEN *parent; + const void *ctx; +} ACL_TOKEN; + +#define ACL_TOKEN_TREE_MATCH(acl_token_tree_in, s_in, delim_in, delim_tab_in, acl_token_out) do \ +{ \ + const ACL_TOKEN *acl_token_iter = (acl_token_tree_in), *acl_token_tmp; \ + (acl_token_out) = NULL; \ + if (((const char*) delim_in)) { \ + int _i; \ + while (*(s_in)) { \ + for (_i = 0; ((const char*) delim_in)[_i]; _i++) { \ + if (*(s_in) == ((const char*) delim_in)[_i]) \ + goto _END; \ + } \ + acl_token_tmp = acl_token_iter->tokens[*((const unsigned char*)(s_in))]; \ + if (acl_token_tmp == NULL) { \ + if ((acl_token_out)) \ + break; \ + acl_token_iter = (acl_token_tree_in); \ + acl_token_tmp = acl_token_iter->tokens[*((const unsigned char*)(s_in))]; \ + if (acl_token_tmp == NULL) { \ + (s_in)++; \ + continue; \ + } \ + } \ + if ((acl_token_tmp->flag & ACL_TOKEN_F_STOP)) \ + (acl_token_out) = acl_token_tmp; \ + acl_token_iter = acl_token_tmp; \ + (s_in)++; \ + } \ +_END: \ + break; \ + } else if (((char*) delim_tab_in)) { \ + while (*(s_in)) { \ + if (((char*) delim_tab_in)[*((const unsigned char*)(s_in))]) \ + break; \ + acl_token_tmp = acl_token_iter->tokens[*((const unsigned char*)(s_in))]; \ + if (acl_token_tmp == NULL) { \ + if ((acl_token_out)) \ + break; \ + acl_token_iter = (acl_token_tree_in); \ + acl_token_tmp = acl_token_iter->tokens[*((const unsigned char*)(s_in))]; \ + if (acl_token_tmp == NULL) { \ + (s_in)++; \ + continue; \ + } \ + } \ + if ((acl_token_tmp->flag & ACL_TOKEN_F_STOP)) \ + (acl_token_out) = acl_token_tmp; \ + acl_token_iter = acl_token_tmp; \ + (s_in)++; \ + } \ + } else { \ + while (*(s_in)) { \ + acl_token_tmp = acl_token_iter->tokens[*((const unsigned char*)(s_in))]; \ + if (acl_token_tmp == NULL) { \ + if ((acl_token_out)) \ + break; \ + acl_token_iter = (acl_token_tree_in); \ + acl_token_tmp = acl_token_iter->tokens[*((const unsigned char*)(s_in))]; \ + if (acl_token_tmp == NULL) { \ + (s_in)++; \ + continue; \ + } \ + } \ + if ((acl_token_tmp->flag & ACL_TOKEN_F_STOP)) \ + (acl_token_out) = acl_token_tmp; \ + acl_token_iter = acl_token_tmp; \ + (s_in)++; \ + } \ + } \ +} while (0) + +ACL_API char *acl_token_delim_tab_new(const char *delim); +ACL_API void acl_token_delim_tab_free(char *delim_tab); +ACL_API ACL_TOKEN *acl_token_new(void); +ACL_API void acl_token_free(ACL_TOKEN *token); +ACL_API void acl_token_name(const ACL_TOKEN *token, ACL_VSTRING *buf); +ACL_API const char *acl_token_name1(const ACL_TOKEN *token); +ACL_API ACL_TOKEN *acl_token_tree_add(ACL_TOKEN *token_tree, + const char *word, unsigned int flag, const void *ctx); +ACL_API ACL_TOKEN *acl_token_tree_add_word_map(ACL_TOKEN *token_tree, + const char *word, const char *word_map, unsigned int flag); +ACL_API const ACL_TOKEN *acl_token_tree_word_match(const ACL_TOKEN *token_tree, + const char *word); +ACL_API const ACL_TOKEN *acl_token_tree_match(const ACL_TOKEN *token_tree, + const char **ptr, const char *delim, const char *delim_tab); +ACL_API void acl_token_tree_walk(const ACL_TOKEN *token_tree, + void (*walk_fn)(const ACL_TOKEN*, void*), void *arg); +ACL_API void acl_token_tree_print(const ACL_TOKEN *token_tree); +ACL_API ACL_TOKEN *acl_token_tree_create(const char *s); +ACL_API ACL_TOKEN *acl_token_tree_create2(const char *s, const char *sep); +ACL_API void acl_token_tree_destroy(ACL_TOKEN *token_tree); +ACL_API void acl_token_tree_load_deny(const char *filepath, ACL_TOKEN *token_tree); +ACL_API void acl_token_tree_load_pass(const char *filepath, ACL_TOKEN *token_tree); +ACL_API void acl_token_tree_test(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/include/stdlib/acl_vbuf.h b/lib_acl/include/stdlib/acl_vbuf.h new file mode 100644 index 000000000..50d330ea0 --- /dev/null +++ b/lib_acl/include/stdlib/acl_vbuf.h @@ -0,0 +1,76 @@ +#ifndef __ACL_VBUF_H_INCLUDED__ +#define __ACL_VBUF_H_INCLUDED__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "acl_define.h" + +typedef struct ACL_VBUF ACL_VBUF; +typedef int (*ACL_VBUF_GET_READY_FN) (ACL_VBUF *); +typedef int (*ACL_VBUF_PUT_READY_FN) (ACL_VBUF *); +typedef int (*ACL_VBUF_SPACE_FN) (ACL_VBUF *, int); + +struct ACL_VBUF { + int flags; /* status, see below */ + unsigned char *data; /* variable-length buffer */ + int len; /* buffer length */ + int cnt; /* bytes left to read/write */ + unsigned char *ptr; /* read/write position */ + ACL_VBUF_GET_READY_FN get_ready; /* read buffer empty action */ + ACL_VBUF_PUT_READY_FN put_ready; /* write buffer full action */ + ACL_VBUF_SPACE_FN space; /* request for buffer space */ + void *ctx; +}; + + /* + * Typically, an application will embed a VBUF structure into a larger + * structure that also contains application-specific members. This approach + * gives us the best of both worlds. The application can still use the + * generic VBUF primitives for reading and writing VBUFs. The macro below + * transforms a pointer from VBUF structure to the structure that contains + * it. + */ +#define ACL_VBUF_TO_APPL(vbuf_ptr,app_type,vbuf_member) \ + ((app_type *) (((char *) (vbuf_ptr)) - offsetof(app_type,vbuf_member))) + + /* + * Buffer status management. + */ +#define ACL_VBUF_FLAG_ERR (1<<0) /* some I/O error */ +#define ACL_VBUF_FLAG_EOF (1<<1) /* end of data */ +#define ACL_VBUF_FLAG_TIMEOUT (1<<2) /* timeout error */ +#define ACL_VBUF_FLAG_BAD (ACL_VBUF_FLAG_ERR | ACL_VBUF_FLAG_EOF | ACL_VBUF_FLAG_TIMEOUT) +#define ACL_VBUF_FLAG_FIXED (1<<3) /* fixed-size buffer */ + +#define acl_vbuf_error(v) ((v)->flags & ACL_VBUF_FLAG_ERR) +#define acl_vbuf_eof(v) ((v)->flags & ACL_VBUF_FLAG_EOF) +#define acl_vbuf_timeout(v) ((v)->flags & ACL_VBUF_FLAG_TIMEOUT) +#define acl_vbuf_clearerr(v) ((v)->flags &= ~ACL_VBUF_FLAG_BAD) + + /* + * Buffer I/O-like operations and results. + */ +#define ACL_VBUF_GET(v) ((v)->cnt < 0 ? ++(v)->cnt, \ + (int) *(v)->ptr++ : acl_vbuf_get(v)) +#define ACL_VBUF_PUT(v,c) ((v)->cnt > 0 ? --(v)->cnt, \ + (int) (*(v)->ptr++ = (c)) : acl_vbuf_put((v),(c))) +#define ACL_VBUF_SPACE(v,n) ((v)->space((v),(n))) + +#define ACL_VBUF_CHARAT(v, offset) ((int) (v).data[offset]) + +#define ACL_VBUF_EOF (-1) /* no more space or data */ + +ACL_API int acl_vbuf_get(ACL_VBUF *); +ACL_API int acl_vbuf_put(ACL_VBUF *, int); +ACL_API int acl_vbuf_unget(ACL_VBUF *, int); +ACL_API int acl_vbuf_read(ACL_VBUF *, char *, int); +ACL_API int acl_vbuf_write(ACL_VBUF *, const char *, int); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/include/stdlib/acl_vbuf_print.h b/lib_acl/include/stdlib/acl_vbuf_print.h new file mode 100644 index 000000000..5127596d9 --- /dev/null +++ b/lib_acl/include/stdlib/acl_vbuf_print.h @@ -0,0 +1,30 @@ +#ifndef __ACL_VBUF_PRINT_H_INCLUDED__ +#define __ACL_VBUF_PRINT_H_INCLUDED__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "acl_define.h" + + /* + * System library. + */ +#include + + /* + * Utility library. + */ +#include "acl_vbuf.h" + + /* + * External interface. + */ +ACL_API ACL_VBUF *acl_vbuf_print(ACL_VBUF *, const char *, va_list); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/include/stdlib/acl_vsprintf.h b/lib_acl/include/stdlib/acl_vsprintf.h new file mode 100644 index 000000000..a5034cca8 --- /dev/null +++ b/lib_acl/include/stdlib/acl_vsprintf.h @@ -0,0 +1,22 @@ + +#ifndef __ACL_VSPRINTF_INCLUDE_H__ +#define __ACL_VSPRINTF_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "acl_define.h" +#include +#include + +ACL_API int acl_vsnprintf(char *buf, size_t size, const char *fmt, va_list args); +ACL_API int acl_snprintf(char * buf, size_t size, const char *fmt, ...); +ACL_API int acl_vsprintf(char *buf, const char *fmt, va_list args); +ACL_API int acl_sprintf(char * buf, const char *fmt, ...); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/include/stdlib/acl_vstream.h b/lib_acl/include/stdlib/acl_vstream.h new file mode 100644 index 000000000..365c312fa --- /dev/null +++ b/lib_acl/include/stdlib/acl_vstream.h @@ -0,0 +1,869 @@ +/** + * @file acl_vstream.h + * @author zsx + * @date 2008-12-15 + * @brief 本文件中定义了关于 ACL_VSTREAM 通信流操作的类型说明及函数接口. + * @version 2.0 + */ + +#ifndef __ACL_VSTREAM_INCLUDE_H__ +#define __ACL_VSTREAM_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "acl_define.h" +#include +#include + +#ifdef ACL_UNIX +#include +#include +#include +#include +#endif + +#include "acl_array.h" +#include "acl_binhash.h" +#include "acl_vstring.h" + +#define ACL_VSTREAM_EOF (-1) /* no more space or data */ + +#ifdef ACL_UNIX +# ifndef O_RDONLY +# define O_RDONLY 0 +# endif +# ifndef O_WRONLY +# define O_WRONLY 1 +# endif +# ifndef O_RDWR +# define O_RDWR 2 +# endif +#endif + +#define ACL_VSTREAM_BUFSIZE 4096 + +typedef struct ACL_VSTREAM ACL_VSTREAM; + +typedef int (*ACL_VSTREAM_RD_FN)(ACL_SOCKET fd, void *buf, size_t size, int timeout, void *context); +typedef int (*ACL_VSTREAM_WR_FN)(ACL_SOCKET fd, const void *buf, size_t size, int timeout, void *context); +typedef int (*ACL_VSTREAM_WV_FN)(ACL_SOCKET fd, const struct iovec *vector, int count, int timeout, void *context); +typedef int (*ACL_FSTREAM_RD_FN)(ACL_FILE_HANDLE fh, void *buf, size_t size, int timeout, void *context); +typedef int (*ACL_FSTREAM_WR_FN)(ACL_FILE_HANDLE fh, const void *buf, size_t size, int timeout, void *context); +typedef int (*ACL_FSTREAM_WV_FN)(ACL_FILE_HANDLE fh, const struct iovec *vector, int count, int timeout, void *context); + +/* 当关闭或释放一个数据流时, 需要回调一些释放函数, 此结果定义了该回调 + * 函数的句柄类型 ---add by zsx, 2006.6.20 + */ +typedef struct ACL_VSTREAM_CLOSE_HANDLE { + void (*close_fn)(ACL_VSTREAM*, void*); + void *context; +} ACL_VSTREAM_CLOSE_HANDLE; + +/* 数据读写流类型定义 */ +struct ACL_VSTREAM { + union { + ACL_SOCKET sock; /**< the master socket */ + ACL_FILE_HANDLE h_file; /**< the file handle */ + } fd; + + int is_nonblock; /**< just for WINDOWS, because the ioctlsocket is too weak */ + int type; /**< defined as: ACL_VSTREAM_TYPE_XXX */ +#define ACL_VSTREAM_TYPE_SOCK (1 << 0) +#define ACL_VSTREAM_TYPE_FILE (1 << 1) +#define ACL_VSTREAM_TYPE_LISTEN (1 << 2) +#define ACL_VSTREAM_TYPE_LISTEN_INET (1 << 3) +#define ACL_VSTREAM_TYPE_LISTEN_UNIX (1 << 4) +#define ACL_VSTREAM_TYPE_LISTEN_IOCP (1 << 5) + + acl_off_t offset; /**< cached seek info */ + acl_off_t sys_offset; /**< cached seek info */ + + unsigned char *wbuf; /**< used when call acl_vstream_buffed_writen */ + int wbuf_size; /**< used when call acl_vstream_buffed_writen */ + int wbuf_dlen; /**< used when call acl_vstream_buffed_writen */ + + unsigned char *read_buf; /**< read buff */ + int read_buf_len; /**< read_buf's capacity */ + int read_cnt; /**< data's length in read_buf */ + unsigned char *read_ptr; /**< pointer to next position in read_buf */ + int sys_read_ready; /**< if the system buffer has some data */ + + acl_off_t total_read_cnt; /**< total read count of the stream */ + acl_off_t total_write_cnt; /**< total write count of the stream */ + + void *ioctl_read_ctx; /**< only for acl_ioctl_xxx in acl_ioctl.c */ + void *ioctl_write_ctx; /**< only for acl_ioctl_xxx in acl_ioctl.c */ + void *fdp; /**< only for event */ + + unsigned int flag; /**< defined as: ACL_VSTREAM_FLAG_XXX */ +#define ACL_VSTREAM_FLAG_READ (1 << 0) +#define ACL_VSTREAM_FLAG_WRITE (1 << 1) +#define ACL_VSTREAM_FLAG_RW (1 << 2) +#define ACL_VSTREAM_FLAG_CACHE_SEEK (1 << 3) +#define ACL_VSTREAM_FLAG_DEFER_FREE (1 << 4) /**< 延迟关闭 */ + +#define ACL_VSTREAM_FLAG_ERR (1 << 10) /**< 其它错误 */ +#define ACL_VSTREAM_FLAG_EOF (1 << 11) /**< 结束 */ +#define ACL_VSTREAM_FLAG_TIMEOUT (1 << 12) /**< 超时 */ +#define ACL_VSTREAM_FLAG_RDSHORT (1 << 13) /**< 读的不够 */ +#define ACL_VSTREAM_FLAG_BAD (ACL_VSTREAM_FLAG_ERR \ + | ACL_VSTREAM_FLAG_EOF \ + | ACL_VSTREAM_FLAG_TIMEOUT) +#define ACL_VSTREAM_FLAG_CLIENT (1 << 14) +#define ACL_VSTREAM_FLAG_CONNECT (1 << 15) +#define ACL_VSTREAM_FLAG_SOCKPAIR (1 << 16) + +#define ACL_VSTREAM_FLAG_TAGYES (1 << 17) /* 若读到要求的标志位的要求则置位 */ +#define ACL_VSTREAM_FLAG_TAGNO (1 << 18) /* 没有找到标志位 */ + +#define ACL_VSTREAM_FLAG_CONNECTING (1 << 19) /* 正在连接过程中 */ +#define ACL_VSTREAM_FLAG_PREREAD (1 << 20) /* 对于 acl_vstream_can_read 调用过程是否允许预读 */ + + char errbuf[128]; /**< error info */ + int errnum; /**< record the system errno here */ + int rw_timeout; /**< read/write timeout */ + char local_addr[256]; /**< the local addr of the stream */ + char remote_addr[256]; /**< the remote addr of the stream */ + const char *path; /**< the path just for file operation */ + void *context; /**< the application's special data */ + + ACL_ARRAY *close_handle_lnk; /**< before this stream is free, + * function in close_handle_lnk + * will be called. + * add by zsx, 2006.6.20 + */ + int (*sys_getc)(ACL_VSTREAM*); /**< called by ACL_VSTREAM_GETC()/1 */ + ACL_VSTREAM_RD_FN read_fn; /**< system socket read API */ + ACL_VSTREAM_WR_FN write_fn; /**< system socket write API */ + ACL_VSTREAM_WV_FN writev_fn; /**< system socket writev API */ + + ACL_FSTREAM_RD_FN fread_fn; /**< system file read API */ + ACL_FSTREAM_WR_FN fwrite_fn; /**< system file write API */ + ACL_FSTREAM_WV_FN fwritev_fn; /**< system file writev API */ + + int (*close_fn)(ACL_SOCKET); /**< system socket close API */ + int (*fclose_fn)(ACL_FILE_HANDLE); /**< system file close API */ + + unsigned int oflags; /**< the system's open flags */ + /* general flags(ANSI): + * O_RDONLY: 0x0000, O_WRONLY: 0x0001, O_RDWR: 0x0002, O_APPEND: 0x0008, + * O_CREAT: 0x0100, O_TRUNC: 0x0200, O_EXCL: 0x0400; + * just for win32: + * O_TEXT: 0x4000, O_BINARY: 0x8000, O_RAW: O_BINARY, + * O_SEQUENTIAL: 0x0020, O_RANDOM: 0x0010. + */ + + int nrefer; /**< refer count, used for engine moudle */ + +#ifdef ACL_MS_WINDOWS + int pid; + HANDLE hproc; + ACL_SOCKET iocp_sock; +#elif defined(ACL_UNIX) + pid_t pid; +#endif +}; + +extern ACL_API ACL_VSTREAM acl_vstream_fstd[]; /**< pre-defined streams */ +#define ACL_VSTREAM_IN (&acl_vstream_fstd[0]) /**< 标准输入 */ +#define ACL_VSTREAM_OUT (&acl_vstream_fstd[1]) /**< 标准输出 */ +#define ACL_VSTREAM_ERR (&acl_vstream_fstd[2]) /**< 标准错误输出 */ + +/*--------------------------------------------------------------------------*/ +/** + * 初始化ACL_VSTREAM流的函数库 + * 对于WIN32来说,如果想要用标准输入输出,则需要调用此函数进行初始化 + */ +ACL_API void acl_vstream_init(void); + +/** + * 功能: 探测流中有多少数据, 包含缓冲区中的数据与系统缓冲区的数据 + * @param stream {ACL_VSTREAM*} 流指针, 不能为空 + * @return ret {int}, ret > 0 OK; ret <= 0 Error + * 注: 仅适应于网络套接字 + */ +ACL_API int acl_vstream_peekfd(ACL_VSTREAM *stream); + +/** + * 克隆一个ACL_VSTREAM流,除ioctl_read_ctx, ioctl_write_ctx, fdp + * 外所有数据都拷贝,如果是动态内存数据,则新的流将在内部动态分配 + * 内存且将源数据进行拷贝 + * @param stream_src {ACL_VSTREAM*} 源流指针 + * @return {ACL_VSTREAM*} 目的流指针 + */ +ACL_API ACL_VSTREAM *acl_vstream_clone(const ACL_VSTREAM *stream_src); + +/** + * 设置数据流的类型,该函数将根据所给类型设定用于该数据流上的读、写、关闭函数 + * @param stream {ACL_VSTREAM*} 流指针, 不能为空 + * @param type {int} 数据流的类型,defined above: ACL_VSTREAM_TYPE_XXX + * @return ret {int}, ret >= 0 OK; ret < 0 Error + */ +ACL_API int acl_vstream_set_fdtype(ACL_VSTREAM *stream, int type); + +/** + * 分配一文件句柄所对应的数据流 + * @param fh {ACL_FILE_HANDLE} 文件句柄 + * @param oflags {unsigned int} 标志位, We're assuming that O_RDONLY: 0x0000, + * O_WRONLY: 0x0001, O_RDWR: 0x0002, O_APPEND: 0x0008, O_CREAT: 0x0100, + * O_TRUNC: 0x0200, O_EXCL: 0x0400; just for win32, O_TEXT: 0x4000, + * O_BINARY: 0x8000, O_RAW: O_BINARY, O_SEQUENTIAL: 0x0020, O_RANDOM: 0x0010. + * 同时设置 + * @return {ACL_VSTREAM*} 数据流句柄 + */ +ACL_API ACL_VSTREAM *acl_vstream_fhopen(ACL_FILE_HANDLE fh, unsigned int oflags); + +/** + * 分配一个数据流 + * @param fd {ACL_SOCKET} 描述符(可以为网络描述字也可以为文件描述字) + * @param oflags {unsigned int} 标志位, We're assuming that O_RDONLY: 0x0000, + * O_WRONLY: 0x0001, O_RDWR: 0x0002, O_APPEND: 0x0008, O_CREAT: 0x0100, + * O_TRUNC: 0x0200, O_EXCL: 0x0400; just for win32, O_TEXT: 0x4000, + * O_BINARY: 0x8000, O_RAW: O_BINARY, O_SEQUENTIAL: 0x0020, O_RANDOM: 0x0010. + * @param buflen {size_t} 内置缓冲区的大小 + * @param rw_timeo {int} 读写超时时间(以秒为单位) + * @param fdtype {int} ACL_VSTREAM_TYPE_FILE, ACL_VSTREAM_TYPE_SOCK, + * ACL_VSTREAM_TYPE_LISTEN | ACL_VSTREAM_TYPE_LISTEN_INET | ACL_VSTREAM_TYPE_LISTEN_UNIX + * @return ret {ACL_VSTREAM*}, ret == NULL: 出错, ret != NULL: OK + */ +ACL_API ACL_VSTREAM *acl_vstream_fdopen(ACL_SOCKET fd, unsigned int oflags, + size_t buflen, int rw_timeo, int fdtype); + +/** + * 打开一个文件的数据流 + * @param path {const char*} 文件名 + * @param oflags {unsigned int} 标志位, We're assuming that O_RDONLY: 0x0000, + * O_WRONLY: 0x0001, O_RDWR: 0x0002, O_APPEND: 0x0008, O_CREAT: 0x0100, + * O_TRUNC: 0x0200, O_EXCL: 0x0400; just for win32, O_TEXT: 0x4000, + * O_BINARY: 0x8000, O_RAW: O_BINARY, O_SEQUENTIAL: 0x0020, O_RANDOM: 0x0010. + * @param mode {int} 打开文件句柄时的模式(如: 0600) + * @param buflen {size_t} 内置缓冲区的大小 + * @return ret {ACL_VSTREAM*}, ret== NULL: 出错, ret != NULL: OK + */ +ACL_API ACL_VSTREAM *acl_vstream_fopen(const char *path, unsigned int oflags, + int mode, size_t buflen); + +/** + * 读取整个文件内容于内存中 + * @param path {const char*} 文件名, 如: /opt/acl/conf/service/test.cf + * @return {char*} 存有文件全部内容的缓冲区, 用完后用户需要调用 acl_myfree + * 释放该内存区 + */ +ACL_API char *acl_vstream_loadfile(const char *path); + +/** + * 读取整个文件内容于内存中 + * @param path {const char*} 文件名, 如: /opt/acl/conf/service/test.cf + * @param size {ssize_t*} 如果非空,则该值存储返回的缓冲区大小,如果读取内容 + * 出错,则该值会被置 -1 + * @return {char*} 存有文件全部内容的缓冲区, 用完后用户需要调用 acl_myfree + * 释放该内存区 + */ +ACL_API char *acl_vstream_loadfile2(const char *path, ssize_t *size); + +/** + * 设置流的各个参数 + * @param stream {ACL_VSTREAM*} 流指针 + * @param name {int} 所设置的参数类型中的第一个参数类型名, + * defined as ACL_VSTREAM_CTL_ + */ +ACL_API void acl_vstream_ctl(ACL_VSTREAM *stream, int name,...); +#define ACL_VSTREAM_CTL_END 0 +#define ACL_VSTREAM_CTL_READ_FN 1 +#define ACL_VSTREAM_CTL_WRITE_FN 2 +#define ACL_VSTREAM_CTL_PATH 3 +#define ACL_VSTREAM_CTL_FD 4 +#define ACL_VSTREAM_CTL_TIMEOUT 5 +#define ACL_VSTREAM_CTL_CONTEXT 6 +#define ACL_VSTREAM_CTL_CTX ACL_VSTREAM_CTL_CONTEXT +#define ACL_VSTREAM_CTL_CACHE_SEEK 7 + +/** + * 定位文件指针 + * @param stream {ACL_VSTREAM*} 数据流指针 + * @param offset {acl_off_t} 偏移量 + * @param whence {int} 偏移方向, SEEK_SET, SEEK_CUR, SEEK_END + * @return ret {acl_off_t}, ret >= 0: 正确, ret < 0: 出错 + * 注: acl_vstream_fseek() 效率更高些, 其充分利用了缓冲区的功能, + * 且比 acl_vstream_fseek2() 少调用一次 lseek() 系统调用. + */ +ACL_API acl_off_t acl_vstream_fseek(ACL_VSTREAM *stream, acl_off_t offset, int whence); + +/** + * 定位文件指针 + * @param stream {ACL_VSTREAM*} 数据流指针 + * @param offset {acl_off_t} 偏移量 + * @param whence {int} 偏移方向, SEEK_SET, SEEK_CUR, SEEK_END + * @return ret {acl_off_t}, ret >= 0: 正确, ret < 0: 出错 + * @deprecated 该函数的效率较低 + */ +ACL_API acl_off_t acl_vstream_fseek2(ACL_VSTREAM *stream, acl_off_t offset, int whence); + +/** + * 将源文件进程截断 + * @param fp {ACL_VSTREAM*} 数据流指针 + * @param length {acl_off_t} 数据长度(>=0) + * @return {int} 0: ok, -1: error + */ +ACL_API int acl_file_ftruncate(ACL_VSTREAM *fp, acl_off_t length); + +/** + * 将源文件进程截断 + * @param path {const char*} 文件名(可以是全路径或相对路径) + * @param length {acl_off_t} 数据长度(>=0) + * @return {int} 0: ok, -1: error + */ +ACL_API int acl_file_truncate(const char *path, acl_off_t length); + +/** + * 查看一个文件流句柄的属性 + * @param fp {ACL_VSTREAM *} 文件流句柄 + * @param buf {acl_stat *} 存储结果的结构地址 + * @return {int} 0: ok; -1: error + */ +ACL_API int acl_vstream_fstat(ACL_VSTREAM *fp, struct acl_stat *buf); + +/** + * 查看一个文件的大小 + * @param fp {ACL_VSTREAM *} 文件流句柄 + * @return {int} >= 0: ok; -1: error + */ +ACL_API acl_int64 acl_vstream_fsize(ACL_VSTREAM *fp); + +/** + * 从stream 流中读取一个字节 + * @param stream {ACL_VSTREAM*} 数据流指针 + * @return {int} ACL_VSTREAM_EOF(出错) 或所读到的某个字节的ASCII + * 或为 ACL_VSTREAM_EOF: 读出错或对方关闭了连接, 应该关闭该数据流 + */ +ACL_API int acl_vstream_getc(ACL_VSTREAM *stream); +#define acl_vstream_get_char acl_vstream_getc + +/** + * 从 stream 流中非阻塞地一次性最大读取 size 个字节 + * @param stream {ACL_VSTREAM*} 数据流指针 + * @param buf {char*} 用户传来的内存缓存区 + * @param size {int} buf 缓存区的空间大小 + * @return {int} 所读取的字节数 n, 如果 n == ACL_VSTREAM_EOF 表明出错, 否则 + * n >= 0 正确. + */ +ACL_API int acl_vstream_nonb_readn(ACL_VSTREAM *stream, char *buf, int size); + +/** + * 判断一个给定的数据流是否已经被系统关闭了,当数据流缓存区没有数据时, + * 该函数会调用系统的读函数(即读一个字节)来判断是否socket出错或已经 + * 关闭;如成功读取一个字节,则说明socket正常,同时将所读的数据放回缓存 + * 区, 如果读返回ACL_VSTREAM_EOF, 便需要判断错误号是否被关闭 + * @param stream {ACL_VSTREAM*} 数据流指针 + * @return {int}, 0 说明该socket正常; -1 该socket出错或已经被系统关闭 + */ +ACL_API int acl_vstream_probe_status(ACL_VSTREAM *stream); + +/** + * 将一个字符放回数据流中 + * @param stream {ACL_VSTREAM*} 数据流指针 + * @param ch {int} 字符的 ASCII 码 + * @return {int} 字符的 ASCII 码, 该函数应不会出错, 除非内部内存分配失败而产生 + * core 文件. + */ +ACL_API int acl_vstream_ungetc(ACL_VSTREAM *stream, int ch); + +/** + * 将指定长度的数据放回至数据流中 + * @param stream {ACL_VSTREAM*} 数据流指针 + * @param ptr {const void *} 需要放回至流中的数据的起始地址 + * @param length {size_t} 需要放回至流中的数据的长度 + * @return {int} 被成功放回至流中的数据长度, 应该永不会出错, 除非内部内存分配 + * 失败而自动产生 core 文件! + */ +ACL_API int acl_vstream_unread(ACL_VSTREAM *stream, const void *ptr, size_t length); + +/** + * 从数据流中读取一行数据, 直到读到 "\n" 或读结束为止, 正常情况下包括 "\n" + * @param stream {ACL_VSTREAM*} 数据流 + * @param vptr {void*} 用户所给的内存缓冲区指针 + * @param maxlen {size_t} vptr 缓冲区的大小 + * @return ret {int}, ret == ACL_VSTREAM_EOF: 读出错或对方关闭了连接, + * 应该关闭本地数据流; n > 0: 读到 了 n 个字节的数据, 如果该 n 个数据 + * 的最后一个非 0 字符为 "\n" 表明读到了一个完整的行, 否则表明读到了 n + * 个数据但对方未发送 "\n" 就关闭了连接; 还可以通过检查 + * (stream->flag & ACL_VSTREAM_FLAG_TAGYES) + * 不等于 0 来判断是否读到了 "\n", 如果非 0 则表示读到了 "\n". + */ +ACL_API int acl_vstream_gets(ACL_VSTREAM *stream, void *vptr, size_t maxlen); +#define acl_vstream_readline acl_vstream_gets +#define acl_vstream_fgets acl_vstream_gets + +/** + * 从数据流中读取一行数据, 直到读到 "\n" 或读结束为止, 返回的结果中不包括 "\n" + * @param stream {ACL_VSTREAM*} 数据流 + * @param vptr {void*} 用户所给的内存缓冲区指针 + * @param maxlen {size_t} vptr 缓冲区的大小 + * @return ret {int}, ret == ACL_VSTREAM_EOF: 读出错或对方关闭了连接, + * 应该关闭本地数据流, n == 0: 读到了一行数据, 但该行数据仅有 "\r\n", + * n > 0: 读到 了 n 个字节的数据. + */ +ACL_API int acl_vstream_gets_nonl(ACL_VSTREAM *stream, void *vptr, size_t maxlen); + +/** + * 从数据流中获得以字符串为标志结束位的内容 + * @param stream {ACL_VSTREAM*} 类型指针 + * @param vptr {void*} 数据存储缓冲区 + * @param maxlen {size_t} vptr 缓冲区大小 + * @param tag {const char*} 字符串标志 + * @param taglen {size_t} tag 中内容的长度大小 + * @return ret {int}, ret == ACL_VSTREAM_EOF: 读出错或对方关闭了连接, + * 应该关闭本地数据流, n > 0: 读到 了 n 个字节的数据, 如果读到了所需要的 + * 标志串, 则 stream 流中 (stream->flag & ACL_VSTREAM_FLAG_TAGYES) 不等于 0. + */ +ACL_API int acl_vstream_readtags(ACL_VSTREAM *stream, void *vptr, size_t maxlen, + const char *tag, size_t taglen); + +/** + * 循环读取 maxlen 个数据, 直到读到 maxlen 个字节为止或读出错 + * @param stream {ACL_VSTREAM*} 数据流 + * @param vptr {void*} 用户的数据缓冲区指针地址 + * @param maxlen {size_t} vptr 数据缓冲区的空间大小 + * @return ret {int}, ret == ACL_VSTREAM_EOF: 读出错或对方关闭了连接, 应该 + * 关闭本地数据流 n > 0: 成功读取了 maxlen 个字节的数据 + * 如果实际读取的字节数与 maxlen 不相等也返回错误(ACL_VSTREAM_EOF) + */ +ACL_API int acl_vstream_readn(ACL_VSTREAM *stream, void *vptr, size_t maxlen); + +/** + * 将 stream 缓冲区内的数据拷贝到 vptr 中 + * @param stream {ACL_VSTREAM*} 数据流 + * @param vptr {void*} 用户的数据缓冲区指针地址 + * @param maxlen {size_t} vptr 数据缓冲区的空间大小 + * @return ret {int}, ret == ACL_VSTREAM_EOF: 表示出错, 应该关闭本地数据流, + * ret >= 0: 成功从 stream 数据流的缓冲区中读取了 ret 个字节的数据 + */ +ACL_API int acl_vstream_bfcp_some(ACL_VSTREAM *stream, void *vptr, size_t maxlen); + +/** + * 从数据流中一次性读取 n 个数据, 该 n 有可能会小于用户所需要的 maxlen + * @param stream {ACL_VSTREAM*} 数据流 + * @param vptr {void*} 用户的数据缓冲区指针地址 + * @param maxlen {size_t} vptr 数据缓冲区的空间大小 + * @return ret {int}, ret == ACL_VSTREAM_EOF: 表示出错, 应该关闭本地数据流, + * ret > 0: 表示读到了 ret 个字节的数据 + * 注: 如果缓冲区内有数据, 则直接把缓冲区内的数据复制到用户的缓冲区然后直接返回; + * 如果缓冲区内无数据, 则需要调用系统读操作(有可能会阻塞在系统读操作上), 该 + * 次调用返回后则把读到数据复制到用户缓冲区返回. + * 在这两种情况下都不能保证读到的字节数等于所要求的字节数, 若想读到所要求的 + * 字节后才返回则请调用 vstream_loop_readn() 函数. + */ +ACL_API int acl_vstream_read(ACL_VSTREAM *stream, void *vptr, size_t maxlen); + +/** +* 一次性从 ACL_VSTREAM 流或系统缓存区中读取一行数据, 包括回车换行符 +* (调用者自行解决WINDOWS与UNIX对于回车换行的兼容性问题), 如果未读到 +* 回车换行符, 也将数据拷贝至用户的内存缓冲区. +* @param stream {ACL_VSTREAM*} 数据流 +* @param strbuf {ACL_VSTRING*} 数据缓冲区 +* @param ready {int*} 是否按要求读到所需数据的标志位指针, 不能为空 +* @return ret {int}, ret == ACL_VSTREAM_EOF: 表示出错, 应该关闭本地数据流, +* ret >= 0: 成功从 stream 数据流的缓冲区中读取了 ret 个字节的数据 +*/ +ACL_API int acl_vstream_gets_peek(ACL_VSTREAM *stream, ACL_VSTRING *strbuf, int *ready); + +/** + * 一次性从 ACL_VSTREAM 流或系统缓存区中读取一行数据, 如果未读到回车换行符, + * 也将数据拷贝至用户的内存缓冲区, 如果读到回车换行符便将回车换行符自动去掉, + * 并将回车换行符前的数据拷贝至用户内存区. + * @param stream {ACL_VSTREAM*} 数据流 + * @param strbuf {ACL_VSTRING*} 数据缓冲区 + * @param ready {int*} 是否按要求读到所需数据的标志位指针, 不能为空 + * @return ret {int}, ret == ACL_VSTREAM_EOF: 表示出错, 应该关闭本地数据流, + * ret >= 0: 成功从 stream 数据流的缓冲区中读取了 ret 个字节的数据, 如果仅 + * 读到了一个空行, 则 ret == 0. + */ +ACL_API int acl_vstream_gets_nonl_peek(ACL_VSTREAM *stream, ACL_VSTRING *strbuf, int *ready); +/** +* 功能: 一次性从 ACL_VSTREAM 流或系统缓存区中读取固定长度的数据, +* 如果未读到所要求的数据, 也将数据拷贝至用户内存缓冲区, 如 +* 果读到所要求的数据, 则将 ready 标志位置位. +* @param stream {ACL_VSTREAM*} 数据流 +* @param strbuf {ACL_VSTRING*} 数据缓冲区 +* @param cnt {int} 所需要读的数据的长度 +* @param ready {int*} 是否按要求读到所需数据的标志位指针, 不能为空 +* @return ret {int}, ret == ACL_VSTREAM_EOF: 表示出错, 应该关闭本地数据流, +* ret >= 0: 成功从 stream 数据流的缓冲区中读取了 ret 个字节的数据, +* (*ready) != 0: 表示读到了所要求长度的数据. +*/ +ACL_API int acl_vstream_readn_peek(ACL_VSTREAM *stream, ACL_VSTRING *strbuf, int cnt, int *ready); + +/** + * 一次性从 ACL_VSTREAM 流或系统缓存区中读取不固定长度的数据, + * 只要能读到大于 0 个字节的数据则将 ready 标志位置位 + * @param stream {ACL_VSTREAM*} 数据流 + * @param strbuf {ACL_VSTRING*} 数据缓冲区 + * @return ret {int}, ret == ACL_VSTREAM_EOF: 表示出错, 应该关闭本地数据流, + * ret >= 0: 成功从 stream 数据流的缓冲区中读取了 ret 个字节的数据. + */ +ACL_API int acl_vstream_read_peek(ACL_VSTREAM *stream, ACL_VSTRING *strbuf); + +/** + * 检查 ACL_VSTREAM 流是否可读或出错 + * @param stream {ACL_VSTREAM*} 数据流 + * @return {int} 0: 表示无数据可读; ACL_VSTREAM_EOF 表示出错; > 0 表示有数据可读 + */ +ACL_API int acl_vstream_can_read(ACL_VSTREAM *stream); + +/** + * 将文件流中的系统缓冲区及流缓冲区中的数据都直接同步至硬盘 + * @param fp {ACL_VSTREAM*} 文件流指针 + * @return {int} 0: ok; ACL_VSTREAM_EOF: error + */ +ACL_API int acl_vstream_fsync(ACL_VSTREAM *fp); + +/** + * 对于带缓冲方式的写,该函数保证缓冲区空间非空 + * @param stream {ACL_VSTREAM*} 数据流 + */ +ACL_API void acl_vstream_buffed_space(ACL_VSTREAM *stream); + +/** + * 刷新写缓冲区里的数据 + * @param stream: socket 数据流 + * @return 刷新写缓冲区里的数据量或出错 ACL_VSTREAM_EOF + */ +ACL_API int acl_vstream_fflush(ACL_VSTREAM *stream); + +/** + * 带缓冲式写 + * @param stream {ACL_VSTREAM*} 数据流 + * @param vptr {const void*} 数据指针起始位置 + * @param dlen {size_t} 要写入的数据量 + * @return {int} 写入的数据量或出错 ACL_VSTREAM_EOF + */ +ACL_API int acl_vstream_buffed_writen(ACL_VSTREAM *stream, const void *vptr, size_t dlen); +#define acl_vstream_buffed_fwrite acl_vstream_buffed_writen + +/** + * 缓冲带格式的流输出, 类似于 vfprintf() + * @param stream {ACL_VSTREAM*} 数据流 + * @param fmt {const char*} 数据格式 + * @param ap {va_list} + * @return ret {int}, ret == ACL_VSTREAM_EOF: 表示写出错, 应该关闭本地数据流, + * ret > 0: 表示成功写了 dlen 个字节的数据 + */ +ACL_API int acl_vstream_buffed_vfprintf(ACL_VSTREAM *stream, const char *fmt, va_list ap); + +/** + * 缓冲带格式的流输出, 类似于 fprintf() + * @param stream {ACL_VSTREAM*} 数据流 + * @param fmt {const char*} 数据格式 + * @param ... 变参序列 + * @return ret {int}, ret == ACL_VSTREAM_EOF: 表示写出错, 应该关闭本地数据流, + * ret > 0: 表示成功写了 dlen 个字节的数据 + */ +#ifdef WIN32 +ACL_API int acl_vstream_buffed_fprintf(ACL_VSTREAM *stream, const char *fmt, ...); +#else +ACL_API int __attribute__((format(printf,2,3))) + acl_vstream_buffed_fprintf(ACL_VSTREAM *stream, const char *fmt, ...); +#endif + +/** + * 向标准输出打印信息 + * @param fmt {const char*} 数据格式 + * @param ... 变参序列 + * @return {int}, ACL_VSTREAM_EOF: 表示写出错, > 0: 表示成功写了 dlen 个字节的数据 + */ +ACL_API int acl_vstream_buffed_printf(const char*, ...); + +/** + * 向流缓冲区中写入一行数据 + * @param s {const char*} 源字符串 + * @param stream {ACL_VSTREAM*} 数据流 + * @return {int} 0 成功; ACL_VSTREAM_EOF 失败 + */ +ACL_API int acl_vstream_buffed_fputs(const char *s, ACL_VSTREAM *stream); + +/** + * 向标准输出流缓冲区中写入一行数据 + * @param s {const char*} 源字符串 + * @return {int} 0 成功; ACL_VSTREAM_EOF 失败 + */ +ACL_API int acl_vstream_buffed_puts(const char *s); + +/** +* 一次性写入流操作, 返回实际写入的字节数. +* @param stream {ACL_VSTREAM*} 数据流 +* @param vptr {const void*} 数据区指针地址 +* @param dlen {int} 待写的数据区数据长度 +* @return ret {int}, ret == ACL_VSTREAM_EOF: 表示写出错, 应该关闭本地数据流, +* ret > 0: 表示成功写了 ret 个字节的数据 +*/ +ACL_API int acl_vstream_write(ACL_VSTREAM *stream, const void *vptr, int dlen); + +/** + * 一次性写入流操作,采用 writev 模式,返回实际写入的字节数 + * @param stream {ACL_VSTREAM*} + * @param vector {const struct iovec*} + * @param count {int} vector 数组的长度 + * @return {int} 返回成功写入的字节数,如果出错,则返回CL_VSTREAM_EOF + */ +ACL_API int acl_vstream_writev(ACL_VSTREAM *stream, const struct iovec *vector, int count); + +/** + * 采用 writev 模式往流中写,直至全部数据写完为止或出错 + * @param stream {ACL_VSTREAM*} + * @param vector {const struct iovec*} + * @param count {int} vector 数组的长度 + * @return {int} 返回成功写入的字节数,如果出错,则返回CL_VSTREAM_EOF + */ +ACL_API int acl_vstream_writevn(ACL_VSTREAM *stream, const struct iovec *vector, int count); + +/** + * 带格式的流输出, 类似于 vfprintf() + * @param stream {ACL_VSTREAM*} 数据流 + * @param fmt {const char*} 数据格式 + * @param ap {va_list} + * @return ret {int}, ret == ACL_VSTREAM_EOF: 表示写出错, 应该关闭本地数据流, + * ret > 0: 表示成功写了 dlen 个字节的数据 + */ +ACL_API int acl_vstream_vfprintf(ACL_VSTREAM *stream, const char *fmt, va_list ap); + +/** + * 带格式的流输出, 类似于 fprintf() + * @param stream {ACL_VSTREAM*} 数据流 + * @param fmt {const char*} 数据格式 + * @param ... 变参序列 + * @return ret {int}, ret == ACL_VSTREAM_EOF: 表示写出错, 应该关闭本地数据流, + * ret > 0: 表示成功写了 dlen 个字节的数据 + */ +#ifdef WIN32 +ACL_API int acl_vstream_fprintf(ACL_VSTREAM *stream, const char *fmt, ...); +#else +ACL_API int __attribute__((format(printf,2,3))) + acl_vstream_fprintf(ACL_VSTREAM *stream, const char *fmt, ...); +#endif + +/** + * 向标准输出打印信息 + * @param fmt {const char*} 数据格式 + * @param ... 变参序列 + * @return {int}, ACL_VSTREAM_EOF: 表示写出错, > 0: 表示成功写了 dlen 个字节的数据 + */ +ACL_API int acl_vstream_printf(const char*, ...); + +/** + * 向流中写入一行数据 + * @param s {const char*} 源字符串 + * @param stream {ACL_VSTREAM*} 数据流 + * @return {int} 0 成功; ACL_VSTREAM_EOF 失败 + */ +ACL_API int acl_vstream_fputs(const char *s, ACL_VSTREAM *stream); + +/** + * 向标准输出流中写入一行数据 + * @param s {const char*} 源字符串 + * @return {int} 0 成功; ACL_VSTREAM_EOF 失败 + */ +ACL_API int acl_vstream_puts(const char *s); + +/** + * 循环向数据流中写 dlen 个字节的数据直至写完或出错为止 + * @param stream {ACL_VSTREAM*} 数据流 + * @param vptr {const char*} 数据区指针地址 + * @param dlen {size_t} 待写的数据区数据长度 + * @return ret {int}, ret == ACL_VSTREAM_EOF: 表示写出错, 应该关闭本地数据流, + * ret > 0: 表示成功写了 dlen 个字节的数据 + */ +ACL_API int acl_vstream_writen(ACL_VSTREAM *stream, const void *vptr, size_t dlen); +#define acl_vstream_fwrite acl_vstream_writen + +/** + * 释放一个数据流的内存空间, 但并不关闭 socket 描述符 + * @param stream {ACL_VSTREAM*} 数据流 + */ +ACL_API void acl_vstream_free(ACL_VSTREAM *stream); + +/** + * 释放一个数据流的内存空间并关闭其所携带的 socket 描述符 + * @param stream {ACL_VSTREAM*} 数据流 + */ +ACL_API int acl_vstream_close(ACL_VSTREAM *stream); +#define acl_vstream_fclose acl_vstream_close + +/** + * 调用数据流中的所有关闭回调函数同时清除这些回调函数 + * @param stream {ACL_VSTREAM*} 数据流 + */ +ACL_API void acl_vstream_call_close_handles(ACL_VSTREAM *stream); + +/** + * 注册一个关闭函数 + * @param stream {ACL_VSTREAM*} 数据流 + * @param close_fn {void (*)(ACL_VSTREAM*, void*)} 关闭函数指针 + * @param context {void*} close_fn 所需要的参数 + */ +ACL_API void acl_vstream_add_close_handle(ACL_VSTREAM *stream, + void (*close_fn)(ACL_VSTREAM*, void*), void *context); + +/** + * 删除一个关闭句柄. + * @param stream {ACL_VSTREAM*} 数据流 + * @param close_fn {void (*)(ACL_VSTREAM*, void*)} 关闭函数指针 + * @param context {void*} close_fn 所需要的参数 + */ +ACL_API void acl_vstream_delete_close_handle(ACL_VSTREAM *stream, + void (*close_fn)(ACL_VSTREAM*, void*), void *context); +/** + * 清除一个数据流中所有的关闭句柄 + * @param stream {ACL_VSTREAM*} 数据流 + */ +ACL_API void acl_vstream_clean_close_handle(ACL_VSTREAM *stream); + +/** + * 重新复位数据流的内部数据指针及计数值 + * @param stream {ACL_VSTREAM*} 数据流 + */ +ACL_API void acl_vstream_reset(ACL_VSTREAM *stream); + +/** + * 取得当前数据流的错误状态 + * @param stream {ACL_VSTREAM*} 数据流 + * @return {const char*} 错误描述 + */ +ACL_API const char *acl_vstream_strerror(ACL_VSTREAM *stream); + +/*----------------------- 以下为常用的宏函数 ------------------------------*/ +/** + * 从stream 流中读取一个字节的宏实现,效率要比 acl_vstream_getc()/1 高 + * @param stream {ACL_VSTREAM*} 数据流指针 + * @return {int} ACL_VSTREAM_EOF(出错) 或所读到的某个字节的ASCII, + * 若为 ACL_VSTREAM_EOF: 读出错或对方关闭了连接, 应该关闭该数据流 + */ +#define ACL_VSTREAM_GETC(stream_ptr) ( \ + (stream_ptr)->read_cnt > 0 ? \ + (stream_ptr)->read_cnt--, \ + (stream_ptr)->offset++, \ + *(stream_ptr)->read_ptr++: \ + (stream_ptr)->sys_getc((stream_ptr))) + +/** + * 向 stream 流中写一个字节的宏实现 + * @param stream {ACL_VSTREAM*} 数据流指针 + * @return {int} ACL_VSTREAM_EOF(出错) 或所写入字节的 ASCII + */ +#define ACL_VSTREAM_PUTC(ch, stream_ptr) ( \ + (stream_ptr)->wbuf_size == 0 ? \ + (acl_vstream_buffed_space((stream_ptr)), \ + ((stream_ptr)->wbuf[(size_t) (stream_ptr)->wbuf_dlen++] = (ch))) \ + : ((stream_ptr)->wbuf_dlen == stream_ptr->wbuf_size ? \ + (acl_vstream_fflush((stream_ptr)) == ACL_VSTREAM_EOF ? \ + ACL_VSTREAM_EOF \ + : ((stream_ptr)->wbuf[(size_t) (stream_ptr)->wbuf_dlen++] = (ch))) \ + : ((stream_ptr)->wbuf[(size_t) (stream_ptr)->wbuf_dlen++] = (ch)))) + +/** + * 由流获得套接字 + * @param stream_ptr {ACL_VSTREAM*} + */ +#define ACL_VSTREAM_SOCK(stream_ptr) ((stream_ptr)->fd.sock) + +/** + * 由流获得文件句柄 + * @param stream_ptr {ACL_VSTREAM*} + */ +#define ACL_VSTREAM_FILE(stream_ptr) ((stream_ptr)->fd.h_file) + +/** + * 获得文件流句柄的文件路径名 + * @param stream_ptr {ACL_VSTREAM*} + */ +#define ACL_VSTREAM_PATH(stream_ptr) ((stream_ptr)->path) + +/** + * 当 ACL_VSTREAM 为网络流时,用此宏取得对方的地址 + */ +#define ACL_VSTREAM_PEER(stream_ptr) ((stream_ptr)->remote_addr) + +/** + * 当 ACL_VSTREAM 为网络流时,用此宏取得本地的地址 + */ +#define ACL_VSTREAM_LOCAL(stream_ptr) ((stream_ptr)->local_addr) + +/** + * 设定流的读/写套接字 + * @param stream_ptr {ACL_VSTREAM*} + * @param _fd {ACL_SOCKET} 套接字 + */ +#define ACL_VSTREAM_SET_SOCK(stream_ptr, _fd) do { \ + ACL_VSTREAM *__stream_ptr = stream_ptr; \ + __stream_ptr->fd.sock = _fd; \ +} while (0) + +/** + * 设置流中的文件句柄 + * @param stream_ptr {ACL_VSTREAM*} + * @param _fh {ACL_FILE_HANDLE} + */ +#define ACL_VSTREAM_SET_FILE(stream_ptr, _fh) do { \ + ACL_VSTREAM *__stream_ptr = stream_ptr; \ + __stream_ptr->fd.h_file = _fh; \ +} while (0) + +/* 一些比较快速的宏的运算模式 */ + +/** + * 流中在读缓冲区中的数据量大小 + * @param stream_ptr {ACL_VSTREAM*) 类型的指针 + * @return -1: 表示出错, >= 0 此值即为流读缓冲区中的数据量大小 + */ +#define ACL_VSTREAM_BFRD_CNT(stream_ptr) \ + ((stream_ptr) == NULL ? -1 : (stream_ptr)->read_cnt) + +/** + * 设定流的读写超时值 + * @param stream_ptr {ACL_VSTREAM*) 类型的指针 + * @param _rw_timeo {int} 超时值大小(以秒为单位) + */ +#define ACL_VSTREAM_SET_RWTIMO(stream_ptr, _rw_timeo) do { \ + ACL_VSTREAM *__stream_ptr = stream_ptr; \ + __stream_ptr->rw_timeout = _rw_timeo; \ +} while (0) + +/** + * 将流置为结束状态 + * @param stream_ptr {ACL_VSTREAM*) 类型的指针 + */ +#define ACL_VSTREAM_SET_EOF(stream_ptr) do { \ + ACL_VSTREAM *__stream_ptr = stream_ptr; \ + __stream_ptr->flag |= ACL_VSTREAM_FLAG_EOF; \ +} while (0) + +/** + * 判断数据流是否出了错 + * @param stream_ptr: ACL_VSTREAM 类型的指针 + * @return 0表示正常, 非0表示出错 + */ +#define ACL_IF_VSTREAM_ERR(stream_ptr) \ + ((stream_ptr)->flag & ACL_VSTREAM_FLAG_BAD) + +#ifdef __cplusplus +} +#endif + +/** + * 从数据流中取出与该流读写有关的系统错误号 + * @param stream_ptr {ACL_VSTREAM*) 类型的指针 + * @return err {int} 整形错误号,调用者可以用 strerror(err) 的方式查看具体含义 + */ +#define ACL_VSTREAM_ERRNO(stream_ptr) ((stream_ptr)->errnum) + +/** + * 判断一个流是否超时 + * @param stream_ptr {ACL_VSTREAM*) 类型的指针 + * @return {int} 0: 否; != 0: 是 + */ +#define acl_vstream_ftimeout(stream_ptr) \ + ((stream_ptr)->flag & ACL_VSTREAM_FLAG_TIMEOUT) + +#endif + diff --git a/lib_acl/include/stdlib/acl_vstream_popen.h b/lib_acl/include/stdlib/acl_vstream_popen.h new file mode 100644 index 000000000..9d61eb6da --- /dev/null +++ b/lib_acl/include/stdlib/acl_vstream_popen.h @@ -0,0 +1,34 @@ +#ifndef __ACL_VSTREAM_POPEN_INCLUDE_H__ +#define __ACL_VSTREAM_POPEN_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "acl_define.h" +#include "acl_vstream.h" + +#ifdef ACL_UNIX +#define DUP2 dup2 +#endif + +ACL_API ACL_VSTREAM *acl_vstream_popen(int,...); +ACL_API int acl_vstream_pclose(ACL_VSTREAM *); + +#define acl_vstream_ispipe(vp) ((vp)->pid != 0) + +#define ACL_VSTREAM_POPEN_END 0 /* terminator */ +#define ACL_VSTREAM_POPEN_COMMAND 1 /* command is string */ +#define ACL_VSTREAM_POPEN_ARGV 2 /* command is array */ +#define ACL_VSTREAM_POPEN_UID 3 /* privileges */ +#define ACL_VSTREAM_POPEN_GID 4 /* privileges */ +#define ACL_VSTREAM_POPEN_ENV 5 /* extra environment */ +#define ACL_VSTREAM_POPEN_SHELL 6 /* alternative shell */ +#define ACL_VSTREAM_POPEN_WAITPID_FN 7 /* child catcher, waitpid() compat. */ +#define ACL_VSTREAM_POPEN_EXPORT 8 /* exportable environment */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/include/stdlib/acl_vstring.h b/lib_acl/include/stdlib/acl_vstring.h new file mode 100644 index 000000000..2b4413386 --- /dev/null +++ b/lib_acl/include/stdlib/acl_vstring.h @@ -0,0 +1,404 @@ +#ifndef __ACL_VSTRING_H_INCLUDED__ +#define __ACL_VSTRING_H_INCLUDED__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "acl_define.h" +#include +#include "acl_vbuf.h" +#include "acl_slice.h" + +/** + * 封装了 ACL_VBUF,ACL_VSTRING 结构类型定义 + */ +typedef struct ACL_VSTRING { + ACL_VBUF vbuf; + int maxlen; + ACL_SLICE_POOL *slice; +} ACL_VSTRING; + +/** + * 初始化 ACL_VSTRING 结构并指定缺省的缓冲区大小,当用户在自己的函数或 + * 内部以 ACL_VSTRING str 方式(非动态分配方式)使用时需要用此函数进行初始化, + * 另外,必须用 acl_vstring_free_buf 方式来释放由该函数分配的内部缓冲区 + * @param vp {ACL_VSTRING*} 对象地址,不能为空 + * @param len {size_t} 初始时缓冲区大小 + */ +ACL_API void acl_vstring_init(ACL_VSTRING *vp, size_t len); + +/** + * 当以 acl_vstring_init 初始化 ACL_VSTRING 对象时需要调用此函数释放缓冲区内存 + * @param vp {ACL_VSTRING*} 对象地址,不能为空 + */ +ACL_API void acl_vstring_free_buf(ACL_VSTRING *vp); + +/** + * 动态分配一个 ACL_VSTRING 对象并指定内部缓冲区的初始化大小 + * @param len {size_t} 初始时缓冲区大小 + * @return {ACL_VSTRING*} 新分配的 ACL_VSTRING 对象 + */ +ACL_API ACL_VSTRING *acl_vstring_alloc(size_t len); + +/** + * 动态分配一个 ACL_VSTRING 对象并指定内部缓冲区的初始化大小, + * 同时指定内存池对象,优化内存分配 + * @param slice {ACL_SLICE_POOL*} 切片内存池管理对象 + * @param len {size_t} 初始时缓冲区大小 + * @return {ACL_VSTRING*} 新分配的 ACL_VSTRING 对象 + */ +ACL_API ACL_VSTRING *acl_vstring_alloc2(ACL_SLICE_POOL *slice, size_t len); + +/** + * 设置 ACL_VSTRING 对象的属性, 目前该函数的功能还不够完善 + * @param vp {ACL_VSTRING*} + * @param ... 由 ACL_VSTRING_CTL_XXX 表示的控制参数,结束标志为 ACL_VSTRING_CTL_END + */ +ACL_API void acl_vstring_ctl(ACL_VSTRING *vp,...); + +#define ACL_VSTRING_CTL_MAXLEN 1 +#define ACL_VSTRING_CTL_END 0 + +/** + * 将缓冲区内的数据截短至指定长度 + * @param vp {ACL_VSTRING*} + * @param len {size_t} 截短后的长度 + * @return {ACL_VSTRING*} 与 vp 相同 + */ +ACL_API ACL_VSTRING *acl_vstring_truncate(ACL_VSTRING *vp, size_t len); + +/** + * 释放由 acl_vstring_alloc 动态分配的 ACL_VSTRING 对象 + * @param vp {ACL_VSTRING*} + * @return {ACL_VSTRING*} 永远为 NULL,所以不必关心返回值 + */ +ACL_API ACL_VSTRING *acl_vstring_free(ACL_VSTRING *vp); + +/** + * 拷贝字符串 + * @param vp {ACL_VSTRING*} + * @param src {const char*} 源字符串 + * @return {ACL_VSTRING*} 与 vp 相同 + */ +ACL_API ACL_VSTRING *acl_vstring_strcpy(ACL_VSTRING *vp, const char *src); + +/** + * 拷贝字符串,但不得超过规定长度限制 + * @param vp {ACL_VSTRING*} + * @param src {const char*} 源字符串 + * @param len {size_t} 规定长度限制 + * @return {ACL_VSTRING*} 与 vp 相同 + */ +ACL_API ACL_VSTRING *acl_vstring_strncpy(ACL_VSTRING *vp, const char *src, size_t len); + +/** + * 附加拷贝字符串 + * @param vp {ACL_VSTRING*} + * @param src {const char*} 源字符串 + * @return {ACL_VSTRING*} 与 vp 相同 + */ +ACL_API ACL_VSTRING *acl_vstring_strcat(ACL_VSTRING *vp, const char *src); + +/** + * 附加拷贝字符串,但不得超过规定长度限制 + * @param vp {ACL_VSTRING*} + * @param src {const char*} 源字符串 + * @param len {size_t} 规定长度限制 + * @return {ACL_VSTRING*} 与 vp 相同 + */ +ACL_API ACL_VSTRING *acl_vstring_strncat(ACL_VSTRING *vp, const char *src, size_t len); + +/** + * 拷贝内存区数据 + * @param vp {ACL_VSTRING*} + * @param src {const char*} 源数据地址 + * @param len {size_t} 源数据长度 + * @return {ACL_VSTRING*} 与 vp 相同 + */ +ACL_API ACL_VSTRING *acl_vstring_memcpy(ACL_VSTRING *vp, const char *src, size_t len); + +/** + * 移动内存区数据, 源数据与目标地址的内存区可以是同一块内存区也可以不是同一块内存区 + * @param vp {ACL_VSTRING*} + * @param src {const char*} 源数据地址 + * @param len {size_t} 源数据长度 + * @return {ACL_VSTRING*} 与 vp 相同 + */ +ACL_API ACL_VSTRING *acl_vstring_memmove(ACL_VSTRING *vp, const char *src, size_t len); + +/** + * 拷贝内存区 + * @param vp {ACL_VSTRING*} + * @param src {const char*} 源数据地址 + * @param len {size_t} 源数据长度 + * @return {ACL_VSTRING*} 与 vp 相同 + */ +ACL_API ACL_VSTRING *acl_vstring_memcat(ACL_VSTRING *vp, const char *src, size_t len); + +/** + * 查找某个字符 + * @param vp {ACL_VSTRING*} + * @param ch {int} 要查找的字符 + * @return {char*} 目标字符所在位置的地址, 如果未查到则返回 NULL, 注:该返回地址是不能 + * 被单独释放的,因为其由 ACL_VSTRING 对象统一进行管理 + */ +ACL_API char *acl_vstring_memchr(ACL_VSTRING *vp, int ch); + +/** + * 查找某个字符串,字符串大小写敏感 + * @param vp {ACL_VSTRING*} + * @param needle {const char*} 要查找的字符 + * @return {char*} 目标字符所在位置的地址, 如果未查到则返回 NULL, 注:该返回地址是不能 + * 被单独释放的,因为其由 ACL_VSTRING 对象统一进行管理 + */ +ACL_API char *acl_vstring_strstr(ACL_VSTRING *vp, const char *needle); + +/** + * 查找某个字符串,忽略字符串大小写 + * @param vp {ACL_VSTRING*} + * @param needle {const char*} 要查找的字符 + * @return {char*} 目标字符所在位置的地址, 如果未查到则返回 NULL, 注:该返回地址是不能 + * 被单独释放的,因为其由 ACL_VSTRING 对象统一进行管理 + */ +ACL_API char *acl_vstring_strcasestr(ACL_VSTRING *vp, const char *needle); + +/** + * 从后向前查找字符串,字符串大小写敏感 + * @param vp {ACL_VSTRING*} + * @param needle {const char*} 要查找的字符 + * @return {char*} 目标字符所在位置的地址, 如果未查到则返回 NULL, 注:该返回地址是不能 + * 被单独释放的,因为其由 ACL_VSTRING 对象统一进行管理 + */ +ACL_API char *acl_vstring_rstrstr(ACL_VSTRING *vp, const char *needle); + +/** + * 从后向前查找字符串,字符串大小写不敏感 + * @param vp {ACL_VSTRING*} + * @param needle {const char*} 要查找的字符 + * @return {char*} 目标字符所在位置的地址, 如果未查到则返回 NULL, 注:该返回地址是不能 + * 被单独释放的,因为其由 ACL_VSTRING 对象统一进行管理 + */ +ACL_API char *acl_vstring_rstrcasestr(ACL_VSTRING *vp, const char *needle); + +/** + * 向缓冲区的某个指定位置后添加数据 + * @param vp {ACL_VSTRING*} + * @param start {size_t} 指定的位置 + * @param buf {const char*} 数据地址 + * @param len {size_t} 数据长度 + * @return {ACL_VSTRING*} 与 vp 相同 + */ +ACL_API ACL_VSTRING *acl_vstring_insert(ACL_VSTRING *vp, size_t start, + const char *buf, size_t len); + +/** + * 向缓冲区的头部添加数据 + * @param vp {ACL_VSTRING*} + * @param buf {const char*} 数据地址 + * @param len {size_t} 数据长度 + * @return {ACL_VSTRING*} 与 vp 相同 + */ +ACL_API ACL_VSTRING *acl_vstring_prepend(ACL_VSTRING *vp, const char *buf, size_t len); + +/** + * 向缓冲区按格式方式添加数据 + * @param vp {ACL_VSTRING*} + * @param format {const char*} 格式化字符串 + * @param ... 变参序列 + * @return {ACL_VSTRING*} 与 vp 相同 + */ +#ifdef WIN32 +ACL_API ACL_VSTRING *acl_vstring_sprintf(ACL_VSTRING *vp, const char *format,...); +#else +ACL_API ACL_VSTRING *__attribute__((format(printf,2,3))) + acl_vstring_sprintf(ACL_VSTRING *vp, const char *format,...); +#endif + +/** + * 以附加方式向缓冲区按格式方式添加数据 + * @param vp {ACL_VSTRING*} + * @param format {const char*} 格式化字符串 + * @param ... 变参序列 + * @return {ACL_VSTRING*} 与 vp 相同 + */ +#ifdef WIN32 +ACL_API ACL_VSTRING *acl_vstring_sprintf_append(ACL_VSTRING *vp, const char *format,...); +#else +ACL_API ACL_VSTRING *__attribute__((format(printf,2,3))) + acl_vstring_sprintf_append(ACL_VSTRING *vp, const char *format,...); +#endif + +/** + * 导出缓冲区内的数据区同时将 ACL_VSTRING 对象释放,用户需要单独调用 acl_myfree 来 + * 释放返回的数据区内存 + * @param vp {ACL_VSTRING*} + * @return {char*} 数据区地址,当返回值不为 NULL 时用户需要单独调用 acl_myfree 来 + * 释放该地址,否则会造成内存泄漏 + */ +ACL_API char *acl_vstring_export(ACL_VSTRING *vp); + +/** + * 将用户的存储字符串的动态分配内存区导入并生成新的 ACL_VSTRING 对象 + * @param str {char*} 外部动态分配的存储字符串的内存地址 + * @return {ACL_VSTRING*} 新分配的 ACL_VSTRING 对象 + */ +ACL_API ACL_VSTRING *acl_vstring_import(char *str); + +/** + * 将动态内存区与 ACL_VSTRING 粘合,注:vp 不能是调用 acl_vstring_alloc 产生的, + * 并且不能调用 acl_vstring_init 进行过初始化, vp 可以是由 acl_mymalloc 产生或 + * 位于栈上的一个变量(如: ACL_VSTRING v) + * @param vp {ACL_VSTRING*} 需由 acl_mymalloc 生成或是一个栈变量, 当以 acl_mymalloc + * 方式生成的时应该通过 acl_myfree 释放它 + * @param buf {void*} 用户传递的内存区, 可以是栈变量 + * @param len {size_t} buf 内存区的长度 + */ +ACL_API void acl_vstring_glue(ACL_VSTRING *vp, void *buf, size_t len); + +/** + * 取得某个位置的字符 + * @param vp {ACL_VSTRING*} + * @param len {size_t} 位置,如果该值越界,则函数内部会 fatal + * @return {char} 查找的字符 + */ +ACL_API char acl_vstring_charat(ACL_VSTRING *vp, size_t len); + +/** + * 按规定格式添加数据 + * @param vp {ACL_VSTRING*} + * @param format {const char*} + * @param ap {va_list} + * @return {ACL_VSTRING*} 与 vp 相同 + * @see acl_vstring_sprintf + */ +ACL_API ACL_VSTRING *acl_vstring_vsprintf(ACL_VSTRING *vp, const char *format, va_list ap); + +/** + * 按规定格式向尾部添加数据 + * @param vp {ACL_VSTRING*} + * @param format {const char*} + * @param ap {va_list} + * @return {ACL_VSTRING*} 与 vp 相同 + */ +ACL_API ACL_VSTRING *acl_vstring_vsprintf_append(ACL_VSTRING *vp, const char *format, va_list ap); + +/** + * 按规定格式向头部添加数据 + * @param vp {ACL_VSTRING*} + * @param format {const char*} + * @param ... 变参序列 + * @return {ACL_VSTRING*} 与 vp 相同 + */ +#ifdef WIN32 +ACL_API ACL_VSTRING *acl_vstring_sprintf_prepend(ACL_VSTRING *vp, const char *format, ...); +#else +ACL_API ACL_VSTRING *__attribute__((format(printf,2,3))) + acl_vstring_sprintf_prepend(ACL_VSTRING *vp, const char *format, ...); +#endif + +/** + * 从源串中获得一行数据(不含 "\r\n" 和 "\n"),同时将剩余数据缓存起来, 如果未获得完整行,则只缓存源串 + * @param vp {ACL_VSTRING*} 字符串数据缓存区 + * @param src {const char**} 源字符串指针地址, 返回后指针地址移动至下一位置 + * @param dlen {size_t} 源字符串数据长度 + * @return {const ACL_VSTRING*} NULL, 表示未找到 "\r\n" 或 "\n",但会将剩余的数据 + * 拷贝至缓冲区内,应用需要通过 ACL_VSTRING_LEN 判断缓冲区中是否还有数据;!NULL,表示读到完整行 + * 注:读到完整行后应该调用 ACL_VSTRING_RESET(vp) 将缓冲区清空 + */ +ACL_API const ACL_VSTRING *acl_buffer_gets_nonl(ACL_VSTRING *vp, const char **src, size_t dlen); + +/** + * 从源串中获得一行数据(包含 "\r\n" 或 "\n"),同时将剩余数据缓存起来, 如果未获得完整行,则只缓存源串 + * @param vp {ACL_VSTRING*} 字符串数据缓存区 + * @param src {const char**} 源字符串指针地址, 返回后指针地址移动至下一位置 + * @param dlen {size_t} 源字符串数据长度 + * @return {const ACL_VSTRING*} NULL, 表示未找到 "\r\n" 或 "\n",但会将剩余的数据 + * 拷贝至缓冲区内,应用需要通过 ACL_VSTRING_LEN 判断缓冲区中是否还有数据;!NULL,表示读到完整行 + * 注:读到完整行后应该调用 ACL_VSTRING_RESET(vp) 将缓冲区清空 + */ +ACL_API const ACL_VSTRING *acl_buffer_gets(ACL_VSTRING *vp, const char **src, size_t dlen); + + /* + * Macros. Unsafe macros have UPPERCASE names. + */ +#define ACL_VSTRING_SPACE(vp, len) ((vp)->vbuf.space(&(vp)->vbuf, len)) + +/** + * 取得当前 ACL_VSTRING 数据存储地址 + * @param vp {ACL_VSTRING*} + * @return {char*} + */ +#define acl_vstring_str(vp) ((char *) (vp)->vbuf.data) + +/** + * 取得当前 ACL_VSTRING 所存储的数据的长度 + * @param vp {ACL_VSTRING*} + * @return {int} + */ +#define ACL_VSTRING_LEN(vp) (size_t) ((vp)->vbuf.ptr - (vp)->vbuf.data) + +/** + * 取得当前 ACL_VSTRING 内部缓冲区的总大小 + * @param vp {ACL_VSTRING*} + * @return {int} + */ +#define ACL_VSTRING_SIZE(vp) ((vp)->vbuf.len) + +/** + * 取得当前 ACL_VSTRING 的数据偏移指针位置 + * @param vp {ACL_VSTRING*} + * @return {char*} + */ +#define acl_vstring_end(vp) ((char *) (vp)->vbuf.ptr) + +/** + * 将 ACL_VSTRING 的数据偏移指针位置置 0 + * @param vp {ACL_VSTRING*} + */ +#define ACL_VSTRING_TERMINATE(vp) { if ((vp)->vbuf.cnt <= 0) \ + ACL_VSTRING_SPACE((vp),1); \ + *(vp)->vbuf.ptr = 0; } + +/** + * 重置 ACL_VSTRING 内部缓冲区同时将偏移指针位置置 0 + * @param vp {ACL_VSTRING*} + */ +#define ACL_VSTRING_RESET(vp) { (vp)->vbuf.ptr = (vp)->vbuf.data; \ + (vp)->vbuf.cnt = (vp)->vbuf.len; } + +/** + * 添加一个字符至 ACL_VSTRING 缓冲区 + * @param vp {ACL_VSTRING*} + * @param ch {int} 字符 + */ +#define ACL_VSTRING_ADDCH(vp, ch) ACL_VBUF_PUT(&(vp)->vbuf, ch) + +/** + * 移动数据偏移指针至内部缓冲区尾部 + * @param vp {ACL_VSTRING*} + */ +#define ACL_VSTRING_SKIP(vp) { while ((vp)->vbuf.cnt > 0 && *(vp)->vbuf.ptr) \ + (vp)->vbuf.ptr++, (vp)->vbuf.cnt--; } + +/** + * 当前 ACL_VSTRING 中还有多少数据可用 + * @param vp {ACL_VSTRING*} + */ +#define acl_vstring_avail(vp) ((vp)->vbuf.cnt) + + /** + * The following macro is not part of the public interface, because it can + * really screw up a buffer by positioning past allocated memory. + */ +#define ACL_VSTRING_AT_OFFSET(vp, offset) { \ + (vp)->vbuf.ptr = (vp)->vbuf.data + (offset); \ + (vp)->vbuf.cnt = (vp)->vbuf.len - (offset); \ + } + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/include/stdlib/acl_vstring_vstream.h b/lib_acl/include/stdlib/acl_vstring_vstream.h new file mode 100644 index 000000000..b31dac13a --- /dev/null +++ b/lib_acl/include/stdlib/acl_vstring_vstream.h @@ -0,0 +1,84 @@ +#ifndef __ACL_VSTRING_VSTREAM_INCLUDE_H__ +#define __ACL_VSTRING_VSTREAM_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "acl_define.h" +#include "acl_vstring.h" +#include "acl_vstream.h" + +/** + * 从数据流中读一行数据,直至读到一行、出错,或读完为止 + * @param vp {ACL_VSTRING*} 存储结果的缓存区 + * @param fp {ACL_VSTREAM*} 数据流 + * @return {int} 最后一个字符的ASCII,或 ACL_VSTREAM_EOF + */ +ACL_API int acl_vstring_gets(ACL_VSTRING *vp, ACL_VSTREAM *fp); + +/** + * 从数据流中读一行数据,直至读到一行、出错,或读完为止, 读的数据不包含 + * "\r\n" 或 "\n" + * @param vp {ACL_VSTRING*} 存储结果的缓存区 + * @param fp {ACL_VSTREAM*} 数据流 + * @return {int} 最后一个字符的ASCII,或 ACL_VSTREAM_EOF + */ +ACL_API int acl_vstring_gets_nonl(ACL_VSTRING *vp, ACL_VSTREAM *fp); + +/** + * 从数据流中读到 "\0" 结尾的数据或出错为止, 但不包含 "\0" + * @param vp {ACL_VSTRING*} 存储结果的缓存区 + * @param fp {ACL_VSTREAM*} 数据流 + * @return {int} 最后一个字符的ASCII,或 ACL_VSTREAM_EOF + */ +ACL_API int acl_vstring_gets_null(ACL_VSTRING *vp, ACL_VSTREAM *fp); + +/** + * 从数据流中读一行数据,但读的数据长度不得超过限定值 + * @param vp {ACL_VSTRING*} 存储结果的缓存区 + * @param fp {ACL_VSTREAM*} 数据流 + * @param bound {ssize_t} 所读数据最大长度限制 + * @return {int} 最后一个字符的ASCII,或 ACL_VSTREAM_EOF + */ +ACL_API int acl_vstring_gets_bound(ACL_VSTRING *vp, ACL_VSTREAM *fp, ssize_t bound); + +/** + * 从数据流中读一行数据,但读的数据长度不得超过限定值, 且结果中不包含 "\n" 或 "\r\n" + * @param vp {ACL_VSTRING*} 存储结果的缓存区 + * @param fp {ACL_VSTREAM*} 数据流 + * @param bound {ssize_t} 所读数据最大长度限制 + * @return {int} 最后一个字符的ASCII,或 ACL_VSTREAM_EOF + */ +ACL_API int acl_vstring_gets_nonl_bound(ACL_VSTRING *vp, ACL_VSTREAM *fp, ssize_t bound); + +/** + * 从数据流中读到 "\0" 结尾的数据或出错或超过最大长度限制为止,结果中不包含 "\0" + * @param vp {ACL_VSTRING*} 存储结果的缓存区 + * @param fp {ACL_VSTREAM*} 数据流 + * @param bound {ssize_t} 所读数据最大长度限制 + * @return {int} 最后一个字符的ASCII,或 ACL_VSTREAM_EOF + */ +ACL_API int acl_vstring_gets_null_bound(ACL_VSTRING *vp, ACL_VSTREAM *fp, ssize_t bound); + +/** + * Backwards compatibility for code that still uses the vstring_fgets() + * interface. Unfortunately we can't change the macro name to upper case. + */ + +#define acl_vstring_fgets(s, p) \ + (acl_vstring_gets((s), (p)) == ACL_VSTREAM_EOF ? 0 : (s)) +#define acl_vstring_fgets_nonl(s, p) \ + (acl_vstring_gets_nonl((s), (p)) == ACL_VSTREAM_EOF ? 0 : (s)) +#define acl_vstring_fgets_null(s, p) \ + (acl_vstring_gets_null((s), (p)) == ACL_VSTREAM_EOF ? 0 : (s)) +#define acl_vstring_fgets_bound(s, p, l) \ + (acl_vstring_gets_bound((s), (p), (l)) == ACL_VSTREAM_EOF ? 0 : (s)) +#define acl_vstring_fgets_nonl_bound(s, p, l) \ + (acl_vstring_gets_nonl_bound((s), (p), (l)) == ACL_VSTREAM_EOF ? 0 : (s)) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/include/stdlib/acl_xinetd_cfg.h b/lib_acl/include/stdlib/acl_xinetd_cfg.h new file mode 100644 index 000000000..01c7ffe12 --- /dev/null +++ b/lib_acl/include/stdlib/acl_xinetd_cfg.h @@ -0,0 +1,144 @@ +#ifndef __ACL_XINETD_CFG_INCLUDE_H_ +#define __ACL_XINETD_CFG_INCLUDE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "acl_define.h" +#include "acl_array.h" + +/** + * 配置文件解析句柄类型定义 + */ +typedef struct ACL_XINETD_CFG_PARSER ACL_XINETD_CFG_PARSER; + +/** + * 功能: 获得所需要的配置 项的内容 + * @param xcp: 结构指针, 不能为空 + * @param name: 配置项的变量名 + * @return 配置文件中配置项的内容 + */ +ACL_API const char *acl_xinetd_cfg_get(const ACL_XINETD_CFG_PARSER *xcp, const char *name); + +/** + * 功能: 获得所需要的配置项的数组,对于一个变量名对应多个变量值时有用 + * @param xcp: 结构指针, 不能为空 + * @param name: 配置项的变量名 + * @return 配置文件中配置项的内容动态数组 + */ +ACL_API const ACL_ARRAY *acl_xinetd_cfg_get_ex(const ACL_XINETD_CFG_PARSER *xcp, const char *name); + +/** + * 功能: 从配置文件中获得对应在于某一个索引值位置的内容 + * @param xcp: 结构指针, 不能为空 + * @param idx: 索引位置值 + * @param ppname: 指向指针的地址的变量 + * @param ppvalue: 指向指针的地址的变量 + * @return 0: OK, -1: ERR + */ +ACL_API int acl_xinetd_cfg_index(const ACL_XINETD_CFG_PARSER *xcp, + int idx, + char **ppname, + char **ppvalue); + +/** + * 功能: 配置文件中配置项的条数 + * @param xcp: 结构指针, 不能为空 + * @return 配置文件中配置项的条数 + */ +ACL_API int acl_xinetd_cfg_size(const ACL_XINETD_CFG_PARSER *xcp); + +/** + * 功能: 释放由结构指针所指向的内存空间 + * @param xcp: 结构指针 + */ +ACL_API void acl_xinetd_cfg_free(ACL_XINETD_CFG_PARSER *xcp); + +/** + * 功能: 读取配置文件并进行解析 + * @param pathname: 配置文件的文件名 + * @return 已经解析了配置文件的结构指针 + */ +ACL_API ACL_XINETD_CFG_PARSER *acl_xinetd_cfg_load(const char *pathname); + +/** + * 整数类配置项结构 + */ +typedef struct ACL_CFG_INT_TABLE { + const char *name; + int defval; + int *target; + int min; + int max; +} ACL_CFG_INT_TABLE; + +/** + * 64 位整数类配置项结构 + */ +typedef struct ACL_CFG_INT64_TABLE { + const char *name; + acl_int64 defval; + acl_int64 *target; + acl_int64 min; + acl_int64 max; +} ACL_CFG_INT64_TABLE; + +/** + * 字符串类配置项结构 + */ +typedef struct ACL_CFG_STR_TABLE { + const char *name; + const char *defval; + char **target; +} ACL_CFG_STR_TABLE; + +/** + * 布尔型类配置项结构 + */ +typedef struct ACL_CFG_BOOL_TABLE { + const char *name; + int defval; + int *target; +} ACL_CFG_BOOL_TABLE; + +/* in acl_xinetd_params.c */ + +/** + * 从配置文件解析器中读取整数类型的表 + * @param cfg {ACL_XINETD_CFG_PARSER*} 当为空时则用默认值进行赋值 + * @param table {ACL_CFG_INT_TABLE*} + */ +ACL_API void acl_xinetd_params_int_table(ACL_XINETD_CFG_PARSER *cfg, + ACL_CFG_INT_TABLE *table); + +/** + * 从配置文件解析器中读取 64 位整数类型的表 + * @param cfg {ACL_XINETD_CFG_PARSER*} 当为空时则用默认值进行赋值 + * @param table {ACL_CFG_INT64_TABLE*} + */ +ACL_API void acl_xinetd_params_int64_table(ACL_XINETD_CFG_PARSER *cfg, + ACL_CFG_INT64_TABLE *table); + +/** +* 从配置文件解析器中读取字符串类型的表 +* @param cfg {ACL_XINETD_CFG_PARSER*} 当为空时则用默认值进行赋值 +* @param table {ACL_CFG_STR_TABLE*} +*/ +ACL_API void acl_xinetd_params_str_table(ACL_XINETD_CFG_PARSER *cfg, + ACL_CFG_STR_TABLE *table); + +/** +* 从配置文件解析器中读取BOOL类型的表 +* @param cfg {ACL_XINETD_CFG_PARSER*} 当为空时则用默认值进行赋值 +* @param table {ACL_CFG_BOOL_TABLE*} +*/ +ACL_API void acl_xinetd_params_bool_table(ACL_XINETD_CFG_PARSER *cfg, + ACL_CFG_BOOL_TABLE *table); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/include/stdlib/avl.h b/lib_acl/include/stdlib/avl.h new file mode 100644 index 000000000..4441bfbab --- /dev/null +++ b/lib_acl/include/stdlib/avl.h @@ -0,0 +1,314 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _AVL_H +#define _AVL_H + +/* + * This is a private header file. Applications should not directly include + * this file. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_define.h" +#include +#include "avl_impl.h" + +/* + * This is a generic implemenatation of AVL trees for use in the Solaris kernel. + * The interfaces provide an efficient way of implementing an ordered set of + * data structures. + * + * AVL trees provide an alternative to using an ordered linked list. Using AVL + * trees will usually be faster, however they requires more storage. An ordered + * linked list in general requires 2 pointers in each data structure. The + * AVL tree implementation uses 3 pointers. The following chart gives the + * approximate performance of operations with the different approaches: + * + * Operation Link List AVL tree + * --------- -------- -------- + * lookup O(n) O(log(n)) + * + * insert 1 node constant constant + * + * delete 1 node constant between constant and O(log(n)) + * + * delete all nodes O(n) O(n) + * + * visit the next + * or prev node constant between constant and O(log(n)) + * + * + * The data structure nodes are anchored at an "avl_tree_t" (the equivalent + * of a list header) and the individual nodes will have a field of + * type "avl_node_t" (corresponding to list pointers). + * + * The type "avl_index_t" is used to indicate a position in the list for + * certain calls. + * + * The usage scenario is generally: + * + * 1. Create the list/tree with: avl_create() + * + * followed by any mixture of: + * + * 2a. Insert nodes with: avl_add(), or avl_find() and avl_insert() + * + * 2b. Visited elements with: + * avl_first() - returns the lowest valued node + * avl_last() - returns the highest valued node + * AVL_NEXT() - given a node go to next higher one + * AVL_PREV() - given a node go to previous lower one + * + * 2c. Find the node with the closest value either less than or greater + * than a given value with avl_nearest(). + * + * 2d. Remove individual nodes from the list/tree with avl_remove(). + * + * and finally when the list is being destroyed + * + * 3. Use avl_destroy_nodes() to quickly process/free up any remaining nodes. + * Note that once you use avl_destroy_nodes(), you can no longer + * use any routine except avl_destroy_nodes() and avl_destoy(). + * + * 4. Use avl_destroy() to destroy the AVL tree itself. + * + * Any locking for multiple thread access is up to the user to provide, just + * as is needed for any linked list implementation. + */ + +/* + * Type used for the root of the AVL tree. + */ +typedef struct avl_tree avl_tree_t; + +/* + * The data nodes in the AVL tree must have a field of this type. + */ +typedef struct avl_node avl_node_t; + +/* + * An opaque type used to locate a position in the tree where a node + * would be inserted. + */ +#ifdef MS_VC6 +typedef unsigned int uintptr_t; +typedef uintptr_t avl_index_t; +#elif defined(BORLAND_CB) +typedef unsigned int uintptr_t; +typedef uintptr_t avl_index_t; +#else +typedef uintptr_t avl_index_t; +#endif + +/* + * Direction constants used for avl_nearest(). + */ +#define AVL_BEFORE (0) +#define AVL_AFTER (1) + + +/* + * Prototypes + * + * Where not otherwise mentioned, "void *" arguments are a pointer to the + * user data structure which must contain a field of type avl_node_t. + * + * Also assume the user data structures looks like: + * stuct my_type { + * ... + * avl_node_t my_link; + * ... + * }; + */ + +/* + * Initialize an AVL tree. Arguments are: + * + * tree - the tree to be initialized + * compar - function to compare two nodes, it must return exactly: -1, 0, or +1 + * -1 for <, 0 for ==, and +1 for > + * size - the value of sizeof(struct my_type) + * offset - the value of OFFSETOF(struct my_type, my_link) + */ +ACL_API void avl_create(avl_tree_t *tree, + int (*compar) (const void *, const void *), size_t size, size_t offset); + + +/* + * Find a node with a matching value in the tree. Returns the matching node + * found. If not found, it returns NULL and then if "where" is not NULL it sets + * "where" for use with avl_insert() or avl_nearest(). + * + * node - node that has the value being looked for + * where - position for use with avl_nearest() or avl_insert(), may be NULL + */ +ACL_API void *avl_find(avl_tree_t *tree, void *node, avl_index_t *where); + +/* + * Insert a node into the tree. + * + * node - the node to insert + * where - position as returned from avl_find() + */ +ACL_API void avl_insert(avl_tree_t *tree, void *node, avl_index_t where); + +/* + * Insert "new_data" in "tree" in the given "direction" either after + * or before the data "here". + * + * This might be usefull for avl clients caching recently accessed + * data to avoid doing avl_find() again for insertion. + * + * new_data - new data to insert + * here - existing node in "tree" + * direction - either AVL_AFTER or AVL_BEFORE the data "here". + */ +ACL_API void avl_insert_here(avl_tree_t *tree, void *new_data, void *here, + int direction); + + +/* + * Return the first or last valued node in the tree. Will return NULL + * if the tree is empty. + * + */ +ACL_API void *avl_first(avl_tree_t *tree); +ACL_API void *avl_last(avl_tree_t *tree); + + +/* + * Return the next or previous valued node in the tree. + * AVL_NEXT() will return NULL if at the last node. + * AVL_PREV() will return NULL if at the first node. + * + * node - the node from which the next or previous node is found + */ +#define AVL_NEXT(tree, node) avl_walk(tree, node, AVL_AFTER) +#define AVL_PREV(tree, node) avl_walk(tree, node, AVL_BEFORE) + + +/* + * Find the node with the nearest value either greater or less than + * the value from a previous avl_find(). Returns the node or NULL if + * there isn't a matching one. + * + * where - position as returned from avl_find() + * direction - either AVL_BEFORE or AVL_AFTER + * + * EXAMPLE get the greatest node that is less than a given value: + * + * avl_tree_t *tree; + * struct my_data look_for_value = {....}; + * struct my_data *node; + * struct my_data *less; + * avl_index_t where; + * + * node = avl_find(tree, &look_for_value, &where); + * if (node != NULL) + * less = AVL_PREV(tree, node); + * else + * less = avl_nearest(tree, where, AVL_BEFORE); + */ +ACL_API void *avl_nearest(avl_tree_t *tree, avl_index_t where, int direction); + + +/* + * Add a single node to the tree. + * The node must not be in the tree, and it must not + * compare equal to any other node already in the tree. + * + * node - the node to add + */ +ACL_API void avl_add(avl_tree_t *tree, void *node); + + +/* + * Remove a single node from the tree. The node must be in the tree. + * + * node - the node to remove + */ +ACL_API void avl_remove(avl_tree_t *tree, void *node); + +/* + * Reinsert a node only if its order has changed relative to its nearest + * neighbors. To optimize performance avl_update_lt() checks only the previous + * node and avl_update_gt() checks only the next node. Use avl_update_lt() and + * avl_update_gt() only if you know the direction in which the order of the + * node may change. + */ +ACL_API boolean_t avl_update(avl_tree_t *, void *); +ACL_API boolean_t avl_update_lt(avl_tree_t *, void *); +ACL_API boolean_t avl_update_gt(avl_tree_t *, void *); + +/* + * Return the number of nodes in the tree + */ +ACL_API ulong_t avl_numnodes(avl_tree_t *tree); + +/* + * Return B_TRUE if there are zero nodes in the tree, B_FALSE otherwise. + */ +ACL_API boolean_t avl_is_empty(avl_tree_t *tree); + +/* + * Used to destroy any remaining nodes in a tree. The cookie argument should + * be initialized to NULL before the first call. Returns a node that has been + * removed from the tree and may be free()'d. Returns NULL when the tree is + * empty. + * + * Once you call avl_destroy_nodes(), you can only continuing calling it and + * finally avl_destroy(). No other AVL routines will be valid. + * + * cookie - a "void *" used to save state between calls to avl_destroy_nodes() + * + * EXAMPLE: + * avl_tree_t *tree; + * struct my_data *node; + * void *cookie; + * + * cookie = NULL; + * while ((node = avl_destroy_nodes(tree, &cookie)) != NULL) + * free(node); + * avl_destroy(tree); + */ +ACL_API void *avl_destroy_nodes(avl_tree_t *tree, void **cookie); + + +/* + * Final destroy of an AVL tree. Arguments are: + * + * tree - the empty tree to destroy + */ +ACL_API void avl_destroy(avl_tree_t *tree); + +#ifdef __cplusplus +} +#endif + +#endif /* _AVL_H */ diff --git a/lib_acl/include/stdlib/avl_impl.h b/lib_acl/include/stdlib/avl_impl.h new file mode 100644 index 000000000..276022e90 --- /dev/null +++ b/lib_acl/include/stdlib/avl_impl.h @@ -0,0 +1,187 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _AVL_IMPL_H +#define _AVL_IMPL_H + +/* + * This is a private header file. Applications should not directly include + * this file. + */ +#include "stdlib/acl_define.h" + +#include +#include +#ifdef ACL_UNIX +# include /* uintptr_t */ +# define HAS_UINTPTR +#elif defined(ACL_MS_WINDOWS) +# include +# define HAS_UINTPTR +#endif + +#ifndef HAS_UINTPTR +# define HAS_UINTPTR +# define _UINTPTR_T_DEFINED /* for win32 */ +# ifdef UINTPTR_ULONG_INT +typedef unsigned long int uintptr_t; +# else +typedef unsigned int uintptr_t; +# endif +#endif + +#ifndef SUNOS5 +typedef unsigned int ulong_t; +typedef char boolean_t; +#endif + +#define B_FALSE 0 +#define B_TRUE 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * generic AVL tree implementation for kernel use + * + * There are 5 pieces of information stored for each node in an AVL tree + * + * pointer to less than child + * pointer to greater than child + * a pointer to the parent of this node + * an indication [0/1] of which child I am of my parent + * a "balance" (-1, 0, +1) indicating which child tree is taller + * + * Since they only need 3 bits, the last two fields are packed into the + * bottom bits of the parent pointer on 64 bit machines to save on space. + */ + +#ifndef _LP64 + +struct avl_node { + struct avl_node *avl_child[2]; /* left/right children */ + struct avl_node *avl_parent; /* this node's parent */ + unsigned short avl_child_index; /* my index in parent's avl_child[] */ + short avl_balance; /* balance value: -1, 0, +1 */ +}; + +#define AVL_XPARENT(n) ((n)->avl_parent) +#define AVL_SETPARENT(n, p) ((n)->avl_parent = (p)) + +#define AVL_XCHILD(n) ((n)->avl_child_index) +#define AVL_SETCHILD(n, c) ((n)->avl_child_index = (unsigned short)(c)) + +#define AVL_XBALANCE(n) ((n)->avl_balance) +#define AVL_SETBALANCE(n, b) ((n)->avl_balance = (short)(b)) + +#else /* _LP64 */ + +/* + * for 64 bit machines, avl_pcb contains parent pointer, balance and child_index + * values packed in the following manner: + * + * |63 3| 2 |1 0 | + * |-------------------------------------|-----------------|-------------| + * | avl_parent hi order bits | avl_child_index | avl_balance | + * | | | + 1 | + * |-------------------------------------|-----------------|-------------| + * + */ + +struct avl_node { + struct avl_node *avl_child[2]; /* left/right children nodes */ + uintptr_t avl_pcb; /* parent, child_index, balance */ +}; + +/* + * macros to extract/set fields in avl_pcb + * + * pointer to the parent of the current node is the high order bits + */ +#define AVL_XPARENT(n) ((struct avl_node *)((n)->avl_pcb & ~7)) +#define AVL_SETPARENT(n, p) \ + ((n)->avl_pcb = (((n)->avl_pcb & 7) | (uintptr_t)(p))) + +/* + * index of this node in its parent's avl_child[]: bit #2 + */ +#define AVL_XCHILD(n) (((n)->avl_pcb >> 2) & 1) +#define AVL_SETCHILD(n, c) \ + ((n)->avl_pcb = (uintptr_t)(((n)->avl_pcb & ~4) | ((c) << 2))) + +/* + * balance indication for a node, lowest 2 bits. A valid balance is + * -1, 0, or +1, and is encoded by adding 1 to the value to get the + * unsigned values of 0, 1, 2. + */ +#define AVL_XBALANCE(n) ((int)(((n)->avl_pcb & 3) - 1)) +#define AVL_SETBALANCE(n, b) \ + ((n)->avl_pcb = (uintptr_t)((((n)->avl_pcb & ~3) | ((b) + 1)))) + +#endif /* _LP64 */ + + + +/* + * switch between a node and data pointer for a given tree + * the value of "o" is tree->avl_offset + */ +#define AVL_NODE2DATA(n, o) ((void *)((uintptr_t)(n) - (o))) +#define AVL_DATA2NODE(d, o) ((struct avl_node *)((uintptr_t)(d) + (o))) + +/* + * macros used to create/access an avl_index_t + */ +#define AVL_INDEX2NODE(x) ((avl_node_t *)((x) & ~1)) +#define AVL_INDEX2CHILD(x) ((x) & 1) +#define AVL_MKINDEX(n, c) ((avl_index_t)(n) | (c)) + + +/* + * The tree structure. The fields avl_root, avl_compar, and avl_offset come + * first since they are needed for avl_find(). We want them to fit into + * a single 64 byte cache line to make avl_find() as fast as possible. + */ +struct avl_tree { + struct avl_node *avl_root; /* root node in tree */ + int (*avl_compar)(const void *, const void *); + size_t avl_offset; /* offsetof(type, avl_link_t field) */ + ulong_t avl_numnodes; /* number of nodes in the tree */ + size_t avl_size; /* sizeof user type struct */ +}; + + +/* + * This will only by used via AVL_NEXT() or AVL_PREV() + */ +ACL_API void *avl_walk(struct avl_tree *, void *, int); + +#ifdef __cplusplus +} +#endif + +#endif /* _AVL_IMPL_H */ diff --git a/lib_acl/include/stdlib/unix/acl_chroot_uid.h b/lib_acl/include/stdlib/unix/acl_chroot_uid.h new file mode 100644 index 000000000..183030905 --- /dev/null +++ b/lib_acl/include/stdlib/unix/acl_chroot_uid.h @@ -0,0 +1,22 @@ +#ifndef __ACL_CHROOT_UID_H_INCLUDED__ +#define __ACL_CHROOT_UID_H_INCLUDED__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "../acl_define.h" +#ifdef ACL_UNIX + + /* External interface. */ + +extern void acl_chroot_uid(const char *, const char *); + +#endif /* ACL_UNIX */ + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/include/stdlib/unix/acl_mychown.h b/lib_acl/include/stdlib/unix/acl_mychown.h new file mode 100644 index 000000000..e555a2d05 --- /dev/null +++ b/lib_acl/include/stdlib/unix/acl_mychown.h @@ -0,0 +1,21 @@ +#ifndef __ACL_MYCHOWN_INCLUDE_H__ +#define __ACL_MYCHOWN_INCLUDE_H__ + +#ifdef _cplusplus +extern "C" { +#endif + +#include "../acl_define.h" +#ifdef ACL_UNIX + +int acl_mychown(const char *path, const char *s_owner, const char *s_group); +int acl_myfchown(const int fd, const char *s_owner, const char *s_group); + +#endif /* ACL_UNIX */ + +#ifdef _cplusplus +} +#endif + +#endif + diff --git a/lib_acl/include/stdlib/unix/acl_open_lock.h b/lib_acl/include/stdlib/unix/acl_open_lock.h new file mode 100644 index 000000000..88366bb71 --- /dev/null +++ b/lib_acl/include/stdlib/unix/acl_open_lock.h @@ -0,0 +1,35 @@ + +#ifndef __ACL_OPEN_LOCK_INCLUDE_H__ +#define __ACL_OPEN_LOCK_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "../acl_define.h" + +#ifdef ACL_UNIX + /* + * System library. + */ +#include + + /* + * Utility library. + */ +#include "../acl_vstream.h" +#include "../acl_vstring.h" + + /* + * External interface. + */ +extern ACL_VSTREAM *acl_open_lock(const char *, int, int, ACL_VSTRING *); + +#endif /* ACL_UNIX */ + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/include/stdlib/unix/acl_safe_open.h b/lib_acl/include/stdlib/unix/acl_safe_open.h new file mode 100644 index 000000000..d4c4e7108 --- /dev/null +++ b/lib_acl/include/stdlib/unix/acl_safe_open.h @@ -0,0 +1,37 @@ +#ifndef _SAFE_OPEN_H_INCLUDED_ +#define _SAFE_OPEN_H_INCLUDED_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "../acl_define.h" + +#ifdef ACL_UNIX + + /* + * System library. + */ +#include +#include + + /* + * Utility library. + */ +#include "../acl_vstream.h" +#include "../acl_vstring.h" + + /* + * External interface. + */ +extern ACL_VSTREAM *acl_safe_open(const char *path, int flags, int mode, + struct stat * st, uid_t user, gid_t group, ACL_VSTRING *why); + +#endif /* ACL_UNIX */ + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/include/stdlib/unix/acl_sane_socketpair.h b/lib_acl/include/stdlib/unix/acl_sane_socketpair.h new file mode 100644 index 000000000..4bb0e2720 --- /dev/null +++ b/lib_acl/include/stdlib/unix/acl_sane_socketpair.h @@ -0,0 +1,22 @@ +#ifndef __ACL_SANE_SOCKETPAIR_H__ +#define __ACL_SANE_SOCKETPAIR_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "../acl_define.h" +#ifdef ACL_UNIX + + /* External interface. */ + +int acl_sane_socketpair(int domain, int type, int protocol, int result[2]); + +#endif /* ACL_UNIX */ + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/include/stdlib/unix/acl_set_eugid.h b/lib_acl/include/stdlib/unix/acl_set_eugid.h new file mode 100644 index 000000000..0f8136120 --- /dev/null +++ b/lib_acl/include/stdlib/unix/acl_set_eugid.h @@ -0,0 +1,24 @@ +#ifndef __ACL_SET_EUGID_INCLUDE_H__ +#define __ACL_SET_EUGID_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "../acl_define.h" +#ifdef ACL_UNIX + +#include +#include + +void acl_set_eugid(uid_t euid, gid_t egid); + +#endif /* ACL_UNIX */ + +#ifdef __cplusplus +} +#endif + + +#endif + diff --git a/lib_acl/include/stdlib/unix/acl_set_ugid.h b/lib_acl/include/stdlib/unix/acl_set_ugid.h new file mode 100644 index 000000000..8b44f3024 --- /dev/null +++ b/lib_acl/include/stdlib/unix/acl_set_ugid.h @@ -0,0 +1,25 @@ +#ifndef __ACL_SET_UGID_INCLUDE_H__ +#define __ACL_SET_UGID_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "../acl_define.h" +#ifdef ACL_UNIX + +#include +#include + +void acl_set_ugid(uid_t uid, gid_t gid); +int acl_change_uid(char *user_name); + +#endif /* ACL_UNIX*/ + +#ifdef __cplusplus +} +#endif + + +#endif + diff --git a/lib_acl/include/stdlib/unix/acl_timed_wait.h b/lib_acl/include/stdlib/unix/acl_timed_wait.h new file mode 100644 index 000000000..a871ff433 --- /dev/null +++ b/lib_acl/include/stdlib/unix/acl_timed_wait.h @@ -0,0 +1,24 @@ +#ifndef __ACL_TIMED_WAIT_H_INCLUDED__ +#define __ACL_TIMED_WAIT_H_INCLUDED__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "../acl_define.h" +#ifdef ACL_UNIX +#include +#include + /* + * External interface. + */ +extern int acl_timed_waitpid(pid_t, ACL_WAIT_STATUS_T *, int, int); + +#endif /* ACL_UNIX */ + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/include/stdlib/unix/acl_trace.h b/lib_acl/include/stdlib/unix/acl_trace.h new file mode 100644 index 000000000..8eab46e4b --- /dev/null +++ b/lib_acl/include/stdlib/unix/acl_trace.h @@ -0,0 +1,19 @@ +#ifndef __ACL_TRACE_INCLUDE_H__ +#define __ACL_TRACE_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "../acl_define.h" +#ifdef ACL_UNIX + +void acl_dump_trace(const char *filepath); + +#endif /* ACL_UNIX */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/include/stdlib/unix/acl_transfer_fd.h b/lib_acl/include/stdlib/unix/acl_transfer_fd.h new file mode 100644 index 000000000..a7456b26d --- /dev/null +++ b/lib_acl/include/stdlib/unix/acl_transfer_fd.h @@ -0,0 +1,40 @@ + +#ifndef _ACL_TRANSFER_FD_INCLUDE_ +#define _ACL_TRANSFER_FD_INCLUDE_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "../acl_define.h" + +#ifdef ACL_UNIX + +#include +#include + +#ifdef SUNOS5 +#undef HAVE_MSGHDR_MSG_CONTROL +#else +#define HAVE_MSGHDR_MSG_CONTROL +#endif + +#ifndef CMSG_LEN +#define CMSG_LEN(size) (sizeof(struct cmsghdr) + (size)) +#endif + +#ifndef CMSG_SPACE +#define CMSG_SPACE(size) (sizeof(struct cmsghdr) + (size)) +#endif + +int acl_read_fd(int fd, void *ptr, int nbytes, int *recv_fd); +int acl_write_fd(int fd, void *ptr, int nbytes, int send_fd); + +#endif /* ACL_UNIX */ + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/include/stdlib/unix/acl_unix.h b/lib_acl/include/stdlib/unix/acl_unix.h new file mode 100644 index 000000000..dfc6ff900 --- /dev/null +++ b/lib_acl/include/stdlib/unix/acl_unix.h @@ -0,0 +1,25 @@ +#ifndef __ACL_UNIX_INCLUDE_H__ +#define __ACL_UNIX_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "acl_username.h" +#include "acl_timed_wait.h" +#include "acl_set_ugid.h" +#include "acl_set_eugid.h" +#include "acl_sane_socketpair.h" +#include "acl_mychown.h" +#include "acl_chroot_uid.h" +#include "acl_safe_open.h" +#include "acl_open_lock.h" +#include "acl_transfer_fd.h" +#include "acl_watchdog.h" +#include "acl_trace.h" + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/include/stdlib/unix/acl_username.h b/lib_acl/include/stdlib/unix/acl_username.h new file mode 100644 index 000000000..46e52c419 --- /dev/null +++ b/lib_acl/include/stdlib/unix/acl_username.h @@ -0,0 +1,20 @@ +#ifndef __ACL_USERNAME_INCLUDE_H__ +#define __ACL_USERNAME_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "../acl_define.h" +#ifdef ACL_UNIX + +const char *acl_username(void); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/include/stdlib/unix/acl_watchdog.h b/lib_acl/include/stdlib/unix/acl_watchdog.h new file mode 100644 index 000000000..7aae6d94a --- /dev/null +++ b/lib_acl/include/stdlib/unix/acl_watchdog.h @@ -0,0 +1,30 @@ +#ifndef _WATCHDOG_H_INCLUDED_ +#define _WATCHDOG_H_INCLUDED_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "../acl_define.h" + +#ifdef ACL_UNIX + + /* + * External interface. + */ +typedef struct ACL_WATCHDOG ACL_WATCHDOG; +typedef void (*ACL_WATCHDOG_FN) (ACL_WATCHDOG *, char *); +extern ACL_WATCHDOG *acl_watchdog_create(unsigned, ACL_WATCHDOG_FN, char *); +extern void acl_watchdog_start(ACL_WATCHDOG *); +extern void acl_watchdog_stop(ACL_WATCHDOG *); +extern void acl_watchdog_destroy(ACL_WATCHDOG *); +extern void acl_watchdog_pat(void); + +#endif /* ACL_UNIX*/ + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/include/thread/acl_pthread.h b/lib_acl/include/thread/acl_pthread.h new file mode 100644 index 000000000..6a9c6fb77 --- /dev/null +++ b/lib_acl/include/thread/acl_pthread.h @@ -0,0 +1,193 @@ + +#ifndef __ACL_PTHREAD_WIN32_INCLUDE_H__ +#define __ACL_PTHREAD_WIN32_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_define.h" + +#define ACL_MUTEX_MAXWAIT (~(unsigned int)0) +#ifdef ACL_HAS_PTHREAD + +# include + +typedef pthread_t acl_pthread_t; +typedef pthread_attr_t acl_pthread_attr_t; +typedef pthread_mutex_t acl_pthread_mutex_t; +typedef pthread_cond_t acl_pthread_cond_t; +typedef pthread_mutexattr_t acl_pthread_mutexattr_t; +typedef pthread_condattr_t acl_pthread_condattr_t; +typedef pthread_key_t acl_pthread_key_t; +typedef pthread_once_t acl_pthread_once_t; + +#define acl_pthread_attr_init pthread_attr_init +#define acl_pthread_attr_setstacksize pthread_attr_setstacksize +#define acl_pthread_attr_setdetachstate pthread_attr_setdetachstate +#define acl_pthread_attr_destroy pthread_attr_destroy +#define acl_pthread_self pthread_self +#define acl_pthread_create pthread_create +#define acl_pthread_detach pthread_detach +#define acl_pthread_once pthread_once +#define acl_pthread_join pthread_join +#define acl_pthread_mutex_destroy pthread_mutex_destroy +#define acl_pthread_mutex_init pthread_mutex_init +#define acl_pthread_mutex_lock pthread_mutex_lock +#define acl_pthread_mutex_unlock pthread_mutex_unlock +#define acl_pthread_mutex_trylock pthread_mutex_trylock +#define acl_pthread_cond_init pthread_cond_init +/* #define acl_pthread_cond_create pthread_cond_create */ +#define acl_pthread_cond_destroy pthread_cond_destroy +#define acl_pthread_cond_signal pthread_cond_signal +#define acl_pthread_cond_broadcast pthread_cond_broadcast +#define acl_pthread_cond_timedwait pthread_cond_timedwait +#define acl_pthread_cond_wait pthread_cond_wait +#define acl_pthread_key_create pthread_key_create +#define acl_pthread_getspecific pthread_getspecific +#define acl_pthread_setspecific pthread_setspecific + +#define ACL_PTHREAD_CREATE_DETACHED PTHREAD_CREATE_DETACHED +#define ACL_PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_JOINABLE +#define ACL_TLS_OUT_OF_INDEXES 0xffffffff +#define ACL_PTHREAD_KEYS_MAX PTHREAD_KEYS_MAX +#ifdef ACL_SUNOS5 +# define ACL_PTHREAD_ONCE_INIT { PTHREAD_ONCE_INIT } +#else +# define ACL_PTHREAD_ONCE_INIT PTHREAD_ONCE_INIT +#endif + +#else + +#include + +#include "acl_sem.h" + +#define ACL_PTHREAD_CREATE_DETACHED 1 +#define ACL_PTHREAD_CREATE_JOINABLE 0 +#define ACL_TLS_OUT_OF_INDEXES 0xffffffff +#define ACL_PTHREAD_KEYS_MAX 1024 +#define ACL_PTHREAD_ONCE_INIT 0 + +typedef struct acl_pthread_t acl_pthread_t; +typedef struct acl_pthread_attr_t acl_pthread_attr_t; +typedef struct acl_pthread_mutex_t acl_pthread_mutex_t; +typedef struct acl_pthread_cond_t acl_pthread_cond_t; +typedef struct acl_pthread_mutexattr_t acl_pthread_mutexattr_t; +typedef struct acl_pthread_condattr_t acl_pthread_condattr_t; +typedef int acl_pthread_key_t; +typedef int acl_pthread_once_t; + +struct acl_pthread_t { + unsigned long id; + HANDLE handle; + void *(*start_routine)(void *); + void *routine_arg; + char detached; +}; + +struct acl_pthread_attr_t { + SECURITY_ATTRIBUTES attr; + size_t stacksize; + char detached; +}; + +struct acl_pthread_mutex_t { + HANDLE id; + char dynamic; +}; + +struct acl_pthread_mutexattr_t { + SECURITY_ATTRIBUTES attr; +}; + +struct acl_pthread_cond_t { + acl_pthread_mutex_t *lock; + int waiting; + int signals; + ACL_SEM *wait_sem; + ACL_SEM *wait_done; + char dynamic; +}; + +struct acl_pthread_condattr_t { + char unused_name[1]; +}; + +struct timespec { + time_t tv_sec; /* Seconds. */ + long int tv_nsec; /* Nanoseconds. */ +#if 0 + long int tv_msec; /* millisecond, add by zsx */ +#endif +}; + +/* in acl_pthread.c */ +ACL_API void acl_pthread_end(void); +ACL_API int acl_pthread_once(acl_pthread_once_t *once_control, void (*init_routine)(void)); +ACL_API int acl_pthread_key_create(acl_pthread_key_t *key_ptr, void (*destructor)(void*)); +ACL_API void *acl_pthread_getspecific(acl_pthread_key_t key); +ACL_API int acl_pthread_setspecific(acl_pthread_key_t key, void *value); +ACL_API int acl_pthread_attr_init(acl_pthread_attr_t *attr); +ACL_API int acl_pthread_attr_setstacksize(acl_pthread_attr_t *attr, size_t stacksize); +ACL_API int acl_pthread_attr_setdetachstate(acl_pthread_attr_t *attr, int detached); +ACL_API int acl_pthread_attr_destroy(acl_pthread_attr_t *thr_attr); +ACL_API unsigned long acl_pthread_self(void); +ACL_API int acl_pthread_create(acl_pthread_t *thread, + acl_pthread_attr_t *attr, + void * (*start_routine)(void *), + void *arg); +ACL_API int acl_pthread_detach(acl_pthread_t thread); +ACL_API int acl_pthread_join(acl_pthread_t thread, void **thread_return); + +/* in acl_pthread_mutex.c */ +ACL_API int acl_pthread_mutex_destroy(acl_pthread_mutex_t *mutex); +ACL_API int acl_pthread_mutex_init(acl_pthread_mutex_t *mutex, const acl_pthread_mutexattr_t *mattr); +ACL_API int acl_pthread_mutex_lock(acl_pthread_mutex_t *mutex); +ACL_API int acl_pthread_mutex_unlock(acl_pthread_mutex_t *mutex); + +#define acl_pthread_mutex_trylock acl_pthread_mutex_lock + +/* in acl_pthread_cond.c */ +ACL_API int acl_pthread_cond_init(acl_pthread_cond_t *cond, acl_pthread_condattr_t *cond_attr); +ACL_API acl_pthread_cond_t * acl_pthread_cond_create(void); +ACL_API int acl_pthread_cond_destroy(acl_pthread_cond_t *cond); +ACL_API int acl_pthread_cond_signal(acl_pthread_cond_t *cond); +ACL_API int acl_pthread_cond_broadcast(acl_pthread_cond_t *cond); +ACL_API int acl_pthread_cond_timedwait(acl_pthread_cond_t *cond, acl_pthread_mutex_t *mutex, + const struct timespec *timeout); +ACL_API int acl_pthread_cond_wait(acl_pthread_cond_t *cond, acl_pthread_mutex_t *mutex); + +#endif /* !ACL_HAS_PTHREAD */ + +/* general functions */ + +/* in acl_pthread_mutex.c */ +ACL_API int acl_thread_mutex_lock(acl_pthread_mutex_t *mutex); +ACL_API int acl_thread_mutex_unlock(acl_pthread_mutex_t *mutex); +ACL_API int acl_thread_mutex_nested(acl_pthread_mutex_t *mutex); + +/* in acl_pthread_mutex.c */ +ACL_API acl_pthread_mutex_t *acl_pthread_mutex_create(void); + +/* in acl_pthread.c */ +ACL_API int acl_pthread_atexit_add(void *arg, void (*free_callback)(void*)); +ACL_API int acl_pthread_atexit_remove(void *arg, void (*free_callback)(void*)); +ACL_API int acl_pthread_tls_set_max(int max); +ACL_API int acl_pthread_tls_get_max(void); +ACL_API void *acl_pthread_tls_get(acl_pthread_key_t *key_ptr); +ACL_API int acl_pthread_tls_set(acl_pthread_key_t key, void *ptr, void (*free_fn)(void *)); +ACL_API int acl_pthread_tls_del(acl_pthread_key_t key); +ACL_API void acl_pthread_tls_once_get(acl_pthread_once_t *control_once); +ACL_API void acl_pthread_tls_once_set(acl_pthread_once_t control_once); +ACL_API acl_pthread_key_t acl_pthread_tls_key_get(void); +ACL_API void acl_pthread_tls_key_set(acl_pthread_key_t key); + +/* in acl_pthread_cond.c */ +ACL_API acl_pthread_cond_t * acl_pthread_cond_create(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/include/thread/acl_pthread_pool.h b/lib_acl/include/thread/acl_pthread_pool.h new file mode 100644 index 000000000..93d77586f --- /dev/null +++ b/lib_acl/include/thread/acl_pthread_pool.h @@ -0,0 +1,203 @@ + +#ifndef __ACL_PTHREAD_POOL_H_INCLUDED__ +#define __ACL_PTHREAD_POOL_H_INCLUDED__ + +#include "stdlib/acl_define.h" +#include + +#ifdef ACL_UNIX +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * 线程池对象结构类型定义 + */ +typedef struct acl_pthread_pool_t acl_pthread_pool_t; + +/** + * 线程池对象属性的结构类型定义 + */ +typedef struct acl_pthread_pool_attr_t { + int threads_limit; /**< 线程池最大线程数限制 */ +#define ACL_PTHREAD_POOL_DEF_THREADS 100 /**< 缺省最大值为 100 个线程 */ + int idle_timeout; /**< 工作线程空闲超时时间(秒) */ +#define ACL_PTHREAD_POOL_DEF_IDLE 60 /**< 缺省空间超时时间为 60 秒 */ + size_t stack_size; /**< 工作线程的堆栈大小(字节) */ +} acl_pthread_pool_attr_t; + +/** + * 更简单地创建线程对象的方法 + * @param threads_limit {int} 线程池中最大并发线程数 + * @param idle_timeout {int} 工作线程空闲超时退出时间(秒) + * @return {acl_pthread_pool_t*}, 如果不为空则表示成功,否则失败 + */ +ACL_API acl_pthread_pool_t *acl_thread_pool_create(int threads_limit, int idle_timeout); + +/** + * 创建一个线程池对象 + * @param attr {acl_pthread_pool_attr_t*} 线程池创建时的属性,如果该参数为空, + * 则采用默认参数: ACL_PTHREAD_POOL_DEF_XXX + * @return {acl_pthread_pool_t*}, 如果不为空则表示成功,否则失败 + */ +ACL_API acl_pthread_pool_t *acl_pthread_pool_create(const acl_pthread_pool_attr_t *attr); + +/** + * 当队列堆积的任务数大于空闲线程数的2倍时. 通过此函数设置添加任务的 + * 线程休眠时间, 如果不调用此函数进行设置, 则添加线程不会进入休眠状态. + * @param thr_pool {acl_pthread_pool_t*} 线程池对象,不能为空 + * @param timewait_sec {int} 休眠 的时间值, 建议将此值设置为 1--5 秒内 + * @return {int} 成功返回 0, 失败返回 -1 + */ +ACL_API int acl_pthread_pool_set_timewait(acl_pthread_pool_t *thr_pool, int timewait_sec); + +/** + * 添加注册函数,在线程创建后立即执行此初始化函数 + * @param thr_pool {acl_pthread_pool_t*} 线程池对象,不能为空 + * @param init_fn {int (*)(void*)} 工作线程初始化函数, 如果该函数返回 < 0, + * 则该线程自动退出。 + * @param init_arg {void*} init_fn 所需要的参数 + * @return {int} 0: OK; != 0: Error. + */ +ACL_API int acl_pthread_pool_atinit(acl_pthread_pool_t *thr_pool, + int (*init_fn)(void *), void *init_arg); + +/** + * 添加注册函数,在线程退出立即执行此初函数 + * @param thr_pool {acl_pthread_pool_t*} 线程池对象,不能为空 + * @param free_fn {void (*)(void*)} 工作线程退出前必须执行的函数 + * @param free_arg {void*} free_fn 所需要的参数 + * @return {int} 0: OK; != 0: Error. + */ +ACL_API int acl_pthread_pool_atfree(acl_pthread_pool_t *thr_pool, + void (*free_fn)(void *), void *free_arg); + +/** + * 销毁一个线程池对象, 成功销毁后该对象不能再用. + * @param thr_pool {acl_pthread_pool_t*} 线程池对象,不能为空 + * @return {int} 0: 成功; != 0: 失败 + */ +ACL_API int acl_pthread_pool_destroy(acl_pthread_pool_t *thr_pool); + +/** + * 暂停一个线程池对象的运行, 停止后还可以再运行. + * @param thr_pool {acl_pthread_pool_t*} 线程池对象,不能为空 + * @return {int} 0: 成功; != 0: 失败 + */ +ACL_API int acl_pthread_pool_stop(acl_pthread_pool_t *thr_pool); + +/** + * 向线程池添加一个任务 + * @param thr_pool {acl_pthread_pool_t*} 线程池对象,不能为空 + * @param run_fn {void (*)(*)} 当有可用工作线程时所调用的回调处理函数 + * @param run_arg {void*} 回调函数 run_fn 所需要的回调参数 + * @return {int} 0: 成功; != 0: 失败 + */ +ACL_API int acl_pthread_pool_add(acl_pthread_pool_t *thr_pool, + void (*run_fn)(void *), void *run_arg); + +/** + * 开始进行批处理方式的添加任务, 实际上是开始进行加锁 + * @param thr_pool {acl_pthread_pool_t*} 线程池对象,不能为空 + */ +ACL_API void acl_pthread_pool_add_begin(acl_pthread_pool_t *thr_pool); + +/** + * 添加一个新任务, 前提是已经成功加锁, 即调用acl_pthread_pool_add_begin 成功 + * @param thr_pool {acl_pthread_pool_t*} 线程池对象,不能为空 + * @param run_fn {void (*)(void*)} 当有可用工作线程时所调用的回调处理函数 + * @param run_arg 回调函数 run_fn 所需要的回调参数 + */ +ACL_API void acl_pthread_pool_add_one(acl_pthread_pool_t *thr_pool, + void (*run_fn)(void *), void *run_arg); +/** + * 批处理添加结束, 实际是解锁 + * @param thr_pool {acl_pthread_pool_t*} 线程池对象,不能为空 + */ +ACL_API void acl_pthread_pool_add_end(acl_pthread_pool_t *thr_pool); + +/** + * 设置线程池 POLLER 调度函数,若要使用此功能,需要在用函数 + * acl_pthread_pool_create 后通过此函数设置调度函数,然后再 + * 调用 acl_pthread_pool_start_poller 启动后台调度函数,该后台 + * 调度函数会不断地调用 poller_fn (即用户的回调函数),用户可以 + * 在回调函数里调用 acl_pthread_pool_add 将新任务添加进线程池中 + * @param thr_pool {acl_pthread_pool_t*} 线程池对象,不能为空 + * @param poller_fn {int (*)(void*)} 循环检测任务队列的回调函数 + * @param poller_arg {void*} poller_fn 所需要的参数 + */ +ACL_API void acl_pthread_pool_set_poller(acl_pthread_pool_t *thr_pool, + int (*poller_fn)(void *), void *poller_arg); +/** + * 启动一个线程池 POLLER 调度线程 + * @param thr_pool {acl_pthread_pool_t*} 线程池对象,不能为空 + * @return 0 成功; != 0 失败, 可以对返回值调用 strerror(ret) 取得错误原因描述 + */ +ACL_API int acl_pthread_pool_start_poller(acl_pthread_pool_t *thr_pool); + +/** + * 以批处理方式进行任务的分发, 其内部其实是调用了 acl_pthread_pool_add_one() + * @return 0: OK; -1: err + */ +ACL_API int acl_pthread_pool_add_dispatch(void *dispatch_arg, + void (*run_fn)(void *), void *run_arg); + +/** + * 以单个添加的方式进行任务的分发 + * @return 0: OK; -1: err + * 注:worker_fn 中的第二个参数为ACL_WORKER_ATTR结构指针,由线程池的某个 + * 工作线程维护,该结构指针中的成员变量 init_data 为用户的赋值传送变量, + * 如:数据库连接对象等。 + */ +ACL_API int acl_pthread_pool_dispatch(void *dispatch_arg, + void (*run_fn)(void *), void *run_arg); + +/** + * 当前线程池中的线程数 + * @param thr_pool {acl_pthread_pool_t*} 线程池对象,不能为空 + * @return {int} 返回线程池中的总线程数 + */ +ACL_API int acl_pthread_pool_size(acl_pthread_pool_t *thr_pool); + +/** + * 设置线程池中线程的堆栈大小 + * @param thr_pool {acl_pthread_pool_t*} 线程池对象,不能为空 + * @param size {size_t} 线程创建时的堆栈大小,单位为字节 + */ +ACL_API void acl_pthread_pool_set_stacksize(acl_pthread_pool_t *thr_pool, size_t size); + +/** + * 初始化线程池属性值 + * @param attr {acl_pthread_pool_attr_t*} + */ +ACL_API void acl_pthread_pool_attr_init(acl_pthread_pool_attr_t *attr); + +/** + * 设置线程池属性中的最大堆栈大小(字节) + * @param attr {acl_pthread_pool_attr_t*} + * @param size {size_t} + */ +ACL_API void acl_pthread_pool_attr_set_stacksize(acl_pthread_pool_attr_t *attr, size_t size); + +/** + * 设置线程池属性中的最大线程数限制值 + * @param attr {acl_pthread_pool_attr_t*} + * @param threads_limit {int} 线程池中的最大线程数 + */ +ACL_API void acl_pthread_pool_attr_set_threads_limit(acl_pthread_pool_attr_t *attr, int threads_limit); + +/** + * 设置线程池属性中线程空闲超时值 + * @param attr {acl_pthread_pool_attr_t*} + * @param idle_timeout {int} 线程空闲超时时间(秒) + */ +ACL_API void acl_pthread_pool_attr_set_idle_timeout(acl_pthread_pool_attr_t *attr, int idle_timeout); + +#ifdef __cplusplus +} +#endif + +#endif /* !__acl_pthread_pool_t_H_INCLUDED__ */ diff --git a/lib_acl/include/thread/acl_pthread_rwlock.h b/lib_acl/include/thread/acl_pthread_rwlock.h new file mode 100644 index 000000000..ed30c3918 --- /dev/null +++ b/lib_acl/include/thread/acl_pthread_rwlock.h @@ -0,0 +1,106 @@ +/* +Copyright (C) 1999, 2000 Igor Khasilev, igor@paco.net +Copyright (C) 2000 Andrey Igoshin, ai@vsu.ru + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +/*- + * Copyright (c) 1998 Alex Nash + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef __ACL_PTHREAD_RWLOCK__ +#define __ACL_PTHREAD_RWLOCK__ + +#include "stdlib/acl_define.h" +#include "thread/acl_pthread.h" +#ifdef ACL_MS_WINDOWS +# define ACL_HAVE_NO_RWLOCK +#endif + +#ifdef ACL_HAVE_NO_RWLOCK + +#if !defined(ACL_PTHREAD_PROCESS_PRIVATE) +#define ACL_PTHREAD_PROCESS_PRIVATE 0 +#endif +#if !defined(ACL_PTHREAD_PROCESS_SHARED) +#define ACL_PTHREAD_PROCESS_SHARED 1 +#endif + +#if !defined(ACL_PTHREAD_RWLOCK_INITIALIZER) +#define ACL_PTHREAD_RWLOCK_INITIALIZER NULL + +struct acl_pthread_rwlock { + acl_pthread_mutex_t lock; /* monitor lock acl_pthread_mutex_t */ + int state; /* 0 = idle >0 = # of readers -1 = writer */ + acl_pthread_cond_t read_signal; + acl_pthread_cond_t write_signal; + int blocked_writers; +}; + +struct acl_pthread_rwlockattr { + int pshared; +}; + +typedef struct acl_pthread_rwlock *acl_pthread_rwlock_t; +typedef struct acl_pthread_rwlockattr *acl_pthread_rwlockattr_t; + +#if defined(__cplusplus) +extern "C" { +#endif + +int acl_pthread_rwlock_destroy (acl_pthread_rwlock_t *); +int acl_pthread_rwlock_init (acl_pthread_rwlock_t *, const acl_pthread_rwlockattr_t *); +int acl_pthread_rwlock_rdlock (acl_pthread_rwlock_t *); +int acl_pthread_rwlock_tryrdlock (acl_pthread_rwlock_t *); +int acl_pthread_rwlock_trywrlock (acl_pthread_rwlock_t *); +int acl_pthread_rwlock_unlock (acl_pthread_rwlock_t *); +int acl_pthread_rwlock_wrlock (acl_pthread_rwlock_t *); +int acl_pthread_rwlockattr_init (acl_pthread_rwlockattr_t *); +int acl_pthread_rwlockattr_getpshared (const acl_pthread_rwlockattr_t *, int *); +int acl_pthread_rwlockattr_setpshared (acl_pthread_rwlockattr_t *, int); +int acl_pthread_rwlockattr_destroy (acl_pthread_rwlockattr_t *); + +#if defined(__cplusplus) +} +#endif + +#endif + +#endif /* ACL_HAVE_NO_RWLOCK */ +#endif /* __ACl_THREAD_RWLOCK__ */ diff --git a/lib_acl/include/thread/acl_sem.h b/lib_acl/include/thread/acl_sem.h new file mode 100644 index 000000000..b4dc57199 --- /dev/null +++ b/lib_acl/include/thread/acl_sem.h @@ -0,0 +1,33 @@ + +#ifndef __ACL_SEM_INCLUDE_H__ +#define __ACL_SEM_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif +#include "stdlib/acl_define.h" + +#ifdef ACL_MS_WINDOWS + +typedef struct ACL_SEM ACL_SEM; +struct ACL_SEM { + HANDLE id; + unsigned int volatile count; +}; + +ACL_API ACL_SEM *acl_sem_create2(const char *pathname, unsigned int initial_value); +ACL_API ACL_SEM *acl_sem_create(unsigned int initial_value); +ACL_API void acl_sem_destroy(ACL_SEM *sem); +ACL_API int acl_sem_wait_timeout(ACL_SEM *sem, unsigned int timeout); +ACL_API int acl_sem_try_wait(ACL_SEM *sem); +ACL_API int acl_sem_wait(ACL_SEM *sem); +ACL_API unsigned int acl_sem_value(ACL_SEM *sem); +ACL_API int acl_sem_post(ACL_SEM *sem); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/include/thread/acl_thread.h b/lib_acl/include/thread/acl_thread.h new file mode 100644 index 000000000..2384549d2 --- /dev/null +++ b/lib_acl/include/thread/acl_thread.h @@ -0,0 +1,18 @@ + +#ifndef __ACL_THREAD_INCLUDE_H__ +#define __ACL_THREAD_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "acl_pthread.h" +#include "acl_pthread_rwlock.h" +#include "acl_pthread_pool.h" +#include "acl_sem.h" + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/include/unit_test/acl_test_global.h b/lib_acl/include/unit_test/acl_test_global.h new file mode 100644 index 000000000..cf33a6faf --- /dev/null +++ b/lib_acl/include/unit_test/acl_test_global.h @@ -0,0 +1,240 @@ +#ifndef __ACL_TEST_GLOBAL_INCLUDE_H_ +#define __ACL_TEST_GLOBAL_INCLUDE_H_ + +# ifdef __plusplus +extern "C" { +# endif + +#include "stdlib/acl_define.h" +#include "stdlib/acl_loadcfg.h" +#include "stdlib/acl_array.h" + +#include "acl_test_struct.h" + +/*----------------------- 内部函数接口 -----------------------------------*/ +/* in acl_test_cfg.c */ +ACL_API ACL_ARRAY *aut_parse_args_list(const char *str_in); +ACL_API void aut_free_args_list(ACL_ARRAY *a); + +/* in acl_test_cfg_general.c */ +ACL_API int aut_cfg_add_general_line(const ACL_CFG_LINE *line); + +/* in acl_test_inner.c*/ +ACL_API AUT_LINE *aut_add_inner_cmd(const ACL_CFG_LINE *line); + +/* in acl_test_outer.c */ +ACL_API AUT_LINE *aut_add_outer_cmd(const ACL_CFG_LINE *line); + +/* in acl_test_token.c */ +ACL_API AUT_CMD_TOKEN *aut_line_peer_token(const AUT_LINE *test_line); +ACL_API AUT_LINE *aut_line_peer(const AUT_LINE *test_line); + +/* in acl_test_misc.c */ +ACL_API void aut_line_free(void *ctx); + +/*------------------ 外部可以调用的一些函数接口 ----------------------------*/ + +/* in acl_test_cfg.c */ + +/** + * 功能: 读取配置文件 + * @param pathname 配置文件名 + * @return 0 表示成功, -1 表示失败 + */ +ACL_API int aut_cfg_parse(const char *pathname); + +/** + * 功能: 打印所有有效的配置行内容 + * @return 成功: 0, 失败: -1 + */ +ACL_API int aut_cfg_print(void); + +/* in acl_test_misc.c */ + +ACL_API AUT_LINE *aut_line_new(const ACL_CFG_LINE *cfg_line); + +/** + * 功能: 获得对应于命令字的配置参数集合的容器, 以动态数组表示 + * @param cmd_name 命令字 + * @return 成功: 非空指针, 失败: 空指针 + */ +ACL_API const ACL_ARRAY *aut_args_get(const char *cmd_name); + +/** + * 功能: 获得有效配置项的总条目 + * @return 成功: >0, 失败: -1 + */ +ACL_API int aut_size(void); + +/** + * 功能: 根据下标值取出所对应的有效配置行结构指针 + * @param idx 下标索引值 + * @return 成功: 非空结构指针, 失败: 空指针 + * + */ +ACL_API AUT_LINE *aut_index(int idx); + +/** + * 功能: 比较所给的命令是否与 test_line 中所记录的命令相同 + * @param test_line: 与某一有效配置行相关的结构指针 + * @param cmd_name: 待查询的命令 + * @return 如果相等则返回 0, 如果不等则返回非 0 + */ +ACL_API int aut_line_cmdcmp(const AUT_LINE *test_line, const char *cmd_name); + +/** + * 功能: 比较所给的执行结果值是否与配置文件中所期望的结果值相等 + * @param test_line: 与某一有效配置行相关的结构指针 + * @param result: 程序某个任务函数的执行结果值 + * @return 相等则返回 0, 不相等则返回非 0 + */ +ACL_API int aut_line_resultcmp(const AUT_LINE *test_line, int result); + +/** + * 功能: 取得该有效配置行在配置文件中的行号位置 + * @param test_line: 与某一有效配置行相关的结构指针 + * @return 成功: >=0, 该值即为行号, 失败: < 0 + */ +ACL_API int aut_line_number(const AUT_LINE *test_line); + +/** + * 功能: 取得所给命令行的有效行号 + * @param test_line: 与某一有效配置行相关的结构指针 + * @return 成功: >=0, 该值即为行号, 失败: < 0 + */ +ACL_API int aut_line_valid_linenum(const AUT_LINE *test_line); + +/** + * 功能: 获得该配置行的命令字 + * @param test_line: 与某一有效配置行相关的结构指针 + * @return 相等返回 0, 不等则返回非 0 + */ +ACL_API const char *aut_line_cmdname(const AUT_LINE *test_line); + +/** + * 功能: 返回该配置行中参数的个数 + * @param test_line: 与某一有效配置行相关的结构指针 + * @return 成功: >= 0, 失败: -1 + */ +ACL_API int aut_line_argc(const AUT_LINE *test_line); + +/** + * 功能: 读取配置文件行中的参数值 + * @param test_line AUT_LINE 结构指针 + * @param name 要查找的关建字 + * @return 成功: 非空指针, 失败: 空指针 + */ +ACL_API const char *aut_line_getvalue(const AUT_LINE *test_line, const char *name); + +/** + * 功能: 返回该配置行的内容 + * @param test_line: 与某一有效配置行相关的结构指针 + * @return 成功: 非空指针, 失败: 空指针 + */ +ACL_API const char *aut_line_argstr(const AUT_LINE *test_line); + +/** + * 功能: 返回该配置行中期望的执行结果值 + * @param test_line: 与某一有效配置行相关的结构指针 + * @return 期望的执行结果值 + * 说明: 没有出错的情况, 如果传入的参数非法则返回 -1, 但无法区分该 -1 值是 + * 非法值还是期望的执行结果值 + */ +ACL_API int aut_line_result(const AUT_LINE *test_line); + +/** + * 功能: 是否遇到了配置行中的结束字段 + * @param test_line: 与某一有效配置行相关的结构指针 + * @return 是: 1, 否: 0 + */ +ACL_API int aut_line_stop(const AUT_LINE *test_line); + +/** + * 功能: 内部保留字段, 遇到此内部保留配置行则需要跳过 + * @param test_line: 与某一有效配置行相关的结构指针 + * @return 是: 1, 否: 0 + */ +ACL_API int aut_line_reserved(AUT_LINE *test_line); + +/** + * 功能: 调用者可以把自己的参数添加到 test_line 之中 + * @param test_line: 与某一有效配置行相关的结构指针 + * @param arg: 用户要添加的参数 + * @return 成功: 0, 失败: -1 + */ +ACL_API int aut_line_add_arg(AUT_LINE *test_line, void *arg); + +/** + * 功能: 从 test_line 删除用户自己的参数 + * @param test_line: 与某一有效配置行相关的结构指针 + * @param free_fn: 用户自己的析构函数 + */ +ACL_API void aut_line_del_arg(AUT_LINE *test_line, void (*free_fn) (void *)); + +/** + * 功能: 从 test_line 中取出用户自己的参数 + * @param test_line: 与某一有效配置行相关的结构指针 + * @return 成功: 非空指针, 如果返回指针为空则有可能是内部错误或本来就是空 + */ +ACL_API void *aut_line_get_arg(const AUT_LINE *test_line); + +/** + * 功能: 取得所给命令行的结尾行 + * @param start_linenum 命令开始执行点所在行号 + * @return >= 0 ok; < 0 未找到 + */ +ACL_API int aut_end_linenum(int start_linenum); + +/** + * 功能: 从当前所提供的 test_line 起, 一直向下找到某个与所提供标志位相同的 + * test_line. + * @param test_line: 与某一有效配置行相关的结构指针 + * @param flag: defined as AUT_FLAG_ in acl_test_struct.h + * @return != NULL, ok find it; == NULL, not found. + */ +ACL_API const AUT_LINE *aut_lookup_from_line(const AUT_LINE *test_line, int flag); + +/* in acl_test_runner.c */ + +/** + * 功能 执行所有注册的测试函数, 如果有任何一个任务执行的结果与预期结果不一致则退 + * 出执行 + * @return 成功: 0, 失败: -1 + */ +ACL_API int aut_start(void); + +/** + * 测试过程结束后需要调用此函数以释放一些内存资源 + */ +ACL_API void aut_stop(void); + +/** + * 功能 将需要进行单元测试的任务函数注册 + * @param test_fn_tab 单元测试函数结构数组 + */ +ACL_API void aut_register(const AUT_FN_ITEM test_fn_tab[]); + +/* in acl_test_loop.c */ +ACL_API AUT_LINE *aut_loop_make_begin(const ACL_CFG_LINE *cfg_line); +ACL_API AUT_LINE *aut_loop_make_break(const ACL_CFG_LINE *cfg_line); +ACL_API AUT_LINE *aut_loop_make_end(const ACL_CFG_LINE *cfg_line); +ACL_API const AUT_LINE *aut_loop_end(const AUT_LINE *test_begin); +ACL_API int aut_loop_count(const AUT_LINE *test_line); +ACL_API int aut_loop_from(const AUT_LINE *test_line); +ACL_API int aut_loop_to(const AUT_LINE *test_line); + +/* in acl_test_log.c */ + +ACL_API int aut_log_open(const char *pathname); +ACL_API void aut_log_info(const char *format, ...); +ACL_API void aut_log_warn(const char *format, ...); +ACL_API void aut_log_error(const char *format, ...); +ACL_API void aut_log_fatal(const char *format, ...); +ACL_API void aut_log_panic(const char *format, ...); + +# ifdef __plusplus +} +# endif + +#endif + diff --git a/lib_acl/include/unit_test/acl_test_macro.h b/lib_acl/include/unit_test/acl_test_macro.h new file mode 100644 index 000000000..89129d787 --- /dev/null +++ b/lib_acl/include/unit_test/acl_test_macro.h @@ -0,0 +1,44 @@ + +#ifndef __ACL_TEST_MACRO_INCLUDE_H__ +#define __ACL_TEST_MACRO_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#define AUT_SET_STR(__test_line__, __name__, __value__) do { \ + __value__ = aut_line_getvalue(__test_line__, __name__); \ + if (__value__ == NULL) { \ + printf("%s(%d): getvalue error for %s, line=%d\n", \ + __FILE__, __LINE__, \ + __name__, aut_line_number(__test_line__)); \ + return (-1); \ + } \ +} while (0) + +#define AUT_SET_INT(__test_line__, __name__, __value__) do { \ + const char *__ptr__; \ + __ptr__ = aut_line_getvalue(__test_line__, __name__); \ + if (__ptr__ == NULL) { \ + printf("%s(%d): getvalue error for %s, line=%d\n", \ + __FILE__, __LINE__, \ + __name__, aut_line_number(__test_line__)); \ + return (-1); \ + } \ + __value__ = atoi(__ptr__); \ +} while (0) + +#define AUT_RETURN_ERROR(__test_line__) do { \ + printf("%s(%d): %s error, line=%d\n", \ + __FILE__, __LINE__, \ + aut_line_cmdname(__test_line__), \ + aut_line_number(__test_line__)); \ + return (-1); \ +} while (0) + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/include/unit_test/acl_test_struct.h b/lib_acl/include/unit_test/acl_test_struct.h new file mode 100644 index 000000000..05c2614fb --- /dev/null +++ b/lib_acl/include/unit_test/acl_test_struct.h @@ -0,0 +1,141 @@ +#ifndef __ACL_TEST_STRUCT_INCLUDE_H__ +#define __ACL_TEST_STRUCT_INCLUDE_H__ + +# ifdef __cplusplus +extern "C" { +# endif + +#include "stdlib/acl_array.h" + +typedef struct AUT_LINE { + char cmd_name[128]; /* 命令函数名称 */ + int result; /* 执行结果 */ + int argc; /* 参数个数 */ + ACL_ARRAY *argv; /* 参数列表 */ + char *args_str; /* 参数列表的备份 */ + int valid_line_idx; /* 该有效配置行在所有有效配置行中的行号 */ + int line_number; /* 该有效配置行在配置文件中的行号 */ + void *arg_inner; /* 内部注册自己的参数到该结构中 */ + void (*free_arg_inner)(void*); + void *arg_outer; /* 外部应用注册自己的参数到该结构中 */ + int obj_type; /* 是内部命令对象还是外部命令对象标志位, + * defined as: AUT_OBJ_ + */ +} AUT_LINE; + +typedef int (*AUT_FN) (AUT_LINE *test_line, void *arg); + +/** + * 说明: 单元测试所采用的一致的数据结构 + */ +typedef struct AUT_FN_ITEM { + const char *cmd_name; /* 命令字名称 */ + const char *fn_name; /* 函数名称 */ + AUT_FN fn_callback; /* 测试用回调函数 */ + void *arg; /* 测试回调函数所用的参数 */ + int inner; /* 是否是内部的命令 */ +} AUT_FN_ITEM; + +/* 内部数据结构定义 */ +typedef struct { + char *name; + char *value; +} AUT_ARG_ITEM; + +typedef struct { + int match_number; /* 成对命令中相互间的匹配号, + * 例如: loop_begin 与 loop_end 之间 + * 对非成对的命令项无效, 如对: + * stop 命令项. + */ + AUT_LINE *peer; /* 与该有效配置行成对的另一个对象 */ + int flag; /* define as: AUT_FLAG_ */ + int status; /* define as: AUT_STAT_ */ + int valid_line_idx; /* 在所有有效配置行中的下标位置 */ + + /* 私有类型定义如下 */ + /* 针对循环执行命令序列 */ + int nloop_max; /* 最大循环次数, 由配置文件中获得 */ + int nloop_cur; /* 当前循环的次数 */ + int offset_valid_line_idx; /* 相对有效配置行下标索引 */ + int loop_sleep; /* 循环执行时的休息 */ +} AUT_CMD_TOKEN; + +#define AUT_OBJ_OUTER 0 /* 默认为外部命令对象 */ +#define AUT_OBJ_INNER 1 /* 为内部对象 */ + +#define AUT_FLAG_LOOP_BEGIN 1 +#define AUT_FLAG_LOOP_BREAK 2 +#define AUT_FLAG_LOOP_CONTINUE 3 +#define AUT_FLAG_LOOP_END 4 + +#define AUT_FLAG_IF 5 +#define AUT_FLAG_ELSE 6 +#define AUT_FLAG_ELIF 7 +#define AUT_FLAG_ENDIF 8 + +#define AUT_FLAG_STOP 9 + +#define AUT_STAT_FREE 0 +#define AUT_STAT_BUSY 1 + + +#define AUT_LOOP_BREAK -100 + +#define VAR_AUT_LOG_PRINT 0x0001 +#define VAR_AUT_LOG_FPRINT 0x0010 + +/* 配置文件中的关键字 */ +/* 日志记录级别 */ +#define VAR_AUT_LOG "LOG" + +/* 执行停止标志位 */ +#define VAR_AUT_STOP "STOP" + +/* 休息标志位 */ +#define VAR_AUT_SLEEP "SLEEP" + +/* 暂停标志位 */ +#define VAR_AUT_PAUSE "PAUSE" + +/* 循环执行开始标志位 */ +#define VAR_AUT_LOOP_BEGIN "LOOP_BEGIN" + +/* 循环执行停止标志位 */ +#define VAR_AUT_LOOP_END "LOOP_END" + +/* 跳出循环执行 */ +#define VAR_AUT_LOOP_BREAK "LOOP_BREAK" + +/* 循环继续 */ +#define VAR_AUT_LOOP_CONTINUE "LOOP_CONTINUE" + +/* 条件判断开始语句 */ +#define VAR_AUT_IF "IF" + +/* 条件判断 else 语句 */ +#define VAR_AUT_ELSE "ELSE" + +/* 条件判断结束语句 */ +#define VAR_AUT_ENDIF "ENDIF" + +/* 跳转执行语句 */ +#define VAR_AUT_GOTO "GOTO" + +/*----------------- 内部保留的一些配置文件参数 -----------------------------*/ +/** + * 通用的整数值参数名变量: + * + * 对于 VAR_AUT_SLEEP 则表示为休息的秒数值; + * 对于 VAR_AUT_LOOP_BEGIN 则表示循环的次数 + */ + +#define VAR_AUT_ITEM_COUNT "COUNT" + + +# ifdef __cplusplus +} +# endif + +#endif + diff --git a/lib_acl/include/unit_test/acl_test_var.h b/lib_acl/include/unit_test/acl_test_var.h new file mode 100644 index 000000000..689839040 --- /dev/null +++ b/lib_acl/include/unit_test/acl_test_var.h @@ -0,0 +1,21 @@ +#ifndef __ACL_TEST_VAR_INCLUDE_H__ +#define __ACL_TEST_VAR_INCLUDE_H__ + +# ifdef __cplusplus +extern "C" { +# endif + +#include "stdlib/acl_array.h" + +extern int var_aut_log_level; +extern int var_aut_verbose; + +extern ACL_ARRAY *var_aut_line_array; +extern int var_aut_valid_line_idx; + +# ifdef __cplusplus +} +# endif + +#endif + diff --git a/lib_acl/include/unit_test/acl_unit_test.h b/lib_acl/include/unit_test/acl_unit_test.h new file mode 100644 index 000000000..4c2cce715 --- /dev/null +++ b/lib_acl/include/unit_test/acl_unit_test.h @@ -0,0 +1,18 @@ +#ifndef __ACL_UNIT_TEST_INCLUDE_H__ +#define __ACL_UNIT_TEST_INCLUDE_H__ + +# ifdef __cplusplus +extern "C" { +# endif + +#include "acl_test_struct.h" +#include "acl_test_global.h" +#include "acl_test_var.h" +#include "acl_test_macro.h" + +# ifdef __cplusplus +} +# endif + +#endif + diff --git a/lib_acl/include/vld.h b/lib_acl/include/vld.h new file mode 100644 index 000000000..c5f124de2 --- /dev/null +++ b/lib_acl/include/vld.h @@ -0,0 +1,98 @@ +//////////////////////////////////////////////////////////////////////////////// +// $Id: vld.h,v 1.27 2006/11/12 18:09:20 dmouldin Exp $ +// +// Visual Leak Detector (Version 1.9d) - Import Library Header +// Copyright (c) 2006 Dan Moulding +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +// +// See COPYING.txt for the full terms of the GNU Lesser General Public License. +// +//////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#ifdef _DEBUG + +#pragma comment(lib, "vld.lib") + +// Force a symbolic reference to the global VisualLeakDetector class object from +// the DLL. This enusres that the DLL is loaded and linked with the program, +// even if no code otherwise imports any of the DLL's exports. +#pragma comment(linker, "/include:__imp_?vld@@3VVisualLeakDetector@@A") + +//////////////////////////////////////////////////////////////////////////////// +// +// Visual Leak Detector APIs +// + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +// VLDDisable - Disables Visual Leak Detector's memory leak detection at +// runtime. If memory leak detection is already disabled, then calling this +// function has no effect. +// +// Note: In multithreaded programs, this function operates on a per-thread +// basis. In other words, if you call this function from one thread, then +// memory leak detection is only disabled for that thread. If memory leak +// detection is enabled for other threads, then it will remain enabled for +// those other threads. It was designed to work this way to insulate you, +// the programmer, from having to ensure thread synchronization when calling +// VLDEnable() and VLDDisable(). Without this, calling these two functions +// unsychronized could result in unpredictable and unintended behavior. +// But this also means that if you want to disable memory leak detection +// process-wide, then you need to call this function from every thread in +// the process. +// +// Return Value: +// +// None. +// +__declspec(dllimport) void VLDDisable (); + +// VLDEnable - Enables Visual Leak Detector's memory leak detection at runtime. +// If memory leak detection is already enabled, which it is by default, then +// calling this function has no effect. +// +// Note: In multithreaded programs, this function operates on a per-thread +// basis. In other words, if you call this function from one thread, then +// memory leak detection is only enabled for that thread. If memory leak +// detection is disabled for other threads, then it will remain disabled for +// those other threads. It was designed to work this way to insulate you, +// the programmer, from having to ensure thread synchronization when calling +// VLDEnable() and VLDDisable(). Without this, calling these two functions +// unsychronized could result in unpredictable and unintended behavior. +// But this also means that if you want to enable memory leak detection +// process-wide, then you need to call this function from every thread in +// the process. +// +// Return Value: +// +// None. +// +__declspec(dllimport) void VLDEnable (); + +#ifdef __cplusplus +} +#endif // __cplusplus + +#else // !_DEBUG + +#define VLDEnable() +#define VLDDisable() + +#endif // _DEBUG \ No newline at end of file diff --git a/lib_acl/include/xml/acl_xml.h b/lib_acl/include/xml/acl_xml.h new file mode 100644 index 000000000..1af1b6bb3 --- /dev/null +++ b/lib_acl/include/xml/acl_xml.h @@ -0,0 +1,519 @@ +#ifndef __ACL_XML_INCLUDE_H__ +#define __ACL_XML_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_array.h" +#include "stdlib/acl_ring.h" +#include "stdlib/acl_vstream.h" +#include "stdlib/acl_htable.h" +#include "stdlib/acl_vstring.h" +#include "stdlib/acl_iterator.h" +#include "stdlib/acl_slice.h" + +typedef struct ACL_XML ACL_XML; +typedef struct ACL_XML_NODE ACL_XML_NODE; +typedef struct ACL_XML_ATTR ACL_XML_ATTR; + +struct ACL_XML_ATTR { + ACL_XML_NODE *node; /**< 所属结点 */ + ACL_VSTRING *name; /**< 属性名 */ + ACL_VSTRING *value; /**< 属性值 */ + + /* private */ + int quote; /**< 非 0 表示 ' 或 " */ + int backslash; /**< 转义字符 \ */ + int part_word; /**< 半个汉字的情况处理标志位 */ + int slash; /**< 是否有 '/' 标志位设定 */ +}; + +struct ACL_XML_NODE { + ACL_VSTRING *ltag; /**< 左标签名 */ + ACL_VSTRING *rtag; /**< 右标签名 */ + const ACL_VSTRING *id; /**< ID标识符, 只有在 xml->id_table 存在的结点的 id 才非空 */ + ACL_VSTRING *text; /**< 文本显示内容 */ + ACL_ARRAY *attr_list; /**< 属性(ACL_XML_ATTR)列表 */ + ACL_XML_NODE *parent; /**< 父结点 */ + ACL_RING children; /**< 子结点集合 */ + int depth; /**< 当前结点的深度 */ + + /* private */ + ACL_XML *xml; /**< xml 对象 */ + ACL_RING node; /**< 当前结点 */ + ACL_XML_ATTR *curr_attr; /**< 当前正在解析的属性 */ + int quote; /**< 非 0 表示 ' 或 " */ + int last_ch; /**< 所记录本结点的前一个字节值 */ + int nlt; /**< '<' 个数 */ + char meta[3]; /**< 元数据临时缓冲区 */ + unsigned int flag; +#define ACL_XML_F_META_QM (1 << 0) /**< '?' flag */ +#define ACL_XML_F_META_CM (1 << 1) /**< '!--' flag */ +#define ACL_XML_F_META_EM (1 << 2) /**< only '!' flag */ +#define ACL_XML_F_SELF_CL (1 << 3) /**< self closed flag */ +#define ACL_XML_F_LEAF (1 << 4) /**< leaf node has no child node */ + +/**< 是否是元数据 */ +#define ACL_XML_F_META \ + (ACL_XML_F_META_QM | ACL_XML_F_META_CM | ACL_XML_F_META_EM) + + int status; /**< 状态机当前解析状态 */ +#define ACL_XML_S_NXT 0 /**< 下一个结点 */ +#define ACL_XML_S_LLT 1 /**< 左边 '<' */ +#define ACL_XML_S_LGT 2 /**< 右边 '>' */ +#define ACL_XML_S_LCH 3 /**< 左边 '<' 后第一个字节 */ +#define ACL_XML_S_LEM 4 /**< 左边 '<' 后的 '!' */ +#define ACL_XML_S_LTAG 5 /**< 左边的标签名 */ +#define ACL_XML_S_RLT 6 /**< 右边的 '<' */ +#define ACL_XML_S_RGT 7 /**< 右边的 '>' */ +#define ACL_XML_S_RTAG 8 /**< 右边的标签名 */ +#define ACL_XML_S_ATTR 9 /**< 标签属性名 */ +#define ACL_XML_S_AVAL 10 /**< 标签属性值 */ +#define ACL_XML_S_TXT 11 /**< 结点文本 */ +#define ACL_XML_S_MTAG 12 /**< 元数据标签 */ +#define ACL_XML_S_MTXT 13 /**< 元数据文本 */ +#define ACL_XML_S_MCMT 14 /**< 元数据注释 */ +#define ACL_XML_S_MEND 15 /**< 元数据结束 */ + + /* public: for acl_iterator, 通过 acl_foreach 列出该结点的一级子结点 */ + + /* 取迭代器头函数 */ + ACL_XML_NODE *(*iter_head)(ACL_ITER*, ACL_XML_NODE*); + /* 取迭代器下一个函数 */ + ACL_XML_NODE *(*iter_next)(ACL_ITER*, ACL_XML_NODE*); + /* 取迭代器尾函数 */ + ACL_XML_NODE *(*iter_tail)(ACL_ITER*, ACL_XML_NODE*); + /* 取迭代器上一个函数 */ + ACL_XML_NODE *(*iter_prev)(ACL_ITER*, ACL_XML_NODE*); +}; + +struct ACL_XML { + /* public */ + int depth; /**< 最大深度 */ + int node_cnt; /**< 结点总数, 包括 root 结点 */ + ACL_XML_NODE *root; /**< XML 根结点 */ + + /* private */ + ACL_HTABLE *id_table; /**< id 标识符哈希表 */ + ACL_XML_NODE *curr_node; /**< 当前正在处理的 XML 结点 */ + ACL_SLICE_POOL *slice; /**< 内存池对象 */ + + ACL_ARRAY *node_cache; /**< XML结点缓存池 */ + int max_cache; /**< XML结点缓存池的最大容量 */ + unsigned flag; /**< 标志位: ACL_XML_FLAG_xxx */ +#define ACL_XML_FLAG_PART_WORD (1 << 0) /**< 是否兼容后半个汉字为转义符 '\' 的情况 */ +#define ACL_XML_FLAG_IGNORE_SLASH (1 << 1) /**< 是否兼容单结点中没有 '/' 情况 */ + + /* public: for acl_iterator, 通过 acl_foreach 可以列出所有子结点 */ + + /* 取迭代器头函数 */ + ACL_XML_NODE *(*iter_head)(ACL_ITER*, ACL_XML*); + /* 取迭代器下一个函数 */ + ACL_XML_NODE *(*iter_next)(ACL_ITER*, ACL_XML*); + /* 取迭代器尾函数 */ + ACL_XML_NODE *(*iter_tail)(ACL_ITER*, ACL_XML*); + /* 取迭代器上一个函数 */ + ACL_XML_NODE *(*iter_prev)(ACL_ITER*, ACL_XML*); +}; + +#define ACL_XML_IS_COMMENT(x) (((x)->flag & ACL_XML_F_META_CM)) + +/***************************************************************************/ +/* 公共函数接口,用户可以放心使用该接口集 */ +/***************************************************************************/ + +/*----------------------------- in acl_xml.c ------------------------------*/ + +/** + * 判断 xml 对象是否闭合的, 即是否所解析的数据是否完整, 如果该 xml 对象里的 + * xml 结点元素为空, 则也认为不是闭合的 + * @param xml {ACL_XML*} xml 对象 + * @return {int} 0: 否; 1: 是 + */ +ACL_API int acl_xml_is_closure(ACL_XML *xml); + +/** + * 根据指定的标签名判断 xml 解析已经完成, 当该标签与 xml 对象中 root 一级子结点 + * 中的最后一个 xml 结点的标签相同时, 则认为 xml 解析完成, 为了保证判断的正确性, + * 数据源应保证最外层的根结点只有一个, 即 xml->root 的一级子结点只有一个, 否则 + * 会造成误判 + * @param xml {ACL_XML*} xml 对象 + * @param tag {const char*} 用户给定标签名, 内部在匹配时不区分大小写 + * @return {int} 0: 否; 1: 是 + */ +ACL_API int acl_xml_is_complete(ACL_XML *xml, const char *tag); + +/** + * 创建一个 xml 对象 + * @return {ACL_XML*} 新创建的 xml 对象 + */ +ACL_API ACL_XML *acl_xml_alloc(void); + +/** + * 创建一个 xml 对象,该 xml 对象及所有的内部内存分配都在该内存池上进行分配 + * @param slice {ACL_SLICE_POOL*} 内存池对象,可以为空指针,表明不用内存池 + * @return {ACL_XML*} 新创建的 xml 对象 + */ +ACL_API ACL_XML *acl_xml_alloc1(ACL_SLICE_POOL *slice); + +/** + * 将某一个 ACL_XML_NODE 结点作为一个 XML 对象的根结点,从而可以方便地遍历出该 + * 结点的各级子结点(在遍历过程中的所有结点不含本结点自身),该遍历方式有别于单独 + * 遍历某一个 ACL_XML_NODE 结点时仅能遍历其一级子结点的情形 + * @param xml {ACL_XML*} xml 对象 + * @param node {ACL_XML_NODE*} AXL_XML_NODE 结点 + */ +ACL_API void acl_xml_foreach_init(ACL_XML *xml, ACL_XML_NODE *node); + +/** + * 对于 XML 单结点的情况, 是否允许可以没有 /, 如: + * , , 当可以允许没有 / 则这两种写法 + * 都是合法的,否则只有第二个写法是合法的,如果允许这种兼容性,则 + * 会造成一定的性能损失 + * @param xml {ACL_XML*} xml 对象 + * @param ignore {int} 如果非 0 表示单结点必须有 / + */ +ACL_API void acl_xml_slash(ACL_XML *xml, int ignore); + +/** + * 打开或关闭XML的缓存功能,当复用 ACL_XML 对象时打开XML的结点缓存功能有利提高效率 + * @param xml {ACL_XML*} xml 对象 + * @param max_cache {int} 缓存的最大值,当该值 > 0 时会打开 xml 解析器对 xml 结点的 + * 缓存功能,否则会关闭 xml 解析器对 xml 结点的缓存功能 + */ +ACL_API void acl_xml_cache(ACL_XML *xml, int max_cache); + +/** + * 释放 XML 缓存的 XML 结点对象 + * @param xml {ACL_XML*} xml 对象 + */ +ACL_API void acl_xml_cache_free(ACL_XML *xml); + +/** + * 释放一个 xml 对象, 同时释放该对象里容纳的所有 xml 结点 + * @param xml {ACL_XML*} xml 对象 + */ +ACL_API int acl_xml_free(ACL_XML *xml); + +/** + * 重置 XML 解析器对象 + * @param xml {ACL_XML*} xml 对象 + */ +ACL_API void acl_xml_reset(ACL_XML *xml); + +/*------------------------- in acl_xml_parse.c ----------------------------*/ + +/** + * 解析 xml 数据, 并持续地自动生成 xml 结点树 + * @param xml {ACL_XML*} xml 对象 + * @param data {const char*} 以 '\0' 结尾的数据字符串, 可以是完整的 xml 数据; + * 也可以是不完整的 xml 数据, 允许循环调用此函数, 将不完整数据持续地输入 + */ +ACL_API void acl_xml_update(ACL_XML *xml, const char *data); +#define acl_xml_parse acl_xml_update + +/*------------------------- in acl_xml_util.c -----------------------------*/ + +/** + * 初始化类似于 input, br, hr 等的自闭合标签, 形成自闭合标签树, 以便于 + * acl_xml_tag_selfclosed 查询该树, 检查所给标签是否是保留的自闭合标签, + * 该函数只能被初始化一次, 也可以不初始化 + */ +ACL_API void acl_xml_tag_init(void); + +/** + * 允许用户自己添加一些非自闭合的标签 + * @param tag {const char*} 标签名,注意标签长度不得大于 254 个字节 + */ +ACL_API void acl_xml_tag_add(const char *tag); + +/** + * 当调用 acl_xml_tag_init 初始化保留的自闭合标签树后, 可以调用此函数判断所给 + * 标签是否属于自闭合标签, 如果未调用 acl_xml_tag_init, 则该函数永远返回 0 + * @parma tag {const char*} 标签名称 + * @return {int} 0: 表示否, 1: 表示是 + */ +ACL_API int acl_xml_tag_selfclosed(const char *tag); + +/** + * 判断标签所属 xml 结点是否是叶结点, 叶结点没有子结点 + * @param tag {const char*} 标签名 + * @return {int} 0: 不是叶结点; 1: 是叶结点 + */ +ACL_API int acl_xml_tag_leaf(const char *tag); + +/** + * 释放由 acl_xml_getElementsByTagName, acl_xml_getElementsByName, + * acl_xml_getElementsByAttr 等函数返回的动态数组对象, 因为该动态数组中的 + * 元素都是 ACL_XML 对象中元素的引用, 所以释放掉该动态数组后, 只要 ACL_XML + * 对象不释放, 则原来存于该数组中的元素依然可以使用. + * 但并不释放里面的 xml 结点元素 + * @param a {ACL_ARRAY*} 动态数组对象 + */ +ACL_API void acl_xml_free_array(ACL_ARRAY *a); + +/** + * 从 xml 对象中获得所有的与所给标签名相同的 xml 结点的集合 + * @param xml {ACL_XML*} xml 对象 + * @param tag {const char*} 标签名称 + * @return {ACL_ARRAY*} 符合条件的 xml 结点集合, 存于 动态数组中, 若返回 NULL 则 + * 表示没有符合条件的 xml 结点, 非空值需要调用 acl_xml_free_array 释放 + */ +ACL_API ACL_ARRAY *acl_xml_getElementsByTagName(ACL_XML *xml, const char *tag); + +/** + * 从 xml 对象中获得所有的与给定多级标签名相同的 xml 结点的集合 + * @param xml {ACL_XML*} xml 对象 + * @param tags {const char*} 多级标签名,由 '/' 分隔各级标签名,如针对 xml 数据: + * text1 + * text2 + * text3 + * 可以通过多级标签名:root/first/second/third 一次性查出所有符合条件的结点 + * @return {ACL_ARRAY*} 符合条件的 xml 结点集合, 存于 动态数组中, 若返回 NULL 则 + * 表示没有符合条件的 xml 结点, 非空值需要调用 acl_xml_free_array 释放 + */ +ACL_API ACL_ARRAY *acl_xml_getElementsByTags(ACL_XML *xml, const char *tags); + +/** + * 从 xml 对象中获得所有的与给定属性名 name 的属性值相同的 xml 结点元素集合 + * @param xml {ACL_XML*} xml 对象 + * @param value {const char*} 属性名为 name 的属性值 + * @return {ACL_ARRAY*} 符合条件的 xml 结点集合, 存于 动态数组中, 若返回 NULL 则 + * 表示没有符合条件的 xml 结点, 非空值需要调用 acl_xml_free_array 释放 + */ +ACL_API ACL_ARRAY *acl_xml_getElementsByName(ACL_XML *xml, const char *value); + +/** + * 从 xml 对象中获得所有给定属性名及属性值的 xml 结点元素集合 + * @param xml {ACL_XML*} xml 对象 + * @param name {const char*} 属性名 + * @param value {const char*} 属性值 + * @return {ACL_ARRAY*} 符合条件的 xml 结点集合, 存于 动态数组中, 若返回 NULL 则 + * 表示没有符合条件的 xml 结点, 非空值需要调用 acl_xml_free_array 释放 + */ +ACL_API ACL_ARRAY *acl_xml_getElementsByAttr(ACL_XML *xml, + const char *name, const char *value); + +/** + * 从 xml 对象中获得指定 id 值的 xml 结点元素的某个属性对象 + * @param xml {ACL_XML*} xml 对象 + * @param id {const char*} id 值 + * @return {ACL_XML_ATTR*} 某 xml 结点的某个属性对象, 若返回 NULL 则表示 + * 没有符合条件的属性, 返回值不需要释放 + */ +ACL_API ACL_XML_ATTR *acl_xml_getAttrById(ACL_XML *xml, const char *id); + +/** + * 从 xml 对象中获得指定 id 值的 xml 结点元素的某个属性值 + * @param xml {ACL_XML*} xml 对象 + * @param id {const char*} id 值 + * @return {const char*} 某 xml 结点的某个属性值, 若返回 NULL 则表示没有符合 + * 条件的属性 + */ +ACL_API const char *acl_xml_getAttrValueById(ACL_XML *xml, const char *id); + +/** + * 从 xml 对象中获得指定 id 值的 xml 结点元素 + * @param xml {ACL_XML*} xml 对象 + * @param id {const char*} id 值 + * @return {ACL_XML_NODE*} xml 结点元素, 若返回 NULL 则表示没有符合 + * 条件的 xml 结点, 返回值不需要释放 + */ +ACL_API ACL_XML_NODE *acl_xml_getElementById(ACL_XML *xml, const char *id); + +/** + * 从 xml 对象中提取有在 ? ! 等开头的结点 + * @param xml {ACL_XML*} xml 对象 + * @param tag {const char*} 标签名 + * @return {ACL_XML_NODE*} xml 结点元素, 若返回 NULL 则表示没有符合 + * 条件的 xml 结点, 返回值不需要释放 + */ +ACL_API ACL_XML_NODE *acl_xml_getElementMeta(ACL_XML *xml, const char *tag); + +/** + * 获得 xml 的字符集编码格式 + * @param xml {ACL_XML*} xml 对象 + * @return {const char*} 返回字符集编码格式,返回 NULL 时表示没有该属性 + */ +ACL_API const char *acl_xml_getEncoding(ACL_XML *xml); + +/** + * 获得 xml 数据的类型,如:text/xsl + * @param xml {ACL_XML*} xml 对象 + * @return {const char*} 返回 NULL 表示没有该属性 + */ +ACL_API const char *acl_xml_getType(ACL_XML *xml); + +/** + * 从 xml 结点中获得指定属性名的属性对象 + * @param node {ACL_XML_NODE*} xml 结点 + * @param name {const char*} 属性名称 + * @return {ACL_XML_ATTR*} 属性对象, 为空表示不存在, 返回值不需要释放 + */ +ACL_API ACL_XML_ATTR *acl_xml_getElementAttr(ACL_XML_NODE *node, const char *name); + +/** + * 从 xml 结点中获得指定属性名的属性值 + * @param node {ACL_XML_NODE*} xml 结点 + * @param name {const char*} 属性名称 + * @return {const char*} 属性值, 为空表示不存在 + */ +ACL_API const char *acl_xml_getElementAttrVal(ACL_XML_NODE *node, const char *name); + +/** + * 从 xml 结点删除某个属性对象, 如果该属性为 id 属性, 则同时会从 xml->id_table 中删除 + * @param node {ACL_XML_NODE*} xml 结点 + * @param name {const char*} 属性名称 + * @return {int} 0 表示删除成功, -1: 表示删除失败(有可能是该属性不存在) + */ +ACL_API int acl_xml_removeElementAttr(ACL_XML_NODE *node, const char *name); + +/** + * 给 xml 结点添加属性, 如果该属性名已存在, 则用新的属性值替换其属性值, 否则 + * 创建并添加新的属性对象 + * @param node {ACL_XML_NODE*} xml 结点 + * @param name {const char*} 属性名称 + * @param value {const char*} 属性值 + * @return {ACL_XML_ATTR*} 返回该属性对象(有可能是原来的, 也有可能是新的), + * 返回值不需释放 + */ +ACL_API ACL_XML_ATTR *acl_xml_addElementAttr(ACL_XML_NODE *node, + const char *name, const char *value); + +/** + * 将标签名及结点文本做为参数创建 xml 结点,该函数主要用在构建 xml 对象时 + * @param xml {ACL_XML*} xml 对象,该对象应该是由 acl_xml_alloc 创建的 + * @param tagname {const char*} 标签名,必须非空且字符串长度大于 0 + * @param text {const char*} 结点的文本内容,可以为空 + * @return {ACL_XML_NODE*} 新创建的 xml 结点,该返回永远返回非空,如果输入 + * 参数非法则会导致内部自动产生断言 + */ +ACL_API ACL_XML_NODE *acl_xml_create_node(ACL_XML *xml, + const char* tagname, const char* text); + +/** + * 给一个 xml 结点添加属性,该函数主要用在构建 xml 对象时 + * @param node {ACL_XML_NODE*} 由 acl_xml_create_node 创建的结点 + * @param name {const char*} 属性名,必须为非空字符串且字符串长度大于 0 + * @param value {const char*} 属性值,可以为空 + * @return {ACL_XML_ATTR*} xml 结点的属性对象,当输入参数非法时该函数 + * 内部自动产生断言 + */ +ACL_API ACL_XML_ATTR *acl_xml_node_add_attr(ACL_XML_NODE *node, + const char *name, const char *value); + +/** + * 给一个 xml 结点添加一组属性,该函数主要用在构建 xml 对象时 + * @param node {ACL_XML_NODE*} 由 acl_xml_create_node 创建的结点 + * @param ... 一组属性,遇到 NULL 时表示结束,如: + * {name1}, {value1}, {name2}, {value2}, ... NULL + */ +ACL_API void acl_xml_node_add_attrs(ACL_XML_NODE *node, ...); + +/** + * 给一个 xml 结点添加文本内容,该函数主要用在构建 xml 对象时 + * @param node {ACL_XML_NODE*} 由 acl_xml_create_node 创建的结点 + * @param text {const char*} 文本内容 + */ +ACL_API void acl_xml_node_set_text(ACL_XML_NODE *node, const char *text); + +/** + * 将 xml 对象转成字符串内容 + * @param xml {ACL_XML*} xml 对象 + * @param buf {ACL_VSTRING*} 存储结果集的缓冲区,当该参数为空时则函数内部会 + * 自动分配一段缓冲区,应用用完后需要释放掉;非空函数内部会直接将结果存储其中 + * @return {ACL_VSTRING*} xml 对象转换成字符串后的存储缓冲区,该返回值永远非空, + * 使用者可以通过 ACL_VSTRING_LEN(x) 宏来判断内容是否为空,返回的 ACL_VSTRING + * 指针如果为该函数内部创建的,则用户名必须用 acl_vstring_free 进行释放 + */ +ACL_API ACL_VSTRING* acl_xml_build(ACL_XML* xml, ACL_VSTRING *buf); + +/** + * 将 xml 对象转储于指定流中,注:该转储信息仅为调试用的数据 + * @param xml {ACL_XML*} xml 对象 + * @param fp {ACL_VSTREAM*} 流对象 + */ +ACL_API void acl_xml_dump(ACL_XML *xml, ACL_VSTREAM *fp); + +/** + * 将 xml 对象转存于指定缓冲区中,注:该转储信息仅为调试用的数据 + * @param xml {ACL_XML*} xml 对象 + * @param buf {ACL_VSTRING*} 缓冲区, 需要用户自己分配空间 + */ +ACL_API void acl_xml_dump2(ACL_XML *xml, ACL_VSTRING *buf); + +/***************************************************************************/ +/* 以下为更为低级的接口, 用户可以根据需要调用以下接口 */ +/***************************************************************************/ + +/*----------------------------- in acl_xml.c ------------------------------*/ + +/** + * 创建 xml 结点的属性 + * @param node {ACL_XML_NODE*} xml 结点 + * @return {ACL_XML_ATTR*} 新创建的结点属性 + */ +ACL_API ACL_XML_ATTR *acl_xml_attr_alloc(ACL_XML_NODE *node); + +/** + * 释放 xml 结点的属性所占内存, 调用该函数前, 必须注意已经将该属性 + * 从其所从属的结点中删除 + * @param attr {ACL_XML_ATTR*} xml 结点的属性 + */ +ACL_API void acl_xml_attr_free(ACL_XML_ATTR *attr); + +/** + * 创建一个 xml 结点 + * @param xml {ACL_XML*} xml 对象 + * @return {ACL_XML_NODE*} xml 结点对象 + */ +ACL_API ACL_XML_NODE *acl_xml_node_alloc(ACL_XML *xml); + +/** + * 将某个 xml 结点及其子结点从 xml 对象中删除, 并释放该结点及其子结点所占空间 + * 函数来释放该 xml 结点所占内存 + * @param node {ACL_XML_NODE*} xml 结点 + * @return {int} 返回删除的结点个数 + */ +ACL_API int acl_xml_node_delete(ACL_XML_NODE *node); + +/** + * 向某个 xml 结点添加兄弟结点(该兄弟结点必须是独立的 xml 结点) + * @param node1 {ACL_XML_NODE*} 向本结点添加 xml 结点 + * @param node2 {ACL_XML_NODE*} 新添加的兄弟 xml 结点 + */ +ACL_API void acl_xml_node_append(ACL_XML_NODE *node1, ACL_XML_NODE *node2); + +/** + * 将某个 xml 结点作为子结点加入某父 xml 结点中 + * @param parent {ACL_XML_NODE*} 父结点 + * @param child {ACL_XML_NODE*} 子结点 + */ +ACL_API void acl_xml_node_add_child(ACL_XML_NODE *parent, ACL_XML_NODE *child); + +/** + * 获得某个 xml 结点的父结点 + * @param node {ACL_XML_NODE*} xml 结点 + * @return {ACL_XML_NODE*} 父结点, 如果为 NULL 则表示其父结点不存在 + */ +ACL_API ACL_XML_NODE *acl_xml_node_parent(ACL_XML_NODE *node); + +/** + * 获得某个 xml 结点的后一个兄弟结点 + * @param node {ACL_XML_NODE*} xml 结点 + * @return {ACL_XML_NODE*} 给定 xml 结点的后一个兄弟结点, 若为NULL则表示不存在 + */ +ACL_API ACL_XML_NODE *acl_xml_node_next(ACL_XML_NODE *node); + +/** + * 获得某个 xml 结点的前一个兄弟结点 + * @param node {ACL_XML_NODE*} xml 结点 + * @return {ACL_XML_NODE*} 给定 xml 结点的前一个兄弟结点, 若为NULL则表示不存在 + */ +ACL_API ACL_XML_NODE *acl_xml_node_prev(ACL_XML_NODE *node); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/lib_acl/lib/keep b/lib_acl/lib/keep new file mode 100644 index 000000000..139597f9c --- /dev/null +++ b/lib_acl/lib/keep @@ -0,0 +1,2 @@ + + diff --git a/lib_acl/lib_acl.rc b/lib_acl/lib_acl.rc new file mode 100644 index 000000000..b7e7b02e4 --- /dev/null +++ b/lib_acl/lib_acl.rc @@ -0,0 +1,102 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// ??(???????) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) +#ifdef _WIN32 +LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED +#pragma code_page(936) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 2,1,2,9 + PRODUCTVERSION 2,1,2,9 + FILEFLAGSMASK 0x17L +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x7L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "080404b0" + BEGIN + VALUE "Comments", "本库为跨平台的C库,包括了网络通讯,服务器框架等功能" + VALUE "FileDescription", "acl 库" + VALUE "FileVersion", "2, 1, 2, 9" + VALUE "InternalName", "lib_acl" + VALUE "LegalCopyright", "zsx (C) 2011" + VALUE "OriginalFilename", "lib_acl.lib" + VALUE "ProductName", " acl 库" + VALUE "ProductVersion", "2, 1, 2, 9" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x804, 1200 + END +END + +#endif // ??(???????) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/lib_acl/lib_acl_vc2003.vcproj b/lib_acl/lib_acl_vc2003.vcproj new file mode 100644 index 000000000..c4b535584 --- /dev/null +++ b/lib_acl/lib_acl_vc2003.vcproj @@ -0,0 +1,1829 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_acl/lib_acl_vc2010.vcxproj b/lib_acl/lib_acl_vc2010.vcxproj new file mode 100644 index 000000000..d9cf31938 --- /dev/null +++ b/lib_acl/lib_acl_vc2010.vcxproj @@ -0,0 +1,668 @@ +锘 + + + + Debug + Win32 + + + DebugDll + Win32 + + + ReleaseDll + Win32 + + + Release + Win32 + + + + lib_acl + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + acl_lib + + + + + + DynamicLibrary + + + DynamicLibrary + + + StaticLibrary + false + MultiByte + + + StaticLibrary + false + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + .\ + .\Release\ + *.obj%3b*.ilk%3b*.pdb%3b*.tlb%3b*.tli%3b*.tlh%3b*.tmp%3b*.rsp%3b*.bat%3b*.map%3b*.pch%3b$(TargetPath) + .\ + .\Debug\ + *.obj%3b*.ilk%3b*.pdb%3b*.tlb%3b*.tli%3b*.tlh%3b*.tmp%3b*.rsp%3b*.bat%3b*.map%3b*.pch%3b$(TargetPath) + .\ + ReleaseDll\ + *.obj%3b*.ilk%3b*.pdb%3b*.tlb%3b*.tli%3b*.tlh%3b*.tmp%3b*.rsp%3b*.bat%3b*.map%3b*.pch%3b$(TargetPath) + false + .\ + DebugDll\ + *.obj%3b*.ilk%3b*.pdb%3b*.tlb%3b*.tli%3b*.tlh%3b*.tmp%3b*.rsp%3b*.bat%3b*.map%3b*.pch%3b$(TargetPath) + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + $(ProjectName)_vc2010 + $(ProjectName)_vc2010d + $(ProjectName)_d + + + + MaxSpeed + OnlyExplicitInline + Size + .\include;.;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;_MT;_CRT_SECURE_NO_WARNINGS;MS_VC;ACL_PREPARE_COMPILE;%(PreprocessorDefinitions) + true + MultiThreaded + true + Use + .\Release/acl_lib.pch + .\Release/ + .\Release/ + $(ProjectName)_vc2010.pdb + Level3 + true + ProgramDatabase + + + $(ProjectName)_vc2010.lib + true + MachineX86 + + + copy $(TargetName).lib ..\dist\lib\win32\$(TargetName).lib /Y +copy $(TargetName).pdb ..\dist\lib\win32\$(TargetName).pdb /Y + + + NDEBUG;%(PreprocessorDefinitions) + 0x0804 + + + + + Disabled + Size + .\include;.;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_LIB;_MT;MS_VC;ACL_PREPARE_COMPILE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + Use + $(TargetName).pch + .\Debug/ + .\Debug/ + $(ProjectName)_vc2010d.pdb + Level3 + true + ProgramDatabase + Default + + + $(ProjectName)_vc2010d.lib + true + MachineX86 + + + copy $(TargetName).lib ..\dist\lib\win32\$(TargetName).lib /Y +copy $(TargetName).pdb ..\dist\lib\win32\$(TargetName).pdb /Y + + + _DEBUG;%(PreprocessorDefinitions) + 0x0804 + + + + + .\include;.;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;_MT;_CRT_SECURE_NO_WARNINGS;ACL_PREPARE_COMPILE;MS_VC;ACL_DLL;ACL_EXPORTS;%(PreprocessorDefinitions) + MultiThreadedDLL + Use + $(ProjectName).pdb + ProgramDatabase + + + wsock32.lib;ws2_32.lib;IPHlpApi.Lib;%(AdditionalDependencies) + $(ProjectName).dll + MachineX86 + + + copy $(TargetName).lib ..\dist\lib\win32\$(TargetName).lib /Y +copy $(TargetName).dll ..\dist\lib\win32\$(TargetName).dll /Y +copy $(TargetName).pdb ..\dist\lib\win32\$(TargetName).pdb /Y + + + + + + Disabled + Size + .\include;.;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_LIB;_MT;_CRT_SECURE_NO_WARNINGS;MS_VC;ACL_DLL;ACL_EXPORTS;ACL_PREPARE_COMPILE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Use + $(ProjectName)_d.pdb + Level3 + ProgramDatabase + + + wsock32.lib;ws2_32.lib;IPHlpApi.Lib;%(AdditionalDependencies) + $(ProjectName)_d.dll + true + true + true + false + $(OutDir)$(TargetName).lib + MachineX86 + + + copy $(TargetName).lib ..\dist\lib\win32\$(TargetName).lib /Y +copy $(TargetName).dll ..\dist\lib\win32\$(TargetName).dll /Y +copy $(TargetName).pdb ..\dist\lib\win32\$(TargetName).pdb /Y + + + + + + Create + Create + Create + Create + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_acl/lib_acl_vc2010.vcxproj.filters b/lib_acl/lib_acl_vc2010.vcxproj.filters new file mode 100644 index 000000000..9c06f3ed2 --- /dev/null +++ b/lib_acl/lib_acl_vc2010.vcxproj.filters @@ -0,0 +1,1513 @@ +锘 + + + + {bfe7a9a3-0369-4d86-954a-0a3e67d1290e} + cpp;c;cxx;rc;def;r;odl;idl;hpj;bat + + + {cc389572-fee6-4643-a9af-85b1e2367054} + + + {34f0e452-7c64-43ae-ada7-1a5086e805c5} + + + {92f34b3b-3a7d-4093-9588-5e81a88db4cf} + + + {094be268-129e-4b49-b455-ec1ae3381e6f} + + + {f80bf918-aa94-4aae-a22f-76f6514f471a} + + + {0885a3f0-31b0-42cc-b5bd-bea215c80db2} + + + {ce3d4944-6dd1-418b-b2f7-5cde214b8aac} + + + {e2b0d0b7-ace0-4bb7-8c6f-2d34cc667791} + + + {70c495e7-d5ee-4921-8a3f-cf9ef215fae5} + + + {e31eab40-d204-4e30-9cea-c466c81bd858} + + + {12babb5a-4ccc-4b0e-9ce8-38c58649d3bb} + + + {93f23048-87ac-4874-b099-2fc6d210034a} + + + {da67f89a-e3e5-46e5-8e04-5b7da0ae466b} + + + {b879860a-bdbf-4f7a-9904-9cadb1be607b} + + + {ab7e8b79-4337-4406-b611-ebfe8dec8a8c} + + + {84458eeb-c970-48e9-89ce-e6e3bacd61d0} + + + {8ecdec21-169a-4ba2-a7bb-5b7def517ec5} + + + {b90e2e8a-57a3-4d73-b0a7-d0eba4712deb} + + + {844ca1c9-8bff-439e-b915-e45887eabde5} + + + {40fc0cb7-638e-4fe4-aca9-0304814e175f} + + + {d0609c6f-01f5-42f5-8835-c859c27ad6ea} + + + {b39c4127-4c0e-4506-b74e-1ed8b905a297} + + + {7af66f47-af08-436a-8032-464cd99502b8} + + + {12069517-4364-4c36-a10d-9ff46c05f3c7} + + + {4c1d9804-7881-41a8-83ed-222081d29a77} + + + {ea811014-788a-48fe-b707-a9b89b53bd06} + + + {6edd8537-3799-413f-b207-e2ce6c4517bf} + + + {fc860aba-9b94-4555-9ee1-ddf5bca931d4} + + + {01684461-568d-4c09-b1c0-1c4df0e12ae6} + + + {9b13391b-9bed-4d58-9e22-bc169844986e} + + + {35b92483-33d0-43ee-b8af-f8f93b8dcd3b} + + + {d249f3dc-3b3d-4453-96fd-87ceced12484} + + + {f721cf19-6c42-4e35-9e10-e1a681d6daed} + + + {d64b387b-872a-4d46-a8b8-e2ff2e084e29} + + + {02a7431c-7564-4276-925b-747dc3626119} + + + {2c232e54-a68f-4ef8-8e38-3b671d18b65c} + + + {142958f0-a535-495f-8415-d08b1f5adb6f} + + + {729d8b0e-de47-4916-a69a-b8cbe555d0ae} + h;hpp;hxx;hm;inl + + + {929ad0d6-4d30-4fd7-a07f-152d6044043a} + + + {872a9249-19b2-45ca-a49d-683e8750faea} + + + {77757d9e-a544-4dbb-9003-07d3214c022c} + + + {9c48db63-1706-4dbf-b270-fdb6ece0e265} + + + {388a38a0-dee2-49ff-8cad-b75d8959b35b} + + + {1b368af6-ce4d-4811-8063-14dff7a64020} + + + {c54eee41-e8f6-4659-9e21-c43f32efe6df} + + + {51551e5f-b371-48e8-b790-00c4f3e894f9} + + + {41299863-cdec-43fa-a837-3119cd21e6a1} + + + {18ea3512-9ecd-44bd-9fdb-a2336e93132a} + + + {1f760363-c10d-4e0a-8734-1adebdbb95c4} + + + {6cc2f181-647d-42e2-b6ba-0e66d7fdc7b1} + + + {460f8bf7-4788-483a-b278-e207cb9707dd} + + + {4a873376-2f34-482f-941f-3e85e52b96cb} + + + {9b3325d8-5f0a-4914-91f2-df60048c240f} + + + {5dd5951b-a552-43b0-96f2-53bee78c440e} + + + {1e3ecec3-12ea-4261-b557-a5ef8dbbd195} + + + {39ba72d7-77d0-4034-b7fd-0da49add37bd} + + + + + Source Files + + + Source Files\stdlib + + + Source Files\stdlib + + + Source Files\stdlib + + + Source Files\stdlib + + + Source Files\stdlib + + + Source Files\stdlib + + + Source Files\stdlib + + + Source Files\stdlib + + + Source Files\stdlib + + + Source Files\stdlib + + + Source Files\stdlib + + + Source Files\stdlib + + + Source Files\stdlib + + + Source Files\stdlib + + + Source Files\stdlib + + + Source Files\stdlib + + + Source Files\stdlib + + + Source Files\stdlib\iostuff + + + Source Files\stdlib\iostuff + + + Source Files\stdlib\iostuff + + + Source Files\stdlib\iostuff + + + Source Files\stdlib\iostuff + + + Source Files\stdlib\iostuff + + + Source Files\stdlib\iostuff + + + Source Files\stdlib\iostuff + + + Source Files\stdlib\iostuff + + + Source Files\stdlib\iostuff + + + Source Files\stdlib\iostuff + + + Source Files\stdlib\iostuff + + + Source Files\stdlib\iostuff + + + Source Files\stdlib\iostuff + + + Source Files\stdlib\iostuff + + + Source Files\stdlib\common + + + Source Files\stdlib\common + + + Source Files\stdlib\common + + + Source Files\stdlib\common + + + Source Files\stdlib\common + + + Source Files\stdlib\common + + + Source Files\stdlib\common + + + Source Files\stdlib\common + + + Source Files\stdlib\common + + + Source Files\stdlib\common + + + Source Files\stdlib\common + + + Source Files\stdlib\common + + + Source Files\stdlib\common + + + Source Files\stdlib\common + + + Source Files\stdlib\common + + + Source Files\stdlib\common + + + Source Files\stdlib\configure + + + Source Files\stdlib\configure + + + Source Files\stdlib\configure + + + Source Files\stdlib\filedir + + + Source Files\stdlib\filedir + + + Source Files\stdlib\filedir + + + Source Files\stdlib\filedir + + + Source Files\stdlib\filedir + + + Source Files\stdlib\sys + + + Source Files\stdlib\sys + + + Source Files\stdlib\sys + + + Source Files\stdlib\sys + + + Source Files\stdlib\sys + + + Source Files\stdlib\sys + + + Source Files\stdlib\sys + + + Source Files\stdlib\sys + + + Source Files\stdlib\sys + + + Source Files\stdlib\sys + + + Source Files\stdlib\sys + + + Source Files\stdlib\sys\unix + + + Source Files\stdlib\sys\unix + + + Source Files\stdlib\sys\unix + + + Source Files\stdlib\sys\unix + + + Source Files\stdlib\sys\unix + + + Source Files\stdlib\sys\unix + + + Source Files\stdlib\sys\unix + + + Source Files\stdlib\sys\unix + + + Source Files\stdlib\sys\unix + + + Source Files\stdlib\sys\unix + + + Source Files\stdlib\sys\unix + + + Source Files\stdlib\sys\unix + + + Source Files\stdlib\string + + + Source Files\stdlib\string + + + Source Files\stdlib\string + + + Source Files\stdlib\string + + + Source Files\stdlib\string + + + Source Files\stdlib\string + + + Source Files\stdlib\string + + + Source Files\stdlib\string + + + Source Files\stdlib\string + + + Source Files\stdlib\string + + + Source Files\stdlib\memory + + + Source Files\stdlib\memory + + + Source Files\stdlib\memory + + + Source Files\stdlib\memory + + + Source Files\stdlib\memory + + + Source Files\stdlib\memory + + + Source Files\stdlib\memory + + + Source Files\stdlib\memory + + + Source Files\stdlib\memory + + + Source Files\stdlib\memory + + + Source Files\stdlib\memory + + + Source Files\stdlib\memory + + + Source Files\stdlib\debug + + + Source Files\stdlib\debug + + + Source Files\net + + + Source Files\net + + + Source Files\net + + + Source Files\net + + + Source Files\net + + + Source Files\net + + + Source Files\net + + + Source Files\net + + + Source Files\net + + + Source Files\net\listen + + + Source Files\net\listen + + + Source Files\net\listen + + + Source Files\net\listen + + + Source Files\net\connect + + + Source Files\net\connect + + + Source Files\net\connect + + + Source Files\net\connect + + + Source Files\net\connect + + + Source Files\net\dns + + + Source Files\net\dns + + + Source Files\net\dns + + + Source Files\net\dns + + + Source Files\net\dns + + + Source Files\net\dns + + + Source Files\thread + + + Source Files\thread + + + Source Files\thread + + + Source Files\thread + + + Source Files\thread + + + Source Files\thread + + + Source Files\msg + + + Source Files\msg + + + Source Files\xml + + + Source Files\xml + + + Source Files\xml + + + Source Files\event + + + Source Files\event + + + Source Files\event + + + Source Files\event + + + Source Files\event + + + Source Files\event + + + Source Files\event + + + Source Files\event + + + Source Files\event + + + Source Files\event + + + Source Files\event + + + Source Files\event + + + Source Files\event + + + Source Files\event + + + Source Files\event + + + Source Files\event + + + Source Files\event + + + Source Files\event + + + Source Files\event + + + Source Files\ioctl + + + Source Files\ioctl + + + Source Files\ioctl + + + Source Files\aio + + + Source Files\aio + + + Source Files\aio + + + Source Files\aio + + + Source Files\aio + + + Source Files\aio + + + Source Files\aio + + + Source Files\db + + + Source Files\db + + + Source Files\db\mysql + + + Source Files\db\mysql + + + Source Files\db\memdb + + + Source Files\db\memdb + + + Source Files\db\memdb + + + Source Files\db\memdb + + + Source Files\db\memdb + + + Source Files\db\null + + + Source Files\db\null + + + Source Files\db\zdb + + + Source Files\db\zdb + + + Source Files\db\zdb + + + Source Files\db\zdb + + + Source Files\db\zdb + + + Source Files\db\zdb + + + Source Files\db\zdb + + + Source Files\unit_test + + + Source Files\unit_test + + + Source Files\unit_test + + + Source Files\unit_test + + + Source Files\unit_test + + + Source Files\unit_test + + + Source Files\unit_test + + + Source Files\unit_test + + + Source Files\unit_test + + + Source Files\master + + + Source Files\master + + + Source Files\master + + + Source Files\master + + + Source Files\master\template + + + Source Files\master\template + + + Source Files\master\template + + + Source Files\master\template + + + Source Files\master\template + + + Source Files\master\template + + + Source Files\master\template + + + Source Files\master\template + + + Source Files\master\framework + + + Source Files\master\framework + + + Source Files\master\framework + + + Source Files\master\framework + + + Source Files\master\framework + + + Source Files\master\framework + + + Source Files\master\framework + + + Source Files\master\framework + + + Source Files\master\framework + + + Source Files\master\framework + + + Source Files\master\framework\trigger + + + Source Files\master\framework\trigger + + + Source Files\master\framework\trigger + + + Source Files\master\framework\trigger + + + Source Files\master\daemon + + + Source Files\proctl + + + Source Files\proctl + + + Source Files\proctl + + + Source Files\proctl + + + Source Files\proctl + + + Source Files\init + + + Source Files\private + + + Source Files\private + + + Source Files\private + + + Source Files\private + + + Source Files\private + + + Source Files\json + + + Source Files\json + + + Source Files\json + + + Source Files\code + + + Source Files\code + + + Source Files\code + + + Source Files\code + + + Source Files\code + + + Source Files\code + + + Source Files\code + + + + + Source Files + + + + + Source Files + + + Source Files\stdlib + + + Source Files\stdlib\filedir + + + Source Files\stdlib\sys\unix + + + Source Files\stdlib\memory + + + Source Files\stdlib\memory + + + Source Files\stdlib\memory + + + Source Files\stdlib\memory + + + Source Files\stdlib\debug + + + Source Files\net + + + Source Files\net + + + Source Files\net\dns + + + Source Files\net\dns + + + Source Files\event + + + Source Files\event + + + Source Files\event + + + Source Files\event + + + Source Files\event + + + Source Files\event + + + Source Files\event + + + Source Files\event + + + Source Files\event + + + Source Files\event + + + Source Files\ioctl + + + Source Files\aio + + + Source Files\db\mysql + + + Source Files\db\mysql + + + Source Files\db\memdb + + + Source Files\db\memdb + + + Source Files\db\memdb + + + Source Files\db\memdb + + + Source Files\db\null + + + Source Files\db\null + + + Source Files\db\zdb + + + Source Files\master + + + Source Files\master + + + Source Files\master + + + Source Files\master\template + + + Source Files\master\framework + + + Source Files\master\framework + + + Source Files\master\framework\trigger + + + Source Files\proctl + + + Source Files\init + + + Source Files\private + + + Source Files\private + + + Source Files\private + + + Source Files\private + + + Source Files\private + + + Source Files\private + + + Source Files\private + + + Header Files + + + Header Files + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb\unix + + + Header Files\stdlb\unix + + + Header Files\stdlb\unix + + + Header Files\stdlb\unix + + + Header Files\stdlb\unix + + + Header Files\stdlb\unix + + + Header Files\stdlb\unix + + + Header Files\stdlb\unix + + + Header Files\stdlb\unix + + + Header Files\stdlb\unix + + + Header Files\stdlb\unix + + + Header Files\stdlb\unix + + + Header Files\net + + + Header Files\net + + + Header Files\net + + + Header Files\net + + + Header Files\net + + + Header Files\net + + + Header Files\net + + + Header Files\net + + + Header Files\net + + + Header Files\net + + + Header Files\net + + + Header Files\net + + + Header Files\net + + + Header Files\net + + + Header Files\net + + + Header Files\thread + + + Header Files\thread + + + Header Files\thread + + + Header Files\thread + + + Header Files\thread + + + Header Files\msg + + + Header Files\msg + + + Header Files\xml + + + Header Files\event + + + Header Files\event + + + Header Files\aio + + + Header Files\ioctl + + + Header Files\ioctl + + + Header Files\ioctl + + + Header Files\db + + + Header Files\db + + + Header Files\db + + + Header Files\db + + + Header Files\db + + + Header Files\db + + + Header Files\unit_test + + + Header Files\unit_test + + + Header Files\unit_test + + + Header Files\unit_test + + + Header Files\unit_test + + + Header Files\code + + + Header Files\code + + + Header Files\code + + + Header Files\code + + + Header Files\code + + + Header Files\code + + + Header Files\master + + + Header Files\master + + + Header Files\master + + + Header Files\master + + + Header Files\master + + + Header Files\master + + + Header Files\master + + + Header Files\master + + + Header Files\master + + + Header Files\master + + + Header Files\proctl + + + Header Files\experiment + + + Header Files\init + + + Header Files\json + + + Source Files\code + + + Source Files\code + + + Source Files\code + + + Source Files\code + + + + + doc + + + + diff --git a/lib_acl/lib_acl_vc2010.vcxproj.user b/lib_acl/lib_acl_vc2010.vcxproj.user new file mode 100644 index 000000000..ace9a86ac --- /dev/null +++ b/lib_acl/lib_acl_vc2010.vcxproj.user @@ -0,0 +1,3 @@ +锘 + + \ No newline at end of file diff --git a/lib_acl/lib_acl_vc2012.vcxproj b/lib_acl/lib_acl_vc2012.vcxproj new file mode 100644 index 000000000..0f8faad90 --- /dev/null +++ b/lib_acl/lib_acl_vc2012.vcxproj @@ -0,0 +1,672 @@ +锘 + + + + Debug + Win32 + + + DebugDll + Win32 + + + ReleaseDll + Win32 + + + Release + Win32 + + + + lib_acl + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + acl_lib + + + + + + DynamicLibrary + v110 + + + DynamicLibrary + v110 + + + StaticLibrary + false + MultiByte + v110 + + + StaticLibrary + false + MultiByte + v110 + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + .\ + .\Release\ + *.obj%3b*.ilk%3b*.pdb%3b*.tlb%3b*.tli%3b*.tlh%3b*.tmp%3b*.rsp%3b*.bat%3b*.map%3b*.pch%3b$(TargetPath) + .\ + .\Debug\ + *.obj%3b*.ilk%3b*.pdb%3b*.tlb%3b*.tli%3b*.tlh%3b*.tmp%3b*.rsp%3b*.bat%3b*.map%3b*.pch%3b$(TargetPath) + .\ + ReleaseDll\ + *.obj%3b*.ilk%3b*.pdb%3b*.tlb%3b*.tli%3b*.tlh%3b*.tmp%3b*.rsp%3b*.bat%3b*.map%3b*.pch%3b$(TargetPath) + false + .\ + DebugDll\ + *.obj%3b*.ilk%3b*.pdb%3b*.tlb%3b*.tli%3b*.tlh%3b*.tmp%3b*.rsp%3b*.bat%3b*.map%3b*.pch%3b$(TargetPath) + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + $(ProjectName)_vc2012 + $(ProjectName)_vc2012d + $(ProjectName)_d + + + + MaxSpeed + OnlyExplicitInline + Size + .\include;.;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;_MT;_CRT_SECURE_NO_WARNINGS;MS_VC;ACL_PREPARE_COMPILE;%(PreprocessorDefinitions) + true + MultiThreaded + true + Use + .\Release/acl_lib.pch + .\Release/ + .\Release/ + $(ProjectName)_vc2012.pdb + Level3 + true + ProgramDatabase + + + $(ProjectName)_vc2012.lib + true + MachineX86 + + + copy $(TargetName).lib ..\dist\lib\win32\$(TargetName).lib /Y +copy $(TargetName).pdb ..\dist\lib\win32\$(TargetName).pdb /Y + + + NDEBUG;%(PreprocessorDefinitions) + 0x0804 + + + + + Disabled + Size + .\include;.;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_LIB;_MT;MS_VC;ACL_PREPARE_COMPILE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + Use + $(TargetName).pch + .\Debug/ + .\Debug/ + $(ProjectName)_vc2012d.pdb + Level3 + true + ProgramDatabase + Default + + + $(ProjectName)_vc2012d.lib + true + MachineX86 + + + copy $(TargetName).lib ..\dist\lib\win32\$(TargetName).lib /Y +copy $(TargetName).pdb ..\dist\lib\win32\$(TargetName).pdb /Y + + + _DEBUG;%(PreprocessorDefinitions) + 0x0804 + + + + + .\include;.;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;_MT;_CRT_SECURE_NO_WARNINGS;ACL_PREPARE_COMPILE;MS_VC;ACL_DLL;ACL_EXPORTS;%(PreprocessorDefinitions) + MultiThreadedDLL + Use + $(ProjectName).pdb + ProgramDatabase + + + wsock32.lib;ws2_32.lib;IPHlpApi.Lib;%(AdditionalDependencies) + $(ProjectName).dll + MachineX86 + + + copy $(TargetName).lib ..\dist\lib\win32\$(TargetName).lib /Y +copy $(TargetName).dll ..\dist\lib\win32\$(TargetName).dll /Y +copy $(TargetName).pdb ..\dist\lib\win32\$(TargetName).pdb /Y + + + + + + Disabled + Size + .\include;.;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_LIB;_MT;_CRT_SECURE_NO_WARNINGS;MS_VC;ACL_DLL;ACL_EXPORTS;ACL_PREPARE_COMPILE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Use + $(ProjectName)_d.pdb + Level3 + ProgramDatabase + + + wsock32.lib;ws2_32.lib;IPHlpApi.Lib;%(AdditionalDependencies) + $(ProjectName)_d.dll + true + true + true + false + $(OutDir)$(TargetName).lib + MachineX86 + + + copy $(TargetName).lib ..\dist\lib\win32\$(TargetName).lib /Y +copy $(TargetName).dll ..\dist\lib\win32\$(TargetName).dll /Y +copy $(TargetName).pdb ..\dist\lib\win32\$(TargetName).pdb /Y + + + + + + Create + Create + Create + Create + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_acl/lib_acl_vc2012.vcxproj.filters b/lib_acl/lib_acl_vc2012.vcxproj.filters new file mode 100644 index 000000000..9c06f3ed2 --- /dev/null +++ b/lib_acl/lib_acl_vc2012.vcxproj.filters @@ -0,0 +1,1513 @@ +锘 + + + + {bfe7a9a3-0369-4d86-954a-0a3e67d1290e} + cpp;c;cxx;rc;def;r;odl;idl;hpj;bat + + + {cc389572-fee6-4643-a9af-85b1e2367054} + + + {34f0e452-7c64-43ae-ada7-1a5086e805c5} + + + {92f34b3b-3a7d-4093-9588-5e81a88db4cf} + + + {094be268-129e-4b49-b455-ec1ae3381e6f} + + + {f80bf918-aa94-4aae-a22f-76f6514f471a} + + + {0885a3f0-31b0-42cc-b5bd-bea215c80db2} + + + {ce3d4944-6dd1-418b-b2f7-5cde214b8aac} + + + {e2b0d0b7-ace0-4bb7-8c6f-2d34cc667791} + + + {70c495e7-d5ee-4921-8a3f-cf9ef215fae5} + + + {e31eab40-d204-4e30-9cea-c466c81bd858} + + + {12babb5a-4ccc-4b0e-9ce8-38c58649d3bb} + + + {93f23048-87ac-4874-b099-2fc6d210034a} + + + {da67f89a-e3e5-46e5-8e04-5b7da0ae466b} + + + {b879860a-bdbf-4f7a-9904-9cadb1be607b} + + + {ab7e8b79-4337-4406-b611-ebfe8dec8a8c} + + + {84458eeb-c970-48e9-89ce-e6e3bacd61d0} + + + {8ecdec21-169a-4ba2-a7bb-5b7def517ec5} + + + {b90e2e8a-57a3-4d73-b0a7-d0eba4712deb} + + + {844ca1c9-8bff-439e-b915-e45887eabde5} + + + {40fc0cb7-638e-4fe4-aca9-0304814e175f} + + + {d0609c6f-01f5-42f5-8835-c859c27ad6ea} + + + {b39c4127-4c0e-4506-b74e-1ed8b905a297} + + + {7af66f47-af08-436a-8032-464cd99502b8} + + + {12069517-4364-4c36-a10d-9ff46c05f3c7} + + + {4c1d9804-7881-41a8-83ed-222081d29a77} + + + {ea811014-788a-48fe-b707-a9b89b53bd06} + + + {6edd8537-3799-413f-b207-e2ce6c4517bf} + + + {fc860aba-9b94-4555-9ee1-ddf5bca931d4} + + + {01684461-568d-4c09-b1c0-1c4df0e12ae6} + + + {9b13391b-9bed-4d58-9e22-bc169844986e} + + + {35b92483-33d0-43ee-b8af-f8f93b8dcd3b} + + + {d249f3dc-3b3d-4453-96fd-87ceced12484} + + + {f721cf19-6c42-4e35-9e10-e1a681d6daed} + + + {d64b387b-872a-4d46-a8b8-e2ff2e084e29} + + + {02a7431c-7564-4276-925b-747dc3626119} + + + {2c232e54-a68f-4ef8-8e38-3b671d18b65c} + + + {142958f0-a535-495f-8415-d08b1f5adb6f} + + + {729d8b0e-de47-4916-a69a-b8cbe555d0ae} + h;hpp;hxx;hm;inl + + + {929ad0d6-4d30-4fd7-a07f-152d6044043a} + + + {872a9249-19b2-45ca-a49d-683e8750faea} + + + {77757d9e-a544-4dbb-9003-07d3214c022c} + + + {9c48db63-1706-4dbf-b270-fdb6ece0e265} + + + {388a38a0-dee2-49ff-8cad-b75d8959b35b} + + + {1b368af6-ce4d-4811-8063-14dff7a64020} + + + {c54eee41-e8f6-4659-9e21-c43f32efe6df} + + + {51551e5f-b371-48e8-b790-00c4f3e894f9} + + + {41299863-cdec-43fa-a837-3119cd21e6a1} + + + {18ea3512-9ecd-44bd-9fdb-a2336e93132a} + + + {1f760363-c10d-4e0a-8734-1adebdbb95c4} + + + {6cc2f181-647d-42e2-b6ba-0e66d7fdc7b1} + + + {460f8bf7-4788-483a-b278-e207cb9707dd} + + + {4a873376-2f34-482f-941f-3e85e52b96cb} + + + {9b3325d8-5f0a-4914-91f2-df60048c240f} + + + {5dd5951b-a552-43b0-96f2-53bee78c440e} + + + {1e3ecec3-12ea-4261-b557-a5ef8dbbd195} + + + {39ba72d7-77d0-4034-b7fd-0da49add37bd} + + + + + Source Files + + + Source Files\stdlib + + + Source Files\stdlib + + + Source Files\stdlib + + + Source Files\stdlib + + + Source Files\stdlib + + + Source Files\stdlib + + + Source Files\stdlib + + + Source Files\stdlib + + + Source Files\stdlib + + + Source Files\stdlib + + + Source Files\stdlib + + + Source Files\stdlib + + + Source Files\stdlib + + + Source Files\stdlib + + + Source Files\stdlib + + + Source Files\stdlib + + + Source Files\stdlib + + + Source Files\stdlib\iostuff + + + Source Files\stdlib\iostuff + + + Source Files\stdlib\iostuff + + + Source Files\stdlib\iostuff + + + Source Files\stdlib\iostuff + + + Source Files\stdlib\iostuff + + + Source Files\stdlib\iostuff + + + Source Files\stdlib\iostuff + + + Source Files\stdlib\iostuff + + + Source Files\stdlib\iostuff + + + Source Files\stdlib\iostuff + + + Source Files\stdlib\iostuff + + + Source Files\stdlib\iostuff + + + Source Files\stdlib\iostuff + + + Source Files\stdlib\iostuff + + + Source Files\stdlib\common + + + Source Files\stdlib\common + + + Source Files\stdlib\common + + + Source Files\stdlib\common + + + Source Files\stdlib\common + + + Source Files\stdlib\common + + + Source Files\stdlib\common + + + Source Files\stdlib\common + + + Source Files\stdlib\common + + + Source Files\stdlib\common + + + Source Files\stdlib\common + + + Source Files\stdlib\common + + + Source Files\stdlib\common + + + Source Files\stdlib\common + + + Source Files\stdlib\common + + + Source Files\stdlib\common + + + Source Files\stdlib\configure + + + Source Files\stdlib\configure + + + Source Files\stdlib\configure + + + Source Files\stdlib\filedir + + + Source Files\stdlib\filedir + + + Source Files\stdlib\filedir + + + Source Files\stdlib\filedir + + + Source Files\stdlib\filedir + + + Source Files\stdlib\sys + + + Source Files\stdlib\sys + + + Source Files\stdlib\sys + + + Source Files\stdlib\sys + + + Source Files\stdlib\sys + + + Source Files\stdlib\sys + + + Source Files\stdlib\sys + + + Source Files\stdlib\sys + + + Source Files\stdlib\sys + + + Source Files\stdlib\sys + + + Source Files\stdlib\sys + + + Source Files\stdlib\sys\unix + + + Source Files\stdlib\sys\unix + + + Source Files\stdlib\sys\unix + + + Source Files\stdlib\sys\unix + + + Source Files\stdlib\sys\unix + + + Source Files\stdlib\sys\unix + + + Source Files\stdlib\sys\unix + + + Source Files\stdlib\sys\unix + + + Source Files\stdlib\sys\unix + + + Source Files\stdlib\sys\unix + + + Source Files\stdlib\sys\unix + + + Source Files\stdlib\sys\unix + + + Source Files\stdlib\string + + + Source Files\stdlib\string + + + Source Files\stdlib\string + + + Source Files\stdlib\string + + + Source Files\stdlib\string + + + Source Files\stdlib\string + + + Source Files\stdlib\string + + + Source Files\stdlib\string + + + Source Files\stdlib\string + + + Source Files\stdlib\string + + + Source Files\stdlib\memory + + + Source Files\stdlib\memory + + + Source Files\stdlib\memory + + + Source Files\stdlib\memory + + + Source Files\stdlib\memory + + + Source Files\stdlib\memory + + + Source Files\stdlib\memory + + + Source Files\stdlib\memory + + + Source Files\stdlib\memory + + + Source Files\stdlib\memory + + + Source Files\stdlib\memory + + + Source Files\stdlib\memory + + + Source Files\stdlib\debug + + + Source Files\stdlib\debug + + + Source Files\net + + + Source Files\net + + + Source Files\net + + + Source Files\net + + + Source Files\net + + + Source Files\net + + + Source Files\net + + + Source Files\net + + + Source Files\net + + + Source Files\net\listen + + + Source Files\net\listen + + + Source Files\net\listen + + + Source Files\net\listen + + + Source Files\net\connect + + + Source Files\net\connect + + + Source Files\net\connect + + + Source Files\net\connect + + + Source Files\net\connect + + + Source Files\net\dns + + + Source Files\net\dns + + + Source Files\net\dns + + + Source Files\net\dns + + + Source Files\net\dns + + + Source Files\net\dns + + + Source Files\thread + + + Source Files\thread + + + Source Files\thread + + + Source Files\thread + + + Source Files\thread + + + Source Files\thread + + + Source Files\msg + + + Source Files\msg + + + Source Files\xml + + + Source Files\xml + + + Source Files\xml + + + Source Files\event + + + Source Files\event + + + Source Files\event + + + Source Files\event + + + Source Files\event + + + Source Files\event + + + Source Files\event + + + Source Files\event + + + Source Files\event + + + Source Files\event + + + Source Files\event + + + Source Files\event + + + Source Files\event + + + Source Files\event + + + Source Files\event + + + Source Files\event + + + Source Files\event + + + Source Files\event + + + Source Files\event + + + Source Files\ioctl + + + Source Files\ioctl + + + Source Files\ioctl + + + Source Files\aio + + + Source Files\aio + + + Source Files\aio + + + Source Files\aio + + + Source Files\aio + + + Source Files\aio + + + Source Files\aio + + + Source Files\db + + + Source Files\db + + + Source Files\db\mysql + + + Source Files\db\mysql + + + Source Files\db\memdb + + + Source Files\db\memdb + + + Source Files\db\memdb + + + Source Files\db\memdb + + + Source Files\db\memdb + + + Source Files\db\null + + + Source Files\db\null + + + Source Files\db\zdb + + + Source Files\db\zdb + + + Source Files\db\zdb + + + Source Files\db\zdb + + + Source Files\db\zdb + + + Source Files\db\zdb + + + Source Files\db\zdb + + + Source Files\unit_test + + + Source Files\unit_test + + + Source Files\unit_test + + + Source Files\unit_test + + + Source Files\unit_test + + + Source Files\unit_test + + + Source Files\unit_test + + + Source Files\unit_test + + + Source Files\unit_test + + + Source Files\master + + + Source Files\master + + + Source Files\master + + + Source Files\master + + + Source Files\master\template + + + Source Files\master\template + + + Source Files\master\template + + + Source Files\master\template + + + Source Files\master\template + + + Source Files\master\template + + + Source Files\master\template + + + Source Files\master\template + + + Source Files\master\framework + + + Source Files\master\framework + + + Source Files\master\framework + + + Source Files\master\framework + + + Source Files\master\framework + + + Source Files\master\framework + + + Source Files\master\framework + + + Source Files\master\framework + + + Source Files\master\framework + + + Source Files\master\framework + + + Source Files\master\framework\trigger + + + Source Files\master\framework\trigger + + + Source Files\master\framework\trigger + + + Source Files\master\framework\trigger + + + Source Files\master\daemon + + + Source Files\proctl + + + Source Files\proctl + + + Source Files\proctl + + + Source Files\proctl + + + Source Files\proctl + + + Source Files\init + + + Source Files\private + + + Source Files\private + + + Source Files\private + + + Source Files\private + + + Source Files\private + + + Source Files\json + + + Source Files\json + + + Source Files\json + + + Source Files\code + + + Source Files\code + + + Source Files\code + + + Source Files\code + + + Source Files\code + + + Source Files\code + + + Source Files\code + + + + + Source Files + + + + + Source Files + + + Source Files\stdlib + + + Source Files\stdlib\filedir + + + Source Files\stdlib\sys\unix + + + Source Files\stdlib\memory + + + Source Files\stdlib\memory + + + Source Files\stdlib\memory + + + Source Files\stdlib\memory + + + Source Files\stdlib\debug + + + Source Files\net + + + Source Files\net + + + Source Files\net\dns + + + Source Files\net\dns + + + Source Files\event + + + Source Files\event + + + Source Files\event + + + Source Files\event + + + Source Files\event + + + Source Files\event + + + Source Files\event + + + Source Files\event + + + Source Files\event + + + Source Files\event + + + Source Files\ioctl + + + Source Files\aio + + + Source Files\db\mysql + + + Source Files\db\mysql + + + Source Files\db\memdb + + + Source Files\db\memdb + + + Source Files\db\memdb + + + Source Files\db\memdb + + + Source Files\db\null + + + Source Files\db\null + + + Source Files\db\zdb + + + Source Files\master + + + Source Files\master + + + Source Files\master + + + Source Files\master\template + + + Source Files\master\framework + + + Source Files\master\framework + + + Source Files\master\framework\trigger + + + Source Files\proctl + + + Source Files\init + + + Source Files\private + + + Source Files\private + + + Source Files\private + + + Source Files\private + + + Source Files\private + + + Source Files\private + + + Source Files\private + + + Header Files + + + Header Files + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb + + + Header Files\stdlb\unix + + + Header Files\stdlb\unix + + + Header Files\stdlb\unix + + + Header Files\stdlb\unix + + + Header Files\stdlb\unix + + + Header Files\stdlb\unix + + + Header Files\stdlb\unix + + + Header Files\stdlb\unix + + + Header Files\stdlb\unix + + + Header Files\stdlb\unix + + + Header Files\stdlb\unix + + + Header Files\stdlb\unix + + + Header Files\net + + + Header Files\net + + + Header Files\net + + + Header Files\net + + + Header Files\net + + + Header Files\net + + + Header Files\net + + + Header Files\net + + + Header Files\net + + + Header Files\net + + + Header Files\net + + + Header Files\net + + + Header Files\net + + + Header Files\net + + + Header Files\net + + + Header Files\thread + + + Header Files\thread + + + Header Files\thread + + + Header Files\thread + + + Header Files\thread + + + Header Files\msg + + + Header Files\msg + + + Header Files\xml + + + Header Files\event + + + Header Files\event + + + Header Files\aio + + + Header Files\ioctl + + + Header Files\ioctl + + + Header Files\ioctl + + + Header Files\db + + + Header Files\db + + + Header Files\db + + + Header Files\db + + + Header Files\db + + + Header Files\db + + + Header Files\unit_test + + + Header Files\unit_test + + + Header Files\unit_test + + + Header Files\unit_test + + + Header Files\unit_test + + + Header Files\code + + + Header Files\code + + + Header Files\code + + + Header Files\code + + + Header Files\code + + + Header Files\code + + + Header Files\master + + + Header Files\master + + + Header Files\master + + + Header Files\master + + + Header Files\master + + + Header Files\master + + + Header Files\master + + + Header Files\master + + + Header Files\master + + + Header Files\master + + + Header Files\proctl + + + Header Files\experiment + + + Header Files\init + + + Header Files\json + + + Source Files\code + + + Source Files\code + + + Source Files\code + + + Source Files\code + + + + + doc + + + + diff --git a/lib_acl/master/keep b/lib_acl/master/keep new file mode 100644 index 000000000..2fa992c0b --- /dev/null +++ b/lib_acl/master/keep @@ -0,0 +1 @@ +keep diff --git a/lib_acl/resource.h b/lib_acl/resource.h new file mode 100644 index 000000000..627209301 --- /dev/null +++ b/lib_acl/resource.h @@ -0,0 +1,14 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by lib_acl.rc + +// 新对象的下一些默认值 +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/lib_acl/src/acl_stdafx.c b/lib_acl/src/acl_stdafx.c new file mode 100644 index 000000000..09f15b61c --- /dev/null +++ b/lib_acl/src/acl_stdafx.c @@ -0,0 +1 @@ +#include "StdAfx.h" \ No newline at end of file diff --git a/lib_acl/src/aio/acl_aio.c b/lib_acl/src/aio/acl_aio.c new file mode 100644 index 000000000..382463ca7 --- /dev/null +++ b/lib_acl/src/aio/acl_aio.c @@ -0,0 +1,193 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_stdlib.h" +#include "net/acl_net.h" +#include "aio/acl_aio.h" + +#endif +#include "stdlib/acl_array.h" +#include "../event/events.h" +#include "aio.h" + +void acl_aio_check(ACL_AIO *aio) +{ + aio_delay_check(aio); +} + +void acl_aio_free(ACL_AIO *aio) +{ + acl_event_free(aio->event); + acl_array_free(aio->dead_streams, NULL); + acl_myfree(aio); +} + +ACL_AIO *acl_aio_create(int event_mode) +{ + return (acl_aio_create2(event_mode, 0)); +} + +ACL_AIO *acl_aio_create2(int event_mode, unsigned int nMsg) +{ + const char *myname = "acl_aio_create"; + char ebuf[256]; + ACL_AIO *aio; + + aio = acl_mycalloc(1, sizeof(ACL_AIO)); + if (aio == NULL) + acl_msg_fatal("%s: calloc error(%s)", + myname, acl_last_strerror(ebuf, sizeof(ebuf))); + +#ifdef ACL_MS_WINDOWS + aio->tid = acl_pthread_self(); +#endif + + aio->delay_sec = 1; + aio->delay_usec = 0; + aio->keep_read = 1; + aio->rbuf_size = 8192; + aio->event_mode = event_mode; + + switch (event_mode) { + case ACL_EVENT_KERNEL: + aio->event = acl_event_new_kernel(aio->delay_sec, aio->delay_usec); + break; + case ACL_EVENT_SELECT: + aio->event = acl_event_new_select(aio->delay_sec, aio->delay_usec); + break; + case ACL_EVENT_POLL: + aio->event = acl_event_new_poll(aio->delay_sec, aio->delay_usec); + break; + case ACL_EVENT_WMSG: + aio->event = acl_event_new_wmsg(nMsg); + break; + default: + acl_msg_fatal("%s(%d): event_mode(%d) not support", + myname, __LINE__, event_mode); + break; + } + aio->dead_streams = acl_array_create(aio->event->fdsize); + return (aio); +} + +int acl_aio_event_mode(ACL_AIO *aio) +{ + return (aio->event_mode); +} + +int acl_aio_get_keep_read(ACL_AIO *aio) +{ + if (aio) + return (aio->keep_read); + return (0); +} + +void acl_aio_set_keep_read(ACL_AIO *aio, int onoff) +{ + if (aio) + aio->keep_read = onoff; +} + +int acl_aio_get_delay_sec(ACL_AIO *aio) +{ + if (aio) + return (aio->delay_sec); + return (-1); +} + +int acl_aio_get_delay_usec(ACL_AIO *aio) +{ + if (aio) + return (aio->delay_usec); + return (-1); +} + +void acl_aio_set_delay_sec(ACL_AIO *aio, int delay_sec) +{ + if (aio) { + aio->delay_sec = delay_sec; + acl_event_set_delay_sec(aio->event, delay_sec); + } +} + +void acl_aio_set_delay_usec(ACL_AIO *aio, int delay_usec) +{ + if (aio) { + aio->delay_usec = delay_usec; + acl_event_set_delay_usec(aio->event, delay_usec); + } +} + +void acl_aio_loop(ACL_AIO *aio) +{ + if (aio == NULL || aio->event == NULL) + return; + + acl_event_loop(aio->event); + aio_delay_check(aio); +} + +ACL_EVENT *acl_aio_event(ACL_AIO *aio) +{ + if (aio) + return (aio->event); + return (NULL); +} + +void acl_aio_set_rbuf_size(ACL_AIO *aio, int rbuf_size) +{ + aio->rbuf_size = rbuf_size; +} + +/*---------------------------------------------------------------------------*/ + +acl_int64 acl_aio_request_timer(ACL_AIO *aio, ACL_AIO_TIMER_FN timer_fn, + void *context, acl_int64 idle_limit, int keep) +{ + const char *myname = "acl_aio_request_timer"; + + if (aio == NULL || aio->event == NULL || timer_fn == NULL) + acl_msg_fatal("%s: input invalid", myname); + + return (acl_event_request_timer(aio->event, timer_fn, context, + idle_limit, keep)); +} + +acl_int64 acl_aio_cancel_timer(ACL_AIO *aio, ACL_AIO_TIMER_FN timer_fn, void *context) +{ + const char *myname = "acl_aio_cancel_timer"; + + if (aio == NULL || aio->event == NULL || timer_fn == NULL) + acl_msg_fatal("%s: input invalid", myname); + + return (acl_event_cancel_timer(aio->event, timer_fn, context)); +} + +void acl_aio_keep_timer(ACL_AIO *aio, ACL_AIO_TIMER_FN callback, + void *context, int onoff) +{ + const char *myname = "acl_aio_keep_timer"; + + if (aio == NULL || aio->event == NULL) + acl_msg_fatal("%s: input invalid", myname); + acl_event_keep_timer(aio->event, callback, context, onoff); +} + +int acl_aio_timer_ifkeep(ACL_AIO *aio, ACL_AIO_TIMER_FN callback, void *context) +{ + const char *myname = "acl_aio_timer_ifkeep"; + + if (aio == NULL || aio->event == NULL) + acl_msg_fatal("%s: input invalid", myname); + return (acl_event_timer_ifkeep(aio->event, callback, context)); +} diff --git a/lib_acl/src/aio/acl_aio_connect.c b/lib_acl/src/aio/acl_aio_connect.c new file mode 100644 index 000000000..d0ff2e2c9 --- /dev/null +++ b/lib_acl/src/aio/acl_aio_connect.c @@ -0,0 +1,219 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif +#include "stdlib/acl_stdlib.h" +#include "net/acl_net.h" +#include "aio/acl_aio.h" + +#endif + +#include "../event/events_define.h" /* just for ACL_EVENTS_STYLE_IOCP define */ +#include "aio.h" + +#define WRITE_SAFE_ENABLE(x, callback) do { \ + if (((x)->flag & ACL_AIO_FLAG_ISWR) == 0) { \ + (x)->flag |= ACL_AIO_FLAG_ISWR; \ + acl_event_enable_write((x)->aio->event, (x)->stream, \ + (x)->timeout, callback, (x)); \ + } \ +} while (0) + +#define WRITE_SAFE_DIABLE(x) do { \ + if (((x)->flag & ACL_AIO_FLAG_ISWR) != 0) { \ + (x)->flag &= ~ACL_AIO_FLAG_ISWR; \ + acl_event_disable_write((x)->aio->event, (x)->stream); \ + } \ +} while (0) + +#ifdef ACL_MS_WINDOWS +static void __connect_notify_callback(int event_type, void *context); + +static void ConnectTimer(int event_type acl_unused, void *ctx) +{ + ACL_ASTREAM *astream = (ACL_ASTREAM*) ctx; + + if (astream->aio->event_mode != ACL_EVENT_WMSG) + acl_msg_fatal("event_mode(%d) != ACL_EVENT_WMSG(%d)", + astream->aio->event_mode, ACL_EVENT_WMSG); + __connect_notify_callback(ACL_EVENT_RW_TIMEOUT, ctx); +} +#endif + +static void __connect_notify_callback(int event_type, void *context) +{ + const char *myname = "__connect_notify_callback"; + ACL_ASTREAM *astream = (ACL_ASTREAM *) context; + int ret, err; + socklen_t errlen; + + WRITE_SAFE_DIABLE(astream); + + /* 先判断是否是超时导致返回 */ + if (event_type == ACL_EVENT_RW_TIMEOUT) { + ret = aio_timeout_callback(astream); + if (ret < 0) { + acl_aio_iocp_close(astream); + return; + } + /* 增加引用计数,以防异常关闭 */ + ret = aio_timeout_callback(astream); + if (ret < 0) { + acl_aio_iocp_close(astream); + } else if (astream->flag & ACL_AIO_FLAG_IOCP_CLOSE) { + /* 该流正处于IO延迟关闭状态,因为本次写IO已经成功完成, + * 所以需要完成流的IO延迟关闭过程 + */ + acl_aio_iocp_close(astream); + } else { + acl_event_enable_write(astream->aio->event, + astream->stream, astream->timeout, + __connect_notify_callback, astream); + } + return; + } + +#ifdef ACL_MS_WINDOWS + /* 如果是基于 win32 窗口消息的事件引擎则需要取消之前设置的超时定时器 */ + if (astream->aio->event_mode == ACL_EVENT_WMSG) + acl_aio_cancel_timer(astream->aio, ConnectTimer, astream); +#endif + + if (event_type == ACL_EVENT_XCPT) { + acl_aio_iocp_close(astream); + return; + } + + errlen = sizeof(err); + ret = getsockopt(ACL_VSTREAM_SOCK(acl_aio_vstream(astream)), + SOL_SOCKET, SO_ERROR, (char *) &err, &errlen); + if (ret >= 0) + acl_set_error(err); + +#if defined(ACL_SUNOS5) + /* + * Solaris 2.4's socket emulation doesn't allow you + * to determine the error from a failed non-blocking + * connect and just returns EPIPE. Create a fake + * error message for connect. -- fenner@parc.xerox.com + */ + if (ret < 0 && errno == EPIPE) + acl_set_error(ACL_ENOTCONN); +#endif + + if (errno == 0 || errno == ACL_EISCONN) { + event_type = ACL_EVENT_CONNECT; + } else if (event_type == ACL_EVENT_CONNECT) { + event_type = ACL_EVENT_XCPT; + } + + if (event_type == ACL_EVENT_XCPT) { + astream->flag |= ACL_AIO_FLAG_DEAD; + acl_aio_iocp_close(astream); + return; + } + + if (event_type != ACL_EVENT_CONNECT) + acl_msg_fatal("%s: unknown event type(%d)", myname, event_type); + + /* 将引用计数加1以防止在 connect_fn 内部调用了关闭过程,connect_fn + * 可通过返回-1,在回调返回后真正关闭 + */ + astream->nrefer++; + + if (astream->connect_handles) { + ACL_ITER iter; + ACL_FIFO connect_handles; + + /* XXX: 必须将各个回调句柄从回调队列中一一提出置入一个单独队列中, + * 因为 ACL_AIO 在回调过程中有可能发生嵌套,防止被重复调用 + */ + + acl_fifo_init(&connect_handles); + acl_foreach_reverse(iter, astream->connect_handles) { + AIO_CONNECT_HOOK *handle = (AIO_CONNECT_HOOK*) iter.data; + if (handle->disable) + continue; + acl_fifo_push(&connect_handles, handle); + } + + while (1) { + AIO_CONNECT_HOOK *handle = acl_fifo_pop(&connect_handles); + if (handle == NULL) + break; + ret = handle->callback(astream, handle->ctx); + if (ret != 0) { + astream->nrefer--; + if (ret < 0 || astream->flag & ACL_AIO_FLAG_IOCP_CLOSE) + acl_aio_iocp_close(astream); + return; + } + } + } + + astream->nrefer--; + + if (ret < 0) { + acl_aio_iocp_close(astream); + } else if ((astream->flag & ACL_AIO_FLAG_IOCP_CLOSE)) { + /* 之前该流已经被设置了IO完成延迟关闭标志位, + * 则再次启动IO完成延迟关闭过程 + */ + acl_aio_iocp_close(astream); + } +} + +ACL_ASTREAM *acl_aio_connect(ACL_AIO *aio, const char *addr, int timeout) +{ + const char *myname = "acl_aio_connect"; + ACL_ASTREAM *astream; + ACL_VSTREAM *cstream; + + if (aio == NULL || addr == NULL || *addr == 0) + acl_msg_fatal("%s: input invalid", myname); + +#ifdef ACL_EVENTS_STYLE_IOCP + if (aio->event_mode == ACL_EVENT_KERNEL) { + ACL_SOCKET connfd = WSASocket(AF_INET, SOCK_STREAM, + IPPROTO_TCP, 0, 0, WSA_FLAG_OVERLAPPED); + + cstream = acl_vstream_fdopen(connfd, ACL_VSTREAM_FLAG_RW, + aio->rbuf_size, timeout, ACL_VSTREAM_TYPE_SOCK); + acl_assert(cstream); + ACL_SAFE_STRNCPY(cstream->remote_addr, addr, sizeof(cstream->remote_addr)); + } else +#endif + cstream = acl_vstream_connect(addr, ACL_NON_BLOCKING, + 0, 0, aio->rbuf_size); + + if (cstream == NULL) { + acl_msg_error("%s: connect addr(%s) error", myname, addr); + return (NULL); + } + + + cstream->flag |= ACL_VSTREAM_FLAG_CONNECTING; + + astream = acl_aio_open(aio, cstream); + if (astream == NULL) { + acl_msg_fatal("%s: open astream error", myname); + } + +#ifdef ACL_MS_WINDOWS + if (timeout > 0 && aio->event_mode == ACL_EVENT_WMSG) + acl_aio_request_timer(aio, ConnectTimer, astream, timeout * 1000000, 0); +#endif + astream->error = acl_last_error(); + acl_aio_ctl(astream, ACL_AIO_CTL_TIMEOUT, timeout, ACL_AIO_CTL_END); + + WRITE_SAFE_ENABLE(astream, __connect_notify_callback); + return (astream); +} diff --git a/lib_acl/src/aio/acl_aio_listen.c b/lib_acl/src/aio/acl_aio_listen.c new file mode 100644 index 000000000..8c067355f --- /dev/null +++ b/lib_acl/src/aio/acl_aio_listen.c @@ -0,0 +1,119 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_stdlib.h" +#include "net/acl_net.h" +#include "aio/acl_aio.h" + +#endif + +#include "aio.h" + +static void __accept_notify_callback(int event_type, void *context) +{ + const char *myname = "__accept_notify_callback"; + ACL_ASTREAM *astream = (ACL_ASTREAM *) context; + ACL_ASTREAM *client; + ACL_VSTREAM *cstream; + int i; + + if (event_type == ACL_EVENT_XCPT) { + char ebuf[256]; + acl_msg_error("%s: listen error, sleep 1 second(%s)", + myname, acl_last_strerror(ebuf, sizeof(ebuf))); + sleep(1); + /* not reached here */ + return; + } else if (event_type == ACL_EVENT_RW_TIMEOUT) { + (void) aio_timeout_callback(astream); + return; + } + + if (event_type != ACL_EVENT_READ) + acl_msg_fatal("%s: unknown event type(%d)", myname, event_type); + + for (i = 0; i < astream->accept_nloop; i++) { + /* cstream read_buf 的长度 read_buf_len 继承自监听流的 read_buf_len */ + cstream = acl_vstream_accept(astream->stream, NULL, 0); + if (cstream == NULL) { + int ret; + char ebuf[256]; + + ret = acl_last_error(); + if (ret == ACL_EAGAIN || ret == ACL_ECONNABORTED) + break; + acl_msg_fatal("%s: listen exception, error(%s)", + myname, acl_last_strerror(ebuf, sizeof(ebuf))); + break; + } + + client = acl_aio_open(astream->aio, cstream); + if (astream->accept_fn(client, astream->context) < 0) { + char ebuf[256]; + + acl_aio_iocp_close(client); + acl_msg_warn("%s(%d): accept_fn return < 0, " + "close client and break, err(%s)", myname, + __LINE__, acl_last_strerror(ebuf, sizeof(ebuf))); + break; + } + } +} + +void acl_aio_accept(ACL_ASTREAM *astream) +{ + const char *myname = "acl_aio_accept"; + + if (astream == NULL) + acl_msg_fatal("%s: input invalid", myname); + + astream->flag |= ACL_AIO_FLAG_ISRD; + acl_event_enable_listen(astream->aio->event, astream->stream, + astream->timeout, __accept_notify_callback, astream); +} + +static void __listen_notify_callback(int event_type, void *context) +{ + const char *myname = "__listen_notify_callback"; + ACL_ASTREAM *astream = (ACL_ASTREAM *) context; + int i; + + if (event_type == ACL_EVENT_XCPT) { + char ebuf[256]; + acl_msg_error("%s: listen error, sleep 1 second(%s)", + myname, acl_last_strerror(ebuf, sizeof(ebuf))); + sleep(1); + return; + } else if (event_type == ACL_EVENT_RW_TIMEOUT) { + (void) aio_timeout_callback(astream); + return; + } + + for (i = 0; i < astream->accept_nloop; i++) { + if (astream->listen_fn(astream, astream->context) < 0) { + break; + } + } +} + +void acl_aio_listen(ACL_ASTREAM *astream) +{ + char myname[] = "acl_aio_listen"; + + if (astream == NULL) + acl_msg_fatal("%s: input invalid", myname); + + astream->flag |= ACL_AIO_FLAG_ISRD; + acl_event_enable_listen(astream->aio->event, astream->stream, + astream->timeout, __listen_notify_callback, astream); +} diff --git a/lib_acl/src/aio/acl_aio_read.c b/lib_acl/src/aio/acl_aio_read.c new file mode 100644 index 000000000..14167c76e --- /dev/null +++ b/lib_acl/src/aio/acl_aio_read.c @@ -0,0 +1,828 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_stdlib.h" +#include "net/acl_net.h" +#include "aio/acl_aio.h" + +#endif + +#include "../event/events.h" +#include "aio.h" + +#if 0 + +#define READ_SAFE_ENABLE(x, callback) do { \ + if (((x)->flag & ACL_AIO_FLAG_ISRD) == 0) { \ + (x)->flag |= ACL_AIO_FLAG_ISRD; \ + acl_event_enable_read((x)->aio->event, (x)->stream, \ + (x)->timeout, callback, (x)); \ + } \ +} while (0) + +#define READ_SAFE_DISABLE(x) do { \ + if (((x)->flag & ACL_AIO_FLAG_ISRD) != 0) { \ + (x)->flag &= ~ACL_AIO_FLAG_ISRD; \ + (x)->can_read_fn = NULL; \ + (x)->can_read_ctx = NULL; \ + acl_event_disable_read((x)->aio->event, (x)->stream); \ + } \ +} while (0) + +#else + +#define READ_SAFE_ENABLE(x, callback) do { \ + if (((x)->flag & ACL_AIO_FLAG_ISRD) == 0) { \ + (x)->flag |= ACL_AIO_FLAG_ISRD; \ + (x)->aio->event->enable_read_fn((x)->aio->event, \ + (x)->stream, (x)->timeout, callback, (x)); \ + } \ +} while (0) + +#define READ_SAFE_DISABLE(x) do { \ + if (((x)->flag & ACL_AIO_FLAG_ISRD) != 0) { \ + (x)->flag &= ~ACL_AIO_FLAG_ISRD; \ + (x)->can_read_fn = NULL; \ + (x)->can_read_ctx = NULL; \ + (x)->aio->event->disable_read_fn((x)->aio->event, (x)->stream); \ + } \ +} while (0) + +#endif + +# define READ_IOCP_CLOSE(x) do { \ + READ_SAFE_DISABLE((x)); \ + (x)->flag |= ACL_AIO_FLAG_IOCP_CLOSE; \ + acl_aio_iocp_close((x)); \ +} while (0) + +/* 统一的读事件处理回调接口 */ +static void main_read_callback(int event_type, void *context) +{ + ACL_ASTREAM *astream = (ACL_ASTREAM*) context; + + /* 调用 __gets_notify_callback/__read_notify_callback/__readn_notify_callback */ + + astream->event_read_callback(event_type, astream); +} + +static int read_complete_callback(ACL_ASTREAM *astream, char *data, int len) +{ + int ret = 0; + + /* 必须将缓存区复位,否则在下一次读事件(如有数据或出错)触发时, + * 因为上述的 if (astream->count <= n) {} 而导致 fatal + * ---2008.11.5, zsx + */ + /* 需要将缓冲区清空,以防被重复利用 */ + ACL_VSTRING_RESET(&astream->strbuf); + + /* 流引用计数加1,以防止流被异常关闭 */ + astream->nrefer++; + + if (astream->read_handles) { + ACL_ITER iter; + AIO_READ_HOOK *handle; + + /* XXX: 必须将各个回调句柄从回调队列中一一提出置入一个单独队列中, + * 因为 ACL_AIO 在回调过程中有可能发生嵌套,防止被重复调用 + */ + + while (1) { + handle = astream->read_handles->pop_back( + astream->read_handles); + if (handle == NULL) + break; + astream->reader_fifo.push_back(&astream->reader_fifo, handle); + } + + acl_foreach_reverse(iter, &astream->reader_fifo) { + handle = (AIO_READ_HOOK*) iter.data; + if (handle->disable) + continue; + ret = handle->callback(astream, handle->ctx, data, len); + if (ret != 0) { + astream->nrefer--; + return (ret); + } + } + } + + astream->nrefer--; + return (ret); +} + +/* 尝试性读一行数据 + * @param astream {ACL_ASTREAM*} + * @return {int} 返回值 + * -1: 表示出错,或希望关闭流 + * 0: 表示数据未准备好或用户设置了非连续读 + * 1: 表示数据已准备好,且已经调用过一次用户的回调函数且用户希望继续读 + */ + +static int __gets_peek(ACL_ASTREAM *astream) +{ + int n, ready = 0; + + n = astream->read_ready_fn(astream->stream, &astream->strbuf, &ready); + + if (n == ACL_VSTREAM_EOF) { + if ((astream->stream->errnum == ACL_EWOULDBLOCK + || astream->stream->errnum == ACL_EAGAIN)) + { + READ_SAFE_ENABLE(astream, main_read_callback); + return (0); + } + + /* XXX: 必须查看缓冲区中是否还有数据, + * 必须兼容数据读不够的情况! + */ + if (ACL_VSTRING_LEN(&astream->strbuf) > 0) { + char *ptr = acl_vstring_str(&astream->strbuf); + int len = ACL_VSTRING_LEN(&astream->strbuf); + + (void) read_complete_callback(astream, ptr, len); + } + /* 读出错,需要关闭流 */ + astream->flag |= ACL_AIO_FLAG_DEAD; + READ_IOCP_CLOSE(astream); + return (-1); + } else if (ready) { + char *ptr = acl_vstring_str(&astream->strbuf); + int len = ACL_VSTRING_LEN(&astream->strbuf); + + /* 回调用户的读行成功处理函数 */ + n = read_complete_callback(astream, ptr, len); + + /* 当用户希望关闭流或该流正处于延迟关闭状态,则需要调用 + * 流的IO延迟关闭过程 + */ + if (n < 0 || (astream->flag & ACL_AIO_FLAG_IOCP_CLOSE)) { + READ_IOCP_CLOSE(astream); + return (-1); + } else if (astream->keep_read == 0 + || (astream->flag & ACL_AIO_FLAG_ISRD) == 0) + { + return (0); + } + return (len); + } + + /* 未读到所要求的一行数据,继续监控该流的读行事件 */ + READ_SAFE_ENABLE(astream, main_read_callback); + return (0); +} + +/* 由事件监控过程回调触发的读行事件处理过程 */ + +static void __gets_notify_callback(int event_type, ACL_ASTREAM *astream) +{ + const char *myname = "__gets_notify_callback"; + + if (astream->keep_read == 0) + READ_SAFE_DISABLE(astream); + + if (event_type == ACL_EVENT_XCPT) { + /* 该流出错,但是有可能关闭的事件通知到达时流依然可读, + * 则应该保证读优先,直到把操作系统缓冲区中的数据读完 + * 为止,最后再处理关闭事件,即关闭流 + */ + int ret; + acl_non_blocking(ACL_VSTREAM_SOCK(astream->stream), + ACL_NON_BLOCKING); + do { + astream->stream->sys_read_ready = 1; + ret = __gets_peek(astream); + if (astream->keep_read == 0) + break; + } while (ret > 0); + READ_IOCP_CLOSE(astream); + return; + } else if (event_type == ACL_EVENT_RW_TIMEOUT) { + /* 读流超时,如果应用返回值大于等于0,则希望继续读, + * 如果返回值小于0则希望关闭流。有人会有这种需求吗? + */ + int ret = aio_timeout_callback(astream); + if (ret < 0) { + READ_IOCP_CLOSE(astream); + } else if (astream->flag & ACL_AIO_FLAG_IOCP_CLOSE) { + /* 该流正处于IO延迟关闭状态,因为本次读IO已经 + * 成功完成,所以需要完成流的IO延迟关闭过程 + */ + READ_IOCP_CLOSE(astream); + } else { + READ_SAFE_ENABLE(astream, main_read_callback); + } + + return; + } + + if (event_type != ACL_EVENT_READ) + acl_msg_fatal("%s: unknown event(%d)", myname, event_type); + + /* 尝试性地读数据 */ + while (1) { + if (__gets_peek(astream) <= 0 || astream->keep_read == 0) + break; + } +} + +/** + * 异步读一行数据 + * @param astream {ACL_ASTREAM*} + * @param nonl {int} 是否自动去掉尾部的 \r\n + */ +static void __aio_gets(ACL_ASTREAM *astream, int nonl) +{ + const char *myname = "__aio_gets"; + + if ((astream->flag & ACL_AIO_FLAG_DELAY_CLOSE)) + return; + if (astream->stream == NULL) + acl_msg_fatal("%s: astream->stream null", myname); + + /* 设置读流函数 */ + if (nonl) + astream->read_ready_fn = acl_vstream_gets_nonl_peek; + else + astream->read_ready_fn = acl_vstream_gets_peek; + + astream->event_read_callback = __gets_notify_callback; + + ACL_VSTRING_RESET(&astream->strbuf); + + /* 将嵌套计数加1,以防止嵌套层次太深而使栈溢出 */ + astream->read_nested++; + + /* 当满足回调条件时,有可能是从系统缓冲区中读取数据,也有可能从用户 + * 缓冲区读数据,对于持续读过程,当用户在回调中取消了读监听,则当用户 + * 缓冲区中无数据时,而无法监控该流的系统缓冲区,所以对于持续流的读 + * 操作,必须保证流处于读监听状态 + */ + if (astream->keep_read) + READ_SAFE_ENABLE(astream, main_read_callback); + + /* 如果嵌套调用次数小于阀值,则允许进行嵌套调用 */ + if (astream->read_nested < astream->read_nested_limit) { + /* 尝试性地读数据 */ + while (1) { + if (__gets_peek(astream) <= 0 || astream->keep_read == 0) + break; + } + astream->read_nested--; + return; + } + + /* 递归嵌套读次数达到了规定的阀值, + * 只需记个警告信息即可,因为有嵌套限制 + */ + if (acl_msg_verbose) + acl_msg_warn("%s: read_nested(%d) >= max(%d)", myname, + astream->read_nested, astream->read_nested_limit); + /* 否则,不允许继续嵌套,将读事件置于事件监控循环中,以减少嵌套层次 */ + + astream->read_nested--; + + /* 将该流的读事件置入事件监控中 */ + READ_SAFE_ENABLE(astream, main_read_callback); +} + +void acl_aio_gets(ACL_ASTREAM *astream) +{ + __aio_gets(astream, 0); +} + +void acl_aio_gets_nonl(ACL_ASTREAM *astream) +{ + __aio_gets(astream, 1); +} + +/* 尝试性读数据 + * @param astream {ACL_ASTREAM*} + * @return {int} 返回值 + * -1: 表示出错,或希望关闭流 + * 0: 表示数据未准备好或用户设置了非连续读 + * 1: 表示数据已准备好,且已经调用过一次用户的回调函数且用户希望继续读 + */ + +static int __read_peek(ACL_ASTREAM *astream) +{ + int n; + + /* 尝试性地读数据 */ + n = acl_vstream_read_peek(astream->stream, &astream->strbuf); + + if (n == ACL_VSTREAM_EOF) { + if (astream->stream->errnum == ACL_EAGAIN + || astream->stream->errnum == ACL_EWOULDBLOCK) + { + READ_SAFE_ENABLE(astream, main_read_callback); + return (0); + } + + /* XXX: 必须查看缓冲区中是否还有数据, 必须兼容数据读不够的情况! */ + if (ACL_VSTRING_LEN(&astream->strbuf) > 0) { + char *ptr = acl_vstring_str(&astream->strbuf); + int len = ACL_VSTRING_LEN(&astream->strbuf); + + (void) read_complete_callback(astream, ptr, len); + } + /* 读出错,需要关闭流 */ + astream->flag |= ACL_AIO_FLAG_DEAD; + READ_IOCP_CLOSE(astream); + return (-1); + } else if (n > 0) { + char *ptr = acl_vstring_str(&astream->strbuf); + int len = ACL_VSTRING_LEN(&astream->strbuf); + + /* 回调用户的读成功处理函数 */ + n = read_complete_callback(astream, ptr, len); + + /* 当用户希望关闭流或该流正处于延迟关闭状态,则需要调用 + * 流的IO延迟关闭过程 + */ + if (n < 0 || astream->flag & ACL_AIO_FLAG_IOCP_CLOSE) { + READ_IOCP_CLOSE(astream); + return (-1); + } else if (astream->keep_read == 0 + || (astream->flag & ACL_AIO_FLAG_ISRD) == 0) + { + return (0); + } + return (len); + } else { + /* 读数据不符合要求,继续监控该读事件 */ + READ_SAFE_ENABLE(astream, main_read_callback); + return (0); + } +} + +/* 由事件监控过程回调触发的读事件处理过程 */ + +static void __read_notify_callback(int event_type, ACL_ASTREAM *astream) +{ + const char *myname = "__read_notify_callback"; + + if (astream->keep_read == 0) + READ_SAFE_DISABLE(astream); + + if (event_type == ACL_EVENT_XCPT) { + /* 该流出错,但是有可能关闭的事件通知到达时流依然可读, + * 则应该保证读优先,直到把操作系统缓冲区中的数据读完 + * 为止,最后再处理关闭事件,即关闭流 + */ + int ret; + acl_non_blocking(ACL_VSTREAM_SOCK(astream->stream), + ACL_NON_BLOCKING); + do { + astream->stream->sys_read_ready = 1; + ret = __read_peek(astream); + } while (ret > 0); + READ_IOCP_CLOSE(astream); + return; + } else if (event_type == ACL_EVENT_RW_TIMEOUT) { + /* 读流超时,如果应用返回值大于等于0,则希望继续读, + * 如果返回值小于0则希望关闭流。有人会有这种需求吗? + */ + int ret = aio_timeout_callback(astream); + if (ret < 0) { + /* 用户希望关闭流 */ + READ_IOCP_CLOSE(astream); + } else if (astream->flag & ACL_AIO_FLAG_IOCP_CLOSE) { + /* 该流正处于IO延迟关闭状态,因为本次读IO已经成功完成, + * 所以需要完成流的IO延迟关闭过程 + */ + READ_IOCP_CLOSE(astream); + } else { + READ_SAFE_ENABLE(astream, main_read_callback); + } + return; + } + + if (event_type != ACL_EVENT_READ) + acl_msg_fatal("%s: unknown event(%d)", myname, event_type); + + /* 尝试性地读数据 */ + while (1) { + if (__read_peek(astream) <= 0 || astream->keep_read == 0) + break; + } +} + +void acl_aio_read(ACL_ASTREAM *astream) +{ + const char *myname = "acl_aio_read"; + + if ((astream->flag & ACL_AIO_FLAG_DELAY_CLOSE)) + return; + if (astream->stream == NULL) + acl_msg_fatal("%s: astream(%lx)->stream null", + myname, (long) astream); + + astream->event_read_callback = __read_notify_callback; + /* XXX: 必须将缓冲区重置 */ + ACL_VSTRING_RESET(&astream->strbuf); + + /* 当满足回调条件时,有可能是从系统缓冲区中读取数据,也有可能从用户 + * 缓冲区读数据,对于持续读过程,当用户在回调中取消了读监听,则当用户 + * 缓冲区中无数据时,而无法监控该流的系统缓冲区,所以对于持续流的读 + * 操作,必须保证流处于读监听状态 + */ + if (astream->keep_read) + READ_SAFE_ENABLE(astream, main_read_callback); + + /* 将嵌套计数加1,以防止嵌套层次太深而使栈溢出 */ + astream->read_nested++; + + /* 如果嵌套调用次数小于阀值,则允许进行嵌套调用 */ + if (astream->read_nested < astream->read_nested_limit) { + /* 尝试性地读数据 */ + while (1) { + if (__read_peek(astream) <= 0 || astream->keep_read == 0) + break; + } + astream->read_nested--; + return; + } + + /* 递归嵌套读次数达到了规定的阀值,只需记个警告信息,因为有嵌套限制 */ + if (acl_msg_verbose) + acl_msg_warn("%s: read_nested(%d) >= max(%d)", myname, + astream->read_nested, astream->read_nested_limit); + + /* 否则,不允许继续嵌套,将读事件置于事件监控循环中,减少嵌套层次 */ + + astream->read_nested--; + + /* 将该流的读事件置入事件监控中 */ + READ_SAFE_ENABLE(astream, main_read_callback); +} + +/* 尝试性读规定数据量的数据 + * @param astream {ACL_ASTREAM*} + * @return {int} 返回值 + * -1: 表示出错,或希望关闭流 + * 0: 表示数据未准备好或用户设置了非连续读 + * 1: 表示数据已准备好,且已经调用过一次用户的回调函数且用户希望继续读 + */ + +static int __readn_peek(ACL_ASTREAM *astream) +{ + const char *myname = "__readn_peek"; + int n, ready = 0; + + n = ACL_VSTRING_LEN(&astream->strbuf); + + if (astream->count <= n) + acl_msg_fatal("%s: count(%d) < strlen(%d), read_netsted(%d)", + myname, astream->count, n, astream->read_nested); + + /* 尝试性地读数据 */ + n = acl_vstream_readn_peek(astream->stream, &astream->strbuf, + astream->count - n, &ready); + if (n == ACL_VSTREAM_EOF) { + if (astream->stream->errnum == ACL_EAGAIN + || astream->stream->errnum == ACL_EWOULDBLOCK) + { + READ_SAFE_ENABLE(astream, main_read_callback); + return (0); + } + /* XXX: 查看缓冲区中是否还有数据, 必须兼容数据读不够的情况! */ + if (ACL_VSTRING_LEN(&astream->strbuf) > 0) { + char *ptr = acl_vstring_str(&astream->strbuf); + int len = ACL_VSTRING_LEN(&astream->strbuf); + + acl_msg_warn("%s: nneed(%d), nread(%d)," + " read_netsted(%d), nrefer(%d)", + myname, astream->count, len, + astream->read_nested, astream->nrefer); + + (void) read_complete_callback(astream, ptr, len); + } + /* 读出错或读关闭,需要关闭流 */ + astream->flag |= ACL_AIO_FLAG_DEAD; + READ_IOCP_CLOSE(astream); + return (-1); + } else if (ready) { + /* ok, 已经满足读条件,即已经获得了所要求数据长度的数据 */ + char *ptr = acl_vstring_str(&astream->strbuf); + int len = ACL_VSTRING_LEN(&astream->strbuf); + + if (len != astream->count) + acl_msg_fatal("%s: len: %d != count: %d", + myname, len, astream->count); + + /* 回调用户的读成功处理函数 */ + n = read_complete_callback(astream, ptr, len); + if (n < 0 || astream->flag & ACL_AIO_FLAG_IOCP_CLOSE) { + READ_IOCP_CLOSE(astream); + return (-1); + } else if (astream->keep_read == 0 + || (astream->flag & ACL_AIO_FLAG_ISRD) == 0) + { + return (0); + } + return (len); + } else { + /* 读数据不符合要求,继续监控该读事件 */ + READ_SAFE_ENABLE(astream, main_read_callback); + return (0); + } +} + +/* 读事件触发回调处理函数 */ + +static void __readn_notify_callback(int event_type, ACL_ASTREAM *astream) +{ + const char *myname = "__readn_notify_callback"; + int n; + + if (astream->keep_read == 0) + READ_SAFE_DISABLE(astream); + + if (event_type == ACL_EVENT_XCPT) { + /* 该流出错,但是有可能关闭的事件通知到达时流依然可读, + * 则应该保证读优先,直到把操作系统缓冲区中的数据读完 + * 为止,最后再处理关闭事件,即关闭流 + */ + int ret; + acl_non_blocking(ACL_VSTREAM_SOCK(astream->stream), + ACL_NON_BLOCKING); + do { + astream->stream->sys_read_ready = 1; + ret = __readn_peek(astream); + } while (astream->keep_read && ret > 0); + READ_IOCP_CLOSE(astream); + return; + } else if (event_type == ACL_EVENT_RW_TIMEOUT) { + /* 读流超时,如果应用返回值大于等于0,则希望继续读, + * 如果返回值小于0则希望关闭流。有人会有这种需求吗? + */ + n = aio_timeout_callback(astream); + + if (n < 0) { + READ_IOCP_CLOSE(astream); + } else if (astream->flag & ACL_AIO_FLAG_IOCP_CLOSE) { + /* 该流正处于IO延迟关闭状态,因为本次读IO已经成功完成, + * 所以需要完成流的IO延迟关闭过程 + */ + READ_IOCP_CLOSE(astream); + } else { + READ_SAFE_ENABLE(astream, main_read_callback); + } + return; + } + + if (event_type != ACL_EVENT_READ) + acl_msg_fatal("%s: unknown event type(%d)", myname, event_type); + if (astream->stream == NULL) + acl_msg_fatal("%s: stream null", myname); + + while (1) { + if (__readn_peek(astream) <= 0 || astream->keep_read == 0) + break; + } +} + +void acl_aio_readn(ACL_ASTREAM *astream, int count) +{ + const char *myname = "acl_aio_readn"; + + if ((astream->flag & ACL_AIO_FLAG_DELAY_CLOSE)) + return; + if (count <= 0) + acl_msg_fatal("%s: count(%d) <= 0", myname, count); + + /* 设置回调函数 */ + astream->event_read_callback = __readn_notify_callback; + /* count 表示用户希望读的数据总长度 */ + astream->count = count; + + ACL_VSTRING_RESET(&astream->strbuf); + + /* 当满足回调条件时,有可能是从系统缓冲区中读取数据,也有可能从用户 + * 缓冲区读数据,对于持续读过程,当用户在回调中取消了读监听,则当用户 + * 缓冲区中无数据时,而无法监控该流的系统缓冲区,所以对于持续流的读 + * 操作,必须保证流处于读监听状态 + */ + if (astream->keep_read) + READ_SAFE_ENABLE(astream, main_read_callback); + + /* 将嵌套计数加1,以防止嵌套层次太深而使栈溢出 */ + astream->read_nested++; + + /* 如果嵌套调用次数小于阀值,则允许进行嵌套调用 */ + if (astream->read_nested < astream->read_nested_limit) { + /* 尝试性地读数据 */ + while (1) { + if (__readn_peek(astream) <= 0 || astream->keep_read == 0) + break; + } + astream->read_nested--; + return; + } + + /* 递归嵌套读次数达到了规定的阀值,只需记个警告信息,因为有嵌套限制 */ + if (acl_msg_verbose) + acl_msg_warn("%s: read_nested(%d) >= max(%d)", myname, + astream->read_nested, astream->read_nested_limit); + + /* 否则,不允许继续嵌套,将读事件置于事件监控循环中,减少嵌套层次 */ + + astream->read_nested--; + + /* 将该流的读事件置入事件监控中 */ + READ_SAFE_ENABLE(astream, main_read_callback); +} + +ACL_VSTRING *acl_aio_gets_peek(ACL_ASTREAM *astream) +{ + int ready = 0; + + if ((astream->flag & ACL_AIO_FLAG_DELAY_CLOSE)) + return (NULL); + if (acl_vstream_gets_peek(astream->stream, + &astream->strbuf, &ready) == ACL_VSTREAM_EOF + && astream->stream->errnum != ACL_EAGAIN + && astream->stream->errnum != ACL_EWOULDBLOCK) + { + astream->flag |= ACL_AIO_FLAG_DEAD; + if (ACL_VSTRING_LEN(&astream->strbuf) > 0) { + return (&astream->strbuf); + } else { + return (NULL); + } + } else if (ready) { + return (&astream->strbuf); + } else + return (NULL); +} + +ACL_VSTRING *acl_aio_gets_nonl_peek(ACL_ASTREAM *astream) +{ + int ready = 0; + + if ((astream->flag & ACL_AIO_FLAG_DELAY_CLOSE)) + return (NULL); + if (acl_vstream_gets_nonl_peek(astream->stream, + &astream->strbuf, &ready) == ACL_VSTREAM_EOF + && astream->stream->errnum != ACL_EAGAIN + && astream->stream->errnum != ACL_EWOULDBLOCK) + { + astream->flag |= ACL_AIO_FLAG_DEAD; + if (ACL_VSTRING_LEN(&astream->strbuf) > 0) { + return (&astream->strbuf); + } else { + return (NULL); + } + } else if (ready) { + return (&astream->strbuf); + } else + return (NULL); +} + +ACL_VSTRING *acl_aio_read_peek(ACL_ASTREAM *astream) +{ + int n; + + if ((astream->flag & ACL_AIO_FLAG_DELAY_CLOSE)) + return (NULL); + if ((n = acl_vstream_read_peek(astream->stream, + &astream->strbuf)) == ACL_VSTREAM_EOF + && astream->stream->errnum != ACL_EAGAIN + && astream->stream->errnum != ACL_EWOULDBLOCK) + { + astream->flag |= ACL_AIO_FLAG_DEAD; + if (ACL_VSTRING_LEN(&astream->strbuf) > 0) { + return (&astream->strbuf); + } else { + return (NULL); + } + } else if (n > 0) { + return (&astream->strbuf); + } else + return (NULL); +} + +ACL_VSTRING *acl_aio_readn_peek(ACL_ASTREAM *astream, int count) +{ + int ready = 0; + + if ((astream->flag & ACL_AIO_FLAG_DELAY_CLOSE)) + return (NULL); + if (acl_vstream_readn_peek(astream->stream, + &astream->strbuf, count, &ready) == ACL_VSTREAM_EOF + && astream->stream->errnum != ACL_EAGAIN + && astream->stream->errnum != ACL_EWOULDBLOCK) + { + astream->flag |= ACL_AIO_FLAG_DEAD; + if (ACL_VSTRING_LEN(&astream->strbuf) > 0) { + return (&astream->strbuf); + } else { + return (NULL); + } + } else if (ready) { + return (&astream->strbuf); + } else + return (NULL); +} + +int acl_aio_can_read(ACL_ASTREAM *astream) +{ + return (acl_vstream_can_read(astream->stream)); +} + +static void can_read_callback(int event_type, void *context) +{ + ACL_ASTREAM *astream = (ACL_ASTREAM*) context; + + if (astream->keep_read == 0) + READ_SAFE_DISABLE(astream); + + if (event_type == ACL_EVENT_XCPT) { + READ_IOCP_CLOSE(astream); + return; + } else if (event_type == ACL_EVENT_RW_TIMEOUT) { + int ret = aio_timeout_callback(astream); + if (ret < 0) { + READ_IOCP_CLOSE(astream); + } else if (astream->flag & ACL_AIO_FLAG_IOCP_CLOSE) { + /* 该流正处于IO延迟关闭状态,因为本次读IO已经成功完成, + * 所以需要完成流的IO延迟关闭过程 + */ + READ_IOCP_CLOSE(astream); + } else { + READ_SAFE_ENABLE(astream, can_read_callback); + } + return; + } + + astream->nrefer++; + if (astream->can_read_fn(astream, astream->can_read_ctx) < 0) { + astream->nrefer--; + READ_IOCP_CLOSE(astream); + } else if (astream->flag & ACL_AIO_FLAG_IOCP_CLOSE) { + astream->nrefer--; + READ_IOCP_CLOSE(astream); + } else { + astream->nrefer--; + } +} + +void acl_aio_enable_read(ACL_ASTREAM *astream, + ACL_AIO_NOTIFY_FN can_read_fn, void *context) +{ + int ret; + + if ((astream->flag & ACL_AIO_FLAG_DELAY_CLOSE)) + return; + + astream->can_read_fn = can_read_fn; + astream->can_read_ctx = context; + + ++astream->read_nested; + + if ((ret = acl_vstream_can_read(astream->stream)) == ACL_VSTREAM_EOF) { + READ_IOCP_CLOSE(astream); + astream->flag |= ACL_AIO_FLAG_DEAD; + } else if (ret > 0 && astream->read_nested < astream->read_nested_limit) { + can_read_callback(ACL_EVENT_READ, astream); + } else { + READ_SAFE_ENABLE(astream, can_read_callback); + } + + --astream->read_nested; +} + +void acl_aio_disable_read(ACL_ASTREAM *astream) +{ + if ((astream->flag & ACL_AIO_FLAG_ISRD) == 0) + return; + astream->flag &= ~ACL_AIO_FLAG_ISRD; + astream->can_read_fn = NULL; + astream->can_read_ctx = NULL; + if (astream->stream) + acl_event_disable_read(astream->aio->event, astream->stream); +} + +int acl_aio_isrset(ACL_ASTREAM *astream) +{ + const char *myname = "acl_aio_isrset"; + + if (astream == NULL) + acl_msg_fatal("%s: input invalid", myname); + if (astream->stream == NULL) + return (0); + + return (acl_event_isrset(astream->aio->event, astream->stream)); +} diff --git a/lib_acl/src/aio/acl_aio_stream.c b/lib_acl/src/aio/acl_aio_stream.c new file mode 100644 index 000000000..8db311977 --- /dev/null +++ b/lib_acl/src/aio/acl_aio_stream.c @@ -0,0 +1,830 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_stdlib.h" +#include "thread/acl_pthread.h" +#include "net/acl_net.h" +#include "aio/acl_aio.h" + +#endif +#include "stdlib/acl_array.h" +#include "../event/events.h" +#include "aio.h" + +static int accept_callback(ACL_ASTREAM *astream acl_unused, void *context acl_unused) +{ + const char *myname = "accept_callback"; + + acl_msg_fatal("%s: default accept_callback be called", myname); + return (-1); +} + +static int listen_callback(ACL_ASTREAM *astream acl_unused, void *context acl_unused) +{ + const char *myname = "listen_callback"; + + acl_msg_fatal("%s: default listen_callback be called", myname); + return (-1); +} + +ACL_AIO *acl_aio_handle(ACL_ASTREAM *stream) +{ + if (stream == NULL) + return (NULL); + return (stream->aio); +} + +void acl_aio_set_ctx(ACL_ASTREAM *stream, void *ctx) +{ + if (stream) + stream->context = ctx; +} + +void *acl_aio_get_ctx(ACL_ASTREAM *stream) +{ + return (stream ? stream->context : NULL); +} + +ACL_ASTREAM *acl_aio_open(ACL_AIO *aio, ACL_VSTREAM *stream) +{ + const char *myname = "acl_aio_open"; + char ebuf[256]; + ACL_ASTREAM *astream; + + acl_non_blocking(ACL_VSTREAM_SOCK(stream), ACL_NON_BLOCKING); + + astream = acl_mymalloc(sizeof(ACL_ASTREAM)); + if (astream == NULL) + acl_msg_fatal("%s: calloc error(%s)", + myname, acl_last_strerror(ebuf, sizeof(ebuf))); + + astream->aio = aio; + astream->stream = stream; + stream->rw_timeout = 0; /* 防止在读时阻塞 */ + + acl_vstring_init(&astream->strbuf, __default_line_length); + astream->timeout = 0; + astream->nrefer = 0; + astream->flag = 0; + + /* for read */ + astream->read_nested = 0; + astream->read_nested_limit = __AIO_NESTED_MAX; + astream->read_ready_fn = NULL; + astream->count = 0; + astream->keep_read = aio->keep_read; /* 继承异步句柄的持续读标志 */ + + /* just for listen fd */ + if ((stream->type & ACL_VSTREAM_TYPE_LISTEN)) { + if (stream->read_buf == NULL) + stream->read_buf_len = aio->rbuf_size; + else + acl_msg_warn("%s(%d): stream->read_buf not null, fixed", + myname, __LINE__); + astream->accept_nloop = 1; + } + + /* for write */ + acl_fifo_init(&astream->write_fifo); + astream->write_left = 0; + astream->write_offset = 0; + astream->write_nested = 0; + astream->write_nested_limit = __AIO_NESTED_MAX; + + /* set default callback functions */ + astream->accept_fn = accept_callback; + astream->listen_fn = listen_callback; + astream->context = NULL; + + /* create callback link */ + astream->read_handles = acl_array_create(10); + astream->write_handles = acl_array_create(10); + astream->close_handles = acl_array_create(10); + astream->timeo_handles = acl_array_create(10); + astream->connect_handles = acl_array_create(10); + + acl_fifo_init(&astream->reader_fifo); + acl_fifo_init(&astream->writer_fifo); + + return (astream); +} + +void acl_aio_set_accept_nloop(ACL_ASTREAM *astream, int accept_nloop) +{ + astream->accept_nloop = accept_nloop; +} + +ACL_VSTREAM *acl_aio_cancel(ACL_ASTREAM *astream) +{ + ACL_VSTREAM *stream; + + stream = astream->stream; + stream->flag = 0; + acl_aio_clean_hooks(astream); + acl_myfree(astream); + return (stream); +} + +int acl_aio_refer_value(ACL_ASTREAM * astream) +{ + const char *myname = "acl_aio_refer_value"; + + if (astream == NULL) { + acl_msg_error("%s(%d): astream null", myname, __LINE__); + return (-1); + } + return (astream->nrefer); +} + +void acl_aio_refer(ACL_ASTREAM *astream) +{ + if (astream) + astream->nrefer++; +} + +void acl_aio_unrefer(ACL_ASTREAM *astream) +{ + if (astream) + astream->nrefer--; +} + +static void aio_disable_readwrite(ACL_AIO *aio, ACL_ASTREAM *astream) +{ + if (astream->stream == NULL) + return; + + if ((astream->flag & ACL_AIO_FLAG_ISRD) != 0) { + astream->flag &= ~ACL_AIO_FLAG_ISRD; + acl_event_disable_read(aio->event, astream->stream); + } + if ((astream->flag & ACL_AIO_FLAG_ISWR) != 0) { + astream->flag &= ~ACL_AIO_FLAG_ISWR; + acl_event_disable_write(aio->event, astream->stream); + } +} + +static void close_astream(ACL_ASTREAM *astream) +{ + if (astream->stream) { + if ((astream->flag & ACL_AIO_FLAG_ISRD) != 0) { + astream->flag &= ~ACL_AIO_FLAG_ISRD; + acl_event_disable_read(astream->aio->event, + astream->stream); + } + if ((astream->flag & ACL_AIO_FLAG_ISWR) != 0) { + astream->flag &= ~ACL_AIO_FLAG_ISWR; + acl_event_disable_write(astream->aio->event, + astream->stream); + } + acl_vstream_close(astream->stream); + } + acl_aio_clean_hooks(astream); + + /* bugfix: 在 acl_aio_clean_hooks 中并不会释放数组对象 --zsx, 2012.7.2 */ + acl_array_destroy(astream->read_handles, NULL); + acl_array_destroy(astream->write_handles, NULL); + acl_array_destroy(astream->close_handles, NULL); + acl_array_destroy(astream->timeo_handles, NULL); + acl_array_destroy(astream->connect_handles, NULL); + + acl_myfree(astream); +} + +static void aio_delay_close(ACL_ASTREAM *astream) +{ + if (astream->nrefer > 0) { + /* 如果该异步流对象的引用计数大于0,则只需要置标志位 */ + astream->flag |= ACL_AIO_FLAG_IOCP_CLOSE; + /* 放在延迟关闭队列中 */ + if ((astream->flag & ACL_AIO_FLAG_DELAY_CLOSE) == 0) { + astream->aio->dead_streams->push_back(astream->aio->dead_streams, + astream); + astream->flag |= ACL_AIO_FLAG_DELAY_CLOSE; + } + return; + } else if (astream->stream == NULL) { + /* 需要关闭该异步流对象 */ + aio_close_callback(astream); + close_astream(astream); + return; + } + + astream->flag &= ~ACL_AIO_FLAG_IOCP_CLOSE; + astream->nrefer++; + acl_assert(astream->nrefer > 0); + aio_close_callback(astream); + astream->nrefer--; + + /* 真正关闭异步流 */ + close_astream(astream); +} + +void aio_delay_check(ACL_AIO *aio) +{ + ACL_ASTREAM *astream; + + while (1) { + astream = (ACL_ASTREAM*) + aio->dead_streams->pop_back(aio->dead_streams); + if (astream == NULL) + break; + + aio_delay_close(astream); + } +} + +#define ACL_USE_EVENT_TIMER + +#ifdef ACL_MS_WINDOWS + +# ifdef ACL_USE_TLS_POOL + +static acl_pthread_key_t __aio_tls_key = ACL_TLS_OUT_OF_INDEXES; + +static VOID CALLBACK CloseTimer(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) +{ + const char *myname = "CloseTimer"; + ACL_AIO *tls_aio; + + KillTimer(hwnd, idEvent); + + if (__aio_tls_key == ACL_TLS_OUT_OF_INDEXES) + acl_msg_fatal("%s(%d): __aio_tls_key invalid", myname, __LINE__); + + tls_aio = acl_pthread_tls_get(&__aio_tls_key); + if (tls_aio == NULL) + acl_msg_fatal("%s(%d): get tls aio error(%s), tls_key: %d", + myname, __LINE__, acl_last_serror(), (int) __aio_tls_key); + aio_delay_check(tls_aio); +} + +# elif defined(ACL_USE_EVENT_TIMER) + +static void CloseTimer(int event_type acl_unused, void *ctx) +{ + ACL_AIO *aio = (ACL_AIO*) ctx; + + aio_delay_check(aio); + aio->timer_active = 0; +} + +# else + +static acl_pthread_key_t __aio_tls_key = ACL_TLS_OUT_OF_INDEXES; +static acl_pthread_once_t __aio_once_control = ACL_PTHREAD_ONCE_INIT; + +static VOID CALLBACK CloseTimer(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) +{ + const char *myname = "CloseTimer"; + ACL_AIO *tls_aio; + + KillTimer(hwnd, idEvent); + + if (__aio_tls_key == ACL_TLS_OUT_OF_INDEXES) + acl_msg_fatal("%s(%d): __aio_tls_key invalid", myname, __LINE__); + + tls_aio = acl_pthread_getspecific(__aio_tls_key); + if (tls_aio == NULL) + acl_msg_fatal("%s(%d): get tls aio error(%s), tls_key: %d", + myname, __LINE__, acl_last_serror(), (int) __aio_tls_key); + aio_delay_check(tls_aio); + tls_aio->timer_active = 0; +} + +static void finish_thread_aio(void *arg acl_unused) +{ + +} + +static void init_thread_aio(void) +{ + acl_pthread_key_create(&__aio_tls_key, finish_thread_aio); +} + +# endif /* ACL_USE_TLS_POOL */ + +#endif /* ACL_MS_WINDOWS */ + +/* 该函数非常关键,采用的IO完成时才关闭的策略,防止重复关闭 */ +void acl_aio_iocp_close(ACL_ASTREAM *astream) +{ + const char *myname = "acl_aio_iocp_close"; + ACL_ITER iter; + ACL_AIO *aio = astream->aio; + + if ((astream->flag & ACL_AIO_FLAG_DELAY_CLOSE)) + return; + if (!(astream->flag & ACL_AIO_FLAG_DEAD) + && (astream->flag & ACL_AIO_FLAG_ISWR)) + { + astream->flag |= ACL_AIO_FLAG_IOCP_CLOSE; + return; + } + + acl_foreach(iter, aio->dead_streams) { + ACL_ASTREAM *s = (ACL_ASTREAM*) iter.data; + if (s == astream) + { + acl_msg_fatal("%s(%d): flag: %d, size: %d", + myname, __LINE__, astream->flag, iter.size); + } + } + /* 放在延迟关闭队列中 */ + aio->dead_streams->push_back(aio->dead_streams, astream); + astream->flag |= ACL_AIO_FLAG_DELAY_CLOSE; + aio_disable_readwrite(aio, astream); +#ifdef ACL_MS_WINDOWS + +# ifdef ACL_USE_TLS_POOL + + if (aio->event_mode == ACL_EVENT_WMSG && !aio->timer_active) { + HWND hWnd = acl_event_wmsg_hwnd(aio->event); + ACL_AIO *tls_aio = acl_pthread_tls_get(&__aio_tls_key); + + acl_assert(hWnd != NULL); + if (__aio_tls_key == ACL_TLS_OUT_OF_INDEXES) + acl_msg_fatal("%s(%d): __tls_key invalid", myname, __LINE__); + if (tls_aio == NULL) + acl_pthread_tls_set(__aio_tls_key, aio, NULL); + else if (tls_aio != aio) + acl_msg_fatal("%s(%d): tls_aio != aio", myname, __LINE__); + aio->timer_active = 1; + SetTimer(hWnd, aio->tid, 1000, CloseTimer); + } +# elif defined(ACL_USE_EVENT_TIMER) + + if (aio->event_mode == ACL_EVENT_WMSG && !aio->timer_active) { + acl_event_request_timer(aio->event, CloseTimer, aio, 1000, 0); + aio->timer_active = 1; + } + +# else + + if (aio->event_mode == ACL_EVENT_WMSG && !aio->timer_active) { + HWND hWnd = acl_event_wmsg_hwnd(aio->event); + ACL_AIO *tls_aio; + + acl_assert(hWnd != NULL); + + (void) acl_pthread_once(&__aio_once_control, init_thread_aio); + + if (__aio_tls_key == ACL_TLS_OUT_OF_INDEXES) + acl_msg_fatal("%s(%d): __tls_key invalid", myname, __LINE__); + + tls_aio = acl_pthread_getspecific(__aio_tls_key); + if (tls_aio == NULL) + acl_pthread_setspecific(__aio_tls_key, aio); + else if (tls_aio != aio) + acl_msg_fatal("%s(%d): tls_aio != aio", myname, __LINE__); + + aio->timer_active = 1; + SetTimer(hWnd, aio->tid, 1, CloseTimer); + } + +# endif /* ACL_USE_TLS_POOL */ + +#endif /* ACL_MS_WINDOWS */ +} + +void acl_aio_add_read_hook(ACL_ASTREAM *astream, ACL_AIO_READ_FN callback, void *ctx) +{ + const char *myname = "acl_aio_add_read_hook"; + AIO_READ_HOOK *handle; + ACL_ITER iter; + + acl_assert(callback); + + acl_foreach(iter, &astream->reader_fifo) { + handle = (AIO_READ_HOOK *) iter.data; + if (handle->callback == callback) { + handle->disable = 0; + handle->ctx = ctx; + return; + } + } + + handle = acl_mymalloc(sizeof(AIO_READ_HOOK)); + handle->callback = callback; + handle->ctx = ctx; + handle->disable = 0; + if (acl_array_append(astream->read_handles, handle) < 0) + acl_msg_fatal("%s(%d), %s: add to array error", + __FILE__, __LINE__, myname); +} + +void acl_aio_add_write_hook(ACL_ASTREAM *astream, ACL_AIO_WRITE_FN callback, void *ctx) +{ + const char *myname = "acl_aio_add_write_hook"; + AIO_WRITE_HOOK *handle; + ACL_ITER iter; + + acl_assert(callback); + + acl_foreach(iter, &astream->writer_fifo) { + handle = (AIO_WRITE_HOOK *) iter.data; + if (handle->callback == callback) { + handle->disable = 0; + handle->ctx = ctx; + return; + } + } + + handle = acl_mymalloc(sizeof(AIO_WRITE_HOOK)); + handle->callback = callback; + handle->ctx = ctx; + handle->disable = 0; + if (acl_array_append(astream->write_handles, handle) < 0) + acl_msg_fatal("%s(%d), %s: add to array error", + __FILE__, __LINE__, myname); +} + +void acl_aio_add_close_hook(ACL_ASTREAM *astream, ACL_AIO_CLOSE_FN callback, void *ctx) +{ + const char *myname = "acl_aio_add_close_hook"; + AIO_CLOSE_HOOK *handle; + ACL_ITER iter; + + acl_assert(callback); + + acl_foreach(iter, astream->close_handles) { + handle = (AIO_CLOSE_HOOK *) iter.data; + if (handle->callback == callback) { + handle->disable = 0; + handle->ctx = ctx; + return; + } + } + + handle = acl_mymalloc(sizeof(AIO_CLOSE_HOOK)); + handle->callback = callback; + handle->ctx = ctx; + handle->disable = 0; + if (acl_array_append(astream->close_handles, handle) < 0) + acl_msg_fatal("%s(%d), %s: add to array error", + __FILE__, __LINE__, myname); +} + +void acl_aio_add_timeo_hook(ACL_ASTREAM *astream, ACL_AIO_TIMEO_FN callback, void *ctx) +{ + const char *myname = "acl_aio_add_timeo_hook"; + AIO_TIMEO_HOOK *handle; + ACL_ITER iter; + + acl_assert(callback); + + acl_foreach(iter, astream->timeo_handles) { + handle = (AIO_TIMEO_HOOK *) iter.data; + if (handle->callback == callback) { + handle->disable = 0; + handle->ctx = ctx; + return; + } + } + + handle = acl_mymalloc(sizeof(AIO_TIMEO_HOOK)); + handle->callback = callback; + handle->ctx = ctx; + handle->disable = 0; + if (acl_array_append(astream->timeo_handles, handle) < 0) + acl_msg_fatal("%s(%d), %s: add to array error", + __FILE__, __LINE__, myname); +} + +void acl_aio_add_connect_hook(ACL_ASTREAM *astream, ACL_AIO_CONNECT_FN callback, void *ctx) +{ + const char *myname = "acl_aio_add_connect_hook"; + AIO_CONNECT_HOOK *handle; + ACL_ITER iter; + + acl_assert(callback); + + acl_foreach(iter, astream->connect_handles) { + handle = (AIO_CONNECT_HOOK *) iter.data; + if (handle->callback == callback) { + handle->disable = 0; + handle->ctx = ctx; + return; + } + } + + handle = acl_mymalloc(sizeof(AIO_TIMEO_HOOK)); + handle->callback = callback; + handle->ctx = ctx; + handle->disable = 0; + if (acl_array_append(astream->connect_handles, handle) < 0) + acl_msg_fatal("%s(%d), %s: add to array error", + __FILE__, __LINE__, myname); +} + +void acl_aio_del_read_hook(ACL_ASTREAM *astream, ACL_AIO_READ_FN callback, void *ctx) +{ + ACL_ITER iter; + + acl_foreach(iter, astream->read_handles) { + AIO_READ_HOOK *handle = (AIO_READ_HOOK *) iter.data; + if (handle->callback == callback && handle->ctx == ctx) { + handle->disable = 1; + handle->ctx = NULL; + return; + } + } + acl_foreach(iter, &astream->reader_fifo) { + AIO_READ_HOOK *handle = (AIO_READ_HOOK*) iter.data; + if (handle->callback == callback && handle->ctx == ctx) { + handle->disable = 1; + handle->ctx = NULL; + break; + } + } +} + +void acl_aio_del_write_hook(ACL_ASTREAM *astream, ACL_AIO_WRITE_FN callback, void *ctx) +{ + ACL_ITER iter; + + acl_foreach(iter, astream->write_handles) { + AIO_WRITE_HOOK *handle = (AIO_WRITE_HOOK *) iter.data; + if (handle->callback == callback && handle->ctx == ctx) { + handle->disable = 1; + handle->ctx = NULL; + return; + } + } + acl_foreach(iter, &astream->writer_fifo) { + AIO_WRITE_HOOK *handle = (AIO_WRITE_HOOK*) iter.data; + if (handle->callback == callback && handle->ctx == ctx) { + handle->disable = 1; + handle->ctx = NULL; + break; + } + } +} + +void acl_aio_del_close_hook(ACL_ASTREAM *astream, ACL_AIO_CLOSE_FN callback, void *ctx) +{ + ACL_ITER iter; + + acl_foreach(iter, astream->close_handles) { + AIO_CLOSE_HOOK *handle = (AIO_CLOSE_HOOK *) iter.data; + if (handle->callback == callback && handle->ctx == ctx) { + handle->disable = 1; + handle->ctx = NULL; + break; + } + } +} + +void acl_aio_del_timeo_hook(ACL_ASTREAM *astream, ACL_AIO_TIMEO_FN callback, void *ctx) +{ + ACL_ITER iter; + + acl_foreach(iter, astream->timeo_handles) { + AIO_TIMEO_HOOK *handle = (AIO_TIMEO_HOOK *) iter.data; + if (handle->callback == callback && handle->ctx == ctx) { + handle->disable = 1; + handle->ctx = NULL; + break; + } + } +} + +void acl_aio_del_connect_hook(ACL_ASTREAM *astream, ACL_AIO_CONNECT_FN callback, void *ctx) +{ + ACL_ITER iter; + + acl_foreach(iter, astream->connect_handles) { + AIO_CONNECT_HOOK *handle = (AIO_CONNECT_HOOK *) iter.data; + if (handle->callback == callback && handle->ctx == ctx) { + handle->disable = 1; + handle->ctx = NULL; + break; + } + } +} + +static void free_handle(void *handle) +{ + acl_myfree(handle); +} + +void acl_aio_clean_read_hooks(ACL_ASTREAM *astream) +{ + acl_array_clean(astream->read_handles, free_handle); + while (1) { + AIO_READ_HOOK *handle = astream->reader_fifo.pop_back( + &astream->reader_fifo); + if (handle == NULL) + break; + free_handle(handle); + } + acl_vstring_free_buf(&astream->strbuf); +} + +void acl_aio_clean_write_hooks(ACL_ASTREAM *astream) +{ + acl_array_clean(astream->write_handles, free_handle); + while (1) { + AIO_WRITE_HOOK *handle = astream->writer_fifo.pop_back( + &astream->writer_fifo); + if (handle == NULL) + break; + free_handle(handle); + } + while (1) { + ACL_VSTRING *str = (ACL_VSTRING*) acl_fifo_pop( + &astream->write_fifo); + if (str == NULL) + break; + acl_vstring_free(str); + } +} + +void acl_aio_clean_close_hooks(ACL_ASTREAM *astream) +{ + acl_array_clean(astream->close_handles, free_handle); +} + +void acl_aio_clean_timeo_hooks(ACL_ASTREAM *astream) +{ + acl_array_clean(astream->timeo_handles, free_handle); +} + +void acl_aio_clean_connect_hooks(ACL_ASTREAM *astream) +{ + acl_array_clean(astream->connect_handles, free_handle); +} + +void acl_aio_clean_hooks(ACL_ASTREAM *astream) +{ + acl_aio_clean_read_hooks(astream); + acl_aio_clean_write_hooks(astream); + acl_aio_clean_close_hooks(astream); + acl_aio_clean_timeo_hooks(astream); + acl_aio_clean_connect_hooks(astream); +} + +void acl_aio_stream_set_keep_read(ACL_ASTREAM *astream, int onoff) +{ + astream->keep_read = onoff; +} + +int acl_aio_stream_get_keep_read(ACL_ASTREAM *astream) +{ + return (astream->keep_read); +} + +void acl_aio_ctl(ACL_ASTREAM *astream, int name, ...) +{ + const char *myname = "acl_aio_ctl"; + va_list ap; + ACL_AIO_READ_FN read_fn; + ACL_AIO_WRITE_FN write_fn; + ACL_AIO_ACCEPT_FN accept_fn; + ACL_AIO_LISTEN_FN listen_fn; + ACL_AIO_CONNECT_FN connect_fn; + ACL_AIO_TIMEO_FN timeo_fn; + ACL_AIO_CLOSE_FN close_fn; + ACL_VSTREAM *stream; + void *ctx; + + if (astream == NULL) { + acl_msg_error("%s: astream null", myname); + return; + } + + va_start(ap, name); + + for (; name != ACL_AIO_CTL_END; name = va_arg(ap, int)) { + switch (name) { + case ACL_AIO_CTL_ACCEPT_FN: + accept_fn = va_arg(ap, ACL_AIO_ACCEPT_FN); + if (accept_fn) + astream->accept_fn = accept_fn; + else + astream->accept_fn = accept_callback; + break; + case ACL_AIO_CTL_LISTEN_FN: + listen_fn = va_arg(ap, ACL_AIO_LISTEN_FN); + if (listen_fn) + astream->listen_fn = listen_fn; + else + astream->listen_fn = listen_callback; + break; + case ACL_AIO_CTL_CTX: + astream->context = va_arg(ap, void *); + break; + case ACL_AIO_CTL_TIMEOUT: + astream->timeout = va_arg(ap, int); + break; + case ACL_AIO_CTL_STREAM: + stream = va_arg(ap, ACL_VSTREAM*); + astream->stream = stream; + break; + case ACL_AIO_CTL_READ_NESTED: + astream->read_nested_limit = va_arg(ap, int); + if (astream->read_nested_limit < 0) + astream->read_nested_limit = 0; + break; + case ACL_AIO_CTL_WRITE_NESTED: + astream->write_nested_limit = va_arg(ap, int); + if (astream->write_nested_limit < 0) + astream->write_nested_limit = 0; + break; + case ACL_AIO_CTL_KEEP_READ: + astream->keep_read = va_arg(ap, int); + break; + case ACL_AIO_CTL_READ_HOOK_ADD: + read_fn = va_arg(ap, ACL_AIO_READ_FN); + ctx = va_arg(ap, void *); + acl_aio_add_read_hook(astream, read_fn, ctx); + break; + case ACL_AIO_CTL_READ_HOOK_DEL: + read_fn = va_arg(ap, ACL_AIO_READ_FN); + ctx = va_arg(ap, void *); + acl_aio_del_read_hook(astream, read_fn, ctx); + break; + case ACL_AIO_CTL_WRITE_HOOK_ADD: + write_fn = va_arg(ap, ACL_AIO_WRITE_FN); + ctx = va_arg(ap, void *); + acl_aio_add_write_hook(astream, write_fn, ctx); + break; + case ACL_AIO_CTL_WRITE_HOOK_DEL: + write_fn = va_arg(ap, ACL_AIO_WRITE_FN); + ctx = va_arg(ap, void *); + acl_aio_del_write_hook(astream, write_fn, ctx); + break; + case ACL_AIO_CTL_CLOSE_HOOK_ADD: + close_fn = va_arg(ap, ACL_AIO_CLOSE_FN); + ctx = va_arg(ap, void *); + acl_aio_add_close_hook(astream, close_fn, ctx); + break; + case ACL_AIO_CTL_CLOSE_HOOK_DEL: + close_fn = va_arg(ap, ACL_AIO_CLOSE_FN); + ctx = va_arg(ap, void *); + acl_aio_del_close_hook(astream, close_fn, ctx); + break; + case ACL_AIO_CTL_TIMEO_HOOK_ADD: + timeo_fn = va_arg(ap, ACL_AIO_TIMEO_FN); + ctx = va_arg(ap, void *); + acl_aio_add_timeo_hook(astream, timeo_fn, ctx); + break; + case ACL_AIO_CTL_TIMEO_HOOK_DEL: + timeo_fn = va_arg(ap, ACL_AIO_TIMEO_FN); + ctx = va_arg(ap, void *); + acl_aio_del_timeo_hook(astream, timeo_fn, ctx); + break; + case ACL_AIO_CTL_CONNECT_HOOK_ADD: + connect_fn = va_arg(ap, ACL_AIO_CONNECT_FN); + ctx = va_arg(ap, void *); + acl_aio_add_connect_hook(astream, connect_fn, ctx); + break; + case ACL_AIO_CTL_CONNECT_HOOK_DEL: + connect_fn = va_arg(ap, ACL_AIO_CONNECT_FN); + ctx = va_arg(ap, void *); + acl_aio_del_connect_hook(astream, connect_fn, ctx); + break; + default: + acl_msg_fatal("%s(%d): unknown name flag(%d)", + myname, __LINE__, name); + break; + } + } + + va_end(ap); +} + +ACL_VSTREAM *acl_aio_vstream(ACL_ASTREAM *astream) +{ + if (astream && astream->stream) + return (astream->stream); + + return (NULL); +} + +void acl_aio_disable_readwrite(ACL_ASTREAM *astream) +{ + acl_aio_disable_read(astream); + acl_aio_disable_write(astream); +} + +int acl_aio_isset(ACL_ASTREAM *astream) +{ + const char *myname = "acl_aio_isset"; + + if (astream == NULL) + acl_msg_fatal("%s: input invalid", myname); + else if (astream->stream == NULL) + return (0); + + return (acl_event_isset(astream->aio->event, astream->stream)); +} diff --git a/lib_acl/src/aio/acl_aio_write.c b/lib_acl/src/aio/acl_aio_write.c new file mode 100644 index 000000000..11036974b --- /dev/null +++ b/lib_acl/src/aio/acl_aio_write.c @@ -0,0 +1,599 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_stdlib.h" +#include "net/acl_net.h" +#include "aio/acl_aio.h" + +#endif + +#include "aio.h" + +#define WRITE_SAFE_ENABLE(x, callback) do { \ + if (((x)->flag & ACL_AIO_FLAG_ISWR) == 0) { \ + (x)->flag |= ACL_AIO_FLAG_ISWR; \ + acl_event_enable_write((x)->aio->event, (x)->stream, \ + (x)->timeout, callback, (x)); \ + } \ +} while (0) + +#define WRITE_SAFE_DIABLE(x) do { \ + if (((x)->flag & ACL_AIO_FLAG_ISWR) != 0) { \ + (x)->flag &= ~ACL_AIO_FLAG_ISWR; \ + (x)->can_write_fn = NULL; \ + (x)->can_write_ctx = NULL; \ + acl_event_disable_write((x)->aio->event, (x)->stream); \ + } \ +} while (0) + +#define WRITE_IOCP_CLOSE(x) do { \ + WRITE_SAFE_DIABLE((x)); \ + (x)->flag |= ACL_AIO_FLAG_IOCP_CLOSE; \ + acl_aio_iocp_close((x)); \ +} while (0) + +static int write_complete_callback(ACL_ASTREAM *astream) +{ + int ret = 0; + + /* 流引用计数加1,以防止流被异常关闭 */ + astream->nrefer++; + + if (astream->write_handles) { + ACL_ITER iter; + AIO_WRITE_HOOK *handle; + + /* XXX: 必须将各个回调句柄从回调队列中一一提出置入一个单独队列中, + * 因为 ACL_AIO 在回调过程中有可能发生嵌套,防止被重复调用 + */ + + while (1) { + handle = astream->write_handles->pop_back( + astream->write_handles); + if (handle == NULL) + break; + astream->writer_fifo.push_back(&astream->writer_fifo, handle); + } + + acl_foreach_reverse(iter, &astream->writer_fifo) { + handle = (AIO_WRITE_HOOK*) iter.data; + if (handle->disable) + continue; + + /* 回调写成功注册函数 */ + ret = handle->callback(astream, handle->ctx); + if (ret != 0) { + astream->nrefer--; + return (ret); + } + } + } + + astream->nrefer--; + return (ret); +} + +/* 尝试发送流写队列里的数据,返回值为写队列里还剩余的数据长度或写失败 */ + +static int __try_fflush(ACL_ASTREAM *astream) +{ + const char *myname = "__try_fflush"; + ACL_VSTRING *str; + const char *ptr; + int n, dlen; + int i = 0; + + /* 针对写队列,也许调用 writev 会更好,应该那个写的效率会更高些 --- zsx */ + + while (1) { + /* 提取流写队列的数据头部分 */ + str = acl_fifo_head(&astream->write_fifo); + if (str == NULL) { + /* 说明写队列已经为空 */ + if (astream->write_left != 0) + acl_msg_fatal("%s: write_left(%d) != 0", + myname, astream->write_left); + return (astream->write_left); + } + + /* 计算本数据块的长度及数据开始位置, write_offset 仅是本数据块的相对位置, + * 即相对于数据块的起始位置的相对长度,所以 dlen 仅是本数据块中在本次写 + * 操作需要被写的数据的长度;而 write_left 则是全局性的,是整个写队列的 + * 数据长度,需要将该这两个变量区分开,将来也许应该将 write_offset 也设 + * 定为全局性的。--- zsx :) + */ + + dlen = ACL_VSTRING_LEN(str) - astream->write_offset; + ptr = acl_vstring_str(str) + astream->write_offset; + /* 开始进行非阻塞式写操作 */ + n = acl_vstream_write(astream->stream, ptr, dlen); + if (n == ACL_VSTREAM_EOF) { + if (acl_last_error() != ACL_EAGAIN) { + astream->flag |= ACL_AIO_FLAG_DEAD; + return (-1); + } + /* 本次写操作未写入任务数据,仅需要返回剩余数据长度即可 */ + return (astream->write_left); + } + + /* 重新计算写队列里剩余数据的总长度 */ + astream->write_left -= n; + + if (n < dlen) { + /* 未能将本数据块的可写数据全部写入,所以需要重新计算该数据块的 + * 可写数据的相对偏移位置 + */ + astream->write_offset += n; + return (astream->write_left); + } + + /* 将本数据块从写队列中剔除并释放该数据块所占的内存 */ + + str = acl_fifo_pop(&astream->write_fifo); + acl_vstring_free(str); + + /* 重置 write_offset 以为写入下一个数据块做准备, 将来该变量 + * 作为写队列的相对偏移变量后会更好些. --- zsx + */ + astream->write_offset = 0; + + /* 如果本轮写队列操作的循环次数过多,则应返回,以给其它的数据连接 + * 可读写的机会, 别忘了,在单线程条件下进行非阻塞写时可能会有很多 + * 数据连接需要被处理,总之,数据面前大家平等:) + */ + if (++i >= 10) { + if (acl_msg_verbose) + acl_msg_warn("%s: write_left=%d, loop=%d", + myname, astream->write_left, i); + return (astream->write_left); + } + } +} + +/* 流出错或流可写时触发了流的写事件处理函数 */ + +static void __writen_notify_callback(int event_type, void *context) +{ + const char *myname = "__write_notify_callback"; + ACL_ASTREAM *astream = (ACL_ASTREAM *) context; + int nleft; + + WRITE_SAFE_DIABLE(astream); + + if (event_type == ACL_EVENT_XCPT) { + /* 流发生了错误,启动IO完成延迟关闭关闭 */ + WRITE_IOCP_CLOSE(astream); + return; + } else if (event_type == ACL_EVENT_RW_TIMEOUT) { + /* 写操作超时,如果用户的回调函数返回 -1则启动IO完成延迟关闭过程 */ + int ret; + + ret = aio_timeout_callback(astream); + + if (ret < 0) { + WRITE_IOCP_CLOSE(astream); + } else if (astream->flag & ACL_AIO_FLAG_IOCP_CLOSE) { + /* 该流正处于IO延迟关闭状态,因为本次写IO已经成功完成, + * 所以需要完成流的IO延迟关闭过程 + */ + WRITE_IOCP_CLOSE(astream); + } else { + /* 说明用户希望继续等待写事件 */ + WRITE_SAFE_ENABLE(astream, __writen_notify_callback); + } + return; + } + + if (event_type != ACL_EVENT_WRITE) + acl_msg_fatal("%s: unknown event type(%d)", myname, event_type); + + /* 尝试发送流的写队列里的数据 */ + nleft = __try_fflush(astream); + + if (nleft < 0) { + /* 尝试写失败则启动IO完成延迟过程 */ + WRITE_IOCP_CLOSE(astream); + } else if (nleft == 0) { + /* 之前流的写队列为空或已经成功清空了写队列里的所有数据 */ + int ret; + + ret = write_complete_callback(astream); + if (ret < 0) { + /* 用户希望关闭该流,则启动IO完成延迟关闭过程 */ + WRITE_IOCP_CLOSE(astream); + } else if (astream->flag & ACL_AIO_FLAG_IOCP_CLOSE) { + /* 之前该流已经被设置了IO完成延迟关闭标志位, + * 则再次启动IO完成延迟关闭过程 + */ + WRITE_IOCP_CLOSE(astream); + } + } else { + /* 说明写队列里的数据未发送完毕,需要再次发送,所以将写事件置入事件监控中 */ + WRITE_SAFE_ENABLE(astream, __writen_notify_callback); + } +} + +void acl_aio_writen(ACL_ASTREAM *astream, const char *data, int dlen) +{ + const char *myname = "acl_aio_writen"; + ACL_VSTRING *str; + int n; + + if ((astream->flag & (ACL_AIO_FLAG_DELAY_CLOSE | ACL_AIO_FLAG_DEAD))) + return; + + /* 将嵌套计数加1,以防止嵌套层次太深而使栈溢出 */ + astream->write_nested++; + + /* 如果嵌套调用次数小于阀值,则允许进行嵌套调用 */ + if (astream->write_nested < astream->write_nested_limit) { + /* 先尝试写流的写队列中的数据 */ + n = __try_fflush(astream); + + if (n < 0) { /* 说明尝试写失败,需要关闭流 */ + astream->write_nested--; + WRITE_IOCP_CLOSE(astream); + return; + } else if (n == 0) { + /* __try_fflush 返回的是队列中的数据已经清空, + * 本次可以真正调用一次写操作 + */ + n = acl_vstream_write(astream->stream, data, dlen); + if (n == ACL_VSTREAM_EOF) { + if (acl_last_error() != ACL_EAGAIN) { + astream->write_nested--; + WRITE_IOCP_CLOSE(astream); + astream->flag |= ACL_AIO_FLAG_DEAD; + return; + } + /* 如果未写任何数据且诊断该流的对等点并未关闭, + * 则将此次数据置入该流的写队列中 + */ + n = 0; + } else if (n == dlen) { /* 说明已经成功写入了全部的数据 */ + int ret; + + ret = write_complete_callback(astream); + if (ret < 0) { + /* 调用者希望关闭流 */ + WRITE_IOCP_CLOSE(astream); + } else if ((astream->flag & ACL_AIO_FLAG_IOCP_CLOSE)) { + /* 因为本次写IO已经成功完成,所以需要完成流的IO延迟关闭过程 */ + WRITE_IOCP_CLOSE(astream); + } + return; + } + /* 0 < n < dlen */ + /* 只是成功写入了部分流,n 表示还剩余的数据长度 */ + } else { + /* __try_fflush 并未全部写完写队列的所有的数据,所以也需要本次的数据 + * 全部加入流的写队列中 + */ + n = 0; + } + } else { + /* 递归嵌套写次数达到了规定的阀值,只需记个警告信息即可,因为有嵌套限制 */ + if (acl_msg_verbose) + acl_msg_warn("%s(%d): write_nested(%d) >= max(%d)", + myname, __LINE__, astream->write_nested, + astream->write_nested_limit); + n = 0; + } + + /* 否则,不允许继续嵌套,而是将写事件置于事件监控循环中,从而减少嵌套层次 */ + + astream->write_nested--; + + /* Notice: in acl_vstring_memcpy, vstring_extend should not be called! */ + + /* 将数据置入该流的写队列中 */ + + str = acl_vstring_alloc(dlen - n + 1); + acl_vstring_memcpy(str, data + n, dlen - n); + acl_fifo_push(&astream->write_fifo, str); + astream->write_left += dlen - n; + + /* 将该流的写事件置入事件监控中 */ + WRITE_SAFE_ENABLE(astream, __writen_notify_callback); +} + +void acl_aio_vfprintf(ACL_ASTREAM *astream, const char *fmt, va_list ap) +{ + const char *myname = "acl_aio_vfprintf"; + ACL_VSTRING *str; + int n = 0, len; + + if ((astream->flag & (ACL_AIO_FLAG_DELAY_CLOSE | ACL_AIO_FLAG_DEAD))) + return; + + str = acl_vstring_alloc(__default_line_length); + acl_vstring_vsprintf(str, fmt, ap); + + /* 将嵌套计数加1,以防止嵌套层次太深而使栈溢出 */ + astream->write_nested++; + + /* 如果嵌套调用次数小于阀值,则允许进行嵌套调用 */ + if (astream->write_nested < astream->write_nested_limit) { + /* 先尝试写流的写队列中的数据 */ + n = __try_fflush(astream); + + if (n < 0) { /* 说明尝试写失败,需要关闭流 */ + astream->write_nested--; + WRITE_IOCP_CLOSE(astream); + return; + } else if (n == 0) { + /* __try_fflush 返回的是队列中的数据已经清空, + * 本次可以真正调用一次写操作 + */ + const char *ptr; + + ptr = acl_vstring_str(str); + len = ACL_VSTRING_LEN(str); + n = acl_vstream_write(astream->stream, ptr, len); + if (n == ACL_VSTREAM_EOF) { + if (acl_last_error() != ACL_EAGAIN) { + astream->flag |= ACL_AIO_FLAG_DEAD; + astream->write_nested--; + WRITE_IOCP_CLOSE(astream); + return; + } + /* 如果未写任何数据且诊断该流的对等点并未关闭, + * 则将此次数据置入该流的写队列中 + */ + n = 0; + } else if (n == len) { /* 说明已经成功写入了全部的数据 */ + int ret; + + ret = write_complete_callback(astream); + astream->write_nested--; + acl_vstring_free(str); + + if (ret < 0) /* 调用者希望关闭流 */ + WRITE_IOCP_CLOSE(astream); + else if ((astream->flag & ACL_AIO_FLAG_IOCP_CLOSE)) { + /* 因为本次写IO已经成功完成,所以需要完成流的IO延迟关闭过程 */ + WRITE_IOCP_CLOSE(astream); + } + return; + } + /* 0 < n < dlen */ + /* 只是成功写入了部分流,n 表示还剩余的数据长度 */ + } else { + /* __try_fflush 并未全部写完写队列的所有的数据,所以也需要本次的数据 + * 全部加入流的写队列中 + */ + n = 0; + } + } else { + /* 递归嵌套写次数达到了规定的阀值,只需记个警告信息即可,因为有嵌套限制 */ + if (acl_msg_verbose) + acl_msg_warn("%s: write_nested(%d) >= max(%d)", + myname, astream->write_nested, astream->write_nested_limit); + n = 0; + } + + /* 否则,不允许继续嵌套,而是将写事件置于事件监控循环中,从而减少嵌套层次 */ + + astream->write_nested--; + + acl_assert(n >= 0); + + len = ACL_VSTRING_LEN(str); + if (n < len) + acl_vstring_memmove(str, acl_vstring_str(str) + n, len - n); + + /* 将数据置入该流的写队列中 */ + acl_fifo_push(&astream->write_fifo, str); + astream->write_left += ACL_VSTRING_LEN(str); + + /* 将该流的写事件置入事件监控中 */ + WRITE_SAFE_ENABLE(astream, __writen_notify_callback); +} + +void acl_aio_fprintf(ACL_ASTREAM *astream, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + acl_aio_vfprintf(astream, fmt, ap); + va_end(ap); +} + +void acl_aio_writev(ACL_ASTREAM *astream, const struct iovec *vector, int count) +{ + const char *myname = "acl_aio_writev"; + ACL_VSTRING *str; + int n, i, j, dlen; + + acl_assert(vector); + acl_assert(count); + + if ((astream->flag & (ACL_AIO_FLAG_DELAY_CLOSE | ACL_AIO_FLAG_DEAD))) + return; + + /* 将嵌套计数加1,以防止嵌套层次太深而使栈溢出 */ + astream->write_nested++; + + /* 如果嵌套调用次数小于阀值,则允许进行嵌套调用 */ + if (astream->write_nested < astream->write_nested_limit) { + /* 先尝试写流的写队列中的数据 */ + n = __try_fflush(astream); + if (n < 0) { /* 说明尝试写失败,需要关闭流 */ + astream->write_nested--; + WRITE_IOCP_CLOSE(astream); + return; + } else if (n == 0) { + /* __try_fflush 返回的是队列中的数据已经清空, + * 本次可以真正调用一次写操作 + */ + n = acl_vstream_writev(astream->stream, vector, count); + if (n == ACL_VSTREAM_EOF) { + if (acl_last_error() != ACL_EAGAIN) { + astream->flag |= ACL_AIO_FLAG_DEAD; + astream->write_nested--; + WRITE_IOCP_CLOSE(astream); + return; + } + /* 如果未写任何数据且诊断该流的对等点并未关闭, + * 则将此次数据置入该流的写队列中 + */ + n = 0; + } + } else { + /* __try_fflush 并未全部写完写队列的所有的数据,所以也需要本次的数据 + * 全部加入流的写队列中 + */ + n = 0; + } + } else { + /* 递归嵌套写次数达到了规定的阀值,只需记个警告信息即可,因为有嵌套限制 */ + if (acl_msg_verbose) + acl_msg_warn("%s(%d): write_nested(%d) >= max(%d)", + myname, __LINE__, astream->write_nested, astream->write_nested_limit); + n = 0; + } + + /* 计算剩余的未发送的数据长度 */ + + for (i = 0; i < count; i++) { + if (n >= (int) vector[i].iov_len) { + /* written */ + n -= vector[i].iov_len; + } else { + /* partially written */ + break; + } + } + + if (i >= count) { + int ret; + + acl_assert(n == 0); + ret = write_complete_callback(astream); + astream->write_nested--; + + if (ret < 0) { + /* 调用者希望关闭流 */ + WRITE_IOCP_CLOSE(astream); + } else if ((astream->flag & ACL_AIO_FLAG_IOCP_CLOSE)) { + /* 因为本次写IO已经成功完成,所以需要完成流的IO延迟关闭过程 */ + WRITE_IOCP_CLOSE(astream); + } + return; + } + + /* 否则,不允许继续嵌套,而是将写事件置于事件监控循环中,从而减少嵌套层次 */ + + astream->write_nested--; + + /* 计算剩余的数据总长度 */ + + j = i; + dlen = vector[i].iov_len - n; + i++; /* skipt this */ + for (; i < count; i++) { + dlen += vector[i].iov_len; + } + + /* 将数据置入该流的写队列中 */ + + /* 先分配一个足够大的缓冲区以能容下所有的剩余的数据 */ + str = acl_vstring_alloc(dlen + 1); + + acl_vstring_memcpy(str, (const char*) vector[j].iov_base + n, + vector[j].iov_len - n); + for (i = j + 1; i < count; i++) { + acl_vstring_memcat(str, vector[i].iov_base, vector[i].iov_len); + } + + acl_fifo_push(&astream->write_fifo, str); + astream->write_left += dlen; + + /* 将该流的写事件置入事件监控中 */ + WRITE_SAFE_ENABLE(astream, __writen_notify_callback); +} + +static void can_write_callback(int event_type, void *context) +{ + const char *myname = "can_write_callback"; + ACL_ASTREAM *astream = (ACL_ASTREAM*) context; + + WRITE_SAFE_DIABLE(astream); + + if (event_type == ACL_EVENT_XCPT) { + WRITE_IOCP_CLOSE(astream); + return; + } else if (event_type == ACL_EVENT_RW_TIMEOUT) { + int ret; + + ret = aio_timeout_callback(astream); + if (ret < 0) { + WRITE_IOCP_CLOSE(astream); + } else if (astream->flag & ACL_AIO_FLAG_IOCP_CLOSE) { + /* 该流正处于IO延迟关闭状态,因为本次读IO已经成功完成, + * 所以需要完成流的IO延迟关闭过程 + */ + WRITE_IOCP_CLOSE(astream); + } else { + WRITE_SAFE_ENABLE(astream, can_write_callback); + } + return; + } + + if (astream->can_write_fn == NULL) + acl_msg_fatal("%s(%d): can_write_fn null for astream(%lx)", + myname, __LINE__, (long) astream); + + astream->nrefer++; + if (astream->can_write_fn(astream, astream->can_write_ctx) < 0) { + astream->nrefer--; + WRITE_IOCP_CLOSE(astream); + } else if (astream->flag & ACL_AIO_FLAG_IOCP_CLOSE) { + astream->nrefer--; + WRITE_IOCP_CLOSE(astream); + } else { + astream->nrefer--; + } +} +void acl_aio_enable_write(ACL_ASTREAM *astream, + ACL_AIO_NOTIFY_FN can_write_fn, void *context) +{ + if ((astream->flag & (ACL_AIO_FLAG_DELAY_CLOSE | ACL_AIO_FLAG_DEAD))) + return; + astream->can_write_fn = can_write_fn; + astream->can_write_ctx = context; + WRITE_SAFE_ENABLE(astream, can_write_callback); +} + +void acl_aio_disable_write(ACL_ASTREAM *astream) +{ + if ((astream->flag & ACL_AIO_FLAG_ISWR) == 0) + return; + astream->flag &= ~ACL_AIO_FLAG_ISWR; + astream->can_write_fn = NULL; + astream->can_write_ctx = NULL; + if (astream->stream) + acl_event_disable_write(astream->aio->event, astream->stream); +} + +int acl_aio_iswset(ACL_ASTREAM *astream) +{ + const char *myname = "acl_aio_iswset"; + + if (astream == NULL) + acl_msg_fatal("%s: input invalid", myname); + if (astream->stream == NULL) + return (0); + + return (acl_event_iswset(astream->aio->event, astream->stream)); +} diff --git a/lib_acl/src/aio/aio.h b/lib_acl/src/aio/aio.h new file mode 100644 index 000000000..1002929e5 --- /dev/null +++ b/lib_acl/src/aio/aio.h @@ -0,0 +1,73 @@ +#ifndef __INTERNAL_AIO_INCLUDE_H__ +#define __INTERNAL_AIO_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_define.h" +#include "stdlib/acl_vstream.h" +#include "stdlib/acl_vstring.h" +#include "stdlib/acl_array.h" +#include "aio/acl_aio.h" + +struct ACL_AIO { + ACL_EVENT *event; + int delay_sec; + int delay_usec; + int keep_read; + int rbuf_size; + int event_mode; + ACL_ARRAY *dead_streams; +#ifdef ACL_MS_WINDOWS + int timer_active; + unsigned int tid; +#endif +}; + +typedef struct AIO_READ_HOOK { + ACL_AIO_READ_FN callback; + void *ctx; + char disable; +} AIO_READ_HOOK; + +typedef struct AIO_WRITE_HOOK { + ACL_AIO_WRITE_FN callback; + void *ctx; + char disable; +} AIO_WRITE_HOOK; + +typedef struct AIO_CLOSE_HOOK { + ACL_AIO_CLOSE_FN callback; + void *ctx; + char disable; +} AIO_CLOSE_HOOK; + +typedef struct AIO_TIMEO_HOOK { + ACL_AIO_TIMEO_FN callback; + void *ctx; + char disable; +} AIO_TIMEO_HOOK; + +typedef struct AIO_CONNECT_HOOK { + ACL_AIO_CONNECT_FN callback; + void *ctx; + char disable; +} AIO_CONNECT_HOOK; + +#define __AIO_NESTED_MAX 10 +#define __default_line_length 4096 + +/* in aio_callback.c */ +int aio_timeout_callback(ACL_ASTREAM *astream); +void aio_close_callback(ACL_ASTREAM *astream); + +/* in acl_aio_stream.c */ +void aio_delay_check(ACL_AIO *aio); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/src/aio/aio_callback.c b/lib_acl/src/aio/aio_callback.c new file mode 100644 index 000000000..44fe651dc --- /dev/null +++ b/lib_acl/src/aio/aio_callback.c @@ -0,0 +1,103 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_stdlib.h" +#include "aio/acl_aio.h" + +#endif + +#include "aio.h" + +int aio_timeout_callback(ACL_ASTREAM *astream) +{ + int ret = 0; + + /* 需要将缓冲区清空,以防被重复利用 */ + ACL_VSTRING_RESET(&astream->strbuf); + + /* 流引用计数加1,以防止流被异常关闭 */ + astream->nrefer++; + + if (astream->timeo_handles) { + ACL_ITER iter; + ACL_FIFO timeo_handles; + + /* XXX: 必须将各个回调句柄从回调队列中一一提出置入一个单独队列中, + * 因为 ACL_AIO 在回调过程中有可能发生嵌套,防止被重复调用 + */ + + acl_fifo_init(&timeo_handles); + acl_foreach_reverse(iter, astream->timeo_handles) { + AIO_TIMEO_HOOK *handle = (AIO_TIMEO_HOOK*) iter.data; + if (handle->disable) + continue; + acl_fifo_push(&timeo_handles, handle); + } + + while (1) { + AIO_TIMEO_HOOK *handle = acl_fifo_pop(&timeo_handles); + if (handle == NULL) + break; + ret = handle->callback(astream, handle->ctx); + if (ret < 0) { + astream->nrefer--; + return (ret); + } + } + } + + astream->nrefer--; + return (ret); +} + +void aio_close_callback(ACL_ASTREAM *astream) +{ + /* 需要将缓冲区清空,以防被重复利用 */ + ACL_VSTRING_RESET(&astream->strbuf); + + /* 流引用计数加1,以防止流被异常关闭 */ + astream->nrefer++; + + if (astream->close_handles) { + ACL_ITER iter; + ACL_FIFO close_handles; + + /* XXX: 必须将各个回调句柄从回调队列中一一提出置入一个单独队列中, + * 因为 ACL_AIO 在回调过程中有可能发生嵌套,防止被重复调用 + */ + + acl_fifo_init(&close_handles); + acl_foreach_reverse(iter, astream->close_handles) { + AIO_CLOSE_HOOK *handle = (AIO_CLOSE_HOOK*) iter.data; + if (handle->disable) + continue; + acl_fifo_push(&close_handles, handle); + } + + while (1) { + AIO_CLOSE_HOOK *handle = acl_fifo_pop(&close_handles); + void *ctx; + + if (handle == NULL) + break; + /* xxx: 关闭回调仅能被调用一次 */ + ctx = handle->ctx; + handle->disable = 1; + handle->ctx = NULL; + if (handle->callback(astream, ctx) < 0) { + astream->nrefer--; + return; + } + } + } + + astream->nrefer--; +} diff --git a/lib_acl/src/code/acl_base64.c b/lib_acl/src/code/acl_base64.c new file mode 100644 index 000000000..3e14be362 --- /dev/null +++ b/lib_acl/src/code/acl_base64.c @@ -0,0 +1,129 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_mymalloc.h" +#include "code/acl_base64.h" + +#endif + +static const unsigned char to_b64_tab[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +static const unsigned char un_b64_tab[] = { + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 255, 255, 255, + 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255, + 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 +}; + +unsigned char *acl_base64_encode(const char *in, int len) +{ + const unsigned char *clear = (const unsigned char*) in; + unsigned char *code = NULL; + unsigned char *p; + + code = acl_mymalloc(4 * ((len + 2) / 3) + 1); + p = code; + + while (len-- >0) { + register int x, y; + + x = *clear++; + *p++ = to_b64_tab[(x >> 2) & 63]; + + if (len-- <= 0) { + *p++ = to_b64_tab[(x << 4) & 63]; + *p++ = '='; + *p++ = '='; + break; + } + + y = *clear++; + *p++ = to_b64_tab[((x << 4) | ((y >> 4) & 15)) & 63]; + + if (len-- <= 0) { + *p++ = to_b64_tab[(y << 2) & 63]; + *p++ = '='; + break; + } + + x = *clear++; + *p++ = to_b64_tab[((y << 2) | ((x >> 6) & 3)) & 63]; + + *p++ = to_b64_tab[x & 63]; + } + + *p = 0; + + return (code); +} + +int acl_base64_decode(const char *in, char **pptr_in) +{ + const unsigned char *code = (const unsigned char*) in; + unsigned char **pptr = (unsigned char**) pptr_in; + register int x, y; + unsigned char *result, *result_saved = NULL; + +#undef ERETURN +#define ERETURN(x) { \ + if (result_saved != NULL) \ + acl_myfree(result_saved); \ + *pptr = NULL; \ + return (x); \ +} + + result_saved = result = acl_mymalloc(3 * (strlen((const char *) code) / 4) + 1); + *pptr = result; + + /* Each cycle of the loop handles a quantum of 4 input bytes. For the last + quantum this may decode to 1, 2, or 3 output bytes. */ + + while ((x = (*code++)) != 0) { + if (x > 127 || (x = un_b64_tab[x]) == 255) + ERETURN (-1); + if ((y = (*code++)) == 0 || (y = un_b64_tab[y]) == 255) + ERETURN (-1); + *result++ = (x << 2) | (y >> 4); + + if ((x = (*code++)) == '=') { + if (*code++ != '=' || *code != 0) + ERETURN (-1); + } else { + if (x > 127 || (x = un_b64_tab[x]) == 255) + ERETURN (-1); + *result++ = (y << 4) | (x >> 2); + if ((y = (*code++)) == '=') { + if (*code != 0) + ERETURN (-1); + } else { + if (y > 127 || (y = un_b64_tab[y]) == 255) + ERETURN (-1); + *result++ = (x << 6) | y; + } + } + } + + *result = 0; + return (result - *pptr); +} diff --git a/lib_acl/src/code/acl_gbcode.c b/lib_acl/src/code/acl_gbcode.c new file mode 100644 index 000000000..7cf141ff6 --- /dev/null +++ b/lib_acl/src/code/acl_gbcode.c @@ -0,0 +1,59 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include "stdlib/acl_mymalloc.h" +#include "code/acl_gbcode.h" + +#endif + +#include "gb_jt2ft.h" +#include "gb_ft2jt.h" + +static void gbtransfer(const unsigned short chartab[], const char *data, size_t dlen, + char *buf, size_t size) +{ + const unsigned char *ptr_jt = (const unsigned char*) data; + unsigned char *ptr_ft = (unsigned char*) buf; + unsigned short n; + + while (dlen > 0 && size > 0) { + if (*ptr_jt > 0x80) { + n = chartab[*((const unsigned short*) ptr_jt)]; + if (n == 0xffff) { + *ptr_ft++ = *ptr_jt++; + dlen--; + size--; + if (dlen == 0 || size == 0) + break; + *ptr_ft++ = *ptr_jt++; + dlen--; + size--; + } else if (size == 1) { + *ptr_ft++ = *ptr_jt++; + break; + } else { + *((unsigned short*) ptr_ft) = n; + ptr_ft += 2; + size -= 2; + ptr_jt += 2; + dlen -= 2; + } + } else { + *ptr_ft++ = *ptr_jt++; + dlen--; + size--; + } + } +} + +void acl_gbjt2ft(const char *data, size_t dlen, char *buf, size_t size) +{ + gbtransfer(__jt2ft_tab, data, dlen, buf, size); +} + +void acl_gbft2jt(const char *data, size_t dlen, char *buf, size_t size) +{ + gbtransfer(__ft2jt_tab, data, dlen, buf, size); +} diff --git a/lib_acl/src/code/acl_htmlcode.c b/lib_acl/src/code/acl_htmlcode.c new file mode 100644 index 000000000..51487ab30 --- /dev/null +++ b/lib_acl/src/code/acl_htmlcode.c @@ -0,0 +1,146 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include + +#include "stdlib/acl_msg.h" +#include "stdlib/acl_vstring.h" +#include "stdlib/acl_token_tree.h" +#include "thread/acl_pthread.h" +#include "code/acl_htmlcode.h" + +#endif + +#include "uni2utf8.h" +#include "html_charset.h" + +int acl_html_encode(const char *in, ACL_VSTRING *out) +{ + int n = 0; + const unsigned char *ptr = (const unsigned char*) in; + unsigned int k; + + while (*ptr) { + k = (unsigned char) (*ptr); + if (k >= 128) + ACL_VSTRING_ADDCH(out, k); + else if (html_charmap[k] != NULL) { + acl_vstring_strcat(out, html_charmap[k]); + n++; + } else + ACL_VSTRING_ADDCH(out, k); + ptr++; + } + + ACL_VSTRING_TERMINATE(out); + return (n); +} + +static ACL_TOKEN *__decode_token_tree = NULL; + +static void html_decode_free(void) +{ + if (__decode_token_tree) { + acl_token_tree_destroy(__decode_token_tree); + __decode_token_tree = NULL; + } +} + +static void html_decode_init(void) +{ + size_t i, n = sizeof(html_tab) / sizeof(html_tab[0]); + + __decode_token_tree = acl_token_new(); + + /* 暂且不兼容全角空格等字符 */ + + for (i = 0; i < n; i++) { +#if 0 + if (acl_token_tree_word_match(__decode_token_tree, + html_tab[i].txt) != NULL) + { + continue; + } +#endif + acl_token_tree_add(__decode_token_tree, html_tab[i].txt, + ACL_TOKEN_F_STOP, &html_tab[i]); + } + + /* 进程退出时调用 html_decode_free 释放内存资源 */ + atexit(html_decode_free); +} + +static acl_pthread_once_t __decode_token_once = ACL_PTHREAD_ONCE_INIT; + +static const char* markup_unescape(const char* in, ACL_VSTRING* out) +{ + unsigned int n; + char temp[2], buf[7]; + + while (*in != 0) { + if (*in == '&' && *(in + 1) == '#' + && (sscanf(in, "&#%u%1[;]", &n, temp) == 2 + || sscanf(in, "&#x%x%1[;]", &n, temp) == 2) + && n != 0) + { + int buflen = uni2utf8((unsigned int) n, + buf, sizeof(buf)); + buf[buflen] = '\0'; + acl_vstring_strcat(out, buf); + + n = *(in + 2) == 'x' ? 3 : 2; + while (isxdigit(in[n])) + n++; + if(in[n] == ';') + n++; + in += n; + } else { + ACL_VSTRING_ADDCH(out, (unsigned char) (*in)); + in++; + } + } + + return (in); +} + +int acl_html_decode(const char *in, ACL_VSTRING *out) +{ + int n = 0, len; + const char *ptr = in, *pre; + const ACL_TOKEN *token; + const HTML_SPEC *spec; + + acl_pthread_once(&__decode_token_once, html_decode_init); + if (__decode_token_tree == NULL) + acl_msg_fatal("__decode_token_tree null"); + + while (*ptr != 0) { + pre = ptr; + token = acl_token_tree_match(__decode_token_tree, + &ptr, NULL, NULL); + if (token == NULL) { + pre = markup_unescape(pre, out); + len = ptr - pre; + if (len > 0) + acl_vstring_memcat(out, pre, len); + break; + } + spec = (const HTML_SPEC*) token->ctx; + acl_assert(spec != NULL); + + len = ptr - pre - spec->len; + if (len > 0) + acl_vstring_memcat(out, pre, len); + if (spec->ch > 255) + acl_vstring_memcat(out, (char*) &spec->ch, sizeof(spec->ch)); + else + ACL_VSTRING_ADDCH(out, (unsigned char) spec->ch); + n++; + } + + ACL_VSTRING_TERMINATE(out); + return (n); +} diff --git a/lib_acl/src/code/acl_urlcode.c b/lib_acl/src/code/acl_urlcode.c new file mode 100644 index 000000000..058a8afc5 --- /dev/null +++ b/lib_acl/src/code/acl_urlcode.c @@ -0,0 +1,100 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include + +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_msg.h" +#include "code/acl_urlcode.h" + +#endif + +static unsigned char hex_enc_table[] = "0123456789ABCDEF"; + +char *acl_url_encode(const char *str) +{ + const char *myname = "acl_url_encode"; + register int i, j, len, tmp_len; + unsigned char *tmp; + + len = strlen(str); + tmp_len = len; + tmp = (unsigned char*) acl_mymalloc(len+1); + if (tmp == NULL) + acl_msg_fatal("%s(%d): malloc error", myname, __LINE__); + + for (i = 0, j = 0; i < len; i++, j++) { + tmp[j] = (unsigned char)str[i]; + if (tmp[j] == ' ') + tmp[j] = '+'; + else if (!isalnum(tmp[j]) && strchr("_-.", tmp[j]) == NULL) { + tmp_len += 3; + tmp = acl_myrealloc(tmp, tmp_len); + if (!tmp) + acl_msg_fatal("%s(%d): realloc error", myname, __LINE__); + + tmp[j++] = '%'; + tmp[j++] = hex_enc_table[(unsigned char)str[i] >> 4]; + tmp[j] = hex_enc_table[(unsigned char)str[i] & 0x0F]; + } + } + + tmp[j] = '\0'; + + return ((char*) tmp); +} + +static unsigned char hex_dec_table[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, + 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 10, 11, 12, 13, 13, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + +char *acl_url_decode(const char *str) +{ + const char *myname = "acl_url_decode"; + char *tmp; + register int i, len, pos = 0; + + len = strlen(str); + tmp = (char *) acl_mymalloc(len + 1); + if (tmp == NULL) + acl_msg_fatal("%s(%d): malloc error", myname, __LINE__); + + for (i = 0; i < len; i++) { + /* If we found a '%' character, then the next two are the character + * hexa code. Converting a hexadecimal code to their decimal is easy: + * The first character needs to be multiplied by 16 ( << 4 ), and the + * another one we just get the value from hextable variable + */ + if ((str[i] == '%') && isalnum(str[i+1]) && isalnum(str[i+2])) { + tmp[pos] = (hex_dec_table[(unsigned char) str[i+1]] << 4) + + hex_dec_table[(unsigned char) str[i+2]]; + i += 2; + } else if (str[i] == '+') + tmp[pos] = ' '; + else + tmp[pos] = str[i]; + + pos++; + } + + tmp[pos] = '\0'; + + return (tmp); +} diff --git a/lib_acl/src/code/acl_vstring_base64.c b/lib_acl/src/code/acl_vstring_base64.c new file mode 100644 index 000000000..53c965330 --- /dev/null +++ b/lib_acl/src/code/acl_vstring_base64.c @@ -0,0 +1,198 @@ +/* System library. */ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#ifndef UCHAR_MAX +#define UCHAR_MAX 0xff +#endif + +/* Utility library. */ + +#include "stdlib/acl_msg.h" +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_vstring.h" +#include "code/acl_vstring_base64.h" + +#endif + +/* Application-specific. */ + +static const unsigned char to_b64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +static const unsigned char un_b64[] = { + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 255, 255, 255, + 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255, + 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 +}; + +#define UNSIG_CHAR_PTR(x) ((const unsigned char *)(x)) + +/* vstring_base64_encode - raw data to encoded */ + +ACL_VSTRING *acl_vstring_base64_encode(ACL_VSTRING *result, const char *in, int len) +{ + const unsigned char *cp; + int count; + + /* + * Encode 3 -> 4. + */ + ACL_VSTRING_RESET(result); + for (cp = UNSIG_CHAR_PTR(in), count = len; + count > 0; count -= 3, cp += 3) { + ACL_VSTRING_ADDCH(result, to_b64[cp[0] >> 2]); + if (count > 1) { + ACL_VSTRING_ADDCH(result, + to_b64[(cp[0] & 0x3) << 4 | cp[1] >> 4]); + if (count > 2) { + ACL_VSTRING_ADDCH(result, + to_b64[(cp[1] & 0xf) << 2 | cp[2] >> 6]); + ACL_VSTRING_ADDCH(result, to_b64[cp[2] & 0x3f]); + } else { + ACL_VSTRING_ADDCH(result, to_b64[(cp[1] & 0xf) << 2]); + ACL_VSTRING_ADDCH(result, '='); + break; + } + } else { + ACL_VSTRING_ADDCH(result, to_b64[(cp[0] & 0x3) << 4]); + ACL_VSTRING_ADDCH(result, '='); + ACL_VSTRING_ADDCH(result, '='); + break; + } + } + ACL_VSTRING_TERMINATE(result); + return (result); +} + +/* acl_vstring_base64_decode - encoded data to raw */ + +ACL_VSTRING *acl_vstring_base64_decode(ACL_VSTRING *result, const char *in, int len) +{ + const unsigned char *cp; + int count; + int ch0; + int ch1; + int ch2; + int ch3; + +#define CHARS_PER_BYTE (UCHAR_MAX + 1) +#define INVALID 0xff + + /* + * Sanity check. + */ + if (len % 4) + return (NULL); + + /* + * Once: initialize the decoding lookup table on the fly. + * + * if (un_b64 == 0) { + * un_b64 = (unsigned char *) mymalloc(CHARS_PER_BYTE); + * memset(un_b64, INVALID, CHARS_PER_BYTE); + * for (cp = to_b64; cp < to_b64 + sizeof(to_b64); cp++) + * un_b64[*cp] = cp - to_b64; + * } + */ + + /* + * Decode 4 -> 3. + */ + ACL_VSTRING_RESET(result); + for (cp = UNSIG_CHAR_PTR(in), count = 0; count < len; count += 4) { + if ((ch0 = un_b64[*cp++]) == INVALID + || (ch1 = un_b64[*cp++]) == INVALID) + return (0); + ACL_VSTRING_ADDCH(result, ch0 << 2 | ch1 >> 4); + if ((ch2 = *cp++) == '=') + break; + if ((ch2 = un_b64[ch2]) == INVALID) + return (0); + ACL_VSTRING_ADDCH(result, ch1 << 4 | ch2 >> 2); + if ((ch3 = *cp++) == '=') + break; + if ((ch3 = un_b64[ch3]) == INVALID) + return (0); + ACL_VSTRING_ADDCH(result, ch2 << 6 | ch3); + } + ACL_VSTRING_TERMINATE(result); + return (result); +} + +#ifdef TEST + + /* + * Proof-of-concept test program: convert to base 64 and back. + */ + +#define STR(x) vstring_str(x) +#define LEN(x) VSTRING_LEN(x) + +int main(int unused_argc, char **unused_argv) +{ + ACL_VSTRING *b1 = acl_vstring_alloc(1); + ACL_VSTRING *b2 = acl_vstring_alloc(1); + char *test = "this is a test"; + +#define DECODE(b,x,l) { \ + if (acl_vstring_base64_decode((b),(x),(l)) == 0) \ + acl_msg_panic("bad base64: %s", (x)); \ + } +#define VERIFY(b,t) { \ + if (strcmp((b), (t)) != 0) \ + acl_msg_panic("bad test: %s", (b)); \ + } + + acl_vstring_base64_encode(b1, test, strlen(test)); + DECODE(b2, STR(b1), LEN(b1)); + VERIFY(STR(b2), test); + + acl_vstring_base64_encode(b1, test, strlen(test)); + acl_vstring_base64_encode(b2, STR(b1), LEN(b1)); + acl_vstring_base64_encode(b1, STR(b2), LEN(b2)); + DECODE(b2, STR(b1), LEN(b1)); + DECODE(b1, STR(b2), LEN(b2)); + DECODE(b2, STR(b1), LEN(b1)); + VERIFY(STR(b2), test); + + acl_vstring_base64_encode(b1, test, strlen(test)); + acl_vstring_base64_encode(b2, STR(b1), LEN(b1)); + acl_vstring_base64_encode(b1, STR(b2), LEN(b2)); + acl_vstring_base64_encode(b2, STR(b1), LEN(b1)); + acl_vstring_base64_encode(b1, STR(b2), LEN(b2)); + DECODE(b2, STR(b1), LEN(b1)); + DECODE(b1, STR(b2), LEN(b2)); + DECODE(b2, STR(b1), LEN(b1)); + DECODE(b1, STR(b2), LEN(b2)); + DECODE(b2, STR(b1), LEN(b1)); + VERIFY(STR(b2), test); + + acl_vstring_free(b1); + acl_vstring_free(b2); + return (0); +} + +#endif diff --git a/lib_acl/src/code/acl_xmlcode.c b/lib_acl/src/code/acl_xmlcode.c new file mode 100644 index 000000000..7bf22ba68 --- /dev/null +++ b/lib_acl/src/code/acl_xmlcode.c @@ -0,0 +1,180 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include + +#include "stdlib/acl_msg.h" +#include "stdlib/acl_vstring.h" +#include "stdlib/acl_token_tree.h" +#include "thread/acl_pthread.h" +#include "code/acl_xmlcode.h" + +#endif + +#include +#include "uni2utf8.h" + +static const char *__charmap[] = { + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, """, NULL, NULL, NULL, "&", "'", + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, "<", NULL, ">", NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL +}; + +int acl_xml_encode(const char *in, ACL_VSTRING *out) +{ + int n = 0; + + while (*in) { + if (__charmap[(unsigned char)(*in)] != NULL) { + acl_vstring_strcat(out, + __charmap[(unsigned char)(*in)]); + n++; + } else + ACL_VSTRING_ADDCH(out, (*in)); + in++; + } + + ACL_VSTRING_TERMINATE(out); + return (n); +} + +typedef struct { + const char *str; + const char *txt; + size_t len; +} XML_SPEC; + +static const XML_SPEC __tab[] = { + { "<", "<", sizeof("<") - 1 }, + { ">", ">", sizeof(">") - 1 }, + { "&", "&", sizeof("&") - 1 }, + { "\'", "'", sizeof("'") - 1 }, + { "\"", """, sizeof(""") - 1 }, + { "\302\251", "©", sizeof("©") - 1 }, + { "\302\256", "®", sizeof("®") - 1 }, + { " ", " ", sizeof(" ") - 1}, + { 0, 0, 0 } +}; + +static ACL_TOKEN *__token_tree = NULL; + +static void xml_decode_free(void) +{ + if (__token_tree) { + acl_token_tree_destroy(__token_tree); + __token_tree = NULL; + } +} + +static void xml_decode_init(void) +{ + int i; + + __token_tree = acl_token_new(); + + for (i = 0; __tab[i].str != 0; i++) + acl_token_tree_add(__token_tree, __tab[i].txt, + ACL_TOKEN_F_STOP, &__tab[i]); + + /* 进程退出时调用 html_decode_free 释放内存资源 */ + atexit(xml_decode_free); +} + +static acl_pthread_once_t __token_once = ACL_PTHREAD_ONCE_INIT; + +static const char* markup_unescape(const char* in, ACL_VSTRING* out) +{ + unsigned int n; + char temp[2], buf[7]; + + while (*in != 0) { + if (*in == '&' && *(in + 1) == '#' + && (sscanf(in, "&#%u%1[;]", &n, temp) == 2 + || sscanf(in, "&#x%x%1[;]", &n, temp) == 2) + && n != 0) + { + int buflen = uni2utf8((unsigned int) n, + buf, sizeof(buf)); + buf[buflen] = '\0'; + acl_vstring_strcat(out, buf); + + n = *(in + 2) == 'x' ? 3 : 2; + while (isxdigit(in[n])) + n++; + if(in[n] == ';') + n++; + in += n; + } else { + ACL_VSTRING_ADDCH(out, (unsigned char) (*in)); + in++; + } + } + + return (in); +} + +int acl_xml_decode(const char *in, ACL_VSTRING *out) +{ + int n = 0, len; + const char *ptr = in, *pre; + const ACL_TOKEN *token; + const XML_SPEC *spec; + + acl_pthread_once(&__token_once, xml_decode_init); + if (__token_tree == NULL) + acl_msg_fatal("__token_tree null"); + + while (*ptr != 0) { + pre = ptr; + token = acl_token_tree_match(__token_tree, &ptr, NULL, NULL); + if (token == NULL) { + pre = markup_unescape(pre, out); + len = ptr - pre; + if (len > 0) + acl_vstring_memcat(out, pre, len); + break; + } + spec = (const XML_SPEC*) token->ctx; + acl_assert(spec != NULL); + + len = ptr - pre - spec->len; + if (len > 0) + acl_vstring_memcat(out, pre, len); + acl_vstring_strcat(out, spec->str); + n++; + } + + ACL_VSTRING_TERMINATE(out); + return (n); +} diff --git a/lib_acl/src/code/gb_ft2jt.h b/lib_acl/src/code/gb_ft2jt.h new file mode 100644 index 000000000..70eb31108 --- /dev/null +++ b/lib_acl/src/code/gb_ft2jt.h @@ -0,0 +1,8194 @@ +static const unsigned short __ft2jt_tab[] = { + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xbecc, + 0xb0d4,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xdbce,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xf1bb,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xbac0,0xffff,0xffff,0xffff,0xffff, + 0xc6c8,0xffff,0xffff,0xfbc1,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xaab0,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xdaf1,0xffff,0xffff,0xffff,0xccda,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xafd4,0xe2d5, + 0xffff,0xffff,0xffff,0xead7,0xa7ef,0xffff,0xc2c7,0xffff, + 0xffff,0xffff,0xbbc0,0xffff,0xffff,0xffff,0xfef1,0xd4cf, + 0xffff,0xffff,0xffff,0xaabe,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xe3c7,0xffff,0xffff,0xffff,0xffff, + 0xb2d4,0xeebc,0xd0bc,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xecf0,0xffff,0xf9ed,0xffff,0xffff,0xa1b4,0xffff,0xf7d9, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xb5f4,0xffff, + 0xaabb,0xffff,0xffff,0xffff,0xfedd,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xcfcb,0xffff,0xffff,0xffff, + 0xffff,0xfcd6,0xaed3,0xffff,0xffff,0xffff,0xa4ea,0xffff, + 0xffff,0xffff,0xcbee,0xffff,0xfbee,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xd7bd,0xffff,0xffff,0xa4d4,0xadf2, + 0xc3e2,0xffff,0xffff,0xe4e6,0xffff,0xffff,0xf1f6,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xc3cf, + 0xffff,0xaccc,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xf8c9,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xfeb5, + 0xeff0,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xfed6,0xffff,0xffff,0xdcc9,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xd0da,0xffff, + 0xffff,0xdbea,0xe1ea,0xffff,0xffff,0xffff,0xffff,0xacc1, + 0xffff,0xaadb,0xffff,0xe8ee,0xf0ee,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xe7cd,0xadc2, + 0xf8d1,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xa7f7, + 0xf1c4,0xffff,0xccf0,0xffff,0xffff,0xfaf7,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xddc1,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xb3e3,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xfabb,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xcccc,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xd4c1,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xc3bd,0xffff,0xffff,0xffff,0xffff, + 0xd1ce,0xffff,0xffff,0xffff,0xffff,0xa4e7,0xdbd7,0xffff, + 0xe5d0,0xffff,0xffff,0xe0cb,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xf6dc,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xf4d9,0xffff,0xffff,0xb3da,0xb3d0,0xa4d6, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xb0b7,0xe7ee,0xa4ef,0xffff,0xffff,0xe1ef, + 0xedef,0xffff,0xffff,0xffff,0xffff,0xffff,0xe4b0,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xb6e0, + 0xbccd,0xffff,0xffff,0xbeb8,0xaee6,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xb7bc,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xe0c6,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xf7f0,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xddcd,0xffff,0xe6f3,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xc0e7,0xffff,0xffff,0xffff,0xffff,0xb0c0,0xe8bc,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xecea,0xffff,0xefd6,0xffff,0xffff, + 0xffff,0xdfea,0xffff,0xffff,0xffff,0xffff,0xaad7,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xedee,0xffff,0xccef,0xffff, + 0xd8c0,0xffff,0xd9e3,0xffff,0xffff,0xffff,0xd9b6,0xa8f2, + 0xfcb6,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xecd9,0xffff,0xffff,0xffff,0xf0f4,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xcdd9,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xa7cc,0xffff,0xffff,0xffff, + 0xe5e8,0xd6cd,0xffff,0xffff,0xffff,0xffff,0xede4,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xeee1,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xa8e7,0xb6e7,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xbbbc,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xf7be,0xb2da,0xffff,0xffff, + 0xffff,0xa1b7,0xdfd4,0xa3bc,0xcef5,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xc9d4,0xffff,0xffff,0xffff,0xa7c8, + 0xffff,0xffff,0xa5bf,0xe8d6,0xffff,0xd1f6,0xeef6,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xc5cd,0xffff,0xffff,0xffff,0xffff,0xffff,0xbbe1,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xcbec,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xdeca,0xd6cf,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xeec7,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xcdeb,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xe4bf,0xffff,0xffff, + 0xffff,0xf3b9,0xffff,0xffff,0xffff,0xf4e9,0xffff,0xffff, + 0xffff,0xffff,0xa5c7,0xffff,0xffff,0xb6d7,0xffff,0xffff, + 0xfacc,0xffff,0xffff,0xffff,0xedce,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xf2f6,0xffff, + 0xaff0,0xffff,0xcdf0,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xaab6,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xb0e4,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xbad8,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xa4d2,0xffff,0xffff,0xffff,0xffff,0xffff,0xccc2,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xded1,0xa3be, + 0xffff,0xffff,0xffff,0xbcdc,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xabda,0xffff,0xc9da,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xe9ee,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xc4e2,0xffff,0xd2b3,0xffff,0xffff,0xd2f6,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xc2c2,0xf6bd,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xabce,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xa1cc,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xaae7,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xd7c7,0xffff,0xffff,0xffff,0xdcda, + 0xffff,0xe1b1,0xeaca,0xffff,0xffff,0xffff,0xded5,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xf6ee,0xb9ef,0xffff,0xacef, + 0xffff,0xffff,0xd8e3,0xcabc,0xffff,0xffff,0xc4c6,0xffff, + 0xd9c4,0xffff,0xffff,0xbfc2,0xffff,0xffff,0xeff6,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xbbc5, + 0xffff,0xffff,0xffff,0xabe6,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xb5d2,0xffff,0xffff,0xffff,0xe1c0,0xffff,0xf5b1,0xffff, + 0xaad3,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xd7cf,0xffff,0xf6e7,0xffff,0xffff, + 0xffff,0xc1b5,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xefb3,0xffff,0xa9e7,0xf1b3,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xf6c9,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xadde,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xbed6,0xcdda,0xa5bc, + 0xffff,0xf2c2,0xcdd8,0xffff,0xffff,0xffff,0xcebd,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xfcbc,0xcfef, + 0xecee,0xffff,0xdae3,0xffff,0xffff,0xffff,0xecc1,0xffff, + 0xf6b6,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xabf7, + 0xffff,0xffff,0xffff,0xd7f0,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xc3df,0xffff, + 0xffff,0xffff,0xbcdb,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xd5c7,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xa8e2,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xb9e7,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xabc2,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xe9ea,0xffff,0xcfc8,0xd1da,0xffff, + 0xffff,0xfbb4,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xf1c8,0xffff,0xc8ef,0xffff, + 0xffff,0xffff,0xb3b4,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xf8e6,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xa2b2,0xffff,0xffff,0xffff,0xffff,0xffff,0xf5df, + 0xffff,0xe9bf,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xd2b2,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xb5d5,0xffff,0xffff,0xffff,0xadb0,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xd5d6,0xffff,0xffff, + 0xfec9,0xffff,0xffff,0xffff,0xffff,0xe0d4,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xd5cb,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xacb2,0xffff,0xbfef,0xffff,0xffff, + 0xf5ee,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xede6,0xf7e6,0xffff,0xffff,0xf0f6,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xddd9,0xffff,0xffff,0xffff,0xa2b3, + 0xffff,0xe3dc,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xa4c7,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xdeed,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xe6bb,0xffff,0xffff,0xffff,0xcbeb,0xf5d9,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xa5e1,0xffff,0xc3b7,0xffff,0xffff,0xffff, + 0xffff,0xdcea,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xa4b3,0xffff,0xffff,0xffff,0xffff,0xffff,0xe7b7, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xa8be,0xa8f7, + 0xffff,0xffff,0xbadd,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xd1b2,0xffff,0xffff,0xe2c4,0xffff,0xffff,0xffff, + 0xffff,0xe1ba,0xffff,0xffff,0xffff,0xfac2,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xc1cf,0xa4e2,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xa1be,0xffff,0xffff,0xffff,0xffff,0xffff,0xd5bd, + 0xc0f1,0xffff,0xffff,0xffff,0xffff,0xe9d7,0xffff,0xd3dd, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xc6b9,0xffff,0xd0f1,0xedea,0xffff,0xffff,0xe4bb,0xffff, + 0xf1c6,0xd1b7,0xd3b8,0xffff,0xffff,0xefe9,0xffff,0xf8bd, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xdbef, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xa2f2,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xeeb1, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xeedb,0xffff,0xffff,0xffff,0xffff,0xffff,0xf8b3, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xfecc, + 0xd3b2,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xb7b1,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xd6d6, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xc6e7, + 0xffff,0xffff,0xccc7,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xb7b2,0xbec7,0xccd4,0xffff,0xffff,0xf7f2, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xbfda,0xffff,0xffff, + 0xffff,0xf9cc,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xfacf,0xb8b4,0xe0d5,0xdcef, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xc5e2,0xffff,0xffff,0xffff,0xffff,0xffff,0xecf6,0xffff, + 0xffff,0xe9be,0xffff,0xffff,0xe1f7,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xe9df, + 0xffff,0xffff,0xffff,0xffff,0xefcb,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xabbc,0xffff,0xffff,0xffff,0xcbe4,0xe6d3,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xddf0,0xe0bc,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xedb0,0xffff,0xcbe7, + 0xebbc,0xffff,0xbfb0,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xc9dc,0xbbdd,0xffff,0xffff,0xbbc6,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xe8c9,0xc0da,0xcfda,0xffff, + 0xffff,0xddea,0xffff,0xffff,0xbbf5,0xffff,0xa5ea,0xffff, + 0xffff,0xffff,0xceee,0xdeee,0xffff,0xc5ef,0xffff,0xdeef, + 0xeeef,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xedf6,0xffff, + 0xffff,0xc1f0,0xffff,0xffff,0xffff,0xfef7,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xadbf,0xffff,0xffff,0xffff, + 0xffff,0xf5db,0xffff,0xffff,0xffff,0xffff,0xffff,0xcbd8, + 0xffff,0xffff,0xffff,0xefd1,0xf7b1,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xccc5,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xcab1,0xffff,0xffff,0xffff,0xffff,0xffff,0xc4e7, + 0xffff,0xa3b7,0xffff,0xffff,0xffff,0xd4ce,0xffff,0xffff, + 0xffff,0xaadd,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xeeea,0xffff,0xffff,0xffff,0xdada, + 0xffff,0xffff,0xffff,0xffff,0xecb3,0xffff,0xffff,0xffff, + 0xa3db,0xffff,0xffff,0xffff,0xe2d0,0xa3ef,0xffff,0xf9b2, + 0xffff,0xffff,0xd8b9,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xeae6,0xffff,0xffff,0xffff,0xffff, + 0xefb7,0xbef0,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xd0d8,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xfae2,0xffff,0xbbbb,0xa1c5,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xf6be,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xc6b3, + 0xfabf,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xd9e7,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xcfb2,0xffff,0xffff,0xffff,0xffff,0xaeb5,0xffff,0xffff, + 0xfaca,0xb3c3,0xffff,0xffff,0xd2f5,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xcaee,0xafc7,0xffff,0xbcef,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xc6e2,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xf9c3,0xffff,0xd7ba,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xb6d9,0xffff,0xffff,0xe3bb,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xedc3, + 0xffff,0xffff,0xffff,0xffff,0xe9b8,0xffff,0xffff,0xffff, + 0xffff,0xc0e9,0xffff,0xffff,0xe8c1,0xffff,0xa6bd,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xacc2,0xffff,0xffff,0xffff,0xffff,0xf9d3,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xd6f4,0xffff,0xb7e7,0xffff, + 0xd8e7,0xeec2,0xffff,0xffff,0xffff,0xd9c1,0xffff,0xffff, + 0xb3c0,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xc8da,0xb6ca, + 0xffff,0xd8ba,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xe0cc,0xffff,0xf1ef,0xb5be, + 0xffff,0xffff,0xdbe3,0xffff,0xffff,0xffff,0xa1f2,0xa9ec, + 0xffff,0xedc2,0xffff,0xffff,0xffff,0xd3f6,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xb5f0,0xffff,0xebc6,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xc8c7,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xaee1,0xa7b3, + 0xffff,0xffff,0xffff,0xffff,0xc0d6,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xd9c2,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xf1cb,0xffff,0xffff,0xe0b7,0xffff,0xacce,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xd0dc,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xedd0,0xffff,0xedb7,0xdbda, + 0xe1b7,0xdaea,0xffff,0xffff,0xbed4,0xe1d6,0xffff,0xffff, + 0xa7db,0xffff,0xcfee,0xffff,0xb1ef,0xffff,0xffff,0xdaef, + 0xffff,0xffff,0xffff,0xe6cb,0xffff,0xffff,0xffff,0xaaec, + 0xffff,0xa6d4,0xece6,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xb0f0,0xffff,0xffff,0xffff,0xc6bb,0xabd5,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xd1d8,0xb1d4,0xffff, + 0xffff,0xbfcd,0xffff,0xffff,0xffff,0xffff,0xffff,0xd0e2, + 0xffff,0xdfb9,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xf8e3,0xffff, + 0xf2d6,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xb1ea,0xffff, + 0xf1b1,0xffff,0xffff,0xffff,0xb6cb,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xd5b0,0xffff,0xffff,0xe1eb,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xd5d3,0xeed6,0xb7cc, + 0xffff,0xb8c2,0xffff,0xffff,0xffff,0xf2e9,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xadc3,0xffff,0xffff,0xffff,0xffff, + 0xfdd6,0xc5c3,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xa4bd,0xebb7,0xefc6,0xffff,0xffff,0xd8f6,0xf3f6,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xc7df,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xcfb7, + 0xffff,0xffff,0xffff,0xffff,0xa9c0,0xffff,0xffff,0xcbb8, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xf8ec,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xbae7,0xa7e7, + 0xc9bd,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xddd5, + 0xf9c2,0xc1f4,0xffff,0xefea,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xdec1,0xffff,0xffff,0xdcf5,0xf7e9,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xa6c7,0xffff,0xc4ef,0xffff,0xceef, + 0xffff,0xffff,0xfbb2,0xd5cf,0xffff,0xffff,0xc3d2,0xffff, + 0xffff,0xffff,0xebe6,0xffff,0xffff,0xabb1,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xc9e1,0xe3b9, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xcaeb,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xcbc2,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xd5b3,0xffff,0xffff,0xffff,0xffff,0xf3bf,0xffff,0xffff, + 0xffff,0xffff,0xc6f3,0xffff,0xffff,0xffff,0xd9b8,0xcce7, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xdeb8,0xffff,0xffff, + 0xffff,0xffff,0xe4dd,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xdfcb,0xbdda,0xe8d1,0xd7c6, + 0xffff,0xdfbb,0xffff,0xffff,0xc8f5,0xf0e9,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xa7b6,0xbec3,0xffff, + 0xffff,0xc5e3,0xffff,0xffff,0xabf6,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xd6f6,0xffff,0xaef7, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xa9bb, + 0xffff,0xffff,0xc2b0,0xffff,0xa7d1,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xb7c5,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xf7d1,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xace7,0xf8cd,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xb0dd,0xffff,0xb2dd,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xe0ea,0xffff,0xffff,0xd9f5,0xf3e9,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xc1c9,0xffff,0xffff,0xffff,0xffff,0xa4f2,0xffff, + 0xdacf,0xd4cd,0xffff,0xffff,0xdef7,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xd0f0,0xffff,0xb4ec,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xebc1,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xa2df,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xdcf0,0xffff,0xffff,0xffff,0xb8ed,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xeaf3,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xd4c4,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xe5f2, + 0xffff,0xffff,0xffff,0xf5be,0xadda,0xffff,0xceda,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xe9f5,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xe1ee,0xc1c2,0xaec7,0xcdef,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xb3f7,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xf5f6,0xadf7, + 0xffff,0xffff,0xbdf7,0xd9f0,0xffff,0xddb3,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xc6de,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xe6e2,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xa8d4,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xcdce,0xffff, + 0xa2d6,0xffff,0xffff,0xffff,0xffff,0xffff,0xf1c0,0xffff, + 0xffff,0xffff,0xb8c9,0xffff,0xffff,0xe1bd,0xbad7,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xafbd,0xffff,0xc1de,0xffff,0xffff,0xffff, + 0xffff,0xefc0,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xcad7,0xffff,0xffff,0xffff,0xf8e9,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xc9f6, + 0xffff,0xffff,0xcbe3,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xdbb3,0xffff,0xffff,0xb7b6,0xffff,0xffff,0xffff, + 0xffff,0xc3f0,0xcff0,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xebdf, + 0xffff,0xffff,0xe1b6,0xffff,0xffff,0xffff,0xecd3,0xffff, + 0xffff,0xcbcb,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xb5e4,0xffff,0xffff,0xffff, + 0xe2bb,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xc2ed,0xffff,0xffff, + 0xdcb4,0xffff,0xffff,0xffff,0xb8c1,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xefd3,0xb5c5,0xffff, + 0xffff,0xd6bc,0xffff,0xffff,0xffff,0xffff,0xe4ba,0xffff, + 0xffff,0xffff,0xd9ee,0xffff,0xb6ef,0xffff,0xffff,0xffff, + 0xecef,0xc6e3,0xffff,0xffff,0xa8f6,0xffff,0xffff,0xabec, + 0xffff,0xb1d1,0xffff,0xffff,0xffff,0xffff,0xffff,0xacf7, + 0xffff,0xecb6,0xffff,0xbff0,0xe4d9,0xb3f6,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xa5d0, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xc0d4,0xdee2, + 0xffff,0xffff,0xffff,0xffff,0xdab0,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xdff0,0xffff,0xd0c3,0xffff,0xffff,0xf9c0,0xf2ec,0xffff, + 0xcfc7,0xffff,0xffff,0xa5f4,0xffff,0xffff,0xffff,0xffff, + 0xefd2,0xffff,0xffff,0xffff,0xd7d6,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xd0b4,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xc0c0,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xced3, + 0xffff,0xffff,0xd5ee,0xffff,0xffff,0xffff,0xd1ef,0xffff, + 0xffff,0xffff,0xffff,0xfed2,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xd6c4,0xffff,0xffff,0xdbc1, + 0xffff,0xffff,0xffff,0xbdf0,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xb4df, + 0xffff,0xffff,0xffff,0xffff,0xcfc2,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xd3cb,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xb3c7,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xafb7,0xbbb5,0xffff, + 0xffff,0xffff,0xffff,0xfdc1,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xe0dc,0xffff,0xbade,0xffff,0xffff,0xfdf2, + 0xffff,0xffff,0xc0b0,0xffff,0xefd5,0xcfb3,0xb1c4,0xffff, + 0xffff,0xf4d4,0xffff,0xffff,0xffff,0xffff,0xcee0,0xcbd4, + 0xffff,0xffff,0xffff,0xffff,0xbfd0,0xf5bd,0xffff,0xffff, + 0xd9ef,0xffff,0xffff,0xffff,0xb0f6,0xd6e7,0xffff,0xffff, + 0xffff,0xffff,0xf0e6,0xffff,0xffff,0xffff,0xffff,0xe0f6, + 0xffff,0xffff,0xcbf0,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xebce,0xffff,0xffff,0xffff,0xffff,0xffff,0xaec2, + 0xffff,0xc7c2,0xffff,0xd3bb,0xa3df,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xbbc3,0xffff,0xffff,0xdee4,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xaef1,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xbcf1,0xffff,0xffff,0xffff,0xffff,0xffff,0xdac2,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xf6bc,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xebea,0xa2d7,0xebbd,0xcbda,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xd1f5,0xffff,0xf6e9,0xffff, + 0xcad3,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xd5b1,0xffff,0xa4c2,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xd2e3,0xffff,0xffff,0xffff, + 0xffff,0xc0f0,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xf8c7,0xffff,0xd8df, + 0xffff,0xffff,0xdcb7,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xc2e4,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xe1e7,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xbfed,0xffff,0xffff,0xffff, + 0xeed4,0xffff,0xffff,0xffff,0xffff,0xf8be,0xb8e7,0xffff, + 0xccbc,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xdbb9,0xffff,0xffff,0xbdce,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xcfbd,0xffff,0xfdb9, + 0xffff,0xffff,0xd7ee,0xb3b9,0xb5b1,0xaac3,0xf7b0,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xb2f7,0xb7cd,0xffff, + 0xddb9,0xffff,0xffff,0xffff,0xffff,0xdaf6,0xffff,0xffff, + 0xffff,0xc4f0,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xf7db,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xc5c8,0xffff,0xffff,0xffff, + 0xffff,0xdde9,0xffff,0xe5b3,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xa2d1,0xffff,0xffff,0xffff,0xb7c8,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xb2e7,0xffff, + 0xcde7,0xdec2,0xffff,0xffff,0xc5bd,0xa8cc,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xf8c8,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xdcce,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xf1e9,0xefb4, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xaabf,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xadc6,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xcef0,0xffff,0xffff,0xb5f6,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xbcdf, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xa8f1,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xd4c7,0xffff,0xd9f3,0xffff,0xffff,0xffff,0xc0d5,0xbfb8, + 0xd7e7,0xbcee,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xfcdd,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xf3ce,0xdccc,0xffff, + 0xffff,0xffff,0xffff,0xf9bc,0xffff,0xfbe9,0xffff,0xa5ce, + 0xffff,0xffff,0xffff,0xdbee,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xcae3,0xffff,0xa5c1,0xe9c1,0xffff,0xffff,0xacec, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xa5e3,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xbdc5,0xbad0,0xffff, + 0xfdbd,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xa8e8,0xfab2,0xffff, + 0xabf1,0xffff,0xffff,0xffff,0xebc2,0xc3ed,0xffff,0xffff, + 0xffff,0xc8f3,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xf1d2,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xb9b2,0xffff,0xffff,0xffff,0xbeda,0xdfd6,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xfdce,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xd5bc,0xffff, + 0xffff,0xffff,0xffff,0xb9b0,0xffff,0xffff,0xeaf6,0xf7f6, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xc0cf,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xf8d5,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xb8d3,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xc2b4,0xc7e7, + 0xffff,0xbfee,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xb0d7,0xffff,0xffff,0xacda,0xd0cb,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xe6f5,0xfae9,0xffff,0xa3d2, + 0xffff,0xffff,0xd0ee,0xffff,0xfaee,0xffff,0xffff,0xffff, + 0xf8bc,0xc8e3,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xcee3,0xdcf6,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xb7f6,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xecc7,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xc9e4,0xffff, + 0xe2ec,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xb1cc,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xcff4,0xffff,0xb1e7,0xc9e7, + 0xffff,0xffff,0xffff,0xffff,0xa6b3,0xebd3,0xbbdb,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xcff1,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xe2ea,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xc6c4,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xf2c8,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xfdf6,0xd7f6, + 0xb2f0,0xffff,0xffff,0xffff,0xe3b5,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xfccc, + 0xffff,0xffff,0xffff,0xffff,0xf3de,0xffff,0xffff,0xd9e8, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xb7be, + 0xb2f1,0xffff,0xffff,0xffff,0xffff,0xffff,0xbacd,0xd5f6, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xe0c3,0xc8e7, + 0xffff,0xc2d8,0xffff,0xffff,0xc9eb,0xcbd0,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xd7dc,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xc9f1,0xffff,0xffff,0xe5bb,0xffff,0xdeda, + 0xffff,0xdec9,0xffff,0xffff,0xffff,0xd8d4,0xffff,0xb7d1, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xc0ef,0xffff,0xffff, + 0xefef,0xffff,0xffff,0xffff,0xffff,0xb5f7,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xb1f0,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xe8e1,0xf0b1,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xa3ec,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xfdbb, + 0xffff,0xffff,0xffff,0xd6f3,0xe1d9,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xeff1,0xffff,0xf0eb,0xd9be,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xd1bb,0xffff, + 0xffff,0xf6b1,0xffff,0xffff,0xffff,0xf9e9,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xf2ee,0xedb4,0xffff,0xffff, + 0xffff,0xd0cf,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xb4f6,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xc7d9,0xffff,0xadd0,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xecc4,0xffff,0xffff,0xffff, + 0xffff,0xdfe8,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xb1d3, + 0xffff,0xffff,0xffff,0xfdf3,0xffff,0xabe7,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xc9be,0xffff,0xafd7, + 0xf2cd,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xb5cb,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xdab4,0xffff,0xffff,0xddb5, + 0xffff,0xffff,0xffff,0xe2ee,0xffff,0xffff,0xffff,0xfcee, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xa4ce,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xbbd1,0xffff,0xffff,0xffff,0xffff,0xb6f6,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xc5e8, + 0xffff,0xffff,0xb6bb,0xffff,0xffff,0xffff,0xafe4,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xeeed,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xd0f4,0xcabd,0xffff,0xffff, + 0xffff,0xffff,0xecf1,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xb4ca,0xffff, + 0xf5ca,0xffff,0xffff,0xffff,0xaeda,0xffff,0xffff,0xebd2, + 0xffff,0xe4ea,0xffff,0xffff,0xf2f5,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xdbb6,0xe3ee,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xe4bc,0xffff,0xffff,0xffff,0xcdc8,0xffff,0xffff, + 0xffff,0xb5b2,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xc6f0,0xffff,0xffff,0xffff,0xe4c1,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xbec9,0xffff,0xc2df,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xf9bf,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xbaba,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xb7bb,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xe9c0,0xffff,0xffff,0xffff,0xd8cf, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xdcf1,0xffff,0xffff,0xffff,0xffff,0xe9d2, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xb6d4, + 0xffff,0xf3b3,0xffff,0xffff,0xe6b7,0xffff,0xffff,0xe4ef, + 0xffff,0xc9e3,0xffff,0xc1f6,0xffff,0xffff,0xa5f2,0xaec6, + 0xbce2,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xb3b5,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xb0c1,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xccf4,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xb5e7,0xffff, + 0xd3e7,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xd5c3,0xffff, + 0xedd6,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xa9db,0xffff,0xffff,0xffff,0xffff,0xccc3,0xf8cb,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xb1be,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xf4c5,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xd4df, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xe5f3,0xe1c2,0xffff,0xe7c2,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xf9dc,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xcdd4,0xd4ee,0xffff,0xffff,0xffff,0xffff,0xeaef, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xc7cd,0xadec, + 0xb9ce,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xe5e7,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xa4d1,0xffff,0xffff, + 0xfee6,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xd7da,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xeff5,0xffff,0xecb0,0xffff, + 0xffff,0xffff,0xd3ee,0xffff,0xffff,0xffff,0xd3ef,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xaff7, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xf5cc, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xf4b1,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xa2b7,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xbbe7,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xb1f2, + 0xc0ce,0xffff,0xffff,0xffff,0xffff,0xadcb,0xffff,0xb4c7, + 0xffff,0xe3ea,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xe7cf,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xa2d5,0xffff,0xffff,0xffff,0xffff,0xb5c6,0xaeec, + 0xc7e2,0xffff,0xffff,0xffff,0xffff,0xffff,0xf8f6,0xffff, + 0xffff,0xc7f0,0xffff,0xffff,0xffff,0xb8f6,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xbeb3,0xffff,0xffff,0xacb9,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xa9b7,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xf7c2,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xc0be,0xffff,0xffff,0xffff, + 0xf8d0,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xbcc0,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xe0cd,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xfce9,0xffff,0xcaca, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xe4cb,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xfcf6,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xcdc2,0xffff, + 0xffff,0xc7d3,0xffff,0xffff,0xa3c2,0xffff,0xffff,0xc9e8, + 0xffff,0xb5b5,0xffff,0xffff,0xffff,0xd5d7,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xf5d3,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xabdd,0xd4b2,0xa1dd,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xe5b3,0xffff,0xffff,0xffff,0xaada,0xcebf,0xffff,0xffff, + 0xffff,0xcdb4,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xaeb3,0xffff,0xffff,0xaaef,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xa6f6,0xabba,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xdbf6,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xc1bb,0xffff,0xf2e3,0xdece, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xcdbc,0xf8b8,0xf4bd,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xa5be, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xebe0,0xa4bb, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xa8b8,0xc7b4,0xffff, + 0xffff,0xffff,0xa5c5,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xb2be,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xdef6,0xffff,0xffff, + 0xffff,0xb5c8,0xffff,0xffff,0xf5f7,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xdbe1,0xffff, + 0xffff,0xffff,0xffff,0xf0cb,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xf5bc,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xb3e7,0xecb7, + 0xf8b2,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xa5dd,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xa9d5,0xffff,0xffff,0xffff, + 0xffff,0xcdc9,0xffff,0xffff,0xffff,0xe1c7,0xe8b1,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xe5ee,0xffff,0xffff,0xabcb,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xd1f0,0xffff,0xffff,0xbaf6,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xd9d8,0xffff,0xffff,0xffff, + 0xffff,0xb5c7,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xbfe8,0xffff,0xeacb,0xffff,0xffff,0xc7d5,0xffff,0xffff, + 0xb8cb,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xccd3,0xffff,0xf5e7,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xfbe6,0xdec8,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xd5da,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xe7b1,0xffff, + 0xffff,0xffff,0xffff,0xc2bd,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xbee2,0xffff,0xb9e5,0xffff,0xffff,0xd9f6,0xfaf6,0xddf6, + 0xffff,0xffff,0xffff,0xffff,0xb9c3,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xdbbc,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xd2d1,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xb9c0,0xb1ca,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xf6bf,0xffff,0xffff,0xa4c1,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xcae7, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xd1dc,0xffff, + 0xffff,0xffff,0xdbdd,0xffff,0xffff,0xffff,0xbacf,0xffff, + 0xffff,0xffff,0xc4b3,0xffff,0xb1da,0xc7da,0xf9b0,0xffff, + 0xffff,0xe2c5,0xffff,0xffff,0xffff,0xffff,0xa9c5,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xfbb3,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xcacf,0xffff,0xffff, + 0xd2cd,0xffff,0xffff,0xffff,0xffff,0xb9f6,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xb4c8,0xffff,0xffff, + 0xf0db,0xffff,0xffff,0xffff,0xffff,0xade1,0xffff,0xb1df, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xd9c8,0xffff,0xffff,0xffff,0xffff,0xd3e4,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xf8e1,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xbcd4,0xffff,0xffff,0xf5cb, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xf5b2, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xd9e2,0xcfb8,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xefee,0xb2ef,0xffff,0xffff,0xffff, + 0xf0ef,0xffff,0xffff,0xd3d4,0xffff,0xffff,0xffff,0xffff, + 0xf3c1,0xffff,0xefe6,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xf6d8,0xffff,0xf2d4,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xfcde,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xece4,0xffff, + 0xafc2,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xf4e7,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xa8c2,0xffff,0xecba,0xffff,0xffff,0xffff, + 0xa7d3,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xafda,0xffff,0xabc7,0xffff, + 0xffff,0xcdcf,0xffff,0xffff,0xffff,0xffff,0xffff,0xd9b3, + 0xffff,0xbdd2,0xffff,0xf5b8,0xffff,0xffff,0xffff,0xf3ee, + 0xffff,0xffff,0xffff,0xffff,0xefeb,0xb8e8,0xffff,0xffff, + 0xc8e2,0xffff,0xf2e6,0xc3f7,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xb8c5,0xffff,0xf2f7,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xead0, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xbab5,0xffff,0xffff, + 0xdcb3,0xffff,0xffff,0xa1d2,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xede8,0xffff,0xffff,0xd0ce,0xa5bd,0xebe4,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xa9d7,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xfae6,0xffff,0xffff,0xffff, + 0xffff,0xc7f4,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xcdf2, + 0xffff,0xffff,0xaecf,0xffff,0xc0c6,0xccb7,0xd6da,0xfed3, + 0xffff,0xf4c2,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xded7,0xb4bd,0xffff,0xffff,0xb7ef,0xbdef,0xd9ce,0xffff, + 0xe5ef,0xd2ba,0xffff,0xa6bc,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xcbf7,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xb1c2,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xb9b1,0xffff,0xb7b5,0xf3b2,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xfac0,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xfce6,0xffff,0xffff,0xddd7, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xd4bc, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xb2bd,0xd9da, + 0xffff,0xfabc,0xffff,0xffff,0xffff,0xbec1,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xc7cf,0xf6dd,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xccd8,0xffff,0xffff,0xffff, + 0xffff,0xa4d7,0xdacc,0xffff,0xffff,0xffff,0xfbf6,0xffff, + 0xffff,0xffff,0xbaf0,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xc4df,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xe9b9,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xefe1,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xa3f0, + 0xffff,0xffff,0xffff,0xffff,0xfde6,0xffff,0xf7d0,0xd0e7, + 0xcbcf,0xdbcf,0xffff,0xffff,0xf4b7,0xffff,0xffff,0xffff, + 0xffff,0xc7b8,0xf1dc,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xd4d5,0xffff,0xffff,0xa2ea,0xffff,0xa8c7, + 0xf9da,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xf3b8,0xffff,0xffff,0xffff,0xbae8,0xc5bf,0xc9b7, + 0xffff,0xe5e6,0xffff,0xe5cc,0xffff,0xffff,0xfac8,0xffff, + 0xffff,0xffff,0xd2f0,0xffff,0xbcf6,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xc7d2,0xb2c9,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xa5df,0xfabd,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xe0bb, + 0xffff,0xffff,0xffff,0xffff,0xd2c8,0xffff,0xffff,0xffff, + 0xffff,0xe5d2,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xe6b3, + 0xffff,0xffff,0xffff,0xfcf5,0xb0da,0xead2,0xbbd0,0xc1b6, + 0xffff,0xb3b8,0xffff,0xbbd3,0xffff,0xd4bb,0xffff,0xa1d1, + 0xffff,0xffff,0xfbbe,0xfeee,0xffff,0xc1ef,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xebc0,0xffff,0xb9f7,0xffff,0xffff, + 0xc9e2,0xd4be,0xffff,0xc6f7,0xffff,0xffff,0xffff,0xffff, + 0xa7d4,0xffff,0xffff,0xffff,0xbdf6,0xa3c8,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xd2c2,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xb1d7,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xafd0,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xe2b2,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xc6ce,0xb3cd,0xb4e7,0xffff, + 0xdae7,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xf1dd,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xe6ea,0xffff,0xffff,0xffff,0xfee9,0xffff,0xffff, + 0xc7d4,0xffff,0xffff,0xf8d2,0xf4ee,0xffff,0xd6ef,0xffff, + 0xffff,0xa7b7,0xffff,0xd1c4,0xffff,0xb9e8,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xc5f7,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xcccf,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xa9c1,0xafd9,0xffff,0xffff,0xffff,0xd0df, + 0xffff,0xffff,0xffff,0xb4e6,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xafc1,0xffff,0xffff,0xe3c9,0xffff,0xffff,0xffff, + 0xffff,0xecbc,0xffff,0xffff,0xffff,0xffff,0xf3e4,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xfcd3,0xffff,0xebe7,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xbfcb,0xffff,0xcfe7, + 0xffff,0xffff,0xffff,0xffff,0xbabd,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xa3f6,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xa1ea,0xffff,0xc5d2, + 0xffff,0xffff,0xffff,0xffff,0xfab3,0xffff,0xf8ee,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xf8c2,0xe0e6,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xb6f0,0xffff,0xffff,0xbaf5,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xbfcf,0xffff,0xffff, + 0xffff,0xbec6,0xffff,0xa6df,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xc9e9,0xe2e9,0xffff,0xffff,0xacbd,0xf1e3,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xa8ca,0xffff,0xffff,0xffff,0xffff,0xe9f0, + 0xffff,0xf6ed,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xe3bc,0xffff,0xffff,0xc9c4,0xd0cc,0xffff,0xeaf4, + 0xffff,0xffff,0xffff,0xb2d0,0xffff,0xffff,0xffff,0xc8dc, + 0xffff,0xffff,0xa4dd,0xb6c0,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xe7d7,0xf7b5,0xa5d2,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xadef,0xcdee,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xddbc,0xffff,0xffff,0xffff,0xffff,0xffff,0xf9f6, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xdad2,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xfedb,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xb4e3,0xffff,0xffff,0xffff,0xffff,0xabb6,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xfee4,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xe2e7,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xbde7,0xc6c2, + 0xc2c0,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xbfdc,0xa3dd,0xffff,0xffff,0xffff,0xc9f2, + 0xffff,0xffff,0xffff,0xa5b4,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xcad6,0xffff,0xffff,0xfbc7,0xffff,0xffff,0xc9c1, + 0xffff,0xffff,0xffff,0xa5ef,0xb8ef,0xc7ef,0xa1ef,0xa6ef, + 0xe7ef,0xebb9,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xe3e6,0xffff,0xcaf7,0xffff,0xffff,0xd4f6, + 0xb7f0,0xffff,0xffff,0xefbc,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xd6b2,0xffff,0xffff,0xffff,0xffff,0xd5df, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xa3f2,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xa8b0,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xeabc,0xffff, + 0xffff,0xffff,0xa5ca,0xf6c2,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xdcc2,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xe5ea,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xc6b8,0xffff,0xffff,0xffff,0xcbef,0xffff, + 0xffff,0xf6c3,0xffff,0xffff,0xffff,0xffff,0xe2cc,0xffff, + 0xcae2,0xffff,0xa7c9,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xced1,0xffff,0xbbf6,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xebbf,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xd7ed,0xffff,0xffff,0xffff, + 0xffff,0xddf3,0xffff,0xffff,0xa6c5,0xffff,0xbce7,0xcee7, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xb6d2,0xffff,0xb5dd,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xcab4,0xc6da,0xffff,0xffff, + 0xffff,0xcbd5,0xffff,0xffff,0xffff,0xffff,0xffff,0xf5c2, + 0xffff,0xffff,0xffff,0xadcd,0xb0ef,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xeeb6,0xffff, + 0xcbe2,0xe6e6,0xf3e6,0xffff,0xe3d3,0xffff,0xffff,0xe2f6, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xf6b8,0xf3bc,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xcfdb,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xdcd4,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xc3c0,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xb6c4,0xffff, + 0xffff,0xffff,0xfaed,0xffff,0xffff,0xffff,0xffff,0xc8ce, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xdfcf,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xc4b6,0xffff,0xffff,0xffff,0xffff,0xffff,0xb9bb, + 0xffff,0xffff,0xd8ee,0xffff,0xffff,0xffff,0xe4b8,0xffff, + 0xbfd4,0xcde3,0xeada,0xffff,0xffff,0xffff,0xa6f2,0xffff, + 0xcce2,0xe2e6,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xe6df, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xd7c5,0xffff,0xcec2,0xffff,0xffff,0xffff, + 0xe7e8,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xeebe,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xe5c4,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xe9dc,0xffff,0xffff,0xffff,0xcfce,0xcfd2, + 0xffff,0xffff,0xffff,0xffff,0xbdd3,0xbbd7,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xf5b9,0xffff,0xffff, + 0xffff,0xffff,0xd1ee,0xffff,0xccc6,0xf8b9,0xffff,0xffff, + 0xffff,0xcfe3,0xffff,0xffff,0xffff,0xffff,0xd5d1,0xffff, + 0xa1c0,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xb3f0,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xd5b8,0xffff,0xffff,0xdcdf, + 0xffff,0xffff,0xffff,0xa3e6,0xffff,0xffff,0xffff,0xffff, + 0xc3d4,0xffff,0xffff,0xffff,0xafcc,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xedc7,0xffff,0xe8b7, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xbabe,0xffff,0xffff,0xffff,0xa3e7,0xffff,0xffff,0xdcd7, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xbcda,0xffff,0xffff,0xffff, + 0xeac0,0xffff,0xffff,0xffff,0xffff,0xfde9,0xffff,0xffff, + 0xffff,0xffff,0xd6ee,0xffff,0xffff,0xffff,0xf2d5,0xcdc1, + 0xe2cf,0xcce3,0xffff,0xffff,0xffff,0xffff,0xffff,0xbde2, + 0xcde2,0xbbca,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xa8d8,0xc7c3,0xffff,0xfeb0,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xe7d6,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xf1d1, + 0xffff,0xffff,0xffff,0xffff,0xd3ed,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xbfb4,0xffff,0xa9bc,0xa8bc, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xafd1,0xffff,0xd3da,0xe4b1, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xc7e5, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xc6b6,0xffff,0xffff, + 0xffff,0xffff,0xc2c9,0xffff,0xffff,0xffff,0xffff,0xbfe2, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xb8f0,0xf3e1,0xbef6,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xcac9,0xffff,0xffff,0xffff,0xffff,0xe1da,0xffff, + 0xffff,0xacb5,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xb1bd,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xf9ef, + 0xffff,0xffff,0xecf3,0xffff,0xa2e7,0xffff,0xd0b6,0xffff, + 0xffff,0xffff,0xc5ce,0xd6eb,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xe8d2,0xb8cc,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xc4f5,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xf0c4,0xffff,0xffff,0xffff,0xffff,0xd7ef,0xa9ef, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xc0e2, + 0xffff,0xd5cd,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xecd1,0xffff,0xd4f0,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xcfb1,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xa5da,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xf7c7,0xffff,0xffff,0xb2b1,0xffff,0xdfb1, + 0xffff,0xc6d0,0xffff,0xffff,0xf1ee,0xffff,0xffff,0xe6ef, + 0xffff,0xffff,0xffff,0xc6d4,0xffff,0xffff,0xa7f2,0xffff, + 0xffff,0xffff,0xe2c2,0xffff,0xffff,0xe7f6,0xfef6,0xffff, + 0xffff,0xb4f0,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xc7d1,0xffff,0xcfd9,0xffff,0xffff,0xffff,0xc8e0, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xf2e5, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xebbb,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xf2bc,0xffff,0xb4c9,0xffff,0xdeb5,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xa9b6,0xffff,0xc3da,0xd8da,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xd6c2,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xafef,0xffff,0xffff,0xe2ef, + 0xffff,0xc4d4,0xffff,0xffff,0xffff,0xffff,0xffff,0xc1e2, + 0xffff,0xe1e6,0xffff,0xffff,0xffff,0xe1f6,0xffff,0xffff, + 0xbcd1,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xc7d8,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xc1bd,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xf2e4,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xe7e7,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xc5e7,0xc1b1, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xa6dd,0xffff,0xffff,0xd5d2,0xffff,0xffff,0xcff2,0xffff, + 0xffff,0xffff,0xffff,0xbcb8,0xd4ca,0xffff,0xfdc3,0xc5f6, + 0xffff,0xb5c0,0xffff,0xffff,0xb5b3,0xffff,0xffff,0xffff, + 0xcbb5,0xa7f5,0xffff,0xffff,0xaeef,0xffff,0xf8c4,0xffff, + 0xf7c4,0xffff,0xf3d5,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xa2bc,0xffff,0xebdd,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xc8f0,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xe0df, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xc1e1,0xffff,0xc5d5, + 0xffff,0xffff,0xffff,0xffff,0xbfc0,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xd0b2,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xbebb, + 0xffff,0xffff,0xffff,0xcced,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xf1f3,0xffff,0xbdd6,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xb6b9,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xebc7,0xffff,0xffff, + 0xa8c3,0xffff,0xffff,0xffff,0xfed4,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xabef,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xb9b7, + 0xc4c8,0xffff,0xf1e6,0xffff,0xffff,0xffff,0xe5f6,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xfac1,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xb1d9,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xfac6, + 0xffff,0xc4e9,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xb6ed,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xb6bc,0xf3b0,0xb5d4,0xd2e7, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xafdd,0xdedd,0xffff,0xffff,0xffff,0xffff,0xacd3, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xecb9,0xffff,0xffff,0xdfc2, + 0xffff,0xa6f5,0xeaee,0xffff,0xffff,0xffff,0xd8ef,0xffff, + 0xe9ef,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xe9e6,0xeee6,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xadd9,0xffff,0xffff,0xffff,0xe7c5, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xbfc7, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xc3c6,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xdad6,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xd7b7,0xffff,0xffff,0xd1e7, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xb2f2, + 0xffff,0xffff,0xfbbc,0xffff,0xabca,0xbada,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xfcbe,0xffff,0xffff,0xcee5, + 0xffff,0xffff,0xffff,0xb3cf,0xffff,0xc9ef,0xffff,0xd3d6, + 0xffff,0xffff,0xffff,0xe7b5,0xffff,0xffff,0xb8d4,0xffff, + 0xffff,0xffff,0xf4e6,0xffff,0xffff,0xffff,0xa4f7,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xb9d7,0xffff,0xc1e6,0xdec7,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xb9b9,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xace8,0xadbb,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xa1e7,0xafe7,0xffff,0xdff1, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xc6bc,0xffff,0xffff,0xffff,0xf7b2, + 0xffff,0xffff,0xffff,0xcff5,0xffff,0xadbc,0xffff,0xffff, + 0xffff,0xffff,0xe6ee,0xffff,0xffff,0xffff,0xffff,0xebef, + 0xffff,0xd1e3,0xffff,0xffff,0xffff,0xffff,0xaaf2,0xfbd2, + 0xcff7,0xffff,0xf5e6,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xd3c5,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xe8c2,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xc0c7,0xffff,0xffff,0xffff,0xffff, + 0xb9c7,0xffff,0xe6e9,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xb4ee,0xffff, + 0xffff,0xffff,0xffff,0xbaed,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xc1e7,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xefb2,0xc1da,0xffff,0xc3c8, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xcdca,0xffff,0xfdee,0xffff,0xffff,0xffff,0xffff, + 0xe0c2,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xfdc7,0xffff,0xffff,0xe9f6,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xd6b6, + 0xffff,0xffff,0xffff,0xffff,0xb5ca,0xffff,0xffff,0xffff, + 0xffff,0xdfb7,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xe0bd,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xf6cb,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xeff3,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xb6d1,0xb8da,0xffff,0xffff,0xffff, + 0xffff,0xacd7,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xa3d6,0xffff,0xffff,0xffff,0xb3ef,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xcfd4,0xdfb5,0xc2e2, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xa3f7,0xffff, + 0xb9f0,0xffff,0xd3f0,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xd0b9,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xb8e5,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xfbc4,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xf9d5,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xfed1,0xffff,0xffff,0xf9f0, + 0xffff,0xffff,0xffff,0xe2d1,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xaee7,0xe0b1,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xb4b5,0xa9d2,0xa6b4,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xe6b9,0xffff,0xeeb9,0xc2da,0xa9da,0xbec0, + 0xffff,0xe7ea,0xf5f4,0xffff,0xf9d0,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xddee,0xffff,0xffff,0xa1d5,0xffff,0xffff, + 0xc7f6,0xcbd1,0xf5d2,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xf0c0,0xa5f7,0xffff, + 0xbbf0,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xf3c9,0xdab8,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xd1ec, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xafb4, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xc4b7,0xffff,0xbabb,0xffff, + 0xa7b2,0xffff,0xffff,0xfced,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xabc1,0xdfce,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xa7da,0xb9da,0xc2c1,0xffff,0xdfda, + 0xffff,0xbab9,0xffff,0xffff,0xffff,0xa3ea,0xffff,0xffff, + 0xdac1,0xc5ee,0xe5c1,0xf9ee,0xe2be,0xffff,0xffff,0xe3ef, + 0xe4d4,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xe8f6,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xa8b9,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xd7c2,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xd5b4,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xecd2,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xb0cb,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xb0e7,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xcadc,0xffff,0xffff,0xffff,0xccf2,0xffff,0xabd0, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xb4b1,0xfcc8,0xffff,0xffff,0xede9,0xffff,0xffff,0xffff, + 0xa6b5,0xc6ee,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xd6d1,0xc2b3,0xffff,0xffff,0xffff,0xe0c0,0xffff, + 0xd0f7,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xd5f0,0xf6c0,0xffff,0xe8ed,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xb4d0,0xffff,0xffff,0xffff, + 0xffff,0xf5c3,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xf7bc,0xe4e9,0xffff,0xffff,0xffff,0xbdc0,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xb6e8,0xffff,0xb1c5, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xa8b5,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xc9cd,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xd6cc,0xb5da,0xffff,0xffff,0xffff, + 0xead5,0xd3d8,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xc9ee,0xffff,0xfac3,0xffff,0xcdb6,0xffff,0xffff, + 0xffff,0xd5e3,0xbdc2,0xffff,0xffff,0xeccf,0xffff,0xffff, + 0xffff,0xffff,0xe8e6,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xc5f0,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xdcd8,0xe1d1,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xedbf,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xb6c1, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xe5f0,0xffff,0xffff,0xffff,0xffff,0xffff,0xd1b8,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xe5c3,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xdaeb,0xffff,0xffff,0xffff, + 0xa7dd,0xffff,0xf4cf,0xb4de,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xd9c3,0xffff,0xb0bb,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xfeda,0xffff,0xdcee,0xffff,0xffff,0xffff,0xffff,0xe8ef, + 0xffff,0xd4e3,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xf6b2,0xffff,0xffff,0xffff,0xffff,0xffff,0xa2f7,0xffff, + 0xffff,0xffff,0xc2f0,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xb4b4,0xffff,0xffff,0xccdf, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xe4e2,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xb1c7,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xa8d3,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xcded,0xbbc2,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xaac1,0xd1cd,0xa7c5,0xd5b2,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xe9d0,0xffff,0xffff,0xd3f2, + 0xffff,0xffff,0xffff,0xa6da,0xc3b8,0xdbc2,0xffff,0xffff, + 0xbab8,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xc8ee,0xe0ee,0xa2ef,0xd6b8,0xffff,0xd5ef,0xffff, + 0xffff,0xd0e3,0xffff,0xffff,0xffff,0xb3d2,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xa5b3,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xdcdc,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xafd2,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xeac2,0xffff,0xb1b5,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xcfb4,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xadce,0xffff,0xffff,0xffff,0xb2c2,0xffff,0xffff,0xeef2, + 0xffff,0xffff,0xffff,0xffff,0xeacf,0xc5da,0xf7bd,0xffff, + 0xc6b2,0xffff,0xffff,0xffff,0xffff,0xe4ca,0xffff,0xffff, + 0xa6db,0xa4b6,0xebee,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xd3e3,0xffff,0xffff,0xffff,0xa5b6,0xa9f2,0xffff, + 0xffff,0xa7ba,0xe7e6,0xffff,0xb3c2,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xeab9,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xb3ce,0xd5e7, + 0xffff,0xb0cf,0xf9c9,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xd3ca,0xffff,0xffff,0xffff,0xffff,0xd4da, + 0xb1b9,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xc7ee,0xdaee,0xcecf,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xeac7,0xffff,0xc7cb, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xf7c0,0xcace,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xb4e1,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xc7e8, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xe3e3,0xffff, + 0xfbb6,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xcacb,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xc5ba,0xffff,0xffff,0xbaf2, + 0xf2d9,0xffff,0xffff,0xb5d1,0xb7da,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xf4d1,0xffff,0xaeb9,0xffff,0xffff,0xa5b1, + 0xcee2,0xffff,0xf6e6,0xffff,0xffff,0xffff,0xe3f6,0xffff, + 0xffff,0xc9f0,0xd6f0,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xafb5, + 0xffff,0xdccf,0xffff,0xffff,0xffff,0xffff,0xffff,0xe6d4, + 0xffff,0xffff,0xe9e9,0xffff,0xffff,0xffff,0xdce4,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xe4f1,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xe7cb,0xc3e7,0xafd6, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xe8ea,0xffff,0xffff,0xffff,0xffff,0xddda, + 0xffff,0xdeea,0xffff,0xffff,0xeee9,0xf8b7,0xffff,0xffff, + 0xf7da,0xffff,0xffff,0xffff,0xffff,0xffff,0xdfef,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xeecf,0xabf2,0xceca, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xa1f7,0xffff, + 0xffff,0xffff,0xa5d3,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xc9d8,0xffff,0xc5cf, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xbfe1,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xbfec, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xc5c0,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xbfe7,0xc9c9, + 0xffff,0xffff,0xf9f1,0xffff,0xb3c1,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xb9f2,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xa8da,0xffff,0xc4da,0xffff,0xffff, + 0xffff,0xb8d7,0xffff,0xe7f5,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xebd5,0xdfee,0xffff,0xbeef,0xffff,0xffff,0xb4ef, + 0xffff,0xd6e3,0xffff,0xffff,0xffff,0xb3cb,0xffff,0xffff, + 0xffff,0xe6c2,0xffff,0xffff,0xffff,0xffff,0xa6f7,0xffff, + 0xffff,0xcaf0,0xd8f0,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xe9b6,0xa9e6,0xffff,0xe8b3,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xf1b9,0xffff,0xffff,0xffff,0xf3c8,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xe5d6,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xfad4,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xf4c4,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xfdc6,0xffff,0xfdb5,0xa1c3,0xffff, + 0xffff,0xffff,0xffff,0xd9d7,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xcbd3,0xeeee,0xffff,0xffff,0xffff,0xb5ef, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xfcf1,0xcbb9,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xd0f6,0xf6f6,0xffff,0xffff, + 0xe8ba,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xa6b1,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xe7e9,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xc0b6,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xf5d6,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xb8cf,0xffff,0xb7c1,0xffff, + 0xffff,0xffff,0xb0d6,0xffff,0xeac6,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xf7dd,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xb6c6,0xffff,0xffff,0xffff,0xffff,0xb7d5,0xffff,0xffff, + 0xffff,0xffff,0xe4ee,0xffff,0xffff,0xcaef,0xffff,0xd0ef, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xebd0,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xaaf7,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xa7cb,0xd6c3, + 0xffff,0xe4d2,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xebe9,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xfcf0, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xc1d4,0xa6e7,0xadbe,0xffff,0xffff, + 0xbff3,0xffff,0xffff,0xcdd5,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xecc2,0xffff, + 0xffff,0xffff,0xffff,0xc7bc,0xffff,0xd2da,0xffff,0xffff, + 0xf5bb,0xf9d4,0xffff,0xffff,0xedc8,0xdfd3,0xffff,0xffff, + 0xffff,0xffff,0xd8bc,0xffff,0xbcc2,0xc6ef,0xe0ef,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xebf6,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xf6e1,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xf6bb,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xa5e7,0xffff,0xc2e7,0xffff, + 0xffff,0xffff,0xf7f1,0xffff,0xf7eb,0xaff4,0xffff,0xffff, + 0xffff,0xeadc,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xb6da,0xffff,0xffff,0xffff, + 0xb7b7,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xa8ef,0xffff,0xffff,0xb4c1,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xefe7,0xffff,0xc8bd, + 0xffff,0xffff,0xbebd,0xffff,0xcff6,0xdff6,0xe6f6,0xffff, + 0xffff,0xffff,0xffff,0xf3c2,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xaebb,0xffff,0xffff,0xe2df, + 0xfbdb,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xe4cd, + 0xeae2,0xffff,0xffff,0xe2de,0xffff,0xffff,0xffff,0xb0b6, + 0xffff,0xffff,0xffff,0xffff,0xa5e4,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xfde1,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xf5ec,0xffff,0xffff, + 0xffff,0xdabd,0xffff,0xffff,0xf0c9,0xffff,0xffff,0xd4e7, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xc8d7,0xffff, + 0xe7bb,0xffff,0xffff,0xffff,0xf7bf,0xffff,0xffff,0xffff, + 0xffff,0xe3bf,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xb0cc,0xded4,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xbaef,0xffff,0xffff,0xd4ef, + 0xffff,0xc7e3,0xffff,0xffff,0xffff,0xffff,0xfcb2,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xebb8,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xc5d3,0xfdd4,0xffff,0xffff,0xffff, + 0xffff,0xd8b7,0xffff,0xfde5,0xffff,0xffff,0xffff,0xffff, + 0xc6c3,0xffff,0xffff,0xffff,0xffff,0xced4,0xffff,0xffff, + 0xffff,0xffff,0xdfbc,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xa9c7,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xa2bd,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xc2dc,0xffff,0xffff,0xa9d3,0xafc0, + 0xffff,0xcdf1,0xffff,0xefb6,0xffff,0xffff,0xffff,0xffff, + 0xe1b9,0xffff,0xffff,0xffff,0xffff,0xb1ec,0xffff,0xffff, + 0xffff,0xf6b5,0xffff,0xbfd2,0xc2ef,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xcccb,0xacf2,0xfdb1, + 0xffff,0xffff,0xe9d1,0xffff,0xffff,0xffff,0xe4f6,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xa6ca,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xcdea,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xccd1, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xfcc4,0xffff,0xffff,0xffff,0xffff,0xc6c1, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xb1c1,0xffff,0xffff,0xffff,0xbee7,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xb3f1,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xb4da,0xbbda,0xffff,0xffff, + 0xf0d4,0xffff,0xffff,0xffff,0xffff,0xffff,0xc9e5,0xffff, + 0xffff,0xccee,0xffff,0xf7ee,0xc3ef,0xbbef,0xd2ef,0xffff, + 0xffff,0xabc0,0xedda,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xeff4,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xfde8,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xebb3,0xffff, + 0xffff,0xf6d5,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xb6b7,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xfdcc,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xc3f2, + 0xffff,0xffff,0xeaea,0xc8d1,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xc4c9,0xffff,0xffff,0xf5e9,0xbdcf,0xffff,0xffff, + 0xffff,0xffff,0xd2ee,0xffff,0xffff,0xffff,0xddef,0xadc1, + 0xffff,0xd7e3,0xd3b6,0xffff,0xffff,0xfdf1,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xf4f6,0xa9f7,0xffff, + 0xbcf0,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xe7be,0xffff,0xc6d1,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xdcb0,0xffff,0xffff,0xffff, + 0xa4e9,0xffff,0xffff,0xffff,0xaaed,0xb1e4,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xf5c1,0xceb2,0xf4c6,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xabbd,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xf0d0,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xb1c9,0xffff,0xffff,0xa3c0,0xf7c8,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xf4b9,0xffff,0xffff,0xe0e0, + 0xffff,0xffff,0xffff,0xffff,0xa8d7,0xcee1,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xbbd5, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xb0d1,0xffff,0xcad5,0xcdd2, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xc7bf,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xb0ce,0xffff,0xdbd8,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xe8de,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xbfd3,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xa2b4,0xa3bd,0xffff,0xffff,0xffff, + 0xffff,0xbdc7,0xffff,0xffff,0xd4b6,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xe4dc, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xf6c4, + 0xffff,0xffff,0xffff,0xffff,0xbcb5,0xffff,0xf8b4,0xffff, + 0xffff,0xffff,0xffff,0xa7c2,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xd9bb,0xffff,0xffff,0xe4e4,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xd1bf,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xf0e8, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xc0bb, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xc1bc,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xe5d1, + 0xffff,0xd2bf,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xd6e9,0xffff,0xffff,0xffff,0xffff,0xb2cc,0xb3b7, + 0xb9eb,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xa6d3,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xb0bd,0xffff,0xb9c5,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xb3d9,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xf8e2,0xffff,0xeade,0xffff,0xffff,0xffff,0xdcc6, + 0xffff,0xffff,0xffff,0xffff,0xc0cc,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xa1d6,0xffff, + 0xffff,0xc1e3,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xb6e4,0xffff,0xbeec, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xacc9,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xa3e5,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xd0d9,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xf8e0,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xb0e5,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xced9,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xb3cc,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xb2d9,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xb5e9,0xffff,0xdad0,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xcee8,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xd4b4,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xbdbd,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xbfdf, + 0xffff,0xffff,0xffff,0xfce5,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xd0b5,0xa9b3,0xffff,0xffff, + 0xffff,0xfce8,0xffff,0xffff,0xffff,0xd4c0,0xe5cd,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xd7d0,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xbfd6,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xdae9,0xffff,0xffff,0xffff,0xffff,0xd0c2,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xfcc1, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xfdca,0xffff,0xffff,0xffff, + 0xffff,0xdde8,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xd2b6,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xaed0,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xaed7,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xdad3,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xd6c0,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xefbb,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xd9bf,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xf1e8,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xb5e6,0xffff,0xb0e1,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xd9e4,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xd5e1,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xf9b6,0xffff,0xffff,0xffff,0xffff, + 0xebdb,0xb9d1,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xf1b6,0xffff,0xffff,0xffff,0xffff,0xddd4,0xffff,0xffff, + 0xc8e8,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xa1ed,0xffff,0xd2de,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xf7b3,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xf0d9,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xfee0,0xb6be, + 0xffff,0xffff,0xffff,0xf4b2,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xc6e9,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xd4dd,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xbdbb,0xffff, + 0xffff,0xddc0,0xffff,0xffff,0xffff,0xffff,0xfde0,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xd3e8,0xffff,0xffff,0xffff,0xa7bd,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xb7e0, + 0xffff,0xdbdb,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xafed,0xffff,0xffff,0xb2c1,0xffff,0xffff,0xe2e8, + 0xffff,0xffff,0xffff,0xffff,0xede3,0xffff,0xffff,0xffff, + 0xa3c7,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xcfd1, + 0xffff,0xe4db,0xffff,0xffff,0xcfde,0xffff,0xffff,0xffff, + 0xd5c4,0xffff,0xffff,0xffff,0xd0b1,0xffff,0xffff,0xffff, + 0xffff,0xc0e8,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xa2e3,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xcde9,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xd3e0, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xb4e9,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xdde1, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xbbde,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xecbd,0xffff,0xc4d6,0xffff, + 0xffff,0xfbe2,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xb5bb,0xffff,0xffff,0xffff,0xffff,0xffff,0xd3b4, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xd6d4,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xa2be,0xffff,0xffff,0xffff, + 0xffff,0xe2db,0xffff,0xffff,0xffff,0xffff,0xd2b1,0xffff, + 0xfce2,0xffff,0xffff,0xffff,0xffff,0xffff,0xa4d5,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xace6,0xacca,0xffff,0xffff,0xe2e1, + 0xffff,0xffff,0xffff,0xccc0,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xc5e4,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xe2ce,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xa5c2,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xe0b2,0xdac4,0xffff,0xc5c4,0xffff,0xffff, + 0xffff,0xdedb,0xffff,0xbfe6,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xecd5,0xbdc1,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xbfbd,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xd0e8,0xffff,0xffff,0xffff,0xf3d4,0xffff,0xabd3, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xa5c9,0xf9df, + 0xffff,0xffff,0xe9d3,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xbcd7,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xbfe0, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xeab1,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xc7c7,0xf9cf, + 0xb4d6,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xb5ec,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xefb0,0xb4b8, + 0xffff,0xcdb3,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xb4ed,0xffff,0xc1ec, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xc2db,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xb1ce,0xffff,0xffff,0xc0c2,0xa5b5,0xffff, + 0xffff,0xd3b0,0xffff,0xffff,0xffff,0xffff,0xfce0,0xffff, + 0xffff,0xffff,0xffff,0xc5b3,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xb7e9,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xfddc,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xe6d9, + 0xffff,0xffff,0xffff,0xffff,0xebcc,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xd3c4,0xffff,0xcaea,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xb5b9,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xf9d8,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xc1c0,0xd1de,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xe0ca,0xffff,0xa7eb,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xb4d3,0xffff, + 0xffff,0xb3d7,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xb3bb,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xa3d3,0xffff,0xa4e4,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xbddf, + 0xffff,0xffff,0xffff,0xffff,0xc5c2,0xffff,0xffff,0xffff, + 0xffff,0xfcd0,0xffff,0xffff,0xffff,0xbcea,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xabe4,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xafb6,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xe3b2,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xedc4,0xffff,0xffff,0xffff,0xffff, + 0xf9d1,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xe1b2,0xffff,0xffff,0xffff,0xffff, + 0xe1bc,0xffff,0xffff,0xcde6,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xe3e2,0xffff,0xffff,0xffff,0xfecf,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xf1ce,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xf0e5,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xedb5,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xc9b8,0xffff, + 0xffff,0xe5be,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xb1d5,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xabd1,0xffff,0xffff,0xffff, + 0xd1db,0xffff,0xffff,0xffff,0xffff,0xffff,0xb8bc,0xffff, + 0xffff,0xffff,0xffff,0xd8de,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xf8ba,0xffff,0xffff,0xffff,0xffff,0xffff,0xb9b3, + 0xffff,0xe5c9,0xffff,0xffff,0xb6d5,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xc2ce,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xa4ca,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xf4ca,0xffff,0xffff,0xffff, + 0xffff,0xb5c1,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xbfb6,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xcdc0,0xffff,0xffff,0xf6d6, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xb8c0,0xaaeb,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xd9ca,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xaeb0,0xffff,0xffff,0xa7b5,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xdcbd,0xffff,0xffff,0xffff,0xbac7,0xffff, + 0xffff,0xffff,0xffff,0xc8e6,0xffff,0xffff,0xffff,0xffff, + 0xabe3,0xffff,0xffff,0xa6b2,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xfee3,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xc6ca,0xffff,0xc4d8,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xdce3,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xfece,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xf1db,0xffff,0xffff,0xd6e6,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xb0ed,0xa8c9,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xd5c2,0xffff,0xcfb6,0xffff,0xffff,0xffff, + 0xffff,0xa8c8,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xf7d8,0xffff,0xffff,0xffff,0xf0c2,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xa7b8,0xffff,0xd3ea,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xc7d7,0xffff,0xc8c8, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xf3ba,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xb4c3, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xd0e1,0xffff,0xffff, + 0xa8ed,0xa7ea,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xf8c6,0xffff,0xffff,0xa8c5,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xa1c9,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xd3c6,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xb6e3,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xb8b1,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xa6c2,0xffff,0xffff,0xb8d5,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xcbc6,0xffff,0xffff,0xffff,0xffff, + 0xf7ca,0xffff,0xe2c7,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xf6db,0xffff,0xffff,0xc9e6,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xecde,0xffff,0xffff,0xffff,0xffff, + 0xebe8,0xa1e9,0xb2eb,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xb8df, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xd7b2,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xe0db,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xddc3,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xabe1,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xf5bf,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xf0c3,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xd8ce,0xd1b4, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xefe8,0xb5eb,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xa2cc,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xaace,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xf9e6,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xbddb,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xa8ea,0xf5d5,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xa4d3,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xcece,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xcadb,0xffff,0xffff,0xffff,0xffff,0xe3b3, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xe2bf,0xffff, + 0xffff,0xafea,0xd2b9,0xf1bc,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xade9,0xffff,0xffff,0xd3b5,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xe3e4,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xb5ed,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xb4c0,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xebe2,0xffff,0xffff,0xb5d3,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xe2f0,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xf8c0,0xffff,0xefdf,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xeed1, + 0xffff,0xffff,0xffff,0xffff,0xfedc,0xffff,0xffff,0xc7ec, + 0xb4d7,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xb0c2,0xffff,0xffff,0xffff,0xffff, + 0xe3e8,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xd9e0,0xffff, + 0xffff,0xd6ec,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xf4c9,0xffff,0xffff,0xffff,0xffff, + 0xfde2,0xbdd5,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xc0e3,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xb0c8,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xf1d4,0xffff,0xb9c9,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xaaca,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xf2b5,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xb6d3,0xffff,0xc8d4,0xffff,0xffff,0xffff, + 0xa2d2,0xbbb9,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xb7cf,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xc5c7,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xc1b3,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xa8b1,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xccd9,0xbbbe,0xffff,0xffff,0xd9df,0xffff, + 0xffff,0xcec3,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xa7bb,0xffff,0xf7bb,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xf9e8,0xffff,0xffff,0xffff,0xa2c5,0xffff,0xc6b5, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xb2b5,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xdace,0xc0ec, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xd8c2,0xffff,0xb3b6,0xffff,0xffff,0xffff,0xffff, + 0xa1b3,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xb9c1,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xabb4,0xffff,0xffff,0xffff,0xffff,0xf0e0, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xc0e1,0xffff,0xffff, + 0xe9e2,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xe3b7, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xf1d8,0xffff,0xffff,0xffff,0xffff,0xfab9, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xe9ca,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xc5d7,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xaed5,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xd4b8,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xe8b9,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xa7ce, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xdeb2,0xffff, + 0xffff,0xffff,0xffff,0xa3b5,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xc3bc,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xcbc9,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xe1cf,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xa6bb,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xe8e0,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xc7be,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xcecc,0xffff,0xd5c9, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xceec,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xbde1,0xffff,0xffff, + 0xffff,0xffff,0xf0bc,0xddbe,0xffff,0xe1bb,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xcdd6,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xfcb5,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, +}; diff --git a/lib_acl/src/code/gb_jt2ft.h b/lib_acl/src/code/gb_jt2ft.h new file mode 100644 index 000000000..9877bcabc --- /dev/null +++ b/lib_acl/src/code/gb_jt2ft.h @@ -0,0 +1,8194 @@ +static const unsigned short __jt2ft_tab[] = { + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xf688,0x41b5,0xffff,0xffff,0x45d9, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x4db1,0xffff, + 0x81f0,0xffff,0xffff,0x99d6,0xffff,0x5194,0xffff,0xffff, + 0xffff,0xe382,0xffff,0xffff,0x48ab,0xffff,0xffff,0xffff, + 0xffff,0x78df,0x7593,0xffff,0xffff,0x8ee5,0xac8e,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0x6eca,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x8bbc, + 0xffff,0xe599,0x7add,0xffff,0xffff,0xbb91,0xffff,0x7ce6, + 0xffff,0xffff,0x52ee,0xffff,0xffff,0xffff,0xffff,0x97f6, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0x4b81,0x4c87,0xa683,0xffff,0xffff,0x6cb0, + 0xffff,0xffff,0xffff,0xffff,0x87f0,0x9ec5,0xc584,0xffff, + 0xffff,0xffff,0xc589,0xffff,0xffff,0xf49d,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xe993,0xffff,0xffff,0xffff, + 0xffff,0x5fb0,0xf288,0xffff,0xffff,0x6ce9,0x59b0,0x5dd4, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x5894, + 0xffff,0xffff,0xffff,0xc190,0xffff,0xffff,0xffff,0x84bc, + 0xffff,0xffff,0x77dd,0xffff,0xffff,0xffff,0xffff,0x93e3, + 0xffff,0xffff,0x4dee,0xffff,0xffff,0xffff,0xffff,0x92f6, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xfa93,0xffff,0x50c1, + 0xffff,0xffff,0xffff,0xffff,0x45db,0xa684,0x47c7,0xffff, + 0xa29d,0xffff,0x6e94,0xffff,0xffff,0xffff,0xffff,0xbfa0, + 0x78fd,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0x62df,0xd199,0xffff,0xffff,0x8de0,0xffff, + 0xffff,0xffff,0xffff,0x50e0,0xffff,0x7ccb,0xffff,0x5d94, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xadb5,0x828b,0x82bc, + 0xffff,0xffff,0x8fdd,0xffff,0x659a,0xffff,0xffff,0x50e5, + 0x77b7,0xffff,0x7d9d,0xffff,0xffff,0xffff,0x7ad3,0x8df6, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0x4ce9,0xffff,0xffff,0x94e1,0xffff, + 0xffff,0xffff,0xffff,0x6fd7,0xffff,0x54f0,0xffff,0xffff, + 0xffff,0x729e,0x5deb,0xffff,0xffff,0xffff,0xffff,0x4c92, + 0xffff,0xffff,0xd984,0xffff,0xffff,0xffff,0x66ed,0xffff, + 0xffff,0x6bbd,0x47b8,0xeb8b,0x41ee,0xc596,0x43d7,0x76f1, + 0xffff,0xffff,0xffff,0xffff,0xffff,0x7bca,0xffff,0xffff, + 0xffff,0xffff,0x4dab,0xffff,0xd19b,0xffff,0xffff,0x43bd, + 0xffff,0xa198,0x41de,0xffff,0xffff,0xffff,0xffff,0x43e4, + 0xffff,0xffff,0x57ee,0xffff,0xffff,0xffff,0xffff,0x8af6, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0x96ef,0xffff,0x9483,0x7cd3,0xce86,0x94ed,0xffff, + 0xffff,0xffff,0xffff,0xffff,0x49d7,0x759d,0x6fc7,0x45f2, + 0xffff,0x60eb,0xc798,0xffff,0xffff,0x6fe2,0xffff,0x46e2, + 0xffff,0xca86,0x7dc2,0xffff,0xffff,0xffff,0x60df,0xffff, + 0x5b87,0xffff,0x7bd6,0x97fa,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0x85d3,0xffff,0xffff,0x70c9,0xffff,0x7894, + 0xffff,0x4cd2,0xffff,0x6191,0x9d9c,0xffff,0xffff,0x9cbc, + 0xffff,0xffff,0x4fde,0xffff,0xffff,0xffff,0xffff,0x7ce3, + 0xffff,0xffff,0x68ee,0xffff,0x5bbb,0xffff,0xffff,0x8ef6, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0x9a8c,0xdc93,0x63c4,0x8ecc,0x90e0,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xfb9c,0x75eb,0x529e,0xffff,0xffff, + 0xffff,0xffff,0xe48a,0xffff,0xffff,0x7ebc,0xffff,0x55e3, + 0xffff,0xffff,0x9f8e,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xaa91,0x53f1,0xffff,0xffff,0xffff, + 0xffff,0xffff,0x93d3,0x94e0,0xffff,0x87c8,0xffff,0x7b93, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x9bbc, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x7ce7, + 0xffff,0xffff,0x80ee,0xffff,0xffff,0x89e1,0x6eec,0x98f6, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0x8fc0,0x538f,0xffff,0xdb93,0x56e5,0x79e9, + 0xe193,0xffff,0x94f1,0xf491,0xffff,0xbe9d,0xffff,0xffff, + 0xffff,0xffff,0xa793,0xffff,0xffff,0x93c4,0xffff,0xffff, + 0x45ef,0x7df2,0xffff,0x9b8e,0x4594,0xffff,0xfa87,0xffff, + 0xffff,0x578c,0xffff,0x74c0,0x78f8,0xffff,0xffff,0xffff, + 0xffff,0xffff,0x8fd3,0x53e0,0xffff,0x92c8,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x55bf, + 0xffff,0xffff,0xe291,0xd09a,0xffff,0xffff,0xffff,0x40e4, + 0xffff,0xffff,0x85ee,0xffff,0xffff,0x87e1,0xffff,0x42f7, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0x7db0,0xf388,0xffff,0xffff,0xffff,0x91c4,0xffff,0xffff, + 0x6fdd,0x8ffd,0xffff,0xffff,0x83bf,0xffff,0x4cf6,0xffff, + 0xffff,0xffff,0x74ba,0x88d8,0xffff,0xe29d,0xffff,0x77df, + 0xe099,0xdf92,0x7baa,0xffff,0x5fc5,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0x93ac,0x599c,0xffff,0xffff,0xa38c, + 0x8381,0xffff,0x98d3,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0x4aab,0xffff,0xffff,0xffff,0xffff,0x45bd, + 0x61ad,0xffff,0xea91,0xffff,0xffff,0xe290,0xffff,0x9ce3, + 0xffff,0x60b0,0x44ef,0xffff,0xffff,0xffff,0x5aec,0x4cf7, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xb395,0xffff,0xffff,0x86d3,0x6dac, + 0xffff,0xffff,0xffff,0x5787,0x83be,0xffff,0xffff,0xffff, + 0x5594,0x7a82,0xffff,0xffff,0xffff,0x72de,0xffff,0x9eba, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0x8ecb,0x9ece,0xffff,0x70d4,0xffff,0x75b4, + 0xffff,0xffff,0x8ed6,0x69e0,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x998a,0x49bd, + 0xffff,0xffff,0xffff,0xffff,0x52ef,0xffff,0xffff,0x84e7, + 0xffff,0xffff,0x94ee,0xffff,0xffff,0xffff,0xffff,0xa0f6, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0x40cc,0xffff,0xffff,0xffff,0xffff,0xffff,0x4781,0xffff, + 0xffff,0xffff,0xffff,0x41c8,0xffff,0xffff,0x40f3,0x5fe9, + 0xffff,0x93c2,0xffff,0x5ee5,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xf19d,0xffff,0xffff,0xffff,0xe99e,0xffff, + 0xffff,0xffff,0xffff,0x49a0,0xffff,0xffff,0xffff,0x44de, + 0xffff,0xffff,0x6ed4,0x42e1,0xffff,0x50c9,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x48bd, + 0xffff,0xffff,0xffff,0xda9a,0x53ef,0xa19c,0xffff,0x6ee5, + 0xffff,0xffff,0x8bee,0xffff,0xffff,0xffff,0xffff,0x9af6, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0x55f5,0xffff,0xffff,0xf782,0xffff,0x7c96,0xffff, + 0xffff,0xffff,0x6eed,0xffff,0x4f98,0xa28c,0xffff,0xffff, + 0x9fe9,0x8fc9,0x4acc,0xffff,0xffff,0xffff,0xffff,0x74d6, + 0xffff,0xffff,0x8ad4,0x70eb,0xffff,0xffff,0x489e,0xffff, + 0x90cf,0xd784,0xffff,0xc99f,0xffff,0x53fd,0xffff,0xffff, + 0xffff,0xffff,0x47d4,0xffff,0xffff,0x6ec8,0xffff,0xffff, + 0xffff,0xe78d,0xffff,0xdc90,0xd29d,0xffff,0x498b,0x66bd, + 0xffff,0xffff,0xffff,0xffff,0x5aef,0xffff,0xffff,0x88e4, + 0xffff,0x61b0,0x97ee,0xffff,0xffff,0xffff,0x56ec,0x49f7, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0x4be3,0xffff,0xffff,0x8491,0xffff,0xffff, + 0xffff,0x6d8c,0xffff,0xffff,0xffff,0x7b9d,0xffff,0xffff, + 0xffff,0x42df,0x52b1,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xad9d,0xc68c,0xffff,0x4291,0xffff,0x53be,0xffff, + 0xffff,0xffff,0xffff,0x89cf,0xffff,0xffff,0xffff,0x8dd9, + 0xffff,0xffff,0x62d4,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xc68b,0x57bd, + 0x8bad,0xffff,0xffff,0xffff,0x60ef,0xffff,0xffff,0x48e7, + 0xffff,0xffff,0x9eee,0xffff,0xffff,0xffff,0xffff,0x5af7, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0x4bb5,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0x8bae,0x8bdd,0xffff,0x9bbd,0x5084, + 0xffff,0xa0e7,0x42ef,0x54e3,0xffff,0xffff,0x5ff2,0xffff, + 0xffff,0xffff,0xffff,0x6cd5,0xffff,0x7ee3,0x94c8,0xffff, + 0x6685,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0x8a83,0x58d4,0xffff,0xffff,0xffff,0x49cc,0xffff, + 0xffff,0x738d,0xffff,0xffff,0xffff,0xffff,0xffff,0x7bbd, + 0xffff,0xec99,0xffff,0xffff,0x6aef,0xffff,0xffff,0x7be4, + 0xffff,0xffff,0x41ef,0xffff,0xffff,0xffff,0xffff,0x58f7, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xdb90,0xffff,0xffff,0x6ee2,0xffff,0x51d5,0xffff,0xffff, + 0xffff,0x96ec,0xffff,0x9d84,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0x5d8f,0xffff,0xffff,0xffff,0x68ef,0x58e5, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x75d2, + 0xb692,0xffff,0xffff,0x41da,0xffff,0xf982,0xffff,0xb698, + 0xffff,0xffff,0x67d4,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0x538e,0xffff,0xffff,0xffff,0xffff,0x448c,0x8ebd, + 0xffff,0xffff,0xffff,0xffff,0x6cef,0xffff,0xffff,0x87e4, + 0xffff,0x5db0,0xffff,0xffff,0xffff,0xffff,0xffff,0x56f7, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0x8faf,0x978f,0xd384,0x5cb5, + 0xffff,0xffff,0xffff,0xffff,0xffff,0x59ca,0xffff,0xffff, + 0x9ecf,0x7a91,0x74a0,0xffff,0xffff,0xffff,0xffff,0x51e3, + 0xffff,0xffff,0xffff,0xffff,0x8294,0xffff,0xffff,0xffff, + 0x7994,0x83d4,0x94a0,0xffff,0x40de,0xffff,0x97bf,0x66c7, + 0xffff,0x7a83,0x74d4,0xffff,0xffff,0x89c9,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0x679e,0xffff,0xffff,0x8bbd, + 0xffff,0xffff,0xec91,0xffff,0xffff,0xbf91,0xffff,0x86e4, + 0x46f8,0xffff,0xffff,0xffff,0x9cc5,0xffff,0xffff,0x6bf7, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x9d97,0x43e2, + 0xffff,0xffff,0xffff,0x92d4,0xffff,0xaa98,0xffff,0xffff, + 0x44c5,0x699d,0xef93,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xf184,0xffff,0xffff,0x90b6,0x9dd8,0xffff,0xa582,0x95c1, + 0xffff,0xa48c,0xffff,0xffff,0x4088,0xffff,0x9ac2,0x62d1, + 0xffff,0xffff,0x78d4,0xffff,0xffff,0x57c9,0xffff,0xffff, + 0xffff,0xb98d,0xffff,0xffff,0x479d,0xae9e,0xffff,0x90bd, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xdf91,0xffff,0x7ee4, + 0x53f8,0xffff,0xffff,0xffff,0xffff,0xffff,0x5cec,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0x94ae,0xffff,0xffff, + 0xffff,0x95d8,0xffff,0xffff,0xffff,0x84aa,0x69ee,0xffff, + 0xffff,0x9fba,0x75fb,0xffff,0x5cd6,0x91af,0xffff,0x939d, + 0xffff,0xa29a,0x7295,0xffff,0x63b0,0xffff,0xce82,0xffff, + 0xffff,0x5af1,0xffff,0x66b7,0x5486,0xd69a,0xffff,0x798a, + 0xffff,0x8983,0x72d4,0xffff,0xffff,0xffff,0xffff,0x738f, + 0xffff,0xffff,0xffff,0xffff,0xa19d,0xffff,0xffff,0x63be, + 0xffff,0xffff,0x54ae,0xffff,0x9edd,0xffff,0xffff,0x53e4, + 0x64f8,0xffff,0x6ccf,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0x85dd,0xffff,0xffff,0xffff,0xf593,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0x76d6,0x6fec,0xffff, + 0xffff,0xbf94,0x94cc,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0x7884,0xffff,0xffff,0xa99e,0xffff,0xffff,0xffff, + 0x7bc3,0xffff,0xffff,0xffff,0x4188,0xffff,0xffff,0xffff, + 0xffff,0xb083,0x45d5,0xffff,0xffff,0x57cb,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x5fbe, + 0xffff,0xffff,0xffff,0xe59a,0xffff,0xffff,0xffff,0x73e4, + 0x63f8,0x64b0,0x8acf,0xffff,0xffff,0xffff,0xffff,0x5eed, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0x4aea,0x68fc,0xf683,0xa99f, + 0x78d9,0x5ee3,0xffff,0xd191,0xffff,0xffff,0xffff,0xffff, + 0x52c8,0x98c4,0x94f4,0x51d9,0xffff,0xffff,0xffff,0x5c9c, + 0xffff,0xffff,0xffff,0x98ed,0xaf89,0x79bd,0x95be,0x8ae3, + 0x43d6,0xffff,0x93ed,0xffff,0xffff,0xffff,0xffff,0xd189, + 0xffff,0xab83,0x43d5,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0x4391,0xffff,0xffff,0xffff,0x70be, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x8de4, + 0x81f8,0x9fc4,0xffff,0xffff,0xffff,0xffff,0x5afd,0x58ed, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0x90d8,0xffff,0xffff,0x9384,0x8eca,0xffff,0xffff, + 0xcd8f,0xffff,0xffff,0xffff,0xffff,0x75e1,0xffff,0xffff, + 0xed81,0x9ce6,0xffff,0xe1f7,0xffff,0xffff,0xffff,0x6cd7, + 0x7385,0x86bc,0x67ce,0xffff,0xffff,0xffff,0xffff,0xffff, + 0x918c,0xffff,0xffff,0xd186,0xffff,0xffff,0xcc88,0xeea0, + 0xffff,0xffff,0x9fd4,0xffff,0xffff,0xffff,0x92cb,0x5c87, + 0xffff,0x968d,0xffff,0x7c91,0xffff,0xffff,0x7a8b,0x79be, + 0xffff,0xc299,0xffff,0xffff,0x57fd,0xcd9d,0x8cae,0x98e7, + 0x85f9,0xffff,0xffff,0xffff,0xffff,0xffff,0x65fd,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0x5ee4,0x67f1,0x87dc,0xffff,0x6e99,0xffff,0xffff, + 0xffff,0xcf9c,0xffff,0xc489,0xffff,0xffff,0x52e7,0xffff, + 0x87d9,0xd991,0xffff,0xffff,0xffff,0x5ad6,0x6cee,0x7189, + 0x6ff9,0xffff,0x8d8c,0x66d5,0xffff,0xffff,0xffff,0xffff, + 0xffff,0x96d3,0x4998,0xed93,0x89be,0x4bb1,0xffff,0xffff, + 0xffff,0xffff,0x91d4,0xffff,0xffff,0x7eca,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0x5a9c,0xffff,0xb98b,0x69be, + 0xffff,0xb099,0xffff,0xe89a,0xcc94,0xecc3,0xffff,0x99e7, + 0x52fb,0xffff,0xffff,0xffff,0x41c6,0xffff,0x5ffd,0x64ed, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xa0b9, + 0xffff,0x88c6,0xffff,0x679a,0x89bc,0xffff,0xbd8f,0xffff, + 0x7bcb,0x929f,0xffff,0xffff,0x80ae,0xffff,0x9ad8,0xffff, + 0xffff,0xffff,0x52d7,0x54b4,0xffff,0xffff,0xffff,0xffff, + 0xffff,0x8dd3,0x7ec8,0xf282,0x68df,0xd894,0xffff,0x46e5, + 0xffff,0x5282,0x9cd4,0xffff,0xffff,0xffff,0xffff,0xffff, + 0x4487,0xffff,0xffff,0xe3c0,0xac9d,0xffff,0xffff,0x45be, + 0x91ad,0xffff,0xffff,0xffff,0xffff,0x89b4,0xffff,0x5ae4, + 0x7af8,0xffff,0xffff,0xffff,0xffff,0xffff,0x66fd,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0x4eaa,0x4eca,0xffff,0xffff,0x7693,0x59f4,0x9cd8, + 0xffff,0xffff,0xffff,0x68ad,0x4494,0xffff,0x64af,0xffff, + 0xffff,0x9abe,0xffff,0xffff,0xffff,0x579a,0xffff,0xffff, + 0x5fb4,0xffff,0xffff,0xffff,0x54d7,0x5eee,0xffff,0xf291, + 0xffff,0x64df,0xffff,0xffff,0xffff,0x9add,0xffff,0xffff, + 0xffff,0xffff,0x96d4,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xbf87,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x52be, + 0xffff,0xce99,0xffff,0xffff,0xffff,0xffff,0xffff,0x75e4, + 0x7cf8,0xffff,0xffff,0xffff,0xffff,0xffff,0x62fd,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xe482,0xffff,0xffff,0x4ee5,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xd78e,0xffff,0xffff,0xffff, + 0xda99,0x5abc,0x54d9,0xffff,0xffff,0x74fa,0xffff,0xffff, + 0xffff,0x59ba,0xffff,0x71a0,0x84d5,0xffff,0xffff,0x9abc, + 0xffff,0xffff,0xffff,0x62b0,0x8aee,0xe48d,0xffff,0x98d9, + 0xffff,0xffff,0x8dd4,0xffff,0xffff,0xffff,0xffff,0xe5df, + 0xffff,0xffff,0xffff,0xffff,0xffff,0x8e8c,0xffff,0x5ebe, + 0x74ed,0xffff,0xffff,0xffff,0xffff,0x58b4,0xffff,0x7ce4, + 0x83fa,0xffff,0xffff,0xffff,0xffff,0xffff,0x6cfd,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0x61f3,0x7691,0x61d1,0xd88f,0xffff,0xffff,0xffff,0x88ef, + 0xffff,0x8b98,0xffff,0x80df,0xffff,0xffff,0xffff,0xffff, + 0x7294,0xf69b,0xffff,0x71fc,0xffff,0xaa9a,0xffff,0x8c98, + 0xffff,0xf195,0xffff,0xffff,0xffff,0xffff,0x6af0,0xffff, + 0xffff,0xba89,0xffff,0xffff,0xffff,0xffff,0xffff,0x8b89, + 0xffff,0xffff,0x8fd4,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0x71f2,0xffff,0x4abe, + 0x79ed,0xffff,0xffff,0xa9a0,0xffff,0xffff,0xffff,0x48e5, + 0x8df8,0xffff,0x98cd,0xffff,0xffff,0xffff,0x72fd,0x78ed, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0x758d,0xffff,0xffff, + 0x93d8,0x8fd9,0x689d,0x8fbe,0xffff,0x7ac4,0x82b8,0xffff, + 0x40bb,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xdc86, + 0xffff,0xffff,0xffff,0xffff,0xffff,0x64b6,0xffff,0x72ce, + 0x619e,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x59be, + 0x47b2,0xffff,0x8ad5,0xffff,0xffff,0x4cfa,0x5ccc,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x55be, + 0x77ed,0xffff,0xffff,0xffff,0xffff,0x8cb3,0xffff,0x9de4, + 0x76fa,0xffff,0x96cf,0xffff,0xffff,0x7afb,0x70fd,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0x5cb6,0xffff,0xffff, + 0xffff,0xf289,0xffff,0x5193,0x45cb,0xffff,0xf483,0xffff, + 0x40ea,0xffff,0x93b5,0x5d9b,0xffff,0x4987,0x4fcc,0xffff, + 0xffff,0xffff,0x82f1,0xffff,0xffff,0xffff,0xffff,0xffff, + 0x78d6,0x66f8,0xffff,0x78db,0xffff,0xa397,0xffff,0x81d5, + 0xffff,0xffff,0x9fd5,0x63c6,0xffff,0x4fc9,0xc2e9,0xffff, + 0xffff,0x468e,0xffff,0xffff,0xffff,0xffff,0xffff,0x6cbe, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x9fe5, + 0x8ef8,0xffff,0xffff,0xffff,0xffff,0x4fdc,0x7dfd,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xa78c,0xffff,0xffff, + 0x87d3,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0x6dcc,0xffff,0x9be4,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0x4488,0xffff,0xffff, + 0xffff,0x86f8,0xffff,0xffff,0x73bc,0xffff,0xffff,0xca9c, + 0xffff,0xffff,0x82d4,0x4a8a,0x47cb,0xffff,0xffff,0x6087, + 0xffff,0xffff,0x68f0,0xffff,0xffff,0xffff,0xffff,0x7ebe, + 0xffff,0xffff,0xd295,0xffff,0xffff,0xffff,0x60c1,0x51e5, + 0xa0f8,0x5db8,0xffff,0xffff,0xffff,0xffff,0x77fc,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xbe86,0xffff,0xb29d,0xffff,0xffff, + 0x919e,0xc983,0x91ea,0xffff,0xffff,0x619d,0xffff,0xa689, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x5ed6,0xa0dd, + 0xffff,0xffff,0x74e1,0x81d4,0xffff,0xf091,0x88bc,0xffff, + 0xffff,0xffff,0x56d5,0xea84,0xffff,0xffff,0xffff,0xd287, + 0xffff,0xfe8d,0x82ef,0xffff,0xffff,0xffff,0xffff,0x7cbe, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x75e5, + 0x5bfb,0xffff,0xffff,0xffff,0xffff,0xffff,0x78fc,0x58fa, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0x6d89,0xffff,0xffff,0xffff,0xffff, + 0x448b,0xffff,0xffff,0x88af,0xffff,0x9cf2,0xffff,0xffff, + 0x8ed7,0x76dd,0xffff,0x56e6,0xffff,0xffff,0x7b91,0x4ecb, + 0xffff,0x6884,0xffff,0xffff,0x4087,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0x53dc,0xffff,0x49d5,0xffff, + 0xffff,0xffff,0x61d5,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0x71f0,0xffff,0xffff,0xffff,0xffff,0x9fbe, + 0xffff,0xffff,0xffff,0xffff,0xac9f,0xffff,0xffff,0x98e4, + 0x50f9,0xffff,0xffff,0xffff,0xffff,0xffff,0x83fc,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0x4fc2,0xffff,0xffff,0xffff,0x83bc,0xffff,0xd9a0,0xffff, + 0x60bf,0xffff,0xffff,0xffff,0xffff,0xc98b,0xffff,0xffff, + 0x8894,0xffff,0x48f3,0xffff,0xffff,0xffff,0xffff,0x8a8f, + 0xffff,0xffff,0xffff,0x7abd,0xffff,0x5489,0xffff,0x7b8d, + 0x5ce4,0xffff,0x9ee3,0xa59c,0x80e8,0xffff,0xb493,0xffff, + 0xffff,0xffff,0x4ed5,0xffff,0x7cca,0xffff,0xffff,0xb387, + 0xcb87,0x988d,0x83ef,0xffff,0xffff,0xffff,0xc88b,0x98be, + 0x7198,0xffff,0xffff,0xffff,0x989f,0x5eb4,0x62c1,0x4be5, + 0x5afb,0xffff,0xffff,0x9bc0,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0x5cd2,0xffff,0xffff,0xffff,0xffff,0xffff,0x9aaa,0xffff, + 0xffff,0xffff,0xffff,0xa89f,0xffff,0xffff,0x6dbc,0xffff, + 0x5bd3,0xffff,0xce85,0xffff,0xffff,0xffff,0x75d4,0x8c93, + 0xffff,0xffff,0xffff,0xffff,0xab9c,0xffff,0x6cd0,0x6282, + 0xffff,0xffff,0xffff,0xffff,0x5b8e,0x60be,0x5394,0xffff, + 0xffff,0xffff,0x4fd5,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xf78d,0x84ef,0xf0e2,0xffff,0xffff,0xffff,0x44c0, + 0xc099,0x5299,0xffff,0xffff,0xf59f,0xffff,0xffff,0x64e5, + 0x5df9,0x4db8,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0x87bf,0xffff,0xf2c9,0xffff,0x49b1,0x78d7,0xffff, + 0xffff,0xffff,0xffff,0x6f9c,0xa984,0x8794,0xffff,0xffff, + 0xd091,0xffff,0x58e4,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0x57e9,0xffff,0xffff,0xffff,0xffff,0xffff,0x4daa, + 0xffff,0xffff,0xffff,0xffff,0x9bbb,0xffff,0xffff,0xffff, + 0xffff,0xffff,0x8cd5,0xffff,0xffff,0xffff,0x59cc,0xffff, + 0xffff,0x888d,0x86ef,0xac91,0xffff,0xffff,0x8b8b,0x8cbe, + 0xffff,0xffff,0xffff,0xffff,0xcd9f,0xffff,0xffff,0x78e5, + 0x4ff9,0xffff,0xffff,0xffff,0x55d1,0xffff,0x68eb,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0x578a,0xffff,0xffff,0x90ea,0x62be,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0x71e3,0xffff,0xffff, + 0x7cc0,0x8fd5,0x4882,0xffff,0xffff,0xffff,0xffff,0x40e6, + 0xffff,0x83ea,0xffff,0xffff,0xffff,0xffff,0xd89c,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0x64c1,0xffff,0x8ed5,0xcdc3,0x9ecb,0xffff,0xffff,0x6886, + 0xffff,0xffff,0x8def,0xffff,0x5e9e,0xffff,0xffff,0x9cbe, + 0xffff,0xffff,0xffff,0xffff,0xffff,0x5ab5,0xffff,0x9ee4, + 0x92fa,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x4cd4, + 0x93d4,0xffff,0xffff,0xffff,0xfa9d,0x43b3,0xffff,0xffff, + 0x80a0,0xffff,0xffff,0xffff,0xffff,0xffff,0x8a9d,0xffff, + 0x8cd7,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x428f, + 0xffff,0xffff,0x55ee,0xffff,0x8290,0xffff,0xffff,0xffff, + 0xffff,0xffff,0x86d5,0xffff,0xffff,0xffff,0xffff,0x4a86, + 0xffff,0xffff,0x41f0,0xffff,0xffff,0xffff,0xffff,0x97be, + 0xffff,0xffff,0xffff,0xffff,0xffff,0x61b5,0xffff,0x9fe4, + 0x59f9,0xffff,0xa0cf,0xffff,0xffff,0xffff,0xffff,0x74f3, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0x72d2,0xffff,0xffff,0x80d9,0x8fbc, + 0xffff,0xffff,0xffff,0xffff,0xffff,0x6583,0xffff,0xffff, + 0x459e,0xffff,0xffff,0xffff,0xffff,0xffff,0x48ee,0xffff, + 0x88f0,0xa0d9,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0x86e9,0xffff,0xc38e,0xffff, + 0xdd86,0xffff,0x98d5,0xffff,0xffff,0xffff,0xffff,0x7786, + 0xffff,0xffff,0x47f0,0xffff,0xffff,0xffff,0xffff,0x50bf, + 0xffff,0x8999,0xffff,0xffff,0xffff,0xffff,0xffff,0x55e5, + 0x5ef9,0xffff,0xffff,0xffff,0xffff,0x84db,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xce93,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0x96cc,0xffff,0xffff,0x5fc4,0xffff,0x77ee, + 0x98ac,0xffff,0xd28c,0x54e9,0xc885,0xffff,0xffff,0xf298, + 0x5f94,0xffff,0xffff,0xffff,0xffff,0x4688,0x84c2,0x9887, + 0xffff,0xffff,0x7adf,0x9e83,0xffff,0x888f,0xffff,0xf8d6, + 0xffff,0xffff,0x94d5,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0x4ef0,0x56e9,0xc69d,0xffff,0xffff,0x87be, + 0x6797,0xffff,0xffff,0xffff,0xffff,0xffff,0x8fe1,0x4fe5, + 0x91f9,0xffff,0xffff,0xffff,0xffff,0xffff,0x87d7,0x79f3, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0x94d8,0x51b7,0xffff,0xf49f,0x83e5,0xffff, + 0x7de2,0x4dd0,0xffff,0x53fc,0x8bd3,0xffff,0xffff,0xffff, + 0xffff,0x9faf,0x7cbf,0x9e90,0x63e2,0xffff,0xffff,0xffff, + 0x40c0,0xffff,0xdd84,0xffff,0xffff,0xffff,0x79bc,0xffff, + 0x85e1,0xa186,0xffff,0xffff,0x85eb,0xffff,0xffff,0xffff, + 0xffff,0xffff,0x7ed5,0xffff,0xffff,0xffff,0x598a,0xffff, + 0xffff,0xffff,0x51f0,0x5ae9,0xffff,0xffff,0xffff,0x4ebf, + 0xffff,0xbd99,0xffff,0xffff,0xffff,0xffff,0x90e1,0x9be5, + 0x67f9,0xffff,0xffff,0x56ba,0xffff,0xffff,0xffff,0x78f3, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0x6fde,0xffff,0xffff,0xffff, + 0x77c9,0xffff,0xffff,0xffff,0x9bd3,0xffff,0xfd8e,0xa49a, + 0xffff,0xffff,0x5d91,0x8382,0xffff,0xffff,0xffff,0xcc86, + 0xffff,0xffff,0xffff,0x95ef,0xffff,0x6aee,0xffff,0x76e5, + 0xffff,0x8681,0x7883,0x6e91,0x79e0,0x719d,0xffff,0xe19d, + 0x8785,0x6683,0x72d5,0xffff,0xffff,0xffff,0xffff,0x5586, + 0xffff,0xffff,0x6cf0,0x9de9,0xffff,0x83df,0xffff,0x62bf, + 0x9697,0xffff,0xffff,0xffff,0xee9f,0xffff,0x95e1,0x7ce5, + 0x6cf9,0xffff,0xffff,0xffff,0x75c1,0xffff,0x8ee8,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0x9cef,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x5383, + 0xe19f,0xffff,0xffff,0xffff,0xffff,0xffff,0x80b7,0xffff, + 0xffff,0xa0d3,0xffff,0xffff,0xf284,0xffff,0xffff,0x9dc6, + 0xffff,0xffff,0x52d6,0xffff,0x7bc7,0xffff,0xffff,0xffff, + 0x8687,0xffff,0x74f0,0x62e9,0xffff,0xffff,0xdc8b,0x64bf, + 0xba98,0xffff,0xffff,0xffff,0xffff,0xffff,0x93e1,0x4ae6, + 0x87f9,0xffff,0xffff,0x61b9,0xffff,0x56dc,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x77ef, + 0xd68e,0xffff,0xffff,0xffff,0xffff,0x55c0,0x66c5,0xffff, + 0xffff,0x7cdf,0xffff,0xffff,0x7bbc,0xffff,0xffff,0xffff, + 0xffff,0x98bf,0xffff,0xffff,0xffff,0x91cd,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0x45eb,0xffff,0xffff,0xffff, + 0x9885,0xffff,0x47d6,0xffff,0x4fc8,0xffff,0xffff,0xffff, + 0xffff,0x568e,0x78f0,0x68e9,0x639e,0x9fde,0xe58b,0x63bf, + 0x6e97,0x7b99,0xffff,0x64c4,0xffff,0xffff,0x91e1,0x8ae5, + 0x96f9,0x64d2,0x7ccf,0xffff,0xffff,0xffff,0x59e7,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0x50b9,0xffff,0xffff,0x7ed4,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0x48eb,0x67bd,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0x8489,0x6ddf,0x96c2,0xffff,0xffff,0x9686,0x72f5, + 0xffff,0xffff,0xffff,0x5de0,0xffff,0xa48e,0x7cd9,0x59d9, + 0xffff,0xffff,0x6fd6,0xeb9a,0x90c9,0xffff,0xffff,0xffff, + 0xffff,0xffff,0x7df0,0x60e9,0xffff,0xffff,0xffff,0x72bf, + 0xffff,0xffff,0xcf95,0x5696,0xffff,0xffff,0x51e2,0x9ae5, + 0x98f9,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x7cf4, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0x87e0,0xffff,0xffff, + 0x5597,0x99ee,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0x569e,0xffff,0xffff,0xffff,0xe493,0xffff, + 0xffff,0xfb82,0xffff,0x5a91,0xffff,0xffff,0xffff,0x77c0, + 0x64c5,0x8ee9,0xffff,0x99e2,0x5cdf,0x7ed9,0xffff,0xffff, + 0x508f,0xffff,0x5dd6,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0x7ef0,0x59ea,0x4f9c,0xffff,0xffff,0x4fbf, + 0xffff,0xffff,0xffff,0x4cc4,0x46a0,0xffff,0x41e2,0x7de6, + 0x5cfa,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x75f4, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x75d5, + 0xffff,0xffff,0xffff,0xffff,0x5ec0,0xffff,0xffff,0xffff, + 0xc693,0xffff,0x47be,0x69e5,0xffff,0x50b1,0x81e4,0x4ec2, + 0xffff,0xffff,0xffff,0x9eed,0x43a0,0xffff,0xffff,0x79fb, + 0xffff,0x9f9f,0xffff,0x71aa,0x4ecc,0xffff,0xffff,0xffff, + 0x76ec,0xf482,0x40d6,0xffff,0xffff,0xffff,0xffff,0x9387, + 0xffff,0xffff,0x80f0,0x82e9,0xffff,0xffff,0xffff,0x56bf, + 0xffff,0xffff,0xffff,0xffff,0xffff,0x88b3,0x9fe1,0x44e6, + 0x42fa,0xffff,0x90cd,0xffff,0x69b6,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xcd91,0x6ed9,0xffff,0x91e5,0xffff, + 0xffff,0xffff,0xffff,0xffff,0x6fbc,0xffff,0xffff,0xffff, + 0xda84,0x82e7,0x6e8e,0xffff,0xffff,0xffff,0xffff,0xffff, + 0x67ed,0x70d9,0x8ce1,0xffff,0xffff,0xffff,0x59ae,0x74d9, + 0xffff,0xffff,0xa48f,0xffff,0x6ae1,0x9bc3,0xfe9c,0xffff, + 0x49da,0x4583,0x49d6,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0x82f0,0x80e9,0xffff,0xffff,0xd48b,0x5fc0, + 0xffff,0xc199,0x9f95,0x46c5,0xffff,0x93b4,0x7be5,0x58e6, + 0x46fa,0x9ed1,0x75cf,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xa285,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0x49de,0xffff,0x6ed5, + 0xffff,0xffff,0x8194,0xf489,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0x97ef,0xffff,0xfd9d,0xffff,0xeb93,0x95e3, + 0xffff,0x7dfb,0xffff,0x5bdf,0x9e95,0xffff,0xffff,0xffff, + 0xffff,0xaf83,0x58d6,0xffff,0xffff,0xffff,0xffff,0xffff, + 0x5cde,0xa38d,0x96f0,0x62f4,0xffff,0x8adf,0xffff,0x7ebf, + 0xb199,0xffff,0xffff,0xffff,0xfdba,0xffff,0x4fe2,0x55e7, + 0x5ffa,0xffff,0xffff,0xffff,0xffff,0x45dc,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0x85ae,0x51d0,0x5cd5,0x94c2,0xffff,0xe094,0x558f, + 0x73da,0xffff,0xffff,0xffff,0xffff,0x5edd,0xffff,0xffff, + 0xffff,0xffff,0x5c8c,0xffff,0xffff,0xffff,0xffff,0x5bb8, + 0x4ad5,0xffff,0xffff,0x41d4,0xffff,0xffff,0x81ce,0xffff, + 0xffff,0xc087,0x81cf,0xffff,0x8ded,0xffff,0xffff,0xffff, + 0xffff,0x8683,0x4fd6,0x808e,0xffff,0xffff,0xc08c,0xffff, + 0xffff,0xffff,0xffff,0x81e9,0xffff,0xffff,0xffff,0x7abf, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x53e2,0x49e7, + 0x59fa,0x63d2,0x87ce,0xffff,0x63bc,0x8bdb,0x9cf4,0x8bf0, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xc094,0x889a,0xffff,0x5bca,0xb394,0x84be,0xffff, + 0xffff,0x8e84,0xffff,0xffff,0x418a,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xb49e,0x5bb2,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0x62d5,0x7bbd,0xffff,0x759c,0x65e9, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0x5185,0xae83,0x42d6,0xffff,0x53c6,0xffff,0xffff,0x7a87, + 0xffff,0xe28d,0x548f,0x93e9,0xffff,0xffff,0xffff,0x77bf, + 0xc999,0xffff,0xffff,0xffff,0xffff,0xffff,0x62e2,0x9ae7, + 0x57fb,0x4dd2,0xffff,0xffff,0x67bc,0xffff,0x99f4,0x90f0, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0x4d91,0xffff,0xe887,0xffff,0xffff,0x4dd9, + 0x92b6,0xffff,0xffff,0x65d6,0xffff,0xffff,0xffff,0xa889, + 0xffff,0xffff,0xffff,0xffff,0x79eb,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0x93c3,0x43b8,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0x5485,0xffff,0x4ad6,0xd788,0x72c6,0xffff,0xd092,0xffff, + 0xffff,0xffff,0xffff,0x8be9,0xffff,0xffff,0xffff,0x8abf, + 0xffff,0xffff,0xffff,0xffff,0x8f9f,0xffff,0x81e2,0x5be6, + 0x70fa,0xffff,0xffff,0xffff,0xffff,0x5ddc,0x45f5,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xc58e,0x4b91,0x47f2,0xffff,0xffff,0xb683,0xffff, + 0xffff,0xec92,0x75e9,0xffff,0xffff,0xffff,0xffff,0xa991, + 0xffff,0xffff,0x7981,0xffff,0xffff,0xffff,0xffff,0xffff, + 0x78bc,0xffff,0xffff,0xffff,0xffff,0x72f8,0xffff,0xffff, + 0xffff,0x728e,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0x9bd5,0xffff,0xffff,0xffff,0xbb93,0xffff, + 0xffff,0xffff,0xffff,0x5df4,0xffff,0xffff,0xffff,0x89bf, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xa0e2,0x9fe6, + 0x77fa,0xffff,0xffff,0xffff,0xffff,0x51dc,0x47f5,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xce89,0xffff,0x4ea0,0xffff,0xc48f,0xec9c,0xa0ea,0xffff, + 0x4dda,0xffff,0xffff,0x5d93,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xcf93,0x8bfd,0xe398,0xffff, + 0xffff,0xffff,0x95d2,0x5c94,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0x73eb,0xffff,0x8ae7,0xffff, + 0x91d9,0xffff,0x83d6,0xffff,0xffff,0x4dbf,0xffff,0xffff, + 0xc287,0xffff,0xffff,0x94e9,0x739d,0xffff,0xffff,0x69c0, + 0xbe99,0xffff,0xe195,0xffff,0xffff,0x83b4,0x6be2,0x6be6, + 0x8dfa,0xffff,0x93cf,0xffff,0xffff,0xffff,0x52f5,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0x6ec9,0xffff,0xb285,0xffff,0xa68c,0xffff, + 0xf98c,0xffff,0xffff,0x78dd,0x76c7,0xffff,0x78f1,0xffff, + 0xb39d,0x43ab,0xffff,0xffff,0x58c4,0xffff,0xffff,0x60b8, + 0xffff,0xffff,0x87d4,0xffff,0xffff,0x57f1,0x50c5,0x40ef, + 0xffff,0xffff,0xffff,0xffff,0xffff,0x77da,0xffff,0xffff, + 0xffff,0xffff,0x95d7,0xffff,0xffff,0xbdb9,0xffff,0x6a87, + 0xffff,0xffff,0xffff,0x92e9,0xffff,0xffff,0xffff,0x9dbf, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x6ae2,0x9de7, + 0x84fa,0xffff,0xffff,0xffff,0xffff,0xffff,0x7cf7,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0x54c1,0x5de9,0x93c5,0x56b0,0x909c,0xffff,0xffff,0xffff, + 0x8284,0xffff,0xffff,0xffff,0x61ee,0x4db7,0xffff,0xffff, + 0xffff,0xffff,0xe092,0x69d6,0xc090,0xffff,0xffff,0x4a9a, + 0xffff,0xfd9f,0xffff,0x4bcc,0xffff,0x84f1,0xffff,0x55eb, + 0xffff,0x81ee,0x87cb,0x54d5,0xffff,0xffff,0x4bbd,0x6e9d, + 0xffff,0xffff,0x71d6,0xffff,0xffff,0xffff,0xffff,0x7d87, + 0xffff,0xb9bc,0xffff,0x91e9,0xffff,0xffff,0xffff,0x95bf, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x5be2,0x93e6, + 0x90fa,0xffff,0xffff,0xffff,0xffff,0xffff,0x64b7,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0x7d82,0xffff,0xffff,0xffff,0x8d87,0xffff, + 0x93e4,0xffff,0xffff,0xffff,0x5ad9,0xffff,0xffff,0xffff, + 0xb798,0xffff,0x86dd,0x9b8f,0x5bf4,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0x91d3,0x4599,0xffff,0x46ac, + 0xffff,0x90e9,0xffff,0xffff,0xc49e,0xffff,0x4eb7,0xffff, + 0xffff,0xffff,0x75d6,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0x98e9,0xffff,0xffff,0xdf8b,0x5ced, + 0xffff,0xa999,0xffff,0x84c3,0xefc1,0xffff,0x82e2,0x79e6, + 0x96fa,0xffff,0xffff,0x65bb,0x52bc,0xffff,0x56f5,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xe69c,0xffff,0xffff,0xffff,0xffff,0x8abc, + 0xffff,0xffff,0x51fa,0xffff,0xffff,0x41eb,0xffff,0xffff, + 0xffff,0xffff,0x9082,0xffff,0xffff,0x8192,0x56d7,0x48d3, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x49ab, + 0xb483,0xffff,0xffff,0xffff,0xffff,0xffff,0x5bc4,0xffff, + 0xffff,0xffff,0x6bd6,0xffff,0x64cc,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xa0e9,0xffff,0xffff,0xffff,0x60c0, + 0xffff,0xffff,0xffff,0xffff,0xffff,0x7eb4,0x5ee2,0x84e6, + 0x49fb,0xffff,0xffff,0xffff,0xffff,0xffff,0x63f7,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x9e89, + 0xffff,0x50ea,0x52d9,0xffff,0x9be2,0xffff,0xffff,0xffff, + 0x44e8,0xffff,0xf681,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xe886,0x68bf, + 0xffff,0xffff,0xffff,0xffff,0x64dd,0xffff,0xffff,0xffff, + 0xffff,0xffff,0x86d6,0xffff,0xffff,0xffff,0xd793,0x5e87, + 0xffff,0xffff,0xffff,0x48ea,0xffff,0xffff,0xffff,0x52c0, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x80e2,0x89e6, + 0x98fa,0xffff,0xffff,0xffff,0xffff,0xffff,0x54f5,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0x74df,0xffff,0xffff,0x44ee,0xffff, + 0x56be,0xffff,0xffff,0xa79a,0xffff,0xffff,0x65c5,0xb893, + 0xffff,0x52c5,0x539c,0x92d2,0x48f0,0xffff,0xffff,0xffff, + 0x7398,0xffff,0xdb89,0xffff,0xffff,0xffff,0x75e6,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x99db, + 0x7184,0xffff,0x76d7,0xffff,0xffff,0xffff,0xffff,0xf486, + 0xefbe,0xffff,0x73d9,0x44ea,0xb99e,0xffff,0xffff,0x51c0, + 0x6497,0xffff,0xffff,0xffff,0xffff,0xffff,0x5ae2,0x5ce8, + 0x58fb,0xffff,0xffff,0x60ba,0xffff,0x57dc,0x71f5,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0x5b94,0xffff,0xffff,0xffff,0x66dc,0xffff,0xffff,0xffff, + 0x8f8d,0xffff,0xffff,0xffff,0xffff,0x9db9,0xffff,0xffff, + 0xffff,0x8fe0,0x5dbe,0xffff,0xc883,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0x76f2,0xffff,0xf59e,0x57f0, + 0xb09b,0xffff,0x7c83,0xb6ec,0xffff,0xffff,0x8ab1,0xffff, + 0xffff,0xffff,0x50d7,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0x49ea,0xffff,0xffff,0xffff,0x79c0, + 0xffff,0xb499,0x53d9,0x92c4,0xffff,0xffff,0x95e2,0x53e7, + 0xffff,0x40d2,0xffff,0xffff,0xffff,0xffff,0x5ef5,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0x59f1,0xffff,0xffff,0x67e2,0xffff, + 0xffff,0x5ed3,0xffff,0xffff,0x7283,0xffff,0xffff,0xffff, + 0xffff,0x5bf7,0x93d5,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x409b,0x77c1, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x43be, + 0xa584,0xffff,0x53d7,0xbf89,0xffff,0x72ca,0xffff,0xffff, + 0xffff,0x708e,0xffff,0x52ea,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0x42d9,0xffff,0xffff,0xffff,0x60e3,0x4de7, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x6ef5,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xa194,0xffff,0xffff,0x7590,0x5ab8,0xffff,0xffff,0x5e8a, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xdc82,0xffff,0xffff, + 0xffff,0xffff,0x7dcc,0xffff,0xffff,0xffff,0xab97,0xffff, + 0xffff,0x42bd,0xffff,0xffff,0x60d6,0xffff,0x5fd5,0x9791, + 0xffff,0xffff,0xffff,0xffff,0x8094,0xffff,0xffff,0x82bf, + 0x9284,0xffff,0x48d7,0xffff,0x9499,0xffff,0xffff,0x8287, + 0xffff,0xffff,0xffff,0xdde3,0x979e,0xffff,0xffff,0xffff, + 0xffff,0xffff,0x4cd9,0xffff,0xffff,0xffff,0x92e2,0x4ee7, + 0x58b0,0x68d2,0xffff,0xffff,0xffff,0x55dc,0x62f5,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0x58fd,0xffff,0x66df,0xffff,0xffff, + 0xffff,0x5ef0,0xffff,0xffff,0x7bf1,0xffff,0xfe93,0xffff, + 0xbe89,0x4384,0xffff,0xe783,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0x44b8,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xba95,0x55cf,0xffff,0x76bf, + 0xffff,0x4c83,0x97d7,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xc2b7,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xb599,0x5f99,0x4fd9,0xffff,0xffff,0xffff,0x8ee2,0xa0e6, + 0x4fb0,0xffff,0xffff,0x7eb9,0xffff,0xffff,0x71f7,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xfa8e,0xffff,0xffff,0x86be,0xffff,0xffff, + 0x56c5,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0x55d9,0x5fc1,0xffff,0xffff,0xffff,0xffff,0x8b8c, + 0x71bd,0x64d9,0x46ab,0xffff,0xffff,0xffff,0x6f9f,0xffff, + 0xffff,0x47c6,0xffff,0xffff,0x9dd9,0x48de,0xffff,0x75e0, + 0xffff,0xffff,0x64d7,0xc889,0xffff,0x89ca,0xffff,0xffff, + 0xffff,0xffff,0x5b8f,0xffff,0x5d9e,0xffff,0xffff,0xffff, + 0xffff,0xffff,0x97d9,0xffff,0xffff,0x4c9d,0x4fe3,0x4fe7, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x6ff5,0x57f4, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0x85df,0xffff,0xffff,0xffff,0x8dee,0xffff,0x8d91, + 0xffff,0x5491,0xffff,0x56d9,0x9e9a,0xffff,0xffff,0xffff, + 0xffff,0xffff,0x89df,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0x56d4,0xffff,0xffff,0x8fca,0x80be, + 0xffff,0xffff,0xffff,0x9bdd,0x45da,0xffff,0x61d6,0xffff, + 0xffff,0xffff,0x8fd7,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0x6699,0xffff,0x44d9,0xffff,0xffff,0xffff,0x98e2,0x97e6, + 0x5bb0,0x8bbf,0xffff,0xffff,0xffff,0xffff,0x9cf5,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0x8ebe,0xc882,0xffff,0xffff,0xffff,0xffff,0x53bc, + 0xffff,0xffff,0xffff,0x78b7,0x4fb1,0x8d9d,0xffff,0xffff, + 0x90ee,0xffff,0x8ce8,0x64be,0xffff,0xffff,0x449c,0xffff, + 0xffff,0xffff,0xd098,0x43c3,0x52e4,0x6dd2,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0x4bc5,0x4ee6,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xe6da,0x5cca,0xffff,0xffff,0x8887, + 0xa387,0xffff,0xffff,0xffff,0xffff,0xffff,0x7af1,0xffff, + 0xffff,0xffff,0x57d9,0xffff,0xffff,0xffff,0x93e2,0x9be6, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x5cf7,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0x48d9,0xd483,0xffff,0xffff,0xffff,0x5a8a,0x53d8, + 0xffff,0x9ed8,0x4d99,0xfe95,0xd488,0x59bd,0xffff,0xffff, + 0x499c,0xffff,0x6abb,0xffff,0xffff,0xffff,0xffff,0x70dd, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xfb8e, + 0xffff,0x9285,0xffff,0xffff,0xffff,0xffff,0x53dd,0xffff, + 0xffff,0x65bc,0x848e,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x86f1,0x5ead, + 0xffff,0xffff,0x42da,0x54c4,0xffff,0xffff,0x58e3,0x43e7, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x86f5,0x4efc, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0x799c,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0x5aa0,0xffff,0xffff,0x8fe4,0xec8e, + 0xffff,0xffff,0x85f2,0xffff,0x4d94,0x72d9,0xffff,0xe49a, + 0xffff,0xffff,0xffff,0xffff,0x7dee,0xffff,0xc785,0x82e8, + 0x50e4,0x8eb3,0xffff,0xffff,0xffff,0x40df,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xc589,0xffff,0xffff,0x9d93,0x9d87, + 0xffff,0xc68f,0xffff,0xffff,0xffff,0xffff,0x80f1,0x7cac, + 0xbf97,0x7b9a,0x63d9,0xffff,0x63a0,0xffff,0x66e3,0x86e7, + 0xede5,0xffff,0xffff,0xffff,0xffff,0xffff,0x7ef7,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xd38c,0xeb9f,0xffff,0x63fc,0xffff,0xf797, + 0xffff,0x568f,0xffff,0x5285,0x7bb9,0xffff,0xffff,0x9dd1, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x4183, + 0xffff,0x7a94,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0x7ef4,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0x4c89,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xd491,0x969e,0xecbb,0xffff,0x7cf2,0xffff, + 0xef98,0xffff,0x6cd9,0xffff,0xffff,0xffff,0x67e3,0x8fe7, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x96f6,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0x43ee,0x83d7,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0x80e6,0xffff,0x5ade,0x4dd6,0x67e9,0xffff,0xffff,0x46d5, + 0xffff,0x67fd,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0x94dd,0x6deb,0xffff,0x9d8f,0xffff,0xffff, + 0xffff,0xffff,0x9b91,0xffff,0x8fe8,0xffff,0xffff,0xffff, + 0xffff,0x5afc,0xffff,0xc089,0xa69f,0x56ca,0xffff,0xffff, + 0xffff,0xffff,0x9391,0xffff,0xa79d,0xffff,0x41f3,0xffff, + 0xffff,0x919a,0x67d9,0xffff,0xffff,0xffff,0x9ae2,0x68e7, + 0xffff,0x97b0,0xffff,0xffff,0xffff,0xffff,0x9ef6,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0x6ed0,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0x64d5,0xffff,0xffff,0xd691,0xffff, + 0xffff,0x8fe2,0xffff,0x92be,0x81c4,0xffff,0xffff,0xffff, + 0xffff,0xd891,0xffff,0xffff,0x77f3,0xb39e,0xffff,0xffff, + 0x43c0,0xa98f,0x78c1,0xffff,0xffff,0xffff,0x99b0,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x77f1,0x6bab, + 0x4598,0xffff,0x7dd9,0xffff,0xffff,0xffff,0x70e8,0x75e8, + 0x92b0,0xffff,0x58cf,0x6aba,0xffff,0xffff,0x88f6,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0x78cf,0xffff,0x7c89,0xffff,0x68e4, + 0xffff,0x8ed2,0xffff,0x4cc0,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0x98f1,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0x53eb,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0x4f9d,0x9797,0xffff,0xffff,0xffff, + 0xffff,0xcf87,0xffff,0xffff,0xffff,0xffff,0xffff,0x8187, + 0xffff,0xffff,0x5991,0xffff,0xffff,0xffff,0x7ef1,0xffff, + 0xffff,0x8c9a,0x79d9,0xffff,0xffff,0xffff,0x8be2,0x85e7, + 0xffff,0xffff,0xffff,0x44ba,0xffff,0x62dc,0x9cf6,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0x71de,0xffff,0xffff,0xffff,0x8aeb,0xffff,0x4cef, + 0xffff,0xffff,0xffff,0x9dc8,0xffff,0xffff,0xa184,0xffff, + 0xffff,0xffff,0x6abd,0xffff,0xffff,0x8a87,0xffff,0xffff, + 0xffff,0xffff,0xffff,0x97bd,0xffff,0x42ee,0xffff,0x6ce0, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x8395,0x7bd4, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x94f2,0x87ad, + 0x8198,0x9a9a,0x8ed9,0xffff,0xffff,0xffff,0x43e3,0x7ce8, + 0xffff,0xffff,0xffff,0xffff,0xffff,0x98db,0x85f5,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0x70de,0xffff,0x998c,0xffff,0xffff,0xffff,0x82af, + 0xffff,0xf9ce,0x99f8,0xffff,0x44c6,0xffff,0xffff,0xffff, + 0xffff,0x529c,0x8c8b,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0x4fd4,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0x56d6,0x84d4,0xffff,0xffff,0xffff,0x45f3,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xa593,0xffff, + 0xfcc5,0x6583,0xffff,0xffff,0xffff,0xffff,0x91f2,0xffff, + 0xffff,0xffff,0x97d2,0xffff,0xffff,0x90fd,0x42e3,0x92e7, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x8ff5,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x9989,0xffff, + 0x5294,0x779a,0xffff,0xffff,0xffff,0xffff,0x4ef9,0x4b89, + 0x68bb,0x60ec,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xf895,0xffff,0xffff,0xffff,0xffff,0xffff, + 0x93cc,0x9ef2,0x68d7,0xca8a,0xffff,0xffff,0xffff,0x4dbd, + 0xffff,0xffff,0xffff,0xffff,0x81ca,0xffff,0xffff,0x4f87, + 0xffff,0xffff,0xf790,0xffff,0xffff,0xffff,0x89f1,0xffff, + 0xffff,0x979a,0x4ad3,0xffff,0xffff,0xffff,0x47e3,0x89e8, + 0x7baf,0xffff,0xffff,0xffff,0xffff,0x58dc,0x8cf5,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xcb98,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0x94fd,0xffff,0xffff,0x7dbe,0xffff,0xffff,0xffff, + 0x82d8,0xffff,0x94ac,0xffff,0xffff,0xffff,0x9ac4,0x95ed, + 0xffff,0xffff,0x48da,0x719a,0xffff,0xffff,0xffff,0x94d4, + 0x7587,0xffff,0x78d5,0xffff,0xffff,0x91d8,0xffff,0x40e3, + 0xffff,0xffff,0x80ea,0xffff,0x9cc9,0xffff,0xab93,0xffff, + 0xffff,0xffff,0x9d90,0xffff,0xffff,0xffff,0x50f3,0xffff, + 0xffff,0xffff,0xa0d2,0xffff,0xffff,0xffff,0x89e2,0x6ae7, + 0xffff,0xffff,0xffff,0x58bb,0x7bbf,0xffff,0x61f6,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xa0ae,0xffff,0xffff,0xffff,0x54f1, + 0x9df8,0x7ce9,0xffff,0x869c,0x4fc0,0x5dd5,0xffff,0x7e83, + 0x78eb,0x588e,0x61b4,0xffff,0xffff,0xffff,0x52fd,0x88d5, + 0xffff,0xffff,0xffff,0xffff,0xcf8c,0xffff,0x5d89,0xffff, + 0x9aed,0xffff,0x67d7,0x63c5,0xffff,0x98e1,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xba88,0xffff,0x87f2,0xffff,0x5a87, + 0x6fd6,0xffff,0xed90,0xffff,0x759e,0xffff,0x55f2,0x7aac, + 0xe598,0x9b9a,0x5dd3,0xffff,0xffff,0xffff,0x94e2,0x8be7, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x9bf5,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0x6bde,0xffff,0xffff,0x50dc,0xffff,0xffff,0x5af9,0x70bf, + 0xffff,0x89dc,0x74bc,0xffff,0x7a99,0xc38c,0xffff,0xffff, + 0xffff,0x49ee,0x9bce,0xffff,0x6694,0xffff,0xffff,0x6391, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x91ed, + 0xffff,0x84f8,0x90ae,0x5a8e,0xffff,0xc982,0xffff,0xffff, + 0xffff,0x44f8,0xffff,0xffff,0xffff,0xffff,0xe593,0xffff, + 0xffff,0xffff,0xffff,0xffff,0x749e,0xffff,0x53f2,0xffff, + 0xffff,0xffff,0x44d3,0xffff,0xffff,0xffff,0x49e8,0x5ae8, + 0x41b0,0x67c2,0xffff,0x84ba,0xffff,0xffff,0x4ef6,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0x4fbd,0xffff,0xffff,0xffff,0x65e5,0xd59d,0xffff,0x53d6, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x928c, + 0xffff,0xffff,0x52f1,0x528f,0xd393,0xffff,0xffff,0x82ad, + 0x9bdc,0xffff,0xffff,0xffff,0xffff,0xffff,0x46ec,0xffff, + 0x53d4,0xffff,0xffff,0xffff,0xffff,0xffff,0x69d8,0xffff, + 0xffff,0xffff,0x9fea,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xbf9c,0x459e,0xffff,0x4bf2,0xffff, + 0x7599,0x90dc,0x4dd3,0xffff,0xffff,0xffff,0x44e4,0x43e8, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x4ff6,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0x4df7,0xffff,0xffff,0xffff,0xffff,0x7eee,0xffff, + 0xffff,0x8ed4,0xffff,0xffff,0x4189,0xffff,0x81bd,0xffff, + 0xffff,0xffff,0x52c1,0xffff,0xffff,0xffff,0xffff,0x46b8, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x97ed, + 0xffff,0xee97,0xffff,0xffff,0x5eb8,0xffff,0x54d6,0xffff, + 0xffff,0xffff,0xffff,0x4e89,0xffff,0xffff,0xffff,0xffff, + 0xffff,0x45ab,0xffff,0xffff,0xffff,0xffff,0x89f2,0xffff, + 0xffff,0x97dc,0x50d3,0xffff,0xffff,0x67b2,0x99e3,0x4fe8, + 0xffff,0xffff,0x94cf,0xffff,0xffff,0xffff,0x45f6,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xcd8e,0xffff,0x8cd4,0x49bb,0x5fdf,0xffff,0x9ed3,0x50f8, + 0xffff,0xffff,0xffff,0xb7e2,0x7cfb,0xffff,0xffff,0xffff, + 0x59d1,0xffff,0xffff,0xffff,0xffff,0xffff,0x54f2,0xffff, + 0xffff,0xffff,0xffff,0x4f8c,0xffff,0xffff,0xffff,0xffff, + 0xffff,0x5093,0x5bc0,0x5ad5,0xffff,0x5cd4,0x44d5,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xee86, + 0xffff,0x77aa,0xffff,0xffff,0xffff,0xffff,0x73f2,0x9ced, + 0xe899,0x4ddd,0x55d3,0x74ec,0xffff,0xffff,0x73e3,0x64e8, + 0x42b0,0x65c2,0xffff,0x8dba,0x9ffb,0x6bdc,0x48f6,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0x6584,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xfe92,0xffff,0xffff,0xffff, + 0x8ef5,0xffff,0xe186,0xe79c,0x84e1,0xffff,0xffff,0xffff, + 0xffff,0x9dbc,0xffff,0x7093,0xffff,0xffff,0xffff,0xffff, + 0xa294,0xffff,0xffff,0xffff,0x9fd8,0xffff,0xffff,0xffff, + 0xffff,0xbc83,0xffff,0x7388,0xffff,0xffff,0xffff,0xffff, + 0xf787,0xffff,0xffff,0xffff,0xffff,0xd58c,0x5cf2,0xffff, + 0xa897,0x56dd,0xffff,0x65c4,0xffff,0xffff,0x42e4,0x73e8, + 0xffff,0xffff,0xffff,0xffff,0x44fc,0xffff,0x4bf6,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0x54b0,0xffff,0x49be,0xffff,0xffff,0xba90,0xffff, + 0xffff,0x9999,0xffff,0x40ab,0xec93,0xffff,0xffff,0xffff, + 0x59b6,0xffff,0xffff,0xffff,0x42f8,0xffff,0x4dd8,0xffff, + 0x4ae4,0xffff,0xffff,0x53b9,0xffff,0xffff,0xd584,0xffff, + 0xffff,0x83af,0x61ca,0xffff,0xf193,0xffff,0xffff,0xffff, + 0xf882,0xffff,0xffff,0xdf88,0x77ca,0x79cc,0xffff,0xffff, + 0xffff,0xffff,0xffff,0x7b9e,0xffff,0xffff,0x88f2,0xffff, + 0xb8b0,0x5fde,0xffff,0xffff,0xffff,0xffff,0x85e4,0x52e6, + 0xffff,0xffff,0xffff,0x88ba,0xffff,0xffff,0x41f6,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xf1b5,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0x86ba,0xffff,0xffff,0xffff, + 0xffff,0xffff,0x49d9,0xffff,0xffff,0xffff,0xffff,0xffff, + 0x63e9,0xffff,0xffff,0xffff,0xffff,0x66c8,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0x7484,0x82e6,0x54a0,0xffff, + 0xffff,0x96d0,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0x6f9e,0x879e,0x868f,0x74f2,0xffff, + 0xffff,0x54dd,0xffff,0xffff,0x5bb6,0xffff,0x65e4,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0x67dc,0x46f6,0x74fc, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0x89bd,0xffff,0x7694,0x68e1,0xffff,0xffff,0xffff,0xffff, + 0x77e9,0x46d9,0xe1e1,0xffff,0x8083,0xffff,0xffff,0x56b5, + 0xffff,0x73f0,0x9cfb,0xffff,0xffff,0xffff,0xffff,0xffff, + 0x999d,0x8f8c,0xffff,0xffff,0xffff,0xffff,0x60d5,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xc99d,0x87ea,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x6494,0xffff, + 0xffff,0x83fb,0xffff,0xffff,0x7a9e,0xffff,0x7ef2,0xffff, + 0xffff,0x57dd,0xffff,0xffff,0xffff,0xffff,0x74e7,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x54f6,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0x6c9e,0xbd93,0xffff,0xffff,0xffff,0xffff,0x77c4, + 0xffff,0xa384,0xffff,0xffff,0xffff,0x6fbe,0xffff,0xffff, + 0xffff,0xffff,0x75d9,0xffff,0x99c2,0x69f9,0xa286,0xffff, + 0xffff,0xf08b,0xd98c,0xffff,0xffff,0xffff,0xffff,0x92ca, + 0xffff,0x96ea,0xffff,0xffff,0x5cd9,0xffff,0xffff,0xffff, + 0xffff,0x43d2,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x8af2,0x74ad, + 0xffff,0x46dd,0xffff,0xffff,0xffff,0xffff,0x79e4,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xa0f5,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0x499e,0x73cf,0xffff,0xffff,0xffff,0xffff,0xffff, + 0x74e3,0x81dd,0xffff,0x9bd8,0x709c,0x5ce5,0x58d3,0xe795, + 0xffff,0xa284,0x7edf,0x9191,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0x67d0,0x73bf,0x6c97,0xffff,0xffff,0xffff, + 0xffff,0xffff,0x8eea,0x6ebb,0xffff,0xea92,0x9ab2,0xffff, + 0xffff,0x4cc5,0xffff,0x5089,0xffff,0xffff,0xffff,0x4b87, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x8bf2,0x71ac, + 0xffff,0xa0dc,0xffff,0xffff,0x9db5,0xffff,0x4be8,0xffff, + 0xffff,0xffff,0xffff,0xffff,0x8eda,0xffff,0x58f6,0x6ffc, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0x65d9,0x92f0,0xffff,0xffff,0x9ee1,0x49f0,0xffff, + 0x8082,0x4c9d,0xffff,0x9cb5,0x5dcb,0x4883,0x519b,0x729b, + 0x90fb,0xffff,0x7dc3,0x7de9,0xa787,0xffff,0xffff,0xffff, + 0xffff,0x49c4,0xffff,0x8dac,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xa0b1,0xda87,0xffff, + 0x7482,0xffff,0xffff,0xe588,0x43cb,0x76e6,0xffff,0xffff, + 0xffff,0x9caa,0xffff,0xffff,0xffff,0xffff,0x96f2,0x49ad, + 0xffff,0x5dde,0xffff,0xffff,0xffff,0x7bb1,0x48e4,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x99f5,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0x5ee6,0x5094,0x8bd7,0xbb99,0xffff,0x7bd5,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xf493,0x9199,0x94d6,0x45d4,0x9dcc, + 0x9685,0xffff,0x6db2,0xffff,0x87e8,0xffff,0xffff,0x85da, + 0xa29e,0xffff,0xe498,0xffff,0xffff,0xffff,0xffff,0xffff, + 0x77be,0x57b0,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xe182,0x41b7,0x97e0,0x5f89,0xffff,0x9aca,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x4bf3,0xffff, + 0xffff,0x55dd,0xffff,0x9cc4,0xffff,0xffff,0x9fe3,0xffff, + 0x44b0,0x9cc2,0x4ecf,0xffff,0xffff,0xffff,0x61f7,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0x70c0,0x4e8f,0xa78e,0xffff,0xffff,0x97dd, + 0x6fbd,0x81e5,0xd889,0xffff,0x62e8,0x4ddf,0x5ebd,0xffff, + 0xee84,0xffff,0x7af0,0xffff,0x87e6,0xffff,0xe29a,0x5e85, + 0x5fcb,0x429d,0xffff,0x69e6,0xffff,0x57be,0xffff,0xffff, + 0x6dc0,0x42f0,0x79e3,0xffff,0xffff,0x62aa,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xae8e,0x73aa,0xab91,0x549e,0xffff,0xffff,0x4af3,0xffff, + 0xffff,0x59dd,0xffff,0xffff,0x55b6,0xffff,0x7ae6,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x6cf6,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0x72d6,0xffff,0x50e7,0xffff,0xffff,0xffff,0xba83,0xffff, + 0xffff,0xffff,0xffff,0xffff,0x60db,0xffff,0xffff,0x688e, + 0x5bb5,0xffff,0x55d0,0x51f8,0xffff,0xffff,0xffff,0xffff, + 0xffff,0x95c2,0xffff,0xffff,0x4ed9,0xffff,0xffff,0xcc87, + 0x8edc,0xd398,0xffff,0x52b6,0x9bd9,0x8ea0,0xffff,0xffff, + 0xd081,0xffff,0x77e0,0xffff,0x6acb,0xffff,0xffff,0xca87, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xe9f4,0xffff, + 0xf499,0x65dd,0xffff,0xffff,0xffff,0x41b2,0x8fe3,0x84b7, + 0x8eaf,0x98c2,0xffff,0xffff,0xffff,0xffff,0x7bf7,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0x61ae,0x7ae4,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xf887,0xffff,0x4399,0x76d9,0x7895,0xffff,0x51b8, + 0x769a,0x88fd,0x4d9d,0x91e3,0xffff,0xffff,0x8997,0xffff, + 0x77f6,0xffff,0x51d8,0xffff,0x46e8,0xffff,0xffff,0x4ee4, + 0xffff,0xffff,0xffff,0xffff,0x99bc,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0x5191,0xffff,0xffff,0xffff,0x75bc,0xffff, + 0xffff,0x62dd,0xffff,0xffff,0xffff,0x80b2,0x62e4,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x71f6,0x42fd, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0x55ea,0x72eb,0x4ad9,0xffff,0x96a0,0xffff, + 0xffff,0xffff,0xffff,0xffff,0x8ad2,0xffff,0x78e2,0xffff, + 0xffff,0x40c3,0xffff,0xffff,0x8e99,0xffff,0xffff,0x7cdc, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0x8bef,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0x9d88,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xc391,0xffff,0xffff,0xffff,0x71bc,0xffff, + 0xffff,0x60dd,0xffff,0xffff,0xffff,0xffff,0x41e4,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0x76f6,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0x9dee,0xffff,0xffff,0xfeb5,0x44f0,0xffff, + 0xffff,0xffff,0xffff,0xffff,0x49e6,0xffff,0x8adc,0xffff, + 0xffff,0xb587,0xffff,0xffff,0x9faa,0xffff,0xffff,0xffff, + 0x90d9,0xffff,0xffff,0xffff,0x648f,0xffff,0xffff,0xffff, + 0xd291,0xffff,0xffff,0x7aaa,0xffff,0xffff,0x41d9,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0x60cc,0x7494,0xffff, + 0xce8e,0xffff,0xc590,0xffff,0xffff,0xb38b,0x76bc,0xffff, + 0xb399,0x6ddd,0xffff,0xffff,0xffff,0x8fc3,0x66e7,0xffff, + 0x9baf,0x99ed,0xffff,0xffff,0xffff,0x78d3,0x6df6,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0x9eef,0xffff,0xffff,0xffff,0x99d5,0xffff,0xffff, + 0xffff,0x5edf,0xffff,0x65b7,0xffff,0x61a0,0xffff,0xffff, + 0xffff,0x5cbb,0xffff,0x87d6,0xffff,0xffff,0x99d3,0x8cf2, + 0xffff,0xffff,0xb594,0xffff,0xa0c2,0xffff,0x61e5,0xffff, + 0xffff,0xffff,0xffff,0xffff,0x9e84,0xffff,0x54e8,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xcea0,0xffff,0xffff,0xffff, + 0xbe8e,0x9daa,0xf090,0xffff,0xffff,0x9e8b,0x77bc,0xffff, + 0xa098,0x82dd,0xffff,0xffff,0xffff,0xffff,0x8ce3,0xffff, + 0xffff,0xa0ed,0x5ccf,0x66bb,0xffff,0xffff,0x63f6,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0x8384,0xffff,0xffff,0xffff,0xffff,0x42af,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0x8e8c,0xffff,0xffff,0xffff, + 0xffff,0x4bc0,0xffff,0xffff,0x4e9f,0xffff,0xdea0,0xd495, + 0xffff,0x8eac,0x5beb,0x75d7,0x88dc,0xffff,0x42ba,0xffff, + 0xffff,0xffff,0x92e0,0x7c89,0xee9c,0x41cc,0xffff,0xffff, + 0xbd8e,0xffff,0xffff,0xdc9b,0x7c9e,0xffff,0x6bc0,0xffff, + 0xffff,0x79dd,0xffff,0xffff,0xffff,0xffff,0x78e3,0xffff, + 0xffff,0x40ee,0xffff,0xffff,0xffff,0xffff,0x85f6,0x4ffd, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, + 0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff, +}; diff --git a/lib_acl/src/code/html_charset.h b/lib_acl/src/code/html_charset.h new file mode 100644 index 000000000..20c79f929 --- /dev/null +++ b/lib_acl/src/code/html_charset.h @@ -0,0 +1,8461 @@ +#ifndef __HTML_CHARSET_INCLUDE_H__ +#define __HTML_CHARSET_INCLUDE_H__ + +static const char *html_charmap[] = { + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, """, NULL, NULL, NULL, "&", "'", + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, "<", NULL, ">", NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + " ", "¡", "¢", "£", "¤", "¥", "¦", "§", + "¨", "©", "ª", "«", "¬", "­", "®", "¯", + "°", "±", "²", "³", "´", "µ", "¶", "·", + "¸", "¹", "º", "»", "¼", "½", "¾", "¿", + "À", "Á", "Â", "Ã", "Ä", "Å", "Æ", "Ç", + "È", "É", "Ê", "Ë", "Ì", "Í", "Î", "Ï", + "Ð", "Ñ", "Ò", "Ó", "Ô", "Õ", "Ö", "×", + "Ø", "Ù", "Ú", "Û", "Ü", "Ý", "Þ", "ß", + "à", "á", "â", "ã", "ä", "å", "æ", "ç", + "è", "é", "ê", "ë", "ì", "í", "î", "ï", + "ð", "ñ", "ò", "ó", "ô", "õ", "ö", "÷", + "ø", "ù", "ú", "û", "ü", "ý", "þ", "ÿ", + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, "Œ", "œ", NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + "Š", "š", NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + "Ÿ", NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, "ƒ", NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, "ˆ", NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, "˜", NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, "Α", "Β", "Γ", "Δ", "Ε", "Ζ", "Η", + "Θ", "Ι", "Κ", "Λ", "Μ", "Ν", "Ξ", "Ο", + "Π", "Ρ", NULL, "Σ", "Τ", "Υ", "Φ", "Χ", + "Ψ", "Ω", NULL, NULL, NULL, NULL, NULL, NULL, + NULL, "α", "β", "γ", "δ", "ε", "ζ", "η", + "θ", "ι", "κ", "λ", "μ", "ν", "ξ", "ο", + "π", "ρ", "ς", "σ", "τ", "υ", "φ", "χ", + "ψ", "ω", NULL, NULL, NULL, NULL, NULL, NULL, + NULL, "&thetasym", "ϒ", NULL, NULL, NULL, "ϖ", NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, " ", " ", NULL, NULL, NULL, NULL, + NULL, " ", NULL, NULL, "‌", "‍", "‎", "‏", + NULL, NULL, NULL, "–", "—", NULL, NULL, NULL, + "‘", "’", "‚", NULL, "“", "”", "„", NULL, + "†", "‡", "•", NULL, NULL, NULL, "…", NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + "‰", NULL, "′", "″", NULL, NULL, NULL, NULL, + NULL, "‹", "›", NULL, NULL, NULL, "‾", NULL, + NULL, NULL, NULL, NULL, "⁄", NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, "€", NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, "ℑ", NULL, NULL, NULL, NULL, NULL, NULL, + "℘", NULL, NULL, NULL, "ℜ", NULL, NULL, NULL, + NULL, NULL, "™", NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, "ℵ", NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + "←", "↑", "→", "↓", "↔", NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, "↵", NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + "⇐", "⇑", "⇒", "⇓", "⇔", NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + "∀", NULL, "∂", "∃", NULL, "∅", NULL, "∇", + "∈", "∉", NULL, "∋", NULL, NULL, NULL, "∏", + NULL, "∑", "−", NULL, NULL, NULL, NULL, "∗", + NULL, NULL, "√", NULL, NULL, "∝", "∞", NULL, + "∠", NULL, NULL, NULL, NULL, NULL, NULL, "∧", + "∨", "∩", "∪", "∫", NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, "∴", NULL, NULL, NULL, + NULL, NULL, NULL, NULL, "∼", NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, "≅", NULL, NULL, + "≈", NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + "≠", "≡", NULL, NULL, "≤", "≥", NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, "⊂", "⊃", "⊄", NULL, "⊆", "⊇", + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, "⊕", NULL, "⊗", + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, "⊥", NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, "⋅", NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + "⌈", "⌉", "⌊", "⌋", NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, "⟨", "⟩", NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, "◊", NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + "♠", NULL, NULL, "♣", NULL, "♥", "♦", NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL +}; + +typedef struct { + unsigned short ch; + const char *txt; + size_t len; +} HTML_SPEC; + +static const HTML_SPEC html_tab[] = { + { 34, """, sizeof(""") - 1 }, + { 38, "&", sizeof("&") - 1 }, + { 39, "'", sizeof("'") - 1 }, + { 60, "<", sizeof("<") - 1 }, + { 62, ">", sizeof(">") - 1 }, + { 160, " ", sizeof(" ") - 1 }, + { 161, "¡", sizeof("¡") - 1 }, + { 162, "¢", sizeof("¢") - 1 }, + { 163, "£", sizeof("£") - 1 }, + { 164, "¤", sizeof("¤") - 1 }, + { 165, "¥", sizeof("¥") - 1 }, + { 166, "¦", sizeof("¦") - 1 }, + { 167, "§", sizeof("§") - 1 }, + { 168, "¨", sizeof("¨") - 1 }, + { 169, "©", sizeof("©") - 1 }, + { 170, "ª", sizeof("ª") - 1 }, + { 171, "«", sizeof("«") - 1 }, + { 172, "¬", sizeof("¬") - 1 }, + { 173, "­", sizeof("­") - 1 }, + { 174, "®", sizeof("®") - 1 }, + { 175, "¯", sizeof("¯") - 1 }, + { 176, "°", sizeof("°") - 1 }, + { 177, "±", sizeof("±") - 1 }, + { 178, "²", sizeof("²") - 1 }, + { 179, "³", sizeof("³") - 1 }, + { 180, "´", sizeof("´") - 1 }, + { 181, "µ", sizeof("µ") - 1 }, + { 182, "¶", sizeof("¶") - 1 }, + { 183, "·", sizeof("·") - 1 }, + { 184, "¸", sizeof("¸") - 1 }, + { 185, "¹", sizeof("¹") - 1 }, + { 186, "º", sizeof("º") - 1 }, + { 187, "»", sizeof("»") - 1 }, + { 188, "¼", sizeof("¼") - 1 }, + { 189, "½", sizeof("½") - 1 }, + { 190, "¾", sizeof("¾") - 1 }, + { 191, "¿", sizeof("¿") - 1 }, + { 192, "À", sizeof("À") - 1 }, + { 193, "Á", sizeof("Á") - 1 }, + { 194, "Â", sizeof("Â") - 1 }, + { 195, "Ã", sizeof("Ã") - 1 }, + { 196, "Ä", sizeof("Ä") - 1 }, + { 197, "Å", sizeof("Å") - 1 }, + { 198, "Æ", sizeof("Æ") - 1 }, + { 199, "Ç", sizeof("Ç") - 1 }, + { 200, "È", sizeof("È") - 1 }, + { 201, "É", sizeof("É") - 1 }, + { 202, "Ê", sizeof("Ê") - 1 }, + { 203, "Ë", sizeof("Ë") - 1 }, + { 204, "Ì", sizeof("Ì") - 1 }, + { 205, "Í", sizeof("Í") - 1 }, + { 206, "Î", sizeof("Î") - 1 }, + { 207, "Ï", sizeof("Ï") - 1 }, + { 208, "Ð", sizeof("Ð") - 1 }, + { 209, "Ñ", sizeof("Ñ") - 1 }, + { 210, "Ò", sizeof("Ò") - 1 }, + { 211, "Ó", sizeof("Ó") - 1 }, + { 212, "Ô", sizeof("Ô") - 1 }, + { 213, "Õ", sizeof("Õ") - 1 }, + { 214, "Ö", sizeof("Ö") - 1 }, + { 215, "×", sizeof("×") - 1 }, + { 216, "Ø", sizeof("Ø") - 1 }, + { 217, "Ù", sizeof("Ù") - 1 }, + { 218, "Ú", sizeof("Ú") - 1 }, + { 219, "Û", sizeof("Û") - 1 }, + { 220, "Ü", sizeof("Ü") - 1 }, + { 221, "Ý", sizeof("Ý") - 1 }, + { 222, "Þ", sizeof("Þ") - 1 }, + { 223, "ß", sizeof("ß") - 1 }, + { 224, "à", sizeof("à") - 1 }, + { 225, "á", sizeof("á") - 1 }, + { 226, "â", sizeof("â") - 1 }, + { 227, "ã", sizeof("ã") - 1 }, + { 228, "ä", sizeof("ä") - 1 }, + { 229, "å", sizeof("å") - 1 }, + { 230, "æ", sizeof("æ") - 1 }, + { 231, "ç", sizeof("ç") - 1 }, + { 232, "è", sizeof("è") - 1 }, + { 233, "é", sizeof("é") - 1 }, + { 234, "ê", sizeof("ê") - 1 }, + { 235, "ë", sizeof("ë") - 1 }, + { 236, "ì", sizeof("ì") - 1 }, + { 237, "í", sizeof("í") - 1 }, + { 238, "î", sizeof("î") - 1 }, + { 239, "ï", sizeof("ï") - 1 }, + { 240, "ð", sizeof("ð") - 1 }, + { 241, "ñ", sizeof("ñ") - 1 }, + { 242, "ò", sizeof("ò") - 1 }, + { 243, "ó", sizeof("ó") - 1 }, + { 244, "ô", sizeof("ô") - 1 }, + { 245, "õ", sizeof("õ") - 1 }, + { 246, "ö", sizeof("ö") - 1 }, + { 247, "÷", sizeof("÷") - 1 }, + { 248, "ø", sizeof("ø") - 1 }, + { 249, "ù", sizeof("ù") - 1 }, + { 250, "ú", sizeof("ú") - 1 }, + { 251, "û", sizeof("û") - 1 }, + { 252, "ü", sizeof("ü") - 1 }, + { 253, "ý", sizeof("ý") - 1 }, + { 254, "þ", sizeof("þ") - 1 }, + { 255, "ÿ", sizeof("ÿ") - 1 }, + { 338, "Œ", sizeof("Œ") - 1 }, + { 339, "œ", sizeof("œ") - 1 }, + { 352, "Š", sizeof("Š") - 1 }, + { 353, "š", sizeof("š") - 1 }, + { 376, "Ÿ", sizeof("Ÿ") - 1 }, + { 402, "ƒ", sizeof("ƒ") - 1 }, + { 710, "ˆ", sizeof("ˆ") - 1 }, + { 732, "˜", sizeof("˜") - 1 }, + { 913, "Α", sizeof("Α") - 1 }, + { 914, "Β", sizeof("Β") - 1 }, + { 915, "Γ", sizeof("Γ") - 1 }, + { 916, "Δ", sizeof("Δ") - 1 }, + { 917, "Ε", sizeof("Ε") - 1 }, + { 918, "Ζ", sizeof("Ζ") - 1 }, + { 919, "Η", sizeof("Η") - 1 }, + { 920, "Θ", sizeof("Θ") - 1 }, + { 921, "Ι", sizeof("Ι") - 1 }, + { 922, "Κ", sizeof("Κ") - 1 }, + { 923, "Λ", sizeof("Λ") - 1 }, + { 924, "Μ", sizeof("Μ") - 1 }, + { 925, "Ν", sizeof("Ν") - 1 }, + { 926, "Ξ", sizeof("Ξ") - 1 }, + { 927, "Ο", sizeof("Ο") - 1 }, + { 928, "Π", sizeof("Π") - 1 }, + { 929, "Ρ", sizeof("Ρ") - 1 }, + { 931, "Σ", sizeof("Σ") - 1 }, + { 932, "Τ", sizeof("Τ") - 1 }, + { 933, "Υ", sizeof("Υ") - 1 }, + { 934, "Φ", sizeof("Φ") - 1 }, + { 935, "Χ", sizeof("Χ") - 1 }, + { 936, "Ψ", sizeof("Ψ") - 1 }, + { 937, "Ω", sizeof("Ω") - 1 }, + { 945, "α", sizeof("α") - 1 }, + { 946, "β", sizeof("β") - 1 }, + { 947, "γ", sizeof("γ") - 1 }, + { 948, "δ", sizeof("δ") - 1 }, + { 949, "ε", sizeof("ε") - 1 }, + { 950, "ζ", sizeof("ζ") - 1 }, + { 951, "η", sizeof("η") - 1 }, + { 952, "θ", sizeof("θ") - 1 }, + { 953, "ι", sizeof("ι") - 1 }, + { 954, "κ", sizeof("κ") - 1 }, + { 955, "λ", sizeof("λ") - 1 }, + { 956, "μ", sizeof("μ") - 1 }, + { 957, "ν", sizeof("ν") - 1 }, + { 958, "ξ", sizeof("ξ") - 1 }, + { 959, "ο", sizeof("ο") - 1 }, + { 960, "π", sizeof("π") - 1 }, + { 961, "ρ", sizeof("ρ") - 1 }, + { 962, "ς", sizeof("ς") - 1 }, + { 963, "σ", sizeof("σ") - 1 }, + { 964, "τ", sizeof("τ") - 1 }, + { 965, "υ", sizeof("υ") - 1 }, + { 966, "φ", sizeof("φ") - 1 }, + { 967, "χ", sizeof("χ") - 1 }, + { 968, "ψ", sizeof("ψ") - 1 }, + { 969, "ω", sizeof("ω") - 1 }, + { 977, "&thetasym", sizeof("&thetasym") - 1 }, + { 978, "ϒ", sizeof("ϒ") - 1 }, + { 982, "ϖ", sizeof("ϖ") - 1 }, + { 8194, " ", sizeof(" ") - 1 }, + { 8195, " ", sizeof(" ") - 1 }, + { 8201, " ", sizeof(" ") - 1 }, + { 8204, "‌", sizeof("‌") - 1 }, + { 8205, "‍", sizeof("‍") - 1 }, + { 8206, "‎", sizeof("‎") - 1 }, + { 8207, "‏", sizeof("‏") - 1 }, + { 8211, "–", sizeof("–") - 1 }, + { 8212, "—", sizeof("—") - 1 }, + { 8216, "‘", sizeof("‘") - 1 }, + { 8217, "’", sizeof("’") - 1 }, + { 8218, "‚", sizeof("‚") - 1 }, + { 8220, "“", sizeof("“") - 1 }, + { 8221, "”", sizeof("”") - 1 }, + { 8222, "„", sizeof("„") - 1 }, + { 8224, "†", sizeof("†") - 1 }, + { 8225, "‡", sizeof("‡") - 1 }, + { 8226, "•", sizeof("•") - 1 }, + { 8230, "…", sizeof("…") - 1 }, + { 8240, "‰", sizeof("‰") - 1 }, + { 8242, "′", sizeof("′") - 1 }, + { 8243, "″", sizeof("″") - 1 }, + { 8249, "‹", sizeof("‹") - 1 }, + { 8250, "›", sizeof("›") - 1 }, + { 8254, "‾", sizeof("‾") - 1 }, + { 8260, "⁄", sizeof("⁄") - 1 }, + { 8364, "€", sizeof("€") - 1 }, + { 8465, "ℑ", sizeof("ℑ") - 1 }, + { 8472, "℘", sizeof("℘") - 1 }, + { 8476, "ℜ", sizeof("ℜ") - 1 }, + { 8482, "™", sizeof("™") - 1 }, + { 8501, "ℵ", sizeof("ℵ") - 1 }, + { 8592, "←", sizeof("←") - 1 }, + { 8593, "↑", sizeof("↑") - 1 }, + { 8594, "→", sizeof("→") - 1 }, + { 8595, "↓", sizeof("↓") - 1 }, + { 8596, "↔", sizeof("↔") - 1 }, + { 8629, "↵", sizeof("↵") - 1 }, + { 8656, "⇐", sizeof("⇐") - 1 }, + { 8657, "⇑", sizeof("⇑") - 1 }, + { 8658, "⇒", sizeof("⇒") - 1 }, + { 8659, "⇓", sizeof("⇓") - 1 }, + { 8660, "⇔", sizeof("⇔") - 1 }, + { 8704, "∀", sizeof("∀") - 1 }, + { 8706, "∂", sizeof("∂") - 1 }, + { 8707, "∃", sizeof("∃") - 1 }, + { 8709, "∅", sizeof("∅") - 1 }, + { 8711, "∇", sizeof("∇") - 1 }, + { 8712, "∈", sizeof("∈") - 1 }, + { 8713, "∉", sizeof("∉") - 1 }, + { 8715, "∋", sizeof("∋") - 1 }, + { 8719, "∏", sizeof("∏") - 1 }, + { 8721, "∑", sizeof("∑") - 1 }, + { 8722, "−", sizeof("−") - 1 }, + { 8727, "∗", sizeof("∗") - 1 }, + { 8730, "√", sizeof("√") - 1 }, + { 8733, "∝", sizeof("∝") - 1 }, + { 8734, "∞", sizeof("∞") - 1 }, + { 8736, "∠", sizeof("∠") - 1 }, + { 8743, "∧", sizeof("∧") - 1 }, + { 8744, "∨", sizeof("∨") - 1 }, + { 8745, "∩", sizeof("∩") - 1 }, + { 8746, "∪", sizeof("∪") - 1 }, + { 8747, "∫", sizeof("∫") - 1 }, + { 8756, "∴", sizeof("∴") - 1 }, + { 8764, "∼", sizeof("∼") - 1 }, + { 8773, "≅", sizeof("≅") - 1 }, + { 8776, "≈", sizeof("≈") - 1 }, + { 8800, "≠", sizeof("≠") - 1 }, + { 8801, "≡", sizeof("≡") - 1 }, + { 8804, "≤", sizeof("≤") - 1 }, + { 8805, "≥", sizeof("≥") - 1 }, + { 8834, "⊂", sizeof("⊂") - 1 }, + { 8835, "⊃", sizeof("⊃") - 1 }, + { 8836, "⊄", sizeof("⊄") - 1 }, + { 8838, "⊆", sizeof("⊆") - 1 }, + { 8839, "⊇", sizeof("⊇") - 1 }, + { 8853, "⊕", sizeof("⊕") - 1 }, + { 8855, "⊗", sizeof("⊗") - 1 }, + { 8869, "⊥", sizeof("⊥") - 1 }, + { 8901, "⋅", sizeof("⋅") - 1 }, + { 8968, "⌈", sizeof("⌈") - 1 }, + { 8969, "⌉", sizeof("⌉") - 1 }, + { 8970, "⌊", sizeof("⌊") - 1 }, + { 8971, "⌋", sizeof("⌋") - 1 }, + { 9001, "⟨", sizeof("⟨") - 1 }, + { 9002, "⟩", sizeof("⟩") - 1 }, + { 9674, "◊", sizeof("◊") - 1 }, + { 9824, "♠", sizeof("♠") - 1 }, + { 9827, "♣", sizeof("♣") - 1 }, + { 9829, "♥", sizeof("♥") - 1 }, + { 9830, "♦", sizeof("♦") - 1 }, +}; + +#endif diff --git a/lib_acl/src/code/uni2utf8.c b/lib_acl/src/code/uni2utf8.c new file mode 100644 index 000000000..7d003a234 --- /dev/null +++ b/lib_acl/src/code/uni2utf8.c @@ -0,0 +1,53 @@ +#include "StdAfx.h" +#include "uni2utf8.h" + +/** + * g_unichar_to_utf8: + * @c: a Unicode character code + * @buf: output buffer, must have at least 6 bytes of space. + * If %NULL, the length will be computed and returned + * and nothing will be written to @buf. + * + * Converts a single character to UTF-8. + * + * Return value: number of bytes written + **/ + +int uni2utf8(unsigned int c, char *buf, size_t size) +{ + unsigned int len = 0; + int first; + int i; + + if (c < 0x80) { + first = 0; + len = 1; + } else if (c < 0x800) { + first = 0xc0; + len = 2; + } else if (c < 0x10000) { + first = 0xe0; + len = 3; + } else if (c < 0x200000) { + first = 0xf0; + len = 4; + } else if (c < 0x4000000) { + first = 0xf8; + len = 5; + } else { + first = 0xfc; + len = 6; + } + + if (buf && size > 0) { + if (len > size) + len = size; + for (i = len - 1; i > 0; --i) { + buf[i] = (c & 0x3f) | 0x80; + c >>= 6; + } + buf[0] = c | first; + } + + return len; +} diff --git a/lib_acl/src/code/uni2utf8.h b/lib_acl/src/code/uni2utf8.h new file mode 100644 index 000000000..3500eee2b --- /dev/null +++ b/lib_acl/src/code/uni2utf8.h @@ -0,0 +1,7 @@ +#ifndef __ACL_UNI2UTF8_INCLUDE_H__ +#define __ACL_UNI2UTF8_INCLUDE_H__ +#include "stdlib/acl_define.h" + +int uni2utf8(unsigned int c, char *buf, size_t size); + +#endif diff --git a/lib_acl/src/db/acl_dbpool.c b/lib_acl/src/db/acl_dbpool.c new file mode 100644 index 000000000..7dfdbc558 --- /dev/null +++ b/lib_acl/src/db/acl_dbpool.c @@ -0,0 +1,138 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_stdlib.h" +#include "db/acl_dbpool.h" + +#endif + +#include "mysql/acl_dbpool_mysql.h" +#include "null/acl_dbpool_null.h" + +/*----------------------------------------------------------------------------*/ +#if 0 +static void __dbpool_debug_cfg(const ACL_DB_INFO *db_info) +{ + acl_msg_info("db_addr = %s\n", db_info->db_addr); + acl_msg_info("db_user = %s\n", db_info->db_user); + acl_msg_info("db_pass = %s\n", db_info->db_pass); + acl_msg_info("db_name = %s\n", db_info->db_name); + acl_msg_info("db_max = %d\n", db_info->db_max); + acl_msg_info("ping_inter = %d\n", db_info->ping_inter); + acl_msg_info("timeout_inter = %d\n", db_info->timeout_inter); +} +#endif +/*----------------------------------------------------------------------------*/ +ACL_DB_POOL *acl_dbpool_create(const char *db_type, const ACL_DB_INFO *db_info) +{ + char myname[] = "acl_dbpool_create"; + ACL_DB_POOL *db_pool = NULL; + ACL_DB_INFO *info; + + if (db_type == NULL) + db_type = "mysql"; + + if (strcasecmp(db_type, "null") == 0) + db_pool = acl_dbpool_null_create(db_info); +#ifdef HAS_MYSQL + else if (strcasecmp(db_type, "mysql") == 0) + db_pool = acl_dbpool_mysql_create(db_info); +#endif + else { + acl_msg_fatal("%s, %s(%d): %s not supported yet", + __FILE__, myname, __LINE__, db_type); + } + + if (db_pool == NULL) { + acl_msg_error("%s, %s(%d): dbpool_%s_create error", + __FILE__, myname, __LINE__, db_type); + return (NULL); + } + + info = &db_pool->db_info; + +#if 0 + ACL_SAFE_STRNCPY(info->db_addr, db_info->db_addr, sizeof(info->db_addr)); + ACL_SAFE_STRNCPY(info->db_name, db_info->db_name, sizeof(info->db_name)); + ACL_SAFE_STRNCPY(info->db_user, db_info->db_user, sizeof(info->db_user)); + ACL_SAFE_STRNCPY(info->db_pass, db_info->db_pass, sizeof(info->db_pass)); + + info->db_max = db_info->db_max; + info->ping_inter = db_info->ping_inter; + info->timeout_inter = db_info->timeout_inter; +#endif + + memcpy(info, db_info, sizeof(ACL_DB_INFO)); + + db_pool->db_max = info->db_max; + db_pool->db_ready = 0; + db_pool->db_inuse = 0; + + return (db_pool); +} + +/*----------------------------------------------------------------------------*/ +void acl_dbpool_destroy(ACL_DB_POOL *db_pool) +{ + db_pool->destroy(db_pool); +} + +/*----------------------------------------------------------------------------*/ +ACL_DB_HANDLE *acl_dbpool_peek(ACL_DB_POOL *db_pool) +{ + return (db_pool->dbh_peek(db_pool)); +} + +/*----------------------------------------------------------------------------*/ +void acl_dbpool_check(ACL_DB_POOL *db_pool) +{ + db_pool->dbh_check(db_pool); +} + +/*----------------------------------------------------------------------------*/ +void acl_dbpool_release(ACL_DB_HANDLE *db_handle) +{ + ACL_DB_POOL *db_pool; + + db_pool = db_handle->parent; + +/* if ((db_pool->db_info.debug_flag & ACL_DB_DEBUG_MEM)) + acl_memory_stat(); +*/ + + db_pool->dbh_release(db_handle); +} + +/*----------------------------------------------------------------------------*/ +void *acl_dbpool_export(ACL_DB_HANDLE *db_handle) +{ + ACL_DB_POOL *db_pool; + + db_pool = db_handle->parent; + return (db_pool->dbh_export(db_handle)); +} + +/*----------------------------------------------------------------------------*/ +void acl_dbpool_close(ACL_DB_HANDLE *db_handle) +{ + ACL_DB_POOL *db_pool; + + db_pool = db_handle->parent; + db_pool->dbh_close(db_handle); +} +/*----------------------------------------------------------------------------*/ +void acl_dbpool_set_ping(ACL_DB_POOL *db_pool, int (*ping_fn)(ACL_DB_HANDLE*)) +{ + db_pool->dbh_ping = ping_fn; +} +/*----------------------------------------------------------------------------*/ + diff --git a/lib_acl/src/db/acl_dbsql.c b/lib_acl/src/db/acl_dbsql.c new file mode 100644 index 000000000..a3ddac78a --- /dev/null +++ b/lib_acl/src/db/acl_dbsql.c @@ -0,0 +1,104 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "db/acl_dbsql.h" +#include "stdlib/acl_stdlib.h" +#include "db/acl_dbsql.h" + +#endif + +ACL_SQL_RES *acl_dbsql_select(ACL_DB_HANDLE *handle, const char *sql, int *error) +{ + const char *myname = "acl_dbsql_select"; + + if (handle == NULL || sql == NULL || *sql == 0) + acl_msg_fatal("%s(%d): input invalid", myname, __LINE__); + + if (handle->sql_select == NULL) + acl_msg_fatal("%s(%d): sql_select null", myname, __LINE__); + + return (handle->sql_select(handle, sql, error)); +} + +void acl_dbsql_free_result(ACL_DB_HANDLE *handle, ACL_SQL_RES *res) +{ + const char *myname = "acl_dbsql_free_result"; + + if (handle == NULL || res == NULL) { + acl_msg_error("%s(%d): input invalid", myname, __LINE__); + return; + } + if (handle->free_result == NULL) + acl_msg_fatal("%s(%d): free_result null", myname, __LINE__); + handle->free_result(res); +} + +/* 用于有返回结果集的查询 */ + +int acl_dbsql_results(ACL_DB_HANDLE *handle, const char *sql, int *error, + int (*walk_fn)(const void** result_row, void *arg), void *arg) +{ + const char *myname = "acl_dbsql_results"; + int n, err; + + if (handle == NULL || sql == NULL || *sql == 0 || walk_fn == NULL) + acl_msg_fatal("%s(%d): input invalid", myname, __LINE__); + + if (handle->sql_results == NULL) + acl_msg_fatal("%s(%d): sql_results null", myname, __LINE__); + + n = handle->sql_results(handle, sql, &err, walk_fn, arg); + if (error) + *error = err; + + return (n); +} + +/* 用于仅查询一个结果的情况 */ + +int acl_dbsql_result(ACL_DB_HANDLE *handle, const char *sql, int *error, + int (*walk_fn)(const void** result_row, void *arg), void *arg) +{ + const char *myname = "acl_dbsql_result"; + int n, err; + + if (handle == NULL || sql == NULL || *sql == 0 || walk_fn == NULL) + acl_msg_fatal("%s(%d): input invalid", myname, __LINE__); + + if (handle->sql_results == NULL) + acl_msg_fatal("%s(%d): sql_result null", myname, __LINE__); + + n = handle->sql_result(handle, sql, &err, walk_fn, arg); + if (error) + *error = err; + + return (n); +} + +int acl_dbsql_update(ACL_DB_HANDLE *handle, const char *sql, int *error) +{ + const char *myname = "acl_dbsql_update"; + int n, err; + + if (handle == NULL || sql == NULL || *sql == 0) + acl_msg_fatal("%s(%d): input invalid", myname, __LINE__); + + if (handle->sql_update == NULL) + acl_msg_fatal("%s(%d): sql_update null", myname, __LINE__); + + n = handle->sql_update(handle, sql, &err); + if (error) + *error = err; + + return (n); +} + diff --git a/lib_acl/src/db/memdb/acl_mdb.c b/lib_acl/src/db/memdb/acl_mdb.c new file mode 100644 index 000000000..5299aeedf --- /dev/null +++ b/lib_acl/src/db/memdb/acl_mdb.c @@ -0,0 +1,260 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_msg.h" +#include "stdlib/acl_htable.h" +#include "stdlib/acl_mystring.h" + +#include "db/acl_mdb.h" + +#endif + +#include "struct.h" +#include "mdb_private.h" + +ACL_MDB *acl_mdb_create(const char *dbname, const char *dbtype) +{ + const char *myname = "acl_mdb_create"; + ACL_MDB *mdb; + + if (dbname == NULL || *dbname == 0) { + acl_msg_error("%s(%d): dbname invalid", myname, __LINE__); + return (NULL); + } + if (dbtype == NULL || *dbtype == 0) { + acl_msg_error("%s(%d): dbtype invalid", myname, __LINE__); + return (NULL); + } + + mdb = acl_mycalloc(1, sizeof(ACL_MDB)); + ACL_SAFE_STRNCPY(mdb->name, dbname, sizeof(mdb->name)); + ACL_SAFE_STRNCPY(mdb->type, dbtype, sizeof(mdb->type)); + mdb->tbls = acl_htable_create(10, 0); + return (mdb); +} + +static void free_tbl_fn(void *arg) +{ + ACL_MDT *mdt = (ACL_MDT*) arg; + acl_mdt_free(mdt); +} + +void acl_mdb_free(ACL_MDB *mdb) +{ + acl_htable_free(mdb->tbls, free_tbl_fn); + acl_myfree(mdb); +} + +ACL_MDT *acl_mdb_tbl_create(ACL_MDB *mdb, const char *tbl_name, + unsigned int tbl_flag, size_t init_capacity, + const char *key_labels[], unsigned int flags[]) +{ + const char *myname = "acl_mdb_tbl_create"; + ACL_MDT *mdt; + + if (mdb == NULL || tbl_name == NULL || *tbl_name == 0) { + acl_msg_error("%s(%d): input invalid", myname, __LINE__); + return (NULL); + } + + if (init_capacity < 128) + init_capacity = 128; + + mdt = acl_mdt_create(mdb->type, tbl_name, tbl_flag, + init_capacity, key_labels, flags); + + if (acl_htable_enter(mdb->tbls, tbl_name, (char *) mdt) == NULL) + acl_msg_fatal("%s(%d): acl_htable_enter error, tbl_name = %s", + myname, __LINE__, tbl_name); + + return (mdt); +} + +ACL_MDT_NOD *acl_mdb_add(ACL_MDB *mdb, const char *tbl_name, + void *data, unsigned int dlen, + const char *key_labels[], const char *keys[]) +{ + const char *myname = "acl_mdb_add"; + ACL_MDT *mdt; + ACL_MDT_NOD *node; + + if (tbl_name == NULL || *tbl_name == 0) { + acl_msg_error("%s(%d): tbl_name invalid", myname, __LINE__); + return (NULL); + } + if (data == NULL) { + acl_msg_error("%s(%d): data invalid", myname, __LINE__); + return (NULL); + } + + /* 从数据库中获得所需要的数据索引表 */ + mdt = (ACL_MDT *) acl_htable_find(mdb->tbls, tbl_name); + if (mdt == NULL) { + acl_msg_error("%s(%d): table no exist, tbl_name(%s)", + myname, __LINE__, tbl_name); + return (NULL); + } + + node = mdt->add(mdt, data, dlen, key_labels, keys); + + return (node); +} + +int acl_mdb_probe(ACL_MDB *mdb, const char *tbl_name, + const char *key_label, const char *key) +{ + const char *myname = "acl_mdb_probe"; + ACL_MDT *mdt; + + if (tbl_name == NULL || *tbl_name == 0) { + acl_msg_error("%s(%d): tbl_name invalid", myname, __LINE__); + return (0); + } + if (key_label == NULL || *key_label == 0) { + acl_msg_error("%s(%d): key_label invalid", myname, __LINE__); + return (0); + } + if (key == NULL || *key == 0) { + acl_msg_error("%s(%d): key invalid", myname, __LINE__); + return (0); + } + + mdt = (ACL_MDT *) acl_htable_find(mdb->tbls, tbl_name); + if (mdt == NULL) { + acl_msg_error("%s(%d): table no exist, tbl_name(%s)", + myname, __LINE__, tbl_name); + return (0); + } + + return (mdt->probe(mdt, key_label, key)); +} + +ACL_MDT_RES *acl_mdb_find(ACL_MDB *mdb, const char *tbl_name, + const char *key_label, const char *key, int from, int limit) +{ + const char *myname = "acl_mdb_find"; + ACL_MDT *mdt; + + if (tbl_name == NULL || *tbl_name == 0) { + acl_msg_error("%s(%d): tbl_name invalid", myname, __LINE__); + return (NULL); + } + if (key_label == NULL || *key_label == 0) { + acl_msg_error("%s(%d): key_label invalid", myname, __LINE__); + return (NULL); + } + if (key == NULL || *key == 0) { + acl_msg_error("%s(%d): key invalid", myname, __LINE__); + return (NULL); + } + + mdt = (ACL_MDT *) acl_htable_find(mdb->tbls, tbl_name); + if (mdt == NULL) { + acl_msg_error("%s(%d): table no exist, tbl_name(%s)", + myname, __LINE__, tbl_name); + return (NULL); + } + + return (mdt->get(mdt, key_label, key, from, limit)); +} + +ACL_MDT_RES *acl_mdb_list(ACL_MDB *mdb, const char *tbl_name, int from, int limit) +{ + const char *myname = "acl_mdb_list"; + ACL_MDT *mdt; + + if (tbl_name == NULL || *tbl_name == 0) { + acl_msg_error("%s(%d): tbl_name invalid", myname, __LINE__); + return (NULL); + } + + mdt = (ACL_MDT *) acl_htable_find(mdb->tbls, tbl_name); + if (mdt == NULL) { + acl_msg_error("%s(%d): table no exist, tbl_name(%s)", + myname, __LINE__, tbl_name); + return (NULL); + } + + return (mdt->list(mdt, from, limit)); +} + +int acl_mdb_del(ACL_MDB *mdb, const char *tbl_name, + const char *key_label, const char *key, + void (*onfree_fn)(void*, unsigned int)) +{ + const char *myname = "acl_mdb_del"; + ACL_MDT *mdt; + + if (tbl_name == NULL || *tbl_name == 0) { + acl_msg_error("%s(%d): tbl_name invalid", myname, __LINE__); + return (-1); + } + if (key_label == NULL || *key_label == 0) { + acl_msg_error("%s(%d): key_label invalid", myname, __LINE__); + return (-1); + } + if (key == NULL || *key == 0) { + acl_msg_error("%s(%d): key invalid", myname, __LINE__); + return (-1); + } + + mdt = (ACL_MDT *) acl_htable_find(mdb->tbls, tbl_name); + if (mdt == NULL) { + acl_msg_error("%s(%d): table no exist, tbl_name(%s)", + myname, __LINE__, tbl_name); + return (-1); + } + + return (mdt->del(mdt, key_label, key, onfree_fn)); +} + +int acl_mdb_walk(ACL_MDB *mdb, const char *tbl_name, + int (*walk_fn)(const void*, unsigned int), int from, int limit) +{ + const char *myname = "acl_mdb_walk"; + ACL_MDT *mdt; + + if (tbl_name == NULL || *tbl_name == 0) { + acl_msg_error("%s(%d): tbl_name invalid", myname, __LINE__); + return (-1); + } + + mdt = (ACL_MDT *) acl_htable_find(mdb->tbls, tbl_name); + if (mdt == NULL) { + acl_msg_error("%s(%d): table no exist, tbl_name(%s)", + myname, __LINE__, tbl_name); + return (-1); + } + + return (mdt->walk(mdt, walk_fn, from, limit)); +} + +int acl_mdb_cnt(ACL_MDB *mdb, const char *tbl_name) +{ + const char *myname = "acl_mdb_cnt"; + ACL_MDT *mdt; + + if (tbl_name == NULL || *tbl_name == 0) { + acl_msg_error("%s(%d): tbl_name invalid", myname, __LINE__); + return (-1); + } + + mdt = (ACL_MDT *) acl_htable_find(mdb->tbls, tbl_name); + if (mdt == NULL) { + acl_msg_error("%s(%d): table no exist, tbl_name(%s)", + myname, __LINE__, tbl_name); + return (-1); + } + + return (acl_mdt_cnt(mdt)); +} diff --git a/lib_acl/src/db/memdb/acl_mdt.c b/lib_acl/src/db/memdb/acl_mdt.c new file mode 100644 index 000000000..06419c0c1 --- /dev/null +++ b/lib_acl/src/db/memdb/acl_mdt.c @@ -0,0 +1,670 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_msg.h" +#include "stdlib/acl_mystring.h" + +#include "db/acl_mdb.h" + +#endif + +#include "struct.h" +#include "mdb_private.h" + +/*---------------------------------------------------------------------------*/ + +/** + * 从数据表中查询某个索引表项 + */ +static ACL_MDT_IDX *mdt_idx(const ACL_MDT *mdt, const char *key_label) +{ + RING *iter; + ACL_MDT_IDX *idx; + + FOREACH_RING_ENTRY(iter, &mdt->idx_head) { + idx = RING_TO_APPL(iter, ACL_MDT_IDX, mdt_entry); + if (strcasecmp(idx->name, key_label) == 0) + return (idx); + } + + return (NULL); +} + +/* 创建该索引表里的各个索引字段 */ + +static void mdt_idx_create(ACL_MDT *mdt, size_t init_capacity, + const char *key_labels[], unsigned int idx_flags[]) +{ + ACL_MDT_IDX *idx; + const char *ptr; + int i = 0; + + while ((ptr = key_labels[i]) != NULL) { + idx = mdt->idx_create(mdt, init_capacity, ptr, idx_flags[i]); + idx->mdt = mdt; + ring_prepend(&mdt->idx_head, &idx->mdt_entry); + i++; + } +} + +/* 销毁所有的索引 */ + +static void mdt_idx_free(ACL_MDT *mdt) +{ + RING *iter, *iter_tmp; + ACL_MDT_IDX *idx; + + for (iter = ring_succ(&mdt->idx_head); iter != &mdt->idx_head;) { + iter_tmp = ring_succ(iter); + idx = RING_TO_APPL(iter, ACL_MDT_IDX, mdt_entry); + mdt->idx_free(idx); + iter = iter_tmp; + } +} + +/** + * 释放某个数据结点,同时根据用户的释放回调来释放用户的数据 + * @param mdt {ACL_MDT*} 数据表句柄 + * @param node {ACL_MDT_NODE*} 某个数据结点指针 + * @param onfree_fn 在释放某个数据结点前调用该函数 + */ +static void mdt_node_free(ACL_MDT *mdt, ACL_MDT_NOD *node, + void (*onfree_fn)(void*, unsigned int)) +{ + if (onfree_fn && node->data) + onfree_fn(node->data, node->dlen); + + ring_detach(&node->mdt_entry); + if ((mdt->tbl_flag & ACL_MDT_FLAG_DMR) == 0 && node->data) + acl_myfree(node->data); + if (mdt->nod_slice) + acl_slice_free2(mdt->nod_slice, node); + else + acl_myfree(node); + mdt->node_cnt--; +} + +/** + * 分配一个新的数据项结点 + * @param data {void*} 用户的动态数据指针 + * @return {ACL_MDT_NOD*} 产生的新的数据结点 + */ +static ACL_MDT_NOD *mdt_node_new(ACL_MDT *mdt, void *data, unsigned int dlen) +{ + ACL_MDT_NOD *node; + void *pdata; + + if (mdt->nod_slice) + node = (ACL_MDT_NOD*) acl_slice_alloc(mdt->nod_slice); + else + node = (ACL_MDT_NOD*) acl_mymalloc(sizeof(ACL_MDT_NOD)); + + if ((mdt->tbl_flag & ACL_MDT_FLAG_DMR) == 0) { + pdata = acl_mymalloc(dlen); + memcpy(pdata, data, dlen); + node->data = pdata; + } else { + node->data = data; + } + node->dlen = dlen; + node->nrefer = 0; + ring_init(&node->ref_head); + + /* 将数据结点置入表的数据结点双向链中 */ + ring_prepend(&mdt->nod_head, &node->mdt_entry); + mdt->node_cnt++; + return (node); +} + +/** + * 根据键 key 创建一个新的结果集合对象 + */ +static ACL_MDT_REC *mdt_rec_new(ACL_MDT *mdt) +{ + ACL_MDT_REC *rec; + + if (mdt->rec_slice) + rec = (ACL_MDT_REC*) acl_slice_calloc(mdt->rec_slice); + else + rec = (ACL_MDT_REC*) acl_mycalloc(1, sizeof(ACL_MDT_REC)); + + ring_init(&rec->ref_head); + rec->nrefer = 0; + + return (rec); +} + +/** + * 释放一个结果集对象 + * @param rec {ACL_MDT_REC*} + */ +static void mdt_rec_free(ACL_MDT *mdt, ACL_MDT_REC *rec) +{ + if (mdt->rec_slice) + acl_slice_free2(mdt->rec_slice, rec); + else + acl_myfree(rec); +} + +/** + * 释放一个引用结点,当该引用结点所引用的数据结点或结果集合的各自引用 + * 计数为0时便会自动释放数据结点或结果集合 + * @param ref {ACL_MDT_REF*} 某个数据结点中与某索引键相对应的引用结点 + */ +static void mdt_ref_del(ACL_MDT *mdt, ACL_MDT_REF *ref) +{ + ring_detach(&ref->nod_entry); + ring_detach(&ref->rec_entry); + ref->node->nrefer--; + ref->rec->nrefer--; + if (mdt->ref_slice) + acl_slice_free2(mdt->ref_slice, ref); + else + acl_myfree(ref); +} + +/** + * 创建一个新的引用结点并将其 与 node, rec 进行关联 + * @param ref {ACL_MDT_REF*} + * @parma node {ACL_MDT_NOD*} + * @param rec {ACL_MDT_REC*} + */ +static void mdt_ref_add(ACL_MDT *mdt, ACL_MDT_NOD *node, ACL_MDT_REC *rec) +{ + ACL_MDT_REF *ref; + + if (mdt->ref_slice) + ref = (ACL_MDT_REF *) acl_slice_calloc(mdt->ref_slice); + else + ref = (ACL_MDT_REF *) acl_mycalloc(1, sizeof(ACL_MDT_REF)); + + /* 将引用结点与数据结点进行关联 */ + ref->node = node; + node->nrefer++; + /* 将引用结点置入数据结点的引用结点集合中 */ + ring_prepend(&node->ref_head, &ref->nod_entry); + + /* 将引用结点与结果集结点进行关联 */ + ref->rec = rec; + rec->nrefer++; /* 将引用计数加1 */ + /* 将引用结点置入结果集合的引用结点集合中 */ + ring_prepend(&rec->ref_head, &ref->rec_entry); +} + +/** + * 向表中添加数据,同时添加索引项 + * @param mdt {ACL_MDT*} 表 + * @param data {void*} 数据指针 + * @param dlen {unsigned int} data 数据大小 + * @param key_lables {const char*[]} 索引关键字段标识 + * @param keys {const char*[]} 索引关键字 + * @return {ACL_MDT_NOD*} 新创建的表结点 + */ +static ACL_MDT_NOD *mdt_add(ACL_MDT *mdt, void *data, unsigned int dlen, + const char *key_labels[], const char *keys[]) +{ + const char *myname = "mdt_add"; + ACL_MDT_IDX *idx; + ACL_MDT_NOD *node; + ACL_MDT_REC *rec; + int i; + + /* 先进行各个索引字段的约束性检查 */ + + node = mdt_node_new(mdt, data, dlen); /* 建立数据结点项 */ + + i = 0; + while (key_labels[i] != NULL && keys[i] != NULL) { + idx = mdt_idx(mdt, key_labels[i]); + if (idx == NULL) { + acl_msg_error("%s(%d): key_label(%s) no exist in table(%s)", + myname, __LINE__, key_labels[i], mdt->name); + return (NULL); + } + /* 从表索引中获得对应于键的索引记录结果集 */ + rec = mdt->idx_get(idx, keys[i]); + if (rec == NULL) { + /* 创建新的记录结果集 */ + rec = mdt_rec_new(mdt); + /* 引用其所对应的索引表 */ + rec->idx = idx; + /* 在表索引中增加新的索引数据项 */ + mdt->idx_add(idx, keys[i], rec); + } else if (idx->flag & ACL_MDT_FLAG_UNI) { + acl_msg_warn("%s(%d): duplex key, key_label(%s), key(%s)", + myname, __LINE__, key_labels[i], keys[i]); + mdt_node_free(mdt, node, NULL); + return (NULL); + } + + /* 创建新的引用结点并将与其数据结点及结果集合对象进行关联 */ + mdt_ref_add(mdt, node, rec); + i++; + } + return (node); +} + +/** + * 探测某个键在表索引中是否存在 + * @param mdt {ACL_MDT*} + * @param key_label {const char*} + * @param key {const char*} + * @return {int} 0: 不存在; 1: 存在 + */ +static int mdt_probe(ACL_MDT *mdt, const char *key_label, const char *key) +{ + const char *myname = "mdt_probe"; + ACL_MDT_REC *rec; + ACL_MDT_IDX *idx; + + idx = mdt_idx(mdt, key_label); + if (idx == NULL) { + acl_msg_warn("%s: key_lable(%s) no exist in %s", + myname, key_label, mdt->name); + return (0); + } + + rec = mdt->idx_get(idx, key); + if (rec == NULL) + return (0); + return (1); +} + +/** + * 在表索引中根据某个索引键值查询结果集 + * @param mdt {ACL_MDT*} + * @param key_label {const char*} + * @param key {const char*} + * @param from {int} 起始位置 + * @param limit {int} 个数限制 + * @return {ACL_MDT_RES*} 查询结果集, NULL: 结果为空, != NULL: 结果集非空 + */ +static ACL_MDT_RES *mdt_get(ACL_MDT *mdt, const char *key_label, + const char *key, int from, int limit) +{ + const char *myname = "mdt_get"; + ACL_MDT_RES *res; + ACL_MDT_REC *rec; + ACL_MDT_REF *ref; + ACL_MDT_IDX *idx; + RING *ref_iter; + void *data; + int i, n; + + idx = mdt_idx(mdt, key_label); + if (idx == NULL) { + acl_msg_warn("%s: key_lable(%s) no exist in %s", + myname, key_label, mdt->name); + return (NULL); + } + + rec = mdt->idx_get(idx, key); + if (rec == NULL) + return (NULL); + + res = (ACL_MDT_RES*) acl_mycalloc(1, sizeof(ACL_MDT_RES)); + res->a = acl_array_create(100); + res->ipos = 0; + + i = 0; + n = 0; + FOREACH_RING_FORWARD(ref_iter, &rec->ref_head) { + if (from >= 0 && i++ < from) + continue; + ref = RING_TO_APPL(ref_iter, ACL_MDT_REF, rec_entry); + data = acl_mymalloc(ref->node->dlen); + memcpy(data, ref->node->data, ref->node->dlen); + if (acl_array_append(res->a, data) < 0) + acl_msg_fatal("%s(%d): add array error(%s)", + myname, __LINE__, acl_last_serror()); + if (limit > 0 && ++n >= limit) + break; + } + if (acl_array_size(res->a) == 0) { + acl_array_destroy(res->a, NULL); + acl_myfree(res); + return (NULL); + } + return (res); +} + +/** + * 根据索引值从表中删除对应于该索引值的结果集 + * @param mdt {ACL_MDT*} + * @param key_label {const char*} + * @param key {const char*} + * @param onfree_fn {void (*)(void*, unsigned int} 回调函数 + * @return {int} 被删除的结果集中结点的个数. -1: 出错, >= 0: ok + */ +static int mdt_del(ACL_MDT *mdt, const char *key_label, + const char *key, void (*onfree_fn)(void*, unsigned int)) +{ + const char *myname = "mdt_del"; + ACL_MDT_REC *rec, *rec2; + ACL_MDT_REF *ref, *ref2; + ACL_MDT_NOD *node; + RING *iter, *iter2; + ACL_MDT_IDX *idx; + int n = 0; + + idx = mdt_idx(mdt, key_label); + if (idx == NULL) { + acl_msg_warn("%s: key_label(%s) not exist in %s", + myname, key_label, mdt->name); + return (-1); + } + + /* 查出与该字段的键相关的记录结果集合 */ + rec = mdt->idx_get(idx, key); + if (rec == NULL) + return (0); + + /* 遍历该结果集合中的所有引用结点,找出其所属的数据结点 */ + for (iter = ring_succ(&rec->ref_head); iter && rec->nrefer > 0;) { + + ref = RING_TO_APPL(iter, ACL_MDT_REF, rec_entry); + iter = ring_succ(iter); + + /* 遍历该属于该数据结点的所有引用结点, 并删除这些引用结点 */ + node = ref->node; /* 数据结点 */ + + /* 遍历该数据结点的所有索引引用结点 */ + for (iter2 = ring_succ(&node->ref_head); + iter2 != NULL && node->nrefer > 0;) { + + ref2 = RING_TO_APPL(iter2, ACL_MDT_REF, nod_entry); + rec2 = ref2->rec; + iter2 = ring_succ(iter2); + + mdt_ref_del(mdt, ref2); /* 删除引用 */ + + /* 在最外层循环未完成之前,需要防止 rec 被提前释放! */ + if (rec2->nrefer == 0 && rec2 != rec) { + mdt->idx_del(rec2->idx, rec2->key); + mdt_rec_free(mdt, rec2); + } + } + + if (node->nrefer != 0) + acl_msg_fatal("%s(%d): node->nrefer(%d) != 0," + " tbl_name(%s), key_label(%s), key(%s)", + myname, __LINE__, node->nrefer, + mdt->name, key_label, key); + mdt_node_free(mdt, node, onfree_fn); /* 删除数据结点 */ + + n++; + } + + if (rec->nrefer != 0) + acl_msg_fatal("%s(%d): rec->nrefer(%d) != 0," + " tbl_name(%s), key_label(%s), key(%s)", + myname, __LINE__, rec->nrefer, + mdt->name, key_label, key); + /* 从当前索引中删除 */ + mdt->idx_del(rec->idx, rec->key); + mdt_rec_free(mdt, rec); + + /* 返回所删除的引用结点数 */ + return (n); +} + +/** + * 从表中列出一些结果集 + * @param mdt {ACL_MDT*} + * @param from {int} 起始位置 + * @param limit {int} 个数限制 + * @return {ACL_MDT_RES*} 结果集, NULL: 空, != NULL: 非空 + */ +static ACL_MDT_RES *mdt_list(ACL_MDT *mdt, int from, int limit) +{ + const char *myname = "mdt_list"; + ACL_MDT_RES *res; + ACL_MDT_NOD *node; + RING *nod_iter; + void *data; + int n = 0, i = 0; + + if (mdt == NULL) + return (NULL); + + res = (ACL_MDT_RES*) acl_mycalloc(1, sizeof(ACL_MDT_RES)); + res->a = acl_array_create(limit > 0 ? limit : 100); + res->ipos = 0; + + FOREACH_RING_FORWARD(nod_iter, &mdt->nod_head) { + if (from >= 0 && i++ < from) + continue; + n++; + node = RING_TO_APPL(nod_iter, ACL_MDT_NOD, mdt_entry); + data = acl_mymalloc(node->dlen); + memcpy(data, node->data, node->dlen); + if (acl_array_append(res->a, data) < 0) { + acl_msg_fatal("%s(%d): add array", myname, __LINE__); + break; + } + if (limit > 0 && n >= limit) + break; + } + + return (res); +} + +/** + * 遍历表中的数据对象 + * @param mdt {ACL_MDT*} 表 + * @param walk_fn {int (*)(const void*, unsigned int)} 遍历表对象的回调函数 + * @param from {int} 开始遍历表的起始位置 + * @param limit {int} 遍历表对象的最大个数 + * @return {int} 已经遍历过的表对象的具数 + */ +static int mdt_walk(ACL_MDT *mdt, int (*walk_fn)(const void*, unsigned int), + int from, int limit) +{ + ACL_MDT_NOD *node; + RING *iter; + int n = 0, i = 0; + + if (walk_fn == NULL || mdt == NULL) + return (0); + + FOREACH_RING_ENTRY(iter, &mdt->nod_head) { + if (from >= 0 && i++ < from) + continue; + node = RING_TO_APPL(iter, ACL_MDT_NOD, mdt_entry); + n++; + if (walk_fn(node->data, node->dlen)) + break; + if (limit > 0 && n >= limit) + break; + } + + return (n); +} + +/* 删除所有数据结点 */ + +static void mdt_nodes_free(ACL_MDT *mdt) +{ + ACL_MDT_NOD *node; + ACL_MDT_REC *rec; + ACL_MDT_REF *ref; + RING *iter, *tmp, *iter2; + + for (iter = ring_succ(&mdt->nod_head); iter != &mdt->nod_head; ) { + tmp = ring_succ(iter); + node = RING_TO_APPL(iter, ACL_MDT_NOD, mdt_entry); + for (iter2 = ring_succ(&node->ref_head); iter2 != &node->ref_head;) { + ref = RING_TO_APPL(iter2, ACL_MDT_REF, nod_entry); + rec = ref->rec; + iter2 = ring_succ(iter2); + mdt_ref_del(mdt, ref); + if (rec->nrefer == 0) { + mdt_rec_free(mdt, rec); + } + } + mdt_node_free(mdt, node, NULL); + iter = tmp; + } +} + +/*---------------------------------------------------------------------------*/ + +ACL_MDT *acl_mdt_create(const char *dbtype, const char *tbl_name, + unsigned int tbl_flag, size_t init_capacity, + const char *key_labels[], unsigned int idx_flags[]) +{ + const char *myname = "acl_mdt_create"; + ACL_MDT *mdt; + unsigned int rtgc_flag = 0; + + if (strcasecmp(dbtype, "hash") == 0) { + mdt = acl_mdt_hash_create(); + } else if (strcasecmp(dbtype, "binhash") == 0) { + mdt = acl_mdt_binhash_create(); + } else if (strcasecmp(dbtype, "avl") == 0) { + mdt = acl_mdt_avl_create(); + } else { + acl_msg_error("%s(%d): dbtype(%s)", myname, __LINE__, dbtype); + return (NULL); + } + + mdt->name = acl_mystrdup(tbl_name); + mdt->node_cnt = 0; + mdt->tbl_flag = tbl_flag; + + ring_init(&mdt->nod_head); + ring_init(&mdt->idx_head); + mdt_idx_create(mdt, init_capacity, key_labels, idx_flags); + + mdt->add = mdt_add; + mdt->get = mdt_get; + mdt->del = mdt_del; + mdt->probe = mdt_probe; + mdt->list = mdt_list; + mdt->walk = mdt_walk; + + if ((tbl_flag & ACL_MDT_FLAG_SLICE_RTGC_OFF)) + rtgc_flag = ACL_MDT_FLAG_SLICE_RTGC_OFF; + + if ((tbl_flag & ACL_MDT_FLAG_SLICE1)) { + mdt->nod_slice = acl_slice_create("nod_slice", 0, + sizeof(ACL_MDT_NOD), ACL_SLICE_FLAG_GC1 | rtgc_flag); + mdt->rec_slice = acl_slice_create("rec_slice", 0, + sizeof(ACL_MDT_REC), ACL_SLICE_FLAG_GC1 | rtgc_flag); + mdt->ref_slice = acl_slice_create("ref_slice", 0, + sizeof(ACL_MDT_REF), ACL_SLICE_FLAG_GC1 | rtgc_flag); + } else if ((tbl_flag & ACL_MDT_FLAG_SLICE2)) { + mdt->nod_slice = acl_slice_create("nod_slice", 0, + sizeof(ACL_MDT_NOD), ACL_SLICE_FLAG_GC2 | rtgc_flag); + mdt->rec_slice = acl_slice_create("rec_slice", 0, + sizeof(ACL_MDT_REC), ACL_SLICE_FLAG_GC2 | rtgc_flag); + mdt->ref_slice = acl_slice_create("ref_slice", 0, + sizeof(ACL_MDT_REF), ACL_SLICE_FLAG_GC2 | rtgc_flag); + } else if ((tbl_flag & ACL_MDT_FLAG_SLICE3)) { + mdt->nod_slice = acl_slice_create("nod_slice", 0, + sizeof(ACL_MDT_NOD), ACL_SLICE_FLAG_GC3 | rtgc_flag); + mdt->rec_slice = acl_slice_create("rec_slice", 0, + sizeof(ACL_MDT_REC), ACL_SLICE_FLAG_GC3 | rtgc_flag); + mdt->ref_slice = acl_slice_create("ref_slice", 0, + sizeof(ACL_MDT_REF), ACL_SLICE_FLAG_GC3 | rtgc_flag); + } + return (mdt); +} + +void acl_mdt_free(ACL_MDT *mdt) +{ + acl_myfree(mdt->name); + mdt_idx_free(mdt); + mdt_nodes_free(mdt); + if (mdt->nod_slice) + acl_slice_destroy(mdt->nod_slice); + if (mdt->rec_slice) + acl_slice_destroy(mdt->rec_slice); + if (mdt->ref_slice) + acl_slice_destroy(mdt->ref_slice); + mdt->tbl_free(mdt); +} + +ACL_MDT_NOD *acl_mdt_add(ACL_MDT *mdt, void *data, unsigned int dlen, + const char *key_labels[], const char *keys[]) +{ + return (mdt->add(mdt, data, dlen, key_labels, keys)); +} + +ACL_MDT_RES *acl_mdt_find(ACL_MDT *mdt, const char *key_label, + const char *key, int from, int limit) +{ + return (mdt->get(mdt, key_label, key, from, limit)); +} + +int acl_mdt_probe(ACL_MDT *mdt, const char *key_label, const char *key) +{ + return (mdt->probe(mdt, key_label, key)); +} + +ACL_MDT_RES *acl_mdt_list(ACL_MDT *mdt, int from, int limit) +{ + return (mdt->list(mdt, from, limit)); +} + +int acl_mdt_delete(ACL_MDT *mdt, const char *key_label, + const char *key, void (*onfree_fn)(void*, unsigned int)) +{ + return (mdt->del(mdt, key_label, key, onfree_fn)); +} + +int acl_mdt_walk(ACL_MDT *mdt, int (*walk_fn)(const void*, unsigned int), + int from, int limit) +{ + return (mdt->walk(mdt, walk_fn, from, limit)); +} + +const void *acl_mdt_fetch_row(ACL_MDT_RES *res) +{ + const char *myname = "acl_mdt_fetch_row"; + void *ptr; + int n; + + if (res == NULL || res->a == NULL || res->ipos < 0) { + acl_msg_error("%s(%d): input error", myname, __LINE__); + return (NULL); + } + + n = acl_array_size(res->a); + if (res->ipos >= n) + return (NULL); + ptr = (void *) acl_array_index(res->a, res->ipos++); + return (ptr); +} + +int acl_mdt_row_count(ACL_MDT_RES *res) +{ + if (res == NULL || res->a == NULL || res->ipos < 0) + return (0); + return (acl_array_size(res->a)); +} + +void acl_mdt_res_free(ACL_MDT_RES *res) +{ + if (res->a) + acl_array_destroy(res->a, acl_myfree_fn); + acl_myfree(res); +} + +int acl_mdt_cnt(ACL_MDT *mdt) +{ + if (mdt == NULL) + return (0); + + return (mdt->node_cnt); +} diff --git a/lib_acl/src/db/memdb/acl_mdt_avl.c b/lib_acl/src/db/memdb/acl_mdt_avl.c new file mode 100644 index 000000000..1c1572fd3 --- /dev/null +++ b/lib_acl/src/db/memdb/acl_mdt_avl.c @@ -0,0 +1,209 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_msg.h" +#include "thread/acl_thread.h" +#include "stdlib/acl_vstring.h" +#include "stdlib/acl_mystring.h" +#include "stdlib/avl.h" + +#endif + +#include "define.h" +#include "struct.h" +#include "mdb_private.h" + +#ifdef PACK_STRUCT +#pragma pack(4) +#endif +typedef struct { + union { + char *key; + const char *c_key; + } key; + ACL_MDT_REC *rec; + avl_node_t node; +} TREE_NODE; +#ifdef PACK_STRUCT +#pragma pack(0) +#endif + +/** + * AVL 用的比较回调函数 + */ +static int cmp_fn(const void *v1, const void *v2) +{ + const TREE_NODE *n1 = (const TREE_NODE*) v1; + const TREE_NODE *n2 = (const TREE_NODE*) v2; + int ret = strcmp(n1->key.c_key, n2->key.c_key); + + if (ret < 0) + return (-1); + else if (ret > 0) + return (1); + else + return (0); +} + +/** + * 创建索引 + */ +static ACL_MDT_IDX *mdt_idx_create(ACL_MDT *mdt, size_t init_capacity acl_unused, + const char *name, unsigned int flag) +{ + ACL_MDT_IDX_AVL *idx; +#ifdef _LP64 + unsigned int slice_align = ACL_SLICE_FLAG_LP64_ALIGN; +#else + unsigned int slice_align = 0; +#endif + unsigned int rtgc_off = 0; + + idx = (ACL_MDT_IDX_AVL*) acl_mycalloc(1, sizeof(ACL_MDT_IDX_AVL)); + avl_create(&idx->avl, cmp_fn, sizeof(TREE_NODE), offsetof(TREE_NODE, node)); + + if ((mdt->tbl_flag & ACL_MDT_FLAG_SLICE_RTGC_OFF)) + rtgc_off = 1; + + if ((mdt->tbl_flag & ACL_MDT_FLAG_SLICE1)) + idx->slice = acl_slice_create("ACL_MDT_IDX_AVL->slice", 0, + sizeof(TREE_NODE), ACL_SLICE_FLAG_GC1 | slice_align | rtgc_off); + else if ((mdt->tbl_flag & ACL_MDT_FLAG_SLICE2)) + idx->slice = acl_slice_create("ACL_MDT_IDX_AVL->slice", 0, + sizeof(TREE_NODE), ACL_SLICE_FLAG_GC2 | slice_align | rtgc_off); + else if ((mdt->tbl_flag & ACL_MDT_FLAG_SLICE3)) + idx->slice = acl_slice_create("ACL_MDT_IDX_AVL->slice", 0, + sizeof(TREE_NODE), ACL_SLICE_FLAG_GC3 | slice_align | rtgc_off); + + idx->idx.name = acl_mystrdup(name); + idx->idx.flag = flag; + return ((ACL_MDT_IDX*) idx); +} + +static void mdt_idx_free(ACL_MDT_IDX *idx) +{ + ACL_MDT_IDX_AVL *idx_avl = (ACL_MDT_IDX_AVL*) idx; + TREE_NODE *pnode; + + while (1) { + pnode = (TREE_NODE*) avl_first(&idx_avl->avl); + if (pnode == NULL) + break; + + avl_remove(&idx_avl->avl, pnode); + if (!(idx->flag & ACL_MDT_FLAG_KMR)) + acl_myfree(pnode->key.key); + + if (idx_avl->slice) + acl_slice_free2(idx_avl->slice, pnode); + else + acl_myfree(pnode); + } + + avl_destroy(&idx_avl->avl); + acl_myfree(idx->name); + if (idx_avl->slice) + acl_slice_destroy(idx_avl->slice); + acl_myfree(idx_avl); +} + +/** + * 向一个表索引中添加新的字段 + * @param idx {ACL_MDT_IDX*} 表索引 + * @param key {const char*} 数据表索引字段值 + * @param rec {ACL_MDT_REC*} + * @return {ACL_HTABLE_INFO*} + */ +static void mdt_idx_add(ACL_MDT_IDX *idx, const char *key, ACL_MDT_REC *rec) +{ + ACL_MDT_IDX_AVL *idx_avl = (ACL_MDT_IDX_AVL*) idx; + TREE_NODE *pnode; + + if (idx_avl->slice) + pnode = (TREE_NODE*) acl_slice_alloc(idx_avl->slice); + else + pnode = (TREE_NODE*) acl_mymalloc(sizeof(TREE_NODE)); + if (idx->flag & ACL_MDT_FLAG_KMR) + pnode->key.c_key = key; + else + pnode->key.key = acl_mystrdup(key); + + pnode->rec = rec; + avl_add(&idx_avl->avl, pnode); + rec->key = pnode->key.c_key; +} + +/** + * 从数据表的索引中查询对应某个索引键值的结果集 + * @param idx {ACL_MDT_IDX*} 表索引 + * @param key {const char*} 数据表索引字段值 + * @return {ACL_MDT_REC*} 对应某个索引字段值的结果集合 + */ +static ACL_MDT_REC *mdt_idx_get(ACL_MDT_IDX *idx, const char *key) +{ + ACL_MDT_IDX_AVL *idx_avl = (ACL_MDT_IDX_AVL*) idx; + TREE_NODE node, *pnode; + + node.key.c_key = key; + pnode = (TREE_NODE*) avl_find(&idx_avl->avl, &node, NULL); + return (pnode ? pnode->rec : NULL); +} + +/** + * 从一个表索引中删除该索引 + * @param idx {ACL_MDT_IDX*} 表索引 + * @param rec {ACL_MDT_REC*} 索引表中对应某个键的结果集对象 + * @param key_value {const char*} 数据结点的引用结点的引用键值 + */ +static void mdt_idx_del(ACL_MDT_IDX *idx, const char *key) +{ + const char *myname = "mdt_idx_del"; + ACL_MDT_IDX_AVL *idx_avl = (ACL_MDT_IDX_AVL*) idx; + TREE_NODE node, *pnode; + + node.key.c_key = key; + pnode = (TREE_NODE*) avl_find(&idx_avl->avl, &node, NULL); + if (pnode == NULL) + acl_msg_fatal("%s: key(%s) not exist", myname, key); + avl_remove(&idx_avl->avl, pnode); + if (!(idx->flag & ACL_MDT_FLAG_KMR)) + acl_myfree(pnode->key.key); + if (idx_avl->slice) + acl_slice_free2(idx_avl->slice, pnode); + else + acl_myfree(pnode); +} + +/** + * 释放平衡二叉树模式的数据表 + */ +static void mdt_avl_free(ACL_MDT *mdt) +{ + ACL_MDT_AVL *mdt_avl = (ACL_MDT_AVL*) mdt; + + acl_myfree(mdt_avl); +} + +ACL_MDT *acl_mdt_avl_create() +{ + ACL_MDT_AVL *mdt; + + mdt = (ACL_MDT_AVL *) acl_mycalloc(1, sizeof(ACL_MDT_AVL)); + mdt->mdt.tbl_free = mdt_avl_free; + mdt->mdt.idx_create = mdt_idx_create; + mdt->mdt.idx_free = mdt_idx_free; + mdt->mdt.idx_add = mdt_idx_add; + mdt->mdt.idx_get = mdt_idx_get; + mdt->mdt.idx_del = mdt_idx_del; + return ((ACL_MDT*) mdt); +} diff --git a/lib_acl/src/db/memdb/acl_mdt_binhash.c b/lib_acl/src/db/memdb/acl_mdt_binhash.c new file mode 100644 index 000000000..e125224c9 --- /dev/null +++ b/lib_acl/src/db/memdb/acl_mdt_binhash.c @@ -0,0 +1,136 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_msg.h" +#include "stdlib/acl_mystring.h" + +#endif + +#include "struct.h" +#include "mdb_private.h" + +/** + * 创建索引 + */ +static ACL_MDT_IDX *mdt_idx_create(ACL_MDT *mdt, size_t init_capacity, + const char *name, unsigned int flag) +{ + ACL_MDT_IDX_BHASH *idx; + unsigned int flag2 = 0; + + if (init_capacity < 128) + init_capacity = 128; + idx = (ACL_MDT_IDX_BHASH*) acl_mycalloc(1, sizeof(ACL_MDT_IDX_BHASH)); + + if ((mdt->tbl_flag & ACL_MDT_FLAG_SLICE1)) + flag2 |= ACL_BINHASH_FLAG_SLICE1; + else if ((mdt->tbl_flag & ACL_MDT_FLAG_SLICE2)) + flag2 |= ACL_BINHASH_FLAG_SLICE2; + else if ((mdt->tbl_flag & ACL_MDT_FLAG_SLICE3)) + flag2 |= ACL_BINHASH_FLAG_SLICE3; + + if ((mdt->tbl_flag & ACL_MDT_FLAG_SLICE_RTGC_OFF)) + flag2 |= ACL_BINHASH_FLAG_SLICE_RTGC_OFF; + if ((flag & ACL_MDT_FLAG_KMR)) + flag2 |= ACL_BINHASH_FLAG_KEY_REUSE; + + idx->table = acl_binhash_create(init_capacity, flag2); + idx->idx.name = acl_mystrdup(name); + idx->idx.flag = flag; + return ((ACL_MDT_IDX*) idx); +} + +static void mdt_idx_free(ACL_MDT_IDX *idx) +{ + ACL_MDT_IDX_BHASH *idx_bhash = (ACL_MDT_IDX_BHASH*) idx; + + acl_binhash_free(idx_bhash->table, NULL); + acl_myfree(idx->name); + acl_myfree(idx_bhash); +} + + +/** + * 向一个表索引中添加新的字段 + * @param idx {ACL_MDT_IDX*} 表索引 + * @param key {const char*} 数据表索引字段值 + * @param rec {ACL_MDT_REC*} + * @return {ACL_HTABLE_INFO*} + */ +static void mdt_idx_add(ACL_MDT_IDX *idx, const char *key, ACL_MDT_REC *rec) +{ + const char *myname = "mdt_idx_add"; + ACL_MDT_IDX_BHASH *idx_bhash = (ACL_MDT_IDX_BHASH*) idx; + ACL_BINHASH_INFO *info; + + info = acl_binhash_enter(idx_bhash->table, key, strlen(key) + 1, (char*) rec); + if (info == NULL) + acl_msg_error("%s(%d): binhash_enter error, value(%s)", + myname, __LINE__, key); + else + rec->key = info->key.c_key; +} + +/** + * 从数据表的索引中查询对应某个索引键值的结果集 + * @param idx {ACL_MDT_IDX*} 表索引 + * @param key {const char*} 数据表索引字段值 + * @return {ACL_MDT_REC*} 对应某个索引字段值的结果集合 + */ +static ACL_MDT_REC *mdt_idx_get(ACL_MDT_IDX *idx, const char *key) +{ + ACL_MDT_IDX_BHASH *idx_bhash = (ACL_MDT_IDX_BHASH*) idx; + ACL_MDT_REC *rec; + + rec = (ACL_MDT_REC*) acl_binhash_find(idx_bhash->table, key, strlen(key) + 1); + return (rec); +} + +/** + * 从一个表索引中删除该索引 + * @param idx {ACL_MDT_IDX*} 表索引 + * @param key_value {const char*} 数据结点的引用结点的引用键值 + */ +static void mdt_idx_del(ACL_MDT_IDX *idx, const char *key) +{ + ACL_MDT_IDX_BHASH *idx_bhash = (ACL_MDT_IDX_BHASH*) idx; + + /* idx->table 哈希表里存储的是: rec->key: rec 对,所以不需要在 + * 哈希表内部释放 rec 内存,因为可以显示地释放该资源 + */ + acl_binhash_delete(idx_bhash->table, key, strlen(key) + 1, NULL); +} + +/** + * 释放二进制哈希模式的数据表 + */ +static void mdt_binhash_free(ACL_MDT *mdt) +{ + ACL_MDT_BHASH *mdt_bhash = (ACL_MDT_BHASH*) mdt; + + acl_myfree(mdt_bhash); +} + +ACL_MDT *acl_mdt_binhash_create() +{ + ACL_MDT_BHASH *mdt; + + mdt = (ACL_MDT_BHASH *) acl_mycalloc(1, sizeof(ACL_MDT_BHASH)); + mdt->mdt.tbl_free = mdt_binhash_free; + mdt->mdt.idx_create = mdt_idx_create; + mdt->mdt.idx_free = mdt_idx_free; + mdt->mdt.idx_add = mdt_idx_add; + mdt->mdt.idx_get = mdt_idx_get; + mdt->mdt.idx_del = mdt_idx_del; + return ((ACL_MDT*) mdt); +} diff --git a/lib_acl/src/db/memdb/acl_mdt_hash.c b/lib_acl/src/db/memdb/acl_mdt_hash.c new file mode 100644 index 000000000..256921ec9 --- /dev/null +++ b/lib_acl/src/db/memdb/acl_mdt_hash.c @@ -0,0 +1,127 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_msg.h" +#include "stdlib/acl_mystring.h" + +#endif + +#include "struct.h" +#include "mdb_private.h" + +/** + * 创建索引 + */ +static ACL_MDT_IDX *mdt_idx_create(ACL_MDT *mdt acl_unused, size_t init_capacity, + const char *name, unsigned int flag) +{ + ACL_MDT_IDX_HASH *idx; + unsigned int flag2 = 0; + + if (init_capacity < 128) + init_capacity = 128; + idx = (ACL_MDT_IDX_HASH*) acl_mycalloc(1, sizeof(ACL_MDT_IDX_HASH)); + + if ((flag & ACL_MDT_FLAG_KMR)) + flag2 |= ACL_HTABLE_FLAG_KEY_REUSE; + + idx->table = acl_htable_create(init_capacity, flag2); + idx->idx.name = acl_mystrdup(name); + idx->idx.flag = flag; + return ((ACL_MDT_IDX*) idx); +} + +static void mdt_idx_free(ACL_MDT_IDX *idx) +{ + ACL_MDT_IDX_HASH *idx_hash = (ACL_MDT_IDX_HASH*) idx; + + acl_htable_free(idx_hash->table, NULL); + acl_myfree(idx->name); + acl_myfree(idx_hash); +} + +/** + * 向一个表索引中添加新的字段 + * @param idx {ACL_MDT_IDX*} 表索引 + * @param key {const char*} 数据表索引字段值 + * @param rec {ACL_MDT_REC*} + * @return {ACL_HTABLE_INFO*} + */ +static void mdt_idx_add(ACL_MDT_IDX *idx, const char *key, ACL_MDT_REC *rec) +{ + const char *myname = "mdt_idx_add"; + ACL_MDT_IDX_HASH *idx_hash = (ACL_MDT_IDX_HASH*) idx; + ACL_HTABLE_INFO *info; + + info = acl_htable_enter(idx_hash->table, key, (char*) rec); + if (info == NULL) + acl_msg_fatal("%s(%d): acl_htable_enter error, value(%s)", + myname, __LINE__, key); + else + rec->key = info->key.c_key; +} + +/** + * 从数据表的索引中查询对应某个索引键值的结果集 + * @param idx {ACL_MDT_IDX*} 表索引 + * @param key {const char*} 数据表索引字段值 + * @return {ACL_MDT_REC*} 对应某个索引字段值的结果集合 + */ +static ACL_MDT_REC *mdt_idx_get(ACL_MDT_IDX *idx, const char *key) +{ + ACL_MDT_IDX_HASH *idx_hash = (ACL_MDT_IDX_HASH*) idx; + ACL_MDT_REC *rec; + + rec = (ACL_MDT_REC*) acl_htable_find(idx_hash->table, key); + return (rec); +} + +/** + * 从一个表索引中删除该索引 + * @param idx {ACL_MDT_IDX*} 表索引 + * @param rec {ACL_MDT_REC*} 索引表中对应某个键的结果集对象 + * @param key_value {const char*} 数据结点的引用结点的引用键值 + */ +static void mdt_idx_del(ACL_MDT_IDX *idx, const char *key) +{ + ACL_MDT_IDX_HASH *idx_hash = (ACL_MDT_IDX_HASH*) idx; + + /* idx->table 哈希表里存储的是: rec->key: rec 对,所以不需要在 + * 哈希表内部释放 rec 内存,因为可以显示地释放该资源 + */ + acl_htable_delete(idx_hash->table, key, NULL); +} + +/** + * 释放哈希模式的数据表 + */ +static void mdt_hash_free(ACL_MDT *mdt) +{ + ACL_MDT_HASH *mdt_hash = (ACL_MDT_HASH*) mdt; + + acl_myfree(mdt_hash); +} + +ACL_MDT *acl_mdt_hash_create() +{ + ACL_MDT_HASH *mdt; + + mdt = (ACL_MDT_HASH *) acl_mycalloc(1, sizeof(ACL_MDT_HASH)); + mdt->mdt.tbl_free = mdt_hash_free; + mdt->mdt.idx_create = mdt_idx_create; + mdt->mdt.idx_free = mdt_idx_free; + mdt->mdt.idx_add = mdt_idx_add; + mdt->mdt.idx_get = mdt_idx_get; + mdt->mdt.idx_del = mdt_idx_del; + return ((ACL_MDT*) mdt); +} diff --git a/lib_acl/src/db/memdb/define.h b/lib_acl/src/db/memdb/define.h new file mode 100644 index 000000000..dbf5e9f15 --- /dev/null +++ b/lib_acl/src/db/memdb/define.h @@ -0,0 +1,8 @@ +#ifndef __DEFINE_PRIVATE_H__ +#define __DEFINE_PRIVATE_H__ + +#ifdef PACK_STRUCT +#define PACK_STRUCT 4 +#endif + +#endif diff --git a/lib_acl/src/db/memdb/mdb_private.h b/lib_acl/src/db/memdb/mdb_private.h new file mode 100644 index 000000000..605ee4f9f --- /dev/null +++ b/lib_acl/src/db/memdb/mdb_private.h @@ -0,0 +1,10 @@ +#ifndef __MDB_PRIVATE_INCLUDE_H__ +#define __MDB_PRIVATE_INCLUDE_H__ + +#include "struct.h" + +ACL_MDT *acl_mdt_hash_create(void); +ACL_MDT *acl_mdt_binhash_create(void); +ACL_MDT *acl_mdt_avl_create(void); + +#endif diff --git a/lib_acl/src/db/memdb/ring.h b/lib_acl/src/db/memdb/ring.h new file mode 100644 index 000000000..ec08f647c --- /dev/null +++ b/lib_acl/src/db/memdb/ring.h @@ -0,0 +1,82 @@ + +#ifndef _RING_H_INCLUDE_ +#define _RING_H_INCLUDE_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +typedef struct RING RING; + +struct RING { + RING *succ; /* successor */ + RING *pred; /* predecessor */ +}; + +#define ring_init(ring_in) do \ +{ \ + RING *ring = ring_in; \ + ring->pred = ring->succ = ring; \ +} while (0) + +#define ring_append(ring_in, entry_in) do \ +{ \ + RING *ring = ring_in; \ + RING *entry = entry_in; \ + entry->succ = ring->succ; \ + entry->pred = ring; \ + ring->succ->pred = entry; \ + ring->succ = entry; \ +} while (0) + +#define ring_prepend(ring_in, entry_in) do \ +{ \ + RING *ring = ring_in; \ + RING *entry = entry_in; \ + entry->pred = ring->pred; \ + entry->succ = ring; \ + ring->pred->succ = entry; \ + ring->pred = entry; \ +} while (0) + +#define ring_detach(entry_in) do \ +{ \ + RING *entry = entry_in; \ + RING *succ; \ + RING *pred; \ + succ = entry->succ; \ + pred = entry->pred; \ + if (succ != NULL && pred != NULL) { \ + pred->succ = succ; \ + succ->pred = pred; \ + entry->succ = entry->pred = 0; \ + } \ +} while (0) + +#define ring_succ(c) ((c)->succ) +#define ring_pred(c) ((c)->pred) + +#define RING_TO_APPL(ring_ptr, app_type, ring_member) \ + ((app_type *) (((char *) (ring_ptr)) - offsetof(app_type,ring_member))) + +#define FOREACH_TO_APPL_ENTRY(entry, head) \ + for (entry = ring_succ(head); entry != (head); entry = ring_succ(entry)) +#define FOREACH_RING_ENTRY(entry, head) \ + for (entry = ring_succ(head); entry != (head); entry = ring_succ(entry)) + +#define FOREACH_RING_FORWARD FOREACH_RING_ENTRY +#define FOREACH_RING_BACKWARD(entry, head) \ + for (entry = ring_pred(head); entry != (head); entry = ring_pred(entry)) + +#define FIRST_APPL(head, app_type, ring_member) \ + (ring_succ(head) != (head) ? \ + RING_TO_APPL(ring_succ(head), app_type, ring_member) : 0) + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/src/db/memdb/struct.h b/lib_acl/src/db/memdb/struct.h new file mode 100644 index 000000000..e42804503 --- /dev/null +++ b/lib_acl/src/db/memdb/struct.h @@ -0,0 +1,162 @@ +#ifndef __MESTRUCT_INCLUDE_H__ +#define __MESTRUCT_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_define.h" +#include "stdlib/acl_array.h" +#include "stdlib/acl_htable.h" +#include "db/acl_mdb.h" +#include "stdlib/avl.h" +#include "stdlib/acl_slice.h" +#include "stdlib/acl_htable.h" +#include "stdlib/acl_binhash.h" +#include "ring.h" + +/* 用户查询结果集合 */ +struct ACL_MDT_RES { + ACL_ARRAY *a; /* 将 ACL_MDT_NOD 的查询结果集合存储在此数组中 */ + int ipos; /* 下一个数组元素在动态数组中的位置 */ +}; + +/* 数据结点的数据结构定义(24 byte) */ +struct ACL_MDT_NOD { + RING mdt_entry; /* 链接进 ACL_MDT 中的 node_head */ + RING ref_head; /* 引用该数据结点的所有引用结点的集合 */ + void *data; /* 用户级数据项的内部表示, 可以为各种用户 + * 所自定义的数据类型, 通过强制类型转换将其 + * 统一转化为 void * 类型, 在建立索引时用户 + * 需要以自定义数据类型中的某些字段为键值 + * 来建立索引记录及索引表, 从而建立索引数据库, + * 最终该 data 字段中的键将与 ACL_MDT_REC 中的 + * key 相同并映射到 ACL_MDT_REC 中的 table + * 集合中. + */ + + unsigned int dlen:24; /* data 数据的长度 */ + unsigned int nrefer:8; /* 引用该数据结点的 ACL_MDT_REF 数量 */ +}; + +/* 索引表的索引记录数据结构定义, 索引表(ACL_MDT)的索引集合字段(table) + * 的组成单位为 ACL_REC, 即 ACL_MDT.table 是由一系列 ACL_REC + * 数据索引记录组成的. + * (12 byte) + */ +struct ACL_MDT_REC { + RING ref_head; /* 具有相同键值的 ACL_MDT_NOD_REF 的集合 */ + ACL_MDT_IDX *idx; /* 引用其所属的索引表 */ + const char *key; /* 索引键引用 */ + unsigned int nrefer:8; /* 该结果集合的 ACL_MDT_NODE_REF 元素总和 */ +}; + +/** + * 引用结点定义(20 byte) + */ +struct ACL_MDT_REF { + RING nod_entry; /* 与 ACL_MDT_NOD 关联 */ + RING rec_entry; /* 与 ACL_MDT_REC 关联 */ + ACL_MDT_NOD *node; /* 引用 ACL_MDT_NOD */ + ACL_MDT_REC *rec; /* 引用 ACL_MDT_REC */ +}; + +/** + * 表的索引字段对象类型, 索引表中每个索引项都有一个索引字段对象 + */ +struct ACL_MDT_IDX { + RING mdt_entry; /* 链接进 ACL_MDT 中的 idx_head 链表 */ + char *name; /* 字段名称 */ + ACL_MDT *mdt; /* 反向引用其所从属的索引表 */ + unsigned int flag; /* 该数据表的约束标志 */ +}; + +/** + * 表索引以哈希表方式存储 + */ +typedef struct ACL_MDT_IDX_HASH { + ACL_MDT_IDX idx; + ACL_HTABLE *table; /* 容纳索引键及其所标识数据结点对象的集合 */ +} ACL_MDT_IDX_HASH; + +/** + * 表索引以哈希表方式存储 + */ +typedef struct ACL_MDT_IDX_BHASH { + ACL_MDT_IDX idx; + ACL_BINHASH *table; /* 容纳索引键及其所标识数据结点对象的集合 */ +} ACL_MDT_IDX_BHASH; + +/** + * 表索引以平稳二叉树方式存储 + */ +typedef struct ACL_MDT_IDX_AVL { + ACL_MDT_IDX idx; + avl_tree_t avl; + ACL_SLICE *slice; /* 内存分配池 */ +} ACL_MDT_IDX_AVL; + +/* 索引表数据结构定义, 每个索引表在建立时就是以数据结点(ACL_NODE)中的 + * 用户数据(data)中的某个数据字段为键值建立的. + */ +struct ACL_MDT { + RING idx_head; /* 索引字段对象链表 */ + RING nod_head; /* 所有数据结点的集合 */ + + char *name; /* 索引表名称 */ + int node_cnt; /* 所有数据结点的总和 */ + int error; /* 当出错时记录出错状态号 */ + unsigned int tbl_flag; /* 标志位 */ + + ACL_SLICE *nod_slice; + ACL_SLICE *rec_slice; + ACL_SLICE *ref_slice; + + /* public */ + ACL_MDT_NOD *(*add)(ACL_MDT *mdt, void *data, unsigned int dlen, + const char *key_labels[], const char *keys[]); + ACL_MDT_RES *(*get)(ACL_MDT *mdt, const char *key_label, + const char *key, int from, int limit); + int (*del)(ACL_MDT *mdt, const char *key_label, + const char *key, void (*onfree_fn)(void *data, unsigned int dlen)); + int (*probe)(ACL_MDT *mdt, const char *key_label, const char *key); + ACL_MDT_RES *(*list)(ACL_MDT *mdt, int from, int limit); + int (*walk)(ACL_MDT *mdt, int (*walk_fn)(const void *data, unsigned int dlen), + int from, int limit); + + void (*tbl_free)(ACL_MDT*); + + /* private */ + ACL_MDT_IDX *(*idx_create)(ACL_MDT *mdt, size_t init_capacity, + const char *name, unsigned int flag); + void (*idx_free)(ACL_MDT_IDX *idx); + void (*idx_add)(ACL_MDT_IDX *idx, const char *key, ACL_MDT_REC *rec); + void (*idx_del)(ACL_MDT_IDX *idx, const char *key); + ACL_MDT_REC *(*idx_get)(ACL_MDT_IDX *idx, const char *key); +}; + +typedef struct ACL_MDT_HASH { + ACL_MDT mdt; +} ACL_MDT_HASH; + +typedef struct ACL_MDT_BHASH { + ACL_MDT mdt; +} ACL_MDT_BHASH; + +typedef struct ACL_MDT_AVL { + ACL_MDT mdt; +} ACL_MDT_AVL; + +/* 索引数据库数据结构定义 */ +struct ACL_MDB { + char name[128]; /* 数据库名称 */ + char type[32]; /* 数据库类型: hash/avl */ + ACL_HTABLE *tbls; /* 容纳所有索引表的集合 */ +}; + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/src/db/mysql/acl_dbmysql.c b/lib_acl/src/db/mysql/acl_dbmysql.c new file mode 100644 index 000000000..c363db933 --- /dev/null +++ b/lib_acl/src/db/mysql/acl_dbmysql.c @@ -0,0 +1,330 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#endif + +#ifdef HAS_MYSQL + +#include "mysql.h" +#include "errmsg.h" +#include "mysqld_error.h" + +#include "stdlib/acl_stdlib.h" +#include "db/acl_dberr.h" +#include "acl_dbpool_mysql.h" +#include "acl_dbmysql.h" + +static const void *dbmysql_iter_head(ACL_ITER *iter, struct ACL_SQL_RES *res) +{ + MYSQL_RES *my_res = (MYSQL_RES*) res->res; + MYSQL_ROW my_row; + + iter->dlen = -1; + iter->key = NULL; + iter->klen = -1; + iter->i = 0; + iter->size = res->num; + + my_row = mysql_fetch_row(my_res); + if (my_row == NULL) { + iter->data = iter->ptr = NULL; + return (NULL); + } + + iter->data = iter->ptr = (void*) my_row; + return (iter->ptr); +} + +static const void *dbmysql_iter_next(ACL_ITER *iter, struct ACL_SQL_RES *res) +{ + MYSQL_RES *my_res = (MYSQL_RES*) res->res; + MYSQL_ROW my_row; + + my_row = mysql_fetch_row(my_res); + if (my_row == NULL) { + iter->data = iter->ptr = NULL; + return (NULL); + } + + iter->i++; + iter->data = iter->ptr = (void*) my_row; + return (iter->ptr); +} + +static MYSQL *sane_mysql_query(ACL_DB_HANDLE *handle, const char *sql) +{ + const char *myname = "acl_mysql_query"; + MYSQL *myconn; + int errnum; + + myconn = acl_dbpool_export(handle); + if (myconn == NULL) + acl_msg_fatal("%s(%d): null mysql handle", myname, __LINE__); + if (mysql_query(myconn, sql) == 0) + return (myconn); + + /* 重新打开MYSQL连接进行重试 */ + + errnum = mysql_errno(myconn); + if (errnum != CR_SERVER_LOST && errnum != CR_SERVER_GONE_ERROR) { + acl_msg_error("%s(%d): sql(%s) error(%s)", + myname, __LINE__, sql, mysql_error(myconn)); + return (NULL); + } + if (sane_mysql_reopen(handle) < 0) + return (NULL); + + myconn = acl_dbpool_export(handle); + if (myconn == NULL) + acl_msg_fatal("%s(%d): null mysql handle", myname, __LINE__); + if (mysql_query(myconn, sql) == 0) + return (myconn); + + acl_msg_error("%s(%d): sql(%s) error(%s)", + myname, __LINE__, sql, mysql_error(myconn)); + return (NULL); +} + +ACL_SQL_RES *acl_dbmysql_select(ACL_DB_HANDLE *handle, const char *sql, int *error) +{ + const char *myname = "acl_dbmysql_select"; + ACL_SQL_RES *res; + MYSQL *myconn; + MYSQL_RES *my_res; + int n; + + if (handle == NULL || sql == NULL || *sql == 0) + acl_msg_fatal("%s(%d): input invalid", myname, __LINE__); + + if (error) + *error = ACL_DB_OK; + + if ((myconn = sane_mysql_query(handle, sql)) == NULL) { + if (error) + *error = ACL_DB_ERR_SELECT; + acl_msg_error("%s(%d): mysql_query error(%s), sql(%s)", + myname, __LINE__, mysql_error(myconn), sql); + return (NULL); + } + + my_res = mysql_store_result(myconn); + + if (my_res == NULL) { + if (mysql_errno(myconn) == 0) { + if (error) + *error = ACL_DB_ERR_EMPTY; + return (NULL); + } + if (error) + *error = ACL_DB_ERR_STORE; + acl_msg_error("%s(%d): mysql_store_result error(%s), sql(%s)", + myname, __LINE__, mysql_error(myconn), sql); + return (NULL); + } + + if ((n = mysql_num_rows(my_res)) <= 0) { + if (error) + *error = ACL_DB_ERR_EMPTY; + mysql_free_result(my_res); + return (NULL); + } + + res = (ACL_SQL_RES*) acl_mymalloc(sizeof(ACL_SQL_RES)); + if (res == NULL) { + if (error) + *error = ACL_DB_ERR_ALLOC; + acl_msg_error("%s(%d): malloc error", myname, __LINE__); + mysql_free_result(my_res); + return (NULL); + } + + res->res = (void*) my_res; + res->num = n; + res->iter_head = dbmysql_iter_head; + res->iter_next = dbmysql_iter_next; + return (res); +} + +void acl_dbmysql_free_result(ACL_SQL_RES *res) +{ + MYSQL_RES *my_res = (MYSQL_RES*) res->res; + + if (my_res) + mysql_free_result(my_res); + acl_myfree(res); +} + +/* 用于有返回结果集的查询 */ + +int acl_dbmysql_results(ACL_DB_HANDLE *handle, const char *sql, int *error, + int (*walk_fn)(const void** my_row, void *arg), void *arg) +{ + const char *myname = "acl_dbmysql_results"; + MYSQL *myconn; + MYSQL_RES *my_res; + MYSQL_ROW my_row; + int n; + + if (handle == NULL || sql == NULL || *sql == 0 || walk_fn == NULL) + acl_msg_fatal("%s(%d): input invalid", myname, __LINE__); + + if (error) + *error = ACL_DB_OK; + + if ((myconn = sane_mysql_query(handle, sql)) == NULL) { + if (error) + *error = ACL_DB_ERR_SELECT; + acl_msg_error("%s(%d): mysql_query error(%s), sql(%s)", + myname, __LINE__, mysql_error(myconn), sql); + return (-1); + } + + my_res = mysql_store_result(myconn); + + if (my_res == NULL) { + if (mysql_errno(myconn) == 0) { + if (error) + *error = ACL_DB_ERR_EMPTY; + return (0); + } + if (error) + *error = ACL_DB_ERR_STORE; + acl_msg_error("%s(%d): mysql_store_result error(%s), sql(%s)", + myname, __LINE__, mysql_error(myconn), sql); + return (-1); + } + + my_row = mysql_fetch_row(my_res); + if (my_row == NULL) { + if (error) + *error = ACL_DB_ERR_EMPTY; + mysql_free_result(my_res); + return (0); + } + + if (walk_fn((const void**) my_row, arg) < 0) { + if (error) + *error = ACL_DB_ERR_CALLBACK; + mysql_free_result(my_res); + return (-1); + } + + n = 1; + + while ((my_row = mysql_fetch_row(my_res)) != NULL) { + if (walk_fn((const void**) my_row, arg) < 0) { + if (error) + *error = ACL_DB_ERR_CALLBACK; + mysql_free_result(my_res); + return (-1); + } + n++; + } + + mysql_free_result(my_res); + + return (n); +} + +/* 用于仅查询一个结果的情况 */ + +int acl_dbmysql_result(ACL_DB_HANDLE *handle, const char *sql, int *error, + int (*callback)(const void** my_row, void *arg), void *arg) +{ + const char *myname = "acl_dbmysql_result"; + MYSQL *myconn; + MYSQL_RES *my_res; + MYSQL_ROW my_row; + + if (handle == NULL || sql == NULL || *sql == 0 || callback == NULL) + acl_msg_fatal("%s(%d): input invalid", myname, __LINE__); + + if (error) + *error = ACL_DB_OK; + + if ((myconn = sane_mysql_query(handle, sql)) == NULL) { + if (error) + *error = ACL_DB_ERR_SELECT; + acl_msg_error("%s(%d): mysql_query error(%s), sql(%s)", + myname, __LINE__, mysql_error(myconn), sql); + return (-1); + } + + my_res = mysql_store_result(myconn); + + if (my_res == NULL) { + if (mysql_errno(myconn) == 0) { + if (error) + *error = ACL_DB_ERR_EMPTY; + return (0); + } + if (error) + *error = ACL_DB_ERR_STORE; + acl_msg_error("%s(%d): mysql_store_result error(%s), sql(%s)", + myname, __LINE__, mysql_error(myconn), sql); + return (-1); + } + + my_row = mysql_fetch_row(my_res); + if (my_row == NULL) { + if (error) + *error = ACL_DB_ERR_EMPTY; + mysql_free_result(my_res); + return (0); + } + + if (callback((const void**) my_row, arg) < 0) { + if (error) + *error = ACL_DB_ERR_CALLBACK; + mysql_free_result(my_res); + return (-1); + } + + mysql_free_result(my_res); + + return (1); +} + +int acl_dbmysql_update(ACL_DB_HANDLE *handle, const char *sql, int *error) +{ + const char *myname = "acl_dbmysql_update"; + MYSQL *myconn; + int ret; + + if (handle == NULL || sql == NULL || *sql == 0) + acl_msg_fatal("%s(%d): input invalid", myname, __LINE__); + + if (error) + *error = ACL_DB_OK; + + if ((myconn = sane_mysql_query(handle, sql)) == NULL) { + if (error) + *error = ACL_DB_ERR_UPDATE; + acl_msg_error("%s(%d): mysql_query error(%s), sql(%s)", + myname, __LINE__, mysql_error(myconn), sql); + return (-1); + } + + ret = (int) mysql_affected_rows(myconn); + if (ret == (int) (-1)) { /* XXX */ + if (error) + *error = ACL_DB_ERR_AFFECTED; + acl_msg_error("%s(%d): mysql_affected_rows error(%s), sql(%s)", + myname, __LINE__, mysql_error(myconn), sql); + return (-1); + } + + return (ret); +} + +#endif /* HAS_MYSQL */ + diff --git a/lib_acl/src/db/mysql/acl_dbmysql.h b/lib_acl/src/db/mysql/acl_dbmysql.h new file mode 100644 index 000000000..f660f80ed --- /dev/null +++ b/lib_acl/src/db/mysql/acl_dbmysql.h @@ -0,0 +1,28 @@ +#ifndef __ACL_DBMYSQL_INCLUDE_H__ +#define __ACL_DBMYSQL_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_define.h" +#include "db/acl_dbpool.h" + +#ifdef HAS_MYSQL + +ACL_SQL_RES *acl_dbmysql_select(ACL_DB_HANDLE *handle, const char *sql, int *error); +void acl_dbmysql_free_result(ACL_SQL_RES *res); +int acl_dbmysql_results(ACL_DB_HANDLE *handle, const char *sql, int *error, + int (*walk_fn)(const void** my_row, void *arg), void *arg); +int acl_dbmysql_result(ACL_DB_HANDLE *handle, const char *sql, int *error, + int (*callback)(const void** my_row, void *arg), void *arg); +int acl_dbmysql_update(ACL_DB_HANDLE *handle, const char *sql, int *error); + +#endif /* HAS_MYSQL */ + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/src/db/mysql/acl_dbpool_mysql.c b/lib_acl/src/db/mysql/acl_dbpool_mysql.c new file mode 100644 index 000000000..561f716e3 --- /dev/null +++ b/lib_acl/src/db/mysql/acl_dbpool_mysql.c @@ -0,0 +1,495 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "thread/acl_thread.h" +#include "stdlib/acl_stdlib.h" +#include "db/acl_dbpool.h" + +#endif + +#ifdef HAS_MYSQL + +#include "mysql.h" +#include "acl_dbmysql.h" +#include "acl_dbpool_mysql.h" + +typedef struct ACL_DB_HANDLE_MYSQL { + ACL_DB_HANDLE handle; + MYSQL *connection; +} ACL_DB_HANDLE_MYSQL; + +typedef struct ACL_DB_POOL_MYSQL { + ACL_DB_POOL db_pool; + + acl_pthread_mutex_t mutex; + ACL_ARRAY *handles; + time_t when_check; +} ACL_DB_POOL_MYSQL; + +#define DB_LOCK(mlock) { acl_pthread_mutex_lock(&mlock); } +#define DB_UNLOCK(mlock) { acl_pthread_mutex_unlock(&mlock); } + +static void __close_mysql_handle(ACL_DB_HANDLE_MYSQL *mysql_handle); + +/*----------------------------------------------------------------------------*/ +static ACL_DB_HANDLE_MYSQL *__new_mysql_handle(void) +{ + ACL_DB_HANDLE_MYSQL *mysql_handle; + + mysql_handle = (ACL_DB_HANDLE_MYSQL *) + acl_mycalloc(1, sizeof(ACL_DB_HANDLE_MYSQL)); + + mysql_handle->handle.sql_results = acl_dbmysql_results; + mysql_handle->handle.sql_result = acl_dbmysql_result; + mysql_handle->handle.sql_update = acl_dbmysql_update; + mysql_handle->handle.sql_select = acl_dbmysql_select; + mysql_handle->handle.free_result = acl_dbmysql_free_result; + + return (mysql_handle); +} + +static ACL_DB_HANDLE_MYSQL *__open_mysql_handle(ACL_DB_POOL_MYSQL *mysql_pool, + ACL_DB_HANDLE_MYSQL *mysql_handle, ACL_DB_INFO *db_info) +{ + char myname[] = "__open_mysql_handle"; + int reuse_flag = 0; + const char *ptr; + char *db_host, *db_unix; + int db_port; + char tmpbuf[256]; + int n, len, i; + my_bool reconnect = 1; + + ptr = strchr(db_info->db_addr, '/'); + if (ptr == NULL) { + ptr = strchr(db_info->db_addr, ':'); + if (ptr == NULL) + acl_msg_fatal("%s, %s(%d): invalid db_addr=%s", + __FILE__, myname, __LINE__, db_info->db_addr); + len = ptr - db_info->db_addr; + if (len == 0) + acl_msg_fatal("%s, %s(%d): invalid db_addr=%s", + __FILE__, myname, __LINE__, db_info->db_addr); + + len++; /* 1 for '\0' */ + i = sizeof(tmpbuf) - 1; + n = i > len ? len : i - 1; + ACL_SAFE_STRNCPY(tmpbuf, db_info->db_addr, n); + db_host = tmpbuf; + + ptr++; /* skip ':' */ + db_port = atoi(ptr); + if (db_port <= 0) + acl_msg_fatal("%s, %s(%d): invalid port=%d", + __FILE__, myname, __LINE__, db_port); + + db_unix = NULL; + } else { + db_unix = db_info->db_addr; + db_host = NULL; + db_port = 0; + } + + if (mysql_handle == NULL) { + mysql_handle = __new_mysql_handle(); + mysql_handle->handle.parent = &mysql_pool->db_pool; + } else + reuse_flag = 1; + + mysql_handle->connection = mysql_init(NULL); + if (mysql_handle->connection == NULL) { + acl_msg_error("%s, %s(%d): mysql init error", + __FILE__, myname, __LINE__); + if (!reuse_flag) + acl_myfree(mysql_handle); + return (NULL); + } + + if (db_info->conn_timeout > 0) + mysql_options(mysql_handle->connection, + MYSQL_OPT_CONNECT_TIMEOUT, + (const void*) &db_info->conn_timeout); + if (db_info->rw_timeout > 0) { + mysql_options(mysql_handle->connection, + MYSQL_OPT_READ_TIMEOUT, + (const void*) &db_info->rw_timeout); + mysql_options(mysql_handle->connection, + MYSQL_OPT_WRITE_TIMEOUT, + (const void*) &db_info->rw_timeout); + } + mysql_options(mysql_handle->connection, + MYSQL_OPT_RECONNECT, (const void*) &reconnect); + + if (db_info->db_before_connect + && db_info->db_before_connect((ACL_DB_HANDLE*) mysql_handle, + db_info->ctx) < 0) + { + acl_msg_error("%s, %s(%d): db_before_connect return < 0", + __FILE__, myname, __LINE__); + mysql_close(mysql_handle->connection); + mysql_handle->connection = NULL; + if (!reuse_flag) + acl_myfree(mysql_handle); + return (NULL); + } + + if (mysql_real_connect(mysql_handle->connection, + db_host, + db_info->db_user, + db_info->db_pass, + db_info->db_name, + db_port, + db_unix, + db_info->db_flags) == NULL) { + acl_msg_error("%s, %s(%d): connect mysql error(%s), db_host=%s", + __FILE__, myname, __LINE__, + mysql_error(mysql_handle->connection), db_info->db_addr); + + mysql_close(mysql_handle->connection); + mysql_handle->connection = NULL; + if (!reuse_flag) + acl_myfree(mysql_handle); + return (NULL); + } + +#if MYSQL_VERSION_ID >= 50000 + if (mysql_autocommit(mysql_handle->connection, db_info->auto_commit) != 0) { + acl_msg_error("%s, %s(%d): mysql_autocommit error", + __FILE__, myname, __LINE__); + mysql_close(mysql_handle->connection); + mysql_handle->connection = NULL; + if (!reuse_flag) + acl_myfree(mysql_handle); + return (NULL); + } +#else + db_info->auto_commit = 0; +#endif + + if (db_info->db_after_connect + && db_info->db_after_connect((ACL_DB_HANDLE*) mysql_handle, + db_info->ctx) < 0) + { + acl_msg_error("%s, %s(%d): db_after_connect return < 0", + __FILE__, myname, __LINE__); + mysql_handle->connection = NULL; + if (!reuse_flag) + acl_myfree(mysql_handle); + return (NULL); + } + + if (acl_msg_verbose) + acl_msg_info("OK, database connected, db_host: %s" + ", db_name: %s, db_user: %s, autocommit %s", + db_info->db_addr, db_info->db_name, db_info->db_user, + db_info->auto_commit ? "true" : "false"); +#if 0 + acl_msg_info("db_pass: %s\n", db_info->db_pass); +#endif + + mysql_handle->handle.status = ACL_DBH_STATUS_READY; + mysql_handle->handle.timeout = time(NULL) + db_info->timeout_inter; + mysql_handle->handle.ping = time(NULL) + db_info->ping_inter; + + if (!reuse_flag) { + if (acl_array_append(mysql_pool->handles, mysql_handle) < 0) { + acl_msg_fatal("%s, %s(%d): append to handles error(%s)", + __FILE__, myname, __LINE__, acl_last_serror()); + } + } + + return (mysql_handle); +} + +int sane_mysql_reopen(ACL_DB_HANDLE *handle) +{ + const char *myname = "sane_mysql_repopen"; + ACL_DB_HANDLE_MYSQL *mysql_handle = (ACL_DB_HANDLE_MYSQL*) handle; + MYSQL *myconn_saved = mysql_handle->connection; + ACL_DB_INFO *db_info = &mysql_handle->handle.parent->db_info; + + if (__open_mysql_handle((ACL_DB_POOL_MYSQL*) handle->parent, + mysql_handle, db_info) == NULL) + { + acl_msg_error("%s(%d): reopen mysql connection error", + myname, __LINE__); + mysql_handle->connection = myconn_saved; + return (-1); + } + __close_mysql_handle(mysql_handle); + return (0); +} + +/*----------------------------------------------------------------------------*/ +static void __close_mysql_handle(ACL_DB_HANDLE_MYSQL *mysql_handle) +{ + if (mysql_handle->connection == NULL) + return; + mysql_close(mysql_handle->connection); + mysql_handle->connection = NULL; + mysql_handle->handle.status = ACL_DBH_STATUS_NULL; + mysql_handle->handle.timeout = 0; + mysql_handle->handle.ping = 0; +} + +/*----------------------------------------------------------------------------*/ +static void __dbpool_mysql_check(ACL_DB_POOL *db_pool) +{ + ACL_DB_POOL_MYSQL *mysql_pool = (ACL_DB_POOL_MYSQL*) db_pool; + ACL_DB_HANDLE_MYSQL *mysql_handle; + int i, n, ping_inter; + time_t now = time(NULL); + + ping_inter = mysql_pool->db_pool.db_info.ping_inter; + + n = acl_array_size(mysql_pool->handles); + + for (i = 0; i < n; i++) { + mysql_handle = (ACL_DB_HANDLE_MYSQL *) + acl_array_index(mysql_pool->handles, i); + if (mysql_handle == NULL) + continue; + if (mysql_handle->handle.status != ACL_DBH_STATUS_READY) + continue; + + /* if the connecion is idle timeout ? */ + if (now > mysql_handle->handle.timeout) { + __close_mysql_handle(mysql_handle); + mysql_pool->db_pool.db_ready--; + continue; + } + + /* has the ping time reached ? */ + if (now <= mysql_handle->handle.ping) + continue; + + if (mysql_ping(mysql_handle->connection) == 0) { + mysql_handle->handle.ping = time(NULL) + ping_inter; + } else { + __close_mysql_handle(mysql_handle); + mysql_pool->db_pool.db_ready--; + } + } +} + +/*----------------------------------------------------------------------------*/ +static ACL_DB_HANDLE *__dbpool_mysql_peek(ACL_DB_POOL *db_pool) +{ + char myname[] = "__dbpool_mysql_peek"; + ACL_DB_POOL_MYSQL *mysql_pool = (ACL_DB_POOL_MYSQL *) db_pool; + ACL_DB_HANDLE_MYSQL *mysql_handle, *mysql_handle_slot = NULL; + int i, n; + time_t now; + static time_t last_time; /* 因为在调用此函数时已经上锁, + * 所以此处声明一静态变量是线程安全的. + */ + +#undef RETURN +#define RETURN(_x_) do { \ + now = time(NULL); \ + if (acl_msg_verbose && now - last_time > 5) { \ + acl_msg_info("Database status: max = %d, idle = %d, busy = %d", \ + db_pool->db_max, db_pool->db_ready, db_pool->db_inuse); \ + last_time = now; \ + } \ + DB_UNLOCK(mysql_pool->mutex); \ + return (_x_); \ +} while (0) + + DB_LOCK(mysql_pool->mutex); + + if (time(NULL) >= mysql_pool->when_check) { + int inter = db_pool->db_info.ping_inter > db_pool->db_info.timeout_inter + ? db_pool->db_info.timeout_inter : db_pool->db_info.ping_inter; + + db_pool->dbh_check(db_pool); + mysql_pool->when_check = time(NULL) + inter; + } + + + if (db_pool->db_inuse >= db_pool->db_max) { + acl_msg_warn("%s, %s(%d): all connections be used, reached db_max(%d)", + __FILE__, myname, __LINE__, db_pool->db_max); + RETURN (NULL); + } + + n = acl_array_size(mysql_pool->handles); + + /* lookup mysql connection from pool */ + for (i = 0; i < n; i++) { + mysql_handle = (ACL_DB_HANDLE_MYSQL *) + acl_array_index(mysql_pool->handles, i); + + if (mysql_handle == NULL) + continue; + + if (mysql_handle->handle.status == ACL_DBH_STATUS_READY) { + mysql_handle->handle.status = ACL_DBH_STATUS_INUSE; + db_pool->db_inuse++; + db_pool->db_ready--; + + RETURN ((ACL_DB_HANDLE *) mysql_handle); + } else if (mysql_handle->handle.status == ACL_DBH_STATUS_NULL + && mysql_handle_slot == NULL) + mysql_handle_slot = mysql_handle; + } + + /* create new mysql connection */ + + mysql_handle = __open_mysql_handle(mysql_pool, mysql_handle_slot, &db_pool->db_info); + if (mysql_handle == NULL) + RETURN (NULL); + + mysql_handle->handle.status = ACL_DBH_STATUS_INUSE; + db_pool->db_inuse++; + + RETURN ((ACL_DB_HANDLE *) mysql_handle); +} + +/*----------------------------------------------------------------------------*/ +static void __dbpool_mysql_release(ACL_DB_HANDLE *db_handle) +{ + char myname[] = "__dbpool_mysql_release"; + ACL_DB_POOL *db_pool; + ACL_DB_POOL_MYSQL *mysql_pool; + ACL_DB_HANDLE_MYSQL *mysql_handle; + int timeout_inter, ping_inter; + + mysql_handle = (ACL_DB_HANDLE_MYSQL *) db_handle; + if (db_handle->status != ACL_DBH_STATUS_INUSE || mysql_handle->connection == NULL) { + acl_msg_error("%s, %s(%d): status %s ACL_DBH_STATUS_INUSE, connection %s", + __FILE__, myname, __LINE__, + db_handle->status == ACL_DBH_STATUS_INUSE ? "=" : "!=", + mysql_handle->connection ? "not null" : "null"); + return; + } + + db_pool = db_handle->parent; + timeout_inter = db_pool->db_info.timeout_inter; + ping_inter = db_pool->db_info.ping_inter; + + if (db_pool == NULL) + acl_msg_fatal("%s, %s(%d): db_handle's parent is null", + __FILE__, myname, __LINE__); + + mysql_pool = (ACL_DB_POOL_MYSQL *) db_pool; + DB_LOCK(mysql_pool->mutex); + + db_handle->status = ACL_DBH_STATUS_READY; + db_handle->timeout = time(NULL) + timeout_inter; + db_handle->ping = time(NULL) + ping_inter; + + db_pool->db_inuse--; + db_pool->db_ready++; + + DB_UNLOCK(mysql_pool->mutex); +} +/*----------------------------------------------------------------------------*/ +static void *__dbpool_mysql_export(ACL_DB_HANDLE *db_handle) +{ + ACL_DB_HANDLE_MYSQL *mysql_handle = (ACL_DB_HANDLE_MYSQL *) db_handle; + + return ((void *) mysql_handle->connection); +} +/*----------------------------------------------------------------------------*/ +static void __dbpool_mysql_close(ACL_DB_HANDLE *db_handle) +{ + char myname[] = "__dbpool_mysql_close"; + ACL_DB_POOL *db_pool; + ACL_DB_POOL_MYSQL *mysql_pool; + ACL_DB_HANDLE_MYSQL *mysql_handle = (ACL_DB_HANDLE_MYSQL *) db_handle; + + if (db_handle->status != ACL_DBH_STATUS_INUSE || mysql_handle->connection == NULL) { + acl_msg_error("%s, %s(%d): status %s ACL_DBH_STATUS_INUSE, connection %s", + __FILE__, myname, __LINE__, + db_handle->status == ACL_DBH_STATUS_INUSE ? "=" : "!=", + mysql_handle->connection ? "not null" : "null"); + return; + } + + db_pool = db_handle->parent; + if (db_pool == NULL) + acl_msg_fatal("%s, %s(%d): db_handle's parent is null", + __FILE__, myname, __LINE__); + mysql_pool = (ACL_DB_POOL_MYSQL *) db_pool; + + DB_LOCK(mysql_pool->mutex); + + __close_mysql_handle(mysql_handle); + db_pool->db_inuse--; + + DB_UNLOCK(mysql_pool->mutex); +} +/*----------------------------------------------------------------------------*/ +static void __dbpool_mysql_destroy(ACL_DB_POOL *db_pool) +{ + ACL_DB_POOL_MYSQL *mysql_pool; + ACL_DB_HANDLE_MYSQL *mysql_handle; + int i, n; + + mysql_pool = (ACL_DB_POOL_MYSQL *) db_pool; + + n = acl_array_size(mysql_pool->handles); + for (i = 0; i < n; i++) { + mysql_handle = (ACL_DB_HANDLE_MYSQL *) + acl_array_index(mysql_pool->handles, i); + if (mysql_handle == NULL) + continue; + __close_mysql_handle(mysql_handle); + acl_myfree(mysql_handle); + } + acl_pthread_mutex_destroy(&mysql_pool->mutex); + acl_array_destroy(mysql_pool->handles, NULL); + acl_myfree(mysql_pool); + mysql_library_end(); +} +/*----------------------------------------------------------------------------*/ +ACL_DB_POOL *acl_dbpool_mysql_create(const ACL_DB_INFO *db_info) +{ + char myname[] = "acl_dbpool_mysql_create"; + ACL_DB_POOL_MYSQL *mysql_pool; + + mysql_pool = (ACL_DB_POOL_MYSQL *) acl_mycalloc(1, sizeof(ACL_DB_POOL_MYSQL)); + if (mysql_pool == NULL) { + char tbuf[256]; + acl_msg_fatal("%s, %s(%d): calloc error=%s", + __FILE__, myname, __LINE__, acl_last_strerror(tbuf, sizeof(tbuf))); + } + + mysql_pool->db_pool.dbh_peek = &__dbpool_mysql_peek; + mysql_pool->db_pool.dbh_check = &__dbpool_mysql_check; + mysql_pool->db_pool.dbh_release = &__dbpool_mysql_release; + mysql_pool->db_pool.dbh_export = &__dbpool_mysql_export; + mysql_pool->db_pool.dbh_close = &__dbpool_mysql_close; + + mysql_pool->db_pool.destroy = &__dbpool_mysql_destroy; + + mysql_pool->handles = acl_array_create(db_info->db_max); + acl_pthread_mutex_init(&mysql_pool->mutex, NULL); + + return ((ACL_DB_POOL *) mysql_pool); +} +/*----------------------------------------------------------------------------*/ + +#if 0 +#ifdef ACL_MS_WINDOWS +/* XXX: just for the poor mysql */ +extern void _dosmaperr(unsigned long error); +void _dosmaperr(unsigned long error) +{ + +} +#endif /* ACL_MS_WINDOWS */ +#endif + +#endif /* HAS_MYSQL */ + diff --git a/lib_acl/src/db/mysql/acl_dbpool_mysql.h b/lib_acl/src/db/mysql/acl_dbpool_mysql.h new file mode 100644 index 000000000..fd8cce5db --- /dev/null +++ b/lib_acl/src/db/mysql/acl_dbpool_mysql.h @@ -0,0 +1,37 @@ + +#ifndef __ACL_DBPOOL_MYSQL_INCLUDE_H__ +#define __ACL_DBPOOL_MYSQL_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_define.h" +#include "db/acl_dbpool.h" + +#ifdef HAS_MYSQL + +/* in acl_dbpool_mysql.c */ + +/** + * 创建一个 mysql 类型的数据库连接池 + * @param db_info 记录着有关连接数据所需要的信息 + * @return DB_POOL * 返回一个能用的连接池句柄 + */ +ACL_DB_POOL *acl_dbpool_mysql_create(const ACL_DB_INFO *db_info); + +/** + * 重新再打开 mysql 连接, 如果重新打开成功, 则同时关闭旧连接, 如果打开 + * 失败, 则保留原连接于 handle 中 + * @param handle {ACL_DB_HANDLE*} + * @return {int} 0: 表示重新打开成功 + */ +int sane_mysql_reopen(ACL_DB_HANDLE *handle); + +#endif /* HAS_MYSQL */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/src/db/null/acl_dbnull.c b/lib_acl/src/db/null/acl_dbnull.c new file mode 100644 index 000000000..7226d5ef7 --- /dev/null +++ b/lib_acl/src/db/null/acl_dbnull.c @@ -0,0 +1,49 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_stdlib.h" +#include "db/acl_dberr.h" + +#endif + +#include "acl_dbnull.h" + +int acl_dbnull_results(ACL_DB_HANDLE *handle acl_unused, + const char *sql acl_unused, int *error acl_unused, + int (*walk_fn)(const void** my_row, void *arg) acl_unused, + void *arg acl_unused) +{ + const char *myname = "acl_dbnull_results"; + + acl_msg_fatal("%s, %s(%d): not supported!", __FILE__, myname, __LINE__); + return (-1); +} + +int acl_dbnull_result(ACL_DB_HANDLE *handle acl_unused, + const char *sql acl_unused, int *error acl_unused, + int (*callback)(const void** my_row, void *arg) acl_unused, + void *arg acl_unused) +{ + const char *myname = "acl_dbnull_result"; + + acl_msg_fatal("%s, %s(%d): not supported!", __FILE__, myname, __LINE__); + return (-1); +} + +int acl_dbnull_update(ACL_DB_HANDLE *handle acl_unused, + const char *sql acl_unused, int *error acl_unused) +{ + const char *myname = "acl_dbnull_update"; + + acl_msg_fatal("%s, %s(%d): not supported!", __FILE__, myname, __LINE__); + return (-1); +} diff --git a/lib_acl/src/db/null/acl_dbnull.h b/lib_acl/src/db/null/acl_dbnull.h new file mode 100644 index 000000000..35699998f --- /dev/null +++ b/lib_acl/src/db/null/acl_dbnull.h @@ -0,0 +1,22 @@ +#ifndef __ACL_DB_NULL_INCLUDE_H__ +#define __ACL_DB_NULL_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_define.h" +#include "db/acl_dbpool.h" + +int acl_dbnull_results(ACL_DB_HANDLE *handle, const char *sql, int *error, + int (*walk_fn)(const void** my_row, void *arg), void *arg); +int acl_dbnull_result(ACL_DB_HANDLE *handle, const char *sql, int *error, + int (*callback)(const void** my_row, void *arg), void *arg); +int acl_dbnull_update(ACL_DB_HANDLE *handle, const char *sql, int *error); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/src/db/null/acl_dbpool_null.c b/lib_acl/src/db/null/acl_dbpool_null.c new file mode 100644 index 000000000..91b26577e --- /dev/null +++ b/lib_acl/src/db/null/acl_dbpool_null.c @@ -0,0 +1,356 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "thread/acl_thread.h" +#include "stdlib/acl_stdlib.h" +#include "net/acl_vstream_net.h" +#include "db/acl_dbpool.h" + +#endif + +#include "acl_dbnull.h" +#include "acl_dbpool_null.h" + +typedef struct ACL_DB_HANDLE_NULL { + ACL_DB_HANDLE handle; + ACL_VSTREAM *connection; +} ACL_DB_HANDLE_NULL; + +typedef struct ACL_DB_POOL_NULL { + ACL_DB_POOL db_pool; + + acl_pthread_mutex_t mutex; + ACL_ARRAY *handles; + time_t when_check; +} ACL_DB_POOL_NULL; + +#define DB_LOCK(mlock) { acl_pthread_mutex_lock(&mlock); } +#define DB_UNLOCK(mlock) { acl_pthread_mutex_unlock(&mlock); } + +/*----------------------------------------------------------------------------*/ +static ACL_DB_HANDLE_NULL *__new_null_handle(void) +{ + ACL_DB_HANDLE_NULL *handle; + + handle = (ACL_DB_HANDLE_NULL *) + acl_mycalloc(1, sizeof(ACL_DB_HANDLE_NULL)); + + handle->handle.sql_results = acl_dbnull_results; + handle->handle.sql_result = acl_dbnull_result; + handle->handle.sql_update = acl_dbnull_update; + + return (handle); +} + +static ACL_DB_HANDLE_NULL *__open_handle(ACL_DB_HANDLE_NULL *handle, + ACL_DB_INFO *db_info) +{ + const char *myname = "__open_handle"; + int reuse_flag = 0; + + if (handle == NULL) + handle = __new_null_handle(); + else + reuse_flag = 1; + + handle->connection = acl_vstream_connect(db_info->db_addr, ACL_BLOCKING, + db_info->conn_timeout, db_info->rw_timeout, db_info->buf_size); + + if (handle->connection == NULL) { + char ebuf[256]; + acl_msg_error("%s, %s(%d): connect addr(%s) error(%s)", + __FILE__, myname, __LINE__, db_info->db_addr, + acl_last_strerror(ebuf, sizeof(ebuf))); + if (!reuse_flag) + acl_myfree(handle); + return (NULL); + } + + handle->handle.status = ACL_DBH_STATUS_READY; + handle->handle.timeout = time(NULL) + db_info->timeout_inter; + handle->handle.ping = time(NULL) + db_info->ping_inter; + + return (handle); +} + +/*----------------------------------------------------------------------------*/ +static void __close_handle(ACL_DB_HANDLE_NULL *handle) +{ + if (handle->connection == NULL) + return; + acl_vstream_close(handle->connection); + handle->connection = NULL; + handle->handle.status = ACL_DBH_STATUS_NULL; + handle->handle.timeout = 0; + handle->handle.ping = 0; +} + +/*----------------------------------------------------------------------------*/ +static int __dbpool_ping_default(ACL_DB_HANDLE *db_handle) +{ + ACL_DB_HANDLE_NULL *handle = (ACL_DB_HANDLE_NULL*) db_handle; + + if (acl_vstream_probe_status(handle->connection) == 0) + return (0); + return (-1); +} + +/*----------------------------------------------------------------------------*/ +static void __dbpool_check(ACL_DB_POOL *db_pool) +{ + ACL_DB_POOL_NULL *pool = (ACL_DB_POOL_NULL*) db_pool; + ACL_DB_HANDLE_NULL *handle; + int i, n, ping_inter; + time_t now = time(NULL); + + ping_inter = pool->db_pool.db_info.ping_inter; + + n = acl_array_size(pool->handles); + + for (i = 0; i < n; i++) { + handle = (ACL_DB_HANDLE_NULL *) acl_array_index(pool->handles, i); + if (handle == NULL) + continue; + if (handle->handle.status != ACL_DBH_STATUS_READY) + continue; + + /* if the connecion is idle timeout ? */ + if (now > handle->handle.timeout) { + __close_handle(handle); + pool->db_pool.db_ready--; + continue; + } + + if (pool->db_pool.dbh_ping == NULL) + continue; + + /* has the ping time reached ? */ + if (now <= handle->handle.ping) + continue; + + if (pool->db_pool.dbh_ping((ACL_DB_HANDLE*) handle) == 0) { + handle->handle.ping = time(NULL) + ping_inter; + } else { + __close_handle(handle); + pool->db_pool.db_ready--; + } + } +} + +/*----------------------------------------------------------------------------*/ +static ACL_DB_HANDLE *__dbpool_peek(ACL_DB_POOL *db_pool) +{ + const char *myname = "__dbpool_peek"; + ACL_DB_POOL_NULL *null_pool = (ACL_DB_POOL_NULL *) db_pool; + ACL_DB_HANDLE_NULL *handle, *handle_slot = NULL; + int i, n; + time_t now; + static time_t last_time; /* 因为在调用此函数时已经上锁, + * 所以此处声明一静态变量是线程安全的. + */ + +#undef RETURN +#define RETURN(_x_) do { \ + now = time(NULL); \ + if (acl_msg_verbose && now - last_time > 5) { \ + acl_msg_info("Database status: max = %d, idle = %d, busy = %d", \ + db_pool->db_max, db_pool->db_ready, db_pool->db_inuse); \ + last_time = now; \ + } \ + DB_UNLOCK(null_pool->mutex); \ + return (_x_); \ +} while (0) + + DB_LOCK(null_pool->mutex); + + if (time(NULL) >= null_pool->when_check) { + int inter = db_pool->db_info.ping_inter > db_pool->db_info.timeout_inter + ? db_pool->db_info.timeout_inter : db_pool->db_info.ping_inter; + + db_pool->dbh_check(db_pool); + null_pool->when_check = time(NULL) + inter; + } + + if (db_pool->db_inuse >= db_pool->db_max) { + acl_msg_warn("%s, %s(%d): all connections be used, reached db_max(%d)", + __FILE__, myname, __LINE__, db_pool->db_max); + RETURN (NULL); + } + + n = acl_array_size(null_pool->handles); + + /* lookup null connection from pool */ + for (i = 0; i < n; i++) { + handle = (ACL_DB_HANDLE_NULL *) + acl_array_index(null_pool->handles, i); + + if (handle == NULL) + continue; + + if (handle->handle.status == ACL_DBH_STATUS_READY) { + handle->handle.status = ACL_DBH_STATUS_INUSE; + db_pool->db_inuse++; + db_pool->db_ready--; + + RETURN ((ACL_DB_HANDLE *) handle); + } else if (handle->handle.status == ACL_DBH_STATUS_NULL + && handle_slot == NULL) + handle_slot = handle; + } + + /* create new connection */ + + handle = __open_handle(handle_slot, &db_pool->db_info); + if (handle == NULL) + RETURN (NULL); + + if (handle_slot == NULL) { + if (acl_array_append(null_pool->handles, (void *) handle) < 0) { + char tbuf[256]; + acl_msg_fatal("%s, %s(%d): append to handles error(%s)", + __FILE__, myname, __LINE__, + acl_last_strerror(tbuf, sizeof(tbuf))); + } + handle->handle.parent = &null_pool->db_pool; + } + handle->handle.status = ACL_DBH_STATUS_INUSE; + db_pool->db_inuse++; + + RETURN ((ACL_DB_HANDLE *) handle); +#ifdef ACL_BCB_COMPILER + return (NULL); +#endif +} + +/*----------------------------------------------------------------------------*/ +static void __dbpool_release(ACL_DB_HANDLE *db_handle) +{ + const char *myname = "__dbpool_release"; + ACL_DB_POOL *db_pool; + ACL_DB_POOL_NULL *null_pool; + ACL_DB_HANDLE_NULL *handle; + int timeout_inter, ping_inter; + + handle = (ACL_DB_HANDLE_NULL *) db_handle; + if (db_handle->status != ACL_DBH_STATUS_INUSE || handle->connection == NULL) { + acl_msg_error("%s, %s(%d): status %s ACL_DBH_STATUS_INUSE, connection %s", + __FILE__, myname, __LINE__, + db_handle->status == ACL_DBH_STATUS_INUSE ? "=" : "!=", + handle->connection ? "not null" : "null"); + return; + } + + db_pool = db_handle->parent; + timeout_inter = db_pool->db_info.timeout_inter; + ping_inter = db_pool->db_info.ping_inter; + + if (db_pool == NULL) + acl_msg_fatal("%s, %s(%d): db_handle's parent is null", + __FILE__, myname, __LINE__); + + null_pool = (ACL_DB_POOL_NULL *) db_pool; + DB_LOCK(null_pool->mutex); + + db_handle->status = ACL_DBH_STATUS_READY; + db_handle->timeout = time(NULL) + timeout_inter; + db_handle->ping = time(NULL) + ping_inter; + + db_pool->db_inuse--; + db_pool->db_ready++; + + DB_UNLOCK(null_pool->mutex); +} +/*----------------------------------------------------------------------------*/ +static void *__dbpool_export(ACL_DB_HANDLE *db_handle) +{ + ACL_DB_HANDLE_NULL *handle = (ACL_DB_HANDLE_NULL *) db_handle; + + return ((void *) handle->connection); +} +/*----------------------------------------------------------------------------*/ +static void __dbpool_close(ACL_DB_HANDLE *db_handle) +{ + const char *myname = "__dbpool_close"; + ACL_DB_POOL *db_pool; + ACL_DB_POOL_NULL *null_pool; + ACL_DB_HANDLE_NULL *handle = (ACL_DB_HANDLE_NULL *) db_handle; + + if (db_handle->status != ACL_DBH_STATUS_INUSE || handle->connection == NULL) { + acl_msg_error("%s, %s(%d): status %s ACL_DBH_STATUS_INUSE, connection %s", + __FILE__, myname, __LINE__, + db_handle->status == ACL_DBH_STATUS_INUSE ? "=" : "!=", + handle->connection ? "not null" : "null"); + return; + } + + db_pool = db_handle->parent; + if (db_pool == NULL) + acl_msg_fatal("%s, %s(%d): db_handle's parent is null", + __FILE__, myname, __LINE__); + null_pool = (ACL_DB_POOL_NULL *) db_pool; + + DB_LOCK(null_pool->mutex); + + __close_handle(handle); + db_pool->db_inuse--; + + DB_UNLOCK(null_pool->mutex); +} +/*----------------------------------------------------------------------------*/ +static void __dbpool_destroy(ACL_DB_POOL *db_pool) +{ + ACL_DB_POOL_NULL *null_pool; + ACL_DB_HANDLE_NULL *handle; + int i, n; + + null_pool = (ACL_DB_POOL_NULL *) db_pool; + + n = acl_array_size(null_pool->handles); + for (i = 0; i < n; i++) { + handle = (ACL_DB_HANDLE_NULL *) + acl_array_index(null_pool->handles, i); + if (handle == NULL) + continue; + __close_handle(handle); + acl_myfree(handle); + } + acl_pthread_mutex_destroy(&null_pool->mutex); + acl_myfree(null_pool); +} +/*----------------------------------------------------------------------------*/ +ACL_DB_POOL *acl_dbpool_null_create(const ACL_DB_INFO *db_info) +{ + const char *myname = "acl_dbpool_null_create"; + ACL_DB_POOL_NULL *null_pool; + + null_pool = (ACL_DB_POOL_NULL *) acl_mycalloc(1, sizeof(ACL_DB_POOL_NULL)); + if (null_pool == NULL) { + char tbuf[256]; + acl_msg_fatal("%s, %s(%d): calloc error=%s", + __FILE__, myname, __LINE__, acl_last_strerror(tbuf, sizeof(tbuf))); + } + + null_pool->db_pool.dbh_peek = &__dbpool_peek; + null_pool->db_pool.dbh_check = &__dbpool_check; + null_pool->db_pool.dbh_release = &__dbpool_release; + null_pool->db_pool.dbh_export = &__dbpool_export; + null_pool->db_pool.dbh_close = &__dbpool_close; + null_pool->db_pool.dbh_ping = &__dbpool_ping_default; + + null_pool->db_pool.destroy = &__dbpool_destroy; + + null_pool->handles = acl_array_create(db_info->db_max); + acl_pthread_mutex_init(&null_pool->mutex, NULL); + + return ((ACL_DB_POOL *) null_pool); +} +/*----------------------------------------------------------------------------*/ diff --git a/lib_acl/src/db/null/acl_dbpool_null.h b/lib_acl/src/db/null/acl_dbpool_null.h new file mode 100644 index 000000000..ea5099c6b --- /dev/null +++ b/lib_acl/src/db/null/acl_dbpool_null.h @@ -0,0 +1,24 @@ + +#ifndef __ACL_DBPOOL_NULL_INCLUDE_H__ +#define __ACL_DBPOOL_NULL_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_define.h" +#include "db/acl_dbpool.h" + +/* in acl_dbpool_null.c */ +/** + * 创建一个 null 类型的数据库连接池 + * @param db_info 记录着有关连接数据所需要的信息 + * @return DB_POOL * 返回一个能用的连接池句柄 + */ +extern ACL_DB_POOL *acl_dbpool_null_create(const ACL_DB_INFO *db_info); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/src/db/zdb/zdb.c b/lib_acl/src/db/zdb/zdb.c new file mode 100644 index 000000000..98a6eb542 --- /dev/null +++ b/lib_acl/src/db/zdb/zdb.c @@ -0,0 +1,386 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "lib_acl.h" +#include "db/zdb.h" + +#endif + +#include "zdb_private.h" + +/*----------------------------------------------------------------------------*/ + +void zdb_init() +{ + /* 初始化文件句柄 */ + acl_fhandle_init(1000, 100, 0); +} + +void zdb_end() +{ + /* 需要关闭所有存储句柄 */ + acl_fhandle_end(); +} + +#define PATH_LEN 256 +#define IDISK_LEN 32 +#define PRIORITY_LEN 32 +#define LIMIT_LEN 32 +#define COUNT_LEN 32 +#define INFO_LEN (PATH_LEN + IDISK_LEN + PRIORITY_LEN + LIMIT_LEN + COUNT_LEN + 2) +#define ITEM_CNT 5 + +/* 存储格式: {path} {idisk} {priority} {limit} {count} */ + +static void free_disk(void *arg) +{ + ZDB_DISK *disk = (ZDB_DISK*) arg; + + if (disk->path) + acl_myfree(disk->path); + acl_myfree(disk); +} + +static ZDB_DISK *zdb_disks_load(const char *dbname, const char *dbpath) +{ + const char *myname = "zdb_disks_load"; + ACL_VSTRING *buf = acl_vstring_alloc(256); + ACL_FILE *fp = NULL; + char disk_info[INFO_LEN + 1]; + ZDB_DISK *disk, *disks; + ACL_ARRAY *a = NULL; + ACL_ITER iter; + int n, i; + +#undef RETURN +#define RETURN(x) do { \ + if (fp) \ + acl_fclose(fp); \ + acl_vstring_free(buf); \ + if (a) \ + acl_array_destroy(a, free_disk); \ + return (x); \ +} while (0) + + acl_vstring_sprintf(buf, "%s/.%s.disk", dbpath, dbname); + fp = acl_fopen(STR(buf), "r"); + if (fp == NULL) { + acl_msg_error("%s(%d): fopen(%s) error(%s)", + myname, __LINE__, STR(buf), acl_last_serror()); + RETURN (NULL); + } + + a = acl_array_create(10); + while (1) { + ACL_ARGV *argv; + + if (acl_fgets_nonl(disk_info, sizeof(disk_info), fp) == NULL) + break; + argv = acl_argv_split(disk_info, "|"); + if (argv->argc != ITEM_CNT) { + acl_msg_error("%s(%d): invalid line(%s)", + myname, __LINE__, disk_info); + acl_argv_free(argv); + continue; + } + disk = (ZDB_DISK*) acl_mycalloc(1, sizeof(ZDB_DISK)); + disk->path = acl_mystrdup(argv->argv[0]); + disk->idisk = atoi(argv->argv[1]); + disk->priority = atoi(argv->argv[2]); + disk->limit = acl_atoui64(argv->argv[3]); + disk->count = acl_atoui64(argv->argv[4]); + if (acl_array_append(a, disk) < 0) + acl_msg_fatal("%s(%d): add disk error(%s)", + myname, __LINE__, acl_last_serror()); + acl_argv_free(argv); + } + + n = acl_array_size(a); + if (n <= 0) { + acl_msg_error("%s(%d): empty array of ZDB_DISK", myname, __LINE__); + RETURN (NULL); + } + + disks = (ZDB_DISK*) acl_mycalloc(n + 1, sizeof(ZDB_DISK)); + i = 0; + acl_foreach(iter, a) { + disk = (ZDB_DISK*) iter.data; + disks[i].limit = disk->limit; + disks[i].count = disk->count; + disks[i].path = acl_mystrdup(disk->path); + disks[i].idisk = disk->idisk; + disks[i].priority = disk->priority; + disks[i].dat_ifiles = NULL; + disks[i].dat_ifiles_size = 0; + if (disks[i].idisk != i) { + acl_msg_error("%s(%d): idisk(%d) != %d invalid for %s", + myname, __LINE__, disks[i].idisk, i, disks[i].path); + acl_myfree(disks); + RETURN (NULL); + } + i++; + } + + disks[i].path = NULL; /* 将最后一个置空表示结束 */ + RETURN (disks); +} + +static void zdb_disks_update(const char *dbname, const char *dbpath, const ZDB_DISK *disks) +{ + const char *myname = "zdb_disks_update"; + ACL_VSTRING *buf = acl_vstring_alloc(256); + ACL_FILE *fp; + char tmp[32]; + int i; + + acl_vstring_sprintf(buf, "%s/.%s.disk", dbpath, dbname); + fp = acl_fopen(STR(buf), "w"); + if (fp == NULL) { + acl_msg_error("%s(%d): fopen(%s) error(%s)", + myname, __LINE__, STR(buf), acl_last_serror()); + acl_vstring_free(buf); + return; + } + + /* 存储格式: {path} {idisk} {priority} {limit} {count} */ + + i = 0; + for (i = 0; disks[i].path != NULL; i++) { + acl_vstring_sprintf(buf, "%s|%d|%d", + disks[i].path, disks[i].idisk, disks[i].priority); + acl_vstring_strcat(buf, "|"); + acl_ui64toa(disks[i].limit, tmp, sizeof(tmp)); + acl_vstring_strcat(buf, tmp); + acl_vstring_strcat(buf, "|"); + acl_ui64toa(disks[i].count, tmp, sizeof(tmp)); + acl_vstring_strcat(buf, tmp); + if (acl_fputs(STR(buf), fp) == EOF) { + acl_msg_error("%s(%d): fputs to %s/%s.disks error(%s)", + myname, __LINE__, dbname, dbpath, acl_last_serror()); + break; + } + } + + acl_vstring_free(buf); + acl_fclose(fp); +} + +int zdb_disk_select(ZDB *db) +{ + const char *myname = "zdb_disk_select"; + int idisk = -1, i; + acl_int64 count = ((acl_int64) 1 << 62); + + for (i = 0; db->dat_disks[i].path != NULL; i++) { + if (db->dat_disks[i].count < count) { + count = db->dat_disks[i].count; + idisk = i; + } + } + + if (idisk == -1) { + acl_msg_error("%s(%d): idisk(%d) < 0, i(%d), no disk available", + myname, __LINE__, idisk, i); + } else { + db->dat_disks[idisk].count++; + } + + return (idisk); +} + +void zdb_sync(ZDB *db) +{ + zdb_disks_update(db->dbname, db->key_path, db->dat_disks); +} + +ZDB *zdb_open(const char *dbname, unsigned int oflags, const ZDB_CFG *cfg) +{ + const char *myname = "zdb_open"; + ZDB *db; + ZDB_DISK *disks; +#ifdef INCLUDE_PATH + int i; + ACL_VSTRING *buf = acl_vstring_alloc(256); +#endif + + /* 先保证存储目录存在 */ + acl_make_dirs(cfg->key_path, 0700); + + disks = zdb_disks_load(dbname, cfg->key_path); + if (disks == NULL) { + acl_msg_error("%s(%d): zdb_disks_load error", + myname, __LINE__); + return (NULL); + } + + db = (ZDB*) acl_mycalloc(1, sizeof(ZDB)); + + db->dbname = acl_mystrdup(dbname); + db->key_path = acl_mystrdup(cfg->key_path); + db->oflags = oflags; + db->dat_disks = disks; + + if (cfg->key_cache_max <= 0 || cfg->key_cache_timeout <= 0) { + db->oflags &=~ZDB_FLAG_CACHE_KEY; + db->key_cache_max = 0; + db->key_cache_timeout = 0; + db->key_wback_max = 0; + } else { + db->key_cache_max = cfg->key_cache_max; + db->key_cache_timeout = cfg->key_cache_timeout; + db->key_wback_max = cfg->key_wback_max; + } + + if (cfg->dat_cache_max <= 0 || cfg->dat_cache_timeout <= 0) { + db->oflags &= ~ZDB_FLAG_CACHE_DAT; + db->dat_cache_max = 0; + db->dat_cache_timeout = 0; + db->dat_wback_max = 0; + } else { + db->dat_cache_max = cfg->dat_cache_max; + db->dat_cache_timeout = cfg->dat_cache_timeout; + db->dat_wback_max = cfg->dat_wback_max; + } + + + db->path_tmp = acl_vstring_alloc(256); + + db->key_begin = cfg->key_begin; + db->key_limit = cfg->key_limit; + + db->dat_limit = cfg->dat_limit; + db->blk_dlen = cfg->blk_dlen; + db->dat_nstep = cfg->dat_nstep; + + db->key_get = zdb_key_get; + db->key_set = zdb_key_set; + db->dat_get = zdb_dat_get; + db->dat_add = zdb_dat_add; + db->dat_update = zdb_dat_update; + +#ifdef INCLUDE_PATH + for (i = 0; i < ZDB_KEY_DIR_LIMIT; i++) { + acl_vstring_sprintf(buf, "%s/%d", cfg->key_path, i); + acl_make_dirs(STR(buf), 0700); + } + acl_vstring_free(buf); +#endif + return (db); +} + +void zdb_close(ZDB *db) +{ + int i; + + zdb_sync(db); /* 先同步磁盘分区信息至磁盘 */ + acl_myfree(db->dbname); + acl_myfree(db->key_path); + acl_vstring_free(db->path_tmp); + + for (i = 0; db->dat_disks[i].path != NULL; i++) { + if (db->dat_disks[i].dat_ifiles) + acl_myfree(db->dat_disks[i].dat_ifiles); + acl_myfree(db->dat_disks[i].path); + } + acl_myfree(db->dat_disks); + acl_myfree(db); +} + +ZDB_BLK *zdb_lookup(ZDB *db, zdb_key_t key, size_t *size_ptr, ZDB_BLK_OFF *blk_off_buf) +{ + const char *myname = "zdb_lookup"; + ZDB_BLK_OFF blk_off; + zdb_key_t key_tmp; + ZDB_BLK *blk; + int ret; + + if (key < db->key_begin) { + acl_msg_error("%s(%d): key(" ACL_FMT_I64D ") < key_begin(" + ACL_FMT_I64D "), invalid", + myname, __LINE__, key, db->key_begin); + return (NULL); + } + + ret = db->key_get(db, key, &blk_off); + if (ret <= 0) + return (NULL); + + blk = db->dat_get(db, &blk_off, &key_tmp, size_ptr); + if (blk == NULL) { + acl_msg_error("%s(%d): zdb_dat_get null for key(" + ACL_FMT_I64D ")", myname, __LINE__, key); + if (blk_off_buf) { + blk_off_buf->offset = -1; + blk_off_buf->inode = -1; + } + return (NULL); + } + + if (blk_off_buf) + memcpy(blk_off_buf, &blk_off, sizeof(blk_off)); + + /* 必须判断键的一致性 */ + + if (key != key_tmp) { + acl_msg_warn("%s(%d): key(" ACL_FMT_I64D ") != key_tmp(" + ACL_FMT_I64D "), blk_off: " ACL_FMT_I64D ", inode: %d", + myname, __LINE__, key, key_tmp, + blk_off.offset, blk_off.inode & DIR_MASK); + zdb_blk_free(blk); + return (NULL); + } + + return (blk); +} + +int zdb_update(ZDB *db, zdb_key_t key, const ZDB_BLK_OFF *blk_off_saved, + const void *dat, size_t len) +{ + const char *myname = "zdb_update"; + ZDB_BLK_OFF blk_off; + int ret; + + if (key < db->key_begin) { + acl_msg_error("%s(%d): key(" ACL_FMT_I64D ") < key_begin(" + ACL_FMT_I64D "), invalid", + myname, __LINE__, key, db->key_begin); + return (-1); + } + + if (dat == NULL) { + acl_msg_error("%s(%d): data null", myname, __LINE__); + return (-1); + } + + if (len <= 0) { + acl_msg_error("%s(%d): len(%d) invalid", myname, __LINE__, (int) len); + return (-1); + } + + /* 可以重复利用传入的 blk_off_saved (此值是上次调用 zdb_lookup 获得) */ + + if (blk_off_saved == NULL || blk_off_saved->offset < 0) { + blk_off_saved = NULL; + ret = db->key_get(db, key, &blk_off); + if (ret < 0) { + acl_msg_error("%s(%d): key_get key(" ACL_FMT_I64D ") error(%s)", + myname, __LINE__, key, acl_last_serror()); + return (-1); + } + if (ret > 0) + blk_off_saved = &blk_off; + } + + if (blk_off_saved == NULL) { + db->status |= ZDB_STAT_KEY_NEW; /* 设置状态位以表明当前为新值 */ + ret = db->dat_add(db, key, dat, len); + db->status &= ~ZDB_STAT_KEY_NEW; /* 清除标志位 */ + } else { + db->status &=~ ZDB_STAT_KEY_NEW; /* 清除标志位表明是修改旧数据 */ + ret = db->dat_update(db, key, blk_off_saved, dat, len); + } + + return (ret); +} + +/*----------------------------------------------------------------------------*/ diff --git a/lib_acl/src/db/zdb/zdb_dat.c b/lib_acl/src/db/zdb/zdb_dat.c new file mode 100644 index 000000000..463bda2c3 --- /dev/null +++ b/lib_acl/src/db/zdb/zdb_dat.c @@ -0,0 +1,1305 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "lib_acl.h" +#include "db/zdb.h" +#include "thread/acl_pthread.h" + +#endif + +#include "zdb_private.h" + +int dat_store_header_sync(ZDB_DAT_STORE *store) +{ + const char *myname = "dat_store_header_sync"; + int ret; + + ret = ZDB_WRITE((ZDB_STORE*) store, &store->hdr, sizeof(store->hdr), 0); + if (ret == -1) + acl_msg_error("%s(%d): zdb_write to %s error(%s)", myname, + __LINE__, STORE_PATH(&store->store), acl_last_serror()); + return (ret); +} + +/** + * 释放 ACL_VSTRING 回调函数 + * @param arg {void*} 回调参数, 可转换成 ACL_VSTRING 对象 + */ +static void free_vstring_fn(void *arg) +{ + ACL_VSTRING *s = (ACL_VSTRING*) arg; + + acl_vstring_free(s); +} + +/** + * 确保 ZDB.dat_ifiles 的数组容量够用 + * @param db {ZDB*} + * @param size {int} 数组容量的大小要求 + */ +static void dat_ifiles_space(ZDB *db, int idisk, int size) +{ + int i; + + /* xxx: 只所以加1是因为下标是从1开始的, 而 C 语言中的数组下载是从 0 开始的, + * 所以说 db->dat_disks[0] 是给浪费掉了 :( --- zsx + */ + size++; + + if (db->dat_disks[idisk].dat_ifiles == NULL) { + if (size < 16) + size = 16; + db->dat_disks[idisk].dat_ifiles = (int*) + acl_mycalloc(size, sizeof(int)); + db->dat_disks[idisk].dat_ifiles_size = size; + return; + } + + if (size < db->dat_disks[idisk].dat_ifiles_size) + return; + db->dat_disks[idisk].dat_ifiles = (int*) + acl_myrealloc(db->dat_disks[idisk].dat_ifiles, size * sizeof(int)); + + for (i = db->dat_disks[idisk].dat_ifiles_size; i < size; i++) + db->dat_disks[idisk].dat_ifiles[i] = 0; + db->dat_disks[idisk].dat_ifiles_size = size; +} + +/** + * 计算值存储的相对路径号 + * @param db {ZDB*} + * @param len {int} 数据的长度 + * @return {int} >= 0: ok; -1: error + */ +static int dat_inode(ZDB *db, int len) +{ + const char *myname = "dat_inode"; + int inode; + + /* 所给的长度必须为基础块的整数倍 */ + + if (len % db->blk_dlen != 0) { + acl_msg_error("%s(%d): len(%d) %% db->blk_dlen(%d) != 0, invalid", + myname, __LINE__, len, db->blk_dlen); + return (-1); + } + + /* 根据数据块长度计算出基础块的个数, 同时也是存储文件所在目录的标识号 */ + + inode = len / db->blk_dlen; + if (inode > DIR_LIMIT) { + acl_msg_error("%s(%d): inode(%d) > %u, too large", + myname, __LINE__, inode, DIR_LIMIT); + return (-1); + } + + return (inode); +} + +/** + * 获得值存储的文件全路径 + * @param db {ZDB*} + * @param buf {ACL_VSTRING*} 存储结果的缓冲区 + * @param inode {int} 路径号 + * @param ifile {int} 文件号 + * @return {ACL_VSTRING*} 结果缓冲区地址 + **/ +static ACL_VSTRING *dat_filepath(ZDB *db, ACL_VSTRING *buf, int idisk, int inode, int ifile) +{ + static acl_pthread_key_t buf_key = ACL_TLS_OUT_OF_INDEXES; + ACL_VSTRING *buf_safe; + static ACL_VSTRING *__buf_unsafe = NULL; + + buf_safe = (ACL_VSTRING*) acl_pthread_tls_get(&buf_key); + if (buf_safe == NULL) { + if (buf_key == (acl_pthread_key_t) ACL_TLS_OUT_OF_INDEXES) { + if (__buf_unsafe == NULL) + __buf_unsafe = acl_vstring_alloc(256); + buf_safe = __buf_unsafe; + } else { + buf_safe = acl_vstring_alloc(256); + acl_pthread_tls_set(buf_key, buf_safe, free_vstring_fn); + } + } + + if (buf == NULL) + buf = buf_safe; + +#ifdef INCLUDE_PATH + acl_vstring_sprintf(buf, "%s/%d/%s_%d_%d.dat", + db->dat_disks[idisk].path, inode, db->dbname, inode, ifile); +#else + acl_vstring_sprintf(buf, "%s/%s_%d_%d.dat", + db->dat_disks[idisk].path, db->dbname, inode, ifile); +#endif + return (buf); +} + +/** + * 获得文件的所在路径 + * @param db {ZDB*} + * @param buf {ACL_VSTRING*} 存储结果的缓冲区 + * @param inode {int} 路径号 + * @return {ACL_VSTRING*} 结果缓冲区地址 + */ +static ACL_VSTRING *dat_path(ZDB *db, ACL_VSTRING *buf, int idisk, int inode acl_unused) +{ + static acl_pthread_key_t buf_key = (acl_pthread_key_t) ACL_TLS_OUT_OF_INDEXES; + ACL_VSTRING *buf_safe; + static ACL_VSTRING *__buf_unsafe = NULL; + + buf_safe = (ACL_VSTRING*) acl_pthread_tls_get(&buf_key); + if (buf_safe == NULL) { + if (buf_key == (acl_pthread_key_t) ACL_TLS_OUT_OF_INDEXES) { + if (__buf_unsafe == NULL) + __buf_unsafe = acl_vstring_alloc(256); + buf_safe = __buf_unsafe; + } else { + buf_safe = acl_vstring_alloc(256); + acl_pthread_tls_set(buf_key, buf_safe, free_vstring_fn); + } + } + + if (buf == NULL) + buf = buf_safe; + +#ifdef INCLUDE_PATH + acl_vstring_sprintf(buf, "%s/%d", db->dat_disks[idisk].path, inode); +#else + acl_vstring_sprintf(buf, "%s", db->dat_disks[idisk].path); +#endif + + return (buf); +} + +#ifdef ZDB_LINK_BUSY + +/** + * 将新的占用块链接到占用链中 + * @param store {ZDB_DAT_STORE*} + * @param blk {ZDB_BLK*} + * @parem ilnk {zdb_lnk_t} + * @return {int} 0: ok; -1: error + */ +static int busy_blk_link(ZDB_DAT_STORE *store, ZDB_BLK *blk, zdb_lnk_t ilnk) +{ + const char *myname = "busy_blk_link"; + ZDB_BLK *hdr_blk = NULL; + zdb_off_t off; + int ret, blk_len; + +#undef RETURN +#define RETURN(x) do { \ + if (hdr_blk) \ + zdb_blk_free(hdr_blk); \ + return (x); \ +} while (0) + + if (store->hdr.itail_busy == -1) { + if (store->hdr.ihead_busy != -1) { + acl_msg_error("%s(%d): %s, ihead_busy(%d) != -1", + myname, __LINE__, STORE_PATH((ZDB_STORE*) store), + store->hdr.ihead_busy); + RETURN (-1); + } + store->hdr.itail_busy = ilnk; + store->hdr.ihead_busy = ilnk; + blk->hdr.inext_busy = -1; + blk->hdr.iprev_busy = -1; + RETURN (0); + } else if (store->hdr.ihead_busy == -1) { + acl_msg_error("%s(%d): %s, ihead_busy(%d) invalid", myname, + __LINE__, STORE_PATH((ZDB_STORE*) store), + store->hdr.ihead_busy); + RETURN (-1); + } + + off = BLK_HDR_OFF(store, store->hdr.ihead_busy); + if (off <= 0) { + acl_msg_error("%s(%d): %s, off(" ACL_FMT_I64D ") invalid", + myname, __LINE__, STORE_PATH((ZDB_STORE*) store), off); + RETURN (-1); + } + + blk_len = BLK_LEN(store); + hdr_blk = (ZDB_BLK*) acl_mymalloc(blk_len); + ret = ZDB_READ((ZDB_STORE*) store, hdr_blk, blk_len, off); + if (ret == -1) { + acl_msg_error("%s(%d): zdb_read %s error(%s)", myname, __LINE__, + STORE_PATH((ZDB_STORE*) store), acl_last_serror()); + RETURN (-1); + } + + if (hdr_blk->hdr.blk_ilnk != store->hdr.ihead_busy) { + acl_msg_error("%s(%d): %s, blk_ilnk(%d) != ihead_busy(%d)", + myname, __LINE__, STORE_PATH((ZDB_STORE*) store), + hdr_blk->hdr.blk_ilnk, store->hdr.ihead_busy); + RETURN (-1); + } + + hdr_blk->hdr.iprev_busy = ilnk; + blk->hdr.inext_busy = store->hdr.ihead_busy; + blk->hdr.iprev_busy = -1; + store->hdr.ihead_busy = ilnk; /* 更新占用块链头 */ + + /* 更新某占用块的头信息 */ + ret = ZDB_WRITE((ZDB_STORE*) store, hdr_blk, blk_len, off); + if (ret == -1) { + acl_msg_error("%s(%d): zdb_write to %s error(%s)", + myname, __LINE__, STORE_PATH((ZDB_STORE*) store), + acl_last_serror()); + RETURN (-1); + } + + RETURN (0); +} + +static int busy_blk_unlink(ZDB_DAT_STORE *store, ZDB_BLK *blk, zdb_lnk_t ilnk) +{ + const char *myname = "busy_blk_unlink"; + ZDB_BLK_HDR *blk_hdr = NULL; + zdb_off_t off; + int ret; + +#undef RETURN +#define RETURN(x) do { \ + if (blk_hdr) \ + acl_myfree(blk_hdr); \ + return (x); \ +} while (0) + + if (ilnk < 0) { + acl_msg_error("%s(%d): %s, ilnk(%d) invalid", + myname, __LINE__, STORE_PATH((ZDB_STORE*) store), ilnk); + RETURN (-1); + } + + if (store->hdr.ihead_busy == -1) { + acl_msg_error("%s(%d): ihead_busy(%d) invalid", + myname, __LINE__, store->hdr.ihead_busy); + RETURN (-1); + } else if (store->hdr.itail_busy == -1) { + acl_msg_error("%s(%d): itail_busy(%d) invalid", + myname, __LINE__, store->hdr.itail_busy); + RETURN (-1); + } + + if (blk->hdr.iprev_busy == -1) { + /* 该占用块应该是头部块 */ + + if (store->hdr.ihead_busy != ilnk) { + acl_msg_error("%s(%d): %s, ihead_busy(%d) != ilnk(%d)", + myname, __LINE__, STORE_PATH((ZDB_STORE*) store), + store->hdr.ihead_busy, ilnk); + RETURN (-1); + } + if (store->hdr.itail_busy == ilnk) { + /* 说明该 blk 是最后一个占用块了 */ + + store->hdr.ihead_busy = store->hdr.itail_busy = -1; + blk->hdr.inext_busy = blk->hdr.iprev_busy = -1; + RETURN (0); + } else if (blk->hdr.inext_busy < 0) { + acl_msg_error("%s(%d): %s, inext_busy(%d) invalid", + myname, __LINE__, STORE_PATH((ZDB_STORE*) store), + blk->hdr.inext_busy); + RETURN (-1); + } + + blk_hdr = (ZDB_BLK_HDR*) acl_mymalloc(sizeof(ZDB_BLK_HDR)); + off = BLK_HDR_OFF(store, blk->hdr.inext_busy); + ret = ZDB_READ((ZDB_STORE*) store, blk_hdr, sizeof(ZDB_BLK_HDR), off); + if (ret == -1) { + acl_msg_error("%s(%d): zdb_read %s error(%s)", + myname, __LINE__, STORE_PATH((ZDB_STORE*) store), + acl_last_serror()); + RETURN (-1); + } else if (blk_hdr->blk_ilnk != blk->hdr.inext_busy) { + acl_msg_error("%s(%d): blk_ilnk(%d) != inext_busy(%d)", + myname, __LINE__, blk_hdr->blk_ilnk, + blk->hdr.inext_busy); + RETURN (-1); + } + + blk_hdr->iprev_busy = -1; + ret = ZDB_WRITE((ZDB_STORE*) store, blk_hdr, sizeof(ZDB_BLK_HDR), off); + if (ret == -1) { + acl_msg_error("%s(%d): zdb_write %s error(%s)", + myname, __LINE__, STORE_PATH((ZDB_STORE*) store), + acl_last_serror()); + RETURN (-1); + } + + store->hdr.ihead_busy = blk_hdr->blk_ilnk; + RETURN (0); + } + + if (blk->hdr.inext_busy == -1) { + /* 说明该占用块应该为尾部块 */ + + if (store->hdr.itail_busy != ilnk) { + acl_msg_error("%s(%d): %s, itail_busy(%d) != ilnk(%d)", + myname, __LINE__, STORE_PATH((ZDB_STORE*) store), + store->hdr.itail_busy, ilnk); + RETURN (-1); + } + + /* xxx: sanity check */ + if (store->hdr.ihead_busy == ilnk) { + /* 说明该 blk 是最后一个占用块了 */ + + store->hdr.ihead_busy = store->hdr.itail_busy = -1; + blk->hdr.inext_busy = blk->hdr.iprev_busy = -1; + RETURN (0); + } else if (blk->hdr.iprev_busy < 0) { + acl_msg_error("%s(%d): %s, iprev_busy(%d) invalid", + myname, __LINE__, STORE_PATH((ZDB_STORE*) store), + blk->hdr.iprev_busy); + RETURN (-1); + } + + blk_hdr = (ZDB_BLK_HDR*) acl_mymalloc(sizeof(ZDB_BLK_HDR)); + off = BLK_HDR_OFF(store, blk->hdr.iprev_busy); + ret = ZDB_READ((ZDB_STORE*) store, blk_hdr, sizeof(ZDB_BLK_HDR), off); + if (ret == -1) { + acl_msg_error("%s(%d): zdb_read %s error(%s)", + myname, __LINE__, STORE_PATH((ZDB_STORE*) store), + acl_last_serror()); + RETURN (-1); + } else if (blk_hdr->blk_ilnk != blk->hdr.iprev_busy) { + acl_msg_error("%s(%d): blk_ilnk(%d) != iprev_busy(%d)", + myname, __LINE__, blk_hdr->blk_ilnk, + blk->hdr.iprev_busy); + RETURN (-1); + } + + blk_hdr->inext_busy = -1; + ret = ZDB_WRITE((ZDB_STORE*) store, blk_hdr, sizeof(ZDB_BLK_HDR), off); + if (ret == -1) { + acl_msg_error("%s(%d): zdb_write %s error(%s)", + myname, __LINE__, STORE_PATH((ZDB_STORE*) store), + acl_last_serror()); + RETURN (-1); + } + + store->hdr.itail_busy = blk_hdr->blk_ilnk; + RETURN (0); + } + + /* 说明该占用块应该为中间块 */ + + /* 更新后一个占用块的头信息 */ + + blk_hdr = (ZDB_BLK_HDR*) acl_mymalloc(sizeof(ZDB_BLK_HDR)); + off = BLK_HDR_OFF(store, blk->hdr.inext_busy); + ret = ZDB_READ((ZDB_STORE*) store, blk_hdr, sizeof(ZDB_BLK_HDR), off); + if (ret == -1) { + acl_msg_error("%s(%d): zdb_read %s error(%s)", + myname, __LINE__, STORE_PATH((ZDB_STORE*) store), + acl_last_serror()); + RETURN (-1); + } else if (blk_hdr->blk_ilnk != blk->hdr.inext_busy) { + acl_msg_error("%s(%d): blk_ilnk(%d) != inext_busy(%d)", + myname, __LINE__, blk_hdr->blk_ilnk, + blk->hdr.inext_busy); + RETURN (-1); + } + + blk_hdr->iprev_busy = blk->hdr.iprev_busy; + ret = ZDB_WRITE((ZDB_STORE*) store, blk_hdr, sizeof(ZDB_BLK_HDR), off); + if (ret == -1) { + acl_msg_error("%s(%d): zdb_write %s error(%s)", + myname, __LINE__, STORE_PATH((ZDB_STORE*) store), + acl_last_serror()); + RETURN (-1); + } + + /* 更新前一个占用块的头信息 */ + + off = BLK_HDR_OFF(store, blk->hdr.iprev_busy); + ret = ZDB_READ((ZDB_STORE*)store, blk_hdr, sizeof(ZDB_BLK_HDR), off); + if (ret == -1) { + acl_msg_error("%s(%d): zdb_read %s error(%s)", + myname, __LINE__, STORE_PATH((ZDB_STORE*) store), + acl_last_serror()); + RETURN (-1); + } else if (blk_hdr->blk_ilnk != blk->hdr.iprev_busy) { + acl_msg_error("%s(%d): blk_ilnk(%d) != iprev_busy(%d)", + myname, __LINE__, blk_hdr->blk_ilnk, + blk->hdr.iprev_busy); + RETURN (-1); + } + + blk_hdr->inext_busy = blk->hdr.inext_busy; + ret = ZDB_WRITE((ZDB_STORE*) store, blk_hdr, sizeof(ZDB_BLK_HDR), off); + if (ret == -1) { + acl_msg_error("%s(%d): zdb_write %s error(%s)", + myname, __LINE__, STORE_PATH((ZDB_STORE*) store), + acl_last_serror()); + RETURN (-1); + } + + blk->hdr.inext_busy = blk->hdr.iprev_busy = 1; + RETURN (0); +} + +#endif /* ZDB_LINK_BUSY */ + +/** + * 增加并初始化值存储的数据块 + * @param store {ZDB_DAT_STORE*} 值存储句柄 + * @param count {acl_int64} 增加的数据块个数 + * @return {int} 0: ok; -1: error + */ +static int dat_store_blk_add(ZDB_DAT_STORE *store, acl_int64 count) +{ + const char *myname = "dat_store_blk_add"; + ZDB_BLK *blk; + acl_int64 i; + int ret; + + /* 检查输入是否合法 */ + if (count <= 0) { + acl_msg_error("%s(%d): count(" ACL_FMT_I64D ") invalid", + myname, __LINE__, count); + return (-1); + } + + /* 检查是否已经达到分配限制个数 */ + if (store->hdr.size >= store->hdr.limit) { + acl_msg_error("%s(%d): store(%s)'s size(" ACL_FMT_I64D + ") >= limit(" ACL_FMT_I64D ")", + myname, __LINE__, STORE_PATH((ZDB_STORE*) store), + store->hdr.size, store->hdr.limit); + return (-1); + } + + count += store->hdr.size; /* 将 count 设为最大值 */ + if (count > store->hdr.limit) + count = store->hdr.limit; /* 必须保证不能超过限制 */ + + if ((((ZDB_STORE*) store)->db->oflags & ZDB_FLAG_CACHE_DAT) == 0) { + /* 将文件指针置尾 */ + if (acl_vstream_fseek(((ZDB_STORE*) store)->fhandle.fp, 0, SEEK_END) < 0) { + acl_msg_error("%s(%d): fseek %s error(%s)", + myname, __LINE__, STORE_PATH((ZDB_STORE*) store), + acl_last_serror()); + return (-1); + } + } + + /* 计算真实的 ZDB_BLK 的空间大小并分配一个新的 ZDB_BLK 对象 */ + blk = (ZDB_BLK*) acl_mycalloc(1, (size_t) BLK_LEN(store)); + + /* 顺序初始化值存储中的各个数据块, 并形成单向链 */ + + if ((((ZDB_STORE*) store)->db->oflags & ZDB_FLAG_CACHE_DAT) == 0) { + for (i = store->hdr.size; i < count; i++) { + blk->hdr.inext_idle = (zdb_lnk_t) i + 1; + /* 当达到最大值时表示下一个位置无效 */ + if (blk->hdr.inext_idle == count) + blk->hdr.inext_idle = -1; + blk->hdr.blk_ilnk = (zdb_lnk_t) i; /* 标识自己的索引位置号, 校验用 */ + blk->hdr.inext_idle = store->hdr.ihead_idle; /* 与链连接 */ + blk->hdr.key = -1; /* 所有的初始键为 -1 */ + +#ifdef ZDB_LINK_BUSY + blk->hdr.inext_busy = -1; + blk->hdr.iprev_busy = -1; +#endif + + store->hdr.ihead_idle = (zdb_lnk_t) i; /* 更新值存储头的头空闲指针 */ + + ret = acl_vstream_buffed_writen(((ZDB_STORE*) store)->fhandle.fp, + blk, (size_t) BLK_LEN(store)); + if (ret == ACL_VSTREAM_EOF) { + acl_myfree(blk); + acl_msg_error("%s(%d): write to %s error(%s)", myname, + __LINE__, STORE_PATH((ZDB_STORE*) store), + acl_last_serror()); + return (-1); + } + } + + } else { + for (i = store->hdr.size; i < count; i++) { + blk->hdr.inext_idle = (zdb_lnk_t) i + 1; + /* 当达到最大值时表示下一个位置无效 */ + if (blk->hdr.inext_idle == count) + blk->hdr.inext_idle = -1; + blk->hdr.blk_ilnk = (zdb_lnk_t) i; /* 标识自己的索引位置号, 校验用 */ + blk->hdr.inext_idle = store->hdr.ihead_idle; /* 与链连接 */ + blk->hdr.key = -1; /* 所有的初始键为 -1 */ + +#ifdef ZDB_LINK_BUSY + blk->hdr.inext_busy = -1; + blk->hdr.iprev_busy = -1; +#endif + + store->hdr.ihead_idle = (zdb_lnk_t) i; /* 更新值存储头的头空闲指针 */ + + ret = ZDB_WRITE((ZDB_STORE*) store, blk, (size_t) BLK_HDR_LEN(store), + BLK_HDR_OFF(store, i)); /* 只需初始化块头信息 */ + if (ret == ACL_VSTREAM_EOF) { + acl_myfree(blk); + acl_msg_error("%s(%d): write to %s error(%s)", myname, + __LINE__, STORE_PATH((ZDB_STORE*) store), + acl_last_serror()); + return (-1); + } + } + } + + acl_myfree(blk); + + if ((((ZDB_STORE*) store)->db->oflags & ZDB_FLAG_CACHE_DAT) == 0) { + /* 刷新写的缓冲区至磁盘 */ + if (acl_vstream_fflush(((ZDB_STORE*)store)->fhandle.fp) == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): fflush to %s error %s", + myname, __LINE__, STORE_PATH((ZDB_STORE*) store), + acl_last_serror()); + return (-1); + } + } + + store->hdr.size = count; /* 更新值存储总分配的数据块个数 */ + return (0); +} + +/** + * 初始化值存储 + * @param store {ZDB_DAT_STORE*} 值存储句柄 + * @param db {ZDB*} ZDB 句柄 + * @return {int} 0: ok; -1: error + */ +static int dat_store_init(ZDB_DAT_STORE *store, ZDB *db) +{ + const char *myname = "dat_store_init"; + int ret; + + /* 初始化值存储的头信息 */ + + store->hdr.limit = db->dat_limit; + store->hdr.nstep = db->dat_nstep > 0 ? db->dat_nstep : (int) db->dat_limit; + store->hdr.size = 0; + store->hdr.count = 0; + store->hdr.blk_hdr_dlen = sizeof(ZDB_BLK_HDR); + store->hdr.blk_dlen = db->blk_dlen; + store->hdr.blk_count = db->blk_count_tmp; + store->hdr.ihead_idle = -1; /* 指向一个空位置 */ + +#ifdef ZDB_LINK_BUSY + store->hdr.ihead_busy = -1; /* 没有占用数据块 */ + store->hdr.itail_busy = -1; /* 没有占用数据块 */ +#endif + + if ((((ZDB_STORE*) store)->db->oflags & ZDB_FLAG_CACHE_DAT) == 0) + ret = acl_vstream_buffed_writen(((ZDB_STORE*) store)->fhandle.fp, + &store->hdr, sizeof(store->hdr)); + else + ret = ZDB_WRITE((ZDB_STORE*) store, &store->hdr, sizeof(store->hdr), 0); + + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): write header to %s error(%s)", + myname, __LINE__, STORE_PATH((ZDB_STORE*) store), + acl_last_serror()); + return (-1); + } + + return (0); +} + +/** + * 打开值存储文件句柄时的回调函数 + * @param fh {ACL_FHANDLE*} 文件句柄 + * @param arg {void*} 参数 + * @return {int} 0: ok; -1: error + */ +static int dat_store_on_open(ACL_FHANDLE *fh, void *arg) +{ + const char *myname = "dat_store_on_open"; + ZDB_DAT_STORE *store = (ZDB_DAT_STORE*) fh; + ZDB *db = (ZDB*) arg; + int ret; + + if (fh->size != sizeof(ZDB_DAT_STORE)) + acl_msg_fatal("%s: fh->size(%d) != ZDB_DAT_STORE's size(%d)", + myname, (int) fh->size, (int) sizeof(ZDB_DAT_STORE)); + ((ZDB_STORE*) store)->db = db; + ((ZDB_STORE*) store)->flag = STORE_FLAG_DAT; + if ((db->oflags & ZDB_FLAG_SLICE_DAT)) + ((ZDB_STORE*) store)->flag |= STORE_FLAG_IO_SLICE; + + /* 如果是新文件则初始化 */ + + if (fh->fsize == 0) { + acl_debug(ZDB_DBG_DAT, 1) ("%s: begin init %s ...", + myname, STORE_PATH((ZDB_STORE*) store)); + if (dat_store_init(store, db) < 0) { + acl_msg_error("%s(%d): %s, dat_store_init error", + myname, __LINE__, STORE_PATH((ZDB_STORE*) store)); + return (-1); + } + acl_debug(ZDB_DBG_DAT, 1) ("%s: init %s ok", + myname, STORE_PATH((ZDB_STORE*) store)); + + if ((db->oflags & ZDB_FLAG_CACHE_DAT) != 0) { + ((ZDB_STORE*) store)->cache_max = db->dat_cache_max; + ((ZDB_STORE*) store)->cache_timeout = db->dat_cache_timeout; + ((ZDB_STORE*) store)->wback_max = db->dat_wback_max; + zdb_io_cache_open((ZDB_STORE*) store, (size_t) BLK_LEN(store)); + } + + /* 开始添加并初始化值存储中的数据块 */ + if (dat_store_blk_add(store, store->hdr.nstep) < 0) { + acl_msg_error("%s(%d): dat_store_blk_add error", + myname, __LINE__); + return (-1); + } + zdb_dat_iter_set(store, 1); + return (0); + } + + /* 如果是旧文件则读取文件头信息, 且应进行检验 */ + + if ((((ZDB_STORE*) store)->db->oflags & ZDB_FLAG_CACHE_DAT) == 0) + ret = acl_vstream_readn(((ZDB_STORE*) store)->fhandle.fp, + &store->hdr, sizeof(store->hdr)); + else + ret = ZDB_READ((ZDB_STORE*) store, &store->hdr, sizeof(store->hdr), 0); + + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): %s, read key header from %s error(%s)", + myname, __LINE__, __FILE__, STORE_PATH((ZDB_STORE*) store), acl_last_serror()); + return (-1); + } + + if ((db->oflags & ZDB_FLAG_CACHE_DAT) != 0) { + ((ZDB_STORE*) store)->cache_max = db->dat_cache_max; + ((ZDB_STORE*) store)->cache_timeout = db->dat_cache_timeout; + ((ZDB_STORE*) store)->wback_max = db->dat_wback_max; + zdb_io_cache_open((ZDB_STORE*) store, (size_t) BLK_LEN(store)); + } + + zdb_dat_iter_set(store, 1); + return (0); +} + +/** + * 关闭值存储文件句柄时的回调函数 + * @param fh {ACL_FHANDLE*} 文件句柄 + */ +static void dat_store_on_close(ACL_FHANDLE *fh) +{ + const char *myname = "dat_store_on_close"; + ZDB_DAT_STORE *store = (ZDB_DAT_STORE*) fh; + + dat_store_header_sync(store); + zdb_io_cache_close((ZDB_STORE*) store); + acl_debug(ZDB_DBG_DAT, 2) ("%s(%d): sync header ok, close %s now", + myname, __LINE__, STORE_PATH((ZDB_STORE*) store)); +} + +void zdb_dat_store_close(ZDB_DAT_STORE *store) +{ + acl_fhandle_close(&((ZDB_STORE*) store)->fhandle, 120); +} + +ZDB_DAT_STORE *zdb_dat_store_open(ZDB *db, const char *filepath) +{ + const char *myname = "zdb_dat_store_open"; + ZDB_DAT_STORE *store; + unsigned int oflags = ACL_FHANDLE_O_NOATIME /* | ACL_FHANDLE_O_DIRECT */; + + if ((db->oflags & ZDB_FLAG_OPEN_LOCK) != 0) + oflags |= ACL_FHANDLE_O_MLOCK; + + acl_vstring_strcpy(db->path_tmp, filepath); + store = (ZDB_DAT_STORE*) acl_fhandle_open(sizeof(ZDB_DAT_STORE), oflags, + filepath, dat_store_on_open, db, dat_store_on_close); + if (store == NULL) + acl_msg_error("%s(%d): open file(%s) error(%s)", + myname, __LINE__, filepath, acl_last_serror()); + return (store); +} + +ZDB_BLK *zdb_dat_get(ZDB *db, const ZDB_BLK_OFF *blk_off, zdb_key_t *key, size_t *size) +{ + const char *myname = "zdb_dat_get"; + int idisk, inode, ifile, ret, blk_dlen; + ZDB_DAT_STORE *store; + const ACL_VSTRING *path; + zdb_lnk_t blk_ilnk; + zdb_off_t off; + ZDB_BLK *blk; + + idisk = (blk_off->inode >> DIR_BITS) & DISK_MASK; + if (idisk < 0 || idisk > DISK_LIMIT) { + acl_msg_error("%s(%d): idisk(%d) invalid", + myname, __LINE__, idisk); + return (NULL); + } + + inode = blk_off->inode & DIR_MASK; + if (inode < 0 || inode > DIR_LIMIT) { + acl_msg_error("%s(%d): inode(%d) invalid", + myname, __LINE__, inode); + return (NULL); + } + + /* 判断在值存储中的偏移值 */ + if (blk_off->offset < 0) { + acl_msg_error("%s(%d): blk_off_old(" ACL_FMT_I64D ") invalid", + myname, __LINE__, blk_off->offset); + return (NULL); + } + + ifile = (int) blk_off->offset / (int) db->dat_limit; /* 文件结点号 */ + + path = dat_filepath(db, NULL, idisk, inode, ifile); + store = zdb_dat_store_open(db, STR(path)); + if (store == NULL) { + acl_msg_error("%s(%d): open %s error(%s)", + myname, __LINE__, STR(path), acl_last_serror()); + return (NULL); + } + + /* 计算在文件中的真实位置 */ + + blk_ilnk = (int) blk_off->offset - (zdb_lnk_t) db->dat_limit * ifile; /* 文件位置索引值 */ + off = BLK_HDR_OFF(store, blk_ilnk); + + /* 计算真实的 ZDB_BLK 的空间大小 */ + + blk_dlen = (int) BLK_LEN(store); + + /* 分配一个 ZDB_BLK 对象 */ + + blk = (ZDB_BLK*) acl_mycalloc(1, blk_dlen); + + ret = ZDB_READ((ZDB_STORE*) store, blk, blk_dlen, off); + + acl_debug(ZDB_DBG_GETD, 2) + ("%s(%d): %s, zdb_read(%d), blk_off: " ACL_FMT_I64D + ", idisk: %d, inode: %d," + " ifile: %d, ilnk: %d, dat_limit: " ACL_FMT_I64D ", blk_dlen: %d", + myname, __LINE__, STORE_PATH((ZDB_STORE*) store), ret, off, + idisk, inode, ifile, blk_ilnk, db->dat_limit, blk_dlen); + + if (ret == -1) { + acl_msg_error("%s(%d): zdb_read %s error(%s), blk_off(" + ACL_FMT_I64D "), blk_dlen(%d), idisk: %d, inode: %d, ifile: %d", + myname, __LINE__, STORE_PATH((ZDB_STORE*) store), + acl_last_serror(), off, blk_dlen, + idisk, inode, ifile); + zdb_blk_free(blk); + zdb_dat_store_close(store); /* 关闭值存储 */ + return (NULL); + } + + zdb_dat_store_close(store); /* 关闭值存储 */ + + if (key) + *key = blk->hdr.key; + if (size) + *size = (size_t) (BLK_LEN(store) - BLK_HDR_LEN(store)); + return (blk); +} + +int zdb_dat_add(ZDB *db, zdb_key_t key, const void *dat, int len) +{ + const char *myname = "zdb_dat_add"; + ZDB_DAT_STORE *store = NULL, *store_tmp; + int n, blk_dlen, idisk, inode, ifile; + ZDB_BLK *blk = NULL; + ZDB_BLK_OFF blk_off; + zdb_off_t off; + zdb_lnk_t ilnk; + const ACL_VSTRING *path; + +#undef RETURN +#define RETURN0(x) do { \ + return ((x)); \ +} while (0) + +#define RETURN(x) do { \ + if (store) \ + zdb_dat_store_close(store); \ + if (blk) \ + zdb_blk_free(blk); \ + return ((x)); \ +} while (0) + + inode = dat_inode(db, len); + if (inode < 0) { + acl_msg_error("%s(%d): inode(%d) invalid, dat len(%d)", + myname, __LINE__, inode, len); + RETURN (-1); + } + + /* xxx: 因为每个目录号值与该目录下值存储的数据中的数据块个数相等 */ + db->blk_count_tmp = inode; /* xxx: 设置此临时量主要为了参数传递 */ + + /* 尝试遍历该存储目录下所有可用的存储文件: 有可能是旧文件, 也有可能是新文件 */ + + idisk = zdb_disk_select(db); + if (idisk < 0) { + acl_msg_error("%s(%d): no disk available", myname, __LINE__); + RETURN (-1); + } + + dat_ifiles_space(db, idisk, inode); /* 确保 db->dat_ifiles 数组空间够用 */ + ifile = db->dat_disks[idisk].dat_ifiles[inode]; + if (ifile < 0) + ifile = 0; + + /* 选择可用的值存储句柄 */ + + for (; ifile < ZDB_DAT_FILE_LIMIT; ifile++) { + path = dat_filepath(db, NULL, idisk, inode, ifile); + acl_debug(ZDB_DBG_ADDD, 2) ("%s(%d): path(%s)", + myname, __LINE__, STR(path)); + store_tmp = zdb_dat_store_open(db, STR(path)); + if (store_tmp == NULL) { + acl_msg_error("%s(%d): zdb_dat_store_open %s error(%s)", + myname, __LINE__, STR(path), acl_last_serror()); + RETURN (-1); + } + + /* 是否有可用空闲块? */ + + if (store_tmp->hdr.limit <= store_tmp->hdr.count) { + /* 关闭已满了的值存储 */ + zdb_dat_store_close(store_tmp); + continue; + } + + /* 如果需要增加值存储空间则增加 */ + if (store_tmp->hdr.size <= store_tmp->hdr.count) { + n = dat_store_blk_add(store_tmp, store_tmp->hdr.nstep); + if (n < 0) { + acl_msg_error("%s(%d): add blk to %s error", + myname, __LINE__, + STORE_PATH((ZDB_STORE*) store_tmp)); + zdb_dat_store_close(store_tmp); + RETURN (-1); + } + } + + store = store_tmp; + db->dat_disks[idisk].dat_ifiles[inode] = ifile; /* 缓存该文件索引号 */ + break; + } + + if (store == NULL) { + acl_msg_error("%s(%d): too many ifile(%d), ZDB_DAT_FILE_LIMIT(%d)," + " idisk(%d), inode(%d), path(%s)", myname, __LINE__, ifile, + ZDB_DAT_FILE_LIMIT, idisk, inode, + acl_sane_dirname(NULL, STR(dat_path(db, NULL, idisk, inode)))); + RETURN (-1); + } + + if (store->hdr.ihead_idle < 0) { + acl_msg_error("%s(%d): %s, ihead_idle(%d) invalid, limit(" + ACL_FMT_I64D "), count(" ACL_FMT_I64D ")", myname, + __LINE__, STORE_PATH((ZDB_STORE*) store), + store->hdr.ihead_idle, store->hdr.limit, + store->hdr.count); + RETURN (-1); + } + + /* 使用第一个空闲块 */ + ilnk = store->hdr.ihead_idle; + + /* 计算真实的 ZDB_BLK 的空间大小 */ + blk_dlen = (int) BLK_LEN(store); + + /* 计算第一个空闲块的物理位置 */ + off = BLK_HDR_OFF(store, ilnk); + + acl_debug(ZDB_DBG_ADDD, 2) + ("%s(%d): blk_count: %d, blk_dlen: %d, blk_off(" ACL_FMT_I64D + "), blk_hdr_dlen: %d, len: %d", myname, __LINE__, + store->hdr.blk_count, store->hdr.blk_dlen, + off, store->hdr.blk_hdr_dlen, len); + + /* 分配一个 ZDB_BLK 对象 */ + blk = (ZDB_BLK*) acl_mymalloc(blk_dlen); + if (blk == NULL) + acl_msg_fatal("%s(%d): calloc error(%s)", + myname, __LINE__, acl_last_serror()); + + /* 读取该空闲数据块头信息 */ + n = ZDB_READ((ZDB_STORE*) store, blk, (size_t) BLK_HDR_LEN(store), off); + if (n == -1) { + acl_msg_error("%s(%d): zdb_read %s error(%s), ihead_idle(%d)," + " blk_dlen(%d), blk_off(" ACL_FMT_I64D "), blk_hdr_dlen(%d)", + myname, __LINE__, STORE_PATH((ZDB_STORE*) store), + acl_last_serror(), ilnk, blk_dlen, off, + store->hdr.blk_hdr_dlen); + RETURN (-1); + } + + /* xxx: 该 blk 其实就是第一个空闲块, 参见上面 ilnk 的形成 */ + + blk->hdr.key = key; + store->hdr.ihead_idle = blk->hdr.inext_idle; /* 更新空闲块链头 */ + blk->hdr.inext_idle = -1; /* 从空闲块链中分离 */ + +#ifdef ZDB_LINK_BUSY + if ((db->oflags & ZDB_FLAG_LINK_BUSY) != 0) { + if (busy_blk_link(store, blk, ilnk) < 0) + RETURN (-1); + } +#endif + + acl_debug(ZDB_DBG_ADDD, 2) + ("%s(%d): blk_off: " ACL_FMT_I64D ", inext: %d, key: " + ACL_FMT_I64D, myname, __LINE__, off, ilnk, key); + + /* 更新当前空闲数据块信息 */ + + memcpy(blk->dat, dat, len); /* 拷贝源数据内容 */ + + n = ZDB_WRITE((ZDB_STORE*) store, blk, blk_dlen, off); /* 更新数据块信息 */ + if (n == -1) { + acl_msg_error("%s(%d): zdb_write to %s error(%s)", + myname, __LINE__, STORE_PATH((ZDB_STORE*) store), + acl_last_serror()); + RETURN (-1); + } + + /* 更新值存储头信息 */ + + store->hdr.count++; + + /* 将 blk_off 映射为键存储中的值 */ + + blk_off.offset = ilnk + db->dat_limit * ifile; /* 累加之前所有的文件中记录的值个数之和 */ + if (blk_off.offset < 0) { + acl_msg_error("%s(%d): blk_off.offset(" ACL_FMT_I64D + ") too large", myname, __LINE__, blk_off.offset); + RETURN (-1); + } + + acl_debug(ZDB_DBG_ADDD, 2) + ("%s(%d): blk_off: " ACL_FMT_I64D ", ihead_idle: %d, dat_limit: " + ACL_FMT_I64D ", inode: %d, ifile: %d", + myname, __LINE__, blk_off.offset, store->hdr.ihead_idle, + db->dat_limit, inode, ifile); + + /* 将 idisk 与 inode 组合存储 */ + blk_off.inode = (idisk << DIR_BITS) + inode; + + /* 更新键存储中数据索引值 */ + if (db->key_set(db, key, &blk_off) < 0) { + acl_msg_error("%s(%d): set key store error(%s)", + myname, __LINE__, acl_last_serror()); + RETURN (-1); + } + + RETURN (1); +} + +int zdb_dat_update(ZDB *db, zdb_key_t key, const ZDB_BLK_OFF *blk_off, + const void *dat, size_t len) +{ + const char *myname = "zdb_dat_update"; + int idisk, inode, inode_new, ifile, ret; + const ACL_VSTRING *path; + ZDB_DAT_STORE *store = NULL; + zdb_lnk_t ilnk; + zdb_off_t off; + ZDB_BLK *blk = NULL; + +#undef RETURN +#define RETURN(x) do { \ + if (store) \ + zdb_dat_store_close(store); \ + if (blk) \ + zdb_blk_free(blk); \ + return (x); \ +} while (0) + + idisk = (blk_off->inode >> DIR_BITS) & DISK_MASK; + if (idisk < 0 || idisk > DISK_LIMIT) { + acl_msg_error("%s(%d): idisk(%d) invalid", + myname, __LINE__, idisk); + RETURN (-1); + } + + inode = blk_off->inode & DIR_MASK; + if (inode < 0 || inode > DIR_LIMIT) { + acl_msg_error("%s(%d): inode(%d) invalid", + myname, __LINE__, inode); + RETURN (-1); + } + + /* 判断在值存储中的偏移值 */ + if (blk_off->offset < 0) { + acl_msg_error("%s(%d): blk_off_old(" ACL_FMT_I64D + ") invalid", myname, __LINE__, blk_off->offset); + RETURN (-1); + } + + /* 计算新的 inode 相对路径号 */ + inode_new = dat_inode(db, len); + if (inode_new < 0) { + acl_msg_error("%s(%d): inode(%d) invalid, dat len(%d)", + myname, __LINE__, inode_new, (int) len); + RETURN (-1); + } + + ifile = (int) blk_off->offset / (int) db->dat_limit; /* 文件结点号 */ + + /* 文件位置索引值 */ + ilnk = (zdb_lnk_t) (blk_off->offset - db->dat_limit * ifile); + + path = dat_filepath(db, NULL, idisk, inode, ifile); + store = zdb_dat_store_open(db, STR(path)); + if (store == NULL) { + acl_msg_error("%s(%d): open %s error(%s)", + myname, __LINE__, STR(path), acl_last_serror()); + RETURN (-1); + } + + if (inode_new == inode) { + /* 更新旧位置的数据信息 */ + + /* 计算真实的存储位置中数据起始位置值 */ + off = BLK_DAT_OFF(store, ilnk); + + /* 写入新数据 */ + ret = ZDB_WRITE((ZDB_STORE*) store, dat, len, off); + + if (ret == -1) { + acl_msg_error("%s(%d): zdb_write to %s error(%s)", + myname, __LINE__, STR(path), acl_last_serror()); + RETURN (-1); + } + RETURN (1); + } + + /* 需要移动数据块数据至其它值存储中 */ + + /* 该值存储中肯定就有占用数据块 */ + + if (store->hdr.count <= 0) { + acl_msg_error("%s(%d): %s, store->hdr.count(" ACL_FMT_I64D + ") <= 0, ihead_idle(%d), inode(%d, %d), inode_new(%d, %d)," + " key(" ACL_FMT_I64D "), blk_off(" ACL_FMT_I64D ")", + myname, __LINE__, STORE_PATH((ZDB_STORE*) store), + store->hdr.count, store->hdr.ihead_idle, + idisk, inode, inode_new >> DISK_BITS, + inode_new & DIR_MASK, key, blk_off->offset); + store->hdr.count = 0; /* xxx: reset to 0 */ + RETURN (-1); + } + + /* 计算真实的存储位置中数据块头起始位置值 */ + off = BLK_HDR_OFF(store, ilnk); + + /* 需要移动值的位置且使旧位置变为空闲块 */ + + blk = (ZDB_BLK*) acl_mymalloc((size_t) BLK_LEN(store)); /* 分配数据块 */ + + /* 读取该占用数据块的头部信息 */ + ret = ZDB_READ((ZDB_STORE*) store, blk, (size_t) BLK_HDR_LEN(store), off); + if (ret == -1) { + acl_msg_error("%s(%d): zdb_read %s error(%s)," + " blk_hdr_dlen(%d), blk_off(" ACL_FMT_I64D ")", + myname, __LINE__, STORE_PATH((ZDB_STORE*) store), + acl_last_serror(), (int) BLK_HDR_LEN(store), blk_off->offset); + RETURN (-1); + } + + blk->hdr.key = -1; + blk->hdr.inext_idle = store->hdr.ihead_idle; /* 与空闲数据块链连接 */ + +#ifdef ZDB_LINK_BUSY + if ((db->oflags & ZDB_FLAG_LINK_BUSY) != 0) { + if (busy_blk_unlink(store, blk, ilnk) < 0) { + acl_msg_error("%s(%d): %s, unlink busy blk error", + myname, __LINE__, STORE_PATH((ZDB_STORE*) store)); + RETURN (-1); + } + } +#endif + + /* 更新值存储头信息 */ + + store->hdr.ihead_idle = ilnk; + store->hdr.count--; + + /* 调整缓存的文件索引号 */ + + dat_ifiles_space(db, idisk, inode); + if (inode < db->dat_disks[idisk].dat_ifiles[inode]) + db->dat_disks[idisk].dat_ifiles[inode] = inode; + + /* 只写数据块的头部信息, 将该数据块变为空闲块 */ + ret = ZDB_WRITE((ZDB_STORE*) store, blk, (size_t) BLK_HDR_LEN(store), off); + if (ret == -1) { + acl_msg_error("%s(%d): prwrite %s error(%s), blk_off(" + ACL_FMT_I64D ", " ACL_FMT_I64D ")", + myname, __LINE__, STR(path), + acl_last_serror(), blk_off->offset, off); + RETURN (-1); + } + + db->dat_disks[idisk].count--; /* 将所在磁盘分区的分配数量减 1 */ + if (db->dat_disks[idisk].count < 0) { + acl_msg_error("%s(%d): count(%lld) < 0 in %s", + myname, __LINE__, db->dat_disks[idisk].count, + db->dat_disks[idisk].path); + RETURN (-1); + } + + /* 向另一个值存储中添加新记录 */ + + ret = zdb_dat_add(db, key, dat, len); + RETURN (ret); +} + +int zdb_dat_stat(ZDB *db, const char *filepath, ZDB_DAT_HDR *dat_hdr) +{ + const char *myname = "zdb_dat_stat"; + ZDB_DAT_STORE *store; + + store = zdb_dat_store_open(db, filepath); + if (store == NULL) { + acl_msg_error("%s(%d): open %s error(%s)", + myname, __LINE__, filepath, acl_last_serror()); + return (-1); + } + + memcpy(dat_hdr, &store->hdr, sizeof(ZDB_DAT_HDR)); + zdb_dat_store_close(store); + return (0); +} + +int zdb_dat_check(ZDB_DAT_STORE *store, ZDB_DAT_HDR *dat_hdr) +{ + const char *myname = "zdb_dat_check"; + acl_int64 nidle = 0, nused = 0; + ZDB_BLK *blk; + zdb_lnk_t ilnk; + zdb_off_t blk_off; + int blk_len, ret, failed = 0; + ACL_ITER iter; + time_t begin; + + acl_msg_info("%s(%d): %s: checking ......", + myname, __LINE__, STORE_PATH((ZDB_STORE*) store)); + acl_msg_info("%s(%d):\tHDR STATUS:", myname, __LINE__); + acl_msg_info("%s(%d):\tlimit: " ACL_FMT_I64D ", size: " + ACL_FMT_I64D ", count: " ACL_FMT_I64D, + myname, __LINE__, store->hdr.limit, + store->hdr.size, store->hdr.count); + acl_msg_info("%s(%d):\tnstep: %d, blk_hdr_dlen: %d, blk_dlen: %d," + " blk_count: %d", myname, __LINE__, store->hdr.nstep, + store->hdr.blk_hdr_dlen, store->hdr.blk_dlen, + store->hdr.blk_count); + acl_msg_info("%s(%d):\tihead_idle: %d, ihead_busy: %d", + myname, __LINE__, store->hdr.ihead_idle, store->hdr.ihead_busy); + + if (dat_hdr) + memcpy(dat_hdr, &store->hdr, sizeof(ZDB_DAT_HDR)); + + /* 扫描所有被使用的数据块结点 */ + + acl_msg_info("%s(%d):\tBegin check used blk ......", myname, __LINE__); + + time(&begin); + + /* 仅检查数据块的头 */ + zdb_dat_iter_set(store, 1); + acl_foreach(iter, (ZDB_STORE*) store) { + nused++; + if (nused > 0 && nused % 10000 == 0) { + ZDB_BLK_HDR *blk_hdr = (ZDB_BLK_HDR*) iter.data; + + printf("\tnused: " ACL_FMT_I64D ", key: " + ACL_FMT_I64D ", dlen: %d, ", + nused, blk_hdr->key, iter.dlen); + ACL_METER_TIME("-"); + } + } + + if (nused != store->hdr.count) { + acl_msg_error("%s(%d):\terror, nused(" ACL_FMT_I64D + ") != store->hdr.count(" ACL_FMT_I64D + ") for %s, please repair it!, time: %ld", myname, __LINE__, + nused, store->hdr.count, STORE_PATH((ZDB_STORE*) store), + (long) (time(NULL) - begin)); + failed = 1; + } else { + acl_msg_info("%s(%d):\tOk, check used blk over, busy blk: " + ACL_FMT_I64D ", time: %ld", + myname, __LINE__, store->hdr.count, time(NULL) - begin); + } + + /* 允许遍历数据块的数据体 */ + zdb_dat_iter_set(store, 1); + + /* 开始扫描所有的空闲数据块结点 */ + + acl_msg_info("%s(%d):\tBegin check idle blk ......", myname, __LINE__); + + time(&begin); + + ret = 0; + blk_len = (int) BLK_LEN(store); + blk = (ZDB_BLK*) acl_mymalloc(blk_len); + ilnk = store->hdr.ihead_idle; + while (ilnk >= 0) { + blk_off = BLK_HDR_OFF(store, ilnk); + ret = ZDB_READ((ZDB_STORE*) store, blk, blk_len, blk_off); + if (ret == -1) { + acl_msg_error("%s(%d): zdb_read %s error(%s), blk_off(" + ACL_FMT_I64D ")", myname, __LINE__, + STORE_PATH((ZDB_STORE*) store), + acl_last_serror(), blk_off); + failed = 1; + break; + } + ilnk = blk->hdr.inext_idle; + nidle++; + } + + if (ret >= 0 && nidle == store->hdr.size - store->hdr.count) + acl_msg_info("%s(%d):\tOk, check idle blk over , idle blk: " + ACL_FMT_I64D ", time: %ld", + myname, __LINE__, nidle, time(NULL) - begin); + else { + acl_msg_error("%s(%d):\tcheck idle blk error for %s, time: %ld", + myname, __LINE__, STORE_PATH((ZDB_STORE*) store), time(NULL) - begin); + acl_msg_error("%s(%d): \tret: %d, idle blk: " ACL_FMT_I64D + ", store->hdr.size - store->hdr.count: " ACL_FMT_I64D, + myname, __LINE__, ret, nidle, + store->hdr.size - store->hdr.count); + failed = 1; + } + + zdb_blk_free(blk); + + return (failed ? -1 : 0); +} + +int zdb_dat_check3(ZDB *db, const char *filepath, ZDB_DAT_HDR *dat_hdr) +{ + const char *myname = "zdb_dat_check3"; + ZDB_DAT_STORE *store; + int ret; + + store = zdb_dat_store_open(db, filepath); + if (store == NULL) { + acl_msg_error("%s(%d): open %s error(%s)", + myname, __LINE__, filepath, acl_last_serror()); + return (-1); + } + + ret = zdb_dat_check(store, dat_hdr); + zdb_dat_store_close(store); + return (ret); +} diff --git a/lib_acl/src/db/zdb/zdb_dat_iter.c b/lib_acl/src/db/zdb/zdb_dat_iter.c new file mode 100644 index 000000000..15811581f --- /dev/null +++ b/lib_acl/src/db/zdb/zdb_dat_iter.c @@ -0,0 +1,382 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "lib_acl.h" +#include "db/zdb.h" + +#endif + +#include "zdb_private.h" + +typedef struct { + ZDB_BLK *blk; + int blk_len; +} BLK_CTX_T; + +static void dummy(void *ptr acl_unused) +{ + +} + +static void free_tls(void *ptr) +{ + BLK_CTX_T *ctx = (BLK_CTX_T*) ptr; + acl_myfree(ctx->blk); + acl_myfree(ctx); +} + +static void *__tls = NULL; +static void main_free_tls(void) +{ + if (__tls) { + BLK_CTX_T *ctx = (BLK_CTX_T*) __tls; + acl_myfree(ctx->blk); + acl_myfree(ctx); + __tls = NULL; + } +} + +static acl_pthread_key_t once_key; +static void once_init(void) +{ + if ((unsigned long) acl_pthread_self() == acl_main_thread_self()) { + acl_pthread_key_create(&once_key, dummy); + atexit(main_free_tls); + } else + acl_pthread_key_create(&once_key, free_tls); +} + +static acl_pthread_once_t once_control = ACL_PTHREAD_ONCE_INIT; +static BLK_CTX_T *tls_alloc(int len) +{ + BLK_CTX_T *ptr; + + (void) acl_pthread_once(&once_control, once_init); + ptr = (BLK_CTX_T*) acl_pthread_getspecific(once_key); + if (ptr == NULL) { + ptr = acl_mymalloc(sizeof(BLK_CTX_T)); + ptr->blk = acl_mymalloc(len); + ptr->blk_len = len; + acl_pthread_setspecific(once_key, ptr); + if ((unsigned long) acl_pthread_self() == acl_main_thread_self()) + __tls = ptr; + return ptr; + } else if (ptr->blk_len >= len) + return ptr; + + acl_myfree(ptr->blk); + ptr->blk = acl_mymalloc(len); + ptr->blk_len = len; + return ptr; +} + +static const void *dat_iter_get_next(ZDB_DAT_STORE *store, ACL_ITER *iter) +{ + const char *myname = "dat_iter_get_next"; + zdb_off_t blk_off; + int ret; + int blk_len = (int) BLK_LEN(store); + BLK_CTX_T *ctx = tls_alloc(blk_len); + ZDB_BLK *blk = ctx->blk; + + for (; iter->i < store->hdr.size; iter->i++) { + blk_off = BLK_HDR_OFF(store, iter->i); + ret = ZDB_READ((ZDB_STORE*) store, blk, blk_len, blk_off); + if (ret == -1 ) { + acl_msg_error("%s(%d): zdb_read %s error, blk_off(" + ACL_FMT_I64D ")", myname, __LINE__, + STORE_PATH((ZDB_STORE*) store), blk_off); + iter->data = iter->ptr = NULL; + return (NULL); + } + if (blk->hdr.key == -1) { + iter->data = iter->ptr = NULL; + return (NULL); + } + + iter->data = iter->ptr = blk; + iter->dlen = blk_len; + iter->i++; /* 保留下一个索引位置 */ + return (iter->ptr); + } + + iter->data = iter->ptr = NULL; + return (NULL); +} + +/** + * 获得迭代器头部数据 + * @param iter {ACL_ITER*} 迭代器指针 + * @return {const void*} 数据地址 + */ +static const void *dat_iter_head(ACL_ITER *iter, struct ZDB_DAT_STORE *store) +{ +#ifdef ZDB_LINK_BUSY + const char *myname = "dat_iter_head"; + zdb_off_t blk_off; + int ret; + int blk_len = (int) BLK_LEN(store); + BLK_CTX_T *ctx = tls_alloc(blk_len); + ZDB_BLK *blk = ctx->blk; +#endif + + iter->key = NULL; + iter->klen = 0; + + if (!(((ZDB_STORE*) store)->db->oflags & ZDB_FLAG_LINK_BUSY)) { + iter->i = 0; + return (dat_iter_get_next(store, iter)); + } + +#ifdef ZDB_LINK_BUSY + if (store->hdr.ihead_busy < 0) { + iter->data = iter->ptr = NULL; + return (NULL); + } + + blk_off = BLK_HDR_OFF(store, store->hdr.ihead_busy); + ret = ZDB_READ((ZDB_STORE*) store, __blk, blk_len, blk_off); + if (ret == -1) { + acl_msg_error("%s(%d): zdb_read %s error(%s), blk_off(" + ACL_FMT_I64D ")", myname, __LINE__, + STORE_PATH((ZDB_STORE*) store), blk_off); + iter->data = iter->ptr = NULL; + return (NULL); + } + iter->data = iter->ptr = blk; + iter->dlen = blk_len; + iter->i = (int) blk->hdr.inext_busy; /* 保留下一个索引位置 */ + return (iter->ptr); +#else + iter->i = 0; + return (dat_iter_get_next(store, iter)); +#endif +} + +/** + * 获得迭代器的那一个数据 + * @param iter {ACL_ITER*} 迭代器指针 + * @return {const void*} 数据地址 + */ +static const void *dat_iter_next(ACL_ITER *iter, struct ZDB_DAT_STORE *store) +{ +#ifdef ZDB_LINK_BUSY + const char *myname = "dat_iter_next"; + zdb_off_t blk_off; + int ret; + int blk_len = (int) BLK_LEN(store); + BLK_CTX_T *ctx = tls_alloc(blk_len); + ZDB_BLK *blk = ctx->blk; +#endif + + if (!(((ZDB_STORE*) store)->db->oflags & ZDB_FLAG_LINK_BUSY)) { + return (dat_iter_get_next(store, iter)); + } + +#ifdef ZDB_LINK_BUSY + + if (iter->i < 0) { + iter->data = iter->ptr = NULL; + return (NULL); + } + + blk_off = BLK_HDR_OFF(store, iter->i); + ret = ZDB_READ((ZDB_STORE*) store, __blk, blk_len, blk_off); + if (ret == -1) { + acl_msg_error("%s(%d): zdb_read %s error(%s), blk_off(" + ACL_FMT_I64D ")", myname, __LINE__, + STORE_PATH((ZDB_STORE*) store), blk_off); + iter->data = iter->ptr = NULL; + return (NULL); + } + iter->data = iter->ptr = blk; + iter->dlen = blk_len; + iter->i = (int) blk->hdr.inext_busy; /* 保留下一个索引位置 */ + return (iter->ptr); +#else + return (dat_iter_get_next(store, iter)); +#endif +} + +/************************************************************************/ + +static void dummy2(void *ptr acl_unused) +{ + +} + +static void free_tls2(void *ptr) +{ + acl_myfree(ptr); +} + +static void *__tls2 = NULL; +static void main_free_tls2(void) +{ + if (__tls2) { + acl_myfree(__tls2); + __tls2 = NULL; + } +} + +static acl_pthread_key_t once_key2; +static void once_init2(void) +{ + if ((unsigned long) acl_pthread_self() == acl_main_thread_self()) { + acl_pthread_key_create(&once_key2, dummy2); + atexit(main_free_tls2); + } else + acl_pthread_key_create(&once_key2, free_tls2); +} + +static acl_pthread_once_t once_control2 = ACL_PTHREAD_ONCE_INIT; +static ZDB_BLK_HDR *get_blk_hdr(void) +{ + ZDB_BLK_HDR *ptr; + + (void) acl_pthread_once(&once_control2, once_init2); + ptr = (ZDB_BLK_HDR*) acl_pthread_getspecific(once_key2); + if (ptr == NULL) { + ptr = (ZDB_BLK_HDR *) acl_mymalloc(sizeof(ZDB_BLK_HDR)); + acl_pthread_setspecific(once_key2, ptr); + if ((unsigned long) acl_pthread_self() == acl_main_thread_self()) + __tls2 = ptr; + } + return ptr; +} + +static const void *hdr_iter_get_next(ZDB_DAT_STORE *store, ACL_ITER *iter) +{ + const char *myname = "hdr_iter_get_next"; + zdb_off_t blk_off; + int ret; + int hdr_len = (int) BLK_HDR_LEN(store); + ZDB_BLK_HDR *blk_hdr = get_blk_hdr(); + + for (; iter->i < store->hdr.size; iter->i++) { + blk_off = BLK_HDR_OFF(store, iter->i); + ret = ZDB_READ((ZDB_STORE*) store, blk_hdr, hdr_len, blk_off); + if (ret == -1 ) { + acl_msg_error("%s(%d): zdb_read %s error, blk_off(" + ACL_FMT_I64D ")", myname, __LINE__, + STORE_PATH((ZDB_STORE*) store), blk_off); + iter->data = iter->ptr = NULL; + return (NULL); + } + if (blk_hdr->key == -1) { + iter->data = iter->ptr = NULL; + return (NULL); + } + + iter->data = iter->ptr = blk_hdr; + iter->dlen = hdr_len; + iter->i++; /* 保留下一个索引位置 */ + return (iter->ptr); + } + + iter->data = iter->ptr = NULL; + return (NULL); +} + +/** + * 获得迭代器头部数据 + * @param iter {ACL_ITER*} 迭代器指针 + * @return {const void*} 数据地址 + */ +static const void *hdr_iter_head(ACL_ITER *iter, struct ZDB_DAT_STORE *store) +{ +#ifdef ZDB_LINK_BUSY + const char *myname = "hdr_iter_head"; + zdb_off_t blk_off; + int ret; + ZDB_BLK_HDR *blk_hdr = get_blk_hdr(); + int hdr_len = (int) BLK_HDR_LEN(store); +#endif + + iter->key = NULL; + iter->klen = 0; + + if (!(((ZDB_STORE*) store)->db->oflags & ZDB_FLAG_LINK_BUSY)) { + iter->i = 0; + return (hdr_iter_get_next(store, iter)); + } + +#ifdef ZDB_LINK_BUSY + if (store->hdr.ihead_busy < 0) { + iter->data = iter->ptr = NULL; + return (NULL); + } + + blk_off = BLK_HDR_OFF(store, store->hdr.ihead_busy); + ret = ZDB_READ((ZDB_STORE*) store, &__blk_hdr, hdr_len, blk_off); + if (ret == -1) { + acl_msg_error("%s(%d): zdb_read %s error(%s), blk_off(" + ACL_FMT_I64D ")", myname, __LINE__, + STORE_PATH((ZDB_STORE*) store), blk_off); + iter->data = iter->ptr = NULL; + return (NULL); + } + iter->data = iter->ptr = blk_hdr; + iter->dlen = hdr_len; + iter->i = (int) blk_hdr->inext_busy; /* 保留下一个索引位置 */ + return (iter->ptr); +#else + iter->i = 0; + return (hdr_iter_get_next(store, iter)); +#endif +} + +/** + * 获得迭代器的那一个数据 + * @param iter {ACL_ITER*} 迭代器指针 + * @return {const void*} 数据地址 + */ +static const void *hdr_iter_next(ACL_ITER *iter, struct ZDB_DAT_STORE *store) +{ +#ifdef ZDB_LINK_BUSY + const char *myname = "hdr_iter_next"; + zdb_off_t blk_off; + ZDB_BLK_HDR *blk_hdr = get_blk_hdr(); + int ret; + int hdr_len = (int) BLK_HDR_LEN(store); +#endif + + if (!(((ZDB_STORE*) store)->db->oflags & ZDB_FLAG_LINK_BUSY)) { + return (hdr_iter_get_next(store, iter)); + } + +#ifdef ZDB_LINK_BUSY + + if (iter->i < 0) { + iter->data = iter->ptr = NULL; + return (NULL); + } + + blk_off = BLK_HDR_OFF(store, iter->i); + ret = ZDB_READ((ZDB_STORE*) store, &__blk_hdr, hdr_len, blk_off); + if (ret == -1) { + acl_msg_error("%s(%d): zdb_read %s error(%s), blk_off(" + ACL_FMT_I64D ")", myname, __LINE__, + STORE_PATH((ZDB_STORE*) store), blk_off); + iter->data = iter->ptr = NULL; + return (NULL); + } + iter->data = iter->ptr = blk_hdr; + iter->dlen = hdr_len; + iter->i = (int) blk_hdr->inext_busy; /* 保留下一个索引位置 */ + return (iter->ptr); +#else + return (hdr_iter_get_next(store, iter)); +#endif +} + +void zdb_dat_iter_set(ZDB_DAT_STORE *store, int read_data) +{ + if (read_data) { + ((ZDB_STORE*) store)->iter_head = (STORE_ITER) dat_iter_head; + ((ZDB_STORE*) store)->iter_next = (STORE_ITER) dat_iter_next; + } else { + ((ZDB_STORE*) store)->iter_head = (STORE_ITER) hdr_iter_head; + ((ZDB_STORE*) store)->iter_next = (STORE_ITER) hdr_iter_next; + } +} diff --git a/lib_acl/src/db/zdb/zdb_dat_walk.c b/lib_acl/src/db/zdb/zdb_dat_walk.c new file mode 100644 index 000000000..469168c5e --- /dev/null +++ b/lib_acl/src/db/zdb/zdb_dat_walk.c @@ -0,0 +1,79 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "lib_acl.h" +#include "db/zdb.h" + +#endif + +#include "zdb_private.h" + +static int zdb_dat_scan_path(ZDB *db, const char *path, + int (*walk_fn)(ZDB_DAT_STORE *store)) +{ + const char *myname = "zdb_dat_scan_path"; + ZDB_DAT_STORE *store; + ACL_SCAN_DIR *scan; + const char *fname; + char pathbuf[256]; + int ret = 0; + + scan = acl_scan_dir_open(path, 1); + if (scan == NULL) { + acl_msg_error("%s(%d): open dir %s error(%s)", + myname, __LINE__, path, acl_last_serror()); + return (-1); + } + + while (1) { + fname = acl_scan_dir_next_file(scan); + if (fname == NULL) { + acl_msg_info("%s(%d): scan over for %s", + myname, __LINE__, path); + break; + } + if (strrncasecmp(fname, ".dat", 4) != 0) { + acl_msg_info("%s(%d): skip %s/%s", myname, + __LINE__, acl_scan_dir_path(scan), fname); + continue; + } + snprintf(pathbuf, sizeof(pathbuf), "%s/%s", + acl_scan_dir_path(scan), fname); + store = zdb_dat_store_open(db, pathbuf); + if (store == NULL) { + acl_msg_error("%s(%d): open file(%s) error(%s)", + myname, __LINE__, pathbuf, acl_last_serror()); + break; + } + + ret = walk_fn(store); + zdb_dat_store_close(store); + + if (ret < 0) { + acl_msg_error("%s(%d): walk_fn ret: %d, break", + myname, __LINE__, ret); + break; + } + } + + acl_scan_dir_close(scan); + return (ret); +} + +int zdb_dat_walk(ZDB *db, int (*walk_fn)(ZDB_DAT_STORE *store)) +{ + const char *myname = "zdb_dat_walk"; + int ret = 0, i; + + for (i = 0; db->dat_disks[i].path != NULL; i++) { + acl_msg_info("%s(%d): begin scan %s", + myname, __LINE__, db->dat_disks[i].path); + ret = zdb_dat_scan_path(db, db->dat_disks[i].path, walk_fn); + acl_msg_info("%s(%d): scan %s end\n", + myname, __LINE__, db->dat_disks[i].path); + if (ret < 0) + break; + } + + return (ret); +} diff --git a/lib_acl/src/db/zdb/zdb_io.c b/lib_acl/src/db/zdb/zdb_io.c new file mode 100644 index 000000000..45187f1e3 --- /dev/null +++ b/lib_acl/src/db/zdb/zdb_io.c @@ -0,0 +1,423 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef ACL_LINUX +# define __USE_UNIX98 +# include + +# define PWRITE pwrite64 +# define PREAD pread64 + +#else +# undef PWRITE +# undef PREAD +#endif + +#include "db/zdb.h" + +#endif + +#include "zdb_private.h" + +#define KEY_LEN 21 + +typedef struct ZDB_IO_BLK { + zdb_off_t off; + avl_node_t node; + char *dat; + size_t dlen; + unsigned int flag; +#define BLK_F_DIRTY (1 << 0) + + ZDB_IO *io; +} ZDB_IO_BLK; + +struct ZDB_IO { + avl_tree_t blk_tree; /* 存储所有需要同步至磁盘的缓存数据块 */ + ACL_CACHE *blk_cache; /* 存储所有缓存数据块 */ + size_t blk_len; + ACL_SLICE *blk_slice; + ACL_SLICE *dat_slice; + ACL_VSTRING *buf; + ZDB_STORE *store; +}; + +#define IO_STREAM(io) ((io)->store->fhandle.fp) +#define IO_HANDLE(io) (ACL_VSTREAM_FILE(IO_STREAM((io)))) +#define IO_PATH(io) (STORE_PATH((io)->store)) + +static int __n = 0; + +static void io_blk_free(ZDB_IO_BLK *blk) +{ + const char *myname = "io_blk_free"; + int ret; + + if ((blk->flag & BLK_F_DIRTY)) { + ZDB_IO *io = blk->io; + + avl_remove(&io->blk_tree, blk); + +#ifdef PWRITE + ret = PWRITE(IO_HANDLE(io), blk->dat, blk->dlen, blk->off); + if (ret != (int) blk->dlen) { + acl_msg_error("%s(%d): pwrite to %s error(%s)," + " ret(%d) != len(%d), off: " ACL_FMT_I64D, + myname, __LINE__, PATH(IO_STREAM(io)), + acl_last_serror(), ret, + (int) blk->dlen, blk->off); + } +#else + if (acl_vstream_fseek(IO_STREAM(io), blk->off, SEEK_SET) < 0) { + acl_msg_error("%s(%d): fseek %s error(%s), off: " ACL_FMT_I64D, + myname, __LINE__, IO_PATH(io), + acl_last_serror(), blk->off); + } else if ((ret = acl_vstream_writen(IO_STREAM(io), blk->dat, blk->dlen)) + == ACL_VSTREAM_EOF) + { + acl_msg_error("%s(%d): readn from %s, ret(%d) != size(%d)," + " off(" ACL_FMT_I64D "), error(%s)", myname, __LINE__, + IO_PATH(io), ret, (int) blk->dlen, + blk->off, acl_last_serror()); + } +#endif + } + + if (blk->io->dat_slice) + acl_slice_free2(blk->io->dat_slice, blk->dat); + else + acl_myfree(blk->dat); + if (blk->io->blk_slice) + acl_slice_free2(blk->io->blk_slice, blk); + else + acl_myfree(blk); + __n--; +} + +static ZDB_IO_BLK *io_blk_new(ZDB_IO *io) +{ + ZDB_IO_BLK *blk; + + if (io->blk_slice) + blk = (ZDB_IO_BLK*) acl_slice_alloc(io->blk_slice); + else + blk = (ZDB_IO_BLK*) acl_mymalloc(sizeof(ZDB_IO_BLK)); + if (io->dat_slice) + blk->dat = (char*) acl_slice_alloc(io->dat_slice); + else + blk->dat = (char*) acl_mymalloc(io->blk_len); + + blk->flag = 0; + blk->io = io; + __n++; + return (blk); +} + +/*----------------------------------------------------------------------------*/ + +static int cmp_fn(const void *v1, const void *v2) +{ + const ZDB_IO_BLK *n1 = (const ZDB_IO_BLK*) v1; + const ZDB_IO_BLK *n2 = (const ZDB_IO_BLK*) v2; + + if (n1->off > n2->off) + return (1); + else if (n1->off < n2->off) + return (-1); + else + return (0); +} + +static void free_blk_cache(const ACL_CACHE_INFO *info acl_unused, void *arg) +{ + ZDB_IO_BLK *blk = (ZDB_IO_BLK*) arg; + + io_blk_free(blk); +} + +void zdb_io_cache_open(ZDB_STORE *store, size_t blk_len) +{ + ZDB_IO *io = (ZDB_IO*) acl_mycalloc(1, sizeof(ZDB_IO)); +#ifdef _LP64 + unsigned int flag = ACL_SLICE_FLAG_GC2 | ACL_SLICE_FLAG_RTGC_OFF | ACL_SLICE_FLAG_LP64_ALIGN; +#else + unsigned int flag = ACL_SLICE_FLAG_GC2 | ACL_SLICE_FLAG_RTGC_OFF; +#endif + int page_size = 4096 * 10; + + if ((int) blk_len >= page_size) + page_size = blk_len * 100; + + io->store = store; + io->blk_len = blk_len; + avl_create(&io->blk_tree, cmp_fn, sizeof(ZDB_IO_BLK), + offsetof(ZDB_IO_BLK, node)); + io->blk_cache = acl_cache_create(store->cache_max, store->cache_timeout, free_blk_cache); + if ((store->flag & STORE_FLAG_IO_SLICE)) { + io->blk_slice = acl_slice_create("blk_slice", 0, sizeof(ZDB_IO_BLK), flag); + io->dat_slice = acl_slice_create("dat_slice", page_size, blk_len, flag); + } else { + io->blk_slice = NULL; + io->dat_slice = NULL; + } + io->buf = acl_vstring_alloc(page_size); + store->io = io; +} + +void zdb_io_cache_close(ZDB_STORE *store) +{ + if (!store->io) + return; + + (void) zdb_io_cache_sync(store); + avl_destroy(&store->io->blk_tree); + acl_vstring_free(store->io->buf); + acl_cache_free(store->io->blk_cache); + if (store->io->dat_slice) + acl_slice_destroy(store->io->dat_slice); + if (store->io->blk_slice) + acl_slice_destroy(store->io->blk_slice); + acl_myfree(store->io); +} + +int zdb_io_cache_sync(ZDB_STORE *store) +{ + const char *myname = "zdb_io_cache_sync"; + ZDB_IO_BLK *blk_first, *blk_next, *blk_iter; + int ret, n, dlen = 0; + zdb_off_t off; + ZDB_IO *io = store->io; + + if (!io) + return (0); + + while (1) { + blk_first = (ZDB_IO_BLK*) avl_first(&io->blk_tree); + if (blk_first == NULL) + break; + + off = blk_first->off; + blk_iter = blk_first; + acl_vstring_memcpy(io->buf, blk_iter->dat, blk_iter->dlen); + + /* 尽量将连续数据组合成一块数据写,可以减少 IO 次数 */ + n = 0; + while (1) { + blk_next = (ZDB_IO_BLK*) AVL_NEXT(&io->blk_tree, blk_iter); + if (blk_next == NULL) + break; + if (blk_iter->off + (int) blk_iter->dlen != blk_next->off) + break; + + avl_remove(&io->blk_tree, blk_iter); + + /* 防止在 io_blk_free 再次调用 avl_remove */ + blk_iter->flag &= ~BLK_F_DIRTY; + blk_iter = blk_next; + acl_vstring_memcat(io->buf, blk_iter->dat, blk_iter->dlen); + n++; + } + +#ifdef PWRITE + ret = PWRITE(IO_HANDLE(io), STR(io->buf), LEN(io->buf), off); + if (ret != (int) LEN(io->buf)) { + acl_msg_error("%s(%d): pwrite to %s error(%s)," + " ret(%d) != len(%d), off: " ACL_FMT_I64D, myname, + __LINE__, PATH(IO_STREAM(io)), acl_last_serror(), + ret, (int) LEN(io->buf), off); + return (-1); + } +#else + if (acl_vstream_fseek(IO_STREAM(io), off, SEEK_SET) < 0) { + acl_msg_error("%s(%d): fseek %s error(%s), off: " ACL_FMT_I64D, + myname, __LINE__, IO_PATH(io), acl_last_serror(), off); + return (-1); + } + + ret = acl_vstream_writen(IO_STREAM(io), STR(io->buf), LEN(io->buf)); + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): readn from %s, ret(%d) != size(%d)," + " off(" ACL_FMT_I64D "), error(%s)", myname, __LINE__, + IO_PATH(io), ret, (int) LEN(io->buf), + off, acl_last_serror()); + return (-1); + } +#endif + + dlen += (int) LEN(io->buf); + if (n == 0) { + avl_remove(&io->blk_tree, blk_first); + /* 防止在 io_blk_free 再次调用 avl_remove */ + blk_first->flag &= ~BLK_F_DIRTY; + } + } + + return (dlen); +} + +static void zdb_io_cache_add(ZDB_IO *io, const void *buf, + size_t len, zdb_off_t off, int dirty) +{ + ZDB_IO_BLK *blk; + char key[KEY_LEN]; + + if (io->blk_len < len) + return; + + acl_i64toa(off, key, sizeof(key)); + + blk = io_blk_new(io); + memcpy(blk->dat, buf, len); + blk->off = off; + blk->dlen = len; + if (dirty) { + blk->flag |= BLK_F_DIRTY; + /* 添加进写缓存中 */ + avl_add(&io->blk_tree, blk); + + /* 同步写缓存中的数据块至磁盘 */ + if ((int) avl_numnodes(&io->blk_tree) >= io->store->wback_max) { + (void) zdb_io_cache_sync(io->store); + } + } + + /* 添加进总缓存中 */ + (void) acl_cache_enter(io->blk_cache, key, blk); +} + +static int zdb_io_cache_write(ZDB_IO *io, const void *buf, + size_t len, zdb_off_t off) +{ + ZDB_IO_BLK *blk; + char key[KEY_LEN]; + + if (io->blk_len < len) + return (0); + + /* 先查询缓存中是否存在 */ + + acl_i64toa(off, key, sizeof(key)); + + blk = (ZDB_IO_BLK*) acl_cache_find(io->blk_cache, key); + if (blk) { + if (len > blk->dlen) + blk->dlen = len; + memcpy(blk->dat, buf, len); /* just override */ + if ((blk->flag & BLK_F_DIRTY)) /* 说明已经在写缓存了 */ + return (len); + /* 需要添加进写缓存 */ + blk->flag |= BLK_F_DIRTY; + avl_add(&io->blk_tree, blk); + return (len); + } + + /* 说明是新数据 */ + + zdb_io_cache_add(io, buf, len, off, 1); + return (len); +} + +static int zdb_io_cache_read(ZDB_IO *io, void *buf, + size_t size, zdb_off_t off) +{ + ZDB_IO_BLK *blk; + char key[KEY_LEN]; + + if (size > io->blk_len) + return (0); + + acl_i64toa(off, key, sizeof(key)); + + blk = (ZDB_IO_BLK*) acl_cache_find(io->blk_cache, key); + if (blk != NULL && blk->dlen >= size) { + memcpy(buf, blk->dat, size); + return ((int) size); + } + + return (0); +} + +int zdb_write(ZDB_STORE *store, const void *buf, size_t len, zdb_off_t off) +{ + const char *myname = "zdb_write"; + int ret = 0; + + if (store->io != NULL) { + ret = zdb_io_cache_write(store->io, buf, len, off); + if (ret > 0) + return (ret); + } + +#ifdef PWRITE + ret = PWRITE(STORE_FILE(store), buf, len, off); + + if (ret != (int) len) { + acl_msg_error("%s(%d): pwrite to %s, ret(%d) != len(%d)", + myname, __LINE__, STORE_PATH(store), ret, (int) len); + return (ACL_VSTREAM_EOF); + } +#else + if (acl_vstream_fseek(STORE_STREAM(store), off, SEEK_SET) < 0) { + acl_msg_error("%s(%d): fseek %s error(%s), off: " ACL_FMT_I64D, + myname, __LINE__, STORE_PATH(store), acl_last_serror(), off); + return (ACL_VSTREAM_EOF); + } + + ret = acl_vstream_writen(STORE_STREAM(store), buf, len); + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): readn from %s, ret(%d) != size(%d)," + " off(" ACL_FMT_I64D "), error(%s)", myname, __LINE__, + STORE_PATH(store), ret, (int) len, off, acl_last_serror()); + return (ACL_VSTREAM_EOF); + } +#endif + + return (ret); +} + +int zdb_read(ZDB_STORE *store, void *buf, size_t size, zdb_off_t off) +{ + const char *myname = "zdb_read"; + int ret; + + if (store->io != NULL) { + ret = zdb_io_cache_read(store->io, buf, size, off); + if (ret > 0) + return (ret); + } + +#ifdef PREAD + ret = PREAD(STORE_FILE(store), buf, size, off); + if (ret != (int) size) { + acl_msg_error("%s(%d): pread from %s, ret(%d) != size(%d)," + " off(" ACL_FMT_I64D "), error(%s)", myname, __LINE__, + STORE_PATH(store), ret, (int) size, off, acl_last_serror()); + return (ACL_VSTREAM_EOF); + } +#else + if (acl_vstream_fseek(STORE_STREAM(store), off, SEEK_SET) < 0) { + acl_msg_error("%s(%d): fseek %s error(%s), off: " ACL_FMT_I64D, + myname, __LINE__, STORE_PATH(store), acl_last_serror(), off); + return (ACL_VSTREAM_EOF); + } + + ret = acl_vstream_readn(STORE_STREAM(store), buf, size); + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): readn from %s, ret(%d) != size(%d)," + " off(" ACL_FMT_I64D "), error(%s)", myname, __LINE__, + STORE_PATH(store), ret, (int) size, off, acl_last_serror()); + return (ACL_VSTREAM_EOF); + } +#endif + + if (store->io != NULL) { + /* 添加进缓存中 */ + zdb_io_cache_add(store->io, buf, size, off, 0); + } + + return (ret); +} + +/*----------------------------------------------------------------------------*/ diff --git a/lib_acl/src/db/zdb/zdb_key.c b/lib_acl/src/db/zdb/zdb_key.c new file mode 100644 index 000000000..268c9d7fd --- /dev/null +++ b/lib_acl/src/db/zdb/zdb_key.c @@ -0,0 +1,636 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "lib_acl.h" +#include "db/zdb.h" + +#endif + +#include "zdb_private.h" + +int key_store_header_sync(ZDB_KEY_STORE *store) +{ + const char *myname = "key_store_header_sync"; + int ret; + + ret = ZDB_WRITE((ZDB_STORE*) store, &store->hdr, sizeof(store->hdr), 0); + if (ret == -1) + acl_msg_error("%s(%d): zdb_write to %s error(%s)", + myname, __LINE__, STORE_PATH((ZDB_STORE*) store), acl_last_serror()); + return (ret); +} + +static void dummy(void *ptr acl_unused) +{ + +} + +static void free_tls(void *ptr) +{ + acl_myfree(ptr); +} + +static void *__tls = NULL; +static void main_free_tls(void) +{ + if (__tls) { + acl_myfree(__tls); + __tls = NULL; + } +} + +static acl_pthread_key_t once_key; +static void once_init(void) +{ + if ((unsigned long) acl_pthread_self() == acl_main_thread_self()) { + acl_pthread_key_create(&once_key, dummy); + atexit(main_free_tls); + } else + acl_pthread_key_create(&once_key, free_tls); +} + +static acl_pthread_once_t once_control = ACL_PTHREAD_ONCE_INIT; +static ZDB_BLK_OFF *get_tls(void) +{ + ZDB_BLK_OFF *ptr; + + (void) acl_pthread_once(&once_control, once_init); + ptr = (ZDB_BLK_OFF*) acl_pthread_getspecific(once_key); + if (ptr == NULL) { + ptr = (ZDB_BLK_OFF *) acl_mymalloc(sizeof(ZDB_BLK_OFF)); + acl_pthread_setspecific(once_key, ptr); + if ((unsigned long) acl_pthread_self() == acl_main_thread_self()) + __tls = ptr; + } + return ptr; +} + +/** + * 获得迭代器头部数据 + * @param iter {ACL_ITER*} 迭代器指针 + * @return {const void*} 数据地址 + */ +static const void *key_iter_head(ACL_ITER *iter, struct ZDB_KEY_STORE *store) +{ + zdb_off_t key_off; + int ret; + ZDB_BLK_OFF *blk_off = get_tls(); + + iter->key = NULL; + iter->klen = 0; + for (iter->i = 0; iter->i < store->hdr.key_limit; iter->i++) { + key_off = KEY_OFF(((ZDB_STORE*) store)->db, iter->i); + ret = ZDB_READ((ZDB_STORE*) store, blk_off, + sizeof(ZDB_BLK_OFF), key_off); + if (ret == -1) { + iter->data = iter->ptr = NULL; + return (NULL); + } + if (blk_off->offset >= 0 && blk_off->inode >= 0) { + iter->data = iter->ptr = blk_off; + iter->i++; /* 指向下一个位置 */ + return (iter->ptr); + } + } + + iter->data = iter->ptr = NULL; + return (NULL); +} + +/** + * 获得迭代器的那一个数据 + * @param iter {ACL_ITER*} 迭代器指针 + * @return {const void*} 数据地址 + */ +static const void *key_iter_next(ACL_ITER *iter, struct ZDB_KEY_STORE *store) +{ + zdb_off_t key_off; + int ret; + ZDB_BLK_OFF *blk_off= get_tls(); + + for (; iter->i < store->hdr.key_limit; iter->i++) { + key_off = KEY_OFF(((ZDB_STORE*) store)->db, iter->i); + ret = ZDB_READ((ZDB_STORE*) store, blk_off, + sizeof(ZDB_BLK_OFF), key_off); + if (ret == -1) { + iter->data = iter->ptr = NULL; + return (NULL); + } + if (blk_off->offset >= 0 && blk_off->inode >= 0) { + iter->data = iter->ptr = blk_off; + iter->i++; /* 指向下一个位置 */ + return (iter->ptr); + } + } + + iter->data = iter->ptr = NULL; + return (NULL); +} + +/** + * 初始化键存储 + * @param store {ZDB_KEY_STORE*} + * @return {int} 0: ok; -1: error + */ +static int key_store_init(ZDB_KEY_STORE *store) +{ + const char *myname = "key_store_init"; + zdb_key_t i; + ZDB_BLK_OFF blk_off; + int ret; + + /* 初始化键存储的头部信息 */ + + if ((((ZDB_STORE*) store)->db->oflags & ZDB_FLAG_CACHE_KEY) == 0) + ret = acl_vstream_buffed_writen(((ZDB_STORE*) store)->fhandle.fp, + &store->hdr, sizeof(store->hdr)); + else + ret = ZDB_WRITE((ZDB_STORE*) store, &store->hdr, sizeof(store->hdr), 0); + + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): write header to %s error(%s)", + myname, __LINE__, STORE_PATH((ZDB_STORE*) store), + acl_last_serror()); + return (-1); + } + + blk_off.offset = -1; + blk_off.inode = -1; + + if ((((ZDB_STORE*) store)->db->oflags & ZDB_FLAG_CACHE_KEY) == 0) { + for (i = 0; i < store->hdr.key_limit; i++) { + ret = acl_vstream_buffed_writen(((ZDB_STORE*) store)->fhandle.fp, + &blk_off, sizeof(blk_off)); + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): write to %s error(%s)", + myname, __LINE__, STORE_PATH((ZDB_STORE*) store), + acl_last_serror()); + return (-1); + } + } + } else { + for (i = 0; i < store->hdr.key_limit; i++) { + ret = ZDB_WRITE((ZDB_STORE*) store, &blk_off, sizeof(blk_off), + (zdb_off_t) sizeof(store->hdr) + + (zdb_off_t) sizeof(blk_off) * i); + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): write to %s error(%s)", + myname, __LINE__, + STORE_PATH((ZDB_STORE*) store), + acl_last_serror()); + return (-1); + } + } + } + + if ((((ZDB_STORE*) store)->db->oflags & ZDB_FLAG_CACHE_KEY) == 0) { + /* 刷新写的缓冲区至磁盘 */ + if (acl_vstream_fflush(((ZDB_STORE*) store)->fhandle.fp) + == ACL_VSTREAM_EOF) + { + acl_msg_error("%s(%d): fflush to %s error %s", myname, + __LINE__, STORE_PATH((ZDB_STORE*) store), + acl_last_serror()); + return (-1); + } + } + return (0); +} + +/** + * 打开键存储时的回调函数 + * @param fh {ACL_FHANDLE*} 新打开的文件句柄 + * @param arg {void*} 参数 + * @return {int} 0: ok; -1: error, 若返回 -1 则新打开的文件句柄会自动被关闭 + */ +static int key_store_on_open(ACL_FHANDLE *fh, void *arg) +{ + const char *myname = "key_store_on_open"; + ZDB *db = (ZDB*) arg; + ZDB_KEY_STORE *store = (ZDB_KEY_STORE*) fh; + int ret; + + if (fh->size != sizeof(ZDB_KEY_STORE)) + acl_msg_fatal("%s: fh->size(%d) != ZDB_KEY_STORE's size(%d)", + myname, (int) fh->size, (int) sizeof(ZDB_KEY_STORE)); + ((ZDB_STORE*) store)->db = db; + ((ZDB_STORE*) store)->flag = STORE_FLAG_KEY; + if ((db->oflags & ZDB_FLAG_SLICE_KEY)) + ((ZDB_STORE*) store)->flag |= STORE_FLAG_IO_SLICE; + + /* 如果是新文件则初始化 */ + + if (fh->fsize == 0) { + acl_debug(ZDB_DBG_KEY, 1) ("%s: begin init %s ...", myname, STR(db->path_tmp)); + store->hdr.key_limit = db->key_limit; + store->hdr.key_count = 0; + store->hdr.key_begin = 0; + + if ((db->oflags & ZDB_FLAG_CACHE_KEY) != 0) { + ((ZDB_STORE*) store)->cache_max = db->key_cache_max; + ((ZDB_STORE*) store)->cache_timeout = db->key_cache_timeout; + ((ZDB_STORE*) store)->wback_max = db->key_wback_max; + zdb_io_cache_open((ZDB_STORE*) store, sizeof(ZDB_BLK_OFF)); + } + + if (key_store_init(store) < 0) { + acl_msg_error("%s(%d): key_store_init error", myname, __LINE__); + return (-1); + } + acl_debug(ZDB_DBG_KEY, 1) ("%s: init %s ok", myname, STR(db->path_tmp)); + return (0); + } + + /* 如果是旧文件则读取文件头信息, 且应进行检验 */ + + if ((((ZDB_STORE*) store)->db->oflags & ZDB_FLAG_CACHE_KEY) == 0) + ret = acl_vstream_readn(((ZDB_STORE*) store)->fhandle.fp, + &store->hdr, sizeof(store->hdr)); + else + ret = ZDB_READ((ZDB_STORE*) store, &store->hdr, + sizeof(store->hdr), 0); + + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): read key header from %s error(%s)", + myname, __LINE__, STR(db->path_tmp), acl_last_serror()); + return (-1); + } + + if ((db->oflags & ZDB_FLAG_CACHE_KEY) != 0) { + ((ZDB_STORE*) store)->cache_max = db->key_cache_max; + ((ZDB_STORE*) store)->cache_timeout = db->key_cache_timeout; + ((ZDB_STORE*) store)->wback_max = db->key_wback_max; + zdb_io_cache_open((ZDB_STORE*) store, sizeof(ZDB_BLK_OFF)); + } + + return (0); +} + +/** + * 关闭键存储时的回调函数 + * @param fh {ACL_FHANDLE*} 文件句柄 + */ +static void key_store_on_close(ACL_FHANDLE *fh) +{ + const char *myname = "key_store_on_close"; + ZDB_KEY_STORE *store = (ZDB_KEY_STORE*) fh; + + key_store_header_sync(store); + zdb_io_cache_close((ZDB_STORE*) store); + acl_debug(ZDB_DBG_KEY, 2) ("%s(%d): sync header ok, close %s now, nrefer: %d", + myname, __LINE__, STORE_PATH((ZDB_STORE*) store), + ((ZDB_STORE*) store)->fhandle.nrefer); +} + +ZDB_KEY_STORE *zdb_key_store_open2(ZDB *db, const char *filepath) +{ + const char *myname = "zdb_key_store_open2"; + ZDB_KEY_STORE *store; + unsigned int oflags = ACL_FHANDLE_O_NOATIME; + + if ((db->oflags & ZDB_FLAG_OPEN_LOCK) != 0) + oflags |= ACL_FHANDLE_O_MLOCK; + + /* 打开或创建一个文件句柄 */ + store = (ZDB_KEY_STORE*) acl_fhandle_open(sizeof(ZDB_KEY_STORE), oflags, + filepath, key_store_on_open, db, + key_store_on_close); + if (store == NULL) { + acl_msg_error("%s(%d): acl_fhandle_open %s error(%s)", + myname, __LINE__, filepath, acl_last_serror()); + return (NULL); + } else { + ((ZDB_STORE*) store)->iter_head = (STORE_ITER) key_iter_head; + ((ZDB_STORE*) store)->iter_next = (STORE_ITER) key_iter_next; + } + return (store); +} + + +ZDB_KEY_STORE *zdb_key_store_open(ZDB *db, zdb_key_t key) +{ + const char *myname = "zdb_key_store_open"; + int inode; + + /* 计算出该 key 所在的存储文件的存储目录的标识号 */ + inode = KEY_INODE(db, key); + if (inode < 0 || inode > 65353) { + acl_msg_error("%s(%d): inode(%d) invalid, key(" ACL_FMT_I64D ")", + myname, __LINE__, inode, key); + return (NULL); + } + +#ifdef INCLUDE_PATH + acl_vstring_sprintf(db->path_tmp, "%s/%d/%s_%d.key", + db->key_path, inode, db->dbname, inode); +#else + acl_vstring_sprintf(db->path_tmp, "%s/%s_%d.key", + db->key_path, db->dbname, inode); +#endif + + return (zdb_key_store_open2(db, STR(db->path_tmp))); +} + +void zdb_key_store_close(ZDB_KEY_STORE *store) +{ + acl_fhandle_close(&((ZDB_STORE*) store)->fhandle, 120); +} + +int zdb_key_set(ZDB *db, zdb_key_t key, const ZDB_BLK_OFF *blk_off) +{ + const char *myname = "zdb_key_set"; + zdb_off_t key_off; + ZDB_KEY_STORE *store = NULL; + int ret, inode; + +#undef RETURN +#define RETURN(x) do { \ + if (store) \ + zdb_key_store_close(store); \ + return ((x)); \ +} while (0) + + store = zdb_key_store_open(db, key); + if (store == NULL) { + acl_msg_error("%s(%d): open key(" ACL_FMT_I64D ") store error", + myname, __LINE__, key); + RETURN (-1); + } + + /* 计算 key 在键存储中的位置 */ + + inode = KEY_INODE(store->store.db, key); + if (inode < 0 || inode > 65353) { + acl_msg_error("%s(%d): %s, inode(%d) invalid, key(" + ACL_FMT_I64D ")", myname, __LINE__, + STORE_PATH(&store->store), inode, key); + RETURN (-1); + } + + key_off = KEY_OFF(store->store.db, key); + if (key_off < (zdb_off_t) sizeof(ZDB_KEY_HDR)) { + acl_msg_error("%s(%d): %s, key_off(" ACL_FMT_I64D + ") < ZDB_KEY_HDR's size(%d), key(" ACL_FMT_I64D + "), inode(%d), key_limit(" ACL_FMT_I64D ")", + myname, __LINE__, STORE_PATH(&store->store), key_off, + (int) sizeof(ZDB_KEY_HDR), key, inode, store->store.db->key_limit); + RETURN (-1); + } + + ret = ZDB_WRITE((ZDB_STORE*) store, blk_off, sizeof(ZDB_BLK_OFF), key_off); + if (ret == -1) { + acl_msg_error("%s(%d): write to %s error %s, blk_off(" + ACL_FMT_I64D ", %d), key(" ACL_FMT_I64D ")", + myname, __LINE__, STORE_PATH(&store->store), acl_last_serror(), + blk_off->offset, blk_off->inode, key); + RETURN (-1); + } + + /* 如果为新数据插入则增加计数器 */ + + if ((db->status & ZDB_STAT_KEY_NEW)) + store->hdr.key_count++; + RETURN (0); +} + +int zdb_key_get(ZDB *db, zdb_key_t key, ZDB_BLK_OFF *blk_off) +{ + const char *myname = "zdb_key_get"; + zdb_off_t key_off; + ZDB_KEY_STORE *store = NULL; + int ret, inode; + +#undef RETURN +#define RETURN(x) do { \ + if (store) \ + zdb_key_store_close(store); \ + return ((x)); \ +} while (0) + + store = zdb_key_store_open(db, key); + if (store == NULL) { + acl_msg_error("%s(%d): open key(" ACL_FMT_I64D ") store error", + myname, __LINE__, key); + RETURN (-1); + } + + /* 计算 key 在键存储中的位置 */ + + inode = KEY_INODE(store->store.db, key); + if (inode < 0 || inode > 65353) { + acl_msg_error("%s(%d): %s, inode(%d) invalid, key(" + ACL_FMT_I64D ")", myname, __LINE__, + STORE_PATH(&store->store), inode, key); + RETURN (-1); + } + + key_off = KEY_OFF(store->store.db, key); + if (key_off < (int) sizeof(ZDB_KEY_HDR)) { + acl_msg_error("%s(%d): %s, key_off(" ACL_FMT_I64D + ") < ZDB_KEY_HDR's size(%d), key(" ACL_FMT_I64D + "), inode(%d), key_limit(" ACL_FMT_I64D ")", + myname, __LINE__, STORE_PATH(&store->store), key_off, + (int) sizeof(ZDB_KEY_HDR), key, inode, store->store.db->key_limit); + RETURN (-1); + } + + ret = ZDB_READ((ZDB_STORE*) store, blk_off, sizeof(ZDB_BLK_OFF), key_off); + + acl_debug(ZDB_DBG_GETK, 2) + ("%s(%d): zdb_read ret: %d, blk_off: " ACL_FMT_I64D + ", key_off: " ACL_FMT_I64D, + myname, __LINE__, ret, blk_off->offset, key_off); + + if (ret == -1) { + acl_msg_error("%s(%d): zdb_read from %s error %s," + " key(" ACL_FMT_I64D "), key_off(" ACL_FMT_I64D ")", + myname, __LINE__, STORE_PATH(&store->store), + acl_last_serror(), key, key_off); + RETURN (-1); + } + + if (blk_off->offset < 0 || blk_off->inode < 0) { + acl_debug(ZDB_DBG_GETK, 2) + ("%s(%d): blk_off(" ACL_FMT_I64D ") from %s invalid for" + " key(" ACL_FMT_I64D "), key_off(" ACL_FMT_I64D ")", + myname, __LINE__, blk_off->offset, + STORE_PATH(&store->store), key, key_off); + RETURN (0); + } + + /* 只有 blk_off->offset >= 0 && blk_off->inode >= 0 时才表明找到值位置索引 */ + RETURN (1); +} + +int zdb_key_status(ZDB *db, const char *filepath, ZDB_KEY_HDR *key_hdr) +{ + const char *myname = "zdb_key_status"; + ZDB_KEY_STORE *store; + + store = zdb_key_store_open2(db, filepath); + if (store == NULL) { + acl_msg_error("%s(%d): open %s error(%s)", + myname, __LINE__, filepath, acl_last_serror()); + return (-1); + } + + memcpy(key_hdr, &store->hdr, sizeof(ZDB_KEY_HDR)); + zdb_key_store_close(store); + return (0); +} + +int zdb_key_check(ZDB_KEY_STORE *store, ZDB_KEY_HDR *key_hdr) +{ + const char *myname = "zdb_key_check"; + acl_int64 nused = 0; + int failed = 0; + ACL_ITER iter; + + if (key_hdr) + memcpy(key_hdr, &store->hdr, sizeof(ZDB_KEY_HDR)); + + /* 扫描所有被使用的数据结点 */ + + acl_msg_info("%s(%d): begin check %s's used key", + myname, __LINE__, STORE_PATH((ZDB_STORE*) store)); + + acl_foreach(iter, (ZDB_STORE*) store) { + nused++; + } + + if (nused != store->hdr.key_count) { + acl_msg_error("%s(%d): nused(" ACL_FMT_I64D + ") != store->hdr.key_count(" ACL_FMT_I64D ")" + " for %s, please repair it!", myname, __LINE__, + nused, store->hdr.key_count, STORE_PATH(&store->store)); + failed = 1; + } else { + acl_msg_info("%s(%d): check used key ok for %s," + " store->hdr.key_count(" ACL_FMT_I64D ")", myname, __LINE__, + STORE_PATH(&store->store), store->hdr.key_count); + } + return (failed ? -1 : 0); +} + +int zdb_key_check3(ZDB *db, const char *filepath, ZDB_KEY_HDR *key_hdr) +{ + const char *myname = "zdb_key_check3"; + ZDB_KEY_STORE *store; + int ret; + + store = zdb_key_store_open2(db, filepath); + if (store == NULL) { + acl_msg_error("%s(%d): open %s error(%s)", + myname, __LINE__, filepath, acl_last_serror()); + return (-1); + } + + ret = zdb_key_check(store, key_hdr); + zdb_key_store_close(store); + return (ret); +} + +static int store_init_on_open(ACL_FHANDLE *fh, void *arg) +{ + const char *myname = "store_init_on_open"; + ZDB_KEY_STORE *store = (ZDB_KEY_STORE*) fh; + ZDB *db = (ZDB*) arg; + ZDB_BLK_OFF blk_off; + zdb_key_t key; + int ret; + + if (fh->size != sizeof(ZDB_KEY_STORE)) + acl_msg_fatal("%s: fh->size(%d) != ZDB_KEY_STORE's size(%d)", + myname, (int) fh->size, (int) sizeof(ZDB_KEY_STORE)); + ((ZDB_STORE*) store)->db = db; + ((ZDB_STORE*) store)->flag = STORE_FLAG_KEY; + if ((db->oflags & ZDB_FLAG_SLICE_KEY)) + ((ZDB_STORE*) store)->flag |= STORE_FLAG_IO_SLICE; + + acl_debug(ZDB_DBG_KEY, 1) ("%s: begin init %s ...", myname, STR(db->path_tmp)); + store->hdr.key_limit = db->key_limit; + store->hdr.key_count = 0; + store->hdr.key_begin = 0; + + /* 初始化键存储的头部信息 */ + ret = acl_vstream_buffed_writen(((ZDB_STORE*) store)->fhandle.fp, + &store->hdr, sizeof(store->hdr)); + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): write header to %s error(%s)", + myname, __LINE__, STORE_PATH((ZDB_STORE*) store), + acl_last_serror()); + return (-1); + } + + blk_off.offset = -1; + blk_off.inode = -1; + for (key = 0; key < store->hdr.key_limit; key++) { + ret = acl_vstream_buffed_writen(((ZDB_STORE*) store)->fhandle.fp, + &blk_off, sizeof(blk_off)); + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): write to %s error(%s)", myname, + __LINE__, STORE_PATH((ZDB_STORE*) store), + acl_last_serror()); + return (-1); + } + if ((key % 5000000) == 0) { + acl_msg_info("%s(%d): %s, key: " ACL_FMT_I64D ", key_limit: " + ACL_FMT_I64D, myname, __LINE__, + STORE_PATH((ZDB_STORE*) store), key, db->key_limit); + } + } + + /* 刷新写的缓冲区至磁盘 */ + if (acl_vstream_fflush(((ZDB_STORE*) store)->fhandle.fp) == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): fflush to %s error %s", myname, __LINE__, + STORE_PATH((ZDB_STORE*) store), acl_last_serror()); + return (-1); + } + + + acl_debug(ZDB_DBG_KEY, 1) ("%s: init %s ok", myname, STR(db->path_tmp)); + return (0); +} + +static void store_init_on_close(ACL_FHANDLE *fh) +{ + ZDB_KEY_STORE *store = (ZDB_KEY_STORE*) fh; + + key_store_header_sync(store); + zdb_io_cache_close((ZDB_STORE*) store); +} + +int zdb_key_init(ZDB *db, zdb_key_t key_begin, zdb_key_t key_end) +{ + const char *myname = "zdb_key_init"; + ZDB_KEY_STORE *store; + zdb_key_t key; + int inode; + + acl_msg_info("%s(%d): key_begin: " ACL_FMT_I64D ", key_end: " + ACL_FMT_I64D ", key_limit: " ACL_FMT_I64D, + myname, __LINE__, key_begin, key_end, db->key_limit); + + for (key = key_begin; key < key_end;) { + inode = KEY_INODE(db, key); + acl_vstring_sprintf(db->path_tmp, "%s/%s_%d.key", + db->key_path, db->dbname, inode); + /* 打开或创建一个文件句柄 */ + acl_msg_info("%s(%d): open %s", myname, __LINE__, STR(db->path_tmp)); + store = (ZDB_KEY_STORE*) acl_fhandle_open(sizeof(ZDB_KEY_STORE), + 0, STR(db->path_tmp), store_init_on_open, + db, store_init_on_close); + if (store == NULL) { + acl_msg_error("%s(%d): acl_fhandle_open %s error(%s)", + myname, __LINE__, STR(db->path_tmp), + acl_last_serror()); + return (-1); + } + + acl_msg_info("%s(%d): close %s", myname, __LINE__, STR(db->path_tmp)); + acl_fhandle_close(&((ZDB_STORE*) store)->fhandle, 0); + key += db->key_limit; + } + + return (0); +} diff --git a/lib_acl/src/db/zdb/zdb_key_walk.c b/lib_acl/src/db/zdb/zdb_key_walk.c new file mode 100644 index 000000000..d953fc022 --- /dev/null +++ b/lib_acl/src/db/zdb/zdb_key_walk.c @@ -0,0 +1,57 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "lib_acl.h" +#include "db/zdb.h" + +#endif + +#include "zdb_private.h" + +int zdb_key_walk(ZDB *db, int (*walk_fn)(ZDB_KEY_STORE*)) +{ + const char *myname = "zdb_key_walk"; + ZDB_KEY_STORE *store; + ACL_SCAN_DIR *scan = NULL; + const char *fname; + char pathbuf[256]; + int ret = 0; + + scan = acl_scan_dir_open(db->key_path, 1); + if (scan == NULL) { + acl_msg_error("%s: open dir %s error(%s)", + myname, db->key_path, acl_last_serror()); + return (-1); + } + + while (1) { + fname = acl_scan_dir_next_file(scan); + if (fname == NULL) { + acl_msg_info("%s: scan over for %s\n", myname, db->key_path); + break; + } + if (strrncasecmp(fname, ".key", 4) != 0) { + acl_msg_info("%s: skip %s/%s\n", myname, + acl_scan_dir_path(scan), fname); + continue; + } + snprintf(pathbuf, sizeof(pathbuf), "%s/%s", + acl_scan_dir_path(scan), fname); + store = zdb_key_store_open2(db, pathbuf); + if (store == NULL) { + acl_msg_error("%s: open file(%s) error(%s)", + myname, pathbuf, acl_last_serror()); + ret = -1; + break; + } + + ret = walk_fn(store); + zdb_key_store_close(store); + + if (ret < 0) + break; + } + + acl_scan_dir_close(scan); + return (ret); +} diff --git a/lib_acl/src/db/zdb/zdb_private.h b/lib_acl/src/db/zdb/zdb_private.h new file mode 100644 index 000000000..0b42ace12 --- /dev/null +++ b/lib_acl/src/db/zdb/zdb_private.h @@ -0,0 +1,199 @@ +#ifndef __ZDB_PRIVATE_INCLUDE_H__ +#define __ZDB_PRIVATE_INCLUDE_H__ + +#include "lib_acl.h" +#include "db/zdb.h" + +#define ZDB_DBG_BASE 500 +#define ZDB_DBG_GETK (ZDB_DBG_BASE) +#define ZDB_DBG_GETD (ZDB_DBG_BASE + 1) +#define ZDB_DBG_ADDD (ZDB_DBG_BASE + 2) +#define ZDB_DBG_KEY (ZDB_DBG_BASE + 3) +#define ZDB_DBG_DAT (ZDB_DBG_BASE + 4) + +#define ZDB_KEY_LIMIT (unsigned int) -1 +#define ZDB_DAT_FILE_LIMIT 10000 /* 值存储目录下每个目录下最大的文件个数 */ +#define ZDB_KEY_DIR_LIMIT 10 /* 键存储目录个数 */ +#define ZDB_DAT_DIR_LIMIT 10 /* 值存储目录个数 */ + +typedef const void *(*STORE_ITER)(ACL_ITER*, ZDB_STORE*); + +/*--------------------------- 一些简单方便的宏定义 ---------------------------*/ + +#define DISK_BITS 8 +#define DISK_MASK 0xff +#define DISK_LIMIT (1 << 8) + +#define DIR_BITS 24 +#define DIR_MASK 0xffffff +#define DIR_LIMIT (1 << 24) + +/** + * 取得 ACL_VSTRING 对象中的数据地址 + * @param x {ACL_VSTRING*} + * @return {char*} + */ +#ifndef STR +#define STR(x) acl_vstring_str((x)) +#endif + +/** + * 取得 ACL_VSTRING 对象中数据长度 + * @param x {ACL_VSTRING*} + * @return {size_t} 数据长度 + */ +#ifndef LEN +#define LEN(x) ACL_VSTRING_LEN((x)) +#endif + +/** + * 取得 ACL_VSTREAM 对象中文件路径 + * @param x {ACL_VSTREAM*} + * @return {char*} 文件路径 + */ +#define PATH(x) ACL_VSTREAM_PATH((x)) + +/** + * 取得存储中文件句柄的文件路径 + * @param s {ZDB_KEY_STORE* || ZDB_DAT_STORE*} + * @return {char*} 文件路径 + */ +#define STORE_PATH(s) PATH((s)->fhandle.fp) + +/** + * 取得存储中文件描述符 + * @param s {ZDB_KEY_STORE* || ZDB_DAT_STORE*} + * @return {ACL_FILE_HANDLE} 文件描述符 + */ +#define STORE_FILE(s) ACL_VSTREAM_FILE((s)->fhandle.fp) + +/** + * 获得存储文件的 ACL_VSTREAM 流 + * @param s {ZDB_KEY_STORE* || ZDB_DAT_STORE*} + * @return {ACL_VSTREAM*} + */ +#define STORE_STREAM(s) ((s)->fhandle.fp) + +/** + * 根据键值取得键存储的相对路径号 + * @param z {ZDB*} + * @param k {zdb_key_t} + * @return {int} 相对路径号 + */ +#define KEY_INODE(z, k) (int) ((k) / (z)->key_limit) + +/** + * 由键值及键限制值取得该键值的余数 + * @param z {ZDB*} + * @param k {zdb_key_t} + * @return {zdb_key_t} 余数 + */ +#define KEY_MOD(z, k) ((k) % (z)->key_limit) + +/** + * 根据键值取得该键在键存储文件中的偏移位置 + * @param z {ZDB*} + * @param k {zdb_key_t} + * @return {zdb_off_t} + */ +#define KEY_OFF(z, k) ( \ + ((k) - KEY_INODE((z), (k)) * (zdb_off_t) (z)->key_limit) \ + * (zdb_off_t) sizeof(ZDB_BLK_OFF) \ + + (zdb_off_t) sizeof(ZDB_KEY_HDR) ) + +/** + * 数据块头部长度 + * @param s {ZDB_DAT_STORE*} + * @return {int} + */ +#define BLK_HDR_LEN(s) ((zdb_off_t) (s)->hdr.blk_hdr_dlen) + +/** + * 数据块长度(包含数据头部分) + * @param s {ZDB_DAT_STORE*} + * @return {int} + */ +#define BLK_LEN(s) ( \ + BLK_HDR_LEN((s)) + \ + (zdb_off_t) (s)->hdr.blk_dlen * (zdb_off_t) (s)->hdr.blk_count ) + +/** + * 计算数据块中数据头在值存储中的偏移位置 + * @param s {ZDB_DAT_STORE*} + * @param x {zdb_lnk_t} 文件存储位置索引号 + * @return {zdb_off_t} + */ +#define BLK_HDR_OFF(s, x) ( \ + (zdb_off_t) sizeof(ZDB_DAT_HDR) + BLK_LEN((s)) * (zdb_off_t) ((x)) ) + +/** + * 计算数据块中数据部分在值存储中的偏移位置 + * @param s {ZDB_DAT_STORE*} + * @param x {zdb_lnk_t} 文件存储位置索引号 + * @return {zdb_off_t} + */ +#define BLK_DAT_OFF(s, x) \ + (BLK_HDR_OFF(s, x) + (zdb_off_t) sizeof(ZDB_BLK_HDR)) + +#ifdef __cplusplus +extern "C" { +#endif + +/*---------------------------- in zdb.c ----------------------------------*/ + +/** + * 从磁盘分区中选择合适的分区节点 + * @param db {ZDB*} + */ +int zdb_disk_select(ZDB *db); + +/*--------------------------------- in zdb_io.c ------------------------------*/ + +#undef DEBUG_ZDB_RW + +#ifdef DEBUG_ZDB_RW +#define ZDB_WRITE(s, buf, len, off) ( \ + acl_msg_info("%s(%d), %s: call zdb_write(%s, %ld, %lld)\n", \ + __FILE__, __LINE__, __FUNCTION__, STORE_PATH((s)), \ + (size_t) len, (zdb_off_t) off), 1 ? \ + zdb_write((s), (buf), (len), (off)) : ACL_VSTREAM_EOF ) + +#define ZDB_READ(s, buf, len, off) ( \ + acl_msg_info("%s(%d), %s: call zdb_read(%s, %ld, %lld)\n", \ + __FILE__, __LINE__, __FUNCTION__, STORE_PATH((s)), \ + (size_t) len, (zdb_off_t) off), 1 ? \ + zdb_read((s), (buf), (len), (off)) : ACL_VSTREAM_EOF ) +#else +#define ZDB_WRITE zdb_write +#define ZDB_READ zdb_read +#endif + +int zdb_io_cache_sync(ZDB_STORE *store); +void zdb_io_cache_open(ZDB_STORE *store, size_t blk_len); +void zdb_io_cache_close(ZDB_STORE *store); + +/** + * 封装了 pwrite64 的写接口 + * @param store {ZDB_STORE*} 文件句柄 + * @param buf {const void*} 数据地址 + * @param len {size_t} 数据长度 + * @param off {zdb_off_t} 文件中的位置偏移量 + * @return {int} > 0: ok; -1: error + */ +int zdb_write(ZDB_STORE *store, const void *buf, size_t len, zdb_off_t off); + +/** + * 封装了 pread64 的读接口 + * @param store {ZDB_STORE*} 文件句柄 + * @param buf {const void*} 缓冲区地址 + * @param len {size_t} 缓冲区长度 + * @param off {zdb_off_t} 文件中的位置偏移量 + * @return {int} > 0: ok; -1: error + */ +int zdb_read(ZDB_STORE *store, void *buf, size_t size, zdb_off_t off); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/src/event/acl_events.c b/lib_acl/src/event/acl_events.c new file mode 100644 index 000000000..6449baee0 --- /dev/null +++ b/lib_acl/src/event/acl_events.c @@ -0,0 +1,462 @@ +/* + * Name: events.c + * Author: zsx + * Date: 2005-4-7, Version: 1.0 + * Date: 2005-7-9, Version: 1.1 + * Date: 2006-6-23, Version: 1.2 + */ + +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_msg.h" +#include "stdlib/acl_ring.h" +#include "stdlib/acl_vstream.h" +#include "stdlib/acl_iostuff.h" +#include "event/acl_events.h" + +#endif + +#include "events_define.h" +#include "events_epoll.h" +#include "events_devpoll.h" +#include "events_iocp.h" +#include "events_wmsg.h" +#include "events.h" + +static void event_init(ACL_EVENT *eventp, int fdsize, + int delay_sec, int delay_usec) +{ + eventp->fdsize = fdsize; + /* eventp->fdtab_free_cnt = 0; */ + eventp->fdcnt = 0; + eventp->fdcnt_ready = 0; + eventp->fdtabs = (ACL_EVENT_FDTABLE **) + acl_mycalloc(fdsize,sizeof(ACL_EVENT_FDTABLE *)); + eventp->fdtabs_ready = (ACL_EVENT_FDTABLE **) + acl_mycalloc(fdsize, sizeof(ACL_EVENT_FDTABLE *)); + + eventp->maxfd = 0; + eventp->nested = 0; + + eventp->delay_sec = delay_sec + delay_usec / 1000000; + eventp->delay_usec = delay_usec % 1000000; + /* + acl_ring_init(&eventp->used_ring); + acl_ring_init(&eventp->slot_ring); + */ + + acl_ring_init(&eventp->timer_head); + eventp->timer_keep = 0; + SET_TIME(eventp->event_present); + SET_TIME(eventp->event_last_debug); + + if (eventp->init_fn) + eventp->init_fn(eventp); +} + +static int event_limit(int fdsize) +{ + const char *myname = "event_limit"; + +#ifdef ACL_UNIX + if ((fdsize = acl_open_limit(fdsize)) < 0) { + acl_msg_fatal("%s: unable to determine open file limit, err=%s", + myname, acl_last_serror()); + } +#else + if (fdsize == 0) + fdsize = 1024; +#endif + if ((unsigned) (fdsize) < FD_SETSIZE / 2 && fdsize < 256) + acl_msg_warn("%s: could allocate space for only %d open files", + myname, fdsize); + + acl_msg_info("%s: max fdsize: %d", myname, fdsize); + + return (fdsize); +} + +ACL_EVENT *acl_event_new_select(int delay_sec, int delay_usec) +{ + ACL_EVENT *eventp; + int fdsize; + + fdsize = event_limit(FD_SETSIZE); + eventp = event_new_select(); + event_init(eventp, fdsize, delay_sec, delay_usec); + return (eventp); +} + +ACL_EVENT *acl_event_new_select_thr(int delay_sec, int delay_usec) +{ + ACL_EVENT *eventp; + int fdsize; + + fdsize = event_limit(FD_SETSIZE); + eventp = event_new_select_thr(); + event_init(eventp, fdsize, delay_sec, delay_usec); + return (eventp); +} + +ACL_EVENT *acl_event_new_poll(int delay_sec, int delay_usec) +{ +#ifdef ACL_EVENTS_POLL_STYLE + ACL_EVENT *eventp; + int fdsize; + + fdsize = event_limit(0); + eventp = event_new_poll(fdsize); + event_init(eventp, fdsize, delay_sec, delay_usec); + return (eventp); +#else + const char *myname = "acl_event_new_poll"; + + delay_sec = delay_sec; + delay_usec = delay_usec; + acl_msg_fatal("%s(%d): not support!", myname, __LINE__); + return (NULL); +#endif +} + +ACL_EVENT *acl_event_new_poll_thr(int delay_sec, int delay_usec) +{ +#ifdef ACL_EVENTS_POLL_STYLE + ACL_EVENT *eventp; + int fdsize; + + fdsize = event_limit(0); + eventp = event_new_poll_thr(fdsize); + event_init(eventp, fdsize, delay_sec, delay_usec); + return (eventp); +#else + const char *myname = "acl_event_new_poll_thr"; + + delay_sec = delay_sec; + delay_usec = delay_usec; + acl_msg_fatal("%s(%d): not support!", myname, __LINE__); + return (NULL); +#endif +} + +ACL_EVENT *acl_event_new_kernel(int delay_sec, int delay_usec) +{ +#ifdef ACL_EVENTS_KERNEL_STYLE + ACL_EVENT *eventp; + int fdsize; + + fdsize = event_limit(0); + eventp = event_new_kernel(fdsize); + event_init(eventp, fdsize, delay_sec, delay_usec); + return (eventp); +#elif defined(ACL_EVENTS_STYLE_IOCP) + ACL_EVENT *eventp; + int fdsize; + + fdsize = event_limit(0); + eventp = event_new_iocp(fdsize); + event_init(eventp, fdsize, delay_sec, delay_usec); + return (eventp); +#else + const char *myname = "acl_event_new_kernel"; + + delay_sec = delay_sec; + delay_usec = delay_usec; + acl_msg_fatal("%s(%d): not support!", myname, __LINE__); + return (NULL); +#endif +} + +ACL_EVENT *acl_event_new_kernel2(int delay_sec, int delay_usec) +{ +#ifdef ACL_EVENTS_KERNEL_STYLE + ACL_EVENT *eventp; + int fdsize; + + fdsize = event_limit(0); + eventp = event_new_kernel2(fdsize); + event_init(eventp, fdsize, delay_sec, delay_usec); + return (eventp); +#else + const char *myname = "acl_event_new_kernel2"; + + delay_sec = delay_sec; + delay_usec = delay_usec; + acl_msg_fatal("%s(%d): not support!", myname, __LINE__); + return (NULL); +#endif +} + +ACL_EVENT *acl_event_new_kernel3(int delay_sec, int delay_usec) +{ +#ifdef ACL_EVENTS_KERNEL_STYLE + ACL_EVENT *eventp; + int fdsize; + + fdsize = event_limit(0); + eventp = event_new_kernel2(fdsize); + event_init(eventp, fdsize, delay_sec, delay_usec); + return (eventp); +#else + const char *myname = "acl_event_new_kernel3"; + + delay_sec = delay_sec; + delay_usec = delay_usec; + acl_msg_fatal("%s(%d): not support!", myname, __LINE__); + return (NULL); +#endif +} + +ACL_EVENT *acl_event_new_kernel_thr(int delay_sec, int delay_usec) +{ +#ifdef ACL_EVENTS_KERNEL_STYLE + ACL_EVENT *eventp; + int fdsize; + + fdsize = event_limit(0); + eventp = event_new_kernel_thr(fdsize); + event_init(eventp, fdsize, delay_sec, delay_usec); + return (eventp); +#else + const char *myname = "acl_event_new_kernel_thr"; + + delay_sec = delay_sec; + delay_usec = delay_usec; + acl_msg_fatal("%s(%d): not support!", myname, __LINE__); + return (NULL); +#endif +} + +ACL_EVENT *acl_event_new_wmsg(unsigned int nMsg) +{ +#ifdef ACL_EVENTS_STYLE_WMSG + ACL_EVENT *eventp; + int fdsize; + + fdsize = event_limit(0); + eventp = event_new_wmsg(nMsg); + event_init(eventp, fdsize, 0, 0); + return (eventp); +#else + const char *myname = "acl_event_new_kernel"; + + (void) nMsg; + acl_msg_fatal("%s(%d): not support!", myname, __LINE__); + return (NULL); +#endif +} + +ACL_EVENT *acl_event_new(int event_mode, int use_thr, int delay_sec, int delay_usec) +{ + const char *myname = "acl_event_new"; + ACL_EVENT *eventp = NULL; + + if (use_thr) { + switch (event_mode) { + case ACL_EVENT_SELECT: + eventp = acl_event_new_select_thr(delay_sec, delay_usec); + break; + case ACL_EVENT_KERNEL: + eventp = acl_event_new_kernel_thr(delay_sec, delay_usec); + break; + case ACL_EVENT_POLL: + eventp = acl_event_new_poll_thr(delay_sec, delay_usec); + break; + default: + acl_msg_fatal("%s(%d): unsupport %d event", + myname, __LINE__, event_mode); + break; + } + } else { + switch (event_mode) { + case ACL_EVENT_SELECT: + eventp = acl_event_new_select(delay_sec, delay_usec); + break; + case ACL_EVENT_KERNEL: + eventp = acl_event_new_kernel(delay_sec, delay_usec); + break; + case ACL_EVENT_KERNEL2: + eventp = acl_event_new_kernel2(delay_sec, delay_usec); + break; + case ACL_EVENT_KERNEL3: + eventp = acl_event_new_kernel3(delay_sec, delay_usec); + break; + case ACL_EVENT_POLL: + eventp = acl_event_new_poll(delay_sec, delay_usec); + break; + case ACL_EVENT_WMSG: + /* 使用该值作为消息号 */ + eventp = acl_event_new_wmsg((unsigned int) delay_sec); + break; + default: + acl_msg_fatal("%s(%d): unsupport %d event", + myname, __LINE__, event_mode); + break; + } + } + + return (eventp); +} + +void acl_event_add_dog(ACL_EVENT *eventp) +{ + eventp->add_dog_fn(eventp); +} + +void acl_event_free(ACL_EVENT *eventp) +{ + void (*free_fn)(ACL_EVENT *) = eventp->free_fn; + ACL_EVENT_TIMER *timer; + + while ((timer = ACL_FIRST_TIMER(&eventp->timer_head)) != 0) { + acl_ring_detach(&timer->ring); + acl_myfree(timer); + } + acl_myfree(eventp->fdtabs); + acl_myfree(eventp->fdtabs_ready); + free_fn(eventp); +} + +acl_int64 acl_event_time(ACL_EVENT *eventp) +{ + return (eventp->event_present); +} + +void acl_event_enable_read(ACL_EVENT *eventp, ACL_VSTREAM *stream, + int read_timeout, ACL_EVENT_NOTIFY_RDWR callback, void *context) +{ + const char *myname = "acl_event_enable_read"; + ACL_SOCKET sockfd = ACL_VSTREAM_SOCK(stream); + if (sockfd == ACL_SOCKET_INVALID) + acl_msg_fatal("%s(%d): sockfd(%d) invalid", + myname, __LINE__, sockfd); + eventp->enable_read_fn(eventp, stream, read_timeout, callback, context); +} + +void acl_event_enable_write(ACL_EVENT *eventp, ACL_VSTREAM *stream, + int write_timeout, ACL_EVENT_NOTIFY_RDWR callback, void *context) +{ + const char *myname = "acl_event_enable_write"; + ACL_SOCKET sockfd = ACL_VSTREAM_SOCK(stream); + if (sockfd == ACL_SOCKET_INVALID) + acl_msg_fatal("%s(%d): sockfd(%d) invalid", + myname, __LINE__, sockfd); + eventp->enable_write_fn(eventp, stream, write_timeout, callback, context); +} + +void acl_event_enable_listen(ACL_EVENT *eventp, ACL_VSTREAM *stream, + int read_timeout, ACL_EVENT_NOTIFY_RDWR callback, void *context) +{ + eventp->enable_listen_fn(eventp, stream, read_timeout, callback, context); +} + +void acl_event_disable_read(ACL_EVENT *eventp, ACL_VSTREAM *stream) +{ + const char *myname = "acl_event_disable_read"; + ACL_SOCKET sockfd = ACL_VSTREAM_SOCK(stream); + if (sockfd == ACL_SOCKET_INVALID) + acl_msg_fatal("%s(%d): sockfd(%d) invalid", + myname, __LINE__, sockfd); + eventp->disable_read_fn(eventp, stream); +} + +void acl_event_disable_write(ACL_EVENT *eventp, ACL_VSTREAM *stream) +{ + const char *myname = "acl_event_disable_write"; + ACL_SOCKET sockfd = ACL_VSTREAM_SOCK(stream); + if (sockfd == ACL_SOCKET_INVALID) + acl_msg_fatal("%s(%d): sockfd(%d) invalid", + myname, __LINE__, sockfd); + eventp->disable_write_fn(eventp, stream); +} + +void acl_event_disable_readwrite(ACL_EVENT *eventp, ACL_VSTREAM *stream) +{ + eventp->disable_readwrite_fn(eventp, stream); +} + +int acl_event_isset(ACL_EVENT *eventp, ACL_VSTREAM *stream) +{ + return (acl_event_isrset(eventp, stream) || acl_event_iswset(eventp, stream)); +} + +int acl_event_isrset(ACL_EVENT *eventp, ACL_VSTREAM *stream) +{ + return (eventp->isrset_fn(eventp, stream)); +} + +int acl_event_iswset(ACL_EVENT *eventp, ACL_VSTREAM *stream) +{ + return (eventp->iswset_fn(eventp, stream)); +} + +int acl_event_isxset(ACL_EVENT *eventp, ACL_VSTREAM *stream) +{ + return (eventp->isxset_fn(eventp, stream)); +} + +acl_int64 acl_event_request_timer(ACL_EVENT *eventp, ACL_EVENT_NOTIFY_TIME callback, + void *context, acl_int64 delay, int keep) +{ + char myname[] = "acl_event_request_timer"; + + if (delay < 0) + acl_msg_panic("%s: invalid delay: %lld", myname, delay); + + return (eventp->timer_request(eventp, callback, context, delay, keep)); +} + +acl_int64 acl_event_cancel_timer(ACL_EVENT *eventp, ACL_EVENT_NOTIFY_TIME callback, + void *context) +{ + return (eventp->timer_cancel(eventp, callback, context)); +} + +void acl_event_keep_timer(ACL_EVENT *eventp, ACL_EVENT_NOTIFY_TIME callback, + void *context, int onoff) +{ + eventp->timer_keep(eventp, callback, context, onoff); +} + +int acl_event_timer_ifkeep(ACL_EVENT *eventp, ACL_EVENT_NOTIFY_TIME callback, + void *context) +{ + return (eventp->timer_ifkeep(eventp, callback, context)); +} + +void acl_event_loop(ACL_EVENT *eventp) +{ + eventp->loop_fn(eventp); +} + +void acl_event_set_delay_sec(ACL_EVENT *eventp, int sec) +{ + eventp->delay_sec = sec; +} + +void acl_event_set_delay_usec(ACL_EVENT *eventp, int usec) +{ + eventp->delay_usec = usec; +} + +int acl_event_use_thread(ACL_EVENT *eventp) +{ + return (eventp->use_thread); +} + +int acl_event_mode(ACL_EVENT *eventp) +{ + return (eventp->event_mode); +} diff --git a/lib_acl/src/event/acl_timer.c b/lib_acl/src/event/acl_timer.c new file mode 100644 index 000000000..89d976ce5 --- /dev/null +++ b/lib_acl/src/event/acl_timer.c @@ -0,0 +1,248 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include "stdlib/acl_ring.h" +#include "stdlib/acl_mymalloc.h" +#include "event/acl_timer.h" + +#endif + +#include "events.h" + +#define RING_TO_TIMER(r) \ + ((ACL_TIMER_INFO *) ((char *) (r) - offsetof(ACL_TIMER_INFO, entry))) + +#define FIRST_TIMER(head) \ + (acl_ring_succ(head) != (head) ? RING_TO_TIMER(acl_ring_succ(head)) : 0) + +acl_int64 acl_timer_request(ACL_TIMER* timer, void *obj, acl_int64 delay) +{ + ACL_RING_ITER iter; + ACL_TIMER_INFO *pTimerItem = NULL; + + SET_TIME(timer->present); + + acl_ring_foreach(iter, &timer->timer_header) { + pTimerItem = RING_TO_TIMER(iter.ptr); + if (pTimerItem->obj == obj) { + pTimerItem->when = timer->present + delay; + acl_ring_detach(iter.ptr); + break; + } + } + + /* If not found, schedule a new timer request. */ + if (iter.ptr == &timer->timer_header) { + pTimerItem = (ACL_TIMER_INFO*) + acl_mycalloc(1, sizeof(ACL_TIMER_INFO)); + pTimerItem->when = timer->present + delay; + pTimerItem->obj = obj; + } + + acl_ring_foreach(iter, &timer->timer_header) { + ACL_TIMER_INFO *pItem = RING_TO_TIMER(iter.ptr); + if (pTimerItem->when < pItem->when) + break; + } + acl_ring_prepend(iter.ptr, &pTimerItem->entry); + + return (pTimerItem->when); +} + +acl_int64 acl_timer_cancel(ACL_TIMER* timer, void *obj) +{ + ACL_RING_ITER iter; + acl_int64 time_left = -1; + + SET_TIME(timer->present); + + acl_ring_foreach(iter, &timer->timer_header) { + ACL_TIMER_INFO *pItem = RING_TO_TIMER(iter.ptr); + if (pItem->obj == obj) { + if ((time_left = pItem->when - timer->present) < 0) + time_left = 0; + acl_ring_detach(iter.ptr); + acl_myfree(pItem); + break; + } + } + + timer->time_left = time_left; + return (time_left); +} + +void *acl_timer_popup(ACL_TIMER* timer) +{ + ACL_TIMER_INFO *pTimerItem; + void *obj; + + SET_TIME(timer->present); + + pTimerItem = FIRST_TIMER(&timer->timer_header); + if (pTimerItem == NULL) + return (NULL); + + if (pTimerItem->when > timer->present) + return (NULL); + + acl_ring_detach(&pTimerItem->entry); /* first this */ + obj = pTimerItem->obj; + acl_myfree(pTimerItem); + + return (obj); +} + +acl_int64 acl_timer_left(ACL_TIMER* timer) +{ + ACL_TIMER_INFO *pTimerItem; + acl_int64 time_left = -1; + + SET_TIME(timer->present); + + pTimerItem = FIRST_TIMER(&timer->timer_header); + if (pTimerItem != NULL) { + time_left = pTimerItem->when - timer->present; + /* 如果下一个定时任务已经到期,则将剩余时间设定为0, + * 以使定时器尽快触发到期定时任务 + */ + if (time_left < 0) + time_left = 0; + } else { + /* 如果当时定时器没有定时任务,则将时间值赋为 -1 */ + time_left = -1; + } + + return (time_left); +} + +void acl_timer_walk(ACL_TIMER *timer, void (*action)(ACL_TIMER_INFO *, void *), void *arg) +{ + ACL_TIMER_INFO *info; + ACL_RING_ITER iter; + + acl_ring_foreach(iter, &timer->timer_header) { + info = RING_TO_TIMER(iter.ptr); + action(info, arg); + } +} + +static const void *timer_iter_head(ACL_ITER *iter, struct ACL_TIMER *timer) +{ + ACL_TIMER_INFO *info; + + iter->dlen = -1; + iter->key = NULL; + iter->klen = -1; + iter->i = 0; + iter->size = timer->timer_header.len; + iter->ptr = acl_ring_succ(&timer->timer_header); + if (iter->ptr == &timer->timer_header) { + iter->data = iter->ptr = NULL; + return (NULL); + } + info = RING_TO_TIMER(iter->ptr); + iter->data = info->obj; + return (iter->ptr); +} + +static const void *timer_iter_next(ACL_ITER *iter, struct ACL_TIMER *timer) +{ + ACL_TIMER_INFO *info; + + iter->i++; + iter->ptr = acl_ring_succ((ACL_RING*) iter->ptr); + if (iter->ptr == &timer->timer_header) { + iter->data = iter->ptr = NULL; + return (NULL); + } + info = RING_TO_TIMER(iter->ptr); + iter->data = info->obj; + return (iter->ptr); +} + +static const void *timer_iter_tail(ACL_ITER *iter, struct ACL_TIMER *timer) +{ + ACL_TIMER_INFO *info; + + iter->dlen = -1; + iter->key = NULL; + iter->klen = -1; + iter->size = timer->timer_header.len; + iter->i = iter->size - 1; + iter->ptr = acl_ring_pred(&timer->timer_header); + if (iter->ptr == &timer->timer_header) { + iter->data = iter->ptr = NULL; + return (NULL); + } + info = RING_TO_TIMER(iter->ptr); + iter->data = info->obj; + return (iter->ptr); + +} + +static const void *timer_iter_prev(ACL_ITER *iter, struct ACL_TIMER *timer) +{ + ACL_TIMER_INFO *info; + + iter->i--; + iter->ptr = acl_ring_pred((ACL_RING*) iter->ptr); + if (iter->ptr == &timer->timer_header) { + iter->data = iter->ptr = NULL; + return (NULL); + } + info = RING_TO_TIMER(iter->ptr); + iter->data = info->obj; + return (iter->ptr); +} + +static const ACL_TIMER_INFO *timer_iter_info(ACL_ITER *iter, struct ACL_TIMER *timer) +{ + ACL_TIMER_INFO *info; + + if (iter->ptr == NULL || iter->ptr == &timer->timer_header) + return (NULL); + + info = RING_TO_TIMER(iter->ptr); + return (info); +} + +ACL_TIMER *acl_timer_new() +{ + ACL_TIMER *timer; + + timer = (ACL_TIMER*) acl_mycalloc(1, sizeof(ACL_TIMER)); + timer->request = acl_timer_request; + timer->cancel = acl_timer_cancel; + timer->popup = acl_timer_popup; + + timer->iter_head = timer_iter_head; + timer->iter_next = timer_iter_next; + timer->iter_tail = timer_iter_tail; + timer->iter_prev = timer_iter_prev; + timer->iter_info = timer_iter_info; + + acl_ring_init(&timer->timer_header); + + return (timer); +} + +void acl_timer_free(ACL_TIMER* timer, void (*free_fn)(void *)) +{ + ACL_TIMER_INFO *info; + + while ((info = FIRST_TIMER(&timer->timer_header)) != NULL) { + if (free_fn) + free_fn(info->obj); + acl_ring_detach(&info->entry); + acl_myfree(info); + } + + acl_myfree(timer); +} + +int acl_timer_size(ACL_TIMER *timer) +{ + return (acl_ring_size(&timer->timer_header)); +} diff --git a/lib_acl/src/event/events.c b/lib_acl/src/event/events.c new file mode 100644 index 000000000..5b6d44e41 --- /dev/null +++ b/lib_acl/src/event/events.c @@ -0,0 +1,270 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_msg.h" + +#endif + +#include "events.h" + +void event_check_fds(ACL_EVENT *ev) +{ + ACL_EVENT_FDTABLE *fdp; + int i; + + for (i = 0; i < ev->fdcnt; i++) { + fdp = ev->fdtabs[i]; + if ((fdp->stream->flag & ACL_VSTREAM_FLAG_BAD) != 0) { + fdp->stream->flag &= ~ACL_VSTREAM_FLAG_BAD; + fdp->event_type |= ACL_EVENT_XCPT; + fdp->fdidx_ready = ev->fdcnt_ready; + ev->fdtabs_ready[ev->fdcnt_ready++] = fdp; + } else if ((fdp->flag & EVENT_FDTABLE_FLAG_READ)) { + if (ACL_VSTREAM_BFRD_CNT(fdp->stream) > 0) { + fdp->stream->sys_read_ready = 0; + fdp->event_type |= ACL_EVENT_READ; + fdp->fdidx_ready = ev->fdcnt_ready; + ev->fdtabs_ready[ev->fdcnt_ready++] = fdp; + } else if (fdp->r_ttl > 0 + && ev->event_present > fdp->r_ttl) + { + fdp->event_type |= ACL_EVENT_RW_TIMEOUT; + fdp->fdidx_ready = ev->fdcnt_ready; + ev->fdtabs_ready[ev->fdcnt_ready++] = fdp; + } + } else if ((fdp->flag & EVENT_FDTABLE_FLAG_WRITE)) { + if (fdp->w_ttl > 0 && ev->event_present > fdp->w_ttl) { + fdp->event_type |= ACL_EVENT_RW_TIMEOUT; + fdp->fdidx_ready = ev->fdcnt_ready; + ev->fdtabs_ready[ev->fdcnt_ready++] = fdp; + } + } + } +} + +int event_prepare(ACL_EVENT *ev) +{ + ACL_EVENT_FDTABLE *fdp; + ACL_SOCKET sockfd; + int i, nwait = 0; + + ev->fdcnt_ready = 0; + + for (i = 0; i < ev->fdcnt; i++) { + fdp = ev->fdtabs[i]; + sockfd = ACL_VSTREAM_SOCK(fdp->stream); + fdp->event_type = 0; + if (ev->maxfd < sockfd) + ev->maxfd = sockfd; + if ((fdp->stream->flag & ACL_VSTREAM_FLAG_BAD) != 0) { + fdp->stream->flag &= ~ACL_VSTREAM_FLAG_BAD; + fdp->event_type |= ACL_EVENT_XCPT; + fdp->fdidx_ready = ev->fdcnt_ready; + ev->fdtabs_ready[ev->fdcnt_ready++] = fdp; + } else if ((fdp->flag & EVENT_FDTABLE_FLAG_READ)) { + if (ACL_VSTREAM_BFRD_CNT(fdp->stream) > 0) { + fdp->stream->sys_read_ready = 0; + fdp->event_type |= ACL_EVENT_READ; + fdp->fdidx_ready = ev->fdcnt_ready; + ev->fdtabs_ready[ev->fdcnt_ready++] = fdp; + } else if (fdp->r_ttl > 0 + && ev->event_present > fdp->r_ttl) + { + fdp->event_type |= ACL_EVENT_RW_TIMEOUT; + fdp->fdidx_ready = ev->fdcnt_ready; + ev->fdtabs_ready[ev->fdcnt_ready++] = fdp; + } else + nwait++; + } else if ((fdp->flag & EVENT_FDTABLE_FLAG_WRITE)) { + if (fdp->w_ttl > 0 && ev->event_present > fdp->w_ttl) { + fdp->event_type |= ACL_EVENT_RW_TIMEOUT; + fdp->fdidx_ready = ev->fdcnt_ready; + ev->fdtabs_ready[ev->fdcnt_ready++] = fdp; + } else + nwait++; + } else { + nwait++; + } + } + return nwait; +} + +void event_fire(ACL_EVENT *ev) +{ + ACL_EVENT_FDTABLE *fdp; + int i, event_type; + acl_int64 r_timeout, w_timeout; + ACL_EVENT_NOTIFY_RDWR r_callback, w_callback; + + for (i = 0; i < ev->fdcnt_ready; i++) { + fdp = ev->fdtabs_ready[i]; + /* ev->fdtabs_ready[i] maybe be set NULL in timer callback */ + if (fdp == NULL || fdp->stream == NULL) + continue; + event_type = fdp->event_type; + + if ((event_type & ACL_EVENT_XCPT) != 0) { + fdp->event_type &= ~ACL_EVENT_XCPT; + r_callback = fdp->r_callback; + w_callback = fdp->w_callback; + + if (r_callback) + r_callback(ACL_EVENT_XCPT, fdp->r_context); + + /* ev->fdtabs_ready[i] maybe be set NULL in r_callback */ + if (w_callback && ev->fdtabs_ready[i]) + w_callback(ACL_EVENT_XCPT, fdp->w_context); + continue; + } + + if ((event_type & ACL_EVENT_RW_TIMEOUT) != 0) { + fdp->event_type &= ~ACL_EVENT_RW_TIMEOUT; + r_timeout = fdp->r_timeout; + w_timeout = fdp->w_timeout; + r_callback = fdp->r_callback; + w_callback = fdp->w_callback; + + if (r_timeout > 0 && r_callback) { + fdp->r_ttl = ev->event_present + fdp->r_timeout; + fdp->r_callback(ACL_EVENT_RW_TIMEOUT, fdp->r_context); + } + + /* ev->fdtabs_ready[i] maybe be set NULL in r_callback */ + if (w_timeout > 0 && w_callback && ev->fdtabs_ready[i]) { + fdp->w_ttl = ev->event_present + fdp->w_timeout; + fdp->w_callback(ACL_EVENT_RW_TIMEOUT, fdp->w_context); + } + continue; + } + + if ((event_type & ACL_EVENT_READ) != 0) { + fdp->event_type &= ~ACL_EVENT_READ; + if (fdp->r_timeout > 0) + fdp->r_ttl = ev->event_present + fdp->r_timeout; + fdp->r_callback(ACL_EVENT_READ, fdp->r_context); + } + + /* ev->fdtabs_ready[i] maybe be set NULL in fdp->r_callback() */ + if ((event_type & ACL_EVENT_WRITE) && ev->fdtabs_ready[i]) { + if (fdp->w_timeout > 0) + fdp->w_ttl = ev->event_present + fdp->w_timeout; + fdp->event_type &= ~ACL_EVENT_WRITE; + fdp->w_callback(ACL_EVENT_WRITE, fdp->w_context); + } + } +} + +int event_thr_prepare(ACL_EVENT *ev) +{ + ACL_SOCKET sockfd; + ACL_EVENT_FDTABLE *fdp; + int i, nwait = 0; + + ev->fdcnt_ready = 0; + + for (i = 0; i < ev->fdcnt; i++) { + fdp = ev->fdtabs[i]; + sockfd = ACL_VSTREAM_SOCK(fdp->stream); + fdp->event_type = 0; + if (ev->maxfd < sockfd) + ev->maxfd = sockfd; + + if (fdp->listener) { + nwait++; + continue; + } + + if (fdp->stream->flag & ACL_VSTREAM_FLAG_BAD) { + fdp->stream->flag &= ~ACL_VSTREAM_FLAG_BAD; + fdp->event_type |= ACL_EVENT_XCPT; + fdp->fdidx_ready = ev->fdcnt_ready; + ev->fdtabs_ready[ev->fdcnt_ready++] = fdp; + } else if ((fdp->flag & EVENT_FDTABLE_FLAG_READ)) { + if (ACL_VSTREAM_BFRD_CNT(fdp->stream) > 0) { + fdp->stream->sys_read_ready = 0; + fdp->event_type = ACL_EVENT_READ; + fdp->fdidx_ready = ev->fdcnt_ready; + ev->fdtabs_ready[ev->fdcnt_ready++] = fdp; + } else if (fdp->r_ttl > 0 + && ev->event_present > fdp->r_ttl) + { + fdp->event_type = ACL_EVENT_RW_TIMEOUT; + fdp->fdidx_ready = ev->fdcnt_ready; + ev->fdtabs_ready[ev->fdcnt_ready++] = fdp; + } else + nwait++; + } else if ((fdp->flag & EVENT_FDTABLE_FLAG_WRITE)) { + if (fdp->w_ttl > 0 && ev->event_present > fdp->w_ttl) { + fdp->event_type = ACL_EVENT_RW_TIMEOUT; + fdp->fdidx_ready = ev->fdcnt_ready; + ev->fdtabs_ready[ev->fdcnt_ready++] = fdp; + } else + nwait++; + } else { + nwait++; + } + } + + return nwait; +} + +void event_thr_fire(ACL_EVENT *ev) +{ + ACL_EVENT_FDTABLE *fdp; + ACL_EVENT_NOTIFY_FN worker_fn; + void *worker_arg; + int i; + + for (i = 0; i < ev->fdcnt_ready; i++) { + fdp = ev->fdtabs_ready[i]; + /* ev->fdtabs_ready[i] maybe be set NULL by timer callback */ + if (fdp == NULL || fdp->stream == NULL) + continue; + + if (fdp->event_type & ACL_EVENT_XCPT) { + fdp->event_type &= ~ACL_EVENT_XCPT; + if (fdp->r_callback) { + worker_fn = fdp->r_callback; + worker_arg = fdp->r_context; + } else if (fdp->w_callback) { + worker_fn = fdp->w_callback; + worker_arg = fdp->w_context; + } else { + worker_fn = NULL; + worker_arg = NULL; + } + ev->disable_readwrite_fn(ev, fdp->stream); + if (worker_fn) + worker_fn(ACL_EVENT_XCPT, worker_arg); + } else if (fdp->event_type & ACL_EVENT_RW_TIMEOUT) { + fdp->event_type &= ~ACL_EVENT_RW_TIMEOUT; + if (fdp->r_callback) { + worker_fn = fdp->r_callback; + worker_arg = fdp->r_context; + } else if (fdp->w_callback) { + worker_fn = fdp->w_callback; + worker_arg = fdp->w_context; + } else { + worker_fn = NULL; + worker_arg = NULL; + } + if (!fdp->listener) + ev->disable_readwrite_fn(ev, fdp->stream); + if (worker_fn) + worker_fn(ACL_EVENT_RW_TIMEOUT, worker_arg); + } else if (fdp->event_type & ACL_EVENT_READ) { + fdp->event_type &= ~ACL_EVENT_READ; + worker_fn = fdp->r_callback; + worker_arg = fdp->r_context; + if (!fdp->listener) + ev->disable_readwrite_fn(ev, fdp->stream); + worker_fn(ACL_EVENT_READ, worker_arg); + } else if (fdp->event_type & ACL_EVENT_WRITE) { + fdp->event_type &= ~ACL_EVENT_WRITE; + worker_fn = fdp->w_callback; + worker_arg = fdp->w_context; + ev->disable_readwrite_fn(ev, fdp->stream); + worker_fn(ACL_EVENT_WRITE, worker_arg); + } + } +} diff --git a/lib_acl/src/event/events.h b/lib_acl/src/event/events.h new file mode 100644 index 000000000..6e802785b --- /dev/null +++ b/lib_acl/src/event/events.h @@ -0,0 +1,346 @@ +#ifndef __EVENTS_INCLUDED_H__ +#define __EVENTS_INCLUDED_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_define.h" +#include +#include "stdlib/acl_ring.h" +#include "stdlib/acl_vstream.h" +#include "stdlib/acl_fifo.h" +#include "thread/acl_thread.h" +#include "event/acl_events.h" + +#include "events_dog.h" +#include "fdmap.h" +#include "events_define.h" +#include "events_epoll.h" +#include "events_devpoll.h" + +/* + * I/O events. We pre-allocate one data structure per file descriptor. XXX + * For now use FD_SETSIZE as defined along with the fd-set type. + */ + +#ifdef ACL_MS_WINDOWS +typedef struct IOCP_EVENT IOCP_EVENT; +#endif + +struct ACL_EVENT_FDTABLE { + ACL_VSTREAM *stream; + ACL_EVENT_NOTIFY_RDWR r_callback; + ACL_EVENT_NOTIFY_RDWR w_callback; + void *r_context; + void *w_context; + acl_int64 r_ttl; + acl_int64 w_ttl; + acl_int64 r_timeout; + acl_int64 w_timeout; + int event_type; + int listener; /* if the fd is a listening fd */ + int flag; +#define EVENT_FDTABLE_FLAG_READ (1 << 1) +#define EVENT_FDTABLE_FLAG_WRITE (1 << 2) +#define EVENT_FDTABLE_FLAG_EXPT (1 << 3) +#define EVENT_FDTABLE_FLAG_ADD_READ (1 << 4) +#define EVENT_FDTABLE_FLAG_ADD_WRITE (1 << 5) +#define EVENT_FDTABLE_FLAG_DEL_READ (1 << 6) +#define EVENT_FDTABLE_FLAG_DEL_WRITE (1 << 7) +#define EVENT_FDTABLE_FLAG_DELAY_OPER (1 << 8) +#define EVENT_FDTABLE_FLAG_IOCP (1 << 9) + + int fdidx; + int fdidx_ready; + ACL_RING delay_entry; + +#ifdef ACL_MS_WINDOWS + HANDLE h_iocp; + IOCP_EVENT *event_read; + IOCP_EVENT *event_write; +#endif +}; + +struct ACL_EVENT { + /* 事件引擎名称标识 */ + char name[128]; + + /* 事件引擎: + * ACL_EVENT_SELECT, ACL_EVENT_KERNEL, + * ACL_EVENT_POLL, ACL_EVENT_WMSG + */ + int event_mode; + /* 该事件引擎是否在多线程环境下使用 */ + int use_thread; + + /* 避免事件引擎被嵌套调用 */ + int nested; + /* 当前时间截(微秒级) */ + acl_int64 event_present; + acl_int64 event_last_debug; + /* 事件引擎的最大等待时间(秒) */ + int delay_sec; + /* 事件引擎的最大等待时间(微秒) */ + int delay_usec; + /* 定时器任务列表头 */ + ACL_RING timer_head; + + /* + ACL_RING used_ring; + ACL_RING slot_ring; + ACL_RING ready_ring; + ACL_RING wait_ring; + */ + + /* 套接字最大个数 */ + int fdsize; + /* 当前套接字个数 */ + int fdcnt; + /* 事件循环时准备好的套接字个数 */ + int fdcnt_ready; + /* int fdtab_free_cnt; */ + /* 套接字事件对象表集合 */ + ACL_EVENT_FDTABLE **fdtabs; + /* 准备好的套接字事件对象表集合 */ + ACL_EVENT_FDTABLE **fdtabs_ready; + /* 本进程中最大套接字值 */ + ACL_SOCKET maxfd; + + /* 事件引擎的循环检查过程 */ + void (*loop_fn)(ACL_EVENT *ev); + /* 有些事件引擎可能需要提前进行初始化 */ + void (*init_fn)(ACL_EVENT *ev); + /* 释放事件引擎对象 */ + void (*free_fn)(ACL_EVENT *ev); + /* 当在多线程下使用事件引擎时,需要此接口及时唤醒事件引擎 */ + void (*add_dog_fn)(ACL_EVENT *ev); + + /* 开始监控某个套接字的可读状态 */ + void (*enable_read_fn)(ACL_EVENT *, ACL_VSTREAM *, int, + ACL_EVENT_NOTIFY_RDWR, void *); + /* 开始监控某个套接字的可写状态 */ + void (*enable_write_fn)(ACL_EVENT *, ACL_VSTREAM *, int, + ACL_EVENT_NOTIFY_RDWR, void *); + /* 开始监控监听套接口的可读状态 */ + void (*enable_listen_fn)(ACL_EVENT *, ACL_VSTREAM *, int, + ACL_EVENT_NOTIFY_RDWR, void *); + + /* 停止监控某个套接口的可读状态 */ + void (*disable_read_fn)(ACL_EVENT *, ACL_VSTREAM *); + /* 停止监控某个套接口的可写状态 */ + void (*disable_write_fn)(ACL_EVENT *, ACL_VSTREAM *); + /* 停止监控某个套接口的读、写状态 */ + void (*disable_readwrite_fn)(ACL_EVENT *, ACL_VSTREAM *); + + /* 套接口的可读状态是否被监控 */ + int (*isrset_fn)(ACL_EVENT *, ACL_VSTREAM *); + /* 套接口的可写状态是否被监控 */ + int (*iswset_fn)(ACL_EVENT *, ACL_VSTREAM *); + /* 套接口的异常状态是否被监控 */ + int (*isxset_fn)(ACL_EVENT *, ACL_VSTREAM *); + + /* 添加定时器任务 */ + acl_int64 (*timer_request)(ACL_EVENT *ev, ACL_EVENT_NOTIFY_TIME, + void *, acl_int64, int); + /* 取消定时器任务 */ + acl_int64 (*timer_cancel)(ACL_EVENT *ev, + ACL_EVENT_NOTIFY_TIME, void *); + /* 设置定时器是否为循环执行 */ + void (*timer_keep)(ACL_EVENT *ev, ACL_EVENT_NOTIFY_TIME, + void *, int); + /* 定时器是否循环执行的 */ + int (*timer_ifkeep)(ACL_EVENT *eventp, ACL_EVENT_NOTIFY_TIME, void *); +}; + +/* +如果采用自旋锁,性能反而下降非常厉害,可能与加锁时间片长有关系 +#ifdef ACL_HAS_SPINLOCK +#define EVENT_USE_SPINLOCK +#endif +*/ + +typedef struct EVENT_THR { + ACL_EVENT event; + + /* just for thread */ +#ifdef EVENT_USE_SPINLOCK + pthread_spinlock_t tm_mutex; + pthread_spinlock_t tb_mutex; +#else + acl_pthread_mutex_t tm_mutex; + acl_pthread_mutex_t tb_mutex; +#endif + EVENT_DOG *evdog; + int blocked; +} EVENT_THR; + +/* local macro */ +#define FD_ENTRY_CLR(_fdp_) do { \ + _fdp_->stream = NULL; \ + _fdp_->r_callback = NULL; \ + _fdp_->w_callback = NULL; \ + _fdp_->r_context = NULL; \ + _fdp_->w_context = NULL; \ + _fdp_->r_ttl = 0; \ + _fdp_->w_ttl = 0; \ + _fdp_->r_timeout = 0; \ + _fdp_->w_timeout = 0; \ + _fdp_->listener = 0; \ + _fdp_->event_type = 0; \ + _fdp_->flag = 0; \ + _fdp_->fdidx = -1; \ + _fdp_->fdidx_ready = -1; \ + _fdp_->fifo_info = NULL; \ +} while (0); + +/* in events.c */ +void event_check_fds(ACL_EVENT *ev); +int event_prepare(ACL_EVENT *ev); +void event_fire(ACL_EVENT *ev); +int event_thr_prepare(ACL_EVENT *ev); +void event_thr_fire(ACL_EVENT *ev); + +/* in events_alloc.c */ +ACL_EVENT *event_alloc(size_t size); + +/* in events_select.c */ +ACL_EVENT *event_new_select(void); + +/* in events_select_thr.c */ +ACL_EVENT *event_new_select_thr(void); + +/* in events_poll.c */ +ACL_EVENT *event_new_poll(int fdsize); + +/* in events_poll_thr.c */ +ACL_EVENT *event_new_poll_thr(int fdsize); + +/* in events_kernel.c */ +ACL_EVENT *event_new_kernel(int fdsize); + +/* in events_kernel2.c */ +ACL_EVENT *event_new_kernel2(int fdsize); + +/* in events_kernel2.3 */ +ACL_EVENT *event_new_kernel3(int fdsize); + +/* in events_kernel_thr.c */ +ACL_EVENT *event_new_kernel_thr(int fdsize); + +struct ACL_EVENT_TIMER { + acl_int64 when; /* when event is wanted */ + acl_int64 delay; /* timer deley */ + ACL_EVENT_NOTIFY_TIME callback; /* callback function */ + int event_type; + void *context; /* callback context */ + ACL_RING ring; /* linkage */ + int nrefer; /* refered's count */ + int ncount; /* timer callback count */ + /* 定时器被触发后是否会被自动加入下一个定时器过程 */ + int keep; +}; + +#define ACL_RING_TO_TIMER(r) \ + ((ACL_EVENT_TIMER *) ((char *) (r) - offsetof(ACL_EVENT_TIMER, ring))) + +#define ACL_FIRST_TIMER(head) \ + (acl_ring_succ(head) != (head) ? ACL_RING_TO_TIMER(acl_ring_succ(head)) : 0) + +#ifdef EVENT_USE_SPINLOCK + +# define LOCK_INIT(mutex_in) do { \ + pthread_spinlock_t *sp = mutex_in; \ + int status = pthread_spin_init(sp, PTHREAD_PROCESS_PRIVATE); \ + if (status != 0) \ + acl_msg_fatal("%s(%d): init lock error(%s)", \ + __FILE__, __LINE__, strerror(status)); \ +} while (0) + +# define LOCK_DESTROY(mutex_in) do { \ + pthread_spinlock_t *sp = mutex_in; \ + pthread_spin_destroy(sp); \ +} while (0) + +# define THREAD_LOCK(mutex_in) do { \ + pthread_spinlock_t *sp = mutex_in; \ + int status = pthread_spin_lock(sp); \ + if (status != 0) \ + acl_msg_fatal("%s(%d): lock error(%s)", \ + __FILE__, __LINE__, strerror(status)); \ +} while (0) + +# define THREAD_UNLOCK(mutex_in) do { \ + pthread_spinlock_t *sp = mutex_in; \ + int status = pthread_spin_unlock(sp); \ + if (status != 0) \ + acl_msg_fatal("%s(%d): unlock error(%s)", \ + __FILE__, __LINE__, strerror(status)); \ +} while (0) + +#else + +# define LOCK_INIT(mutex_in) do { \ + acl_pthread_mutex_t *mutex_ptr = (mutex_in); \ + int status = acl_pthread_mutex_init(mutex_ptr, NULL); \ + if (status != 0) \ + acl_msg_fatal("%s(%d): init lock error(%s)", \ + __FILE__, __LINE__, strerror(status)); \ +} while (0) + +# define LOCK_DESTROY(mutex_in) do { \ + acl_pthread_mutex_t *mutex_ptr = (mutex_in); \ + (void) acl_pthread_mutex_destroy(mutex_ptr); \ +} while (0) + +# define THREAD_LOCK(mutex_in) do { \ + acl_pthread_mutex_t *mutex_ptr = (mutex_in); \ + int status = acl_pthread_mutex_lock(mutex_ptr); \ + if (status != 0) \ + acl_msg_fatal("%s(%d): lock error(%s)", \ + __FILE__, __LINE__, strerror(status)); \ +} while (0) + +# define THREAD_UNLOCK(mutex_in) do { \ + acl_pthread_mutex_t *mutex_ptr = (mutex_in); \ + int status = acl_pthread_mutex_unlock(mutex_ptr); \ + if (status != 0) \ + acl_msg_fatal("%s(%d): unlock error(%s)", \ + __FILE__, __LINE__, strerror(status)); \ +} while (0) + +#endif + +#define SET_TIME(x) { \ + struct timeval _tv; \ + gettimeofday(&_tv, NULL); \ + (x) = ((acl_int64) _tv.tv_sec) * 1000000 + ((acl_int64) _tv.tv_usec); \ +} + +/* in events_timer.c */ +acl_int64 event_timer_request(ACL_EVENT *ev, ACL_EVENT_NOTIFY_TIME callback, + void *context, acl_int64 delay, int keep); +acl_int64 event_timer_cancel(ACL_EVENT *ev, ACL_EVENT_NOTIFY_TIME callback, + void *context); +void event_timer_keep(ACL_EVENT *ev, ACL_EVENT_NOTIFY_TIME callback, + void *context, int keep); +int event_timer_ifkeep(ACL_EVENT *ev, ACL_EVENT_NOTIFY_TIME callback, + void *context); + +/* in events_timer_thr.c */ +acl_int64 event_timer_request_thr(ACL_EVENT *ev, + ACL_EVENT_NOTIFY_TIME callback, void *context, + acl_int64 delay, int keep); +acl_int64 event_timer_cancel_thr(ACL_EVENT *ev, + ACL_EVENT_NOTIFY_TIME callback, void *context); + +void event_timer_keep_thr(ACL_EVENT *ev, ACL_EVENT_NOTIFY_TIME callback, + void *context, int keep); +int event_timer_ifkeep_thr(ACL_EVENT *ev, ACL_EVENT_NOTIFY_TIME callback, + void *context); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/src/event/events_alloc.c b/lib_acl/src/event/events_alloc.c new file mode 100644 index 000000000..7be8e09f3 --- /dev/null +++ b/lib_acl/src/event/events_alloc.c @@ -0,0 +1,177 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_msg.h" +#include "stdlib/acl_mystring.h" +#include "event/acl_events.h" + +#endif + +#include "events.h" + +static void event_default_loop(ACL_EVENT *eventp) +{ + const char *myname = "event_default_loop"; + acl_msg_fatal("%s(%d): Not supported in %s", + myname, __LINE__, eventp->name); +} + +static void event_default_enable_read(ACL_EVENT *eventp, + ACL_VSTREAM *stream acl_unused, + int timeout acl_unused, + ACL_EVENT_NOTIFY_RDWR callback acl_unused, + void *context acl_unused) +{ + const char *myname = "event_default_enable_read"; + acl_msg_fatal("%s(%d): Not supported in %s", + myname, __LINE__, eventp->name); +} + +static void event_default_enable_write(ACL_EVENT *eventp, + ACL_VSTREAM *stream acl_unused, + int timeout acl_unused, + ACL_EVENT_NOTIFY_RDWR callback acl_unused, + void *context acl_unused) +{ + const char *myname = "event_default_enable_write"; + acl_msg_fatal("%s(%d): Not supported in %s", + myname, __LINE__, eventp->name); +} + +static void event_default_disable_read(ACL_EVENT *eventp, + ACL_VSTREAM *stream acl_unused) +{ + const char *myname = "event_default_disable_read"; + acl_msg_fatal("%s(%d): Not supported in %s", + myname, __LINE__, eventp->name); +} + +static void event_default_disable_write(ACL_EVENT *eventp, + ACL_VSTREAM *stream acl_unused) +{ + const char *myname = "event_default_disable_write"; + acl_msg_fatal("%s(%d): Not supported in %s", + myname, __LINE__, eventp->name); +} + +static void event_default_disable_readwrite(ACL_EVENT *eventp, + ACL_VSTREAM *stream acl_unused) +{ + const char *myname = "event_default_disable_readwrite"; + acl_msg_fatal("%s(%d): Not supported in %s", + myname, __LINE__, eventp->name); +} + +static int event_default_isrset(ACL_EVENT *eventp, + ACL_VSTREAM *stream acl_unused) +{ + const char *myname = "event_default_isrset"; + acl_msg_fatal("%s(%d): Not supported in %s", + myname, __LINE__, eventp->name); + return (0); +} + +static int event_default_iswset(ACL_EVENT *eventp, + ACL_VSTREAM *stream acl_unused) +{ + const char *myname = "event_default_iswset"; + acl_msg_fatal("%s(%d): Not supported in %s", + myname, __LINE__, eventp->name); + return (0); +} + +static int event_default_isxset(ACL_EVENT *eventp, + ACL_VSTREAM *stream acl_unused) +{ + const char *myname = "event_default_isxset"; + acl_msg_fatal("%s(%d): Not supported %s", + myname, __LINE__, eventp->name); + return (0); +} + +static acl_int64 event_default_timer_request(ACL_EVENT *eventp, + ACL_EVENT_NOTIFY_TIME callback acl_unused, + void *context acl_unused, + acl_int64 delay acl_unused, + int keep acl_unused) +{ + const char *myname = "event_default_request_timer"; + acl_msg_fatal("%s(%d): Not supported in %s", + myname, __LINE__, eventp->name); + return (0); +} + +static acl_int64 event_default_timer_cancel(ACL_EVENT *eventp, + ACL_EVENT_NOTIFY_TIME callback acl_unused, + void *context acl_unused) +{ + const char *myname = "event_default_cancel_timer"; + acl_msg_fatal("%s(%d): Not supported in %s", + myname, __LINE__, eventp->name); + return (0); +} + +static void event_default_timer_keep(ACL_EVENT *eventp, + ACL_EVENT_NOTIFY_TIME callback acl_unused, + void * ctx acl_unused, int keep acl_unused) +{ + const char *myname = "event_default_cancel_timer"; + acl_msg_fatal("%s(%d): Not supported in %s", + myname, __LINE__, eventp->name); +} + +static int event_default_timer_ifkeep(ACL_EVENT *eventp, + ACL_EVENT_NOTIFY_TIME callback acl_unused, void * ctx acl_unused) +{ + const char *myname = "event_default_timer_ifkeep"; + acl_msg_fatal("%s(%d): Not supported in %s", + myname, __LINE__, eventp->name); + return 0; +} + +static void event_default_add_dog(ACL_EVENT *eventp) +{ + const char *myname = "event_default_add_dog"; + acl_msg_fatal("%s(%d): Not supported in %s", + myname, __LINE__, eventp->name); +} + +static void event_default_free(ACL_EVENT *eventp) +{ + acl_myfree(eventp); +} + +ACL_EVENT *event_alloc(size_t size) +{ + const char *myname = "event_alloc"; + ACL_EVENT *eventp; + + if (size < sizeof(ACL_EVENT)) + acl_msg_fatal("%s(%d): size(%d) too small", + myname, __LINE__, (int) size); + eventp = acl_mycalloc(1, size); + + ACL_SAFE_STRNCPY(eventp->name, "events_alloc", sizeof(eventp->name)); + eventp->init_fn = NULL; + eventp->loop_fn = event_default_loop; + eventp->free_fn = event_default_free; + eventp->add_dog_fn = event_default_add_dog; + eventp->enable_read_fn = event_default_enable_read; + eventp->enable_write_fn = event_default_enable_write; + eventp->enable_listen_fn = event_default_enable_read; + eventp->disable_read_fn = event_default_disable_read; + eventp->disable_write_fn = event_default_disable_write; + eventp->disable_readwrite_fn = event_default_disable_readwrite; + eventp->isrset_fn = event_default_isrset; + eventp->iswset_fn = event_default_iswset; + eventp->isxset_fn = event_default_isxset; + eventp->timer_request = event_default_timer_request; + eventp->timer_cancel = event_default_timer_cancel; + eventp->timer_keep = event_default_timer_keep; + eventp->timer_ifkeep = event_default_timer_ifkeep; + + return (eventp); +} diff --git a/lib_acl/src/event/events_define.h b/lib_acl/src/event/events_define.h new file mode 100644 index 000000000..830f57b95 --- /dev/null +++ b/lib_acl/src/event/events_define.h @@ -0,0 +1,49 @@ + +#ifndef __EVENTS_DEFINE_INCLUDE_H__ +#define __EVENTS_DEFINE_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_define.h" +#include "stdlib/acl_mymalloc.h" +#include + +#define ACL_EVENT_ALLOC_INCR 10 + +#define ACL_EVENTS_STYLE_SELECT 1 +#define ACL_EVENTS_STYLE_EPOLL 2 +#define ACL_EVENTS_STYLE_DEVPOLL 3 +#define ACL_EVENTS_STYLE_KQUEUE 4 + +#ifdef ACL_MS_WINDOWS +# if(_MSC_VER >= 1300) +# define ACL_EVENTS_STYLE_IOCP 5 +# endif +# define ACL_EVENTS_STYLE_WMSG 6 +#endif + +#ifdef LINUX2 +# define ACL_EVENTS_KERNEL_STYLE ACL_EVENTS_STYLE_EPOLL +#elif defined(SUNOS5) +# define ACL_EVENTS_KERNEL_STYLE ACL_EVENTS_STYLE_DEVPOLL +# define USE_FDMAP +#elif defined(FREEBSD) || defined(MACOSX) +# define ACL_EVENTS_KERNEL_STYLE ACL_EVENTS_STYLE_KQUEUE +#else +# undef ACL_EVENTS_KERNEL_STYLE +#endif + +#ifdef ACL_UNIX +# define ACL_EVENTS_POLL_STYLE 5 +#else +# undef ACL_EVENTS_POLL_STYLE +#endif + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/src/event/events_devpoll.h b/lib_acl/src/event/events_devpoll.h new file mode 100644 index 000000000..09f5f5cff --- /dev/null +++ b/lib_acl/src/event/events_devpoll.h @@ -0,0 +1,100 @@ + +#ifndef __EVENTS_DEVPOLL_INCLUDE_H__ +#define __EVENTS_DEVPOLL_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "events_define.h" + + /* + * Solaris /dev/poll does not support application context, so we have to + * maintain our own. This has the benefit of avoiding an expensive system + * call just to change a call-back function or argument. + * + * Solaris /dev/poll does have a way to query if a specific descriptor is + * registered. However, we maintain a descriptor mask anyway because a) it + * avoids having to make an expensive system call to find out if something + * is registered, b) some EVENTS_STYLE_MUMBLE implementations need a + * descriptor bitmask anyway and c) we use the bitmask already to implement + * sanity checks. + */ +#if (ACL_EVENTS_KERNEL_STYLE == ACL_EVENTS_STYLE_DEVPOLL) +#include +#include + +#define EVENT_NAME "devpoll" + + /* + * Macros to initialize the kernel-based filter; see event_init(). + */ + +#define EVENT_REG_INIT_HANDLE(eh, n) do { \ + eh = open("/dev/poll", O_RDWR); \ +} while (0) +#define EVENT_REG_INIT_TEXT "open /dev/poll" + + /* + * Macros to update the kernel-based filter; see event_enable_read(), + * event_enable_write() and event_disable_readwrite(). + */ +#define EVENT_REG_FD_OP(er, eh, fh, ev) do { \ + struct pollfd dummy; \ + dummy.fd = (fh); \ + dummy.events = (ev); \ + dummy.revents = 0; \ + (er) = write(eh, (char *) &dummy, \ + sizeof(dummy)) != sizeof(dummy) ? -1 : 0; \ +} while (0) + +#define EVENT_REG_ADD_READ(er, eh, fh, ctx_dummy) \ + EVENT_REG_FD_OP((er), (eh), (fh), POLLIN) +#define EVENT_REG_ADD_WRITE(er, eh, fh, ctx_dummy) \ + EVENT_REG_FD_OP((er), (eh), (fh), POLLOUT) +#define EVENT_REG_ADD_RDWR(er, eh, fh, ctx_dummy) \ + EVENT_REG_FD_OP((er), (eh), (fh), POLLIN | POLLOUT) +#define EVENT_REG_ADD_TEXT "write /dev/poll add" + +#define EVENT_REG_MOD_READ(er, eh, fh, ctx_dummy) \ + EVENT_REG_FD_OP((er), (eh), (fh), POLLIN) +#define EVENT_REG_MOD_WRITE(er, eh, fh, ctx_dummy) \ + EVENT_REG_FD_OP((er), (eh), (fh), POLLOUT) +#define EVENT_REG_MOD_RDWR(er, eh, fh, ctx_dummy) \ + EVENT_REG_FD_OP((er), (eh), (fh), POLLIN | POLLOUT) +#define EVENT_REG_MOD_TEXT "write /dev/poll modify" + +#define EVENT_REG_DEL_BOTH(er, eh, fh) \ + EVENT_REG_FD_OP((er), (eh), (fh), POLLREMOVE) +#define EVENT_REG_DEL_TEXT "write /dev/poll delete" + + /* + * Macros to retrieve event buffers from the kernel; see event_loop(). + */ +typedef struct pollfd EVENT_BUFFER; + +#define EVENT_BUFFER_READ(ev_cnt, eh, ev_buf, buflen, delay) do { \ + struct dvpoll dvpoll; \ + dvpoll.dp_fds = (ev_buf); \ + dvpoll.dp_nfds = (buflen); \ + dvpoll.dp_timeout = (delay) < 0 ? -1 : (delay); \ + (ev_cnt) = ioctl(eh, DP_POLL, &dvpoll); \ +} while (0) +#define EVENT_BUFFER_READ_TEXT "ioctl DP_POLL" + + /* + * Macros to process event buffers from the kernel; see event_loop(). + */ +#define EVENT_GET_FD(bp) ((bp)->fd) +#define EVENT_GET_TYPE(bp) ((bp)->revents) +#define EVENT_TEST_READ(bp) (EVENT_GET_TYPE(bp) & POLLIN) +#define EVENT_TEST_WRITE(bp) (EVENT_GET_TYPE(bp) & POLLOUT) +#define EVENT_TEST_ERROR(bp) (EVENT_GET_TYPE(bp) & (POLLERR|POLLHUP|POLLNVAL)) + +#endif /* ACL_EVENTS_KERNEL_STYLE == ACL_EVENTS_STYLE_DEVPOLL */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/src/event/events_dog.c b/lib_acl/src/event/events_dog.c new file mode 100644 index 000000000..c58515c7b --- /dev/null +++ b/lib_acl/src/event/events_dog.c @@ -0,0 +1,151 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_msg.h" +#include "net/acl_vstream_net.h" +#include "stdlib/acl_iostuff.h" +#include "event/acl_events.h" + +#endif + +#include "events_dog.h" + +struct EVENT_DOG { + ACL_EVENT *eventp; + ACL_VSTREAM *sstream; + ACL_VSTREAM *server; + ACL_VSTREAM *client; + int thread_mode; +}; + +/* forward declare */ + +static void event_dog_reopen(EVENT_DOG *evdog); + +static void event_dog_close(EVENT_DOG *evdog) +{ + if (evdog->sstream) + acl_vstream_close(evdog->sstream); + if (evdog->server) + acl_vstream_close(evdog->server); + if (evdog->client) { + if (!evdog->thread_mode) + acl_event_disable_read(evdog->eventp, evdog->client); + acl_vstream_close(evdog->client); + } + + evdog->sstream = NULL; + evdog->server = NULL; + evdog->client = NULL; +} + +static void read_fn(int event_type acl_unused, void *context) +{ + EVENT_DOG *evdog = (EVENT_DOG*) context; + char buf[2]; + + evdog->client->rw_timeout = 1; + if (acl_vstream_readn(evdog->client, buf, 1) == ACL_VSTREAM_EOF) { + acl_event_disable_read(evdog->eventp, evdog->client); + event_dog_reopen(evdog); + } else + acl_event_enable_read(evdog->eventp, evdog->client, 0, read_fn, evdog); +} + +static void event_dog_open(EVENT_DOG *evdog) +{ + const char *myname = "event_dog_open"; + const char *addr = "127.0.0.1:0"; + char buf[32]; + + buf[0] = 'x'; + buf[1] = 0; + + evdog->sstream = acl_vstream_listen(addr, 32); + if (evdog->sstream == NULL) + acl_msg_fatal("%s(%d): listen on addr(%s) error(%s)", + myname, __LINE__, addr, acl_last_serror()); + + evdog->server = acl_vstream_connect(evdog->sstream->local_addr, + ACL_BLOCKING, 0, 0, 1024); + if (evdog->server == NULL) + acl_msg_fatal("%s(%d): connect to addr(%s) error(%s)", + myname, __LINE__, addr, acl_last_serror()); + + if (acl_vstream_writen(evdog->server, buf, 1) == ACL_VSTREAM_EOF) + acl_msg_fatal("%s(%d): pre write error(%s)", + myname, __LINE__, acl_last_serror()); + + evdog->client = acl_vstream_accept(evdog->sstream, buf, sizeof(buf)); + if (evdog->client == NULL) + acl_msg_fatal("%s(%d): accept error(%s)", + myname, __LINE__, acl_last_serror()); + + if (acl_vstream_readn(evdog->client, buf, 1) == ACL_VSTREAM_EOF) + acl_msg_fatal("%s(%d): pre read error(%s)", + myname, __LINE__, acl_last_serror()); + + acl_vstream_close(evdog->sstream); + evdog->sstream = NULL; + + acl_event_enable_read(evdog->eventp, evdog->client, 0, read_fn, evdog); +} + +static void event_dog_reopen(EVENT_DOG *evdog) +{ + event_dog_close(evdog); + event_dog_open(evdog); +} + +EVENT_DOG *event_dog_create(ACL_EVENT *eventp, int thread_mode) +{ + const char *myname = "event_dog_create"; + EVENT_DOG *evdog; + + evdog = (EVENT_DOG*) acl_mycalloc(1, sizeof(EVENT_DOG)); + if (evdog == NULL) + acl_msg_fatal("%s(%d): calloc error", myname, __LINE__); + + evdog->eventp = eventp; + evdog->thread_mode = thread_mode; + + event_dog_open(evdog); + return (evdog); +} + +ACL_VSTREAM *event_dog_client(EVENT_DOG *evdog) +{ + if (evdog && evdog->client) + return (evdog->client); + return (NULL); +} + +void event_dog_notify(EVENT_DOG *evdog) +{ + const char *myname = "event_dog_notify"; + char buf[2]; + + buf[0] = '0'; + buf[1] = 0; + + if (acl_vstream_writen(evdog->server, buf, 1) == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): notify error, reset", myname, __LINE__); + event_dog_reopen(evdog); + } +} + +void event_dog_free(EVENT_DOG *evdog) +{ + event_dog_close(evdog); + acl_myfree(evdog); +} + diff --git a/lib_acl/src/event/events_dog.h b/lib_acl/src/event/events_dog.h new file mode 100644 index 000000000..832d6d291 --- /dev/null +++ b/lib_acl/src/event/events_dog.h @@ -0,0 +1,23 @@ +#ifndef __EVENTS_DOG_INCLUDE_H__ +#define __EVENTS_DOG_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_define.h" +#include "event/acl_events.h" + +typedef struct EVENT_DOG EVENT_DOG; + +EVENT_DOG *event_dog_create(ACL_EVENT *eventp, int thread_mode); +void event_dog_notify(EVENT_DOG *evdog); +void event_dog_wait(EVENT_DOG *evdog); +ACL_VSTREAM *event_dog_client(EVENT_DOG *evdog); +void event_dog_free(EVENT_DOG *evdog); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/src/event/events_epoll.h b/lib_acl/src/event/events_epoll.h new file mode 100644 index 000000000..e526de989 --- /dev/null +++ b/lib_acl/src/event/events_epoll.h @@ -0,0 +1,111 @@ +#ifndef __EVENTS_EPOLL_INCLUDE_H__ +#define __EVENTS_EPOLL_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "events_define.h" + + /* + * Linux epoll supports no system call to find out what descriptors are + * registered in the kernel-based filter. To implement our own sanity checks + * we maintain our own descriptor bitmask. + * + * Linux epoll does support application context pointers. Unfortunately, + * changing that information would cost a system call, and some of the + * competitors don't support application context. To keep the implementation + * simple we maintain our own table with call-back information. + * + * Linux epoll silently unregisters a descriptor from its filter when the + * descriptor is closed, so our information could get out of sync with the + * kernel. But that will never happen, because we have to meticulously + * unregister a file descriptor before it is closed, to avoid errors on + */ +#if (ACL_EVENTS_KERNEL_STYLE == ACL_EVENTS_STYLE_EPOLL) +#include +#include + +#define EVENT_NAME "epoll" + +/* + * Macros to initalize the kernel-based filter; see acl_event_init() + */ + +#define EVENT_REG_INIT_HANDLE(eh, n) do { \ + eh = epoll_create(n); \ +} while (0) +#define EVENT_REG_INIT_TEXT "epoll_create" + +/* + * Macros to update the kernel-based filter; see acl_event_enable_read(), + * acl_event_enable_write(), acl_event_disable_read(), + * acl_event_disable_write(), acl_event_disable_readwrite(). + */ +#include + +/* + dummy.events = (ev) | EPOLLET; +*/ +#define EVENT_REG_FD_OP(er, eh, fh, ctx, ev, op) do { \ + struct epoll_event dummy; \ + memset(&dummy, 0, sizeof(dummy)); \ + dummy.events = (ev) | EPOLLHUP | EPOLLERR; \ + dummy.data.ptr = ctx; \ + (er) = epoll_ctl(eh, (op), (fh), &dummy); \ +} while (0) + +#define EVENT_REG_ADD_OP(er, eh, fh, ctx, ev) \ + EVENT_REG_FD_OP((er), (eh), (fh), (ctx), (ev), EPOLL_CTL_ADD) +#define EVENT_REG_ADD_READ(er, eh, fh, ctx) \ + EVENT_REG_ADD_OP((er), (eh), (fh), (ctx), EPOLLIN) +#define EVENT_REG_ADD_WRITE(er, eh, fh, ctx) \ + EVENT_REG_ADD_OP((er), (eh), (fh), (ctx), EPOLLOUT) +#define EVENT_REG_ADD_RDWR(er, eh, fh, ctx) \ + EVENT_REG_ADD_OP((er), (eh), (fh), (ctx), EPOLLIN | EPOLLOUT) +#define EVENT_REG_ADD_TEXT "epoll_ctl EPOLL_CTL_ADD" + +#define EVENT_REG_MOD_OP(er, eh, fh, ctx, ev) \ + EVENT_REG_FD_OP((er), (eh), (fh), (ctx), (ev), EPOLL_CTL_MOD) +#define EVENT_REG_MOD_READ(er, eh, fh, ctx) \ + EVENT_REG_MOD_OP((er), (eh), (fh), (ctx), EPOLLIN) +#define EVENT_REG_MOD_WRITE(er, eh, fh, ctx) \ + EVENT_REG_MOD_OP((er), (eh), (fh), (ctx), EPOLLOUT) +#define EVENT_REG_MOD_RDWR(er, eh, fh, ctx) \ + EVENT_REG_MOD_OP((er), (eh), (fh), (ctx), EPOLLIN | EPOLLOUT) +#define EVENT_REG_MOD_TEXT "epoll_ctl EPOLL_CTL_MOD" + +#define EVENT_REG_DEL_OP(er, eh, fh, ev) \ + EVENT_REG_FD_OP((er), (eh), (fh), NULL, (ev), EPOLL_CTL_DEL) +#define EVENT_REG_DEL_BOTH(er, eh, fh) \ + EVENT_REG_DEL_OP((er), (eh), (fh), 0) +#define EVENT_REG_DEL_TEXT "epoll_ctl EPOLL_CTL_DEL" + +/* + * Macros to retrieve event buffers from the kernel; see acl_event_loop(). + */ +typedef struct epoll_event EVENT_BUFFER; + +#define EVENT_BUFFER_READ(ev_cnt, eh, ev_buf, buflen, delay) do { \ + (ev_cnt) = epoll_wait(eh, (ev_buf), (buflen), \ + (delay) < 0 ? -1 : (delay)); \ +} while (0) +#define EVENT_BUFFER_READ_TEXT "epoll_wait" + +/* + * Macros to process event buffers from the kernel; see acl_event_loop(). + */ +#define EVENT_GET_CTX(bp) ((bp)->data.ptr) +#define EVENT_GET_TYPE(bp) ((bp)->events) +#define EVENT_TEST_READ(bp) (EVENT_GET_TYPE(bp) & EPOLLIN) +#define EVENT_TEST_WRITE(bp) (EVENT_GET_TYPE(bp) & EPOLLOUT) +#define EVENT_TEST_ERROR(bp) (EVENT_GET_TYPE(bp) & (EPOLLERR | EPOLLHUP)) + +#endif /* (ACL_EVENTS_KERNEL_STYLE == ACL_EVENTS_STYLE_EPOLL) */ + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/src/event/events_fdtable.c b/lib_acl/src/event/events_fdtable.c new file mode 100644 index 000000000..b0722dfd7 --- /dev/null +++ b/lib_acl/src/event/events_fdtable.c @@ -0,0 +1,39 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_ring.h" +#include "stdlib/acl_msg.h" +#include "event/acl_events.h" + +#endif + +#include "events.h" +#include "events_fdtable.h" + +ACL_EVENT_FDTABLE *event_fdtable_alloc() +{ + ACL_EVENT_FDTABLE *fdp = acl_mycalloc(1, sizeof(ACL_EVENT_FDTABLE)); + fdp->fdidx = -1; + fdp->fdidx_ready = -1; + return (fdp); +} + +void event_fdtable_free(ACL_EVENT_FDTABLE *fdp) +{ + acl_myfree(fdp); +} + +void event_fdtable_reset(ACL_EVENT_FDTABLE *fdp) +{ + memset(fdp, 0, sizeof(ACL_EVENT_FDTABLE)); + fdp->fdidx = -1; + fdp->fdidx_ready = -1; +} diff --git a/lib_acl/src/event/events_fdtable.h b/lib_acl/src/event/events_fdtable.h new file mode 100644 index 000000000..6ab17b8ba --- /dev/null +++ b/lib_acl/src/event/events_fdtable.h @@ -0,0 +1,19 @@ +#ifndef __EVENTS_FDTABLE_INCLUDE_H__ +#define __EVENTS_FDTABLE_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "event/acl_events.h" + +extern ACL_EVENT_FDTABLE *event_fdtable_alloc(void); +extern void event_fdtable_free(ACL_EVENT_FDTABLE *fdp); +extern void event_fdtable_reset(ACL_EVENT_FDTABLE *fdp); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/src/event/events_iocp.c b/lib_acl/src/event/events_iocp.c new file mode 100644 index 000000000..d88fcfd7f --- /dev/null +++ b/lib_acl/src/event/events_iocp.c @@ -0,0 +1,861 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include +#include +#include +#include + +#include "stdlib/acl_sys_patch.h" +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_msg.h" +#include "stdlib/acl_vstream.h" +#include "stdlib/acl_fifo.h" +#include "stdlib/acl_mystring.h" +#include "event/acl_events.h" + +#endif /* ACL_PREPARE_COMPILE */ + +#include "events_define.h" + +#ifdef ACL_EVENTS_STYLE_IOCP + +#include "events_fdtable.h" +#include "events.h" +#include "events_iocp.h" + +typedef BOOL (PASCAL FAR* LPFN_CONNECTEX) ( + IN SOCKET s, + IN const struct sockaddr FAR *name, + IN int namelen, + IN PVOID lpSendBuffer OPTIONAL, + IN DWORD dwSendDataLength, + OUT LPDWORD lpdwBytesSent, + IN LPOVERLAPPED lpOverlapped +); + +typedef struct EVENT_KERNEL { + ACL_EVENT event; + ACL_RING fdp_delay_list; + int event_fdslots; + int event_fd; + acl_int64 last_check; + HANDLE h_iocp; +} EVENT_KERNEL; + +struct IOCP_EVENT { + OVERLAPPED overlapped; + int type; +#define IOCP_EVENT_READ (1 << 0) +#define IOCP_EVENT_WRITE (1 << 2) + ACL_EVENT_FDTABLE *fdp; + +#define ACCEPT_ADDRESS_LENGTH ((sizeof(struct sockaddr_in) + 16)) + char myAddrBlock[ACCEPT_ADDRESS_LENGTH * 2]; +}; + +static void stream_on_close(ACL_VSTREAM *stream, void *arg) +{ + const char *myname = "stream_on_close"; + EVENT_KERNEL *ev = (EVENT_KERNEL*) arg; + ACL_EVENT_FDTABLE *fdp = (ACL_EVENT_FDTABLE*) stream->fdp; + ACL_SOCKET sockfd = ACL_VSTREAM_SOCK(stream); + + if (fdp == NULL) + acl_msg_fatal("%s(%d): fdp null, sockfd(%d)", + myname, __LINE__, sockfd); + + if (fdp->h_iocp != NULL) { + fdp->h_iocp = NULL; + fdp->flag &= ~EVENT_FDTABLE_FLAG_IOCP; + } + + /* 必须在释放 fdp->event_read/fdp->event_write 前关闭套接口句柄 */ + + if (ACL_VSTREAM_SOCK(stream) != ACL_SOCKET_INVALID && stream->close_fn) + (void) stream->close_fn(ACL_VSTREAM_SOCK(stream)); + else if (ACL_VSTREAM_FILE(stream) != ACL_FILE_INVALID && stream->fclose_fn) + (void) stream->fclose_fn(ACL_VSTREAM_FILE(stream)); + ACL_VSTREAM_SOCK(stream) = ACL_SOCKET_INVALID; + ACL_VSTREAM_FILE(stream) = ACL_FILE_INVALID; + + if (fdp->event_read) { + acl_myfree(fdp->event_read); + fdp->event_read = NULL; + } + if (fdp->event_write) { + acl_myfree(fdp->event_write); + fdp->event_write = NULL; + } + + if ((fdp->flag & EVENT_FDTABLE_FLAG_DELAY_OPER)) { + fdp->flag &= ~EVENT_FDTABLE_FLAG_DELAY_OPER; + acl_ring_detach(&fdp->delay_entry); + } + + if (ev->event.maxfd == ACL_VSTREAM_SOCK(fdp->stream)) + ev->event.maxfd = ACL_SOCKET_INVALID; + if (fdp->fdidx >= 0 && fdp->fdidx < --ev->event.fdcnt) { + ev->event.fdtabs[fdp->fdidx] = ev->event.fdtabs[ev->event.fdcnt]; + ev->event.fdtabs[fdp->fdidx]->fdidx = fdp->fdidx; + } + fdp->fdidx = -1; + + if (fdp->fdidx_ready >= 0 + && fdp->fdidx_ready < ev->event.fdcnt_ready + && ev->event.fdtabs_ready[fdp->fdidx_ready] == fdp) + { + ev->event.fdtabs_ready[fdp->fdidx_ready] = NULL; + } + fdp->fdidx_ready = -1; + event_fdtable_free(fdp); + stream->fdp = NULL; +} + +static void event_enable_read(ACL_EVENT *eventp, ACL_VSTREAM *stream, + int timeout, ACL_EVENT_NOTIFY_RDWR callback, void *context) +{ + const char *myname = "event_enable_read"; + EVENT_KERNEL *ev = (EVENT_KERNEL *) eventp; + ACL_EVENT_FDTABLE *fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + ACL_SOCKET sockfd = ACL_VSTREAM_SOCK(stream); + + if (fdp == NULL) { + fdp = event_fdtable_alloc(); + + fdp->flag = EVENT_FDTABLE_FLAG_ADD_READ | EVENT_FDTABLE_FLAG_EXPT; + fdp->stream = stream; + acl_ring_append(&ev->fdp_delay_list, &fdp->delay_entry); + fdp->flag |= EVENT_FDTABLE_FLAG_DELAY_OPER; + stream->fdp = (void *) fdp; + /* 添加流关闭时的回调函数 */ + acl_vstream_add_close_handle(stream, stream_on_close, eventp); + } else if ((fdp->flag & EVENT_FDTABLE_FLAG_ADD_READ)) { + goto END; + } else if ((fdp->flag & EVENT_FDTABLE_FLAG_DEL_READ)) { + + /* 停止禁止读监听过程 */ + + acl_assert((fdp->flag & EVENT_FDTABLE_FLAG_READ)); + + /* 重新启用读监听过程, 因为之前的过程是正在拆除读监听过程但 + * 还没有正式拆除,所以只需要清除拆除标志位即可 + */ + + fdp->flag &= ~EVENT_FDTABLE_FLAG_DEL_READ; + } else if (!(fdp->flag & EVENT_FDTABLE_FLAG_READ)) { + fdp->flag |= EVENT_FDTABLE_FLAG_ADD_READ; + if (!(fdp->flag & EVENT_FDTABLE_FLAG_DELAY_OPER)) { + acl_ring_append(&ev->fdp_delay_list, &fdp->delay_entry); + fdp->flag |= EVENT_FDTABLE_FLAG_DELAY_OPER; + } + } + +END: + if (fdp->fdidx == -1) { + fdp->fdidx = eventp->fdcnt; + eventp->fdtabs[eventp->fdcnt++] = fdp; + } + if (eventp->maxfd != ACL_SOCKET_INVALID && eventp->maxfd < sockfd) + eventp->maxfd = sockfd; + + if (fdp->r_callback != callback || fdp->r_context != context) { + fdp->r_callback = callback; + fdp->r_context = context; + } + + if (timeout > 0) { + fdp->r_timeout = timeout * 1000000; + fdp->r_ttl = eventp->event_present + fdp->r_timeout; + } else { + fdp->r_ttl = 0; + fdp->r_timeout = 0; + } +} + +static void event_enable_write(ACL_EVENT *eventp, ACL_VSTREAM *stream, + int timeout, ACL_EVENT_NOTIFY_RDWR callback, void *context) +{ + EVENT_KERNEL *ev = (EVENT_KERNEL *) eventp; + ACL_EVENT_FDTABLE *fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + ACL_SOCKET sockfd = ACL_VSTREAM_SOCK(stream); + + if (fdp == NULL) { + fdp = event_fdtable_alloc(); + + fdp->flag = EVENT_FDTABLE_FLAG_ADD_WRITE | EVENT_FDTABLE_FLAG_EXPT; + fdp->stream = stream; + acl_ring_append(&ev->fdp_delay_list, &fdp->delay_entry); + fdp->flag |= EVENT_FDTABLE_FLAG_DELAY_OPER; + stream->fdp = (void *) fdp; + /* 添加流关闭时的回调函数 */ + acl_vstream_add_close_handle(stream, stream_on_close, eventp); + } else if ((fdp->flag & EVENT_FDTABLE_FLAG_ADD_WRITE)) { + goto END; + } else if ((fdp->flag & EVENT_FDTABLE_FLAG_DEL_WRITE)) { + + acl_assert((fdp->flag & EVENT_FDTABLE_FLAG_WRITE)); + + fdp->flag &= ~EVENT_FDTABLE_FLAG_DEL_WRITE; + } else if (!(fdp->flag & EVENT_FDTABLE_FLAG_WRITE)) { + fdp->flag |= EVENT_FDTABLE_FLAG_ADD_WRITE; + if (!(fdp->flag & EVENT_FDTABLE_FLAG_DELAY_OPER)) { + acl_ring_append(&ev->fdp_delay_list, &fdp->delay_entry); + fdp->flag |= EVENT_FDTABLE_FLAG_DELAY_OPER; + } + } + +END: + if (fdp->fdidx == -1) { + fdp->fdidx = eventp->fdcnt; + eventp->fdtabs[eventp->fdcnt++] = fdp; + } + + if (eventp->maxfd != ACL_SOCKET_INVALID && eventp->maxfd < sockfd) + eventp->maxfd = sockfd; + + if (fdp->w_callback != callback || fdp->w_context != context) { + fdp->w_callback = callback; + fdp->w_context = context; + } + + if (timeout > 0) { + fdp->w_timeout = timeout * 1000000; + fdp->w_ttl = eventp->event_present + fdp->w_timeout; + } else { + fdp->w_ttl = 0; + fdp->w_timeout = 0; + } +} + +/* event_disable_read - disable request for read events */ + +static void event_disable_read(ACL_EVENT *eventp, ACL_VSTREAM *stream) +{ + const char *myname = "event_disable_read"; + EVENT_KERNEL *ev = (EVENT_KERNEL *) eventp; + ACL_EVENT_FDTABLE *fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + + if (fdp == NULL) { + acl_msg_warn("%s(%d): fdp null", myname, __LINE__); + return; + } + if (fdp->fdidx < 0 || fdp->fdidx >= eventp->fdcnt) { + acl_msg_warn("%s(%d): sockfd(%d)'s fdidx(%d) invalid, fdcnt: %d", + myname, __LINE__, ACL_VSTREAM_SOCK(stream), + fdp->fdidx, eventp->fdcnt); + return; + } + if ((fdp->flag & EVENT_FDTABLE_FLAG_DEL_READ)) { + return; + } + if ((fdp->flag & EVENT_FDTABLE_FLAG_ADD_READ)) { + fdp->flag &= ~EVENT_FDTABLE_FLAG_ADD_READ; + goto DEL_READ_TAG; + } + + if (!(fdp->flag & EVENT_FDTABLE_FLAG_READ)) { + acl_msg_warn("%s(%d): sockfd(%d) not be set", + myname, __LINE__, ACL_VSTREAM_SOCK(stream)); + return; + } + fdp->flag |= EVENT_FDTABLE_FLAG_DEL_READ; + if (!(fdp->flag & EVENT_FDTABLE_FLAG_DELAY_OPER)) { + acl_ring_append(&ev->fdp_delay_list, &fdp->delay_entry); + fdp->flag |= EVENT_FDTABLE_FLAG_DELAY_OPER; + } + +DEL_READ_TAG: + + fdp->r_ttl = 0; + fdp->r_timeout = 0; + fdp->r_callback = NULL; + fdp->event_type &= ~ACL_EVENT_READ; + + if ((fdp->flag & EVENT_FDTABLE_FLAG_WRITE) + || (fdp->flag & EVENT_FDTABLE_FLAG_ADD_WRITE)) + { + return; + } + + if (eventp->maxfd == ACL_VSTREAM_SOCK(fdp->stream)) + eventp->maxfd = ACL_SOCKET_INVALID; + + if (fdp->fdidx < --eventp->fdcnt) { + eventp->fdtabs[fdp->fdidx] = eventp->fdtabs[eventp->fdcnt]; + eventp->fdtabs[fdp->fdidx]->fdidx = fdp->fdidx; + } + fdp->fdidx = -1; + + if (fdp->fdidx_ready >= 0 + && fdp->fdidx_ready < eventp->fdcnt_ready + && eventp->fdtabs_ready[fdp->fdidx_ready] == fdp) + { + eventp->fdtabs_ready[fdp->fdidx_ready] = NULL; + } + fdp->fdidx_ready = -1; +} + +/* event_disable_write - disable request for write events */ + +static void event_disable_write(ACL_EVENT *eventp, ACL_VSTREAM *stream) +{ + const char *myname = "event_disable_write"; + EVENT_KERNEL *ev = (EVENT_KERNEL *) eventp; + ACL_EVENT_FDTABLE *fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + + if (fdp == NULL) { + acl_msg_warn("%s(%d): fdp null", myname, __LINE__); + return; + } + if (fdp->fdidx < 0 || fdp->fdidx >= eventp->fdcnt) { + acl_msg_warn("%s(%d): sockfd(%d)'s fdidx(%d) invalid", + myname, __LINE__, ACL_VSTREAM_SOCK(stream), fdp->fdidx); + return; + } + if ((fdp->flag & EVENT_FDTABLE_FLAG_DEL_WRITE)) { + return; + } + if ((fdp->flag & EVENT_FDTABLE_FLAG_ADD_WRITE)) { + fdp->flag &= ~EVENT_FDTABLE_FLAG_ADD_WRITE; + goto DEL_WRITE_TAG; + } + if (!(fdp->flag & EVENT_FDTABLE_FLAG_WRITE)) { + acl_msg_warn("%s(%d): sockfd(%d) not be set", + myname, __LINE__, ACL_VSTREAM_SOCK(stream)); + return; + } + + fdp->flag |= EVENT_FDTABLE_FLAG_DEL_WRITE; + if (!(fdp->flag & EVENT_FDTABLE_FLAG_DELAY_OPER)) { + acl_ring_append(&ev->fdp_delay_list, &fdp->delay_entry); + fdp->flag |= EVENT_FDTABLE_FLAG_DELAY_OPER; + } + +DEL_WRITE_TAG: + + fdp->w_ttl = 0; + fdp->w_timeout = 0; + fdp->w_callback = NULL; + fdp->event_type &= ~ACL_EVENT_WRITE; + + if ((fdp->flag & EVENT_FDTABLE_FLAG_READ) + || (fdp->flag & EVENT_FDTABLE_FLAG_ADD_READ)) + { + return; + } + + if (eventp->maxfd == ACL_VSTREAM_SOCK(stream)) + eventp->maxfd = ACL_SOCKET_INVALID; + + if (fdp->fdidx < --eventp->fdcnt) { + eventp->fdtabs[fdp->fdidx] = eventp->fdtabs[eventp->fdcnt]; + eventp->fdtabs[fdp->fdidx]->fdidx = fdp->fdidx; + } + fdp->fdidx = -1; + + if (fdp->fdidx_ready >= 0 + && fdp->fdidx_ready < eventp->fdcnt_ready + && eventp->fdtabs_ready[fdp->fdidx_ready] == fdp) + { + eventp->fdtabs_ready[fdp->fdidx_ready] = NULL; + } + fdp->fdidx_ready = -1; +} + +/* event_disable_readwrite - disable request for read or write events */ + +static void event_disable_readwrite(ACL_EVENT *eventp, ACL_VSTREAM *stream) +{ + event_disable_read(eventp, stream); + event_disable_write(eventp, stream); +} + +static void enable_listen(EVENT_KERNEL *ev, ACL_EVENT_FDTABLE *fdp) +{ + const char *myname = "enable_listen"; + ACL_SOCKET sock; + DWORD ReceiveLen = 0; + + sock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, + 0, 0, WSA_FLAG_OVERLAPPED); + + memset(&fdp->event_read->overlapped, 0, + sizeof(fdp->event_read->overlapped)); + + fdp->stream->type |= ACL_VSTREAM_TYPE_LISTEN_IOCP; + fdp->stream->iocp_sock = sock; + + if (AcceptEx(ACL_VSTREAM_SOCK(fdp->stream), sock, + fdp->event_read->myAddrBlock, 0, + ACCEPT_ADDRESS_LENGTH, ACCEPT_ADDRESS_LENGTH, + &ReceiveLen, &fdp->event_read->overlapped) == FALSE + && acl_last_error() !=ERROR_IO_PENDING) + { + acl_msg_warn("%s(%d): AcceptEx error(%s)", + myname, __LINE__, acl_last_serror()); + } +} + +static void enable_read(EVENT_KERNEL *ev, ACL_EVENT_FDTABLE *fdp) +{ + const char *myname = "enable_read"; + ACL_SOCKET sockfd = ACL_VSTREAM_SOCK(fdp->stream); + DWORD recvBytes; + + fdp->flag &= ~EVENT_FDTABLE_FLAG_ADD_READ; + fdp->flag |= EVENT_FDTABLE_FLAG_READ; + + if (fdp->h_iocp == NULL) { + fdp->h_iocp = CreateIoCompletionPort((HANDLE) sockfd, + ev->h_iocp, (DWORD) fdp, 0); + if (fdp->h_iocp != ev->h_iocp) + acl_msg_fatal("%s(%d): CreateIoCompletionPort error(%s)", + myname, __LINE__, acl_last_serror()); + fdp->flag |= EVENT_FDTABLE_FLAG_IOCP; + } + + if (fdp->event_read == NULL) { + fdp->event_read = (IOCP_EVENT*) acl_mymalloc(sizeof(IOCP_EVENT)); + fdp->event_read->fdp = fdp; + } else if (fdp->event_read->type == IOCP_EVENT_READ) { + return; + } + + fdp->event_read->type = IOCP_EVENT_READ; + + if ((fdp->stream->type & ACL_VSTREAM_TYPE_LISTEN)) { + enable_listen(ev, fdp); + return; + } + + memset(&fdp->event_read->overlapped, 0, + sizeof(fdp->event_read->overlapped)); + + if (ReadFile((HANDLE) sockfd, NULL, 0, + &recvBytes, &fdp->event_read->overlapped) == FALSE + && acl_last_error() != ERROR_IO_PENDING) + { + acl_msg_warn("%s(%d): ReadFile error(%s)", + myname, __LINE__, acl_last_serror()); + } +} + +static void parse_addr(char *addr, unsigned short *port, + char **local_ip, char **remote_addr) +{ + const char *myname = "parse_addr"; + char *ptr; + + ptr = strchr(addr, ':'); + if (ptr == NULL) { + acl_msg_fatal("%s, %s(%d): invalid addr(%s)", + __FILE__, myname, __LINE__, addr); + } + + *ptr++ = 0; + *port = atoi(ptr); + if (*port <= 0) { + acl_msg_fatal("%s, %s(%d): invalid port(%d)", + __FILE__, myname, __LINE__, *port); + } + + ptr = strchr(addr, '@'); + if (ptr != NULL) { + *ptr++ = 0; + *local_ip = addr; + *remote_addr = ptr; + } else { + *local_ip = NULL; + *remote_addr = addr; + } + + if (strlen(*remote_addr) == 0) { + acl_msg_fatal("%s, %s(%d): ip buf's length is 0", + __FILE__, myname, __LINE__); + } +} + +static void enable_connect(EVENT_KERNEL *ev, ACL_EVENT_FDTABLE *fdp) +{ + const char *myname = "enable_connect"; + DWORD SentLen = 0; + struct sockaddr_in addr; + unsigned short port; + char *local_ip, *remote_addr, buf[256]; + ACL_SOCKET sock = ACL_VSTREAM_SOCK(fdp->stream); + LPFN_CONNECTEX lpfnConnectEx = NULL; + GUID GuidConnectEx = WSAID_CONNECTEX; + int dwErr, dwBytes; + static char *any_ip = "0.0.0.0"; + + memset(&fdp->event_write->overlapped, 0, + sizeof(fdp->event_write->overlapped)); + + ACL_SAFE_STRNCPY(buf, fdp->stream->remote_addr, sizeof(buf)); + parse_addr(buf, &port, &local_ip, &remote_addr); + + if (!local_ip || !*local_ip) { + local_ip = any_ip; + } + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = inet_addr(local_ip); + addr.sin_port = htons(0); + if (bind(sock, (struct sockaddr *) &addr, sizeof(struct sockaddr)) < 0) { + acl_msg_fatal("%s(%d): bind local ip(%s) error(%s, %d), sock: %d", + myname, __LINE__, local_ip, acl_last_serror(), + acl_last_error(), (int) sock); + } + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons((short) port); + addr.sin_addr.s_addr = inet_addr(remote_addr); + + dwErr = WSAIoctl(sock, + SIO_GET_EXTENSION_FUNCTION_POINTER, + &GuidConnectEx, + sizeof(GuidConnectEx), + &lpfnConnectEx, + sizeof(lpfnConnectEx), + &dwBytes, + NULL, + NULL); + if(dwErr == SOCKET_ERROR) + acl_msg_fatal("%s(%d): WSAIoctl error(%s)", + myname, __LINE__, acl_last_serror()); + + if (lpfnConnectEx(sock, + (const struct sockaddr *) &addr, + sizeof(struct sockaddr), + NULL, + 0, + NULL, + &fdp->event_write->overlapped) == FALSE + && acl_last_error() !=ERROR_IO_PENDING) + { + acl_msg_warn("%s(%d): ConnectEx error(%s), sock(%d)", + myname, __LINE__, acl_last_serror(), sock); + } +} + +static void enable_write(EVENT_KERNEL *ev, ACL_EVENT_FDTABLE *fdp) +{ + const char *myname = "enable_write"; + ACL_SOCKET sockfd = ACL_VSTREAM_SOCK(fdp->stream); + DWORD sendBytes; + + fdp->flag &= ~EVENT_FDTABLE_FLAG_ADD_WRITE; + fdp->flag |= EVENT_FDTABLE_FLAG_WRITE; + + if (fdp->h_iocp == NULL) { + fdp->h_iocp = CreateIoCompletionPort((HANDLE) sockfd, + ev->h_iocp, (DWORD) fdp, 0); + if (fdp->h_iocp != ev->h_iocp) + acl_msg_fatal("%s(%d): CreateIoCompletionPort error(%s)", + myname, __LINE__, acl_last_serror()); + fdp->flag |= EVENT_FDTABLE_FLAG_IOCP; + } + + if (fdp->event_write == NULL) { + fdp->event_write = (IOCP_EVENT*) acl_mymalloc(sizeof(IOCP_EVENT)); + fdp->event_write->fdp = fdp; + } else if (fdp->event_write->type == IOCP_EVENT_WRITE) { + return; + } + + fdp->event_write->type = IOCP_EVENT_WRITE; + + if ((fdp->stream->flag & ACL_VSTREAM_FLAG_CONNECTING)) { + enable_connect(ev, fdp); + fdp->stream->flag &= ~ACL_VSTREAM_FLAG_CONNECTING; + return; + } + + memset(&fdp->event_write->overlapped, 0, + sizeof(fdp->event_write->overlapped)); + + if (WriteFile((HANDLE) sockfd, NULL, 0, + &sendBytes, &fdp->event_write->overlapped) == FALSE + && acl_last_error() != ERROR_IO_PENDING) + { + acl_msg_warn("%s(%d): WriteFile error(%s), sockfd(%d)", + myname, __LINE__, acl_last_serror(), sockfd); + } +} + +static int disable_read(EVENT_KERNEL *ev, ACL_EVENT_FDTABLE *fdp) +{ + ACL_VSTREAM *stream = fdp->stream; + + fdp->flag &= ~EVENT_FDTABLE_FLAG_DEL_READ; + fdp->flag &= ~EVENT_FDTABLE_FLAG_READ; + fdp->event_type &= ~ACL_EVENT_READ; + return 1; +} + +static int disable_write(EVENT_KERNEL *ev, ACL_EVENT_FDTABLE *fdp) +{ + ACL_VSTREAM *stream = fdp->stream; + + fdp->flag &= ~EVENT_FDTABLE_FLAG_DEL_WRITE; + fdp->flag &= ~EVENT_FDTABLE_FLAG_WRITE; + fdp->event_type &= ~ACL_EVENT_WRITE; + return 1; +} + +static void event_set_all(ACL_EVENT *eventp) +{ + EVENT_KERNEL *ev = (EVENT_KERNEL *) eventp; + ACL_EVENT_FDTABLE *fdp; + int i; + + /* 优先处理添加读/写监控任务, 这样可以把中间的 ADD 状态转换成正式状态 */ + + eventp->fdcnt_ready = 0; + + if (eventp->event_present - ev->last_check >= 1000000) { + ev->last_check = eventp->event_present; + event_check_fds(eventp); + } + + /* 处理任务项 */ + + while (1) { + ACL_RING *r = acl_ring_pop_head(&ev->fdp_delay_list); + if (r == NULL) + break; + fdp = acl_ring_to_appl(r, ACL_EVENT_FDTABLE, delay_entry); + + if ((fdp->flag & EVENT_FDTABLE_FLAG_ADD_READ)) { + enable_read(ev, fdp); + } + if ((fdp->flag & EVENT_FDTABLE_FLAG_ADD_WRITE)) { + enable_write(ev, fdp); + } + if ((fdp->flag & EVENT_FDTABLE_FLAG_DEL_READ)) { + disable_read(ev, fdp); + } + if ((fdp->flag & EVENT_FDTABLE_FLAG_DEL_WRITE)) { + disable_write(ev, fdp); + } + + fdp->flag &= ~EVENT_FDTABLE_FLAG_DELAY_OPER; + } + + for (i = 0; i < eventp->fdcnt; i++) { + fdp = eventp->fdtabs[i]; + if ((fdp->event_type & (ACL_EVENT_XCPT | ACL_EVENT_RW_TIMEOUT))) + continue; + if ((fdp->flag & EVENT_FDTABLE_FLAG_READ) + && (fdp->event_read == NULL || fdp->event_read->type == 0)) + { + enable_read(ev, fdp); + } + if ((fdp->flag & EVENT_FDTABLE_FLAG_WRITE) + && (fdp->event_write == NULL || fdp->event_write->type == 0)) + { + enable_write(ev, fdp); + } + } +} + +static void event_loop(ACL_EVENT *eventp) +{ + const char *myname = "event_loop"; + EVENT_KERNEL *ev = (EVENT_KERNEL *) eventp; + ACL_EVENT_NOTIFY_FN worker_fn; + void *worker_arg; + ACL_EVENT_TIMER *timer; + int delay; + ACL_EVENT_FDTABLE *fdp; + + delay = (int) (eventp->delay_sec * 1000 + eventp->delay_usec / 1000); + if (delay < 0) + delay = 0; /* 0 milliseconds at least */ + + SET_TIME(eventp->event_present); + + /* + * Find out when the next timer would go off. Timer requests are sorted. + * If any timer is scheduled, adjust the delay appropriately. + */ + if ((timer = ACL_FIRST_TIMER(&eventp->timer_head)) != 0) { + acl_int64 n = (timer->when - eventp->event_present) / 1000; + + if (n <= 0) + delay = 0; + else if ((int) n < delay) + delay = (int) n; + } + + eventp->nested++; + + event_set_all(eventp); + + if (eventp->fdcnt == 0) { + if (eventp->fdcnt_ready == 0) + sleep(1); + goto TAG_DONE; + } + + if (eventp->fdcnt_ready > 0) + delay = 0; + +TAG_DONE: + + /* + * Deliver timer events. Requests are sorted: we can stop when we reach + * the future or the list end. Allow the application to update the timer + * queue while it is being called back. To this end, we repeatedly pop + * the first request off the timer queue before delivering the event to + * the application. + */ + SET_TIME(eventp->event_present); + while ((timer = ACL_FIRST_TIMER(&eventp->timer_head)) != 0) { + if (timer->when > eventp->event_present) + break; + worker_fn = timer->callback; + worker_arg = timer->context; + + /* 如果定时器的时间间隔 > 0 且允许定时器被循环调用,则再重设定时器 */ + if (timer->delay > 0 && timer->keep) { + timer->ncount++; + eventp->timer_request(eventp, timer->callback, + timer->context, timer->delay, timer->keep); + } else { + acl_ring_detach(&timer->ring); /* first this */ + timer->nrefer--; + if (timer->nrefer != 0) + acl_msg_fatal("%s(%d): nrefer(%d) != 0", + myname, __LINE__, timer->nrefer); + acl_myfree(timer); + } + worker_fn(ACL_EVENT_TIME, worker_arg); + } + + for (;;) { + BOOL isSuccess = FALSE; + DWORD bytesTransferred = 0; + DWORD iocpKey = 0; + DWORD lastError = 0; + IOCP_EVENT *iocp_event = NULL; + + isSuccess = GetQueuedCompletionStatus(ev->h_iocp, &bytesTransferred, + (DWORD*) &fdp, (OVERLAPPED**) &iocp_event, delay); + if (!isSuccess) { + if (iocp_event == NULL) + break; + if (!(fdp->event_type & (ACL_EVENT_XCPT | ACL_EVENT_RW_TIMEOUT))) { + fdp->event_type |= ACL_EVENT_XCPT; + fdp->fdidx_ready = eventp->fdcnt_ready; + eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp; + } + continue; + } + + acl_assert(fdp == iocp_event->fdp); + + if ((fdp->event_type & (ACL_EVENT_XCPT | ACL_EVENT_RW_TIMEOUT))) + continue; + if (iocp_event->type == IOCP_EVENT_READ) { + acl_assert(fdp->event_read == iocp_event); + iocp_event->type &= ~IOCP_EVENT_READ; + fdp->stream->sys_read_ready = 1; + if ((fdp->event_type & (ACL_EVENT_READ | ACL_EVENT_WRITE)) == 0) + { + fdp->event_type |= ACL_EVENT_READ; + fdp->fdidx_ready = eventp->fdcnt_ready; + eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp; + } + } + if (iocp_event->type == IOCP_EVENT_WRITE) { + acl_assert(fdp->event_write == iocp_event); + iocp_event->type &= ~IOCP_EVENT_WRITE; + if ((fdp->event_type & (ACL_EVENT_READ | ACL_EVENT_WRITE)) == 0) + { + fdp->event_type |= ACL_EVENT_WRITE; + fdp->fdidx_ready = eventp->fdcnt_ready; + eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp; + } + } + delay = 0; + } + + if (eventp->fdcnt_ready > 0) + event_fire(eventp); + eventp->nested--; +} + +static int event_isrset(ACL_EVENT *eventp acl_unused, ACL_VSTREAM *stream) +{ + ACL_EVENT_FDTABLE *fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + + return fdp == NULL ? 0 : (fdp->flag & EVENT_FDTABLE_FLAG_READ); +} + +static int event_iswset(ACL_EVENT *eventp acl_unused, ACL_VSTREAM *stream) +{ + ACL_EVENT_FDTABLE *fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + + return fdp == NULL ? 0 : (fdp->flag & EVENT_FDTABLE_FLAG_WRITE); + +} + +static int event_isxset(ACL_EVENT *eventp acl_unused, ACL_VSTREAM *stream) +{ + ACL_EVENT_FDTABLE *fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + + return fdp == NULL ? 0 : (fdp->flag & EVENT_FDTABLE_FLAG_EXPT); +} + +static void event_free(ACL_EVENT *eventp) +{ + EVENT_KERNEL *ev = (EVENT_KERNEL *) eventp; + + CloseHandle(ev->h_iocp); + acl_myfree(ev); +} + +ACL_EVENT *event_new_iocp(int fdsize acl_unused) +{ + const char *myname = "event_new_iocp"; + ACL_EVENT *eventp; + EVENT_KERNEL *ev; + + eventp = event_alloc(sizeof(EVENT_KERNEL)); + + snprintf(eventp->name, sizeof(eventp->name), "events - %s", EVENT_NAME); + eventp->event_mode = ACL_EVENT_KERNEL; + eventp->use_thread = 0; + eventp->loop_fn = event_loop; + eventp->free_fn = event_free; + eventp->enable_read_fn = event_enable_read; + eventp->enable_write_fn = event_enable_write; + eventp->enable_listen_fn = event_enable_read; + eventp->disable_read_fn = event_disable_read; + eventp->disable_write_fn = event_disable_write; + eventp->disable_readwrite_fn = event_disable_readwrite; + eventp->isrset_fn = event_isrset; + eventp->iswset_fn = event_iswset; + eventp->isxset_fn = event_isxset; + eventp->timer_request = event_timer_request; + eventp->timer_cancel = event_timer_cancel; + eventp->timer_keep = event_timer_keep; + eventp->timer_ifkeep = event_timer_ifkeep; + + ev = (EVENT_KERNEL*) eventp; + ev->h_iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0); + if (ev->h_iocp == NULL) + acl_msg_fatal("%s(%d): create iocp error(%s)", + myname, __LINE__, acl_last_serror()); + acl_ring_init(&ev->fdp_delay_list); + return eventp; +} + +#endif diff --git a/lib_acl/src/event/events_iocp.h b/lib_acl/src/event/events_iocp.h new file mode 100644 index 000000000..680002053 --- /dev/null +++ b/lib_acl/src/event/events_iocp.h @@ -0,0 +1,23 @@ +#ifndef __EVENTS_IOCP_INCLUDE_H__ +#define __EVENTS_IOCP_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "events_define.h" + +#ifdef ACL_EVENTS_STYLE_IOCP + +#define EVENT_NAME "iocp" +#define MAX_WAIT_OBJECTS 64 + +ACL_API ACL_EVENT *event_new_iocp(int fdsize); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/src/event/events_kernel.c b/lib_acl/src/event/events_kernel.c new file mode 100644 index 000000000..75e9c999a --- /dev/null +++ b/lib_acl/src/event/events_kernel.c @@ -0,0 +1,875 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include +#include +#include + +#if 0 +#define NDEBUG +#endif + +#include + +#ifdef ACL_UNIX +#include +#endif + +#include "stdlib/acl_sys_patch.h" +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_mystring.h" +#include "stdlib/acl_msg.h" +#include "stdlib/acl_debug.h" +#include "stdlib/acl_vstream.h" +#include "stdlib/acl_fifo.h" +#include "stdlib/acl_meter_time.h" /* just for performance test */ +#include "event/acl_events.h" + +#endif + +#include "events_define.h" + +#ifdef ACL_EVENTS_KERNEL_STYLE + +#include "events_epoll.h" +#include "events_devpoll.h" +#include "events_kqueue.h" +#include "events_fdtable.h" +#include "events.h" + +typedef struct EVENT_KERNEL { + ACL_EVENT event; + EVENT_BUFFER *event_buf; + ACL_RING fdp_delay_list; + int event_fdslots; + int event_fd; + time_t last_check; +#ifdef USE_FDMAP + ACL_FD_MAP *fdmap; +#endif +} EVENT_KERNEL; + +/** + * 对于 epoll/kqueue/devpoll 这些内核级操作,当描述符关闭时该描述符将 + * 会自动从内核监控中去除 + */ +#undef EVENT_AUTO_DEL + +#include "stdlib/acl_meter_time.h" + +static void stream_on_close(ACL_VSTREAM *stream, void *arg) +{ + const char *myname = "stream_on_close"; + EVENT_KERNEL *ev = (EVENT_KERNEL*) arg; + ACL_EVENT_FDTABLE *fdp = (ACL_EVENT_FDTABLE*) stream->fdp; + ACL_SOCKET sockfd = ACL_VSTREAM_SOCK(stream); + int err = 0, ret = 0; + + if (fdp == NULL) + acl_msg_fatal("%s(%d): fdp null, sockfd(%d)", + myname, __LINE__, sockfd); + +#ifdef EVENT_REG_DEL_BOTH + if ((fdp->flag & EVENT_FDTABLE_FLAG_READ) + || (fdp->flag & EVENT_FDTABLE_FLAG_WRITE)) + { +# ifndef EVENT_AUTO_DEL + EVENT_REG_DEL_BOTH(err, ev->event_fd, sockfd); + ret = 1; +# else + ret = 2; +# endif + } +#else + if ((fdp->flag & EVENT_FDTABLE_FLAG_READ) + && (fdp->flag & EVENT_FDTABLE_FLAG_WRITE)) + { +# ifndef EVENT_AUTO_DEL + EVENT_REG_DEL_READ(err, ev->event_fd, sockfd); + EVENT_REG_DEL_WRITE(err, ev->event_fd, sockfd); + ret = 3; +# else + ret = 4; +# endif + } else if ((fdp->flag & EVENT_FDTABLE_FLAG_READ)) { +# ifndef EVENT_AUTO_DEL + EVENT_REG_DEL_READ(err, ev->event_fd, sockfd); + ret = 5; +# else + ret = 6; +# endif + } else if ((fdp->flag & EVENT_FDTABLE_FLAG_WRITE)) { +# ifndef EVENT_AUTO_DEL + EVENT_REG_DEL_WRITE(err, ev->event_fd, sockfd); +# else + ret = 7; +# endif + ret = 8; + } +#endif + + if (err < 0) { + acl_msg_fatal("%s: %s: %s, err(%d), fd(%d), ret(%d)", + myname, EVENT_REG_DEL_TEXT, acl_last_serror(), + err, sockfd, ret); + } + + if ((fdp->flag & EVENT_FDTABLE_FLAG_DELAY_OPER)) { + fdp->flag &= ~EVENT_FDTABLE_FLAG_DELAY_OPER; + acl_ring_detach(&fdp->delay_entry); + } + + if (ret) { +#ifdef USE_FDMAP + acl_fdmap_del(ev->fdmap, sockfd); +#endif + } + + if (ev->event.maxfd == ACL_VSTREAM_SOCK(fdp->stream)) + ev->event.maxfd = ACL_SOCKET_INVALID; + if (fdp->fdidx >= 0 && fdp->fdidx < --ev->event.fdcnt) { + ev->event.fdtabs[fdp->fdidx] = ev->event.fdtabs[ev->event.fdcnt]; + ev->event.fdtabs[fdp->fdidx]->fdidx = fdp->fdidx; + } + fdp->fdidx = -1; + + if (fdp->fdidx_ready >= 0 + && fdp->fdidx_ready < ev->event.fdcnt_ready + && ev->event.fdtabs_ready[fdp->fdidx_ready] == fdp) + { + ev->event.fdtabs_ready[fdp->fdidx_ready] = NULL; + } + fdp->fdidx_ready = -1; + event_fdtable_free(fdp); + stream->fdp = NULL; +} + +static void event_enable_read(ACL_EVENT *eventp, ACL_VSTREAM *stream, + int timeout, ACL_EVENT_NOTIFY_RDWR callback, void *context) +{ + EVENT_KERNEL *ev = (EVENT_KERNEL *) eventp; + ACL_EVENT_FDTABLE *fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + ACL_SOCKET sockfd = ACL_VSTREAM_SOCK(stream); + + if (fdp == NULL) { + fdp = event_fdtable_alloc(); + + fdp->flag = EVENT_FDTABLE_FLAG_ADD_READ | EVENT_FDTABLE_FLAG_EXPT; + fdp->stream = stream; + acl_ring_append(&ev->fdp_delay_list, &fdp->delay_entry); + fdp->flag |= EVENT_FDTABLE_FLAG_DELAY_OPER; + stream->fdp = (void *) fdp; + /* 添加流关闭时的回调函数 */ + acl_vstream_add_close_handle(stream, stream_on_close, eventp); +#ifdef USE_FDMAP + acl_fdmap_add(ev->fdmap, sockfd, fdp); +#endif + } else if ((fdp->flag & EVENT_FDTABLE_FLAG_ADD_READ)) { + goto END; + } else if ((fdp->flag & EVENT_FDTABLE_FLAG_DEL_READ)) { + + /* 停止禁止读监听过程 */ + + acl_assert((fdp->flag & EVENT_FDTABLE_FLAG_READ)); + + /* 重新启用读监听过程, 因为之前的过程是正在拆除读监听过程但 + * 还没有正式拆除,所以只需要清除拆除标志位即可 + */ + + fdp->flag &= ~EVENT_FDTABLE_FLAG_DEL_READ; + } else if (!(fdp->flag & EVENT_FDTABLE_FLAG_READ)) { + fdp->flag |= EVENT_FDTABLE_FLAG_ADD_READ; + if (!(fdp->flag & EVENT_FDTABLE_FLAG_DELAY_OPER)) { + acl_ring_append(&ev->fdp_delay_list, &fdp->delay_entry); + fdp->flag |= EVENT_FDTABLE_FLAG_DELAY_OPER; + } + } + +END: + if (fdp->fdidx == -1) { + fdp->fdidx = eventp->fdcnt; + eventp->fdtabs[eventp->fdcnt++] = fdp; + } + if (eventp->maxfd != ACL_SOCKET_INVALID && eventp->maxfd < sockfd) + eventp->maxfd = sockfd; + + if (fdp->r_callback != callback || fdp->r_context != context) { + fdp->r_callback = callback; + fdp->r_context = context; + } + + if (timeout > 0) { + fdp->r_timeout = timeout * 1000000; + fdp->r_ttl = eventp->event_present + fdp->r_timeout; + } else { + fdp->r_ttl = 0; + fdp->r_timeout = 0; + } +} + +static void event_enable_write(ACL_EVENT *eventp, ACL_VSTREAM *stream, + int timeout, ACL_EVENT_NOTIFY_RDWR callback, void *context) +{ + EVENT_KERNEL *ev = (EVENT_KERNEL *) eventp; + ACL_EVENT_FDTABLE *fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + ACL_SOCKET sockfd = ACL_VSTREAM_SOCK(stream); + + if (fdp == NULL) { + fdp = event_fdtable_alloc(); + + fdp->flag = EVENT_FDTABLE_FLAG_ADD_WRITE | EVENT_FDTABLE_FLAG_EXPT; + fdp->stream = stream; + acl_ring_append(&ev->fdp_delay_list, &fdp->delay_entry); + fdp->flag |= EVENT_FDTABLE_FLAG_DELAY_OPER; + stream->fdp = (void *) fdp; + /* 添加流关闭时的回调函数 */ + acl_vstream_add_close_handle(stream, stream_on_close, eventp); +#ifdef USE_FDMAP + acl_fdmap_add(ev->fdmap, sockfd, fdp); +#endif + } else if ((fdp->flag & EVENT_FDTABLE_FLAG_ADD_WRITE)) { + goto END; + } else if ((fdp->flag & EVENT_FDTABLE_FLAG_DEL_WRITE)) { + acl_assert((fdp->flag & EVENT_FDTABLE_FLAG_WRITE)); + + fdp->flag &= ~EVENT_FDTABLE_FLAG_DEL_WRITE; + } else if (!(fdp->flag & EVENT_FDTABLE_FLAG_WRITE)) { + fdp->flag |= EVENT_FDTABLE_FLAG_ADD_WRITE; + if (!(fdp->flag & EVENT_FDTABLE_FLAG_DELAY_OPER)) { + acl_ring_append(&ev->fdp_delay_list, &fdp->delay_entry); + fdp->flag |= EVENT_FDTABLE_FLAG_DELAY_OPER; + } + } + +END: + if (fdp->fdidx == -1) { + fdp->fdidx = eventp->fdcnt; + eventp->fdtabs[eventp->fdcnt++] = fdp; + } + + if (eventp->maxfd != ACL_SOCKET_INVALID && eventp->maxfd < sockfd) + eventp->maxfd = sockfd; + + if (fdp->w_callback != callback || fdp->w_context != context) { + fdp->w_callback = callback; + fdp->w_context = context; + } + + if (timeout > 0) { + fdp->w_timeout = timeout * 1000000; + fdp->w_ttl = eventp->event_present + fdp->w_timeout; + } else { + fdp->w_ttl = 0; + fdp->w_timeout = 0; + } +} + +/* event_disable_read - disable request for read events */ + +static void event_disable_read(ACL_EVENT *eventp, ACL_VSTREAM *stream) +{ + const char *myname = "event_disable_read"; + EVENT_KERNEL *ev = (EVENT_KERNEL *) eventp; + ACL_EVENT_FDTABLE *fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + + if (fdp == NULL) { + acl_msg_warn("%s(%d): fdp null", myname, __LINE__); + return; + } + if (fdp->fdidx < 0 || fdp->fdidx >= eventp->fdcnt) { + acl_msg_warn("%s(%d): sockfd(%d)'s fdidx(%d) invalid, fdcnt: %d", + myname, __LINE__, ACL_VSTREAM_SOCK(stream), + fdp->fdidx, eventp->fdcnt); + return; + } + if ((fdp->flag & EVENT_FDTABLE_FLAG_DEL_READ)) { + return; + } + if ((fdp->flag & EVENT_FDTABLE_FLAG_ADD_READ)) { + fdp->flag &= ~EVENT_FDTABLE_FLAG_ADD_READ; + goto DEL_READ_TAG; + } + + if (!(fdp->flag & EVENT_FDTABLE_FLAG_READ)) { + acl_msg_warn("%s(%d): sockfd(%d) not be set", + myname, __LINE__, ACL_VSTREAM_SOCK(stream)); + return; + } + fdp->flag |= EVENT_FDTABLE_FLAG_DEL_READ; + if (!(fdp->flag & EVENT_FDTABLE_FLAG_DELAY_OPER)) { + acl_ring_append(&ev->fdp_delay_list, &fdp->delay_entry); + fdp->flag |= EVENT_FDTABLE_FLAG_DELAY_OPER; + } + +DEL_READ_TAG: + + fdp->r_ttl = 0; + fdp->r_timeout = 0; + fdp->r_callback = NULL; + fdp->event_type &= ~ACL_EVENT_READ; + + if ((fdp->flag & EVENT_FDTABLE_FLAG_WRITE) + || (fdp->flag & EVENT_FDTABLE_FLAG_ADD_WRITE)) + { + return; + } + + if (eventp->maxfd == ACL_VSTREAM_SOCK(fdp->stream)) + eventp->maxfd = ACL_SOCKET_INVALID; + + if (fdp->fdidx < --eventp->fdcnt) { + eventp->fdtabs[fdp->fdidx] = eventp->fdtabs[eventp->fdcnt]; + eventp->fdtabs[fdp->fdidx]->fdidx = fdp->fdidx; + } + fdp->fdidx = -1; + + if (fdp->fdidx_ready >= 0 + && fdp->fdidx_ready < eventp->fdcnt_ready + && eventp->fdtabs_ready[fdp->fdidx_ready] == fdp) + { + eventp->fdtabs_ready[fdp->fdidx_ready] = NULL; + } + fdp->fdidx_ready = -1; +} + +/* event_disable_write - disable request for write events */ + +static void event_disable_write(ACL_EVENT *eventp, ACL_VSTREAM *stream) +{ + const char *myname = "event_disable_write"; + EVENT_KERNEL *ev = (EVENT_KERNEL *) eventp; + ACL_EVENT_FDTABLE *fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + + if (fdp == NULL) { + acl_msg_warn("%s(%d): fdp null", myname, __LINE__); + return; + } + if (fdp->fdidx < 0 || fdp->fdidx >= eventp->fdcnt) { + acl_msg_warn("%s(%d): sockfd(%d)'s fdidx(%d) invalid", + myname, __LINE__, ACL_VSTREAM_SOCK(stream), fdp->fdidx); + return; + } + if ((fdp->flag & EVENT_FDTABLE_FLAG_DEL_WRITE)) { + return; + } + if ((fdp->flag & EVENT_FDTABLE_FLAG_ADD_WRITE)) { + fdp->flag &= ~EVENT_FDTABLE_FLAG_ADD_WRITE; + goto DEL_WRITE_TAG; + } + if (!(fdp->flag & EVENT_FDTABLE_FLAG_WRITE)) { + acl_msg_warn("%s(%d): sockfd(%d) not be set", + myname, __LINE__, ACL_VSTREAM_SOCK(stream)); + return; + } + + fdp->flag |= EVENT_FDTABLE_FLAG_DEL_WRITE; + if (!(fdp->flag & EVENT_FDTABLE_FLAG_DELAY_OPER)) { + acl_ring_append(&ev->fdp_delay_list, &fdp->delay_entry); + fdp->flag |= EVENT_FDTABLE_FLAG_DELAY_OPER; + } + +DEL_WRITE_TAG: + + fdp->w_ttl = 0; + fdp->w_timeout = 0; + fdp->w_callback = NULL; + fdp->event_type &= ~ACL_EVENT_WRITE; + + if ((fdp->flag & EVENT_FDTABLE_FLAG_READ) + || (fdp->flag & EVENT_FDTABLE_FLAG_ADD_READ)) + { + return; + } + + if (eventp->maxfd == ACL_VSTREAM_SOCK(stream)) + eventp->maxfd = ACL_SOCKET_INVALID; + + if (fdp->fdidx < --eventp->fdcnt) { + eventp->fdtabs[fdp->fdidx] = eventp->fdtabs[eventp->fdcnt]; + eventp->fdtabs[fdp->fdidx]->fdidx = fdp->fdidx; + } + fdp->fdidx = -1; + + if (fdp->fdidx_ready >= 0 + && fdp->fdidx_ready < eventp->fdcnt_ready + && eventp->fdtabs_ready[fdp->fdidx_ready] == fdp) + { + eventp->fdtabs_ready[fdp->fdidx_ready] = NULL; + } + fdp->fdidx_ready = -1; +} + +/* event_disable_readwrite - disable request for read or write events */ + +static void event_disable_readwrite(ACL_EVENT *eventp, ACL_VSTREAM *stream) +{ + const char *myname = "event_disable_readwrite"; + EVENT_KERNEL *ev = (EVENT_KERNEL *) eventp; + ACL_SOCKET sockfd = ACL_VSTREAM_SOCK(stream); + ACL_EVENT_FDTABLE *fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + int err = 0; + + if (fdp == NULL) + return; + + if (fdp->flag == 0 || fdp->fdidx < 0 || fdp->fdidx >= eventp->fdcnt) { + acl_msg_warn("%s(%d): sockfd(%d) no set, fdp no null", + myname, __LINE__, sockfd); + event_fdtable_free(fdp); + stream->fdp = NULL; + return; + } + + if (eventp->maxfd == sockfd) + eventp->maxfd = ACL_SOCKET_INVALID; + if (fdp->fdidx < --eventp->fdcnt) { + eventp->fdtabs[fdp->fdidx] = eventp->fdtabs[eventp->fdcnt]; + eventp->fdtabs[fdp->fdidx]->fdidx = fdp->fdidx; + } + fdp->fdidx = -1; + +#ifdef EVENT_REG_DEL_BOTH + EVENT_REG_DEL_BOTH(err, ev->event_fd, sockfd); +#else + if (fdp->flag & EVENT_FDTABLE_FLAG_READ) { + EVENT_REG_DEL_READ(err, ev->event_fd, sockfd); + } + if (fdp->flag & EVENT_FDTABLE_FLAG_WRITE) { + EVENT_REG_DEL_WRITE(err, ev->event_fd, sockfd); + } +#endif + + if (err < 0) { + acl_msg_fatal("%s: %s: %s", myname, EVENT_REG_DEL_TEXT, + acl_last_serror()); + } + +#ifdef USE_FDMAP + acl_fdmap_del(ev->fdmap, sockfd); +#endif + if (fdp->fdidx_ready >= 0 + && fdp->fdidx_ready < eventp->fdcnt_ready + && eventp->fdtabs_ready[fdp->fdidx_ready] == fdp) + { + eventp->fdtabs_ready[fdp->fdidx_ready] = NULL; + } + fdp->fdidx_ready = -1; + event_fdtable_free(fdp); + stream->fdp = NULL; +} + +static void enable_read(EVENT_KERNEL *ev, ACL_EVENT_FDTABLE *fdp) +{ + const char *myname = "enable_read"; + ACL_SOCKET sockfd = ACL_VSTREAM_SOCK(fdp->stream); + int err; + + fdp->flag &= ~EVENT_FDTABLE_FLAG_ADD_READ; + fdp->flag |= EVENT_FDTABLE_FLAG_READ; + + if ((fdp->flag & EVENT_FDTABLE_FLAG_WRITE)) { +#if (ACL_EVENTS_KERNEL_STYLE == ACL_EVENTS_STYLE_KQUEUE) + EVENT_REG_ADD_READ(err, ev->event_fd, sockfd, fdp); +#else + EVENT_REG_MOD_RDWR(err, ev->event_fd, sockfd, fdp); +#endif + } else { + EVENT_REG_ADD_READ(err, ev->event_fd, sockfd, fdp); + } + if (err < 0) { + acl_msg_fatal("%s: %s: %s, err(%d), fd(%d)", + myname, EVENT_REG_ADD_TEXT, + acl_last_serror(), err, sockfd); + } +} + +static void enable_write(EVENT_KERNEL *ev, ACL_EVENT_FDTABLE *fdp) +{ + const char *myname = "enable_write"; + ACL_SOCKET sockfd = ACL_VSTREAM_SOCK(fdp->stream); + int err; + + fdp->flag &= ~EVENT_FDTABLE_FLAG_ADD_WRITE; + fdp->flag |= EVENT_FDTABLE_FLAG_WRITE; + + if ((fdp->flag & EVENT_FDTABLE_FLAG_READ)) { +#if (ACL_EVENTS_KERNEL_STYLE == ACL_EVENTS_STYLE_KQUEUE) + EVENT_REG_ADD_WRITE(err, ev->event_fd, sockfd, fdp); +#else + EVENT_REG_MOD_RDWR(err, ev->event_fd, sockfd, fdp); +#endif + } else { + EVENT_REG_ADD_WRITE(err, ev->event_fd, sockfd, fdp); + } + + if (err < 0) { + acl_msg_fatal("%s: %s: %s, err(%d), fd(%d)", + myname, EVENT_REG_ADD_TEXT, + acl_last_serror(), err, sockfd); + } +} + +static int disable_read(EVENT_KERNEL *ev, ACL_EVENT_FDTABLE *fdp) +{ + const char *myname = "disable_read"; + ACL_VSTREAM *stream = fdp->stream; + ACL_SOCKET sockfd = ACL_VSTREAM_SOCK(stream); + int err, ret = 0; + + fdp->flag &= ~EVENT_FDTABLE_FLAG_DEL_READ; + fdp->flag &= ~EVENT_FDTABLE_FLAG_READ; + fdp->event_type &= ~ACL_EVENT_READ; + + if ((fdp->flag & EVENT_FDTABLE_FLAG_WRITE)) { +#if (ACL_EVENTS_KERNEL_STYLE == ACL_EVENTS_STYLE_KQUEUE) + EVENT_REG_DEL_READ(err, ev->event_fd, sockfd); +#else + EVENT_REG_MOD_WRITE(err, ev->event_fd, sockfd, fdp); +#endif + } else { +#ifdef EVENT_REG_DEL_BOTH + EVENT_REG_DEL_BOTH(err, ev->event_fd, sockfd); +#else + EVENT_REG_DEL_READ(err, ev->event_fd, sockfd); +#endif +#ifdef USE_FDMAP + acl_fdmap_del(ev->fdmap, sockfd); +#endif + ret = 1; + } + if (err < 0) { + acl_msg_fatal("%s: %s: %s, err(%d), fd(%d), ret(%d)", + myname, EVENT_REG_DEL_TEXT, acl_last_serror(), + err, sockfd, ret); + } + return ret; +} + +static int disable_write(EVENT_KERNEL *ev, ACL_EVENT_FDTABLE *fdp) +{ + const char *myname = "disable_write"; + ACL_VSTREAM *stream = fdp->stream; + ACL_SOCKET sockfd = ACL_VSTREAM_SOCK(stream); + int err, ret = 0; + + fdp->flag &= ~EVENT_FDTABLE_FLAG_DEL_WRITE; + fdp->flag &= ~EVENT_FDTABLE_FLAG_WRITE; + fdp->event_type &= ~ACL_EVENT_WRITE; + + if ((fdp->flag & EVENT_FDTABLE_FLAG_READ)) { +#if (ACL_EVENTS_KERNEL_STYLE == ACL_EVENTS_STYLE_KQUEUE) + EVENT_REG_DEL_WRITE(err, ev->event_fd, sockfd); +#else + EVENT_REG_MOD_READ(err, ev->event_fd, sockfd, fdp); +#endif + } else { +#ifdef USE_FDMAP + acl_fdmap_del(ev->fdmap, sockfd); +#endif +#ifdef EVENT_REG_DEL_BOTH + EVENT_REG_DEL_BOTH(err, ev->event_fd, sockfd); +#else + EVENT_REG_DEL_WRITE(err, ev->event_fd, sockfd); +#endif + ret = 1; + } + if (err < 0) { + acl_msg_fatal("%s: %s: %s, err(%d), fd(%d), ret(%d)", + myname, EVENT_REG_DEL_TEXT, acl_last_serror(), + err, sockfd, ret); + } + return (ret); +} + +static void event_set_all(ACL_EVENT *eventp) +{ + EVENT_KERNEL *ev = (EVENT_KERNEL *) eventp; + ACL_EVENT_FDTABLE *fdp; + + /* 优先处理添加读/写监控任务, 这样可以把中间的 ADD 状态转换成正式状态 */ + + eventp->fdcnt_ready = 0; + + if (eventp->event_present - ev->last_check >= 1000000) { + ev->last_check = eventp->event_present; + event_check_fds(eventp); + } + + /* 处理任务项 */ + + while (1) { + ACL_RING *r = acl_ring_pop_head(&ev->fdp_delay_list); + if (r == NULL) + break; + fdp = acl_ring_to_appl(r, ACL_EVENT_FDTABLE, delay_entry); + + if ((fdp->flag & EVENT_FDTABLE_FLAG_ADD_READ)) { + enable_read(ev, fdp); + } + if ((fdp->flag & EVENT_FDTABLE_FLAG_ADD_WRITE)) { + enable_write(ev, fdp); + } + if ((fdp->flag & EVENT_FDTABLE_FLAG_DEL_READ)) { + disable_read(ev, fdp); + } + if ((fdp->flag & EVENT_FDTABLE_FLAG_DEL_WRITE)) { + disable_write(ev, fdp); + } + + fdp->flag &= ~EVENT_FDTABLE_FLAG_DELAY_OPER; + } +} + +static void event_loop(ACL_EVENT *eventp) +{ + const char *myname = "event_loop"; + EVENT_KERNEL *ev = (EVENT_KERNEL *) eventp; + ACL_EVENT_NOTIFY_FN worker_fn; + void *worker_arg; + ACL_EVENT_TIMER *timer; + int delay, nready; + ACL_EVENT_FDTABLE *fdp; + EVENT_BUFFER *bp; + + delay = (int) (eventp->delay_sec * 1000 + eventp->delay_usec / 1000); + if (delay < 0) + delay = 0; /* 0 milliseconds at least */ + + /* 调整事件引擎的时间截 */ + + SET_TIME(eventp->event_present); + + /* 根据定时器任务的最近任务计算 epoll/kqueue/devpoll 的检测超时上限 */ + + if ((timer = ACL_FIRST_TIMER(&eventp->timer_head)) != 0) { + acl_int64 n = (timer->when - eventp->event_present) / 1000; + + if (n <= 0) + delay = 0; + else if ((int) n < delay) + delay = (int) n; + } + + /* 设置描述字对象的状态,添加/删除之前设置的描述字对象 */ + + event_set_all(eventp); + + if (eventp->fdcnt == 0) { + if (eventp->fdcnt_ready == 0) + sleep(1); + goto TAG_DONE; + } + + /* 如果已经有描述字准备好则检测超时时间置 0 */ + + if (eventp->fdcnt_ready > 0) + delay = 0; + + /* 调用 epoll/kquque/devpoll 系统调用检测可用描述字 */ + + EVENT_BUFFER_READ(nready, ev->event_fd, ev->event_buf, + ev->event_fdslots, delay); + + if (eventp->nested++ > 0) + acl_msg_fatal("%s(%d): recursive call", myname, __LINE__); + if (nready < 0) { + if (acl_last_error() != ACL_EINTR) { + acl_msg_fatal("%s(%d), %s: select: %s", __FILE__, + __LINE__, myname, acl_last_serror()); + } + goto TAG_DONE; + } else if (nready == 0) + goto TAG_DONE; + + /* 检查检测结果 */ + + for (bp = ev->event_buf; bp < ev->event_buf + nready; bp++) { +#ifdef USE_FDMAP + ACL_SOCKET sockfd; + + sockfd = EVENT_GET_FD(bp); + fdp = acl_fdmap_ctx(ev->fdmap, sockfd); + if (fdp == NULL || fdp->stream == NULL) + continue; + if (sockfd != ACL_VSTREAM_SOCK(fdp->stream)) + acl_msg_fatal("%s(%d): sockfd(%d) != %d", myname, + __LINE__, sockfd, ACL_VSTREAM_SOCK(fdp->stream)); +#else + fdp = (ACL_EVENT_FDTABLE *) EVENT_GET_CTX(bp); + if (fdp == NULL || fdp->stream == NULL) + continue; +#endif + + /* 如果该描述字对象已经在被设置为异常或超时状态则继续 */ + + if ((fdp->event_type & (ACL_EVENT_XCPT | ACL_EVENT_RW_TIMEOUT))) + continue; + + /* 检查描述字是否可读 */ + + if ((fdp->flag & EVENT_FDTABLE_FLAG_READ) && EVENT_TEST_READ(bp)) { + + /* 该描述字可读则设置 ACL_VSTREAM 的系统可读标志从而触发 + * ACL_VSTREAM 流在读时调用系统的 read 函数 + */ + + fdp->stream->sys_read_ready = 1; + + /* 给该描述字对象附加可读属性 */ + + if ((fdp->event_type & (ACL_EVENT_READ | ACL_EVENT_WRITE)) == 0) + { + fdp->event_type |= ACL_EVENT_READ; + fdp->fdidx_ready = eventp->fdcnt_ready; + eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp; + } + } + + /* 检查描述字是否可写 */ + + if ((fdp->flag & EVENT_FDTABLE_FLAG_WRITE) && EVENT_TEST_WRITE(bp)) { + + /* 给该描述字对象附加可写属性 */ + + if ((fdp->event_type & (ACL_EVENT_READ | ACL_EVENT_WRITE)) == 0) + { + fdp->event_type |= ACL_EVENT_WRITE; + fdp->fdidx_ready = eventp->fdcnt_ready; + eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp; + } + } + +#ifdef EVENT_TEST_ERROR + if (EVENT_TEST_ERROR(bp)) { + /* 如果出现异常则设置异常属性 */ + + if ((fdp->event_type & (ACL_EVENT_READ | ACL_EVENT_WRITE)) == 0) + { + fdp->event_type |= ACL_EVENT_XCPT; + fdp->fdidx_ready = eventp->fdcnt_ready; + eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp; + } + } +#endif + } + +TAG_DONE: + + /* + * Deliver timer events. Requests are sorted: we can stop when we reach + * the future or the list end. Allow the application to update the timer + * queue while it is being called back. To this end, we repeatedly pop + * the first request off the timer queue before delivering the event to + * the application. + */ + + /* 调整事件引擎的时间截 */ + + SET_TIME(eventp->event_present); + + while ((timer = ACL_FIRST_TIMER(&eventp->timer_head)) != 0) { + if (timer->when > eventp->event_present) + break; + worker_fn = timer->callback; + worker_arg = timer->context; + + /* 如果定时器的时间间隔 > 0 且允许定时器被循环调用,则再重设定时器 */ + if (timer->delay > 0 && timer->keep) { + timer->ncount++; + eventp->timer_request(eventp, timer->callback, + timer->context, timer->delay, timer->keep); + } else { + acl_ring_detach(&timer->ring); /* first this */ + timer->nrefer--; + if (timer->nrefer != 0) + acl_msg_fatal("%s(%d): nrefer(%d) != 0", + myname, __LINE__, timer->nrefer); + acl_myfree(timer); + } + worker_fn(ACL_EVENT_TIME, worker_arg); + } + + /* 处理准备好的描述字事件 */ + + if (eventp->fdcnt_ready > 0) + event_fire(eventp); + + eventp->nested--; +} + +static int event_isrset(ACL_EVENT *eventp acl_unused, ACL_VSTREAM *stream) +{ + ACL_EVENT_FDTABLE *fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + + return fdp == NULL ? 0 : (fdp->flag & EVENT_FDTABLE_FLAG_READ); +} + +static int event_iswset(ACL_EVENT *eventp acl_unused, ACL_VSTREAM *stream) +{ + ACL_EVENT_FDTABLE *fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + + return fdp == NULL ? 0 : (fdp->flag & EVENT_FDTABLE_FLAG_WRITE); + +} + +static int event_isxset(ACL_EVENT *eventp acl_unused, ACL_VSTREAM *stream) +{ + ACL_EVENT_FDTABLE *fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + + return fdp == NULL ? 0 : (fdp->flag & EVENT_FDTABLE_FLAG_EXPT); +} + +static void event_free(ACL_EVENT *eventp) +{ + EVENT_KERNEL *ev = (EVENT_KERNEL *) eventp; + +#ifdef USE_FDMAP + acl_fdmap_free(ev->fdmap); +#endif + acl_myfree(ev->event_buf); + close(ev->event_fd); + acl_myfree(ev); +} + +ACL_EVENT *event_new_kernel(int fdsize acl_unused) +{ + ACL_EVENT *eventp; + EVENT_KERNEL *ev; + static int __default_max_events = 1000; + + eventp = event_alloc(sizeof(EVENT_KERNEL)); + + snprintf(eventp->name, sizeof(eventp->name), "events - %s", EVENT_NAME); + eventp->event_mode = ACL_EVENT_KERNEL; + eventp->use_thread = 0; + eventp->loop_fn = event_loop; + eventp->free_fn = event_free; + eventp->enable_read_fn = event_enable_read; + eventp->enable_write_fn = event_enable_write; + eventp->enable_listen_fn = event_enable_read; + eventp->disable_read_fn = event_disable_read; + eventp->disable_write_fn = event_disable_write; + eventp->disable_readwrite_fn = event_disable_readwrite; + eventp->isrset_fn = event_isrset; + eventp->iswset_fn = event_iswset; + eventp->isxset_fn = event_isxset; + eventp->timer_request = event_timer_request; + eventp->timer_cancel = event_timer_cancel; + eventp->timer_keep = event_timer_keep; + eventp->timer_ifkeep = event_timer_ifkeep; + + ev = (EVENT_KERNEL*) eventp; + EVENT_REG_INIT_HANDLE(ev->event_fd, fdsize); + ev->event_fdslots = __default_max_events; + ev->event_buf = (EVENT_BUFFER *) + acl_mycalloc(ev->event_fdslots + 1, sizeof(EVENT_BUFFER)); + acl_ring_init(&ev->fdp_delay_list); +#ifdef USE_FDMAP + ev->fdmap = acl_fdmap_create(fdsize); +#endif + return eventp; +} +#endif /* ACL_EVENTS_KERNEL_STYLE */ diff --git a/lib_acl/src/event/events_kernel.c.bak b/lib_acl/src/event/events_kernel.c.bak new file mode 100644 index 000000000..b219ba591 --- /dev/null +++ b/lib_acl/src/event/events_kernel.c.bak @@ -0,0 +1,819 @@ +#include "stdlib/acl_define.h" +#include +#include +#include +#include +#include + +#if 0 +#define NDEBUG +#endif + +#include +#include + +#ifdef ACL_UNIX +#include +#endif + +#include "stdlib/acl_sys_patch.h" +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_mystring.h" +#include "stdlib/acl_msg.h" +#include "stdlib/acl_debug.h" +#include "stdlib/acl_vstream.h" +#include "stdlib/acl_fifo.h" +#include "stdlib/acl_meter_time.h" /* just for performance test */ +#include "event/acl_events.h" + +#include "events_define.h" + +#ifdef ACL_EVENTS_KERNEL_STYLE + +#include "events_epoll.h" +#include "events_devpoll.h" +#include "events_kqueue.h" +#include "events_fdtable.h" +#include "events.h" + +typedef struct EVENT_KERNEL { + ACL_EVENT event; + EVENT_BUFFER *event_buf; + ACL_FIFO *fdp_free_list; + int event_fdslots; + int event_fd; +#ifdef USE_FDMAP + ACL_FD_MAP *fdmap; +#endif +} EVENT_KERNEL; + +#include "stdlib/acl_meter_time.h" + +static void event_enable_read(ACL_EVENT *eventp, ACL_VSTREAM *stream, + int timeout, ACL_EVENT_NOTIFY_RDWR callback, void *context) +{ + ACL_EVENT_FDTABLE *fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + ACL_SOCKET sockfd = ACL_VSTREAM_SOCK(stream); + + if (fdp == NULL) { + fdp = event_fdtable_alloc(eventp); + + fdp->flag = EVENT_FDTABLE_FLAG_ADD_READ | EVENT_FDTABLE_FLAG_EXPT; + fdp->stream = stream; + stream->fdp = (void *) fdp; +#ifdef USE_FDMAP + acl_fdmap_add(ev->fdmap, sockfd, fdp); +#endif + } else if ((fdp->flag & EVENT_FDTABLE_FLAG_ADD_READ)) { + goto END; + } else if ((fdp->flag & EVENT_FDTABLE_FLAG_DEL_READ)) { + + /* 停止禁止读监听过程 */ + + assert((fdp->flag & EVENT_FDTABLE_FLAG_READ)); + assert(fdp->fifo_info); + + /* 重新启用读监听过程, 因为之前的过程是正在拆除读监听过程但 + * 还没有正式拆除,所以只需要清除拆除标志位即可 + */ + + fdp->flag &= ~EVENT_FDTABLE_FLAG_DEL_READ; + + if (!(fdp->flag & EVENT_FDTABLE_FLAG_DEL_WRITE)) { + EVENT_KERNEL *ev = (EVENT_KERNEL *) eventp; + acl_fifo_delete_info(ev->fdp_free_list, fdp->fifo_info); + fdp->fifo_info = NULL; + } + } else if (!(fdp->flag & EVENT_FDTABLE_FLAG_READ)) { + + assert((fdp->flag & EVENT_FDTABLE_FLAG_WRITE)); + + fdp->flag |= EVENT_FDTABLE_FLAG_ADD_READ; + + /* xxx: can this happen ? */ + if (!(fdp->flag & EVENT_FDTABLE_FLAG_DEL_WRITE) && fdp->fifo_info) { + EVENT_KERNEL *ev = (EVENT_KERNEL *) eventp; + acl_fifo_delete_info(ev->fdp_free_list, fdp->fifo_info); + fdp->fifo_info = NULL; + assert(0); + } + } + +END: + if (fdp->fdidx == -1) { + fdp->fdidx = eventp->fdcnt; + eventp->fdtabs[eventp->fdcnt++] = fdp; + } + if (eventp->maxfd != ACL_SOCKET_INVALID && eventp->maxfd < sockfd) + eventp->maxfd = sockfd; + + if (fdp->r_callback != callback || fdp->r_context != context) { + fdp->r_callback = callback; + fdp->r_context = context; + } + + if (timeout > 0) { + fdp->r_ttl = eventp->event_present + timeout; + fdp->r_timeout = timeout; + } else { + fdp->r_ttl = 0; + fdp->r_timeout = 0; + } +} + +static void event_enable_write(ACL_EVENT *eventp, ACL_VSTREAM *stream, + int timeout, ACL_EVENT_NOTIFY_RDWR callback, void *context) +{ + ACL_EVENT_FDTABLE *fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + ACL_SOCKET sockfd = ACL_VSTREAM_SOCK(stream); + + if (fdp == NULL) { + fdp = event_fdtable_alloc(eventp); + + fdp->flag = EVENT_FDTABLE_FLAG_ADD_WRITE | EVENT_FDTABLE_FLAG_EXPT; + fdp->stream = stream; + stream->fdp = (void *) fdp; +#ifdef USE_FDMAP + acl_fdmap_add(ev->fdmap, sockfd, fdp); +#endif + } else if ((fdp->flag & EVENT_FDTABLE_FLAG_ADD_WRITE)) { + goto END; + } else if ((fdp->flag & EVENT_FDTABLE_FLAG_DEL_WRITE)) { + assert((fdp->flag & EVENT_FDTABLE_FLAG_WRITE)); + assert(fdp->fifo_info); + + fdp->flag &= ~EVENT_FDTABLE_FLAG_DEL_WRITE; + + if (!(fdp->flag & EVENT_FDTABLE_FLAG_DEL_READ)) { + EVENT_KERNEL *ev = (EVENT_KERNEL *) eventp; + acl_fifo_delete_info(ev->fdp_free_list, fdp->fifo_info); + fdp->fifo_info = NULL; + } + } else if (!(fdp->flag & EVENT_FDTABLE_FLAG_WRITE)) { + + assert((fdp->flag & EVENT_FDTABLE_FLAG_READ)); + + fdp->flag |= EVENT_FDTABLE_FLAG_ADD_WRITE; + + /* xxx: can this happen ? */ + if (!(fdp->flag & EVENT_FDTABLE_FLAG_DEL_READ) && fdp->fifo_info) { + EVENT_KERNEL *ev = (EVENT_KERNEL *) eventp; + acl_fifo_delete_info(ev->fdp_free_list, fdp->fifo_info); + fdp->fifo_info = NULL; + assert(0); + } + } + +END: + if (fdp->fdidx == -1) { + fdp->fdidx = eventp->fdcnt; + eventp->fdtabs[eventp->fdcnt++] = fdp; + } + + if (eventp->maxfd != ACL_SOCKET_INVALID && eventp->maxfd < sockfd) + eventp->maxfd = sockfd; + + if (fdp->w_callback != callback || fdp->w_context != context) { + fdp->w_callback = callback; + fdp->w_context = context; + } + + if (timeout > 0) { + fdp->w_ttl = eventp->event_present + timeout; + fdp->w_timeout = timeout; + } else { + fdp->w_ttl = 0; + fdp->w_timeout = 0; + } +} + +/* event_disable_read - disable request for read events */ + +static void event_disable_read(ACL_EVENT *eventp, ACL_VSTREAM *stream) +{ + const char *myname = "event_disable_read"; + EVENT_KERNEL *ev = (EVENT_KERNEL *) eventp; + ACL_EVENT_FDTABLE *fdp; + + fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + if (fdp == NULL) { + acl_msg_warn("%s(%d): fdp null", myname, __LINE__); + return; + } + if (fdp->fdidx < 0 || fdp->fdidx >= eventp->fdcnt) { + acl_msg_warn("%s(%d): sockfd(%d)'s fdidx(%d) invalid, fdcnt: %d", + myname, __LINE__, ACL_VSTREAM_SOCK(stream), + fdp->fdidx, eventp->fdcnt); + return; + } + if ((fdp->flag & EVENT_FDTABLE_FLAG_DEL_READ)) { + return; + } + if ((fdp->flag & EVENT_FDTABLE_FLAG_ADD_READ)) { + fdp->flag &= ~EVENT_FDTABLE_FLAG_ADD_READ; + goto DEL_READ_TAG; + } + + if (!(fdp->flag & EVENT_FDTABLE_FLAG_READ)) { + acl_msg_warn("%s(%d): sockfd(%d) not be set", + myname, __LINE__, ACL_VSTREAM_SOCK(stream)); + return; + } + fdp->flag |= EVENT_FDTABLE_FLAG_DEL_READ; + if (fdp->fifo_info == NULL) { + fdp->fifo_info = acl_fifo_push(ev->fdp_free_list, fdp); + } + +DEL_READ_TAG: + + fdp->event_type &= ~ACL_EVENT_READ; + fdp->r_ttl = 0; + fdp->r_timeout = 0; + fdp->r_callback = NULL; + + if ((fdp->flag & EVENT_FDTABLE_FLAG_WRITE)) { + return; + } + + if (eventp->maxfd == ACL_VSTREAM_SOCK(fdp->stream)) + eventp->maxfd = ACL_SOCKET_INVALID; + if (fdp->fdidx < --eventp->fdcnt) { + eventp->fdtabs[fdp->fdidx] = eventp->fdtabs[eventp->fdcnt]; + eventp->fdtabs[fdp->fdidx]->fdidx = fdp->fdidx; + } + fdp->fdidx = -1; + if (fdp->fdidx_ready > 0 + && fdp->fdidx_ready < eventp->fdcnt_ready + && eventp->fdtabs_ready[fdp->fdidx_ready] == fdp) + { + eventp->fdtabs_ready[fdp->fdidx_ready] = NULL; + fdp->fdidx_ready = -1; + } +} + +/* event_disable_write - disable request for write events */ + +static void event_disable_write(ACL_EVENT *eventp, ACL_VSTREAM *stream) +{ + const char *myname = "event_disable_write"; + EVENT_KERNEL *ev = (EVENT_KERNEL *) eventp; + ACL_EVENT_FDTABLE *fdp; + + fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + if (fdp == NULL) { + acl_msg_warn("%s(%d): fdp null", myname, __LINE__); + return; + } + if (fdp->fdidx < 0 || fdp->fdidx >= eventp->fdcnt) { + acl_msg_warn("%s(%d): sockfd(%d)'s fdidx(%d) invalid", + myname, __LINE__, ACL_VSTREAM_SOCK(stream), fdp->fdidx); + return; + } + if ((fdp->flag & EVENT_FDTABLE_FLAG_DEL_WRITE)) { + return; + } + if ((fdp->flag & EVENT_FDTABLE_FLAG_ADD_WRITE)) { + fdp->flag &= ~EVENT_FDTABLE_FLAG_ADD_WRITE; + goto DEL_WRITE_TAG; + } + if (!(fdp->flag & EVENT_FDTABLE_FLAG_WRITE)) { + acl_msg_warn("%s(%d): sockfd(%d) not be set", + myname, __LINE__, ACL_VSTREAM_SOCK(stream)); + return; + } + + fdp->flag |= EVENT_FDTABLE_FLAG_DEL_WRITE; + if (fdp->fifo_info == NULL) { + fdp->fifo_info = acl_fifo_push(ev->fdp_free_list, fdp); + } + +DEL_WRITE_TAG: + + fdp->event_type &= ~ACL_EVENT_WRITE; + fdp->w_ttl = 0; + fdp->w_timeout = 0; + fdp->w_callback = NULL; + + if ((fdp->flag & EVENT_FDTABLE_FLAG_READ)) { + return; + } + if (eventp->maxfd == ACL_VSTREAM_SOCK(stream)) + eventp->maxfd = ACL_SOCKET_INVALID; + if (fdp->fdidx < --eventp->fdcnt) { + eventp->fdtabs[fdp->fdidx] = eventp->fdtabs[eventp->fdcnt]; + eventp->fdtabs[fdp->fdidx]->fdidx = fdp->fdidx; + } + fdp->fdidx = -1; + if (fdp->fdidx_ready > 0 + && fdp->fdidx_ready < eventp->fdcnt_ready + && eventp->fdtabs_ready[fdp->fdidx_ready] == fdp) + { + eventp->fdtabs_ready[fdp->fdidx_ready] = NULL; + fdp->fdidx_ready = -1; + } +} + +/* event_disable_readwrite - disable request for read or write events */ + +static void event_disable_readwrite(ACL_EVENT *eventp, ACL_VSTREAM *stream) +{ + const char *myname = "event_disable_readwrite"; + EVENT_KERNEL *ev = (EVENT_KERNEL *) eventp; + ACL_EVENT_FDTABLE *fdp; + ACL_SOCKET sockfd; + int err = 0; + + sockfd = ACL_VSTREAM_SOCK(stream); + fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + if (fdp == NULL) { + return; + } + + if (fdp->flag == 0 || fdp->fdidx < 0 || fdp->fdidx >= eventp->fdcnt) { + acl_msg_warn("%s(%d): sockfd(%d) no set, fdp no null", + myname, __LINE__, sockfd); + event_fdtable_free(eventp, fdp); + stream->fdp = NULL; + return; + } + + if (eventp->maxfd == sockfd) + eventp->maxfd = ACL_SOCKET_INVALID; + if (fdp->fdidx < --eventp->fdcnt) { + eventp->fdtabs[fdp->fdidx] = eventp->fdtabs[eventp->fdcnt]; + eventp->fdtabs[fdp->fdidx]->fdidx = fdp->fdidx; + } + +#ifdef EVENT_REG_DEL_BOTH + EVENT_REG_DEL_BOTH(err, ev->event_fd, sockfd); +#else + if (fdp->flag & EVENT_FDTABLE_FLAG_READ) { + EVENT_REG_DEL_READ(err, ev->event_fd, sockfd); + } + if (fdp->flag & EVENT_FDTABLE_FLAG_WRITE) { + EVENT_REG_DEL_WRITE(err, ev->event_fd, sockfd); + } +#endif + + if (fdp->flag & EVENT_FDTABLE_FLAG_READ) { + stream->nrefer--; + } + if (fdp->flag & EVENT_FDTABLE_FLAG_WRITE) { + stream->nrefer--; + } + + if (err < 0) { + acl_msg_fatal("%s: %s: %s", myname, EVENT_REG_DEL_TEXT, + acl_last_serror()); + } + +#ifdef USE_FDMAP + acl_fdmap_del(ev->fdmap, sockfd); +#endif + if (fdp->fdidx_ready > 0 + && fdp->fdidx_ready < eventp->fdcnt_ready + && eventp->fdtabs_ready[fdp->fdidx_ready] == fdp) + { + eventp->fdtabs_ready[fdp->fdidx_ready] = NULL; + } + event_fdtable_free(eventp, fdp); + stream->fdp = NULL; +} + +static void enable_read(EVENT_KERNEL *ev, ACL_EVENT_FDTABLE *fdp) +{ + const char *myname = "enable_read"; + ACL_SOCKET sockfd = ACL_VSTREAM_SOCK(fdp->stream); + int err; + + fdp->flag &= ~EVENT_FDTABLE_FLAG_ADD_READ; + fdp->flag |= EVENT_FDTABLE_FLAG_READ; + fdp->stream->nrefer++; + + if ((fdp->flag & EVENT_FDTABLE_FLAG_WRITE)) { +#if (ACL_EVENTS_KERNEL_STYLE == ACL_EVENTS_STYLE_KQUEUE) + EVENT_REG_ADD_READ(err, ev->event_fd, sockfd, fdp); +#else + EVENT_REG_MOD_RDWR(err, ev->event_fd, sockfd, fdp); +#endif + } else { + EVENT_REG_ADD_READ(err, ev->event_fd, sockfd, fdp); + } + if (err < 0) { + acl_msg_fatal("%s: %s: %s, err(%d), fd(%d)", + myname, EVENT_REG_ADD_TEXT, + acl_last_serror(), err, sockfd); + } +} + +static void enable_write(EVENT_KERNEL *ev, ACL_EVENT_FDTABLE *fdp) +{ + const char *myname = "enable_write"; + ACL_SOCKET sockfd = ACL_VSTREAM_SOCK(fdp->stream); + int err; + + fdp->flag &= ~EVENT_FDTABLE_FLAG_ADD_WRITE; + fdp->flag |= EVENT_FDTABLE_FLAG_WRITE; + fdp->stream->nrefer++; + + if ((fdp->flag & EVENT_FDTABLE_FLAG_READ)) { +#if (ACL_EVENTS_KERNEL_STYLE == ACL_EVENTS_STYLE_KQUEUE) + EVENT_REG_ADD_WRITE(err, ev->event_fd, sockfd, fdp); +#else + EVENT_REG_MOD_RDWR(err, ev->event_fd, sockfd, fdp); +#endif + } else { + EVENT_REG_ADD_WRITE(err, ev->event_fd, sockfd, fdp); + } + + if (err < 0) { + acl_msg_fatal("%s: %s: %s, err(%d), fd(%d)", + myname, EVENT_REG_ADD_TEXT, + acl_last_serror(), err, sockfd); + } +} + +static int disable_read(EVENT_KERNEL *ev, ACL_EVENT_FDTABLE *fdp) +{ + const char *myname = "disable_read"; + ACL_VSTREAM *stream = fdp->stream; + ACL_SOCKET sockfd = ACL_VSTREAM_SOCK(stream); + int err, ret = 0, nrefer = -1, defer = 0; + + if ((fdp->flag & EVENT_FDTABLE_FLAG_WRITE)) { + fdp->flag &= ~EVENT_FDTABLE_FLAG_DEL_READ; + fdp->flag &= ~EVENT_FDTABLE_FLAG_READ; + /* + fdp->event_type &= ~ACL_EVENT_READ; + */ +#if (ACL_EVENTS_KERNEL_STYLE == ACL_EVENTS_STYLE_KQUEUE) + EVENT_REG_DEL_READ(err, ev->event_fd, sockfd); +#else + EVENT_REG_MOD_WRITE(err, ev->event_fd, sockfd, fdp); +#endif + stream->nrefer--; + nrefer = stream->nrefer; + } else { + fdp->stream = NULL; + event_fdtable_free(&ev->event, fdp); +#ifdef EVENT_REG_DEL_BOTH + EVENT_REG_DEL_BOTH(err, ev->event_fd, sockfd); +#else + EVENT_REG_DEL_READ(err, ev->event_fd, sockfd); +#endif +#ifdef USE_FDMAP + acl_fdmap_del(ev->fdmap, sockfd); +#endif + stream->fdp = NULL; + stream->nrefer--; + nrefer = stream->nrefer; + if ((stream->flag & ACL_VSTREAM_FLAG_DEFER_FREE)) { + acl_vstream_close(stream); + defer = 1; + } + ret = 1; + } + if (err < 0) { + acl_msg_fatal("%s: %s: %s, err(%d), fd(%d), ret(%d), nrefer(%d), defer(%d)", + myname, EVENT_REG_DEL_TEXT, acl_last_serror(), + err, sockfd, ret, nrefer, defer); + } + return (ret); +} + +static int disable_write(EVENT_KERNEL *ev, ACL_EVENT_FDTABLE *fdp) +{ + const char *myname = "disable_write"; + ACL_VSTREAM *stream = fdp->stream; + ACL_SOCKET sockfd = ACL_VSTREAM_SOCK(stream); + int err, ret = 0; + + if ((fdp->flag & EVENT_FDTABLE_FLAG_READ)) { + fdp->flag &= ~EVENT_FDTABLE_FLAG_DEL_WRITE; + fdp->flag &= ~EVENT_FDTABLE_FLAG_WRITE; + /* + fdp->event_type &= ~ACL_EVENT_WRITE; + */ +#if (ACL_EVENTS_KERNEL_STYLE == ACL_EVENTS_STYLE_KQUEUE) + EVENT_REG_DEL_WRITE(err, ev->event_fd, sockfd); +#else + EVENT_REG_MOD_READ(err, ev->event_fd, sockfd, fdp); +#endif + stream->nrefer--; + } else { + fdp->stream = NULL; + event_fdtable_free(&ev->event, fdp); +#ifdef USE_FDMAP + acl_fdmap_del(ev->fdmap, sockfd); +#endif +#ifdef EVENT_REG_DEL_BOTH + EVENT_REG_DEL_BOTH(err, ev->event_fd, sockfd); +#else + EVENT_REG_DEL_WRITE(err, ev->event_fd, sockfd); +#endif + stream->fdp = NULL; + stream->nrefer--; + if ((stream->flag & ACL_VSTREAM_FLAG_DEFER_FREE)) { + acl_vstream_close(stream); + } + ret = 1; + } + if (err < 0) { + acl_msg_fatal("%s: %s: %s, err(%d), fd(%d), ret(%d)", + myname, EVENT_REG_DEL_TEXT, acl_last_serror(), + err, sockfd, ret); + } + return (ret); +} + +static int event_set_all(ACL_EVENT *eventp) +{ + EVENT_KERNEL *ev = (EVENT_KERNEL *) eventp; + ACL_EVENT_FDTABLE *fdp; + int i, nwait = 0; + + /* 优先处理添加读/写监控任务, 这样可以把中间的 ADD 状态转换成正式状态 */ + + eventp->fdcnt_ready = 0; + + for (i = 0; i < eventp->fdcnt; i++) { + fdp = eventp->fdtabs[i]; + assert (fdp->stream); + + if ((fdp->flag & EVENT_FDTABLE_FLAG_ADD_READ)) { + enable_read(ev, fdp); + } + if ((fdp->flag & EVENT_FDTABLE_FLAG_ADD_WRITE)) { + enable_write(ev, fdp); + } + if ((fdp->stream->flag & ACL_VSTREAM_FLAG_BAD) != 0) { + fdp->stream->flag &= ~ACL_VSTREAM_FLAG_BAD; + fdp->event_type |= ACL_EVENT_XCPT; + fdp->fdidx_ready = eventp->fdcnt_ready; + eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp; + } else if ((fdp->flag & EVENT_FDTABLE_FLAG_READ)) { + if (ACL_VSTREAM_BFRD_CNT(fdp->stream) > 0) { + fdp->stream->sys_read_ready = 0; + fdp->event_type |= ACL_EVENT_READ; + fdp->fdidx_ready = eventp->fdcnt_ready; + eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp; + } else if (fdp->r_ttl > 0 && eventp->event_present > fdp->r_ttl) { + fdp->event_type |= ACL_EVENT_RW_TIMEOUT; + fdp->fdidx_ready = eventp->fdcnt_ready; + eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp; + } else + nwait++; + } else if ((fdp->flag & EVENT_FDTABLE_FLAG_WRITE)) { + if (fdp->w_ttl > 0 && eventp->event_present > fdp->w_ttl) { + fdp->event_type |= ACL_EVENT_RW_TIMEOUT; + fdp->fdidx_ready = eventp->fdcnt_ready; + eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp; + } else + nwait++; + } else + nwait++; + } + + /* 处理 DEL 类型的任务项 */ + + while (1) { + fdp = (ACL_EVENT_FDTABLE *) acl_fifo_pop(ev->fdp_free_list); + if (fdp == NULL) + break; + fdp->fifo_info = NULL; + i = 0; + if ((fdp->flag & EVENT_FDTABLE_FLAG_DEL_READ)) { + i = disable_read(ev, fdp); + } + if (i == 0 && (fdp->flag & EVENT_FDTABLE_FLAG_DEL_WRITE)) { + disable_write(ev, fdp); + } + } + + return (nwait); +} + +static void event_loop(ACL_EVENT *eventp) +{ + const char *myname = "event_loop"; + EVENT_KERNEL *ev = (EVENT_KERNEL *) eventp; + ACL_EVENT_NOTIFY_FN worker_fn; + void *worker_arg; + ACL_EVENT_TIMER *timer; + int delay, n, nready; + ACL_EVENT_FDTABLE *fdp; + EVENT_BUFFER *bp; + + delay = eventp->delay_sec * 1000 + eventp->delay_usec / 1000; + if (delay <= 0) + delay = 100; /* 100 milliseconds at least */ + + eventp->event_present = time((time_t *) 0); + + /* + * Find out when the next timer would go off. Timer requests are sorted. + * If any timer is scheduled, adjust the delay appropriately. + */ + if ((timer = ACL_FIRST_TIMER(&eventp->timer_head)) != 0) { + n = (int) (timer->when - eventp->event_present); + if (n <= 0) { + delay = 0; + } else if (delay > eventp->delay_sec) { + delay = n * 1000 + eventp->delay_usec / 1000; + } + } + + if (event_set_all(eventp) == 0) { + if (eventp->fdcnt_ready == 0) { + sleep(1); + } + nready = 0; + goto TAG_DONE; + } + + if (eventp->fdcnt_ready > 0) { + delay = 0; + } + + EVENT_BUFFER_READ(nready, + ev->event_fd, + ev->event_buf, + ev->event_fdslots, + delay); + + if (eventp->nested++ > 0) + acl_msg_fatal("%s(%d): recursive call", myname, __LINE__); + if (nready < 0) { + if (acl_last_error() != ACL_EINTR) { + char ebuf[256]; + acl_msg_fatal("%s(%d), %s: select: %s", + __FILE__, __LINE__, myname, + acl_last_strerror(ebuf, sizeof(ebuf))); + } else if (eventp->fdcnt_ready > 0) + goto TAG_DONE; + eventp->nested--; + return; + } + +TAG_DONE: + + /* + * Deliver timer events. Requests are sorted: we can stop when we reach + * the future or the list end. Allow the application to update the timer + * queue while it is being called back. To this end, we repeatedly pop + * the first request off the timer queue before delivering the event to + * the application. + */ + eventp->event_present = time((time_t *) 0); + while ((timer = ACL_FIRST_TIMER(&eventp->timer_head)) != 0) { + if (timer->when > eventp->event_present) + break; + worker_fn = timer->callback; + worker_arg = timer->context; + + acl_ring_detach(&timer->ring); /* first this */ + timer->nrefer--; + if (timer->nrefer != 0) + acl_msg_fatal("%s(%d): nrefer(%d) != 0", + myname, __LINE__, timer->nrefer); + acl_myfree(timer); + worker_fn(ACL_EVENT_TIME, worker_arg); + } + + for (bp = ev->event_buf; bp < ev->event_buf + nready; bp++) { +#ifdef USE_FDMAP + ACL_SOCKET sockfd; + + sockfd = EVENT_GET_FD(bp); + fdp = acl_fdmap_ctx(ev->fdmap, sockfd); + if (fdp == NULL || fdp->stream == NULL) + continue; + if (sockfd != ACL_VSTREAM_SOCK(fdp->stream)) + acl_msg_fatal("%s(%d): sockfd(%d) != %d", myname, + __LINE__, sockfd, ACL_VSTREAM_SOCK(fdp->stream)); +#else + fdp = (ACL_EVENT_FDTABLE *) EVENT_GET_CTX(bp); + if (fdp == NULL || fdp->stream == NULL) { + continue; + } +#endif + + if ((fdp->event_type & ACL_EVENT_XCPT) + || (fdp->event_type & ACL_EVENT_RW_TIMEOUT)) + { + continue; + } + + if ((fdp->flag & EVENT_FDTABLE_FLAG_READ) && EVENT_TEST_READ(bp)) { + fdp->stream->sys_read_ready = 1; + if ((fdp->event_type & ACL_EVENT_READ) == 0 + && (fdp->event_type & ACL_EVENT_WRITE) == 0) + { + fdp->event_type |= ACL_EVENT_READ; + fdp->fdidx_ready = eventp->fdcnt_ready; + eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp; + } + } + + if ((fdp->flag & EVENT_FDTABLE_FLAG_WRITE) && EVENT_TEST_WRITE(bp)) { + if ((fdp->event_type & ACL_EVENT_READ) == 0 + && (fdp->event_type & ACL_EVENT_WRITE) == 0) + { + fdp->event_type |= ACL_EVENT_WRITE; + fdp->fdidx_ready = eventp->fdcnt_ready; + eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp; + } + } + } + + event_fire(eventp); + eventp->nested--; +} + +static int event_isrset(ACL_EVENT *eventp acl_unused, ACL_VSTREAM *stream) +{ + ACL_EVENT_FDTABLE *fdp; + + fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + if (fdp == NULL) { + return (0); + } + + return ((fdp->flag & EVENT_FDTABLE_FLAG_READ)); +} + +static int event_iswset(ACL_EVENT *eventp acl_unused, ACL_VSTREAM *stream) +{ + ACL_EVENT_FDTABLE *fdp; + + fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + if (fdp == NULL) + return (0); + + return ((fdp->flag & EVENT_FDTABLE_FLAG_WRITE)); + +} + +static int event_isxset(ACL_EVENT *eventp acl_unused, ACL_VSTREAM *stream) +{ + ACL_EVENT_FDTABLE *fdp; + + fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + if (fdp == NULL) + return (0); + + return ((fdp->flag & EVENT_FDTABLE_FLAG_EXPT)); +} + +static void event_free(ACL_EVENT *eventp) +{ + const char *myname = "event_free"; + EVENT_KERNEL *ev = (EVENT_KERNEL *) eventp; + + if (eventp == NULL) + acl_msg_fatal("%s, %s(%d): eventp null", __FILE__, myname, __LINE__); + +#ifdef USE_FDMAP + acl_fdmap_free(ev->fdmap); +#endif + acl_myfree(ev->event_buf); + close(ev->event_fd); + acl_myfree(ev); +} + +ACL_EVENT *event_new_kernel(int fdsize acl_unused) +{ + ACL_EVENT *eventp; + EVENT_KERNEL *ev; + static int __default_max_events = 1000; + + eventp = event_alloc(sizeof(EVENT_KERNEL)); + + snprintf(eventp->name, sizeof(eventp->name), "events - %s", EVENT_NAME); + eventp->event_mode = ACL_EVENT_KERNEL; + eventp->use_thread = 0; + eventp->loop_fn = event_loop; + eventp->free_fn = event_free; + eventp->enable_read_fn = event_enable_read; + eventp->enable_write_fn = event_enable_write; + eventp->enable_listen_fn = event_enable_read; + eventp->disable_read_fn = event_disable_read; + eventp->disable_write_fn = event_disable_write; + eventp->disable_readwrite_fn = event_disable_readwrite; + eventp->isrset_fn = event_isrset; + eventp->iswset_fn = event_iswset; + eventp->isxset_fn = event_isxset; + eventp->request_timer = event_request_timer; + eventp->cancel_timer = event_cancel_timer; + + ev = (EVENT_KERNEL*) eventp; + EVENT_REG_INIT_HANDLE(ev->event_fd, fdsize); + ev->event_fdslots = __default_max_events; + ev->event_buf = (EVENT_BUFFER *) acl_mycalloc(ev->event_fdslots + 1, sizeof(EVENT_BUFFER)); + ev->fdp_free_list = acl_fifo_new(); +#ifdef USE_FDMAP + ev->fdmap = acl_fdmap_create(fdsize); +#endif + return (eventp); +} +#endif /* ACL_EVENTS_KERNEL_STYLE */ diff --git a/lib_acl/src/event/events_kernel2.c b/lib_acl/src/event/events_kernel2.c new file mode 100644 index 000000000..ea70d0ea3 --- /dev/null +++ b/lib_acl/src/event/events_kernel2.c @@ -0,0 +1,672 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include +#include +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#ifdef ACL_UNIX +#include +#endif + +#include "stdlib/acl_sys_patch.h" +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_mystring.h" +#include "stdlib/acl_msg.h" +#include "stdlib/acl_debug.h" +#include "stdlib/acl_vstream.h" +#include "event/acl_events.h" + +#endif + +#include "events_define.h" + +#ifdef ACL_EVENTS_KERNEL_STYLE + +#include "events_epoll.h" +#include "events_devpoll.h" +#include "events_kqueue.h" +#include "events_fdtable.h" +#include "events.h" + +typedef struct EVENT_KERNEL { + ACL_EVENT event; + EVENT_BUFFER *event_buf; + int event_fdslots; + int event_fd; +#ifdef USE_FDMAP + ACL_FD_MAP *fdmap; +#endif +} EVENT_KERNEL; + +#include "stdlib/acl_meter_time.h" + +static void event_enable_read(ACL_EVENT *eventp, ACL_VSTREAM *stream, + int timeout, ACL_EVENT_NOTIFY_RDWR callback, void *context) +{ + const char *myname = "event_enable_read"; + EVENT_KERNEL *ev = (EVENT_KERNEL *) eventp; + ACL_EVENT_FDTABLE *fdp; + ACL_SOCKET sockfd; + char ebuf[256]; + int err = 0; + + sockfd = ACL_VSTREAM_SOCK(stream); + fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + if (fdp == NULL) { + fdp = event_fdtable_alloc(); + + fdp->flag = EVENT_FDTABLE_FLAG_READ | EVENT_FDTABLE_FLAG_EXPT; + fdp->stream = stream; + fdp->fdidx = eventp->fdcnt; + eventp->fdtabs[eventp->fdcnt] = fdp; + eventp->fdcnt++; + + stream->fdp = (void *) fdp; + stream->nrefer++; +#ifdef USE_FDMAP + acl_fdmap_add(ev->fdmap, sockfd, fdp); +#endif + EVENT_REG_ADD_READ(err, ev->event_fd, sockfd, fdp); + } else if (fdp->stream != stream) { + acl_msg_fatal("%s(%d), %s: corrupt stream", + __FILE__, __LINE__, myname); + } else if (fdp->fdidx < 0 || fdp->fdidx >= eventp->fdcnt || eventp->fdtabs[fdp->fdidx] != fdp) { + /* xxx: can this will happen ? */ + + fdp->flag = EVENT_FDTABLE_FLAG_READ | EVENT_FDTABLE_FLAG_EXPT; + fdp->fdidx = eventp->fdcnt; + eventp->fdtabs[eventp->fdcnt] = fdp; + eventp->fdcnt++; + + stream->nrefer++; +#ifdef USE_FDMAP + acl_fdmap_add(ev->fdmap, sockfd, fdp); +#endif + EVENT_REG_ADD_READ(err, ev->event_fd, sockfd, fdp); + } else if (fdp->flag & EVENT_FDTABLE_FLAG_WRITE) { + fdp->flag |= EVENT_FDTABLE_FLAG_READ; + + stream->nrefer++; +#if (ACL_EVENTS_KERNEL_STYLE == ACL_EVENTS_STYLE_KQUEUE) + EVENT_REG_ADD_READ(err, ev->event_fd, sockfd, fdp); +#else + EVENT_REG_MOD_RDWR(err, ev->event_fd, sockfd, fdp); +#endif + } + + if (err < 0) { + acl_msg_fatal("%s: %s(%s): %s, err(%d), fd(%d)", myname, + EVENT_REG_ADD_TEXT, + fdp->flag & EVENT_FDTABLE_FLAG_WRITE ? "write also" : "read only", + acl_last_strerror(ebuf, sizeof(ebuf)), err, sockfd); + } + + if (eventp->maxfd != ACL_SOCKET_INVALID && eventp->maxfd < sockfd) + eventp->maxfd = sockfd; + + if (fdp->r_callback != callback || fdp->r_context != context) { + fdp->r_callback = callback; + fdp->r_context = context; + } + + if (timeout > 0) { + fdp->r_timeout = timeout * 1000000; + fdp->r_ttl = eventp->event_present + fdp->r_timeout; + } else { + fdp->r_ttl = 0; + fdp->r_timeout = 0; + } +} + +static void event_enable_write(ACL_EVENT *eventp, ACL_VSTREAM *stream, + int timeout, ACL_EVENT_NOTIFY_RDWR callback, void *context) +{ + const char *myname = "event_enable_write"; + EVENT_KERNEL *ev = (EVENT_KERNEL *) eventp; + ACL_EVENT_FDTABLE *fdp; + ACL_SOCKET sockfd; + char ebuf[256]; + int err = 0; + + sockfd = ACL_VSTREAM_SOCK(stream); + fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + if (fdp == NULL) { + fdp = event_fdtable_alloc(); + + fdp->flag = EVENT_FDTABLE_FLAG_WRITE | EVENT_FDTABLE_FLAG_EXPT; + fdp->stream = stream; + fdp->fdidx = eventp->fdcnt; + eventp->fdtabs[eventp->fdcnt] = fdp; + eventp->fdcnt++; + + stream->fdp = (void *) fdp; + stream->nrefer++; +#ifdef USE_FDMAP + acl_fdmap_add(ev->fdmap, sockfd, fdp); +#endif + EVENT_REG_ADD_WRITE(err, ev->event_fd, sockfd, fdp); + } else if (fdp->stream != stream) { + acl_msg_fatal("%s(%d), %s: corrupt stream", + __FILE__, __LINE__, myname); + } else if (fdp->fdidx < 0 || fdp->fdidx >= eventp->fdcnt || eventp->fdtabs[fdp->fdidx] != fdp) { + /* xxx: can this will happen ? */ + + fdp->flag = EVENT_FDTABLE_FLAG_WRITE | EVENT_FDTABLE_FLAG_EXPT; + fdp->fdidx = eventp->fdcnt; + eventp->fdtabs[eventp->fdcnt] = fdp; + eventp->fdcnt++; + + stream->nrefer++; +#ifdef USE_FDMAP + acl_fdmap_add(ev->fdmap, sockfd, fdp); +#endif + EVENT_REG_ADD_WRITE(err, ev->event_fd, sockfd, fdp); + } else if (fdp->flag & EVENT_FDTABLE_FLAG_READ) { + fdp->flag |= EVENT_FDTABLE_FLAG_WRITE; + + stream->nrefer++; +#if (ACL_EVENTS_KERNEL_STYLE == ACL_EVENTS_STYLE_KQUEUE) + EVENT_REG_ADD_WRITE(err, ev->event_fd, sockfd, fdp); +#else + EVENT_REG_MOD_RDWR(err, ev->event_fd, sockfd, fdp); +#endif + } + + if (err < 0) { + acl_msg_fatal("%s: %s(%s): %s, err(%d), fd(%d)", myname, + EVENT_REG_ADD_TEXT, + fdp->flag & EVENT_FDTABLE_FLAG_READ ? "read also" : "write only", + acl_last_strerror(ebuf, sizeof(ebuf)), err, sockfd); + } + + + if (eventp->maxfd != ACL_SOCKET_INVALID && eventp->maxfd < sockfd) + eventp->maxfd = sockfd; + + if (fdp->w_callback != callback || fdp->w_context != context) { + fdp->w_callback = callback; + fdp->w_context = context; + } + + if (timeout > 0) { + fdp->w_timeout = timeout * 1000000; + fdp->w_ttl = eventp->event_present + fdp->w_timeout; + } else { + fdp->w_ttl = 0; + fdp->w_timeout = 0; + } +} + +/* event_disable_read - disable request for read events */ + +static void event_disable_read(ACL_EVENT *eventp, ACL_VSTREAM *stream) +{ + const char *myname = "event_disable_read"; + EVENT_KERNEL *ev = (EVENT_KERNEL *) eventp; + ACL_EVENT_FDTABLE *fdp; + ACL_SOCKET sockfd; + int flag; + char ebuf[256]; + int err = 0; + + sockfd = ACL_VSTREAM_SOCK(stream); + fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + if (fdp == NULL) { + acl_msg_warn("%s(%d): fdp null", myname, __LINE__); + return; + } + + if (fdp->fdidx < 0 || fdp->fdidx >= eventp->fdcnt) { + acl_msg_warn("%s(%d): sockfd(%d)'s fdidx invalid", + myname, __LINE__, sockfd); + return; + } + + if (!(fdp->flag & EVENT_FDTABLE_FLAG_READ)) { + acl_msg_warn("%s(%d): sockfd(%d) not be set", + myname, __LINE__, sockfd); + return; + } + + flag = fdp->flag; /* save the fdp's flag */ + + if (!(fdp->flag & EVENT_FDTABLE_FLAG_WRITE)) { + if (eventp->maxfd == sockfd) + eventp->maxfd = ACL_SOCKET_INVALID; + if (fdp->fdidx < --eventp->fdcnt) { + eventp->fdtabs[fdp->fdidx] = eventp->fdtabs[eventp->fdcnt]; + eventp->fdtabs[fdp->fdidx]->fdidx = fdp->fdidx; + } + if (fdp->fdidx_ready > 0 + && fdp->fdidx_ready < eventp->fdcnt_ready + && eventp->fdtabs_ready[fdp->fdidx_ready] == fdp) + { + eventp->fdtabs_ready[fdp->fdidx_ready] = NULL; + } +#ifdef USE_FDMAP + acl_fdmap_del(ev->fdmap, sockfd); +#endif + event_fdtable_free(fdp); + stream->fdp = NULL; +#ifdef EVENT_REG_DEL_BOTH + EVENT_REG_DEL_BOTH(err, ev->event_fd, sockfd); +#else + EVENT_REG_DEL_READ(err, ev->event_fd, sockfd); +#endif + } else { + fdp->flag &= ~EVENT_FDTABLE_FLAG_READ; + fdp->event_type &= ~ACL_EVENT_READ; + fdp->r_ttl = 0; + fdp->r_timeout = 0; + fdp->r_callback = NULL; +#if (ACL_EVENTS_KERNEL_STYLE == ACL_EVENTS_STYLE_KQUEUE) + EVENT_REG_DEL_READ(err, ev->event_fd, sockfd); +#else + EVENT_REG_MOD_WRITE(err, ev->event_fd, sockfd, fdp); +#endif + } + + if (err < 0) { + acl_msg_fatal("%s: %s: %s, %s, err(%d), fd(%d)", myname, + EVENT_REG_DEL_TEXT, + flag & EVENT_FDTABLE_FLAG_WRITE ? "write only" : "no read write", + acl_last_strerror(ebuf, (int) sizeof(ebuf)), err, sockfd); + } + + stream->nrefer--; +} + +/* event_disable_write - disable request for write events */ + +static void event_disable_write(ACL_EVENT *eventp, ACL_VSTREAM *stream) +{ + const char *myname = "event_disable_write"; + EVENT_KERNEL *ev = (EVENT_KERNEL *) eventp; + ACL_EVENT_FDTABLE *fdp; + ACL_SOCKET sockfd; + int flag; + char ebuf[256]; + int err = 0; + + sockfd = ACL_VSTREAM_SOCK(stream); + fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + if (fdp == NULL) { + acl_msg_warn("%s(%d): fdp null", myname, __LINE__); + return; + } + + if (fdp->fdidx < 0 || fdp->fdidx >= eventp->fdcnt) { + acl_msg_warn("%s(%d): sockfd(%d)'s fdidx(%d) invalid", + myname, __LINE__, sockfd, fdp->fdidx); + return; + } + + if (!(fdp->flag & EVENT_FDTABLE_FLAG_WRITE)) { + acl_msg_warn("%s(%d): sockfd(%d) not be set", + myname, __LINE__, sockfd); + return; + } + + flag = fdp->flag; /* save the fdp's flag */ + + if (!(fdp->flag & EVENT_FDTABLE_FLAG_READ)) { + if (eventp->maxfd == sockfd) + eventp->maxfd = ACL_SOCKET_INVALID; + if (fdp->fdidx < --eventp->fdcnt) { + eventp->fdtabs[fdp->fdidx] = eventp->fdtabs[eventp->fdcnt]; + eventp->fdtabs[fdp->fdidx]->fdidx = fdp->fdidx; + } + if (fdp->fdidx_ready > 0 + && fdp->fdidx_ready < eventp->fdcnt_ready + && eventp->fdtabs_ready[fdp->fdidx_ready] == fdp) + { + eventp->fdtabs_ready[fdp->fdidx_ready] = NULL; + } +#ifdef USE_FDMAP + acl_fdmap_del(ev->fdmap, sockfd); +#endif + event_fdtable_free(fdp); + stream->fdp = NULL; +#ifdef EVENT_REG_DEL_BOTH + EVENT_REG_DEL_BOTH(err, ev->event_fd, sockfd); +#else + EVENT_REG_DEL_WRITE(err, ev->event_fd, sockfd); +#endif + } else { + fdp->flag &= ~EVENT_FDTABLE_FLAG_WRITE; + fdp->event_type &= ~ACL_EVENT_WRITE; + fdp->w_ttl = 0; + fdp->w_timeout = 0; + fdp->w_callback = NULL; +#if (ACL_EVENTS_KERNEL_STYLE == ACL_EVENTS_STYLE_KQUEUE) + EVENT_REG_DEL_WRITE(err, ev->event_fd, sockfd); +#else + EVENT_REG_MOD_READ(err, ev->event_fd, sockfd, fdp); +#endif + } + + if (err < 0) { + acl_msg_fatal("%s: %s(%s): %s, err(%d), fd(%d)", myname, + EVENT_REG_DEL_TEXT, + flag & EVENT_FDTABLE_FLAG_READ ? "read only" : "no read write", + acl_last_strerror(ebuf, sizeof(ebuf)), err, sockfd); + } + + stream->nrefer--; +} + +/* event_disable_readwrite - disable request for read or write events */ + +static void event_disable_readwrite(ACL_EVENT *eventp, ACL_VSTREAM *stream) +{ + const char *myname = "event_disable_readwrite"; + EVENT_KERNEL *ev = (EVENT_KERNEL *) eventp; + ACL_EVENT_FDTABLE *fdp; + ACL_SOCKET sockfd; + char ebuf[256]; + int err = 0; + + sockfd = ACL_VSTREAM_SOCK(stream); + fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + if (fdp == NULL) { + /* + * acl_msg_warn("%s(%d): fdp null", myname, __LINE__); + */ + return; + } + + if (fdp->flag == 0 || fdp->fdidx < 0 || fdp->fdidx >= eventp->fdcnt) { + acl_msg_warn("%s(%d): sockfd(%d) no set, fdp no null", + myname, __LINE__, sockfd); + event_fdtable_free(fdp); + stream->fdp = NULL; + return; + } + + if (eventp->maxfd == sockfd) + eventp->maxfd = ACL_SOCKET_INVALID; + if (fdp->fdidx < --eventp->fdcnt) { + eventp->fdtabs[fdp->fdidx] = eventp->fdtabs[eventp->fdcnt]; + eventp->fdtabs[fdp->fdidx]->fdidx = fdp->fdidx; + } + +#ifdef EVENT_REG_DEL_BOTH + EVENT_REG_DEL_BOTH(err, ev->event_fd, sockfd); +#else + if (fdp->flag & EVENT_FDTABLE_FLAG_READ) { + EVENT_REG_DEL_READ(err, ev->event_fd, sockfd); + } + if (fdp->flag & EVENT_FDTABLE_FLAG_WRITE) { + EVENT_REG_DEL_WRITE(err, ev->event_fd, sockfd); + } +#endif + + if (fdp->flag & EVENT_FDTABLE_FLAG_READ) { + stream->nrefer--; + } + if (fdp->flag & EVENT_FDTABLE_FLAG_WRITE) { + stream->nrefer--; + } + + if (err < 0) { + acl_msg_fatal("%s: %s: %s", myname, EVENT_REG_DEL_TEXT, + acl_last_strerror(ebuf, sizeof(ebuf))); + } + +#ifdef USE_FDMAP + acl_fdmap_del(ev->fdmap, sockfd); +#endif + if (fdp->fdidx_ready > 0 + && fdp->fdidx_ready < eventp->fdcnt_ready + && eventp->fdtabs_ready[fdp->fdidx_ready] == fdp) + { + eventp->fdtabs_ready[fdp->fdidx_ready] = NULL; + } + event_fdtable_free(fdp); + stream->fdp = NULL; +} + +static int event_isrset(ACL_EVENT *eventp acl_unused, ACL_VSTREAM *stream) +{ + ACL_EVENT_FDTABLE *fdp; + + fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + if (fdp == NULL) { + return (0); + } + + return ((fdp->flag & EVENT_FDTABLE_FLAG_READ)); +} + +static int event_iswset(ACL_EVENT *eventp acl_unused, ACL_VSTREAM *stream) +{ + ACL_EVENT_FDTABLE *fdp; + + fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + if (fdp == NULL) { + return (0); + } + + return ((fdp->flag & EVENT_FDTABLE_FLAG_WRITE)); + +} + +static int event_isxset(ACL_EVENT *eventp acl_unused, ACL_VSTREAM *stream) +{ + ACL_EVENT_FDTABLE *fdp; + + fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + if (fdp == NULL) { + return (0); + } + + return ((fdp->flag & EVENT_FDTABLE_FLAG_EXPT)); +} + +static void event_loop(ACL_EVENT *eventp) +{ + const char *myname = "event_loop"; + EVENT_KERNEL *ev = (EVENT_KERNEL *) eventp; + ACL_EVENT_NOTIFY_FN worker_fn; + void *worker_arg; + ACL_EVENT_TIMER *timer; + int delay, n, nready; + ACL_EVENT_FDTABLE *fdp; + EVENT_BUFFER *bp; + + delay = eventp->delay_sec * 1000 + eventp->delay_usec / 1000; + if (delay <= 0) + delay = 100; /* 100 milliseconds at least */ + + SET_TIME(eventp->event_present); + + /* + * Find out when the next timer would go off. Timer requests are sorted. + * If any timer is scheduled, adjust the delay appropriately. + */ + if ((timer = ACL_FIRST_TIMER(&eventp->timer_head)) != 0) { + n = (int) (timer->when - eventp->event_present + 1000000 - 1) / 1000000; + if (n <= 0) { + delay = 0; + } else if (delay > eventp->delay_sec) { + delay = n * 1000 + eventp->delay_usec / 1000; + } + } + + if (event_prepare(eventp) == 0) { + if (eventp->fdcnt_ready == 0) { + sleep(1); + } + goto TAG_DONE; + } + + if (eventp->fdcnt_ready > 0) + delay = 0; + + EVENT_BUFFER_READ(nready, + ev->event_fd, + ev->event_buf, + ev->event_fdslots, + delay); + + if (eventp->nested++ > 0) + acl_msg_fatal("%s(%d): recursive call", myname, __LINE__); + if (nready < 0) { + if (acl_last_error() != ACL_EINTR) { + char ebuf[256]; + acl_msg_fatal("%s(%d), %s: select: %s", + __FILE__, __LINE__, myname, + acl_last_strerror(ebuf, sizeof(ebuf))); + } + goto TAG_DONE; + } else if (nready == 0) + goto TAG_DONE; + + for (bp = ev->event_buf; bp < ev->event_buf + nready; bp++) { +#ifdef USE_FDMAP + ACL_SOCKET sockfd; + + sockfd = EVENT_GET_FD(bp); + fdp = acl_fdmap_ctx(ev->fdmap, sockfd); + if (fdp == NULL || fdp->stream == NULL) + continue; + if (sockfd != ACL_VSTREAM_SOCK(fdp->stream)) + acl_msg_fatal("%s(%d): sockfd(%d) != %d", + myname, __LINE__, sockfd, ACL_VSTREAM_SOCK(fdp->stream)); +#else + fdp = (ACL_EVENT_FDTABLE *) EVENT_GET_CTX(bp); + if (fdp == NULL || fdp->stream == NULL) + continue; +#endif + + if ((fdp->event_type & (ACL_EVENT_XCPT | ACL_EVENT_RW_TIMEOUT))) + continue; + + if ((fdp->flag & EVENT_FDTABLE_FLAG_READ) && EVENT_TEST_READ(bp)) { + fdp->stream->sys_read_ready = 1; + if ((fdp->event_type & (ACL_EVENT_READ | ACL_EVENT_WRITE)) == 0) + { + fdp->event_type |= ACL_EVENT_READ; + fdp->fdidx_ready = eventp->fdcnt_ready; + eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp; + } + } + + if ((fdp->flag & EVENT_FDTABLE_FLAG_WRITE) && EVENT_TEST_WRITE(bp)) { + if ((fdp->event_type & (ACL_EVENT_READ | ACL_EVENT_WRITE)) == 0) + { + fdp->event_type |= ACL_EVENT_WRITE; + fdp->fdidx_ready = eventp->fdcnt_ready; + eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp; + } + } +#ifdef EVENT_TEST_ERROR + if (EVENT_TEST_ERROR(bp)) { + if ((fdp->event_type & (ACL_EVENT_READ | ACL_EVENT_WRITE)) == 0) + { + fdp->event_type |= ACL_EVENT_XCPT; + fdp->fdidx_ready = eventp->fdcnt_ready; + eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp; + } + } +#endif + } + +TAG_DONE: + + /* + * Deliver timer events. Requests are sorted: we can stop when we reach + * the future or the list end. Allow the application to update the timer + * queue while it is being called back. To this end, we repeatedly pop + * the first request off the timer queue before delivering the event to + * the application. + */ + SET_TIME(eventp->event_present); + while ((timer = ACL_FIRST_TIMER(&eventp->timer_head)) != 0) { + if (timer->when > eventp->event_present) + break; + worker_fn = timer->callback; + worker_arg = timer->context; + + /* 如果定时器的时间间隔 > 0 且允许定时器被循环调用,则再重设定时器 */ + if (timer->delay > 0 && timer->keep) { + timer->ncount++; + eventp->timer_request(eventp, timer->callback, + timer->context, timer->delay, timer->keep); + } else { + acl_ring_detach(&timer->ring); /* first this */ + timer->nrefer--; + if (timer->nrefer != 0) + acl_msg_fatal("%s(%d): nrefer(%d) != 0", + myname, __LINE__, timer->nrefer); + acl_myfree(timer); + } + worker_fn(ACL_EVENT_TIME, worker_arg); + } + + event_fire(eventp); + eventp->nested--; +} + +static void event_free(ACL_EVENT *eventp) +{ + const char *myname = "event_free"; + EVENT_KERNEL *ev = (EVENT_KERNEL *) eventp; + + if (eventp == NULL) + acl_msg_fatal("%s, %s(%d): eventp null", __FILE__, myname, __LINE__); + +#ifdef USE_FDMAP + acl_fdmap_free(ev->fdmap); +#endif + acl_myfree(ev->event_buf); + close(ev->event_fd); + acl_myfree(ev); +} + +ACL_EVENT *event_new_kernel2(int fdsize acl_unused) +{ + ACL_EVENT *eventp; + EVENT_KERNEL *ev; + static int __default_max_events = 1000; + + eventp = event_alloc(sizeof(EVENT_KERNEL)); + + snprintf(eventp->name, sizeof(eventp->name), "events - %s", EVENT_NAME); + eventp->event_mode = ACL_EVENT_KERNEL2; + eventp->use_thread = 0; + eventp->loop_fn = event_loop; + eventp->free_fn = event_free; + eventp->enable_read_fn = event_enable_read; + eventp->enable_write_fn = event_enable_write; + eventp->enable_listen_fn = event_enable_read; + eventp->disable_read_fn = event_disable_read; + eventp->disable_write_fn = event_disable_write; + eventp->disable_readwrite_fn = event_disable_readwrite; + eventp->isrset_fn = event_isrset; + eventp->iswset_fn = event_iswset; + eventp->isxset_fn = event_isxset; + eventp->timer_request = event_timer_request; + eventp->timer_cancel = event_timer_cancel; + eventp->timer_keep = event_timer_keep; + eventp->timer_ifkeep = event_timer_ifkeep; + + ev = (EVENT_KERNEL*) eventp; + EVENT_REG_INIT_HANDLE(ev->event_fd, fdsize); + ev->event_fdslots = __default_max_events; + ev->event_buf = (EVENT_BUFFER *) acl_mycalloc(ev->event_fdslots + 1, sizeof(EVENT_BUFFER)); +#ifdef USE_FDMAP + ev->fdmap = acl_fdmap_create(fdsize); +#endif + return (eventp); +} +#endif /* ACL_EVENTS_KERNEL_STYLE */ diff --git a/lib_acl/src/event/events_kernel3.c b/lib_acl/src/event/events_kernel3.c new file mode 100644 index 000000000..2dac12f93 --- /dev/null +++ b/lib_acl/src/event/events_kernel3.c @@ -0,0 +1,859 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include +#include +#include + +#if 0 +#define NDEBUG +#endif + +#include + +#ifdef ACL_UNIX +#include +#endif + +#include "stdlib/acl_sys_patch.h" +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_mystring.h" +#include "stdlib/acl_msg.h" +#include "stdlib/acl_debug.h" +#include "stdlib/acl_vstream.h" +#include "stdlib/acl_fifo.h" +#include "stdlib/acl_meter_time.h" /* just for performance test */ +#include "event/acl_events.h" + +#endif + +#include "events_define.h" + +#ifdef ACL_EVENTS_KERNEL_STYLE + +#include "events_epoll.h" +#include "events_devpoll.h" +#include "events_kqueue.h" +#include "events_fdtable.h" +#include "events.h" + +typedef struct EVENT_KERNEL { + ACL_EVENT event; + EVENT_BUFFER *event_buf; + ACL_RING fdp_delay_list; + int event_fdslots; + int event_fd; +#ifdef USE_FDMAP + ACL_FD_MAP *fdmap; +#endif +} EVENT_KERNEL; + +/** + * 对于 epoll/kqueue/devpoll 这些内核级操作,当描述符关闭时该描述符将 + * 会自动从内核监控中去除 + */ +#undef EVENT_AUTO_DEL + +#include "stdlib/acl_meter_time.h" + +static void stream_on_close(ACL_VSTREAM *stream, void *arg) +{ + const char *myname = "stream_on_close"; + EVENT_KERNEL *ev = (EVENT_KERNEL*) arg; + ACL_EVENT_FDTABLE *fdp = (ACL_EVENT_FDTABLE*) stream->fdp; + ACL_SOCKET sockfd = ACL_VSTREAM_SOCK(stream); + int err = 0, ret = 0; + + if (fdp == NULL) + acl_msg_fatal("%s(%d): fdp null, sockfd(%d)", + myname, __LINE__, sockfd); + +#ifdef EVENT_REG_DEL_BOTH + if ((fdp->flag & EVENT_FDTABLE_FLAG_READ) + || (fdp->flag & EVENT_FDTABLE_FLAG_WRITE)) + { +# ifndef EVENT_AUTO_DEL + EVENT_REG_DEL_BOTH(err, ev->event_fd, sockfd); + ret = 1; +# else + ret = 2; +# endif + } +#else + if ((fdp->flag & EVENT_FDTABLE_FLAG_READ) + && (fdp->flag & EVENT_FDTABLE_FLAG_WRITE)) + { +# ifndef EVENT_AUTO_DEL + EVENT_REG_DEL_READ(err, ev->event_fd, sockfd); + EVENT_REG_DEL_WRITE(err, ev->event_fd, sockfd); + ret = 3; +# else + ret = 4; +# endif + } else if ((fdp->flag & EVENT_FDTABLE_FLAG_READ)) { +# ifndef EVENT_AUTO_DEL + EVENT_REG_DEL_READ(err, ev->event_fd, sockfd); + ret = 5; +# else + ret = 6; +# endif + } else if ((fdp->flag & EVENT_FDTABLE_FLAG_WRITE)) { +# ifndef EVENT_AUTO_DEL + EVENT_REG_DEL_WRITE(err, ev->event_fd, sockfd); +# else + ret = 7; +# endif + ret = 8; + } +#endif + + if (err < 0) { + acl_msg_fatal("%s: %s: %s, err(%d), fd(%d), ret(%d)", + myname, EVENT_REG_DEL_TEXT, acl_last_serror(), + err, sockfd, ret); + } + + if (ret) { + acl_ring_detach(&fdp->delay_entry); +#ifdef USE_FDMAP + acl_fdmap_del(ev->fdmap, sockfd); +#endif + } + + if (ev->event.maxfd == ACL_VSTREAM_SOCK(fdp->stream)) + ev->event.maxfd = ACL_SOCKET_INVALID; + if (fdp->fdidx >= 0 && fdp->fdidx < --ev->event.fdcnt) { + ev->event.fdtabs[fdp->fdidx] = ev->event.fdtabs[ev->event.fdcnt]; + ev->event.fdtabs[fdp->fdidx]->fdidx = fdp->fdidx; + } + fdp->fdidx = -1; + + if (fdp->fdidx_ready >= 0 + && fdp->fdidx_ready < ev->event.fdcnt_ready + && ev->event.fdtabs_ready[fdp->fdidx_ready] == fdp) + { + ev->event.fdtabs_ready[fdp->fdidx_ready] = NULL; + } + fdp->fdidx_ready = -1; + event_fdtable_free(fdp); +} + +static void event_enable_read(ACL_EVENT *eventp, ACL_VSTREAM *stream, + int timeout, ACL_EVENT_NOTIFY_RDWR callback, void *context) +{ + ACL_EVENT_FDTABLE *fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + ACL_SOCKET sockfd = ACL_VSTREAM_SOCK(stream); + + if (fdp == NULL) { + fdp = event_fdtable_alloc(); + + fdp->flag = EVENT_FDTABLE_FLAG_ADD_READ | EVENT_FDTABLE_FLAG_EXPT; + fdp->stream = stream; + acl_ring_init(&fdp->delay_entry); + stream->fdp = (void *) fdp; + /* 添加流关闭时的回调函数 */ + acl_vstream_add_close_handle(stream, stream_on_close, eventp); +#ifdef USE_FDMAP + acl_fdmap_add(ev->fdmap, sockfd, fdp); +#endif + } else if ((fdp->flag & EVENT_FDTABLE_FLAG_ADD_READ)) { + goto END; + } else if ((fdp->flag & EVENT_FDTABLE_FLAG_DEL_READ)) { + + /* 停止禁止读监听过程 */ + + acl_assert((fdp->flag & EVENT_FDTABLE_FLAG_READ)); + + /* 重新启用读监听过程, 因为之前的过程是正在拆除读监听过程但 + * 还没有正式拆除,所以只需要清除拆除标志位即可 + */ + + fdp->flag &= ~EVENT_FDTABLE_FLAG_DEL_READ; + + if (!(fdp->flag & EVENT_FDTABLE_FLAG_DEL_WRITE)) { + acl_ring_detach(&fdp->delay_entry); + } + } else if (!(fdp->flag & EVENT_FDTABLE_FLAG_READ)) { + fdp->flag |= EVENT_FDTABLE_FLAG_ADD_READ; + } + +END: + if (fdp->fdidx == -1) { + fdp->fdidx = eventp->fdcnt; + eventp->fdtabs[eventp->fdcnt++] = fdp; + } + if (eventp->maxfd != ACL_SOCKET_INVALID && eventp->maxfd < sockfd) + eventp->maxfd = sockfd; + + if (fdp->r_callback != callback || fdp->r_context != context) { + fdp->r_callback = callback; + fdp->r_context = context; + } + + if (timeout > 0) { + fdp->r_timeout = timeout * 1000000; + fdp->r_ttl = eventp->event_present + fdp->r_timeout; + } else { + fdp->r_ttl = 0; + fdp->r_timeout = 0; + } +} + +static void event_enable_write(ACL_EVENT *eventp, ACL_VSTREAM *stream, + int timeout, ACL_EVENT_NOTIFY_RDWR callback, void *context) +{ + ACL_EVENT_FDTABLE *fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + ACL_SOCKET sockfd = ACL_VSTREAM_SOCK(stream); + + if (fdp == NULL) { + fdp = event_fdtable_alloc(); + + fdp->flag = EVENT_FDTABLE_FLAG_ADD_WRITE | EVENT_FDTABLE_FLAG_EXPT; + fdp->stream = stream; + acl_ring_init(&fdp->delay_entry); + stream->fdp = (void *) fdp; + /* 添加流关闭时的回调函数 */ + acl_vstream_add_close_handle(stream, stream_on_close, eventp); +#ifdef USE_FDMAP + acl_fdmap_add(ev->fdmap, sockfd, fdp); +#endif + } else if ((fdp->flag & EVENT_FDTABLE_FLAG_ADD_WRITE)) { + goto END; + } else if ((fdp->flag & EVENT_FDTABLE_FLAG_DEL_WRITE)) { + acl_assert((fdp->flag & EVENT_FDTABLE_FLAG_WRITE)); + + fdp->flag &= ~EVENT_FDTABLE_FLAG_DEL_WRITE; + + if (!(fdp->flag & EVENT_FDTABLE_FLAG_DEL_READ)) { + acl_ring_detach(&fdp->delay_entry); + } + } else if (!(fdp->flag & EVENT_FDTABLE_FLAG_WRITE)) { + fdp->flag |= EVENT_FDTABLE_FLAG_ADD_WRITE; + } + +END: + if (fdp->fdidx == -1) { + fdp->fdidx = eventp->fdcnt; + eventp->fdtabs[eventp->fdcnt++] = fdp; + } + + if (eventp->maxfd != ACL_SOCKET_INVALID && eventp->maxfd < sockfd) + eventp->maxfd = sockfd; + + if (fdp->w_callback != callback || fdp->w_context != context) { + fdp->w_callback = callback; + fdp->w_context = context; + } + + if (timeout > 0) { + fdp->w_timeout = timeout * 100000; + fdp->w_ttl = eventp->event_present + fdp->w_timeout; + } else { + fdp->w_ttl = 0; + fdp->w_timeout = 0; + } +} + +/* event_disable_read - disable request for read events */ + +static void event_disable_read(ACL_EVENT *eventp, ACL_VSTREAM *stream) +{ + const char *myname = "event_disable_read"; + EVENT_KERNEL *ev = (EVENT_KERNEL *) eventp; + ACL_EVENT_FDTABLE *fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + + if (fdp == NULL) { + acl_msg_warn("%s(%d): fdp null", myname, __LINE__); + return; + } + if (fdp->fdidx < 0 || fdp->fdidx >= eventp->fdcnt) { + acl_msg_warn("%s(%d): sockfd(%d)'s fdidx(%d) invalid, fdcnt: %d", + myname, __LINE__, ACL_VSTREAM_SOCK(stream), + fdp->fdidx, eventp->fdcnt); + return; + } + if ((fdp->flag & EVENT_FDTABLE_FLAG_DEL_READ)) { + return; + } + if ((fdp->flag & EVENT_FDTABLE_FLAG_ADD_READ)) { + fdp->flag &= ~EVENT_FDTABLE_FLAG_ADD_READ; + goto DEL_READ_TAG; + } + + if (!(fdp->flag & EVENT_FDTABLE_FLAG_READ)) { + acl_msg_warn("%s(%d): sockfd(%d) not be set", + myname, __LINE__, ACL_VSTREAM_SOCK(stream)); + return; + } + fdp->flag |= EVENT_FDTABLE_FLAG_DEL_READ; + if (!(fdp->flag & EVENT_FDTABLE_FLAG_DEL_WRITE)) { + acl_ring_append(&ev->fdp_delay_list, &fdp->delay_entry); + } + +DEL_READ_TAG: + + fdp->r_ttl = 0; + fdp->r_timeout = 0; + fdp->r_callback = NULL; + fdp->event_type &= ~ACL_EVENT_READ; + + if ((fdp->flag & EVENT_FDTABLE_FLAG_WRITE)) { + return; + } + + if (eventp->maxfd == ACL_VSTREAM_SOCK(fdp->stream)) + eventp->maxfd = ACL_SOCKET_INVALID; + + if (fdp->fdidx < --eventp->fdcnt) { + eventp->fdtabs[fdp->fdidx] = eventp->fdtabs[eventp->fdcnt]; + eventp->fdtabs[fdp->fdidx]->fdidx = fdp->fdidx; + } + fdp->fdidx = -1; + + if (fdp->fdidx_ready >= 0 + && fdp->fdidx_ready < eventp->fdcnt_ready + && eventp->fdtabs_ready[fdp->fdidx_ready] == fdp) + { + eventp->fdtabs_ready[fdp->fdidx_ready] = NULL; + } + fdp->fdidx_ready = -1; +} + +/* event_disable_write - disable request for write events */ + +static void event_disable_write(ACL_EVENT *eventp, ACL_VSTREAM *stream) +{ + const char *myname = "event_disable_write"; + EVENT_KERNEL *ev = (EVENT_KERNEL *) eventp; + ACL_EVENT_FDTABLE *fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + + if (fdp == NULL) { + acl_msg_warn("%s(%d): fdp null", myname, __LINE__); + return; + } + if (fdp->fdidx < 0 || fdp->fdidx >= eventp->fdcnt) { + acl_msg_warn("%s(%d): sockfd(%d)'s fdidx(%d) invalid", + myname, __LINE__, ACL_VSTREAM_SOCK(stream), fdp->fdidx); + return; + } + if ((fdp->flag & EVENT_FDTABLE_FLAG_DEL_WRITE)) { + return; + } + if ((fdp->flag & EVENT_FDTABLE_FLAG_ADD_WRITE)) { + fdp->flag &= ~EVENT_FDTABLE_FLAG_ADD_WRITE; + goto DEL_WRITE_TAG; + } + if (!(fdp->flag & EVENT_FDTABLE_FLAG_WRITE)) { + acl_msg_warn("%s(%d): sockfd(%d) not be set", + myname, __LINE__, ACL_VSTREAM_SOCK(stream)); + return; + } + + fdp->flag |= EVENT_FDTABLE_FLAG_DEL_WRITE; + if (!(fdp->flag & EVENT_FDTABLE_FLAG_DEL_READ)) { + acl_ring_append(&ev->fdp_delay_list, &fdp->delay_entry); + } + +DEL_WRITE_TAG: + + fdp->w_ttl = 0; + fdp->w_timeout = 0; + fdp->w_callback = NULL; + fdp->event_type &= ~ACL_EVENT_WRITE; + + if ((fdp->flag & EVENT_FDTABLE_FLAG_READ)) { + return; + } + + if (eventp->maxfd == ACL_VSTREAM_SOCK(stream)) + eventp->maxfd = ACL_SOCKET_INVALID; + + if (fdp->fdidx < --eventp->fdcnt) { + eventp->fdtabs[fdp->fdidx] = eventp->fdtabs[eventp->fdcnt]; + eventp->fdtabs[fdp->fdidx]->fdidx = fdp->fdidx; + } + fdp->fdidx = -1; + + if (fdp->fdidx_ready >= 0 + && fdp->fdidx_ready < eventp->fdcnt_ready + && eventp->fdtabs_ready[fdp->fdidx_ready] == fdp) + { + eventp->fdtabs_ready[fdp->fdidx_ready] = NULL; + } + fdp->fdidx_ready = -1; +} + +/* event_disable_readwrite - disable request for read or write events */ + +static void event_disable_readwrite(ACL_EVENT *eventp, ACL_VSTREAM *stream) +{ + const char *myname = "event_disable_readwrite"; + EVENT_KERNEL *ev = (EVENT_KERNEL *) eventp; + ACL_SOCKET sockfd = ACL_VSTREAM_SOCK(stream); + ACL_EVENT_FDTABLE *fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + int err = 0; + + if (fdp == NULL) { + return; + } + + if (fdp->flag == 0 || fdp->fdidx < 0 || fdp->fdidx >= eventp->fdcnt) { + acl_msg_warn("%s(%d): sockfd(%d) no set, fdp no null", + myname, __LINE__, sockfd); + event_fdtable_free(fdp); + stream->fdp = NULL; + return; + } + + if (eventp->maxfd == sockfd) + eventp->maxfd = ACL_SOCKET_INVALID; + if (fdp->fdidx < --eventp->fdcnt) { + eventp->fdtabs[fdp->fdidx] = eventp->fdtabs[eventp->fdcnt]; + eventp->fdtabs[fdp->fdidx]->fdidx = fdp->fdidx; + } + fdp->fdidx = -1; + +#ifdef EVENT_REG_DEL_BOTH + EVENT_REG_DEL_BOTH(err, ev->event_fd, sockfd); +#else + if (fdp->flag & EVENT_FDTABLE_FLAG_READ) { + EVENT_REG_DEL_READ(err, ev->event_fd, sockfd); + } + if (fdp->flag & EVENT_FDTABLE_FLAG_WRITE) { + EVENT_REG_DEL_WRITE(err, ev->event_fd, sockfd); + } +#endif + + if (err < 0) { + acl_msg_fatal("%s: %s: %s", myname, EVENT_REG_DEL_TEXT, + acl_last_serror()); + } + +#ifdef USE_FDMAP + acl_fdmap_del(ev->fdmap, sockfd); +#endif + if (fdp->fdidx_ready >= 0 + && fdp->fdidx_ready < eventp->fdcnt_ready + && eventp->fdtabs_ready[fdp->fdidx_ready] == fdp) + { + eventp->fdtabs_ready[fdp->fdidx_ready] = NULL; + } + fdp->fdidx_ready = -1; + event_fdtable_free(fdp); + stream->fdp = NULL; +} + +static void enable_read(EVENT_KERNEL *ev, ACL_EVENT_FDTABLE *fdp) +{ + const char *myname = "enable_read"; + ACL_SOCKET sockfd = ACL_VSTREAM_SOCK(fdp->stream); + int err; + + fdp->flag &= ~EVENT_FDTABLE_FLAG_ADD_READ; + fdp->flag |= EVENT_FDTABLE_FLAG_READ; + + if ((fdp->flag & EVENT_FDTABLE_FLAG_WRITE)) { +#if (ACL_EVENTS_KERNEL_STYLE == ACL_EVENTS_STYLE_KQUEUE) + EVENT_REG_ADD_READ(err, ev->event_fd, sockfd, fdp); +#else + EVENT_REG_MOD_RDWR(err, ev->event_fd, sockfd, fdp); +#endif + } else { + EVENT_REG_ADD_READ(err, ev->event_fd, sockfd, fdp); + } + if (err < 0) { + acl_msg_fatal("%s: %s: %s, err(%d), fd(%d)", + myname, EVENT_REG_ADD_TEXT, + acl_last_serror(), err, sockfd); + } +} + +static void enable_write(EVENT_KERNEL *ev, ACL_EVENT_FDTABLE *fdp) +{ + const char *myname = "enable_write"; + ACL_SOCKET sockfd = ACL_VSTREAM_SOCK(fdp->stream); + int err; + + fdp->flag &= ~EVENT_FDTABLE_FLAG_ADD_WRITE; + fdp->flag |= EVENT_FDTABLE_FLAG_WRITE; + + if ((fdp->flag & EVENT_FDTABLE_FLAG_READ)) { +#if (ACL_EVENTS_KERNEL_STYLE == ACL_EVENTS_STYLE_KQUEUE) + EVENT_REG_ADD_WRITE(err, ev->event_fd, sockfd, fdp); +#else + EVENT_REG_MOD_RDWR(err, ev->event_fd, sockfd, fdp); +#endif + } else { + EVENT_REG_ADD_WRITE(err, ev->event_fd, sockfd, fdp); + } + + if (err < 0) { + acl_msg_fatal("%s: %s: %s, err(%d), fd(%d)", + myname, EVENT_REG_ADD_TEXT, + acl_last_serror(), err, sockfd); + } +} + +static int disable_read(EVENT_KERNEL *ev, ACL_EVENT_FDTABLE *fdp) +{ + const char *myname = "disable_read"; + ACL_VSTREAM *stream = fdp->stream; + ACL_SOCKET sockfd = ACL_VSTREAM_SOCK(stream); + int err, ret = 0; + + fdp->flag &= ~EVENT_FDTABLE_FLAG_DEL_READ; + fdp->flag &= ~EVENT_FDTABLE_FLAG_READ; + fdp->event_type &= ~ACL_EVENT_READ; + + if ((fdp->flag & EVENT_FDTABLE_FLAG_WRITE)) { +#if (ACL_EVENTS_KERNEL_STYLE == ACL_EVENTS_STYLE_KQUEUE) + EVENT_REG_DEL_READ(err, ev->event_fd, sockfd); +#else + EVENT_REG_MOD_WRITE(err, ev->event_fd, sockfd, fdp); +#endif + } else { +#ifdef EVENT_REG_DEL_BOTH + EVENT_REG_DEL_BOTH(err, ev->event_fd, sockfd); +#else + EVENT_REG_DEL_READ(err, ev->event_fd, sockfd); +#endif +#ifdef USE_FDMAP + acl_fdmap_del(ev->fdmap, sockfd); +#endif + ret = 1; + } + if (err < 0) { + acl_msg_fatal("%s: %s: %s, err(%d), fd(%d), ret(%d)", + myname, EVENT_REG_DEL_TEXT, acl_last_serror(), + err, sockfd, ret); + } + return (ret); +} + +static int disable_write(EVENT_KERNEL *ev, ACL_EVENT_FDTABLE *fdp) +{ + const char *myname = "disable_write"; + ACL_VSTREAM *stream = fdp->stream; + ACL_SOCKET sockfd = ACL_VSTREAM_SOCK(stream); + int err, ret = 0; + + fdp->flag &= ~EVENT_FDTABLE_FLAG_DEL_WRITE; + fdp->flag &= ~EVENT_FDTABLE_FLAG_WRITE; + fdp->event_type &= ~ACL_EVENT_WRITE; + + if ((fdp->flag & EVENT_FDTABLE_FLAG_READ)) { +#if (ACL_EVENTS_KERNEL_STYLE == ACL_EVENTS_STYLE_KQUEUE) + EVENT_REG_DEL_WRITE(err, ev->event_fd, sockfd); +#else + EVENT_REG_MOD_READ(err, ev->event_fd, sockfd, fdp); +#endif + } else { +#ifdef USE_FDMAP + acl_fdmap_del(ev->fdmap, sockfd); +#endif +#ifdef EVENT_REG_DEL_BOTH + EVENT_REG_DEL_BOTH(err, ev->event_fd, sockfd); +#else + EVENT_REG_DEL_WRITE(err, ev->event_fd, sockfd); +#endif + ret = 1; + } + if (err < 0) { + acl_msg_fatal("%s: %s: %s, err(%d), fd(%d), ret(%d)", + myname, EVENT_REG_DEL_TEXT, acl_last_serror(), + err, sockfd, ret); + } + return (ret); +} + +static int event_set_all(ACL_EVENT *eventp) +{ + EVENT_KERNEL *ev = (EVENT_KERNEL *) eventp; + ACL_EVENT_FDTABLE *fdp; + int i, nwait = 0; + + /* 优先处理添加读/写监控任务, 这样可以把中间的 ADD 状态转换成正式状态 */ + + eventp->fdcnt_ready = 0; + + for (i = 0; i < eventp->fdcnt; i++) { + fdp = eventp->fdtabs[i]; + acl_assert (fdp->stream); + + if ((fdp->flag & EVENT_FDTABLE_FLAG_ADD_READ)) { + enable_read(ev, fdp); + } + if ((fdp->flag & EVENT_FDTABLE_FLAG_ADD_WRITE)) { + enable_write(ev, fdp); + } + if ((fdp->stream->flag & ACL_VSTREAM_FLAG_BAD) != 0) { + fdp->stream->flag &= ~ACL_VSTREAM_FLAG_BAD; + fdp->event_type |= ACL_EVENT_XCPT; + fdp->fdidx_ready = eventp->fdcnt_ready; + eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp; + } else if ((fdp->flag & EVENT_FDTABLE_FLAG_READ)) { + if (ACL_VSTREAM_BFRD_CNT(fdp->stream) > 0) { + fdp->stream->sys_read_ready = 0; + fdp->event_type |= ACL_EVENT_READ; + fdp->fdidx_ready = eventp->fdcnt_ready; + eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp; + } else if (fdp->r_ttl > 0 && eventp->event_present > fdp->r_ttl) { + fdp->event_type |= ACL_EVENT_RW_TIMEOUT; + fdp->fdidx_ready = eventp->fdcnt_ready; + eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp; + } else + nwait++; + } else if ((fdp->flag & EVENT_FDTABLE_FLAG_WRITE)) { + if (fdp->w_ttl > 0 && eventp->event_present > fdp->w_ttl) { + fdp->event_type |= ACL_EVENT_RW_TIMEOUT; + fdp->fdidx_ready = eventp->fdcnt_ready; + eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp; + } else + nwait++; + } else + nwait++; + } + + /* 处理 DEL 类型的任务项 */ + + while (1) { + ACL_RING *r = acl_ring_pop_head(&ev->fdp_delay_list); + if (r == NULL) + break; + fdp = acl_ring_to_appl(r, ACL_EVENT_FDTABLE, delay_entry); + if ((fdp->flag & EVENT_FDTABLE_FLAG_DEL_READ)) { + disable_read(ev, fdp); + } + if ((fdp->flag & EVENT_FDTABLE_FLAG_DEL_WRITE)) { + disable_write(ev, fdp); + } + } + + return (nwait); +} + +static void event_loop(ACL_EVENT *eventp) +{ + const char *myname = "event_loop"; + EVENT_KERNEL *ev = (EVENT_KERNEL *) eventp; + ACL_EVENT_NOTIFY_FN worker_fn; + void *worker_arg; + ACL_EVENT_TIMER *timer; + int delay, n, nready; + ACL_EVENT_FDTABLE *fdp; + EVENT_BUFFER *bp; + + delay = eventp->delay_sec * 1000 + eventp->delay_usec / 1000; + if (delay <= 0) + delay = 100; /* 100 milliseconds at least */ + + SET_TIME(eventp->event_present); + + /* + * Find out when the next timer would go off. Timer requests are sorted. + * If any timer is scheduled, adjust the delay appropriately. + */ + if ((timer = ACL_FIRST_TIMER(&eventp->timer_head)) != 0) { + n = (int) (timer->when - eventp->event_present + 1000000 - 1) / 1000000; + if (n <= 0) { + delay = 0; + } else if (delay > eventp->delay_sec) { + delay = n * 1000 + eventp->delay_usec / 1000; + } + } + + if (event_set_all(eventp) == 0) { + if (eventp->fdcnt_ready == 0) { + sleep(1); + } + nready = 0; + goto TAG_DONE; + } + + if (eventp->fdcnt_ready > 0) { + delay = 0; + } + + EVENT_BUFFER_READ(nready, + ev->event_fd, + ev->event_buf, + ev->event_fdslots, + delay); + + if (eventp->nested++ > 0) + acl_msg_fatal("%s(%d): recursive call", myname, __LINE__); + if (nready < 0) { + if (acl_last_error() != ACL_EINTR) { + char ebuf[256]; + acl_msg_fatal("%s(%d), %s: select: %s", + __FILE__, __LINE__, myname, + acl_last_strerror(ebuf, sizeof(ebuf))); + } + goto TAG_DONE; + } else if (nready == 0) + goto TAG_DONE; + + for (bp = ev->event_buf; bp < ev->event_buf + nready; bp++) { +#ifdef USE_FDMAP + ACL_SOCKET sockfd; + + sockfd = EVENT_GET_FD(bp); + fdp = acl_fdmap_ctx(ev->fdmap, sockfd); + if (fdp == NULL || fdp->stream == NULL) + continue; + if (sockfd != ACL_VSTREAM_SOCK(fdp->stream)) + acl_msg_fatal("%s(%d): sockfd(%d) != %d", myname, + __LINE__, sockfd, ACL_VSTREAM_SOCK(fdp->stream)); +#else + fdp = (ACL_EVENT_FDTABLE *) EVENT_GET_CTX(bp); + if (fdp == NULL || fdp->stream == NULL) { + continue; + } +#endif + + if ((fdp->event_type & (ACL_EVENT_READ | ACL_EVENT_WRITE)) == 0) + continue; + + if ((fdp->flag & EVENT_FDTABLE_FLAG_READ) && EVENT_TEST_READ(bp)) { + fdp->stream->sys_read_ready = 1; + if ((fdp->event_type & (ACL_EVENT_READ | ACL_EVENT_WRITE)) == 0) + { + fdp->event_type |= ACL_EVENT_READ; + fdp->fdidx_ready = eventp->fdcnt_ready; + eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp; + } + } + + if ((fdp->flag & EVENT_FDTABLE_FLAG_WRITE) && EVENT_TEST_WRITE(bp)) { + if ((fdp->event_type & (ACL_EVENT_READ | ACL_EVENT_WRITE)) == 0) + { + fdp->event_type |= ACL_EVENT_WRITE; + fdp->fdidx_ready = eventp->fdcnt_ready; + eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp; + } + } + +#ifdef EVENT_TEST_ERROR + if (EVENT_TEST_ERROR(bp)) { + if ((fdp->event_type & (ACL_EVENT_READ | ACL_EVENT_WRITE)) == 0) + { + fdp->event_type |= ACL_EVENT_XCPT; + fdp->fdidx_ready = eventp->fdcnt_ready; + eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp; + } + } +#endif + } + +TAG_DONE: + + /* + * Deliver timer events. Requests are sorted: we can stop when we reach + * the future or the list end. Allow the application to update the timer + * queue while it is being called back. To this end, we repeatedly pop + * the first request off the timer queue before delivering the event to + * the application. + */ + SET_TIME(eventp->event_present); + while ((timer = ACL_FIRST_TIMER(&eventp->timer_head)) != 0) { + if (timer->when > eventp->event_present) + break; + worker_fn = timer->callback; + worker_arg = timer->context; + + /* 如果定时器的时间间隔 > 0 且允许定时器被循环调用,则再重设定时器 */ + if (timer->delay > 0 && timer->keep) { + timer->ncount++; + eventp->timer_request(eventp, timer->callback, + timer->context, timer->delay, timer->keep); + } else { + acl_ring_detach(&timer->ring); /* first this */ + timer->nrefer--; + if (timer->nrefer != 0) + acl_msg_fatal("%s(%d): nrefer(%d) != 0", + myname, __LINE__, timer->nrefer); + acl_myfree(timer); + } + worker_fn(ACL_EVENT_TIME, worker_arg); + } + + event_fire(eventp); + eventp->nested--; +} + +static int event_isrset(ACL_EVENT *eventp acl_unused, ACL_VSTREAM *stream) +{ + ACL_EVENT_FDTABLE *fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + + return (fdp == NULL ? 0 : (fdp->flag & EVENT_FDTABLE_FLAG_READ)); +} + +static int event_iswset(ACL_EVENT *eventp acl_unused, ACL_VSTREAM *stream) +{ + ACL_EVENT_FDTABLE *fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + + return (fdp == NULL ? 0 : (fdp->flag & EVENT_FDTABLE_FLAG_WRITE)); + +} + +static int event_isxset(ACL_EVENT *eventp acl_unused, ACL_VSTREAM *stream) +{ + ACL_EVENT_FDTABLE *fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + + return (fdp == NULL ? 0 : (fdp->flag & EVENT_FDTABLE_FLAG_EXPT)); +} + +static void event_free(ACL_EVENT *eventp) +{ + EVENT_KERNEL *ev = (EVENT_KERNEL *) eventp; + +#ifdef USE_FDMAP + acl_fdmap_free(ev->fdmap); +#endif + acl_myfree(ev->event_buf); + close(ev->event_fd); + acl_myfree(ev); +} + +ACL_EVENT *event_new_kernel3(int fdsize acl_unused) +{ + ACL_EVENT *eventp; + EVENT_KERNEL *ev; + static int __default_max_events = 1000; + + eventp = event_alloc(sizeof(EVENT_KERNEL)); + + snprintf(eventp->name, sizeof(eventp->name), "events - %s", EVENT_NAME); + eventp->event_mode = ACL_EVENT_KERNEL3; + eventp->use_thread = 0; + eventp->loop_fn = event_loop; + eventp->free_fn = event_free; + eventp->enable_read_fn = event_enable_read; + eventp->enable_write_fn = event_enable_write; + eventp->enable_listen_fn = event_enable_read; + eventp->disable_read_fn = event_disable_read; + eventp->disable_write_fn = event_disable_write; + eventp->disable_readwrite_fn = event_disable_readwrite; + eventp->isrset_fn = event_isrset; + eventp->iswset_fn = event_iswset; + eventp->isxset_fn = event_isxset; + eventp->timer_request = event_timer_request; + eventp->timer_cancel = event_timer_cancel; + eventp->timer_keep = event_timer_keep; + eventp->timer_ifkeep = event_timer_ifkeep; + + ev = (EVENT_KERNEL*) eventp; + EVENT_REG_INIT_HANDLE(ev->event_fd, fdsize); + ev->event_fdslots = __default_max_events; + ev->event_buf = (EVENT_BUFFER *) + acl_mycalloc(ev->event_fdslots + 1, sizeof(EVENT_BUFFER)); + acl_ring_init(&ev->fdp_delay_list); +#ifdef USE_FDMAP + ev->fdmap = acl_fdmap_create(fdsize); +#endif + return (eventp); +} +#endif /* ACL_EVENTS_KERNEL_STYLE */ diff --git a/lib_acl/src/event/events_kernel_thr.c b/lib_acl/src/event/events_kernel_thr.c new file mode 100644 index 000000000..70c677cf4 --- /dev/null +++ b/lib_acl/src/event/events_kernel_thr.c @@ -0,0 +1,585 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include +#include +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#ifdef ACL_UNIX +#include +#endif + +#include "stdlib/acl_sys_patch.h" +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_mystring.h" +#include "stdlib/acl_msg.h" +#include "stdlib/acl_ring.h" +#include "stdlib/acl_vstream.h" +#include "event/acl_events.h" + +#endif + +#include "events_define.h" + +#ifdef ACL_EVENTS_KERNEL_STYLE + +#include "events_epoll.h" +#include "events_devpoll.h" +#include "events_kqueue.h" +#include "events_fdtable.h" +#include "events_dog.h" +#include "events.h" + +typedef struct EVENT_KERNEL_THR { + EVENT_THR event; + EVENT_BUFFER *event_buf; + int event_fdslots; + int event_fd; +#ifdef USE_FDMAP + ACL_FD_MAP *fdmap; +#endif +} EVENT_KERNEL_THR; + +static void event_enable_read(ACL_EVENT *eventp, ACL_VSTREAM *stream, + int timeout, ACL_EVENT_NOTIFY_RDWR callback, void *context) +{ + const char *myname = "event_enable_read"; + EVENT_KERNEL_THR *event_thr = (EVENT_KERNEL_THR *) eventp; + ACL_EVENT_FDTABLE *fdp; + ACL_SOCKET sockfd; + int err = 0; + + sockfd = ACL_VSTREAM_SOCK(stream); + fdp = (ACL_EVENT_FDTABLE*) stream->fdp; + if (fdp == NULL) { + fdp = event_fdtable_alloc(); + fdp->listener = 0; + fdp->stream = stream; + stream->fdp = (void *) fdp; + } + + /* 对同一连接的读写操作禁止同时进行监控 */ + else if (fdp->flag & EVENT_FDTABLE_FLAG_WRITE) + acl_msg_panic("%s(%d), %s: fd %d: multiple I/O request", + __FILE__, __LINE__, myname, sockfd); + else { + fdp->listener = 0; + fdp->stream = stream; + } + + if (fdp->r_callback != callback || fdp->r_context != context) { + fdp->r_callback = callback; + fdp->r_context = context; + } + + if (timeout > 0) { + fdp->r_timeout = timeout * 1000000; + fdp->r_ttl = eventp->event_present + fdp->r_timeout; + } else { + fdp->r_ttl = 0; + fdp->r_timeout = 0; + } + + THREAD_LOCK(&event_thr->event.tb_mutex); + + if ((fdp->flag & EVENT_FDTABLE_FLAG_READ) == 0) { + stream->nrefer++; + fdp->flag = EVENT_FDTABLE_FLAG_READ | EVENT_FDTABLE_FLAG_EXPT; + fdp->fdidx = eventp->fdcnt; + eventp->fdtabs[eventp->fdcnt] = fdp; + eventp->fdcnt++; + + if (eventp->maxfd != ACL_SOCKET_INVALID && eventp->maxfd < sockfd) + eventp->maxfd = sockfd; +#ifdef USE_FDMAP + acl_fdmap_add(event_thr->fdmap, sockfd, fdp); +#endif + EVENT_REG_ADD_READ(err, event_thr->event_fd, sockfd, fdp); + if (err < 0) { + acl_msg_fatal("%s: %s: %s, err(%d), fd(%d)", + myname, EVENT_REG_ADD_TEXT, + acl_last_serror(), err, sockfd); + } + } + + /* 将 EVENT_REG_ADD_READ 包括在 THREAD_UNLOCK 之内,也许可以减少内核 + * 层次锁的冲突(因为 epoll 的函数是线程安全的,所以为了保证多线程操作 + * 的安全性,应该是有锁同步操作) + */ + THREAD_UNLOCK(&event_thr->event.tb_mutex); + + /* 主要是为了减少通知次数 */ + if (event_thr->event.blocked && event_thr->event.evdog + && event_dog_client(event_thr->event.evdog) != stream) + event_dog_notify(event_thr->event.evdog); +} + +static void event_enable_listen(ACL_EVENT *eventp, ACL_VSTREAM *stream, + int timeout, ACL_EVENT_NOTIFY_RDWR callback, void *context) +{ + const char *myname = "event_enable_listen"; + EVENT_KERNEL_THR *event_thr = (EVENT_KERNEL_THR *) eventp; + ACL_EVENT_FDTABLE *fdp; + ACL_SOCKET sockfd; + int err = 0; + + sockfd = ACL_VSTREAM_SOCK(stream); + fdp = (ACL_EVENT_FDTABLE*) stream->fdp; + if (fdp == NULL) { + fdp = event_fdtable_alloc(); + fdp->stream = stream; + fdp->listener = 1; + stream->fdp = (void *) fdp; + } + + /* 对同一连接的读写操作禁止同时进行监控 */ + else if (fdp->flag & EVENT_FDTABLE_FLAG_WRITE) + acl_msg_panic("%s(%d)->%s: fd %d: multiple I/O request", + __FILE__, __LINE__, myname, sockfd); + else { + fdp->stream = stream; + fdp->listener = 1; + } + + if (fdp->r_callback != callback || fdp->r_context != context) { + fdp->r_callback = callback; + fdp->r_context = context; + } + + if (timeout > 0) { + fdp->r_timeout = timeout * 1000000; + fdp->r_ttl = eventp->event_present + fdp->r_timeout; + } else { + fdp->r_ttl = 0; + fdp->r_timeout = 0; + } + + THREAD_LOCK(&event_thr->event.tb_mutex); + + if ((fdp->flag & EVENT_FDTABLE_FLAG_READ) == 0) { + fdp->flag = EVENT_FDTABLE_FLAG_READ | EVENT_FDTABLE_FLAG_EXPT; + stream->nrefer++; + fdp->fdidx = eventp->fdcnt; + eventp->fdtabs[eventp->fdcnt] = fdp; + eventp->fdcnt++; + + if (eventp->maxfd != ACL_SOCKET_INVALID && eventp->maxfd < sockfd) + eventp->maxfd = sockfd; +#ifdef USE_FDMAP + acl_fdmap_add(event_thr->fdmap, sockfd, fdp); +#endif + EVENT_REG_ADD_READ(err, event_thr->event_fd, sockfd, fdp); + if (err < 0) + acl_msg_fatal("%s: %s: %s, err(%d), fd(%d)", + myname, EVENT_REG_ADD_TEXT, + acl_last_serror(), err, sockfd); + } + + THREAD_UNLOCK(&event_thr->event.tb_mutex); +} + +static void event_enable_write(ACL_EVENT *eventp, ACL_VSTREAM *stream, + int timeout, ACL_EVENT_NOTIFY_RDWR callback, void *context) +{ + const char *myname = "event_enable_write"; + EVENT_KERNEL_THR *event_thr = (EVENT_KERNEL_THR *) eventp; + ACL_EVENT_FDTABLE *fdp; + ACL_SOCKET sockfd; + int err = 0; + + sockfd = ACL_VSTREAM_SOCK(stream); + fdp = (ACL_EVENT_FDTABLE*) stream->fdp; + if (fdp == NULL) { + fdp = event_fdtable_alloc(); + fdp->listener = 0; + fdp->stream = stream; + stream->fdp = (void *) fdp; + } + /* 对同一连接的读写操作禁止同时进行监控 */ + else if (fdp->flag & EVENT_FDTABLE_FLAG_READ) + acl_msg_panic("%s(%d)->%s: fd %d: multiple I/O request", + __FILE__, __LINE__, myname, sockfd); + else { + fdp->listener = 0; + fdp->stream = stream; + } + + if (fdp->w_callback != callback || fdp->w_context != context) { + fdp->w_callback = callback; + fdp->w_context = context; + } + + if (timeout > 0) { + fdp->w_timeout = timeout * 1000000; + fdp->w_ttl = eventp->event_present + fdp->w_timeout; + } else { + fdp->w_ttl = 0; + fdp->w_timeout = 0; + } + + THREAD_LOCK(&event_thr->event.tb_mutex); + + if ((fdp->flag & EVENT_FDTABLE_FLAG_WRITE) == 0) { + fdp->flag = EVENT_FDTABLE_FLAG_WRITE | EVENT_FDTABLE_FLAG_EXPT; + stream->nrefer++; + fdp->fdidx = eventp->fdcnt; + eventp->fdtabs[eventp->fdcnt] = fdp; + eventp->fdcnt++; + + if (eventp->maxfd != ACL_SOCKET_INVALID && eventp->maxfd < sockfd) + eventp->maxfd = sockfd; +#ifdef USE_FDMAP + acl_fdmap_add(event_thr->fdmap, sockfd, fdp); +#endif + EVENT_REG_ADD_WRITE(err, event_thr->event_fd, sockfd, fdp); + if (err < 0) { + acl_msg_fatal("%s: %s: %s, err(%d), fd(%d)", + myname, EVENT_REG_ADD_TEXT, + acl_last_serror(), err, sockfd); + } + } + + THREAD_UNLOCK(&event_thr->event.tb_mutex); + + if (event_thr->event.blocked && event_thr->event.evdog + && event_dog_client(event_thr->event.evdog) != stream) + event_dog_notify(event_thr->event.evdog); +} + +/* event_disable_readwrite - disable request for read or write events */ + +static void event_disable_readwrite(ACL_EVENT *eventp, ACL_VSTREAM *stream) +{ + const char *myname = "event_disable_readwrite"; + EVENT_KERNEL_THR *event_thr = (EVENT_KERNEL_THR *) eventp; + ACL_EVENT_FDTABLE *fdp; + ACL_SOCKET sockfd; + int err = 0; + + sockfd = ACL_VSTREAM_SOCK(stream); + + fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + if (fdp == NULL) { + acl_msg_error("%s(%d): fdp null", myname, __LINE__); + return; + } + + if ((fdp->flag & (EVENT_FDTABLE_FLAG_READ | EVENT_FDTABLE_FLAG_WRITE)) == 0) { + acl_msg_error("%s(%d): sockfd(%d) not be set", + myname, __LINE__, sockfd); + return; + } + if (fdp->fdidx == -1) + acl_msg_fatal("%s(%d): fdidx(%d) invalid", + myname, __LINE__, fdp->fdidx); + + THREAD_LOCK(&event_thr->event.tb_mutex); + + if (eventp->maxfd == sockfd) + eventp->maxfd = ACL_SOCKET_INVALID; + + if (eventp->fdtabs[fdp->fdidx] != fdp) + acl_msg_fatal("%s(%d): fdidx(%d)'s fdp invalid", + myname, __LINE__, fdp->fdidx); + + if (fdp->fdidx < --eventp->fdcnt) { + eventp->fdtabs[fdp->fdidx] = eventp->fdtabs[eventp->fdcnt]; + eventp->fdtabs[fdp->fdidx]->fdidx = fdp->fdidx; + } + +#ifdef USE_FDMAP + acl_fdmap_del(event_thr->fdmap, sockfd); +#endif + if (fdp->fdidx_ready > 0 + && fdp->fdidx_ready < eventp->fdcnt_ready + && eventp->fdtabs_ready[fdp->fdidx_ready] == fdp) + { + eventp->fdtabs_ready[fdp->fdidx_ready] = NULL; + } + +#ifdef EVENT_REG_DEL_BOTH + EVENT_REG_DEL_BOTH(err, event_thr->event_fd, sockfd); + if (fdp->flag & EVENT_FDTABLE_FLAG_READ) + stream->nrefer--; + if (fdp->flag & EVENT_FDTABLE_FLAG_WRITE) + stream->nrefer--; +#else + if (fdp->flag & EVENT_FDTABLE_FLAG_READ) { + EVENT_REG_DEL_READ(err, event_thr->event_fd, sockfd); + stream->nrefer--; + } + if (fdp->flag & EVENT_FDTABLE_FLAG_WRITE) { + EVENT_REG_DEL_WRITE(err, event_thr->event_fd, sockfd); + stream->nrefer--; + } +#endif + + THREAD_UNLOCK(&event_thr->event.tb_mutex); + + if (err < 0) { + acl_msg_fatal("%s: %s: %s", myname, EVENT_REG_DEL_TEXT, + acl_last_serror()); + } + + event_fdtable_reset(fdp); +} + +static int event_isrset(ACL_EVENT *eventp acl_unused, ACL_VSTREAM *stream) +{ + ACL_EVENT_FDTABLE *fdp; + + fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + if (fdp == NULL) + return (0); + + return ((fdp->flag & EVENT_FDTABLE_FLAG_READ)); +} + +static int event_iswset(ACL_EVENT *eventp acl_unused, ACL_VSTREAM *stream) +{ + ACL_EVENT_FDTABLE *fdp; + + fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + if (fdp == NULL) + return (0); + + return ((fdp->flag & EVENT_FDTABLE_FLAG_WRITE)); +} + +static int event_isxset(ACL_EVENT *eventp acl_unused, ACL_VSTREAM *stream) +{ + ACL_EVENT_FDTABLE *fdp; + + fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + if (fdp == NULL) + return (0); + + return ((fdp->flag & EVENT_FDTABLE_FLAG_EXPT)); +} + +static void event_loop(ACL_EVENT *eventp) +{ + const char *myname = "event_loop"; + EVENT_KERNEL_THR *event_thr = (EVENT_KERNEL_THR *) eventp; + ACL_EVENT_NOTIFY_FN worker_fn; + void *worker_arg; + ACL_EVENT_TIMER *timer; + int n, delay, nready; + ACL_EVENT_FDTABLE *fdp; + ACL_RING timer_ring, *entry_ptr; + EVENT_BUFFER *bp; + + acl_ring_init(&timer_ring); + + delay = eventp->delay_sec * 1000 + eventp->delay_usec / 1000; + if (delay <= 0) + delay = 100; /* 100 milliseconds at least */ + + SET_TIME(eventp->event_present); + + THREAD_LOCK(&event_thr->event.tm_mutex); + + /* + * Find out when the next timer would go off. Timer requests are sorted. + * If any timer is scheduled, adjust the delay appropriately. + */ + if ((timer = ACL_FIRST_TIMER(&eventp->timer_head)) != 0) { + n = (int) (timer->when + - eventp->event_present + 1000000 - 1) / 1000000; + if (n <= 0) { + delay = 0; + } else if (n < eventp->delay_sec) { + delay = n * 1000 + eventp->delay_usec / 1000; + } + } + + THREAD_UNLOCK(&event_thr->event.tm_mutex); + + THREAD_LOCK(&event_thr->event.tb_mutex); + + if (event_thr_prepare(eventp) == 0) { + THREAD_UNLOCK(&event_thr->event.tb_mutex); + + if (eventp->fdcnt_ready == 0) + sleep(1); + + nready = 0; + goto TAG_DONE; + } + + if (eventp->fdcnt_ready > 0) + delay = 0; + + THREAD_UNLOCK(&event_thr->event.tb_mutex); + + event_thr->event.blocked = 1; + EVENT_BUFFER_READ(nready, event_thr->event_fd, event_thr->event_buf, + event_thr->event_fdslots, delay); + event_thr->event.blocked = 0; + + if (nready < 0) { + if (acl_last_error() != ACL_EINTR) { + acl_msg_fatal("%s(%d), %s: event_loop: select: %s", + __FILE__, __LINE__, myname, acl_last_serror()); + } + goto TAG_DONE; + } else if (nready == 0) + goto TAG_DONE; + + THREAD_LOCK(&event_thr->event.tb_mutex); + + bp = event_thr->event_buf; + for (; bp < event_thr->event_buf + nready; bp++) { +#ifdef USE_FDMAP + ACL_SOCKET sockfd; + + sockfd = EVENT_GET_FD(bp); + fdp = acl_fdmap_ctx(event_thr->fdmap, sockfd); + if (fdp == NULL || fdp->stream == NULL) + continue; + + if (sockfd != ACL_VSTREAM_SOCK(fdp->stream)) + acl_msg_fatal("%s(%d): sockfd(%d) != %d", myname, + __LINE__, sockfd, ACL_VSTREAM_SOCK(fdp->stream)); +#else + fdp = (ACL_EVENT_FDTABLE *) EVENT_GET_CTX(bp); +#endif + if ((fdp->event_type & (ACL_EVENT_XCPT | ACL_EVENT_RW_TIMEOUT))) + continue; + + if ((fdp->flag & EVENT_FDTABLE_FLAG_READ) + && EVENT_TEST_READ(bp)) + { + fdp->stream->sys_read_ready = 1; + if ((fdp->event_type & ACL_EVENT_READ) == 0) { + fdp->event_type |= ACL_EVENT_READ; + fdp->fdidx_ready = eventp->fdcnt_ready; + eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp; + } + } else if ((fdp->flag & EVENT_FDTABLE_FLAG_WRITE) + && EVENT_TEST_WRITE(bp)) + { + fdp->event_type |= ACL_EVENT_WRITE; + fdp->fdidx_ready = eventp->fdcnt_ready; + eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp; + } + } + + THREAD_UNLOCK(&event_thr->event.tb_mutex); + +TAG_DONE: + + /* + * Deliver timer events. Requests are sorted: we can stop when we reach + * the future or the list end. Allow the application to update the timer + * queue while it is being called back. To this end, we repeatedly pop + * the first request off the timer queue before delivering the event to + * the application. + */ + + SET_TIME(eventp->event_present); + + THREAD_LOCK(&event_thr->event.tm_mutex); + + while ((timer = ACL_FIRST_TIMER(&eventp->timer_head)) != 0) { + if (timer->when > eventp->event_present) + break; + + acl_ring_detach(&timer->ring); /* first this */ + acl_ring_prepend(&timer_ring, &timer->ring); + } + + THREAD_UNLOCK(&event_thr->event.tm_mutex); + + while (1) { + entry_ptr = acl_ring_pop_head(&timer_ring); + if (entry_ptr == NULL) + break; + + timer = ACL_RING_TO_TIMER(entry_ptr); + worker_fn = timer->callback; + worker_arg = timer->context; + + worker_fn(ACL_EVENT_TIME, worker_arg); + + acl_myfree(timer); + } + + event_thr_fire(eventp); +} + +static void event_add_dog(ACL_EVENT *eventp) +{ + EVENT_KERNEL_THR *event_thr = (EVENT_KERNEL_THR*) eventp; + + event_thr->event.evdog = event_dog_create((ACL_EVENT*) event_thr, 1); +} + +static void event_free(ACL_EVENT *eventp) +{ + const char *myname = "event_free"; + EVENT_KERNEL_THR *event_thr = (EVENT_KERNEL_THR *) eventp; + + if (eventp == NULL) + acl_msg_fatal("%s, %s(%d): eventp null", + __FILE__, myname, __LINE__); + + LOCK_DESTROY(&event_thr->event.tm_mutex); + LOCK_DESTROY(&event_thr->event.tb_mutex); + +#ifdef USE_FDMAP + acl_fdmap_free(event_thr->fdmap); +#endif + acl_myfree(event_thr->event_buf); + close(event_thr->event_fd); + acl_myfree(eventp); +} + +ACL_EVENT *event_new_kernel_thr(int fdsize acl_unused) +{ + EVENT_KERNEL_THR *event_thr; + static int __default_max_events = 1024; + + event_thr = (EVENT_KERNEL_THR*) event_alloc(sizeof(EVENT_KERNEL_THR)); + + snprintf(event_thr->event.event.name, sizeof(event_thr->event.event.name), + "thread events - %s", EVENT_NAME); + event_thr->event.event.event_mode = ACL_EVENT_KERNEL; + event_thr->event.event.use_thread = 1; + event_thr->event.event.loop_fn = event_loop; + event_thr->event.event.free_fn = event_free; + event_thr->event.event.add_dog_fn = event_add_dog; + event_thr->event.event.enable_read_fn = event_enable_read; + event_thr->event.event.enable_write_fn = event_enable_write; + event_thr->event.event.enable_listen_fn = event_enable_listen; + event_thr->event.event.disable_readwrite_fn = event_disable_readwrite; + event_thr->event.event.isrset_fn = event_isrset; + event_thr->event.event.iswset_fn = event_iswset; + event_thr->event.event.isxset_fn = event_isxset; + event_thr->event.event.timer_request = event_timer_request_thr; + event_thr->event.event.timer_cancel = event_timer_cancel_thr; + event_thr->event.event.timer_keep = event_timer_keep_thr; + event_thr->event.event.timer_ifkeep = event_timer_ifkeep_thr; + + LOCK_INIT(&event_thr->event.tm_mutex); + LOCK_INIT(&event_thr->event.tb_mutex); + + EVENT_REG_INIT_HANDLE(event_thr->event_fd, fdsize); + event_thr->event_fdslots = __default_max_events; + event_thr->event_buf = (EVENT_BUFFER *) + acl_mycalloc(event_thr->event_fdslots + 1, sizeof(EVENT_BUFFER)); +#ifdef USE_FDMAP + event_thr->fdmap = acl_fdmap_create(fdsize); +#endif + return ((ACL_EVENT *) event_thr); +} + +#endif /* ACL_EVENTS_KERNEL_STYLE */ diff --git a/lib_acl/src/event/events_kqueue.h b/lib_acl/src/event/events_kqueue.h new file mode 100644 index 000000000..1d218af61 --- /dev/null +++ b/lib_acl/src/event/events_kqueue.h @@ -0,0 +1,112 @@ +#ifndef __EVENTS_KQUEUE_INCLUDE_H__ +#define __EVENTS_KQUEUE_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * FreeBSD kqueue supports no system call to find out what descriptors are + * registered in the kernel-based filter. To implement our own sanity checks + * we maintain our own descriptor bitmask. + * + * FreeBSD kqueue does support application context pointers. Unfortunately, + * changing that information would cost a system call, and some of the + * competitors don't support application context. To keep the implementation + * simple we maintain our own table with call-back information. + * + * FreeBSD kqueue silently unregisters a descriptor from its filter when the + * descriptor is closed, so our information could get out of sync with the + * kernel. But that will never happen, because we have to meticulously + * unregister a file descriptor before it is closed, to avoid errors on + * systems that are built with EVENTS_STYLE == EVENTS_STYLE_SELECT. + */ +#if (ACL_EVENTS_KERNEL_STYLE == ACL_EVENTS_STYLE_KQUEUE) +#include + +#define EVENT_NAME "kqueue" + + /* + * Some early FreeBSD implementations don't have the EV_SET macro. + */ +#ifndef EV_SET +#define EV_SET(kp, id, fi, fl, ffl, da, ud) do { \ + (kp)->ident = (id); \ + (kp)->filter = (fi); \ + (kp)->flags = (fl); \ + (kp)->fflags = (ffl); \ + (kp)->data = (da); \ + (kp)->udata = (ud); \ + } while(0) +#endif + + /* + * Macros to initialize the kernel-based filter; see event_init(). + */ + +#define EVENT_REG_INIT_HANDLE(eh, n) do { \ + eh = kqueue(); \ + } while (0) +#define EVENT_REG_INIT_TEXT "kqueue" + + /* + * Macros to update the kernel-based filter; see event_enable_read(), + * event_enable_write() and event_disable_readwrite(). + */ +#define EVENT_REG_FD_OP(er, eh, fh, ctx, ev, op) do { \ + struct kevent dummy; \ + EV_SET(&dummy, (fh), (ev), (op), 0, 0, ctx); \ + (er) = kevent(eh, &dummy, 1, 0, 0, 0); \ + } while (0) + +#define EVENT_REG_ADD_OP(er, eh, fh, ctx, ev) \ + EVENT_REG_FD_OP((er), (eh), (fh), ctx, (ev), EV_ADD) +#define EVENT_REG_ADD_READ(er, eh, fh, ctx) \ + EVENT_REG_ADD_OP((er), (eh), (fh), ctx, EVFILT_READ) +#define EVENT_REG_ADD_WRITE(er, eh, fh, ctx) \ + EVENT_REG_ADD_OP((er), (eh), (fh), ctx, EVFILT_WRITE) +#define EVENT_REG_ADD_TEXT "kevent EV_ADD" + +#define EVENT_REG_DEL_OP(er, eh, fh, ev) \ + EVENT_REG_FD_OP((er), (eh), (fh), NULL, (ev), EV_DELETE) +#define EVENT_REG_DEL_READ(er, eh, fh) \ + EVENT_REG_DEL_OP((er), (eh), (fh), EVFILT_READ) +#define EVENT_REG_DEL_WRITE(er, eh, fh) \ + EVENT_REG_DEL_OP((er), (eh), (fh), EVFILT_WRITE) +#define EVENT_REG_DEL_TEXT "kevent EV_DELETE" + + /* + * Macros to retrieve event buffers from the kernel; see event_loop(). + */ +typedef struct kevent EVENT_BUFFER; + +#define EVENT_BUFFER_READ(ev_cnt, eh, ev_buf, buflen, delay) do { \ + struct timespec ts; \ + struct timespec *tsp; \ + if ((delay) < 0) { \ + tsp = 0; \ + } else { \ + tsp = &ts; \ + ts.tv_nsec = 0; \ + ts.tv_sec = (delay); \ + } \ + (ev_cnt) = kevent(eh, (struct kevent *) 0, 0, (ev_buf), (buflen), (tsp)); \ +} while (0) +#define EVENT_BUFFER_READ_TEXT "kevent" + + /* + * Macros to process event buffers from the kernel; see event_loop(). + */ +#define EVENT_GET_FD(fp) ((bp)->ident) +#define EVENT_GET_CTX(bp) ((bp)->udata) +#define EVENT_GET_TYPE(bp) ((bp)->filter) +#define EVENT_TEST_READ(bp) (EVENT_GET_TYPE(bp) == EVFILT_READ) +#define EVENT_TEST_WRITE(bp) (EVENT_GET_TYPE(bp) == EVFILT_WRITE) + +#endif /* (ACL_EVENTS_KERNEL_STYLE == ACL_EVENTS_STYLE_KQUEUE) */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/src/event/events_poll.c b/lib_acl/src/event/events_poll.c new file mode 100644 index 000000000..7a2154a28 --- /dev/null +++ b/lib_acl/src/event/events_poll.c @@ -0,0 +1,563 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include +#include +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_sys_patch.h" +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_mystring.h" +#include "stdlib/acl_msg.h" +#include "stdlib/acl_debug.h" +#include "stdlib/acl_vstream.h" +#include "event/acl_events.h" + +#endif + +#include "events_define.h" + +#ifdef ACL_EVENTS_POLL_STYLE +#include +#include + +#include "events_fdtable.h" +#include "events.h" + +typedef struct EVENT_POLL { + ACL_EVENT event; + struct pollfd *fds; + ACL_FD_MAP *fdmap; +} EVENT_POLL; + +static void stream_on_close(ACL_VSTREAM *stream, void *arg) +{ + EVENT_POLL *ev = (EVENT_POLL*) arg; + ACL_EVENT_FDTABLE *fdp = (ACL_EVENT_FDTABLE*) stream->fdp; + ACL_SOCKET sockfd = ACL_VSTREAM_SOCK(stream); + int ret = 0; + + if (fdp == NULL) + return; + + if ((fdp->flag & EVENT_FDTABLE_FLAG_READ) + && (fdp->flag & EVENT_FDTABLE_FLAG_WRITE)) + { + ret = 1; + } else if ((fdp->flag & EVENT_FDTABLE_FLAG_READ)) { + ret = 2; + } else if ((fdp->flag & EVENT_FDTABLE_FLAG_WRITE)) { + ret = 3; + } + + if (ret) { + acl_fdmap_del(ev->fdmap, sockfd); + } + + if (ev->event.maxfd == ACL_VSTREAM_SOCK(fdp->stream)) + ev->event.maxfd = ACL_SOCKET_INVALID; + if (fdp->fdidx >= 0 && fdp->fdidx < --ev->event.fdcnt) { + ev->fds[fdp->fdidx] = ev->fds[ev->event.fdcnt]; + ev->event.fdtabs[fdp->fdidx] = ev->event.fdtabs[ev->event.fdcnt]; + ev->event.fdtabs[fdp->fdidx]->fdidx = fdp->fdidx; + } + fdp->fdidx = -1; + + if (fdp->fdidx_ready >= 0 + && fdp->fdidx_ready < ev->event.fdcnt_ready + && ev->event.fdtabs_ready[fdp->fdidx_ready] == fdp) + { + ev->event.fdtabs_ready[fdp->fdidx_ready] = NULL; + } + fdp->fdidx_ready = -1; + event_fdtable_free(fdp); + stream->fdp = NULL; +} + +static void event_enable_read(ACL_EVENT *eventp, ACL_VSTREAM *stream, + int timeout, ACL_EVENT_NOTIFY_RDWR callback, void *context) +{ + EVENT_POLL *ev = (EVENT_POLL *) eventp; + ACL_SOCKET sockfd = ACL_VSTREAM_SOCK(stream); + ACL_EVENT_FDTABLE *fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + + if (fdp == NULL) { + fdp = event_fdtable_alloc(); + + fdp->stream = stream; + stream->fdp = (void *) fdp; + acl_vstream_add_close_handle(stream, stream_on_close, eventp); + acl_fdmap_add(ev->fdmap, sockfd, fdp); + } + + if (fdp->fdidx == -1) { + fdp->fdidx = eventp->fdcnt; + eventp->fdtabs[eventp->fdcnt++] = fdp; + } + + if ((fdp->flag & EVENT_FDTABLE_FLAG_WRITE)) { + fdp->flag |= EVENT_FDTABLE_FLAG_READ; + ev->fds[fdp->fdidx].events |= POLLIN | POLLHUP | POLLERR; + } else { + fdp->flag = EVENT_FDTABLE_FLAG_READ | EVENT_FDTABLE_FLAG_EXPT; + ev->fds[fdp->fdidx].events = POLLIN | POLLHUP | POLLERR; + } + + ev->fds[fdp->fdidx].fd = sockfd; + + if (eventp->maxfd != ACL_SOCKET_INVALID && eventp->maxfd < sockfd) + eventp->maxfd = sockfd; + + if (fdp->r_callback != callback || fdp->r_context != context) { + fdp->r_callback = callback; + fdp->r_context = context; + } + + if (timeout > 0) { + fdp->r_timeout = timeout * 1000000; + fdp->r_ttl = eventp->event_present + fdp->r_timeout; + } else { + fdp->r_ttl = 0; + fdp->r_timeout = 0; + } +} + +static void event_enable_write(ACL_EVENT *eventp, ACL_VSTREAM *stream, + int timeout, ACL_EVENT_NOTIFY_RDWR callback, void *context) +{ + EVENT_POLL *ev = (EVENT_POLL *) eventp; + ACL_SOCKET sockfd = ACL_VSTREAM_SOCK(stream); + ACL_EVENT_FDTABLE *fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + + if (fdp == NULL) { + fdp = event_fdtable_alloc(); + + fdp->stream = stream; + stream->fdp = (void *) fdp; + acl_vstream_add_close_handle(stream, stream_on_close, eventp); + acl_fdmap_add(ev->fdmap, sockfd, fdp); + } + + if (fdp->fdidx == -1) { + fdp->fdidx = eventp->fdcnt; + eventp->fdtabs[eventp->fdcnt++] = fdp; + } + + if ((fdp->flag & EVENT_FDTABLE_FLAG_READ)) { + fdp->flag |= EVENT_FDTABLE_FLAG_WRITE; + ev->fds[fdp->fdidx].events |= POLLOUT | POLLHUP | POLLERR; + } else { + fdp->flag = EVENT_FDTABLE_FLAG_WRITE | EVENT_FDTABLE_FLAG_EXPT; + ev->fds[fdp->fdidx].events = POLLOUT | POLLHUP | POLLERR; + } + + ev->fds[fdp->fdidx].fd = sockfd; + + if (eventp->maxfd != ACL_SOCKET_INVALID && eventp->maxfd < sockfd) + eventp->maxfd = sockfd; + + if (fdp->w_callback != callback || fdp->w_context != context) { + fdp->w_callback = callback; + fdp->w_context = context; + } + + if (timeout > 0) { + fdp->w_timeout = timeout * 1000000; + fdp->w_ttl = eventp->event_present + fdp->w_timeout; + } else { + fdp->w_ttl = 0; + fdp->w_timeout = 0; + } +} + +/* event_disable_read - disable request for read events */ + +static void event_disable_read(ACL_EVENT *eventp, ACL_VSTREAM *stream) +{ + const char *myname = "event_disable_read"; + EVENT_POLL *ev = (EVENT_POLL *) eventp; + ACL_SOCKET sockfd = ACL_VSTREAM_SOCK(stream); + ACL_EVENT_FDTABLE *fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + + if (fdp == NULL) { + acl_msg_warn("%s(%d): fdp null", myname, __LINE__); + return; + } + + if (fdp->fdidx < 0 || fdp->fdidx >= eventp->fdcnt) { + acl_msg_warn("%s(%d): sockfd(%d)'s fdidx(%d) invalid", + myname, __LINE__, sockfd, fdp->fdidx); + return; + } + + if (!(fdp->flag & EVENT_FDTABLE_FLAG_READ)) { + acl_msg_warn("%s(%d): sockfd(%d) not be set", + myname, __LINE__, sockfd); + return; + } + + fdp->r_ttl = 0; + fdp->r_timeout = 0; + fdp->r_callback = NULL; + fdp->event_type &= ~ACL_EVENT_READ; + fdp->flag &= ~EVENT_FDTABLE_FLAG_READ; + + if ((fdp->flag & EVENT_FDTABLE_FLAG_WRITE)) { + ev->fds[fdp->fdidx].events = POLLOUT | POLLHUP | POLLERR; + return; + } + + if (eventp->maxfd == sockfd) + eventp->maxfd = ACL_SOCKET_INVALID; + + if (fdp->fdidx < --eventp->fdcnt) { + ev->fds[fdp->fdidx] = ev->fds[eventp->fdcnt]; + eventp->fdtabs[fdp->fdidx] = eventp->fdtabs[eventp->fdcnt]; + eventp->fdtabs[fdp->fdidx]->fdidx = fdp->fdidx; + } + fdp->fdidx = -1; + + if (fdp->fdidx_ready >= 0 + && fdp->fdidx_ready < eventp->fdcnt_ready + && eventp->fdtabs_ready[fdp->fdidx_ready] == fdp) + { + eventp->fdtabs_ready[fdp->fdidx_ready] = NULL; + } + fdp->fdidx_ready = -1; + + acl_fdmap_del(ev->fdmap, sockfd); +} + +/* event_disable_write - disable request for write events */ + +static void event_disable_write(ACL_EVENT *eventp, ACL_VSTREAM *stream) +{ + const char *myname = "event_disable_write"; + EVENT_POLL *ev = (EVENT_POLL *) eventp; + ACL_SOCKET sockfd = ACL_VSTREAM_SOCK(stream); + ACL_EVENT_FDTABLE *fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + + if (fdp == NULL) { + acl_msg_warn("%s(%d): fdp null", myname, __LINE__); + return; + } + + if (fdp->fdidx < 0 || fdp->fdidx >= eventp->fdcnt) { + acl_msg_warn("%s(%d): sockfd(%d)'s fdidx(%d) invalid", + myname, __LINE__, sockfd, fdp->fdidx); + return; + } + + if (!(fdp->flag & EVENT_FDTABLE_FLAG_WRITE)) { + acl_msg_warn("%s(%d): sockfd(%d) not be set", + myname, __LINE__, sockfd); + return; + } + + fdp->w_ttl = 0; + fdp->w_timeout = 0; + fdp->w_callback = NULL; + fdp->event_type &= ~ACL_EVENT_WRITE; + fdp->flag &= ~EVENT_FDTABLE_FLAG_WRITE; + + if ((fdp->flag & EVENT_FDTABLE_FLAG_READ)) { + ev->fds[fdp->fdidx].events = POLLIN | POLLHUP | POLLERR; + return; + } + + if (eventp->maxfd == sockfd) + eventp->maxfd = ACL_SOCKET_INVALID; + + if (fdp->fdidx < --eventp->fdcnt) { + ev->fds[fdp->fdidx] = ev->fds[eventp->fdcnt]; + eventp->fdtabs[fdp->fdidx] = eventp->fdtabs[eventp->fdcnt]; + eventp->fdtabs[fdp->fdidx]->fdidx = fdp->fdidx; + } + fdp->fdidx = -1; + + if (fdp->fdidx_ready >= 0 + && fdp->fdidx_ready < eventp->fdcnt_ready + && eventp->fdtabs_ready[fdp->fdidx_ready] == fdp) + { + eventp->fdtabs_ready[fdp->fdidx_ready] = NULL; + } + fdp->fdidx_ready = -1; + + acl_fdmap_del(ev->fdmap, sockfd); +} + +/* event_disable_readwrite - disable request for read or write events */ + +static void event_disable_readwrite(ACL_EVENT *eventp, ACL_VSTREAM *stream) +{ + const char *myname = "event_disable_readwrite"; + EVENT_POLL *ev = (EVENT_POLL *) eventp; + ACL_EVENT_FDTABLE *fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + ACL_SOCKET sockfd = ACL_VSTREAM_SOCK(stream); + + if (fdp == NULL) { + return; + } + + if (fdp->flag == 0 || fdp->fdidx < 0 || fdp->fdidx >= eventp->fdcnt) { + acl_msg_warn("%s(%d): sockfd(%d) no set, fdp no null", + myname, __LINE__, sockfd); + acl_fdmap_del(ev->fdmap, sockfd); + event_fdtable_free(fdp); + stream->fdp = NULL; + return; + } + + if (eventp->maxfd == sockfd) + eventp->maxfd = ACL_SOCKET_INVALID; + + if (fdp->fdidx < --eventp->fdcnt) { + ev->fds[fdp->fdidx] = ev->fds[eventp->fdcnt]; + eventp->fdtabs[fdp->fdidx] = eventp->fdtabs[eventp->fdcnt]; + eventp->fdtabs[fdp->fdidx]->fdidx = fdp->fdidx; + } + fdp->fdidx = -1; + + if (fdp->fdidx_ready >= 0 + && fdp->fdidx_ready < eventp->fdcnt_ready + && eventp->fdtabs_ready[fdp->fdidx_ready] == fdp) + { + eventp->fdtabs_ready[fdp->fdidx_ready] = NULL; + } + fdp->fdidx_ready = -1; + + acl_fdmap_del(ev->fdmap, sockfd); + event_fdtable_free(fdp); + stream->fdp = NULL; +} + +static void event_loop(ACL_EVENT *eventp) +{ + const char *myname = "event_loop"; + EVENT_POLL *ev = (EVENT_POLL *) eventp; + ACL_EVENT_NOTIFY_FN worker_fn; + void *worker_arg; + ACL_EVENT_TIMER *timer; + int delay, nready, i, revents; + ACL_EVENT_FDTABLE *fdp; + + delay = eventp->delay_sec * 1000 + eventp->delay_usec / 1000; + if (delay < 0) + delay = 0; /* 0 milliseconds at least */ + + /* 调整事件引擎的时间截 */ + + SET_TIME(eventp->event_present); + + /* 根据定时器任务的最近任务计算 poll 的检测超时上限 */ + + if ((timer = ACL_FIRST_TIMER(&eventp->timer_head)) != 0) { + acl_int64 n = timer->when - eventp->event_present; + if (n <= 0) + delay = 0; + else if ((int) n < delay) + delay = (int) n; + } + + /* 调用 event_prepare 检查有多少个描述字需要通过 poll 进行检测 */ + + if (event_prepare(eventp) == 0) { + + /* 说明无须 poll 检测 */ + + if (eventp->fdcnt_ready == 0) { + /* 为避免循环过快,休眠一下 */ + sleep(1); + } + goto TAG_DONE; + } + + /* 如果已经有描述字准备好则 poll 检测超时时间置 0 */ + + if (eventp->fdcnt_ready > 0) + delay = 0; + + /* 调用 poll 系统调用检测可用描述字 */ + + nready = poll(ev->fds, eventp->fdcnt, delay); + + if (eventp->nested++ > 0) + acl_msg_fatal("%s(%d): recursive call", myname, __LINE__); + if (nready < 0) { + if (acl_last_error() != ACL_EINTR) { + acl_msg_fatal("%s(%d), %s: select: %s", + __FILE__, __LINE__, myname, + acl_last_serror()); + } + goto TAG_DONE; + } else if (nready == 0) + goto TAG_DONE; + + /* 检查 poll 的检测结果集合 */ + + for (i = 0; i < eventp->fdcnt; i++) { + fdp = acl_fdmap_ctx(ev->fdmap, ev->fds[i].fd); + if (fdp == NULL || fdp->stream == NULL) + continue; + + /* 如果该描述字对象已经在被设置为异常或超时状态则继续 */ + + if ((fdp->event_type & (ACL_EVENT_XCPT | ACL_EVENT_RW_TIMEOUT))) + continue; + + revents = ev->fds[i].revents; + + /* 检查描述字是否出现异常 */ + + if ((revents & (POLLHUP | POLLERR)) != 0) { + fdp->event_type |= ACL_EVENT_XCPT; + fdp->fdidx_ready = eventp->fdcnt_ready; + eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp; + continue; + } + + /* 检查描述字是否可读 */ + + if ((fdp->flag & EVENT_FDTABLE_FLAG_READ) && (revents & POLLIN) ) { + + /* 该描述字可读则设置 ACL_VSTREAM 的系统可读标志从而触发 + * ACL_VSTREAM 流在读时调用系统的 read 函数 + */ + + fdp->stream->sys_read_ready = 1; + + /* 给该描述字对象附加可读属性 */ + + if ((fdp->event_type & (ACL_EVENT_READ | ACL_EVENT_WRITE)) == 0) + { + fdp->event_type |= ACL_EVENT_READ; + fdp->fdidx_ready = eventp->fdcnt_ready; + eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp; + } + } + + /* 检查描述字是否可写 */ + + if ((fdp->flag & EVENT_FDTABLE_FLAG_WRITE) && (revents & POLLOUT)) { + + /* 给该描述字对象附加可写属性 */ + + if ((fdp->event_type & (ACL_EVENT_READ | ACL_EVENT_WRITE)) == 0) + { + fdp->event_type |= ACL_EVENT_WRITE; + fdp->fdidx_ready = eventp->fdcnt_ready; + eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp; + } + } + } + +TAG_DONE: + + /* 调整事件引擎的时间截 */ + + SET_TIME(eventp->event_present); + + /* 优先处理定时器中的任务 */ + + while ((timer = ACL_FIRST_TIMER(&eventp->timer_head)) != 0) { + if (timer->when > eventp->event_present) + break; + worker_fn = timer->callback; + worker_arg = timer->context; + + /* 如果定时器的时间间隔 > 0 且允许定时器被循环调用,则再重设定时器 */ + if (timer->delay > 0 && timer->keep) { + timer->ncount++; + eventp->timer_request(eventp, timer->callback, + timer->context, timer->delay, timer->keep); + } else { + acl_ring_detach(&timer->ring); /* first this */ + timer->nrefer--; + if (timer->nrefer != 0) + acl_msg_fatal("%s(%d): nrefer(%d) != 0", + myname, __LINE__, timer->nrefer); + acl_myfree(timer); + } + worker_fn(ACL_EVENT_TIME, worker_arg); + } + + /* 处理准备好的描述字事件 */ + + if (eventp->fdcnt_ready > 0) + event_fire(eventp); + + eventp->nested--; +} + +static int event_isrset(ACL_EVENT *eventp acl_unused, ACL_VSTREAM *stream) +{ + ACL_EVENT_FDTABLE *fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + + return fdp == NULL ? 0 : (fdp->flag & EVENT_FDTABLE_FLAG_READ); +} + +static int event_iswset(ACL_EVENT *eventp acl_unused, ACL_VSTREAM *stream) +{ + ACL_EVENT_FDTABLE *fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + + return fdp == NULL ? 0 : (fdp->flag & EVENT_FDTABLE_FLAG_WRITE); + +} + +static int event_isxset(ACL_EVENT *eventp acl_unused, ACL_VSTREAM *stream) +{ + ACL_EVENT_FDTABLE *fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + + return fdp == NULL ? 0 : (fdp->flag & EVENT_FDTABLE_FLAG_EXPT); +} + +static void event_free(ACL_EVENT *eventp) +{ + EVENT_POLL *ev = (EVENT_POLL *) eventp; + + acl_fdmap_free(ev->fdmap); + acl_myfree(ev->fds); + acl_myfree(ev); +} + +ACL_EVENT *event_new_poll(int fdsize) +{ + ACL_EVENT *eventp; + EVENT_POLL *ev; + + eventp = event_alloc(sizeof(EVENT_POLL)); + + snprintf(eventp->name, sizeof(eventp->name), "events - poll"); + eventp->event_mode = ACL_EVENT_POLL; + eventp->use_thread = 0; + eventp->loop_fn = event_loop; + eventp->free_fn = event_free; + eventp->enable_read_fn = event_enable_read; + eventp->enable_write_fn = event_enable_write; + eventp->enable_listen_fn = event_enable_read; + eventp->disable_read_fn = event_disable_read; + eventp->disable_write_fn = event_disable_write; + eventp->disable_readwrite_fn = event_disable_readwrite; + eventp->isrset_fn = event_isrset; + eventp->iswset_fn = event_iswset; + eventp->isxset_fn = event_isxset; + eventp->timer_request = event_timer_request; + eventp->timer_cancel = event_timer_cancel; + eventp->timer_keep = event_timer_keep; + eventp->timer_ifkeep = event_timer_ifkeep; + + ev = (EVENT_POLL*) eventp; + ev->fds = (struct pollfd *) + acl_mycalloc(fdsize + 1, sizeof(struct pollfd)); + ev->fdmap = acl_fdmap_create(fdsize); + return eventp; +} +#endif /* ACL_EVENTS_POLL_STYLE */ diff --git a/lib_acl/src/event/events_poll_thr.c b/lib_acl/src/event/events_poll_thr.c new file mode 100644 index 000000000..4d29beeb1 --- /dev/null +++ b/lib_acl/src/event/events_poll_thr.c @@ -0,0 +1,509 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include +#include +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_sys_patch.h" +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_mystring.h" +#include "stdlib/acl_msg.h" +#include "stdlib/acl_ring.h" +#include "stdlib/acl_vstream.h" +#include "event/acl_events.h" + +#endif + +#include "events_define.h" + +#ifdef ACL_EVENTS_POLL_STYLE +#include +#include +#include "events_fdtable.h" +#include "events_dog.h" +#include "events.h" + +typedef struct EVENT_POLL_THR { + EVENT_THR event; + struct pollfd *fds; + ACL_FD_MAP *fdmap; +} EVENT_POLL_THR; + +static void event_enable_read(ACL_EVENT *eventp, ACL_VSTREAM *stream, + int timeout, ACL_EVENT_NOTIFY_RDWR callback, void *context) +{ + const char *myname = "event_enable_read"; + EVENT_POLL_THR *event_thr = (EVENT_POLL_THR *) eventp; + ACL_EVENT_FDTABLE *fdp; + ACL_SOCKET sockfd; + + sockfd = ACL_VSTREAM_SOCK(stream); + fdp = stream->fdp; + if (fdp == NULL) { + fdp = event_fdtable_alloc(); + fdp->listener = 0; + fdp->stream = stream; + stream->fdp = (void *) fdp; + } + /* 对同一连接的读写操作禁止同时进行监控 */ + else if (fdp->flag & EVENT_FDTABLE_FLAG_WRITE) + acl_msg_panic("%s(%d)->%s: fd %d: multiple I/O request", + __FILE__, __LINE__, myname, sockfd); + else { + fdp->listener = 0; + fdp->stream = stream; + } + + if (fdp->r_callback != callback || fdp->r_context != context) { + fdp->r_callback = callback; + fdp->r_context = context; + } + + if (timeout > 0) { + fdp->r_timeout = timeout * 1000000; + fdp->r_ttl = eventp->event_present + fdp->r_timeout; + } else { + fdp->r_ttl = 0; + fdp->r_timeout = 0; + } + + THREAD_LOCK(&event_thr->event.tb_mutex); + + if ((fdp->flag & EVENT_FDTABLE_FLAG_READ) == 0) { + fdp->flag = EVENT_FDTABLE_FLAG_READ | EVENT_FDTABLE_FLAG_EXPT; + stream->nrefer++; + fdp->fdidx = eventp->fdcnt; + eventp->fdtabs[eventp->fdcnt] = fdp; + eventp->fdcnt++; + + event_thr->fds[fdp->fdidx].fd = sockfd; + event_thr->fds[fdp->fdidx].events = POLLIN | POLLHUP | POLLERR; + acl_fdmap_add(event_thr->fdmap, sockfd, fdp); + + if (eventp->maxfd != ACL_SOCKET_INVALID && eventp->maxfd < sockfd) + eventp->maxfd = sockfd; + } + + THREAD_UNLOCK(&event_thr->event.tb_mutex); + + /* 主要是为了减少通知次数 */ + if (event_thr->event.blocked && event_thr->event.evdog + && event_dog_client(event_thr->event.evdog) != stream) + event_dog_notify(event_thr->event.evdog); +} + +static void event_enable_listen(ACL_EVENT *eventp, ACL_VSTREAM *stream, + int timeout, ACL_EVENT_NOTIFY_RDWR callback, void *context) +{ + const char *myname = "event_enable_listen"; + EVENT_POLL_THR *event_thr = (EVENT_POLL_THR *) eventp; + ACL_EVENT_FDTABLE *fdp; + ACL_SOCKET sockfd; + + sockfd = ACL_VSTREAM_SOCK(stream); + fdp = stream->fdp; + if (fdp == NULL) { + fdp = event_fdtable_alloc(); + fdp->listener = 1; + fdp->stream = stream; + stream->fdp = (void *) fdp; + } + /* 对同一连接的读写操作禁止同时进行监控 */ + else if (fdp->flag & EVENT_FDTABLE_FLAG_WRITE) + acl_msg_panic("%s(%d)->%s: fd %d: multiple I/O request", + __FILE__, __LINE__, myname, sockfd); + else { + fdp->listener = 1; + fdp->stream = stream; + } + + if (fdp->r_callback != callback || fdp->r_context != context) { + fdp->r_callback = callback; + fdp->r_context = context; + } + + if (timeout > 0) { + fdp->r_timeout = timeout * 1000000; + fdp->r_ttl = eventp->event_present + fdp->r_timeout; + } else { + fdp->r_ttl = 0; + fdp->r_timeout = 0; + } + + THREAD_LOCK(&event_thr->event.tb_mutex); + + if ((fdp->flag & EVENT_FDTABLE_FLAG_READ) == 0) { + fdp->flag = EVENT_FDTABLE_FLAG_READ | EVENT_FDTABLE_FLAG_EXPT; + stream->nrefer++; + fdp->fdidx = eventp->fdcnt; + eventp->fdtabs[eventp->fdcnt] = fdp; + eventp->fdcnt++; + + event_thr->fds[fdp->fdidx].fd = sockfd; + event_thr->fds[fdp->fdidx].events = POLLIN | POLLHUP | POLLERR; + acl_fdmap_add(event_thr->fdmap, sockfd, fdp); + + if (eventp->maxfd != ACL_SOCKET_INVALID && eventp->maxfd < sockfd) + eventp->maxfd = sockfd; + } + + THREAD_UNLOCK(&event_thr->event.tb_mutex); +} + +static void event_enable_write(ACL_EVENT *eventp, ACL_VSTREAM *stream, + int timeout, ACL_EVENT_NOTIFY_RDWR callback, void *context) +{ + const char *myname = "event_enable_write"; + EVENT_POLL_THR *event_thr = (EVENT_POLL_THR *) eventp; + ACL_EVENT_FDTABLE *fdp; + ACL_SOCKET sockfd; + + sockfd = ACL_VSTREAM_SOCK(stream); + fdp = (ACL_EVENT_FDTABLE*) stream->fdp; + if (fdp == NULL) { + fdp = event_fdtable_alloc(); + fdp->listener = 0; + fdp->stream = stream; + stream->fdp = (void *) fdp; + } + /* 对同一连接的读写操作禁止同时进行监控 */ + else if (fdp->flag & EVENT_FDTABLE_FLAG_READ) + acl_msg_panic("%s(%d)->%s: fd %d: multiple I/O request", + __FILE__, __LINE__, myname, sockfd); + else { + fdp->listener = 0; + fdp->stream = stream; + } + + if (fdp->w_callback != callback || fdp->w_context != context) { + fdp->w_callback = callback; + fdp->w_context = context; + } + + if (timeout > 0) { + fdp->w_timeout = timeout * 1000000; + fdp->w_ttl = eventp->event_present + fdp->w_timeout; + } else { + fdp->w_ttl = 0; + fdp->w_timeout = 0; + } + + THREAD_LOCK(&event_thr->event.tb_mutex); + + if ((fdp->flag & EVENT_FDTABLE_FLAG_WRITE) == 0) { + fdp->flag = EVENT_FDTABLE_FLAG_WRITE | EVENT_FDTABLE_FLAG_EXPT; + stream->nrefer++; + fdp->fdidx = eventp->fdcnt; + eventp->fdtabs[eventp->fdcnt] = fdp; + eventp->fdcnt++; + + event_thr->fds[fdp->fdidx].fd = sockfd; + event_thr->fds[fdp->fdidx].events = POLLOUT | POLLHUP | POLLERR; + acl_fdmap_add(event_thr->fdmap, sockfd, fdp); + + if (eventp->maxfd != ACL_SOCKET_INVALID && eventp->maxfd < sockfd) + eventp->maxfd = sockfd; + } + + THREAD_UNLOCK(&event_thr->event.tb_mutex); + + if (event_thr->event.blocked && event_thr->event.evdog + && event_dog_client(event_thr->event.evdog) != stream) + event_dog_notify(event_thr->event.evdog); +} + +/* event_disable_readwrite - disable request for read or write events */ + +static void event_disable_readwrite(ACL_EVENT *eventp, ACL_VSTREAM *stream) +{ + const char *myname = "event_disable_readwrite"; + EVENT_POLL_THR *event_thr = (EVENT_POLL_THR *) eventp; + ACL_EVENT_FDTABLE *fdp; + ACL_SOCKET sockfd; + + sockfd = ACL_VSTREAM_SOCK(stream); + fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + if (fdp == NULL) { + acl_msg_error("%s(%d): fdp null", myname, __LINE__); + return; + } + + if ((fdp->flag & (EVENT_FDTABLE_FLAG_READ | EVENT_FDTABLE_FLAG_WRITE)) == 0) { + acl_msg_error("%s(%d): sockfd(%d) not be set", + myname, __LINE__, sockfd); + return; + } + if (fdp->fdidx == -1) + acl_msg_fatal("%s(%d): fdidx(%d) invalid", + myname, __LINE__, fdp->fdidx); + + THREAD_LOCK(&event_thr->event.tb_mutex); + + if (eventp->maxfd == sockfd) + eventp->maxfd = ACL_SOCKET_INVALID; + + if (eventp->fdtabs[fdp->fdidx] != fdp) + acl_msg_fatal("%s(%d): fdidx(%d)'s fdp invalid", + myname, __LINE__, fdp->fdidx); + + if (fdp->fdidx < --eventp->fdcnt) { + eventp->fdtabs[fdp->fdidx] = eventp->fdtabs[eventp->fdcnt]; + eventp->fdtabs[fdp->fdidx]->fdidx = fdp->fdidx; + event_thr->fds[fdp->fdidx] = event_thr->fds[eventp->fdcnt]; + } + + if (fdp->fdidx_ready > 0 + && fdp->fdidx_ready < eventp->fdcnt_ready + && eventp->fdtabs_ready[fdp->fdidx_ready] == fdp) + { + eventp->fdtabs_ready[fdp->fdidx_ready] = NULL; + } + + acl_fdmap_del(event_thr->fdmap, sockfd); + + THREAD_UNLOCK(&event_thr->event.tb_mutex); + + if (fdp->flag & EVENT_FDTABLE_FLAG_READ) + stream->nrefer--; + if (fdp->flag & EVENT_FDTABLE_FLAG_WRITE) + stream->nrefer--; + + event_fdtable_reset(fdp); +} + +static int event_isrset(ACL_EVENT *eventp acl_unused, ACL_VSTREAM *stream) +{ + ACL_EVENT_FDTABLE *fdp; + + fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + if (fdp == NULL) + return 0; + + return (fdp->flag & EVENT_FDTABLE_FLAG_READ) == 0 ? 0 : 1; +} + +static int event_iswset(ACL_EVENT *eventp acl_unused, ACL_VSTREAM *stream) +{ + ACL_EVENT_FDTABLE *fdp; + + fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + if (fdp == NULL) + return 0; + + return (fdp->flag & EVENT_FDTABLE_FLAG_WRITE) == 0 ? 0 : 1; +} + +static int event_isxset(ACL_EVENT *eventp acl_unused, ACL_VSTREAM *stream) +{ + ACL_EVENT_FDTABLE *fdp; + + fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + if (fdp == NULL) + return 0; + + return (fdp->flag & EVENT_FDTABLE_FLAG_EXPT) == 0 ? 0 : 1; +} + +static void event_loop(ACL_EVENT *eventp) +{ + const char *myname = "event_loop"; + EVENT_POLL_THR *event_thr = (EVENT_POLL_THR *) eventp; + ACL_EVENT_NOTIFY_FN worker_fn; + void *worker_arg; + ACL_EVENT_TIMER *timer; + int n, delay, nready, i, revents; + ACL_EVENT_FDTABLE *fdp; + ACL_RING timer_ring, *entry_ptr; + + acl_ring_init(&timer_ring); + + delay = eventp->delay_sec * 1000 + eventp->delay_usec / 1000; + if (delay <= 0) + delay = 100; /* 100 milliseconds at least */ + + SET_TIME(eventp->event_present); + THREAD_LOCK(&event_thr->event.tm_mutex); + /* + * Find out when the next timer would go off. Timer requests are sorted. + * If any timer is scheduled, adjust the delay appropriately. + */ + if ((timer = ACL_FIRST_TIMER(&eventp->timer_head)) != 0) { + n = (int) (timer->when - eventp->event_present + 1000000 - 1) + / 1000000; + if (n <= 0) + delay = 0; + else if (n < eventp->delay_sec) + delay = n * 1000 + eventp->delay_usec / 1000; + } + + THREAD_UNLOCK(&event_thr->event.tm_mutex); + + THREAD_LOCK(&event_thr->event.tb_mutex); + + if (event_thr_prepare(eventp) == 0) { + if (eventp->fdcnt_ready == 0) + sleep(1); + + THREAD_UNLOCK(&event_thr->event.tb_mutex); + goto TAG_DONE; + } + + if (eventp->fdcnt_ready > 0) + delay = 0; + + THREAD_UNLOCK(&event_thr->event.tb_mutex); + + event_thr->event.blocked = 1; + nready = poll(event_thr->fds, eventp->fdcnt, delay); + event_thr->event.blocked = 0; + + if (nready < 0) { + if (acl_last_error() != ACL_EINTR) { + acl_msg_fatal("%s(%d), %s: event_loop: select: %s", + __FILE__, __LINE__, myname, acl_last_serror()); + } + goto TAG_DONE; + } else if (nready == 0) + goto TAG_DONE; + + THREAD_LOCK(&event_thr->event.tb_mutex); + + for (i = 0; i < eventp->fdcnt; i++) { + fdp = acl_fdmap_ctx(event_thr->fdmap, event_thr->fds[i].fd); + if (fdp == NULL || fdp->stream == NULL) + continue; + if ((fdp->event_type & (ACL_EVENT_XCPT | ACL_EVENT_RW_TIMEOUT))) + continue; + + revents = event_thr->fds[i].revents; + if ((revents & (POLLHUP | POLLERR)) != 0) { + fdp->event_type |= ACL_EVENT_XCPT; + fdp->fdidx_ready = eventp->fdcnt_ready; + eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp; + continue; + } + + if ((fdp->flag & EVENT_FDTABLE_FLAG_READ) && (revents & POLLIN)) { + fdp->stream->sys_read_ready = 1; + if ((fdp->event_type & ACL_EVENT_READ) == 0) { + fdp->event_type |= ACL_EVENT_READ; + fdp->fdidx_ready = eventp->fdcnt_ready; + eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp; + } + } else if ((fdp->flag & EVENT_FDTABLE_FLAG_WRITE) && (revents & POLLOUT)) { + fdp->event_type |= ACL_EVENT_WRITE; + fdp->fdidx_ready = eventp->fdcnt_ready; + eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp; + } + } + + THREAD_UNLOCK(&event_thr->event.tb_mutex); + +TAG_DONE: + + /* + * Deliver timer events. Requests are sorted: we can stop when we reach + * the future or the list end. Allow the application to update the timer + * queue while it is being called back. To this end, we repeatedly pop + * the first request off the timer queue before delivering the event to + * the application. + */ + + SET_TIME(eventp->event_present); + + THREAD_LOCK(&event_thr->event.tm_mutex); + + while ((timer = ACL_FIRST_TIMER(&eventp->timer_head)) != 0) { + if (timer->when > eventp->event_present) + break; + + acl_ring_detach(&timer->ring); /* first this */ + acl_ring_prepend(&timer_ring, &timer->ring); + } + + THREAD_UNLOCK(&event_thr->event.tm_mutex); + + while (1) { + entry_ptr = acl_ring_pop_head(&timer_ring); + if (entry_ptr == NULL) + break; + + timer = ACL_RING_TO_TIMER(entry_ptr); + worker_fn = timer->callback; + worker_arg = timer->context; + + worker_fn(ACL_EVENT_TIME, worker_arg); + + acl_myfree(timer); + } + + event_thr_fire(eventp); +} + +static void event_add_dog(ACL_EVENT *eventp) +{ + EVENT_POLL_THR *event_thr = (EVENT_POLL_THR*) eventp; + + event_thr->event.evdog = event_dog_create((ACL_EVENT*) event_thr, 1); +} + +static void event_free(ACL_EVENT *eventp) +{ + const char *myname = "event_free"; + EVENT_POLL_THR *event_thr = (EVENT_POLL_THR *) eventp; + + if (eventp == NULL) + acl_msg_fatal("%s, %s(%d): eventp null", + __FILE__, myname, __LINE__); + + LOCK_DESTROY(&event_thr->event.tm_mutex); + LOCK_DESTROY(&event_thr->event.tb_mutex); + + acl_fdmap_free(event_thr->fdmap); + acl_myfree(event_thr->fds); + acl_myfree(eventp); +} + +ACL_EVENT *event_new_poll_thr(int fdsize) +{ + EVENT_POLL_THR *event_thr; + + event_thr = (EVENT_POLL_THR*) event_alloc(sizeof(EVENT_POLL_THR)); + + snprintf(event_thr->event.event.name, sizeof(event_thr->event.event.name), + "thread events - poll" ); + event_thr->event.event.event_mode = ACL_EVENT_POLL; + event_thr->event.event.use_thread = 1; + event_thr->event.event.loop_fn = event_loop; + event_thr->event.event.free_fn = event_free; + event_thr->event.event.add_dog_fn = event_add_dog; + event_thr->event.event.enable_read_fn = event_enable_read; + event_thr->event.event.enable_write_fn = event_enable_write; + event_thr->event.event.enable_listen_fn = event_enable_listen; + event_thr->event.event.disable_readwrite_fn = event_disable_readwrite; + event_thr->event.event.isrset_fn = event_isrset; + event_thr->event.event.iswset_fn = event_iswset; + event_thr->event.event.isxset_fn = event_isxset; + event_thr->event.event.timer_request = event_timer_request_thr; + event_thr->event.event.timer_cancel = event_timer_cancel_thr; + event_thr->event.event.timer_keep = event_timer_keep_thr; + event_thr->event.event.timer_ifkeep = event_timer_ifkeep_thr; + + LOCK_INIT(&event_thr->event.tm_mutex); + LOCK_INIT(&event_thr->event.tb_mutex); + + event_thr->fds = (struct pollfd *) acl_mycalloc(fdsize + 1, sizeof(struct pollfd)); + event_thr->fdmap = acl_fdmap_create(fdsize); + return (ACL_EVENT *) event_thr; +} + +#endif /* ACL_EVENTS_POLL_STYLE */ diff --git a/lib_acl/src/event/events_select.c b/lib_acl/src/event/events_select.c new file mode 100644 index 000000000..2dadf7535 --- /dev/null +++ b/lib_acl/src/event/events_select.c @@ -0,0 +1,590 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include +#include +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#ifdef ACL_UNIX +#include +#endif + +#include "stdlib/acl_sys_patch.h" +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_mystring.h" +#include "stdlib/acl_msg.h" +#include "stdlib/acl_debug.h" +#include "stdlib/acl_vstream.h" +#include "event/acl_events.h" + +#endif + +#include "events.h" +#include "events_fdtable.h" + +typedef struct EVENT_SELECT { + ACL_EVENT event; + fd_set rmask; + fd_set wmask; + fd_set xmask; +} EVENT_SELECT; + +static void stream_on_close(ACL_VSTREAM *stream, void *arg) +{ + EVENT_SELECT *ev = (EVENT_SELECT*) arg; + ACL_EVENT_FDTABLE *fdp = (ACL_EVENT_FDTABLE*) stream->fdp; + ACL_SOCKET sockfd = ACL_VSTREAM_SOCK(stream); + + if (fdp == NULL) + return; + + FD_CLR(sockfd, &ev->xmask); + + if ((fdp->flag & EVENT_FDTABLE_FLAG_READ) + && (fdp->flag & EVENT_FDTABLE_FLAG_WRITE)) + { + FD_CLR(sockfd, &ev->rmask); + FD_CLR(sockfd, &ev->wmask); + } else if ((fdp->flag & EVENT_FDTABLE_FLAG_READ)) { + FD_CLR(sockfd, &ev->rmask); + } else if ((fdp->flag & EVENT_FDTABLE_FLAG_WRITE)) { + FD_CLR(sockfd, &ev->wmask); + } + + if (ev->event.maxfd == ACL_VSTREAM_SOCK(fdp->stream)) + ev->event.maxfd = ACL_SOCKET_INVALID; + if (fdp->fdidx >= 0 && fdp->fdidx < --ev->event.fdcnt) { + ev->event.fdtabs[fdp->fdidx] = ev->event.fdtabs[ev->event.fdcnt]; + ev->event.fdtabs[fdp->fdidx]->fdidx = fdp->fdidx; + fdp->fdidx = -1; + } + + if (fdp->fdidx_ready >= 0 + && fdp->fdidx_ready < ev->event.fdcnt_ready + && ev->event.fdtabs_ready[fdp->fdidx_ready] == fdp) + { + ev->event.fdtabs_ready[fdp->fdidx_ready] = NULL; + fdp->fdidx_ready = -1; + } + event_fdtable_free(fdp); + stream->fdp = NULL; +} + +static void event_enable_read(ACL_EVENT *eventp, ACL_VSTREAM *stream, + int timeout, ACL_EVENT_NOTIFY_RDWR callback, void *context) +{ + EVENT_SELECT *ev = (EVENT_SELECT *) eventp; + ACL_SOCKET sockfd = ACL_VSTREAM_SOCK(stream); + ACL_EVENT_FDTABLE *fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + + if (fdp == NULL) { + fdp = event_fdtable_alloc(); + + fdp->stream = stream; + stream->fdp = (void *) fdp; + acl_vstream_add_close_handle(stream, stream_on_close, eventp); + } + + if (fdp->fdidx == -1) { + fdp->fdidx = eventp->fdcnt; + eventp->fdtabs[eventp->fdcnt++] = fdp; + } + + if ((fdp->flag & EVENT_FDTABLE_FLAG_WRITE)) { + fdp->flag |= EVENT_FDTABLE_FLAG_READ; + } else { + fdp->flag = EVENT_FDTABLE_FLAG_READ | EVENT_FDTABLE_FLAG_EXPT; + } + FD_SET(sockfd, &ev->rmask); + FD_SET(sockfd, &ev->xmask); + + if (eventp->maxfd != ACL_SOCKET_INVALID && eventp->maxfd < sockfd) + eventp->maxfd = sockfd; + + if (fdp->r_callback != callback || fdp->r_context != context) { + fdp->r_callback = callback; + fdp->r_context = context; + } + + if (timeout > 0) { + fdp->r_timeout = timeout * 1000000; + fdp->r_ttl = eventp->event_present + fdp->r_timeout; + } else { + fdp->r_ttl = 0; + fdp->r_timeout = 0; + } +} + +static void event_enable_write(ACL_EVENT *eventp, ACL_VSTREAM *stream, + int timeout, ACL_EVENT_NOTIFY_RDWR callback, void *context) +{ + EVENT_SELECT *ev = (EVENT_SELECT *) eventp; + ACL_SOCKET sockfd = ACL_VSTREAM_SOCK(stream); + ACL_EVENT_FDTABLE *fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + + if (fdp == NULL) { + fdp = event_fdtable_alloc(); + + fdp->stream = stream; + stream->fdp = (void *) fdp; + acl_vstream_add_close_handle(stream, stream_on_close, eventp); + } + + if (fdp->fdidx == -1) { + fdp->fdidx = eventp->fdcnt; + eventp->fdtabs[eventp->fdcnt++] = fdp; + } + + if ((fdp->flag & EVENT_FDTABLE_FLAG_READ)) { + fdp->flag |= EVENT_FDTABLE_FLAG_WRITE; + } else { + fdp->flag = EVENT_FDTABLE_FLAG_WRITE | EVENT_FDTABLE_FLAG_EXPT; + } + FD_SET(sockfd, &ev->wmask); + FD_SET(sockfd, &ev->xmask); + + if (eventp->maxfd != ACL_SOCKET_INVALID && eventp->maxfd < sockfd) + eventp->maxfd = sockfd; + + if (fdp->w_callback != callback || fdp->w_context != context) { + fdp->w_callback = callback; + fdp->w_context = context; + } + + if (timeout > 0) { + fdp->w_timeout = timeout * 1000000; + fdp->w_ttl = eventp->event_present + fdp->w_timeout; + } else { + fdp->w_ttl = 0; + fdp->w_timeout = 0; + } +} + +/* event_disable_read - disable request for read events */ + +static void event_disable_read(ACL_EVENT *eventp, ACL_VSTREAM *stream) +{ + const char *myname = "event_disable_read"; + EVENT_SELECT *ev = (EVENT_SELECT *) eventp; + ACL_SOCKET sockfd = ACL_VSTREAM_SOCK(stream); + ACL_EVENT_FDTABLE *fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + + if (fdp == NULL) { + acl_msg_warn("%s(%d): fdp null", myname, __LINE__); + return; + } + + if (fdp->fdidx < 0 || fdp->fdidx >= eventp->fdcnt) { + acl_msg_warn("%s(%d): sockfd(%d)'s fdidx invalid", + myname, __LINE__, sockfd); + return; + } + + if (!(fdp->flag & EVENT_FDTABLE_FLAG_READ)) { + acl_msg_warn("%s(%d): sockfd(%d) not in rmask", + myname, __LINE__, sockfd); + return; + } + + fdp->r_ttl = 0; + fdp->r_timeout = 0; + fdp->r_callback = NULL; + fdp->event_type &= ~ACL_EVENT_READ; + fdp->flag &= ~EVENT_FDTABLE_FLAG_READ; + + if ((fdp->flag & EVENT_FDTABLE_FLAG_WRITE)) { + FD_CLR(sockfd, &ev->rmask); + return; + } + + if (eventp->maxfd == sockfd) + eventp->maxfd = ACL_SOCKET_INVALID; + + if (fdp->fdidx < --eventp->fdcnt) { + eventp->fdtabs[fdp->fdidx] = eventp->fdtabs[eventp->fdcnt]; + eventp->fdtabs[fdp->fdidx]->fdidx = fdp->fdidx; + } + fdp->fdidx = -1; + + if (fdp->fdidx_ready >= 0 + && fdp->fdidx_ready < eventp->fdcnt_ready + && eventp->fdtabs_ready[fdp->fdidx_ready] == fdp) + { + eventp->fdtabs_ready[fdp->fdidx_ready] = NULL; + } + fdp->fdidx_ready = -1; + + FD_CLR(sockfd, &ev->xmask); + FD_CLR(sockfd, &ev->rmask); +#if 0 + event_fdtable_free(fdp); + stream->fdp = NULL; +#endif +} + +/* event_disable_write - disable request for write events */ + +static void event_disable_write(ACL_EVENT *eventp, ACL_VSTREAM *stream) +{ + const char *myname = "event_disable_write"; + EVENT_SELECT *ev = (EVENT_SELECT *) eventp; + ACL_SOCKET sockfd = ACL_VSTREAM_SOCK(stream); + ACL_EVENT_FDTABLE *fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + + if (fdp == NULL) { + acl_msg_warn("%s(%d): fdp null", myname, __LINE__); + return; + } + + if (fdp->fdidx < 0 || fdp->fdidx >= eventp->fdcnt) { + acl_msg_warn("%s(%d): sockfd(%d)'s fdidx invalid", + myname, __LINE__, sockfd); + return; + } + + if (!(fdp->flag & EVENT_FDTABLE_FLAG_WRITE)) { + acl_msg_warn("%s(%d): sockfd(%d) not in wmask", + myname, __LINE__, sockfd); + return; + } + + fdp->w_ttl = 0; + fdp->w_timeout = 0; + fdp->w_callback = NULL; + fdp->event_type &= ~ACL_EVENT_WRITE; + fdp->flag &= ~EVENT_FDTABLE_FLAG_WRITE; + + if ((fdp->flag & EVENT_FDTABLE_FLAG_READ)) { + FD_CLR(sockfd, &ev->wmask); + return; + } + + if (eventp->maxfd == sockfd) + eventp->maxfd = ACL_SOCKET_INVALID; + + if (fdp->fdidx < --eventp->fdcnt) { + eventp->fdtabs[fdp->fdidx] = eventp->fdtabs[eventp->fdcnt]; + eventp->fdtabs[fdp->fdidx]->fdidx = fdp->fdidx; + } + fdp->fdidx = -1; + + if (fdp->fdidx_ready >= 0 + && fdp->fdidx_ready < eventp->fdcnt_ready + && eventp->fdtabs_ready[fdp->fdidx_ready] == fdp) + { + eventp->fdtabs_ready[fdp->fdidx_ready] = NULL; + } + fdp->fdidx_ready = -1; + + FD_CLR(sockfd, &ev->xmask); + FD_CLR(sockfd, &ev->wmask); +#if 0 + event_fdtable_free(fdp); + stream->fdp = NULL; +#endif +} + +/* event_disable_readwrite - disable request for read or write events */ + +static void event_disable_readwrite(ACL_EVENT *eventp, ACL_VSTREAM *stream) +{ + const char *myname = "event_disable_readwrite"; + EVENT_SELECT *ev = (EVENT_SELECT *) eventp; + ACL_EVENT_FDTABLE *fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + ACL_SOCKET sockfd = ACL_VSTREAM_SOCK(stream); + + if (fdp == NULL) { + return; + } + + if (fdp->flag == 0 || fdp->fdidx < 0 || fdp->fdidx >= eventp->fdcnt) { + acl_msg_warn("%s(%d): sockfd(%d) no set, fdp no null", + myname, __LINE__, sockfd); + event_fdtable_free(fdp); + stream->fdp = NULL; + return; + } + + if (!FD_ISSET(sockfd, &ev->rmask) && !FD_ISSET(sockfd, &ev->wmask)) { + acl_msg_error("%s(%d): sockfd(%d) no set, fdp no null", + myname, __LINE__, sockfd); + event_fdtable_free(fdp); + stream->fdp = NULL; + return; + } + + if (eventp->maxfd == sockfd) + eventp->maxfd = ACL_SOCKET_INVALID; + + if (fdp->fdidx < --eventp->fdcnt) { + eventp->fdtabs[fdp->fdidx] = eventp->fdtabs[eventp->fdcnt]; + eventp->fdtabs[fdp->fdidx]->fdidx = fdp->fdidx; + } + fdp->fdidx = -1; + + if (FD_ISSET(sockfd, &ev->rmask)) { + FD_CLR(sockfd, &ev->rmask); + } + if (FD_ISSET(sockfd, &ev->wmask)) { + FD_CLR(sockfd, &ev->wmask); + } + FD_CLR(sockfd, &ev->xmask); + + if (fdp->fdidx_ready >= 0 + && fdp->fdidx_ready < eventp->fdcnt_ready + && eventp->fdtabs_ready[fdp->fdidx_ready] == fdp) + { + eventp->fdtabs_ready[fdp->fdidx_ready] = NULL; + } + fdp->fdidx_ready = -1; + event_fdtable_free(fdp); + stream->fdp = NULL; +} + +static void event_loop(ACL_EVENT *eventp) +{ + const char *myname = "event_loop"; + EVENT_SELECT *ev = (EVENT_SELECT *) eventp; + ACL_EVENT_NOTIFY_FN worker_fn; + void *worker_arg; + ACL_SOCKET sockfd; + ACL_EVENT_TIMER *timer; + int nready, i; + acl_int64 delay; + ACL_EVENT_FDTABLE *fdp; + struct timeval tv, *tvp; + fd_set rmask; /* enabled read events */ + fd_set wmask; /* enabled write events */ + fd_set xmask; /* for bad news mostly */ + + delay = eventp->delay_sec * 1000000 + eventp->delay_usec; + + /* 调整事件引擎的时间截 */ + + SET_TIME(eventp->event_present); + + /* 根据定时器任务的最近任务计算 select 的检测超时上限 */ + + if ((timer = ACL_FIRST_TIMER(&eventp->timer_head)) != 0) { + acl_int64 n = timer->when - eventp->event_present; + + if (n <= 0) + delay = 0; + else if (n < delay) + delay = n; + } + + /* 调用 event_prepare 检查有多少个描述字需要通过 select 进行检测 */ + + if (event_prepare(eventp) == 0) { + if (eventp->fdcnt_ready == 0) { + if (delay <= 0) + delay = 1; + /* 为避免循环过快,休眠一下 */ + sleep((int) delay); + } + + goto TAG_DONE; + } + + if (eventp->fdcnt_ready > 0) { + tv.tv_sec = 0; + tv.tv_usec = 0; + tvp = &tv; + } else if (delay >= 0) { + tv.tv_sec = (long) delay / 1000000; + tv.tv_usec = (long) delay - tv.tv_sec * 1000000; + tvp = &tv; + } else + tvp = NULL; + + rmask = ev->rmask; + wmask = ev->wmask; + xmask = ev->xmask; + + /* 调用 select 系统调用检测可用描述字 */ + +#ifdef ACL_MS_WINDOWS + nready = select(0, &rmask, &wmask, &xmask, tvp); +#else + nready = select(eventp->maxfd + 1, &rmask, &wmask, &xmask, tvp); +#endif + + if (eventp->nested++ > 0) + acl_msg_fatal("%s(%d): recursive call(%d)", + myname, __LINE__, eventp->nested); + if (nready < 0) { + if (acl_last_error() != ACL_EINTR) { + acl_msg_fatal("%s(%d), %s: select: %s", + __FILE__, __LINE__, myname, acl_last_serror()); + } + goto TAG_DONE; + } else if (nready == 0) + goto TAG_DONE; + + /* 检查 select 的检测结果集合 */ + + /* if some fdp was cleared from eventp->fdtabs in timer callback, + * which has no effection on the rest fdp in eventp->fdtabs + */ + + for (i = 0; i < eventp->fdcnt; i++) { + fdp = eventp->fdtabs[i]; + + /* 如果该描述字对象已经在被设置为异常或超时状态则继续 */ + + if ((fdp->event_type & (ACL_EVENT_XCPT | ACL_EVENT_RW_TIMEOUT))) + continue; + + sockfd = ACL_VSTREAM_SOCK(fdp->stream); + + /* 检查描述字是否出现异常 */ + + if (FD_ISSET(sockfd, &xmask)) { + fdp->event_type |= ACL_EVENT_XCPT; + fdp->fdidx_ready = eventp->fdcnt_ready; + eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp; + continue; + } + + /* 检查描述字是否可读 */ + + if (FD_ISSET(sockfd, &rmask)) { + + /* 该描述字可读则设置 ACL_VSTREAM 的系统可读标志从而触发 + * ACL_VSTREAM 流在读时调用系统的 read 函数 + */ + + fdp->stream->sys_read_ready = 1; + + /* 给该描述字对象附加可读属性 */ + + if ((fdp->event_type & (ACL_EVENT_READ | ACL_EVENT_WRITE)) == 0) + { + fdp->event_type |= ACL_EVENT_READ; + fdp->fdidx_ready = eventp->fdcnt_ready; + eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp; + } + } + + /* 检查描述字是否可写 */ + + if (FD_ISSET(sockfd, &wmask)) { + + /* 给该描述字对象附加可写属性 */ + + if ((fdp->event_type & (ACL_EVENT_READ | ACL_EVENT_WRITE)) == 0) + { + fdp->event_type |= ACL_EVENT_WRITE; + fdp->fdidx_ready = eventp->fdcnt_ready; + eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp; + } + } + } + +TAG_DONE: + + /* 调整事件引擎的时间截 */ + + SET_TIME(eventp->event_present); + + /* 优先处理定时器中的任务 */ + + while ((timer = ACL_FIRST_TIMER(&eventp->timer_head)) != 0) { + if (timer->when > eventp->event_present) + break; + worker_fn = timer->callback; + worker_arg = timer->context; + + /* 如果定时器的时间间隔 > 0 且允许定时器被循环调用,则再重设定时器 */ + if (timer->delay > 0 && timer->keep) { + timer->ncount++; + eventp->timer_request(eventp, timer->callback, + timer->context, timer->delay, timer->keep); + } else { + acl_ring_detach(&timer->ring); /* first this */ + timer->nrefer--; + if (timer->nrefer != 0) + acl_msg_fatal("%s(%d): nrefer(%d) != 0", + myname, __LINE__, timer->nrefer); + acl_myfree(timer); + } + worker_fn(ACL_EVENT_TIME, worker_arg); + } + + /* 处理准备好的描述字事件 */ + + if (eventp->fdcnt_ready > 0) + event_fire(eventp); + + eventp->nested--; +} + +static int event_isrset(ACL_EVENT *eventp, ACL_VSTREAM *stream) +{ + EVENT_SELECT *ev = (EVENT_SELECT *) eventp; + + return FD_ISSET(ACL_VSTREAM_SOCK(stream), &ev->rmask); +} + +static int event_iswset(ACL_EVENT *eventp, ACL_VSTREAM *stream) +{ + EVENT_SELECT *ev = (EVENT_SELECT *) eventp; + + return FD_ISSET(ACL_VSTREAM_SOCK(stream), &ev->wmask); +} + +static int event_isxset(ACL_EVENT *eventp, ACL_VSTREAM *stream) +{ + EVENT_SELECT *ev = (EVENT_SELECT *) eventp; + + return FD_ISSET(ACL_VSTREAM_SOCK(stream), &ev->xmask); +} + +static void event_free(ACL_EVENT *eventp) +{ + EVENT_SELECT *ev = (EVENT_SELECT *) eventp; + + acl_myfree(ev); +} + +ACL_EVENT *event_new_select(void) +{ + ACL_EVENT *eventp; + EVENT_SELECT *ev; + + eventp = event_alloc(sizeof(EVENT_SELECT)); + + snprintf(eventp->name, sizeof(eventp->name), "events - select"); + eventp->event_mode = ACL_EVENT_SELECT; + eventp->use_thread = 0; + eventp->loop_fn = event_loop; + eventp->free_fn = event_free; + eventp->enable_read_fn = event_enable_read; + eventp->enable_write_fn = event_enable_write; + eventp->enable_listen_fn = event_enable_read; + eventp->disable_read_fn = event_disable_read; + eventp->disable_write_fn = event_disable_write; + eventp->disable_readwrite_fn = event_disable_readwrite; + eventp->isrset_fn = event_isrset; + eventp->iswset_fn = event_iswset; + eventp->isxset_fn = event_isxset; + eventp->timer_request = event_timer_request; + eventp->timer_cancel = event_timer_cancel; + eventp->timer_keep = event_timer_keep; + eventp->timer_ifkeep = event_timer_ifkeep; + + ev = (EVENT_SELECT*) eventp; + FD_ZERO(&ev->rmask); + FD_ZERO(&ev->wmask); + FD_ZERO(&ev->xmask); + return eventp; +} diff --git a/lib_acl/src/event/events_select_thr.c b/lib_acl/src/event/events_select_thr.c new file mode 100644 index 000000000..c036a6fac --- /dev/null +++ b/lib_acl/src/event/events_select_thr.c @@ -0,0 +1,541 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include +#include +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#ifdef ACL_UNIX +#include +#endif + +#include "stdlib/acl_sys_patch.h" +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_mystring.h" +#include "stdlib/acl_msg.h" +#include "stdlib/acl_ring.h" +#include "stdlib/acl_vstream.h" +#include "event/acl_events.h" + +#endif + +#include "events_dog.h" +#include "events.h" +#include "events_fdtable.h" + +typedef struct EVENT_SELECT_THR { + EVENT_THR event; + fd_set rmask; + fd_set wmask; + fd_set xmask; +} EVENT_SELECT_THR; + +static void event_enable_read(ACL_EVENT *eventp, ACL_VSTREAM *stream, + int timeout, ACL_EVENT_NOTIFY_RDWR callback, void *context) +{ + const char *myname = "event_enable_read"; + EVENT_SELECT_THR *event_thr = (EVENT_SELECT_THR *) eventp; + ACL_EVENT_FDTABLE *fdp; + ACL_SOCKET sockfd; + + sockfd = ACL_VSTREAM_SOCK(stream); + + THREAD_LOCK(&event_thr->event.tb_mutex); + + /* + * Disallow multiple requests on the same file descriptor. + * Allow duplicates of the same request. + */ + if (FD_ISSET(sockfd, &event_thr->wmask)) + acl_msg_panic("%s(%d), %s: fd %d: multiple I/O request", + __FILE__, __LINE__, myname, sockfd); + + fdp = stream->fdp; + if (fdp == NULL) + fdp = event_fdtable_alloc(); + + if (fdp->flag & EVENT_FDTABLE_FLAG_WRITE) + acl_msg_panic("%s(%d)->%s: fd %d: multiple I/O request", + __FILE__, __LINE__, myname, sockfd); + + if ((fdp->flag & EVENT_FDTABLE_FLAG_READ) == 0) { + fdp->flag = EVENT_FDTABLE_FLAG_READ | EVENT_FDTABLE_FLAG_EXPT; + + if (FD_ISSET(sockfd, &event_thr->rmask)) + acl_msg_fatal("%s, %s(%d): sockfd(%d) has been in rmask", + myname, __FILE__, __LINE__, sockfd); + + FD_SET(sockfd, &event_thr->xmask); + FD_SET(sockfd, &event_thr->rmask); + + stream->fdp = (void *) fdp; + stream->nrefer++; + fdp->stream = stream; + fdp->listener = 0; + fdp->fdidx = eventp->fdcnt; + eventp->fdtabs[eventp->fdcnt] = fdp; + eventp->fdcnt++; + + if (eventp->maxfd != ACL_SOCKET_INVALID && eventp->maxfd < sockfd) + eventp->maxfd = sockfd; + } + + if (fdp->r_callback != callback || fdp->r_context != context) { + fdp->r_callback = callback; + fdp->r_context = context; + } + + if (timeout > 0) { + fdp->r_timeout = timeout * 1000000; + fdp->r_ttl = eventp->event_present + fdp->r_timeout; + } else { + fdp->r_ttl = 0; + fdp->r_timeout = 0; + } + + THREAD_UNLOCK(&event_thr->event.tb_mutex); + + /* 主要是为了减少通知次数 */ + if (event_thr->event.blocked && event_thr->event.evdog + && event_dog_client(event_thr->event.evdog) != stream) + event_dog_notify(event_thr->event.evdog); +} + +static void event_enable_listen(ACL_EVENT *eventp, ACL_VSTREAM *stream, + int timeout, ACL_EVENT_NOTIFY_RDWR callback, void *context) +{ + const char *myname = "event_enable_listen"; + EVENT_SELECT_THR *event_thr = (EVENT_SELECT_THR *) eventp; + ACL_EVENT_FDTABLE *fdp; + ACL_SOCKET sockfd; + + sockfd = ACL_VSTREAM_SOCK(stream); + + THREAD_LOCK(&event_thr->event.tb_mutex); + + /* + * Disallow multiple requests on the same file descriptor. + * Allow duplicates of the same request. + */ + if (FD_ISSET(sockfd, &event_thr->wmask)) + acl_msg_panic("%s(%d), %s: fd %d: multiple I/O request", + __FILE__, __LINE__, myname, sockfd); + + fdp = stream->fdp; + if (fdp == NULL) + fdp = event_fdtable_alloc(); + + if (fdp->flag & EVENT_FDTABLE_FLAG_WRITE) + acl_msg_panic("%s(%d)->%s: fd %d: multiple I/O request", + __FILE__, __LINE__, myname, sockfd); + + if ((fdp->flag & EVENT_FDTABLE_FLAG_READ) == 0) { + fdp->flag = EVENT_FDTABLE_FLAG_READ | EVENT_FDTABLE_FLAG_EXPT; + + if (FD_ISSET(sockfd, &event_thr->rmask)) + acl_msg_fatal("%s, %s(%d): sockfd(%d) has been in rmask", + myname, __FILE__, __LINE__, sockfd); + + FD_SET(sockfd, &event_thr->xmask); + FD_SET(sockfd, &event_thr->rmask); + + stream->fdp = (void *) fdp; + stream->nrefer++; + fdp->stream = stream; + fdp->listener = 1; + fdp->fdidx = eventp->fdcnt; + eventp->fdtabs[eventp->fdcnt] = fdp; + eventp->fdcnt++; + + if (eventp->maxfd != ACL_SOCKET_INVALID && eventp->maxfd < sockfd) + eventp->maxfd = sockfd; + } + + if (fdp->r_callback != callback || fdp->r_context != context) { + fdp->r_callback = callback; + fdp->r_context = context; + } + + if (timeout > 0) { + fdp->r_timeout = timeout * 1000000; + fdp->r_ttl = eventp->event_present + fdp->r_timeout; + } else { + fdp->r_ttl = 0; + fdp->r_timeout = 0; + } + + THREAD_UNLOCK(&event_thr->event.tb_mutex); +} + +static void event_enable_write(ACL_EVENT *eventp, ACL_VSTREAM *stream, + int timeout, ACL_EVENT_NOTIFY_RDWR callback, void *context) +{ + const char *myname = "event_enable_write"; + EVENT_SELECT_THR *event_thr = (EVENT_SELECT_THR *) eventp; + ACL_EVENT_FDTABLE *fdp; + ACL_SOCKET sockfd; + + sockfd = ACL_VSTREAM_SOCK(stream); + + THREAD_LOCK(&event_thr->event.tb_mutex); + + /* + * Disallow multiple requests on the same file descriptor. + * Allow duplicates of the same request. + */ + if (FD_ISSET(sockfd, &event_thr->rmask)) + acl_msg_panic("%s(%d), %s: fd %d: multiple I/O request", + __FILE__, __LINE__, myname, sockfd); + + fdp = stream->fdp; + if (fdp == NULL) + fdp = event_fdtable_alloc(); + + if (fdp->flag & EVENT_FDTABLE_FLAG_READ) + acl_msg_panic("%s(%d)->%s: fd %d: multiple I/O request", + __FILE__, __LINE__, myname, sockfd); + + + if ((fdp->flag & EVENT_FDTABLE_FLAG_WRITE) == 0) { + fdp->flag = EVENT_FDTABLE_FLAG_WRITE | EVENT_FDTABLE_FLAG_EXPT; + + if (FD_ISSET(sockfd, &event_thr->wmask)) + acl_msg_fatal("%s, %s(%d): sockfd(%d) has been in wmask", + myname, __FILE__, __LINE__, sockfd); + + FD_SET(sockfd, &event_thr->xmask); + FD_SET(sockfd, &event_thr->wmask); + + stream->fdp = (void *) fdp; + stream->nrefer++; + fdp->stream = stream; + fdp->listener = 0; + fdp->fdidx = eventp->fdcnt; + eventp->fdtabs[eventp->fdcnt] = fdp; + eventp->fdcnt++; + + if (eventp->maxfd != ACL_SOCKET_INVALID && eventp->maxfd < sockfd) + eventp->maxfd = sockfd; + } + + if (fdp->w_callback != callback || fdp->w_context != context) { + fdp->w_callback = callback; + fdp->w_context = context; + } + + if (timeout > 0) { + fdp->w_timeout = timeout * 1000000; + fdp->w_ttl = eventp->event_present + fdp->w_timeout; + } else { + fdp->w_ttl = 0; + fdp->w_timeout = 0; + } + + THREAD_UNLOCK(&event_thr->event.tb_mutex); + + if (event_thr->event.blocked && event_thr->event.evdog + && event_dog_client(event_thr->event.evdog) != stream) + event_dog_notify(event_thr->event.evdog); +} + +/* event_disable_readwrite - disable request for read or write events */ + +static void event_disable_readwrite(ACL_EVENT *eventp, ACL_VSTREAM *stream) +{ + const char *myname = "event_disable_readwrite"; + EVENT_SELECT_THR *event_thr = (EVENT_SELECT_THR *) eventp; + ACL_EVENT_FDTABLE *fdp; + ACL_SOCKET sockfd; + + sockfd = ACL_VSTREAM_SOCK(stream); + + THREAD_LOCK(&event_thr->event.tb_mutex); + if (!FD_ISSET(sockfd, &event_thr->xmask)) { + acl_msg_error("%s(%d): sockfd(%d) not be set", + myname, __LINE__, sockfd); + THREAD_UNLOCK(&event_thr->event.tb_mutex); + return; + } + fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + if (fdp == NULL) { + acl_msg_error("%s(%d): fdp null", myname, __LINE__); + THREAD_UNLOCK(&event_thr->event.tb_mutex); + return; + } + + if (fdp->fdidx == -1) + acl_msg_fatal("%s(%d): fdidx(%d) invalid", + myname, __LINE__, fdp->fdidx); + + FD_CLR(sockfd, &event_thr->xmask); + FD_CLR(sockfd, &event_thr->rmask); + FD_CLR(sockfd, &event_thr->wmask); + + fdp->flag = 0; + + if (eventp->maxfd == sockfd) + eventp->maxfd = ACL_SOCKET_INVALID; + if (eventp->fdtabs[fdp->fdidx] == fdp) { + if (fdp->fdidx < --eventp->fdcnt) { + eventp->fdtabs[fdp->fdidx] = eventp->fdtabs[eventp->fdcnt]; + eventp->fdtabs[fdp->fdidx]->fdidx = fdp->fdidx; + } + } else + acl_msg_fatal("%s(%d): fdidx(%d)'s fdp invalid", + myname, __LINE__, fdp->fdidx); + + if (fdp->fdidx_ready > 0 + && fdp->fdidx_ready < eventp->fdcnt_ready + && eventp->fdtabs_ready[fdp->fdidx_ready] == fdp) + { + eventp->fdtabs_ready[fdp->fdidx_ready] = NULL; + } + event_fdtable_free(fdp); + stream->fdp = NULL; + stream->nrefer--; + THREAD_UNLOCK(&event_thr->event.tb_mutex); +} + +static int event_isrset(ACL_EVENT *eventp, ACL_VSTREAM *stream) +{ + EVENT_SELECT_THR *event_thr = (EVENT_SELECT_THR *) eventp; + + return FD_ISSET(ACL_VSTREAM_SOCK(stream), &event_thr->rmask); +} + +static int event_iswset(ACL_EVENT *eventp, ACL_VSTREAM *stream) +{ + EVENT_SELECT_THR *event_thr = (EVENT_SELECT_THR *) eventp; + + return FD_ISSET(ACL_VSTREAM_SOCK(stream), &event_thr->wmask); +} + +static int event_isxset(ACL_EVENT *eventp, ACL_VSTREAM *stream) +{ + EVENT_SELECT_THR *event_thr = (EVENT_SELECT_THR *) eventp; + + return FD_ISSET(ACL_VSTREAM_SOCK(stream), &event_thr->xmask); +} + +static void event_loop(ACL_EVENT *eventp) +{ + const char *myname = "event_loop"; + EVENT_SELECT_THR *event_thr = (EVENT_SELECT_THR *) eventp; + ACL_EVENT_NOTIFY_FN worker_fn; + void *worker_arg; + ACL_SOCKET sockfd; + ACL_EVENT_TIMER *timer; + int select_delay, nready, i; + ACL_EVENT_FDTABLE *fdp; + ACL_RING timer_ring, *entry_ptr; + struct timeval tv, *tvp; + fd_set rmask; /* enabled read events */ + fd_set wmask; /* enabled write events */ + fd_set xmask; /* for bad news mostly */ + + acl_ring_init(&timer_ring); + + SET_TIME(eventp->event_present); + THREAD_LOCK(&event_thr->event.tm_mutex); + + /* + * Find out when the next timer would go off. Timer requests are sorted. + * If any timer is scheduled, adjust the delay appropriately. + */ + if ((timer = ACL_FIRST_TIMER(&eventp->timer_head)) != 0) { + select_delay = (int) (timer->when - eventp->event_present + 1000000 - 1) + / 1000000; + if (select_delay < 0) + select_delay = 0; + else if (eventp->delay_sec >= 0 && select_delay > eventp->delay_sec) + select_delay = eventp->delay_sec; + } else + select_delay = eventp->delay_sec; + + THREAD_UNLOCK(&event_thr->event.tm_mutex); + + THREAD_LOCK(&event_thr->event.tb_mutex); + + if (event_thr_prepare(eventp) == 0) { + if (eventp->fdcnt_ready == 0) { + if (select_delay <= 0) + select_delay = 1; + sleep(select_delay); + } + + THREAD_UNLOCK(&event_thr->event.tb_mutex); + goto TAG_DONE; + } + + if (eventp->fdcnt_ready > 0) { + tv.tv_sec = 0; + tv.tv_usec = 0; + tvp = &tv; + } else if (select_delay < 0) { + tvp = NULL; + } else { + tv.tv_sec = select_delay; + tv.tv_usec = eventp->delay_usec; + tvp = &tv; + } + + rmask = event_thr->rmask; + wmask = event_thr->wmask; + xmask = event_thr->xmask; + + THREAD_UNLOCK(&event_thr->event.tb_mutex); + + event_thr->event.blocked = 1; + nready = select(eventp->maxfd + 1, &rmask, &wmask, &xmask, tvp); + event_thr->event.blocked = 0; + + if (nready < 0) { + if (acl_last_error() != ACL_EINTR) { + acl_msg_fatal("%s(%d), %s: event_loop: select: %s", + __FILE__, __LINE__, myname, acl_last_serror()); + } + goto TAG_DONE; + } else if (nready == 0) + goto TAG_DONE; + + THREAD_LOCK(&event_thr->event.tb_mutex); + + for (i = 0; i < eventp->fdcnt; i++) { + fdp = eventp->fdtabs[i]; + + /* if fdp has been set in eventp->fdtabs_ready ? */ + if ((fdp->event_type & (ACL_EVENT_XCPT | ACL_EVENT_RW_TIMEOUT))) + continue; + + sockfd = ACL_VSTREAM_SOCK(fdp->stream); + + if (FD_ISSET(sockfd, &xmask)) { + fdp->event_type |= ACL_EVENT_XCPT; + fdp->fdidx_ready = eventp->fdcnt_ready; + eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp; + continue; + } + + if (FD_ISSET(sockfd, &rmask)) { + fdp->stream->sys_read_ready = 1; + /* has been set in fdtabs_ready ? */ + if ((fdp->event_type & ACL_EVENT_READ) == 0) { + fdp->event_type |= ACL_EVENT_READ; + fdp->fdidx_ready = eventp->fdcnt_ready; + eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp; + } + } else if (fdp->w_callback && FD_ISSET(sockfd, &wmask)) { + fdp->event_type |= ACL_EVENT_WRITE; + fdp->fdidx_ready = eventp->fdcnt_ready; + eventp->fdtabs_ready[eventp->fdcnt_ready++] = fdp; + } + } + + THREAD_UNLOCK(&event_thr->event.tb_mutex); + +TAG_DONE: + + /* + * Deliver timer events. Requests are sorted: we can stop when we reach + * the future or the list end. Allow the application to update the timer + * queue while it is being called back. To this end, we repeatedly pop + * the first request off the timer queue before delivering the event to + * the application. + */ + + SET_TIME(eventp->event_present); + + THREAD_LOCK(&event_thr->event.tm_mutex); + + while ((timer = ACL_FIRST_TIMER(&eventp->timer_head)) != 0) { + if (timer->when > eventp->event_present) + break; + + acl_ring_detach(&timer->ring); /* first this */ + acl_ring_prepend(&timer_ring, &timer->ring); + } + + THREAD_UNLOCK(&event_thr->event.tm_mutex); + + while (1) { + entry_ptr = acl_ring_pop_head(&timer_ring); + if (entry_ptr == NULL) + break; + + timer = ACL_RING_TO_TIMER(entry_ptr); + worker_fn = timer->callback; + worker_arg = timer->context; + + worker_fn(ACL_EVENT_TIME, worker_arg); + + acl_myfree(timer); + } + + event_thr_fire(eventp); +} + +static void event_add_dog(ACL_EVENT *eventp) +{ + EVENT_SELECT_THR *event_thr = (EVENT_SELECT_THR*) eventp; + + event_thr->event.evdog = event_dog_create((ACL_EVENT*) event_thr, 1); +} + +static void event_free(ACL_EVENT *eventp) +{ + const char *myname = "event_free"; + EVENT_SELECT_THR *event_thr = (EVENT_SELECT_THR *) eventp; + + if (eventp == NULL) + acl_msg_fatal("%s, %s(%d): eventp null", + __FILE__, myname, __LINE__); + + LOCK_DESTROY(&event_thr->event.tm_mutex); + LOCK_DESTROY(&event_thr->event.tb_mutex); + + acl_myfree(eventp); +} + +ACL_EVENT *event_new_select_thr(void) +{ + EVENT_SELECT_THR *event_thr; + + event_thr = (EVENT_SELECT_THR*) event_alloc(sizeof(EVENT_SELECT_THR)); + + snprintf(event_thr->event.event.name, sizeof(event_thr->event.event.name), + "thread events - select"); + event_thr->event.event.event_mode = ACL_EVENT_SELECT; + event_thr->event.event.use_thread = 1; + event_thr->event.event.loop_fn = event_loop; + event_thr->event.event.free_fn = event_free; + event_thr->event.event.add_dog_fn = event_add_dog; + event_thr->event.event.enable_read_fn = event_enable_read; + event_thr->event.event.enable_write_fn = event_enable_write; + event_thr->event.event.enable_listen_fn = event_enable_listen; + event_thr->event.event.disable_readwrite_fn = event_disable_readwrite; + event_thr->event.event.isrset_fn = event_isrset; + event_thr->event.event.iswset_fn = event_iswset; + event_thr->event.event.isxset_fn = event_isxset; + event_thr->event.event.timer_request = event_timer_request_thr; + event_thr->event.event.timer_cancel = event_timer_cancel_thr; + event_thr->event.event.timer_keep = event_timer_keep_thr; + event_thr->event.event.timer_ifkeep = event_timer_ifkeep_thr; + + FD_ZERO(&event_thr->rmask); + FD_ZERO(&event_thr->wmask); + FD_ZERO(&event_thr->xmask); + + LOCK_INIT(&event_thr->event.tm_mutex); + LOCK_INIT(&event_thr->event.tb_mutex); + + return (ACL_EVENT *) event_thr; +} + diff --git a/lib_acl/src/event/events_timer.c b/lib_acl/src/event/events_timer.c new file mode 100644 index 000000000..b0e8997b0 --- /dev/null +++ b/lib_acl/src/event/events_timer.c @@ -0,0 +1,159 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_msg.h" +#include "stdlib/acl_ring.h" +#include "event/acl_events.h" + +#endif + +#include "events.h" + +/* event_timer_request - (re)set timer */ + +acl_int64 event_timer_request(ACL_EVENT *eventp, ACL_EVENT_NOTIFY_TIME callback, + void *context, acl_int64 delay, int keep) +{ + const char *myname = "event_timer_request"; + ACL_RING_ITER iter; + ACL_EVENT_TIMER *timer = NULL; + + /* + * Make sure we schedule this event at the right time. + */ + SET_TIME(eventp->event_present); + + /* + * See if they are resetting an existing timer request. If so, take the + * request away from the timer queue so that it can be inserted at the + * right place. + */ + acl_ring_foreach(iter, &eventp->timer_head) { + timer = ACL_RING_TO_TIMER(iter.ptr); + if (timer->callback == callback && timer->context == context) { + timer->when = eventp->event_present + delay; + timer->keep = keep; + timer->nrefer++; + acl_ring_detach(iter.ptr); + timer->nrefer--; + if (acl_msg_verbose > 2) + acl_msg_info("%s: reset 0x%lx 0x%lx %lld", myname, + (long) callback, (long) context, delay); + break; + } + } + + /* + * If not found, schedule a new timer request. + */ + if (iter.ptr == &eventp->timer_head) { + timer = (ACL_EVENT_TIMER *) acl_mymalloc(sizeof(ACL_EVENT_TIMER)); + if (timer == NULL) + acl_msg_panic("%s: can't mymalloc for timer", myname); + timer->when = eventp->event_present + delay; + timer->delay = delay; + timer->callback = callback; + timer->context = context; + timer->event_type = ACL_EVENT_TIME; + timer->nrefer = 1; + timer->ncount = 0; + timer->keep = keep; + if (acl_msg_verbose > 2) + acl_msg_info("%s: set 0x%lx 0x%lx %lld", myname, + (long) callback, (long) context, delay); + } + + /* + * Insert the request at the right place. Timer requests are kept sorted + * to reduce lookup overhead in the event loop. + */ + + acl_ring_foreach(iter, &eventp->timer_head) + if (timer->when < ACL_RING_TO_TIMER(iter.ptr)->when) + break; + if (iter.ptr == &timer->ring) + acl_msg_fatal("%s: ring invalid", myname); + + acl_ring_prepend(iter.ptr, &timer->ring); + + return (timer->when); +} + +/* event_timer_cancel - cancel timer */ + +acl_int64 event_timer_cancel(ACL_EVENT *eventp, ACL_EVENT_NOTIFY_TIME callback, void *context) +{ + const char *myname = "event_timer_cancel"; + ACL_RING_ITER iter; + ACL_EVENT_TIMER *timer; + acl_int64 time_left = -1; + + /* + * See if they are canceling an existing timer request. Do not complain + * when the request is not found. It might have been canceled from some + * other thread. + */ + + SET_TIME(eventp->event_present); + + acl_ring_foreach(iter, &eventp->timer_head) { + timer = ACL_RING_TO_TIMER(iter.ptr); + if (timer->callback == callback && timer->context == context) { + if ((time_left = timer->when - eventp->event_present) < 0) + time_left = 0; + acl_ring_detach(&timer->ring); + timer->nrefer--; + if (timer->nrefer != 0) + acl_msg_fatal("%s(%d): timer's nrefer(%d) != 0", + myname, __LINE__, timer->nrefer); + acl_myfree(timer); + break; + } + } + if (acl_msg_verbose > 2) + acl_msg_info("%s: 0x%lx 0x%lx %lld", myname, + (long) callback, (long) context, time_left); + return (time_left); +} + +void event_timer_keep(ACL_EVENT *eventp, ACL_EVENT_NOTIFY_TIME callback, + void *context, int keep) +{ + ACL_RING_ITER iter; + ACL_EVENT_TIMER *timer; + + acl_ring_foreach(iter, &eventp->timer_head) { + timer = ACL_RING_TO_TIMER(iter.ptr); + if (timer->callback == callback && timer->context == context) { + timer->keep = keep; + break; + } + } +} + +int event_timer_ifkeep(ACL_EVENT *eventp, ACL_EVENT_NOTIFY_TIME callback, + void *context) +{ + ACL_RING_ITER iter; + ACL_EVENT_TIMER *timer; + + acl_ring_foreach(iter, &eventp->timer_head) { + timer = ACL_RING_TO_TIMER(iter.ptr); + if (timer->callback == callback && timer->context == context) + return timer->keep; + } + + return 0; +} diff --git a/lib_acl/src/event/events_timer_thr.c b/lib_acl/src/event/events_timer_thr.c new file mode 100644 index 000000000..68e9714bf --- /dev/null +++ b/lib_acl/src/event/events_timer_thr.c @@ -0,0 +1,167 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_msg.h" +#include "stdlib/acl_ring.h" + +#endif + +#include "events.h" + +/* event_timer_request_thr - (re)set timer */ + +acl_int64 event_timer_request_thr(ACL_EVENT *eventp, + ACL_EVENT_NOTIFY_TIME callback, void *context, + acl_int64 delay, int keep acl_unused) +{ + const char *myname = "event_timer_request_thr"; + EVENT_THR *event_thr = (EVENT_THR *) eventp; + ACL_RING_ITER iter; + ACL_EVENT_TIMER *timer = NULL; + + if (delay < 0) + acl_msg_panic("%s: invalid delay: %lld", myname, delay); + + THREAD_LOCK(&event_thr->tm_mutex); + + /* + * Make sure we schedule this event at the right time. + */ + SET_TIME(eventp->event_present); + + /* + * See if they are resetting an existing timer request. If so, take the + * request away from the timer queue so that it can be inserted at the + * right place. + */ + acl_ring_foreach(iter, &eventp->timer_head) { + timer = ACL_RING_TO_TIMER(iter.ptr); + if (timer->callback == callback && timer->context == context) { + timer->when = eventp->event_present + delay; + acl_ring_detach(iter.ptr); + if (acl_msg_verbose > 2) + acl_msg_info("%s: reset 0x%lx 0x%lx %lld", myname, + (long) callback, (long) context, delay); + break; + } + } + + /* + * If not found, schedule a new timer request. + */ + if (iter.ptr == &eventp->timer_head) { + timer = (ACL_EVENT_TIMER *) acl_mymalloc(sizeof(ACL_EVENT_TIMER)); + if (timer == NULL) + acl_msg_panic("%s: can't mymalloc for timer", myname); + timer->when = eventp->event_present + delay; + timer->callback = callback; + timer->context = context; + timer->event_type = ACL_EVENT_TIME; + + if (acl_msg_verbose > 2) + acl_msg_info("%s: set 0x%lx 0x%lx %lld", myname, + (long) callback, (long) context, delay); + } + + /* + * Insert the request at the right place. Timer requests are kept sorted + * to reduce lookup overhead in the event loop. + */ + acl_ring_foreach(iter, &eventp->timer_head) + if (timer->when < ACL_RING_TO_TIMER(iter.ptr)->when) + break; + acl_ring_prepend(iter.ptr, &timer->ring); + + THREAD_UNLOCK(&event_thr->tm_mutex); + return (timer->when); +} + +/* event_timer_cancel_thr - cancel timer */ + +acl_int64 event_timer_cancel_thr(ACL_EVENT *eventp, + ACL_EVENT_NOTIFY_TIME callback, void *context) +{ + const char *myname = "event_timer_cancel_thr"; + EVENT_THR *event_thr = (EVENT_THR *) eventp; + ACL_RING_ITER iter; + ACL_EVENT_TIMER *timer; + acl_int64 time_left = -1; + + THREAD_LOCK(&event_thr->tm_mutex); + + /* + * See if they are canceling an existing timer request. Do not complain + * when the request is not found. It might have been canceled from some + * other thread. + */ + + SET_TIME(eventp->event_present); + + acl_ring_foreach(iter, &eventp->timer_head) { + timer = ACL_RING_TO_TIMER(iter.ptr); + if (timer->callback == callback && timer->context == context) { + if ((time_left = timer->when - eventp->event_present) < 0) + time_left = 0; + acl_ring_detach(&timer->ring); + acl_myfree(timer); + break; + } + } + + THREAD_UNLOCK(&event_thr->tm_mutex); + + if (acl_msg_verbose > 2) + acl_msg_info("%s: 0x%lx 0x%lx %lld", myname, + (long) callback, (long) context, time_left); + + return (time_left); +} + +void event_timer_keep_thr(ACL_EVENT *eventp, ACL_EVENT_NOTIFY_TIME callback, + void *context, int keep) +{ + EVENT_THR *event_thr = (EVENT_THR *) eventp; + ACL_RING_ITER iter; + ACL_EVENT_TIMER *timer; + + THREAD_LOCK(&event_thr->tm_mutex); + acl_ring_foreach(iter, &eventp->timer_head) { + timer = ACL_RING_TO_TIMER(iter.ptr); + if (timer->callback == callback && timer->context == context) { + timer->keep = keep; + break; + } + } + THREAD_UNLOCK(&event_thr->tm_mutex); +} + +int event_timer_ifkeep_thr(ACL_EVENT *eventp, ACL_EVENT_NOTIFY_TIME callback, + void *context) +{ + EVENT_THR *event_thr = (EVENT_THR *) eventp; + ACL_RING_ITER iter; + ACL_EVENT_TIMER *timer; + + THREAD_LOCK(&event_thr->tm_mutex); + acl_ring_foreach(iter, &eventp->timer_head) { + timer = ACL_RING_TO_TIMER(iter.ptr); + if (timer->callback == callback && timer->context == context) { + THREAD_UNLOCK(&event_thr->tm_mutex); + return timer->keep; + } + } + THREAD_UNLOCK(&event_thr->tm_mutex); + return 0; +} diff --git a/lib_acl/src/event/events_wmsg.c b/lib_acl/src/event/events_wmsg.c new file mode 100644 index 000000000..746e88f8b --- /dev/null +++ b/lib_acl/src/event/events_wmsg.c @@ -0,0 +1,872 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include +#include +#include +#include + +#include "stdlib/acl_sys_patch.h" +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_msg.h" +#include "stdlib/acl_vstream.h" +#include "stdlib/acl_fifo.h" +#include "stdlib/acl_mystring.h" +#include "stdlib/acl_htable.h" +#include "event/acl_events.h" + +#endif /* ACL_PREPARE_COMPILE */ + +#include "events_define.h" + +#ifdef ACL_EVENTS_STYLE_WMSG + +#define WM_SOCKET_NOTIFY (WM_USER + 8192) + +#include "events_fdtable.h" +#include "events.h" +#include "events_wmsg.h" + +typedef struct EVENT_WMSG { + ACL_EVENT event; + UINT nMsg; + HWND hWnd; + HINSTANCE hInstance; + const char *class_name; + unsigned int tid; + int timer_active; + ACL_HTABLE *htbl; + void (*delay_close)(void *ctx); + void *ctx; +} EVENT_WMSG; + +static void stream_on_close(ACL_VSTREAM *stream, void *arg) +{ + const char *myname = "stream_on_close"; + EVENT_WMSG *ev = (EVENT_WMSG*) arg; + ACL_EVENT_FDTABLE *fdp = (ACL_EVENT_FDTABLE*) stream->fdp; + ACL_SOCKET sockfd = ACL_VSTREAM_SOCK(stream); + char key[64]; + + if (fdp == NULL) { + acl_msg_error("%s(%d): fdp null", myname, __LINE__); + return; + } + + snprintf(key, sizeof(key), "%d", sockfd); + acl_htable_delete(ev->htbl, key, NULL); + + /* 虽然该设置能取消以后的读写消息,但依然不能取消因为 + * closesocket 而产生的 FD_CLOSE 消息 + */ + WSAAsyncSelect(sockfd, ev->hWnd, 0, 0); + + /* + if ((fdp->flag & EVENT_FDTABLE_FLAG_READ) + && (fdp->flag & EVENT_FDTABLE_FLAG_WRITE)) + { + } else if ((fdp->flag & EVENT_FDTABLE_FLAG_READ)) { + } else if ((fdp->flag & EVENT_FDTABLE_FLAG_WRITE)) { + } + */ + + if (ev->event.maxfd == ACL_VSTREAM_SOCK(fdp->stream)) + ev->event.maxfd = ACL_SOCKET_INVALID; + if (fdp->fdidx >= 0 && fdp->fdidx < --ev->event.fdcnt) { + ev->event.fdtabs[fdp->fdidx] = ev->event.fdtabs[ev->event.fdcnt]; + ev->event.fdtabs[fdp->fdidx]->fdidx = fdp->fdidx; + fdp->fdidx = -1; + } + + if (fdp->fdidx_ready >= 0 + && fdp->fdidx_ready < ev->event.fdcnt_ready + && ev->event.fdtabs_ready[fdp->fdidx_ready] == fdp) + { + ev->event.fdtabs_ready[fdp->fdidx_ready] = NULL; + fdp->fdidx_ready = -1; + } + event_fdtable_free(fdp); + stream->fdp = NULL; +} + +static ACL_EVENT_FDTABLE *stream_on_open(EVENT_WMSG *ev, ACL_VSTREAM *stream) +{ + const char *myname = "stream_on_open"; + ACL_EVENT_FDTABLE *fdp = event_fdtable_alloc(); + ACL_SOCKET sockfd = ACL_VSTREAM_SOCK(stream); + char key[64]; + + fdp->stream = stream; + stream->fdp = (void *) fdp; + acl_vstream_add_close_handle(stream, stream_on_close, ev); + + snprintf(key, sizeof(key), "%d", sockfd); + if (acl_htable_enter(ev->htbl, key, fdp) == NULL) + acl_msg_fatal("%s(%d): add key(%s) error", + myname, __LINE__, key); + + return fdp; +} + +static void event_enable_read(ACL_EVENT *eventp, ACL_VSTREAM *stream, + int timeout, ACL_EVENT_NOTIFY_RDWR callback, void *context) +{ + const char *myname = "event_enable_read"; + EVENT_WMSG *ev = (EVENT_WMSG *) eventp; + ACL_SOCKET sockfd = ACL_VSTREAM_SOCK(stream); + ACL_EVENT_FDTABLE *fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + long lEvent; + + if (fdp == NULL) + fdp = stream_on_open(ev, stream); + + if (fdp->fdidx == -1) { + fdp->fdidx = eventp->fdcnt; + eventp->fdtabs[eventp->fdcnt++] = fdp; + } + + if ((fdp->stream->type & ACL_VSTREAM_TYPE_LISTEN)) { + fdp->flag = EVENT_FDTABLE_FLAG_READ | EVENT_FDTABLE_FLAG_EXPT; + lEvent = FD_ACCEPT | FD_READ | FD_CLOSE; + } else if ((fdp->flag & EVENT_FDTABLE_FLAG_WRITE)) { + fdp->flag |= EVENT_FDTABLE_FLAG_READ; + lEvent = FD_READ | FD_WRITE | FD_CLOSE; + } else { + fdp->flag = EVENT_FDTABLE_FLAG_READ | EVENT_FDTABLE_FLAG_EXPT; + lEvent = FD_READ | FD_CLOSE; + } + + if (WSAAsyncSelect(sockfd, ev->hWnd, ev->nMsg, lEvent) != 0) + acl_msg_fatal("%s(%d): set read error: %s", + myname, __LINE__, acl_last_serror()); + + if (eventp->maxfd != ACL_SOCKET_INVALID && eventp->maxfd < sockfd) + eventp->maxfd = sockfd; + + if (fdp->r_callback != callback || fdp->r_context != context) { + fdp->r_callback = callback; + fdp->r_context = context; + } + + if (timeout > 0) { + fdp->r_timeout = timeout * 1000000; + fdp->r_ttl = eventp->event_present + fdp->r_timeout; + } else { + fdp->r_ttl = 0; + fdp->r_timeout = 0; + } +} + +static void event_enable_write(ACL_EVENT *eventp, ACL_VSTREAM *stream, + int timeout, ACL_EVENT_NOTIFY_RDWR callback, void *context) +{ + const char *myname = "event_enable_write"; + EVENT_WMSG *ev = (EVENT_WMSG *) eventp; + ACL_SOCKET sockfd = ACL_VSTREAM_SOCK(stream); + ACL_EVENT_FDTABLE *fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + long lEvent; + + if (fdp == NULL) + fdp = stream_on_open(ev, stream); + + if (fdp->fdidx == -1) { + fdp->fdidx = eventp->fdcnt; + eventp->fdtabs[eventp->fdcnt++] = fdp; + } + + if ((fdp->stream->flag & ACL_VSTREAM_FLAG_CONNECTING)) { + fdp->flag = EVENT_FDTABLE_FLAG_WRITE | EVENT_FDTABLE_FLAG_EXPT; + lEvent = FD_CONNECT | FD_WRITE | FD_CLOSE; + } else if ((fdp->flag & EVENT_FDTABLE_FLAG_READ)) { + fdp->flag |= EVENT_FDTABLE_FLAG_WRITE; + lEvent = FD_READ | FD_WRITE | FD_CLOSE; + } else { + fdp->flag = EVENT_FDTABLE_FLAG_WRITE | EVENT_FDTABLE_FLAG_EXPT; + lEvent = FD_WRITE | FD_CLOSE; + } + + if (WSAAsyncSelect(sockfd, ev->hWnd, ev->nMsg, lEvent) != 0) + acl_msg_fatal("%s(%d): set read error: %s", + myname, __LINE__, acl_last_serror()); + + if (eventp->maxfd != ACL_SOCKET_INVALID && eventp->maxfd < sockfd) + eventp->maxfd = sockfd; + + if (fdp->w_callback != callback || fdp->w_context != context) { + fdp->w_callback = callback; + fdp->w_context = context; + } + + if (timeout > 0) { + fdp->w_timeout = timeout * 1000000; + fdp->w_ttl = eventp->event_present + fdp->w_timeout; + } else { + fdp->w_ttl = 0; + fdp->w_timeout = 0; + } +} + +static void event_disable_read(ACL_EVENT *eventp, ACL_VSTREAM *stream) +{ + const char *myname = "event_disable_read"; + EVENT_WMSG *ev = (EVENT_WMSG *) eventp; + ACL_SOCKET sockfd = ACL_VSTREAM_SOCK(stream); + ACL_EVENT_FDTABLE *fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + + if (fdp == NULL) { + acl_msg_warn("%s(%d): fdp null", myname, __LINE__); + return; + } + + if (fdp->fdidx < 0 || fdp->fdidx >= eventp->fdcnt) { + acl_msg_warn("%s(%d): sockfd(%d)'s fdidx invalid", + myname, __LINE__, sockfd); + return; + } + + if (!(fdp->flag & EVENT_FDTABLE_FLAG_READ)) { + acl_msg_warn("%s(%d): sockfd(%d) not in rmask", + myname, __LINE__, sockfd); + return; + } + + fdp->r_ttl = 0; + fdp->r_timeout = 0; + fdp->r_callback = NULL; + fdp->event_type &= ~ACL_EVENT_READ; + fdp->flag &= ~EVENT_FDTABLE_FLAG_READ; + + if ((fdp->flag & EVENT_FDTABLE_FLAG_WRITE)) { + WSAAsyncSelect(sockfd, ev->hWnd, ev->nMsg, FD_WRITE | FD_CLOSE); + return; + } + + if (eventp->maxfd == sockfd) + eventp->maxfd = ACL_SOCKET_INVALID; + + if (fdp->fdidx < --eventp->fdcnt) { + eventp->fdtabs[fdp->fdidx] = eventp->fdtabs[eventp->fdcnt]; + eventp->fdtabs[fdp->fdidx]->fdidx = fdp->fdidx; + } + fdp->fdidx = -1; + + if (fdp->fdidx_ready >= 0 + && fdp->fdidx_ready < eventp->fdcnt_ready + && eventp->fdtabs_ready[fdp->fdidx_ready] == fdp) + { + eventp->fdtabs_ready[fdp->fdidx_ready] = NULL; + } + fdp->fdidx_ready = -1; + + WSAAsyncSelect(sockfd, ev->hWnd, ev->nMsg, FD_CLOSE); +} + +/* event_disable_write - disable request for write events */ + +static void event_disable_write(ACL_EVENT *eventp, ACL_VSTREAM *stream) +{ + const char *myname = "event_disable_write"; + EVENT_WMSG *ev = (EVENT_WMSG *) eventp; + ACL_SOCKET sockfd = ACL_VSTREAM_SOCK(stream); + ACL_EVENT_FDTABLE *fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + + if (fdp == NULL) { + acl_msg_warn("%s(%d): fdp null", myname, __LINE__); + return; + } + + if (fdp->fdidx < 0 || fdp->fdidx >= eventp->fdcnt) { + acl_msg_warn("%s(%d): sockfd(%d)'s fdidx invalid", + myname, __LINE__, sockfd); + return; + } + + if (!(fdp->flag & EVENT_FDTABLE_FLAG_WRITE)) { + acl_msg_warn("%s(%d): sockfd(%d) not in wmask", + myname, __LINE__, sockfd); + return; + } + + fdp->w_ttl = 0; + fdp->w_timeout = 0; + fdp->w_callback = NULL; + fdp->event_type &= ~ACL_EVENT_WRITE; + fdp->flag &= ~EVENT_FDTABLE_FLAG_WRITE; + + if ((fdp->flag & EVENT_FDTABLE_FLAG_READ)) { + WSAAsyncSelect(sockfd, ev->hWnd, ev->nMsg, FD_READ | FD_CLOSE); + return; + } + + if (eventp->maxfd == sockfd) + eventp->maxfd = ACL_SOCKET_INVALID; + + if (fdp->fdidx < --eventp->fdcnt) { + eventp->fdtabs[fdp->fdidx] = eventp->fdtabs[eventp->fdcnt]; + eventp->fdtabs[fdp->fdidx]->fdidx = fdp->fdidx; + } + fdp->fdidx = -1; + + if (fdp->fdidx_ready >= 0 + && fdp->fdidx_ready < eventp->fdcnt_ready + && eventp->fdtabs_ready[fdp->fdidx_ready] == fdp) + { + eventp->fdtabs_ready[fdp->fdidx_ready] = NULL; + } + fdp->fdidx_ready = -1; + + WSAAsyncSelect(sockfd, ev->hWnd, ev->nMsg, FD_CLOSE); +} + +/* event_disable_readwrite - disable request for read or write events */ + +static void event_disable_readwrite(ACL_EVENT *eventp, ACL_VSTREAM *stream) +{ + const char *myname = "event_disable_readwrite"; + EVENT_WMSG *ev = (EVENT_WMSG *) eventp; + ACL_EVENT_FDTABLE *fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + ACL_SOCKET sockfd = ACL_VSTREAM_SOCK(stream); + + if (fdp == NULL) + return; + + if (fdp->flag == 0 || fdp->fdidx < 0 || fdp->fdidx >= eventp->fdcnt) { + acl_msg_warn("%s(%d): sockfd(%d) no set, fdp no null", + myname, __LINE__, sockfd); + event_fdtable_free(fdp); + stream->fdp = NULL; + return; + } + + if (!eventp->isrset_fn(eventp, stream) + && !eventp->iswset_fn(eventp, stream)) + { + acl_msg_error("%s(%d): sockfd(%d) no set, fdp no null", + myname, __LINE__, sockfd); + event_fdtable_free(fdp); + stream->fdp = NULL; + return; + } + + if (eventp->maxfd == sockfd) + eventp->maxfd = ACL_SOCKET_INVALID; + + if (fdp->fdidx < --eventp->fdcnt) { + eventp->fdtabs[fdp->fdidx] = eventp->fdtabs[eventp->fdcnt]; + eventp->fdtabs[fdp->fdidx]->fdidx = fdp->fdidx; + } + fdp->fdidx = -1; + + WSAAsyncSelect(sockfd, ev->hWnd, ev->nMsg, FD_CLOSE); + + if (fdp->fdidx_ready >= 0 + && fdp->fdidx_ready < eventp->fdcnt_ready + && eventp->fdtabs_ready[fdp->fdidx_ready] == fdp) + { + eventp->fdtabs_ready[fdp->fdidx_ready] = NULL; + } + fdp->fdidx_ready = -1; + event_fdtable_free(fdp); + stream->fdp = NULL; +} + +static int event_isrset(ACL_EVENT *eventp acl_unused, ACL_VSTREAM *stream) +{ + const char *myname = "event_isrset"; + ACL_SOCKET sockfd = ACL_VSTREAM_SOCK(stream); + ACL_EVENT_FDTABLE *fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + + if (fdp == NULL) { + acl_msg_warn("%s(%d): fdp null", myname, __LINE__); + return 0; + } + + return (fdp->flag & EVENT_FDTABLE_FLAG_READ) == 0 ? 0 : 1; +} + +static int event_iswset(ACL_EVENT *eventp acl_unused, ACL_VSTREAM *stream) +{ + const char *myname = "event_iswset"; + ACL_SOCKET sockfd = ACL_VSTREAM_SOCK(stream); + ACL_EVENT_FDTABLE *fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + + if (fdp == NULL) { + acl_msg_warn("%s(%d): fdp null", myname, __LINE__); + return 0; + } + + return (fdp->flag & EVENT_FDTABLE_FLAG_WRITE) == 0 ? 0 : 1; +} + +static int event_isxset(ACL_EVENT *eventp acl_unused, ACL_VSTREAM *stream) +{ + const char *myname = "event_isxset"; + ACL_SOCKET sockfd = ACL_VSTREAM_SOCK(stream); + ACL_EVENT_FDTABLE *fdp = (ACL_EVENT_FDTABLE *) stream->fdp; + + if (fdp == NULL) { + acl_msg_warn("%s(%d): fdp null", myname, __LINE__); + return 0; + } + + return (fdp->flag & EVENT_FDTABLE_FLAG_EXPT) == 0 ? 0 : 1; +} + +#ifdef USE_TLS + +static acl_pthread_key_t __event_key; +static acl_pthread_once_t once_control = ACL_PTHREAD_ONCE_INIT; + +static EVENT_WMSG *get_hwnd_event(HWND hWnd acl_unused) +{ + EVENT_WMSG *ev = acl_pthread_getspecific(__event_key); + return ev; +} + +static void finish_thread_event(void *arg acl_unused) +{ + +} + +static void init_thread_event(void) +{ + acl_pthread_key_create(&__event_key, finish_thread_event); +} + +static void set_hwnd_event(HWND hWnd acl_unused, EVENT_WMSG *ev) +{ + const char *myname = "set_hwnd_event"; + + (void) acl_pthread_once(&once_control, init_thread_event); + if (acl_pthread_getspecific(__event_key) != NULL) + acl_msg_fatal("%s(%d): __event_key(%d)'s value not null", + myname, __LINE__, (int) __event_key); + acl_pthread_setspecific(__event_key, ev); +} + +#else + +static EVENT_WMSG *get_hwnd_event(HWND hWnd) +{ + EVENT_WMSG *ev = (EVENT_WMSG*) GetWindowLongPtr(hWnd, GWL_USERDATA); + return ev; +} + +static void set_hwnd_event(HWND hWnd, EVENT_WMSG *ev) +{ + SetWindowLongPtr(hWnd, GWL_USERDATA, (LONG) ev); +} + +#endif + +static ACL_EVENT_FDTABLE *event_fdtable_find(EVENT_WMSG *ev, ACL_SOCKET sockfd) +{ + ACL_EVENT_FDTABLE *fdp; + char key[64]; + + snprintf(key, sizeof(key), "%d", sockfd); + fdp = acl_htable_find(ev->htbl, key); + return fdp; +} + +static void handleClose(EVENT_WMSG *ev, ACL_SOCKET sockfd) +{ + const char *myname = "handleClose"; + ACL_EVENT_FDTABLE *fdp = event_fdtable_find(ev, sockfd); + + if (fdp == NULL) + return; + else if (fdp->r_callback) + fdp->r_callback(ACL_EVENT_XCPT, fdp->r_context); + else if (fdp->w_callback) + fdp->w_callback(ACL_EVENT_XCPT, fdp->w_context); + /* + else + acl_msg_error("%s(%d): w_callback and r_callback null" + " for sockfd(%d)", myname, __LINE__, (int) sockfd); + */ +} + +static void handleConnect(EVENT_WMSG *ev, ACL_SOCKET sockfd) +{ + const char *myname = "handleConnect"; + ACL_EVENT_FDTABLE *fdp = event_fdtable_find(ev, sockfd); + + if (fdp == NULL) + acl_msg_error("%s(%d): fdp null for sockfd(%d)", + myname, __LINE__, (int) sockfd); + else if (fdp->w_callback == NULL) + acl_msg_error("%s(%d): fdp->w_callback null for sockfd(%d)", + myname, __LINE__, (int) sockfd); + else { + fdp->stream->flag &= ~ACL_VSTREAM_FLAG_CONNECTING; + fdp->w_callback(ACL_EVENT_WRITE, fdp->w_context); + } +} + +static void handleAccept(EVENT_WMSG *ev, ACL_SOCKET sockfd) +{ + const char *myname = "handleAccept"; + ACL_EVENT_FDTABLE *fdp = event_fdtable_find(ev, sockfd); + + if (fdp == NULL) + acl_msg_fatal("%s(%d): fdp null", myname, __LINE__); + else if (fdp->r_callback == NULL) + acl_msg_fatal("%s(%d): fdp callback null", myname, __LINE__); + + fdp->r_callback(ACL_EVENT_READ, fdp->r_context); +} + +static void handleRead(EVENT_WMSG *ev, ACL_SOCKET sockfd) +{ + const char *myname = "handleRead"; + ACL_EVENT_FDTABLE *fdp = event_fdtable_find(ev, sockfd); + + if (fdp == NULL) + acl_msg_error("%s(%d): fdp null for sockfd(%d)", + myname, __LINE__, (int) sockfd); + else if ((fdp->stream->type & ACL_VSTREAM_TYPE_LISTEN)) + fdp->r_callback(ACL_EVENT_READ, fdp->r_context); + else if (fdp->r_callback != NULL) { + /* 该描述字可读则设置 ACL_VSTREAM 的系统可读标志从而触发 + * ACL_VSTREAM 流在读时调用系统的 read 函数 + */ + fdp->stream->sys_read_ready = 1; + fdp->r_callback(ACL_EVENT_READ, fdp->r_context); + } + /* else + acl_msg_error("%s(%d): fdp->r_callback null for sockfd(%d)", + myname, __LINE__, (int) sockfd); + */ +} + +static void handleWrite(EVENT_WMSG *ev, ACL_SOCKET sockfd) +{ + const char *myname = "handleWrite"; + ACL_EVENT_FDTABLE *fdp = event_fdtable_find(ev, sockfd); + + if (fdp == NULL) + acl_msg_error("%s(%d): fdp null for sockfd(%d)", + myname, __LINE__, (int) sockfd); + else if ((fdp->stream->flag & ACL_VSTREAM_FLAG_CONNECTING)) + handleConnect(ev, sockfd); + else if (fdp->w_callback != NULL) + fdp->w_callback(ACL_EVENT_WRITE, fdp->w_context); + /* + else + acl_msg_error("%s(%d): fdp->w_callback null for sockfd(%d)", + myname, __LINE__, (int) sockfd); + */ +} + +static LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + ACL_SOCKET sockfd; + EVENT_WMSG *ev = get_hwnd_event(hWnd); + + if (ev == NULL) + return (DefWindowProc(hWnd, msg, wParam, lParam)); + + if (msg == WM_SOCKET_NOTIFY) { + sockfd = wParam; + switch (WSAGETSELECTEVENT(lParam)) { + case FD_ACCEPT: + handleAccept(ev, sockfd); + break; + case FD_CONNECT: + handleConnect(ev, sockfd); + break; + case FD_READ: + handleRead(ev, sockfd); + break; + case FD_WRITE: + handleWrite(ev, sockfd); + break; + case FD_CLOSE: + handleClose(ev, sockfd); + break; + default: + break; + } + } + + return (DefWindowProc(hWnd, msg, wParam, lParam)); +} + +static BOOL InitApplication(const char *class_name, HINSTANCE hInstance) +{ + const char *myname = "InitApplication"; + WNDCLASSEX wcx; + + if (GetClassInfoEx(hInstance, class_name, &wcx)) + { + /* class already registered */ + acl_msg_info("%s(%d): class(%s) already registered", + myname, __LINE__, class_name); + return TRUE; + } + + /* Fill in the window class structure with parameters + * that describe the main window. + */ + + memset(&wcx, 0, sizeof(wcx)); + + wcx.cbSize = sizeof(wcx); /* size of structure */ + wcx.style = CS_HREDRAW | CS_VREDRAW; + wcx.lpfnWndProc = WndProc; /* points to window procedure */ + wcx.cbClsExtra = 0; /* no extra class memory */ + wcx.cbWndExtra = 0; /* no extra window memory */ + wcx.hInstance = hInstance; /* handle to instance */ + + wcx.hIcon = LoadIcon(NULL, IDI_APPLICATION); /* predefined app. icon */ + wcx.hCursor = LoadCursor(NULL, IDC_ARROW); /* predefined arrow */ + wcx.hbrBackground = GetStockObject(WHITE_BRUSH); /* white background brush */ + wcx.lpszMenuName = NULL; /* name of menu resource */ + wcx.lpszClassName = class_name; /* name of window class */ + wcx.hIconSm = LoadImage(hInstance, /* small class icon */ + MAKEINTRESOURCE(5), + IMAGE_ICON, + GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON), + LR_DEFAULTCOLOR); + + /* Register the window class. */ + if (RegisterClassEx(&wcx) == 0) { + acl_msg_error("%s(%d): RegisterClassEx error(%d, %s)", + myname, __LINE__, acl_last_error(), acl_last_serror()); + return (FALSE); + } else + return (TRUE); +} + +static HWND InitInstance(const char *class_name, HINSTANCE hInstance) +{ + const char *myname = "InitInstance"; + HWND hWnd; + CREATESTRUCT cs; + + cs.dwExStyle = 0; + cs.lpszClass = class_name; + cs.lpszName = "Acl Socket Notification Sink"; + cs.style = WS_OVERLAPPED; + cs.x = 0; + cs.y = 0; + cs.cx = 0; + cs.cy = 0; + cs.hwndParent = NULL; + cs.hMenu = NULL; + cs.hInstance = hInstance; + cs.lpCreateParams = NULL; + + hWnd = CreateWindowEx(cs.dwExStyle, cs.lpszClass, + cs.lpszName, cs.style, cs.x, cs.y, cs.cx, cs.cy, + cs.hwndParent, cs.hMenu, cs.hInstance, cs.lpCreateParams); + if (hWnd == NULL) + acl_msg_error("%s(%d): create windows error: %s", + myname, __LINE__, acl_last_serror()); + return hWnd; +} + +static HWND CreateSockWindow(const char *class_name, HINSTANCE hInstance) +{ + if (InitApplication(class_name, hInstance) == FALSE) + return (FALSE); + return InitInstance(class_name, hInstance); +} + +static void event_loop(ACL_EVENT *eventp acl_unused) +{ + +} + +static VOID CALLBACK event_timer_callback(HWND hwnd, UINT uMsg, + UINT_PTR idEvent, DWORD dwTime) +{ + const char *myname = "event_timer_callback"; + EVENT_WMSG *ev = get_hwnd_event(hwnd); + ACL_EVENT *eventp; + ACL_EVENT_TIMER *timer; + ACL_EVENT_NOTIFY_FN worker_fn; + void *worker_arg; + + if (ev == NULL) + acl_msg_fatal("%s(%d): ev null", myname, __LINE__); + if (ev->tid != idEvent) + acl_msg_fatal("%s(%d): ev->tid(%u) != idEvent(%u)", + myname, __LINE__, (unsigned int) ev->tid, + (unsigned int) idEvent); + + eventp = &ev->event; + SET_TIME(eventp->event_present); + + while ((timer = ACL_FIRST_TIMER(&eventp->timer_head)) != 0) { + if (timer->when > eventp->event_present) + break; + worker_fn = timer->callback; + worker_arg = timer->context; + + /* 如果定时器的时间间隔 > 0 且允许定时器被循环调用,则再重设定时器 */ + if (timer->delay > 0 && timer->keep) { + timer->ncount++; + eventp->timer_request(eventp, timer->callback, + timer->context, timer->delay, timer->keep); + } else { + acl_ring_detach(&timer->ring); /* first this */ + timer->nrefer--; + if (timer->nrefer != 0) + acl_msg_fatal("%s(%d): nrefer(%d) != 0", + myname, __LINE__, timer->nrefer); + acl_myfree(timer); + } + worker_fn(ACL_EVENT_TIME, worker_arg); + } + + if ((timer = ACL_FIRST_TIMER(&eventp->timer_head)) == 0) { + KillTimer(hwnd, idEvent); + ev->timer_active = 0; + } else { + int delay; + + SET_TIME(eventp->event_present); + delay = (int) (timer->when - eventp->event_present + 999) / 1000; + + /* 要求时间定时器的间隔最少是 1 毫秒 */ + if (delay < 1000) + delay = 1000; + SetTimer(ev->hWnd, ev->tid, delay, event_timer_callback); + } +} + +static acl_int64 event_set_timer(ACL_EVENT *eventp, ACL_EVENT_NOTIFY_TIME callback, + void *context, acl_int64 delay, int keep) +{ + EVENT_WMSG *ev = (EVENT_WMSG*) eventp; + ACL_EVENT_TIMER *timer; + acl_int64 when; + acl_int64 first_delay; + + /* 要求时间定时器的间隔最少是 1 毫秒 */ + if (delay < 1000) + delay = 1000; + + timer = ACL_FIRST_TIMER(&eventp->timer_head); + if (timer == NULL) + first_delay = -1; + else { + SET_TIME(eventp->event_present); + first_delay = timer->when - eventp->event_present; + if (first_delay < 0) + first_delay = 0; + } + + when = event_timer_request(eventp, callback, context, delay, keep); + + if (ev->timer_active == 0) { + /* set the new timer */ + SetTimer(ev->hWnd, ev->tid, (unsigned int) delay / 1000, + event_timer_callback); + ev->timer_active = 1; + } else if (first_delay > delay) { + /* reset the old timer */ + SetTimer(ev->hWnd, ev->tid, (unsigned int) delay / 1000, + event_timer_callback); + } + + return when; +} + +static acl_int64 event_del_timer(ACL_EVENT *eventp, + ACL_EVENT_NOTIFY_TIME callback, void *context) +{ + EVENT_WMSG *ev = (EVENT_WMSG*) eventp; + acl_int64 when = event_timer_cancel(eventp, callback, context); + + if (ev->timer_active && ACL_FIRST_TIMER(&eventp->timer_head) == 0) { + KillTimer(ev->hWnd, ev->tid); + ev->timer_active = 0; + } + return when; +} + +static void event_free(ACL_EVENT *eventp) +{ + const char *myname = "event_free"; + EVENT_WMSG *ev = (EVENT_WMSG *) eventp; + + if (eventp == NULL) + acl_msg_fatal("%s(%d): eventp null", myname, __LINE__); + + if (ev->hWnd != NULL) { + WNDCLASSEX wcx; + + DestroyWindow(ev->hWnd); + if (ev->class_name && GetClassInfoEx(ev->hInstance, + ev->class_name, &wcx)) + { + acl_msg_info("unregister class: %s", ev->class_name); + UnregisterClass(ev->class_name, ev->hInstance); + } + } + acl_htable_free(ev->htbl, NULL); + acl_myfree(ev); +} + +static const char *__class_name = "__AclEventsMainWClass"; +ACL_EVENT *event_new_wmsg(UINT nMsg) +{ + ACL_EVENT *eventp; + EVENT_WMSG *ev; + + HINSTANCE hInstance = GetModuleHandle(NULL); + HWND hWnd = CreateSockWindow(__class_name, hInstance); + + if (hWnd == NULL) + return (NULL); + + eventp = event_alloc(sizeof(EVENT_WMSG)); + + snprintf(eventp->name, sizeof(eventp->name), "events - wmsg"); + eventp->event_mode = ACL_EVENT_WMSG; + eventp->use_thread = 0; + eventp->loop_fn = event_loop; + eventp->free_fn = event_free; + eventp->enable_read_fn = event_enable_read; + eventp->enable_write_fn = event_enable_write; + eventp->enable_listen_fn = event_enable_read; + eventp->disable_read_fn = event_disable_read; + eventp->disable_write_fn = event_disable_write; + eventp->disable_readwrite_fn = event_disable_readwrite; + eventp->isrset_fn = event_isrset; + eventp->iswset_fn = event_iswset; + eventp->isxset_fn = event_isxset; + eventp->timer_request = event_set_timer; + eventp->timer_cancel = event_del_timer; + eventp->timer_keep = event_timer_keep; + eventp->timer_ifkeep = event_timer_ifkeep; + + ev = (EVENT_WMSG*) eventp; + ev->nMsg = nMsg > 0 ? nMsg : WM_SOCKET_NOTIFY; + ev->htbl = acl_htable_create(100, 0); + ev->hWnd = hWnd; + ev->hInstance = hInstance; + ev->class_name = __class_name; + ev->tid = acl_pthread_self(); + ev->timer_active = 0; + ev->delay_close = NULL; + ev->ctx = NULL; + + set_hwnd_event(hWnd, ev); + return eventp; +} + +HWND acl_event_wmsg_hwnd(ACL_EVENT *eventp) +{ + EVENT_WMSG *ev = (EVENT_WMSG*) eventp; + return ev->hWnd; +} + +#endif /* ACL_EVENTS_STYLE_WMSG */ diff --git a/lib_acl/src/event/events_wmsg.h b/lib_acl/src/event/events_wmsg.h new file mode 100644 index 000000000..e705e558d --- /dev/null +++ b/lib_acl/src/event/events_wmsg.h @@ -0,0 +1,19 @@ +#ifndef __EVENTS_WMSG_INCLUDE_H__ +#define __EVENTS_WMSG_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "events_define.h" + +#ifdef ACL_EVENTS_STYLE_WMSG +# define EVENT_NAME_WMSG "windows message" +ACL_API ACL_EVENT *event_new_wmsg(UINT nMsg); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __EVENTS_WMSG_INCLUDE_H__ */ diff --git a/lib_acl/src/event/fdmap.c b/lib_acl/src/event/fdmap.c new file mode 100644 index 000000000..b41a96157 --- /dev/null +++ b/lib_acl/src/event/fdmap.c @@ -0,0 +1,90 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_msg.h" +#include "stdlib/acl_mymalloc.h" + +#endif + +#include "fdmap.h" + +typedef struct FD_ENTRY { + int fd; + void *ctx; +} FD_ENTRY; + +struct ACL_FD_MAP { + FD_ENTRY *table; + int size; +}; + +ACL_FD_MAP *acl_fdmap_create(int size) +{ + const char *myname = "acl_fdmap_create"; + ACL_FD_MAP *map; + + if (size < 0) + acl_msg_fatal("%s(%d): maxfd(%d) invalid", + myname, __LINE__, size); + + map = (ACL_FD_MAP *) acl_mycalloc(1, sizeof(ACL_FD_MAP)); + if (map == NULL) + acl_msg_fatal("%s(%d): calloc error(%s)", + myname, __LINE__, acl_last_serror()); + + map->size = size; + map->table = (FD_ENTRY *) acl_mycalloc(map->size, sizeof(FD_ENTRY)); + if (map->table == NULL) + acl_msg_fatal("%s(%d): calloc error(%s)", + myname, __LINE__, acl_last_serror()); + + return (map); +} + +void acl_fdmap_add(ACL_FD_MAP *map, int fd, void *ctx) +{ + const char *myname = "acl_fdmap_add"; + + if (fd >= map->size) + acl_msg_fatal("%s(%d): fd(%d) >= map's size(%d)", + myname, __LINE__, fd, map->size); + + map->table[fd].fd = fd; + map->table[fd].ctx = ctx; +} + +void acl_fdmap_del(ACL_FD_MAP *map, int fd) +{ + const char *myname = "acl_fdmap_del"; + + if (fd >= map->size) + acl_msg_fatal("%s(%d): fd(%d) >= map's size(%d)", + myname, __LINE__, fd, map->size); + +} + +void *acl_fdmap_ctx(ACL_FD_MAP *map, int fd) +{ + const char *myname = "acl_fdmap_ctx"; + + if (fd >= map->size) + acl_msg_fatal("%s(%d): fd(%d) >= map's size(%d)", + myname, __LINE__, fd, map->size); + + return (map->table[fd].ctx); +} + +void acl_fdmap_free(ACL_FD_MAP *map) +{ + if (map) { + acl_myfree(map->table); + acl_myfree(map); + } +} diff --git a/lib_acl/src/event/fdmap.h b/lib_acl/src/event/fdmap.h new file mode 100644 index 000000000..d33643145 --- /dev/null +++ b/lib_acl/src/event/fdmap.h @@ -0,0 +1,21 @@ +#ifndef __ACL_FDMAP_INCLUDE_H__ +#define __ACL_FDMAP_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct ACL_FD_MAP ACL_FD_MAP; + +extern ACL_FD_MAP *acl_fdmap_create(int maxfd); +extern void acl_fdmap_add(ACL_FD_MAP *map, int fd, void *ctx); +extern void acl_fdmap_del(ACL_FD_MAP *map, int fd); +extern void *acl_fdmap_ctx(ACL_FD_MAP *map, int fd); +extern void acl_fdmap_free(ACL_FD_MAP *map); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/src/init/acl_init.c b/lib_acl/src/init/acl_init.c new file mode 100644 index 000000000..3bbb5ed1e --- /dev/null +++ b/lib_acl/src/init/acl_init.c @@ -0,0 +1,123 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#ifdef ACL_UNIX +#include +#endif +#include "stdlib/acl_sys_patch.h" +#include "stdlib/acl_msg.h" +#include "stdlib/acl_vstream.h" +#include "thread/acl_pthread.h" +#include "init/acl_init.h" + +#endif /* ACL_PREPARE_COMPILE */ + +#if defined(ACL_MS_WINDOWS) +#pragma comment(lib,"ws2_32") +#pragma comment(lib, "wsock32") +#endif + +#ifdef ACL_MS_WINDOWS +#include +#endif + +#include "init.h" + +static char *version = "lib_acl_2.1.2.8"; + +const char *acl_version(void) +{ + return (version); +} + +#ifdef ACL_UNIX +static acl_pthread_t acl_var_main_tid = (acl_pthread_t) -1; +#elif defined(ACL_MS_WINDOWS) +static unsigned long acl_var_main_tid = (unsigned long) -1; +#else +#error "Unknown OS" +#endif + +#ifdef ACL_UNIX +void acl_init(void) __attribute__ ((constructor)); +#endif + +void acl_init(void) +{ + static int __have_inited = 0; + + if (__have_inited) + return; + __have_inited = 1; +#ifdef ACL_UNIX + signal(SIGPIPE, SIG_IGN); +#elif defined(ACL_MS_WINDOWS) + acl_socket_init(); + acl_vstream_init(); +#endif + acl_var_main_tid = acl_pthread_self(); +} + +#ifdef ACL_UNIX +void acl_end(void) __attribute__ ((destructor)); +#endif + +void acl_end(void) +{ + static int __have_ended = 0; + + if (__have_ended) + return; + __have_ended = 1; +#if defined(ACL_MS_WINDOWS) + acl_socket_end(); + acl_pthread_end(); +#endif +} + +int __acl_var_use_poll = 1; + +void acl_poll_prefered(int yesno) +{ + __acl_var_use_poll = yesno; +} + +#ifdef ACL_MS_WINDOWS +static acl_pthread_once_t __once_control = ACL_PTHREAD_ONCE_INIT; + +static void get_main_thread_id(void) +{ + HANDLE hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); + THREADENTRY32 th32; + DWORD currentPID; + BOOL bOk; + + if (hThreadSnap == INVALID_HANDLE_VALUE) + return; + currentPID = GetCurrentProcessId(); + th32.dwSize = sizeof(THREADENTRY32); + + for (bOk = Thread32First(hThreadSnap, &th32); bOk; + bOk = Thread32Next(hThreadSnap, &th32)) + { + if (th32.th32OwnerProcessID == currentPID) { + acl_var_main_tid = th32.th32ThreadID; + break; + } + } +} +#endif + +unsigned long acl_main_thread_self() +{ +#ifdef ACL_UNIX + return ((unsigned long) acl_var_main_tid); +#elif defined(ACL_MS_WINDOWS) + if (acl_var_main_tid == (unsigned long) -1) + acl_pthread_once(&__once_control, get_main_thread_id); + return (acl_var_main_tid); +#else +#error "Unknown OS" +#endif +} diff --git a/lib_acl/src/init/init.h b/lib_acl/src/init/init.h new file mode 100644 index 000000000..c98ee6a2f --- /dev/null +++ b/lib_acl/src/init/init.h @@ -0,0 +1,6 @@ +#ifndef __INIT_INCLUDE_H__ +#define __INIT_INCLUDE_H__ + +extern int __acl_var_use_poll; + +#endif diff --git a/lib_acl/src/ioctl/acl_ioctl.c b/lib_acl/src/ioctl/acl_ioctl.c new file mode 100644 index 000000000..0267fad4a --- /dev/null +++ b/lib_acl/src/ioctl/acl_ioctl.c @@ -0,0 +1,399 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_stdlib.h" +#include "event/acl_events.h" +#include "thread/acl_pthread_pool.h" +#include "net/acl_net.h" +#include "ioctl/acl_ioctl.h" + +#endif + +#include "ioctl_internal.h" + +static int __poller_fn(void *arg) +{ + ACL_IOCTL *ioc = (ACL_IOCTL *) arg; + + acl_event_loop(ioc->event); + return 0; +} + +ACL_IOCTL *acl_ioctl_create_ex(int event_mode, int max_threads, + int idle_timeout, int delay_sec, int delay_usec) +{ + const char *myname = "acl_ioctl_create_ex"; + ACL_IOCTL *ioc; + + if (max_threads < 0) + max_threads = 0; + if (max_threads > 0 && idle_timeout <= 0) { + idle_timeout = 60; + acl_msg_error("%s, %s(%d): idle_timeout(%d) invalid", + __FILE__, myname, __LINE__, idle_timeout); + } + + ioc = (ACL_IOCTL *) acl_mycalloc(1, sizeof(ACL_IOCTL)); + + if (delay_sec <= 0 && delay_usec <= 0) { + delay_sec = 1; + delay_usec = 0; + } + ioc->event_mode = event_mode; + ioc->max_threads = max_threads; + ioc->idle_timeout = idle_timeout; + ioc->delay_sec = delay_sec; + ioc->delay_usec = delay_usec; + ioc->stacksize = 0; + + return ioc; +} + +ACL_IOCTL *acl_ioctl_create(int max_threads, int idle_timeout) +{ + int delay_sec = 0, delay_usec = 5000; + + return acl_ioctl_create_ex(ACL_EVENT_SELECT, max_threads, + idle_timeout, delay_sec, delay_usec); +} + +void acl_ioctl_ctl(ACL_IOCTL *ioc, int name, ...) +{ + va_list ap; + + va_start(ap, name); + + for (; name != ACL_IOCTL_CTL_END; name = va_arg(ap, int)) { + switch (name) { + case ACL_IOCTL_CTL_THREAD_MAX: + ioc->max_threads = va_arg(ap, int); + break; + case ACL_IOCTL_CTL_THREAD_STACKSIZE: + ioc->stacksize = va_arg(ap, int); + break; + case ACL_IOCTL_CTL_THREAD_IDLE: + ioc->idle_timeout = va_arg(ap, int); + break; + case ACL_IOCTL_CTL_DELAY_SEC: + ioc->delay_sec = va_arg(ap, int); + if (ioc->event) + acl_event_set_delay_sec(ioc->event, ioc->delay_sec); + break; + case ACL_IOCTL_CTL_DELAY_USEC: + ioc->delay_usec = va_arg(ap, int); + if (ioc->event) + acl_event_set_delay_usec(ioc->event, ioc->delay_usec); + break; + case ACL_IOCTL_CTL_INIT_FN: + ioc->thread_init_fn = va_arg(ap, ACL_IOCTL_THREAD_INIT_FN); + break; + case ACL_IOCTL_CTL_EXIT_FN: + ioc->thread_exit_fn = va_arg(ap, ACL_IOCTL_THREAD_EXIT_FN); + break; + case ACL_IOCTL_CTL_INIT_CTX: + ioc->thread_init_arg = va_arg(ap, void*); + break; + case ACL_IOCTL_CTL_EXIT_CTX: + ioc->thread_exit_arg = va_arg(ap, void*); + break; + default: + acl_msg_fatal("%s(%d): unknown arg", __FILE__, __LINE__); + /* not reached */ + break; + } + } + + va_end(ap); +} + +void acl_ioctl_free(ACL_IOCTL *ioc) +{ + if (ioc == NULL) + return; + + if (ioc->tp) + acl_pthread_pool_destroy(ioc->tp); + if (ioc->event) + acl_event_free(ioc->event); + + acl_myfree(ioc); +} + +void acl_ioctl_add_dog(ACL_IOCTL *ioc) +{ + if (ioc->max_threads > 0) + ioc->enable_dog = 1; + else + ioc->enable_dog = 0; +} + +static int __on_thread_init(void *arg_init) +{ + const char *myname = "__on_thread_init"; + ACL_IOCTL *ioc = (ACL_IOCTL*) arg_init; + + if (ioc->thread_init_fn == NULL) + acl_msg_fatal("%s, %s(%d): thread_init_fn null", + __FILE__, myname, __LINE__); + + ioc->thread_init_fn(ioc->thread_init_arg); + return 0; +} + +static void __on_thread_exit(void *arg_free) +{ + const char *myname = "__on_thread_exit"; + ACL_IOCTL *ioc = (ACL_IOCTL*) arg_free; + + if (ioc->thread_exit_fn == NULL) + acl_msg_fatal("%s, %s(%d): thread_exit_fn null", + __FILE__, myname, __LINE__); + + ioc->thread_exit_fn(ioc->thread_exit_arg); +} + +int acl_ioctl_start(ACL_IOCTL *ioc) +{ + /* 单线程模式 */ + if (ioc->max_threads == 0) { + ioc->tp = NULL; + ioc->event = acl_event_new(ioc->event_mode, 0, + ioc->delay_sec, ioc->delay_usec); + return 0; + } + + /* 多线程模式 */ + ioc->tp = acl_thread_pool_create(ioc->max_threads, ioc->idle_timeout); + acl_pthread_pool_set_poller(ioc->tp, __poller_fn, ioc); + + if (ioc->thread_init_fn) + acl_pthread_pool_atinit(ioc->tp, __on_thread_init, ioc); + if (ioc->thread_exit_fn) + acl_pthread_pool_atfree(ioc->tp, __on_thread_exit, ioc); + + ioc->event = acl_event_new(ioc->event_mode, 1, + ioc->delay_sec, ioc->delay_usec); + if (ioc->enable_dog) + acl_event_add_dog(ioc->event); + + return acl_pthread_pool_start_poller(ioc->tp); +} + +void acl_ioctl_loop(ACL_IOCTL *ioc) +{ + if (ioc && ioc->event) + acl_event_loop(ioc->event); +} + +ACL_EVENT *acl_ioctl_event(ACL_IOCTL *ioc) +{ + if (ioc) + return (ioc->event); + return NULL; +} + +void acl_ioctl_disable_readwrite(ACL_IOCTL *ioc, ACL_VSTREAM *stream) +{ + if (ioc && ioc->event && stream) + acl_event_disable_readwrite(ioc->event, stream); +} + +void acl_ioctl_disable_read(ACL_IOCTL *ioc, ACL_VSTREAM *stream) +{ + if (ioc && ioc->event && stream) + acl_event_disable_read(ioc->event, stream); +} + +void acl_ioctl_disable_write(ACL_IOCTL *ioc, ACL_VSTREAM *stream) +{ + if (ioc && ioc->event && stream) + acl_event_disable_write(ioc->event, stream); +} + +int acl_ioctl_isset(ACL_IOCTL *ioc, ACL_VSTREAM *stream) +{ + return acl_event_isset(ioc->event, stream); +} + +int acl_ioctl_isrset(ACL_IOCTL *ioc, ACL_VSTREAM *stream) +{ + return acl_event_isrset(ioc->event, stream); +} + +int acl_ioctl_iswset(ACL_IOCTL *ioc, ACL_VSTREAM *stream) +{ + return acl_event_iswset(ioc->event, stream); +} + +static void __free_ctx(ACL_VSTREAM *stream acl_unused, void *ctx) +{ + acl_myfree(ctx); +} + +void acl_ioctl_enable_read(ACL_IOCTL *ioc, ACL_VSTREAM *stream, + int timeout, ACL_IOCTL_NOTIFY_FN notify_fn, void *context) +{ + const char *myname = "acl_ioctl_enable_read"; + ACL_IOCTL_CTX *ctx; + + if (ioc == NULL || stream == NULL) + acl_msg_fatal("%s(%d): input invalid", myname, __LINE__); + + if (stream->ioctl_read_ctx == NULL) { + stream->ioctl_read_ctx = acl_mymalloc(sizeof(ACL_IOCTL_CTX)); + ((ACL_IOCTL_CTX *) stream->ioctl_read_ctx)->stream = stream; + acl_vstream_add_close_handle(stream, __free_ctx, + stream->ioctl_read_ctx); + } + + ctx = stream->ioctl_read_ctx; + + ctx->ioc = ioc; + ctx->notify_fn = notify_fn; + ctx->context = context; + ctx->event_type = ACL_EVENT_READ; + + /* 将数据流的状态置入事件监控集合中 */ + if (ioc->max_threads == 0) + acl_event_enable_read(ioc->event, stream, + timeout, read_notify_callback, (void *) ctx); + else + acl_event_enable_read(ioc->event, stream, + timeout, read_notify_callback_r, (void *) ctx); +} + +void acl_ioctl_enable_write(ACL_IOCTL *ioc, ACL_VSTREAM *stream, + int timeout, ACL_IOCTL_NOTIFY_FN notify_fn, void *context) +{ + const char *myname = "acl_ioctl_enable_write"; + ACL_IOCTL_CTX *ctx; + + if (ioc == NULL || stream == NULL) + acl_msg_fatal("%s(%d): input invalid", myname, __LINE__); + + if (stream->ioctl_write_ctx == NULL) { + stream->ioctl_write_ctx = acl_mymalloc(sizeof(ACL_IOCTL_CTX)); + ((ACL_IOCTL_CTX *) stream->ioctl_write_ctx)->stream = stream; + acl_vstream_add_close_handle(stream, __free_ctx, + stream->ioctl_write_ctx); + } + + ctx = stream->ioctl_write_ctx; + + ctx->ioc = ioc; + ctx->notify_fn = notify_fn; + ctx->context = context; + + /* 将客户端数据流的状态置入事件监控集合中 */ + if (ioc->max_threads == 0) + acl_event_enable_write(ioc->event, stream, + timeout, write_notify_callback, (void *) ctx); + else + acl_event_enable_write(ioc->event, stream, + timeout, write_notify_callback_r, (void *) ctx); +} + +void acl_ioctl_enable_connect(ACL_IOCTL *ioc, ACL_VSTREAM *stream, + int timeout, ACL_IOCTL_NOTIFY_FN notify_fn, void *context) +{ + const char *myname = "acl_ioctl_enable_connect"; + + if (ioc == NULL || stream == NULL) + acl_msg_fatal("%s(%d): input invalid", myname, __LINE__); + + acl_ioctl_enable_write(ioc, stream, timeout, notify_fn, context); +} + +void acl_ioctl_enable_listen(ACL_IOCTL *ioc, ACL_VSTREAM *stream, + int timeout, ACL_IOCTL_NOTIFY_FN notify_fn, void *context) +{ + const char *myname = "acl_ioctl_enable_listen"; + ACL_IOCTL_CTX *ctx; + + if (ioc == NULL || stream == NULL) + acl_msg_fatal("%s(%d): input invalid", myname, __LINE__); + + if (stream->ioctl_read_ctx == NULL) { + stream->ioctl_read_ctx = acl_mymalloc(sizeof(ACL_IOCTL_CTX)); + ((ACL_IOCTL_CTX *) stream->ioctl_read_ctx)->stream = stream; + acl_vstream_add_close_handle(stream, __free_ctx, stream->ioctl_read_ctx); + } + + ctx = stream->ioctl_read_ctx; + + ctx->ioc = ioc; + ctx->notify_fn = notify_fn; + ctx->context = context; + + if (ioc->max_threads == 0) + acl_event_enable_listen(ioc->event, stream, + timeout, listen_notify_callback, (void *) ctx); + else + acl_event_enable_listen(ioc->event, stream, + timeout, listen_notify_callback_r, (void *) ctx); +} + +ACL_VSTREAM *acl_ioctl_connect(const char *addr, int timeout) +{ + ACL_VSTREAM *stream; + + if (timeout == 0) + stream = acl_vstream_connect(addr, ACL_NON_BLOCKING, 0, 0, 4096); + else if (timeout < 0) + stream = acl_vstream_connect(addr, ACL_BLOCKING, 0, 0, 4096); + else + stream = acl_vstream_connect(addr, ACL_NON_BLOCKING, timeout, 0, 4096); + + return stream; +} + +ACL_VSTREAM *acl_ioctl_listen(const char *addr, int qlen) +{ + return acl_vstream_listen(addr, qlen); +} + +ACL_VSTREAM *acl_ioctl_listen_ex(const char *addr, int qlen, + int block_mode, int io_bufsize, int io_timeout) +{ + return acl_vstream_listen_ex(addr, qlen, block_mode, + io_bufsize, io_timeout); +} + +ACL_VSTREAM *acl_ioctl_accept(ACL_VSTREAM *sstream, char *ipbuf, int size) +{ + return acl_vstream_accept(sstream, ipbuf, size); +} + +acl_int64 acl_ioctl_request_timer(ACL_IOCTL *ioc, ACL_IOCTL_TIMER_FN timer_fn, + void *context, acl_int64 idle_limit) +{ + const char *myname = "acl_ioctl_request_timer"; + + if (ioc == NULL || timer_fn == NULL) + acl_msg_fatal("%s(%d): input invalid", myname, __LINE__); + if (ioc->event == NULL) + acl_msg_fatal("%s(%d): ioctl's event null", myname, __LINE__); + + return acl_event_request_timer(ioc->event, timer_fn, + context, idle_limit, 0); +} + +acl_int64 acl_ioctl_cancel_timer(ACL_IOCTL *ioc, + ACL_IOCTL_TIMER_FN timer_fn, void *context) +{ + const char *myname = "acl_ioctl_cancel_timer"; + + if (ioc == NULL || ioc->event == NULL || timer_fn == NULL) + acl_msg_fatal("%s(%d): input invalid", myname, __LINE__); + + return acl_event_cancel_timer(ioc->event, timer_fn, context); +} diff --git a/lib_acl/src/ioctl/ioctl_internal.h b/lib_acl/src/ioctl/ioctl_internal.h new file mode 100644 index 000000000..238e3f707 --- /dev/null +++ b/lib_acl/src/ioctl/ioctl_internal.h @@ -0,0 +1,45 @@ +#ifndef __IOCTL_INTERNAL_INCLUDE_H__ +#define __IOCTL_INTERNAL_INCLUDE_H__ + +#include "thread/acl_pthread_pool.h" + +/* 服务器框架用句柄 */ +struct ACL_IOCTL { + int event_mode; /* ACL_EVENT_SELECT/ACL_EVENT_KERNEL */ + int max_threads; /* 最大启用线程数 */ + size_t stacksize; /* 线程的堆栈尺寸 */ + int idle_timeout; + int delay_sec; + int delay_usec; + acl_pthread_pool_t *tp; /* 线程池句柄 */ + + ACL_EVENT *event; /* 事件循环句柄 */ + int enable_dog; + + ACL_IOCTL_THREAD_INIT_FN thread_init_fn; + ACL_IOCTL_THREAD_EXIT_FN thread_exit_fn; + void *thread_init_arg; + void *thread_exit_arg; +}; + +typedef struct ACL_IOCTL_CTX { + ACL_IOCTL *ioc; + ACL_VSTREAM *stream; + int event_type; + + ACL_IOCTL_NOTIFY_FN notify_fn; + ACL_IOCTL_WORKER_FN worker_fn; + void *context; +} ACL_IOCTL_CTX; + +/* in ioctl_thr.c */ +void read_notify_callback_r(int event_type, void *context); +void write_notify_callback_r(int event_type, void *context); +void listen_notify_callback_r(int event_type, void *context); + +/* in ioctl_proc.c */ +void read_notify_callback(int event_type, void *context); +void write_notify_callback(int event_type, void *context); +void listen_notify_callback(int event_type, void *context); + +#endif diff --git a/lib_acl/src/ioctl/ioctl_proc.c b/lib_acl/src/ioctl/ioctl_proc.c new file mode 100644 index 000000000..b4dcde9e7 --- /dev/null +++ b/lib_acl/src/ioctl/ioctl_proc.c @@ -0,0 +1,97 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_stdlib.h" +#include "event/acl_events.h" +#include "thread/acl_pthread_pool.h" +#include "net/acl_net.h" +#include "ioctl/acl_ioctl.h" + +#endif + +#include "ioctl_internal.h" + +void read_notify_callback(int event_type, void *context) +{ + ACL_IOCTL_CTX *ctx = (ACL_IOCTL_CTX *) context; + ACL_IOCTL *ioc = (ACL_IOCTL*) ctx->ioc; + ACL_VSTREAM *stream = ctx->stream; + ACL_IOCTL_NOTIFY_FN notify_fn = ctx->notify_fn; + void *arg = ctx->context; + + ctx->event_type = event_type; + acl_event_disable_read(ioc->event, stream); + + switch (event_type) { + case ACL_EVENT_READ: + case ACL_EVENT_RW_TIMEOUT: + case ACL_EVENT_XCPT: + notify_fn(event_type, ioc, stream, arg); + break; + default: + acl_msg_fatal("%s(%d): unknown event type(%d)", + __FILE__, __LINE__, event_type); + /* not reached */ + break; + } +} + +void write_notify_callback(int event_type, void *context) +{ + ACL_IOCTL_CTX *ctx = (ACL_IOCTL_CTX *) context; + ACL_IOCTL *ioc = (ACL_IOCTL*) ctx->ioc; + ACL_VSTREAM *stream = ctx->stream; + ACL_IOCTL_NOTIFY_FN notify_fn = ctx->notify_fn; + void *arg = ctx->context; + + ctx->event_type = event_type; + + acl_event_disable_write(ioc->event, stream); + + switch (event_type) { + case ACL_EVENT_WRITE: + case ACL_EVENT_RW_TIMEOUT: + case ACL_EVENT_XCPT: + notify_fn(event_type, ioc, stream, arg); + break; + default: + acl_msg_fatal("%s(%d): unknown event type(%d)", + __FILE__, __LINE__, event_type); + /* not reached */ + break; + } +} + +void listen_notify_callback(int event_type, void *context) +{ + ACL_IOCTL_CTX *ctx= (ACL_IOCTL_CTX *) context; + ACL_IOCTL *ioc = (ACL_IOCTL*) ctx->ioc; + ACL_VSTREAM *stream = ctx->stream; + ACL_IOCTL_NOTIFY_FN notify_fn = ctx->notify_fn; + void *arg = ctx->context; + + ctx->event_type = event_type; + + switch (event_type) { + case ACL_EVENT_RW_TIMEOUT: + case ACL_EVENT_XCPT: + acl_event_disable_read(ioc->event, stream); + case ACL_EVENT_READ: + notify_fn(event_type, ioc, stream, arg); + break; + default: + acl_msg_fatal("%s(%d): unknown event type(%d)", + __FILE__, __LINE__, event_type); + /* not reached */ + break; + } +} diff --git a/lib_acl/src/ioctl/ioctl_thr.c b/lib_acl/src/ioctl/ioctl_thr.c new file mode 100644 index 000000000..638ca5e38 --- /dev/null +++ b/lib_acl/src/ioctl/ioctl_thr.c @@ -0,0 +1,137 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_stdlib.h" +#include "event/acl_events.h" +#include "thread/acl_pthread_pool.h" +#include "net/acl_net.h" +#include "ioctl/acl_ioctl.h" + +#endif + +#include "ioctl_internal.h" + +static void worker_callback_r(void *context) +{ + ACL_IOCTL_CTX *ctx = (ACL_IOCTL_CTX *) context; + ACL_IOCTL *ioc = ctx->ioc; + ACL_VSTREAM *stream = ctx->stream; + ACL_IOCTL_NOTIFY_FN notify_fn = ctx->notify_fn; + void *arg = ctx->context; + + notify_fn(ctx->event_type, ioc, stream, arg); +} + +void read_notify_callback_r(int event_type, void *context) +{ + ACL_IOCTL_CTX *ctx = (ACL_IOCTL_CTX *) context; + ACL_IOCTL *ioc = ctx->ioc; + + ctx->event_type = event_type; + + switch (event_type) { + case ACL_EVENT_READ: + case ACL_EVENT_RW_TIMEOUT: + case ACL_EVENT_XCPT: + acl_pthread_pool_add(ioc->tp, worker_callback_r, ctx); + break; + default: + acl_msg_fatal("%s(%d): unknown event type(%d)", + __FILE__, __LINE__, event_type); + /* not reached */ + break; + } +} + +void write_notify_callback_r(int event_type, void *context) +{ + ACL_IOCTL_CTX *ctx = (ACL_IOCTL_CTX *) context; + ACL_IOCTL *ioc = ctx->ioc; + + ctx->event_type = event_type; + + switch (event_type) { + case ACL_EVENT_WRITE: + case ACL_EVENT_RW_TIMEOUT: + case ACL_EVENT_XCPT: + acl_pthread_pool_add(ioc->tp, worker_callback_r, ctx); + break; + default: + acl_msg_fatal("%s(%d): unknown event type(%d)", + __FILE__, __LINE__, event_type); + /* not reached */ + break; + } +} + +void listen_notify_callback_r(int event_type, void *context) +{ + ACL_IOCTL_CTX *ctx= (ACL_IOCTL_CTX *) context; + ACL_IOCTL *ioc = ctx->ioc; + ACL_VSTREAM *stream = ctx->stream; + ACL_IOCTL_NOTIFY_FN notify_fn = ctx->notify_fn; + void *arg = ctx->context; + + ctx->event_type = event_type; + + switch (event_type) { + case ACL_EVENT_READ: + case ACL_EVENT_RW_TIMEOUT: + case ACL_EVENT_XCPT: + notify_fn(event_type, ioc, stream, arg); + break; + default: + acl_msg_fatal("%s(%d): unknown event type(%d)", + __FILE__, __LINE__, event_type); + /* not reached */ + break; + } +} + +static void worker_ready_callback(void *context) +{ + ACL_IOCTL_CTX *ctx = (ACL_IOCTL_CTX *) context; + ACL_IOCTL *ioc = ctx->ioc; + ACL_IOCTL_WORKER_FN callback = ctx->worker_fn; + void *arg = ctx->context; + + acl_myfree(ctx); + callback(ioc, arg); +} + +int acl_ioctl_add(ACL_IOCTL *ioc, ACL_IOCTL_WORKER_FN callback, void *arg) +{ + const char *myname = "acl_ioctl_add"; + ACL_IOCTL_CTX *ctx; + int ret; + + if (ioc == NULL || ioc->tp == NULL) + acl_msg_fatal("%s(%d): input invalid", myname, __LINE__); + + ctx = acl_mymalloc(sizeof(ACL_IOCTL_CTX)); + ctx->ioc = ioc; + ctx->worker_fn = callback; + ctx->context = arg; + + ret = acl_pthread_pool_add(ioc->tp, worker_ready_callback, ctx); + if (ret != 0) { + acl_msg_error("thread pool add failed!"); + acl_myfree(ctx); + } + + return (ret); +} + +int acl_ioctl_nworker(ACL_IOCTL *ioc) +{ + return acl_pthread_pool_size(ioc->tp); +} diff --git a/lib_acl/src/json/acl_json.c b/lib_acl/src/json/acl_json.c new file mode 100644 index 000000000..ae52b095e --- /dev/null +++ b/lib_acl/src/json/acl_json.c @@ -0,0 +1,499 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_msg.h" +#include "json/acl_json.h" +#include "stdlib/acl_vstring.h" +#endif + +#define LEN ACL_VSTRING_LEN +#define STR acl_vstring_str + +static ACL_JSON_NODE *node_iter_head(ACL_ITER *it, ACL_JSON_NODE *node) +{ + ACL_RING *ring_ptr; + + it->dlen = -1; + it->key = NULL; + it->klen = -1; + + it->i = 0; + it->size = node->children.len; + + if ((ring_ptr = acl_ring_succ(&node->children)) == &node->children) { + it->ptr = it->data = NULL; + return (NULL); + } + it->ptr = acl_ring_to_appl(ring_ptr, ACL_JSON_NODE, node); + it->data = it->ptr; + return (it->ptr); +} + +static ACL_JSON_NODE *node_iter_next(ACL_ITER *it, ACL_JSON_NODE *node) +{ + ACL_RING *ring_ptr; + struct ACL_JSON_NODE *child; + + child = (struct ACL_JSON_NODE*) it->data; + if ((ring_ptr = acl_ring_succ(&child->node)) == &node->children) { + it->ptr = it->data = NULL; + return (NULL); + } + it->i++; + it->ptr = acl_ring_to_appl(ring_ptr, ACL_JSON_NODE, node); + it->data = it->ptr; + return (it->ptr); +} + +static ACL_JSON_NODE *node_iter_tail(ACL_ITER *it, ACL_JSON_NODE *node) +{ + ACL_RING *ring_ptr; + + it->dlen = -1; + it->key = NULL; + it->klen = -1; + + it->i = 0; + it->size = node->children.len; + + if ((ring_ptr = acl_ring_pred(&node->children)) == &node->children) { + it->ptr = it->data = NULL; + return (NULL); + } + + it->ptr = acl_ring_to_appl(ring_ptr, ACL_JSON_NODE, node); + it->data = it->ptr; + return (it->ptr); +} + +static ACL_JSON_NODE *node_iter_prev(ACL_ITER *it, ACL_JSON_NODE *node) +{ + ACL_RING *ring_ptr; + struct ACL_JSON_NODE *child; + + child = (struct ACL_JSON_NODE*) it->data; + if ((ring_ptr = acl_ring_pred(&child->node)) == &node->children) { + it->ptr = it->data = NULL; + return (NULL); + } + it->i++; + it->ptr = acl_ring_to_appl(ring_ptr, ACL_JSON_NODE, node); + it->data = it->ptr; + return (it->ptr); +} + +static void acl_json_node_reset(ACL_JSON_NODE *node) +{ + ACL_VSTRING_RESET(node->ltag); + ACL_VSTRING_RESET(node->text); + ACL_VSTRING_TERMINATE(node->ltag); + ACL_VSTRING_TERMINATE(node->text); + + node->tag_node = NULL; + node->type = ACL_JSON_T_LEAF; + + node->parent = NULL; + acl_ring_init(&node->children); + node->depth = 0; + + acl_ring_init(&node->node); + node->quote = 0; + node->status = -1; + node->backslash = 0; + node->left_ch = node->right_ch = 0; + node->part_word = 0; +} + +ACL_JSON_NODE *acl_json_node_alloc(ACL_JSON *json) +{ + ACL_JSON_NODE *node; + + if (json->node_cache) { + node = (ACL_JSON_NODE*) + json->node_cache->pop_back(json->node_cache); + if (node) { + acl_json_node_reset(node); + node->json = json; + json->node_cnt++; + return (node); + } + } + + if (json->slice) + node = (ACL_JSON_NODE*) acl_slice_pool_calloc(__FILE__, __LINE__, + json->slice, 1, sizeof(ACL_JSON_NODE)); + else + node = (ACL_JSON_NODE*) acl_mycalloc(1, sizeof(ACL_JSON_NODE)); + acl_ring_init(&node->children); + acl_ring_init(&node->node); + + node->json = json; + node->status = ACL_JSON_S_NXT; + node->ltag = acl_vstring_alloc2(json->slice, 16); + node->text = acl_vstring_alloc2(json->slice, 16); + node->part_word = 0; + json->node_cnt++; + + node->iter_head = node_iter_head; + node->iter_next = node_iter_next; + node->iter_tail = node_iter_tail; + node->iter_prev = node_iter_prev; + return (node); +} + +static void acl_json_node_free(ACL_JSON_NODE *node) +{ + acl_vstring_free(node->ltag); + acl_vstring_free(node->text); + acl_ring_detach(&node->node); + if (node->json->slice) + acl_slice_pool_free(__FILE__, __LINE__, node); + else + acl_myfree(node); +} + +int acl_json_node_delete(ACL_JSON_NODE *node) +{ + ACL_RING *next; + ACL_JSON_NODE *node_next; + int n = 1; + + while ((next = acl_ring_pop_head(&node->children)) != NULL) { + node_next = acl_ring_to_appl(next, ACL_JSON_NODE, node); + n += acl_json_node_delete(node_next); + } + + node->json->node_cnt--; + if (node->json->node_cache && + acl_array_size(node->json->node_cache) < node->json->max_cache) + { + node->json->node_cache->push_back(node->json->node_cache, node); + acl_ring_detach(&node->node); + } else + acl_json_node_free(node); + return (n); +} + +void acl_json_node_append(ACL_JSON_NODE *node1, ACL_JSON_NODE *node2) +{ + acl_ring_append(&node1->node, &node2->node); + node2->parent = node1->parent; +} + +void acl_json_node_add_child(ACL_JSON_NODE *parent, ACL_JSON_NODE *child) +{ + acl_ring_prepend(&parent->children, &child->node); + child->parent = parent; +} + +ACL_JSON_NODE *acl_json_node_parent(ACL_JSON_NODE *node) +{ + return (node->parent); +} + +ACL_JSON_NODE *acl_json_node_next(ACL_JSON_NODE *node) +{ + ACL_RING *ring_ptr = acl_ring_succ(&node->node); + ACL_JSON_NODE *parent; + + if (ring_ptr == &node->node) + return (NULL); + parent = node->parent; + acl_assert(parent != NULL); + if (ring_ptr == &parent->children) + return (NULL); + return (acl_ring_to_appl(ring_ptr, ACL_JSON_NODE, node)); +} + +ACL_JSON_NODE *acl_json_node_prev(ACL_JSON_NODE *node) +{ + ACL_RING *ring_ptr = acl_ring_pred(&node->node); + ACL_JSON_NODE *parent; + + if (ring_ptr == &node->node) + return (NULL); + parent = node->parent; + acl_assert(parent != NULL); + if (ring_ptr == &parent->children) + return (NULL); + + return (acl_ring_to_appl(ring_ptr, ACL_JSON_NODE, node)); +} + +const char *acl_json_node_type(const ACL_JSON_NODE *node) +{ + static char *types_tab[] = { "leaf node", "node object", "array object" }; + static char *unknown = "unknown"; + + if (node->type >= 0 && node->type <= 2) + return (types_tab[node->type]); + return (unknown); +} + +/************************************************************************/ +/* json 对象处理函数集 */ +/************************************************************************/ + +static ACL_JSON_NODE *json_iter_head(ACL_ITER *it, ACL_JSON *json) +{ + ACL_RING *ring_ptr; + + it->dlen = -1; + it->key = NULL; + it->klen = -1; + + it->i = 0; + it->size = json->node_cnt; + + ring_ptr = acl_ring_succ(&json->root->children); + if (ring_ptr== &json->root->children) { + it->ptr = it->data = NULL; + return (NULL); + } + it->ptr = acl_ring_to_appl(ring_ptr, ACL_JSON_NODE, node); + it->data = it->ptr; + + return (it->ptr); +} + +static ACL_JSON_NODE *json_iter_next(ACL_ITER *it, ACL_JSON *json) +{ + ACL_RING *ring_ptr; + struct ACL_JSON_NODE *node, *parent; + + node = (struct ACL_JSON_NODE*) it->data; + + /* 先遍历当前结点的子结点 */ + + ring_ptr = acl_ring_succ(&node->children); + if (ring_ptr != &node->children) { + it->i++; + it->ptr = acl_ring_to_appl(ring_ptr, ACL_JSON_NODE, node); + it->data = it->ptr; + return (it->ptr); + } + + /* 当前结点的子结点遍历完毕,再遍历当前结点的兄弟结点 */ + + parent = acl_json_node_parent(node); + ring_ptr = acl_ring_succ(&node->node); + if (ring_ptr != &parent->children) { + it->i++; + it->ptr = acl_ring_to_appl(ring_ptr, ACL_JSON_NODE, node); + it->data = it->ptr; + return (it->ptr); + } + + /* 当前结点的兄弟结点遍历完毕,最后遍历当前结点的父结点的兄弟结点 */ + + do { + if (parent == json->root) + break; + + ring_ptr = acl_ring_succ(&parent->node); + parent = acl_json_node_parent(parent); + if (parent == NULL) + acl_msg_fatal("%s(%d): parent null", __FILE__, __LINE__); + + if (ring_ptr != &parent->children) { + it->i++; + it->ptr = acl_ring_to_appl(ring_ptr, ACL_JSON_NODE, node); + it->data = it->ptr; + return (it->ptr); + } + } while (ring_ptr != &json->root->children); + + /* 遍历完所有结点 */ + + it->ptr = it->data = NULL; + return (NULL); +} + +static ACL_JSON_NODE *json_iter_tail(ACL_ITER *it, ACL_JSON *json) +{ + ACL_RING *ring_ptr; + + it->dlen = -1; + it->key = NULL; + it->klen = -1; + + it->i = 0; + it->size = json->node_cnt; + + ring_ptr = acl_ring_pred(&json->root->children); + if (ring_ptr== &json->root->children) { + it->ptr = it->data = NULL; + return (NULL); + } + it->ptr = acl_ring_to_appl(ring_ptr, ACL_JSON_NODE, node); + it->data = it->ptr; + return (it->ptr); +} + +static ACL_JSON_NODE *json_iter_prev(ACL_ITER *it, ACL_JSON *json) +{ + ACL_RING *ring_ptr; + struct ACL_JSON_NODE *node, *parent; + + node = (struct ACL_JSON_NODE*) it->data; + + /* 先遍历当前结点的子结点 */ + + ring_ptr = acl_ring_pred(&node->children); + if (ring_ptr != &node->children) { + it->i++; + it->ptr = acl_ring_to_appl(ring_ptr, ACL_JSON_NODE, node); + it->data = it->ptr; + return (it->ptr); + } + + /* 当前结点的子结点遍历完毕,再遍历当前结点的兄弟结点 */ + + parent = acl_json_node_parent(node); + ring_ptr = acl_ring_pred(&node->node); + if (ring_ptr != &parent->children) { + it->i++; + it->ptr = acl_ring_to_appl(ring_ptr, ACL_JSON_NODE, node); + it->data = it->ptr; + return (it->ptr); + } + + /* 当前结点的兄弟结点遍历完毕,最后遍历当前结点的父结点的兄弟结点 */ + + do { + if (parent == json->root) + break; + ring_ptr = acl_ring_pred(&parent->node); + parent = acl_json_node_parent(parent); + if (parent == NULL) + acl_msg_fatal("%s(%d): parent null", __FILE__, __LINE__); + + if (ring_ptr != &parent->children) { + it->i++; + it->ptr = acl_ring_to_appl(ring_ptr, ACL_JSON_NODE, node); + it->data = it->ptr; + return (it->ptr); + } + } while (ring_ptr != &json->root->children); + + /* 遍历完所有结点 */ + + it->ptr = it->data = NULL; + return (NULL); +} + +ACL_JSON *acl_json_alloc() +{ + return (acl_json_alloc1(NULL)); +} + +ACL_JSON *acl_json_alloc1(ACL_SLICE_POOL *slice) +{ + ACL_JSON *json; + + if (slice) { + json = (ACL_JSON*) acl_slice_pool_calloc(__FILE__, __LINE__, + slice, 1, sizeof(ACL_JSON)); + json->slice = slice; + } else { + json = (ACL_JSON*) acl_mycalloc(1, sizeof(ACL_JSON)); + json->slice = NULL; + } + + json->root = acl_json_node_alloc(json); + /* 将根结点作为当前结点 */ + json->curr_node = json->root; + /* 设置根结点的属性状态 */ + json->curr_node->status = ACL_JSON_S_ROOT; + + /* 设置迭代函数 */ + + json->iter_head = json_iter_head; + json->iter_next = json_iter_next; + json->iter_tail = json_iter_tail; + json->iter_prev = json_iter_prev; + return (json); +} + +void acl_json_foreach_init(ACL_JSON *json, ACL_JSON_NODE *node) +{ + json->root = node; + json->iter_head = json_iter_head; + json->iter_next = json_iter_next; + json->iter_tail = json_iter_tail; + json->iter_prev = json_iter_prev; +} + +void acl_json_cache(ACL_JSON *json, int max_cache) +{ + if (json->node_cache != NULL) { + acl_array_free(json->node_cache, + (void (*)(void*)) acl_json_node_free); + json->node_cache = NULL; + json->max_cache = 0; + } + if (max_cache > 0) { + json->node_cache = acl_array_create(max_cache); + json->max_cache = max_cache; + } +} + +void acl_json_cache_free(ACL_JSON *json) +{ + if (json->node_cache != NULL) { + acl_array_free(json->node_cache, + (void (*)(void*)) acl_json_node_free); + json->node_cache = NULL; + json->max_cache = 0; + } +} + +int acl_json_free(ACL_JSON *json) +{ + ACL_RING *next; + ACL_JSON_NODE *node; + int n = 1; + + while ((next = acl_ring_pop_head(&json->root->children)) != NULL) { + node = acl_ring_to_appl(next, ACL_JSON_NODE, node); + n += acl_json_node_delete(node); + } + + acl_json_node_free(json->root); + json->node_cnt--; + acl_assert(json->node_cnt == 0); + if (json->node_cache != NULL) + acl_array_free(json->node_cache, + (void (*)(void*)) acl_json_node_free); + if (json->slice) + acl_slice_pool_free(__FILE__, __LINE__, json); + else + acl_myfree(json); + return (n); +} + +void acl_json_reset(ACL_JSON *json) +{ + const char *myname = "acl_json_reset"; + ACL_RING *next; + ACL_JSON_NODE *node; + + while ((next = acl_ring_pop_head(&json->root->children)) != NULL) { + node = acl_ring_to_appl(next, ACL_JSON_NODE, node); + (void) acl_json_node_delete(node); + } + + /* 因为根结点是一个虚结点,所以不需要释放,其会在调用 + * acl_json_free 时被释放 + */ + acl_ring_detach(&json->root->node); + acl_json_node_reset(json->root); + if (json->node_cnt != 1) + acl_msg_fatal("%s(%d): node_cnt(%d) invalid", + myname, __LINE__, json->node_cnt); + + json->root->status = ACL_JSON_S_ROOT; + json->curr_node = json->root; + json->finish = 0; + json->depth = 0; +} diff --git a/lib_acl/src/json/acl_json_parse.c b/lib_acl/src/json/acl_json_parse.c new file mode 100644 index 000000000..21d2a54b9 --- /dev/null +++ b/lib_acl/src/json/acl_json_parse.c @@ -0,0 +1,422 @@ +#include "StdAfx.h" +#include +#ifndef ACL_PREPARE_COMPILE +#include "json/acl_json.h" +#endif + +#define LEN ACL_VSTRING_LEN +#define STR acl_vstring_str +#define END acl_vstring_end +#define IS_QUOTE(x) ((x) == '\"' || (x) == '\'') +#define IS_SPACE(c) ((c) == ' ' || (c) == '\t' || (c) == '\r' || (c) == '\n') +#define SKIP_WHILE(cond, ptr) { while(*(ptr) && (cond)) (ptr)++; } +#define SKIP_SPACE(ptr) { while(IS_SPACE(*(ptr))) (ptr)++; } + +/* 分析结点对象值,必须找到 '{' 或 '[' */ + +static const char *json_obj(ACL_JSON *json, const char *data) +{ + ACL_JSON_NODE *node; + + SKIP_SPACE(data); + + /* 必须找到子结点的开始字符 */ + SKIP_WHILE(*data != '{' && *data != '[', data); + + if (*data == 0) + return (NULL); + + /* 需要把当前结点的状态置 ACL_JSON_S_NXT 以便子结点 + * 处理完毕返回该结点时可以继续查找该结点的兄弟结点 + */ + if (json->curr_node != json->root) + json->curr_node->status = ACL_JSON_S_NXT; + + /* 根据 json 结点对象前缀的不同,记录不同的对象后缀 */ + + json->curr_node->left_ch = *data; + if (*data == '{') { + json->curr_node->right_ch = '}'; + json->curr_node->type = ACL_JSON_T_NODE; + } else { + json->curr_node->right_ch = ']'; + json->curr_node->type = ACL_JSON_T_ARRAY; + } + + /* 去掉前导符 '{' 或 '[' */ + data++; + + /* 创建子结点,并将子结点设为当前结点 */ + + node = acl_json_node_alloc(json); + acl_json_node_add_child(json->curr_node, node); + node->depth = json->curr_node->depth + 1; + if (node->depth > json->depth) + json->depth = node->depth; + node->status = ACL_JSON_S_TAG; + + /* 当前结点的标签非空时表示新结点为当前结点标签的json 结点 */ + if (LEN(json->curr_node->ltag) > 0) + json->curr_node->tag_node = node; + + /* 设置新的结点为当前处理结点 */ + json->curr_node = node; + + return (data); +} + +/* 从根结点开始分析 */ + +static const char *json_root(ACL_JSON *json, const char *data) +{ + acl_assert(json->root == json->curr_node); + + /* 根结点没有标签名,只有子结点 */ + return (json_obj(json, data)); +} + +/* 尝试分析本结点的下一个兄弟结点,必须能找到分隔符 ',' 或 ';' */ + +static const char *json_next(ACL_JSON *json, const char *data) +{ + ACL_JSON_NODE *node; + + /* 根结点不可能有兄弟结点 */ + acl_assert(json->curr_node != json->root); + + SKIP_SPACE(data); + if (*data == 0) + return (NULL); + + /* 如果到达根结点的结束符,则 json 解析过程完毕 */ + node = acl_json_node_parent(json->curr_node); + if (*data == node->right_ch) { + data++; + if (node == json->root) { + json->finish = 1; + return (NULL); + } + /* 弹出父结点 */ + json->curr_node = node; + /* 查询父结点的下一个兄弟结点 */ + json->curr_node->status = ACL_JSON_S_NXT; + return (data); + } + + /* 必须得先找到分隔符: ',' 或 ';' 才能启动下一个兄弟结点的解析过程 */ + + SKIP_WHILE(*data != ',' && *data != ';', data); + if (*data == 0) + return (NULL); + + data++; + + /* 创建新结点,并将其作为当前结点的兄弟结点 */ + + node = acl_json_node_alloc(json); + acl_json_node_append(json->curr_node, node); + node->depth = json->curr_node->depth; + json->curr_node = node; + + /* 下一步需要分析标签名 */ + json->curr_node->status = ACL_JSON_S_TAG; + return (data); +} + +/* 解析结点的标签名称,结点允许没有标签名;叶结点没有 { } [ ] 分隔符 */ + +static const char *json_tag(ACL_JSON *json, const char *data) +{ + int ch; + + /* 开始分析标签时,需要检查该标签名前是否有引号,并清除多余空格 */ + if (LEN(json->curr_node->ltag) == 0 && json->curr_node->quote == 0) { + ACL_JSON_NODE *node = acl_json_node_parent(json->curr_node); + + acl_assert(node); + SKIP_SPACE(data); + + /* 如果当前字符为父结点的右分隔符,则表示父结点结束 */ + if (*data == node->right_ch) { + data++; /* 去掉父结点的右分隔符 */ + + if (node == json->root) { + /* 如果根结点分析结束则整个 json 分析完毕 */ + json->finish = 1; + return (NULL); + } + /* 弹出父结点 */ + json->curr_node = node; + /* 查询父结点的下一个兄弟结点 */ + json->curr_node->status = ACL_JSON_S_NXT; + return (data); + } + + if (*data == '{' || *data == '[') { + /* 为 '{' 或 '[' 时说明遇到了当前结点的子结点 */ + + json->curr_node->status = ACL_JSON_S_OBJ; + return (data); + } + + /* 如果标签名前有引号,记录下该引号 */ + if (IS_QUOTE(*data) && json->curr_node->quote == 0) + json->curr_node->quote = *data++; + } + + while ((ch = *data) != 0) { + /* 如果前面有引号,则需要找到结尾引号 */ + if (json->curr_node->quote) { + if (json->curr_node->backslash) { + ACL_VSTRING_ADDCH(json->curr_node->ltag, ch); + json->curr_node->backslash = 0; + } + + /* 当为双字节汉字时,第一个字节为的高位为 1, + * 第二个字节为 92,正好与转义字符相同 + */ + else if (ch == '\\') { + /* 处理半个汉字的情形 */ + if (json->curr_node->part_word) { + ACL_VSTRING_ADDCH(json->curr_node->ltag, ch); + json->curr_node->part_word = 0; + } else + json->curr_node->backslash = 1; + } else if (ch == json->curr_node->quote) { + ACL_JSON_NODE *parent = + acl_json_node_parent(json->curr_node); + if (parent->left_ch == '[') + json->curr_node->status = ACL_JSON_S_NXT; + /* 标签值分析结束,下一步需要找到冒号 */ + else + json->curr_node->status = ACL_JSON_S_COL; + json->curr_node->quote = 0; + json->curr_node->part_word = 0; + data++; + break; + } else { + ACL_VSTRING_ADDCH(json->curr_node->ltag, ch); + + /* 是否兼容后半个汉字为转义符 '\' 的情况 */ + if ((json->flag & ACL_JSON_FLAG_PART_WORD)) { + /* 处理半个汉字的情形 */ + if (json->curr_node->part_word) + json->curr_node->part_word = 0; + else if (ch < 0) + json->curr_node->part_word = 1; + } + } + } + + /* 分析标签名前没有引号的情况 */ + + else if (json->curr_node->backslash) { + ACL_VSTRING_ADDCH(json->curr_node->ltag, ch); + json->curr_node->backslash = 0; + } + + /* 当为双字节汉字时,第一个字节为的高位为 1, + * 第二个字节为 92,正好与转义字符相同 + */ + else if (ch == '\\') { + /* 处理半个汉字的情形 */ + if (json->curr_node->part_word) { + ACL_VSTRING_ADDCH(json->curr_node->ltag, ch); + json->curr_node->part_word = 0; + } else + json->curr_node->backslash = 1; + } else if (IS_SPACE(ch) || ch == ':') { + /* 标签名分析结束,下一步需要找到冒号 */ + json->curr_node->status = ACL_JSON_S_COL; + json->curr_node->part_word = 0; + break; + } else { + ACL_VSTRING_ADDCH(json->curr_node->ltag, ch); + + /* 是否兼容后半个汉字为转义符 '\' 的情况 */ + if ((json->flag & ACL_JSON_FLAG_PART_WORD)) { + /* 处理半个汉字的情形 */ + if (json->curr_node->part_word) + json->curr_node->part_word = 0; + else if (ch < 0) + json->curr_node->part_word = 1; + } + } + data++; + } + + /* 如果标签名非空,则需要保证以 0 结尾 */ + if (LEN(json->curr_node->ltag) > 0) + ACL_VSTRING_TERMINATE(json->curr_node->ltag); + return (data); +} + +/* 一直查到冒号为止,然后切换至分析标签值过程 */ + +static const char *json_colon(ACL_JSON *json, const char *data) +{ + SKIP_SPACE(data); + if (*data == 0) + return (NULL); + else if (*data != ':') { + data++; + return (data); + } else { + data++; + /* 下一步分析标签名所对应的标签值,有可能为字符串, + * 也有可能为子结点对象 + */ + json->curr_node->status = ACL_JSON_S_VAL; + return (data); + } +} + +/* 分析标签值,该值有可能是纯文本(即该结点为叶结点),也有可能是一个子结点 */ + +static const char *json_val(ACL_JSON *json, const char *data) +{ + int ch; + + /* 当文本长度为 0 时,可以认为还未遇到有效的字符 */ + + if (LEN(json->curr_node->text) == 0 && json->curr_node->quote == 0) { + /* 先过滤开头没用的空格 */ + SKIP_SPACE(data); + SKIP_WHILE(*data == ':', data); + if (*data == 0) + return (NULL); + + if (*data == '{' || *data == '[') { + /* 为 '{' 或 '[' 时说明遇到了当前结点的子结点 */ + + json->curr_node->status = ACL_JSON_S_OBJ; + return (data); + } + + /* 兼容一下有些数据格式为 "xxx: ," 的方式 */ + if (*data == ',' || *data == ';') { + /* 切换至查询该结点的兄弟结点的过程 */ + json->curr_node->status = ACL_JSON_S_NXT; + return (data); + } + + /* 说明标签名后面的标签值为字符串或数字 */ + + /* 如果标签值前有引号,记录下该引号 */ + if (IS_QUOTE(*data) && json->curr_node->quote == 0) + json->curr_node->quote = *data++; + } + + /* 说明本结点是叶结点 */ + + while ((ch = *data) != 0) { + /* 如果开始有引号,则需要以该引号作为结尾符 */ + if (json->curr_node->quote) { + if (json->curr_node->backslash) { + ACL_VSTRING_ADDCH(json->curr_node->text, ch); + json->curr_node->backslash = 0; + } + + /* 当为双字节汉字时,第一个字节为的高位为 1, + * 第二个字节有可能为 92,正好与转义字符相同 + */ + else if (ch == '\\') { + /* 处理半个汉字的情况,如果前一个字节是前半个汉字, + * 则当前的转义符当作后半个汉字 + */ + if (json->curr_node->part_word) { + ACL_VSTRING_ADDCH(json->curr_node->text, ch); + json->curr_node->part_word = 0; + } else + json->curr_node->backslash = 1; + } else if (ch == json->curr_node->quote) { + json->curr_node->quote = 0; + + /* 切换至查询该结点的兄弟结点的过程 */ + json->curr_node->status = ACL_JSON_S_NXT; + json->curr_node->part_word = 0; + data++; + break; + } else { + ACL_VSTRING_ADDCH(json->curr_node->text, ch); + + /* 是否兼容后半个汉字为转义符 '\' 的情况 */ + if ((json->flag & ACL_JSON_FLAG_PART_WORD)) { + /* 若前一个字节为前半个汉字,则当前字节 + * 为后半个汉字,正好为一个完整的汉字 + */ + if (json->curr_node->part_word) + json->curr_node->part_word = 0; + + /* 前一个字节非前半个汉字且当前字节高位为 1, + * 则表明当前字节为前半个汉字 + */ + else if (ch < 0) + json->curr_node->part_word = 1; + } + } + } else if (json->curr_node->backslash) { + ACL_VSTRING_ADDCH(json->curr_node->text, ch); + json->curr_node->backslash = 0; + } else if (ch == '\\') { + if (json->curr_node->part_word) { + ACL_VSTRING_ADDCH(json->curr_node->text, ch); + json->curr_node->part_word = 0; + } else + json->curr_node->backslash = 1; + } else if (IS_SPACE(ch) || ch == ',' || ch == ';' + || ch == '}' || ch == ']') + { + /* 切换至查询该结点的兄弟结点的过程 */ + json->curr_node->status = ACL_JSON_S_NXT; + break; + } else { + ACL_VSTRING_ADDCH(json->curr_node->text, ch); + + /* 是否兼容后半个汉字为转义符 '\' 的情况 */ + if ((json->flag & ACL_JSON_FLAG_PART_WORD)) { + /* 处理半个汉字的情形 */ + if (json->curr_node->part_word) + json->curr_node->part_word = 0; + else if (ch < 0) + json->curr_node->part_word = 1; + } + } + data++; + } + + if (LEN(json->curr_node->text) > 0) + ACL_VSTRING_TERMINATE(json->curr_node->text); + return (data); +} + +/* 状态机数据结构类型 */ + +struct JSON_STATUS_MACHINE { + int status; /**< 状态码 */ + const char *(*callback) (ACL_JSON*, const char*); /**< 状态机处理函数 */ +}; + +static struct JSON_STATUS_MACHINE status_tab[] = { + { ACL_JSON_S_ROOT, json_root }, /* parse root */ + { ACL_JSON_S_OBJ, json_obj }, /* begin json node */ + { ACL_JSON_S_NXT, json_next }, /* parse brother node */ + { ACL_JSON_S_TAG, json_tag }, /* for tag name */ + { ACL_JSON_S_VAL, json_val }, /* for tag value */ + { ACL_JSON_S_COL, json_colon }, /* for ':' */ +}; + +void acl_json_update(ACL_JSON *json, const char *data) +{ + const char *ptr = data; + + /* 检查是否已经解析完毕 */ + if (json->finish) + return; + + /* json 解析器状态机循环处理过程 */ + + while (ptr && *ptr) { + ptr = status_tab[json->curr_node->status].callback(json, ptr); + } +} diff --git a/lib_acl/src/json/acl_json_util.c b/lib_acl/src/json/acl_json_util.c new file mode 100644 index 000000000..df3ed9a87 --- /dev/null +++ b/lib_acl/src/json/acl_json_util.c @@ -0,0 +1,227 @@ +#include "StdAfx.h" +#include +#ifndef ACL_PREPARE_COMPILE +#include "stdlib/acl_iterator.h" +#include "stdlib/acl_vstring.h" +#include "stdlib/acl_mystring.h" +#include "stdlib/acl_array.h" +#include "stdlib/acl_argv.h" +#include "stdlib/acl_msg.h" +#include "json/acl_json.h" +#endif + +#define STR acl_vstring_str + +void acl_json_free_array(ACL_ARRAY *a) +{ + acl_array_destroy(a, NULL); +} + +ACL_ARRAY *acl_json_getElementsByTagName(ACL_JSON *json, const char *tag) +{ + ACL_ITER iter; + ACL_ARRAY *a = acl_array_create(10); + + acl_foreach(iter, json) { + ACL_JSON_NODE *node = (ACL_JSON_NODE*) iter.data; + if (strcasecmp(tag, STR(node->ltag)) == 0) { + acl_array_append(a, node); + } + } + + if (acl_array_size(a) == 0) { + acl_array_destroy(a, NULL); + return (NULL); + } + + return (a); +} + +ACL_ARRAY *acl_json_getElementsByTags(ACL_JSON *json, const char *tags) +{ + ACL_ARGV *tokens = acl_argv_split(tags, "/"); + ACL_ARRAY *a, *ret; + ACL_ITER iter; + + a = acl_json_getElementsByTagName(json, tokens->argv[tokens->argc - 1]); + if (a == NULL) { + acl_argv_free(tokens); + return (NULL); + } + + ret = acl_array_create(acl_array_size(a)); + + acl_foreach(iter, a) { + ACL_JSON_NODE *node_saved, *node = (ACL_JSON_NODE*) iter.data; + int i = tokens->argc - 1; + node_saved = node; + while (i >= 0 && node->parent != NULL) { + if (strcasecmp(tokens->argv[i], "*") != 0 && + strcasecmp(tokens->argv[i], STR(node->ltag)) != 0) + { + break; + } + i--; + node = node->parent; + } + if (i == -1) + ret->push_back(ret, node_saved); + } + + acl_json_free_array(a); + acl_argv_free(tokens); + + if (acl_array_size(ret) == 0) { + acl_array_free(ret, NULL); + ret = NULL; + } + return (ret); +} + +#define LEN ACL_VSTRING_LEN +#define STR acl_vstring_str + +ACL_JSON_NODE *acl_json_create_leaf(ACL_JSON *json, + const char *name, const char *text) +{ + ACL_JSON_NODE *node = acl_json_node_alloc(json); + + acl_vstring_strcpy(node->ltag, name); + acl_vstring_strcpy(node->text, text); + node->type = ACL_JSON_T_LEAF; + return (node); +} + +ACL_JSON_NODE *acl_json_create_obj(ACL_JSON *json) +{ + ACL_JSON_NODE *node = acl_json_node_alloc(json); + + node->left_ch = '{'; + node->right_ch = '}'; + node->type = ACL_JSON_T_OBJ; + return (node); +} + +ACL_JSON_NODE *acl_json_create_array(ACL_JSON *json) +{ + ACL_JSON_NODE *node = acl_json_node_alloc(json); + + node->left_ch = '['; + node->right_ch = ']'; + node->type = ACL_JSON_T_ARRAY; + return (node); +} + +ACL_JSON_NODE *acl_json_create_node(ACL_JSON *json, + const char *name, ACL_JSON_NODE *value) +{ + ACL_JSON_NODE *node = acl_json_node_alloc(json); + + acl_vstring_strcpy(node->ltag, name); + node->tag_node = value; + node->type = ACL_JSON_T_NODE; + acl_json_node_add_child(node, value); + return (node); +} + +void acl_json_node_append_child(ACL_JSON_NODE *parent, ACL_JSON_NODE *child) +{ + const char *myname = "acl_json_node_append_child"; + + if (parent->type != ACL_JSON_T_ARRAY + && parent->type != ACL_JSON_T_OBJ + && parent != parent->json->root) + { + acl_msg_fatal("%s(%d): parent's type not array or obj", + myname, __LINE__); + } + acl_json_node_add_child(parent, child); +} + +static void json_escape_append(ACL_VSTRING *buf, const char *src) +{ + const unsigned char *ptr = (const unsigned char*) src; + + ACL_VSTRING_ADDCH(buf, '"'); + while (*ptr) { + if (*ptr == '"' || *ptr == '\\' || *ptr == '{' + || *ptr == '}' || *ptr == '[' || *ptr == ']') + { + ACL_VSTRING_ADDCH(buf, '\\'); + } + ACL_VSTRING_ADDCH(buf, *ptr); + ptr++; + } + ACL_VSTRING_ADDCH(buf, '"'); + ACL_VSTRING_TERMINATE(buf); +} + +ACL_VSTRING *acl_json_build(ACL_JSON *json, ACL_VSTRING *buf) +{ + ACL_JSON_NODE *node, *prev; + ACL_ITER iter; + + if (buf == NULL) + buf = acl_vstring_alloc(256); + + if (json->root->left_ch > 0) { + ACL_VSTRING_ADDCH(buf, json->root->left_ch); + ACL_VSTRING_TERMINATE(buf); + } + + acl_foreach(iter, json) { + node = (ACL_JSON_NODE*) iter.data; + prev = acl_json_node_prev(node); + + /* 只有当标签的对应值为 JSON 对象或数组对象时 tag_node 非空 */ + if (node->tag_node != NULL) { + if (prev != NULL) + acl_vstring_strcat(buf, ", "); + json_escape_append(buf, STR(node->ltag)); + ACL_VSTRING_ADDCH(buf, ':'); + ACL_VSTRING_ADDCH(buf, ' '); + if (node->left_ch != 0) { + /* '{' or '[' */ + ACL_VSTRING_ADDCH(buf, node->left_ch); + } + ACL_VSTRING_TERMINATE(buf); + continue; + } + + if (prev) + acl_vstring_strcat(buf, ", "); + + /* 当结点有标签名时 */ + if (LEN(node->ltag) > 0) { + json_escape_append(buf, STR(node->ltag)); + ACL_VSTRING_ADDCH(buf, ':'); + ACL_VSTRING_ADDCH(buf, ' '); + json_escape_append(buf, STR(node->text)); + } + + /* 当结点为没有标签名的容器(为 '{}' 或 '[]')时 */ + else if (node->left_ch != 0) { + ACL_VSTRING_ADDCH(buf, node->left_ch); + ACL_VSTRING_TERMINATE(buf); + } + + /* 当本结点有子结点或虽为叶结点,但该结点的下一个兄弟结点 + * 非空时继续下一个循环过程 + */ + if (acl_json_node_next(node) != NULL || acl_ring_size(&node->children) > 0) + continue; + + /* 当本结点为叶结点且后面没有兄弟结点时,需要一级一级回溯将父结点的分隔符 + * 添加至本叶结点尾部,直到遇到根结点或父结点的下一个兄弟结点非空 + */ + while (node != node->json->root && acl_json_node_next(node) == NULL) { + if (node->parent->right_ch != 0) { + /* node->parent->right_ch: '}' or ']' */ + ACL_VSTRING_ADDCH(buf, node->parent->right_ch); + ACL_VSTRING_TERMINATE(buf); + } + node = node->parent; + } + } + return (buf); +} diff --git a/lib_acl/src/master/daemon/master.c b/lib_acl/src/master/daemon/master.c new file mode 100644 index 000000000..ec4095490 --- /dev/null +++ b/lib_acl/src/master/daemon/master.c @@ -0,0 +1,219 @@ +/* System libraries. */ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "lib_acl.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#endif + +#ifdef ACL_UNIX + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +/* #include for safe_basename() */ + +#include "../master_params.h" +#include "../framework/master.h" + +char *var_master_version = "version1.0"; +char *var_master_procname; + +/* usage - show hint and terminate */ + +static void usage(const char *me) +{ + acl_msg_fatal("usage: %s [-c root_dir] [-l log_file] [-e exit_time]" + " [-D (debug)] [-t (test)] [-v] [-k (keep_mask)]", me); +} + +/* main - main program */ + +int main(int argc, char **argv) +{ + static ACL_VSTREAM *lock_fp = NULL; + int ch; + int fd; + int n, keep_mask = 0; + char *ptr; + ACL_WATCHDOG *watchdog; + ACL_VSTRING *strbuf; + + /* + * Strip and save the process name for diagnostics etc. + */ + var_master_procname = acl_mystrdup(acl_safe_basename(argv[0])); + acl_var_master_pid = getpid(); + + acl_var_master_conf_dir = NULL; + acl_var_master_log_file = NULL; + + while ((ch = getopt(argc, argv, "vc:l:k")) > 0) { + switch (ch) { + case 'v': + acl_msg_verbose++; + break; + case 'c': + acl_var_master_conf_dir = acl_mystrdup(optarg); + break; + case 'l': + acl_var_master_log_file = acl_mystrdup(optarg); + break; + case 'k': + keep_mask = 1; + break; + default: + usage(argv[0]); + /* NOTREACHED */ + } + } + + /* + * Initialize. + */ + if (!keep_mask) + umask(077); /* never fails! */ + + /* + * Don't die when a process goes away unexpectedly. + */ + signal(SIGPIPE, SIG_IGN); + + if (acl_var_master_conf_dir == NULL || acl_var_master_log_file == NULL) + usage(argv[0]); + + ptr = strrchr(acl_var_master_conf_dir, '/'); + if (ptr != NULL && *(ptr + 1) == '\0') /* as "/opt/master/conf/" */ + *ptr = '\0'; + + /* + * This program takes no other arguments. + */ + if (argc > optind) + usage(argv[0]); + + /* + * When running a child process, don't leak any open files that were + * leaked to us by our own (privileged) parent process. Descriptors 0-2 + * are taken care of after we have initialized error logging. + * + * Some systems such as AIX have a huge per-process open file limit. In + * those cases, limit the search for potential file descriptor leaks to + * just the first couple hundred. + * + * The Debian post-installation script passes an open file descriptor into + * the master process and waits forever for someone to close it. Because + * of this we have to close descriptors > 2, and pray that doing so does + * not break things. + */ + + acl_closefrom(3); /* 0: stdin; 1: stdout; 2: stderr */ + + /* + * Initialize logging and exit handler. + */ + /* 关闭 0, 以使该描述字供日志文件所用 :) */ + close(0); + acl_msg_open(acl_var_master_log_file, var_master_procname); + + /* + * If started from a terminal, get rid of any tty association. This also + * means that all errors and warnings must go to the syslog daemon. + */ + for (fd = 1; fd < 3; fd++) { + (void) close(fd); + if (open("/dev/null", O_RDWR, 0) != fd) + acl_msg_fatal("open /dev/null: %s", acl_last_serror()); + } + + /* + * Make some room for plumbing with file descriptors. XXX This breaks + * when a service listens on many ports. In order to do this right we + * must change the master-child interface so that descriptors do not need + * to have fixed numbers. + * + * In a child we need two descriptors for the flow control pipe, one for + * child->master status updates and at least one for listening. + */ + for (n = 0; n < 5; n++) { + fd = dup(1); + if (acl_close_on_exec(fd, ACL_CLOSE_ON_EXEC) < 0) + acl_msg_fatal("dup(0): %s", acl_last_serror()); + if (acl_msg_verbose) + acl_msg_info("dup(0), fd = %d, n = %d", fd, n); + } + + acl_master_flow_init(); /* just for prefork service -- zsx, 2012.3.24 */ + acl_master_config(); /* load configure and start all services processes */ + + /* + * Finish initialization, last part. We must process configuration + * files after processing command-line parameters, so that we get + * consistent results when we SIGHUP the server to reload + * configuration files. + */ + acl_master_sigsetup(); + + /* open pid file, lock it and write the master's pid value into it */ + + strbuf = acl_vstring_alloc(10); + + lock_fp = acl_open_lock(acl_var_master_pid_file, O_RDWR | O_CREAT, 0644, strbuf); + if (lock_fp == 0) + acl_msg_fatal("%s(%d): open lock file %s: %s", + __FILE__, __LINE__, + acl_var_master_pid_file, acl_vstring_str(strbuf)); + acl_vstring_sprintf(strbuf, "%*lu\n", (int) sizeof(unsigned long) * 4, + (unsigned long) acl_var_master_pid); + acl_vstream_writen(lock_fp, acl_vstring_str(strbuf), ACL_VSTRING_LEN(strbuf)); + acl_close_on_exec(ACL_VSTREAM_FILE(lock_fp), ACL_CLOSE_ON_EXEC); + acl_vstring_free(strbuf); + + acl_msg_info("daemon started -- version %s, configuration %s", + var_master_version, acl_var_master_conf_dir); + + /* + * Process events. The event handler will execute the read/write/timer + * action routines. Whenever something has happened, see if we received + * any signal in the mean time. Although the master process appears to do + * multiple things at the same time, it really is all a single thread, so + * that there are no concurrency conflicts within the master process. + */ + watchdog = acl_watchdog_create(1000, (ACL_WATCHDOG_FN) 0, (char *) 0); + + for (;;) { +#ifdef HAS_VOLATILE_LOCKS + if (acl_myflock(ACL_VSTREAM_FILE(lock_fp), ACL_INTERNAL_LOCK, + ACL_MYFLOCK_OP_EXCLUSIVE) < 0) + acl_msg_fatal("refresh exclusive lock: %m"); +#endif + + acl_watchdog_start(watchdog); /* same as trigger servers */ + + acl_event_loop(acl_var_master_global_event); + if (acl_var_master_gotsighup) { + acl_msg_info("reload configuration"); + acl_var_master_gotsighup = 0; /* this first */ + acl_master_refresh(); /* then this */ + } + if (acl_var_master_gotsigchld) { + if (acl_msg_verbose) + acl_msg_info("got sigchld"); + acl_var_master_gotsigchld = 0; /* this first */ + acl_master_reap_child(); /* then this */ + } + } +} +#endif /* ACL_UNIX */ + diff --git a/lib_acl/src/master/framework/master.h b/lib_acl/src/master/framework/master.h new file mode 100644 index 000000000..236f4d609 --- /dev/null +++ b/lib_acl/src/master/framework/master.h @@ -0,0 +1,202 @@ + +#ifndef __ACL_MASTER_INCLUDE_H__ +#define __ACL_MASTER_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_define.h" +#ifdef ACL_UNIX + +#include "stdlib/acl_vstream.h" +#include "stdlib/acl_array.h" +#include "event/acl_events.h" +#include "net/acl_netdb.h" + +typedef struct ACL_MASTER_NV { + char *name; + char *value; +} ACL_MASTER_NV; + +typedef struct ACL_MASTER_ADDR { + int type; + char *addr; +} ACL_MASTER_ADDR; + + /* + * Server processes that provide the same service share a common "listen" + * socket to accept connection requests, and share a common pipe to the + * master process to send status reports. Server processes die voluntarily + * when idle for a configurable amount of time, or after servicing a + * configurable number of requests; the master process spawns new processes + * on demand up to a configurable concurrency limit and/or periodically. + */ +typedef struct ACL_MASTER_SERV { + int flags; /* status, features, etc. */ + char *name; /* service endpoint name */ + ACL_ARRAY *children_env; /* the env array of the children */ + int type; /* UNIX-domain, INET, etc. */ + int wakeup_time; /* wakeup interval */ + /* EVENT *eventp; * event pointer */ + int *listen_fds; /* incoming requests */ + ACL_VSTREAM **listen_streams; /* multi-listening stream */ + int listen_fd_count; /* nr of descriptors */ + int defer_accept; /* accept timeout if no data from client */ + ACL_ARRAY *addrs; /* in which ACL_MASTER_ADDR save */ + int max_qlen; /* max listening qlen */ + int max_proc; /* upper bound on # processes */ + int prefork_proc; /* prefork processes */ + char *path; /* command pathname */ + char *notify_addr; /* warning address when not null */ + char *notify_recipients; /* users warned to */ + struct ACL_ARGV *args; /* argument vector */ + int avail_proc; /* idle processes */ + int total_proc; /* number of processes */ + int throttle_delay; /* failure recovery parameter */ + int status_fd[2]; /* child status reports */ + ACL_VSTREAM *status_read_stream; /* status stream */ + struct ACL_BINHASH *children; /* linkage */ + struct ACL_MASTER_SERV *next; /* linkage */ +} ACL_MASTER_SERV; + + /* + * Per-service flag bits. We assume trouble when a child process terminates + * before completing its first request: either the program is defective, + * some configuration is wrong, or the system is out of resources. + */ +#define ACL_MASTER_FLAG_THROTTLE (1<<0) /* we're having trouble */ +#define ACL_MASTER_FLAG_MARK (1<<1) /* garbage collection support */ +#define ACL_MASTER_FLAG_CONDWAKE (1<<2) /* wake up if actually used */ +#define ACL_MASTER_FLAG_RELOADING (1<<3) /* the service is reloading */ + +#define ACL_MASTER_THROTTLED(f) ((f)->flags & ACL_MASTER_FLAG_THROTTLE) + +#define ACL_MASTER_LIMIT_OK(limit, count) ((limit) == 0 || ((count) < (limit))) + + /* + * Service types. + */ +#define ACL_MASTER_SERV_TYPE_NULL 0 /* invalid type */ +#define ACL_MASTER_SERV_TYPE_UNIX 1 /* AF_UNIX domain socket */ +#define ACL_MASTER_SERV_TYPE_INET 2 /* AF_INET domain socket */ +#define ACL_MASTER_SERV_TYPE_FIFO 3 /* fifo (named pipe) */ +#define ACL_MASTER_SERV_TYPE_SOCK 4 /* AF_UNIX/AF_INET socket */ + + /* + * Default process management policy values. This is only the bare minimum. + * Most policy management is delegated to child processes. The process + * manager runs at high privilege level and has to be kept simple. + */ +#define ACL_MASTER_DEF_MIN_IDLE 1 /* preferred # of idle processes */ + + /* + * Structure of child process. + */ +typedef int ACL_MASTER_PID; /* pid is key into binhash table */ + +typedef struct ACL_MASTER_PROC { + ACL_MASTER_PID pid; /* child process id */ + unsigned gen; /* child generation number */ + int avail; /* availability */ + ACL_MASTER_SERV *serv; /* parent linkage */ + int use_count; /* number of service requests */ +} ACL_MASTER_PROC; + + /* + * Other manifest constants. + */ +#define ACL_MASTER_BUF_LEN 2048 /* logical config line length */ + + /* + * acl_master_ent.c + */ +extern void acl_set_master_service_path(const char *); +extern void acl_set_master_ent(void); +extern void acl_end_master_ent(void); +extern void acl_print_master_ent(ACL_MASTER_SERV *); +extern ACL_MASTER_SERV *acl_get_master_ent(void); +extern void acl_free_master_ent(ACL_MASTER_SERV *); + + /* + * acl_master_conf.c + */ +extern void acl_master_config(void); +extern void acl_master_refresh(void); + + /* + * acl_master_service.c + */ +extern ACL_MASTER_SERV *acl_var_master_head; +extern ACL_EVENT *acl_var_master_global_event; +extern void acl_master_start_service(ACL_MASTER_SERV *); +extern void acl_master_stop_service(ACL_MASTER_SERV *); +extern void acl_master_restart_service(ACL_MASTER_SERV *); + + /* + * acl_master_events.c + */ +extern int acl_var_master_gotsighup; +extern int acl_var_master_gotsigchld; +extern void acl_master_sigsetup(void); + + /* + * acl_master_status.c + */ +extern void acl_master_status_init(ACL_MASTER_SERV *); +extern void acl_master_status_cleanup(ACL_MASTER_SERV *); + + /* + * acl_master_wakeup.c + */ +extern void acl_master_wakeup_init(ACL_MASTER_SERV *); +extern void acl_master_wakeup_cleanup(ACL_MASTER_SERV *); + + /* + * acl_master_listen.c + */ +extern void acl_master_listen_init(ACL_MASTER_SERV *); +extern void acl_master_listen_cleanup(ACL_MASTER_SERV *); + +/* + * acl_msg_prefork.c + */ +extern void acl_master_prefork(ACL_MASTER_SERV *); + + /* + * acl_master_avail.c + */ +extern void acl_master_avail_listen(ACL_MASTER_SERV *); +extern void acl_master_avail_cleanup(ACL_MASTER_SERV *); +extern void acl_master_avail_more(ACL_MASTER_SERV *, ACL_MASTER_PROC *); +extern void acl_master_avail_less(ACL_MASTER_SERV *, ACL_MASTER_PROC *); +extern void acl_master_avail_reset(ACL_MASTER_SERV *serv); + + /* + * acl_master_spawn.c + */ +extern struct ACL_BINHASH *acl_var_master_child_table; +extern void acl_master_spawn(ACL_MASTER_SERV *); +extern void acl_master_reap_child(void); +extern void acl_master_delete_children(ACL_MASTER_SERV *); + + /* + * acl_master_flow.c + */ +extern void acl_master_flow_init(void); +extern int acl_var_master_flow_pipe[2]; + + /* + * master_warning.c + */ +extern void master_warning(const char *notify_addr, const char *notify_recipients, + const char *path, int pid, const char *info); + +#endif /* ACL_UNIX */ + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/src/master/framework/master_avail.c b/lib_acl/src/master/framework/master_avail.c new file mode 100644 index 000000000..9ded8dc1e --- /dev/null +++ b/lib_acl/src/master/framework/master_avail.c @@ -0,0 +1,212 @@ +/* System libraries. */ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#endif + +#ifdef ACL_UNIX + +/* Utility library. */ + +#include "stdlib/acl_msg.h" +#include "stdlib/acl_mymalloc.h" +#include "event/acl_events.h" + +/* Application-specific. */ + +#include "../master_proto.h" +#include "master.h" + +/* master_prefork -- prefork service proccess and return the number */ + +static int master_prefork(ACL_MASTER_SERV *serv) +{ + const char *myname = "master_prefork"; + + if (serv->prefork_proc <= 0) + return 0; + else if ((serv->flags & ACL_MASTER_FLAG_RELOADING) != 0) { + int n; + for (n = 0; n < serv->prefork_proc; n++) + acl_master_spawn(serv); + + if (acl_msg_verbose) + acl_msg_info("%s: service %s prefork %d processes ok ...", + myname, serv->name, n); + return n; + } else if (serv->total_proc < serv->prefork_proc) { + int nproc = serv->prefork_proc - serv->total_proc; + int n = serv->max_proc - serv->total_proc; + + /* xxx: sanity check */ + if (n > 0 && n < nproc) + nproc = n; + + for (n = 0 ; n < nproc; n++) + acl_master_spawn(serv); + + if (acl_msg_verbose) + acl_msg_info("%s: service %s prefork %d processes ok ...", + myname, serv->name, n); + return nproc; + } else + return 0; +} + +/* master_avail_event - create child process to handle connection request */ + +static void master_avail_event(int event, void *context) +{ + ACL_MASTER_SERV *serv = (ACL_MASTER_SERV *) context; + int n; + + if (event == 0) /* XXX Can this happen? */ + acl_msg_panic("master_avail_event: null event"); + else if (ACL_MASTER_THROTTLED(serv)) { /* XXX interface botch */ + for (n = 0; n < serv->listen_fd_count; n++) { + acl_event_disable_readwrite(acl_var_master_global_event, + serv->listen_streams[n]); + } + } else if (serv->prefork_proc > 0) + (void) master_prefork(serv); + else + acl_master_spawn(serv); +} + +/* acl_master_avail_listen - make sure that someone monitors the listen socket */ + +void acl_master_avail_listen(ACL_MASTER_SERV *serv) +{ + const char *myname = "acl_master_avail_listen"; + int listen_flag; + + /* + * When no-one else is monitoring the service's listen socket, + * start monitoring the socket for connection requests. All + * this under the restriction that we have sufficient resources + * to service a connection request. + */ + if (acl_msg_verbose) + acl_msg_info("%s: avail %d total %d max %d", myname, + serv->avail_proc, serv->total_proc, serv->max_proc); + + if (ACL_MASTER_THROTTLED(serv)) + listen_flag = 0; + else if (serv->prefork_proc > 0) + listen_flag = master_prefork(serv) > 0 ? 0 : 1; /* prefork services */ + else if (serv->avail_proc > 0) + listen_flag = 0; + else if (ACL_MASTER_LIMIT_OK(serv->max_proc, serv->total_proc)) + listen_flag = 1; + else + listen_flag = 0; + + if (listen_flag) { + int i; + + if (acl_msg_verbose) + acl_msg_info("%s(%d), %s: enable events %s", + __FILE__, __LINE__, myname, serv->name); + for (i = 0; i < serv->listen_fd_count; i++) { + acl_event_enable_read(acl_var_master_global_event, + serv->listen_streams[i], 0, + master_avail_event, (void *) serv); + } + } +} + +/* acl_master_avail_cleanup - cleanup */ + +void acl_master_avail_cleanup(ACL_MASTER_SERV *serv) +{ + int n; + + acl_master_delete_children(serv); /* XXX calls master_avail_listen */ + for (n = 0; n < serv->listen_fd_count; n++) { + /* XXX must be last */ + acl_event_disable_readwrite(acl_var_master_global_event, + serv->listen_streams[n]); + } +} + +/* acl_master_avail_more - one more available child process */ + +void acl_master_avail_more(ACL_MASTER_SERV *serv, ACL_MASTER_PROC *proc) +{ + const char *myname = "acl_master_avail_more"; + int n; + + /* + * This child process has become available for servicing connection + * requests, so we can stop monitoring the service's listen socket. + * The child will do it for us. + */ + if (acl_msg_verbose) + acl_msg_info("%s: pid %d (%s)", myname, proc->pid, + proc->serv->name); + if (proc->avail == ACL_MASTER_STAT_AVAIL) + acl_msg_panic("%s(%d), %s: process already available", + __FILE__, __LINE__, myname); + serv->avail_proc++; + proc->avail = ACL_MASTER_STAT_AVAIL; + if (acl_msg_verbose) + acl_msg_info("%s: disable events %s", myname, serv->name); + for (n = 0; n < serv->listen_fd_count; n++) { + acl_event_disable_readwrite(acl_var_master_global_event, + serv->listen_streams[n]); + } +} + +/* acl_master_avail_less - one less available child process */ + +void acl_master_avail_less(ACL_MASTER_SERV *serv, ACL_MASTER_PROC *proc) +{ + const char *myname = "acl_master_avail_less"; + + /* + * This child is no longer available for servicing connection + * requests. When no child processes are available, start + * monitoring the service's listen socket for new connection requests. + */ + if (acl_msg_verbose) + acl_msg_info("%s: pid %d (%s)", myname, + proc->pid, proc->serv->name); + if (proc->avail != ACL_MASTER_STAT_AVAIL) + acl_msg_panic("%s(%d), %s: process not available", + __FILE__, __LINE__, myname); + serv->avail_proc--; + proc->avail = ACL_MASTER_STAT_TAKEN; + acl_master_avail_listen(serv); +} + +void acl_master_avail_reset(ACL_MASTER_SERV *serv) +{ + ACL_BINHASH_INFO **list; + ACL_BINHASH_INFO **info; + ACL_MASTER_PROC *proc; + + if (acl_var_master_child_table == NULL) + return; + + for (info = list = acl_binhash_list(acl_var_master_child_table); + *info; info++) + { + proc = (ACL_MASTER_PROC *) info[0]->value; + if (proc->serv == serv) { + /* just avoid panic error in acl_master_avail_less */ + if (proc->avail == ACL_MASTER_STAT_TAKEN) + proc->avail = ACL_MASTER_STAT_AVAIL; + if (proc->avail == ACL_MASTER_STAT_AVAIL) + acl_master_avail_less(serv, proc); + } + } + + acl_myfree(list); +} +#endif /* ACL_UNIX */ diff --git a/lib_acl/src/master/framework/master_conf.c b/lib_acl/src/master/framework/master_conf.c new file mode 100644 index 000000000..ce82d0ca3 --- /dev/null +++ b/lib_acl/src/master/framework/master_conf.c @@ -0,0 +1,145 @@ +/* System libraries. */ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#endif + +#ifdef ACL_UNIX + +#include +#include +#include + +/* Utility library. */ + +#include "stdlib/acl_msg.h" +#include "stdlib/acl_argv.h" +#include "stdlib/acl_stringops.h" +#include "stdlib/acl_mymalloc.h" + +/* Application-specific. */ + +#include "../master_params.h" +#include "master.h" + +/* acl_master_refresh - re-read configuration table */ + +void acl_master_refresh(void) +{ + ACL_MASTER_SERV *serv; + ACL_MASTER_SERV **servp; + + /* + * Mark all existing services. + */ + for (serv = acl_var_master_head; serv != 0; serv = serv->next) + serv->flags |= ACL_MASTER_FLAG_MARK; + + /* + * Read the master.cf configuration file. The master_conf() routine + * unmarks services upon update. New services are born with the mark + * bit off. After this, anything with the mark bit on should be + * removed. + */ + acl_master_config(); + + /* + * Delete all services that are still marked - they disappeared from + * the configuration file and are therefore no longer needed. + */ + for (servp = &acl_var_master_head; (serv = *servp) != 0; /* void */ ) { + if ((serv->flags & ACL_MASTER_FLAG_MARK) != 0) { + *servp = serv->next; + acl_master_stop_service(serv); + acl_free_master_ent(serv); + } else { + servp = &serv->next; + } + } +} + +/* acl_master_config - read config file */ + +void acl_master_config(void) +{ + const char *myname = "acl_master_config"; + ACL_MASTER_SERV *entry; + ACL_MASTER_SERV *serv; + char *pathname; + int service_null = 1; + +#define STR_DIFF strcmp +#define STR_SAME !strcmp +#define SWAP(type,a,b) { type temp = a; a = b; b = temp; } + + pathname = acl_concatenate(acl_var_master_conf_dir, "/", "main.cf", (char *) 0); + acl_master_params_load(pathname); + acl_myfree(pathname); + + acl_master_vars_init(acl_var_master_buf_size, acl_var_master_rw_timeout); + acl_set_master_service_path(acl_var_master_service_dir); + + /* + * A service is identified by its endpoint name AND by its transport + * type, not just by its name alone. The name is unique within its + * transport type. XXX Service privacy is encoded in the service name. + */ + acl_set_master_ent(); + while ((entry = acl_get_master_ent()) != 0) { + if (acl_msg_verbose) + acl_print_master_ent(entry); + for (serv = acl_var_master_head; serv != 0; serv = serv->next) + if (STR_SAME(serv->name, entry->name) && serv->type == entry->type) + break; + + service_null = 0; + /* + * Add a new service entry. We do not really care in what + * order the service entries are kept in memory. + */ + if (serv == 0) { + entry->next = acl_var_master_head; + acl_var_master_head = entry; + acl_master_start_service(entry); + continue; + } + + /* reset all proc of the serv before restart the service. --zsx */ + acl_master_avail_reset(serv); + + /* + * Update an existing service entry. Make the current + * generation of child processes commit suicide whenever + * it is convenient. The next generation of child processes + * will run with the new configuration settings. + */ + serv->flags &= ~ACL_MASTER_FLAG_MARK; + if (entry->flags & ACL_MASTER_FLAG_CONDWAKE) + serv->flags |= ACL_MASTER_FLAG_CONDWAKE; + else + serv->flags &= ~ACL_MASTER_FLAG_CONDWAKE; + serv->wakeup_time = entry->wakeup_time; + serv->max_proc = entry->max_proc; + serv->prefork_proc = entry->prefork_proc; + serv->throttle_delay = entry->throttle_delay; + SWAP(char *, serv->path, entry->path); + SWAP(char *, serv->notify_addr, entry->notify_addr); + SWAP(char *, serv->notify_recipients, entry->notify_recipients); + SWAP(ACL_ARGV *, serv->args, entry->args); + acl_master_restart_service(serv); + acl_free_master_ent(entry); + } + acl_end_master_ent(); + + if (service_null) + acl_msg_fatal("%s(%d)->%s: no service file in dir %s%s can be used", + __FILE__, __LINE__, myname, acl_var_master_service_dir, + acl_var_master_scan_subdir ? " and its subdir" : ""); +} +#endif /* ACL_UNIX */ diff --git a/lib_acl/src/master/framework/master_ent.c b/lib_acl/src/master/framework/master_ent.c new file mode 100644 index 000000000..458f8002f --- /dev/null +++ b/lib_acl/src/master/framework/master_ent.c @@ -0,0 +1,691 @@ +/* System lib */ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" /* for ISDIGIT */ + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#endif + +#ifdef ACL_UNIX + +#include +#include +#include +#include +#include +#include + +/* Util lib */ +#include "stdlib/acl_msg.h" +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_scan_dir.h" +#include "stdlib/acl_xinetd_cfg.h" +#include "stdlib/acl_vstring.h" +#include "stdlib/acl_argv.h" +#include "stdlib/acl_stringops.h" +#include "stdlib/acl_mystring.h" +#include "stdlib/acl_argv.h" +#include "net/acl_sane_inet.h" +#include "net/acl_host_port.h" + +/* Application specific */ +#include "../master_proto.h" +#include "../master_params.h" +#include "master_pathname.h" +#include "master.h" + +static char *__master_path = NULL; /* dir name of config files */ +static ACL_SCAN_DIR *__scan = NULL; + +const char *__config_file_ptr = NULL; + +static const char __master_blanks[] = " \t\r\n"; /* field delimiters */ + +void acl_set_master_service_path(const char *path) +{ + if (__master_path != 0) + acl_myfree(__master_path); + __master_path = acl_mystrdup(path); +} + +void acl_set_master_ent() +{ + const char *myname = "acl_set_master_ent"; + + if (__master_path == NULL) + acl_msg_fatal("%s(%d), %s: master_path is null", + __FILE__, __LINE__, myname); + + if (__scan) + acl_end_master_ent(); + + __scan = acl_scan_dir_open(__master_path, acl_var_master_scan_subdir); + if (__scan == NULL) + acl_msg_fatal("%s(%d), %s: open dir(%s) err, serr=%s", + __FILE__, __LINE__, myname, + __master_path, strerror(errno)); +} + +void acl_end_master_ent() +{ + if (__scan) + acl_scan_dir_close(__scan); + __scan = NULL; +} + +/* fatal_with_context - print fatal error with file/line context */ + +static void fatal_with_context(const char *format,...) +{ + const char *myname = "fatal_with_context"; + ACL_VSTRING *vp = acl_vstring_alloc(100); + va_list ap; + + if (__master_path == 0) + acl_msg_panic("%s: no configuration file specified", myname); + + va_start(ap, format); + acl_vstring_vsprintf(vp, format, ap); + va_end(ap); + acl_msg_fatal("%s: file %s: %s", __master_path, + __config_file_ptr ? __config_file_ptr : "why?", + acl_vstring_str(vp)); +} + +/* fatal_invalid_field - report invalid field value */ + +static void fatal_invalid_field(const char *name, const char *value) +{ + fatal_with_context("field \"%s\": bad value: \"%s\"", name, value); +} + +/* get_str_ent - extract string field */ + +static const char *get_str_ent(ACL_XINETD_CFG_PARSER *xcp, + const char *name, const char *def_val) +{ + const char *value; + + value = acl_xinetd_cfg_get(xcp, name); + if (value == 0) { + if (def_val) + return (def_val); + fatal_with_context("missing \"%s\" field", name); + } + + if (strcmp(value, "-") == 0) { + if (def_val != 0) + return (def_val); + fatal_with_context("field \"%s\" has no default value", name); + /* no reach here */ + return (NULL); + } else + return (value); +} + +/* get_bool_ent - extract boolean field */ + +static int get_bool_ent(ACL_XINETD_CFG_PARSER *xcp, + const char *name, const char *def_val) +{ + const char *value; + + value = acl_xinetd_cfg_get(xcp, name); + if (value == 0) { + if (def_val == NULL) + fatal_with_context("missing \"%s\" field", name); + if (strcasecmp("y", def_val) == 0) + return (1); + else if (strcasecmp("n", def_val) == 0) + return (0); + else + fatal_invalid_field(name, value); + } + + if (strcasecmp("y", value) == 0) { + return (1); + } else if (strcasecmp("n", value) == 0) { + return (0); + } else { + fatal_invalid_field(name, value); + } + /* NOTREACHED */ + return (0); +} + +/* get_int_ent - extract integer field */ + +static int get_int_ent(ACL_XINETD_CFG_PARSER *xcp, const char *name, + const char *def_val, int min_val) +{ + const char *value; + int n = 0; + + value = acl_xinetd_cfg_get(xcp, name); + if (value == 0) { + if (def_val == NULL) + fatal_with_context("missing \"%s\" field", name); + if (!ACL_ISDIGIT(*def_val) || (n = atoi(def_val)) < min_val) + fatal_invalid_field(name, def_val); + return (n); + } + + if (!ACL_ISDIGIT(*value) || (n = atoi(value)) < min_val) + fatal_invalid_field(name, value); + return (n); +} + +static ACL_XINETD_CFG_PARSER *lookup_service_conf(ACL_VSTRING *path_buf) +{ + const char *myname = "lookup_service_conf"; + const char *config_file; + const char *value; + ACL_XINETD_CFG_PARSER *xcp; + + while (1) { + config_file = acl_scan_dir_next_file(__scan); + if (config_file == NULL) /* over now */ + return (NULL); + +#if 0 + acl_vstring_sprintf(path_buf, "%s/%s", __master_path, config_file); +#else + acl_vstring_sprintf(path_buf, "%s/%s", + acl_scan_dir_path(__scan), config_file); +#endif + + acl_msg_info("%s(%d)->%s: load service file = %s", + __FILE__, __LINE__, myname, acl_vstring_str(path_buf)); + + xcp = acl_xinetd_cfg_load(acl_vstring_str(path_buf)); + if (xcp == NULL) { + acl_msg_warn("%s(%d)->%s: acl_xinetd_cfg_load(%s), serr=%s", + __FILE__, __LINE__, myname, + acl_vstring_str(path_buf), strerror(errno)); + continue; + } + + value = get_str_ent(xcp, ACL_VAR_MASTER_SERV_DISABLE, "yes"); + if (value == NULL || strcasecmp(value, "yes") == 0) { + acl_xinetd_cfg_free(xcp); + xcp = NULL; + continue; + } + + break; + } + + __config_file_ptr = config_file; + + return (xcp); +} + +static void init_listeners(ACL_MASTER_SERV *serv) +{ + const char *myname = "init_listeners"; + int n; + + /* + * Listen socket(s). XXX We pre-allocate storage because the number of + * sockets is frozen anyway once we build the command-line vector below. + */ + if (serv->listen_fd_count == 0) + acl_msg_fatal("%s(%d)->%s: file %s: no valid IP address found", + __FILE__, __LINE__, myname, __config_file_ptr); + + serv->listen_fds = (int *) acl_mycalloc( + 1, sizeof(int) * serv->listen_fd_count); + serv->listen_streams = (ACL_VSTREAM **) acl_mycalloc( + 1, sizeof(ACL_VSTREAM *) * serv->listen_fd_count); + for (n = 0; n < serv->listen_fd_count; n++) { + serv->listen_fds[n] = -1; + serv->listen_streams[n] = NULL; + } +} + +/* FIFO service */ + +static void service_fifo(ACL_XINETD_CFG_PARSER *xcp, ACL_MASTER_SERV *serv) +{ + const char *name = get_str_ent(xcp, ACL_VAR_MASTER_SERV_SERVICE, NULL); + char private_val = get_bool_ent(xcp, ACL_VAR_MASTER_SERV_PRIVATE, "y"); + + serv->addrs = NULL; + serv->type = ACL_MASTER_SERV_TYPE_FIFO; + serv->listen_fd_count = 1; + serv->name = acl_master_pathname(acl_var_master_queue_dir, + private_val ? ACL_MASTER_CLASS_PRIVATE : + ACL_MASTER_CLASS_PUBLIC, name); +} + +/* inet service */ + +static void service_inet(ACL_XINETD_CFG_PARSER *xcp, ACL_MASTER_SERV *serv) +{ + const char *name = get_str_ent(xcp, ACL_VAR_MASTER_SERV_SERVICE, NULL); + + serv->addrs = NULL; + serv->type = ACL_MASTER_SERV_TYPE_INET; + serv->listen_fd_count = 1; + serv->name = acl_mystrdup(name); +} + +/* unix service */ + +static void service_unix(ACL_XINETD_CFG_PARSER *xcp, ACL_MASTER_SERV *serv) +{ + const char *name = get_str_ent(xcp, ACL_VAR_MASTER_SERV_SERVICE, NULL); + char private_val = get_bool_ent(xcp, ACL_VAR_MASTER_SERV_PRIVATE, "y"); + + serv->addrs = NULL; + serv->type = ACL_MASTER_SERV_TYPE_UNIX; + serv->listen_fd_count = 1; + serv->name = acl_master_pathname(acl_var_master_queue_dir, + private_val ? ACL_MASTER_CLASS_PRIVATE : + ACL_MASTER_CLASS_PUBLIC, name); +} + +/* Inet/Unix socket service */ + +static void service_sock(ACL_XINETD_CFG_PARSER *xcp, ACL_MASTER_SERV *serv) +{ + /* + * Service name. Syntax is transport-specific. + */ + const char *name = get_str_ent(xcp, ACL_VAR_MASTER_SERV_SERVICE, NULL); + char private_val = get_bool_ent(xcp, ACL_VAR_MASTER_SERV_PRIVATE, "y"); + ACL_ARGV *tokens = acl_argv_split(name, ",; \t"); + ACL_ITER iter; + + serv->type = ACL_MASTER_SERV_TYPE_SOCK; + serv->addrs = acl_array_create(1); + serv->name = acl_mystrdup(name); + + acl_foreach(iter, tokens) { + const char* path = (const char*) iter.data; + ACL_MASTER_ADDR *addr = (ACL_MASTER_ADDR*) + acl_mycalloc(1, sizeof(ACL_MASTER_ADDR)); + + if (acl_ipv4_addr_valid(path) || acl_alldig(path) + || (*path == ':' && acl_alldig(path + 1))) + { + addr->type = ACL_MASTER_SERV_TYPE_INET; + addr->addr = acl_mystrdup(path); + } else { + addr->type = ACL_MASTER_SERV_TYPE_UNIX; + addr->addr = acl_master_pathname( + acl_var_master_queue_dir, private_val + ? ACL_MASTER_CLASS_PRIVATE : + ACL_MASTER_CLASS_PUBLIC, path); + } + acl_array_append(serv->addrs, addr); + serv->listen_fd_count++; + } + + acl_argv_free(tokens); +} + +/* Transport type: inet (wild-card listen or virtual) or unix. */ + +static void service_transport(ACL_XINETD_CFG_PARSER *xcp, ACL_MASTER_SERV *serv) +{ + const char *transport; + +#undef STR_SAME +#define STR_SAME !strcasecmp + + transport = get_str_ent(xcp, ACL_VAR_MASTER_SERV_TYPE, (const char *) 0); + if (transport == NULL || *transport == 0) + acl_msg_fatal("master_service no found"); + + serv->defer_accept = get_int_ent(xcp, ACL_VAR_MASTER_SERV_DEFER_ACCEPT, + ACL_DEF_MASTER_SERV_DEFER_ACCEPT, 0); + + if (STR_SAME(transport, ACL_MASTER_XPORT_NAME_FIFO)) + service_fifo(xcp, serv); + else if (STR_SAME(transport, ACL_MASTER_XPORT_NAME_UNIX)) + service_unix(xcp, serv); + else if (STR_SAME(transport, ACL_MASTER_XPORT_NAME_INET)) + service_inet(xcp, serv); + else if (STR_SAME(transport, ACL_MASTER_XPORT_NAME_SOCK)) + service_sock(xcp, serv); + else + acl_msg_fatal("unknown master_service: %s", transport); + + init_listeners(serv); +} + +static void service_wakeup_time(ACL_XINETD_CFG_PARSER *xcp, + ACL_MASTER_SERV *serv) +{ + const char *ptr_const; + char *ptr, *ptr1; + + /* + * Wakeup timer. XXX should we require that var_master_proc_limit == 1? + * Right now, the only services that have a wakeup timer also happen + * to be the services that have at most one running instance: + * local pickup and local delivery. + */ + ptr_const = get_str_ent(xcp, ACL_VAR_MASTER_SERV_WAKEUP, "0"); + + /* + * Find out if the wakeup time is conditional, i.e., wakeup triggers + * should not be sent until the service has actually been used. + */ + ptr = NULL; + if (ptr_const) { + ptr = acl_mystrdup(ptr_const); + ptr1 = strchr(ptr, '?'); + if (ptr1) + *ptr1 = 0; + serv->wakeup_time = atoi(ptr); + } else { + ptr1 = NULL; + serv->wakeup_time = 0; + } + + if (serv->wakeup_time > 0 && ptr1 != NULL) + serv->flags |= ACL_MASTER_FLAG_CONDWAKE; + if (ptr) + acl_myfree(ptr); +} + +static void service_proc(ACL_XINETD_CFG_PARSER *xcp, ACL_MASTER_SERV *serv) +{ + + /* + * Concurrency limit. Zero means no limit. + */ + + serv->max_qlen = get_int_ent(xcp, ACL_VAR_MASTER_SERV_MAX_QLEN, + ACL_DEF_MASTER_SERV_MAX_QLEN, 0); + serv->max_proc = get_int_ent(xcp, ACL_VAR_MASTER_SERV_MAX_PROC, + ACL_DEF_MASTER_SERV_MAX_PROC, 0); + serv->prefork_proc = get_int_ent(xcp, ACL_VAR_MASTER_SERV_PREFORK_PROC, + ACL_DEF_MASTER_SERV_PREFORK_PROC, 0); + if (serv->max_proc > 0 && serv->prefork_proc > serv->max_proc) + serv->prefork_proc = serv->max_proc; + + /* + * Idle and total process count. + */ + serv->avail_proc = 0; + serv->total_proc = 0; +} + +static void service_args(ACL_XINETD_CFG_PARSER *xcp, ACL_MASTER_SERV *serv, + ACL_VSTRING *path) +{ + const char *myname = "service_args"; + const char *command, *name, *transport, *args, *ptr_const; + char *args_buf, *ptr, *cp; + char unprivileged, chroot_var; + ACL_VSTRING *junk = acl_vstring_alloc(100); + + /* + * Privilege level. Default is to restrict process privileges + * to those of the mail owner. + */ + unprivileged = get_bool_ent(xcp, ACL_VAR_MASTER_SERV_UNPRIV, "y"); + + /* + * Chroot. Default is to restrict file system access to the mail + * queue. + * XXX Chroot cannot imply unprivileged service (for example, + * the pickup service runs chrooted but needs privileges to open + * files as the user). + */ + chroot_var = get_bool_ent(xcp, ACL_VAR_MASTER_SERV_CHROOT, "y"); + + /* + * Path to command, + */ + command = get_str_ent(xcp, ACL_VAR_MASTER_SERV_COMMAND, (char *) 0); + serv->path = acl_concatenate(acl_var_master_daemon_dir, "/", + command, (char *) 0); + + /* + * Notify Address + */ + ptr_const = get_str_ent(xcp, ACL_VAR_MASTER_NOTIFY_ADDR, "no"); + if (ptr_const == NULL || strcasecmp(ptr_const, "no") == 0) + serv->notify_addr = NULL; + else + serv->notify_addr = acl_mystrdup(ptr_const); + + ptr_const = get_str_ent(xcp, ACL_VAR_MASTER_NOTIFY_RECIPIENTS, "no"); + if (ptr_const == NULL || strcasecmp(ptr_const, "no") == 0) + serv->notify_recipients = NULL; + else + serv->notify_recipients = acl_mystrdup(ptr_const); + + /* + * Command-line vector. Add "-n service_name" when the process name + * safe_basename differs from the service name. Always add the transport. + */ + serv->args = acl_argv_alloc(0); + acl_argv_add(serv->args, command, (char *) 0); + + name = get_str_ent(xcp, ACL_VAR_MASTER_SERV_SERVICE, (const char *) 0); + + /* add "-f configure_file_path" flag */ + acl_argv_add(serv->args, "-f", acl_vstring_str(path), (char *) 0); + + if (serv->max_proc == 1) + acl_argv_add(serv->args, "-l", (char *) 0); + if (serv->max_proc == 0) + acl_argv_add(serv->args, "-z", (char *) 0); + if (strcmp(acl_safe_basename(command), name) != 0) { + char *tmp = acl_concatenate("\"", name, "\"", 0); + acl_argv_add(serv->args, "-n", tmp, (char *) 0); + acl_myfree(tmp); + } + + transport = get_str_ent(xcp, ACL_VAR_MASTER_SERV_TYPE, (const char *) 0); + acl_argv_add(serv->args, "-t", transport, (char *) 0); + if (acl_msg_verbose) + acl_argv_add(serv->args, "-v", (char *) 0); + if (unprivileged) + acl_argv_add(serv->args, "-u", (char *) 0); + if (chroot_var) + acl_argv_add(serv->args, "-c", (char *) 0); + if (serv->listen_fd_count > 1) + acl_argv_add(serv->args, "-s", acl_vstring_str( + acl_vstring_sprintf(junk, "%d", serv->listen_fd_count)), + (char *) 0); + + /* use myname to avoid fatal error when nothing get */ + args = get_str_ent(xcp, ACL_VAR_MASTER_SERV_ARGS, myname); + if (args != myname) { + args_buf = acl_mystrdup(args); + ptr = args_buf; + while ((cp = acl_mystrtok(&ptr, __master_blanks)) != 0) + acl_argv_add(serv->args, cp, (char *) 0); + acl_myfree(args_buf); + } + + acl_argv_terminate(serv->args); + acl_vstring_free(junk); +} + +static void service_env(ACL_XINETD_CFG_PARSER *xcp, ACL_MASTER_SERV *serv) +{ + ACL_MASTER_NV *nv; + const char *value; + + serv->children_env = acl_array_create(10); + + /* 如果配置文件中没有服务的日志项, 则继承使用 master 主进程的日志文件 */ + value = get_str_ent(xcp, ACL_VAR_MASTER_SERV_LOG, acl_var_master_log_file); + + nv = (ACL_MASTER_NV *) acl_mycalloc(1, sizeof(ACL_MASTER_NV)); + nv->name = acl_mystrdup("MASTER_LOG"); + nv->value = acl_mystrdup(acl_var_master_log_file); + (void) acl_array_append(serv->children_env, nv); + + nv = (ACL_MASTER_NV *) acl_mycalloc(1, sizeof(ACL_MASTER_NV)); + nv->name = acl_mystrdup("SERVICE_LOG"); + nv->value = acl_mystrdup(value); + (void) acl_array_append(serv->children_env, nv); + + /* 为了保证兼容性 */ + nv = (ACL_MASTER_NV *) acl_mycalloc(1, sizeof(ACL_MASTER_NV)); + nv->name = acl_mystrdup("LOG"); + nv->value = acl_mystrdup(value); + (void) acl_array_append(serv->children_env, nv); + + value = get_str_ent(xcp, ACL_VAR_MASTER_SERV_ENV, "-"); + if (value && strcmp(value, "-") != 0) { + nv = (ACL_MASTER_NV *) acl_mycalloc(1, sizeof(ACL_MASTER_NV)); + nv->name = acl_mystrdup("SERVICE_ENV"); + nv->value = acl_mystrdup(value); + (void) acl_array_append(serv->children_env, nv); + } +} + +ACL_MASTER_SERV *acl_get_master_ent() +{ + ACL_XINETD_CFG_PARSER *xcp = NULL; + ACL_VSTRING *path_buf = acl_vstring_alloc(256); + ACL_MASTER_SERV *serv; + static char *saved_interfaces = 0; + +#undef RETURN +#define RETURN(x) { \ + acl_vstring_free(path_buf); \ + if (xcp != NULL) \ + acl_xinetd_cfg_free(xcp); \ + return (x); \ +} + + /* + * XXX We cannot change the inet_interfaces setting for a running master + * process. Listening sockets are inherited by child processes so that + * closing and reopening those sockets in the master does not work. + * + * Another problem is that library routines still cache results that are + * based on the old inet_interfaces setting. It is too much trouble to + * recompute everything. + * + * In order to keep our data structures consistent we ignore changes in + * inet_interfaces settings, and issue a warning instead. + */ + if (saved_interfaces == 0) + saved_interfaces = acl_mystrdup(acl_var_master_inet_interfaces); + + xcp = lookup_service_conf(path_buf); + + if (xcp == NULL) + RETURN (NULL); + + /* Initialize service structure members in order. */ + serv = (ACL_MASTER_SERV *) acl_mycalloc(1, sizeof(ACL_MASTER_SERV)); + serv->next = 0; + + /* + * Flags member. + */ + serv->flags = 0; + + service_transport(xcp, serv); + service_wakeup_time(xcp, serv); + service_proc(xcp, serv); + service_args(xcp, serv, path_buf); + service_env(xcp, serv); + + /* + * Backoff time in case a service is broken. + */ + serv->throttle_delay = acl_var_master_throttle_time; + + /* + * Shared channel for child status updates. + */ + serv->status_fd[0] = serv->status_fd[1] = -1; + + /* + * Child process structures. + */ + serv->children = 0; + + RETURN (serv); +} + +/* acl_print_master_ent - show service entry contents */ + +void acl_print_master_ent(ACL_MASTER_SERV *serv) +{ + char **cpp; + + acl_msg_info("====start service entry"); + acl_msg_info("flags: %d", serv->flags); + acl_msg_info("name: %s", serv->name); + acl_msg_info("type: %s", + serv->type == ACL_MASTER_SERV_TYPE_UNIX ? ACL_MASTER_XPORT_NAME_UNIX : + serv->type == ACL_MASTER_SERV_TYPE_FIFO ? ACL_MASTER_XPORT_NAME_FIFO : + serv->type == ACL_MASTER_SERV_TYPE_INET ? ACL_MASTER_XPORT_NAME_INET : + serv->type == ACL_MASTER_SERV_TYPE_SOCK ? ACL_MASTER_XPORT_NAME_SOCK : + "unknown transport type"); + acl_msg_info("listen_fd_count: %d", serv->listen_fd_count); + acl_msg_info("wakeup: %d", serv->wakeup_time); + acl_msg_info("max_proc: %d", serv->max_proc); + acl_msg_info("prefork_proc: %d", serv->prefork_proc); + acl_msg_info("path: %s", serv->path); + for (cpp = serv->args->argv; *cpp; cpp++) + acl_msg_info("arg[%d]: %s", (int) (cpp - serv->args->argv), *cpp); + acl_msg_info("prefork_proc: %d", serv->prefork_proc); + acl_msg_info("avail_proc: %d", serv->avail_proc); + acl_msg_info("total_proc: %d", serv->total_proc); + acl_msg_info("throttle_delay: %d", serv->throttle_delay); + acl_msg_info("status_fd %d %d", serv->status_fd[0], serv->status_fd[1]); + acl_msg_info("children: 0x%lx", (long) serv->children); + acl_msg_info("next: 0x%lx", (long) serv->next); + acl_msg_info("====end service entry"); +} + +static void __free_nv_fn(void *arg) +{ + ACL_MASTER_NV *nv; + + if (arg) { + nv = (ACL_MASTER_NV *) arg; + acl_myfree(nv->name); + acl_myfree(nv->value); + acl_myfree(nv); + } +} + +void acl_free_master_ent(ACL_MASTER_SERV *serv) +{ + /* + * Undo what get_master_ent() created. + */ + + if (serv->addrs != NULL) { + ACL_ITER iter; + acl_foreach(iter, serv->addrs) { + ACL_MASTER_ADDR *addr = (ACL_MASTER_ADDR*) iter.data; + acl_myfree(addr->addr); + acl_myfree(addr); + } + acl_array_free(serv->addrs, NULL); + } + + acl_myfree(serv->name); + acl_myfree(serv->path); + if (serv->notify_addr) + acl_myfree(serv->notify_addr); + if (serv->notify_recipients) + acl_myfree(serv->notify_recipients); + acl_argv_free(serv->args); + acl_array_destroy(serv->children_env, __free_nv_fn); + acl_myfree(serv->listen_fds); + acl_myfree(serv->listen_streams); + acl_myfree(serv); +} +#endif /* ACL_UNIX */ diff --git a/lib_acl/src/master/framework/master_listen.c b/lib_acl/src/master/framework/master_listen.c new file mode 100644 index 000000000..2b7956237 --- /dev/null +++ b/lib_acl/src/master/framework/master_listen.c @@ -0,0 +1,254 @@ +/* System library. */ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#endif + +#ifdef ACL_UNIX + +#include +#include +#include +#include +#include +#include + +/* Utility library. */ + +#include "stdlib/acl_msg.h" +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_stringops.h" +#include "stdlib/unix/acl_set_eugid.h" +#include "stdlib/unix/acl_set_ugid.h" +#include "stdlib/acl_iostuff.h" +#include "stdlib/acl_vstream.h" + +#include "net/acl_listen.h" +#include "net/acl_tcp_ctl.h" + +/* Application-specific. */ + +#include "../master_params.h" +#include "master.h" + +/* listen on inet/unix socket */ + +static void master_listen_sock(ACL_MASTER_SERV *serv) +{ + const char *myname = "master_listen_sock"; + int i, service_type; + int qlen; + + qlen = serv->max_qlen > acl_var_master_proc_limit + ? serv->max_qlen : acl_var_master_proc_limit; + if (qlen < 128) { + acl_msg_warn("%s(%d): qlen(%d) too small, use 128 now", + myname, __LINE__, qlen); + qlen = 128; + } + + if (serv->listen_fd_count != acl_array_size(serv->addrs)) + acl_msg_panic("listen_fd_count(%d) != addrs's size(%d)", + serv->listen_fd_count, acl_array_size(serv->addrs)); + + for (i = 0; i < serv->listen_fd_count; i++) { + ACL_MASTER_ADDR *addr = (ACL_MASTER_ADDR*) + acl_array_index(serv->addrs, i); + switch (addr->type) { + case ACL_MASTER_SERV_TYPE_INET: + serv->listen_fds[i] = acl_inet_listen( + addr->addr, qlen, ACL_NON_BLOCKING); + acl_tcp_defer_accept(serv->listen_fds[i], + serv->defer_accept); + service_type = ACL_VSTREAM_TYPE_LISTEN_INET; + break; + case ACL_MASTER_SERV_TYPE_UNIX: + acl_set_eugid(acl_var_master_owner_uid, + acl_var_master_owner_gid); + serv->listen_fds[i] = acl_unix_listen( + addr->addr, qlen, ACL_NON_BLOCKING); + acl_set_ugid(getuid(), getgid()); + + service_type = ACL_VSTREAM_TYPE_LISTEN_UNIX; + break; + default: + service_type = 0; /* avoid compile warning */ + acl_msg_panic("invalid type: %d, addr: %s", + addr->type, addr->addr); + break; + } + + if (serv->listen_fds[i] == ACL_SOCKET_INVALID) + acl_msg_fatal("%s(%d), %s: listen on %s error %s", + __FILE__, __LINE__, myname, + addr->addr, strerror(errno)); + + acl_close_on_exec(serv->listen_fds[i], ACL_CLOSE_ON_EXEC); + + serv->listen_streams[i] = acl_vstream_fdopen(serv->listen_fds[i], + O_RDONLY, acl_var_master_buf_size, + acl_var_master_rw_timeout, service_type); + + acl_msg_info("%s(%d), %s: listen on: %s, qlen: %d", + __FILE__, __LINE__, myname, addr->addr, qlen); + } +} + +static void master_listen_inet(ACL_MASTER_SERV *serv) +{ + const char *myname = "master_listen_inet"; + int qlen; + + qlen = serv->max_qlen > acl_var_master_proc_limit + ? serv->max_qlen : acl_var_master_proc_limit; + if (qlen < 128) { + acl_msg_warn("%s(%d): qlen(%d) too small, use 128 now", + myname, __LINE__, qlen); + qlen = 128; + } + + serv->listen_fds[0] = acl_inet_listen(serv->name, qlen, ACL_NON_BLOCKING); + if (serv->listen_fds[0] == ACL_SOCKET_INVALID) + acl_msg_fatal("%s(%d)->%s: listen on addr(%s) error(%s)", + __FILE__, __LINE__, myname, serv->name, strerror(errno)); + + if (serv->defer_accept > 0) + acl_tcp_defer_accept(serv->listen_fds[0], serv->defer_accept); + + serv->listen_streams[0] = acl_vstream_fdopen(serv->listen_fds[0], + O_RDONLY, acl_var_master_buf_size, + acl_var_master_rw_timeout, ACL_VSTREAM_TYPE_LISTEN_INET); + acl_close_on_exec(serv->listen_fds[0], ACL_CLOSE_ON_EXEC); + acl_msg_info("%s(%d), %s: listen on inet: %s, qlen: %d", + __FILE__, __LINE__, myname, serv->name, qlen); +} + +static void master_listen_unix(ACL_MASTER_SERV *serv) +{ + const char *myname = "master_listen_unix"; + int qlen; + + qlen = serv->max_qlen > acl_var_master_proc_limit + ? serv->max_qlen : acl_var_master_proc_limit; + if (qlen < 128) { + acl_msg_warn("%s(%d): qlen(%d) too small, use 128 now", + myname, __LINE__, qlen); + qlen = 128; + } + + acl_set_eugid(acl_var_master_owner_uid, acl_var_master_owner_gid); + serv->listen_fds[0] = acl_unix_listen(serv->name, qlen, ACL_NON_BLOCKING); + if (serv->listen_fds[0] == ACL_SOCKET_INVALID) + acl_msg_fatal("%s(%d)->%s: listen on addr(%s) error(%s)", + __FILE__, __LINE__, myname, serv->name, strerror(errno)); + + serv->listen_streams[0] = acl_vstream_fdopen(serv->listen_fds[0], + O_RDONLY, acl_var_master_buf_size, + acl_var_master_rw_timeout, ACL_VSTREAM_TYPE_LISTEN_UNIX); + acl_close_on_exec(serv->listen_fds[0], ACL_CLOSE_ON_EXEC); + acl_set_ugid(getuid(), getgid()); + acl_msg_info("%s(%d), %s: listen on domain socket: %s, qlen: %d", + __FILE__, __LINE__, myname, serv->name, qlen); +} + +static void master_listen_fifo(ACL_MASTER_SERV *serv) +{ + const char *myname = "master_listen_fifo"; + + acl_set_eugid(acl_var_master_owner_uid, acl_var_master_owner_gid); + serv->listen_fds[0] = acl_fifo_listen(serv->name, + 0622, ACL_NON_BLOCKING); + if (serv->listen_fds[0] == ACL_SOCKET_INVALID) + acl_msg_fatal("%s(%d), %s: listen on name(%s) error(%s)", + __FILE__, __LINE__, myname, serv->name, strerror(errno)); + + serv->listen_streams[0] = acl_vstream_fdopen(serv->listen_fds[0], + O_RDONLY, acl_var_master_buf_size, + acl_var_master_rw_timeout, ACL_VSTREAM_TYPE_LISTEN); + acl_close_on_exec(serv->listen_fds[0], ACL_CLOSE_ON_EXEC); + acl_set_ugid(getuid(), getgid()); + acl_msg_info("%s(%d), %s: listen on fifo socket: %s", + __FILE__, __LINE__, myname, serv->name); +} + +/* acl_master_listen_init - enable connection requests */ + +void acl_master_listen_init(ACL_MASTER_SERV *serv) +{ + const char *myname = "acl_master_listen_init"; + + /* + * Find out what transport we should use, then create one or + * more listener sockets. Make the listener sockets non-blocking, + * so that child processes don't block in accept() when multiple + * processes are selecting on the same socket and only one of + * them gets the connection. + */ + + switch (serv->type) { + + /* + * SOCK: INET/UNIX domain or stream listener endpoints + */ + case ACL_MASTER_SERV_TYPE_SOCK: + master_listen_sock(serv); + break; + + /* + * INET-domain listener endpoints can be wildcarded (the default) or + * bound to specific interface addresses. + */ + case ACL_MASTER_SERV_TYPE_INET: + master_listen_inet(serv); + break; + + /* + * UNIX-domain or stream listener endpoints always come as singlets. + */ + case ACL_MASTER_SERV_TYPE_UNIX: + master_listen_unix(serv); + break; + + /* + * FIFO listener endpoints always come as singlets. + */ + case ACL_MASTER_SERV_TYPE_FIFO: + master_listen_fifo(serv); + break; + + default: + acl_msg_panic("%s: unknown service type: %d", + myname, serv->type); + } +} + +/* acl_master_listen_cleanup - disable connection requests */ + +void acl_master_listen_cleanup(ACL_MASTER_SERV *serv) +{ + const char *myname = "acl_master_listen_cleanup"; + int i; + + /* + * XXX The listen socket is shared with child processes. Closing the + * socket in the master process does not really disable listeners in + * child processes. There seems to be no documented way to turn off a + * listener. The 4.4BSD shutdown(2) man page promises an ENOTCONN error + * when shutdown(2) is applied to a socket that is not connected. + */ + for (i = 0; i < serv->listen_fd_count; i++) { + if (close(serv->listen_fds[i]) < 0) + acl_msg_warn("%s: close listener socket %d: %s", + myname, serv->listen_fds[i], strerror(errno)); + serv->listen_fds[i] = -1; + acl_vstream_free(serv->listen_streams[i]); + serv->listen_streams[i] = NULL; + } +} +#endif /* ACL_UNIX */ diff --git a/lib_acl/src/master/framework/master_pathname.c b/lib_acl/src/master/framework/master_pathname.c new file mode 100644 index 000000000..ed3a7d22e --- /dev/null +++ b/lib_acl/src/master/framework/master_pathname.c @@ -0,0 +1,31 @@ +/* System library. */ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#endif + +#ifdef ACL_UNIX + +/* Utility library. */ + +#include "stdlib/acl_stringops.h" + +/* Global library. */ + +#include "master_pathname.h" + +/* acl_master_pathname - map service class and service name to pathname */ + +char *acl_master_pathname(const char *queue_path, const char *service_class, + const char *service_name) +{ + return (acl_concatenate(queue_path, "/", service_class, "/", + service_name, (char *) 0)); +} +#endif /* ACL_UNIX */ diff --git a/lib_acl/src/master/framework/master_pathname.h b/lib_acl/src/master/framework/master_pathname.h new file mode 100644 index 000000000..db79cc431 --- /dev/null +++ b/lib_acl/src/master/framework/master_pathname.h @@ -0,0 +1,20 @@ +#ifndef __ACL_MASTER_PATHNAME_INCLUDE_H__ +#define __ACL_MASTER_PATHNAME_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_define.h" +#ifdef ACL_UNIX + +char *acl_master_pathname(const char *queue_path, const char *service_class, const char *service_name); + +#endif /* ACL_UNIX */ + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/src/master/framework/master_service.c b/lib_acl/src/master/framework/master_service.c new file mode 100644 index 000000000..5e8753582 --- /dev/null +++ b/lib_acl/src/master/framework/master_service.c @@ -0,0 +1,113 @@ +/* System libraries. */ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#endif + +#ifdef ACL_UNIX + +#include +#include +#include + +/* Utility library. */ + +#include "stdlib/acl_msg.h" +#include "event/acl_events.h" + +/* Application-specific. */ + +#include "../master_params.h" +#include "master.h" + +ACL_MASTER_SERV *acl_var_master_head = NULL; +ACL_EVENT *acl_var_master_global_event = NULL; + +/* acl_master_start_service - activate service */ + +void acl_master_start_service(ACL_MASTER_SERV *serv) +{ + const char *myname = "acl_master_start_service"; + + if (serv == NULL) + acl_msg_fatal("%s(%d): serv null", myname, __LINE__); + + if (acl_var_master_global_event == NULL) + acl_var_master_global_event = acl_event_new_select( + acl_var_master_delay_sec, acl_var_master_delay_usec); + if (acl_var_master_global_event == NULL) + acl_msg_fatal("%s(%d)->%s: acl_event_new null, serr=%s", + __FILE__, __LINE__, myname, strerror(errno)); + + /* + * Enable connection requests, wakeup timers, and status updates from + * child processes. + */ + acl_msg_info("%s: starting service %s ...", myname, serv->name); + + acl_master_listen_init(serv); + acl_msg_info("%s: service %s listen init ok ...", myname, serv->name); + acl_master_status_init(serv); + acl_msg_info("%s: service %s status init ok ...", myname, serv->name); + acl_master_avail_listen(serv); + acl_msg_info("%s: service %s avail listen ok ...", myname, serv->name); + acl_master_wakeup_init(serv); + acl_msg_info("%s: service %s wakeup init ok ...", myname, serv->name); + + acl_msg_info("%s: service started!", myname); +} + +/* acl_master_stop_service - deactivate service */ + +void acl_master_stop_service(ACL_MASTER_SERV *serv) +{ + /* + * Undo the things that master_start_service() did. + */ + acl_master_wakeup_cleanup(serv); + acl_master_status_cleanup(serv); + acl_master_avail_cleanup(serv); + acl_master_listen_cleanup(serv); +} + +/* acl_master_restart_service - restart service after configuration reload */ + +void acl_master_restart_service(ACL_MASTER_SERV *serv) +{ + const char *myname = "acl_master_restart_service"; + + if (acl_var_master_global_event == NULL) + acl_var_master_global_event = acl_event_new_select( + acl_var_master_delay_sec, + acl_var_master_delay_usec); + if (acl_var_master_global_event == NULL) + acl_msg_fatal("%s(%d)->%s: acl_event_new null, serr=%s", + __FILE__, __LINE__, myname, strerror(errno)); + /* + * Undo some of the things that master_start_service() did. + */ + acl_master_wakeup_cleanup(serv); + acl_master_status_cleanup(serv); + + /* + * Now undo the undone. + */ + acl_master_status_init(serv); + + /* set ACL_MASTER_FLAG_RELOADING flag */ + serv->flags |= ACL_MASTER_FLAG_RELOADING; + + acl_master_avail_listen(serv); + + /* delete ACL_MASTER_FLAG_RELOADING flag */ + serv->flags &= ~ACL_MASTER_FLAG_RELOADING; + + acl_master_wakeup_init(serv); +} +#endif /* ACL_UNIX */ diff --git a/lib_acl/src/master/framework/master_sig.c b/lib_acl/src/master/framework/master_sig.c new file mode 100644 index 000000000..5aa0c2139 --- /dev/null +++ b/lib_acl/src/master/framework/master_sig.c @@ -0,0 +1,268 @@ +/* System libraries. */ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#endif + +#ifdef ACL_UNIX + +#include +#include +#include +#include +#include + +/* Utility library. */ + +#include "stdlib/acl_msg.h" + +/* Application-specific. */ + +#include "master.h" +#include "../master_params.h" + +#ifdef USE_SIG_RETURN +#include +#endif + +#ifndef USE_SIG_RETURN +#define USE_SIG_PIPE +#endif + +/* Local stuff. */ + +#ifdef USE_SIG_PIPE +#include +#include + +#include "stdlib/acl_iostuff.h" +#include "stdlib/acl_vstream.h" +#include "event/acl_events.h" + +int acl_master_sig_pipe[2]; + +#define ACL_SIG_PIPE_WRITE_FD acl_master_sig_pipe[1] +#define ACL_SIG_PIPE_READ_FD acl_master_sig_pipe[0] +#endif + +ACL_VSTREAM *ACL_SIG_PIPE_WRITE_STREAM = NULL; +ACL_VSTREAM *ACL_SIG_PIPE_READ_STREAM = NULL; + +int acl_var_master_gotsigchld = 0; +int acl_var_master_gotsighup = 0; + +/* master_sighup - register arrival of hangup signal */ + +static void master_sighup(int sig) +{ + + /* + * WARNING WARNING WARNING. + * + * This code runs at unpredictable moments, as a signal handler. Don't put + * any code here other than for setting a global flag. + */ + acl_var_master_gotsighup = sig; +} + +/* master_sigchld - register arrival of child death signal */ + +#ifdef USE_SIG_RETURN + +static void master_sigchld(int sig, int code, struct sigcontext * scp) +{ + + code = code; + if (acl_msg_verbose) + acl_msg_info("%s(%d), USE_SIG_RETURN", __FILE__, __LINE__); + + /* + * WARNING WARNING WARNING. + * + * This code runs at unpredictable moments, as a signal handler. Don't put + * any code here other than for setting a global flag, or code that is + * intended to be run within a signal handler. + */ + acl_var_master_gotsigchld = sig; + if (scp != NULL && scp->sc_syscall == SYS_select) { + scp->sc_syscall_action = SIG_RETURN; +#ifndef SA_RESTART + } else if (scp != NULL) { + scp->sc_syscall_action = SIG_RESTART; +#endif + } +} + +#else + +#ifdef USE_SIG_PIPE + +/* master_sigchld - force wakeup from select() */ + +static void master_sigchld(int unused_sig) +{ + int saved_errno = errno; + + unused_sig = unused_sig; + + if (acl_msg_verbose) + acl_msg_info("%s(%d), USE_SIG_PIPE", __FILE__, __LINE__); + /* + * WARNING WARNING WARNING. + * + * This code runs at unpredictable moments, as a signal handler. Don't put + * any code here other than for setting a global flag, or code that is + * intended to be run within a signal handler. Restore errno in case we + * are interrupting the epilog of a failed system call. + */ + if (write(ACL_SIG_PIPE_WRITE_FD, "", 1) != 1) + acl_msg_warn("write to SIG_PIPE_WRITE_FD failed: %s", strerror(errno)); + errno = saved_errno; +} + +/* master_sig_event - called upon return from select() */ + +static void master_sig_event(int unused_event, void *unused_context) +{ + char c[1]; + + unused_event = unused_event; + unused_context = unused_context; + + while (read(ACL_SIG_PIPE_READ_FD, c, 1) > 0) + /* void */ ; + acl_var_master_gotsigchld = 1; +} + +#else + +static void master_sigchld(int sig) +{ + if (acl_msg_verbose) + acl_msg_info("%s(%d), use nothing", __FILE__, __LINE__); + + /* + * WARNING WARNING WARNING. + * + * This code runs at unpredictable moments, as a signal handler. Don't put + * any code here other than for setting a global flag. + */ + acl_var_master_gotsigchld = sig; +} + +#endif +#endif + +/* master_sigdeath - die, women and children first */ + +static void master_sigdeath(int sig) +{ + char *myname = "master_sigdeath"; + struct sigaction action; + pid_t pid = getpid(); + + /* + * XXX We're running from a signal handler, and really should not call + * any msg() routines at all, but it would be even worse to silently + * terminate without informing the sysadmin. + */ + acl_msg_info("%s: terminating on signal %d", myname, sig); + + /* + * Terminate all processes in our process group, except ourselves. + */ + sigemptyset(&action.sa_mask); + action.sa_flags = 0; + action.sa_handler = SIG_IGN; + if (sigaction(SIGTERM, &action, (struct sigaction *) 0) < 0) + acl_msg_fatal("%s: sigaction: %s", myname, strerror(errno)); + if (kill(-pid, SIGTERM) < 0) { + acl_msg_error("%s: kill process group: %s", myname, strerror(errno)); + exit (1); + } + + /* + * Deliver the signal to ourselves and clean up. XXX We're running as a + * signal handler and really should not be doing complicated things... + */ + sigemptyset(&action.sa_mask); + action.sa_flags = 0; + action.sa_handler = SIG_DFL; + if (sigaction(sig, &action, (struct sigaction *) 0) < 0) + acl_msg_fatal("%s: sigaction: %s", myname, strerror(errno)); + if (kill(pid, sig) < 0) + acl_msg_fatal("%s: kill myself: %s", myname, strerror(errno)); +} + +/* acl_master_sigsetup - set up signal handlers */ + +void acl_master_sigsetup(void) +{ + char *myname = "acl_master_sigsetup"; + struct sigaction action; + static int sigs[] = { + SIGINT, SIGQUIT, SIGILL, SIGBUS, /* SIGSEGV, only for test */ SIGTERM, + }; + unsigned i; + + sigemptyset(&action.sa_mask); + action.sa_flags = 0; + + /* + * Prepare to kill our children + * when we receive any of the above signals. + */ + action.sa_handler = master_sigdeath; + for (i = 0; i < sizeof(sigs) / sizeof(sigs[0]); i++) + if (sigaction(sigs[i], &action, (struct sigaction *) 0) < 0) + acl_msg_fatal("%s: sigaction(%d): %s", + myname, sigs[i], strerror(errno)); + + +#ifdef USE_SIG_PIPE + if (pipe(acl_master_sig_pipe)) + acl_msg_fatal("pipe: %s", strerror(errno)); + acl_non_blocking(ACL_SIG_PIPE_WRITE_FD, ACL_NON_BLOCKING); + acl_non_blocking(ACL_SIG_PIPE_READ_FD, ACL_NON_BLOCKING); + acl_close_on_exec(ACL_SIG_PIPE_WRITE_FD, ACL_CLOSE_ON_EXEC); + acl_close_on_exec(ACL_SIG_PIPE_READ_FD, ACL_CLOSE_ON_EXEC); + + ACL_SIG_PIPE_READ_STREAM = acl_vstream_fdopen(ACL_SIG_PIPE_READ_FD, + O_RDONLY, acl_var_master_buf_size, + acl_var_master_rw_timeout, ACL_VSTREAM_TYPE_SOCK); + if (ACL_SIG_PIPE_READ_STREAM == NULL) + acl_msg_fatal("%s(%d)->%s: acl_vstream_fdopen error=%s", + __FILE__, __LINE__, myname, strerror(errno)); + + if (acl_msg_verbose) + acl_msg_info("%s(%d)->%s: call acl_event_enable_read, " + "SIG_PIPE_READ_FD = %d", __FILE__, __LINE__, myname, + ACL_SIG_PIPE_READ_FD); + acl_event_enable_read(acl_var_master_global_event, + ACL_SIG_PIPE_READ_STREAM, 0, master_sig_event, (void *) 0); +#endif + + /* + * Intercept SIGHUP (re-read config file) and SIGCHLD (child exit). + */ +#ifdef SA_RESTART + action.sa_flags |= SA_RESTART; +#endif + action.sa_handler = master_sighup; + if (sigaction(SIGHUP, &action, (struct sigaction *) 0) < 0) + acl_msg_fatal("%s: sigaction(%d): %s", + myname, SIGHUP, strerror(errno)); + + action.sa_flags |= SA_NOCLDSTOP; + action.sa_handler = master_sigchld; + if (sigaction(SIGCHLD, &action, (struct sigaction *) 0) < 0) + acl_msg_fatal("%s: sigaction(%d): %s", + myname, SIGCHLD, strerror(errno)); +} +#endif /* ACL_UNIX */ diff --git a/lib_acl/src/master/framework/master_spawn.c b/lib_acl/src/master/framework/master_spawn.c new file mode 100644 index 000000000..fdf582453 --- /dev/null +++ b/lib_acl/src/master/framework/master_spawn.c @@ -0,0 +1,409 @@ +/* System libraries. */ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#endif + +#ifdef ACL_UNIX + +#include +#include +#include +#include +#include /* closelog() */ +#include +#include +#include +#include +#include + +/* Utility libraries. */ + +#include "stdlib/acl_msg.h" +#include "stdlib/acl_binhash.h" +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_vstring.h" +#include "stdlib/acl_argv.h" +#include "event/acl_events.h" + +/* Application-specific. */ + +#include "../master_proto.h" +#include "master.h" + +ACL_BINHASH *acl_var_master_child_table = NULL; +static void master_unthrottle(ACL_MASTER_SERV *serv); + +/* master_unthrottle_wrapper - in case (char *) != (struct *) */ + +static void master_unthrottle_wrapper(int unused_event, void *ptr) +{ + ACL_MASTER_SERV *serv = (ACL_MASTER_SERV *) ptr; + + unused_event = unused_event; + /* + * This routine runs after expiry of the timer set + * in master_throttle(), which gets called when it + * appears that the world is falling apart. + */ + master_unthrottle(serv); +} + +/* master_unthrottle - enable process creation */ + +static void master_unthrottle(ACL_MASTER_SERV *serv) +{ + + /* + * Enable process creation within this class. + * Disable the "unthrottle" timer just in case + * we're being called directly from the cleanup + * routine, instead of from the event manager. + */ + if ((serv->flags & ACL_MASTER_FLAG_THROTTLE) != 0) { + serv->flags &= ~ACL_MASTER_FLAG_THROTTLE; + acl_event_cancel_timer(acl_var_master_global_event, + master_unthrottle_wrapper, (void *) serv); + if (acl_msg_verbose) + acl_msg_info("throttle released for command %s", + serv->path); + acl_master_avail_listen(serv); /* XXX interface botch */ + } +} + +/* master_throttle - suspend process creation */ + +static void master_throttle(ACL_MASTER_SERV *serv) +{ + const char *myname = "master_throttle"; + + /* + * Perhaps the command to be run is defective, + * perhaps some configuration is wrong, or + * perhaps the system is out of resources. Disable further + * process creation attempts for a while. + */ + if ((serv->flags & ACL_MASTER_FLAG_THROTTLE) == 0) { + + serv->flags |= ACL_MASTER_FLAG_THROTTLE; + acl_event_request_timer(acl_var_master_global_event, + master_unthrottle_wrapper, (void *) serv, + (acl_int64) serv->throttle_delay * 1000000, 0); + if (acl_msg_verbose) + acl_msg_info("%s(%d)->%s: throttling command %s", + __FILE__, __LINE__, myname, serv->path); + } +} + +/* acl_master_spawn - spawn off new child process if we can */ + +void acl_master_spawn(ACL_MASTER_SERV *serv) +{ + const char *myname = "acl_master_spawn"; + ACL_MASTER_PROC *proc; + ACL_MASTER_NV *nv; + ACL_MASTER_PID pid; + int n, i; + static unsigned _master_generation = 0; + static ACL_VSTRING *env_gen = 0; + + if (acl_var_master_child_table == 0) + acl_var_master_child_table = acl_binhash_create(0, 0); + if (env_gen == 0) + env_gen = acl_vstring_alloc(100); + + /* + * Sanity checks. The master_avail module is supposed + * to know what it is doing. + */ + + if (!(serv->flags & ACL_MASTER_FLAG_RELOADING)) { + if (!ACL_MASTER_LIMIT_OK(serv->max_proc, serv->total_proc)) { + acl_msg_panic("%s(%d)->%s: at process limit %d", + __FILE__, __LINE__, myname, serv->total_proc); + } + if (serv->avail_proc > 0 && (serv->prefork_proc <= 0 + || serv->avail_proc > serv->prefork_proc)) + { + acl_msg_panic("%s(%d)->%s: processes available: %d" + ", processes prefork: %d", __FILE__, __LINE__, + myname, serv->avail_proc, serv->prefork_proc); + } + } + + if (serv->flags & ACL_MASTER_FLAG_THROTTLE) + acl_msg_panic("%s(%d)-%s: throttled service: %s", + __FILE__, __LINE__, myname, serv->path); + + /* + * Create a child process and connect parent and + * child via the status pipe. + */ + _master_generation += 1; + switch (pid = fork()) { + + /* + * Error. We're out of some essential resource. + * Best recourse is to try again later. + */ + case -1: + acl_msg_warn("%s: fork: %s -- throttling", myname, strerror(errno)); + master_throttle(serv); + return; + + /* + * Child process. Redirect child stdin/stdout to + * the parent-child connection and run the requested + * command. Leave child stderr alone. Disable exit + * handlers: they should be executed by the parent only. + */ + case 0: /* child process */ + + /* MASTER_FLOW_READ_STREAM has been inited in master_vars.c */ + if (acl_var_master_flow_pipe[0] <= ACL_MASTER_FLOW_READ) + acl_msg_fatal("%s: flow pipe read descriptor <= %d", + myname, ACL_MASTER_FLOW_READ); + if (dup2(acl_var_master_flow_pipe[0], ACL_MASTER_FLOW_READ) < 0) + acl_msg_fatal("%s: dup2: %s", myname, strerror(errno)); + if (close(acl_var_master_flow_pipe[0]) < 0) + acl_msg_fatal("close %d: %s", + acl_var_master_flow_pipe[0], strerror(errno)); + + /* MASTER_FLOW_WRITE_STREAM has been inited in master_vars.c */ + if (acl_var_master_flow_pipe[1] <= ACL_MASTER_FLOW_WRITE) + acl_msg_fatal("%s: flow pipe read descriptor <= %d", + myname, ACL_MASTER_FLOW_WRITE); + if (dup2(acl_var_master_flow_pipe[1], ACL_MASTER_FLOW_WRITE) < 0) + acl_msg_fatal("%s: dup2: %s", myname, strerror(errno)); + if (close(acl_var_master_flow_pipe[1]) < 0) + acl_msg_fatal("close %d: %s", + acl_var_master_flow_pipe[1], strerror(errno)); + + close(serv->status_fd[0]); /* status channel */ + acl_vstream_free(serv->status_read_stream); + + /* MASTER_STAT_STREAM has been inited in master_vars.c*/ + if (serv->status_fd[1] <= ACL_MASTER_STATUS_FD) + acl_msg_fatal("%s: status file descriptor collision", + myname); + if (dup2(serv->status_fd[1], ACL_MASTER_STATUS_FD) < 0) + acl_msg_fatal("%s: dup2 status_fd: %s", + myname, strerror(errno)); + (void) close(serv->status_fd[1]); + + for (n = 0; n < serv->listen_fd_count; n++) { + if (serv->listen_fds[n] <= ACL_MASTER_LISTEN_FD + n) + acl_msg_fatal("%s(%d)->%s: " + "listen file descriptor collision", + __FILE__, __LINE__, myname); + if (dup2(serv->listen_fds[n], ACL_MASTER_LISTEN_FD + n) < 0) + acl_msg_fatal("%s: dup2 listen_fd %d: %s", + myname, serv->listen_fds[n], strerror(errno)); + (void) close(serv->listen_fds[n]); + acl_vstream_free(serv->listen_streams[n]); + } + + acl_vstring_sprintf(env_gen, "%s=%o", + ACL_MASTER_GEN_NAME, _master_generation); + if (putenv(acl_vstring_str(env_gen)) < 0) + acl_msg_fatal("%s: putenv: %s", myname, strerror(errno)); + + n = acl_array_size(serv->children_env); + for (i = 0; i < n; i++) { + nv = (ACL_MASTER_NV *) + acl_array_index(serv->children_env, i); + if (nv == NULL) + break; + setenv(nv->name, nv->value, 1); + } + + /* begin to call the child process */ + if (acl_msg_verbose) + acl_msg_info("%s(%d)->%s: cmd = %s", + __FILE__, __LINE__, myname, serv->path); + execvp(serv->path, serv->args->argv); + acl_msg_fatal("%s(%d)->%s: exec %s: %s", __FILE__, __LINE__, + myname, serv->path, strerror(errno)); + exit(1); + /* NOTREACHED */ + + /* + * Parent. Fill in a process member data structure + * and set up links between child and process. + * Say this process has become available. + * If this service has a wakeup timer that is turned + * on only when the service is actually used, + * turn on the wakeup timer. + */ + default: /* the parent process */ + if (acl_msg_verbose) + acl_msg_info("spawn command %s; pid %d", + serv->path, pid); + proc = (ACL_MASTER_PROC *) acl_mycalloc(1, + sizeof(ACL_MASTER_PROC)); + proc->serv = serv; + proc->pid = pid; + proc->gen = _master_generation; + proc->use_count = 0; + proc->avail = 0; + acl_binhash_enter(acl_var_master_child_table, (char *) &pid, + sizeof(pid), (char *) proc); + serv->total_proc++; + acl_master_avail_more(serv, proc); + if (serv->flags & ACL_MASTER_FLAG_CONDWAKE) { + serv->flags &= ~ACL_MASTER_FLAG_CONDWAKE; + acl_master_wakeup_init(serv); + if (acl_msg_verbose) + acl_msg_info("start conditional timer for %s", + serv->name); + } + + return; + } +} + +/* master_delete_child - destroy child process info */ + +static void master_delete_child(ACL_MASTER_PROC *proc) +{ + const char *myname = "master_delete_child"; + ACL_MASTER_SERV *serv; + + /* + * Undo the things that master_spawn did. + * Stop the process if it still exists, + * and remove it from the lookup tables. + * Update the number of available processes. + */ + serv = proc->serv; + serv->total_proc--; + if (proc->avail == ACL_MASTER_STAT_AVAIL) { + if (acl_msg_verbose) + acl_msg_info("%s(%d)->%s: call master_avail_less", + __FILE__, __LINE__, myname); + acl_master_avail_less(serv, proc); + } else if (ACL_MASTER_LIMIT_OK(serv->max_proc, serv->total_proc) + && serv->avail_proc < 1) + { + if (acl_msg_verbose) + acl_msg_info("%s(%d)->%s: listen again", + __FILE__, __LINE__, myname); + acl_master_avail_listen(serv); + } + + if (acl_msg_verbose > 2) + acl_msg_info("%s(%d)->%s: delete process id: %d", + __FILE__, __LINE__, myname, proc->pid); + + acl_binhash_delete(acl_var_master_child_table, (void *) &proc->pid, + sizeof(proc->pid), (void (*) (void *)) 0); + acl_myfree(proc); +} + +/* acl_master_reap_child - reap dead children */ + +void acl_master_reap_child(void) +{ + const char *myname = "acl_master_reap_child"; + ACL_MASTER_SERV *serv; + ACL_MASTER_PROC *proc; + ACL_MASTER_PID pid; + ACL_WAIT_STATUS_T status; + char buf[256]; + + /* + * Pick up termination status of all dead children. + * When a process failed on its first job, assume + * we see the symptom of a structural problem + * (configuration problem, system running out of resources) + * and back off. + */ + while ((pid = waitpid((pid_t) - 1, &status, WNOHANG)) > 0) { + if (acl_msg_verbose) + acl_msg_info("master_reap_child: pid %d", pid); + if ((proc = (ACL_MASTER_PROC *) + acl_binhash_find(acl_var_master_child_table, + (char *) &pid, sizeof(pid))) == 0) { + acl_msg_panic("master_reap: unknown pid: %d", pid); + continue; + } + serv = proc->serv; + + if (ACL_NORMAL_EXIT_STATUS(status)) { + master_delete_child(proc); + continue; + } + + if (WIFEXITED(status)) { + acl_msg_warn("%s(%d), %s: process %s pid %d " + "exit status %d", __FILE__, __LINE__, + myname, serv->path, pid, WEXITSTATUS(status)); + if (serv->notify_addr != NULL + && serv->notify_recipients != NULL) + { + snprintf(buf, sizeof(buf), "exit status %d", + WEXITSTATUS(status)); + master_warning(serv->notify_addr, + serv->notify_recipients, + serv->path, pid, buf); + } + } + if (WIFSIGNALED(status)) { + acl_msg_warn("%s(%d), %s: process %s pid %d killed" + " by signal %d", __FILE__, __LINE__, myname, + serv->path, pid, WTERMSIG(status)); + if (serv->notify_addr != NULL + && serv->notify_recipients != NULL) + { + snprintf(buf, sizeof(buf), "killed by %d", + WTERMSIG(status)); + master_warning(serv->notify_addr, + serv->notify_recipients, + serv->path, pid, buf); + } + } + if (proc->use_count == 0 + && (serv->flags & ACL_MASTER_FLAG_THROTTLE) == 0) { + acl_msg_warn("%s(%d), %s: bad command startup, path=%s" + " -- throttling", __FILE__, __LINE__, + myname, serv->path); + master_throttle(serv); + } + + master_delete_child(proc); + } +} + +/* acl_master_delete_children - delete all child processes of service */ + +void acl_master_delete_children(ACL_MASTER_SERV *serv) +{ + ACL_BINHASH_INFO **list; + ACL_BINHASH_INFO **info; + ACL_MASTER_PROC *proc; + + /* + * XXX turn on the throttle so that master_reap_child() doesn't. + * Someone has to turn off the throttle in order to stop the + * associated timer request, so we might just as well do it at the end. + */ + master_throttle(serv); + info = list = acl_binhash_list(acl_var_master_child_table); + for (; *info; info++) { + proc = (ACL_MASTER_PROC *) info[0]->value; + if (proc->serv == serv) + (void) kill(proc->pid, SIGTERM); + } + while (serv->total_proc > 0) + acl_master_reap_child(); + acl_myfree(list); + master_unthrottle(serv); +} + +#endif /* ACL_UNIX */ diff --git a/lib_acl/src/master/framework/master_status.c b/lib_acl/src/master/framework/master_status.c new file mode 100644 index 000000000..5fde67dd7 --- /dev/null +++ b/lib_acl/src/master/framework/master_status.c @@ -0,0 +1,219 @@ +/* System libraries. */ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#endif + +#ifdef ACL_UNIX + +#include +#include +#include + +/* Utility library. */ + +#include "stdlib/acl_msg.h" +#include "stdlib/acl_vstream.h" +#include "stdlib/acl_binhash.h" +#include "stdlib/acl_iostuff.h" +#include "event/acl_events.h" + +/* Application-specific. */ + +#include "../master_proto.h" +#include "../master_params.h" +#include "master.h" + +/* master_status_event - status read event handler */ + +static void master_status_event(int event, void *context) +{ + const char *myname = "master_status_event"; + ACL_MASTER_SERV *serv = (ACL_MASTER_SERV *) context; + ACL_MASTER_STATUS stat_buf; + ACL_MASTER_PROC *proc; + ACL_MASTER_PID pid; + int n; + + if (event == 0) /* XXX Can this happen? */ + return; + + /* + * We always keep the child end of the status pipe open, so an EOF read + * condition means that we're seriously confused. We use non-blocking + * reads so that we don't get stuck when someone sends a partial message. + * Messages are short, so a partial read means someone wrote less than a + * whole status message. Hopefully the next read will be in sync again... + * We use a global child process status table because when a child dies + * only its pid is known - we do not know what service it came from. + */ + +#if 1 + n = read(ACL_VSTREAM_FILE(serv->status_read_stream), + (char *) &stat_buf, sizeof(stat_buf)); +#else + n = acl_vstream_readn(serv->status_read_stream, + (char *) &stat_buf, sizeof(stat_buf)); +#endif + + switch (n) { + case -1: + acl_msg_warn("%s(%d)->%s: fd = %d, read: %s", + __FILE__, __LINE__, myname, + serv->status_fd[0], strerror(errno)); + return; + + case 0: + acl_msg_panic("%s(%d)->%s: fd = %d, read EOF status", + __FILE__, __LINE__, myname, serv->status_fd[0]); + /* NOTREACHED */ + + default: + acl_msg_warn("%s(%d)->%s: service %s: child (pid %d) " + "sent partial, fd = %d, status update (%d bytes)", + __FILE__, __LINE__, myname, serv->name, stat_buf.pid, + serv->status_fd[0], n); + return; + + case sizeof(stat_buf): + pid = stat_buf.pid; + if (acl_msg_verbose) + acl_msg_info("%s: pid = %d, gen = %u, avail = %d, " + "fd = %d", myname, stat_buf.pid, stat_buf.gen, + stat_buf.avail, serv->status_fd[0]); + } /* end switch */ + + /* + * Sanity checks. Do not freak out when the child sends garbage because + * it is confused or for other reasons. However, be sure to freak out + * when our own data structures are inconsistent. A process not found + * condition can happen when we reap a process before receiving its + * status update, so this is not an error. + */ + + if (acl_var_master_child_table == 0) + acl_msg_fatal("%s(%d): acl_var_master_child_table null", + myname, __LINE__); + + if ((proc = (ACL_MASTER_PROC *) acl_binhash_find( + acl_var_master_child_table, (char *) &pid, sizeof(pid))) == 0) + { + acl_msg_warn("%s(%d)->%s: process id not found: pid = %d," + " status = %d, gen = %u", __FILE__, __LINE__, + myname, stat_buf.pid, stat_buf.avail, stat_buf.gen); + return; + } + if (proc->gen != stat_buf.gen) { + acl_msg_warn("%s(%d)->%s: ignoring status update from child " + "pid %d generation %u", __FILE__, __LINE__, + myname, pid, stat_buf.gen); + return; + } + if (proc->serv != serv) + acl_msg_panic("%s(%d)->%s: pointer corruption: %p != %p", + __FILE__, __LINE__, myname, (void *) proc->serv, + (void *) serv); + + /* + * Update our idea of the child process status. Allow redundant status + * updates, because different types of events may be processed out of + * order. Otherwise, warn about weird status updates but do not take + * action. It's all gossip after all. + */ + if (proc->avail == stat_buf.avail) + return; + + switch (stat_buf.avail) { + case ACL_MASTER_STAT_AVAIL: + proc->use_count++; + acl_master_avail_more(serv, proc); + break; + case ACL_MASTER_STAT_TAKEN: + acl_master_avail_less(serv, proc); + break; + default: + acl_msg_warn("%s(%d)->%s: ignoring unknown status: %d " + "allegedly from pid: %d", __FILE__, __LINE__, + myname, stat_buf.pid, stat_buf.avail); + break; + } +} + +/* acl_master_status_init - start status event processing for this service */ + +void acl_master_status_init(ACL_MASTER_SERV *serv) +{ + const char *myname = "acl_master_status_init"; + + /* + * Sanity checks. + */ + if (serv->status_fd[0] >= 0 || serv->status_fd[1] >= 0) + acl_msg_panic("%s: status events already enabled", myname); + if (acl_msg_verbose) + acl_msg_info("%s: %s", myname, serv->name); + + /* + * Make the read end of this service's status pipe non-blocking so that + * we can detect partial writes on the child side. We use a duplex pipe + * so that the child side becomes readable when the master goes away. + */ + if (acl_duplex_pipe(serv->status_fd) < 0) + acl_msg_fatal("pipe: %s", strerror(errno)); + acl_non_blocking(serv->status_fd[0], ACL_BLOCKING); + acl_close_on_exec(serv->status_fd[0], ACL_CLOSE_ON_EXEC); + acl_close_on_exec(serv->status_fd[1], ACL_CLOSE_ON_EXEC); + serv->status_read_stream = acl_vstream_fdopen(serv->status_fd[0], + O_RDWR, acl_var_master_buf_size, + acl_var_master_rw_timeout, ACL_VSTREAM_TYPE_SOCK); + + if (acl_msg_verbose) + acl_msg_info("%s(%d)->%s: call acl_event_enable_read, " + "status_fd = %d", __FILE__, __LINE__, + myname, serv->status_fd[0]); + + acl_event_enable_read(acl_var_master_global_event, + serv->status_read_stream, 0, master_status_event, + (void *) serv); +} + +/* acl_master_status_cleanup - stop status event processing for this service */ + +void acl_master_status_cleanup(ACL_MASTER_SERV *serv) +{ + const char *myname = "acl_master_status_cleanup"; + + /* + * Sanity checks. + */ + if (serv->status_fd[0] < 0 || serv->status_fd[1] < 0) + acl_msg_panic("%s: status events not enabled", myname); + if (acl_msg_verbose) + acl_msg_info("%s: %s", myname, serv->name); + + /* + * Dispose of this service's status pipe after disabling read events. + */ + + acl_event_disable_readwrite(acl_var_master_global_event, + serv->status_read_stream); + + if (close(serv->status_fd[0]) != 0) + acl_msg_warn("%s: close status descriptor (read side): %s", + myname, strerror(errno)); + if (close(serv->status_fd[1]) != 0) + acl_msg_warn("%s: close status descriptor (write side): %s", + myname, strerror(errno)); + serv->status_fd[0] = serv->status_fd[1] = -1; + if (serv->status_read_stream) + acl_vstream_free(serv->status_read_stream); + serv->status_read_stream = NULL; +} + +#endif /* ACL_UNIX */ diff --git a/lib_acl/src/master/framework/master_wakeup.c b/lib_acl/src/master/framework/master_wakeup.c new file mode 100644 index 000000000..9d8af4262 --- /dev/null +++ b/lib_acl/src/master/framework/master_wakeup.c @@ -0,0 +1,154 @@ +/* System library. */ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#endif + +#ifdef ACL_UNIX + +#include +#include +#include + +/* Utility library. */ + +#include "stdlib/acl_msg.h" +#include "stdlib/unix/acl_set_eugid.h" +#include "stdlib/unix/acl_set_ugid.h" +#include "event/acl_events.h" + +/* Global library. */ + +#include "trigger/trigger.h" + +/* Application-specific. */ + +#include "../master_proto.h" /* triggers */ +#include "../master_params.h" + +#include "master.h" + +/* master_wakeup_timer_event - wakeup event handler */ + +static void master_wakeup_timer_event(int event acl_unused, void *context) +{ + const char *myname = "master_wakeup_timer_event"; + ACL_MASTER_SERV *serv = (ACL_MASTER_SERV *) context; + static char wakeup = ACL_TRIGGER_REQ_WAKEUP; + int status = 0; + + /* + * Don't wakeup services whose automatic wakeup feature was + * turned off in the mean time. + */ + if (serv->wakeup_time == 0) + return; + + /* + * Don't wakeup services whose is ACL_MASTER_SERV_TYPE_SOCK + */ + if (serv->type == ACL_MASTER_SERV_TYPE_SOCK) + return; + + /* + * Don't wake up services that are throttled. Find out what + * transport to use. We can't block here so we choose a short timeout. + */ +#define BRIEFLY 1 + + if (ACL_MASTER_THROTTLED(serv) == 0) { + if (acl_msg_verbose) + acl_msg_info("%s: service %s", myname, serv->name); + + switch (serv->type) { + case ACL_MASTER_SERV_TYPE_INET: + status = acl_inet_trigger(acl_var_master_global_event, + serv->name, &wakeup, sizeof(wakeup), BRIEFLY); + break; + case ACL_MASTER_SERV_TYPE_UNIX: + status = ACL_LOCAL_TRIGGER(acl_var_master_global_event, + serv->name, &wakeup, sizeof(wakeup), BRIEFLY); + break; + + /* + * If someone compromises the postfix account then this must not + * overwrite files outside the chroot jail. Countermeasures: + * + * - Limit the damage by accessing the FIFO as postfix not root. + * + * - Have fifo_trigger() call safe_open() so we won't follow + * arbitrary hard/symlinks to files in/outside the chroot jail. + * + * - All non-chroot postfix-related files must be root owned (or + * postfix check complains). + * + * - The postfix user and group ID must not be shared with other + * applications (says the INSTALL documentation). + * + * Result of a discussion with Michael Tokarev, who received his + * insights from Solar Designer, who tested Postfix with a kernel + * module that is paranoid about open() calls. + */ + case ACL_MASTER_SERV_TYPE_FIFO: + acl_set_eugid(acl_var_master_owner_uid, + acl_var_master_owner_gid); + status = acl_fifo_trigger(acl_var_master_global_event, + serv->name, &wakeup, sizeof(wakeup), BRIEFLY); + acl_set_ugid(getuid(), getgid()); + break; + default: + acl_msg_panic("%s: unknown service type: %d", + myname, serv->type); + } + if (status < 0) + acl_msg_warn("%s: service %s: %s", + myname, serv->name, strerror(errno)); + } + + /* + * Schedule another wakeup event. + */ + acl_event_request_timer(acl_var_master_global_event, + master_wakeup_timer_event, (void *) serv, + (acl_int64) serv->wakeup_time * 1000000, 0); +} + +/* acl_master_wakeup_init - start automatic service wakeup */ + +void acl_master_wakeup_init(ACL_MASTER_SERV *serv) +{ + const char *myname = "acl_master_wakeup_init"; + + if (serv->wakeup_time == 0 || (serv->flags & ACL_MASTER_FLAG_CONDWAKE)) + return; + if (acl_msg_verbose) + acl_msg_info("%s: service %s time %d", + myname, serv->name, serv->wakeup_time); + master_wakeup_timer_event(0, (void *) serv); +} + +/* acl_master_wakeup_cleanup - cancel wakeup timer */ + +void acl_master_wakeup_cleanup(ACL_MASTER_SERV *serv) +{ + const char *myname = "acl_master_wakeup_cleanup"; + + /* + * Cleanup, even when the wakeup feature has been turned off. There might + * still be a pending timer. Don't depend on the code that reloads the + * config file to reset the wakeup timer when things change. + */ + if (acl_msg_verbose) + acl_msg_info("%s: service %s", myname, serv->name); + + acl_event_cancel_timer(acl_var_master_global_event, + master_wakeup_timer_event, (void *) serv); +} + +#endif /* ACL_UNIX */ diff --git a/lib_acl/src/master/framework/master_warning.c b/lib_acl/src/master/framework/master_warning.c new file mode 100644 index 000000000..a175c8a84 --- /dev/null +++ b/lib_acl/src/master/framework/master_warning.c @@ -0,0 +1,107 @@ +#include "stdlib/acl_define.h" + +#ifdef ACL_UNIX +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_vstring.h" +#include "net/acl_net.h" +#include "thread/acl_thread.h" +#include "../master_params.h" +#include "master.h" + +typedef struct WARN_INFO { + char *notify_addr; + char *notify_recipients; + char *path; + int pid; + char *desc; +} WARN_INFO; + +static WARN_INFO *warn_info_new(const char *notify_addr, + const char *notify_recipients, const char *path, + int pid, const char *desc) +{ + WARN_INFO *info = (WARN_INFO*) acl_mycalloc(1, sizeof(WARN_INFO)); + + info->notify_addr = acl_mystrdup(notify_addr); + info->notify_recipients = acl_mystrdup(notify_recipients); + info->path = acl_mystrdup(path); + info->pid = pid; + info->desc = acl_mystrdup(desc); + return (info); +} + +static void warn_info_free(WARN_INFO *info) +{ + acl_myfree(info->notify_addr); + acl_myfree(info->notify_recipients); + acl_myfree(info->path); + acl_myfree(info->desc); + acl_myfree(info); +} + +static void notify_thread(void *arg) +{ + const char *myname = "notify_thread"; + WARN_INFO *info = (WARN_INFO*) arg; + ACL_VSTREAM *client; + ACL_VSTRING *buf; + int ret; + + buf = acl_vstring_alloc(256); + acl_vstring_sprintf(buf, "PROC=%s|PID=%d|RCPT=%s|info=%s\r\n", + info->path, info->pid, info->notify_recipients, info->desc); + + client = acl_vstream_connect(info->notify_addr, + ACL_BLOCKING, 60, 60, 1024); + if (client == NULL) { + acl_msg_error("%s(%d): connect %s error, info(%s)", myname, + __LINE__, info->notify_addr, acl_vstring_str(buf)); + acl_vstring_free(buf); + warn_info_free(info); + return; + } + + /* 禁止将该句柄传递给子进程 */ + acl_close_on_exec(ACL_VSTREAM_SOCK(client), ACL_CLOSE_ON_EXEC); + + ret = acl_vstream_writen(client, acl_vstring_str(buf), + ACL_VSTRING_LEN(buf)); + if (ret == ACL_VSTREAM_EOF) + acl_msg_error("%s(%d): write to notify server error, info(%s)", + myname, __LINE__, acl_vstring_str(buf)); + else + acl_msg_info("%s(%d): notify ok!", myname, __LINE__); + + acl_vstream_close(client); + acl_vstring_free(buf); + warn_info_free(info); +} + +void master_warning(const char *notify_addr, const char *notify_recipients, + const char *path, int pid, const char *desc) +{ + const char *myname = "master_warning"; + WARN_INFO *info; + + if (notify_addr == NULL || *notify_addr == 0) { + acl_msg_warn("%s(%d): notify_addr invalid", myname, __LINE__); + return; + } + if (path == NULL || *path == 0) { + acl_msg_warn("%s(%d): path invalid", myname, __LINE__); + return; + } + if (desc == NULL || *desc == 0) { + acl_msg_warn("%s(%d): desc invalid", myname, __LINE__); + return; + } + + info = warn_info_new(notify_addr, notify_recipients, path, pid, desc); + if (acl_pthread_pool_add(acl_var_master_thread_pool, + notify_thread, info) != 0) + { + warn_info_free(info); + } +} + +#endif /* ACL_UNIX */ diff --git a/lib_acl/src/master/framework/trigger/fifo_trigger.c b/lib_acl/src/master/framework/trigger/fifo_trigger.c new file mode 100644 index 000000000..af64404ff --- /dev/null +++ b/lib_acl/src/master/framework/trigger/fifo_trigger.c @@ -0,0 +1,153 @@ +/* System library. */ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#endif + +#ifdef ACL_UNIX + +#include +#include +#include +#include +#include + +/* Utility library. */ + +#include "stdlib/acl_msg.h" +#include "stdlib/acl_iostuff.h" +#include "stdlib/unix/acl_safe_open.h" + +/* Process manager. */ + +#include "trigger.h" + +/* acl_fifo_trigger - wakeup fifo server */ + +int acl_fifo_trigger(ACL_EVENT *eventp_unused, const char *service, + const char *buf, int len, int timeout) +{ + const char *myname = "acl_fifo_trigger"; + static ACL_VSTRING *why; + ACL_VSTREAM *fp; + int fd; + + eventp_unused = eventp_unused; + + if (why == 0) + why = acl_vstring_alloc(1); + + /* + * Write the request to the service fifo. According to POSIX, the open + * shall always return immediately, and shall return an error when no + * process is reading from the FIFO. + * + * Use safe_open() so that we don't follow symlinks, and so that we don't + * open files with multiple hard links. We're not (yet) going to bother + * the caller with safe_open() specific quirks such as the why argument. + */ + if ((fp = acl_safe_open(service, O_WRONLY | O_NONBLOCK, 0, + (struct stat *) 0, (uid_t) -1, + (uid_t) -1, why)) == 0) + { + if (acl_msg_verbose) + acl_msg_info("%s: open %s: %s", + myname, service, acl_vstring_str(why)); + return (-1); + } + fd = ACL_VSTREAM_FILE(fp); + + /* + * Write the request... + */ + acl_non_blocking(fd, timeout > 0 ? ACL_NON_BLOCKING : ACL_BLOCKING); + if (acl_write_buf(fd, buf, len, timeout) < 0) + if (acl_msg_verbose) + acl_msg_warn("%s: write %s: %s", + myname, service, strerror(errno)); + + /* + * Disconnect. + */ + if (acl_vstream_fclose(fp)) + if (acl_msg_verbose) + acl_msg_warn("%s: close %s: %s", + myname, service, strerror(errno)); + return (0); +} +#endif /* ACL_UNIX */ + +#ifdef TEST + +/* + * Set up a FIFO listener, and keep triggering until the listener becomes + * idle, which should never happen. + */ +#include +#include + +#include "acl_events.h" +#include "acl_listen.h" + +#define TEST_FIFO "test-fifo" + +int trig_count; +int wakeup_count; + +static void cleanup(void) +{ + unlink(TEST_FIFO); + exit(1); +} + +static void handler(int sig) +{ + acl_msg_fatal("got signal %d after %d triggers %d wakeups", + sig, trig_count, wakeup_count); +} + +static void read_event(int unused_event, char *context) +{ + int fd = (int) context; + char ch; + + wakeup_count++; + + if (read(fd, &ch, 1) != 1) + acl_msg_fatal("read %s: %m", TEST_FIFO); +} + +int main(int unused_argc, char **unused_argv) +{ + int listen_fd; + + listen_fd = acl_fifo_listen(TEST_FIFO, 0600, ACL_NON_BLOCKING); + acl_msg_cleanup(cleanup); + acl_event_enable_read(listen_fd, read_event, (char *) listen_fd); + signal(SIGINT, handler); + signal(SIGALRM, handler); + for (;;) { + alarm(10); + if (acl_fifo_trigger(TEST_FIFO, "", 1, 0) < 0) + acl_msg_fatal("trigger %s: %m", TEST_FIFO); + trig_count++; + if (acl_fifo_trigger(TEST_FIFO, "", 1, 0) < 0) + acl_msg_fatal("trigger %s: %m", TEST_FIFO); + trig_count++; + if (acl_fifo_trigger(TEST_FIFO, "", 1, 0) < 0) + acl_msg_fatal("trigger %s: %m", TEST_FIFO); + trig_count++; + acl_event_loop(-1); + acl_event_loop(-1); + acl_event_loop(-1); + } +} + +#endif + diff --git a/lib_acl/src/master/framework/trigger/inet_trigger.c b/lib_acl/src/master/framework/trigger/inet_trigger.c new file mode 100644 index 000000000..080198ada --- /dev/null +++ b/lib_acl/src/master/framework/trigger/inet_trigger.c @@ -0,0 +1,126 @@ +/* System library. */ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#endif + +#ifdef ACL_UNIX + +#include +#include +#include +#include +#include +#include +#include +#include + +/* Utility library. */ + +#include "stdlib/acl_msg.h" +#include "stdlib/acl_iostuff.h" +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_vstream.h" +#include "event/acl_events.h" +#include "net/acl_connect.h" + +/* Process manager. */ + +#include "trigger.h" + +struct ACL_INET_TRIGGER { + int fd; + ACL_EVENT *eventp; + ACL_VSTREAM *stream; + char *service; +}; + +/* ACL_INET_TRIGGER_event - disconnect from peer */ + +static void acl_inet_trigger_event(int event, void *context) +{ + const char *myname = "acl_inet_trigger_event"; + struct ACL_INET_TRIGGER *ip = (struct ACL_INET_TRIGGER *) context; + + /* + * Disconnect. + */ + if (event == ACL_EVENT_TIME) + acl_msg_warn("%s: read timeout for service %s", + myname, ip->service); + acl_event_disable_readwrite(ip->eventp, ip->stream); + /* + * acl_event_cancel_timer(ip->eventp, acl_inet_trigger_event, context); + */ + if (acl_vstream_close(ip->stream) < 0) + acl_msg_warn("%s: close %s: %s", + myname, ip->service, strerror(errno)); + acl_myfree(ip->service); + acl_myfree(ip); +} + + +/* acl_inet_trigger - wakeup INET-domain server */ + +int acl_inet_trigger(ACL_EVENT *eventp, const char *service, + const char *buf, int len, int timeout) +{ + const char *myname = "acl_inet_trigger"; + struct ACL_INET_TRIGGER *ip; + int fd; + + if (acl_msg_verbose > 1) + acl_msg_info("%s: service %s", myname, service); + + /* + * Connect... + */ + if ((fd = acl_inet_connect(service, ACL_BLOCKING, timeout)) < 0) { + if (acl_msg_verbose) + acl_msg_warn("%s: connect to %s: %s", + myname, service, strerror(errno)); + return (-1); + } + acl_close_on_exec(fd, ACL_CLOSE_ON_EXEC); + + /* + * Stash away context. + */ + ip = (struct ACL_INET_TRIGGER *) acl_mymalloc(sizeof(*ip)); + ip->fd = fd; + ip->service = acl_mystrdup(service); + ip->stream = acl_vstream_fdopen(fd, O_RDWR, 4096, + timeout, ACL_VSTREAM_TYPE_LISTEN_INET); + ip->eventp = eventp; + + /* + * Write the request... + */ + if (acl_write_buf(fd, buf, len, timeout) < 0 + || acl_write_buf(fd, "", 1, timeout) < 0) + { + if (acl_msg_verbose) + acl_msg_warn("%s: write to %s: %s", + myname, service, strerror(errno)); + } + + /* + * Wakeup when the peer disconnects, or when we lose patience. + */ + + if (timeout > 0) + acl_event_enable_read(ip->eventp, ip->stream, timeout + 100, + acl_inet_trigger_event, (void *) ip); + else + acl_event_enable_read(ip->eventp, ip->stream, 0, + acl_inet_trigger_event, (void *) ip); + + return (0); +} +#endif /* ACL_UNIX */ diff --git a/lib_acl/src/master/framework/trigger/stream_trigger.c b/lib_acl/src/master/framework/trigger/stream_trigger.c new file mode 100644 index 000000000..ee034f2ff --- /dev/null +++ b/lib_acl/src/master/framework/trigger/stream_trigger.c @@ -0,0 +1,123 @@ +/* System library. */ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#endif + +#ifdef ACL_UNIX + +#include +#include +#include +#include + +/* Utility library. */ + +#include "stdlib/acl_msg.h" +#include "stdlib/acl_iostuff.h" +#include "stdlib/acl_mymalloc.h" +#include "net/acl_connect.h" +#include "event/acl_events.h" + +/* Process manager. */ + +#include "trigger.h" + +#ifdef SUNOS5 + +struct ACL_STREAM_TRIGGER { + int fd; + ACL_VSTREAM *stream; + ACL_EVENT *eventp; + char *service; +}; + +/* acl_stream_trigger_event - disconnect from peer */ + +static void acl_stream_trigger_event(int event, void *context) +{ + const char *myname = "acl_stream_trigger_event"; + struct ACL_STREAM_TRIGGER *sp = (struct ACL_STREAM_TRIGGER *) context; + + /* + * Disconnect. + */ + if (event == ACL_EVENT_TIME) + acl_msg_warn("%s: read timeout for service %s", + myname, sp->service); + acl_event_disable_readwrite(sp->eventp, sp->stream); + /* + * acl_event_cancel_timer(sp->eventp, acl_stream_trigger_event, context); + */ + if (acl_vstream_close(sp->stream) < 0) + acl_msg_warn("%s: close %s: %s", + myname, sp->service, strerror(errno)); + acl_myfree(sp->service); + acl_myfree(sp); +} + +/* acl_stream_trigger - wakeup stream server */ + +int acl_stream_trigger(ACL_EVENT *eventp, const char *service, + const char *buf,int len, int timeout) +{ + const char *myname = "acl_stream_trigger"; + struct ACL_STREAM_TRIGGER *sp; + int fd; + + if (acl_msg_verbose > 1) + acl_msg_info("%s: service %s", myname, service); + + /* + * Connect... + */ + if ((fd = acl_stream_connect(service, ACL_BLOCKING, timeout)) < 0) { + if (acl_msg_verbose) + acl_msg_warn("%s: connect to %s: %s", + myname, service, strerror(errno)); + return (-1); + } + acl_close_on_exec(fd, ACL_CLOSE_ON_EXEC); + + /* + * Stash away context. + */ + sp = (struct ACL_STREAM_TRIGGER *) acl_mymalloc(sizeof(*sp)); + sp->fd = fd; + sp->service = acl_mystrdup(service); + sp->stream = acl_vstream_fdopen(fd, O_RDWR, 4096, + timeout, ACL_VSTREAM_TYPE_SOCK); + sp->eventp = eventp; + + /* + * Write the request... + */ + if (acl_write_buf(fd, buf, len, timeout) < 0 + || acl_write_buf(fd, "", 1, timeout) < 0) + { + if (acl_msg_verbose) + acl_msg_warn("%s: write to %s: %s", + myname, service, strerror(errno)); + } + + /* + * Wakeup when the peer disconnects, or when we lose patience. + */ + + if (timeout > 0) + acl_event_enable_read(sp->eventp, sp->stream, timeout + 100, + acl_stream_trigger_event, (void *) sp); + else + acl_event_enable_read(sp->eventp, sp->stream, 0, + acl_stream_trigger_event, (void *) sp); + + return (0); +} +#endif /* SUNOS5 */ +#endif /* ACL_UNIX */ diff --git a/lib_acl/src/master/framework/trigger/trigger.h b/lib_acl/src/master/framework/trigger/trigger.h new file mode 100644 index 000000000..a35aeac7c --- /dev/null +++ b/lib_acl/src/master/framework/trigger/trigger.h @@ -0,0 +1,36 @@ +#ifndef __ACL_TRIGGER_INCLUDED_H__ +#define __ACL_TRIGGER_INCLUDED_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_define.h" +#ifdef ACL_UNIX + +#include "event/acl_events.h" + +#ifdef SUNOS5 +#define ACL_LOCAL_TRIGGER acl_stream_trigger +#else +#define ACL_LOCAL_TRIGGER acl_unix_trigger +#endif + + /* + * External interface. + */ +extern int acl_unix_trigger(ACL_EVENT *, const char *, const char *, int, int); +extern int acl_inet_trigger(ACL_EVENT *, const char *, const char *, int, int); +extern int acl_fifo_trigger(ACL_EVENT *, const char *, const char *, int, int); +#ifdef SUNOS5 +extern int acl_stream_trigger(ACL_EVENT *, const char *, const char *, int, int); +#endif + +#endif /* ACL_UNIX */ + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/src/master/framework/trigger/unix_trigger.c b/lib_acl/src/master/framework/trigger/unix_trigger.c new file mode 100644 index 000000000..1ce9f43d0 --- /dev/null +++ b/lib_acl/src/master/framework/trigger/unix_trigger.c @@ -0,0 +1,127 @@ +/* System library. */ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE +#include "stdlib/acl_define.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#endif + +#ifdef ACL_UNIX + +#include +#include +#include +#include +#include + +/* Utility library. */ + +#include "stdlib/acl_msg.h" +#include "stdlib/acl_iostuff.h" +#include "stdlib/acl_mymalloc.h" +#include "net/acl_connect.h" +#include "event/acl_events.h" + +/* Process manager. */ + +#include "trigger.h" + +#undef __USE_TIMER + +struct ACL_UNIX_TRIGGER { + ACL_VSTREAM *stream; + ACL_EVENT *eventp; + char *service; +}; + +/* acl_unix_trigger_event - disconnect from peer */ + +static void acl_unix_trigger_event(int event, void *context) +{ + const char *myname = "acl_unix_trigger_event"; + struct ACL_UNIX_TRIGGER *up = (struct ACL_UNIX_TRIGGER *) context; + + /* + * Disconnect. + */ + if (event == ACL_EVENT_TIME) + acl_msg_warn("%s: read timeout for service %s", + myname, up->service); + acl_event_disable_readwrite(up->eventp, up->stream); +#ifdef __USE_TIMER + acl_event_cancel_timer(up->eventp, acl_unix_trigger_event, up); +#endif + if (acl_vstream_close(up->stream) < 0) + acl_msg_warn("%s: close %s: %s", + myname, up->service, strerror(errno)); + acl_myfree(up->service); + acl_myfree(up); +} + +/* acl_unix_trigger - wakeup UNIX-domain server */ + +int acl_unix_trigger(ACL_EVENT *eventp, const char *service, + const char *buf, int len, int timeout) +{ + const char *myname = "acl_unix_trigger"; + struct ACL_UNIX_TRIGGER *up; + ACL_SOCKET fd; + + if (acl_msg_verbose > 0) + acl_msg_info("%s: service %s", myname, service); + + /* + * Connect... + */ + if ((fd = acl_unix_connect(service, ACL_BLOCKING, timeout)) < 0) { + if (acl_msg_verbose) + acl_msg_warn("%s: connect to %s: %s", + myname, service, strerror(errno)); + return (-1); + } + acl_close_on_exec(fd, ACL_CLOSE_ON_EXEC); + + /* + * Stash away context. + */ + up = (struct ACL_UNIX_TRIGGER *) acl_mymalloc(sizeof(*up)); + up->service = acl_mystrdup(service); + up->stream = acl_vstream_fdopen(fd, O_RDWR, 4096, + timeout, ACL_VSTREAM_TYPE_LISTEN_UNIX); + up->eventp = eventp; + + /* + * Write the request... + */ + if (acl_vstream_writen(up->stream, buf, len) < 0 + || acl_vstream_writen(up->stream, "", 1) < 0) + { + if (acl_msg_verbose) + acl_msg_warn("%s: write to %s: %s", + myname, service, strerror(errno)); + } + + /* + * Wakeup when the peer disconnects, or when we lose patience. + */ +#ifdef __USE_TIMER + if (timeout > 0) + acl_event_request_timer(up->eventp, acl_unix_trigger_event, + (void *) up, (timeout + 100) * 1000000); + acl_event_enable_read(up->eventp, up->stream, 0, + acl_unix_trigger_event, (void *) up); +#else + if (timeout > 0) + acl_event_enable_read(up->eventp, up->stream, timeout + 100, + acl_unix_trigger_event, (void *) up); + else + acl_event_enable_read(up->eventp, up->stream, 0, + acl_unix_trigger_event, (void *) up); +#endif + + return (0); +} +#endif /* ACL_UNIX */ diff --git a/lib_acl/src/master/master_flow.c b/lib_acl/src/master/master_flow.c new file mode 100644 index 000000000..253887b10 --- /dev/null +++ b/lib_acl/src/master/master_flow.c @@ -0,0 +1,136 @@ +/* System library. */ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#endif + +#ifdef ACL_UNIX + +#include +#include +#include +#include +#include +#include + +/* Utility library. */ + +#include "stdlib/acl_msg.h" +#include "stdlib/acl_iostuff.h" + +/* Global library. */ + +#include "master_proto.h" +#include "master_flow.h" + +#define BUFFER_SIZE 1024 + +int acl_var_master_flow_pipe[2]; + +/* acl_master_flow_init - initialize the flow control channel */ + +void acl_master_flow_init(void) +{ + char *myname = "acl_master_flow_init"; + + if (pipe(acl_var_master_flow_pipe) < 0) + acl_msg_fatal("%s(%d)->%s: pipe: %s", + __FILE__, __LINE__, myname, strerror(errno)); + + acl_non_blocking(acl_var_master_flow_pipe[0], ACL_NON_BLOCKING); + acl_non_blocking(acl_var_master_flow_pipe[1], ACL_NON_BLOCKING); + + acl_close_on_exec(acl_var_master_flow_pipe[0], ACL_CLOSE_ON_EXEC); + acl_close_on_exec(acl_var_master_flow_pipe[1], ACL_CLOSE_ON_EXEC); +} + +/* acl_master_flow_get - read N tokens */ + +int acl_master_flow_get(int len) +{ + char myname[] = "acl_master_flow_get"; + char buf[BUFFER_SIZE]; + struct stat st; + int count; + int n = 0; + + /* + * Sanity check. + */ + if (len <= 0) + acl_msg_panic("%s: bad length %d", myname, len); + + /* + * Silence some wild claims. + */ + if (fstat(ACL_MASTER_FLOW_WRITE, &st) < 0) + acl_msg_fatal("fstat flow pipe write descriptor: %s", strerror(errno)); + + /* + * Read and discard N bytes. XXX AIX read() can return 0 when an open + * pipe is empty. + */ + for (count = len; count > 0; count -= n) { + n = read(ACL_MASTER_FLOW_READ, + buf, + count > BUFFER_SIZE ? BUFFER_SIZE : count); + if (n <= 0) + return (-1); + } + + if (acl_msg_verbose) + acl_msg_info("%s: %d %d", myname, len, len - count); + return (len - count); +} + +/* acl_master_flow_put - put N tokens */ + +int acl_master_flow_put(int len) +{ + char myname[] = "acl_master_flow_put"; + char buf[BUFFER_SIZE]; + int count; + int n = 0; + + /* + * Sanity check. + */ + if (len <= 0) + acl_msg_panic("%s: bad length %d", myname, len); + + /* + * Write or discard N bytes. + */ + memset(buf, 0, len > BUFFER_SIZE ? BUFFER_SIZE : len); + + for (count = len; count > 0; count -= n) { + n = write(ACL_MASTER_FLOW_WRITE, + buf, + count > BUFFER_SIZE ? BUFFER_SIZE : count); + if (n < 0) + return (-1); + } + + if (acl_msg_verbose) + acl_msg_info("%s: %d %d", myname, len, len - count); + return (len - count); +} + +/* acl_master_flow_count - return number of available tokens */ + +int acl_master_flow_count(void) +{ + char myname[] = "acl_master_flow_count"; + int count; + + if ((count = acl_peekfd(ACL_MASTER_FLOW_READ)) < 0) + acl_msg_warn("%s: %s", myname, strerror(errno)); + return (count); +} +#endif /* ACL_UNIX */ diff --git a/lib_acl/src/master/master_flow.h b/lib_acl/src/master/master_flow.h new file mode 100644 index 000000000..612f568d8 --- /dev/null +++ b/lib_acl/src/master/master_flow.h @@ -0,0 +1,25 @@ +#ifndef __ACL_MASTER_FLOW_INCLUDED_H__ +#define __ACL_MASTER_FLOW_INCLUDED_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_define.h" +#ifdef ACL_UNIX + + /* + * Functional interface. + */ +extern void acl_master_flow_init(void); +extern int acl_master_flow_get(int); +extern int acl_master_flow_put(int); +extern int acl_master_flow_count(void); + +#endif /* ACL_UNIX */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/src/master/master_params.c b/lib_acl/src/master/master_params.c new file mode 100644 index 000000000..6ecf10a47 --- /dev/null +++ b/lib_acl/src/master/master_params.c @@ -0,0 +1,398 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include +#include +#include + +#include "stdlib/acl_mymalloc.h" +#include "master/acl_master_conf.h" +#include "stdlib/acl_msg.h" +#include "stdlib/acl_loadcfg.h" +#include "stdlib/acl_xinetd_cfg.h" +#include "stdlib/acl_mystring.h" + +#endif + +#ifdef ACL_UNIX +#include +#include "master_params.h" + +char *acl_var_master_conf_dir; /* must be set value in app */ + +char *acl_var_master_inet_interfaces; +int acl_var_master_proc_limit; +char *acl_var_master_owner_user; +uid_t acl_var_master_owner_uid; +char *acl_var_master_owner; +char *acl_var_master_owner_group; +gid_t acl_var_master_owner_gid; +int acl_var_master_throttle_time; +char *acl_var_master_daemon_dir; +char *acl_var_master_queue_dir; +char *acl_var_master_service_dir; +char *acl_var_master_log_file; +char *acl_var_master_pid_file; +int acl_var_master_buf_size; +int acl_var_master_rw_timeout; +pid_t acl_var_master_pid; +int acl_var_master_in_flow_delay; +int acl_var_master_delay_sec; +int acl_var_master_delay_usec; +int acl_var_master_scan_subdir; + +static ACL_CONFIG_INT_TABLE __conf_int_tab[] = { + { ACL_VAR_MASTER_PROC_LIMIT, ACL_DEF_MASTER_PROC_LIMIT, &acl_var_master_proc_limit, 0, 0 }, + { ACL_VAR_MASTER_THROTTLE_TIME, ACL_DEF_MASTER_THROTTLE_TIME, &acl_var_master_throttle_time, 0, 0 }, + { ACL_VAR_MASTER_BUF_SIZE, ACL_DEF_MASTER_BUF_SIZE, &acl_var_master_buf_size, 0, 0 }, + { ACL_VAR_MASTER_RW_TIMEOUT, ACL_DEF_MASTER_RW_TIMEOUT, &acl_var_master_rw_timeout, 0, 0 }, + { ACL_VAR_MASTER_IN_FLOW_DELAY, ACL_DEF_MASTER_IN_FLOW_DELAY, &acl_var_master_in_flow_delay, 0, 0 }, + { ACL_VAR_MASTER_DELAY_SEC, ACL_DEF_MASTER_DELAY_SEC, &acl_var_master_delay_sec, 0, 0 }, + { ACL_VAR_MASTER_DELAY_USEC, ACL_DEF_MASTER_DELAY_USEC, &acl_var_master_delay_usec, 0, 0 }, + { 0, 0, 0, 0, 0 }, +}; + +static ACL_CONFIG_STR_TABLE __conf_str_tab[] = { + { ACL_VAR_MASTER_INET_INTERFACES, ACL_DEF_MASTER_INET_INTERFACES, &acl_var_master_inet_interfaces }, + { ACL_VAR_MASTER_OWNER_USER, ACL_DEF_MASTER_OWNER_USER, &acl_var_master_owner_user }, + { ACL_VAR_MASTER_OWNER, ACL_DEF_MASTER_OWNER, &acl_var_master_owner }, + { ACL_VAR_MASTER_OWNER_GROUP, ACL_DEF_MASTER_OWNER_GROUP, &acl_var_master_owner_group }, + { ACL_VAR_MASTER_DAEMON_DIR, ACL_DEF_MASTER_DAEMON_DIR, &acl_var_master_daemon_dir }, + { ACL_VAR_MASTER_QUEUE_DIR, ACL_DEF_MASTER_QUEUE_DIR, &acl_var_master_queue_dir }, + { ACL_VAR_MASTER_SERVICE_DIR, ACL_DEF_MASTER_SERVICE_DIR, &acl_var_master_service_dir }, + { ACL_VAR_MASTER_LOG_FILE, ACL_DEF_MASTER_LOG_FILE, &acl_var_master_log_file }, + { ACL_VAR_MASTER_PID_FILE, ACL_DEF_MASTER_PID_FILE, &acl_var_master_pid_file }, + { 0, 0, 0 }, +}; + +static ACL_CONFIG_BOOL_TABLE __conf_bool_tab[] = { + { ACL_VAR_MASTER_SCAN_SUBDIR, ACL_DEF_MASTER_SCAN_SUBDIR, &acl_var_master_scan_subdir }, + { 0, 0, 0 }, +}; +#endif /* ACL_UNIX */ + +/*-------------- global static inition and update functions ----------------*/ + +static void __init_conf_int_vars(ACL_CONFIG_INT_TABLE cit[]) +{ + int i; + + for (i = 0; cit[i].name != 0; i++) + *(cit[i].target) = cit[i].defval; +} + +static void __init_conf_int64_vars(ACL_CONFIG_INT64_TABLE cit[]) +{ + int i; + + for (i = 0; cit[i].name != 0; i++) + *(cit[i].target) = cit[i].defval; +} + +static void __init_conf_str_vars(ACL_CONFIG_STR_TABLE cst[]) +{ + int i; + + for (i = 0; cst[i].name != 0; i++) { + /* + if (*(cst[i].target) != 0) + acl_myfree(*(cst[i].target)); + */ + *(cst[i].target) = acl_mystrdup(cst[i].defval); + } +} + +static void __init_conf_bool_vars(ACL_CONFIG_BOOL_TABLE cbt[]) +{ + int i; + + for (i = 0; cbt[i].name != 0; i++) { + if (cbt[i].defval == 0) + *(cbt[i].target) = 0; + else + *(cbt[i].target) = 1; + } +} + +static void __update_conf_int_vars(ACL_CONFIG_INT_TABLE cit[], + const char *name, + const char *value) +{ + int i; + + for (i = 0; cit[i].name != 0; i++) { + if (strcasecmp(cit[i].name, name) == 0) + *(cit[i].target) = atoi(value); + } +} + +static void __update_conf_int64_vars(ACL_CONFIG_INT64_TABLE cit[], + const char *name, + const char *value) +{ + int i; + + for (i = 0; cit[i].name != 0; i++) { + if (strcasecmp(cit[i].name, name) == 0) + *(cit[i].target) = acl_atoi64(value); + } +} + +static void __update_conf_str_vars(ACL_CONFIG_STR_TABLE cst[], + const char *name, + const char *value) +{ + int i; + + for (i = 0; cst[i].name != 0; i++) { + if (strcasecmp(cst[i].name, name) == 0) { + acl_myfree(*(cst[i].target)); + *(cst[i].target) = acl_mystrdup(value); + } + } +} + +static void __update_conf_bool_vars(ACL_CONFIG_BOOL_TABLE cbt[], + const char *name, + const char *value) +{ + int i, n; + + for (i = 0; cbt[i].name != 0; i++) { + if (strcasecmp(cbt[i].name, name) == 0) { + n = atoi(value); + if (n != 0) + *(cbt[i].target) = 1; + else + *(cbt[i].target) = 0; + } + } +} + +/*--------------------------------------------------------------------------*/ +#ifdef ACL_UNIX + +/* for master process begin */ + +static ACL_CFG_PARSER *__cfg_parser = NULL; + +static void __init_master_vars(void) +{ + __init_conf_int_vars(__conf_int_tab); + __init_conf_str_vars(__conf_str_tab); + __init_conf_bool_vars(__conf_bool_tab); +} + +static void __update_master_conf_vars(ACL_CFG_PARSER *parser) +{ + int i, n; + ACL_CFG_LINE *cfg_line; + + n = acl_cfg_parser_size(parser); + + for (i = 0; i < n; i++) { + cfg_line = acl_cfg_parser_index(parser, i); + if (cfg_line == NULL) + break; + if (cfg_line->ncount < 2) + continue; + + if (acl_msg_verbose) + acl_msg_info("%s = [%s]", + cfg_line->value[0], + cfg_line->value[1]); + + __update_conf_int_vars(__conf_int_tab, + cfg_line->value[0], + cfg_line->value[1]); + } + + for (i = 0; i < n; i++) { + cfg_line = acl_cfg_parser_index(parser, i); + if (cfg_line == NULL) + break; + if (cfg_line->ncount < 2) + continue; + + if (acl_msg_verbose) + acl_msg_info("%s = [%s]", + cfg_line->value[0], + cfg_line->value[1]); + + __update_conf_str_vars(__conf_str_tab, + cfg_line->value[0], + cfg_line->value[1]); + } + + for (i = 0; i < n; i++) { + cfg_line = acl_cfg_parser_index(parser, i); + if (cfg_line == NULL) + break; + if (cfg_line->ncount < 2) + continue; + + if (acl_msg_verbose) + acl_msg_info("%s = [%s]", + cfg_line->value[0], + cfg_line->value[1]); + + __update_conf_bool_vars(__conf_bool_tab, + cfg_line->value[0], + cfg_line->value[1]); + } +} + +void acl_master_params_load(const char *pathname) +{ + char myname[] = "acl_master_params_load"; + + if (pathname == NULL || *pathname == 0) + acl_msg_fatal("%s(%d)->%s: input error", + __FILE__, __LINE__, myname); + if (__cfg_parser != NULL) + acl_cfg_parser_free(__cfg_parser); + + __init_master_vars(); + + __cfg_parser = acl_cfg_parser_load(pathname, " ="); + + if (__cfg_parser == NULL) + acl_msg_fatal("%s(%d)->%s: can't load file = %s, serr = %s", + __FILE__, __LINE__, myname, + pathname, strerror(errno)); + __update_master_conf_vars(__cfg_parser); +} + +#endif /* ACL_UNIX */ + +/* for master process end */ + +/* below configure operations will be called by the app server */ + +static ACL_XINETD_CFG_PARSER *__app_cfg = NULL; +static char *__app_conf_file = NULL; + +void acl_app_conf_load(const char *pathname) +{ + char myname[] = "acl_app_conf_load"; + + if (pathname == NULL || *pathname == 0) + acl_msg_fatal("%s(%d)->%s: input error", + __FILE__, __LINE__, myname); + + if (__app_cfg != NULL) + acl_xinetd_cfg_free(__app_cfg); + + __app_cfg = acl_xinetd_cfg_load(pathname); + + if (__app_cfg == NULL) + acl_msg_fatal("%s(%d)->%s: xinetd_cfg_load null, file=%s, serr=%s", + __FILE__, __LINE__, myname, + pathname, strerror(errno)); + + __app_conf_file = acl_mystrdup(pathname); +} + +void acl_get_app_conf_int_table(ACL_CONFIG_INT_TABLE *table) +{ + char myname[] = "acl_get_app_conf_int_table"; + int i, n, ret; + char *name, *value; + + if (__app_cfg == NULL) + acl_msg_fatal("%s(%d)->%s: app_cfg null, call app_conf_load first", + __FILE__, __LINE__, myname); + + if (table == NULL) + return; + + __init_conf_int_vars(table); + + n = acl_xinetd_cfg_size(__app_cfg); + + for (i = 0; i < n; i++) { + ret = acl_xinetd_cfg_index(__app_cfg, i, &name, &value); + if (ret == 0) + __update_conf_int_vars(table, name, value); + } +} + +void acl_get_app_conf_int64_table(ACL_CONFIG_INT64_TABLE *table) +{ + char myname[] = "acl_get_app_conf_int64_table"; + int i, n, ret; + char *name, *value; + + if (__app_cfg == NULL) + acl_msg_fatal("%s(%d)->%s: app_cfg null, call app_conf_load first", + __FILE__, __LINE__, myname); + + if (table == NULL) + return; + + __init_conf_int64_vars(table); + + n = acl_xinetd_cfg_size(__app_cfg); + + for (i = 0; i < n; i++) { + ret = acl_xinetd_cfg_index(__app_cfg, i, &name, &value); + if (ret == 0) + __update_conf_int64_vars(table, name, value); + } +} + +void acl_get_app_conf_str_table(ACL_CONFIG_STR_TABLE *table) +{ + char myname[] = "acl_get_app_conf_str_table"; + int i, n, ret; + char *name, *value; + + if (__app_cfg == NULL) + acl_msg_fatal("%s(%d)->%s: app_cfg null, call app_conf_load first", + __FILE__, __LINE__, myname); + + if (table == NULL) + return; + + __init_conf_str_vars(table); + + n = acl_xinetd_cfg_size(__app_cfg); + + for (i = 0; i < n; i++) { + ret = acl_xinetd_cfg_index(__app_cfg, i, &name, &value); + if (ret == 0) { + __update_conf_str_vars(table, name, value); + } + } +} + +void acl_get_app_conf_bool_table(ACL_CONFIG_BOOL_TABLE *table) +{ + char myname[] = "acl_get_app_conf_bool_table"; + int i, n, ret; + char *name, *value; + + if (__app_cfg == NULL) + acl_msg_fatal("%s(%d)->%s: app_cfg null, call app_conf_load first", + __FILE__, __LINE__, myname); + + if (table == NULL) + return; + + __init_conf_bool_vars(table); + + n = acl_xinetd_cfg_size(__app_cfg); + + for (i = 0; i < n; i++) { + ret = acl_xinetd_cfg_index(__app_cfg, i, &name, &value); + if (ret == 0) + __update_conf_bool_vars(table, name, value); + } +} + diff --git a/lib_acl/src/master/master_params.h b/lib_acl/src/master/master_params.h new file mode 100644 index 000000000..aff9dcdd4 --- /dev/null +++ b/lib_acl/src/master/master_params.h @@ -0,0 +1,159 @@ +#ifndef __ACL_MASTER_PARAMS_INCLUDE_H__ +#define __ACL_MASTER_PARAMS_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_define.h" + +#ifdef ACL_UNIX + +#include "thread/acl_thread.h" +#include "master/acl_master_type.h" +#include "master/acl_master_conf.h" +#include +#include + +/* be set value in master.c */ + +extern char *acl_var_master_conf_dir; + +/* every service's configure entry is different*/ + +#define ACL_MASTER_CONF_FILE "conf" +#define ACL_DEF_MASTER_PID_DIR "pid" + +#define ACL_VAR_MASTER_SERV_DISABLE "master_disable" +#define ACL_VAR_MASTER_SERV_SERVICE "master_service" +#define ACL_VAR_MASTER_SERV_TYPE "master_type" +#define ACL_VAR_MASTER_SERV_PRIVATE "master_private" +#define ACL_VAR_MASTER_SERV_UNPRIV "master_unpriv" +#define ACL_VAR_MASTER_SERV_CHROOT "master_chroot" +#define ACL_VAR_MASTER_SERV_WAKEUP "master_wakeup" +#define ACL_VAR_MASTER_SERV_LOG "master_log" +#define ACL_VAR_MASTER_SERV_COMMAND "master_command" +#define ACL_VAR_MASTER_SERV_ARGS "master_args" +#define ACL_VAR_MASTER_SERV_ENV "master_env" +#define ACL_VAR_MASTER_NOTIFY_ADDR "master_notify_addr" +#define ACL_VAR_MASTER_NOTIFY_RECIPIENTS "master_notify_recipients" + +#define ACL_DEF_MASTER_SERV_MAX_QLEN "128" +#define ACL_VAR_MASTER_SERV_MAX_QLEN "master_backlog" + +#define ACL_DEF_MASTER_SERV_MAX_PROC "5" +#define ACL_VAR_MASTER_SERV_MAX_PROC "master_maxproc" + +#define ACL_DEF_MASTER_SERV_PREFORK_PROC "0" +#define ACL_VAR_MASTER_SERV_PREFORK_PROC "master_prefork" + +#define ACL_VAR_MASTER_SERV_DEFER_ACCEPT "master_defer_accept" +#define ACL_DEF_MASTER_SERV_DEFER_ACCEPT "0" + + /* + * master's main configure file + * Virtual host support. Default is to listen on all machine interfaces. + */ +#define ACL_VAR_MASTER_INET_INTERFACES "inet_interfaces" /* listen addresses */ +#define ACL_INET_INTERFACES_ALL "all" +#define ACL_INET_INTERFACES_LOCAL "loopback-only" +#define ACL_DEF_MASTER_INET_INTERFACES ACL_INET_INTERFACES_ALL +extern char *acl_var_master_inet_interfaces; + +#define ACL_VAR_MASTER_PROC_LIMIT "default_process_limit" +#define ACL_DEF_MASTER_PROC_LIMIT 100 +extern int acl_var_master_proc_limit; + +#define ACL_VAR_MASTER_OWNER_USER "owner_user" +#define ACL_DEF_MASTER_OWNER_USER "master" +extern char *acl_var_master_owner_user; +extern uid_t acl_var_master_owner_uid; /* zsx test */ + +#define ACL_VAR_MASTER_OWNER "master_owner" +#define ACL_DEF_MASTER_OWNER "master" +extern char *acl_var_master_owner; + +#define ACL_VAR_MASTER_OWNER_GROUP "owner_group" +#define ACL_DEF_MASTER_OWNER_GROUP "master" +extern char *acl_var_master_owner_group; +extern gid_t acl_var_master_owner_gid; /* zsx test */ + +#define ACL_VAR_MASTER_THROTTLE_TIME "service_throttle_time" +#define ACL_DEF_MASTER_THROTTLE_TIME 60 +extern int acl_var_master_throttle_time; + +#define ACL_VAR_MASTER_DAEMON_DIR "daemon_directory" +#define ACL_DEF_MASTER_DAEMON_DIR "/opt/acl/libexec" +extern char *acl_var_master_daemon_dir; + +#define ACL_VAR_MASTER_SERVICE_DIR "service_directory" +#define ACL_DEF_MASTER_SERVICE_DIR "/opt/acl/conf/service" +extern char *acl_var_master_service_dir; + +#define ACL_VAR_MASTER_QUEUE_DIR "queue_directory" +#define ACL_DEF_MASTER_QUEUE_DIR "/opt/acl/var" +extern char *acl_var_master_queue_dir; + +#define ACL_VAR_MASTER_LOG_FILE "log_file" +#define ACL_DEF_MASTER_LOG_FILE "/opt/acl/var/log/master.log" +extern char *acl_var_master_log_file; + +#define ACL_VAR_MASTER_PID_FILE "pid_file" +#define ACL_DEF_MASTER_PID_FILE "/opt/acl/var/pid/master.pid" +extern char *acl_var_master_pid_file; + +#define ACL_VAR_MASTER_BUF_SIZE "buf_size" +#define ACL_DEF_MASTER_BUF_SIZE 81920 +extern int acl_var_master_buf_size; + +#define ACL_VAR_MASTER_RW_TIMEOUT "rw_timeout" +#define ACL_DEF_MASTER_RW_TIMEOUT 30 +extern int acl_var_master_rw_timeout; + +#define ACL_VAR_MASTER_SCAN_SUBDIR "scan_subdir" +#define ACL_DEF_MASTER_SCAN_SUBDIR 0 +extern int acl_var_master_scan_subdir; + +extern pid_t acl_var_master_pid; + +/* + * Inbound mail flow control. This allows for a stiffer coupling between + * receiving mail and sending mail. A sending process produces one token for + * each message that it takes from the incoming queue; a receiving process + * consumes one token for each message that it adds to the incoming queue. + * When no token is available (Postfix receives more mail than it is able to + * deliver) a receiving process pauses for $in_flow_delay seconds so that + * the sending processes get a chance to access the disk. + */ +#define ACL_VAR_MASTER_IN_FLOW_DELAY "in_flow_delay" +#ifdef ACL_PIPES_CANT_FIONREAD +#define ACL_DEF_MASTER_IN_FLOW_DELAY 0 +#else +#define ACL_DEF_MASTER_IN_FLOW_DELAY 1 +#endif +extern int acl_var_master_in_flow_delay; + +#define ACL_VAR_MASTER_DELAY_SEC "event_delay_sec" +#define ACL_DEF_MASTER_DELAY_SEC 1 +extern int acl_var_master_delay_sec; + +#define ACL_VAR_MASTER_DELAY_USEC "event_delay_usec" +#define ACL_DEF_MASTER_DELAY_USEC 5000 +extern int acl_var_master_delay_usec; + +void acl_master_params_load(const char *pathname); + + /* + * acl_master_vars.c + */ +extern acl_pthread_pool_t *acl_var_master_thread_pool; +extern void acl_master_vars_init(int buf_size, int rw_timeout); + +#endif /* ACL_UNIX */ + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/src/master/master_proto.c b/lib_acl/src/master/master_proto.c new file mode 100644 index 000000000..73d528cf3 --- /dev/null +++ b/lib_acl/src/master/master_proto.c @@ -0,0 +1,57 @@ +/* System library. */ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#endif + +#ifdef ACL_UNIX + +#include +#include +#include + +/* Utility library. */ + +#include "stdlib/acl_msg.h" + +/* Global library. */ + +#include "master_proto.h" + +int acl_master_notify(int pid, unsigned generation, int status) +{ + char *myname = "acl_master_notify"; + ACL_MASTER_STATUS stat_buf; + + /* + * We use a simple binary protocol to minimize security risks. + * Since this is local IPC, there are no byte order or word + * length issues. The server treats this information as gossip, + * so sending a bad PID or a bad status code will only have + * amusement value. + */ + stat_buf.pid = pid; + stat_buf.gen = generation; + stat_buf.avail = status; + + if (write(ACL_MASTER_STATUS_FD, (char *) &stat_buf, sizeof(stat_buf)) + != sizeof(stat_buf)) { + if (acl_msg_verbose) + acl_msg_warn("%s(%d)->%s: status %d: %s", + __FILE__, __LINE__, myname, status, strerror(errno)); + return (-1); + } else { + if (acl_msg_verbose) + acl_msg_info("%s(%d)->%s: OK, status %d, pid = %d", + __FILE__, __LINE__, myname, + status, pid); + return (0); + } +} +#endif /* ACL_UNIX */ diff --git a/lib_acl/src/master/master_proto.h b/lib_acl/src/master/master_proto.h new file mode 100644 index 000000000..ff89bcb0d --- /dev/null +++ b/lib_acl/src/master/master_proto.h @@ -0,0 +1,88 @@ +#ifndef __ACL_MASTER_PROTO_INCLUDE_H__ +#define __ACL_MASTER_PROTO_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_define.h" +#ifdef ACL_UNIX + +#include "stdlib/acl_vstream.h" + + /* + * Well-known socket or FIFO directories. The main difference is in file + * access permissions. + */ +#define ACL_MASTER_CLASS_PUBLIC "public" +#define ACL_MASTER_CLASS_PRIVATE "private" + + /* + * Generic triggers. + */ +#define ACL_TRIGGER_REQ_WAKEUP 'W' /* wakeup */ + + /* + * Transport names. The master passes the transport name on the command + * line, and thus the name is part of the master to child protocol. + */ +#define ACL_MASTER_XPORT_NAME_UNIX "unix" /* local IPC */ +#define ACL_MASTER_XPORT_NAME_FIFO "fifo" /* local IPC */ +#define ACL_MASTER_XPORT_NAME_INET "inet" /* non-local IPC */ +#define ACL_MASTER_XPORT_NAME_SOCK "sock" /* inet/unix IPC */ +/*#define ACL_MASTER_XPORT_NAME_PASS "pass" local IPC */ + + /* + * Format of a status message sent by a child process to the process + * manager. Since this is between processes on the same machine we need not + * worry about byte order and word length. + */ +typedef struct ACL_MASTER_STATUS { + int pid; /* process ID */ + unsigned gen; /* child generation number */ + int avail; /* availability */ +} ACL_MASTER_STATUS; + +#define ACL_MASTER_GEN_NAME "GENERATION" /* passed via environment */ + +#define ACL_MASTER_STAT_TAKEN 0 /* this one is occupied */ +#define ACL_MASTER_STAT_AVAIL 1 /* this process is idle */ + +extern int acl_master_notify(int, unsigned, int); /* encapsulate status msg */ + + /* + * File descriptors inherited from the master process. The flow control pipe + * is read by receive processes and is written to by send processes. If + * receive processes get too far ahead they will pause for a brief moment. + */ +#define ACL_MASTER_FLOW_READ 3 +extern ACL_VSTREAM *ACL_MASTER_FLOW_READ_STREAM; + +#define ACL_MASTER_FLOW_WRITE 4 +extern ACL_VSTREAM *ACL_MASTER_FLOW_WRITE_STREAM; + + /* + * File descriptors inherited from the master process. All processes that + * provide a given service share the same status file descriptor, and listen + * on the same service socket(s). The kernel decides what process gets the + * next connection. Usually the number of listening processes is small, so + * one connection will not cause a "thundering herd" effect. When no process + * listens on a given socket, the master process will. ACL_MASTER_LISTEN_FD is + * actually the lowest-numbered descriptor of a sequence of descriptors to + * listen on. + */ +#define ACL_MASTER_STATUS_FD 5 /* shared channel to parent */ +extern ACL_VSTREAM *ACL_MASTER_STAT_STREAM; + +#define ACL_MASTER_LISTEN_FD 6 /* accept connections here */ +extern ACL_VSTREAM *ACL_MASTER_LISTEN_STREAM; + +#endif /* ACL_UNIX */ + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/lib_acl/src/master/master_vars.c b/lib_acl/src/master/master_vars.c new file mode 100644 index 000000000..c5756d4fd --- /dev/null +++ b/lib_acl/src/master/master_vars.c @@ -0,0 +1,69 @@ +/* System library. */ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#endif + +#ifdef ACL_UNIX + +#include + +/* Utility library. */ + +#include "stdlib/acl_msg.h" +#include "stdlib/acl_vstream.h" +#include "thread/acl_thread.h" +#include "event/acl_events.h" /* just for var_ACL_event_fd_busy_ifcheck's use */ + +/* Application-specific. */ +#include "master_proto.h" +#include "master_params.h" + + /* + * Tunable parameters. + */ +ACL_VSTREAM *ACL_MASTER_STAT_STREAM = NULL; +ACL_VSTREAM *ACL_MASTER_FLOW_READ_STREAM = NULL; +ACL_VSTREAM *ACL_MASTER_FLOW_WRITE_STREAM = NULL; +acl_pthread_pool_t *acl_var_master_thread_pool = NULL; + +/* acl_master_vars_init - initialize from global Postfix configuration file */ + +void acl_master_vars_init(int buf_size, int rw_timeout) +{ + const char *myname = "acl_master_vars_init"; + + if (ACL_MASTER_STAT_STREAM != NULL) + acl_vstream_free(ACL_MASTER_STAT_STREAM); + if (ACL_MASTER_FLOW_READ_STREAM != NULL) + acl_vstream_free(ACL_MASTER_FLOW_READ_STREAM); + if (ACL_MASTER_FLOW_WRITE_STREAM != NULL) + acl_vstream_free(ACL_MASTER_FLOW_WRITE_STREAM); + + ACL_MASTER_STAT_STREAM = acl_vstream_fdopen(ACL_MASTER_STATUS_FD, + O_RDWR, + buf_size, + rw_timeout, + ACL_VSTREAM_TYPE_SOCK); + ACL_MASTER_FLOW_READ_STREAM = acl_vstream_fdopen(ACL_MASTER_FLOW_READ, + O_RDONLY, + buf_size, + rw_timeout, + ACL_VSTREAM_TYPE_SOCK); + ACL_MASTER_FLOW_WRITE_STREAM = acl_vstream_fdopen(ACL_MASTER_FLOW_WRITE, + O_WRONLY, + buf_size, + rw_timeout, + ACL_VSTREAM_TYPE_SOCK); + if (acl_var_master_thread_pool == NULL) + acl_var_master_thread_pool = acl_thread_pool_create(100, 60); + if (acl_var_master_thread_pool == NULL) + acl_msg_fatal("%s(%d): create thread pool error", myname, __LINE__); +} +#endif /* ACL_UNIX */ diff --git a/lib_acl/src/master/template/acl_aio_app_main.c b/lib_acl/src/master/template/acl_aio_app_main.c new file mode 100644 index 000000000..aabd67e9c --- /dev/null +++ b/lib_acl/src/master/template/acl_aio_app_main.c @@ -0,0 +1,343 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "lib_acl.h" +#include +#include +#include +#include + +#endif + +#ifdef ACL_UNIX + +#include "master/acl_app_main.h" + +static int __mempool_limit = 0; +static int __mempool_use_mutex = 0; + +static ACL_AIO_RUN_FN __run_fn = NULL; +static ACL_AIO_RUN2_FN __run2_fn = NULL; +static void *__run_ctx = NULL; +static ACL_APP_INIT_FN __app_init_fn = NULL; +static void *__app_init_ctx = NULL; +static ACL_APP_EXIT_FN __app_exit_fn = NULL; +static void *__app_exit_ctx = NULL; +static ACL_APP_OPEN_LOG __app_open_log = NULL; +static ACL_APP_CLOSE_LOG __app_close_log = NULL; +static ACL_APP_PRE_JAIL __app_pre_jail = NULL; +static void *__app_pre_jail_ctx = NULL; + +static char *__default_deny_info = "You are not welcome!\r\n"; +static char *__deny_info; + +static void __service(ACL_SOCKET fd, char *service acl_unused, char **argv acl_unused) +{ + char myname[] = "__service"; + char addr[64], *ptr, ip[64]; + + /* Sanity check. This service takes no command-line arguments. */ + if (argv[0]) + acl_msg_fatal("%s, %s(%d): unexpected command-line argument: %s, service=%s", + __FILE__, myname, __LINE__, argv[0], service ? service : "null"); + + acl_watchdog_pat(); + + if (isatty(fd)) { + acl_msg_error("%s, %s(%d): fd isatty", __FILE__, myname, __LINE__); + return; + } + + if (acl_getpeername(fd, addr, sizeof(addr)) < 0) { + acl_msg_warn("%s, %s(%d): can't get socket's addr", + __FILE__, myname, __LINE__); + acl_socket_close(fd); + return; + } + ACL_SAFE_STRNCPY(ip, addr, sizeof(ip)); + ptr = strchr(ip, ':'); + if (ptr) + *ptr = 0; + + if (!acl_access_permit(ip)) { + acl_msg_warn("%s, %s(%d): addr(%s) be denied", + __FILE__, myname, __LINE__, ip); + acl_socket_write(fd, __deny_info, strlen(__deny_info), 0, 0); + acl_socket_close(fd); + } else if (__run_fn != NULL) { + ACL_VSTREAM *vstream; + ACL_ASTREAM *astream; + + vstream = acl_vstream_fdopen(fd, O_RDWR, acl_var_aio_buf_size, 0, ACL_VSTREAM_TYPE_SOCK); + ACL_SAFE_STRNCPY(vstream->remote_addr, addr, sizeof(vstream->remote_addr)); + acl_getsockname(fd, vstream->local_addr, sizeof(vstream->local_addr)); + astream = acl_aio_open(acl_aio_server_handle(), vstream); + if (__run_fn(astream, __run_ctx) != 0) + acl_aio_iocp_close(astream); + } else if (__run2_fn != NULL) { + if (__run2_fn(fd, __run_ctx) != 0) + acl_socket_close(fd); + } else { + acl_msg_fatal("%s(%d), %s: __run_fn and __run2_fn are null", + __FILE__, __LINE__, myname); + } +} + +static void __pre_accept(char *name acl_unused, char **argv acl_unused) +{ +} + +static void __pre_jail_init(char *name acl_unused, char **argv acl_unused) +{ + /* 是否采用用户自定义的日志函数库 */ + if (__app_open_log) + __app_open_log(); + + if (__app_pre_jail) + __app_pre_jail(__app_pre_jail_ctx); +} + +static void __post_jail_init(char *name acl_unused, char **argv acl_unused) +{ + + if (acl_var_aio_access_allow != NULL) + acl_access_add(acl_var_aio_access_allow, ", \t", ":"); + + if (__app_init_fn != NULL) + __app_init_fn(__app_init_ctx); + + if (__mempool_limit > 0) { + acl_msg_info("use mempool, size limit is %d, %s mutex", + __mempool_limit, __mempool_use_mutex ? "use" : "no"); + } + + /* TODO: you can add some init functions here */ +} + +static void __app_on_exit(char *service acl_unused, char **argv acl_unused) +{ + if (__app_exit_fn) + __app_exit_fn(__app_exit_ctx); + if (__app_close_log) + __app_close_log(); +} + +static void app_main_init(void) +{ + char *ptr, *pname; + ACL_ARGV *env_argv; + int i; + + __deny_info = __default_deny_info; + ptr = getenv("SERVICE_ENV"); + if (ptr == NULL || *ptr == 0) + return; + + env_argv = acl_argv_split(ptr, ",\t "); + if (env_argv == NULL) + return; + if (env_argv->argc == 0) { + acl_argv_free(env_argv); + return; + } + + for (i = 0; i argc; i++) { + pname = acl_argv_index(env_argv, i); + ptr = strchr(pname, ':'); + if (ptr == NULL) + continue; + *ptr++ = 0; + if (ptr == 0) + continue; + if (strcasecmp(pname, "mempool_limit") == 0) { + __mempool_limit = atoi(ptr); + } else if (strcasecmp(pname, "mempool_use_mutex") == 0) { + if (strcasecmp(ptr, "true") == 0) + __mempool_use_mutex = 1; + } + } + + acl_argv_free(env_argv); + + if (__mempool_limit > 0) + acl_mempool_open(__mempool_limit, __mempool_use_mutex); +} + +static ACL_CONFIG_BOOL_TABLE null_conf_bool_tab[] = { + /* TODO: you can add configure variables of int type here */ + { 0, 0, 0 }, +}; + +static ACL_CONFIG_INT_TABLE null_conf_int_tab[] = { + /* TODO: you can add configure variables of int type here */ + { 0, 0, 0, 0, 0 }, +}; + +static ACL_CONFIG_INT64_TABLE null_conf_int64_tab[] = { + /* TODO: you can add configure variables of acl_int64 type here */ + { 0, 0, 0, 0, 0 }, +}; + +static ACL_CONFIG_STR_TABLE null_conf_str_tab[] = { + /* TODO: you can add configure variables of int type here */ + { 0, 0, 0 }, +}; + +void acl_aio_app_main(int argc, char *argv[], ACL_AIO_RUN_FN run_fn, void *run_ctx, int name, ...) +{ + const char *myname = "acl_aio_app_main"; + va_list ap; + ACL_CONFIG_BOOL_TABLE *bool_tab = null_conf_bool_tab; + ACL_CONFIG_INT_TABLE *int_tab = null_conf_int_tab; + ACL_CONFIG_INT64_TABLE *int64_tab = null_conf_int64_tab; + ACL_CONFIG_STR_TABLE *str_tab = null_conf_str_tab; + + app_main_init(); + /* 提前进行模板初始化,以使日志尽早地打开 */ + acl_master_log_open(argv[0]); + + if (run_fn == NULL) + acl_msg_fatal("%s: run_fn null", myname); + + __run_fn = run_fn; + __run_ctx = run_ctx; + + va_start(ap, name); + + for (; name != ACL_APP_CTL_END; name = va_arg(ap, int)) { + switch (name) { + case ACL_APP_CTL_INIT_FN: + __app_init_fn = va_arg(ap, ACL_APP_INIT_FN); + break; + case ACL_APP_CTL_INIT_CTX: + __app_init_ctx = va_arg(ap, void *); + break; + case ACL_APP_CTL_EXIT_FN: + __app_exit_fn = va_arg(ap, ACL_APP_EXIT_FN); + break; + case ACL_APP_CTL_EXIT_CTX: + __app_exit_ctx = va_arg(ap, void *); + break; + + case ACL_APP_CTL_OPEN_LOG: + __app_open_log = va_arg(ap, ACL_APP_OPEN_LOG); + break; + case ACL_APP_CTL_CLOSE_LOG: + __app_close_log = va_arg(ap, ACL_APP_CLOSE_LOG); + break; + case ACL_APP_CTL_CFG_BOOL: + bool_tab = va_arg(ap, ACL_CONFIG_BOOL_TABLE *); + break; + case ACL_APP_CTL_CFG_INT: + int_tab = va_arg(ap, ACL_CONFIG_INT_TABLE *); + break; + case ACL_APP_CTL_CFG_INT64: + int64_tab = va_arg(ap, ACL_CONFIG_INT64_TABLE *); + break; + case ACL_APP_CTL_CFG_STR: + str_tab = va_arg(ap, ACL_CONFIG_STR_TABLE *); + break; + case ACL_APP_CTL_DENY_INFO: + __deny_info = acl_mystrdup(va_arg(ap, const char*)); + break; + default: + acl_msg_info("%s: bad name(%d)", myname, name); + } + } + + va_end(ap); + + acl_aio_server_main(argc, argv, __service, + ACL_MASTER_SERVER_BOOL_TABLE, bool_tab, + ACL_MASTER_SERVER_INT_TABLE, int_tab, + ACL_MASTER_SERVER_INT64_TABLE, int64_tab, + ACL_MASTER_SERVER_STR_TABLE, str_tab, + ACL_MASTER_SERVER_PRE_INIT, __pre_jail_init, + ACL_MASTER_SERVER_PRE_ACCEPT, __pre_accept, + ACL_MASTER_SERVER_POST_INIT, __post_jail_init, + ACL_MASTER_SERVER_EXIT, __app_on_exit, + 0); +} + +void acl_aio_app2_main(int argc, char *argv[], ACL_AIO_RUN2_FN run2_fn, void *run_ctx, int name, ...) +{ + const char *myname = "acl_aio_app2_main"; + va_list ap; + ACL_CONFIG_BOOL_TABLE *bool_tab = null_conf_bool_tab; + ACL_CONFIG_INT_TABLE *int_tab = null_conf_int_tab; + ACL_CONFIG_INT64_TABLE *int64_tab = null_conf_int64_tab; + ACL_CONFIG_STR_TABLE *str_tab = null_conf_str_tab; + + app_main_init(); + /* 提前进行模板初始化,以使日志尽早地打开 */ + acl_master_log_open(argv[0]); + + if (run2_fn == NULL) + acl_msg_fatal("%s: run_fn null", myname); + + __run2_fn = run2_fn; + __run_ctx = run_ctx; + + va_start(ap, name); + + for (; name != ACL_APP_CTL_END; name = va_arg(ap, int)) { + switch (name) { + case ACL_APP_CTL_INIT_FN: + __app_init_fn = va_arg(ap, ACL_APP_INIT_FN); + break; + case ACL_APP_CTL_INIT_CTX: + __app_init_ctx = va_arg(ap, void *); + break; + case ACL_APP_CTL_EXIT_FN: + __app_exit_fn = va_arg(ap, ACL_APP_EXIT_FN); + break; + case ACL_APP_CTL_EXIT_CTX: + __app_exit_ctx = va_arg(ap, void *); + break; + + case ACL_APP_CTL_OPEN_LOG: + __app_open_log = va_arg(ap, ACL_APP_OPEN_LOG); + break; + case ACL_APP_CTL_CLOSE_LOG: + __app_close_log = va_arg(ap, ACL_APP_CLOSE_LOG); + break; + case ACL_APP_CTL_PRE_JAIL_CTX: + __app_pre_jail_ctx = va_arg(ap, void*); + break; + case ACL_APP_CTL_PRE_JAIL: + __app_pre_jail = va_arg(ap, ACL_APP_PRE_JAIL); + break; + case ACL_APP_CTL_CFG_BOOL: + bool_tab = va_arg(ap, ACL_CONFIG_BOOL_TABLE *); + break; + case ACL_APP_CTL_CFG_INT: + int_tab = va_arg(ap, ACL_CONFIG_INT_TABLE *); + break; + case ACL_APP_CTL_CFG_INT64: + int64_tab = va_arg(ap, ACL_CONFIG_INT64_TABLE *); + break; + case ACL_APP_CTL_CFG_STR: + str_tab = va_arg(ap, ACL_CONFIG_STR_TABLE *); + break; + case ACL_APP_CTL_DENY_INFO: + __deny_info = acl_mystrdup(va_arg(ap, const char*)); + break; + default: + acl_msg_info("%s: bad name(%d)", myname, name); + } + } + + va_end(ap); + + acl_aio_server_main(argc, argv, __service, + ACL_MASTER_SERVER_BOOL_TABLE, bool_tab, + ACL_MASTER_SERVER_INT_TABLE, int_tab, + ACL_MASTER_SERVER_INT64_TABLE, int64_tab, + ACL_MASTER_SERVER_STR_TABLE, str_tab, + ACL_MASTER_SERVER_PRE_INIT, __pre_jail_init, + ACL_MASTER_SERVER_PRE_ACCEPT, __pre_accept, + ACL_MASTER_SERVER_POST_INIT, __post_jail_init, + ACL_MASTER_SERVER_EXIT, __app_on_exit, + 0); +} +#endif diff --git a/lib_acl/src/master/template/acl_aio_server.c b/lib_acl/src/master/template/acl_aio_server.c new file mode 100644 index 000000000..4d144454a --- /dev/null +++ b/lib_acl/src/master/template/acl_aio_server.c @@ -0,0 +1,1268 @@ +/* System library. */ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#endif + +#ifdef ACL_UNIX + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef STRCASECMP_IN_STRINGS_H +#include +#endif +#include +#include + +/* Utility library. */ + +#include "init/acl_init.h" +#include "stdlib/acl_msg.h" +#include "stdlib/unix/acl_chroot_uid.h" +#include "stdlib/acl_vstring.h" +#include "stdlib/acl_vstream.h" +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_iostuff.h" +#include "stdlib/acl_stringops.h" +#include "stdlib/acl_myflock.h" +#include "stdlib/unix/acl_watchdog.h" +#include "stdlib/acl_split_at.h" +#include "net/acl_listen.h" +#include "net/acl_tcp_ctl.h" +#include "net/acl_sane_socket.h" +#include "event/acl_events.h" +#include "aio/acl_aio.h" + +/* Global library. */ + +#include "../master_flow.h" + +/* Process manager. */ +#include "../master_proto.h" +#include "../master_params.h" + +/* Application-specific */ +#include "master/acl_aio_params.h" +#include "master/acl_server_api.h" +#include "template.h" + +int acl_var_aio_pid; + +int acl_var_aio_buf_size; +int acl_var_aio_rw_timeout; +int acl_var_aio_in_flow_delay; +int acl_var_aio_max_threads; +int acl_var_aio_thread_idle_limit; +int acl_var_aio_idle_limit; +int acl_var_aio_delay_sec; +int acl_var_aio_delay_usec; +int acl_var_aio_daemon_timeout; +int acl_var_aio_use_limit; +int acl_var_aio_master_maxproc; +int acl_var_aio_max_accept; +int acl_var_aio_min_notify; +int acl_var_aio_quick_abort; +int acl_var_aio_enable_core; +int acl_var_aio_accept_timer; + +static ACL_CONFIG_INT_TABLE __conf_int_tab[] = { + { ACL_VAR_AIO_BUF_SIZE, ACL_DEF_AIO_BUF_SIZE, &acl_var_aio_buf_size, 0, 0 }, + { ACL_VAR_AIO_RW_TIMEOUT, ACL_DEF_AIO_RW_TIMEOUT, &acl_var_aio_rw_timeout, 0, 0 }, + { ACL_VAR_AIO_IN_FLOW_DELAY, ACL_DEF_AIO_IN_FLOW_DELAY, &acl_var_aio_in_flow_delay, 0, 0 }, + { ACL_VAR_AIO_MAX_THREADS, ACL_DEF_AIO_MAX_THREADS, &acl_var_aio_max_threads, 0, 0}, + { ACL_VAR_AIO_THREAD_IDLE_LIMIT, ACL_DEF_AIO_THREAD_IDLE_LIMIT, &acl_var_aio_thread_idle_limit, 0, 0 }, + { ACL_VAR_AIO_IDLE_LIMIT, ACL_DEF_AIO_IDLE_LIMIT, &acl_var_aio_idle_limit, 0, 0 }, + { ACL_VAR_AIO_DELAY_SEC, ACL_DEF_AIO_DELAY_SEC, &acl_var_aio_delay_sec, 0, 0 }, + { ACL_VAR_AIO_DELAY_USEC, ACL_DEF_AIO_DELAY_USEC, &acl_var_aio_delay_usec, 0, 0 }, + { ACL_VAR_AIO_DAEMON_TIMEOUT, ACL_DEF_AIO_DAEMON_TIMEOUT, &acl_var_aio_daemon_timeout, 0, 0 }, + { ACL_VAR_AIO_USE_LIMIT, ACL_DEF_AIO_USE_LIMIT, &acl_var_aio_use_limit, 0, 0 }, + { ACL_VAR_AIO_MASTER_MAXPROC, ACL_DEF_AIO_MASTER_MAXPROC, &acl_var_aio_master_maxproc, 0, 0 }, + { ACL_VAR_AIO_MAX_ACCEPT, ACL_DEF_AIO_MAX_ACCEPT, &acl_var_aio_max_accept, 0, 0 }, + { ACL_VAR_AIO_MIN_NOTIFY, ACL_DEF_AIO_MIN_NOTIFY, &acl_var_aio_min_notify, 0, 0 }, + { ACL_VAR_AIO_QUICK_ABORT, ACL_DEF_AIO_QUICK_ABORT, &acl_var_aio_quick_abort, 0, 0 }, + { ACL_VAR_AIO_ENABLE_CORE, ACL_DEF_AIO_ENABLE_CORE, &acl_var_aio_enable_core, 0, 0 }, + { ACL_VAR_AIO_ACCEPT_TIMER, ACL_DEF_AIO_ACCEPT_TIMER, &acl_var_aio_accept_timer, 0, 0 }, + { 0, 0, 0, 0, 0 }, +}; + +char *acl_var_aio_procname; +char *acl_var_aio_log_file; + +char *acl_var_aio_queue_dir; +char *acl_var_aio_owner; +char *acl_var_aio_event_mode; +char *acl_var_aio_pid_dir; +char *acl_var_aio_access_allow; +char *acl_var_aio_accept_alone; + +static ACL_CONFIG_STR_TABLE __conf_str_tab[] = { + { ACL_VAR_AIO_QUEUE_DIR, ACL_DEF_AIO_QUEUE_DIR, &acl_var_aio_queue_dir }, + { ACL_VAR_AIO_OWNER, ACL_DEF_AIO_OWNER, &acl_var_aio_owner }, + { ACL_VAR_AIO_PID_DIR, ACL_DEF_AIO_PID_DIR, &acl_var_aio_pid_dir }, + { ACL_VAR_AIO_ACCESS_ALLOW, ACL_DEF_AIO_ACCESS_ALLOW, &acl_var_aio_access_allow }, + { ACL_VAR_AIO_EVENT_MODE, ACL_DEF_AIO_EVENT_MODE, &acl_var_aio_event_mode }, + { ACL_VAR_AIO_ACCEPT_ALONE, ACL_DEF_AIO_ACCEPT_ALONE, &acl_var_aio_accept_alone }, + { 0, 0, 0 }, +}; + + /* + * Global state. + */ +static int __event_mode; +static int __client_count = 0; +static int __use_count = 0; +static int __use_limit_delay = 1; +static int __socket_count = 1; +static int __listen_disabled = 0; + +static ACL_AIO *__h_aio = NULL; +static ACL_ASTREAM **__listen_astreams; + +static time_t __last_closing_time = 0; +static pthread_mutex_t __closing_time_mutex; +static pthread_mutex_t __counter_mutex; + +static void (*aio_server_wakeup) (ACL_AIO *, int); +static void (*aio_server_service) (ACL_SOCKET, char *, char **); +static char *aio_server_name; +static char **aio_server_argv; +static void (*aio_server_accept) (ACL_ASTREAM *, void *); +static void (*aio_server_onexit) (char *, char **); +static void (*aio_server_pre_accept) (char *, char **); +static ACL_VSTREAM *aio_server_lock; +static int aio_server_in_flow_delay; +static unsigned aio_server_generation; +static void (*aio_server_pre_disconn) (ACL_VSTREAM *, char *, char **); +static int (*aio_server_on_accept)(ACL_VSTREAM *); + +/* add by zsx for rw timeout, 2005.9.25*/ +static void (*aio_server_rw_timer) (ACL_VSTREAM *); + +static ACL_ASTREAM *ACL_MASTER_STAT_ASTREAM = NULL; + +/* forward declare */ +static void aio_server_timeout(int eventd, void *context); + +static void aio_init(void) +{ + pthread_mutex_init(&__closing_time_mutex, NULL); + pthread_mutex_init(&__counter_mutex, NULL); + __last_closing_time = time(NULL); + + __use_limit_delay = acl_var_aio_delay_sec > 1 ? + acl_var_aio_delay_sec : 1; +} + +static void lock_closing_time(void) +{ + pthread_mutex_lock(&__closing_time_mutex); +} + +static void unlock_closing_time(void) +{ + pthread_mutex_unlock(&__closing_time_mutex); +} + +static void lock_counter(void) +{ + pthread_mutex_lock(&__counter_mutex); +} + +static void unlock_counter(void) +{ + pthread_mutex_unlock(&__counter_mutex); +} + +/* +static void update_closing_time(void) +{ + if (acl_var_aio_max_threads > 0) + lock_closing_time(); + __last_closing_time = time(NULL); + if (acl_var_aio_max_threads > 0) + unlock_closing_time(); +} +*/ + +static time_t last_closing_time(void) +{ + time_t last; + + if (acl_var_aio_max_threads > 0) + lock_closing_time(); + last = __last_closing_time; + if (acl_var_aio_max_threads > 0) + unlock_closing_time(); + + return (last); +} + +static void increase_client_counter(void) +{ + if (acl_var_aio_max_threads > 0) + lock_counter(); + __client_count++; + if (acl_var_aio_max_threads > 0) + unlock_counter(); +} + +/* +static void decrease_client_counter(void) +{ + if (acl_var_aio_max_threads > 0) + lock_counter(); + __client_count--; + if (acl_var_aio_max_threads > 0) + unlock_counter(); +} +*/ + +static int get_client_count(void) +{ + int n; + + if (acl_var_aio_max_threads > 0) + lock_counter(); + n = __client_count; + if (acl_var_aio_max_threads > 0) + unlock_counter(); + + return (n); +} + +ACL_EVENT *acl_aio_server_event() +{ + return (acl_aio_event(__h_aio)); +} + +ACL_AIO* acl_aio_server_handle() +{ + return (__h_aio); +} + +void acl_aio_server_request_timer(ACL_AIO_TIMER_FN timer_fn, void *arg, int delay) +{ + const char *myname = "acl_aio_server_request_timer"; + + acl_aio_request_timer(__h_aio, timer_fn, arg, (acl_int64) delay * 1000000, 0); + if (__h_aio == NULL) + acl_msg_fatal("%s(%d)->%s: aio has not been inited", + __FILE__, __LINE__, myname); +} + +void acl_aio_server_cancel_timer(ACL_AIO_TIMER_FN timer_fn, void *arg) +{ + const char *myname = "acl_aio_server_cancel_timer"; + + if (__h_aio == NULL) + acl_msg_fatal("%s(%d)->%s: aio has not been inited", + __FILE__, __LINE__, myname); + acl_aio_cancel_timer(__h_aio, timer_fn, arg); +} + +static void disable_listen(void) +{ + int i; + + if (__listen_astreams == NULL) + return; + for (i = 0; __listen_astreams[i] != NULL; i++) { + acl_aio_disable_read(__listen_astreams[i]); + acl_aio_iocp_close(__listen_astreams[i]); + __listen_astreams[i] = NULL; + } + + acl_myfree(__listen_astreams); + __listen_astreams = NULL; +} + +/* aio_server_exit - normal termination */ + +static void aio_server_exit(void) +{ + if (aio_server_onexit) + aio_server_onexit(aio_server_name, aio_server_argv); + exit(0); +} + +/* aio_server_abort - terminate after abnormal master exit */ + +static void aio_server_abort(ACL_ASTREAM *astream, void *context acl_unused) +{ + const char *myname = "aio_server_abort"; + int n; + ACL_AIO *aio = acl_aio_handle(astream); + + if (aio != __h_aio) + acl_msg_fatal("%s(%d): aio invalid", myname, __LINE__); + + if (!__listen_disabled) + __listen_disabled = 1; + + if (acl_var_aio_quick_abort == 0) { + n = get_client_count(); + if (n > 0) { + /* set idle timeout to 1 second */ + acl_var_aio_idle_limit = 1; + acl_aio_request_timer(__h_aio, aio_server_timeout, (void*) aio, + (acl_int64) acl_var_aio_idle_limit * 1000000, 0); + return; + } + } + + if (acl_msg_verbose) + acl_msg_info("master disconnect -- exiting"); + aio_server_exit(); +} + +static void aio_server_read_abort(ACL_ASTREAM *astream, void *context, + const char *data acl_unused, int dlen acl_unused) +{ + aio_server_abort(astream, context); +} + +/* aio_server_timeout - idle time exceeded */ + +static void aio_server_timeout(int event acl_unused, void *context) +{ + ACL_AIO *aio = (ACL_AIO *) context; + time_t last, inter; + int n; + + n = get_client_count(); + + /* if there are some fds not be closed, the timer should be reset again */ + if (n > 0 && acl_var_aio_idle_limit > 0) { + acl_aio_request_timer(aio, aio_server_timeout, (void *) aio, + (acl_int64) acl_var_aio_idle_limit * 1000000, 0); + return; + } + + last = last_closing_time(); + inter = time(NULL) - last; + + if (inter >= 0 && inter < acl_var_aio_idle_limit) { + acl_aio_request_timer(aio, aio_server_timeout, (void *) aio, + (acl_int64) (acl_var_aio_idle_limit - inter) * 1000000, 0); + return; + } + + if (acl_msg_verbose) + acl_msg_info("idle timeout -- exiting"); + + aio_server_exit(); +} + +static void aio_server_use_timer(int event acl_unused, void *context) +{ + ACL_AIO *aio = (ACL_AIO *) context; + int n; + + n = get_client_count(); + + if (n > 0 || __use_count < acl_var_aio_use_limit) { + acl_aio_request_timer(aio, aio_server_use_timer, + (void *) aio, (acl_int64) __use_limit_delay * 1000000, 0); + return; + } + + if (acl_msg_verbose) + acl_msg_info("use limit -- exiting"); + + aio_server_exit(); +} + +int acl_aio_server_read(ACL_ASTREAM *astream, int timeout, + ACL_AIO_READ_FN notify_fn, void *context) +{ + const char *myname = "acl_aio_server_read"; + + if (astream == NULL || notify_fn == NULL) + acl_msg_fatal("%s(%d): input error", myname, __LINE__); + + acl_aio_ctl(astream, ACL_AIO_CTL_READ_HOOK_ADD, notify_fn, context, + ACL_AIO_CTL_TIMEOUT, timeout, ACL_AIO_CTL_END); + acl_aio_read(astream); + return (0); +} + +int acl_aio_server_readn(ACL_ASTREAM *astream, int count, int timeout, + ACL_AIO_READ_FN notify_fn, void *context) +{ + const char *myname = "acl_aio_server_readn"; + + if (astream == NULL || notify_fn == NULL || count <= 0) + acl_msg_fatal("%s(%d): input error", myname, __LINE__); + + acl_aio_ctl(astream, ACL_AIO_CTL_READ_HOOK_ADD, notify_fn, context, + ACL_AIO_CTL_TIMEOUT, timeout, ACL_AIO_CTL_END); + acl_aio_readn(astream, count); + return (0); +} + +int acl_aio_server_gets(ACL_ASTREAM *astream, int timeout, + ACL_AIO_READ_FN notify_fn, void *context) +{ + const char *myname = "acl_aio_server_gets"; + + if (astream == NULL || notify_fn == NULL) + acl_msg_fatal("%s(%d): input invalid", myname, __LINE__); + + acl_aio_ctl(astream, ACL_AIO_CTL_READ_HOOK_ADD, notify_fn, context, + ACL_AIO_CTL_TIMEOUT, timeout, ACL_AIO_CTL_END); + acl_aio_gets(astream); + return (0); +} + +int acl_aio_server_gets_nonl(ACL_ASTREAM *astream, int timeout, + ACL_AIO_READ_FN notify_fn, void *context) +{ + const char *myname = "acl_aio_server_gets_nonl"; + + if (astream == NULL || notify_fn == NULL) + acl_msg_fatal("%s(%d): input invalid", myname, __LINE__); + + acl_aio_ctl(astream, ACL_AIO_CTL_READ_HOOK_ADD, notify_fn, context, + ACL_AIO_CTL_TIMEOUT, timeout, ACL_AIO_CTL_END); + acl_aio_gets_nonl(astream); + return (0); +} + +int acl_aio_server_writen(ACL_ASTREAM *astream, ACL_AIO_WRITE_FN notify_fn, + void *context, const char *data, int dlen) +{ + const char *myname = "acl_aio_server_writen"; + + if (astream == NULL || notify_fn == NULL || data == NULL || dlen <= 0) + acl_msg_fatal("%s(%d): input invalid", myname, __LINE__); + + acl_aio_ctl(astream, ACL_AIO_CTL_WRITE_HOOK_ADD, notify_fn, context, + ACL_AIO_CTL_END); + acl_aio_writen(astream, data, dlen); + return (0); +} + +int acl_aio_server_vfprintf(ACL_ASTREAM *astream, ACL_AIO_WRITE_FN notify_fn, + void *context, const char *fmt, va_list ap) +{ + const char *myname = "acl_aio_server_vfprintf"; + + if (astream == NULL || notify_fn == NULL || fmt == NULL) + acl_msg_fatal("%s(%d): input invalid", myname, __LINE__); + + acl_aio_ctl(astream, ACL_AIO_CTL_WRITE_HOOK_ADD, notify_fn, context, + ACL_AIO_CTL_END); + acl_aio_vfprintf(astream, fmt, ap); + return (0); +} + +int acl_aio_server_fprintf(ACL_ASTREAM *astream, ACL_AIO_WRITE_FN notify_fn, + void *context, const char *fmt, ...) +{ + const char *myname = "acl_aio_server_fprintf"; + va_list ap; + int ret; + + if (astream == NULL || notify_fn == NULL || fmt == NULL) + acl_msg_fatal("%s(%d): input invalid", myname, __LINE__); + + va_start(ap, fmt); + ret = acl_aio_server_vfprintf(astream, notify_fn, context, fmt, ap); + va_end(ap); + + return (ret); +} + +int acl_aio_server_connect(const char *saddr, int timeout, + ACL_AIO_CONNECT_FN connect_fn, void *context) +{ + const char *myname = "acl_aio_server_connect"; + ACL_ASTREAM *astream; + + if (saddr == NULL || connect_fn == NULL) + acl_msg_fatal("%s(%d): input invalid", myname, __LINE__); + + astream = acl_aio_connect(__h_aio, saddr, timeout); + if (astream == NULL) + return (-1); + acl_aio_ctl(astream, ACL_AIO_CTL_CONNECT_HOOK_ADD, connect_fn, context, + ACL_AIO_CTL_TIMEOUT, timeout, ACL_AIO_CTL_END); + return (0); +} + +/* +static void decrease_counter_callback(ACL_VSTREAM *stream acl_unused, void *arg acl_unused) +{ + update_closing_time(); + decrease_client_counter(); +} +*/ + +/* server_wakeup - wake up application in main thread */ + +static void server_wakeup(ACL_AIO *aio acl_unused, int fd) +{ + if (acl_msg_verbose) + acl_msg_info("connection established fd %d", fd); + + acl_non_blocking(fd, ACL_NON_BLOCKING); + acl_close_on_exec(fd, ACL_CLOSE_ON_EXEC); + + increase_client_counter(); + + __use_count++; + aio_server_service(fd, aio_server_name, aio_server_argv); +} + +static void dummy(void *ptr acl_unused) +{ + +} + +static void free_tls(void *ptr) +{ + acl_myfree(ptr); +} + +static void *__tls = NULL; +static void main_free_tls(void) +{ + if (__tls) { + acl_myfree(__tls); + __tls = NULL; + } +} + +static acl_pthread_key_t once_key; +static void once_init(void) +{ + if ((unsigned long) acl_pthread_self() == acl_main_thread_self()) { + acl_pthread_key_create(&once_key, dummy); + atexit(main_free_tls); + } else + acl_pthread_key_create(&once_key, free_tls); +} + +static acl_pthread_once_t once_control = ACL_PTHREAD_ONCE_INIT; +static void *tls_alloc(size_t len) +{ + void *ptr; + + (void) acl_pthread_once(&once_control, once_init); + ptr = acl_pthread_getspecific(once_key); + if (ptr == NULL) { + ptr = acl_mymalloc(len); + acl_pthread_setspecific(once_key, ptr); + if ((unsigned long) acl_pthread_self() == acl_main_thread_self()) + __tls = ptr; + } + return ptr; +} + +/* restart listening */ + +static void restart_listen(int event acl_unused, void *context) +{ + ACL_ASTREAM *stream = (ACL_ASTREAM*) context; + acl_msg_info("restart listen now!"); + acl_aio_listen(stream); +} + +#ifdef MASTER_XPORT_NAME_PASS + +/* aio_server_accept_pass - accept descriptor */ + +static void aio_server_accept_pass(ACL_ASTREAM *astream, void *context) +{ + const char *myname = "aio_server_accept_pass"; + ACL_VSTREAM *vstream = acl_aio_vstream(astream); + int listen_fd = acl_vstream_fileno(vstream); + ACL_AIO *aio = (ACL_AIO *) context; + int time_left = -1; + int fd; + int *fds; + int i, j; + int delay_listen = 0; + + /* + * Be prepared for accept() to fail because some other process already + * got the connection (the number of processes competing for clients + * is kept small, so this is not a "thundering herd" problem). If the + * accept() succeeds, be sure to disable non-blocking I/O, in order to + * minimize confusion. + */ + if (acl_var_aio_idle_limit > 0) + time_left = (int) ((acl_aio_cancel_timer(aio, aio_server_timeout, + (void *) aio) + 999999) / 1000000); + else + time_left = acl_var_aio_idle_limit; + + if (aio_server_pre_accept) + aio_server_pre_accept(aio_server_name, aio_server_argv); + + fds = (int*) tls_alloc(sizeof(int) * acl_var_aio_max_accept); + + for (i = 0; i < acl_var_aio_max_accept; i++) { + fd = PASS_ACCEPT(listen_fd); + if (fd >= 0) + fds[i] = fd; + else if (errno == EMFILE) { + delay_listen = 1; + acl_msg_warn("accept connection: %s", acl_last_serror()); + break; + } else if (errno == EAGAIN || errno == EINTR) + break; + else + acl_msg_fatal("%s: accept connection: %s", + myname, strerror(errno)); + } + + if (acl_var_aio_master_maxproc > 1 && i >= acl_var_aio_min_notify + && acl_master_notify(acl_var_aio_pid, aio_server_generation, + ACL_MASTER_STAT_TAKEN) < 0) + { + aio_server_abort(astream, NULL); + } + + for (j = 0; j < i; j++) + aio_server_wakeup(aio, fds[j]); + + if (acl_var_aio_master_maxproc > 1 && i >= acl_var_aio_min_notify + && acl_master_notify(acl_var_aio_pid, aio_server_generation, + ACL_MASTER_STAT_AVAIL) < 0) + { + aio_server_abort(astream, NULL); + } + + if (aio_server_lock != 0 + && acl_myflock(ACL_VSTREAM_FILE(aio_server_lock), + ACL_INTERNAL_LOCK, ACL_MYFLOCK_OP_NONE) < 0) + { + acl_msg_fatal("%s: select unlock: %s", myname, strerror(errno)); + } + + if (delay_listen) { + acl_aio_disable_read(astream); + acl_aio_request_timer(aio, restart_listen, astream, 2000000, 0); + } + + if (time_left > 0) + acl_aio_request_timer(aio, aio_server_timeout, (void *) aio, + (acl_int64) time_left * 1000000, 0); +} + +#endif + +/* aio_server_accept_sock2 - accept client connection request */ + +static int aio_server_accept_sock2(ACL_ASTREAM *astream, ACL_AIO *aio) +{ + const char *myname = "aio_serer_accept_sock2"; + ACL_VSTREAM *vstream = acl_aio_vstream(astream); + int listen_fd = ACL_VSTREAM_SOCK(vstream); + int fd, *fds, i, j, delay_listen = 0, sock_type; + + if (aio_server_pre_accept) + aio_server_pre_accept(aio_server_name, aio_server_argv); + + fds = (int*) tls_alloc(sizeof(int) * acl_var_aio_max_accept); + + /* + * Be prepared for accept() to fail because some other process already + * got the connection (the number of processes competing for clients + * is kept small, so this is not a "thundering herd" problem). If the + * accept() succeeds, be sure to disable non-blocking I/O, in order to + * minimize confusion. + */ + + for (i = 0; i < acl_var_aio_max_accept; i++) { + fd = acl_accept(listen_fd, NULL, 0, &sock_type); + if (fd >= 0) { + /* TCP 连接避免发送延迟现象 */ + if (sock_type == AF_INET) + acl_tcp_set_nodelay(fd); + fds[i] = fd; + } else if (errno == EMFILE) { + delay_listen = 1; + acl_msg_warn("%s(%d), %s: accept connection: %s", + __FILE__, __LINE__, myname, acl_last_serror()); + } else if (errno == EAGAIN || errno == EINTR) + break; + else + acl_msg_fatal("%s(%d), %s: accept connection: %s", + __FILE__, __LINE__, myname, acl_last_serror()); + } + + if (acl_var_aio_master_maxproc > 1 && i >= acl_var_aio_min_notify + && acl_master_notify(acl_var_aio_pid, + aio_server_generation, ACL_MASTER_STAT_TAKEN) < 0) + { + aio_server_abort(astream, NULL); + } + + for (j = 0; j < i; j++) + aio_server_wakeup(aio, fds[j]); + + if (acl_var_aio_master_maxproc > 1 && i >= acl_var_aio_min_notify + && acl_master_notify(acl_var_aio_pid, aio_server_generation, + ACL_MASTER_STAT_AVAIL) < 0) + { + aio_server_abort(astream, NULL); + } + + if (aio_server_lock != 0 + && acl_myflock(ACL_VSTREAM_FILE(aio_server_lock), + ACL_INTERNAL_LOCK, ACL_MYFLOCK_OP_NONE) < 0) + { + acl_msg_fatal("%s(%d), %s: select unlock: %s", + __FILE__, __LINE__, myname, acl_last_serror()); + } + + if (delay_listen) { + acl_aio_disable_read(astream); + acl_aio_request_timer(aio, restart_listen, astream, 2000000, 0); + } + + return i; +} + +static void aio_server_accept_timer(int event acl_unused, void *context) +{ + ACL_ASTREAM *astream = (ACL_ASTREAM*) context; + ACL_AIO *aio = acl_aio_handle(astream); + + (void) aio_server_accept_sock2(astream, aio); + acl_aio_request_timer(aio, aio_server_accept_timer, + astream, (acl_int64) acl_var_aio_accept_timer * 1000000, 0); +} + +static void aio_server_accept_sock(ACL_ASTREAM *astream, void *context) +{ + ACL_AIO *aio = (ACL_AIO *) context; + int time_left = -1; + + if (acl_var_aio_idle_limit > 0) + time_left = (int) ((acl_aio_cancel_timer(aio, aio_server_timeout, + (void *) aio) + 999999) / 1000000); + else + time_left = acl_var_aio_idle_limit; + + (void) aio_server_accept_sock2(astream, aio); + + if (time_left > 0) + acl_aio_request_timer(aio, aio_server_timeout, + (void *) aio, (acl_int64) time_left * 1000000, 0); +} + +static void aio_server_init(const char *procname) +{ + const char *myname = "aio_server_init"; + static int inited = 0; + + if (inited) + return; + + inited = 1; + + if (procname == NULL || *procname == 0) + acl_msg_fatal("%s(%d); procname null", myname, __LINE__); + + /* + * Don't die when a process goes away unexpectedly. + */ + signal(SIGPIPE, SIG_IGN); + + /* + * Don't die for frivolous reasons. + */ +#ifdef SIGXFSZ + signal(SIGXFSZ, SIG_IGN); +#endif + + /* + * May need this every now and then. + */ + acl_var_aio_pid = getpid(); + acl_var_aio_procname = acl_mystrdup(acl_safe_basename(procname)); + + acl_var_aio_log_file = getenv("SERVICE_LOG"); + if (acl_var_aio_log_file == NULL) { + acl_var_aio_log_file = acl_mystrdup("acl_master.log"); + acl_msg_warn("%s(%d)->%s: can't get SERVICE_LOG's env value, use %s log", + __FILE__, __LINE__, myname, acl_var_aio_log_file); + } + + /* 获得本服务器框架所需要的配置参数 */ + + acl_get_app_conf_int_table(__conf_int_tab); + acl_get_app_conf_str_table(__conf_str_tab); + + /* 初始化IPC通道 */ + + acl_master_vars_init(acl_var_aio_buf_size, acl_var_aio_rw_timeout); +} + +static void aio_server_open_log(void) +{ + /* first, close the master's log */ + master_log_close(); + + /* second, open the service's log */ + acl_msg_open(acl_var_aio_log_file, acl_var_aio_procname); +} + +static void usage(int argc, char *argv[]) +{ + int i; + char *service_name; + + if (argc <= 0) + acl_msg_fatal("%s(%d): argc(%d) invalid", __FILE__, __LINE__, argc); + + service_name = acl_mystrdup(acl_safe_basename(argv[0])); + + for (i = 0; i < argc; i++) { + acl_msg_info("argv[%d]: %s", i, argv[i]); + } + + acl_msg_info("usage: %s -h[help]" + " -c [use chroot]" + " -d [debug]" + " -l [run alone]" + " -n service_name" + " -s socket_count" + " -i [use stdin]" + " -t transport" + " -u [use setgid initgroups setuid]" + " -v [on acl_msg_verbose]" + " -z [unlimit process count]" + " -f conf_file", + service_name); +} + +/* 创建异步IO */ + +static ACL_AIO *create_aio(int *event_mode) +{ + ACL_AIO *aio; + + if (strcasecmp(acl_var_aio_event_mode, "select") == 0) { + *event_mode = ACL_EVENT_SELECT; + } else if (strcasecmp(acl_var_aio_event_mode, "poll") == 0) { + *event_mode = ACL_EVENT_POLL; + } else if (strcasecmp(acl_var_aio_event_mode, "kernel") == 0) { + *event_mode = ACL_EVENT_KERNEL; + } else { + *event_mode = ACL_EVENT_SELECT; + } + aio = acl_aio_create(*event_mode); + acl_aio_set_delay_sec(aio, acl_var_aio_delay_sec); + acl_aio_set_delay_usec(aio, acl_var_aio_delay_usec); + acl_aio_set_keep_read(aio, 1); + return (aio); +} + +static void log_event_mode(int event_mode) +{ + const char *myname = "log_event_mode"; + + switch (event_mode) { + case ACL_EVENT_SELECT: + acl_msg_info("%s(%d): use select event", myname, __LINE__); + break; + case ACL_EVENT_POLL: + acl_msg_info("%s(%d): use poll event", myname, __LINE__); + break; + case ACL_EVENT_KERNEL: + acl_msg_info("%s(%d): use kernel_event", myname, __LINE__); + break; + default: + acl_msg_info("%s(%d): use select event", myname, __LINE__); + break; + } +} + +/* 创建定时器 */ + +static void create_timer(ACL_AIO *aio, int use_limit_delay) +{ + /* + * Running as a semi-resident server. Service connection requests. + * Terminate when we have serviced a sufficient number of clients, when + * no-one has been talking to us for a configurable amount of time, or + * when the master process terminated abnormally. + */ + if (acl_var_aio_idle_limit > 0) + acl_aio_request_timer(aio, aio_server_timeout, + aio, (acl_int64) acl_var_aio_idle_limit * 1000000, 0); + if (acl_var_aio_use_limit > 0) + acl_aio_request_timer(aio, aio_server_use_timer, + aio, (acl_int64) use_limit_delay * 1000000, 0); +} + +/* 创建监听者 */ + +static ACL_ASTREAM **create_listener(ACL_AIO *aio, int event_mode acl_unused, + const char *transport, int socket_count) +{ + const char *myname = "create_listener"; + int i, fd, fdtype = 0; + ACL_AIO *aio_ptr; + ACL_VSTREAM *stream; + ACL_ASTREAM *astream, **listen_astreams; + + /* socket count is as same listen_fd_count in parent process */ + + listen_astreams = (ACL_ASTREAM **) + acl_mycalloc(socket_count + 1, sizeof(ACL_ASTREAM *)); + for (i = 0; i < socket_count + 1; i++) + listen_astreams[i] = NULL; + + aio_server_wakeup = server_wakeup; + aio_ptr = aio; + + /* 选择连接接收接口 */ + + if (transport == 0) + acl_msg_fatal("no transport type specified"); + if (strcasecmp(transport, ACL_MASTER_XPORT_NAME_INET) == 0) { + aio_server_accept = aio_server_accept_sock; + fdtype = ACL_VSTREAM_TYPE_LISTEN | ACL_VSTREAM_TYPE_LISTEN_INET; + } else if (strcasecmp(transport, ACL_MASTER_XPORT_NAME_UNIX) == 0) { + aio_server_accept = aio_server_accept_sock; + fdtype = ACL_VSTREAM_TYPE_LISTEN | ACL_VSTREAM_TYPE_LISTEN_UNIX; + } else if (strcasecmp(transport, ACL_MASTER_XPORT_NAME_SOCK) == 0) { + aio_server_accept = aio_server_accept_sock; + fdtype = ACL_VSTREAM_TYPE_LISTEN | ACL_VSTREAM_TYPE_LISTEN_INET; +#ifdef MASTER_XPORT_NAME_PASS + } else if (strcasecmp(transport, ACL_MASTER_XPORT_NAME_PASS) == 0) { + aio_server_accept = aio_server_accept_pass; + fdtype = ACL_VSTREAM_TYPE_LISTEN; +#endif + } else { + acl_msg_fatal("unsupported transport type: %s", transport); + } + + for (i = 0, fd = ACL_MASTER_LISTEN_FD; + fd < ACL_MASTER_LISTEN_FD + socket_count; fd++) + { + /* 打开监听数据流 */ + stream = acl_vstream_fdopen(fd, O_RDWR, acl_var_aio_buf_size, + acl_var_aio_rw_timeout, fdtype); + if (stream == NULL) + acl_msg_fatal("%s(%d)->%s: stream null, fd = %d", + __FILE__, __LINE__, myname, fd); + + acl_non_blocking(ACL_VSTREAM_SOCK(stream), ACL_NON_BLOCKING); + acl_close_on_exec(ACL_VSTREAM_SOCK(stream), ACL_CLOSE_ON_EXEC); + + /* 打开异步数据流 */ + astream = acl_aio_open(aio_ptr, stream); + if (astream == NULL) + acl_msg_fatal("%s(%d)->%s: astream null, fd=%d", + __FILE__, __LINE__, myname, fd); + + /* 如果采用子线程单独 accept 连接,则 aio_server_accept 在子线程 + * 的异步事件循环中运行,否则在主线程的异步事件循环中运行 + */ + acl_aio_ctl(astream, ACL_AIO_CTL_LISTEN_FN, aio_server_accept, + ACL_AIO_CTL_CTX, aio_ptr, ACL_AIO_CTL_END); + + /* 设置异步监听 */ + acl_aio_listen(astream); + listen_astreams[i++] = astream; + + /* 为了保证 accept 的优先级,可以设置接收定时器 */ + if (acl_var_aio_accept_timer > 0) + acl_aio_request_timer(aio, aio_server_accept_timer, + astream, (acl_int64) acl_var_aio_accept_timer * 1000000, 0); + } + + return (listen_astreams); +} + +/* 进程间通信设置 */ + +static void setup_ipc(ACL_AIO *aio) +{ + const char *myname = "setup_ipc"; + + ACL_MASTER_STAT_ASTREAM = acl_aio_open(aio, ACL_MASTER_STAT_STREAM); + if (ACL_MASTER_STAT_ASTREAM == NULL) + acl_msg_fatal("%s(%d): open master stat astream error", + myname, __LINE__); + acl_aio_ctl(ACL_MASTER_STAT_ASTREAM, + ACL_AIO_CTL_READ_HOOK_ADD, aio_server_read_abort, NULL, + ACL_AIO_CTL_CLOSE_HOOK_ADD, aio_server_abort, NULL, + ACL_AIO_CTL_END); + acl_aio_read(ACL_MASTER_STAT_ASTREAM); + + acl_close_on_exec(ACL_MASTER_STATUS_FD, ACL_CLOSE_ON_EXEC); + acl_close_on_exec(ACL_MASTER_FLOW_READ, ACL_CLOSE_ON_EXEC); + acl_close_on_exec(ACL_MASTER_FLOW_WRITE, ACL_CLOSE_ON_EXEC); +} + +/* 开始进入事件循环过程 */ + +static void run_loop(const char *procname) +{ + ACL_WATCHDOG *watchdog; + + watchdog = acl_watchdog_create(acl_var_aio_daemon_timeout, + (ACL_WATCHDOG_FN) 0, (char *) 0); + + acl_msg_info("%s: starting...(accept_alone: %s)", + procname, acl_var_aio_accept_alone); + + if (acl_msg_verbose) + acl_msg_info("%s(%d): daemon started, log = %s", + acl_var_aio_procname, __LINE__, acl_var_aio_log_file); + + /* + * Traditionally, BSD select() can't handle aiople processes selecting + * on the same socket, and wakes up every process in select(). See TCP/IP + * Illustrated volume 2 page 532. We avoid select() collisions with an + * external lock file. + */ + + while (1) { + if (aio_server_lock != 0) { + acl_watchdog_stop(watchdog); + if (acl_myflock(ACL_VSTREAM_FILE(aio_server_lock), + ACL_INTERNAL_LOCK, ACL_MYFLOCK_OP_EXCLUSIVE) < 0) + { + acl_msg_fatal("select lock: %s", strerror(errno)); + } + } + + acl_watchdog_start(watchdog); + + if (acl_var_aio_max_threads == 0) /* single thread mode */ + acl_aio_loop(__h_aio); + else /* multi-threads mode */ + sleep(1); + if (__listen_disabled == 1) { + __listen_disabled = 2; + /* 该进程不再负责监听,防止 acl_master 主进程无法正常重启 */ + disable_listen(); + } + } + + /* not reached here */ + aio_server_exit(); +} + +/* acl_aio_server_main - the real main program */ + +void acl_aio_server_main(int argc, char **argv, ACL_AIO_SERVER_FN service,...) +{ + const char *myname = "acl_aio_server_main"; + ACL_VSTREAM *stream = 0; + int key, f_flag = 0; + char *root_dir = 0, *user_name = 0 /*, debug_me = 0 */; + char *service_name = acl_mystrdup(acl_safe_basename(argv[0])); + va_list ap; + ACL_MASTER_SERVER_INIT_FN pre_init = 0; + ACL_MASTER_SERVER_INIT_FN post_init = 0; + int alone = 0, zerolimit = 0; + char *transport = 0, *generation, *conf_file_ptr = 0; + + aio_init(); /* 初始化ACL库 */ + + /* + * Pick up policy settings from master process. Shut up error messages to + * stderr, because no-one is going to see them. + */ + + opterr = 0; + + while ((key = getopt(argc, argv, "hcdlm:n:o:s:it:uvzf:")) > 0) { + switch (key) { + case 'h': + usage(argc, argv); + exit (0); + case 'f': + acl_app_conf_load(optarg); + f_flag = 1; + conf_file_ptr = optarg; + break; + case 'c': + root_dir = "setme"; + break; + case 'l': + alone = 1; + break; + case 'n': + service_name = optarg; + break; + case 's': + if ((__socket_count = atoi(optarg)) <= 0) + acl_msg_fatal("invalid socket_count: %s", optarg); + break; + case 'i': + stream = ACL_VSTREAM_IN; + break; + case 'u': + user_name = "setme"; + break; + case 't': + transport = optarg; + break; + case 'v': + acl_msg_verbose++; + break; + case 'z': + zerolimit = 1; + break; + default: + break; + } + } + + /* If not connected to stdin, stdin must not be a terminal. */ + if (stream == 0 && isatty(STDIN_FILENO)) + acl_msg_fatal("%s(%d)->%s: do not run this command by hand", + __FILE__, __LINE__, myname); + if (stream == 0) + aio_server_init(argv[0]); + + if (f_flag == 0) + acl_msg_fatal("%s(%d)->%s: need \"-f pathname\"", + __FILE__, __LINE__, myname); + else if (acl_msg_verbose) + acl_msg_info("%s(%d)->%s: configure file = %s", + __FILE__, __LINE__, myname, conf_file_ptr); + + /* + * Application-specific initialization. + */ + va_start(ap, service); + while ((key = va_arg(ap, int)) != 0) { + switch (key) { + case ACL_MASTER_SERVER_INT_TABLE: + acl_get_app_conf_int_table(va_arg(ap, ACL_CONFIG_INT_TABLE *)); + break; + case ACL_MASTER_SERVER_INT64_TABLE: + acl_get_app_conf_int64_table(va_arg(ap, ACL_CONFIG_INT64_TABLE *)); + break; + case ACL_MASTER_SERVER_STR_TABLE: + acl_get_app_conf_str_table(va_arg(ap, ACL_CONFIG_STR_TABLE *)); + break; + case ACL_MASTER_SERVER_BOOL_TABLE: + acl_get_app_conf_bool_table(va_arg(ap, ACL_CONFIG_BOOL_TABLE *)); + break; + case ACL_MASTER_SERVER_PRE_INIT: + pre_init = va_arg(ap, ACL_MASTER_SERVER_INIT_FN); + break; + case ACL_MASTER_SERVER_POST_INIT: + post_init = va_arg(ap, ACL_MASTER_SERVER_INIT_FN); + break; + case ACL_MASTER_SERVER_EXIT: + aio_server_onexit = va_arg(ap, ACL_MASTER_SERVER_EXIT_FN); + break; + case ACL_MASTER_SERVER_PRE_ACCEPT: + aio_server_pre_accept = va_arg(ap, ACL_MASTER_SERVER_ACCEPT_FN); + break; + case ACL_MASTER_SERVER_PRE_DISCONN: + aio_server_pre_disconn = va_arg(ap, ACL_MASTER_SERVER_DISCONN_FN); + break; + case ACL_MASTER_SERVER_ON_ACCEPT: + aio_server_on_accept = va_arg(ap, ACL_MASTER_SERVER_ON_ACCEPT_FN); + break; + case ACL_MASTER_SERVER_RW_TIMER: + aio_server_rw_timer = va_arg(ap, ACL_MASTER_SERVER_RW_TIMER_FN); + break; + case ACL_MASTER_SERVER_IN_FLOW_DELAY: + aio_server_in_flow_delay = 1; + break; + case ACL_MASTER_SERVER_SOLITARY: + if (!alone) + acl_msg_fatal("service %s requires a process limit of 1", + service_name); + break; + case ACL_MASTER_SERVER_UNLIMITED: + if (!zerolimit) + acl_msg_fatal("service %s requires a process limit of 0", + service_name); + break; + case ACL_MASTER_SERVER_PRIVILEGED: + if (user_name) + acl_msg_fatal("service %s requires privileged operation", + service_name); + break; + default: + acl_msg_panic("%s: unknown argument type: %d", myname, key); + } + } + va_end(ap); + + /* 读完配置文件后重新设置 */ + + if (root_dir) + root_dir = acl_var_aio_queue_dir; + if (user_name) + user_name = acl_var_aio_owner; + + /* + * Retrieve process generation from environment. + */ + if ((generation = getenv(ACL_MASTER_GEN_NAME)) != 0) { + if (!acl_alldig(generation)) + acl_msg_fatal("bad generation: %s", generation); + sscanf(generation, "%o", &aio_server_generation); + if (acl_msg_verbose) + acl_msg_info("process generation: %s (%o)", + generation, aio_server_generation); + } + + /* Set up call-back info. */ + + aio_server_service = service; + aio_server_name = service_name; + aio_server_argv = argv + optind; + + __h_aio = create_aio(&__event_mode); /* 创建异步IO引擎 */ + + /* change to given directory */ + if (chdir(acl_var_aio_queue_dir) < 0) + acl_msg_fatal("chdir(\"%s\"): %s", acl_var_aio_queue_dir, + strerror(errno)); + + /* Run pre-jail initialization. */ + if (pre_init) + pre_init(aio_server_name, aio_server_argv); + + acl_chroot_uid(root_dir, user_name); /* 切换用户身份 */ + + /* 设置子进程运行环境,允许产生 core 文件 */ + if (acl_var_aio_enable_core) + set_core_limit(); + + aio_server_open_log(); /* 打开日志 */ + log_event_mode(__event_mode); /* 将事件模式记入日志中 */ + + /* Run post-jail initialization. */ + if (post_init) + post_init(aio_server_name, aio_server_argv); + + create_timer(__h_aio, __use_limit_delay); /* 创建定时器 */ + __listen_astreams = create_listener(__h_aio, __event_mode, + transport, __socket_count); /* 创建监听者 */ + setup_ipc(__h_aio); /* 安装进程间通信的通道 */ + run_loop(argv[0]); /* 进入事件主循环过程 */ +} +#endif /* ACL_UNIX */ diff --git a/lib_acl/src/master/template/acl_ioctl_app_main.c b/lib_acl/src/master/template/acl_ioctl_app_main.c new file mode 100644 index 000000000..4e84651d8 --- /dev/null +++ b/lib_acl/src/master/template/acl_ioctl_app_main.c @@ -0,0 +1,435 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "lib_acl.h" +#include +#include +#include +#include + +#endif + +#ifdef ACL_UNIX + +#include "master/acl_app_main.h" + +typedef struct ACL_APP_HANDLE { + char name[256]; +} ACL_APP_HANDLE; + +static ACL_IOCTL_RUN_FN __run_fn = NULL; +static void *__run_ctx = NULL; + +static ACL_CONFIG_INT_TABLE __conf_int_tab[] = { + /* TODO: you can add configure variables of int type here */ + { 0, 0, 0, 0, 0 }, +}; + +static char *__default_deny_info = "You are not welcome!\r\n"; +static char *__deny_info; +static int (*__app_on_timeout)(ACL_VSTREAM *stream, void*) = NULL; +static void (*__app_on_close)(ACL_VSTREAM *stream, void*) = NULL; +/*----------------------------------------------------------------------------*/ + +/** + * 创建一个服务器框架 + * @return ACL_APP_HANDLE* 用户自己的应用数据句柄. + */ + +static ACL_APP_HANDLE *app_create(void) +{ + char myname[] = "app_create"; + ACL_APP_HANDLE *app; + + app = (ACL_APP_HANDLE *) acl_mycalloc(1, sizeof(ACL_APP_HANDLE)); + if (app == NULL) + acl_msg_fatal("%s(%d): calloc error(%s)", + myname, __LINE__, strerror(errno)); + + ACL_SAFE_STRNCPY(app->name, myname, sizeof(app->name)); + + return (app); +} +/*----------------------------------------------------------------------------*/ +static void __read_notify_callback(int event_type, ACL_IOCTL *h_ioctl, + ACL_VSTREAM *cstream, void *context) +{ + const char myname[] = "__read_notify_callback"; + ACL_APP_HANDLE *app; + int ret; + + app = (ACL_APP_HANDLE *) context; + + switch (event_type) { + case ACL_EVENT_READ: + ret = __run_fn(cstream, __run_ctx); + if (ret < 0) { + if (__app_on_close != NULL) + __app_on_close(cstream, __run_ctx); + acl_vstream_close(cstream); + } else if (ret == 0) { + if (acl_msg_verbose) + acl_msg_info("enable(%s), fd=%d, h_ioctl(%p)", + myname, ACL_VSTREAM_SOCK(cstream), + (void*) h_ioctl); + acl_ioctl_enable_read(h_ioctl, cstream, acl_var_ioctl_rw_timeout, + __read_notify_callback, (void *) app); + + } + break; + case ACL_EVENT_RW_TIMEOUT: + if (__app_on_timeout == NULL) { + if (__app_on_close != NULL) + __app_on_close(cstream, __run_ctx); + acl_vstream_close(cstream); + } else if (__app_on_timeout(cstream, __run_ctx) < 0) { + if (__app_on_close != NULL) + __app_on_close(cstream, __run_ctx); + acl_vstream_close(cstream); + } else { + acl_ioctl_enable_read(h_ioctl, cstream, acl_var_ioctl_rw_timeout, + __read_notify_callback, (void *) app); + } + break; + case ACL_EVENT_XCPT: + if (__app_on_close != NULL) + __app_on_close(cstream, __run_ctx); + acl_vstream_close(cstream); + break; + default: + acl_msg_fatal("%s, %s(%d): unknown event type(%d)", + __FILE__, myname, __LINE__, event_type); + /* not reached */ + break; + } + if (acl_msg_verbose) + acl_msg_info("%s(%d): total alloc: %d", + myname, __LINE__, acl_mempool_total_allocated()); +} + +/** + * 向任务池中添加一个工作任务 + * @param h_ioctl 服务器任务池句柄 + * @param app_handle 用户自己的应用数据句柄. + * @param cstream 客户端数据流指针 + * 注: cstream 数据流会在该函数内部的回调函数中进行关闭, 所以该函数的调用者不要 + * 关闭该流. + */ + +static void app_add_worker(ACL_IOCTL *h_ioctl, ACL_APP_HANDLE *app, ACL_VSTREAM *cstream) +{ + const char *myname = "app_add_worker"; + + if (h_ioctl == NULL || cstream == NULL || app == NULL) + acl_msg_fatal("%s(%d): input invalid", myname, __LINE__); + + /* 将客户端数据流的状态置入事件监控集合中 */ + if (acl_msg_verbose) + acl_msg_info("%s(%d): ioctl=%p, fd=%d, timeout: %d", + myname, __LINE__, (void*) h_ioctl, ACL_VSTREAM_SOCK(cstream), + acl_var_ioctl_rw_timeout); + + acl_ioctl_enable_read(h_ioctl, cstream, acl_var_ioctl_rw_timeout, + __read_notify_callback, (void *) app); +} +/*---------------------- app main functions ----------------------------------*/ + +static int __mempool_limit = 0; + +static ACL_APP_HANDLE *__app_handle = NULL; + +static ACL_APP_INIT_FN __app_init_fn = NULL; +static void *__app_init_ctx = NULL; +static ACL_APP_EXIT_FN __app_exit_fn = NULL; +static void *__app_exit_ctx = NULL; +static ACL_APP_THREAD_INIT_FN __app_thread_init_fn = NULL; +static ACL_APP_THREAD_EXIT_FN __app_thread_exit_fn = NULL; +static ACL_APP_OPEN_LOG __app_open_log = NULL; +static ACL_APP_PRE_JAIL __app_pre_jail = NULL; +static void *__app_pre_jail_ctx = NULL; +static ACL_APP_CLOSE_LOG __app_close_log = NULL; +static int (*__app_on_accept)(ACL_VSTREAM *stream) = NULL; + +static void __service(ACL_IOCTL *h_ioctl, ACL_VSTREAM *stream, + char *service acl_unused, char **argv acl_unused) +{ + char myname[] = "__service"; + char addr[64], *ptr; + + /* + * Sanity check. This service takes no command-line arguments. + */ + if (argv[0]) + acl_msg_fatal("%s, %s(%d): unexpected command-line argument: %s, service=%s", + __FILE__, myname, __LINE__, argv[0], service ? service : "null"); + acl_watchdog_pat(); + + if (isatty(ACL_VSTREAM_SOCK(stream))) { + (void) __run_fn(stream, __run_ctx); + return; + } + + if (acl_getpeername(ACL_VSTREAM_SOCK(stream), addr, sizeof(addr)) < 0) { + acl_msg_warn("%s, %s(%d): can't get socket's addr(%s)", + __FILE__, myname, __LINE__, acl_last_serror()); + acl_vstream_close(stream); + return; + } + + ptr = strchr(addr, ':'); + if (ptr) + *ptr = 0; + + if (!acl_access_permit(addr)) { + acl_msg_warn("%s, %s(%d): addr(%s) be denied", + __FILE__, myname, __LINE__, addr); + (void) acl_vstream_writen(stream, __deny_info, strlen(__deny_info)); + acl_vstream_close(stream); + } else { + int ret = 0; + if (__app_on_accept) { + if ((ret = __app_on_accept(stream)) < 0) + acl_vstream_close(stream); + } + if (ret == 0) + app_add_worker(h_ioctl, __app_handle, stream); + } +} + +static void __pre_accept(char *name acl_unused, char **argv acl_unused) +{ +} + +static void __pre_jail_init(char *name acl_unused, char **argv acl_unused) +{ + acl_get_app_conf_int_table(__conf_int_tab); + + /* 是否采用用户自定义的日志函数库 */ + if (__app_open_log) + __app_open_log(); + + if (__app_pre_jail) + __app_pre_jail(__app_pre_jail_ctx); +} + +static void __post_jail_init(char *name acl_unused, char **argv acl_unused) +{ + char myname[] = "__post_jail_init"; + + if (acl_var_ioctl_access_allow != NULL) + acl_access_add(acl_var_ioctl_access_allow, ", \t", ":"); + + __app_handle = app_create(); + if (__app_handle == NULL) + acl_msg_fatal("%s(%d): ioctl_create error(%s)", + myname, __LINE__, strerror(errno)); + + if (__app_init_fn != NULL) + __app_init_fn(__app_init_ctx); + + if (__mempool_limit > 0) { + acl_msg_info("use mempool, size limit is %d, use mutex", + __mempool_limit); + } + + /* TODO: you can add some init functions here */ +} + +static void __app_on_exit(char *service acl_unused, char **argv acl_unused) +{ + if (__app_exit_fn) + __app_exit_fn(__app_exit_ctx); + + if (__app_close_log) + __app_close_log(); +} + +static void __thread_init(void *arg) +{ + if (__app_thread_init_fn) + __app_thread_init_fn(arg); +} + +static void __thread_exit(void *arg) +{ + if (__app_thread_exit_fn) + __app_thread_exit_fn(arg); +} + +static void app_main_init(void) +{ + char *ptr, *pname; + ACL_ARGV *env_argv; + int i; + + __deny_info = __default_deny_info; + ptr = getenv("SERVICE_ENV"); + if (ptr == NULL || *ptr == 0) + return; + + env_argv = acl_argv_split(ptr, ",\t "); + if (env_argv == NULL) + return; + if (env_argv->argc == 0) { + acl_argv_free(env_argv); + return; + } + + for (i = 0; i argc; i++) { + pname = acl_argv_index(env_argv, i); + ptr = strchr(pname, ':'); + if (ptr == NULL) + continue; + *ptr++ = 0; + if (ptr == 0) + continue; + if (strcasecmp(pname, "mempool_limit") == 0) { + __mempool_limit = atoi(ptr); + break; + } + } + + acl_argv_free(env_argv); + + /* 因为是多线程程序,所以需要加互斥锁 */ + if (__mempool_limit > 0) + acl_mempool_open(__mempool_limit, 1); +} + +static ACL_CONFIG_BOOL_TABLE null_conf_bool_tab[] = { + /* TODO: you can add configure variables of int type here */ + { 0, 0, 0 }, +}; + +static ACL_CONFIG_INT_TABLE null_conf_int_tab[] = { + /* TODO: you can add configure variables of int type here */ + { 0, 0, 0, 0, 0 }, +}; + +static ACL_CONFIG_INT64_TABLE null_conf_int64_tab[] = { + /* TODO: you can add configure variables of int type here */ + { 0, 0, 0, 0, 0 }, +}; + +static ACL_CONFIG_STR_TABLE null_conf_str_tab[] = { + /* TODO: you can add configure variables of int type here */ + { 0, 0, 0 }, +}; + +void acl_ioctl_app_main(int argc, char *argv[], + ACL_IOCTL_RUN_FN run_fn, void *run_ctx, int name, ...) +{ + const char *myname = "acl_ioctl_app_main"; + va_list ap; + ACL_CONFIG_BOOL_TABLE *bool_tab = null_conf_bool_tab; + ACL_CONFIG_INT_TABLE *int_tab = null_conf_int_tab; + ACL_CONFIG_INT64_TABLE *int64_tab = null_conf_int64_tab; + ACL_CONFIG_STR_TABLE *str_tab = null_conf_str_tab; + void *thread_init_ctx = NULL, *thread_exit_ctx = NULL; + + app_main_init(); + + /* 提前进行模板初始化,以使日志尽早地打开 */ + acl_master_log_open(argv[0]); + + if (run_fn == NULL) + acl_msg_fatal("%s: run_fn null", myname); + + __run_fn = run_fn; + __run_ctx = run_ctx; + + va_start(ap, name); + + for (; name != ACL_APP_CTL_END; name = va_arg(ap, int)) { + switch (name) { + case ACL_APP_CTL_ON_ACCEPT: + __app_on_accept = va_arg(ap, int (*)(ACL_VSTREAM*)); + break; + case ACL_APP_CTL_ON_TIMEOUT: + __app_on_timeout = va_arg(ap, int (*)(ACL_VSTREAM*, void*)); + break; + case ACL_APP_CTL_ON_CLOSE: + __app_on_close = va_arg(ap, void (*)(ACL_VSTREAM*, void*)); + break; + + case ACL_APP_CTL_INIT_FN: + __app_init_fn = va_arg(ap, ACL_APP_INIT_FN); + break; + case ACL_APP_CTL_INIT_CTX: + __app_init_ctx = va_arg(ap, void *); + break; + + case ACL_APP_CTL_EXIT_FN: + __app_exit_fn = va_arg(ap, ACL_APP_EXIT_FN); + break; + case ACL_APP_CTL_EXIT_CTX: + __app_exit_ctx = va_arg(ap, void *); + break; + + case ACL_APP_CTL_THREAD_INIT: + __app_thread_init_fn = va_arg(ap, ACL_APP_THREAD_INIT_FN); + break; + case ACL_APP_CTL_THREAD_INIT_CTX: + thread_init_ctx = va_arg(ap, void*); + break; + + case ACL_APP_CTL_THREAD_EXIT: + __app_thread_exit_fn = va_arg(ap, ACL_APP_THREAD_EXIT_FN); + break; + case ACL_APP_CTL_THREAD_EXIT_CTX: + thread_exit_ctx = va_arg(ap, void*); + break; + + case ACL_APP_CTL_OPEN_LOG: + __app_open_log = va_arg(ap, ACL_APP_OPEN_LOG); + break; + case ACL_APP_CTL_CLOSE_LOG: + __app_close_log = va_arg(ap, ACL_APP_CLOSE_LOG); + break; + + case ACL_APP_CTL_PRE_JAIL_CTX: + __app_pre_jail_ctx = va_arg(ap, void*); + break; + case ACL_APP_CTL_PRE_JAIL: + __app_pre_jail = va_arg(ap, ACL_APP_PRE_JAIL); + break; + + case ACL_APP_CTL_CFG_BOOL: + bool_tab = va_arg(ap, ACL_CONFIG_BOOL_TABLE *); + break; + case ACL_APP_CTL_CFG_INT: + int_tab = va_arg(ap, ACL_CONFIG_INT_TABLE *); + break; + case ACL_APP_CTL_CFG_INT64: + int64_tab = va_arg(ap, ACL_CONFIG_INT64_TABLE *); + break; + case ACL_APP_CTL_CFG_STR: + str_tab = va_arg(ap, ACL_CONFIG_STR_TABLE *); + break; + case ACL_APP_CTL_DENY_INFO: + __deny_info = acl_mystrdup(va_arg(ap, const char*)); + break; + default: + acl_msg_fatal("%s: bad name(%d)", myname, name); + } + } + + va_end(ap); + + acl_ioctl_server_main(argc, argv, __service, + ACL_MASTER_SERVER_BOOL_TABLE, bool_tab, + ACL_MASTER_SERVER_INT_TABLE, int_tab, + ACL_MASTER_SERVER_INT64_TABLE, int64_tab, + ACL_MASTER_SERVER_STR_TABLE, str_tab, + ACL_MASTER_SERVER_PRE_INIT, __pre_jail_init, + ACL_MASTER_SERVER_PRE_ACCEPT, __pre_accept, + ACL_MASTER_SERVER_POST_INIT, __post_jail_init, + ACL_MASTER_SERVER_EXIT, __app_on_exit, + ACL_MASTER_SERVER_THREAD_INIT, __thread_init, + ACL_MASTER_SERVER_THREAD_EXIT, __thread_exit, + ACL_MASTER_SERVER_THREAD_INIT_CTX, thread_init_ctx, + ACL_MASTER_SERVER_THREAD_EXIT_CTX, thread_exit_ctx, + 0); +} +#endif + diff --git a/lib_acl/src/master/template/acl_ioctl_server.c b/lib_acl/src/master/template/acl_ioctl_server.c new file mode 100644 index 000000000..c06a7ff4a --- /dev/null +++ b/lib_acl/src/master/template/acl_ioctl_server.c @@ -0,0 +1,1106 @@ +/* System library. */ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#endif + +#ifdef ACL_UNIX + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef STRCASECMP_IN_STRINGS_H +#include +#endif +#include +#include + +/* Utility library. */ + +#include "stdlib/acl_msg.h" +#include "stdlib/unix/acl_chroot_uid.h" +#include "stdlib/acl_vstring.h" +#include "stdlib/acl_vstream.h" +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_iostuff.h" +#include "stdlib/acl_stringops.h" +#include "stdlib/acl_myflock.h" +#include "stdlib/unix/acl_watchdog.h" +#include "stdlib/acl_split_at.h" +#include "net/acl_listen.h" +#include "net/acl_tcp_ctl.h" +#include "net/acl_sane_socket.h" +#include "event/acl_events.h" +#include "ioctl/acl_myioctl.h" + +/* Global library. */ + +#include "../master_flow.h" +#include "../master_params.h" +#include "../master_proto.h" + +/* Application-specific */ +#include "master/acl_ioctl_params.h" +#include "master/acl_server_api.h" +#include "template.h" + +int acl_var_ioctl_pid; +char *acl_var_ioctl_procname; +char *acl_var_ioctl_log_file; + +int acl_var_ioctl_buf_size; +int acl_var_ioctl_rw_timeout; +int acl_var_ioctl_in_flow_delay; +int acl_var_ioctl_max_threads; +int acl_var_ioctl_stacksize; +int acl_var_ioctl_thread_idle_limit; +int acl_var_ioctl_idle_limit; +char *acl_var_ioctl_queue_dir; +char *acl_var_ioctl_owner; +int acl_var_ioctl_delay_sec; +int acl_var_ioctl_delay_usec; +char *acl_var_ioctl_event_mode; +int acl_var_ioctl_daemon_timeout; +int acl_var_ioctl_use_limit; +char *acl_var_ioctl_pid_dir; +char *acl_var_ioctl_access_allow; +int acl_var_ioctl_master_maxproc; +int acl_var_ioctl_max_accept; +int acl_var_ioctl_enable_dog; +int acl_var_ioctl_quick_abort; +int acl_var_ioctl_enable_core; + +static ACL_CONFIG_INT_TABLE __conf_int_tab[] = { + { ACL_VAR_IOCTL_BUF_SIZE, ACL_DEF_IOCTL_BUF_SIZE, &acl_var_ioctl_buf_size, 0, 0 }, + { ACL_VAR_IOCTL_RW_TIMEOUT, ACL_DEF_IOCTL_RW_TIMEOUT, &acl_var_ioctl_rw_timeout, 0, 0 }, + { ACL_VAR_IOCTL_IN_FLOW_DELAY, ACL_DEF_IOCTL_IN_FLOW_DELAY, &acl_var_ioctl_in_flow_delay, 0, 0 }, + { ACL_VAR_IOCTL_MAX_THREADS, ACL_DEF_IOCTL_MAX_THREADS, &acl_var_ioctl_max_threads, 0, 0 }, + { ACL_VAR_IOCTL_STACKSIZE, ACL_DEF_IOCTL_STACKSIZE, &acl_var_ioctl_stacksize, 0, 0 }, + { ACL_VAR_IOCTL_THREAD_IDLE_LIMIT, ACL_DEF_IOCTL_THREAD_IDLE_LIMIT, &acl_var_ioctl_thread_idle_limit, 0, 0 }, + { ACL_VAR_IOCTL_IDLE_LIMIT, ACL_DEF_IOCTL_IDLE_LIMIT, &acl_var_ioctl_idle_limit, 0, 0 }, + { ACL_VAR_IOCTL_DELAY_SEC, ACL_DEF_IOCTL_DELAY_SEC, &acl_var_ioctl_delay_sec, 0, 0 }, + { ACL_VAR_IOCTL_DELAY_USEC, ACL_DEF_IOCTL_DELAY_USEC, &acl_var_ioctl_delay_usec, 0, 0 }, + { ACL_VAR_IOCTL_DAEMON_TIMEOUT, ACL_DEF_IOCTL_DAEMON_TIMEOUT, &acl_var_ioctl_daemon_timeout, 0, 0 }, + { ACL_VAR_IOCTL_USE_LIMIT, ACL_DEF_IOCTL_USE_LIMIT, &acl_var_ioctl_use_limit, 0, 0 }, + { ACL_VAR_IOCTL_MASTER_MAXPROC, ACL_DEF_IOCTL_MASTER_MAXPROC, &acl_var_ioctl_master_maxproc, 0, 0}, + { ACL_VAR_IOCTL_MAX_ACCEPT, ACL_DEF_IOCTL_MAX_ACCEPT, &acl_var_ioctl_max_accept, 0, 0 }, + { ACL_VAR_IOCTL_ENABLE_DOG, ACL_DEF_IOCTL_ENABLE_DOG, &acl_var_ioctl_enable_dog, 0, 0 }, + { ACL_VAR_IOCTL_QUICK_ABORT, ACL_DEF_IOCTL_QUICK_ABORT, &acl_var_ioctl_quick_abort, 0, 0 }, + { ACL_VAR_IOCTL_ENABLE_CORE, ACL_DEF_IOCTL_ENABLE_CORE, &acl_var_ioctl_enable_core, 0, 0 }, + { 0, 0, 0, 0, 0 }, +}; + +static ACL_CONFIG_STR_TABLE __conf_str_tab[] = { + { ACL_VAR_IOCTL_QUEUE_DIR, ACL_DEF_IOCTL_QUEUE_DIR, &acl_var_ioctl_queue_dir }, + { ACL_VAR_IOCTL_OWNER, ACL_DEF_IOCTL_OWNER, &acl_var_ioctl_owner }, + { ACL_VAR_IOCTL_PID_DIR, ACL_DEF_IOCTL_PID_DIR, &acl_var_ioctl_pid_dir }, + { ACL_VAR_IOCTL_ACCESS_ALLOW, ACL_DEF_IOCTL_ACCESS_ALLOW, &acl_var_ioctl_access_allow }, + { ACL_VAR_IOCTL_EVENT_MODE, ACL_DEF_IOCTL_EVENT_MODE, &acl_var_ioctl_event_mode }, + { 0, 0, 0 }, +}; + + /* + * Global state. + */ +static int __client_count; +static int __use_count; +static int __use_limit_delay = 1; +static int __socket_count = 1; +static int __listen_disabled = 0; + +static ACL_IOCTL *__h_ioctl = NULL; +static ACL_VSTREAM **__listen_streams; + +static time_t __last_closing_time = 0; +static pthread_mutex_t __closing_time_mutex; +static pthread_mutex_t __counter_mutex; + +static void (*ioctl_server_service) (ACL_IOCTL *, ACL_VSTREAM *, char *, char **); +static char *ioctl_server_name; +static char **ioctl_server_argv; +static void (*ioctl_server_accept) (int, ACL_IOCTL *, ACL_VSTREAM *, void *); +static void (*ioctl_server_onexit) (char *, char **); +static void (*ioctl_server_pre_accept) (char *, char **); +static ACL_VSTREAM *ioctl_server_lock; +static int ioctl_server_in_flow_delay; +static unsigned ioctl_server_generation; +static void (*ioctl_server_pre_disconn) (ACL_VSTREAM *, char *, char **); +static int (*ioctl_server_on_accept)(ACL_VSTREAM *); +static void (*ioctl_server_rw_timer) (ACL_VSTREAM *); + +/* forward declare */ +static void ioctl_server_timeout(int event acl_unused, void *context); + +static void ioctl_init(void) +{ + pthread_mutex_init(&__closing_time_mutex, NULL); + pthread_mutex_init(&__counter_mutex, NULL); + __last_closing_time = time(NULL); + + __use_limit_delay = acl_var_ioctl_delay_sec > 1 ? + acl_var_ioctl_delay_sec : 1; +} + +static void lock_closing_time(void) +{ + pthread_mutex_lock(&__closing_time_mutex); +} + +static void unlock_closing_time(void) +{ + pthread_mutex_unlock(&__closing_time_mutex); +} + +static void lock_counter(void) +{ + pthread_mutex_lock(&__counter_mutex); +} + +static void unlock_counter(void) +{ + pthread_mutex_unlock(&__counter_mutex); +} + +static void update_closing_time(void) +{ + lock_closing_time(); + __last_closing_time = time(NULL); + unlock_closing_time(); +} + +static time_t last_closing_time(void) +{ + time_t last; + + lock_closing_time(); + last = __last_closing_time; + unlock_closing_time(); + + return (last); +} + +static void increase_client_counter(void) +{ + lock_counter(); + __client_count++; + unlock_counter(); +} + +static void decrease_client_counter(void) +{ + lock_counter(); + __client_count--; + unlock_counter(); +} + +static int get_client_count(void) +{ + int n; + + lock_counter(); + n = __client_count; + unlock_counter(); + + return (n); +} + +void acl_ioctl_server_request_timer(ACL_IOCTL_TIMER_FN timer_fn, + void *arg, int delay) +{ + acl_assert(__h_ioctl); + acl_ioctl_request_timer(__h_ioctl, timer_fn, arg, + (acl_int64) delay * 1000000); +} + +void acl_ioctl_server_cancel_timer(ACL_IOCTL_TIMER_FN timer_fn, void *arg) +{ + acl_assert(__h_ioctl); + acl_ioctl_cancel_timer(__h_ioctl, timer_fn, arg); +} + +ACL_EVENT *acl_ioctl_server_event() +{ + return (acl_ioctl_event(__h_ioctl)); +} + +ACL_IOCTL *acl_ioctl_server_handle() +{ + return (__h_ioctl); +} + +static void close_listen_timer(int event acl_unused, void *context acl_unused) +{ + int i; + + if (__listen_streams == NULL) + return; + for (i = 0; __listen_streams[i] != NULL; i++) { + acl_ioctl_disable_readwrite(__h_ioctl, __listen_streams[i]); + acl_vstream_close(__listen_streams[i]); + __listen_streams[i] = NULL; + acl_msg_info("All listener closed now!"); + } + acl_myfree(__listen_streams); + __listen_streams = NULL; +} + +static void disable_listen(void) +{ + if (__listen_streams == NULL) + return; + + /** + * 只所以采用定时器关闭监听流,一方面因为监听流在事件集合中是“常驻留”的, + * 另一方面本线程与事件循环主线程是不同的线程空间,如果在本线程直接关闭 + * 监听流,会造成事件循环主线程在 select() 时报描述符非法,而当加了定时器 + * 关闭方法后,定时器的运行线程空间与事件循环的运行线程空间是相同的,所以 + * 不会造成冲突。这主要因为事件循环线程中先执行 select(), 后执行定时器,如果 + * select() 执行后定时器启动并将监听流从事件集合中删除,则即使该监听流已经 + * 准备好也会因其从事件集合中被删除而不会被触发,这样在下次事件循环时 select() + * 所调用的事件集合中就不存在该监听流了。 + */ + acl_ioctl_request_timer(__h_ioctl, close_listen_timer, NULL, 1000000); +} + +/* ioctl_server_exit - normal termination */ + +static void ioctl_server_exit(void) +{ + if (ioctl_server_onexit) + ioctl_server_onexit(ioctl_server_name, ioctl_server_argv); + + /* XXX: some bugs exist, need to be fixed --- zsx + if (__h_ioctl) + acl_ioctl_free(__h_ioctl); + */ + + exit(0); +} + +/* ioctl_server_abort - terminate after abnormal master exit */ + +static void ioctl_server_abort(int event acl_unused, ACL_IOCTL *h_ioctl, + ACL_VSTREAM *stream acl_unused, void *context acl_unused) +{ + static int __aborting = 0; + const char *myname = "ioctl_server_abort"; + int n; + + if (__aborting) + return; + + if (acl_var_ioctl_quick_abort) { + acl_msg_info("%s: master disconnect -- quick exiting", myname); + ioctl_server_exit(); + } + + if (!__listen_disabled) { + __listen_disabled = 1; + disable_listen(); + } + + __aborting = 1; + + n = get_client_count(); + if (n > 0) { + acl_msg_info("%s: wait for all connection(count=%d) closing", + myname, n); + /* set idle timeout to 1 second, one second check once */ + acl_var_ioctl_idle_limit = 1; + acl_ioctl_request_timer(h_ioctl, ioctl_server_timeout, + h_ioctl, (acl_int64) acl_var_ioctl_idle_limit * 1000000); + return; + } + + acl_msg_info("%s: master disconnect -- exiting", myname); + ioctl_server_exit(); +} + +/* ioctl_server_timeout - idle time exceeded */ + +static void ioctl_server_timeout(int event acl_unused, void *context) +{ + const char* myname = "ioctl_server_timeout"; + ACL_IOCTL *h_ioctl = (ACL_IOCTL *) context; + time_t last, inter; + int n; + + n = get_client_count(); + + /* if there are some fds not be closed, the timer should be reset again */ + if (n > 0 && acl_var_ioctl_idle_limit > 0) { + acl_ioctl_request_timer(h_ioctl, ioctl_server_timeout, h_ioctl, + (acl_int64) acl_var_ioctl_idle_limit * 1000000); + return; + } + + last = last_closing_time(); + inter = time(NULL) - last; + + if (inter >= 0 && inter < acl_var_ioctl_idle_limit) { + acl_ioctl_request_timer(h_ioctl, ioctl_server_timeout, h_ioctl, + (acl_int64) (acl_var_ioctl_idle_limit - inter) * 1000000); + return; + } + + if (acl_msg_verbose) + acl_msg_info("%s: idle timeout -- exiting", myname); + + ioctl_server_exit(); +} + +static void ioctl_server_use_timer(int event acl_unused, void *context) +{ + ACL_IOCTL *h_ioctl = (ACL_IOCTL *) context; + int n; + + n = get_client_count(); + + if (n > 0 || __use_count < acl_var_ioctl_use_limit) { + acl_ioctl_request_timer(h_ioctl, ioctl_server_use_timer, + h_ioctl, (acl_int64) __use_limit_delay * 1000000); + return; + } + + if (acl_msg_verbose) + acl_msg_info("use limit -- exiting"); + + ioctl_server_exit(); +} + +void acl_ioctl_server_enable_read(ACL_IOCTL *h_ioctl, ACL_VSTREAM *stream, + int timeout, ACL_IOCTL_NOTIFY_FN notify_fn, void *context) +{ + const char *myname = "acl_ioctl_server_enable_read"; + + if (h_ioctl == NULL || stream == NULL || ACL_VSTREAM_SOCK(stream) < 0) { + acl_msg_error("%s(%d): input error", myname, __LINE__); + return; + } + /* __client_count++; */ + acl_ioctl_enable_read(h_ioctl, stream, timeout, notify_fn, context); +} + +/* ioctl_server_execute - in case (char *) != (struct *) */ + +static void ioctl_server_execute(ACL_IOCTL *h_ioctl, ACL_VSTREAM *stream) +{ + if (acl_var_ioctl_master_maxproc > 1 + && acl_master_notify(acl_var_ioctl_pid, ioctl_server_generation, + ACL_MASTER_STAT_TAKEN) < 0) + { + ioctl_server_abort(ACL_EVENT_NULL_TYPE, h_ioctl, stream, + ACL_EVENT_NULL_CONTEXT); + } + + ioctl_server_service(h_ioctl, stream, ioctl_server_name, ioctl_server_argv); + + if (acl_var_ioctl_master_maxproc > 1 + && acl_master_notify(acl_var_ioctl_pid, ioctl_server_generation, + ACL_MASTER_STAT_AVAIL) < 0) + { + ioctl_server_abort(ACL_EVENT_NULL_TYPE, h_ioctl, stream, + ACL_EVENT_NULL_CONTEXT); + } +} + +static void decrease_counter_callback(ACL_VSTREAM *stream acl_unused, + void *arg acl_unused) +{ + update_closing_time(); + decrease_client_counter(); +} + +/* ioctl_server_wakeup - wake up application */ + +static void ioctl_server_wakeup(ACL_IOCTL *h_ioctl, int fd, + const char *remote_addr, const char *local_addr) +{ + ACL_VSTREAM *stream; + + if (acl_msg_verbose) + acl_msg_info("connection established fd %d", fd); + +/* + acl_non_blocking(fd, ACL_BLOCKING); +*/ + acl_close_on_exec(fd, ACL_CLOSE_ON_EXEC); + + increase_client_counter(); + + __use_count++; + + stream = acl_vstream_fdopen(fd, O_RDWR, acl_var_ioctl_buf_size, + acl_var_ioctl_rw_timeout, ACL_VSTREAM_TYPE_SOCK); + if (stream == NULL) + acl_msg_fatal("%s(%d): acl_vstream_fdopen error(%s)", + __FILE__, __LINE__, strerror(errno)); + + if (remote_addr) + ACL_SAFE_STRNCPY(stream->remote_addr, remote_addr, + sizeof(stream->remote_addr)); + if (local_addr) + ACL_SAFE_STRNCPY(stream->local_addr, local_addr, + sizeof(stream->local_addr)); + /* when the stream is closed, the callback will be called to decrease the counter */ + acl_vstream_add_close_handle(stream, decrease_counter_callback, NULL); + + ioctl_server_execute(h_ioctl, stream); +} + +/* restart listening */ + +static void ioctl_restart_listen(int event acl_unused, void *context) +{ + ACL_VSTREAM *stream = (ACL_VSTREAM*) context; + acl_assert(__h_ioctl); + acl_msg_info("restart listen now!"); + acl_ioctl_enable_listen(__h_ioctl, stream, 0, + ioctl_server_accept, __h_ioctl); +} + +#ifdef MASTER_XPORT_NAME_PASS + +/* ioctl_server_accept_pass - accept descriptor */ + +static void ioctl_server_accept_pass(int event_type, ACL_IOCTL *h_ioctl, + ACL_VSTREAM *stream, void *context) +{ + const char *myname = "ioctl_server_accept_pass"; + int listen_fd = acl_vstream_fileno(stream); + int time_left = -1; + int fd; + int delay_listen = 0; + int i = 0; + + if (__listen_streams == NULL) { + acl_msg_info("Server stoping ..."); + return; + } + + if (event_type != ACL_EVENT_READ) + acl_msg_fatal("%s, %s(%d): unknown event_type(%d)", + __FILE__, myname, __LINE__, event_type); + + /* + * Be prepared for accept() to fail because some other process already + * got the connection (the number of processes competing for clients + * is kept small, so this is not a "thundering herd" problem). If the + * accept() succeeds, be sure to disable non-blocking I/O, in order to + * minimize confusion. + */ + if (acl_var_ioctl_idle_limit > 0) + time_left = (int) ((acl_ioctl_cancel_timer(h_ioctl, + ioctl_server_timeout, h_ioctl) + 999999) / 1000000); + else + time_left = acl_var_ioctl_idle_limit; + + if (ioctl_server_pre_accept) + ioctl_server_pre_accept(ioctl_server_name, ioctl_server_argv); + + while (i++ < acl_var_ioctl_max_accept) { + fd = PASS_ACCEPT(listen_fd); + if (fd >= 0) { + ioctl_server_wakeup(h_ioctl, fd, NULL, NULL); + continue; + } + + if (errno == EMFILE) { + delay_listen = 1; + acl_msg_warn("accept connection: %s", strerror(errno)); + } else if (errno != EAGAIN && errno != EINTR) { + acl_msg_warn("accept connection: %s, stoping ...", + strerror(errno)); + acl_ioctl_disable_readwrite(h_ioctl, stream); + ioctl_server_abort(0, h_ioctl, stream, h_ioctl); + return; + } + + break; + } + + if (ioctl_server_lock != 0 + && acl_myflock(ACL_VSTREAM_FILE(ioctl_server_lock), + ACL_INTERNAL_LOCK, ACL_MYFLOCK_OP_NONE) < 0) + { + acl_msg_fatal("select unlock: %s", strerror(errno)); + } + + if (delay_listen) { + acl_ioctl_disable_readwrite(h_ioctl, stream); + acl_ioctl_request_timer(h_ioctl, ioctl_restart_listen, + stream, 2000000); + } else + acl_ioctl_enable_listen(h_ioctl, stream, + 0, ioctl_server_accept, context); + + if (time_left >= 0) + acl_ioctl_request_timer(h_ioctl, ioctl_server_timeout, + (void *) h_ioctl, (acl_int64) time_left * 1000000); +} + +#endif + +/* ioctl_server_accept_sock - accept client connection request */ + +static void ioctl_server_accept_sock(int event_type, ACL_IOCTL *h_ioctl, + ACL_VSTREAM *stream, void *context) +{ + const char *myname = "ioctl_serer_accept_inet"; + int listen_fd = ACL_VSTREAM_SOCK(stream); + int time_left = -1, i = 0, delay_listen = 0, fd, sock_type; + char remote_addr[64], local_addr[64]; + + if (__listen_streams == NULL) { + acl_msg_info("Server stoping ..."); + return; + } + + if (event_type != ACL_EVENT_READ) + acl_msg_fatal("%s, %s(%d): unknown event_type(%d)", + __FILE__, myname, __LINE__, event_type); + + /* + * Be prepared for accept() to fail because some other process already + * got the connection (the number of processes competing for clients + * is kept small, so this is not a "thundering herd" problem). If the + * accept() succeeds, be sure to disable non-blocking I/O, in order to + * minimize confusion. + */ + if (acl_var_ioctl_idle_limit > 0) + time_left = (int) ((acl_ioctl_cancel_timer(h_ioctl, + ioctl_server_timeout, h_ioctl) + 999999) / 1000000); + else + time_left = acl_var_ioctl_idle_limit; + + if (ioctl_server_pre_accept) + ioctl_server_pre_accept(ioctl_server_name, ioctl_server_argv); + + while (i++ < acl_var_ioctl_max_accept) { + fd = acl_accept(listen_fd, remote_addr, + sizeof(remote_addr), &sock_type); + if (fd < 0) { + if (errno == EMFILE) { + delay_listen = 1; + acl_msg_warn("accept connection: %s", + strerror(errno)); + break; + } + + if (errno == EAGAIN || errno == EINTR) + break; + + acl_msg_warn("accept connection: %s, stoping ...", + strerror(errno)); + acl_ioctl_disable_readwrite(h_ioctl, stream); + ioctl_server_abort(0, h_ioctl, stream, h_ioctl); + return; + } + + /* 如果为 TCP 套接口,则设置 nodelay 选项以避免发送延迟现象 */ + if (sock_type == AF_INET) + acl_tcp_set_nodelay(fd); + if (acl_getsockname(fd, local_addr, sizeof(local_addr)) < 0) + memset(local_addr, 0, sizeof(local_addr)); + ioctl_server_wakeup(h_ioctl, fd, remote_addr, local_addr); + } + + if (ioctl_server_lock != 0 + && acl_myflock(ACL_VSTREAM_FILE(ioctl_server_lock), + ACL_INTERNAL_LOCK, ACL_MYFLOCK_OP_NONE) < 0) + { + acl_msg_fatal("select unlock: %s", strerror(errno)); + } + + if (delay_listen) { + acl_ioctl_disable_readwrite(h_ioctl, stream); + acl_ioctl_request_timer(h_ioctl, ioctl_restart_listen, + stream, 2000000); + } else + acl_ioctl_enable_listen(h_ioctl, stream, 0, + ioctl_server_accept, context); + + if (time_left > 0) + acl_ioctl_request_timer(h_ioctl, ioctl_server_timeout, + h_ioctl, (acl_int64) time_left * 1000000); +} + +static void ioctl_server_init(const char *procname) +{ + const char *myname = "ioctl_server_init"; + static int inited = 0; + + if (inited) + return; + + inited = 1; + + if (procname == NULL || *procname == 0) + acl_msg_fatal("%s(%d); procname null", myname, __LINE__); + + /* + * Don't die when a process goes away unexpectedly. + */ + signal(SIGPIPE, SIG_IGN); + + /* + * Don't die for frivolous reasons. + */ +#ifdef SIGXFSZ + signal(SIGXFSZ, SIG_IGN); +#endif + + /* + * May need this every now and then. + */ + acl_var_ioctl_pid = getpid(); + acl_var_ioctl_procname = acl_mystrdup(acl_safe_basename(procname)); + + acl_var_ioctl_log_file = getenv("SERVICE_LOG"); + if (acl_var_ioctl_log_file == NULL) { + acl_var_ioctl_log_file = acl_mystrdup("acl_master.log"); + acl_msg_warn("%s(%d)->%s: can't get SERVICE_LOG's env value, use %s log", + __FILE__, __LINE__, myname, acl_var_ioctl_log_file); + } + + acl_get_app_conf_int_table(__conf_int_tab); + acl_get_app_conf_str_table(__conf_str_tab); + + acl_master_vars_init(acl_var_ioctl_buf_size, acl_var_ioctl_rw_timeout); +} + +static void ioctl_server_open_log(void) +{ + /* first, close the master's log */ + master_log_close(); + + /* second, open the service's log */ + acl_msg_open(acl_var_ioctl_log_file, acl_var_ioctl_procname); +} + +static void usage(int argc, char *argv[]) +{ + int i; + char *service_name; + + if (argc <= 0) + acl_msg_fatal("%s(%d): argc(%d) invalid", __FILE__, __LINE__, argc); + + service_name = acl_mystrdup(acl_safe_basename(argv[0])); + + for (i = 0; i < argc; i++) { + acl_msg_info("argv[%d]: %s", i, argv[i]); + } + + acl_msg_info("usage: %s -h[help]" + " -c [use chroot]" + " -d [debug]" + " -l [run alone]" + " -n service_name" + " -s socket_count" + " -i [use stdin]" + " -t transport" + " -u [use setgid initgroups setuid]" + " -v [on acl_msg_verbose]" + " -z [unlimit process count]" + " -f conf_file", + service_name); +} + +/* acl_ioctl_server_main - the real main program */ + +void acl_ioctl_server_main(int argc, char **argv, ACL_IOCTL_SERVER_FN service, ...) +{ + const char *myname = "acl_ioctl_server_main"; + ACL_VSTREAM *stream = 0; + char *root_dir = 0; + char *user_name = 0; + char *service_name = acl_mystrdup(acl_safe_basename(argv[0])); + int c; + va_list ap; + ACL_MASTER_SERVER_INIT_FN pre_init = 0; + ACL_MASTER_SERVER_INIT_FN post_init = 0; + int key; + char *transport = 0; + int alone = 0; + int zerolimit = 0; + ACL_WATCHDOG *watchdog; + char *generation; + int fd, i, fdtype = 0; + int event_mode; + + int f_flag = 0; + char conf_file[1024]; + + ACL_MASTER_SERVER_THREAD_INIT_FN thread_init_fn = NULL; + ACL_MASTER_SERVER_THREAD_EXIT_FN thread_exit_fn = NULL; + void *thread_init_ctx = NULL; + void *thread_exit_ctx = NULL; + + /* + * Pick up policy settings from master process. Shut up error messages to + * stderr, because no-one is going to see them. + */ + opterr = 0; + while ((c = getopt(argc, argv, "hcdlm:n:o:s:it:uvzf:")) > 0) { + switch (c) { + case 'h': + usage(argc, argv); + exit (0); + case 'f': + acl_app_conf_load(optarg); + f_flag = 1; + ACL_SAFE_STRNCPY(conf_file, optarg, sizeof(conf_file)); + break; + case 'c': + root_dir = "setme"; + break; + case 'l': + alone = 1; + break; + case 'n': + service_name = optarg; + break; + case 's': + if ((__socket_count = atoi(optarg)) <= 0) + acl_msg_fatal("invalid socket_count: %s", optarg); + break; + case 'i': + stream = ACL_VSTREAM_IN; + break; + case 'u': + user_name = "setme"; + break; + case 't': + transport = optarg; + break; + case 'v': + acl_msg_verbose++; + break; + case 'z': + zerolimit = 1; + break; + default: + break; + } + } + + if (stream == NULL) + ioctl_server_init(argv[0]); + + if (f_flag == 0) + acl_msg_fatal("%s(%d)->%s: need \"-f pathname\"", + __FILE__, __LINE__, myname); + else if (acl_msg_verbose) + acl_msg_info("%s(%d)->%s: configure file = %s", + __FILE__, __LINE__, myname, conf_file); + + /* + * Application-specific initialization. + */ + va_start(ap, service); + while ((key = va_arg(ap, int)) != 0) { + switch (key) { + case ACL_MASTER_SERVER_INT_TABLE: + acl_get_app_conf_int_table(va_arg(ap, ACL_CONFIG_INT_TABLE *)); + break; + case ACL_MASTER_SERVER_INT64_TABLE: + acl_get_app_conf_int64_table(va_arg(ap, ACL_CONFIG_INT64_TABLE *)); + break; + case ACL_MASTER_SERVER_STR_TABLE: + acl_get_app_conf_str_table(va_arg(ap, ACL_CONFIG_STR_TABLE *)); + break; + case ACL_MASTER_SERVER_BOOL_TABLE: + acl_get_app_conf_bool_table(va_arg(ap, ACL_CONFIG_BOOL_TABLE *)); + break; + + case ACL_MASTER_SERVER_THREAD_INIT: + thread_init_fn = va_arg(ap, ACL_MASTER_SERVER_THREAD_INIT_FN); + break; + case ACL_MASTER_SERVER_THREAD_EXIT: + thread_exit_fn = va_arg(ap, ACL_MASTER_SERVER_THREAD_EXIT_FN); + break; + case ACL_MASTER_SERVER_THREAD_INIT_CTX: + thread_init_ctx = va_arg(ap, void*); + break; + case ACL_MASTER_SERVER_THREAD_EXIT_CTX: + thread_exit_ctx = va_arg(ap, void*); + break; + + case ACL_MASTER_SERVER_PRE_INIT: + pre_init = va_arg(ap, ACL_MASTER_SERVER_INIT_FN); + break; + case ACL_MASTER_SERVER_POST_INIT: + post_init = va_arg(ap, ACL_MASTER_SERVER_INIT_FN); + break; + case ACL_MASTER_SERVER_EXIT: + ioctl_server_onexit = va_arg(ap, ACL_MASTER_SERVER_EXIT_FN); + break; + case ACL_MASTER_SERVER_PRE_ACCEPT: + ioctl_server_pre_accept = va_arg(ap, ACL_MASTER_SERVER_ACCEPT_FN); + break; + case ACL_MASTER_SERVER_PRE_DISCONN: + ioctl_server_pre_disconn = va_arg(ap, ACL_MASTER_SERVER_DISCONN_FN); + break; + case ACL_MASTER_SERVER_ON_ACCEPT: + ioctl_server_on_accept = va_arg(ap, ACL_MASTER_SERVER_ON_ACCEPT_FN); + break; + case ACL_MASTER_SERVER_RW_TIMER: + ioctl_server_rw_timer = va_arg(ap, ACL_MASTER_SERVER_RW_TIMER_FN); + break; + case ACL_MASTER_SERVER_IN_FLOW_DELAY: + ioctl_server_in_flow_delay = 1; + break; + case ACL_MASTER_SERVER_SOLITARY: + if (!alone) + acl_msg_fatal("service %s requires a process limit of 1", + service_name); + break; + case ACL_MASTER_SERVER_UNLIMITED: + if (!zerolimit) + acl_msg_fatal("service %s requires a process limit of 0", + service_name); + break; + case ACL_MASTER_SERVER_PRIVILEGED: + if (user_name) + acl_msg_fatal("service %s requires privileged operation", + service_name); + break; + default: + acl_msg_panic("%s: unknown argument type: %d", myname, key); + } + } + va_end(ap); + + if (root_dir) + root_dir = acl_var_ioctl_queue_dir; + if (user_name) + user_name = acl_var_ioctl_owner; + + /* + * If not connected to stdin, stdin must not be a terminal. + */ + if (stream == 0 && isatty(STDIN_FILENO)) + acl_msg_fatal("%s(%d)->%s: do not run this command by hand", + __FILE__, __LINE__, myname); + + /* + * Can options be required? + */ + if (stream == 0) { + if (transport == 0) + acl_msg_fatal("no transport type specified"); + if (strcasecmp(transport, ACL_MASTER_XPORT_NAME_INET) == 0) { + ioctl_server_accept = ioctl_server_accept_sock; + fdtype = ACL_VSTREAM_TYPE_LISTEN | ACL_VSTREAM_TYPE_LISTEN_INET; + } else if (strcasecmp(transport, ACL_MASTER_XPORT_NAME_UNIX) == 0) { + ioctl_server_accept = ioctl_server_accept_sock; + fdtype = ACL_VSTREAM_TYPE_LISTEN | ACL_VSTREAM_TYPE_LISTEN_UNIX; + } else if (strcasecmp(transport, ACL_MASTER_XPORT_NAME_SOCK) == 0) { + ioctl_server_accept = ioctl_server_accept_sock; + fdtype = ACL_VSTREAM_TYPE_LISTEN | ACL_VSTREAM_TYPE_LISTEN_INET; +#ifdef MASTER_XPORT_NAME_PASS + } else if (strcasecmp(transport, ACL_MASTER_XPORT_NAME_PASS) == 0) { + ioctl_server_accept = ioctl_server_accept_pass; + fdtype = ACL_VSTREAM_TYPE_LISTEN; +#endif + } else { + acl_msg_fatal("unsupported transport type: %s", transport); + } + } + + /* + * Retrieve process generation from environment. + */ + if ((generation = getenv(ACL_MASTER_GEN_NAME)) != 0) { + if (!acl_alldig(generation)) + acl_msg_fatal("bad generation: %s", generation); + sscanf(generation, "%o", &ioctl_server_generation); + if (acl_msg_verbose) + acl_msg_info("process generation: %s (%o)", + generation, ioctl_server_generation); + } + + /* + * Traditionally, BSD select() can't handle ioctlple processes selecting + * on the same socket, and wakes up every process in select(). See TCP/IP + * Illustrated volume 2 page 532. We avoid select() collisions with an + * external lock file. + */ + + /* + * Set up call-back info. + */ + ioctl_server_service = service; + ioctl_server_name = service_name; + ioctl_server_argv = argv + optind; + + ioctl_init(); + + /* + * create event and call user's thread callback + */ + if (strcasecmp(acl_var_ioctl_event_mode, "select") == 0) { + event_mode = ACL_EVENT_SELECT; + } else if (strcasecmp(acl_var_ioctl_event_mode, "poll") == 0) { + event_mode = ACL_EVENT_POLL; + } else if (strcasecmp(acl_var_ioctl_event_mode, "kernel") == 0) { + event_mode = ACL_EVENT_KERNEL; + } else { + event_mode = ACL_EVENT_SELECT; + } + + __h_ioctl = acl_ioctl_create_ex(event_mode, acl_var_ioctl_max_threads, + acl_var_ioctl_thread_idle_limit, acl_var_ioctl_delay_sec, + acl_var_ioctl_delay_usec); + acl_ioctl_ctl(__h_ioctl, ACL_IOCTL_CTL_THREAD_STACKSIZE, + acl_var_ioctl_stacksize, ACL_IOCTL_CTL_END); + if (thread_init_fn) + acl_ioctl_ctl(__h_ioctl, ACL_IOCTL_CTL_INIT_FN, thread_init_fn, + ACL_IOCTL_CTL_INIT_CTX, thread_init_ctx, + ACL_IOCTL_CTL_END); + if (thread_exit_fn) + acl_ioctl_ctl(__h_ioctl, ACL_IOCTL_CTL_EXIT_FN, thread_exit_fn, + ACL_IOCTL_CTL_EXIT_CTX, thread_exit_ctx, + ACL_IOCTL_CTL_END); + + if (acl_var_ioctl_enable_dog) + acl_ioctl_add_dog(__h_ioctl); + + /* + * Run pre-jail initialization. + */ + if (chdir(acl_var_ioctl_queue_dir) < 0) + acl_msg_fatal("chdir(\"%s\"): %s", + acl_var_ioctl_queue_dir, strerror(errno)); + + if (pre_init) + pre_init(ioctl_server_name, ioctl_server_argv); + + acl_chroot_uid(root_dir, user_name); + /* 设置子进程运行环境,允许产生 core 文件 */ + if (acl_var_ioctl_enable_core) + set_core_limit(); + ioctl_server_open_log(); + + switch (event_mode) { + case ACL_EVENT_SELECT: + acl_msg_info("%s(%d): use select event", myname, __LINE__); + break; + case ACL_EVENT_POLL: + acl_msg_info("%s(%d): use poll event", myname, __LINE__); + break; + case ACL_EVENT_KERNEL: + acl_msg_info("%s(%d): use kernel_event", myname, __LINE__); + break; + default: + acl_msg_info("%s(%d): use select event", myname, __LINE__); + break; + } + + /* + * The event loop, at last. + */ + if (acl_ioctl_start(__h_ioctl) < 0) + acl_msg_fatal("%s(%d): acl_ioctl_start error(%s)", + myname, __LINE__, strerror(errno)); + + /* + * Run post-jail initialization. + */ + if (post_init) + post_init(ioctl_server_name, ioctl_server_argv); + + /* + * Are we running as a one-shot server with the client connection on + * standard input? If so, make sure the output is written to stdout so as + * to satisfy common expectation. + */ + if (stream != 0) { + service(__h_ioctl, stream, ioctl_server_name, ioctl_server_argv); + ioctl_server_exit(); + } + + /* + * Running as a semi-resident server. Service connection requests. + * Terminate when we have serviced a sufficient number of clients, when + * no-one has been talking to us for a configurable amount of time, or + * when the master process terminated abnormally. + */ + if (acl_var_ioctl_idle_limit > 0) { + acl_ioctl_request_timer(__h_ioctl, ioctl_server_timeout, + __h_ioctl, (acl_int64) acl_var_ioctl_idle_limit * 1000000); + } + + if (acl_var_ioctl_use_limit > 0) { + acl_ioctl_request_timer(__h_ioctl, ioctl_server_use_timer, + __h_ioctl, (acl_int64) __use_limit_delay * 1000000); + } + + /* socket count is as same listen_fd_count in parent process */ + + __listen_streams = (ACL_VSTREAM **) + acl_mycalloc(__socket_count + 1, sizeof(ACL_VSTREAM *)); + for (i = 0; i < __socket_count + 1; i++) { + __listen_streams[i] = NULL; + } + + i = 0; + for (fd = ACL_MASTER_LISTEN_FD; fd < ACL_MASTER_LISTEN_FD + __socket_count; fd++) { + stream = acl_vstream_fdopen(fd, O_RDWR, acl_var_ioctl_buf_size, + acl_var_ioctl_rw_timeout, fdtype); + if (stream == NULL) + acl_msg_fatal("%s(%d)->%s: stream null, fd = %d", + __FILE__, __LINE__, myname, fd); + + acl_non_blocking(ACL_VSTREAM_SOCK(stream), ACL_NON_BLOCKING); + acl_ioctl_enable_listen(__h_ioctl, stream, 0, + ioctl_server_accept, NULL); + acl_close_on_exec(ACL_VSTREAM_SOCK(stream), ACL_CLOSE_ON_EXEC); + __listen_streams[i++] = stream; + } + + acl_ioctl_enable_read(__h_ioctl, ACL_MASTER_STAT_STREAM, + 0, ioctl_server_abort, (void *) 0); + acl_close_on_exec(ACL_MASTER_STATUS_FD, ACL_CLOSE_ON_EXEC); + acl_close_on_exec(ACL_MASTER_FLOW_READ, ACL_CLOSE_ON_EXEC); + acl_close_on_exec(ACL_MASTER_FLOW_WRITE, ACL_CLOSE_ON_EXEC); + watchdog = acl_watchdog_create(acl_var_ioctl_daemon_timeout, + (ACL_WATCHDOG_FN) 0, (char *) 0); + + acl_msg_info("%s: starting...", argv[0]); + + if (acl_msg_verbose) + acl_msg_info("%s(%d): daemon started, log = %s", + acl_var_ioctl_procname, __LINE__, acl_var_ioctl_log_file); + + while (1) { + if (ioctl_server_lock != 0) { + acl_watchdog_stop(watchdog); + if (acl_myflock(ACL_VSTREAM_FILE(ioctl_server_lock), + ACL_INTERNAL_LOCK, ACL_MYFLOCK_OP_EXCLUSIVE) < 0) + { + acl_msg_fatal("select lock: %s", strerror(errno)); + } + } + acl_watchdog_start(watchdog); + sleep(1); + } + + /* not reached here */ + ioctl_server_exit(); +} +#endif /* ACL_UNIX */ diff --git a/lib_acl/src/master/template/acl_master_log.c b/lib_acl/src/master/template/acl_master_log.c new file mode 100644 index 000000000..3981e8360 --- /dev/null +++ b/lib_acl/src/master/template/acl_master_log.c @@ -0,0 +1,41 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#endif + +#ifdef ACL_UNIX +#include +#include "stdlib/acl_msg.h" +#include "master/acl_server_api.h" +#include "template.h" + +static int var_master_log_opened = 0; + +void acl_master_log_open(const char *procname) +{ + const char *myname = "acl_master_log_open"; + char *master_log; + + /* use master's log before chroot */ + master_log = getenv("MASTER_LOG"); + if (master_log == NULL) { + acl_msg_info("%s(%d): no MASTER_LOG's env value", myname, __LINE__); + } else { + acl_msg_open(master_log, procname); + var_master_log_opened = 1; + if (acl_msg_verbose) + acl_msg_info("%s(%d): service: %s, log opened now.", + myname, __LINE__, procname); + } +} + +void master_log_close() +{ + if (var_master_log_opened) { + acl_msg_close(); + var_master_log_opened = 0; + } +} +#endif diff --git a/lib_acl/src/master/template/acl_multi_server.c b/lib_acl/src/master/template/acl_multi_server.c new file mode 100644 index 000000000..54140d2b7 --- /dev/null +++ b/lib_acl/src/master/template/acl_multi_server.c @@ -0,0 +1,851 @@ +/* System library. */ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#endif + +#ifdef ACL_UNIX + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef STRCASECMP_IN_STRINGS_H +#include +#endif +#include + +/* Utility library. */ + +#include "stdlib/acl_msg.h" +#include "stdlib/unix/acl_chroot_uid.h" +#include "stdlib/acl_vstring.h" +#include "stdlib/acl_vstream.h" +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_iostuff.h" +#include "stdlib/acl_stringops.h" +#include "stdlib/acl_myflock.h" +#include "stdlib/unix/acl_watchdog.h" +#include "stdlib/acl_split_at.h" +#include "net/acl_listen.h" +#include "net/acl_tcp_ctl.h" +#include "event/acl_events.h" + +/* Global library. */ + +#include "../master_flow.h" +#include "../master_params.h" +#include "../master_proto.h" + +/* Application-specific */ +#include "master/acl_multi_params.h" +#include "master/acl_server_api.h" +#include "template.h" + +int acl_var_multi_pid; +char *acl_var_multi_procname; +char *acl_var_multi_log_file; + +int acl_var_multi_buf_size; +int acl_var_multi_rw_timeout; +int acl_var_multi_in_flow_delay; +int acl_var_multi_idle_limit; +char *acl_var_multi_queue_dir; +char *acl_var_multi_owner; +int acl_var_multi_delay_sec; +int acl_var_multi_delay_usec; +int acl_var_multi_daemon_timeout; +int acl_var_multi_use_limit; +char *acl_var_multi_pid_dir; +int acl_var_multi_enable_core; + +static ACL_CONFIG_INT_TABLE __conf_int_tab[] = { + { ACL_VAR_MULTI_BUF_SIZE, ACL_DEF_MULTI_BUF_SIZE, &acl_var_multi_buf_size, 0, 0 }, + { ACL_VAR_MULTI_RW_TIMEOUT, ACL_DEF_MULTI_RW_TIMEOUT, &acl_var_multi_rw_timeout, 0, 0 }, + { ACL_VAR_MULTI_IN_FLOW_DELAY, ACL_DEF_MULTI_IN_FLOW_DELAY, &acl_var_multi_in_flow_delay, 0, 0 }, + { ACL_VAR_MULTI_IDLE_LIMIT, ACL_DEF_MULTI_IDLE_LIMIT, &acl_var_multi_idle_limit, 0, 0 }, + { ACL_VAR_MULTI_DELAY_SEC, ACL_DEF_MULTI_DELAY_SEC, &acl_var_multi_delay_sec, 0, 0 }, + { ACL_VAR_MULTI_DELAY_USEC, ACL_DEF_MULTI_DELAY_USEC, &acl_var_multi_delay_usec, 0, 0 }, + { ACL_VAR_MULTI_DAEMON_TIMEOUT, ACL_DEF_MULTI_DAEMON_TIMEOUT, &acl_var_multi_daemon_timeout, 0, 0 }, + { ACL_VAR_MULTI_USE_LIMIT, ACL_DEF_MULTI_USE_LIMIT, &acl_var_multi_use_limit, 0, 0 }, + { ACL_VAR_MULTI_ENABLE_CORE, ACL_DEF_MULTI_ENABLE_CORE, &acl_var_multi_enable_core, 0, 0 }, + { 0, 0, 0, 0, 0 }, +}; + +static ACL_CONFIG_STR_TABLE __conf_str_tab[] = { + { ACL_VAR_MULTI_QUEUE_DIR, ACL_DEF_MULTI_QUEUE_DIR, &acl_var_multi_queue_dir }, + { ACL_VAR_MULTI_OWNER, ACL_DEF_MULTI_OWNER, &acl_var_multi_owner }, + { ACL_VAR_MULTI_PID_DIR, ACL_DEF_MULTI_PID_DIR, &acl_var_multi_pid_dir }, + { 0, 0, 0 }, +}; + + /* + * Global state. + */ +static int client_count; +static int use_count; +static int socket_count = 1; +static int listen_disabled = 0; + +static ACL_EVENT *__eventp = NULL; +static ACL_VSTREAM **__listen_streams = NULL; + +static void (*multi_server_service) (ACL_VSTREAM *, char *, char **); +static char *multi_server_name; +static char **multi_server_argv; +static void (*multi_server_accept) (int, void *); +static void (*multi_server_onexit) (char *, char **); +static void (*multi_server_pre_accept) (char *, char **); +static ACL_VSTREAM *multi_server_lock; +static int multi_server_in_flow_delay; +static unsigned multi_server_generation; +static void (*multi_server_pre_disconn) (ACL_VSTREAM *, char *, char **); +static int (*multi_server_on_accept)(ACL_VSTREAM *); + +/* add by zsx for rw timeout, 2005.9.25*/ +static void (*multi_server_rw_timer) (ACL_VSTREAM *); + +/* forward declare */ +static void multi_server_timeout(int event, void *context); + +ACL_EVENT *acl_multi_server_event() +{ + return (__eventp); +} + +/* add by zsx for rw timeout, 2005.9.25*/ +void acl_multi_server_request_rw_timer(ACL_VSTREAM *stream) +{ + const char *myname = "acl_multi_server_request_rw_timer"; + + if (stream == NULL) + acl_msg_fatal("%s(%d), %s: input error", + __FILE__, __LINE__, myname); + if (__eventp == NULL) + acl_msg_fatal("%s(%d), %s: event has not been inited", + __FILE__, __LINE__, myname); +} + +/* add by zsx for rw timeout, 2005.9.25*/ +void acl_multi_server_cancel_rw_timer(ACL_VSTREAM *stream) +{ + const char *myname = "acl_multi_server_cancel_rw_timer"; + + if (stream == NULL) + acl_msg_fatal("%s(%d), %s: input error", + __FILE__, __LINE__, myname); + if (__eventp == NULL) + acl_msg_fatal("%s(%d), %s: event has not been inited", + __FILE__, __LINE__, myname); +} + +static void disable_listen(void) +{ + int i; + + if (__listen_streams == NULL) + return; + + for (i = 0; __listen_streams[i] != NULL; i++) { + acl_event_disable_readwrite(__eventp, __listen_streams[i]); + acl_vstream_close(__listen_streams[i]); + __listen_streams[i] = NULL; + } + acl_myfree(__listen_streams); + __listen_streams = NULL; +} + +/* multi_server_exit - normal termination */ + +static void multi_server_exit(void) +{ + if (multi_server_onexit) + multi_server_onexit(multi_server_name, multi_server_argv); + exit(0); +} + +/* multi_server_abort - terminate after abnormal master exit */ + +static void multi_server_abort(int event acl_unused, void *context acl_unused) +{ + if (!listen_disabled) + listen_disabled = 1; + + if (client_count > 0) { + /* set idle timeout to 1 second */ + acl_var_multi_idle_limit = 1; + acl_event_request_timer(__eventp, multi_server_timeout, NULL, + (acl_int64) acl_var_multi_idle_limit * 1000000, 0); + return; + } + + if (acl_msg_verbose) + acl_msg_info("master disconnect -- exiting"); + multi_server_exit(); +} + +/* multi_server_timeout - idle time exceeded */ + +static void multi_server_timeout(int event acl_unused, void *context acl_unused) +{ + if (client_count > 0) { + /* set idle timeout to 1 second */ + acl_var_multi_idle_limit = 1; + acl_event_request_timer(__eventp, multi_server_timeout, NULL, + (acl_int64) acl_var_multi_idle_limit * 1000000, 0); + return; + } + + if (acl_msg_verbose) + acl_msg_info("idle timeout -- exiting"); + multi_server_exit(); +} + +/* acl_multi_server_drain - stop accepting new clients */ + +int acl_multi_server_drain(void) +{ + int i; + + switch (fork()) { + /* Try again later. */ + case -1: + return (-1); + /* Finish existing clients in the background, then terminate. */ + case 0: + if (__listen_streams == NULL) + acl_msg_fatal("%s(%d): __listen_streams null", + __FILE__, __LINE__); + + for (i = 0; __listen_streams[i] != NULL; i++) { + acl_event_disable_readwrite(__eventp, __listen_streams[i]); + acl_vstream_close(__listen_streams[i]); + __listen_streams[i] = NULL; + } + acl_var_multi_use_limit = 1; + return (0); + /* Let the master start a new process. */ + default: + exit(0); + } +} + +/* acl_multi_server_disconnect - terminate client session */ + +void acl_multi_server_disconnect(ACL_VSTREAM *stream) +{ + if (acl_msg_verbose) + acl_msg_info("connection closed fd %d", + ACL_VSTREAM_SOCK(stream)); + if (multi_server_pre_disconn) + multi_server_pre_disconn(stream, + multi_server_name, multi_server_argv); + acl_event_disable_readwrite(__eventp, stream); + (void) acl_vstream_fclose(stream); + client_count--; +} + +/* multi_server_execute - in case (char *) != (struct *) */ + +static void multi_server_execute(int event, void *context) +{ + const char *myname = "multi_server_execute"; + ACL_VSTREAM *stream = (ACL_VSTREAM *) context; + + if (multi_server_lock != 0 + && acl_myflock(ACL_VSTREAM_FILE(multi_server_lock), + ACL_INTERNAL_LOCK, ACL_MYFLOCK_OP_NONE) < 0) + { + acl_msg_fatal("%s(%d)->%s: select unlock: %s", + __FILE__, __LINE__, myname, strerror(errno)); + } + + /* + * Do not bother the application when the client disconnected. + */ + if (acl_vstream_peekfd(stream) > 0) { + if (acl_master_notify(acl_var_multi_pid, + multi_server_generation, ACL_MASTER_STAT_TAKEN) < 0) + { + multi_server_abort(ACL_EVENT_NULL_TYPE, + ACL_EVENT_NULL_CONTEXT); + } + multi_server_service(stream, multi_server_name, + multi_server_argv); + if (acl_master_notify(acl_var_multi_pid, + multi_server_generation, ACL_MASTER_STAT_AVAIL) < 0) + { + multi_server_abort(ACL_EVENT_NULL_TYPE, + ACL_EVENT_NULL_CONTEXT); + } + } else { + /* add by zsx for rw timeout, 2005.9.25*/ + if (event == ACL_EVENT_RW_TIMEOUT && multi_server_rw_timer) + multi_server_rw_timer(stream); + else + acl_multi_server_disconnect(stream); + } + if (client_count == 0 && acl_var_multi_idle_limit > 0) + acl_event_request_timer(__eventp, multi_server_timeout, NULL, + (acl_int64) acl_var_multi_idle_limit * 1000000, 0); +} + +/* multi_server_enable_read - enable read events */ + +static void __multi_server_enable_read(int event acl_unused, void *context) +{ + ACL_VSTREAM *stream = (ACL_VSTREAM *) context; + int ret; + + if (multi_server_on_accept != NULL) { + ret = multi_server_on_accept(stream); + if (ret < 0) { + acl_multi_server_disconnect(stream); + return; + } + } + + use_count++; + + acl_event_enable_read(__eventp, stream, acl_var_multi_rw_timeout, + multi_server_execute, (void *) stream); +} + +void acl_multi_server_enable_read(ACL_VSTREAM *stream) +{ + const char *myname = "acl_multi_server_enable_read"; + + if (stream == NULL || ACL_VSTREAM_SOCK(stream) < 0) { + acl_msg_error("%s(%d)->%s: input error", + __FILE__, __LINE__, myname); + } else { + client_count++; + acl_event_enable_read(__eventp, + stream, acl_var_multi_rw_timeout, + multi_server_execute, (void *) stream); + } +} + +/* multi_server_wakeup - wake up application */ + +static void multi_server_wakeup(int fd) +{ + ACL_VSTREAM *stream; + + if (acl_msg_verbose) + acl_msg_info("connection established fd %d", fd); + acl_non_blocking(fd, ACL_BLOCKING); + acl_close_on_exec(fd, ACL_CLOSE_ON_EXEC); + client_count++; + + stream = acl_vstream_fdopen(fd, O_RDWR, acl_var_multi_buf_size, + acl_var_multi_rw_timeout, ACL_VSTREAM_TYPE_SOCK); + + if (multi_server_in_flow_delay && acl_master_flow_get(1) < 0) + acl_event_request_timer(__eventp, + __multi_server_enable_read, (void *) stream, + (acl_int64) acl_var_multi_in_flow_delay* 1000000, 0); + else + __multi_server_enable_read(0, (void *) stream); +} + +#ifdef MASTER_XPORT_NAME_PASS + +/* multi_server_accept_pass - accept descriptor */ + +static void multi_server_accept_pass(int event acl_unused, void *context) +{ + ACL_VSTREAM *stream = (ACL_VSTREAM *) context; + int listen_fd = acl_vstream_fileno(stream), time_left = -1, fd; + + /* + * Be prepared for accept() to fail because some other process already + * got the connection (the number of processes competing for clients + * is kept small, so this is not a "thundering herd" problem). If the + * accept() succeeds, be sure to disable non-blocking I/O, in order to + * minimize confusion. + */ + if (client_count == 0 && acl_var_multi_idle_limit > 0) + time_left = (int) ((acl_event_cancel_timer(__evenpt, + multi_server_timeout, NULL) + 999999) / 1000000); + + if (multi_server_pre_accept) + multi_server_pre_accept(multi_server_name, multi_server_argv); + fd = PASS_ACCEPT(listen_fd); + if (multi_server_lock != 0 + && acl_myflock(ACL_VSTREAM_FILE(multi_server_lock), + ACL_INTERNAL_LOCK, ACL_MYFLOCK_OP_NONE) < 0) + { + acl_msg_fatal("select unlock: %s", strerror(errno)); + } + if (fd < 0) { + if (errno != EAGAIN) + acl_msg_fatal("accept connection: %s", strerror(errno)); + if (time_left >= 0) + acl_event_request_timer(__eventp, multi_server_timeout, + NULL, (acl_int64) time_left * 1000000, 0); + } else + multi_server_wakeup(fd); +} + +#endif + +/* multi_server_accept_sock - accept client connection request */ + +static void multi_server_accept_sock(int event acl_unused, void *context) +{ + ACL_VSTREAM *stream = (ACL_VSTREAM *) context; + int listen_fd = ACL_VSTREAM_SOCK(stream), time_left = -1, fd, sock_type; + + /* + * Be prepared for accept() to fail because some other process already + * got the connection (the number of processes competing for clients + * is kept small, so this is not a "thundering herd" problem). If the + * accept() succeeds, be sure to disable non-blocking I/O, in order to + * minimize confusion. + */ + if (client_count == 0 && acl_var_multi_idle_limit > 0) + time_left = (int) ((acl_event_cancel_timer(__eventp, + multi_server_timeout, NULL) + 9999999) / 1000000); + + if (multi_server_pre_accept) + multi_server_pre_accept(multi_server_name, multi_server_argv); + fd = acl_accept(listen_fd, NULL, 0, &sock_type); + if (multi_server_lock != 0 + && acl_myflock(ACL_VSTREAM_FILE(multi_server_lock), + ACL_INTERNAL_LOCK, ACL_MYFLOCK_OP_NONE) < 0) + { + acl_msg_fatal("select unlock: %s", strerror(errno)); + } + if (fd < 0) { + if (errno != EAGAIN) + acl_msg_fatal("accept connection: %s", strerror(errno)); + if (time_left >= 0) + acl_event_request_timer(__eventp, multi_server_timeout, + NULL, (acl_int64) time_left * 1000000, 0); + } else { + /* 避免发送延迟现象 */ + if (sock_type == AF_INET) + acl_tcp_set_nodelay(fd); + multi_server_wakeup(fd); + } +} + +static void multi_server_init(const char *procname) +{ + const char *myname = "multi_server_init"; + static int inited = 0; + + if (inited) + return; + + inited = 1; + + if (procname == NULL || *procname == 0) + acl_msg_fatal("%s(%d); procname null", myname, __LINE__); + + /* + * Don't die when a process goes away unexpectedly. + */ + signal(SIGPIPE, SIG_IGN); + + /* + * Don't die for frivolous reasons. + */ +#ifdef SIGXFSZ + signal(SIGXFSZ, SIG_IGN); +#endif + + /* + * May need this every now and then. + */ + acl_var_multi_pid = getpid(); + acl_var_multi_procname = acl_mystrdup(acl_safe_basename(procname)); + + acl_var_multi_log_file = getenv("SERVICE_LOG"); + if (acl_var_multi_log_file == NULL) { + acl_var_multi_log_file = acl_mystrdup("acl_master.log"); + acl_msg_warn("%s(%d)->%s: can't get MASTER_LOG's env value, use %s log", + __FILE__, __LINE__, myname, acl_var_multi_log_file); + } + + acl_get_app_conf_int_table(__conf_int_tab); + acl_get_app_conf_str_table(__conf_str_tab); + + acl_master_vars_init(acl_var_multi_buf_size, acl_var_multi_rw_timeout); +} + +static void multi_server_open_log(void) +{ + /* first, close the master's log */ + master_log_close(); + + /* second, open the service's log */ + acl_msg_open(acl_var_multi_log_file, acl_var_multi_procname); +} + +static void usage(int argc, char *argv[]) +{ + int i; + char *service_name; + + if (argc <= 0) + acl_msg_fatal("%s(%d): argc(%d) invalid", __FILE__, __LINE__, argc); + + service_name = acl_mystrdup(acl_safe_basename(argv[0])); + + for (i = 0; i < argc; i++) + acl_msg_info("argv[%d]: %s", i, argv[i]); + + acl_msg_info("usage: %s -h[help]" + " -c [use chroot]" + " -d [debug]" + " -l [run alone]" + " -n service_name" + " -s socket_count" + " -i [use stdin]" + " -t transport" + " -u [use setgid initgroups setuid]" + " -v [on acl_msg_verbose]" + " -z [unlimit process count]" + " -f conf_file", + service_name); +} + +/* acl_multi_server_main - the real main program */ + +void acl_multi_server_main(int argc, char **argv, ACL_MULTI_SERVER_FN service,...) +{ + const char *myname = "acl_multi_server_main"; + ACL_VSTREAM *stream = 0; + char *root_dir = 0; + char *user_name = 0; + char *service_name = acl_mystrdup(acl_safe_basename(argv[0])); + int c; + va_list ap; + ACL_MASTER_SERVER_INIT_FN pre_init = 0; + ACL_MASTER_SERVER_INIT_FN post_init = 0; + ACL_MASTER_SERVER_LOOP_FN loop = 0; + int key; + char *transport = 0; + int alone = 0; + int zerolimit = 0; + ACL_WATCHDOG *watchdog; + char *generation; + int fd, i, fdtype = 0; + + int f_flag = 0; + char *conf_file_ptr = 0; + + if (acl_msg_verbose) + acl_msg_info("%s(%d): daemon started, log = %s", + acl_var_multi_procname, __LINE__, acl_var_multi_log_file); + + /* + * Pick up policy settings from master process. Shut up error messages to + * stderr, because no-one is going to see them. + */ + opterr = 0; + while ((c = getopt(argc, argv, "hcdlm:n:s:it:uvzf:")) > 0) { + switch (c) { + case 'h': + usage(argc, argv); + exit (0); + case 'f': + acl_app_conf_load(optarg); + f_flag = 1; + conf_file_ptr = optarg; + break; + case 'c': + root_dir = "setme"; + break; + case 'l': + alone = 1; + break; + case 'n': + service_name = optarg; + break; + case 's': + if ((socket_count = atoi(optarg)) <= 0) + acl_msg_fatal("invalid socket_count: %s", optarg); + break; + case 'i': + stream = ACL_VSTREAM_IN; + break; + case 'u': + user_name = "setme"; + break; + case 't': + transport = optarg; + break; + case 'v': + acl_msg_verbose++; + break; + case 'z': + zerolimit = 1; + break; + default: + break; + } + } + + if (stream == NULL) + multi_server_init(argv[0]); + + if (f_flag == 0) + acl_msg_fatal("%s(%d)->%s: need \"-f pathname\"", + __FILE__, __LINE__, myname); + else if (acl_msg_verbose) + acl_msg_info("%s(%d)->%s: configure file = %s", + __FILE__, __LINE__, myname, conf_file_ptr); + + /* + * Application-specific initialization. + */ + va_start(ap, service); + while ((key = va_arg(ap, int)) != 0) { + switch (key) { + case ACL_MASTER_SERVER_INT_TABLE: + acl_get_app_conf_int_table(va_arg(ap, ACL_CONFIG_INT_TABLE *)); + break; + case ACL_MASTER_SERVER_INT64_TABLE: + acl_get_app_conf_int64_table(va_arg(ap, ACL_CONFIG_INT64_TABLE *)); + break; + case ACL_MASTER_SERVER_STR_TABLE: + acl_get_app_conf_str_table(va_arg(ap, ACL_CONFIG_STR_TABLE *)); + break; + case ACL_MASTER_SERVER_BOOL_TABLE: + acl_get_app_conf_bool_table(va_arg(ap, ACL_CONFIG_BOOL_TABLE *)); + break; + + case ACL_MASTER_SERVER_PRE_INIT: + pre_init = va_arg(ap, ACL_MASTER_SERVER_INIT_FN); + break; + case ACL_MASTER_SERVER_POST_INIT: + post_init = va_arg(ap, ACL_MASTER_SERVER_INIT_FN); + break; + case ACL_MASTER_SERVER_LOOP: + loop = va_arg(ap, ACL_MASTER_SERVER_LOOP_FN); + break; + case ACL_MASTER_SERVER_EXIT: + multi_server_onexit = va_arg(ap, ACL_MASTER_SERVER_EXIT_FN); + break; + case ACL_MASTER_SERVER_PRE_ACCEPT: + multi_server_pre_accept = va_arg(ap, ACL_MASTER_SERVER_ACCEPT_FN); + break; + case ACL_MASTER_SERVER_PRE_DISCONN: + multi_server_pre_disconn = va_arg(ap, ACL_MASTER_SERVER_DISCONN_FN); + break; + case ACL_MASTER_SERVER_ON_ACCEPT: + multi_server_on_accept = va_arg(ap, ACL_MASTER_SERVER_ON_ACCEPT_FN); + break; + + /* add by zsx for rw timeout, 2005.9.25*/ + case ACL_MASTER_SERVER_RW_TIMER: + multi_server_rw_timer = va_arg(ap, ACL_MASTER_SERVER_RW_TIMER_FN); + break; /* bugfix, I forgot add 'break' here, sorry, 2005.9.26 */ + + case ACL_MASTER_SERVER_IN_FLOW_DELAY: + multi_server_in_flow_delay = 1; + break; + case ACL_MASTER_SERVER_SOLITARY: + if (!alone) + acl_msg_fatal("service %s requires a process limit of 1", + service_name); + break; + case ACL_MASTER_SERVER_UNLIMITED: + if (!zerolimit) + acl_msg_fatal("service %s requires a process limit of 0", + service_name); + break; + case ACL_MASTER_SERVER_PRIVILEGED: + if (user_name) + acl_msg_fatal("service %s requires privileged operation", + service_name); + break; + default: + acl_msg_panic("%s: unknown argument type: %d", myname, key); + } + } + va_end(ap); + + if (root_dir) + root_dir = acl_var_multi_queue_dir; + if (user_name) + user_name = acl_var_multi_owner; + + /* + * If not connected to stdin, stdin must not be a terminal. + */ + if (stream == 0 && isatty(STDIN_FILENO)) + acl_msg_fatal("%s(%d)->%s: do not run this command by hand", + __FILE__, __LINE__, myname); + + /* + * Can options be required? + */ + if (stream == 0) { + if (transport == 0) + acl_msg_fatal("no transport type specified"); + if (strcasecmp(transport, ACL_MASTER_XPORT_NAME_INET) == 0) { + multi_server_accept = multi_server_accept_sock; + fdtype = ACL_VSTREAM_TYPE_LISTEN | ACL_VSTREAM_TYPE_LISTEN_INET; + } else if (strcasecmp(transport, ACL_MASTER_XPORT_NAME_UNIX) == 0) { + multi_server_accept = multi_server_accept_sock; + fdtype = ACL_VSTREAM_TYPE_LISTEN | ACL_VSTREAM_TYPE_LISTEN_UNIX; + } else if (strcasecmp(transport, ACL_MASTER_XPORT_NAME_SOCK) == 0) { + multi_server_accept = multi_server_accept_sock; + fdtype = ACL_VSTREAM_TYPE_LISTEN | ACL_VSTREAM_TYPE_LISTEN_INET; +#ifdef MASTER_XPORT_NAME_PASS + } else if (strcasecmp(transport, ACL_MASTER_XPORT_NAME_PASS) == 0) { + multi_server_accept = multi_server_accept_pass; + fdtype = ACL_VSTREAM_TYPE_LISTEN; +#endif + } else + acl_msg_fatal("unsupported transport type: %s", transport); + } + + /* + * Retrieve process generation from environment. + */ + if ((generation = getenv(ACL_MASTER_GEN_NAME)) != 0) { + if (!acl_alldig(generation)) + acl_msg_fatal("bad generation: %s", generation); + sscanf(generation, "%o", &multi_server_generation); + if (acl_msg_verbose) + acl_msg_info("process generation: %s (%o)", + generation, multi_server_generation); + } + + /* + * Traditionally, BSD select() can't handle multiple processes selecting + * on the same socket, and wakes up every process in select(). See TCP/IP + * Illustrated volume 2 page 532. We avoid select() collisions with an + * external lock file. + */ + + /* + * Set up call-back info. + */ + multi_server_service = service; + multi_server_name = service_name; + multi_server_argv = argv + optind; + + __eventp = acl_event_new_select(acl_var_multi_delay_sec, + acl_var_multi_delay_usec); + + /* + * Run pre-jail initialization. + */ + if (chdir(acl_var_multi_queue_dir) < 0) + acl_msg_fatal("chdir(\"%s\"): %s", acl_var_multi_queue_dir, + strerror(errno)); + if (pre_init) + pre_init(multi_server_name, multi_server_argv); + + acl_chroot_uid(root_dir, user_name); + /* 设置子进程运行环境,允许产生 core 文件 */ + if (acl_var_multi_enable_core) + set_core_limit(); + multi_server_open_log(); + + /* + * Run post-jail initialization. + */ + if (post_init) + post_init(multi_server_name, multi_server_argv); + + /* + * Are we running as a one-shot server with the client connection on + * standard input? If so, make sure the output is written to stdout so as + * to satisfy common expectation. + */ + if (stream != 0) { + while (1) + service(stream, multi_server_name, multi_server_argv); + /* not reached here */ + multi_server_exit(); + } + + /* + * Running as a semi-resident server. Service connection requests. + * Terminate when we have serviced a sufficient number of clients, when + * no-one has been talking to us for a configurable amount of time, or + * when the master process terminated abnormally. + */ + if (acl_var_multi_idle_limit > 0) + acl_event_request_timer(__eventp, multi_server_timeout, + NULL, (acl_int64) acl_var_multi_idle_limit * 1000000, 0); + + /* socket count is as same listen_fd_count in parent process */ + + __listen_streams = (ACL_VSTREAM **) + acl_mycalloc(socket_count + 1, sizeof(ACL_VSTREAM *)); + for (i = 0; i < socket_count + 1; i++) + __listen_streams[i] = NULL; + + i = 0; + fd = ACL_MASTER_LISTEN_FD; + for (; fd < ACL_MASTER_LISTEN_FD + socket_count; fd++) { + stream = acl_vstream_fdopen(fd, O_RDWR, acl_var_multi_buf_size, + acl_var_multi_rw_timeout, fdtype); + if (stream == NULL) + acl_msg_fatal("%s(%d)->%s: stream null, fd = %d", + __FILE__, __LINE__, myname, fd); + + acl_event_enable_read(__eventp, stream, 0, + multi_server_accept, stream); + acl_close_on_exec(ACL_VSTREAM_SOCK(stream), ACL_CLOSE_ON_EXEC); + __listen_streams[i] = stream; + } + + acl_event_enable_read(__eventp, ACL_MASTER_STAT_STREAM, 0, + multi_server_abort, (void *) 0); + acl_close_on_exec(ACL_MASTER_STATUS_FD, ACL_CLOSE_ON_EXEC); + acl_close_on_exec(ACL_MASTER_FLOW_READ, ACL_CLOSE_ON_EXEC); + acl_close_on_exec(ACL_MASTER_FLOW_WRITE, ACL_CLOSE_ON_EXEC); + watchdog = acl_watchdog_create(acl_var_multi_daemon_timeout, + (ACL_WATCHDOG_FN) 0, (char *) 0); + + /* + * The event loop, at last. + */ + while (acl_var_multi_use_limit == 0 + || use_count < acl_var_multi_use_limit + || client_count > 0) + { + int delay_sec; + + if (multi_server_lock != 0) { + acl_watchdog_stop(watchdog); + if (acl_myflock(ACL_VSTREAM_FILE(multi_server_lock), + ACL_INTERNAL_LOCK, ACL_MYFLOCK_OP_EXCLUSIVE) < 0) + { + acl_msg_fatal("select lock: %s", strerror(errno)); + } + } + acl_watchdog_start(watchdog); + delay_sec = loop ? loop(multi_server_name, multi_server_argv) : -1; + acl_event_set_delay_sec(__eventp, delay_sec); + acl_event_loop(__eventp); + if (listen_disabled == 1) { + listen_disabled = 2; + disable_listen(); + } + } + multi_server_exit(); +} + +#endif /* ACL_UNIX */ diff --git a/lib_acl/src/master/template/acl_single_server.c b/lib_acl/src/master/template/acl_single_server.c new file mode 100644 index 000000000..c15bb9562 --- /dev/null +++ b/lib_acl/src/master/template/acl_single_server.c @@ -0,0 +1,696 @@ +/* System library. */ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#endif + +#ifdef ACL_UNIX + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef STRCASECMP_IN_STRINGS_H +#include +#endif +#include + +/* Utility library. */ + +#include "stdlib/acl_msg.h" +#include "stdlib/unix/acl_chroot_uid.h" +#include "stdlib/acl_vstring.h" +#include "stdlib/acl_vstream.h" +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_iostuff.h" +#include "stdlib/acl_stringops.h" +#include "stdlib/acl_myflock.h" +#include "stdlib/unix/acl_watchdog.h" +#include "stdlib/acl_split_at.h" +#include "stdlib/unix/acl_safe_open.h" +#include "net/acl_listen.h" +#include "net/acl_tcp_ctl.h" +#include "net/acl_sane_socket.h" +#include "event/acl_events.h" + +/* Global library. */ + +#include "../master_flow.h" +#include "../master_params.h" +#include "../master_proto.h" + +/* Application-specific */ +#include "master/acl_single_params.h" +#include "master/acl_server_api.h" +#include "template.h" + +int acl_var_single_pid; +char *acl_var_single_procname; +char *acl_var_single_log_file; +char *acl_var_single_pid_dir; + +int acl_var_single_buf_size; +int acl_var_single_rw_timeout; +int acl_var_single_in_flow_delay; +int acl_var_single_idle_limit; +char *acl_var_single_queue_dir; +char *acl_var_single_owner; +int acl_var_single_delay_sec; +int acl_var_single_delay_usec; +int acl_var_single_daemon_timeout; +int acl_var_single_use_limit; +int acl_var_single_enable_core; + +static ACL_CONFIG_INT_TABLE __conf_int_tab[] = { + { ACL_VAR_SINGLE_BUF_SIZE, ACL_DEF_SINGLE_BUF_SIZE, &acl_var_single_buf_size, 0, 0 }, + { ACL_VAR_SINGLE_RW_TIMEOUT, ACL_DEF_SINGLE_RW_TIMEOUT, &acl_var_single_rw_timeout, 0, 0 }, + { ACL_VAR_SINGLE_IN_FLOW_DELAY, ACL_DEF_SINGLE_IN_FLOW_DELAY, &acl_var_single_in_flow_delay, 0, 0 }, + { ACL_VAR_SINGLE_IDLE_LIMIT, ACL_DEF_SINGLE_IDLE_LIMIT, &acl_var_single_idle_limit, 0, 0 }, + { ACL_VAR_SINGLE_DELAY_SEC, ACL_DEF_SINGLE_DELAY_SEC, &acl_var_single_delay_sec, 0, 0 }, + { ACL_VAR_SINGLE_DELAY_USEC, ACL_DEF_SINGLE_DELAY_USEC, &acl_var_single_delay_usec, 0, 0 }, + { ACL_VAR_SINGLE_DAEMON_TIMEOUT, ACL_DEF_SINGLE_DAEMON_TIMEOUT, &acl_var_single_daemon_timeout, 0, 0 }, + { ACL_VAR_SINGLE_USE_LIMIT, ACL_DEF_SINGLE_USE_LIMIT, &acl_var_single_use_limit, 0, 0 }, + { ACL_VAR_SINGLE_ENABLE_CORE, ACL_DEF_SINGLE_ENABLE_CORE, &acl_var_single_enable_core, 0, 0 }, + { 0, 0, 0, 0, 0 }, +}; + +static ACL_CONFIG_STR_TABLE __conf_str_tab[] = { + { ACL_VAR_SINGLE_QUEUE_DIR, ACL_DEF_SINGLE_QUEUE_DIR, &acl_var_single_queue_dir }, + { ACL_VAR_SINGLE_OWNER, ACL_DEF_SINGLE_OWNER, &acl_var_single_owner }, + { ACL_VAR_SINGLE_PID_DIR, ACL_DEF_SINGLE_PID_DIR, &acl_var_single_pid_dir }, + { 0, 0, 0 }, +}; + + /* + * Global state. + */ +static int use_count; +static ACL_EVENT *__eventp = NULL; +static ACL_VSTREAM **__stream_array; + +static void (*single_server_service) (ACL_VSTREAM *, char *, char **); +static char *single_server_name; +static char **single_server_argv; +static void (*single_server_accept) (int, void *); +static void (*single_server_onexit) (char *, char **); +static void (*single_server_pre_accept) (char *, char **); +static ACL_VSTREAM *single_server_lock; +static int single_server_in_flow_delay; +static unsigned single_server_generation; + +ACL_EVENT *acl_single_server_event() +{ + return (__eventp); +} + +/* single_server_exit - normal termination */ + +static void single_server_exit(void) +{ + if (single_server_onexit) + single_server_onexit(single_server_name, single_server_argv); + exit(0); +} + +/* single_server_abort - terminate after abnormal master exit */ + +static void single_server_abort(int event acl_unused, void *context acl_unused) +{ + if (acl_msg_verbose) + acl_msg_info("master disconnect -- exiting"); + single_server_exit(); +} + +/* single_server_timeout - idle time exceeded */ + +static void single_server_timeout(int event acl_unused, void *context acl_unused) +{ + if (acl_msg_verbose) + acl_msg_info("idle timeout -- exiting"); + single_server_exit(); +} + +/* single_server_wakeup - wake up application */ + +static void single_server_wakeup(int fd, + const char *remote_addr, const char *local_addr) +{ + const char *myname = "single_server_wakeup"; + ACL_VSTREAM *stream; + + /* + * If the accept() succeeds, be sure to disable non-blocking I/O, + * because the application is supposed to be single-threaded. + * Notice the master of our (un)availability to service connection + * requests. Commit suicide when the master process disconnected + * from us. + */ + if (acl_msg_verbose) + acl_msg_info("%s(%d), %s: connection established, fd = %d", + __FILE__, __LINE__, myname, fd); + acl_non_blocking(fd, ACL_BLOCKING); + acl_close_on_exec(fd, ACL_CLOSE_ON_EXEC); + stream = acl_vstream_fdopen(fd, O_RDWR, acl_var_single_buf_size, + acl_var_single_rw_timeout, ACL_VSTREAM_TYPE_SOCK); + if (remote_addr) + ACL_SAFE_STRNCPY(stream->remote_addr, remote_addr, + sizeof(stream->remote_addr)); + if (local_addr) + ACL_SAFE_STRNCPY(stream->local_addr, local_addr, + sizeof(stream->local_addr)); + + if (acl_master_notify(acl_var_single_pid, single_server_generation, + ACL_MASTER_STAT_TAKEN) < 0) + { + single_server_abort(ACL_EVENT_NULL_TYPE, ACL_EVENT_NULL_CONTEXT); + } + if (single_server_in_flow_delay && acl_master_flow_get(1) < 0) + acl_doze(acl_var_single_in_flow_delay * 1000); + single_server_service(stream, single_server_name, single_server_argv); + (void) acl_vstream_fclose(stream); + if (acl_master_notify(acl_var_single_pid, single_server_generation, + ACL_MASTER_STAT_AVAIL) < 0) + { + single_server_abort(ACL_EVENT_NULL_TYPE, ACL_EVENT_NULL_CONTEXT); + } + if (acl_msg_verbose) + acl_msg_info("%s(%d), %s: connection closed, fd = %d", + __FILE__, __LINE__, myname, fd); + use_count++; + if (acl_var_single_idle_limit > 0) + acl_event_request_timer(__eventp, single_server_timeout, NULL, + (acl_int64) acl_var_single_idle_limit * 1000000, 0); +} + +#ifdef MASTER_XPORT_NAME_PASS + +/* single_server_accept_pass - accept descriptor */ + +static void single_server_accept_pass(int event acl_unused, void *context) +{ + ACL_VSTREAM *stream = (ACL_VSTREAM *) context; + int listen_fd = ACL_VSTREAM_SOCK(stream); + int time_left = -1; + int fd; + + /* + * Be prepared for accept() to fail because some other process already + * got the connection. We use select() + accept(), instead of simply + * blocking in accept(), because we must be able to detect that the + * master process has gone away unexpectedly. + */ + if (acl_var_single_idle_limit > 0) + time_left = (int) ((acl_event_cancel_timer(__eventp, + single_server_timeout, NULL) + 999999) / 1000000); + + if (single_server_pre_accept) + single_server_pre_accept(single_server_name, single_server_argv); + fd = PASS_ACCEPT(listen_fd); + if (single_server_lock != 0 + && acl_myflock(ACL_VSTREAM_FILE(single_server_lock), + ACL_INTERNAL_LOCK, ACL_MYFLOCK_OP_NONE) < 0) + { + acl_msg_fatal("select unlock: %s", strerror(errno)); + } + if (fd < 0) { + if (errno != EAGAIN) + acl_msg_fatal("accept connection: %s", strerror(errno)); + if (time_left >= 0) + acl_event_request_timer(__eventp, single_server_timeout, + NULL, (acl_int64) time_left * 1000000, 0); + } else + single_server_wakeup(fd, NULL, NULL); +} + +#endif + +/* single_server_accept_sock - accept client connection request */ + +static void single_server_accept_sock(int event acl_unused, void *context) +{ + ACL_VSTREAM *stream = (ACL_VSTREAM *) context; + int listen_fd = ACL_VSTREAM_SOCK(stream); + int time_left = -1, fd, sock_type; + char remote_addr[64], local_addr[64]; + + /* + * Be prepared for accept() to fail because some other process already + * got the connection. We use select() + accept(), instead of simply + * blocking in accept(), because we must be able to detect that the + * master process has gone away unexpectedly. + */ + if (acl_var_single_idle_limit > 0) + time_left = (int) ((acl_event_cancel_timer(__eventp, + single_server_timeout, NULL) + 999999) / 1000000); + + if (single_server_pre_accept) + single_server_pre_accept(single_server_name, single_server_argv); + fd = acl_accept(listen_fd, remote_addr, sizeof(remote_addr), &sock_type); + if (single_server_lock != 0 + && acl_myflock(ACL_VSTREAM_FILE(single_server_lock), + ACL_INTERNAL_LOCK, ACL_MYFLOCK_OP_NONE) < 0) + { + acl_msg_fatal("select unlock: %s", strerror(errno)); + } + + if (fd < 0) { + if (errno != EAGAIN) + acl_msg_fatal("accept connection: %s", strerror(errno)); + if (time_left > 0) + acl_event_request_timer(__eventp, single_server_timeout, + NULL, (acl_int64) time_left * 1000000, 0); + return; + } + + if (sock_type == AF_INET) + acl_tcp_set_nodelay(fd); + + if (acl_getsockname(fd, local_addr, sizeof(local_addr)) < 0) + memset(local_addr, 0, sizeof(local_addr)); + + single_server_wakeup(fd, remote_addr, local_addr); +} + +static void single_server_init(const char *procname) +{ + const char *myname = "single_server_init"; + static int inited = 0; + + if (inited) + return; + + if (procname == NULL || *procname == 0) + acl_msg_fatal("%s(%d); procname null", myname, __LINE__); + + /* + * Don't die when a process goes away unexpectedly. + */ + signal(SIGPIPE, SIG_IGN); + + /* + * Don't die for frivolous reasons. + */ +#ifdef SIGXFSZ + signal(SIGXFSZ, SIG_IGN); +#endif + + /* + * May need this every now and then. + */ + acl_var_single_pid = getpid(); + acl_var_single_procname = acl_mystrdup(acl_safe_basename(procname)); + + acl_var_single_log_file = getenv("SERVICE_LOG"); + if (acl_var_single_log_file == NULL) { + acl_var_single_log_file = acl_mystrdup("acl_master.log"); + acl_msg_fatal("%s(%d)->%s: can't get MASTER_LOG's env value, use %s log", + __FILE__, __LINE__, myname, acl_var_single_log_file); + } + + acl_get_app_conf_int_table(__conf_int_tab); + acl_get_app_conf_str_table(__conf_str_tab); + + acl_master_vars_init(acl_var_single_buf_size, acl_var_single_rw_timeout); +} + +static void single_server_open_log(const char *proc) +{ + /* first, close the master's log */ + acl_msg_info("service: %s detach acl_master's log now", proc); + master_log_close(); + + /* second, open the service's log */ + acl_msg_open(acl_var_single_log_file, acl_var_single_procname); +} + +static void usage(int argc, char *argv[]) +{ + int i; + char *service_name; + + if (argc <= 0) + acl_msg_fatal("%s(%d): argc(%d) invalid", __FILE__, __LINE__, argc); + + service_name = acl_mystrdup(acl_safe_basename(argv[0])); + + for (i = 0; i < argc; i++) + acl_msg_info("argv[%d]: %s", i, argv[i]); + + acl_msg_info("usage: %s -h[help]" + " -c [use chroot]" + " -d [debug]" + " -l [run alone]" + " -n service_name" + " -s socket_count" + " -i [use stdin]" + " -t transport" + " -u [use setgid initgroups setuid]" + " -v [on acl_msg_verbose]" + " -z [unlimit process count]" + " -f conf_file", + service_name); +} + +/* acl_single_server_main - the real main program */ + +void acl_single_server_main(int argc, char **argv, ACL_SINGLE_SERVER_FN service,...) +{ + const char *myname = "single_server_main"; + ACL_VSTREAM *stream = 0; + char *root_dir = 0; + char *user_name = 0; + char *service_name = acl_mystrdup(acl_safe_basename(argv[0])); + int c; + int socket_count = 1; + int fd, fdtype = 0; + va_list ap; + ACL_MASTER_SERVER_INIT_FN pre_init = 0; + ACL_MASTER_SERVER_INIT_FN post_init = 0; + ACL_MASTER_SERVER_LOOP_FN loop = 0; + int key; + char *transport = 0; + char *lock_path; + ACL_VSTRING *why; + int alone = 0; + int zerolimit = 0; + ACL_WATCHDOG *watchdog; + char *generation; + + int f_flag = 0; + char *conf_file_ptr = 0; + + /* + * Pick up policy settings from master process. Shut up error messages to + * stderr, because no-one is going to see them. + */ + opterr = 0; + while ((c = getopt(argc, argv, "hcdlm:n:s:it:uvzf:")) > 0) { + switch (c) { + case 'h': + usage(argc, argv); + exit (0); + case 'f': + acl_app_conf_load(optarg); + f_flag = 1; + conf_file_ptr = optarg; + break; + case 'c': + root_dir = "setme"; + break; + case 'l': + alone = 1; + break; + case 'n': + service_name = optarg; + break; + case 's': + if ((socket_count = atoi(optarg)) <= 0) + acl_msg_fatal("invalid socket_count: %s", optarg); + break; + case 'i': + stream = ACL_VSTREAM_IN; + break; + case 'u': + user_name = "setme"; + break; + case 't': + transport = optarg; + break; + case 'v': + acl_msg_verbose++; + break; + case 'z': + zerolimit = 1; + break; + default: + break; + } + } + + if (stream == NULL) + single_server_init(argv[0]); + + /* 提前进行模板初始化,以使日志尽早地打开, 开始先使用 acl_master 的日志文件 */ + acl_master_log_open(argv[0]); + + acl_msg_info("%s(%d): daemon started, log=%s", + acl_var_single_procname, __LINE__, acl_var_single_log_file); + + if (f_flag == 0) + acl_msg_fatal("%s(%d)->%s: need \"-f pathname\"", + __FILE__, __LINE__, myname); + else if (acl_msg_verbose) + acl_msg_info("%s(%d)->%s: configure file = %s", + __FILE__, __LINE__, myname, conf_file_ptr); + + /* + * Application-specific initialization. + */ + va_start(ap, service); + while ((key = va_arg(ap, int)) != 0) { + switch (key) { + case ACL_MASTER_SERVER_INT_TABLE: + acl_get_app_conf_int_table(va_arg(ap, ACL_CONFIG_INT_TABLE *)); + break; + case ACL_MASTER_SERVER_INT64_TABLE: + acl_get_app_conf_int64_table(va_arg(ap, ACL_CONFIG_INT64_TABLE *)); + break; + case ACL_MASTER_SERVER_STR_TABLE: + acl_get_app_conf_str_table(va_arg(ap, ACL_CONFIG_STR_TABLE *)); + break; + case ACL_MASTER_SERVER_BOOL_TABLE: + acl_get_app_conf_bool_table(va_arg(ap, ACL_CONFIG_BOOL_TABLE *)); + break; + + case ACL_MASTER_SERVER_PRE_INIT: + pre_init = va_arg(ap, ACL_MASTER_SERVER_INIT_FN); + break; + case ACL_MASTER_SERVER_POST_INIT: + post_init = va_arg(ap, ACL_MASTER_SERVER_INIT_FN); + break; + case ACL_MASTER_SERVER_LOOP: + loop = va_arg(ap, ACL_MASTER_SERVER_LOOP_FN); + break; + case ACL_MASTER_SERVER_EXIT: + single_server_onexit = va_arg(ap, ACL_MASTER_SERVER_EXIT_FN); + break; + case ACL_MASTER_SERVER_PRE_ACCEPT: + single_server_pre_accept = va_arg(ap, ACL_MASTER_SERVER_ACCEPT_FN); + break; + + case ACL_MASTER_SERVER_IN_FLOW_DELAY: + single_server_in_flow_delay = 1; + break; + case ACL_MASTER_SERVER_SOLITARY: + if (!alone) + acl_msg_fatal("service %s requires a process limit of 1", + service_name); + break; + case ACL_MASTER_SERVER_UNLIMITED: + if (!zerolimit) + acl_msg_fatal("service %s requires a process limit of 0", + service_name); + break; + case ACL_MASTER_SERVER_PRIVILEGED: + if (user_name) + acl_msg_fatal("service %s requires privileged operation", + service_name); + break; + default: + acl_msg_panic("%s: unknown argument type: %d", myname, key); + } + } + + va_end(ap); + + if (root_dir) + root_dir = acl_var_single_queue_dir; + if (user_name) + user_name = acl_var_single_owner; + + /* + * If not connected to stdin, stdin must not be a terminal. + */ + if (stream == 0 && isatty(STDIN_FILENO)) + acl_msg_fatal("%s(%d)->%s: do not run this command by hand", + __FILE__, __LINE__, myname); + + /* + * Can options be required? + */ + if (stream == 0) { + if (transport == 0) + acl_msg_fatal("no transport type specified"); + if (strcasecmp(transport, ACL_MASTER_XPORT_NAME_INET) == 0) { + single_server_accept = single_server_accept_sock; + fdtype = ACL_VSTREAM_TYPE_LISTEN | ACL_VSTREAM_TYPE_LISTEN_INET; + } else if (strcasecmp(transport, ACL_MASTER_XPORT_NAME_UNIX) == 0) { + single_server_accept = single_server_accept_sock; + fdtype = ACL_VSTREAM_TYPE_LISTEN | ACL_VSTREAM_TYPE_LISTEN_UNIX; + } else if (strcasecmp(transport, ACL_MASTER_XPORT_NAME_SOCK) == 0) { + single_server_accept = single_server_accept_sock; + fdtype = ACL_VSTREAM_TYPE_LISTEN | ACL_VSTREAM_TYPE_LISTEN_INET; +#ifdef MASTER_XPORT_NAME_PASS + } else if (strcasecmp(transport, ACL_MASTER_XPORT_NAME_PASS) == 0) { + single_server_accept = single_server_accept_pass; + fdtype = ACL_VSTREAM_TYPE_LISTEN; +#endif + } else + acl_msg_fatal("unsupported transport type: %s", transport); + } + + /* + * Retrieve process generation from environment. + */ + if ((generation = getenv(ACL_MASTER_GEN_NAME)) != 0) { + if (!acl_alldig(generation)) + acl_msg_fatal("bad generation: %s", generation); + sscanf(generation, "%o", &single_server_generation); + if (acl_msg_verbose) + acl_msg_info("process generation: %s (%o)", + generation, single_server_generation); + } + + /* + * Traditionally, BSD select() can't handle multiple processes selecting + * on the same socket, and wakes up every process in select(). See TCP/IP + * Illustrated volume 2 page 532. We avoid select() collisions with an + * external lock file. + */ + if (stream == 0 && !alone) { + lock_path = acl_concatenate(acl_var_single_pid_dir, "/", + transport, ".", service_name, (char *) 0); + why = acl_vstring_alloc(1); + if ((single_server_lock = acl_safe_open(lock_path, + O_CREAT | O_RDWR, 0600, (struct stat *) 0, + (uid_t)-1, (uid_t )-1, why)) == 0) + { + acl_msg_fatal("open lock file %s: %s", + lock_path, acl_vstring_str(why)); + } + + acl_close_on_exec(ACL_VSTREAM_FILE(single_server_lock), + ACL_CLOSE_ON_EXEC); + acl_myfree(lock_path); + acl_vstring_free(why); + } + + /* + * Set up call-back info. + */ + single_server_service = service; + single_server_name = service_name; + single_server_argv = argv + optind; + + __eventp = acl_event_new_select(acl_var_single_delay_sec, + acl_var_single_delay_usec); + + /* + * Run pre-jail initialization. + */ + + if (chdir(acl_var_single_queue_dir) < 0) + acl_msg_fatal("%s(%d)->%s: chdir(\"%s\"): %s", __FILE__, + __LINE__, myname, acl_var_single_queue_dir, strerror(errno)); + + if (pre_init) + pre_init(single_server_name, single_server_argv); + +#ifdef SNAPSHOT + tzset(); +#endif + acl_chroot_uid(root_dir, user_name); + /* 设置子进程运行环境,允许产生 core 文件 */ + if (acl_var_single_enable_core) + set_core_limit(); + single_server_open_log(argv[0]); + + /* + * Run post-jail initialization. + */ + if (post_init) + post_init(single_server_name, single_server_argv); + + /* + * Are we running as a one-shot server with the client connection on + * standard input? If so, make sure the output is written to stdout so as + * to satisfy common expectation. + */ + if (stream != 0) { + service(stream, single_server_name, single_server_argv); + single_server_exit(); + } + + /* + * Running as a semi-resident server. Service connection requests. + * Terminate when we have serviced a sufficient number of clients, when + * no-one has been talking to us for a configurable amount of time, or + * when the master process terminated abnormally. + */ + if (acl_var_single_idle_limit > 0) + acl_event_request_timer(__eventp, single_server_timeout, NULL, + (acl_int64) acl_var_single_idle_limit * 1000000, 0); + + __stream_array = (ACL_VSTREAM **) acl_mycalloc( + ACL_MASTER_LISTEN_FD + socket_count, sizeof(ACL_VSTREAM *)); + + fd = ACL_MASTER_LISTEN_FD; + for (; fd < ACL_MASTER_LISTEN_FD + socket_count; fd++) { + stream = acl_vstream_fdopen(fd, O_RDWR, acl_var_single_buf_size, + acl_var_single_rw_timeout, fdtype); + if (stream == NULL) + acl_msg_fatal("%s(%d)->%s: stream null, fd = %d", + __FILE__, __LINE__, myname, fd); + + acl_event_enable_read(__eventp, stream, 0, + single_server_accept, stream); + acl_close_on_exec(ACL_VSTREAM_SOCK(stream), ACL_CLOSE_ON_EXEC); + } + + acl_event_enable_read(__eventp, ACL_MASTER_STAT_STREAM, 0, + single_server_abort, NULL); + acl_close_on_exec(ACL_MASTER_STATUS_FD, ACL_CLOSE_ON_EXEC); + acl_close_on_exec(ACL_MASTER_FLOW_READ, ACL_CLOSE_ON_EXEC); + acl_close_on_exec(ACL_MASTER_FLOW_WRITE, ACL_CLOSE_ON_EXEC); + + watchdog = acl_watchdog_create(acl_var_single_daemon_timeout, + (ACL_WATCHDOG_FN) 0, NULL); + + /* + * The event loop, at last. + */ + while (acl_var_single_use_limit == 0 + || use_count < acl_var_single_use_limit) + { + int delay_sec; + + if (single_server_lock != 0) { + acl_watchdog_stop(watchdog); + if (acl_myflock(ACL_VSTREAM_FILE(single_server_lock), + ACL_INTERNAL_LOCK, ACL_MYFLOCK_OP_EXCLUSIVE) < 0) + { + acl_msg_fatal("error lock: %s", strerror(errno)); + } + } + acl_watchdog_start(watchdog); + delay_sec = loop ? loop(single_server_name, single_server_argv) : -1; + acl_event_set_delay_sec(__eventp, delay_sec); + acl_event_loop(__eventp); + } + single_server_exit(); +} + +#endif /* ACL_UNIX */ diff --git a/lib_acl/src/master/template/acl_tmpl.c b/lib_acl/src/master/template/acl_tmpl.c new file mode 100644 index 000000000..24476ee80 --- /dev/null +++ b/lib_acl/src/master/template/acl_tmpl.c @@ -0,0 +1,47 @@ +#include "StdAfx.h" + +#ifndef ACL_PREPARE_COMPILE +#include "stdlib/acl_define.h" +#endif + +#ifdef ACL_UNIX + +#include +#include +#ifndef ACL_MACOSX +# include +#endif +#include "stdlib/acl_msg.h" +#include "template.h" + +void set_core_limit(void) +{ + const char *myname = "set_limit"; + struct rlimit rlim, rlim_new; + +#ifndef ACL_MACOSX + if (prctl(PR_SET_DUMPABLE, 1) < 0) { + acl_msg_warn("%s(%d): prctl error(%s)", + myname, __LINE__, acl_last_serror()); + } +#endif + + if (getrlimit(RLIMIT_CORE, &rlim) == 0) { + rlim_new.rlim_cur = rlim_new.rlim_max = RLIM_INFINITY; + if (setrlimit(RLIMIT_CORE, &rlim_new) != 0) { + /* failed. try raising just to the old max */ + rlim_new.rlim_cur = rlim_new.rlim_max = rlim.rlim_max; + if (setrlimit(RLIMIT_CORE, &rlim_new) != 0) + acl_msg_warn("%s(%d): can't set core limit: %s", + myname, __LINE__, acl_last_serror()); + } + } else { + rlim.rlim_cur = RLIM_INFINITY; + rlim.rlim_max = RLIM_INFINITY; + if (setrlimit(RLIMIT_CORE, &rlim) != 0) + acl_msg_warn("%s(%d): can't set core limit: %s", + myname, __LINE__, acl_last_serror()); + } +} + +#endif diff --git a/lib_acl/src/master/template/acl_trigger_server.c b/lib_acl/src/master/template/acl_trigger_server.c new file mode 100644 index 000000000..cfa4699b5 --- /dev/null +++ b/lib_acl/src/master/template/acl_trigger_server.c @@ -0,0 +1,722 @@ +/* System library. */ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#endif + +#ifdef ACL_UNIX + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef STRCASECMP_IN_STRINGS_H +#include +#endif +#include + +/* Utility library. */ + +#include "stdlib/acl_msg.h" +#include "stdlib/unix/acl_chroot_uid.h" +#include "stdlib/acl_vstring.h" +#include "stdlib/acl_vstream.h" +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_iostuff.h" +#include "stdlib/acl_stringops.h" +#include "stdlib/acl_myflock.h" +#include "stdlib/unix/acl_safe_open.h" +#include "stdlib/unix/acl_watchdog.h" +#include "stdlib/acl_split_at.h" +#include "net/acl_listen.h" +#include "event/acl_events.h" + +/* Global library. */ + +#include "../master_flow.h" +#include "../master_params.h" +#include "../master_proto.h" + +/* Application-specific */ + +#include "master/acl_trigger_params.h" +#include "master/acl_server_api.h" +#include "template.h" + +int acl_var_trigger_pid; +char *acl_var_trigger_procname; +char *acl_var_trigger_log_file; +char *acl_var_trigger_pid_dir; + +int acl_var_trigger_buf_size; +int acl_var_trigger_rw_timeout; +int acl_var_trigger_in_flow_delay; +int acl_var_trigger_idle_limit; +char *acl_var_trigger_queue_dir; +char *acl_var_trigger_owner; +int acl_var_trigger_delay_sec; +int acl_var_trigger_delay_usec; +int acl_var_trigger_daemon_timeout; +int acl_var_trigger_use_limit; +int acl_var_trigger_enable_core; + +static ACL_CONFIG_INT_TABLE __conf_int_tab[] = { + { ACL_VAR_TRIGGER_BUF_SIZE, ACL_DEF_TRIGGER_BUF_SIZE, &acl_var_trigger_buf_size, 0, 0 }, + { ACL_VAR_TRIGGER_RW_TIMEOUT, ACL_DEF_TRIGGER_RW_TIMEOUT, &acl_var_trigger_rw_timeout, 0, 0 }, + { ACL_VAR_TRIGGER_IN_FLOW_DELAY, ACL_DEF_TRIGGER_IN_FLOW_DELAY, &acl_var_trigger_in_flow_delay, 0, 0 }, + { ACL_VAR_TRIGGER_IDLE_LIMIT, ACL_DEF_TRIGGER_IDLE_LIMIT, &acl_var_trigger_idle_limit, 0, 0 }, + { ACL_VAR_TRIGGER_DELAY_SEC, ACL_DEF_TRIGGER_DELAY_SEC, &acl_var_trigger_delay_sec, 0, 0 }, + { ACL_VAR_TRIGGER_DELAY_USEC, ACL_DEF_TRIGGER_DELAY_USEC, &acl_var_trigger_delay_usec, 0, 0 }, + { ACL_VAR_TRIGGER_DAEMON_TIMEOUT, ACL_DEF_TRIGGER_DAEMON_TIMEOUT, &acl_var_trigger_daemon_timeout, 0, 0 }, + { ACL_VAR_TRIGGER_USE_LIMIT, ACL_DEF_TRIGGER_USE_LIMIT, &acl_var_trigger_use_limit, 0, 0 }, + { ACL_VAR_TRIGGER_ENABLE_CORE, ACL_DEF_TRIGGER_ENABLE_CORE, &acl_var_trigger_enable_core, 0, 0 }, + { 0, 0, 0, 0, 0 }, +}; + +static ACL_CONFIG_STR_TABLE __conf_str_tab[] = { + { ACL_VAR_TRIGGER_QUEUE_DIR, ACL_DEF_TRIGGER_QUEUE_DIR, &acl_var_trigger_queue_dir }, + { ACL_VAR_TRIGGER_OWNER, ACL_DEF_TRIGGER_OWNER, &acl_var_trigger_owner }, + { ACL_VAR_TRIGGER_PID_DIR, ACL_DEF_TRIGGER_PID_DIR, &acl_var_trigger_pid_dir }, + { 0, 0, 0 }, +}; + + /* + * Global state. + */ +static int use_count; +static ACL_EVENT *__eventp = NULL; +static ACL_VSTREAM **__stream_array; + +static ACL_TRIGGER_SERVER_FN trigger_server_service; +static char *trigger_server_name; +static char **trigger_server_argv; +static void (*trigger_server_accept) (int, void *); +static void (*trigger_server_onexit) (char *, char **); +static void (*trigger_server_pre_accept) (char *, char **); +static ACL_VSTREAM *trigger_server_lock; +static int trigger_server_in_flow_delay; +static unsigned trigger_server_generation; + +ACL_EVENT *acl_trigger_server_event() +{ + return (__eventp); +} + +/* trigger_server_exit - normal termination */ + +static void trigger_server_exit(void) +{ + if (trigger_server_onexit) + trigger_server_onexit(trigger_server_name, trigger_server_argv); + exit(0); +} + +/* trigger_server_abort - terminate after abnormal master exit */ + +static void trigger_server_abort(int event acl_unused, void *context acl_unused) +{ + if (acl_msg_verbose) + acl_msg_info("master disconnect -- exiting"); + trigger_server_exit(); +} + +/* trigger_server_timeout - idle time exceeded */ + +static void trigger_server_timeout(int event acl_unused, void *context acl_unused) +{ + if (acl_msg_verbose) + acl_msg_info("idle timeout -- exiting"); + trigger_server_exit(); +} + +/* trigger_server_wakeup - wake up application */ + +static void trigger_server_wakeup(int fd) +{ + char buf[ACL_TRIGGER_BUF_SIZE]; + int len; + + /* + * Commit suicide when the master process disconnected from us. + */ + if (acl_master_notify(acl_var_trigger_pid, trigger_server_generation, + ACL_MASTER_STAT_TAKEN) < 0) + { + trigger_server_abort(ACL_EVENT_NULL_TYPE, ACL_EVENT_NULL_CONTEXT); + } + if (trigger_server_in_flow_delay && acl_master_flow_get(1) < 0) + acl_doze(acl_var_trigger_in_flow_delay * 1000); + if ((len = read(fd, buf, sizeof(buf))) >= 0) + trigger_server_service(buf, len, trigger_server_name, + trigger_server_argv); + + if (acl_master_notify(acl_var_trigger_pid, trigger_server_generation, + ACL_MASTER_STAT_AVAIL) < 0) + { + trigger_server_abort(ACL_EVENT_NULL_TYPE, ACL_EVENT_NULL_CONTEXT); + } + if (acl_var_trigger_idle_limit > 0) + acl_event_request_timer(__eventp, trigger_server_timeout, NULL, + (acl_int64) acl_var_trigger_idle_limit * 1000000, 0); + use_count++; +} + +/* trigger_server_accept_fifo - accept fifo client request */ + +static void trigger_server_accept_fifo(int event acl_unused, void *context) +{ + const char *myname = "trigger_server_accept_fifo"; + ACL_VSTREAM *stream = (ACL_VSTREAM *) context; + int listen_fd = ACL_VSTREAM_SOCK(stream); + + if (trigger_server_lock != 0 + && acl_myflock(ACL_VSTREAM_FILE(trigger_server_lock), + ACL_INTERNAL_LOCK, ACL_MYFLOCK_OP_NONE) < 0) + { + acl_msg_fatal("select unlock: %s", strerror(errno)); + } + + if (acl_msg_verbose) + acl_msg_info("%s: trigger arrived", myname); + + /* + * Read whatever the other side wrote into the FIFO. The FIFO read end is + * non-blocking so we won't get stuck when multiple processes wake up. + */ + if (trigger_server_pre_accept) + trigger_server_pre_accept(trigger_server_name, trigger_server_argv); + trigger_server_wakeup(listen_fd); +} + +/* trigger_server_accept_local - accept socket client request */ + +static void trigger_server_accept_local(int event acl_unused, void *context) +{ + const char *myname = "trigger_server_accept_local"; + ACL_VSTREAM *stream = (ACL_VSTREAM *) context; + int listen_fd = ACL_VSTREAM_SOCK(stream), time_left = 0, fd; + + if (acl_msg_verbose) + acl_msg_info("%s: trigger arrived", myname); + + /* + * Read a message from a socket. Be prepared for accept() to fail because + * some other process already got the connection. The socket is + * non-blocking so we won't get stuck when multiple processes wake up. + * Don't get stuck when the client connects but sends no data. Restart + * the idle timer if this was a false alarm. + */ + if (acl_var_trigger_idle_limit > 0) + time_left = (int) ((acl_event_cancel_timer(__eventp, + trigger_server_timeout, NULL) + 999999) / 1000000); + + if (trigger_server_pre_accept) + trigger_server_pre_accept(trigger_server_name, trigger_server_argv); + fd = acl_unix_accept(listen_fd); + if (trigger_server_lock != 0 + && acl_myflock(ACL_VSTREAM_FILE(trigger_server_lock), + ACL_INTERNAL_LOCK, ACL_MYFLOCK_OP_NONE) < 0) + { + acl_msg_fatal("select unlock: %s", strerror(errno)); + } + if (fd < 0) { + if (errno != EAGAIN) + acl_msg_fatal("accept connection: %s", strerror(errno)); + if (time_left >= 0) + acl_event_request_timer(__eventp, trigger_server_timeout, + NULL, (acl_int64) time_left * 1000000, 0); + return; + } + acl_close_on_exec(fd, ACL_CLOSE_ON_EXEC); + if (acl_read_wait(fd, 10) == 0) + trigger_server_wakeup(fd); + else if (time_left >= 0) + acl_event_request_timer(__eventp, trigger_server_timeout, + NULL, (acl_int64) time_left * 1000000, 0); + close(fd); +} + +#ifdef ACL_MASTER_XPORT_NAME_PASS + +/* trigger_server_accept_pass - accept descriptor */ + +static void trigger_server_accept_pass(int event acl_unused, void *context) +{ + const char *myname = "trigger_server_accept_pass"; + ACL_VSTREAM *stream = (ACL_VSTREAM *) context; + int listen_fd = ACL_VSTREAM_SOCK(stream), time_left = 0, fd; + + if (acl_msg_verbose) + acl_msg_info("%s: trigger arrived", myname); + + /* + * Read a message from a socket. Be prepared for accept() to fail because + * some other process already got the connection. The socket is + * non-blocking so we won't get stuck when multiple processes wake up. + * Don't get stuck when the client connects but sends no data. Restart + * the idle timer if this was a false alarm. + */ + if (acl_var_trigger_idle_limit > 0) + time_left = (int) ((acl_event_cancel_timer(__eventp, + trigger_server_timeout, NULL) + 999999) / 1000000); + + if (trigger_server_pre_accept) + trigger_server_pre_accept(trigger_server_name, trigger_server_argv); + fd = PASS_ACCEPT(listen_fd); + if (trigger_server_lock != 0 + && acl_myflock(ACL_VSTREAM_FILE(trigger_server_lock), + ACL_INTERNAL_LOCK, + ACL_MYFLOCK_OP_NONE) < 0) + acl_msg_fatal("select unlock: %s", strerror(errno)); + if (fd < 0) { + if (errno != EAGAIN) + acl_msg_fatal("accept connection: %s", strerror(errno)); + if (time_left >= 0) + acl_event_request_timer(__eventp, trigger_server_timeout, + NULL, (acl_int64) time_left * 1000000, 0); + return; + } + acl_close_on_exec(fd, ACL_CLOSE_ON_EXEC); + if (acl_read_wait(fd, 10) == 0) + trigger_server_wakeup(fd); + else if (time_left >= 0) + acl_event_request_timer(__eventp, trigger_server_timeout, + NULL, (acl_int64) time_left * 1000000, 0); + close(fd); +} + +#endif + +static void trigger_server_init(const char *procname) +{ + const char *myname = "trigger_server_init"; + static int inited = 0; + + if (inited) + return; + + inited = 1; + + if (procname == NULL || *procname == 0) + acl_msg_fatal("%s(%d); procname null", myname, __LINE__); + + /* + * Don't die when a process goes away unexpectedly. + */ + signal(SIGPIPE, SIG_IGN); + + /* + * Don't die for frivolous reasons. + */ +#ifdef SIGXFSZ + signal(SIGXFSZ, SIG_IGN); +#endif + + /* + * May need this every now and then. + */ + + acl_var_trigger_pid = getpid(); + acl_var_trigger_procname = acl_mystrdup(acl_safe_basename(procname)); + + acl_var_trigger_log_file = getenv("SERVICE_LOG"); + if (acl_var_trigger_log_file == NULL) { + acl_var_trigger_log_file = acl_mystrdup("acl_master.log"); + acl_msg_fatal("%s(%d)->%s: can't get MASTER_LOG's env value, use %s log", + __FILE__, __LINE__, myname, acl_var_trigger_log_file); + } + + acl_get_app_conf_int_table(__conf_int_tab); + acl_get_app_conf_str_table(__conf_str_tab); + + acl_master_vars_init(acl_var_trigger_buf_size, acl_var_trigger_rw_timeout); +} + +static void trigger_server_open_log(void) +{ + /* first, close the master's log */ + master_log_close(); + + /* second, open the service's log */ + acl_msg_open(acl_var_trigger_log_file, acl_var_trigger_procname); +} + +static void usage(int argc, char *argv[]) +{ + int i; + char *service_name; + + if (argc <= 0) + acl_msg_fatal("%s(%d): argc(%d) invalid", + __FILE__, __LINE__, argc); + + service_name = acl_mystrdup(acl_safe_basename(argv[0])); + + for (i = 0; i < argc; i++) + acl_msg_info("argv[%d]: %s", i, argv[i]); + + acl_msg_info("usage: %s -h[help]" + " -c [use chroot]" + " -d [debug]" + " -l [run alone]" + " -n service_name" + " -s socket_count" + " -i [use stdin]" + " -t transport" + " -u [use setgid initgroups setuid]" + " -v [on acl_msg_verbose]" + " -z [unlimit process count]" + " -f conf_file", + service_name); +} + +/* trigger_server_main - the real main program */ + +void acl_trigger_server_main(int argc, char **argv, ACL_TRIGGER_SERVER_FN service,...) +{ + const char *myname = "trigger_server_main"; + char *root_dir = 0; + char *user_name = 0; + char *service_name = acl_mystrdup(acl_safe_basename(argv[0])); + ACL_VSTREAM *stream = 0; + int delay; + int c; + int socket_count = 1; + va_list ap; + ACL_MASTER_SERVER_INIT_FN pre_init = 0; + ACL_MASTER_SERVER_INIT_FN post_init = 0; + ACL_MASTER_SERVER_LOOP_FN loop = 0; + int key; + char buf[ACL_TRIGGER_BUF_SIZE]; + int len; + char *transport = 0; + char *lock_path; + ACL_VSTRING *why; + int alone = 0; + int zerolimit = 0; + ACL_WATCHDOG *watchdog; + char *generation; + + int fd, fdtype = 0; + int f_flag = 0; + char *conf_file_ptr = 0; + + /* 提前进行模板初始化,以使日志尽早地打开, 开始先使用 acl_master 的日志文件 */ + acl_master_log_open(argv[0]); + + if (acl_msg_verbose) + acl_msg_info("daemon started"); + + /* + * Pick up policy settings from master process. Shut up error messages to + * stderr, because no-one is going to see them. + */ + opterr = 0; + while ((c = getopt(argc, argv, "hcDlm:n:s:it:uvzf:")) > 0) { + switch (c) { + case 'h': + usage(argc, argv); + exit (0); + case 'f': + acl_app_conf_load(optarg); + f_flag = 1; + conf_file_ptr = optarg; + break; + case 'c': + root_dir = "setme"; + break; + case 'l': + alone = 1; + break; + case 'n': + service_name = optarg; + break; + case 's': + if ((socket_count = atoi(optarg)) <= 0) + acl_msg_fatal("invalid socket_count: %s", optarg); + break; + case 't': + transport = optarg; + break; + case 'u': + user_name = "setme"; + break; + case 'v': + acl_msg_verbose++; + break; + case 'z': + zerolimit = 1; + break; + default: + break; + } + } + + if (stream == NULL) + trigger_server_init(argv[0]); + + if (f_flag == 0) + acl_msg_fatal("%s(%d), %s: need \"-f pathname\"", + __FILE__, __LINE__, myname); + else if (acl_msg_verbose) + acl_msg_info("%s(%d), %s: configure file = %s", + __FILE__, __LINE__, myname, conf_file_ptr); + + /* + * Application-specific initialization. + */ + va_start(ap, service); + while ((key = va_arg(ap, int)) != 0) { + switch (key) { + case ACL_MASTER_SERVER_INT_TABLE: + acl_get_app_conf_int_table(va_arg(ap, ACL_CONFIG_INT_TABLE *)); + break; + case ACL_MASTER_SERVER_INT64_TABLE: + acl_get_app_conf_int64_table(va_arg(ap, ACL_CONFIG_INT64_TABLE *)); + break; + case ACL_MASTER_SERVER_STR_TABLE: + acl_get_app_conf_str_table(va_arg(ap, ACL_CONFIG_STR_TABLE *)); + break; + case ACL_MASTER_SERVER_BOOL_TABLE: + acl_get_app_conf_bool_table(va_arg(ap, ACL_CONFIG_BOOL_TABLE *)); + break; + + case ACL_MASTER_SERVER_PRE_INIT: + pre_init = va_arg(ap, ACL_MASTER_SERVER_INIT_FN); + break; + case ACL_MASTER_SERVER_POST_INIT: + post_init = va_arg(ap, ACL_MASTER_SERVER_INIT_FN); + break; + case ACL_MASTER_SERVER_LOOP: + loop = va_arg(ap, ACL_MASTER_SERVER_LOOP_FN); + break; + case ACL_MASTER_SERVER_EXIT: + trigger_server_onexit = va_arg(ap, ACL_MASTER_SERVER_EXIT_FN); + break; + case ACL_MASTER_SERVER_PRE_ACCEPT: + trigger_server_pre_accept = va_arg(ap, ACL_MASTER_SERVER_ACCEPT_FN); + break; + case ACL_MASTER_SERVER_IN_FLOW_DELAY: + trigger_server_in_flow_delay = 1; + break; + case ACL_MASTER_SERVER_SOLITARY: + if (!alone) + acl_msg_fatal("service %s requires a process limit of 1", + service_name); + break; + case ACL_MASTER_SERVER_UNLIMITED: + if (!zerolimit) + acl_msg_fatal("service %s requires a process limit of 0", + service_name); + break; + case ACL_MASTER_SERVER_PRIVILEGED: + if (user_name) + acl_msg_fatal("service %s requires privileged operation", + service_name); + break; + default: + acl_msg_panic("%s: unknown argument type: %d", myname, key); + } + } + va_end(ap); + + if (root_dir) + root_dir = acl_var_trigger_queue_dir; + if (user_name) + user_name = acl_var_trigger_owner; + + /* + * If not connected to stdin, stdin must not be a terminal. + */ + if (stream == 0 && isatty(STDIN_FILENO)) + acl_msg_fatal("do not run this command by hand"); + + /* + * Can options be required? + * + * XXX Initially this code was implemented with UNIX-domain sockets, but + * Solaris <= 2.5 UNIX-domain sockets misbehave hopelessly when the + * client disconnects before the server has accepted the connection. + * Symptom: the server accept() fails with EPIPE or EPROTO, but the + * socket stays readable, so that the program goes into a wasteful loop. + * + * The initial fix was to use FIFOs, but those turn out to have their own + * problems, witness the workarounds in the fifo_listen() routine. + * Therefore we support both FIFOs and UNIX-domain sockets, so that the + * user can choose whatever works best. + * + * Well, I give up. Solaris UNIX-domain sockets still don't work properly, + * so it will have to limp along with a streams-specific alternative. + */ + if (stream == 0) { + if (transport == 0) + acl_msg_fatal("no transport type specified"); + if (strcasecmp(transport, ACL_MASTER_XPORT_NAME_UNIX) == 0) { + trigger_server_accept = trigger_server_accept_local; + fdtype = ACL_VSTREAM_TYPE_LISTEN | ACL_VSTREAM_TYPE_LISTEN_INET; + } else if (strcasecmp(transport, ACL_MASTER_XPORT_NAME_FIFO) == 0) { + trigger_server_accept = trigger_server_accept_fifo; + fdtype = ACL_VSTREAM_TYPE_LISTEN | ACL_VSTREAM_TYPE_LISTEN_UNIX; +#ifdef ACL_MASTER_XPORT_NAME_PASS + } else if (strcasecmp(transport, ACL_MASTER_XPORT_NAME_PASS) == 0) { + trigger_server_accept = trigger_server_accept_pass; + fdtype = ACL_VSTREAM_TYPE_LISTEN; +#endif + } else + acl_msg_fatal("unsupported transport type: %s", transport); + } + + /* + * Retrieve process generation from environment. + */ + if ((generation = getenv(ACL_MASTER_GEN_NAME)) != 0) { + if (!acl_alldig(generation)) + acl_msg_fatal("bad generation: %s", generation); + sscanf(generation, "%o", &trigger_server_generation); + if (acl_msg_verbose) + acl_msg_info("process generation: %s (%o)", + generation, trigger_server_generation); + } + + /* + * Traditionally, BSD select() can't handle multiple processes selecting + * on the same socket, and wakes up every process in select(). See TCP/IP + * Illustrated volume 2 page 532. We avoid select() collisions with an + * external lock file. + */ + if (stream == 0 && !alone) { + lock_path = acl_concatenate(acl_var_trigger_pid_dir, "/", + transport, ".", service_name, (char *) 0); + why = acl_vstring_alloc(1); + if ((trigger_server_lock = acl_safe_open(lock_path, + O_CREAT | O_RDWR, 0600, (struct stat *) 0, + (uid_t) -1, (uid_t) -1, why)) == 0) + { + acl_msg_fatal("open lock file %s: %s", + lock_path, acl_vstring_str(why)); + } + acl_close_on_exec(ACL_VSTREAM_FILE(trigger_server_lock), + ACL_CLOSE_ON_EXEC); + acl_myfree(lock_path); + acl_vstring_free(why); + } + + /* + * Set up call-back info. + */ + trigger_server_service = service; + trigger_server_name = service_name; + trigger_server_argv = argv + optind; + + __eventp = acl_event_new_select(acl_var_trigger_delay_sec, + acl_var_trigger_delay_usec); + + /* + * Run pre-jail initialization. + */ + if (chdir(acl_var_trigger_queue_dir) < 0) + acl_msg_fatal("chdir(\"%s\"): %s", + acl_var_trigger_queue_dir, strerror(errno)); + if (pre_init) + pre_init(trigger_server_name, trigger_server_argv); + +#ifdef SNAPSHOT + tzset(); +#endif + acl_chroot_uid(root_dir, user_name); + + trigger_server_open_log(); + + /* 设置子进程运行环境,允许产生 core 文件 */ + if (acl_var_trigger_enable_core) + set_core_limit(); + + /* + * Run post-jail initialization. + */ + if (post_init) + post_init(trigger_server_name, trigger_server_argv); + + /* + * Are we running as a one-shot server with the client connection on + * standard input? + */ + if (stream != 0) { + len = read(ACL_VSTREAM_SOCK(stream), buf, sizeof(buf)); + if (len <= 0) + acl_msg_fatal("read: %s", strerror(errno)); + service(buf, len, trigger_server_name, trigger_server_argv); + trigger_server_exit(); + } + + /* + * Running as a semi-resident server. Service connection requests. + * Terminate when we have serviced a sufficient number of clients, when + * no-one has been talking to us for a configurable amount of time, or + * when the master process terminated abnormally. + */ + if (acl_var_trigger_idle_limit > 0) + acl_event_request_timer(__eventp, trigger_server_timeout, NULL, + (acl_int64) acl_var_trigger_idle_limit * 1000000, 0); + + /* socket count is the same value of listen_fd_count in parent process */ + + __stream_array = (ACL_VSTREAM **) acl_mycalloc( + ACL_MASTER_LISTEN_FD + socket_count, sizeof(ACL_VSTREAM *)); + + fd = ACL_MASTER_LISTEN_FD; + for (; fd < ACL_MASTER_LISTEN_FD + socket_count; fd++) { + stream = acl_vstream_fdopen(fd, O_RDWR, acl_var_trigger_buf_size, + acl_var_trigger_rw_timeout, fdtype); + if (stream == NULL) + acl_msg_fatal("%s(%d)->%s: stream null, fd = %d", + __FILE__, __LINE__, myname, fd); + + acl_event_enable_read(__eventp, stream, 0, + trigger_server_accept, stream); + acl_close_on_exec(ACL_VSTREAM_SOCK(stream), ACL_CLOSE_ON_EXEC); + } + + acl_event_enable_read(__eventp, ACL_MASTER_STAT_STREAM, 0, + trigger_server_abort, (void *) 0); + acl_close_on_exec(ACL_MASTER_STATUS_FD, ACL_CLOSE_ON_EXEC); + acl_close_on_exec(ACL_MASTER_FLOW_READ, ACL_CLOSE_ON_EXEC); + acl_close_on_exec(ACL_MASTER_FLOW_WRITE, ACL_CLOSE_ON_EXEC); + watchdog = acl_watchdog_create(acl_var_trigger_daemon_timeout, + (ACL_WATCHDOG_FN) 0, (char *) 0); + + /* + * The event loop, at last. + */ + while (acl_var_trigger_use_limit == 0 + || use_count < acl_var_trigger_use_limit) + { + if (trigger_server_lock != 0) { + acl_watchdog_stop(watchdog); + if (acl_myflock(ACL_VSTREAM_FILE(trigger_server_lock), + ACL_INTERNAL_LOCK, ACL_MYFLOCK_OP_EXCLUSIVE) < 0) + { + acl_msg_fatal("select lock: %s", strerror(errno)); + } + } + acl_watchdog_start(watchdog); + delay = loop ? loop(trigger_server_name, trigger_server_argv) : -1; + acl_event_set_delay_sec(__eventp, delay); + acl_event_loop(__eventp); + } + trigger_server_exit(); +} +#endif /* ACL_UNIX */ diff --git a/lib_acl/src/master/template/template.h b/lib_acl/src/master/template/template.h new file mode 100644 index 000000000..e8bb2fd6b --- /dev/null +++ b/lib_acl/src/master/template/template.h @@ -0,0 +1,21 @@ +#ifndef __SERVER_TEMPLATE_INCLUDE_H__ +#define __SERVER_TEMPLATE_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_define.h" + +#ifdef ACL_UNIX + +void master_log_close(void); +void set_core_limit(void); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/src/msg/acl_aqueue.c b/lib_acl/src/msg/acl_aqueue.c new file mode 100644 index 000000000..fcc7dd867 --- /dev/null +++ b/lib_acl/src/msg/acl_aqueue.c @@ -0,0 +1,327 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include +#ifdef ACL_UNIX +#include +#include +#include +#include +#include +#include +#include + +#elif defined(ACL_MS_WINDOWS) +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#ifdef ACL_MS_VC +#pragma once +#endif + +#endif /* defined(ACL_MS_WINDOWS) */ + +#include "stdlib/acl_sys_patch.h" +#include "thread/acl_thread.h" +#include "stdlib/acl_msg.h" +#include "stdlib/acl_mymalloc.h" +#include "msg/acl_aqueue.h" + +#endif + +#undef __SET_ERRNO +#ifdef ACL_MS_WINDOWS +# define __SET_ERRNO(_x_) (void) 0 +#elif defined(ACL_UNIX) +# define __SET_ERRNO(_x_) (acl_set_error(_x_)) +#else +# error "unknown OS type" +#endif + +/* 内部结果类型定义 */ + +struct ACL_AQUEUE_ITEM { + struct ACL_AQUEUE_ITEM *next; + void *data; +}; + +struct ACL_AQUEUE { + ACL_AQUEUE_ITEM *first, *last; + int qlen; + int error; + int quit; + int nlink; + char check_owner; + unsigned long owner; + acl_pthread_mutex_t lock; + acl_pthread_cond_t cond; +}; + +ACL_AQUEUE *acl_aqueue_new(void) +{ + const char *myname = "acl_aqueue_new"; + ACL_AQUEUE *queue; + char buf[256]; + + queue = (ACL_AQUEUE *) acl_mymalloc(sizeof(ACL_AQUEUE)); + if (queue == NULL) + acl_msg_fatal("%s: malloc error(%s)", + myname, acl_last_strerror(buf, sizeof(buf))); + + acl_pthread_mutex_init(&queue->lock, NULL); + acl_pthread_cond_init(&queue->cond, NULL); + + queue->first = queue->last = NULL; + queue->qlen = 0; + queue->error = ACL_AQUEUE_OK; + queue->quit = 0; + queue->nlink = 0; + queue->owner = (unsigned long) acl_pthread_self(); + queue->check_owner = 0; + + return (queue); +} + +void acl_aqueue_check_owner(ACL_AQUEUE *queue, char flag) +{ + if (queue) + queue->check_owner = flag; +} + +void acl_aqueue_set_owner(ACL_AQUEUE *queue, unsigned int owner) +{ + if (queue) + queue->owner = owner; +} + +void acl_aqueue_free(ACL_AQUEUE *queue, ACL_AQUEUE_FREE_FN free_fn) +{ + const char *myname = "acl_aqueue_free"; + ACL_AQUEUE_ITEM *qi; + char buf[256]; + int status; + + if (queue == NULL) + return; + + if (queue->check_owner && (unsigned long) acl_pthread_self() != queue->owner) { + acl_msg_error("%s: cur tid(%lu) != owner(%lu), denied", + myname, (unsigned long) acl_pthread_self(), + queue->owner); + return; + } + + queue->quit = 1; + status = acl_pthread_mutex_lock(&queue->lock); + if (status != 0) + acl_msg_error("%s: lock error(%s)", + myname, acl_last_strerror(buf, sizeof(buf))); + + while (1) { + qi = queue->first; + if (qi == NULL) + break; + if (free_fn != NULL) + free_fn(qi->data); + acl_myfree(qi); + } + + status = acl_pthread_mutex_unlock(&queue->lock); + if (status != 0) + acl_msg_error("%s: lock error(%s)", + myname, acl_last_strerror(buf, sizeof(buf))); + + acl_pthread_mutex_destroy(&queue->lock); + acl_pthread_cond_destroy(&queue->cond); + acl_myfree(queue); +} + +void *acl_aqueue_pop(ACL_AQUEUE *queue) +{ + return (acl_aqueue_pop_timedwait(queue, -1, -1)); +} + +static int aqueue_wait(ACL_AQUEUE *queue, const struct timespec *ptimeout) +{ + const char *myname = "aqueue_wait"; + char buf[256]; + int status; + + while (queue->first == NULL && queue->quit == 0) { + status = acl_pthread_cond_timedwait(&queue->cond, &queue->lock, ptimeout); + if (ptimeout && status == ACL_ETIMEDOUT) { + status = acl_pthread_mutex_unlock(&queue->lock); + if (status != 0) + acl_msg_error("%s(%d): unlock error(%s)", + myname, __LINE__, + acl_last_strerror(buf, sizeof(buf))); + + queue->error = ACL_AQUEUE_ERR_TIMEOUT; + return (-1); + } else if (status != 0) { + status = acl_pthread_mutex_unlock(&queue->lock); + if (status != 0) + acl_msg_error("%s(%d): unlock error(%s)", + myname, __LINE__, + acl_last_strerror(buf, sizeof(buf))); + + queue->error = ACL_AQUEUE_ERR_COND_WAIT; + __SET_ERRNO(status); + acl_msg_error("%s: cond wait error(%s)", + myname, acl_last_strerror(buf, sizeof(buf))); + return (-1); + } + } + + return (0); +} + +void *acl_aqueue_pop_timedwait(ACL_AQUEUE *queue, int tmo_sec, int tmo_usec) +{ + const char *myname = "acl_aqueue_pop_timedwait"; + ACL_AQUEUE_ITEM *qi; + struct timeval tv; + struct timespec timeout, *ptimeout; + int status; + void *data; + char buf[256]; + + if (queue == NULL) + acl_msg_fatal("%s: queue null", myname); + + queue->error = ACL_AQUEUE_OK; + + status = acl_pthread_mutex_lock(&queue->lock); + if (status) { + __SET_ERRNO(status); + acl_msg_error("%s: lock error(%s)", + myname, acl_last_strerror(buf, sizeof(buf))); + + queue->error = ACL_AQUEUE_ERR_LOCK; + return (NULL); + } + + qi = NULL; + + while (1) { + if (tmo_sec < 0 || tmo_usec < 0) + ptimeout = NULL; + else { + gettimeofday(&tv, NULL); + timeout.tv_sec = tv.tv_sec + tmo_sec; + timeout.tv_nsec = tv.tv_usec * 1000 + tmo_usec * 1000; + } + + ptimeout = &timeout; + if (aqueue_wait(queue, ptimeout) < 0) + return (NULL); + + qi = queue->first; + if (qi != NULL) { + queue->first = qi->next; + queue->qlen--; + if (queue->last == qi) + queue->last = NULL; + break; + } + if (queue->quit != 0) { + status = acl_pthread_mutex_unlock(&queue->lock); + if (status != 0) { + acl_msg_error("%s(%d): unlock error(%s)", + myname, __LINE__, acl_last_strerror(buf, sizeof(buf))); + queue->error = ACL_AQUEUE_ERR_UNLOCK; + } + + return (NULL); + } + } + + status = acl_pthread_mutex_unlock(&queue->lock); + if (status != 0) + acl_msg_error("%s(%d): unlock error(%s)", + myname, __LINE__, acl_last_strerror(buf, sizeof(buf))); + + if (qi == NULL) + acl_msg_fatal("%s(%d): qi null", myname, __LINE__); + + data = qi->data; + acl_myfree(qi); + + return (data); +} + +int acl_aqueue_push(ACL_AQUEUE *queue, void *data) +{ + const char *myname = "acl_aqueue_push"; + ACL_AQUEUE_ITEM *qi; + char buf[256]; + int status; + + if (queue == NULL) + acl_msg_fatal("%s: aqueue null", myname); + + qi = acl_mycalloc(1, sizeof(ACL_AQUEUE_ITEM)); + if (qi == NULL) + acl_msg_fatal("%s: calloc error(%s)", + myname, acl_last_strerror(buf, sizeof(buf))); + + qi->data = data; + + status = acl_pthread_mutex_lock(&queue->lock); + if (status != 0) { + __SET_ERRNO(status); + acl_msg_error("%s: lock error(%s)", + myname, acl_last_strerror(buf, sizeof(buf))); + acl_myfree(qi); + queue->error = ACL_AQUEUE_ERR_LOCK; + return (-1); + } + + if (queue->first == NULL) + queue->first = qi; + else + queue->last->next = qi; + + queue->last = qi; + queue->qlen++; + + status = acl_pthread_mutex_unlock(&queue->lock); + if (status != 0) { + __SET_ERRNO(status); + acl_msg_error("%s: unlock error(%s)", + myname, acl_last_strerror(buf, sizeof(buf))); + return (-1); + } + + status = acl_pthread_cond_signal(&queue->cond); + if (status != 0) { + __SET_ERRNO(status); + acl_msg_error("%s: cond signal error(%s)", + myname, acl_last_strerror(buf, sizeof(buf))); + return (-1); + } + + return (0); +} + +void acl_aqueue_set_quit(ACL_AQUEUE *queue) +{ + if (queue) + queue->quit = 1; +} +int acl_aqueue_last_error(const ACL_AQUEUE *queue) +{ + if (queue == NULL) + return (ACL_AQUEUE_ERR_UNKNOWN); + + return (queue->error); +} diff --git a/lib_acl/src/msg/acl_msgio.c b/lib_acl/src/msg/acl_msgio.c new file mode 100644 index 000000000..36249c63d --- /dev/null +++ b/lib_acl/src/msg/acl_msgio.c @@ -0,0 +1,951 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_ring.h" +#include "stdlib/acl_msg.h" +#include "stdlib/acl_vstream.h" +#include "stdlib/acl_vstring.h" +#include "thread/acl_pthread.h" +#include "net/acl_vstream_net.h" +#include "msg/acl_msgio.h" + +#endif + +typedef struct MSGIO_CTX MSGIO_CTX; + +/* IO 消息句柄 */ +struct ACL_MSGIO { + ACL_AIO *aio; + ACL_RING msg_list; + union { + ACL_ASTREAM *async; + ACL_VSTREAM *sync; + } stream; + int rw_timeout; + char addr[256]; + MSGIO_CTX *ctx; + int type; +#define ACL_MSGIO_TYPE_CLIENT 0 +#define ACL_MSGIO_TYPE_SERVER 1 +#define ACL_MSGIO_TYPE_ACCEPT 2 + + int keep_alive; +}; + +/* 消息信息载体结构定义 */ +typedef struct MSG_ITEM { + int id; /* 消息 ID */ + int inherit; /* 是否允许消息继承,主要用于在创建客户端 + * 消息对象后克隆监听对象的消息集合时 + */ + ACL_RING entry; /* 连接进 ACL_MSGIO.msg_list */ + ACL_RING call_list; /* MSG_CALL 对象集合 */ +} MSG_ITEM; + +/* 消息回调处理过程载体结构定义 */ +typedef struct MSG_CALL { + MSG_ITEM *msg; /* 指向消息 */ + ACL_RING entry; /* 连接进 MSG_ITEM.call_list */ + ACL_MSGIO_NOTIFY_FN notify_fn; /* 消息回调函数 */ + void *arg; /* 消息回调函数的参数 */ +} MSG_CALL; + +struct MSGIO_CTX { + ACL_MSGIO *mio; + ACL_MSGIO_INFO info; + char addr[256]; +}; + +static ACL_MSGIO *__global_mio = NULL; +static acl_pthread_mutex_t __global_mutex; + +/*----------------------------------------------------------------------------*/ + +static MSGIO_CTX *msgio_ctx_new(ACL_MSGIO *mio, const char *addr) +{ + MSGIO_CTX *ctx; + + ctx = acl_mycalloc(1, sizeof(MSGIO_CTX)); + ctx->info.body.buf = acl_vstring_alloc(256); + ctx->mio = mio; + ACL_SAFE_STRNCPY(ctx->addr, addr, sizeof(ctx->addr)); + mio->ctx = ctx; + return (ctx); +} + +static void msg_ctx_free(MSGIO_CTX *ctx) +{ + acl_vstring_free(ctx->info.body.buf); + acl_myfree(ctx); +} + +/*----------------------------------------------------------------------------*/ + +/* 创建新的消息回调处理对象 */ + +static MSG_CALL *msg_call_new(MSG_ITEM *msg, ACL_MSGIO_NOTIFY_FN notify_fn, void *arg) +{ + MSG_CALL *call = acl_mycalloc(1, sizeof(MSG_CALL)); + + call->msg = msg; + call->notify_fn = notify_fn; + call->arg = arg; + return (call); +} + +/* 释放消息回调处理对象 */ + +static void msg_call_free(MSG_CALL *call) +{ + acl_myfree(call); +} + +/*----------------------------------------------------------------------------*/ + +/* 创建新的消息对象 */ + +static MSG_ITEM *msg_new(int id, int inherit) +{ + MSG_ITEM *msg; + + msg = acl_mycalloc(1, sizeof(MSG_ITEM)); + msg->id = id; + msg->inherit = inherit; + acl_ring_init(&msg->call_list); + return (msg); +} + +/* 向消息的处理对象集合中添加新的处理对象 */ + +static void msg_add(MSG_ITEM *msg, MSG_CALL *call) +{ + acl_ring_append(&msg->call_list, &call->entry); +} + +/* 释放消息对象 */ + +static void msg_free(MSG_ITEM *msg) +{ + MSG_CALL *call; + ACL_RING *tmp; + + while ((tmp = acl_ring_pop_head(&msg->call_list)) != NULL) { + call = ACL_RING_TO_APPL(tmp, MSG_CALL, entry); + msg_call_free(call); + } + acl_myfree(msg); +} + +/* 向消息处理对象集合中添加新的处理对象 */ + +static void msg_append(MSG_ITEM *msg, ACL_MSGIO_NOTIFY_FN notify_fn, void *arg) +{ + ACL_RING_ITER iter; + MSG_CALL *call; + + acl_ring_foreach(iter, &msg->call_list) { + call = ACL_RING_TO_APPL(iter.ptr, MSG_CALL, entry); + if (call->notify_fn == notify_fn) { + return; + } + } + + call = msg_call_new(msg, notify_fn, arg); + acl_ring_append(&msg->call_list, &call->entry); +} + +/* 拷贝克隆某消息的处理对象集合 */ + +static void msg_clone(MSG_ITEM *msg_from, MSG_ITEM *msg_to) +{ + MSG_CALL *call_from, *call_to; + ACL_RING_ITER iter; + + acl_ring_foreach(iter, &msg_from->call_list) { + call_from = ACL_RING_TO_APPL(iter.ptr, MSG_CALL, entry); + call_to = msg_call_new(msg_to, call_from->notify_fn, + call_from->arg); + msg_add(msg_to, call_to); + } +} + +/* 拷贝克隆消息集合及消息处理对象集合 */ + +static void msg_list_clone(ACL_MSGIO *mio_from, ACL_MSGIO *mio_to) +{ + MSG_ITEM *msg_from, *msg_to; + ACL_RING_ITER iter; + + acl_ring_foreach(iter, &mio_from->msg_list) { + msg_from = ACL_RING_TO_APPL(iter.ptr, MSG_ITEM, entry); + if (!msg_from->inherit) + continue; + msg_to = msg_new(msg_from->id, msg_from->inherit); + acl_ring_append(&mio_to->msg_list, &msg_to->entry); + msg_clone(msg_from, msg_to); + } +} + +/* 根据消息ID查询消息对象 */ + +static MSG_ITEM *msg_find(ACL_MSGIO *mio, int id) +{ + MSG_ITEM *msg; + ACL_RING_ITER iter; + + acl_ring_foreach(iter, &mio->msg_list) { + msg = ACL_RING_TO_APPL(iter.ptr, MSG_ITEM, entry); + if (msg->id == id) + return (msg); + } + + return (NULL); +} + +/* 取消某消息的某个处理过程 */ + +static void msg_unreg(MSG_ITEM *msg, ACL_MSGIO_NOTIFY_FN notify_fn) +{ + ACL_RING_ITER iter; + MSG_CALL *call; + + acl_ring_foreach(iter, &msg->call_list) { + call = ACL_RING_TO_APPL(iter.ptr, MSG_CALL, entry); + if (call->notify_fn == notify_fn) { + acl_ring_detach(&call->entry); + msg_call_free(call); + break; + } + } +} + +/* 取消某消息的所有处理过程并释放消息对象 */ + +static void msg_unreg_all(MSG_ITEM *msg) +{ + msg_free(msg); +} + +/*----------------------------------------------------------------------------*/ + +static ACL_MSGIO *msgio_new(void) +{ + const char *myname = "acl_msgio_new"; + ACL_MSGIO *mio; + + mio = acl_mycalloc(1, sizeof(ACL_MSGIO)); + if (mio == NULL) { + char ebuf[256]; + acl_msg_fatal("%s: calloc error(%s)", + myname, acl_last_strerror(ebuf, sizeof(ebuf))); + } + + acl_ring_init(&mio->msg_list); + + return (mio); +} + +void acl_msgio_close(ACL_MSGIO *mio) +{ + acl_msgio_unreg_all(mio); + if (mio->aio) + acl_aio_iocp_close(mio->stream.async); + else + acl_vstream_close(mio->stream.sync); +} + +void acl_msgio_init(void) +{ + const char *myname = "acl_msgio_init"; + + if (__global_mio != NULL) + acl_msg_fatal("%s: be called more than twice", myname); + + acl_pthread_mutex_init(&__global_mutex, NULL); + __global_mio = msgio_new(); +} + +static void msgio_reg(ACL_MSGIO *mio, int id, + ACL_MSGIO_NOTIFY_FN callback, void *arg, int inherit) +{ + const char *myname= "acl_msgio_reg"; + MSG_ITEM *msg; + + if (mio == NULL) + mio = __global_mio; + + if (mio == NULL) + acl_msg_fatal("%s: call acl_msgio_init first", myname); + + msg = msg_find(mio, id); + + /* 先查询某个消息是否存在,如果存在则向该消息对象添加处理过程, + * 否则,创建并添加新的消息对象及处理过程 + */ + + if (msg) { + msg_append(msg, callback, arg); + } else { + MSG_CALL *call; + + msg = msg_new(id, inherit); + call = msg_call_new(msg, callback, arg); + msg_add(msg, call); + acl_ring_append(&mio->msg_list, &msg->entry); + } +} + +void acl_msgio_reg(ACL_MSGIO *mio, int id, + ACL_MSGIO_NOTIFY_FN callback, void *arg) +{ + msgio_reg(mio, id, callback, arg, 0); +} + +void acl_msgio_listen_reg(ACL_MSGIO *mio, int id, + ACL_MSGIO_NOTIFY_FN callback, void *arg, int inherit) +{ + msgio_reg(mio, id, callback, arg, inherit); +} + +void acl_msgio_unreg(ACL_MSGIO *mio, int id, ACL_MSGIO_NOTIFY_FN callback) +{ + const char *myname = "acl_msgio_unreg"; + MSG_ITEM *msg; + + if (mio == NULL) + mio = __global_mio; + + if (mio == NULL) + acl_msg_fatal("%s: call acl_msgio_init first", myname); + + msg = msg_find(mio, id); + if (msg != NULL) + msg_unreg(msg, callback); +} + +void acl_msgio_unreg_id(ACL_MSGIO *mio, int id) +{ + const char *myname = "acl_msgio_unreg_id"; + MSG_ITEM *msg; + + if (mio == NULL) + mio = __global_mio; + + if (mio == NULL) + acl_msg_fatal("%s: call acl_msgio_init first", myname); + + msg = msg_find(mio, id); + if (msg != NULL) { + acl_ring_detach(&msg->entry); + msg_unreg_all(msg); + } +} + +void acl_msgio_unreg_all(ACL_MSGIO *mio) +{ + const char *myname = "acl_msgio_unreg_all"; + MSG_ITEM *msg; + ACL_RING *tmp; + + if (mio == NULL) + mio = __global_mio; + + if (mio == NULL) + acl_msg_fatal("%s: call acl_msgio_init first", myname); + + while (1) { + tmp = acl_ring_pop_head(&mio->msg_list); + if (tmp == NULL) + break; + + msg = ACL_RING_TO_APPL(tmp, MSG_ITEM, entry); + msg_unreg_all(msg); + } +} + +/* 调用某个 ACL_MSGIO 句柄中某个消息的所有处理过程 */ + +static int dispatch_foreach(ACL_MSGIO *mio, const ACL_MSGIO_INFO *info, int id) +{ + const char *myname = "dispatch_foreach"; + ACL_RING_ITER iter; + MSG_CALL *call; + MSG_ITEM *msg; + int ret = 0; + + /* 找出注册该消息 (id) 的对象集合 */ + msg = msg_find(mio, id); + if (msg == NULL) { + if (id == ACL_MSGIO_QUIT) { + acl_msg_info("%s: not found quit handler," + " msgio quit(%d) now", myname, id); + return (-1); + } + return (0); + } + + acl_ring_foreach(iter, &msg->call_list) { + call = ACL_RING_TO_APPL(iter.ptr, MSG_CALL, entry); + ret = call->notify_fn(id, mio, info, call->arg); + if (ret != 0) + break; + } + + if (id == ACL_MSGIO_QUIT) { + acl_msg_info("msgio quit now"); + return (-1); + } + + return (ret); +} + +/* 发送消息, 调用消息回调函数 */ + +static int message_dispatch(MSGIO_CTX *ctx) +{ + const char *myname = "message_dispatch"; + int ret; + + ret = dispatch_foreach(ctx->mio, &ctx->info, ctx->info.hdr.type); + if (ret < 0) { + acl_msg_error("%s: dispatch_foreach error, type=%d", + myname, ctx->info.hdr.type); + acl_msgio_close(ctx->mio); + return (-1); + } else if (ret == 0 && __global_mio) { + ret = dispatch_foreach(__global_mio, &ctx->info, + ctx->info.hdr.type); + if (ret < 0) { + acl_msg_error("%s: dispatch_foreach error, type=%d", + myname, ctx->info.hdr.type); + acl_msgio_close(ctx->mio); + return (-1); + } + } + return (ret); +} + +/* 异步读消息体回调函数 */ + +static int read_body_callback(ACL_ASTREAM *astream acl_unused, void *arg, + char *data, int dlen) +{ + const char *myname = "read_body_callback"; + MSGIO_CTX *ctx = (MSGIO_CTX *) arg; + + if (dlen != ctx->info.hdr.dlen) { + acl_msg_fatal("%s: dlen=%d, hdr.dlen=%d", + myname, dlen, ctx->info.hdr.dlen); + } + + /* 拷贝消息体数据 */ + acl_vstring_memcpy(ctx->info.body.buf, data, dlen); + + /* 发送消息至各个注册函数 */ + if (message_dispatch(ctx) < 0) + return (-1); + + /* 异步等待下一个消息 */ + return (acl_msgio_wait(ctx->mio)); +} + +/* 异步读消息头回调函数 */ + +static int read_hdr_callback(ACL_ASTREAM *astream, void *arg, + char *data, int dlen) +{ + const char *myname = "read_hdr_callback"; + MSGIO_CTX *ctx = (MSGIO_CTX *) arg; + const ACL_MSGIO_INFO *info = (const ACL_MSGIO_INFO *) data; + + /* 校验消息头长度 */ + if (dlen != sizeof(ctx->info.hdr)) { + acl_msg_fatal("%s: dlen=%d, size=%d", + myname, dlen, (int) sizeof(ctx->info.hdr)); + } + + ctx->info.hdr.type = info->hdr.type; + ctx->info.hdr.dlen = info->hdr.dlen; + + /* 如果该消息有消息体则读消息体 */ + if (ctx->info.hdr.dlen > 0) { + acl_aio_add_read_hook(astream, read_body_callback, ctx); + /* 开始读消息体 */ + acl_aio_readn(astream, ctx->info.hdr.dlen); + return (0); + } + + /* 该消息没有消息体,则开始派发消息 */ + if (message_dispatch(ctx) < 0) { + acl_msg_error("%s: message_dispatch error", myname); + return (-1); + } + + /* 异步等待下一个消息 */ + return (acl_msgio_wait(ctx->mio)); +} + +/* 异步方式等待IO消息 */ + +static int async_wait_msg(ACL_MSGIO *mio) +{ + /* 注册回调函数 */ + acl_aio_ctl(mio->stream.async, + ACL_AIO_CTL_READ_HOOK_ADD, read_hdr_callback, mio->ctx, + ACL_AIO_CTL_END); + + /* 异步读消息头 */ + acl_aio_readn(mio->stream.async, sizeof(mio->ctx->info.hdr)); + return (0); +} + +/* 同步方式等待IO消息 */ + +static int sync_wait_msg(ACL_MSGIO *mio) +{ + const char *myname = "sync_wait_msg"; + MSGIO_CTX *ctx = mio->ctx; + char buf[1024]; + int dlen, n; + + /* 同步读消息头 */ + if (acl_vstream_readn(mio->stream.sync, + &ctx->info.hdr, sizeof(ctx->info.hdr)) == ACL_VSTREAM_EOF) + { + acl_msg_error("%s: vstream read error", myname); + acl_vstream_close(mio->stream.sync); + return (-1); + } + + if (ctx->info.hdr.dlen <= 0) + return (message_dispatch(ctx)); /* 发送消息到各个注册函数 */ + + dlen = ctx->info.hdr.dlen; + /* 同步读消息体 */ + while (dlen > 0) { + n = acl_vstream_read(mio->stream.sync, buf, sizeof(buf)); + if (n == ACL_VSTREAM_EOF) { + acl_msg_error("%s: read msg body error(%s)", + myname, acl_last_serror()); + acl_vstream_close(mio->stream.sync); + return (-1); + } + acl_vstring_strncat(ctx->info.body.buf, buf, n); + dlen -= n; + } + + /* 发送消息到各个注册函数 */ + return (message_dispatch(ctx)); +} + +int acl_msgio_wait(ACL_MSGIO *mio_client) +{ + const char *myname = "acl_msgio_wait"; + + if (mio_client->type == ACL_MSGIO_TYPE_ACCEPT) + acl_msg_fatal("%s(%d): ACL_MSGIO_TYPE_ACCEPT use here", + myname, __LINE__); + if (mio_client->aio) + return (async_wait_msg(mio_client)); + else + return (sync_wait_msg(mio_client)); +} + +static void free_mio_onclose(ACL_VSTREAM *stream acl_unused, void *arg) +{ + ACL_MSGIO *mio = (ACL_MSGIO *) arg; + acl_msgio_unreg_all(mio); + acl_myfree(mio); +} + +static void free_msg_ctx_onclose(ACL_VSTREAM *stream acl_unused, void *arg) +{ + MSGIO_CTX *ctx = (MSGIO_CTX *) arg; + msg_ctx_free(ctx); +} + +static int close_callback(ACL_ASTREAM *astream, void *arg) +{ + const char *myname = "close_callback"; + MSGIO_CTX *ctx = (MSGIO_CTX *) arg; + + acl_msg_error("%s: close it(%d) now(%s)", myname, + ACL_VSTREAM_SOCK(acl_aio_vstream(astream)), acl_last_serror()); + + ctx->info.hdr.type = ACL_MSGIO_EXCEPT; + ctx->info.hdr.dlen = 0; + message_dispatch(ctx); + return (-1); +} + +static int io_timeout_callback(ACL_ASTREAM *astream, void *arg) +{ + MSGIO_CTX *ctx = (MSGIO_CTX *) arg; + + astream = astream; + ctx->info.hdr.type = ACL_MSGIO_TIMEOUT; + ctx->info.hdr.dlen = 0; + if (message_dispatch(ctx) < 0) + return (-1); + + return (0); +} + +/* 消息服务器接收客户端连接 */ + +static ACL_MSGIO *accept_connection(ACL_VSTREAM *sstream, ACL_MSGIO *listener) +{ + const char *myname = "accept_connection"; + ACL_VSTREAM *stream; + ACL_MSGIO *mio_client; + MSGIO_CTX *ctx_client; + + stream = acl_vstream_accept(sstream, NULL, 0); + if (stream == NULL) { + acl_msg_error("%s(%d): accept error(%s)", + myname, __LINE__, acl_last_serror()); + return (NULL); + } + + acl_non_blocking(ACL_VSTREAM_SOCK(stream), ACL_BLOCKING); + mio_client = msgio_new(); + mio_client->type = ACL_MSGIO_TYPE_SERVER; + mio_client->rw_timeout = listener->rw_timeout; + msg_list_clone(listener, mio_client); + mio_client->aio = listener->aio; + + ctx_client = msgio_ctx_new(mio_client, stream->remote_addr); + acl_vstream_add_close_handle(stream, free_msg_ctx_onclose, ctx_client); + acl_vstream_add_close_handle(stream, free_mio_onclose, mio_client); + + if (mio_client->aio) { + /* 若是异步读消息,则... */ + mio_client->stream.async = acl_aio_open(mio_client->aio, stream); + acl_aio_ctl(mio_client->stream.async, + ACL_AIO_CTL_TIMEOUT, mio_client->rw_timeout, + ACL_AIO_CTL_TIMEO_HOOK_ADD, io_timeout_callback, ctx_client, + ACL_AIO_CTL_CLOSE_HOOK_ADD, close_callback, ctx_client, + ACL_AIO_CTL_CTX, ctx_client, + ACL_AIO_CTL_END); + } else + mio_client->stream.sync = stream; + + return (mio_client); +} + +/* 监听描述符可读的回调函数 */ + +static int listen_callback(ACL_ASTREAM *sstream acl_unused, void *arg) +{ + const char *myname = "listen_callback"; + MSGIO_CTX *ctx = (MSGIO_CTX *) arg; + ACL_MSGIO *mio_client; + + if (sstream != ctx->mio->stream.async) + acl_msg_fatal("%s(%d): sstream invalid", myname, __LINE__); + + mio_client = accept_connection(acl_aio_vstream(sstream), ctx->mio); + if (mio_client == NULL) + acl_msg_warn("%s(%d): accept null", myname, __LINE__); + else if (acl_msgio_wait(mio_client) < 0) + acl_msg_warn("%s(%d): acl_msgio_wait error", myname, __LINE__); + return (0); +} + +ACL_MSGIO *acl_msgio_listen(ACL_AIO *aio, const char *addr) +{ + const char *myname = "acl_msgio_listen"; + char local_addr[] = "127.0.0.1:0"; + const char *addr_ptr; + MSGIO_CTX *ctx; + ACL_MSGIO *listener; + ACL_VSTREAM *stream; + + if (aio == NULL) + acl_msg_fatal("%s: aio null", myname); + if (addr != NULL) + addr_ptr = addr; + else + addr_ptr = local_addr; + + listener = msgio_new(); + listener->type = ACL_MSGIO_TYPE_ACCEPT; + stream = acl_vstream_listen_ex(addr_ptr, 128, ACL_NON_BLOCKING, 1024, 0); + if (stream == NULL) + acl_msg_fatal("%s: listen(%s) error(%s)", + myname, addr_ptr, acl_last_serror()); + + ACL_SAFE_STRNCPY(listener->addr, stream->local_addr, sizeof(listener->addr)); + + ctx = msgio_ctx_new(listener, listener->addr); + + listener->aio = aio; + listener->stream.async = acl_aio_open(aio, stream); + acl_aio_ctl(listener->stream.async, + ACL_AIO_CTL_LISTEN_FN, listen_callback, + ACL_AIO_CTL_TIMEOUT, 0, + ACL_AIO_CTL_CTX, ctx, + ACL_AIO_CTL_END); + acl_aio_listen(listener->stream.async); + return (listener); +} + +ACL_MSGIO *acl_msgio_accept(ACL_MSGIO *listener) +{ + ACL_MSGIO *mio_client; + + mio_client = accept_connection( + acl_aio_vstream(listener->stream.async), + listener); + return (mio_client); +} + +/* 连接超时回调函数 */ + +static int connect_timeout_callback(ACL_ASTREAM *astream, void *arg) +{ + MSGIO_CTX *ctx = (MSGIO_CTX *) arg; + + astream = astream; + ctx->info.hdr.type = ACL_MSGIO_CONNECT_TIMEOUT; + ctx->info.hdr.dlen = 0; + (void) message_dispatch(ctx); + return (-1); +} + +/* 连接成功回调函数 */ + +static int connect_callback(ACL_ASTREAM *astream, void *arg) +{ + MSGIO_CTX *ctx = (MSGIO_CTX *) arg; + + /* reset the timeout handler */ + acl_aio_ctl(astream, ACL_AIO_CTL_TIMEO_HOOK_ADD, io_timeout_callback, ctx, + ACL_AIO_CTL_END); + + ctx->info.hdr.type = ACL_MSGIO_CONNECT; + ctx->info.hdr.dlen = 0; + + if (message_dispatch(ctx) < 0) + return (-1); + + /* 异步等待消息 */ + return (acl_msgio_wait(ctx->mio)); +} + +/* 开始异步连接消息服务器 */ + +static ACL_ASTREAM *async_connect(ACL_AIO *aio, const char *addr, + int rw_timeout, MSGIO_CTX *ctx) +{ + ACL_ASTREAM *astream; + + astream = acl_aio_connect(aio, addr, rw_timeout); + if (astream == NULL) + return (NULL); + + acl_aio_ctl(astream, + ACL_AIO_CTL_CONNECT_HOOK_ADD, connect_callback, ctx, + ACL_AIO_CTL_CLOSE_HOOK_ADD, close_callback, ctx, + ACL_AIO_CTL_TIMEO_HOOK_ADD, connect_timeout_callback, ctx, + ACL_AIO_CTL_TIMEOUT, rw_timeout, + ACL_AIO_CTL_END); + return (astream); +} + +void acl_msgio_set_noblock(ACL_AIO *aio, ACL_MSGIO *mio) +{ + mio->aio = aio; + mio->stream.async = acl_aio_open(aio, mio->stream.sync); + acl_aio_ctl(mio->stream.async, + ACL_AIO_CTL_CTX, mio->ctx, + ACL_AIO_CTL_END); + + /* 异步等待消息 */ + (void) acl_msgio_wait(mio); +} + +ACL_MSGIO *acl_msgio_connect(ACL_AIO *aio, const char *addr, int rw_timeout) +{ + MSGIO_CTX *ctx; + ACL_MSGIO *mio; + ACL_VSTREAM *stream; + + mio = msgio_new(); + mio->keep_alive = 1; + mio->type = ACL_MSGIO_TYPE_CLIENT; + mio->rw_timeout = rw_timeout > 0 ? rw_timeout : 0; + ACL_SAFE_STRNCPY(mio->addr, addr, sizeof(mio->addr)); + + ctx = msgio_ctx_new(mio, addr); + + if (aio != NULL) { + mio->aio = aio; + mio->stream.async = async_connect(aio, addr, rw_timeout, ctx); + if (mio->stream.async) + stream = acl_aio_vstream(mio->stream.async); + else + stream = NULL; + } else { + stream = acl_vstream_connect(addr, ACL_BLOCKING, rw_timeout, + rw_timeout, 1024); + mio->stream.sync = stream; + } + + if (stream == NULL) { + msg_ctx_free(ctx); + acl_msgio_close(mio); + return (NULL); + } + + acl_vstream_add_close_handle(stream, free_msg_ctx_onclose, ctx); + acl_vstream_add_close_handle(stream, free_mio_onclose, mio); + return (mio); +} + +/* 同步发送消息 */ + +static int send_msg(ACL_MSGIO *mio, int type, void *data, int dlen) +{ + const char *myname = "send_msg"; + ACL_MSGIO_INFO info; + ACL_VSTREAM *stream; + struct iovec vector[2]; + int ret, n = 0; + + if (mio->aio) + stream = acl_aio_vstream(mio->stream.async); + else + stream = mio->stream.sync; + + if (stream == NULL) + acl_msg_fatal("%s: stream NULL", myname); + + if (data == NULL || dlen < 0) + dlen = 0; + + memset(&info, 0, sizeof(ACL_MSGIO_INFO)); + info.hdr.type = type; + info.hdr.dlen = dlen; + +#if 1 + vector[0].iov_base = (void*) &info.hdr; + vector[0].iov_len = sizeof(info.hdr); + n++; + if (data && dlen > 0) { + vector[1].iov_base = data; + vector[1].iov_len = dlen; + n++; + } + ret = acl_vstream_writevn(stream, vector, n); + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s: write msg hdr error(%s)", + myname, acl_last_serror()); + return (-1); + } + return (0); +#elif 1 + /* 同步发送消息头 */ + ret = acl_vstream_buffed_writen(stream, &info.hdr, sizeof(info.hdr)); + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s: write msg hdr error(%s)", + myname, acl_last_serror()); + return (-1); + } + + if (dlen > 0) { + /* 同步发送消息体 */ + ret = acl_vstream_buffed_writen(stream, data, dlen); + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s: write msg body error(%s)", + myname, acl_last_serror()); + return (-1); + } + } + + if (acl_vstream_fflush(stream) == ACL_VSTREAM_EOF) { + acl_msg_error("%s: fflush to stream(%d) error(%s)", + myname, ACL_VSTREAM_SOCK(stream), acl_last_serror()); + return (-1); + } +#else + /* 同步发送消息头 */ + ret = acl_vstream_writen(stream, &info.hdr, sizeof(info.hdr)); + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s: write msg hdr error(%s)", + myname, acl_last_serror()); + return (-1); + } + + if (dlen > 0) { + /* 同步发送消息体 */ + ret = acl_vstream_writen(stream, data, dlen); + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s: write msg body error(%s)", + myname, acl_last_serror()); + return (-1); + } + } +#endif + return (0); +} + +int acl_msgio_send(ACL_MSGIO *mio, int type, void *data, int dlen) +{ + const char *myname = "acl_msgio_send"; + + if (mio == NULL || mio->ctx == NULL) + acl_msg_fatal("%s: input invalid", myname); + + if (mio->type == ACL_MSGIO_TYPE_ACCEPT) { + ACL_MSGIO *client; + char addr[256]; + int ret; + + acl_msgio_addr(mio, addr, sizeof(addr)); + client = acl_msgio_connect(NULL, addr, 10); + if (client == NULL) { + acl_msg_error("%s: connect server(%s) error(%s)", + myname, addr, acl_last_serror()); + return (-1); + } + ret = send_msg(client, type, data, dlen); + acl_msgio_close(client); + return (ret); + } + + return (send_msg(mio, type, data, dlen)); +} + +void acl_msgio_addr(const ACL_MSGIO *mio, char *buf, size_t size) +{ + ACL_SAFE_STRNCPY(buf, mio->addr, size); +} + +ACL_AIO *acl_msgio_aio(ACL_MSGIO *mio) +{ + return (mio->aio); +} + +ACL_VSTREAM *acl_msgio_vstream(ACL_MSGIO *mio) +{ + if (mio->aio) + return (acl_aio_vstream(mio->stream.async)); + else + return (mio->stream.sync); +} + +ACL_ASTREAM *acl_msgio_astream(ACL_MSGIO *mio) +{ + if (mio->aio) + return (mio->stream.async); + else + return (NULL); +} diff --git a/lib_acl/src/net/IPTypes.h b/lib_acl/src/net/IPTypes.h new file mode 100644 index 000000000..46edd2cf5 --- /dev/null +++ b/lib_acl/src/net/IPTypes.h @@ -0,0 +1,331 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + iptypes.h + +--*/ + +#ifndef IP_TYPES_INCLUDED +#define IP_TYPES_INCLUDED + +#include "stdlib/acl_define.h" +#ifdef MS_VC6 + +#if _MSC_VER > 1000 +#pragma once +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#pragma warning(push) +#pragma warning(disable:4201) + +#include + +// Definitions and structures used by getnetworkparams and getadaptersinfo apis + +#define MAX_ADAPTER_DESCRIPTION_LENGTH 128 // arb. +#define MAX_ADAPTER_NAME_LENGTH 256 // arb. +#define MAX_ADAPTER_ADDRESS_LENGTH 8 // arb. +#define DEFAULT_MINIMUM_ENTITIES 32 // arb. +#define MAX_HOSTNAME_LEN 128 // arb. +#define MAX_DOMAIN_NAME_LEN 128 // arb. +#define MAX_SCOPE_ID_LEN 256 // arb. + +// +// types +// + +// Node Type + +#define BROADCAST_NODETYPE 1 +#define PEER_TO_PEER_NODETYPE 2 +#define MIXED_NODETYPE 4 +#define HYBRID_NODETYPE 8 + +// +// IP_ADDRESS_STRING - store an IP address as a dotted decimal string +// + +typedef struct { + char String[4 * 4]; +} IP_ADDRESS_STRING, *PIP_ADDRESS_STRING, IP_MASK_STRING, *PIP_MASK_STRING; + +// +// IP_ADDR_STRING - store an IP address with its corresponding subnet mask, +// both as dotted decimal strings +// + +typedef struct _IP_ADDR_STRING { + struct _IP_ADDR_STRING* Next; + IP_ADDRESS_STRING IpAddress; + IP_MASK_STRING IpMask; + DWORD Context; +} IP_ADDR_STRING, *PIP_ADDR_STRING; + +// +// ADAPTER_INFO - per-adapter information. All IP addresses are stored as +// strings +// + +typedef struct _IP_ADAPTER_INFO { + struct _IP_ADAPTER_INFO* Next; + DWORD ComboIndex; + char AdapterName[MAX_ADAPTER_NAME_LENGTH + 4]; + char Description[MAX_ADAPTER_DESCRIPTION_LENGTH + 4]; + UINT AddressLength; + BYTE Address[MAX_ADAPTER_ADDRESS_LENGTH]; + DWORD Index; + UINT Type; + UINT DhcpEnabled; + PIP_ADDR_STRING CurrentIpAddress; + IP_ADDR_STRING IpAddressList; + IP_ADDR_STRING GatewayList; + IP_ADDR_STRING DhcpServer; + BOOL HaveWins; + IP_ADDR_STRING PrimaryWinsServer; + IP_ADDR_STRING SecondaryWinsServer; + time_t LeaseObtained; + time_t LeaseExpires; +} IP_ADAPTER_INFO, *PIP_ADAPTER_INFO; + +#ifdef _WINSOCK2API_ + +// +// The following types require Winsock2. +// + +typedef enum { + IpPrefixOriginOther = 0, + IpPrefixOriginManual, + IpPrefixOriginWellKnown, + IpPrefixOriginDhcp, + IpPrefixOriginRouterAdvertisement, +} IP_PREFIX_ORIGIN; + +typedef enum { + IpSuffixOriginOther = 0, + IpSuffixOriginManual, + IpSuffixOriginWellKnown, + IpSuffixOriginDhcp, + IpSuffixOriginLinkLayerAddress, + IpSuffixOriginRandom, +} IP_SUFFIX_ORIGIN; + +typedef enum { + IpDadStateInvalid = 0, + IpDadStateTentative, + IpDadStateDuplicate, + IpDadStateDeprecated, + IpDadStatePreferred, +} IP_DAD_STATE; + +typedef struct _IP_ADAPTER_UNICAST_ADDRESS { + union { + ULONGLONG Alignment; + struct { + ULONG Length; + DWORD Flags; + }; + }; + struct _IP_ADAPTER_UNICAST_ADDRESS *Next; + SOCKET_ADDRESS Address; + + IP_PREFIX_ORIGIN PrefixOrigin; + IP_SUFFIX_ORIGIN SuffixOrigin; + IP_DAD_STATE DadState; + + ULONG ValidLifetime; + ULONG PreferredLifetime; + ULONG LeaseLifetime; +} IP_ADAPTER_UNICAST_ADDRESS, *PIP_ADAPTER_UNICAST_ADDRESS; + +typedef struct _IP_ADAPTER_ANYCAST_ADDRESS { + union { + ULONGLONG Alignment; + struct { + ULONG Length; + DWORD Flags; + }; + }; + struct _IP_ADAPTER_ANYCAST_ADDRESS *Next; + SOCKET_ADDRESS Address; +} IP_ADAPTER_ANYCAST_ADDRESS, *PIP_ADAPTER_ANYCAST_ADDRESS; + +typedef struct _IP_ADAPTER_MULTICAST_ADDRESS { + union { + ULONGLONG Alignment; + struct { + ULONG Length; + DWORD Flags; + }; + }; + struct _IP_ADAPTER_MULTICAST_ADDRESS *Next; + SOCKET_ADDRESS Address; +} IP_ADAPTER_MULTICAST_ADDRESS, *PIP_ADAPTER_MULTICAST_ADDRESS; + +// +// Per-address Flags +// +#define IP_ADAPTER_ADDRESS_DNS_ELIGIBLE 0x01 +#define IP_ADAPTER_ADDRESS_TRANSIENT 0x02 + +typedef struct _IP_ADAPTER_DNS_SERVER_ADDRESS { + union { + ULONGLONG Alignment; + struct { + ULONG Length; + DWORD Reserved; + }; + }; + struct _IP_ADAPTER_DNS_SERVER_ADDRESS *Next; + SOCKET_ADDRESS Address; +} IP_ADAPTER_DNS_SERVER_ADDRESS, *PIP_ADAPTER_DNS_SERVER_ADDRESS; + +typedef struct _IP_ADAPTER_PREFIX { + union { + ULONGLONG Alignment; + struct { + ULONG Length; + DWORD Flags; + }; + }; + struct _IP_ADAPTER_PREFIX *Next; + SOCKET_ADDRESS Address; + ULONG PrefixLength; +} IP_ADAPTER_PREFIX, *PIP_ADAPTER_PREFIX; + +// +// Per-adapter Flags +// +#define IP_ADAPTER_DDNS_ENABLED 0x01 +#define IP_ADAPTER_REGISTER_ADAPTER_SUFFIX 0x02 +#define IP_ADAPTER_DHCP_ENABLED 0x04 +#define IP_ADAPTER_RECEIVE_ONLY 0x08 +#define IP_ADAPTER_NO_MULTICAST 0x10 +#define IP_ADAPTER_IPV6_OTHER_STATEFUL_CONFIG 0x20 + +// +// OperStatus values from RFC 2863 +// +typedef enum { + IfOperStatusUp = 1, + IfOperStatusDown, + IfOperStatusTesting, + IfOperStatusUnknown, + IfOperStatusDormant, + IfOperStatusNotPresent, + IfOperStatusLowerLayerDown +} IF_OPER_STATUS; + +// +// Scope levels from RFC 2373 used with ZoneIndices array. +// +typedef enum { + ScopeLevelInterface = 1, + ScopeLevelLink = 2, + ScopeLevelSubnet = 3, + ScopeLevelAdmin = 4, + ScopeLevelSite = 5, + ScopeLevelOrganization = 8, + ScopeLevelGlobal = 14 +} SCOPE_LEVEL; + +typedef struct _IP_ADAPTER_ADDRESSES { + union { + ULONGLONG Alignment; + struct { + ULONG Length; + DWORD IfIndex; + }; + }; + struct _IP_ADAPTER_ADDRESSES *Next; + PCHAR AdapterName; + PIP_ADAPTER_UNICAST_ADDRESS FirstUnicastAddress; + PIP_ADAPTER_ANYCAST_ADDRESS FirstAnycastAddress; + PIP_ADAPTER_MULTICAST_ADDRESS FirstMulticastAddress; + PIP_ADAPTER_DNS_SERVER_ADDRESS FirstDnsServerAddress; + PWCHAR DnsSuffix; + PWCHAR Description; + PWCHAR FriendlyName; + BYTE PhysicalAddress[MAX_ADAPTER_ADDRESS_LENGTH]; + DWORD PhysicalAddressLength; + DWORD Flags; + DWORD Mtu; + DWORD IfType; + IF_OPER_STATUS OperStatus; + DWORD Ipv6IfIndex; + DWORD ZoneIndices[16]; + PIP_ADAPTER_PREFIX FirstPrefix; +} IP_ADAPTER_ADDRESSES, *PIP_ADAPTER_ADDRESSES; + +// +// Flags used as argument to GetAdaptersAddresses(). +// "SKIP" flags are added when the default is to include the information. +// "INCLUDE" flags are added when the default is to skip the information. +// +#define GAA_FLAG_SKIP_UNICAST 0x0001 +#define GAA_FLAG_SKIP_ANYCAST 0x0002 +#define GAA_FLAG_SKIP_MULTICAST 0x0004 +#define GAA_FLAG_SKIP_DNS_SERVER 0x0008 +#define GAA_FLAG_INCLUDE_PREFIX 0x0010 +#define GAA_FLAG_SKIP_FRIENDLY_NAME 0x0020 + +#endif /* _WINSOCK2API_ */ + +// +// IP_PER_ADAPTER_INFO - per-adapter IP information such as DNS server list. +// + +typedef struct _IP_PER_ADAPTER_INFO { + UINT AutoconfigEnabled; + UINT AutoconfigActive; + PIP_ADDR_STRING CurrentDnsServer; + IP_ADDR_STRING DnsServerList; +} IP_PER_ADAPTER_INFO, *PIP_PER_ADAPTER_INFO; + +// +// FIXED_INFO - the set of IP-related information which does not depend on DHCP +// + +typedef struct { + char HostName[MAX_HOSTNAME_LEN + 4] ; + char DomainName[MAX_DOMAIN_NAME_LEN + 4]; + PIP_ADDR_STRING CurrentDnsServer; + IP_ADDR_STRING DnsServerList; + UINT NodeType; + char ScopeId[MAX_SCOPE_ID_LEN + 4]; + UINT EnableRouting; + UINT EnableProxy; + UINT EnableDns; +} FIXED_INFO, *PFIXED_INFO; + +#ifndef IP_INTERFACE_NAME_INFO_DEFINED +#define IP_INTERFACE_NAME_INFO_DEFINED + +typedef struct ip_interface_name_info { + ULONG Index; // Interface Index + ULONG MediaType; // Interface Types - see ipifcons.h + UCHAR ConnectionType; + UCHAR AccessType; + GUID DeviceGuid; // Device GUID is the guid of the device + // that IP exposes + GUID InterfaceGuid; // Interface GUID, if not GUID_NULL is the + // GUID for the interface mapped to the device. +} IP_INTERFACE_NAME_INFO, *PIP_INTERFACE_NAME_INFO; + +#endif + +#pragma warning(pop) + +#ifdef __cplusplus +} +#endif + +#endif // MS_VC6 +#endif diff --git a/lib_acl/src/net/Ipifcons.h b/lib_acl/src/net/Ipifcons.h new file mode 100644 index 000000000..5ecba939d --- /dev/null +++ b/lib_acl/src/net/Ipifcons.h @@ -0,0 +1,279 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + ipifcons.h + +Abstract: + Constants needed for the Interface Object + +--*/ + +#ifndef __IPIFCONS_H__ +#define __IPIFCONS_H__ + +#include "stdlib/acl_define.h" +#ifdef MS_VC6 + +#if _MSC_VER > 1000 +#pragma once +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +////////////////////////////////////////////////////////////////////////////// +// // +// Media types // +// // +////////////////////////////////////////////////////////////////////////////// + +#define MIN_IF_TYPE 1 + +#define IF_TYPE_OTHER 1 // None of the below +#define IF_TYPE_REGULAR_1822 2 +#define IF_TYPE_HDH_1822 3 +#define IF_TYPE_DDN_X25 4 +#define IF_TYPE_RFC877_X25 5 +#define IF_TYPE_ETHERNET_CSMACD 6 +#define IF_TYPE_IS088023_CSMACD 7 +#define IF_TYPE_ISO88024_TOKENBUS 8 +#define IF_TYPE_ISO88025_TOKENRING 9 +#define IF_TYPE_ISO88026_MAN 10 +#define IF_TYPE_STARLAN 11 +#define IF_TYPE_PROTEON_10MBIT 12 +#define IF_TYPE_PROTEON_80MBIT 13 +#define IF_TYPE_HYPERCHANNEL 14 +#define IF_TYPE_FDDI 15 +#define IF_TYPE_LAP_B 16 +#define IF_TYPE_SDLC 17 +#define IF_TYPE_DS1 18 // DS1-MIB +#define IF_TYPE_E1 19 // Obsolete; see DS1-MIB +#define IF_TYPE_BASIC_ISDN 20 +#define IF_TYPE_PRIMARY_ISDN 21 +#define IF_TYPE_PROP_POINT2POINT_SERIAL 22 // proprietary serial +#define IF_TYPE_PPP 23 +#define IF_TYPE_SOFTWARE_LOOPBACK 24 +#define IF_TYPE_EON 25 // CLNP over IP +#define IF_TYPE_ETHERNET_3MBIT 26 +#define IF_TYPE_NSIP 27 // XNS over IP +#define IF_TYPE_SLIP 28 // Generic Slip +#define IF_TYPE_ULTRA 29 // ULTRA Technologies +#define IF_TYPE_DS3 30 // DS3-MIB +#define IF_TYPE_SIP 31 // SMDS, coffee +#define IF_TYPE_FRAMERELAY 32 // DTE only +#define IF_TYPE_RS232 33 +#define IF_TYPE_PARA 34 // Parallel port +#define IF_TYPE_ARCNET 35 +#define IF_TYPE_ARCNET_PLUS 36 +#define IF_TYPE_ATM 37 // ATM cells +#define IF_TYPE_MIO_X25 38 +#define IF_TYPE_SONET 39 // SONET or SDH +#define IF_TYPE_X25_PLE 40 +#define IF_TYPE_ISO88022_LLC 41 +#define IF_TYPE_LOCALTALK 42 +#define IF_TYPE_SMDS_DXI 43 +#define IF_TYPE_FRAMERELAY_SERVICE 44 // FRNETSERV-MIB +#define IF_TYPE_V35 45 +#define IF_TYPE_HSSI 46 +#define IF_TYPE_HIPPI 47 +#define IF_TYPE_MODEM 48 // Generic Modem +#define IF_TYPE_AAL5 49 // AAL5 over ATM +#define IF_TYPE_SONET_PATH 50 +#define IF_TYPE_SONET_VT 51 +#define IF_TYPE_SMDS_ICIP 52 // SMDS InterCarrier Interface +#define IF_TYPE_PROP_VIRTUAL 53 // Proprietary virtual/internal +#define IF_TYPE_PROP_MULTIPLEXOR 54 // Proprietary multiplexing +#define IF_TYPE_IEEE80212 55 // 100BaseVG +#define IF_TYPE_FIBRECHANNEL 56 +#define IF_TYPE_HIPPIINTERFACE 57 +#define IF_TYPE_FRAMERELAY_INTERCONNECT 58 // Obsolete, use 32 or 44 +#define IF_TYPE_AFLANE_8023 59 // ATM Emulated LAN for 802.3 +#define IF_TYPE_AFLANE_8025 60 // ATM Emulated LAN for 802.5 +#define IF_TYPE_CCTEMUL 61 // ATM Emulated circuit +#define IF_TYPE_FASTETHER 62 // Fast Ethernet (100BaseT) +#define IF_TYPE_ISDN 63 // ISDN and X.25 +#define IF_TYPE_V11 64 // CCITT V.11/X.21 +#define IF_TYPE_V36 65 // CCITT V.36 +#define IF_TYPE_G703_64K 66 // CCITT G703 at 64Kbps +#define IF_TYPE_G703_2MB 67 // Obsolete; see DS1-MIB +#define IF_TYPE_QLLC 68 // SNA QLLC +#define IF_TYPE_FASTETHER_FX 69 // Fast Ethernet (100BaseFX) +#define IF_TYPE_CHANNEL 70 +#define IF_TYPE_IEEE80211 71 // Radio spread spectrum +#define IF_TYPE_IBM370PARCHAN 72 // IBM System 360/370 OEMI Channel +#define IF_TYPE_ESCON 73 // IBM Enterprise Systems Connection +#define IF_TYPE_DLSW 74 // Data Link Switching +#define IF_TYPE_ISDN_S 75 // ISDN S/T interface +#define IF_TYPE_ISDN_U 76 // ISDN U interface +#define IF_TYPE_LAP_D 77 // Link Access Protocol D +#define IF_TYPE_IPSWITCH 78 // IP Switching Objects +#define IF_TYPE_RSRB 79 // Remote Source Route Bridging +#define IF_TYPE_ATM_LOGICAL 80 // ATM Logical Port +#define IF_TYPE_DS0 81 // Digital Signal Level 0 +#define IF_TYPE_DS0_BUNDLE 82 // Group of ds0s on the same ds1 +#define IF_TYPE_BSC 83 // Bisynchronous Protocol +#define IF_TYPE_ASYNC 84 // Asynchronous Protocol +#define IF_TYPE_CNR 85 // Combat Net Radio +#define IF_TYPE_ISO88025R_DTR 86 // ISO 802.5r DTR +#define IF_TYPE_EPLRS 87 // Ext Pos Loc Report Sys +#define IF_TYPE_ARAP 88 // Appletalk Remote Access Protocol +#define IF_TYPE_PROP_CNLS 89 // Proprietary Connectionless Proto +#define IF_TYPE_HOSTPAD 90 // CCITT-ITU X.29 PAD Protocol +#define IF_TYPE_TERMPAD 91 // CCITT-ITU X.3 PAD Facility +#define IF_TYPE_FRAMERELAY_MPI 92 // Multiproto Interconnect over FR +#define IF_TYPE_X213 93 // CCITT-ITU X213 +#define IF_TYPE_ADSL 94 // Asymmetric Digital Subscrbr Loop +#define IF_TYPE_RADSL 95 // Rate-Adapt Digital Subscrbr Loop +#define IF_TYPE_SDSL 96 // Symmetric Digital Subscriber Loop +#define IF_TYPE_VDSL 97 // Very H-Speed Digital Subscrb Loop +#define IF_TYPE_ISO88025_CRFPRINT 98 // ISO 802.5 CRFP +#define IF_TYPE_MYRINET 99 // Myricom Myrinet +#define IF_TYPE_VOICE_EM 100 // Voice recEive and transMit +#define IF_TYPE_VOICE_FXO 101 // Voice Foreign Exchange Office +#define IF_TYPE_VOICE_FXS 102 // Voice Foreign Exchange Station +#define IF_TYPE_VOICE_ENCAP 103 // Voice encapsulation +#define IF_TYPE_VOICE_OVERIP 104 // Voice over IP encapsulation +#define IF_TYPE_ATM_DXI 105 // ATM DXI +#define IF_TYPE_ATM_FUNI 106 // ATM FUNI +#define IF_TYPE_ATM_IMA 107 // ATM IMA +#define IF_TYPE_PPPMULTILINKBUNDLE 108 // PPP Multilink Bundle +#define IF_TYPE_IPOVER_CDLC 109 // IBM ipOverCdlc +#define IF_TYPE_IPOVER_CLAW 110 // IBM Common Link Access to Workstn +#define IF_TYPE_STACKTOSTACK 111 // IBM stackToStack +#define IF_TYPE_VIRTUALIPADDRESS 112 // IBM VIPA +#define IF_TYPE_MPC 113 // IBM multi-proto channel support +#define IF_TYPE_IPOVER_ATM 114 // IBM ipOverAtm +#define IF_TYPE_ISO88025_FIBER 115 // ISO 802.5j Fiber Token Ring +#define IF_TYPE_TDLC 116 // IBM twinaxial data link control +#define IF_TYPE_GIGABITETHERNET 117 +#define IF_TYPE_HDLC 118 +#define IF_TYPE_LAP_F 119 +#define IF_TYPE_V37 120 +#define IF_TYPE_X25_MLP 121 // Multi-Link Protocol +#define IF_TYPE_X25_HUNTGROUP 122 // X.25 Hunt Group +#define IF_TYPE_TRANSPHDLC 123 +#define IF_TYPE_INTERLEAVE 124 // Interleave channel +#define IF_TYPE_FAST 125 // Fast channel +#define IF_TYPE_IP 126 // IP (for APPN HPR in IP networks) +#define IF_TYPE_DOCSCABLE_MACLAYER 127 // CATV Mac Layer +#define IF_TYPE_DOCSCABLE_DOWNSTREAM 128 // CATV Downstream interface +#define IF_TYPE_DOCSCABLE_UPSTREAM 129 // CATV Upstream interface +#define IF_TYPE_A12MPPSWITCH 130 // Avalon Parallel Processor +#define IF_TYPE_TUNNEL 131 // Encapsulation interface +#define IF_TYPE_COFFEE 132 // Coffee pot +#define IF_TYPE_CES 133 // Circuit Emulation Service +#define IF_TYPE_ATM_SUBINTERFACE 134 // ATM Sub Interface +#define IF_TYPE_L2_VLAN 135 // Layer 2 Virtual LAN using 802.1Q +#define IF_TYPE_L3_IPVLAN 136 // Layer 3 Virtual LAN using IP +#define IF_TYPE_L3_IPXVLAN 137 // Layer 3 Virtual LAN using IPX +#define IF_TYPE_DIGITALPOWERLINE 138 // IP over Power Lines +#define IF_TYPE_MEDIAMAILOVERIP 139 // Multimedia Mail over IP +#define IF_TYPE_DTM 140 // Dynamic syncronous Transfer Mode +#define IF_TYPE_DCN 141 // Data Communications Network +#define IF_TYPE_IPFORWARD 142 // IP Forwarding Interface +#define IF_TYPE_MSDSL 143 // Multi-rate Symmetric DSL +#define IF_TYPE_IEEE1394 144 // IEEE1394 High Perf Serial Bus +#define IF_TYPE_RECEIVE_ONLY 145 // TV adapter type + +#define MAX_IF_TYPE 145 + +////////////////////////////////////////////////////////////////////////////// +// // +// Access types // +// // +////////////////////////////////////////////////////////////////////////////// + +#define IF_ACCESS_LOOPBACK 1 +#define IF_ACCESS_BROADCAST 2 +#define IF_ACCESS_POINTTOPOINT 3 +#define IF_ACCESS_POINTTOMULTIPOINT 4 + +////////////////////////////////////////////////////////////////////////////// +// // +// Interface Capabilities (bit flags) // +// // +////////////////////////////////////////////////////////////////////////////// + +#define IF_CHECK_NONE 0x00 +#define IF_CHECK_MCAST 0x01 +#define IF_CHECK_SEND 0x02 + + +////////////////////////////////////////////////////////////////////////////// +// // +// Connection Types // +// // +////////////////////////////////////////////////////////////////////////////// + +#define IF_CONNECTION_DEDICATED 1 +#define IF_CONNECTION_PASSIVE 2 +#define IF_CONNECTION_DEMAND 3 + + +#define IF_ADMIN_STATUS_UP 1 +#define IF_ADMIN_STATUS_DOWN 2 +#define IF_ADMIN_STATUS_TESTING 3 + +////////////////////////////////////////////////////////////////////////////// +// // +// The following are the the operational states for WAN and LAN interfaces. // +// The order of the states seems weird, but is done for a purpose. All // +// states >= CONNECTED can transmit data right away. States >= DISCONNECTED // +// can tx data but some set up might be needed. States < DISCONNECTED can // +// not transmit data. // +// A card is marked UNREACHABLE if DIM calls InterfaceUnreachable for // +// reasons other than failure to connect. // +// // +// NON_OPERATIONAL -- Valid for LAN Interfaces. Means the card is not // +// working or not plugged in or has no address. // +// UNREACHABLE -- Valid for WAN Interfaces. Means the remote site is // +// not reachable at this time. // +// DISCONNECTED -- Valid for WAN Interfaces. Means the remote site is // +// not connected at this time. // +// CONNECTING -- Valid for WAN Interfaces. Means a connection attempt // +// has been initiated to the remote site. // +// CONNECTED -- Valid for WAN Interfaces. Means the remote site is // +// connected. // +// OPERATIONAL -- Valid for LAN Interfaces. Means the card is plugged // +// in and working. // +// // +// It is the users duty to convert these values to MIB-II values if they // +// are to be used by a subagent // +// // +////////////////////////////////////////////////////////////////////////////// + +#define IF_OPER_STATUS_NON_OPERATIONAL 0 +#define IF_OPER_STATUS_UNREACHABLE 1 +#define IF_OPER_STATUS_DISCONNECTED 2 +#define IF_OPER_STATUS_CONNECTING 3 +#define IF_OPER_STATUS_CONNECTED 4 +#define IF_OPER_STATUS_OPERATIONAL 5 + +#define MIB_IF_TYPE_OTHER 1 +#define MIB_IF_TYPE_ETHERNET 6 +#define MIB_IF_TYPE_TOKENRING 9 +#define MIB_IF_TYPE_FDDI 15 +#define MIB_IF_TYPE_PPP 23 +#define MIB_IF_TYPE_LOOPBACK 24 +#define MIB_IF_TYPE_SLIP 28 + +#define MIB_IF_ADMIN_STATUS_UP 1 +#define MIB_IF_ADMIN_STATUS_DOWN 2 +#define MIB_IF_ADMIN_STATUS_TESTING 3 + +#define MIB_IF_OPER_STATUS_NON_OPERATIONAL 0 +#define MIB_IF_OPER_STATUS_UNREACHABLE 1 +#define MIB_IF_OPER_STATUS_DISCONNECTED 2 +#define MIB_IF_OPER_STATUS_CONNECTING 3 +#define MIB_IF_OPER_STATUS_CONNECTED 4 +#define MIB_IF_OPER_STATUS_OPERATIONAL 5 + +#ifdef __cplusplus +} +#endif +#endif //MS_VC6 +#endif //__ROUTING_IPIFCONS_H__ diff --git a/lib_acl/src/net/acl_access.c b/lib_acl/src/net/acl_access.c new file mode 100644 index 000000000..95a633c86 --- /dev/null +++ b/lib_acl/src/net/acl_access.c @@ -0,0 +1,194 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_stdlib.h" +#include "net/acl_access.h" + +#endif + +/* local variables */ +static ACL_IPLINK *__host_allow_link = NULL; +static void (*__log_fn) (const char *fmt, ...) = acl_msg_info; +static int __host_allow_all = 0; + +static void __access_init(void) +{ + char myname[] = "__access_init"; + + if (__host_allow_link) + return; + + __host_allow_link = acl_iplink_create(10); + if (__host_allow_link == NULL) { + char tbuf[256]; + __log_fn("FATAL, %s(%d)->%s: call acl_iplink_create error=%s", + __FILE__, __LINE__, myname, + acl_last_strerror(tbuf, sizeof(tbuf))); + exit (1); + } +} + +int acl_access_add(const char *data, const char *sep1, const char *sep2) +{ + /* data format: ip1 sep2 ip2 sep1 ip3 sep2 ip4 ... + * example: + * 127.0.0.1:127.0.0.1, 10.0.250.1:10.0.250:10, 192.168.0.1:192.168.0.255 + * 127.0.0.1,127.0.0.1; 10.0.250.1,10.0.250:10; 192.168.0.1,192.168.0.255 + */ + char myname[] = "acl_access_add"; + ACL_ARGV *items; + char *psrc, *ptr, *from, *to, buf[256]; + int i; + + if (data == NULL || *data == 0) { + __log_fn("%s, %s(%d): input invalid", + __FILE__, myname, __LINE__); + return (0); + } + + if (__host_allow_all) + return (0); + + if (strcasecmp(data, "all") == 0) { + __host_allow_all = 1; + return (0); + } + + if (strcmp(sep1, "0.0.0.0") == 0 && strcmp(sep2, "255.255.255.255") == 0) { + __host_allow_all = 1; + return (0); + } + + if (__host_allow_link == NULL) + __access_init(); + + items = acl_argv_split(data, sep1); + if (items == NULL) { + char tbuf[256]; + __log_fn("%s, %s(%d): acl_argv_split error(%s)", + __FILE__, myname, __LINE__, acl_last_strerror(tbuf, sizeof(tbuf))); + exit (1); + } + +#define STRIP_SPACE(_ptr) do { \ + char *_tmp; \ + while (*_ptr == ' ' || *_ptr == '\t') \ + _ptr++; \ + _tmp = _ptr; \ + while (*_tmp) { \ + if (*_tmp == ' ' || *_tmp == '\t') { \ + *_tmp = 0; \ + break; \ + } \ + _tmp++; \ + } \ +} while (0) + + for (i = 0; i < items->argc; i++) { + psrc = acl_argv_index(items, i); + ACL_SAFE_STRNCPY(buf, psrc, sizeof(buf) - 1); + ptr = buf; + + from = acl_mystrtok(&ptr, sep2); + if (from == NULL || *from == 0) { + __log_fn("%s, %s(%d): invalid data(%s)", + __FILE__, myname, __LINE__, psrc); + continue; + } + + STRIP_SPACE(from); + if (*from == 0) + continue; + + to = acl_mystrtok(&ptr, sep2); + if (to == NULL || *to == 0) { + __log_fn("%s, %s(%d): invalid data(%s)", + __FILE__, myname, __LINE__, psrc); + continue; + } + + STRIP_SPACE(to); + if (*to == 0) + continue; + + if (acl_msg_verbose) + __log_fn("add access: from(%s), to(%s)", from, to); + if (acl_iplink_insert(__host_allow_link, from, to) == NULL) + __log_fn("%s, %s(%d): acl_iplink_insert error(%s)", + __FILE__, myname, __LINE__, psrc); + } + + acl_argv_free(items); + + return (0); +} + +int acl_access_cfg(ACL_XINETD_CFG_PARSER *xcp, const char *name) +{ + char myname[] = "acl_access_cfg"; + const ACL_ARRAY *p_array; + const char *pctr; + int i, n; + + p_array = acl_xinetd_cfg_get_ex(xcp, name); + if (p_array == NULL) { + __log_fn("%s(%d)->%s: host allow all", + __FILE__, __LINE__, myname); + return (0); + } + + n = acl_array_size(p_array); + for (i = 0; i < n; i++) { + pctr = (const char *) acl_array_index(p_array, i); + if (pctr == NULL) + break; + acl_access_add(pctr, ",", ":"); + } + + return (0); +} + +void acl_access_setup_logfn(void (*log_fn)(const char *fmt, ...)) +{ + if (log_fn != NULL) + __log_fn = log_fn; +} + +int acl_access_permit(const char *addr) +{ + char ip[32], *ptr; + + if (__host_allow_all) + return (1); + if (__host_allow_link == NULL) + return (1); + + ACL_SAFE_STRNCPY(ip, addr, sizeof(ip)); + ptr = strchr(ip, ':'); + if (ptr) + *ptr = 0; + if (acl_iplink_lookup_str(__host_allow_link, ip) != NULL) + return (1); + + return (0); +} + +static void __access_cfg_out(void) +{ + + acl_iplink_list(__host_allow_link); +} + +void acl_access_debug(void) +{ + __access_cfg_out(); +} diff --git a/lib_acl/src/net/acl_host_port.c b/lib_acl/src/net/acl_host_port.c new file mode 100644 index 000000000..f74c25d15 --- /dev/null +++ b/lib_acl/src/net/acl_host_port.c @@ -0,0 +1,77 @@ +/* System library. */ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#include +#include +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +/* Utility library. */ + +#include "stdlib/acl_msg.h" +#include "stdlib/acl_split_at.h" +#include "stdlib/acl_stringops.h" + +#include "net/acl_valid_hostname.h" + +/* Global library. */ + +#include "net/acl_host_port.h" + +#endif + +/* host_port - parse string into host and port, destroy string */ + +const char *acl_host_port(char *buf, char **host, char *def_host, + char **port, char *def_service) +{ + char *cp = buf; + + /* + * [host]:port, [host]:, [host]. + */ + if (*cp == '[') { + *host = ++cp; + if ((cp = acl_split_at(cp, ']')) == 0) + return ("missing \"]\""); + if (*cp && *cp++ != ':') + return ("garbage after \"]\""); + *port = *cp ? cp : def_service; + } + + /* + * host:port, host:, host, :port, port. + */ + else { + if ((cp = acl_split_at_right(buf, ':')) != 0) { + *host = *buf ? buf : def_host; + *port = *cp ? cp : def_service; + } else { + *host = def_host ? def_host : (*buf ? buf : 0); + *port = def_service ? def_service : (*buf ? buf : 0); + } + } + if (*host == 0) + return ("missing host information"); + if (*port == 0) + return ("missing service information"); + + /* + * Final sanity checks. We're still sloppy, allowing bare numerical + * network addresses instead of requiring proper [ipaddress] forms. + */ + if (*host != def_host + && !acl_valid_hostname(*host, ACL_DONT_GRIPE) + && !acl_valid_hostaddr(*host, ACL_DONT_GRIPE)) + return ("valid hostname or network address required"); + if (*port != def_service && ACL_ISDIGIT(**port) && !acl_alldig(*port)) + return ("garbage after numerical service"); + return (0); +} diff --git a/lib_acl/src/net/acl_ifconf.c b/lib_acl/src/net/acl_ifconf.c new file mode 100644 index 000000000..dc1301bd7 --- /dev/null +++ b/lib_acl/src/net/acl_ifconf.c @@ -0,0 +1,333 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include "stdlib/acl_msg.h" +#include "stdlib/acl_iterator.h" +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_mystring.h" +#include "net/acl_sane_inet.h" +#include "net/acl_ifconf.h" + +#endif + +static const ACL_IFADDR *ifaddrs_iter_head(ACL_ITER *iter, struct ACL_IFCONF *ifconf) +{ + iter->dlen = -1; + iter->key = NULL; + iter->klen = -1; + + iter->i = 0; + iter->size = ifconf->length; + iter->ptr = iter->data = &ifconf->addrs[0]; + return (iter->ptr); +} + +static const ACL_IFADDR *ifaddrs_iter_next(ACL_ITER *iter, struct ACL_IFCONF *ifconf) +{ + iter->i++; + if (iter->i >= ifconf->length) + iter->data = iter->ptr = NULL; + else + iter->data = iter->ptr = &ifconf->addrs[iter->i]; + return (iter->ptr); +} + +static const ACL_IFADDR *ifaddrs_iter_tail(ACL_ITER *iter, struct ACL_IFCONF *ifconf) +{ + iter->dlen = -1; + iter->key = NULL; + iter->klen = -1; + + iter->i = ifconf->length - 1; + iter->size = ifconf->length; + if (iter->i < 0) + iter->data = iter->ptr = NULL; + else + iter->ptr = iter->data = &ifconf->addrs[iter->i]; + return (iter->ptr); +} + +static const ACL_IFADDR *ifaddrs_iter_prev(ACL_ITER *iter, struct ACL_IFCONF *ifconf) +{ + iter->i--; + if (iter->i < 0) + iter->data = iter->ptr = NULL; + else + iter->data = iter->ptr = &ifconf->addrs[iter->i]; + return (iter->ptr); +} + +#ifdef ACL_UNIX + +#include +#include +#include +#include +#include +#ifdef ACL_SUNOS5 +#include +#endif + +ACL_IFCONF *acl_get_ifaddrs() +{ + const char *myname = "acl_get_ifaddrs"; + ACL_IFCONF *ifconf; + struct ifreq *ifaces; + int ifaces_size = 8 * sizeof(struct ifreq); + struct ifconf param; + int sock; + int i, j; + + sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP); + if (sock <= 0) { + acl_msg_error("%s(%d): create socket error(%s)", + myname, __LINE__, acl_last_serror()); + return (NULL); + } + + ifaces = acl_mymalloc(ifaces_size); + for (;;) { + param.ifc_len = ifaces_size; + param.ifc_req = ifaces; + if (ioctl(sock, SIOCGIFCONF, ¶m)) { + acl_msg_error("%s(%d): ioctl error(%s)", + myname, __LINE__, acl_last_serror()); + close(sock); + acl_myfree(ifaces); + return (NULL); + } + if (param.ifc_len < ifaces_size) + break; + acl_myfree(ifaces); + ifaces_size *= 2; + ifaces = acl_mymalloc(ifaces_size); + } + + close(sock); + + ifconf = (ACL_IFCONF*) acl_mymalloc(sizeof(ACL_IFCONF)); + ifconf->length = param.ifc_len / sizeof(struct ifreq); + ifconf->addrs = (ACL_IFADDR*) + acl_mycalloc(ifconf->length, sizeof(ACL_IFADDR)); + + for (i = 0, j = 0; i < ifconf->length; i++) { + if (ifaces[i].ifr_addr.sa_family != AF_INET +#ifdef ACL_MACOSX + && ifaces[i].ifr_addr.sa_family != AF_LINK +#endif + ) + continue; + ifconf->addrs[j].name = acl_mystrdup(ifaces[i].ifr_name); + ifconf->addrs[j].addr = ((struct sockaddr_in *) + &(ifaces[i].ifr_addr))->sin_addr.s_addr; + acl_inet_ntoa(((struct sockaddr_in *) &ifaces[i].ifr_addr)->sin_addr, + ifconf->addrs[j].ip, sizeof(ifconf->addrs[j].ip)); + j++; + } + + if (j == 0) { + acl_myfree(ifconf->addrs); + acl_myfree(ifconf); + return (NULL); + } + + ifconf->length = j; /* reset the ifconf->length */ + + /* set the iterator callback */ + ifconf->iter_head = ifaddrs_iter_head; + ifconf->iter_next = ifaddrs_iter_next; + ifconf->iter_tail = ifaddrs_iter_tail; + ifconf->iter_prev = ifaddrs_iter_prev; + + acl_myfree(ifaces); + return (ifconf); +} + +#elif defined(ACL_MS_WINDOWS) + +#ifdef MS_VC6 + +#include "iptypes.h" +#include "Ipifcons.h" + +typedef HRESULT STDAPICALLTYPE PGAINFO(PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen); + +ACL_IFCONF *acl_get_ifaddrs() +{ + const char *myname = "acl_get_ifaddrs"; + IP_ADAPTER_INFO info_temp, *infos, *info; + ACL_IFCONF *ifconf; + ULONG len = 0; + int j; + HMODULE hInst; + PGAINFO *pGAInfo; + + hInst = LoadLibrary("iphlpapi.dll"); + if(!hInst) { + MessageBox(0, "iphlpapi.dll not supported in this platform!", "Error", 0); + return (NULL); + } + + pGAInfo = (PGAINFO*) GetProcAddress(hInst,"GetAdaptersInfo"); + if (pGAInfo == NULL) { + MessageBox(0, "can't find GetAdaptersInfo function!", "Error", 0); + return (NULL); + } + + if (pGAInfo(&info_temp, &len) != ERROR_BUFFER_OVERFLOW) { + acl_msg_error("%s(%d): GetAdaptersInfo eror(%s)", + myname, __LINE__, acl_last_serror()); + FreeLibrary(hInst); + return (NULL); + } + + infos = (IP_ADAPTER_INFO *) acl_mymalloc(len); + if (pGAInfo(infos, &len) != NO_ERROR) { + acl_msg_error("%s(%d): GetAdaptersInfo eror(%s)", + myname, __LINE__, acl_last_serror()); + acl_myfree(infos); + FreeLibrary(hInst); + return (NULL); + } + + ifconf = (ACL_IFCONF*) acl_mymalloc(sizeof(ACL_IFCONF)); + ifconf->length = len / sizeof(IP_ADAPTER_INFO) + 1; + ifconf->addrs = (ACL_IFADDR*) + acl_mycalloc(ifconf->length, sizeof(ACL_IFADDR)); + + for (info = infos, j = 0; info != NULL; info = info->Next) { + if (info->Type == MIB_IF_TYPE_LOOPBACK) + continue; + if (strcmp(info->IpAddressList.IpAddress.String, "0.0.0.0") == 0) + continue; + if (acl_is_ip(info->IpAddressList.IpAddress.String) < 0) + continue; + + ifconf->addrs[j].name = acl_mystrdup(info->AdapterName); + ifconf->addrs[j].desc = acl_mystrdup(info->Description); + snprintf(ifconf->addrs[j].ip, sizeof(ifconf->addrs[j].ip), + "%s", info->IpAddressList.IpAddress.String); + ifconf->addrs[j].addr = inet_addr(ifconf->addrs[j].ip); + j++; + if (j == ifconf->length) { + ifconf->length *= 2; + ifconf->addrs = (ACL_IFADDR*) acl_myrealloc(ifconf->addrs, + ifconf->length * sizeof(ACL_IFADDR)); + } + } + + acl_myfree(infos); + + if (j == 0) { + acl_myfree(ifconf->addrs); + acl_myfree(ifconf); + FreeLibrary(hInst); + return (NULL); + } + + ifconf->length = j; /* reset the ifconf->length */ + + /* set the iterator callback */ + ifconf->iter_head = ifaddrs_iter_head; + ifconf->iter_next = ifaddrs_iter_next; + ifconf->iter_tail = ifaddrs_iter_tail; + ifconf->iter_prev = ifaddrs_iter_prev; + + FreeLibrary(hInst); + return (ifconf); +} + +#else /* MS_VC6 */ + +#include + +ACL_IFCONF *acl_get_ifaddrs() +{ + const char *myname = "acl_get_ifaddrs"; + IP_ADAPTER_INFO info_temp, *infos, *info; + ACL_IFCONF *ifconf; + ULONG len = 0; + int j; + + if (GetAdaptersInfo(&info_temp, &len) != ERROR_BUFFER_OVERFLOW) { + acl_msg_error("%s(%d): GetAdaptersInfo eror(%s)", + myname, __LINE__, acl_last_serror()); + return (NULL); + } + + infos = (IP_ADAPTER_INFO *) acl_mymalloc(len); + if (GetAdaptersInfo(infos, &len) != NO_ERROR) { + acl_msg_error("%s(%d): GetAdaptersInfo eror(%s)", + myname, __LINE__, acl_last_serror()); + acl_myfree(infos); + return (NULL); + } + + ifconf = (ACL_IFCONF*) acl_mymalloc(sizeof(ACL_IFCONF)); + ifconf->length = len / sizeof(IP_ADAPTER_INFO) + 1; + ifconf->addrs = (ACL_IFADDR*) + acl_mycalloc(ifconf->length, sizeof(ACL_IFADDR)); + + for (info = infos, j = 0; info != NULL; info = info->Next) { + if (info->Type == MIB_IF_TYPE_LOOPBACK) + continue; + if (strcmp(info->IpAddressList.IpAddress.String, "0.0.0.0") == 0) + continue; + if (acl_is_ip(info->IpAddressList.IpAddress.String) < 0) + continue; + + ifconf->addrs[j].name = acl_mystrdup(info->AdapterName); + ifconf->addrs[j].desc = acl_mystrdup(info->Description); + snprintf(ifconf->addrs[j].ip, sizeof(ifconf->addrs[j].ip), + "%s", info->IpAddressList.IpAddress.String); + ifconf->addrs[j].addr = inet_addr(ifconf->addrs[j].ip); + j++; + if (j == ifconf->length) { + ifconf->length *= 2; + ifconf->addrs = (ACL_IFADDR*) acl_myrealloc(ifconf->addrs, + ifconf->length * sizeof(ACL_IFADDR)); + } + } + + acl_myfree(infos); + + if (j == 0) { + acl_myfree(ifconf->addrs); + acl_myfree(ifconf); + return (NULL); + } + + ifconf->length = j; /* reset the ifconf->length */ + + /* set the iterator callback */ + ifconf->iter_head = ifaddrs_iter_head; + ifconf->iter_next = ifaddrs_iter_next; + ifconf->iter_tail = ifaddrs_iter_tail; + ifconf->iter_prev = ifaddrs_iter_prev; + + return (ifconf); +} +#endif /* !MS_VC6 */ +#else +# error "unknow OS" +#endif + +void acl_free_ifaddrs(ACL_IFCONF *ifconf) +{ + int i; + + if (ifconf == NULL) + return; + for (i = 0; i < ifconf->length; i++) { +#ifdef ACL_MS_WINDOWS + if (ifconf->addrs[i].desc != NULL) + acl_myfree(ifconf->addrs[i].desc); +#endif + if (ifconf->addrs[i].name != NULL) + acl_myfree(ifconf->addrs[i].name); + } + + acl_myfree(ifconf->addrs); + acl_myfree(ifconf); +} diff --git a/lib_acl/src/net/acl_mask_addr.c b/lib_acl/src/net/acl_mask_addr.c new file mode 100644 index 000000000..591837c8d --- /dev/null +++ b/lib_acl/src/net/acl_mask_addr.c @@ -0,0 +1,40 @@ +/* System library. */ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include /* CHAR_BIT */ + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +/* Utility library. */ + +#include "stdlib/acl_msg.h" +#include "net/acl_mask_addr.h" + +#endif + +/* acl_mask_addr - mask off a variable-length address */ + +void acl_mask_addr(unsigned char *addr_bytes, + unsigned addr_byte_count, unsigned network_bits) +{ + unsigned char *p; + + if (network_bits > addr_byte_count * CHAR_BIT) + acl_msg_panic("mask_addr: address byte count %d" + " too small for bit count %d", + addr_byte_count, network_bits); + + p = addr_bytes + network_bits / CHAR_BIT; + network_bits %= CHAR_BIT; + + if (network_bits != 0) + *p++ &= ~0 << (CHAR_BIT - network_bits); + + while (p < addr_bytes + addr_byte_count) + *p++ = 0; +} + diff --git a/lib_acl/src/net/acl_sane_inet.c b/lib_acl/src/net/acl_sane_inet.c new file mode 100644 index 000000000..1ec63fb62 --- /dev/null +++ b/lib_acl/src/net/acl_sane_inet.c @@ -0,0 +1,235 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#ifdef ACL_UNIX +#include +#include +#include +#include +#include +#include +#include +#endif + +#include "stdlib/acl_sys_patch.h" +#include "stdlib/acl_msg.h" +#include "net/acl_sane_inet.h" + +#endif + +const char *acl_inet_ntop4(const unsigned char *src, char *dst, size_t size) +{ + const size_t MIN_SIZE = 16; /* space for 255.255.255.255\0 */ + int n = 0; + char *next = dst; + + if (size < MIN_SIZE) + return NULL; + + do { + unsigned char u = *src++; + if (u > 99) { + *next++ = '0' + u/100; + u %= 100; + *next++ = '0' + u/10; + u %= 10; + } + else if (u > 9) { + *next++ = '0' + u/10; + u %= 10; + } + *next++ = '0' + u; + *next++ = '.'; + n++; + } while (n < 4); + *--next = 0; + return (dst); +} + +const char *acl_inet_ntoa(struct in_addr in, char *dst, size_t size) +{ + unsigned char *src = (unsigned char *) &in.s_addr; + + return (acl_inet_ntop4(src, dst, size)); +} + +int acl_is_ip(const char *pstrip) +{ + const char *ptr; + int count = 0, n = 0; + char ch; + + if (pstrip == NULL || *pstrip == 0) + return(-1); + + ptr = pstrip; + if(*ptr == '.') { /* the first char should not be '.' */ + return(-1); + } + while(*ptr) { + if (*ptr == '.') { + ch = *(ptr + 1); + if (ch < '0' || ch > '9') { + return(-1); + } + count++; + } else { + ch = *ptr; + if (ch < '0' || ch > '9') { + return(-1); + } + } + ptr++; + n++; + if (n > 16) + return (-1); + } + if(*(ptr - 1) == '.') { /* the last char should not be '.' */ + return(-1); + } + if(count != 3) { /* 192.168.0.1 has the number '.' is 4 */ + return(-1); + } + return(0); +} + +int acl_ipv4_valid(const char *addr) +{ + const char *ptr = addr; + int n, k; + + if (addr == NULL || *addr == 0) + return (0); + k = 3; + while (*ptr && *ptr != '.') { + n = *ptr; + if (n < '0' || n > '9') + return (0); + ptr++; + k--; + if (k < 0) + return (0); + } + if (*ptr == 0) + return (0); + + k = 3; + ptr++; + while (*ptr && *ptr != '.') { + n = *ptr; + if (n < '0' || n > '9') + return (0); + ptr++; + k--; + if (k < 0) + return (0); + } + if (*ptr == 0) + return (0); + + k = 3; + ptr++; + while (*ptr && *ptr != '.') { + n = *ptr; + if (n < '0' || n > '9') + return (0); + ptr++; + k--; + if (k < 0) + return (0); + } + if (*ptr == 0) + return (0); + + k = 3; + ptr++; + while (*ptr) { + n = *ptr; + if (n < '0' || n > '9') + return (0); + ptr++; + k--; + if (k < 0) + return (0); + } + return (1); +} + +int acl_ipv4_addr_valid(const char *addr) +{ + const char *ptr = addr; + int n, k; + + if (addr == NULL || *addr == 0) + return (0); + k = 3; + while (*ptr && *ptr != '.') { + n = *ptr; + if (n < '0' || n > '9') + return (0); + ptr++; + k--; + if (k < 0) + return (0); + } + if (*ptr == 0) + return (0); + + k = 3; + ptr++; + while (*ptr && *ptr != '.') { + n = *ptr; + if (n < '0' || n > '9') + return (0); + ptr++; + k--; + if (k < 0) + return (0); + } + if (*ptr == 0) + return (0); + + k = 3; + ptr++; + while (*ptr && *ptr != '.') { + n = *ptr; + if (n < '0' || n > '9') + return (0); + ptr++; + k--; + if (k < 0) + return (0); + } + if (*ptr == 0) + return (0); + + k = 3; + ptr++; + while (*ptr && *ptr != ':') { + n = *ptr; + if (n < '0' || n > '9') + return (0); + ptr++; + k--; + if (k < 0) + return (0); + } + if (*ptr == 0) + return (0); + + ptr++; + n = atoi(ptr); + if (n < 0 || n > 65535) + return (0); + return (1); +} + diff --git a/lib_acl/src/net/acl_sane_socket.c b/lib_acl/src/net/acl_sane_socket.c new file mode 100644 index 000000000..1928dc50b --- /dev/null +++ b/lib_acl/src/net/acl_sane_socket.c @@ -0,0 +1,124 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef HP_UX +#define _XOPEN_SOURCE +#define _XOPEN_SOURCE_EXTENDED 1 +#endif + +#include +#include +#ifdef ACL_UNIX +#include +#include +#include +#endif + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "net/acl_sane_inet.h" +#include "net/acl_sane_socket.h" + +#endif + +#ifdef WIN32 +struct SOCK_ADDR { + union { + struct sockaddr_in in; + } sa; +}; +#else +struct SOCK_ADDR { + union { + struct sockaddr_in in; + struct sockaddr_un un; + struct sockaddr sa; + } sa; +}; +#endif + +int acl_getpeername(ACL_SOCKET sockfd, char *buf, size_t size) +{ + struct SOCK_ADDR addr; + struct sockaddr *sa = (struct sockaddr*) &addr; + socklen_t len = sizeof(addr); + char ip[32]; + int port; + + if (sockfd == ACL_SOCKET_INVALID || buf == NULL || size <= 0) + return -1; + + memset(&addr, 0, sizeof(addr)); + if (getpeername(sockfd, sa, &len) == -1) + return -1; + +#ifndef WIN32 + if (sa->sa_family == AF_UNIX) { + snprintf(buf, size, "%s", addr.sa.un.sun_path); + return 0; + } else +#endif + if (sa->sa_family != AF_INET) + return -1; + if (acl_inet_ntoa(addr.sa.in.sin_addr, ip, sizeof(ip)) == NULL) + return -1; + port = ntohs(addr.sa.in.sin_port); + snprintf(buf, size, "%s:%d", ip, port); + return 0; +} + +int acl_getsockname(ACL_SOCKET sockfd, char *buf, size_t size) +{ + struct SOCK_ADDR addr; + struct sockaddr *sa = (struct sockaddr*) &addr; + socklen_t len = sizeof(addr); + char ip[32]; + int port; + + if (sockfd == ACL_SOCKET_INVALID || buf == NULL || size <= 0) + return -1; + + memset(&addr, 0, sizeof(addr)); + + if (getsockname(sockfd, sa, &len) == -1) + return -1; + +#ifndef WIN32 + if (sa->sa_family == AF_UNIX) { + snprintf(buf, size, "%s", addr.sa.un.sun_path); + return 0; + } else +#endif + if (sa->sa_family != AF_INET) + return -1; + if (acl_inet_ntoa(addr.sa.in.sin_addr, ip, sizeof(ip)) == NULL) + return -1; + port = ntohs(addr.sa.in.sin_port); + snprintf(buf, size, "%s:%d", ip, port); + return 0; +} + +int acl_getsocktype(ACL_SOCKET sockfd) +{ + struct SOCK_ADDR addr; + struct sockaddr *sa = (struct sockaddr*) &addr; + socklen_t len = sizeof(addr); + + if (sockfd == ACL_SOCKET_INVALID) + return -1; + + if (getsockname(sockfd, sa, &len) == -1) + return -1; + +#ifndef WIN32 + if (sa->sa_family == AF_UNIX) + return AF_UNIX; +#endif + if (sa->sa_family == AF_INET) + return AF_INET; + return -1; +} diff --git a/lib_acl/src/net/acl_tcp_ctl.c b/lib_acl/src/net/acl_tcp_ctl.c new file mode 100644 index 000000000..8c2f0dba5 --- /dev/null +++ b/lib_acl/src/net/acl_tcp_ctl.c @@ -0,0 +1,125 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef ACL_UNIX +#include +#include +# ifdef ACL_FREEBSD +# include +# include +# endif +#include +#include +#include +#include +#endif + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_msg.h" +#include "net/acl_tcp_ctl.h" + +#endif + +void acl_tcp_set_rcvbuf(ACL_SOCKET fd, int size) +{ + const char *myname = "acl_tcp_set_rcvbuf"; + char ebuf[256]; + + if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *) &size, sizeof(size)) < 0) + acl_msg_error("%s(%d): size(%d), setsockopt error(%s)", + myname, __LINE__, size, acl_last_strerror(ebuf, sizeof(ebuf))); +} + +void acl_tcp_set_sndbuf(ACL_SOCKET fd, int size) +{ + const char *myname = "acl_tcp_sndbuf"; + char ebuf[256]; + + if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (char *) &size, sizeof(size)) < 0) + acl_msg_error("%s: FD %d, SIZE %d: %s\n", + myname, fd, size, acl_last_strerror(ebuf, sizeof(ebuf))); +} + +int acl_tcp_get_rcvbuf(ACL_SOCKET fd) +{ + const char *myname = "acl_tcp_get_rcvbuf"; + char ebuf[256]; + int size; + socklen_t len; + + len = (socklen_t) sizeof(size); + if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *) &size, &len) < 0) { + acl_msg_error("%s(%d): size(%d), setsockopt error(%s)", + myname, __LINE__, size, acl_last_strerror(ebuf, sizeof(ebuf))); + return (-1); + } + + return (size); +} + +int acl_tcp_get_sndbuf(ACL_SOCKET fd) +{ + const char *myname = "acl_tcp_get_sndbuf"; + char ebuf[256]; + int size; + socklen_t len; + + len = (socklen_t) sizeof(size); + if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, (char *) &size, &len) < 0) { + acl_msg_error("%s(%d): size(%d), setsockopt error(%s)", + myname, __LINE__, size, acl_last_strerror(ebuf, sizeof(ebuf))); + return (-1); + } + + return (size); +} + +void acl_tcp_set_nodelay(ACL_SOCKET fd) +{ + acl_tcp_nodelay(fd, 1); +} + +void acl_tcp_nodelay(ACL_SOCKET fd, int onoff) +{ + const char *myname = "acl_tcp_nodelay"; + int on = onoff ? 1 : 0; + + if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &on, sizeof(on)) < 0) { + char ebuf[256]; + acl_msg_error("%s(%d): set nodelay error(%s), onoff(%d)", + myname, __LINE__, acl_last_strerror(ebuf, sizeof(ebuf)), onoff); + } +} + +void acl_tcp_defer_accept(ACL_SOCKET fd acl_unused, int timeout acl_unused) +{ +#ifdef TCP_DEFER_ACCEPT + const char *myname = "acl_tcp_defer_accept"; + char ebuf[256]; + + if (timeout < 0) + timeout = 0; + if (setsockopt(fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &timeout, sizeof(timeout)) < 0) + acl_msg_error("%s: setsockopt(TCP_DEFER_ACCEPT): %s", + myname, acl_last_strerror(ebuf, sizeof(ebuf))); +#endif +} + +void acl_tcp_so_linger(ACL_SOCKET fd, int onoff, int timeout) +{ + const char *myname = "acl_tcp_so_linger"; + struct linger l; + + l.l_onoff = onoff ? 1 : 0; + l.l_linger = timeout >= 0 ? timeout : 0; + if (setsockopt(fd, SOL_SOCKET, SO_LINGER, (char *) &l, sizeof(l)) < 0) { + char ebuf[256]; + acl_msg_error("%s(%d): setsockopt(SO_LINGER) error(%s), onoff(%d), timeout(%d)", + myname, __LINE__, acl_last_strerror(ebuf, sizeof(ebuf)), onoff, timeout); + } +} diff --git a/lib_acl/src/net/acl_valid_hostname.c b/lib_acl/src/net/acl_valid_hostname.c new file mode 100644 index 000000000..32e2a2426 --- /dev/null +++ b/lib_acl/src/net/acl_valid_hostname.c @@ -0,0 +1,298 @@ +/* System library. */ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +/* Utility library. */ + +#include "stdlib/acl_msg.h" +#include "net/acl_valid_hostname.h" + +#endif + +/* acl_valid_hostname - screen out bad hostnames */ + +int acl_valid_hostname(const char *name, int gripe) +{ + char *myname = "acl_valid_hostname"; + const char *cp; + int label_length = 0; + int label_count = 0; + int non_numeric = 0; + int ch; + + /* + * Trivial cases first. + */ + if (*name == 0) { + if (gripe) + acl_msg_warn("%s: empty hostname", myname); + return (0); + } + + /* + * Find bad characters or label lengths. Find adjacent delimiters. + */ + for (cp = name; (ch = *(const unsigned char *) cp) != 0; cp++) { + if (ACL_ISALNUM(ch) || ch == '_') { /* grr.. */ + if (label_length == 0) + label_count++; + label_length++; + if (label_length > ACL_VALID_LABEL_LEN) { + if (gripe) + acl_msg_warn("%s: hostname label" + " too long: %.100s", + myname, name); + return (0); + } + if (!ACL_ISDIGIT(ch)) + non_numeric = 1; + } else if (ch == '.') { + if (label_length == 0 || cp[1] == 0) { + if (gripe) + acl_msg_warn("%s: misplaced delimiter:" + " %.100s", myname, name); + return (0); + } + label_length = 0; + } else if (ch == '-') { + label_length++; + if (label_length == 1 || cp[1] == 0 || cp[1] == '.') { + if (gripe) + acl_msg_warn("%s: misplaced hyphen:" + " %.100s", myname, name); + return (0); + } + } +#ifdef SLOPPY_VALID_HOSTNAME + else if (ch == ':' && acl_valid_ipv6_hostaddr(name, ACL_DONT_GRIPE)) { + non_numeric = 0; + break; + } +#endif + else { + if (gripe) + acl_msg_warn("%s: invalid character %d(decimal): %.100s", + myname, ch, name); + return (0); + } + } + + if (non_numeric == 0) { + if (gripe) + acl_msg_warn("%s: numeric hostname: %.100s", myname, name); +#ifndef SLOPPY_VALID_HOSTNAME + return (0); +#endif + } + if (cp - name > ACL_VALID_HOSTNAME_LEN) { + if (gripe) + acl_msg_warn("%s: bad length %d for %.100s...", + myname, (int) (cp - name), name); + return (0); + } + return (1); +} + +/* acl_valid_hostaddr - verify numerical address syntax */ + +int acl_valid_hostaddr(const char *addr, int gripe) +{ + const char *myname = "acl_valid_hostaddr"; + + /* + * Trivial cases first. + */ + if (*addr == 0) { + if (gripe) + acl_msg_warn("%s: empty address", myname); + return (0); + } + + /* + * Protocol-dependent processing next. + */ + if (strchr(addr, ':') != 0) + return (acl_valid_ipv6_hostaddr(addr, gripe)); + else + return (acl_valid_ipv4_hostaddr(addr, gripe)); +} + +/* acl_valid_ipv4_hostaddr - test dotted quad string for correctness */ + +int acl_valid_ipv4_hostaddr(const char *addr, int gripe) +{ + const char *cp; + char *myname = "acl_valid_ipv4_hostaddr"; + int in_byte = 0; + int byte_count = 0; + int byte_val = 0; + int ch; + +#define BYTES_NEEDED 4 + + /* + * Scary code to avoid sscanf() overflow nasties. + * + * This routine is called by valid_ipv6_hostaddr(). It must not call that + * routine, to avoid deadly recursion. + */ + for (cp = addr; (ch = *(unsigned const char *) cp) != 0; cp++) { + if (ACL_ISDIGIT(ch)) { + if (in_byte == 0) { + in_byte = 1; + byte_val = 0; + byte_count++; + } + byte_val *= 10; + byte_val += ch - '0'; + if (byte_val > 255) { + if (gripe) + acl_msg_warn("%s: invalid octet value:" + " %.100s", myname, addr); + return (0); + } + } else if (ch == '.') { + if (in_byte == 0 || cp[1] == 0) { + if (gripe) + acl_msg_warn("%s: misplaced dot:" + " %.100s", myname, addr); + return (0); + } + /* XXX Allow 0.0.0.0 but not 0.1.2.3 */ + if (byte_count == 1 && byte_val == 0 + && addr[strspn(addr, "0.")]) { + if (gripe) + acl_msg_warn("%s: bad initial octet" + " value: %.100s", myname, addr); + return (0); + } + in_byte = 0; + } else { + if (gripe) + acl_msg_warn("%s: invalid character %d(decimal): %.100s", + myname, ch, addr); + return (0); + } + } + + if (byte_count != BYTES_NEEDED) { + if (gripe) + acl_msg_warn("%s: invalid octet count: %.100s", + myname, addr); + return (0); + } + return (1); +} + +/* acl_valid_ipv6_hostaddr - validate IPv6 address syntax */ + +int acl_valid_ipv6_hostaddr(const char *addr, int gripe) +{ + const char *myname = "acl_valid_ipv6_hostaddr"; + int null_field = 0; + int field = 0; + const unsigned char *cp = (const unsigned char *) addr; + int len = 0; + + /* + * FIX 200501 The IPv6 patch validated syntax with getaddrinfo(), but I + * am not confident that everyone's system library routines are robust + * enough, like buffer overflow free. Remember, the valid_hostmumble() + * routines are meant to protect Postfix against malformed information + * in data received from the network. + * + * We require eight-field hex addresses of the form 0:1:2:3:4:5:6:7, + * 0:1:2:3:4:5:6a.6b.7c.7d, or some :: compressed version of the same. + * + * Note: the character position is advanced inside the loop. I have added + * comments to show why we can't get stuck. + */ + for (;;) { + switch (*cp) { + case 0: + /* Terminate the loop. */ + if (field < 2) { + if (gripe) + acl_msg_warn("%s: too few `:' in IPv6" + " address: %.100s", + myname, addr); + return (0); + } else if (len == 0 && null_field != field - 1) { + if (gripe) + acl_msg_warn("%s: bad null last field" + " in IPv6 address: %.100s", + myname, addr); + return (0); + } else + return (1); + case '.': + /* Terminate the loop. */ + if (field < 2 || field > 6) { + if (gripe) + acl_msg_warn("%s: malformed IPv4-in-IPv6" + " address: %.100s", + myname, addr); + return (0); + } + /* NOT: acl_valid_hostaddr(). Avoid recursion. */ + return (acl_valid_ipv4_hostaddr((const char *) cp - len, gripe)); + case ':': + /* advance by exactly 1 character position or terminate. */ + if (field == 0 && len == 0 && ACL_ISALNUM(cp[1])) { + if (gripe) + acl_msg_warn("%s: bad null first field" + " in IPv6 address: %.100s", + myname, addr); + return (0); + } + field++; + if (field > 7) { + if (gripe) + acl_msg_warn("%s: too many `:' in" + " IPv6 address: %.100s", + myname, addr); + return (0); + } + cp++; + len = 0; + if (*cp == ':') { + if (null_field > 0) { + if (gripe) + acl_msg_warn("%s: too many `::'" + " in IPv6 address: %.100s", + myname, addr); + return (0); + } + null_field = field; + } + break; + default: + /* Advance by at least 1 character position or terminate. */ + len = strspn((const char *) cp, "0123456789abcdefABCDEF"); + if (len /* - strspn((char *) cp, "0") */ > 4) { + if (gripe) + acl_msg_warn("%s: malformed IPv6 address: %.100s", + myname, addr); + return (0); + } + if (len <= 0) { + if (gripe) + acl_msg_warn("%s: invalid character" + " %d(decimal) in IPv6 address: %.100s", + myname, *cp, addr); + return (0); + } + cp += len; + break; + } + } +} + diff --git a/lib_acl/src/net/acl_vstream_net.c b/lib_acl/src/net/acl_vstream_net.c new file mode 100644 index 000000000..2a1728606 --- /dev/null +++ b/lib_acl/src/net/acl_vstream_net.c @@ -0,0 +1,254 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef HP_UX +#define _XOPEN_SOURCE +#define _XOPEN_SOURCE_EXTENDED 1 +#endif + +#include +#include +#include +#include +#ifdef ACL_MS_WINDOWS +#include +#include +#endif + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_stdlib.h" +#include "net/acl_sane_inet.h" +#include "net/acl_sane_socket.h" +#include "net/acl_connect.h" +#include "net/acl_listen.h" +#include "net/acl_vstream_net.h" + +#endif + +ACL_VSTREAM *acl_vstream_listen_ex(const char *addr, int qlen, + int block_mode, int io_bufsize, int io_timeout) +{ + const char *myname = "acl_vstream_listen_ex"; + ACL_SOCKET listenfd; + struct sockaddr_in local; + ACL_VSTREAM *listen_stream; + int len; + + if (addr == 0 || *addr == 0 || qlen <= 0) + { + acl_msg_error("%s: input invalid", myname); + return NULL; + } + +#ifdef ACL_UNIX + /* this maybe unix addr, such as '/home/test/listen.sock' */ + if (strchr(addr, '/') != NULL) { + listenfd = acl_unix_listen(addr, qlen, 0); + if (listenfd == ACL_SOCKET_INVALID) + return NULL; + acl_non_blocking(listenfd, block_mode); + listen_stream = acl_vstream_fdopen(listenfd, + ACL_VSTREAM_FLAG_RW, io_bufsize, + io_timeout, ACL_VSTREAM_TYPE_LISTEN_UNIX); + if (listen_stream == NULL) { + acl_socket_close(listenfd); + acl_msg_error("%s: open vstream error, addr(%s)", + myname, addr); + return NULL; + } + snprintf(listen_stream->local_addr, + sizeof(listen_stream->local_addr), "%s", addr); + sprintf(listen_stream->errbuf, "+OK"); + return (listen_stream); + } +#endif + /* addr such as '192.168.0.1:80' */ + listenfd = acl_inet_listen(addr, qlen, block_mode); + if (listenfd == ACL_SOCKET_INVALID) { + acl_msg_error("%s: listen addr(%s) error(%s)", + myname, addr, acl_last_serror()); + return NULL; + } + listen_stream = acl_vstream_fdopen(listenfd, + ACL_VSTREAM_FLAG_RW, io_bufsize, + io_timeout, ACL_VSTREAM_TYPE_LISTEN_INET); + if (listen_stream == NULL) { + acl_socket_close(listenfd); + acl_msg_error("%s: open vstream error addr(%s)", myname, addr); + return NULL; + } + + memset(&local, 0, sizeof(local)); + len = (int) sizeof(struct sockaddr); + if (getsockname(listenfd, (struct sockaddr*) &local, + (socklen_t *) &len) < 0) + { + acl_msg_warn("%s: getsockname error(%s) for sock(%d)", + myname, acl_last_serror(), listenfd); + snprintf(listen_stream->local_addr, + sizeof(listen_stream->local_addr), "%s", addr); + } else { + char ip[32]; + int port; + + acl_inet_ntoa(local.sin_addr, ip, sizeof(ip)); + port = ntohs(local.sin_port); + snprintf(listen_stream->local_addr, + sizeof(listen_stream->local_addr), "%s:%d", ip, port); + } + + sprintf(listen_stream->errbuf, "+OK"); + return listen_stream; +} + +ACL_VSTREAM *acl_vstream_listen(const char *addr, int qlen) +{ + return acl_vstream_listen_ex(addr, qlen, ACL_BLOCKING, 0, 0); +} + +ACL_VSTREAM *acl_vstream_accept_ex(ACL_VSTREAM *listen_stream, + ACL_VSTREAM *client_stream, char *ipbuf, int bsize) +{ + const char *myname = "acl_vstream_accept_ex"; + ACL_SOCKET connfd = ACL_SOCKET_INVALID; + ACL_SOCKET servfd = ACL_VSTREAM_SOCK(listen_stream); + char buf[256]; + + if ((listen_stream->type | ACL_VSTREAM_TYPE_LISTEN_INET)) { +#ifdef ACL_MS_WINDOWS + if (!(listen_stream->type & ACL_VSTREAM_TYPE_LISTEN_IOCP)) + connfd = acl_inet_accept_ex(servfd, buf, sizeof(buf)); + else if (listen_stream->iocp_sock == ACL_SOCKET_INVALID) + return NULL; + else { + int ret; + + connfd = listen_stream->iocp_sock; + listen_stream->iocp_sock = ACL_SOCKET_INVALID; + + /* iocp 方式下,需调用下面过程以允许调用 getpeername/getsockname */ + ret = setsockopt(connfd, SOL_SOCKET, + SO_UPDATE_ACCEPT_CONTEXT, + (char *)&servfd, sizeof(servfd)); + buf[0] = 0; + if (ret != SOCKET_ERROR) + acl_getpeername(connfd, buf, sizeof(buf)); + } +#else + connfd = acl_inet_accept_ex(servfd, buf, sizeof(buf)); +#endif + + if (connfd != ACL_SOCKET_INVALID && ipbuf != NULL && bsize > 0) + ACL_SAFE_STRNCPY(ipbuf, buf, bsize); +#ifdef ACL_UNIX + } else if ((listen_stream->type | ACL_VSTREAM_TYPE_LISTEN_UNIX)) { + connfd = acl_unix_accept(servfd); + listen_stream->remote_addr[0] = 0; + if (ipbuf) + ipbuf[0] = 0; + buf[0] = 0; +#endif + } else + acl_msg_fatal("%s(%d)->%s: invalid listen stream(%d)", + __FILE__, __LINE__, myname, listen_stream->flag); + + if (connfd == ACL_SOCKET_INVALID) + return NULL; + + if (client_stream != NULL) { + acl_vstream_reset(client_stream); + ACL_VSTREAM_SET_SOCK(client_stream, connfd); + } else { + client_stream = acl_vstream_fdopen(connfd, + ACL_VSTREAM_FLAG_RW, + (int) listen_stream->read_buf_len, + listen_stream->rw_timeout, + ACL_VSTREAM_TYPE_SOCK); + /* 让 client_stream 的 context 成员继承 listen_stream 的 + * context 成员变量. + */ + client_stream->context = listen_stream->context; + } + if (client_stream == NULL) + return NULL; + + ACL_SAFE_STRNCPY(client_stream->remote_addr, buf, + sizeof(client_stream->remote_addr)); + + return client_stream; +} + +ACL_VSTREAM *acl_vstream_accept(ACL_VSTREAM *listen_stream, + char *ipbuf, int bsize) +{ + return acl_vstream_accept_ex(listen_stream, NULL, ipbuf, bsize); +} + +ACL_VSTREAM *acl_vstream_connect_ex(const char *addr, + int block_mode, int connect_timeout, int rw_timeout, + int rw_bufsize, int *he_errorp) +{ + const char *myname = "acl_vstream_connect_ex"; + ACL_VSTREAM *connect_stream; + ACL_SOCKET connfd; + char *ptr; + + if (addr == NULL || *addr == 0) + acl_msg_fatal("%s: addr null", myname); + + ptr = strchr(addr, ':'); + if (ptr != NULL) { + connfd = acl_inet_connect_ex(addr, block_mode, + connect_timeout, he_errorp); + } +#ifdef ACL_MS_WINDOWS + else { + acl_msg_error("%s(%d): addr(%s) invalid, examples(192.168.0.1:80)", + myname, __LINE__, addr); + return NULL; + } +#elif defined(ACL_UNIX) + else { + connfd = acl_unix_connect(addr, block_mode, connect_timeout); + } +#else + else { + connfd = ACL_SOCKET_INVALID; + } +#endif + + if (connfd == ACL_SOCKET_INVALID) + return NULL; + connect_stream = acl_vstream_fdopen(connfd, ACL_VSTREAM_FLAG_RW, + rw_bufsize, rw_timeout, ACL_VSTREAM_TYPE_SOCK); + if (connect_stream == NULL) { + acl_socket_close(connfd); + return NULL; + } + + if (acl_getpeername(ACL_VSTREAM_SOCK(connect_stream), + connect_stream->remote_addr, + sizeof(connect_stream->remote_addr) - 1) < 0) + { + snprintf(connect_stream->remote_addr, + sizeof(connect_stream->remote_addr) - 1, + "%s", addr); + } + + return connect_stream; +} + +ACL_VSTREAM *acl_vstream_connect(const char *addr, + int block_mode, int connect_timeout, + int rw_timeout,int rw_bufsize) +{ + return acl_vstream_connect_ex(addr, block_mode, connect_timeout, + rw_timeout, rw_bufsize, NULL); +} + + diff --git a/lib_acl/src/net/connect/acl_inet_connect.c b/lib_acl/src/net/connect/acl_inet_connect.c new file mode 100644 index 000000000..79b33a4a0 --- /dev/null +++ b/lib_acl/src/net/connect/acl_inet_connect.c @@ -0,0 +1,214 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE +#include "stdlib/acl_define.h" + +#include +#include +#include +#include +#ifdef ACL_UNIX +#include +#include +#include +#include +#endif + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +/* Utility library. */ + +#ifdef ACL_MS_VC +#include "stdlib/acl_mystring.h" +#endif + +#include "stdlib/acl_sys_patch.h" +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_msg.h" +#include "stdlib/acl_iostuff.h" +#include "net/acl_tcp_ctl.h" +#include "net/acl_netdb.h" +#include "net/acl_connect.h" + +#endif + +static ACL_SOCKET inet_connect_one(const char *ip, int port, const char *local_ip, int b_mode, int timeout); + +/* acl_inet_connect - connect to TCP listener */ + +ACL_SOCKET acl_inet_connect(const char *addr, int block_mode, int timeout) +{ + int h_error = 0; + + return (acl_inet_connect_ex(addr, block_mode, timeout, &h_error)); +} + +ACL_SOCKET acl_inet_connect_ex(const char *addr, int b_mode, int timeout, int *h_error) +{ + char myname[] = "acl_inet_connect_ex"; + ACL_SOCKET sock = ACL_SOCKET_INVALID; + char buf[256], *ptr; + const char *pip, *remote_addr, *local_ip; + int port, i, n; + ACL_DNS_DB *h_dns_db; + + if (h_error) + *h_error = 0; + + snprintf(buf, sizeof(buf) - 1, "%s", addr); + ptr = strchr(buf, ':'); + if (ptr == NULL) { + acl_msg_error("%s, %s(%d): invalid addr(%s)", + __FILE__, myname, __LINE__, addr); + return (ACL_SOCKET_INVALID); + } + + *ptr++ = 0; + port = atoi(ptr); + if (port <= 0) { + acl_msg_error("%s, %s(%d): invalid port(%d)", + __FILE__, myname, __LINE__, port); + return (ACL_SOCKET_INVALID); + } + + ptr = strchr(buf, '@'); + if (ptr != NULL) { + *ptr++ = 0; + local_ip = buf; + remote_addr = ptr; + } else { + local_ip = NULL; + remote_addr = buf; + } + + if (strlen(remote_addr) == 0) { + acl_msg_error("%s, %s(%d): ip buf's length is 0", + __FILE__, myname, __LINE__); + return (ACL_SOCKET_INVALID); + } + + h_dns_db = acl_gethostbyname(remote_addr, h_error); + if (h_dns_db == NULL) { + n = h_error ? *h_error : -1; + + acl_msg_error("%s, %s(%d): gethostbyname error(%s), addr=%s", + __FILE__, myname, __LINE__, + acl_netdb_strerror(n), remote_addr); + return (ACL_SOCKET_INVALID); + } + + sock = ACL_SOCKET_INVALID; + n = acl_netdb_size(h_dns_db); + + for (i = 0; i < n; i++) { + pip = acl_netdb_index_ip(h_dns_db, i); + if (pip == NULL) + break; + + sock = inet_connect_one(pip, port, local_ip, b_mode, timeout); + if (sock != ACL_SOCKET_INVALID) + break; + acl_msg_error("%s(%d): connect ip(%s) port(%d) error", + myname, __LINE__, pip, port); + } + + acl_netdb_free(h_dns_db); + + return (sock); +} + +/* inet_connect_one - try to connect to one address */ + +static ACL_SOCKET inet_connect_one(const char *ip, int port, const char *local_ip, int b_mode, int timeout) +{ + const char *myname = "inet_connect_one"; + ACL_SOCKET sock; + struct sockaddr_in saddr; + + /* + * Create a client socket. + */ + /* sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); */ + sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock == ACL_SOCKET_INVALID) { + acl_msg_error("%s(%d): create socket error(%s)", myname, __LINE__, acl_last_serror()); + return (ACL_SOCKET_INVALID); + } + + acl_tcp_set_rcvbuf(sock, ACL_SOCKET_RBUF_SIZE); + acl_tcp_set_sndbuf(sock, ACL_SOCKET_WBUF_SIZE); + + if (local_ip != NULL && *local_ip != 0) { + memset(&saddr, 0, sizeof(saddr)); + saddr.sin_family = AF_INET; + saddr.sin_addr.s_addr = inet_addr(local_ip); + if (bind(sock, (struct sockaddr *) &saddr, sizeof(struct sockaddr)) < 0) { + acl_socket_close(sock); + acl_msg_error("%s(%d): bind local ip(%s) error(%s)", + myname, __LINE__, local_ip, acl_last_serror()); + return (ACL_SOCKET_INVALID); + } + } + + memset(&saddr, 0, sizeof(saddr)); + saddr.sin_family = AF_INET; + saddr.sin_port = htons((short) port); + saddr.sin_addr.s_addr = inet_addr(ip); + + /* + * Timed connect. + */ + if (timeout > 0) { + acl_non_blocking(sock, ACL_NON_BLOCKING); + if (acl_timed_connect(sock, (const struct sockaddr *) &saddr, + sizeof(struct sockaddr), timeout) < 0) { + acl_socket_close(sock); + return (ACL_SOCKET_INVALID); + } + if (b_mode != ACL_NON_BLOCKING) + acl_non_blocking(sock, b_mode); + return (sock); + } + + /* + * Maybe block until connected. + */ + acl_non_blocking(sock, b_mode); + if (acl_sane_connect(sock, (const struct sockaddr *) &saddr, sizeof(saddr)) < 0) { + int ret, err, errno_saved; + socklen_t len; + + errno_saved = acl_last_error(); + len = sizeof(err); + ret = getsockopt(sock, SOL_SOCKET, SO_ERROR, (char *) &err, &len); + if (ret < 0) { +#ifdef SUNOS5 + /* + * Solaris 2.4's socket emulation doesn't allow you + * to determine the error from a failed non-blocking + * connect and just returns EPIPE. Create a fake + * error message for connect. -- fenner@parc.xerox.com + */ + if (errno == EPIPE) + acl_set_error(ACL_ENOTCONN); +#endif + acl_socket_close(sock); + return (ACL_SOCKET_INVALID); + } else if (err != 0) { + errno_saved = err; + acl_set_error(err); + } + +#ifdef ACL_MS_WINDOWS + if (errno_saved == ACL_EINPROGRESS || errno_saved == ACL_EWOULDBLOCK) + return (sock); +#elif defined(ACL_UNIX) + if (errno_saved == ACL_EINPROGRESS || errno_saved == EISCONN) + return (sock); +#endif + acl_socket_close(sock); + return (ACL_SOCKET_INVALID); + } + return (sock); +} diff --git a/lib_acl/src/net/connect/acl_sane_connect.c b/lib_acl/src/net/connect/acl_sane_connect.c new file mode 100644 index 000000000..ac0bdee07 --- /dev/null +++ b/lib_acl/src/net/connect/acl_sane_connect.c @@ -0,0 +1,58 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef ACL_UNIX +#include +#include +#include +#endif + +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_msg.h" +#include "net/acl_tcp_ctl.h" +#include "net/acl_connect.h" + +#endif + +/* acl_sane_connect - sanitize connect() results */ + +int acl_sane_connect(ACL_SOCKET sock, const struct sockaddr * sa, socklen_t len) +{ + int on; + + /* + * XXX Solaris select() produces false read events, so that read() + * blocks forever on a blocking socket, and fails with EAGAIN on + * a non-blocking socket. Turning on keepalives will fix a blocking + * socket provided that the kernel's keepalive timer expires before + * the Postfix watchdog timer. + */ + + if (sa->sa_family == AF_INET) { + /* default set to nodelay --- zsx, 2008.9.4*/ + acl_tcp_nodelay(sock, 1); +#if defined(BROKEN_READ_SELECT_ON_TCP_SOCKET) && defined(SO_KEEPALIVE) + on = 1; + (void) setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, + (char *) &on, sizeof(on)); +#endif + } + + on = 1; + + if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on)) < 0) { + char ebuf[256]; + acl_msg_error("acl_sane_connect: setsockopt error(%s)", + acl_last_strerror(ebuf, sizeof(ebuf))); + } + + return (connect(sock, sa, len)); +} + diff --git a/lib_acl/src/net/connect/acl_stream_connect.c b/lib_acl/src/net/connect/acl_stream_connect.c new file mode 100644 index 000000000..a2b1ccc85 --- /dev/null +++ b/lib_acl/src/net/connect/acl_stream_connect.c @@ -0,0 +1,96 @@ +/* System library. */ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#endif + +#ifdef ACL_UNIX + +#include +#include +#include +#include +#include +/* +# ifndef ACL_FREEBSD +# include +# endif +*/ +#include +#include + +/* Utility library. */ + +#include "stdlib/acl_msg.h" +#include "stdlib/acl_iostuff.h" +#include "net/acl_connect.h" + +/* acl_stream_connect - connect to stream listener */ + +#ifdef SUNOS5 +int acl_stream_connect(const char *path, int block_mode, int unused_timeout) +{ + char *myname = "acl_stream_connect"; + +#ifdef ACL_FREEBSD + path = path; + block_mode = block_mode; + unused_timeout = unused_timeout; + + acl_msg_fatal("%s(%d): not support!", myname, __LINE__); + return (-1); +#else + int pair[2]; + int fifo; + + unused_timeout = unused_timeout; + + /* + * The requested file system object must exist, otherwise we can't reach + * the server. + */ + if ((fifo = open(path, O_WRONLY | O_NONBLOCK, 0)) < 0) + return (-1); + + /* + * Create a pipe, and send one pipe end to the server. + */ + if (pipe(pair) < 0) { + char tbuf[256]; + acl_msg_fatal("%s: pipe: %s", + myname, acl_last_strerror(tbuf, sizeof(tbuf))); + } + if (ioctl(fifo, I_SENDFD, pair[1]) < 0) { + char tbuf[256]; + acl_msg_fatal("%s: send file descriptor: %s", + myname, acl_last_strerror(tbuf, sizeof(tbuf))); + } + close(pair[1]); + + /* + * This is for {unix,inet}_connect() compatibility. + */ + if (block_mode == ACL_NON_BLOCKING) + acl_non_blocking(pair[0], ACL_NON_BLOCKING); + + /* + * Cleanup. + */ + close(fifo); + + /* + * Keep the other end of the pipe. + */ + return (pair[0]); +#endif /* ACL_FREEBSD */ +} +#endif + +#endif /* ACL_UNIX */ + diff --git a/lib_acl/src/net/connect/acl_timed_connect.c b/lib_acl/src/net/connect/acl_timed_connect.c new file mode 100644 index 000000000..336eb1ed7 --- /dev/null +++ b/lib_acl/src/net/connect/acl_timed_connect.c @@ -0,0 +1,82 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#include +#include +#include +#ifdef ACL_UNIX +#include +#include +#endif + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_msg.h" +#include "stdlib/acl_iostuff.h" +#include "net/acl_connect.h" + +#endif + +int acl_timed_connect(ACL_SOCKET sock, const struct sockaddr * sa, socklen_t len, int timeout) +{ + int err; + + /* + * Sanity check. Just like with timed_wait(), the timeout must be a + * positive number. + */ + if (timeout < 0) + acl_msg_panic("timed_connect: bad timeout: %d", timeout); + + /* + * Start the connection, and handle all possible results. + */ + if (acl_sane_connect(sock, sa, len) == 0) + return (0); + + errno = acl_last_error(); + +#ifdef ACL_UNIX + if (errno != ACL_EINPROGRESS) + return (-1); +#elif defined(ACL_MS_WINDOWS) + if (errno != ACL_EINPROGRESS && errno != ACL_EWOULDBLOCK) + return (-1); +#endif + + /* + * A connection is in progress. Wait for a limited amount of time for + * something to happen. If nothing happens, report an error. + */ + if (acl_write_wait(sock, timeout) < 0) + return (-1); + + /* + * Something happened. Some Solaris 2 versions have getsockopt() itself + * return the error, instead of returning it via the parameter list. + */ + len = sizeof(err); + if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (char *) &err, &len) < 0) { +#ifdef SUNOS5 + /* + * Solaris 2.4's socket emulation doesn't allow you + * to determine the error from a failed non-blocking + * connect and just returns EPIPE. Create a fake + * error message for connect. -- fenner@parc.xerox.com + */ + if (errno == EPIPE) + acl_set_error(ACL_ENOTCONN); +#endif + return (-1); + } + + if (err != 0) { + acl_set_error(err); + return (-1); + } else + return (0); +} diff --git a/lib_acl/src/net/connect/acl_unix_connect.c b/lib_acl/src/net/connect/acl_unix_connect.c new file mode 100644 index 000000000..2b93e4fd8 --- /dev/null +++ b/lib_acl/src/net/connect/acl_unix_connect.c @@ -0,0 +1,86 @@ +/* System interfaces. */ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#endif + +#ifdef ACL_UNIX + +#include +#include +#include +#include +#include + +/* Utility library. */ + +#include "stdlib/acl_msg.h" +#include "stdlib/acl_iostuff.h" +#include "net/acl_connect.h" + +/* acl_unix_connect - connect to UNIX-domain listener */ + +ACL_SOCKET acl_unix_connect(const char *addr, int block_mode, int timeout) +{ +#undef sun + struct sockaddr_un sun; + int len = strlen(addr); + ACL_SOCKET sock; + + /* + * Translate address information to internal form. + */ + if (len >= (int) sizeof(sun.sun_path)) + acl_msg_fatal("unix-domain name too long: %s", addr); + memset((char *) &sun, 0, sizeof(sun)); + sun.sun_family = AF_UNIX; +#ifdef HAS_SUN_LEN + sun.sun_len = len + 1; +#endif + memcpy(sun.sun_path, addr, len + 1); + + /* + * Create a client socket. + */ + if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { + char tbuf[256]; + acl_msg_fatal("socket: %s", acl_last_strerror(tbuf, sizeof(tbuf))); + } + + /* + * Timed connect. + */ + if (timeout > 0) { + acl_non_blocking(sock, ACL_NON_BLOCKING); + if (acl_timed_connect(sock, (struct sockaddr *) & sun, + sizeof(sun), timeout) < 0) { + close(sock); + return (-1); + } + if (block_mode != ACL_NON_BLOCKING) + acl_non_blocking(sock, block_mode); + return (sock); + } + + /* + * Maybe block until connected. + */ + else { + acl_non_blocking(sock, block_mode); + if (acl_sane_connect(sock, (struct sockaddr *) & sun, sizeof(sun)) < 0 + && acl_last_error() != EINPROGRESS) { + + close(sock); + return (-1); + } + return (sock); + } +} +#endif + diff --git a/lib_acl/src/net/dns/acl_dns.c b/lib_acl/src/net/dns/acl_dns.c new file mode 100644 index 000000000..a05190c92 --- /dev/null +++ b/lib_acl/src/net/dns/acl_dns.c @@ -0,0 +1,764 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#ifdef ACL_UNIX +#include +#include +#include +#include +#endif + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_vstream.h" +#include "stdlib/acl_htable.h" +#include "stdlib/acl_array.h" +#include "net/acl_sane_inet.h" +#include "net/acl_mask_addr.h" +#include "net/acl_dns.h" + +#endif + +#include "rfc1035.h" + +typedef struct ACL_DOMAIN_GROUP { + char group[RFC1035_MAXHOSTNAMESZ]; + int group_len; + char domain[RFC1035_MAXHOSTNAMESZ]; + ACL_ARGV *excepts; +} ACL_DOMAIN_GROUP; + +struct ACL_DNS_REQ{ + char key[RFC1035_MAXHOSTNAMESZ + 16]; + void (*callback)(ACL_DNS_DB *, void *, int); + void *ctx; + unsigned short qid; + int nretry; + ACL_DNS *dns; +}; + +static void dns_stream_open(ACL_DNS *dns); + +/* ACL_VSTREAM: 从数据流读取数据的回调函数 */ + +static int dns_read(ACL_SOCKET fd, void *buf, size_t size, + int timeout acl_unused, void *arg) +{ + const char *myname = "dns_read"; + ACL_DNS *dns = (ACL_DNS*) arg; + int ret; + + dns->addr_from.addr_len = sizeof(dns->addr_from.addr); +#ifdef ACL_UNIX + ret = recvfrom(fd, buf, size, 0, (struct sockaddr*) &dns->addr_from.addr, + (socklen_t*) &dns->addr_from.addr_len); +#elif defined(ACL_MS_WINDOWS) + ret = recvfrom(fd, (char*) buf, (int) size, 0, + (struct sockaddr*) &dns->addr_from.addr, + &dns->addr_from.addr_len); +#else +#error "unknown OS" +#endif + if (ret < 0) + acl_msg_error("%s, %s(%d): recvfrom error(%s)", + __FILE__, myname, __LINE__, acl_last_serror()); + return (ret); +} + +/* ACL_VSTREAM: 向数据流写取数据的回调函数 */ + +static int dns_write(ACL_SOCKET fd, const void *buf, size_t size, + int timeout acl_unused, void *arg) +{ + const char *myname = "dns_write"; + ACL_DNS *dns = (ACL_DNS*) arg; + int ret; + unsigned short i; + ACL_DNS_ADDR *addr; + + if (dns->dns_list->count <= 0) + acl_msg_fatal("%s(%d): dns_list's size(%d) invalid", + myname, __LINE__, dns->dns_list->count); + + /* 根据当前ID号取模获得目标DNS地址 */ + i = dns->qid % dns->dns_list->count; + addr = acl_array_index(dns->dns_list, i); + if (addr == NULL) + acl_msg_fatal("%s(%d): addr null for %d", + myname, __LINE__, i); + +#ifdef ACL_UNIX + ret = sendto(fd, buf, size, 0, (struct sockaddr*) &addr->addr, + addr->addr_len); +#elif defined(ACL_MS_WINDOWS) + ret = sendto(fd, (const char*) buf, (int) size, 0, + (struct sockaddr*) &addr->addr, addr->addr_len); +#else +#error "unknown OS" +#endif + return (ret); +} + +/* 根据DNS查询结果生成 ACL_DNS_DB 对象 */ + +static ACL_DNS_DB *build_dns_db(const rfc1035_message *res, int count, + unsigned int *ttl_min) +{ + const char *myname = "build_dns_db"; + ACL_DNS_DB *dns_db = acl_netdb_new(res->query->name); + int i; + + if (ttl_min) + *ttl_min = 100000000; + + for (i = 0; i < count; i++) { + if (res->answer[i].type == RFC1035_TYPE_A) { + ACL_HOSTNAME *phost = + acl_mycalloc(1, sizeof(ACL_HOSTNAME)); + if (phost == NULL) { + acl_msg_fatal("%s: calloc error(%s)", + myname, acl_last_serror()); + } + +#if 0 + memcpy(&phost->saddr.sin_addr, res->answer[i].rdata, 4); +#elif defined(ACL_UNIX) + /* 这样直接赋值要比用 memcpy 快些 */ + phost->saddr.sin_addr.s_addr = + *((in_addr_t*) res->answer[i].rdata); +#elif defined(ACL_MS_WINDOWS) + phost->saddr.sin_addr.s_addr = + *((unsigned int*) res->answer[i].rdata); +#endif + acl_inet_ntoa(phost->saddr.sin_addr, + phost->ip, sizeof(phost->ip)); + phost->ttl = res->answer[i].ttl; + if (ttl_min && *ttl_min > phost->ttl) + *ttl_min = phost->ttl; + + if (acl_array_append(dns_db->h_db, phost) < 0) { + acl_msg_fatal("%s(%d): array append error(%s)", + myname, __LINE__, acl_last_serror()); + } + dns_db->size++; + } else if (0) { + ACL_HOSTNAME *phost = + acl_mycalloc(1, sizeof(ACL_HOSTNAME)); + if (phost == NULL) { + acl_msg_fatal("%s: calloc error(%s)", + myname, acl_last_serror()); + } + + memcpy(&phost->saddr.sin_addr, res->answer[i].rdata, 4); + acl_inet_ntoa(phost->saddr.sin_addr, + phost->ip, sizeof(phost->ip)); + phost->ttl = res->answer[i].ttl; + + if (acl_array_append(dns_db->h_db, phost) < 0) { + acl_msg_fatal("%s(%d): array append error(%s)", + myname, __LINE__, acl_last_serror()); + } + dns_db->size++; + + acl_msg_warn("%s: can't print answer type %d, domain %s, ip %s", + myname, res->answer[i].type, res->query->name, phost->ip); + } + } + + return (dns_db); +} + +/* 有DNS服务器数据可读时的回调函数 */ + +static int dns_lookup_callback(ACL_ASTREAM *astream acl_unused, void *ctx, + char *data, int dlen) +{ + const char *myname = "dns_lookup_callback"; + ACL_DNS *dns = (ACL_DNS*) ctx; + int ret; + ACL_DNS_REQ *handle; + rfc1035_message *res; + char key[RFC1035_MAXHOSTNAMESZ + 16]; + + /* 解析DNS响应数据包 */ + ret = rfc1035MessageUnpack(data, dlen, &res); + if (ret < 0) { + if (res == NULL) + return (0); + + snprintf(key, sizeof(key), "%s:%d", res->query->name, res->id); + acl_lowercase(key); + handle = acl_htable_find(dns->lookup_table, key); + + if (handle) { + void (*callback)(ACL_DNS_DB*, void*, int) = handle->callback; + void *arg = handle->ctx; + + /* 取消定时器 */ + acl_aio_cancel_timer(dns->aio, dns->lookup_timeout, handle); + /* 释放该查询对象 */ + acl_htable_delete(dns->lookup_table, handle->key, NULL); + acl_myfree(handle); + /* 通知应用查询失败 */ + callback(NULL, arg, res->rcode); + } + + rfc1035MessageDestroy(res); + return (0); + } else if (ret == 0) { + rfc1035MessageDestroy(res); + return (0); + } + + /* 是否检查 DNS 源/目的地址, 以保证安全性 */ + + if ((dns->flag & ACL_DNS_FLAG_CHECK_DNS_IP)) { + ACL_DNS_ADDR *addr; + unsigned short i; + + /* 获得本数据包对应的 DNS 地址索引 */ + i = (res->id + 1) % dns->dns_list->count; + addr = acl_array_index(dns->dns_list, i); + if (addr == NULL) + acl_msg_fatal("%s(%d): addr null for %d", + myname, __LINE__, i); + + if (dns->addr_from.addr.sin_addr.s_addr != addr->addr.sin_addr.s_addr) { + char from[64], to[64]; + acl_inet_ntoa(dns->addr_from.addr.sin_addr, from, sizeof(from)); + acl_inet_ntoa(addr->addr.sin_addr, to, sizeof(to)); + acl_msg_warn("%s(%d): from(%s) != to(%s)", + myname, __LINE__, from, to); + rfc1035MessageDestroy(res); + return (0); + } + } + + /* 是否检查 DNS 源/目的网络, 以保证安全性 */ + + if ((dns->flag & ACL_DNS_FLAG_CHECK_DNS_NET)) { + struct in_addr in; + ACL_DNS_ADDR *addr; + unsigned short i; + + /* 获得本数据包对应的 DNS 地址索引 */ + i = (res->id + 1) % dns->dns_list->count; + addr = acl_array_index(dns->dns_list, i); + if (addr == NULL) + acl_msg_fatal("%s(%d): addr null for %d", + myname, __LINE__, i); + + in.s_addr = dns->addr_from.addr.sin_addr.s_addr; + acl_mask_addr((unsigned char*) &in.s_addr, + sizeof(in.s_addr), addr->mask_length); + if (in.s_addr != addr->in.s_addr) { + char from[64], to[64]; + acl_inet_ntoa(in, from, sizeof(from)); + acl_inet_ntoa(addr->in, to, sizeof(to)); + acl_msg_warn("%s(%d): from(%s) != to(%s)", + myname, __LINE__, from, to); + rfc1035MessageDestroy(res); + return (0); + } + } + + acl_lowercase(res->query->name); + snprintf(key, sizeof(key), "%s:%d", res->query->name, res->id); + handle = acl_htable_find(dns->lookup_table, key); + if (handle != NULL) { + int ttl_min; + void (*callback)(ACL_DNS_DB*, void*, int) = handle->callback; + void *arg = handle->ctx; + ACL_DNS_DB *dns_db = + build_dns_db(res, ret, (unsigned int*) &ttl_min); + + /* 取消定时器 */ + acl_aio_cancel_timer(dns->aio, dns->lookup_timeout, handle); + /* 释放该查询对象 */ + acl_htable_delete(dns->lookup_table, handle->key, NULL); + acl_myfree(handle); + + /* 回调函数用户的回调函数 */ + callback(dns_db, arg, res->rcode); + + /* 如果缓存机制允许则缓存该查询结果 */ + if (dns->dns_cache == NULL) { + /* 释放结果对象 */ + acl_netdb_free(dns_db); + } else { + if (ttl_min <= 0 || acl_cache2_enter(dns->dns_cache, + res->query->name, dns_db, ttl_min) == NULL) + { + acl_netdb_free(dns_db); + } + } + } + + rfc1035MessageDestroy(res); + return (0); +} + +/* 数据流出错时的回调函数 */ + +static int dns_lookup_error(ACL_ASTREAM *server acl_unused, void *ctx) +{ + const char *myname = "dns_lookup_error"; + ACL_DNS *dns = (ACL_DNS*) ctx; + + acl_msg_warn("%s(%d): error(%s), re-open a new socket", + myname, __LINE__, acl_last_serror()); + + /* 创建一个新的套接口 */ + dns_stream_open(dns); + + /* 异步读DNS服务器响应数据 */ + acl_aio_read(dns->astream); + return (-1); +} + +/* 创建DNS查询的异步流 */ + +static void dns_stream_open(ACL_DNS *dns) +{ + const char *myname = "dns_stream_open"; + ACL_SOCKET fd = socket(PF_INET, SOCK_DGRAM, 0); + ACL_VSTREAM *vstream; + + if (fd == ACL_SOCKET_INVALID) + acl_msg_fatal("%s: socket create error", myname); + + /* 创建 ACL_VSTREAM 流并设置读写接口 */ + + vstream = acl_vstream_fdopen(fd, O_RDWR, 1024, 0, ACL_VSTREAM_TYPE_SOCK); + acl_vstream_ctl(vstream, + ACL_VSTREAM_CTL_READ_FN, dns_read, + ACL_VSTREAM_CTL_WRITE_FN, dns_write, + ACL_VSTREAM_CTL_CONTEXT, dns, + ACL_VSTREAM_CTL_END); + + /* 创建异步流 */ + dns->astream = acl_aio_open(dns->aio, vstream); + + /* 设置查询套接口可读时的回调函数 */ + acl_aio_add_read_hook(dns->astream, dns_lookup_callback, dns); + acl_aio_add_close_hook(dns->astream, dns_lookup_error, dns); + /* 设置该异步流为持续读状态 */ + dns->astream->keep_read = 1; +} + +static int dns_lookup_send(ACL_DNS *dns, ACL_DNS_REQ *handle, const char *domain) +{ + const char *myname = "dns_lookup_send"; + char buf[1024]; + int ret; + + memset(buf, 0, sizeof(buf)); + /* 创建DNS查询数据包 */ + ret = rfc1035BuildAQuery(domain, buf, sizeof(buf), dns->qid, NULL); + if (ret < 0) { + acl_msg_error("%s(%d): rfc1035BuildAQuery error for(%s)", + myname, __LINE__, domain); + return (-1); + } + + /* 增加ID号 */ + dns->qid++; + + /* 发送请求DNS包 */ + acl_aio_writen(dns->astream, buf, ret); + + /* 设置定时器 */ + acl_aio_request_timer(dns->aio, dns->lookup_timeout, + handle, dns->timeout * 1000000, 0); + return (0); +} + +/* 查询超时的回调函数 */ + +static void dns_lookup_timeout(int event_type, void *context) +{ + const char *myname = "dns_lookup_timeout"; + ACL_DNS_REQ *handle = (ACL_DNS_REQ*) context; + ACL_DNS *dns = handle->dns; + void (*callback)(ACL_DNS_DB*, void*, int) = handle->callback; + void *arg = handle->ctx; + + if (event_type != ACL_EVENT_TIME) { + acl_msg_warn("%s(%d): invalid event_type(%d)", + myname, __LINE__, event_type); + } + + if (++handle->nretry <= dns->retry_limit) { + char domain[RFC1035_MAXHOSTNAMESZ + 16], *ptr; + + ACL_SAFE_STRNCPY(domain, handle->key, sizeof(domain)); + ptr = strchr(domain, ':'); + if (ptr) + *ptr = 0; + if (dns_lookup_send(dns, handle, domain) == 0) + return; + } + + /* 释放该查询对象 */ + acl_htable_delete(handle->dns->lookup_table, handle->key, NULL); + acl_myfree(handle); + + /* 回调函数用户的回调函数 */ + callback(NULL, arg, ACL_DNS_ERR_TIMEOUT); +} + +void acl_dns_init(ACL_DNS *dns, ACL_AIO *aio, int timeout) +{ + dns->flag &= ~ACL_DNS_FLAG_ALLOC; /* 默认为栈空间 */ + dns->aio = aio; + dns->timeout = timeout > 0 ? timeout : 5; + dns->qid = 0; + dns->dns_idx = 0; + dns->retry_limit = 0; + + /* 创建DNS服务器地址数组 */ + dns->dns_list = acl_array_create(10); + /* 创建查询对象表 */ + dns->lookup_table = acl_htable_create(1024, 0); + + dns->lookup_timeout = dns_lookup_timeout; + + /* 打开异步读取DNS服务器响应的数据流 */ + dns_stream_open(dns); + + /* 开始异步读查询结果 */ + acl_aio_read(dns->astream); +} + +ACL_DNS *acl_dns_create(ACL_AIO *aio, int timeout) +{ + ACL_DNS *dns = (ACL_DNS*) acl_mycalloc(1, sizeof(ACL_DNS)); + + acl_dns_init(dns, aio, timeout); + dns->flag |= ACL_DNS_FLAG_ALLOC; /* 设置为堆分配的变量 */ + return (dns); +} + +void acl_dns_close(ACL_DNS *dns) +{ + ACL_ITER iter; + + acl_foreach(iter, dns->lookup_table) { + ACL_DNS_REQ *handle = (ACL_DNS_REQ*) iter.data; + acl_myfree(handle); + } + + acl_htable_free(dns->lookup_table, NULL); + dns->lookup_table = NULL; + if (dns->dns_cache) { + acl_cache2_free(dns->dns_cache); + dns->dns_cache = NULL; + } + acl_aio_iocp_close(dns->astream); + dns->aio = NULL; + dns->astream = NULL; + acl_array_destroy(dns->dns_list, acl_myfree_fn); + + if (dns->groups) { + acl_foreach(iter, dns->groups) { + ACL_DOMAIN_GROUP *tmp = (ACL_DOMAIN_GROUP*) iter.data; + if (tmp->excepts) + acl_argv_free(tmp->excepts); + acl_myfree(tmp); + } + acl_array_destroy(dns->groups, NULL); + } + + if ((dns->flag & ACL_DNS_FLAG_ALLOC)) + acl_myfree(dns); + else + dns->flag = 0; +} + +void acl_dns_check_dns_ip(ACL_DNS *dns) +{ + dns->flag |= ACL_DNS_FLAG_CHECK_DNS_IP; +} + +void acl_dns_check_dns_net(ACL_DNS *dns) +{ + dns->flag |= ACL_DNS_FLAG_CHECK_DNS_NET; +} + +void acl_dns_set_retry_limit(ACL_DNS *dns, int retry_limit) +{ + dns->retry_limit = retry_limit; +} + +static void cache_free_fn(const ACL_CACHE2_INFO *info acl_unused, void *arg) +{ + ACL_DNS_DB *dns_db = (ACL_DNS_DB*) arg; + + /* 释放缓存对象 */ + acl_netdb_free(dns_db); +} + +void acl_dns_open_cache(ACL_DNS *dns, int limit) +{ + if (dns->dns_cache) + return; + if (limit <= 0) + return; + dns->dns_cache = acl_cache2_create(limit, cache_free_fn); +} + +void acl_dns_add_dns(ACL_DNS *dns, const char *dns_ip, + unsigned short dns_port, int mask_length) +{ + const char *myname = "acl_dns_add_dns"; + ACL_DNS_ADDR *addr; + + if (mask_length >= 32 || mask_length <= 0) { + acl_msg_error("%s(%d): mask_length(%d) invalid", + myname, __LINE__, mask_length); + return; + } + + addr = (ACL_DNS_ADDR*) acl_mycalloc(1, sizeof(ACL_DNS_ADDR)); + addr->mask_length = mask_length; + + /* 设置DNS服务器地址 */ + + ACL_SAFE_STRNCPY(addr->ip, dns_ip, sizeof(addr->ip)); + addr->port = dns_port; + + memset(&addr->addr, 0, sizeof(addr->addr)); + addr->addr.sin_family = AF_INET; + addr->addr.sin_port = htons(dns_port); + addr->addr.sin_addr.s_addr = inet_addr(dns_ip); + addr->addr_len = sizeof(struct sockaddr_in); + + addr->in.s_addr = addr->addr.sin_addr.s_addr; + acl_mask_addr((unsigned char*) &addr->in.s_addr, + sizeof(addr->in.s_addr), mask_length); + + /* 将该DNS地址添加进数组中 */ + + if (acl_array_append(dns->dns_list, addr) < 0) + acl_msg_fatal("%s(%d): add dns error(%s)", + myname, __LINE__, acl_last_serror()); +} + +void acl_dns_add_host(ACL_DNS *dns, const char *domain, const char *ip_list) +{ + const char *myname = "acl_dns_add_host"; + ACL_DNS_DB *dns_db; + ACL_ARGV *argv; + ACL_ITER iter; + + if (dns->dns_cache == NULL) { + acl_msg_error("%s(%d): please call acl_dns_open_cache first!", + myname, __LINE__); + return; + } + + dns_db = acl_netdb_new(domain); + argv = acl_argv_split(ip_list, ",; \t"); + acl_foreach(iter, argv) { + char *ip = (char*) iter.data; + ACL_HOSTNAME *phost = acl_mycalloc(1, sizeof(ACL_HOSTNAME)); + + ACL_SAFE_STRNCPY(phost->ip, ip, sizeof(phost->ip)); + phost->saddr.sin_family = AF_INET; + phost->saddr.sin_addr.s_addr = inet_addr(ip); + if (acl_array_append(dns_db->h_db, phost) < 0) { + acl_msg_fatal("%s(%d): array append error(%s)", + myname, __LINE__, acl_last_serror()); + } + } + + if (acl_cache2_enter(dns->dns_cache, dns_db->name, dns_db, 0) == NULL) { + acl_msg_fatal("%s(%d): add domain(%s) error(%s)", + myname, __LINE__, domain, acl_last_serror()); + acl_netdb_free(dns_db); + } + acl_argv_free(argv); +} + +void acl_dns_add_group(ACL_DNS *dns, const char *group, const char *refer, + const char *ip_list, const char *excepts) +{ + const char *myname = "acl_dns_add_group"; + ACL_DOMAIN_GROUP *dmgrp; + ACL_ITER iter; + + if (dns->groups == NULL) + dns->groups = acl_array_create(10); + + acl_foreach(iter, dns->groups) { + dmgrp = (ACL_DOMAIN_GROUP*) iter.data; + if (strcasecmp(dmgrp->group, group) == 0) { + acl_msg_warn("%s(%d): group(%s) already exist", + myname, __LINE__, group); + return; + } + } + + dmgrp = (ACL_DOMAIN_GROUP*) acl_mycalloc(1, sizeof(ACL_DOMAIN_GROUP)); + + ACL_SAFE_STRNCPY(dmgrp->group, group, sizeof(dmgrp->group)); + acl_lowercase(dmgrp->group); + dmgrp->group_len = strlen(dmgrp->group); + + if (refer == NULL || *refer == 0) + ACL_SAFE_STRNCPY(dmgrp->domain, dmgrp->group, sizeof(dmgrp->domain)); + else { + ACL_SAFE_STRNCPY(dmgrp->domain, refer, sizeof(dmgrp->domain)); + acl_lowercase(dmgrp->domain); + } + if (excepts) + dmgrp->excepts = acl_argv_split(excepts, ",; \t"); + else + dmgrp->excepts = NULL; + + acl_array_append(dns->groups, dmgrp); + + if (ip_list && *ip_list) + acl_dns_add_host(dns, dmgrp->domain, ip_list); +} + +ACL_DNS_REQ *acl_dns_lookup(ACL_DNS *dns, const char *domain_in, + void (*callback)(ACL_DNS_DB *, void *, int), void *ctx) +{ + const char *myname = "acl_dns_lookup"; + char key[RFC1035_MAXHOSTNAMESZ + 16], domain[RFC1035_MAXHOSTNAMESZ]; + ACL_DNS_REQ *handle; + + /* 先检查是否匹配域名组 */ + if (dns->groups) { + ACL_DOMAIN_GROUP *dmgrp = NULL; + ACL_ITER iter; + acl_foreach(iter, dns->groups) { + ACL_ITER iter2; + ACL_DOMAIN_GROUP *tmp = (ACL_DOMAIN_GROUP*) iter.data; + /* 先找到域名组对象 */ + if (acl_strrncasecmp(tmp->group, domain_in, tmp->group_len)) + continue; + /* 检查该域名是否是域名组的例外域名 */ + if (tmp->excepts) { + acl_foreach(iter2, tmp->excepts) { + char *except = (char*) iter2.data; + if (strcasecmp(except, domain_in) == 0) + goto END_FOREACH_TAG; + } + } + dmgrp = tmp; + break; + } + +END_FOREACH_TAG: + if (dmgrp) + ACL_SAFE_STRNCPY(domain, dmgrp->domain, sizeof(domain)); + else + ACL_SAFE_STRNCPY(domain, domain_in, sizeof(domain)); + } else + ACL_SAFE_STRNCPY(domain, domain_in, sizeof(domain)); + + acl_lowercase(domain); + + /* 如果打开DNS缓存功能,则优先查询缓存 */ + if (dns->dns_cache) { + ACL_DNS_DB *dns_db; + dns_db = acl_cache2_find(dns->dns_cache, domain); + if (dns_db) { + callback(dns_db, ctx, ACL_DNS_OK_CACHE); + return (NULL); + } + } + + snprintf(key, sizeof(key), "%s:%d", domain, dns->qid); + acl_lowercase(key); + handle = (ACL_DNS_REQ*) acl_htable_find(dns->lookup_table, key); + /* XXX: 不应存在相同的键存在, 因为该键是由域名及自动ID组成 */ + if (handle != NULL) { + acl_msg_warn("%s(%d): key(%s) exist", myname, __LINE__, key); + callback(NULL, ctx, ACL_DNS_ERR_EXIST); + return (NULL); + } + + /* 分配新的查询对象 */ + handle = (ACL_DNS_REQ*) acl_mycalloc(1, sizeof(ACL_DNS_REQ)); + handle->dns = dns; + handle->callback = callback; + handle->ctx = ctx; + handle->qid = dns->qid; + ACL_SAFE_STRNCPY(handle->key, key, sizeof(handle->key)); + + /* 添加进查询对象表中 */ + if (acl_htable_enter(dns->lookup_table, key, handle) == NULL) + acl_msg_fatal("%s(%d): enter htable error(%s)", + myname, __LINE__, acl_last_serror()); + + if (dns_lookup_send(dns, handle, domain) < 0) { + acl_htable_delete(dns->lookup_table, key, NULL); + acl_myfree(handle); + callback(NULL, ctx, ACL_DNS_ERR_BUILD_REQ); + return (NULL); + } + return (handle); +} + +void acl_dns_cancel(ACL_DNS_REQ *handle) +{ + const char *myname = "acl_dns_cancel"; + + if (handle == NULL || handle->dns == NULL) { + acl_msg_error("%s(%d): input error", myname, __LINE__); + return; + } + acl_htable_delete(handle->dns->lookup_table, handle->key, NULL); + acl_myfree(handle); +} + +const char *acl_dns_serror(int errnum) +{ + struct __ERRMSG{ + int errnum; + const char *msg; + }; + static const struct __ERRMSG errmsg[] = { + { ACL_DNS_OK, "OK, No error condition" }, + { ACL_DNS_OK_CACHE, "OK, in cache" }, + { ACL_DNS_ERR_FMT, "Format Error: The name server was unable to " + "interpret the query." }, + { ACL_DNS_ERR_SVR, "Server Failure: The name server was " + "unable to process this query." }, + { ACL_DNS_ERR_NO_EXIST, "Name Error: The domain name does not exist." }, + { ACL_DNS_ERR_NO_SUPPORT, "Not Implemented: The name server does " + "not support the requested kind of query." }, + { ACL_DNS_ERR_DENY, "Refused: The name server refuses to " + "perform the specified operation." }, + { ACL_DNS_ERR_YX, "The domain should not exist" }, + { ACL_DNS_ERR_YXRR, "The domain's RR should not exist" }, + { ACL_DNS_ERR_NXRR, "The domain's RR should exist" }, + { ACL_DNS_ERR_NO_AUTH, "The dns is not authority" }, + { ACL_DNS_ERR_NOT_ZONE, "The domain name is not in the zone" }, + { ACL_DNS_ERR_NOT_ZONE + 1, "Unknown Error" }, + { ACL_DNS_ERR_NOT_ZONE + 2, "Unknown Error" }, + { ACL_DNS_ERR_NOT_ZONE + 3, "Unknown Error" }, + { ACL_DNS_ERR_NOT_ZONE + 4, "Unknown Error" }, + { ACL_DNS_ERR_UNPACK, "The DNS reply message is corrupt or could " + "not be safely parsed." }, + { ACL_DNS_ERR_TIMEOUT, "The DNS reply timeout" }, + { ACL_DNS_ERR_EXIST, "The same DNS search exist" }, + { ACL_DNS_ERR_BUILD_REQ, "Can't build query packet" }, + { 0, 0 } + }; + const char *unknown = "Unknown Error"; + size_t i; + + for (i = 0; errmsg[i].msg != NULL; ++i) + { + if (errnum == errmsg[i].errnum) + return errmsg[i].msg; + } + return unknown; +} diff --git a/lib_acl/src/net/dns/acl_netdb.c b/lib_acl/src/net/dns/acl_netdb.c new file mode 100644 index 000000000..d623fff2a --- /dev/null +++ b/lib_acl/src/net/dns/acl_netdb.c @@ -0,0 +1,496 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#include +#include +#ifdef ACL_UNIX +#include +#include +#include +#include +#include +/* extern int h_errno; */ +#endif + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_mystring.h" +#include "stdlib/acl_msg.h" +#include "stdlib/acl_array.h" +#include "net/acl_sane_inet.h" +#include "net/acl_netdb.h" + +#endif + +const ACL_HOSTNAME *acl_netdb_index(const ACL_DNS_DB *h_dns_db, int n) +{ + const char *myname = "acl_netdb_index"; + ACL_HOSTNAME *h_hostname; + + if (h_dns_db == NULL || n < 0) { + acl_msg_error("%s, %s(%d): input error", + __FILE__, myname, __LINE__); + return (NULL); + } + + if (h_dns_db->size == 0) { + acl_msg_error("%s, %s(%d): dns db size is 0", + __FILE__, myname, __LINE__); + return (NULL); + } + if (n >= h_dns_db->size) { + acl_msg_error("%s, %s(%d): index(%d) > size(%d)", + __FILE__, myname, __LINE__, n, h_dns_db->size); + return (NULL); + } + + h_hostname = (ACL_HOSTNAME *) acl_array_index(h_dns_db->h_db, n); + return (h_hostname); +} + +const struct sockaddr_in *acl_netdb_index_saddr(ACL_DNS_DB *h_dns_db, int n) +{ + const char *myname= "acl_netdb_index_saddr"; + ACL_HOSTNAME *h_hostname; + + if (h_dns_db == NULL || n < 0) { + acl_msg_error("%s, %s(%d): input error", + __FILE__, myname, __LINE__); + return (NULL); + } + if (h_dns_db->size == 0) { + acl_msg_error("%s, %s(%d): dns db size is 0", + __FILE__, myname, __LINE__); + return (NULL); + } + if (n >= h_dns_db->size) { + acl_msg_error("%s, %s(%d): index(%d) > size(%d)", + __FILE__, myname, __LINE__, n, h_dns_db->size); + return (NULL); + } + + h_hostname = (ACL_HOSTNAME *) acl_array_index(h_dns_db->h_db, n); + return (&h_hostname->saddr); +} + +const char *acl_netdb_index_ip(const ACL_DNS_DB *h_dns_db, int n) +{ + const char *myname = "acl_netdb_index_ip"; + ACL_HOSTNAME *h_hostname; + + if (h_dns_db == NULL || n < 0) { + acl_msg_error("%s, %s(%d): input error", + __FILE__, myname, __LINE__); + return (NULL); + } + if (h_dns_db->size == 0) { + acl_msg_error("%s, %s(%d): dns db size is 0", + __FILE__, myname, __LINE__); + return (NULL); + } + if (n >= h_dns_db->size) { + acl_msg_error("%s, %s(%d): index(%d) > size(%d)", + __FILE__, myname, __LINE__, n, h_dns_db->size); + return (NULL); + } + h_hostname = (ACL_HOSTNAME *) acl_array_index(h_dns_db->h_db, n); + return (h_hostname->ip); +} + +void acl_netdb_refer_oper(ACL_DNS_DB *h_dns_db, int idx, int value) +{ + const char *myname = "acl_netdb_refer_oper"; + ACL_HOSTNAME *h_hostname; + + if (h_dns_db == NULL || idx < 0) { + acl_msg_error("%s, %s(%d): input error", + __FILE__, myname, __LINE__); + return; + } + + if (h_dns_db->size == 0) { + acl_msg_error("%s, %s(%d): dns db size is 0", + __FILE__, myname, __LINE__); + return; + } + if (idx >= h_dns_db->size) { + acl_msg_error("%s, %s(%d): index(%d) > size(%d)", + __FILE__, myname, __LINE__, idx, h_dns_db->size); + return; + } + h_hostname = (ACL_HOSTNAME *) acl_array_index(h_dns_db->h_db, idx); + + h_hostname->nrefer += value; +} + +void acl_netdb_refer(ACL_DNS_DB *h_dns_db, int idx) +{ + acl_netdb_refer_oper(h_dns_db, idx, 1); +} + +void acl_netdb_unrefer(ACL_DNS_DB *h_dns_db, int idx) +{ + acl_netdb_refer_oper(h_dns_db, idx, -1); +} + +int acl_netdb_size(const ACL_DNS_DB *h_dns_db) +{ + const char *myname = "acl_netdb_size"; + + if (h_dns_db == NULL) { + acl_msg_error("%s, %s(%d): input invalid", + __FILE__, myname, __LINE__); + return (-1); + } + + return (h_dns_db->size); +} + +static void free_dns_db(void *ctx) +{ + acl_myfree(ctx); +} + +void acl_netdb_free(ACL_DNS_DB *h_dns_db) +{ + if (h_dns_db == NULL) + return; + if (h_dns_db->h_db) + acl_array_destroy(h_dns_db->h_db, free_dns_db); + acl_myfree(h_dns_db); +} + +static const ACL_HOST_INFO *netdb_iter_head(ACL_ITER *iter, struct ACL_DNS_DB *dns_db) +{ + return ((const ACL_HOST_INFO*) dns_db->h_db->iter_head(iter, dns_db->h_db)); +} + +static const ACL_HOST_INFO *netdb_iter_next(ACL_ITER *iter, struct ACL_DNS_DB *dns_db) +{ + return ((const ACL_HOST_INFO*) dns_db->h_db->iter_next(iter, dns_db->h_db)); +} + +static const ACL_HOST_INFO *netdb_iter_tail(ACL_ITER *iter, struct ACL_DNS_DB *dns_db) +{ + return ((const ACL_HOST_INFO*) dns_db->h_db->iter_tail(iter, dns_db->h_db)); +} + +static const ACL_HOST_INFO *netdb_iter_prev(ACL_ITER *iter, struct ACL_DNS_DB *dns_db) +{ + return ((const ACL_HOST_INFO*) dns_db->h_db->iter_prev(iter, dns_db->h_db)); +} + +static const ACL_HOST_INFO *netdb_iter_info(ACL_ITER *iter, struct ACL_DNS_DB *dns_db acl_unused) +{ + return (iter->ptr ? (ACL_HOST_INFO*) iter->ptr : NULL); +} + +ACL_DNS_DB *acl_netdb_new(const char *domain) +{ + const char *myname = "acl_netdb_new"; + ACL_DNS_DB *dns_db; + char buf[256]; + + dns_db = acl_mycalloc(1, sizeof(ACL_DNS_DB)); + if (dns_db == NULL) { + acl_msg_error("%s, %s(%d): calloc error(%s)", + __FILE__, myname, __LINE__, + acl_last_strerror(buf, sizeof(buf))); + return (NULL); + } + + dns_db->h_db = acl_array_create(5); + if (dns_db->h_db == NULL) { + acl_msg_error("%s, %s(%d): create array error(%s)", + __FILE__, myname, __LINE__, + acl_last_strerror(buf, sizeof(buf))); + acl_myfree(dns_db); + return (NULL); + } + + snprintf(dns_db->name, sizeof(dns_db->name), "%s", domain); + acl_lowercase(dns_db->name); + + dns_db->iter_head = netdb_iter_head; + dns_db->iter_next = netdb_iter_next; + dns_db->iter_tail = netdb_iter_tail; + dns_db->iter_prev = netdb_iter_prev; + dns_db->iter_info = netdb_iter_info; + + return (dns_db); +} + +void acl_netdb_addip(ACL_DNS_DB *dns_db, const char *ip) +{ + acl_netdb_add_addr(dns_db, ip, 0); +} + +void acl_netdb_add_addr(ACL_DNS_DB *dns_db, const char *ip, int hport) +{ + const char *myname = "acl_netdb_add_addr"; + ACL_HOSTNAME *phost; + char buf[256]; + + if (dns_db == NULL || dns_db->h_db == NULL || ip == NULL) { + acl_msg_error("%s(%d): input invalid", myname, __LINE__); + return; + } + + phost = acl_mycalloc(1, sizeof(ACL_HOSTNAME)); + if (phost == NULL) { + acl_msg_error("%s(%d): calloc error(%s)", + myname, __LINE__, acl_last_strerror(buf, sizeof(buf))); + return; + } + + memset(&phost->saddr, 0, sizeof(phost->saddr)); + ACL_SAFE_STRNCPY(phost->ip, ip, sizeof(phost->ip)); + phost->saddr.sin_addr.s_addr = (unsigned long) inet_addr(ip); + phost->hport = hport; + + if (acl_array_append(dns_db->h_db, phost) < 0) { + acl_msg_error("%s(%d): array append error(%s)", + myname, __LINE__, acl_last_strerror(buf, sizeof(buf))); + return; + } + + dns_db->size++; +} + +ACL_DNS_DB *acl_netdb_clone(const ACL_DNS_DB *h_dns_db) +{ + const char *myname = "acl_netdb_clone"; + char buf[256]; + ACL_DNS_DB *dns_db; + ACL_HOSTNAME *phost, *h_host; + int i, n; + + if (h_dns_db == NULL || h_dns_db->h_db == NULL) + return (NULL); + + n = acl_array_size(h_dns_db->h_db); + if (n <= 0) { + acl_msg_error("%s, %s(%d): h_db's size(%d) <= 0", + __FILE__, myname, __LINE__, n); + return (NULL); + } + + dns_db = acl_netdb_new(h_dns_db->name); + if (dns_db == NULL) { + acl_msg_error("%s, %s(%d): acl_netdb_new error(%s)", + __FILE__, myname, __LINE__, + acl_last_strerror(buf, sizeof(buf))); + return (NULL); + } + + for (i = 0; i < n; i++) { + phost = (ACL_HOSTNAME *) acl_array_index(h_dns_db->h_db, i); + acl_assert(phost); + + h_host = acl_mycalloc(1, sizeof(ACL_HOSTNAME)); + if (h_host == NULL) { + acl_msg_error("%s, %s(%d): calloc error(%s)", + __FILE__, myname, __LINE__, + acl_last_strerror(buf, sizeof(buf))); + acl_netdb_free(dns_db); + return (NULL); + } + + h_host->saddr.sin_addr.s_addr = phost->saddr.sin_addr.s_addr; + ACL_SAFE_STRNCPY(h_host->ip, phost->ip, sizeof(h_host->ip)); + h_host->hport = phost->hport; + + if (acl_array_append(dns_db->h_db, h_host) < 0) { + acl_msg_error("%s, %s(%d): array append error(%s)", + __FILE__, myname, __LINE__, + acl_last_strerror(buf, sizeof(buf))); + acl_netdb_free(dns_db); + return (NULL); + } + + dns_db->size++; + } + + return (dns_db); +} + +ACL_DNS_DB *acl_gethostbyname(const char *name, int *h_error) +{ + char myname[] = "acl_gethostbyname"; + ACL_DNS_DB *h_dns_db = NULL; + ACL_HOSTNAME *h_host; +/* #ifndef SUNOS5 */ + struct hostent *h_addrp = NULL; +/* #endif */ + +#ifdef ACL_UNIX +# ifndef ACL_MACOSX + struct hostent h_buf; + int errnum = 0; +# endif +#endif + char **pptr, buf[4096]; + int n; + +#undef ERETURN +#define ERETURN(_x_) do { \ + if (h_dns_db) \ + acl_netdb_free(h_dns_db); \ + return (_x_); \ +} while (0) + + if (name == NULL) { + acl_msg_error("%s, %s(%d): input error", + __FILE__, myname, __LINE__); + ERETURN (NULL); + } + + if (h_error) + *h_error = 0; + + /* lookup the local dns cache first */ + h_dns_db = acl_netdb_cache_lookup(name); + if (h_dns_db) + return (h_dns_db); + + h_dns_db = acl_netdb_new(name); + if (h_dns_db == NULL) { + acl_msg_error("%s, %s(%d): acl_netdb_new error(%s)", + __FILE__, myname, __LINE__, + acl_last_strerror(buf, sizeof(buf))); + return (NULL); + } + + if (acl_is_ip(name) == 0) { + h_host = acl_mycalloc(1, sizeof(ACL_HOSTNAME)); + if (h_host == NULL) { + acl_msg_error("%s, %s(%d): calloc error(%s)", + __FILE__, myname, __LINE__, + acl_last_strerror(buf, sizeof(buf))); + ERETURN (NULL); + } + h_host->saddr.sin_addr.s_addr = inet_addr(name); + ACL_SAFE_STRNCPY(h_host->ip, name, sizeof(h_host->ip)); + + if (acl_array_append(h_dns_db->h_db, h_host) < 0) { + acl_msg_error("%s, %s(%d): array append error(%s)", + __FILE__, myname, __LINE__, + acl_last_strerror(buf, sizeof(buf))); + ERETURN (NULL); + } + + h_dns_db->size++; + + return (h_dns_db); + } + + memset(buf, 0, sizeof(buf)); + + h_addrp = NULL; + +#if defined(ACL_MS_WINDOWS) || defined(ACL_MACOSX) + h_addrp = gethostbyname(name); + if (h_addrp == NULL) { + acl_msg_error("%s, %s(%d): gethostbyname error(%s), addr=%s", + __FILE__, myname, __LINE__, + acl_last_strerror(buf, sizeof(buf)), name); + ERETURN (NULL); + } + +#elif defined(ACL_UNIX) + memset(&h_buf, 0, sizeof(h_buf)); +# if defined(LINUX2) || defined(ACL_FREEBSD) + n = gethostbyname_r(name, &h_buf, buf, sizeof(buf), &h_addrp, &errnum); + if (n) { + if (h_error) + *h_error = errnum; + ERETURN (NULL); + } +# elif defined(SUNOS5) + h_addrp = gethostbyname_r(name, &h_buf, buf, sizeof(buf), &errnum); + if (h_addrp == NULL) { + if (h_error) + *h_error = errnum; + ERETURN (NULL); + } +# else +# error "unknown OS type" +# endif +#else +# error "unknown OS type" +#endif + + if (h_addrp == NULL || h_addrp->h_addr_list == NULL) { + acl_msg_error("%s, %s(%d): null result return(%s)", + __FILE__, myname, __LINE__, + acl_last_strerror(buf, sizeof(buf))); + ERETURN (NULL); + } + + for (pptr = h_addrp->h_addr_list; *pptr != NULL; pptr++) { + h_host = acl_mycalloc(1, sizeof(ACL_HOSTNAME)); + if (h_host == NULL) { + acl_msg_error("%s, %s(%d): calloc error(%s)", + __FILE__, myname, __LINE__, + acl_last_strerror(buf, sizeof(buf))); + ERETURN (NULL); + } + + memset(&h_host->saddr, 0, sizeof(h_host->saddr)); + n = (int) sizeof(h_host->saddr.sin_addr) > h_addrp->h_length + ? h_addrp->h_length : (int) sizeof(h_host->saddr.sin_addr); + memcpy(&h_host->saddr.sin_addr, *pptr, n); + /* bugifx: 2009.12.8 + * this is not thread safe + * ACL_SAFE_STRNCPY(h_host->ip, inet_ntoa(h_host->saddr.sin_addr), sizeof(h_host->ip)); + */ + acl_inet_ntoa(h_host->saddr.sin_addr, h_host->ip, sizeof(h_host->ip)); + + if (acl_array_append(h_dns_db->h_db, h_host) < 0) { + acl_msg_error("%s, %s(%d): array append error(%s)", + __FILE__, myname, __LINE__, + acl_last_strerror(buf, sizeof(buf))); + ERETURN (NULL); + } + + h_dns_db->size++; + } + + acl_netdb_cache_push(h_dns_db, 0); + + return (h_dns_db); +} + +typedef struct ACL_DNS_ERROR { + int h_error; + const char *info; +} ACL_DNS_ERROR; + +static ACL_DNS_ERROR __dns_errlist[] = { +#ifdef LINUX2 + { HOST_NOT_FOUND, "The specified host is unknown" }, + { TRY_AGAIN, "A temporary error occurred on an authoritative name server. Try again later." }, + { NO_RECOVERY, "A non-recoverable name server error occurred" }, + { NO_DATA, "The requested name is valid but does not have an IP address" }, +#endif + { -1, "unknown error" }, +}; + +const char *acl_netdb_strerror(int errnum) +{ + int i, n; + + n = sizeof(__dns_errlist) / sizeof(ACL_DNS_ERROR); + + for (i = 0; i < n; i++) + if (__dns_errlist[i].h_error == errnum) + return (__dns_errlist[i].info); + + return ("unknown error number"); +} + diff --git a/lib_acl/src/net/dns/acl_netdb_cache.c b/lib_acl/src/net/dns/acl_netdb_cache.c new file mode 100644 index 000000000..48936effb --- /dev/null +++ b/lib_acl/src/net/dns/acl_netdb_cache.c @@ -0,0 +1,287 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#ifdef ACL_MS_WINDOWS +#include +#endif +#ifdef ACL_UNIX +#include +#include +#include +#endif + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_stdlib.h" +#include "thread/acl_thread.h" +#include "net/acl_netdb.h" + +#endif + +static acl_pthread_mutex_t __cache_mutex; +static ACL_HTABLE *__cache_table = NULL; +static ACL_RING __cache_ring; + +typedef struct CACHE { + ACL_DNS_DB *h_dns_db; + char name[256]; + time_t tm_timeout; + ACL_RING ring_entry; +} CACHE; + +static int __use_trylock = 0; +static int __cache_timeout = 300; /* 300 seconds */ + +static void cache_lock(void) +{ + const char *myname = "cache_lock"; + char buf[256]; + int status; + + status = acl_pthread_mutex_lock(&__cache_mutex); + if (status) { + acl_msg_fatal("%s: pthread_mutex_lock error(%s)", + myname, acl_last_strerror(buf, sizeof(buf))); + } +} + +static int cache_trylock(void) +{ + int status; + + status = acl_pthread_mutex_trylock(&__cache_mutex); + if (status == 0) + return (0); + else { + return (-1); + } +} + +static void cache_unlock(void) +{ + const char *myname = "cache_unlock"; + char buf[256]; + int status; + + status = acl_pthread_mutex_unlock(&__cache_mutex); + if (status) { + acl_msg_fatal("%s: pthread_mutex_lock error(%s)", + myname, acl_last_strerror(buf, sizeof(buf))); + } +} + +static void free_cache_fn(char *value) +{ + CACHE *cache = (CACHE *) value; + + if (cache->h_dns_db) + acl_netdb_free(cache->h_dns_db); + acl_ring_detach(&cache->ring_entry); + acl_htable_delete(__cache_table, cache->name, NULL); + acl_myfree(cache); +} + +static void cache_timer_fn(void) +{ + CACHE *cache, *tmp; + ACL_RING_ITER iter; + time_t current; + + current = time(NULL); + + acl_ring_foreach(iter, &__cache_ring) { + cache = ACL_RING_TO_APPL(iter.ptr, CACHE, ring_entry); + if (current >= cache->tm_timeout) { + tmp = cache; + iter.ptr = acl_ring_succ(iter.ptr); + free_cache_fn((char *) tmp); + } else + break; + } +} + +void acl_netdb_cache_push(const ACL_DNS_DB *h_dns_db, int timeout) +{ + const char *myname = "acl_netdb_cache_push"; + char buf[256]; + CACHE *cache; + + /* 如果禁止缓存,则直接返回 */ + if (__cache_timeout <= 0) + return; + + if (__cache_table == NULL) + return; + + if (h_dns_db == NULL || h_dns_db->h_db == NULL) { + acl_msg_error("%s(%d): input invalid", myname, __LINE__); + return; + } + if (__cache_table == NULL) { + acl_msg_error("%s(%d): acl_netdb_cache_init first", myname, __LINE__); + } + if (h_dns_db->name[0] == 0) { + acl_msg_error("%s(%d): host name empty", myname, __LINE__); + return; + } + if (h_dns_db->size <= 0) { + acl_msg_error("%s(%d): size(%d) <= 0", myname, __LINE__, h_dns_db->size); + return; + } + if (h_dns_db->size != acl_array_size(h_dns_db->h_db)) { + acl_msg_fatal("%s(%d): size(%d) != array size(%d)", + myname, __LINE__, h_dns_db->size, + acl_array_size(h_dns_db->h_db)); + } + + if (__use_trylock) { + if (cache_trylock() < 0) { + return; + } + } else + cache_lock(); + + cache = (CACHE *) acl_htable_find(__cache_table, h_dns_db->name); + if (cache == NULL) { + cache = (CACHE *) acl_mycalloc(1, sizeof(CACHE)); + if (cache == NULL) { + cache_unlock(); + acl_msg_error("%s(%d): calloc error(%s)", + myname, __LINE__, acl_last_strerror(buf, sizeof(buf))); + return; + } + + if (acl_htable_enter(__cache_table, h_dns_db->name, (char *) cache) == NULL) { + cache_unlock(); + acl_msg_error("%s(%d): add to htable error(%s)", + myname, __LINE__, acl_last_strerror(buf, sizeof(buf))); + return; + } + + acl_ring_prepend(&__cache_ring, &cache->ring_entry); + + ACL_SAFE_STRNCPY(cache->name, h_dns_db->name, sizeof(cache->name)); + } else { + /* override the old cache */ + + if (cache->h_dns_db != NULL) + acl_netdb_free(cache->h_dns_db); + cache->h_dns_db = NULL; + acl_ring_detach(&cache->ring_entry); + acl_ring_prepend(&__cache_ring, &cache->ring_entry); + } + + cache->tm_timeout = time(NULL) + timeout > 0 ? timeout : __cache_timeout; + cache->h_dns_db = acl_netdb_clone(h_dns_db); + if (cache->h_dns_db == NULL) { + free_cache_fn((char *) cache); + } + + cache_unlock(); +} + +ACL_DNS_DB *acl_netdb_cache_lookup(const char *name) +{ + const char *myname = "acl_netdb_cache_lookup"; + CACHE *cache; + char buf[256]; + ACL_DNS_DB *h_dns_db = NULL; + + if (__cache_table == NULL || name == NULL) + return (NULL); + + if (__use_trylock) { + if (cache_trylock() < 0) + return (NULL); + } else + cache_lock(); + + cache_timer_fn(); + + ACL_SAFE_STRNCPY(buf, name, sizeof(buf)); + acl_lowercase(buf); + + cache = (CACHE *) acl_htable_find(__cache_table, buf); + if (cache == NULL) { + cache_unlock(); + return (NULL); + } + + if (cache->h_dns_db == NULL) { /* XXX */ + acl_msg_error("%s, %s(%d): h_dns_db null", + __FILE__, myname, __LINE__); + free_cache_fn((char *) cache); + cache_unlock(); + return (NULL); + } + + /* if the dns cache has been timeout ? */ + + if (time(NULL) >= cache->tm_timeout) { + free_cache_fn((char *) cache); + cache_unlock(); + return (NULL); + } + + /* clone the ACL_DNS_DB object */ + + h_dns_db = acl_netdb_clone(cache->h_dns_db); + if (h_dns_db == NULL) { + acl_msg_error("%s, %s(%d): calloc error(%s)", + __FILE__, myname, __LINE__, + acl_last_strerror(buf, sizeof(buf))); + cache_unlock(); + return (NULL); + } + + cache_unlock(); + + return (h_dns_db); +} + +void acl_netdb_cache_del_host(const char *name) +{ + CACHE *cache; + + if (__cache_table == NULL) + return; + + cache_lock(); + cache = (CACHE *) acl_htable_find(__cache_table, name); + if (cache) + free_cache_fn((char *) cache); + cache_unlock(); +} + +void acl_netdb_cache_init(int timeout, int thread_safe) +{ + const char *myname = "acl_netdb_cache_init"; + char buf[256]; + int status; + + if (timeout > 0) + __cache_timeout = timeout; + + if (thread_safe) { + status = acl_pthread_mutex_init(&__cache_mutex, NULL); + if (status) { + acl_msg_error("%s: pthread_mutex_init error(%s)", + myname, acl_last_strerror(buf, sizeof(buf))); + return; + } + __use_trylock = 1; + } + + __cache_table = acl_htable_create(256, 0); + if (__cache_table == NULL) + acl_msg_error("%s: create htable error(%s)", + myname, acl_last_strerror(buf, sizeof(buf))); + + acl_ring_init(&__cache_ring); +} + + diff --git a/lib_acl/src/net/dns/acl_res.c b/lib_acl/src/net/dns/acl_res.c new file mode 100644 index 000000000..5d6a3eb71 --- /dev/null +++ b/lib_acl/src/net/dns/acl_res.c @@ -0,0 +1,278 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#ifdef ACL_UNIX +#include +#include +#include +#include +#endif +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_stdlib.h" +#include "net/acl_vstream_net.h" +#include "net/acl_sane_inet.h" +#include "net/acl_res.h" + +#endif + +#include "rfc1035.h" + +ACL_RES *acl_res_new(const char *dns_ip, unsigned short dns_port) +{ + const char *myname = "acl_res_new"; + ACL_RES *res; + + if (dns_ip == NULL || *dns_ip == 0) + acl_msg_fatal("%s: dns_ip invalid", myname); + if (dns_port <= 0) + dns_port = 53; + + res = acl_mycalloc(1, sizeof(ACL_RES)); + res->cur_qid = (unsigned short) time(NULL); + + ACL_SAFE_STRNCPY(res->dns_ip, dns_ip, sizeof(res->dns_ip)); + res->dns_port = dns_port; + + res->conn_timeout = 10; + res->rw_timeout = 10; + res->transfer = ACL_RES_USE_UDP; + + return (res); +} + +void acl_res_free(ACL_RES *res) +{ + if (res) + acl_myfree(res); +} + +static int udp_res_lookup(ACL_RES *res, const char *data, int dlen, char *buf, int size) +{ + const char *myname = "udp_res_lookup"; + int ret; + ACL_SOCKET fd; + struct sockaddr_in addr; + + fd = socket(PF_INET, SOCK_DGRAM, 0); + if (fd == ACL_SOCKET_INVALID) + acl_msg_fatal("%s: socket create error", myname); + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(res->dns_port); + addr.sin_addr.s_addr = inet_addr(res->dns_ip); + + ret = sendto(fd, data, dlen, 0, (struct sockaddr *) &addr, (int) sizeof(addr)); + if (ret < 0) { + acl_socket_close(fd); + res->errnum = ACL_RES_ERR_SEND; + return (-1); + } + + ret = acl_read_wait(fd, res->rw_timeout); + if (ret < 0) { + acl_socket_close(fd); + res->errnum = ACL_RES_ERR_RTMO; + return (-1); + } + + ret = recv(fd, buf, size, 0); + acl_socket_close(fd); + + if (ret <= 0) { + res->errnum = ACL_RES_ERR_SEND; + return (-1); + } + + return (ret); +} + +static int tcp_res_lookup(ACL_RES *res, const char *data, int dlen, char *buf, int size) +{ + ACL_VSTREAM *stream = NULL; + char addr[256], *pbuf = NULL, *ptr, tbuf[3]; + unsigned short nsz, n; + int ret; + +#undef RETURN +#define RETURN(_x_) do { \ + if (pbuf) \ + acl_myfree(pbuf); \ + if (stream) \ + acl_vstream_close(stream); \ + return (_x_); \ +} while (0) + + snprintf(addr, sizeof(addr), "%s:%d", res->dns_ip, res->dns_port); + stream = acl_vstream_connect(addr, ACL_BLOCKING, res->conn_timeout, + res->rw_timeout, 1024); + if (stream == NULL) { + res->errnum = ACL_RES_ERR_CONN; + RETURN (-1); + } + + pbuf = acl_mycalloc(1, dlen + 2); + nsz = htons((short) dlen); + ptr = pbuf; + memcpy(ptr, &nsz, 2); + ptr += 2; + memcpy(ptr, data, dlen); + + ret = acl_vstream_writen(stream, pbuf, dlen + 2); + if (ret == ACL_VSTREAM_EOF) { + res->errnum = ACL_RES_ERR_SEND; + RETURN (-1); + } + + memset(tbuf, 0, sizeof(tbuf)); + + ret = acl_vstream_readn(stream, &n, 2); + if (ret == ACL_VSTREAM_EOF) { + res->errnum = ACL_RES_ERR_READ; + RETURN (-1); + } + + nsz = ntohs(n); + + size = size > nsz ? nsz : size; + ret = acl_vstream_readn(stream, buf, size); + if (ret == ACL_VSTREAM_EOF) { + res->errnum = ACL_RES_ERR_READ; + RETURN (-1); + } + + RETURN (ret); +#ifdef ACL_BCB_COMPILER + return (-1); +#endif +} + +static int res_lookup(ACL_RES *res, const char *data, int dlen, + char *buf, int size) +{ + if (res->transfer == ACL_RES_USE_TCP) + return (tcp_res_lookup(res, data, dlen, buf, size)); + else + return (udp_res_lookup(res, data, dlen, buf, size)); +} + +ACL_DNS_DB *acl_res_lookup(ACL_RES *res, const char *domain) +{ + const char *myname = "acl_res_lookup"; + ACL_DNS_DB *dns_db; + char buf[1024]; + int ret, i; + rfc1035_message *answers; + ACL_HOSTNAME *phost; + time_t begin; + + if (res == NULL || domain == NULL || *domain == 0) + acl_msg_fatal("%s: input invalid", myname); + + memset(buf, 0, sizeof(buf)); + ret = rfc1035BuildAQuery(domain, buf, sizeof(buf), res->cur_qid++, NULL); + + (void) time(&begin); + ret = res_lookup(res, buf, ret, buf, sizeof(buf)); + res->tm_spent = time(NULL) - begin; + + if (ret <= 0) + return (NULL); + + ret = rfc1035MessageUnpack(buf, ret, &answers); + if (ret < 0) { + res->errnum = ret; + return (NULL); + } else if (ret == 0) { + rfc1035MessageDestroy(answers); + res->errnum = ACL_RES_ERR_NULL; + return (NULL); + } + + dns_db = acl_netdb_new(domain); + if (dns_db == NULL) { + rfc1035MessageDestroy(answers); + acl_msg_error("%s: acl_netdb_new error", myname); + return (NULL); + } + + for (i = 0; i < ret; i++) { + if (answers->answer[i].type == RFC1035_TYPE_A) { + phost = acl_mycalloc(1, sizeof(ACL_HOSTNAME)); + if (phost == NULL) { + acl_msg_error("%s: calloc error(%s)", + myname, acl_last_strerror(buf, sizeof(buf))); + acl_netdb_free(dns_db); + rfc1035MessageDestroy(answers); + return (NULL); + } + + memcpy(&phost->saddr.sin_addr, answers->answer[i].rdata, 4); + /* bugfix: 2009.12.8 + * ACL_SAFE_STRNCPY(phost->ip, inet_ntoa(phost->saddr.sin_addr), + * sizeof(phost->ip)); + */ + acl_inet_ntoa(phost->saddr.sin_addr, phost->ip, sizeof(phost->ip)); + phost->ttl = answers->answer[i].ttl; + + if (acl_array_append(dns_db->h_db, phost) < 0) { + acl_msg_error("%s, %s(%d): array append error(%s)", + __FILE__, myname, __LINE__, + acl_last_strerror(buf, sizeof(buf))); + acl_netdb_free(dns_db); + rfc1035MessageDestroy(answers); + return (NULL); + } + + dns_db->size++; + } else { + if (acl_msg_verbose) + acl_msg_error("%s: can't print answer type %d, domain %s", + myname, (int) answers->answer[i].type, domain); + } + } + + rfc1035MessageDestroy(answers); + + return (dns_db); +} + +const char *acl_res_strerror(int errnum) +{ + int i; + struct __ERRMSG { + int errnum; + const char *msg; + }; + static const struct __ERRMSG errmsg[] = { + { ACL_RES_ERR_SEND, "send msg error" }, + { ACL_RES_ERR_READ, "read msg error" }, + { ACL_RES_ERR_RTMO, "read timeout" }, + { ACL_RES_ERR_NULL, "result emplty" }, + { ACL_RES_ERR_CONN, "connect error" }, + { 0, NULL }, + }; + + for (i = 0; errmsg[i].errnum != 0; i++) { + if (errmsg[i].errnum == errnum) + return (errmsg[i].msg); + } + + return (rfc1035Strerror(errnum)); +} + +const char *acl_res_errmsg(const ACL_RES *res) +{ + const char *myname = "acl_res_errmsg"; + + if (res == NULL) + acl_msg_fatal("%s: res null", myname); + + return (acl_res_strerror(res->errnum)); +} diff --git a/lib_acl/src/net/dns/res_util.c b/lib_acl/src/net/dns/res_util.c new file mode 100644 index 000000000..f6b81557f --- /dev/null +++ b/lib_acl/src/net/dns/res_util.c @@ -0,0 +1,35 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "lib_acl.h" + +#endif + +#include "rfc1035.h" +#include "util.h" + +ACL_ARGV *res_a_create(const rfc1035_rr *answer, int n) +{ + int i; + struct in_addr sin_addr; + ACL_ARGV *a; + char ip[32]; + + if (n <= 0) + return (NULL); + + a = acl_argv_alloc(n); + + for (i = 0; i < n; i++) { + if (answer[i].type == RFC1035_TYPE_A) { + memcpy(&sin_addr, answer[i].rdata, 4); + /* bugfix: 2009.12.8 + * ACL_SAFE_STRNCPY(ip, inet_ntoa(sin_addr), sizeof(ip)); + */ + acl_inet_ntoa(sin_addr, ip, sizeof(ip)); + acl_argv_add(a, ip, NULL); + } + } + + return (a); +} diff --git a/lib_acl/src/net/dns/rfc1035.c b/lib_acl/src/net/dns/rfc1035.c new file mode 100644 index 000000000..2c8874656 --- /dev/null +++ b/lib_acl/src/net/dns/rfc1035.c @@ -0,0 +1,825 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include /* for snprintf */ + +#ifdef ACL_UNIX +#include +#include +#include +#endif + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_msg.h" +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_mystring.h" + +#endif + +#include "rfc1035.h" + +#define RFC1035_MAXLABELSZ 63 +#define rfc1035_unpack_error 15 + +#if 0 +#define RFC1035_UNPACK_DEBUG acl_msg_error("unpack error at %s:%d", __FILE__,__LINE__) +#else +#define RFC1035_UNPACK_DEBUG (void)0 +#endif + +/* +* rfc1035HeaderPack() +* +* Packs a rfc1035_header structure into a buffer. +* Returns number of octets packed (should always be 12) +*/ +static int rfc1035HeaderPack(char *buf, size_t sz, rfc1035_message * hdr) +{ + const char *myname = "rfc1035HeaderPack"; + int off = 0; + unsigned short s; + unsigned short t; + + if (sz < 12) + acl_msg_fatal("%s: sz(%d) < 12", myname, (int) sz); + + s = htons(hdr->id); + memcpy(buf + off, &s, sizeof(s)); + off += sizeof(s); + t = 0; + t |= hdr->qr << 15; + t |= (hdr->opcode << 11); + t |= (hdr->aa << 10); + t |= (hdr->tc << 9); + t |= (hdr->rd << 8); + t |= (hdr->ra << 7); + t |= hdr->rcode; + s = htons(t); + memcpy(buf + off, &s, sizeof(s)); + off += sizeof(s); + s = htons(hdr->qdcount); + memcpy(buf + off, &s, sizeof(s)); + off += sizeof(s); + s = htons(hdr->ancount); + memcpy(buf + off, &s, sizeof(s)); + off += sizeof(s); + s = htons(hdr->nscount); + memcpy(buf + off, &s, sizeof(s)); + off += sizeof(s); + s = htons(hdr->arcount); + memcpy(buf + off, &s, sizeof(s)); + off += sizeof(s); + if (off != 12) + acl_msg_fatal("%s: off(%d) != 12", myname, off); + return off; +} + +/* +* rfc1035LabelPack() +* +* Packs a label into a buffer. The format of +* a label is one octet specifying the number of character +* bytes to follow. Labels must be smaller than 64 octets. +* Returns number of octets packed. +*/ +static int rfc1035LabelPack(char *buf, size_t sz, const char *label) +{ + const char *myname = "rfc1035LabelPack"; + int off = 0; + size_t len = label ? strlen(label) : 0; + + if (label) { + if (strchr(label, '.') != NULL) + acl_msg_fatal("%s: '.' exist in label(%s)", myname, label); + } + + if (len > RFC1035_MAXLABELSZ) + len = RFC1035_MAXLABELSZ; + if (sz < len + 1) + acl_msg_fatal("%s: sz(%d) < len(%d) + 1", myname, (int) sz, (int) len); + *(buf + off) = (char) len; + off++; + memcpy(buf + off, label, len); + off += (int) len; + return off; +} + +/* +* rfc1035NamePack() +* +* Packs a name into a buffer. Names are packed as a +* sequence of labels, terminated with NULL label. +* Note message compression is not supported here. +* Returns number of octets packed. +*/ +static int rfc1035NamePack(char *buf, size_t sz, const char *name) +{ + const char *myname = "rfc1035NamePack"; + int off = 0; + char *copy, *ptr; + char *t; + + copy = acl_mystrdup(name); + /* + * NOTE: use of strtok here makes names like foo....com valid. + */ + ptr = copy; + for (t = acl_mystrtok(&ptr, "."); t; t = acl_mystrtok(&ptr, ".")) + off += rfc1035LabelPack(buf + off, sz - off, t); + acl_myfree(copy); + off += rfc1035LabelPack(buf + off, sz - off, NULL); + if (off > (int) sz) + acl_msg_fatal("%s: off(%d) > sz(%d)", myname, off, (int) sz); + return off; +} + +/* +* rfc1035QuestionPack() +* +* Packs a QUESTION section of a message. +* Returns number of octets packed. +*/ +static int rfc1035QuestionPack(char *buf, size_t sz, const char *name, + unsigned short type, unsigned short tclass) +{ + const char *myname = "rfc1035QuestionPack"; + int off = 0; + unsigned short s; + + off += rfc1035NamePack(buf + off, sz - off, name); + s = htons(type); + memcpy(buf + off, &s, sizeof(s)); + off += sizeof(s); + s = htons(tclass); + memcpy(buf + off, &s, sizeof(s)); + off += sizeof(s); + if (off > (int) sz) + acl_msg_fatal("%s: off(%d) > sz(%d)", myname, off, (int) sz); + + return off; +} + +/* +* rfc1035HeaderUnpack() +* +* Unpacks a RFC1035 message header buffer into the header fields +* of the rfc1035_message structure. +* +* Updates the buffer offset, which is the same as number of +* octects unpacked since the header starts at offset 0. +* +* Returns 0 (success) or 1 (error) +*/ +static int rfc1035HeaderUnpack(const char *buf, size_t sz, int *off, + rfc1035_message * h) +{ + const char *myname = "rfc1035HeaderUnpack"; + unsigned short s; + unsigned short t; + + if (*off != 0) + acl_msg_fatal("%s: *off(%d) != 0", myname, *off); + + /* + * The header is 12 octets. This is a bogus message if the size + * is less than that. + */ + if (sz < 12) + return 1; + memcpy(&s, buf + (*off), sizeof(s)); + (*off) += sizeof(s); + h->id = ntohs(s); + memcpy(&s, buf + (*off), sizeof(s)); + (*off) += sizeof(s); + t = ntohs(s); + h->qr = (t >> 15) & 0x01; + h->opcode = (t >> 11) & 0x0F; + h->aa = (t >> 10) & 0x01; + h->tc = (t >> 9) & 0x01; + h->rd = (t >> 8) & 0x01; + h->ra = (t >> 7) & 0x01; + /* + * We might want to check that the reserved 'Z' bits (6-4) are + * all zero as per RFC 1035. If not the message should be + * rejected. + */ + h->rcode = t & 0x0F; + memcpy(&s, buf + (*off), sizeof(s)); + (*off) += sizeof(s); + h->qdcount = ntohs(s); + memcpy(&s, buf + (*off), sizeof(s)); + (*off) += sizeof(s); + h->ancount = ntohs(s); + memcpy(&s, buf + (*off), sizeof(s)); + (*off) += sizeof(s); + h->nscount = ntohs(s); + memcpy(&s, buf + (*off), sizeof(s)); + (*off) += sizeof(s); + h->arcount = ntohs(s); + + if (*off != 12) + acl_msg_fatal("%s: *off(%d) != 12", myname, *off); + return 0; +} + +/* +* rfc1035NameUnpack() +* +* Unpacks a Name in a message buffer into a char*. +* Note 'buf' points to the beginning of the whole message, +* 'off' points to the spot where the Name begins, and 'sz' +* is the size of the whole message. 'name' must be allocated +* by the caller. +* +* Supports the RFC1035 message compression through recursion. +* +* Updates the new buffer offset. +* +* Returns 0 (success) or 1 (error) +*/ +static int rfc1035NameUnpack(const char *buf, size_t sz, int *off, + unsigned short *rdlength, char *name, size_t ns, int rdepth) +{ + const char *myname = "rfc1035NameUnpack"; + int no = 0; + unsigned char c; + size_t len; + + if (ns <= 0) + acl_msg_fatal("%s: ns(%d) <= 0", myname, (int) ns); + do { + if (*off >= (int) sz) + acl_msg_fatal("%s: *off(%d) >= sz(%d)", myname, *off, (int) sz); + c = *(buf + (*off)); + if (c > 191) { + /* blasted compression */ + unsigned short s; + int ptr; + if (rdepth > 64) /* infinite pointer loop */ + return 1; + memcpy(&s, buf + (*off), sizeof(s)); + s = ntohs(s); + (*off) += sizeof(s); + /* Sanity check */ + if ((*off) >= (int) sz) + return 1; + ptr = s & 0x3FFF; + /* Make sure the pointer is inside this message */ + if (ptr >= (int) sz) + return 1; + return rfc1035NameUnpack(buf, sz, &ptr, rdlength, name + no, + ns - no, rdepth + 1); + } else if (c > RFC1035_MAXLABELSZ) { + /* + * "(The 10 and 01 combinations are reserved for future use.)" + */ + return 1; + } else { + (*off)++; + len = (size_t) c; + if (len == 0) + break; + if (len > (ns - no - 1)) /* label won't fit */ + return 1; + if ((*off) + len >= sz) /* message is too short */ + return 1; + memcpy(name + no, buf + (*off), len); + (*off) += (int) len; + no += (int) len; + *(name + (no++)) = '.'; + if (rdlength) + *rdlength += (unsigned short) len + 1; + } + } while (c > 0 && no < (int) ns); + if (no) + *(name + no - 1) = '\0'; + else + *name = '\0'; + /* make sure we didn't allow someone to overflow the name buffer */ + if (no > (int) ns) + acl_msg_fatal("%s: no(%d) > ns(%d)", myname, no, (int) ns); + return 0; +} + +/* +* rfc1035RRUnpack() +* +* Unpacks a RFC1035 Resource Record into 'RR' from a message buffer. +* The caller must free RR->rdata! +* +* Updates the new message buffer offset. +* +* Returns 0 (success) or 1 (error) +*/ +static int rfc1035RRUnpack(const char *buf, size_t sz, int *off, rfc1035_rr * RR) +{ + const char *myname = "rfc1035RRUnpack"; + unsigned short s; + unsigned int i; + unsigned short rdlength; + int rdata_off; + + if (rfc1035NameUnpack(buf, sz, off, NULL, RR->name, RFC1035_MAXHOSTNAMESZ, 0)) { + RFC1035_UNPACK_DEBUG; + memset(RR, '\0', sizeof(*RR)); + return 1; + } + /* + * Make sure the remaining message has enough octets for the + * rest of the RR fields. + */ + if ((*off) + 10 > (int) sz) { + RFC1035_UNPACK_DEBUG; + memset(RR, '\0', sizeof(*RR)); + return 1; + } + memcpy(&s, buf + (*off), sizeof(s)); + (*off) += sizeof(s); + RR->type = ntohs(s); + memcpy(&s, buf + (*off), sizeof(s)); + (*off) += sizeof(s); + RR->tclass = ntohs(s); + memcpy(&i, buf + (*off), sizeof(i)); + (*off) += sizeof(i); + RR->ttl = ntohl(i); + memcpy(&s, buf + (*off), sizeof(s)); + (*off) += sizeof(s); + rdlength = ntohs(s); + if ((*off) + rdlength > (int) sz) { + /* + * We got a truncated packet. 'dnscache' truncates UDP + * replies at 512 octets, as per RFC 1035. + */ + RFC1035_UNPACK_DEBUG; + memset(RR, '\0', sizeof(*RR)); + return 1; + } + RR->rdlength = rdlength; + switch (RR->type) { + case RFC1035_TYPE_PTR: + RR->rdata = (char*) acl_mymalloc(RFC1035_MAXHOSTNAMESZ); + rdata_off = *off; + RR->rdlength = 0; /* Filled in by rfc1035NameUnpack */ + if (rfc1035NameUnpack(buf, sz, &rdata_off, &RR->rdlength, + RR->rdata, RFC1035_MAXHOSTNAMESZ, 0)) + return 1; + if (rdata_off > ((*off) + rdlength)) { + /* + * This probably doesn't happen for valid packets, but + * I want to make sure that NameUnpack doesn't go beyond + * the RDATA area. + */ + RFC1035_UNPACK_DEBUG; + acl_myfree(RR->rdata); + memset(RR, '\0', sizeof(*RR)); + return 1; + } + break; + case RFC1035_TYPE_A: + default: + RR->rdata = (char*) acl_mymalloc(rdlength); + memcpy(RR->rdata, buf + (*off), rdlength); + break; + } + (*off) += rdlength; + if (*off > (int) sz) + acl_msg_fatal("%s: *off(%d) > sz(%d)", myname, *off, (int) sz); + return 0; +} + +const char *rfc1035Strerror(int errnum) +{ + struct __ERRMSG{ + int errnum; + const char *msg; + }; + static const struct __ERRMSG errmsg[] = { + { 0, "No error condition" }, + { 1, "Format Error: The name server was unable to " + "interpret the query." }, + { 2, "Server Failure: The name server was " + "unable to process this query." }, + { 3, "Name Error: The domain name does not exist." }, + { 4, "Not Implemented: The name server does " + "not support the requested kind of query." }, + { 5, "Refused: The name server refuses to " + "perform the specified operation." }, + { rfc1035_unpack_error, "The DNS reply message is corrupt or could " + "not be safely parsed." }, + { -1, NULL }, + }; + const char *unknown = "Unknown Error"; + int i; + + for (i = 0; errmsg[i].msg != NULL; i++) { + if (errmsg[i].errnum == -errnum) + return (errmsg[i].msg); + } + + return (unknown); +} + +static void rfc1035SetErrno(int n) +{ + errno = n; +} + +static void rfc1035RRDestroy(rfc1035_rr * rr, int n) +{ + const char *myname = "rfc1035RRDestroy"; + + if (rr == NULL) + return; + if (n <= 0) + acl_msg_fatal("%s: n(%d) <= 0", myname, n); + while (n--) { + if (rr[n].rdata) + acl_myfree(rr[n].rdata); + } + acl_myfree(rr); +} + +/* +* rfc1035QueryUnpack() +* +* Unpacks a RFC1035 Query Record into 'query' from a message buffer. +* +* Updates the new message buffer offset. +* +* Returns 0 (success) or 1 (error) +*/ +static int rfc1035QueryUnpack(const char *buf, size_t sz, int *off, + rfc1035_query * query) +{ + unsigned short s; + + if (rfc1035NameUnpack(buf, sz, off, NULL, query->name, RFC1035_MAXHOSTNAMESZ, 0)) { + RFC1035_UNPACK_DEBUG; + memset(query, '\0', sizeof(*query)); + return 1; + } + if (*off + 4 > (int) sz) { + RFC1035_UNPACK_DEBUG; + memset(query, '\0', sizeof(*query)); + return 1; + } + memcpy(&s, buf + *off, 2); + *off += 2; + query->qtype = ntohs(s); + memcpy(&s, buf + *off, 2); + *off += 2; + query->qclass = ntohs(s); + return 0; +} + +void rfc1035MessageDestroy(rfc1035_message * msg) +{ + if (!msg) + return; + if (msg->query) + acl_myfree(msg->query); + if (msg->answer) + rfc1035RRDestroy(msg->answer, msg->ancount); + acl_myfree(msg); +} + +/* +* rfc1035QueryCompare() +* +* Compares two rfc1035_query entries +* +* Returns 0 (equal) or !=0 (different) +*/ +int rfc1035QueryCompare(const rfc1035_query * a, const rfc1035_query * b) +{ + size_t la, lb; + + if (a->qtype != b->qtype) + return 1; + if (a->qclass != b->qclass) + return 1; + la = strlen(a->name); + lb = strlen(b->name); + if (la != lb) { + /* Trim root label(s) */ + while (la > 0 && a->name[la - 1] == '.') + la--; + while (lb > 0 && b->name[lb - 1] == '.') + lb--; + } + if (la != lb) + return 1; + + return strncasecmp(a->name, b->name, la); +} + +/* +* rfc1035MessageUnpack() +* +* Takes the contents of a DNS reply and fills in an array +* of resource record structures. The records array is allocated +* here, and should be freed by calling rfc1035RRDestroy(). +* +* Returns number of records unpacked, zero if DNS reply indicates +* zero answers, or an error number < 0. +*/ + +int rfc1035MessageUnpack(const char *buf, size_t sz, rfc1035_message **answer) +{ + int off = 0; + int i; + int nr = 0; + rfc1035_message *msg; + rfc1035_rr *recs; + rfc1035_query *querys; + + *answer = NULL; + msg = (rfc1035_message*) acl_mycalloc(1, sizeof(*msg)); + if (rfc1035HeaderUnpack(buf + off, sz - off, &off, msg)) { + RFC1035_UNPACK_DEBUG; + rfc1035SetErrno(rfc1035_unpack_error); + acl_myfree(msg); + return -rfc1035_unpack_error; + } + errno = 0; + i = (int) msg->qdcount; + if (i != 1) { + /* This can not be an answer to our queries.. */ + RFC1035_UNPACK_DEBUG; + rfc1035SetErrno(rfc1035_unpack_error); + acl_myfree(msg); + return -rfc1035_unpack_error; + } + querys = msg->query = (rfc1035_query*) acl_mycalloc((int) msg->qdcount, sizeof(*querys)); + for (i = 0; i < (int) msg->qdcount; i++) { + if (rfc1035QueryUnpack(buf, sz, &off, &querys[i])) { + RFC1035_UNPACK_DEBUG; + rfc1035SetErrno(rfc1035_unpack_error); + rfc1035MessageDestroy(msg); + acl_myfree(msg->query); + acl_myfree(msg); + return -rfc1035_unpack_error; + } + } + *answer = msg; + if (msg->rcode) { + RFC1035_UNPACK_DEBUG; + rfc1035SetErrno((int) msg->rcode); + return -((int) msg->rcode); + } + if (msg->ancount == 0) + return 0; + recs = msg->answer = (rfc1035_rr*) acl_mycalloc((int) msg->ancount, sizeof(*recs)); + for (i = 0; i < (int) msg->ancount; i++) { + if (off >= (int) sz) { /* corrupt packet */ + RFC1035_UNPACK_DEBUG; + break; + } + if (rfc1035RRUnpack(buf, sz, &off, &recs[i])) { /* corrupt RR */ + RFC1035_UNPACK_DEBUG; + break; + } + nr++; + } + if (nr == 0) { + /* + * we expected to unpack some answers (ancount != 0), but + * didn't actually get any. + */ + rfc1035MessageDestroy(msg); + acl_myfree(msg->query); + acl_myfree(msg); + *answer = NULL; + rfc1035SetErrno(rfc1035_unpack_error); + return -rfc1035_unpack_error; + } + + if (msg->nscount > 0) { + /* rfc1035NSUnpack(buf, sz, &off); */ + } + + if (msg->arcount > 0) { + /* rfc1035ARUnpack(buf, sz, &off); */ + } + return nr; +} + +/* +* rfc1035RRPack() +* +* Unpacks a RFC1035 Resource Record into 'RR' from a message buffer. +* The caller must free RR->rdata! +* +* Updates the new message buffer offset. +* +* Returns > 0 (success) or 0 (error) +*/ +static int rfc1035RRPack(const rfc1035_rr *RR, char *buf, size_t sz) +{ + const char *myname = "rfc1035RRPack"; + unsigned short s; + unsigned int i; + int off = 0, off_saved; + + off = rfc1035NamePack(buf + off, sz, RR->name); + s = htons(RR->type); + memcpy(buf + off, &s,sizeof(s)); + off += sizeof(s); + + s = htons(RR->tclass); + memcpy(buf + off, &s ,sizeof(s)); + off += sizeof(s); + + i = htonl(RR->ttl); + memcpy(buf + off, &i ,sizeof(i)); + off += sizeof(i); + + switch (RR->type) { + case RFC1035_TYPE_PTR: + case RFC1035_TYPE_NS: + if (strlen(RR->rdata) > RFC1035_MAXHOSTNAMESZ) + return (0); + off_saved = off; + off += sizeof(s); + off += rfc1035NamePack(buf + off, sz, RR->rdata); + s = off - off_saved - (unsigned short) sizeof(s); + s = htons(s); + memcpy(buf + off_saved, &s ,sizeof(s)); + break; + default: + s = htons(RR->rdlength); + memcpy(buf + off, &s ,sizeof(s)); + off += sizeof(s); + memcpy(buf + off, RR->rdata, RR->rdlength); + off += RR->rdlength; + break; + } + + if ((unsigned) off > sz) + acl_msg_fatal("%s: off(%d) > sz(%d)", myname, off, (int) sz); + + return (off); +} + +ssize_t rfc1035BuildAReply(const char *hostname, const ACL_ARGV *ip_argv, + const char *domain_root, const char *dnsname, const char *dns_ip, + unsigned short qid, char *buf, size_t sz) +{ + rfc1035_message h; + rfc1035_rr rr; + size_t offset = 0; + unsigned int nip; + int i; + + memset(&h, '\0', sizeof(h)); + h.id = qid; + h.qr = 1; + h.opcode = 0; /* QUERY */ + h.aa = 0; + h.tc = 0; + h.rd = 1; + h.ra = 0; + h.rcode = 0; + h.qdcount = 1; + h.ancount = ip_argv->argc; + h.nscount = (dnsname && *dnsname) ? 1 : 0; + h.arcount = (h.nscount && dns_ip && *dns_ip) ? 1 : 0; + offset += rfc1035HeaderPack(buf + offset, sz - offset, &h); + offset += rfc1035QuestionPack(buf + offset, sz - offset, hostname, + RFC1035_TYPE_A, RFC1035_CLASS_IN); + + for (i = 0; i < ip_argv->argc; i++) { + memset(&rr, 0, sizeof(rr)); + snprintf(rr.name, sizeof(rr.name), "%s", hostname); + rr.type = RFC1035_TYPE_A; + rr.tclass = RFC1035_CLASS_IN; + rr.ttl = 600; + rr.rdlength = 4; + nip = inet_addr(ip_argv->argv[i]); + rr.rdata = (char*) acl_mycalloc(1, rr.rdlength); + memcpy(rr.rdata, &nip, rr.rdlength); + offset += rfc1035RRPack(&rr, buf + offset, sz - offset); + acl_myfree(rr.rdata); + } + + if (h.nscount) { + memset(&rr, 0, sizeof(rr)); + snprintf(rr.name, sizeof(rr.name), "%s", domain_root); + rr.type = RFC1035_TYPE_NS; + rr.tclass = RFC1035_CLASS_IN; + rr.ttl = 600; + rr.rdlength = (unsigned short) strlen(dnsname); + rr.rdata = acl_mystrdup(dnsname); + offset += rfc1035RRPack(&rr, buf + offset, sz - offset); + acl_myfree(rr.rdata); + } + + if (h.arcount) { + memset(&rr, 0, sizeof(rr)); + snprintf(rr.name, sizeof(rr.name), "%s", dnsname); + rr.type = RFC1035_TYPE_A; + rr.tclass = RFC1035_CLASS_IN; + rr.ttl = 600; + nip = inet_addr(dns_ip); + rr.rdlength = 4; + rr.rdata = (char*) acl_mycalloc(1, rr.rdlength); + memcpy(rr.rdata, &nip, rr.rdlength); + offset += rfc1035RRPack(&rr, buf + offset, sz - offset); + acl_myfree(rr.rdata); + } + + return ((int) offset); +} +/* +* rfc1035BuildAQuery() +* +* Builds a message buffer with a QUESTION to lookup A records +* for a hostname. Caller must allocate 'buf' which should +* probably be at least 512 octets. The 'szp' initially +* specifies the size of the buffer, on return it contains +* the size of the message (i.e. how much to write). +* Returns the size of the query +*/ +ssize_t rfc1035BuildAQuery(const char *hostname, char *buf, size_t sz, + unsigned short qid, rfc1035_query * query) +{ + const char *myname = "rfc1035BuildAQuery"; + rfc1035_message h; + size_t offset = 0; + + memset(&h, '\0', sizeof(h)); + h.id = qid; + h.qr = 0; + h.rd = 1; + h.opcode = 0; /* QUERY */ + h.qdcount = (unsigned int) 1; + offset += rfc1035HeaderPack(buf + offset, sz - offset, &h); + offset += rfc1035QuestionPack(buf + offset, sz - offset, hostname, + RFC1035_TYPE_A, RFC1035_CLASS_IN); + if (query) { + query->qtype = RFC1035_TYPE_A; + query->qclass = RFC1035_CLASS_IN; + ACL_SAFE_STRNCPY(query->name, hostname, sizeof(query->name)); + } + + if (offset > sz) + acl_msg_fatal("%s: offset(%d) > sz(%d)", myname, (int) offset, (int) sz); + return (ssize_t) offset; +} + +/* +* rfc1035BuildPTRQuery() +* +* Builds a message buffer with a QUESTION to lookup PTR records +* for an address. Caller must allocate 'buf' which should +* probably be at least 512 octets. The 'szp' initially +* specifies the size of the buffer, on return it contains +* the size of the message (i.e. how much to write). +* Returns the size of the query +*/ +ssize_t rfc1035BuildPTRQuery(const struct in_addr addr, char *buf, + size_t sz, unsigned short qid, rfc1035_query * query) +{ + const char *myname = "rfc1035BuildPTRQuery"; + rfc1035_message h; + size_t offset = 0; + static char rev[32]; + unsigned int i; + + memset(&h, '\0', sizeof(h)); + i = (unsigned int) ntohl(addr.s_addr); + snprintf(rev, 32, "%u.%u.%u.%u.in-addr.arpa.", + i & 255, (i >> 8) & 255, (i >> 16) & 255, (i >> 24) & 255); + h.id = qid; + h.qr = 0; + h.rd = 1; + h.opcode = 0; /* QUERY */ + h.qdcount = (unsigned int) 1; + offset += rfc1035HeaderPack(buf + offset, sz - offset, &h); + offset += rfc1035QuestionPack(buf + offset, sz - offset, rev, + RFC1035_TYPE_PTR, RFC1035_CLASS_IN); + if (query) { + query->qtype = RFC1035_TYPE_PTR; + query->qclass = RFC1035_CLASS_IN; + ACL_SAFE_STRNCPY(query->name, rev, sizeof(query->name)); + } + if (offset > sz) + acl_msg_fatal("%s: offset(%d) > sz(%d)", myname, (int) offset, (int) sz); + return (ssize_t) offset; +} + +/* +* We're going to retry a former query, but we +* just need a new ID for it. Lucky for us ID +* is the first field in the message buffer. +*/ +void rfc1035SetQueryID(char *buf, unsigned short qid) +{ + unsigned short s = htons(qid); + memcpy(buf, &s, sizeof(s)); +} diff --git a/lib_acl/src/net/dns/rfc1035.h b/lib_acl/src/net/dns/rfc1035.h new file mode 100644 index 000000000..5b65738cf --- /dev/null +++ b/lib_acl/src/net/dns/rfc1035.h @@ -0,0 +1,75 @@ +#ifndef __MY_RFC1035_INCLUDE_H__ +#define __MY_RFC1035_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_define.h" +#include "stdlib/acl_argv.h" +#ifdef ACL_UNIX +#include +#endif + +/* rfc1035 - DNS */ +#define RFC1035_MAXHOSTNAMESZ 256 + +typedef struct rfc1035_rr { + char name[RFC1035_MAXHOSTNAMESZ]; + unsigned short type; + unsigned short tclass; /* class */ + unsigned int ttl; + unsigned short rdlength; + char *rdata; +} rfc1035_rr; + +typedef struct rfc1035_query { + char name[RFC1035_MAXHOSTNAMESZ]; + unsigned short qtype; + unsigned short qclass; +} rfc1035_query; + +typedef struct rfc1035_message { + unsigned short id; + unsigned int qr:1; + unsigned int opcode:4; + unsigned int aa:1; + unsigned int tc:1; + unsigned int rd:1; + unsigned int ra:1; + unsigned int rcode:4; + unsigned short qdcount; + unsigned short ancount; + unsigned short nscount; + unsigned short arcount; + rfc1035_query *query; + rfc1035_rr *answer; +} rfc1035_message; + +const char *rfc1035Strerror(int errnum); +ssize_t rfc1035BuildAQuery(const char *hostname, char *buf, size_t sz, + unsigned short qid, rfc1035_query * query); +ssize_t rfc1035BuildPTRQuery(const struct in_addr, char *buf, size_t sz, + unsigned short qid, rfc1035_query * query); +void rfc1035SetQueryID(char *, unsigned short qid); +int rfc1035MessageUnpack(const char *buf, size_t sz, + rfc1035_message ** answer); +int rfc1035QueryCompare(const rfc1035_query *, const rfc1035_query *); +void rfc1035MessageDestroy(rfc1035_message * message); +ssize_t rfc1035BuildAReply(const char *hostname, const ACL_ARGV *ip_argv, + const char *domain_root, const char *dnsname, const char *dns_ip, + unsigned short qid, char *buf, size_t sz); + +#define RFC1035_TYPE_A 1 +#define RFC1035_TYPE_NS 2 +#define RFC1035_TYPE_CNAME 5 +#define RFC1035_TYPE_PTR 12 +#define RFC1035_TYPE_AAAA 28 +#define RFC1035_CLASS_IN 1 + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/src/net/dns/util.h b/lib_acl/src/net/dns/util.h new file mode 100644 index 000000000..fceca9b1c --- /dev/null +++ b/lib_acl/src/net/dns/util.h @@ -0,0 +1,15 @@ +#ifndef __DGATE_UTIL_INCLUDE_H__ +#define __DGATE_UTIL_INCLUDE_H__ + +#include "lib_acl.h" +#ifdef __cplusplus +extern "C" { +#endif + +ACL_ARGV *res_a_create(const rfc1035_rr *answer, int n); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/src/net/listen/acl_fifo_listen.c b/lib_acl/src/net/listen/acl_fifo_listen.c new file mode 100644 index 000000000..5c6d77f3f --- /dev/null +++ b/lib_acl/src/net/listen/acl_fifo_listen.c @@ -0,0 +1,101 @@ +/* System interfaces. */ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#endif + +#ifdef ACL_UNIX + +#include +#include +#include +#include +#include + +/* Utility library. */ + +#include "stdlib/acl_msg.h" +#include "stdlib/acl_iostuff.h" +#include "net/acl_listen.h" + +#define BUF_LEN 100 + +/* acl_fifo_listen - create fifo listener */ + +int acl_fifo_listen(const char *path, int permissions, int block_mode) +{ + char *myname = "acl_fifo_listen"; + char buf[BUF_LEN], tbuf[256]; + static int open_mode = 0; + struct stat st; + int fd; + int count; + + /* + * Create a named pipe (fifo). Do whatever we can so we don't run into + * trouble when this process is restarted after crash. Make sure that we + * open a fifo and not something else, then change permissions to what we + * wanted them to be, because mkfifo() is subject to umask settings. + * Instead we could zero the umask temporarily before creating the FIFO, + * but that would cost even more system calls. Figure out if the fifo + * needs to be opened O_RDWR or O_RDONLY. Some systems need one, some + * need the other. If we choose the wrong mode, the fifo will stay + * readable, causing the program to go into a loop. + */ + if (unlink(path) && acl_last_error() != ENOENT) { + acl_msg_fatal("%s: remove %s: %s", myname, path, + acl_last_strerror(tbuf, sizeof(tbuf))); + } + if (mkfifo(path, permissions) < 0) { + acl_msg_fatal("%s: create fifo %s: %s", myname, path, + acl_last_strerror(tbuf, sizeof(tbuf))); + } + switch (open_mode) { + case 0: + if ((fd = open(path, O_RDWR | O_NONBLOCK, 0)) < 0) + acl_msg_fatal("%s: open %s: %s", myname, path, + acl_last_strerror(tbuf, sizeof(tbuf))); + if (acl_readable(fd) == 0) { + open_mode = O_RDWR | O_NONBLOCK; + break; + } else { + open_mode = O_RDONLY | O_NONBLOCK; + if (acl_msg_verbose) + acl_msg_info("open O_RDWR makes fifo readable" + " - trying O_RDONLY"); + (void) close(fd); + /* FALLTRHOUGH */ + } + default: + if ((fd = open(path, open_mode, 0)) < 0) + acl_msg_fatal("%s: open %s: %s", myname, path, + acl_last_strerror(tbuf, sizeof(tbuf))); + break; + } + + /* + * Make sure we opened a FIFO and skip any cruft that might have + * accumulated before we opened it. + */ + if (fstat(fd, &st) < 0) + acl_msg_fatal("%s: fstat %s: %s", myname, path, + acl_last_strerror(tbuf, sizeof(tbuf))); + if (S_ISFIFO(st.st_mode) == 0) + acl_msg_fatal("%s: not a fifo: %s", myname, path); + if (fchmod(fd, permissions) < 0) + acl_msg_fatal("%s: fchmod %s: %s", myname, path, + acl_last_strerror(tbuf, sizeof(tbuf))); + acl_non_blocking(fd, block_mode); + while ((count = acl_peekfd(fd)) > 0 + && read(fd, buf, BUF_LEN < count ? BUF_LEN : count) > 0) + /* void */ ; + return (fd); +} +#endif /* ACL_UNIX */ + diff --git a/lib_acl/src/net/listen/acl_inet_listen.c b/lib_acl/src/net/listen/acl_inet_listen.c new file mode 100644 index 000000000..5a6fe924e --- /dev/null +++ b/lib_acl/src/net/listen/acl_inet_listen.c @@ -0,0 +1,149 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#include +#include +#include + +#ifdef ACL_UNIX +#include +#include +#include +#include +#include +#include +#include +#endif + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_sys_patch.h" +#include "stdlib/acl_msg.h" +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_argv.h" +#include "stdlib/acl_iostuff.h" +#include "net/acl_sane_inet.h" +#include "net/acl_host_port.h" +#include "net/acl_listen.h" + +#endif + +/* acl_inet_listen - create TCP listener */ + +ACL_SOCKET acl_inet_listen(const char *addr, int backlog, int block_mode) +{ + const char *myname = "acl_inet_listen"; + ACL_SOCKET sock; + int on, nport; + char *buf, *host = NULL, *sport = NULL; + const char *ptr; + struct sockaddr_in sa; + char tbuf[256]; + + /* + * Translate address information to internal form. + */ + buf = acl_mystrdup(addr); + ptr = acl_host_port(buf, &host, "", &sport, (char *) 0); + if (ptr) { + acl_msg_error("%s(%d): %s, %s invalid", myname, __LINE__, addr, ptr); + acl_myfree(buf); + return (ACL_SOCKET_INVALID); + } + + if (host && *host == 0) + host = 0; + if (host == NULL) + host = "0.0.0.0"; + + if (sport == NULL) { + acl_msg_error("%s(%d): no port given from addr(%s)", myname, __LINE__, addr); + acl_myfree(buf); + return (ACL_SOCKET_INVALID); + } + nport = atoi(sport); + if (nport < 0) { + acl_msg_error("%s: port(%d) < 0 invalid from addr(%s)", + myname, nport, addr); + acl_myfree(buf); + return (ACL_SOCKET_INVALID); + } + + memset(&sa, 0, sizeof(sa)); + sa.sin_family = AF_INET; + sa.sin_port = htons((short) nport); + sa.sin_addr.s_addr = inet_addr(host); + + acl_myfree(buf); + + /* Create a listener socket. */ + sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock == ACL_SOCKET_INVALID) { + acl_msg_error("%s: socket %s", myname, acl_last_strerror(tbuf, sizeof(tbuf))); + return (ACL_SOCKET_INVALID); + } + + on = 1; + if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on)) < 0) + acl_msg_error("%s: setsockopt(SO_REUSEADDR): %s", + myname, acl_last_strerror(tbuf, sizeof(tbuf))); + + if (bind(sock, (struct sockaddr *) &sa, sizeof(struct sockaddr)) < 0) { + acl_msg_error("%s: bind %s port %d: %s", + myname, host, nport, acl_last_strerror(tbuf, sizeof(tbuf))); + acl_socket_close(sock); + return (ACL_SOCKET_INVALID); + } + + acl_non_blocking(sock, block_mode); + + if (listen(sock, backlog) < 0) { + acl_msg_error("%s: listen error: %s, addr(%s)", + myname, acl_last_strerror(tbuf, sizeof(tbuf)), addr); + acl_socket_close(sock); + return (ACL_SOCKET_INVALID); + } + + return (sock); +} + +ACL_SOCKET acl_inet_accept(ACL_SOCKET listen_fd) +{ + return (acl_inet_accept_ex(listen_fd, NULL, 0)); +} + +ACL_SOCKET acl_inet_accept_ex(ACL_SOCKET listen_fd, char *ipbuf, size_t size) +{ + struct sockaddr_in client_addr; + socklen_t addr_len; + ACL_SOCKET fd; + + memset(&client_addr, 0, sizeof(client_addr)); + addr_len = sizeof(client_addr); + + /* when client_addr not null and protocol is AF_INET, acl_sane_accept + * will set nodelay on the accepted socket, 2008.9.4, zsx + */ + fd = acl_sane_accept(listen_fd, (struct sockaddr *)&client_addr, &addr_len); + if (fd == ACL_SOCKET_INVALID) + return fd; + if (ipbuf != NULL && size > 0) { + size_t n; + + if (acl_inet_ntoa(client_addr.sin_addr, ipbuf, size) == NULL) + return fd; + n = strlen(ipbuf); + if (n >= size) + return fd; + + snprintf(ipbuf + n, size - n, ":%u", + (unsigned short) ntohs(client_addr.sin_port)); + ipbuf[size - 1] = 0; + } + + return fd; +} diff --git a/lib_acl/src/net/listen/acl_sane_accept.c b/lib_acl/src/net/listen/acl_sane_accept.c new file mode 100644 index 000000000..fcb692fbd --- /dev/null +++ b/lib_acl/src/net/listen/acl_sane_accept.c @@ -0,0 +1,157 @@ +/* System library. */ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#ifdef HP_UX +#define _XOPEN_SOURCE +#define _XOPEN_SOURCE_EXTENDED 1 +#endif + +#include +#include +#include + +#ifdef ACL_UNIX +#include +#include +#include +#endif + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +/* Utility library. */ + +#include "stdlib/acl_msg.h" +#include "net/acl_tcp_ctl.h" +#include "net/acl_sane_inet.h" +#include "net/acl_listen.h" + +#endif + +/* acl_sane_accept - sanitize accept() error returns */ + +ACL_SOCKET acl_sane_accept(ACL_SOCKET sock, struct sockaddr * sa, socklen_t *len) +{ + static int accept_ok_errors[] = { +#ifdef ACL_UNIX + ACL_EAGAIN, +#endif + ACL_ECONNREFUSED, + ACL_ECONNRESET, + ACL_EHOSTDOWN, + ACL_EHOSTUNREACH, + ACL_EINTR, + ACL_ENETDOWN, + ACL_ENETUNREACH, + ACL_ENOTCONN, + ACL_EWOULDBLOCK, + ACL_ENOBUFS, /* HPUX11 */ + ACL_ECONNABORTED, + 0, + }; + ACL_SOCKET fd; + + /* + * XXX Solaris 2.4 accept() returns EPIPE when a UNIX-domain client + * has disconnected in the mean time. From then on, UNIX-domain + * sockets are hosed beyond recovery. There is no point treating + * this as a beneficial error result because the program would go + * into a tight loop. + * XXX LINUX < 2.1 accept() wakes up before the three-way handshake is + * complete, so it can fail with ECONNRESET and other "false alarm" + * indications. + * + * XXX FreeBSD 4.2-STABLE accept() returns ECONNABORTED when a + * UNIX-domain client has disconnected in the mean time. The data + * that was sent with connect() write() close() is lost, even though + * the write() and close() reported successful completion. + * This was fixed shortly before FreeBSD 4.3. + * + * XXX HP-UX 11 returns ENOBUFS when the client has disconnected in + * the mean time. + */ + fd = accept(sock, (struct sockaddr *) sa, (socklen_t *) len); + if (fd == ACL_SOCKET_INVALID) { + int count = 0, err, error = acl_last_error(); + for (; (err = accept_ok_errors[count]) != 0; count++) { + if (error == err) { + acl_set_error(ACL_EAGAIN); + break; + } + } + } + + /* + * XXX Solaris select() produces false read events, so that read() + * blocks forever on a blocking socket, and fails with EAGAIN on + * a non-blocking socket. Turning on keepalives will fix a blocking + * socket provided that the kernel's keepalive timer expires before + * the Postfix watchdog timer. + */ + else if (sa != 0 && sa->sa_family == AF_INET) { + int on = 1; + + /* default set client to nodelay --- add by zsx, 2008.9.4 */ + acl_tcp_nodelay(fd, on); + +#if defined(BROKEN_READ_SELECT_ON_TCP_SOCKET) && defined(SO_KEEPALIVE) + (void) setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, + (char *) &on, sizeof(on)); +#endif + } + return (fd); +} + +ACL_SOCKET acl_accept(ACL_SOCKET sock, char *buf, size_t size, int* sock_type) +{ +#ifdef WIN32 + struct { + union { + struct sockaddr_in in; + } sa; + } addr; +#else + struct { + union { + struct sockaddr_in in; + struct sockaddr_un un; + struct sockaddr sa; + } sa; + } addr; +#endif + socklen_t len = sizeof(addr); + struct sockaddr *sa = (struct sockaddr*) &addr; + ACL_SOCKET fd; + + memset(&addr, 0, sizeof(addr)); + fd = acl_sane_accept(sock, sa, &len); + if (fd == ACL_SOCKET_INVALID) + return fd; + + if (sock_type != NULL) + *sock_type = sa->sa_family; + + if (buf != NULL && size > 0) { + size_t n; +#ifndef WIN32 + if (sa->sa_family == AF_UNIX) + snprintf(buf, size, "%s", addr.sa.un.sun_path); +#endif + if (sa->sa_family != AF_INET) + return fd; + if (acl_inet_ntoa(addr.sa.in.sin_addr, buf, size) == NULL) + return fd; + n = strlen(buf); + if (n >= size) + return fd; + + snprintf(buf + n, size - n, ":%u", + (unsigned short) ntohs(addr.sa.in.sin_port)); + buf[size - 1] = 0; + } + + return fd; +} diff --git a/lib_acl/src/net/listen/acl_unix_listen.c b/lib_acl/src/net/listen/acl_unix_listen.c new file mode 100644 index 000000000..58b35b088 --- /dev/null +++ b/lib_acl/src/net/listen/acl_unix_listen.c @@ -0,0 +1,85 @@ +/* System interfaces. */ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#endif + +#ifdef ACL_UNIX +#include +#include +#include +#include +#include + +#include +#include + +/* Utility library. */ + +#include "stdlib/acl_msg.h" +#include "stdlib/acl_iostuff.h" +#include "net/acl_sane_inet.h" +#include "net/acl_listen.h" + +/* acl_unix_listen - create UNIX-domain listener */ + +ACL_SOCKET acl_unix_listen(const char *addr, int backlog, int block_mode) +{ +#undef sun + struct sockaddr_un sun; + int len = strlen(addr); + ACL_SOCKET sock; + char tbuf[256]; + + /* + * Translate address information to internal form. + */ + if (len >= (int) sizeof(sun.sun_path)) + acl_msg_fatal("unix-domain name too long: %s", addr); + memset((char *) &sun, 0, sizeof(sun)); + sun.sun_family = AF_UNIX; +#ifdef HAS_SUN_LEN + sun.sun_len = len + 1; +#endif + memcpy(sun.sun_path, addr, len + 1); + + /* + * Create a listener socket. Do whatever we can so we don't run into + * trouble when this process is restarted after crash. + */ + if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == ACL_SOCKET_INVALID) + acl_msg_fatal("socket: %s", acl_last_strerror(tbuf, sizeof(tbuf))); + (void) unlink(addr); + + if (bind(sock, (struct sockaddr *) & sun, sizeof(sun)) < 0) + acl_msg_fatal("bind: %s: %s", addr, acl_last_strerror(tbuf, sizeof(tbuf))); +#ifdef FCHMOD_UNIX_SOCKETS + if (fchmod(sock, 0666) < 0) + acl_msg_fatal("fchmod socket %s: %s", addr, + acl_last_strerror(tbuf, sizeof(tbuf))); +#else + if (chmod(addr, 0666) < 0) + acl_msg_fatal("chmod socket %s: %s", addr, + acl_last_strerror(tbuf, sizeof(tbuf))); +#endif + acl_non_blocking(sock, block_mode); + if (listen(sock, backlog) < 0) + acl_msg_fatal("listen: %s", acl_last_strerror(tbuf, sizeof(tbuf))); + return (sock); +} + +/* acl_unix_accept - accept connection */ + +ACL_SOCKET acl_unix_accept(ACL_SOCKET fd) +{ + return (acl_sane_accept(fd, (struct sockaddr *) 0, (socklen_t *) 0)); +} + +#endif + diff --git a/lib_acl/src/private/bak/binhash.c b/lib_acl/src/private/bak/binhash.c new file mode 100644 index 000000000..d9b9b2628 --- /dev/null +++ b/lib_acl/src/private/bak/binhash.c @@ -0,0 +1,264 @@ +/* C library */ + +#include "stdlib/acl_define.h" + +#include + +#ifdef BCB_COMPILER +#pragma hdrstop +#endif + +/* Local stuff */ + +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_msg.h" +#include "stdlib/acl_slice.h" +#include "binhash.h" + +/** + * Structure of one hash table. + */ +struct BINHASH { + int size; /**< length of entries array */ + int used; /**< number of entries in table */ + BINHASH_INFO **data; /**< entries array, auto-resized */ + unsigned int flag; + ACL_SLICE *slice; +}; + +/* binhash_hash - hash a string */ + +static unsigned binhash_hash(const char *key, int len, unsigned size) +{ + unsigned long h = 0; + unsigned long g; + + /* + * From the "Dragon" book by Aho, Sethi and Ullman. + */ + + while (len-- > 0) { + h = (h << 4) + *key++; + if ((g = (h & 0xf0000000)) != 0) { + h ^= (g >> 24); + h ^= g; + } + } + return (h % size); +} + +/* binhash_link - insert element into table */ + +#define binhash_link(table, elm) { \ + BINHASH_INFO **_h = table->data + binhash_hash(elm->key.c_key, elm->key_len, table->size);\ + elm->prev = 0; \ + if ((elm->next = *_h) != 0) \ + (*_h)->prev = elm; \ + *_h = elm; \ + table->used++; \ +} + +/* binhash_size - allocate and initialize hash table */ + +static void binhash_size(BINHASH *table, unsigned size) +{ + BINHASH_INFO **h; + + size |= 1; + + table->data = h = (BINHASH_INFO **) acl_mymalloc(size * sizeof(BINHASH_INFO *)); + table->size = size; + table->used = 0; + + while (size-- > 0) + *h++ = 0; +} + +/* binhash_create - create initial hash table */ + +BINHASH *binhash_create(int size, unsigned int flag, int slice_type) +{ + BINHASH *table; + + table = (BINHASH *) acl_mycalloc(1, sizeof(BINHASH)); + binhash_size(table, size < 13 ? 13 : size); + table->flag = flag; + if (slice_type) + table->slice = acl_slice_create("binhash", 0, + sizeof(BINHASH_INFO), slice_type); + return (table); +} + +/* binhash_grow - extend existing table */ + +static void binhash_grow(BINHASH *table) +{ + BINHASH_INFO *ht; + BINHASH_INFO *next; + unsigned old_size = table->size; + BINHASH_INFO **h = table->data; + BINHASH_INFO **old_entries = h; + + binhash_size(table, 2 * old_size); + + while (old_size-- > 0) { + for (ht = *h++; ht; ht = next) { + next = ht->next; + binhash_link(table, ht); + } + } + acl_myfree(old_entries); +} + +/* binhash_enter - enter (key, value) pair */ + +BINHASH_INFO *binhash_enter(BINHASH *table, const char *key, int key_len, char *value) +{ + BINHASH_INFO *ht; + + if (table->used >= table->size) + binhash_grow(table); + if (table->slice) + ht = (BINHASH_INFO*) acl_slice_alloc(table->slice); + else + ht = (BINHASH_INFO *) acl_mymalloc(sizeof(BINHASH_INFO)); + if (table->flag & KEY_REUSE) + ht->key.c_key = key; + else + ht->key.key = acl_mymemdup(key, key_len); + ht->key_len = key_len; + ht->value = value; + binhash_link(table, ht); + return (ht); +} + +/* binhash_find - lookup value */ + +char *binhash_find(BINHASH *table, const char *key, int key_len) +{ + BINHASH_INFO *ht; + +#define KEY_EQ(x,y,l) (x[0] == y[0] && memcmp(x,y,l) == 0) + + if (table != 0) + for (ht = table->data[binhash_hash(key, key_len, table->size)]; ht; ht = ht->next) + if (key_len == ht->key_len && KEY_EQ(key, ht->key.c_key, key_len)) + return (ht->value); + return (0); +} + +/* binhash_locate - lookup entry */ + +BINHASH_INFO *binhash_locate(BINHASH *table, const char *key, int key_len) +{ + BINHASH_INFO *ht; + +#define KEY_EQ(x,y,l) (x[0] == y[0] && memcmp(x,y,l) == 0) + + if (table != 0) + for (ht = table->data[binhash_hash(key, key_len, table->size)]; ht; ht = ht->next) + if (key_len == ht->key_len && KEY_EQ(key, ht->key.c_key, key_len)) + return (ht); + return (0); +} + +/* binhash_delete - delete one entry */ + +void binhash_delete(BINHASH *table, const char *key, int key_len, void (*free_fn) (char *)) +{ + if (table != 0) { + BINHASH_INFO *ht; + BINHASH_INFO **h = table->data + binhash_hash(key, key_len, table->size); + +#define KEY_EQ(x,y,l) (x[0] == y[0] && memcmp(x,y,l) == 0) + + for (ht = *h; ht; ht = ht->next) { + if (key_len == ht->key_len && KEY_EQ(key, ht->key.c_key, key_len)) { + if (ht->next) + ht->next->prev = ht->prev; + if (ht->prev) + ht->prev->next = ht->next; + else + *h = ht->next; + table->used--; + if (free_fn) + (*free_fn) (ht->value); + if (!(table->flag & KEY_REUSE)) + acl_myfree(ht->key.key); + if (table->slice) + acl_slice_free(table->slice, ht); + else + acl_myfree(ht); + return; + } + } + acl_msg_warn("binhash_delete: unknown_key: \"%s\"", key); + } +} + +/* binhash_free - destroy hash table */ + +void binhash_free(BINHASH *table, void (*free_fn) (char *)) +{ + if (table != 0) { + unsigned i = table->size; + BINHASH_INFO *ht; + BINHASH_INFO *next; + BINHASH_INFO **h = table->data; + + while (i-- > 0) { + for (ht = *h++; ht; ht = next) { + next = ht->next; + if (!(table->flag & KEY_REUSE)) + acl_myfree(ht->key.key); + if (free_fn) + (*free_fn) (ht->value); + if (table->slice) + acl_slice_free(table->slice, ht); + else + acl_myfree(ht); + } + } + acl_myfree(table->data); + if (table->slice) + acl_slice_destroy(table->slice); + acl_myfree(table); + } +} + +/* binhash_walk - iterate over hash table */ + +void binhash_walk(BINHASH *table, void (*action) (BINHASH_INFO *, char *), + char *ptr) { + if (table != 0) { + unsigned i = table->size; + BINHASH_INFO **h = table->data; + BINHASH_INFO *ht; + + while (i-- > 0) + for (ht = *h++; ht; ht = ht->next) + (*action) (ht, ptr); + } +} + +/* binhash_list - list all table members */ + +BINHASH_INFO **binhash_list(BINHASH *table) +{ + BINHASH_INFO **list; + BINHASH_INFO *member; + int count = 0; + int i; + + if (table != 0) { + list = (BINHASH_INFO **) acl_mymalloc(sizeof(*list) * (table->used + 1)); + for (i = 0; i < table->size; i++) + for (member = table->data[i]; member != 0; member = member->next) + list[count++] = member; + } else { + list = (BINHASH_INFO **) acl_mymalloc(sizeof(*list)); + } + list[count] = 0; + return (list); +} + diff --git a/lib_acl/src/private/bak/binhash.h b/lib_acl/src/private/bak/binhash.h new file mode 100644 index 000000000..6d642b952 --- /dev/null +++ b/lib_acl/src/private/bak/binhash.h @@ -0,0 +1,105 @@ +#ifndef __BINHASH_H_INCLUDED_H__ +#define __BINHASH_H_INCLUDED_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "private.h" + +typedef struct BINHASH BINHASH; + +/** + * Structure of one hash table entry. + */ +#ifdef PACK_STRUCT +#pragma pack(4) +#endif +typedef struct BINHASH_INFO { + union { + char *key; + const char *c_key; + } key; /**< lookup key */ + int key_len; /**< key length */ + char *value; /**< associated value */ + struct BINHASH_INFO *next; /**< colliding entry */ + struct BINHASH_INFO *prev; /**< colliding entry */ +} BINHASH_INFO; +#ifdef PACK_STRUCT +#pragma pack(0) +#endif + +/** + * 创建一个哈希表 + * @param size {int} 哈希表的初始化大小 + * @param flag {unsigned int} 与 ACL_MDT_IDX 中的 flag 相同 + * @return {BINHASH*} 新创建的哈希表指针 + */ +BINHASH *binhash_create(int size, unsigned int flag, int use_slice); + +/** + * 向哈希表中添加对象 + * @param table {BINHASH*} 哈希表指针 + * @param key {const char*} 哈希键 + * @param key_len {int} key 的长度 + * @param value {char*} 键值 + * @return {BINHASH_INFO*} 新创建的哈希条目指针 + */ +BINHASH_INFO *binhash_enter(BINHASH *table, const char *key, int key_len, char *value); + +/** + * 从哈希表中根据键名取得对应的哈希条目 + * @param table {BINHASH*} 哈希表指针 + * @param key {const char*} 哈希键 + * @param key_len {int} key 的长度 + * @return {BINHASH_INFO*} 哈希条目指针 + */ +BINHASH_INFO *binhash_locate(BINHASH *table, const char *key, int key_len); + +/** + * 查询某个哈希键的键值 + * @param table {BINHASH*} 哈希表指针 + * @param key {const char*} 哈希键 + * @param key_len {int} key 的长度 + * @return {char*} 哈希键值 + */ +char *binhash_find(BINHASH *table, const char *key, int key_len); + +/** + * 删除某个哈希项 + * @param table {BINHASH*} 哈希表指针 + * @param key {const char*} 哈希键 + * @param key_len {int} key 的长度 + * @param free_fn {void (*)(char*)} 用来释放哈希键值的函数指针,如果为空则不在内部释放键值 + */ +void binhash_delete(BINHASH *table, const char *key, int key_len, void (*free_fn) (char *)); + +/** + * 释放哈希表 + * @param table {BINHASH*} 哈希表指针 + * @param free_fn {void (*)(char*)} 如果不为空,则用此函数来释放哈希表内的所有键值 + */ +void binhash_free(BINHASH *table, void (*free_fn) (char *)); + +/** + * 遍历整个哈希表,并用用户给出的回调函数操作哈希表中的键值 + * @param table {BINHASH*} 哈希表指针 + * @param walk_fn {void (*)(BINHASH_INFO*, char*)} 在遍历哈希表中的每个元素时的回调函数 + * @param arg {char*} 用户传递的参数,作为参数在 walk_fn 中传递 + */ +void binhash_walk(BINHASH *table, void (*walk_fn) (BINHASH_INFO *, char *), char *arg); + +/** + * 列出当前哈希表中的所有元素数组列表 + * @param table {BINHASH*} 哈希表指针 + * @return {BINHASH_INFO*} 哈希表中所有元素组成的BINHASH_INFO数组, + * 该数组中的最后一个指针为 NULL + */ +BINHASH_INFO **binhash_list(BINHASH *table); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/src/private/bak/fifo.c b/lib_acl/src/private/bak/fifo.c new file mode 100644 index 000000000..f06b85509 --- /dev/null +++ b/lib_acl/src/private/bak/fifo.c @@ -0,0 +1,231 @@ + +#include "stdlib/acl_define.h" +#include +#include "stdlib/acl_malloc.h" +#include "stdlib/acl_msg.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "fifo.h" + +typedef struct FIFO_INFO FIFO_INFO; + +struct FIFO_INFO { + void *data; + FIFO_INFO *prev; + FIFO_INFO *next; +}; + +struct FIFO_ITER { + FIFO *fifo; + FIFO_INFO *info_curr; +}; + +struct FIFO { + FIFO_INFO *head; + FIFO_INFO *tail; + FIFO_ITER iter; + int cnt; +}; + +FIFO *fifo_new(void) +{ + FIFO *fifo; + + fifo = (FIFO *) acl_default_calloc(__FILE__, __LINE__, 1, sizeof(*fifo)); + fifo->iter.fifo = fifo; + fifo->iter.info_curr = NULL; + + return (fifo); +} + +void fifo_free(FIFO *fifo, void (*free_fn)(void *)) +{ + void *data; + + if (fifo) { + while ((data = fifo_pop(fifo)) != NULL) { + if (free_fn) + free_fn(data); + } + + acl_default_free(__FILE__, __LINE__, fifo); + } +} + +void fifo_push(FIFO *fifo, void *data) +{ + const char *myname = "fifo_push"; + FIFO_INFO *info; + + if (fifo == NULL) { + acl_msg_error("%s: fifo null", myname); + return; + } + + if (data == NULL) { + acl_msg_error("%s: data null", myname); + return; + } + + info = (FIFO_INFO *) acl_default_malloc(__FILE__, __LINE__, sizeof(*info)); + info->data = data; + info->prev = NULL; + info->next = NULL; + + if (fifo->head == NULL) { + fifo->head = info; + fifo->tail = info; + } else { + fifo->tail->next = info; + info->prev = fifo->tail; + fifo->tail = info; + } + + fifo->cnt++; +} + +void *fifo_pop(FIFO *fifo) +{ + const char *myname = "fifo_pop"; + FIFO_INFO *info; + void *data; + + if (fifo == NULL) { + acl_msg_error("%s: fifo null", myname); + return (NULL); + } + + info = fifo->head; + if (info == NULL) + return (NULL); + + if (fifo->head->next) + fifo->head->next->prev = NULL; + fifo->head = fifo->head->next; + if (fifo->head == NULL) + fifo->tail = NULL; + + data = info->data; + acl_default_free(__FILE__, __LINE__, info); + + fifo->cnt--; + + return (data); +} + +void *fifo_head(FIFO *fifo) +{ + if (fifo && fifo->head) + return (fifo->head->data); + else + return (NULL); +} + +void *fifo_tail(FIFO *fifo) +{ + if (fifo && fifo->tail) + return (fifo->tail->data); + else + return (NULL); +} + +FIFO_ITER *fifo_iterator_head(FIFO *fifo) +{ + if (fifo && fifo->head) { + fifo->iter.info_curr = fifo->head; + return (&fifo->iter); + } else + return (NULL); +} + +FIFO_ITER *fifo_iterator_next(FIFO_ITER *iter) +{ + if (iter == NULL) + return (NULL); + + iter->info_curr = iter->info_curr->next; + if (iter->info_curr == NULL) + return (NULL); + return (iter); +} + +FIFO_ITER *fifo_iterator_tail(FIFO *fifo) +{ + if (fifo && fifo->tail) { + fifo->iter.info_curr = fifo->tail; + return (&fifo->iter); + } else + return (NULL); +} + +FIFO_ITER *fifo_iterator_prev(FIFO_ITER *iter) +{ + if (iter == NULL) + return (NULL); + + iter->info_curr = iter->info_curr->prev; + if (iter->info_curr == NULL) + return (NULL); + return (iter); +} + +void *fifo_iterator_data(FIFO_ITER *iter) +{ + if (iter == NULL) + return (NULL); + + return (iter->info_curr->data); +} + +FIFO_ITER *fifo_iterator_delete(FIFO_ITER *iter, void (*free_fn)(void *)) +{ + FIFO_INFO *info = iter->info_curr, *prev, *next; + FIFO *fifo; + + if (iter == NULL || info == NULL) { + iter->info_curr = NULL; + return (NULL); + } + + fifo = iter->fifo; + + prev = info->prev; + next = info->next; + + fifo->cnt--; + + if (info == fifo->head) { + fifo->head = next; + if (fifo->head == NULL) + fifo->tail = NULL; + } else if (info == fifo->tail) { + fifo->tail = prev; + if (fifo->tail == NULL) + fifo->head = NULL; + } + + if (prev) + prev->next = next; + if (next) + next->prev = prev; + + if (info->data && free_fn) + free_fn(info->data); + acl_default_free(__FILE__, __LINE__, info); + + if (next == NULL) + return (NULL); + iter->info_curr = next; + return (iter); +} + +int fifo_size(FIFO *fifo) +{ + if (fifo) + return (fifo->cnt); + else + return (0); +} diff --git a/lib_acl/src/private/bak/fifo.h b/lib_acl/src/private/bak/fifo.h new file mode 100644 index 000000000..7912452e3 --- /dev/null +++ b/lib_acl/src/private/bak/fifo.h @@ -0,0 +1,30 @@ +#ifndef __FIFO_INCLUDE_H__ +#define __FIFO_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct FIFO_ITER FIFO_ITER; +typedef struct FIFO FIFO; + +extern FIFO *fifo_new(void); +extern void fifo_free(FIFO *fifo, void (*free_fn)(void *)); +extern void fifo_push(FIFO *fifo, void *data); +extern void *fifo_pop(FIFO *fifo); +extern void *fifo_head(FIFO *fifo); +extern void *fifo_tail(FIFO *fifo); +extern int fifo_size(FIFO *fifo); +extern FIFO_ITER *fifo_iterator_head(FIFO *fifo); +extern FIFO_ITER *fifo_iterator_next(FIFO_ITER *iter); +extern FIFO_ITER *fifo_iterator_tail(FIFO *fifo); +extern FIFO_ITER *fifo_iterator_prev(FIFO_ITER *iter); +extern void *fifo_iterator_data(FIFO_ITER *iter); +extern FIFO_ITER *fifo_iterator_delete(FIFO_ITER *iter, void (*free_fn)(void *)); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/src/private/bak/htable.c b/lib_acl/src/private/bak/htable.c new file mode 100644 index 000000000..e578276e4 --- /dev/null +++ b/lib_acl/src/private/bak/htable.c @@ -0,0 +1,436 @@ +#include "stdlib/acl_define.h" +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_msg.h" +#include "stdlib/acl_slice.h" + +#include +#include +#include + +#include "htable.h" + +/* Structure of one hash table. */ + +struct HTABLE { + int size; /* length of entries array */ + int init_size; /* length of initial entryies array */ + int used; /* number of entries in table */ + HTABLE_INFO **data; /* entries array, auto-resized */ + int status; /* the operator's status on the htable */ + + ACL_SLICE *slice; + unsigned int flag; /* same as ACL_MDT_IDX->flag */ + HASH_FN hash_fn; /* hash function */ +}; + +/* __def_hash_fn - hash a string */ + +static unsigned __def_hash_fn(const void *buffer, size_t len) +{ + unsigned long h = 0; + unsigned long g; + const unsigned char* s = (const unsigned char *) buffer; + + /* + * From the "Dragon" book by Aho, Sethi and Ullman. + */ + + while (len-- > 0) { + h = (h << 4) + *s++; + if ((g = (h & 0xf0000000)) != 0) { + h ^= (g >> 24); + h ^= g; + } + } + + return (h); +} +/* htable_link - insert element into table */ + +#define htable_link(_table, _element, _n) { \ + HTABLE_INFO **_h = _table->data + _n; \ + _element->prev = 0; \ + if ((_element->next = *_h) != 0) \ + (*_h)->prev = _element; \ + *_h = _element; \ + _table->used++; \ +} + +/* htable_size - allocate and initialize hash table */ + +static int htable_size(HTABLE *table, unsigned size) +{ + HTABLE_INFO **h; + + size |= 1; + + table->data = h = (HTABLE_INFO **) acl_mymalloc(size * sizeof(HTABLE_INFO *)); + if(table->data == NULL) + return(-1); + + table->size = size; + table->used = 0; + + while (size-- > 0) + *h++ = 0; + + return(0); +} + +/* htable_grow - extend existing table */ + +static int htable_grow(HTABLE *table) +{ + int ret; + HTABLE_INFO *ht; + HTABLE_INFO *next; + unsigned old_size = table->size; + HTABLE_INFO **h0 = table->data; + HTABLE_INFO **old_entries = h0; + unsigned n; + + ret = htable_size(table, 2 * old_size); + if (ret < 0) + return(-1); + + while (old_size-- > 0) { + for (ht = *h0++; ht; ht = next) { + next = ht->next; + n = table->hash_fn(ht->key.c_key, strlen(ht->key.c_key)) % table->size; + htable_link(table, ht, n); + } + } + + acl_myfree(old_entries); + + return(0); +} + +/* htable_create - create initial hash table */ + +HTABLE *htable_create(int size, unsigned int flag, int slice_type) +{ + HTABLE *table; + int ret; + + table = (HTABLE *) acl_mycalloc(1, sizeof(HTABLE)); + if(table == NULL) + return(NULL); + + table->init_size = size; + + ret = htable_size(table, size < 13 ? 13 : size); + if(ret < 0) { + acl_myfree(table); + return(NULL); + } + + if (slice_type) + table->slice = acl_slice_create("htable", 0, + sizeof(HTABLE_INFO), slice_type); + + table->hash_fn = __def_hash_fn; + table->flag = flag; + return (table); +} + +void htable_ctl(HTABLE *table, int name, ...) +{ + const char *myname = "htable_ctl"; + va_list ap; + + if (table == NULL) + return; + + va_start(ap, name); + for (; name != HTABLE_CTL_END; name = va_arg(ap, int)) { + switch (name) { + case HTABLE_CTL_HASH_FN: + table->hash_fn = va_arg(ap, HASH_FN); + if (table->hash_fn == NULL) + table->hash_fn = __def_hash_fn; + break; + default: + acl_msg_fatal("%s: bad name %d", myname, name); + } + } + va_end(ap); +} + +int htable_last_errno(HTABLE *table) +{ + if (table == NULL) + return (HTABLE_STAT_INVAL); + return (table->status); +} + +void htable_set_errno(HTABLE *table, int error) +{ + if (table) + table->status = error; +} + +#define STREQ(x,y) (x == y || (x[0] == y[0] && strcmp(x,y) == 0)) + +/* htable_enter - enter (key, value) pair */ + +HTABLE_INFO *htable_enter(HTABLE *table, const char *key, char *value acl_unused) +{ + const char *myname = "htable_enter"; + HTABLE_INFO *ht; + int ret; + unsigned n; + + table->status = HTABLE_STAT_OK; + + if (table->used >= table->size) { + ret = htable_grow(table); + if(ret < 0) { + return(NULL); + } + } + + n = table->hash_fn(key, strlen(key)); + n = n % table->size; + + for (ht = table->data[n]; ht; ht = ht->next) { + if (STREQ(key, ht->key.c_key)) { + table->status = HTABLE_STAT_DUPLEX_KEY; + return (ht); + } + } + + if (table->slice) + ht = (HTABLE_INFO*) acl_slice_alloc(table->slice); + else + ht = (HTABLE_INFO *) acl_mymalloc(sizeof(HTABLE_INFO)); + if (ht == NULL) { + acl_msg_error("%s(%d): alloc error", myname, __LINE__); + return(NULL); + } + + if (table->flag & KEY_REUSE) + ht->key.c_key = key; + else + ht->key.key = acl_mystrdup(key); + if (ht->key.key == NULL) { + acl_myfree(ht); + return(NULL); + } + +#ifdef HAS_VALUE + ht->value = value; +#endif + htable_link(table, ht, n); + + return (ht); +} + +/* htable_find - lookup value */ + +char *htable_find(HTABLE *table, const char *key) +{ + HTABLE_INFO *ht; + unsigned n; + +#ifndef HAS_VALUE + return (NULL); +#endif + if (table == NULL || key == NULL) + return (NULL); + + n = table->hash_fn(key, strlen(key)); + + n = n % table->size; + + for (ht = table->data[n]; ht; ht = ht->next) { + if (STREQ(key, ht->key.c_key)) { +#ifdef HAS_VALUE + return (ht->value); +#endif + } + } + + return (NULL); +} + +/* htable_locate - lookup entry */ + +HTABLE_INFO *htable_locate(HTABLE *table, const char *key) +{ + HTABLE_INFO *ht; + unsigned n; + + if(table == NULL || key == NULL) + return (NULL); + + n = table->hash_fn(key, strlen(key)); + + n = n % table->size; + + for (ht = table->data[n]; ht; ht = ht->next) { + if (STREQ(key, ht->key.c_key)) { + return (ht); + } + } + + return (NULL); +} + +/* htable_delete - delete one entry */ + +int htable_delete(HTABLE *table, const char *key, void (*free_fn) (char *) acl_unused) +{ + if (table && key) { + HTABLE_INFO *ht; + unsigned n = table->hash_fn(key, strlen(key)); + HTABLE_INFO **h; + + n = n % table->size; + + h = table->data + n; + for (ht = *h; ht; ht = ht->next) { + if (STREQ(key, ht->key.c_key)) { + if (ht->next) + ht->next->prev = ht->prev; + if (ht->prev) + ht->prev->next = ht->next; + else + *h = ht->next; + table->used--; +#ifdef HAS_VALUE + if (free_fn && ht->value) + (*free_fn) (ht->value); +#endif + if (!(table->flag & KEY_REUSE)) + acl_myfree(ht->key.key); + if (table->slice) + acl_slice_free(table->slice, ht); + else + acl_myfree(ht); + return(0); + } + } + } + + return(-1); +} + +/* htable_free - destroy hash table */ + +void htable_free(HTABLE *table, void (*free_fn) (char *) acl_unused) +{ + if (table) { + unsigned i = table->size; + HTABLE_INFO *ht; + HTABLE_INFO *next; + HTABLE_INFO **h = table->data; + + while (i-- > 0) { + for (ht = *h++; ht; ht = next) { + next = ht->next; +#ifdef HAS_VALUE + if (free_fn && ht->value) + (*free_fn) (ht->value); +#endif + if (!(table->flag & KEY_REUSE)) + acl_myfree(ht->key.key); + if (table->slice) + acl_slice_free(table->slice, ht); + else + acl_myfree(ht); + } + } + acl_myfree(table->data); + if (table->slice) + acl_slice_destroy(table->slice); + acl_myfree(table); + } +} + +/* htable_walk - iterate over hash table */ + +void htable_walk(HTABLE *table, void (*action)(HTABLE_INFO *, char *), char *ptr) +{ + if (table) { + unsigned i = table->size; + HTABLE_INFO **h = table->data; + HTABLE_INFO *ht; + + while (i-- > 0) + for (ht = *h++; ht; ht = ht->next) + (*action) (ht, ptr); + } +} + +int htable_capacity(const HTABLE *table) +{ + if (table) + return (table->size); + else + return (0); +} + +int htable_used(const HTABLE *table) +{ + if (table) + return (table->used); + else + return (0); +} + +/* htable_list - list all table members */ + +HTABLE_INFO **htable_list(const HTABLE *table) +{ + HTABLE_INFO **list; + HTABLE_INFO *member; + int count = 0; + int i; + + if (table != 0) { + list = (HTABLE_INFO **) acl_mymalloc(sizeof(*list) * (table->used + 1)); + for (i = 0; i < table->size; i++) + for (member = table->data[i]; member != 0; member = member->next) + list[count++] = member; + } else { + list = (HTABLE_INFO **) acl_mymalloc(sizeof(*list)); + } + list[count] = 0; + return (list); +} + +void htable_list_free(HTABLE_INFO **list) +{ + acl_myfree(list); +} + +void htable_stat(const HTABLE *table) +{ + HTABLE_INFO *member; + int i, count; + + if(table != NULL) { + printf("hash stat count for each key:\n"); + for(i = 0; i < table->size; i++) { + count = 0; + member = table->data[i]; + for(; member != 0; member = member->next) + count++; + if(count > 0) + printf("chains[%d]: count[%d]\n", i, count); + } + + printf("hash stat all values for each key:\n"); + for(i = 0; i < table->size; i++) { + member = table->data[i]; + if(member) { + printf("chains[%d]: ", i); + for(; member != 0; member = member->next) + printf("[%s]", member->key.c_key); + printf("\n"); + } + } + printf("hash table size=%d, used=%d\n", table->size, table->used); + } +} diff --git a/lib_acl/src/private/bak/htable.h b/lib_acl/src/private/bak/htable.h new file mode 100644 index 000000000..8ea4cff5d --- /dev/null +++ b/lib_acl/src/private/bak/htable.h @@ -0,0 +1,172 @@ + +#ifndef __HTABLE_H_INCLUDED__ +#define __HTABLE_H_INCLUDED__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "private.h" + +#define HAS_VALUE + +/*--------------------------------------------------------------------------*/ +/** + * 哈希函数类型定义 + * @param buffer 需要被哈希的字符串 + * @param len s 的长度 + */ +typedef unsigned (*HASH_FN)(const void *buffer, size_t len); + +/** + * 哈希表对象结构句柄, 该类型定义在 htable.c 中是为了保护内部成员变量 + */ +typedef struct HTABLE HTABLE; + +/** + * 哈希表中每一个哈希项的存储信息类型 + */ +#ifdef PACK_STRUCT +#pragma pack(4) +#endif +typedef struct HTABLE_INFO { + union { + char *key; + const char *c_key; + } key; /**< lookup key */ +#ifdef HAS_VALUE + char *value; /**< associated value */ +#endif + struct HTABLE_INFO *next; /**< colliding entry */ + struct HTABLE_INFO *prev; /**< colliding entry */ +} HTABLE_INFO; +#ifdef PACK_STRUCT +#pragma pack(0) +#endif + +/** + * 建立哈希表 + * @param size 哈希表长度 + * @param flag 与 ACL_MDT_IDX 中的 flag 相同 + * @return 所建哈希表的头指针或为空(这时表示出了严重的错误, 主要是内存分配问题) + */ +HTABLE *htable_create(int size, unsigned int flag, int use_slice); + +/** + * 设置哈希表的控制参数 + * @param table 哈希表对象句柄 + * @param name 控制参数的变参初始值, name 及以后的控制参数如下定义 + * HTABLE_CTL_END: 变参表结束标志 + * HTABLE_CTL_RWLOCK: 是否启用读写锁机制 + * HTABLE_CTL_HASH_FN: 用户自定义的哈希值计算函数 + */ +void htable_ctl(HTABLE *table, int name, ...); +#define HTABLE_CTL_END 0 /**< 控制结束标志 */ +#define HTABLE_CTL_HASH_FN 2 /**< 设置私有哈希函数 */ + +/** + * 检查上一次哈希表操作后哈希表的状态 + * @param table 哈希表指针 + * @return {int} 操作哈希表后的状态, 参见如下的 HTABLE_STAT_XXX + */ +int htable_last_errno(HTABLE *table); +#define HTABLE_STAT_OK 0 /**< 状态正常 */ +#define HTABLE_STAT_INVAL 1 /**< 无效参数 */ +#define HTABLE_STAT_DUPLEX_KEY 2 /**< 重复键 */ + +/** + * 设置哈希表的当前状态, error 取值 HTABLE_STAT_XXX + * @param table 哈希表指针 + * @param error 设置哈希表的错误状态 + */ +void htable_set_errno(HTABLE *table, int error); + +/** + * 往哈希表里添加新的项 + * @param table 哈希表指针 + * @param key 键, 在函数内部会复制此 key 键 + * @param value 用户自己的特定数据项(可以由类型硬转化而来, 但是此数据项必须不能堆栈变量) + * @return 所分配的哈希表项的指针, == NULL: 表示内部分分配内存出错, 为严重的错误 + * 注:如果在添加时该哈希争键存在,则返回已经存在的哈希项,使用者应该通过调用 + * htable_last_errno() 来查看是否重复添加同一个键值(HTABLE_STAT_DUPLEX_KEY) + */ +HTABLE_INFO *htable_enter(HTABLE *table, const char *key, char *value); + +/** + * 由所给的 key 键查寻某一特定哈希项 + * @param table 哈希表指针 + * @param key 键 + * @return 不为空指针: 表示查到了对应于 key 键的哈希项 + * 为空: 表示未查到对应于 key 键的哈希项 + */ +HTABLE_INFO *htable_locate(HTABLE *table, const char *key); + +/** + * 由所给的 key 键查寻用户的数据项 + * @param table 哈希表指针 + * @param key 键 + * @return 不为空: 表示查到了对应于 key 键的数据项, 用户可以根据用户自己的 + * 数据类型进行转换; 为空: 表示未查到对应于 key 键的数据项 + */ +char *htable_find(HTABLE *table, const char *key); + +/** + * 根据所给的 key 键删除某一哈希项 + * @param table 哈希表指针 + * @param key 键 + * @param free_fn 如果该函数指针不为空并且找到了对应于 key 键的数据项, 则先调用用户 + * 所提供的析构函数做一些清尾工作, 然后再释放该哈希项 + * @return 0: 成功; -1: 未找到该 key 键 + */ +int htable_delete(HTABLE *table, const char *key, void (*free_fn) (char *)); + +/** + * 释放整个哈希表 + * @param table 哈希表指针 + * @param free_fn 如果该指针不为空则对哈希表中的每一项哈希项先用该函数做清尾工作, 然后再释放 + */ +void htable_free(HTABLE *table, void (*free_fn) (char *)); + +/** + * 对哈希表中的每一项哈希项进行处理 + * @param table 哈希表指针 + * @param walk_fn 处理每一项哈希项的函数指针, 不能为空 + * @param arg 用户自己类型的数据 + */ +void htable_walk(HTABLE *table, void (*walk_fn) (HTABLE_INFO *, char *), char *arg); + +/** + * 返回哈希表当前的容器空间大小(该值应大于哈希表中元素个数) + * @param table 哈希表指针 + * @return 哈希表的容器空间大小 + */ +int htable_capacity(const HTABLE *table); + +/** + * 返回哈希表当前的窗口中所含元素个数 + * @param table 哈希表指针 + * @return 哈希表中元素个数 + */ +int htable_used(const HTABLE *table); + +/** + * 将哈希表里的所有项组合成一个链表 + * @param table 哈希表 + * @return 不为空: 链表指针; 为空: 表示该哈希表里没有哈希项 + */ +HTABLE_INFO **htable_list(const HTABLE *table); + +void htable_list_free(HTABLE_INFO ** list); + +/** + * 显示哈希表中 key 键的分布状态 + * @param table 哈希表指针 + */ +void htable_stat(const HTABLE *table); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/src/private/private.h b/lib_acl/src/private/private.h new file mode 100644 index 000000000..fc8469f3f --- /dev/null +++ b/lib_acl/src/private/private.h @@ -0,0 +1,8 @@ +#ifndef __PRIVATE_INCLUDE_H__ +#define __PRIVATE_INCLUDE_H__ + +#ifndef KEY_REUSE +#define KEY_REUSE (1 << 0) +#endif + +#endif diff --git a/lib_acl/src/private/private_array.c b/lib_acl/src/private/private_array.c new file mode 100644 index 000000000..54110a251 --- /dev/null +++ b/lib_acl/src/private/private_array.c @@ -0,0 +1,214 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include + +#endif + +#include "private_array.h" + +/* array_iter_head - get the head of the array */ + +static void *array_iter_head(ACL_ITER *iter, struct ACL_ARRAY *a) +{ + iter->dlen = -1; + iter->key = NULL; + iter->klen = 0; + iter->i = 0; + iter->size = a->count; + if (a->items == NULL) + iter->ptr = iter->data = 0; + else + iter->ptr = a->items[0]; + + iter->data = iter->ptr; + return (iter->ptr); +} + +/* array_iter_next - get the next of the array */ + +static void *array_iter_next(ACL_ITER *iter, struct ACL_ARRAY *a) +{ + iter->i++; + if (iter->i >= a->count) + iter->data = iter->ptr = 0; + else + iter->data = iter->ptr = a->items[iter->i]; + return (iter->ptr); +} + +/* array_iter_tail - get the tail of the array */ + +static void *array_iter_tail(ACL_ITER *iter, struct ACL_ARRAY *a) +{ + iter->dlen = -1; + iter->key = NULL; + iter->klen = 0; + iter->i = a->count - 1; + iter->size = a->count; + if (a->items == NULL) + iter->ptr = iter->data = 0; + else if (iter->i < 0) + iter->data = iter->ptr = 0; + else + iter->data = iter->ptr = a->items[iter->i]; + return (iter->ptr); +} + +/* array_iter_prev - get the prev of the array */ + +static void *array_iter_prev(ACL_ITER *iter, struct ACL_ARRAY *a) +{ + iter->i--; + if (iter->i < 0) + iter->data = iter->ptr = 0; + else + iter->data = iter->ptr = a->items[iter->i]; + return (iter->ptr); +} + +/* grows internal buffer to satisfy required minimal capacity */ + +void private_array_grow(ACL_ARRAY *a, int min_capacity) +{ + int min_delta = 16; + int delta; + + /* don't need to grow the capacity of the array */ + if(a->capacity >= min_capacity) + return; + delta = min_capacity; + /* make delta a multiple of min_delta */ + delta += min_delta - 1; + delta /= min_delta; + delta *= min_delta; + /* actual grow */ + if (delta <= 0) + return; + a->capacity += delta; + if (a->items) { + a->items = (void **) realloc(a->items, a->capacity * sizeof(void *)); + } else { + a->items = (void **) malloc(a->capacity * sizeof(void *)); + } + + /* reset, just in case */ + memset(a->items + a->count, 0, (a->capacity - a->count) * sizeof(void *)); +} + +static void array_init(ACL_ARRAY *a) +{ + memset(a, 0, sizeof(ACL_ARRAY)); +} + +static void array_prepare_append(ACL_ARRAY *a, int app_count) +{ + acl_assert(app_count > 0); + if (a->count + app_count > a->capacity) + private_array_grow(a, a->count + app_count); +} + +ACL_ARRAY *private_array_create(int init_size) +{ + ACL_ARRAY *a; + + a = (ACL_ARRAY *) calloc(1, sizeof(ACL_ARRAY)); + acl_assert(a); + + array_init(a); + a->iter_head = array_iter_head; + a->iter_next = array_iter_next; + a->iter_tail = array_iter_tail; + a->iter_prev = array_iter_prev; + + if(init_size > 0) + array_prepare_append(a, init_size); + + return(a); +} + +void private_array_clean(ACL_ARRAY *a, void (*free_fn)(void *)) +{ + int idx; + + for (idx = 0; idx < a->count; idx++) { + if(free_fn != NULL && a->items[idx] != NULL) + free_fn(a->items[idx]); + a->items[idx] = NULL; /* sanity set to be null */ + } + a->count = 0; +} + +void private_array_destroy(ACL_ARRAY *a, void (*free_fn)(void *)) +{ + private_array_clean(a, free_fn); + if (a->items) + free(a->items); + free(a); +} + +int private_array_push(ACL_ARRAY *a, void *obj) +{ + if (a->count >= a->capacity) + private_array_grow(a, a->count + 16); + a->items[a->count++] = obj; + return(a->count - 1); +} + +void *private_array_pop(ACL_ARRAY *a) +{ + void *ptr; + + if (a->count <= 0) + return (NULL); + a->count--; + ptr = a->items[a->count]; + a->items[a->count] = NULL; + return (ptr); +} + +int private_array_delete(ACL_ARRAY *a, int idx, void (*free_fn)(void*)) +{ + if (a == NULL) + return (-1); + if (idx < 0 || idx >= a->count) + return (-1); + if (free_fn != NULL && a->items[idx] != NULL) + free_fn(a->items[idx]); + a->count--; + if (a->count > 0) + a->items[idx] = a->items[a->count]; + return (0); +} + +int private_array_delete_obj(ACL_ARRAY *a, void *obj, void (*free_fn)(void*)) +{ + int i; + + if (a == NULL || obj == NULL) + return (-1); + for (i = 0; i < a->count; i++) { + if (a->items[i] == obj) { + return (private_array_delete(a, i, free_fn)); + } + } + return (-1); +} + +void *private_array_index(const ACL_ARRAY *a, int idx) +{ + if(idx < 0 || idx > a->count - 1) + return(NULL); + + return(a->items[idx]); +} + +int private_array_size(const ACL_ARRAY *a) +{ + if(a == NULL) + return(-1); + return(a->count); +} diff --git a/lib_acl/src/private/private_array.h b/lib_acl/src/private/private_array.h new file mode 100644 index 000000000..5172d73d3 --- /dev/null +++ b/lib_acl/src/private/private_array.h @@ -0,0 +1,102 @@ +#ifndef __PRIVATE_ARRAY_INCLUDE_H_ +#define __PRIVATE_ARRAY_INCLUDE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_define.h" +#include "stdlib/acl_iterator.h" +#include "stdlib/acl_array.h" + +/** + * 创建一个动态数组 + * @param init_size {int} 动态数组的初始大小 + * @return {ACL_ARRAY*} 动态数组指针 + */ +ACL_ARRAY *private_array_create(int init_size); + +/** + * 释放掉动态数组内的成员变量,但并不释放动态数组对象 + * @param a {ACL_ARRAY*} 动态数组指针 + * @param free_fn {void (*)(void*)} 用于释放动态数组内成员变量的释放函数指针 + */ +void private_array_clean(ACL_ARRAY *a, void (*free_fn)(void *)); + +/** + * 释放掉动态数组内的成员变量,并释放动态数组对象 + * @param a {ACL_ARRAY*} 动态数组指针 + * @param free_fn {void (*)(void*)} 用于释放动态数组内成员变量的释放函数指针 + */ +void private_array_destroy(ACL_ARRAY *a, void (*free_fn)(void *)); + +/** + * 向动态数组尾部添加动态成员变量 + * @param a {ACL_ARRAY*} 动态数组指针 + * @param obj {void*} 动态成员变量 + * @return {int} 0: 成功;-1: 失败 + */ +int private_array_push(ACL_ARRAY *a, void *obj); + +/** + * 从动态数组中弹出最尾一个对象 + * @param a {ACL_ARRAY*} 动态数组指针 + * @return {void*}, NULL 表示数组为空 + */ +void* private_array_pop(ACL_ARRAY *a); + +/** + * 从动态数组中的指定位置删除某个对象,删除后数组内元素的先后顺序有可能发生了改变, + * 因为删除后会自动将数组中最后的元素移至该位置处 + * @param a {ACL_ARRAY*} 动态数组指针 + * @param position {int} 某个位置,不得越界 + * @param free_fn {void (*)(void*)} 用于释放动态数组内成员变量的释放函数指针,如果该 + * 指针为空,则不释放,否则用此函数进行释放动态对象 + * @return {int} 0: 成功;-1: 失败 + */ +int private_array_delete(ACL_ARRAY *a, int idx, void (*free_fn)(void*)); + +int private_array_delete_obj(ACL_ARRAY *a, void *obj, void (*free_fn)(void*)); + +/** + * 从动态数组中的某个下标位置取出动态对象 + * @param a {ACL_ARRAY*} 动态数组指针 + * @param idx {int} 下标位置,不能越界,否则返回-1 + * @return {void*} != NULL: 成功;== NULL: 不存在或失败 + */ +void *private_array_index(const ACL_ARRAY *a, int idx); + +/** + * 获得当前动态数组中动态对象的个数 + * @param a {ACL_ARRAY*} 动态数组指针 + * @return {int} 动态数组中动态对象的个数 + */ +int private_array_size(const ACL_ARRAY *a); + +void private_array_grow(ACL_ARRAY *a, int min_capacity); + +#define PRIVATE_ARRAY_PUSH(a, ptr) do \ +{ \ + if ((a)->count >= (a)->capacity) \ + private_array_grow((a), (a)->count + 16); \ + (a)->items[(a)->count++] = (ptr); \ +} while (0) + +#define PRIVATE_ARRAY_POP(a, ptr) do \ +{ \ + if ((a)->count > 0) { \ + (a)->count--; \ + (ptr) = (a)->items[(a)->count]; \ + (a)->items[(a)->count] = NULL; \ + } else { \ + (ptr) = NULL; \ + } \ +} while (0) + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/src/private/private_fifo.c b/lib_acl/src/private/private_fifo.c new file mode 100644 index 000000000..14311f4fc --- /dev/null +++ b/lib_acl/src/private/private_fifo.c @@ -0,0 +1,196 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include + +#endif + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "private_fifo.h" + +static void *fifo_iter_head(ACL_ITER *iter, struct ACL_FIFO *fifo) +{ + ACL_FIFO_INFO *ptr; + + iter->dlen = -1; + iter->key = NULL; + iter->klen = -1; + iter->i = 0; + iter->size = fifo->cnt; + iter->ptr = ptr = fifo->head; + iter->data = ptr ? ptr->data : NULL; + return (iter->ptr); +} + +static void *fifo_iter_next(ACL_ITER *iter, struct ACL_FIFO *fifo acl_unused) +{ + ACL_FIFO_INFO *ptr; + + ptr = (ACL_FIFO_INFO*) iter->ptr; + iter->ptr = ptr = ptr ? ptr->next : NULL; + if (ptr) { + iter->data = ptr->data; + iter->i++; + } else + iter->data = NULL; + return (iter); +} + +static void *fifo_iter_tail(ACL_ITER *iter, struct ACL_FIFO *fifo) +{ + ACL_FIFO_INFO *ptr; + + iter->dlen = -1; + iter->key = NULL; + iter->klen = -1; + iter->i = fifo->cnt - 1; + iter->size = fifo->cnt; + iter->ptr = ptr = fifo->tail; + iter->data = ptr ? ptr->data : NULL; + return (iter->ptr); +} + +static void *fifo_iter_prev(ACL_ITER *iter, struct ACL_FIFO *fifo acl_unused) +{ + ACL_FIFO_INFO *ptr; + + ptr = (ACL_FIFO_INFO*) iter->ptr; + iter->ptr = ptr = ptr ? ptr->prev : NULL; + if (ptr) { + iter->data = ptr->data; + iter->i--; + } else + iter->data = NULL; + return (iter); +} + +static ACL_FIFO_INFO *fifo_iter_info(ACL_ITER *iter, struct ACL_FIFO *fifo acl_unused) +{ + return (iter->ptr ? (ACL_FIFO_INFO*) iter->ptr : NULL); +} + +void private_fifo_init(ACL_FIFO *fifo) +{ + fifo->head = NULL; + fifo->tail = NULL; + fifo->cnt = 0; + + fifo->iter_head = fifo_iter_head; + fifo->iter_next = fifo_iter_next; + fifo->iter_tail = fifo_iter_tail; + fifo->iter_prev = fifo_iter_prev; + fifo->iter_info = fifo_iter_info; +} + +ACL_FIFO *private_fifo_new(void) +{ + ACL_FIFO *fifo; + + fifo = (ACL_FIFO *) malloc(sizeof(*fifo)); + fifo->head = NULL; + fifo->tail = NULL; + fifo->cnt = 0; + + fifo->iter_head = fifo_iter_head; + fifo->iter_next = fifo_iter_next; + fifo->iter_tail = fifo_iter_tail; + fifo->iter_prev = fifo_iter_prev; + + return (fifo); +} + +void private_fifo_free(ACL_FIFO *fifo, void (*free_fn)(void *)) +{ + void *data; + + while ((data = private_fifo_pop(fifo)) != NULL) { + if (free_fn) + free_fn(data); + } + free(fifo); +} + +ACL_FIFO_INFO *private_fifo_push(ACL_FIFO *fifo, void *data) +{ + ACL_FIFO_INFO *info; + + info = (ACL_FIFO_INFO *) malloc(sizeof(*info)); + info->data = data; + + if (fifo->tail == NULL) { + info->prev = info->next = NULL; + fifo->head = fifo->tail = info; + } else { + fifo->tail->next = info; + info->prev = fifo->tail; + info->next = NULL; + fifo->tail = info; + } + + fifo->cnt++; + return (info); +} + +void *private_fifo_pop(ACL_FIFO *fifo) +{ + ACL_FIFO_INFO *info; + void *data; + + if (fifo->head == NULL) + return (NULL); + + info = fifo->head; + if (fifo->head->next) { + fifo->head->next->prev = NULL; + fifo->head = fifo->head->next; + } else { + fifo->head = fifo->tail = NULL; + } + data = info->data; + free(info); + fifo->cnt--; + return (data); +} + +void private_delete_info(ACL_FIFO *fifo, ACL_FIFO_INFO *info) +{ + if (info->prev) + info->prev->next = info->next; + else + fifo->head = info->next; + if (info->next) + info->next->prev = info->prev; + else + fifo->tail = info->prev; + + free(info); + fifo->cnt--; +} + +void *private_fifo_head(ACL_FIFO *fifo) +{ + if (fifo->head) + return (fifo->head->data); + else + return (NULL); +} + +void *private_fifo_tail(ACL_FIFO *fifo) +{ + if (fifo->tail) + return (fifo->tail->data); + else + return (NULL); +} + +int private_fifo_size(ACL_FIFO *fifo) +{ + if (fifo) + return (fifo->cnt); + else + return (0); +} diff --git a/lib_acl/src/private/private_fifo.h b/lib_acl/src/private/private_fifo.h new file mode 100644 index 000000000..e6c6576e7 --- /dev/null +++ b/lib_acl/src/private/private_fifo.h @@ -0,0 +1,53 @@ +#ifndef __PRIVATE_FIFO_INCLUDE_H__ +#define __PRIVATE_FIFO_INCLUDE_H__ + +#include "stdlib/acl_fifo.h" +#include "stdlib/acl_malloc.h" + +void private_fifo_init(ACL_FIFO *fifo); +ACL_FIFO *private_fifo_new(void); +void private_fifo_free(ACL_FIFO *fifo, void (*free_fn)(void *)); +ACL_FIFO_INFO *private_fifo_push(ACL_FIFO *fifo, void *data); +void *private_fifo_pop(ACL_FIFO *fifo); +void private_delete_info(ACL_FIFO *fifo, ACL_FIFO_INFO *info); +void *private_fifo_head(ACL_FIFO *fifo); +void *private_fifo_tail(ACL_FIFO *fifo); +int private_fifo_size(ACL_FIFO *fifo); + +#define PRIVATE_FIFO_PUSH(_fifo, _data) do \ +{ \ + ACL_FIFO_INFO *_info; \ + _info = (ACL_FIFO_INFO *) acl_default_malloc(__FILE__, __LINE__, sizeof(*_info)); \ + _info->data = (_data); \ + if ((_fifo)->tail == NULL) { \ + _info->prev = _info->next = NULL; \ + (_fifo)->head = (_fifo)->tail = _info; \ + } else { \ + (_fifo)->tail->next = _info; \ + _info->prev = (_fifo)->tail; \ + _info->next = NULL; \ + (_fifo)->tail = _info; \ + } \ + (_fifo)->cnt++; \ +} while (0) + +#define PRIVATE_FIFO_POP(_fifo, _data_ptr) do \ +{ \ + ACL_FIFO_INFO *_info; \ + if ((_fifo)->head != NULL) { \ + _info = (_fifo)->head; \ + if ((_fifo)->head->next) { \ + (_fifo)->head->next->prev = NULL; \ + (_fifo)->head = (_fifo)->head->next; \ + } else { \ + (_fifo)->head = (_fifo)->tail = NULL; \ + } \ + (_data_ptr) = _info->data; \ + acl_default_free(__FILE__, __LINE__, _info); \ + (_fifo)->cnt--; \ + } else { \ + (_data_ptr) = NULL; \ + } \ +} while (0) + +#endif diff --git a/lib_acl/src/private/private_vstream.c b/lib_acl/src/private/private_vstream.c new file mode 100644 index 000000000..83644e4a1 --- /dev/null +++ b/lib_acl/src/private/private_vstream.c @@ -0,0 +1,817 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#include +#include +#include +#include +#include +#include +#include /* for S_IREAD */ + +#ifdef ACL_MS_WINDOWS +# include +#elif defined(ACL_UNIX) +# include +# include +# include +#else +# error "unknown OS type" +#endif + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_sys_patch.h" +#include "stdlib/acl_array.h" +#include "stdlib/acl_iostuff.h" +#include "stdlib/acl_vstream.h" +#include "stdlib/acl_msg.h" +#include "stdlib/acl_mystring.h" +#include "net/acl_connect.h" +#include "net/acl_sane_socket.h" + +#endif + +#include "private_array.h" +#include "private_vstream.h" + +static int __sys_getc(ACL_VSTREAM *stream); + +static int __read_wait(ACL_SOCKET fd, int timeout) +{ + fd_set read_fds; + fd_set except_fds; + struct timeval tv; + struct timeval *tp; + +#ifdef ACL_UNIX + /* + * Sanity checks. + */ + acl_assert(FD_SETSIZE > (unsigned) fd); +#endif + + /* + * Use select() so we do not depend on alarm() and on signal() handlers. + * Restart the select when interrupted by some signal. Some select() + * implementations reduce the time to wait when interrupted, which is + * exactly what we want. + */ + FD_ZERO(&read_fds); + FD_SET(fd, &read_fds); + FD_ZERO(&except_fds); + FD_SET(fd, &except_fds); + if (timeout >= 0) { + tv.tv_usec = 0; + tv.tv_sec = timeout; + tp = &tv; + } else { + tp = 0; + } + + for (;;) { + switch (select(fd + 1, &read_fds, (fd_set *) 0, &except_fds, tp)) { + case -1: + if (acl_last_error() != ACL_EINTR) + return (-1); + continue; + case 0: + acl_set_error(ACL_ETIMEDOUT); + return (-1); + default: + return (0); + } + } +} + +static int __vstream_sys_read(ACL_VSTREAM *stream) +{ + if (stream == NULL) + return (-1); + + if (stream->type == ACL_VSTREAM_TYPE_FILE) { + if (ACL_VSTREAM_FILE(stream) == ACL_FILE_INVALID) + return (-1); + } else if (ACL_VSTREAM_SOCK(stream) == ACL_SOCKET_INVALID) + return (-1); + +AGAIN: + if (stream->rw_timeout > 0 + && __read_wait(ACL_VSTREAM_SOCK(stream), stream->rw_timeout) < 0) { + + stream->errnum = acl_last_error(); + + if (stream->errnum != ACL_ETIMEDOUT) { + (void) acl_strerror(stream->errnum, + stream->errbuf, + sizeof(stream->errbuf)); + stream->flag |= ACL_VSTREAM_FLAG_ERR; + } else { + stream->flag |= ACL_VSTREAM_FLAG_TIMEOUT; + ACL_SAFE_STRNCPY(stream->errbuf, "read timeout", sizeof(stream->errbuf)); + } + + return (-1); + } + + acl_set_error(0); + + if (stream->type == ACL_VSTREAM_TYPE_FILE) { + stream->read_cnt = stream->fread_fn(ACL_VSTREAM_FILE(stream), + stream->read_buf, + (size_t) stream->read_buf_len, + stream->rw_timeout, + stream->context); + if (stream->read_cnt > 0) + stream->sys_offset += stream->read_cnt; + } else + stream->read_cnt = stream->read_fn(ACL_VSTREAM_SOCK(stream), + stream->read_buf, + (size_t) stream->read_buf_len, + stream->rw_timeout, + stream->context); + if (stream->read_cnt < 0) { + stream->errnum = acl_last_error(); + if (stream->errnum == ACL_EINTR) { + goto AGAIN; + } else if (stream->errnum == ACL_ETIMEDOUT) { + stream->flag |= ACL_VSTREAM_FLAG_TIMEOUT; + ACL_SAFE_STRNCPY(stream->errbuf, "read timeout", sizeof(stream->errbuf)); + } else if (stream->errnum != ACL_EWOULDBLOCK && stream->errnum != ACL_EAGAIN) { + stream->flag |= ACL_VSTREAM_FLAG_ERR; + acl_strerror(stream->errnum, stream->errbuf, sizeof(stream->errbuf)); + } + /* XXX: should do something where, 2009.12.25 -- zsx */ + + stream->read_cnt = 0; /* xxx: why? */ + return (-1); + } else if (stream->read_cnt == 0) { /* closed by peer */ + char ebuf[256]; + stream->flag = ACL_VSTREAM_FLAG_EOF; + stream->errnum = 0; + snprintf(stream->errbuf, sizeof(stream->errbuf), + "closed by peer(%s)", acl_last_strerror(ebuf, sizeof(ebuf))); + + return (0); + } + + stream->read_ptr = stream->read_buf; + stream->flag &= ~ACL_VSTREAM_FLAG_BAD; + stream->errnum = 0; + stream->errbuf[0] = 0; + stream->total_read_cnt += stream->read_cnt; + + return ((int) stream->read_cnt); +} + +static int __sys_getc(ACL_VSTREAM *stream) +{ + stream->read_cnt = __vstream_sys_read(stream); + if (stream->read_cnt <= 0) { + return (ACL_VSTREAM_EOF); + } else { + return (ACL_VSTREAM_GETC(stream)); + } +} + +int private_vstream_getc(ACL_VSTREAM *stream) +{ + if (stream == NULL) + return (ACL_VSTREAM_EOF); + if (stream->read_cnt <= 0) { + if (__vstream_sys_read(stream) <= 0) + return (ACL_VSTREAM_EOF); + } + + stream->read_cnt--; + stream->offset++; + return (*stream->read_ptr++); +} + +int private_vstream_ungetc(ACL_VSTREAM *stream, int ch) +{ + unsigned char c; + + c = (unsigned char) ch; + (void) acl_vstream_unread(stream, &c, 1); + return (ch); +} + +static int vstream_bfcp_some(ACL_VSTREAM *stream, void *vptr, size_t maxlen) +{ + int n; + + /* input params error */ + acl_assert(stream && vptr && maxlen > 0); + + /* internal fatal error */ + acl_assert(stream->read_cnt >= 0); + + /* there is no any data in buf */ + if (stream->read_cnt == 0) { + stream->read_ptr = stream->read_buf; + return (0); + } + + if (stream->read_ptr >= stream->read_buf + (int) stream->read_buf_len) { + stream->read_cnt = 0; + stream->read_ptr = stream->read_buf; + return (0); + } + + n = (int) stream->read_cnt > (int) maxlen ? (int) maxlen : (int) stream->read_cnt; + + memcpy(vptr, stream->read_ptr, n); + + stream->read_cnt -= n; + stream->read_ptr += n; + stream->offset += n; + + return (n); +} + +int private_vstream_gets(ACL_VSTREAM *stream, void *vptr, size_t maxlen) +{ + int n, ch; + unsigned char *ptr; + + if (stream == NULL || vptr == NULL || maxlen <= 0) + return (ACL_VSTREAM_EOF); + + ptr = (unsigned char *) vptr; + for (n = 1; n < (int) maxlen; n++) { /* left one byte for '\0' */ + ch = private_vstream_getc(stream); + if (ch == ACL_VSTREAM_EOF) { + stream->flag &= ~ACL_VSTREAM_FLAG_TAGYES; + stream->flag |= ACL_VSTREAM_FLAG_TAGNO; + if (n == 1) + return (ACL_VSTREAM_EOF);/* EOF, nodata read */ + break; /* EOF, some data was read */ + } else { + *ptr++ = ch; + if (ch == '\n'){ /* newline is stored, like fgets() */ + stream->flag |= ACL_VSTREAM_FLAG_TAGYES; + stream->flag &= ~ACL_VSTREAM_FLAG_TAGNO; + break; + } + } + } + + *ptr = 0; /* null terminate like fgets() */ + return (n); +} + +int private_vstream_gets_nonl(ACL_VSTREAM *stream, void *vptr, size_t maxlen) +{ + int n, ch; + unsigned char *ptr; + + if (stream == NULL || vptr == NULL || maxlen <= 0) { + return (ACL_VSTREAM_EOF); + } + + ptr = (unsigned char *) vptr; + for (n = 1; n < (int) maxlen; n++) { + ch = private_vstream_getc(stream); + if (ch == ACL_VSTREAM_EOF) { + stream->flag &= ~ACL_VSTREAM_FLAG_TAGYES; + stream->flag |= ACL_VSTREAM_FLAG_TAGNO; + if (n == 1) + return (ACL_VSTREAM_EOF); /* EOF, nodata read */ + else + break; /* EOF, some data was read */ + } else { + *ptr++ = ch; + if (ch == '\n') { + stream->flag |= ACL_VSTREAM_FLAG_TAGYES; + stream->flag &= ~ACL_VSTREAM_FLAG_TAGNO; + break; /* newline is stored, like fgets() */ + } + } + } + + *ptr = 0; /* null terminate like fgets() */ + ptr--; + while (ptr >= (unsigned char *) vptr) { + if (*ptr == '\r' || *ptr == '\n') { + *ptr-- = 0; + n--; + continue; + } + break; + } + return (n); +} + +int private_vstream_readn(ACL_VSTREAM *stream, void *vptr, size_t maxlen) +{ + int n, ch; + unsigned char *ptr; + + if (stream == NULL || vptr == NULL || (int) maxlen <= 0) + return (ACL_VSTREAM_EOF); + + ptr = (unsigned char *) vptr; + for (n = 0; n < (int) maxlen; n++) { + ch = private_vstream_getc(stream); + if (ch == ACL_VSTREAM_EOF) { + if (n == 0) + return (ACL_VSTREAM_EOF); /* EOF, nodata read */ + else + break; /* EOF, some data was read */ + } else { + *ptr++ = ch; + } + } + + if (n != (int) maxlen) { + snprintf(stream->errbuf, sizeof(stream->errbuf), + "nread=%d, nneed=%d, errmsg=not read the needed data", + n, (int) maxlen); + stream->flag |= ACL_VSTREAM_FLAG_RDSHORT; + + return (ACL_VSTREAM_EOF); + } + + return (n); +} + +int private_vstream_read(ACL_VSTREAM *stream, void *vptr, size_t maxlen) +{ + int read_cnt; + unsigned char *ptr; + + if (stream == NULL || vptr == NULL || (int) maxlen <= 0) + return (ACL_VSTREAM_EOF); + + acl_assert(stream->read_cnt >= 0); + ptr = (unsigned char *) vptr; + if (stream->read_cnt > 0) { + read_cnt = vstream_bfcp_some(stream, ptr, maxlen); + return (read_cnt); + } + + /* stream->read_cnt == 0 */ + + /* there is no data in buf, so need to read data from system */ + read_cnt = __vstream_sys_read(stream); + if (read_cnt < 0) + return (ACL_VSTREAM_EOF); + else if (read_cnt == 0) + return (ACL_VSTREAM_EOF); + + read_cnt = vstream_bfcp_some(stream, ptr, maxlen); + return (read_cnt); +} + +static int __vstream_sys_write(ACL_VSTREAM *stream, const void *vptr, int dlen) +{ + int n, neintr = 0; + + acl_assert(stream && vptr && dlen > 0); + + if (stream->type == ACL_VSTREAM_TYPE_FILE) { + if (ACL_VSTREAM_FILE(stream) == ACL_FILE_INVALID) + return (ACL_VSTREAM_EOF); + } else if (ACL_VSTREAM_SOCK(stream) == ACL_SOCKET_INVALID) + return (ACL_VSTREAM_EOF); + +TAG_AGAIN: + + if (stream->type == ACL_VSTREAM_TYPE_FILE) { + if ((stream->oflags & O_APPEND)) { +#ifdef ACL_MS_WINDOWS + stream->sys_offset = acl_lseek(ACL_VSTREAM_FILE(stream), 0, SEEK_END); + if (stream->sys_offset < 0) + return (ACL_VSTREAM_EOF); +#endif + } else if ((stream->flag & ACL_VSTREAM_FLAG_CACHE_SEEK) + && stream->offset != stream->sys_offset) { + + stream->sys_offset = acl_lseek(ACL_VSTREAM_FILE(stream), + stream->offset, SEEK_SET); + if (stream->sys_offset == -1) + return (ACL_VSTREAM_EOF); + stream->offset = stream->sys_offset; + } + + n = stream->fwrite_fn(ACL_VSTREAM_FILE(stream), vptr, dlen, + stream->rw_timeout, stream->context); + if (n > 0) { + stream->sys_offset += n; + stream->offset = stream->sys_offset; + stream->read_cnt = 0; /* 防止缓冲区内的数据与实际不一致, 仅对文件IO有效 */ + } + } else + n = stream->write_fn(ACL_VSTREAM_SOCK(stream), vptr, dlen, + stream->rw_timeout, stream->context); + if (n < 0) { + if (acl_last_error() == ACL_EINTR) { + if (++neintr >= 5) + return (ACL_VSTREAM_EOF); + + goto TAG_AGAIN; + } + + if (acl_last_error() == ACL_EAGAIN || acl_last_error() == ACL_EWOULDBLOCK) + acl_set_error(ACL_EAGAIN); + + return (ACL_VSTREAM_EOF); + } + + stream->total_write_cnt += n; + return (n); +} + +static int __loop_writen(ACL_VSTREAM *stream, const void *vptr, size_t dlen) +{ + const unsigned char *ptr; + int n; + + ptr = (const unsigned char *) vptr; + while (dlen > 0) { + n = __vstream_sys_write(stream, ptr, dlen); + if (n <= 0) { + if (acl_last_error() == ACL_EINTR || acl_last_error() == ACL_EAGAIN) + continue; + return (ACL_VSTREAM_EOF); + } + + dlen -= n; + ptr += n; + } + + return (ptr - (const unsigned char *) vptr); +} + +int private_vstream_writen(ACL_VSTREAM *stream, const void *vptr, size_t dlen) +{ + acl_assert(stream && vptr && dlen > 0); + + if (stream->wbuf_dlen > 0) { + if (private_vstream_fflush(stream) == ACL_VSTREAM_EOF) + return (ACL_VSTREAM_EOF); + } + return (__loop_writen(stream, vptr, dlen)); +} + +int private_vstream_write(ACL_VSTREAM *stream, const void *vptr, size_t dlen) +{ + return (__vstream_sys_write(stream, vptr, dlen)); +} + +int private_vstream_buffed_writen(ACL_VSTREAM *stream, const void *vptr, size_t dlen) +{ + acl_assert(stream && vptr && dlen > 0); + + if (stream->wbuf == NULL) { + stream->wbuf_size = 8192; + stream->wbuf = malloc(stream->wbuf_size); + } + + if (dlen >= (size_t) stream->wbuf_size) { + if (private_vstream_fflush(stream) == ACL_VSTREAM_EOF) + return (ACL_VSTREAM_EOF); + else if (__loop_writen(stream, vptr, dlen) == ACL_VSTREAM_EOF) + return (ACL_VSTREAM_EOF); + else + return (dlen); + } else if (dlen + (size_t) stream->wbuf_dlen >= (size_t) stream->wbuf_size) { + if (private_vstream_fflush(stream) == ACL_VSTREAM_EOF) + return (ACL_VSTREAM_EOF); + } + + memcpy(stream->wbuf + (size_t) stream->wbuf_dlen, vptr, dlen); + stream->wbuf_dlen += dlen; + return(dlen); +} + +int private_vstream_fflush(ACL_VSTREAM *stream) +{ + unsigned char *ptr; + int n; + + acl_assert(stream); + if (stream->wbuf == NULL || stream->wbuf_dlen == 0) + return 0; + + ptr = stream->wbuf; + while (stream->wbuf_dlen > 0) { + n = __vstream_sys_write(stream, ptr, (int) stream->wbuf_dlen); + if (n <= 0) { + if (acl_last_error() == ACL_EINTR || acl_last_error() == ACL_EAGAIN) + continue; + return (ACL_VSTREAM_EOF); + } + + stream->wbuf_dlen -= n; + ptr += n; + } + + acl_assert(stream->wbuf_dlen >= 0); + + return (ptr - stream->wbuf); +} + +ACL_VSTREAM *private_vstream_fhopen(ACL_FILE_HANDLE fh, unsigned int oflags) +{ + ACL_VSTREAM *fp; + + acl_assert(fh != ACL_FILE_INVALID); + + fp = private_vstream_fdopen(ACL_SOCKET_INVALID, oflags, 4096, 0, ACL_VSTREAM_TYPE_FILE); + if (fp == NULL) + return (NULL); + + fp->fd.h_file = fh; + return (fp); +} + + +/* 定义流的缓冲区的默认大小 */ + +#define ACL_VSTREAM_DEF_MAXLEN 8192 + +ACL_VSTREAM *private_vstream_fdopen(ACL_SOCKET fd, unsigned int oflags, + size_t buflen, int rw_timeo, int fdtype) +{ + ACL_VSTREAM *stream = NULL; + + stream = (ACL_VSTREAM *) calloc(1, sizeof(ACL_VSTREAM)); + acl_assert(stream); + + if (buflen < ACL_VSTREAM_DEF_MAXLEN) + buflen = ACL_VSTREAM_DEF_MAXLEN; + + /* XXX: 只有非监听流才需要有读缓冲区 */ + + if ((fdtype & ACL_VSTREAM_TYPE_LISTEN_INET) + || (fdtype & ACL_VSTREAM_TYPE_LISTEN_UNIX)) + { + fdtype |= ACL_VSTREAM_TYPE_LISTEN; + stream->read_buf = NULL; + } else { + stream->read_buf = (unsigned char *) malloc(buflen + 1); + acl_assert(stream->read_buf != NULL); + } + + if (fdtype == 0) + fdtype = ACL_VSTREAM_TYPE_SOCK; + + stream->read_buf_len = buflen; + stream->type = fdtype; + ACL_VSTREAM_SOCK(stream) = fd; +#ifdef ACL_MS_WINDOWS + stream->iocp_sock = ACL_SOCKET_INVALID; +#endif + + stream->read_ptr = stream->read_buf; + stream->oflags = oflags; + ACL_SAFE_STRNCPY(stream->errbuf, "OK", sizeof(stream->errbuf)); + + if (rw_timeo > 0) + stream->rw_timeout = rw_timeo; + else + stream->rw_timeout = 0; + + stream->sys_getc = __sys_getc; + if (fdtype == ACL_VSTREAM_TYPE_FILE) { + stream->fread_fn = acl_file_read; + stream->fwrite_fn = acl_file_write; + stream->fwritev_fn = acl_file_writev; + stream->fclose_fn = acl_file_close; + } else { + stream->read_fn = acl_socket_read; + stream->write_fn = acl_socket_write; + stream->writev_fn = acl_socket_writev; + stream->close_fn = acl_socket_close; + } + + stream->path = stream->remote_addr; /* default */ + + stream->close_handle_lnk = private_array_create(5); + if (stream->close_handle_lnk == NULL) { + free(stream->read_buf); + free(stream); + return (NULL); + } + + return (stream); +} + +ACL_VSTREAM *private_vstream_fopen(const char *path, unsigned int oflags, int mode, size_t buflen) +{ + ACL_VSTREAM *fp; + ACL_FILE_HANDLE fh; + + /* for linux2.6 */ +#ifdef _LARGEFILE64_SOURCE + oflags |= O_LARGEFILE; +#endif + +#ifdef ACL_MS_WINDOWS + oflags |= O_BINARY; +#endif + + fh = acl_file_open(path, oflags, mode); + + if (fh == ACL_FILE_INVALID) + return (NULL); + + fp = private_vstream_fdopen(ACL_SOCKET_INVALID, + oflags, + buflen, + 0, + ACL_VSTREAM_TYPE_FILE); + if (fp == NULL) + return (NULL); + + fp->fd.h_file = fh; + ACL_SAFE_STRNCPY(fp->remote_addr, path, sizeof(fp->remote_addr)); + return (fp); +} + +void private_vstream_ctl(ACL_VSTREAM *stream, int name,...) +{ + va_list ap; + int n; + char *ptr; + + va_start(ap, name); + for (; name != ACL_VSTREAM_CTL_END; name = va_arg(ap, int)) { + switch (name) { + case ACL_VSTREAM_CTL_READ_FN: + stream->read_fn = va_arg(ap, ACL_VSTREAM_RD_FN); + break; + case ACL_VSTREAM_CTL_WRITE_FN: + stream->write_fn = va_arg(ap, ACL_VSTREAM_WR_FN); + break; + case ACL_VSTREAM_CTL_CONTEXT: + stream->context = va_arg(ap, char *); + break; + case ACL_VSTREAM_CTL_PATH: + ptr = va_arg(ap, char*); + ACL_SAFE_STRNCPY(stream->remote_addr, + ptr, sizeof(stream->remote_addr)); + break; + case ACL_VSTREAM_CTL_FD: + ACL_VSTREAM_SOCK(stream) = va_arg(ap, ACL_SOCKET); + break; + case ACL_VSTREAM_CTL_TIMEOUT: + stream->rw_timeout = va_arg(ap, int); + break; + case ACL_VSTREAM_CTL_CACHE_SEEK: + n = va_arg(ap, int); + if (n) { + stream->flag |= ACL_VSTREAM_FLAG_CACHE_SEEK; + } else { + stream->flag &= ~ACL_VSTREAM_FLAG_CACHE_SEEK; + } + break; + default: + acl_assert(0); + break; + } + } + va_end(ap); +} + +ACL_VSTREAM *private_vstream_connect(const char *addr, int conn_timeout, int rw_timeout) +{ + return (private_vstream_connect_ex(addr, ACL_BLOCKING, + conn_timeout, rw_timeout, 8192, NULL)); +} + +ACL_VSTREAM *private_vstream_connect_ex(const char *addr, int block_mode, + int conn_timeout, int rw_timeout, int rw_bufsize, int *he_errorp) +{ + ACL_VSTREAM *stream; + ACL_SOCKET fd; + char *ptr; + + acl_assert(addr && *addr); + ptr = strchr(addr, ':'); + if (ptr) + fd = acl_inet_connect_ex(addr, ACL_BLOCKING, conn_timeout, he_errorp); +#ifdef ACL_MS_WINDOWS + else + return (NULL); +#elif defined(ACL_UNIX) + else + fd = acl_unix_connect(addr, block_mode, conn_timeout); +#else + else + return (NULL); +#endif + + if (fd == ACL_SOCKET_INVALID) + return (NULL); + stream = private_vstream_fdopen(fd, ACL_VSTREAM_FLAG_RW, rw_bufsize, + rw_timeout, ACL_VSTREAM_TYPE_SOCK); + acl_assert(stream); + + if (acl_getpeername(ACL_VSTREAM_SOCK(stream), + stream->remote_addr, + sizeof(stream->remote_addr) - 1) < 0) + { + snprintf(stream->remote_addr, + sizeof(stream->remote_addr) - 1, "%s", addr); + } + + return (stream); +} + +void private_vstream_free(ACL_VSTREAM *stream) +{ + if (stream->nrefer > 0) { + /* 设置延迟释放标志位 */ + stream->flag |= ACL_VSTREAM_FLAG_DEFER_FREE; + return; + } + + if (stream->close_handle_lnk != NULL) { + ACL_VSTREAM_CLOSE_HANDLE *close_handle; + int i, n = private_array_size(stream->close_handle_lnk); + + /* 因为添加时是正序的, 所以在删除时是倒序的, + * 这样对动态数组的使用的效率才会比较高, + * 避免了动态数组内部移动的情况 + */ + for (i = n - 1; i >= 0; i++) { + close_handle = (ACL_VSTREAM_CLOSE_HANDLE *) + private_array_index(stream->close_handle_lnk, i); + if (close_handle == NULL) + break; + if (close_handle->close_fn == NULL) + continue; + /* 只所将此调用放在 close_fn 前面,是为了防止有人误在 close_fn + * 里调用了删除回调函数的操作而造成对同一内存的多次释放 + */ + private_array_delete(stream->close_handle_lnk, i, NULL); + close_handle->close_fn(stream, close_handle->context); + free(close_handle); + } + private_array_destroy(stream->close_handle_lnk, NULL); + } + + if (stream->read_buf != NULL) + free(stream->read_buf); + + ACL_VSTREAM_SOCK(stream) = ACL_SOCKET_INVALID; + ACL_VSTREAM_FILE(stream) = ACL_FILE_INVALID; + free(stream); +} + +int private_vstream_close(ACL_VSTREAM *stream) +{ + int ret = 0; + + if (stream->nrefer > 0) { + /* 设置延迟释放标志位 */ + stream->flag |= ACL_VSTREAM_FLAG_DEFER_FREE; + return (0); + } + + if (stream->wbuf_dlen > 0) + (void) private_vstream_fflush(stream); + + if (stream->close_handle_lnk != NULL) { + ACL_VSTREAM_CLOSE_HANDLE *close_handle; + int i, n = private_array_size(stream->close_handle_lnk); + + /* 因为添加时是正序的, 所以在删除时是倒序的, + * 这样对动态数组的使用的效率才会比较高, + * 避免了动态数组内部移动的情况 + */ + for (i = n - 1; i >= 0; i--) { + close_handle = (ACL_VSTREAM_CLOSE_HANDLE *) + private_array_index(stream->close_handle_lnk, i); + if (close_handle == NULL) + continue; + if (close_handle->close_fn == NULL) + continue; + /* 只所将此调用放在 close_fn 前面,是为了防止有人误在 close_fn + * 里调用了删除回调函数的操作而造成对同一内存的多次释放 + */ + private_array_delete(stream->close_handle_lnk, i, NULL); + close_handle->close_fn(stream, close_handle->context); + free(close_handle); + } + private_array_destroy(stream->close_handle_lnk, NULL); + } + + if (ACL_VSTREAM_SOCK(stream) != ACL_SOCKET_INVALID && stream->close_fn) + ret = stream->close_fn(ACL_VSTREAM_SOCK(stream)); + else if (ACL_VSTREAM_FILE(stream) != ACL_FILE_INVALID && stream->fclose_fn) + ret = stream->fclose_fn(ACL_VSTREAM_FILE(stream)); + if (stream->read_buf != NULL) + free(stream->read_buf); + if (stream->wbuf != NULL) + free(stream->wbuf); + free(stream); + return (ret); +} diff --git a/lib_acl/src/private/private_vstream.h b/lib_acl/src/private/private_vstream.h new file mode 100644 index 000000000..789e42f32 --- /dev/null +++ b/lib_acl/src/private/private_vstream.h @@ -0,0 +1,27 @@ +#ifndef __PRIVATE_VSTREAM_INCLUDE_H__ +#define __PRIVATE_VSTREAM_INCLUDE_H__ + +#include "stdlib/acl_vstream.h" + +int private_vstream_getc(ACL_VSTREAM *stream); +int private_vstream_ungetc(ACL_VSTREAM *stream, int ch); +int private_vstream_gets(ACL_VSTREAM *stream, void *vptr, size_t maxlen); +int private_vstream_gets_nonl(ACL_VSTREAM *stream, void *vptr, size_t maxlen); +int private_vstream_readn(ACL_VSTREAM *stream, void *vptr, size_t maxlen); +int private_vstream_read(ACL_VSTREAM *stream, void *vptr, size_t maxlen); +int private_vstream_write(ACL_VSTREAM *stream, const void *vptr, size_t dlen); +int private_vstream_writen(ACL_VSTREAM *stream, const void *vptr, size_t dlen); +int private_vstream_buffed_writen(ACL_VSTREAM *stream, const void *vptr, size_t dlen); +int private_vstream_fflush(ACL_VSTREAM *stream); +ACL_VSTREAM *private_vstream_fhopen(ACL_FILE_HANDLE fh, unsigned int oflags); +ACL_VSTREAM *private_vstream_fdopen(ACL_SOCKET fd, unsigned int oflags, + size_t buflen, int rw_timeo, int fdtype); +ACL_VSTREAM *private_vstream_fopen(const char *path, unsigned int oflags, int mode, size_t buflen); +ACL_VSTREAM *private_vstream_connect(const char *addr, int conn_timeout, int rw_timeout); +ACL_VSTREAM *private_vstream_connect_ex(const char *addr, int block_mode, + int conn_timeout, int rw_timeout, int rw_bufsize, int *he_errorp); +void private_vstream_ctl(ACL_VSTREAM *stream, int name,...); +void private_vstream_free(ACL_VSTREAM *stream); +int private_vstream_close(ACL_VSTREAM *stream); + +#endif diff --git a/lib_acl/src/private/sem.c b/lib_acl/src/private/sem.c new file mode 100644 index 000000000..b2864ce11 --- /dev/null +++ b/lib_acl/src/private/sem.c @@ -0,0 +1,117 @@ +/* Semaphore functions using the Win32 API */ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#endif + +#ifdef ACL_MS_WINDOWS + +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "thread/acl_pthread.h" +#include "thread/acl_sem.h" + +#include "sem.h" + +/* Create a semaphore */ +ACL_SEM *sem_create2(const char *pathname, unsigned int initial_value) +{ + ACL_SEM *sem; + + /* Allocate sem memory */ + sem = (ACL_SEM *) malloc(sizeof(*sem)); + acl_assert(sem); + /* Create the semaphore, with max value 32K */ + sem->id = CreateSemaphore(NULL, initial_value, 32 * 1024, pathname); + sem->count = initial_value; + acl_assert(sem->id); + + return(sem); +} + +ACL_SEM *sem_create(unsigned int initial_value) +{ + return (sem_create2(NULL, initial_value)); +} + +/* Free the semaphore */ +void sem_destroy(ACL_SEM *sem) +{ + if (sem) { + if (sem->id) { + CloseHandle(sem->id); + sem->id = 0; + } + free(sem); + } +} + +int sem_wait_timeout(ACL_SEM *sem, unsigned int timeout) +{ + int retval; + DWORD dwMilliseconds; + + acl_assert(sem != NULL); + + if (timeout == ACL_MUTEX_MAXWAIT) { + dwMilliseconds = INFINITE; + } else { + dwMilliseconds = (DWORD) timeout; + } + + switch (WaitForSingleObject(sem->id, dwMilliseconds)) { + case WAIT_OBJECT_0: + --sem->count; + retval = 0; + break; + case WAIT_TIMEOUT: + retval = ACL_ETIMEDOUT; + break; + default: + retval = -1; + break; + } + return retval; +} + +int sem_try_wait(ACL_SEM *sem) +{ + return sem_wait_timeout(sem, 0); +} + +int sem_wait(ACL_SEM *sem) +{ + return sem_wait_timeout(sem, ACL_MUTEX_MAXWAIT); +} + +/* Returns the current count of the semaphore */ +unsigned int sem_value(ACL_SEM *sem) +{ + acl_assert(sem != NULL); + return sem->count; +} + +int sem_post(ACL_SEM *sem) +{ + acl_assert(sem != NULL); + /* Increase the counter in the first place, because + * after a successful release the semaphore may + * immediately get destroyed by another thread which + * is waiting for this semaphore. + */ + ++sem->count; + + if (ReleaseSemaphore(sem->id, 1, NULL) == FALSE) { + --sem->count; /* restore */ + return -1; + } + return 0; +} + +#endif /* ACL_MS_WINDOWS */ diff --git a/lib_acl/src/private/sem.h b/lib_acl/src/private/sem.h new file mode 100644 index 000000000..7247f2c3d --- /dev/null +++ b/lib_acl/src/private/sem.h @@ -0,0 +1,28 @@ + +#ifndef __INTERNAL_SEM_INCLUDE_H__ +#define __INTERNAL_SEM_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif +#include "stdlib/acl_define.h" + +#ifdef ACL_MS_WINDOWS +#include "thread/acl_sem.h" + +ACL_SEM *sem_create2(const char *pathname, unsigned int initial_value); +ACL_SEM *sem_create(unsigned int initial_value); +void sem_destroy(ACL_SEM *sem); +int sem_wait_timeout(ACL_SEM *sem, unsigned int timeout); +int sem_try_wait(ACL_SEM *sem); +int sem_wait(ACL_SEM *sem); +unsigned int sem_value(ACL_SEM *sem); +int sem_post(ACL_SEM *sem); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/src/private/thread.h b/lib_acl/src/private/thread.h new file mode 100644 index 000000000..10a762278 --- /dev/null +++ b/lib_acl/src/private/thread.h @@ -0,0 +1,37 @@ +#ifndef __INTERNAL_THREAD_INCLUDE_H__ +#define __INTERNAL_THREAD_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_define.h" +#include "thread/acl_pthread.h" + +#ifdef ACL_HAS_PTHREAD +int thread_mutex_destroy(acl_pthread_mutex_t *mutex); +# define thread_mutex_init pthread_mutex_init +# define thread_mutex_lock pthread_mutex_lock +# define thread_mutex_unlock pthread_mutex_unlock +#else + +/* in thread_mutex.c */ +int thread_mutex_destroy(acl_pthread_mutex_t *mutex); +int thread_mutex_init(acl_pthread_mutex_t *mutex, const acl_pthread_mutexattr_t *mattr); +int thread_mutex_lock(acl_pthread_mutex_t *mutex); +int thread_mutex_unlock(acl_pthread_mutex_t *mutex); + +#define thread_mutex_trylock thread_mutex_lock + +#endif /* ACL_HAS_PTHREAD */ + +/* general functions */ + +/* in acl_pthread_mutex.c */ +acl_pthread_mutex_t *thread_mutex_create(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/src/private/thread_mutex.c b/lib_acl/src/private/thread_mutex.c new file mode 100644 index 000000000..608a3895b --- /dev/null +++ b/lib_acl/src/private/thread_mutex.c @@ -0,0 +1,107 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "thread/acl_pthread.h" + +#endif + +#include "sem.h" +#include "thread.h" +#ifndef ACL_HAS_PTHREAD + +int thread_mutex_init(acl_pthread_mutex_t *mutex, const acl_pthread_mutexattr_t *mattr) +{ + acl_assert(mutex != NULL); + + mutex->dynamic = 0; + + /* Create the mutex, with initial value signaled */ + mutex->id = CreateMutex((SECURITY_ATTRIBUTES *) mattr, FALSE, NULL); + acl_assert(mutex->id); + return (0); +} + +acl_pthread_mutex_t *thread_mutex_create(void) +{ + acl_pthread_mutex_t *mutex; + + mutex = calloc(1, sizeof(acl_pthread_mutex_t)); + acl_assert(mutex); + mutex->dynamic = 1; + + /* Create the mutex, with initial value signaled */ + mutex->id = CreateMutex(NULL, FALSE, NULL); + acl_assert(mutex->id); + return (mutex); +} + +/* Free the mutex */ +int thread_mutex_destroy(acl_pthread_mutex_t *mutex) +{ + if (mutex) { + if (mutex->id) { + CloseHandle(mutex->id); + mutex->id = 0; + } + if (mutex->dynamic) + free(mutex); + return (0); + } else + return (-1); +} + +int thread_mutex_lock(acl_pthread_mutex_t *mutex) +{ + acl_assert(mutex); + + if (WaitForSingleObject(mutex->id, INFINITE) == WAIT_FAILED) + return (-1); + + return (0); +} + +int thread_mutex_unlock(acl_pthread_mutex_t *mutex) +{ + acl_assert(mutex); + + if (ReleaseMutex(mutex->id) == FALSE) + return (-1); + + return (0); +} + +#elif defined(ACL_UNIX) + +#include + +acl_pthread_mutex_t *thread_mutex_create(void) +{ + acl_pthread_mutex_t *mutex; + int status; + + mutex = (acl_pthread_mutex_t *) malloc(sizeof(acl_pthread_mutex_t)); + acl_assert(mutex); + if ((status = pthread_mutex_init(mutex, NULL)) < 0) { + free(mutex); + return (NULL); + } + + return (mutex); +} + +int thread_mutex_destroy(acl_pthread_mutex_t *mutex) +{ + pthread_mutex_destroy(mutex); + free(mutex); + return (0); +} + +#endif /* ACL_HAS_PTHREAD */ diff --git a/lib_acl/src/proctl/acl_proctl.c b/lib_acl/src/proctl/acl_proctl.c new file mode 100644 index 000000000..12cf586b5 --- /dev/null +++ b/lib_acl/src/proctl/acl_proctl.c @@ -0,0 +1,376 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include "stdlib/acl_stdlib.h" +#include "proctl/acl_proctl.h" + +#endif /* ACL_PREPARE_COMPILE */ + +#ifdef ACL_MS_WINDOWS + +#include "net/acl_net.h" +#include "thread/acl_thread.h" +#include "proctl_internal.h" +#include + +char *var_progname = NULL; + +static void proctl_init(const char *progname) +{ + acl_socket_init(); +} + +static void proctl_start_init(const char *progname) +{ + proctl_init(progname); + proctl_service_init(); +} + +void acl_proctl_daemon_path(char *buf, size_t size) +{ + const char *myname = "acl_proctl_daemon_path"; + + if (buf == NULL || size <= 0) { + acl_msg_error("%s(%d): input invalid", myname, __LINE__); + return; + } + get_exec_path(buf, size); +} + +void acl_proctl_deamon_init(const char *progname) +{ + acl_pthread_attr_t attr; + acl_pthread_t tid; + + var_progname = acl_mystrdup(progname); + proctl_start_init(var_progname); + acl_pthread_attr_init(&attr); + (void) acl_pthread_attr_setdetachstate(&attr, 1); + acl_pthread_create(&tid, &attr, proctl_monitor_thread, NULL); +} + +void acl_proctl_daemon_loop() +{ + const char *myname = "acl_proctl_daemon_loop"; + time_t tm_start, tm_end; + + while (1) { + tm_start = time(NULL); + proctl_service_wait(); + proctl_service_join(); + tm_end = time(NULL); + + if (tm_end - tm_start <= 1) { + acl_msg_warn("%s(%d): start process too fast, sleep 2 second", + myname, __LINE__); + sleep(2); + } + } +} + +int acl_proctl_deamon_start_one(const char *progchild, int argc, char *argv[]) +{ + const char *myname = "acl_proctl_deamon_start_one"; + PROCTL_SERVICE *service; + + if (proctl_service_exist(progchild)) { + acl_msg_error("%s(%d): child(%s) maybe be running!", + myname, __LINE__, progchild); + return (-1); + } + + service = proctl_service_new(progchild, argc, argv); + if (proctl_service_start(service) < 0) { + proctl_service_free(service); + return (-1); + } + + return (0); +} + +/* 打开与控制进程的监听线程之间的数据连接 */ +static ACL_VSTREAM *proctl_client_open(const char *progname) +{ + const char *myname = "proctl_client_open"; + char ebuf[256], lock_file[MAX_PATH], addr[256]; + ACL_VSTREAM *client; + + proctl_init(progname); + + get_lock_file(lock_file, sizeof(lock_file)); + + if (get_addr_from_file(lock_file, addr, sizeof(addr)) < 0) + acl_msg_fatal("%s(%d): get addr from file(%s) error(%s)", + myname, __LINE__, lock_file, acl_last_strerror(ebuf, sizeof(ebuf))); + + client = acl_vstream_connect(addr, ACL_BLOCKING, 10, 10, 1024); + if (client == NULL) + acl_msg_fatal("%s(%d): connect addr(%s) error(%s)", + myname, __LINE__, addr, acl_last_strerror(ebuf, sizeof(ebuf))); + + return (client); +} + +/* 关闭与控制进程的监听线程之间的数据连接 */ +static void proctl_client_close(ACL_VSTREAM *client) +{ + acl_vstream_close(client); +} + +void acl_proctl_start_one(const char *progname, + const char *progchild, int argc, char *argv[]) +{ + const char *myname = "acl_proctl_start_one"; + char ebuf[256], buf[1024]; + ACL_VSTREAM *client; + ACL_VSTRING *child_args = NULL; + int n; + + if (argc > 0) { + int i; + + child_args = acl_vstring_alloc(256); + for (i = 0; i < argc; i++) { + if (i > 0) + acl_vstring_strcat(child_args, " "); + acl_vstring_strcat(child_args, "\""); + acl_vstring_strcat(child_args, argv[i]); + acl_vstring_strcat(child_args, "\""); + } + + } + + /* 打开与控制进程之间的连接 */ + client = proctl_client_open(progname); + if (child_args) { + /* 向控制进程发送消息,带有控制参数 */ + n = acl_vstream_fprintf(client, "%s|-d|START|-f|%s|-a|%s\r\n", + progname, progchild, acl_vstring_str(child_args)); + } else { + /* 向控制进程发送消息,不带控制参数 */ + n = acl_vstream_fprintf(client, "%s|-d|START|-f|%s\r\n", + progname, progchild); + } + + if (child_args != NULL) + acl_vstring_free(child_args); + + if (n == ACL_VSTREAM_EOF) + acl_msg_fatal("%s(%d): fprintf to acl_proctl error(%s)", + myname, __LINE__, acl_last_strerror(ebuf, sizeof(ebuf))); + + /* 接收所有来自于控制进程的消息响应结果 */ + while (1) { + n = acl_vstream_gets_nonl(client, buf, sizeof(buf)); + if (n == ACL_VSTREAM_EOF) + break; + acl_msg_info("%s(%d): %s", myname, __LINE__, buf); + } + + proctl_client_close(client); +} + +void acl_proctl_stop_one(const char *progname, + const char *progchild, int argc, char *argv[]) +{ + const char *myname = "acl_proctl_stop_one"; + char ebuf[256], buf[1024]; + ACL_VSTREAM *client; + ACL_VSTRING *child_args = NULL; + int n; + + if (argc > 0) { + int i; + + child_args = acl_vstring_alloc(256); + for (i = 0; i < argc; i++) { + if (i > 0) + acl_vstring_strcat(child_args, " "); + acl_vstring_strcat(child_args, "\""); + acl_vstring_strcat(child_args, argv[i]); + acl_vstring_strcat(child_args, "\""); + } + + } + + client = proctl_client_open(progname); + if (child_args) + n = acl_vstream_fprintf(client, "%s|-d|STOP|-f|%s|-a|%s\r\n", + progname, progchild, acl_vstring_str(child_args)); + else + n = acl_vstream_fprintf(client, "%s|-d|STOP|-f|%s\r\n", + progname, progchild); + + if (child_args != NULL) + acl_vstring_free(child_args); + + if (n == ACL_VSTREAM_EOF) + acl_msg_fatal("%s(%d): fprintf to acl_proctl error(%s)", + myname, __LINE__, acl_last_strerror(ebuf, sizeof(ebuf))); + + while (1) { + n = acl_vstream_gets_nonl(client, buf, sizeof(buf)); + if (n == ACL_VSTREAM_EOF) + break; + acl_msg_info("%s(%d): %s", myname, __LINE__, buf); + } + + proctl_client_close(client); +} + +void acl_proctl_stop_all(const char *progname) +{ + acl_proctl_stop_one(progname, "all", 0, NULL); +} + +void acl_proctl_quit(const char *progname) +{ + const char *myname = "acl_proctl_quit"; + char ebuf[256], buf[1024]; + ACL_VSTREAM *client; + int n; + + client = proctl_client_open(progname); + n = acl_vstream_fprintf(client, "%s|-d|QUIT\r\n", progname); + if (n == ACL_VSTREAM_EOF) + acl_msg_fatal("%s(%d): fprintf to acl_proctl error(%s)", + myname, __LINE__, acl_last_strerror(ebuf, sizeof(ebuf))); + + while (1) { + n = acl_vstream_gets_nonl(client, buf, sizeof(buf)); + if (n == ACL_VSTREAM_EOF) + break; + acl_debug(ACL_DEBUG_PROCTL, 2) ("%s(%d): buf(%s)", + myname, __LINE__, buf); + } + + proctl_client_close(client); +} + +void acl_proctl_list(const char *progname) +{ + const char *myname = "acl_proctl_list"; + char ebuf[256], buf[1024]; + ACL_VSTREAM *client; + int n; + + client = proctl_client_open(progname); + n = acl_vstream_fprintf(client, "%s|-d|LIST\r\n", progname); + if (n == ACL_VSTREAM_EOF) + acl_msg_fatal("%s(%d): fprintf to acl_proctl error(%s)", + myname, __LINE__, acl_last_strerror(ebuf, sizeof(ebuf))); + + while (1) { + if (acl_vstream_gets_nonl(client, buf, sizeof(buf)) == ACL_VSTREAM_EOF) + break; + acl_debug(ACL_DEBUG_PROCTL, 2) ("%s(%d): buf(%s)", + myname, __LINE__, buf); + printf("%s\r\n", buf); + } + + proctl_client_close(client); +} + +void acl_proctl_probe(const char *progname, const char *progchild) +{ + const char *myname = "acl_proctl_list"; + char ebuf[256], buf[1024]; + ACL_VSTREAM *client; + int n; + + client = proctl_client_open(progname); + n = acl_vstream_fprintf(client, "%s|-d|PROBE|-f|%s\r\n", + progname, progchild); + if (n == ACL_VSTREAM_EOF) + acl_msg_fatal("%s(%d): fprintf to acl_proctl error(%s)", + myname, __LINE__, acl_last_strerror(ebuf, sizeof(ebuf))); + + while (1) { + if (acl_vstream_gets_nonl(client, buf, sizeof(buf)) == ACL_VSTREAM_EOF) + break; + acl_debug(ACL_DEBUG_PROCTL, 2) ("%s(%d): buf(%s)", + myname, __LINE__, buf); + printf("%s\r\n", buf); + } + + proctl_client_close(client); +} + +void acl_proctl_child(const char *progname, void (*onexit_fn)(void *), void *arg) +{ + acl_pthread_attr_t attr; + acl_pthread_t tid; + + proctl_child_atexit(onexit_fn, arg); + var_progname = acl_mystrdup(progname); + acl_pthread_attr_init(&attr); + (void) acl_pthread_attr_setdetachstate(&attr, 1); + acl_pthread_create(&tid, &attr, proctl_child_thread, NULL); +} +#else +void acl_proctl_deamon_init(const char *progname acl_unused) +{ + const char *myname = "acl_proctl_deamon_init"; + + acl_msg_fatal("%s(%d): not support!", myname, __LINE__); +} + +void acl_proctl_daemon_loop() +{ + const char *myname = "acl_proctl_daemon_loop"; + + acl_msg_fatal("%s(%d): not support!", myname, __LINE__); +} + +int acl_proctl_deamon_start_one(const char *progchild acl_unused, + int argc acl_unused, char *argv[] acl_unused) +{ + const char *myname = "acl_proctl_deamon_start_one"; + + acl_msg_fatal("%s(%d): not support!", myname, __LINE__); + + return (-1); +} + +void acl_proctl_start_one(const char *progname acl_unused, + const char *progchild acl_unused, + int argc acl_unused, char *argv[] acl_unused) +{ + const char *myname = "acl_proctl_start_one"; + + acl_msg_fatal("%s(%d): not support!", myname, __LINE__); +} + +void acl_proctl_stop_one(const char *progname acl_unused, + const char *progchild acl_unused, + int argc acl_unused, char *argv[] acl_unused) +{ + const char *myname = "acl_proctl_stop_one"; + + acl_msg_fatal("%s(%d): not support!", myname, __LINE__); +} + +void acl_proctl_stop_all(const char *progname acl_unused) +{ + const char *myname = "acl_proctl_stop_all"; + + acl_msg_fatal("%s(%d): not support!", myname, __LINE__); +} + +void acl_proctl_quit(const char *progname acl_unused) +{ + const char *myname = "acl_proctl_quit"; + + acl_msg_fatal("%s(%d): not support!", myname, __LINE__); +} + +void acl_proctl_child(const char *progname acl_unused, + void (*onexit_fn)(void *) acl_unused, void *arg acl_unused) +{ + const char *myname = "acl_proctl_child"; + + acl_msg_fatal("%s(%d): not support!", myname, __LINE__); +} +#endif /* ACL_MS_WINDOWS */ + diff --git a/lib_acl/src/proctl/proctl_child.c b/lib_acl/src/proctl/proctl_child.c new file mode 100644 index 000000000..ac571cbbe --- /dev/null +++ b/lib_acl/src/proctl/proctl_child.c @@ -0,0 +1,168 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#endif /* ACL_PREPARE_COMPILE */ + +#ifdef ACL_MS_WINDOWS + +#include "stdlib/acl_stdlib.h" +#include "net/acl_net.h" +#include +#include "proctl_internal.h" + +static void (*__onexit_fn)(void*) = NULL; +static void *__onexit_arg = NULL; + +static void usage(ACL_VSTREAM *client) +{ + acl_vstream_fprintf(client, + "usage: %s -h[help]|-d|STOP|-f|filepath|[-a|args]\r\n", var_progname); + acl_msg_info("usage: %s -h[help]|-d|STOP|-f|filepath|[-a|args]\r\n", + var_progname); +} + +static void proctl_child_cmd_stop(ACL_VSTREAM *client, const char *filepath) +{ + const char *myname = "proctl_child_cmd_stop"; + + if (filepath[0] == 0) { + acl_vstream_fprintf(client, "-ERR|filepath null\r\n"); + acl_msg_error("%s(%d): no filepath", myname, __LINE__); + return; + } + + if (strcasecmp(filepath, var_progname) != 0) { + acl_vstream_fprintf(client, "-ERR|filepath(%s)!=progname(%s)\r\n", + filepath, var_progname); + acl_msg_error("%s(%d): filepath=(%s) invalid, progname=(%s)", + myname, __LINE__, filepath, var_progname); + return; + } + + acl_vstream_fprintf(client, "+OK|%s is stopping\r\n", filepath); + acl_vstream_close(client); /* 显式关闭是为了将数据传输完 */ + + if (__onexit_fn) { + acl_msg_info("%s(%d): call onexit_fn before exit, filepath(%s) ", + myname, __LINE__, filepath); + __onexit_fn(__onexit_arg); + } + + acl_msg_info("%s(%d): filepath(%s) exit now", myname, __LINE__, filepath); + exit(0); +} + +static int proctl_child_main(ACL_VSTREAM *client, int argc, char *argv[]) +{ + const char *myname = "proctl_child_main"; + char cmd[256], filepath[256], args[256]; + int i; + + cmd[0] = 0; + filepath[0] = 0; + args[0] = 0; + + /* "d:f:a:h" */ + for (i = 0; i < argc; i++) { + if (argv[i][0] != '-') + continue; + + switch (argv[i][1]) { + case 'h': + usage(client); + return (0); + case 'd': + if (argv[++i] == NULL) { + usage(client); + return (0); + } + ACL_SAFE_STRNCPY(cmd, argv[i], sizeof(cmd)); + break; + case 'f': + if (argv[++i] == NULL) { + usage(client); + return (0); + } + ACL_SAFE_STRNCPY(filepath, argv[i], sizeof(filepath)); + break; + case 'a': + if (argv[++i] == NULL) { + usage(client); + return (0); + } + ACL_SAFE_STRNCPY(args, argv[i], sizeof(args)); + break; + default: + break; + } + } + + if (strcasecmp(cmd, "STOP") == 0) { + proctl_child_cmd_stop(client, filepath); + } else { + usage(client); + acl_msg_warn("%s(%d): unknown cmd(%s)", myname, __LINE__, cmd); + } + + return (0); +} + +static void proctl_child_loop(ACL_VSTREAM *sstream) +{ + const char *myname = "proctl_child_loop"; + ACL_VSTREAM *client; + int n; + char buf[1024]; + ACL_ARGV *cmd_argv; + + while (1) { + client = acl_vstream_accept(sstream, NULL, 0); + if (client == NULL) + continue; + + n = acl_vstream_gets_nonl(client, buf, sizeof(buf)); + if (n == ACL_VSTREAM_EOF) + continue; + + acl_debug(ACL_DEBUG_PROCTL, 2) ("%s(%d): get buf(%s)", + myname, __LINE__, buf); + cmd_argv = acl_argv_split(buf, "|"); + if (cmd_argv) + proctl_child_main(client, cmd_argv->argc, cmd_argv->argv); + else + acl_msg_error("%s(%d): buf(%s) invalid", myname, __LINE__, buf); + acl_vstream_close(client); + } +} + +void proctl_child_atexit(void (*onexit_fn)(void*), void *arg) +{ + __onexit_fn = onexit_fn; + __onexit_arg = arg; +} + +/* 服务子进程单独处理消息的线程 */ +void *proctl_child_thread(void *arg) +{ + const char *myname = "ptoctl_child_thread"; + ACL_VSTREAM *sstream; + char ebuf[256]; + + sstream = local_listen(); + if (sstream == NULL) { + acl_msg_error("%s(%d): local_listen error(%s), maybe there's another" + " instance is running", myname, __LINE__, + acl_last_strerror(ebuf, sizeof(ebuf))); + /* XXX: 此处必须以0的方式退出程序运行,以防止被父进程频繁启动 */ + exit(0); + } + + proctl_child_loop(sstream); + + return (NULL); +} + +#endif /* ACL_MS_WINDOWS */ + diff --git a/lib_acl/src/proctl/proctl_internal.h b/lib_acl/src/proctl/proctl_internal.h new file mode 100644 index 000000000..1a9614fbf --- /dev/null +++ b/lib_acl/src/proctl/proctl_internal.h @@ -0,0 +1,73 @@ +#ifndef __PROCTL_INTERNAL_INCLUDE_H__ +#define __PROCTL_INTERNAL_INCLUDE_H__ + +#include "stdlib/acl_define.h" + +#ifdef ACL_MS_WINDOWS +#include "stdlib/acl_stdlib.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct PROCTL_SERVICE { + HANDLE hProcess; + char *filepath; + ACL_VSTRING *cmdline; + STARTUPINFO start_info; + PROCESS_INFORMATION process_info; +} PROCTL_SERVICE; + +typedef struct PROCTL_MSG { + int msg_type; +#define PROCTL_MSG_NULL 0 /* 空消息 */ +#define PROCTL_MSG_START 1 /* 启动某个服务程序 */ +#define PROCTL_MSG_STOP 2 /* 停止某个服务程序 */ +#define PROCTL_MSG_QUIT 3 /* 停止所有服务程序并退出 */ +#define PROCTL_MSG_LIST 4 /* 列出当前正在运行的服务程序 */ +#define PROCTL_MSG_CHECK 5 /* 检查某个服务程序是否在运行 */ + + PROCTL_SERVICE *service; + void *arg; + void (*free_fn)(void *); +} PROCTL_MSG; + +/* in acl_proctl_main.cpp */ +extern char *var_progname; + +/* in proctl_service.cpp */ +PROCTL_MSG *proctl_msg_new(int msg_type); +void proctl_msg_free(PROCTL_MSG *msg); +void proctl_service_init(void); +PROCTL_SERVICE *proctl_service_alloc(const char *filepath, ACL_VSTRING *cmdline); +PROCTL_SERVICE *proctl_service_new(const char *filepath, int argc, char *argv[]); +void proctl_service_free(PROCTL_SERVICE *service); +ACL_ARGV *proctl_serivce_get_all(void); +void proctl_service_free_all(ACL_ARGV *argv); +int proctl_service_exist(const char *filepath); +int proctl_service_start(PROCTL_SERVICE *service); +int proctl_service_wait(void); +int proctl_service_join(void); +void proctl_msg_push(PROCTL_MSG *msg); + +/* in proctl_monitor.cpp */ +void *proctl_monitor_thread(void *arg); + +/* in proctl_child.cpp */ +void proctl_child_atexit(void (*onexit_fn)(void*), void *arg); +void *proctl_child_thread(void *arg); + +/* in proctl_utils.cpp */ +void get_lock_file(char *buf, size_t size); +void get_exec_path(char *buf, size_t size); +void get_lock_file2(const char *filepath, char *buf, size_t size); +int get_addr_from_file(const char *filepath, char *buf, size_t size); +ACL_VSTREAM *local_listen(void); + +#ifdef __cplusplus +} +#endif + +#endif /* ACL_MS_WINDOWS */ +#endif + diff --git a/lib_acl/src/proctl/proctl_monitor.c b/lib_acl/src/proctl/proctl_monitor.c new file mode 100644 index 000000000..9f76681c0 --- /dev/null +++ b/lib_acl/src/proctl/proctl_monitor.c @@ -0,0 +1,336 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#endif /* ACL_PREPARE_COMPILE */ + +#ifdef ACL_MS_WINDOWS +#include "stdlib/acl_stdlib.h" +#include "net/acl_net.h" +#include +#include +#include "proctl_internal.h" + +/* 连接某个服务进程的监听接口,发送停止消息 */ +static void proctl_monitor_stop_service(ACL_VSTREAM *client, + const char *filepath, const char *args) +{ + const char *myname = "proctl_monitor_stop_service"; + ACL_VSTREAM *stream; + char addr[256], ebuf[256], buf[1024], logfile[MAX_PATH]; + int n; + + get_lock_file2(filepath, logfile, sizeof(logfile)); + + if (get_addr_from_file(logfile, addr, sizeof(addr)) < 0) { + acl_vstream_fprintf(client, "-ERR|get addr error from %s\r\n", filepath); + acl_msg_error("%s(%d): get addr for filepath(%s) error", + myname, __LINE__, filepath); + return; + } + + stream = acl_vstream_connect(addr, ACL_BLOCKING, 10, 10, 1024); + if (stream == NULL) { + acl_vstream_fprintf(client, "-ERR|connect addr=%s error, file=%s\r\n", + addr, filepath); + acl_msg_error("%s(%d): connect addr(%s) error(%s)", + myname, __LINE__, addr, acl_last_strerror(ebuf, sizeof(ebuf))); + return; + } + + if (args && *args) + n = acl_vstream_fprintf(stream, "%s|-d|STOP|-f|%s|-a|%s\r\n", + filepath, filepath, args); + else + n = acl_vstream_fprintf(stream, "%s|-d|STOP|-f|%s\r\n", + filepath, filepath); + + buf[0] = 0; + + if (n == ACL_VSTREAM_EOF) { + acl_vstream_fprintf(client, "-ERR|write to addr=%s error, file=%s\r\n", + addr, filepath); + acl_msg_error("%s(%d): fprintf to acl_master error(%s)", + myname, __LINE__, acl_last_strerror(ebuf, sizeof(ebuf))); + } else if (acl_vstream_gets_nonl(stream, buf, sizeof(buf)) == ACL_VSTREAM_EOF) { + acl_vstream_fprintf(client, "-ERR|filepath(%s), not get respond\r\n", filepath); + acl_msg_error("%s(%d): not get respond, filepath(%s)", + myname, __LINE__, filepath); + } else if (strncasecmp(buf, "+OK", 3) != 0) { + acl_vstream_fprintf(client, "-ERR|filepath(%s), child respond(%s)\r\n", + filepath, buf); + acl_msg_error("%s(%d): child respond error(%s), filepath(%s)", + myname, __LINE__, buf, filepath); + } else { + acl_vstream_fprintf(client, "+OK|stopped %s\r\n", filepath); + acl_msg_info("%s(%d): stop child(%s) ok", myname, __LINE__, filepath); + } + + acl_vstream_close(stream); +} + +/* 停止所有服务进程 */ +static void proctl_monitor_stop_all_service(ACL_VSTREAM *client) +{ + ACL_ARGV *service_argv; + int i; + + service_argv = proctl_serivce_get_all(); + if (service_argv == NULL) { + acl_vstream_fprintf(client, "+OK|no service running yet!\r\n"); + return; + } + + for (i = 0; i < service_argv->argc; i++) { + proctl_monitor_stop_service(client, service_argv->argv[i], NULL); + } + + proctl_service_free_all(service_argv); +} + +/* 停止某个服务进程 */ +static int proctl_monitor_cmd_stop(ACL_VSTREAM *client, + const char *filepath, const char *args) +{ + const char *myname = "proctl_monitor_cmd_stop"; + + if (filepath == NULL || *filepath == 0) { + acl_vstream_fprintf(client, "-ERR|filepath null\r\n"); + acl_msg_error("%s(%d): no filepath", myname, __LINE__); + return (-1); + } + + if (strcasecmp(filepath, "all") == 0) { + acl_msg_info("begin to stop file(%s)", filepath); + proctl_monitor_stop_all_service(client); + } else if (!proctl_service_exist(filepath)) { + acl_msg_error("%s(%d): filepath(%s) not running now", + myname, __LINE__, filepath); + acl_vstream_fprintf(client, "-ERR|filepath(%s) not running\r\n", + filepath); + return (-1); + } + + acl_msg_info("%s(%d): begin to stop file(%s)", myname, __LINE__, filepath); + proctl_monitor_stop_service(client, filepath, args); + acl_msg_info("%s(%d): stop (%s) end", myname, __LINE__, filepath); + return (0); +} + +/* 通知主线程,启动一个服务 */ +static int proctl_monitor_cmd_start(ACL_VSTREAM *client, + const char *filepath, const char *args) +{ + const char *myname = "proctl_monitor_cmd_start"; + ACL_VSTRING *cmdline; + PROCTL_SERVICE *service; + PROCTL_MSG *msg; + + if (filepath[0] == 0) { + acl_vstream_fprintf(client, "-ERR|filepath null\r\n"); + acl_msg_error("%s(%d): no filepath", myname, __LINE__); + return (-1); + } + + if (proctl_service_exist(filepath)) { + acl_msg_error("%s(%d): child(%s) maybe be running!", + myname, __LINE__, filepath); + acl_vstream_fprintf(client, "-ERR|child(%s) maybe be running!\r\n", + filepath); + return (-1); + } + + cmdline = acl_vstring_alloc(256); + acl_vstring_strcpy(cmdline, "\""); + acl_vstring_strcat(cmdline, filepath); + acl_vstring_strcat(cmdline, "\""); + if (args && *args) { + acl_vstring_strcat(cmdline, " "); + acl_vstring_strcat(cmdline, args); + } + service = proctl_service_alloc(filepath, cmdline); + msg = proctl_msg_new(PROCTL_MSG_START); + msg->service = service; + proctl_msg_push(msg); + return (0); +} + +/* 停止所有的服务,并退出整个控制进程 */ +static void proctl_monitor_cmd_quit(ACL_VSTREAM *client) +{ + const char *myname = "proctl_monitor_cmd_quit"; + + acl_msg_info("%s(%d): begin to quit ...", myname, __LINE__); + acl_msg_info("%s(%d): begin to stop all ...", myname, __LINE__); + proctl_monitor_stop_all_service(client); + acl_msg_info("%s(%d): stop all end", myname, __LINE__); + acl_msg_info("%s(%d): quit ok", myname, __LINE__); + acl_vstream_fprintf(client, "+OK|stopped all children, and quit now\r\n"); + acl_vstream_close(client); + exit(0); +} + +static int proctl_monitor_cmd_list(ACL_VSTREAM *client) +{ + ACL_ARGV *service_argv; + int i, ret = 0; + + service_argv = proctl_serivce_get_all(); + if (service_argv == NULL) { + acl_vstream_fprintf(client, "+OK|no service running yet!\r\n"); + return (0); + } + + for (i = 0; i < service_argv->argc; i++) { + ret = acl_vstream_fprintf(client, "+OK|service=%s running\r\n", + service_argv->argv[i]); + if (ret == ACL_VSTREAM_EOF) + break; + } + + if (ret != ACL_VSTREAM_EOF) + acl_vstream_fprintf(client, "+OK|total service is %d\r\n", + service_argv->argc); + proctl_service_free_all(service_argv); + + return (0); +} + +static int proctl_monitor_cmd_probe(ACL_VSTREAM *client, const char *filepath) +{ + if (filepath == NULL || *filepath == 0) { + acl_vstream_fprintf(client, "-ERR|filepath is null\r\n"); + return (-1); + } + + if (proctl_service_exist(filepath)) + acl_vstream_fprintf(client, "+OK|service: %s is running\r\n", filepath); + else + acl_vstream_fprintf(client, "+OK|service: %s is not running\r\n", filepath); + + return (0); +} + +static void usage(ACL_VSTREAM *client) +{ + acl_vstream_fprintf(client, "usage: progname|-h[help]" + "|-d|{action}[START|STOP|QUIT|LIST|PROBE]|-f|filepath|-a|args\r\n"); + acl_msg_info("usage: progname|-h[help]|-d|{action}[START|STOP|QUIT|LIST|PROBE]" + "|-f|filepath|-a|args"); +} + +/* 控制进程的监听线程处理命令总入口 */ +static int proctl_monitor_main(ACL_VSTREAM *client, int argc, char *argv[]) +{ + const char *myname = "proctl_monitor_main"; + char i, cmd[256], filepath[MAX_PATH], args[512]; + + cmd[0] = 0; + filepath[0] = 0; + args[0] = 0; + + if (acl_do_debug(ACL_DEBUG_PROCTL, 2)) { + int i; + for (i = 0; i < argc; i++) + acl_msg_info("%s(%d): argv[%d]=%s", myname, __LINE__, i, argv[i]); + } + + /* "d:f:a:h" */ + for (i = 0; i < argc; i++) { + if (argv[i][0] != '-') + continue; + switch(argv[i][1]) { + case 'h': + usage(client); + return (0); + case 'd': + if (argv[++i] == NULL) { + usage(client); + return (0); + } + ACL_SAFE_STRNCPY(cmd, argv[i], sizeof(cmd)); + break; + case 'f': + if (argv[++i] == NULL) { + usage(client); + return (0); + } + ACL_SAFE_STRNCPY(filepath, argv[i], sizeof(filepath)); + break; + case 'a': + if (argv[++i] == NULL) { + usage(client); + return (0); + } + ACL_SAFE_STRNCPY(args, argv[i], sizeof(args)); + break; + default: + break; + } + } + + if (strcasecmp(cmd, "STOP") == 0) { + proctl_monitor_cmd_stop(client, filepath, args); + } else if (strcasecmp(cmd, "START") == 0) { + proctl_monitor_cmd_start(client, filepath, args); + } else if (strcasecmp(cmd, "QUIT") == 0) { + proctl_monitor_cmd_quit(client); + } else if (strcasecmp(cmd, "LIST") == 0) { + proctl_monitor_cmd_list(client); + } else if (strcasecmp(cmd, "PROBE") == 0) { + proctl_monitor_cmd_probe(client, filepath); + } else { + usage(client); + acl_msg_warn("%s(%d): unknown cmd(%s)", myname, __LINE__, cmd); + } + + return (0); +} + +static void proctl_monitor_loop(ACL_VSTREAM *sstream) +{ + const char *myname = "proctl_monitor_loop"; + ACL_VSTREAM *client; + int n; + char buf[1024]; + ACL_ARGV *cmd_argv; + + while (1) { + client = acl_vstream_accept(sstream, NULL, 0); + if (client == NULL) + continue; + + n = acl_vstream_gets_nonl(client, buf, sizeof(buf)); + if (n == ACL_VSTREAM_EOF) + continue; + + acl_debug(ACL_DEBUG_PROCTL, 2) ("%s(%d): get buf(%s)", + myname, __LINE__, buf); + cmd_argv = acl_argv_split(buf, "|"); + if (cmd_argv) + proctl_monitor_main(client, cmd_argv->argc, cmd_argv->argv); + else + usage(client); + acl_vstream_close(client); + } +} + +void *proctl_monitor_thread(void *arg) +{ + const char *myname = "proctl_monitor_thread"; + ACL_VSTREAM *sstream; + char ebuf[256]; + + sstream = local_listen(); + if (sstream == NULL) + acl_msg_fatal("%s(%d): local_listen return NULL, error(%s)", + myname, __LINE__, acl_last_strerror(ebuf, sizeof(ebuf))); + proctl_monitor_loop(sstream); + + /* unreached */ + return (NULL); +} + +#endif /* ACL_MS_WINDOWS */ + diff --git a/lib_acl/src/proctl/proctl_service.c b/lib_acl/src/proctl/proctl_service.c new file mode 100644 index 000000000..dfd9c0956 --- /dev/null +++ b/lib_acl/src/proctl/proctl_service.c @@ -0,0 +1,464 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#endif /* ACL_PREPARE_COMPILE */ + +#ifdef ACL_MS_WINDOWS + +#include "stdlib/acl_stdlib.h" +#include "thread/acl_thread.h" +#include +#include "proctl_internal.h" + +static ACL_ARRAY *__services = NULL; /* 当前正在运行的服务对象队列 */ +static acl_pthread_mutex_t __mutex_running_service; +static HANDLE *__handles = NULL; +static HANDLE __sem_handle = INVALID_HANDLE_VALUE; +static int __max_handle = 64; +static int __cur_handle = 0; +static ACL_FIFO *__services_wait = NULL; /* 当前正在待启动的服务对象队列 */ +static acl_pthread_mutex_t __mutex_waiting_service; + +#define LOCK_RUNNING_SERVICE do \ +{ \ + acl_pthread_mutex_lock(&__mutex_running_service); \ +} while(0); + +#define UNLOCK_RUNNING_SERVICE do \ +{ \ + acl_pthread_mutex_unlock(&__mutex_running_service); \ +} while(0); + +#define LOCK_WAITING_SERVICE do \ +{ \ + acl_pthread_mutex_lock(&__mutex_waiting_service); \ +} while(0); + +#define UNLOCK_WAITING_SERVICE do \ +{ \ + acl_pthread_mutex_unlock(&__mutex_waiting_service); \ +} while(0); + +/* 初始化进程句柄数组 */ + +static void handles_init(void) +{ + const char *myname = "handles_init"; + int i; + + __handles = (HANDLE *) acl_mycalloc(__max_handle, sizeof(HANDLE)); + acl_assert(__handles); + __cur_handle = 0; + + for (i = 0; i < __max_handle; i++) { + __handles[i] = INVALID_HANDLE_VALUE; + } +} + +/* 向进程句柄数组中添加新的进程句柄 */ + +static void handles_add(HANDLE handle) +{ + const char *myname = "handles_add"; + int i; + + if (__cur_handle >= __max_handle) + acl_msg_fatal("%s(%d): too many handle", myname, __LINE__); + + for (i = 0; i < __max_handle; i++) { + if (__handles[i] == INVALID_HANDLE_VALUE) { + __handles[i] = handle; + __cur_handle++; + return; + } + } + + acl_msg_fatal("%s(%d): no position for new handle", myname, __LINE__); +} + +/* 从进程句柄数组中删除句柄 */ + +static void handles_del(HANDLE handle) +{ + const char *myname = "handles_del"; + int i; + + for (i = 0; i < __cur_handle; i++) { + if (__handles[i] == handle) { + __cur_handle--; + if (i < __cur_handle) { + __handles[i] = __handles[__cur_handle]; + } + __handles[__cur_handle] = INVALID_HANDLE_VALUE; + return; + } + } + + acl_msg_fatal("%s(%d): not found the handle", myname, __LINE__); +} + +/* 进程管理服务库初始化 */ + +void proctl_service_init() +{ + const char *myname = "proctl_service_init"; + char ebuf[256]; + + __services = acl_array_create(10); + __services_wait = acl_fifo_new(); + acl_pthread_mutex_init(&__mutex_running_service, NULL); + acl_pthread_mutex_init(&__mutex_waiting_service, NULL); + handles_init(); + + __sem_handle = CreateSemaphore(NULL, 0, 1024, NULL); + if (__sem_handle == NULL) + acl_msg_fatal("%s(%d): CreateSemaphore error(%s)", + myname, __LINE__, acl_last_strerror(ebuf, sizeof(ebuf))); + handles_add(__sem_handle); +} + +/* 创建一个新的服务对象 */ + +PROCTL_SERVICE *proctl_service_alloc(const char *filepath, ACL_VSTRING *cmdline) +{ + PROCTL_SERVICE *service; + + service = (PROCTL_SERVICE*) acl_mycalloc(1, sizeof(PROCTL_SERVICE)); + acl_assert(service); + service->filepath = acl_mystrdup(filepath); + service->cmdline = cmdline; + service->hProcess = INVALID_HANDLE_VALUE; + + return (service); +} + +static void proctl_service_add(PROCTL_SERVICE *service) +{ + const char *myname = "proctl_service_add"; + + /* 向服务对象数据组中添加新的服务对象 */ + + LOCK_RUNNING_SERVICE; + if (acl_array_append(__services, service) < 0) + acl_msg_fatal("%s(%d): add service to array error", myname, __LINE__); + UNLOCK_RUNNING_SERVICE; +} + +PROCTL_SERVICE *proctl_service_new(const char *filepath, int argc, char *argv[]) +{ + const char *myname = "proctl_service_new"; + PROCTL_SERVICE *service; + ACL_VSTRING *cmdline = acl_vstring_alloc(256); + int i; + + acl_assert(cmdline); + + /* 组建启动进程命令行参数表 */ + + /* 为了避免参数传递时可能因其中间含有空格而被分隔成 + * 多个参数,所以需要在参数两边加上引号 + */ + + acl_vstring_strcat(cmdline, "\""); + acl_vstring_strcat(cmdline, filepath); + acl_vstring_strcat(cmdline, "\" "); + + for (i = 0; i < argc; i++) { + acl_vstring_strcat(cmdline, "\""); + acl_vstring_strcat(cmdline, argv[i]); + acl_vstring_strcat(cmdline, "\" "); + } + + acl_msg_info("%s(%d): filepath=%s, cmdline=%s", + myname, __LINE__, filepath, acl_vstring_str(cmdline)); + + service = proctl_service_alloc(filepath, cmdline); + proctl_service_add(service); + return (service); +} + +/* 释放一个服务对象 */ + +void proctl_service_free(PROCTL_SERVICE *service) +{ + if (service->hProcess != INVALID_HANDLE_VALUE) + CloseHandle(service->hProcess); + acl_myfree(service->filepath); + acl_vstring_free(service->cmdline); + + LOCK_RUNNING_SERVICE; + acl_array_delete_obj(__services, service, NULL); + UNLOCK_RUNNING_SERVICE; + + acl_myfree(service); +} + +/* 根据进程句柄查询服务对象 */ + +static PROCTL_SERVICE *proctl_service_find(HANDLE handle) +{ + const char *myname = "proctl_service_find"; + PROCTL_SERVICE *service; + int i, n; + + LOCK_RUNNING_SERVICE; + + n = acl_array_size(__services); + for (i = 0; i < n; i++) { + service = (PROCTL_SERVICE*) acl_array_index(__services, i); + if (service->hProcess == handle) { + UNLOCK_RUNNING_SERVICE; + return (service); + } + } + + UNLOCK_RUNNING_SERVICE; + return (NULL); +} + +/* 获得所有的服务对象的程序名称,并将结果存储在一个数组中 */ + +ACL_ARGV *proctl_serivce_get_all() +{ + ACL_ARGV *argv = acl_argv_alloc(10); + PROCTL_SERVICE *service; + int i, n; + + LOCK_RUNNING_SERVICE; + n = acl_array_size(__services); + for (i = 0; i < n; i++) { + service = (PROCTL_SERVICE*) acl_array_index(__services, i); + acl_argv_add(argv, service->filepath, NULL); + } + UNLOCK_RUNNING_SERVICE; + + if (argv->argc == 0) { + acl_argv_free(argv); + return (NULL); + } + return (argv); +} + +/* 释放由 proctl_service_get_all 产生的对象数组 */ + +void proctl_service_free_all(ACL_ARGV *argv) +{ + if (argv) + acl_argv_free(argv); +} + +/* 根据程序全路径名查看某个进程是否在运行中 */ + +int proctl_service_exist(const char *filepath) +{ + PROCTL_SERVICE *service; + int i, n; + + LOCK_RUNNING_SERVICE; + n = acl_array_size(__services); + for (i = 0; i < n; i++) { + service = (PROCTL_SERVICE*) acl_array_index(__services, i); + if (strcasecmp(service->filepath, filepath) == 0) + break; + } + UNLOCK_RUNNING_SERVICE; + + if (n <= 0 || i == n) + return (0); + return (1); +} + +/* 释放某个服务对象及其所绑定的进程句柄 */ + +static void proctl_service_stopped(PROCTL_SERVICE *service) +{ + handles_del(service->hProcess); + proctl_service_free(service); +} + +/* 开始启动某个服务进程 */ + +int proctl_service_start(PROCTL_SERVICE *service) +{ + const char *myname = "proctl_service_start"; + HANDLE hThread; + char ebuf[256]; + + if(!CreateProcess(service->filepath, acl_vstring_str(service->cmdline), + NULL, NULL, 0, DETACHED_PROCESS, NULL, NULL, + &service->start_info, &service->process_info)) + { + + acl_msg_error("%s(%d): CreateProcess error(%s), file(%s)", + myname, __LINE__, acl_last_strerror(ebuf, sizeof(ebuf)), + service->filepath); + return (-1); + } + + service->hProcess = service->process_info.hProcess; + hThread = service->process_info.hThread; + CloseHandle(hThread); + handles_add(service->hProcess); + + return (0); +} + +/* 重新启动某个服务进程 */ + +static int proctl_service_restart(PROCTL_SERVICE *service) +{ + handles_del(service->hProcess); + CloseHandle(service->hProcess); + service->hProcess = INVALID_HANDLE_VALUE; + + return (proctl_service_start(service)); +} + +PROCTL_MSG *proctl_msg_new(int msg_type) +{ + PROCTL_MSG *msg = (PROCTL_MSG *) acl_mycalloc(1, sizeof(PROCTL_MSG)); + + msg->msg_type = msg_type; + return (msg); +} + +void proctl_msg_free(PROCTL_MSG *msg) +{ + if (msg->free_fn && msg->arg) + msg->free_fn(msg->arg); + acl_myfree(msg); +} + +/* 往消息队列中添加一个消息,并向主线程发送通知 */ +void proctl_msg_push(PROCTL_MSG *msg) +{ + LOCK_WAITING_SERVICE; + acl_fifo_push(__services_wait, msg); + UNLOCK_WAITING_SERVICE; + + /* 向主线程发送消息 */ + ReleaseSemaphore(__sem_handle, 1, NULL); +} + +/* 启动消息:启动一个服务子进程 */ +static void proctl_msg_start(PROCTL_MSG *msg) +{ + PROCTL_SERVICE *service = msg->service; + + proctl_service_add(service); + (void) proctl_service_start(service); +} + +/* 处理来自于监听线程的消息命令的主入口 */ +static void proctl_msg_main(void) +{ + const char *myname = "proctl_msg_main"; + PROCTL_MSG *msg; + + LOCK_WAITING_SERVICE; + while (1) { + msg = acl_fifo_pop(__services_wait); + if (msg == NULL) + break; + switch (msg->msg_type) { + case PROCTL_MSG_START: + proctl_msg_start(msg); + break; + default: + acl_msg_error("%s(%d): unknown msg type(%d)", + myname, __LINE__, msg->msg_type); + break; + } + + proctl_msg_free(msg); + } + + UNLOCK_WAITING_SERVICE; +} + +/* 等待所有的服务进程的状态 */ + +int proctl_service_wait(void) +{ + const char *myname = "proctl_service_wait"; + DWORD timeout = 1000 * 2, ret; + char ebuf[256]; + HANDLE handle_sem; + + if (__cur_handle == 0) + return (0); + + /* Create the semaphore, with max value 32K */ + handle_sem = CreateSemaphore(NULL, 0, 32 * 1024, NULL); + while (1) { + ret = WaitForMultipleObjects(__cur_handle, __handles, FALSE, timeout); + if (ret == WAIT_OBJECT_0) { + proctl_msg_main(); + } else if (ret == WAIT_FAILED) { + acl_msg_error("%s(%d): wait child object error(%s)", + myname, __LINE__, acl_last_strerror(ebuf, sizeof(ebuf))); + return (-1); + } else if (ret != WAIT_TIMEOUT) + break; + } + + acl_debug(ACL_DEBUG_PROCTL, 2) ("%s(%d): __cur_handle=%d", + myname, __LINE__, __cur_handle); + return (0); +} + +/* 回收一些退出的进程,并根据条件重启异常退出的进程 */ + +int proctl_service_join(void) +{ + const char *myname = "proctl_service_join"; + PROCTL_SERVICE *service; + HANDLE hProcess; + DWORD status; + int i; + char ebuf[256]; + + for (i = 0; i < __cur_handle; i++) { + hProcess = __handles[i]; + if (hProcess == INVALID_HANDLE_VALUE) + acl_msg_fatal("%s(%d): invalid handle in array, i(%d)", + myname, __LINE__, i); + + service = proctl_service_find(hProcess); + if (service == NULL) { + if (hProcess == __sem_handle) + continue; + acl_msg_fatal("%s(%d): not found hProcess", myname, __LINE__); + } + + status = 0; + if (!GetExitCodeProcess(hProcess, &status)) { + acl_msg_error("%s(%d): get child exit error(%s)", + myname, __LINE__, acl_last_strerror(ebuf, sizeof(ebuf))); + if (proctl_service_restart(service) < 0) + proctl_service_stopped(service); + } else if (status == 0) { + acl_msg_error("%s(%d): child exit status 0, error(%s)", + myname, __LINE__, acl_last_strerror(ebuf, sizeof(ebuf))); + + /* 因为进程是正常退出,所以不需要重启动 */ + proctl_service_stopped(service); + } else if (status != STILL_ACTIVE) { + /* child has exited abnormaly */ + acl_msg_error("%s(%d): child exit status %d, child exit(%s)", + myname, __LINE__, (int) status, + acl_last_strerror(ebuf, sizeof(ebuf))); + + /* 因为进程是异常退出,所以需要重启动 */ + if (proctl_service_restart(service) < 0) + proctl_service_stopped(service); + } + /* else: STILL_ACTIVE */ + } + + return (0); +} + +#endif /*ACL_MS_WINDOWS */ diff --git a/lib_acl/src/proctl/proctl_utils.c b/lib_acl/src/proctl/proctl_utils.c new file mode 100644 index 000000000..56f4f8761 --- /dev/null +++ b/lib_acl/src/proctl/proctl_utils.c @@ -0,0 +1,126 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#endif /* ACL_PREPARE_COMPILE */ + +#ifdef ACL_MS_WINDOWS +#include "stdlib/acl_stdlib.h" +#include "net/acl_net.h" +#include +#include "proctl_internal.h" + +void get_lock_file(char *buf, size_t size) +{ + char full_path[MAX_PATH], driver[MAX_PATH], dir_path[MAX_PATH]; + char file_name[MAX_PATH], ext_name[MAX_PATH]; + + GetModuleFileName(NULL, full_path, MAX_PATH); + _splitpath(full_path, driver, dir_path, file_name, ext_name); + snprintf(buf, size, "%s%s%s.lock", driver, dir_path, file_name); +} + +void get_exec_path(char *buf, size_t size) +{ + char full_path[MAX_PATH], driver[MAX_PATH], dir_path[MAX_PATH]; + char file_name[MAX_PATH], ext_name[MAX_PATH], *ptr; + + GetModuleFileName(NULL, full_path, MAX_PATH); + _splitpath(full_path, driver, dir_path, file_name, ext_name); + snprintf(buf, size, "%s%s", driver, dir_path); + ptr = buf + strlen(buf) - 1; + while (ptr >= buf && (*ptr == '\\' || *ptr == '/')) { + *ptr-- = 0; + } +} + +void get_lock_file2(const char *filepath, char *buf, size_t size) +{ + char *ptr; + + snprintf(buf, size, "%s", filepath); + + ptr = strrchr(buf, '.'); + if (ptr) + *ptr = 0; + else + ptr = buf + strlen(buf); + + size = buf + size - ptr; + snprintf(ptr, size, ".lock"); +} + +int get_addr_from_file(const char *filepath, char *buf, size_t size) +{ + const char *myname = "get_addr_from_file"; + ACL_VSTREAM *fp; + char ebuf[256]; + int n; + + fp = acl_vstream_fopen(filepath, O_RDONLY, 0600, 1024); + if (fp == NULL) { + acl_msg_error("%s(%d): fopen file(%s) error(%s)", + myname, __LINE__, filepath, acl_last_strerror(ebuf, sizeof(ebuf))); + return (-1); + } + + n = acl_vstream_gets_nonl(fp, buf, size); + acl_vstream_close(fp); + + if (n == ACL_VSTREAM_EOF) + acl_msg_error("%s(%d): gets from file(%s) error(%s)", + myname, __LINE__, filepath, acl_last_strerror(ebuf, sizeof(ebuf))); + + return (0); +} + +ACL_VSTREAM *local_listen() +{ + const char *myname = "local_listen"; + char lock_file[MAX_PATH], ebuf[256]; + ACL_VSTREAM *sstream, *fp; + ACL_FILE_HANDLE handle; + + get_lock_file(lock_file, sizeof(lock_file)); + + fp = acl_vstream_fopen(lock_file, O_RDWR | O_CREAT, 0600, 1024); + if (fp == NULL) + acl_msg_fatal("%s(%d): open file(%s) error(%s)", + myname, __LINE__, lock_file, acl_last_strerror(ebuf, sizeof(ebuf))); + + handle = ACL_VSTREAM_FILE(fp); + if (acl_myflock(handle, 0, ACL_MYFLOCK_OP_EXCLUSIVE | ACL_MYFLOCK_OP_NOWAIT) == -1) { + acl_msg_error("%s(%d): lock file(%s) error(%s)", + myname, __LINE__, lock_file, acl_last_strerror(ebuf, sizeof(ebuf))); + return (NULL); + } + + sstream = acl_vstream_listen_ex("127.0.0.1:0", 128, ACL_BLOCKING, 1024, 0); + if (sstream == NULL) + acl_msg_fatal("%s(%d): listen error(%s)", + myname, __LINE__, acl_last_strerror(ebuf, sizeof(ebuf))); + + if (acl_file_ftruncate(fp, 0) < 0) + acl_msg_fatal("%s(%d): truncate file(%s) error(%s)", + myname, __LINE__, lock_file, acl_last_strerror(ebuf, sizeof(ebuf))); + if (acl_vstream_fseek(fp, 0, SEEK_SET) < 0) + acl_msg_fatal("%s(%d): fseek file(%s) error(%s)", + myname, __LINE__, lock_file, acl_last_strerror(ebuf, sizeof(ebuf))); + + if (acl_vstream_fprintf(fp, "%s\r\n", sstream->local_addr) == ACL_VSTREAM_EOF) + acl_msg_fatal("%s(%d): fprintf to file(%s) error(%s)", + myname, __LINE__, lock_file, acl_last_strerror(ebuf, sizeof(ebuf))); + + /* XXX: 只能采用先解排它锁,再加共享锁,微软比较弱!!! */ + + if (acl_myflock(handle, 0, ACL_MYFLOCK_OP_NONE) == -1) + acl_msg_fatal("%s(%d): unlock file(%s) error(%s)", + myname, __LINE__, lock_file, acl_last_strerror(ebuf, sizeof(ebuf))); + if (acl_myflock(handle, 0, ACL_MYFLOCK_OP_SHARED | ACL_MYFLOCK_OP_NOWAIT) == -1) + acl_msg_fatal("%s(%d): lock file(%s) error(%s)", + myname, __LINE__, lock_file, acl_last_strerror(ebuf, sizeof(ebuf))); + return (sstream); +} + +#endif /* ACL_MS_WINDOWS */ diff --git a/lib_acl/src/stdlib/acl_chunk_chain.c b/lib_acl/src/stdlib/acl_chunk_chain.c new file mode 100644 index 000000000..3bb16bb21 --- /dev/null +++ b/lib_acl/src/stdlib/acl_chunk_chain.c @@ -0,0 +1,378 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include + +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_msg.h" +#include "stdlib/acl_ring.h" +#include "stdlib/acl_vstring.h" +#include "stdlib/acl_chunk_chain.h" + +#endif + +typedef struct ACL_CHUNK { + acl_int64 from; + acl_int64 dlen; + char *buf; + + ACL_RING entry; /* linkage */ +} ACL_CHUNK; + +struct ACL_CHAIN { + acl_int64 from_next; /* 当前连续数据链的位置 */ + acl_int64 off_begin; /* 偏移量起始位置 */ + + ACL_RING ring; /* 多个 DBUF 数据块组成的数据链 */ + ACL_VSTRING sbuf; +}; + +static ACL_CHUNK *acl_chunk_new(const void *buf, acl_int64 from, int dlen) +{ + ACL_CHUNK *chunk = (ACL_CHUNK*) acl_mycalloc(1, sizeof(ACL_CHUNK)); + + chunk->from = from; + chunk->dlen = dlen; + chunk->buf = (char *) acl_mymemdup(buf, dlen); + return (chunk); +} + +static void acl_chunk_free(ACL_CHUNK *chunk) +{ + acl_myfree(chunk->buf); + acl_myfree(chunk); +} + +static void acl_chunk_merge(ACL_CHUNK *chunk, const char *pdata, + acl_int64 from, int dlen) +{ + char *tmpbuf, *ptr; + acl_int64 to = from + dlen, n, chunk_to = chunk->from + chunk->dlen; + + /* sanity check: 必须保证新添数据必须与数据块有数据交叉 */ + + if (from < chunk->from) { + if (to < chunk->from) + return; + + /* from < chunk->from <= to */ + + if (to < chunk_to) { + /* from < chunk->from <= to < chunk_to */ + n = chunk->from - from; + ptr = tmpbuf = acl_mymalloc((int) (chunk->dlen + n)); + memcpy(ptr, pdata, dlen); + ptr += dlen; + n = to - chunk->from; + pdata = chunk->buf + n; + memcpy(ptr, pdata, (int) (chunk->dlen - n)); + + acl_myfree(chunk->buf); + chunk->buf = tmpbuf; + chunk->dlen += chunk->from - from; + chunk->from = from; + } else { + /* from < chunk->from < chunk_to <= to */ + acl_myfree(chunk->buf); + chunk->buf = (char*) acl_mymemdup(pdata, dlen); + chunk->from = from; + chunk->dlen = dlen; + } + } else if (from <= chunk_to) { + /* chunk->from <= from <= chunk_to */ + if (to > chunk_to) { + /* chunk->from <= from <= chunk_to < to */ + n = to - chunk_to ; + ptr = tmpbuf = acl_mymalloc((int) (chunk->dlen + n)); + memcpy(ptr, chunk->buf, (int) chunk->dlen); + ptr += chunk->dlen; + pdata += chunk_to - from; + n = to - chunk_to; + memcpy(ptr, pdata, (int) n); + + acl_myfree(chunk->buf); + chunk->buf = tmpbuf; + chunk->dlen += n; + /* chunk->from no changed */ + } + /* else: chunk->from <= from <= to <= chunk_to, do nothing */ + } + /* else: chunk->from <= chunk_to < from <= to, do nothing */ +} + +ACL_CHAIN *acl_chain_new(size_t init_size, acl_int64 off_begin) +{ + ACL_CHAIN *chain; + + chain = (ACL_CHAIN*) acl_mycalloc(1, sizeof(ACL_CHAIN)); + acl_vstring_init(&chain->sbuf, init_size); + acl_ring_init(&chain->ring); + chain->off_begin = off_begin; + chain->from_next = off_begin; + return (chain); +} + +void acl_chain_free(ACL_CHAIN *chain) +{ + ACL_RING *ring_iter; + ACL_CHUNK *chunk; + + while ((ring_iter = acl_ring_pop_head(&chain->ring))) { + chunk = ACL_RING_TO_APPL(ring_iter, ACL_CHUNK, entry); + acl_chunk_free(chunk); + } + acl_vstring_free_buf(&chain->sbuf); + acl_myfree(chain); +} + +void acl_chain_set_from_next(ACL_CHAIN *chain, acl_int64 from_next) +{ + chain->from_next = from_next; + ACL_VSTRING_RESET(&chain->sbuf); +} + +void acl_chain_reset(ACL_CHAIN *chain, acl_int64 off_begin) +{ + chain->off_begin = off_begin; + chain->from_next = off_begin; + ACL_VSTRING_RESET(&chain->sbuf); +} + +acl_int64 acl_chain_from_next(ACL_CHAIN *chain) +{ + return (chain->from_next); +} + +acl_int64 acl_chain_off_begin(ACL_CHAIN *chain) +{ + return (chain->off_begin); +} + +const char *acl_chain_data(ACL_CHAIN *chain) +{ + if (ACL_VSTRING_LEN(&chain->sbuf) == 0) + return (NULL); + + return (acl_vstring_str(&chain->sbuf)); +} + +int acl_chain_data_len(ACL_CHAIN *chain) +{ + return (ACL_VSTRING_LEN(&chain->sbuf)); +} + +int acl_chain_size(ACL_CHAIN *chain) +{ + ACL_RING_ITER iter; + int n = 0; + + acl_ring_foreach(iter, &chain->ring) { + n++; + } + + return (n); +} + +int acl_chain_chunk_data_len(ACL_CHAIN *chain) +{ + ACL_RING_ITER iter; + ACL_CHUNK *chunk_iter; + int n = 0; + + acl_ring_foreach(iter, &chain->ring) { + chunk_iter = ACL_RING_TO_APPL(iter.ptr, ACL_CHUNK, entry); + n += (int) chunk_iter->dlen; + } + + return (n); +} + +void acl_chain_add(ACL_CHAIN *chain, const void *data, + acl_int64 from, int dlen) +{ + const char *myname = "acl_chain_add"; + const char *pdata = (const char*) data; + ACL_CHUNK *chunk_iter, *chunk, *chunk_saved; + ACL_RING *ring_ptr, *ring_next; + ACL_RING_ITER ring_iter; + acl_int64 to, n, chunk_to; + + to = from + dlen; + /* 过滤掉重复数据 */ + if (to < chain->from_next) { + acl_msg_warn("%s(%d): past data, to(" ACL_FMT_I64D ") < from_next(" + ACL_FMT_I64D "), from=" ACL_FMT_I64D ", dlen=%d", + myname, __LINE__, to, chain->from_next, from, dlen); + return; + } + + /* make sure: from >= chain->from_next */ + if (from < chain->from_next) { + n = chain->from_next - from; + dlen -= (int) n; + pdata += n; + from = chain->from_next; + } + + if (from == chain->from_next) { + /* 将连续的数据块拷贝至连接数据缓冲区中 */ + acl_vstring_memcat(&chain->sbuf, pdata, dlen); + chain->from_next += dlen; + + while ((chunk_iter = ACL_RING_FIRST_APPL(&chain->ring, ACL_CHUNK, entry)) != NULL) { + acl_int64 to_first; + + /* 如果遇到非连接块则退出循环 */ + if (to < chunk_iter->from) + break; + + /* 处理连接数据块的情况 */ + + /* 去掉该交叉数据块的链接结点 */ + (void) acl_ring_pop_head(&chain->ring); + + to_first = chunk_iter->from + chunk_iter->dlen; + + /* 如果新数据块包含旧数据块,则去除重复的旧数据块 */ + if (to >= to_first) { + acl_chunk_free(chunk_iter); + continue; + } + + /* 数据块交叉情况 */ + + /* from <= to < to_first + * chunk_iter->from <= from <= to < to_first + * or: + * from <= chunk_iter->from <= to < to_first + */ + n = to_first - to; + pdata = chunk_iter->buf + chunk_iter->dlen - n; + acl_vstring_memcat(&chain->sbuf, pdata, (int) n); + chain->from_next += n; + + acl_chunk_free(chunk_iter); + break; + } + + return; + } + + /* 处理据块不连续数的添加情形 */ + + /* chain->from_next < from <= to*/ + chunk_iter = ACL_RING_FIRST_APPL(&chain->ring, ACL_CHUNK, entry); + if (chunk_iter == NULL) { + /* 说明是第一个数据块 */ + chunk = acl_chunk_new(data, from, dlen); + acl_ring_append(&chain->ring, &chunk->entry); + return; + } + + chunk_saved = NULL; + + acl_ring_foreach(ring_iter, &chain->ring) { + chunk_iter = ACL_RING_TO_APPL(ring_iter.ptr, ACL_CHUNK, entry); + chunk_to = chunk_iter->from + chunk_iter->dlen; + + /* chunk_iter->from <= to */ + if (from <= chunk_iter->from) { + if (to < chunk_iter->from) { + /* 说明新数据块与数据链中的数据块无交集 */ + /* from <= to < chunk_iter->from <= chunk_to */ + chunk = acl_chunk_new(data, from, dlen); + /* 前插数据块结点 */ + acl_ring_prepend(&chunk_iter->entry, &chunk->entry); + return; + } + /* from <= chunk_iter->from <= to */ + if (to <= chunk_to) { + /* from <= chunk_iter->from <= to <= chunk_to */ + acl_chunk_merge(chunk_iter, pdata, from, dlen); + return; + } + /* else: from <= chunk_iter->from <= chunk_to < to */ + /* 交集数据可能存在于多个数据结点中 */ + chunk_saved = chunk_iter; + break; + } else if (from <= chunk_to) { + /* chunk_iter->from < from <= chunk_to */ + if (to <= chunk_to) { + /* chunk_iter->from <= from <= to <= chunk_to */ + acl_chunk_merge(chunk_iter, pdata, from, dlen); + return; + } + /* else: chunk_iter->from < from <= chunk_to < to */ + /* 交集数据可能存在于多个数据结点中 */ + chunk_saved = chunk_iter; + break; + } + /* else: from > chunk_to, continue */ + } + + if (chunk_saved == NULL) { + /* 说明新数据块与数据链中的数据块无交集 */ + /* from <= to < chunk_iter->from <= chunk_to */ + chunk = acl_chunk_new(data, from, dlen); + /* 前插数据块结点 */ + acl_ring_prepend(&chain->ring, &chunk->entry); + + return; + } + + /* from <= chunk_iter->from <= chunk_to < to + * or: + * chunk_iter->from < from <= chunk_to < to + */ + acl_chunk_merge(chunk_saved, pdata, from, dlen); + ring_next = acl_ring_succ(ring_iter.ptr); + while (ring_next != &chain->ring) { + chunk = ACL_RING_TO_APPL(ring_next, ACL_CHUNK, entry); + if (to < chunk->from) + break; + /* to >= chunk->from */ + chunk_to = chunk->from + chunk->dlen; + if (to >= chunk_to) { + /* from < chunk->from <= chunk_to <= to + * or: + * chunk_iter->from < from < chunk_to <= to + */ + ring_ptr = ring_next; + ring_next = acl_ring_succ(ring_next); + acl_ring_detach(ring_ptr); + acl_chunk_free(chunk); + continue; + } + /* from <= chunk->from < to < chunk_to + * or: + * chunk_iter->from < from < to < chunk_to + */ + acl_chunk_merge(chunk_saved, chunk->buf, chunk->from, (int) chunk->dlen); + ring_ptr = ring_next; + ring_next = acl_ring_succ(ring_next); + acl_ring_detach(ring_ptr); + acl_chunk_free(chunk); + break; + } +} + +void acl_chain_list(ACL_CHAIN *chain) +{ + ACL_RING_ITER ring_iter; + ACL_CHUNK *chunk; + acl_int64 chunk_to; + + if (ACL_VSTRING_LEN(&chain->sbuf) > 0) + printf("from=" ACL_FMT_I64D ", next to=" ACL_FMT_I64D " , dlen=%d\r\n", + chain->off_begin, chain->from_next, (int) ACL_VSTRING_LEN(&chain->sbuf)); + + acl_ring_foreach(ring_iter, &chain->ring) { + chunk = ACL_RING_TO_APPL(ring_iter.ptr, ACL_CHUNK, entry); + chunk_to = chunk->from + chunk->dlen; + printf("from=" ACL_FMT_I64D ", next to=" ACL_FMT_I64D ", dlen=%d\r\n", + chunk->from, chunk_to, (int) chunk->dlen); + } +} diff --git a/lib_acl/src/stdlib/acl_debug.c b/lib_acl/src/stdlib/acl_debug.c new file mode 100644 index 000000000..a75793561 --- /dev/null +++ b/lib_acl/src/stdlib/acl_debug.c @@ -0,0 +1,95 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_debug.h" +#include "stdlib/acl_argv.h" +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_mystring.h" + +#endif + +#define DEF_DEBUG_SECTIONS 1000 +static int __max_debug_sections = DEF_DEBUG_SECTIONS; + +static int *pDebugLevels = NULL; + +void acl_debug_end() +{ + if (pDebugLevels != NULL) { + acl_myfree(pDebugLevels); + pDebugLevels = NULL; + } +} + +/* pStr format: 1,1; 2,10; 3,8... */ +void acl_debug_init(const char *pStr) +{ + acl_debug_init2(pStr, DEF_DEBUG_SECTIONS); +} + +void acl_debug_init2(const char *pStr, int max_debug_level) +{ + int i, level_all = -1, section, level; + ACL_ARGV* pItem = acl_argv_split(pStr, ";"); + + __max_debug_sections = max_debug_level > 100 ? max_debug_level : 100; + + pDebugLevels = (int*) acl_mycalloc(__max_debug_sections, sizeof(int)); + + for (i = 0; i < __max_debug_sections; i++) + pDebugLevels[i] = 0; + + for (i = 0; i < pItem->argc; i++) { + char* pSection = pItem->argv[i]; + ACL_ARGV* pPair = acl_argv_split(pSection, ":,\t "); + if (pPair->argc != 2) { + acl_argv_free(pPair); + continue; + } + + if (strcasecmp(pPair->argv[0], "All") == 0) { + level_all = atoi(pPair->argv[1]); + acl_argv_free(pPair); + continue; + } + + section = atoi(pPair->argv[0]); + level = atoi(pPair->argv[1]); + + acl_argv_free(pPair); + + if (section >= __max_debug_sections || section < 0 || level < 0) { + continue; + } + pDebugLevels[section] = level; + } + + acl_argv_free(pItem); + + if (level_all >= 0) { + for (i = 0; i < __max_debug_sections; i++) { + if (pDebugLevels[i] < level_all) + pDebugLevels[i] = level_all; + } + } +} + +int acl_do_debug(int section, int level) +{ + if (pDebugLevels == NULL) + return (0); + if (section >= __max_debug_sections || section < 0) + return (0); + if (level > pDebugLevels[section]) + return (0); + + return (1); +} diff --git a/lib_acl/src/stdlib/acl_file.c b/lib_acl/src/stdlib/acl_file.c new file mode 100644 index 000000000..3c0d35880 --- /dev/null +++ b/lib_acl/src/stdlib/acl_file.c @@ -0,0 +1,387 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#include +#include +#include /* just for EOF */ +#include +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_msg.h" +#include "stdlib/acl_file.h" + +#endif + +ACL_FILE *acl_fopen(const char *filename, const char *mode) +{ + ACL_FILE *fp; + ACL_VSTREAM *stream; + int oflags = 0, whileflag; +#ifdef ACL_MS_WINDOWS + int commodeset = 0, scanset = 0; +#endif + + /* Skip leading spaces */ + while (*mode == ' ') { + mode++; + } + + /* First mode character must be 'r', 'w', or 'a'. */ + + switch (*mode) { + case 'r': + oflags = O_RDONLY; + break; + case 'w': + oflags = O_WRONLY | O_CREAT | O_TRUNC; + break; + case 'a': + oflags = O_WRONLY | O_CREAT | O_APPEND; + break; + default: + errno = EINVAL; + acl_msg_error("Invalid file open mode"); + return NULL; + } + + /* There can be up to three more optional mode characters: + * (1) A single '+' character, + * (2) One of 't' and 'b' and + * (3) One of 'c' and 'n'. + */ + + whileflag = 1; + + while (*++mode && whileflag) { + switch (*mode) { + case ' ': + /* skip spaces */ + break; + case '+': + if (oflags & O_RDWR) + whileflag = 0; + else { + oflags |= O_RDWR; + oflags &= ~(O_RDONLY | O_WRONLY); + } + break; + case 'b': +#ifdef ACL_MS_WINDOWS + if (oflags & (O_TEXT | O_BINARY)) + whileflag = 0; + else + oflags |= O_BINARY; +#endif + break; +#ifdef ACL_MS_WINDOWS + case 't': + if (oflags & (O_TEXT | O_BINARY)) + whileflag = 0; + else + oflags |= O_TEXT; + break; + case ('c'): + if (commodeset) + whileflag = 0; + else + commodeset = 1; + break; + case 'n': + if (commodeset) + whileflag = 0; + else + commodeset = 1; + break; + case 'S': + if (scanset) + whileflag = 0; + else { + scanset = 1; + oflags |= O_SEQUENTIAL; + } + break; + case 'R': + if (scanset) + whileflag = 0; + else { + scanset = 1; + oflags |= O_RANDOM; + } + break; +#if 0 + case 'T': + if (oflags & O_SHORT_LIVED) + whileflag = 0; + else + oflags |= O_SHORT_LIVED; + break; +#endif + case 'D': + if (oflags & O_TEMPORARY) + whileflag = 0; + else + oflags |= O_TEMPORARY; + break; + case 'N': + oflags |= O_NOINHERIT; + break; +#endif /* ACL_MS_WINDOWS */ + default: + errno = EINVAL; + acl_msg_error("Invalid file open mode"); + return NULL; + } + } + + stream = acl_vstream_fopen(filename, oflags, 0644, 4096); + if (stream == NULL) + return NULL; + + fp = (ACL_FILE*) acl_mymalloc(sizeof(ACL_FILE)); + fp->stream = stream; + fp->status = 0; + fp->errnum = 0; + return fp; +} + +void acl_clearerr(ACL_FILE *fp) +{ + fp->status = 0; + fp->errnum = 0; +} + +int acl_fclose(ACL_FILE *fp) +{ + int ret = acl_vstream_fclose(fp->stream); + + acl_myfree(fp); + if (ret == ACL_VSTREAM_EOF || ret < 0) + return EOF; + return (0); +} + +int acl_feof(ACL_FILE *fp) +{ + return (fp->status & ACL_FILE_EOF) != 0; +} + +size_t acl_fread(void *buf, size_t size, size_t nitems, ACL_FILE *fp) +{ + int ret; + + if (size == 0 || nitems == 0) + return 0; + + fp->status &= ~ACL_FILE_EOF; + fp->errnum = 0; + + ret = acl_vstream_readn(fp->stream, buf, size * nitems); + if (ret == ACL_VSTREAM_EOF) { + fp->status |= ACL_FILE_EOF; + return EOF; + } + + ret /= size; + if (ret == (int) nitems) + return (nitems); + else if (ret == 0) { + fp->status |= ACL_FILE_EOF; + return EOF; + } else + return ret; +} + +char *acl_fgets(char *buf, int size, ACL_FILE *fp) +{ + int ret; + + fp->status &= ~ACL_FILE_EOF; + fp->errnum = 0; + + ret = acl_vstream_gets(fp->stream, buf, size); + if (ret == ACL_VSTREAM_EOF) { + fp->status |= ACL_FILE_EOF; + return NULL; + } + return buf; +} + +char *acl_fgets_nonl(char *buf, int size, ACL_FILE *fp) +{ + int ret; + + fp->status &= ~ACL_FILE_EOF; + fp->errnum = 0; + + ret = acl_vstream_gets_nonl(fp->stream, buf, size); + if (ret == ACL_VSTREAM_EOF) { + fp->status |= ACL_FILE_EOF; + return NULL; + } + return buf; +} + +int acl_fgetc(ACL_FILE *fp) +{ + int ret = ACL_VSTREAM_GETC(fp->stream); + + fp->status &= ~ACL_FILE_EOF; + fp->errnum = 0; + + if (ret == ACL_VSTREAM_EOF) { + fp->status |= ACL_FILE_EOF; + return EOF; + } + return ret; +} + +char *acl_gets(char *buf, size_t size) +{ + return acl_vstream_gets(ACL_VSTREAM_IN, buf, size) + == ACL_VSTREAM_EOF ? NULL : buf; +} + +char *acl_gets_nonl(char *buf, size_t size) +{ + return acl_vstream_gets_nonl(ACL_VSTREAM_IN, buf, size) + == ACL_VSTREAM_EOF ? NULL : buf; +} + +int acl_getchar() +{ + return acl_vstream_getc(ACL_VSTREAM_IN); +} + +int acl_fprintf(ACL_FILE *fp, const char *fmt, ...) +{ + va_list ap; + int ret; + + va_start(ap, fmt); + ret = acl_vfprintf(fp, fmt, ap); + va_end(ap); + + return ret; +} + +int acl_vfprintf(ACL_FILE *fp, const char *fmt, va_list ap) +{ + int ret; + + fp->status &= ~ACL_FILE_EOF; + fp->errnum = 0; + + ret = acl_vstream_vfprintf(fp->stream, fmt, ap); + if (ret == ACL_VSTREAM_EOF) { + fp->status |= ACL_FILE_EOF; + return EOF; + } + + return ret; +} + +size_t acl_fwrite(const void *ptr, size_t size, size_t nitems, ACL_FILE *fp) +{ + int ret; + + if (size == 0 || nitems == 0) + return 0; + + fp->status &= ~ACL_FILE_EOF; + fp->errnum = 0; + + ret = acl_vstream_writen(fp->stream, ptr, size * nitems); + if (ret == ACL_VSTREAM_EOF) { + fp->status |= ACL_FILE_EOF; + return EOF; + } + + return nitems; +} + +int acl_printf(const char *fmt, ...) +{ + va_list ap; + int ret; + + va_start(ap, fmt); + ret = acl_vprintf(fmt, ap); + va_end(ap); + + return ret; +} + +int acl_vprintf(const char *fmt, va_list ap) +{ + int ret; + + ret = acl_vstream_vfprintf(ACL_VSTREAM_OUT, fmt, ap); + if (ret == ACL_VSTREAM_EOF) + return EOF; + return ret; +} + +int acl_fputs(const char *s, ACL_FILE *fp) +{ + int ret; + + fp->status &= ~ACL_FILE_EOF; + fp->errnum = 0; + + ret = acl_vstream_fputs(s, fp->stream); + if (ret == ACL_VSTREAM_EOF) { + fp->status |= ACL_FILE_EOF; + return EOF; + } + + return ret; +} + +int acl_putc(int c, ACL_FILE *fp) +{ + int ret; + unsigned char ch = (unsigned char) c; + + fp->status &= ~ACL_FILE_EOF; + fp->errnum = 0; + + ret = ACL_VSTREAM_PUTC(ch, fp->stream); + if (ret == ACL_VSTREAM_EOF) { + fp->status |= ACL_FILE_EOF; + return EOF; + } + if (acl_vstream_fflush(ACL_VSTREAM_OUT) == ACL_VSTREAM_EOF) { + fp->status |= ACL_FILE_EOF; + return EOF; + } + return ret; +} + +int acl_puts(const char *s) +{ + int ret; + + ret = acl_vstream_fputs(s, ACL_VSTREAM_OUT); + if (ret == ACL_VSTREAM_EOF) + return EOF; + return ret; +} + +int acl_putchar(int c) +{ + int ret; + unsigned char ch = (unsigned char) c; + + ret = ACL_VSTREAM_PUTC(ch, ACL_VSTREAM_OUT); + if (ret == ACL_VSTREAM_EOF) + return EOF; + if (acl_vstream_fflush(ACL_VSTREAM_OUT) == ACL_VSTREAM_EOF) + return EOF; + return ret; +} + +acl_off_t acl_fseek(ACL_FILE *fp, acl_off_t offset, int whence) +{ + return acl_vstream_fseek(fp->stream, offset, whence); +} diff --git a/lib_acl/src/stdlib/acl_getopt.c b/lib_acl/src/stdlib/acl_getopt.c new file mode 100644 index 000000000..0d4f888b7 --- /dev/null +++ b/lib_acl/src/stdlib/acl_getopt.c @@ -0,0 +1,72 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include + +#endif + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_getopt.h" + +char *acl_optarg = NULL; /* Global argument pointer. */ +int acl_optind = 0; /* Global argv index. */ + +static char *scan = NULL; /* Private scan pointer. */ + +void acl_getopt_init(void) +{ + scan = NULL; +} + +int acl_getopt(int argc, char *argv[], const char *optstring) +{ + register char c; + register char *place; + + acl_optarg = NULL; + + if (scan == NULL || *scan == '\0') { + if (acl_optind == 0) + acl_optind++; + + if (acl_optind >= argc || argv[acl_optind][0] != '-' || argv[acl_optind][1] == '\0') + return(EOF); + if (strcmp(argv[acl_optind], "--")==0) { + acl_optind++; + return(EOF); + } + + scan = argv[acl_optind]+1; + acl_optind++; + } + + c = *scan++; + place = strchr(optstring, c); + + if (place == NULL || c == ':') { + printf("%s: unknown option -%c\n", argv[0], c); + return('?'); + } + + place++; + if (*place == ':') { + if (*scan != '\0') { + acl_optarg = scan; + scan = NULL; + } else if (acl_optind < argc) { + acl_optarg = argv[acl_optind]; + acl_optind++; + } else { + printf("%s: -%c argument missing\n", argv[0], c); + return('?'); + } + } + + return(c); +} diff --git a/lib_acl/src/stdlib/acl_getopt.c.bak b/lib_acl/src/stdlib/acl_getopt.c.bak new file mode 100644 index 000000000..e3272d4a6 --- /dev/null +++ b/lib_acl/src/stdlib/acl_getopt.c.bak @@ -0,0 +1,92 @@ + +#include "stdlib/acl_define.h" +#include +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_getopt.h" + +#define ERR(s, c) \ + if (acl_opterr) { \ + char errbuf[2]; \ + errbuf[0] = c; errbuf[1] = '\n'; \ + (void) printf("%s", argv[0]); \ + (void) printf("%s", s); \ + (void) printf("%s", errbuf); \ + } + +int acl_opterr; +int acl_optind; +int acl_optopt; +char *acl_optarg; + +static int sp = 1; +static int call_first = 1; + +void acl_getopt_init(void) +{ + acl_opterr = 1; + acl_optind = 1; + call_first = 0; + + sp = 1; +} + +int acl_getopt(int argc, char **argv, char *opts) +{ + register int c; + register char *cp; + + if (call_first) + acl_getopt_init(); + + if(sp == 1) { + if(acl_optind >= argc || argv[acl_optind][0] != '-' || argv[acl_optind][1] == '\0') + return(-1); + else if(strcmp(argv[acl_optind], "--") == 0) { + acl_optind++; + return(-1); + } + } + acl_optopt = c = argv[acl_optind][sp]; + if (c == ':') { + ERR(": illegal option -- ", c); + if (argv[acl_optind][++sp] == '\0') { + acl_optind++; + sp = 1; + } + return('?'); + + } + + if ((cp = strchr(opts, c)) == NULL) { + if (argv[acl_optind][++sp] == '\0') { + acl_optind++; + sp = 1; + } + return('?'); + } + + if(*++cp == ':') { + if(argv[acl_optind][sp+1] != '\0') + acl_optarg = &argv[acl_optind++][sp+1]; + else if(++acl_optind >= argc) { + ERR(": option requires an argument -- ", c); + sp = 1; + return('?'); + } else + acl_optarg = argv[acl_optind++]; + sp = 1; + } else { + if(argv[acl_optind][++sp] == '\0') { + sp = 1; + acl_optind++; + } + acl_optarg = NULL; + } + return(c); +} diff --git a/lib_acl/src/stdlib/acl_meter_time.c b/lib_acl/src/stdlib/acl_meter_time.c new file mode 100644 index 000000000..042e7b54e --- /dev/null +++ b/lib_acl/src/stdlib/acl_meter_time.c @@ -0,0 +1,97 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_sys_patch.h" +#include "init/acl_init.h" +#include "thread/acl_pthread.h" +#include +#include +#ifdef ACL_UNIX +#include +#endif +#include "stdlib/acl_meter_time.h" + +#endif + +static void dummy(void *ptr acl_unused) +{ + +} + +static void free_tls(void *ptr) +{ + acl_myfree(ptr); +} + +static void *__tls = NULL; +static void main_free_tls(void) +{ + if (__tls) { + acl_myfree(__tls); + __tls = NULL; + } +} + +static acl_pthread_key_t once_key; +static void once_init(void) +{ + if ((unsigned long) acl_pthread_self() == acl_main_thread_self()) { + acl_pthread_key_create(&once_key, dummy); + atexit(main_free_tls); + } else + acl_pthread_key_create(&once_key, free_tls); +} + +static acl_pthread_once_t once_control = ACL_PTHREAD_ONCE_INIT; +static void *tls_calloc(size_t len) +{ + void *ptr; + + (void) acl_pthread_once(&once_control, once_init); + ptr = (void*) acl_pthread_getspecific(once_key); + if (ptr == NULL) { + ptr = acl_mycalloc(1, len); + acl_pthread_setspecific(once_key, ptr); + if ((unsigned long) acl_pthread_self() == acl_main_thread_self()) + __tls = ptr; + } + return ptr; +} + +typedef struct { + struct timeval stamp; + int init_done; +} METER_CTX_T; + +double acl_meter_time(const char *filename, int line, const char *info) +{ + struct timeval now; + double f; + METER_CTX_T *ctx = tls_calloc(sizeof(METER_CTX_T)); + + if (ctx->init_done == 0) { + ctx->init_done = 1; + gettimeofday(&ctx->stamp, NULL); + } + + gettimeofday(&now, NULL); + now.tv_usec -= ctx->stamp.tv_usec; + if (now.tv_usec < 0) { + --now.tv_sec; + now.tv_usec += 1000000; + } + now.tv_sec -= ctx->stamp.tv_sec; + + f = now.tv_sec * 1000.0 + now.tv_usec/1000.0; + if (info) + printf("tid=%lu, %s(%d), %s: time inter = %8.3f ms\r\n", + (unsigned long) acl_pthread_self(), filename, line, info, f); + else + printf("tid=%lu, %s(%d): time inter = %8.3f ms\r\n", + (unsigned long) acl_pthread_self(), filename, line, f); + + gettimeofday(&ctx->stamp, NULL); + return (f); +} diff --git a/lib_acl/src/stdlib/acl_msg.c b/lib_acl/src/stdlib/acl_msg.c new file mode 100644 index 000000000..7a56247a7 --- /dev/null +++ b/lib_acl/src/stdlib/acl_msg.c @@ -0,0 +1,568 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef ACL_UNIX +#include +#endif + +#include +#include +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_mylog.h" +#include "stdlib/acl_msg.h" +#include "stdlib/acl_mymalloc.h" +#include "thread/acl_pthread.h" +#include "init/acl_init.h" + +#endif + +int acl_msg_verbose = 0; + +#ifndef USE_PRINTF_MACRO + +static int __log_open_flag = 0; +static int __stdout_enable = 0; + +static ACL_MSG_OPEN_FN __open_fn = NULL; +static ACL_MSG_CLOSE_FN __close_fn = NULL; +static ACL_MSG_WRITE_FN __write_fn = NULL; +static ACL_MSG_PRE_WRITE_FN __pre_write_fn = NULL; +static void *__pre_write_ctx = NULL; +static void *__msg_ctx = NULL; + +void acl_msg_register(ACL_MSG_OPEN_FN open_fn, ACL_MSG_CLOSE_FN close_fn, + ACL_MSG_WRITE_FN write_fn, void *ctx) +{ + if (open_fn == NULL || write_fn == NULL) + return; + + __open_fn = open_fn; + __close_fn = close_fn, + __write_fn = write_fn; + __msg_ctx = ctx; +} + +void acl_msg_unregister(void) +{ + __open_fn = NULL; + __close_fn = NULL; + __write_fn = NULL; + __msg_ctx = NULL; +} + +void acl_msg_pre_write(ACL_MSG_PRE_WRITE_FN pre_write, void *ctx) +{ + __pre_write_fn = pre_write; + __pre_write_ctx = ctx; +} + +void acl_msg_stdout_enable(int onoff) +{ + __stdout_enable = onoff; +} + +void acl_msg_open2(ACL_VSTREAM *fp, const char *info_pre) +{ + if (fp == NULL || info_pre == NULL || *info_pre == 0) + return; + + if (__open_fn != NULL) { + int ret = __open_fn(ACL_VSTREAM_PATH(fp), __msg_ctx); + /* if return < 0, use the default log */ + if (ret < 0) { + __open_fn = NULL; + __close_fn = NULL; + __write_fn = NULL; + __msg_ctx = NULL; + acl_log_fp_set(fp, info_pre); + } + } else { + acl_log_fp_set(fp, info_pre); + } + __log_open_flag = 1; +} + +void acl_msg_open(const char *log_file, const char *info_pre) +{ + char where[] = "acl_msg_open"; + int ret; + + if (log_file == NULL || *log_file == 0 + || info_pre == NULL || *info_pre == 0) + { + return; + } + + if (__open_fn != NULL) { + ret = __open_fn(log_file, __msg_ctx); + /* if return < 0, use the default log */ + if (ret < 0) { + __open_fn = NULL; + __close_fn = NULL; + __write_fn = NULL; + __msg_ctx = NULL; + ret = acl_open_log(log_file, info_pre); + } + } else { + ret = acl_open_log(log_file, info_pre); + } + if (ret < 0) { + char ebuf[256]; + printf("%s: can't open log file=%s, info_pre=%s,%s\n", + where, log_file, info_pre, acl_last_strerror(ebuf, sizeof(ebuf))); + __log_open_flag = 0; + __open_fn = NULL; + __write_fn = NULL; + __msg_ctx = NULL; + return; + } + __log_open_flag = 1; +} + +void acl_msg_close(void) +{ + if (__log_open_flag == 0) + return; + acl_close_log(); + __log_open_flag = 0; + if (__close_fn) + __close_fn(__msg_ctx); +} + +void acl_msg_info(const char *fmt,...) +{ + va_list ap; + + va_start (ap, fmt); + + if (__pre_write_fn) { + __pre_write_fn(__pre_write_ctx, fmt, ap); + } + + if (__log_open_flag) { + if (__write_fn != NULL) + __write_fn(__msg_ctx, fmt, ap); + else + acl_write_to_log2("info", fmt, ap); + } else if (__stdout_enable) { +#ifdef LINUX + printf("acl_msg_info->pid(%d), ", getpid()); +#elif defined(SOLARIS) + printf("acl_msg_info->pid(%ld), ", getpid()); +#endif + vprintf(fmt, ap); + printf("\r\n"); + } + + va_end (ap); +} + +void acl_msg_info2(const char *fmt, va_list ap) +{ + if (__pre_write_fn) + __pre_write_fn(__pre_write_ctx, fmt, ap); + + if (__log_open_flag) { + if (__write_fn != NULL) + __write_fn(__msg_ctx, fmt, ap); + else + acl_write_to_log2("info", fmt, ap); + } else if (__stdout_enable) { +#ifdef LINUX + printf("acl_msg_info->pid(%d), ", getpid()); +#elif defined(SOLARIS) + printf("acl_msg_info->pid(%ld), ", getpid()); +#endif + vprintf(fmt, ap); + printf("\r\n"); + } +} +void acl_msg_warn(const char *fmt,...) +{ + va_list ap; + + va_start (ap, fmt); + + if (__pre_write_fn) + __pre_write_fn(__pre_write_ctx, fmt, ap); + + if (__log_open_flag) { + if (__write_fn != NULL) + __write_fn(__msg_ctx, fmt, ap); + else + acl_write_to_log2("warn", fmt, ap); + } else if (__stdout_enable) { +#ifdef LINUX + printf("acl_msg_warn->pid(%d), ", getpid()); +#elif defined(SOLARIS) + printf("acl_msg_warn->pid(%ld), ", getpid()); +#endif + + vprintf(fmt, ap); + printf("\r\n"); + } + + va_end (ap); +} +void acl_msg_warn2(const char *fmt, va_list ap) +{ + if (__pre_write_fn) + __pre_write_fn(__pre_write_ctx, fmt, ap); + + if (__log_open_flag) { + if (__write_fn != NULL) + __write_fn(__msg_ctx, fmt, ap); + else + acl_write_to_log2("warn", fmt, ap); + } else if (__stdout_enable) { +#ifdef LINUX + printf("acl_msg_warn->pid(%d), ", getpid()); +#elif defined(SOLARIS) + printf("acl_msg_warn->pid(%ld), ", getpid()); +#endif + vprintf(fmt, ap); + printf("\r\n"); + } +} +void acl_msg_error(const char *fmt,...) +{ + va_list ap; + + va_start (ap, fmt); + + if (__pre_write_fn) + __pre_write_fn(__pre_write_ctx, fmt, ap); + + if (__log_open_flag) { + if (__write_fn != NULL) + __write_fn(__msg_ctx, fmt, ap); + else + acl_write_to_log2("error", fmt, ap); + } else if (__stdout_enable) { +#ifdef LINUX + printf("acl_msg_error->pid(%d), ", getpid()); +#elif defined(SOLARIS) + printf("acl_msg_error->pid(%ld), ", getpid()); +#endif + vprintf(fmt, ap); + printf("\r\n"); + } + + va_end (ap); +} +void acl_msg_error2(const char *fmt, va_list ap) +{ + if (__pre_write_fn) + __pre_write_fn(__pre_write_ctx, fmt, ap); + + if (__log_open_flag) { + if (__write_fn != NULL) + __write_fn(__msg_ctx, fmt, ap); + else + acl_write_to_log2("error", fmt, ap); + } else if (__stdout_enable) { +#ifdef LINUX + printf("acl_msg_error->pid(%d), ", getpid()); +#elif defined(SOLARIS) + printf("acl_msg_error->pid(%ld), ", getpid()); +#endif + vprintf(fmt, ap); + printf("\r\n"); + } +} +void acl_msg_fatal(const char *fmt,...) +{ + va_list ap; + + va_start (ap, fmt); + + if (__pre_write_fn) + __pre_write_fn(__pre_write_ctx, fmt, ap); + + if (__log_open_flag) { + if (__write_fn != NULL) + __write_fn(__msg_ctx, fmt, ap); + else + acl_write_to_log2("fatal", fmt, ap); + } else if (__stdout_enable) { +#ifdef LINUX + printf("acl_msg_fatal->pid(%d), ", getpid()); +#elif defined(SOLARIS) + printf("acl_msg_fatal->pid(%ld), ", getpid()); +#endif + printf("fatal:"); + vprintf(fmt, ap); + printf("\r\n"); + } + + va_end (ap); + acl_close_log(); + acl_assert(0); +} + +void acl_msg_fatal2(const char *fmt, va_list ap) +{ + if (__pre_write_fn) + __pre_write_fn(__pre_write_ctx, fmt, ap); + + if (__log_open_flag) { + if (__write_fn != NULL) + __write_fn(__msg_ctx, fmt, ap); + else + acl_write_to_log2("fatal", fmt, ap); + } else if (__stdout_enable) { +#ifdef LINUX + printf("acl_msg_fatal->pid(%d), ", getpid()); +#elif defined(SOLARIS) + printf("acl_msg_fatal->pid(%ld), ", getpid()); +#endif + vprintf(fmt, ap); + printf("\r\n"); + } + acl_close_log(); + acl_assert(0); +} + +void acl_msg_fatal_status(int status, const char *fmt,...) +{ + va_list ap; + + status = status; + va_start (ap, fmt); + + if (__log_open_flag) { + if (__write_fn != NULL) + __write_fn(__msg_ctx, fmt, ap); + else + acl_write_to_log2("fatal", fmt, ap); + } else if (__stdout_enable) { +#ifdef LINUX + printf("acl_msg_fatal_status->pid(%d), ", getpid()); +#elif defined(SOLARIS) + printf("acl_msg_fatal_status->pid(%ld), ", getpid()); +#endif + vprintf(fmt, ap); + printf("\r\n"); + } + + va_end (ap); + acl_close_log(); + acl_assert(0); +} + +void acl_msg_fatal_status2(int status, const char *fmt, va_list ap) +{ + status = status; + if (__log_open_flag) { + if (__write_fn != NULL) + __write_fn(__msg_ctx, fmt, ap); + else + acl_write_to_log2("fatal", fmt, ap); + } else if (__stdout_enable) { +#ifdef LINUX + printf("acl_msg_fatal_status->pid(%d), ", getpid()); +#elif defined(SOLARIS) + printf("acl_msg_fatal_status->pid(%ld), ", getpid()); +#endif + vprintf(fmt, ap); + printf("\r\n"); + } + + acl_close_log(); + acl_assert(0); +} + +void acl_msg_panic(const char *fmt,...) +{ + va_list ap; + + va_start (ap, fmt); + + if (__pre_write_fn) + __pre_write_fn(__pre_write_ctx, fmt, ap); + + if (__log_open_flag) { + if (__write_fn != NULL) + __write_fn(__msg_ctx, fmt, ap); + else + acl_write_to_log2("panic", fmt, ap); + } else if (__stdout_enable) { +#ifdef LINUX + printf("acl_msg_panic->pid(%d), ", getpid()); +#elif defined(SOLARIS) + printf("acl_msg_panic->pid(%ld), ", getpid()); +#endif + vprintf(fmt, ap); + printf("\r\n"); + } + + va_end (ap); + acl_close_log(); + acl_assert(0); +} + +void acl_msg_panic2(const char *fmt, va_list ap) +{ + if (__pre_write_fn) + __pre_write_fn(__pre_write_ctx, fmt, ap); + + if (__log_open_flag) { + if (__write_fn != NULL) + __write_fn(__msg_ctx, fmt, ap); + else + acl_write_to_log2("panic", fmt, ap); + } else if (__stdout_enable) { +#ifdef LINUX + printf("acl_msg_panic->pid(%d), ", getpid()); +#elif defined(SOLARIS) + printf("acl_msg_panic->pid(%ld), ", getpid()); +#endif + vprintf(fmt, ap); + printf("\r\n"); + } + + acl_close_log(); + acl_assert(0); +} +#endif /* USE_PRINTF_MACRO */ + +const char *acl_strerror(unsigned int errnum, char *buffer, int size) +{ + char myname[] = "acl_strerror"; +#ifdef ACL_MS_WINDOWS + int L; + + if (buffer == NULL || size <= 0) { + acl_msg_error("%s, %s(%d): input error", + __FILE__, myname, __LINE__); + return (NULL); + } + + L = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY, + NULL, + errnum, + 0, + buffer, + size, + NULL); + while((L > 0) && + ((buffer[L - 1] >= 0 && + buffer[L - 1] <= 32) || + (buffer[L - 1] == '.'))) { + buffer[L - 1] = '\0'; + L--; + } +#elif defined(ACL_UNIX) + if (buffer == NULL || size <= 0) { + acl_msg_error("%s, %s(%d): input error", + __FILE__, myname, __LINE__); + return (NULL); + } + + snprintf(buffer, size, "%s", strerror(errnum)); +#else +# error "unknown OS type" +#endif + + return (buffer); +} + +const char *acl_last_strerror(char *buffer, int size) +{ + return (acl_strerror(acl_last_error(), buffer, size)); +} + +static acl_pthread_key_t __errbuf_key; + +static void free_buf(void *arg) +{ + char *buf = (char*) arg; + acl_myfree(buf); +} + +static void dummy_free(void *arg acl_unused) +{ +} + +static char *__main_buf = NULL; + +static void free_main_buf(void) +{ + if (__main_buf) + acl_myfree(__main_buf); +} + +static void error_buf_init(void) +{ + if ((unsigned long) acl_pthread_self() == acl_main_thread_self()) { + acl_pthread_key_create(&__errbuf_key, dummy_free); + atexit(free_main_buf); + } else + acl_pthread_key_create(&__errbuf_key, free_buf); +} + +static acl_pthread_once_t once_control = ACL_PTHREAD_ONCE_INIT; + +const char *acl_last_serror(void) +{ + char *buf; + int error = acl_last_error(); + static int __buf_size = 4096; + + (void) acl_pthread_once(&once_control, error_buf_init); + buf = acl_pthread_getspecific(__errbuf_key); + if (buf == NULL) { + buf = acl_mymalloc(__buf_size); + acl_pthread_setspecific(__errbuf_key, buf); + if ((unsigned long) acl_pthread_self() == acl_main_thread_self()) + __main_buf = buf; + } + return (acl_strerror(error, buf, __buf_size)); +} + +int acl_last_error(void) +{ + int error; + +#ifdef ACL_MS_WINDOWS + error = WSAGetLastError(); + WSASetLastError(error); +#elif defined(ACL_UNIX) + error = errno; +#else +# error "unknow OS type" +#endif + return (error); +} + +void acl_set_error(int errnum) +{ +#ifdef ACL_MS_WINDOWS + WSASetLastError(errnum); + errno = errnum; +#elif defined(ACL_UNIX) + errno = errnum; +#else +# error "unknown OS type" +#endif +} + +void acl_msg_printf(const char *fmt,...) +{ + char buf[2048]; + va_list ap; + + va_start (ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + printf("%s\r\n", buf); + + va_end (ap); +} diff --git a/lib_acl/src/stdlib/acl_myflock.c b/lib_acl/src/stdlib/acl_myflock.c new file mode 100644 index 000000000..e818cc6b9 --- /dev/null +++ b/lib_acl/src/stdlib/acl_myflock.c @@ -0,0 +1,216 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +/* System library. */ + +#include "stdlib/acl_define.h" +#include "stdlib/acl_msg.h" +#include "stdlib/acl_myflock.h" +#include "stdlib/acl_sys_patch.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include + +#endif + +#ifdef ACL_UNIX + +#include +#include /* printf() */ + +#include + +#ifdef ACL_HAS_FCNTL_LOCK +#include +#include +#endif + +#ifdef ACL_HAS_FLOCK_LOCK +#include +#endif + +/* acl_myflock - lock/unlock entire open file */ + +int acl_myflock(ACL_FILE_HANDLE fd, int lock_style, int operation) +{ + int status = 0; + + /* + * Sanity check. + */ + if ((operation & (ACL_MYFLOCK_OP_BITS)) != operation) + acl_msg_panic("myflock: improper operation type: 0x%x", operation); + + switch (lock_style) { + + /* + * flock() does exactly what we need. Too bad it is not standard. + */ +#ifdef ACL_HAS_FLOCK_LOCK + case ACL_MYFLOCK_STYLE_FLOCK: + { + static int lock_ops[] = { + LOCK_UN, LOCK_SH, LOCK_EX, -1, + -1, LOCK_SH | LOCK_NB, LOCK_EX | LOCK_NB, -1 + }; + + status = flock(fd, lock_ops[operation]); + break; + } +#endif + + /* + * fcntl() is standard and does more than we need, but we can handle + * it. + */ +#ifdef ACL_HAS_FCNTL_LOCK + case ACL_MYFLOCK_STYLE_FCNTL: + { + struct flock lock; + int request; + static int lock_ops[] = { + F_UNLCK, F_RDLCK, F_WRLCK + }; + + memset((char *) &lock, 0, sizeof(lock)); + lock.l_type = lock_ops[operation & ~ACL_MYFLOCK_OP_NOWAIT]; + request = (operation & ACL_MYFLOCK_OP_NOWAIT) ? F_SETLK : F_SETLKW; + while ((status = fcntl(fd, request, &lock)) < 0 + && request == F_SETLKW + && (acl_last_error() == ACL_EINTR + || acl_last_error() == ENOLCK + || acl_last_error() == EDEADLK)) + sleep(1); + break; + } +#endif + default: + acl_msg_panic("myflock: unsupported lock style: 0x%x", lock_style); + } + + /* + * Return a consistent result. Some systems return EACCES when a lock is + * taken by someone else, and that would complicate error processing. + */ + if (status < 0 && (operation & ACL_MYFLOCK_OP_NOWAIT) != 0) { + char error = acl_last_error(); + if (error == ACL_EAGAIN || error == ACL_EWOULDBLOCK || error == EACCES) + acl_set_error(ACL_EAGAIN); + } + + return (status); +} +#endif /* ACL_UNIX */ + +#ifdef ACL_MS_WINDOWS +# ifdef USE_LOCK_FILE +/* use LockFile/UnlockFile */ +int acl_myflock(ACL_FILE_HANDLE fd, int lock_style acl_unused, int operation) +{ + const char *myname = "acl_myflock"; + DWORD size = 0xFFFFFFFF; + char ebuf[256]; + unsigned char lock_op; + + if ((operation & (ACL_MYFLOCK_OP_BITS)) != operation) + acl_msg_panic("myflock: improper operation type: 0x%x", operation); + + lock_op = operation & ~ACL_MYFLOCK_OP_NOWAIT; + + if (lock_op == ACL_MYFLOCK_OP_NONE) { + if(UnlockFile(fd, 0, 0, size, 0)) + return (0); + + acl_msg_error("%s(%d): unlock error(%s)", + myname, __LINE__, acl_last_strerror(ebuf,sizeof(ebuf))); + return (-1); + } else if (lock_op == ACL_MYFLOCK_OP_SHARED) { + while (1) { + if(LockFile(fd, 0, 0, size, 0)) + return (0); + + if ((operation & ACL_MYFLOCK_OP_NOWAIT)) + return (-1); + sleep(1); + } + } else if (lock_op == ACL_MYFLOCK_OP_EXCLUSIVE) { + while (1) { + if(LockFile(fd, 0, 0, size, 0)) + return (0); + + if ((operation & ACL_MYFLOCK_OP_NOWAIT)) + return (-1); + sleep(1); + } + } + + acl_msg_error("%s(%d): invalid lock_op(%d)", myname, __LINE__, lock_op); + return (-1); +} +# else +/* use LockFileEx/UnlockFileEx */ +int acl_myflock(ACL_FILE_HANDLE fd, int lock_style acl_unused, int operation) +{ + const char *myname = "acl_myflock"; + DWORD size = 0xFFFFFFFF; + char ebuf[256]; + unsigned char lock_op; + OVERLAPPED ovlp; + DWORD flags; + + if ((operation & (ACL_MYFLOCK_OP_BITS)) != operation) + acl_msg_panic("myflock: improper operation type: 0x%x", operation); + + memset(&ovlp, 0, sizeof(ovlp)); + + ovlp.Offset = 0; + lock_op = operation & ~ACL_MYFLOCK_OP_NOWAIT; + if (lock_op == ACL_MYFLOCK_OP_NONE) { + if(UnlockFileEx(fd, 0, 1, 0, &ovlp)) + return (0); + acl_msg_error("%s(%d): unlock error(%s)", + myname, __LINE__, acl_last_strerror(ebuf,sizeof(ebuf))); + return (-1); + } else if (lock_op == ACL_MYFLOCK_OP_SHARED) { + while (1) { + flags = 0; + if ((operation & ACL_MYFLOCK_OP_NOWAIT)) + flags |= LOCKFILE_FAIL_IMMEDIATELY; + + if(LockFileEx(fd, flags, 0, 1, 0, &ovlp)) + return (0); + if ((operation & ACL_MYFLOCK_OP_NOWAIT)) { + acl_msg_error("%s(%d): lock error(%s)", myname, __LINE__, + acl_last_strerror(ebuf,sizeof(ebuf))); + return (-1); + } + sleep(1); + } + } else if (lock_op == ACL_MYFLOCK_OP_EXCLUSIVE) { + while (1) { + flags = LOCKFILE_EXCLUSIVE_LOCK; + if ((operation & ACL_MYFLOCK_OP_NOWAIT)) + flags |= LOCKFILE_FAIL_IMMEDIATELY; + + if(LockFileEx(fd, flags, 0, 1, 0, &ovlp)) + return (0); + + if ((operation & ACL_MYFLOCK_OP_NOWAIT)) { + acl_msg_error("%s(%d): lock error(%s)", myname, __LINE__, + acl_last_strerror(ebuf,sizeof(ebuf))); + return (-1); + } + sleep(1); + } + } + + acl_msg_error("%s(%d): invalid lock_op(%d)", myname, __LINE__, lock_op); + return (-1); +} +# endif /* #if 0 */ +#endif + + diff --git a/lib_acl/src/stdlib/acl_mylog.c b/lib_acl/src/stdlib/acl_mylog.c new file mode 100644 index 000000000..2dda7e6c2 --- /dev/null +++ b/lib_acl/src/stdlib/acl_mylog.c @@ -0,0 +1,745 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE +#include "stdlib/acl_define.h" + +/* #include */ +#include +#include + +#ifdef ACL_MS_WINDOWS +# include +# ifdef ACL_MS_VC +/* #include */ +# include +# include +/* #include */ +# endif +#elif defined(ACL_UNIX) +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#else +# error "unknown OS type" +#endif + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_sys_patch.h" +#include "stdlib/acl_iostuff.h" +#include "stdlib/acl_iterator.h" +#include "stdlib/acl_msg.h" +#include "stdlib/acl_argv.h" +#include "net/acl_sane_inet.h" +#include "stdlib/acl_mylog.h" + +#endif + +#include "../private/private_fifo.h" +#include "../private/private_vstream.h" +#include "../private/thread.h" + +struct ACL_LOG { + ACL_VSTREAM *fp; + char *path; + int flag; +#define ACL_LOG_F_DEAD (1 << 0) +#define ACL_LOG_F_FIXED (1 << 1) + + int type; +#define ACL_LOG_T_UNKNOWN 0 +#define ACL_LOG_T_FILE 1 +#define ACL_LOG_T_TCP 2 +#define ACL_LOG_T_UDP 3 +#define ACL_LOG_T_UNIX 4 + +#define IS_NET_STREAM(x) ((x)->type == ACL_LOG_T_TCP || (x)->type == ACL_LOG_T_UNIX) + + char logpre[256]; + acl_pthread_mutex_t *lock; + struct sockaddr_in from; + struct sockaddr_in dest; + int from_len; + acl_uint64 count; /**< 已经记录的日志条数 */ + time_t last_open; /**< 上次日志打开时间 */ + time_t reopen_inter; /**< 日志重新打开的最小时间间隔 */ +}; + +#ifdef WIN32 +# define strdup _strdup +#endif + +static int __log_thread_id = 0; +static ACL_FIFO *__loggers = NULL; + +void acl_log_add_tid(int onoff) +{ + __log_thread_id = onoff ? 1 : 0; +} + +void acl_log_fp_set(ACL_VSTREAM *fp, const char *logpre) +{ + const char *myname = "acl_log_fp_set"; + ACL_LOG *log; + ACL_ITER iter; + + acl_assert(fp); + + if (__loggers == NULL) + __loggers = private_fifo_new(); + + acl_foreach(iter, __loggers) { + log = (ACL_LOG*) iter.data; + if (strcmp(log->path, fp->remote_addr) == 0) { + acl_msg_warn("%s(%d): log %s has been opened.", + myname, __LINE__, log->path); + return; + } + } + +#ifdef ACL_UNIX + acl_close_on_exec(ACL_VSTREAM_SOCK(fp), ACL_CLOSE_ON_EXEC); +#endif + log = (ACL_LOG*) calloc(1, sizeof(ACL_LOG)); + log->fp = fp; + log->path = strdup(fp->remote_addr); + log->type = ACL_LOG_T_UNKNOWN; + log->lock = (acl_pthread_mutex_t*) calloc(1, sizeof(acl_pthread_mutex_t)); + thread_mutex_init(log->lock, NULL); + if (logpre && *logpre) + snprintf(log->logpre, sizeof(log->logpre), "%s", logpre); + else + log->logpre[0] = 0; + log->flag |= ACL_LOG_F_FIXED; + private_fifo_push(__loggers, log); +} + +static int open_file_log(const char *filename, const char *logpre) +{ + const char *myname = "open_file_log"; +#ifdef ACL_MS_WINDOWS + int flag = O_RDWR | O_CREAT | O_APPEND | O_BINARY; +#else + int flag = O_RDWR | O_CREAT | O_APPEND; +#endif + int mode = S_IREAD | S_IWRITE; + ACL_LOG *log; + ACL_ITER iter; + ACL_VSTREAM *fp; + ACL_FILE_HANDLE fh; + + acl_foreach(iter, __loggers) { + log = (ACL_LOG*) iter.data; + if (strcmp(log->path, filename) == 0) { + acl_msg_warn("%s(%d): log %s has been opened.", + myname, __LINE__, filename); + return (0); + } + } + + fh = acl_file_open(filename, flag, mode); + if (fh == ACL_FILE_INVALID) { + printf("%s(%d): open %s error(%s)", myname, __LINE__, + filename, acl_last_serror()); + return (-1); + } + + fp = private_vstream_fhopen(fh, O_RDWR); + snprintf(fp->remote_addr, sizeof(fp->remote_addr), "%s", filename); + +#ifdef ACL_UNIX + acl_close_on_exec(fh, ACL_CLOSE_ON_EXEC); +#endif + + log = (ACL_LOG*) calloc(1, sizeof(ACL_LOG)); + log->last_open = time(NULL); + log->fp = fp; + log->path = strdup(filename); + log->type = ACL_LOG_T_FILE; + log->lock = (acl_pthread_mutex_t*) calloc(1, sizeof(acl_pthread_mutex_t)); + thread_mutex_init(log->lock, NULL); + if (logpre && *logpre) + snprintf(log->logpre, sizeof(log->logpre), "%s", logpre); + else + log->logpre[0] = 0; + + private_fifo_push(__loggers, log); + return (0); +} + +static int reopen_log(ACL_LOG *log) +{ + time_t now = time(NULL); + +#undef RETURN +#define RETURN(x) do { \ + if (log->lock) \ + thread_mutex_unlock(log->lock); \ + return (x); \ +} while (0) + + if (log->lock) + thread_mutex_lock(log->lock); + + if (!(log->flag & ACL_LOG_F_DEAD) + || (log->flag & ACL_LOG_F_FIXED) + || !IS_NET_STREAM(log) + || log->fp == NULL + || log->reopen_inter <= 0) + { + RETURN (-1); + } + + if (log->count == 0) { + if (now - log->last_open < 5 * log->reopen_inter) + RETURN (-1); + } else if (now - log->last_open < log->reopen_inter) + RETURN (-1); + + private_vstream_close(log->fp); + acl_assert(log->path); + log->fp = private_vstream_connect(log->path, 60, 60); + log->last_open = time(NULL); + if (log->fp == NULL) + RETURN (-1); + log->flag &= ~ACL_LOG_F_DEAD; + log->last_open = time(NULL); + RETURN (0); +} + +static int open_stream_log(const char *addr, const char *logpre, int type) +{ + const char *myname = "open_stream_log"; + ACL_VSTREAM *fp; + ACL_LOG *log; + ACL_ITER iter; + + acl_foreach(iter, __loggers) { + log = (ACL_LOG*) iter.data; + if (strcmp(log->path, addr) == 0 && log->type == type) { + acl_msg_warn("%s(%d): log(%s) has been opened!", + myname, __LINE__, addr); + return (0); + } + } + + fp = private_vstream_connect(addr, 60, 60); + if (fp == NULL) { + printf("%s(%d): connect %s error(%s)\n", + myname, __LINE__, addr, acl_last_serror()); + return (-1); + } + + log = (ACL_LOG*) calloc(1, sizeof(ACL_LOG)); + log->last_open = time(NULL); + log->reopen_inter = 60; + log->fp = fp; + log->path = strdup(addr); + log->lock = (acl_pthread_mutex_t*) calloc(1, sizeof(acl_pthread_mutex_t)); + thread_mutex_init(log->lock, NULL); + log->type = type; + if (logpre && *logpre) + snprintf(log->logpre, sizeof(log->logpre), "%s", logpre); + else + log->logpre[0] = 0; + + private_fifo_push(__loggers, log); + return (0); +} + +static int open_tcp_log(const char *addr, const char *logpre) +{ + return (open_stream_log(addr, logpre, ACL_LOG_T_TCP)); +} + +static int open_unix_log(const char *addr, const char *logpre) +{ + return (open_stream_log(addr, logpre, ACL_LOG_T_UNIX)); +} + +static int udp_read(ACL_SOCKET fd, void *buf, size_t size, + int timeout acl_unused, void *arg) +{ + ACL_LOG *log = (ACL_LOG*) arg; + int ret; + +#ifdef ACL_UNIX + ret = recvfrom(fd, buf, size, 0, (struct sockaddr*) &log->from, + (socklen_t*) &log->from_len); +#elif defined(ACL_MS_WINDOWS) + ret = recvfrom(fd, (char*) buf, (int) size, 0, + (struct sockaddr*) &log->from, &log->from_len); +#else +#error "unknown OS" +#endif + return (ret); +} + +static int udp_write(ACL_SOCKET fd, const void *buf, size_t size, + int timeout acl_unused, void *arg) +{ + ACL_LOG *log = (ACL_LOG*) arg; + int ret; + +#ifdef ACL_UNIX + ret = sendto(fd, buf, size, 0, (struct sockaddr*) &log->dest, + sizeof(log->dest)); +#elif defined(ACL_MS_WINDOWS) + ret = sendto(fd, (const char*) buf, (int) size, 0, + (struct sockaddr*) &log->dest, sizeof(log->dest)); +#else +#error "unknown OS" +#endif + return (ret); +} + +static int open_udp_log(const char *addr, const char *logpre) +{ + const char *myname = "open_udp_log"; + ACL_LOG *log; + ACL_ITER iter; + ACL_SOCKET fd; + char ip[64], *ptr; + int port; + + snprintf(ip, sizeof(ip), "%s", addr); + ptr = strchr(ip, ':'); + acl_assert(ptr); + *ptr++ = 0; + port = atoi(ptr); + acl_assert(port > 0); + + acl_foreach(iter, __loggers) { + log = (ACL_LOG*) iter.data; + if (strcmp(log->path, addr) == 0 && log->type == ACL_LOG_T_UDP) { + acl_msg_warn("%s(%d): log(%s) has been opened!", + myname, __LINE__, addr); + return (0); + } + } + + log = (ACL_LOG*) calloc(1, sizeof(ACL_LOG)); + + fd = socket(AF_INET, SOCK_DGRAM, 0); + acl_assert(fd != ACL_SOCKET_INVALID); + log->fp = private_vstream_fdopen(fd, O_RDWR, 1024, 0, ACL_VSTREAM_TYPE_SOCK); + private_vstream_ctl(log->fp, + ACL_VSTREAM_CTL_READ_FN, udp_read, + ACL_VSTREAM_CTL_WRITE_FN, udp_write, + ACL_VSTREAM_CTL_CONTEXT, log, + ACL_VSTREAM_CTL_END); + log->last_open = time(NULL); + log->dest.sin_family = AF_INET; + log->dest.sin_addr.s_addr = inet_addr(ip); + log->dest.sin_port = htons(port); + + log->from_len = sizeof(log->from); + + log->path = strdup(addr); + log->lock = (acl_pthread_mutex_t*) calloc(1, sizeof(acl_pthread_mutex_t)); + thread_mutex_init(log->lock, NULL); + log->type = ACL_LOG_T_UDP; + if (logpre && *logpre) + snprintf(log->logpre, sizeof(log->logpre), "%s", logpre); + else + log->logpre[0] = 0; + + private_fifo_push(__loggers, log); + return (0); +} + +/* + * recipient: + * tcp:127.0.0.1:8088 + * udp:127.0.0.1:8088 + * unix:/var/log/unix.sock + * file:/var/log/unix.log + * /var/log/unix.log + */ +static int open_log(const char *recipient, const char *logpre) +{ + const char *myname = "open_log"; + const char *ptr; + + if (strncasecmp(recipient, "tcp:", 4) == 0) { + ptr = recipient + 4; + if (acl_ipv4_addr_valid(ptr) == 0) { + printf("%s(%d): recipient(%s) invalid", + myname, __LINE__, recipient); + return (-1); + } + return (open_tcp_log(ptr, logpre)); + } else if (strncasecmp(recipient, "udp:", 4) == 0) { + ptr = recipient + 4; + if (acl_ipv4_addr_valid(ptr) == 0) { + printf("%s(%d): recipient(%s) invalid", + myname, __LINE__, recipient); + return (-1); + } + return (open_udp_log(ptr, logpre)); + } else if (strncasecmp(recipient, "unix:", 5) == 0) { + ptr = recipient + 5; + if (*ptr == 0) { + printf("%s(%d): recipient(%s) invalid", + myname, __LINE__, recipient); + return (-1); + } + return (open_unix_log(ptr, logpre)); + } else if (strncasecmp(recipient, "file:", 5) == 0) { + ptr = recipient + 5; + if (*ptr == 0) { + printf("%s(%d): recipient(%s) invalid", + myname, __LINE__, recipient); + return (-1); + } + return (open_file_log(recipient, logpre)); + } else { + return (open_file_log(recipient, logpre)); + } +} + +/* + * recipients 可以是以下日志格式的组合: + * tcp:127.0.0.1:8088 + * udp:127.0.0.1:8088 + * unix:/var/log/unix.sock + * file:/var/log/unix.log + * /var/log/unix.log + * 如:tcp:127.0.0.1:8088|/var/log/unix.log + */ +int acl_open_log(const char *recipients, const char *logpre) +{ + const char *myname = "acl_open_log"; + const char *ptr; + ACL_ARGV *argv = NULL; + ACL_ITER iter; + + if (recipients == NULL || *recipients == 0) { + printf("%s(%d): recipients null\n", myname, __LINE__); + return (-1); + } else if (logpre == NULL || *logpre == 0) { + printf("%s(%d): logpre null\n", myname, __LINE__); + return (-1); + } + + if (__loggers == NULL) + __loggers = private_fifo_new(); + + argv = acl_argv_split(recipients, "|"); + acl_foreach(iter, argv) { + ptr = (const char*) iter.data; + if (open_log(ptr, logpre) < 0) { + acl_argv_free(argv); + return (-1); + } + } + acl_argv_free(argv); + return (0); +} + +void acl_logtime_fmt(char *buf, size_t size) +{ + time_t now; +#ifdef ACL_UNIX + struct tm local_time; + + (void) time (&now); + (void) localtime_r(&now, &local_time); + strftime(buf, size, "%Y/%m/%d %H:%M:%S", &local_time); +#elif defined(ACL_MS_WINDOWS) + struct tm *local_time; + + (void) time (&now); + local_time = localtime(&now); + strftime(buf, size, "%Y/%m/%d %H:%M:%S", local_time); +#else +# error "unknown OS type" +#endif +} + +#ifdef ACL_UNIX + +static char *get_buf(const char *pre, const char *fmt, va_list ap, size_t *len) +{ + va_list ap_tmp; + char *buf, *ptr; + size_t n1, n2, n; + int ret; + + n1 = strlen(pre); + + n = n1 + 1024; + buf = (char*) malloc(n); + acl_assert(buf); + + strcpy(buf, pre); + ptr = buf + n1; + n2 = n - n1; + va_copy(ap_tmp, ap); + ret = vsnprintf(ptr, n2, fmt, ap_tmp); + acl_assert(ret > 0); + + *len = n1 + ret; + + if (ret >= (int) n2) { + n = n1 + ret + 1; + buf = (char*) realloc(buf, n); + acl_assert(buf); + + ptr = buf + n1; + n2 = n - n1; + va_copy(ap_tmp, ap); + ret = vsnprintf(ptr, n2, fmt, ap_tmp); + acl_assert(ret > 0 && ret < (int) n2); + } + + return (buf); +} + +#else + +static char *get_buf(const char *pre, const char *fmt, va_list ap, size_t *len) +{ + char *buf, *ptr; + size_t n1, n2, n; + int ret, i; + + n1 = strlen(pre); + + n = n1 + 1024; + buf = (char*) malloc(n); + acl_assert(buf); + + strcpy(buf, pre); + ptr = buf + n1; + n2 = n - n1; + ret = vsnprintf(ptr, n2, fmt, ap); + if (ret > 0 && ret < (int) n2) { + *len = n1 + ret; + return (buf); + } + + i = 0; + while (1) { + n += 1024; + buf = (char*) realloc(buf, n); + acl_assert(buf); + ptr = buf + n1; + n2 = n - n1; + ret = vsnprintf(ptr, n2, fmt, ap); + if (ret > 0 && ret <= (int) n2) { + *len = n1 + ret; + break; + } + if (++i >= 10000) + acl_assert(0); + } + + return (buf); +} + +#endif + +static void file_vsyslog(ACL_LOG *log, const char *info, const char *fmt, va_list ap) +{ + char fmtstr[128], tbuf[1024], *buf; + size_t len; + + acl_logtime_fmt(fmtstr, sizeof(fmtstr)); + + if (__log_thread_id) { +#ifdef LINUX2 + snprintf(tbuf, sizeof(tbuf), "%s %s (pid=%d, tid=%llu)(%s): ", + fmtstr, log->logpre, (int) getpid(), + (unsigned long long int) pthread_self(), info); +#elif defined(SUNOS5) + snprintf(tbuf, sizeof(tbuf), "%s %s (pid=%d, tid=%d)(%s): ", + fmtstr, log->logpre, (int) getpid(), (int) pthread_self(), info); +#elif defined(ACL_MS_WINDOWS) + snprintf(tbuf, sizeof(tbuf), "%s %s (pid=%d, tid=%d)(%s): ", + fmtstr, log->logpre, (int) _getpid(), (int) acl_pthread_self(), info); +#else + snprintf(tbuf, sizeof(tbuf), "%s %s: (%s): ", + fmtstr, log->logpre, info); +#endif + } else { +#if defined(SUNOS5) + snprintf(tbuf, sizeof(tbuf), "%s %s (pid=%d)(%s): ", + fmtstr, log->logpre, (int) getpid(), info); +#elif defined(ACL_MS_WINDOWS) + snprintf(tbuf, sizeof(tbuf), "%s %s (pid=%d)(%s): ", + fmtstr, log->logpre, (int) _getpid(), info); +#else + snprintf(tbuf, sizeof(tbuf), "%s %s (pid=%d)(%s): ", + fmtstr, log->logpre, (int) getpid(), info); +#endif + } + + buf = get_buf(tbuf, fmt, ap, &len); + + if (log->lock) + thread_mutex_lock(log->lock); + + if (private_vstream_writen(log->fp, buf, len) == ACL_VSTREAM_EOF + || private_vstream_writen(log->fp, "\r\n", 2) == ACL_VSTREAM_EOF) + { + log->flag |= ACL_LOG_F_DEAD; + } else + log->count++; + + if (log->lock) + thread_mutex_unlock(log->lock); + + free(buf); +} + +static void net_vsyslog(ACL_LOG *log, const char *info, const char *fmt, va_list ap) +{ + char tbuf[1024], *buf; + size_t len; + + if (__log_thread_id) { +#ifdef LINUX2 + snprintf(tbuf, sizeof(tbuf), " %s (pid=%d, tid=%llu)(%s): ", + log->logpre, (int) getpid(), + (unsigned long long int) pthread_self(), info); +#elif defined(SUNOS5) + snprintf(tbuf, sizeof(tbuf), " %s (pid=%d, tid=%d)(%s): ", + log->logpre, (int) getpid(), (int) pthread_self(), info); +#elif defined(ACL_MS_WINDOWS) + snprintf(tbuf, sizeof(tbuf), " %s (pid=%d, tid=%d)(%s): ", + log->logpre, (int) _getpid(), (int) acl_pthread_self(), info); +#else + snprintf(tbuf, sizeof(tbuf), " %s: (%s): ", log->logpre, info); +#endif + } else { +#if defined(SUNOS5) + snprintf(tbuf, sizeof(tbuf), " %s (pid=%d)(%s): ", + log->logpre, (int) getpid(), info); +#elif defined(ACL_MS_WINDOWS) + snprintf(tbuf, sizeof(tbuf), " %s (pid=%d)(%s): ", + log->logpre, (int) _getpid(), info); +#else + snprintf(tbuf, sizeof(tbuf), " %s (pid=%d)(%s): ", + log->logpre, (int) getpid(), info); +#endif + } + + buf = get_buf(tbuf, fmt, ap, &len); + + if (log->lock) + thread_mutex_lock(log->lock); + + if (log->type == ACL_LOG_T_UDP) { + (void) private_vstream_write(log->fp, buf, len); + log->count++; + } else if (private_vstream_buffed_writen(log->fp, buf, len) == ACL_VSTREAM_EOF + || private_vstream_writen(log->fp, "\r\n", 2) == ACL_VSTREAM_EOF) + { + log->flag |= ACL_LOG_F_DEAD; + } else + log->count++; + + if (log->lock) + thread_mutex_unlock(log->lock); + + free(buf); +} + +int acl_write_to_log2(const char *info, const char *fmt, va_list ap) +{ + ACL_ITER iter; + ACL_LOG *log; +#ifdef ACL_UNIX + va_list tmp; +#endif + + if (__loggers == NULL) + return (0); + +#ifdef ACL_UNIX + acl_foreach(iter, __loggers) { + log = (ACL_LOG*) iter.data; + if ((log->flag & ACL_LOG_F_DEAD)) { + if (reopen_log(log) < 0) + continue; + } + va_copy(tmp, ap); + if (log->type == ACL_LOG_T_FILE) + file_vsyslog(log, info, fmt, tmp); + else if (log->type == ACL_LOG_T_TCP + || log->type == ACL_LOG_T_UDP + || log->type == ACL_LOG_T_UNIX) + { + net_vsyslog(log, info, fmt, tmp); + } + } +#else + acl_foreach(iter, __loggers) { + log = (ACL_LOG*) iter.data; + if ((log->flag & ACL_LOG_F_DEAD)) { + if (reopen_log(log) < 0) + continue; + } + if (log->type == ACL_LOG_T_FILE) + file_vsyslog(log, info, fmt, ap); + else if (log->type == ACL_LOG_T_TCP + || log->type == ACL_LOG_T_UDP + || log->type == ACL_LOG_T_UNIX) + { + net_vsyslog(log, info, fmt, ap); + } + } +#endif + + return (0); +} + +int acl_write_to_log(const char *fmt, ...) +{ + va_list ap; + int ret; + + va_start (ap, fmt); + ret = acl_write_to_log2("-", fmt, ap); + va_end(ap); + return (ret); +} + +void acl_close_log() +{ + ACL_LOG *log; + + if (__loggers == NULL) + return; + + while (1) { + log = (ACL_LOG*) private_fifo_pop(__loggers); + if (log == NULL) + break; + + if ((log->flag & ACL_LOG_F_FIXED)) + continue; + + if (log->fp) + private_vstream_close(log->fp); + if (log->path) + free(log->path); + if (log->lock) + thread_mutex_destroy(log->lock); + free(log); + } + + free(__loggers); + __loggers = NULL; +} diff --git a/lib_acl/src/stdlib/acl_readline.c b/lib_acl/src/stdlib/acl_readline.c new file mode 100644 index 000000000..81a3b5ef3 --- /dev/null +++ b/lib_acl/src/stdlib/acl_readline.c @@ -0,0 +1,73 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include "stdlib/acl_msg.h" +#include "stdlib/acl_vstream.h" +#include "stdlib/acl_vstring.h" +#include "stdlib/acl_readline.h" + +#endif + +#define STR(x) acl_vstring_str(x) +#define LEN(x) ACL_VSTRING_LEN(x) +#define END(x) acl_vstring_end(x) + +/* readlline - read one logical line */ + +ACL_VSTRING *acl_readlline(ACL_VSTRING *buf, ACL_VSTREAM *fp, int *lineno) +{ + char *cp; + size_t start; + int ch, next; + + ACL_VSTRING_RESET(buf); + + /* + * Ignore comment lines, all whitespace lines, and empty lines. Terminate + * at EOF or at the beginning of the next logical line. + */ + for (;;) { + /* Read one line, possibly not newline terminated. */ + start = LEN(buf); + while ((ch = acl_vstream_getc(fp)) != ACL_VSTREAM_EOF && ch != '\n') + ACL_VSTRING_ADDCH(buf, ch); + if (ch == '\n' && lineno != 0) + *lineno += 1; + /* Ignore comment line, all whitespace line, or empty line. */ + for (cp = STR(buf) + start; cp < END(buf) && ACL_ISSPACE(*cp); cp++) + /* void */ ; + if (cp == END(buf) || *cp == '#') + acl_vstring_truncate(buf, start); + /* Terminate at EOF or at the beginning of the next logical line. */ + if (ch == ACL_VSTREAM_EOF) + break; + if (LEN(buf) > 0) { + if ((next = acl_vstream_getc(fp)) != ACL_VSTREAM_EOF) + acl_vstream_ungetc(fp, next); + if (next != '#' && !ACL_ISSPACE(next)) + break; + } + } + ACL_VSTRING_TERMINATE(buf); + + /* + * Invalid input: continuing text without preceding text. Allowing this + * would complicate "postconf -e", which implements its own multi-line + * parsing routine. Do not abort, just warn, so that critical programs + * like postmap do not leave behind a truncated table. + */ + if (LEN(buf) > 0 && ACL_ISSPACE(*STR(buf))) { + acl_msg_warn("%s: logical line must not start with whitespace: \"%.30s%s\"", + ACL_VSTREAM_PATH(fp), STR(buf), LEN(buf) > 30 ? "..." : ""); + return (acl_readlline(buf, fp, lineno)); + } + + /* + * Done. + */ + return (LEN(buf) > 0 ? buf : NULL); +} + diff --git a/lib_acl/src/stdlib/acl_vbuf.c b/lib_acl/src/stdlib/acl_vbuf.c new file mode 100644 index 000000000..595169267 --- /dev/null +++ b/lib_acl/src/stdlib/acl_vbuf.c @@ -0,0 +1,98 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +/* System library. */ + +#include "stdlib/acl_define.h" + +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +/* Utility library. */ + +#include "stdlib/acl_vbuf.h" + +#endif + +/* vbuf_unget - implement at least one character pushback */ + +int acl_vbuf_unget(ACL_VBUF *bp, int ch) +{ + if ((ch & 0xff) != ch || -bp->cnt >= bp->len) { + bp->flags |= ACL_VBUF_FLAG_ERR; + return (ACL_VBUF_EOF); + } else { + bp->cnt--; + bp->flags &= ~ACL_VBUF_FLAG_EOF; + return ((*--bp->ptr = ch)); + } +} + +/* vbuf_get - handle read buffer empty condition */ + +int acl_vbuf_get(ACL_VBUF *bp) +{ + return (bp->get_ready(bp) ? ACL_VBUF_EOF : ACL_VBUF_GET(bp)); +} + +/* vbuf_put - handle write buffer full condition */ + +int acl_vbuf_put(ACL_VBUF *bp, int ch) +{ + return (bp->put_ready(bp) ? ACL_VBUF_EOF : ACL_VBUF_PUT(bp, ch)); +} + +/* vbuf_read - bulk read from buffer */ + +int acl_vbuf_read(ACL_VBUF *bp, char *buf, int len) +{ + int count; + char *cp; + int n; + +#if 0 + for (count = 0; count < len; count++) + if ((buf[count] = ACL_VBUF_GET(bp)) < 0) + break; + return (count); +#else + for (cp = buf, count = len; count > 0; cp += n, count -= n) { + if (bp->cnt >= 0 && bp->get_ready(bp)) + break; + n = (count < -bp->cnt ? count : -bp->cnt); + memcpy(cp, bp->ptr, n); + bp->ptr += n; + bp->cnt += n; + } + return (len - count); +#endif +} + +/* vbuf_write - bulk write to buffer */ + +int acl_vbuf_write(ACL_VBUF *bp, const char *buf, int len) +{ + int count; + const char *cp; + int n; + +#if 0 + for (count = 0; count < len; count++) + if (ACL_VBUF_PUT(bp, buf[count]) < 0) + break; + return (count); +#else + for (cp = buf, count = len; count > 0; cp += n, count -= n) { + if (bp->cnt <= 0 && bp->put_ready(bp) != 0) + break; + n = (count < bp->cnt ? count : bp->cnt); + memcpy(bp->ptr, cp, n); + bp->ptr += n; + bp->cnt -= n; + } + return (len - count); +#endif +} diff --git a/lib_acl/src/stdlib/acl_vbuf_print.c b/lib_acl/src/stdlib/acl_vbuf_print.c new file mode 100644 index 000000000..00d4aa495 --- /dev/null +++ b/lib_acl/src/stdlib/acl_vbuf_print.c @@ -0,0 +1,272 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +/* System library. */ + +#include "stdlib/acl_define.h" + +#include /* 44BSD stdarg.h uses abort() */ +#include +#include +#include +#include /* 44bsd stdarg.h uses abort() */ +#include /* sprintf() prototype */ +#include /* range of doubles */ +#include /* CHAR_BIT */ + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +/* Application-specific. */ + +#include "stdlib/acl_msg.h" +#include "stdlib/acl_vbuf.h" +#include "stdlib/acl_vstring.h" +#include "stdlib/acl_vsprintf.h" +#include "stdlib/acl_vbuf_print.h" + +#endif + + /* + * What we need here is a *sprintf() routine that can ask for more room (as + * in 4.4 BSD). However, that functionality is not widely available, and I + * have no plans to maintain a complete 4.4 BSD *sprintf() alternative. + * + * This means we're stuck with plain old ugly sprintf() for all non-trivial + * conversions. We cannot use snprintf() even if it is available, because + * that routine truncates output, and we want everything. Therefore, it is + * up to us to ensure that sprintf() output always stays within bounds. + * + * Due to the complexity of *printf() format strings we cannot easily predict + * how long results will be without actually doing the conversions. A trick + * used by some people is to print to a temporary file and to read the + * result back. In programs that do a lot of formatting, that might be too + * expensive. + * + * Guessing the output size of a string (%s) conversion is not hard. The + * problem is with numerical results. Instead of making an accurate guess we + * take a wide margin when reserving space. The INT_SPACE margin should be + * large enough to hold the result from any (octal, hex, decimal) integer + * conversion that has no explicit width or precision specifiers. With + * floating-point numbers, use a similar estimate, and add DBL_MAX_10_EXP + * just to be sure. + */ + +#define INT_SPACE ((CHAR_BIT * sizeof(acl_int64)) / 2) +#define SIZE_T_SPACE ((CHAR_BIT * sizeof(size_t)) / 2) +#define DBL_SPACE ((CHAR_BIT * sizeof(double)) / 2 + DBL_MAX_10_EXP) +#define PTR_SPACE ((CHAR_BIT * sizeof(char *)) / 2) + + /* + * Helper macros... Note that there is no need to check the result from + * VSTRING_SPACE() because that always succeeds or never returns. + */ +#define VBUF_SKIP(bp) { \ + while ((bp)->cnt > 0 && *(bp)->ptr) \ + (bp)->ptr++, (bp)->cnt--; \ + } + +#define VBUF_STRCAT(bp, s) { \ + const unsigned char *_cp = (const unsigned char *) (s); \ + int _ch; \ + while ((_ch = *_cp++) != 0) \ + ACL_VBUF_PUT((bp), _ch); \ + } + +/* vbuf_print - format string, vsprintf-like interface */ + +ACL_VBUF *acl_vbuf_print(ACL_VBUF *bp, const char *format, va_list ap) +{ + const unsigned char *cp; + unsigned width; /* field width */ + unsigned prec; /* numerical precision */ + unsigned long_flag; /* long or plain integer */ + int ch; + char *s; +#define MAX_LEN 128 + char fmt[MAX_LEN + 1]; /* format specifier */ + int i; + +#define CHECK_OVERFLOW(_i, _max) do { \ + if (_i >= _max) \ + acl_msg_fatal("fmt overflow: i: %d MAX: %d", (_i), (_max)); \ +} while (0) + + /* + * Iterate over characters in the format string, picking up arguments + * when format specifiers are found. + */ + for (cp = (const unsigned char *) format; *cp; cp++) { + if (*cp != '%') { + ACL_VBUF_PUT(bp, *cp); /* ordinary character */ + continue; + } else if (cp[1] == '%') { + ACL_VBUF_PUT(bp, *cp++); /* %% becomes % */ + continue; + } + + /* + * Handle format specifiers one at a time, since we can only + * deal with arguments one at a time. Try to determine the end + * of the format specifier. We do not attempt to fully parse + * format strings, since we are ging to let sprintf() do the + * hard work. + * In regular expression notation, we recognize: + * + * %-?0?([0-9]+|\*)?\.?([0-9]+|\*)?l?[a-zA-Z] + * + * which includes some combinations that do not make sense. + * Garbage in, garbage out. + */ + i = 0; /* clear format string */ + fmt[i++] = *cp++; + if (*cp == '-') /* left-adjusted field? */ + fmt[i++] = *cp++; + if (*cp == '+') /* signed field? */ + fmt[i++] = *cp++; + if (*cp == '0') /* zero-padded field? */ + fmt[i++] = *cp++; + if (*cp == '*') { /* dynamic field width */ + width = va_arg(ap, int); + sprintf(fmt + i, "%d", width); + i = strlen(fmt); /* reset i to string length */ + cp++; + } else { /* hard-coded field width */ + for (width = 0; ACL_ISDIGIT(ch = *cp); cp++) { + width = width * 10 + ch - '0'; + fmt[i++] = ch; + CHECK_OVERFLOW(i, MAX_LEN); + } + } + if (*cp == '.') /* width/precision separator */ + fmt[i++] = *cp++; + if (*cp == '*') { /* dynamic precision */ + prec = va_arg(ap, int); + sprintf(fmt + i, "%d", prec); + i = strlen(fmt); /* reset i to string length */ + cp++; + } else { /* hard-coded precision */ + for (prec = 0; ACL_ISDIGIT(ch = *cp); cp++) { + prec = prec * 10 + ch - '0'; + fmt[i++] = ch; + CHECK_OVERFLOW(i, MAX_LEN); + } + } +#ifdef ACL_MS_WINDOWS + if (*cp == 'l') { + if (*(cp + 1) == 'l') { + fmt[i++] = 'I'; + fmt[i++] = '6'; + fmt[i++] = '4'; + cp += 2; + long_flag = 2; + } else { + fmt[i++] = *cp++; + long_flag = 1; + } + } else if (*cp == 'z') { + fmt[i++] = 'I'; + cp++; + long_flag = 1; + } else + long_flag = 0; +#else + if (*cp == 'l') { /* long whatever */ + if (*(cp + 1) == 'l') { + fmt[i++] = *cp++; + fmt[i++] = *cp++; + long_flag = 2; + } else { + fmt[i++] = *cp++; + long_flag = 1; + fmt[i] = 0; + } + } else if (*cp == 'z') { + fmt[i++] = *cp++; + long_flag = 1; + } else + long_flag = 0; +#endif + if (*cp == 0) /* premature end, punt */ + break; + fmt[i++] = *cp; /* type (checked below) */ + fmt[i] = 0; /* null terminate */ + + /* + * Execute the format string - let sprintf() do the hard work + * for non-trivial cases only. For simple string conversions + * and for long string conversions, do a direct copy to the + * output buffer. + */ + switch (*cp) { + case 's': /* string-valued argument */ + s = va_arg(ap, char *); + if (prec > 0 || (width > 0 && width > strlen(s))) { + if (ACL_VBUF_SPACE(bp, (width > prec + ? width : prec) + INT_SPACE)) + { + return bp; + } + sprintf((char *) bp->ptr, fmt, s); + VBUF_SKIP(bp); + } else { + VBUF_STRCAT(bp, s); + } + break; + case 'c': /* integral-valued argument */ + case 'd': + case 'u': + case 'o': + case 'x': + case 'X': + if (ACL_VBUF_SPACE(bp, (width > prec + ? width : prec) + INT_SPACE)) + { + return bp; + } + if (long_flag == 0) + sprintf((char *) bp->ptr, fmt, va_arg(ap, int)); + else if (long_flag == 1) + sprintf((char *) bp->ptr, fmt, va_arg(ap, long)); + else if (long_flag == 2) + sprintf((char *) bp->ptr, fmt, va_arg(ap, acl_int64)); + else + acl_msg_panic("%s: unknown format type: %c," + " long_flag: %d", __FUNCTION__, + *cp, long_flag); + VBUF_SKIP(bp); + break; + case 'e': /* float-valued argument */ + case 'f': + case 'g': + if (ACL_VBUF_SPACE(bp, (width > prec + ? width : prec) + DBL_SPACE)) + { + return bp; + } + sprintf((char *) bp->ptr, fmt, va_arg(ap, double)); + VBUF_SKIP(bp); + break; + case 'm': + VBUF_STRCAT(bp, acl_last_serror()); + break; + case 'p': + if (ACL_VBUF_SPACE(bp, (width > prec + ? width : prec) + PTR_SPACE)) + { + return bp; + } + sprintf((char *) bp->ptr, fmt, va_arg(ap, char *)); + VBUF_SKIP(bp); + break; + default: /* anything else is bad */ + acl_msg_panic("%s: unknown format type: %c", + __FUNCTION__, *cp); + /* NOTREACHED */ + break; + } + } + + return bp; +} diff --git a/lib_acl/src/stdlib/acl_vbuf_print.c.old b/lib_acl/src/stdlib/acl_vbuf_print.c.old new file mode 100644 index 000000000..e980fc97e --- /dev/null +++ b/lib_acl/src/stdlib/acl_vbuf_print.c.old @@ -0,0 +1,264 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +/* System library. */ + +#include "stdlib/acl_define.h" + +#include /* 44BSD stdarg.h uses abort() */ +#include +#include +#include +#include /* 44bsd stdarg.h uses abort() */ +#include /* sprintf() prototype */ +#include /* range of doubles */ +#include /* CHAR_BIT */ + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +/* Application-specific. */ + +#include "stdlib/acl_msg.h" +#include "stdlib/acl_vbuf.h" +#include "stdlib/acl_vstring.h" +#include "stdlib/acl_vsprintf.h" +#include "stdlib/acl_vbuf_print.h" + +#endif + + /* + * What we need here is a *sprintf() routine that can ask for more room (as + * in 4.4 BSD). However, that functionality is not widely available, and I + * have no plans to maintain a complete 4.4 BSD *sprintf() alternative. + * + * This means we're stuck with plain old ugly sprintf() for all non-trivial + * conversions. We cannot use snprintf() even if it is available, because + * that routine truncates output, and we want everything. Therefore, it is + * up to us to ensure that sprintf() output always stays within bounds. + * + * Due to the complexity of *printf() format strings we cannot easily predict + * how long results will be without actually doing the conversions. A trick + * used by some people is to print to a temporary file and to read the + * result back. In programs that do a lot of formatting, that might be too + * expensive. + * + * Guessing the output size of a string (%s) conversion is not hard. The + * problem is with numerical results. Instead of making an accurate guess we + * take a wide margin when reserving space. The INT_SPACE margin should be + * large enough to hold the result from any (octal, hex, decimal) integer + * conversion that has no explicit width or precision specifiers. With + * floating-point numbers, use a similar estimate, and add DBL_MAX_10_EXP + * just to be sure. + */ +#define INT_SPACE ((CHAR_BIT * sizeof(acl_int64)) / 2) +#define SIZE_T_SPACE ((CHAR_BIT * sizeof(size_t)) / 2) +#define DBL_SPACE ((CHAR_BIT * sizeof(double)) / 2 + DBL_MAX_10_EXP) +#define PTR_SPACE ((CHAR_BIT * sizeof(char *)) / 2) + + /* + * Helper macros... Note that there is no need to check the result from + * VSTRING_SPACE() because that always succeeds or never returns. + */ +#define VBUF_SKIP(bp) { \ + while ((bp)->cnt > 0 && *(bp)->ptr) \ + (bp)->ptr++, (bp)->cnt--; \ + } + +#define ACL_VSTRING_ADDNUM(vp, n) { \ + ACL_VSTRING_SPACE(vp, INT_SPACE); \ + snprintf(acl_vstring_end(vp), ACL_VSTRING_SIZE(vp), "%d", n); \ + VBUF_SKIP(&vp->vbuf); \ + } + +#define ACL_VBUF_STRCAT(bp, s) { \ + const unsigned char *_cp = (const unsigned char *) (s); \ + int _ch; \ + while ((_ch = *_cp++) != 0) \ + ACL_VBUF_PUT((bp), _ch); \ + } + +/* vbuf_print - format string, vsprintf-like interface */ + +ACL_VBUF *acl_vbuf_print(ACL_VBUF *bp, const char *format, va_list ap) +{ +#if 0 + static ACL_VSTRING *fmt; /* format specifier */ +#endif + ACL_VSTRING *fmt = NULL; /* format specifier */ + const unsigned char *cp; + unsigned width; /* field width */ + unsigned prec; /* numerical precision */ + unsigned long_flag; /* long or plain integer */ + int ch; + char *s; + +#undef RETURN +#define RETURN(x) { \ + if (fmt) \ + acl_vstring_free(fmt); \ + return (x); \ +} + + /* + * Assume that format strings are short. + * if (fmt == 0) + */ + + fmt = acl_vstring_alloc(INT_SPACE); + + /* + * Iterate over characters in the format string, picking up arguments + * when format specifiers are found. + */ + for (cp = (const unsigned char *) format; *cp; cp++) { + if (*cp != '%') { + ACL_VBUF_PUT(bp, *cp); /* ordinary character */ + } else if (cp[1] == '%') { + ACL_VBUF_PUT(bp, *cp++); /* %% becomes % */ + } else { + char ebuf[256]; + + /* + * Handle format specifiers one at a time, since we can only deal + * with arguments one at a time. Try to determine the end of the + * format specifier. We do not attempt to fully parse format + * strings, since we are ging to let sprintf() do the hard work. + * In regular expression notation, we recognize: + * + * %-?0?([0-9]+|\*)?\.?([0-9]+|\*)?l?[a-zA-Z] + * + * which includes some combinations that do not make sense. Garbage + * in, garbage out. + */ + ACL_VSTRING_RESET(fmt); /* clear format string */ + ACL_VSTRING_ADDCH(fmt, *cp++); + if (*cp == '-') /* left-adjusted field? */ + ACL_VSTRING_ADDCH(fmt, *cp++); + if (*cp == '+') /* signed field? */ + ACL_VSTRING_ADDCH(fmt, *cp++); + if (*cp == '0') /* zero-padded field? */ + ACL_VSTRING_ADDCH(fmt, *cp++); + if (*cp == '*') { /* dynamic field width */ + width = va_arg(ap, int); + ACL_VSTRING_ADDNUM(fmt, width); + cp++; + } else { /* hard-coded field width */ + for (width = 0; ACL_ISDIGIT(ch = *cp); cp++) { + width = width * 10 + ch - '0'; + ACL_VSTRING_ADDCH(fmt, ch); + } + } + if (*cp == '.') /* width/precision separator */ + ACL_VSTRING_ADDCH(fmt, *cp++); + if (*cp == '*') { /* dynamic precision */ + prec = va_arg(ap, int); + ACL_VSTRING_ADDNUM(fmt, prec); + cp++; + } else { /* hard-coded precision */ + for (prec = 0; ACL_ISDIGIT(ch = *cp); cp++) { + prec = prec * 10 + ch - '0'; + ACL_VSTRING_ADDCH(fmt, ch); + } + } +#ifdef ACL_MS_WINDOWS + if (*cp == 'l') { + if (*(cp + 1) == 'l') { + acl_vstring_strcat(fmt, "I64"); + cp += 2; + long_flag = 2; + } else { + ACL_VSTRING_ADDCH(fmt, *cp++); + long_flag = 1; + } + } else if (*cp == 'z') { + ACL_VSTRING_ADDCH(fmt, 'I'); + cp++; + long_flag = 1; + } else + long_flag = 0; +#else + if (*cp == 'l') { /* long whatever */ + if (*(cp + 1) == 'l') { + ACL_VSTRING_ADDCH(fmt, *cp++); + ACL_VSTRING_ADDCH(fmt, *cp++); + long_flag = 2; + } else { + ACL_VSTRING_ADDCH(fmt, *cp++); + long_flag = 1; + } + } else if (*cp == 'z') { + ACL_VSTRING_ADDCH(fmt, *cp++); + long_flag = 1; + } else + long_flag = 0; +#endif + if (*cp == 0) /* premature end, punt */ + break; + ACL_VSTRING_ADDCH(fmt, *cp); /* type (checked below) */ + ACL_VSTRING_TERMINATE(fmt); /* null terminate */ + + /* + * Execute the format string - let sprintf() do the hard work for + * non-trivial cases only. For simple string conversions and for + * long string conversions, do a direct copy to the output + * buffer. + */ + switch (*cp) { + case 's': /* string-valued argument */ + s = va_arg(ap, char *); + if (prec > 0 || (width > 0 && width > strlen(s))) { + if (ACL_VBUF_SPACE(bp, (width > prec ? width : prec) + INT_SPACE)) + RETURN (bp); + sprintf((char *) bp->ptr, acl_vstring_str(fmt), s); + VBUF_SKIP(bp); + } else { + ACL_VBUF_STRCAT(bp, s); + } + break; + case 'c': /* integral-valued argument */ + case 'd': + case 'u': + case 'o': + case 'x': + case 'X': + if (ACL_VBUF_SPACE(bp, (width > prec ? width : prec) + INT_SPACE)) + RETURN (bp); + if (long_flag == 0) + sprintf((char *) bp->ptr, acl_vstring_str(fmt), va_arg(ap, int)); + else if (long_flag == 1) + sprintf((char *) bp->ptr, acl_vstring_str(fmt), va_arg(ap, long)); + else if (long_flag == 2) + sprintf((char *) bp->ptr, acl_vstring_str(fmt), va_arg(ap, acl_int64)); + else + acl_msg_panic("vbuf_print: unknown format type: %c, long_flag: %d", *cp, long_flag); + VBUF_SKIP(bp); + break; + case 'e': /* float-valued argument */ + case 'f': + case 'g': + if (ACL_VBUF_SPACE(bp, (width > prec ? width : prec) + DBL_SPACE)) + RETURN (bp); + sprintf((char *) bp->ptr, acl_vstring_str(fmt), va_arg(ap, double)); + VBUF_SKIP(bp); + break; + case 'm': + ACL_VBUF_STRCAT(bp, acl_last_strerror(ebuf, sizeof(ebuf))); + break; + case 'p': + if (ACL_VBUF_SPACE(bp, (width > prec ? width : prec) + PTR_SPACE)) + RETURN (bp); + sprintf((char *) bp->ptr, acl_vstring_str(fmt), va_arg(ap, char *)); + VBUF_SKIP(bp); + break; + default: /* anything else is bad */ + acl_msg_panic("vbuf_print: unknown format type: %c", *cp); + /* NOTREACHED */ + break; + } + } + } + RETURN (bp); +} + diff --git a/lib_acl/src/stdlib/acl_vsprintf.c b/lib_acl/src/stdlib/acl_vsprintf.c new file mode 100644 index 000000000..33cf74d85 --- /dev/null +++ b/lib_acl/src/stdlib/acl_vsprintf.c @@ -0,0 +1,416 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_mystring.h" +#include "stdlib/acl_vsprintf.h" + +#endif + +#define ZEROPAD 1 /* pad with zero */ +#define SIGN 2 /* unsigned/signed long */ +#define PLUS 4 /* show plus */ +#define SPACE 8 /* space if plus */ +#define LEFT 16 /* left justified */ +#define SPECIAL 32 /* 0x */ +#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */ + +static char * number(char * buf, char * end, long int num, int base, int size, int precision, int type) +{ + char c,sign,tmp[66]; + const char *digits; + const char small_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz"; + const char large_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + int i; + + digits = (type & LARGE) ? large_digits : small_digits; + if (type & LEFT) + type &= ~ZEROPAD; + if (base < 2 || base > 36) + return 0; + c = (type & ZEROPAD) ? '0' : ' '; + sign = 0; + if (type & SIGN) { + if (num < 0) { + sign = '-'; + num = -num; + size--; + } else if (type & PLUS) { + sign = '+'; + size--; + } else if (type & SPACE) { + sign = ' '; + size--; + } + } + if (type & SPECIAL) { + if (base == 16) + size -= 2; + else if (base == 8) + size--; + } + i = 0; + if (num == 0) + tmp[i++]='0'; + else { + while (num != 0) { + long int __res; + __res = ((unsigned long int) num) % (unsigned) base; + num = ((unsigned long int) num) / (unsigned) base; + tmp[i++] = digits[__res]; + } + } + if (i > precision) + precision = i; + size -= precision; + if (!(type&(ZEROPAD+LEFT))) { + while(size-->0) { + if (buf <= end) + *buf = ' '; + ++buf; + } + } + if (sign) { + if (buf <= end) + *buf = sign; + ++buf; + } + if (type & SPECIAL) { + if (base==8) { + if (buf <= end) + *buf = '0'; + ++buf; + } else if (base==16) { + if (buf <= end) + *buf = '0'; + ++buf; + if (buf <= end) + *buf = digits[33]; + ++buf; + } + } + if (!(type & LEFT)) { + while (size-- > 0) { + if (buf <= end) + *buf = c; + ++buf; + } + } + while (i < precision--) { + if (buf <= end) + *buf = '0'; + ++buf; + } + while (i-- > 0) { + if (buf <= end) + *buf = tmp[i]; + ++buf; + } + while (size-- > 0) { + if (buf <= end) + *buf = ' '; + ++buf; + } + return buf; +} + +static int skip_atoi(const char **s) +{ + int i=0; + + while (isdigit(**s)) + i = i*10 + *((*s)++) - '0'; + return i; +} + +/** +* vsnprintf - Format a string and place it in a buffer +* @buf: The buffer to place the result into +* @size: The size of the buffer, including the trailing null space +* @fmt: The format string to use +* @args: Arguments for the format string +* +* Call this function if you are already dealing with a va_list. +* You probably want snprintf instead. + */ +int acl_vsnprintf(char *buf, size_t size, const char *fmt, va_list args) +{ + int len; + long int num; + int i, base; + char *str, *end, c; + const char *s; + + int flags; /* flags to number() */ + + int field_width; /* width of output field */ + int precision; /* min. # of digits for integers; max + number of chars for from string */ + int qualifier; /* 'h', 'l', or 'L' for integer fields */ + /* 'z' support added 23/7/1999 S.H. */ + /* 'z' changed to 'Z' --davidm 1/25/99 */ + + str = buf; + end = buf + size - 1; + + if (end < buf - 1) { + end = ((void *) -1); + size = end - buf + 1; + } + + for (; *fmt ; ++fmt) { + if (*fmt != '%') { + if (str <= end) + *str = *fmt; + ++str; + continue; + } + + /* process flags */ + flags = 0; + repeat: + ++fmt; /* this also skips first '%' */ + switch (*fmt) { + case '-': flags |= LEFT; goto repeat; + case '+': flags |= PLUS; goto repeat; + case ' ': flags |= SPACE; goto repeat; + case '#': flags |= SPECIAL; goto repeat; + case '0': flags |= ZEROPAD; goto repeat; + } + + /* get field width */ + field_width = -1; + if (isdigit(*fmt)) + field_width = skip_atoi(&fmt); + else if (*fmt == '*') { + ++fmt; + /* it's the next argument */ + field_width = va_arg(args, int); + if (field_width < 0) { + field_width = -field_width; + flags |= LEFT; + } + } + + /* get the precision */ + precision = -1; + if (*fmt == '.') { + ++fmt; + if (isdigit(*fmt)) + precision = skip_atoi(&fmt); + else if (*fmt == '*') { + ++fmt; + /* it's the next argument */ + precision = va_arg(args, int); + } + if (precision < 0) + precision = 0; + } + + /* get the conversion qualifier */ + qualifier = -1; + if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || *fmt =='Z') { + qualifier = *fmt; + ++fmt; + } + + /* default base */ + base = 10; + + switch (*fmt) { + case 'c': + if (!(flags & LEFT)) { + while (--field_width > 0) { + if (str <= end) + *str = ' '; + ++str; + } + } + c = (unsigned char) va_arg(args, int); + if (str <= end) + *str = c; + ++str; + while (--field_width > 0) { + if (str <= end) + *str = ' '; + ++str; + } + continue; + + case 's': + s = va_arg(args, char *); + if (!s) + s = ""; + + len = acl_strnlen(s, precision); + + if (!(flags & LEFT)) { + while (len < field_width--) { + if (str <= end) + *str = ' '; + ++str; + } + } + for (i = 0; i < len; ++i) { + if (str <= end) + *str = *s; + ++str; ++s; + } + while (len < field_width--) { + if (str <= end) + *str = ' '; + ++str; + } + continue; + + case 'p': + if (field_width == -1) { + field_width = 2*sizeof(void *); + flags |= ZEROPAD; + } + str = number(str, end, + (unsigned long) va_arg(args, void *), + 16, field_width, precision, flags); + continue; + + + case 'n': + /* FIXME: + * What does C99 say about the overflow case here? */ + if (qualifier == 'l') { + long * ip = va_arg(args, long *); + *ip = (str - buf); + } else if (qualifier == 'Z') { + size_t * ip = va_arg(args, size_t *); + *ip = (str - buf); + } else { + int * ip = va_arg(args, int *); + *ip = (str - buf); + } + continue; + + case '%': + if (str <= end) + *str = '%'; + ++str; + continue; + + /* integer number formats - set up the flags and "break" */ + case 'o': + base = 8; + break; + + case 'X': + flags |= LARGE; + case 'x': + base = 16; + break; + + case 'd': + case 'i': + flags |= SIGN; + case 'u': + break; + + default: + if (str <= end) + *str = '%'; + ++str; + if (*fmt) { + if (str <= end) + *str = *fmt; + ++str; + } else { + --fmt; + } + continue; + } + if (qualifier == 'L') + num = va_arg(args, long int); + else if (qualifier == 'l') { + num = va_arg(args, unsigned long); + if (flags & SIGN) + num = (signed long) num; + } else if (qualifier == 'Z') { + num = va_arg(args, size_t); + } else if (qualifier == 'h') { + num = (unsigned short) va_arg(args, int); + if (flags & SIGN) + num = (signed short) num; + } else { + num = va_arg(args, unsigned int); + if (flags & SIGN) + num = (signed int) num; + } + str = number(str, end, num, base, + field_width, precision, flags); + } + if (str <= end) + *str = '\0'; + else if (size > 0) + /* don't write out a null byte if the buf size is zero */ + *end = '\0'; + /* the trailing null byte doesn't count towards the total + * ++str; + */ + return str-buf; +} + +/** + * snprintf - Format a string and place it in a buffer + * @buf: The buffer to place the result into + * @size: The size of the buffer, including the trailing null space + * @fmt: The format string to use + * @...: Arguments for the format string + */ +int acl_snprintf(char * buf, size_t size, const char *fmt, ...) +{ + va_list args; + int i; + + va_start(args, fmt); + i=acl_vsnprintf(buf,size,fmt,args); + va_end(args); + return i; +} + +/** + * vsprintf - Format a string and place it in a buffer + * @buf: The buffer to place the result into + * @fmt: The format string to use + * @args: Arguments for the format string + * + * Call this function if you are already dealing with a va_list. + * You probably want sprintf instead. + */ +int acl_vsprintf(char *buf, const char *fmt, va_list args) +{ + return acl_vsnprintf(buf, 0xFFFFFFFFUL, fmt, args); +} + + +/** + * sprintf - Format a string and place it in a buffer + * @buf: The buffer to place the result into + * @fmt: The format string to use + * @...: Arguments for the format string + */ +int acl_sprintf(char * buf, const char *fmt, ...) +{ + va_list args; + int i; + + va_start(args, fmt); + i=acl_vsprintf(buf,fmt,args); + va_end(args); + return i; +} + diff --git a/lib_acl/src/stdlib/acl_vstream.c b/lib_acl/src/stdlib/acl_vstream.c new file mode 100644 index 000000000..379b6da89 --- /dev/null +++ b/lib_acl/src/stdlib/acl_vstream.c @@ -0,0 +1,2577 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#include +#include +#include +#include +#include +#include +#include /* for S_IREAD */ + +#ifdef ACL_MS_WINDOWS +# include +#elif defined(ACL_UNIX) +# include +# include +# include +#else +# error "unknown OS type" +#endif + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_sys_patch.h" +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_msg.h" +#include "stdlib/acl_mystring.h" +#include "stdlib/acl_array.h" +#include "stdlib/acl_iostuff.h" +#include "stdlib/acl_vstream.h" + +#endif + +#include "../event/events_fdtable.h" + + /* + * Initialization of the three pre-defined streams. Pre-allocate a static + * I/O buffer for the standard error stream, so that the error handler can + * produce a diagnostic even when memory allocation fails. + */ + +static unsigned char __vstream_stdin_buf[ACL_VSTREAM_BUFSIZE]; +static unsigned char __vstream_stdout_buf[ACL_VSTREAM_BUFSIZE]; +static unsigned char __vstream_stderr_buf[ACL_VSTREAM_BUFSIZE]; + +static int __sys_getc(ACL_VSTREAM *stream); + +ACL_VSTREAM acl_vstream_fstd[] = { + { +#ifdef ACL_UNIX + { STDIN_FILENO }, /* h_file */ +#elif defined(ACL_MS_WINDOWS) + -1, /* h_file */ +#endif + 0, /* is_nonblock */ + ACL_VSTREAM_TYPE_FILE, /* type */ + 0, /* offset */ + 0, /* sys_offset */ + 0, /* wbuf */ + 0, /* wbuf_size */ + 0, /* wbuf_dlen */ + __vstream_stdin_buf, /* read_buf */ + sizeof(__vstream_stdin_buf), /* read_buf_len */ + 0, /* read_cnt */ + __vstream_stdin_buf, /* read_ptr */ + 0, /* sys_read_ready */ + 0, /* total_read_cnt */ + 0, /* total_write_cnt */ + NULL, /* ioctl_read_ctx */ + NULL, /* ioctl_write_ctx */ + NULL, /* fdp */ + ACL_VSTREAM_FLAG_READ, /* flag */ + "\0", /* errbuf */ + 0, /* errnum */ + 0, /* rw_timeout */ + "\0", /* local_addr */ + "\0", /* remote_addr */ + NULL, /* path */ + NULL, /* context */ + NULL, /* close_handle_lnk */ + __sys_getc, /* sys_getc */ + acl_socket_read, /* read_fn */ + NULL, /* write_fn */ + NULL, /* writev_fn */ + acl_file_read, /* fread_fn */ + NULL, /* fwrite_fn */ + NULL, /* fwritev_fn */ + acl_socket_close, /* close_fn */ + acl_file_close, /* fclose_fn */ + 0, /* oflags */ + 0, /* nrefer */ + 0, /* pid */ +#ifdef ACL_MS_WINDOWS + NULL, /* hproc */ + ACL_SOCKET_INVALID, /* iocp_sock */ +#endif + }, + + { +#ifdef ACL_UNIX + { STDOUT_FILENO }, /* h_file */ +#elif defined(ACL_MS_WINDOWS) + -1, /* h_file */ +#endif + 0, /* is_nonblock */ + ACL_VSTREAM_TYPE_FILE, /* type */ + 0, /* offset */ + 0, /* sys_offset */ + 0, /* wbuf */ + 0, /* wbuf_size */ + 0, /* wbuf_dlen */ + __vstream_stdout_buf, /* read_buf */ + sizeof(__vstream_stdout_buf), /* read_buf_len */ + 0, /* read_cnt */ + __vstream_stdout_buf, /* read_ptr */ + 0, /* sys_read_ready */ + 0, /* total_read_cnt */ + 0, /* total_write_cnt */ + NULL, /* ioctl_read_ctx */ + NULL, /* ioctl_write_ctx */ + NULL, /* fdp */ + ACL_VSTREAM_FLAG_WRITE, /* flag */ + "\0", /* errbuf */ + 0, /* errnum */ + 0, /* rw_timeout */ + "\0", /* local_addr */ + "\0", /* remote_addr */ + NULL, /* path */ + NULL, /* context */ + NULL, /* close_handle_lnk */ + __sys_getc, /* sys_getc */ + NULL, /* read_fn */ + acl_socket_write, /* write_fn */ + acl_socket_writev, /* writev_fn */ + NULL, /* fread_fn */ + acl_file_write, /* fwrite_fn */ + acl_file_writev, /* fwritev_fn */ + acl_socket_close, /* close_fn */ + acl_file_close, /* fclose_fn */ + 0, /* oflags */ + 0, /* nrefer */ + 0, /* pid */ +#ifdef ACL_MS_WINDOWS + NULL, /* hproc */ + ACL_SOCKET_INVALID, /* iocp_sock */ +#endif + }, + { +#ifdef ACL_UNIX + { STDERR_FILENO }, /* h_file */ +#elif defined(ACL_MS_WINDOWS) + -1, /* h_file */ +#endif + 0, /* is_nonblock */ + ACL_VSTREAM_TYPE_FILE, /* type */ + 0, /* offset */ + 0, /* sys_offset */ + 0, /* wbuf */ + 0, /* wbuf_size */ + 0, /* wbuf_dlen */ + __vstream_stderr_buf, /* read_buf */ + sizeof(__vstream_stderr_buf), /* read_buf_len */ + 0, /* read_cnt */ + __vstream_stderr_buf, /* read_ptr */ + 0, /* sys_read_ready */ + 0, /* total_read_cnt */ + 0, /* total_write_cnt */ + NULL, /* ioctl_read_ctx */ + NULL, /* ioctl_write_ctx */ + NULL, /* fdp */ + ACL_VSTREAM_FLAG_WRITE, /* flag */ + "\0", /* errbuf */ + 0, /* errnum */ + 0, /* rw_timeout */ + "\0", /* local_addr */ + "\0", /* remote_addr */ + NULL, /* path */ + NULL, /* context */ + NULL, /* close_handle_lnk */ + __sys_getc, /* sys_getc */ + NULL, /* read_fn */ + acl_socket_write, /* write_fn */ + acl_socket_writev, /* writev_fn */ + NULL, /* fread_fn */ + acl_file_write, /* fwrite_fn */ + acl_file_writev, /* fwritev_fn */ + acl_socket_close, /* close_fn */ + acl_file_close, /* fclose_fn */ + 0, /* oflags */ + 0, /* nrefer */ + 0, /* pid */ +#ifdef ACL_MS_WINDOWS + NULL, /* hproc */ + ACL_SOCKET_INVALID, /* iocp_sock */ +#endif + }, +}; + +void acl_vstream_init() +{ + static int __called = 0; + + if (__called) + return; + __called = 1; + +#ifdef ACL_MS_WINDOWS +# if 0 + ACL_VSTREAM_IN->fd.h_file = (HANDLE) _get_osfhandle(_fileno(stdin)); + ACL_VSTREAM_OUT->fd.h_file = (HANDLE) _get_osfhandle(_fileno(stdout)); + ACL_VSTREAM_ERR->fd.h_file = (HANDLE) _get_osfhandle(_fileno(stderr)); +# else + ACL_VSTREAM_IN->fd.h_file = GetStdHandle(STD_INPUT_HANDLE); + ACL_VSTREAM_OUT->fd.h_file = GetStdHandle(STD_OUTPUT_HANDLE); + ACL_VSTREAM_ERR->fd.h_file = GetStdHandle(STD_ERROR_HANDLE); +# endif +#endif +} + +static int __vstream_sys_read(ACL_VSTREAM *stream) +{ + /* 清除可读标志位 */ + stream->sys_read_ready = 0; + + if (stream->type == ACL_VSTREAM_TYPE_FILE) { + if (ACL_VSTREAM_FILE(stream) == ACL_FILE_INVALID) + return (-1); + } else if (ACL_VSTREAM_SOCK(stream) == ACL_SOCKET_INVALID) + return (-1); + +AGAIN: + if (stream->rw_timeout > 0 + && acl_read_wait(ACL_VSTREAM_SOCK(stream), stream->rw_timeout) < 0) { + + stream->errnum = acl_last_error(); + + if (stream->errnum != ACL_ETIMEDOUT) { + (void) acl_strerror(stream->errnum, + stream->errbuf, + sizeof(stream->errbuf)); + stream->flag |= ACL_VSTREAM_FLAG_ERR; + } else { + stream->flag |= ACL_VSTREAM_FLAG_TIMEOUT; + ACL_SAFE_STRNCPY(stream->errbuf, "read timeout", sizeof(stream->errbuf)); + } + + return (-1); + } + + acl_set_error(0); + + if (stream->type == ACL_VSTREAM_TYPE_FILE) { + stream->read_cnt = stream->fread_fn(ACL_VSTREAM_FILE(stream), + stream->read_buf, + (size_t) stream->read_buf_len, + stream->rw_timeout, + stream->context); + if (stream->read_cnt > 0) + stream->sys_offset += stream->read_cnt; + } else + stream->read_cnt = stream->read_fn(ACL_VSTREAM_SOCK(stream), + stream->read_buf, + (size_t) stream->read_buf_len, + stream->rw_timeout, + stream->context); + if (stream->read_cnt < 0) { + stream->errnum = acl_last_error(); + if (stream->errnum == ACL_EINTR) { + goto AGAIN; + } else if (stream->errnum == ACL_ETIMEDOUT) { + stream->flag |= ACL_VSTREAM_FLAG_TIMEOUT; + ACL_SAFE_STRNCPY(stream->errbuf, "read timeout", sizeof(stream->errbuf)); + } else if (stream->errnum != ACL_EWOULDBLOCK && stream->errnum != ACL_EAGAIN) { + stream->flag |= ACL_VSTREAM_FLAG_ERR; + acl_strerror(stream->errnum, stream->errbuf, sizeof(stream->errbuf)); + } + /* XXX: should do something where, 2009.12.25 -- zsx */ + + stream->read_cnt = 0; /* xxx: why? */ + return (-1); + } else if (stream->read_cnt == 0) { /* closed by peer */ + char ebuf[256]; + stream->flag = ACL_VSTREAM_FLAG_EOF; + stream->errnum = 0; + snprintf(stream->errbuf, sizeof(stream->errbuf), + "closed by peer(%s)", acl_last_strerror(ebuf, sizeof(ebuf))); + + return (0); + } + + stream->read_ptr = stream->read_buf; + stream->flag &= ~ACL_VSTREAM_FLAG_BAD; + stream->errnum = 0; + stream->errbuf[0] = 0; + stream->total_read_cnt += stream->read_cnt; + + return ((int) stream->read_cnt); +} + +static int __sys_getc(ACL_VSTREAM *stream) +{ + stream->read_cnt = __vstream_sys_read(stream); + if (stream->read_cnt <= 0) { + return (ACL_VSTREAM_EOF); + } else { + return (ACL_VSTREAM_GETC(stream)); + } +} + +int acl_vstream_getc(ACL_VSTREAM *stream) +{ + if (stream == NULL) + return (ACL_VSTREAM_EOF); + if (stream->read_cnt <= 0) { + if (__vstream_sys_read(stream) <= 0) + return (ACL_VSTREAM_EOF); + } + + stream->read_cnt--; + stream->offset++; + return (*stream->read_ptr++); +} + +int acl_vstream_nonb_readn(ACL_VSTREAM *stream, char *buf, int size) +{ + const char *myname = "acl_vstream_nonb_readn"; + int n, nread, read_cnt; + unsigned char *ptr; + int rw_timeout; +#ifdef ACL_UNIX + int flags; +#endif + + if (stream == NULL || buf == NULL || size <= 0) + return (ACL_VSTREAM_EOF); + + if (stream->read_cnt < 0) + acl_msg_fatal("%s, %s(%d): read_cnt(%d) < 0, fd(%d)", myname, __FILE__, + __LINE__, (int) stream->read_cnt, ACL_VSTREAM_SOCK(stream)); + + ptr = (unsigned char *) buf; + nread = 0; + + if (stream->read_cnt > 0) { + n = size > (int) stream->read_cnt ? (int) stream->read_cnt : size; + read_cnt = acl_vstream_bfcp_some(stream, ptr, n); + if (read_cnt <= 0) { + acl_msg_error("%s, %s(%d): internal error, read_cnt = %d", + myname, __FILE__, __LINE__, read_cnt); + return (ACL_VSTREAM_EOF); + } + size -= read_cnt; + ptr += read_cnt; + nread += read_cnt; + if (size == 0) + return (read_cnt); + else if (size < 0) { + acl_msg_error("%s, %s(%d): internal error, size = %d", + myname, __FILE__, __LINE__, size); + return (ACL_VSTREAM_EOF); + } + } + +#ifdef ACL_UNIX + flags = fcntl(ACL_VSTREAM_SOCK(stream), F_GETFL, 0); + if (flags < 0) { + acl_msg_error("%s, %s(%d): fcntl error(%s), fd=%d", + myname, __FILE__, __LINE__, acl_last_serror(), + ACL_VSTREAM_SOCK(stream)); + return (ACL_VSTREAM_EOF); + } + acl_non_blocking(ACL_VSTREAM_SOCK(stream), 1); +#elif defined(ACL_MS_WINDOWS) + if (stream->type != ACL_VSTREAM_TYPE_FILE) + acl_non_blocking(ACL_VSTREAM_SOCK(stream), 1); +#endif + + /* 先保留读写超时时间值,并将该流的超时值置为0,以免 + * 启动读超时过程(select)。 + */ + rw_timeout = stream->rw_timeout; + stream->rw_timeout = 0; + stream->errnum = 0; + + read_cnt = __vstream_sys_read(stream); + + stream->rw_timeout = rw_timeout; + + /* 恢复该套接字的原有标记位 */ +#ifdef ACL_UNIX + flags = fcntl(ACL_VSTREAM_SOCK(stream), F_SETFL, flags); + if (flags < 0) { + acl_msg_error("%s, %s(%d): fcntl error(%s), fd=%d", + myname, __FILE__, __LINE__, + acl_last_serror(), ACL_VSTREAM_SOCK(stream)); + return (ACL_VSTREAM_EOF); + } + +#elif defined(ACL_MS_WINDOWS) + if (stream->is_nonblock == 0 && stream->type != ACL_VSTREAM_TYPE_FILE) + acl_non_blocking(ACL_VSTREAM_SOCK(stream), ACL_BLOCKING); +#endif + + if (read_cnt < 0) { +#ifdef ACL_MS_WINDOWS + if (stream->errnum == ACL_EWOULDBLOCK) +#elif defined(ACL_UNIX) + if (stream->errnum == ACL_EWOULDBLOCK || stream->errnum == ACL_EAGAIN) +#endif + return (nread); + else if (nread == 0) + return (ACL_VSTREAM_EOF); + else + return (nread); + } else if (read_cnt == 0) { + if (nread == 0) + return (ACL_VSTREAM_EOF); + else + return (nread); + } + + if (stream->read_cnt > 0) { + n = size > (int) stream->read_cnt ? (int) stream->read_cnt : size; + read_cnt = acl_vstream_bfcp_some(stream, ptr, n); + if (read_cnt <= 0) { + acl_msg_error("%s, %s(%d): internal error, read_cnt = %d", + myname, __FILE__, __LINE__, read_cnt); + return (ACL_VSTREAM_EOF); + } + + nread += read_cnt; + } + + stream->rw_timeout = rw_timeout; + + return (nread); +} + +int acl_vstream_probe_status(ACL_VSTREAM *stream) +{ +#ifdef ACL_UNIX + const char *myname = "acl_vstream_probe_status"; + int flags; +#endif + int ch; + int rw_timeout; + + if (stream == NULL) + return (-1); + +#ifdef ACL_UNIX + flags = fcntl(ACL_VSTREAM_SOCK(stream), F_GETFL, 0); + if (flags < 0) { + acl_msg_error("%s, %s(%d): fcntl error(%s), fd=%d", + myname, __FILE__, __LINE__, + acl_last_serror(), ACL_VSTREAM_SOCK(stream)); + return (-1); + } + acl_non_blocking(ACL_VSTREAM_SOCK(stream), 1); +#elif defined(ACL_MS_WINDOWS) + if (stream->type != ACL_VSTREAM_TYPE_FILE) + acl_non_blocking(ACL_VSTREAM_SOCK(stream), 1); +#endif + + rw_timeout = stream->rw_timeout; + + /* 先保留读写超时时间值,并将该流的超时值置为0,以免 + * 启动读超时过程(select)。 + */ + stream->rw_timeout = 0; + stream->errnum = 0; + + ch = acl_vstream_getc(stream); + + stream->rw_timeout = rw_timeout; + + /* 恢复该套接字的原有标记位 */ +#ifdef ACL_UNIX + flags = fcntl(ACL_VSTREAM_SOCK(stream), F_SETFL, flags); + if (flags < 0) { + acl_msg_error("%s, %s(%d): fcntl error(%s), fd=%d", + myname, __FILE__, __LINE__, + acl_last_serror(), ACL_VSTREAM_SOCK(stream)); + return (-1); + } + +#elif defined(ACL_MS_WINDOWS) + if (stream->is_nonblock == 0 && stream->type != ACL_VSTREAM_TYPE_FILE) + acl_non_blocking(ACL_VSTREAM_SOCK(stream), ACL_BLOCKING); +#endif + + if (ch == ACL_VSTREAM_EOF) { +#ifdef ACL_MS_WINDOWS + if (stream->errnum == ACL_EWOULDBLOCK) +#elif defined(ACL_UNIX) + if (stream->errnum == ACL_EWOULDBLOCK || stream->errnum == ACL_EAGAIN) +#endif + return (0); + else + return (-1); + } else { + /* 将读到的数据再放回原处:) */ + stream->read_cnt++; + stream->read_ptr--; + stream->offset--; + if (stream->read_ptr < stream->read_buf) + return (-1); + return (0); + } +} + +int acl_vstream_ungetc(ACL_VSTREAM *stream, int ch) +{ + unsigned char c; + + c = (unsigned char) ch; + (void) acl_vstream_unread(stream, &c, 1); + return (ch); +} + +static void *vstream_memmove(ACL_VSTREAM *stream, size_t n) +{ +#if 1 + char *src, *dst, *dst_saved; + + if (stream->read_cnt == 0) + return (stream->read_buf); + + src = (char*) stream->read_ptr + stream->read_cnt - 1; + dst_saved = dst = (char*) stream->read_ptr + n + stream->read_cnt - 1; + + /* 为了防止内存数据覆盖问题, 采用数据从尾部拷贝方式 */ + while (src >= (char*) stream->read_ptr) + *dst-- = *src--; + return (dst_saved); +#else + return (memmove((char*) stream->read_ptr + n, + stream->read_ptr, stream->read_cnt)); +#endif +} + +int acl_vstream_unread(ACL_VSTREAM *stream, const void *ptr, size_t length) +{ + size_t capacity = stream->read_ptr - stream->read_buf; + ssize_t k = capacity - length; + + /* 如果读缓冲中前部分空间不足, 则需要调整数据位置或扩充读缓冲区空间 */ + + if (k < 0) { + void *pbuf; + size_t n, min_delta = 4096; + + n = (size_t) -k; + + /* 如果读缓冲区后部分空间够用, 则只需后移缓冲区中的数据 */ + + if (stream->read_buf_len - stream->read_cnt > (acl_off_t) length) { + if (stream->read_cnt > 0) + vstream_memmove(stream, n); + + memcpy(stream->read_buf, ptr, length); + stream->read_ptr = stream->read_buf; + stream->read_cnt += length; + stream->offset = 0; + return ((int) length); + } + + /* 说明整个缓冲区的空间都不够用, 所以需要扩充缓冲区空间 */ + + n = min_delta * ((n + min_delta - 1) / min_delta); + acl_assert(n > 0); + stream->read_buf_len += n; + pbuf = acl_mymalloc((size_t) stream->read_buf_len); + + memcpy(pbuf, ptr, length); + if (stream->read_cnt > 0) + memcpy((char*) pbuf + length, + stream->read_ptr, (size_t) stream->read_cnt); + acl_myfree(stream->read_buf); + + stream->read_buf = pbuf; + stream->read_ptr = stream->read_buf; + stream->read_cnt += length; + stream->offset = 0; + return ((int) length); + } + + stream->read_ptr -= length; + memcpy(stream->read_ptr, ptr, length); + stream->read_cnt += length; + stream->offset -= length; + return ((int) length); +} + +int acl_vstream_bfcp_some(ACL_VSTREAM *stream, void *vptr, size_t maxlen) +{ + const char *myname = "acl_vstream_bfcp_some"; + int n; + + /* input params error */ + if (stream == NULL || vptr == NULL || maxlen <= 0) + acl_msg_fatal("%s, %s(%d): input error", myname, __FILE__, __LINE__); + + /* internal fatal error */ + if (stream->read_cnt < 0) + acl_msg_fatal("%s, %s(%d): read_cnt(=%d) < 0", + myname, __FILE__, __LINE__, (int) stream->read_cnt); + + /* there is no any data in buf */ + if (stream->read_cnt == 0) { + stream->read_ptr = stream->read_buf; + return (0); + } + + if (stream->read_ptr >= stream->read_buf + (int) stream->read_buf_len) { + stream->read_cnt = 0; + stream->read_ptr = stream->read_buf; + return (0); + } + + n = (int) stream->read_cnt > (int) maxlen ? (int) maxlen : (int) stream->read_cnt; + + memcpy(vptr, stream->read_ptr, n); + + stream->read_cnt -= n; + stream->read_ptr += n; + stream->offset += n; + + return (n); +} + +int acl_vstream_gets(ACL_VSTREAM *stream, void *vptr, size_t maxlen) +{ + int n, ch; + unsigned char *ptr; + + if (stream == NULL || vptr == NULL || maxlen <= 0) + return (ACL_VSTREAM_EOF); + + ptr = (unsigned char *) vptr; + for (n = 1; n < (int) maxlen; n++) { /* left one byte for '\0' */ +#ifdef _USE_FAST_MACRO + ch = ACL_VSTREAM_GETC(stream); +#else + ch = acl_vstream_getc(stream); +#endif + if (ch == ACL_VSTREAM_EOF) { + stream->flag &= ~ACL_VSTREAM_FLAG_TAGYES; + stream->flag |= ACL_VSTREAM_FLAG_TAGNO; + if (n == 1) + return (ACL_VSTREAM_EOF);/* EOF, nodata read */ + break; /* EOF, some data was read */ + } else { + *ptr++ = ch; + if (ch == '\n'){ /* newline is stored, like fgets() */ + stream->flag |= ACL_VSTREAM_FLAG_TAGYES; + stream->flag &= ~ACL_VSTREAM_FLAG_TAGNO; + break; + } + } + } + + *ptr = 0; /* null terminate like fgets() */ + return (n); +} + +int acl_vstream_readtags(ACL_VSTREAM *stream, + void *vptr, + size_t maxlen, + const char *tag, + size_t taglen) +{ + int n, ch, flag_match = 0; + unsigned char *ptr; + const unsigned char *ptr_haystack; + const unsigned char *ptr_needle, *ptr_needle_end; + + if (stream == NULL || vptr == NULL || maxlen <= 0 + || tag == NULL || taglen <= 0) + return (ACL_VSTREAM_EOF); + + ptr_needle_end = (const unsigned char *) tag; + + while(1) { + taglen--; + if (taglen == 0) + break; + ptr_needle_end++; + } + ptr = (unsigned char *) vptr; + + for (n = 1; n < (int) maxlen; n++) { /* left one byte for '\0' */ +#ifdef _USE_FAST_MACRO + ch = ACL_VSTREAM_GETC(stream); +#else + ch = acl_vstream_getc(stream); +#endif + if (ch == ACL_VSTREAM_EOF) { + if (n == 1) + return (ACL_VSTREAM_EOF);/* EOF, nodata read */ + else { + stream->flag &= ~ACL_VSTREAM_FLAG_TAGYES; + stream->flag |= ACL_VSTREAM_FLAG_TAGNO; + break; /* EOF, some data was read */ + } + } else { + *ptr = ch; + if (ch == *ptr_needle_end) { + ptr_haystack = ptr - 1; + ptr_needle = ptr_needle_end - 1; + flag_match = 0; + while(1) { + /* 已经成功比较完毕(匹配) */ + if (ptr_needle < (const unsigned char *) tag) { + flag_match = 1; + break; + } + + /* 原字符串用完而匹配串还没有比较完(不匹配) */ + if (ptr_haystack < (unsigned char *) vptr) + break; + /* 不相等(不匹配) */ + if (*ptr_haystack != *ptr_needle) + break; + ptr_haystack--; + ptr_needle--; + } + } + ptr++; + if (flag_match) { + stream->flag |= ACL_VSTREAM_FLAG_TAGYES; + stream->flag &= ~ACL_VSTREAM_FLAG_TAGNO; + break; + } + } + } + *ptr = 0; /* null terminate like fgets() */ + return (n); +} + +int acl_vstream_gets_nonl(ACL_VSTREAM *stream, void *vptr, size_t maxlen) +{ + int n, ch; + unsigned char *ptr; + + if (stream == NULL || vptr == NULL || maxlen <= 0) { + return (ACL_VSTREAM_EOF); + } + + ptr = (unsigned char *) vptr; + for (n = 1; n < (int) maxlen; n++) { +#ifdef _USE_FAST_MACRO + ch = ACL_VSTREAM_GETC(stream); +#else + ch = acl_vstream_getc(stream); +#endif + if (ch == ACL_VSTREAM_EOF) { + stream->flag &= ~ACL_VSTREAM_FLAG_TAGYES; + stream->flag |= ACL_VSTREAM_FLAG_TAGNO; + if (n == 1) + return (ACL_VSTREAM_EOF); /* EOF, nodata read */ + else + break; /* EOF, some data was read */ + } else { + *ptr++ = ch; + if (ch == '\n') { + stream->flag |= ACL_VSTREAM_FLAG_TAGYES; + stream->flag &= ~ACL_VSTREAM_FLAG_TAGNO; + break; /* newline is stored, like fgets() */ + } + } + } + + *ptr = 0; /* null terminate like fgets() */ + ptr--; + while (ptr >= (unsigned char *) vptr) { + if (*ptr == '\r' || *ptr == '\n') { + *ptr-- = 0; + n--; + continue; + } + break; + } + return (n); +} + +int acl_vstream_readn(ACL_VSTREAM *stream, void *vptr, size_t maxlen) +{ + int n, ch; + unsigned char *ptr; + + if (stream == NULL || vptr == NULL || (int) maxlen <= 0) + return (ACL_VSTREAM_EOF); + + ptr = (unsigned char *) vptr; + for (n = 0; n < (int) maxlen; n++) { +#ifdef _USE_FAST_MACRO + ch = ACL_VSTREAM_GETC(stream); +#else + ch = acl_vstream_getc(stream); +#endif + if (ch == ACL_VSTREAM_EOF) { + if (n == 0) + return (ACL_VSTREAM_EOF); /* EOF, nodata read */ + else + break; /* EOF, some data was read */ + } else { + *ptr++ = ch; + } + } + + if (n != (int) maxlen) { + snprintf(stream->errbuf, sizeof(stream->errbuf), + "nread=%d, nneed=%d, errmsg=not read the needed data", + n, (int) maxlen); + stream->flag |= ACL_VSTREAM_FLAG_RDSHORT; + + return (ACL_VSTREAM_EOF); + } + + return (n); +} + +int acl_vstream_read(ACL_VSTREAM *stream, void *vptr, size_t maxlen) +{ + const char *myname = "acl_vstream_read"; + int read_cnt; + unsigned char *ptr; + + if (stream == NULL || vptr == NULL || (int) maxlen <= 0) + return (ACL_VSTREAM_EOF); + + if (stream->read_cnt < 0) { + acl_msg_fatal("%s, %s(%d): read_cnt(%d) < 0", + myname, __FILE__, __LINE__, (int) stream->read_cnt); + } + ptr = (unsigned char *) vptr; + if (stream->read_cnt > 0) { + read_cnt = acl_vstream_bfcp_some(stream, ptr, maxlen); + return (read_cnt); + } + + /* stream->read_cnt == 0 */ + + /* there is no data in buf, so need to read data from system */ + read_cnt = __vstream_sys_read(stream); + if (read_cnt < 0) + return (ACL_VSTREAM_EOF); + else if (read_cnt == 0) + return (ACL_VSTREAM_EOF); + + read_cnt = acl_vstream_bfcp_some(stream, ptr, maxlen); + return (read_cnt); +} + +static void __bfgets_crlf_peek(ACL_VSTREAM *stream, ACL_VSTRING *strbuf, int *ready) +{ + if (stream->read_cnt <= 0) /* XXX: sanity check */ + return; + while (stream->read_cnt > 0) { + ACL_VSTRING_ADDCH(strbuf, *(stream->read_ptr)); + stream->read_cnt--; + stream->offset++; + if (*(stream->read_ptr) == '\n') { + *ready = 1; + stream->read_ptr++; + break; + } + stream->read_ptr++; + } + + ACL_VSTRING_TERMINATE(strbuf); /* set '\0' teminated */ +} + +int acl_vstream_gets_peek(ACL_VSTREAM *stream, ACL_VSTRING *strbuf, int *ready) +{ + const char *myname = "acl_vstream_gets_peek"; + int n; + + if (stream == NULL || strbuf == NULL || ready == NULL) + acl_msg_fatal("%s, %s(%d): invalid input", myname, __FILE__, __LINE__); + + *ready = 0; + n = ACL_VSTRING_LEN(strbuf); + + if (stream->read_cnt < 0) + acl_msg_fatal("%s, %s(%d): read_cnt(=%d) < 0", + myname, __FILE__, __LINE__, (int) stream->read_cnt); + + if (stream->read_cnt > 0) { + __bfgets_crlf_peek(stream, strbuf, ready); + if (*ready) + return (ACL_VSTRING_LEN(strbuf) - n); + } + + /* XXX: 调用者通过检查 *ready 值来判断是否读够数据 */ + /* 系统IO读操作出错或关闭时返回结束标记 */ + /* 如果返回 ACL_VSTRING_EOF 则调用者应该通过检查缓冲区长度来处理未被处理的数据 */ + + if (stream->sys_read_ready) { + if (__vstream_sys_read(stream) <= 0) { + n = ACL_VSTRING_LEN(strbuf) - n; + return (n > 0 ? n : ACL_VSTREAM_EOF); + } + } + + if (stream->read_cnt > 0) + __bfgets_crlf_peek(stream, strbuf, ready); + return (ACL_VSTRING_LEN(strbuf) - n); +} + +static void __bfgets_no_crlf_peek(ACL_VSTREAM *stream, ACL_VSTRING *strbuf, int *ready) +{ + int n, ch; + + if (stream->read_cnt <= 0) /* XXX: sanity check */ + return; + + while (stream->read_cnt > 0) { + ACL_VSTRING_ADDCH(strbuf, *(stream->read_ptr)); + stream->read_cnt--; + stream->offset++; + if (*(stream->read_ptr) == '\n') { /* ok, get '\n' */ + *ready = 1; /* set to be ready */ + stream->read_ptr++; + break; + } + stream->read_ptr++; + } + + if (*ready == 1) { + n = ACL_VSTRING_LEN(strbuf) - 1; + while (n >= 0) { + ch = acl_vstring_charat(strbuf, n); + if (ch == '\r' || ch == '\n') + n--; + else + break; + } + acl_vstring_truncate(strbuf, n + 1); /* reset the offset position */ + } + + ACL_VSTRING_TERMINATE(strbuf); /* set '\0' teminated */ +} + +int acl_vstream_gets_nonl_peek(ACL_VSTREAM *stream, ACL_VSTRING *strbuf, int *ready) +{ + const char *myname = "acl_vstream_gets_nonl_peek"; + int n; + + if (stream == NULL || strbuf == NULL || ready == NULL) + acl_msg_fatal("%s, %s(%d): invalid input", myname, __FILE__, __LINE__); + + *ready = 0; + n = ACL_VSTRING_LEN(strbuf); + + if (stream->read_cnt < 0) + acl_msg_fatal("%s, %s(%d): read_cnt(=%d) < 0", + myname, __FILE__, __LINE__, (int) stream->read_cnt); + + if (stream->read_cnt > 0) { + __bfgets_no_crlf_peek(stream, strbuf, ready); + if (*ready) + return (ACL_VSTRING_LEN(strbuf) - n); + } + + /* XXX: 调用者通过检查 *ready 值来判断是否读够数据 */ + /* 系统IO读操作出错或关闭时返回结束标记 */ + /* 如果返回 ACL_VSTRING_EOF 则调用者应该通过检查缓冲区长度来处理未被处理的数据 */ + + if (stream->sys_read_ready) { + if (__vstream_sys_read(stream) <= 0) { + n = ACL_VSTRING_LEN(strbuf) - n; + return (n > 0 ? n : ACL_VSTREAM_EOF); + } + } + + if (stream->read_cnt > 0) + __bfgets_no_crlf_peek(stream, strbuf, ready); + return (ACL_VSTRING_LEN(strbuf) - n); +} + +static int __bfread_cnt_peek(ACL_VSTREAM *stream, ACL_VSTRING *strbuf, int cnt, int *ready) +{ + int n; + + if (stream->read_cnt <= 0) /* XXX: sanity check */ + return (0); + n = (int) (stream->read_cnt > cnt ? cnt : stream->read_cnt); + acl_vstring_memcat(strbuf, (char*) stream->read_ptr, n); + stream->read_cnt -= n; + stream->offset += n; + stream->read_ptr += n; + cnt -= n; + if (cnt == 0) + *ready = 1; + + ACL_VSTRING_TERMINATE(strbuf); /* set '\0' teminated */ + return (n); +} + +int acl_vstream_readn_peek(ACL_VSTREAM *stream, ACL_VSTRING *strbuf, int cnt, int *ready) +{ + const char *myname = "acl_vstream_readn_peek"; + int cnt_saved = cnt; + + if (stream == NULL || strbuf == NULL || cnt <= 0 || ready == NULL) + acl_msg_fatal("%s, %s(%d): invalid input", myname, __FILE__, __LINE__); + + *ready = 0; + if (stream->read_cnt < 0) + acl_msg_fatal("%s, %s(%d): read_cnt(=%d) < 0", + myname, __FILE__, __LINE__, (int) stream->read_cnt); + + if (stream->read_cnt > 0) { + cnt -= __bfread_cnt_peek(stream, strbuf, cnt, ready); + if (*ready) + return (cnt_saved - cnt); + } + + /* XXX: 调用者通过检查 *ready 值来判断是否读够数据 */ + /* 系统IO读操作出错或关闭时返回结束标记 */ + /* 如果返回 ACL_VSTRING_EOF 则调用者应该通过检查缓冲区长度来处理未被处理的数据 */ + + if (stream->sys_read_ready) { + if (__vstream_sys_read(stream) <= 0) { + int n = cnt_saved - cnt; + return (n > 0 ? n : ACL_VSTREAM_EOF); + } + } + + if (stream->read_cnt > 0) + cnt -= __bfread_cnt_peek(stream, strbuf, cnt, ready); + return (cnt_saved - cnt); +} + +static void __bfread_peek(ACL_VSTREAM *stream, ACL_VSTRING *strbuf) +{ + if (stream->read_cnt <= 0) /* XXX: sanity check */ + return; + acl_vstring_memcat(strbuf, (char*) stream->read_ptr, + (size_t) stream->read_cnt); + stream->offset += stream->read_cnt; + stream->read_ptr += stream->read_cnt; + stream->read_cnt = 0; + + ACL_VSTRING_TERMINATE(strbuf); /* set '\0' teminated */ +} + +int acl_vstream_read_peek(ACL_VSTREAM *stream, ACL_VSTRING *strbuf) +{ + const char *myname = "acl_vstream_read_peek"; + int n; + + if (stream == NULL || strbuf == NULL) + acl_msg_fatal("%s, %s(%d): invalid input", myname, __FILE__, __LINE__); + + n = ACL_VSTRING_LEN(strbuf); + + if (stream->read_cnt < 0) + acl_msg_fatal("%s, %s(%d): read_cnt(=%d) < 0", + myname, __FILE__, __LINE__, (int) stream->read_cnt); + + if (stream->read_cnt > 0) + __bfread_peek(stream, strbuf); + + /* 系统IO读操作出错或关闭时返回结束标记 */ + /* 如果返回 ACL_VSTRING_EOF 则调用者应该通过检查缓冲区长度来处理未被处理的数据 */ + + if (stream->sys_read_ready) { + if (__vstream_sys_read(stream) <= 0) { + n = ACL_VSTRING_LEN(strbuf) - n; + return (n > 0 ? n : ACL_VSTREAM_EOF); + } + } + + if (stream->read_cnt > 0) + __bfread_peek(stream, strbuf); + return (ACL_VSTRING_LEN(strbuf) - n); +} + +int acl_vstream_can_read(ACL_VSTREAM *stream) +{ + const char *myname = "acl_vstream_can_read"; + + if (stream->read_cnt < 0) + acl_msg_fatal("%s, %s(%d): read_cnt(=%d) < 0", + myname, __FILE__, __LINE__, (int) stream->read_cnt); + + if (stream->flag & (ACL_VSTREAM_FLAG_ERR | ACL_VSTREAM_FLAG_EOF)) + return (ACL_VSTREAM_EOF); + else if (stream->read_cnt > 0) + return (1); + else if (stream->sys_read_ready == 0) + return (0); + else if ((stream->flag & ACL_VSTREAM_FLAG_PREREAD) != 0) { + if (__vstream_sys_read(stream) <= 0) + return (ACL_VSTREAM_EOF); + else + return (1); + } + else + return (1); +} + +static int __vstream_sys_write(ACL_VSTREAM *stream, const void *vptr, int dlen) +{ + const char *myname = "__vstream_sys_write"; + int n, neintr = 0; + + if (stream == NULL || vptr == NULL || dlen <= 0) { + if (stream == NULL) + acl_msg_error("%s, %s(%d): stream null", myname, __FILE__, __LINE__); + if (vptr == NULL) + acl_msg_error("%s, %s(%d): vptr null", myname, __FILE__, __LINE__); + if (dlen <= 0) + acl_msg_error("%s, %s(%d): dlen(%d) <= 0", myname, __FILE__, __LINE__, dlen); + acl_msg_error("%s, %s(%d): input invalid", myname, __FILE__, __LINE__); + return (ACL_VSTREAM_EOF); + } + + if (stream->type == ACL_VSTREAM_TYPE_FILE) { + if (ACL_VSTREAM_FILE(stream) == ACL_FILE_INVALID) { + acl_msg_error("%s, %s(%d): h_file invalid", myname, __FILE__, __LINE__); + return (ACL_VSTREAM_EOF); + } + } else if (ACL_VSTREAM_SOCK(stream) == ACL_SOCKET_INVALID) { + acl_msg_error("%s, %s(%d): sockfd invalid", myname, __FILE__, __LINE__); + return (ACL_VSTREAM_EOF); + } + +TAG_AGAIN: + + if (stream->type == ACL_VSTREAM_TYPE_FILE) { + if ((stream->oflags & O_APPEND)) { +#ifdef ACL_MS_WINDOWS + stream->sys_offset = acl_lseek(ACL_VSTREAM_FILE(stream), 0, SEEK_END); + if (stream->sys_offset < 0) + return (ACL_VSTREAM_EOF); +#endif + } else if ((stream->flag & ACL_VSTREAM_FLAG_CACHE_SEEK) + && stream->offset != stream->sys_offset) { + + stream->sys_offset = acl_lseek(ACL_VSTREAM_FILE(stream), + stream->offset, SEEK_SET); + if (stream->sys_offset == -1) { + acl_msg_error("%s, %s(%d): lseek error(%s), offset(" ACL_FMT_I64D + "), sys_offset(" ACL_FMT_I64D ")", myname, __FILE__, + __LINE__, acl_last_serror(), + stream->offset, stream->sys_offset); + return (ACL_VSTREAM_EOF); + } + stream->offset = stream->sys_offset; + } + + n = stream->fwrite_fn(ACL_VSTREAM_FILE(stream), vptr, dlen, + stream->rw_timeout, stream->context); + if (n > 0) { + stream->sys_offset += n; + stream->offset = stream->sys_offset; + stream->read_cnt = 0; /* 防止缓冲区内的数据与实际不一致, 仅对文件IO有效 */ + } + } else + n = stream->write_fn(ACL_VSTREAM_SOCK(stream), vptr, dlen, + stream->rw_timeout, stream->context); + if (n < 0) { + if (acl_last_error() == ACL_EINTR) { + if (++neintr >= 5) + return (ACL_VSTREAM_EOF); + + goto TAG_AGAIN; + } + + if (acl_last_error() == ACL_EAGAIN || acl_last_error() == ACL_EWOULDBLOCK) + acl_set_error(ACL_EAGAIN); + + return (ACL_VSTREAM_EOF); + } + + stream->total_write_cnt += n; + return (n); +} + +static int __vstream_sys_writev(ACL_VSTREAM *stream, const struct iovec *vector, int count) +{ + const char *myname = "__vstream_sys_writev"; + int n, neintr = 0; + + if (stream == NULL || vector == NULL || count <= 0) { + acl_msg_error("%s, %s(%d): input invalid", myname, __FILE__, __LINE__); + return (ACL_VSTREAM_EOF); + } + + if (stream->type == ACL_VSTREAM_TYPE_FILE) { + if (ACL_VSTREAM_FILE(stream) == ACL_FILE_INVALID) { + acl_msg_error("%s, %s(%d): h_file invalid", myname, __FILE__, __LINE__); + return (ACL_VSTREAM_EOF); + } + } else if (ACL_VSTREAM_SOCK(stream) == ACL_SOCKET_INVALID) { + acl_msg_error("%s, %s(%d): sockfd invalid", myname, __FILE__, __LINE__); + return (ACL_VSTREAM_EOF); + } + +TAG_AGAIN: + + if (stream->type == ACL_VSTREAM_TYPE_FILE) { + if ((stream->oflags & O_APPEND)) { +#ifdef ACL_MS_WINDOWS + stream->sys_offset = acl_lseek(ACL_VSTREAM_FILE(stream), 0, SEEK_END); + if (stream->sys_offset < 0) + return (ACL_VSTREAM_EOF); +#endif + } else if ((stream->flag & ACL_VSTREAM_FLAG_CACHE_SEEK) + && stream->offset != stream->sys_offset) { + stream->sys_offset = acl_lseek(ACL_VSTREAM_FILE(stream), + stream->offset, SEEK_SET); + if (stream->sys_offset == -1) { + acl_msg_error("%s, %s(%d): lseek error(%s), offset(" ACL_FMT_I64D + "), sys_offset(" ACL_FMT_I64D ")", myname, __FILE__, + __LINE__, acl_last_serror(), + stream->offset, stream->sys_offset); + return (ACL_VSTREAM_EOF); + } + } + + n = stream->fwritev_fn(ACL_VSTREAM_FILE(stream), vector, count, + stream->rw_timeout, stream->context); + if (n > 0) { + stream->sys_offset += n; + stream->offset = stream->sys_offset; + stream->read_cnt = 0; /* 防止缓冲区内的数据与实际不一致, 仅对文件IO有效 */ + } + } else + n = stream->writev_fn(ACL_VSTREAM_SOCK(stream), vector, count, + stream->rw_timeout, stream->context); + if (n < 0) { + if (acl_last_error() == ACL_EINTR) { + if (++neintr >= 5) + return (ACL_VSTREAM_EOF); + + goto TAG_AGAIN; + } + + if (acl_last_error() == ACL_EAGAIN || acl_last_error() == ACL_EWOULDBLOCK) + acl_set_error(ACL_EAGAIN); + + return (ACL_VSTREAM_EOF); + } + + stream->total_write_cnt += n; + return (n); +} + +int acl_vstream_write(ACL_VSTREAM *stream, const void *vptr, int dlen) +{ + if (stream->wbuf_dlen > 0) { + if (acl_vstream_fflush(stream) == ACL_VSTREAM_EOF) + return (ACL_VSTREAM_EOF); + } + return (__vstream_sys_write(stream, vptr, dlen)); +} + +int acl_vstream_writev(ACL_VSTREAM *stream, const struct iovec *vector, int count) +{ + if (stream->wbuf_dlen > 0) { + if (acl_vstream_fflush(stream) == ACL_VSTREAM_EOF) + return (ACL_VSTREAM_EOF); + } + return (__vstream_sys_writev(stream, vector, count)); +} + +int acl_vstream_writevn(ACL_VSTREAM *stream, const struct iovec *vector, int count) +{ + const char *myname = "acl_vstream_writevn"; + int n, i, dlen, k; + struct iovec *vect; + + if (count <= 0 || vector == NULL) + acl_msg_fatal("%s, %s(%d): invalid input", myname, __FILE__, __LINE__); + + if (stream->wbuf_dlen > 0) { + if (acl_vstream_fflush(stream) == ACL_VSTREAM_EOF) + return (ACL_VSTREAM_EOF); + } + vect = (struct iovec*) acl_mycalloc(count, sizeof(struct iovec)); + for (i = 0; i < count; i++) { + vect[i].iov_base = vector[i].iov_base; + vect[i].iov_len = vector[i].iov_len; + } + + dlen = 0; + + while (1) { + n = __vstream_sys_writev(stream, vect, count); + if (n == ACL_VSTREAM_EOF) { + acl_myfree(vect); + return (ACL_VSTREAM_EOF); + } + dlen += n; + + k = 0; + for (i = 0; i < count; i++) { + if (n >= (int) vect[i].iov_len) { + /* written */ + n -= vect[i].iov_len; + k++; + } else { + /* partially written */ + vect[i].iov_base = (void *) ((unsigned char*) vect[i].iov_base + n); + vect[i].iov_len -= n; + break; + } + } + + if (i >= count) { + acl_myfree(vect); + return (dlen); + } + count -= k; + vector += k; + } +} + +int acl_vstream_vfprintf(ACL_VSTREAM *stream, const char *fmt, va_list ap) +{ + const char *myname = "acl_vstream_vfprintf"; + ACL_VSTRING *strbuf; + int n; + + if (stream == NULL || fmt == NULL || *fmt == 0) { + acl_msg_error("%s, %s(%d): fmt invalid", myname, __FILE__, __LINE__); + return (ACL_VSTREAM_EOF); + } + + strbuf = acl_vstring_alloc(ACL_VSTREAM_BUFSIZE); + if (strbuf == NULL) { + acl_msg_fatal("%s, %s(%d): alloc error(%s)", + myname, __FILE__, __LINE__, acl_last_serror()); + } + + if (acl_vstring_vsprintf(strbuf, fmt, ap) == NULL) + acl_msg_fatal("%s, %s(%d): vsprintf return null", myname, __FILE__, __LINE__); + + n = ACL_VSTRING_LEN(strbuf); + if (n <= 0) + acl_msg_fatal("%s, %s(%d): len(%d) <= 0", myname, __FILE__, __LINE__, n); + + n = acl_vstream_writen(stream, acl_vstring_str(strbuf), n); + + acl_vstring_free(strbuf); + + return (n); +} + +int acl_vstream_fprintf(ACL_VSTREAM *stream, const char *fmt, ...) +{ + const char *myname = "acl_vstream_fprintf"; + va_list ap; + int n; + + if (stream == NULL || fmt == NULL) { + acl_msg_error("%s, %s(%d): input invalid", myname, __FILE__, __LINE__); + return (ACL_VSTREAM_EOF); + } + + va_start(ap, fmt); + n = acl_vstream_vfprintf(stream, fmt, ap); + va_end(ap); + return (n); +} + +int acl_vstream_printf(const char *fmt, ...) +{ + const char *myname = "acl_vstream_printf"; + va_list ap; + int n; + + if (fmt == NULL) { + acl_msg_error("%s, %s(%d): input invalid", myname, __FILE__, __LINE__); + return (ACL_VSTREAM_EOF); + } + + if (ACL_VSTREAM_OUT->fd.h_file == (ACL_FILE_HANDLE) -1) + acl_vstream_init(); + if (ACL_VSTREAM_OUT->fd.h_file == ACL_FILE_INVALID) { + acl_msg_error("%s, %s(%d): ACL_VSTREAM_OUT can't be inited", + myname, __FILE__, __LINE__); + return (ACL_VSTREAM_EOF); + } + va_start(ap, fmt); + n = acl_vstream_vfprintf(ACL_VSTREAM_OUT, fmt, ap); + va_end(ap); + + return (n); +} + +int acl_vstream_fputs(const char *s, ACL_VSTREAM *fp) +{ + const char *myname = "acl_vstream_fputs"; + + if (s == NULL || fp == NULL) { + acl_msg_error("%s(%d): input invalid", myname, __LINE__); + return (ACL_VSTREAM_EOF); + } + + if ((*s) != 0 && acl_vstream_buffed_fwrite(fp, s, strlen(s)) == ACL_VSTREAM_EOF) + return (ACL_VSTREAM_EOF); + if (acl_vstream_buffed_fwrite(fp, "\r\n", 2) == ACL_VSTREAM_EOF) + return (ACL_VSTREAM_EOF); + return (acl_vstream_fflush(fp) == ACL_VSTREAM_EOF ? ACL_VSTREAM_EOF : 0); +} + +int acl_vstream_puts(const char *s) +{ + const char *myname = "acl_vstream_puts"; + + if (ACL_VSTREAM_OUT->fd.h_file == (ACL_FILE_HANDLE) -1) + acl_vstream_init(); + if (ACL_VSTREAM_OUT->fd.h_file == ACL_FILE_INVALID) { + acl_msg_error("%s, %s(%d): ACL_VSTREAM_OUT can't be inited", + myname, __FILE__, __LINE__); + return (ACL_VSTREAM_EOF); + } + + return (acl_vstream_fputs(s, ACL_VSTREAM_OUT)); +} + +static int __loop_writen(ACL_VSTREAM *stream, const void *vptr, size_t dlen) +{ + const unsigned char *ptr; + int n; + + ptr = (const unsigned char *) vptr; + while (dlen > 0) { + n = __vstream_sys_write(stream, ptr, dlen); + if (n <= 0) { + if (acl_last_error() == ACL_EINTR || acl_last_error() == ACL_EAGAIN) + continue; + return (ACL_VSTREAM_EOF); + } + + dlen -= n; + ptr += n; + } + + return (ptr - (const unsigned char *) vptr); +} + +int acl_vstream_writen(ACL_VSTREAM *stream, const void *vptr, size_t dlen) +{ + if (stream == NULL || vptr == NULL || dlen <= 0) + return (ACL_VSTREAM_EOF); + + if (stream->wbuf_dlen > 0) { + if (acl_vstream_fflush(stream) == ACL_VSTREAM_EOF) + return (ACL_VSTREAM_EOF); + } + return (__loop_writen(stream, vptr, dlen)); +} + +int acl_vstream_buffed_writen(ACL_VSTREAM *stream, const void *vptr, size_t dlen) +{ + if (stream == NULL || vptr == NULL || dlen == 0) + return (ACL_VSTREAM_EOF); + + if (stream->wbuf == NULL) { + stream->wbuf_size = 8192; + stream->wbuf = acl_mymalloc(stream->wbuf_size); + } + + if (dlen >= (size_t) stream->wbuf_size) { + if (acl_vstream_fflush(stream) == ACL_VSTREAM_EOF) + return (ACL_VSTREAM_EOF); + else if (__loop_writen(stream, vptr, dlen) == ACL_VSTREAM_EOF) + return (ACL_VSTREAM_EOF); + else + return (dlen); + } else if (dlen + (size_t) stream->wbuf_dlen >= (size_t) stream->wbuf_size) { + if (acl_vstream_fflush(stream) == ACL_VSTREAM_EOF) + return (ACL_VSTREAM_EOF); + } + + memcpy(stream->wbuf + (size_t) stream->wbuf_dlen, vptr, dlen); + stream->wbuf_dlen += (int) dlen; + return(dlen); +} + +int acl_vstream_buffed_vfprintf(ACL_VSTREAM *stream, const char *fmt, va_list ap) +{ + const char *myname = "acl_vstream_buffed_vfprintf"; + ACL_VSTRING *strbuf; + int n; + + if (stream == NULL || fmt == NULL || *fmt == 0) { + acl_msg_error("%s, %s(%d): fmt invalid", myname, __FILE__, __LINE__); + return (ACL_VSTREAM_EOF); + } + + strbuf = acl_vstring_alloc(ACL_VSTREAM_BUFSIZE); + if (strbuf == NULL) { + acl_msg_fatal("%s, %s(%d): alloc error(%s)", + myname, __FILE__, __LINE__, acl_last_serror()); + } + + if (acl_vstring_vsprintf(strbuf, fmt, ap) == NULL) + acl_msg_fatal("%s, %s(%d): vsprintf return null", myname, __FILE__, __LINE__); + + n = ACL_VSTRING_LEN(strbuf); + if (n <= 0) + acl_msg_fatal("%s, %s(%d): len(%d) <= 0", myname, __FILE__, __LINE__, n); + + n = acl_vstream_buffed_writen(stream, acl_vstring_str(strbuf), n); + + acl_vstring_free(strbuf); + + return (n); +} + +int acl_vstream_buffed_fprintf(ACL_VSTREAM *stream, const char *fmt, ...) +{ + const char *myname = "acl_vstream_buffed_fprintf"; + va_list ap; + int n; + + if (stream == NULL || fmt == NULL) { + acl_msg_error("%s, %s(%d): input invalid", myname, __FILE__, __LINE__); + return (ACL_VSTREAM_EOF); + } + + va_start(ap, fmt); + n = acl_vstream_buffed_vfprintf(stream, fmt, ap); + va_end(ap); + return (n); +} + +int acl_vstream_buffed_printf(const char *fmt, ...) +{ + const char *myname = "acl_vstream_buffed_printf"; + va_list ap; + int n; + + if (fmt == NULL) { + acl_msg_error("%s, %s(%d): input invalid", myname, __FILE__, __LINE__); + return (ACL_VSTREAM_EOF); + } + + if (ACL_VSTREAM_OUT->fd.h_file == (ACL_FILE_HANDLE) -1) + acl_vstream_init(); + if (ACL_VSTREAM_OUT->fd.h_file == ACL_FILE_INVALID) { + acl_msg_error("%s, %s(%d): ACL_VSTREAM_OUT can't be inited", + myname, __FILE__, __LINE__); + return (ACL_VSTREAM_EOF); + } + va_start(ap, fmt); + n = acl_vstream_buffed_vfprintf(ACL_VSTREAM_OUT, fmt, ap); + va_end(ap); + + return (n); +} + +int acl_vstream_buffed_fputs(const char *s, ACL_VSTREAM *fp) +{ + const char *myname = "acl_vstream_buffed_fputs"; + + if (s == NULL || fp == NULL) { + acl_msg_error("%s(%d): input invalid", myname, __LINE__); + return (ACL_VSTREAM_EOF); + } + + if ((*s) != 0 && acl_vstream_buffed_fwrite(fp, s, strlen(s)) == ACL_VSTREAM_EOF) + return (ACL_VSTREAM_EOF); + if (acl_vstream_buffed_fwrite(fp, "\r\n", 2) == ACL_VSTREAM_EOF) + return (ACL_VSTREAM_EOF); + return (0); +} + +int acl_vstream_buffed_puts(const char *s) +{ + const char *myname = "acl_vstream_buffed_puts"; + + if (ACL_VSTREAM_OUT->fd.h_file == (ACL_FILE_HANDLE) -1) + acl_vstream_init(); + if (ACL_VSTREAM_OUT->fd.h_file == ACL_FILE_INVALID) { + acl_msg_error("%s, %s(%d): ACL_VSTREAM_OUT can't be inited", + myname, __FILE__, __LINE__); + return (ACL_VSTREAM_EOF); + } + + return (acl_vstream_buffed_fputs(s, ACL_VSTREAM_OUT)); +} + +int acl_vstream_fsync(ACL_VSTREAM *fp) +{ + const char *myname = "acl_vstream_fsync"; + + if (fp == NULL) { + acl_msg_error("%s(%d): fp null", myname, __LINE__); + return (ACL_VSTREAM_EOF); + } + if (fp->type != ACL_VSTREAM_TYPE_FILE) { + acl_msg_error("%s(%d): not a file stream", myname, __LINE__); + return (ACL_VSTREAM_EOF); + } + + if (acl_vstream_fflush(fp) == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): fflush fp stream's buff error(%s)", + myname, __LINE__, acl_last_serror()); + return (ACL_VSTREAM_EOF); + } + + if (acl_file_fflush(ACL_VSTREAM_FILE(fp)) < 0) { + acl_msg_error("%s(%d): fflush to disk error(%s)", + myname, __LINE__, acl_last_serror()); + return (ACL_VSTREAM_EOF); + } + + return (0); +} + +void acl_vstream_buffed_space(ACL_VSTREAM *stream) +{ + if (stream->wbuf == NULL) { + stream->wbuf_size = 8192; + stream->wbuf_dlen = 0; + stream->wbuf = acl_mymalloc(stream->wbuf_size); + } +} + +int acl_vstream_fflush(ACL_VSTREAM *stream) +{ + const char *myname = "acl_vstream_fflush"; + unsigned char *ptr; + int n; + + if (stream == NULL) { + acl_msg_error("%s(%d): stream null", myname, __LINE__); + return (ACL_VSTREAM_EOF); + } else if (stream->wbuf == NULL || stream->wbuf_dlen == 0) + return 0; + + ptr = stream->wbuf; + while (stream->wbuf_dlen > 0) { + n = __vstream_sys_write(stream, ptr, (int) stream->wbuf_dlen); + if (n <= 0) { + if (acl_last_error() == ACL_EINTR || acl_last_error() == ACL_EAGAIN) + continue; + return (ACL_VSTREAM_EOF); + } + + stream->wbuf_dlen -= n; + ptr += n; + } + + if (stream->wbuf_dlen < 0) + acl_msg_fatal("%s(%d): wbuf_dlen(%d) < 0", + myname, __LINE__, (int) stream->wbuf_dlen); + + return (ptr - stream->wbuf); +} + +int acl_vstream_peekfd(ACL_VSTREAM *stream) +{ +#ifdef ACL_UNIX + int n; + + if (stream != NULL && ACL_VSTREAM_SOCK(stream) != ACL_SOCKET_INVALID) { + n = acl_peekfd(ACL_VSTREAM_SOCK(stream)); + if (n < 0) + return (-1); + n += ACL_VSTREAM_BFRD_CNT(stream); + + return (n); + } + + return (-1); +#else + const char *myname = "acl_vstream_peekfd"; + + acl_msg_fatal("%s: not implement yet", myname); + + /* not reached */ + return (-1); +#endif /* ACL_UNIX */ +} + +ACL_VSTREAM *acl_vstream_fhopen(ACL_FILE_HANDLE fh, unsigned int oflags) +{ + const char *myname = "acl_vstream_fhopen"; + ACL_VSTREAM *fp; + + if (fh == ACL_FILE_INVALID) { + acl_msg_error("%s, %s(%d): fh invalid", myname, __FILE__, __LINE__); + return (NULL); + } + + fp = acl_vstream_fdopen(ACL_SOCKET_INVALID, oflags, 4096, 0, ACL_VSTREAM_TYPE_FILE); + if (fp == NULL) + return (NULL); + + fp->fd.h_file = fh; + return (fp); +} + + +/* 定义流的缓冲区的默认大小 */ + +#define ACL_VSTREAM_DEF_MAXLEN 8192 + +ACL_VSTREAM *acl_vstream_fdopen(ACL_SOCKET fd, unsigned int oflags, + size_t buflen, int rw_timeo, int fdtype) +{ + const char *myname = "acl_vstream_fdopen"; + ACL_VSTREAM *stream = NULL; + + stream = (ACL_VSTREAM *) acl_mycalloc(1, sizeof(ACL_VSTREAM)); + if (stream == NULL) { + acl_msg_error("%s(%d): calloc error(%s)", + myname, __LINE__, acl_last_serror()); + return (NULL); + } + + if (buflen <= 0 && !(fdtype & (ACL_VSTREAM_TYPE_LISTEN_INET + | ACL_VSTREAM_TYPE_LISTEN_UNIX))) + acl_msg_warn("%s(%d): buflen(%d) invalid", + myname, __LINE__, (int) buflen); + + if (buflen < ACL_VSTREAM_DEF_MAXLEN) + buflen = ACL_VSTREAM_DEF_MAXLEN; + + /* XXX: 只有非监听流才需要有读缓冲区 */ + + if ((fdtype & ACL_VSTREAM_TYPE_LISTEN_INET) + || (fdtype & ACL_VSTREAM_TYPE_LISTEN_UNIX)) + { + fdtype |= ACL_VSTREAM_TYPE_LISTEN; + stream->read_buf = NULL; + } else { + stream->read_buf = (unsigned char *) acl_mymalloc(buflen + 1); + if (stream->read_buf == NULL) { + acl_myfree(stream); + acl_msg_error("%s(%d): calloc error(%s)", + myname, __LINE__, acl_last_serror()); + return (NULL); + } + } + + if (fdtype == 0) { + fdtype = ACL_VSTREAM_TYPE_SOCK; + acl_msg_warn("%s(%d): fdtype(0), set to ACL_VSTREAM_TYPE_SOCK", + myname, __LINE__); + } + + stream->read_buf_len = buflen; + stream->type = fdtype; + ACL_VSTREAM_SOCK(stream) = fd; +#ifdef ACL_MS_WINDOWS + stream->iocp_sock = ACL_SOCKET_INVALID; +#endif + + stream->read_ptr = stream->read_buf; + stream->oflags = oflags; + ACL_SAFE_STRNCPY(stream->errbuf, "OK", sizeof(stream->errbuf)); + + if (rw_timeo > 0) + stream->rw_timeout = rw_timeo; + else + stream->rw_timeout = 0; + + stream->sys_getc = __sys_getc; + if (fdtype == ACL_VSTREAM_TYPE_FILE) { + stream->fread_fn = acl_file_read; + stream->fwrite_fn = acl_file_write; + stream->fwritev_fn = acl_file_writev; + stream->fclose_fn = acl_file_close; + } else { + stream->read_fn = acl_socket_read; + stream->write_fn = acl_socket_write; + stream->writev_fn = acl_socket_writev; + stream->close_fn = acl_socket_close; + } + + stream->path = stream->remote_addr; /* default */ + + stream->close_handle_lnk = acl_array_create(5); + if (stream->close_handle_lnk == NULL) { + acl_myfree(stream->read_buf); + acl_myfree(stream); + acl_msg_error("%s, %s(%d): acl_array_create error=%s", + myname, __FILE__, __LINE__, acl_last_serror()); + return (NULL); + } + + return (stream); +} + +ACL_VSTREAM *acl_vstream_clone(const ACL_VSTREAM *stream_src) +{ + const char *myname = "acl_vstream_clone"; + ACL_VSTREAM *stream_obj; + ACL_VSTREAM_CLOSE_HANDLE *handle_from, *handle_to; + int i, n; + + stream_obj = (ACL_VSTREAM *) acl_mycalloc(1, sizeof(ACL_VSTREAM)); + if (stream_obj == NULL) + return (NULL); + + memcpy(stream_obj, stream_src, sizeof(ACL_VSTREAM)); + + stream_obj->read_buf = (unsigned char *) acl_mymalloc((int) stream_obj->read_buf_len + 1); + if (stream_obj->read_buf == NULL) { + acl_myfree(stream_obj); + return (NULL); + } + memcpy(stream_obj->read_buf, stream_src->read_buf, (size_t) stream_obj->read_buf_len); + stream_obj->read_ptr = stream_obj->read_buf + + (stream_src->read_ptr - stream_src->read_buf); + + stream_obj->path = stream_obj->remote_addr; /* default */ + ACL_SAFE_STRNCPY(stream_obj->remote_addr, stream_src->remote_addr, sizeof(stream_obj->remote_addr)); + + stream_obj->ioctl_read_ctx = NULL; + stream_obj->ioctl_write_ctx = NULL; + stream_obj->fdp = NULL; + + stream_obj->context = stream_src->context; + + stream_obj->close_handle_lnk = acl_array_create(5); + if (stream_obj->close_handle_lnk == NULL) { + acl_msg_fatal("%s, %s(%d): acl_array_create error=%s", + myname, __FILE__, __LINE__, acl_last_serror()); + } + + if (stream_src->close_handle_lnk == NULL) + return (stream_obj); + + n = acl_array_size(stream_src->close_handle_lnk); + for (i = 0; i < n; i++) { + handle_from = (ACL_VSTREAM_CLOSE_HANDLE *) + acl_array_index(stream_src->close_handle_lnk, i); + if (handle_from == NULL) + continue; + if (handle_from->close_fn == NULL) + continue; + + handle_to = (ACL_VSTREAM_CLOSE_HANDLE *) + acl_mycalloc(1, sizeof(ACL_VSTREAM_CLOSE_HANDLE)); + if (handle_to == NULL) + acl_msg_fatal("%s, %s(%d): calloc error=%s", + myname, __FILE__, __LINE__, acl_last_serror()); + handle_to->close_fn = handle_from->close_fn; + handle_to->context = handle_from->context; + + if (acl_array_append(stream_obj->close_handle_lnk, handle_to) < 0) + acl_msg_fatal("%s, %s(%d): acl_array_append error=%s", + myname, __FILE__, __LINE__, + acl_last_serror()); + } + + return (stream_obj); +} + +int acl_vstream_set_fdtype(ACL_VSTREAM *stream, int type) +{ + if (type == ACL_VSTREAM_TYPE_FILE) { + stream->fread_fn = acl_file_read; + stream->fwrite_fn = acl_file_write; + stream->fclose_fn = acl_file_close; + } else if (type == ACL_VSTREAM_TYPE_SOCK) { + stream->read_fn = acl_socket_read; + stream->write_fn = acl_socket_write; + stream->close_fn = acl_socket_close; + } + + return (-1); +} +/* acl_vstream_fopen - open buffered file stream */ + +ACL_VSTREAM *acl_vstream_fopen(const char *path, unsigned int oflags, int mode, size_t buflen) +{ + ACL_VSTREAM *fp; + ACL_FILE_HANDLE fh; + + /* for linux2.6 */ +#ifdef _LARGEFILE64_SOURCE + oflags |= O_LARGEFILE; +#endif + +#ifdef ACL_MS_WINDOWS + oflags |= O_BINARY; +#endif + + fh = acl_file_open(path, oflags, mode); + + if (fh == ACL_FILE_INVALID) + return (NULL); + + fp = acl_vstream_fdopen(ACL_SOCKET_INVALID, oflags, buflen, 0, ACL_VSTREAM_TYPE_FILE); + if (fp == NULL) + return (NULL); + + fp->fd.h_file = fh; + ACL_SAFE_STRNCPY(fp->remote_addr, path, sizeof(fp->remote_addr)); + return (fp); +} + +char *acl_vstream_loadfile(const char *path) +{ + return (acl_vstream_loadfile2(path, NULL)); +} + +char *acl_vstream_loadfile2(const char *path, ssize_t *size) +{ + const char *myname = "acl_vstream_loadfile"; + ACL_VSTREAM *fp; +#ifdef ACL_MS_WINDOWS + int oflags = O_RDONLY | O_BINARY; +#else + int oflags = O_RDONLY; +#endif + int mode = S_IREAD; + int ret; + ACL_VSTRING *vbuf; + unsigned char buf[4096]; + + if (size) + *size = -1; + + if (path == NULL || *path == 0) { + acl_msg_error("%s, %s(%d):path invalid", myname, __FILE__, __LINE__); + return (NULL); + } + + fp = acl_vstream_fopen(path, oflags, mode, 4096); + if (fp == NULL) { + acl_msg_error("%s, %s(%d): open file(%s) error(%s)", + myname, __FILE__, __LINE__, + path, acl_last_serror()); + return (NULL); + } + + vbuf = acl_vstring_alloc(1024); + if (buf == NULL) { + acl_msg_error("%s, %s(%d): alloc vstring error(%s)", + myname, __FILE__, __LINE__, + acl_last_serror()); + acl_vstream_close(fp); + return (NULL); + } + + while (1) { + ret = acl_vstream_read(fp, buf, sizeof(buf)); + if (ret == ACL_VSTREAM_EOF) + break; + acl_vstring_memcat(vbuf, (char *) buf, ret); + } + + if (size) + *size = (ssize_t) ACL_VSTRING_LEN(vbuf); + acl_vstream_close(fp); + ACL_VSTRING_TERMINATE(vbuf); + return (acl_vstring_export(vbuf)); +} + +/* acl_vstream_ctl - fine control */ + +void acl_vstream_ctl(ACL_VSTREAM *stream, int name,...) +{ + const char *myname = "acl_vstream_ctl"; + va_list ap; + int n; + char *ptr; + + va_start(ap, name); + for (; name != ACL_VSTREAM_CTL_END; name = va_arg(ap, int)) { + switch (name) { + case ACL_VSTREAM_CTL_READ_FN: + stream->read_fn = va_arg(ap, ACL_VSTREAM_RD_FN); + break; + case ACL_VSTREAM_CTL_WRITE_FN: + stream->write_fn = va_arg(ap, ACL_VSTREAM_WR_FN); + break; + case ACL_VSTREAM_CTL_CONTEXT: + stream->context = va_arg(ap, char *); + break; + case ACL_VSTREAM_CTL_PATH: + ptr = va_arg(ap, char*); + ACL_SAFE_STRNCPY(stream->remote_addr, + ptr, sizeof(stream->remote_addr)); + break; + case ACL_VSTREAM_CTL_FD: + ACL_VSTREAM_SOCK(stream) = va_arg(ap, ACL_SOCKET); + break; + case ACL_VSTREAM_CTL_TIMEOUT: + stream->rw_timeout = va_arg(ap, int); + break; + case ACL_VSTREAM_CTL_CACHE_SEEK: + n = va_arg(ap, int); + if (n) { + stream->flag |= ACL_VSTREAM_FLAG_CACHE_SEEK; + } else { + stream->flag &= ~ACL_VSTREAM_FLAG_CACHE_SEEK; + } + break; + default: + acl_msg_panic("%s, %s(%d): bad name %d", + myname, __FILE__, __LINE__, name); + } + } + va_end(ap); +} + +acl_off_t acl_vstream_fseek2(ACL_VSTREAM *stream, acl_off_t offset, int whence) +{ + const char *myname = "acl_vstream_fseek2"; + acl_off_t n; + + if (stream == NULL || ACL_VSTREAM_FILE(stream) == ACL_FILE_INVALID) + acl_msg_fatal("%s, %s(%d): input error", myname, __FILE__, __LINE__); + + if (stream->type != ACL_VSTREAM_TYPE_FILE) { + acl_msg_error("%s, %s(%d): stream->type(%d) not ACL_VSTREAM_TYPE_FILE", + myname, __FILE__, __LINE__, stream->type); + return (-1); + } + + if (stream->wbuf_dlen > 0) { + if (acl_vstream_fflush(stream) == ACL_VSTREAM_EOF) { + acl_msg_error("%s, %s(%d): acl_vstream_fflush error", + myname, __FILE__, __LINE__); + return (-1); + } + } + + if ((stream->flag & ACL_VSTREAM_FLAG_CACHE_SEEK) == 0) { + stream->read_cnt = 0; + goto SYS_SEEK2; + } + + /* 获得真正的当前文件指针位置 */ + n = acl_lseek(ACL_VSTREAM_FILE(stream), (acl_off_t) 0, SEEK_CUR); + if (n < 0) + return (-1); + + if (whence == SEEK_CUR) { + if (stream->read_cnt >= offset) { + stream->read_cnt -= (int) offset; + n = -stream->read_cnt; /* 计算出真实的文件位置 */ + stream->read_cnt = 0; + } else if (stream->read_cnt >= 0) { + offset -= stream->read_cnt; + n = offset; /* 计算出真实的文件位置 */ + stream->read_cnt = 0; + } else { /* stream->read_cnt < 0 ? */ + acl_msg_fatal("%s, %s(%d): invalud read_cnt = %d", + myname, __FILE__, __LINE__, (int) stream->read_cnt); + } + } else { + n = offset; + stream->read_cnt = 0; + } + +SYS_SEEK2: + /* 定位到合适的位置 */ + stream->sys_offset = acl_lseek(ACL_VSTREAM_FILE(stream), offset, whence); + stream->offset = stream->sys_offset; + return (stream->offset); +} + +acl_off_t acl_vstream_fseek(ACL_VSTREAM *stream, acl_off_t offset, int whence) +{ + const char *myname = "acl_vstream_fseek"; + acl_off_t n; + + if (stream == NULL || ACL_VSTREAM_FILE(stream) == ACL_FILE_INVALID) + acl_msg_fatal("%s, %s(%d): input error", myname, __FILE__, __LINE__); + + if (stream->type != ACL_VSTREAM_TYPE_FILE) { + acl_msg_error("%s, %s(%d): stream->type(%d) not ACL_VSTREAM_TYPE_FILE", + myname, __FILE__, __LINE__, stream->type); + return (-1); + } + + if (stream->wbuf_dlen > 0) { + if (acl_vstream_fflush(stream) == ACL_VSTREAM_EOF) { + acl_msg_error("%s, %s(%d): acl_vstream_fflush error", + myname, __FILE__, __LINE__); + return (-1); + } + } + + if ((stream->flag & ACL_VSTREAM_FLAG_CACHE_SEEK) == 0) { + stream->read_cnt = 0; + goto SYS_SEEK; + } + + if (whence == SEEK_CUR) { + /* 相对当前流位置 stream->offset 开始偏移 offset 的位置 */ + + /* 必须严格检验 */ + if (stream->offset + stream->read_cnt != stream->sys_offset) { + acl_msg_error("%s, %s(%d): offset(" ACL_FMT_I64D + ") + read_cnt(%d) != sys_offset(" + ACL_FMT_I64D ")", myname, __FILE__, __LINE__, + stream->offset, stream->read_cnt, stream->sys_offset); + stream->read_cnt = 0; + goto SYS_SEEK; + } + + /* 是否在读缓冲区间内 */ + if (stream->read_cnt >= offset) { + /* 因为要从 stream->offset 偏移 offset 个字节后, 读指针 + * stream->read_ptr 依然在缓冲区内, 所以只需要移动读指针 + * 且减少缓冲区字节数、增加 stream->offset 偏移量即可. + */ + stream->read_cnt -= (int) offset; + stream->read_ptr += (int) offset; + stream->offset += offset; + return (stream->offset); + } else if (stream->read_cnt >= 0) { + /* 因为要计算从当前流位置 stream->offset 开始偏移 offset 的位置, + * 而且流中还存在一定的缓存数据(stream->read_cnt), 所以需要先从 + * stream->offset 开始移动 stream->read_cnt 个字节(移动出读缓冲区), + * 然后再移动剩余的字节(即 offset - stream->read_cnt) 即可; 因为 + * 已经称出读缓冲区,所以需要将 stream->read_cnt 置 0. + */ + offset -= stream->read_cnt; + stream->read_cnt = 0; + } else { /* stream->read_cnt < 0 ? */ + acl_msg_error("%s, %s(%d): invalud read_cnt = %d", + myname, __FILE__, __LINE__, (int) stream->read_cnt); + stream->read_cnt = 0; + } + } else if (whence == SEEK_SET) { +#if 0 + /* 获得真正的当前文件指针位置 */ + stream->sys_offset = acl_lseek(ACL_VSTREAM_FILE(stream), (off_t) 0, SEEK_CUR); +#endif + /* 利用缓存的偏移位置 */ + + if (stream->sys_offset < 0) { + acl_msg_error("%s, %s(%d): seek n(" ACL_FMT_I64D ") invalid", + myname, __FILE__, __LINE__, stream->sys_offset); + stream->read_cnt = 0; + goto SYS_SEEK; + } + + /* 必须严格检验 */ + if (stream->offset + stream->read_cnt != stream->sys_offset) { + acl_msg_error("%s, %s(%d): offset(" ACL_FMT_I64D + ") + read_cnt(%d) != sys_offset(" + ACL_FMT_I64D ")", myname, __FILE__, __LINE__, + stream->offset, stream->read_cnt, stream->sys_offset); + stream->read_cnt = 0; + goto SYS_SEEK; + } + + /* 如果读数据指针经过移动,可以将其回移,因为缓冲区内数据并未破坏,可以复用 */ + if (stream->read_ptr > stream->read_buf) { + n = stream->read_ptr - stream->read_buf; + stream->offset -= n; + stream->read_ptr = stream->read_buf; + stream->read_cnt += (int) n; + } + + /* 判断请求的偏移位置是否在读缓存区间内 */ + if (offset >= stream->offset && offset <= stream->sys_offset) { + n = offset - stream->offset; + stream->read_cnt -= (int) n; + stream->read_ptr += n; + stream->offset += n; + return (stream->offset); + } + stream->read_cnt = 0; + } else + stream->read_cnt = 0; + +SYS_SEEK: + /* 调用系统调用定位位置 */ + stream->sys_offset = acl_lseek(ACL_VSTREAM_FILE(stream), offset, whence); + stream->offset = stream->sys_offset; + + return (stream->offset); +} + +#ifdef ACL_MS_WINDOWS +int acl_file_ftruncate(ACL_VSTREAM *fp, acl_off_t length) +{ + const char *myname = "acl_file_ftruncate"; + ACL_FILE_HANDLE hf = ACL_VSTREAM_FILE(fp); + + /* 参见:C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\crt\src + * osfinfo.c + * _open_osfhandle: 将WIN32 API的文件句柄转换为标准C的文件句柄 + * _get_osfhandle: 根据标准C文件句柄查询WIN32 API文件句柄 + * _free_osfhnd: 释放由 _open_osfhandle 打开的标准C文件句柄的资源, + * 但并不实际关闭该WIN32 API句柄,所以还得要对其真实 + * WIN32 API文件句柄进行关闭 + * close.c + * _close: 关闭并释放标准C的文件句柄 + */ + + if (acl_vstream_fseek(fp, length, SEEK_SET) < 0) { + acl_msg_error("%s, %s(%d): fseek error(%s)", + myname, __FILE__, __LINE__, acl_last_serror()); + return (-1); + } + + if (!SetEndOfFile(hf)) { + acl_msg_error("%s, %s(%d): SetEndOfFile error(%s)", + myname, __FILE__, __LINE__, acl_last_serror()); + return (-1); + } + + if (acl_vstream_fseek(fp, 0, SEEK_SET) < 0) { + acl_msg_error("%s, %s(%d): fseek error(%s)", + myname, __FILE__, __LINE__, acl_last_serror()); + return (-1); + } + + return (0); +} + +int acl_file_truncate(const char *path, acl_off_t length) +{ + const char *myname = "acl_file_truncate"; + ACL_VSTREAM* fp; + + fp = acl_vstream_fopen(path, O_WRONLY | O_BINARY | O_CREAT, 0600, 1024); + if (fp == NULL) { + acl_msg_error("%s, %s(%d): fopen file(%s) error(%s)", + myname, __FILE__, __LINE__, path, acl_last_serror()); + return (-1); + } + + if (acl_file_ftruncate(fp, length) < 0) { + acl_vstream_close(fp); + return (-1); + } + acl_vstream_close(fp); + return (0); +} +#elif defined(ACL_UNIX) +int acl_file_ftruncate(ACL_VSTREAM *fp, acl_off_t length) +{ + ACL_FILE_HANDLE hf = ACL_VSTREAM_FILE(fp); + + return (ftruncate(hf, length)); +} + +int acl_file_truncate(const char *path, acl_off_t length) +{ + return (truncate(path, length)); +} +#endif /* !ACL_MS_WINDOWS, ACL_UNIX */ + +int acl_vstream_fstat(ACL_VSTREAM *fp, struct acl_stat *buf) +{ + const char *myname = "acl_vstream_fstat"; + + if (fp == NULL || buf == NULL) { + acl_msg_error("%s(%d): input invalid", myname, __LINE__); + return (-1); + } else if (fp->type != ACL_VSTREAM_TYPE_FILE) { + acl_msg_error("%s(%d): not a file stream", myname, __LINE__); + return (-1); + } + + return (acl_fstat(ACL_VSTREAM_FILE(fp), buf)); +} + +acl_int64 acl_vstream_fsize(ACL_VSTREAM *fp) +{ + const char *myname = "acl_vstream_fsize"; + + if (fp == NULL) { + acl_msg_error("%s(%d): fp null", myname, __LINE__); + return (-1); + } else if (fp->type != ACL_VSTREAM_TYPE_FILE) { + acl_msg_error("%s(%d): not a file stream", myname, __LINE__); + return (-1); + } + return (acl_file_fsize(ACL_VSTREAM_FILE(fp)) + fp->wbuf_dlen); +} + +void acl_vstream_reset(ACL_VSTREAM *stream) +{ + if (stream) { + stream->read_cnt = 0; + stream->read_ptr = stream->read_buf; + stream->flag = ACL_VSTREAM_FLAG_RW; + stream->total_read_cnt = 0; + stream->total_write_cnt = 0; + stream->sys_read_ready = 0; + stream->wbuf_dlen = 0; + stream->offset = 0; + stream->nrefer = 0; + stream->read_buf_len = 0; + ACL_SAFE_STRNCPY(stream->errbuf, "OK", sizeof(stream->errbuf)); + acl_vstream_clean_close_handle(stream); + if (stream->fdp != NULL) + event_fdtable_reset(stream->fdp); + } +} + +void acl_vstream_free(ACL_VSTREAM *stream) +{ + if (stream->nrefer > 0) { + /* 设置延迟释放标志位 */ + stream->flag |= ACL_VSTREAM_FLAG_DEFER_FREE; + return; + } + + if (stream->close_handle_lnk != NULL) { + ACL_VSTREAM_CLOSE_HANDLE *close_handle; + int i, n = acl_array_size(stream->close_handle_lnk); + + /* 因为添加时是正序的, 所以在删除时是倒序的, + * 这样对动态数组的使用的效率才会比较高, + * 避免了动态数组内部移动的情况 + */ + for (i = n - 1; i >= 0; i++) { + close_handle = (ACL_VSTREAM_CLOSE_HANDLE *) + acl_array_index(stream->close_handle_lnk, i); + if (close_handle == NULL) + break; + if (close_handle->close_fn == NULL) + continue; + /* 只所将此调用放在 close_fn 前面,是为了防止有人误在 close_fn + * 里调用了删除回调函数的操作而造成对同一内存的多次释放 + */ + acl_array_delete_idx(stream->close_handle_lnk, i, NULL); + close_handle->close_fn(stream, close_handle->context); + acl_myfree(close_handle); + } + acl_array_destroy(stream->close_handle_lnk, NULL); + } + + if (stream->fdp != NULL) + event_fdtable_free(stream->fdp); + if (stream->read_buf != NULL) + acl_myfree(stream->read_buf); + if (stream->wbuf != NULL) + acl_myfree(stream->wbuf); + + acl_myfree(stream); +} + +int acl_vstream_close(ACL_VSTREAM *stream) +{ + int ret = 0; + + if (stream->nrefer > 0) { + /* 设置延迟释放标志位 */ + stream->flag |= ACL_VSTREAM_FLAG_DEFER_FREE; + return (0); + } + + if (stream->wbuf_dlen > 0) { + if (acl_vstream_fflush(stream) == ACL_VSTREAM_EOF) { + acl_msg_error("acl_vstream_close: fflush stream error"); + } + } + + /* 必须在调用各个关闭回调函数之前将连接关闭,否则会影响 iocp 的事件引擎 + * 的正常工作。在使用 iocp 作为事件引擎时,当流关闭时会调用 events_iocp.c + * 中的 stream_on_close,该函数会释放掉 fdp->event_read/fdp->event_write + * 两个对象,但当套接口未关闭时,这两个对象有可能会被 iocp 使用时,只有 + * 当套接口关闭时,iocp 才不会使用这两个对象中的 IOCP_EVENT->overlapped 等 + * 成员. ---2011.5.18, zsx + */ + /* + * 2011.5.18 的改动虽然解决了事件引擎为 iocp 的问题,但同时造成了 win32 + * 窗口消息引擎的问题,虽然 win32 消息引擎的方式在关闭套接口之前会回调 + * stream_on_close,而该回调要求套接口必须是打开的,既然二者出现了冲突, + * 则 iocp 的问题还是由 iocp 引擎本身去解决吧,即在 iocp 引擎的 + * stream_on_close 中,在释放 fdp->event_read/fdp->event_write 之前关闭 + * 套接口即可,在 acl_vstream_close 最后需要关闭套接口时只要根据句柄是否 + * 有效来判断是否调用关闭过程. ---2011.5.19, zsx + */ + /* + if (stream->read_buf != NULL) + acl_myfree(stream->read_buf); + if (ACL_VSTREAM_SOCK(stream) != ACL_SOCKET_INVALID && stream->close_fn) + ret = stream->close_fn(ACL_VSTREAM_SOCK(stream)); + else if (ACL_VSTREAM_FILE(stream) != ACL_FILE_INVALID && stream->fclose_fn) + ret = stream->fclose_fn(ACL_VSTREAM_FILE(stream)); + ACL_VSTREAM_SOCK(stream) = ACL_SOCKET_INVALID; + ACL_VSTREAM_FILE(stream) = ACL_FILE_INVALID; + */ + + if (stream->close_handle_lnk != NULL) { + ACL_VSTREAM_CLOSE_HANDLE *close_handle; + int i, n = acl_array_size(stream->close_handle_lnk); + + /* 因为添加时是正序的, 所以在删除时是倒序的, + * 这样对动态数组的使用的效率才会比较高, + * 避免了动态数组内部移动的情况 + */ + for (i = n - 1; i >= 0; i--) { + close_handle = (ACL_VSTREAM_CLOSE_HANDLE *) + acl_array_index(stream->close_handle_lnk, i); + if (close_handle == NULL) + continue; + if (close_handle->close_fn == NULL) + continue; + /* 只所将此调用放在 close_fn 前面,是为了防止有人误在 close_fn + * 里调用了删除回调函数的操作而造成对同一内存的多次释放 + */ + acl_array_delete_idx(stream->close_handle_lnk, i, NULL); + close_handle->close_fn(stream, close_handle->context); + acl_myfree(close_handle); + } + acl_array_destroy(stream->close_handle_lnk, NULL); + } + + if (ACL_VSTREAM_SOCK(stream) != ACL_SOCKET_INVALID && stream->close_fn) + ret = stream->close_fn(ACL_VSTREAM_SOCK(stream)); + else if (ACL_VSTREAM_FILE(stream) != ACL_FILE_INVALID && stream->fclose_fn) + ret = stream->fclose_fn(ACL_VSTREAM_FILE(stream)); + + if (stream->fdp != NULL) + event_fdtable_free(stream->fdp); + if (stream->read_buf != NULL) + acl_myfree(stream->read_buf); + if (stream->wbuf != NULL) + acl_myfree(stream->wbuf); + + acl_myfree(stream); + return (ret); +} + +void acl_vstream_call_close_handles(ACL_VSTREAM *stream) +{ + if (stream->close_handle_lnk != NULL) { + ACL_VSTREAM_CLOSE_HANDLE *close_handle; + int i, n = acl_array_size(stream->close_handle_lnk); + + /* 因为添加时是正序的, 所以在删除时是倒序的, + * 这样对动态数组的使用的效率才会比较高, + * 避免了动态数组内部移动的情况 + */ + for (i = n - 1; i >= 0; i--) { + close_handle = (ACL_VSTREAM_CLOSE_HANDLE *) + acl_array_index(stream->close_handle_lnk, i); + if (close_handle == NULL) + continue; + if (close_handle->close_fn == NULL) + continue; + /* 只所将此调用放在 close_fn 前面,是为了防止有人误在 close_fn + * 里调用了删除回调函数的操作而造成对同一内存的多次释放 + */ + acl_array_delete_idx(stream->close_handle_lnk, i, NULL); + close_handle->close_fn(stream, close_handle->context); + acl_myfree(close_handle); + } + acl_array_clean(stream->close_handle_lnk, NULL); + } +} + +void acl_vstream_add_close_handle(ACL_VSTREAM *stream, + void (*close_fn)(ACL_VSTREAM*, void*), void *context) +{ + const char *myname = "acl_vstream_add_close_handle"; + ACL_VSTREAM_CLOSE_HANDLE *close_handle; + ACL_ITER iter; + + if (stream == NULL) + acl_msg_fatal("%s, %s(%d): stream null", + myname, __FILE__, __LINE__); + if (stream->close_handle_lnk == NULL) + acl_msg_fatal("%s, %s(%d): close_handle_lnk null", + myname, __FILE__, __LINE__); + if (close_fn == NULL) + acl_msg_fatal("%s, %s(%d): close_fn null", + myname, __FILE__, __LINE__); + + acl_foreach(iter, stream->close_handle_lnk) { + close_handle = (ACL_VSTREAM_CLOSE_HANDLE*) iter.data; + if (close_handle->close_fn == close_fn + && close_handle->context == context) + { + return; + } + } + + close_handle = (ACL_VSTREAM_CLOSE_HANDLE *) + acl_mycalloc(1, sizeof(ACL_VSTREAM_CLOSE_HANDLE)); + if (close_handle == NULL) { + acl_msg_fatal("%s, %s(%d): calloc error=%s", + myname, __FILE__, __LINE__, acl_last_serror()); + } + close_handle->close_fn = close_fn; + close_handle->context = context; + + if (acl_array_append(stream->close_handle_lnk, close_handle) < 0) + acl_msg_fatal("%s, %s(%d): acl_array_append error=%s", + myname, __FILE__, __LINE__, acl_last_serror()); +} + +void acl_vstream_delete_close_handle(ACL_VSTREAM *stream, + void (*close_fn)(ACL_VSTREAM*, void*), void *context) +{ + const char *myname = "acl_vstream_delete_close_handle"; + ACL_VSTREAM_CLOSE_HANDLE *close_handle; + int i, n; + + if (stream == NULL) { + acl_msg_error("%s(%d): stream null", myname, __LINE__); + return; + } + if (stream->close_handle_lnk == NULL) { + acl_msg_error("%s(%d): close_handle_lnk null", myname, __LINE__); + return; + } + if (close_fn == NULL) { + acl_msg_error("%s(%d): close_fn null", myname, __LINE__); + return; + } + + n = acl_array_size(stream->close_handle_lnk); + if (n <= 0) + return; + + /* 因为添加时是正序的, 所以在删除时是倒序的, + * 这样对动态数组的使用的效率才会比较高, + * 避免了动态数组内部移动的情况 + */ + for (i = n - 1; i >= 0; i--) { + close_handle = (ACL_VSTREAM_CLOSE_HANDLE *) + acl_array_index(stream->close_handle_lnk, i); + if (close_handle == NULL) + continue; + if (close_handle->close_fn == close_fn + && close_handle->context == context) { + acl_array_delete_idx(stream->close_handle_lnk, i, NULL); + acl_myfree(close_handle); + break; + } + } +} + +void acl_vstream_clean_close_handle(ACL_VSTREAM *stream) +{ + int i, n; + ACL_VSTREAM_CLOSE_HANDLE *close_handle; + + if (stream == NULL || stream->close_handle_lnk == NULL) + return; + + n = acl_array_size(stream->close_handle_lnk); + /* 因为添加时是正序的, 所以在删除时是倒序的, + * 这样对动态数组的使用的效率才会比较高, + * 避免了动态数组内部移动的情况 + */ + for (i = n - 1; i >= 0; i++) { + close_handle = (ACL_VSTREAM_CLOSE_HANDLE *) + acl_array_index(stream->close_handle_lnk, i); + acl_array_delete_idx(stream->close_handle_lnk, i, NULL); + acl_myfree(close_handle); + } + + acl_array_clean(stream->close_handle_lnk, NULL); +} + +const char *acl_vstream_strerror(ACL_VSTREAM *stream) +{ + static char err[] = "input error"; + + if (stream == NULL) + return (err); + + return (stream->errbuf); +} diff --git a/lib_acl/src/stdlib/acl_vstream_popen.c b/lib_acl/src/stdlib/acl_vstream_popen.c new file mode 100644 index 000000000..1f2de0c59 --- /dev/null +++ b/lib_acl/src/stdlib/acl_vstream_popen.c @@ -0,0 +1,405 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include "stdlib/acl_vstream.h" +#include "stdlib/acl_msg.h" +#include +#include + +#include "stdlib/acl_argv.h" +#include "stdlib/acl_iostuff.h" +#include "stdlib/unix/acl_set_ugid.h" +#include "stdlib/acl_env.h" +#include "stdlib/acl_exec_command.h" +#include "stdlib/acl_vstream_popen.h" + +#ifdef ACL_UNIX +#include +#include +#endif + +#endif + +/* Application-specific. */ + +#ifdef ACL_UNIX +typedef int (*ACL_VSTREAM_WAITPID_FN) (pid_t, ACL_WAIT_STATUS_T *, int); +#endif + +typedef struct ACL_VSTREAM_POPEN_ARGS { + char **argv; + char *command; + int privileged; + char **env; + char **export; + char *shell; +#ifdef ACL_UNIX + uid_t uid; + gid_t gid; + ACL_VSTREAM_WAITPID_FN waitpid_fn; +#endif +} ACL_VSTREAM_POPEN_ARGS; + +/* vstream_parse_args - get arguments from variadic list */ + +static void vstream_parse_args(ACL_VSTREAM_POPEN_ARGS *args, va_list ap) +{ + const char *myname = "vstream_parse_args"; + int key; + + /* + * First, set the default values (on all non-zero entries) + */ + args->argv = 0; + args->command = 0; + args->privileged = 0; + args->env = 0; + args->export = 0; + args->shell = 0; +#ifdef ACL_UNIX + args->uid = 0; + args->gid = 0; + args->waitpid_fn = 0; +#endif + + /* + * Then, override the defaults with user-supplied inputs. + */ + while ((key = va_arg(ap, int)) != ACL_VSTREAM_POPEN_END) { + switch (key) { + case ACL_VSTREAM_POPEN_ARGV: + if (args->command != 0) + acl_msg_panic("%s: got ACL_VSTREAM_POPEN_ARGV" + " and ACL_VSTREAM_POPEN_COMMAND", myname); + args->argv = va_arg(ap, char **); + break; + case ACL_VSTREAM_POPEN_COMMAND: + if (args->argv != 0) + acl_msg_panic("%s: got ACL_VSTREAM_POPEN_ARGV" + " and ACL_VSTREAM_POPEN_COMMAND", myname); + args->command = va_arg(ap, char *); + break; + case ACL_VSTREAM_POPEN_ENV: + args->env = va_arg(ap, char **); + break; + case ACL_VSTREAM_POPEN_EXPORT: + args->export = va_arg(ap, char **); + break; + case ACL_VSTREAM_POPEN_SHELL: + args->shell = va_arg(ap, char *); + break; +#ifdef ACL_UNIX + case ACL_VSTREAM_POPEN_UID: + args->privileged = 1; + args->uid = va_arg(ap, uid_t); + break; + case ACL_VSTREAM_POPEN_GID: + args->privileged = 1; + args->gid = va_arg(ap, gid_t); + break; + case ACL_VSTREAM_POPEN_WAITPID_FN: + args->waitpid_fn = va_arg(ap, ACL_VSTREAM_WAITPID_FN); + break; +#endif + default: + acl_msg_panic("%s: unknown key: %d", myname, key); + } + } + + if (args->command == 0 && args->argv == 0) + acl_msg_panic("%s: missing ACL_VSTREAM_POPEN_ARGV" + " or ACL_VSTREAM_POPEN_COMMAND", myname); +#ifdef ACL_UNIX + if (args->privileged != 0 && args->uid == 0) + acl_msg_panic("%s: privileged uid", myname); + if (args->privileged != 0 && args->gid == 0) + acl_msg_panic("%s: privileged gid", myname); +#endif +} + +#ifdef ACL_UNIX + +/* acl_vstream_popen - open stream to child process */ + +ACL_VSTREAM *acl_vstream_popen(int flags,...) +{ + const char *myname = "acl_vstream_popen"; + ACL_VSTREAM_POPEN_ARGS args; + va_list ap; + ACL_VSTREAM *stream; + int sockfd[2]; + int pid; + int fd; + ACL_ARGV *argv; + char **cpp; + + va_start(ap, flags); + vstream_parse_args(&args, ap); + va_end(ap); + + if (args.command == 0) + args.command = args.argv[0]; + + if (acl_duplex_pipe(sockfd) < 0) + return (0); + + switch (pid = fork()) { + case -1: /* error */ + (void) close(sockfd[0]); + (void) close(sockfd[1]); + return (0); + case 0: /* child */ + if (close(sockfd[1])) + acl_msg_warn("close: %s", acl_last_serror()); + for (fd = 0; fd < 2; fd++) + if (sockfd[0] != fd && DUP2(sockfd[0], fd) < 0) + acl_msg_fatal("dup2: %s", acl_last_serror()); + if (sockfd[0] >= 2 && close(sockfd[0])) + acl_msg_warn("close: %s", acl_last_serror()); + + /* + * Don't try to become someone else unless the user specified it. + */ + if (args.privileged) + acl_set_ugid(args.uid, args.gid); + + /* + * Environment plumbing. Always reset the command search path. XXX + * That should probably be done by clean_env(). + */ + if (args.export) + acl_clean_env(args.export); + if (setenv("PATH", ACL_PATH_DEFPATH, 1)) + acl_msg_fatal("%s: setenv: %s", myname, acl_last_serror()); + if (args.env) + for (cpp = args.env; *cpp; cpp += 2) + if (setenv(cpp[0], cpp[1], 1)) + acl_msg_fatal("setenv: %s", acl_last_serror()); + + /* + * Process plumbing. If possible, avoid running a shell. + */ + acl_msg_close(); + if (args.argv) { + execvp(args.argv[0], args.argv); + acl_msg_fatal("%s: execvp %s: %s", + myname, args.argv[0], acl_last_serror()); + } else if (args.shell && *args.shell) { + argv = acl_argv_split(args.shell, " \t\r\n"); + acl_argv_add(argv, args.command, (char *) 0); + acl_argv_terminate(argv); + execvp(argv->argv[0], argv->argv); + acl_msg_fatal("%s: execvp %s: %s", + myname, argv->argv[0], acl_last_serror()); + } else { + acl_exec_command(args.command); + } + /* NOTREACHED */ + default: /* parent */ + if (close(sockfd[0])) + acl_msg_warn("close: %s", acl_last_serror()); + stream = acl_vstream_fdopen(sockfd[1], flags, + 4096, 0, ACL_VSTREAM_TYPE_FILE); + /* + * stream->waitpid_fn = args.waitpid_fn; + */ + stream->pid = pid; + return (stream); + } +} + +/* acl_vstream_pclose - close stream to child process */ + +int acl_vstream_pclose(ACL_VSTREAM *stream) +{ + pid_t saved_pid = stream->pid; + /* + * ACL_VSTREAM_WAITPID_FN saved_waitpid_fn = stream->waitpid_fn; + */ + ACL_VSTREAM_WAITPID_FN saved_waitpid_fn = 0; + pid_t pid; + ACL_WAIT_STATUS_T wait_status; + + /* + * Close the pipe. Don't trigger an alarm in vstream_fclose(). + */ + if (saved_pid == 0) + acl_msg_panic("vstream_pclose: stream has no process"); + stream->pid = 0; + acl_vstream_fclose(stream); + + /* + * Reap the child exit status. + */ + do { + if (saved_waitpid_fn != 0) + pid = saved_waitpid_fn(saved_pid, &wait_status, 0); + else + pid = waitpid(saved_pid, &wait_status, 0); + } while (pid == -1 && errno == EINTR); + return (pid == -1 ? -1 : + WIFSIGNALED(wait_status) ? WTERMSIG(wait_status) : + WEXITSTATUS(wait_status)); +} + +#elif defined(ACL_MS_WINDOWS) + +#include +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_sys_patch.h" + +/* acl_vstream_popen - open stream to child process */ + +ACL_VSTREAM *acl_vstream_popen(int flags,...) +{ + const char *myname = "acl_vstream_popen"; + ACL_VSTREAM_POPEN_ARGS args; + va_list ap; + ACL_VSTREAM *stream; + ACL_FILE_HANDLE fds[2]; + HANDLE prochnd, hInOut; + STARTUPINFOA sinfo; + PROCESS_INFORMATION pinfo; + DWORD dwCreationFlags = 0; + ACL_VSTRING *envbuf, *cmdline = acl_vstring_alloc(256); + char **cpp; + + va_start(ap, flags); + vstream_parse_args(&args, ap); + va_end(ap); + + if (args.command == 0) { + int i; + + args.command = args.argv[0]; + + /* 组建启动进程命令行参数表 */ + /* 为了避免参数传递时可能因其中间含有空格而被分隔成 + * 多个参数,所以需要在参数两边加上引号 + */ + for (i = 0; args.argv[i] != NULL; i++) { + acl_vstring_strcat(cmdline, "\""); + acl_vstring_strcat(cmdline, args.argv[i]); + acl_vstring_strcat(cmdline, "\" "); + } + } else { + acl_vstring_strcpy(cmdline, "\""); + acl_vstring_strcat(cmdline, args.command); + acl_vstring_strcat(cmdline, "\""); + } + + if (acl_duplex_pipe(fds) < 0) { + acl_vstring_free(cmdline); + return (NULL); + } + + prochnd = GetCurrentProcess(); + if (!DuplicateHandle(prochnd, fds[1], prochnd, &hInOut, + 0L, TRUE, DUPLICATE_SAME_ACCESS)) + { + acl_msg_error("%s(%d): DuplicateHandle error(%s)", + myname, __LINE__, acl_last_serror()); + acl_file_close(fds); + acl_vstring_free(cmdline); + return (NULL); + } + + if (args.env) { + envbuf = acl_vstring_alloc(256); + for (cpp = args.env; *cpp; cpp += 2) { + acl_vstring_memcat(envbuf, cpp[0], strlen(cpp[0])); + ACL_VSTRING_ADDCH(envbuf, '='); + acl_vstring_memcat(envbuf, cpp[1], strlen(cpp[1])); + ACL_VSTRING_ADDCH(envbuf, '\0'); + } + if (ACL_VSTRING_LEN(envbuf) == 0) + ACL_VSTRING_ADDCH(envbuf, '\0'); + ACL_VSTRING_ADDCH(envbuf, '\0'); + } else { + envbuf = NULL; + } + + memset(&sinfo, 0, sizeof(sinfo)); + sinfo.cb = sizeof(sinfo); + /* sinfo.dwFlags = STARTF_USESHOWWINDOW;*/ + sinfo.dwFlags |= STARTF_USESTDHANDLES; + /* sinfo.wShowWindow = SW_HIDE; */ + sinfo.hStdInput = hInOut; + sinfo.hStdOutput = hInOut; + sinfo.hStdError = GetStdHandle(STD_ERROR_HANDLE); + + if (!CreateProcessA(args.command, acl_vstring_str(cmdline), /* Command line */ + NULL, NULL, /* Proc & thread security attributes */ + TRUE, /* Inherit handles */ + dwCreationFlags, /* Creation flags */ + envbuf ? acl_vstring_str(envbuf) : NULL, /* Environment block */ + NULL, /* Current directory name */ + &sinfo, &pinfo)) + { + acl_msg_error("%s: CreateProcess(%s) error(%s)", + myname, args.command, acl_last_serror()); + CloseHandle(pinfo.hThread); + acl_file_close(fds); + if (envbuf) + acl_vstring_free(envbuf); + acl_vstring_free(cmdline); + return (NULL); + } + + acl_file_close(fds[1]); + acl_file_close(hInOut); + CloseHandle(pinfo.hThread); + stream = acl_vstream_fhopen(fds[0], flags); + stream->pid = pinfo.dwProcessId; + stream->hproc = pinfo.hProcess; + + if (envbuf) + acl_vstring_free(envbuf); + acl_vstring_free(cmdline); + return (stream); +} + +/* wail_child -- wait the child exit status */ + +static void wait_child(ACL_VSTREAM *stream) +{ + const char *myname = "wait_child"; + DWORD wait_status, ntime = INFINITE; + + if (stream->hproc == INVALID_HANDLE_VALUE) + return; + + wait_status = WaitForSingleObject(stream->hproc, ntime); + if (wait_status == WAIT_OBJECT_0) { + if (GetExitCodeProcess(stream->hproc, &wait_status)) { + if (wait_status != 0) + acl_msg_warn("%s(%d): child exit code(%d)", + myname, __LINE__, wait_status); + } + } else if (wait_status == WAIT_TIMEOUT) { + acl_msg_warn("%s(%d): wait child timeout", myname, __LINE__); + } else { + acl_msg_warn("%s(%d): wait child error(%s)", + myname, __LINE__, acl_last_serror()); + } + + CloseHandle(stream->hproc); + stream->hproc = INVALID_HANDLE_VALUE; +} + +/* acl_vstream_pclose - close stream to child process */ + +int acl_vstream_pclose(ACL_VSTREAM *stream) +{ + const char *myname = "acl_vstream_pclose"; + + /* + * Reap the monitor_child_thread exit status. + */ + wait_child(stream); + acl_vstream_fclose(stream); + return (-1); +} + +#endif /* ACL_MS_WINDOWS */ diff --git a/lib_acl/src/stdlib/acl_vstring.c b/lib_acl/src/stdlib/acl_vstring.c new file mode 100644 index 000000000..0506bb4d5 --- /dev/null +++ b/lib_acl/src/stdlib/acl_vstring.c @@ -0,0 +1,669 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +/* System libraries. */ + +#include "stdlib/acl_define.h" + +#include /* 44BSD stdarg.h uses abort() */ +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +/* Utility library. */ + +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_msg.h" +#include "stdlib/acl_vbuf_print.h" +#include "stdlib/acl_vstring.h" + +#endif + +#include "charmap.h" + +/* vstring_extend - variable-length string buffer extension policy */ + +static void vstring_extend(ACL_VBUF *bp, int incr) +{ + unsigned used = bp->ptr - bp->data; + int new_len; + ACL_VSTRING *vp = (ACL_VSTRING *) bp->ctx; + + /* + * Note: vp->vbuf.len is the current buffer size (both on entry and on + * exit of this routine). We round up the increment size to the buffer + * size to avoid silly little buffer increments. With really large + * strings we might want to abandon the length doubling strategy, and go + * to fixed increments. + */ + new_len = bp->len + (bp->len > incr ? bp->len : incr); + if (vp->slice) + bp->data = (unsigned char *) acl_slice_pool_realloc( + __FILE__, __LINE__, vp->slice, bp->data, new_len); + else + bp->data = (unsigned char *) acl_myrealloc(bp->data, new_len); + bp->len = new_len; + bp->ptr = bp->data + used; + bp->cnt = bp->len - used; +} + +/* vstring_buf_get_ready - vbuf callback for read buffer empty condition */ + +static int vstring_buf_get_ready(ACL_VBUF *buf acl_unused) +{ + acl_msg_panic("vstring_buf_get: write-only buffer"); + return (0); +} + +/* vstring_buf_put_ready - vbuf callback for write buffer full condition */ + +static int vstring_buf_put_ready(ACL_VBUF *bp) +{ + vstring_extend(bp, 0); + return (0); +} + +/* vstring_buf_space - vbuf callback to reserve space */ + +static int vstring_buf_space(ACL_VBUF *bp, int len) +{ + int need; + + if (len < 0) + acl_msg_panic("vstring_buf_space: bad length %d", len); + if ((need = len - bp->cnt) > 0) + vstring_extend(bp, need); + return (0); +} + +void acl_vstring_init(ACL_VSTRING *vp, size_t len) +{ + if (len < 1) + acl_msg_panic("acl_vstring_alloc: bad input, vp null or len < 1"); + + vp->vbuf.flags = 0; + vp->vbuf.len = 0; + vp->vbuf.data = (unsigned char *) acl_mymalloc(len); + vp->vbuf.len = len; + ACL_VSTRING_RESET(vp); + vp->vbuf.data[0] = 0; + vp->vbuf.get_ready = vstring_buf_get_ready; + vp->vbuf.put_ready = vstring_buf_put_ready; + vp->vbuf.space = vstring_buf_space; + vp->vbuf.ctx = vp; + vp->maxlen = 0; + vp->slice = NULL; +} + +void acl_vstring_free_buf(ACL_VSTRING *vp) +{ + if (vp->vbuf.data) { + acl_myfree(vp->vbuf.data); + vp->vbuf.data = NULL; + } +} + +/* acl_vstring_alloc - create variable-length string */ + +ACL_VSTRING *acl_vstring_alloc(size_t len) +{ + return (acl_vstring_alloc2(NULL, len)); +} + +ACL_VSTRING *acl_vstring_alloc2(ACL_SLICE_POOL *slice, size_t len) +{ + ACL_VSTRING *vp; + + if (len < 1) + acl_msg_panic("acl_vstring_alloc: bad length %d", (int) len); + if (slice) { + vp = (ACL_VSTRING*) acl_slice_pool_alloc(__FILE__, __LINE__, + slice, sizeof(*vp)); + vp->slice = slice; + } else { + vp = (ACL_VSTRING *) acl_mymalloc(sizeof(*vp)); + vp->slice = NULL; + } + vp->vbuf.flags = 0; + vp->vbuf.len = 0; + if (vp->slice) + vp->vbuf.data = (unsigned char *) acl_slice_pool_alloc( + __FILE__, __LINE__, vp->slice, len); + else + vp->vbuf.data = (unsigned char *) acl_mymalloc(len); + vp->vbuf.len = len; + ACL_VSTRING_RESET(vp); + vp->vbuf.data[0] = 0; + vp->vbuf.get_ready = vstring_buf_get_ready; + vp->vbuf.put_ready = vstring_buf_put_ready; + vp->vbuf.space = vstring_buf_space; + vp->vbuf.ctx = vp; + vp->maxlen = 0; + return (vp); +} + +/* acl_vstring_free - destroy variable-length string */ + +ACL_VSTRING *acl_vstring_free(ACL_VSTRING *vp) +{ + if (vp->vbuf.data) { + if (vp->slice) + acl_slice_pool_free(__FILE__, __LINE__, vp->vbuf.data); + else + acl_myfree(vp->vbuf.data); + } + if (vp->slice) + acl_slice_pool_free(__FILE__, __LINE__, vp); + else + acl_myfree(vp); + return (0); +} + +/* acl_vstring_ctl - modify memory management policy */ + +void acl_vstring_ctl(ACL_VSTRING *vp,...) +{ + const char *myname = "acl_vstring_ctl"; + va_list ap; + int code; + + va_start(ap, vp); + while ((code = va_arg(ap, int)) != ACL_VSTRING_CTL_END) { + switch (code) { + default: + acl_msg_panic("%s: unknown code: %d", myname, code); + case ACL_VSTRING_CTL_MAXLEN: + vp->maxlen = va_arg(ap, int); + if (vp->maxlen < 0) + acl_msg_panic("%s: bad max length %d", + myname, vp->maxlen); + break; + } + } + va_end(ap); +} + +/* acl_vstring_truncate - truncate string */ + +ACL_VSTRING *acl_vstring_truncate(ACL_VSTRING *vp, size_t len) +{ + if (len < ACL_VSTRING_LEN(vp)) + ACL_VSTRING_AT_OFFSET(vp, len); + return (vp); +} + +/* acl_vstring_strcpy - copy string */ + +ACL_VSTRING *acl_vstring_strcpy(ACL_VSTRING *vp, const char *src) +{ + ACL_VSTRING_RESET(vp); + + while (*src) { + ACL_VSTRING_ADDCH(vp, *src); + src++; + } + ACL_VSTRING_TERMINATE(vp); + return (vp); +} + +/* acl_vstring_strncpy - copy string of limited length */ + +ACL_VSTRING *acl_vstring_strncpy(ACL_VSTRING *vp, const char *src, size_t len) +{ + ACL_VSTRING_RESET(vp); + + while (len-- > 0 && *src) { + ACL_VSTRING_ADDCH(vp, *src); + src++; + } + ACL_VSTRING_TERMINATE(vp); + return (vp); +} + +/* acl_vstring_strcat - append string */ + +ACL_VSTRING *acl_vstring_strcat(ACL_VSTRING *vp, const char *src) +{ + while (*src) { + ACL_VSTRING_ADDCH(vp, *src); + src++; + } + ACL_VSTRING_TERMINATE(vp); + return (vp); +} + +/* acl_vstring_strncat - append string of limited length */ + +ACL_VSTRING *acl_vstring_strncat(ACL_VSTRING *vp, const char *src, size_t len) +{ + while (len-- > 0 && *src) { + ACL_VSTRING_ADDCH(vp, *src); + src++; + } + ACL_VSTRING_TERMINATE(vp); + return (vp); +} + +/* acl_vstring_memcpy - copy buffer of limited length */ + +ACL_VSTRING *acl_vstring_memcpy(ACL_VSTRING *vp, const char *src, size_t len) +{ + ACL_VSTRING_RESET(vp); + + ACL_VSTRING_SPACE(vp, len); + memcpy(acl_vstring_str(vp), src, len); + ACL_VSTRING_AT_OFFSET(vp, len); + return (vp); +} + +/* acl_vstring_memmove - move buffer of limited length */ + +ACL_VSTRING *acl_vstring_memmove(ACL_VSTRING *vp, const char *src, size_t len) +{ + if (src >= acl_vstring_str(vp) + && (src + len <= acl_vstring_str(vp) + ACL_VSTRING_SIZE(vp))) + { + /* 说明是同一内存区间的数据移动 */ + memmove(acl_vstring_str(vp), src, len); + ACL_VSTRING_AT_OFFSET(vp, len); + return (vp); + } else { + /* 说明不是同一内存区间的数据移动 */ + char *ptr = acl_mymalloc(len); + + memcpy(ptr, src, len); + acl_myfree(vp->vbuf.data); + vp->vbuf.data = (unsigned char *) ptr; + vp->vbuf.len = len; + ACL_VSTRING_AT_OFFSET(vp, len); + vp->maxlen = 0; + return (vp); + } +} + +/* acl_vstring_memcat - append buffer of limited length */ + +ACL_VSTRING *acl_vstring_memcat(ACL_VSTRING *vp, const char *src, size_t len) +{ + ACL_VSTRING_SPACE(vp, len); + memcpy(acl_vstring_end(vp), src, len); + len += ACL_VSTRING_LEN(vp); + ACL_VSTRING_AT_OFFSET(vp, len); + return (vp); +} + +/* acl_vstring_memchr - locate byte in buffer */ + +char *acl_vstring_memchr(ACL_VSTRING *vp, int ch) +{ + unsigned char *cp; + + for (cp = (unsigned char *) acl_vstring_str(vp); + cp < (unsigned char *) acl_vstring_end(vp); cp++) { + if (*cp == ch) + return ((char *) cp); + } + return (NULL); +} + +/* acl_vstring_strstr - locate byte in buffer */ + +char *acl_vstring_strstr(ACL_VSTRING *vp, const char *needle) +{ + unsigned char *cp, *startn = 0; + const unsigned char *np = 0; + + if (vp == NULL || needle == NULL || *needle == 0) + return (NULL); + + for (cp = (unsigned char *) acl_vstring_str(vp); + cp < (unsigned char *) acl_vstring_end(vp); cp++) { + if (np) { + if (*cp == *np) { + if (!*++np) + return ((char *) startn); + } else + np = 0; + } + if (!np && *cp == *((const unsigned char *)needle)) { + np = (const unsigned char *) needle + 1; + if (*np == 0) + return ((char *) cp); + startn = cp; + } + } + + return (NULL); +} + +/* acl_vstring_strcasestr - locate byte in buffer */ + +char *acl_vstring_strcasestr(ACL_VSTRING *vp, const char *needle) +{ + const unsigned char *cm = maptolower; + unsigned char *cp, *startn = 0; + const unsigned char *np = 0; + + if (vp == NULL || needle == NULL || *needle == 0) + return (NULL); + + for (cp = (unsigned char *) acl_vstring_str(vp); + cp < (unsigned char *) acl_vstring_end(vp); cp++) { + if (np) { + if (cm[*cp] == cm[*np]) { + if (!*++np) + return ((char *) startn); + } else + np = 0; + } + if (!np && cm[*cp] == cm[*((const unsigned char *)needle)]) { + np = (const unsigned char *) needle + 1; + if (*np == 0) + return ((char *) cp); + startn = cp; + } + } + + return (NULL); +} + +/* acl_vstring_rstrstr - locate byte in buffer */ + +char *acl_vstring_rstrstr(ACL_VSTRING *vp, const char *needle) +{ + unsigned char *cp; + const unsigned char *np = 0, *needle_end; + + if (vp == NULL || needle == NULL || *needle == 0) + return (NULL); + + needle_end = (const unsigned char *) needle + strlen(needle) - 1; + + for (cp = (unsigned char *) acl_vstring_end(vp) - 1; + cp >= (unsigned char *) acl_vstring_str(vp); cp--) { + if (np) { + if (*cp == *np) { + if (--np < (const unsigned char *) needle) + return ((char *) cp); + } else + np = 0; + } + if (!np && *cp == *needle_end) { + np = needle_end - 1; + if (np < (const unsigned char *) needle) + return ((char *) cp); + } + } + + return (NULL); +} + +/* acl_vstring_rstrcasestr - locate byte in buffer */ + +char *acl_vstring_rstrcasestr(ACL_VSTRING *vp, const char *needle) +{ + const unsigned char *cm = maptolower; + unsigned char *cp; + const unsigned char *np = 0, *needle_end; + + if (vp == NULL || needle == NULL || *needle == 0) + return (NULL); + + needle_end = (const unsigned char *) needle + strlen(needle) - 1; + + for (cp = (unsigned char *) acl_vstring_end(vp) - 1; + cp >= (unsigned char *) acl_vstring_str(vp); cp--) { + if (np) { + if (*cp == cm[*np]) { + if (--np < (const unsigned char *) needle) + return ((char *) cp); + } else + np = 0; + } + if (!np && *cp == cm[*needle_end]) { + np = needle_end - 1; + if (np < (const unsigned char *) needle) + return ((char *) cp); + } + } + + return (NULL); +} + +/* acl_vstring_insert - insert text into string */ + +ACL_VSTRING *acl_vstring_insert(ACL_VSTRING *vp, size_t start, + const char *buf, size_t len) +{ + const char *myname = "acl_vstring_insert"; + size_t new_len; + + /* + * Sanity check. + */ + if (start >= ACL_VSTRING_LEN(vp)) + acl_msg_panic("%s(%d): bad start %ld", + myname, __LINE__, (long) start); + + /* + * Move the existing content and copy the new content. + */ + new_len = ACL_VSTRING_LEN(vp) + len; + ACL_VSTRING_SPACE(vp, len); + memmove(acl_vstring_str(vp) + start + len, + acl_vstring_str(vp) + start, + ACL_VSTRING_LEN(vp) - start); + memcpy(acl_vstring_str(vp) + start, buf, len); + ACL_VSTRING_AT_OFFSET(vp, new_len); + ACL_VSTRING_TERMINATE(vp); + return (vp); +} + +/* acl_vstring_prepend - prepend text to string */ + +ACL_VSTRING *acl_vstring_prepend(ACL_VSTRING *vp, const char *buf, size_t len) +{ + ssize_t new_len; + + /* + * Move the existing content and copy the new content. + */ + new_len = ACL_VSTRING_LEN(vp) + len; + ACL_VSTRING_SPACE(vp, len); + memmove(acl_vstring_str(vp) + len, acl_vstring_str(vp), ACL_VSTRING_LEN(vp)); + memcpy(acl_vstring_str(vp), buf, len); + ACL_VSTRING_AT_OFFSET(vp, new_len); + ACL_VSTRING_TERMINATE(vp); + return (vp); +} + +/* acl_vstring_export - VSTRING to bare string */ + +char *acl_vstring_export(ACL_VSTRING *vp) +{ + char *cp; + + cp = (char *) vp->vbuf.data; + vp->vbuf.data = 0; + acl_myfree(vp); + return (cp); +} + +/* acl_vstring_import - bare string to vstring */ + +ACL_VSTRING *acl_vstring_import(char *str) +{ + ACL_VSTRING *vp; + int len; + + vp = (ACL_VSTRING *) acl_mymalloc(sizeof(*vp)); + vp->slice = NULL; + len = strlen(str); + vp->vbuf.data = (unsigned char *) str; + vp->vbuf.len = len + 1; + ACL_VSTRING_AT_OFFSET(vp, len); + vp->maxlen = 0; + return (vp); +} + +void acl_vstring_glue(ACL_VSTRING *vp, void *buf, size_t len) +{ + vp->vbuf.flags = 0; + vp->vbuf.data = buf; + vp->vbuf.len = len; + ACL_VSTRING_RESET(vp); + vp->vbuf.data[0] = 0; + vp->vbuf.get_ready = vstring_buf_get_ready; + vp->vbuf.put_ready = vstring_buf_put_ready; + vp->vbuf.space = vstring_buf_space; + vp->maxlen = 0; +} + +/* acl_vstring_charat -- get the position char */ + +char acl_vstring_charat(ACL_VSTRING *vp, size_t offset) +{ + char myname[] = "acl_vstring_charat"; + + if (vp == NULL) + acl_msg_fatal("%s(%d): invalid input", myname, __LINE__); + if (offset >= ACL_VSTRING_LEN(vp)) + acl_msg_fatal("%s(%d): offset(%d) >= strlen(%d)", + myname, __LINE__, (int) offset, + (int) ACL_VSTRING_LEN(vp)); + return (ACL_VBUF_CHARAT(vp->vbuf, offset)); +} + +/* acl_vstring_sprintf - formatted string */ + +ACL_VSTRING *acl_vstring_sprintf(ACL_VSTRING *vp, const char *format,...) +{ + va_list ap; + + va_start(ap, format); + vp = acl_vstring_vsprintf(vp, format, ap); + va_end(ap); + return (vp); +} + +/* acl_vstring_vsprintf - format string, vsprintf-like interface */ + +ACL_VSTRING *acl_vstring_vsprintf(ACL_VSTRING *vp, const char *format, va_list ap) +{ + ACL_VSTRING_RESET(vp); + acl_vbuf_print(&vp->vbuf, format, ap); + ACL_VSTRING_TERMINATE(vp); + return (vp); +} + +/* acl_vstring_sprintf_append - append formatted string */ + +ACL_VSTRING *acl_vstring_sprintf_append(ACL_VSTRING *vp, const char *format,...) +{ + va_list ap; + + va_start(ap, format); + vp = acl_vstring_vsprintf_append(vp, format, ap); + va_end(ap); + return (vp); +} + +/* acl_vstring_vsprintf_append - append format string, vsprintf-like interface */ + +ACL_VSTRING *acl_vstring_vsprintf_append(ACL_VSTRING *vp, const char *format, va_list ap) +{ + acl_vbuf_print(&vp->vbuf, format, ap); + ACL_VSTRING_TERMINATE(vp); + return (vp); +} + +/* acl_vstring_sprintf_prepend - format + prepend string, vsprintf-like interface */ + +ACL_VSTRING *acl_vstring_sprintf_prepend(ACL_VSTRING *vp, const char *format,...) +{ + va_list ap; + ssize_t old_len = ACL_VSTRING_LEN(vp); + ssize_t result_len; + + /* Construct: old|new|free */ + va_start(ap, format); + vp = acl_vstring_vsprintf_append(vp, format, ap); + va_end(ap); + result_len = ACL_VSTRING_LEN(vp); + + /* Construct: old|new|old|free */ + ACL_VSTRING_SPACE(vp, old_len); /* avoid dangling pointer */ + acl_vstring_memcat(vp, acl_vstring_str(vp), old_len); + + /* Construct: new|old|free */ + memmove(acl_vstring_str(vp), acl_vstring_str(vp) + old_len, result_len); + ACL_VSTRING_AT_OFFSET(vp, result_len); + ACL_VSTRING_TERMINATE(vp); + return (vp); +} + +const ACL_VSTRING *acl_buffer_gets_nonl(ACL_VSTRING *vp, const char **src, size_t dlen) +{ + const char *myname = "acl_buffer_gets_nonl"; + const char *ptr, *pend, *pbegin = *src; + + if (dlen <= 0) { + acl_msg_warn("%s(%d): dlen(%d) invalid", + myname, __LINE__, (int) dlen); + return (NULL); + } + + ptr = memchr(pbegin, '\n', dlen); + if (ptr == NULL) { + acl_vstring_memcat(vp, pbegin, dlen); + ACL_VSTRING_TERMINATE(vp); + *src += dlen; /* 移动 *src 指针位置 */ + return (NULL); + } + *src = ptr + 1; /* 移动 *src 指针位置 */ + pend = ptr; + + /* 去除多余的 \r\n */ + while (pend >= pbegin) { + if (*pend != '\r' && *pend != '\n') { + break; + } + pend--; + } + if (pend < pbegin) { + /* 说明 data 中只包括 \r, \n */ + ACL_VSTRING_TERMINATE(vp); + return (vp); + } + acl_vstring_memcat(vp, pbegin, pend - pbegin + 1); + ACL_VSTRING_TERMINATE(vp); + return (vp); +} + +const ACL_VSTRING *acl_buffer_gets(ACL_VSTRING *vp, const char **src, size_t dlen) +{ + const char *myname = "acl_buffer_gets"; + const char *ptr; + + if (dlen <= 0) { + acl_msg_warn("%s(%d): dlen(%d) invalid", + myname, __LINE__, (int) dlen); + return (NULL); + } + + ptr = memchr(*src, '\n', dlen); + if (ptr == NULL) { + acl_vstring_memcat(vp, *src, dlen); + ACL_VSTRING_TERMINATE(vp); + *src += dlen; + return (NULL); + } + + acl_vstring_memcat(vp, *src, ptr - *src + 1); + ACL_VSTRING_TERMINATE(vp); + *src = ptr + 1; /* 修改 *src 指针位置 */ + return (vp); +} diff --git a/lib_acl/src/stdlib/acl_vstring_vstream.c b/lib_acl/src/stdlib/acl_vstring_vstream.c new file mode 100644 index 000000000..3ebc03bcf --- /dev/null +++ b/lib_acl/src/stdlib/acl_vstring_vstream.c @@ -0,0 +1,133 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include "stdlib/acl_msg.h" +#include "stdlib/acl_vstring.h" +#include "stdlib/acl_vstream.h" +#include "stdlib/acl_vstring_vstream.h" + +#endif + +/* + * Macro to return the last character added to a ACL_VSTRING, for consistency. + */ +#define ACL_VSTRING_GET_RESULT(vp) \ + (ACL_VSTRING_LEN(vp) > 0 ? acl_vstring_end(vp)[-1] : ACL_VSTREAM_EOF) + +/* acl_vstring_gets - read line from file, keep newline */ + +int acl_vstring_gets(ACL_VSTRING *vp, ACL_VSTREAM *fp) +{ + int ch; + + ACL_VSTRING_RESET(vp); + while ((ch = ACL_VSTREAM_GETC(fp)) != ACL_VSTREAM_EOF) { + ACL_VSTRING_ADDCH(vp, ch); + if (ch == '\n') + break; + } + ACL_VSTRING_TERMINATE(vp); + return (ACL_VSTRING_GET_RESULT(vp)); +} + +/* acl_vstring_gets_nonl - read line from file, strip newline */ + +int acl_vstring_gets_nonl(ACL_VSTRING *vp, ACL_VSTREAM *fp) +{ + int ch, last = 0; + + ACL_VSTRING_RESET(vp); + while ((ch = ACL_VSTREAM_GETC(fp)) != ACL_VSTREAM_EOF && ch != '\n') { + if (ch == '\r') { + last = ch; + } else { + if (last != 0) { + ACL_VSTRING_ADDCH(vp, last); + last = 0; + } + ACL_VSTRING_ADDCH(vp, ch); + } + } + ACL_VSTRING_TERMINATE(vp); + return (ch == '\n' ? ch : ACL_VSTRING_GET_RESULT(vp)); +} + +/* acl_vstring_gets_null - read null-terminated string from file */ + +int acl_vstring_gets_null(ACL_VSTRING *vp, ACL_VSTREAM *fp) +{ + int ch; + + ACL_VSTRING_RESET(vp); + while ((ch = ACL_VSTREAM_GETC(fp)) != ACL_VSTREAM_EOF && ch != 0) + ACL_VSTRING_ADDCH(vp, ch); + ACL_VSTRING_TERMINATE(vp); + return (ch == 0 ? ch : ACL_VSTRING_GET_RESULT(vp)); +} + +/* acl_vstring_gets_bound - read line from file, keep newline, up to bound */ + +int acl_vstring_gets_bound(ACL_VSTRING *vp, ACL_VSTREAM *fp, ssize_t bound) +{ + const char *myname = "acl_vstring_gets_bound"; + int ch; + + if (bound <= 0) + acl_msg_panic("%s: invalid bound %ld", myname, (long) bound); + + ACL_VSTRING_RESET(vp); + while (bound-- > 0 && (ch = ACL_VSTREAM_GETC(fp)) != ACL_VSTREAM_EOF) { + ACL_VSTRING_ADDCH(vp, ch); + if (ch == '\n') + break; + } + ACL_VSTRING_TERMINATE(vp); + return (ACL_VSTRING_GET_RESULT(vp)); +} + +/* acl_vstring_gets_nonl_bound - read line from file, strip newline, up to bound */ + +int acl_vstring_gets_nonl_bound(ACL_VSTRING *vp, ACL_VSTREAM *fp, ssize_t bound) +{ + const char *myname = "acl_vstring_gets_nonl_bound"; + int ch = 0, last = 0; + + if (bound <= 0) + acl_msg_panic("%s: invalid bound %ld", myname, (long) bound); + + ACL_VSTRING_RESET(vp); + while (bound-- > 0 && (ch = ACL_VSTREAM_GETC(fp)) != ACL_VSTREAM_EOF && ch != '\n') { + if (ch == '\r') { + last = ch; + } else { + if (last != 0) { + ACL_VSTRING_ADDCH(vp, last); + if (bound-- == 0) + break; + last = 0; + } + ACL_VSTRING_ADDCH(vp, ch); + } + } + ACL_VSTRING_TERMINATE(vp); + return (ch == '\n' ? ch : ACL_VSTRING_GET_RESULT(vp)); +} + +/* acl_vstring_gets_null_bound - read null-terminated string from file */ + +int acl_vstring_gets_null_bound(ACL_VSTRING *vp, ACL_VSTREAM *fp, ssize_t bound) +{ + const char *myname = "acl_vstring_gets_null_bound"; + int ch = ACL_VSTREAM_EOF; + + if (bound <= 0) + acl_msg_panic("%s: invalid bound %ld", myname, (long) bound); + + ACL_VSTRING_RESET(vp); + while (bound-- > 0 && (ch = ACL_VSTREAM_GETC(fp)) != ACL_VSTREAM_EOF && ch != 0) + ACL_VSTRING_ADDCH(vp, ch); + ACL_VSTRING_TERMINATE(vp); + return (ch == 0 ? ch : ACL_VSTRING_GET_RESULT(vp)); +} + diff --git a/lib_acl/src/stdlib/charmap.h b/lib_acl/src/stdlib/charmap.h new file mode 100644 index 000000000..c87adcbdc --- /dev/null +++ b/lib_acl/src/stdlib/charmap.h @@ -0,0 +1,84 @@ +#ifndef __ACL_CHARMAP_INCLUDE_H__ +#define __ACL_CHARMAP_INCLUDE_H__ + +#ifndef USE_CHARMAP +#define USE_CHARMAP +/* + * This array is designed for mapping upper and lower case letter + * together for a case independent comparison. The mappings are + * based upon ascii character sequences. + */ + +static unsigned char maptolower[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff +}; + +#if 0 +static const unsigned char maptolower[] = { + 0000, 0001, 0002, 0003, 0004, 0005, 0006, 0007, + 0010, 0011, 0012, 0013, 0014, 0015, 0016, 0017, + 0020, 0021, 0022, 0023, 0024, 0025, 0026, 0027, + 0030, 0031, 0032, 0033, 0034, 0035, 0036, 0037, + 0040, 0041, 0042, 0043, 0044, 0045, 0046, 0047, + 0050, 0051, 0052, 0053, 0054, 0055, 0056, 0057, + 0060, 0061, 0062, 0063, 0064, 0065, 0066, 0067, + 0070, 0071, 0072, 0073, 0074, 0075, 0076, 0077, + 0100, 0141, 0142, 0143, 0144, 0145, 0146, 0147, + 0150, 0151, 0152, 0153, 0154, 0155, 0156, 0157, + 0160, 0161, 0162, 0163, 0164, 0165, 0166, 0167, + 0170, 0171, 0172, 0133, 0134, 0135, 0136, 0137, + 0140, 0141, 0142, 0143, 0144, 0145, 0146, 0147, + 0150, 0151, 0152, 0153, 0154, 0155, 0156, 0157, + 0160, 0161, 0162, 0163, 0164, 0165, 0166, 0167, + 0170, 0171, 0172, 0173, 0174, 0175, 0176, 0177, + 0200, 0201, 0202, 0203, 0204, 0205, 0206, 0207, + 0210, 0211, 0212, 0213, 0214, 0215, 0216, 0217, + 0220, 0221, 0222, 0223, 0224, 0225, 0226, 0227, + 0230, 0231, 0232, 0233, 0234, 0235, 0236, 0237, + 0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247, + 0250, 0251, 0252, 0253, 0254, 0255, 0256, 0257, + 0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267, + 0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277, + 0300, 0301, 0302, 0303, 0304, 0305, 0306, 0307, + 0310, 0311, 0312, 0313, 0314, 0315, 0316, 0317, + 0320, 0321, 0322, 0323, 0324, 0325, 0326, 0327, + 0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337, + 0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347, + 0350, 0351, 0352, 0353, 0354, 0355, 0356, 0357, + 0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367, + 0370, 0371, 0372, 0373, 0374, 0375, 0376, 0377 +}; +#endif +#endif /* USE_CHARMAP */ +#endif diff --git a/lib_acl/src/stdlib/common/acl_argv.c b/lib_acl/src/stdlib/common/acl_argv.c new file mode 100644 index 000000000..5385e2043 --- /dev/null +++ b/lib_acl/src/stdlib/common/acl_argv.c @@ -0,0 +1,326 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#include /* 44BSD stdarg.h uses abort() */ +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +/* Application-specific. */ + +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_msg.h" +#include "stdlib/acl_argv.h" + +#endif + +#define SPACE_LEFT(a) ((a)->len - (a)->argc - 1) + +/* argv_extend - extend array */ + +static void argv_extend(ACL_ARGV *argvp) +{ + int new_len; + + new_len = argvp->len * 2; + if (argvp->slice) + argvp->argv = (char **) acl_slice_pool_realloc(__FILE__, __LINE__, + argvp->slice, argvp->argv, (new_len + 1) * sizeof(char *)); + else + argvp->argv = (char **) acl_myrealloc((char *) argvp->argv, + (new_len + 1) * sizeof(char *)); + argvp->len = new_len; +} + +static void argv_push_back(struct ACL_ARGV *argvp, const char *s) +{ + acl_argv_add(argvp, s, 0); +} + +static void argv_push_front(struct ACL_ARGV *argvp, const char *s) +{ + int i; + + /* Make sure that always argvp->argc < argvp->len. */ + + if (SPACE_LEFT(argvp) <= 0) + argv_extend(argvp); + for (i = argvp->argc; i > 0; i--) { + argvp->argv[i] = argvp->argv[i - 1]; + } + if (argvp->slice) + argvp->argv[0] = acl_slice_pool_strdup(__FILE__, __LINE__, + argvp->slice, s); + else + argvp->argv[0] = acl_mystrdup(s); + argvp->argc++; +} + +static char *argv_pop_back(struct ACL_ARGV *argvp) +{ + if (argvp->argc <= 0) + return (NULL); + return (argvp->argv[--argvp->argc]); +} + +static char *argv_pop_front(struct ACL_ARGV *argvp) +{ + char *s; + int i; + + if (argvp->argc <= 0) + return (NULL); + s = argvp->argv[0]; + argvp->argc--; + for (i = 0; i < argvp->argc; i++) { + argvp->argv[i] = argvp->argv[i + 1]; + } + return (s); +} + +/* argv_iter_head - get the head of the array */ + +static void *argv_iter_head(ACL_ITER *iter, struct ACL_ARGV *argv) +{ + iter->dlen = -1; + iter->key = NULL; + iter->klen = -1; + + iter->i = 0; + iter->size = argv->argc; + iter->ptr = argv->argv[0]; + + iter->data = iter->ptr; + return (iter->ptr); +} + +/* argv_iter_next - get the next of the array */ + +static void *argv_iter_next(ACL_ITER *iter, struct ACL_ARGV *argv) +{ + iter->i++; + if (iter->i >= argv->argc) + iter->data = iter->ptr = 0; + else + iter->data = iter->ptr = argv->argv[iter->i]; + return (iter->ptr); +} + +/* argv_iter_tail - get the tail of the array */ + +static void *argv_iter_tail(ACL_ITER *iter, struct ACL_ARGV *argv) +{ + iter->dlen = -1; + iter->key = NULL; + iter->klen = -1; + + iter->i = argv->argc - 1; + iter->size = argv->argc; + if (iter->i < 0) + iter->data = iter->ptr = 0; + else + iter->data = iter->ptr = argv->argv[iter->i]; + return (iter->ptr); +} + +/* argv_iter_prev - get the prev of the array */ + +static void *argv_iter_prev(ACL_ITER *iter, struct ACL_ARGV *argv) +{ + iter->i--; + if (iter->i < 0) + iter->data = iter->ptr = 0; + else + iter->data = iter->ptr = argv->argv[iter->i]; + return (iter->ptr); +} + +/* acl_argv_free - destroy string array */ + +ACL_ARGV *acl_argv_free(ACL_ARGV *argvp) +{ + char **cpp; + + for (cpp = argvp->argv; cpp < argvp->argv + argvp->argc; cpp++) { + if (argvp->slice) + acl_slice_pool_free(__FILE__, __LINE__, *cpp); + else + acl_myfree(*cpp); + } + if (argvp->slice) { + acl_slice_pool_free(__FILE__, __LINE__, argvp->argv); + acl_slice_pool_free(__FILE__, __LINE__, argvp); + } else { + acl_myfree(argvp->argv); + acl_myfree(argvp); + } + return (NULL); +} + +/* acl_argv_alloc - initialize string array */ + +ACL_ARGV *acl_argv_alloc(int size) +{ + return (acl_argv_alloc2(size, NULL)); +} + +ACL_ARGV *acl_argv_alloc2(int len, ACL_SLICE_POOL *slice) +{ + ACL_ARGV *argvp; + int sane_len; + + /* Make sure that always argvp->argc < argvp->len. */ + + if (slice) { + argvp = (ACL_ARGV *) acl_slice_pool_alloc(__FILE__, __LINE__, + slice, sizeof(*argvp)); + argvp->slice = slice; + } else { + argvp = (ACL_ARGV *) acl_mymalloc(sizeof(*argvp)); + argvp->slice = NULL; + } + argvp->len = 0; + sane_len = (len < 2 ? 2 : len); + if (argvp->slice) + argvp->argv = (char **) acl_slice_pool_alloc(__FILE__, __LINE__, + argvp->slice, (sane_len + 1) * sizeof(char *)); + else + argvp->argv = (char **) acl_mymalloc((sane_len + 1) * sizeof(char *)); + argvp->len = sane_len; + argvp->argc = 0; + argvp->argv[0] = 0; + + argvp->push_back = argv_push_back; + argvp->push_front = argv_push_front; + argvp->pop_back = argv_pop_back; + argvp->pop_front = argv_pop_front; + + /* set the iterator callback */ + argvp->iter_head = argv_iter_head; + argvp->iter_next = argv_iter_next; + argvp->iter_tail = argv_iter_tail; + argvp->iter_prev = argv_iter_prev; + + return (argvp); +} + +/* acl_argv_add - add string to vector */ + +void acl_argv_add(ACL_ARGV *argvp,...) +{ + const char *arg; + va_list ap; + + /* Make sure that always argvp->argc < argvp->len. */ + + va_start(ap, argvp); + while ((arg = va_arg(ap, const char *)) != 0) { + if (SPACE_LEFT(argvp) <= 0) + argv_extend(argvp); + if (argvp->slice) + argvp->argv[argvp->argc++] = acl_slice_pool_strdup(__FILE__, __LINE__, + argvp->slice, arg); + else + argvp->argv[argvp->argc++] = acl_mystrdup(arg); + } + va_end(ap); + argvp->argv[argvp->argc] = 0; +} + +void acl_argv_addv(ACL_ARGV *argvp, va_list ap) +{ + const char *arg; + + /* Make sure that always argvp->argc < argvp->len. */ + + while ((arg = va_arg(ap, const char *)) != 0) { + if (SPACE_LEFT(argvp) <= 0) + argv_extend(argvp); + if (argvp->slice) + argvp->argv[argvp->argc++] = acl_slice_pool_strdup(__FILE__, __LINE__, + argvp->slice, arg); + else + argvp->argv[argvp->argc++] = acl_mystrdup(arg); + } + argvp->argv[argvp->argc] = 0; +} + +/* acl_argv_addn - add string to vector */ + +void acl_argv_addn(ACL_ARGV *argvp,...) +{ + const char *myname = "acl_argv_addn"; + const char *arg; + int len; + va_list ap; + + /* Make sure that always argvp->argc < argvp->len. */ + + va_start(ap, argvp); + while ((arg = va_arg(ap, const char *)) != 0) { + if ((len = va_arg(ap, int)) < 0) + acl_msg_panic("%s: bad string length %d", myname, len); + if (SPACE_LEFT(argvp) <= 0) + argv_extend(argvp); + if (argvp->slice) + argvp->argv[argvp->argc++] = acl_slice_pool_strndup(__FILE__, __LINE__, + argvp->slice, arg, len); + else + argvp->argv[argvp->argc++] = acl_mystrndup(arg, len); + } + va_end(ap); + argvp->argv[argvp->argc] = 0; +} + +void acl_argv_addnv(ACL_ARGV *argvp, va_list ap) +{ + const char *myname = "acl_argv_addnv"; + const char *arg; + int len; + + /* Make sure that always argvp->argc < argvp->len. */ + + while ((arg = va_arg(ap, const char *)) != 0) { + if ((len = va_arg(ap, int)) < 0) + acl_msg_panic("%s: bad string length %d", myname, len); + if (SPACE_LEFT(argvp) <= 0) + argv_extend(argvp); + if (argvp->slice) + argvp->argv[argvp->argc++] = acl_slice_pool_strndup(__FILE__, __LINE__, + argvp->slice, arg, len); + else + argvp->argv[argvp->argc++] = acl_mystrndup(arg, len); + } + argvp->argv[argvp->argc] = 0; +} + +/* acl_argv_terminate - terminate string array */ + +void acl_argv_terminate(ACL_ARGV *argvp) +{ + + /* Trust that argvp->argc < argvp->len. */ + argvp->argv[argvp->argc] = 0; +} + +char *acl_argv_index(ACL_ARGV *argvp, int idx) +{ + if (argvp == NULL || idx < 0 || idx > argvp->argc - 1) + return(NULL); + + return(argvp->argv[idx]); +} + +int acl_argv_size(ACL_ARGV *argvp) +{ + if (argvp == NULL) + return (-1); + + return (argvp->argc); +} + diff --git a/lib_acl/src/stdlib/common/acl_argv_split.c b/lib_acl/src/stdlib/common/acl_argv_split.c new file mode 100644 index 000000000..5ee0141c0 --- /dev/null +++ b/lib_acl/src/stdlib/common/acl_argv_split.c @@ -0,0 +1,110 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +/* Application-specific. */ + +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_argv.h" +#include "stdlib/acl_mystring.h" + +#endif + +/* acl_argv_split - split string into token array */ + +ACL_ARGV *acl_argv_split(const char *str, const char *delim) +{ + return (acl_argv_split3(str, delim, NULL)); +} + +ACL_ARGV *acl_argv_split3(const char *str, const char *delim, + ACL_SLICE_POOL *slice) +{ + ACL_ARGV *argvp = acl_argv_alloc2(1, slice); + char *saved_string = slice ? + acl_slice_pool_strdup(__FILE__, __LINE__, slice, str) : + acl_mystrdup(str); + char *bp = saved_string; + char *arg; + + while ((arg = acl_mystrtok(&bp, delim)) != 0) + acl_argv_add(argvp, arg, (char *) 0); + acl_argv_terminate(argvp); + if (slice) + acl_slice_pool_free(__FILE__, __LINE__, saved_string); + else + acl_myfree(saved_string); + return (argvp); +} + +/* acl_argv_splitn - split string into token array with max items */ + +ACL_ARGV *acl_argv_splitn(const char *str, const char *delim, size_t n) +{ + return (acl_argv_splitn4(str, delim, n, NULL)); +} + +ACL_ARGV *acl_argv_splitn4(const char *str, const char *delim, + size_t n, ACL_SLICE_POOL *slice) +{ + ACL_ARGV *argvp = acl_argv_alloc2(n > 0 ? n : 1, slice); + char *saved_string = slice ? + acl_slice_pool_strdup(__FILE__, __LINE__, slice, str) : + acl_mystrdup(str); + char *bp = saved_string; + char *arg; + + while (n-- > 0 && (arg = acl_mystrtok(&bp, delim)) != 0) + acl_argv_add(argvp, arg, (char *) 0); + acl_argv_terminate(argvp); + if (slice) + acl_slice_pool_free(__FILE__, __LINE__, saved_string); + else + acl_myfree(saved_string); + return (argvp); +} + +/* acl_argv_split_append - split string into token array, append to array */ + +ACL_ARGV *acl_argv_split_append(ACL_ARGV *argvp, const char *str, const char *delim) +{ + char *saved_string = argvp->slice ? + acl_slice_pool_strdup(__FILE__, __LINE__, argvp->slice, str) : + acl_mystrdup(str); + char *bp = saved_string; + char *arg; + + while ((arg = acl_mystrtok(&bp, delim)) != 0) + acl_argv_add(argvp, arg, (char *) 0); + acl_argv_terminate(argvp); + if (argvp->slice) + acl_slice_pool_free(__FILE__, __LINE__, saved_string); + else + acl_myfree(saved_string); + return (argvp); +} + +/* acl_argv_splitn_append - split string into token array, append to array with max items */ + +ACL_ARGV *acl_argv_splitn_append(ACL_ARGV *argvp, const char *str, const char *delim, size_t n) +{ + char *saved_string = argvp->slice ? + acl_slice_pool_strdup(__FILE__, __LINE__, argvp->slice, str) : + acl_mystrdup(str); + char *bp = saved_string; + char *arg; + + while (n-- > 0 && (arg = acl_mystrtok(&bp, delim)) != 0) + acl_argv_add(argvp, arg, (char *) 0); + acl_argv_terminate(argvp); + if (argvp->slice) + acl_slice_pool_free(__FILE__, __LINE__, saved_string); + else + acl_myfree(saved_string); + return (argvp); +} diff --git a/lib_acl/src/stdlib/common/acl_array.c b/lib_acl/src/stdlib/common/acl_array.c new file mode 100644 index 000000000..b0728dd40 --- /dev/null +++ b/lib_acl/src/stdlib/common/acl_array.c @@ -0,0 +1,410 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#include +#include +#include + +#endif + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_msg.h" +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_array.h" + +static void array_push_back(struct ACL_ARRAY *a, void *obj) +{ + acl_array_append(a, obj); +} + +static void array_push_front(struct ACL_ARRAY *a, void *obj) +{ + acl_array_prepend(a, obj); +} + +static void *array_pop_back(struct ACL_ARRAY *a) +{ + void *obj; + if (a->count <= 0) + return (NULL); + a->count--; + obj = a->items[a->count]; + return (obj); +} + +static void *array_pop_front(struct ACL_ARRAY *a) +{ + void *obj; + int i; + + if (a->count <= 0) + return (NULL); + obj = a->items[0]; + a->count--; + for (i = 0; i < a->count; i++) + a->items[i] = a->items[i + 1]; + + return (obj); +} + +/* array_iter_head - get the head of the array */ + +static void *array_iter_head(ACL_ITER *iter, struct ACL_ARRAY *a) +{ + iter->dlen = -1; + iter->key = NULL; + iter->klen = 0; + iter->i = 0; + iter->size = a->count; + if (a->items == NULL || a->count <= 0) + iter->ptr = iter->data = 0; + else + iter->ptr = iter->data = a->items[0]; + + return (iter->ptr); +} + +/* array_iter_next - get the next of the array */ + +static void *array_iter_next(ACL_ITER *iter, struct ACL_ARRAY *a) +{ + iter->i++; + if (iter->i >= a->count) + iter->data = iter->ptr = 0; + else + iter->data = iter->ptr = a->items[iter->i]; + return (iter->ptr); +} + +/* array_iter_tail - get the tail of the array */ + +static void *array_iter_tail(ACL_ITER *iter, struct ACL_ARRAY *a) +{ + iter->dlen = -1; + iter->key = NULL; + iter->klen = 0; + iter->i = a->count - 1; + iter->size = a->count; + if (a->items == NULL || iter->i < 0) + iter->ptr = iter->data = 0; + else + iter->data = iter->ptr = a->items[iter->i]; + return (iter->ptr); +} + +/* array_iter_prev - get the prev of the array */ + +static void *array_iter_prev(ACL_ITER *iter, struct ACL_ARRAY *a) +{ + iter->i--; + if (iter->i < 0) + iter->data = iter->ptr = 0; + else + iter->data = iter->ptr = a->items[iter->i]; + return (iter->ptr); +} + +/* grows internal buffer to satisfy required minimal capacity */ +static void acl_array_grow(ACL_ARRAY *a, int min_capacity) +{ + const int min_delta = 16; + int delta; + + /* don't need to grow the capacity of the array */ + if(a->capacity >= min_capacity) + return; + delta = min_capacity; + /* make delta a multiple of min_delta */ + delta += min_delta - 1; + delta /= min_delta; + delta *= min_delta; + /* actual grow */ + if (delta <= 0) + return; + a->capacity += delta; + if (a->items) { + a->items = (void **) acl_myrealloc(a->items, + a->capacity * sizeof(void *)); + } else { + a->items = (void **) acl_mymalloc(a->capacity + * sizeof(void *)); + } + + /* reset, just in case */ + memset(a->items + a->count, 0, + (a->capacity - a->count) * sizeof(void *)); +} + +ACL_ARRAY *acl_array_create(int init_size) +{ + int ret; + ACL_ARRAY *a; + + a = (ACL_ARRAY *) acl_mycalloc(1, sizeof(ACL_ARRAY)); + + a->push_back = array_push_back; + a->push_front = array_push_front; + a->pop_back = array_pop_back; + a->pop_front = array_pop_front; + a->iter_head = array_iter_head; + a->iter_next = array_iter_next; + a->iter_tail = array_iter_tail; + a->iter_prev = array_iter_prev; + + if(init_size > 0) { + ret = acl_array_pre_append(a, init_size); + if(ret < 0) { + acl_myfree(a); + return(NULL); + } + } + + return(a); +} + +void acl_array_clean(ACL_ARRAY *a, void (*free_fn)(void *)) +{ + int idx; + + for(idx = 0; idx < a->count; idx++) { + if(free_fn != NULL && a->items[idx] != NULL) + free_fn(a->items[idx]); + a->items[idx] = NULL; /* sanity set to be null */ + } + a->count = 0; +} + +void acl_array_free(ACL_ARRAY *a, void (*free_fn)(void *)) +{ + acl_array_clean(a, free_fn); + if (a->items) + acl_myfree(a->items); + acl_myfree(a); +} + +int acl_array_append(ACL_ARRAY *a, void *obj) +{ + if (a->count >= a->capacity) + acl_array_grow(a, a->count + 16); + a->items[a->count++] = obj; + return(a->count - 1); +} + +int acl_array_pred_insert(ACL_ARRAY *a, int position, void *obj) +{ + int idx; + + /* + * a->items[count - 1] should be the last valid item node + * position should: positioin >= 0 && position <= a->count - 1 + */ + if(obj == NULL || position < 0 || position >= a->count) + return(-1); + if(a->count >= a->capacity) + acl_array_grow(a, a->count + 1); + + /* NOTICE: the C's index begin with 0 + * when position == 0, just prepend one new node before the first node + * of the array + */ + for(idx = a->count; idx > position && idx > 0; idx--) { + /* if idx == 0 then we has arrived + * at the beginning of the array + */ + a->items[idx] = a->items[idx - 1]; + } + a->items[position] = obj; + a->count++; + return(position); +} + +int acl_array_succ_insert(ACL_ARRAY *a, int position, void *obj) +{ + int idx, position_succ; + + /* + * a->items[count - 1] should be the last valid item node + * position should: position >= 0 && position <= a->count - 1 + */ + if(a == NULL || obj == NULL || position < 0 || position >= a->count) + return(-1); + if(a->count >= a->capacity) + acl_array_grow(a, a->count + 1); + + position_succ = position + 1; + /* + * position_succ should: + * position_succ > 0 (because position >= 0 and position_succ = position + 1) + * and position_succ <= a->count (when position == a->count - 1, + * position == a->count, and just append one new node after the last node) + * NOTICE: the C's index begin with 0 + */ + for(idx = a->count; idx > position_succ; idx--) + a->items[idx] = a->items[idx - 1]; + a->items[position_succ] = obj; + a->count++; + return(position_succ); +} + +int acl_array_prepend(ACL_ARRAY *a, void *obj) +{ + int position = 0, ret; + + if(a == NULL || obj == NULL) + return(-1); + ret = acl_array_pred_insert(a, position, obj); + return(ret); +} + +int acl_array_delete_idx(ACL_ARRAY *a, int position, void (*free_fn)(void *)) +{ + int idx; + + if(a == NULL || position < 0 || position >= a->count) + return(-1); + if(free_fn != NULL && a->items[position] != NULL) + free_fn(a->items[position]); + a->items[position] = NULL; /* sanity set to be null */ + + for(idx = position; idx < a->count - 1; idx++) + a->items[idx] = a->items[idx + 1]; + a->count--; + return(0); +} + +int acl_array_delete(ACL_ARRAY *a, int idx, void (*free_fn)(void*)) +{ + if (a == NULL) + return (-1); + if (idx < 0 || idx >= a->count) + return (-1); + if (free_fn != NULL && a->items[idx] != NULL) + free_fn(a->items[idx]); + a->count--; + if (a->count > 0) + a->items[idx] = a->items[a->count]; + return (0); +} + +int acl_array_delete_obj(ACL_ARRAY *a, void *obj, void (*free_fn)(void *)) +{ + int idx, position, ret; + + if(a == NULL || obj == NULL) + return(-1); + position = -1; + for(idx = 0; idx < a->count; idx++) { + if(a->items[idx] == obj) { + position = idx; + break; + } + } + + if(free_fn != NULL && obj != NULL) + free_fn(obj); + if(position == -1) /* not found */ + return(-1); + + /* don't need to free the obj in acl_array_delete_idx */ + a->items[idx] = NULL; + ret = acl_array_delete_idx(a, position, NULL); + if(ret < 0) + return(-1); + return(ret); +} + +int acl_array_delete_range(ACL_ARRAY *a, int ibegin, int iend, void (*free_fn)(void*)) +{ + int i, imax; + + if (a == NULL || ibegin < 0 || iend < 0 || a->count <= 0) + return (-1); + if (ibegin > iend) + return (-1); + + imax = a->count - 1; + if (iend > imax) + iend = imax; + + if (free_fn != NULL) { + for (i = ibegin; i <= iend; i++) { + if (a->items[i] != NULL) + free_fn(a->items[i]); + a->items[i] = NULL; + } + } + + a->count -= iend - ibegin + 1; + + for (iend++; iend <= imax;) { + a->items[ibegin++] = a->items[iend++]; + } + + return (0); +} + +int acl_array_mv_idx(ACL_ARRAY *a, int ito, int ifrom, void (*free_fn)(void *)) +{ + int i, i_obj, i_src, i_max; + + if(a == NULL || ito < 0 || ifrom < 0 || a->count < 0) + return(-1); + + if(a->count == 0 || ito >= ifrom || ifrom >= a->count) + return(0); + + i_obj = ito; + i_src = ifrom; + i_max = a->count - 1; + + if(free_fn != NULL) { + for(i = i_obj; i < i_src; i++) { + if(a->items[i] != NULL) + free_fn(a->items[i]); + a->items[i] = NULL; + } + } + for(; i_src <= i_max; i_src++) { + a->items[i_obj] = a->items[i_src]; + i_obj++; + } + + a->count -= ifrom - ito; + if(a->count < 0) /* imposible, sanity check */ + return(-1); + + return(0); +} + +/* if you are going to append a known and large number of items, call this first */ +int acl_array_pre_append(ACL_ARRAY *a, int app_count) +{ + char myname[] = "acl_array_pre_append"; + + if(a == NULL || app_count <= 0) + acl_msg_fatal("%s(%d)->%s: invalid input", + __FILE__, __LINE__, myname); + if (a->count + app_count > a->capacity) + acl_array_grow(a, a->count + app_count); + return(0); +} + +void *acl_array_index(const ACL_ARRAY *a, int idx) +{ + if(a == NULL || idx < 0 || idx > a->count - 1) + return(NULL); + + return(a->items[idx]); +} + +int acl_array_size(const ACL_ARRAY *a) +{ + if(a == NULL) + return(-1); + return(a->count); +} diff --git a/lib_acl/src/stdlib/common/acl_binhash.c b/lib_acl/src/stdlib/common/acl_binhash.c new file mode 100644 index 000000000..b7d28efc9 --- /dev/null +++ b/lib_acl/src/stdlib/common/acl_binhash.c @@ -0,0 +1,527 @@ +/* C library */ + +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +/* Local stuff */ + +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_msg.h" +#include "stdlib/acl_slice.h" +#include "stdlib/acl_binhash.h" + +#endif + +/* binhash_iter_head */ + +static void *binhash_iter_head(ACL_ITER *iter, struct ACL_BINHASH *table) +{ + ACL_BINHASH_INFO *ptr = NULL; + + iter->dlen = -1; + iter->i = 0; + iter->size = table->size; + iter->ptr = NULL; + + for (; iter->i < iter->size; iter->i++) { + if (table->data[iter->i] != NULL) { + iter->ptr = ptr = table->data[iter->i]; + break; + } + } + + if (ptr) { + iter->data = ptr->value; + iter->key = (const char*) ptr->key.c_key; + iter->klen = ptr->key_len; + } else { + iter->data = NULL; + iter->key = NULL; + iter->klen = 0; + } + return (iter->ptr); +} + +/* binhash_iter_next */ + +static void *binhash_iter_next(ACL_ITER *iter, struct ACL_BINHASH *table) +{ + ACL_BINHASH_INFO *ptr; + + ptr = (ACL_BINHASH_INFO*) iter->ptr; + if (ptr) { + iter->ptr = ptr = ptr->next; + if (ptr) { + iter->data = ptr->value; + iter->key = (const char*) ptr->key.c_key; + iter->klen = ptr->key_len; + return (iter->ptr); + } + } + + for (iter->i++; iter->i < iter->size; iter->i++) { + if (table->data[iter->i] != NULL) { + iter->ptr = ptr = table->data[iter->i]; + break; + } + } + + if (ptr) { + iter->data = ptr->value; + iter->key = (const char*) ptr->key.c_key; + iter->klen = ptr->key_len; + } else { + iter->data = NULL; + iter->key = NULL; + iter->klen = 0; + } + return (iter->ptr); +} + +/* binhash_iter_tail */ + +static void *binhash_iter_tail(ACL_ITER *iter, struct ACL_BINHASH *table) +{ + ACL_BINHASH_INFO *ptr = NULL; + + iter->dlen = -1; + iter->i = table->size - 1; + iter->size = table->size; + iter->ptr = NULL; + + for (; iter->i >= 0; iter->i--) { + if (table->data[iter->i] != NULL) { + iter->ptr = ptr = table->data[iter->i]; + break; + } + } + + if (ptr) { + iter->data = ptr->value; + iter->key = (const char*) ptr->key.c_key; + iter->klen = ptr->key_len; + } else { + iter->data = NULL; + iter->key = NULL; + iter->klen = 0; + } + return (iter->ptr); +} + +/* binhash_iter_prev */ + +static void *binhash_iter_prev(ACL_ITER *iter, struct ACL_BINHASH *table) +{ + ACL_BINHASH_INFO *ptr; + + ptr = (ACL_BINHASH_INFO*) iter->ptr; + if (ptr) { + iter->ptr = ptr = ptr->next; + if (ptr != NULL) { + iter->data = ptr->value; + iter->key = (const char*) ptr->key.c_key; + iter->klen = ptr->key_len; + return (iter->ptr); + } + } + + for (iter->i--; iter->i >= 0; iter->i--) { + if (table->data[iter->i] != NULL) { + iter->ptr = ptr = table->data[iter->i]; + break; + } + } + + iter->data = ptr ? ptr->value : NULL; + return (iter->ptr); +} + +/* binhash_iter_info */ + +static ACL_BINHASH_INFO *binhash_iter_info(ACL_ITER *iter, struct ACL_BINHASH *table acl_unused) +{ + return (iter->ptr ? (ACL_BINHASH_INFO*) iter->ptr : NULL); +} + +/* binhash_hash - hash a string */ + +static unsigned binhash_hash(const void *key_in, size_t len) +{ + const char *key = (const char *) key_in; + unsigned long h = 0; + unsigned long g; + + /* + * From the "Dragon" book by Aho, Sethi and Ullman. + */ + + while (len-- > 0) { + h = (h << 4) + *key++; + if ((g = (h & 0xf0000000)) != 0) { + h ^= (g >> 24); + h ^= g; + } + } + return (h); +} + +/* binhash_link - insert element into table */ + +#define binhash_link(_table, _element, _n) { \ + ACL_BINHASH_INFO **_h = _table->data + _n; \ + _element->prev = 0; \ + if ((_element->next = *_h) != 0) \ + (*_h)->prev = _element; \ + *_h = _element; \ + _table->used++; \ +} + +#define KEY_EQ(x,y,l) (((const char*)x)[0] == ((const char*)y)[0] && memcmp(x,y,l) == 0) + +/* binhash_size - allocate and initialize hash table */ + +static void binhash_size(ACL_BINHASH *table, unsigned size) +{ + ACL_BINHASH_INFO **h; + + size |= 1; + + table->data = h = (ACL_BINHASH_INFO **) + acl_mymalloc(size * sizeof(ACL_BINHASH_INFO *)); + table->size = size; + table->used = 0; + + while (size-- > 0) + *h++ = 0; +} + +/* acl_binhash_create - create initial hash table */ + +ACL_BINHASH *acl_binhash_create(int size, unsigned int flag) +{ + ACL_BINHASH *table; + unsigned int slice_flag = 0; + + table = (ACL_BINHASH *) acl_mycalloc(1, sizeof(ACL_BINHASH)); + binhash_size(table, size < 13 ? 13 : size); + table->flag = flag; + table->hash_fn = binhash_hash; + + table->iter_head = binhash_iter_head; + table->iter_next = binhash_iter_next; + table->iter_tail = binhash_iter_tail; + table->iter_prev = binhash_iter_prev; + table->iter_info = binhash_iter_info; + + if ((flag & ACL_BINHASH_FLAG_SLICE1)) + slice_flag |= ACL_SLICE_FLAG_GC1; + if ((flag & ACL_BINHASH_FLAG_SLICE2)) + slice_flag |= ACL_SLICE_FLAG_GC2; + if ((flag & ACL_BINHASH_FLAG_SLICE3)) + slice_flag |= ACL_SLICE_FLAG_GC3; + + if (slice_flag) { + if ((slice_flag & ACL_BINHASH_FLAG_SLICE_RTGC_OFF)) + slice_flag |= ACL_SLICE_FLAG_RTGC_OFF; + table->slice = acl_slice_create("acl_binhash", 0, + sizeof(ACL_BINHASH_INFO), slice_flag); + } + return (table); +} + +/* acl_binhash_grow - extend existing table */ + +static void acl_binhash_grow(ACL_BINHASH *table) +{ + ACL_BINHASH_INFO *ht; + ACL_BINHASH_INFO *next; + unsigned old_size = table->size; + ACL_BINHASH_INFO **h = table->data; + ACL_BINHASH_INFO **old_entries = h; + unsigned n; + + binhash_size(table, 2 * old_size); + + while (old_size-- > 0) { + for (ht = *h++; ht; ht = next) { + next = ht->next; + n = table->hash_fn(ht->key.c_key, ht->key_len) % table->size; + binhash_link(table, ht, n); + } + } + acl_myfree(old_entries); +} + +/* acl_binhash_enter - enter (key, value) pair */ + +ACL_BINHASH_INFO *acl_binhash_enter(ACL_BINHASH *table, const void *key, int key_len, void *value) +{ + ACL_BINHASH_INFO *ht; + const char *p1, *p2; + unsigned n; + + if (table->used >= table->size) + acl_binhash_grow(table); + + n = table->hash_fn(key, key_len) % table->size; + for (ht = table->data[n]; ht; ht = ht->next) { + p1 = (const char*) key; + p2 = (const char*) ht->key.c_key; + + if (key_len == ht->key_len && KEY_EQ(p1, p2, key_len)) { + table->status = ACL_BINHASH_STAT_DUPLEX_KEY; + return (ht); + } + } + + if (table->slice) + ht = (ACL_BINHASH_INFO *) acl_slice_alloc(table->slice); + else + ht = (ACL_BINHASH_INFO *) acl_mymalloc(sizeof(ACL_BINHASH_INFO)); + + if ((table->flag & ACL_BINHASH_FLAG_KEY_REUSE)) + ht->key.c_key = key; + else + ht->key.key = acl_mymemdup(key, key_len); + ht->key_len = key_len; + ht->value = value; + binhash_link(table, ht, n); + table->status = ACL_BINHASH_STAT_OK; + return (ht); +} + +/* acl_binhash_find - lookup value */ + +void *acl_binhash_find(ACL_BINHASH *table, const void *key, int key_len) +{ + ACL_BINHASH_INFO *ht; + unsigned n; + + n = table->hash_fn(key, key_len) % table->size; + + for (ht = table->data[n]; ht; ht = ht->next) { + if (key_len == ht->key_len && KEY_EQ(key, ht->key.c_key, key_len)) { + table->status = ACL_BINHASH_STAT_OK; + return (ht->value); + } + } + table->status = ACL_BINHASH_STAT_NO_KEY; + return (0); +} + +/* acl_binhash_locate - lookup entry */ + +ACL_BINHASH_INFO *acl_binhash_locate(ACL_BINHASH *table, const void *key, int key_len) +{ + ACL_BINHASH_INFO *ht; + unsigned n; + + n = table->hash_fn(key, key_len) % table->size; + + for (ht = table->data[n]; ht; ht = ht->next) { + if (key_len == ht->key_len && KEY_EQ(key, ht->key.c_key, key_len)) { + table->status = ACL_BINHASH_STAT_OK; + return (ht); + } + } + table->status = ACL_BINHASH_STAT_NO_KEY; + return (0); +} + +/* acl_binhash_delete - delete one entry */ + +int acl_binhash_delete(ACL_BINHASH *table, const void *key, int key_len, void (*free_fn) (void *)) +{ + ACL_BINHASH_INFO *ht, **h; + unsigned n; + + n = table->hash_fn(key, key_len) % table->size; + h = table->data + n; + + for (ht = *h; ht; ht = ht->next) { + if (key_len == ht->key_len && KEY_EQ(key, ht->key.c_key, key_len)) { + if (ht->next) + ht->next->prev = ht->prev; + if (ht->prev) + ht->prev->next = ht->next; + else + *h = ht->next; + if (free_fn) + (*free_fn) (ht->value); + if (!(table->flag & ACL_BINHASH_FLAG_KEY_REUSE)) + acl_myfree(ht->key.key); + if (table->slice) + acl_slice_free2(table->slice, ht); + else + acl_myfree(ht); + table->used--; + table->status = ACL_BINHASH_STAT_OK; + return (0); + } + } + table->status = ACL_BINHASH_STAT_NO_KEY; + return (-1); +} + +/* acl_binhash_free - destroy hash table */ + +void acl_binhash_free(ACL_BINHASH *table, void (*free_fn) (void *)) +{ + unsigned i = table->size; + ACL_BINHASH_INFO *ht; + ACL_BINHASH_INFO *next; + ACL_BINHASH_INFO **h = table->data; + + while (i-- > 0) { + for (ht = *h++; ht; ht = next) { + next = ht->next; + if (free_fn) + (*free_fn) (ht->value); + if (!(table->flag & ACL_BINHASH_FLAG_KEY_REUSE)) + acl_myfree(ht->key.key); + if (!table->slice) + acl_myfree(ht); +#if 0 + else + acl_slice_free2(table->slice, ht); +#endif + } + } + + acl_myfree(table->data); + if (table->slice) + acl_slice_destroy(table->slice); + acl_myfree(table); +} + +/* acl_binhash_walk - iterate over hash table */ + +void acl_binhash_walk(ACL_BINHASH *table, + void (*action) (ACL_BINHASH_INFO *, void *), void *ptr) +{ + unsigned i = table->size; + ACL_BINHASH_INFO **h = table->data; + ACL_BINHASH_INFO *ht; + + while (i-- > 0) + for (ht = *h++; ht; ht = ht->next) + (*action) (ht, ptr); +} + +/* acl_binhash_list - list all table members */ + +ACL_BINHASH_INFO **acl_binhash_list(ACL_BINHASH *table) +{ + ACL_BINHASH_INFO **list; + ACL_BINHASH_INFO *member; + int count = 0; + int i; + + list = (ACL_BINHASH_INFO **) acl_mymalloc(sizeof(*list) * (table->used + 1)); + for (i = 0; i < table->size; i++) + for (member = table->data[i]; member != 0; member = member->next) + list[count++] = member; + list[count] = 0; + return (list); +} + +int acl_binhash_errno(ACL_BINHASH *table) +{ + return (table->status); +} + +int acl_binhash_size(const ACL_BINHASH *table) +{ + if (table) + return (table->size); + else + return (0); +} + +int acl_binhash_used(ACL_BINHASH *table) +{ + return (table->used); +} + +ACL_BINHASH_INFO **acl_binhash_data(ACL_BINHASH *table) +{ + return ((ACL_BINHASH_INFO**) table->data); +} + +const ACL_BINHASH_INFO *acl_binhash_iter_head(ACL_BINHASH *table, ACL_BINHASH_ITER *iter) +{ + iter->i = 0; + iter->size = table->size; + iter->h = table->data; + iter->ptr = NULL; + + for (; iter->i < iter->size; iter->i++) { + if (iter->h[iter->i] != 0) { + iter->ptr = iter->h[iter->i]; + break; + } + } + + return (iter->ptr); +} + +const ACL_BINHASH_INFO *acl_binhash_iter_next(ACL_BINHASH_ITER *iter) +{ + if (iter->ptr) { + iter->ptr = iter->ptr->next; + if (iter->ptr != NULL) + return (iter->ptr); + } + + for (iter->i++; iter->i < iter->size; iter->i++) { + if (iter->h[iter->i] != 0) { + iter->ptr = iter->h[iter->i]; + break; + } + } + + return (iter->ptr); +} + +const ACL_BINHASH_INFO *acl_binhash_iter_tail(ACL_BINHASH *table, ACL_BINHASH_ITER *iter) +{ + iter->i = table->size - 1; + iter->size = table->size; + iter->h = table->data; + iter->ptr = NULL; + + for (; iter->i >= 0; iter->i--) { + if (iter->h[iter->i] != 0) { + iter->ptr = iter->h[iter->i]; + break; + } + } + + return (iter->ptr); +} + +const ACL_BINHASH_INFO *acl_binhash_iter_prev(ACL_BINHASH_ITER *iter) +{ + if (iter->ptr) { + iter->ptr = iter->ptr->next; + if (iter->ptr != NULL) + return (iter->ptr); + } + + for (iter->i--; iter->i >= 0; iter->i--) { + if (iter->h[iter->i] != 0) { + iter->ptr = iter->h[iter->i]; + break; + } + } + + return (iter->ptr); +} diff --git a/lib_acl/src/stdlib/common/acl_btree.c b/lib_acl/src/stdlib/common/acl_btree.c new file mode 100644 index 000000000..504ec743c --- /dev/null +++ b/lib_acl/src/stdlib/common/acl_btree.c @@ -0,0 +1,421 @@ +/* + * FILE: btree.c + * PROGRAM: RAT + * AUTHOR: O.Hodson + * MODIFIED: C.Perkins + * + * Binary tree implementation - Mostly verbatim from: + * + * Introduction to Algorithms by Corman, Leisserson, and Rivest, + * MIT Press / McGraw Hill, 1990. + * + */ + +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_msg.h" +#include "stdlib/acl_slice.h" +#include "stdlib/acl_btree.h" + +#endif + +typedef struct BTREE_NODE { + unsigned int key; + void *data; + struct BTREE_NODE *parent; + struct BTREE_NODE *left; + struct BTREE_NODE *right; + unsigned int magic; +} BTREE_NODE; + +struct ACL_BTREE { + BTREE_NODE *root; + unsigned int magic; + int count; + ACL_SLICE *slice; +}; + +/*****************************************************************************/ +/* Debugging functions... */ +/*****************************************************************************/ + +#define BTREE_MAGIC 0x10101010 +#define BTREE_NODE_MAGIC 0x01010101 + +#ifdef DEBUG +static int btree_count; + +static void btree_validate_node(BTREE_NODE *node, BTREE_NODE *parent) +{ + const char *myname = "btree_validate_node"; + + if (node->magic != BTREE_NODE_MAGIC) + acl_msg_fatal("%s(%d): magic(%u) invalid", myname, __LINE__, node->magic); + + if (node->parent != parent) + acl_msg_fatal("%s(%d): parent invalid", myname, __LINE__); + + btree_count++; + + if (node->left != NULL) { + btree_validate_node(node->left, node); + } + if (node->right != NULL) { + btree_validate_node(node->right, node); + } +} + +#endif + +static void btree_validate(ACL_BTREE *t) +{ + const char *myname = "btree_validate"; + + if (t->magic != BTREE_MAGIC) + acl_msg_fatal("%s(%d): magic(%u) invalid", myname, __LINE__, t->magic); + +#ifdef DEBUG + btree_count = 0; + if (t->root != NULL) { + btree_validate_node(t->root, NULL); + } + if (btree_count != t->count) + acl_msg_fatal("%s(%d): btree_count(%d) invalid", + myname, __LINE__, btree_count); +#endif +} + +/*****************************************************************************/ +/* Utility functions */ +/*****************************************************************************/ + +static BTREE_NODE *btree_min(BTREE_NODE *x) +{ + if (x == NULL) { + return (NULL); + } + while(x->left) { + x = x->left; + } + return (x); +} + +static BTREE_NODE *btree_max(BTREE_NODE *x) +{ + if (x == NULL) { + return (NULL); + } + while(x->right) { + x = x->right; + } + return (x); +} + +static BTREE_NODE *btree_successor(BTREE_NODE *x) +{ + BTREE_NODE *y; + + if (x->right != NULL) { + return (btree_min(x->right)); + } + + y = x->parent; + while (y != NULL && x == y->right) { + x = y; + y = y->parent; + } + + return (y); +} + +static BTREE_NODE *btree_search(BTREE_NODE *x, unsigned int key) +{ + while (x != NULL && key != x->key) { + if (key < x->key) { + x = x->left; + } else { + x = x->right; + } + } + return (x); +} + +static void btree_insert_node(ACL_BTREE *tree, BTREE_NODE *z) +{ + const char *myname = "btree_insert_node"; + BTREE_NODE *x, *y; + + btree_validate(tree); + y = NULL; + x = tree->root; + while (x != NULL) { + y = x; + if (z->key == x->key) + acl_msg_fatal("%s(%d): key(%u) exist", + myname, __LINE__, z->key); + if (z->key < x->key) { + x = x->left; + } else { + x = x->right; + } + } + + z->parent = y; + if (y == NULL) { + tree->root = z; + } else if (z->key < y->key) { + y->left = z; + } else { + y->right = z; + } + tree->count++; + btree_validate(tree); +} + +static BTREE_NODE *btree_delete_node(ACL_BTREE *tree, BTREE_NODE *z) +{ + BTREE_NODE *x, *y; + + btree_validate(tree); + if (z->left == NULL || z->right == NULL) { + y = z; + } else { + y = btree_successor(z); + } + + if (y->left != NULL) { + x = y->left; + } else { + x = y->right; + } + + if (x != NULL) { + x->parent = y->parent; + } + + if (y->parent == NULL) { + tree->root = x; + } else if (y == y->parent->left) { + y->parent->left = x; + } else { + y->parent->right = x; + } + + z->key = y->key; + z->data = y->data; + + tree->count--; + + btree_validate(tree); + return (y); +} + +/*****************************************************************************/ +/* Exported functions */ +/*****************************************************************************/ + +ACL_BTREE *acl_btree_create() +{ + ACL_BTREE *t = (ACL_BTREE*) acl_mymalloc(sizeof(ACL_BTREE)); + + if (t) { + t->count = 0; + t->magic = BTREE_MAGIC; + t->root = NULL; + t->slice = acl_slice_create("acl_btree", 0, + sizeof(BTREE_NODE), ACL_SLICE_FLAG_GC1); + return (t); + } + return (NULL); +} + +int acl_btree_destroy(ACL_BTREE *tree) +{ + const char *myname = "acl_btree_destroy"; + + btree_validate(tree); + if (tree->root != NULL) { + acl_msg_error("%s(%d): Tree not empty", myname, __LINE__); + return (-1); + } + + acl_slice_destroy(tree->slice); + acl_myfree(tree); + return (0); +} + +void *acl_btree_find(ACL_BTREE *tree, unsigned int key) +{ + BTREE_NODE *x; + + btree_validate(tree); + x = btree_search(tree->root, key); + if (x != NULL) { + return (x->data); + } + return (NULL); +} + +int acl_btree_add(ACL_BTREE *tree, unsigned int key, void *data) +{ + const char *myname = "acl_btree_add"; + BTREE_NODE *x; + + btree_validate(tree); + x = btree_search(tree->root, key); + if (x != NULL) { + acl_msg_error("%s(%d): Item already exists - key %u", + myname, __LINE__, key); + return (-1); + } + + x = (BTREE_NODE *) acl_slice_alloc(tree->slice); + x->key = key; + x->data = data; + x->parent = NULL; + x->left = NULL; + x->right = NULL; + x->magic = BTREE_NODE_MAGIC; + btree_insert_node(tree, x); + + return (0); +} + +void *acl_btree_remove(ACL_BTREE *tree, unsigned int key) +{ + const char *myname = "acl_btree_remove"; + BTREE_NODE *x; + void *data; + + btree_validate(tree); + x = btree_search(tree->root, key); + if (x == NULL) { + acl_msg_error("%s(%d): Item not on tree - key %u\n", + myname, __LINE__, key); + return (NULL); + } + + /* Note value that gets freed is not necessarily the the same + * as node that gets removed from tree since there is an + * optimization to avoid pointer updates in tree which means + * sometimes we just copy key and data from one node to another. + */ + + data = x->data; + x = btree_delete_node(tree, x); + acl_slice_free2(tree->slice, x); + + return (data); +} + +int acl_btree_get_min_key(ACL_BTREE *tree, unsigned int *key) +{ + BTREE_NODE *x; + + btree_validate(tree); + if (tree->root == NULL) { + return (-1); + } + + x = btree_min(tree->root); + if (x == NULL) { + return (-1); + } + + *key = x->key; + return (0); +} + +int acl_btree_get_max_key(ACL_BTREE *tree, unsigned int *key) +{ + BTREE_NODE *x; + + btree_validate(tree); + if (tree->root == NULL) { + return (-1); + } + + x = btree_max(tree->root); + if (x == NULL) { + return (-1); + } + + *key = x->key; + return (0); +} + +int acl_btree_get_next_key(ACL_BTREE *tree, + unsigned int cur_key, unsigned int *next_key) +{ + BTREE_NODE *x; + + btree_validate(tree); + x = btree_search(tree->root, cur_key); + if (x == NULL) { + return (-1); + } + + x = btree_successor(x); + if (x == NULL) { + return (-1); + } + + *next_key = x->key; + return (0); +} + +static int btree_depth(BTREE_NODE *x) +{ + int l, r; + + if (x == NULL) { + return (0); + } + + l = btree_depth(x->left); + r = btree_depth(x->right); + + if (l > r) { + return (l + 1); + } else { + return (r + 1); + } +} + +int acl_btree_depth(ACL_BTREE *tree) +{ + return (btree_depth(tree->root)); +} + +static void btree_dump_node(BTREE_NODE *x, int depth, int c, int w) +{ + int i; + + if (x == NULL) { + return; + } + + /* move(depth * 2, c); */ + for (i = 0; i < depth * 2; i++) { + printf("\r\n"); + } + for (i = 0; i < c; i++) { + printf("%c", ' '); + } + fflush(stdout); + + printf("%u\r\n", x->key); + + btree_dump_node(x->left, depth + 1, c - w/2, w/2); + btree_dump_node(x->right, depth + 1, c + w/2, w/2); +} + +void acl_btree_dump(ACL_BTREE *b) +{ + btree_dump_node(b->root, 0, 40, 48); +} diff --git a/lib_acl/src/stdlib/common/acl_cache.c b/lib_acl/src/stdlib/common/acl_cache.c new file mode 100644 index 000000000..cb3c3188b --- /dev/null +++ b/lib_acl/src/stdlib/common/acl_cache.c @@ -0,0 +1,457 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include "stdlib/acl_htable.h" +#include "stdlib/acl_ring.h" +#include "stdlib/acl_msg.h" +#include "stdlib/acl_mymalloc.h" +#include "thread/acl_pthread.h" +#include "stdlib/acl_slice.h" +#include "stdlib/acl_cache.h" + +#endif + +static void *cache_iter_head(ACL_ITER *iter, struct ACL_CACHE *cache) +{ + ACL_CACHE_INFO *ptr; + ACL_RING *ring; + + iter->dlen = -1; + iter->i = 0; + iter->size = cache->size; + iter->ptr = ring = acl_ring_succ(&cache->ring); + + if (ring != &cache->ring) { + ptr = ACL_RING_TO_APPL(ring, ACL_CACHE_INFO, entry); + iter->data = ptr->value; + iter->key = ptr->key; + } else { + iter->ptr = NULL; + iter->data = NULL; + iter->key = NULL; + } + return (iter->ptr); +} + +static void *cache_iter_next(ACL_ITER *iter, struct ACL_CACHE *cache) +{ + ACL_CACHE_INFO *ptr; + ACL_RING *ring; + + ring = (ACL_RING*) iter->ptr; + iter->ptr = ring = acl_ring_succ(ring); + if (ring != &cache->ring) { + ptr = ACL_RING_TO_APPL(ring, ACL_CACHE_INFO, entry); + iter->data = ptr->value; + iter->key = ptr->key; + iter->i++; + } else { + iter->ptr = NULL; + iter->data = NULL; + iter->key = NULL; + } + return (iter->ptr); +} + +static void *cache_iter_tail(ACL_ITER *iter, struct ACL_CACHE *cache) +{ + ACL_CACHE_INFO *ptr; + ACL_RING *ring; + + iter->dlen = -1; + iter->i = cache->size - 1; + iter->size = cache->size; + iter->ptr = ring = acl_ring_pred(&cache->ring); + + if (ring != &cache->ring) { + ptr = ACL_RING_TO_APPL(ring, ACL_CACHE_INFO, entry); + iter->data = ptr->value; + iter->key = ptr->key; + } else { + iter->ptr = NULL; + iter->data = NULL; + iter->key = NULL; + } + return (iter->ptr); +} + +static void *cache_iter_prev(ACL_ITER *iter, struct ACL_CACHE *cache) +{ + ACL_CACHE_INFO *ptr; + ACL_RING *ring; + + ring = (ACL_RING*) iter->ptr; + iter->ptr = ring = acl_ring_pred(ring); + if (ring != &cache->ring) { + ptr = ACL_RING_TO_APPL(ring, ACL_CACHE_INFO, entry); + iter->data = ptr->value; + iter->key = ptr->key; + iter->i--; + } else { + iter->ptr = NULL; + iter->data = NULL; + iter->key = NULL; + } + return (iter->ptr); +} + +static ACL_CACHE_INFO *cache_iter_info(ACL_ITER *iter, struct ACL_CACHE *cache) +{ + ACL_CACHE_INFO *ptr; + + if (iter->ptr == NULL || iter->ptr == &cache->ring) + return (NULL); + ptr = ACL_RING_TO_APPL((ACL_RING*) iter->ptr, ACL_CACHE_INFO, entry); + return (ptr); +} + +ACL_CACHE *acl_cache_create(int max_size, int timeout, + void (*free_fn)(const ACL_CACHE_INFO*, void*)) +{ + const char *myname = "acl_cache_create"; + ACL_CACHE *cache; + + if (max_size <= 0 || timeout <= 0) { + acl_msg_info("%s(%d): max_size(%d), timeout(%d), no need cache", + myname, __LINE__, max_size, timeout); + return (NULL); + } + + if (free_fn == NULL) + acl_msg_info("%s(%d), %s: free_fn null", + __FILE__, __LINE__, myname); + + cache = (ACL_CACHE *) acl_mycalloc(1, sizeof(ACL_CACHE)); + cache->max_size = max_size < 1 ? 1 : max_size; + cache->timeout = timeout < 0 ? 0 : timeout; + cache->free_fn = free_fn; + cache->table = acl_htable_create(100, 0); + cache->slice = acl_slice_create("acl_cache", 0, + sizeof(ACL_CACHE_INFO), ACL_SLICE_FLAG_GC1); + acl_ring_init(&cache->ring); + acl_pthread_mutex_init(&cache->lock, NULL); + + cache->iter_head = cache_iter_head; + cache->iter_next = cache_iter_next; + cache->iter_tail = cache_iter_tail; + cache->iter_prev = cache_iter_prev; + cache->iter_info = cache_iter_info; + + return (cache); +} + +void acl_cache_free(ACL_CACHE *cache) +{ + const char *myname = "acl_cache_free"; + ACL_CACHE_INFO *info; + + if (cache == NULL || cache->max_size <= 0) + return; + + while ((info = ACL_RING_FIRST_APPL(&cache->ring, ACL_CACHE_INFO, entry)) != 0) { + if (info->nrefer > 0) { + acl_msg_warn("%s(%d), %s: key(%s)'s nrefer(%d) > 0", + __FILE__, __LINE__, myname, info->key, info->nrefer); + info->nrefer = 0; /* force to set 0 */ + } + (void) acl_cache_delete(cache, info); + } + acl_htable_free(cache->table, NULL); + acl_pthread_mutex_destroy(&cache->lock); + acl_slice_destroy(cache->slice); + acl_myfree(cache); +} + +ACL_CACHE_INFO *acl_cache_enter(ACL_CACHE *cache, const char *key, void *value) +{ + const char *myname = "acl_cache_enter"; + ACL_CACHE_INFO *info; + + if (cache == NULL || cache->max_size <= 0) + return (NULL); + + info = (ACL_CACHE_INFO*) acl_htable_find(cache->table, key); + if (info != NULL) { + if (info->nrefer > 0) { + acl_msg_warn("%s(%d), %s: key(%s)'s old's" + " value's refer(%d) > 0", + __FILE__, __LINE__, myname, key, info->nrefer); + return (NULL); + } + if (cache->free_fn) + cache->free_fn(info, info->value); + info->value = value; + return (info); + } + + /* 如果发现缓存池溢出,则优先采用过期策略 */ + if (cache->size >= cache->max_size) { + (void) acl_cache_timeout(cache); + } + + /* 如果依然发现缓存池溢出,则采用删除最旧的数据策略 */ + if (cache->size >= cache->max_size) { + ACL_RING_ITER iter; + + /* 尽量删除一个最老的对象 */ + acl_ring_foreach(iter, &cache->ring) { + info = ACL_RING_TO_APPL(iter.ptr, ACL_CACHE_INFO, entry); + if (info->nrefer > 0 || info->when_timeout == 0) + continue; + (void) acl_cache_delete(cache, info); + break; + } + } + + /* 如果缓存池还是处于溢出状态,则直接返回不进行任务添加 */ + if (cache->size >= cache->max_size) { + acl_msg_error("%s(%d), %s: cache->size(%d) >= cache->max_size(%d)" + ", add key(%s) error", __FILE__, __LINE__, myname, + cache->size, cache->max_size, key); + return (NULL); + } + + info = (ACL_CACHE_INFO*) acl_slice_calloc(cache->slice); + info->key = acl_mystrdup(key); + if (acl_htable_enter(cache->table, key, (char*) info) == NULL) { + acl_msg_error("%s(%d), %s: add key(%s) to htable error(%s)", + __FILE__, __LINE__, myname, key, acl_last_serror()); + acl_slice_free2(cache->slice, info); + return (NULL); + } + cache->size++; + + info->value = value; + info->when_timeout = cache->timeout > 0 ? (time(NULL) + cache->timeout) : 0; + /* 将最新的数据添加在过期数据链的尾部, 当由链头向链尾方向遍历时,数据总是 + * 由最旧的数据向最新的数据开始,即:acl_ring_succ: 旧 --> 新 + */ + acl_ring_prepend(&cache->ring, &info->entry); + return (info); +} + +void *acl_cache_find(ACL_CACHE *cache, const char *key) +{ + ACL_CACHE_INFO *info; + + if (cache == NULL || cache->max_size <= 0) + return (NULL); + + info = (ACL_CACHE_INFO*) acl_htable_find(cache->table, key); + if (info != NULL) + return (info->value); + else + return (NULL); +} + +ACL_CACHE_INFO *acl_cache_locate(ACL_CACHE *cache, const char *key) +{ + ACL_CACHE_INFO *info; + + if (cache == NULL || cache->max_size <= 0) + return (NULL); + + info = (ACL_CACHE_INFO*) acl_htable_find(cache->table, key); + if (info != NULL) + return (info); + else + return (NULL); +} + +int acl_cache_delete(ACL_CACHE *cache, ACL_CACHE_INFO *info) +{ + if (cache == NULL || cache->max_size <= 0) + return (0); + + if (info->nrefer > 0) + return (-1); + if (acl_htable_delete(cache->table, info->key, NULL) < 0) + return (-1); + acl_ring_detach(&info->entry); + if (cache->free_fn) + cache->free_fn(info, info->value); + acl_myfree(info->key); + acl_slice_free2(cache->slice, info); + cache->size--; + return (0); +} + +int acl_cache_delete2(ACL_CACHE *cache, const char *key) +{ + ACL_CACHE_INFO *info; + + if (cache == NULL || cache->max_size <= 0) + return (0); + + info = (ACL_CACHE_INFO*) acl_htable_find(cache->table, key); + if (info == NULL) + return (-1); + if (info->nrefer > 0) + return (-1); + return (acl_cache_delete(cache, info)); +} + +int acl_cache_timeout(ACL_CACHE *cache) +{ + ACL_CACHE_INFO *info; + time_t now = time(NULL); + ACL_RING *iter, *iter_next; + int n = 0; + + if (cache == NULL || cache->max_size <= 0) + return (n); + + /* 因为数据链的添加是尾部添加的,所以从首部至尾部数据依次由旧变新 */ + for (iter = acl_ring_succ(&cache->ring); iter != &cache->ring;) { + info = ACL_RING_TO_APPL(iter, ACL_CACHE_INFO, entry); + if (info->when_timeout > now) + break; + if (info->nrefer > 0) { + iter = acl_ring_succ(iter); + continue; + } + if (info->when_timeout == 0) { + iter = acl_ring_succ(iter); + continue; + } + iter_next = acl_ring_succ(iter); + if (acl_cache_delete(cache, info) == 0) + n++; + iter = iter_next; + } + return (n); +} + +void acl_cache_update2(ACL_CACHE *cache, ACL_CACHE_INFO *info, int timeout) +{ + if (cache == NULL || cache->max_size <= 0) + return; + + acl_ring_detach(&info->entry); + info->when_timeout = timeout > 0 ? (time(NULL) + timeout) : 0; + /* 将最新的数据添加在过期数据链的尾部, 当由链头向链尾方向遍历时,数据总是 + * 由最旧的数据向最新的数据开始,即:acl_ring_succ: 旧 --> 新 + */ + acl_ring_prepend(&cache->ring, &info->entry); +} + +void acl_cache_update(ACL_CACHE *cache, const char *key, int timeout) +{ + ACL_CACHE_INFO *info; + + if (cache == NULL || cache->max_size <= 0) + return; + + info = (ACL_CACHE_INFO*) acl_htable_find(cache->table, key); + if (info) + acl_cache_update2(cache, info, timeout); +} + +void acl_cache_refer(ACL_CACHE_INFO *info) +{ + info->nrefer++; +} + +void acl_cache_refer2(ACL_CACHE *cache, const char *key) +{ + ACL_CACHE_INFO *info; + + if (cache == NULL || cache->max_size <= 0) + return; + + info = (ACL_CACHE_INFO*) acl_htable_find(cache->table, key); + if (info == NULL) + return; + info->nrefer++; +} + +void acl_cache_unrefer2(ACL_CACHE *cache, const char *key) +{ + ACL_CACHE_INFO *info; + + if (cache == NULL || cache->max_size <= 0) + return; + + info = (ACL_CACHE_INFO*) acl_htable_find(cache->table, key); + if (info == NULL) + return; + info->nrefer--; +} + +void acl_cache_unrefer(ACL_CACHE_INFO *info) +{ + const char *myname = "acl_cache_unrefer"; + + info->nrefer--; + if (info->nrefer < 0) + acl_msg_warn("%s(%d), %s: key(%s)'s nrefer(%d) invalid", + __FILE__, __LINE__, myname, info->key, info->nrefer); +} + +void acl_cache_lock(ACL_CACHE *cache) +{ + if (cache == NULL || cache->max_size <= 0) + return; + acl_pthread_mutex_lock(&cache->lock); +} + +void acl_cache_unlock(ACL_CACHE *cache) +{ + if (cache == NULL || cache->max_size <= 0) + return; + acl_pthread_mutex_unlock(&cache->lock); +} + +void acl_cache_walk(ACL_CACHE *cache, void (*walk_fn)(ACL_CACHE_INFO*, void*), void *arg) +{ + ACL_CACHE_INFO *info; + ACL_RING_ITER iter; + + if (cache == NULL || cache->max_size <= 0) + return; + acl_ring_foreach(iter, &cache->ring) { + info = ACL_RING_TO_APPL(iter.ptr, ACL_CACHE_INFO, entry); + walk_fn(info, arg); + } +} + +int acl_cache_clean(ACL_CACHE *cache, int force) +{ + const char *myname = "acl_cache_clean"; + ACL_CACHE_INFO *info; + ACL_RING *iter, *iter_next; + int n = 0; + + if (cache == NULL || cache->max_size <= 0) + return (0); + + for (iter = acl_ring_succ(&cache->ring); iter != &cache->ring;) { + info = ACL_RING_TO_APPL(iter, ACL_CACHE_INFO, entry); + if (info->nrefer > 0) { + if (force == 0) { + iter = acl_ring_succ(iter); + continue; + } else { + acl_msg_warn("%s(%d), %s: key(%s)'s refer(%d) > 0", + __FILE__, __LINE__, myname, + info->key, info->nrefer); + info->nrefer = 0; /* force set 0 */ + } + } + iter_next = acl_ring_succ(iter); + if (acl_cache_delete(cache, info) == 0) + n++; + iter = iter_next; + } + + return (n); +} + +int acl_cache_size(ACL_CACHE *cache) +{ + if (cache == NULL || cache->max_size <= 0) + return (0); + return (cache->size); +} diff --git a/lib_acl/src/stdlib/common/acl_cache2.c b/lib_acl/src/stdlib/common/acl_cache2.c new file mode 100644 index 000000000..af936474a --- /dev/null +++ b/lib_acl/src/stdlib/common/acl_cache2.c @@ -0,0 +1,630 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include "stdlib/acl_htable.h" +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_msg.h" +#include "stdlib/avl.h" +#include "stdlib/acl_cache2.h" + +#endif + +typedef struct { + ACL_CACHE2 cache; /**< 封装了 ACL_CACHE2 */ + ACL_HTABLE *table; /**< 哈希表 */ + avl_tree_t avl; /**< 用于按时间排序的平稳二叉树 */ + acl_pthread_mutex_t lock; /**< 缓存池锁 */ +} CACHE; + +typedef struct CACHE_INFO CACHE_INFO; + +typedef struct TREE_NODE { + CACHE_INFO *head; + CACHE_INFO *tail; + avl_node_t node; + time_t when_timeout; +} TREE_NODE; + +struct CACHE_INFO { + ACL_CACHE2_INFO info; + TREE_NODE *tree_node; + CACHE_INFO *prev; + CACHE_INFO *next; +}; + +/** + * AVL 用的比较回调函数 + */ +static int cmp_fn(const void *v1, const void *v2) +{ + const TREE_NODE *n1 = (const TREE_NODE*) v1; + const TREE_NODE *n2 = (const TREE_NODE*) v2; + time_t ret = n1->when_timeout - n2->when_timeout; + + if (ret < 0) + return (-1); + else if (ret > 0) + return (1); + else + return (0); +} + +static void *cache_iter_head(ACL_ITER *iter, struct ACL_CACHE2 *cache2) +{ + CACHE *cache = (CACHE*) cache2; + CACHE_INFO *info; + TREE_NODE *pnode; + + iter->dlen = -1; + iter->i = 0; + iter->size = cache2->size; + + pnode = avl_first(&cache->avl); + if (pnode == NULL) { + iter->ptr = NULL; + iter->data = NULL; + iter->key = NULL; + return (iter->ptr); + } + + iter->ptr = info = pnode->head; + acl_assert(info); + iter->data = ((ACL_CACHE2_INFO *) info)->value; + iter->key = ((ACL_CACHE2_INFO *) info)->key; + return (iter->ptr); +} + +static void *cache_iter_next(ACL_ITER *iter, struct ACL_CACHE2 *cache2) +{ + CACHE *cache = (CACHE*) cache2; + CACHE_INFO *info = (CACHE_INFO*) iter->ptr; + TREE_NODE *pnode = info->tree_node; + + info = info->next; + if (info) { + iter->ptr = info; + iter->data = ((ACL_CACHE2_INFO *) info)->value; + iter->key = ((ACL_CACHE2_INFO *) info)->key; + iter->i++; + return (iter->ptr); + } + + pnode = AVL_NEXT(&cache->avl, pnode); + if (pnode == NULL) { + iter->ptr = NULL; + iter->data = NULL; + iter->key = NULL; + return (iter->ptr); + } + + iter->ptr = info = pnode->head; + acl_assert(info); + iter->data = ((ACL_CACHE2_INFO *) info)->value; + iter->key = ((ACL_CACHE2_INFO *) info)->key; + iter->i++; + return (iter->ptr); +} + +static void *cache_iter_tail(ACL_ITER *iter, struct ACL_CACHE2 *cache2) +{ + CACHE *cache = (CACHE*) cache2; + CACHE_INFO *info; + TREE_NODE *pnode; + + iter->dlen = -1; + iter->i = cache2->size - 1; + iter->size = cache2->size; + + pnode = avl_last(&cache->avl); + if (pnode == NULL) { + iter->ptr = NULL; + iter->data = NULL; + iter->key = NULL; + return (iter->ptr); + } + + iter->ptr = info = pnode->tail; + acl_assert(info); + iter->data = ((ACL_CACHE2_INFO *) info)->value; + iter->key = ((ACL_CACHE2_INFO *) info)->key; + return (iter->ptr); +} + +static void *cache_iter_prev(ACL_ITER *iter, struct ACL_CACHE2 *cache2) +{ + CACHE *cache = (CACHE*) cache2; + CACHE_INFO *info = (CACHE_INFO*) iter->ptr; + TREE_NODE *pnode = info->tree_node; + + info = info->prev; + if (info) { + iter->ptr = info; + iter->data = ((ACL_CACHE2_INFO *) info)->value; + iter->key = ((ACL_CACHE2_INFO *) info)->key; + iter->i++; + return (iter->ptr); + } + + pnode = AVL_PREV(&cache->avl, pnode); + if (pnode == NULL) { + iter->ptr = NULL; + iter->data = NULL; + iter->key = NULL; + return (iter->ptr); + } + + iter->ptr = info = pnode->tail; + acl_assert(info); + iter->data = ((ACL_CACHE2_INFO *) info)->value; + iter->key = ((ACL_CACHE2_INFO *) info)->key; + iter->i++; + return (iter->ptr); +} + +static ACL_CACHE2_INFO *cache_iter_info(ACL_ITER *iter, struct ACL_CACHE2 *cache2 acl_unused) +{ + if (iter->ptr == NULL) + return (NULL); + return ((ACL_CACHE2_INFO*) iter->ptr); +} + +ACL_CACHE2 *acl_cache2_create(int max_size, + void (*free_fn)(const ACL_CACHE2_INFO*, void*)) +{ + const char *myname = "acl_cache2_create"; + ACL_CACHE2 *cache2; + CACHE *cache; + + if (max_size <= 0) { + acl_msg_info("%s(%d): max_size(%d), no need cache", + myname, __LINE__, max_size); + return (NULL); + } + + if (free_fn == NULL) + acl_msg_info("%s(%d), %s: free_fn null", + __FILE__, __LINE__, myname); + + cache = (CACHE *) acl_mycalloc(1, sizeof(CACHE)); + cache->table = acl_htable_create(100, 0); + avl_create(&cache->avl, cmp_fn, sizeof(TREE_NODE), offsetof(TREE_NODE, node)); + acl_pthread_mutex_init(&cache->lock, NULL); + + cache2 = (ACL_CACHE2*) cache; + cache2->max_size = max_size < 1 ? 1 : max_size; + cache2->free_fn = free_fn; + cache2->iter_head = cache_iter_head; + cache2->iter_next = cache_iter_next; + cache2->iter_tail = cache_iter_tail; + cache2->iter_prev = cache_iter_prev; + cache2->iter_info = cache_iter_info; + return (cache2); +} + +void acl_cache2_free(ACL_CACHE2 *cache2) +{ + const char *myname = "acl_cache2_free"; + CACHE *cache = (CACHE*) cache2; + TREE_NODE *pnode; + ACL_CACHE2_INFO *info2; + CACHE_INFO *info; + + if (cache == NULL) + return; + + pnode = (TREE_NODE*) avl_first(&cache->avl); + while (pnode) { + info = pnode->head; + pnode = AVL_NEXT(&cache->avl, pnode); + while (info) { + info2 = (ACL_CACHE2_INFO*) info; + info = info->next; + if (info2->nrefer > 0) { + acl_msg_warn("%s(%d): key(%s)'s nrefer(%d) > 0", + myname, __LINE__, info2->key, info2->nrefer); + info2->nrefer = 0; /* force to set 0 */ + } + (void) acl_cache2_delete(cache2, info2); + } + } + + avl_destroy(&cache->avl); + acl_htable_free(cache->table, NULL); + acl_pthread_mutex_destroy(&cache->lock); + acl_myfree(cache); +} + +ACL_CACHE2_INFO *acl_cache2_enter(ACL_CACHE2 *cache2, + const char *key, void *value, int timeout) +{ + const char *myname = "acl_cache2_enter"; + CACHE *cache = (CACHE *) cache2; + ACL_CACHE2_INFO *info2; + CACHE_INFO *info; + TREE_NODE *pnode, node; + time_t when_timeout = time(NULL) + timeout; + + if (cache == NULL) + return (NULL); + + info2 = (ACL_CACHE2_INFO*) acl_htable_find(cache->table, key); + if (info2 != NULL) { + if (info2->nrefer > 0) { + acl_msg_warn("%s(%d): key(%s)'s old's" + " value's refer(%d) > 0", + myname, __LINE__, key, info2->nrefer); + return (NULL); + } + if (cache2->free_fn) + cache2->free_fn(info2, info2->value); + info2->value = value; + return (info2); + } + + /* 如果发现缓存池溢出,则优先采用过期策略 */ + if (cache2->size >= cache2->max_size) { + (void) acl_cache2_timeout(cache2); + } + + /* 如果依然发现缓存池溢出,则采用删除最旧的数据策略 */ + if (cache2->size >= cache2->max_size) { + pnode = (TREE_NODE*) avl_first(&cache->avl); + while (pnode) { + ACL_CACHE2_INFO *tmp = NULL; + if (pnode->when_timeout == 0) { + pnode = AVL_NEXT(&cache->avl, pnode); + continue; + } + info = pnode->head; + pnode = AVL_NEXT(&cache->avl, pnode); + while (info) { + info2 = (ACL_CACHE2_INFO*) info; + info = info->next; + if (info2->nrefer == 0) { + tmp = info2; + break; + } + } + if (tmp != NULL) { + (void) acl_cache2_delete(cache2, tmp); + break; + } + } + } + + /* 如果缓存池还是处于溢出状态,则直接返回不进行任务添加 */ + if (cache2->size >= cache2->max_size) { + acl_msg_error("%s(%d): cache->size(%d) >= cache->max_size(%d)" + ", add key(%s) error", myname, __LINE__, + cache2->size, cache2->max_size, key); + return (NULL); + } + + node.when_timeout = timeout > 0 ? when_timeout : 0; + pnode = (TREE_NODE*) avl_find(&cache->avl, &node, NULL); + if (pnode == NULL) { + pnode = (TREE_NODE*) acl_mycalloc(1, sizeof(TREE_NODE)); + pnode->when_timeout = node.when_timeout; + avl_add(&cache->avl, pnode); + } + + info = (CACHE_INFO*) acl_mycalloc(1, sizeof(CACHE_INFO)); + info2 = (ACL_CACHE2_INFO*) info; + + info2->value = value; + info2->key = acl_mystrdup(key); + if (acl_htable_enter(cache->table, key, (char*) info2) == NULL) { + acl_msg_fatal("%s(%d): add key(%s) to htable error(%s)", + myname, __LINE__, key, acl_last_serror()); + } + + if (pnode->tail == NULL) { + info->prev = info->next = NULL; + pnode->head = pnode->tail = info; + } else { + pnode->tail->next = info; + info->prev = pnode->tail; + info->next = NULL; + pnode->tail = info; + } + info->tree_node = pnode; + info2->when_timeout = pnode->when_timeout; + + cache2->size++; + return (info2); +} + +void *acl_cache2_find(ACL_CACHE2 *cache2, const char *key) +{ + CACHE *cache = (CACHE*) cache2; + ACL_CACHE2_INFO *info; + + if (cache2 == NULL || cache2->max_size <= 0) + return (NULL); + + info = (ACL_CACHE2_INFO*) acl_htable_find(cache->table, key); + if (info != NULL) + return (info->value); + else + return (NULL); +} + +ACL_CACHE2_INFO *acl_cache2_locate(ACL_CACHE2 *cache2, const char *key) +{ + ACL_CACHE2_INFO *info; + CACHE *cache = (CACHE*) cache2; + + if (cache2 == NULL || cache2->max_size <= 0) + return (NULL); + + info = (ACL_CACHE2_INFO*) acl_htable_find(cache->table, key); + if (info != NULL) + return (info); + else + return (NULL); +} + +int acl_cache2_delete(ACL_CACHE2 *cache2, ACL_CACHE2_INFO *info2) +{ + CACHE_INFO *info = (CACHE_INFO*) info2; + TREE_NODE *pnode = info->tree_node; + CACHE *cache = (CACHE*) cache2; + + if (cache2 == NULL || cache2->max_size <= 0) + return (0); + + if (info2->nrefer > 0) + return (-1); + if (acl_htable_delete(cache->table, info2->key, NULL) < 0) + return (-1); + + if (info->prev) + info->prev->next = info->next; + else + pnode->head = info->next; + if (info->next) + info->next->prev = info->prev; + else + pnode->tail = info->prev; + + if (cache2->free_fn) + cache2->free_fn(info2, info2->value); + acl_myfree(info2->key); + acl_myfree(info2); + cache2->size--; + + if (pnode->head == NULL) { + avl_remove(&cache->avl, pnode); + acl_myfree(pnode); + } + return (0); +} + +int acl_cache2_delete2(ACL_CACHE2 *cache2, const char *key) +{ + CACHE *cache = (CACHE*) cache2; + ACL_CACHE2_INFO *info2; + + if (cache2 == NULL || cache2->max_size <= 0) + return (0); + + info2 = (ACL_CACHE2_INFO*) acl_htable_find(cache->table, key); + if (info2 == NULL) + return (-1); + if (info2->nrefer > 0) + return (-1); + return (acl_cache2_delete(cache2, info2)); +} + +int acl_cache2_timeout(ACL_CACHE2 *cache2) +{ + CACHE *cache = (CACHE*) cache2; + ACL_CACHE2_INFO *info2; + CACHE_INFO *info; + TREE_NODE *pnode, *pnode_next; + time_t now = time(NULL); + int n = 0; + + if (cache2 == NULL || cache2->max_size <= 0) + return (n); + + pnode = (TREE_NODE*) avl_first(&cache->avl); + while (1) { + if (pnode == NULL || pnode->when_timeout > now) + break; + if (pnode->when_timeout == 0) { + pnode = AVL_NEXT(&cache->avl, pnode); + continue; + } + pnode_next = AVL_NEXT(&cache->avl, pnode); + info = pnode->head; + while (info) { + info2 = (ACL_CACHE2_INFO*) info; + info = info->next; + if (info2->nrefer > 0) + continue; + if (acl_cache2_delete(cache2, info2) == 0) + n++; + } + pnode = pnode_next; + } + return (n); +} + +void acl_cache2_update2(ACL_CACHE2 *cache2, ACL_CACHE2_INFO *info2, int timeout) +{ + CACHE *cache = (CACHE*) cache2; + CACHE_INFO *info = (CACHE_INFO*) info2; + TREE_NODE *pnode = info->tree_node, node; + + if (cache2 == NULL || cache2->max_size <= 0) + return; + + if (info->prev) + info->prev->next = info->next; + else + pnode->head = info->next; + if (info->next) + info->next->prev = info->prev; + else + pnode->tail = info->prev; + + if (pnode->head == NULL) { + avl_remove(&cache->avl, pnode); + acl_myfree(pnode); + } + + node.when_timeout = timeout > 0 ? timeout : 0; + pnode = (TREE_NODE*) avl_find(&cache->avl, &node, NULL); + if (pnode == NULL) { + pnode = (TREE_NODE*) acl_mycalloc(1, sizeof(TREE_NODE)); + pnode->when_timeout = node.when_timeout; + avl_add(&cache->avl, pnode); + } + + if (pnode->tail == NULL) { + info->prev = info->next = NULL; + pnode->head = pnode->tail = info; + } else { + pnode->tail->next = info; + info->prev = pnode->tail; + info->next = NULL; + pnode->tail = info; + } + info->tree_node = pnode; + info2->when_timeout = pnode->when_timeout; +} + +void acl_cache2_update(ACL_CACHE2 *cache2, const char *key, int timeout) +{ + CACHE *cache = (CACHE*) cache2; + ACL_CACHE2_INFO *info2; + + if (cache2 == NULL || cache2->max_size <= 0) + return; + + info2 = (ACL_CACHE2_INFO*) acl_htable_find(cache->table, key); + if (info2) + acl_cache2_update2(cache2, info2, timeout); +} + +void acl_cache2_refer(ACL_CACHE2_INFO *info2) +{ + info2->nrefer++; +} + +void acl_cache2_refer2(ACL_CACHE2 *cache2, const char *key) +{ + CACHE *cache = (CACHE*) cache2; + ACL_CACHE2_INFO *info2; + + if (cache2 == NULL || cache2->max_size <= 0) + return; + + info2 = (ACL_CACHE2_INFO*) acl_htable_find(cache->table, key); + if (info2 == NULL) + return; + info2->nrefer++; +} + +void acl_cache2_unrefer2(ACL_CACHE2 *cache2, const char *key) +{ + CACHE *cache = (CACHE*) cache2; + ACL_CACHE2_INFO *info2; + + if (cache2 == NULL || cache2->max_size <= 0) + return; + + info2 = (ACL_CACHE2_INFO*) acl_htable_find(cache->table, key); + if (info2 == NULL) + return; + info2->nrefer--; +} + +void acl_cache2_unrefer(ACL_CACHE2_INFO *info2) +{ + const char *myname = "acl_cache2_unrefer"; + + info2->nrefer--; + if (info2->nrefer < 0) + acl_msg_warn("%s(%d): key(%s)'s nrefer(%d) invalid", + myname, __LINE__, info2->key, info2->nrefer); +} + +void acl_cache2_lock(ACL_CACHE2 *cache2) +{ + CACHE *cache = (CACHE*) cache2; + if (cache2 == NULL || cache2->max_size <= 0) + return; + acl_pthread_mutex_lock(&cache->lock); +} + +void acl_cache2_unlock(ACL_CACHE2 *cache2) +{ + CACHE *cache = (CACHE*) cache2; + + if (cache2 == NULL || cache2->max_size <= 0) + return; + acl_pthread_mutex_unlock(&cache->lock); +} + +void acl_cache2_walk(ACL_CACHE2 *cache2, + void (*walk_fn)(ACL_CACHE2_INFO*, void*), void *arg) +{ + CACHE *cache = (CACHE*) cache2; + ACL_CACHE2_INFO *info2; + CACHE_INFO *info; + TREE_NODE *pnode; + + if (cache2 == NULL || cache2->max_size <= 0) + return; + + pnode = (TREE_NODE*) avl_first(&cache->avl); + while (1) { + if (pnode == NULL) + break; + info = pnode->head; + while (info) { + info2 = (ACL_CACHE2_INFO*) info; + walk_fn(info2, arg); + info = info->next; + } + pnode = AVL_NEXT(&cache->avl, pnode); + } +} + +int acl_cache2_clean(ACL_CACHE2 *cache2, int force) +{ + CACHE *cache = (CACHE*) cache2; + ACL_CACHE2_INFO *info2; + CACHE_INFO *info; + TREE_NODE *pnode; + int n = 0; + + if (cache2 == NULL || cache2->max_size <= 0) + return (0); + + pnode = (TREE_NODE*) avl_first(&cache->avl); + while (pnode) { + info = pnode->head; + pnode = AVL_NEXT(&cache->avl, pnode); + while (info) { + info2 = (ACL_CACHE2_INFO*) info; + info = info->next; + if (info2->nrefer > 0 && force == 0) + continue; + if (acl_cache2_delete(cache2, info2) == 0) + n++; + } + } + return (n); +} + +int acl_cache2_size(ACL_CACHE2 *cache2) +{ + if (cache2 == NULL || cache2->max_size <= 0) + return (0); + return (cache2->size); +} diff --git a/lib_acl/src/stdlib/common/acl_dlink.c b/lib_acl/src/stdlib/common/acl_dlink.c new file mode 100644 index 000000000..f4ba1c98f --- /dev/null +++ b/lib_acl/src/stdlib/common/acl_dlink.c @@ -0,0 +1,794 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#ifdef ACL_UNIX +#include +#endif + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_mystring.h" +#include "stdlib/acl_msg.h" +#include "stdlib/acl_array.h" +#include "stdlib/acl_dlink.h" + +#endif + +static void dlink_free_callback(void *arg) +{ + ACL_DITEM *pitem; + + if(arg == NULL) + return; + pitem = (ACL_DITEM *) arg; + pitem->pnode = NULL; /* sanity set to be null */ + + acl_myfree(pitem); +} + +/* + * 功能: 找出某个长整数在数组中的下标范围位置 + * 参数: + * a: 结构数组指针 + * n: 长整数 + * 返回值: 下标索引, 该索引满足如下条件: + * (idx >= 0 && idx < a->count - 1 + * && n >= a->items[idx]->begin + * && n < a->item[a->count - 1]->begin ) + * or (idx == 0 && n < a->item[idx]->begin) + * or (idx == a->count - 1 && n >= a->item[idx]->begin) + * 失败: -1 + * 成功: >= 0 + * 说明: if idx == 0 ----> 说明在数组的开始位置添加或在开始位置前插入 + * if idx > 0 && idx <= a->count - 1 -----> 说明在数组的中间的某一位置 + * if idx > a->count - 1 -----> 说明在数组的最后一位置添加 + */ +static int scope_pos(const ACL_ARRAY *a, acl_uint64 n) +{ + ACL_DITEM *pitem_left, *pitem_right; + int lidx, hidx, midx, ridx, idx; + + lidx = 0; + hidx = acl_array_size(a) - 1; + ridx = 0; + idx = 0; + while(lidx <= hidx) { + /* + * find the postion where n >= item_low->begin + * and n < item_high->begin + * NOTICE: + * item_low->begin <= item_low->end < item_high->begin !!!! + * because the dlink is sorted correctly, or some error must happen + * if(item_low->begin == item_high->begin + * || item_low->end == item_high->begin) + * then we should merge them first + */ + + midx = (lidx + hidx)/2; + ridx = midx + 1; + if(ridx > hidx) { + /* + * here hidx == 0 or hidx == a->count - 1, we've been + * out of the search scope now, so break out of the loop + */ + + if(hidx == 0) + idx = 0; + else if (hidx == acl_array_size(a) - 1) + idx = acl_array_size(a) - 1; + else /* an error happens */ + idx = -1; + break; + } + + pitem_left = (ACL_DITEM *) acl_array_index(a, midx); + pitem_right = (ACL_DITEM *) acl_array_index(a, ridx); + + if(n >= pitem_left->begin && n < pitem_right->begin) { + idx = midx; /* find it :) */ + break; + } + /* not find, continue...... */ + if(n >= pitem_right->begin) + lidx = ridx; + else if(n < pitem_left->begin) + hidx = midx; + else { /* why does the array not to be sorted ? */ + idx = -1; + break; + } + } + + return idx; +} + +static int begin_pos(const ACL_ARRAY *a, acl_uint64 n) +{ + return scope_pos(a, n); +} + +static int end_pos(const ACL_ARRAY *a, acl_uint64 n) +{ + return scope_pos(a, n); +} + +#ifdef _USE_PRED_INSERT_ +static ACL_DITEM *dlink_pred_insert(ACL_ARRAY *a, int idx_position, + acl_uint64 begin, acl_uint64 end) +{ + ACL_DITEM *pitem; + int ret; + + pitem = acl_mymalloc(sizeof(ACL_DITEM)); + if(pitem == NULL) + return NULL; + pitem->begin = begin; + pitem->end = end; + ret = acl_array_pred_insert(a, idx_position, pitem); + if(ret < 0) { + acl_myfree(pitem); + return NULL; + } + pitem->pnode = NULL; + + return pitem; +} +#endif + +static ACL_DITEM *dlink_succ_insert(ACL_ARRAY *a, int idx_position, + acl_uint64 begin, acl_uint64 end) +{ + ACL_DITEM *pitem; + int ret; + + pitem = (ACL_DITEM *) acl_mymalloc(sizeof(ACL_DITEM)); + if(pitem == NULL) + return NULL; + pitem->begin = begin; + pitem->end = end; + ret = acl_array_succ_insert(a, idx_position, pitem); + if(ret < 0) { + acl_myfree(pitem); + return NULL; + } + pitem->pnode = NULL; + + return pitem; +} + +static ACL_DITEM *dlink_append(ACL_ARRAY *a, acl_uint64 begin, acl_uint64 end) +{ + ACL_DITEM *pitem; + int ret; + + pitem = (ACL_DITEM *) acl_mymalloc(sizeof(ACL_DITEM)); + if(pitem == NULL) + return NULL; + pitem->begin = begin; + pitem->end = end; + ret = acl_array_append(a, pitem); + if(ret < 0) { + acl_myfree(pitem); + return NULL; + } + pitem->pnode = NULL; + + return pitem; +} + +static ACL_DITEM *dlink_prepend(ACL_ARRAY *a, acl_uint64 begin, acl_uint64 end) +{ + ACL_DITEM *pitem; + int ret; + + pitem = (ACL_DITEM *) acl_mymalloc(sizeof(ACL_DITEM)); + if(pitem == NULL) + return NULL; + pitem->begin = begin; + pitem->end = end; + ret = acl_array_prepend(a, pitem); + if(ret < 0) { + acl_myfree(pitem); + return NULL; + } + pitem->pnode = NULL; + + return pitem; +} + +static int dlink_node_merge(ACL_ARRAY *a, int idx_obj_begin, int idx_src_begin) +{ + int ret; + + if(idx_obj_begin >= idx_src_begin) + return 0; + + ret = acl_array_mv_idx(a, idx_obj_begin, idx_src_begin, dlink_free_callback); + if(ret < 0) + return -1; + + return 0; +} + +static ACL_DITEM *dlink_add(ACL_ARRAY *a, acl_uint64 begin, acl_uint64 end) +{ + ACL_DITEM *pitem_right, *pitem_left, *pitem; + int idx_begin, idx_end; + int ret; + + /* sanity check, maybe useless */ + /* because it's used internal */ + if(begin > end) + return NULL; + + idx_begin = begin_pos(a, begin); + if(idx_begin < 0 || idx_begin >= acl_array_size(a)) /* an error happened */ + return NULL; + + idx_end = end_pos(a, end); + if(idx_end < 0 || idx_end >= acl_array_size(a)) /* an error happened */ + return NULL; + + if(idx_begin > idx_end) /* an error happened */ + return NULL; + + if(acl_array_size(a) == 0) { /* the d-link is empty so just add one :) */ + pitem = dlink_append(a, begin, end); + return pitem; + } + + pitem_left = (ACL_DITEM *) acl_array_index(a, idx_begin); + pitem_right = (ACL_DITEM *) acl_array_index(a, idx_end); + + /* if idx_end == 0 then idx_begin must be equal to 0, I'm sure it :) */ + if (idx_begin == idx_end) { + /* + * pitem_left == pitem_right + * here idx_begin maybe one of: 0, a->count - 1, + * or the one between 0 and a->count + * this is to say the begin and end is on the same d-link + */ + + if (end < pitem_left->begin) { + /* + * here idx_begin == idx_end must be equal to 0 + * the begin and the end must be less + * than the next node's begin + * add one new node before the one + */ + pitem = dlink_prepend(a, begin, end); + return pitem; + } + + if (begin > pitem_left->end) { + /* + * this is to say begin and end + * between the current node's end + * the next node's begin, and we just + * insert one new node between the + * current node and the next node, when + * the next node is NULL(which say that + * idx_begin == idx_end == a->count - 1), + * just insert one new node after + * the the last node + */ + pitem = dlink_succ_insert(a, idx_begin, begin, end); + return pitem; + } + + /* + * here idx_begin == idx_end must in the middle + * here begin <= pitem_left->end, + * and end < the next node's begin, + * and end >= pitem_left->begin + */ + + if (begin < pitem_left->begin) + /* + * just merge, which happens when + * idx_begin == idx_end == 0 && begin < pitem_left->begin + * && end >= pitem_left->begin + */ + pitem_left->begin = begin; + + if (end > pitem_left->end) + /* + * just merge, pitem_left->begin <= pitem_left->end + * pitem_left->begin <= end < pitem_right->end + * or pitem_right == NULL + */ + pitem_left->end = end; + + return pitem_left; + } + + /* + * idx_end > idx_begin, idx_begin >= 0, idx_end <= a->count - 1 + * ===> 0 <= idx_begin < idx_end <= a->count - 1; + * + * idx_end > idx_begin, so the begin and end + * are separately in defferent node, + * because the d-link is sored correctly:). + * ===> I just only merge them--the reason is shown below: + * idx_end > idx_begin, d-link is sorted correctly + * ===> pitem_left->begin < pitem_right->begin <= end, + * begin < pitem_right->begin; + */ + + if(begin < pitem_left->begin) { + /* + * in the first position of the array + * idx_begin == 0 and idx_end >= 1 + * just merge :) + */ + + pitem_left->begin = begin; + } + + /* + * ===> pitem_left->begin + * ===> <= begin + * ===> ...... + * ===> < pitem_right->begin + * ===> <= end + */ + + if(begin <= pitem_left->end) { + /* + * ===> pitem_left->begin + * ===> <= begin + * +++> <= pitem_left->end + * ===> < pitem_right->begin + * ===> <= end + * ===> so, just merge the nodes between the + * ===> pitem_left node and the pitem_right node, and include both of them + */ + + /* + * merge the pitem_left node, begin ---> end into pitem_right node, + * and merge all nodes into one node which are between + * the pitem_left node and the pitem_right node, + * include both of pitem_left node and pitem_right node + */ + + if(end > pitem_right->end) { + /* + * ===> pitem_left->begin + * ===> <= begin + * ===> <= pitem_left->end + * ===> < pitem_right->begin + * +++> <= pitem_right->end + * ===> < end + */ + + pitem_right->end = end; + } + /* + * else + * ===> pitem_left->begin + * ===> <= begin + * ===> <= pitem_left->end + * ===> < pitem_right->begin + * ===> <= end + * +++> <= pitem_right->end + */ + + pitem_right->begin = pitem_left->begin; + + ret = dlink_node_merge(a, idx_begin, idx_end); + if(ret < 0) + return NULL; + + return pitem_right; + } + + /* + * ===> pitem_left->begin + * ===> <= pitem_left->end + * ===> < begin + * ===> < pitem_right->begin + * ===> <= end + * + * merge the begin--->end into pitem_right node + * and at the same time, merge all the nodes into idx_begin + 1 + * which between the idx_begin + 1 node and the pitem_right node, + * include idx_begin + 1 node and pitem_righ node + */ + + if(end > pitem_right->end) { + /* + * ===> pitem_left->begin + * ===> <= pitem_left->end + * ===> < begin + * ===> < pitem_right->begin + * +++> <= pitem_right->end + * ===> < end + */ + + pitem_right->end = end; + } + /* + * else + * ===> pitem_left->begin + * ===> <= pitem_left->end + * ===> < begin + * ===> < pitem_right->begin + * ===> < end + * +++> <= pitem_right->end + */ + + pitem_right->begin = begin; + + ret = dlink_node_merge(a, idx_begin + 1, idx_end); + if(ret < 0) + return NULL; + + return pitem_right; +} + +static void *dlink_iter_head(ACL_ITER *iter, struct ACL_DLINK *dlink) +{ + return dlink->parray->iter_head(iter, dlink->parray); +} + +static void *dlink_iter_next(ACL_ITER *iter, struct ACL_DLINK *dlink) +{ + return dlink->parray->iter_next(iter, dlink->parray); +} + +static void *dlink_iter_tail(ACL_ITER *iter, struct ACL_DLINK *dlink) +{ + return dlink->parray->iter_tail(iter, dlink->parray); +} + +static void *dlink_iter_prev(ACL_ITER *iter, struct ACL_DLINK *dlink) +{ + return dlink->parray->iter_prev(iter, dlink->parray); +} + +ACL_DLINK *acl_dlink_create(int nsize) +{ + ACL_DLINK *plink; + + plink = (ACL_DLINK *) acl_mymalloc(sizeof(ACL_DLINK)); + plink->parray = NULL; + plink->call_back_data = NULL; + nsize = nsize > 0 ? nsize : 1; + plink->parray = acl_array_create(nsize); + if(plink->parray == NULL) { + acl_myfree(plink); + return NULL; + } + + plink->iter_head = dlink_iter_head; + plink->iter_next = dlink_iter_next; + plink->iter_tail = dlink_iter_tail; + plink->iter_prev = dlink_iter_prev; + + return plink; +} + +void acl_dlink_free(ACL_DLINK *plink) +{ + if(plink == NULL) + return; + if(plink->parray) + acl_array_destroy(plink->parray, dlink_free_callback); + acl_myfree(plink); +} + +ACL_DITEM *acl_dlink_lookup_by_item(const ACL_DLINK *plink, ACL_DITEM *pitem) +{ + return acl_dlink_lookup2_by_item(plink, pitem, NULL); +} + +ACL_DITEM *acl_dlink_lookup2_by_item(const ACL_DLINK *plink, ACL_DITEM *pitem, int *pidx) +{ + int i; + ACL_ARRAY *parray = plink->parray; + + for(i = 0; i < acl_array_size(parray) - 1; i++) { + if((ACL_DITEM *) acl_array_index(parray, i) == pitem) { + if (pidx) + *pidx = i; + return pitem; + } + } + return NULL; +} + +ACL_DITEM *acl_dlink_lookup(const ACL_DLINK *plink, acl_uint64 n) +{ + return acl_dlink_lookup2(plink, n, NULL); +} + +ACL_DITEM *acl_dlink_lookup2(const ACL_DLINK *plink, acl_uint64 n, int *pidx) +{ + int lidx, midx, hidx; + + lidx = 0; + hidx = acl_array_size(plink->parray) - 1; + while(lidx <= hidx) { + ACL_DITEM* pitem; + + midx = (lidx + hidx) / 2; + pitem = (ACL_DITEM *) acl_array_index(plink->parray, midx); + if(n >= pitem->begin && n <= pitem->end) { + if (pidx) + *pidx = midx; + return pitem; + } + if(n < pitem->begin) + hidx = midx - 1; + else if(n > pitem->end) + lidx = midx + 1; + else /* why does this array not to be sorted ? */ + break; + } + + return NULL; /*not in the d_link scope */ +} + +ACL_DITEM *acl_dlink_lookup_range(const ACL_DLINK *plink, acl_uint64 begin, + acl_uint64 end, int *pidx) +{ + ACL_DITEM *ditem; + + if (end < begin) + return NULL; + ditem = acl_dlink_lookup2(plink, begin, pidx); + if (ditem == NULL) + return NULL; + if (ditem->end >= end) + return ditem; + return NULL; +} + +ACL_DITEM *acl_dlink_lookup_larger(const ACL_DLINK *plink, + acl_uint64 off, int *pidx) +{ + int i, size; + + size = acl_array_size(plink->parray); + + for (i = 0; i < size; i++) { + ACL_DITEM* pitem = (ACL_DITEM*) + acl_array_index(plink->parray, i); + if (pitem->end >= off) { + if (pidx) + *pidx = i; + return pitem; + } + } + + return NULL; /*not in the d_link scope */ +} + +ACL_DITEM *acl_dlink_lookup_lower(const ACL_DLINK *plink, + acl_uint64 off, int *pidx) +{ + int i, size; + + size = acl_array_size(plink->parray); + + for (i = size - 1; i >= 0; i--) { + ACL_DITEM* pitem = (ACL_DITEM*) + acl_array_index(plink->parray, i); + if (pitem->begin <= off) { + if (pidx) + *pidx = i; + return pitem; + } + } + + return NULL; /*not in the d_link scope */ +} + +ACL_DITEM *acl_dlink_insert(ACL_DLINK *plink, acl_uint64 begin, acl_uint64 end) +{ + if (begin > end) { + acl_uint64 tmp; + /* swap the begin and end if end < begin */ + tmp = begin; + begin = end; + end = tmp; + } + + if(acl_array_size(plink->parray) == 0) { + /* this is the first item of the array */ + return dlink_append(plink->parray, begin, end); + } + + /* 此函数内有可能进行了结点项的合并 */ + return dlink_add(plink->parray, begin, end); +} + +int acl_dlink_delete(ACL_DLINK *plink, acl_uint64 n) +{ + const ACL_DITEM *ditem; + int idx; + + ditem = acl_dlink_lookup2(plink, n, &idx); + if (ditem == NULL) + return -1; + acl_array_delete_idx(plink->parray, idx, dlink_free_callback); + return 0; +} + +int acl_dlink_delete_by_item(ACL_DLINK *plink, ACL_DITEM *pitem) +{ + int ret; + + ret = acl_array_delete_obj(plink->parray, pitem, dlink_free_callback); + if (ret < 0) /* this is impossile, but a sanity check */ + return -1; + return 0; +} + +int acl_dlink_delete_range(ACL_DLINK *plink, acl_uint64 begin, acl_uint64 end) +{ + ACL_ARRAY *parray = plink->parray; + ACL_DITEM *pitem, *pitem_low; + int i, low, high, size; + + low = 0; + pitem_low = NULL; + size = acl_array_size(parray); + + for (i = 0; i < size; i++) { + pitem = (ACL_DITEM*) acl_array_index(parray, i); + if (begin > pitem->end) + continue; + + /* begin <= pitem->end */ + + if (begin <= pitem->begin) { + /* begin <= pitem->begin <= pitem->end */ + if (end < pitem->end) { + /* begin <= pitem->begin <= end < pitem->end */ + pitem->begin = end + 1; + return 0; + } else if (end == pitem->end) { + /* begin <= pitem->begin <= pitem->end == end */ + acl_array_delete_idx(parray, i, dlink_free_callback); + return 0; + } + /* begin <= pitem->begin <= pitem->end < end */ + low = i; + } + + /* pitem->begin < begin <= pitem->end */ + + else if (end == pitem->end) { + /* pitem->begin < begin <= end == pitem->end */ + pitem->end = begin - 1; + return 0; + } else if (end < pitem->end) { + /* pitem->begin < begin <= end < pitem->end */ + acl_uint64 tmp_begin, tmp_end; + + tmp_begin = end + 1; + tmp_end = pitem->end; + pitem->end = begin - 1; + /* add one ditem hole */ + dlink_add(parray, tmp_begin, tmp_end); + return 0; + } else { + /* pitem->begin < begin <= pitem->end < end */ + pitem->end = begin - 1; + low = i + 1; + if (low >= size) /* i is the last item's idx */ + return 0; + pitem_low = (ACL_DITEM*) acl_array_index(parray, low); + if (pitem_low->begin > end) + return 0; + /* begin < pitem_low->begin <= end */ + if (end < pitem_low->end) { + /* begin < pitem_low->begin <= end < pitem_low->end */ + pitem_low->begin = end + 1; + return 0; + } else if (end == pitem_low->end) { + /* begin < pitem_low->begin <= pitem_low->end == end */ + acl_array_delete_idx(parray, low, dlink_free_callback); + return 0; + } + + /* begin < pitem_low->begin <= pitem_low->end < end */ + } + break; + } + + high = size - 1; + for (i = low + 1; i < size; i++) { + pitem = (ACL_DITEM*) acl_array_index(parray, i); + if (end > pitem->end) + continue; + + /* end <= pitem->end */ + + if (end < pitem->begin) { + /* end < pitem->begin <= pitem->end */ + high = i - 1; + } else if (end == pitem->begin) { + /* end == pitem->begin <= pitem->end */ + if (pitem->begin == pitem->end) { + /* end == pitem->begin == pitem->end */ + high = i; + } else { + /* end == pitem->begin < pitem->end */ + pitem->begin = end + 1; + high = i - 1; + } + } + + /* pitem->begin < end <= pitem->end */ + + else if (end == pitem->end) { + /* pitem->begin < end == pitem->end */ + high = i; + } else { + /* pitem->begin < end < pitem->end */ + pitem->begin = end + 1; + high = i - 1; + } + break; + } + + if (low > high) + return 0; + + return acl_array_delete_range(parray, low, high, dlink_free_callback); +} + +ACL_DITEM *acl_dlink_modify(ACL_DLINK *plink, acl_uint64 begin, acl_uint64 end) +{ + if (begin > end) { + acl_uint64 tmp; + /* swap the begin andend if end < begin */ + tmp = begin; + begin = end; + end = tmp; + } + + return dlink_add(plink->parray, begin, end); +} + +ACL_DITEM *acl_dlink_index(const ACL_DLINK *plink, int idx) +{ + return (ACL_DITEM *) acl_array_index(plink->parray, idx); +} + +int acl_dlink_size(const ACL_DLINK *plink) +{ + return acl_array_size(plink->parray); +} + +/* ++++++++++++++++++++++++++below functions are used only for test ++++++++++++ */ + +int acl_dlink_list(const ACL_DLINK *plink) +{ + const char *myname = "acl_dlink_list"; + int i, n; + ACL_DITEM *item; + + if(plink == NULL || plink->parray == NULL) { + printf("%s: input error\r\n", myname); + return-1; + } + + n = acl_array_size(plink->parray); + for (i = 0; i < n; i++) { + item = (ACL_DITEM *) acl_array_index(plink->parray, i); + if (item == NULL) + break; + printf("begin=" ACL_FMT_I64D ", end=" ACL_FMT_I64D "\r\n", + item->begin, item->end); + } + return 0; +} diff --git a/lib_acl/src/stdlib/common/acl_fifo.c b/lib_acl/src/stdlib/common/acl_fifo.c new file mode 100644 index 000000000..7d6000c50 --- /dev/null +++ b/lib_acl/src/stdlib/common/acl_fifo.c @@ -0,0 +1,392 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_msg.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_fifo.h" + +#endif + +static void fifo_push_back(ACL_FIFO *fifo, void *data) +{ + acl_fifo_push_back(fifo, data); +} + +static void fifo_push_front(ACL_FIFO *fifo, void *data) +{ + acl_fifo_push_front(fifo, data); +} + +static void* fifo_pop_back(ACL_FIFO *fifo) +{ + return (acl_fifo_pop_back(fifo)); +} + +static void* fifo_pop_front(ACL_FIFO *fifo) +{ + return (acl_fifo_pop_front(fifo)); +} + +static void *fifo_iter_head(ACL_ITER *iter, struct ACL_FIFO *fifo) +{ + ACL_FIFO_INFO *ptr; + + iter->dlen = -1; + iter->key = NULL; + iter->klen = -1; + iter->i = 0; + iter->size = fifo->cnt; + iter->ptr = ptr = fifo->head; + iter->data = ptr ? ptr->data : NULL; + return (iter->ptr); +} + +static void *fifo_iter_next(ACL_ITER *iter, struct ACL_FIFO *fifo acl_unused) +{ + ACL_FIFO_INFO *ptr; + + ptr = (ACL_FIFO_INFO*) iter->ptr; + iter->ptr = ptr = ptr ? ptr->next : NULL; + if (ptr) { + iter->data = ptr->data; + iter->i++; + } else + iter->data = NULL; + return (iter); +} + +static void *fifo_iter_tail(ACL_ITER *iter, struct ACL_FIFO *fifo) +{ + ACL_FIFO_INFO *ptr; + + iter->dlen = -1; + iter->key = NULL; + iter->klen = -1; + iter->i = fifo->cnt - 1; + iter->size = fifo->cnt; + iter->ptr = ptr = fifo->tail; + iter->data = ptr ? ptr->data : NULL; + return (iter->ptr); +} + +static void *fifo_iter_prev(ACL_ITER *iter, struct ACL_FIFO *fifo acl_unused) +{ + ACL_FIFO_INFO *ptr; + + ptr = (ACL_FIFO_INFO*) iter->ptr; + iter->ptr = ptr = ptr ? ptr->prev : NULL; + if (ptr) { + iter->data = ptr->data; + iter->i--; + } else + iter->data = NULL; + return (iter); +} + +static ACL_FIFO_INFO *fifo_iter_info(ACL_ITER *iter, struct ACL_FIFO *fifo acl_unused) +{ + return (iter->ptr ? (ACL_FIFO_INFO*) iter->ptr : NULL); +} + +void acl_fifo_init(ACL_FIFO *fifo) +{ + fifo->head = NULL; + fifo->tail = NULL; + fifo->cnt = 0; + fifo->slice = NULL; + + fifo->push_back = fifo_push_back; + fifo->push_front = fifo_push_front; + fifo->pop_back = fifo_pop_back; + fifo->pop_front = fifo_pop_front; + fifo->iter_head = fifo_iter_head; + fifo->iter_next = fifo_iter_next; + fifo->iter_tail = fifo_iter_tail; + fifo->iter_prev = fifo_iter_prev; + fifo->iter_info = fifo_iter_info; +} + +ACL_FIFO *acl_fifo_new(void) +{ + return (acl_fifo_new1(NULL)); +} + +ACL_FIFO *acl_fifo_new1(ACL_SLICE_POOL *slice) +{ + ACL_FIFO *fifo; + + if (slice) { + fifo = (ACL_FIFO *) acl_slice_pool_alloc(__FILE__, __LINE__, + slice, sizeof(*fifo)); + fifo->slice = slice; + } else { + fifo = (ACL_FIFO *) acl_mymalloc(sizeof(*fifo)); + fifo->slice = NULL; + } + fifo->head = NULL; + fifo->tail = NULL; + fifo->cnt = 0; + + fifo->push_back = fifo_push_back; + fifo->push_front = fifo_push_front; + fifo->pop_back = fifo_pop_back; + fifo->pop_front = fifo_pop_front; + fifo->iter_head = fifo_iter_head; + fifo->iter_next = fifo_iter_next; + fifo->iter_tail = fifo_iter_tail; + fifo->iter_prev = fifo_iter_prev; + + return (fifo); +} + +void acl_fifo_free(ACL_FIFO *fifo, void (*free_fn)(void *)) +{ + void *data; + + while ((data = acl_fifo_pop(fifo)) != NULL) { + if (free_fn) + free_fn(data); + } + if (fifo->slice) + acl_slice_pool_free(__FILE__, __LINE__, fifo); + else + acl_myfree(fifo); +} + +ACL_FIFO_INFO *acl_fifo_push_back(ACL_FIFO *fifo, void *data) +{ + ACL_FIFO_INFO *info; + + if (fifo->slice) + info = (ACL_FIFO_INFO *) acl_slice_pool_alloc(__FILE__, __LINE__, + fifo->slice, sizeof(*info)); + else + info = (ACL_FIFO_INFO *) acl_mymalloc(sizeof(*info)); + info->data = data; + + if (fifo->tail == NULL) { + info->prev = info->next = NULL; + fifo->head = fifo->tail = info; + } else { + fifo->tail->next = info; + info->prev = fifo->tail; + info->next = NULL; + fifo->tail = info; + } + + fifo->cnt++; + return (info); +} + +ACL_FIFO_INFO *acl_fifo_push_front(ACL_FIFO *fifo, void *data) +{ + ACL_FIFO_INFO *info; + + if (fifo->slice) + info = (ACL_FIFO_INFO *) acl_slice_pool_alloc(__FILE__, __LINE__, + fifo->slice, sizeof(*info)); + else + info = (ACL_FIFO_INFO*) acl_mymalloc(sizeof(*info)); + info->data = data; + + if (fifo->head == NULL) { + info->prev = info->next = NULL; + fifo->head = fifo->tail = info; + } else { + info->next = fifo->head; + fifo->head->prev = info; + info->prev = NULL; + fifo->head = info; + } + + fifo->cnt++; + return (info); +} + +void *acl_fifo_pop_front(ACL_FIFO *fifo) +{ + ACL_FIFO_INFO *info; + void *data; + + if (fifo->head == NULL) + return (NULL); + + info = fifo->head; + if (fifo->head->next) { + fifo->head->next->prev = NULL; + fifo->head = fifo->head->next; + } else { + fifo->head = fifo->tail = NULL; + } + data = info->data; + if (fifo->slice) + acl_slice_pool_free(__FILE__, __LINE__, info); + else + acl_myfree(info); + fifo->cnt--; + return (data); +} + +void *acl_fifo_pop_back(ACL_FIFO *fifo) +{ + ACL_FIFO_INFO *info; + void *data; + + if (fifo->tail == NULL) + return (NULL); + + info = fifo->tail; + if (fifo->tail->prev) { + fifo->tail->prev->next = NULL; + fifo->tail = fifo->tail->prev; + } else { + fifo->head = fifo->tail = NULL; + } + data = info->data; + if (fifo->slice) + acl_slice_pool_free(__FILE__, __LINE__, info); + else + acl_myfree(info); + fifo->cnt--; + return (data); +} + +int acl_fifo_delete(ACL_FIFO *fifo, const void *data) +{ + ACL_FIFO_INFO *iter = fifo->head; + + while (iter) { + if (iter->data == data) { + if (iter->prev) + iter->prev->next = iter->next; + else + fifo->head = iter->next; + if (iter->next) + iter->next->prev = iter->prev; + else + fifo->tail = iter->prev; + if (fifo->slice) + acl_slice_pool_free(__FILE__, __LINE__, iter); + else + acl_myfree(iter); + fifo->cnt--; + return (1); + } + + iter = iter->next; + } + return (0); +} + +void *acl_fifo_head(ACL_FIFO *fifo) +{ + if (fifo->head) + return (fifo->head->data); + else + return (NULL); +} + +void *acl_fifo_tail(ACL_FIFO *fifo) +{ + if (fifo->tail) + return (fifo->tail->data); + else + return (NULL); +} + +void acl_fifo_free2(ACL_FIFO *fifo, void (*free_fn)(ACL_FIFO_INFO *)) +{ + ACL_FIFO_INFO *info; + + while ((info = acl_fifo_pop_info(fifo)) != NULL) { + if (free_fn) + free_fn(info); + } + if (fifo->slice) + acl_slice_pool_free(__FILE__, __LINE__, fifo); + else + acl_myfree(fifo); +} + +void acl_fifo_push_info_back(ACL_FIFO *fifo, ACL_FIFO_INFO *info) +{ + if (fifo->tail == NULL) { + info->prev = info->next = NULL; + fifo->head = fifo->tail = info; + } else { + fifo->tail->next = info; + info->prev = fifo->tail; + info->next = NULL; + fifo->tail = info; + } + + fifo->cnt++; +} + +ACL_FIFO_INFO *acl_fifo_pop_info(ACL_FIFO *fifo) +{ + ACL_FIFO_INFO *info; + + if (fifo->head == NULL) + return (NULL); + + info = fifo->head; + if (fifo->head->next) { + fifo->head->next->prev = NULL; + fifo->head = fifo->head->next; + } else { + fifo->head = fifo->tail = NULL; + } + + fifo->cnt--; + return (info); +} + +void acl_fifo_delete_info(ACL_FIFO *fifo, ACL_FIFO_INFO *info) +{ + if (info->prev) + info->prev->next = info->next; + else + fifo->head = info->next; + if (info->next) + info->next->prev = info->prev; + else + fifo->tail = info->prev; + + if (fifo->slice) + acl_slice_pool_free(__FILE__, __LINE__, info); + else + acl_myfree(info); + fifo->cnt--; +} + +ACL_FIFO_INFO *acl_fifo_head_info(ACL_FIFO *fifo) +{ + if (fifo->head) + return (fifo->head); + else + return (NULL); +} + +ACL_FIFO_INFO *acl_fifo_tail_info(ACL_FIFO *fifo) +{ + if (fifo->tail) + return (fifo->tail); + else + return (NULL); +} + +int acl_fifo_size(ACL_FIFO *fifo) +{ + if (fifo) + return (fifo->cnt); + else + return (0); +} diff --git a/lib_acl/src/stdlib/common/acl_hash.c b/lib_acl/src/stdlib/common/acl_hash.c new file mode 100644 index 000000000..aaf295121 --- /dev/null +++ b/lib_acl/src/stdlib/common/acl_hash.c @@ -0,0 +1,572 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_hash.h" + +#endif + +#if 0 +/* 该实现有可能在64位系统存在一定问题 */ + +static unsigned long m_table32n[256] = { + 0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9, 0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005, + 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61, 0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD, + 0x4C11DB70, 0x48D0C6C7, 0x4593E01E, 0x4152FDA9, 0x5F15ADAC, 0x5BD4B01B, 0x569796C2, 0x52568B75, + 0x6A1936C8, 0x6ED82B7F, 0x639B0DA6, 0x675A1011, 0x791D4014, 0x7DDC5DA3, 0x709F7B7A, 0x745E66CD, + 0x9823B6E0, 0x9CE2AB57, 0x91A18D8E, 0x95609039, 0x8B27C03C, 0x8FE6DD8B, 0x82A5FB52, 0x8664E6E5, + 0xBE2B5B58, 0xBAEA46EF, 0xB7A96036, 0xB3687D81, 0xAD2F2D84, 0xA9EE3033, 0xA4AD16EA, 0xA06C0B5D, + 0xD4326D90, 0xD0F37027, 0xDDB056FE, 0xD9714B49, 0xC7361B4C, 0xC3F706FB, 0xCEB42022, 0xCA753D95, + 0xF23A8028, 0xF6FB9D9F, 0xFBB8BB46, 0xFF79A6F1, 0xE13EF6F4, 0xE5FFEB43, 0xE8BCCD9A, 0xEC7DD02D, + 0x34867077, 0x30476DC0, 0x3D044B19, 0x39C556AE, 0x278206AB, 0x23431B1C, 0x2E003DC5, 0x2AC12072, + 0x128E9DCF, 0x164F8078, 0x1B0CA6A1, 0x1FCDBB16, 0x018AEB13, 0x054BF6A4, 0x0808D07D, 0x0CC9CDCA, + 0x7897AB07, 0x7C56B6B0, 0x71159069, 0x75D48DDE, 0x6B93DDDB, 0x6F52C06C, 0x6211E6B5, 0x66D0FB02, + 0x5E9F46BF, 0x5A5E5B08, 0x571D7DD1, 0x53DC6066, 0x4D9B3063, 0x495A2DD4, 0x44190B0D, 0x40D816BA, + 0xACA5C697, 0xA864DB20, 0xA527FDF9, 0xA1E6E04E, 0xBFA1B04B, 0xBB60ADFC, 0xB6238B25, 0xB2E29692, + 0x8AAD2B2F, 0x8E6C3698, 0x832F1041, 0x87EE0DF6, 0x99A95DF3, 0x9D684044, 0x902B669D, 0x94EA7B2A, + 0xE0B41DE7, 0xE4750050, 0xE9362689, 0xEDF73B3E, 0xF3B06B3B, 0xF771768C, 0xFA325055, 0xFEF34DE2, + 0xC6BCF05F, 0xC27DEDE8, 0xCF3ECB31, 0xCBFFD686, 0xD5B88683, 0xD1799B34, 0xDC3ABDED, 0xD8FBA05A, + 0x690CE0EE, 0x6DCDFD59, 0x608EDB80, 0x644FC637, 0x7A089632, 0x7EC98B85, 0x738AAD5C, 0x774BB0EB, + 0x4F040D56, 0x4BC510E1, 0x46863638, 0x42472B8F, 0x5C007B8A, 0x58C1663D, 0x558240E4, 0x51435D53, + 0x251D3B9E, 0x21DC2629, 0x2C9F00F0, 0x285E1D47, 0x36194D42, 0x32D850F5, 0x3F9B762C, 0x3B5A6B9B, + 0x0315D626, 0x07D4CB91, 0x0A97ED48, 0x0E56F0FF, 0x1011A0FA, 0x14D0BD4D, 0x19939B94, 0x1D528623, + 0xF12F560E, 0xF5EE4BB9, 0xF8AD6D60, 0xFC6C70D7, 0xE22B20D2, 0xE6EA3D65, 0xEBA91BBC, 0xEF68060B, + 0xD727BBB6, 0xD3E6A601, 0xDEA580D8, 0xDA649D6F, 0xC423CD6A, 0xC0E2D0DD, 0xCDA1F604, 0xC960EBB3, + 0xBD3E8D7E, 0xB9FF90C9, 0xB4BCB610, 0xB07DABA7, 0xAE3AFBA2, 0xAAFBE615, 0xA7B8C0CC, 0xA379DD7B, + 0x9B3660C6, 0x9FF77D71, 0x92B45BA8, 0x9675461F, 0x8832161A, 0x8CF30BAD, 0x81B02D74, 0x857130C3, + 0x5D8A9099, 0x594B8D2E, 0x5408ABF7, 0x50C9B640, 0x4E8EE645, 0x4A4FFBF2, 0x470CDD2B, 0x43CDC09C, + 0x7B827D21, 0x7F436096, 0x7200464F, 0x76C15BF8, 0x68860BFD, 0x6C47164A, 0x61043093, 0x65C52D24, + 0x119B4BE9, 0x155A565E, 0x18197087, 0x1CD86D30, 0x029F3D35, 0x065E2082, 0x0B1D065B, 0x0FDC1BEC, + 0x3793A651, 0x3352BBE6, 0x3E119D3F, 0x3AD08088, 0x2497D08D, 0x2056CD3A, 0x2D15EBE3, 0x29D4F654, + 0xC5A92679, 0xC1683BCE, 0xCC2B1D17, 0xC8EA00A0, 0xD6AD50A5, 0xD26C4D12, 0xDF2F6BCB, 0xDBEE767C, + 0xE3A1CBC1, 0xE760D676, 0xEA23F0AF, 0xEEE2ED18, 0xF0A5BD1D, 0xF464A0AA, 0xF9278673, 0xFDE69BC4, + 0x89B8FD09, 0x8D79E0BE, 0x803AC667, 0x84FBDBD0, 0x9ABC8BD5, 0x9E7D9662, 0x933EB0BB, 0x97FFAD0C, + 0xAFB010B1, 0xAB710D06, 0xA6322BDF, 0xA2F33668, 0xBCB4666D, 0xB8757BDA, 0xB5365D03, 0xB1F740B4 +}; + +unsigned acl_hash_crc32(const void *key, size_t len) +{ + unsigned long m_crc; + const unsigned char* ptr = (const unsigned char *) key; + + m_crc = 0xFFFFFFFF; + while (len-- > 0) + m_crc = m_table32n[((m_crc >> 24) ^ *ptr++)] ^ (m_crc << 8); + + return (m_crc); +} + +#else +/* ======================================================================== +* Table of CRC-32's of all single-byte values (made by make_crc_table) +*/ +static const unsigned long crc32_table[256] = { + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, + 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, + 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, + 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, + 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, + 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, + 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, + 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, + 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, + 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, + 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, + 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, + 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, + 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, + 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, + 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, + 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, + 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, + 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, + 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, + 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, + 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, + 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, + 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, + 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, + 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, + 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, + 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, + 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, + 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, + 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, + 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, + 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, + 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, + 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, + 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, + 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, + 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, + 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, + 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, + 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, + 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, + 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, + 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, + 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, + 0x2d02ef8dL +}; +/* ========================================================================= */ +#define DO1(buf) crc = crc32_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8); +#define DO2(buf) DO1(buf); DO1(buf); +#define DO4(buf) DO2(buf); DO2(buf); +#define DO8(buf) DO4(buf); DO4(buf); + +/* ========================================================================= */ +unsigned acl_hash_crc32(const void *buffer, size_t len) +{ + const unsigned char* buf = (const unsigned char *) buffer; + unsigned long crc = 0; + + if (buf == 0) + return 0L; + crc = crc ^ 0xffffffffL; + while (len >= 8) { + DO8(buf); + len -= 8; + } + if (len > 0) + do { + DO1(buf); + } while (--len > 0); + return (crc ^ 0xffffffffL); +} +#endif + +/* + * Improved calculation of CRC-64 values for protein sequences + * By David T. Jones (dtj@cs.ucl.ac.uk) - September 28th 2002 + * + * Modified from code at URL: + * ftp://ftp.ebi.ac.uk/pub/software/swissprot/Swissknife/old/SPcrc.tar.gz + */ + +/* If you want to try the old CRC-64 function, currently employed in + SWISSPROT/TrEMBL then uncomment the next line */ +/* add by guozhaohui, 2008.4.25 */ +/* #define OLDCRC */ + +#ifdef OLDCRC + #define POLY64REV 0xd800000000000000ll + #define INITIALCRC 0x0000000000000000ll +#elif defined(MS_VC6) + #define POLY64REV 0x95ac9329ac4bc9b5 + #define INITIALCRC 0xffffffffffffffff +#else + #define POLY64REV 0x95ac9329ac4bc9b5ll + #define INITIALCRC 0xffffffffffffffffll +#endif + +#ifdef MS_VC6 +static acl_uint64 crc64_table[256] = { + 0x0, + 0x7ad870c830358979, 0xf5b0e190606b12f2, 0x8f689158505e9b8b, + 0xc038e5739841b68f, 0xbae095bba8743ff6, 0x358804e3f82aa47d, + 0x4f50742bc81f2d04, 0xab28ecb46814fe75, 0xd1f09c7c5821770c, + 0x5e980d24087fec87, 0x24407dec384a65fe, 0x6b1009c7f05548fa, + 0x11c8790fc060c183, 0x9ea0e857903e5a08, 0xe478989fa00bd371, + 0x7d08ff3b88be6f81, 0x7d08ff3b88be6f8, 0x88b81eabe8d57d73, + 0xf2606e63d8e0f40a, 0xbd301a4810ffd90e, 0xc7e86a8020ca5077, + 0x4880fbd87094cbfc, 0x32588b1040a14285, 0xd620138fe0aa91f4, + 0xacf86347d09f188d, 0x2390f21f80c18306, 0x594882d7b0f40a7f, + 0x1618f6fc78eb277b, 0x6cc0863448deae02, 0xe3a8176c18803589, + 0x997067a428b5bcf0, 0xfa11fe77117cdf02, 0x80c98ebf2149567b, + 0xfa11fe77117cdf0, 0x75796f2f41224489, 0x3a291b04893d698d, + 0x40f16bccb908e0f4, 0xcf99fa94e9567b7f, 0xb5418a5cd963f206, + 0x513912c379682177, 0x2be1620b495da80e, 0xa489f35319033385, + 0xde51839b2936bafc, 0x9101f7b0e12997f8, 0xebd98778d11c1e81, + 0x64b116208142850a, 0x1e6966e8b1770c73, 0x8719014c99c2b083, + 0xfdc17184a9f739fa, 0x72a9e0dcf9a9a271, 0x8719014c99c2b08, + 0x4721e43f0183060c, 0x3df994f731b68f75, 0xb29105af61e814fe, + 0xc849756751dd9d87, 0x2c31edf8f1d64ef6, 0x56e99d30c1e3c78f, + 0xd9810c6891bd5c04, 0xa3597ca0a188d57d, 0xec09088b6997f879, + 0x96d1784359a27100, 0x19b9e91b09fcea8b, 0x636199d339c963f2, + 0xdf7adabd7a6e2d6f, 0xa5a2aa754a5ba416, 0x2aca3b2d1a053f9d, + 0x50124be52a30b6e4, 0x1f423fcee22f9be0, 0x659a4f06d21a1299, + 0xeaf2de5e82448912, 0x902aae96b271006b, 0x74523609127ad31a, + 0xe8a46c1224f5a63, 0x81e2d7997211c1e8, 0xfb3aa75142244891, + 0xb46ad37a8a3b6595, 0xceb2a3b2ba0eecec, 0x41da32eaea507767, + 0x3b024222da65fe1e, 0xa2722586f2d042ee, 0xd8aa554ec2e5cb97, + 0x57c2c41692bb501c, 0x2d1ab4dea28ed965, 0x624ac0f56a91f461, + 0x1892b03d5aa47d18, 0x97fa21650afae693, 0xed2251ad3acf6fea, + 0x95ac9329ac4bc9b, 0x7382b9faaaf135e2, 0xfcea28a2faafae69, + 0x8632586aca9a2710, 0xc9622c4102850a14, 0xb3ba5c8932b0836d, + 0x3cd2cdd162ee18e6, 0x460abd1952db919f, 0x256b24ca6b12f26d, + 0x5fb354025b277b14, 0xd0dbc55a0b79e09f, 0xaa03b5923b4c69e6, + 0xe553c1b9f35344e2, 0x9f8bb171c366cd9b, 0x10e3202993385610, + 0x6a3b50e1a30ddf69, 0x8e43c87e03060c18, 0xf49bb8b633338561, + 0x7bf329ee636d1eea, 0x12b592653589793, 0x4e7b2d0d9b47ba97, + 0x34a35dc5ab7233ee, 0xbbcbcc9dfb2ca865, 0xc113bc55cb19211c, + 0x5863dbf1e3ac9dec, 0x22bbab39d3991495, 0xadd33a6183c78f1e, + 0xd70b4aa9b3f20667, 0x985b3e827bed2b63, 0xe2834e4a4bd8a21a, + 0x6debdf121b863991, 0x1733afda2bb3b0e8, 0xf34b37458bb86399, + 0x8993478dbb8deae0, 0x6fbd6d5ebd3716b, 0x7c23a61ddbe6f812, + 0x3373d23613f9d516, 0x49aba2fe23cc5c6f, 0xc6c333a67392c7e4, + 0xbc1b436e43a74e9d, 0x95ac9329ac4bc9b5, 0xef74e3e19c7e40cc, + 0x601c72b9cc20db47, 0x1ac40271fc15523e, 0x5594765a340a7f3a, + 0x2f4c0692043ff643, 0xa02497ca54616dc8, 0xdafce7026454e4b1, + 0x3e847f9dc45f37c0, 0x445c0f55f46abeb9, 0xcb349e0da4342532, + 0xb1eceec59401ac4b, 0xfebc9aee5c1e814f, 0x8464ea266c2b0836, + 0xb0c7b7e3c7593bd, 0x71d40bb60c401ac4, 0xe8a46c1224f5a634, + 0x927c1cda14c02f4d, 0x1d148d82449eb4c6, 0x67ccfd4a74ab3dbf, + 0x289c8961bcb410bb, 0x5244f9a98c8199c2, 0xdd2c68f1dcdf0249, + 0xa7f41839ecea8b30, 0x438c80a64ce15841, 0x3954f06e7cd4d138, + 0xb63c61362c8a4ab3, 0xcce411fe1cbfc3ca, 0x83b465d5d4a0eece, + 0xf96c151de49567b7, 0x76048445b4cbfc3c, 0xcdcf48d84fe7545, + 0x6fbd6d5ebd3716b7, 0x15651d968d029fce, 0x9a0d8ccedd5c0445, + 0xe0d5fc06ed698d3c, 0xaf85882d2576a038, 0xd55df8e515432941, + 0x5a3569bd451db2ca, 0x20ed197575283bb3, 0xc49581ead523e8c2, + 0xbe4df122e51661bb, 0x3125607ab548fa30, 0x4bfd10b2857d7349, + 0x4ad64994d625e4d, 0x7e7514517d57d734, 0xf11d85092d094cbf, + 0x8bc5f5c11d3cc5c6, 0x12b5926535897936, 0x686de2ad05bcf04f, + 0xe70573f555e26bc4, 0x9ddd033d65d7e2bd, 0xd28d7716adc8cfb9, + 0xa85507de9dfd46c0, 0x273d9686cda3dd4b, 0x5de5e64efd965432, + 0xb99d7ed15d9d8743, 0xc3450e196da80e3a, 0x4c2d9f413df695b1, + 0x36f5ef890dc31cc8, 0x79a59ba2c5dc31cc, 0x37deb6af5e9b8b5, + 0x8c157a32a5b7233e, 0xf6cd0afa9582aa47, 0x4ad64994d625e4da, + 0x300e395ce6106da3, 0xbf66a804b64ef628, 0xc5bed8cc867b7f51, + 0x8aeeace74e645255, 0xf036dc2f7e51db2c, 0x7f5e4d772e0f40a7, + 0x5863dbf1e3ac9de, 0xe1fea520be311aaf, 0x9b26d5e88e0493d6, + 0x144e44b0de5a085d, 0x6e963478ee6f8124, 0x21c640532670ac20, + 0x5b1e309b16452559, 0xd476a1c3461bbed2, 0xaeaed10b762e37ab, + 0x37deb6af5e9b8b5b, 0x4d06c6676eae0222, 0xc26e573f3ef099a9, + 0xb8b627f70ec510d0, 0xf7e653dcc6da3dd4, 0x8d3e2314f6efb4ad, + 0x256b24ca6b12f26, 0x788ec2849684a65f, 0x9cf65a1b368f752e, + 0xe62e2ad306bafc57, 0x6946bb8b56e467dc, 0x139ecb4366d1eea5, + 0x5ccebf68aecec3a1, 0x2616cfa09efb4ad8, 0xa97e5ef8cea5d153, + 0xd3a62e30fe90582a, 0xb0c7b7e3c7593bd8, 0xca1fc72bf76cb2a1, + 0x45775673a732292a, 0x3faf26bb9707a053, 0x70ff52905f188d57, + 0xa2722586f2d042e, 0x854fb3003f739fa5, 0xff97c3c80f4616dc, + 0x1bef5b57af4dc5ad, 0x61372b9f9f784cd4, 0xee5fbac7cf26d75f, + 0x9487ca0fff135e26, 0xdbd7be24370c7322, 0xa10fceec0739fa5b, + 0x2e675fb4576761d0, 0x54bf2f7c6752e8a9, 0xcdcf48d84fe75459, + 0xb71738107fd2dd20, 0x387fa9482f8c46ab, 0x42a7d9801fb9cfd2, + 0xdf7adabd7a6e2d6, 0x772fdd63e7936baf, 0xf8474c3bb7cdf024, + 0x829f3cf387f8795d, 0x66e7a46c27f3aa2c, 0x1c3fd4a417c62355, + 0x935745fc4798b8de, 0xe98f353477ad31a7, 0xa6df411fbfb21ca3, + 0xdc0731d78f8795da, 0x536fa08fdfd90e51, 0x29b7d047efec8728 +}; +#else +static acl_uint64 crc64_table[256] = { + 0x0ll, + 0x7ad870c830358979ll, 0xf5b0e190606b12f2ll, 0x8f689158505e9b8bll, + 0xc038e5739841b68fll, 0xbae095bba8743ff6ll, 0x358804e3f82aa47dll, + 0x4f50742bc81f2d04ll, 0xab28ecb46814fe75ll, 0xd1f09c7c5821770cll, + 0x5e980d24087fec87ll, 0x24407dec384a65fell, 0x6b1009c7f05548fall, + 0x11c8790fc060c183ll, 0x9ea0e857903e5a08ll, 0xe478989fa00bd371ll, + 0x7d08ff3b88be6f81ll, 0x7d08ff3b88be6f8ll, 0x88b81eabe8d57d73ll, + 0xf2606e63d8e0f40all, 0xbd301a4810ffd90ell, 0xc7e86a8020ca5077ll, + 0x4880fbd87094cbfcll, 0x32588b1040a14285ll, 0xd620138fe0aa91f4ll, + 0xacf86347d09f188dll, 0x2390f21f80c18306ll, 0x594882d7b0f40a7fll, + 0x1618f6fc78eb277bll, 0x6cc0863448deae02ll, 0xe3a8176c18803589ll, + 0x997067a428b5bcf0ll, 0xfa11fe77117cdf02ll, 0x80c98ebf2149567bll, + 0xfa11fe77117cdf0ll, 0x75796f2f41224489ll, 0x3a291b04893d698dll, + 0x40f16bccb908e0f4ll, 0xcf99fa94e9567b7fll, 0xb5418a5cd963f206ll, + 0x513912c379682177ll, 0x2be1620b495da80ell, 0xa489f35319033385ll, + 0xde51839b2936bafcll, 0x9101f7b0e12997f8ll, 0xebd98778d11c1e81ll, + 0x64b116208142850all, 0x1e6966e8b1770c73ll, 0x8719014c99c2b083ll, + 0xfdc17184a9f739fall, 0x72a9e0dcf9a9a271ll, 0x8719014c99c2b08ll, + 0x4721e43f0183060cll, 0x3df994f731b68f75ll, 0xb29105af61e814fell, + 0xc849756751dd9d87ll, 0x2c31edf8f1d64ef6ll, 0x56e99d30c1e3c78fll, + 0xd9810c6891bd5c04ll, 0xa3597ca0a188d57dll, 0xec09088b6997f879ll, + 0x96d1784359a27100ll, 0x19b9e91b09fcea8bll, 0x636199d339c963f2ll, + 0xdf7adabd7a6e2d6fll, 0xa5a2aa754a5ba416ll, 0x2aca3b2d1a053f9dll, + 0x50124be52a30b6e4ll, 0x1f423fcee22f9be0ll, 0x659a4f06d21a1299ll, + 0xeaf2de5e82448912ll, 0x902aae96b271006bll, 0x74523609127ad31all, + 0xe8a46c1224f5a63ll, 0x81e2d7997211c1e8ll, 0xfb3aa75142244891ll, + 0xb46ad37a8a3b6595ll, 0xceb2a3b2ba0eececll, 0x41da32eaea507767ll, + 0x3b024222da65fe1ell, 0xa2722586f2d042eell, 0xd8aa554ec2e5cb97ll, + 0x57c2c41692bb501cll, 0x2d1ab4dea28ed965ll, 0x624ac0f56a91f461ll, + 0x1892b03d5aa47d18ll, 0x97fa21650afae693ll, 0xed2251ad3acf6feall, + 0x95ac9329ac4bc9bll, 0x7382b9faaaf135e2ll, 0xfcea28a2faafae69ll, + 0x8632586aca9a2710ll, 0xc9622c4102850a14ll, 0xb3ba5c8932b0836dll, + 0x3cd2cdd162ee18e6ll, 0x460abd1952db919fll, 0x256b24ca6b12f26dll, + 0x5fb354025b277b14ll, 0xd0dbc55a0b79e09fll, 0xaa03b5923b4c69e6ll, + 0xe553c1b9f35344e2ll, 0x9f8bb171c366cd9bll, 0x10e3202993385610ll, + 0x6a3b50e1a30ddf69ll, 0x8e43c87e03060c18ll, 0xf49bb8b633338561ll, + 0x7bf329ee636d1eeall, 0x12b592653589793ll, 0x4e7b2d0d9b47ba97ll, + 0x34a35dc5ab7233eell, 0xbbcbcc9dfb2ca865ll, 0xc113bc55cb19211cll, + 0x5863dbf1e3ac9decll, 0x22bbab39d3991495ll, 0xadd33a6183c78f1ell, + 0xd70b4aa9b3f20667ll, 0x985b3e827bed2b63ll, 0xe2834e4a4bd8a21all, + 0x6debdf121b863991ll, 0x1733afda2bb3b0e8ll, 0xf34b37458bb86399ll, + 0x8993478dbb8deae0ll, 0x6fbd6d5ebd3716bll, 0x7c23a61ddbe6f812ll, + 0x3373d23613f9d516ll, 0x49aba2fe23cc5c6fll, 0xc6c333a67392c7e4ll, + 0xbc1b436e43a74e9dll, 0x95ac9329ac4bc9b5ll, 0xef74e3e19c7e40ccll, + 0x601c72b9cc20db47ll, 0x1ac40271fc15523ell, 0x5594765a340a7f3all, + 0x2f4c0692043ff643ll, 0xa02497ca54616dc8ll, 0xdafce7026454e4b1ll, + 0x3e847f9dc45f37c0ll, 0x445c0f55f46abeb9ll, 0xcb349e0da4342532ll, + 0xb1eceec59401ac4bll, 0xfebc9aee5c1e814fll, 0x8464ea266c2b0836ll, + 0xb0c7b7e3c7593bdll, 0x71d40bb60c401ac4ll, 0xe8a46c1224f5a634ll, + 0x927c1cda14c02f4dll, 0x1d148d82449eb4c6ll, 0x67ccfd4a74ab3dbfll, + 0x289c8961bcb410bbll, 0x5244f9a98c8199c2ll, 0xdd2c68f1dcdf0249ll, + 0xa7f41839ecea8b30ll, 0x438c80a64ce15841ll, 0x3954f06e7cd4d138ll, + 0xb63c61362c8a4ab3ll, 0xcce411fe1cbfc3call, 0x83b465d5d4a0eecell, + 0xf96c151de49567b7ll, 0x76048445b4cbfc3cll, 0xcdcf48d84fe7545ll, + 0x6fbd6d5ebd3716b7ll, 0x15651d968d029fcell, 0x9a0d8ccedd5c0445ll, + 0xe0d5fc06ed698d3cll, 0xaf85882d2576a038ll, 0xd55df8e515432941ll, + 0x5a3569bd451db2call, 0x20ed197575283bb3ll, 0xc49581ead523e8c2ll, + 0xbe4df122e51661bbll, 0x3125607ab548fa30ll, 0x4bfd10b2857d7349ll, + 0x4ad64994d625e4dll, 0x7e7514517d57d734ll, 0xf11d85092d094cbfll, + 0x8bc5f5c11d3cc5c6ll, 0x12b5926535897936ll, 0x686de2ad05bcf04fll, + 0xe70573f555e26bc4ll, 0x9ddd033d65d7e2bdll, 0xd28d7716adc8cfb9ll, + 0xa85507de9dfd46c0ll, 0x273d9686cda3dd4bll, 0x5de5e64efd965432ll, + 0xb99d7ed15d9d8743ll, 0xc3450e196da80e3all, 0x4c2d9f413df695b1ll, + 0x36f5ef890dc31cc8ll, 0x79a59ba2c5dc31ccll, 0x37deb6af5e9b8b5ll, + 0x8c157a32a5b7233ell, 0xf6cd0afa9582aa47ll, 0x4ad64994d625e4dall, + 0x300e395ce6106da3ll, 0xbf66a804b64ef628ll, 0xc5bed8cc867b7f51ll, + 0x8aeeace74e645255ll, 0xf036dc2f7e51db2cll, 0x7f5e4d772e0f40a7ll, + 0x5863dbf1e3ac9dell, 0xe1fea520be311aafll, 0x9b26d5e88e0493d6ll, + 0x144e44b0de5a085dll, 0x6e963478ee6f8124ll, 0x21c640532670ac20ll, + 0x5b1e309b16452559ll, 0xd476a1c3461bbed2ll, 0xaeaed10b762e37abll, + 0x37deb6af5e9b8b5bll, 0x4d06c6676eae0222ll, 0xc26e573f3ef099a9ll, + 0xb8b627f70ec510d0ll, 0xf7e653dcc6da3dd4ll, 0x8d3e2314f6efb4adll, + 0x256b24ca6b12f26ll, 0x788ec2849684a65fll, 0x9cf65a1b368f752ell, + 0xe62e2ad306bafc57ll, 0x6946bb8b56e467dcll, 0x139ecb4366d1eea5ll, + 0x5ccebf68aecec3a1ll, 0x2616cfa09efb4ad8ll, 0xa97e5ef8cea5d153ll, + 0xd3a62e30fe90582all, 0xb0c7b7e3c7593bd8ll, 0xca1fc72bf76cb2a1ll, + 0x45775673a732292all, 0x3faf26bb9707a053ll, 0x70ff52905f188d57ll, + 0xa2722586f2d042ell, 0x854fb3003f739fa5ll, 0xff97c3c80f4616dcll, + 0x1bef5b57af4dc5adll, 0x61372b9f9f784cd4ll, 0xee5fbac7cf26d75fll, + 0x9487ca0fff135e26ll, 0xdbd7be24370c7322ll, 0xa10fceec0739fa5bll, + 0x2e675fb4576761d0ll, 0x54bf2f7c6752e8a9ll, 0xcdcf48d84fe75459ll, + 0xb71738107fd2dd20ll, 0x387fa9482f8c46abll, 0x42a7d9801fb9cfd2ll, + 0xdf7adabd7a6e2d6ll, 0x772fdd63e7936bafll, 0xf8474c3bb7cdf024ll, + 0x829f3cf387f8795dll, 0x66e7a46c27f3aa2cll, 0x1c3fd4a417c62355ll, + 0x935745fc4798b8dell, 0xe98f353477ad31a7ll, 0xa6df411fbfb21ca3ll, + 0xdc0731d78f8795dall, 0x536fa08fdfd90e51ll, 0x29b7d047efec8728ll +}; +#endif /* MS_VC6 */ + +acl_uint64 acl_hash_crc64(const void *buffer, size_t len) +{ + const unsigned char* buf = (const unsigned char *) buffer; + acl_uint64 crc = INITIALCRC; + + while (len-- > 0) { + crc = crc64_table[(int)((crc ^ *buf++) & 0xff)] ^ (crc >> 8); + } + + return (crc); +} + +unsigned acl_hash_bin(const void *key, size_t len) +{ + unsigned long h = 0; + unsigned long g; + const unsigned char *k = (const unsigned char *) key; + + /* + * From the "Dragon" book by Aho, Sethi and Ullman. + */ + + while (len-- > 0) { + h = (h << 4) + *k++; + if ((g = (h & 0xf0000000)) != 0) { + h ^= (g >> 24); + h ^= g; + } + } + + return (h); +} + +unsigned acl_hash_test(const void *key, size_t len) +{ + unsigned long result = 0; + const unsigned char *ptr = (const unsigned char *)key; + int c = 0; + int i = 0; + + len = len; + + for (i = 1; (c = *ptr++) != 0; i++) + result += c * 3 * i; + + return (result); +} + +/* the following function(s) were adapted from + * usr/src/lib/libc/db/hash_func.c, 4.4 BSD lite + */ + +/* Phong Vo's linear congruential hash. */ +#define DCHARHASH(h, c) ((h) = 0x63c63cd9*(h) + 0x9c39c33d + (c)) + +unsigned acl_hash_func2(const void *key, size_t len) +{ + const unsigned char *e, *k; + unsigned h; + unsigned char c; + + k = (const unsigned char *) key; + e = k + len; + for (h = 0; k != e;) { + c = *k++; + if (!c && k > e) + break; + DCHARHASH(h, c); + } + + return (h); +} + +/** + * Ozan Yigit's original sdbm hash. + * + * Ugly, but fast. Break the string up into 8 byte units. On the first time + * through the loop get the "leftover bytes" (strlen % 8). On every other + * iteration, perform 8 HASHC's so we handle all 8 bytes. Essentially, this + * saves us 7 cmp & branch instructions. + */ + +unsigned acl_hash_func3(const void *key, size_t len) +{ + const unsigned char *k; + unsigned n, loop; + +#define HASHC n = *k++ + 65599 * n + n = 0; + k = (const unsigned char *) key; + + loop = (len + 8 - 1) >> 3; + switch (len & (8 - 1)) { + case 0: + do { + HASHC; + case 7: + HASHC; + case 6: + HASHC; + case 5: + HASHC; + case 4: + HASHC; + case 3: + HASHC; + case 2: + HASHC; + case 1: + HASHC; + } while (--loop); + } + + return (n); +} + +/** + * Chris Torek's hash function. Although this function performs only + * slightly worse than __ham_func5 on strings, it performs horribly on numbers. + */ + +unsigned acl_hash_func4(const void *key, size_t len) +{ + const unsigned char *k = (const unsigned char *) key; + size_t loop; + unsigned int h; + +#define HASH4a h = (h << 5) - h + *k++; +#define HASH4b h = (h << 5) + h + *k++; +#define HASH4 HASH4b + + h = 0; + loop = len >> 3; + switch (len & (8 - 1)) { + case 0: + break; + case 7: + HASH4; + /* FALLTHROUGH */ + case 6: + HASH4; + /* FALLTHROUGH */ + case 5: + HASH4; + /* FALLTHROUGH */ + case 4: + HASH4; + /* FALLTHROUGH */ + case 3: + HASH4; + /* FALLTHROUGH */ + case 2: + HASH4; + /* FALLTHROUGH */ + case 1: + HASH4; + } + + while (loop--) { + HASH4; + HASH4; + HASH4; + HASH4; + HASH4; + HASH4; + HASH4; + HASH4; + } + + return (h); +} + +/* + * Fowler/Noll/Vo hash + * + * The basis of the hash algorithm was taken from an idea sent by email to the + * IEEE Posix P1003.2 mailing list from Phong Vo (kpv@research.att.com) and + * Glenn Fowler (gsf@research.att.com). Landon Curt Noll (chongo@toad.com) + * later improved on their algorithm. + * + * The magic is in the interesting relationship between the special prime + * 16777619 (2^24 + 403) and 2^32 and 2^8. + * + * This hash produces the fewest collisions of any function that we've seen so + * far, and works well on both numbers and strings. + * + */ + +unsigned acl_hash_func5(const void *key, size_t len) +{ + const unsigned char *k, *e; + unsigned h; + + k = (const unsigned char *) key; + e = k + len; + for (h = 0; k < e; ++k) { + h *= 16777619; + h ^= *k; + } + + return (h); +} + +/* come from squid */ +unsigned acl_hash_func6(const void *key, size_t len) +{ + const unsigned char *s = (const unsigned char *) key; + unsigned int n = 0; + unsigned int j = 0; + unsigned int i = 0; + + while (len-- > 0) { + j++; + n ^= 271 * (unsigned) *s++; + } + + i = n ^ (j * 271); + return (i); +} diff --git a/lib_acl/src/stdlib/common/acl_htable.c b/lib_acl/src/stdlib/common/acl_htable.c new file mode 100644 index 000000000..007ba9f17 --- /dev/null +++ b/lib_acl/src/stdlib/common/acl_htable.c @@ -0,0 +1,1156 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "thread/acl_pthread.h" +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_msg.h" +#include "stdlib/acl_slice.h" +#include "stdlib/acl_iterator.h" +#include "stdlib/acl_htable.h" +#include "stdlib/acl_mystring.h" + +#endif + +/* htable_iter_head */ + +static void *htable_iter_head(ACL_ITER *iter, ACL_HTABLE *table) +{ + ACL_HTABLE_INFO *ptr = NULL; + + iter->dlen = -1; + iter->klen = -1; + iter->i = 0; + iter->size = table->size; + iter->ptr = NULL; + + for (; iter->i < iter->size; iter->i++) { + if (table->data[iter->i] != NULL) { + iter->ptr = ptr = table->data[iter->i]; + break; + } + } + + if (ptr) { + iter->data = ptr->value; + iter->key = ptr->key.c_key; + } else { + iter->data = NULL; + iter->key = NULL; + } + return (iter->ptr); +} + +/* htable_iter_next */ + +static void *htable_iter_next(ACL_ITER *iter, ACL_HTABLE *table) +{ + ACL_HTABLE_INFO *ptr; + + ptr = (ACL_HTABLE_INFO*) iter->ptr; + if (ptr) { + iter->ptr = ptr = ptr->next; + if (ptr != NULL) { + iter->data = ptr->value; + iter->key = ptr->key.c_key; + return (iter->ptr); + } + } + + for (iter->i++; iter->i < iter->size; iter->i++) { + if (table->data[iter->i] != NULL) { + iter->ptr = ptr = table->data[iter->i]; + break; + } + } + + if (ptr) { + iter->data = ptr->value; + iter->key = ptr->key.c_key; + } else { + iter->data = NULL; + iter->key = NULL; + } + return (iter->ptr); +} + +/* htable_iter_tail */ + +static void *htable_iter_tail(ACL_ITER *iter, ACL_HTABLE *table) +{ + ACL_HTABLE_INFO *ptr = NULL; + + iter->dlen = -1; + iter->klen = -1; + iter->i = table->size - 1; + iter->size = table->size; + iter->ptr = NULL; + + for (; iter->i >= 0; iter->i--) { + if (table->data[iter->i] != NULL) { + iter->ptr = ptr = table->data[iter->i]; + break; + } + } + + if (ptr) { + iter->data = ptr->value; + iter->key = ptr->key.c_key; + } else { + iter->data = NULL; + iter->key = NULL; + } + return (iter->ptr); +} + +/* htable_iter_prev */ + +static void *htable_iter_prev(ACL_ITER *iter, ACL_HTABLE *table) +{ + ACL_HTABLE_INFO *ptr; + + ptr = (ACL_HTABLE_INFO*) iter->ptr; + if (ptr) { + iter->ptr = ptr = ptr->next; + if (ptr != NULL) { + iter->data = ptr->value; + iter->key = ptr->key.c_key; + return (iter->ptr); + } + } + + for (iter->i--; iter->i >= 0; iter->i--) { + if (table->data[iter->i] != NULL) { + iter->ptr = ptr = table->data[iter->i]; + break; + } + } + + if (ptr) { + iter->data = ptr->value; + iter->key = ptr->key.c_key; + } else { + iter->data = NULL; + iter->key = NULL; + } + return (iter->ptr); +} + +/* htable_iter_info */ + +static ACL_HTABLE_INFO *htable_iter_info(ACL_ITER *iter, struct ACL_HTABLE *table acl_unused) +{ + return (iter->ptr ? (ACL_HTABLE_INFO*) iter->ptr : NULL); +} + +/* __def_hash_fn - hash a string */ + +static unsigned __def_hash_fn(const void *buffer, size_t len) +{ + unsigned long h = 0; + unsigned long g; + const unsigned char* s = (const unsigned char *) buffer; + + /* + * From the "Dragon" book by Aho, Sethi and Ullman. + */ + + while (len-- > 0) { + h = (h << 4) + *s++; + if ((g = (h & 0xf0000000)) != 0) { + h ^= (g >> 24); + h ^= g; + } + } + + return (h); +} +/* htable_link - insert element into table */ + +#define htable_link(_table, _element, _n) { \ + ACL_HTABLE_INFO **_h = _table->data + _n; \ + _element->prev = 0; \ + if ((_element->next = *_h) != 0) \ + (*_h)->prev = _element; \ + *_h = _element; \ + _table->used++; \ +} + +/* htable_size - allocate and initialize hash table */ + +static int htable_size(ACL_HTABLE *table, unsigned size) +{ + ACL_HTABLE_INFO **h; + + size |= 1; + + if (table->slice) + table->data = h = (ACL_HTABLE_INFO **) + acl_slice_pool_alloc(__FILE__, __LINE__, table->slice, + size * sizeof(ACL_HTABLE_INFO *)); + else + table->data = h = (ACL_HTABLE_INFO **) + acl_mymalloc(size * sizeof(ACL_HTABLE_INFO *)); + if(table->data == NULL) + return(-1); + + table->size = size; + table->used = 0; + + while (size-- > 0) + *h++ = 0; + + return(0); +} + +/* htable_grow - extend existing table */ + +static int htable_grow(ACL_HTABLE *table) +{ + int ret; + ACL_HTABLE_INFO *ht; + ACL_HTABLE_INFO *next; + unsigned old_size = table->size; + ACL_HTABLE_INFO **h0 = table->data; + ACL_HTABLE_INFO **old_entries = h0; + unsigned n; + + ret = htable_size(table, 2 * old_size); + if (ret < 0) + return(-1); + + while (old_size-- > 0) { + for (ht = *h0++; ht; ht = next) { + next = ht->next; + n = table->hash_fn(ht->key.c_key, + strlen(ht->key.c_key)) % table->size; + htable_link(table, ht, n); + } + } + + if (table->slice) + acl_slice_pool_free(__FILE__, __LINE__, old_entries); + else + acl_myfree(old_entries); + return(0); +} + +#define _RWLOCK_TYPE acl_pthread_mutex_t +#define _RWLOCK_INIT acl_pthread_mutex_init +#define _RWLOCK_DESTROY acl_pthread_mutex_destroy +#define _RWLOCK_RDLOCK acl_pthread_mutex_lock +#define _RWLOCK_WRLOCK acl_pthread_mutex_lock +#define _RWLOCK_UNLOCK acl_pthread_mutex_unlock + +static int __init_table_rwlock(ACL_HTABLE *table, int enable) +{ + const char *myname = "__init_table_rwlock"; + char tbuf[256]; + int ret; + + if (enable && table->rwlock == NULL) { + if (table->slice) + table->rwlock = acl_slice_pool_calloc(__FILE__, __LINE__, + table->slice, 1, sizeof(_RWLOCK_TYPE)); + else + table->rwlock = acl_mycalloc(1, sizeof(_RWLOCK_TYPE)); + if (table->rwlock == NULL) { + acl_msg_error("%s(%s): calloc error(%s)", + __FILE__, myname, acl_last_strerror(tbuf, sizeof(tbuf))); + return (-1); + } + + ret = _RWLOCK_INIT(table->rwlock, NULL); + if (ret) { + acl_msg_error("%s(%d): init rwlock error(%s)", + __FILE__, __LINE__, acl_strerror(ret, tbuf, sizeof(tbuf))); + if (table->slice) + acl_slice_pool_free(__FILE__, __LINE__, table->rwlock); + else + acl_myfree(table->rwlock); + return (-1); + } + } else if (!enable && table->rwlock) { + _RWLOCK_DESTROY(table->rwlock); + if (table->slice) + acl_slice_pool_free(__FILE__, __LINE__, table->rwlock); + else + acl_myfree(table->rwlock); + table->rwlock = NULL; + } + + return (0); +} + +/* acl_htable_create - create initial hash table */ + +ACL_HTABLE *acl_htable_create(int size, unsigned int flag) +{ + return (acl_htable_create3(size, flag, NULL)); +} + +ACL_HTABLE *acl_htable_create3(int size, unsigned int flag, ACL_SLICE_POOL *slice) +{ + ACL_HTABLE *table; + int ret; + + if (slice) { + table = (ACL_HTABLE *) acl_slice_pool_calloc(__FILE__, __LINE__, + slice, 1, sizeof(ACL_HTABLE)); + if (table == NULL) + return (NULL); + table->slice = slice; + } else { + table = (ACL_HTABLE *) acl_mycalloc(1, sizeof(ACL_HTABLE)); + if (table == NULL) + return (NULL); + table->slice = NULL; + } + + table->init_size = size; + table->flag = flag; + + ret = htable_size(table, size < 13 ? 13 : size); + if(ret < 0) { + if (table->slice) + acl_slice_pool_free(__FILE__, __LINE__, table); + else + acl_myfree(table); + return(NULL); + } + + table->hash_fn = __def_hash_fn; + + table->iter_head = htable_iter_head; + table->iter_next = htable_iter_next; + table->iter_tail = htable_iter_tail; + table->iter_prev = htable_iter_prev; + table->iter_info = htable_iter_info; + + if ((flag & ACL_HTABLE_FLAG_USE_LOCK)) { + ret = __init_table_rwlock(table, 1); + if (ret < 0) { + if (table->slice) + acl_slice_pool_free(__FILE__, __LINE__, table); + else + acl_myfree(table); + return (NULL); + } + } else + table->rwlock = NULL; + + return (table); +} + +#ifdef ACL_BCB_COMPILER +static void LOCK_TABLE_READ(const ACL_HTABLE *table) +{ + if (table->rwlock && _RWLOCK_RDLOCK(table->rwlock) != 0) { + acl_msg_fatal("%s(%d): read lock error", + __FILE__, __LINE__); + } +} + +static void LOCK_TABLE_WRITE(const ACL_HTABLE *table) +{ + if (table->rwlock && _RWLOCK_WRLOCK(table->rwlock) != 0) { + acl_msg_fatal("%s(%d): write lock error", + __FILE__, __LINE__); + } +} + +static void UNLOCK_TABLE(const ACL_HTABLE *table) +{ + if (table->rwlock && _RWLOCK_UNLOCK(table->rwlock) != 0) { + acl_msg_fatal("%s(%d): unlock error", + __FILE__, __LINE__); + } +} +#else +#define LOCK_TABLE_READ(_table) do { \ + int _ret; \ + if (_table->rwlock && (_ret = _RWLOCK_RDLOCK(_table->rwlock))) { \ + acl_msg_fatal("%s(%d): read lock error(%s)", \ + __FILE__, __LINE__, strerror(_ret)); \ + } \ +} while (0) + +#define LOCK_TABLE_WRITE(_table) do { \ + int _ret; \ + if (_table->rwlock && (_ret = _RWLOCK_WRLOCK(_table->rwlock))) { \ + acl_msg_fatal("%s(%d): write lock error(%s)", \ + __FILE__, __LINE__, strerror(_ret)); \ + } \ +} while (0) + +#define UNLOCK_TABLE(_table) do { \ + int _ret; \ + if (_table->rwlock && (_ret = _RWLOCK_UNLOCK(_table->rwlock))) { \ + acl_msg_fatal("%s(%d): unlock error(%s)", \ + __FILE__, __LINE__, strerror(_ret)); \ + } \ +} while (0) +#endif + +void acl_htable_ctl(ACL_HTABLE *table, int name, ...) +{ + const char *myname = "acl_htable_ctl"; + va_list ap; + + if (table == NULL) + return; + + va_start(ap, name); + for (; name != ACL_HTABLE_CTL_END; name = va_arg(ap, int)) { + switch (name) { + case ACL_HTABLE_CTL_HASH_FN: + table->hash_fn = va_arg(ap, ACL_HASH_FN); + if (table->hash_fn == NULL) + table->hash_fn = __def_hash_fn; + break; + case ACL_HTABLE_CTL_RWLOCK: + if (__init_table_rwlock(table, va_arg(ap, int)) < 0) + acl_msg_fatal("%s: init rwlock error", myname); + + break; + default: + acl_msg_fatal("%s: bad name %d", myname, name); + } + } + va_end(ap); +} + +int acl_htable_errno(ACL_HTABLE *table) +{ + if (table == NULL) + return (ACL_HTABLE_STAT_INVAL); + return (table->status); +} + +void acl_htable_set_errno(ACL_HTABLE *table, int error) +{ + if (table) + table->status = error; +} + +#define STREQ(x,y) (x == y || (x[0] == y[0] && strcmp(x,y) == 0)) + +/* acl_htable_enter - enter (key, value) pair */ + +ACL_HTABLE_INFO *acl_htable_enter(ACL_HTABLE *table, const char *key_in, void *value) +{ + const char *myname = "acl_htable_enter"; + ACL_HTABLE_INFO *ht; + int ret; + unsigned n; + char *keybuf = NULL; + const char *key; + +#undef RETURN +#define RETURN(x) do \ +{ \ + if (keybuf) { \ + if (table->slice) \ + acl_slice_pool_free(__FILE__, __LINE__, keybuf); \ + else \ + acl_myfree(keybuf); \ + } \ + return (x); \ +} while (0) + + if ((table->flag & ACL_HTABLE_FLAG_KEY_LOWER)) { + if (table->slice) + keybuf = acl_slice_pool_strdup(__FILE__, __LINE__, + table->slice, key_in); + else + keybuf = acl_mystrdup(key_in); + acl_lowercase(keybuf); + key = keybuf; + } else + key = key_in; + + table->status = ACL_HTABLE_STAT_OK; + n = table->hash_fn(key, strlen(key)); + + if (table->used >= table->size) { + ret = htable_grow(table); + if(ret < 0) { + RETURN (NULL); + } + } + + n = n % table->size; + + for (ht = table->data[n]; ht; ht = ht->next) { + if (STREQ(key, ht->key.c_key)) { + table->status = ACL_HTABLE_STAT_DUPLEX_KEY; + acl_msg_info("%s(%d): duplex key(%s) exist", + myname, __LINE__, key); + RETURN (ht); + } + } + + if (table->slice) + ht = (ACL_HTABLE_INFO*) acl_slice_pool_alloc(__FILE__, __LINE__, + table->slice, sizeof(ACL_HTABLE_INFO)); + else + ht = (ACL_HTABLE_INFO *) acl_mymalloc(sizeof(ACL_HTABLE_INFO)); + if (ht == NULL) { + acl_msg_error("%s(%d): alloc error", myname, __LINE__); + RETURN (NULL); + } + + if ((table->flag & ACL_HTABLE_FLAG_KEY_REUSE)) + ht->key.c_key = key; + else { + if (table->slice) + ht->key.key = acl_slice_pool_strdup(__FILE__, __LINE__, + table->slice, key); + else + ht->key.key = acl_mystrdup(key); + if (ht->key.key == NULL) { + acl_msg_error("%s(%d): alloc error", myname, __LINE__); + if (table->slice) + acl_slice_pool_free(__FILE__, __LINE__, ht); + else + acl_myfree(ht); + RETURN (NULL); + } + } + + ht->value = value; + htable_link(table, ht, n); + RETURN (ht); +} + +int acl_htable_enter_r(ACL_HTABLE *table, const char *key_in, void *value, + void (*callback)(ACL_HTABLE_INFO *ht, void *arg), void *arg) +{ + const char *myname = "acl_htable_enter_r"; + ACL_HTABLE_INFO *ht; + int ret; + unsigned n; + char *keybuf = NULL; + const char *key; + +#undef RETURN +#define RETURN(x) do \ +{ \ + if (keybuf) { \ + if (table->slice) \ + acl_slice_pool_free(__FILE__, __LINE__, keybuf); \ + else \ + acl_myfree(keybuf); \ + } \ + return (x); \ +} while (0) + + if ((table->flag & ACL_HTABLE_FLAG_KEY_LOWER)) { + if (table->slice) + keybuf = acl_slice_pool_strdup(__FILE__, __LINE__, + table->slice, key_in); + else + keybuf = acl_mystrdup(key_in); + acl_lowercase(keybuf); + key = keybuf; + } else + key = key_in; + + n = table->hash_fn(key, strlen(key)); + + table->status = ACL_HTABLE_STAT_OK; + LOCK_TABLE_WRITE(table); + + if (table->used >= table->size) { + ret = htable_grow(table); + if(ret < 0) { + UNLOCK_TABLE(table); + RETURN (-1); + } + } + + n = n % table->size; + + for (ht = table->data[n]; ht; ht = ht->next) { + if (STREQ(key, ht->key.c_key)) { + acl_msg_info("%s(%d): duplex key(%s) exist", + myname, __LINE__, key); + table->status = ACL_HTABLE_STAT_DUPLEX_KEY; + if (callback) + callback(ht, arg); + UNLOCK_TABLE(table); + RETURN (0); + } + } + + if (table->slice) + ht = (ACL_HTABLE_INFO*) acl_slice_pool_alloc(__FILE__, __LINE__, + table->slice, sizeof(ACL_HTABLE_INFO)); + else + ht = (ACL_HTABLE_INFO *) acl_mymalloc(sizeof(ACL_HTABLE_INFO)); + + if ((table->flag & ACL_HTABLE_FLAG_KEY_REUSE)) + ht->key.c_key = key; + else if (table->slice) + ht->key.key = acl_slice_pool_strdup(__FILE__, __LINE__, + table->slice, key); + else + ht->key.key = acl_mystrdup(key); + + ht->value = value; + htable_link(table, ht, n); + + if (callback) + callback(ht, arg); + + UNLOCK_TABLE(table); + + RETURN (0); +} +/* acl_htable_find - lookup value */ + +void *acl_htable_find(ACL_HTABLE *table, const char *key_in) +{ + ACL_HTABLE_INFO *ht; + unsigned n; + char *keybuf = NULL; + const char *key; + +#undef RETURN +#define RETURN(x) do \ +{ \ + if (keybuf) { \ + if (table->slice) \ + acl_slice_pool_free(__FILE__, __LINE__, keybuf); \ + else \ + acl_myfree(keybuf); \ + } \ + return (x); \ +} while (0) + + if ((table->flag & ACL_HTABLE_FLAG_KEY_LOWER)) { + if (table->slice) + keybuf = acl_slice_pool_strdup(__FILE__, __LINE__, + table->slice, key_in); + else + keybuf = acl_mystrdup(key_in); + acl_lowercase(keybuf); + key = keybuf; + } else + key = key_in; + + n = table->hash_fn(key, strlen(key)); + + n = n % table->size; + + for (ht = table->data[n]; ht; ht = ht->next) { + if (STREQ(key, ht->key.c_key)) { + if (!(table->flag & ACL_HTABLE_FLAG_MSLOOK)) + RETURN (ht->value); + if (ht == table->data[n]) + RETURN (ht->value); + if (ht->next) { + ht->prev->next = ht->next; + ht->next->prev = ht->prev; + } else { + ht->prev->next = NULL; + } + table->data[n]->prev = ht; + ht->prev = NULL; + ht->next = table->data[n]; + table->data[n] = ht; + RETURN (ht->value); + } + } + + RETURN (NULL); +} + +int acl_htable_find_r(ACL_HTABLE *table, const char *key_in, + void (*callback)(void *value, void *arg), void *arg) +{ + ACL_HTABLE_INFO *ht; + unsigned n; + char *keybuf = NULL; + const char *key; + +#undef RETURN +#define RETURN(x) do \ +{ \ + if (keybuf) { \ + if (table->slice) \ + acl_slice_pool_free(__FILE__, __LINE__, keybuf); \ + else \ + acl_myfree(keybuf); \ + } \ + return (x); \ +} while (0) + + if ((table->flag & ACL_HTABLE_FLAG_KEY_LOWER)) { + if (table->slice) + keybuf = acl_slice_pool_strdup(__FILE__, __LINE__, + table->slice, key_in); + else + keybuf = acl_mystrdup(key_in); + acl_lowercase(keybuf); + key = keybuf; + } else + key = key_in; + + n = table->hash_fn(key, strlen(key)); + + LOCK_TABLE_READ(table); + + n = n % table->size; + + for (ht = table->data[n]; ht; ht = ht->next) { + if (STREQ(key, ht->key.c_key)) { + if (callback) + callback(ht->value, arg); + + if (!(table->flag & ACL_HTABLE_FLAG_MSLOOK)) { + UNLOCK_TABLE(table); + RETURN (0); + } + if (ht == table->data[n]) { + UNLOCK_TABLE(table); + RETURN (0); + } + if (ht->next) { + ht->prev->next = ht->next; + ht->next->prev = ht->prev; + } else { + ht->prev->next = NULL; + } + table->data[n]->prev = ht; + ht->prev = NULL; + ht->next = table->data[n]; + table->data[n] = ht; + + UNLOCK_TABLE(table); + RETURN (0); + } + } + + UNLOCK_TABLE(table); + + RETURN (-1); +} + +/* acl_htable_locate - lookup entry */ + +ACL_HTABLE_INFO *acl_htable_locate(ACL_HTABLE *table, const char *key_in) +{ + ACL_HTABLE_INFO *ht; + unsigned n; + char *keybuf = NULL; + const char *key; + +#undef RETURN +#define RETURN(x) do \ +{ \ + if (keybuf) { \ + if (table->slice) \ + acl_slice_pool_free(__FILE__, __LINE__, keybuf); \ + else \ + acl_myfree(keybuf); \ + } \ + return (x); \ +} while (0) + + if ((table->flag & ACL_HTABLE_FLAG_KEY_LOWER)) { + if (table->slice) + keybuf = acl_slice_pool_strdup(__FILE__, __LINE__, + table->slice, key_in); + else + keybuf = acl_mystrdup(key_in); + acl_lowercase(keybuf); + key = keybuf; + } else + key = key_in; + + n = table->hash_fn(key, strlen(key)); + + n = n % table->size; + + for (ht = table->data[n]; ht; ht = ht->next) { + if (STREQ(key, ht->key.c_key)) { + RETURN (ht); + } + } + + RETURN (NULL); +} + +int acl_htable_locate_r(ACL_HTABLE *table, const char *key_in, + void (*callback)(ACL_HTABLE_INFO *ht, void *arg), void *arg) +{ + ACL_HTABLE_INFO *ht; + unsigned n; + char *keybuf = NULL; + const char *key; + +#undef RETURN +#define RETURN(x) do \ +{ \ + if (keybuf) { \ + if (table->slice) \ + acl_slice_pool_free(__FILE__, __LINE__, keybuf); \ + else \ + acl_myfree(keybuf); \ + } \ + return (x); \ +} while (0) + + if ((table->flag & ACL_HTABLE_FLAG_KEY_LOWER)) { + if (table->slice) + keybuf = acl_slice_pool_strdup(__FILE__, __LINE__, + table->slice, key_in); + else + keybuf = acl_mystrdup(key_in); + acl_lowercase(keybuf); + key = keybuf; + } else + key = key_in; + + n = table->hash_fn(key, strlen(key)); + + LOCK_TABLE_READ(table); + + n = n % table->size; + + for (ht = table->data[n]; ht; ht = ht->next) { + if (STREQ(key, ht->key.c_key)) { + if (callback) + callback(ht, arg); + UNLOCK_TABLE(table); + RETURN (0); + } + } + + UNLOCK_TABLE(table); + + RETURN (-1); +} + +/* acl_htable_delete - delete one entry */ + +int acl_htable_delete(ACL_HTABLE *table, const char *key_in, void (*free_fn) (void *)) +{ + ACL_HTABLE_INFO *ht; + unsigned n; + ACL_HTABLE_INFO **h; + char *keybuf = NULL; + const char *key; + +#undef RETURN +#define RETURN(x) do \ +{ \ + if (keybuf) { \ + if (table->slice) \ + acl_slice_pool_free(__FILE__, __LINE__, keybuf); \ + else \ + acl_myfree(keybuf); \ + } \ + return (x); \ +} while (0) + + if ((table->flag & ACL_HTABLE_FLAG_KEY_LOWER)) { + if (table->slice) + keybuf = acl_slice_pool_strdup(__FILE__, __LINE__, + table->slice, key_in); + else + keybuf = acl_mystrdup(key_in); + acl_lowercase(keybuf); + key = keybuf; + } else + key = key_in; + + n = table->hash_fn(key, strlen(key)); + + LOCK_TABLE_WRITE(table); + + n = n % table->size; + + h = table->data + n; + for (ht = *h; ht; ht = ht->next) { + if (STREQ(key, ht->key.c_key)) { + if (ht->next) + ht->next->prev = ht->prev; + if (ht->prev) + ht->prev->next = ht->next; + else + *h = ht->next; + if (!(table->flag & ACL_HTABLE_FLAG_KEY_REUSE)) { + if (table->slice) + acl_slice_pool_free(__FILE__, __LINE__, + ht->key.key); + else + acl_myfree(ht->key.key); + } + if (free_fn && ht->value) + (*free_fn) (ht->value); + if (table->slice) + acl_slice_pool_free(__FILE__, __LINE__, ht); + else + acl_myfree(ht); + table->used--; + UNLOCK_TABLE(table); + RETURN(0); + } + } + + UNLOCK_TABLE(table); + RETURN(-1); +} + +/* acl_htable_free - destroy hash table */ + +void acl_htable_free(ACL_HTABLE *table, void (*free_fn) (void *)) +{ + unsigned i = table->size; + ACL_HTABLE_INFO *ht; + ACL_HTABLE_INFO *next; + ACL_HTABLE_INFO **h = table->data; + + while (i-- > 0) { + for (ht = *h++; ht; ht = next) { + next = ht->next; + if (!(table->flag & ACL_HTABLE_FLAG_KEY_REUSE)) { + if (table->slice) + acl_slice_pool_free(__FILE__, __LINE__, + ht->key.key); + else + acl_myfree(ht->key.key); + } + if (free_fn && ht->value) + (*free_fn) (ht->value); + if (table->slice) + acl_slice_pool_free(__FILE__, __LINE__, ht); + else + acl_myfree(ht); + } + } + + if (table->slice) + acl_slice_pool_free(__FILE__, __LINE__, table->data); + else + acl_myfree(table->data); + table->data = 0; + if (table->rwlock) { + _RWLOCK_DESTROY(table->rwlock); + if (table->slice) + acl_slice_pool_free(__FILE__, __LINE__, table->rwlock); + else + acl_myfree(table->rwlock); + } + + if (table->slice) + acl_slice_pool_free(__FILE__, __LINE__, table); + else + acl_myfree(table); +} + +int acl_htable_reset(ACL_HTABLE *table, void (*free_fn) (void *)) +{ + unsigned i = table->size; + ACL_HTABLE_INFO *ht; + ACL_HTABLE_INFO *next; + ACL_HTABLE_INFO **h; + int ret; + + LOCK_TABLE_WRITE(table); + + h = table->data; + + while (i-- > 0) { + for (ht = *h++; ht; ht = next) { + next = ht->next; + if (!(table->flag & ACL_HTABLE_FLAG_KEY_REUSE)) { + if (table->slice) + acl_slice_pool_free(__FILE__, __LINE__, ht->key.key); + else + acl_myfree(ht->key.key); + } + if (free_fn && ht->value) + (*free_fn) (ht->value); + if (table->slice) + acl_slice_pool_free(__FILE__, __LINE__, ht); + else + acl_myfree(ht); + } + } + if (table->slice) + acl_slice_pool_free(__FILE__, __LINE__, table->data); + else + acl_myfree(table->data); + ret = htable_size(table, table->init_size < 13 ? 13 : table->init_size); + + UNLOCK_TABLE(table); + return (ret); +} + +const ACL_HTABLE_INFO *acl_htable_iter_head(ACL_HTABLE *table, ACL_HTABLE_ITER *iter) +{ + iter->i = 0; + iter->size = table->size; + iter->h = table->data; + iter->ptr = NULL; + + for (; iter->i < iter->size; iter->i++) { + if (iter->h[iter->i] != 0) { + iter->ptr = iter->h[iter->i]; + break; + } + } + + return (iter->ptr); +} + +const ACL_HTABLE_INFO *acl_htable_iter_next(ACL_HTABLE_ITER *iter) +{ + if (iter->ptr) { + iter->ptr = iter->ptr->next; + if (iter->ptr != NULL) + return (iter->ptr); + } + + for (iter->i++; iter->i < iter->size; iter->i++) { + if (iter->h[iter->i] != 0) { + iter->ptr = iter->h[iter->i]; + break; + } + } + + return (iter->ptr); +} + +const ACL_HTABLE_INFO *acl_htable_iter_tail(ACL_HTABLE *table, ACL_HTABLE_ITER *iter) +{ + iter->i = table->size - 1; + iter->size = table->size; + iter->h = table->data; + iter->ptr = NULL; + + for (; iter->i >= 0; iter->i--) { + if (iter->h[iter->i] != 0) { + iter->ptr = iter->h[iter->i]; + break; + } + } + + return (iter->ptr); +} + +const ACL_HTABLE_INFO *acl_htable_iter_prev(ACL_HTABLE_ITER *iter) +{ + if (iter->ptr) { + iter->ptr = iter->ptr->next; + if (iter->ptr != NULL) + return (iter->ptr); + } + + for (iter->i--; iter->i >= 0; iter->i--) { + if (iter->h[iter->i] != 0) { + iter->ptr = iter->h[iter->i]; + break; + } + } + + return (iter->ptr); +} + +/* acl_htable_walk - iterate over hash table */ + +void acl_htable_walk(ACL_HTABLE *table, void (*action)(ACL_HTABLE_INFO *, void *), void *arg) +{ + unsigned i = table->size; + ACL_HTABLE_INFO **h = table->data; + ACL_HTABLE_INFO *ht; + + LOCK_TABLE_READ(table); + while (i-- > 0) + for (ht = *h++; ht; ht = ht->next) + (*action) (ht, arg); + UNLOCK_TABLE(table); +} + +int acl_htable_size(const ACL_HTABLE *table) +{ + if (table) + return (table->size); + else + return (0); +} + +int acl_htable_used(const ACL_HTABLE *table) +{ + if (table) + return (table->used); + else + return (0); +} + +ACL_HTABLE_INFO **acl_htable_data(ACL_HTABLE *table) +{ + return ((ACL_HTABLE_INFO**) table->data); +} + +/* acl_htable_list - list all table members */ + +ACL_HTABLE_INFO **acl_htable_list(const ACL_HTABLE *table) +{ + ACL_HTABLE_INFO **list; + ACL_HTABLE_INFO *member; + int count = 0; + int i; + + if (table != 0) { + list = (ACL_HTABLE_INFO **) acl_mymalloc(sizeof(*list) * (table->used + 1)); + for (i = 0; i < table->size; i++) + for (member = table->data[i]; member != 0; member = member->next) + list[count++] = member; + } else { + list = (ACL_HTABLE_INFO **) acl_mymalloc(sizeof(*list)); + } + list[count] = 0; + return (list); +} + +void acl_htable_stat(const ACL_HTABLE *table) +{ + ACL_HTABLE_INFO *member; + int i, count; + + LOCK_TABLE_READ(table); + printf("hash stat count for each key:\n"); + for(i = 0; i < table->size; i++) { + count = 0; + member = table->data[i]; + for(; member != 0; member = member->next) + count++; + if(count > 0) + printf("chains[%d]: count[%d]\n", i, count); + } + + printf("hash stat all values for each key:\n"); + for(i = 0; i < table->size; i++) { + member = table->data[i]; + if(member) { + printf("chains[%d]: ", i); + for(; member != 0; member = member->next) + printf("[%s]", member->key.c_key); + printf("\n"); + } + } + printf("hash table size=%d, used=%d\n", table->size, table->used); + UNLOCK_TABLE(table); +} diff --git a/lib_acl/src/stdlib/common/acl_iplink.c b/lib_acl/src/stdlib/common/acl_iplink.c new file mode 100644 index 000000000..b0ef49ec2 --- /dev/null +++ b/lib_acl/src/stdlib/common/acl_iplink.c @@ -0,0 +1,198 @@ +#include "StdAfx.h" + +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#ifdef ACL_UNIX +#include +#include +#include +#include +#endif + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_mystring.h" +#include "stdlib/acl_msg.h" +#include "stdlib/acl_array.h" +#include "stdlib/acl_dlink.h" +#include "stdlib/acl_iplink.h" + +#endif + +static int _check_ip_addr(const char *pstrip) +{ + const char *ptr; + int count = 0; + + if (pstrip == NULL || *pstrip == 0) + return(-1); + + ptr = pstrip; + if(*ptr == '.') /* the first char should not be '.' */ + return(-1); + while(*ptr) { + if (*ptr == '.') { + if (!isdigit((int)*(ptr + 1))) + return(-1); + count++; + } else if (!isdigit((int)*ptr)) + return(-1); + ptr++; + } + if(*(ptr - 1) == '.') /* the last char should not be '.' */ + return(-1); + if(count != 3) /* 192.168.0.1 has the number '.' is 4 */ + return(-1); + + return(0); +} + +ACL_IPLINK *acl_iplink_create(int nsize) +{ + return acl_dlink_create(nsize); +} + +void acl_iplink_free(ACL_IPLINK *lnk) +{ + if (lnk) + acl_dlink_free(lnk); +} + +ACL_IPITEM *acl_iplink_lookup_item(const ACL_IPLINK *plink, + ACL_IPITEM *pitem) +{ + return acl_dlink_lookup_by_item(plink, pitem); +} + +ACL_IPITEM *acl_iplink_lookup_bin(const ACL_IPLINK *plink, unsigned int ip) +{ + return acl_dlink_lookup(plink, ip); +} + +ACL_IPITEM *acl_iplink_lookup_str(const ACL_IPLINK *plink, const char *ipstr) +{ + unsigned int ip; + + ip = (unsigned int) ntohl(inet_addr(ipstr)); + return acl_iplink_lookup_bin(plink, ip); +} + +ACL_IPITEM *acl_iplink_insert_bin(ACL_IPLINK *plink, + unsigned int ip_begin, unsigned int ip_end) +{ + return acl_dlink_insert(plink, ip_begin, ip_end); +} + +ACL_IPITEM *acl_iplink_insert(ACL_IPLINK *plink, + const char *pstrip_begin, const char *pstrip_end ) +{ + const char *myname = "acl_iplink_insert"; + unsigned int ip_begin, ip_end; + + if (_check_ip_addr(pstrip_begin) < 0) { + acl_msg_error("%s: invalid ip begin(%s)", myname, pstrip_begin); + return NULL; + } + if (_check_ip_addr(pstrip_end) < 0) { + acl_msg_error("%s: invalid ip end(%s)", myname, pstrip_end); + return NULL; + } + + ip_begin = (unsigned int) ntohl(inet_addr(pstrip_begin)); + ip_end = (unsigned int) ntohl(inet_addr(pstrip_end)); + + return acl_iplink_insert_bin(plink, ip_begin, ip_end); +} + +int acl_iplink_delete_by_ip(ACL_IPLINK *plink, const char *pstrip_begin) +{ + unsigned int ip; + + if (_check_ip_addr(pstrip_begin) < 0) + return -1; + + ip = (unsigned int) ntohl(inet_addr(pstrip_begin)); + return acl_dlink_delete(plink, ip); +} + +int acl_iplink_delete_by_item(ACL_IPLINK *plink, ACL_IPITEM *pitem) +{ + return acl_dlink_delete_by_item(plink, pitem); +} + +ACL_IPITEM *acl_iplink_modify(ACL_IPLINK *plink, const char *pstrip_id, + const char *pstrip_begin, const char *pstrip_end) +{ + unsigned int ip_begin, ip_end; + + if (_check_ip_addr(pstrip_id) < 0 + || _check_ip_addr(pstrip_begin) < 0 + || _check_ip_addr(pstrip_end) < 0) + return NULL; + + ip_begin = (unsigned int) ntohl(inet_addr(pstrip_begin)); + ip_end = (unsigned int) ntohl(inet_addr(pstrip_end)); + + return acl_dlink_modify(plink, ip_begin, ip_end); +} + +int acl_iplink_count_item(ACL_IPLINK *plink) +{ + return acl_array_size(plink->parray); +} + +/* ++++++++++++++++++++++++++below functions are used only for test ++++++++++++ */ +static char *__sane_inet_ntoa(unsigned int src, char *dst, size_t size) +{ + unsigned char *bytes; + struct in_addr in; + + if (size < 16) + return(NULL); + + /* XXX: may be bugfix here---zsx */ +/* in.s_addr = ntohl(src); */ + in.s_addr = src; + bytes = (unsigned char *) ∈ +#ifdef LINUX2 + snprintf (dst, 18, "%d.%d.%d.%d", bytes[3], bytes[2], bytes[1], bytes[0]); +#elif defined(SUNOS5) + snprintf (dst, 18, "%d.%d.%d.%d", bytes[0], bytes[1], bytes[2], bytes[3]); +#elif defined(HP_UX) + snprintf (dst, 18, "%d.%d.%d.%d", bytes[0], bytes[1], bytes[2], bytes[3]); +#elif defined(ACL_MS_WINDOWS) + snprintf (dst, 18, "%d.%d.%d.%d", bytes[3], bytes[2], bytes[1], bytes[0]); +#else + snprintf (dst, 18, "%d.%d.%d.%d", bytes[0], bytes[1], bytes[2], bytes[3]); +#endif + + return(dst); +} + +int acl_iplink_list(const ACL_IPLINK *plink) +{ + int i, n; + ACL_IPITEM *item; + char buf[64]; + unsigned ip_begin, ip_end; + + n = acl_array_size(plink->parray); + for (i = 0; i < n; i++) { + item = (ACL_IPITEM *) acl_array_index(plink->parray, i); + if (item == NULL) + break; + ip_begin = (unsigned) item->begin; + ip_end = (unsigned) item->end; + __sane_inet_ntoa(ip_begin, buf, sizeof(buf)); + printf("ipbegin=%s", buf); + __sane_inet_ntoa(ip_end, buf, sizeof(buf)); + printf(", ipend=%s\n", buf); + } + + return n; +} diff --git a/lib_acl/src/stdlib/common/acl_ring.c b/lib_acl/src/stdlib/common/acl_ring.c new file mode 100644 index 000000000..ad12140c1 --- /dev/null +++ b/lib_acl/src/stdlib/common/acl_ring.c @@ -0,0 +1,120 @@ +/* Application-specific. */ + +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_ring.h" + +#endif + +/* acl_ring_init - initialize ring head */ +void acl_ring_init(ACL_RING *ring) +{ + if (ring == NULL) + return; + ring->pred = ring->succ = ring; + ring->parent = ring; + ring->len = 0; +} + +/* acl_ring_size - the entry number in the ring */ + +int acl_ring_size(const ACL_RING *ring) +{ + if (ring == NULL) + return (-1); + + return (ring->len); +} + +/* acl_ring_append - insert entry after ring head */ + +void acl_ring_append(ACL_RING *ring, ACL_RING *entry) +{ + if (ring == NULL || entry == NULL) + return; + entry->succ = ring->succ; + entry->pred = ring; + entry->parent = ring->parent; + ring->succ->pred = entry; + ring->succ = entry; + ring->parent->len++; +} + +/* acl_ring_prepend - insert new entry before ring head */ + +void acl_ring_prepend(ACL_RING *ring, ACL_RING *entry) +{ + if (ring == NULL || entry == NULL) + return; + entry->pred = ring->pred; + entry->succ = ring; + entry->parent = ring->parent; + ring->pred->succ = entry; + ring->pred = entry; + ring->parent->len++; +} + +/* acl_ring_detach - remove entry from ring */ + +void acl_ring_detach(ACL_RING *entry) +{ + ACL_RING *succ; + ACL_RING *pred; + + if (entry == NULL) + return; + succ = entry->succ; + pred = entry->pred; + if (succ == NULL || pred == NULL) + return; + pred->succ = succ; + succ->pred = pred; + + entry->parent->len--; + + entry->succ = entry->pred = entry; + entry->parent = entry; + entry->len = 0; +} + +/* acl_ring_pop_head - pop ring's head entry out from ring */ + +ACL_RING *acl_ring_pop_head(ACL_RING *ring) +{ + ACL_RING *succ; + + if (ring == NULL) + return (NULL); + + succ = ring->succ; + if (succ == ring) + return (NULL); + + acl_ring_detach(succ); + + return (succ); +} + +/* acl_ring_pop_tail - pop ring's tail entry out from ring */ + +ACL_RING *acl_ring_pop_tail(ACL_RING *ring) +{ + ACL_RING *pred; + + if (ring == NULL) + return (NULL); + + pred = ring->pred; + if (pred == ring) + return (NULL); + + acl_ring_detach(pred); + + return (pred); +} diff --git a/lib_acl/src/stdlib/common/acl_stack.c b/lib_acl/src/stdlib/common/acl_stack.c new file mode 100644 index 000000000..44003d9d4 --- /dev/null +++ b/lib_acl/src/stdlib/common/acl_stack.c @@ -0,0 +1,306 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_msg.h" +#include "stdlib/acl_malloc.h" +#include "stdlib/acl_stack.h" + +#endif + +static void stack_push_back(struct ACL_STACK *s, void *obj) +{ + acl_stack_append(s, obj); +} + +static void stack_push_front(struct ACL_STACK *s, void *obj) +{ + acl_stack_prepend(s, obj); +} + +static void *stack_pop_back(struct ACL_STACK *s) +{ + return (acl_stack_pop(s)); +} + +static void *stack_pop_front(struct ACL_STACK *s) +{ + int i; + void *obj; + + if (s->count < 1) + return (NULL); + + obj = s->items[0]; + s->count--; + for (i = 0; i < s->count; i++) { + s->items[i] = s->items[i + 1]; + } + return (obj); +} + +/* stack_iter_head - get the head of the stack */ + +static void *stack_iter_head(ACL_ITER *iter, struct ACL_STACK *s) +{ + iter->dlen = -1; + iter->key = NULL; + iter->klen = -1; + iter->i = 0; + iter->size = s->count;; + if (s->items == NULL || s->count <= 0) + iter->ptr = NULL; + else + iter->ptr = s->items[0]; + + iter->data = iter->ptr; + return (iter->ptr); +} + +/* stack_iter_next - get the next of the stack */ + +static void *stack_iter_next(ACL_ITER *iter, struct ACL_STACK *s) +{ + iter->i++; + if (iter->i >= s->count) + iter->data = iter->ptr = 0; + else + iter->data = iter->ptr = s->items[iter->i]; + return (iter->ptr); +} + +/* stack_iter_tail - get the tail of the stack */ + +static void *stack_iter_tail(ACL_ITER *iter, struct ACL_STACK *s) +{ + iter->dlen = -1; + iter->key = NULL; + iter->klen = -1; + iter->i = s->count - 1; + iter->size = s->count; + if (s->items == NULL || iter->i < 0) + iter->data = iter->ptr = 0; + else + iter->data = iter->ptr = s->items[iter->i]; + return (iter->ptr); +} + +/* stack_iter_prev - get the prev of the stack */ + +static void *stack_iter_prev(ACL_ITER *iter, struct ACL_STACK *s) +{ + iter->i--; + if (iter->i < 0) + iter->data = iter->ptr = 0; + else + iter->data = iter->ptr = s->items[iter->i]; + return (iter->ptr); +} + +/* grows internal buffer to satisfy required minimal capacity */ + +static void stack_grow(ACL_STACK *s, int min_capacity) +{ + const char *myname = "stack_grow"; + const char *ptr; + int min_delta = 16; + int delta; + + /* don't need to grow the capacity of the array */ + if (s->capacity >= min_capacity) + return; + delta = min_capacity; + /* make delta a multiple of min_delta */ + delta += min_delta - 1; + delta /= min_delta; + delta *= min_delta; + /* actual grow */ + if (delta <= 0) + return; + s->capacity += delta; + if (s->items) { + s->items = (void **) acl_default_realloc(__FILE__, __LINE__, + s->items, s->capacity * sizeof(void *)); + ptr = "realloc"; + } else { + s->items = (void **) acl_default_malloc(__FILE__, __LINE__, + s->capacity * sizeof(void *)); + ptr = "malloc"; + } + + if (s->items == NULL) { + char ebuf[256]; + acl_msg_fatal("%s(%d): %s error(%s)", + myname, __LINE__, ptr, + acl_last_strerror(ebuf, sizeof(ebuf))); + } + + /* reset, just in case */ + memset(s->items + s->count, 0, (s->capacity - s->count) * sizeof(void *)); +} + +/* if you are going to append a known and large number of items, call this first */ + +void acl_stack_space(ACL_STACK *s, int count) +{ + if (s->count + count > s->capacity) + stack_grow(s, s->count + count); +} + +ACL_STACK *acl_stack_create(int init_size) +{ + const char *myname = "acl_stack_create"; + ACL_STACK *s; + + init_size = init_size > 0 ? init_size : 1; + + s = (ACL_STACK *) acl_default_calloc(__FILE__, __LINE__, 1, sizeof(ACL_STACK)); + if (s == NULL) { + char ebuf[256]; + acl_msg_fatal("%s(%d): can't calloc, error=%s", + myname, __LINE__, acl_last_strerror(ebuf, sizeof(ebuf))); + } + + acl_stack_space(s, init_size); + + s->push_back = stack_push_back; + s->push_front = stack_push_front; + s->pop_back = stack_pop_back; + s->pop_front = stack_pop_front; + s->iter_head = stack_iter_head; + s->iter_next = stack_iter_next; + s->iter_tail = stack_iter_tail; + s->iter_prev = stack_iter_prev; + + return (s); +} + +void acl_stack_clean(ACL_STACK *s, void (*free_fn)(void *)) +{ + int i; + + for (i = 0; i < s->count; i++) { + if (free_fn != NULL && s->items[i] != NULL) + free_fn(s->items[i]); + s->items[i] = NULL; /* sanity set to be null */ + } + + acl_default_free(__FILE__, __LINE__, s->items); + s->items = NULL; + s->count = 0; +} + +void acl_stack_destroy(ACL_STACK *s, void (*free_fn)(void *)) +{ + acl_stack_clean(s, free_fn); + memset(s, 0, sizeof(ACL_STACK)); + acl_default_free(__FILE__, __LINE__, s); +} + +void acl_stack_append(ACL_STACK *s, void *obj) +{ + if (s == NULL || obj == NULL) + return; + if (s->count >= s->capacity) + stack_grow(s, s->count + 16); + s->items[s->count++] = obj; +} + +void acl_stack_prepend(ACL_STACK *s, void *obj) +{ + int i; + + if (s == NULL || obj == NULL) + return; + if (s->count >= s->capacity) + stack_grow(s, s->count + 1); + + for (i = s->count; i > 0; i--) + s->items[i] = s->items[i - 1]; + s->items[0] = obj; + s->count++; +} + +void acl_stack_delete(ACL_STACK *s, int position, void (*free_fn)(void *)) +{ + int i; + + if (s == NULL || position < 0 || position >= s->count) + return; + if (free_fn != NULL && s->items[position] != NULL) + free_fn(s->items[position]); + s->items[position] = NULL; /* sanity set to be null */ + + for (i = position; i < s->count - 1; i++) + s->items[i] = s->items[i + 1]; + s->count--; +} + +void acl_stack_delete_obj(ACL_STACK *s, void *obj, void (*free_fn)(void *)) +{ + int i, position; + + if (s == NULL || obj == NULL) + return; + position = -1; + for (i = 0; i < s->count; i++) { + if (s->items[i] == obj) { + position = i; + break; + } + } + + if (position == -1) /* not found */ + return; + if (free_fn != NULL && obj != NULL) + free_fn(obj); + + /* don't need to free the obj in acl_stack_delete */ + s->items[i] = NULL; + acl_stack_delete(s, position, NULL); +} + +void *acl_stack_index(ACL_STACK *s, int idx) +{ + if (s == NULL || idx < 0 || idx > s->count - 1) + return (NULL); + + return (s->items[idx]); +} + +int acl_stack_size(const ACL_STACK *s) +{ + if (s == NULL) + return (-1); + return (s->count); +} + +void *acl_stack_pop(ACL_STACK *s) +{ + if (s == NULL) + return (NULL); + + if (s->count < 1) + return (NULL); + + return (s->items[--s->count]); +} + +void *acl_stack_top(ACL_STACK *s) +{ + if (s == NULL) + return (NULL); + + if (s->count < 1) + return (NULL); + + return (s->items[s->count - 1]); +} diff --git a/lib_acl/src/stdlib/common/acl_token_tree.c b/lib_acl/src/stdlib/common/acl_token_tree.c new file mode 100644 index 000000000..d2ebeb844 --- /dev/null +++ b/lib_acl/src/stdlib/common/acl_token_tree.c @@ -0,0 +1,649 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_vstring.h" +#include "stdlib/acl_msg.h" +#include "stdlib/acl_argv.h" +#include "stdlib/acl_iterator.h" +#include "stdlib/acl_file.h" +#include "thread/acl_thread.h" +#include "stdlib/acl_token_tree.h" + +#endif + +#ifndef STR +#define STR acl_vstring_str +#endif + +#ifndef LEN +#define LEN ACL_VSTRING_LEN +#endif + +char *acl_token_delim_tab_new(const char *delim) +{ + char *delim_tab = (char*) acl_mycalloc(255, sizeof(char)); + const unsigned char *ptr = (const unsigned char*) delim; + + while (*ptr) { + delim_tab[*ptr] = 'd'; + ptr++; + } + + return (delim_tab); +} + +void acl_token_delim_tab_free(char *delim_tab) +{ + acl_myfree(delim_tab); +} + +ACL_TOKEN *acl_token_new() +{ + ACL_TOKEN *token = (ACL_TOKEN*) acl_mycalloc(1, sizeof(ACL_TOKEN)); + int i; + + for (i = 0; i < ACL_TOKEN_WIDTH; i++) { + token->tokens[i] = NULL; + } + token->ch = '-'; + return (token); +} + +void acl_token_free(ACL_TOKEN *token) +{ + acl_myfree(token); +} + +void acl_token_name(const ACL_TOKEN *token, ACL_VSTRING *buf) +{ + int i, n; + char *ptr, *pend, ch; + const ACL_TOKEN *token_iter; + + ACL_VSTRING_RESET(buf); + token_iter = token; + while (token_iter && token_iter->parent != NULL) { + ACL_VSTRING_ADDCH(buf, token_iter->ch); + token_iter = token_iter->parent; + } + + ACL_VSTRING_TERMINATE(buf); + + pend = acl_vstring_end(buf) - 1; + ptr = STR(buf); + i = 0; + n = (pend - ptr + 1) / 2; + while (i < n) { + ch = *ptr; + *ptr = *pend; + *pend = ch; + i++; + ptr++; + pend--; + } +} + +const char *acl_token_name1(const ACL_TOKEN *token) +{ + static acl_pthread_key_t buf_key = ACL_TLS_OUT_OF_INDEXES; + ACL_VSTRING *buf; + static ACL_VSTRING *__buf_unsafe = NULL; + + buf = (ACL_VSTRING*) acl_pthread_tls_get(&buf_key); + if (buf == NULL) { + if (buf_key == (acl_pthread_key_t) ACL_TLS_OUT_OF_INDEXES) { + if (__buf_unsafe == NULL) + __buf_unsafe = acl_vstring_alloc(256); + buf = __buf_unsafe; + } else { + buf = acl_vstring_alloc(256); + acl_pthread_tls_set(buf_key, buf, + (void (*)(void*)) acl_vstring_free); + } + } + ACL_VSTRING_RESET(buf); + acl_token_name(token, buf); + return (STR(buf)); +} + +ACL_TOKEN *acl_token_tree_add(ACL_TOKEN *token_tree, const char *word, + unsigned int flag, const void *ctx) +{ + const char *myname= "acl_token_tree_add"; + const unsigned char *ptr = (const unsigned char*) word; + ACL_TOKEN *token_iter = token_tree, *token = NULL; + + if ((flag & ACL_TOKEN_F_PASS) && (flag & ACL_TOKEN_F_DENY)) { + acl_msg_error("%s(%d): word(%s)'s flag(%u) is" + " ACL_TOKEN_F_DENY | ACL_TOKEN_F_PASS", + myname, __LINE__, word, flag); + return (NULL); + } + + while (*ptr) { + token = token_iter->tokens[*ptr]; + if (token == NULL) { + token = acl_token_new(); + token->ch = *ptr; + token_iter->tokens[*ptr] = token; + token->parent = token_iter; + ptr++; + token_iter = token; + } else if (token->ch != *ptr) { + acl_msg_fatal("%s(%d): token->ch(%d) != %d", + myname, __LINE__, token->tokens[*ptr]->ch, *ptr); + } else { + ptr++; + token_iter = token; + } + } + + if (token) { + token->flag = flag; + token->ctx = ctx; + } + return (token); +} + +ACL_TOKEN *acl_token_tree_add_word_map(ACL_TOKEN *token_tree, + const char *word, const char *word_map, unsigned int flag) +{ + const char *myname = "acl_token_tree_add_word_map"; + const unsigned char *ptr = (const unsigned char*) word; + const unsigned char *ptr_map = (const unsigned char*) word_map; + ACL_TOKEN *token_iter = token_tree, *token = NULL; + + if ((flag & ACL_TOKEN_F_PASS) && (flag & ACL_TOKEN_F_DENY)) { + acl_msg_error("%s(%d): word(%s)'s flag(%u) is " + "ACL_TOKEN_F_DENY | ACL_TOKEN_F_PASS", + myname, __LINE__, word, flag); + return (NULL); + } + + while (*ptr) { + token = token_iter->tokens[*ptr]; + if (token == NULL) { + token = acl_token_new(); + token->ch = *ptr_map; + token_iter->tokens[*ptr] = token; + token->parent = token_iter; + ptr++; + ptr_map++; + token_iter = token; + } else if (token->ch != *ptr_map) { + acl_msg_fatal("%s(%d): token->ch(%d) != %d", + myname, __LINE__, token->tokens[*ptr]->ch, *ptr_map); + } else { + ptr++; + ptr_map++; + token_iter = token; + } + } + + if (token) + token->flag = flag; + return (token); +} + +const ACL_TOKEN *acl_token_tree_word_match(const ACL_TOKEN *token_tree, const char *word) +{ + const unsigned char *ptr = (const unsigned char*) word; + const ACL_TOKEN *token_iter = token_tree, *token = NULL; + + while (*ptr) { + token = token_iter->tokens[*ptr]; + if (token == NULL) + return (NULL); + token_iter = token; + ptr++; + } + + if (token && (token->flag & ACL_TOKEN_F_STOP)) + return (token); + else + return (NULL); +} + +const ACL_TOKEN *acl_token_tree_match(const ACL_TOKEN *token_tree, + const char **ptr, const char *delim, const char *delim_tab) +{ + const ACL_TOKEN *token_iter = token_tree, *token, *token_last = NULL; + int i, n = 0, is_word; + + if (delim) { + while (**ptr) { + is_word = *((const unsigned char*) *ptr) > 128 ? 1: 0; + n++; + for (i = 0; delim[i]; i++) { + if (**ptr == delim[i]) + goto END; + } + token = token_iter->tokens[*((const unsigned char*) *ptr)]; + if (token == NULL) { + if (token_last) + break; + token_iter = token_tree; + token = token_iter->tokens[*((const unsigned char*) *ptr)]; + if (token == NULL) { + (*ptr)++; + if (**ptr == 0) + break; + if (is_word) + (*ptr)++; + } + } + if (token == NULL) + continue; + else if (is_word == 0) { + if ((token->flag & ACL_TOKEN_F_STOP)) + token_last = token; + token_iter = token; + (*ptr)++; + continue; + } + + token_iter = token; + (*ptr)++; + if (**ptr == 0) + break; + token = token_iter->tokens[*((const unsigned char*) *ptr)]; + if (token == NULL) { + if (token_last) + break; + token_iter = token_tree; + } else if ((token->flag & ACL_TOKEN_F_STOP)) { + token_last = token; + token_iter = token; + } else + token_iter = token; + (*ptr)++; + } + } else if (delim_tab) { + while (**ptr) { + is_word = *((const unsigned char*) *ptr) > 128 ? 1: 0; + n++; + if (delim_tab[*((const unsigned char*) *ptr)]) + goto END; + token = token_iter->tokens[*((const unsigned char*) *ptr)]; + if (token == NULL) { + if (token_last) + break; + token_iter = token_tree; + token = token_iter->tokens[*((const unsigned char*) *ptr)]; + if (token == NULL) { + (*ptr)++; + if (**ptr == 0) + break; + if (is_word) + (*ptr)++; + } + } + if (token == NULL) + continue; + else if (is_word == 0) { + if ((token->flag & ACL_TOKEN_F_STOP)) + token_last = token; + token_iter = token; + (*ptr)++; + continue; + } + + token_iter = token; + (*ptr)++; + if (**ptr == 0) + break; + token = token_iter->tokens[*((const unsigned char*) *ptr)]; + if (token == NULL) { + if (token_last) + break; + token_iter = token_tree; + } else if ((token->flag & ACL_TOKEN_F_STOP)) { + token_last = token; + token_iter = token; + } else + token_iter = token; + (*ptr)++; + } + } else { + while (**ptr) { + is_word = *((const unsigned char*) *ptr) > 128 ? 1: 0; + n++; + token = token_iter->tokens[*((const unsigned char*) *ptr)]; + if (token == NULL) { + if (token_last) + break; + token_iter = token_tree; + token = token_iter->tokens[*((const unsigned char*) *ptr)]; + if (token == NULL) { + (*ptr)++; + if (**ptr == 0) + break; + if (is_word) + (*ptr)++; + } + } + if (token == NULL) + continue; + else if (is_word == 0) { + if ((token->flag & ACL_TOKEN_F_STOP)) + token_last = token; + token_iter = token; + (*ptr)++; + continue; + } + + token_iter = token; + (*ptr)++; + if (**ptr == 0) + break; + token = token_iter->tokens[*((const unsigned char*) *ptr)]; + if (token == NULL) { + if (token_last) + break; + token_iter = token_tree; + } else if ((token->flag & ACL_TOKEN_F_STOP)) { + token_last = token; + token_iter = token; + } else + token_iter = token; + (*ptr)++; + } + } + +END: + return (token_last); +} + +void acl_token_tree_walk(const ACL_TOKEN *token_tree, + void (*walk_fn)(const ACL_TOKEN*, void*), void *arg) +{ + int i; + + if ((token_tree->flag & ACL_TOKEN_F_STOP)) + walk_fn(token_tree, arg); + + for (i = 0; i < ACL_TOKEN_WIDTH; i++) { + if (token_tree->tokens[i]) { + acl_token_tree_walk(token_tree->tokens[i], walk_fn, arg); + } + } +} + +static void acl_token_name_walk(const ACL_TOKEN *token, void *arg) +{ + ACL_VSTRING *buf = (ACL_VSTRING*) arg; + ACL_VSTRING *name = acl_vstring_alloc(256); + + acl_token_name(token, name); + if (LEN(buf) > 0) + ACL_VSTRING_ADDCH(buf, ';'); + acl_vstring_strcat(buf, STR(name)); + acl_vstring_free(name); +} + +void acl_token_tree_print(const ACL_TOKEN *token_tree) +{ + int i; + ACL_VSTRING *buf = acl_vstring_alloc(1024); + + for (i = 0; i < ACL_TOKEN_WIDTH; i++) { + if (token_tree->tokens[i]) { + acl_token_tree_walk(token_tree->tokens[i], acl_token_name_walk, buf); + } + } + + printf(">>>all token: (%s)\n", STR(buf)); + acl_vstring_free(buf); +} + +ACL_TOKEN *acl_token_tree_create(const char *s) +{ + return (acl_token_tree_create2(s, ";, \t")); +} + +ACL_TOKEN *acl_token_tree_create2(const char *s, const char *sep) +{ + const char *myname = "acl_token_tree_create"; + ACL_ARGV *argv; + ACL_ITER iter; + unsigned int flag; + ACL_TOKEN *token_tree; + const ACL_TOKEN *token; + ACL_VSTRING *buf; + + token_tree = acl_token_new(); + if (s == NULL || *s == 0) + return (token_tree); + + buf = acl_vstring_alloc(256); + argv = acl_argv_split(s, sep); + acl_foreach(iter, argv) { + char *word = (char*) iter.ptr; + char *ptr = strchr(word, '|'); + + flag = ACL_TOKEN_F_STOP; + if (ptr) { + *ptr++ = 0; + if (*ptr == 'D' || *ptr == 'd') + flag |= ACL_TOKEN_F_DENY; + if (*ptr == 'P' || *ptr == 'p') + flag |= ACL_TOKEN_F_PASS; + } + token = acl_token_tree_add(token_tree, word, flag, NULL); + if (token == NULL) { + acl_msg_info("%s(%d): word(%s) discard", + myname, __LINE__, word); + } else { + ACL_VSTRING_RESET(buf); + acl_token_name(token, buf); + /* + acl_msg_info("%s(%d): add word(%s) ok, token's name(%s)", + myname, __LINE__, word, STR(buf)); + */ + } + } + + acl_argv_free(argv); + acl_vstring_free(buf); + return (token_tree); +} + +void acl_token_tree_destroy(ACL_TOKEN *token_tree) +{ + int i; + /* + ACL_VSTRING *buf = acl_vstring_alloc(256); + */ + + for (i = 0; i < ACL_TOKEN_WIDTH; i++) { + if (token_tree->tokens[i]) + acl_token_tree_destroy(token_tree->tokens[i]); + } + + /* + acl_token_name(token_tree, buf); + if ((token_tree->flag & ACL_TOKEN_F_STOP)) + acl_msg_info("free token: %s", STR(buf)); + else + printf("free token; "); + acl_vstring_free(buf); + */ + acl_token_free(token_tree); +} + +void acl_token_tree_load_deny(const char *filepath, ACL_TOKEN *token_tree) +{ + const char *myname = "acl_token_tree_load_deny"; + ACL_FILE *fp; + int flag; + char buf[1024], *ptr; + + if (!filepath || !*filepath) + return; + fp = acl_fopen(filepath, "r"); + if (fp == NULL) { + acl_msg_warn("%s(%d): %s open error(%s)", + myname, __LINE__, filepath, acl_last_serror()); + return; + } + + while (1) { + ptr = acl_fgets_nonl(buf, sizeof(buf), fp); + if (ptr == NULL) + break; + ptr = strchr(buf, '|'); + if (ptr) { + *ptr++ = 0; + flag = ACL_TOKEN_F_STOP; + if (*ptr == 'd' || *ptr == 'D') + flag |= ACL_TOKEN_F_DENY; + if (*ptr == 'p' || *ptr == 'P') + flag |= ACL_TOKEN_F_PASS; + } else + flag = ACL_TOKEN_F_STOP | ACL_TOKEN_F_DENY; + acl_token_tree_add(token_tree, buf, flag, NULL); + } + + acl_fclose(fp); +} + +void acl_token_tree_load_pass(const char *filepath, ACL_TOKEN *token_tree) +{ + const char *myname = "acl_token_tree_load_pass"; + ACL_FILE *fp; + int flag; + char buf[1024], *ptr; + + if (!filepath || !*filepath) + return; + fp = acl_fopen(filepath, "r"); + if (fp == NULL) { + acl_msg_warn("%s(%d): %s open error(%s)", + myname, __LINE__, filepath, acl_last_serror()); + return; + } + + while (1) { + ptr = acl_fgets_nonl(buf, sizeof(buf), fp); + if (ptr == NULL) + break; + ptr = strchr(buf, ':'); + if (ptr) { + *ptr++ = 0; + flag = ACL_TOKEN_F_STOP; + if (*ptr == 'd' || *ptr == 'D') + flag |= ACL_TOKEN_F_DENY; + if (*ptr == 'p' || *ptr == 'P') + flag |= ACL_TOKEN_F_PASS; + } else + flag = ACL_TOKEN_F_STOP | ACL_TOKEN_F_PASS; + acl_token_tree_add(token_tree, buf, flag, NULL); + } + + acl_fclose(fp); +} + +static void token_word_test(const char *tokens, const char *test_tab[]) +{ + ACL_TOKEN *token_tree; + const char *ptr; + int i; + + token_tree = acl_token_tree_create(tokens); + acl_token_tree_print(token_tree); + + for (i = 0; test_tab[i] != NULL; i++) { + ptr = test_tab[i]; + printf("match %s %s\n", ptr, + acl_token_tree_word_match(token_tree, ptr) ? "yes" : "no"); + } + acl_token_tree_destroy(token_tree); +} + +static void token_tree_test(const char *tokens, const char *test_tab[]) +{ + ACL_TOKEN *token_tree; + const ACL_TOKEN *token; + const char *ptr, *psaved; + ACL_VSTRING *buf = acl_vstring_alloc(256); + int i; + + token_tree = acl_token_tree_create(tokens); + acl_token_tree_print(token_tree); + + for (i = 0; test_tab[i] != NULL; i++) { + ptr = psaved = test_tab[i]; + token = acl_token_tree_match(token_tree, &ptr, ";", NULL); + if (token) { + ACL_VSTRING_RESET(buf); + acl_token_name(token, buf); + printf("match %s %s, token's name: %s\n", psaved, + (token->flag & ACL_TOKEN_F_DENY) ? "DENY" + : (token->flag & ACL_TOKEN_F_PASS ? "PASS" : "NONE"), + STR(buf)); + } else + printf("match %s none\n", psaved); + } + + acl_token_tree_destroy(token_tree); + acl_vstring_free(buf); +} + +void acl_token_tree_test(void) +{ + const char *tokens1 = "hello world he is a man he" + " 中 中华 中华人 中华人民 中华人民共 中华人民共和 中华人民共和国" + " 中华人民共和国万岁 中华人民共和国万岁万万岁" + " 法轮功|d 研究法轮功|d 反对法轮功|p 法轮功协会|d 口交|d 二十四口交换机|p"; + const char *tokens2 = "法轮功|d 研究法轮功|d 比利时|d 中国|p 说的|d"; + + static const char *test1_tab[] = { + "中华", + "中华人", + "中华人民", + "中华人民共", + "中华人民共和", + "中华人民共和国", + "中华人民共和国万岁", + "我们中华人民共和国万岁", + "我们中华人民共和国万岁万万岁", + "法轮功", + "反对法轮功", + "法轮功协会", + "反对法轮功协会", + "研究法轮功", + "我爱法轮功", + "我爱研法轮功", + "口交", + "男女口交", + "二十四口交换机", + NULL + }; + + static const char *test2_tab[] = { + "hello", + "shello", + "中华人民共和国", + "中华人民", + NULL + }; + + static const char *test3_tab[] = { + "我爱研法轮功", + "中国", + "比利时", + "中国比利时", + "我说的故事", + "宜档闹泄", + NULL + }; + + token_tree_test(tokens1, test1_tab); + token_word_test(tokens1, test2_tab); + token_tree_test(tokens2, test3_tab); +} diff --git a/lib_acl/src/stdlib/common/avl.c b/lib_acl/src/stdlib/common/avl.c new file mode 100644 index 000000000..5f16c4906 --- /dev/null +++ b/lib_acl/src/stdlib/common/avl.c @@ -0,0 +1,1042 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + + +/* + * AVL - generic AVL tree implementation for kernel use + * + * A complete description of AVL trees can be found in many CS textbooks. + * + * Here is a very brief overview. An AVL tree is a binary search tree that is + * almost perfectly balanced. By "almost" perfectly balanced, we mean that at + * any given node, the left and right subtrees are allowed to differ in height + * by at most 1 level. + * + * This relaxation from a perfectly balanced binary tree allows doing + * insertion and deletion relatively efficiently. Searching the tree is + * still a fast operation, roughly O(log(N)). + * + * The key to insertion and deletion is a set of tree maniuplations called + * rotations, which bring unbalanced subtrees back into the semi-balanced state. + * + * This implementation of AVL trees has the following peculiarities: + * + * - The AVL specific data structures are physically embedded as fields + * in the "using" data structures. To maintain generality the code + * must constantly translate between "avl_node_t *" and containing + * data structure "void *"s by adding/subracting the avl_offset. + * + * - Since the AVL data is always embedded in other structures, there is + * no locking or memory allocation in the AVL routines. This must be + * provided for by the enclosing data structure's semantics. Typically, + * avl_insert()/_add()/_remove()/avl_insert_here() require some kind of + * exclusive write lock. Other operations require a read lock. + * + * - The implementation uses iteration instead of explicit recursion, + * since it is intended to run on limited size kernel stacks. Since + * there is no recursion stack present to move "up" in the tree, + * there is an explicit "parent" link in the avl_node_t. + * + * - The left/right children pointers of a node are in an array. + * In the code, variables (instead of constants) are used to represent + * left and right indices. The implementation is written as if it only + * dealt with left handed manipulations. By changing the value assigned + * to "left", the code also works for right handed trees. The + * following variables/terms are frequently used: + * + * int left; // 0 when dealing with left children, + * // 1 for dealing with right children + * + * int left_heavy; // -1 when left subtree is taller at some node, + * // +1 when right subtree is taller + * + * int right; // will be the opposite of left (0 or 1) + * int right_heavy;// will be the opposite of left_heavy (-1 or 1) + * + * int direction; // 0 for "<" (ie. left child); 1 for ">" (right) + * + * Though it is a little more confusing to read the code, the approach + * allows using half as much code (and hence cache footprint) for tree + * manipulations and eliminates many conditional branches. + * + * - The avl_index_t is an opaque "cookie" used to find nodes at or + * adjacent to where a new value would be inserted in the tree. The value + * is a modified "avl_node_t *". The bottom bit (normally 0 for a + * pointer) is set to indicate if that the new node has a value greater + * than the value of the indicated "avl_node_t *". + */ + +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +/* +#include +#include +#include +#include +*/ +#include "stdlib/avl.h" + +#endif + +#define ASSERT acl_assert + +/* + * Small arrays to translate between balance (or diff) values and child indeces. + * + * Code that deals with binary tree data structures will randomly use + * left and right children when examining a tree. C "if()" statements + * which evaluate randomly suffer from very poor hardware branch prediction. + * In this code we avoid some of the branch mispredictions by using the + * following translation arrays. They replace random branches with an + * additional memory reference. Since the translation arrays are both very + * small the data should remain efficiently in cache. + */ +static const int avl_child2balance[2] = {-1, 1}; +static const int avl_balance2child[] = {0, 0, 1}; + + +/* + * Walk from one node to the previous valued node (ie. an infix walk + * towards the left). At any given node we do one of 2 things: + * + * - If there is a left child, go to it, then to it's rightmost descendant. + * + * - otherwise we return thru parent nodes until we've come from a right child. + * + * Return Value: + * NULL - if at the end of the nodes + * otherwise next node + */ +void * +avl_walk(avl_tree_t *tree, void *oldnode, int left) +{ + size_t off = tree->avl_offset; + avl_node_t *node = AVL_DATA2NODE(oldnode, off); + int right = 1 - left; + int was_child; + + + /* + * nowhere to walk to if tree is empty + */ + if (node == NULL) + return (NULL); + + /* + * Visit the previous valued node. There are two possibilities: + * + * If this node has a left child, go down one left, then all + * the way right. + */ + if (node->avl_child[left] != NULL) { + for (node = node->avl_child[left]; + node->avl_child[right] != NULL; + node = node->avl_child[right]) + ; + /* + * Otherwise, return thru left children as far as we can. + */ + } else { + for (;;) { + was_child = AVL_XCHILD(node); + node = AVL_XPARENT(node); + if (node == NULL) + return (NULL); + if (was_child == right) + break; + } + } + + return (AVL_NODE2DATA(node, off)); +} + +/* + * Return the lowest valued node in a tree or NULL. + * (leftmost child from root of tree) + */ +void * +avl_first(avl_tree_t *tree) +{ + avl_node_t *node; + avl_node_t *prev = NULL; + size_t off = tree->avl_offset; + + for (node = tree->avl_root; node != NULL; node = node->avl_child[0]) + prev = node; + + if (prev != NULL) + return (AVL_NODE2DATA(prev, off)); + return (NULL); +} + +/* + * Return the highest valued node in a tree or NULL. + * (rightmost child from root of tree) + */ +void * +avl_last(avl_tree_t *tree) +{ + avl_node_t *node; + avl_node_t *prev = NULL; + size_t off = tree->avl_offset; + + for (node = tree->avl_root; node != NULL; node = node->avl_child[1]) + prev = node; + + if (prev != NULL) + return (AVL_NODE2DATA(prev, off)); + return (NULL); +} + +/* + * Access the node immediately before or after an insertion point. + * + * "avl_index_t" is a (avl_node_t *) with the bottom bit indicating a child + * + * Return value: + * NULL: no node in the given direction + * "void *" of the found tree node + */ +void * +avl_nearest(avl_tree_t *tree, avl_index_t where, int direction) +{ + int child = AVL_INDEX2CHILD(where); + avl_node_t *node = AVL_INDEX2NODE(where); + void *data; + size_t off = tree->avl_offset; + + if (node == NULL) { + ASSERT(tree->avl_root == NULL); + return (NULL); + } + data = AVL_NODE2DATA(node, off); + if (child != direction) + return (data); + + return (avl_walk(tree, data, direction)); +} + + +/* + * Search for the node which contains "value". The algorithm is a + * simple binary tree search. + * + * return value: + * NULL: the value is not in the AVL tree + * *where (if not NULL) is set to indicate the insertion point + * "void *" of the found tree node + */ +void * +avl_find(avl_tree_t *tree, void *value, avl_index_t *where) +{ + avl_node_t *node; + avl_node_t *prev = NULL; + int child = 0; + int diff; + size_t off = tree->avl_offset; + + for (node = tree->avl_root; node != NULL; + node = node->avl_child[child]) { + + prev = node; + + diff = tree->avl_compar(value, AVL_NODE2DATA(node, off)); + ASSERT(-1 <= diff && diff <= 1); + if (diff == 0) { +#ifdef DEBUG + if (where != NULL) + *where = 0; +#endif + return (AVL_NODE2DATA(node, off)); + } + child = avl_balance2child[1 + diff]; + + } + + if (where != NULL) + *where = AVL_MKINDEX(prev, child); + + return (NULL); +} + + +/* + * Perform a rotation to restore balance at the subtree given by depth. + * + * This routine is used by both insertion and deletion. The return value + * indicates: + * 0 : subtree did not change height + * !0 : subtree was reduced in height + * + * The code is written as if handling left rotations, right rotations are + * symmetric and handled by swapping values of variables right/left[_heavy] + * + * On input balance is the "new" balance at "node". This value is either + * -2 or +2. + */ +static int +avl_rotation(avl_tree_t *tree, avl_node_t *node, int balance) +{ + int left = !(balance < 0); /* when balance = -2, left will be 0 */ + int right = 1 - left; + int left_heavy = balance >> 1; + int right_heavy = -left_heavy; + avl_node_t *parent = AVL_XPARENT(node); + avl_node_t *child = node->avl_child[left]; + avl_node_t *cright; + avl_node_t *gchild; + avl_node_t *gright; + avl_node_t *gleft; + int which_child = AVL_XCHILD(node); + int child_bal = AVL_XBALANCE(child); + + /* BEGIN CSTYLED */ + /* + * case 1 : node is overly left heavy, the left child is balanced or + * also left heavy. This requires the following rotation. + * + * (node bal:-2) + * / \ + * / \ + * (child bal:0 or -1) + * / \ + * / \ + * cright + * + * becomes: + * + * (child bal:1 or 0) + * / \ + * / \ + * (node bal:-1 or 0) + * / \ + * / \ + * cright + * + * we detect this situation by noting that child's balance is not + * right_heavy. + */ + /* END CSTYLED */ + if (child_bal != right_heavy) { + + /* + * compute new balance of nodes + * + * If child used to be left heavy (now balanced) we reduced + * the height of this sub-tree -- used in "return...;" below + */ + child_bal += right_heavy; /* adjust towards right */ + + /* + * move "cright" to be node's left child + */ + cright = child->avl_child[right]; + node->avl_child[left] = cright; + if (cright != NULL) { + AVL_SETPARENT(cright, node); + AVL_SETCHILD(cright, left); + } + + /* + * move node to be child's right child + */ + child->avl_child[right] = node; + AVL_SETBALANCE(node, -child_bal); + AVL_SETCHILD(node, right); + AVL_SETPARENT(node, child); + + /* + * update the pointer into this subtree + */ + AVL_SETBALANCE(child, child_bal); + AVL_SETCHILD(child, which_child); + AVL_SETPARENT(child, parent); + if (parent != NULL) + parent->avl_child[which_child] = child; + else + tree->avl_root = child; + + return (child_bal == 0); + } + + /* BEGIN CSTYLED */ + /* + * case 2 : When node is left heavy, but child is right heavy we use + * a different rotation. + * + * (node b:-2) + * / \ + * / \ + * / \ + * (child b:+1) + * / \ + * / \ + * (gchild b: != 0) + * / \ + * / \ + * gleft gright + * + * becomes: + * + * (gchild b:0) + * / \ + * / \ + * / \ + * (child b:?) (node b:?) + * / \ / \ + * / \ / \ + * gleft gright + * + * computing the new balances is more complicated. As an example: + * if gchild was right_heavy, then child is now left heavy + * else it is balanced + */ + /* END CSTYLED */ + gchild = child->avl_child[right]; + gleft = gchild->avl_child[left]; + gright = gchild->avl_child[right]; + + /* + * move gright to left child of node and + * + * move gleft to right child of node + */ + node->avl_child[left] = gright; + if (gright != NULL) { + AVL_SETPARENT(gright, node); + AVL_SETCHILD(gright, left); + } + + child->avl_child[right] = gleft; + if (gleft != NULL) { + AVL_SETPARENT(gleft, child); + AVL_SETCHILD(gleft, right); + } + + /* + * move child to left child of gchild and + * + * move node to right child of gchild and + * + * fixup parent of all this to point to gchild + */ + balance = AVL_XBALANCE(gchild); + gchild->avl_child[left] = child; + AVL_SETBALANCE(child, (balance == right_heavy ? left_heavy : 0)); + AVL_SETPARENT(child, gchild); + AVL_SETCHILD(child, left); + + gchild->avl_child[right] = node; + AVL_SETBALANCE(node, (balance == left_heavy ? right_heavy : 0)); + AVL_SETPARENT(node, gchild); + AVL_SETCHILD(node, right); + + AVL_SETBALANCE(gchild, 0); + AVL_SETPARENT(gchild, parent); + AVL_SETCHILD(gchild, which_child); + if (parent != NULL) + parent->avl_child[which_child] = gchild; + else + tree->avl_root = gchild; + + return (1); /* the new tree is always shorter */ +} + + +/* + * Insert a new node into an AVL tree at the specified (from avl_find()) place. + * + * Newly inserted nodes are always leaf nodes in the tree, since avl_find() + * searches out to the leaf positions. The avl_index_t indicates the node + * which will be the parent of the new node. + * + * After the node is inserted, a single rotation further up the tree may + * be necessary to maintain an acceptable AVL balance. + */ +void +avl_insert(avl_tree_t *tree, void *new_data, avl_index_t where) +{ + avl_node_t *node; + avl_node_t *parent = AVL_INDEX2NODE(where); + int old_balance; + int new_balance; + int which_child = AVL_INDEX2CHILD(where); + size_t off = tree->avl_offset; + + ASSERT(tree); +#ifdef _LP64 + ASSERT(((uintptr_t)new_data & 0x7) == 0); +#endif + + node = AVL_DATA2NODE(new_data, off); + + /* + * First, add the node to the tree at the indicated position. + */ + ++tree->avl_numnodes; + + node->avl_child[0] = NULL; + node->avl_child[1] = NULL; + + AVL_SETCHILD(node, which_child); + AVL_SETBALANCE(node, 0); + AVL_SETPARENT(node, parent); + if (parent != NULL) { + ASSERT(parent->avl_child[which_child] == NULL); + parent->avl_child[which_child] = node; + } else { + ASSERT(tree->avl_root == NULL); + tree->avl_root = node; + } + /* + * Now, back up the tree modifying the balance of all nodes above the + * insertion point. If we get to a highly unbalanced ancestor, we + * need to do a rotation. If we back out of the tree we are done. + * If we brought any subtree into perfect balance (0), we are also done. + */ + for (;;) { + node = parent; + if (node == NULL) + return; + + /* + * Compute the new balance + */ + old_balance = AVL_XBALANCE(node); + new_balance = old_balance + avl_child2balance[which_child]; + + /* + * If we introduced equal balance, then we are done immediately + */ + if (new_balance == 0) { + AVL_SETBALANCE(node, 0); + return; + } + + /* + * If both old and new are not zero we went + * from -1 to -2 balance, do a rotation. + */ + if (old_balance != 0) + break; + + AVL_SETBALANCE(node, new_balance); + parent = AVL_XPARENT(node); + which_child = AVL_XCHILD(node); + } + + /* + * perform a rotation to fix the tree and return + */ + (void) avl_rotation(tree, node, new_balance); +} + +/* + * Insert "new_data" in "tree" in the given "direction" either after or + * before (AVL_AFTER, AVL_BEFORE) the data "here". + * + * Insertions can only be done at empty leaf points in the tree, therefore + * if the given child of the node is already present we move to either + * the AVL_PREV or AVL_NEXT and reverse the insertion direction. Since + * every other node in the tree is a leaf, this always works. + * + * To help developers using this interface, we assert that the new node + * is correctly ordered at every step of the way in DEBUG kernels. + */ +void +avl_insert_here( + avl_tree_t *tree, + void *new_data, + void *here, + int direction) +{ + avl_node_t *node; + int child = direction; /* rely on AVL_BEFORE == 0, AVL_AFTER == 1 */ +#ifdef DEBUG + int diff; +#endif + + ASSERT(tree != NULL); + ASSERT(new_data != NULL); + ASSERT(here != NULL); + ASSERT(direction == AVL_BEFORE || direction == AVL_AFTER); + + /* + * If corresponding child of node is not NULL, go to the neighboring + * node and reverse the insertion direction. + */ + node = AVL_DATA2NODE(here, tree->avl_offset); + +#ifdef DEBUG + diff = tree->avl_compar(new_data, here); + ASSERT(-1 <= diff && diff <= 1); + ASSERT(diff != 0); + ASSERT(diff > 0 ? child == 1 : child == 0); +#endif + + if (node->avl_child[child] != NULL) { + node = node->avl_child[child]; + child = 1 - child; + while (node->avl_child[child] != NULL) { +#ifdef DEBUG + diff = tree->avl_compar(new_data, + AVL_NODE2DATA(node, tree->avl_offset)); + ASSERT(-1 <= diff && diff <= 1); + ASSERT(diff != 0); + ASSERT(diff > 0 ? child == 1 : child == 0); +#endif + node = node->avl_child[child]; + } +#ifdef DEBUG + diff = tree->avl_compar(new_data, + AVL_NODE2DATA(node, tree->avl_offset)); + ASSERT(-1 <= diff && diff <= 1); + ASSERT(diff != 0); + ASSERT(diff > 0 ? child == 1 : child == 0); +#endif + } + ASSERT(node->avl_child[child] == NULL); + + avl_insert(tree, new_data, AVL_MKINDEX(node, child)); +} + +/* + * Add a new node to an AVL tree. + */ +void +avl_add(avl_tree_t *tree, void *new_node) +{ + avl_index_t where; + + /* + * This is unfortunate. We want to call panic() here, even for + * non-DEBUG kernels. In userland, however, we can't depend on anything + * in libc or else the rtld build process gets confused. So, all we can + * do in userland is resort to a normal ASSERT(). + */ + if (avl_find(tree, new_node, &where) != NULL) +#ifdef _KERNEL + panic("avl_find() succeeded inside avl_add()"); +#else + ASSERT(0); +#endif + avl_insert(tree, new_node, where); +} + +/* + * Delete a node from the AVL tree. Deletion is similar to insertion, but + * with 2 complications. + * + * First, we may be deleting an interior node. Consider the following subtree: + * + * d c c + * / \ / \ / \ + * b e b e b e + * / \ / \ / + * a c a a + * + * When we are deleting node (d), we find and bring up an adjacent valued leaf + * node, say (c), to take the interior node's place. In the code this is + * handled by temporarily swapping (d) and (c) in the tree and then using + * common code to delete (d) from the leaf position. + * + * Secondly, an interior deletion from a deep tree may require more than one + * rotation to fix the balance. This is handled by moving up the tree through + * parents and applying rotations as needed. The return value from + * avl_rotation() is used to detect when a subtree did not change overall + * height due to a rotation. + */ +void +avl_remove(avl_tree_t *tree, void *data) +{ + avl_node_t *delete; + avl_node_t *parent; + avl_node_t *node; + avl_node_t tmp; + int old_balance; + int new_balance; + int left; + int right; + int which_child; + size_t off = tree->avl_offset; + + ASSERT(tree); + + delete = AVL_DATA2NODE(data, off); + + /* + * Deletion is easiest with a node that has at most 1 child. + * We swap a node with 2 children with a sequentially valued + * neighbor node. That node will have at most 1 child. Note this + * has no effect on the ordering of the remaining nodes. + * + * As an optimization, we choose the greater neighbor if the tree + * is right heavy, otherwise the left neighbor. This reduces the + * number of rotations needed. + */ + if (delete->avl_child[0] != NULL && delete->avl_child[1] != NULL) { + + /* + * choose node to swap from whichever side is taller + */ + old_balance = AVL_XBALANCE(delete); + left = avl_balance2child[old_balance + 1]; + right = 1 - left; + + /* + * get to the previous value'd node + * (down 1 left, as far as possible right) + */ + for (node = delete->avl_child[left]; + node->avl_child[right] != NULL; + node = node->avl_child[right]) + ; + + /* + * create a temp placeholder for 'node' + * move 'node' to delete's spot in the tree + */ + tmp = *node; + + *node = *delete; + if (node->avl_child[left] == node) + node->avl_child[left] = &tmp; + + parent = AVL_XPARENT(node); + if (parent != NULL) + parent->avl_child[AVL_XCHILD(node)] = node; + else + tree->avl_root = node; + AVL_SETPARENT(node->avl_child[left], node); + AVL_SETPARENT(node->avl_child[right], node); + + /* + * Put tmp where node used to be (just temporary). + * It always has a parent and at most 1 child. + */ + delete = &tmp; + parent = AVL_XPARENT(delete); + parent->avl_child[AVL_XCHILD(delete)] = delete; + which_child = (delete->avl_child[1] != 0); + if (delete->avl_child[which_child] != NULL) + AVL_SETPARENT(delete->avl_child[which_child], delete); + } + + + /* + * Here we know "delete" is at least partially a leaf node. It can + * be easily removed from the tree. + */ + ASSERT(tree->avl_numnodes > 0); + --tree->avl_numnodes; + parent = AVL_XPARENT(delete); + which_child = AVL_XCHILD(delete); + if (delete->avl_child[0] != NULL) + node = delete->avl_child[0]; + else + node = delete->avl_child[1]; + + /* + * Connect parent directly to node (leaving out delete). + */ + if (node != NULL) { + AVL_SETPARENT(node, parent); + AVL_SETCHILD(node, which_child); + } + if (parent == NULL) { + tree->avl_root = node; + return; + } + parent->avl_child[which_child] = node; + + + /* + * Since the subtree is now shorter, begin adjusting parent balances + * and performing any needed rotations. + */ + do { + + /* + * Move up the tree and adjust the balance + * + * Capture the parent and which_child values for the next + * iteration before any rotations occur. + */ + node = parent; + old_balance = AVL_XBALANCE(node); + new_balance = old_balance - avl_child2balance[which_child]; + parent = AVL_XPARENT(node); + which_child = AVL_XCHILD(node); + + /* + * If a node was in perfect balance but isn't anymore then + * we can stop, since the height didn't change above this point + * due to a deletion. + */ + if (old_balance == 0) { + AVL_SETBALANCE(node, new_balance); + break; + } + + /* + * If the new balance is zero, we don't need to rotate + * else + * need a rotation to fix the balance. + * If the rotation doesn't change the height + * of the sub-tree we have finished adjusting. + */ + if (new_balance == 0) + AVL_SETBALANCE(node, new_balance); + else if (!avl_rotation(tree, node, new_balance)) + break; + } while (parent != NULL); +} + +#define AVL_REINSERT(tree, obj) \ + avl_remove((tree), (obj)); \ + avl_add((tree), (obj)) + +boolean_t +avl_update_lt(avl_tree_t *t, void *obj) +{ + void *neighbor; + + ASSERT(((neighbor = AVL_NEXT(t, obj)) == NULL) || + (t->avl_compar(obj, neighbor) <= 0)); + + neighbor = AVL_PREV(t, obj); + if ((neighbor != NULL) && (t->avl_compar(obj, neighbor) < 0)) { + AVL_REINSERT(t, obj); + return (B_TRUE); + } + + return (B_FALSE); +} + +boolean_t +avl_update_gt(avl_tree_t *t, void *obj) +{ + void *neighbor; + + ASSERT(((neighbor = AVL_PREV(t, obj)) == NULL) || + (t->avl_compar(obj, neighbor) >= 0)); + + neighbor = AVL_NEXT(t, obj); + if ((neighbor != NULL) && (t->avl_compar(obj, neighbor) > 0)) { + AVL_REINSERT(t, obj); + return (B_TRUE); + } + + return (B_FALSE); +} + +boolean_t +avl_update(avl_tree_t *t, void *obj) +{ + void *neighbor; + + neighbor = AVL_PREV(t, obj); + if ((neighbor != NULL) && (t->avl_compar(obj, neighbor) < 0)) { + AVL_REINSERT(t, obj); + return (B_TRUE); + } + + neighbor = AVL_NEXT(t, obj); + if ((neighbor != NULL) && (t->avl_compar(obj, neighbor) > 0)) { + AVL_REINSERT(t, obj); + return (B_TRUE); + } + + return (B_FALSE); +} + +/* + * initialize a new AVL tree + */ +void +avl_create(avl_tree_t *tree, int (*compar) (const void *, const void *), + size_t size, size_t offset) +{ + ASSERT(tree); + ASSERT(compar); + ASSERT(size > 0); + ASSERT(size >= offset + sizeof (avl_node_t)); +#ifdef _LP64 + ASSERT((offset & 0x7) == 0); +#endif + + tree->avl_compar = compar; + tree->avl_root = NULL; + tree->avl_numnodes = 0; + tree->avl_size = size; + tree->avl_offset = offset; +} + +/* + * Delete a tree. + */ +/* ARGSUSED */ +void +avl_destroy(avl_tree_t *tree) +{ + ASSERT(tree); + ASSERT(tree->avl_numnodes == 0); + ASSERT(tree->avl_root == NULL); +} + + +/* + * Return the number of nodes in an AVL tree. + */ +ulong_t +avl_numnodes(avl_tree_t *tree) +{ + ASSERT(tree); + return (tree->avl_numnodes); +} + +boolean_t +avl_is_empty(avl_tree_t *tree) +{ + ASSERT(tree); + return (tree->avl_numnodes == 0); +} + +#define CHILDBIT (1L) + +/* + * Post-order tree walk used to visit all tree nodes and destroy the tree + * in post order. This is used for destroying a tree w/o paying any cost + * for rebalancing it. + * + * example: + * + * void *cookie = NULL; + * my_data_t *node; + * + * while ((node = avl_destroy_nodes(tree, &cookie)) != NULL) + * free(node); + * avl_destroy(tree); + * + * The cookie is really an avl_node_t to the current node's parent and + * an indication of which child you looked at last. + * + * On input, a cookie value of CHILDBIT indicates the tree is done. + */ +void * +avl_destroy_nodes(avl_tree_t *tree, void **cookie) +{ + avl_node_t *node; + avl_node_t *parent; + int child; + void *first; + size_t off = tree->avl_offset; + + /* + * Initial calls go to the first node or it's right descendant. + */ + if (*cookie == NULL) { + first = avl_first(tree); + + /* + * deal with an empty tree + */ + if (first == NULL) { + *cookie = (void *)CHILDBIT; + return (NULL); + } + + node = AVL_DATA2NODE(first, off); + parent = AVL_XPARENT(node); + goto check_right_side; + } + + /* + * If there is no parent to return to we are done. + */ + parent = (avl_node_t *)((uintptr_t)(*cookie) & ~CHILDBIT); + if (parent == NULL) { + if (tree->avl_root != NULL) { + ASSERT(tree->avl_numnodes == 1); + tree->avl_root = NULL; + tree->avl_numnodes = 0; + } + return (NULL); + } + + /* + * Remove the child pointer we just visited from the parent and tree. + */ + child = (uintptr_t)(*cookie) & CHILDBIT; + parent->avl_child[child] = NULL; + ASSERT(tree->avl_numnodes > 1); + --tree->avl_numnodes; + + /* + * If we just did a right child or there isn't one, go up to parent. + */ + if (child == 1 || parent->avl_child[1] == NULL) { + node = parent; + parent = AVL_XPARENT(parent); + goto done; + } + + /* + * Do parent's right child, then leftmost descendent. + */ + node = parent->avl_child[1]; + while (node->avl_child[0] != NULL) { + parent = node; + node = node->avl_child[0]; + } + + /* + * If here, we moved to a left child. It may have one + * child on the right (when balance == +1). + */ +check_right_side: + if (node->avl_child[1] != NULL) { + ASSERT(AVL_XBALANCE(node) == 1); + parent = node; + node = node->avl_child[1]; + ASSERT(node->avl_child[0] == NULL && + node->avl_child[1] == NULL); + } else { + ASSERT(AVL_XBALANCE(node) <= 0); + } + +done: + if (parent == NULL) { + *cookie = (void *)CHILDBIT; + ASSERT(node == tree->avl_root); + } else { + *cookie = (void *)((uintptr_t)parent | AVL_XCHILD(node)); + } + + return (AVL_NODE2DATA(node, off)); +} diff --git a/lib_acl/src/stdlib/configure/acl_loadcfg.c b/lib_acl/src/stdlib/configure/acl_loadcfg.c new file mode 100644 index 000000000..d8da1d0c2 --- /dev/null +++ b/lib_acl/src/stdlib/configure/acl_loadcfg.c @@ -0,0 +1,725 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include +#include + +#ifdef ACL_UNIX +#include +#include +#include +#endif + +#ifdef ACL_MS_WINDOWS +#include +#endif + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_msg.h" +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_array.h" +#include "stdlib/acl_mystring.h" +#include "stdlib/acl_sys_patch.h" +#include "stdlib/acl_loadcfg.h" + +#endif + +struct ACL_CFG_PARSER { + ACL_ARRAY *_cfg_array; + int total_line; + int valid_line; +}; + +static int _cfg_file_load(ACL_FILE_HANDLE filefd, char *buf, int bsize) +{ + char *ptr; + int n, len; + + if (filefd < 0 || buf == NULL || bsize < 1) + return (-1); + ptr = buf; + len = 0; + bsize--; /* make one byte room for '\0' */ + while (1) { + n = acl_file_read(filefd, ptr, bsize, 0, NULL); + if (n < 0) /* read error */ + return (-1); + else if (n == 0) /* read over */ + break; + ptr += n; + len += n; + bsize -= n; + if (bsize <= 0) { /* reach the end of memory area */ + buf[len] = 0; + return (len); + } + } + + buf[len] = 0; + + return (len); +} + +static ACL_CFG_LINE *_backup_junk_line(const char *ptr) +{ + char myname[] = "_backup_junk_line"; + ACL_CFG_LINE *cfg_line; + char tbuf[256]; + + if (ptr == NULL) + return (NULL); + + cfg_line = (ACL_CFG_LINE *) acl_mycalloc(1, sizeof(ACL_CFG_LINE)); + if (cfg_line == NULL) { + printf("%s: calloc ACL_CFG_LINE, errmsg=%s", + myname, acl_last_strerror(tbuf, sizeof(tbuf))); + return (NULL); + } + + cfg_line->ncount = 0; + cfg_line->value = NULL; + cfg_line->pdata = acl_mystrdup(ptr); + if (cfg_line->pdata == NULL) { + printf("%s: strdup pdata, errmsg=%s", + myname, acl_last_strerror(tbuf, sizeof(tbuf))); + return (NULL); + } + + return (cfg_line); +} + +static ACL_CFG_LINE *_create_cfg_line(char *data, const char *delimiter) +{ + ACL_CFG_LINE *cfg_line = NULL; + ACL_ARRAY *a = NULL; + int i, n; + char *ptr, *pdata, *pitem; + +#undef ERETURN +#define ERETURN(x) do { \ + if (a) \ + acl_array_destroy(a, acl_myfree_fn); \ + if (cfg_line) { \ + if (cfg_line->value) \ + acl_myfree(cfg_line); \ + acl_myfree(cfg_line); \ + } \ + return (x); \ +} while (0); + + if (data == NULL) + return (NULL); + + pdata = data; + + cfg_line = (ACL_CFG_LINE *) acl_mycalloc(1, sizeof(ACL_CFG_LINE)); + if (cfg_line == NULL) + return (NULL); + + a = acl_array_create(10); + while (1) { + ptr = acl_mystrtok(&pdata, delimiter); + if (ptr == NULL) + break; + pitem = acl_mystrdup(ptr); + if (pitem == NULL) { + ERETURN (NULL); + } + if (acl_array_append(a, (void *) pitem) < 0) { + ERETURN (NULL); + } + } + + cfg_line->ncount = 0; + cfg_line->pdata = NULL; + n = acl_array_size(a); + if (n > 0) { + cfg_line->value = (char **) acl_mycalloc(1 + n, sizeof(char *)); + if (cfg_line->value == NULL) { + ERETURN (NULL); + } + for (i = 0; i < n; i++) { + pitem = (char *) acl_array_index(a, i); + if (pitem == NULL) + break; + cfg_line->value[i] = pitem; + if (cfg_line->value[i] == NULL) + ERETURN (NULL); + cfg_line->ncount++; + } + } + + /* NOTICE: in acl_array_destroy, please don't input acl_myfree, but + * NULL as the second parameter, because the mystrup's result + * set are stored in cfg_line->value now:) + */ + acl_array_destroy(a, NULL); + + return (cfg_line); +} + +ACL_CFG_PARSER *acl_cfg_parser_load(const char *pathname, const char *delimiter) +{ + char myname[] = "acl_cfg_parse_load"; + ACL_CFG_PARSER *parser = NULL; + ACL_CFG_LINE *cfg_line; + struct stat stat_buf; + int buf_size; + char *content_buf = NULL, *ptr; + char *pline_begin; + ACL_FILE_HANDLE filefd = ACL_FILE_INVALID; + char tbuf[256]; + +#undef ERETURN +#define ERETURN(x) do { \ + if (content_buf != NULL) \ + acl_myfree(content_buf); \ + if (filefd != ACL_FILE_INVALID) \ + acl_file_close(filefd); \ + if (parser != NULL) { \ + acl_array_destroy(parser->_cfg_array, NULL); \ + acl_myfree(parser); \ + } \ + return (x); \ +} while (0); + +#undef RETURN +#define RETURN(x) do { \ + if (content_buf != NULL) \ + acl_myfree(content_buf); \ + if (filefd != ACL_FILE_INVALID) \ + acl_file_close(filefd); \ + return (x); \ +} while (0); + + if (pathname == NULL || *pathname == 0) { + printf("%s: invalid pathname\n", myname); + return (NULL); + } + + if (stat(pathname, &stat_buf) < 0) { + printf("%s: can't stat, pathname=%s, errmsg=%s\n", + myname, pathname, acl_last_strerror(tbuf, sizeof(tbuf))); + ERETURN (NULL); + } + + parser = (ACL_CFG_PARSER *) acl_mycalloc(1, sizeof(*parser)); + if (parser == NULL) { + printf("%s: can't calloc ACL_CFG_PARSER, pathname=%s, errmsg=%s", + myname, pathname, acl_last_strerror(tbuf, sizeof(tbuf))); + ERETURN (NULL); + } + + parser->_cfg_array = acl_array_create(10); + if (parser->_cfg_array == NULL) { + printf("%s: can't create array, pathname=%s, errmsg=%s", + myname, pathname, acl_last_strerror(tbuf, sizeof(tbuf))); + ERETURN (NULL); + } + parser->total_line = 0; + parser->valid_line = 0; + + buf_size = stat_buf.st_size + 256; + content_buf = (char *) acl_mycalloc(1, buf_size); + if (content_buf == NULL) { + printf("%s: can't calloc, pathname=%s, errmsg=%s\n", + myname, pathname, acl_last_strerror(tbuf, sizeof(tbuf))); + ERETURN (NULL); + } + +#ifdef ACL_UNIX + filefd = acl_file_open(pathname, O_RDWR, S_IREAD | S_IWRITE | S_IRGRP); +#elif defined(ACL_MS_WINDOWS) + filefd = acl_file_open(pathname, O_RDWR, S_IREAD | S_IWRITE); +#else +# error "unknown OS" +#endif + + if (filefd == ACL_FILE_INVALID) { + printf("%s: can't open, pathname=%s, errmsg=%s\n", + myname, pathname, acl_last_strerror(tbuf, sizeof(tbuf))); + + ERETURN (NULL); + } + + if (_cfg_file_load(filefd, content_buf, buf_size) < 0) { + printf("%s: can't read, pathname=%s, errmsg=%s\n", + myname, pathname, acl_last_strerror(tbuf, sizeof(tbuf))); + ERETURN (NULL); + } + +#undef SKIP +#define SKIP(var, cond) \ + for (; *var && (cond); var++); + + ptr = content_buf; + while (*ptr) { + pline_begin = ptr; /* keep the line header */ + /* first, skip all ' ' and '\t' */ + SKIP(ptr, (*ptr == ' ' || *ptr == '\t')); + + /* 操作存储注释行 */ + if (*ptr == '#') { /* the comment line */ + SKIP(ptr, *ptr != '\n'); /* find the line's end */ + if (*ptr) { /* this must be '\n' */ + *ptr++ = 0; /* set '\0' and skip one byte */ + } + + cfg_line = _backup_junk_line(pline_begin); + if (cfg_line == NULL) + ERETURN (NULL); + if (acl_array_append(parser->_cfg_array, + (void *) cfg_line) < 0) { + printf("%s: can't add ACL_CFG_LINE to array, " + "errmsg=%s", myname, acl_last_strerror(tbuf, sizeof(tbuf))); + ERETURN (NULL); + } + parser->total_line++; + cfg_line->line_number = parser->total_line; + continue; + } else if (*ptr == '\r' || *ptr == '\n') { + /* 操作空行 */ + /* SKIP(ptr, (*ptr == '\r' || *ptr == '\n')); */ + if (*ptr == '\r' && *(ptr + 1) == '\n') { + *ptr = 0; /* set '\0' first and go on */ + ptr += 2; + } else if (*ptr == '\n') { + *ptr = 0; /* set '\0' first and go on */ + ptr++; + } + + cfg_line = _backup_junk_line(pline_begin); + if (cfg_line == NULL) + ERETURN (NULL); + if (acl_array_append(parser->_cfg_array, + (void *) cfg_line) < 0) { + printf("%s: can't add ACL_CFG_LINE to array, " + "errmsg=%s", myname, acl_last_strerror(tbuf, sizeof(tbuf))); + ERETURN (NULL); + } + parser->total_line++; + cfg_line->line_number = parser->total_line; + continue; + } + + /* 操作有效行 */ + pline_begin = ptr; /* reset the line header */ + + /* find the line's end */ + SKIP(ptr, (*ptr != '\n' && *ptr != '\r')); + if (*ptr) { /* this must be '\r' or '\n' */ + if (*ptr == '\r' && *(ptr + 1) == '\n') { + *ptr = 0; /* set '\0' first and go on */ + ptr += 2; + } else if (*ptr == '\n') { + *ptr = 0; /* set '\0' first and go on */ + ptr++; + } + } + + /* make ptr to the next line's beginning */ + /* SKIP(ptr, (*ptr == '\r' || *ptr == '\n')); */ + + cfg_line = _create_cfg_line(pline_begin, delimiter); + if (cfg_line == NULL) + ERETURN (NULL); + if (acl_array_append(parser->_cfg_array, (void *) cfg_line) < 0) { + printf("%s: can't add ACL_CFG_LINE to array, errmsg=%s", + myname, acl_last_strerror(tbuf, sizeof(tbuf))); + ERETURN (NULL); + } + parser->total_line++; + parser->valid_line++; + cfg_line->line_number = parser->total_line; + } + + if (parser->total_line != acl_array_size(parser->_cfg_array)) { + printf("%s: total_line=%d, acl_array_size=%d, errmsg=not equal\n", + myname, parser->total_line, + acl_array_size(parser->_cfg_array)); + } + + RETURN (parser); +#ifdef ACL_BCB_COMPILER + return (NULL); +#endif +} + +/* 释放 ACL_CFG_LINE 项所用的回调函数 */ +static void _cfg_line_free(void *arg) +{ + ACL_CFG_LINE *cfg_line; + int i; + + cfg_line = (ACL_CFG_LINE *) arg; + + if (cfg_line == NULL) + return; + + for (i = 0; i < cfg_line->ncount; i++) { + if (cfg_line->value == NULL) + break; + if (cfg_line->value[i] == NULL) + break; + acl_myfree(cfg_line->value[i]); + } + if (cfg_line->value != NULL) + acl_myfree(cfg_line->value); + if (cfg_line->pdata != NULL) + acl_myfree(cfg_line->pdata); + acl_myfree(cfg_line); +} + +void acl_cfg_parser_free(ACL_CFG_PARSER *parser) +{ + if (parser) { + if (parser->_cfg_array) + acl_array_destroy(parser->_cfg_array, _cfg_line_free); + acl_myfree(parser); + } +} + +void acl_cfg_parser_walk(ACL_CFG_PARSER *parser, ACL_CFG_WALK_FN walk_fn) +{ + int i, n; + ACL_CFG_LINE *cfg_line; + + if (parser) { + n = acl_array_size(parser->_cfg_array); + for (i = 0; i < n; i++) { + cfg_line = (ACL_CFG_LINE *) + acl_array_index(parser->_cfg_array, i); + if (cfg_line == NULL) + break; + walk_fn((void *) cfg_line); + } + } +} + +int acl_cfg_line_replace(ACL_CFG_LINE *cfg_line, const char **value, int from, int to) +{ + char myname[] = "acl_cfg_line_replace"; + int i, n, j; + char tbuf[256]; + + if (cfg_line == NULL) + return (-1); + + n = cfg_line->ncount; + + if (from >= n) + from = n - 1; + if (to >= n) + to = n - 1; + + if (from < 0 || to < 0) + return (-1); + + n = 0; + j = 0; + if (from <= to) { + for (i = from; i <= to; i++) { + if (cfg_line->value == NULL) + break; + if ((const char **) cfg_line->value == value) + break; + if (cfg_line->value[i] == value[j]) { + j++; + continue; + } + if (cfg_line->value[i] != NULL) + acl_myfree(cfg_line->value[i]); + cfg_line->value[i] = acl_mystrdup(value[j]); + if (cfg_line->value[i] == NULL) { + printf("%s: can't strdup, errmsg=%s\n", + myname, acl_last_strerror(tbuf, sizeof(tbuf))); + exit (1); + } + j++; + n++; + } + } else { + for (i = from; i >= to; i--) { + if ((const char **) cfg_line->value == value) + break; + if (cfg_line->value[i] == value[j]) { + j++; + continue; + } + if (cfg_line->value[i] != NULL) + acl_myfree(cfg_line->value[i]); + cfg_line->value[i] = acl_mystrdup(value[j]); + if (cfg_line->value[i] == NULL) { + printf("%s: can't strdup, errmsg=%s\n", + myname, acl_last_strerror(tbuf, sizeof(tbuf))); + exit (1); + } + j++; + n++; + } + } + + return (n); +} + +ACL_CFG_LINE *acl_cfg_parser_index(const ACL_CFG_PARSER *parser, int idx) +{ + ACL_CFG_LINE *cfg_line; + + if (parser == NULL || idx < 0) + return (NULL); + + cfg_line = (ACL_CFG_LINE *) acl_array_index(parser->_cfg_array, idx); + return (cfg_line); +} + +int acl_cfg_parser_size(const ACL_CFG_PARSER *parser) +{ + if (parser == NULL) + return (-1); + + return (parser->total_line); +} + +static int _cfg_line_dump(ACL_FILE_HANDLE filefd, const ACL_CFG_LINE *cfg_line, const char *delimiter) +{ + char myname[] = "_cfg_line_dump"; + char *pbuf, *ptr; + int dlen = 0, i, j, n; + char tbuf[256]; + + n = cfg_line->ncount; + if (delimiter != NULL) + j = strlen(delimiter); + else + j = 0; + + if (cfg_line->value != NULL) { + for (i = 0; i < n; i++) { + if (cfg_line->value[i] == NULL) + break; + dlen += strlen(cfg_line->value[i]) + j; + } + dlen += 2; /* for '\n' and '\0' */ + pbuf = (char *) acl_mycalloc(1, dlen); + ptr = pbuf; + for (i = 0; i < n; i++) { + if (cfg_line->value[i] == NULL) + break; + if (i < n -1) + sprintf(ptr, "%s%s", cfg_line->value[i], delimiter); + else + sprintf(ptr, "%s", cfg_line->value[i]); + ptr = ptr + strlen(ptr); + } + ptr = ptr + strlen(ptr); + strcat(ptr, "\n\0"); + i = acl_file_write(filefd, pbuf, strlen(pbuf), 0, NULL); + if (i <= 0) { + printf("%s: can't write pbuf, error=%s\n", + myname, acl_last_strerror(tbuf, sizeof(tbuf))); + acl_myfree(pbuf); + return (-1); + } + } else if (cfg_line->pdata != NULL) { + dlen = strlen(cfg_line->pdata) + 2; + pbuf = (char *) acl_mycalloc(1, dlen); + if (pbuf == NULL) + return (-1); + sprintf(pbuf, "%s\n", cfg_line->pdata); + i = acl_file_write(filefd, pbuf, strlen(pbuf), 0, NULL); + if (i <= 0) + return (-1); + } + + return (0); +} + +int acl_cfg_parser_dump(const ACL_CFG_PARSER *parser, + const char *pathname, + const char *delimiter) +{ + char myname[] = "acl_cfg_parser_dump"; + ACL_CFG_LINE *cfg_line; + ACL_FILE_HANDLE filefd = ACL_FILE_INVALID; + int i, n, ret; + char tbuf[256]; + +#undef RETURN +#define RETURN(x) do { \ + if (filefd != ACL_FILE_INVALID) \ + acl_file_close(filefd); \ + return (x); \ +} while (0); + + if (parser == NULL || pathname == NULL || *pathname == 0) + return (-1); +#ifdef ACL_UNIX + filefd = acl_file_open(pathname, + O_CREAT | O_TRUNC | O_APPEND | O_WRONLY, + S_IREAD | S_IWRITE | S_IRGRP); +#elif defined(ACL_MS_WINDOWS) + filefd = acl_file_open(pathname, + O_CREAT | O_TRUNC | O_APPEND | O_WRONLY, + S_IREAD | S_IWRITE); +#else +# error "unknown OS" +#endif + if (filefd == ACL_FILE_INVALID) { + printf("%s: can't open, pathname=%s, errmsg=%s\n", + myname, pathname, acl_last_strerror(tbuf, sizeof(tbuf))); + RETURN(-1); + } + + n = acl_array_size(parser->_cfg_array); + for (i = 0; i < n; i++) { + cfg_line = (ACL_CFG_LINE *) + acl_array_index(parser->_cfg_array, i); + if (cfg_line == NULL) + break; + ret = _cfg_line_dump(filefd, cfg_line, delimiter); + if (ret < 0) { + RETURN (-1); + } + } + + RETURN (0); +#ifdef ACL_BCB_COMPILER + return (0); +#endif +} + +int acl_cfg_parser_append(ACL_CFG_PARSER *parser, ACL_CFG_LINE *cfg_line) +{ + char myname[] = "acl_cfg_parser_append"; + char tbuf[256]; + + if (parser == NULL || cfg_line == NULL) { + printf("%s: input error\n", myname); + return (-1); + } + + if (parser->_cfg_array == NULL) { + parser->_cfg_array = acl_array_create(10); + if (parser->_cfg_array == NULL) { + printf("%s: can't create array, errmsg=%s", + myname, acl_last_strerror(tbuf, sizeof(tbuf))); + return (-1); + } + parser->total_line = 0; + parser->valid_line = 0; + } + + if (acl_array_append(parser->_cfg_array, (void *) cfg_line) < 0) { + printf("%s: can't add ACL_CFG_LINE to array, errmsg=%s", + myname, acl_last_strerror(tbuf, sizeof(tbuf))); + return (-1); + } + parser->total_line++; + if (cfg_line->pdata == NULL && cfg_line->value != NULL) + parser->valid_line++; + cfg_line->line_number = parser->total_line; + + return (0); +} + +int acl_cfg_parser_delete(ACL_CFG_PARSER *parser, const char *name) +{ + char myname[] = "acl_cfg_parser_delete"; + ACL_CFG_LINE *cfg_line = NULL; + int i, n, ok = 0, j; + + if (parser == NULL || name == NULL || *name == 0) { + printf("%s: input error\n", myname); + return (-1); + } + + if (parser->_cfg_array == NULL) { + return (0); + } + + n = acl_array_size(parser->_cfg_array); + for (i = 0; i < n; i++) { + cfg_line = (ACL_CFG_LINE *) acl_array_index(parser->_cfg_array, i); + if (cfg_line == NULL) + return (0); + if (cfg_line->ncount < 1) + continue; + if (strcmp(cfg_line->value[0], name) == 0) { + ok = 1; + break; + } + } + + if (ok) { + if (cfg_line->pdata == NULL && cfg_line->value != NULL) + parser->valid_line--; + parser->total_line--; + acl_array_delete_idx(parser->_cfg_array, i, _cfg_line_free); + + n = acl_array_size(parser->_cfg_array); + for (j = i; j < n; j++) { + cfg_line = (ACL_CFG_LINE *) acl_array_index(parser->_cfg_array, j); + if (cfg_line == NULL) + break; + cfg_line->line_number--; + } + } + + return (0); +} + +ACL_CFG_LINE *acl_cfg_line_new(const char **value, int ncount) +{ + ACL_CFG_LINE *cfg_line = NULL; + int i; + +#undef ERETURN +#define ERETURN(x) do { \ + if (cfg_line == NULL) \ + return (x); \ + if (cfg_line->value == NULL) { \ + acl_myfree(cfg_line); \ + return (x); \ + } \ + for (i = 0; i < cfg_line->ncount; i++) { \ + if (cfg_line->value[i] == NULL) \ + break; \ + acl_myfree(cfg_line->value[i]); \ + } \ + acl_myfree(cfg_line->value); \ + acl_myfree(cfg_line); \ + return (x); \ +} while (0); + + if (value == NULL || ncount <= 0) + return (NULL); + + cfg_line = (ACL_CFG_LINE *) acl_mycalloc(1, sizeof(ACL_CFG_LINE)); + if (cfg_line == NULL) + return (NULL); + + cfg_line->value = (char **) acl_mycalloc(1 + ncount, sizeof(char *)); + if (cfg_line->value == NULL) + ERETURN (NULL); + + cfg_line->pdata = NULL; + cfg_line->ncount = 0; + cfg_line->line_number = 0; + + for (i = 0; i < ncount; i++) { + cfg_line->value[i] = acl_mystrdup(value[i]); + if (cfg_line->value[i] == NULL) + ERETURN (NULL); + cfg_line->ncount++; + } + + return (cfg_line); +} + diff --git a/lib_acl/src/stdlib/configure/acl_xinetd_cfg.c b/lib_acl/src/stdlib/configure/acl_xinetd_cfg.c new file mode 100644 index 000000000..3881b8c85 --- /dev/null +++ b/lib_acl/src/stdlib/configure/acl_xinetd_cfg.c @@ -0,0 +1,371 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_msg.h" +#include "stdlib/acl_vstream.h" +#include "stdlib/acl_mystring.h" +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_array.h" +#include "stdlib/acl_xinetd_cfg.h" + +#endif + +/* internal type define */ + +struct ACL_XINETD_CFG_PARSER { + ACL_ARRAY *nv_array; +}; + +typedef struct ACL_XINETD_NV_PAIR { + char *name; +/* char *value; */ + ACL_ARRAY *values; +} ACL_XINETD_NV_PAIR; + +static void __nv_pair_free(void *arg) +{ + ACL_XINETD_NV_PAIR *pair = (ACL_XINETD_NV_PAIR *) arg; + + if (pair) { + if (pair->name) + acl_myfree(pair->name); + if (pair->values) + acl_array_destroy(pair->values, acl_myfree_fn); + acl_myfree(pair); + } +} + +static ACL_XINETD_NV_PAIR *__nv_pair_new(const char *name, const char *value) +{ + char myname[] = "__nv_pair_new"; + ACL_XINETD_NV_PAIR *pair; + char *data; + +#undef ERETURN +#define ERETURN(x) { \ + if (pair) { \ + if (pair->name) \ + acl_myfree(pair->name); \ + if (pair->values) \ + acl_array_destroy(pair->values, acl_myfree_fn); \ + acl_myfree(pair); \ + } \ +} + + pair = (ACL_XINETD_NV_PAIR *) acl_mycalloc(1, sizeof(ACL_XINETD_NV_PAIR)); + if (pair == NULL) + return (NULL); + pair->name = acl_mystrdup(name); + if (pair->name == NULL) + ERETURN (NULL); + data = acl_mystrdup(value); + if (data == NULL) + ERETURN (NULL); + + pair->values = acl_array_create(5); + if (pair->values == NULL) + ERETURN (NULL); + if (acl_array_append(pair->values, data) < 0) { + char ebuf[256]; + acl_msg_error("%s(%d)->%s: acl_array_append err = %s", + __FILE__, __LINE__, myname, + acl_last_strerror(ebuf, sizeof(ebuf))); + ERETURN (NULL); + } + + return (pair); +} + +static int __nv_pair_append(ACL_XINETD_NV_PAIR *pair, const char *value) +{ + char myname[] = "__nv_pair_append"; + char *data = acl_mystrdup(value); + + if (data == NULL) + return (-1); + if (acl_array_append(pair->values, data) < 0) { + char ebuf[256]; + + acl_myfree(data); + acl_msg_error("%s(%d)->%s: acl_array_append err=%s", + __FILE__, __LINE__, myname, + acl_last_strerror(ebuf, sizeof(ebuf))); + return (-1); + } + return (0); +} + +static int __xinetd_cfg_parse(ACL_XINETD_CFG_PARSER *xcp, char *line_nonl) +{ + char myname[] = "__xinetd_cfg_parse"; + char *ptr, *ptr_eq; + char *name = NULL, *value = NULL; + ACL_XINETD_NV_PAIR *pair, *pair_search; + int i, size; + + if (*line_nonl == '\0') + return (0); + + while (*line_nonl == ' ' || *line_nonl == '\t') /* skip ' ' and '\t' */ + line_nonl++; + if (*line_nonl == '#') /* comment line */ + return (0); + + ptr = line_nonl; + ptr_eq = NULL; + while (*ptr) { + if (*ptr == '=') { + *ptr = 0; /* find the position of '=' */ + ptr_eq = ptr + 1; /* make ptr_eq pointer + * the next char addr + */ + break; + } + + ptr++; + } + + if (ptr_eq == NULL) + return (0); + + ptr--; /* move before '=' */ + while (ptr > line_nonl) { /* delete any ' ' and '\t' before '=' */ + if (*ptr != ' ' && *ptr != '\t') + break; + *ptr-- = 0; + } + + /* skip any ' ' and '\t' after '=' */ + while (*ptr_eq == ' ' || *ptr_eq == '\t') + ptr_eq++; + + if (*ptr_eq == 0) /* bugfix: by zsx, 2005.8.21 */ + return (0); + + ptr = ptr_eq; + while (*ptr) { + if (*ptr == '#') { + *ptr = 0; + break; + } + ptr++; + } + + while (ptr > ptr_eq) { /* delete any ' ' and '\t' */ + if (*ptr != ' ' && *ptr != '\t' && *ptr != '\0') + break; + *ptr-- = 0; + } + + /* here line_nonl is the name */ + + name = line_nonl; + value = ptr_eq; + + pair = NULL; + size = acl_array_size(xcp->nv_array); + for (i = 0; i < size; i++) { + pair_search = (ACL_XINETD_NV_PAIR *) acl_array_index(xcp->nv_array, i); + if (pair_search == NULL) + break; + if (strcasecmp(name, pair_search->name) == 0) { + pair = pair_search; + break; + } + } + + /* bugfix: 2006.6.13, ---zsx */ + if (pair == NULL) { /* one new pair node */ + pair = __nv_pair_new(name, value); + if (pair == NULL) + ERETURN (-1); + + if (acl_array_append(xcp->nv_array, pair) < 0) { + char ebuf[256]; + acl_msg_error("%s(%d)->%s: acl_array_append err, serr=%s", + __FILE__, __LINE__, myname, + acl_last_strerror(ebuf, sizeof(ebuf))); + return (-1); + } + return (0); + } else { /* name has already exist ! */ + return (__nv_pair_append(pair, value)); + } +} + +void acl_xinetd_cfg_free(ACL_XINETD_CFG_PARSER *xcp) +{ + char myname[] = "acl_xinetd_cfg_free"; + + if (xcp == NULL) + acl_msg_fatal("%s(%d)->%s: input error", + __FILE__, __LINE__, myname); + + if (xcp->nv_array) + acl_array_destroy(xcp->nv_array, __nv_pair_free); + acl_myfree(xcp); +} + +ACL_XINETD_CFG_PARSER *acl_xinetd_cfg_load(const char *pathname) +{ + char myname[] = "acl_xinetd_cfg_load"; + char *content_buf = NULL; + char *pline, *phead; + ACL_XINETD_CFG_PARSER *xcp = NULL; + char ebuf[256]; + +#undef RETURN +#define RETURN(x) { \ + if (content_buf) \ + acl_myfree(content_buf); \ + return (x); \ +} + +#undef ERETURN +#define ERETURN(x) { \ + if (content_buf) \ + acl_myfree(content_buf); \ + if (xcp) { \ + if (xcp->nv_array) \ + acl_array_destroy(xcp->nv_array, __nv_pair_free); \ + acl_myfree(xcp); \ + } \ + return (x); \ +} + + if (pathname == NULL || *pathname == 0) { + acl_msg_error("%s(%d)->%s: input error", + __FILE__, __LINE__, myname); + ERETURN (NULL); + } + + xcp = (ACL_XINETD_CFG_PARSER *) acl_mycalloc(1, sizeof(ACL_XINETD_CFG_PARSER)); + if (xcp == NULL) { + acl_msg_error("%s(%d)->%s: calloc err, serr=%s", + __FILE__, __LINE__, myname, + acl_last_strerror(ebuf, sizeof(ebuf))); + ERETURN (NULL); + } + + xcp->nv_array = acl_array_create(10); + if (xcp->nv_array == NULL) { + acl_msg_error("%s(%d)->%s: acl_array_create err, serr=%s", + __FILE__, __LINE__, myname, + acl_last_strerror(ebuf, sizeof(ebuf))); + ERETURN (NULL); + } + + content_buf = acl_vstream_loadfile(pathname); + if (content_buf == NULL) { + acl_msg_error("%s(%d)->%s: load file(%s) error(%s)", + __FILE__, __LINE__, myname, pathname, + acl_last_strerror(ebuf, sizeof(ebuf))); + ERETURN (NULL); + } + + phead = content_buf; + while (1) { + pline = acl_mystrline(&phead); + if (pline == NULL) { + break; + } + + if (__xinetd_cfg_parse(xcp, pline) < 0) + ERETURN (NULL); + } + + RETURN (xcp); +} + +const char *acl_xinetd_cfg_get(const ACL_XINETD_CFG_PARSER *xcp, const char *name) +{ + char myname[] = "acl_xinetd_cfg_get"; + ACL_XINETD_NV_PAIR *pair; + int i, n; + + if (xcp == NULL || xcp->nv_array == NULL + || name == NULL || *name == 0) { + acl_msg_error("%s(%d)->%s: input error", + __FILE__, __LINE__, myname); + return (NULL); + } + + n = acl_array_size(xcp->nv_array); + for (i = 0; i < n; i++) { + pair = (ACL_XINETD_NV_PAIR *) acl_array_index(xcp->nv_array, i); + if (pair == NULL) + break; + if (strcasecmp(name, pair->name) == 0) + return (acl_array_index(pair->values, 0)); + } + + return (NULL); +} + +const ACL_ARRAY *acl_xinetd_cfg_get_ex(const ACL_XINETD_CFG_PARSER *xcp, const char *name) +{ + char myname[] = "acl_xinetd_cfg_get"; + ACL_XINETD_NV_PAIR *pair; + int i, n; + + if (xcp == NULL || xcp->nv_array == NULL + || name == NULL || *name == 0) { + acl_msg_error("%s(%d)->%s: input error", + __FILE__, __LINE__, myname); + return (NULL); + } + + n = acl_array_size(xcp->nv_array); + for (i = 0; i < n; i++) { + pair = (ACL_XINETD_NV_PAIR *) acl_array_index(xcp->nv_array, i); + if (pair == NULL) + break; + if (strcasecmp(name, pair->name) == 0) + return (pair->values); + } + + return (NULL); +} + + +int acl_xinetd_cfg_index(const ACL_XINETD_CFG_PARSER *xcp, + int idx, + char **ppname, + char **ppvalue) +{ + ACL_XINETD_NV_PAIR *pair; + + if (xcp == NULL || ppname == NULL || ppvalue == NULL) + return (-1); + + *ppname = NULL; + *ppvalue = NULL; + + if (xcp->nv_array == NULL) + return (-1); + + pair = (ACL_XINETD_NV_PAIR *) acl_array_index(xcp->nv_array, idx); + if (pair == NULL) + return (-1); + + *ppname = pair->name; + *ppvalue = acl_array_index(pair->values, 0); + + return (0); +} + +int acl_xinetd_cfg_size(const ACL_XINETD_CFG_PARSER *xcp) +{ + if (xcp == NULL) + return (-1); + if (xcp->nv_array == NULL) + return (0); + return (acl_array_size(xcp->nv_array)); +} + diff --git a/lib_acl/src/stdlib/configure/acl_xinetd_params.c b/lib_acl/src/stdlib/configure/acl_xinetd_params.c new file mode 100644 index 000000000..0fbab72ef --- /dev/null +++ b/lib_acl/src/stdlib/configure/acl_xinetd_params.c @@ -0,0 +1,205 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include +#include +#include + +#include "stdlib/acl_msg.h" +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_mystring.h" +#include "stdlib/acl_xinetd_cfg.h" + +#endif + +static void __init_conf_int_vars(ACL_CFG_INT_TABLE cit[]) +{ + int i; + + for (i = 0; cit[i].name != 0; i++) + *(cit[i].target) = cit[i].defval; +} + +static void __init_conf_int64_vars(ACL_CFG_INT64_TABLE cit[]) +{ + int i; + + for (i = 0; cit[i].name != 0; i++) + *(cit[i].target) = cit[i].defval; +} + +static void __init_conf_str_vars(ACL_CFG_STR_TABLE cst[]) +{ + int i; + + for (i = 0; cst[i].name != 0; i++) + *(cst[i].target) = acl_mystrdup(cst[i].defval); +} + +static void __init_conf_bool_vars(ACL_CFG_BOOL_TABLE cbt[]) +{ + int i; + + for (i = 0; cbt[i].name != 0; i++) { + if (cbt[i].defval == 0) + *(cbt[i].target) = 0; + else + *(cbt[i].target) = 1; + } +} + +static void __update_conf_int_vars(ACL_CFG_INT_TABLE cit[], + const char *name, + const char *value) +{ + int i; + + for (i = 0; cit[i].name != 0; i++) { + if (strcasecmp(cit[i].name, name) == 0) + *(cit[i].target) = atoi(value); + } +} + +static void __update_conf_int64_vars(ACL_CFG_INT64_TABLE cit[], + const char *name, + const char *value) +{ + int i; + + for (i = 0; cit[i].name != 0; i++) { + if (strcasecmp(cit[i].name, name) == 0) + *(cit[i].target) = acl_atoi64(value); + } +} + +static void __update_conf_str_vars(ACL_CFG_STR_TABLE cst[], + const char *name, + const char *value) +{ + int i; + + for (i = 0; cst[i].name != 0; i++) { + if (strcasecmp(cst[i].name, name) == 0) { + acl_myfree(*(cst[i].target)); + *(cst[i].target) = acl_mystrdup(value); + } + } +} + +static void __update_conf_bool_vars(ACL_CFG_BOOL_TABLE cbt[], + const char *name, + const char *value) +{ + int i, n; + + for (i = 0; cbt[i].name != 0; i++) { + if (strcasecmp(cbt[i].name, name) == 0) { + n = atoi(value); + if (n != 0) + *(cbt[i].target) = 1; + else + *(cbt[i].target) = 0; + } + } +} + +/*--------------------------------------------------------------------------*/ + +void acl_xinetd_params_int_table(ACL_XINETD_CFG_PARSER *cfg, + ACL_CFG_INT_TABLE *table) +{ + int i, n, ret; + char *name, *value; + + if (table == NULL) + return; + + __init_conf_int_vars(table); + + if (cfg == NULL) + return; + + n = acl_xinetd_cfg_size(cfg); + + for (i = 0; i < n; i++) { + ret = acl_xinetd_cfg_index(cfg, i, &name, &value); + if (ret == 0) + __update_conf_int_vars(table, name, value); + } +} + +void acl_xinetd_params_int64_table(ACL_XINETD_CFG_PARSER *cfg, + ACL_CFG_INT64_TABLE *table) +{ + int i, n, ret; + char *name, *value; + + if (table == NULL) + return; + + __init_conf_int64_vars(table); + + if (cfg == NULL) + return; + + n = acl_xinetd_cfg_size(cfg); + + for (i = 0; i < n; i++) { + ret = acl_xinetd_cfg_index(cfg, i, &name, &value); + if (ret == 0) + __update_conf_int64_vars(table, name, value); + } +} + +void acl_xinetd_params_str_table(ACL_XINETD_CFG_PARSER *cfg, + ACL_CFG_STR_TABLE *table) +{ + int i, n, ret; + char *name, *value; + + if (table == NULL) + return; + + __init_conf_str_vars(table); + + if (cfg == NULL) + return; + + n = acl_xinetd_cfg_size(cfg); + + for (i = 0; i < n; i++) { + ret = acl_xinetd_cfg_index(cfg, i, &name, &value); + if (ret == 0) { + __update_conf_str_vars(table, name, value); + } + } +} + +void acl_xinetd_params_bool_table(ACL_XINETD_CFG_PARSER *cfg, + ACL_CFG_BOOL_TABLE *table) +{ + int i, n, ret; + char *name, *value; + + if (table == NULL) + return; + + __init_conf_bool_vars(table); + + if (cfg == NULL) + return; + + n = acl_xinetd_cfg_size(cfg); + + for (i = 0; i < n; i++) { + ret = acl_xinetd_cfg_index(cfg, i, &name, &value); + if (ret == 0) + __update_conf_bool_vars(table, name, value); + } +} diff --git a/lib_acl/src/stdlib/debug/acl_debug_malloc.c b/lib_acl/src/stdlib/debug/acl_debug_malloc.c new file mode 100644 index 000000000..3d11e134b --- /dev/null +++ b/lib_acl/src/stdlib/debug/acl_debug_malloc.c @@ -0,0 +1,270 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include +#include +#include "thread/acl_thread.h" +#include "stdlib/acl_mem_hook.h" +#include "stdlib/acl_debug_malloc.h" + +#endif + +#include "htable.h" + +#ifndef ASSERT +#define ASSERT acl_assert +#endif + +#ifdef ACL_MS_VC +# define SANE_STRDUP _strdup +#else +# define SANE_STRDUP strdup +#endif + +#define DLEN 256 +#define SEP '|' + +struct ACL_DEBUG_MEM { + DEBUG_HTABLE *table; + acl_pthread_mutex_t lock; + FILE *dump_fp; +}; + +static struct ACL_DEBUG_MEM *__debug_mem = NULL; + +#define LOCK do { \ + acl_pthread_mutex_lock(&__debug_mem->lock); \ +} while(0) + +#define UNLOCK do { \ + acl_pthread_mutex_unlock(&__debug_mem->lock); \ +} while(0) + +static void *acl_debug_malloc(const char *filename, int line, size_t size) +{ + char key[256], *value; + void *ptr; + + ASSERT(__debug_mem); + + ptr = malloc(size); + ASSERT(ptr); + snprintf(key, sizeof(key), "0x%lx", (long) ptr); + value = (char*) malloc(DLEN); + snprintf(value, DLEN, "%s%c%d%c%d", filename, SEP, line, SEP, (int) size); + LOCK; + ASSERT(debug_htable_enter(__debug_mem->table, key, value)); + UNLOCK; + return (ptr); +} + +static void *acl_debug_calloc(const char *filename, int line, size_t nmemb, size_t size) +{ + char key[256], *value; + void *ptr; + + ASSERT(__debug_mem); + + ptr = calloc(nmemb, size); + ASSERT(ptr); + snprintf(key, sizeof(key), "0x%lx", (long) ptr); + value = (char*) malloc(DLEN); + ASSERT(value); + snprintf(value, DLEN, "%s%c%d%c%d", filename, SEP, line, SEP, (int) (nmemb * size)); + LOCK; + ASSERT(debug_htable_enter(__debug_mem->table, key, value)); + UNLOCK; + return (ptr); +} + +static void *acl_debug_realloc(const char *filename, int line, void *old, size_t size) +{ + char key[256], *value; + void *ptr; + + ASSERT(__debug_mem); + + snprintf(key, sizeof(key), "0x%lx", (long) old); + LOCK; + value = (char*) debug_htable_find(__debug_mem->table, key); + if (value == NULL) { + fprintf(__debug_mem->dump_fp, "corrumpt%c%s%c%d\n", SEP, filename, SEP, line); + } else { + debug_htable_delete(__debug_mem->table, key, NULL); + free(value); + } + UNLOCK; + + ptr = realloc(old, size); + ASSERT(ptr); + snprintf(key, sizeof(key), "0x%lx", (long) ptr); + value = (char*) malloc(DLEN); + ASSERT(value); + snprintf(value, DLEN, "%s%c%d%c%d", filename, SEP, line, SEP, (int) size); + LOCK; + ASSERT(debug_htable_enter(__debug_mem->table, key, value)); + UNLOCK; + return (ptr); +} + +static char *acl_debug_strdup(const char *filename, int line, const char *str) +{ + char key[256], *value; + size_t size = strlen(str); + char *ptr; + + ASSERT(__debug_mem); + + ptr = SANE_STRDUP(str); + ASSERT(ptr); + snprintf(key, sizeof(key), "0x%lx", (long) ptr); + value = (char*) malloc(DLEN); + ASSERT(value); + snprintf(value, DLEN, "%s%c%d%c%d", filename, SEP, line, SEP, (int) size); + LOCK; + ASSERT(debug_htable_enter(__debug_mem->table, key, value)); + UNLOCK; + return (ptr); +} + +static char *acl_debug_strndup(const char *filename, int line, const char *str, size_t size) +{ + char key[256], *value; + char *ptr; + size_t n = strlen(str); + + ASSERT(__debug_mem); + + size--; + ASSERT(n > 0); + n = n > size ? size : n; + ptr = (char*) malloc(n + 1); + ASSERT(ptr); + memcpy(ptr, str, n); + ptr[n] = 0; + + snprintf(key, sizeof(key), "0x%lx", (long) ptr); + value = (char*) malloc(DLEN); + ASSERT(value); + snprintf(value, DLEN, "%s%c%d%c%d", filename, SEP, line, SEP, (int) n); + LOCK; + ASSERT(debug_htable_enter(__debug_mem->table, key, value)); + UNLOCK; + return (ptr); +} + +static void *acl_debug_memdup(const char *filename, int line, const void *data, size_t size) +{ + char key[256], *value; + void *ptr; + + ASSERT(__debug_mem); + + ptr = malloc(size); + ASSERT(ptr); + memcpy(ptr, data, size); + + snprintf(key, sizeof(key), "0x%lx", (long) ptr); + value = (char*) malloc(DLEN); + ASSERT(value); + snprintf(value, DLEN, "%s%c%d%c%d", filename, SEP, line, SEP, (int) size); + LOCK; + ASSERT(debug_htable_enter(__debug_mem->table, key, value)); + UNLOCK; + return (ptr); +} + +static void acl_debug_free(const char *filename, int line, void *ptr) +{ + char key[256], *value; + + if (ptr == NULL) + return; + ASSERT(__debug_mem); + + snprintf(key, sizeof(key), "0x%lx", (long) ptr); + + LOCK; + value = (char*) debug_htable_find(__debug_mem->table, key); + if (value == NULL) { + fprintf(__debug_mem->dump_fp, "corrupt%c%s%c%d\n", SEP, filename, SEP, line); + } else { + debug_htable_delete(__debug_mem->table, key, NULL); + free(value); + free(ptr); + } + UNLOCK; +} + +static void walk_fn(DEBUG_HTABLE_INFO *info, char *arg acl_unused) +{ + char *value = info->value; + + fprintf(__debug_mem->dump_fp, "leak%c%s\n", SEP, value); +} + +static void __free_fn(char *value) +{ + free(value); +} + +void acl_debug_dump(void) +{ + const char *myname = "acl_debug_dump"; + + if (__debug_mem == NULL) + return; + + fprintf(__debug_mem->dump_fp, "%s(%d): begin scan memory alloc and free\n", myname, __LINE__); + fflush(__debug_mem->dump_fp); + LOCK; + debug_htable_walk(__debug_mem->table, walk_fn, NULL); + UNLOCK; + fprintf(__debug_mem->dump_fp, "%s(%d): scan memory finish\n", myname, __LINE__); + fflush(__debug_mem->dump_fp); +} + +static void debug_dump_atexit(void) +{ + if (__debug_mem == NULL) + return; + + acl_debug_dump(); + debug_htable_free(__debug_mem->table, __free_fn); + fclose(__debug_mem->dump_fp); + acl_pthread_mutex_destroy(&__debug_mem->lock); + free(__debug_mem); + __debug_mem = NULL; +} + +ACL_DEBUG_MEM *acl_debug_malloc_init(ACL_DEBUG_MEM *debug_mem_ptr, const char *dump_file) +{ + if (debug_mem_ptr != NULL) { + __debug_mem = debug_mem_ptr; + } else { + ASSERT(dump_file && *dump_file); + + __debug_mem = (ACL_DEBUG_MEM*) calloc(1, sizeof(ACL_DEBUG_MEM)); + __debug_mem->dump_fp = fopen(dump_file, "wb+"); + ASSERT(__debug_mem->dump_fp); + __debug_mem->table = debug_htable_create(1000); + ASSERT(__debug_mem->table); + acl_pthread_mutex_init(&__debug_mem->lock, NULL); + atexit(debug_dump_atexit); + fprintf(__debug_mem->dump_fp, "begin set mem_hook\n"); + fflush(__debug_mem->dump_fp); + } + + acl_mem_hook(acl_debug_malloc, + acl_debug_calloc, + acl_debug_realloc, + acl_debug_strdup, + acl_debug_strndup, + acl_debug_memdup, + acl_debug_free); + + return (__debug_mem); +} diff --git a/lib_acl/src/stdlib/debug/debug_htable.c b/lib_acl/src/stdlib/debug/debug_htable.c new file mode 100644 index 000000000..aa94fe5f3 --- /dev/null +++ b/lib_acl/src/stdlib/debug/debug_htable.c @@ -0,0 +1,357 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#include +#include +#include + +#endif + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#ifdef ACL_MS_VC +# define SANE_STRDUP _strdup +#else +# define SANE_STRDUP strdup +#endif + +#define MALLOC malloc +#define CALLOC calloc +#define REALLOC realloc +#define FREE free + +#include "htable.h" + +/* Structure of one hash table. */ + +struct DEBUG_HTABLE { + int size; /* length of entries array */ + int init_size; /* length of initial entryies array */ + int used; /* number of entries in table */ + DEBUG_HTABLE_INFO **data; /* entries array, auto-resized */ + DEBUG_HASH_FN hash_fn; /* hash function */ +}; + +/* __def_hash_fn - hash a string */ + +static unsigned __def_hash_fn(const void *buffer, size_t len) +{ + unsigned long h = 0; + unsigned long g; + const unsigned char* s = (const unsigned char *) buffer; + + /* + * From the "Dragon" book by Aho, Sethi and Ullman. + */ + + while (len-- > 0) { + h = (h << 4) + *s++; + if ((g = (h & 0xf0000000)) != 0) { + h ^= (g >> 24); + h ^= g; + } + } + + return (h); +} +/* debug_htable_link - insert element into table */ + +#define debug_htable_link(_table, _element, _n) { \ + DEBUG_HTABLE_INFO **_h = _table->data + _n; \ + _element->prev = 0; \ + if ((_element->next = *_h) != 0) \ + (*_h)->prev = _element; \ + *_h = _element; \ + _table->used++; \ +} + +/* debug_htable_size - allocate and initialize hash table */ + +static int debug_htable_size(DEBUG_HTABLE *table, unsigned size) +{ + DEBUG_HTABLE_INFO **h; + + size |= 1; + + table->data = h = (DEBUG_HTABLE_INFO **) MALLOC(size * sizeof(DEBUG_HTABLE_INFO *)); + if(table->data == NULL) + return(-1); + + table->size = size; + table->used = 0; + + while (size-- > 0) + *h++ = 0; + + return(0); +} + +/* debug_htable_grow - extend existing table */ + +static int debug_htable_grow(DEBUG_HTABLE *table) +{ + int ret; + DEBUG_HTABLE_INFO *ht; + DEBUG_HTABLE_INFO *next; + unsigned old_size = table->size; + DEBUG_HTABLE_INFO **h0 = table->data; + DEBUG_HTABLE_INFO **old_entries = h0; + unsigned n; + + ret = debug_htable_size(table, 2 * old_size); + if (ret < 0) + return(-1); + + while (old_size-- > 0) { + for (ht = *h0++; ht; ht = next) { + next = ht->next; + n = table->hash_fn(ht->key, strlen(ht->key)) % table->size; + debug_htable_link(table, ht, n); + } + } + + FREE(old_entries); + + return(0); +} + +/* debug_htable_create - create initial hash table */ + +DEBUG_HTABLE *debug_htable_create(int size) +{ + DEBUG_HTABLE *table; + int ret; + + table = (DEBUG_HTABLE *) CALLOC(1, sizeof(DEBUG_HTABLE)); + if(table == NULL) + return (NULL); + + table->init_size = size; + + ret = debug_htable_size(table, size < 13 ? 13 : size); + if(ret < 0) { + FREE(table); + return(NULL); + } + + table->hash_fn = __def_hash_fn; + return (table); +} + +#define STREQ(x,y) (x == y || (x[0] == y[0] && strcmp(x,y) == 0)) + +/* debug_htable_enter - enter (key, value) pair */ + +DEBUG_HTABLE_INFO *debug_htable_enter(DEBUG_HTABLE *table, const char *key, char *value) +{ + DEBUG_HTABLE_INFO *ht; + int ret; + unsigned n; + + n = table->hash_fn(key, strlen(key)); + + if (table->used >= table->size) { + ret = debug_htable_grow(table); + if(ret < 0) { + return(NULL); + } + } + + n = n % table->size; + + for (ht = table->data[n]; ht; ht = ht->next) { + if (STREQ(key, ht->key)) { + return (ht); + } + } + + ht = (DEBUG_HTABLE_INFO *) MALLOC(sizeof(DEBUG_HTABLE_INFO)); + if (ht == NULL) { + return(NULL); + } + + ht->key = SANE_STRDUP(key); + if (ht->key == NULL) { + FREE(ht); + return(NULL); + } + + ht->value = value; + debug_htable_link(table, ht, n); + + return (ht); +} + +/* debug_htable_find - lookup value */ + +char *debug_htable_find(DEBUG_HTABLE *table, const char *key) +{ + DEBUG_HTABLE_INFO *ht; + unsigned n; + + if (table == NULL || key == NULL) + return (NULL); + + n = table->hash_fn(key, strlen(key)); + + n = n % table->size; + + for (ht = table->data[n]; ht; ht = ht->next) { + if (STREQ(key, ht->key)) { + return (ht->value); + } + } + + return (NULL); +} + +/* debug_htable_locate - lookup entry */ + +DEBUG_HTABLE_INFO *debug_htable_locate(DEBUG_HTABLE *table, const char *key) +{ + DEBUG_HTABLE_INFO *ht; + unsigned n; + + if(table == NULL || key == NULL) + return (NULL); + + n = table->hash_fn(key, strlen(key)); + + n = n % table->size; + + for (ht = table->data[n]; ht; ht = ht->next) { + if (STREQ(key, ht->key)) { + return (ht); + } + } + + return (NULL); +} + +/* debug_htable_delete - delete one entry */ + +int debug_htable_delete(DEBUG_HTABLE *table, const char *key, void (*free_fn) (char *)) +{ + if (table && key) { + DEBUG_HTABLE_INFO *ht; + unsigned n = table->hash_fn(key, strlen(key)); + DEBUG_HTABLE_INFO **h; + + n = n % table->size; + + h = table->data + n; + for (ht = *h; ht; ht = ht->next) { + if (STREQ(key, ht->key)) { + if (ht->next) + ht->next->prev = ht->prev; + if (ht->prev) + ht->prev->next = ht->next; + else + *h = ht->next; + table->used--; + FREE(ht->key); + if (free_fn && ht->value) + (*free_fn) (ht->value); + FREE(ht); + return(0); + } + } + } + + return(-1); +} + +/* debug_htable_free - destroy hash table */ + +void debug_htable_free(DEBUG_HTABLE *table, void (*free_fn) (char *)) +{ + if (table) { + unsigned i = table->size; + DEBUG_HTABLE_INFO *ht; + DEBUG_HTABLE_INFO *next; + DEBUG_HTABLE_INFO **h = table->data; + + while (i-- > 0) { + for (ht = *h++; ht; ht = next) { + next = ht->next; + FREE(ht->key); + if (free_fn && ht->value) + (*free_fn) (ht->value); + FREE(ht); + } + } + FREE(table->data); + table->data = 0; + FREE(table); + } +} + +int debug_htable_reset(DEBUG_HTABLE *table, void (*free_fn) (char *)) +{ + if (table) { + unsigned i = table->size; + DEBUG_HTABLE_INFO *ht; + DEBUG_HTABLE_INFO *next; + DEBUG_HTABLE_INFO **h; + int ret; + + h = table->data; + + while (i-- > 0) { + for (ht = *h++; ht; ht = next) { + next = ht->next; + FREE(ht->key); + if (free_fn && ht->value) + (*free_fn) (ht->value); + FREE(ht); + } + } + FREE(table->data); + table->data = 0; + + ret = debug_htable_size(table, table->init_size < 13 ? 13 : table->init_size); + return (ret); + } + + return (-1); +} + +/* debug_htable_walk - iterate over hash table */ + +void debug_htable_walk(DEBUG_HTABLE *table, void (*action)(DEBUG_HTABLE_INFO *, char *), char *ptr) +{ + if (table) { + unsigned i = table->size; + DEBUG_HTABLE_INFO **h = table->data; + DEBUG_HTABLE_INFO *ht; + + while (i-- > 0) + for (ht = *h++; ht; ht = ht->next) + (*action) (ht, ptr); + } +} + +/* debug_htable_list - list all table members */ + +DEBUG_HTABLE_INFO **debug_htable_list(const DEBUG_HTABLE *table) +{ + DEBUG_HTABLE_INFO **list; + DEBUG_HTABLE_INFO *member; + int count = 0; + int i; + + if (table != 0) { + list = (DEBUG_HTABLE_INFO **) MALLOC(sizeof(*list) * (table->used + 1)); + for (i = 0; i < table->size; i++) + for (member = table->data[i]; member != 0; member = member->next) + list[count++] = member; + } else { + list = (DEBUG_HTABLE_INFO **) MALLOC(sizeof(*list)); + } + list[count] = 0; + return (list); +} diff --git a/lib_acl/src/stdlib/debug/htable.h b/lib_acl/src/stdlib/debug/htable.h new file mode 100644 index 000000000..6d54cacea --- /dev/null +++ b/lib_acl/src/stdlib/debug/htable.h @@ -0,0 +1,114 @@ + +#ifndef _DEBUG_HTABLE_H_INCLUDED_ +#define _DEBUG_HTABLE_H_INCLUDED_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_define.h" + +/*--------------------------------------------------------------------------*/ + +/* Structure of one hash table entry. */ + +/** + * 哈希函数类型定义 + * @param buffer 需要被哈希的字符串 + * @param len s 的长度 + */ +typedef unsigned (*DEBUG_HASH_FN)(const void *buffer, size_t len); + +/** + * 哈希表对象结构句柄, 该类型定义在 htable.c 中是为了保护内部成员变量 + */ +typedef struct DEBUG_HTABLE DEBUG_HTABLE; + +/* 哈希表中每一个哈希项的存储信息类型 */ +typedef struct DEBUG_HTABLE_INFO { + char *key; /* lookup key */ + char *value; /* associated value */ + struct DEBUG_HTABLE_INFO *next; /* colliding entry */ + struct DEBUG_HTABLE_INFO *prev; /* colliding entry */ +} DEBUG_HTABLE_INFO; + +/** + * 建立哈希表 + * @param size 哈希表长度 + * @return 所建哈希表的头指针或为空(这时表示出了严重的错误, 主要是内存分配问题) + */ +DEBUG_HTABLE *debug_htable_create(int size); + +/** + * 往哈希表里添加新的项 + * @param table 哈希表指针 + * @param key 键, 在函数内部会复制此 key 键 + * @param value 用户自己的特定数据项(可以由类型硬转化而来, 但是此数据项必须不能堆栈变量) + * @return 所分配的哈希表项的指针, == NULL: 表示内部分分配内存出错, 为严重的错误 + */ +DEBUG_HTABLE_INFO *debug_htable_enter(DEBUG_HTABLE *table, const char *key, char *value); + +/** + * 由所给的 key 键查寻某一特定哈希项 + * @param table 哈希表指针 + * @param key 键 + * @return 不为空指针: 表示查到了对应于 key 键的哈希项 + * 为空: 表示未查到对应于 key 键的哈希项 + */ +DEBUG_HTABLE_INFO *debug_htable_locate(DEBUG_HTABLE *table, const char *key); + +/** + * 由所给的 key 键查寻用户的数据项 + * @param table 哈希表指针 + * @param key 键 + * @return 不为空: 表示查到了对应于 key 键的数据项, 用户可以根据用户自己的数据类型进行转换 + * 为空: 表示未查到对应于 key 键的数据项 + */ +char *debug_htable_find(DEBUG_HTABLE *table, const char *key); + +/** + * 功能: 根据所给的 key 键删除某一哈希项 + * @param table 哈希表指针 + * @param key 键 + * @param free_fn 如果该函数指针不为空并且找到了对应于 key 键的数据项, 则先调用用户 + * 所提供的析构函数做一些清尾工作, 然后再释放该哈希项 + * @return 0: 成功; -1: 未找到该 key 键 + */ +int debug_htable_delete(DEBUG_HTABLE *table, const char *key, void (*free_fn) (char *)); + +/** + * 释放整个哈希表 + * @param table 哈希表指针 + * @param free_fn 如果该指针不为空则对哈希表中的每一项哈希项先用该函数做清尾工作, 然后再释放 + */ +void debug_htable_free(DEBUG_HTABLE *table, void (*free_fn) (char *)); + +/** + * 重置哈希表, 该函数会释放哈希表中的所有内容项, 并重新初始化 + * @param table 哈希表指针 + * @param free_fn 如果该指针不为空则对哈希表中的每一项哈希项先用该函数做清尾工作, 然后再释放 + * @return 是否重置成功. 0: OK; < 0: error. + */ +int debug_htable_reset(DEBUG_HTABLE *table, void (*free_fn) (char *)); + +/** + * 对哈希表中的每一项哈希项进行处理 + * @param table 哈希表指针 + * @param walk_fn 处理每一项哈希项的函数指针, 不能为空 + * @param arg 用户自己类型的数据 + */ +void debug_htable_walk(DEBUG_HTABLE *table, void (*walk_fn) (DEBUG_HTABLE_INFO *, char *), char *arg); + +/** + * 将哈希表里的所有项组合成一个链表 + * @param table 哈希表 + * @return 不为空: 链表指针; 为空: 表示该哈希表里没有哈希项 + */ +DEBUG_HTABLE_INFO **debug_htable_list(const DEBUG_HTABLE *table); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/src/stdlib/filedir/acl_dir.c b/lib_acl/src/stdlib/filedir/acl_dir.c new file mode 100644 index 000000000..02aa4aa56 --- /dev/null +++ b/lib_acl/src/stdlib/filedir/acl_dir.c @@ -0,0 +1,263 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#endif /* ACL_PREPARE_COMPILE */ + +#ifdef ACL_MS_VC + +#include +#include +#include +#include +#include +#include +#include "stdlib/acl_msg.h" +#include "stdlib/acl_dir.h" + +#define DIRMAGIC 0xddaa + +#if defined (_UNICODE) +#define LPSTR LPWSTR +#else +#define LPSTR LPCSTR +#endif + +/*---------------------------------------------------------------------- +Name opendir, wopendir - open a directory stream + +Usage #include +DIR *opendir(const char *dirname); +wDIR *opendir(const wchar_t *dirname); + +Related +functions usage struct dirent *readdir(DIR *dirp); +void rewinddir(DIR *dirp); +int closedir(DIR *dirp); + +Prototype in dirent.h + +Description The opendir() and wopendir() functions open a directory +stream for reading. The name of the directory to read +is dirname. The stream is set to read the first entry +in the directory. + +Return value On a successful open, opendir() returns a pointer to +an object of type DIR. On an error, opendir() returns +NULL and sets error as follows: + +ENOENT The directory does not exist. +ENOMEM Not enough memory to allocate a DIR object. + +*---------------------------------------------------------------------*/ + +_tDIR * _topendir(const _TCHAR *dirname) +{ + _TCHAR *name; + int len; + _tDIR *dir; + HANDLE h; + + /* Allocate space for a copy of the directory name, plus + * room for the "*.*" we will concatenate to the end. + */ + len = _tcslen(dirname); + if ((name = malloc((len+5) * sizeof(_TCHAR))) == NULL) { + acl_set_error(ENOMEM); + return (NULL); + } + _tcscpy(name, dirname); + if (len-- && name[len] != _TEXT(':') && name[len] != _TEXT('\\') && name[len] != _TEXT('/')) + _tcscat(name,_TEXT("\\*.*")); + else + _tcscat(name,_TEXT("*.*")); + + /* Allocate space for a DIR structure. + */ + if ((dir = malloc(sizeof(_tDIR))) == NULL) { + acl_set_error(ENOMEM); + free(name); + return (NULL); + } + + /* Search for the first file to see if the directory exists, + * and to obtain directory handle for future FindNextFile() calls. + */ + if ((h = FindFirstFile((LPSTR)name, + (LPWIN32_FIND_DATA)&dir->_d_buf[0])) == (HANDLE)-1) { + free(name); + free(dir); + acl_set_error(ENOTDIR); /* set error */ + return (NULL); + } + + /* Everything is OK. Save information in the DIR structure, return it. + */ + dir->_d_nfiles = 1; + dir->_d_hdir = (unsigned long)h; + dir->_d_dirname = name; + dir->_d_magic = DIRMAGIC; + return dir; +} + +/*---------------------------------------------------------------------- +Name rewinddir, wrewinddir - rewind a directory stream + +Usage #include +void rewinddir(DIR *dirp); +void wrewinddir(wDIR *dirp); + +Related +functions usage struct dirent *readdir(DIR *dirp); +DIR *opendir(const char *dirname); +int closedir(DIR *dirp); + +Prototype in dirent.h + +Description The rewinddir() and wrewinddir() functions reset the +directory stream dirp to the first entry in the directory. + +Return value The rewinddir() function does not return a value. + +*---------------------------------------------------------------------*/ + +void _trewinddir(_tDIR *dir) +{ + HANDLE h; + + /* Verify the handle. + */ + if (dir->_d_magic != DIRMAGIC) + return; + + /* Close the handle, start searching at the beginning with a new + * handle + */ + FindClose((HANDLE)dir->_d_hdir); + + if ((h = FindFirstFile((LPSTR)dir->_d_dirname, + (LPWIN32_FIND_DATA)&dir->_d_buf[0])) != (HANDLE)-1) { + dir->_d_hdir = (unsigned long)h; + dir->_d_nfiles = 1; + } +} + + +/*---------------------------------------------------------------------- +Name readdir, wreaddir - read directory entry from a directory stream + +Usage #include +struct dirent *readdir(DIR *dirp); +struct dirent *wreaddir(wDIR *dirp); +Related +functions usage void rewinddir(DIR *dirp); +DIR *opendir(const char *dirname); +int closedir(DIR *dirp); + +Prototype in dirent.h + +Description The readdir() and wreaddir functions read the directory +entry at the current position in the directory stream dirp, +and advances the directory stream position to the next entry. +The directory entry is an object of type 'struct dirent' +that contains the member +char d_name[] +which is an array of characters containing the null-terminated +filename. + +The readdir() function reads directory entries for all files, +including directories. On DOS, it also reads directory +entries for system and hidden files. It does not read +volume labels or unused directory entries. + +Return value On a successful read, readdir() returns a pointer +to an object of type 'struct direct'. This structure +will be overwritten by subsequent operations on the +same directory stream. It will not be overwritten +by operations on other directory streams. + +When the end of the directory is reached, readdir() +returns NULL but does not set error. + +On an error, readdir() returns NULL and sets error: + +EBADF The dirp parameter does not point to a valid +open directory stream. + +*---------------------------------------------------------------------*/ + +struct _tdirent * _treaddir(_tDIR *dir) +{ + WIN32_FIND_DATA *ff; + + /* Verify the handle. + */ + if (dir->_d_magic != DIRMAGIC) { + acl_set_error(EBADF); + return (NULL); + } + + /* If all files in the buffer have been returned, find some more files. + */ + if (dir->_d_nfiles == 0) { + if (FindNextFile((HANDLE)dir->_d_hdir, + (LPWIN32_FIND_DATA)&dir->_d_buf[0]) != TRUE) + return (NULL); + } + else + dir->_d_nfiles = 0; + + /* Return the filename of the current file in the buffer. + */ + ff = (WIN32_FIND_DATA *)(dir->_d_buf); + return ((struct _tdirent *)&ff->cFileName[0]); +} + +/*---------------------------------------------------------------------- +Name closedir, wclosedir - close directory stream + +Usage #include +int closedir(DIR *dirp); +int wclosedir(wDIR *dirp); + +Related +functions usage void rewinddir(DIR *dirp); +struct dirent *readdir(DIR *dirp); +DIR *opendir(const char *dirname); + +Prototype in dirent.h + +Description The closedir() and wclosedir() functions close the +directory stream dirp. Subsequently, dirp will not +refer to a valid directory stream. + +Return value On a successful close, closedir() returns 0. +On an error, closedir() returns -1 and sets error: + +EBADF The dirp parameter does not point to a valid +open directory stream. + +*---------------------------------------------------------------------*/ + +int _tclosedir(_tDIR *dir) +{ + /* Verify the handle. + */ + if (dir == NULL || dir->_d_magic != DIRMAGIC) { + acl_set_error(EBADF); + return (-1); + } + + dir->_d_magic = 0; /* prevent accidental use after closing */ + FindClose((HANDLE)dir->_d_hdir);/* close directory handle */ + free(dir->_d_dirname); /* free directory name */ + free(dir); /* free directory structure */ + return 0; +} + +#endif /* ACL_MS_VC */ diff --git a/lib_acl/src/stdlib/filedir/acl_fhandle.c b/lib_acl/src/stdlib/filedir/acl_fhandle.c new file mode 100644 index 000000000..044319cd1 --- /dev/null +++ b/lib_acl/src/stdlib/filedir/acl_fhandle.c @@ -0,0 +1,474 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include /* for S_IREAD */ + +#include "stdlib/acl_debug.h" +#include "stdlib/acl_msg.h" +#include "stdlib/acl_htable.h" +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_mystring.h" +#include "stdlib/acl_sane_basename.h" +#include "stdlib/acl_make_dirs.h" +#include "stdlib/acl_myflock.h" +#include "stdlib/acl_fhandle.h" + +# ifdef ACL_UNIX +# include +extern int pthread_mutexattr_settype (pthread_mutexattr_t *__attr, int __kind); +# endif +#else +# ifdef ACL_UNIX +# include +extern int pthread_mutexattr_settype (pthread_mutexattr_t *__attr, int __kind); +# endif +#endif /* ACL_PREPARE_COMPILE */ + +#define PATH ACL_VSTREAM_PATH +#define STR acl_vstring_str + +static int __cache_max_size = 100; +static int __debug_section = 0; +static int __flags = 0; +static ACL_RING __fhandle_free_list; +static ACL_HTABLE *__fhandle_table = NULL; +static acl_pthread_mutex_t __fhandle_mutex; + +#define MUTEX_LOCK(mutex) acl_thread_mutex_lock((mutex)) +#define MUTEX_UNLOCK(mutex) acl_thread_mutex_unlock((mutex)) + +#if 1 + +/* 可嵌套式加锁 */ + +#define LOCK_FS do { \ + int __ret; \ + if ((__flags & ACL_FHANDLE_F_LOCK ) != 0 && (__ret = MUTEX_LOCK(&__fhandle_mutex)) != 0) \ + acl_msg_fatal("%s: lock fs error(%d)", myname, __ret); \ +} while (0) + +#define UNLOCK_FS do { \ + int __ret; \ + if ((__flags & ACL_FHANDLE_F_LOCK ) != 0 && (__ret = MUTEX_UNLOCK(&__fhandle_mutex)) != 0) \ + acl_msg_fatal("%s: unlock fs error(%d)", myname, __ret); \ +} while (0) + +#else +#define LOCK_FS +#define UNLOCK_FS +#endif + +static ACL_FHANDLE *__fhandle_alloc(size_t size, unsigned int oflags) +{ + const char *myname = "__fhandle_alloc"; + ACL_FHANDLE *fs; + + if (size < sizeof(ACL_FHANDLE)) + acl_msg_fatal("%s(%d): size(%d) < ACL_FHANDLE's size(%d)", + myname, __LINE__, (int) size, (int) sizeof(ACL_FHANDLE)); + + fs = (ACL_FHANDLE *) acl_mycalloc(1, size); + fs->tid = acl_pthread_self(); + fs->size = size; + fs->oflags = oflags; + acl_ring_init(&fs->ring); + if ((oflags & ACL_FHANDLE_O_MLOCK) != 0) { +#ifdef ACL_UNIX + acl_pthread_mutexattr_t attr; + + pthread_mutexattr_init(&attr); +# if defined(ACL_FREEBSD) || defined(ACL_SUNOS5) || defined(ACL_MACOSX) + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); +# else + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP); +# endif + pthread_mutex_init(&fs->mutex, &attr); +#else + acl_pthread_mutex_init(&fs->mutex, NULL); +#endif + } + + return (fs); +} + +static void __fhandle_free(ACL_FHANDLE *fs) +{ + if (fs->fp) + acl_vstream_fclose(fs->fp); /* 文件锁自动释放 */ + if ((fs->oflags & ACL_FHANDLE_O_MLOCK) != 0) + acl_pthread_mutex_destroy(&fs->mutex); + acl_myfree(fs); +} + +#include + +ACL_FHANDLE *acl_fhandle_open(size_t size, unsigned int oflags, + const char *file_path, + int (*on_open)(ACL_FHANDLE*, void*), void *open_arg, + void (*on_close)(ACL_FHANDLE*)) +{ + const char *myname = "acl_fhandle_open"; + char *ptr; + ACL_FHANDLE *fs; + unsigned int fopen_flags = O_RDWR | O_CREAT; + + LOCK_FS; + + /* 先查询缓存中是否存在 */ + fs = (ACL_FHANDLE *) acl_htable_find(__fhandle_table, file_path); + if (fs) { + fs->nrefer++; /* 增加引用计数,以防止被多次引用时提前释放 */ + /* 如果该缓存对象处于延迟关闭队列中,则需要从中删除 */ + if (fs->when_free > 0) { + /* 从延迟关闭缓冲中去除 */ + acl_ring_detach(&fs->ring); + fs->when_free = 0; + } + + UNLOCK_FS; + + /* 是否打开后自动加锁 */ + if ((oflags & ACL_FHANDLE_O_EXCL) != 0) + acl_fhandle_lock(fs); + + return (fs); + } + + /* sanity check */ + size = size < sizeof(ACL_FHANDLE) ? sizeof(ACL_FHANDLE) : size; + + /* 分配新的缓存对象 */ + fs = __fhandle_alloc(size, oflags); + fs->on_close = on_close; + + /* 是否自动检查并创建不存在的目录 */ + if ((oflags & ACL_FHANDLE_O_MKDIR) != 0) { + ACL_VSTRING *tmpbuf = acl_vstring_alloc(256); + /* 必须保证目录存在,如果不存在则强行创建该目录 */ + ptr = acl_sane_dirname(tmpbuf, file_path); + if (ptr && strcmp(ptr, ".") != 0) + acl_make_dirs(ptr, 0700); + acl_vstring_free(tmpbuf); + } + +#ifdef ACL_UNUX + if ((oflags & ACL_FHANDLE_O_NOATIME) != 0) + fopen_flags |= O_NOATIME; + if ((oflags & ACL_FHANDLE_O_DIRECT) != 0) + fopen_flags |= O_DIRECT; + if ((oflags & ACL_FHANDLE_O_SYNC) != 0) + fopen_flags |= O_SYNC; +#endif + + /* 创建新文件 */ + fs->fp = acl_vstream_fopen(file_path, fopen_flags, 0600, 4096); + if (fs->fp == NULL) { + UNLOCK_FS; + acl_msg_error("%s(%d): fopen %s error(%s)", myname, __LINE__, + file_path, acl_last_serror()); + __fhandle_free(fs); + return (NULL); + } + + fs->fsize = acl_vstream_fsize(fs->fp); + if (fs->fsize == -1) { + UNLOCK_FS; + acl_msg_error("%s(%d): get %s size error(%s)", + myname, __LINE__, PATH(fs->fp), acl_last_serror()); + __fhandle_free(fs); + return (NULL); + } else if (on_open) { + /* maybe first open, need init the store */ + if (on_open(fs, open_arg) < 0) { + acl_msg_warn("%s(%d): on_create return < 0 for %s", + myname, __LINE__, PATH(fs->fp)); + UNLOCK_FS; + __fhandle_free(fs); + return (NULL); + } + } + + if (acl_htable_enter(__fhandle_table, file_path, fs) == NULL) + acl_msg_fatal("%s(%d): add fpath(%s) to htable error(%s)", + myname, __LINE__, PATH(fs->fp), acl_last_serror()); + fs->nrefer++; + + UNLOCK_FS; + + /* 是否打开后自动加锁 */ + if ((oflags & ACL_FHANDLE_O_EXCL) != 0) + acl_fhandle_lock(fs); + + return (fs); +} + +/* 真正关闭并释放存储对象 */ + +static void __fhandle_close(ACL_FHANDLE *fs) +{ + const char *myname = "__fhandle_close"; + + if (fs->nrefer != 0) + acl_msg_fatal("%s: nrefer: %d != 0", myname, fs->nrefer); + + if (fs->on_close) + fs->on_close(fs); + + acl_ring_detach(&fs->ring); + (void) acl_htable_delete(__fhandle_table, PATH(fs->fp), NULL); + + __fhandle_free(fs); +} + +void acl_fhandle_close(ACL_FHANDLE *fs, int delay_timeout) +{ + const char *myname = "acl_fhandle_close"; + time_t now; + ACL_RING *iter, *iter_next; + ACL_RING_ITER ring_iter; + + LOCK_FS; + + fs->nrefer--; + if (fs->nrefer == 0) { + ACL_FHANDLE *fhandle_iter; + + if (delay_timeout <= 0) { + __fhandle_close(fs); + if ((fs->status & ACL_FHANDLE_S_MUTEX_ON) != 0) + acl_fhandle_unlock(fs); + UNLOCK_FS; + return; + } + + fs->when_free = time(NULL) + delay_timeout; /* 默认的关闭时间截 */ + iter = &__fhandle_free_list; + + /* 数据链的存储方式为,由头 --> 尾,则数据由 旧 --> 新, 即: 时间值 小 --> 大 */ + + /* 从尾部开始扫描,即扫描时间过期值由大向小的方向扫描所有对象,找到 + * 过期时间值比当前对象的时间值小或相等的第一个对象 + */ + acl_ring_foreach_reverse(ring_iter, &__fhandle_free_list) { + fhandle_iter = acl_ring_to_appl(ring_iter.ptr, ACL_FHANDLE, ring); + if (fs->when_free >= fhandle_iter->when_free) { + iter = ring_iter.ptr; + break; + } + } + /* 放在比扫描对象后从而保持数据链的大小顺序不变 */ + acl_ring_append(iter, &fs->ring); + + /* 解锁 */ + if ((fs->status & ACL_FHANDLE_S_MUTEX_ON) != 0) + acl_fhandle_unlock(fs); + + /* 由头部扫描的方法效率较低 + * 从头部开始扫描,即扫描时间过期值由小向大的方向扫描所有对象,找到 + * 过期时间值比当前对象的过期时间大或相等的第一个对象 + * acl_foreach_ring(iter_next, &__fhandle_free_list) { + * fhandle_iter = ACL_RING_TO_APPL(iter_next, ACL_FHANDLE, ring); + * if (fs->when_free <= fhandle_iter->when_free) { + * iter = iter_next; + * break; + * } + * } + * 将当前对象放在扫描对象的前面从而保持数据链的大小顺序不变 + * acl_ring_prepend(iter, &fs->ring); + */ + + if (acl_ring_size(&__fhandle_free_list) > __cache_max_size) { + /* 弹出最老的对象进行释放 */ + iter = acl_ring_pop_head(&__fhandle_free_list); + fs = ACL_RING_TO_APPL(iter, ACL_FHANDLE, ring); + if (fs->nrefer != 0) + acl_msg_fatal("%s: fpath: nrefer: %d != 0, list size: %d", + myname, fs->nrefer, acl_ring_size(&__fhandle_free_list)); + if ((fs->status & ACL_FHANDLE_S_MUTEX_ON) != 0) + acl_fhandle_unlock(fs); + __fhandle_close(fs); + } + } else if ((fs->status & ACL_FHANDLE_S_MUTEX_ON) != 0) + acl_fhandle_unlock(fs); + + (void) time(&now); + + /* 因为数据链中的对象的过期时间值由头 --> 尾是按由 小 --> 大的顺序存储的, + * 所以头部的数据应最先过期; 释放掉过期的延期关闭的缓存对象 + */ + for (iter = acl_ring_succ(&__fhandle_free_list); iter != &__fhandle_free_list;) { + fs = ACL_RING_TO_APPL(iter, ACL_FHANDLE, ring); + if (fs->when_free > now) + break; + if (fs->nrefer > 0) { + acl_msg_warn("%s: fs(%s)'s nrefer(%d) > 0, which in free list", + myname, PATH(fs->fp), fs->nrefer); + iter = acl_ring_succ(iter); + continue; + } + iter_next = acl_ring_succ(iter); + if (fs->nrefer == 0) { + acl_debug(__debug_section, 2) + ("%s: fpath: %s, when_free: %ld, now: %ld", + myname, PATH(fs->fp), fs->when_free, now); + __fhandle_close(fs); + } + iter = iter_next; + } + + UNLOCK_FS; +} + +void acl_fhandle_lock(ACL_FHANDLE *fs) +{ + const char *myname = "acl_fhandle_lock"; +#ifdef ACL_MS_WINDOWS + unsigned long tid = acl_pthread_self(); +#else + acl_pthread_t tid = acl_pthread_self(); +#endif + + if ((fs->oflags & ACL_FHANDLE_O_MLOCK) == 0) { + acl_msg_error("%s(%d): ACL_FHANDLE_O_MLOCK not set", myname, __LINE__); + return; + } + /* 加线程锁,同时允许同一线程可以对同一锁加锁多次 */ + MUTEX_LOCK(&fs->mutex); + fs->status |= ACL_FHANDLE_S_MUTEX_ON; + fs->lock_mutex_tid = tid; + + /* 加进程文件锁以防止不同进程同时访问 */ + if ((fs->oflags & ACL_FHANDLE_O_FLOCK) + && (fs->status & ACL_FHANDLE_S_FLOCK_ON) == 0) + { + if (acl_myflock(ACL_VSTREAM_FILE(fs->fp), + ACL_MYFLOCK_STYLE_FCNTL, ACL_MYFLOCK_OP_EXCLUSIVE) == -1) + { + acl_msg_fatal("%s: lock file(%s) error(%s)", + myname, PATH(fs->fp), acl_last_serror()); + } + fs->status |= ACL_FHANDLE_S_FLOCK_ON; + } +} + +void acl_fhandle_unlock(ACL_FHANDLE *fs) +{ + const char *myname = "acl_fhandle_unlock"; + + /* sanity check */ + + if ((fs->oflags & ACL_FHANDLE_O_MLOCK) == 0) + return; + + if (fs->lock_mutex_tid != acl_pthread_self()) { + acl_msg_warn("%s(%d): thread not locked mutex for %s", + myname, __LINE__, PATH(fs->fp)); + return; + } else if ((fs->status & ACL_FHANDLE_S_MUTEX_ON) == 0) { + acl_msg_warn("%s(%d): thread not locked mutex for %s", + myname, __LINE__, PATH(fs->fp)); + return; + } + + /* xxx: 必须清除线程锁的所有者 */ +#ifdef ACL_MS_WINDOWS + fs->lock_mutex_tid = (unsigned int) -1; +#else + fs->lock_mutex_tid = (acl_pthread_t) -1; +#endif + fs->status &= ~ACL_FHANDLE_S_MUTEX_ON; + + if ((fs->status & ACL_FHANDLE_S_FLOCK_ON) != 0) { + fs->status &= ~ACL_FHANDLE_S_FLOCK_ON; + + if (acl_myflock(ACL_VSTREAM_FILE(fs->fp), + ACL_MYFLOCK_STYLE_FCNTL, ACL_MYFLOCK_OP_NONE) == -1) + { + acl_msg_fatal("%s: unlock file(%s) error(%s)", + myname, PATH(fs->fp), acl_last_serror()); + } + } + + if (MUTEX_UNLOCK(&fs->mutex) != 0) + acl_msg_fatal("%s: unlock mutex for %s error(%s)", + myname, PATH(fs->fp), acl_last_serror()); +} + +void acl_fhandle_init(int cache_size, int debug_section, unsigned int flags) +{ + const char *myname = "acl_fhandle_init"; +#ifdef ACL_UNIX + acl_pthread_mutexattr_t attr; +#endif + + if (__fhandle_table != NULL) { + acl_msg_warn("%s(%d): __fhandle_table not null", myname, __LINE__); + return; + } + + __cache_max_size = cache_size > 0 ? cache_size : 100; + __debug_section = debug_section; +#ifdef ACL_MS_WINDOWS + /* win32 下文件名及路径名是不区分大小写的,所以基于文件路径为键的哈希表 + * 需要设置为自动转为小写键值的情况 + */ + __fhandle_table = acl_htable_create(100, ACL_HTABLE_FLAG_KEY_LOWER); +#else + __fhandle_table = acl_htable_create(100, 0); +#endif + __flags = flags; + acl_ring_init(&__fhandle_free_list); + +#ifdef ACL_UNIX + pthread_mutexattr_init(&attr); +# if defined(ACL_FREEBSD) || defined(ACL_SUNOS5) || defined(ACL_MACOSX) + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); +# else + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP); +# endif + pthread_mutex_init(&__fhandle_mutex, &attr); +#else + acl_pthread_mutex_init(&__fhandle_mutex, NULL); +#endif +} + +static void __fhandle_close2(ACL_FHANDLE *fs) +{ + const char *myname = "__fhandle_close2"; + + if (fs->nrefer != 0) + acl_msg_warn("%s: nrefer: %d != 0, name: %s", + myname, fs->nrefer, ACL_FHANDLE_PATH(fs)); + + if (fs->on_close) + fs->on_close(fs); + + acl_ring_detach(&fs->ring); + + if ((fs->status & ACL_FHANDLE_S_MUTEX_ON) != 0) { + acl_msg_warn("%s: fpath: %s, mutex not release yet", + myname, PATH(fs->fp)); + MUTEX_UNLOCK(&fs->mutex); + } + fs->status &= ~ACL_FHANDLE_S_MUTEX_ON; + + __fhandle_free(fs); +} + +void acl_fhandle_end() +{ + const char *myname = "acl_fhandle_end"; + + acl_msg_info("%s(%d): close all ACL_FHANDLE now", myname, __LINE__); + + if (__fhandle_table == NULL) { + acl_msg_warn("%s(%d): __fhandle_table null", myname, __LINE__); + return; + } + acl_htable_free(__fhandle_table, (void (*)(void*)) __fhandle_close2); + acl_pthread_mutex_destroy(&__fhandle_mutex); + __fhandle_table = NULL; +} diff --git a/lib_acl/src/stdlib/filedir/acl_make_dirs.c b/lib_acl/src/stdlib/filedir/acl_make_dirs.c new file mode 100644 index 000000000..cb5b4d0ac --- /dev/null +++ b/lib_acl/src/stdlib/filedir/acl_make_dirs.c @@ -0,0 +1,214 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +/* System library. */ +#include +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +/* Utility library. */ + +#include "stdlib/acl_msg.h" +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_make_dirs.h" + +#endif + +#include "dir_sys_patch.h" + +/* acl_make_dirs - create directory hierarchy */ + +#ifdef ACL_UNIX + +int acl_make_dirs(const char *path, int perms) +{ + char *saved_path; + unsigned char *cp; + int saved_ch; + struct stat st; + int ret; +#if 0 + mode_t saved_mode = 0; +#endif + + /* + * Initialize. Make a copy of the path that we can safely clobber. + */ + cp = (unsigned char *) (saved_path = acl_mystrdup(path)); + + /* + * I didn't like the 4.4BSD "mkdir -p" implementation, but coming up + * with my own took a day, spread out over several days. + */ +#define SKIP_WHILE(cond, ptr) { while(*ptr && (cond)) ptr++; } + + SKIP_WHILE(*cp == '/', cp); + + for (;;) { + SKIP_WHILE(*cp != '/', cp); + if ((saved_ch = *cp) != 0) + *cp = 0; + if ((ret = stat(saved_path, &st)) >= 0) { + if (!S_ISDIR(st.st_mode)) { + acl_set_error(ENOTDIR); + ret = -1; + break; + } +#if 0 + saved_mode = st.st_mode; +#endif + } else { + if (acl_last_error() != ENOENT) + break; + + /* + * mkdir(foo) fails with EEXIST if foo is a symlink. + */ +#if 0 + + /* + * Create a new directory. Unfortunately, mkdir(2) + * has no equivalent of open(2)'s O_CREAT|O_EXCL + * safety net, so we must require that the parent + * directory is not world writable. + * Detecting a lost race condition after the fact is + * not sufficient, as an attacker could repeat the + * attack and add one directory level at a time. + */ + if (saved_mode & S_IWOTH) { + acl_msg_warn("refusing to mkdir %s: " + "parent directory is " + "writable by everyone", + saved_path); + acl_set_error(EPERM); + ret = -1; + break; + } +#endif + + if ((ret = mkdir(saved_path, perms)) < 0) { + if (acl_last_error() != EEXIST) + break; + /* Race condition? */ + if ((ret = stat(saved_path, &st)) < 0) + break; + if (!S_ISDIR(st.st_mode)) { + acl_set_error(ENOTDIR); + ret = -1; + break; + } + } + } + if (saved_ch != 0) + *cp = saved_ch; + SKIP_WHILE(*cp == '/', cp); + if (*cp == 0) + break; + } + + /* + * Cleanup. + */ + acl_myfree(saved_path); + return (ret); +} + +#elif defined(ACL_MS_WINDOWS) + +int acl_make_dirs(const char *path, int perms) +{ + const char *myname = "acl_make_dirs"; + char *saved_path; + unsigned char *cp; + int saved_ch; + struct stat st; + int ret; + + /* + * Initialize. Make a copy of the path that we can safely clobber. + */ + cp = (unsigned char *) (saved_path = acl_mystrdup(path)); + + if ((*cp >= 'a' && *cp <='z') || (*cp >= 'A' && *cp <= 'Z')) { + if (*(cp + 1) == ':' && *(cp + 2) == '\\') { + char buf[4]; + + buf[0] = *cp++; /* 'a-z' | 'A-Z' */ + buf[1] = *cp++; /* ':' */ + buf[2] = *cp++; /* '\\' */ + buf[3] = 0; + if (stat(buf, &st) < 0) { + acl_msg_error("%s(%d): %s not exist(%s)", + myname, __LINE__, strerror(errno)); + return (-1); + } + } + } + + if (*cp == 0) + return (0); + + /* + * I didn't like the 4.4BSD "mkdir -p" implementation, but coming up + * with my own took a day, spread out over several days. + */ +#define SKIP_WHILE(cond, ptr) { while(*ptr && (cond)) ptr++; } + + SKIP_WHILE(*cp == '/' || *cp == '\\', cp); + + for (;;) { + SKIP_WHILE(*cp != '/' && *cp != '\\', cp); + + if ((saved_ch = *cp) != 0) + *cp = 0; + if ((ret = stat(saved_path, &st)) >= 0) { + if (!S_ISDIR(st.st_mode)) { + errno = ENOTDIR; + acl_set_error(ERROR_PATH_NOT_FOUND); + ret = -1; + break; + } + } else { + if (errno != ENOENT) + break; + + /*if ((ret = mkdir(saved_path)) < 0) {*/ + if (!CreateDirectory(saved_path, NULL)) { + int error = acl_last_error(); + + if (error != ERROR_ALREADY_EXISTS) + break; + /* Race condition? */ + if ((ret = stat(saved_path, &st)) < 0) + break; + if (!S_ISDIR(st.st_mode)) { + acl_set_error(ENOTDIR); + ret = -1; + break; + } + } + } + if (saved_ch != 0) + *cp = saved_ch; + SKIP_WHILE(*cp == '/' || *cp == '\\', cp); + if (*cp == 0) + break; + } + + /* + * Cleanup. + */ + acl_myfree(saved_path); + return (ret); +} + +#else +# error "unknown OS" +#endif + diff --git a/lib_acl/src/stdlib/filedir/acl_sane_basename.c b/lib_acl/src/stdlib/filedir/acl_sane_basename.c new file mode 100644 index 000000000..b9652ae2c --- /dev/null +++ b/lib_acl/src/stdlib/filedir/acl_sane_basename.c @@ -0,0 +1,150 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include + +/* Utility library. */ +#include "thread/acl_pthread.h" +#include "stdlib/acl_vstring.h" +#include "stdlib/acl_msg.h" +#include "stdlib/acl_sane_basename.h" + +#endif + +#define STR(x) acl_vstring_str(x) + +/* acl_sane_basename - skip directory prefix */ + +char *acl_sane_basename(ACL_VSTRING *bp, const char *path) +{ + const char *myname = "acl_sane_basename"; + const char *first; + const char *last; + + /* + * Your buffer or mine? + */ + if (bp == 0) { + acl_msg_error("%s(%d): bp null", myname, __LINE__); + return (NULL); + } + + /* + * Special case: return "." for null or zero-length input. + */ + if (path == 0 || *path == 0) + return (STR(acl_vstring_strcpy(bp, "."))); + + /* + * Remove trailing '/' characters from input. Return "/" if input is all + * '/' characters. + */ + last = path + strlen(path) - 1; +#ifdef ACL_UNIX + while (*last == '/') { +#elif defined(ACL_MS_WINDOWS) + while (*last == '/' || *last == '\\') { +#endif + if (last == path) + return (STR(acl_vstring_strcpy(bp, "/"))); + last--; + } + + /* + * The pathname does not end in '/'. Skip to last '/' character if any. + */ + first = last - 1; +#ifdef ACL_UNIX + while (first >= path && *first != '/') +#elif defined(ACL_MS_WINDOWS) + while (first >= path && *first != '/' && *first != '\\') +#endif + first--; + + return (STR(acl_vstring_strncpy(bp, first + 1, last - first))); +} + +/* acl_sane_dirname - keep directory prefix */ + +char *acl_sane_dirname(ACL_VSTRING *bp, const char *path) +{ + const char *myname = "acl_sane_dirname"; + const char *last; + + /* + * Your buffer or mine? + */ + if (bp == 0) { + acl_msg_error("%s(%d): bp null", myname, __LINE__); + return (NULL); + } + + /* + * Special case: return "." for null or zero-length input. + */ + if (path == 0 || *path == 0) + return (STR(acl_vstring_strcpy(bp, "."))); + + /* + * Remove trailing '/' characters from input. Return "/" if input is all + * '/' characters. + */ + last = path + strlen(path) - 1; +#ifdef ACL_UNIX + while (*last == '/') { +#elif defined(ACL_MS_WINDOWS) + while (*last == '/' || *last == '\\') { +#endif + if (last == path) + return (STR(acl_vstring_strcpy(bp, "/"))); + last--; + } + + /* + * This pathname does not end in '/'. Skip to last '/' character if any. + */ +#ifdef ACL_UNIX + while (last >= path && *last != '/') +#elif defined(ACL_MS_WINDOWS) + while (last >= path && *last != '/' && *last != '\\') +#endif + last--; + if (last < path) /* no '/' */ + return (STR(acl_vstring_strcpy(bp, "."))); + + /* + * Strip trailing '/' characters from dirname (not strictly needed). + */ +#ifdef ACL_UNIX + while (last > path && *last == '/') +#elif defined(ACL_MS_WINDOWS) + while (last > path && (*last == '/' || *last == '\\')) +#endif + last--; + + return (STR(acl_vstring_strncpy(bp, path, last - path + 1))); +} + +#ifdef TEST +#include "stdlib/acl_vstring_vstream.h" + +int main(int argc acl_unused, char **argv acl_unused) +{ + ACL_VSTRING *buf = acl_vstring_alloc(10); + char *dir; + char *base; + + while (acl_vstring_gets_nonl(buf, ACL_VSTREAM_IN) > 0) { + dir = acl_sane_dirname((ACL_VSTRING *) 0, STR(buf)); + base = acl_sane_basename((ACL_VSTRING *) 0, STR(buf)); + acl_vstream_printf("input=\"%s\" dir=\"%s\" base=\"%s\"\n", + STR(buf), dir, base); + } + acl_vstream_fflush(ACL_VSTREAM_OUT); + acl_vstring_free(buf); + return (0); +} + +#endif + diff --git a/lib_acl/src/stdlib/filedir/acl_scan_dir.c b/lib_acl/src/stdlib/filedir/acl_scan_dir.c new file mode 100644 index 000000000..695df869a --- /dev/null +++ b/lib_acl/src/stdlib/filedir/acl_scan_dir.c @@ -0,0 +1,484 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +/* System library. */ + +#include +#include +#include +#include +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#ifdef ACL_UNIX +#include +#include +#elif defined(ACL_BCB_COMPILER) +#include +#endif + +/* Utility library. */ + +#include "stdlib/acl_msg.h" +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_mystring.h" +#include "stdlib/acl_stringops.h" +#include "stdlib/acl_scan_dir.h" + +#endif + +#include "stdlib/acl_dir.h" + +#ifdef ACL_MS_VC +# define SANE_RMDIR _rmdir +# define SANE_UNLINK _unlink +#else +# define SANE_RMDIR rmdir +# define SANE_UNLINK unlink +#endif + +#include "dir_sys_patch.h" + + /* + * The interface is based on an opaque structure, so we don't have to expose + * the user to the guts. Subdirectory info sits in front of parent directory + * info: a simple last-in, first-out list. + */ +typedef struct ACL_SCAN_INFO ACL_SCAN_INFO; + +struct ACL_SCAN_INFO { + char *path; /* directory name */ + DIR *dir_name; /* directory structure */ + struct acl_stat sbuf; /* the stat of the dir or file */ + ACL_SCAN_INFO *parent; /* linkage */ +}; + +struct ACL_SCAN_DIR { + ACL_SCAN_INFO *current; /* current scan */ + int recursive; /* if scan subtree recursive */ + int nfiles; /* total files' count */ + int ndirs; /* total dirs' count */ + acl_int64 nsize; /* total size of all files */ + ACL_SCAN_DIR_FN scan_fn; + void *scan_ctx; + char file_name[256]; /* if is file set it */ +}; + +#define ACL_SCAN_DIR_PATH(scan) (scan->current->path) + +/* acl_scan_dir_open - start directory scan */ + +ACL_SCAN_DIR *acl_scan_dir_open(const char *path, int recursive) +{ + ACL_SCAN_DIR *scan; + + scan = (ACL_SCAN_DIR *) acl_mycalloc(1, sizeof(*scan)); + scan->current = 0; + scan->recursive = recursive; + + scan->nfiles = 0; + scan->ndirs = 0; + scan->nsize = 0; + + if (acl_scan_dir_push(scan, path) < 0) + return (NULL); + return (scan); +} + +/* acl_scan_dir_close - terminate directory scan */ + +void acl_scan_dir_close(ACL_SCAN_DIR *scan) +{ + while (scan->current) + acl_scan_dir_pop(scan); + acl_myfree(scan); +} + +void acl_scan_dir_reset(ACL_SCAN_DIR *scan) +{ + if (scan == NULL) + return; + + scan->nfiles = 0; + scan->ndirs = 0; + scan->nsize = 0; +} + +/* acl_scan_dirctl - ctl interface for set option */ + +void acl_scan_dir_ctl(ACL_SCAN_DIR *scan, int name, ...) +{ + va_list ap; + + if (scan == NULL) + return; + va_start(ap, name); + + for (; name != ACL_SCAN_CTL_END; name = va_arg(ap, int)) { + switch(name) { + case ACL_SCAN_CTL_FN: + scan->scan_fn = va_arg(ap, ACL_SCAN_DIR_FN); + break; + case ACL_SCAN_CTL_CTX: + scan->scan_ctx = va_arg(ap, void*); + break; + default: + break; + } + } + + va_end(ap); +} + +/* acl_scan_dir_path - return the path of the directory being read. */ + +const char *acl_scan_dir_path(ACL_SCAN_DIR *scan) +{ + if (scan == NULL || scan->current == NULL) + return (NULL); + return (ACL_SCAN_DIR_PATH(scan)); +} + +const char *acl_scan_dir_file(ACL_SCAN_DIR *scan) +{ + if (scan == NULL || scan->current == NULL) + return (NULL); + + return (scan->file_name); +} + +int acl_scan_dir_ndirs(ACL_SCAN_DIR *scan) +{ + if (scan) + return (scan->ndirs); + else + return (-1); +} + +int acl_scan_dir_nfiles(ACL_SCAN_DIR *scan) +{ + if (scan) + return (scan->nfiles); + else + return (-1); +} + +acl_int64 acl_scan_dir_nsize(ACL_SCAN_DIR *scan) +{ + if (scan) + return (scan->nsize); + else + return (-1); +} + +int acl_scan_stat(ACL_SCAN_DIR *scan, struct acl_stat *sbuf) +{ + if (scan == NULL || scan->current == NULL || sbuf == NULL) + return (-1); + + memcpy(sbuf, &scan->current->sbuf, sizeof(struct acl_stat)); + return (0); +} + +int acl_scan_dir_end(ACL_SCAN_DIR *scan) +{ + if (scan == NULL) + return (-1); + if (scan->current == NULL) + return (1); + else + return (0); +} +/* acl_scan_dir_push - enter directory */ + +int acl_scan_dir_push(ACL_SCAN_DIR *scan, const char *path) +{ + const char *myname = "acl_scan_dir_push"; + ACL_SCAN_INFO *info; + + info = (ACL_SCAN_INFO *) acl_mymalloc(sizeof(*info)); + if (scan->current) { + info->path = + acl_concatenate(ACL_SCAN_DIR_PATH(scan), "/", path, (char *) 0); + } else { + info->path = acl_mystrdup(path); + } + + if ((info->dir_name = opendir(info->path)) == 0) { + char tbuf[256]; + acl_msg_error("%s(%d), %s: open directory(%s) error(%s)", + __FILE__, __LINE__, myname, + info->path, acl_last_strerror(tbuf, sizeof(tbuf))); + return (-1); + } + if (acl_msg_verbose > 1) + acl_msg_info("%s: open %s", myname, info->path); + info->parent = scan->current; + scan->current = info; + return (0); +} + +/* acl_scan_dir_pop - leave directory */ + +ACL_SCAN_DIR *acl_scan_dir_pop(ACL_SCAN_DIR *scan) +{ + const char *myname = "acl_scan_dir_pop"; + ACL_SCAN_INFO *info = scan->current; + ACL_SCAN_INFO *parent; + + if (info == NULL) + return (NULL); + parent = info->parent; + if (closedir(info->dir_name)) { + char tbuf[256]; + acl_msg_fatal("%s(%d), %s: close directory(%s) error(%s)", + __FILE__, __LINE__, myname, + info->path, acl_last_strerror(tbuf, sizeof(tbuf))); + } + if (acl_msg_verbose > 1) + acl_msg_info("%s: close %s", myname, info->path); + acl_myfree(info->path); + acl_myfree(info); + scan->current = parent; + return (parent ? scan : NULL); +} + +/* acl_scan_dir_next - find next entry */ + +const char *acl_scan_dir_next(ACL_SCAN_DIR *scan) +{ + const char *myname = "acl_scan_dir_next"; + ACL_SCAN_INFO *info = scan->current; + struct dirent *dp; + +#define STREQ(x,y) (strcmp((x),(y)) == 0) + + if (info == NULL) + return (NULL); + + while ((dp = readdir(info->dir_name)) != 0) { + if (STREQ(dp->d_name, ".") || STREQ(dp->d_name, "..")) { + if (acl_msg_verbose > 1) + acl_msg_info("%s: skip %s", myname, dp->d_name); + continue; + } + + if (acl_msg_verbose > 1) + acl_msg_info("%s: found %s", myname, dp->d_name); + + return (dp->d_name); + } + + return (NULL); +} + +/* acl_scan_dir_next_file - find next valid file */ + +const char *acl_scan_dir_next_file(ACL_SCAN_DIR *scan) +{ + const char *myname = "acl_scan_dir_next_file"; + const char *name; + char pathbuf[256]; + struct acl_stat sbuf; + + for (;;) { + if ((name = acl_scan_dir_next(scan)) == NULL) { + if (acl_scan_dir_pop(scan) == 0) + return (NULL); + continue; + } + snprintf(pathbuf, sizeof(pathbuf), "%s/%s", + ACL_SCAN_DIR_PATH(scan), name); + if (acl_stat(pathbuf, &sbuf) < 0) { + char tbuf[256]; + acl_msg_error("%s(%d), %s: stat file(%s) error(%s)", + __FILE__, __LINE__, myname, + pathbuf, acl_last_strerror(tbuf, sizeof(tbuf))); + return (NULL); + } + + memcpy(&scan->current->sbuf, &sbuf, sizeof(sbuf)); + + scan->nsize += sbuf.st_size; + + if (S_ISDIR(sbuf.st_mode)) { + scan->ndirs++; + if (scan->recursive && acl_scan_dir_push(scan, name) < 0) + return (NULL); + } else { + scan->nfiles++; + return (name); + } + } +} + +acl_int64 acl_scan_dir_size2(ACL_SCAN_DIR *scan) +{ + const char *myname = "acl_scan_dir_size2"; + const char *name; + char pathbuf[256]; + struct acl_stat sbuf; + + if (scan == NULL) + return (-1); + + while (1) { + if ((name = acl_scan_dir_next(scan)) == NULL) { + if (acl_scan_dir_pop(scan) == NULL) + break; + continue; + } + snprintf(pathbuf, sizeof(pathbuf), "%s/%s", + ACL_SCAN_DIR_PATH(scan), name); + if (acl_stat(pathbuf, &sbuf) < 0) { + char tbuf[256]; + acl_msg_error("%s(%d), %s: stat file(%s) error(%s)", + __FILE__, __LINE__, myname, + pathbuf, acl_last_strerror(tbuf, sizeof(tbuf))); + break; + } + + memcpy(&scan->current->sbuf, &sbuf, sizeof(sbuf)); + + if (S_ISDIR(sbuf.st_mode)) { + scan->ndirs++; + scan->file_name[0] = 0; + if (scan->recursive && acl_scan_dir_push(scan, name) < 0) + break; + } else { + ACL_SAFE_STRNCPY(scan->file_name, name, sizeof(scan->file_name)); + scan->nfiles++; + scan->nsize += sbuf.st_size; + } + + if (scan->scan_fn && scan->scan_fn(scan, scan->scan_ctx) < 0) + break; + } + + return (scan->nsize); +} + +acl_int64 acl_scan_dir_size(const char *pathname, int recursive, int *nfile, int *ndir) +{ + ACL_SCAN_DIR *scan; + acl_int64 size; + + if (pathname == NULL || *pathname == 0) + return (-1); + scan = acl_scan_dir_open(pathname, recursive); + if (scan == NULL) + return (-1); + size = acl_scan_dir_size2(scan); + if (nfile) + *nfile = scan->nfiles; + if (ndir) + *ndir = scan->ndirs; + acl_scan_dir_close(scan); + return (size); +} + +/* acl_scan_dir_rmall - remove all directoies and file in the dir */ + +void acl_scan_dir_rm2(ACL_SCAN_DIR *scan) +{ + const char *myname = "acl_scan_dir_rm2"; + const char *name; + char path[256]; + struct acl_stat sbuf; + + for (;;) { + if ((name = acl_scan_dir_next(scan)) == NULL) { + if (scan->current != NULL) + snprintf(path, sizeof(path), "%s", ACL_SCAN_DIR_PATH(scan)); + else + path[0] = 0; + + /* 必须退出该空目录后才可以删除该目录 */ + + if (acl_scan_dir_pop(scan) == 0) { + /* 删除最顶层空目录 */ + if (path[0] != 0 && SANE_RMDIR(path) == 0) + scan->ndirs++; + break; + } + + /* 删除空目录 */ + if (path[0] != 0 && SANE_RMDIR(path) == 0) + scan->ndirs++; + continue; + } + + snprintf(path, sizeof(path), "%s/%s", ACL_SCAN_DIR_PATH(scan), name); + + if (acl_stat(path, &sbuf) < 0) { + char tbuf[256]; + acl_msg_error("%s(%d), %s: stat file(%s) error(%s)", + __FILE__, __LINE__, myname, + path, acl_last_strerror(tbuf, sizeof(tbuf))); + break; + } + if (S_ISDIR(sbuf.st_mode)) { + scan->file_name[0] = 0; + if (scan->recursive && acl_scan_dir_push(scan, name) < 0) + break; + if (scan->scan_fn && scan->scan_fn(scan, scan->scan_ctx) < 0) + break; + continue; + } else + ACL_SAFE_STRNCPY(scan->file_name, name, sizeof(scan->file_name)); + + if (scan->scan_fn && scan->scan_fn(scan, scan->scan_ctx) < 0) + break; + scan->nfiles++; + scan->nsize += sbuf.st_size; + SANE_UNLINK(path); + } +} + +acl_int64 acl_scan_dir_rm(const char *pathname, int recursive, int *ndir, int *nfile) +{ + const char *myname = "acl_scan_dir_rmall"; + ACL_SCAN_DIR *scan; + struct acl_stat sbuf; + acl_int64 nsize; + char tbuf[256]; + + if (ndir) + *ndir = 0; + if (nfile) + *nfile = 0; + + if (acl_stat(pathname, &sbuf) < 0) { + acl_msg_error("%s(%d), %s: stat pathname(%s) error(%s)", + __FILE__, __LINE__, myname, pathname, + acl_last_strerror(tbuf, sizeof(tbuf))); + return (-1); + } + if (S_ISDIR(sbuf.st_mode) == 0) { + if (nfile) + *nfile = 1; + SANE_UNLINK(pathname); + + return (1); + } + + scan = acl_scan_dir_open(pathname, recursive); + if (scan == NULL) { + acl_msg_error("%s(%d), %s: open path(%s) error(%s)", + __FILE__, __LINE__, myname, + pathname, acl_last_strerror(tbuf, sizeof(tbuf))); + return (-1); + } + + acl_scan_dir_rm2(scan); + + if (ndir) + *ndir = scan->ndirs; + if (nfile) + *nfile = scan->nfiles; + nsize = scan->nsize; + acl_scan_dir_close(scan); + return (nsize); +} diff --git a/lib_acl/src/stdlib/filedir/dir_sys_patch.h b/lib_acl/src/stdlib/filedir/dir_sys_patch.h new file mode 100644 index 000000000..9b40e2da8 --- /dev/null +++ b/lib_acl/src/stdlib/filedir/dir_sys_patch.h @@ -0,0 +1,21 @@ +#ifndef __DIR_SYS_PATCH_INCLUDE_H__ +#define __DIR_SYS_PATCH_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef ACL_MS_WINDOWS +#include +#define __S_ISTYPE(mode, mask) (((mode) & _S_IFMT) == (mask)) +#ifndef S_ISDIR +# define S_ISDIR(mode) __S_ISTYPE((mode), _S_IFDIR) +#endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/src/stdlib/getopt.c b/lib_acl/src/stdlib/getopt.c new file mode 100644 index 000000000..7f58f77f3 --- /dev/null +++ b/lib_acl/src/stdlib/getopt.c @@ -0,0 +1,97 @@ + +/* +Newsgroups: mod.std.unix +Subject: public domain AT&T getopt source +Date: 3 Nov 85 19:34:15 GMT + +Here's something you've all been waiting for: the AT&T public domain +source for getopt(3). It is the code which was given out at the 1985 +UNIFORUM conference in Dallas. I obtained it by electronic mail +directly from AT&T. The people there assure me that it is indeed +in the public domain. +*/ + +/*LINTLIBRARY*/ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_getopt.h" + +#endif + +#ifdef HAVE_NO_GETOPT + +#define EOF (-1) +#define ERR(s, c) \ + if (opterr) { \ + char errbuf[2]; \ + errbuf[0] = c; errbuf[1] = '\n'; \ + (void) printf("%s", argv[0]); \ + (void) printf("%s", s); \ + (void) printf("%s", errbuf); \ + } + + +int opterr; +int optind; +int optopt; +char *optarg; + +int getopt(int argc, char **argv, char *opts) +{ + static int sp = 1; + register int c; + register char *cp; + static int call_first = 1; + + if (call_first) { + opterr = 1; + optind = 1; + call_first = 0; + } + + if(sp == 1) + if(optind >= argc || argv[optind][0] != '-' || argv[optind][1] == '\0') + return(EOF); + else if(strcmp(argv[optind], "--") == 0) { + optind++; + return(EOF); + } + optopt = c = argv[optind][sp]; + if(c == ':' || (cp=strchr(opts, c)) == NULL) { + ERR(": illegal option -- ", c); + if(argv[optind][++sp] == '\0') { + optind++; + sp = 1; + } + return('?'); + } + if(*++cp == ':') { + if(argv[optind][sp+1] != '\0') + optarg = &argv[optind++][sp+1]; + else if(++optind >= argc) { + ERR(": option requires an argument -- ", c); + sp = 1; + return('?'); + } else + optarg = argv[optind++]; + sp = 1; + } else { + if(argv[optind][++sp] == '\0') { + sp = 1; + optind++; + } + optarg = NULL; + } + return(c); +} +#endif /* HAVE_NO_GETOPT */ diff --git a/lib_acl/src/stdlib/iostuff/acl_close_on_exec.c b/lib_acl/src/stdlib/iostuff/acl_close_on_exec.c new file mode 100644 index 000000000..85ac4e603 --- /dev/null +++ b/lib_acl/src/stdlib/iostuff/acl_close_on_exec.c @@ -0,0 +1,47 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +/* System interfaces. */ +#include "stdlib/acl_define.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#endif + +#ifdef ACL_UNIX + +#include +#include + +/* Utility library. */ + +#include "stdlib/acl_msg.h" + +/* Application-specific. */ + +#include "stdlib/acl_iostuff.h" + +#define ACL_PATTERN FD_CLOEXEC + +/* close_on_exec - set/clear close-on-exec flag */ + +int acl_close_on_exec(int fd, int on) +{ + int flags; + + if ((flags = fcntl(fd, F_GETFD, 0)) < 0) { + char tbuf[256]; + acl_msg_fatal("fcntl: get flags: %s", + acl_last_strerror(tbuf, sizeof(tbuf))); + } + if (fcntl(fd, F_SETFD, on ? flags | ACL_PATTERN : flags & ~ACL_PATTERN) < 0) { + char tbuf[256]; + acl_msg_fatal("fcntl: set close-on-exec flag %s: %s", on ? "on" : "off", + acl_last_strerror(tbuf, sizeof(tbuf))); + } + return ((flags & ACL_PATTERN) != 0); +} + +#endif /* ACL_UNIX */ diff --git a/lib_acl/src/stdlib/iostuff/acl_closefrom.c b/lib_acl/src/stdlib/iostuff/acl_closefrom.c new file mode 100644 index 000000000..80fbee882 --- /dev/null +++ b/lib_acl/src/stdlib/iostuff/acl_closefrom.c @@ -0,0 +1,42 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_msg.h" + +#endif + +#ifdef ACL_UNIX +#include +#include +#include "stdlib/acl_iostuff.h" + +/* acl_closefrom() - closes all file descriptors from the given one up */ + +int acl_closefrom(int lowfd) +{ + int fd_limit = acl_open_limit(0); + int fd; + + /* + * lowfrom does not have an easy to determine upper limit. A process may + * have files open that were inherited from a parent process with a less + * restrictive resource limit. + */ + if (lowfd < 0) { + acl_set_error(EBADF); + return (-1); + } + if (fd_limit > 500) + fd_limit = 500; + for (fd = lowfd; fd < fd_limit; fd++) + (void) close(fd); + + return (0); +} +#endif /* ACL_UNIX */ diff --git a/lib_acl/src/stdlib/iostuff/acl_doze.c b/lib_acl/src/stdlib/iostuff/acl_doze.c new file mode 100644 index 000000000..11e938df7 --- /dev/null +++ b/lib_acl/src/stdlib/iostuff/acl_doze.c @@ -0,0 +1,48 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef ACL_MS_VC +#pragma once +#endif + +#ifdef ACL_UNIX +#include +#include +#include +#include +#endif + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +/* Utility library. */ + +#include "stdlib/acl_msg.h" +#include "stdlib/acl_iostuff.h" + +#endif + +/* doze - sleep a while */ + +void acl_doze(unsigned delay) +{ +#ifdef ACL_UNIX + struct timeval tv; + + tv.tv_sec = delay / 1000; + tv.tv_usec = (delay - tv.tv_sec * 1000) * 1000; + while (select(0, (fd_set *) 0, (fd_set *) 0, (fd_set *) 0, &tv) < 0) + if (acl_last_error() != ACL_EINTR) { + char tbuf[256]; + acl_msg_fatal("doze: select: %s", + acl_last_strerror(tbuf, sizeof(tbuf))); + } +#elif defined(ACL_MS_WINDOWS) + Sleep(delay); +#else +#error "unknown OS" +#endif +} diff --git a/lib_acl/src/stdlib/iostuff/acl_duplex_pipe.c b/lib_acl/src/stdlib/iostuff/acl_duplex_pipe.c new file mode 100644 index 000000000..b85809782 --- /dev/null +++ b/lib_acl/src/stdlib/iostuff/acl_duplex_pipe.c @@ -0,0 +1,31 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include "stdlib/acl_iostuff.h" + +#endif + +#ifdef ACL_UNIX +#include +#include +#include "stdlib/unix/acl_sane_socketpair.h" +#endif + +#ifdef ACL_MS_WINDOWS +#define HAS_DUPLEX_PIPE +#endif + +/* duplex_pipe - give me a duplex pipe or bust */ + +int acl_duplex_pipe(ACL_FILE_HANDLE fds[2]) +{ +#if defined(HAS_DUPLEX_PIPE) + return (acl_pipe(fds)); +#else + return (acl_sane_socketpair(AF_UNIX, SOCK_STREAM, 0, fds)); +#endif +} + + + diff --git a/lib_acl/src/stdlib/iostuff/acl_fdtype.c b/lib_acl/src/stdlib/iostuff/acl_fdtype.c new file mode 100644 index 000000000..ff8802421 --- /dev/null +++ b/lib_acl/src/stdlib/iostuff/acl_fdtype.c @@ -0,0 +1,33 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#endif + +#ifdef ACL_UNIX + +#include +#include +#include + +#include "stdlib/acl_iostuff.h" + +int acl_issock(int fd) +{ + struct stat buf; + + if (fstat(fd, &buf) < 0) + return(0); + + if ((buf.st_mode & S_IFMT) == S_IFSOCK) + return(1); + else + return(0); +} +#endif /* ACL_UNIX*/ + diff --git a/lib_acl/src/stdlib/iostuff/acl_non_blocking.c b/lib_acl/src/stdlib/iostuff/acl_non_blocking.c new file mode 100644 index 000000000..a817d1628 --- /dev/null +++ b/lib_acl/src/stdlib/iostuff/acl_non_blocking.c @@ -0,0 +1,79 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef ACL_UNIX +#include +#endif + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_msg.h" +#include "stdlib/acl_iostuff.h" + +#endif + +#ifdef ACL_UNIX +/* Backwards compatibility */ +# ifndef O_NONBLOCK +# define PATTERN FNDELAY +# else +# define PATTERN O_NONBLOCK +# endif +#endif + +int acl_non_blocking(ACL_SOCKET fd, int on) +{ +#ifdef ACL_UNIX + int flags; + int nonb = PATTERN; +#endif +#ifdef NBLOCK_SYSV + int res; +#endif + + /* + ** NOTE: consult ALL your relevant manual pages *BEFORE* changing + ** these ioctl's. There are quite a few variations on them, + ** as can be seen by the PCS one. They are *NOT* all the same. + ** Heed this well. - Avalon. + */ +#ifdef NBLOCK_POSIX + nonb |= O_NONBLOCK; +#endif +#ifdef NBLOCK_BSD + nonb |= O_NDELAY; +#endif + +#ifdef NBLOCK_SYSV + /* This portion of code might also apply to NeXT. -LynX */ + if (on) + res = 1; + else + res = 0; + if (ioctl (fd, FIONBIO, &res) < 0) { + acl_msg_error("ioctl(fd,FIONBIO) failed"); + return (-1); + } +#elif defined(ACL_UNIX) + if ((flags = fcntl(fd, F_GETFL, 0)) == -1) { + acl_msg_error("fcntl(fd, F_GETFL) failed"); + return (-1); + } + if (fcntl(fd, F_SETFL, on ? flags | nonb : flags & ~nonb) < 0) { + acl_msg_error("fcntl(fd, F_SETL, nonb) failed"); + return (-1); + } +#elif defined(ACL_MS_WINDOWS) + if (ioctlsocket(fd, FIONBIO, (unsigned long *) &on) < 0) { + acl_msg_error("ioctlsocket(fd,FIONBIO) failed"); + return (-1); + } +#else +# error "unknown OS type" +#endif + return (0); +} diff --git a/lib_acl/src/stdlib/iostuff/acl_open_limit.c b/lib_acl/src/stdlib/iostuff/acl_open_limit.c new file mode 100644 index 000000000..6780acff6 --- /dev/null +++ b/lib_acl/src/stdlib/iostuff/acl_open_limit.c @@ -0,0 +1,79 @@ +/* System libraries. */ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include "stdlib/acl_msg.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#endif + +#ifdef ACL_UNIX + +#include +#include +#include + +/* Application-specific. */ + +#include "stdlib/acl_iostuff.h" + + /* + * 44BSD compatibility. + */ +#ifndef RLIMIT_NOFILE +#ifdef RLIMIT_OFILE +#define RLIMIT_NOFILE RLIMIT_OFILE +#endif +#endif + +/* acl_open_limit - set/query file descriptor limit */ + +#include + +int acl_open_limit(int limit) +{ +#ifdef RLIMIT_NOFILE + struct rlimit rl; + int rlim_cur = -1; + + if (getrlimit(RLIMIT_NOFILE, &rl) < 0) + return -1; + + rlim_cur = (int) rl.rlim_cur; + if (limit > 0) { + if (limit > (int) rl.rlim_max) + rl.rlim_cur = rl.rlim_max; + else + rl.rlim_cur = limit; + if (setrlimit(RLIMIT_NOFILE, &rl) < 0) { + acl_msg_warn("setrlimit error: %s, %d", + acl_last_serror(), (int) limit); + return rlim_cur; + } + else + return (int) rl.rlim_cur; + } else if (rl.rlim_max > rl.rlim_cur) { + rlim_cur = (int) rl.rlim_cur; + rl.rlim_cur = rl.rlim_max; + if (setrlimit(RLIMIT_NOFILE, &rl) < 0) { + acl_msg_warn("setrlimit error: %s, %d", + acl_last_serror(), (int) limit); + return rlim_cur; + } + + return (int) rl.rlim_cur; + } else + return (int) rl.rlim_cur; + +#else + (void) limit; + return getdtablesize(); +#endif +} + +#endif /* end ACL_UNIX */ + diff --git a/lib_acl/src/stdlib/iostuff/acl_peekfd.c b/lib_acl/src/stdlib/iostuff/acl_peekfd.c new file mode 100644 index 000000000..5b4ee5079 --- /dev/null +++ b/lib_acl/src/stdlib/iostuff/acl_peekfd.c @@ -0,0 +1,43 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#endif + +#ifdef ACL_UNIX + +#include +#ifdef ACL_FIONREAD_IN_SYS_FILIO_H +#include +#endif +#ifdef ACL_FIONREAD_IN_TERMIOS_H +#include +#endif +#include + +#endif + +/* Utility library. */ + +#include "stdlib/acl_iostuff.h" + +/* acl_peekfd - return amount of data ready to read */ + +int acl_peekfd(ACL_SOCKET fd) +{ + int count; + + /* + * Anticipate a series of system-dependent code fragments. + */ +#ifdef ACL_UNIX + return (ioctl(fd, FIONREAD, (char *) &count) < 0 ? -1 : count); +#elif defined(ACL_MS_WINDOWS) + return (ioctlsocket(fd, FIONREAD, (unsigned long *) &count) < 0 ? -1 : count); +#endif +} diff --git a/lib_acl/src/stdlib/iostuff/acl_pipe.c b/lib_acl/src/stdlib/iostuff/acl_pipe.c new file mode 100644 index 000000000..202122a82 --- /dev/null +++ b/lib_acl/src/stdlib/iostuff/acl_pipe.c @@ -0,0 +1,79 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include "stdlib/acl_msg.h" +#include "stdlib/acl_sys_patch.h" +#include "stdlib/acl_iostuff.h" + +#endif + +#ifdef ACL_MS_WINDOWS + +#include "thread/acl_pthread.h" +#include + +int acl_pipe(ACL_FILE_HANDLE fds[2]) +{ + const char *myname = "acl_pipe"; + DWORD dwPipeMode; + DWORD dwOpenMode; + char name[250]; + SECURITY_ATTRIBUTES sa; + static unsigned long id = 0; + + InterlockedIncrement(&id); + + sa.nLength = sizeof(sa); + sa.bInheritHandle = TRUE; + sa.lpSecurityDescriptor = NULL; + + /* Create the read/write end of the pipe */ + + dwOpenMode = PIPE_ACCESS_DUPLEX; + dwPipeMode = PIPE_WAIT; /* PIPE_NOWAIT; */ + snprintf(name, sizeof(name), "\\\\.\\pipe\\acl-pipe-%u-%lu-%lu", + _getpid(), (unsigned long) acl_pthread_self(), id); + fds[0] = CreateNamedPipe(name, + dwOpenMode, + dwPipeMode, + 1, /* nMaxInstances */ + 65536, /* nOutBufferSize */ + 65536, /* nInBufferSize */ + 1, /* nDefaultTimeOut */ + &sa); + + /* Create the read/write end of the pipe */ + dwOpenMode = FILE_ATTRIBUTE_NORMAL; + fds[1] = CreateFile(name, + GENERIC_WRITE | GENERIC_READ, /* access mode */ + 0, /* share mode */ + NULL, /* Security attributes */ + OPEN_EXISTING, /* dwCreationDisposition */ + dwOpenMode, /* Pipe attributes */ + NULL); /* handle to template file */ + + if (fds[1] == ACL_FILE_INVALID) { + acl_msg_error("%s(%d): CreateFile(%s) error(%s)", + myname, __LINE__, name, acl_last_serror()); + acl_file_close(fds[0]); + return (-1); + } + return (0); +} + +#elif defined(ACL_UNIX) + +#include + +int acl_pipe(ACL_FILE_HANDLE fds[2]) +{ + return (pipe(fds)); +} + +#endif + +int acl_pipe_close(ACL_FILE_HANDLE fds[2]) +{ + return ((acl_file_close(fds[0]) == 0 && acl_file_close(fds[1]) == 0) ? 0 : -1); +} diff --git a/lib_acl/src/stdlib/iostuff/acl_read_wait.c b/lib_acl/src/stdlib/iostuff/acl_read_wait.c new file mode 100644 index 000000000..a1a702d0c --- /dev/null +++ b/lib_acl/src/stdlib/iostuff/acl_read_wait.c @@ -0,0 +1,135 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#include /* in SUNOS, FD_ZERO need memset() */ +#include + +#endif + +#ifdef ACL_UNIX +#include +#include +#include +#endif + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif +#include "stdlib/acl_msg.h" +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_iostuff.h" +#include "../../init/init.h" + +static int select_read_wait(ACL_SOCKET fd, int timeout) +{ + fd_set read_fds; + fd_set except_fds; + struct timeval tv; + struct timeval *tp; +#ifdef ACL_MS_WINDOWS + int errnum; +#endif + +#ifdef ACL_UNIX + /* + * Sanity checks. + */ + if (FD_SETSIZE <= (unsigned) fd) + acl_msg_panic("descriptor %d does not fit FD_SETSIZE %d", + fd, FD_SETSIZE); +#endif + + /* + * Guard the write() with select() so we do not depend on alarm() and on + * signal() handlers. Restart the select when interrupted by some signal. + * Some select() implementations may reduce the time to wait when + * interrupted, which is exactly what we want. + */ + FD_ZERO(&read_fds); + FD_SET(fd, &read_fds); + FD_ZERO(&except_fds); + FD_SET(fd, &except_fds); + if (timeout >= 0) { + tv.tv_usec = 0; + tv.tv_sec = timeout; + tp = &tv; + } else { + tp = 0; + } + + for (;;) { + switch (select(fd + 1, (fd_set *) &read_fds, (fd_set *) 0, &except_fds, tp)) { + case -1: +#ifdef ACL_MS_WINDOWS + errnum = WSAGetLastError(); + if (errnum != WSAEINPROGRESS && errnum != WSAEWOULDBLOCK) { + acl_msg_error("select error"); + return (-1); + } +#else + if (acl_last_error() != ACL_EINTR) { + char tbuf[256]; + acl_msg_error("%s(%d): select error(%s)", + __FILE__, __LINE__, + acl_last_strerror(tbuf, sizeof(tbuf))); + return (-1); + } +#endif + continue; + case 0: + acl_set_error(ACL_ETIMEDOUT); + return (-1); + default: + return (0); + } + } +} + +#ifdef ACL_UNIX + +#include +static int poll_read_wait(ACL_SOCKET fd, int timeout) +{ + const char *myname = "poll_read_wait"; + struct pollfd fds; + int delay = timeout * 1000; + + fds.events = POLLIN | POLLHUP | POLLERR; + fds.fd = fd; + + for (;;) { + switch (poll(&fds, 1, delay)) { + case -1: + if (acl_last_error() != ACL_EINTR) { + char tbuf[256]; + acl_msg_error("%s: poll error(%s)", myname, + acl_last_strerror(tbuf, sizeof(tbuf))); + return (-1); + } + continue; + case 0: + acl_set_error(ACL_ETIMEDOUT); + return (-1); + default: + if ((fds.revents & (POLLHUP | POLLERR)) + || !(fds.revents & POLLIN)) + { + return (-1); + } + return (0); + } + } +} +#endif + +int acl_read_wait(ACL_SOCKET fd, int timeout) +{ +#ifdef ACL_UNIX + if (__acl_var_use_poll) + return (poll_read_wait(fd, timeout)); +#endif + + return (select_read_wait(fd, timeout)); +} diff --git a/lib_acl/src/stdlib/iostuff/acl_readable.c b/lib_acl/src/stdlib/iostuff/acl_readable.c new file mode 100644 index 000000000..459439baa --- /dev/null +++ b/lib_acl/src/stdlib/iostuff/acl_readable.c @@ -0,0 +1,72 @@ +/* System library. */ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include + +#endif + +#ifdef ACL_UNIX +# include +#endif +#include + +#ifdef USE_SYS_SELECT_H +#include +#endif + +/* Utility library. */ + +#include "stdlib/acl_msg.h" +#include "stdlib/acl_iostuff.h" + +/* acl_readable - see if file descriptor is readable */ + +int acl_readable(ACL_SOCKET fd) +{ + struct timeval tv; + fd_set read_fds; + fd_set except_fds; + + /* + * Sanity checks. + */ + if ((unsigned) fd >= FD_SETSIZE) + acl_msg_fatal("fd %d does not fit in FD_SETSIZE", fd); + + /* + * Initialize. + */ + FD_ZERO(&read_fds); + FD_SET(fd, &read_fds); + FD_ZERO(&except_fds); + FD_SET(fd, &except_fds); + tv.tv_sec = 0; + tv.tv_usec = 0; + + /* + * Loop until we have an authoritative answer. + */ + for (;;) { + switch (select(fd + 1, &read_fds, + (fd_set *) 0, &except_fds, &tv)) { + case -1: + if (acl_last_error() != ACL_EINTR) { + char tbuf[256]; + acl_msg_fatal("select: %s", acl_last_strerror(tbuf, sizeof(tbuf))); + } + continue; + default: + return (FD_ISSET(fd, &read_fds)); + case 0: + return (0); + } + } +} + diff --git a/lib_acl/src/stdlib/iostuff/acl_timed_read.c b/lib_acl/src/stdlib/iostuff/acl_timed_read.c new file mode 100644 index 000000000..b13e27154 --- /dev/null +++ b/lib_acl/src/stdlib/iostuff/acl_timed_read.c @@ -0,0 +1,55 @@ + +/* System library. */ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include + +#endif + +#ifdef ACL_UNIX +# include +#endif + +/* Utility library. */ + +#include "stdlib/acl_msg.h" +#include "stdlib/acl_sys_patch.h" +#include "stdlib/acl_iostuff.h" + +/* acl_timed_read - read with deadline */ + +int acl_timed_read(ACL_SOCKET fd, void *buf, unsigned len, + int timeout, void *unused_context acl_unused) +{ + int ret; + + /* + * Wait for a limited amount of time for something to happen. If nothing + * happens, report an ETIMEDOUT error. + * + * XXX Solaris 8 read() fails with EAGAIN after read-select() returns + * success. + */ + for (;;) { + if (timeout > 0 && acl_read_wait(fd, timeout) < 0) + return (-1); + ret = acl_socket_read(fd, buf, len, 0, NULL); + if (ret < 0 && timeout > 0 && acl_last_error() == ACL_EAGAIN) { + acl_msg_warn("read() returns EAGAIN on" + " a readable file descriptor!"); + acl_msg_warn("pausing to avoid going into" + " a tight select/read loop!"); + sleep(1); + } else { + return (ret); + } + } +} + diff --git a/lib_acl/src/stdlib/iostuff/acl_timed_write.c b/lib_acl/src/stdlib/iostuff/acl_timed_write.c new file mode 100644 index 000000000..fe9e29747 --- /dev/null +++ b/lib_acl/src/stdlib/iostuff/acl_timed_write.c @@ -0,0 +1,61 @@ + +/* System library. */ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include + +#endif + +#ifdef ACL_UNIX +# include +#endif + +/* Utility library. */ + +#include "stdlib/acl_msg.h" +#include "stdlib/acl_sys_patch.h" +#include "stdlib/acl_iostuff.h" + +/* acl_timed_write - write with deadline */ + +int acl_timed_write(ACL_SOCKET fd, void *buf, unsigned len, + int timeout, void *unused_context acl_unused) +{ + int ret; + + /* + * Wait for a limited amount of time for something to happen. If nothing + * happens, report an ETIMEDOUT error. + * + * XXX Solaris 8 read() fails with EAGAIN after read-select() returns + * success. The code below exists just in case their write implementation + * is equally broken. + * + * This condition may also be found on systems where select() returns + * success on pipes with less than PIPE_BUF bytes of space, and with + * badly designed software where multiple writers are fighting for access + * to the same resource. + */ + for (;;) { + if (timeout > 0 && acl_write_wait(fd, timeout) < 0) + return (-1); + ret = acl_socket_write(fd, buf, len, 0, NULL); + if (ret < 0 && timeout > 0 && acl_last_error() == ACL_EAGAIN) { + acl_msg_warn("write() returns EAGAIN on" + " a writable file descriptor!"); + acl_msg_warn("pausing to avoid going into" + " a tight select/write loop!"); + sleep(1); + } else { + return (ret); + } + } +} + diff --git a/lib_acl/src/stdlib/iostuff/acl_write_buf.c b/lib_acl/src/stdlib/iostuff/acl_write_buf.c new file mode 100644 index 000000000..5d9bbac0a --- /dev/null +++ b/lib_acl/src/stdlib/iostuff/acl_write_buf.c @@ -0,0 +1,44 @@ + +/* System library. */ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include +#include + +/* Utility library. */ + +#include "stdlib/acl_msg.h" +#include "stdlib/acl_sys_patch.h" +#include "stdlib/acl_iostuff.h" + +#endif + +/* acl_write_buf - write buffer or bust */ + +int acl_write_buf(ACL_SOCKET fd, const char *buf, int len, int timeout) +{ + int count; + + while (len > 0) { + if (timeout > 0 && acl_write_wait(fd, timeout) < 0) + return (-1); + count = acl_socket_write(fd, buf, len, 0, NULL); + if (count < 0) { + if (acl_last_error() == ACL_EAGAIN && timeout > 0) + continue; + return (-1); + } + if (count == 0) + acl_msg_fatal("write returned 0"); + buf += count; + len -= count; + } + return (len); +} diff --git a/lib_acl/src/stdlib/iostuff/acl_write_wait.c b/lib_acl/src/stdlib/iostuff/acl_write_wait.c new file mode 100644 index 000000000..f42b698b3 --- /dev/null +++ b/lib_acl/src/stdlib/iostuff/acl_write_wait.c @@ -0,0 +1,139 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#include /* in SUNOS, FD_ZERO need memset() */ +#include + +#endif + +#ifdef ACL_UNIX +#include +#include +#include +#endif + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_msg.h" +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_iostuff.h" +#include "../../init/init.h" + +static int select_write_wait(ACL_SOCKET fd, int timeout) +{ + const char *myname = "select_write_wait"; + fd_set write_fds; + fd_set except_fds; + struct timeval tv; + struct timeval *tp; + char buf[256]; +#ifdef ACL_MS_WINDOWS + int errnum; +#endif + +#ifdef ACL_UNIX + /* + * Sanity checks. + */ + if (FD_SETSIZE <= (unsigned) fd) + acl_msg_panic("%s, %s(%d): descriptor %d does not fit FD_SETSIZE %d", + myname, __FILE__, __LINE__, fd, FD_SETSIZE); +#endif + + /* + * Guard the write() with select() so we do not depend on alarm() and on + * signal() handlers. Restart the select when interrupted by some signal. + * Some select() implementations may reduce the time to wait when + * interrupted, which is exactly what we want. + */ + FD_ZERO(&write_fds); + FD_SET(fd, &write_fds); + FD_ZERO(&except_fds); + FD_SET(fd, &except_fds); + if (timeout >= 0) { + tv.tv_usec = 0; + tv.tv_sec = timeout; + tp = &tv; + } else { + tp = 0; + } + + for (;;) { + switch (select(fd + 1, (fd_set *) 0, &write_fds, &except_fds, tp)) { + case -1: +#ifdef ACL_MS_WINDOWS + errnum = WSAGetLastError(); + if (errnum != WSAEINPROGRESS && errnum != WSAEWOULDBLOCK) { + acl_msg_error("%s, %s(%d): select error(%s), fd(%d)", + myname, __FILE__, __LINE__, + acl_last_strerror(buf, sizeof(buf)), fd); + return (-1); + } +#else + if (acl_last_error() != ACL_EINTR) { + acl_msg_error("%s, %s(%d): select error(%s), fd(%d)", + myname, __FILE__, __LINE__, + acl_last_strerror(buf, sizeof(buf)), fd); + return (-1); + } +#endif + continue; + case 0: + acl_set_error(ACL_ETIMEDOUT); + return (-1); + default: + return (0); + } + } +} + +#ifdef ACL_UNIX + +#include +static int poll_write_wait(ACL_SOCKET fd, int timeout) +{ + const char *myname = "poll_write_wait"; + struct pollfd fds; + int delay = timeout * 1000; + + fds.events = POLLOUT | POLLHUP | POLLERR; + fds.fd = fd; + + for (;;) { + switch (poll(&fds, 1, delay)) { + case -1: + if (acl_last_error() != ACL_EINTR) { + char tbuf[256]; + acl_msg_error("%s: poll error(%s)", myname, + acl_last_strerror(tbuf, sizeof(tbuf))); + return (-1); + } + continue; + case 0: + acl_set_error(ACL_ETIMEDOUT); + return (-1); + default: + if ((fds.revents & (POLLHUP | POLLERR)) + || !(fds.revents & POLLOUT)) + { + return (-1); + } + return (0); + } + } +} +#endif + +int acl_write_wait(ACL_SOCKET fd, int timeout) +{ +#ifdef ACL_UNIX + if (__acl_var_use_poll) + return (poll_write_wait(fd, timeout)); +#endif + + return (select_write_wait(fd, timeout)); +} diff --git a/lib_acl/src/stdlib/memory/acl_allocator.c b/lib_acl/src/stdlib/memory/acl_allocator.c new file mode 100644 index 000000000..4fd465468 --- /dev/null +++ b/lib_acl/src/stdlib/memory/acl_allocator.c @@ -0,0 +1,400 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_malloc.h" +#include "stdlib/acl_msg.h" +#include "stdlib/acl_allocator.h" + +#endif + +#include "squid_allocator.h" +#include "allocator.h" + +static size_t __min_gross_size = 8; /* 8 byte */ +static size_t __max_gross_size = 1048576; /* 1MB */ + +#define CHECK_TYPE(_type) do { \ + if (_type >= ACL_MEM_TYPE_MAX) \ + acl_msg_fatal("%s: type(%d) > ACL_MEM_TYPE_MAX(%d)", myname, _type, ACL_MEM_TYPE_MAX); \ +} while (0) + +static ACL_MEM_POOL *pool_create(void) +{ + const char *myname = "pool_create"; + + acl_msg_fatal("%s: not supported!", myname); + + return (NULL); +} + +static void pool_destroy(ACL_MEM_POOL * pool acl_unused) +{ + const char *myname = "pool_destroy"; + + acl_msg_fatal("%s: not supported!", myname); +} + +static void pool_clean(ACL_ALLOCATOR *allocator acl_unused) +{ + const char *myname = "pool_clean"; + + acl_msg_fatal("%s: not supported!", myname); +} + +static void *mem_alloc(ACL_ALLOCATOR *allocator acl_unused, + ACL_MEM_POOL * pool acl_unused) +{ + const char *myname = "mem_alloc"; + + acl_msg_fatal("%s: not supported!", myname); + return (NULL); +} + +static void mem_free(ACL_ALLOCATOR *allocator acl_unused, + ACL_MEM_POOL *pool acl_unused, void *obj acl_unused) +{ + const char *myname = "mem_free"; + + acl_msg_fatal("%s: not supported!", myname); +} + +static int pool_ifused(const ACL_MEM_POOL *pool acl_unused) +{ + const char *myname = "pool_ifused"; + + acl_msg_fatal("%s: not supported!", myname); + return (0); +} + +static int pool_inuse_count(const ACL_MEM_POOL *pool acl_unused) +{ + const char *myname = "pool_inuse_count"; + + acl_msg_fatal("%s: not supported!", myname); + return (0); +} + +static size_t pool_inuse_size(const ACL_MEM_POOL *pool acl_unused) +{ + const char *myname = "pool_inuse_size"; + + acl_msg_fatal("%s: not supported!", myname); + return (0); +} + +static size_t pool_total_allocated(ACL_ALLOCATOR *pool acl_unused) +{ + const char *myname = "pool_total_allocated"; + + acl_msg_fatal("%s: not supported!", myname); + return (0); +} + +ACL_ALLOCATOR *allocator_alloc(size_t size) +{ + ACL_ALLOCATOR *allocator; + + allocator = (ACL_ALLOCATOR *) acl_default_calloc(__FILE__, __LINE__, 1, size); + allocator->pools = acl_stack_create(100); + + allocator->pool_create_fn = pool_create; + allocator->pool_destroy_fn = pool_destroy; + allocator->pool_clean_fn = pool_clean; + + allocator->pool_if_used = pool_ifused; + allocator->pool_inuse_count = pool_inuse_count; + allocator->pool_inuse_size = pool_inuse_size; + allocator->pool_total_allocated = pool_total_allocated; + + allocator->mem_alloc_fn = mem_alloc; + allocator->mem_free_fn = mem_free; + + return (allocator); +} + +ACL_ALLOCATOR *acl_allocator_create(size_t mem_limit) +{ + ACL_ALLOCATOR *allocator; + + allocator = squid_allocator_create(); + if (allocator->pool_config_fn) + allocator->pool_config_fn(allocator, mem_limit); + + /* 创建两个默认的内存分配类型池 */ + mem_pool_create(allocator); + vstring_pool_create(allocator); + + return (allocator); +} + +void acl_allocator_ctl(int name, ...) +{ + const char *myname = "acl_allocator_ctl"; + va_list ap; + + va_start(ap, name); + for (; name != ACL_ALLOCATOR_CTL_END; name = va_arg(ap, int)) { + switch(name) { + case ACL_ALLOCATOR_CTL_MIN_SIZE: + __min_gross_size = va_arg(ap, int); + break; + case ACL_ALLOCATOR_CTL_MAX_SIZE: + __max_gross_size = va_arg(ap, int); + break; + default: + acl_msg_panic("%s: bad name %d", myname, name); + } + + } + va_end(ap); +} + +void acl_allocator_config(ACL_ALLOCATOR *allocator, size_t mem_limit) +{ + if (allocator->pool_config_fn) + allocator->pool_config_fn(allocator, mem_limit); +} + +void acl_allocator_free(ACL_ALLOCATOR *allocator) +{ + ACL_MEM_POOL *pool; + + while (1) { + pool = acl_stack_pop(allocator->pools); + if (pool == NULL) + break; + allocator->pool_destroy_fn(pool); + } + + acl_stack_destroy(allocator->pools, NULL); + acl_default_free(__FILE__, __LINE__, allocator); +} + +ACL_MEM_POOL *acl_allocator_pool_add(ACL_ALLOCATOR *allocator, + const char *label, + size_t obj_size, + acl_mem_type type, + void (*after_alloc_fn)(void *obj, void *pool_ctx), + void (*before_free_fn)(void *obj, void *pool_ctx), + void *pool_ctx) +{ + const char *myname = "acl_allocator_pool_add"; + ACL_MEM_POOL *pool; + + CHECK_TYPE(type); + + pool = allocator->pool_create_fn(); + pool->label = label; + pool->obj_size = obj_size; +#if DEBUG_MEMPOOL + pool->real_obj_size = (obj_size & 7) ? (obj_size | 7) + 1 : obj_size; +#endif + pool->type = type; + pool->after_alloc_fn = after_alloc_fn; + pool->before_free_fn = before_free_fn; + pool->pool_ctx = pool_ctx; + pool->pstack = acl_stack_create(1000); + + allocator->MemPools[type] = pool; + acl_stack_append(allocator->pools, pool); + + return (pool); +} + +void acl_allocator_pool_remove(ACL_ALLOCATOR *allocator, ACL_MEM_POOL *pool) +{ + const char *myname = "acl_allocatorr_pool_remove"; + ACL_MEM_POOL *data; + ACL_ITER iter; + + if (allocator == NULL || pool == NULL) + acl_msg_fatal("%s: input invalid", myname); + + acl_foreach(iter, allocator->pools) { + data = (ACL_MEM_POOL*) iter.data; + if (data == pool) { + allocator->MemPools[pool->type] = NULL; + allocator->pool_destroy_fn(data); + acl_stack_delete(allocator->pools, iter.i, NULL); + break; + } + } +} + +void *acl_allocator_mem_alloc(ACL_ALLOCATOR *allocator, acl_mem_type type) +{ + const char *myname = "acl_allocator_mem_alloc"; + ACL_MEM_POOL *pool; + + CHECK_TYPE(type); + + pool = allocator->MemPools[type]; + return (allocator->mem_alloc_fn(allocator, pool)); +} + +void acl_allocator_mem_free(ACL_ALLOCATOR *allocator, acl_mem_type type, void *obj) +{ + const char *myname = "acl_allocator_mem_free"; + ACL_MEM_POOL *pool; + + CHECK_TYPE(type); + + pool = allocator->MemPools[type]; + allocator->mem_free_fn(allocator, pool, obj); +} + +/* Find the best fit ACL_MEM_TYPE_X_BUF type */ + +static acl_mem_type memBufFindSizeType(size_t net_size, size_t *gross_size) +{ + acl_mem_type type; + size_t size; + + if (net_size < __min_gross_size || net_size > __max_gross_size) { + if (gross_size) + *gross_size = net_size; + return ACL_MEM_TYPE_NONE; + } + + if (net_size <= 8) { + type = ACL_MEM_TYPE_8_BUF; + size = 8; + } else if (net_size <= 16) { + type = ACL_MEM_TYPE_16_BUF; + size = 16; + } else if (net_size <= 32) { + type = ACL_MEM_TYPE_32_BUF; + size = 32; + } else if (net_size <= 64) { + type = ACL_MEM_TYPE_64_BUF; + size = 64; + } else if (net_size <= 128) { + type = ACL_MEM_TYPE_128_BUF; + size = 128; + } else if (net_size <= 256) { + type = ACL_MEM_TYPE_256_BUF; + size = 256; + } else if (net_size <= 512) { + type = ACL_MEM_TYPE_512_BUF; + size = 512; + } else if (net_size <= 1024) { + type = ACL_MEM_TYPE_1K_BUF; + size = 1024; + } else if (net_size <= 2048) { + type = ACL_MEM_TYPE_2K_BUF; + size = 2048; + } else if (net_size <= 4096) { + type = ACL_MEM_TYPE_4K_BUF; + size = 4096; + } else if (net_size <= 8192) { + type = ACL_MEM_TYPE_8K_BUF; + size = 8192; + } else if (net_size <= 16384) { + type = ACL_MEM_TYPE_16K_BUF; + size = 16384; + } else if (net_size <= 32768) { + type = ACL_MEM_TYPE_32K_BUF; + size = 32768; + } else if (net_size <= 65536) { + type = ACL_MEM_TYPE_64K_BUF; + size = 65536; + } else if (net_size <= 131072) { + type = ACL_MEM_TYPE_128K_BUF; + size = 131072; + } else if (net_size <= 262144) { + type = ACL_MEM_TYPE_256K_BUF; + size = 262144; + } else if (net_size <= 524288) { + type = ACL_MEM_TYPE_512K_BUF; + size = 524288; + } else if (net_size <= 1048576) { + type = ACL_MEM_TYPE_1M_BUF; + size = 1048576; + } else { + type = ACL_MEM_TYPE_NONE; + size = net_size; + } + if (gross_size) + *gross_size = size; + return type; +} + +void *acl_allocator_membuf_alloc(const char *filename, int line, + ACL_ALLOCATOR *allocator, size_t size) +{ + size_t gross_size; + acl_mem_type type = memBufFindSizeType(size, &gross_size); + + if (type != ACL_MEM_TYPE_NONE) { + return (acl_allocator_mem_alloc(allocator, type)); + } else { + return (acl_default_malloc(filename, line, size)); + } +} + +void *acl_allocator_membuf_realloc(const char *filename, int line, + ACL_ALLOCATOR *allocator, void *oldbuf, size_t size) +{ + /* XXX This can be optimized on very large buffers to use realloc() */ + void *newbuf = acl_allocator_membuf_alloc(filename, line, allocator, size); + + if (oldbuf) { + size_t data_size; + + acl_default_memstat(filename, line, oldbuf, &data_size, NULL); + memcpy(newbuf, oldbuf, data_size > size ? size : data_size); + acl_allocator_membuf_free(filename, line, allocator, oldbuf); + } + return newbuf; +} + +void acl_allocator_membuf_free(const char *filename, int line, + ACL_ALLOCATOR *allocator, void *buf) +{ + size_t gross_size; + acl_mem_type type; + + acl_default_memstat(filename, line, buf, &gross_size, NULL); + type = memBufFindSizeType(gross_size, NULL); + + if (type != ACL_MEM_TYPE_NONE) + acl_allocator_mem_free(allocator, type, buf); + else + acl_default_free(filename, line, buf); +} + +int acl_allocator_pool_ifused(ACL_ALLOCATOR *allocator, acl_mem_type type) +{ + const char *myname = "acl_allocator_pool_ifused"; + + CHECK_TYPE(type); + return (allocator->pool_if_used(allocator->MemPools[type])); +} + +int acl_allocator_pool_inuse_count(ACL_ALLOCATOR *allocator, acl_mem_type type) +{ + const char *myname = "acl_allocator_pool_inuse_count"; + + CHECK_TYPE(type); + return (allocator->pool_inuse_count(allocator->MemPools[type])); +} + +int acl_allocator_pool_inuse_size(ACL_ALLOCATOR *allocator, acl_mem_type type) +{ + const char *myname = "acl_allocator_pool_inuse_size"; + + CHECK_TYPE(type); + return (allocator->pool_inuse_size(allocator->MemPools[type])); +} + +int acl_allocator_pool_total_allocated(ACL_ALLOCATOR *allocator) +{ + return (allocator->pool_total_allocated(allocator)); +} diff --git a/lib_acl/src/stdlib/memory/acl_dbuf_pool.c b/lib_acl/src/stdlib/memory/acl_dbuf_pool.c new file mode 100644 index 000000000..f4d994f94 --- /dev/null +++ b/lib_acl/src/stdlib/memory/acl_dbuf_pool.c @@ -0,0 +1,243 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#ifdef ACL_UNIX +#include +#endif +#include +#include +#include +#include "stdlib/acl_sys_patch.h" +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_dbuf_pool.h" + +#endif + +typedef struct ACL_DBUF { + void *buf; + void *ptr; + struct ACL_DBUF *next; +} ACL_DBUF; + +struct ACL_DBUF_POOL { + ACL_DBUF *head; + int block_size; +}; + +ACL_DBUF_POOL *acl_dbuf_pool_create(int block_size) +{ +#ifdef USE_VALLOC + ACL_DBUF_POOL *pool = (ACL_DBUF_POOL*) valloc(sizeof(ACL_DBUF_POOL)); + memset(pool, 0, sizeof(ACL_DBUF_POOL)); +#else + ACL_DBUF_POOL *pool = (ACL_DBUF_POOL*) acl_mycalloc(1, sizeof(ACL_DBUF_POOL)); +#endif + int size, page_size; + +#ifdef ACL_UNIX + page_size = getpagesize(); +#elif defined(ACL_MS_WINDOWS) + SYSTEM_INFO info; + + memset(&info, 0, sizeof(SYSTEM_INFO)); + GetSystemInfo(&info); + page_size = info.dwPageSize; + if (page_size <= 0) + page_size = 4096; +#else + page_size = 4096; +#endif + + size = (block_size / page_size) * page_size; + if (size == 0) + size = page_size; + + pool->block_size = size; + pool->head = NULL; + return (pool); +} + +void acl_dbuf_pool_destroy(ACL_DBUF_POOL *pool) +{ + ACL_DBUF *iter, *tmp; + + iter = pool->head; + while (iter) { + tmp = iter; + iter = iter->next; +#ifdef USE_VALLOC + free(tmp->buf); + free(tmp); +#else + acl_myfree(tmp->buf); + acl_myfree(tmp); +#endif + } + +#ifdef USE_VALLOC + free(pool); +#else + acl_myfree(pool); +#endif +} + +static ACL_DBUF *acl_dbuf_alloc(ACL_DBUF_POOL *pool, int length) +{ +#ifdef USE_VALLOC + ACL_DBUF *dbuf = (ACL_DBUF*) valloc(sizeof(ACL_DBUF)); + memset(dbuf, 0, sizeof(ACL_DBUF)); +#else + ACL_DBUF *dbuf = (ACL_DBUF*) acl_mycalloc(1, sizeof(ACL_DBUF)); +#endif + dbuf->next = NULL; + +#ifdef USE_VALLOC + dbuf->buf = dbuf->ptr = (void*) valloc(length); +#else + dbuf->buf = dbuf->ptr = (void*) acl_mymalloc(length); +#endif + if (pool->head == NULL) { + pool->head = dbuf; + } else { + dbuf->next = pool->head; + pool->head = dbuf; + } + return (dbuf); +} + +static int acl_dbuf_free(ACL_DBUF *dbuf) +{ + if (dbuf->ptr != dbuf->buf) + return (0); + +#ifdef USE_VALLOC + free(dbuf->ptr); + free(dbuf); +#else + acl_myfree(dbuf->ptr); + acl_myfree(dbuf); +#endif + return (1); +} + +void acl_dbuf_pool_free(ACL_DBUF_POOL *pool, void *ptr, int length) +{ + ACL_DBUF *dbuf, *next; + + if (pool->head == NULL) + return; + + dbuf = pool->head; + if (ptr < dbuf->buf || (char*) dbuf->ptr != (char*) ptr + length) { + return; + } + + dbuf->ptr = ptr; + + if (length > pool->block_size) { + next = dbuf->next; + if (acl_dbuf_free(dbuf)) + pool->head = next; + } +} + +void *acl_dbuf_pool_alloc(ACL_DBUF_POOL *pool, int length) +{ + void *ptr; + ACL_DBUF *dbuf; + + if (length > pool->block_size) + dbuf = acl_dbuf_alloc(pool, length); + else if (pool->head == NULL) + dbuf = acl_dbuf_alloc(pool, pool->block_size); + else if (pool->block_size - ((char*) pool->head->ptr - (char*) pool->head->buf) < length) + dbuf = acl_dbuf_alloc(pool, pool->block_size); + else + dbuf = pool->head; + + ptr = dbuf->ptr; + dbuf->ptr = (char*) dbuf->ptr + length; + return (ptr); +} + +void *acl_dbuf_pool_calloc(ACL_DBUF_POOL *pool, int length) +{ + void *ptr; + + ptr = acl_dbuf_pool_alloc(pool, length); + if (ptr) + memset(ptr, 0, length); + return (ptr); +} + +char *acl_dbuf_pool_strdup(ACL_DBUF_POOL *pool, const char *s) +{ + size_t len = strlen(s); + char *ptr = (char*) acl_dbuf_pool_alloc(pool, len + 1); + + memcpy(ptr, s, len); + ptr[len] = 0; + return (ptr); +} + +void *acl_dbuf_pool_memdup(ACL_DBUF_POOL *pool, const void *s, size_t len) +{ + void *ptr = acl_dbuf_pool_alloc(pool, len); + + memcpy(ptr, s, len); + return (ptr); +} + +void acl_dbuf_pool_test(size_t max) +{ + ACL_DBUF_POOL *pool; + size_t i, n = 1000000, len, j, k; + + for (j = 0; j < max; j++) { + printf("begin alloc, max: %d\n", (int) n); + pool = acl_dbuf_pool_create(0); + for (i = 0; i < n; i++) { + k = i % 10; + switch (k) { + case 0: + len = 1024; + break; + case 1: + len = 1999; + break; + case 2: + len = 999; + break; + case 3: + len = 230; + break; + case 4: + len = 199; + break; + case 5: + len = 99; + break; + case 6: + len = 19; + break; + case 7: + len = 29; + break; + case 8: + len = 9; + break; + case 9: + len = 399; + break; + default: + len = 88; + break; + } + (void) acl_dbuf_pool_alloc(pool, len); + } + printf("alloc over now, sleep(10)\n"); + sleep(10); + acl_dbuf_pool_destroy(pool); + } +} diff --git a/lib_acl/src/stdlib/memory/acl_default_malloc.c b/lib_acl/src/stdlib/memory/acl_default_malloc.c new file mode 100644 index 000000000..94df93b84 --- /dev/null +++ b/lib_acl/src/stdlib/memory/acl_default_malloc.c @@ -0,0 +1,350 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#include +#include +#include /* for offsetof */ +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#ifdef _USE_GLIB +#include +#endif + +#include "stdlib/acl_msg.h" +#include "stdlib/acl_malloc.h" + +#endif + +static char __FILENAME_UNKNOWN[] = "unknown file"; + +/* + * Structure of an annotated memory block. In order to detect spurious + * free() calls we prepend a signature to memory given to the application. + * In order to detect access to free()d blocks, overwrite each block as soon + * as it is passed to myfree(). With the code below, the user data has + * integer alignment or better. + */ +typedef struct MBLOCK { + int signature; /* set when block is active */ + size_t length; /* user requested length */ + union { + ALIGN_TYPE align; + char payload[1]; /* actually a bunch of bytes */ + } u; +} MBLOCK; + +#define SIGNATURE 0xdead +#define FILLER 0x0 + +#define CHECK_PTR(_ptr_, _real_ptr_, _len_, _fname_, _line_) { \ + if (_ptr_ == 0) \ + acl_msg_fatal("%s(%d): null pointer input", _fname_, _line_); \ + _real_ptr_ = (MBLOCK *) ((char *) _ptr_ - offsetof(MBLOCK, u.payload[0])); \ + if (_real_ptr_->signature != SIGNATURE) \ + acl_msg_fatal("%s(%d): corrupt or unallocated memory block(%d, 0x%x, 0x%x)", \ + _fname_, _line_, (int) _real_ptr_->length, _real_ptr_->signature, SIGNATURE); \ + if ((_len_ = _real_ptr_->length) < 1) \ + acl_msg_fatal("%s(%d): corrupt memory block length", _fname_, _line_); \ +} + +#define CHECK_IN_PTR(_ptr_, _real_ptr_, _len_, _fname_, _line_) { \ + if (_ptr_ == 0) \ + acl_msg_fatal("%s(%d): null pointer input", _fname_, _line_); \ + _real_ptr_ = (MBLOCK *) ((char *) _ptr_ - offsetof(MBLOCK, u.payload[0])); \ + if (_real_ptr_->signature != SIGNATURE) \ + acl_msg_fatal("%s(%d): corrupt or unallocated memory block(%d, 0x%x, 0x%x)", \ + _fname_, _line_, (int) _real_ptr_->length, _real_ptr_->signature, SIGNATURE); \ + _real_ptr_->signature = 0; \ + if ((_len_ = _real_ptr_->length) < 1) \ + acl_msg_fatal("%s(%d): corrupt memory block length", _fname_, _line_); \ +} + +#define CHECK_OUT_PTR(_ptr_, _real_ptr_, _len_) { \ + _real_ptr_->signature = SIGNATURE; \ + _real_ptr_->length = _len_; \ + _ptr_ = _real_ptr_->u.payload; \ +} + +#define SPACE_FOR(len) (offsetof(MBLOCK, u.payload[0]) + len) + +/* + * Optimization for short strings. We share one copy with multiple callers. + * This differs from normal heap memory in two ways, because the memory is + * shared: + * + * - It must be read-only to avoid horrible bugs. This is OK because there is + * no legitimate reason to modify the null terminator. + * + * - myfree() cannot overwrite the memory with a filler pattern like it can do + * with heap memory. Therefore, some dangling pointer bugs will be masked. + */ + +/* +#define NO_SHARED_EMPTY_STRINGS +*/ + +#ifndef NO_SHARED_EMPTY_STRINGS +static char empty_string[] = ""; + +#endif + +/* acl_malloc - allocate memory or bust */ + +#ifdef ACL_MS_WINDOWS + +# define SET_FILE(_ptr_, _filename_) do { \ + _ptr_ = strrchr(_filename_, '/'); \ + if (_ptr_ == NULL) { \ + _ptr_ = strrchr(_filename_, '\\'); \ + } \ + if (_ptr_ == NULL) \ + _ptr_ = filename; \ + else \ + _ptr_++; \ +} while (0) + +#else + +# define SET_FILE(_ptr_, _filename_) do { \ + _ptr_ = strrchr(_filename_, '/'); \ + if (_ptr_ == NULL) \ + _ptr_ = filename; \ + else \ + _ptr_++; \ +} while (0) +#endif /* ACL_MS_WINDOWS */ + +void acl_default_memstat(const char *filename, int line, + void *ptr, size_t *len, size_t *real_len) +{ + MBLOCK *real_ptr; + const char *pname = NULL; + size_t old_len; + + if (filename && *filename) + SET_FILE(pname, filename); + else + pname = __FILENAME_UNKNOWN; + + CHECK_PTR(ptr, real_ptr, old_len, pname, line); + if (len) + *len = real_ptr->length; + if (real_len) + *real_len = SPACE_FOR(*len); +} + +void *acl_default_malloc(const char *filename, int line, size_t len) +{ + const char *myname = "acl_default_malloc"; + size_t new_len; + char *ptr; + MBLOCK *real_ptr; + const char *pname = NULL; + + if (filename && *filename) + SET_FILE(pname, filename); + else + pname = __FILENAME_UNKNOWN; + + if (len < 1) + acl_msg_fatal("%s(%d)->%s: malloc: requested length %ld invalid", + pname, line, myname, (long) len); + + new_len = SPACE_FOR(len); + if (new_len <= 0) + acl_msg_fatal("%s(%d): new_len(%d) <= 0", myname, __LINE__, (int) new_len); + else if (new_len >= 100000000) + acl_msg_warn("%s(%d): new_len(%d) too large", myname, __LINE__, (int) new_len); + +#ifdef _USE_GLIB + if ((real_ptr = (MBLOCK *) g_malloc(new_len)) == 0) { + acl_msg_error("%s(%d)->%s: g_malloc error(%s)", + pname, line, myname, strerror(errno)); + return (0); + } +#else + if ((real_ptr = (MBLOCK *) malloc(new_len)) == 0) { + acl_msg_error("%s(%d)->%s: malloc: insufficient memory: %s", + pname, line, myname, strerror(errno)); + return (0); + } +#endif + CHECK_OUT_PTR(ptr, real_ptr, len); +#if 0 + memset(ptr, FILLER, len); +#endif + + return (ptr); +} + +void *acl_default_calloc(const char *filename, int line, size_t nmemb, size_t size) +{ + void *ptr; + int n; + + n = nmemb * size; + ptr = acl_default_malloc(filename, line, n); + memset(ptr, FILLER, n); + return (ptr); +} + +/* acl_default_realloc - reallocate memory or bust */ + +void *acl_default_realloc(const char *filename, int line, void *ptr, size_t len) +{ + const char *myname = "acl_default_realloc"; + MBLOCK *real_ptr; + size_t old_len, new_len; + const char *pname = NULL; + + if (filename && *filename) + SET_FILE(pname, filename); + else + pname = __FILENAME_UNKNOWN; + +#ifndef NO_SHARED_EMPTY_STRINGS + if (ptr == empty_string) + return (acl_default_malloc(pname, line, len)); +#endif + + if (len < 1) + acl_msg_fatal("%s(%d)->%s: realloc: requested length %ld", + pname, line, myname, (long) len); + CHECK_IN_PTR(ptr, real_ptr, old_len, pname, line); + + new_len = SPACE_FOR(len); + if (new_len <= 0) + acl_msg_fatal("%s(%d): new_len(%d) <= 0", myname, __LINE__, (int) new_len); + else if (new_len >= 100000000) + acl_msg_warn("%s(%d): new_len(%d) too large", myname, __LINE__, (int) new_len); + +#ifdef _USE_GLIB + if ((real_ptr = (MBLOCK *) g_realloc((char *) real_ptr, new_len)) == 0) + acl_msg_fatal("%s(%d)->%s: realloc: insufficient memory: %s", + pname, line, myname, strerror(errno)); +#else + if ((real_ptr = (MBLOCK *) realloc((char *) real_ptr, new_len)) == 0) + acl_msg_fatal("%s(%d)->%s: realloc: insufficient memory: %s", + pname, line, myname, strerror(errno)); +#endif + CHECK_OUT_PTR(ptr, real_ptr, len); +#if 0 + if (len > old_len) + memset((char *) ptr + old_len, FILLER, len - old_len); +#endif + + return (ptr); +} + +/* acl_default_free - release memory */ + +void acl_default_free(const char *filename, int line, void *ptr) +{ + const char *myname = "acl_default_free"; + MBLOCK *real_ptr; + size_t len; + const char *pname = NULL; + + if (filename && *filename) + SET_FILE(pname, filename); + else + pname = __FILENAME_UNKNOWN; + + if (ptr == NULL) { + acl_msg_error("%s(%d)->%s: ptr null", pname, line, myname); + return; + } + +# ifndef NO_SHARED_EMPTY_STRINGS + if (ptr != empty_string) { +# endif + CHECK_IN_PTR(ptr, real_ptr, len, pname, line); +/* + memset((char *) real_ptr, FILLER, SPACE_FOR(len)); +*/ +#ifdef _USE_GLIB + g_free(real_ptr); +#else + free((char *) real_ptr); +#endif +# ifndef NO_SHARED_EMPTY_STRINGS + } +# endif +} + +/* acl_default_strdup - save string to heap */ + +char *acl_default_strdup(const char *filename, int line, const char *str) +{ + const char *myname = "acl_default_strdup"; + const char *pname = NULL; + + if (filename && *filename) + SET_FILE(pname, filename); + else + pname = __FILENAME_UNKNOWN; + + if (str == 0) + acl_msg_fatal("%s(%d)->%s: null pointer argument", + pname, line, myname); + +#ifndef NO_SHARED_EMPTY_STRINGS + if (*str == 0) + return ((char *) empty_string); +#endif + return (strcpy(acl_default_malloc(pname, line, strlen(str) + 1), str)); +} + +/* acl_default_strndup - save substring to heap */ + +char *acl_default_strndup(const char *filename, int line, const char *str, size_t len) +{ + const char *myname = "acl_default_strndup"; + char *result; + char *cp; + const char *pname = NULL; + + if (filename && *filename) + SET_FILE(pname, filename); + else + pname = __FILENAME_UNKNOWN; + + if (str == 0) + acl_msg_fatal("%s(%d)->%s: null pointer argument", + pname, line, myname); + +#ifndef NO_SHARED_EMPTY_STRINGS + if (*str == 0) + return ((char *) empty_string); +#endif + if ((cp = memchr(str, 0, len)) != 0) + len = cp - str; + result = memcpy(acl_default_malloc(pname, line, len + 1), str, len); + result[len] = 0; + return (result); +} + +/* acl_default_memdup - copy memory */ + +void *acl_default_memdup(const char *filename, int line, const void *ptr, size_t len) +{ + const char *myname = "acl_default_memdup"; + const char *pname = NULL; + + if (filename && *filename) + SET_FILE(pname, filename); + else + pname = __FILENAME_UNKNOWN; + + if (ptr == 0) + acl_msg_fatal("%s(%d)->%s: null pointer argument", + pname, line, myname); + return (memcpy(acl_default_malloc(pname, line, len), ptr, len)); +} diff --git a/lib_acl/src/stdlib/memory/acl_malloc_glue.c b/lib_acl/src/stdlib/memory/acl_malloc_glue.c new file mode 100644 index 000000000..9aae43782 --- /dev/null +++ b/lib_acl/src/stdlib/memory/acl_malloc_glue.c @@ -0,0 +1,306 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_malloc.h" +#include "malloc_vars.h" +#include "stdlib/acl_msg.h" + +#endif + +#include "../../private/thread.h" + +static int __debug_mem = 0; + +static size_t __alloc_max = 1024000; +static int *__alloc_stat; +static int __alloc_over_1MB; + +static acl_pthread_mutex_t __fastmutex_stat; + +static size_t __malloc_length = 0; +static int __malloc_call_counter = 0; +static int __calloc_call_counter = 0; +static int __realloc_call_counter = 0; +static int __strdup_call_counter = 0; +static int __strndup_call_counter = 0; +static int __memdup_call_counter = 0; +static int __free_call_counter = 0; +static int __mem_counter = 0; +static int __mem_stack = 0; +/*----------------------------------------------------------------------------*/ +/* debug memory and display memory status */ + +#define MSTAT_LOCK thread_mutex_lock(&__fastmutex_stat) +#define MSTAT_UNLOCK thread_mutex_unlock(&__fastmutex_stat) + +void acl_memory_debug_start(void) +{ + __alloc_stat = calloc(__alloc_max, sizeof(int)); + acl_assert(__alloc_stat); + thread_mutex_init(&__fastmutex_stat, NULL); + __debug_mem = 1; +} + +void acl_memory_debug_stop(void) +{ + if (__alloc_stat) { + free(__alloc_stat); + __alloc_stat = NULL; + __debug_mem = 0; + thread_mutex_destroy(&__fastmutex_stat); + } +} + +void acl_memory_debug_stack(int onoff) +{ + __mem_stack = onoff; +} + +static void __mem_alloc_stat(void) +{ + size_t i; + + if (__alloc_max == 0 || __alloc_stat == NULL) + return; + + acl_msg_info("----------------alloc status--------------------------------"); + for (i = 0; i < __alloc_max; i++) { + if (__alloc_stat[i] > 0) + acl_msg_info("%d byte: %d", (int) i, __alloc_stat[i]); + } +} + +void acl_memory_stat(void) +{ + int n; + + if (!__debug_mem) { + acl_msg_warn("Please call acl_memory_debug first!"); + return; + } + + MSTAT_LOCK; + acl_msg_info("-----------------mem status---------------------------------"); + acl_msg_info("__malloc_call_counter = %d\r\n", __malloc_call_counter); + acl_msg_info("__calloc_call_counter = %d\r\n", __calloc_call_counter); + acl_msg_info("__realloc_call_counter = %d\r\n", __realloc_call_counter); + acl_msg_info("__strdup_call_counter = %d\r\n", __strdup_call_counter); + acl_msg_info("__strndup_call_counter = %d\r\n", __strndup_call_counter); + acl_msg_info("__memdup_call_counter = %d\r\n", __memdup_call_counter); + acl_msg_info("__free_call_counter = %d\r\n", __free_call_counter); + acl_msg_info("__malloc_length = %u\r\n", (unsigned int) __malloc_length); + n = __malloc_call_counter + + __calloc_call_counter + + __strdup_call_counter + + __strndup_call_counter + + __memdup_call_counter; + acl_msg_info("total malloc = %d, total free = %d, inter = %d\r\n", + n, __free_call_counter, n - __free_call_counter); + acl_msg_info("-----------------------------------------------------------\r\n"); + MSTAT_UNLOCK; +} + +void acl_memory_alloc_stat(void) +{ + __mem_alloc_stat(); +} + +/*----------------------------------------------------------------------------*/ + +void *(*__malloc_fn)(const char*, int, size_t) = acl_default_malloc; +void *(*__calloc_fn)(const char*, int, size_t, size_t) = acl_default_calloc; +void *(*__realloc_fn)(const char*, int, void*, size_t) = acl_default_realloc; +char *(*__strdup_fn)(const char*, int, const char*) = acl_default_strdup; +char *(*__strndup_fn)(const char*, int, const char*, size_t) = acl_default_strndup; +void *(*__memdup_fn)(const char*, int, const void*, size_t) = acl_default_memdup; +void (*__free_fn)(const char*, int, void*) = acl_default_free; + +void *acl_malloc_glue(const char *filename, int line, size_t size) +{ + if (__alloc_stat) { + if (size >= __alloc_max) + __alloc_over_1MB++; + else + __alloc_stat[size]++; + } + + if (__debug_mem) { + MSTAT_LOCK; + __malloc_call_counter++; + __mem_counter++; + __malloc_length += size; + MSTAT_UNLOCK; + if (__mem_stack) + acl_msg_info("malloc: file=%s, line=%d", filename, line); + } + + return (__malloc_fn(filename, line, size)); +} + +void *acl_calloc_glue(const char *filename, int line, size_t nmemb, size_t size) +{ + if (__alloc_stat) { + if (size >= __alloc_max) + __alloc_over_1MB++; + else + __alloc_stat[size]++; + } + + if (__debug_mem) { + MSTAT_LOCK; + __calloc_call_counter++; + __mem_counter++; + __malloc_length += size; + MSTAT_UNLOCK; + if (__mem_stack) + acl_msg_info("calloc: file=%s, line=%d", filename, line); + } + + return (__calloc_fn(filename, line, nmemb, size)); +} + +void *acl_realloc_glue(const char *filename, int line, void *ptr, size_t size) +{ + if (__alloc_stat) { + if (size >= __alloc_max) + __alloc_over_1MB++; + else + __alloc_stat[size]++; + } + + if (__debug_mem) { + MSTAT_LOCK; + __realloc_call_counter++; + if (__realloc_fn == acl_default_realloc) { + size_t len; + + acl_default_memstat(filename, line, ptr, &len, NULL); + __malloc_length -= len; + __malloc_length += size; + } + MSTAT_UNLOCK; + if (__mem_stack) + acl_msg_info("realloc: file=%s, line=%d", filename, line); + } + + return (__realloc_fn(filename, line, ptr, size)); +} + +char *acl_strdup_glue(const char *filename, int line, const char *str) +{ + if (__alloc_stat) { + size_t len = strlen(str); + + if (len >= __alloc_max) + __alloc_over_1MB++; + else + __alloc_stat[len]++; + } + + if (__debug_mem) { + MSTAT_LOCK; + __strdup_call_counter++; + __mem_counter++; + __malloc_length += strlen(str); + MSTAT_UNLOCK; + if (__mem_stack) + acl_msg_info("strdup: file=%s, line=%d", filename, line); + } + + return (__strdup_fn(filename, line, str)); +} + +char *acl_strndup_glue(const char *filename, int line, const char *str, size_t len) +{ + if (__alloc_stat) { + size_t n = strlen(str); + + n = n > len ? len : n; + if (n >= __alloc_max) + __alloc_over_1MB++; + else + __alloc_stat[n]++; + } + + if (__debug_mem) { + size_t n = strlen(str); + + MSTAT_LOCK; + __strndup_call_counter++; + __mem_counter++; + __malloc_length += len > n ? n: len; + MSTAT_UNLOCK; + if (__mem_stack) + acl_msg_info("strndup: file=%s, line=%d", filename, line); + } + + return (__strndup_fn(filename, line, str, len)); +} + +void *acl_memdup_glue(const char *filename, int line, const void *ptr, size_t len) +{ + if (__alloc_stat) { + if (len >= __alloc_max) + __alloc_over_1MB++; + else + __alloc_stat[len]++; + } + + if (__debug_mem) { + MSTAT_LOCK; + __memdup_call_counter++; + __mem_counter++; + __malloc_length += len; + MSTAT_UNLOCK; + if (__mem_stack) + acl_msg_info("memdup: file=%s, line=%d", filename, line); + } + + return (__memdup_fn(filename, line, ptr, len)); +} + +void acl_free_glue(const char *filename, int line, void *ptr) +{ + if (__debug_mem) { + MSTAT_LOCK; + __free_call_counter++; + __mem_counter--; + if (__free_fn == acl_default_free) { + size_t len; + + acl_default_memstat(filename, line, ptr, &len, NULL); + __malloc_length -= len; + } + MSTAT_UNLOCK; + if (__mem_stack) + acl_msg_info("free: file=%s, line=%d", filename, line); + } + + __free_fn(filename, line, ptr); +} + +void acl_free_fn_glue(void *ptr) +{ + if (__debug_mem) { + MSTAT_LOCK; + __free_call_counter++; + __mem_counter--; + if (__free_fn == acl_default_free) { + size_t len; + + acl_default_memstat("unknown", 0, ptr, &len, NULL); + __malloc_length -= len; + } + MSTAT_UNLOCK; + } + + __free_fn("unknown", 0, ptr); +} diff --git a/lib_acl/src/stdlib/memory/acl_mem_hook.c b/lib_acl/src/stdlib/memory/acl_mem_hook.c new file mode 100644 index 000000000..6f80c43e8 --- /dev/null +++ b/lib_acl/src/stdlib/memory/acl_mem_hook.c @@ -0,0 +1,63 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_msg.h" +#include "stdlib/acl_malloc.h" +#include "stdlib/acl_mem_hook.h" + +#endif + +#include "malloc_vars.h" + +void acl_mem_hook(void *(*malloc_hook)(const char*, int, size_t), + void *(*calloc_hook)(const char*, int, size_t, size_t), + void *(*realloc_hook)(const char*, int, void*, size_t), + char *(*strdup_hook)(const char*, int, const char*), + char *(*strndup_hook)(const char*, int, const char*, size_t), + void *(*memdup_hook)(const char*, int, const void*, size_t), + void (*free_hook)(const char*, int, void*)) +{ + const char *myname = "acl_mem_hook"; + + if (malloc_hook == NULL) { + acl_msg_error("%s(%d): malloc_hook null", myname, __LINE__); + } else if (calloc_hook == NULL) { + acl_msg_error("%s(%d): calloc_hook null", myname, __LINE__); + } else if (realloc_hook == NULL) { + acl_msg_error("%s(%d): realloc_hook null", myname, __LINE__); + } else if (strdup_hook == NULL) { + acl_msg_error("%s(%d): strdup_hook null", myname, __LINE__); + } else if (strndup_hook == NULL) { + acl_msg_error("%s(%d): strncup_hook null", myname, __LINE__); + } else if (memdup_hook == NULL) { + acl_msg_error("%s(%d): memdup_hook null", myname, __LINE__); + } else if (free_hook == NULL) { + acl_msg_error("%s(%d): free_hook null", myname, __LINE__); + } else { + __malloc_fn = malloc_hook; + __calloc_fn = calloc_hook; + __realloc_fn = realloc_hook; + __strdup_fn = strdup_hook; + __strndup_fn = strndup_hook; + __memdup_fn = memdup_hook; + __free_fn = free_hook; + } +} + +void acl_mem_unhook(void) +{ + __malloc_fn = acl_default_malloc; + __calloc_fn = acl_default_calloc; + __realloc_fn = acl_default_realloc; + __strdup_fn = acl_default_strdup; + __strndup_fn = acl_default_strndup; + __memdup_fn = acl_default_memdup; + __free_fn = acl_default_free; +} diff --git a/lib_acl/src/stdlib/memory/acl_mem_slice.c b/lib_acl/src/stdlib/memory/acl_mem_slice.c new file mode 100644 index 000000000..45b934f63 --- /dev/null +++ b/lib_acl/src/stdlib/memory/acl_mem_slice.c @@ -0,0 +1,542 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include /* for offsetof */ +#include "init/acl_init.h" +#include "stdlib/acl_mem_hook.h" +#include "stdlib/acl_malloc.h" +#include "stdlib/acl_slice.h" +#include "stdlib/acl_mem_slice.h" +#include "stdlib/acl_meter_time.h" + +#endif + +#include "../../private/private_array.h" +#include "malloc_vars.h" + +/* xxx: 如果想要使用 pthread_spinlock_t 则不可将 stdlib.h 放在前面, + * 否则编译报错 + */ + +#ifdef ACL_UNIX +# ifndef _GNU_SOURCE +# define _GNU_SOURCE +# endif +# ifndef __USE_XOPEN2K +# define __USE_XOPEN2K +# endif +# include +#endif + +#ifdef ACL_HAS_SPINLOCK +typedef pthread_spinlock_t mylock_t; + +#define MUTEX_INIT(x) pthread_spin_init(&(x)->lock, PTHREAD_PROCESS_PRIVATE) +#define MUTEX_DESTROY(x) pthread_spin_destroy(&(x)->lock) +#define MUTEX_LOCK(x) pthread_spin_lock(&(x)->lock) +#define MUTEX_UNLOCK(x) pthread_spin_unlock(&(x)->lock) + +#include "../../private/thread.h" + +#else + +#include "../../private/thread.h" + +typedef acl_pthread_mutex_t mylock_t; + +#define MUTEX_INIT(x) thread_mutex_init(&(x)->lock, NULL) +#define MUTEX_DESTROY(x) thread_mutex_destroy(&(x)->lock) +#define MUTEX_LOCK(x) thread_mutex_lock(&(x)->lock) +#define MUTEX_UNLOCK(x) thread_mutex_unlock(&(x)->lock) + +#endif + +#include "thread/acl_pthread.h" + +struct ACL_MEM_SLICE { + ACL_SLICE_POOL *slice_pool; /* 内存切片池 */ + mylock_t lock; /* 互斥锁 */ + ACL_ARRAY *list; /* 接管其它线程的释放内存的队列 */ + acl_pthread_key_t tls_key; /* 线程局部存储对应的键 */ + unsigned long tid; /* 拥有此线程池对象的线程ID号 */ + unsigned int nalloc; /* 调用内存分配的次数 */ + unsigned int nalloc_gc; /* 分配多少次内存后自动调用内存垃圾回收 */ + unsigned int slice_flag; /* 内存切片创建时的标志位, 如 ACL_SLICE_FLAG_GC2 | ACL_SLICE_FLAG_RTGC_OFF */ + ACL_ARRAY *slice_list; /* 所有线程的内存池的集合 */ + acl_pthread_mutex_t *slice_list_lock; /* 操作全局 __mem_slice_list 的互斥锁 */ + int delay_free; /* 当本线程退出时,因为还有内存片被其它线程占用着, + * 所以不能立即释放,需要由主线程或其它线程协助释放 + */ +}; + +#include "stdlib/acl_msg.h" +#include + +/*----------------------------------------------------------------------------*/ + +typedef struct { + size_t length; /* 调用者希望分配的内存大小 */ + int signature; /* 签名 */ + ACL_MEM_SLICE *mem_slice; /* 所属的内存切片对象 */ + union { + ALIGN_TYPE align; + char payload[1]; + } u; +} MBLOCK; + +#define SIGNATURE 0xdead +#define FILLER 0x0 + +#define CHECK_PTR(_ptr, _real_ptr, _len, _fname, _line) { \ + if (_ptr == 0) \ + acl_msg_panic("%s(%d): null pointer input", _fname, _line); \ + _real_ptr = (MBLOCK *) ((char *) _ptr - offsetof(MBLOCK, u.payload[0])); \ + if (_real_ptr->signature != SIGNATURE) \ + acl_msg_panic("%s(%d)(CHECK_PTR): corrupt or unallocated memory block(%d, 0x%x, 0x%x)", \ + _fname, _line, (int) _real_ptr->length, _real_ptr->signature, SIGNATURE); \ + if ((_len = _real_ptr->length) < 1) \ + acl_msg_panic("%s(%d): corrupt memory block length", _fname, _line); \ +} + +#define CHECK_IN_PTR(_ptr, _real_ptr, _len, _fname, _line) { \ + if (_ptr == 0) \ + acl_msg_panic("%s(%d): null pointer input", _fname, _line); \ + _real_ptr = (MBLOCK *) ((char *) _ptr - offsetof(MBLOCK, u.payload[0])); \ + if (_real_ptr->signature != SIGNATURE) \ + acl_msg_panic("%s(%d)(CHECK_IN_PTR): corrupt or unallocated memory block(%d, 0x%x, 0x%x)", \ + _fname, _line, (int) _real_ptr->length, _real_ptr->signature, SIGNATURE); \ + _real_ptr->signature = 0; \ + if ((_len = _real_ptr->length) < 1) \ + acl_msg_panic("%s(%d): corrupt memory block length", _fname, _line); \ +} + +#define CHECK_IN_PTR2(_ptr, _real_ptr, _len, _fname, _line) { \ + if (_ptr == 0) \ + acl_msg_panic("%s(%d): null pointer input", _fname, _line); \ + _real_ptr = (MBLOCK *) ((char *) _ptr - offsetof(MBLOCK, u.payload[0])); \ + if (_real_ptr->signature != SIGNATURE) \ + acl_msg_panic("%s(%d)(CHECK_IN_PTR2): corrupt or unallocated memory block(%d, 0x%x, 0x%x)", \ + _fname, _line, (int) _real_ptr->length, _real_ptr->signature, SIGNATURE); \ + if ((_len = _real_ptr->length) < 1) \ + acl_msg_panic("%s(%d): corrupt memory block length", _fname, _line); \ +} + +#define CHECK_OUT_PTR(_ptr, _real_ptr, _mem_slice, _len) { \ + _real_ptr->signature = SIGNATURE; \ + _real_ptr->mem_slice = _mem_slice; \ + _real_ptr->length = _len; \ + _ptr = _real_ptr->u.payload; \ +} + +#define SPACE_FOR(_len) (offsetof(MBLOCK, u.payload[0]) + _len) + +static acl_pthread_key_t __mem_slice_key = (acl_pthread_key_t) -1; +static int __mem_base = 8; +static int __mem_nslice = 1024; +static int __mem_nalloc_gc = 100; +static int __mem_list_init_size = 1000; +static unsigned int __mem_slice_flag = ACL_SLICE_FLAG_GC2 | ACL_SLICE_FLAG_RTGC_OFF; + +static ACL_ARRAY *__mem_slice_list = NULL; +static acl_pthread_mutex_t *__mem_slice_list_lock = NULL; + +static int mem_slice_gc(ACL_MEM_SLICE *mem_slice); + +/* 线程退出前需要调用此函数释放自己的线程局部内存存储池 */ + +static void mem_slice_free(ACL_MEM_SLICE *mem_slice) +{ + const char *myname = "mem_slice_free"; + int n; + + if (mem_slice == NULL) { + acl_msg_info("%s(%d): mem_slice null", myname, __LINE__); + return; + } + + /* 先回收本身线程的垃圾内存片 */ + mem_slice_gc(mem_slice); + + if ((n = acl_slice_pool_used(mem_slice->slice_pool)) > 0) { + acl_msg_info("%s(%d): thread(%ld) mem slice busy slices: %d, delay free it", + myname, __LINE__, mem_slice->tid, n); + + if (__mem_slice_list_lock) + thread_mutex_lock(__mem_slice_list_lock); + mem_slice->delay_free = 1; + if (__mem_slice_list_lock) + thread_mutex_unlock(__mem_slice_list_lock); + + /* 尽量回收一些已经完全释放的内存 */ + acl_slice_pool_gc(mem_slice->slice_pool); + } else { + acl_msg_info("%s(%d): thread(%ld) free mem slice now", + myname, __LINE__, mem_slice->tid); + acl_slice_pool_destroy(mem_slice->slice_pool); + private_array_destroy(mem_slice->list, NULL); + mem_slice->list = NULL; + + /* 将子线程的线程局部存储内存池从全局内存池句柄集合中删除 */ + if (__mem_slice_list_lock) + thread_mutex_lock(__mem_slice_list_lock); + private_array_delete_obj(__mem_slice_list, mem_slice, NULL); + if (__mem_slice_list_lock) + thread_mutex_unlock(__mem_slice_list_lock); + + acl_default_free(__FILE__, __LINE__, mem_slice); + } +} + +static ACL_MEM_SLICE *__main_mem_slice = NULL; + +static void main_thread_slice_free(void) +{ + if (__main_mem_slice) { + mem_slice_free(__main_mem_slice); + __main_mem_slice = NULL; + } +} + +static void free_global_ctx(void) +{ + if (__mem_slice_list) { + private_array_destroy(__mem_slice_list, NULL); + __mem_slice_list = NULL; + } + if (__mem_slice_list_lock) { + thread_mutex_destroy(__mem_slice_list_lock); + __mem_slice_list_lock = NULL; + } +} + +static void slice_key_init(void) +{ + unsigned long curr_tid = (unsigned long) acl_pthread_self(); + unsigned long main_tid = (unsigned long) acl_main_thread_self(); + + if (curr_tid == main_tid) { + acl_pthread_key_create(&__mem_slice_key, NULL); + atexit(main_thread_slice_free); + } else + acl_pthread_key_create(&__mem_slice_key, (void (*)(void*)) mem_slice_free); +} + +static acl_pthread_once_t once_control = ACL_PTHREAD_ONCE_INIT; + +static ACL_MEM_SLICE *mem_slice_create(void) +{ + const char *myname = "mem_slice_create"; + ACL_MEM_SLICE *mem_slice; + + acl_pthread_once(&once_control, slice_key_init); + + if (__mem_slice_key == (acl_pthread_key_t) -1) + acl_msg_fatal("%s(%d): __mem_slice_key(%d) invalid," + " call acl_mem_slice_init or acl_mem_slice_set first", + myname, __LINE__, (int) __mem_slice_key); + + mem_slice = acl_pthread_getspecific(__mem_slice_key); + if (mem_slice != NULL) + return (mem_slice); + + mem_slice = (ACL_MEM_SLICE*) + acl_default_calloc(__FILE__, __LINE__, 1, sizeof(ACL_MEM_SLICE)); + if (mem_slice == NULL) + acl_msg_fatal("%s(%d): can't alloc for mem_slice(%s)", + myname, __LINE__, acl_last_serror()); + + mem_slice->slice_pool = acl_slice_pool_create(__mem_base, + __mem_nslice, __mem_slice_flag); + mem_slice->tid = (unsigned long) acl_pthread_self(); + mem_slice->list = private_array_create(__mem_list_init_size); + MUTEX_INIT(mem_slice); + mem_slice->tls_key = __mem_slice_key; + mem_slice->nalloc_gc = __mem_nalloc_gc; + mem_slice->slice_flag = __mem_slice_flag; + + acl_pthread_setspecific(__mem_slice_key, mem_slice); + + if ((unsigned long) acl_pthread_self() == acl_main_thread_self()) + __main_mem_slice = mem_slice; + + acl_msg_info("%s(%d): thread(%ld) set myown mem_slice(%lx)", + myname, __LINE__, (long) mem_slice->tid, (long) mem_slice); + + return (mem_slice); +} + +static void tls_mem_free(const char *filename, int line, void *ptr) +{ + MBLOCK *real_ptr; + size_t len; + + CHECK_IN_PTR2(ptr, real_ptr, len, filename, line); + +#if 1 + if (real_ptr->mem_slice->tid != (unsigned long) acl_pthread_self()) { +#else + if (real_ptr->mem_slice->tid != mem_slice->tid) { +#endif + MUTEX_LOCK(real_ptr->mem_slice); + PRIVATE_ARRAY_PUSH(real_ptr->mem_slice->list, real_ptr); + MUTEX_UNLOCK(real_ptr->mem_slice); + } else + acl_slice_pool_free(filename, line, real_ptr); +} + +static void *tls_mem_alloc(const char *filename, int line, size_t len) +{ + const char *myname = "tls_mem_alloc"; + ACL_MEM_SLICE *mem_slice = acl_pthread_getspecific(__mem_slice_key); + char *ptr; + MBLOCK *real_ptr; + + if (mem_slice == NULL) { + /* 每个子线程获得自己的线程局部存储内存池 */ + mem_slice = mem_slice_create(); + mem_slice->slice_list = __mem_slice_list; + + /* 将子线程的线程局部存储内存池置入全局内存池句柄集合中 */ + if (__mem_slice_list_lock) + thread_mutex_lock(__mem_slice_list_lock); + private_array_push(__mem_slice_list, mem_slice); + if (__mem_slice_list_lock) + thread_mutex_unlock(__mem_slice_list_lock); + } + + real_ptr = (MBLOCK *) acl_slice_pool_alloc(filename, line, + mem_slice->slice_pool, SPACE_FOR(len)); + if (real_ptr == 0) { + acl_msg_error("%s(%d): malloc: insufficient memory", + myname, __LINE__); + return (0); + } + + mem_slice->nalloc++; + if (mem_slice->nalloc == mem_slice->nalloc_gc) { + mem_slice->nalloc = 0; + mem_slice_gc(mem_slice); + } + CHECK_OUT_PTR(ptr, real_ptr, mem_slice, len); + return (ptr); +} + +static void *tls_mem_calloc(const char *filename, int line, size_t nmemb, size_t size) +{ + void *ptr = tls_mem_alloc(filename, line, nmemb * size); + + memset(ptr, 0, nmemb * size); + return (ptr); +} + +static void *tls_mem_realloc(const char *filename, int line, void *ptr, size_t size) +{ + void *buf = tls_mem_alloc(filename, line, size); + MBLOCK *old_real_ptr; + size_t old_len; + + CHECK_IN_PTR2(ptr, old_real_ptr, old_len, filename, line); + memcpy(buf, ptr, old_len > size ? size : old_len); + if (old_real_ptr->mem_slice->tid != (unsigned long) acl_pthread_self()) { + MUTEX_LOCK(old_real_ptr->mem_slice); + PRIVATE_ARRAY_PUSH(old_real_ptr->mem_slice->list, old_real_ptr); + MUTEX_UNLOCK(old_real_ptr->mem_slice); + } else + acl_slice_pool_free(filename, line, old_real_ptr); + + return (buf); +} + +static void *tls_mem_memdup(const char *filename, int line, const void *ptr, size_t len) +{ + void *buf = tls_mem_alloc(filename, line, len); + + memcpy(buf, ptr, len); + return (buf); +} + +static char *tls_mem_strdup(const char *filename, int line, const char *str) +{ + size_t size = strlen(str) + 1; + void *buf = tls_mem_alloc(filename, line, size); + + memcpy(buf, str, size); + return ((char*) buf); +} + +static char *tls_mem_strndup(const char *filename, int line, const char *str, size_t len) +{ + size_t size = strlen(str); + char *buf; + + size = size > len ? len : size; + buf = (char*) tls_mem_alloc(filename, line, size + 1); + memcpy(buf, str, size); + return (buf); +} + +static int mem_slice_gc(ACL_MEM_SLICE *mem_slice) +{ + int n = 0; + + /* 释放由其它线程交还的内存片 */ + + MUTEX_LOCK(mem_slice); + while (1) { + void *ptr; + PRIVATE_ARRAY_POP(mem_slice->list, ptr); + if (ptr == NULL) + break; + acl_slice_pool_free(__FILE__, __LINE__, ptr); + n++; + } + MUTEX_UNLOCK(mem_slice); + /* 实时进行垃圾回收? */ + if ((mem_slice->slice_flag & ACL_SLICE_FLAG_RTGC_OFF) == 0) + acl_slice_pool_gc(mem_slice->slice_pool); + return (n); +} + +int acl_mem_slice_gc(void) +{ + ACL_MEM_SLICE *mem_slice = acl_pthread_getspecific(__mem_slice_key); + + if (!mem_slice) + return (-1); + return (mem_slice_gc(mem_slice)); +} + +void acl_mem_slice_destroy(void) +{ + ACL_MEM_SLICE *mem_slice = acl_pthread_getspecific(__mem_slice_key); + + if (mem_slice == NULL) + return; + /* 释放该线程所拥有的内存切片池对象 */ + mem_slice_free(mem_slice); + acl_pthread_setspecific(__mem_slice_key, NULL); + if ((unsigned long) acl_pthread_self() == acl_main_thread_self()) + __main_mem_slice = NULL; +} + +void acl_mem_slice_delay_destroy(void) +{ + const char *myname = "acl_mem_slice_delay_destroy"; + int i, n; + + if (__mem_slice_list_lock == NULL) + return; + + thread_mutex_lock(__mem_slice_list_lock); + n = private_array_size(__mem_slice_list); + for (i = 0; i < n; i++) { + ACL_MEM_SLICE *mem_slice = (ACL_MEM_SLICE*) + private_array_index(__mem_slice_list, i); + if (mem_slice == NULL) + break; + if (mem_slice->delay_free == 0) + continue; + if (acl_slice_pool_used(mem_slice->slice_pool) <= 0) { + acl_msg_info("%s(%d): thread(%ld) free mem slice now", + myname, __LINE__, mem_slice->tid); + + acl_slice_pool_destroy(mem_slice->slice_pool); + private_array_destroy(mem_slice->list, NULL); + mem_slice->list = NULL; + + /* 将子线程的线程局部存储内存池从全局内存池句柄集合中删除 */ + private_array_delete_obj(__mem_slice_list, mem_slice, NULL); + acl_default_free(__FILE__, __LINE__, mem_slice); + } else + mem_slice_gc(mem_slice); + } + + thread_mutex_unlock(__mem_slice_list_lock); +} + +ACL_MEM_SLICE *acl_mem_slice_init(int base, int nslice, + int nalloc_gc, unsigned int slice_flag) +{ + const char *myname = "acl_mem_slice_init"; + ACL_MEM_SLICE *mem_slice; + + if (__mem_slice_key != (acl_pthread_key_t) -1) { + acl_msg_error("%s(%d): has been init", myname, __LINE__); + return (NULL); + } + + __mem_base = base; + __mem_nslice = nslice; + __mem_nalloc_gc = nalloc_gc < 10 ? 10 : nalloc_gc; + __mem_slice_flag = slice_flag; + __mem_list_init_size = nalloc_gc / 10; + if (__mem_list_init_size < 1000) + __mem_list_init_size = 1000; + else if (__mem_list_init_size > 1000000) + __mem_list_init_size = 1000000; + + /* 主线程获得自己的线程局部存储内存池 */ + mem_slice = mem_slice_create(); + if (mem_slice == NULL) + acl_msg_fatal("%s(%d): mem_slice null", myname, __LINE__); + + /* 创建进程空间内全局的内存池集合对象, 其存储所有线程的存储内存池句柄 */ + __mem_slice_list = private_array_create(10); + __mem_slice_list_lock = thread_mutex_create(); + private_array_push(__mem_slice_list, mem_slice); + mem_slice->slice_list = __mem_slice_list; + mem_slice->slice_list_lock = __mem_slice_list_lock; + + if (__mem_slice_list == NULL) + acl_msg_fatal("%s(%d): __mem_slice_list null", myname, __LINE__); + if (__mem_slice_list_lock == NULL) + acl_msg_fatal("%s(%d): __mem_slice_list_lock null", myname, __LINE__); + + atexit(free_global_ctx); + + mem_slice->tls_key = __mem_slice_key; + + acl_mem_hook(tls_mem_alloc, + tls_mem_calloc, + tls_mem_realloc, + tls_mem_strdup, + tls_mem_strndup, + tls_mem_memdup, + tls_mem_free); + acl_msg_info("%s(%d): use ACL_MEM_SLICE, with tls", myname, __LINE__); + return (mem_slice); +} + +void acl_mem_slice_set(ACL_MEM_SLICE *mem_slice) +{ + const char *myname = "acl_mem_slice_set"; + + if (__mem_slice_key != (acl_pthread_key_t) -1) { + return; + } + + __mem_slice_key = mem_slice->tls_key; + __mem_base = mem_slice->slice_pool->base; + __mem_nslice = mem_slice->slice_pool->nslice; + __mem_nalloc_gc = mem_slice->nalloc_gc; + __mem_slice_flag = mem_slice->slice_flag; + __mem_slice_list = mem_slice->slice_list; + __mem_slice_list_lock = mem_slice->slice_list_lock; + + __mem_list_init_size = __mem_nalloc_gc / 10; + if (__mem_list_init_size < 1000) + __mem_list_init_size = 1000; + else if (__mem_list_init_size > 1000000) + __mem_list_init_size = 1000000; + + acl_mem_hook(tls_mem_alloc, + tls_mem_calloc, + tls_mem_realloc, + tls_mem_strdup, + tls_mem_strndup, + tls_mem_memdup, + tls_mem_free); + acl_msg_info("%s(%d): set ACL_MEM_SLICE, with tls", myname, __LINE__); +} diff --git a/lib_acl/src/stdlib/memory/acl_mempool.c b/lib_acl/src/stdlib/memory/acl_mempool.c new file mode 100644 index 000000000..c17d7484c --- /dev/null +++ b/lib_acl/src/stdlib/memory/acl_mempool.c @@ -0,0 +1,303 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include "stdlib/acl_mem_hook.h" +#include +#include +#include "stdlib/acl_malloc.h" +#include "stdlib/acl_mem_hook.h" + +#endif + +#include "malloc_vars.h" + +/* xxx: 如果想要使用 pthread_spinlock_t 则不可将 stdlib.h 放在前面, + * 否则编译报错 + */ + +#ifdef ACL_UNIX +# ifndef _GNU_SOURCE +# define _GNU_SOURCE +# endif +# ifndef __USE_XOPEN2K +# define __USE_XOPEN2K +# endif +# include +#endif + +#ifdef ACL_HAS_SPINLOCK +static pthread_spinlock_t __lock; + +#define MUTEX_INIT pthread_spin_init(&__lock, PTHREAD_PROCESS_PRIVATE) +#define MUTEX_DESTROY pthread_spin_destroy(&__lock) +#define MUTEX_LOCK pthread_spin_lock(&__lock) +#define MUTEX_UNLOCK pthread_spin_unlock(&__lock) + +#else + +#include "../../private/thread.h" + +static acl_pthread_mutex_t __lock; + +#define MUTEX_INIT thread_mutex_init(&__lock, NULL) +#define MUTEX_DESTROY thread_mutex_destroy(&__lock) +#define MUTEX_LOCK thread_mutex_lock(&__lock) +#define MUTEX_UNLOCK thread_mutex_unlock(&__lock) + +#endif + +#include "stdlib/acl_msg.h" +#include "stdlib/acl_allocator.h" + +static int __use_lock = 0; +static ACL_ALLOCATOR *__var_allocator = NULL; + +static void *mempool_malloc(const char *filename, int line, size_t size) +{ + return (acl_allocator_membuf_alloc(filename, line, __var_allocator, size)); +} + +static void *mempool_calloc(const char *filename, int line, size_t nmemb, size_t size) +{ + void *ptr; + + ptr = acl_allocator_membuf_alloc(filename, line, __var_allocator, nmemb * size); + memset(ptr, 0, nmemb * size); + return (ptr); +} + +static void *mempool_realloc(const char *filename, int line, void *ptr, size_t size) +{ + return (acl_allocator_membuf_realloc(filename, line, __var_allocator, ptr, size)); +} + +static char *mempool_strdup(const char *filename, int line, const char *str) +{ + char *ptr; + size_t size = strlen(str) + 1; + + ptr = acl_allocator_membuf_alloc(filename, line, __var_allocator, size); + strcpy(ptr, str); + return (ptr); +} + +static char *mempool_strndup(const char *filename, int line, const char *str, size_t len) +{ + char *ptr; + const char *cp; + + if ((cp = memchr(str, 0, len)) != 0) + len = cp - str; + ptr = acl_allocator_membuf_alloc(filename, line, __var_allocator, len + 1); + memcpy(ptr, str, len); + ptr[len] = 0; + + return (ptr); +} + +static void *mempool_memdup(const char *filename, int line, const void *ptr, size_t len) +{ + void *buf; + + buf = acl_allocator_membuf_alloc(filename, line, __var_allocator, len + 1); + memcpy(buf, ptr, len); + return (buf); +} + +static void mempool_free(const char *filename, int line, void *ptr) +{ + acl_allocator_membuf_free(filename, line, __var_allocator, ptr); +} + +static void *mempool_malloc_with_mutex(const char *filename, int line, size_t size) +{ + void *ptr; + + MUTEX_LOCK; + ptr = acl_allocator_membuf_alloc(filename, line, __var_allocator, size); + MUTEX_UNLOCK; + + return (ptr); +} + +static void *mempool_calloc_with_mutex(const char *filename, int line, size_t nmemb, size_t size) +{ + void *ptr; + + MUTEX_LOCK; + ptr = acl_allocator_membuf_alloc(filename, line, __var_allocator, nmemb * size); + MUTEX_UNLOCK; + + memset(ptr, 0, nmemb * size); + return (ptr); +} + +static void *mempool_realloc_with_mutex(const char *filename, int line, void *ptr, size_t size) +{ + void *buf; + + MUTEX_LOCK; + buf = acl_allocator_membuf_realloc(filename, line, __var_allocator, ptr, size); + MUTEX_UNLOCK; + + return (buf); +} + +static char *mempool_strdup_with_mutex(const char *filename, int line, const char *str) +{ + char *ptr; + size_t size = strlen(str) + 1; + + MUTEX_LOCK; + ptr = acl_allocator_membuf_alloc(filename, line, __var_allocator, size); + MUTEX_UNLOCK; + + strcpy(ptr, str); + return (ptr); +} + +static char *mempool_strndup_with_mutex(const char *filename, int line, const char *str, size_t len) +{ + char *ptr; + const char *cp; + + if ((cp = memchr(str, 0, len)) != 0) + len = cp - str; + MUTEX_LOCK; + ptr = acl_allocator_membuf_alloc(filename, line, __var_allocator, len + 1); + MUTEX_UNLOCK; + memcpy(ptr, str, len); + ptr[len] = 0; + + return (ptr); +} + +static void *mempool_memdup_with_mutex(const char *filename, int line, const void *ptr, size_t len) +{ + void *buf; + + MUTEX_LOCK; + buf = acl_allocator_membuf_alloc(filename, line, __var_allocator, len + 1); + MUTEX_UNLOCK; + + memcpy(buf, ptr, len); + return (buf); +} + +static void mempool_free_with_mutex(const char *filename, int line, void *ptr) +{ + MUTEX_LOCK; + acl_allocator_membuf_free(filename, line, __var_allocator, ptr); + MUTEX_UNLOCK; +} + +static void mempool_init_with_mutex(void) +{ + if (__use_lock == 0) { + MUTEX_INIT; + __use_lock = 1; + } + acl_mem_hook(mempool_malloc_with_mutex, + mempool_calloc_with_mutex, + mempool_realloc_with_mutex, + mempool_strdup_with_mutex, + mempool_strndup_with_mutex, + mempool_memdup_with_mutex, + mempool_free_with_mutex); +} + +static void mempool_init_no_mutex(void) +{ + acl_mem_hook(mempool_malloc, + mempool_calloc, + mempool_realloc, + mempool_strdup, + mempool_strndup, + mempool_memdup, + mempool_free); +} + +static void mempool_close(void) +{ + acl_mem_hook(acl_default_malloc, + acl_default_calloc, + acl_default_realloc, + acl_default_strdup, + acl_default_strndup, + acl_default_memdup, + acl_default_free); +} + +void acl_mempool_open(size_t max_size, int use_mutex) +{ + if (__var_allocator == NULL) + __var_allocator = acl_allocator_create(max_size); + + if (use_mutex) + mempool_init_with_mutex(); + else + mempool_init_no_mutex(); +} + +void acl_mempool_close(void) +{ + if (__use_lock) { + MUTEX_DESTROY; + __use_lock = 0; + } + + if (__var_allocator != NULL) { + acl_allocator_free(__var_allocator); + __var_allocator = NULL; + } + + mempool_close(); +} + +void acl_mempool_ctl(int name, ...) +{ + const char *myname = "acl_mempool_ctl"; + va_list ap; + int n; + + if (__var_allocator == NULL) + acl_msg_fatal("%s(%d): call acl_mempool_create first", myname, __LINE__); + + va_start(ap, name); + + for (; name != ACL_MEMPOOL_CTL_END; name = va_arg(ap, int)) { + switch (name) { + case ACL_MEMPOOL_CTL_MUTEX: + n = va_arg(ap, int); + if (n) + mempool_init_with_mutex(); + else + mempool_init_no_mutex(); + break; + case ACL_MEMPOOL_CTL_DISABLE: + n = va_arg(ap, int); + if (n) + mempool_close(); + break; + default: + acl_msg_panic("%s: bad name %d", myname, name); + } + } + va_end(ap); +} + +int acl_mempool_total_allocated() +{ + int n; + + if (__var_allocator == NULL) + return (0); + if (__use_lock) + MUTEX_LOCK; + n = acl_allocator_pool_total_allocated(__var_allocator); + if (__use_lock) + MUTEX_UNLOCK; + + return (n); +} diff --git a/lib_acl/src/stdlib/memory/acl_slice.c b/lib_acl/src/stdlib/memory/acl_slice.c new file mode 100644 index 000000000..6b915524c --- /dev/null +++ b/lib_acl/src/stdlib/memory/acl_slice.c @@ -0,0 +1,1295 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#ifdef ACL_UNIX +#include +#endif +#include +#include +#ifdef ACL_MS_WINDOWS +#include /* just for qsort */ +#endif +#include +#include "stdlib/acl_sys_patch.h" +#include "stdlib/acl_malloc.h" +#include "stdlib/acl_msg.h" +#include "stdlib/acl_slice.h" +#include "stdlib/acl_meter_time.h" + +#endif + +#include "ring.h" + +typedef struct MBUF_SLOTS { + void **slots; /* in which free slice can use */ + int islots; /* current position of free slots slice */ + int nslots; /* total slice count free in slots */ +} MBUF_SLOTS; + +struct ACL_SLICE { + char name[64]; /* the app's name */ + int page_nslots; /* count slice of each page */ + int page_size; /* length of MBUF's buf */ + int gap_size; /* gap_size = page_size - page_nslots * slice_size */ + int slice_length; /* length of each slice from app */ + int slice_size; /* the real size of each slice */ + int nbuf; /* count of MBUF allocated */ + acl_uint64 length; /* total size of all MBUF's buf */ + acl_uint64 used_length; /* total size of used */ + int nalloc; /* statistics: number of calling malloc */ + int nfree; /* statistics: number of calling free */ + unsigned int flag; /* as: ACL_SLICE_FLAG_XXX */ + + ACL_SLICE *(*slice_create)(int page_size, int slice_length); + void (*slice_destroy)(ACL_SLICE *slice); + + void *(*slice_alloc)(ACL_SLICE *slice); + void (*slice_free)(ACL_SLICE *slice, void *ptr); + int (*slice_gc)(ACL_SLICE *slice); /* 返回 1 表示已经释放完毕 */ + int (*slice_used)(ACL_SLICE *slice); + void (*slice_stat)(ACL_SLICE *slice, ACL_SLICE_STAT *sbuf); +}; + +/** + * MBUF1: 比较节省内存模式,但该方式在垃圾自动回收时比较费时, + * 比较适合于分配但不回收的情形 + */ + +typedef struct MBUF1 { + RING entry; /* linked by SLICE1->mbuf_head */ + void *buf; /* memory buf can be sliced */ +} MBUF1; + +typedef struct SLICE1 { + ACL_SLICE slice; /* the bases class */ + MBUF_SLOTS mslots; /* slice slots holding all slice of the mbuf */ + RING mbuf_head; /* link all mbuf's entry */ +} SLICE1; + +/* MBUF2, MBUF3 的基础类型 */ + +#define SIGNATURE 0xdead +#define SLICE_OFF_SIZE 4 + +typedef struct MBUF { + ACL_SLICE *slice; + int signature; /* set when block is active */ + int nused; /* number of using memory slice in payload */ +} MBUF; + +/** + * MBUF2: 内存稍微大点,但实时垃圾的自动回收性能比较好, 但如果某 + * 个 MBUF2 只要有一个结点被引用, 则该内存便不能被释放给系统 + */ + +#define SLICE2_HEAD_SIZE 8 + +typedef struct MBUF2 { + MBUF mbuf; + RING entry; /* be linked by SLICE2->mbuf_head */ + + /* in x64 CPU, sizeof before is 32 bytes */ + + char payload[1]; /* format: {off}{pos}{data}{off}{pos}{data}... */ +} MBUF2; + +typedef struct SLICE2 { + ACL_SLICE slice; /* the base class */ + MBUF_SLOTS mslots; /* slice slots holding all slice of the mbuf */ + RING mbuf_head; /* link all entry in MBUF2 */ +} SLICE2; + +/** + * MBUF3: 内存更大,当顺序分配同时顺序释放时回收内存效果更好, + * 但如果是随机释放则效率下降非常厉害,尤其当结点比较多时 + */ + +#define SLICE3_HEAD_SIZE 4 + +typedef struct MBUF3 { + MBUF mbuf; + MBUF_SLOTS mslots; /* slice slots holding all slice of the mbuf */ + int ibuf; /* position in SLICE3->mbufs array */ + + /* in x64 CPU, sizeof before is 36 bytes */ + + char payload[1]; /* format: {off}{data}{off}{data}... */ +} MBUF3; + +typedef struct SLICE3 { + ACL_SLICE slice; /* the base class */ + MBUF3 **mbufs; /* all MBUF3's array */ + int imbuf_avail; /* current available pos of MBUF3 in mbufs */ + int capacity; /* the mbufs array's size */ +} SLICE3; + +#define MBUF_SLOTS_SPACE(slice, mslots_in, incr, incr_real) do \ +{ \ + MBUF_SLOTS *mslots = mslots_in; \ + if (mslots->slots == NULL) { \ + incr_real = incr < slice->page_nslots ? slice->page_nslots : incr; \ + mslots->slots = (void **) acl_default_malloc(__FILE__, __LINE__, \ + sizeof(void*) * incr_real); \ + mslots->nslots = incr_real; \ + mslots->islots = 0; \ + } else if (mslots->islots + incr >= mslots->nslots) { \ + incr_real = incr < slice->page_nslots ? slice->page_nslots : incr; \ + mslots->nslots += incr_real; \ + mslots->slots = (void **) acl_default_realloc(__FILE__, __LINE__, \ + mslots->slots, sizeof(void*) * mslots->nslots); \ + } \ +} while (0) + +#define SLICE_MBUF_SPACE(slice_in, incr, incr_real, mbuf_type) do \ +{ \ + if (slice_in->mbufs == NULL) { \ + incr_real = incr > 16 ? incr : 16; \ + slice_in->mbufs = (mbuf_type**) acl_default_malloc(__FILE__, \ + __LINE__, sizeof(mbuf_type*) * incr_real); \ + slice_in->capacity = incr_real; \ + slice_in->imbuf_avail = 0; \ + } else if (slice_in->slice.nbuf + incr >= slice_in->capacity) { \ + incr_real = incr > 16 ? incr : 16; \ + slice_in->capacity += incr_real; \ + slice_in->mbufs = (mbuf_type**) \ + acl_default_realloc(__FILE__, __LINE__, slice_in->mbufs, \ + sizeof(mbuf_type*) * slice_in->capacity); \ + } \ +} while (0) + +/* forward declare */ + +#ifdef _LP64 +#include /* just for uintptr_t */ +#endif + +static void slice_init(ACL_SLICE *slice, unsigned int flag); + +/*------------------------- just for time min3 ------------------------------*/ + +static void slice3_mbuf_alloc(ACL_SLICE *slice) +{ +#ifdef _LP64 + const char *myname = "slice3_mbuf_alloc"; +#endif + SLICE3 *slice3 = (SLICE3*) slice; + MBUF3 *mbuf; + int i, incr_real = 0; + char *ptr; + + mbuf = (MBUF3*) acl_default_malloc(__FILE__, __LINE__, slice->page_size); + mbuf->mbuf.slice = slice; + mbuf->mbuf.nused = 0; + mbuf->mbuf.signature = SIGNATURE; + ptr = mbuf->payload; + + slice->nalloc++; + mbuf->mslots.slots = NULL; + + MBUF_SLOTS_SPACE(slice, &mbuf->mslots, slice->page_nslots, incr_real); + acl_assert(mbuf->mslots.islots == 0); + + for (i = 0; i < slice->page_nslots; i++) { + ptr += SLICE3_HEAD_SIZE; +#ifdef _LP64 + if ((slice->flag & ACL_SLICE_FLAG_LP64_ALIGN) && ((uintptr_t)ptr & 0x7) != 0) /* just for AVL */ + acl_msg_fatal("%s(%d): %s, ptr(%lx) invalid", + myname, __LINE__, slice->name, (long) ptr); +#endif + *((int*) (ptr - SLICE_OFF_SIZE)) = (int) (ptr - (char*) mbuf); + mbuf->mslots.slots[mbuf->mslots.islots++] = ptr; + ptr += slice->slice_length; + } + + for (i = slice->page_nslots; i < incr_real; i++) + mbuf->mslots.slots[i] = NULL; + + SLICE_MBUF_SPACE(slice3, 1, incr_real, MBUF3); + for (i = slice->nbuf; i < slice3->capacity; i++) + slice3->mbufs[i] = NULL; + slice3->mbufs[slice->nbuf] = mbuf; + mbuf->ibuf = slice->nbuf; + slice->nbuf++; + slice->length += slice->page_size + sizeof(void*) * slice->page_nslots; +} + +static void *slice3_alloc(ACL_SLICE *slice) +{ + SLICE3 *slice3 = (SLICE3*) slice; + MBUF3 *mbuf = NULL; + char *ptr; + int i; + + if (slice->nbuf == 0 || slice3->mbufs[slice->nbuf - 1]->mslots.islots == 0) + slice3_mbuf_alloc(slice); + + acl_assert(slice->nbuf > 0 && slice3->mbufs[slice->nbuf - 1]->mslots.islots > 0); + acl_assert(slice3->imbuf_avail >= 0 && slice3->imbuf_avail < slice->nbuf); + + if (slice3->mbufs[slice3->imbuf_avail]->mslots.islots == 0) { + for (i = slice3->imbuf_avail + 1; i < slice->nbuf; i++) { + if (slice3->mbufs[i]->mslots.islots > 0) { + mbuf = slice3->mbufs[i]; + slice3->imbuf_avail = i; + break; + } + } + acl_assert(mbuf && mbuf->mslots.islots > 0); + } else { + mbuf = slice3->mbufs[slice3->imbuf_avail]; + acl_assert(mbuf->mslots.islots > 0); + for (i = slice3->imbuf_avail - 1; i >= 0; i--) { + if (slice3->mbufs[i]->mslots.islots == 0) + break; + mbuf = slice3->mbufs[i]; + acl_assert(mbuf->mslots.islots > 0); + slice3->imbuf_avail = i; + } + acl_assert(mbuf->mslots.islots > 0); + } + + ptr = (char*) mbuf->mslots.slots[--mbuf->mslots.islots]; + slice->used_length += slice->slice_size; + mbuf->mbuf.nused++; + return (ptr); +} + +static void slice3_mbuf_free(ACL_SLICE *slice, MBUF3 *mbuf) +{ + SLICE3 *slice3 = (SLICE3*) slice; + + acl_assert(mbuf->ibuf + 1 == slice->nbuf); + + if (slice3->imbuf_avail == mbuf->ibuf) + slice3->imbuf_avail--; + if (slice3->imbuf_avail == -1) + slice3->imbuf_avail = 0; + + acl_default_free(__FILE__, __LINE__, mbuf->mslots.slots); + acl_default_free(__FILE__, __LINE__, mbuf); + slice->nbuf--; + slice->nfree++; + slice->length -= slice->page_size + sizeof(void*) * slice->page_nslots; +} + +static void slice3_free(ACL_SLICE *slice_dummy acl_unused, void *buf) +{ + const char *myname = "slice3_free"; + ACL_SLICE *slice; + SLICE3 *slice3; + char *ptr = (char*) buf; + int off; + MBUF3 *mbuf; + int i; + + off = *((int*)(ptr - SLICE_OFF_SIZE)); + mbuf = (MBUF3*) ((char*) buf - off); + if (mbuf->mbuf.signature != SIGNATURE) + acl_msg_fatal("%s(%d): off (%u), corrupt or unallocated memory block(0x%x, 0x%x)", + myname, __LINE__, off, mbuf->mbuf.signature, SIGNATURE); + + slice = mbuf->mbuf.slice; + slice3 = (SLICE3*) slice; + + acl_assert(mbuf->ibuf < (int) slice->nbuf); + acl_assert(mbuf->mslots.islots < mbuf->mslots.nslots); + + mbuf->mslots.slots[mbuf->mslots.islots++] = ptr; + mbuf->mbuf.nused--; + + for (i = mbuf->ibuf + 1; i < slice->nbuf; i++) { + if (slice3->mbufs[i]->mslots.islots >= mbuf->mslots.islots) + break; + slice3->mbufs[mbuf->ibuf] = slice3->mbufs[i]; + slice3->mbufs[i] = mbuf; + slice3->mbufs[mbuf->ibuf]->ibuf = mbuf->ibuf; + mbuf->ibuf = i; + } + + if (mbuf->mbuf.nused == 0 && !(slice->flag & ACL_SLICE_FLAG_RTGC_OFF)) + slice3_mbuf_free(slice, mbuf); + + slice->used_length -= slice->slice_size; +} + +static int slice3_gc(ACL_SLICE *slice) +{ + SLICE3 *slice3 = (SLICE3*) slice; + MBUF3 *mbuf; + int i; + + for (i = slice->nbuf - 1; i >= 0; i--) { + mbuf = slice3->mbufs[i]; + if (mbuf->mbuf.nused == 0) + slice3_mbuf_free(slice, mbuf); + else + return (0); + } + + return (1); +} + +static int slice3_used(ACL_SLICE *slice) +{ + SLICE3 *slice3 = (SLICE3*) slice; + MBUF3 *mbuf; + int i, n = 0; + + for (i = slice->nbuf - 1; i >= 0; i--) { + mbuf = slice3->mbufs[i]; + n += mbuf->mbuf.nused; + } + return (n); +} + +static void slice3_destroy(ACL_SLICE *slice) +{ + SLICE3 *slice3 = (SLICE3*) slice; + MBUF3 *mbuf; + int i; + + for (i = slice->nbuf - 1; i >= 0; i--) { + mbuf = slice3->mbufs[i]; + slice3_mbuf_free(slice, mbuf); + } + acl_default_free(__FILE__, __LINE__, slice3->mbufs); + acl_default_free(__FILE__, __LINE__, slice3); +} + +static void slice3_stat(ACL_SLICE *slice, ACL_SLICE_STAT *sbuf) +{ + SLICE3 *slice3 = (SLICE3*) slice; + MBUF3 *mbuf; + int i; + + sbuf->nslots = 0; + sbuf->islots = 0; + + for (i = 0; i < slice->nbuf; i++) { + mbuf = slice3->mbufs[i]; + sbuf->nslots += mbuf->mslots.nslots; + sbuf->islots += mbuf->mslots.islots; + } + + sbuf->page_nslots = slice->page_nslots; + sbuf->page_size = slice->page_size; + sbuf->slice_length = slice->slice_length; + sbuf->slice_size = slice->slice_size; + sbuf->nbuf = slice->nbuf; + sbuf->length = slice->length; + sbuf->used_length = slice->used_length; + sbuf->flag = slice->flag; +} + +static ACL_SLICE *slice3_create(int page_size, int slice_length, unsigned int flag) +{ + SLICE3 *slice; + int incr_real; + + slice = (SLICE3 *) acl_default_calloc(__FILE__, __LINE__, 1, sizeof(SLICE3)); + + /* call the base ACL_SLICE's init function */ + + slice_init((ACL_SLICE*) slice, flag); + + /* init the SLICE3's params */ + + SLICE_MBUF_SPACE(slice, 3202, incr_real, MBUF3); + +#ifdef _LP64 + if ((flag & ACL_SLICE_FLAG_LP64_ALIGN) != 0) { + if ((slice_length + SLICE3_HEAD_SIZE) % sizeof(uintptr_t) != 0) { + slice_length = ((slice_length + SLICE3_HEAD_SIZE) + / sizeof(uintptr_t) + 1) * sizeof(uintptr_t) + - SLICE3_HEAD_SIZE; + } + } +#endif + + /* reset the base ACL_SLICE's params */ + + slice->slice.slice_length = slice_length; + slice->slice.slice_size = slice_length + SLICE3_HEAD_SIZE; + slice->slice.page_size = page_size; + slice->slice.page_nslots = (page_size - sizeof(MBUF3)) /slice->slice.slice_size; + slice->slice.gap_size = page_size - slice->slice.page_nslots * slice->slice.slice_size; + + /* reset the base ACL_SLICE's callback */ + + slice->slice.slice_destroy = slice3_destroy; + slice->slice.slice_alloc = slice3_alloc; + slice->slice.slice_free = slice3_free; + slice->slice.slice_gc = slice3_gc; + slice->slice.slice_used = slice3_used; + slice->slice.slice_stat = slice3_stat; + + return ((ACL_SLICE*) slice); +} + +/*---------------------------- just for slice2 -------------------------------*/ + +static void slice2_mbuf_alloc(ACL_SLICE *slice) +{ +#ifdef _LP64 + const char *myname = "slice2_mbuf_alloc"; +#endif + SLICE2 *slice2 = (SLICE2*) slice; + MBUF2 *mbuf; + int i, incr_real = 0; + char *ptr; + + mbuf = (MBUF2*) acl_default_malloc(__FILE__, __LINE__, slice->page_size); + mbuf->mbuf.slice = slice; + mbuf->mbuf.nused = 0; + mbuf->mbuf.signature = SIGNATURE; + ring_append(&slice2->mbuf_head, &mbuf->entry); + ptr = mbuf->payload; + + slice->nalloc++; + MBUF_SLOTS_SPACE(slice, &slice2->mslots, slice->page_nslots, incr_real); + + for (i = 0; i < slice->page_nslots; i++) { + ptr += SLICE2_HEAD_SIZE; +#ifdef _LP64 + if ((slice->flag & ACL_SLICE_FLAG_LP64_ALIGN) && ((uintptr_t)ptr & 0x7) != 0) /* just for AVL */ + acl_msg_fatal("%s(%d): %s, ptr(%lx) invalid, slice_length: %d", + myname, __LINE__, slice->name, (long) ptr, slice->slice_length); +#endif + *((int*) (ptr - SLICE2_HEAD_SIZE)) = (int) slice2->mslots.islots; + *((int*) (ptr - SLICE_OFF_SIZE)) = (int) (ptr - (char*) mbuf); + slice2->mslots.slots[slice2->mslots.islots++] = ptr; + ptr += slice->slice_length; + } + + for (i = slice->page_nslots; i < incr_real; i++) + slice2->mslots.slots[i] = NULL; + + slice->nbuf++; + slice->length += slice->page_size; +} + +static void *slice2_alloc(ACL_SLICE *slice) +{ + const char *myname = "slice2_alloc"; + SLICE2 *slice2 = (SLICE2*) slice; + char *ptr; + MBUF2 *mbuf; + int off, pos; + + if (slice2->mslots.islots == 0) { + slice2_mbuf_alloc(slice); + } + + ptr = (char*) slice2->mslots.slots[--slice2->mslots.islots]; + slice->used_length += slice->slice_size; + + off = *((int*) (ptr - SLICE_OFF_SIZE)); + if (off < 0) + acl_msg_fatal("%s(%d): off(%d) invalid", myname, __LINE__, off); + pos = *((int*) (ptr - SLICE2_HEAD_SIZE)); + if (pos < 0) + acl_msg_fatal("%s(%d): pos(%d) invalid", myname, __LINE__, pos); + + mbuf = (MBUF2 *) (ptr - off); + + if (mbuf->mbuf.signature != SIGNATURE) { + acl_msg_info("%s(%d): %s, off(%d), nused(%d), islots(%d)" + ", used_length(%d), slice_size(%d), slice_length(%d)" + ", page_nslots(%d), page_size(%d)", myname, __LINE__, + slice->name, off, mbuf->mbuf.nused, + slice2->mslots.islots, (int) slice->used_length, + (int) slice->slice_size, (int) slice->slice_length, + slice->page_nslots, slice->page_size); + + acl_msg_fatal("%s(%d): %s, corrupt or unallocated memory block(0x%x, 0x%x)", + myname, __LINE__, slice->name, mbuf->mbuf.signature, SIGNATURE); + } + + /* reset the slice chunk's pos to -1 */ + *((int*) (ptr - SLICE2_HEAD_SIZE)) = -1; + + mbuf->mbuf.nused++; + return (ptr); +} + +static void slice2_mbuf_free(SLICE2 *slice2, MBUF2 *mbuf) +{ + const char *myname = "slice2_mbuf_free"; + char *ptr; + int i; + int pos; + +#if 0 + ptr = mbuf->payload; + for (i = 0; i < slice2->slice.page_nslots; i++) { + ptr += SLICE2_HEAD_SIZE; + pos = *((int*) (ptr - SLICE2_HEAD_SIZE)); + if (pos < 0 || pos >= slice2->mslots.islots) + acl_msg_fatal("%s(%d): %s, pos(%d) invalid, islots(%d), page_nslots(%d)", + myname, __LINE__, ((ACL_SLICE*) slice2)->name, + pos, slice2->mslots.islots, slice2->slice.page_nslots); + + if (slice2->mslots.slots[pos] != ptr) + acl_msg_fatal("%s(%d): pos(%d)'s(%lld, %lld) invalid", + myname, __LINE__, pos, slice2->mslots.slots[pos], ptr); + + if (pos + 1 < slice2->mslots.islots) { + slice2->mslots.slots[pos] = slice2->mslots.slots[slice2->mslots.islots -i - 1]; + + /* reset the slice chunk's pos */ + *((int*) ((char*) slice2->mslots.slots[pos] - SLICE2_HEAD_SIZE)) = pos; + } + ptr += slice2->slice.slice_length; + } + + slice2->mslots.islots -= slice2->slice.page_nslots; +#elif 0 + ptr = mbuf->payload; + for (i = 0; i < slice2->slice.page_nslots; i++) { + ptr += SLICE2_HEAD_SIZE; + pos = *((int*) (ptr - SLICE2_HEAD_SIZE)); + if (pos < 0) { + acl_msg_fatal("%s(%d): %s, pos(%d) invalid, islots(%d), page_nslots(%d)", + myname, __LINE__, ((ACL_SLICE*) slice2)->name, + pos, slice2->mslots.islots, slice2->slice.page_nslots); + } else if (pos + 1 > slice2->mslots.islots) { + ptr += slice2->slice.slice_length; + continue; + } else if (pos + 1 == slice2->mslots.islots) { + ptr += slice2->slice.slice_length; + slice2->mslots.islots--; + continue; + } + + if (slice2->mslots.slots[pos] != ptr) + acl_msg_fatal("%s(%d): pos(%d)'s(%lld, %lld) invalid", + myname, __LINE__, pos, slice2->mslots.slots[pos], ptr); + + slice2->mslots.slots[pos] = slice2->mslots.slots[--slice2->mslots.islots]; + /* reset the slice chunk's pos */ + *((int*) ((char*) slice2->mslots.slots[pos] - SLICE2_HEAD_SIZE)) = pos; + ptr += slice2->slice.slice_length; + } +#else + ptr = mbuf->payload + slice2->slice.slice_size * (slice2->slice.page_nslots - 1); + for (i = slice2->slice.page_nslots - 1; i >= 0; i--) { + pos = *((int*) (ptr)); + if (pos < 0) { + acl_msg_fatal("%s(%d): %s, pos(%d) invalid, islots(%d), page_nslots(%d)", + myname, __LINE__, ((ACL_SLICE*) slice2)->name, + pos, slice2->mslots.islots, slice2->slice.page_nslots); + } else if (pos + 1 > slice2->mslots.islots) { + ptr -= slice2->slice.slice_size; + continue; + } else if (pos + 1 == slice2->mslots.islots) { + ptr -= slice2->slice.slice_size; + slice2->mslots.islots--; + continue; + } + + if ((char*) slice2->mslots.slots[pos] != ptr + SLICE2_HEAD_SIZE) + acl_msg_fatal("%s(%d): pos(%d)'s(%p, %p) invalid", + myname, __LINE__, pos, + slice2->mslots.slots[pos], + (ptr + SLICE2_HEAD_SIZE)); + + slice2->mslots.slots[pos] = slice2->mslots.slots[--slice2->mslots.islots]; + /* reset the slice chunk's pos */ + *((int*) ((char*) slice2->mslots.slots[pos] - SLICE2_HEAD_SIZE)) = pos; + ptr -= slice2->slice.slice_size; + } +#endif + ring_detach(&mbuf->entry); + acl_default_free(__FILE__, __LINE__, mbuf); + slice2->slice.nbuf--; + slice2->slice.nfree++; +} + +static void slice2_free(ACL_SLICE *slice_dummy acl_unused, void *buf) +{ + const char *myname = "slice2_free"; + ACL_SLICE *slice; + SLICE2 *slice2; + char *ptr = (char*) buf; + int incr_real; + int off; + MBUF2 *mbuf; + + off = *((int*) (ptr - SLICE_OFF_SIZE)); + if (off < 0) + acl_msg_fatal("%s(%d): off(%d) invalid", myname, __LINE__, off); + + mbuf = (MBUF2 *) (ptr - off); + if (mbuf->mbuf.signature != SIGNATURE) + acl_msg_fatal("%s(%d), (off %d): corrupt or unallocated memory block(0x%x, 0x%x)", + myname, __LINE__, off, mbuf->mbuf.signature, SIGNATURE); + + slice = mbuf->mbuf.slice; + slice2 = (SLICE2*) slice; + + if (slice != slice_dummy) + acl_msg_fatal("%s(%d): %s invalid", myname, __LINE__, slice->name); + + if (mbuf->mbuf.nused <= 0) + acl_msg_fatal("%s(%d): %s, nused(%d) <= 0", + myname, __LINE__, slice->name, mbuf->mbuf.nused); + + MBUF_SLOTS_SPACE(slice, &slice2->mslots, 1, incr_real); + slice2->mslots.slots[slice2->mslots.islots] = ptr; + + /* reset the slice chunk's pos */ + *((int*) (ptr - SLICE2_HEAD_SIZE)) = (int) slice2->mslots.islots++; + + mbuf->mbuf.nused--; + if (mbuf->mbuf.nused == 0 && !(slice->flag & ACL_SLICE_FLAG_RTGC_OFF)) { + if (mbuf->payload > ptr - SLICE2_HEAD_SIZE) + acl_msg_fatal("%s(%d): %s, ptr overflow", + myname, __LINE__, slice->name); + slice2_mbuf_free(slice2, mbuf); + } + + slice->used_length -= slice->slice_size; +} + +static int slice2_gc(ACL_SLICE *slice) +{ + SLICE2 *slice2 = (SLICE2*) slice; + MBUF2 *mbuf; + RING *iter, *tmp; + + for (iter = ring_succ(&slice2->mbuf_head); iter != &slice2->mbuf_head;) { + tmp = ring_succ(iter); + mbuf = RING_TO_APPL(iter, MBUF2, entry); + if (mbuf->mbuf.nused == 0) { + slice2_mbuf_free(slice2, mbuf); + } else + return (0); + iter = tmp; + } + + return (1); +} + +static int slice2_used(ACL_SLICE *slice) +{ + SLICE2 *slice2 = (SLICE2*) slice; + MBUF2 *mbuf; + RING *iter; + int n = 0; + + for (iter = ring_succ(&slice2->mbuf_head); iter != &slice2->mbuf_head;) { + mbuf = RING_TO_APPL(iter, MBUF2, entry); + n += mbuf->mbuf.nused; + iter = ring_succ(iter); + } + return (n); +} + +static void slice2_destroy(ACL_SLICE *slice) +{ + SLICE2 *slice2 = (SLICE2*) slice; + RING *iter, *tmp; + MBUF2 *mbuf; + + for (iter = ring_succ(&slice2->mbuf_head); iter != &slice2->mbuf_head;) { + tmp = ring_succ(iter); + mbuf = RING_TO_APPL(iter, MBUF2, entry); + acl_default_free(__FILE__, __LINE__, mbuf); + iter = tmp; + } + + if (slice2->mslots.slots) + acl_default_free(__FILE__, __LINE__, slice2->mslots.slots); + acl_default_free(__FILE__, __LINE__, slice2); +} + +static void slice2_stat(ACL_SLICE *slice, ACL_SLICE_STAT *sbuf) +{ + SLICE2 *slice2 = (SLICE2*) slice; + + sbuf->nslots = slice2->mslots.nslots; + sbuf->islots = slice2->mslots.islots; + + sbuf->page_nslots = slice->page_nslots; + sbuf->page_size = slice->page_size; + sbuf->slice_length = slice->slice_length; + sbuf->slice_size = slice->slice_size; + sbuf->nbuf = slice->nbuf; + sbuf->length = slice->length; + sbuf->used_length = slice->used_length; + sbuf->flag = slice->flag; +} + +static ACL_SLICE *slice2_create(int page_size, int slice_length, unsigned int flag) +{ + SLICE2 *slice; + + slice = (SLICE2 *) acl_default_calloc(__FILE__, __LINE__, 1, sizeof(SLICE2)); + + /* call the base ACL_SLICE's init function */ + + slice_init((ACL_SLICE*) slice, flag); + + /* init the SLICE2's params */ + + slice->mslots.slots = NULL; + slice->mslots.nslots = 0; + slice->mslots.islots = 0; + + ring_init(&slice->mbuf_head); + +#ifdef _LP64 + if ((flag & ACL_SLICE_FLAG_LP64_ALIGN) != 0) { + if ((slice_length + SLICE2_HEAD_SIZE) % sizeof(uintptr_t) != 0) { + slice_length = ((slice_length + SLICE2_HEAD_SIZE) + / sizeof(uintptr_t) + 1) * sizeof(uintptr_t) + - SLICE2_HEAD_SIZE; + } + } +#endif + + /* reset the base ACL_SLICE's params */ + + slice->slice.slice_length = slice_length; + slice->slice.slice_size = slice_length + SLICE2_HEAD_SIZE; + slice->slice.page_size = page_size; + slice->slice.page_nslots = (page_size - sizeof(MBUF2)) /slice->slice.slice_size; + slice->slice.gap_size = page_size - slice->slice.page_nslots * slice->slice.slice_size; + + /* reset the base ACL_SLICE's callback */ + + slice->slice.slice_destroy = slice2_destroy; + slice->slice.slice_alloc = slice2_alloc; + slice->slice.slice_free = slice2_free; + slice->slice.slice_gc = slice2_gc; + slice->slice.slice_used = slice2_used; + slice->slice.slice_stat = slice2_stat; + + return ((ACL_SLICE*) slice); +} + +/*---------------------------- just for slice1 -------------------------------*/ + +static void slice1_mbuf_alloc(ACL_SLICE *slice) +{ + SLICE1 *slice1 = (SLICE1*) slice; + MBUF1 *mbuf = (MBUF1*) acl_default_malloc(__FILE__, __LINE__, sizeof(MBUF1)); + int i, incr_real = 0; + char *ptr; + + mbuf->buf = (void*) acl_default_malloc(__FILE__, __LINE__, slice->page_size); + ring_append(&slice1->mbuf_head, &mbuf->entry); + ptr = (char*) mbuf->buf; + + slice->nalloc++; + MBUF_SLOTS_SPACE(slice, &slice1->mslots, slice->page_nslots, incr_real); + + for (i = 0; i < slice->page_nslots; i++) { + slice1->mslots.slots[slice1->mslots.islots++] = ptr; + ptr += slice->slice_size; + } + for (i = slice->page_nslots; i < incr_real; i++) + slice1->mslots.slots[i] = NULL; + + slice->nbuf++; + slice->length += slice->page_size; +} + +static void *slice1_alloc(ACL_SLICE *slice) +{ + SLICE1 *slice1 = (SLICE1*) slice; + void *ptr; + + if (slice1->mslots.islots == 0) + slice1_mbuf_alloc(slice); + + ptr = slice1->mslots.slots[slice1->mslots.islots - 1]; + slice1->mslots.islots--; + slice->used_length += slice->slice_size; + return (ptr); +} + +static void slice1_free(ACL_SLICE *slice, void *ptr) +{ + SLICE1 *slice1 = (SLICE1*) slice; + int incr_real; + + MBUF_SLOTS_SPACE(slice, &slice1->mslots, 1, incr_real); + slice1->mslots.slots[slice1->mslots.islots++] = ptr; + slice->used_length -= slice->slice_size; +} + +static void slice1_mbuf_free(ACL_SLICE *slice, void *buf) +{ + const char *myname = "slice1_mbuf_free"; + SLICE1 *slice1 = (SLICE1*) slice; + RING *iter; + MBUF1 *mbuf; + +#if 0 + FOREACH_RING_FORWARD(iter, &slice->mbuf_head) { +#else + FOREACH_RING_BACKWARD(iter, &slice1->mbuf_head) { +#endif + mbuf = RING_TO_APPL(iter, MBUF1, entry); + if (buf == mbuf->buf) { + ring_detach(&mbuf->entry); + acl_default_free(__FILE__, __LINE__, mbuf->buf); + acl_default_free(__FILE__, __LINE__, mbuf); + slice->nbuf--; + slice->nfree++; + return; + } + } + + acl_msg_fatal("%s: unknown buf addr: 0x%lx", myname, buf ? (long) buf : 0); +} + +static int cmp_fn(const void *p1, const void *p2) +{ + acl_assert(p1); + acl_assert(p2); + return ((const char*) p1 - (const char*) p2); +} + +static int slice1_gc(ACL_SLICE *slice) +{ + const char *myname = "slice1_gc"; + SLICE1 *slice1 = (SLICE1*) slice; + char *ptr; + int i, length, j, n, k = -1; + + if (slice1->mslots.islots == 0) + return (1); + + qsort(slice1->mslots.slots, slice1->mslots.islots, sizeof(void*), cmp_fn); + + j = 0; + n = 0; + length = 0; + ptr = slice1->mslots.slots[j]; + for (i = 0; i < slice1->mslots.islots; i++) { + if (ptr + slice->slice_size * n++ != slice1->mslots.slots[i]) { + j = i; + n = 0; + ptr = slice1->mslots.slots[j]; + length = 0; + sleep(1); + continue; + } + + length += slice->slice_size; + if (length + slice->gap_size == slice->page_size) { + slice1_mbuf_free(slice, ptr); + slice1->mslots.islots -= n; + k = n; + break; + } + } + + if (slice1->mslots.islots > 0) { + for (i = 0; i < k; i++) { + slice1->mslots.slots[j + i] = slice1->mslots.slots[slice1->mslots.islots + i]; + if (slice1->mslots.slots[j + i] == NULL) + acl_msg_fatal("%s: slots[%d] null", myname, j + i); + } + } + + return (1); +} + +static void slice1_destroy(ACL_SLICE *slice) +{ + SLICE1 *slice1 = (SLICE1*) slice; + RING *iter, *tmp; + MBUF1 *mbuf; + + for (iter = ring_succ(&slice1->mbuf_head); iter != &slice1->mbuf_head;) { + tmp = ring_succ(iter); + mbuf = RING_TO_APPL(iter, MBUF1, entry); + acl_default_free(__FILE__, __LINE__, mbuf->buf); + acl_default_free(__FILE__, __LINE__, mbuf); + iter = tmp; + } + if (slice1->mslots.slots) + acl_default_free(__FILE__, __LINE__, slice1->mslots.slots); + acl_default_free(__FILE__, __LINE__, slice1); +} + +static int slice1_used(ACL_SLICE *slice acl_unused) +{ + const char *myname = "slice1_used"; + + acl_msg_warn("%s(%d): not implement yet!", myname, __LINE__); + return (0); +} + +static void slice1_stat(ACL_SLICE *slice, ACL_SLICE_STAT *sbuf) +{ + SLICE1 *slice1 = (SLICE1*) slice; + + sbuf->nslots = slice1->mslots.nslots; + sbuf->islots = slice1->mslots.islots; + + sbuf->page_nslots = slice->page_nslots; + sbuf->page_size = slice->page_size; + sbuf->slice_length = slice->slice_length; + sbuf->slice_size = slice->slice_size; + sbuf->nbuf = slice->nbuf; + sbuf->length = slice->length; + sbuf->used_length = slice->used_length; + sbuf->flag = slice->flag; +} + +static ACL_SLICE *slice1_create(int page_size, int slice_length, unsigned int flag) +{ + SLICE1 *slice; + + slice = (SLICE1 *) acl_default_calloc(__FILE__, __LINE__, 1, sizeof(SLICE1)); + + /* call the base ACL_SLICE's init function */ + + slice_init((ACL_SLICE*) slice, flag); + + /* init the SLICE1's params */ + + slice->mslots.slots = NULL; + slice->mslots.nslots = 0; + slice->mslots.islots = 0; + + /* reset the base ACL_SLICE's params */ + slice->slice.slice_length = slice_length; + slice->slice.slice_size = slice_length; + slice->slice.page_size = page_size; + slice->slice.page_nslots = page_size / slice->slice.slice_size; + slice->slice.gap_size = page_size - slice->slice.page_nslots * slice->slice.slice_size; + + /* set the base ACL_SLICE's callback */ + + slice->slice.slice_destroy = slice1_destroy; + slice->slice.slice_alloc = slice1_alloc; + slice->slice.slice_free = slice1_free; + slice->slice.slice_gc = slice1_gc; + slice->slice.slice_used = slice1_used; + slice->slice.slice_stat = slice1_stat; + + /* init the SLICE1's params */ + + ring_init(&slice->mbuf_head); + + return ((ACL_SLICE*) slice); +} + +/*------------------------ public functions -----------------------------*/ + +void acl_slice_stat(ACL_SLICE *slice, ACL_SLICE_STAT *sbuf) +{ + slice->slice_stat(slice, sbuf); +} + +static void slice_init(ACL_SLICE *slice, unsigned int flag) +{ + slice->nbuf = 0; + slice->length = 0; + slice->used_length = 0; + slice->nalloc = 0; + slice->nfree = 0; + slice->flag = flag; +} + +ACL_SLICE *acl_slice_create(const char *name, int page_size, + int slice_length, unsigned int flag) +{ + const char *myname = "acl_slice_create"; + ACL_SLICE *slice = NULL; + int size, sys_page_size; + +#ifdef ACL_UNIX + sys_page_size = getpagesize(); +#elif defined(ACL_MS_WINDOWS) + SYSTEM_INFO info; + + memset(&info, 0, sizeof(SYSTEM_INFO)); + GetSystemInfo(&info); + sys_page_size = info.dwPageSize; + if (sys_page_size <= 0) + sys_page_size = 4096; +#else + sys_page_size = 4096; +#endif + + size = ((page_size - 1) / sys_page_size + 1) * sys_page_size; + if (size <= 4096) + size = sys_page_size; + + if (size / slice_length < 2) { + acl_msg_warn("%s: slice_length(%d). page_size(%d)" + " maybe too small, please increase it.", + myname, slice_length, page_size); + return (NULL); + } + + if ((flag & ACL_SLICE_FLAG_GC1)) + slice = slice1_create(size, slice_length, flag); + else if ((flag & ACL_SLICE_FLAG_GC2)) + slice = slice2_create(size, slice_length, flag); + else if ((flag & ACL_SLICE_FLAG_GC3)) + slice = slice3_create(size, slice_length, flag); + else { + acl_msg_error("%s: flag invalid", myname); + return (NULL); + } + + snprintf(slice->name, sizeof(slice->name), "%s", name); + return (slice); +} + +void acl_slice_destroy(ACL_SLICE *slice) +{ + slice->slice_destroy(slice); +} + +int acl_slice_used(ACL_SLICE *slice) +{ + return (slice->slice_used(slice)); +} + +void *acl_slice_alloc(ACL_SLICE *slice) +{ + return (slice->slice_alloc(slice)); +} + +void *acl_slice_calloc(ACL_SLICE *slice) +{ + char *ptr = slice->slice_alloc(slice); + + if (ptr) + memset(ptr, 0, slice->slice_length); + return (ptr); +} + +void acl_slice_free2(ACL_SLICE *slice, void *ptr) +{ + slice->slice_free(slice, ptr); +} + +void acl_slice_free(void *ptr) +{ + const char *myname = "acl_slice_free"; + int off; + MBUF *mbuf; + ACL_SLICE *slice; + + off = *((int*) ((char*) ptr - SLICE_OFF_SIZE)); + if (off < 0) + acl_msg_fatal("%s(%d): off(%d) invalid", myname, __LINE__, off); + mbuf = (MBUF *) ((char*) ptr - off); + slice = mbuf->slice; + slice->slice_free(slice, ptr); +} + +int acl_slice_gc(ACL_SLICE *slice) +{ + return (slice->slice_gc(slice)); +} + +/*----------------------------------------------------------------------------*/ + +void acl_slice_pool_init(ACL_SLICE_POOL *asp) +{ + int i; + + for (i = 0; i < asp->nslice; i++) { + char name[256]; + int elsize = asp->base * (i + 1), page_size, n; + + snprintf(name, sizeof(name), "(memory SIZE: %d)", elsize); + if (elsize >= 102400) + n = 10; + else if (elsize >= 81920) + n = 10; + else if (elsize >= 40960) + n = 10; + else if (elsize >= 20480) + n = 20; + else if (elsize >= 10240) + n = 20; + else if (elsize >= 8192) + n = 20; + else if (elsize >= 4096) + n = 30; + else if (elsize >= 2048) + n = 30; + else if (elsize >= 1024) + n = 30; + else if (elsize >= 512) + n = 40; + else if (elsize >= 256) + n = 40; + else if (elsize >= 128) + n = 40; + else if (elsize >= 64) + n = 50; + else if (elsize >= 32) + n = 50; + else if (elsize >= 16) + n = 50; + else + n = 50; + page_size = elsize * n; + asp->slices[i] = acl_slice_create(name, page_size, + elsize, asp->slice_flag); + } +} + +ACL_SLICE_POOL *acl_slice_pool_create(int base, int nslice, unsigned int slice_flag) +{ + ACL_SLICE_POOL *asp = (ACL_SLICE_POOL*) + acl_default_calloc(__FILE__, __LINE__, 1, sizeof(*asp)); + + asp->base = base; + asp->nslice = nslice; + asp->slice_flag = slice_flag; + asp->slices = (ACL_SLICE**) acl_default_calloc(__FILE__, __LINE__, + nslice, sizeof(ACL_SLICE)); + acl_slice_pool_init(asp); + return (asp); +} + +void acl_slice_pool_destroy(ACL_SLICE_POOL *asp) +{ + int i; + + for (i = 0; i < asp->nslice; i++) { + acl_slice_destroy(asp->slices[i]); + } + + acl_default_free(__FILE__, __LINE__, asp->slices); + acl_default_free(__FILE__, __LINE__, asp); +} + +int acl_slice_pool_used(ACL_SLICE_POOL *asp) +{ + int i, n = 0; + + for (i = 0; i < asp->nslice; i++) { + n += acl_slice_used(asp->slices[i]); + } + + return (n); +} + +void acl_slice_pool_gc(ACL_SLICE_POOL *asp) +{ + int i; + + for (i = 0; i < asp->nslice; i++) { + acl_slice_gc(asp->slices[i]); + } +} + +void acl_slice_pool_clean(ACL_SLICE_POOL *asp) +{ + int i; + + for (i = 0; i < asp->nslice; i++) { + acl_slice_destroy(asp->slices[i]); + asp->slices[i] = NULL; + } +} + +void acl_slice_pool_reset(ACL_SLICE_POOL *asp) +{ + acl_slice_pool_clean(asp); + acl_slice_pool_init(asp); +} + +void acl_slice_pool_free(const char *filename, int line, void *buf) +{ + char *ptr = (char*) buf; + + ptr -= sizeof(size_t); /* 移至内存头的标志位 */ + if (*((size_t*) ptr) == 0) + acl_default_free(filename, line, ptr); + else { + acl_slice_free(ptr); + } +} + +void *acl_slice_pool_alloc(const char *filename, int line, + ACL_SLICE_POOL *asp, size_t size) +{ + char *ptr; + int n; + + size += sizeof(size_t); /* 头部留出空间做为标志位 */ + if (asp == NULL || (int) size >= asp->base * asp->nslice) { + ptr = (char*) acl_default_malloc(filename, line, size); + if (ptr) { + *((size_t*) ptr) = 0; + ptr += sizeof(size_t); + } + return (ptr); + } + n = (int) size / asp->base; + if (size % asp->base != 0) + n++; + + ptr = (char*) acl_slice_alloc(asp->slices[n - 1]); + if (ptr) { + *((size_t*) ptr) = 1; + ptr += sizeof(size_t); + } + return (ptr); +} + +void *acl_slice_pool_calloc(const char *filename, int line, + ACL_SLICE_POOL *asp, size_t nmemb, size_t size) +{ + void *ptr = acl_slice_pool_alloc(filename, line, asp, nmemb * size); + + if (ptr) + memset(ptr, 0, nmemb * size); + return (ptr); +} + +void *acl_slice_pool_realloc(const char *filename, int line, + ACL_SLICE_POOL *asp, void *ptr, size_t size) +{ + void *buf; + + buf = acl_slice_pool_alloc(filename, line, asp, size); + memcpy(buf, ptr, size); + acl_slice_pool_free(filename, line, ptr); + return (buf); +} + +void *acl_slice_pool_memdup(const char *filename, int line, + ACL_SLICE_POOL *asp, const void *ptr, size_t len) +{ + void *buf = acl_slice_pool_alloc(filename, line, asp, len); + + memcpy(buf, ptr, len); + return (buf); +} + +char *acl_slice_pool_strdup(const char *filename, int line, + ACL_SLICE_POOL *asp, const char *str) +{ + size_t n = strlen(str) + 1; + char *ptr = (char*) acl_slice_pool_alloc(filename, line, asp, n); + + memcpy(ptr, str, n); + return (ptr); +} + +char *acl_slice_pool_strndup(const char *filename, int line, + ACL_SLICE_POOL *asp, const char *str, size_t len) +{ + char *ptr = (char*) acl_slice_pool_alloc(filename, line, asp, len + 1); + + memcpy(ptr, str, len); + ptr[len] = 0; + return (ptr); +} diff --git a/lib_acl/src/stdlib/memory/allocator.h b/lib_acl/src/stdlib/memory/allocator.h new file mode 100644 index 000000000..4a611b70f --- /dev/null +++ b/lib_acl/src/stdlib/memory/allocator.h @@ -0,0 +1,60 @@ +#ifndef __ALLOCATOR_INCLUDE_H__ +#define __ALLOCATOR_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_define.h" +#include "stdlib/acl_stack.h" +#include "stdlib/acl_allocator.h" + +struct ACL_MEM_POOL { + ACL_STACK *pstack; /* stack for free pointers */ + const char *label; + size_t obj_size; + acl_mem_type type; +#if DEBUG_MEMPOOL + size_t real_obj_size; /* with alignment */ +#endif + void (*after_alloc_fn)(void *obj, void *pool_ctx); + void (*before_free_fn)(void *obj, void *pool_ctx); + void *pool_ctx; +}; + +struct ACL_ALLOCATOR { + ACL_STACK *pools; + size_t mem_idle_limit; + unsigned int mem_pool_alloc_calls; + unsigned int mem_pool_free_calls; + ACL_MEM_POOL *MemPools[ACL_MEM_TYPE_MAX]; + + ACL_MEM_POOL *(*pool_create_fn)(void); + void (*pool_config_fn)(ACL_ALLOCATOR *, size_t); + void (*pool_destroy_fn)(ACL_MEM_POOL *); + void (*pool_clean_fn)(ACL_ALLOCATOR *); + + int (*pool_if_used)(const ACL_MEM_POOL *); + int (*pool_inuse_count)(const ACL_MEM_POOL *); + size_t (*pool_inuse_size)(const ACL_MEM_POOL *); + size_t (*pool_total_allocated)(ACL_ALLOCATOR *); + + void *(*mem_alloc_fn)(ACL_ALLOCATOR *, ACL_MEM_POOL *); + void (*mem_free_fn)(ACL_ALLOCATOR *, ACL_MEM_POOL *, void *); +}; + +/* in acl_allocator.c */ +extern ACL_ALLOCATOR *allocator_alloc(size_t size); + +/* in vstring_pool.c */ +extern void vstring_pool_create(ACL_ALLOCATOR *allocator); + +/* in membuf_pool.c */ +extern void mem_pool_create(ACL_ALLOCATOR *allocator); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/src/stdlib/memory/malloc_vars.h b/lib_acl/src/stdlib/memory/malloc_vars.h new file mode 100644 index 000000000..413b4de99 --- /dev/null +++ b/lib_acl/src/stdlib/memory/malloc_vars.h @@ -0,0 +1,20 @@ +#ifndef __MALLOC_VARS_INCLUDE_H__ +#define __MALLOC_VARS_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +extern void *(*__malloc_fn)(const char*, int, size_t); +extern void *(*__calloc_fn)(const char*, int, size_t, size_t); +extern void *(*__realloc_fn)(const char*, int, void*, size_t); +extern char *(*__strdup_fn)(const char*, int, const char*); +extern char *(*__strndup_fn)(const char*, int, const char*, size_t); +extern void *(*__memdup_fn)(const char*, int, const void*, size_t); +extern void (*__free_fn)(const char*, int, void*); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/src/stdlib/memory/mem_pool.c b/lib_acl/src/stdlib/memory/mem_pool.c new file mode 100644 index 000000000..e4a094f5f --- /dev/null +++ b/lib_acl/src/stdlib/memory/mem_pool.c @@ -0,0 +1,56 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_allocator.h" + +#endif + +#include "allocator.h" + +void mem_pool_create(ACL_ALLOCATOR *allocator) +{ + acl_allocator_pool_add(allocator, "8 Buffer", 8, + ACL_MEM_TYPE_8_BUF, NULL, NULL, NULL); + acl_allocator_pool_add(allocator, "16 Buffer", 16, + ACL_MEM_TYPE_16_BUF, NULL, NULL, NULL); + acl_allocator_pool_add(allocator, "32 Buffer", 32, + ACL_MEM_TYPE_32_BUF, NULL, NULL, NULL); + acl_allocator_pool_add(allocator, "64 Buffer", 64, + ACL_MEM_TYPE_64_BUF, NULL, NULL, NULL); + acl_allocator_pool_add(allocator, "128 Buffer", 128, + ACL_MEM_TYPE_128_BUF, NULL, NULL, NULL); + acl_allocator_pool_add(allocator, "256 Buffer", 256, + ACL_MEM_TYPE_256_BUF, NULL, NULL, NULL); + acl_allocator_pool_add(allocator, "512 Buffer", 512, + ACL_MEM_TYPE_512_BUF, NULL, NULL, NULL); + acl_allocator_pool_add(allocator, "1K Buffer", 1024, + ACL_MEM_TYPE_1K_BUF, NULL, NULL, NULL); + acl_allocator_pool_add(allocator, "2K Buffer", 2048, + ACL_MEM_TYPE_2K_BUF, NULL, NULL, NULL); + acl_allocator_pool_add(allocator, "4K Buffer", 4096, + ACL_MEM_TYPE_4K_BUF, NULL, NULL, NULL); + acl_allocator_pool_add(allocator, "8K Buffer", 8192, + ACL_MEM_TYPE_8K_BUF, NULL, NULL, NULL); + acl_allocator_pool_add(allocator, "16K Buffer", 16384, + ACL_MEM_TYPE_16K_BUF, NULL, NULL, NULL); + acl_allocator_pool_add(allocator, "32K Buffer", 32768, + ACL_MEM_TYPE_32K_BUF, NULL, NULL, NULL); + acl_allocator_pool_add(allocator, "64K Buffer", 65536, + ACL_MEM_TYPE_64K_BUF, NULL, NULL, NULL); + + acl_allocator_pool_add(allocator, "128K Buffer", 131072, + ACL_MEM_TYPE_128K_BUF, NULL, NULL, NULL); + acl_allocator_pool_add(allocator, "256K Buffer", 262144, + ACL_MEM_TYPE_256K_BUF, NULL, NULL, NULL); + acl_allocator_pool_add(allocator, "512K Buffer", 524288, + ACL_MEM_TYPE_512K_BUF, NULL, NULL, NULL); + acl_allocator_pool_add(allocator, "1M Buffer", 1048576, + ACL_MEM_TYPE_1M_BUF, NULL, NULL, NULL); +} + diff --git a/lib_acl/src/stdlib/memory/ring.h b/lib_acl/src/stdlib/memory/ring.h new file mode 100644 index 000000000..246daa6b6 --- /dev/null +++ b/lib_acl/src/stdlib/memory/ring.h @@ -0,0 +1,79 @@ + +#ifndef _RING_H_INCLUDE_ +#define _RING_H_INCLUDE_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +typedef struct RING RING; + +struct RING { + RING *succ; /* successor */ + RING *pred; /* predecessor */ +}; + +#define ring_init(ring_in) do \ +{ \ + RING *ring = ring_in; \ + ring->pred = ring->succ = ring; \ +} while (0) + +#define ring_append(ring_in, entry_in) do \ +{ \ + RING *ring = ring_in; \ + RING *entry = entry_in; \ + entry->succ = ring->succ; \ + entry->pred = ring; \ + ring->succ->pred = entry; \ + ring->succ = entry; \ +} while (0) + +#define ring_prepend(ring_in, entry_in) do \ +{ \ + RING *ring = ring_in; \ + RING *entry = entry_in; \ + entry->pred = ring->pred; \ + entry->succ = ring; \ + ring->pred->succ = entry; \ + ring->pred = entry; \ +} while (0) + +#define ring_detach(entry_in) do \ +{ \ + RING *entry = entry_in; \ + RING *succ; \ + RING *pred; \ + succ = entry->succ; \ + pred = entry->pred; \ + if (succ != NULL && pred != NULL) { \ + pred->succ = succ; \ + succ->pred = pred; \ + entry->succ = entry->pred = 0; \ + } \ +} while (0) + +#define ring_succ(c) ((c)->succ) +#define ring_pred(c) ((c)->pred) + +#define RING_TO_APPL(ring_ptr, app_type, ring_member) \ + ((app_type *) (((char *) (ring_ptr)) - offsetof(app_type,ring_member))) + +#define FOREACH_RING_FORWARD(entry, head) \ + for (entry = ring_succ(head); entry != (head); entry = ring_succ(entry)) + +#define FOREACH_RING_BACKWARD(entry, head) \ + for (entry = ring_pred(head); entry != (head); entry = ring_pred(entry)) + +#define FIRST_APPL(head, app_type, ring_member) \ + (ring_succ(head) != (head) ? \ + RING_TO_APPL(ring_succ(head), app_type, ring_member) : 0) + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/src/stdlib/memory/squid_allocator.c b/lib_acl/src/stdlib/memory/squid_allocator.c new file mode 100644 index 000000000..44b42f3f3 --- /dev/null +++ b/lib_acl/src/stdlib/memory/squid_allocator.c @@ -0,0 +1,356 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_msg.h" +#include "stdlib/acl_malloc.h" +#include "stdlib/acl_allocator.h" +#include "stdlib/acl_stack.h" + +#endif + +#include "allocator.h" +#include "squid_allocator.h" + +/* huge constant to set mem_idle_limit to "unlimited" */ +#define MB ((size_t)1024*1024) +static const size_t mem_unlimited_size = 2 * 1024 * MB - 1; + +/* gb_type operations */ +#define gb_flush_limit (0x3FFFFFFF) +#define gb_inc(gb, delta) { \ + if ((gb)->bytes > gb_flush_limit || delta > gb_flush_limit) \ + gb_flush(gb); \ + (gb)->bytes += delta; \ + (gb)->count++; \ +} + +static size_t memPoolInUseSize(const ACL_MEM_POOL * pool); +static int memPoolInUseCount(const ACL_MEM_POOL * pool); + +/* MemMeter */ +static void memMeterSyncHWater(MemMeter * m); + +#define memMeterCheckHWater(m) do { \ + if ((m).hwater_level < (m).level) \ + memMeterSyncHWater(&(m)); \ +} while (0) +#define memMeterInc(m) { (m).level++; memMeterCheckHWater(m); } +#define memMeterDec(m) { (m).level--; } +#define memMeterAdd(m, sz) { (m).level += (sz); memMeterCheckHWater(m); } +#define memMeterDel(m, sz) { (m).level -= (sz); } + +static double toMB(size_t size) +{ + return ((double) size) / MB; +} + +static size_t toKB(size_t size) +{ + return (size + 1024 - 1) / 1024; +} + +/* to-do: make debug level a parameter? */ +static void memPoolDescribe(const ACL_MEM_POOL * pool) +{ + acl_assert(pool); + acl_msg_info("%-20s: %6d x %4d bytes = %5ld KB", + pool->label, memPoolInUseCount(pool), + (int) pool->obj_size, + (long int) toKB(memPoolInUseSize((const ACL_MEM_POOL *)pool))); +} + +/* MemMeter */ + +static void memMeterSyncHWater(MemMeter * m) +{ + acl_assert(m); + if (m->hwater_level < m->level) { + m->hwater_level = m->level; + m->hwater_stamp = time(NULL); + } +} + +static void memPoolShrink(SQUID_MEM_ALLOCATOR *allocator, MemPool *pool, size_t new_limit) +{ + char *ptr; + + acl_assert(pool); + while (pool->meter.idle.level > new_limit + && acl_stack_size(((ACL_MEM_POOL *) pool)->pstack) > 0) { + memMeterDec(pool->meter.alloc); + memMeterDec(pool->meter.idle); + memMeterDel(allocator->TheMeter.idle, ((ACL_MEM_POOL *)pool)->obj_size); + memMeterDel(allocator->TheMeter.alloc, ((ACL_MEM_POOL *) pool)->obj_size); + ptr = acl_stack_pop(((ACL_MEM_POOL *) pool)->pstack); + acl_default_free(__FILE__, __LINE__, ptr); + } + acl_assert(pool->meter.idle.level <= new_limit); /* paranoid */ +} + +static void memShrink(SQUID_MEM_ALLOCATOR *allocator, size_t new_limit) +{ + size_t start_limit = allocator->TheMeter.idle.level; + ACL_ITER iter; + + /* first phase: cut proportionally to the pool idle size */ + + acl_foreach_reverse(iter, ((ACL_ALLOCATOR *) allocator)->pools) { + MemPool *pool = (MemPool*) iter.data; + const size_t target_pool_size = (size_t) + ((double) pool->meter.idle.level * new_limit) / start_limit; + memPoolShrink(allocator, pool, target_pool_size); + } + + acl_msg_info("memShrink: 1st phase done with %ld KB left", + (long int) toKB(allocator->TheMeter.idle.level)); + + /* second phase: cut to 0 */ + + acl_foreach_reverse(iter, ((ACL_ALLOCATOR *) allocator)->pools) { + MemPool *pool = (MemPool*) iter.data; + memPoolShrink(allocator, pool, 0); + } + + acl_msg_info("memShrink: 2nd phase done with %ld KB left", + (long int) toKB(allocator->TheMeter.idle.level)); + acl_assert(allocator->TheMeter.idle.level <= new_limit); /* paranoid */ +} + +static void memCleanModule(ACL_ALLOCATOR *allocator) +{ + int dirty_count = 0; + ACL_ITER iter; + + acl_foreach_reverse(iter, allocator->pools) { + ACL_MEM_POOL *pool = (ACL_MEM_POOL*) iter.data; + if (!pool) + continue; + if (memPoolInUseCount(pool)) { + memPoolDescribe(pool); + dirty_count++; + } else { + allocator->pool_destroy_fn(pool); + } + } + + if (dirty_count) + acl_msg_warn("memCleanModule: %d pools are left dirty", dirty_count); + + /* we clean the stack anyway */ + + acl_stack_clean(allocator->pools, NULL); +} + +/* Initialization */ + +static void memConfigure(ACL_ALLOCATOR *allocator, size_t mem_limit) +{ + size_t new_pool_limit = allocator->mem_idle_limit; + /* set to configured value first */ + + if (mem_limit > 0) + new_pool_limit = mem_limit; + else if (mem_limit == 0) + new_pool_limit = 0; + else + new_pool_limit = mem_unlimited_size; + /* shrink memory pools if needed */ + if (((SQUID_MEM_ALLOCATOR *) allocator)->TheMeter.idle.level > new_pool_limit) { + acl_msg_info("Shrinking idle mem pools to %.2f MB", toMB(new_pool_limit)); + memShrink((SQUID_MEM_ALLOCATOR *) allocator, new_pool_limit); + } + acl_assert(((SQUID_MEM_ALLOCATOR *) allocator)->TheMeter.idle.level <= new_pool_limit); + allocator->mem_idle_limit = new_pool_limit; +} + +/* MemPool */ + +static ACL_MEM_POOL *memPoolCreate(void) +{ + ACL_MEM_POOL *pool = acl_default_calloc(__FILE__, __LINE__, 1, sizeof(MemPool)); + MemPool *squid_pool = (MemPool *) pool; + + memset(&squid_pool->meter, 0, sizeof(squid_pool->meter)); + return (pool); +} + +static void memPoolDestroy(ACL_MEM_POOL * pool) +{ + void *obj; + ACL_ITER iter; + + acl_foreach_reverse(iter, pool->pstack) { + obj = iter.data; + if (pool->before_free_fn) + pool->before_free_fn(obj, pool->pool_ctx); + acl_default_free(__FILE__, __LINE__, obj); + } + + acl_default_free(__FILE__, __LINE__, pool); +} + +#if DEBUG_MEMPOOL +#define MEMPOOL_COOKIE(p) ((void *)((unsigned long)(p) ^ 0xDEADBEEF)) +struct mempool_cookie { + MemPool *pool; + void *cookie; +}; +#endif + +static void *memPoolAlloc(ACL_ALLOCATOR *allocator, ACL_MEM_POOL * pool) +{ + SQUID_MEM_ALLOCATOR *squid_allocator = (SQUID_MEM_ALLOCATOR *) allocator; + MemPool *squid_pool = (MemPool *) pool; + void *obj; + + memMeterInc(squid_pool->meter.inuse); + gb_inc(&squid_pool->meter.total, 1); + gb_inc(&squid_allocator->TheMeter.total, pool->obj_size); + memMeterAdd(squid_allocator->TheMeter.inuse, pool->obj_size); + gb_inc(&squid_allocator->mem_traffic_volume, pool->obj_size); + allocator->mem_pool_alloc_calls++; + + if (acl_stack_size(pool->pstack)) { + acl_assert(squid_pool->meter.idle.level); + memMeterDec(squid_pool->meter.idle); + memMeterDel(squid_allocator->TheMeter.idle, pool->obj_size); + gb_inc(&squid_pool->meter.saved, 1); + gb_inc(&squid_allocator->TheMeter.saved, pool->obj_size); + obj = acl_stack_pop(pool->pstack); + +#if DEBUG_MEMPOOL + (void) VALGRIND_MAKE_READABLE(obj, pool->real_obj_size + sizeof(struct mempool_cookie)); +#else + (void) VALGRIND_MAKE_READABLE(obj, pool->obj_size); +#endif +#if DEBUG_MEMPOOL + { + struct mempool_cookie *cookie = (void *) (((unsigned char *) obj) + pool->real_obj_size); + acl_assert(cookie->cookie == MEMPOOL_COOKIE(obj)); + acl_assert(cookie->pool == pool); + (void) VALGRIND_MAKE_NOACCESS(cookie, sizeof(cookie)); + } +#endif + } else { + acl_assert(!squid_pool->meter.idle.level); + memMeterInc(squid_pool->meter.alloc); + memMeterAdd(squid_allocator->TheMeter.alloc, pool->obj_size); +#if DEBUG_MEMPOOL + { + struct mempool_cookie *cookie; + obj = acl_default_malloc(__FILE__, __LINE__, + pool->real_obj_size + sizeof(struct mempool_cookie)); + cookie = (struct mempool_cookie *) (((unsigned char *) obj) + pool->real_obj_size); + cookie->cookie = MEMPOOL_COOKIE(obj); + cookie->pool = pool; + (void) VALGRIND_MAKE_NOACCESS(cookie, sizeof(cookie)); + } +#else + obj = acl_default_malloc(__FILE__, __LINE__, pool->obj_size); +#endif + } + + if (pool->after_alloc_fn) + pool->after_alloc_fn(obj, pool->pool_ctx); + + return obj; +} + +static void memPoolFree(ACL_ALLOCATOR *allocator, ACL_MEM_POOL * pool, void *obj) +{ + SQUID_MEM_ALLOCATOR *squid_allocator = (SQUID_MEM_ALLOCATOR *) allocator; + MemPool *squid_pool = (MemPool *) pool; + + acl_assert(pool && obj); + memMeterDec(squid_pool->meter.inuse); + memMeterDel(squid_allocator->TheMeter.inuse, pool->obj_size); + allocator->mem_pool_free_calls++; + (void) VALGRIND_CHECK_WRITABLE(obj, pool->obj_size); +#if DEBUG_MEMPOOL + { + struct mempool_cookie *cookie = (void *) + (((unsigned char *) obj) + pool->real_obj_size); + (void) VALGRIND_MAKE_READABLE(cookie, sizeof(cookie)); + acl_assert(cookie->cookie == MEMPOOL_COOKIE(obj)); + acl_assert(cookie->pool == pool); + } +#endif + if (squid_allocator->TheMeter.idle.level + pool->obj_size <= allocator->mem_idle_limit) { + memMeterInc(squid_pool->meter.idle); + memMeterAdd(squid_allocator->TheMeter.idle, pool->obj_size); +#if DEBUG_MEMPOOL + (void) VALGRIND_MAKE_NOACCESS(obj, pool->real_obj_size + sizeof(struct mempool_cookie)); +#else + (void) VALGRIND_MAKE_NOACCESS(obj, pool->obj_size); +#endif + if (pool->before_free_fn) + pool->before_free_fn(obj, pool->pool_ctx); + + /* xxx: I should add some here--zsx */ + /* memset(obj, 0, pool->obj_size); */ + acl_stack_append(pool->pstack, obj); + } else { + memMeterDec(squid_pool->meter.alloc); + memMeterDel(squid_allocator->TheMeter.alloc, pool->obj_size); + if (pool->before_free_fn) + pool->before_free_fn(obj, pool->pool_ctx); + acl_default_free(__FILE__, __LINE__, obj); + } + acl_assert(squid_pool->meter.idle.level <= squid_pool->meter.alloc.level); +} + +static int memPoolWasUsed(const ACL_MEM_POOL * pool) +{ + acl_assert(pool); + return ((const MemPool *) pool)->meter.alloc.hwater_level > 0; +} + +static int memPoolInUseCount(const ACL_MEM_POOL * pool) +{ + acl_assert(pool); + return ((const MemPool *) pool)->meter.inuse.level; +} + +static size_t memPoolInUseSize(const ACL_MEM_POOL * pool) +{ + acl_assert(pool); + return (pool->obj_size * ((const MemPool *) pool)->meter.inuse.level); +} + +static size_t memTotalAllocated(ACL_ALLOCATOR *allocator) +{ + return ((SQUID_MEM_ALLOCATOR *) allocator)->TheMeter.alloc.level; +} + +ACL_ALLOCATOR *squid_allocator_create(void) +{ + ACL_ALLOCATOR *allocator; + + allocator = allocator_alloc(sizeof(SQUID_MEM_ALLOCATOR)); + + allocator->pool_create_fn = memPoolCreate; + allocator->pool_config_fn = memConfigure; + allocator->pool_destroy_fn = memPoolDestroy; + allocator->pool_clean_fn = memCleanModule; + + allocator->pool_if_used = memPoolWasUsed; + allocator->pool_inuse_count = memPoolInUseCount; + allocator->pool_inuse_size = memPoolInUseSize; + allocator->pool_total_allocated = memTotalAllocated; + + allocator->mem_alloc_fn = memPoolAlloc; + allocator->mem_free_fn = memPoolFree; + + memset(&((SQUID_MEM_ALLOCATOR *) allocator)->TheMeter, 0, sizeof(MemPoolMeter)); + + return ((ACL_ALLOCATOR *) allocator); +} diff --git a/lib_acl/src/stdlib/memory/squid_allocator.h b/lib_acl/src/stdlib/memory/squid_allocator.h new file mode 100644 index 000000000..88f148d03 --- /dev/null +++ b/lib_acl/src/stdlib/memory/squid_allocator.h @@ -0,0 +1,90 @@ +#ifndef __SQUID_ALLOCATOR_INCLUDE_H__ +#define __SQUID_ALLOCATOR_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_define.h" +#include "stdlib/acl_allocator.h" + +#include "allocator.h" +#include /* for time_t */ + +#if WITH_VALGRIND +#include +#else +#define VALGRIND_MAKE_NOACCESS(a,b) (0) +#define VALGRIND_MAKE_WRITABLE(a,b) (0) +#define VALGRIND_MAKE_READABLE(a,b) (0) +#define VALGRIND_CHECK_WRITABLE(a,b) (0) +#define VALGRIND_CHECK_READABLE(a,b) (0) +#define VALGRIND_MALLOCLIKE_BLOCK(a,b,c,d) +#define VALGRIND_FREELIKE_BLOCK(a,b) +#define RUNNING_ON_VALGRIND 0 +#endif /* WITH_VALGRIND */ + +typedef struct { + unsigned int bytes; + unsigned int kb; +} kb_t; + +typedef struct { + size_t count; + size_t bytes; + size_t gb; +} gb_t; + + +typedef struct MemMeter MemMeter; +typedef struct MemPoolMeter MemPoolMeter; +typedef struct MemPool MemPool; + +/* object to track per-action memory usage (e.g. #idle objects) */ +struct MemMeter { + size_t level; /* current level (count or volume) */ + size_t hwater_level; /* high water mark */ + time_t hwater_stamp; /* timestamp of last high water mark change */ +}; + +/* object to track per-pool memory usage (alloc = inuse+idle) */ +struct MemPoolMeter { + MemMeter alloc; + MemMeter inuse; + MemMeter idle; + gb_t saved; + gb_t total; +}; + +/* a pool is a [growing] space for objects of the same size */ +struct MemPool { + ACL_MEM_POOL pool; + MemPoolMeter meter; +#if DEBUG_MEMPOOL + MemPoolMeter diff_meter; +#endif +}; + +typedef struct SQUID_MEM_ALLOCATOR { + ACL_ALLOCATOR allocator; + MemPoolMeter TheMeter; + gb_t mem_traffic_volume; +} SQUID_MEM_ALLOCATOR; + + +/* in tools.h */ + +void kb_incr(kb_t * k, unsigned int v); +void gb_flush(gb_t * g); +double gb_to_double(const gb_t * g); +const char *gb_to_str(const gb_t * g); + +/* in squid_allocator.c */ +extern ACL_ALLOCATOR *squid_allocator_create(void); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/src/stdlib/memory/squid_allocator_tools.c b/lib_acl/src/stdlib/memory/squid_allocator_tools.c new file mode 100644 index 000000000..58ad7a042 --- /dev/null +++ b/lib_acl/src/stdlib/memory/squid_allocator_tools.c @@ -0,0 +1,66 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#endif + +#include "squid_allocator.h" + +void kb_incr(kb_t * k, unsigned int v) +{ + k->bytes += v; + k->kb += (k->bytes >> 10); + k->bytes &= 0x3FF; + if (k->kb == 0) { + /* + * If kb overflows and becomes negative then add powers of + * 2 until it becomes positive again. + */ + kb_t x; + x.kb = 1 << 31; + while (x.kb && ((k->kb + x.kb) == 0)) { + x.kb <<= 1; + } + k->kb += x.kb; + } +} + +void gb_flush(gb_t * g) +{ + g->gb += (g->bytes >> 30); + g->bytes &= (1 << 30) - 1; +} + +double gb_to_double(const gb_t * g) +{ + return ((double) g->gb) * ((double) (1 << 30)) + ((double) g->bytes); +} + +const char *gb_to_str(const gb_t * g) +{ + /* + * it is often convenient to call gb_to_str several times for _one_ printf + */ +#define max_cc_calls 5 + typedef char GbBuf[32]; + static GbBuf bufs[max_cc_calls]; + static int call_id = 0; + double value = gb_to_double(g); + char *buf = bufs[call_id++]; + if (call_id >= max_cc_calls) + call_id = 0; + /* select format */ + if (value < 1e9) + snprintf(buf, sizeof(GbBuf), "%.2f MB", value / 1e6); + else if (value < 1e12) + snprintf(buf, sizeof(GbBuf), "%.2f GB", value / 1e9); + else + snprintf(buf, sizeof(GbBuf), "%.2f TB", value / 1e12); + return buf; +} diff --git a/lib_acl/src/stdlib/memory/vstring_pool.c b/lib_acl/src/stdlib/memory/vstring_pool.c new file mode 100644 index 000000000..026c70810 --- /dev/null +++ b/lib_acl/src/stdlib/memory/vstring_pool.c @@ -0,0 +1,95 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_msg.h" +#include "stdlib/acl_vbuf_print.h" +#include "stdlib/acl_vstring.h" +#include "stdlib/acl_allocator.h" + +#endif + +#include "allocator.h" + +static const char label[] = "vstring"; + +static ACL_ALLOCATOR *__var_allocator; +static int __len = 1024; + +static void vstring_extend(ACL_VBUF *bp, int incr) +{ + unsigned used = bp->ptr - bp->data; + int new_len; + + /* + * Note: vp->vbuf.len is the current buffer size (both on entry and on + * exit of this routine). We round up the increment size to the buffer + * size to avoid silly little buffer increments. With really large + * strings we might want to abandon the length doubling strategy, and go + * to fixed increments. + */ + new_len = bp->len + (bp->len > incr ? bp->len : incr); + /* + * bp->data = (unsigned char *) acl_myrealloc((char *) bp->data, new_len); + */ + bp->data = acl_allocator_membuf_alloc(__FILE__, __LINE__, __var_allocator, new_len); + bp->len = new_len; + bp->ptr = bp->data + used; + bp->cnt = bp->len - used; +} + +static int vstring_buf_get_ready(ACL_VBUF *buf acl_unused) +{ + acl_msg_panic("vstring_buf_get: write-only buffer"); + return (0); +} + +static int vstring_buf_put_ready(ACL_VBUF *bp) +{ + vstring_extend(bp, 0); + return (0); +} + +static int vstring_buf_space(ACL_VBUF *bp, int len) +{ + int need; + + if (len < 0) + acl_msg_panic("vstring_buf_space: bad length %d", len); + if ((need = len - bp->cnt) > 0) + vstring_extend(bp, need); + return (0); +} + +static void after_alloc_fn(void *obj, void *pool_ctx acl_unused) +{ + ACL_VSTRING *vp = (ACL_VSTRING *) obj; + char *buf; + + buf = acl_allocator_membuf_alloc(__FILE__, __LINE__, __var_allocator, __len); + acl_vstring_glue(vp, buf, __len); + vp->vbuf.get_ready = vstring_buf_get_ready; + vp->vbuf.put_ready = vstring_buf_put_ready; + vp->vbuf.space = vstring_buf_space; +} + +static void before_free_fn(void *obj, void *pool_ctx acl_unused) +{ + ACL_VSTRING *vp = (ACL_VSTRING *) obj; + + acl_allocator_membuf_free(__FILE__, __LINE__, __var_allocator, vp->vbuf.data); + vp->vbuf.data = NULL; +} + +void vstring_pool_create(ACL_ALLOCATOR *allocator) +{ + __var_allocator = allocator; + + acl_allocator_pool_add(allocator, label, sizeof(ACL_VSTRING), + ACL_MEM_TYPE_VSTRING, after_alloc_fn, before_free_fn, NULL); +} diff --git a/lib_acl/src/stdlib/string/acl_alldig.c b/lib_acl/src/stdlib/string/acl_alldig.c new file mode 100644 index 000000000..9d5aa97f1 --- /dev/null +++ b/lib_acl/src/stdlib/string/acl_alldig.c @@ -0,0 +1,30 @@ +/* System library. */ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +/* Utility library. */ + +#include "stdlib/acl_stringops.h" + +#endif + +/* acl_alldig - return true if string is all digits */ + +int acl_alldig(const char *string) +{ + const char *cp; + + if (*string == 0) + return (0); + for (cp = string; *cp != 0; cp++) + if (!ACL_ISDIGIT(*cp)) + return (0); + return (1); +} diff --git a/lib_acl/src/stdlib/string/acl_basename.c b/lib_acl/src/stdlib/string/acl_basename.c new file mode 100644 index 000000000..d917291f1 --- /dev/null +++ b/lib_acl/src/stdlib/string/acl_basename.c @@ -0,0 +1,33 @@ +/* System library. */ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +/* Utility library. */ + +#include "stdlib/acl_stringops.h" + +#endif + +/* acl_safe_basename - skip directory prefix */ + +const char *acl_safe_basename(const char *path) +{ + const char *result; + + if ((result = strrchr(path, '/')) == NULL + && (result = strchr(path, '\\')) == NULL) + { + result = (const char *) path; + } else + result += 1; + return (result); +} + + diff --git a/lib_acl/src/stdlib/string/acl_concatenate.c b/lib_acl/src/stdlib/string/acl_concatenate.c new file mode 100644 index 000000000..ac132fb6a --- /dev/null +++ b/lib_acl/src/stdlib/string/acl_concatenate.c @@ -0,0 +1,51 @@ +/* System library. */ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include /* 44BSD stdarg.h uses abort() */ +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +/* Utility library. */ + +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_stringops.h" + +#endif + +/* acl_concatenate - concatenate null-terminated list of strings */ + +char *acl_concatenate(const char *arg0,...) +{ + char *result; + va_list ap; + int len; + char *arg; + + /* + * Compute the length of the resulting string. + */ + va_start(ap, arg0); + len = strlen(arg0); + while ((arg = va_arg(ap, char *)) != 0) + len += strlen(arg); + va_end(ap); + + /* + * Build the resulting string. Don't care about wasting a CPU cycle. + */ + result = (char *) acl_mymalloc(len + 1); + va_start(ap, arg0); + strcpy(result, arg0); + while ((arg = va_arg(ap, char *)) != 0) + strcat(result, arg); + va_end(ap); + return (result); +} + + diff --git a/lib_acl/src/stdlib/string/acl_hex_code.c b/lib_acl/src/stdlib/string/acl_hex_code.c new file mode 100644 index 000000000..e910af2ea --- /dev/null +++ b/lib_acl/src/stdlib/string/acl_hex_code.c @@ -0,0 +1,136 @@ +/* System library. */ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +/* Utility library. */ + +#include "stdlib/acl_msg.h" +#include "stdlib/acl_vstring.h" +#include "stdlib/acl_hex_code.h" + +#endif + +/* Application-specific. */ + +static const unsigned char acl_hex_chars[] = "0123456789ABCDEF"; + +#define UCHAR_PTR(x) ((const unsigned char *)(x)) + +/* acl_hex_encode - raw data to encoded */ + +ACL_VSTRING *acl_hex_encode(ACL_VSTRING *result, const char *in, int len) +{ + const unsigned char *cp; + int ch; + int count; + + ACL_VSTRING_RESET(result); + for (cp = UCHAR_PTR(in), count = len; count > 0; count--, cp++) { + ch = *cp; + ACL_VSTRING_ADDCH(result, acl_hex_chars[(ch >> 4) & 0xf]); + ACL_VSTRING_ADDCH(result, acl_hex_chars[ch & 0xf]); + } + ACL_VSTRING_TERMINATE(result); + return (result); +} + +/* acl_hex_decode - encoded data to raw */ + +ACL_VSTRING *acl_hex_decode(ACL_VSTRING *result, const char *in, int len) +{ + const unsigned char *cp; + int count; + unsigned int hex; + unsigned int bin; + + ACL_VSTRING_RESET(result); + for (cp = UCHAR_PTR(in), count = len; count > 0; cp += 2, count -= 2) { + if (count < 2) + return (0); + hex = cp[0]; + if (hex >= '0' && hex <= '9') + bin = (hex - '0') << 4; + else if (hex >= 'A' && hex <= 'F') + bin = (hex - 'A' + 10) << 4; + else if (hex >= 'a' && hex <= 'f') + bin = (hex - 'a' + 10) << 4; + else + return (0); + hex = cp[1]; + if (hex >= '0' && hex <= '9') + bin |= (hex - '0') ; + else if (hex >= 'A' && hex <= 'F') + bin |= (hex - 'A' + 10) ; + else if (hex >= 'a' && hex <= 'f') + bin |= (hex - 'a' + 10) ; + else + return (0); + ACL_VSTRING_ADDCH(result, bin); + } + ACL_VSTRING_TERMINATE(result); + return (result); +} + +#ifdef TEST + + /* + * Proof-of-concept test program: convert to hexadecimal and back. + */ + +#define STR(x) vstring_str(x) +#define LEN(x) ACL_VSTRING_LEN(x) + +int main(int unused_argc, char **unused_argv) +{ + ACL_VSTRING *b1 = vstring_alloc(1); + ACL_VSTRING *b2 = vstring_alloc(1); + char *test = "this is a test"; + +#define DECODE(b,x,l) { \ + if (acl_hex_decode((b),(x),(l)) == 0) \ + acl_msg_panic("bad hex: %s", (x)); \ + } +#define VERIFY(b,t) { \ + if (strcmp((b), (t)) != 0) \ + acl_msg_panic("bad test: %s", (b)); \ + } + + acl_hex_encode(b1, test, strlen(test)); + DECODE(b2, STR(b1), LEN(b1)); + VERIFY(STR(b2), test); + + acl_hex_encode(b1, test, strlen(test)); + acl_hex_encode(b2, STR(b1), LEN(b1)); + acl_hex_encode(b1, STR(b2), LEN(b2)); + DECODE(b2, STR(b1), LEN(b1)); + DECODE(b1, STR(b2), LEN(b2)); + DECODE(b2, STR(b1), LEN(b1)); + VERIFY(STR(b2), test); + + acl_hex_encode(b1, test, strlen(test)); + acl_hex_encode(b2, STR(b1), LEN(b1)); + acl_hex_encode(b1, STR(b2), LEN(b2)); + acl_hex_encode(b2, STR(b1), LEN(b1)); + acl_hex_encode(b1, STR(b2), LEN(b2)); + DECODE(b2, STR(b1), LEN(b1)); + DECODE(b1, STR(b2), LEN(b2)); + DECODE(b2, STR(b1), LEN(b1)); + DECODE(b1, STR(b2), LEN(b2)); + DECODE(b2, STR(b1), LEN(b1)); + VERIFY(STR(b2), test); + + vstring_free(b1); + vstring_free(b2); + return (0); +} + +#endif + diff --git a/lib_acl/src/stdlib/string/acl_mystring.c b/lib_acl/src/stdlib/string/acl_mystring.c new file mode 100644 index 000000000..ec531373b --- /dev/null +++ b/lib_acl/src/stdlib/string/acl_mystring.c @@ -0,0 +1,489 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_vsprintf.h" +#include "stdlib/acl_mystring.h" + +#endif + +char *acl_lowercase(char *string) +{ + char *cp = string; + + if (string == NULL) + return (NULL); + + while (*cp) { + *cp = tolower(*cp); + cp++; + } + + return (string); +} + +char *acl_lowercase2(char *string, size_t n) +{ + char *cp = string; + + if (string == NULL) + return (NULL); + + while (*cp && n > 0) { + *cp = tolower(*cp); + cp++; + n--; + } + + return (string); +} + +char *acl_lowercase3(const char *string, char *buf, size_t size) +{ + char *cp = buf; + + if (string == NULL || *string == 0 || buf == NULL) + return(NULL); + + while (size > 1 && *string) { + *cp++ = tolower(*string++); + size--; + } + *cp = 0; + + return (buf); +} + +char *acl_uppercase(char *string) +{ + char *cp = string; + + if (string == NULL) + return (NULL); + + while (*cp) { + *cp = toupper(*cp); + cp++; + } + + return (string); +} + +char *acl_uppercase2(char *string, size_t n) +{ + char *cp = string; + + if (string == NULL) + return (NULL); + + while (*cp && n > 0) { + *cp = toupper(*cp); + cp++; + n--; + } + + return (string); +} + +char *acl_uppercase3(const char *string, char *buf, size_t size) +{ + char *cp = buf; + + if (string == NULL || *string == 0 || buf == NULL) + return(NULL); + + while (size > 1 && *string) { + *cp++ = toupper(*string++); + size--; + } + *cp = 0; + + return (buf); +} + +/* acl_mystrtok - safe tokenizer */ + +char *acl_mystrtok(char **src, const char *sep) +{ + char *start = *src; + char *end; + + /* + * Skip over leading delimiters. + */ + start += strspn(start, sep); + if (*start == 0) { + *src = start; + return (0); + } + + /* + * Separate off one token. + */ + end = start + strcspn(start, sep); + if (*end != 0) + *end++ = 0; + *src = end; + return (start); +} + +/* acl_mystrline */ +char *acl_mystrline(char **src) +{ + char *start = *src; + char *end = *src; + int squash = 0, nr = 0; + + if (start == NULL) + return (NULL); + + while (*end) { + switch (*end) { + case '\\': + squash = 1; + break; + case '\r': + nr++; + break; + case '\n': + if (squash == 0) + goto TAG_LOOP_END; + memmove(end - (squash + nr), end + 1, strlen(end + 1)); + default: + squash = 0; + nr = 0; + break; + } + + end++; + } + +TAG_LOOP_END: + + if (*end == '\n') { + *(end - nr) = 0; + *src = end + 1; /* (*src) pointer to the next postion after '\n' */ + } else + *src = 0; + + return (start); +} + +char *acl_mystr_trim(char *str) +{ + size_t len; + char *ptr = str; + + len = strlen(str); + + while (*ptr) { + if (*ptr == ' ' || *ptr == '\t') { + memmove(ptr, ptr + 1, len--); + } else if (((*ptr) &0xff) == 0xa1 && ((*(ptr + 1)) & 0xff) == 0xa1) { + /* 对于全角的空格为: ' ', 即 0xa10xa1 */ + len--; + memmove(ptr, ptr + 2, len--); + } else { + ptr++; + len--; + } + } + + return (str); +} + +int acl_mystr_strip(const char *haystack, const char *needle, char *buf, int bsize) +{ + const char *ptr_src; + char *ptr_des, *ptr; + int len, n, ncpy = 0; + + if (haystack == NULL || *haystack == 0 || needle == NULL + || *needle == 0 || buf == NULL || bsize <= 0) + return(-1); + + ptr_src = haystack; + ptr_des = buf; + len = strlen(needle); + + while(1) { + ptr = strstr(ptr_src, needle); + if (ptr == NULL) { + n = strlen(ptr_src); + if (bsize > n) { + ACL_SAFE_STRNCPY(ptr_des, ptr_src, bsize); + ncpy += n; + *(ptr_des + n) = 0; + } + break; + } + n = ptr - ptr_src; + if (bsize <= n) + break; + ACL_SAFE_STRNCPY(ptr_des, ptr_src, bsize); + ncpy += n; + bsize -= n; + ptr_des += n; + *ptr_des = 0; + ptr_src += n + len; + } + + return(ncpy); +} + +int acl_mystr_truncate_byln(char *str_src) +{ + if (str_src == NULL) + return (-1); + + while (*str_src) { + if (*str_src == '\r' || *str_src == '\n') { + *str_src = 0; + break; + } + str_src++; + } + + return (0); +} + +/*---------------------------------------------------------------------------- + * 返回指针的当前位置, 并且删除路径中多余的 '/'(for unix) or '\\'(for windows) + * 并且返回的当前指针所存储的字符为 '\0', 而到数第二个字符有可能为 '/' or '\\', + * 也有可能不为 //'/' or '\\', 但在结果集中绝不会出现连续的 '/' or '\\' + */ +static char *path_str_strip(const char *psrc, char *pbuf, int sizeb) +{ + const char *ptr_src = psrc; + char *ptr_obj; + int n; + + if (ptr_src == NULL || *ptr_src == 0 || pbuf == NULL || sizeb <= 0) + return(NULL); + + ptr_obj = pbuf; + n = sizeb; + + while (*ptr_src && n > 0) { + if (*ptr_src == c_pathdelim_chr + && *(ptr_src + 1) == c_pathdelim_chr) + ; /* skip any useless '/'(in unix) or '\\'(in windows) */ + else { + *ptr_obj++ = *ptr_src; + n--; + } + + ptr_src++; + } + + if (n <= 0) /* 说明所给的缓冲区空间不够大 */ + return (NULL); + + /* 必须保证最后一个字符是以 '\0' 结束 */ + *ptr_obj = 0; + + return (ptr_obj); +} +/*---------------------------------------------------------------------------- + * 保证结果类似于如下形式: + * /home/avwall/test.txt + */ +int acl_file_path_correct(const char *psrc_file_path, char *pbuf, int sizeb) +{ + char *ptr; + + ptr = path_str_strip(psrc_file_path, pbuf, sizeb); + if (ptr == NULL) + return (-1); + return (0); +} +/*---------------------------------------------------------------------------- + * 保证路径名经过此函数后都为如下格式: + * 源: /home/avwall/, /home//////avwall/, /home/avwall, /////home/avwall/// + * /home/avwall////, /home///avwall///, ///home///avwall/// + * 结果: /home/avwall/ + */ +int acl_dir_correct(const char *psrc_dir, char *pbuf, int sizeb) +{ + char *ptr; + + /* 删除连续的 '/'(unix) or '\\'(windows) */ + ptr = path_str_strip(psrc_dir, pbuf, sizeb); + + /* 该函数若返回的结果不为空, 则 *ptr 定为 '\0' */ + if (ptr == NULL) + return(-1); + + /* 为了保证最后一个字符肯定为 '/'(unix) or '\\'(windows), 需做如下处理 */ + + if (*(ptr - 1) != c_pathdelim_chr) { + if (ptr >= pbuf + sizeb) /* 说明所给的内存空间不够 */ + return(-1); + *ptr++ = c_pathdelim_chr; + *ptr = 0; + } + return(0); +} + +int acl_dir_getpath(const char *pathname, char *pbuf, int bsize) +{ + char *ptr; + int n; + + if (pathname == NULL || pbuf == NULL || bsize <= 0) + return (-1); + + n = acl_file_path_correct(pathname, pbuf, bsize); + if (n < 0) + return (-1); + ptr = strrchr(pbuf, c_pathdelim_chr); + if (ptr != NULL) + *ptr = 0; + if (ptr == pbuf) { /* such as "/tmp.txt", I'll left "/" */ + if (bsize >= 2) + *(ptr + 1) = 0; + } + + return (0); +} + +/** + * strnlen - Find the length of a length-limited string + * @s: The string to be sized + * @count: The maximum number of bytes to search + */ +size_t acl_strnlen(const char * s, size_t count) +{ + const char *sc; + + for (sc = s; count-- && *sc != '\0'; ++sc) + /* nothing */; + return (sc - s); +} + +#ifdef ACL_MS_WINDOWS + +acl_uint64 acl_atoui64(const char *str) +{ + return ((acl_uint64) _atoi64(str)); +} + +acl_int64 acl_atoi64(const char *str) +{ + return (_atoi64(str)); +} + +const char *acl_ui64toa(acl_uint64 value, char *buf, size_t size) +{ + if (size < 21) + return (NULL); + return (_ui64toa(value, buf, 10)); +} + +const char *acl_i64toa(acl_int64 value, char *buf, size_t size) +{ + if (size < 21) + return (NULL); + return (_i64toa(value, buf, 10)); +} + +#elif defined(ACL_UNIX) + +acl_uint64 acl_atoui64(const char *str) +{ + return ((acl_uint64) strtoull(str, NULL, 10)); +} + +acl_int64 acl_atoi64(const char *str) +{ + return ((acl_int64) strtoull(str, NULL, 10)); +} + +const char *acl_ui64toa(acl_uint64 value, char *buf, size_t size) +{ + if (size < 21) + return (NULL); + + snprintf(buf, size, "%llu", value); + return (buf); +} + +const char *acl_i64toa(acl_int64 value, char *buf, size_t size) +{ + if (size < 21) + return (NULL); + + snprintf(buf, size, "%lld", value); + return (buf); +} + +#endif + +static void x64toa(acl_uint64 val, char *buf, size_t size, unsigned radix, int is_neg) +{ + char *p; /* pointer to traverse string */ + char *firstdig; /* pointer to first digit */ + char temp; /* temp char */ + unsigned digval; /* value of digit */ + + p = buf; + + if (is_neg) { + *p++ = '-'; /* negative, so output '-' and negate */ + val = (acl_uint64) (-(acl_int64) val); + } + + firstdig = p; /* save pointer to first digit */ + + do { + if (size-- <= 0) + break; + + digval = (unsigned) (val % radix); + val /= radix; /* get next digit */ + + /* convert to ascii and store */ + if (digval > 9) + *p++ = (char) (digval - 10 + 'a'); /* a letter */ + else + *p++ = (char) (digval + '0'); /* a digit */ + } while (val > 0); + + /* We now have the digit of the number in the buffer, but in reverse + order. Thus we reverse them now. */ + + *p-- = '\0'; /* terminate string; p points to last digit */ + + do { + temp = *p; + *p = *firstdig; + *firstdig = temp; /* swap *p and *firstdig */ + --p; + ++firstdig; /* advance to next two digits */ + } while (firstdig < p); /* repeat until halfway */ +} + +/* Actual functions just call conversion helper with neg flag set correctly, + and return pointer to buffer. */ + +const char *acl_i64toa_radix(acl_int64 val, char *buf, size_t size, int radix) +{ + x64toa((acl_uint64)val, buf, size, radix, (radix == 10 && val < 0)); + return buf; +} + +const char *acl_ui64toa_radix(acl_uint64 val, char *buf, size_t size, int radix) +{ + x64toa(val, buf, size, radix, 0); + return buf; +} + diff --git a/lib_acl/src/stdlib/string/acl_split_at.c b/lib_acl/src/stdlib/string/acl_split_at.c new file mode 100644 index 000000000..f7050d180 --- /dev/null +++ b/lib_acl/src/stdlib/string/acl_split_at.c @@ -0,0 +1,40 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +/* System libraries */ + +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +/* Utility library. */ + +#include "stdlib/acl_split_at.h" + +#endif + +/* acl_split_at - break string at first delimiter, return remainder */ + +char *acl_split_at(char *string, int delimiter) +{ + char *cp; + + if ((cp = strchr(string, delimiter)) != 0) + *cp++ = 0; + return (cp); +} + +/* acl_split_at_right - break string at last delimiter, return remainder */ + +char *acl_split_at_right(char *string, int delimiter) +{ + char *cp; + + if ((cp = strrchr(string, delimiter)) != 0) + *cp++ = 0; + return (cp); +} diff --git a/lib_acl/src/stdlib/string/acl_split_nameval.c b/lib_acl/src/stdlib/string/acl_split_nameval.c new file mode 100644 index 000000000..10546dd61 --- /dev/null +++ b/lib_acl/src/stdlib/string/acl_split_nameval.c @@ -0,0 +1,47 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include "stdlib/acl_stringops.h" + +#endif + +/* acl_split_nameval - split text into name and value */ + +const char *acl_split_nameval(char *buf, char **name, char **value) +{ + char *np; /* name substring */ + char *vp; /* value substring */ + char *cp; + char *ep; + + /* + * Ugly macros to make complex expressions less unreadable. + */ +#define SKIP(start, var, cond) \ + for (var = start; *var && (cond); var++); + +#define TRIM(s) { \ + char *p; \ + for (p = (s) + strlen(s); p > (s) && ACL_ISSPACE(p[-1]); p--); \ + *p = 0; \ +} + + SKIP(buf, np, ACL_ISSPACE(*np)); /* find name begin */ + if (*np == 0) + return ("missing attribute name"); + SKIP(np, ep, !ACL_ISSPACE(*ep) && *ep != '='); /* find name end */ + SKIP(ep, cp, ACL_ISSPACE(*cp)); /* skip blanks before '=' */ + if (*cp != '=') /* need '=' */ + return ("missing '=' after attribute name"); + *ep = 0; /* terminate name */ + cp++; /* skip over '=' */ + SKIP(cp, vp, ACL_ISSPACE(*vp)); /* skip leading blanks */ + TRIM(vp); /* trim trailing blanks */ + *name = np; + *value = vp; + return (NULL); +} + diff --git a/lib_acl/src/stdlib/string/acl_str2time.c b/lib_acl/src/stdlib/string/acl_str2time.c new file mode 100644 index 000000000..28e0fb3fc --- /dev/null +++ b/lib_acl/src/stdlib/string/acl_str2time.c @@ -0,0 +1,34 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_timeops.h" + +#endif + +time_t acl_str2time_t(const char *str) +{ + struct tm t; + + if (str == NULL) + return (0); + + memset(&t, 0, sizeof(t)); + + if (sscanf(str, "%d-%d-%d", &t.tm_year, &t.tm_mon, &t.tm_mday) != 3) + return (0); + + t.tm_year -= 1900; + t.tm_mon -= 1; + + return (mktime(&t)); +} + diff --git a/lib_acl/src/stdlib/string/strcasecmp.c b/lib_acl/src/stdlib/string/strcasecmp.c new file mode 100644 index 000000000..4779b5edb --- /dev/null +++ b/lib_acl/src/stdlib/string/strcasecmp.c @@ -0,0 +1,130 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_mystring.h" + +#endif + +#include "../charmap.h" + +int acl_strcasecmp(const char *s1, const char *s2) +{ + const unsigned char *cm = maptolower, + *us1 = (const unsigned char *) s1, + *us2 = (const unsigned char *) s2; + + while (cm[*us1] == cm[*us2]) { + if (*us1 == '\0') + return (0); + us1++; + us2++; + } + return (cm[*us1] - cm[*us2]); +} + +int acl_strncasecmp(const char *s1, const char *s2, size_t n) +{ + if (n != 0) { + const unsigned char *cm = maptolower, + *us1 = (const unsigned char *) s1, + *us2 = (const unsigned char *) s2; + + do { + if (cm[*us1] != cm[*us2]) + return (cm[*us1] - cm[*us2]); + if (*us1 == '\0') + break; + us1++; + us2++; + } while (--n != 0); + } + return (0); +} + +int acl_strrncasecmp(const char *s1, const char *s2, size_t n) +{ + if (n != 0) { + const unsigned char *cm = maptolower, *us1, *us2; + + if (*s1 == 0) { + if (*s2 == 0) + return (0); + return (-(*s2)); + } + if (*s2 == 0) { + if (*s1 == 0) + return (0); + return (-(*s1)); + } + + us1 = (const unsigned char *) s1 + strlen(s1) - 1; + us2 = (const unsigned char *) s2 + strlen(s2) - 1; + + do { + if (cm[*us1] != cm[*us2]) + return (cm[*us1] - cm[*us2]); + if (us1 == (const unsigned char*) s1) { + if (us2 == (const unsigned char*) s2 || n == 1) + break; + return (-cm[*--us2]); + } + if (us2 == (const unsigned char*) s2) { + if (us1 == (const unsigned char*) s1 || n == 1) + break; + return (-cm[*--us1]); + } + us1--; + us2--; + } while (--n != 0); + } + return (0); +} + +int acl_strrncmp(const char *s1, const char *s2, size_t n) +{ + if (n != 0) { + const unsigned char *us1, *us2; + + if (*s1 == 0) { + if (*s2 == 0) + return (0); + return (-(*s2)); + } + if (*s2 == 0) { + if (*s1 == 0) + return (0); + return (-(*s1)); + } + + us1 = (const unsigned char *) s1 + strlen(s1) - 1; + us2 = (const unsigned char *) s2 + strlen(s2) - 1; + + do { + if (*us1 != *us2) + return (*us1 - *us2); + if (us1 == (const unsigned char*) s1) { + if (us2 == (const unsigned char*) s2 || n == 1) + break; + return (-(*--us2)); + } + if (us2 == (const unsigned char*) s2) { + if (us1 == (const unsigned char*) s1 || n == 1) + break; + return (-(*--us1)); + } + us1--; + us2--; + } while (--n != 0); + } + return (0); +} diff --git a/lib_acl/src/stdlib/string/strcasestr.c b/lib_acl/src/stdlib/string/strcasestr.c new file mode 100644 index 000000000..b5db75d6c --- /dev/null +++ b/lib_acl/src/stdlib/string/strcasestr.c @@ -0,0 +1,124 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_mystring.h" +#endif + +#include "../charmap.h" + +char *acl_rstrstr(char *haystack, const char *needle) +{ + unsigned char *cp, *haystack_end; + const unsigned char *np = 0, *needle_end; + + if (haystack == NULL || *haystack == 0 || needle == NULL || *needle == 0) + return (NULL); + + haystack_end = (unsigned char *) haystack + strlen(haystack) - 1; + needle_end = (const unsigned char *) needle + strlen(needle) - 1; + + for (cp = haystack_end; cp >= (unsigned char *) haystack; cp--) { + if (np) { + if (*cp == *np) { + if (--np < (const unsigned char *) needle) + return ((char *) cp); + } else + np = 0; + } + if (!np && *cp == *needle_end) { + np = needle_end - 1; + if (np < (const unsigned char *) needle) + return ((char *) cp); + } + } + + return (NULL); +} + +char *acl_rstrcasestr(char *haystack, const char *needle) +{ + const unsigned char *cm = maptolower; + unsigned char *cp, *haystack_end; + const unsigned char *np = 0, *needle_end; + + if (haystack == NULL || *haystack == 0 || needle == NULL || *needle == 0) + return (NULL); + + haystack_end = (unsigned char *) haystack + strlen(haystack) - 1; + needle_end = (const unsigned char *) needle + strlen(needle) - 1; + + for (cp = haystack_end; cp >= (unsigned char *) haystack; cp--) { + if (np) { + if (*cp == cm[*np]) { + if (--np < (const unsigned char *) needle) + return ((char *) cp); + } else + np = 0; + } + if (!np && *cp == cm[*needle_end]) { + np = needle_end - 1; + if (np < (const unsigned char *) needle) + return ((char *) cp); + } + } + + return (NULL); +} + +char *acl_strcasestr(char *haystack, const char *needle) +{ + const unsigned char *cm = maptolower; + const unsigned char *np = 0; + unsigned char *p, *startn = 0; + + for (p = (unsigned char*) haystack; *p; p++) { + if (np) { + if (cm[*p] == cm[*np]) { + if (!*++np) + return (char*) (startn); + } else + np = 0; + } + if (!np && cm[*p] == cm[*((const unsigned char*) needle)]) { + np = (const unsigned char*) needle + 1; + if (*np == 0) + return ((char*) p); + startn = p; + } + } + + return 0; +} + +#ifdef ACL_MS_WINDOWS +#if 0 +char *strcasestr(char *haystack, char *needle) +{ + char *p, *startn = 0, *np = 0; + + for (p = haystack; *p; p++) { + if (np) { + if (toupper(*p) == toupper(*np)) { + if (!*++np) + return startn; + } else + np = 0; + } else if (toupper(*p) == toupper(*needle)) { + np = needle + 1; + startn = p; + } + } + + return 0; +} +#endif +#endif /* ACL_MS_WINDOWS */ diff --git a/lib_acl/src/stdlib/sys/_snprintf.h b/lib_acl/src/stdlib/sys/_snprintf.h new file mode 100644 index 000000000..a6ca481ce --- /dev/null +++ b/lib_acl/src/stdlib/sys/_snprintf.h @@ -0,0 +1,18 @@ +#ifndef __SNPRINTF_SAFE_INCLUDE_H__ +#define __SNPRINTF_SAFE_INCLUDE_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int acl_secure_snprintf(char *buf, size_t size, const char *fmt, ...); +int acl_secure_vsnprintf(char *buf, size_t size, const char *fmt, va_list ap); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_acl/src/stdlib/sys/acl_dll.c b/lib_acl/src/stdlib/sys/acl_dll.c new file mode 100644 index 000000000..e23818444 --- /dev/null +++ b/lib_acl/src/stdlib/sys/acl_dll.c @@ -0,0 +1,50 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include "stdlib/acl_msg.h" +#include "stdlib/acl_dll.h" + +#ifdef ACL_UNIX +#include +#endif + +#endif + +ACL_DLL_HANDLE acl_dlopen(const char *dlname) +{ + const char *myname = "acl_dlopen"; + ACL_DLL_HANDLE handle; + +#ifdef ACL_UNIX + if (1) + handle = dlopen(dlname, RTLD_LOCAL | RTLD_LAZY); + else + handle = dlopen(dlname, RTLD_GLOBAL | RTLD_NOW); +#elif defined(ACL_MS_WINDOWS) + handle = LoadLibrary(dlname); +#endif + if (handle == NULL) + acl_msg_error("%s(%d): open(%s) error(%s)", + myname, __LINE__, dlname, acl_last_serror()); + return (handle); +} + +void acl_dlclose(ACL_DLL_HANDLE handle) +{ +#ifdef ACL_UNIX + dlclose(handle); +#elif defined(ACL_MS_WINDOWS) + FreeLibrary(handle); +#endif +} + +ACL_DLL_FARPROC acl_dlsym(void *handle, const char *name) +{ +#ifdef ACL_UNIX + return (dlsym(handle, name)); +#elif defined(ACL_MS_WINDOWS) + return (GetProcAddress(handle, name)); +#endif +} + diff --git a/lib_acl/src/stdlib/sys/acl_env.c b/lib_acl/src/stdlib/sys/acl_env.c new file mode 100644 index 000000000..2c694349d --- /dev/null +++ b/lib_acl/src/stdlib/sys/acl_env.c @@ -0,0 +1,221 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#ifdef ACL_UNIX +#include +#endif +#include + +/* Utility library. */ + +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_msg.h" +#include "stdlib/acl_argv.h" +#include "stdlib/acl_safe.h" +#include "thread/acl_pthread.h" +#include "stdlib/acl_mystring.h" +#include "stdlib/acl_env.h" + +#endif + +/* acl_clean_env - clean up the environment */ + +void acl_clean_env(char **preserve_list) +{ +#ifdef ACL_UNIX + extern char **environ; + char **env = environ; +#elif defined(ACL_MS_WINDOWS) + extern char **_environ; + char **env = _environ; +#endif + ACL_ARGV *save_list; + char *value; + char **cpp; + char *eq; + + /* + * Preserve or specify selected environment variables. + */ +#define STRING_AND_LENGTH(x, y) (x), (ssize_t) (y) + + save_list = acl_argv_alloc(10); + for (cpp = preserve_list; *cpp; cpp++) + if ((eq = strchr(*cpp, '=')) != 0) + acl_argv_addn(save_list, STRING_AND_LENGTH(*cpp, eq - *cpp), + STRING_AND_LENGTH(eq + 1, strlen(eq + 1)), (char *) 0); + else if ((value = acl_safe_getenv(*cpp)) != 0) + acl_argv_add(save_list, *cpp, value, (char *) 0); + + /* + * Truncate the process environment, if available. On some systems + * (Ultrix!), environ can be a null pointer. + */ + if (env) + env[0] = 0; + + /* + * Restore preserved environment variables. + */ + for (cpp = save_list->argv; *cpp; cpp += 2) +#ifdef ACL_UNIX + if (setenv(cpp[0], cpp[1], 1)) +#elif defined(ACL_MS_WINDOWS) + if (!SetEnvironmentVariable(cpp[0], cpp[1])) +#endif + acl_msg_error("setenv(%s, %s): %s", cpp[0], cpp[1], acl_last_serror()); + + /* + * Cleanup. + */ + acl_argv_free(save_list); +} + +char *acl_getenv(const char *name) +{ +#ifdef ACL_MS_WINDOWS + const char *myname = "acl_getenv"; + static acl_pthread_key_t buf_key = ACL_TLS_OUT_OF_INDEXES; + char *buf; +#define ENV_BUF_SIZE 4096 + + buf = (char*) acl_pthread_tls_get(&buf_key); + if (buf == NULL) { + if (buf_key == ACL_TLS_OUT_OF_INDEXES) { + acl_msg_error("%s(%d): acl_pthread_tls_get error(%s)", + myname, __LINE__, acl_last_serror()); + return (NULL); + } + buf = (char*) acl_mymalloc(ENV_BUF_SIZE); + acl_pthread_tls_set(buf_key, buf, (void (*)(void*)) acl_myfree_fn); + } + + if (GetEnvironmentVariable(name, buf, ENV_BUF_SIZE) == 0) + return (NULL); + return (buf); +#else + return (getenv(name)); +#endif +} + +char *acl_getenv3(const char *name, char *buf, size_t len) +{ +#ifdef ACL_MS_WINDOWS + if (GetEnvironmentVariable(name, buf, len) == 0) + return (NULL); + return (buf); +#else + const char *ptr = getenv(name); + if (ptr == NULL) + return (NULL); + ACL_SAFE_STRNCPY(buf, ptr, len); + return (buf); +#endif +} + +int acl_setenv(const char *name, const char *val, int overwrite) +{ +#ifdef ACL_MS_WINDOWS + if (overwrite == 0) { + if (acl_getenv(name) != NULL) + return (0); + } + if (!SetEnvironmentVariable(name, val)) + return (-1); + return (0); +#else + return (setenv(name, val, overwrite)); +#endif +} + +int acl_putenv(char *str) +{ +#ifdef ACL_MS_WINDOWS + const char *myname = "acl_putenv"; + ACL_ARGV *argv = acl_argv_split(str, "="); + + if (argv->argc != 2) { + acl_msg_error("%s(%d): input(%s) invalid", myname, __LINE__, str); + return (-1); + } + if (!SetEnvironmentVariable(argv->argv[0], argv->argv[1])) { + acl_msg_error("%s(%d): putenv(%s, %s) error(%s)", + myname, __LINE__, argv->argv[0], argv->argv[1], acl_last_serror()); + return (-1); + } + return (0); +#else + return (putenv(str)); +#endif +} + +static void free_vstring(ACL_VSTRING *s) +{ + acl_vstring_free(s); +} + +const char *acl_getenv_list(void) +{ + const char *myname = "acl_getenv_list"; +#ifdef ACL_MS_WINDOWS + static acl_pthread_key_t buf_key = ACL_TLS_OUT_OF_INDEXES; + ACL_VSTRING *buf; + LPTSTR lpszVariable; + LPVOID lpvEnv; + int i = 0, ch = 0; + + buf = (ACL_VSTRING*) acl_pthread_tls_get(&buf_key); + if (buf == NULL) { + if (buf_key == ACL_TLS_OUT_OF_INDEXES) { + acl_msg_error("%s(%d): acl_pthread_tls_get error(%s)", + myname, __LINE__, acl_last_serror()); + return (NULL); + } + buf = acl_vstring_alloc(256); + acl_pthread_tls_set(buf_key, buf, (void (*)(void*)) free_vstring); + } else + ACL_VSTRING_RESET(buf); + + lpvEnv = GetEnvironmentStrings(); + for (lpszVariable = (LPTSTR) lpvEnv; *lpszVariable; lpszVariable++) { + if (i++ > 0) + acl_vstring_strcat(buf, ", "); + while (*lpszVariable) { + ACL_VSTRING_ADDCH(buf, *lpszVariable++); + ch = *lpszVariable; + } + } + FreeEnvironmentStrings(lpvEnv); + ACL_VSTRING_TERMINATE(buf); + return (acl_vstring_str(buf)); +#else + extern char **_environ; + static acl_pthread_key_t buf_key = ACL_TLS_OUT_OF_INDEXES; + ACL_VSTRING *buf; + char **pptr = _environ; + int i = 0; + + buf = (ACL_VSTRING*) acl_pthread_tls_get(&buf_key); + if (buf == NULL) { + if (buf_key == (acl_pthread_key_t) ACL_TLS_OUT_OF_INDEXES) { + acl_msg_error("%s(%d): acl_pthread_tls_get error(%s)", + myname, __LINE__, acl_last_serror()); + return (NULL); + } + buf = acl_vstring_alloc(256); + acl_pthread_tls_set(buf_key, buf, (void (*)(void*)) free_vstring); + } else + ACL_VSTRING_RESET(buf); + + while (*pptr) { + if (i++ > 0) + acl_vstring_strcat(buf, ", "); + acl_vstring_strcat(buf, *pptr); + pptr++; + } + return (acl_vstring_str(buf)); +#endif +} diff --git a/lib_acl/src/stdlib/sys/acl_exec_command.c b/lib_acl/src/stdlib/sys/acl_exec_command.c new file mode 100644 index 000000000..27f41c39a --- /dev/null +++ b/lib_acl/src/stdlib/sys/acl_exec_command.c @@ -0,0 +1,79 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include +#ifdef ACL_UNIX +#include +#elif defined(ACL_MS_WINDOWS) +#include +#endif + +/* Utility library. */ + +#include "stdlib/acl_msg.h" +#include "stdlib/acl_argv.h" +#include "stdlib/acl_exec_command.h" + +#endif + +/* Application-specific. */ + +#define SPACE_TAB " \t" + +/* exec_command - exec command */ + +void acl_exec_command(const char *command) +{ + ACL_ARGV *argv; + + /* + * Character filter. In this particular case, we allow space and tab in + * addition to the regular character set. + */ + static char ok_chars[] = "1234567890!@%-_=+:,./" + "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" SPACE_TAB; + + /* + * See if this command contains any shell magic characters. + */ + if (command[strspn(command, ok_chars)] == 0) { + + /* + * No shell meta characters found, so we can try to avoid the overhead + * of running a shell. Just split the command on whitespace and exec + * the result directly. + */ + argv = acl_argv_split(command, SPACE_TAB); +#ifdef ACL_UNIX + (void) execvp(argv->argv[0], argv->argv); +#elif defined(ACL_MS_WINDOWS) + (void) _execvp(argv->argv[0], argv->argv); +#endif + + /* + * Auch. Perhaps they're using some shell built-in command. + */ + if (errno != ENOENT || strchr(argv->argv[0], '/') != 0) + acl_msg_fatal("execvp %s: %s", argv->argv[0], acl_last_serror()); + + /* + * Not really necessary, but... + */ + acl_argv_free(argv); + } + + /* + * Pass the command to a shell. + */ +#ifdef ACL_UNIX + (void) execl(ACL_PATH_BSHELL, "sh", "-c", command, (char *) 0); + acl_msg_fatal("execl %s: %s", ACL_PATH_BSHELL, acl_last_serror()); +#elif defined(ACL_MS_WINDOWS) + (void) _execl(command, command, _execl, NULL); + acl_msg_fatal("execl %s: %s", command, acl_last_serror()); +#endif +} diff --git a/lib_acl/src/stdlib/sys/acl_process.c b/lib_acl/src/stdlib/sys/acl_process.c new file mode 100644 index 000000000..d183b92c3 --- /dev/null +++ b/lib_acl/src/stdlib/sys/acl_process.c @@ -0,0 +1,212 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#ifdef ACL_UNIX +#include +#endif + +#include "stdlib/acl_msg.h" +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_process.h" +#include "thread/acl_thread.h" + +#endif + +#define BUF_SIZE 4096 + +static char *get_tls_buf(void) +{ + const char *myname = "get_tls_buf"; + static acl_pthread_key_t buf_key = ACL_TLS_OUT_OF_INDEXES; + char *buf; + static char buf_unsafe[BUF_SIZE]; + + buf = (char*) acl_pthread_tls_get(&buf_key); + if (buf != NULL) + return (buf); + + if (buf_key == (acl_pthread_key_t) ACL_TLS_OUT_OF_INDEXES) { + acl_msg_warn("%s(%d): acl_pthread_tls_get error(%s), " + "use unsafe buf", myname, __LINE__, acl_last_serror()); + buf = buf_unsafe; + } else { + buf = (char*) acl_mycalloc(1, BUF_SIZE); + acl_pthread_tls_set(buf_key, buf, + (void (*)(void*)) acl_myfree_fn); + } + return (buf); +} + +#ifdef ACL_LINUX +const char *acl_process_path() +{ + const char *myname = "acl_process_path"; + char *buf_ptr = get_tls_buf(); + int ret; + + ret = readlink("/proc/self/exe", buf_ptr, BUF_SIZE); + if (ret < 0) { + acl_msg_error("%s(%d): readlink error(%s)", + myname, __LINE__, acl_last_serror()); + return (NULL); + } + return (buf_ptr); +} + +const char *acl_getcwd() +{ + const char *myname = "acl_getcwd"; + char *buf_ptr = get_tls_buf(); + char *ptr; + + ptr = getcwd(buf_ptr, BUF_SIZE); + if (ptr == NULL) { + acl_msg_error("%s(%d): getcwd error(%s)", + myname, __LINE__, acl_last_serror()); + } + return (ptr); +} +#elif defined(ACL_FREEBSD) +const char *acl_process_path() +{ + const char *myname = "acl_process_path"; + char *buf_ptr = get_tls_buf(); + int ret; + + ret = readlink("/proc/curproc/file", buf_ptr, BUF_SIZE); + if (ret < 0) { + acl_msg_error("%s(%d): readlink error(%s)", + myname, __LINE__, acl_last_serror()); + return (NULL); + } + return (buf_ptr); +} + +const char *acl_getcwd() +{ + const char *myname = "acl_getcwd"; + char *buf_ptr = get_tls_buf(); + char *ptr; + + ptr = getcwd(buf_ptr, BUF_SIZE); + if (ptr == NULL) { + acl_msg_error("%s(%d): getcwd error(%s)", + myname, __LINE__, acl_last_serror()); + } + return (ptr); +} +#elif defined(ACL_MACOSX) +const char *acl_process_path() +{ + const char *myname = "acl_process_path"; + char *buf_ptr = get_tls_buf(); + int ret; + + ret = readlink("/proc/curproc/file", buf_ptr, BUF_SIZE); + if (ret < 0) { + acl_msg_error("%s(%d): readlink error(%s)", + myname, __LINE__, acl_last_serror()); + return (NULL); + } + return (buf_ptr); +} + +const char *acl_getcwd() +{ + const char *myname = "acl_getcwd"; + char *buf_ptr = get_tls_buf(); + char *ptr; + + ptr = getcwd(buf_ptr, BUF_SIZE); + if (ptr == NULL) { + acl_msg_error("%s(%d): getcwd error(%s)", + myname, __LINE__, acl_last_serror()); + } + return (ptr); +} + +#elif defined(ACL_SUNOS5) +const char *acl_process_path() +{ + const char *myname = "acl_process_path"; + char *buf_ptr = get_tls_buf(); + int ret; + + ret = readlink("/proc/self/path/a.out", buf_ptr, BUF_SIZE); + if (ret < 0) { + acl_msg_error("%s(%d): readlink error(%s)", + myname, __LINE__, acl_last_serror()); + return (NULL); + } + return (buf_ptr); +} + +#if 0 +#include +const char *acl_process_path() +{ + const char *myname = "acl_process_path"; + const char *ptr; + + ptr = getexecname(); + if (ptr == NULL) { + acl_msg_error("%s(%d): readlink error(%s)", + myname, __LINE__, acl_last_serror()); + return (NULL); + } + return (ptr); +} +#endif + +const char *acl_getcwd() +{ + const char *myname = "acl_getcwd"; + char *buf_ptr = get_tls_buf(); + char *ptr; + + ptr = getcwd(buf_ptr, BUF_SIZE); + if (ptr == NULL) { + acl_msg_error("%s(%d): getcwd error(%s)", + myname, __LINE__, acl_last_serror()); + } + return (ptr); +} +#elif defined(ACL_MS_WINDOWS) +#include + +const char *acl_process_path() +{ + const char *myname = "acl_process_path"; + char *buf_ptr = get_tls_buf(); + int ret; + + ret = GetModuleFileName(NULL, buf_ptr, BUF_SIZE); + if (ret == 0) { + acl_msg_error("%s(%d): readlink error(%s)", + myname, __LINE__, acl_last_serror()); + return (NULL); + } + return (buf_ptr); +} + +const char *acl_getcwd() +{ + const char *myname = "acl_getcwd"; + char *buf_ptr = get_tls_buf(); + char *ptr; + + ptr = _getcwd(buf_ptr, BUF_SIZE); + if (ptr == NULL) { + acl_msg_error("%s(%d): getcwd error(%s)", + myname, __LINE__, acl_last_serror()); + } + return (ptr); +} +#else +# error "unknown OS type" +#endif diff --git a/lib_acl/src/stdlib/sys/acl_safe_getenv.c b/lib_acl/src/stdlib/sys/acl_safe_getenv.c new file mode 100644 index 000000000..a214743c8 --- /dev/null +++ b/lib_acl/src/stdlib/sys/acl_safe_getenv.c @@ -0,0 +1,23 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include + +/* Utility library. */ + +#include "stdlib/acl_safe.h" + +#endif + +/* safe_getenv - read environment variable with guard */ + +char *acl_safe_getenv(const char *name) +{ +#ifdef ACL_UNIX + return (acl_unsafe() == 0 ? getenv(name) : 0); +#elif defined(ACL_MS_WINDOWS) + return (getenv(name)); +#endif +} + diff --git a/lib_acl/src/stdlib/sys/acl_sys_file.c b/lib_acl/src/stdlib/sys/acl_sys_file.c new file mode 100644 index 000000000..2f45bbebd --- /dev/null +++ b/lib_acl/src/stdlib/sys/acl_sys_file.c @@ -0,0 +1,398 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef ACL_MS_WINDOWS +#include +#include +#include + +#define WIN32_LEAN_AND_MEAN +#include +#include + +#endif + +#ifdef ACL_UNIX +#include +#include +#include +#include +#include +#include +#endif + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_msg.h" +#include "stdlib/acl_vstream.h" /* for ACL_VSTREAM_EOF */ +#include "stdlib/acl_sys_patch.h" + +#endif + +#ifdef ACL_MS_WINDOWS + +ACL_FILE_HANDLE acl_file_open(const char *filepath, int flags, int mode) +{ + ACL_FILE_HANDLE fh; + DWORD fileaccess = 0, fileshare = 0, filecreate = 0, fileattr = 0; + + /* decode the access flags */ + switch (flags & (O_RDONLY | O_WRONLY | O_RDWR)) { + case O_RDONLY: /* read access */ + fileaccess = GENERIC_READ; + break; + case O_WRONLY: /* write access */ + fileaccess = GENERIC_WRITE; + break; + case O_RDWR: /* read and write access */ + fileaccess = GENERIC_READ | GENERIC_WRITE; + break; + default: /* error, bad flags */ + acl_set_error(ERROR_INVALID_PARAMETER); + return (ACL_FILE_INVALID); + } + + /* decode open/create method flags */ + switch (flags & (O_CREAT | O_EXCL | O_TRUNC)) { + case 0: + case O_EXCL: /* ignore EXCL w/o CREAT */ + filecreate = OPEN_EXISTING; + break; + case O_CREAT: + filecreate = OPEN_ALWAYS; + break; + case O_CREAT | O_EXCL: + case O_CREAT | O_TRUNC | O_EXCL: + filecreate = CREATE_NEW; + break; + case O_TRUNC: + case O_TRUNC | O_EXCL: /* ignore EXCL w/o CREAT */ + filecreate = TRUNCATE_EXISTING; + break; + case O_CREAT | O_TRUNC: + filecreate = CREATE_ALWAYS; + break; + default: + /* this can't happen ... all cases are covered */ + acl_set_error(ERROR_INVALID_PARAMETER); + return (ACL_FILE_INVALID); + } + + fileshare |= FILE_SHARE_READ | FILE_SHARE_WRITE; + fileattr = FILE_ATTRIBUTE_NORMAL; + + fh = CreateFile(filepath, fileaccess, fileshare, NULL, + filecreate, fileattr, NULL); + return (fh); +} + +int acl_file_close(ACL_FILE_HANDLE fh) +{ + return (CloseHandle(fh) ? 0 : -1); +} + +acl_off_t acl_lseek(ACL_FILE_HANDLE fh, acl_off_t offset, int whence) +{ + const char *myname = "acl_lseek"; + LARGE_INTEGER li; + DWORD method; + + if (whence == SEEK_CUR) + method = FILE_CURRENT; + else if (whence == SEEK_SET) + method = FILE_BEGIN; + else if (whence == SEEK_END) + method = FILE_END; + else { + acl_msg_error("%s(%d): invalid whence(%d)", myname, __LINE__, whence); + return (-1); + } + + li.QuadPart = offset; + li.LowPart = SetFilePointer(fh, li.LowPart, &li.HighPart, method); + + if (li.LowPart == 0xFFFFFFFF && acl_last_error() != NO_ERROR) { + li.QuadPart = -1; + } + + return li.QuadPart; +} + +int acl_file_read(ACL_FILE_HANDLE fh, void *buf, size_t size, + int timeout acl_unused, void *arg acl_unused) +{ + DWORD nRead = 0; + + if (!ReadFile(fh, buf, size, &nRead, NULL)) + return (ACL_VSTREAM_EOF); + + return (nRead); +} + +int acl_file_write(ACL_FILE_HANDLE fh, const void *buf, size_t size, + int timeout acl_unused, void *arg acl_unused) +{ + DWORD nWritten = 0; + + if (!WriteFile(fh, buf, size, &nWritten, NULL)) + return (ACL_VSTREAM_EOF); + + return (nWritten); +} + +int acl_file_writev(ACL_FILE_HANDLE fh, const struct iovec *vector, int count, + int timeout acl_unused, void *arg acl_unused) +{ + int i, n; + DWORD nWritten = 0; + + n = 0; + for (i = 0; i < count; i++) { + if (!WriteFile(fh, vector[i].iov_base, vector[i].iov_len, &nWritten, NULL)) + return (ACL_VSTREAM_EOF); + else if (nWritten != vector[i].iov_len) { + n += nWritten; + break; + } + n += vector[i].iov_len; + } + return (n); +} + +int acl_file_fflush(ACL_FILE_HANDLE fh) +{ + if (FlushFileBuffers(fh)) + return (0); + return (-1); +} + +acl_int64 acl_file_size(const char *filename) +{ + struct acl_stat sbuf; + + if (acl_stat(filename, &sbuf) == -1) + return (-1); + return (sbuf.st_size); +} + +acl_int64 acl_file_fsize(ACL_FILE_HANDLE fh) +{ + DWORD nLow, nHigh; + acl_int64 n; + + nLow = GetFileSize(fh, &nHigh); + if (nLow == 0xFFFFFFFF) + return (-1); + n = nHigh; + return (nLow + (n << 32)); +} + +/* this function comes from MS'S C Library */ + +int acl_fstat(ACL_FILE_HANDLE fh, struct acl_stat *buf) +{ + int isdev; /* 0 for a file, 1 for a device */ + int retval = 0; /* assume good return */ + BY_HANDLE_FILE_INFORMATION bhfi; + FILETIME LocalFTime; + SYSTEMTIME SystemTime; + struct tm t; + + isdev = GetFileType(fh) & ~FILE_TYPE_REMOTE; + if (isdev != FILE_TYPE_DISK) { + if (isdev == FILE_TYPE_CHAR || isdev == FILE_TYPE_PIPE) { + if (isdev == FILE_TYPE_CHAR) + buf->st_mode = _S_IFCHR; + else + buf->st_mode = _S_IFIFO; + + buf->st_rdev = buf->st_dev = 0; + buf->st_nlink = 1; + buf->st_uid = buf->st_gid = buf->st_ino = 0; + buf->st_atime = buf->st_mtime = buf->st_ctime = 0; + if (isdev == FILE_TYPE_CHAR) { + buf->st_size = 0; + } else { + unsigned long ulAvail; + int rc; + + rc = PeekNamedPipe(fh, NULL, 0, NULL, &ulAvail, NULL); + if (rc) { + buf->st_size = (_off_t) ulAvail; + } else { + buf->st_size = (_off_t) 0; + } + } + + goto done; + } else if (isdev == FILE_TYPE_UNKNOWN) { + retval = -1; + goto done; /* join common return code */ + } else { + retval = -1; + goto done; + } + } + + /* set the common fields + */ + buf->st_ino = buf->st_uid = buf->st_gid = buf->st_mode = 0; + buf->st_nlink = 1; + + /* use the file handle to get all the info about the file */ + if (!GetFileInformationByHandle(fh, &bhfi)) { + retval = -1; + goto done; + } + + if (bhfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY) + buf->st_mode |= (_S_IREAD + (_S_IREAD >> 3) + (_S_IREAD >> 6)); + else + buf->st_mode |= ((_S_IREAD|_S_IWRITE) + ((_S_IREAD|_S_IWRITE) >> 3) + + ((_S_IREAD|_S_IWRITE) >> 6)); + + /* set file date fields */ + if (!FileTimeToLocalFileTime(&(bhfi.ftLastWriteTime), &LocalFTime) + || !FileTimeToSystemTime(&LocalFTime, &SystemTime )) + { + retval = -1; + goto done; + } + + t.tm_year = SystemTime.wYear - 1900; + t.tm_mon = SystemTime.wMonth - 1; + t.tm_mday = SystemTime.wDay; + t.tm_hour = SystemTime.wHour; + t.tm_min = SystemTime.wMinute; + t.tm_sec = SystemTime.wSecond; + buf->st_mtime = mktime(&t); + + if (bhfi.ftLastAccessTime.dwLowDateTime + ||bhfi.ftLastAccessTime.dwHighDateTime) + { + + if (!FileTimeToLocalFileTime(&(bhfi.ftLastAccessTime), + &LocalFTime ) + || !FileTimeToSystemTime(&LocalFTime, &SystemTime)) + { + retval = -1; + goto done; + } + + t.tm_year = SystemTime.wYear - 1900; + t.tm_mon = SystemTime.wMonth - 1; + t.tm_mday = SystemTime.wDay; + t.tm_hour = SystemTime.wHour; + t.tm_min = SystemTime.wMinute; + t.tm_sec = SystemTime.wSecond; + buf->st_atime = mktime(&t); + } + else + buf->st_atime = buf->st_mtime; + + if (bhfi.ftCreationTime.dwLowDateTime + || bhfi.ftCreationTime.dwHighDateTime) + { + if (!FileTimeToLocalFileTime(&(bhfi.ftCreationTime), &LocalFTime) + || !FileTimeToSystemTime(&LocalFTime, &SystemTime)) + { + retval = -1; + goto done; + } + + t.tm_year = SystemTime.wYear - 1900; + t.tm_mon = SystemTime.wMonth - 1; + t.tm_mday = SystemTime.wDay; + t.tm_hour = SystemTime.wHour; + t.tm_min = SystemTime.wMinute; + t.tm_sec = SystemTime.wSecond; + buf->st_ctime = mktime(&t); + } + else + buf->st_ctime = buf->st_mtime; + + buf->st_size = ((__int64)(bhfi.nFileSizeHigh)) * (0x100000000i64) + + (__int64)(bhfi.nFileSizeLow); + + buf->st_mode |= _S_IFREG; + + /* On DOS, this field contains the drive number, but + * the drive number is not available on this platform. + * Also, for UNC network names, there is no drive number. + */ + buf->st_rdev = buf->st_dev = 0; + +/* Common return code */ +done: + return(retval); +} + +#elif defined(ACL_UNIX) + +ACL_FILE_HANDLE acl_file_open(const char *filepath, int flags, int mode) +{ + return (open(filepath, flags, mode)); +} + +int acl_file_close(ACL_FILE_HANDLE fh) +{ + return (close(fh)); +} + +acl_off_t acl_lseek(ACL_FILE_HANDLE fh, acl_off_t offset, int whence) +{ +#if defined(ACL_LINUX) || defined(ACL_SUNOS5) + return (lseek64(fh, offset, whence)); +#else + return (lseek(fh, offset, whence)); +#endif +} + +int acl_file_read(ACL_FILE_HANDLE fh, void *buf, size_t size, + int timeout acl_unused, void *arg acl_unused) +{ + return (read(fh, buf, size)); +} + +int acl_file_write(ACL_FILE_HANDLE fh, const void *buf, size_t size, + int timeout acl_unused, void *arg acl_unused) +{ + return (write(fh, buf, size)); +} + +int acl_file_writev(ACL_FILE_HANDLE fh, const struct iovec *vector, int count, + int timeout acl_unused, void *arg acl_unused) +{ + return (writev(fh, vector, count)); +} + +int acl_file_fflush(ACL_FILE_HANDLE fh) +{ + return (fsync(fh)); +} + +acl_int64 acl_file_size(const char *filename) +{ + struct acl_stat sbuf; + + if (acl_stat(filename, &sbuf) == -1) + return (-1); + return (sbuf.st_size); +} + +acl_int64 acl_file_fsize(ACL_FILE_HANDLE fh) +{ + struct acl_stat sbuf; + + if (acl_fstat(fh, &sbuf) == -1) + return (-1); + return (sbuf.st_size); +} + +#else +# error "unknown OS type" +#endif diff --git a/lib_acl/src/stdlib/sys/acl_sys_socket.c b/lib_acl/src/stdlib/sys/acl_sys_socket.c new file mode 100644 index 000000000..976f32ad4 --- /dev/null +++ b/lib_acl/src/stdlib/sys/acl_sys_socket.c @@ -0,0 +1,209 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#include +#ifdef ACL_MS_WINDOWS +#include +#include + +#define WIN32_LEAN_AND_MEAN +#include +#include + +#endif + +#ifdef ACL_UNIX +#include +#include +#include +#include +#include +#include +#endif + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_msg.h" +#include "stdlib/acl_vstream.h" /* for ACL_VSTREAM_EOF */ +#include "stdlib/acl_sys_patch.h" + +#endif + +#ifdef ACL_MS_WINDOWS + +static int __socket_inited = 0; +static int __socket_ended = 0; + +int acl_socket_init(void) +{ + const char *myname = "acl_socket_init"; + WORD version = 0; + WSADATA data; + char ebuf[256]; + + if (__socket_inited) { + acl_msg_warn("%s(%d): has been inited", myname, __LINE__); + return (0); + } + + __socket_inited = 1; + + FillMemory(&data, sizeof(WSADATA), 0); + + version = MAKEWORD(2, 0); + + if (WSAStartup(version, &data) != 0) { + acl_msg_error("%s(%d): WSAStartup error(%s)", + myname, __LINE__, acl_last_strerror(ebuf, sizeof(ebuf))); + return (-1); + } + if (LOBYTE(data.wVersion) != 2 || HIBYTE(data.wVersion) != 0) { + WSACleanup(); + acl_msg_error("%s(%d): LOBYTE(data.wVersion) = %d" + ", HIBYTE(data.wVersion) = %d", myname, __LINE__, + LOBYTE(data.wVersion), HIBYTE(data.wVersion)); + return (-1); + } + + __socket_ended = 0; + return (0); +} + +int acl_socket_end(void) +{ + const char *myname = "acl_socket_end"; + char ebuf[256]; + + if (__socket_ended) { + acl_msg_warn("%s(%d): has been ended", myname, __LINE__); + return (0); + } + __socket_ended = 1; + + if (WSACleanup() == SOCKET_ERROR) { + acl_msg_error("%s(%d): WSACleanup error(%s)", + myname, __LINE__, acl_last_strerror(ebuf, sizeof(ebuf))); + return -1; + } + + __socket_inited = 0; + return 0; +} + +int acl_socket_close(ACL_SOCKET fd) +{ + return (closesocket(fd)); +} + +int acl_socket_read(ACL_SOCKET fd, void *buf, size_t size, + int timeout acl_unused, void *arg acl_unused) +{ +#if 0 + WSABUF wsaData; + DWORD dwBytes = 0; + DWORD flags = 0; + int ret; + + wsaData.len = (u_long) size; + wsaData.buf = (char*) buf; + ret = WSARecv(fd, &wsaData, 1, &dwBytes, &flags, NULL, NULL); + if (ret == SOCKET_ERROR) + return (-1); + if (dwBytes == 0) + return (-1); + return (dwBytes); +#else + int ret = recv(fd, buf, size, 0); + if (ret <= 0) + errno = acl_last_error(); + return (ret); +#endif +} + +int acl_socket_write(ACL_SOCKET fd, const void *buf, size_t size, + int timeout acl_unused, void *arg acl_unused) +{ +#if 0 + WSABUF wsaData; + DWORD dwBytes = 0; + int ret; + + wsaData.len = (u_long) size; + wsaData.buf = (char*) buf; + + ret = WSASend(fd, &wsaData, 1, &dwBytes, 0, NULL, NULL); + if (ret == SOCKET_ERROR) + return (-1); + return (dwBytes); +#else + int ret = send(fd, buf, size, 0); + + if (ret <= 0) + errno = acl_last_error(); + return (ret); +#endif +} + +int acl_socket_writev(ACL_SOCKET fd, const struct iovec *vector, int count, + int timeout acl_unused, void *arg acl_unused) +{ + int i, n, ret; + + n = 0; + for (i = 0; i < count; i++) { + ret = send(fd, vector[i].iov_base, vector[i].iov_len, 0); + if (ret == SOCKET_ERROR) { + errno = acl_last_error(); + return (-1); + } else if (ret < (int) vector[i].iov_len) { + n += ret; + break; + } + n += ret; + } + return (n); +} + +#elif defined(ACL_UNIX) + +int acl_socket_init(void) +{ + signal(SIGPIPE, SIG_IGN); + return (0); +} + +int acl_socket_end(void) +{ + return (0); +} + +int acl_socket_close(ACL_SOCKET fd) +{ + return (close(fd)); +} + +int acl_socket_read(ACL_SOCKET fd, void *buf, size_t size, + int timeout acl_unused, void *arg acl_unused) +{ + return (read(fd, buf, size)); +} + +int acl_socket_write(ACL_SOCKET fd, const void *buf, size_t size, + int timeout acl_unused, void *arg acl_unused) +{ + return (write(fd, buf, size)); +} + +int acl_socket_writev(ACL_SOCKET fd, const struct iovec *vector, int count, + int timeout acl_unused, void *arg acl_unused) +{ + return (writev(fd, vector, count)); +} + +#else +# error "unknown OS type" +#endif diff --git a/lib_acl/src/stdlib/sys/acl_unsafe.c b/lib_acl/src/stdlib/sys/acl_unsafe.c new file mode 100644 index 000000000..40a4e1d00 --- /dev/null +++ b/lib_acl/src/stdlib/sys/acl_unsafe.c @@ -0,0 +1,30 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include "stdlib/acl_safe.h" + +/* System library. */ +#ifdef ACL_UNIX +#include +#endif + +#endif + +/* acl_unsafe - can we trust user-provided environment, working directory, etc. */ + +#ifdef ACL_UNIX +int acl_unsafe(void) +{ + return (geteuid() != getuid() +#ifdef HAS_ISSETUGID + || issetugid() +#endif + || getgid() != getegid()); +} +#elif defined(ACL_MS_WINDOWS) +int acl_unsafe(void) +{ + return (0); +} +#endif diff --git a/lib_acl/src/stdlib/sys/gettimeofday.c b/lib_acl/src/stdlib/sys/gettimeofday.c new file mode 100644 index 000000000..97ed8bcc5 --- /dev/null +++ b/lib_acl/src/stdlib/sys/gettimeofday.c @@ -0,0 +1,232 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef ACL_MS_WINDOWS +# define WIN32_LEAN_AND_MEAN +# include +# include +#endif + +#ifdef ACL_BCB_COMPILER +# pragma hdrstop +#endif + +#include "stdlib/acl_msg.h" +#include "stdlib/acl_sys_patch.h" + +#endif + +#ifdef ACL_MS_WINDOWS + +#if 1 + +# ifndef __GNUC__ +# define EPOCHFILETIME (116444736000000000i64) +# else +# define EPOCHFILETIME (116444736000000000LL) +# endif + +#ifndef ACL_DLL +int _daylight; +long _timezone; +#endif + +static void dummy(void *ptr acl_unused) +{ + +} + +static void free_tls(void *ptr) +{ + acl_myfree(ptr); +} + +static void *__tls = NULL; +static void main_free_tls(void) +{ + if (__tls) { + acl_myfree(__tls); + __tls = NULL; + } +} + +static acl_pthread_key_t once_key; +static void once_init(void) +{ + if ((unsigned long) acl_pthread_self() == acl_main_thread_self()) { + acl_pthread_key_create(&once_key, dummy); + atexit(main_free_tls); + } else + acl_pthread_key_create(&once_key, free_tls); +} + +static acl_pthread_once_t once_control = ACL_PTHREAD_ONCE_INIT; +static void *tls_calloc(size_t len) +{ + void *ptr; + + (void) acl_pthread_once(&once_control, once_init); + ptr = (void*) acl_pthread_getspecific(once_key); + if (ptr == NULL) { + ptr = acl_mycalloc(1, len); + acl_pthread_setspecific(once_key, ptr); + if ((unsigned long) acl_pthread_self() == acl_main_thread_self()) + __tls = ptr; + } + return ptr; +} + +typedef struct { + time_t last_init; + struct timeval tvbase; + LARGE_INTEGER frequency; + LARGE_INTEGER stamp; + int tzflag; +} TIME_CTX_T; + +int gettimeofday(struct timeval *tv, struct timezone *tz) +{ + FILETIME ft; + LARGE_INTEGER li; + __int64 t; + int nnested = 0; + LARGE_INTEGER stamp; + time_t now; + TIME_CTX_T *ctx = tls_calloc(sizeof(TIME_CTX_T)); + + /* 每个线程调用此函数时都需要进行初始化,但为了防止开机时间太长 + * 而造成时钟计数归零溢出,所以每隔 1 天校对一次基准时间 + */ +#define DAY_SEC (3600 * 24) + + time(&now); + if (now - ctx->last_init > DAY_SEC) { + ctx->last_init = now; + + /* 获得CPU的时钟频率 */ + if (!QueryPerformanceFrequency(&ctx->frequency)) + acl_msg_fatal("%s(%d): Unable to get System Frequency(%s)", + __FILE__, __LINE__, acl_last_serror()); + /* 获得系统时间(自 1970 至今) */ + GetSystemTimeAsFileTime(&ft); + li.LowPart = ft.dwLowDateTime; + li.HighPart = ft.dwHighDateTime; + t = li.QuadPart; /* In 100-nanosecond intervals */ + t -= EPOCHFILETIME; /* Offset to the Epoch time */ + t /= 10; /* In microseconds */ + + /* 转换成本次开机后的基准时间 */ + ctx->tvbase.tv_sec = (long)(t / 1000000); + ctx->tvbase.tv_usec = (long)(t % 1000000); + + /* 获得本次开机后到现在的时钟计数 */ + if (!QueryPerformanceCounter(&ctx->stamp)) + acl_msg_fatal("%s(%d): unable to get System time(%s)", + __FILE__, __LINE__, acl_last_serror()); + } + + /* 开始获得现在的时间截 */ + + if (tv) { + /* 获得本次开机后至现在的时钟计数 */ + if (!QueryPerformanceCounter(&stamp)) + acl_msg_fatal("%s(%d): unable to get System time(%s)", + __FILE__, __LINE__, acl_last_serror()); + + /* 计算当前精确时间截 */ + t = (stamp.QuadPart - ctx->stamp.QuadPart) * 1000000 / ctx->frequency.QuadPart; + tv->tv_sec = ctx->tvbase.tv_sec + (long)(t / 1000000); + tv->tv_usec = ctx->tvbase.tv_usec + (long)(t % 1000000); + } + + if (tz) { + if (!ctx->tzflag) { + _tzset(); + ctx->tzflag++; + } + tz->tz_minuteswest = _timezone / 60; + tz->tz_dsttime = _daylight; + } + + return (0); +} + +#elif 1 + +# ifndef __GNUC__ +# define EPOCHFILETIME (116444736000000000i64) +# else +# define EPOCHFILETIME (116444736000000000LL) +# endif + +int _daylight; +long _timezone; + +int gettimeofday(struct timeval *tv, struct timezone *tz) +{ + FILETIME ft; + LARGE_INTEGER li; + __int64 t; + static int tzflag; + + if (tv) { + GetSystemTimeAsFileTime(&ft); + li.LowPart = ft.dwLowDateTime; + li.HighPart = ft.dwHighDateTime; + t = li.QuadPart; /* In 100-nanosecond intervals */ + t -= EPOCHFILETIME; /* Offset to the Epoch time */ + t /= 10; /* In microseconds */ + tv->tv_sec = (long)(t / 1000000); + tv->tv_usec = (long)(t % 1000000); + } + + if (tz) { + if (!tzflag) { + _tzset(); + tzflag++; + } + tz->tz_minuteswest = _timezone / 60; + tz->tz_dsttime = _daylight; + } + + return (0); +} + +#else + +/* Postgresql's implement */ + +/* FILETIME of Jan 1 1970 00:00:00. */ +# if 0 +#define UINT64CONST (x) ((__int64) x) +static const unsigned __int64 epoch = UINT64CONST(116444736000000000); +# endif +static const unsigned __int64 epoch = 116444736000000000LL; + + /* + * timezone information is stored outside the kernel so tzp isn't used anymore. + * + * Note: this function is not for Win32 high precision timing purpose. See + * elapsed_time(). + */ +int gettimeofday(struct timeval * tp, struct timezone * tzp) + { + FILETIME file_time; + SYSTEMTIME system_time; + ULARGE_INTEGER ularge; + + GetSystemTime(&system_time); + SystemTimeToFileTime(&system_time, &file_time); + ularge.LowPart = file_time.dwLowDateTime; + ularge.HighPart = file_time.dwHighDateTime; + + tp->tv_sec = (long) ((ularge.QuadPart - epoch) / 10000000L); + tp->tv_usec = (long) (system_time.wMilliseconds * 1000); + + return 0; +} + +#endif /* end if 0 */ +#endif /* ACL_MS_WINDOWS */ diff --git a/lib_acl/src/stdlib/sys/sleep.c b/lib_acl/src/stdlib/sys/sleep.c new file mode 100644 index 000000000..3d5257f06 --- /dev/null +++ b/lib_acl/src/stdlib/sys/sleep.c @@ -0,0 +1,14 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include "stdlib/acl_sys_patch.h" + +#endif + +#ifdef ACL_MS_VC +void sleep(int sec) +{ + Sleep((sec * 1000)); +} +#endif diff --git a/lib_acl/src/stdlib/sys/snprintf.c b/lib_acl/src/stdlib/sys/snprintf.c new file mode 100644 index 000000000..665c461b5 --- /dev/null +++ b/lib_acl/src/stdlib/sys/snprintf.c @@ -0,0 +1,44 @@ +#include "StdAfx.h" +#ifdef __STDC_WANT_SECURE_LIB__ +#include + +int acl_secure_snprintf(char *buf, size_t size, const char *fmt, ...) +{ + va_list ap; + int ret; + + va_start(ap, fmt); + ret = _vsnprintf_s(buf, size, size, fmt, ap); + va_end(ap); + return (ret); +} + +int acl_secure_vsnprintf(char *buf, size_t size, const char *fmt, va_list ap) +{ + int ret; + + ret = _vsnprintf_s(buf, size, size, fmt, ap); + return (ret); +} +#else +#include "_snprintf.h" +#include +int acl_secure_snprintf(char *buf, size_t size, const char *fmt, ...) +{ + va_list ap; + int ret; + + va_start(ap, fmt); + ret = vsnprintf(buf, size, fmt, ap); + va_end(ap); + return (ret); +} + +int acl_secure_vsnprintf(char *buf, size_t size, const char *fmt, va_list ap) +{ + int ret; + + ret = vsnprintf(buf, size, fmt, ap); + return (ret); +} +#endif diff --git a/lib_acl/src/stdlib/sys/unix/acl_chroot_uid.c b/lib_acl/src/stdlib/sys/unix/acl_chroot_uid.c new file mode 100644 index 000000000..349da5d33 --- /dev/null +++ b/lib_acl/src/stdlib/sys/unix/acl_chroot_uid.c @@ -0,0 +1,80 @@ +/* System library. */ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#endif + +#ifdef ACL_UNIX +#include +#include +#include +#include +#include + +/* Utility library. */ + +#include "stdlib/acl_msg.h" +#include "stdlib/unix/acl_chroot_uid.h" + +/* chroot_uid - restrict the damage that this program can do */ + +void acl_chroot_uid(const char *root_dir, const char *user_name) +{ + struct passwd *pwd; + uid_t uid = 0; + gid_t gid; + char tbuf[256]; + + /* + * Look up the uid/gid before entering the jail, and save them so they + * can't be clobbered. Set up the primary and secondary groups. + */ + if (user_name != 0) { + if ((pwd = getpwnam(user_name)) == 0) + acl_msg_fatal("unknown user: %s", user_name); + uid = pwd->pw_uid; + gid = pwd->pw_gid; + if (setgid(gid) < 0) + acl_msg_fatal("setgid(%ld): %s", (long) gid, + acl_last_strerror(tbuf, sizeof(tbuf))); + if (initgroups(user_name, gid) < 0) + acl_msg_fatal("initgroups: %s", + acl_last_strerror(tbuf, sizeof(tbuf))); + } + + /* + * Enter the jail. + */ + if (root_dir) { + if (chroot(root_dir)) + acl_msg_fatal("chroot(%s): %s", root_dir, + acl_last_strerror(tbuf, sizeof(tbuf))); + if (chdir("/")) + acl_msg_fatal("chdir(/): %s", + acl_last_strerror(tbuf, sizeof(tbuf))); + } + + /* + * Drop the user privileges. + */ + if (user_name != 0) + if (setuid(uid) < 0) + acl_msg_fatal("setuid(%ld): %s", (long) uid, + acl_last_strerror(tbuf, sizeof(tbuf))); + + /* + * Give the desperate developer a clue of what is happening. + */ + if (acl_msg_verbose > 1) + acl_msg_info("chroot %s user %s", + root_dir ? root_dir : "(none)", + user_name ? user_name : "(none)"); +} +#endif /* ACL_UNIX */ + diff --git a/lib_acl/src/stdlib/sys/unix/acl_mychown.c b/lib_acl/src/stdlib/sys/unix/acl_mychown.c new file mode 100644 index 000000000..f3f92143a --- /dev/null +++ b/lib_acl/src/stdlib/sys/unix/acl_mychown.c @@ -0,0 +1,73 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#endif + +#ifdef ACL_UNIX + +#include +#include +#include +#include +#include + +#include "stdlib/unix/acl_mychown.h" + + +/* 注意, 此函数是线程不安全的, 便如果每次的 s_owner 与 s_group 都一样则无所谓 */ +int acl_mychown(const char *path, const char *s_owner, const char *s_group) +{ + struct passwd *pwd; + struct group *grp; + uid_t uid; + gid_t gid; + int ret; + + if(path == NULL || s_owner == NULL || s_group == NULL) + return(-1); + if ((pwd = getpwnam(s_owner)) != 0) { + uid = pwd->pw_uid; + grp = getgrnam(s_group); + if(grp == NULL) + return(-1); + gid = grp->gr_gid; + ret = chown(path, uid, gid); + if(ret < 0) + return(-1); + return(0); + } + /* no such user */ + return(-1); +} +/* 注意, 此函数是线程不安全的, 便如果每次的 s_owner 与 s_group 都一样则无所谓 */ +int acl_myfchown(const int fd, const char *s_owner, const char *s_group) +{ + struct passwd *pwd; + struct group *grp; + uid_t uid; + gid_t gid; + int ret; + + if(fd < 0 || s_owner == NULL || s_group == NULL) + return(-1); + if ((pwd = getpwnam(s_owner)) != 0) { + uid = pwd->pw_uid; + grp = getgrnam(s_group); + if(grp == NULL) + return(-1); + gid = grp->gr_gid; + ret = fchown(fd, uid, gid); + if(ret < 0) + return(-1); + return(0); + } + /* no such user */ + return(-1); +} +#endif /* ACL_UNIX */ diff --git a/lib_acl/src/stdlib/sys/unix/acl_open_lock.c b/lib_acl/src/stdlib/sys/unix/acl_open_lock.c new file mode 100644 index 000000000..7cbdf59f3 --- /dev/null +++ b/lib_acl/src/stdlib/sys/unix/acl_open_lock.c @@ -0,0 +1,48 @@ +/* System library. */ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#endif + +#ifdef ACL_UNIX + +#include +#include + +/* Utility library. */ + +#include "stdlib/acl_vstream.h" +#include "stdlib/acl_vstring.h" +#include "stdlib/acl_myflock.h" +#include "stdlib/acl_msg.h" +#include "stdlib/unix/acl_safe_open.h" +#include "stdlib/unix/acl_open_lock.h" + +/* open_lock - open file and lock it for exclusive access */ + +ACL_VSTREAM *acl_open_lock(const char *path, int flags, int mode, ACL_VSTRING *why) +{ + ACL_VSTREAM *fp; + + /* + * Carefully create or open the file, and lock it down. Some systems + * don't have the O_LOCK open() flag, or the flag does not do what we + * want, so we roll our own lock. + */ + if ((fp = acl_safe_open(path, flags, mode, (struct stat *) 0, -1, -1, why)) == 0) + return (0); + if (acl_myflock(ACL_VSTREAM_FILE(fp), ACL_INTERNAL_LOCK, + ACL_MYFLOCK_OP_EXCLUSIVE | ACL_MYFLOCK_OP_NOWAIT) < 0) { + acl_vstring_sprintf(why, "unable to set exclusive lock: %s", acl_last_serror()); + acl_vstream_close(fp); + return (0); + } + return (fp); +} +#endif /* ACL_UNIX */ diff --git a/lib_acl/src/stdlib/sys/unix/acl_safe_open.c b/lib_acl/src/stdlib/sys/unix/acl_safe_open.c new file mode 100644 index 000000000..8677eafbc --- /dev/null +++ b/lib_acl/src/stdlib/sys/unix/acl_safe_open.c @@ -0,0 +1,234 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +/* System library. */ +#include "stdlib/acl_define.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#endif + +#ifdef ACL_UNIX + +#include +#include +#include +#include +#include +#include +#include + +/* Utility library. */ + +#include "stdlib/acl_msg.h" +#include "stdlib/acl_vstream.h" +#include "stdlib/acl_vstring.h" +#include "stdlib/unix/acl_safe_open.h" + +/* safe_open_exist - open existing file */ + +static ACL_VSTREAM *acl_safe_open_exist(const char *path, int flags, + struct stat * fstat_st, ACL_VSTRING *why) +{ + struct stat local_statbuf; + struct stat lstat_st; + int saved_error; + ACL_VSTREAM *fp; + char tbuf[256]; + + /* + * Open an existing file. + */ + fp = acl_vstream_fopen(path, flags & ~(O_CREAT | O_EXCL), 0, 4096); + if (fp == 0) { + saved_error = acl_last_error(); + if (why) { + acl_vstring_sprintf(why, "cannot open file %s: %s", + path, acl_last_strerror(tbuf, sizeof(tbuf))); + } + acl_set_error(saved_error); + return (0); + } + + /* + * Examine the modes from the open file: it must have exactly one hard + * link (so that someone can't lure us into clobbering a sensitive file + * by making a hard link to it), and it must be a non-symlink file. + */ + if (fstat_st == 0) + fstat_st = &local_statbuf; + if (fstat(ACL_VSTREAM_FILE(fp), fstat_st) < 0) { + acl_msg_fatal("%s: bad open file status: %s", path, + acl_last_strerror(tbuf, sizeof(tbuf))); + } else if (S_ISDIR(fstat_st->st_mode)) { + if (why) + acl_vstring_sprintf(why, "file is a directory"); + acl_set_error(EISDIR); + } else if (fstat_st->st_nlink != 1) { + if (why) + acl_vstring_sprintf(why, "file has %d hard links", + (int) fstat_st->st_nlink); + acl_set_error(EPERM); + } + + /* + * Look up the file again, this time using lstat(). Compare the fstat() + * (open file) modes with the lstat() modes. If there is any difference, + * either we followed a symlink while opening an existing file, someone + * quickly changed the number of hard links, or someone replaced the file + * after the open() call. The link and mode tests aren't really necessary + * in daemon processes. Set-uid programs, on the other hand, can be + * slowed down by arbitrary amounts, and there it would make sense to + * compare even more file attributes, such as the inode generation number + * on systems that have one. + * + * Grr. Solaris /dev/whatever is a symlink. We'll have to make an exception + * for symlinks owned by root. NEVER, NEVER, make exceptions for symlinks + * owned by a non-root user. This would open a security hole when + * delivering mail to a world-writable mailbox directory. + */ + else if (lstat(path, &lstat_st) < 0) { + if (why) + acl_vstring_sprintf(why, "file status changed unexpectedly: %s", + acl_last_strerror(tbuf, sizeof(tbuf))); + acl_set_error(EPERM); + } else if (S_ISLNK(lstat_st.st_mode)) { + if (lstat_st.st_uid == 0) + return (fp); + if (why) + acl_vstring_sprintf(why, "file is a symbolic link"); + acl_set_error(EPERM); + } else if (fstat_st->st_dev != lstat_st.st_dev + || fstat_st->st_ino != lstat_st.st_ino +#ifdef HAS_ST_GEN + || fstat_st->st_gen != lstat_st.st_gen +#endif + || fstat_st->st_nlink != lstat_st.st_nlink + || fstat_st->st_mode != lstat_st.st_mode) { + if (why) + acl_vstring_sprintf(why, "file status changed unexpectedly"); + acl_set_error(EPERM); + } + + /* + * We are almost there... + */ + else { + return (fp); + } + + /* + * End up here in case of fstat()/lstat() problems or inconsistencies. + */ + acl_vstream_fclose(fp); + return (0); +} + +/* acl_safe_open_create - create new file */ + +static ACL_VSTREAM *acl_safe_open_create(const char *path, int flags, int mode, + struct stat * st, uid_t user, uid_t group, ACL_VSTRING *why) +{ + ACL_VSTREAM *fp; + char tbuf[256]; + + /* + * Create a non-existing file. This relies on O_CREAT | O_EXCL to not + * follow symbolic links. + */ + fp = acl_vstream_fopen(path, flags | (O_CREAT | O_EXCL), mode, 4096); + if (fp == 0) { + if (why) + acl_vstring_sprintf(why, "cannot create file exclusively: %s", + acl_last_strerror(tbuf, sizeof(tbuf))); + return (0); + } + + /* + * Optionally change ownership after creating a new file. If there + * is a problem we should not attempt to delete the file. Something + * else may have opened the file in the mean time. + */ +#define CHANGE_OWNER(user, group) (user != (uid_t) -1 || group != (gid_t) -1) + + if (CHANGE_OWNER(user, group) && fchown(ACL_VSTREAM_FILE(fp), user, group) < 0) { + acl_msg_warn("%s: cannot change file ownership: %s", + path, acl_last_strerror(tbuf, sizeof(tbuf))); + } + + /* + * Optionally look up the file attributes. + */ + if (st != 0 && fstat(ACL_VSTREAM_FILE(fp), st) < 0) + acl_msg_fatal("%s: bad open file status: %s", + path, acl_last_strerror(tbuf, sizeof(tbuf))); + + /* + * We are almost there... + */ + else { + return (fp); + } + + /* + * End up here in case of trouble. + */ + acl_vstream_fclose(fp); + return (0); +} + +/* acl_safe_open - safely open or create file */ + +ACL_VSTREAM *acl_safe_open(const char *path, int flags, int mode, + struct stat * st, uid_t user, gid_t group, ACL_VSTRING *why) +{ + ACL_VSTREAM *fp; + + switch (flags & (O_CREAT | O_EXCL)) { + + /* + * Open an existing file, carefully. + */ + case 0: + return (acl_safe_open_exist(path, flags, st, why)); + + /* + * Create a new file, carefully. + */ + case O_CREAT | O_EXCL: + return (acl_safe_open_create(path, flags, mode, + st, user, group, why)); + + /* + * Open an existing file or create a new one, carefully. + * When opening an existing file, we are prepared to deal + * with "no file" errors only. When creating a file, we + * are prepared for "file exists" errors only. Any other + * error means we better give up trying. + */ + case O_CREAT: + fp = acl_safe_open_exist(path, flags, st, why); + if (fp == 0 && acl_last_error() == ENOENT) { + fp = acl_safe_open_create(path, flags, mode, st, + user, group, why); + if (fp == 0 && acl_last_error() == EEXIST) + fp = acl_safe_open_exist(path, flags, st, why); + } + return (fp); + + /* + * Interface violation. Sorry, but we must be strict. + */ + default: + acl_msg_panic("acl_safe_open: O_EXCL flag without O_CREAT flag"); + } + + /* no reache here */ + + return (NULL); +} + +#endif /* ACL_UNIX */ + diff --git a/lib_acl/src/stdlib/sys/unix/acl_sane_socketpair.c b/lib_acl/src/stdlib/sys/unix/acl_sane_socketpair.c new file mode 100644 index 000000000..5bacc2e8e --- /dev/null +++ b/lib_acl/src/stdlib/sys/unix/acl_sane_socketpair.c @@ -0,0 +1,56 @@ +/* System library. */ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#endif + +#ifdef ACL_UNIX + +#include +#include +#include +#include + +/* Utility library. */ + +#include "stdlib/acl_msg.h" +#include "stdlib/unix/acl_sane_socketpair.h" + +/* sane_socketpair - sanitize socketpair() error returns */ + +int acl_sane_socketpair(int domain, int type, int protocol, int result[2]) +{ + static int socketpair_ok_errors[] = { + EINTR, + 0, + }; + int count; + int err; + int ret; + + /* + * Solaris socketpair() can fail with EINTR. + */ + while ((ret = socketpair(domain, type, protocol, result)) < 0) { + for (count = 0; /* void */ ; count++) { + if ((err = socketpair_ok_errors[count]) == 0) + return (ret); + if (acl_last_error() == err) { + char tbuf[256]; + acl_msg_warn("socketpair: %s (trying again)", + acl_last_strerror(tbuf, sizeof(tbuf))); + sleep(1); + break; + } + } + } + return (ret); +} +#endif /* ACL_UNIX*/ + diff --git a/lib_acl/src/stdlib/sys/unix/acl_set_eugid.c b/lib_acl/src/stdlib/sys/unix/acl_set_eugid.c new file mode 100644 index 000000000..718554b96 --- /dev/null +++ b/lib_acl/src/stdlib/sys/unix/acl_set_eugid.c @@ -0,0 +1,49 @@ +/* System library. */ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#endif + +#ifdef ACL_UNIX + +#include +#include +#include + +/* Utility library. */ + +#include "stdlib/acl_msg.h" +#include "stdlib/unix/acl_set_eugid.h" + +/* set_eugid - set effective user and group attributes */ + +void acl_set_eugid(uid_t euid, gid_t egid) +{ + int saved_error = acl_last_error(); + char tbuf[256]; + + if (geteuid() != 0) + if (seteuid(0)) + acl_msg_fatal("set_eugid: seteuid(0): %s", + acl_last_strerror(tbuf, sizeof(tbuf))); + if (setegid(egid) < 0) + acl_msg_fatal("set_eugid: setegid(%ld): %s", (long) egid, + acl_last_strerror(tbuf, sizeof(tbuf))); + if (setgroups(1, &egid) < 0) + acl_msg_fatal("set_eugid: setgroups(%ld): %s", (long) egid, + acl_last_strerror(tbuf, sizeof(tbuf))); + if (euid != 0 && seteuid(euid) < 0) + acl_msg_fatal("set_eugid: seteuid(%ld): %s", (long) euid, + acl_last_strerror(tbuf, sizeof(tbuf))); + if (acl_msg_verbose) + acl_msg_info("set_eugid: euid %ld egid %ld", + (long) euid, (long) egid); + acl_set_error(saved_error); +} +#endif /* ACL_UNIX */ diff --git a/lib_acl/src/stdlib/sys/unix/acl_set_ugid.c b/lib_acl/src/stdlib/sys/unix/acl_set_ugid.c new file mode 100644 index 000000000..66236c554 --- /dev/null +++ b/lib_acl/src/stdlib/sys/unix/acl_set_ugid.c @@ -0,0 +1,69 @@ +/* System library. */ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#endif + +#ifdef ACL_UNIX + +#include +#include +#include +#include +#include + +/* Utility library. */ + +#include "stdlib/acl_msg.h" +#include "stdlib/unix/acl_set_ugid.h" + +void acl_set_ugid(uid_t uid, gid_t gid) +{ + int saved_error = acl_last_error(); + char tbuf[256]; + + if (geteuid() != 0) + if (seteuid(0) < 0) + acl_msg_fatal("seteuid(0): %s", acl_last_strerror(tbuf, sizeof(tbuf))); + if (setgid(gid) < 0) + acl_msg_fatal("setgid(%ld): %s", (long) gid, + acl_last_strerror(tbuf, sizeof(tbuf))); + if (setgroups(1, &gid) < 0) + acl_msg_fatal("setgroups(1, &%ld): %s", (long) gid, + acl_last_strerror(tbuf, sizeof(tbuf))); + if (setuid(uid) < 0) + acl_msg_fatal("setuid(%ld): %s", (long) uid, + acl_last_strerror(tbuf, sizeof(tbuf))); + if (acl_msg_verbose > 1) + acl_msg_info("setugid: uid %ld gid %ld", (long) uid, (long) gid); + acl_set_error(saved_error); +} + +int acl_change_uid(char *user_name) +{ + char where[] = "change_uid"; + struct passwd *pwd; + uid_t uid; + gid_t gid; + char tbuf[256]; + + if ((pwd = getpwnam(user_name)) == NULL) + acl_msg_fatal("%s: no such user=%s", where, user_name); + uid = pwd->pw_uid; + gid = pwd->pw_gid; + if (setgid(gid) < 0) + acl_msg_fatal("%s: setgid error(%s, %d): %s", + where, user_name, uid, acl_last_strerror(tbuf, sizeof(tbuf))); + if (setuid(uid) < 0) + acl_msg_fatal("%s: setuid error(%s, %d): %s", + where, user_name, uid, acl_last_strerror(tbuf, sizeof(tbuf))); + + return (0); +} +#endif /* ACL_UNIX*/ diff --git a/lib_acl/src/stdlib/sys/unix/acl_timed_wait.c b/lib_acl/src/stdlib/sys/unix/acl_timed_wait.c new file mode 100644 index 000000000..511a2eec3 --- /dev/null +++ b/lib_acl/src/stdlib/sys/unix/acl_timed_wait.c @@ -0,0 +1,97 @@ +/* System library. */ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#endif + +#ifdef ACL_UNIX + +#include +#include +#include +#include +#include + +/* Utility library. */ + +#include "posix_signals.h" +#include "stdlib/acl_msg.h" +#include "stdlib/unix/acl_timed_wait.h" + +/* Application-specific. */ + +static int timed_wait_expired; + +/* timed_wait_alarm - timeout handler */ + +static void timed_wait_alarm(int unused_sig) +{ + + unused_sig = unused_sig; + + /* + * WARNING WARNING WARNING. + * + * This code runs at unpredictable moments, as a signal handler. + * This code is here only so that we can break out of waitpid(). + * Don't put any code here other than for setting a global flag. + */ + timed_wait_expired = 1; +} + +/* timed_waitpid - waitpid with time limit */ + +int acl_timed_waitpid(pid_t pid, ACL_WAIT_STATUS_T *statusp, int options, + int time_limit) +{ + char *myname = "timed_waitpid"; + struct sigaction action; + struct sigaction old_action; + int time_left; + int wpid; + char tbuf[256]; + + /* + * Sanity checks. + */ + if (time_limit <= 0) + acl_msg_panic("%s: bad time limit: %d", myname, time_limit); + + /* + * Set up a timer. + */ + sigemptyset(&action.sa_mask); + action.sa_flags = 0; + action.sa_handler = timed_wait_alarm; + if (sigaction(SIGALRM, &action, &old_action) < 0) + acl_msg_fatal("%s: sigaction(SIGALRM): %s", myname, + acl_last_strerror(tbuf, sizeof(tbuf))); + timed_wait_expired = 0; + time_left = alarm(time_limit); + + /* + * Wait for only a limited amount of time. + */ + if ((wpid = waitpid(pid, statusp, options)) < 0 && timed_wait_expired) + acl_set_error(ETIMEDOUT); + + /* + * Cleanup. + */ + alarm(0); + if (sigaction(SIGALRM, &old_action, (struct sigaction *) 0) < 0) + acl_msg_fatal("%s: sigaction(SIGALRM): %s", myname, + acl_last_strerror(tbuf, sizeof(tbuf))); + if (time_left) + alarm(time_left); + + return (wpid); +} +#endif /* ACL_UNIX */ + diff --git a/lib_acl/src/stdlib/sys/unix/acl_trace.c b/lib_acl/src/stdlib/sys/unix/acl_trace.c new file mode 100644 index 000000000..dfe0bda71 --- /dev/null +++ b/lib_acl/src/stdlib/sys/unix/acl_trace.c @@ -0,0 +1,37 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE +#include "stdlib/acl_define.h" +#include "stdlib/acl_msg.h" +#endif + +#ifdef ACL_UNIX +#include +#include +#include +#include +#include +#include "stdlib/unix/acl_trace.h" + +void acl_dump_trace(const char *filepath) +{ + const char *myname = "acl_dump_trace"; + int fd; + void *buffer[1000]; + size_t n; + + n = backtrace(buffer, 1000); + if (n == 0) + return; + + fd = open(filepath, O_WRONLY | O_CREAT | O_APPEND, 0600); + if (fd == -1) { + acl_msg_error("%s(%d): open %s error(%s)", + myname, __LINE__, filepath, acl_last_serror()); + return; + } + + backtrace_symbols_fd(buffer, n, fd); + close(fd); +} + +#endif diff --git a/lib_acl/src/stdlib/sys/unix/acl_transfer_fd.c b/lib_acl/src/stdlib/sys/unix/acl_transfer_fd.c new file mode 100644 index 000000000..14aa5dadc --- /dev/null +++ b/lib_acl/src/stdlib/sys/unix/acl_transfer_fd.c @@ -0,0 +1,119 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#endif + +#ifdef ACL_UNIX + +#include +#include + +#include "stdlib/acl_msg.h" +#include "stdlib/unix/acl_transfer_fd.h" + +int acl_read_fd(int fd, void *ptr, int nbytes, int *recv_fd) +{ +#ifdef HAVE_MSGHDR_MSG_CONTROL + char *myname = "acl_read_fd"; +#endif + struct msghdr msg; + struct iovec iov[1]; + int n; +#ifdef HAVE_MSGHDR_MSG_CONTROL + union { + struct cmsghdr cm; + char control[CMSG_SPACE(sizeof(int))]; + } control_un; + struct cmsghdr *cmptr; + + msg.msg_control = control_un.control; + msg.msg_controllen = sizeof(control_un.control); +#else + int newfd; + + msg.msg_accrights = (caddr_t) &newfd; + msg.msg_accrightslen = sizeof(int); +#endif + + msg.msg_name = NULL; + msg.msg_namelen = 0; + + iov[0].iov_base = ptr; + iov[0].iov_len = nbytes; + + msg.msg_iov = iov; + msg.msg_iovlen = 1; + + if ((n = recvmsg(fd, &msg, 0)) <= 0) + return (n); + +#ifdef HAVE_MSGHDR_MSG_CONTROL + if ((cmptr = CMSG_FIRSTHDR(&msg)) != NULL + && cmptr->cmsg_len == CMSG_LEN(sizeof(int))) { + if (cmptr->cmsg_level != SOL_SOCKET) + acl_msg_fatal("%s: control level != SOL_SOCKET", myname); + if (cmptr->cmsg_type != SCM_RIGHTS) + acl_msg_fatal("%s: control type != SCM_RIGHTS", myname); + *recv_fd = *CMSG_DATA(cmptr); +/* + *recv_fd = *((int *) CMSG_DATA(cmptr)); +*/ + } else + *recv_fd = -1; /* descriptor was not passed */ +#else + if (msg.msg_accrightslen == sizeof(int)) + *recv_fd = newfd; + else + *recv_fd = -1; /* descriptor was not passed */ +#endif + + return (n); +} + +int acl_write_fd(int fd, void *ptr, int nbytes, int send_fd) +{ + struct msghdr msg; + struct iovec iov[1]; + +#ifdef HAVE_MSGHDR_MSG_CONTROL + union { + struct cmsghdr cm; + char control[CMSG_SPACE(sizeof(int))]; + } control_un; + struct cmsghdr *cmptr; + + msg.msg_control = control_un.control; + msg.msg_controllen = sizeof(control_un.control); + + cmptr = CMSG_FIRSTHDR(&msg); + cmptr->cmsg_len = CMSG_LEN(sizeof(int)); + cmptr->cmsg_level = SOL_SOCKET; + cmptr->cmsg_type = SCM_RIGHTS; + *CMSG_DATA(cmptr) = send_fd; + +/* + *((int *) CMSG_DATA(cmptr)) = send_fd; +*/ +#else + msg.msg_accrights = (caddr_t) &send_fd; + msg.msg_accrightslen = sizeof(int); +#endif + + msg.msg_name = NULL; + msg.msg_namelen = 0; + + iov[0].iov_base = ptr; + iov[0].iov_len = nbytes; + msg.msg_iov = iov; + msg.msg_iovlen = 1; + + return (sendmsg(fd, &msg, 0)); +} + +#endif /* ACL_UNIX */ diff --git a/lib_acl/src/stdlib/sys/unix/acl_username.c b/lib_acl/src/stdlib/sys/unix/acl_username.c new file mode 100644 index 000000000..5ca57b95d --- /dev/null +++ b/lib_acl/src/stdlib/sys/unix/acl_username.c @@ -0,0 +1,30 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#endif + +#ifdef ACL_UNIX + +#include +#include +#include + +#include "stdlib/unix/acl_username.h" + +const char *acl_username(void) +{ + uid_t uid; + struct passwd *pwd; + + uid = getuid(); + if ((pwd = getpwuid(uid)) == 0) + return (0); + return (pwd->pw_name); +} +#endif /* ACL_UNIX */ diff --git a/lib_acl/src/stdlib/sys/unix/acl_watchdog.c b/lib_acl/src/stdlib/sys/unix/acl_watchdog.c new file mode 100644 index 000000000..acdebfc40 --- /dev/null +++ b/lib_acl/src/stdlib/sys/unix/acl_watchdog.c @@ -0,0 +1,169 @@ +/* System library. */ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#endif + +#ifdef ACL_UNIX + +#include +#include +#include +#include "posix_signals.h" + +/* Utility library. */ + +#include "stdlib/acl_msg.h" +#include "stdlib/acl_mymalloc.h" +#include "stdlib/unix/acl_watchdog.h" + +/* Application-specific. */ + + /* + * Rather than having one timer that goes off when it is too late, we break + * up the time limit into smaller intervals so that we can deal with clocks + * that jump occasionally. + */ +#define ACL_WATCHDOG_STEPS 3 + + /* + * UNIX alarms are not stackable, but we can save and restore state, so that + * watchdogs can at least be nested, sort of. + */ + struct ACL_WATCHDOG { + unsigned timeout; /* our time resolution */ + ACL_WATCHDOG_FN action; /* application routine */ + char *context; /* application context */ + int trip_run; /* number of successive timeouts */ + ACL_WATCHDOG *saved_watchdog; /* saved state */ + struct sigaction saved_action; /* saved state */ + unsigned saved_time; /* saved state */ + }; + + /* + * However, only one watchdog instance can be current, and the caller has to + * restore state before a prior watchdog instance can be manipulated. + */ +static ACL_WATCHDOG *acl_watchdog_curr; + +/* acl_watchdog_event - handle timeout event */ + +static void acl_watchdog_event(int unused_sig acl_unused) +{ + const char* myname = "acl_watchdog_event"; + ACL_WATCHDOG *wp; + + /* + * This routine runs as a signal handler. We should not do anything + * that could involve memory allocation/deallocation, but exiting + * without proper explanation would be unacceptable. + */ + if ((wp = acl_watchdog_curr) == 0) + acl_msg_panic("%s: no instance", myname); + if (acl_msg_verbose > 1) + acl_msg_info("%s: %p %d", myname, (void *) wp, wp->trip_run); + if (++(wp->trip_run) < ACL_WATCHDOG_STEPS) + alarm(wp->timeout); + else { + if (wp->action) + wp->action(wp, wp->context); + else + acl_msg_fatal("watchdog timeout"); + } +} + +/* acl_watchdog_create - create watchdog instance */ + +ACL_WATCHDOG *acl_watchdog_create(unsigned timeout, + ACL_WATCHDOG_FN action, char *context) +{ + const char* myname = "acl_watchdog_create"; + struct sigaction sig_action; + ACL_WATCHDOG *wp; + + wp = (ACL_WATCHDOG *) acl_mymalloc(sizeof(*wp)); + if ((wp->timeout = timeout / ACL_WATCHDOG_STEPS) == 0) + acl_msg_panic("%s: timeout %d too small", myname, timeout); + wp->action = action; + wp->context = context; + wp->saved_watchdog = acl_watchdog_curr; + wp->saved_time = alarm(0); + sigemptyset(&sig_action.sa_mask); +#ifdef SA_RESTART + sig_action.sa_flags = SA_RESTART; +#else + sig_action.sa_flags = 0; +#endif + sig_action.sa_handler = acl_watchdog_event; + if (sigaction(SIGALRM, &sig_action, &wp->saved_action) < 0) + acl_msg_fatal("%s: sigaction(SIGALRM): %s", + myname, acl_last_serror()); + if (acl_msg_verbose > 1) + acl_msg_info("%s: %p %d", myname, (void *) wp, timeout); + return (acl_watchdog_curr = wp); +} + +/* acl_watchdog_destroy - destroy watchdog instance, restore state */ + +void acl_watchdog_destroy(ACL_WATCHDOG *wp) +{ + const char* myname = "acl_watchdog_destroy"; + + acl_watchdog_stop(wp); + acl_watchdog_curr = wp->saved_watchdog; + if (sigaction(SIGALRM, &wp->saved_action, (struct sigaction *) 0) < 0) + acl_msg_fatal("%s: sigaction(SIGALRM): %s", + myname, acl_last_serror()); + if (wp->saved_time) + alarm(wp->saved_time); + acl_myfree(wp); + if (acl_msg_verbose > 1) + acl_msg_info("%s: %p", myname, (void *) wp); +} + +/* acl_watchdog_start - enable watchdog timer */ + +void acl_watchdog_start(ACL_WATCHDOG *wp) +{ + const char* myname = "acl_watchdog_start"; + + if (wp != acl_watchdog_curr) + acl_msg_panic("%s: wrong watchdog instance", myname); + wp->trip_run = 0; + alarm(wp->timeout); + if (acl_msg_verbose > 1) + acl_msg_info("%s: %p", myname, (void *) wp); +} + +/* acl_watchdog_stop - disable watchdog timer */ + +void acl_watchdog_stop(ACL_WATCHDOG *wp) +{ + const char* myname = "acl_watchdog_stop"; + + if (wp != acl_watchdog_curr) + acl_msg_panic("%s: wrong watchdog instance", myname); + alarm(0); + if (acl_msg_verbose > 1) + acl_msg_info("%s: %p", myname, (void *) wp); +} + +/* acl_watchdog_pat - pat the dog so it stays quiet */ + +void acl_watchdog_pat(void) +{ + const char* myname = "acl_watchdog_pat"; + + if (acl_watchdog_curr) + acl_watchdog_curr->trip_run = 0; + if (acl_msg_verbose > 1) + acl_msg_info("%s: %p", myname, (void *) acl_watchdog_curr); +} + +#endif /* ACL_UNIX */ diff --git a/lib_acl/src/stdlib/sys/unix/posix_signals.c b/lib_acl/src/stdlib/sys/unix/posix_signals.c new file mode 100644 index 000000000..6fdce4492 --- /dev/null +++ b/lib_acl/src/stdlib/sys/unix/posix_signals.c @@ -0,0 +1,106 @@ +/* System library. */ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#endif + +#ifdef ACL_UNIX + +#include + +/* Utility library.*/ + +#include "posix_signals.h" + +#ifdef MISSING_SIGSET_T + +int sigemptyset(sigset_t *m) +{ + return *m = 0; +} + +int sigaddset(sigset_t *set, int signum) +{ + *set |= sigmask(signum); + return 0; +} + +int sigprocmask(int how, sigset_t *set, sigset_t *old) +{ + int previous; + + if (how == SIG_BLOCK) + previous = sigblock(*set); + else if (how == SIG_SETMASK) + previous = sigsetmask(*set); + else if (how == SIG_UNBLOCK) { + int m = sigblock(0); + + previous = sigsetmask(m & ~*set); + } else { + acl_set_error(EINVAL); + return -1; + } + + if (old) + *old = previous; + return 0; +} + +#endif + +#ifdef MISSING_SIGACTION + +static struct sigaction actions[NSIG] = {}; + +static int sighandle(int signum) +{ + if (signum == SIGCHLD) { + /* XXX If the child is just stopped, don't invoke the handler. */ + } + actions[signum].sa_handler(signum); +} + +int sigaction(int sig, struct sigaction *act, struct sigaction *oact) +{ + static int initialized = 0; + + if (!initialized) { + int i; + + for (i = 0; i < NSIG; i++) + actions[i].sa_handler = SIG_DFL; + initialized = 1; + } + if (sig <= 0 || sig >= NSIG) { + acl_set_error(EINVAL); + return -1; + } + if (oact) + *oact = actions[sig]; + + { + struct sigvec mine = { + sighandle, act->sa_mask, + act->sa_flags & SA_RESTART ? SV_INTERRUPT : 0 + }; + + if (sigvec(sig, &mine, NULL)) + return -1; + } + + actions[sig] = *act; + return 0; +} + +#endif + +#endif /* ACL_UNIX*/ + + diff --git a/lib_acl/src/stdlib/sys/unix/posix_signals.h b/lib_acl/src/stdlib/sys/unix/posix_signals.h new file mode 100644 index 000000000..20adcfebd --- /dev/null +++ b/lib_acl/src/stdlib/sys/unix/posix_signals.h @@ -0,0 +1,57 @@ +#ifndef __ACL_POSIX_SIGNALS_H_INCLUDED__ +#define __ACL_POSIX_SIGNALS_H_INCLUDED__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stdlib/acl_define.h" + +#ifdef ACL_UNIX + + /* + * Compatibility interface. + */ + +#ifdef MISSING_SIGSET_T + +typedef int sigset_t; + +enum { + SIG_BLOCK, + SIG_UNBLOCK, + SIG_SETMASK +}; + +extern int sigemptyset(sigset_t *); +extern int sigaddset(sigset_t *, int); +extern int sigprocmask(int, sigset_t *, sigset_t *); + +#endif + +#ifdef MISSING_SIGACTION + +struct sigaction { + void (*sa_handler) (); + sigset_t sa_mask; + int sa_flags; +}; + + /* Possible values for sa_flags. Or them to set multiple. */ +enum { + SA_RESTART, + SA_NOCLDSTOP = 4 /* drop the = 4. */ +}; + +extern int sigaction(int, struct sigaction *, struct sigaction *); + +#endif + +#endif /* ACL_UNIX */ + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_acl/src/thread/acl_pthread.c b/lib_acl/src/thread/acl_pthread.c new file mode 100644 index 000000000..783db9c3f --- /dev/null +++ b/lib_acl/src/thread/acl_pthread.c @@ -0,0 +1,836 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#include +#include +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_msg.h" +#include "stdlib/acl_malloc.h" +#include "stdlib/acl_ring.h" +#include "thread/acl_pthread.h" +#include "init/acl_init.h" + +#endif + +#include "../private/private_fifo.h" + +#ifdef ACL_MS_WINDOWS + +/*---------------------- WIN32 下模拟实现 Posix 标准接口函数 ----------------*/ + +#include + +#define PTHREAD_STACK_MIN 16384 + +typedef struct { + acl_pthread_key_t key; + void (*destructor)(void *); +} TLS_KEY; + +typedef struct { + TLS_KEY *tls_key; + void *value; +} TLS_VALUE; + +static int __thread_inited = 0; +static acl_pthread_once_t __create_thread_control_once = ACL_PTHREAD_ONCE_INIT; +static TLS_KEY __tls_key_list[ACL_PTHREAD_KEYS_MAX]; +static acl_pthread_mutex_t __thread_lock; +static acl_pthread_key_t __tls_value_list_key = ACL_TLS_OUT_OF_INDEXES; + +static void tls_value_list_free(void); + +void acl_pthread_end(void) +{ + static int __thread_ended = 0; + int i; + + tls_value_list_free(); + + if (__thread_ended) + return; + + __thread_ended = 1; + acl_pthread_mutex_destroy(&__thread_lock); + + for (i = 0; i < ACL_PTHREAD_KEYS_MAX; i++) { + if (__tls_key_list[i].key >= 0 + && __tls_key_list[i].key < ACL_PTHREAD_KEYS_MAX) + { + TlsFree(__tls_key_list[i].key); + __tls_key_list[i].key = ACL_TLS_OUT_OF_INDEXES; + } + __tls_key_list[i].destructor = NULL; + } +} + +/* 每个进程的唯一初始化函数 */ + +static void acl_pthread_init_once(void) +{ + const char *myname = "acl_pthread_init_once"; + char buf[256]; + int i; + + acl_pthread_mutex_init(&__thread_lock, NULL); + __thread_inited = 1; + + for (i = 0; i < ACL_PTHREAD_KEYS_MAX; i++) { + __tls_key_list[i].destructor = NULL; + __tls_key_list[i].key = ACL_TLS_OUT_OF_INDEXES; + } + + __tls_value_list_key = TlsAlloc(); + if (__tls_value_list_key == ACL_TLS_OUT_OF_INDEXES) + acl_msg_fatal("%s(%d): TlsAlloc error(%s)", + myname, __LINE__, acl_last_strerror(buf, sizeof(buf))); + if (__tls_value_list_key < 0 || __tls_value_list_key >= ACL_PTHREAD_KEYS_MAX) + acl_msg_fatal("%s(%d): TlsAlloc error(%s), not in(%d, %d)", + myname, __LINE__, acl_last_strerror(buf, sizeof(buf)), + 0, ACL_PTHREAD_KEYS_MAX); + __tls_key_list[__tls_value_list_key].destructor = NULL; + __tls_key_list[__tls_value_list_key].key = __tls_value_list_key; +} + +/* 获得线程局部变量链表 */ + +static ACL_FIFO *tls_value_list_get(void) +{ + ACL_FIFO *tls_value_list_ptr; + + tls_value_list_ptr = TlsGetValue(__tls_value_list_key); + if (tls_value_list_ptr == NULL) { + tls_value_list_ptr = private_fifo_new(); + TlsSetValue(__tls_value_list_key, tls_value_list_ptr); + } + return (tls_value_list_ptr); +} + +static void tls_value_list_on_free(void *ctx) +{ + acl_default_free(__FILE__, __LINE__, ctx); +} + +static void tls_value_list_free(void) +{ + ACL_FIFO *tls_value_list_ptr; + + tls_value_list_ptr = TlsGetValue(__tls_value_list_key); + if (tls_value_list_ptr != NULL) { + TlsSetValue(__tls_value_list_key, NULL); + private_fifo_free(tls_value_list_ptr, tls_value_list_on_free); + } +} + +#ifdef ACL_WIN32_STDC +static unsigned long __stdcall RunThreadWrap(void *data) +#else +static DWORD WINAPI RunThreadWrap(LPVOID data) +#endif +{ + acl_pthread_t *thread = (acl_pthread_t *) data; + void *return_arg; + ACL_FIFO *tls_value_list_ptr = tls_value_list_get(); + unsigned long *tid = 0; + + /* 只是为了避免与主线程的 h_thread->handle = handle 产生冲突 */ + if (__thread_inited) + acl_pthread_mutex_lock(&__thread_lock); + if (__thread_inited) + acl_pthread_mutex_unlock(&__thread_lock); + + thread->id = acl_pthread_self(); + + return_arg = (void*) thread->start_routine(thread->routine_arg); + + /* 释放由 acl_pthread_setspecific 添加的线程局部变量 */ + while (1) { + TLS_VALUE *tls_value = private_fifo_pop(tls_value_list_ptr); + + if (tls_value == NULL) + break; + else if (tls_value->tls_key == NULL + || tls_value->tls_key->destructor == NULL + || tls_value->tls_key->key < 0 + || tls_value->tls_key->key >= ACL_PTHREAD_KEYS_MAX) + { + acl_default_free(__FILE__, __LINE__, tls_value); + continue; + } + tls_value->tls_key->destructor(tls_value->value); + acl_default_free(__FILE__, __LINE__, tls_value); + } + + private_fifo_free(tls_value_list_ptr, NULL); + + /* 如果线程创建时为分离方式则需要关闭线程句柄 */ + if (thread->detached) { + if (!CloseHandle(thread->handle)) { + char buf[256]; + acl_msg_error("close handle error(%s)", + acl_last_strerror(buf, sizeof(buf))); + } + } + + acl_default_free(__FILE__, __LINE__, thread); + return ((DWORD) return_arg); +} + +int acl_pthread_create(acl_pthread_t *thread, acl_pthread_attr_t *attr, + void * (*start_routine)(void *), void *arg) +{ + const char *myname = "acl_pthread_create"; + acl_pthread_t *h_thread; + HANDLE handle; + unsigned long id, flag; + char buf[256]; + + if (thread == NULL) { + acl_msg_error("%s, %s(%d): input invalid", + __FILE__, myname, __LINE__); + acl_set_error(ACL_EINVAL); + return (ACL_EINVAL); + } + acl_pthread_once(&__create_thread_control_once, acl_pthread_init_once); + memset(thread, 0, sizeof(acl_pthread_t)); + + h_thread = acl_default_calloc(__FILE__, __LINE__, 1, sizeof(acl_pthread_t)); + if (h_thread == NULL) { + acl_msg_error("%s, %s(%d): calloc error(%s)", + __FILE__, myname, __LINE__, + acl_last_strerror(buf, sizeof(buf))); + acl_set_error(ACL_ENOMEM); + return (ACL_ENOMEM); + } + + if (attr != NULL) + h_thread->detached = attr->detached; + else + h_thread->detached = 1; + h_thread->start_routine = start_routine; + h_thread->routine_arg = arg; + + if (__thread_inited) { + acl_pthread_mutex_lock(&__thread_lock); + flag = 0; + } else { + flag = CREATE_SUSPENDED; + } + +#ifdef ACL_WIN32_STDC + h_thread->handle = handle = (HANDLE) _beginthreadex(NULL, + attr ? attr->stacksize : 0, + RunThreadWrap, + (void *) h_thread, + flag, + &id); +#else + h_thread->handle = handle = CreateThread(NULL, + attr ? attr->stacksize : 0,, + RunThreadWrap, + h_thread, + flag, + &id); +#endif + + if (__thread_inited) + acl_pthread_mutex_unlock(&__thread_lock); + else if (flag == CREATE_SUSPENDED && handle != 0) + ResumeThread(handle); + if (handle == 0) { + acl_msg_error("%s, %s(%d): CreateThread error(%s)", + __FILE__, myname, __LINE__, + acl_last_strerror(buf, sizeof(buf))); + return (-1); + } + thread->start_routine = start_routine; + thread->routine_arg = arg; + thread->id = id; + thread->handle = 0; + + /* 根据线程的属性来确定线程创建时是分离模式还是非分离模式 */ + + if (attr == NULL || attr->detached) { + thread->detached = 1; + return (0); + } + + thread->detached = 0; + thread->handle = handle; + return (0); +} + +int acl_pthread_once(acl_pthread_once_t *once_control, void (*init_routine)(void)) +{ + int n = 0; + + if (once_control == NULL || init_routine == NULL) { + acl_set_error(ACL_EINVAL); + return (ACL_EINVAL); + } + + /* 只有第一个调用 InterlockedCompareExchange 的线程才会执行 init_routine, + * 后续线程永远在 InterlockedCompareExchange 外运行,并且一直进入空循环 + * 直至第一个线程执行 init_routine 完毕并且将 *once_control 重新赋值, + * 只有在多核环境中多个线程同时运行至此时才有可能出现短暂的后续线程空循环 + * 现象,如果多个线程顺序至此,则因为 *once_control 已经被第一个线程重新 + * 赋值而不会进入循环体内 + * 只所以如此处理,是为了保证所有线程在调用 acl_pthread_once 返回前 + * init_routine 必须被调用且仅能被调用一次 + * 但在VC6下,InterlockedCompareExchange 接口定义有些怪异,需要做硬性指定 + * 参数类型,参见 Jeffrey Richter, 366 页 + */ + while (1) { +#ifdef MS_VC6 + LONG prev = InterlockedCompareExchange((PVOID) once_control, + (PVOID) 1, (PVOID) ACL_PTHREAD_ONCE_INIT); +#else + LONG prev = InterlockedCompareExchange( + once_control, 1, ACL_PTHREAD_ONCE_INIT); +#endif + if (prev == 2) + return (0); + else if (prev == 0) { + /* 只有第一个线程才会至此 */ + init_routine(); + /* 将 *conce_control 重新赋值以使后续线程不进入 while 循环或 + * 从 while 循环中跳出 + */ + InterlockedExchange(once_control, 2); + return (0); + } else { + acl_assert(prev == 1); + + /* 防止空循环过多地浪费CPU */ + Sleep(1); /** sleep 1ms */ + } + } + return (1); /* 不可达代码,避免编译器报警告 */ +} + +int acl_pthread_attr_init(acl_pthread_attr_t *thr_attr) +{ + if (thr_attr == NULL) { + acl_set_error(ACL_EINVAL); + return (ACL_EINVAL); + } + + memset(&thr_attr->attr, 0, sizeof(thr_attr->attr)); + thr_attr->attr.bInheritHandle = 1; + thr_attr->attr.lpSecurityDescriptor = NULL; + thr_attr->attr.nLength = sizeof(SECURITY_ATTRIBUTES); + thr_attr->stacksize = 0; + thr_attr->detached = 0; + + return (0); +} + +int acl_pthread_attr_setstacksize(acl_pthread_attr_t *attr, size_t stacksize) +{ + if (attr == NULL) { + acl_set_error(ACL_EINVAL); + return (ACL_EINVAL); + } + if (stacksize < PTHREAD_STACK_MIN) { + acl_set_error(ACL_EINVAL); + return (ACL_EINVAL); + } + attr->stacksize = stacksize; + return (0); +} + +int acl_pthread_attr_setdetachstate(acl_pthread_attr_t *thr_attr, int detached) +{ + if (thr_attr == NULL) { + acl_set_error(ACL_EINVAL); + return (ACL_EINVAL); + } + thr_attr->detached = detached; + return (0); +} + +int acl_pthread_attr_destroy(acl_pthread_attr_t *thr_attr) +{ + if (thr_attr == NULL) { + acl_set_error(ACL_EINVAL); + return (ACL_EINVAL); + } + memset(&thr_attr->attr, 0, sizeof(thr_attr->attr)); + return (0); +} + +unsigned long acl_pthread_self(void) +{ + return (GetCurrentThreadId()); +} + +int acl_pthread_key_create(acl_pthread_key_t *key_ptr, void (*destructor)(void*)) +{ + const char *myname = "acl_pthread_key_create"; + + acl_pthread_once(&__create_thread_control_once, acl_pthread_init_once); + + *key_ptr = TlsAlloc(); + if (*key_ptr == ACL_TLS_OUT_OF_INDEXES) { + acl_set_error(ACL_ENOMEM); + return (ACL_ENOMEM); + } else if (*key_ptr >= ACL_PTHREAD_KEYS_MAX) { + acl_msg_error("%s(%d): key(%d) > ACL_PTHREAD_KEYS_MAX(%d)", + myname, __LINE__, *key_ptr, ACL_PTHREAD_KEYS_MAX); + TlsFree(*key_ptr); + *key_ptr = ACL_TLS_OUT_OF_INDEXES; + acl_set_error(ACL_ENOMEM); + return (ACL_ENOMEM); + } + + __tls_key_list[*key_ptr].destructor = destructor; + __tls_key_list[*key_ptr].key = *key_ptr; + return (0); +} + +void *acl_pthread_getspecific(acl_pthread_key_t key) +{ + return (TlsGetValue(key)); +} + +int acl_pthread_setspecific(acl_pthread_key_t key, void *value) +{ + const char *myname = "acl_pthread_setspecific"; + ACL_FIFO *tls_value_list_ptr = tls_value_list_get(); + ACL_ITER iter; + + if (key < 0 || key >= ACL_PTHREAD_KEYS_MAX) { + acl_msg_error("%s(%d): key(%d) invalid", myname, __LINE__, key); + acl_set_error(ACL_EINVAL); + return (ACL_EINVAL); + } + if (__tls_key_list[key].key != key) { + acl_msg_error("%s(%d): __tls_key_list[%d].key(%d) != key(%d) invalid", + myname, __LINE__, key, __tls_key_list[key].key, key); + acl_set_error(ACL_EINVAL); + return (ACL_EINVAL); + } + + acl_foreach(iter, tls_value_list_ptr) { + TLS_VALUE *tls_value = (TLS_VALUE*) iter.data; + if (tls_value->tls_key != NULL && tls_value->tls_key->key == key) { + /* 如果相同的键存在则需要先释放旧数据 */ + if (tls_value->tls_key->destructor || tls_value->value) + tls_value->tls_key->destructor(tls_value->value); + tls_value->tls_key = NULL; + tls_value->value = NULL; + break; + } + } + + if (TlsSetValue(key, value)) { + TLS_VALUE *tls_value = (TLS_VALUE*) + acl_default_malloc(__FILE__, __LINE__, sizeof(TLS_VALUE)); + tls_value->tls_key = &__tls_key_list[key]; + tls_value->value = value; + private_fifo_push(tls_value_list_ptr, tls_value); + return (0); + } else { + char buf[256]; + acl_msg_error("%s(%d): TlsSetValue(key=%d) error(%s)", + myname, __LINE__, key, acl_last_strerror(buf, sizeof(buf))); + return (-1); + } +} + +int acl_pthread_detach(acl_pthread_t thread) +{ + const char *myname = "acl_pthread_detach"; + + if (thread.detached) + return (-1); + if (thread.handle == 0) + return (-1); + + if (!CloseHandle(thread.handle)) { + char buf[256]; + + acl_msg_error("close handle error(%s)", + acl_last_strerror(buf, sizeof(buf))); + } + return (0); +} + +int acl_pthread_join(acl_pthread_t thread, void **thread_return) +{ + const char *myname = "acl_pthread_join"; + void *return_arg; + + if (thread.detached) { + acl_msg_error("%s(%d): thread has been detached", myname, __LINE__); + return (-1); + } + if (thread.handle == 0) { + acl_msg_error("%s(%d): thread->handle == 0", myname, __LINE__); + return (-1); + } + + WaitForSingleObject(thread.handle, INFINITE); + if (GetExitCodeThread(thread.handle, (LPDWORD) &return_arg)) { + if (thread_return != NULL) + *thread_return = return_arg; + } + + if (!CloseHandle(thread.handle)) { + char buf[256]; + + acl_msg_error("close handle error(%s)", + acl_last_strerror(buf, sizeof(buf))); + } + return (0); +} + +#endif /* ACL_MS_WINDOWS */ + +/*------------------ 跨平台的通用函数集,是 Posix 标准的扩展 -----------------*/ + +/*----------------------------------------------------------------------------*/ + +typedef struct pthread_atexit { + void (*free_fn)(void *); + void *arg; +} pthread_atexit_t; + +static acl_pthread_key_t __pthread_atexit_key = ACL_TLS_OUT_OF_INDEXES; +static acl_pthread_once_t __pthread_atexit_control_once = ACL_PTHREAD_ONCE_INIT; + +static void pthread_atexit_done(void *arg) +{ + ACL_FIFO *id_list = (ACL_FIFO*) arg; + pthread_atexit_t *id_ptr; + + while (1) { + id_ptr = (pthread_atexit_t*) private_fifo_pop(id_list); + if (id_ptr == NULL) + break; + if (id_ptr->free_fn) + id_ptr->free_fn(id_ptr->arg); + acl_default_free(__FILE__, __LINE__, id_ptr); + } + private_fifo_free(id_list, NULL); +} + +static void pthread_atexit_init(void) +{ + acl_pthread_key_create(&__pthread_atexit_key, pthread_atexit_done); +} + +int acl_pthread_atexit_add(void *arg, void (*free_fn)(void *)) +{ + const char *myname = "acl_pthread_atexit_add"; + pthread_atexit_t *id; + ACL_FIFO *id_list; + + if (arg == NULL) { + acl_set_error(ACL_EINVAL); + return (ACL_EINVAL); + } + acl_pthread_once(&__pthread_atexit_control_once, pthread_atexit_init); + if (__pthread_atexit_key == (acl_pthread_key_t) ACL_TLS_OUT_OF_INDEXES) { + acl_msg_error("%s(%d): __pthread_atexit_key(%d) invalid", + myname, __LINE__, (int) __pthread_atexit_key); + return (-1); + } + + id = (pthread_atexit_t*) acl_default_malloc(__FILE__, __LINE__, sizeof(pthread_atexit_t)); + if (id == NULL) { + acl_msg_error("%s(%d): malloc error(%s)", + myname, __LINE__, acl_last_serror()); + acl_set_error(ACL_ENOMEM); + return (ACL_ENOMEM); + } + id->free_fn = free_fn; + id->arg = arg; + + id_list = (ACL_FIFO*) acl_pthread_getspecific(__pthread_atexit_key); + if (id_list == NULL) { + id_list = private_fifo_new(); + if (acl_pthread_setspecific(__pthread_atexit_key, id_list) != 0) { + acl_msg_error("%s(%d): acl_pthread_setspecific error(%s), key(%d)", + myname, __LINE__, acl_last_serror(), (int) __pthread_atexit_key); + return (-1); + } + } + private_fifo_push(id_list, id); + return (0); +} + +int acl_pthread_atexit_remove(void *arg, void (*free_fn)(void*)) +{ + const char *myname = "acl_pthread_atexit_remove"; + ACL_FIFO *id_list; + ACL_ITER iter; + + if (arg == NULL) { + acl_set_error(ACL_EINVAL); + return (-1); + } + if (__pthread_atexit_key == (acl_pthread_key_t) ACL_TLS_OUT_OF_INDEXES) { + acl_msg_error("%s(%d): __pthread_atexit_key(%d) invalid", + myname, __LINE__, (int) __pthread_atexit_key); + acl_set_error(ACL_EINVAL); + return (-1); + } + id_list = (ACL_FIFO*) acl_pthread_getspecific(__pthread_atexit_key); + if (id_list == NULL) { + acl_msg_error("%s(%d): __pthread_atexit_key(%d) no exist in tid(%lu)", + myname, __LINE__, (int) __pthread_atexit_key, + (unsigned long) acl_pthread_self()); + return (-1); + } + + acl_foreach(iter, id_list) { + pthread_atexit_t *id_ptr = (pthread_atexit_t*) iter.data; + + if (id_ptr->free_fn == free_fn && id_ptr->arg == arg) { + ACL_FIFO_INFO *id_info = acl_iter_info(iter, id_list); + private_delete_info(id_list, id_info); + acl_default_free(__FILE__, __LINE__, id_ptr); + break; + } + } + return (0); +} + +/*----------------------------------------------------------------------------*/ + +typedef struct { + acl_pthread_key_t key; + void *ptr; + void (*free_fn)(void*); +} TLS_CTX; + +static int acl_tls_ctx_max = 1024; +static acl_pthread_once_t __tls_ctx_control_once = ACL_PTHREAD_ONCE_INIT; +static acl_pthread_key_t __tls_ctx_key = ACL_TLS_OUT_OF_INDEXES; +static TLS_CTX *__main_tls_ctx = NULL; + +int acl_pthread_tls_set_max(int max) +{ + if (max <= 0) { + acl_set_error(ACL_EINVAL); + return (ACL_EINVAL); + } else { + acl_tls_ctx_max = max; + return (0); + } +} + +int acl_pthread_tls_get_max(void) +{ + return (acl_tls_ctx_max); +} + +/* 线程退出时调用此函数释放属于本线程的局部变量 */ + +static void tls_ctx_free(void *ctx) +{ + TLS_CTX *tls_ctxes = (TLS_CTX*) ctx; + int i; + + for (i = 0; i < acl_tls_ctx_max; i++) { + if (tls_ctxes[i].ptr != NULL && tls_ctxes[i].free_fn != NULL) { + tls_ctxes[i].free_fn(tls_ctxes[i].ptr); + } + } + acl_default_free(__FILE__, __LINE__, tls_ctxes); +} + +/* 主线程退出时释放局部变量 */ + +static void main_tls_ctx_free(void) +{ + if (__main_tls_ctx) + tls_ctx_free(__main_tls_ctx); +} + +static void dummy_free(void *ctx acl_unused) +{ +} + +static void tls_ctx_once_init(void) +{ + if ((unsigned long) acl_pthread_self() == (unsigned long) acl_main_thread_self()) { + acl_pthread_key_create(&__tls_ctx_key, dummy_free); + atexit(main_tls_ctx_free); + } else + acl_pthread_key_create(&__tls_ctx_key, tls_ctx_free); +} + +void *acl_pthread_tls_get(acl_pthread_key_t *key_ptr) +{ + const char *myname = "acl_pthread_tls_get"; + TLS_CTX *tls_ctxes; + int i; + + acl_pthread_once(&__tls_ctx_control_once, tls_ctx_once_init); + if (__tls_ctx_key == (acl_pthread_key_t) ACL_TLS_OUT_OF_INDEXES) { + acl_msg_error("%s(%d): __tls_ctx_key invalid, tid(%lu)", + myname, __LINE__, (unsigned long) acl_pthread_self()); + return (NULL); + } + tls_ctxes = (TLS_CTX*) acl_pthread_getspecific(__tls_ctx_key); + if (tls_ctxes == NULL) { + /* 因为该线程中不存在该线程局部变量,所以需要分配一个新的 */ + tls_ctxes = (TLS_CTX*) acl_default_malloc(__FILE__, __LINE__, + acl_tls_ctx_max * sizeof(TLS_CTX)); + if (acl_pthread_setspecific(__tls_ctx_key, tls_ctxes) != 0) { + acl_default_free(__FILE__, __LINE__, tls_ctxes); + acl_msg_error("%s(%d): acl_pthread_setspecific error(%s), tid(%lu)", + myname, __LINE__, acl_last_serror(), + (unsigned long) acl_pthread_self()); + return (NULL); + } + /* 初始化 */ + for (i = 0; i < acl_tls_ctx_max; i++) { + tls_ctxes[i].key = ACL_TLS_OUT_OF_INDEXES; + tls_ctxes[i].ptr = NULL; + tls_ctxes[i].free_fn = NULL; + } + + if ((unsigned long) acl_pthread_self() == (unsigned long) acl_main_thread_self()) + __main_tls_ctx = tls_ctxes; + } + + /* 如果该键已经存在则取出对应数据 */ + if ((int) (*key_ptr) >= 0 && (int) (*key_ptr) < acl_tls_ctx_max) { + if (tls_ctxes[*key_ptr].key == *key_ptr) + return (tls_ctxes[*key_ptr].ptr); + else if (tls_ctxes[*key_ptr].key == + (acl_pthread_key_t) ACL_TLS_OUT_OF_INDEXES) + { + tls_ctxes[*key_ptr].key = *key_ptr; + return (tls_ctxes[*key_ptr].ptr); + } else { + acl_msg_warn("%s(%d): tls_ctxes[%d].key(%d)!= key(%d)", + myname, __LINE__, (int) (*key_ptr), + (int) tls_ctxes[*key_ptr].key, (int) (*key_ptr)); + return (NULL); + } + } + + /* 找出一个空位 */ + for (i = 0; i < acl_tls_ctx_max; i++) { + if (tls_ctxes[i].key == (acl_pthread_key_t) ACL_TLS_OUT_OF_INDEXES) + break; + } + + /* 如果没有空位可用则返回空并置错误标志位 */ + if (i == acl_tls_ctx_max) { + acl_msg_error("%s(%d): no space for tls key", myname, __LINE__); + *key_ptr = (acl_pthread_key_t) ACL_TLS_OUT_OF_INDEXES; + acl_set_error(ACL_ENOMEM); + return (NULL); + } + + /* 为新分配的键初始化线程局部数据对象 */ + tls_ctxes[i].key = (acl_pthread_key_t) i; + tls_ctxes[i].free_fn = NULL; + tls_ctxes[i].ptr = NULL; + *key_ptr = (acl_pthread_key_t) i; + return (NULL); +} + +int acl_pthread_tls_set(acl_pthread_key_t key, void *ptr, void (*free_fn)(void *)) +{ + const char *myname = "acl_pthread_tls_set"; + TLS_CTX *tls_ctxes; + + if ((int) key < 0 || (int) key >= acl_tls_ctx_max) { + acl_msg_error("%s(%d): key(%d) invalid", myname, __LINE__, (int) key); + acl_set_error(ACL_EINVAL); + return (ACL_EINVAL); + } + + if (__tls_ctx_key == (acl_pthread_key_t) ACL_TLS_OUT_OF_INDEXES) { + acl_msg_error("%s(%d): __tls_ctx_key invalid, tid(%lu)", + myname, __LINE__, (unsigned long) acl_pthread_self()); + acl_set_error(ACL_ENOMEM); + return (ACL_ENOMEM); + } + tls_ctxes = (TLS_CTX*) acl_pthread_getspecific(__tls_ctx_key); + if (tls_ctxes == NULL) { + acl_msg_error("%s(%d): __tls_ctx_key(%d) no exist", + myname, __LINE__, (int) __tls_ctx_key); + return (-1); + } + if (tls_ctxes[key].key != key) { + acl_msg_error("%s(%d): key(%d) invalid", myname, __LINE__, (int) key); + acl_set_error(ACL_EINVAL); + return (ACL_EINVAL); + } + /* 如果该键值存在旧数据则首先需要释放掉旧数据 */ + if (tls_ctxes[key].ptr != NULL && tls_ctxes[key].free_fn != NULL) { + tls_ctxes[key].free_fn(tls_ctxes[key].ptr); + } + tls_ctxes[key].free_fn = free_fn; + tls_ctxes[key].ptr = ptr; + return (0); +} + +int acl_pthread_tls_del(acl_pthread_key_t key) +{ + const char *myname = "acl_pthread_tls_del"; + TLS_CTX *tls_ctxes; + + if ((int) key < 0 || (int) key >= acl_tls_ctx_max) { + acl_msg_error("%s(%d): key(%d) invalid", myname, __LINE__, (int) key); + acl_set_error(ACL_EINVAL); + return (ACL_EINVAL); + } + + if (__tls_ctx_key == (acl_pthread_key_t) ACL_TLS_OUT_OF_INDEXES) { + acl_msg_error("%s(%d): __tls_ctx_key invalid, tid(%lu)", + myname, __LINE__, (unsigned long) acl_pthread_self()); + acl_set_error(ACL_ENOMEM); + return (ACL_ENOMEM); + } + + tls_ctxes = (TLS_CTX*) acl_pthread_getspecific(__tls_ctx_key); + if (tls_ctxes == NULL) { + acl_msg_error("%s(%d): __tls_ctx_key(%d) no exist", + myname, __LINE__, (int) __tls_ctx_key); + return (-1); + } + + if (tls_ctxes[key].key != key) { + acl_msg_error("%s(%d): key(%d) invalid", myname, __LINE__, (int) key); + acl_set_error(ACL_EINVAL); + return (ACL_EINVAL); + } + + tls_ctxes[key].free_fn = NULL; + tls_ctxes[key].ptr = NULL; + tls_ctxes[key].key = (acl_pthread_key_t) ACL_TLS_OUT_OF_INDEXES; + return (0); +} + +void acl_pthread_tls_once_get(acl_pthread_once_t *control_once) +{ + memcpy(control_once, &__tls_ctx_control_once, sizeof(acl_pthread_once_t)); +} + +void acl_pthread_tls_once_set(acl_pthread_once_t control_once) +{ + __tls_ctx_control_once = control_once; +} + +acl_pthread_key_t acl_pthread_tls_key_get(void) +{ + return (__tls_ctx_key); +} + +void acl_pthread_tls_key_set(acl_pthread_key_t key) +{ + __tls_ctx_key = key; +} diff --git a/lib_acl/src/thread/acl_pthread_cond.c b/lib_acl/src/thread/acl_pthread_cond.c new file mode 100644 index 000000000..2eb877c84 --- /dev/null +++ b/lib_acl/src/thread/acl_pthread_cond.c @@ -0,0 +1,243 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include "stdlib/acl_msg.h" +#include "stdlib/acl_mymalloc.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#endif + +#ifndef ACL_HAS_PTHREAD + +#include "stdlib/acl_sys_patch.h" +#include "thread/acl_sem.h" +#include "thread/acl_pthread.h" + +int acl_pthread_cond_init(acl_pthread_cond_t *cond, acl_pthread_condattr_t *cond_attr) +{ + char myname[] = "acl_pthread_cond_init"; + + if (cond == NULL) { + acl_msg_error("%s, %s(%d): input invalid", + __FILE__, myname, __LINE__); + return -1; + } + + cond_attr = cond_attr; + + cond->dynamic = 0; + cond->lock = acl_pthread_mutex_create(); + cond->wait_sem = acl_sem_create(0); + cond->wait_done = acl_sem_create(0); + cond->waiting = cond->signals = 0; + + if (!cond->lock || !cond->wait_sem || !cond->wait_done) + return (-1); + return (0); +} + +/* Create a condition variable */ +acl_pthread_cond_t * acl_pthread_cond_create(void) +{ + char myname[] = "acl_pthread_cond_create"; + acl_pthread_cond_t *cond; + char buf[256]; + + cond = (acl_pthread_cond_t *) + acl_mycalloc(1, sizeof(acl_pthread_cond_t)); + if (cond == NULL) { + acl_msg_error("%s, %s(%d): calloc error(%s)", + __FILE__, myname, __LINE__, + acl_last_strerror(buf, sizeof(buf))); + return (NULL); + } + + if (acl_pthread_cond_init(cond, NULL) < 0) { + acl_pthread_cond_destroy(cond); + return (NULL); + } + + cond->dynamic = 1; + + return(cond); +} + +/* Destroy a condition variable */ +int acl_pthread_cond_destroy(acl_pthread_cond_t *cond) +{ + if (cond == NULL) + return (-1); + + if (cond->wait_sem) + acl_sem_destroy(cond->wait_sem); + if ( cond->wait_done ) + acl_sem_destroy(cond->wait_done); + if ( cond->lock ) + acl_pthread_mutex_destroy(cond->lock); + + if (cond->dynamic) + acl_myfree(cond); + + return (0); +} + +/* Restart one of the threads that are waiting on the condition variable */ +int acl_pthread_cond_signal(acl_pthread_cond_t *cond) +{ + char myname[] = "acl_pthread_cond_signal"; + + if (cond == NULL) { + acl_msg_error("%s, %s(%d): input invalid", + __FILE__, myname, __LINE__); + return -1; + } + + /* If there are waiting threads not already signalled, then + * signal the condition and wait for the thread to respond. + */ + acl_pthread_mutex_lock(cond->lock); + if (cond->waiting > cond->signals) { + ++cond->signals; + acl_sem_post(cond->wait_sem); + acl_pthread_mutex_unlock(cond->lock); + acl_sem_wait(cond->wait_done); + } else { + acl_pthread_mutex_unlock(cond->lock); + } + + return 0; +} + +/* Restart all threads that are waiting on the condition variable */ +int acl_pthread_cond_broadcast(acl_pthread_cond_t *cond) +{ + char myname[] = "acl_pthread_cond_broadcast"; + + if (cond == NULL) { + acl_msg_error("%s, %s(%d): input invalid", + __FILE__, myname, __LINE__); + return -1; + } + + /* If there are waiting threads not already signalled, then + * signal the condition and wait for the thread to respond. + */ + acl_pthread_mutex_lock(cond->lock); + if (cond->waiting > cond->signals) { + int i, num_waiting; + + num_waiting = (cond->waiting - cond->signals); + cond->signals = cond->waiting; + for (i = 0; i < num_waiting; ++i) { + acl_sem_post(cond->wait_sem); + } + /* Now all released threads are blocked here, waiting for us. + Collect them all (and win fabulous prizes!) :-) + */ + acl_pthread_mutex_unlock(cond->lock); + for (i = 0; i < num_waiting; ++i) { + acl_sem_wait(cond->wait_done); + } + } else { + acl_pthread_mutex_unlock(cond->lock); + } + + return 0; +} + +/* Wait on the condition variable for at most 'ms' milliseconds. + The mutex must be locked before entering this function! + The mutex is unlocked during the wait, and locked again after the wait. + +Typical use: + +Thread A: + pthread_mutex_lock(lock); + while ( ! condition ) { + SDL_CondWait(cond); + } + pthread_mutex_unlock(lock); + +Thread B: + pthread_mutex_lock(lock); + ... + condition = true; + ... + pthread_mutex_unlock(lock); + */ +int acl_pthread_cond_timedwait(acl_pthread_cond_t *cond, acl_pthread_mutex_t *mutex, + const struct timespec *timeout) +{ + char myname[] = "acl_pthread_cond_timedwait"; + int retval; + + if (cond == NULL) { + acl_msg_error("%s, %s(%d): input invalid", + __FILE__, myname, __LINE__); + return -1; + } + + /* Obtain the protection mutex, and increment the number of waiters. + * This allows the signal mechanism to only perform a signal if there + * are waiting threads. + */ + acl_pthread_mutex_lock(cond->lock); + ++cond->waiting; + acl_pthread_mutex_unlock(cond->lock); + + /* Unlock the mutex, as is required by condition variable semantics */ + acl_pthread_mutex_unlock(mutex); + + /* Wait for a signal */ + if (timeout == NULL) { + retval = acl_sem_wait(cond->wait_sem); + } else { + int ms; + struct timeval tv; + + gettimeofday(&tv, NULL); + ms = (int) (timeout->tv_sec * 1000 + timeout->tv_nsec / 1000000); + ms -= tv.tv_sec * 1000 + tv.tv_usec / 1000; + if (ms < 0) + ms = 0; + retval = acl_sem_wait_timeout(cond->wait_sem, (unsigned int) ms); + } + + /* Let the signaler know we have completed the wait, otherwise + * the signaler can race ahead and get the condition semaphore + * if we are stopped between the mutex unlock and semaphore wait, + * giving a deadlock. See the following URL for details: + * http://www-classic.be.com/aboutbe/benewsletter/volume_III/Issue40.html + */ + acl_pthread_mutex_lock(cond->lock); + if (cond->signals > 0) { + /* If we timed out, we need to eat a condition signal */ + if (retval > 0) { + acl_sem_wait(cond->wait_sem); + } + /* We always notify the signal thread that we are done */ + acl_sem_post(cond->wait_done); + + /* Signal handshake complete */ + --cond->signals; + } + --cond->waiting; + acl_pthread_mutex_unlock(cond->lock); + + /* Lock the mutex, as is required by condition variable semantics */ + acl_pthread_mutex_lock(mutex); + + return (retval); +} + +/* Wait on the condition variable forever */ +int acl_pthread_cond_wait(acl_pthread_cond_t *cond, acl_pthread_mutex_t *mutex) +{ + return (acl_pthread_cond_timedwait(cond, mutex, NULL)); +} + +#endif /* ACL_HAS_PTHREAD */ diff --git a/lib_acl/src/thread/acl_pthread_mutex.c b/lib_acl/src/thread/acl_pthread_mutex.c new file mode 100644 index 000000000..44a5b668b --- /dev/null +++ b/lib_acl/src/thread/acl_pthread_mutex.c @@ -0,0 +1,283 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_dbuf_pool.h" +#include "stdlib/acl_ring.h" +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_msg.h" +#include "thread/acl_pthread.h" + +#endif + +#ifdef ACL_MS_WINDOWS + +int acl_pthread_mutex_init(acl_pthread_mutex_t *mutex, const acl_pthread_mutexattr_t *mattr) +{ + char myname[] = "acl_pthread_mutex_init"; + char buf[256]; + + if (mutex == NULL) { + acl_msg_error("%s, %s(%d): input invalid", + __FILE__, myname, __LINE__); + return (-1); + } + + mutex->dynamic = 0; + + /* Create the mutex, with initial value signaled */ + mutex->id = CreateMutex((SECURITY_ATTRIBUTES *) mattr, FALSE, NULL); + if (!mutex->id) { + acl_msg_error("%s, %s(%d): CreateMutex error(%s)", + __FILE__, myname, __LINE__, + acl_last_strerror(buf, sizeof(buf))); + acl_myfree(mutex); + return (-1); + } + return (0); +} + +acl_pthread_mutex_t *acl_pthread_mutex_create(void) +{ + char myname[] = "acl_pthread_mutex_create"; + acl_pthread_mutex_t *mutex; + char buf[256]; + + mutex = acl_mycalloc(1, sizeof(acl_pthread_mutex_t)); + if (mutex == NULL) { + acl_msg_error("%s, %s(%d): calloc error(%s)", + __FILE__, myname, __LINE__, + acl_last_strerror(buf, sizeof(buf))); + return (NULL); + } + + mutex->dynamic = 1; + + /* Create the mutex, with initial value signaled */ + mutex->id = CreateMutex(NULL, FALSE, NULL); + if (!mutex->id) { + acl_msg_error("%s, %s(%d): CreateMutex error(%s)", + __FILE__, myname, __LINE__, + acl_last_strerror(buf, sizeof(buf))); + acl_myfree(mutex); + return (NULL); + } + return (mutex); +} + +/* Free the mutex */ +int acl_pthread_mutex_destroy(acl_pthread_mutex_t *mutex) +{ + if (mutex) { + if (mutex->id) { + CloseHandle(mutex->id); + mutex->id = 0; + } + if (mutex->dynamic) + acl_myfree(mutex); + return (0); + } else + return (-1); +} + +int acl_pthread_mutex_lock(acl_pthread_mutex_t *mutex) +{ + char myname[] = "acl_pthread_mutex_lock"; + char buf[256]; + + if (mutex == NULL) { + acl_msg_error("%s, %s(%d): input invalid", + __FILE__, myname, __LINE__); + return (-1); + } + + if (WaitForSingleObject(mutex->id, INFINITE) == WAIT_FAILED) { + acl_msg_error("%s, %s(%d): WaitForSingleObject error(%s)", + __FILE__, myname, __LINE__, + acl_last_strerror(buf, sizeof(buf))); + return (-1); + } + + return (0); +} + +int acl_pthread_mutex_unlock(acl_pthread_mutex_t *mutex) +{ + char myname[] = "acl_pthread_mutex_unlock"; + char buf[256]; + + if (mutex == NULL) { + acl_msg_error("%s, %s(%d): input invalid", + __FILE__, myname, __LINE__); + return (-1); + } + + if (ReleaseMutex(mutex->id) == FALSE) { + acl_msg_error("%s, %s(%d): ReleaseMutex error(%s)", + __FILE__, myname, __LINE__, + acl_last_strerror(buf, sizeof(buf))); + return (-1); + } + + return (0); +} + +#elif defined(ACL_UNIX) + +#include + +acl_pthread_mutex_t *acl_pthread_mutex_create(void) +{ + const char *myname = "acl_pthread_mutex_create"; + acl_pthread_mutex_t *mutex; + int status; + char buf[256]; + + mutex = (acl_pthread_mutex_t *) + acl_mymalloc(sizeof(acl_pthread_mutex_t)); + if (mutex == NULL) + return (NULL); + + if ((status = acl_pthread_mutex_init(mutex, NULL)) < 0) { + acl_msg_error("%s: init mutex error(%s)(%s)", + myname, acl_last_strerror(buf, sizeof(buf)), + strerror(status)); + + acl_myfree(mutex); + return (NULL); + } + + return (mutex); +} + +#endif /* ACL_MS_WINDOWS/ACL_UNIX */ + +typedef struct acl_pthread_nested_mutex_t acl_pthread_nested_mutex_t; + +struct acl_pthread_nested_mutex_t { + acl_pthread_mutex_t *mutex; + ACL_RING ring; + int nrefer; + char *ptr; +}; + +static acl_pthread_key_t __header_key; + +static void free_header(void *arg) +{ + ACL_RING *header_ptr = (ACL_RING*) arg; + ACL_RING_ITER iter; + acl_pthread_nested_mutex_t *tmp; + + if (header_ptr == NULL) + return; + + acl_ring_foreach(iter, header_ptr) { + tmp = ACL_RING_TO_APPL(iter.ptr, acl_pthread_nested_mutex_t, ring); + if (tmp->mutex != NULL && tmp->nrefer > 0) { + acl_pthread_mutex_unlock(tmp->mutex); + } + } +} + +static void acl_thread_mutex_init_once(void) +{ + acl_pthread_key_create(&__header_key, free_header); +} + +static acl_pthread_once_t thread_mutex_once_control = ACL_PTHREAD_ONCE_INIT; +int acl_thread_mutex_lock(acl_pthread_mutex_t *mutex) +{ + ACL_RING_ITER iter; + acl_pthread_nested_mutex_t *tmp, *nested_mutex = NULL; + ACL_RING *header_ptr; + + if (mutex == NULL) + return (-1); + + acl_pthread_once(&thread_mutex_once_control, acl_thread_mutex_init_once); + + header_ptr = acl_pthread_getspecific(__header_key); + + if (header_ptr == NULL) { + header_ptr = (ACL_RING*) acl_mymalloc(sizeof(ACL_RING)); + acl_ring_init(header_ptr); + acl_pthread_setspecific(__header_key, header_ptr); + } + + acl_ring_foreach(iter, header_ptr) { + tmp = ACL_RING_TO_APPL(iter.ptr, acl_pthread_nested_mutex_t, ring); + if (tmp->mutex == mutex) { + nested_mutex = tmp; + break; + } + } + + if (nested_mutex == NULL) { + nested_mutex = (acl_pthread_nested_mutex_t*) + acl_mymalloc(sizeof(acl_pthread_nested_mutex_t)); + acl_pthread_mutex_lock(mutex); + nested_mutex->mutex = mutex; + nested_mutex->nrefer = 1; + ACL_RING_APPEND(header_ptr, &nested_mutex->ring); + } else { + nested_mutex->nrefer++; + } + return (0); +} + +int acl_thread_mutex_unlock(acl_pthread_mutex_t *mutex) +{ + ACL_RING_ITER iter; + acl_pthread_nested_mutex_t *tmp, *nested_mutex = NULL; + ACL_RING *header_ptr = acl_pthread_getspecific(__header_key); + + if (mutex == NULL || header_ptr == NULL) + return (-1); + + acl_ring_foreach(iter, header_ptr) { + tmp = ACL_RING_TO_APPL(iter.ptr, acl_pthread_nested_mutex_t, ring); + if (tmp->mutex == mutex) { + nested_mutex = tmp; + break; + } + } + + if (nested_mutex == NULL) + return (-1); + if (--nested_mutex->nrefer == 0) { + ACL_RING_DETACH(&nested_mutex->ring); + acl_myfree(nested_mutex); + acl_pthread_mutex_unlock(mutex); + } + + return (0); +} + +int acl_thread_mutex_nested(acl_pthread_mutex_t *mutex) +{ + ACL_RING_ITER iter; + acl_pthread_nested_mutex_t *tmp, *nested_mutex = NULL; + ACL_RING *header_ptr = acl_pthread_getspecific(__header_key); + + if (mutex == NULL || header_ptr == NULL) + return (-1); + + acl_ring_foreach(iter, header_ptr) { + tmp = ACL_RING_TO_APPL(iter.ptr, acl_pthread_nested_mutex_t, ring); + if (tmp->mutex == mutex) { + nested_mutex = tmp; + break; + } + } + + if (nested_mutex == NULL) + return (0); + return (nested_mutex->nrefer); +} diff --git a/lib_acl/src/thread/acl_pthread_pool.c b/lib_acl/src/thread/acl_pthread_pool.c new file mode 100644 index 000000000..76983a21c --- /dev/null +++ b/lib_acl/src/thread/acl_pthread_pool.c @@ -0,0 +1,1047 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#include +#ifdef ACL_UNIX +#include +#include +#include +#include +#include +#include +#include + +#elif defined(ACL_MS_WINDOWS) +# ifdef ACL_MS_VC +# pragma once +# endif +# ifdef ACL_BCB_COMPILER +# pragma hdrstop +# endif +#endif + +#include "stdlib/acl_sys_patch.h" +#include "stdlib/acl_msg.h" +#include "thread/acl_pthread.h" +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_debug.h" +#include "stdlib/acl_slice.h" +#include "thread/acl_pthread_pool.h" + +#endif + +#define ACL_PTHREAD_POOL_VALID 0x0decca62 + +typedef struct ACL_TASK { + struct ACL_TASK *next; + void (*worker_fn)(void *arg); /* user function */ + void *worker_arg; +} ACL_TASK; + +#undef USE_SLICE + +struct acl_pthread_pool_t { + acl_pthread_mutex_t worker_mutex; /* control access to queue */ + acl_pthread_cond_t worker_cond; /* wait_for_work */ + acl_pthread_mutex_t poller_mutex; /* just for wait poller exit */ + acl_pthread_cond_t poller_cond; /* just for wait poller exit */ + acl_pthread_attr_t attr; /* create detached */ + ACL_TASK *first, *last; /* work queue */ +#ifdef USE_SLICE + ACL_SLICE *slice; +#endif + int poller_running; /* is poller thread running ? */ + int qlen; /* the work queue's length */ + int valid; /* valid */ + int worker_quit; /* worker should quit */ + int poller_quit; /* poller should quit */ + int parallelism; /* maximum threads */ + int counter; /* current threads */ + int idle; /* idle threads */ + int idle_timeout; /* idle timeout second */ + int overload_timewait; /* when too busy, need sleep ? */ + time_t last_warn; /* last warn time */ + int (*poller_fn)(void *arg); /* worker poll function */ + void *poller_arg; /* the arg of poller_fn */ + int (*worker_init_fn)(void *arg); /* the arg is worker_init_arg */ + void *worker_init_arg; + void (*worker_free_fn)(void *arg); /* the arg is worker_free_arg */ + void *worker_free_arg; +}; + +#undef __SET_ERRNO +#ifdef ACL_MS_WINDOWS +# define __SET_ERRNO(_x_) (void) 0 +#elif defined(ACL_UNIX) +# define __SET_ERRNO(_x_) (acl_set_error(_x_)) +#else +# error "unknown OS type" +#endif + +#ifdef ACL_MS_WINDOWS +#define sleep(_x_) do { \ + Sleep(_x_ * 1000); \ +} while (0) +#endif + +static void *__poller_thread(void *arg) +{ + const char *myname = "__poller_thread"; + acl_pthread_pool_t *thr_pool = (acl_pthread_pool_t*) arg; + const int wait_sec = 1, max_loop_persec = 81920; + int loop_count; + int status; + time_t now_t, pre_loop_t; +#ifdef ACL_UNIX + pthread_t id = pthread_self(); +#elif defined(ACL_MS_WINDOWS) + unsigned long id = acl_pthread_self(); +#else + # error "unknown OS" +#endif + + if (thr_pool->poller_fn == NULL) + acl_msg_fatal("%s, %s(%d): poller_fn is null!", + __FILE__, myname, __LINE__); + + acl_debug(ACL_DEBUG_THR_POOL, 2) ("%s(%d): poller(tid=%lu) started ...", + myname, __LINE__, (unsigned long) id); + loop_count = 0; + pre_loop_t = time(NULL); + + status = acl_pthread_mutex_lock(&thr_pool->poller_mutex); + if (status != 0) { + thr_pool->poller_running = 0; + __SET_ERRNO(status); + acl_msg_error("%s, %s(%d): pthread_mutex_lock error(%s)", + __FILE__, myname, __LINE__, acl_last_serror()); + return (NULL); + } + + thr_pool->poller_running = 1; + + for (;;) { + if (thr_pool->poller_quit) + break; + + now_t = time(NULL); + loop_count++; + if (loop_count >= max_loop_persec) { + /* avoid loop too quickly in one second */ + if (now_t - pre_loop_t <= wait_sec) { + acl_msg_warn("%s: loop too fast, sleep %d second", + myname, wait_sec); + sleep(wait_sec); + now_t = time(NULL); /* adjust the time of now */ + } + pre_loop_t = now_t; /*adjust the pre_loop_t time */ + loop_count = 0; + } + + if (thr_pool->poller_fn(thr_pool->poller_arg) < 0) + break; + } + + acl_debug(ACL_DEBUG_THR_POOL, 2) ("%s(%d): poller(%lu) thread quit ...", + myname, __LINE__, (unsigned long) id); + + thr_pool->poller_running = 0; + +#ifdef ACL_MS_WINDOWS + status = acl_pthread_cond_signal(&thr_pool->poller_cond); +#else + status = pthread_cond_broadcast(&thr_pool->poller_cond); +#endif + + if ( status != 0 ) { + __SET_ERRNO(status); + acl_msg_error("%s(%d)->%s: pthread_cond_signal, serr = %s", + __FILE__, __LINE__, myname, acl_last_serror()); + } + + acl_debug(ACL_DEBUG_THR_POOL, 3) ("poller broadcast ok"); + + status = acl_pthread_mutex_unlock(&thr_pool->poller_mutex); + if (status != 0) { + __SET_ERRNO(status); + acl_msg_error("%s, %s(%d): pthread_mutex_unlock error(%s)", + __FILE__, myname, __LINE__, acl_last_serror()); + return (NULL); + } + + acl_debug(ACL_DEBUG_THR_POOL, 3) ("poller unlock ok"); + + return (NULL); +} + +static void *__worker_thread(void* arg) +{ + const char *myname = "__worker_thread"; + acl_pthread_pool_t *thr_pool = (acl_pthread_pool_t*) arg; + int status; + ACL_TASK *we; + struct timespec timeout; + struct timeval tv; + int timedout; + +#undef RETURN +#define RETURN(_x_) { \ + if (thr_pool->worker_free_fn != NULL) \ + thr_pool->worker_free_fn(thr_pool->worker_free_arg); \ + return (_x_); \ +} + + if (thr_pool->worker_init_fn != NULL) { + if (thr_pool->worker_init_fn(thr_pool->worker_init_arg) < 0) { + acl_msg_error("%s(%d), %s: tid = %lu, worker init call error", + __FILE__, __LINE__, myname, + (unsigned long) acl_pthread_self()); + return (NULL); + } + } + + status = acl_pthread_mutex_lock(&thr_pool->worker_mutex); + if (status != 0) { + __SET_ERRNO(status); + acl_msg_error("%s(%d)->%s: tid = %lu, lock error(%s)", + __FILE__, __LINE__, myname, + (unsigned long) acl_pthread_self(), acl_last_serror()); + return (NULL); + } + + for (;;) { + gettimeofday(&tv, NULL); + timeout.tv_sec = tv.tv_sec + thr_pool->idle_timeout; + timeout.tv_nsec = tv.tv_usec * 1000; + timedout = 0; + + while (thr_pool->first == NULL && !thr_pool->worker_quit) { + thr_pool->idle++; + + if (thr_pool->idle_timeout > 0) + status = acl_pthread_cond_timedwait(&thr_pool->worker_cond, + &thr_pool->worker_mutex, &timeout); + else + status = acl_pthread_cond_wait(&thr_pool->worker_cond, + &thr_pool->worker_mutex); + thr_pool->idle--; + if (status == ACL_ETIMEDOUT) { + timedout = 1; + break; + } else if (status != 0) { + __SET_ERRNO(status); + thr_pool->counter--; + acl_pthread_mutex_unlock(&thr_pool->worker_mutex); + acl_msg_error("%s(%d)->%s: tid = %lu," + " cond timewait error(%s)(%s)", + __FILE__, __LINE__, myname, + (unsigned long) acl_pthread_self(), + acl_last_serror(), strerror(status)); + RETURN (NULL); + } + } /* end while */ + we = thr_pool->first; + if (we != NULL) { + if (we->worker_fn == NULL) + acl_msg_fatal("%s(%d)->%s: worker_fn null", + __FILE__, __LINE__, myname); + + thr_pool->first = we->next; + thr_pool->qlen--; + if (thr_pool->last == we) + thr_pool->last = NULL; + /* the lock shuld be unlocked before enter working processs */ + status = acl_pthread_mutex_unlock(&thr_pool->worker_mutex); + if (status != 0) { + __SET_ERRNO(status); + acl_msg_error("%s(%d)->%s: unlock error(%s), tid=%lu", + __FILE__, __LINE__, myname, acl_last_serror(), + (unsigned long) acl_pthread_self()); + RETURN (NULL); + } + we->worker_fn(we->worker_arg); +#ifndef USE_SLICE + acl_myfree(we); +#endif + + /* lock again */ + status = acl_pthread_mutex_lock(&thr_pool->worker_mutex); + if (status != 0) { + __SET_ERRNO(status); + acl_msg_error("%s(%d)->%s: lock error(%s), sid=%lu", + __FILE__, __LINE__, myname, acl_last_serror(), + (unsigned long) acl_pthread_self()); + RETURN (NULL); + } +#ifdef USE_SLICE + acl_slice_free2(thr_pool->slice, we); +#endif + } + if (thr_pool->first == NULL && thr_pool->worker_quit) { + thr_pool->counter--; + if (thr_pool->counter == 0) + acl_pthread_cond_broadcast(&thr_pool->worker_cond); + break; + } + + if (thr_pool->first == NULL && timedout) { + thr_pool->counter--; + break; + } + } + + status = acl_pthread_mutex_unlock(&thr_pool->worker_mutex); + if (status != 0) { + __SET_ERRNO(status); + acl_msg_error("%s, %s(%d): unlock error(%s)", + __FILE__, myname, __LINE__, acl_last_serror()); + } + + acl_debug(ACL_DEBUG_THR_POOL, 2) ("%s(%d): thread(%lu) exit now", + myname, __LINE__, (unsigned long) acl_pthread_self()); + + RETURN (NULL); +} + +static void __init_workq(acl_pthread_pool_t *thr_pool) +{ + thr_pool->worker_quit = 0; + thr_pool->poller_quit = 0; + thr_pool->poller_running = 0; + thr_pool->first = NULL; + thr_pool->last = NULL; + thr_pool->qlen = 0; + thr_pool->overload_timewait = 0; + thr_pool->counter = 0; + thr_pool->idle = 0; +} + +/* create work queue */ + +acl_pthread_pool_t *acl_thread_pool_create(int threads_limit, int idle_timeout) +{ + acl_pthread_pool_t *thr_pool; /* 线程池句柄 */ + acl_pthread_pool_attr_t attr; /* 线程池初始化时的属性 */ + + /* 初始化线程池对象属性 */ + acl_pthread_pool_attr_init(&attr); + acl_pthread_pool_attr_set_threads_limit(&attr, threads_limit); + acl_pthread_pool_attr_set_idle_timeout(&attr, idle_timeout); + + /* 创建半驻留线程句柄 */ + thr_pool = acl_pthread_pool_create(&attr); + return (thr_pool); +} + +acl_pthread_pool_t *acl_pthread_pool_create(const acl_pthread_pool_attr_t *attr) +{ + const char *myname = "acl_pthread_pool_create"; + int status; + acl_pthread_pool_t *thr_pool; + + thr_pool = acl_mycalloc(1, sizeof(*thr_pool)); + status = acl_pthread_attr_init(&thr_pool->attr); + if (status != 0) { + __SET_ERRNO(status); + acl_msg_error("%s(%d)->%s: pthread_attr_init, serr = %s", + __FILE__, __LINE__, myname, acl_last_serror()); + return (NULL); + } + + if (attr && attr->stack_size > 0) + acl_pthread_attr_setstacksize(&thr_pool->attr, attr->stack_size); + +#ifdef ACL_UNIX + status = pthread_attr_setdetachstate(&thr_pool->attr, PTHREAD_CREATE_DETACHED); + if (status != 0) { + acl_set_error(status); + pthread_attr_destroy(&thr_pool->attr); + acl_myfree(thr_pool); + acl_msg_error("%s(%d)->%s: pthread_attr_setdetachstate, serr = %s", + __FILE__, __LINE__, myname, acl_last_serror()); + return (NULL); + } +# if !defined(__FreeBSD__) + status = pthread_attr_setscope(&thr_pool->attr, PTHREAD_SCOPE_SYSTEM); + if (status != 0) { + pthread_attr_destroy(&thr_pool->attr); + acl_myfree(thr_pool); + acl_set_error(status); + acl_msg_error("%s(%d)->%s: pthread_attr_setscope, serr = %s", + __FILE__, __LINE__, myname, acl_last_serror()); + return (NULL); + } +# endif +#elif defined(ACL_MS_WINDOWS) + (void) acl_pthread_attr_setdetachstate(&thr_pool->attr, 1); +#endif + status = acl_pthread_mutex_init(&thr_pool->worker_mutex, NULL); + if (status != 0) { + __SET_ERRNO(status); + acl_pthread_attr_destroy(&thr_pool->attr); + acl_myfree(thr_pool); + acl_msg_error("%s(%d)->%s: pthread_mutex_init, serr = %s", + __FILE__, __LINE__, myname, acl_last_serror()); + return (NULL); + } + status = acl_pthread_cond_init(&thr_pool->worker_cond, NULL); + if (status != 0) { + acl_pthread_attr_destroy(&thr_pool->attr); + acl_pthread_mutex_destroy(&thr_pool->worker_mutex); + acl_myfree(thr_pool); + __SET_ERRNO(status); + acl_msg_error("%s(%d)->%s: pthread_cond_init, serr = %s", + __FILE__, __LINE__, myname, acl_last_serror()); + return (NULL); + } + + status = acl_pthread_mutex_init(&thr_pool->poller_mutex, NULL); + if (status != 0) { + __SET_ERRNO(status); + acl_pthread_attr_destroy(&thr_pool->attr); + acl_pthread_mutex_destroy(&thr_pool->worker_mutex); + acl_pthread_cond_destroy(&thr_pool->worker_cond); + acl_myfree(thr_pool); + acl_msg_error("%s(%d)->%s: pthread_mutex_init, serr = %s", + __FILE__, __LINE__, myname, acl_last_serror()); + return (NULL); + } + status = acl_pthread_cond_init(&thr_pool->poller_cond, NULL); + if (status != 0) { + acl_pthread_attr_destroy(&thr_pool->attr); + acl_pthread_mutex_destroy(&thr_pool->worker_mutex); + acl_pthread_cond_destroy(&thr_pool->worker_cond); + acl_pthread_mutex_destroy(&thr_pool->poller_mutex); + acl_myfree(thr_pool); + __SET_ERRNO(status); + acl_msg_error("%s(%d)->%s: pthread_cond_init, serr = %s", + __FILE__, __LINE__, myname, acl_last_serror()); + return (NULL); + } + + __init_workq(thr_pool); + +#ifdef USE_SLICE + thr_pool->slice = acl_slice_create("thread_pool", 10240 * sizeof(ACL_TASK), + sizeof(ACL_TASK), ACL_SLICE_FLAG_GC2); +#endif + thr_pool->parallelism = (attr && attr->threads_limit > 0) ? + attr->threads_limit : ACL_PTHREAD_POOL_DEF_THREADS; + thr_pool->idle_timeout = (attr && attr->idle_timeout > 0) ? + attr->idle_timeout : ACL_PTHREAD_POOL_DEF_IDLE; + thr_pool->poller_fn = NULL; + thr_pool->poller_arg = NULL; + + thr_pool->worker_init_fn = NULL; + thr_pool->worker_init_arg = NULL; + thr_pool->worker_free_fn = NULL; + thr_pool->worker_free_arg = NULL; + + thr_pool->valid = ACL_PTHREAD_POOL_VALID; + + return (thr_pool); +} + +int acl_pthread_pool_set_timewait(acl_pthread_pool_t *thr_pool, int timewait) +{ + const char *myname = "acl_pthread_pool_set_timewait"; + + if (thr_pool == NULL || thr_pool->valid != ACL_PTHREAD_POOL_VALID + || timewait < 0) + { + acl_msg_error("%s(%d)->%s: invalid input", + __FILE__, __LINE__, myname); + return (-1); + } + + thr_pool->overload_timewait = timewait; + return (0); +} + +int acl_pthread_pool_atinit(acl_pthread_pool_t *thr_pool, + int (*init_fn)(void *), void *init_arg) +{ + const char *myname = "acl_pthread_pool_atinit"; + + if (thr_pool == NULL || thr_pool->valid != ACL_PTHREAD_POOL_VALID) { + acl_msg_error("%s(%d)->%s: input invalid", + __FILE__, __LINE__, myname); + return (ACL_EINVAL); + } + + thr_pool->worker_init_fn = init_fn; + thr_pool->worker_init_arg = init_arg; + + return (0); +} + +int acl_pthread_pool_atfree(acl_pthread_pool_t *thr_pool, + void (*free_fn)(void *), void *free_arg) +{ + const char *myname = "acl_pthread_pool_atfree"; + + if (thr_pool == NULL || thr_pool->valid != ACL_PTHREAD_POOL_VALID) { + acl_msg_error("%s(%d)->%s: input invalid", + __FILE__, __LINE__, myname); + return (ACL_EINVAL); + } + + thr_pool->worker_free_fn = free_fn; + thr_pool->worker_free_arg = free_arg; + + return (0); +} + +static int __wait_poller_exit(acl_pthread_pool_t *thr_pool) +{ + const char *myname = "__wait_poller_exit"; + int status, nwait = 0; + struct timeval tv; + struct timespec timeout; + + acl_debug(ACL_DEBUG_THR_POOL, 3) ("%s: begin to lock", myname); + + thr_pool->poller_quit = 1; + + status = acl_pthread_mutex_lock(&thr_pool->poller_mutex); + if (status != 0) { + __SET_ERRNO(status); + acl_msg_error("%s, %s(%d): pthread_mutex_lock, serr = %s", + __FILE__, myname, __LINE__, acl_last_serror()); + return (status); + } + + acl_debug(ACL_DEBUG_THR_POOL, 3) ("%s: begin to wait cond", myname); + + while (thr_pool->poller_running != 0) { + gettimeofday(&tv, NULL); + timeout.tv_sec = tv.tv_sec + 1; + timeout.tv_nsec = tv.tv_usec * 1000; + + nwait++; + + status = acl_pthread_cond_timedwait(&thr_pool->poller_cond, + &thr_pool->poller_mutex, &timeout); + if (status == ACL_ETIMEDOUT) { + acl_debug(ACL_DEBUG_THR_POOL, 3) ("%s: nwait=%d", myname, nwait); + } else if (status != 0) { + __SET_ERRNO(status); + acl_pthread_mutex_unlock(&thr_pool->poller_mutex); + acl_msg_error("%s, %s(%d): pthread_cond_wait," + " serr = %s", __FILE__, myname, __LINE__, + acl_last_serror()); + return (status); + } + } + + acl_debug(ACL_DEBUG_THR_POOL, 3) ("%s: begin to unlock", myname); + + status = acl_pthread_mutex_unlock(&thr_pool->poller_mutex); + if (status != 0) { + __SET_ERRNO(status); + acl_msg_error("%s, %s(%d): pthread_mutex_unlock error(%s)", + __FILE__, myname, __LINE__, acl_last_serror()); + } + + return (status); +} + +static int __wait_worker_exit(acl_pthread_pool_t *thr_pool) +{ + const char *myname = "__wait_worker_exit"; + int status, nwait = 0; + + status = acl_pthread_mutex_lock(&thr_pool->worker_mutex); + if (status != 0) { + __SET_ERRNO(status); + acl_msg_error("%s(%d)->%s: pthread_mutex_lock, serr = %s", + __FILE__, __LINE__, myname, acl_last_serror()); + return (status); + } + + thr_pool->worker_quit = 1; + + if (thr_pool->counter < 0) { + acl_msg_fatal("%s(%d)->%s: counter = %d", + __FILE__, __LINE__, myname, thr_pool->counter); + } else if (thr_pool->counter == 0) { + acl_debug(ACL_DEBUG_THR_POOL, 2) ("%s: debug: counter = 0", myname); + status = acl_pthread_mutex_unlock(&thr_pool->worker_mutex); + return (0); + } + + /* 1. set quit flag + * 2. broadcast to wakeup any sleeping + * 4. wait till all quit + */ + /* then: thr_pool->counter > 0 */ + + if (thr_pool->idle > 0) { + acl_debug(ACL_DEBUG_THR_POOL, 2) ("%s: idle=%d, signal idle thread", + myname, thr_pool->idle); + status = acl_pthread_cond_broadcast(&thr_pool->worker_cond); + if (status != 0) { + __SET_ERRNO(status); + acl_pthread_mutex_unlock(&thr_pool->worker_mutex); + acl_msg_error("%s(%d)->%s: pthread_cond_broadcast," + " serr = %s", __FILE__, __LINE__, myname, + acl_last_serror()); + return (status); + } + } + + while (thr_pool->counter > 0) { + nwait++; + + acl_debug(ACL_DEBUG_THR_POOL, 2) + ("debug(2): counter = %d, nwait=%d, idle=%d", + thr_pool->counter, nwait, thr_pool->idle); + + /* status = pthread_cond_timedwait(&thr_pool->worker_cond, &thr_pool->worker_mutex, &timeout); */ + status = acl_pthread_cond_wait(&thr_pool->worker_cond, &thr_pool->worker_mutex); + if (status == ACL_ETIMEDOUT) { + acl_debug(ACL_DEBUG_THR_POOL, 2) ("%s: timeout nwait=%d", myname, nwait); + } else if (status != 0) { + __SET_ERRNO(status); + acl_pthread_mutex_unlock(&thr_pool->worker_mutex); + acl_msg_error("%s(%d)->%s: pthread_cond_timedwait," + " serr = %s", __FILE__, __LINE__, myname, + acl_last_serror()); + return (status); + } + } + + status = acl_pthread_mutex_unlock(&thr_pool->worker_mutex); + if (status != 0) { + __SET_ERRNO(status); + acl_msg_error("%s(%d)->%s: pthread_mutex_unlock, serr = %s", + __FILE__, __LINE__, myname, acl_last_serror()); + } + + return (status); +} + +int acl_pthread_pool_destroy(acl_pthread_pool_t *thr_pool) +{ + const char *myname = "acl_pthread_pool_destroy"; + int status, s1, s2, s3, s4, s5; + + if (thr_pool == NULL || thr_pool->valid != ACL_PTHREAD_POOL_VALID) { + acl_msg_error("%s(%d)->%s: input invalid", + __FILE__, __LINE__, myname); + return (ACL_EINVAL); + } + + thr_pool->valid = 0; /* prevent any other operations */ + + status = __wait_poller_exit(thr_pool); + if (status != 0) { + __SET_ERRNO(status); + acl_msg_error("%s, %s(%d): wait_poller_exit error(%s), ret=%d", + __FILE__, myname, __LINE__, acl_last_serror(), status); + return (status); + } + + acl_debug(ACL_DEBUG_THR_POOL, 2) + ("%s(%d): poller thread exits ok, worker counter = %d", + myname, __LINE__, thr_pool->counter); + + status = __wait_worker_exit(thr_pool); + if (status != 0) { + __SET_ERRNO(status); + acl_msg_error("%s, %s(%d): wait_worker_exit error(%s), ret=%d", + __FILE__, myname, __LINE__, acl_last_serror(), status); + return (status); + } + + acl_debug(ACL_DEBUG_THR_POOL, 2) + ("%s(%d): worker threads exit ok, conter=%d", + myname, __LINE__, thr_pool->counter); + + sleep(1); + s1 = acl_pthread_mutex_destroy(&thr_pool->poller_mutex); + s2 = acl_pthread_cond_destroy(&thr_pool->poller_cond); + + s3 = acl_pthread_mutex_destroy(&thr_pool->worker_mutex); + s4 = acl_pthread_cond_destroy(&thr_pool->worker_cond); + s5 = acl_pthread_attr_destroy(&thr_pool->attr); + + acl_myfree(thr_pool); + + status = s1 ? s1 : (s2 ? s2 : (s3 ? s3 : (s4 ? s4 : s5))); + + return (status); +} + +int acl_pthread_pool_stop(acl_pthread_pool_t *thr_pool) +{ + const char *myname = "acl_pthread_pool_stop"; + int status; + + if (thr_pool == NULL || thr_pool->valid != ACL_PTHREAD_POOL_VALID) { + acl_msg_error("%s(%d)->%s: input invalid", + __FILE__, __LINE__, myname); + return (ACL_EINVAL); + } + + thr_pool->valid = 0; /* prevent any other operations */ + + status = __wait_poller_exit(thr_pool); + if (status != 0) { + __SET_ERRNO(status); + acl_msg_error("%s, %s(%d): wait_poller_exit error(%s), ret=%d", + __FILE__, myname, __LINE__, acl_last_serror(), status); + return (status); + } + + acl_debug(ACL_DEBUG_THR_POOL, 2) + ("%s(%d): poller thread exits ok, worker counter = %d", + myname, __LINE__, thr_pool->counter); + + status = __wait_worker_exit(thr_pool); + if (status != 0) { + __SET_ERRNO(status); + acl_msg_error("%s, %s(%d): wait_worker_exit error(%s), ret=%d", + __FILE__, myname, __LINE__, acl_last_serror(), status); + return (status); + } + + thr_pool->valid = ACL_PTHREAD_POOL_VALID; /* restore the valid status */ + + acl_debug(ACL_DEBUG_THR_POOL, 2) + ("%s(%d): worker threads exit ok, conter=%d", + myname, __LINE__, thr_pool->counter); + + return (0); +} + +static void __workq_addone(acl_pthread_pool_t *thr_pool, ACL_TASK *item) +{ + const char *myname = "__workq_addone"; + acl_pthread_t id; + int status; + + if (thr_pool->first == NULL) + thr_pool->first = item; + else + thr_pool->last->next = item; + thr_pool->last = item; + + thr_pool->qlen++; + + if (thr_pool->idle > 0) { +#ifdef ACL_MS_WINDOWS + status = acl_pthread_cond_signal(&thr_pool->worker_cond); +#else + status = pthread_cond_broadcast(&thr_pool->worker_cond); +#endif + if ( status != 0 ) { + __SET_ERRNO(status); + acl_msg_error("%s(%d)->%s: pthread_cond_signal, serr = %s", + __FILE__, __LINE__, myname, acl_last_serror()); + return; + } + } else if (thr_pool->counter < thr_pool->parallelism) { + status = acl_pthread_create(&id, &thr_pool->attr, + __worker_thread, (void*) thr_pool); + if (status != 0) { + __SET_ERRNO(status); + acl_msg_fatal("%s(%d)->%s: pthread_create worker, serr = %s", + __FILE__, __LINE__, myname, acl_last_serror()); + } + thr_pool->counter++; + } else if (thr_pool->qlen > 10 * thr_pool->parallelism) { + time_t now = time(NULL); + + if (now - thr_pool->last_warn >= 2) { + thr_pool->last_warn = now; + acl_msg_warn("%s(%d), %s: reached the max_thread = %d" + ", push into the queue now, qlen=%d, idle=%d", + __FILE__, __LINE__, myname, thr_pool->parallelism, + thr_pool->qlen, thr_pool->idle); + } + if (thr_pool->overload_timewait > 0) { + acl_msg_warn("%s(%d), %s: sleep %d seconds", + __FILE__, __LINE__, myname, + thr_pool->overload_timewait); + sleep(thr_pool->overload_timewait); + } + } + + return; +} + +int acl_pthread_pool_add(acl_pthread_pool_t *thr_pool, + void (*run_fn)(void *), void *run_arg) +{ + const char *myname = "acl_pthread_pool_add"; + ACL_TASK *item; + int status; + + if (thr_pool->valid != ACL_PTHREAD_POOL_VALID || run_fn == NULL) + return (ACL_EINVAL); + +#ifndef USE_SLICE + item = (ACL_TASK*) acl_mymalloc(sizeof(ACL_TASK)); + if (item == NULL) + return (ACL_ENOMEM); + + item->worker_fn = run_fn; + item->worker_arg = run_arg; + item->next = NULL; +#endif + + status = acl_pthread_mutex_lock(&thr_pool->worker_mutex); + if (status != 0) { + __SET_ERRNO(status); +#ifndef USE_SLICE + acl_myfree(item); +#endif + acl_msg_fatal("%s(%d)->%s: pthread_mutex_lock, serr = %s", + __FILE__, __LINE__, myname, acl_last_serror()); + } + +#ifdef USE_SLICE + item = (ACL_TASK*) acl_slice_alloc(thr_pool->slice); + if (item == NULL) { + acl_pthread_mutex_unlock(&thr_pool->worker_mutex); + return (ACL_ENOMEM); + } +#endif + + item->worker_fn = run_fn; + item->worker_arg = run_arg; + item->next = NULL; + + __workq_addone(thr_pool, item); + + status = acl_pthread_mutex_unlock(&thr_pool->worker_mutex); + if (status != 0) { + __SET_ERRNO(status); + acl_msg_fatal("%s(%d)->%s: pthread_mutex_unlock error=%s", + __FILE__, __LINE__, myname, acl_last_serror()); + } + + return (0); +} + +void acl_pthread_pool_add_begin(acl_pthread_pool_t *thr_pool) +{ + const char *myname = "acl_pthread_pool_add_begin"; + int status; + + if (thr_pool == NULL) + acl_msg_fatal("%s(%d)->%s: invalid input", + __FILE__, __LINE__, myname); + + if (thr_pool->valid != ACL_PTHREAD_POOL_VALID) + acl_msg_fatal("%s(%d)->%s: invalid thr_pool->valid", + __FILE__, __LINE__, myname); + + status = acl_pthread_mutex_lock(&thr_pool->worker_mutex); + if (status != 0) { + __SET_ERRNO(status); + acl_msg_fatal("%s(%d)->%s: pthread_mutex_lock, serr = %s", + __FILE__, __LINE__, myname, acl_last_serror()); + } +} + +void acl_pthread_pool_add_one(acl_pthread_pool_t *thr_pool, + void (*run_fn)(void *), void *run_arg) +{ + const char *myname = "acl_pthread_pool_add_one"; + ACL_TASK *item; + + if (thr_pool == NULL) + acl_msg_fatal("%s(%d)->%s: invalid input", + __FILE__, __LINE__, myname); + + if (thr_pool->valid != ACL_PTHREAD_POOL_VALID || run_fn == NULL) + acl_msg_fatal("%s(%d)->%s: invalid thr_pool->valid or run_fn", + __FILE__, __LINE__, myname); + + item = (ACL_TASK*) acl_mymalloc(sizeof(ACL_TASK)); + if (item == NULL) + acl_msg_fatal("%s(%d)->%s: can't malloc, error=%s", + __FILE__, __LINE__, myname, acl_last_serror()); + + item->worker_fn = run_fn; + item->worker_arg = run_arg; + item->next = NULL; + + __workq_addone(thr_pool, item); +} + +void acl_pthread_pool_add_end(acl_pthread_pool_t *thr_pool) +{ + const char *myname = "acl_pthread_pool_add_end"; + int status; + + if (thr_pool == NULL) + acl_msg_fatal("%s(%d)->%s: invalid input", + __FILE__, __LINE__, myname); + if (thr_pool->valid != ACL_PTHREAD_POOL_VALID) + acl_msg_fatal("%s(%d)->%s: invalid thr_pool->valid", + __FILE__, __LINE__, myname); + + status = acl_pthread_mutex_unlock(&thr_pool->worker_mutex); + if (status != 0) { + __SET_ERRNO(status); + acl_msg_fatal("%s(%d)->%s: pthread_mutex_unlock, serr = %s", + __FILE__, __LINE__, myname, acl_last_serror()); + } +} + +void acl_pthread_pool_set_poller(acl_pthread_pool_t *thr_pool, + int (*poller_fn)(void *), void *poller_arg) +{ + const char *myname = "acl_pthread_pool_set_poller"; + if (thr_pool == NULL || thr_pool->valid != ACL_PTHREAD_POOL_VALID + || poller_fn == NULL) + { + acl_msg_error("%s(%d)->%s: input invalid", + __FILE__, __LINE__, myname); + return; + } + + thr_pool->poller_fn = poller_fn; + thr_pool->poller_arg = poller_arg; +} + +int acl_pthread_pool_start_poller(acl_pthread_pool_t *thr_pool) +{ + const char *myname = "acl_pthread_pool_start_poller"; + acl_pthread_t id; + int status; + + if (thr_pool == NULL || thr_pool->valid != ACL_PTHREAD_POOL_VALID) { + acl_msg_error("%s(%d)->%s: input invalid", + __FILE__, __LINE__, myname); + return (-1); + } + + if (thr_pool->poller_fn == NULL) { + acl_msg_warn("%s, %s(%d): poller_fn is null, don't need call %s", + __FILE__, myname, __LINE__, myname); + return (-1); + } + + status = acl_pthread_mutex_lock(&thr_pool->poller_mutex); + if (status != 0) { + __SET_ERRNO(status); + acl_msg_error("%s, %s(%d): lock poller_mutex error(%s)", + __FILE__, myname, __LINE__, acl_last_serror()); + return (-1); + } + + if (thr_pool->poller_running) { + acl_msg_error("%s, %s(%d): server is running", + __FILE__, myname, __LINE__); + return (-1); + } + + status = acl_pthread_mutex_unlock(&thr_pool->poller_mutex); + if (status != 0) { + __SET_ERRNO(status); + acl_msg_error("%s, %s(%d): unlock poller_mutex error(%s)", + __FILE__, myname, __LINE__, acl_last_serror()); + return (-1); + } + + __init_workq(thr_pool); + + status = acl_pthread_create(&id, &thr_pool->attr, + __poller_thread, (void*) thr_pool); + if (status != 0) { + __SET_ERRNO(status); + acl_msg_error("%s(%d)->%s: pthread_create poller, serr = %s", + __FILE__, __LINE__, myname, acl_last_serror()); + return (status); + } + + return (0); +} + +int acl_pthread_pool_add_dispatch(void *dispatch_arg, void (*run_fn)(void *), void *run_arg) +{ + const char *myname = "acl_workq_batadd_dispatch"; + acl_pthread_pool_t *thr_pool; + + if (dispatch_arg == NULL || run_fn == NULL) + acl_msg_fatal("%s(%d)->%s: invalid input", + __FILE__, __LINE__, myname); + + thr_pool = (acl_pthread_pool_t *) dispatch_arg; + acl_pthread_pool_add_one(thr_pool, run_fn, run_arg); + + return (0); +} + +int acl_pthread_pool_dispatch(void *dispatch_arg, void (*run_fn)(void *), void *run_arg) +{ + const char *myname = "acl_pthread_pool_dispatch"; + acl_pthread_pool_t *thr_pool; + + if (dispatch_arg == NULL || run_fn == NULL) + acl_msg_fatal("%s(%d)->%s: invalid input", + __FILE__, __LINE__, myname); + + thr_pool = (acl_pthread_pool_t *) dispatch_arg; + + return (acl_pthread_pool_add(thr_pool, run_fn, run_arg)); +} + +int acl_pthread_pool_size(acl_pthread_pool_t *thr_pool) +{ + const char *myname = "acl_pthread_pool_size"; + int status, n; + + status = acl_pthread_mutex_lock(&thr_pool->worker_mutex); + if (status) { + acl_msg_error("%s(%d)->%s: pthread_mutex_lock error(%s)", + __FILE__, __LINE__, myname, strerror(status)); + return (-1); + } + + n = thr_pool->counter; + status = acl_pthread_mutex_unlock(&thr_pool->worker_mutex); + if (status) { + acl_msg_error("%s(%d)->%s: pthread_mutex_unlock error(%s)", + __FILE__, __LINE__, myname, strerror(status)); + return (-1); + } + + return (n); +} + +void acl_pthread_pool_set_stacksize(acl_pthread_pool_t *thr_pool, size_t size) +{ + if (thr_pool && size > 0) + acl_pthread_attr_setstacksize(&thr_pool->attr, size); +} + +void acl_pthread_pool_attr_init(acl_pthread_pool_attr_t *attr) +{ + if (attr) + memset(attr, 0, sizeof(acl_pthread_pool_attr_t)); +} + +void acl_pthread_pool_attr_set_stacksize(acl_pthread_pool_attr_t *attr, size_t size) +{ + if (attr && size > 0) + attr->stack_size = size; +} + +void acl_pthread_pool_attr_set_threads_limit(acl_pthread_pool_attr_t *attr, int threads_limit) +{ + if (attr && threads_limit > 0) + attr->threads_limit = threads_limit; +} + +void acl_pthread_pool_attr_set_idle_timeout(acl_pthread_pool_attr_t *attr, int idle_timeout) +{ + if (attr && idle_timeout > 0) + attr->idle_timeout = idle_timeout; +} diff --git a/lib_acl/src/thread/acl_pthread_rwlock.c b/lib_acl/src/thread/acl_pthread_rwlock.c new file mode 100644 index 000000000..3169b3511 --- /dev/null +++ b/lib_acl/src/thread/acl_pthread_rwlock.c @@ -0,0 +1,337 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#endif + +#ifndef _GNU_SOURCE +# ifdef ACL_HAVE_NO_RWLOCK +# ifdef ACL_UNIX +# include +# endif +# include +# include +# include "stdlib/acl_mymalloc.h" +# include "thread/acl_pthread.h" +# include "thread/acl_pthread_rwlock.h" + +/* maximum number of times a read lock may be obtained */ +# define MAX_READ_LOCKS 65535 + +int acl_pthread_rwlock_destroy (acl_pthread_rwlock_t *rwlock) +{ + int ret; + + if (rwlock == NULL) + ret = EINVAL; + else { + acl_pthread_rwlock_t prwlock; + + prwlock = *rwlock; + + acl_pthread_mutex_destroy(&prwlock->lock); + acl_pthread_cond_destroy(&prwlock->read_signal); + acl_pthread_cond_destroy(&prwlock->write_signal); + acl_myfree(prwlock); + + *rwlock = NULL; + ret = 0; + } + + return(ret); +} + +int acl_pthread_rwlock_init (acl_pthread_rwlock_t *rwlock, const acl_pthread_rwlockattr_t *attr_unsed) +{ + acl_pthread_rwlock_t prwlock; + int ret; + + attr_unsed = attr_unsed; + + /* allocate rwlock object */ + prwlock = (acl_pthread_rwlock_t) + acl_mymalloc(sizeof(struct acl_pthread_rwlock)); + + if (prwlock == NULL) + return(ENOMEM); + + /* initialize the lock */ + if ((ret = acl_pthread_mutex_init(&prwlock->lock, NULL)) != 0) { + acl_myfree(prwlock); + } else { + /* initialize the read condition signal */ + ret = acl_pthread_cond_init(&prwlock->read_signal, NULL); + + if (ret != 0) { + acl_pthread_mutex_destroy(&prwlock->lock); + acl_myfree(prwlock); + } else { + /* initialize the write condition signal */ + ret = acl_pthread_cond_init(&prwlock->write_signal, NULL); + + if (ret != 0) { + acl_pthread_cond_destroy(&prwlock->read_signal); + acl_pthread_mutex_destroy(&prwlock->lock); + acl_myfree(prwlock); + } else { + /* success */ + prwlock->state = 0; + prwlock->blocked_writers = 0; + + *rwlock = prwlock; + } + } + } + + return(ret); +} + +int acl_pthread_rwlock_rdlock (acl_pthread_rwlock_t *rwlock) +{ + acl_pthread_rwlock_t prwlock; + int ret; + + if (rwlock == NULL) + return(EINVAL); + + prwlock = *rwlock; + + /* check for static initialization */ + if (prwlock == NULL) + return(EINVAL); + + /* grab the monitor lock */ + if ((ret = acl_pthread_mutex_lock(&prwlock->lock)) != 0) + return(ret); + + /* give writers priority over readers */ + while (prwlock->blocked_writers || prwlock->state < 0) { + ret = acl_pthread_cond_wait(&prwlock->read_signal, &prwlock->lock); + + if (ret != 0) { + /* can't do a whole lot if this fails */ + acl_pthread_mutex_unlock(&prwlock->lock); + return(ret); + } + } + + /* check lock count */ + if (prwlock->state == MAX_READ_LOCKS) + ret = EAGAIN; + else + ++prwlock->state; /* indicate we are locked for reading */ + + /* + * Something is really wrong if this call fails. Returning + * error won't do because we've already obtained the read + * lock. Decrementing 'state' is no good because we probably + * don't have the monitor lock. + */ + acl_pthread_mutex_unlock(&prwlock->lock); + + return(ret); +} + +int acl_pthread_rwlock_tryrdlock (acl_pthread_rwlock_t *rwlock) +{ + acl_pthread_rwlock_t prwlock; + int ret; + + if (rwlock == NULL) + return(EINVAL); + + prwlock = *rwlock; + + /* check for static initialization */ + if (prwlock == NULL) + return(EINVAL); + + /* grab the monitor lock */ + if ((ret = acl_pthread_mutex_lock(&prwlock->lock)) != 0) + return(ret); + + /* give writers priority over readers */ + if (prwlock->blocked_writers || prwlock->state < 0) + ret = ACL_EWOULDBLOCK; + else if (prwlock->state == MAX_READ_LOCKS) + ret = ACL_EAGAIN; /* too many read locks acquired */ + else + ++prwlock->state; /* indicate we are locked for reading */ + + /* see the comment on this in pthread_rwlock_rdlock */ + acl_pthread_mutex_unlock(&prwlock->lock); + + return(ret); +} + +int acl_pthread_rwlock_trywrlock (acl_pthread_rwlock_t *rwlock) +{ + acl_pthread_rwlock_t prwlock; + int ret; + + if (rwlock == NULL) + return(EINVAL); + + prwlock = *rwlock; + + /* check for static initialization */ + if (prwlock == NULL) + return(EINVAL); + + /* grab the monitor lock */ + if ((ret = acl_pthread_mutex_lock(&prwlock->lock)) != 0) + return(ret); + + if (prwlock->state != 0) + ret = ACL_EWOULDBLOCK; + else + /* indicate we are locked for writing */ + prwlock->state = -1; + + /* see the comment on this in pthread_rwlock_rdlock */ + acl_pthread_mutex_unlock(&prwlock->lock); + + return(ret); +} + +int acl_pthread_rwlock_unlock (acl_pthread_rwlock_t *rwlock) +{ + acl_pthread_rwlock_t prwlock; + int ret; + + if (rwlock == NULL) + return(EINVAL); + + prwlock = *rwlock; + + /* check for static initialization */ + if (prwlock == NULL) + return(EINVAL); + + /* grab the monitor lock */ + if ((ret = acl_pthread_mutex_lock(&prwlock->lock)) != 0) + return(ret); + + if (prwlock->state > 0) { + if (--prwlock->state == 0 && prwlock->blocked_writers) + ret = acl_pthread_cond_signal(&prwlock->write_signal); + } else if (prwlock->state < 0) { + prwlock->state = 0; + + if (prwlock->blocked_writers) + ret = acl_pthread_cond_signal(&prwlock->write_signal); + else + ret = acl_pthread_cond_broadcast(&prwlock->read_signal); + } else + ret = EINVAL; + + /* see the comment on this in pthread_rwlock_rdlock */ + acl_pthread_mutex_unlock(&prwlock->lock); + + return(ret); +} + +int acl_pthread_rwlock_wrlock (acl_pthread_rwlock_t *rwlock) +{ + acl_pthread_rwlock_t prwlock; + int ret; + + if (rwlock == NULL) + return(EINVAL); + + prwlock = *rwlock; + + /* check for static initialization */ + if (prwlock == NULL) + return(EINVAL); + + /* grab the monitor lock */ + if ((ret = acl_pthread_mutex_lock(&prwlock->lock)) != 0) + return(ret); + + while (prwlock->state != 0) { + ++prwlock->blocked_writers; + + ret = acl_pthread_cond_wait(&prwlock->write_signal, &prwlock->lock); + + if (ret != 0) { + --prwlock->blocked_writers; + acl_pthread_mutex_unlock(&prwlock->lock); + return(ret); + } + + --prwlock->blocked_writers; + } + + /* indicate we are locked for writing */ + prwlock->state = -1; + + /* see the comment on this in pthread_rwlock_rdlock */ + acl_pthread_mutex_unlock(&prwlock->lock); + + return(ret); +} + +int acl_pthread_rwlockattr_destroy(acl_pthread_rwlockattr_t *rwlockattr) +{ + acl_pthread_rwlockattr_t prwlockattr; + + if (rwlockattr == NULL) + return(EINVAL); + + prwlockattr = *rwlockattr; + + /* check for static initialization */ + if (prwlockattr == NULL) + return(EINVAL); + + acl_myfree(prwlockattr); + + return(0); +} + +int acl_pthread_rwlockattr_getpshared(const acl_pthread_rwlockattr_t *rwlockattr, + int *pshared) +{ + *pshared = (*rwlockattr)->pshared; + + return(0); +} + +int acl_pthread_rwlockattr_init(acl_pthread_rwlockattr_t *rwlockattr) +{ + acl_pthread_rwlockattr_t prwlockattr; + + if (rwlockattr == NULL) + return(EINVAL); + + prwlockattr = (acl_pthread_rwlockattr_t) + acl_mymalloc(sizeof(struct acl_pthread_rwlockattr)); + + if (prwlockattr == NULL) + return(ENOMEM); + + prwlockattr->pshared = ACL_PTHREAD_PROCESS_PRIVATE; + *rwlockattr = prwlockattr; + + return(0); +} + +int acl_pthread_rwlockattr_setpshared(acl_pthread_rwlockattr_t *rwlockattr, int pshared) +{ + /* Only PTHREAD_PROCESS_PRIVATE is supported. */ + if (pshared != ACL_PTHREAD_PROCESS_PRIVATE) + return(EINVAL); + + (*rwlockattr)->pshared = pshared; + + return(0); +} + +# endif /* ACL_HAVE_NO_RWLOCK */ +#endif /* _GNU_SOURCE */ diff --git a/lib_acl/src/thread/acl_sem.c b/lib_acl/src/thread/acl_sem.c new file mode 100644 index 000000000..d67ffe06a --- /dev/null +++ b/lib_acl/src/thread/acl_sem.c @@ -0,0 +1,152 @@ +/* Semaphore functions using the Win32 API */ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_msg.h" + +#endif + +#ifdef ACL_MS_WINDOWS + +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "thread/acl_pthread.h" +#include "thread/acl_sem.h" + +/* Create a semaphore */ +ACL_SEM *acl_sem_create2(const char *pathname, unsigned int initial_value) +{ + char myname[] = "acl_sem_create2"; + ACL_SEM *sem; + char buf[256]; + + /* Allocate sem memory */ + sem = (ACL_SEM *) acl_mymalloc(sizeof(*sem)); + if (sem == NULL) { + acl_msg_error("%s, %s(%d): malloc error(%s)", + __FILE__, myname, __LINE__, acl_last_strerror(buf, sizeof(buf))); + return (NULL); + } + /* Create the semaphore, with max value 32K */ + sem->id = CreateSemaphore(NULL, initial_value, 32 * 1024, pathname); + sem->count = initial_value; + if (!sem->id) { + acl_msg_error("%s, %s(%d): Couldn't create semaphore(%s)", + __FILE__, myname, __LINE__, acl_last_strerror(buf, sizeof(buf))); + acl_myfree(sem); + return (NULL); + } + + return(sem); +} + +ACL_SEM *acl_sem_create(unsigned int initial_value) +{ + return (acl_sem_create2(NULL, initial_value)); +} + +/* Free the semaphore */ +void acl_sem_destroy(ACL_SEM *sem) +{ + if (sem) { + if (sem->id) { + CloseHandle(sem->id); + sem->id = 0; + } + acl_myfree(sem); + } +} + +int acl_sem_wait_timeout(ACL_SEM *sem, unsigned int timeout) +{ + char myname[] = "acl_sem_wait_timeout"; + int retval; + DWORD dwMilliseconds; + char buf[256]; + + if (sem == NULL) { + acl_msg_error("%s, %s(%d): input invalid", + __FILE__, myname, __LINE__); + return (-1); + } + + if (timeout == ACL_MUTEX_MAXWAIT) { + dwMilliseconds = INFINITE; + } else { + dwMilliseconds = (DWORD) timeout; + } + + switch (WaitForSingleObject(sem->id, dwMilliseconds)) { + case WAIT_OBJECT_0: + --sem->count; + retval = 0; + break; + case WAIT_TIMEOUT: + retval = ACL_ETIMEDOUT; + break; + default: + acl_msg_error("%s, %s(%d): WaitForSingleObject() failed", + __FILE__, myname, __LINE__, acl_last_strerror(buf, sizeof(buf))); + retval = -1; + break; + } + return retval; +} + +int acl_sem_try_wait(ACL_SEM *sem) +{ + return acl_sem_wait_timeout(sem, 0); +} + +int acl_sem_wait(ACL_SEM *sem) +{ + return acl_sem_wait_timeout(sem, ACL_MUTEX_MAXWAIT); +} + +/* Returns the current count of the semaphore */ +unsigned int acl_sem_value(ACL_SEM *sem) +{ + char myname[] = "acl_sem_value"; + + if (sem == NULL) { + acl_msg_error("%s, %s(%d): input invalid", + __FILE__, myname, __LINE__); + return (0); + } + return sem->count; +} + +int acl_sem_post(ACL_SEM *sem) +{ + char myname[] = "acl_sem_post"; + + if (sem == NULL) { + acl_msg_error("%s, %s(%d): input invalid", + __FILE__, myname, __LINE__); + return (-1); + } + /* Increase the counter in the first place, because + * after a successful release the semaphore may + * immediately get destroyed by another thread which + * is waiting for this semaphore. + */ + ++sem->count; + + if (ReleaseSemaphore(sem->id, 1, NULL) == FALSE) { + char buf[256]; + + --sem->count; /* restore */ + acl_msg_error("%s, %s(%d): ReleaseSemaphore() failed", + __FILE__, myname, __LINE__, acl_last_strerror(buf, sizeof(buf))); + return -1; + } + return 0; +} + +#endif /* ACL_MS_WINDOWS */ diff --git a/lib_acl/src/unit_test/acl_test_cfg.c b/lib_acl/src/unit_test/acl_test_cfg.c new file mode 100644 index 000000000..ed50d11df --- /dev/null +++ b/lib_acl/src/unit_test/acl_test_cfg.c @@ -0,0 +1,249 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +/** + * + * System Library. + * + */ +#include +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +/** + * + * Util Library. + * + */ +#include "stdlib/acl_msg.h" +#include "stdlib/acl_mystring.h" +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_loadcfg.h" +#include "stdlib/acl_array.h" + +/** + * + * Application Specific. + * + */ +#include "unit_test/acl_unit_test.h" + +#endif + +/* 局部变量 */ + +/* 容纳所有有效配置行的动态数组指针 */ +ACL_ARRAY *var_aut_line_array = NULL; + +int var_aut_valid_line_idx = 0; + +int var_aut_log_level = 0; + +/*--------------------------------------------------------------------------*/ +/* 分析配置文件中的第四个参数, 将其进行分解并存入动态数组之中 */ +ACL_ARRAY *aut_parse_args_list(const char *str_in) +{ + char myname[] = "aut_parse_args_list"; + ACL_ARRAY *argvs_array = NULL; + AUT_ARG_ITEM *arg_item = NULL; + char *ptr_item, *pstr, *pstr_saved, *pname, *pvalue; + char *ptr; + int len; + char tbuf[256]; + + argvs_array = acl_array_create(10); + pstr = acl_mystrdup(str_in); + pstr_saved = pstr; + +#define SKIP_WHILE(_cond, _ptr) { while (*_ptr && (_cond)) _ptr++; } +#define SKIP_WHILE_DEC(_cond, _ptr) { while (*_ptr && (_cond)) _ptr--; } + + len = strlen("="); + while (1) { + /* 找到每一参数项, 分隔符为逗号 */ + ptr_item = acl_mystrtok(&pstr, ","); + if (ptr_item == NULL) + break; + + /* 删除变量名前的空格和 tab */ + SKIP_WHILE((*ptr_item == ' ' || *ptr_item == '\t'), ptr_item); + pname = ptr_item; + + /* 先找到等于号分隔符 */ + pvalue = strstr(ptr_item, "="); + if (pvalue == NULL) /* not found '=' */ + continue; + + ptr = pvalue; + + /* 删除等号左边的空格或 tab */ + SKIP_WHILE_DEC((*ptr == ' ' || *ptr == '\t'), ptr); + if (ptr < pvalue) + *(++ptr) = 0; + + *pvalue = 0; + pvalue += len; /* skip '=' */ + + /* 删除等号右边的空格和ab */ + SKIP_WHILE((*pvalue == ' ' || *pvalue == '\t'), pvalue); + if (*pvalue == 0) + continue; + + /* 分配一个参数项 */ + arg_item = (AUT_ARG_ITEM *) acl_mycalloc(1, sizeof(AUT_ARG_ITEM)); + arg_item->name = acl_mystrdup(pname); + arg_item->value = acl_mystrdup(pvalue); + + /* 把该参数项加入到动态数组之中 */ + if (acl_array_append(argvs_array, (void *) arg_item) < 0) + aut_log_fatal("%s(%d): append to array error(%s)", + myname, __LINE__, acl_last_strerror(tbuf, sizeof(tbuf))); + } + + acl_myfree(pstr_saved); + + return (argvs_array); +} + +static void free_arg_item(void* arg) +{ + AUT_ARG_ITEM *item = (AUT_ARG_ITEM*) arg; + acl_myfree(item->name); + acl_myfree(item->value); + acl_myfree(item); +} + +void aut_free_args_list(ACL_ARRAY *a) +{ + if (a == NULL) + return; + acl_array_free(a, free_arg_item); +} + +/*------------------------- 所有的有效配置行入口 ---------------------------*/ + +static void __parse_cfg_line(const ACL_CFG_LINE *line) +{ +/* + * 命令函数名称|预测结果[0:表示成功, 1:表示失败]|参数个数|参数列表[name=参数1, name=参数2...] + * test_line->value[0]: 命令函数名称 + * test_line->value[1]: 预测结果 + * test_line->value[2]: 参数个数 + * test_line->value[3]: 参数列表 + * 说明: 要求前 3 个参数必须有, 后一个参数可选 + */ + + /* 优先查找内部定义的有效配置选项 */ + if (aut_cfg_add_general_line(line) == 0) + return; + + /* 再查找是否是内部命令选项 */ + if (aut_add_inner_cmd(line)) + return; + + /* 和应用相关的命令选项的处理 */ + (void) aut_add_outer_cmd(line); +} + +/* 初始化 */ +static void __init(void) +{ + char myname[] = "__init"; + + if (var_aut_line_array != NULL) + return; + + var_aut_line_array = acl_array_create(10); + if (var_aut_line_array == NULL) { + char tbuf[256]; + aut_log_fatal("%s: acl_array_create error(%s)", + myname, acl_last_strerror(tbuf, sizeof(tbuf))); + } + var_aut_valid_line_idx = 0; +} + +/* 将配置文件读入内存并进行分解 */ +int aut_cfg_parse(const char *pathname) +{ + char myname[] = "aut_cfg_parse"; + ACL_CFG_PARSER *cfg_parser; + ACL_CFG_LINE *cfg_line; + int i, n; + + if (pathname == NULL || *pathname == 0) { + aut_log_error("%s: invalid configure name", myname); + return (-1); + } + + __init(); + + cfg_parser = acl_cfg_parser_load(pathname, "|"); + + if (cfg_parser == NULL) { + char tbuf[256]; + aut_log_fatal("%s: open cfg_file(%s) error(%s)", + myname, pathname, acl_last_strerror(tbuf, sizeof(tbuf))); + } + + n = acl_cfg_parser_size(cfg_parser); + for (i = 0; i < n; i++) { + cfg_line = (ACL_CFG_LINE *) acl_cfg_parser_index(cfg_parser, i); + if (cfg_line == NULL) + break; + if (cfg_line->ncount == 0) + continue; + __parse_cfg_line(cfg_line); + } + + acl_cfg_parser_free(cfg_parser); + + return (0); +} + +/*--------------------------------------------------------------------------*/ +/* 打印输出配置文件中的有效配置行 */ +int aut_cfg_print(void) +{ + char myname[] = "aut_cfg_print"; + AUT_LINE *line = NULL; + AUT_ARG_ITEM *arg; + int i, j, n, m, first_line_arg; + + if (var_aut_line_array == NULL) { + printf("%s: var_aut_line_array=NULL\n", myname); + return (-1); + } + + n = acl_array_size(var_aut_line_array); + + for (i = 0; i < n; i++) { + line = (AUT_LINE *) acl_array_index(var_aut_line_array, i); + if (line == NULL) + break; + printf("%s|%d|%d|", line->cmd_name, line->result, line->argc); + + m = acl_array_size(line->argv); + first_line_arg = 1; + for (j = 0; j < m; j++) { + arg = (AUT_ARG_ITEM *) acl_array_index(line->argv, j); + if (arg == NULL) + break; + + /* 判断是否是第一个参数项 */ + if (first_line_arg) { + printf("%s=%s", arg->name, arg->value); + first_line_arg = 0; + } else { + printf(",%s=%s", arg->name, arg->value); + } + } + printf("\n"); + } + + return (0); +} diff --git a/lib_acl/src/unit_test/acl_test_cfg_general.c b/lib_acl/src/unit_test/acl_test_cfg_general.c new file mode 100644 index 000000000..fea0a6387 --- /dev/null +++ b/lib_acl/src/unit_test/acl_test_cfg_general.c @@ -0,0 +1,64 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_loadcfg.h" +#include "stdlib/acl_array.h" +#include "stdlib/acl_mystring.h" +#include "unit_test/acl_unit_test.h" + +#endif + +/*------------------------ 通常的配置文件选项处理 --------------------------*/ + +static int __put_log_level(const ACL_CFG_LINE *cfg_line) +{ + char myname[] = "__put_log_level"; + + if (cfg_line->ncount < 2) { + aut_log_error("%s: ncount=%d", myname, cfg_line->ncount); + return (-1); + } + + var_aut_log_level = 0; + if (strcasecmp(cfg_line->value[1], "print") == 0) + var_aut_log_level |= VAR_AUT_LOG_PRINT; + if (strcasecmp(cfg_line->value[1], "fprint") == 0) + var_aut_log_level |= VAR_AUT_LOG_FPRINT; + + if (strcasecmp(cfg_line->value[1], "print:fprint") == 0) + var_aut_log_level |= VAR_AUT_LOG_PRINT | VAR_AUT_LOG_FPRINT; + return (0); +} + +/*----------------------------------------------------------------------------*/ +static ACL_CFG_FN __general_cfg_tab[] = { + { VAR_AUT_LOG, __put_log_level }, + { NULL, NULL }, +}; + +int aut_cfg_add_general_line(const ACL_CFG_LINE *line) +{ + char myname[] = "aut_cfg_add_general_line"; + int i; + + if (line->ncount < 1) + aut_log_fatal("%s: ncount=%d", myname, line->ncount); + + for (i = 0; __general_cfg_tab[i].name != NULL; i++) { + if (strcasecmp(line->value[0], __general_cfg_tab[i].name) == 0) { + (void) __general_cfg_tab[i].func(line); + + return (0); + } + } + + return (-1); +} + diff --git a/lib_acl/src/unit_test/acl_test_inner.c b/lib_acl/src/unit_test/acl_test_inner.c new file mode 100644 index 000000000..262652967 --- /dev/null +++ b/lib_acl/src/unit_test/acl_test_inner.c @@ -0,0 +1,182 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_msg.h" +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_mystring.h" +#include "stdlib/acl_array.h" +#include "unit_test/acl_unit_test.h" + +#endif + +static int __if_nested_count = 0; +static int __if_count = 0; +/* static int _else_count = 0; */ +/* static int _elif_count = 0; */ +static int __endif_count = 0; + +/*----------------------------------------------------------------------------*/ +static AUT_LINE *__mkcmd_if(const ACL_CFG_LINE *line) +{ + AUT_LINE *test_line; + AUT_CMD_TOKEN *if_token = NULL; + + __if_nested_count++; + + if_token = (AUT_CMD_TOKEN *) acl_mycalloc(1, sizeof(*if_token)); + if_token->flag = AUT_FLAG_IF; + if_token->match_number = ++__if_count; + if_token->peer = NULL; + + test_line = aut_line_new(line); + + test_line->arg_inner = (void *) if_token; + test_line->free_arg_inner = acl_myfree_fn; + + return (test_line); +} + +static AUT_LINE *__mkcmd_endif(const ACL_CFG_LINE *line) +{ + char myname[] = "__mkcmd_endif"; + AUT_LINE *test_line, *test_line_peer; + AUT_CMD_TOKEN *if_token = NULL, *if_token_peer; + int n, i; + + __if_nested_count--; + if_token = (AUT_CMD_TOKEN *) acl_mycalloc(1, sizeof(*if_token)); + if_token->flag = AUT_FLAG_ENDIF; + if_token->match_number = ++__endif_count; + if_token->peer = NULL; + + test_line = aut_line_new(line); + + test_line->arg_inner = (void *) if_token; + test_line->free_arg_inner = acl_myfree_fn; + + n = acl_array_size(var_aut_line_array); + for (i = 0; i < n; i++) { + test_line_peer = (AUT_LINE *) acl_array_index(var_aut_line_array, i); + if (test_line_peer->arg_inner == NULL) + continue; + if_token_peer = (AUT_CMD_TOKEN *) test_line_peer->arg_inner; + if (if_token_peer->flag != AUT_FLAG_IF) + continue; + + if (if_token_peer->match_number != if_token->match_number) + continue; + + /* 找到匹配的循环开始对等结点 */ + if_token_peer->peer = test_line; + if_token->peer = test_line_peer; + } + + if (if_token->peer == NULL) { + aut_log_fatal("%s: line_number=%d, cmd=%s, " + "if_nested=%d, if_count=%d, " + "endif_count=%d, please check configure, " + "err_msg=not found peer loop begin", + myname, test_line->line_number, + test_line->cmd_name, __if_nested_count, + __if_count, __endif_count); + } + + return (test_line); +} + +static AUT_LINE *__mkcmd_stop(const ACL_CFG_LINE *line) +{ + AUT_LINE *test_line; + AUT_CMD_TOKEN *inner_token = NULL; + + test_line = aut_line_new(line); + + snprintf(test_line->cmd_name, sizeof(test_line->cmd_name), + "%s", line->value[0]); + inner_token = (AUT_CMD_TOKEN *) acl_mycalloc(1, sizeof(*inner_token)); + inner_token->flag = AUT_FLAG_STOP; + + test_line->arg_inner = (void *) inner_token; + test_line->free_arg_inner = acl_myfree_fn; + + return (test_line); +} + +/*---------------------------- 分析与内部命令相匹配的配置行 ---------------- */ +/* 内部保留的命令项数据结构定义 */ +typedef struct { + const char *cmd_name; + AUT_LINE *(*match_fn)(const ACL_CFG_LINE *line); +} __MATCH_CMD; + +/* 内部保留的命令对象表 */ +static __MATCH_CMD __inner_cmd_tab[] = { + { VAR_AUT_LOOP_BEGIN, aut_loop_make_begin }, + { VAR_AUT_LOOP_BREAK, aut_loop_make_break }, + { VAR_AUT_LOOP_END, aut_loop_make_end }, + { VAR_AUT_IF, __mkcmd_if }, + { VAR_AUT_ENDIF, __mkcmd_endif }, + { VAR_AUT_STOP, __mkcmd_stop }, + { NULL, NULL }, +}; + +/* 从内部命令表中取得相应的对象 */ + +AUT_LINE *aut_add_inner_cmd(const ACL_CFG_LINE *line) +{ + char myname[] = "aut_add_inner_cmd"; + AUT_LINE *test_line = NULL; + __MATCH_CMD *pmatch_cmd; + AUT_CMD_TOKEN *inner_token; + int i; + + if (line->ncount < 1) { + aut_log_error("%s: ncount=%d", myname, line->ncount); + return (NULL); + } + + for (i = 0; __inner_cmd_tab[i].cmd_name != NULL; i++) { + pmatch_cmd = &__inner_cmd_tab[i]; + if (strcasecmp(line->value[0], pmatch_cmd->cmd_name) == 0) { + /* 由内部命令保留函数动态分配一个相对应的 + * AUT_LINE 对象 + */ + test_line = pmatch_cmd->match_fn(line); + break; + } + } + + if (test_line == NULL) + return (NULL); + + if (acl_array_append(var_aut_line_array, (void *) test_line) < 0) { + char tbuf[256]; + aut_log_fatal("%s: cmd_name=%s, " + "acl_array_append error, err_msg=%s", + myname, test_line->cmd_name, acl_last_strerror(tbuf, sizeof(tbuf))); + } + + /* 设置有效行号 */ + inner_token = (AUT_CMD_TOKEN *) test_line->arg_inner; + if (inner_token == NULL) + return (test_line); + + test_line->valid_line_idx = var_aut_valid_line_idx++; + + /* 调整有效行号 */ + inner_token->valid_line_idx = test_line->valid_line_idx; + + /* 只对循环命令起作用, 设置相对命令位移 */ + inner_token->offset_valid_line_idx = inner_token->valid_line_idx; + + return (test_line); +} diff --git a/lib_acl/src/unit_test/acl_test_log.c b/lib_acl/src/unit_test/acl_test_log.c new file mode 100644 index 000000000..c86c6089c --- /dev/null +++ b/lib_acl/src/unit_test/acl_test_log.c @@ -0,0 +1,119 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +/** + * + * System Library. + * + */ +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +/** + * + * Util Library. + * + */ +#include "stdlib/acl_msg.h" + +/** + * + * Application Specific. + * + */ +#include "unit_test/acl_unit_test.h" + +#endif + +static char __log_pre[] = "unit_test"; + +int aut_log_open(const char *pathname) +{ + const char *myname = "aut_log_open"; + + if (pathname == NULL || *pathname == 0) { + printf("%s: invalid log_file name\n", myname); + return (-1); + } + + acl_msg_open(pathname, __log_pre); + return (0); +} + +void aut_log_info(const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + + if ((var_aut_log_level & VAR_AUT_LOG_PRINT) != 0) { + vprintf(format, ap); + printf("\n"); + } + if ((var_aut_log_level & VAR_AUT_LOG_FPRINT) != 0) + acl_msg_info2(format, ap); + + va_end(ap); +} + +void aut_log_warn(const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + if ((var_aut_log_level & VAR_AUT_LOG_PRINT) != 0) { + vprintf(format, ap); + printf("\n"); + } + if ((var_aut_log_level & VAR_AUT_LOG_FPRINT) != 0) + acl_msg_warn2(format, ap); + va_end(ap); +} + +void aut_log_error(const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + if ((var_aut_log_level & VAR_AUT_LOG_PRINT) != 0) { + vprintf(format, ap); + printf("\n"); + } + if ((var_aut_log_level & VAR_AUT_LOG_FPRINT) != 0) + acl_msg_error2(format, ap); + va_end(ap); +} + +void aut_log_fatal(const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + if ((var_aut_log_level & VAR_AUT_LOG_PRINT) != 0) { + vprintf(format, ap); + printf("\n"); + acl_assert(0); + } + + acl_msg_fatal2(format, ap); + va_end(ap); +} + +void aut_log_panic(const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + if ((var_aut_log_level & VAR_AUT_LOG_PRINT) != 0) { + vprintf(format, ap); + printf("\n"); + acl_assert(0); + } + acl_msg_panic2(format, ap); + va_end(ap); +} diff --git a/lib_acl/src/unit_test/acl_test_loop.c b/lib_acl/src/unit_test/acl_test_loop.c new file mode 100644 index 000000000..808b9db0e --- /dev/null +++ b/lib_acl/src/unit_test/acl_test_loop.c @@ -0,0 +1,281 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_mymalloc.h" +#include "unit_test/acl_unit_test.h" + +#endif + +static int __loop_nested_count = 0; +static int __loop_begin_count = 0; +static int __loop_end_count = 0; + +AUT_LINE *aut_loop_make_begin(const ACL_CFG_LINE *cfg_line) +{ + AUT_LINE *test_line; + AUT_CMD_TOKEN *loop_token = NULL; + const char *ptr; + + /* 记数器, 对 loop_begin 标记记数加 1 */ + __loop_begin_count++; + + /* 循环对嵌套加 1 */ + __loop_nested_count++; + + loop_token = (AUT_CMD_TOKEN *) acl_mycalloc(1, sizeof(*loop_token)); + loop_token->flag = AUT_FLAG_LOOP_BEGIN; + loop_token->status = AUT_STAT_FREE; + loop_token->match_number = __loop_nested_count; + loop_token->nloop_cur = 0; + loop_token->nloop_max = 0; + loop_token->nloop_cur = 0; + loop_token->peer = NULL; + + test_line = aut_line_new(cfg_line); + test_line->obj_type = AUT_OBJ_INNER; + + /* 将 loop_token 作为内部参数存储在 test_line->arg_inner 中 */ + test_line->arg_inner = (void *) loop_token; + test_line->free_arg_inner = acl_myfree_fn; + + if (cfg_line->ncount < 2) { + loop_token->nloop_max = 0; + return (test_line); + } + + /* 分析配置行参数 */ + test_line->argv = aut_parse_args_list(cfg_line->value[1]); + + /* 从配置文件中取出要循环的次数 */ + ptr = aut_line_getvalue(test_line, VAR_AUT_ITEM_COUNT); + if (ptr != NULL) + loop_token->nloop_max = atoi(ptr); + + if (loop_token->nloop_max < 0) + loop_token->nloop_max = 0; + + return (test_line); +} + +AUT_LINE *aut_loop_make_break(const ACL_CFG_LINE *cfg_line) +{ + char myname[] = "aut_loop_make_break"; + AUT_LINE *break_line, *tmp_line, *begin_line; + AUT_CMD_TOKEN *break_token, *tmp_token, *begin_token; + int i, n; + + break_line = aut_line_new(cfg_line); + break_line->obj_type = AUT_OBJ_INNER; + + break_token = (AUT_CMD_TOKEN *) acl_mycalloc(1, sizeof(AUT_CMD_TOKEN)); + break_token->flag = AUT_FLAG_LOOP_BREAK; + + /* 将 breaktoken 作为内部参数存储在 break_line->arg_inner 中 */ + break_line->arg_inner = (void *) break_token; + break_line->free_arg_inner = acl_myfree_fn; + + n = acl_array_size(var_aut_line_array); + + begin_line = NULL; + begin_token = NULL; + + for (i = n - 1; i >= 0; i--) { + tmp_line = (AUT_LINE *) acl_array_index(var_aut_line_array, i); + if (tmp_line == NULL) + aut_log_fatal("%s(%d): loop_begin null", myname, __LINE__); + if (tmp_line->obj_type != AUT_OBJ_INNER) + continue; + if (tmp_line->arg_inner == NULL) + continue; + tmp_token = (AUT_CMD_TOKEN *) tmp_line->arg_inner; + if (tmp_token->flag != AUT_FLAG_LOOP_BEGIN) + continue; + begin_line = tmp_line; + begin_token = tmp_token; + break; + } + + if (begin_line == NULL || begin_token == NULL) + aut_log_fatal("%s(%d): no LOOP_BEGIN before LOOP_BREAK", + myname, __LINE__); + break_token->peer = begin_line; + + return (break_line); +} + +AUT_LINE *aut_loop_make_end(const ACL_CFG_LINE *cfg_line) +{ + char myname[] = "aut_loop_make_end"; + AUT_LINE *test_line, *test_line_peer; + AUT_CMD_TOKEN *loop_token = NULL, *loop_token_peer; + int n, i; + + /* 记数器, 对 loop_end 标记记数减 1 */ + __loop_end_count++; + + loop_token = (AUT_CMD_TOKEN *) acl_mycalloc(1, sizeof(*loop_token)); + loop_token->flag = AUT_FLAG_LOOP_END; + loop_token->status = AUT_STAT_BUSY; + + /* 与前面的 loop_begin 相匹配 */ + loop_token->match_number = __loop_nested_count; + loop_token->peer = NULL; + + /* 循环对嵌套减 1 */ + __loop_nested_count--; + + test_line = aut_line_new(cfg_line); + test_line->obj_type = AUT_OBJ_INNER; + + /* 将 loop_token 作为内部参数存储在 test_line->arg_inner 中 */ + test_line->arg_inner = (void *) loop_token; + test_line->free_arg_inner = acl_myfree_fn; + + n = acl_array_size(var_aut_line_array); + + /* 查找与循环结束标志相配对的循环开始对象 */ + + for (i = 0; i < n; i++) { + test_line_peer = (AUT_LINE *) + acl_array_index(var_aut_line_array, i); + + /* xxx: 不应该发生此种情况, 除非动态数组出了故障 */ + if (test_line_peer == NULL) + break; + + /* 先判断是否是内部对象 */ + if (test_line_peer->obj_type != AUT_OBJ_INNER) + continue; + + /* 先查看是否有内部数据参数存储在 test_line_peer 中 */ + if (test_line_peer->arg_inner == NULL) + continue; + + loop_token_peer = (AUT_CMD_TOKEN *) test_line_peer->arg_inner; + + /* 看该 loopbegin 对象是否已经被 一个 loopend 对象给匹配了 */ + if (loop_token_peer->status == AUT_STAT_BUSY) + continue; + + /* 是否是 循环开始标志, 以判断是否是一个循环的开始 */ + if (loop_token_peer->flag != AUT_FLAG_LOOP_BEGIN) + continue; + + /* 比较匹配行号是否相等 */ + if (loop_token_peer->match_number != loop_token->match_number) + continue; + + /* 找到匹配的循环开始对等结点 */ + loop_token_peer->peer = test_line; + loop_token_peer->status = AUT_STAT_BUSY; + loop_token->peer = test_line_peer; + } + + if (loop_token->peer == NULL) { + aut_log_fatal("%s(%d)->%s: line_number=%d, cmd=%s, " + "loop_nested=%d, loop_begin=%d, " + "loop_end=%d, please check configure, " + "err_msg=not found peer loop begin", + __FILE__, __LINE__, myname, + test_line->line_number, + test_line->cmd_name, __loop_nested_count, + __loop_begin_count, __loop_end_count); + } + + return (test_line); +} + +/*-------------------------- 与命令循环相关的函数接口 ----------------------*/ +const AUT_LINE *aut_loop_end(const AUT_LINE *test_begin) +{ + if (test_begin == NULL) + return (NULL); + return (aut_line_peer(test_begin)); +} + +int aut_loop_count(const AUT_LINE *test_line) +{ + AUT_CMD_TOKEN *token; + + if (test_line == NULL || test_line->arg_inner == NULL) + return (-1); + + token = (AUT_CMD_TOKEN *) test_line->arg_inner; + if (token->flag == AUT_FLAG_LOOP_BEGIN) + return (token->nloop_max); + else if (token->flag == AUT_FLAG_LOOP_END) { + token = aut_line_peer_token(test_line); + if (token == NULL) + return (-1); + if (token->flag == AUT_FLAG_LOOP_BEGIN) + return (token->nloop_max); + } + + return (-1); +} + +int aut_loop_from(const AUT_LINE *test_line) +{ + AUT_CMD_TOKEN *token; + const AUT_LINE *test_begin; + int ret; + + if (test_line == NULL || test_line->arg_inner == NULL) + return (-1); + + token = (AUT_CMD_TOKEN *) test_line->arg_inner; + if (token->flag == AUT_FLAG_LOOP_BEGIN) + test_begin = test_line; + else if (token->flag == AUT_FLAG_LOOP_END) + test_begin = aut_line_peer(test_line); + else + return (-1); + + if (test_begin == NULL || test_begin->arg_inner == NULL) + return (-1); + + token = (AUT_CMD_TOKEN *) test_begin->arg_inner; + if (token->flag != AUT_FLAG_LOOP_BEGIN) + return (-1); + + ret = aut_line_valid_linenum(test_begin); + if (ret < 0) + return (-1); + return (ret + 1); +} + +int aut_loop_to(const AUT_LINE *test_line) +{ + AUT_CMD_TOKEN *token; + const AUT_LINE *test_end; + + if (test_line == NULL || test_line->arg_inner == NULL) + return (-1); + + token = (AUT_CMD_TOKEN *) test_line->arg_inner; + if (token->flag == AUT_FLAG_LOOP_END) + test_end = test_line; + else if (token->flag == AUT_FLAG_LOOP_BEGIN) + test_end = aut_line_peer(test_line); + else + return (-1); + + if (test_end == NULL || test_end->arg_inner == NULL) + return (-1); + + token = (AUT_CMD_TOKEN *) test_end->arg_inner; + if (token->flag != AUT_FLAG_LOOP_END) + return (-1); + + return (aut_line_valid_linenum(test_end)); +} + diff --git a/lib_acl/src/unit_test/acl_test_misc.c b/lib_acl/src/unit_test/acl_test_misc.c new file mode 100644 index 000000000..82859c11d --- /dev/null +++ b/lib_acl/src/unit_test/acl_test_misc.c @@ -0,0 +1,326 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_msg.h" +#include "stdlib/acl_array.h" +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_mystring.h" +#include "unit_test/acl_unit_test.h" + +#endif + +AUT_LINE *aut_line_new(const ACL_CFG_LINE *cfg_line) +{ + AUT_LINE *test_line = NULL; + + test_line = (AUT_LINE *) acl_mycalloc(1, sizeof(AUT_LINE)); + test_line->line_number = cfg_line->line_number; + snprintf(test_line->cmd_name, sizeof(test_line->cmd_name), + "%s", cfg_line->value[0]); + test_line->obj_type = AUT_OBJ_OUTER; + + return (test_line); +} + +void aut_line_free(void *ctx) +{ + AUT_LINE *test_line = (AUT_LINE*) ctx; + + if (test_line->args_str) + acl_myfree(test_line->args_str); + if (test_line->argv) + aut_free_args_list(test_line->argv); + if (test_line->arg_inner && test_line->free_arg_inner) + test_line->free_arg_inner(test_line->arg_inner); + + acl_myfree(test_line); +} + +const ACL_ARRAY *aut_args_get(const char *cmd_name) +{ + char myname[] = "aut_args_get"; + AUT_LINE *test_line; + int i, n; + + if (var_aut_line_array == NULL) + aut_log_fatal("%s: var_aut_line_array=NULL", myname); + + n = acl_array_size(var_aut_line_array); + for (i = 0; i < n; i++) { + test_line = (AUT_LINE *) acl_array_index(var_aut_line_array, i); + if (test_line == NULL) + break; + if (strcasecmp(cmd_name, test_line->cmd_name) == 0) + return (test_line->argv); + } + + return (NULL); +} + +int aut_size(void) +{ + char myname[] = "aust_size"; + int n; + + if (var_aut_line_array == NULL) + aut_log_fatal("%s: var_aut_line_array=NULL", myname); + + n = acl_array_size(var_aut_line_array); + return (n); +} + +AUT_LINE *aut_index(int idx) +{ + char myname[] = "aut_cfg_index"; + AUT_LINE *test_line; + int n; + + if (var_aut_line_array == NULL) + aut_log_fatal("%s: var_aut_line_array=NULL", myname); + + n = acl_array_size(var_aut_line_array); + + if (idx < 0 || idx > n) { + printf("%s: idx=%d, acl_array_size=%d, err_msg=invalid idx\n", + myname, idx, n); + return (NULL); + } + + test_line = (AUT_LINE *) acl_array_index(var_aut_line_array, idx); + return (test_line); +} + +/* 比较所给的命令字与配置行中的命令字是否相等 */ +int aut_line_cmdcmp(const AUT_LINE *test_line, const char *cmd_name) +{ + char myname[] = "aut_line_cmdcmp"; + + if (test_line == NULL || cmd_name == NULL) { + printf("%s: input error\n", myname); + return (-1); + } + + return (strcasecmp(test_line->cmd_name, cmd_name)); +} + +/* 比较程序执行结果与配置行中的期望结果值 */ +int aut_line_resultcmp(const AUT_LINE *test_line, int value) +{ + char myname[] = "aut_line_resultcmp"; + + if (test_line == NULL) { + printf("%s: input error\n", myname); + return (-1); + } + + if (test_line->result == value) + return (0); + return (1); +} + +/* 取得该配置行在配置文件中的行号 */ +int aut_line_number(const AUT_LINE *test_line) +{ + char myname[] = "aut_line_number"; + + if (test_line == NULL) { + printf("%s: input error\n", myname); + return (-1); + } + return (test_line->line_number); +} + +int aut_line_valid_linenum(const AUT_LINE *test_line) +{ + if (test_line == NULL) + return (-1); + return (test_line->valid_line_idx); +} + +/* 取得该配置行的命令字 */ +const char *aut_line_cmdname(const AUT_LINE *test_line) +{ + char myname[] = "aut_line_cmdname"; + + if (test_line == NULL) { + printf("%s: input error\n", myname); + return (NULL); + } + + return (test_line->cmd_name); +} + +/* 取得该配置行中配置参数的个数 */ +int aut_line_argc(const AUT_LINE *test_line) +{ + char myname[] = "aut_line_argc"; + + if (test_line == NULL) { + printf("%s: input error\n", myname); + return (-1); + } + + return (test_line->argc); +} + +const char *aut_line_getvalue(const AUT_LINE *test_line, const char *name) +{ + char myname[] = "aut_line_getvalue"; + AUT_ARG_ITEM *arg = NULL; + int i, n; + + if (test_line == NULL || name == NULL || *name == 0) { + printf("%s: input error\n", myname); + return (NULL); + } + + n = acl_array_size(test_line->argv); + + for (i = 0; i < n; i++) { + arg = (AUT_ARG_ITEM *) acl_array_index(test_line->argv, i); + if (arg == NULL || arg->name == NULL) + break; + if (strcasecmp(name, arg->name) == 0) + return (arg->value); + } + + return (NULL); +} + +/* 取得该配置行中参数内容 */ +const char *aut_line_argstr(const AUT_LINE *test_line) +{ + char myname[] = "aut_line_argstr"; + + if (test_line == NULL) { + printf("%s: input error\n", myname); + return (NULL); + } + + return (test_line->args_str); +} + +/* 取得该配置行中的期望结果值 */ +int aut_line_result(const AUT_LINE *test_line) +{ + char myname[] = "aut_line_result"; + + if (test_line == NULL) { + printf("%s: input error\n", myname); + return (-1); + } + + return (test_line->result); +} + +/* 判断是否停止继续执行的配置行 */ +int aut_line_stop(const AUT_LINE *test_line) +{ + char myname[] = "aut_line_stop"; + + if (test_line == NULL) + aut_log_fatal("%s: input error", myname); + + if (strcasecmp(test_line->cmd_name, VAR_AUT_STOP) == 0) + return (1); + return (0); +} + +/* 判断是否是保留配置行 */ +int aut_line_reserved(AUT_LINE *test_line) +{ + char myname[] = "aut_line_reserved"; + + if (test_line == NULL) + aut_log_fatal("%s: input error", myname); + + if (strcasecmp(test_line->cmd_name, VAR_AUT_LOG) == 0) + return (1); + return (0); +} + +/* 将用户自己的参数项存储在 test_line 内的 arg_inner 中 */ +int aut_line_add_arg(AUT_LINE *test_line, void *arg) +{ + char myname[] = "aut_line_add_arg"; + + if (test_line == NULL) + aut_log_fatal("%s: input error", myname); + + test_line->arg_outer = arg; + return (0); +} + +void aut_line_del_arg(AUT_LINE *test_line, void (*free_fn) (void *)) +{ + if (test_line == NULL) + return; + if (free_fn != NULL) + free_fn(test_line->arg_outer); + test_line->arg_outer = NULL; +} + +void *aut_line_get_arg(const AUT_LINE *test_line) +{ + if (test_line == NULL) + return (NULL); + return (test_line->arg_outer); +} + +int aut_end_linenum(int start_linenum) +{ + char myname[] = "aut_end_linenum"; + const AUT_LINE *test_line_start; + const AUT_LINE *test_line_end = NULL; + + if (var_aut_line_array == NULL) { + printf("%s: var_aut_line_array=NULL\n", myname); + return (-1); + } + + test_line_start = aut_index(start_linenum); + if (test_line_start == NULL) + return (-1); + + if (strcasecmp(test_line_start->cmd_name, VAR_AUT_LOOP_BEGIN) == 0) + test_line_end = aut_loop_end(test_line_start); + + if (test_line_end == NULL) + return (-1); + + return (aut_line_number(test_line_end)); +} + +const AUT_LINE *aut_lookup_from_line(const AUT_LINE *test_line, int flag) +{ + AUT_CMD_TOKEN *token; + const AUT_LINE *dst_line; + int i, n; + + if (test_line == NULL) + return (NULL); + + n = aut_size(); + for (i = aut_line_valid_linenum(test_line) + 1; i < n; i++) { + dst_line = aut_index(i); + if (dst_line == NULL) + break; + if (dst_line->arg_inner == NULL) + continue; + token = (AUT_CMD_TOKEN *) dst_line->arg_inner; + if (token->flag == flag) + return (dst_line); + } + + return (NULL); +} + diff --git a/lib_acl/src/unit_test/acl_test_outer.c b/lib_acl/src/unit_test/acl_test_outer.c new file mode 100644 index 000000000..d8001cd26 --- /dev/null +++ b/lib_acl/src/unit_test/acl_test_outer.c @@ -0,0 +1,75 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "stdlib/acl_msg.h" +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_mystring.h" +#include "stdlib/acl_array.h" +#include "unit_test/acl_unit_test.h" + +#endif + +/*---------------------------- 分析外部命令配置行 --------------------------*/ + +AUT_LINE *aut_add_outer_cmd(const ACL_CFG_LINE *cfg_line) +{ + char myname[] = "aut_add_outer_cmd"; + AUT_LINE *test_line; + + if (cfg_line->ncount < 3) + aut_log_fatal("%s: cmd_name=%s, ncount=%d, input error, " + "please check configure file", + myname, cfg_line->value[0], cfg_line->ncount); + + test_line = (AUT_LINE *) acl_mycalloc(1, sizeof(*test_line)); + + if (test_line == NULL) { + char tbuf[256]; + aut_log_fatal("%s: can't malloc AUT_LINE, err_msg=%s", + myname, acl_last_strerror(tbuf, sizeof(tbuf))); + } + + snprintf(test_line->cmd_name, sizeof(test_line->cmd_name), + "%s", cfg_line->value[0]); + test_line->line_number = cfg_line->line_number; + test_line->result = atoi(cfg_line->value[1]); + test_line->argc = atoi(cfg_line->value[2]); + + if (cfg_line->ncount >= 4) { + test_line->args_str = acl_mystrdup(cfg_line->value[3]); + if (test_line->args_str == NULL) { + char tbuf[256]; + aut_log_fatal("%s: cmd_name=%s, strdup for " + "args_str, err_msg=%s", + myname, + cfg_line->value[0], + acl_last_strerror(tbuf, sizeof(tbuf))); + } + test_line->argv = aut_parse_args_list(cfg_line->value[3]); + if (test_line->argv == NULL) + aut_log_fatal("%s: cmd_name=%s, aut_parse_args_list error", + myname, cfg_line->value[0]); + } else { + test_line->args_str = NULL; + test_line->argv = NULL; + } + + if (acl_array_append(var_aut_line_array, (void *) test_line) < 0) { + char tbuf[256]; + aut_log_fatal("%s: cmd_name=%s, acl_array_append error, err_msg=%s", + myname, acl_last_strerror(tbuf, sizeof(tbuf))); + } + + test_line->valid_line_idx = var_aut_valid_line_idx++; + + return (test_line); +} diff --git a/lib_acl/src/unit_test/acl_test_runner.c b/lib_acl/src/unit_test/acl_test_runner.c new file mode 100644 index 000000000..77e298898 --- /dev/null +++ b/lib_acl/src/unit_test/acl_test_runner.c @@ -0,0 +1,381 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" +#include +#include +#ifdef ACL_UNIX +#include +#endif +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +/* Util */ +#include "stdlib/acl_msg.h" +#include "stdlib/acl_sys_patch.h" +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_array.h" + +#include "unit_test/acl_unit_test.h" + +#endif + +int var_aut_verbose = 0; + +static ACL_ARRAY *__all_callback_fn = NULL; + +/* forward declare */ +static int __fn_callback(int from, int to, int *stop); + +/*--------------------------------------------------------------------------*/ +static int __test_stop(AUT_LINE *test_line, void *arg_unused) +{ + char myname[] = "__test_stop"; + + arg_unused = arg_unused; + + aut_log_info("%s(%d): Stop here, line=%d, cmd=%s", + myname, __LINE__, + aut_line_number(test_line), + aut_line_cmdname(test_line)); + + return (0); +} + +/* 内部睡眠命令函数 */ +static int __test_sleep(AUT_LINE *test_line, void *arg_unused) +{ + char myname[] = "__test_sleep"; + const char *ptr; + int sleep_second; + + arg_unused = arg_unused; + ptr = aut_line_getvalue(test_line, VAR_AUT_ITEM_COUNT); + if (ptr == NULL) { + aut_log_error("%s: can't get name=%s' value", + myname, VAR_AUT_ITEM_COUNT); + return (-1); + } + + sleep_second = atoi(ptr); + aut_log_info("%s: sleep %s seconds now!", myname, sleep_second); + if (sleep_second > 0) + sleep(sleep_second); + + return (0); +} + +/* 内部暂停函数 */ +static int __test_pause(AUT_LINE *test_line_unused, void *arg_unused) +{ + char myname[] = "__test_pause"; + int i = 0; + + test_line_unused = test_line_unused; + arg_unused = arg_unused; + + aut_log_info("%s: PAUSE, exit when type Ctrl + c", myname); + while (1) { + sleep(1000); + if (++i >= 1000000) + break; + } + + return (0); +} + +static int __test_loop_begin(AUT_LINE *test_line, void *arg_unused) +{ + char myname[] = "__test_loop_begin"; + int count, i, from, to, ret, stop; + + arg_unused = arg_unused; + + count = aut_loop_count(test_line); + if (count < 0) { + aut_log_error("%s(%d): no loop count", myname, __LINE__); + return (-1); + } + + from = aut_loop_from(test_line); + to = aut_loop_to(test_line); + + if (from > to) { + aut_log_error("%s(%d): from(%d) > to(%d)", + myname, __LINE__, from, to); + return (-1); + } + if (from == to) + return (1); + + for (i = 0; i < count; i++) { + stop = 0; + ret = __fn_callback(from, to, &stop); + if (ret < 0) + return (-1); + if (stop) + break; + } + + return (to - from + 1); +} + +static int __test_loop_break(AUT_LINE *test_line, void *arg_unused) +{ + char myname[] = "__test_loop_break"; + const AUT_LINE *loop_end_line; + int num_break, num_end; + + arg_unused = arg_unused; + + loop_end_line = aut_lookup_from_line(test_line, AUT_FLAG_LOOP_END); + if (loop_end_line == NULL) { + aut_log_error("%s(%d): failed, no loop end, line=%d, cmd=%d", + myname, __LINE__, + aut_line_number(test_line), + aut_line_cmdname(test_line)); + return (-1); + } + + num_break = aut_line_valid_linenum(test_line); + num_end = aut_line_valid_linenum(loop_end_line); + if (num_break >= num_end) { + aut_log_error("%s(%d): failed, num_break(%d) >= num_end(%d), " + "line=%d, cmd=%s", + myname, __LINE__, + num_break, num_end, + aut_line_number(test_line), + aut_line_cmdname(test_line)); + return (-1); + } + + return (num_end - num_break + 1); +} + +static int __test_loop_end(AUT_LINE *test_line_unused, void *arg_unused) +{ + test_line_unused = test_line_unused; + arg_unused = arg_unused; + + return (1); +} + +/* not complete yet */ +static int __test_if(AUT_LINE *test_line, void *arg_unused) +{ + test_line = test_line; + arg_unused = arg_unused; + return (1); +} + +/* not complete yet */ +static int __test_else(AUT_LINE *test_line, void *arg_unused) +{ + test_line = test_line; + arg_unused = arg_unused; + return (1); +} + +/* not complete yet */ +static int __test_endif(AUT_LINE *test_line, void *arg_unused) +{ + test_line = test_line; + arg_unused = arg_unused; + return (1); +} + +/* not complete yet */ +static int __test_goto(AUT_LINE *test_line, void *arg_unused) +{ + test_line = test_line; + arg_unused = arg_unused; + + return (1); +} + +/* 内部用动作命令表 */ +static AUT_FN_ITEM __inner_fn_tab[] = { + /* 用来停止执行下一步测试操作 */ + { VAR_AUT_STOP, "__test_stop", __test_stop, NULL, 1 }, + { VAR_AUT_SLEEP, "__test_sleep", __test_sleep, NULL, 1 }, + { VAR_AUT_PAUSE, "__test_pause", __test_pause, NULL, 1 }, + + { VAR_AUT_LOOP_BEGIN, "__test_loop_begin", __test_loop_begin, NULL, 1 }, + { VAR_AUT_LOOP_BREAK, "__test_loop_break", __test_loop_break, NULL, 1 }, + { VAR_AUT_LOOP_END, "__test_loop_end", __test_loop_end, NULL, 1 }, + + { VAR_AUT_IF, "__test_if", __test_if, NULL, 1 }, + { VAR_AUT_ELSE, "__test_else", __test_else, NULL, 1 }, + { VAR_AUT_ENDIF, "__testt_endif", __test_endif, NULL, 1 }, + + { VAR_AUT_GOTO, "__test_goto", __test_goto, NULL, 1 }, + + { NULL, NULL, NULL, NULL, 0 }, +}; +/*--------------------------------------------------------------------------*/ + +static AUT_FN_ITEM *__lookup_fn_item(const AUT_LINE *test_line) +{ + char myname[] = "__lookup_fn_item"; + int i, n; + AUT_FN_ITEM *item = NULL, *tmp; + + n = acl_array_size(__all_callback_fn); + for (i = 0; i < n; i++) { + tmp = (AUT_FN_ITEM *) acl_array_index(__all_callback_fn, i); + if (tmp == NULL) + aut_log_fatal("%s(%d): idx=%d, null rebuild from array", + myname, __LINE__, i); + if (aut_line_cmdcmp(test_line, tmp->cmd_name) == 0) { + item = tmp; + break; + } + } + + return (item); +} + +static int __fn_callback(int from, int to, int *stop) +{ + char myname[] = "__fn_callback"; + AUT_FN_ITEM *item; + AUT_LINE *test_line; + int ret; + + if (from > to) + aut_log_fatal("%s(%d): from(%d) > to(%d)", + myname, __LINE__, from, to); + + for (; from < to;) { + test_line = aut_index(from); + if (test_line == NULL) + break; + item = __lookup_fn_item(test_line); + if (item == NULL) { + aut_log_error("%s(%d): invalid cmd(%s), line=%d", + myname, __LINE__, + aut_line_cmdname(test_line), + aut_line_number(test_line)); + return (-1); + } + + if (item->inner) { + ret = item->fn_callback(test_line, item->arg); + if (ret < 0) { +#ifdef AUT_DEBUG + aut_log_error("%s(%d): failed, line=%d, cmd=%s", + myname, __LINE__, + aut_line_number(test_line), + item->cmd_name); +#endif + return (-1); + } + + from += ret; + if (from > to) { + if (stop) + *stop = 1; + break; + } + + if (item->fn_callback == __test_stop) + break; + continue; + } + + ret = item->fn_callback(test_line, item->arg); + if (aut_line_resultcmp(test_line, ret) != 0) { + aut_log_error("%s(%d): failed, line=%d, cmd=%s", + myname, __LINE__, + aut_line_number(test_line), + item->cmd_name); + if (stop) + *stop = 1; + return (-1); + } + aut_log_info("%s(%d): success, function=%s, cmd=%s", + myname, __LINE__, + item->fn_name, item->cmd_name); + from++; + } + + return (0); +} + +int aut_start(void) +{ + char myname[] = "aut_start"; + int max; + + if (__all_callback_fn == NULL) { + printf("%s: please call aut_register first\n", myname); + return (-1); + } + + /* 取得所有有效配置行的总和 */ + max = aut_size(); + if (max <= 0) { + aut_log_error("%s(%d): configure's size is null", + myname, __LINE__); + return (-1); + } + + return (__fn_callback(0, max, NULL)); +} + +static void free_fn_item(void *arg) +{ + AUT_FN_ITEM *item = (AUT_FN_ITEM*) arg; + + acl_myfree(item); +} + +void aut_stop(void) +{ + if (var_aut_line_array) { + acl_array_free(var_aut_line_array, aut_line_free); + var_aut_line_array = NULL; + } + if (__all_callback_fn) { + acl_array_free(__all_callback_fn, free_fn_item); + __all_callback_fn = NULL; + } +} + +static void __add_fn_item(ACL_ARRAY *fn_tab, const AUT_FN_ITEM *fn_item, int inner) +{ + char myname[] = "__add_fn_item"; + AUT_FN_ITEM *item; + + item = (AUT_FN_ITEM *) acl_mycalloc(1, sizeof(AUT_FN_ITEM)); + item->cmd_name = fn_item->cmd_name; + item->fn_name = fn_item->fn_name; + item->fn_callback = fn_item->fn_callback; + item->arg = fn_item->arg; + item->inner = inner; + + if (acl_array_append(fn_tab, item) < 0) { + char tbuf[256]; + aut_log_fatal("%s(%d): array_append error(%s)", + myname, __LINE__, acl_last_strerror(tbuf, sizeof(tbuf))); + } +} + +void aut_register(const AUT_FN_ITEM test_fn_tab[]) +{ + int i; + + if (__all_callback_fn == NULL) + __all_callback_fn = acl_array_create(10); + + /* 先增加注册内部用命令 */ + for (i = 0; __inner_fn_tab[i].cmd_name != NULL; i++) + __add_fn_item(__all_callback_fn, &__inner_fn_tab[i], 1); + + /* 再注册外部传来的命令任务 */ + for (i = 0; test_fn_tab[i].cmd_name != NULL; i++) + __add_fn_item(__all_callback_fn, &test_fn_tab[i], 0); +} diff --git a/lib_acl/src/unit_test/acl_test_token.c b/lib_acl/src/unit_test/acl_test_token.c new file mode 100644 index 000000000..3740eedeb --- /dev/null +++ b/lib_acl/src/unit_test/acl_test_token.c @@ -0,0 +1,64 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_define.h" + +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif + +#include "unit_test/acl_unit_test.h" + +#endif + +AUT_CMD_TOKEN *aut_line_peer_token(const AUT_LINE *test_line) +{ + char myname[] = "aut_line_peer_token"; + AUT_LINE *test_peer; + + if (test_line == NULL || test_line->arg_inner == NULL) + aut_log_fatal("%s: input error", myname); + + test_peer = aut_line_peer(test_line); + if (test_peer == NULL) + return (NULL); + + return ((AUT_CMD_TOKEN *) test_peer->arg_inner); +} + +AUT_LINE *aut_line_peer(const AUT_LINE *test_line) +{ + char myname[] = "aut_line_peer"; + AUT_LINE *test_peer; + AUT_CMD_TOKEN *token, *token_peer; + + if (test_line == NULL || test_line->arg_inner == NULL) + aut_log_fatal("%s(%d)->%s: input error", + __FILE__, __LINE__, myname); + + /* 从 acl_test_line 中取出以前注册的参数 */ + token = (AUT_CMD_TOKEN *) test_line->arg_inner; + + /* 取得相配对的的指针 */ + test_peer = token->peer; + if (test_peer == NULL || test_peer->arg_inner == NULL) { + aut_log_fatal("%s(%d)->%s: peers null, cmd_name=%s, err=%s", + __FILE__, __LINE__, + myname, test_line, + test_peer == NULL ? "test_line null": "arg_inner null"); + } + + /* 从 acl_test_line 中取出以前注册的参数 */ + token_peer = (AUT_CMD_TOKEN *) test_peer->arg_inner; + + /* 比较 begin 与 end 是否是一对 */ + if (token_peer->peer != test_line) + aut_log_fatal("%s(%d)->%s: not peers", + __FILE__, __LINE__, myname); + + return (test_peer); +} + diff --git a/lib_acl/src/xml/acl_xml.c b/lib_acl/src/xml/acl_xml.c new file mode 100644 index 000000000..fc85660df --- /dev/null +++ b/lib_acl/src/xml/acl_xml.c @@ -0,0 +1,596 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include +#include +#include "stdlib/acl_msg.h" +#include "stdlib/acl_mystring.h" +#include "stdlib/acl_define.h" +#include "stdlib/acl_mymalloc.h" +#include "xml/acl_xml.h" + +#endif + +#define LEN ACL_VSTRING_LEN +#define STR acl_vstring_str + +ACL_XML_ATTR *acl_xml_attr_alloc(ACL_XML_NODE *node) +{ + ACL_XML_ATTR *attr; + + if (node->xml->slice) + attr = (ACL_XML_ATTR*) acl_slice_pool_calloc(__FILE__, __LINE__, + node->xml->slice, 1, sizeof(ACL_XML_ATTR)); + else + attr = (ACL_XML_ATTR*) acl_mycalloc(1, sizeof(ACL_XML_ATTR)); + attr->node = node; + attr->name = acl_vstring_alloc2(node->xml->slice, 16); + attr->value = acl_vstring_alloc2(node->xml->slice, 16); + attr->quote = 0; + attr->backslash = 0; + attr->part_word = 0; + + acl_array_append(node->attr_list, attr); + return (attr); +} + +void acl_xml_attr_free(ACL_XML_ATTR *attr) +{ + acl_vstring_free(attr->name); + acl_vstring_free(attr->value); + if (attr->node->xml->slice) + acl_slice_pool_free(__FILE__, __LINE__, attr); + else + acl_myfree(attr); +} + +static ACL_XML_NODE *node_iter_head(ACL_ITER *it, ACL_XML_NODE *node) +{ + ACL_RING *ring_ptr; + + it->dlen = -1; + it->key = NULL; + it->klen = -1; + + it->i = 0; + it->size = node->children.len; + + if ((ring_ptr = acl_ring_succ(&node->children)) == &node->children) { + it->ptr = it->data = NULL; + return (NULL); + } + it->ptr = acl_ring_to_appl(ring_ptr, ACL_XML_NODE, node); + it->data = it->ptr; + return (it->ptr); +} + +static ACL_XML_NODE *node_iter_next(ACL_ITER *it, ACL_XML_NODE *node) +{ + ACL_RING *ring_ptr; + struct ACL_XML_NODE *child; + + child = (struct ACL_XML_NODE*) it->data; + if ((ring_ptr = acl_ring_succ(&child->node)) == &node->children) { + it->ptr = it->data = NULL; + return (NULL); + } + it->i++; + it->ptr = acl_ring_to_appl(ring_ptr, ACL_XML_NODE, node); + it->data = it->ptr; + return (it->ptr); +} + +static ACL_XML_NODE *node_iter_tail(ACL_ITER *it, ACL_XML_NODE *node) +{ + ACL_RING *ring_ptr; + + it->dlen = -1; + it->key = NULL; + it->klen = -1; + + it->i = 0; + it->size = node->children.len; + + if ((ring_ptr = acl_ring_pred(&node->children)) == &node->children) { + it->ptr = it->data = NULL; + return (NULL); + } + + it->ptr = acl_ring_to_appl(ring_ptr, ACL_XML_NODE, node); + it->data = it->ptr; + return (it->ptr); +} + +static ACL_XML_NODE *node_iter_prev(ACL_ITER *it, ACL_XML_NODE *node) +{ + ACL_RING *ring_ptr; + struct ACL_XML_NODE *child; + + child = (struct ACL_XML_NODE*) it->data; + if ((ring_ptr = acl_ring_pred(&child->node)) == &node->children) { + it->ptr = it->data = NULL; + return (NULL); + } + it->i++; + it->ptr = acl_ring_to_appl(ring_ptr, ACL_XML_NODE, node); + it->data = it->ptr; + return (it->ptr); +} + +static void acl_xml_node_reset(ACL_XML_NODE *node) +{ + ACL_VSTRING_RESET(node->ltag); + ACL_VSTRING_RESET(node->rtag); + ACL_VSTRING_RESET(node->text); + ACL_VSTRING_TERMINATE(node->ltag); + ACL_VSTRING_TERMINATE(node->rtag); + ACL_VSTRING_TERMINATE(node->text); + + node->id = NULL; + + if (node->attr_list) + acl_array_clean(node->attr_list, + (void (*)(void*)) acl_xml_attr_free); + node->parent = NULL; + acl_ring_init(&node->children); + node->depth = 0; + + acl_ring_init(&node->node); + node->curr_attr = NULL; + node->quote = 0; + node->last_ch = 0; + node->nlt = 0; + node->meta[0] = 0; + node->flag = 0; + node->status = ACL_XML_S_NXT; +} + +ACL_XML_NODE *acl_xml_node_alloc(ACL_XML *xml) +{ + ACL_XML_NODE *node; + + if (xml->node_cache) { + node = (ACL_XML_NODE*) + xml->node_cache->pop_back(xml->node_cache); + if (node) { + acl_xml_node_reset(node); + node->xml = xml; + xml->node_cnt++; + return (node); + } + } + + if (xml->slice) + node = (ACL_XML_NODE*) acl_slice_pool_calloc(__FILE__, __LINE__, + xml->slice, 1, sizeof(ACL_XML_NODE)); + else + node = (ACL_XML_NODE*) acl_mycalloc(1, sizeof(ACL_XML_NODE)); + acl_ring_init(&node->children); + acl_ring_init(&node->node); + + node->xml = xml; + node->status = ACL_XML_S_NXT; + node->ltag = acl_vstring_alloc2(xml->slice, 16); + node->rtag = acl_vstring_alloc2(xml->slice, 16); + node->text = acl_vstring_alloc2(xml->slice, 16); + node->attr_list = acl_array_create(5); + xml->node_cnt++; + + node->iter_head = node_iter_head; + node->iter_next = node_iter_next; + node->iter_tail = node_iter_tail; + node->iter_prev = node_iter_prev; + return (node); +} + +static void acl_xml_node_free(ACL_XML_NODE *node) +{ + acl_vstring_free(node->ltag); + acl_vstring_free(node->rtag); + acl_vstring_free(node->text); + acl_ring_detach(&node->node); + acl_array_free(node->attr_list, (void (*)(void*)) acl_xml_attr_free); + if (node->xml->slice) + acl_slice_pool_free(__FILE__, __LINE__, node); + else + acl_myfree(node); +} + +int acl_xml_node_delete(ACL_XML_NODE *node) +{ + ACL_RING *next; + ACL_XML_NODE *node_next; + int n = 1; + + while ((next = acl_ring_pop_head(&node->children)) != NULL) { + node_next = acl_ring_to_appl(next, ACL_XML_NODE, node); + n += acl_xml_node_delete(node_next); + } + + node->xml->node_cnt--; + if (node->id != NULL) + acl_htable_delete(node->xml->id_table, STR(node->id), NULL); + if (node->xml->node_cache && + acl_array_size(node->xml->node_cache) < node->xml->max_cache) + { + node->xml->node_cache->push_back(node->xml->node_cache, node); + acl_ring_detach(&node->node); + } else + acl_xml_node_free(node); + return (n); +} + +void acl_xml_node_append(ACL_XML_NODE *node1, ACL_XML_NODE *node2) +{ + /* + if (node1->parent) + acl_xml_node_add_child(node1->parent, node2); + else + */ + acl_ring_append(&node1->node, &node2->node); + node2->parent = node1->parent; +} + +void acl_xml_node_add_child(ACL_XML_NODE *parent, ACL_XML_NODE *child) +{ + acl_ring_prepend(&parent->children, &child->node); + child->parent = parent; +} + +ACL_XML_NODE *acl_xml_node_parent(ACL_XML_NODE *node) +{ + return (node->parent); +} + +ACL_XML_NODE *acl_xml_node_next(ACL_XML_NODE *node) +{ + ACL_RING *ring_ptr = acl_ring_succ(&node->node); + ACL_XML_NODE *parent; + + if (ring_ptr == &node->node) + return (NULL); + parent = node->parent; + acl_assert(parent != NULL); + if (ring_ptr == &parent->children) + return (NULL); + return (acl_ring_to_appl(ring_ptr, ACL_XML_NODE, node)); +} + +ACL_XML_NODE *acl_xml_node_prev(ACL_XML_NODE *node) +{ + ACL_RING *ring_ptr = acl_ring_succ(&node->node); + ACL_XML_NODE *parent; + + if (ring_ptr == &node->node) + return (NULL); + parent = node->parent; + acl_assert(parent != NULL); + if (ring_ptr == &parent->children) + return (NULL); + + return (acl_ring_to_appl(ring_ptr, ACL_XML_NODE, node)); +} + +static ACL_XML_NODE *xml_iter_head(ACL_ITER *it, ACL_XML *xml) +{ + ACL_RING *ring_ptr; + + it->dlen = -1; + it->key = NULL; + it->klen = -1; + + it->i = 0; + it->size = xml->node_cnt; + + ring_ptr = acl_ring_succ(&xml->root->children); + if (ring_ptr== &xml->root->children) { + it->ptr = it->data = NULL; + return (NULL); + } + it->ptr = acl_ring_to_appl(ring_ptr, ACL_XML_NODE, node); + it->data = it->ptr; + return (it->ptr); +} + +static ACL_XML_NODE *xml_iter_next(ACL_ITER *it, ACL_XML *xml) +{ + ACL_RING *ring_ptr; + struct ACL_XML_NODE *node, *parent; + + node = (struct ACL_XML_NODE*) it->data; + + /* 先遍历当前结点的子结点 */ + + ring_ptr = acl_ring_succ(&node->children); + if (ring_ptr != &node->children) { + it->i++; + it->ptr = acl_ring_to_appl(ring_ptr, ACL_XML_NODE, node); + it->data = it->ptr; + return (it->ptr); + } + + /* 当前结点的子结点遍历完毕,再遍历当前结点的兄弟结点 */ + + parent = acl_xml_node_parent(node); + ring_ptr = acl_ring_succ(&node->node); + if (ring_ptr != &parent->children) { + it->i++; + it->ptr = acl_ring_to_appl(ring_ptr, ACL_XML_NODE, node); + it->data = it->ptr; + return (it->ptr); + } + + /* 当前结点的兄弟结点遍历完毕,最后遍历当前结点的父结点的兄弟结点 */ + + do { + if (parent == xml->root) + break; + ring_ptr = acl_ring_succ(&parent->node); + parent = acl_xml_node_parent(parent); + if (parent == NULL) + acl_msg_fatal("%s(%d): parent null", __FILE__, __LINE__); + + if (ring_ptr != &parent->children) { + it->i++; + it->ptr = acl_ring_to_appl(ring_ptr, ACL_XML_NODE, node); + it->data = it->ptr; + return (it->ptr); + } + } while (ring_ptr != &xml->root->children); + + /* 遍历完所有结点 */ + + it->ptr = it->data = NULL; + return (NULL); +} + +static ACL_XML_NODE *xml_iter_tail(ACL_ITER *it, ACL_XML *xml) +{ + ACL_RING *ring_ptr; + + it->dlen = -1; + it->key = NULL; + it->klen = -1; + + it->i = 0; + it->size = xml->node_cnt; + + ring_ptr = acl_ring_pred(&xml->root->children); + if (ring_ptr== &xml->root->children) { + it->ptr = it->data = NULL; + return (NULL); + } + it->ptr = acl_ring_to_appl(ring_ptr, ACL_XML_NODE, node); + it->data = it->ptr; + return (it->ptr); +} + +static ACL_XML_NODE *xml_iter_prev(ACL_ITER *it, ACL_XML *xml) +{ + ACL_RING *ring_ptr; + struct ACL_XML_NODE *node, *parent; + + node = (struct ACL_XML_NODE*) it->data; + + /* 先遍历当前结点的子结点 */ + + ring_ptr = acl_ring_pred(&node->children); + if (ring_ptr != &node->children) { + it->i++; + it->ptr = acl_ring_to_appl(ring_ptr, ACL_XML_NODE, node); + it->data = it->ptr; + return (it->ptr); + } + + /* 当前结点的子结点遍历完毕,再遍历当前结点的兄弟结点 */ + + parent = acl_xml_node_parent(node); + ring_ptr = acl_ring_pred(&node->node); + if (ring_ptr != &parent->children) { + it->i++; + it->ptr = acl_ring_to_appl(ring_ptr, ACL_XML_NODE, node); + it->data = it->ptr; + return (it->ptr); + } + + /* 当前结点的兄弟结点遍历完毕,最后遍历当前结点的父结点的兄弟结点 */ + + do { + if (parent == xml->root) + break; + ring_ptr = acl_ring_pred(&parent->node); + parent = acl_xml_node_parent(parent); + if (parent == NULL) + acl_msg_fatal("%s(%d): parent null", __FILE__, __LINE__); + + if (ring_ptr != &parent->children) { + it->i++; + it->ptr = acl_ring_to_appl(ring_ptr, ACL_XML_NODE, node); + it->data = it->ptr; + return (it->ptr); + } + } while (ring_ptr != &xml->root->children); + + /* 遍历完所有结点 */ + + it->ptr = it->data = NULL; + return (NULL); +} + +ACL_XML *acl_xml_alloc() +{ + return (acl_xml_alloc1(NULL)); +} + +ACL_XML *acl_xml_alloc1(ACL_SLICE_POOL *slice) +{ + ACL_XML *xml; + + if (slice) { + xml = (ACL_XML*) acl_slice_pool_calloc(__FILE__, __LINE__, + slice, 1, sizeof(ACL_XML)); + xml->slice = slice; + } else { + xml = (ACL_XML*) acl_mycalloc(1, sizeof(ACL_XML)); + xml->slice = NULL; + } + + xml->root = acl_xml_node_alloc(xml); + xml->id_table = acl_htable_create3(10, 0, slice); + + xml->iter_head = xml_iter_head; + xml->iter_next = xml_iter_next; + xml->iter_tail = xml_iter_tail; + xml->iter_prev = xml_iter_prev; + return (xml); +} + +void acl_xml_foreach_init(ACL_XML *xml, ACL_XML_NODE *node) +{ + xml->root = node; + xml->iter_head = xml_iter_head; + xml->iter_next = xml_iter_next; + xml->iter_tail = xml_iter_tail; + xml->iter_prev = xml_iter_prev; +} + +void acl_xml_slash(ACL_XML *xml, int ignore) +{ + if (ignore) + xml->flag |= ACL_XML_FLAG_IGNORE_SLASH; +} + +void acl_xml_cache(ACL_XML *xml, int max_cache) +{ + if (xml->node_cache != NULL) { + acl_array_free(xml->node_cache, + (void (*)(void*)) acl_xml_node_free); + xml->node_cache = NULL; + xml->max_cache = 0; + } + if (max_cache > 0) { + xml->node_cache = acl_array_create(max_cache); + xml->max_cache = max_cache; + } +} + +void acl_xml_cache_free(ACL_XML *xml) +{ + if (xml->node_cache != NULL) { + acl_array_free(xml->node_cache, + (void (*)(void*)) acl_xml_node_free); + xml->node_cache = NULL; + xml->max_cache = 0; + } +} + +int acl_xml_free(ACL_XML *xml) +{ + ACL_RING *next; + ACL_XML_NODE *node; + int n = 1; + + while ((next = acl_ring_pop_head(&xml->root->children)) != NULL) { + node = acl_ring_to_appl(next, ACL_XML_NODE, node); + n += acl_xml_node_delete(node); + } + + acl_xml_node_free(xml->root); + xml->node_cnt--; + acl_assert(xml->node_cnt == 0); + acl_htable_free(xml->id_table, NULL); + if (xml->node_cache != NULL) + acl_array_free(xml->node_cache, + (void (*)(void*)) acl_xml_node_free); + if (xml->slice) + acl_slice_pool_free(__FILE__, __LINE__, xml); + else + acl_myfree(xml); + return (n); +} + +void acl_xml_reset(ACL_XML *xml) +{ + const char *myname = "acl_xml_reset"; + ACL_RING *next; + ACL_XML_NODE *node; + + while ((next = acl_ring_pop_head(&xml->root->children)) != NULL) { + node = acl_ring_to_appl(next, ACL_XML_NODE, node); + (void) acl_xml_node_delete(node); + } + + /* 因为根结点是一个虚结点,所以不需要释放,其会在调用 + * acl_xml_free 时被释放 + */ + acl_ring_detach(&xml->root->node); + acl_xml_node_reset(xml->root); + + if (xml->node_cnt != 1) + acl_msg_fatal("%s(%d): node_cnt(%d) invalid", + myname, __LINE__, xml->node_cnt); + + acl_htable_reset(xml->id_table, NULL); + xml->curr_node = NULL; +} + +int acl_xml_is_closure(ACL_XML *xml) +{ + ACL_RING *ring_ptr; + ACL_XML_NODE *node; + + /* 获得 xml->root 结点的最后一个一级子结点 */ + ring_ptr = acl_ring_succ(&xml->root->children); + + if (ring_ptr == &xml->root->children) { + /* 说明没有真实子结点 */ + return (0); + } + + node = acl_ring_to_appl(ring_ptr, ACL_XML_NODE, node); + + if ((node->flag & ACL_XML_F_SELF_CL)) { + /* 说明该结点是自闭合结点 */ + return (1); + } + + if (node->status == ACL_XML_S_RGT) { + return (1); + } + + /* 说明最后一个一级子结点还未处理完毕 */ + return (0); +} + +int acl_xml_is_complete(ACL_XML *xml, const char *tag) +{ + ACL_RING *ring_ptr; + ACL_XML_NODE *node; + + /* 获得 xml->root 结点的最后一个一级子结点 */ + ring_ptr = acl_ring_succ(&xml->root->children); + + if (ring_ptr == &xml->root->children) { + /* 说明没有真实子结点 */ + return (0); + } + + node = acl_ring_to_appl(ring_ptr, ACL_XML_NODE, node); + + if ((node->flag & ACL_XML_F_SELF_CL)) { + /* 说明该结点是自闭合结点 */ + return (1); + } + + if (node->status != ACL_XML_S_RGT) { + /* 说明最后一个一级子结点还未处理完毕 */ + return (0); + } + + if (strcasecmp(STR(node->rtag), tag) == 0) { + return (1); + } + + /* 说明 xml 中的最后一个结点与所给标签不匹配 */ + return (0); +} diff --git a/lib_acl/src/xml/acl_xml_parse.c b/lib_acl/src/xml/acl_xml_parse.c new file mode 100644 index 000000000..6991a2a67 --- /dev/null +++ b/lib_acl/src/xml/acl_xml_parse.c @@ -0,0 +1,750 @@ +#include "StdAfx.h" +#ifndef ACL_PREPARE_COMPILE + +#include +#include "stdlib/acl_mystring.h" +#include "xml/acl_xml.h" + +#endif + +#define LEN ACL_VSTRING_LEN +#define STR acl_vstring_str +#define END acl_vstring_end + +#define IS_DOCTYPE(ptr) ((*(ptr) == 'd' || *(ptr) == 'D') \ + && (*(ptr + 1) == 'o' || *(ptr + 1) == 'O') \ + && (*(ptr + 2) == 'c' || *(ptr + 2) == 'C') \ + && (*(ptr + 3) == 't' || *(ptr + 3) == 'T') \ + && (*(ptr + 4) == 'y' || *(ptr + 4) == 'Y') \ + && (*(ptr + 5) == 'p' || *(ptr + 5) == 'P') \ + && (*(ptr + 5) == 'E' || *(ptr + 6) == 'E')) +#define IS_ID(ptr) ((*(ptr) == 'i' || *(ptr) == 'I') \ + && (*(ptr + 1) == 'd' || *(ptr + 1) == 'D')) +#define IS_QUOTE(x) ((x) == '\"' || (x) == '\'') +#define IS_SPACE(c) ((c) == ' ' || (c) == '\t' || (c) == '\r' || (c) == '\n') +#define SKIP_WHILE(cond, ptr) { while(*(ptr) && (cond)) (ptr)++; } +#define SKIP_SPACE(ptr) { while(IS_SPACE(*(ptr))) (ptr)++; } + +/* 状态机数据结构类型 */ + +struct XML_STATUS_MACHINE { + int status; /**< 状态码 */ + const char *(*callback) (ACL_XML*, const char*); /**< 状态机处理函数 */ +}; + +static const char *xml_parse_next_left_lt(ACL_XML *xml, const char *data) +{ + SKIP_SPACE(data); + SKIP_WHILE(*data != '<', data); + if (*data == 0) + return (NULL); + data++; + xml->curr_node->status = ACL_XML_S_LLT; + return (data); +} + +static const char *xml_parse_left_lt(ACL_XML *xml, const char *data) +{ + xml->curr_node->status = ACL_XML_S_LCH; + return (data); +} + +static void xml_parse_check_self_closed(ACL_XML *xml) +{ + if ((xml->curr_node->flag & ACL_XML_F_LEAF) == 0) { + if (acl_xml_tag_leaf(STR(xml->curr_node->ltag))) { + xml->curr_node->flag |= ACL_XML_F_LEAF; + } + } + + if ((xml->curr_node->flag & ACL_XML_F_SELF_CL) == 0) { + if (xml->curr_node->last_ch == '/' + || acl_xml_tag_selfclosed(STR(xml->curr_node->ltag))) + { + xml->curr_node->flag |= ACL_XML_F_SELF_CL; + } + } +} + +static const char *xml_parse_left_gt(ACL_XML *xml, const char *data) +{ + xml->curr_node->last_ch = 0; + xml->curr_node->status = ACL_XML_S_TXT; + return (data); +} + +static const char *xml_parse_left_ch(ACL_XML *xml, const char *data) +{ + int ch = *data; + + if (ch == '!') { + xml->curr_node->meta[0] = ch; + xml->curr_node->status = ACL_XML_S_LEM; + data++; + } else if (ch == '?') { + xml->curr_node->meta[0] = ch; + xml->curr_node->flag |= ACL_XML_F_META_QM; + xml->curr_node->status = ACL_XML_S_MTAG; + data++; + } else { + xml->curr_node->status = ACL_XML_S_LTAG; + } + return (data); +} + +static const char *xml_parse_left_em(ACL_XML *xml, const char *data) +{ + if (*data == '-') { + if (xml->curr_node->meta[1] != '-') { + xml->curr_node->meta[1] = '-'; + } else if (xml->curr_node->meta[2] != '-') { + xml->curr_node->meta[0] = 0; + xml->curr_node->meta[1] = 0; + xml->curr_node->meta[2] = 0; + xml->curr_node->flag |= ACL_XML_F_META_CM; + xml->curr_node->status = ACL_XML_S_MCMT; + } + data++; + } else { + if (xml->curr_node->meta[1] == '-') { + ACL_VSTRING_ADDCH(xml->curr_node->ltag, '-'); + xml->curr_node->meta[1] = 0; + } + xml->curr_node->flag |= ACL_XML_F_META_EM; + xml->curr_node->status = ACL_XML_S_MTAG; + } + + ACL_VSTRING_TERMINATE(xml->curr_node->ltag); + return (data); +} + +static const char *xml_parse_meta_tag(ACL_XML *xml, const char *data) +{ + int ch; + + while ((ch = *data) != 0) { + data++; + if (IS_SPACE(ch)) { + xml->curr_node->status = ACL_XML_S_MTXT; + break; + } + ACL_VSTRING_ADDCH(xml->curr_node->ltag, ch); + } + ACL_VSTRING_TERMINATE(xml->curr_node->ltag); + return (data); +} + +static const char *xml_meta_attr_name(ACL_XML_ATTR *attr, const char *data) +{ + int ch; + + while ((ch = *data) != 0) { + if (ch == '=') { + data++; + ACL_VSTRING_TERMINATE(attr->name); + break; + } + if (!IS_SPACE(ch)) + ACL_VSTRING_ADDCH(attr->name, ch); + data++; + } + return data; +} + +static const char *xml_meta_attr_value(ACL_XML_ATTR *attr, const char *data) +{ + int ch; + + SKIP_SPACE(data); + if (*data == 0) + return data; + if (IS_QUOTE(*data)) + attr->quote = *data++; + + while ((ch = *data) != 0) { + if (attr->backslash) { + ACL_VSTRING_ADDCH(attr->value, ch); + attr->backslash = 0; + } else if (ch == '\\') { + if (attr->part_word) { + ACL_VSTRING_ADDCH(attr->value, ch); + attr->part_word = 0; + } else + attr->backslash = 1; + } else if (attr->quote) { + if (ch == attr->quote) { + data++; + break; + } + ACL_VSTRING_ADDCH(attr->value, ch); + } else if (IS_SPACE(ch)) { + data++; + break; + } else { + ACL_VSTRING_ADDCH(attr->value, ch); + if ((attr->node->xml->flag & ACL_XML_FLAG_PART_WORD)) { + if (attr->part_word) + attr->part_word = 0; + else if (ch < 0) + attr->part_word = 1; + } + } + data++; + } + + ACL_VSTRING_TERMINATE(attr->value); + return data; +} + +static void xml_meta_attr(ACL_XML_NODE *node) +{ + ACL_XML_ATTR *attr; + const char *ptr; + int ch; + + if (node->text == NULL) + return; + ptr = STR(node->text); + SKIP_SPACE(ptr); /* 略过 ' ', '\t' */ + if (*ptr == 0) + return; + + while ((ch = *ptr) != 0) { + attr = acl_xml_attr_alloc(node); + ptr = xml_meta_attr_name(attr, ptr); + if (*ptr == 0) + break; + ptr = xml_meta_attr_value(attr, ptr); + if (*ptr == 0) + break; + } +} + +static const char *xml_parse_meta_text(ACL_XML *xml, const char *data) +{ + int ch; + + if (LEN(xml->curr_node->text) == 0) { + SKIP_SPACE(data); + } + + while ((ch = *data) != 0) { + if (xml->curr_node->quote) { + if (ch == xml->curr_node->quote) { + xml->curr_node->quote = 0; + } + ACL_VSTRING_ADDCH(xml->curr_node->text, ch); + } else if (IS_QUOTE(ch)) { + if (xml->curr_node->quote == 0) { + xml->curr_node->quote = ch; + } + ACL_VSTRING_ADDCH(xml->curr_node->text, ch); + } else if (ch == '<') { + xml->curr_node->nlt++; + ACL_VSTRING_ADDCH(xml->curr_node->text, ch); + } else if (ch == '>') { + if (xml->curr_node->nlt == 0) { + char *last; + size_t off; + + data++; + xml->curr_node->status = ACL_XML_S_MEND; + if ((xml->curr_node->flag & ACL_XML_F_META_QM) == 0) + break; + + last = acl_vstring_end(xml->curr_node->text) - 1; + if (last < STR(xml->curr_node->text) || *last != '?') + break; + off = ACL_VSTRING_LEN(xml->curr_node->text) - 1; + if (off == 0) + break; + ACL_VSTRING_AT_OFFSET(xml->curr_node->text, off); + ACL_VSTRING_TERMINATE(xml->curr_node->text); + xml_meta_attr(xml->curr_node); + break; + } + xml->curr_node->nlt--; + ACL_VSTRING_ADDCH(xml->curr_node->text, ch); + } else { + ACL_VSTRING_ADDCH(xml->curr_node->text, ch); + } + data++; + } + + ACL_VSTRING_TERMINATE(xml->curr_node->text); + return (data); +} + +static const char *xml_parse_meta_comment(ACL_XML *xml, const char *data) +{ + int ch; + + if (LEN(xml->curr_node->text) == 0) { + SKIP_SPACE(data); + } + + while ((ch = *data) != 0) { + if (xml->curr_node->quote) { + if (ch == xml->curr_node->quote) { + xml->curr_node->quote = 0; + } else { + ACL_VSTRING_ADDCH(xml->curr_node->text, ch); + } + } else if (IS_QUOTE(ch)) { + if (xml->curr_node->quote == 0) { + xml->curr_node->quote = ch; + } else { + ACL_VSTRING_ADDCH(xml->curr_node->text, ch); + } + } else if (ch == '<') { + xml->curr_node->nlt++; + ACL_VSTRING_ADDCH(xml->curr_node->text, ch); + } else if (ch == '>') { + if (xml->curr_node->nlt == 0) { + if (xml->curr_node->meta[0] == '-' + && xml->curr_node->meta[1] == '-') + { + data++; + xml->curr_node->status = ACL_XML_S_MEND; + break; + } + } + xml->curr_node->nlt--; + ACL_VSTRING_ADDCH(xml->curr_node->text, ch); + } else if (xml->curr_node->nlt > 0) { + ACL_VSTRING_ADDCH(xml->curr_node->text, ch); + } else if (ch == '-') { + if (xml->curr_node->meta[0] != '-') { + xml->curr_node->meta[0] = '-'; + } else if (xml->curr_node->meta[1] != '-') { + xml->curr_node->meta[1] = '-'; + } + } else { + if (xml->curr_node->meta[0] == '-') { + ACL_VSTRING_ADDCH(xml->curr_node->text, '-'); + xml->curr_node->meta[0] = 0; + } + if (xml->curr_node->meta[1] == '-') { + ACL_VSTRING_ADDCH(xml->curr_node->text, '-'); + xml->curr_node->meta[1] = 0; + } + ACL_VSTRING_ADDCH(xml->curr_node->text, ch); + } + data++; + } + + ACL_VSTRING_TERMINATE(xml->curr_node->text); + return (data); +} + +static const char *xml_parse_meta_end(ACL_XML *xml, const char *data) +{ + /* meta 标签是自关闭类型,直接跳至右边 '>' 处理位置 */ + xml->curr_node->status = ACL_XML_S_RGT; + return (data); +} + +static const char *xml_parse_left_tag(ACL_XML *xml, const char *data) +{ + int ch; + + if (LEN(xml->curr_node->ltag) == 0) { + SKIP_SPACE(data); + } + + while ((ch = *data) != 0) { + data++; + if (ch == '>') { + xml->curr_node->status = ACL_XML_S_LGT; + xml_parse_check_self_closed(xml); + if ((xml->curr_node->flag & ACL_XML_F_SELF_CL) + && xml->curr_node->last_ch == '/') + { + acl_vstring_truncate(xml->curr_node->ltag, + LEN(xml->curr_node->ltag) - 1); + } + break; + } else if (IS_SPACE(ch)) { + xml->curr_node->status = ACL_XML_S_ATTR; + xml->curr_node->last_ch = ch; + break; + } else { + ACL_VSTRING_ADDCH(xml->curr_node->ltag, ch); + xml->curr_node->last_ch = ch; + } + } + + ACL_VSTRING_TERMINATE(xml->curr_node->ltag); + return (data); +} + +static const char *xml_parse_attr(ACL_XML *xml, const char *data) +{ + int ch; + ACL_XML_ATTR *attr = xml->curr_node->curr_attr; + + if (attr == NULL || LEN(attr->name) == 0) { + SKIP_SPACE(data); /* 略过 ' ', '\t' */ + if (*data == 0) + return (NULL); + SKIP_WHILE(*data == '=', data); + if (*data == 0) + return (NULL); + } + + if (*data == '>') { + xml->curr_node->status = ACL_XML_S_LGT; + xml_parse_check_self_closed(xml); + xml->curr_node->curr_attr = NULL; + data++; + return (data); + } + + xml->curr_node->last_ch = *data; + if (*data == '/') { + data++; + return (data); + } + + if (attr == NULL) { + attr = acl_xml_attr_alloc(xml->curr_node); + xml->curr_node->curr_attr = attr; + } + + while ((ch = *data) != 0) { + xml->curr_node->last_ch = ch; + if (ch == '=') { + xml->curr_node->status = ACL_XML_S_AVAL; + data++; + break; + } + if (!IS_SPACE(ch)) + ACL_VSTRING_ADDCH(attr->name, ch); + data++; + } + + ACL_VSTRING_TERMINATE(attr->name); + return (data); +} + +static const char *xml_parse_attr_val(ACL_XML *xml, const char *data) +{ + int ch; + ACL_XML_ATTR *attr = xml->curr_node->curr_attr; + + if (LEN(attr->value) == 0 && !attr->quote) { + SKIP_SPACE(data); + if (IS_QUOTE(*data)) { + attr->quote = *data++; + } + if (*data == 0) { + return (NULL); + } + } + + while ((ch = *data) != 0) { + if (attr->backslash) { + ACL_VSTRING_ADDCH(attr->value, ch); + xml->curr_node->last_ch = ch; + attr->backslash = 0; + } else if (ch == '\\') { + if (attr->part_word) { + ACL_VSTRING_ADDCH(attr->value, ch); + attr->part_word = 0; + } + else + attr->backslash = 1; + } else if (attr->quote) { + if (ch == attr->quote) { + xml->curr_node->status = ACL_XML_S_ATTR; + xml->curr_node->last_ch = ch; + data++; + break; + } + ACL_VSTRING_ADDCH(attr->value, ch); + xml->curr_node->last_ch = ch; + } else if (ch == '>') { + xml->curr_node->status = ACL_XML_S_LGT; + xml_parse_check_self_closed(xml); + data++; + break; + } else if (IS_SPACE(ch)) { + xml->curr_node->status = ACL_XML_S_ATTR; + xml->curr_node->last_ch = ch; + data++; + break; + } else { + ACL_VSTRING_ADDCH(attr->value, ch); + xml->curr_node->last_ch = ch; + + if ((xml->flag & ACL_XML_FLAG_PART_WORD)) { + /* 处理半个汉字的情形 */ + if (attr->part_word) + attr->part_word = 0; + else if (ch < 0) + attr->part_word = 1; + } + } + data++; + } + + ACL_VSTRING_TERMINATE(attr->value); + + if (xml->curr_node->status != ACL_XML_S_AVAL) { + /* 将该标签ID号映射至哈希表中,以便于快速查询 */ + if (IS_ID(STR(attr->name)) && LEN(attr->value) > 0) { + const char *ptr = STR(attr->value); + + /* 防止重复ID被插入现象 */ + if (acl_htable_find(xml->id_table, ptr) == NULL) { + acl_htable_enter(xml->id_table, ptr, attr); + + /* 只有当该属性被加入哈希表后才会赋于结点的 id */ + xml->curr_node->id = attr->value; + } + } + + /* 必须将该结点的当前属性对象置空,以便于继续解析时 + * 可以创建新的属性对象 + */ + xml->curr_node->curr_attr = NULL; + } + return (data); +} + +static const char *xml_parse_text(ACL_XML *xml, const char *data) +{ + int ch; + + if (LEN(xml->curr_node->text) == 0) { + SKIP_SPACE(data); + if (*data == 0) + return (NULL); + } + + while ((ch = *data) != 0) { + if (ch == '<') { + xml->curr_node->status = ACL_XML_S_RLT; + data++; + break; + } + ACL_VSTRING_ADDCH(xml->curr_node->text, ch); + data++; + } + + ACL_VSTRING_TERMINATE(xml->curr_node->text); + + if (xml->curr_node->status != ACL_XML_S_RLT) + return (data); + + if ((xml->curr_node->flag & ACL_XML_F_SELF_CL)) { + /* 如果该标签是自关闭类型,则应使父结点直接跳至右边 '/' 处理位置, + * 同时使本结点跳至右边 '>' 处理位置 + */ + ACL_XML_NODE *parent = acl_xml_node_parent(xml->curr_node); + if (parent != xml->root) + parent->status = ACL_XML_S_RLT; + xml->curr_node->status = ACL_XML_S_RGT; + } + + if (LEN(xml->curr_node->text) == 0) + return (data); + + return (data); +} + +static const char *xml_parse_right_lt(ACL_XML *xml, const char *data) +{ + ACL_XML_NODE *node; + + SKIP_SPACE(data); + if (*data == 0) + return (NULL); + if (*data == '/') { + xml->curr_node->status = ACL_XML_S_RTAG; + data++; + return (data); + } else if ((xml->curr_node->flag & ACL_XML_F_LEAF)) { + ACL_VSTRING_ADDCH(xml->curr_node->text, '<'); + ACL_VSTRING_ADDCH(xml->curr_node->text, *data); + ACL_VSTRING_TERMINATE(xml->curr_node->text); + xml->curr_node->status = ACL_XML_S_TXT; + data++; + return (data); + } + + /* 说明遇到了当前结点的子结点 */ + + /* 重新设置当前结点状态,以便于其可以找到 "curr_node->status = ACL_XML_S_TXT; + + /* 创建新的子结点,并将其加入至当前结点的子结点集合中 */ + + node = acl_xml_node_alloc(xml); + acl_xml_node_add_child(xml->curr_node, node); + node->depth = xml->curr_node->depth + 1; + if (node->depth > xml->depth) + xml->depth = node->depth; + xml->curr_node = node; + xml->curr_node->status = ACL_XML_S_LLT; + return (data); +} + +static const char *xml_parse_right_gt(ACL_XML *xml, const char *data) +{ + xml->curr_node = acl_xml_node_parent(xml->curr_node); + if (xml->curr_node == xml->root) { + xml->curr_node = NULL; + } + return (data); +} + +/* 因为该父结点其实为叶结点,所以需要更新附属于该伪父结点的 + * 子结点的深度值,都应与该伪父结点相同 + */ +static void update_children_depth(ACL_XML_NODE *parent) +{ + ACL_ITER iter; + ACL_XML_NODE *child; + + acl_foreach(iter, parent) { + child = (ACL_XML_NODE*) iter.data; + child->depth = parent->depth; + update_children_depth(child); + } +} + +/* 查找与右标签相同的父结点 */ +static int search_match_node(ACL_XML *xml) +{ + ACL_XML_NODE *parent, *node; + ACL_ARRAY *nodes = acl_array_create(10); + ACL_ITER iter; + + parent = acl_xml_node_parent(xml->curr_node); + if (parent != xml->root) + acl_array_append(nodes, xml->curr_node); + + while (parent != xml->root) { + if (acl_strcasecmp(STR(xml->curr_node->rtag), + STR(parent->ltag)) == 0) + { + acl_vstring_strcpy(parent->rtag, + STR(xml->curr_node->rtag)); + ACL_VSTRING_RESET(xml->curr_node->rtag); + ACL_VSTRING_TERMINATE(xml->curr_node->rtag); + parent->status = ACL_XML_S_RGT; + xml->curr_node = parent; + break; + } + + acl_array_append(nodes, parent); + + parent = acl_xml_node_parent(parent); + } + + if (parent == xml->root) { + acl_array_free(nodes, NULL); + return (0); + } + + acl_foreach_reverse(iter, nodes) { + node = (ACL_XML_NODE*) iter.data; + acl_ring_detach(&node->node); + node->flag |= ACL_XML_F_LEAF; + node->depth = parent->depth + 1; + update_children_depth(node); + acl_xml_node_add_child(parent, node); + } + acl_array_free(nodes, NULL); + return (1); +} + +static const char *xml_parse_right_tag(ACL_XML *xml, const char *data) +{ + int ch; + ACL_XML_NODE *curr_node = xml->curr_node; + + if (LEN(curr_node->rtag) == 0) { + SKIP_SPACE(data); + if (*data == 0) + return (NULL); + } + + while ((ch = *data) != 0) { + if (ch == '>') { + curr_node->status = ACL_XML_S_RGT; + data++; + break; + } + + if (!IS_SPACE(ch)) + ACL_VSTRING_ADDCH(curr_node->rtag, ch); + data++; + } + + ACL_VSTRING_TERMINATE(curr_node->rtag); + + if (curr_node->status != ACL_XML_S_RGT) + return (data); + + if (acl_strcasecmp(STR(curr_node->ltag), STR(curr_node->rtag)) != 0) { + int ret = 0; + + if ((xml->flag & ACL_XML_FLAG_IGNORE_SLASH)) + ret = search_match_node(xml); + if (ret == 0) { + /* 如果结点标签名与开始标签名不匹配, + * 则需要继续寻找真正的结束标签 + */ + acl_vstring_strcat(curr_node->text, + STR(curr_node->rtag)); + ACL_VSTRING_RESET(curr_node->rtag); + ACL_VSTRING_TERMINATE(curr_node->rtag); + + /* 重新设置当前结点状态,以便于其可以找到 "status = ACL_XML_S_TXT; + } + } + return (data); +} + +static struct XML_STATUS_MACHINE status_tab[] = { + { ACL_XML_S_NXT, xml_parse_next_left_lt }, + { ACL_XML_S_LLT, xml_parse_left_lt }, + { ACL_XML_S_LGT, xml_parse_left_gt }, + { ACL_XML_S_LCH, xml_parse_left_ch }, + { ACL_XML_S_LEM, xml_parse_left_em }, + { ACL_XML_S_LTAG, xml_parse_left_tag }, + { ACL_XML_S_RLT, xml_parse_right_lt }, + { ACL_XML_S_RGT, xml_parse_right_gt }, + { ACL_XML_S_RTAG, xml_parse_right_tag }, + { ACL_XML_S_ATTR, xml_parse_attr }, + { ACL_XML_S_AVAL, xml_parse_attr_val }, + { ACL_XML_S_TXT, xml_parse_text }, + { ACL_XML_S_MTAG, xml_parse_meta_tag }, + { ACL_XML_S_MTXT, xml_parse_meta_text }, + { ACL_XML_S_MCMT, xml_parse_meta_comment }, + { ACL_XML_S_MEND, xml_parse_meta_end }, +}; + +void acl_xml_update(ACL_XML *xml, const char *data) +{ + const char *ptr = data; + + /* XML 解析器状态机循环处理过程 */ + + while (ptr && *ptr) { + if (xml->curr_node == NULL) { + SKIP_SPACE(ptr); + if (*ptr == 0) + break; + xml->curr_node = acl_xml_node_alloc(xml); + acl_xml_node_add_child(xml->root, xml->curr_node); + xml->curr_node->depth = xml->root->depth + 1; + if (xml->curr_node->depth > xml->depth) + xml->depth = xml->curr_node->depth; + } + ptr = status_tab[xml->curr_node->status].callback(xml, ptr); + } +} diff --git a/lib_acl/src/xml/acl_xml_util.c b/lib_acl/src/xml/acl_xml_util.c new file mode 100644 index 000000000..c43742c69 --- /dev/null +++ b/lib_acl/src/xml/acl_xml_util.c @@ -0,0 +1,467 @@ +#include "StdAfx.h" +#include +#ifndef ACL_PREPARE_COMPILE + +#include "stdlib/acl_vstream.h" +#include "stdlib/acl_iterator.h" +#include "stdlib/acl_vstring.h" +#include "stdlib/acl_mystring.h" +#include "stdlib/acl_token_tree.h" +#include "stdlib/acl_array.h" +#include "stdlib/acl_argv.h" +#include "xml/acl_xml.h" + +#endif + +#define STR acl_vstring_str +#define LEN ACL_VSTRING_LEN + +static ACL_TOKEN *tag_tree = NULL; + +void acl_xml_tag_init(void) +{ + const char *tag_tab = "input|p, meta|p, link|p, hr|p, br|p"; + + if (tag_tree == NULL) + tag_tree = acl_token_tree_create(tag_tab); +} + +void acl_xml_tag_add(const char *tag) +{ + if (tag_tree) { + char buf[256]; + + ACL_SAFE_STRNCPY(buf, tag, sizeof(buf)); + acl_lowercase(buf); + acl_token_tree_add(tag_tree, buf, ACL_TOKEN_F_PASS, NULL); + } +} + +int acl_xml_tag_selfclosed(const char *tag) +{ + const ACL_TOKEN *token; + char buf[256]; + + if (tag_tree == NULL) + return (0); + + ACL_SAFE_STRNCPY(buf, tag, sizeof(buf)); + acl_lowercase(buf); + token = acl_token_tree_word_match(tag_tree, buf); + if (token) + return (1); + else + return (0); +} + +int acl_xml_tag_leaf(const char *tag) +{ + if (strcasecmp(tag, "script") == 0) + return (1); + return (0); +} + +void acl_xml_free_array(ACL_ARRAY *a) +{ + acl_array_destroy(a, NULL); +} + +ACL_ARRAY *acl_xml_getElementsByTagName(ACL_XML *xml, const char *tag) +{ + ACL_ITER iter; + ACL_ARRAY *a = acl_array_create(10); + + acl_foreach(iter, xml) { + ACL_XML_NODE *node = (ACL_XML_NODE*) iter.data; + if (strcasecmp(tag, STR(node->ltag)) == 0) { + acl_array_append(a, node); + } + } + + if (acl_array_size(a) == 0) { + acl_array_destroy(a, NULL); + return (NULL); + } + + return (a); +} + +ACL_ARRAY *acl_xml_getElementsByTags(ACL_XML *xml, const char *tags) +{ + ACL_ARGV *tokens = acl_argv_split(tags, "/"); + ACL_ARRAY *a, *ret; + ACL_ITER iter; + + a = acl_xml_getElementsByTagName(xml, tokens->argv[tokens->argc - 1]); + if (a == NULL) { + acl_argv_free(tokens); + return (NULL); + } + + ret = acl_array_create(acl_array_size(a)); + + acl_foreach(iter, a) { + ACL_XML_NODE *node = (ACL_XML_NODE*) iter.data, *parent = node; + int i = tokens->argc - 2; + while (i >= 0 && (parent = parent->parent) != xml->root) { + if (strcasecmp(tokens->argv[i], "*") != 0 && + strcasecmp(tokens->argv[i], STR(parent->ltag)) != 0) + { + break; + } + i--; + } + if (i == -1) + ret->push_back(ret, node); + } + + acl_xml_free_array(a); + acl_argv_free(tokens); + + if (acl_array_size(ret) == 0) { + acl_array_free(ret, NULL); + ret = NULL; + } + return (ret); +} + +ACL_ARRAY *acl_xml_getElementsByAttr(ACL_XML *xml, + const char *name, const char *value) +{ + ACL_ITER iter; + ACL_ARRAY *a = acl_array_create(10); + + acl_foreach(iter, xml) { + ACL_ITER iter2; + ACL_XML_NODE *node = (ACL_XML_NODE*) iter.data; + + acl_foreach(iter2, node->attr_list) { + ACL_XML_ATTR *attr = (ACL_XML_ATTR*) iter2.data; + + if (strcasecmp(STR(attr->name), name) == 0 + && strcasecmp(STR(attr->value), value) == 0) + { + acl_array_append(a, node); + break; + } + } + } + + if (acl_array_size(a) == 0) { + acl_array_destroy(a, NULL); + return (NULL); + } + + return (a); +} + +ACL_ARRAY *acl_xml_getElementsByName(ACL_XML *xml, const char *value) +{ + return (acl_xml_getElementsByAttr(xml, "name", value)); +} + +ACL_XML_ATTR *acl_xml_getAttrById(ACL_XML *xml, const char *id) +{ + return (acl_htable_find(xml->id_table, id)); +} + +const char *acl_xml_getAttrValueById(ACL_XML *xml, const char *id) +{ + ACL_XML_ATTR *attr = acl_xml_getAttrById(xml, id); + + if (attr == NULL) { + return (NULL); + } + return (STR(attr->value)); +} + +ACL_XML_NODE *acl_xml_getElementById(ACL_XML *xml, const char *id) +{ + ACL_XML_ATTR *attr = acl_xml_getAttrById(xml, id); + + if (attr == NULL) + return (NULL); + return (attr->node); +} +ACL_XML_NODE *acl_xml_getElementMeta(ACL_XML *xml, const char *tag) +{ + ACL_ITER iter; + ACL_XML_NODE *node; + + acl_foreach(iter, xml) { + node = (ACL_XML_NODE*) iter.data; + if ((node->flag & ACL_XML_F_META_QM) == 0 || node->ltag == NULL) + continue; + if (strcasecmp(tag, STR(node->ltag)) == 0) + return node; + } + + return NULL; +} + +const char *acl_xml_getEncoding(ACL_XML *xml) +{ + ACL_XML_NODE *node = acl_xml_getElementMeta(xml, "xml"); + + if (node == NULL) + return NULL; + return acl_xml_getElementAttrVal(node, "encoding"); +} + +const char *acl_xml_getType(ACL_XML *xml) +{ + ACL_XML_NODE *node = acl_xml_getElementMeta(xml, "xml-stylesheet"); + + if (node == NULL) + return NULL; + return acl_xml_getElementAttrVal(node, "type"); +} + +ACL_XML_ATTR *acl_xml_getElementAttr(ACL_XML_NODE *node, const char *name) +{ + ACL_ITER iter; + + acl_foreach(iter, node->attr_list) { + ACL_XML_ATTR *attr = (ACL_XML_ATTR*) iter.data; + + if (strcasecmp(STR(attr->name), name) == 0) { + return (attr); + } + } + + return (NULL); +} + +const char *acl_xml_getElementAttrVal(ACL_XML_NODE *node, const char *name) +{ + ACL_XML_ATTR *attr = acl_xml_getElementAttr(node, name); + + if (attr) { + return (STR(attr->value)); + } + + return (NULL); +} + +int acl_xml_removeElementAttr(ACL_XML_NODE *node, const char *name) +{ + ACL_XML_ATTR *attr = acl_xml_getElementAttr(node, name); + + if (attr == NULL) { + return (-1); + } + + if (acl_array_delete_obj(node->attr_list, attr, NULL) != 0) { + return (-1); + } + + if (node->id == attr->value) { + acl_htable_delete(node->xml->id_table, STR(attr->value), NULL); + node->id = NULL; + } + + acl_xml_attr_free(attr); + return (0); +} + +ACL_XML_ATTR *acl_xml_addElementAttr(ACL_XML_NODE *node, + const char *name, const char *value) +{ + ACL_XML_ATTR *attr = acl_xml_getElementAttr(node, name); + + if (attr) { + acl_vstring_strcpy(attr->value, value); + return (attr); + } + + attr = acl_xml_attr_alloc(node); + acl_vstring_strcpy(attr->name, name); + acl_vstring_strcpy(attr->value, value); + acl_array_append(node->attr_list, attr); + + return (attr); +} + +ACL_XML_NODE *acl_xml_create_node(ACL_XML *xml, const char* tagname, const char* text) +{ + ACL_XML_NODE *node = acl_xml_node_alloc(xml); + + acl_assert(tagname && *tagname); + acl_vstring_strcpy(node->ltag, tagname); + if (text && *text) + acl_vstring_strcpy(node->text, text); + return (node); +} + +ACL_XML_ATTR *acl_xml_node_add_attr(ACL_XML_NODE *node, const char *name, const char *value) +{ + ACL_XML_ATTR *attr = acl_xml_attr_alloc(node); + + acl_assert(name && *name); + acl_vstring_strcpy(attr->name, name); + if (value && *value) + acl_vstring_strcpy(attr->value, value); + return (attr); +} + +void acl_xml_node_add_attrs(ACL_XML_NODE *node, ...) +{ + va_list ap; + const char *name, *value; + + va_start(ap, node); + while ((name = va_arg(ap, const char*)) != 0) { + value = va_arg(ap, const char*); + acl_assert(value); + acl_xml_node_add_attr(node, name, value); + } + va_end(ap); +} + +void acl_xml_node_set_text(ACL_XML_NODE *node, const char *text) +{ + if (text && *text) + acl_vstring_strcpy(node->text, text); +} + +static void xml_escape_append(ACL_VSTRING *buf, const char *src, int quoted) +{ + const unsigned char *ptr = (const unsigned char*) src; + + if (quoted) + ACL_VSTRING_ADDCH(buf, '"'); + while (*ptr) { + if (*ptr == '"' || *ptr == '\\' || *ptr == '<' || *ptr == '>') + ACL_VSTRING_ADDCH(buf, '\\'); + ACL_VSTRING_ADDCH(buf, *ptr); + ptr++; + } + if (quoted) + ACL_VSTRING_ADDCH(buf, '"'); + ACL_VSTRING_TERMINATE(buf); +} + +ACL_VSTRING *acl_xml_build(ACL_XML *xml, ACL_VSTRING *buf) +{ + ACL_XML_ATTR *attr; + ACL_XML_NODE *node; + ACL_ITER iter1, iter2; + + if (buf == NULL) + buf = acl_vstring_alloc(256); + + acl_foreach(iter1, xml) { + node = (ACL_XML_NODE*) iter1.data; + if (ACL_XML_IS_COMMENT(node)) { + acl_vstring_strcat(buf, ""); + continue; + } + if ((node->flag & ACL_XML_F_META_QM) || (node->flag & ACL_XML_F_META_EM)) { + acl_vstring_strcat(buf, ">"); + continue; + } + if (LEN(node->text) == 0) + acl_vstring_strcat(buf, " />"); + else + acl_vstring_sprintf_append(buf, ">%s", + STR(node->text), STR(node->ltag)); + + while (node->parent != node->xml->root && acl_xml_node_next(node) == NULL) { + acl_vstring_sprintf_append(buf, "", STR(node->parent->ltag)); + node = node->parent; + } + } + + return (buf); +} + +void acl_xml_dump(ACL_XML *xml, ACL_VSTREAM *fp) +{ + int i; + ACL_ITER iter1; + const char *sep = "\t"; + + acl_foreach(iter1, xml) { + ACL_ITER iter2; + ACL_XML_NODE *node = (ACL_XML_NODE*) iter1.data; + + for (i = 1; i < node->depth; i++) + acl_vstream_buffed_fprintf(fp, "%s", sep); + + if (ACL_XML_IS_COMMENT(node)) + acl_vstream_buffed_fprintf(fp, "comment> text: %s\n", + STR(node->text)); + else + acl_vstream_buffed_fprintf(fp, "tag> %s, text: %s\n", + STR(node->ltag), STR(node->text)); + + acl_foreach(iter2, node->attr_list) { + ACL_XML_ATTR *attr = (ACL_XML_ATTR*) iter2.data; + + for (i = 1; i < node->depth; i++) + acl_vstream_buffed_fprintf(fp, "%s", sep); + + acl_vstream_buffed_fprintf(fp, "%sattr> %s: %s\n", + sep, STR(attr->name), STR(attr->value)); + } + } + acl_vstream_fflush(fp); +} + +void acl_xml_dump2(ACL_XML *xml, ACL_VSTRING *buf) +{ + int i; + ACL_ITER iter1; + const char *sep = "\t"; + + acl_foreach(iter1, xml) { + ACL_ITER iter2; + ACL_XML_NODE *node = (ACL_XML_NODE*) iter1.data; + + for (i = 1; i < node->depth; i++) + acl_vstring_strcat(buf, sep); + + if (ACL_XML_IS_COMMENT(node)) + acl_vstring_sprintf_append(buf, + "comment> text: %s\n", STR(node->text)); + else + acl_vstring_sprintf_append(buf, "tag> %s, text: %s\n", + STR(node->ltag), STR(node->text)); + + acl_foreach(iter2, node->attr_list) { + ACL_XML_ATTR *attr = (ACL_XML_ATTR*) iter2.data; + + for (i = 1; i < node->depth; i++) + acl_vstring_strcat(buf, sep); + + acl_vstring_sprintf_append(buf, "%sattr> %s: %s\n", + sep, STR(attr->name), STR(attr->value)); + } + } +} diff --git a/lib_acl/todo.txt b/lib_acl/todo.txt new file mode 100644 index 000000000..d20c0c02b --- /dev/null +++ b/lib_acl/todo.txt @@ -0,0 +1,22 @@ +待解决的问题及待增加的功能列表: +---------------------------------------------------------------------------------------------------- + +1) acl_master 框架在切换子进程身份(使用 setuid)后,子进程如果出现错误无法产生 core 文件 --- 解决 +2) acl_trace.c, 当编译时打开 -O2, -O3 选项后无法知道确切的堆栈位置信息,看来 GNU 提供的 +backtrace 的相关函数还是不够完善 +3) acl_html_code.c, 编码部分还没有完全解析 html 所有的特殊字符, +所以 acl_html_encode 只能对255以下的值进行编码 +4) 当事件引擎为 win32 消息引擎(ACL_EVENT_WMSG) 时,acl_aio_read.c,acl_aio_write.c 两个函数库暂不支持 +超时功能 +5) 在采用内存池后,由于 acl_ioctl_server.c 中的线程池是半驻留的,当某个线程退出时归属于它的内存池如果 +正在被其它线程引用而无法释放,需要在主线程中增加功能定期清理一些残留的未释放的内存池,所以不建议在使用 +acl_ioctl_server.c 的模板程序中采用内存池功能 +6) 应该将 xyssl 库引用进来,它要比 openssl 简单实用 +7) acl_pthread_tls_get 函数有一个线程冲突的BUG,其它调用此函数的地方需要修改成标准的事 --- 解决, +使用者在调用本函数时输入的参数 KEY 需要声明为 static __thread acl_pthread_key_t key = -1 +8) acl_master 应该增加了一个定时器,用来定期扫描配置文件,从而将新添加的服务自动加载,同时将 +禁止的服务自动卸载 +9) 配置文件中应支持变量 +10) acl_master 的子进程的监听地址应允许在配置文件中写多个 -- 完成 +11) acl_master 在重读配置是需要支持预启动机制 -- 完成 +12) event 模块需要进一步优化 diff --git a/lib_acl_cpp/Doxyfile b/lib_acl_cpp/Doxyfile new file mode 100644 index 000000000..c1fbd66eb --- /dev/null +++ b/lib_acl_cpp/Doxyfile @@ -0,0 +1,1844 @@ +# Doxyfile 1.8.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 = acl_cpp + +# 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 = 1.1.1.2 + +# 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 = + +# 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 = E:/work/online_help/acl_cpp/logo.png + +# 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 = E:\work\online_help\acl_cpp + +# 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 = Chinese + +# 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 = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# 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. Note that you specify absolute paths here, but also +# relative paths, which will be relative from the directory where doxygen is +# started. + +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 = YES + +# 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 = NO + +# 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 = YES + +# 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 + +# When enabled doxygen tries to link words that correspond to documented classes, +# or namespaces to their corresponding documentation. Such a link can be +# prevented in individual cases by by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. + +AUTOLINK_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 = YES + +# 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 = YES + +# 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 = NO + +# 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 = + +# 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. + +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 = *.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 + +# 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 = YES + +# 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 = YES + +# 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 = NO + +# 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 = YES + +# 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 = YES + +# 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 left blank doxygen will +# generate a default style sheet. Note that it is recommended to use +# HTML_EXTRA_STYLESHEET instead of this one, as it is more robust and this +# tag will in the future become obsolete. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional +# user-defined cascading style sheet that is included after the standard +# style sheets created by doxygen. Using this option one can overrule +# certain style aspects. This is preferred over using HTML_STYLESHEET +# since it does not replace the standard style sheet and is therefor more +# robust against future updates. Doxygen will copy the style sheet file to +# the output directory. + +HTML_EXTRA_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 = YES + +# 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 = acl_cpp_help.chm + +# 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 = YES + +# 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://www.mathjax.org/mathjax + +# 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 = YES + +#--------------------------------------------------------------------------- +# 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 = NO + +# 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 = NO + +# 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 = NO + +# 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 = YES + +#--------------------------------------------------------------------------- +# 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 = YES + +# 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 = YES + +# 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 = YES + +# 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 = NO + +# 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/lib_acl_cpp/Makefile b/lib_acl_cpp/Makefile new file mode 100644 index 000000000..11abd654f --- /dev/null +++ b/lib_acl_cpp/Makefile @@ -0,0 +1,263 @@ +SHELL = /bin/sh +CC = g++ +AR = ar +ARFL = rv +#ARFL = cru +RANLIB = ranlib + +#-Wcast-qual +CFLAGS = -c -g -W -Wall -Wcast-align \ +-Wpointer-arith -Werror -Wshadow -O3 \ +-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS \ +-Wno-long-long \ +-fPIC \ +-DHAS_MYSQL \ +-DHAS_SQLITE \ +-Wformat +#-DHAS_POLARSSL +#-DUSE_DYNAMIC + +########################################################### +#Check system: +# Linux, SunOS, Solaris, BSD variants, AIX, HP-UX +SYSLIB = +CHECKSYSRES = @echo "Unknow system type!";exit 1 +UNIXNAME = $(shell uname -sm) + +ifeq ($(CC),) + CC = g++ +endif + +# For FreeBSD +ifeq ($(findstring FreeBSD, $(UNIXNAME)), FreeBSD) + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DFREEBSD -D_REENTRANT +endif + +# For Linux +ifeq ($(findstring Linux, $(UNIXNAME)), Linux) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DLINUX2 -D_REENTRANT +endif + +# For SunOS +ifeq ($(findstring SunOS, $(UNIXNAME)), SunOS) + ifeq ($(findstring 86, $(UNIXNAME)), 86) + SYSLIB = -lsocket -lnsl -lrt + endif + ifeq ($(findstring sun4u, $(UNIXNAME)), sun4u) + SYSLIB = -lsocket -lnsl -lrt + endif + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DSUNOS5 -D_REENTRANT +endif + +# For HP-UX +ifeq ($(findstring HP-UX, $(UNIXNAME)), HP-UX) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DHP_UX -DHPUX11 + PLAT_NAME=hp-ux +endif + +#Find system type. +ifneq ($(SYSPATH),) + CHECKSYSRES = @echo "System is $(shell uname -sm)" +endif +########################################################### + +OBJ_PATH_DST = ./Debug +LIB_PATH_DST = ./lib +DEF_PATH_DST = ./Debug + +CFLAGS += -I./src -I./include -I../lib_acl/include -I../lib_protocol/include \ + -I../include/sqlite -I../include/mysql -I../include/zlib -I../include + +#Project's objs +OBJS_DST = $(patsubst %.cpp, $(OBJ_PATH_DST)/%.o, $(notdir $(wildcard src/*.cpp))) \ + $(patsubst %.cpp, $(OBJ_PATH_DST)/%.o, $(notdir $(wildcard src/stdlib/*.cpp))) \ + $(patsubst %.cpp, $(OBJ_PATH_DST)/%.o, $(notdir $(wildcard src/stream/*.cpp))) \ + $(patsubst %.cpp, $(OBJ_PATH_DST)/%.o, $(notdir $(wildcard src/master/*.cpp))) \ + $(patsubst %.cpp, $(OBJ_PATH_DST)/%.o, $(notdir $(wildcard src/ipc/*.cpp))) \ + $(patsubst %.cpp, $(OBJ_PATH_DST)/%.o, $(notdir $(wildcard src/db/*.cpp))) \ + $(patsubst %.cpp, $(OBJ_PATH_DST)/%.o, $(notdir $(wildcard src/queue/*.cpp))) \ + $(patsubst %.cpp, $(OBJ_PATH_DST)/%.o, $(notdir $(wildcard src/http/*.cpp))) \ + $(patsubst %.cpp, $(OBJ_PATH_DST)/%.o, $(notdir $(wildcard src/hsocket/*.cpp))) \ + $(patsubst %.cpp, $(OBJ_PATH_DST)/%.o, $(notdir $(wildcard src/beanstalk/*.cpp))) \ + $(patsubst %.cpp, $(OBJ_PATH_DST)/%.o, $(notdir $(wildcard src/memcache/*.cpp))) \ + $(patsubst %.cpp, $(OBJ_PATH_DST)/%.o, $(notdir $(wildcard src/session/*.cpp))) \ + $(patsubst %.cpp, $(OBJ_PATH_DST)/%.o, $(notdir $(wildcard src/mime/*.cpp))) \ + $(patsubst %.cpp, $(OBJ_PATH_DST)/%.o, $(notdir $(wildcard src/mime/internal/*.cpp))) \ + $(patsubst %.cpp, $(OBJ_PATH_DST)/%.o, $(notdir $(wildcard src/connpool/*.cpp))) \ + +OBJS_DEF = $(patsubst %.cpp, $(DEF_PATH_DST)/%.inc, $(notdir $(wildcard src/*.cpp))) \ + $(patsubst %.cpp, $(DEF_PATH_DST)/%.inc, $(notdir $(wildcard src/stdlib/*.cpp))) \ + $(patsubst %.cpp, $(DEF_PATH_DST)/%.inc, $(notdir $(wildcard src/stream/*.cpp))) \ + $(patsubst %.cpp, $(DEF_PATH_DST)/%.inc, $(notdir $(wildcard src/master/*.cpp))) \ + $(patsubst %.cpp, $(DEF_PATH_DST)/%.inc, $(notdir $(wildcard src/ipc/*.cpp))) \ + $(patsubst %.cpp, $(DEF_PATH_DST)/%.inc, $(notdir $(wildcard src/db/*.cpp))) \ + $(patsubst %.cpp, $(DEF_PATH_DST)/%.inc, $(notdir $(wildcard src/queue/*.cpp))) \ + $(patsubst %.cpp, $(DEF_PATH_DST)/%.inc, $(notdir $(wildcard src/http/*.cpp))) \ + $(patsubst %.cpp, $(DEF_PATH_DST)/%.inc, $(notdir $(wildcard src/hsocket/*.cpp))) \ + $(patsubst %.cpp, $(DEF_PATH_DST)/%.inc, $(notdir $(wildcard src/beanstalk/*.cpp))) \ + $(patsubst %.cpp, $(DEF_PATH_DST)/%.inc, $(notdir $(wildcard src/memcache/*.cpp))) \ + $(patsubst %.cpp, $(DEF_PATH_DST)/%.inc, $(notdir $(wildcard src/session/*.cpp))) \ + $(patsubst %.cpp, $(DEF_PATH_DST)/%.inc, $(notdir $(wildcard src/mime/*.cpp))) \ + $(patsubst %.cpp, $(DEF_PATH_DST)/%.inc, $(notdir $(wildcard src/mime/internal/*.cpp))) \ + $(patsubst %.cpp, $(DEF_PATH_DST)/%.inc, $(notdir $(wildcard src/connpool/*.cpp))) \ + +########################################################### +.PHONY = static shared clean +VERSION = 1.1.1.2 +DATE_NOW = 20`date +%y`.`date +%m`.`date +%d` + +all: static shared + +$(shell mkdir -p $(DEF_PATH_DST)) +ifneq ($(MAKECMDGOALS),clean) +-include $(OBJS_DEF) +endif + +COMPILE = $(CC) $(CFLAGS) +COMPILE_OBJ = @(echo 'building $<'; $(COMPILE) $< -o $@) +CREATE_DEF = @(echo 'creating $@'; rm -f $@; \ + $(COMPILE) -MM $< > $@.$$$$; \ + sed 's,.*.o\( \)*:,$(patsubst %.inc,%.o,$@) $@ :,g' < $@.$$$$ > $@; \ + rm -f $@.$$$$) + +########################################################### + +static: depends $(OBJS_DST) + @echo 'creating $(LIB_PATH_DST)/lib_acl_cpp.a' + @$(AR) $(ARFL) $(LIB_PATH_DST)/lib_acl_cpp.a $(OBJS_DST) + @$(RANLIB) $(LIB_PATH_DST)/lib_acl_cpp.a + @echo 'create $(LIB_PATH_DST)/lib_acl_cpp.a ok!' + @(cd samples; make) + +shared_ldflags = -l_protocol -l_acl \ + -lmysqlclient -lsqlite3 -lrt -lpthread -lz -ldl +shared: depends $(OBJS_DST) + @echo 'creating $(LIB_PATH_DST)/lib_acl_cpp.so' + @if test -n "$(rpath)"; then \ + $(CC) -shared -o $(LIB_PATH_DST)/lib_acl_cpp.so $(OBJS_DST) \ + -L$(rpath) $(shared_ldflags) -Wl,-rpath,$(rpath); \ + echo 'build $(LIB_PATH_DST)/lib_acl_cpp.so ok!'; \ + else \ + echo 'skip build $(LIB_PATH_DST)/lib_acl_cpp.so; usage: make rpath=xxx'; \ + fi + +depends: $(OBJS_DEF) + +# src +$(OBJ_PATH_DST)/%.o: ./src/%.cpp + $(COMPILE_OBJ) +$(OBJ_PATH_DST)/%.o: ./src/stdlib/%.cpp + $(COMPILE_OBJ) +$(OBJ_PATH_DST)/%.o: ./src/stream/%.cpp + $(COMPILE_OBJ) +$(OBJ_PATH_DST)/%.o: ./src/master/%.cpp + $(COMPILE_OBJ) +$(OBJ_PATH_DST)/%.o: ./src/ipc/%.cpp + $(COMPILE_OBJ) +$(OBJ_PATH_DST)/%.o: ./src/db/%.cpp + $(COMPILE_OBJ) +$(OBJ_PATH_DST)/%.o: ./src/queue/%.cpp + $(COMPILE_OBJ) +$(OBJ_PATH_DST)/%.o: ./src/http/%.cpp + $(COMPILE_OBJ) +$(OBJ_PATH_DST)/%.o: ./src/hsocket/%.cpp + $(COMPILE_OBJ) +$(OBJ_PATH_DST)/%.o: ./src/beanstalk/%.cpp + $(COMPILE_OBJ) +$(OBJ_PATH_DST)/%.o: ./src/memcache/%.cpp + $(COMPILE_OBJ) +$(OBJ_PATH_DST)/%.o: ./src/session/%.cpp + $(COMPILE_OBJ) +$(OBJ_PATH_DST)/%.o: ./src/connpool/%.cpp + $(COMPILE_OBJ) +$(OBJ_PATH_DST)/%.o: ./src/mime/%.cpp + $(COMPILE_OBJ) + +$(DEF_PATH_DST)/%.inc: ./src/%.cpp + $(CREATE_DEF) +$(DEF_PATH_DST)/%.inc: ./src/stdlib/%.cpp + $(CREATE_DEF) +$(DEF_PATH_DST)/%.inc: ./src/stream/%.cpp + $(CREATE_DEF) +$(DEF_PATH_DST)/%.inc: ./src/master/%.cpp + $(CREATE_DEF) +$(DEF_PATH_DST)/%.inc: ./src/ipc/%.cpp + $(CREATE_DEF) +$(DEF_PATH_DST)/%.inc: ./src/db/%.cpp + $(CREATE_DEF) +$(DEF_PATH_DST)/%.inc: ./src/queue/%.cpp + $(CREATE_DEF) +$(DEF_PATH_DST)/%.inc: ./src/http/%.cpp + $(CREATE_DEF) +$(DEF_PATH_DST)/%.inc: ./src/hsocket/%.cpp + $(CREATE_DEF) +$(DEF_PATH_DST)/%.inc: ./src/beanstalk/%.cpp + $(CREATE_DEF) +$(DEF_PATH_DST)/%.inc: ./src/memcache/%.cpp + $(CREATE_DEF) +$(DEF_PATH_DST)/%.inc: ./src/session/%.cpp + $(CREATE_DEF) +$(DEF_PATH_DST)/%.inc: ./src/connpool/%.cpp + $(CREATE_DEF) +$(DEF_PATH_DST)/%.inc: ./src/mime/%.cpp + $(CREATE_DEF) + +# mime +$(OBJ_PATH_DST)/%.o: ./src/mime/internal/%.cpp + $(COMPILE_OBJ) + +$(DEF_PATH_DST)/%.inc: ./src/mime/internal/%.cpp + $(CREATE_DEF) + +samples: $(lib_acl_cpp.a) + @(cd samples; make) +clean: + rm -f $(LIB_PATH_DST)/lib_acl_cpp.a + rm -f $(OBJS_DST) + rm -f $(OBJS_DEF) + @(cd samples; make clean) + +build_src: clean + @(echo "begin building src release...") + @(rm -rf acl_cpp) + @(echo "copy files ...") + @(mkdir acl_cpp) + @(cp -R src acl_cpp/) + @(cp -R mime acl_cpp/) + @(cp -R lib acl_cpp/) + @(cp -R include acl_cpp/) + @(cp -R samples acl_cpp/) + @(cp -R Debug acl_cpp/) + @(cp -R DebugDll acl_cpp/) + @(cp -R Release acl_cpp/) + @(cp -R ReleaseDll acl_cpp/) + @(cp -R bin acl_cpp/) + @(cp -R doc acl_cpp/) + @(cp lib_acl_cpp_vc2003.vcproj acl_cpp/) + @(cp acl_wrap_vc2003.sln acl_cpp/) + @(cp lib_acl_cpp_vc2010.vcxproj acl_cpp/) + @(cp acl_wrap_vc2010.sln acl_cpp/) + @(cp Makefile acl_cpp/) + @(cp changes.txt acl_cpp/) + @(cp ReadMe.txt acl_cpp/) + @(cp Doxyfile acl_cpp/) + @(echo "make tar package ...") + @(tar -cf acl_cpp.src.tar acl_cpp) + @(echo "make gzip package ...") + @(gzip -c acl_cpp.src.tar > acl_cpp.src.tgz) + @(rm acl_cpp.src.tar) + @(rm -rf acl_cpp) + @(echo "move acl_cpp.src.tgz to ../acl_cpp$(VERSION).src.$(DATE_NOW).tgz") + (mv acl_cpp.src.tgz ../acl_cpp$(VERSION).src.$(DATE_NOW).tgz) diff --git a/lib_acl_cpp/ReadMe.txt b/lib_acl_cpp/ReadMe.txt new file mode 100644 index 000000000..a8f061260 --- /dev/null +++ b/lib_acl_cpp/ReadMe.txt @@ -0,0 +1,18 @@ +1) 编译 +1.1) WIN32 平台:可以用 vc2003 或 vc2010 打开工程文件进行编译,编译后的 lib_acl.lib 库被拷贝至 +lib/ 目录下,如果需要编译 samples/ 下的例子,还需要将 acl_project 的编译后的库 +lib_acl_d.dll/lib_acl_d.lib, lib_acl.dll/lib_acl.lib, lib_acl_vc2003d.lib, lib_acl_vc2003.lib, +lib_acl_vc2010d.lib, lib_acl_vc2010.lib 以及 lib_protocol_d.dll/lib_protocol_d.lib, +lib_protocol.dll/lib_protocol.lib, lib_protocol_vc2003d.lib, lib_protocol_vc2003.lib, +lib_protocol_vc2010d.lib, lib_protocol_vc2010.lib 拷贝至 lib/ 目录下,另外,如果需要编译 +与压缩、数据库操作的示例,则还需要将 mysql, sqlite3 以及 zlib 的库拷贝至 lib/ 目录下,如果 +需要编译 ssl 相关的示例,需要将 polarssl 的库拷贝至 lib/ 目录下. + +1.2) Linux 平台:直接运行 make 便可在 lib/ 目录下生成 lib_acl.a 库,如果需要生成动态库,则需要运行 +make rpath=xxx, 其中 xxx 代表 mysql, sqlite, polarssl 库所在的路径 + +2) 依赖关系 +2.1) acl: 必须是 acl.2.1.2.8.src.2012.8.1.tgz 以后的版本, https://sourceforge.net/projects/acl/ +2.2) zlib: http://zlib.net/ +2.3) polarssl: http://polarssl.org/ +2.4) libmysqlcient diff --git a/lib_acl_cpp/app/ndb/ctl_server/ReadMe.txt b/lib_acl_cpp/app/ndb/ctl_server/ReadMe.txt new file mode 100644 index 000000000..ef0d1a2e8 --- /dev/null +++ b/lib_acl_cpp/app/ndb/ctl_server/ReadMe.txt @@ -0,0 +1,31 @@ +======================================================================== + 控制台应用程序 : ctrl_server 项目概况 +======================================================================== + +应用程序向导已为您创建了这个 ctrl_server 应用程序。 +此文件包含组成 ctrl_server 应用程序 +的每个文件的内容摘要。 + + +ctrl_server.vcproj + 这是用应用程序向导生成的 VC++ 项目的主项目文件。 + 它包含有关生成此文件的 Visual C++ 版本的信息,以及 + 有关用应用程序向导选择的 + 平台、配置和项目功能的信息。 + +ctrl_server.cpp + 这是主应用程序源文件。 + +///////////////////////////////////////////////////////////////////////////// +其他标准文件: + +StdAfx.h、StdAfx.cpp + 这些文件用于生成名为 ctrl_server.pch + 的预编译头(PCH)文件以及名为 StdAfx.obj 的预编译类型文件。 + +///////////////////////////////////////////////////////////////////////////// +其他注释: + +应用程序向导使用 "TODO:" 注释指示应添加或自定义的源代码部分。 + +///////////////////////////////////////////////////////////////////////////// diff --git a/lib_acl_cpp/app/ndb/ctl_server/ctl_server.cpp b/lib_acl_cpp/app/ndb/ctl_server/ctl_server.cpp new file mode 100644 index 000000000..c17dd7845 --- /dev/null +++ b/lib_acl_cpp/app/ndb/ctl_server/ctl_server.cpp @@ -0,0 +1,9 @@ +// ctrl_server.cpp : 定义控制台应用程序的入口点。 +// + +#include "stdafx.h" + +int main(int argc, char* argv[]) +{ + return 0; +} diff --git a/lib_acl_cpp/app/ndb/ctl_server/ctl_server.vcproj b/lib_acl_cpp/app/ndb/ctl_server/ctl_server.vcproj new file mode 100644 index 000000000..72e4d5a00 --- /dev/null +++ b/lib_acl_cpp/app/ndb/ctl_server/ctl_server.vcproj @@ -0,0 +1,183 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_acl_cpp/app/ndb/ctl_server/db.cpp b/lib_acl_cpp/app/ndb/ctl_server/db.cpp new file mode 100644 index 000000000..803d9a6f9 --- /dev/null +++ b/lib_acl_cpp/app/ndb/ctl_server/db.cpp @@ -0,0 +1,88 @@ +#include "StdAfx.h" +#include "db.h" + +db_idx::db_idx(db_tbl* tbl, const char* name, unsigned int id, idx_type_t type) +{ + acl_assert(tbl); + tbl_ = tbl; + acl_assert(name && *name); + name_ = acl_mystrdup(name); + acl_lowercase(name_); + id_ = id; + type_ = type; +} + +db_idx::~db_idx() +{ + acl_myfree(name_); +} + +////////////////////////////////////////////////////////////////////////// + +db_tbl::db_tbl(database* db, const char* name, unsigned int id) +{ + acl_assert(db); + db_ = db; + acl_assert(name && *name); + name_ = acl_mystrdup(name); + acl_lowercase(name_); + id_ = id; +} + +db_tbl::~db_tbl() +{ + acl_myfree(name_); + std::list::iterator it = idxes_.begin(); + for (; it != idxes_.end(); it++) + delete (*it); +} + +void db_tbl::add_idx(db_idx* idx) +{ + idxes_.push_back(idx); +} + +////////////////////////////////////////////////////////////////////////// + +database::database(const char* name, unsigned int id) +{ + acl_assert(name && *name); + name_ = acl_mystrdup(name); + acl_lowercase(name_); + id_ = id; + lock_ = new acl::locker(); +} + +database::~database(void) +{ + acl_myfree(name_); + + std::map::iterator it = tables_.begin(); + for (; it != tables_.end(); it++) + delete it->second; + delete lock_; +} + +void database::add_tbl(db_tbl* tbl) +{ + lock_->lock(); + tables_[tbl->get_name()] = tbl; + lock_->unlock(); +} + +void database::add_idx_host(idx_host* host) +{ + lock_->lock(); + // 需要检查是否是重复添加 + std::vector::iterator it = idx_hosts_.begin(); + for (; it != idx_hosts_.end(); it++) + { + if (host == *it) + { + lock_->unlock(); + return; + } + } + idx_hosts_.push_back(host); + lock_->unlock(); +} diff --git a/lib_acl_cpp/app/ndb/ctl_server/db.h b/lib_acl_cpp/app/ndb/ctl_server/db.h new file mode 100644 index 000000000..286215e68 --- /dev/null +++ b/lib_acl_cpp/app/ndb/ctl_server/db.h @@ -0,0 +1,127 @@ +#pragma once + +class acl::locker; +class db_tbl; +class idx_host; +class database; + +// 索引字段的类型 +typedef enum +{ + IDX_TYPE_STR = 0, // 字符串类型 + IDX_TYPE_BOOL, // 布尔类型 + IDX_TYPE_INT16, // 16位整数 + IDX_TYPE_INT32, // 32位整数 + IDX_TYPE_INT64 // 64位整数 +} idx_type_t; + +/** + * 数据库表对象中的索引对象 + */ +class db_idx +{ +public: + /** + * 表索引对象构造函数 + * @param tbl {db_tbl*} 表对象 + * @param name {const char*} 索引名称 + * @param id {unsigned int} 索引对应的ID号 + * @param type {idx_type_t} 索引字段的数据类型 + */ + db_idx(db_tbl* tbl, const char* name, unsigned int id, idx_type_t type); + ~db_idx(); + + const char* get_name() const + { + return name_; + } + + unsigned int get_id() const + { + return id_; + } + + db_tbl* get_tbl() const + { + return tbl_; + } + + idx_type_t get_type() const + { + return type_; + } +protected: +private: + db_tbl* tbl_; // 所属的数据表对象 + char* name_; // 索引名 + unsigned int id_; // 索引ID号 + idx_type_t type_; // 索引字段的数据类型 +}; + +class db_tbl +{ +public: + /** + * 表对象构造函数 + * @param db {database*} 数据库对象 + * @param name {const char*} 数据表名 + * @param id {unsigned int} 数据表对应的ID号 + */ + db_tbl(database* db, const char* name, unsigned int id); + ~db_tbl(); + + const char* get_name() const + { + return name_; + } + + unsigned int get_id() const + { + return id_; + } + + database* get_db() const + { + return db_; + } + + void add_idx(db_idx* idx); +private: + database* db_; // 所属的数据库对象 + char* name_; // 数据表名 + unsigned int id_; // 数据表的ID号 + std::list idxes_; // 表索引集合 +}; + +class database +{ +public: + /** + * 数据库对象构造函数 + * @param name {const char*} 数据库名称 + * @param id {unsigned int} 数据库对应的ID号 + */ + database(const char* name, unsigned int id); + ~database(); + + const char* get_name() const + { + return name_; + } + + unsigned int get_id() const + { + return id_; + } + + void add_tbl(db_tbl*); + void add_idx_host(idx_host* host); +protected: +private: + char* name_; // 数据库名 + unsigned int id_; // 数据库的ID号 + std::map tables_; // 数据表集合 + std::vector idx_hosts_; // 所对应的索引服务器的集合 + + acl::locker* lock_; // 数据库锁 +}; diff --git a/lib_acl_cpp/app/ndb/ctl_server/db_conf.cpp b/lib_acl_cpp/app/ndb/ctl_server/db_conf.cpp new file mode 100644 index 000000000..b0c9f188f --- /dev/null +++ b/lib_acl_cpp/app/ndb/ctl_server/db_conf.cpp @@ -0,0 +1,49 @@ +#include "stdafx.h" +#include "db_conf.h" + +char* var_cfg_mysql_dbaddr; +char* var_cfg_mysql_dbname; +char* var_cfg_mysql_dbuser; +char* var_cfg_mysql_dbpass; + +int var_cfg_mysql_dbpool_limit; +int var_cfg_mysql_dbpool_timeout; +int var_cfg_mysql_dbpool_dbping; + +static ACL_CFG_STR_TABLE __conf_str_tab[] = +{ + { "mysql_dbaddr", "127.0.0.1:3306", &var_cfg_mysql_dbaddr }, + { "mysql_dbname", "", &var_cfg_mysql_dbname }, + { "mysql_dbuser", "root", &var_cfg_mysql_dbuser }, + { "mysql_dbpass", "", &var_cfg_mysql_dbpass }, + { 0, 0, 0 }, +}; + +static ACL_CFG_INT_TABLE __conf_int_tab[] = +{ + { "mysql_dbpool_limit", 25, &var_cfg_mysql_dbpool_limit, 0, 0 }, + { "mysql_dbpool_timeout", 120, &var_cfg_mysql_dbpool_timeout, 0, 0 }, + { "mysql_dbpool_dbping", 30, &var_cfg_mysql_dbpool_dbping, 0, 0 }, + { 0, 0, 0, 0, 0 }, +}; + +static ACL_XINETD_CFG_PARSER* __cfg = NULL; + +bool db_conf_load(const char* path) +{ + __cfg = acl_xinetd_cfg_load(path); + + acl_xinetd_params_int_table(__cfg, __conf_int_tab); + acl_xinetd_params_str_table(__cfg, __conf_str_tab); + + return true; +} + +void db_conf_unload(void) +{ + if (__cfg) + { + acl_xinetd_cfg_free(__cfg); + __cfg = NULL; + } +} diff --git a/lib_acl_cpp/app/ndb/ctl_server/db_conf.h b/lib_acl_cpp/app/ndb/ctl_server/db_conf.h new file mode 100644 index 000000000..da2120732 --- /dev/null +++ b/lib_acl_cpp/app/ndb/ctl_server/db_conf.h @@ -0,0 +1,21 @@ +#pragma once + +extern char* var_cfg_mysql_dbaddr; +extern char* var_cfg_mysql_dbname; +extern char* var_cfg_mysql_dbuser; +extern char* var_cfg_mysql_dbpass; + +extern int var_cfg_mysql_dbpool_limit; +extern int var_cfg_mysql_dbpool_timeout; +extern int var_cfg_mysql_dbpool_dbping; + +/** + * 加载配置项 + * @param path {const char*} 配置文件路径 + */ +bool db_conf_load(const char* path); + +/** + * 卸载配置内容项内存 + */ +void db_conf_unload(void); diff --git a/lib_acl_cpp/app/ndb/ctl_server/db_ctl.cpp b/lib_acl_cpp/app/ndb/ctl_server/db_ctl.cpp new file mode 100644 index 000000000..83815aeed --- /dev/null +++ b/lib_acl_cpp/app/ndb/ctl_server/db_ctl.cpp @@ -0,0 +1,709 @@ +#include "StdAfx.h" +#include "db_mysql.hpp" + +#include "driver_mysql.h" +#include "db_conf.h" +#include "db.h" +#include "db_host.h" +#include "db_ctl.h" + +struct NAME_TYPE +{ + unsigned int id; + char name[65]; + name_type_t type; +}; + +struct DB_HOST +{ + unsigned int id_db; + unsigned int id_idx_host; + acl_int64 count; +}; + +struct DB_TBL +{ + unsigned int id_db; + unsigned int id_tbl; + acl_int64 count; +}; + +struct TBL_IDX +{ + unsigned int id_idx; + unsigned int id_db; + unsigned int id_tbl; + bool unique; + idx_type_t type; +}; + +db_ctl::db_ctl(void) +{ + driver_ = new driver_mysql(var_cfg_mysql_dbaddr, var_cfg_mysql_dbname, + var_cfg_mysql_dbuser, var_cfg_mysql_dbpass, + var_cfg_mysql_dbpool_limit, var_cfg_mysql_dbpool_dbping, + var_cfg_mysql_dbpool_timeout); + errnum_ = DB_CTL_OK; + ctl_conn_ = new acl::db_mysql(var_cfg_mysql_dbaddr, + var_cfg_mysql_dbname, var_cfg_mysql_dbuser, + var_cfg_mysql_dbpass); + lock_ = new acl::locker(); + ctl_conn_lock_ = new acl::locker(); +} + +db_ctl::~db_ctl(void) +{ + delete driver_; + delete ctl_conn_; + + std::map::iterator it = dbs_.begin(); + for (; it != dbs_.end(); it++) + delete it->second; + + std::vector::iterator idx_host_it = idx_hosts_.begin(); + for (; idx_host_it != idx_hosts_.end(); idx_host_it++) + delete (*idx_host_it); + + std::vector::iterator dat_host_it = dat_hosts_.begin(); + for (; dat_host_it != dat_hosts_.end(); dat_host_it++) + delete (*dat_host_it); + + std::list::iterator name_it = names_.begin(); + for (; name_it != names_.end(); name_it++) + acl_myfree(*name_it); + + std::list::iterator db_host_it = db_hosts_.begin(); + for (; db_host_it != db_hosts_.end(); db_host_it++) + acl_myfree(*db_host_it); + + std::list::iterator db_tbl_it = db_tbls_.begin(); + for (; db_tbl_it != db_tbls_.end(); db_tbl_it++) + acl_myfree(*db_tbl_it); + + std::list::iterator tbl_idx_it = tbl_idxes_.begin(); + for (; tbl_idx_it != tbl_idxes_.end(); tbl_idx_it++) + acl_myfree(*tbl_idx_it); + + delete lock_; + delete ctl_conn_lock_; +} + +#define NCP(x, y, z) ACL_SAFE_STRNCPY((x), (y), (z)) + +void db_ctl::load() +{ + load_names(); + load_idx_hosts(); + load_dat_hosts(); + load_db_hosts(); + load_db_tbls(); + load_tbl_idxes(); + + // 将从数据库中查询的信息进行关联构建 + build_db(); +} + +database* db_ctl::db_open(const char* dbname, const char* dbuser /* = NULL */, + const char* dbpass /* = NULL */) +{ + lock_->lock(); + std::map::iterator it = dbs_.find(dbname); + if (it == dbs_.end()) + { + lock_->unlock(); + return NULL; + } + lock_->unlock(); + return it->second; +} + +unsigned int db_ctl::db_add_name(const char* name, name_type_t type) +{ + char sql[256]; + + // 先添加数据库记录 + snprintf(sql, sizeof(sql), "insert into tbl_name_type(name, type)" + " values('%s', %d)", name, (int) type); + + // 不必关心数据库记录是否已经存在 + (void) ctl_conn_->sql_update(sql); + + // 查询数据库名所对应的ID号 + snprintf(sql, sizeof(sql), "select id from tbl_name_type" + " where name='%s' and type=0", name); + if (ctl_conn_->sql_select(sql) == false) + { + logger_error("create db(%s) error", name); + return (unsigned int) -1; + } + const acl::db_row* first_row = ctl_conn_->get_first_row(); + if (first_row == NULL) + { + logger_error("create db(%s) error, sql(%s)", name, sql); + return (unsigned int) -1; + } + + unsigned int id = (unsigned int) first_row->field_int("id", -1); + if (id == (unsigned int) -1) + { + ctl_conn_->free_result(); + logger_error("create db(%s) error, id(-1) invalid", name); + return (unsigned int) -1; + } + + ctl_conn_->free_result(); + return id; +} + +database* db_ctl::db_create(const char* dbname, const char* dbuser /* = NULL */, + const char* dbpass /* = NULL */) +{ + // 因为对 ctl_db 只有一个数据库连接,所以需要加锁 + ctl_conn_lock_->lock(); + unsigned int id = db_add_name(dbname, NAME_TYPE_DB); + // 释放数据库连接互斥锁 + ctl_conn_lock_->unlock(); + + if (id == (unsigned int) -1) + { + logger_error("add dbname(%s) to tbl_name_type error", dbname); + return NULL; + } + + // 先加锁 + lock_->lock(); + + // 先检查是否已经存在了 + std::map::iterator it = dbs_.find(dbname); + if (it != dbs_.end()) + { + lock_->unlock(); + return it->second; + } + database* db = new database(dbname, id); + db_host_set(db); // 新创建的数据库对象需要设置其索引服务器位置 + dbs_[dbname] = db; + + // 解锁 + lock_->unlock(); + return db; +} + +bool db_ctl::db_host_set(database* db) +{ + char sql[256]; + std::vector::iterator it = idx_hosts_.begin(); + ctl_conn_lock_->lock(); + for (; it != idx_hosts_.end(); it++) + { + idx_host* host = *it; + snprintf(sql, sizeof(sql), + "insert into tbl_db_host(id_db, id_idx_host, count)" + " values(%u, %u, 0)", db->get_id(), host->get_id()); + if (ctl_conn_->sql_update(sql) == false) + { + ctl_conn_lock_->unlock(); + logger_error("sql(%s) error", sql); + return false; + } + db->add_idx_host(host); + } + + ctl_conn_lock_->unlock(); + return true; +} + +// 添加数据表对象,需要先在数据库中添加表记录,然后获得相应ID +db_tbl* db_ctl::db_add_tbl(database* db, const char* tbl_name) +{ + // 因为对 ctl_db 只有一个数据库连接,所以需要加锁 + ctl_conn_lock_->lock(); + unsigned int id = db_add_name(tbl_name, NAME_TYPE_TBL); + // 释放数据库连接互斥锁 + ctl_conn_lock_->unlock(); + + if (id == (unsigned int) -1) + { + logger_error("add tbl_name(%s) to tbl_name_type error", tbl_name); + return NULL; + } + + lock_->lock(); + add_name(tbl_name, id, NAME_TYPE_TBL); + add_tbl(db->get_id(), id, 0); + lock_->unlock(); + + // 将表对象添加进数据库对象中 + db_tbl* tbl = new db_tbl(db, tbl_name, id); + db->add_tbl(tbl); + return tbl; +} + +db_idx* db_ctl::db_add_idx(db_tbl* tbl, const char* tbl_idx, + idx_type_t idx_type) +{ + // 因为对 ctl_db 只有一个数据库连接,所以需要加锁 + ctl_conn_lock_->lock(); + unsigned int id = db_add_name(tbl_idx, NAME_TYPE_TBL); + // 释放数据库连接互斥锁 + ctl_conn_lock_->unlock(); + + if (id == (unsigned int) -1) + { + logger_error("add tbl_idx(%s) to tbl_name_type error", tbl_idx); + return NULL; + } + + lock_->lock(); + lock_->unlock(); + return NULL; +} + +db_idx* db_ctl::db_add_idx(database* db, const char* tbl_name, + const char* tbl_idx, idx_type_t idx_type) +{ + return NULL; +} + +int db_ctl::load_names(void) +{ + const char* sql = "select id, name, type from tbl_name"; + if (ctl_conn_->sql_select(sql) == false) + { + logger_error("sql(%s) error", sql); + return -1; + } + + const std::vector* rows = ctl_conn_->get_rows(); + if (rows == NULL) + { + logger_error("tbl_name empty"); + return 0; + } + + unsigned int id; + int type; + const char* name; + size_t i; + for (i = 0; i < rows->size(); i++) + { + const acl::db_row* row = (*rows)[i]; + id = row->field_int("id", -1); + if (id == (unsigned int) -1) + { + logger_error("invalid id"); + continue; + } + name = row->field_string("name"); + if (name == NULL) + { + logger_error("invalid name"); + continue; + } + type = row->field_int("type", -1); + if (type < NAME_TYPE_DB || type > NAME_TYPE_IDX) + { + logger_error("invalid type"); + continue; + } + add_name(name, id, (name_type_t) type); + } + + ctl_conn_->free_result(); + return (int) i; +} + +int db_ctl::load_idx_hosts(void) +{ + const char* sql = "select id, addr, count from tbl_host_idx"; + if (ctl_conn_->sql_select(sql) == false) + { + logger_error("sql(%s) error", sql); + return -1; + } + + const std::vector* rows = ctl_conn_->get_rows(); + if (rows == NULL) + { + logger_warn("tbl_host_idx empty"); + return 0; + } + + unsigned int id; + const char* addr; + acl_int64 count; + size_t i; + for (i = 0; i < rows->size(); i++) + { + const acl::db_row* row = (*rows)[i]; + if ((id = row->field_int("id", -1)) == (unsigned int) -1) + { + logger_error("id(-1) invalid"); + continue; + } + else if ((addr = row->field_string("addr")) == NULL) + { + logger_error("name null"); + continue; + } + else if ((count = row->field_int64("count", -1)) == -1) + { + logger_error("count invalid"); + continue; + } + idx_host* host = new idx_host(id, addr, count); + idx_hosts_.push_back(host); + } + ctl_conn_->free_result(); + return (int) i; +} + +int db_ctl::load_dat_hosts(void) +{ + const char* sql = "select id, addr, count, priority from tbl_host_dat"; + if (ctl_conn_->sql_select(sql) == false) + { + logger_error("sql(%s) invalid", sql); + return -1; + } + + const std::vector* rows = ctl_conn_->get_rows(); + if (rows == NULL) + { + logger_warn("tbl_host_dat empty"); + return 0; + } + + unsigned int id; + const char* addr; + acl_int64 count; + int priority; + + size_t i; + for (i = 0; i < rows->size(); i++) + { + const acl::db_row* row = (*rows)[i]; + if ((id = row->field_int("id", -1)) == (unsigned int) -1) + { + logger_warn("id(-1) invalid"); + continue; + } + else if ((addr = row->field_string("addr")) == NULL) + { + logger_warn("addr null"); + continue; + } + else if ((count = row->field_int64("count", -1)) == -1) + { + logger_warn("count(-1) invalid"); + continue; + } + priority = row->field_int("priority", 0); + dat_host* host = new dat_host(id, addr, count, priority); + dat_hosts_.push_back(host); + } + + ctl_conn_->free_result(); + return (int) i; +} + +int db_ctl::load_db_hosts(void) +{ + const char* sql = "select id_db, id_idx_host, count from tbl_db_host"; + if ((ctl_conn_->sql_select(sql)) == false) + { + logger_error("sql(%s) error", sql); + return -1; + } + + const std::vector* rows = ctl_conn_->get_rows(); + if (rows == NULL) + { + logger_warn("tbl_db_host empty"); + return 0; + } + + unsigned int id_db, id_idx_host; + acl_int64 count; + + size_t i; + for (i = 0; i < rows->size(); i++) + { + const acl::db_row* row = (*rows)[i]; + if ((id_db = row->field_int("id_db", -1)) == (unsigned int) -1) + { + logger_warn("id_db(-1) invalid"); + continue; + } + else if ((id_idx_host = row->field_int("id_idx_host", -1)) + == (unsigned int) -1) + { + logger_warn("id_idx_host invalid"); + continue; + } + else if ((count = row->field_int64("count", -1)) == -1) + { + logger_warn("count invalid"); + continue; + } + DB_HOST* host = (DB_HOST*) acl_mymalloc(sizeof(DB_HOST)); + host->id_db = id_db; + host->id_idx_host = id_idx_host; + host->count = count; + db_hosts_.push_back(host); + } + + ctl_conn_->free_result(); + return (int) i; +} + +int db_ctl::load_db_tbls(void) +{ + const char* sql = "select id_db, id_tbl, count from tbl_db_tbl"; + if ((ctl_conn_->sql_select(sql)) == false) + { + logger_error("sql(%s) error", sql); + return -1; + } + + const std::vector* rows = ctl_conn_->get_rows(); + if (rows == NULL) + { + logger_warn("tbl_db_tbl empty"); + return 0; + } + + unsigned int id_db, id_tbl; + acl_int64 count; + + size_t i; + for (i = 0; i < rows->size(); i++) + { + const acl::db_row* row = (*rows)[i]; + if ((id_db = row->field_int("id_db", -1)) == (unsigned int) -1) + { + logger_warn("id_db invalid"); + continue; + } + else if ((id_tbl = row->field_int("id_tbl", -1)) == + (unsigned int) -1) + { + logger_warn("id_tbl invalid"); + continue; + } + else if ((count = row->field_int64("count", -1)) == -1) + { + logger_warn("count invalid"); + continue; + } + add_tbl(id_db, id_tbl, count); + } + + ctl_conn_->free_result(); + return (int) i; +} + +int db_ctl::load_tbl_idxes(void) +{ + const char* sql = "select id_idx, id_db, id_tbl, unique, type from tbl_tbl_idx"; + if ((ctl_conn_->sql_select(sql)) == false) + { + logger_error("sql(%s) error", sql); + return -1; + } + + const std::vector* rows = ctl_conn_->get_rows(); + if (rows == NULL) + { + logger_warn("tbl_tbl_idx empty"); + return 0; + } + + unsigned int id_idx, id_db, id_tbl, unique, type; + + size_t i; + for (i = 0; i < rows->size(); i++) + { + const acl::db_row* row = (*rows)[i]; + if ((id_idx = row->field_int("id_idx", -1)) == + (unsigned int) -1) + { + logger_warn("id_idx invalid"); + continue; + } + else if ((id_db = row->field_int("id_db", -1)) == + (unsigned int) -1) + { + logger_warn("id_db invalid"); + continue; + } + else if ((id_tbl = row->field_int("id_tbl", -1)) == + (unsigned int) -1) + { + logger_warn("id_tbl invalid"); + continue; + } + type = row->field_int("type", -1); + if (type < IDX_TYPE_STR || type > IDX_TYPE_INT64) + { + logger_warn("type(%d) invalid", type); + continue; + } + + unique = row->field_int("unique"); + TBL_IDX* idx = (TBL_IDX*) acl_mymalloc(sizeof(TBL_IDX)); + idx->id_idx = id_idx; + idx->id_db = id_db; + idx->id_tbl = id_tbl; + idx->unique = unique ? true : false; + idx->type = (idx_type_t) type; + tbl_idxes_.push_back(idx); + } + + ctl_conn_->free_result(); + return (int) i; +} + +database* db_ctl::get_db(unsigned int id) const +{ + std::map::const_iterator it = dbs_.begin(); + for (; it != dbs_.end(); it++) + { + if (it->second->get_id() == id) + return it->second; + } + return NULL; +} + +idx_host* db_ctl::get_idx_host(unsigned int id) const +{ + std::vector::const_iterator it = idx_hosts_.begin(); + for (; it != idx_hosts_.end(); it++) + { + if (id == (*it)->get_id()) + return *it; + } + return NULL; +} + +void db_ctl::build_db(void) +{ + std::list::iterator name_type_it = names_.begin(); + // 先从中提取出数据库标识 + for (; name_type_it != names_.end(); name_type_it++) + { + if ((*name_type_it)->type != NAME_TYPE_DB) + continue; + database* db = new database((*name_type_it)->name, + (*name_type_it)->id); + dbs_[db->get_name()] = db; + } + + // 取出所有的数据表对象,并将之加入对应的数据库对象中 + std::list::iterator tbl_it = db_tbls_.begin(); + for (; tbl_it != db_tbls_.end(); tbl_it++) + { + database* db = get_db((*tbl_it)->id_db); + if (db != NULL) + add_tbl(db, *tbl_it); + else + logger_warn("tbl's(%d) db(%d) no exist", + (*tbl_it)->id_tbl, (*tbl_it)->id_db); + } + + // 取出所有的将索引服务器对象,并将之加入对应的数据库对象中 + std::list::iterator host_it = db_hosts_.begin(); + for (; host_it != db_hosts_.end(); host_it++) + { + idx_host* host = get_idx_host((*host_it)->id_idx_host); + if (host == NULL) + { + logger_warn("idx_host(%d) not exist", + (*host_it)->id_idx_host); + continue; + } + + database* db = get_db(host->get_id()); + if (db == NULL) + { + logger_warn("idx_host(%d)'s db no exist", + host->get_id()); + continue; + } + db->add_idx_host(host); + } +} + +NAME_TYPE* db_ctl::get_name(unsigned int id, name_type_t type) const +{ + std::list::const_iterator it = names_.begin(); + for (; it != names_.end(); it++) + { + if ((*it)->id == id && (*it)->type == type) + return *it; + } + + return NULL; +} + +void db_ctl::add_name(const char* name, unsigned int id, name_type_t type) +{ + if (get_name(id, type) != NULL) + return; + NAME_TYPE* nt = (NAME_TYPE*) acl_mycalloc(1, sizeof(NAME_TYPE)); + snprintf(nt->name, sizeof(nt->name), "%s", name); + nt->id = id; + nt->type = type; +} + +void db_ctl::add_tbl(database* db, DB_TBL* dbTbl) +{ + // 需要检查该表对象是否与命名表中的记录一致 + NAME_TYPE* name_type = NULL; + std::list::iterator name_type_it = names_.begin(); + for (; name_type_it != names_.end(); name_type_it++) + { + if ((*name_type_it)->id == dbTbl->id_tbl && + (*name_type_it)->type == NAME_TYPE_TBL) + { + name_type = *name_type_it; + break; + } + } + if (!name_type) + return; + + db_tbl* tbl = new db_tbl(db, name_type->name, name_type->id); + db->add_tbl(tbl); + + // 添加所有的表索引对象至所属的表对象中 + std::list::iterator idx_it = tbl_idxes_.begin(); + for (; idx_it != tbl_idxes_.end(); idx_it++) + { + if ((*idx_it)->id_tbl != tbl->get_id() && + (*idx_it)->id_db != db->get_id()) + { + continue; + } + + NAME_TYPE* nt = get_name((*idx_it)->id_idx, NAME_TYPE_IDX); + if (nt == NULL) + logger_warn("id_idx: %d invalid", (*idx_it)->id_idx); + else + { + db_idx* idx = new db_idx(tbl, nt->name, + nt->id, (*idx_it)->type); + tbl->add_idx(idx); // 添加索引对象至数据表中 + } + } +} + +void db_ctl::add_tbl(unsigned int id_db, unsigned int id_tbl, + long long int count) +{ + DB_TBL* tbl = (DB_TBL*) acl_mymalloc(sizeof(DB_TBL)); + tbl->id_db = id_db; + tbl->id_tbl = id_tbl; + tbl->count = count; + db_tbls_.push_back(tbl); +} diff --git a/lib_acl_cpp/app/ndb/ctl_server/db_ctl.h b/lib_acl_cpp/app/ndb/ctl_server/db_ctl.h new file mode 100644 index 000000000..b04764fd0 --- /dev/null +++ b/lib_acl_cpp/app/ndb/ctl_server/db_ctl.h @@ -0,0 +1,159 @@ +#pragma once +#include "db.h" + +class acl::db_handle; // db_handle.hpp +class acl::locker; // locker.hpp + +class db_driver; +class database; +class idx_host; +class dat_host; + +struct NAME_TYPE; +struct DB_HOST; +struct DB_TBL; +struct TBL_IDX; + +typedef enum +{ + NAME_TYPE_DB = 0, + NAME_TYPE_TBL = 1, + NAME_TYPE_IDX = 2 +} name_type_t; + +enum +{ + DB_CTL_OK = 0, + DB_CTL_ERR = 1, +}; + +class db_ctl +{ +public: + db_ctl(void); + ~db_ctl(void); + + /** + * 加载数据库信息 + */ + void load(); + + /** + * 打开指定数据库中的数据库对象,如果数据库不存在,返回NULL + * @param dbname {const char*} 数据库名称 + * @param dbuser {const char*} 用户名 + * @param dbpass {const char*} 用户密码 + * @return {database*} 数据库对象,如果返回 NULL 则表示失败 + */ + database* db_open(const char* dbname, const char* dbuser = NULL, + const char* dbpass = NULL); + + /** + * 创建数据库 + * @param dbname {const char*} 数据库名称 + * @param dbuser {const char*} 用户名 + * @param dbpass {const char*} 用户密码 + * @return {database*} 数据库对象,如果返回 NULL 则表示失败 + */ + database* db_create(const char* dbname, const char* dbuser = NULL, + const char* dbpass = NULL); + + /** + * 关闭数据库 + * @param {database*} db + */ + void db_close(database* db); + + /** + * 向数据库中添加数据表 + * @param db {database*} 数据库名 + * @param tbl_name {const char*} 数据表名 + * @return {db_tbl*} 非空值表示添加成功 + */ + db_tbl* db_add_tbl(database* db, const char* tbl_name); + + /** + * 向数据表中添加索引项 + * @param tbl {db_tbl*} 数据表对象 + * @param tbl_idx {const char*} 数据表索引名 + * @param idx_type {idx_type_t} 表索引的字段类型 + * @return {db_idx*} 非空值表示添加成功 + */ + db_idx* db_add_idx(db_tbl* tbl, const char* tbl_idx, idx_type_t idx_type); + + /** + * 向数据表中添加索引项 + * @param db {database*} 数据库对象 + * @param tbl_name {const char*} 数据表名 + * @param tbl_idx {const char*} 数据表索引名 + * @param idx_type {idx_type_t} 表索引的字段类型 + * @return {db_idx*} 非空值表示添加成功 + */ + db_idx* db_add_idx(database* db, const char* tbl_name, + const char* tbl_idx, idx_type_t idx_type); + +protected: + /** + * 设置索引数据库的主机至对应的数据库对象中,并添加进数据库中 + * @param db {database*} + * @return {bool} + */ + bool db_host_set(database* db); +private: + int errnum_; + db_driver* driver_; + acl::locker* lock_; // db_ctl 对象的互斥锁 + acl::locker* ctl_conn_lock_; // ctl_conn_ 数据库连接的互斥锁 + acl::db_handle* ctl_conn_; // 控制数据库的连接 + std::map dbs_; // 数据库列表 + std::vector idx_hosts_; // 索引服务器列表 + std::vector dat_hosts_; // 数据服务器列表 + + std::list names_; + std::list db_hosts_; + std::list db_tbls_; + std::list tbl_idxes_; + + // 加载表 tbl_name_type + int load_names(void); + + // 加载表 tbl_idx_host + int load_idx_hosts(void); + + // 加载表 tbl_dat_host + int load_dat_hosts(void); + + // 加载表 tbl_db_host + int load_db_hosts(void); + + // 加载表 tbl_db_tbl + int load_db_tbls(void); + + // 加载表 tbl_tbl_idx + int load_tbl_idxes(void); + + // 从 NAME_TYPE 的集合中根据ID号及类型获得指定的 NAME_TYPE 结构对象 + NAME_TYPE* get_name(unsigned int id, name_type_t type) const; + + // 添加 NAME_TYPE对象至 names_ 集合中 + void add_name(const char* name, unsigned int id, name_type_t type); + + // 添加新的名字记录至数据库,并返回其ID号 + unsigned int db_add_name(const char* name, name_type_t type); + + // 构建数据表关联信息 + void build_db(void); + + // 从数据库集合中根据ID号获得指定的数据库对象 + database* get_db(unsigned int id) const; + + // 从索引服务器集合中取得对应ID号的索引服务器对象 + idx_host* get_idx_host(unsigned int id) const; + + // 添加表结构对象至数据库对象中 + void add_tbl(database* db, DB_TBL* tbl); + + // 添加新的表记录对象至 db_tbls_ 集合中 + void add_tbl(unsigned int id_db, unsigned int id_tbl, + long long int count); +}; diff --git a/lib_acl_cpp/app/ndb/ctl_server/db_host.cpp b/lib_acl_cpp/app/ndb/ctl_server/db_host.cpp new file mode 100644 index 000000000..50095f1cf --- /dev/null +++ b/lib_acl_cpp/app/ndb/ctl_server/db_host.cpp @@ -0,0 +1,40 @@ +#include "StdAfx.h" +#include "db_host.h" + +db_host::db_host(unsigned int id, const char* addr, + long long int count) +: id_(id) +, count_(count) +{ + addr_ = acl_mystrdup(addr); +} + +db_host::~db_host(void) +{ + acl_myfree(addr_); +} + +////////////////////////////////////////////////////////////////////////// + +idx_host::idx_host(unsigned int id, const char* addr, + long long int count) +: db_host(id, addr, count) +{ +} + +idx_host::~idx_host() +{ +} + +////////////////////////////////////////////////////////////////////////// + +dat_host::dat_host(unsigned int id, const char* addr, + long long int count, int priority) +: db_host(id, addr, count) +{ + priority_ = priority; +} + +dat_host::~dat_host() +{ +} diff --git a/lib_acl_cpp/app/ndb/ctl_server/db_host.h b/lib_acl_cpp/app/ndb/ctl_server/db_host.h new file mode 100644 index 000000000..eeaabce29 --- /dev/null +++ b/lib_acl_cpp/app/ndb/ctl_server/db_host.h @@ -0,0 +1,54 @@ +#pragma once + +class db_host +{ +public: + db_host(unsigned int id, const char* addr, + long long int count); + virtual ~db_host(void); + + unsigned int get_id() const + { + return id_; + } + + const char* get_addr() const + { + return addr_; + } + + long long int get_count() const + { + return count_; + } +protected: + unsigned int id_; + char* addr_; + long long int count_; +}; + +class idx_host : public db_host +{ +public: + idx_host(unsigned int id, const char* addr, + long long int count); + ~idx_host(); +protected: +private: +}; + +class dat_host : public db_host +{ +public: + dat_host(unsigned int id, const char* addr, + long long int count, int priority); + ~dat_host(); + + int get_priority() const + { + return priority_; + } +protected: + int priority_; +private: +}; diff --git a/lib_acl_cpp/app/ndb/ctl_server/mysql_ctl.sql b/lib_acl_cpp/app/ndb/ctl_server/mysql_ctl.sql new file mode 100644 index 000000000..69711335a --- /dev/null +++ b/lib_acl_cpp/app/ndb/ctl_server/mysql_ctl.sql @@ -0,0 +1,56 @@ +CREATE DATABASE `db_ctl`; +USE `db_ctl`; + +/* 该表定义了 数据库|数据表|索引 的字符串名称与整数值的映射表 */ +CREATE TABLE `tbl_name_type` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '对应 name 的ID号', + `name` varchar(64) NOT NULL COMMENT '数据库|数据表|索引的名称之一', + `type` tinyint(1) unsigned NOT NULL COMMENT '该条记录的名称类型: 0-数据库,1-表,2-索引', + PRIMARY KEY(`id`) USING BTREE, + UNIQUE KEY `Index_name_type` (`name`, `type`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +/* 索引服务器信息表,记录着主机ID号,地址,存储记录数 */ +CREATE TABLE `tbl_idx_host` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '索引服务器唯一标识号', + `addr` varchar(32) NOT NULL COMMENT '主机地址,IP:PORT 或域套接口', + `count` bigint(20) NOT NULL COMMENT '已经存储的总记录数', + PRIMARY KEY(`id`) USING BTREE, + UNIQUE KEY `Index_addr` (`addr`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +/* 数据服务器信息表,记录着主机ID号,地址,存储记录数 */ +CREATE TABLE `tbl_dat_host` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '数据服务器唯一标识号', + `addr` varchar(32) NOT NULL COMMENT '主机地址,IP:PORT 或域套接口', + `priority` int(10) NOT NULL COMMENT '服务器负载权重,值越高表示负载越低', + `count` bigint(20) NOT NULL COMMENT '已经存储的总记录数', + PRIMARY KEY(`id`) USING BTREE, + UNIQUE KEY `Index_addr` (`addr`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +/* 从属于数据库中的索引数据库主机列表 */ +CREATE TABLE `tbl_db_host` ( + `id_db` int(10) unsigned NOT NULL COMMENT '数据库ID号,对应 tbl_name 中 type 类型值为 0 的 id', + `id_idx_host` int(10) unsigned NOT NULL COMMENT '索引服务器ID号,对应 tbl_idx_host 中的 id', + `count` bigint(20) unsigned NOT NULL COMMENT '该数据库在主机中的记录总数', + PRIMARY KEY(`id_db`, `id_idx_host`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +/* 从属于数据库中的数据表列表 */ +CREATE TABLE `tbl_db_tbl` ( + `id_db` int(10) unsigned NOT NULL COMMENT '数据库ID号,对应 tbl_name 中 type 类型值为 0 的 id', + `id_tbl` int(10) unsigned NOT NULL COMMENT '数据表名ID号,对应 tbl_name 中 type 类型值为 1 的 id', + `count` bigint(20) NOT NULL COMMENT '该数据表中记录总数', + PRIMARY KEY(`db_name`, `tbl_name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +/* 数据表中索引集合表 */ +CREATE TABLE `tbl_tbl_idx` ( + `id_idx` int(10) unsigned NOT NULL COMMENT '数据表中索引ID号,对应 tbl_name 中 type 类型值为 2 的 id', + `id_db` int(10) unsigned NOT NULL COMMNET '数据库ID号,对应 tbl_name 中 type 类型值为 0 的 id', + `id_tbl` int(10) unsigned NOT NULL COMMENT '数据表ID号,对应 tbl_name 中 type 类型值为 1 的 id', + `unique` tinyint(1) unsigned NOT NULL COMMENT '该索引在数据表中是否是唯一索引类型', + `type` tinyint(1) unsigned NOT NULL COMMENT '索引类型:0 - 字符串,1 - 布尔型,2 - 16位整数,3 - 32位整数,4 - 64位整数', + PRIMARY KEY(`id_idx`, `id_db`, `id_tbl`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; diff --git a/lib_acl_cpp/app/ndb/ctl_server/stdafx.cpp b/lib_acl_cpp/app/ndb/ctl_server/stdafx.cpp new file mode 100644 index 000000000..02fdb3e81 --- /dev/null +++ b/lib_acl_cpp/app/ndb/ctl_server/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// ctrl_server.pch 将成为预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + +// TODO: 在 STDAFX.H 中 +//引用任何所需的附加头文件,而不是在此文件中引用 diff --git a/lib_acl_cpp/app/ndb/ctl_server/stdafx.h b/lib_acl_cpp/app/ndb/ctl_server/stdafx.h new file mode 100644 index 000000000..d8d6241be --- /dev/null +++ b/lib_acl_cpp/app/ndb/ctl_server/stdafx.h @@ -0,0 +1,17 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是常用但不常更改的项目特定的包含文件 +// + +#pragma once + + +#include +//#include + +// TODO: 在此处引用程序要求的附加头文件 +#include +#include +#include + +#include "lib_acl.h" +#include "lib_acl.hpp" diff --git a/lib_acl_cpp/app/ndb/dat_server/ReadMe.txt b/lib_acl_cpp/app/ndb/dat_server/ReadMe.txt new file mode 100644 index 000000000..9ceadf0a7 --- /dev/null +++ b/lib_acl_cpp/app/ndb/dat_server/ReadMe.txt @@ -0,0 +1,31 @@ +======================================================================== + 控制台应用程序 : node_server 项目概况 +======================================================================== + +应用程序向导已为您创建了这个 node_server 应用程序。 +此文件包含组成 node_server 应用程序 +的每个文件的内容摘要。 + + +node_server.vcproj + 这是用应用程序向导生成的 VC++ 项目的主项目文件。 + 它包含有关生成此文件的 Visual C++ 版本的信息,以及 + 有关用应用程序向导选择的 + 平台、配置和项目功能的信息。 + +node_server.cpp + 这是主应用程序源文件。 + +///////////////////////////////////////////////////////////////////////////// +其他标准文件: + +StdAfx.h、StdAfx.cpp + 这些文件用于生成名为 node_server.pch + 的预编译头(PCH)文件以及名为 StdAfx.obj 的预编译类型文件。 + +///////////////////////////////////////////////////////////////////////////// +其他注释: + +应用程序向导使用 "TODO:" 注释指示应添加或自定义的源代码部分。 + +///////////////////////////////////////////////////////////////////////////// diff --git a/lib_acl_cpp/app/ndb/dat_server/dat_server.cpp b/lib_acl_cpp/app/ndb/dat_server/dat_server.cpp new file mode 100644 index 000000000..437598445 --- /dev/null +++ b/lib_acl_cpp/app/ndb/dat_server/dat_server.cpp @@ -0,0 +1,10 @@ +// node_server.cpp : 定义控制台应用程序的入口点。 +// + +#include "stdafx.h" + +int _tmain(int argc, _TCHAR* argv[]) +{ + return 0; +} + diff --git a/lib_acl_cpp/app/ndb/dat_server/dat_server.vcproj b/lib_acl_cpp/app/ndb/dat_server/dat_server.vcproj new file mode 100644 index 000000000..d31f8d4f4 --- /dev/null +++ b/lib_acl_cpp/app/ndb/dat_server/dat_server.vcproj @@ -0,0 +1,153 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_acl_cpp/app/ndb/dat_server/stdafx.cpp b/lib_acl_cpp/app/ndb/dat_server/stdafx.cpp new file mode 100644 index 000000000..a94f046ae --- /dev/null +++ b/lib_acl_cpp/app/ndb/dat_server/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// node_server.pch 将成为预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + +// TODO: 在 STDAFX.H 中 +//引用任何所需的附加头文件,而不是在此文件中引用 diff --git a/lib_acl_cpp/app/ndb/dat_server/stdafx.h b/lib_acl_cpp/app/ndb/dat_server/stdafx.h new file mode 100644 index 000000000..ff452917c --- /dev/null +++ b/lib_acl_cpp/app/ndb/dat_server/stdafx.h @@ -0,0 +1,11 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是常用但不常更改的项目特定的包含文件 +// + +#pragma once + + +#include +#include + +// TODO: 在此处引用程序要求的附加头文件 diff --git a/lib_acl_cpp/app/ndb/idx_server/ReadMe.txt b/lib_acl_cpp/app/ndb/idx_server/ReadMe.txt new file mode 100644 index 000000000..efe53da64 --- /dev/null +++ b/lib_acl_cpp/app/ndb/idx_server/ReadMe.txt @@ -0,0 +1,31 @@ +======================================================================== + 控制台应用程序 : name_server 项目概况 +======================================================================== + +应用程序向导已为您创建了这个 name_server 应用程序。 +此文件包含组成 name_server 应用程序 +的每个文件的内容摘要。 + + +name_server.vcproj + 这是用应用程序向导生成的 VC++ 项目的主项目文件。 + 它包含有关生成此文件的 Visual C++ 版本的信息,以及 + 有关用应用程序向导选择的 + 平台、配置和项目功能的信息。 + +name_server.cpp + 这是主应用程序源文件。 + +///////////////////////////////////////////////////////////////////////////// +其他标准文件: + +StdAfx.h、StdAfx.cpp + 这些文件用于生成名为 name_server.pch + 的预编译头(PCH)文件以及名为 StdAfx.obj 的预编译类型文件。 + +///////////////////////////////////////////////////////////////////////////// +其他注释: + +应用程序向导使用 "TODO:" 注释指示应添加或自定义的源代码部分。 + +///////////////////////////////////////////////////////////////////////////// diff --git a/lib_acl_cpp/app/ndb/idx_server/idx_server.cpp b/lib_acl_cpp/app/ndb/idx_server/idx_server.cpp new file mode 100644 index 000000000..de71a8aea --- /dev/null +++ b/lib_acl_cpp/app/ndb/idx_server/idx_server.cpp @@ -0,0 +1,10 @@ +// name_server.cpp : 定义控制台应用程序的入口点。 +// + +#include "stdafx.h" + +int main(int argc, char* argv[]) +{ + return 0; +} + diff --git a/lib_acl_cpp/app/ndb/idx_server/idx_server.vcproj b/lib_acl_cpp/app/ndb/idx_server/idx_server.vcproj new file mode 100644 index 000000000..84769b79f --- /dev/null +++ b/lib_acl_cpp/app/ndb/idx_server/idx_server.vcproj @@ -0,0 +1,156 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_acl_cpp/app/ndb/idx_server/mysql_idx.sql b/lib_acl_cpp/app/ndb/idx_server/mysql_idx.sql new file mode 100644 index 000000000..e109c4c30 --- /dev/null +++ b/lib_acl_cpp/app/ndb/idx_server/mysql_idx.sql @@ -0,0 +1,21 @@ +CREATE DATABASE `db_name`; +USE `db_name`; + +CREATE TABLE `tbl_dat` ( + `id_database` int(10) unsigned NOT NULL COMMENT '数据库名称ID', + `id_table` int(10) unsigned NOT NULL COMMENT '数据表名称ID', + `id_index` int(10) unsigned NOT NULL '数据索引名称ID', + `key` varchar(220) NOT NULL '索引字段值', + `id_dat`, bigint(20) unsigned NOT NULL COMMENT '存储唯一ID号', + PRIMARY KEY(`id_database`, `id_table`, `id_index`, `key`) USING BTREE, + KEY `Index_id_dat` (`id_dat`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +或 + +CREATE TABLE `tbl_dat` ( + `key` varchar(256) NOT NULL COMMENT '由 id_database-id_table-id_index-id:key 拼接而成', + `id_dat`, bigint(20) unsigned NOT NULL COMMENT '存储唯一ID号', + PRIMARY KEY(`key`) USING BTREE, + KEY `Index_id_dat` (`id_dat`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; diff --git a/lib_acl_cpp/app/ndb/idx_server/stdafx.cpp b/lib_acl_cpp/app/ndb/idx_server/stdafx.cpp new file mode 100644 index 000000000..381c73ce5 --- /dev/null +++ b/lib_acl_cpp/app/ndb/idx_server/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// name_server.pch 将成为预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + +// TODO: 在 STDAFX.H 中 +//引用任何所需的附加头文件,而不是在此文件中引用 diff --git a/lib_acl_cpp/app/ndb/idx_server/stdafx.h b/lib_acl_cpp/app/ndb/idx_server/stdafx.h new file mode 100644 index 000000000..ff452917c --- /dev/null +++ b/lib_acl_cpp/app/ndb/idx_server/stdafx.h @@ -0,0 +1,11 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是常用但不常更改的项目特定的包含文件 +// + +#pragma once + + +#include +#include + +// TODO: 在此处引用程序要求的附加头文件 diff --git a/lib_acl_cpp/app/ndb/lib_global/ReadMe.txt b/lib_acl_cpp/app/ndb/lib_global/ReadMe.txt new file mode 100644 index 000000000..f10b733cc --- /dev/null +++ b/lib_acl_cpp/app/ndb/lib_global/ReadMe.txt @@ -0,0 +1,28 @@ +======================================================================== + 静态库 : lib_global 项目概况 +======================================================================== + +应用程序向导已为您创建了这个 lib_global 库项目。 +此文件包含组成 lib_global 应用程序 +的每个文件的内容摘要。 + + +lib_global.vcproj + 这是用应用程序向导生成的 VC++ 项目的主项目文件。 + 它包含有关生成此文件的 Visual C++ 版本的信息,以及 + 有关用应用程序向导选择的 + 平台、配置和项目功能的信息。 + + +///////////////////////////////////////////////////////////////////////////// + +StdAfx.h、StdAfx.cpp + 这些文件用于生成名为 lib_global.pch + 的预编译头(PCH)文件以及名为 StdAfx.obj 的预编译类型文件。 + +///////////////////////////////////////////////////////////////////////////// +其他注释: + +应用程序向导使用 "TODO:" 注释指示应添加或自定义的源代码部分。 + +///////////////////////////////////////////////////////////////////////////// diff --git a/lib_acl_cpp/app/ndb/lib_global/db_driver.cpp b/lib_acl_cpp/app/ndb/lib_global/db_driver.cpp new file mode 100644 index 000000000..dac054f2b --- /dev/null +++ b/lib_acl_cpp/app/ndb/lib_global/db_driver.cpp @@ -0,0 +1,4 @@ +#include "stdafx.h" +#include "db_driver.h" + + diff --git a/lib_acl_cpp/app/ndb/lib_global/db_driver.h b/lib_acl_cpp/app/ndb/lib_global/db_driver.h new file mode 100644 index 000000000..cb958a144 --- /dev/null +++ b/lib_acl_cpp/app/ndb/lib_global/db_driver.h @@ -0,0 +1,100 @@ +#pragma once + +typedef enum +{ + DB_OK, // 正常 + DB_ERR_OPEN_DB, // 打开数据库失败 + DB_ERR_CREATE_DB, // 创建数据库失败 + DB_ERR_CREATE_TBL, // 创建数据表失败 + DB_ERR_DB_NO_EXIST, // 数据库不存在 + DB_ERR_TBL_NO_EXIST, // 数据表不存在 + DB_ERR_IDX_NO_EXIST, // 索引不存在 +} db_error_t; + +class db_result +{ +public: + db_result(void) {} + ~db_result(void) {} +}; + +/** + * 纯虚类,该类定义了与后端存储层相关的接口 + */ +class db_driver +{ +public: + db_driver(void) {} + virtual ~db_driver(void) {}; + + /** + * 创建数据库及数据表,若数据库未存在则创建新的数据库,否则 + * 在该数据库上创建新的数据表,若数据表也存在则在该数据表上创建 + * 新的索引,若索引也存在,则直接返回正确 + * @param dbname {const char*} 数据库名称 + * @param tbl {const char* tbl} 数据表名 + * @param idx {const char* idx} 数据表的索引名,若该索引值在数据表 + * 不存在则创建新的基于该索引名的索引,否则打开已经存在的索引名 + * @param idx_unique {bool} 索引字段是否要求唯一性 + * @param user {const char*} 打开该数据库的账号名 + * @param pass {const char*} 打开该数据库的账号密码 + * @return {bool} 创建是否成功 + */ + virtual bool create(const char* dbname, const char* tbl, + const char* idx, bool idx_unique = false, + const char* user = NULL, const char* pass = NULL) = 0; + + /** + * 打开数据库及数据表,如果数据库、数据表或索引不存在则返回失败 + * @param dbname {const char*} 数据库名称 + * @param tbl {const char* tbl} 数据表名 + * @param idx {const char*} 索引字段名 + * @param user {const char*} 打开该数据库的账号名 + * @param pass {const char*} 打开该数据库的账号密码 + * @return {bool} 创建是否成功 + */ + virtual bool open(const char* dbname, const char*tbl, const char* idx, + const char* user = NULL, const char* pass = NULL) = 0; + + /** + * 添加或修改数据,当索引值对应数据不存在时则添加数据,否则修改 + * 为新的数据 + * @param idx_value {const char*} 索引值,必须对应 open 函数中的索引名 + * @param data {cost void*} 数据地址 + * @param dlen {size_t} data 数据长度 + * @return {bool} 返回 false 表示失败,原因请调用 last_error() 获得 + */ + virtual bool set(const char* idx_value, const void* data, size_t dlen) = 0; + + /** + * 根据输入的索引值获得数据 + * @param idx_value {const char*} 索引值,对应 open 打开的索引字段 + * @return {db_result*} 存储查询结果,如果返回值非空则表示查询成功, + * 需要进一步调用 db_result 对象中的函数来获得查询结果;如果返回 + * NULL 则表示出错,需要调用 last_error() 获得出错原因 + */ + virtual db_result* get(const char* idx_value) = 0; + + /** + * 根据输入的索引值删除数据,同时删除与该数据相关的其它的索引项的值 + * @param idx_value {const char*} 对应 open 中的索引字段的索引值 + * @return {bool} 返回 false 表示失败,原因请调用 last_error() 获得, + * 删除的条数请调用 affect_count() 获得 + */ + virtual bool del(const char* idx_value) = 0; + + /** + * 在调用 set/del 操作时调用此函数可以获得所影响的记录的条数,对于 get + * 操作没有必要调用此函数 + * @return {int} 返回值 >= 0 表示影响记录的条数 + */ + virtual size_t affect_count() const = 0; + + /** + * 调用此函数获得上次操作的错误号 + * @return {db_error_t} 错误号类型 + */ + virtual db_error_t last_error() const = 0; + +private: +}; diff --git a/lib_acl_cpp/app/ndb/lib_global/driver_hsocket.cpp b/lib_acl_cpp/app/ndb/lib_global/driver_hsocket.cpp new file mode 100644 index 000000000..5e6e69297 --- /dev/null +++ b/lib_acl_cpp/app/ndb/lib_global/driver_hsocket.cpp @@ -0,0 +1,48 @@ +#include "stdafx.h" +#include "driver_hsocket.h" + +driver_hsocket::driver_hsocket(void) +{ +} + +driver_hsocket::~driver_hsocket(void) +{ +} + +bool driver_hsocket::create(const char* dbname, const char* tbl, + const char* idx, bool idx_unique /* = false */, + const char* user /* = NULL */, const char* pass /* = NULL */) +{ + return true; +} + +bool driver_hsocket::open(const char* dbname, const char*tbl, const char* idx, + const char* user /* = NULL */, const char* pass /* = NULL */) +{ + return true; +} + +bool driver_hsocket::set(const char* idx_value, const void* data, size_t dlen) +{ + return true; +} + +db_result* driver_hsocket::get(const char* idx_value) +{ + return 0; +} + +bool driver_hsocket::del(const char* idx_value) +{ + return true; +} + +size_t driver_hsocket::affect_count() const +{ + return 0; +} + +db_error_t driver_hsocket::last_error() const +{ + return DB_OK; +} diff --git a/lib_acl_cpp/app/ndb/lib_global/driver_hsocket.h b/lib_acl_cpp/app/ndb/lib_global/driver_hsocket.h new file mode 100644 index 000000000..bd3cf82e4 --- /dev/null +++ b/lib_acl_cpp/app/ndb/lib_global/driver_hsocket.h @@ -0,0 +1,78 @@ +#pragma once +#include "db_driver.h" + +class driver_hsocket : public db_driver +{ +public: + driver_hsocket(void); + virtual ~driver_hsocket(void); + + /** + * 创建数据库及数据表,若数据库未存在则创建新的数据库,否则 + * 在该数据库上创建新的数据表,若数据表也存在则在该数据表上创建 + * 新的索引,若索引也存在,则直接返回正确 + * @param dbname {const char*} 数据库名称 + * @param tbl {const char* tbl} 数据表名 + * @param idx {const char* idx} 数据表的索引名,若该索引值在数据表 + * 不存在则创建新的基于该索引名的索引,否则打开已经存在的索引名 + * @param idx_unique {bool} 索引字段是否要求唯一性 + * @param user {const char*} 打开该数据库的账号名 + * @param pass {const char*} 打开该数据库的账号密码 + * @return {bool} 创建是否成功 + */ + virtual bool create(const char* dbname, const char* tbl, + const char* idx, bool idx_unique = false, + const char* user = NULL, const char* pass = NULL); + + /** + * 打开数据库及数据表,如果数据库、数据表或索引不存在则返回失败 + * @param dbname {const char*} 数据库名称 + * @param tbl {const char* tbl} 数据表名 + * @param idx {const char*} 索引字段名 + * @param user {const char*} 打开该数据库的账号名 + * @param pass {const char*} 打开该数据库的账号密码 + * @return {bool} 创建是否成功 + */ + virtual bool open(const char* dbname, const char*tbl, const char* idx, + const char* user = NULL, const char* pass = NULL); + + /** + * 添加或修改数据,当索引值对应数据不存在时则添加数据,否则修改 + * 为新的数据 + * @param idx_value {const char*} 索引值,必须对应 open 函数中的索引名 + * @param data {cost void*} 数据地址 + * @param dlen {size_t} data 数据长度 + * @return {bool} 返回 false 表示失败,原因请调用 last_error() 获得 + */ + virtual bool set(const char* idx_value, const void* data, size_t dlen); + + /** + * 根据输入的索引值获得数据 + * @param idx_value {const char*} 索引值,对应 open 打开的索引字段 + * @return {db_result*} 存储查询结果,如果返回值非空则表示查询成功, + * 需要进一步调用 db_result 对象中的函数来获得查询结果;如果返回 + * NULL 则表示出错,需要调用 last_error() 获得出错原因 + */ + virtual db_result* get(const char* idx_value); + + /** + * 根据输入的索引值删除数据,同时删除与该数据相关的其它的索引项的值 + * @param idx_value {const char*} 对应 open 中的索引字段的索引值 + * @return {bool} 返回 false 表示失败,原因请调用 last_error() 获得, + * 删除的条数请调用 affect_count() 获得 + */ + virtual bool del(const char* idx_value); + + /** + * 在调用 set/del 操作时调用此函数可以获得所影响的记录的条数,对于 get + * 操作没有必要调用此函数 + * @return {int} 返回值 >= 0 表示影响记录的条数 + */ + virtual size_t affect_count() const; + + /** + * 调用此函数获得上次操作的错误号 + * @return {db_error_t} 错误号类型 + */ + virtual db_error_t last_error() const; +}; diff --git a/lib_acl_cpp/app/ndb/lib_global/driver_mysql.cpp b/lib_acl_cpp/app/ndb/lib_global/driver_mysql.cpp new file mode 100644 index 000000000..83d394b22 --- /dev/null +++ b/lib_acl_cpp/app/ndb/lib_global/driver_mysql.cpp @@ -0,0 +1,72 @@ +#include "stdafx.h" + +#include "db_driver.h" +#include "driver_mysql.h" + +driver_mysql::driver_mysql(const char* dbaddr, const char* dbname, + const char* dbuser, const char* dbpass, + int dbpool_limit /* = 50 */, int dbpool_ping /* = 30 */, + int dbpool_timeout /* = 60 */) +{ + ACL_DB_INFO db_info; + + memset(&db_info, 0, sizeof(ACL_DB_INFO)); + + ACL_SAFE_STRNCPY(db_info.db_addr, dbaddr, sizeof(db_info.db_addr)); + ACL_SAFE_STRNCPY(db_info.db_name, dbname, sizeof(db_info.db_name)); + ACL_SAFE_STRNCPY(db_info.db_user, dbuser, sizeof(db_info.db_user)); + ACL_SAFE_STRNCPY(db_info.db_pass, dbpass, sizeof(db_info.db_pass)); + + db_info.db_max = dbpool_limit; + db_info.ping_inter = dbpool_ping; + db_info.timeout_inter = dbpool_timeout; + db_info.auto_commit = 1; + + dbpool_ = acl_dbpool_create("mysql", &db_info); + + if (dbpool_ == NULL) + logger_fatal("acl_dbpool_create(mysql) error"); +} + +driver_mysql::~driver_mysql(void) +{ + acl_dbpool_destroy(dbpool_); +} + +bool driver_mysql::create(const char* dbname, const char* tbl, + const char* idx, bool idx_unique /* = false */, + const char* user /* = NULL */, const char* pass /* = NULL */) +{ + return true; +} + +bool driver_mysql::open(const char* dbname, const char*tbl, const char* idx, + const char* user /* = NULL */, const char* pass /* = NULL */) +{ + return true; +} + +bool driver_mysql::set(const char* idx_value, const void* data, size_t dlen) +{ + return true; +} + +db_result* driver_mysql::get(const char* idx_value) +{ + return NULL; +} + +bool driver_mysql::del(const char* idx_value) +{ + return true; +} + +size_t driver_mysql::affect_count() const +{ + return 0; +} + +db_error_t driver_mysql::last_error() const +{ + return DB_OK; +} diff --git a/lib_acl_cpp/app/ndb/lib_global/driver_mysql.h b/lib_acl_cpp/app/ndb/lib_global/driver_mysql.h new file mode 100644 index 000000000..4e1bb825b --- /dev/null +++ b/lib_acl_cpp/app/ndb/lib_global/driver_mysql.h @@ -0,0 +1,87 @@ +#pragma once +#include "db_driver.h" + +struct ACL_DB_POOL; +class db_result; + +class driver_mysql : public db_driver +{ +public: + driver_mysql(const char* dbaddr, const char* dbname, + const char* dbuser, const char* dbpass, + int dbpool_limit = 50, int dbpool_ping = 30, + int dbpool_timeout = 60); + virtual ~driver_mysql(void); + + /** + * 创建数据库及数据表,若数据库未存在则创建新的数据库,否则 + * 在该数据库上创建新的数据表,若数据表也存在则在该数据表上创建 + * 新的索引,若索引也存在,则直接返回正确 + * @param dbname {const char*} 数据库名称 + * @param tbl {const char* tbl} 数据表名 + * @param idx {const char* idx} 数据表的索引名,若该索引值在数据表 + * 不存在则创建新的基于该索引名的索引,否则打开已经存在的索引名 + * @param idx_unique {bool} 索引字段是否要求唯一性 + * @param user {const char*} 打开该数据库的账号名 + * @param pass {const char*} 打开该数据库的账号密码 + * @return {bool} 创建是否成功 + */ + virtual bool create(const char* dbname, const char* tbl, + const char* idx, bool idx_unique = false, + const char* user = NULL, const char* pass = NULL); + + /** + * 打开数据库及数据表,如果数据库、数据表或索引不存在则返回失败 + * @param dbname {const char*} 数据库名称 + * @param tbl {const char* tbl} 数据表名 + * @param idx {const char*} 索引字段名 + * @param user {const char*} 打开该数据库的账号名 + * @param pass {const char*} 打开该数据库的账号密码 + * @return {bool} 创建是否成功 + */ + virtual bool open(const char* dbname, const char*tbl, const char* idx, + const char* user = NULL, const char* pass = NULL); + + /** + * 添加或修改数据,当索引值对应数据不存在时则添加数据,否则修改 + * 为新的数据 + * @param idx_value {const char*} 索引值,必须对应 open 函数中的索引名 + * @param data {cost void*} 数据地址 + * @param dlen {size_t} data 数据长度 + * @return {bool} 返回 false 表示失败,原因请调用 last_error() 获得 + */ + virtual bool set(const char* idx_value, const void* data, size_t dlen); + + /** + * 根据输入的索引值获得数据 + * @param idx_value {const char*} 索引值,对应 open 打开的索引字段 + * @return {db_result*} 存储查询结果,如果返回值非空则表示查询成功, + * 需要进一步调用 db_result 对象中的函数来获得查询结果;如果返回 + * NULL 则表示出错,需要调用 last_error() 获得出错原因 + */ + virtual db_result* get(const char* idx_value); + + /** + * 根据输入的索引值删除数据,同时删除与该数据相关的其它的索引项的值 + * @param idx_value {const char*} 对应 open 中的索引字段的索引值 + * @return {bool} 返回 false 表示失败,原因请调用 last_error() 获得, + * 删除的条数请调用 affect_count() 获得 + */ + virtual bool del(const char* idx_value); + + /** + * 在调用 set/del 操作时调用此函数可以获得所影响的记录的条数,对于 get + * 操作没有必要调用此函数 + * @return {int} 返回值 >= 0 表示影响记录的条数 + */ + virtual size_t affect_count() const; + + /** + * 调用此函数获得上次操作的错误号 + * @return {db_error_t} 错误号类型 + */ + virtual db_error_t last_error() const; + +private: + ACL_DB_POOL* dbpool_; +}; diff --git a/lib_acl_cpp/app/ndb/lib_global/lib_global.vcproj b/lib_acl_cpp/app/ndb/lib_global/lib_global.vcproj new file mode 100644 index 000000000..3803b4e0c --- /dev/null +++ b/lib_acl_cpp/app/ndb/lib_global/lib_global.vcproj @@ -0,0 +1,154 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_acl_cpp/app/ndb/lib_global/stdafx.cpp b/lib_acl_cpp/app/ndb/lib_global/stdafx.cpp new file mode 100644 index 000000000..027a0eddb --- /dev/null +++ b/lib_acl_cpp/app/ndb/lib_global/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// lib_global.pch 将成为预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + +// TODO: 在 STDAFX.H 中 +//引用任何所需的附加头文件,而不是在此文件中引用 diff --git a/lib_acl_cpp/app/ndb/lib_global/stdafx.h b/lib_acl_cpp/app/ndb/lib_global/stdafx.h new file mode 100644 index 000000000..1f877bd39 --- /dev/null +++ b/lib_acl_cpp/app/ndb/lib_global/stdafx.h @@ -0,0 +1,12 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是常用但不常更改的项目特定的包含文件 +// + +#pragma once + + +#define WIN32_LEAN_AND_MEAN // 从 Windows 头中排除极少使用的资料 + +// TODO: 在此处引用程序要求的附加头文件 +#include "lib_acl.h" +#include "lib_acl.hpp" diff --git a/lib_acl_cpp/app/ndb/ndb.sln b/lib_acl_cpp/app/ndb/ndb.sln new file mode 100644 index 000000000..6f483d75e --- /dev/null +++ b/lib_acl_cpp/app/ndb/ndb.sln @@ -0,0 +1,77 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lib_acl_cpp_vc2003", "..\..\lib_acl_cpp_vc2003.vcproj", "{6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lib_global", "lib_global\lib_global.vcproj", "{1DC9FD3C-9160-42A8-91C4-15BCE2BD120E}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ctl_server", "ctl_server\ctl_server.vcproj", "{56F40A9C-F812-45EB-9069-309BF0463B97}" + ProjectSection(ProjectDependencies) = postProject + {1DC9FD3C-9160-42A8-91C4-15BCE2BD120E} = {1DC9FD3C-9160-42A8-91C4-15BCE2BD120E} + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} = {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "idx_server", "idx_server\idx_server.vcproj", "{871FA0E4-FBFF-4434-A146-5738019C59A1}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dat_server", "dat_server\dat_server.vcproj", "{BD2F7FAD-1498-47EA-99CF-4AACD6DA7C75}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + DebugDll = DebugDll + Release = Release + Releasedll = Releasedll + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.Debug.ActiveCfg = Debug|Win32 + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.Debug.Build.0 = Debug|Win32 + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.DebugDll.ActiveCfg = DebugDll|Win32 + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.DebugDll.Build.0 = DebugDll|Win32 + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.Release.ActiveCfg = Release|Win32 + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.Release.Build.0 = Release|Win32 + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.Releasedll.ActiveCfg = Releasedll|Win32 + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC}.Releasedll.Build.0 = Releasedll|Win32 + {1DC9FD3C-9160-42A8-91C4-15BCE2BD120E}.Debug.ActiveCfg = Debug|Win32 + {1DC9FD3C-9160-42A8-91C4-15BCE2BD120E}.Debug.Build.0 = Debug|Win32 + {1DC9FD3C-9160-42A8-91C4-15BCE2BD120E}.DebugDll.ActiveCfg = Debug|Win32 + {1DC9FD3C-9160-42A8-91C4-15BCE2BD120E}.DebugDll.Build.0 = Debug|Win32 + {1DC9FD3C-9160-42A8-91C4-15BCE2BD120E}.Release.ActiveCfg = Release|Win32 + {1DC9FD3C-9160-42A8-91C4-15BCE2BD120E}.Release.Build.0 = Release|Win32 + {1DC9FD3C-9160-42A8-91C4-15BCE2BD120E}.Releasedll.ActiveCfg = Release|Win32 + {1DC9FD3C-9160-42A8-91C4-15BCE2BD120E}.Releasedll.Build.0 = Release|Win32 + {56F40A9C-F812-45EB-9069-309BF0463B97}.Debug.ActiveCfg = Debug|Win32 + {56F40A9C-F812-45EB-9069-309BF0463B97}.Debug.Build.0 = Debug|Win32 + {56F40A9C-F812-45EB-9069-309BF0463B97}.DebugDll.ActiveCfg = Debug|Win32 + {56F40A9C-F812-45EB-9069-309BF0463B97}.DebugDll.Build.0 = Debug|Win32 + {56F40A9C-F812-45EB-9069-309BF0463B97}.Release.ActiveCfg = Release|Win32 + {56F40A9C-F812-45EB-9069-309BF0463B97}.Release.Build.0 = Release|Win32 + {56F40A9C-F812-45EB-9069-309BF0463B97}.Releasedll.ActiveCfg = Release|Win32 + {56F40A9C-F812-45EB-9069-309BF0463B97}.Releasedll.Build.0 = Release|Win32 + {871FA0E4-FBFF-4434-A146-5738019C59A1}.Debug.ActiveCfg = Debug|Win32 + {871FA0E4-FBFF-4434-A146-5738019C59A1}.Debug.Build.0 = Debug|Win32 + {871FA0E4-FBFF-4434-A146-5738019C59A1}.DebugDll.ActiveCfg = Debug|Win32 + {871FA0E4-FBFF-4434-A146-5738019C59A1}.DebugDll.Build.0 = Debug|Win32 + {871FA0E4-FBFF-4434-A146-5738019C59A1}.Release.ActiveCfg = Release|Win32 + {871FA0E4-FBFF-4434-A146-5738019C59A1}.Release.Build.0 = Release|Win32 + {871FA0E4-FBFF-4434-A146-5738019C59A1}.Releasedll.ActiveCfg = Release|Win32 + {871FA0E4-FBFF-4434-A146-5738019C59A1}.Releasedll.Build.0 = Release|Win32 + {BD2F7FAD-1498-47EA-99CF-4AACD6DA7C75}.Debug.ActiveCfg = Debug|Win32 + {BD2F7FAD-1498-47EA-99CF-4AACD6DA7C75}.Debug.Build.0 = Debug|Win32 + {BD2F7FAD-1498-47EA-99CF-4AACD6DA7C75}.DebugDll.ActiveCfg = Debug|Win32 + {BD2F7FAD-1498-47EA-99CF-4AACD6DA7C75}.DebugDll.Build.0 = Debug|Win32 + {BD2F7FAD-1498-47EA-99CF-4AACD6DA7C75}.Release.ActiveCfg = Release|Win32 + {BD2F7FAD-1498-47EA-99CF-4AACD6DA7C75}.Release.Build.0 = Release|Win32 + {BD2F7FAD-1498-47EA-99CF-4AACD6DA7C75}.Releasedll.ActiveCfg = Release|Win32 + {BD2F7FAD-1498-47EA-99CF-4AACD6DA7C75}.Releasedll.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/lib_acl_cpp/changes.txt b/lib_acl_cpp/changes.txt new file mode 100644 index 000000000..7d61d489a --- /dev/null +++ b/lib_acl_cpp/changes.txt @@ -0,0 +1,758 @@ +修改历史列表: +------------------------------------------------------------------------ + +168) 2013.8.18 +168.1) samples: 增加了测试 http_request_pool 的例子 samples/http_request_pool +168.2) samples: 增加了测试 memcache_pool 的例子 samples/memcache_pool + +167) 2013.8.17 +167.1) feature: 增加了 HTTP 客户端连接池类 http_request_pool;同时将 http_request +类变为 connect_client 的子类 +167.2) feature: memcache 增加了连接池类 memcache_pool;同时将类 mem_cache 改为 +memcache + +166) 2013.8.13 +166.1) mem_cache: 调整了构造函数接口,使之更容易使用 +166.2) feature: 添加了通用的客户端连接池管理对象:connect_client, connect_pool, +connect_manager,这些类均为纯虚类,但子类只需要实现很少的几个虚函数便可获得功能丰富的 +连接池管理功能 + +165) 2013.8.11 +165.1) feature: db_pool 支持动态将空闲时间过期的数据库连接释放掉,从而减少 +对后端数据库的压力 + +164) 2013.8.9 +164.1) bugfix: db/db_mysql.c 在打开 mysql 时原来的实现中,如果需要设置字符集, +则会导致崩溃,原因是设置字符集必须是在连接打开之后设置,原来的做法是在连接打开 +前设置的 + +163) 2013.7.29 +163.1) bugfix: string::split/split2 内部在调用 acl_argv_split 后没有调用 +acl_argv_free 释放动态分配的内存 + +162) 2013.7.1 +162.1) 规整了所有的源文件 + +161) 2013.6.25 +161.1) compile: 消除了在 gcc-4.6.3 下的一些编译警告 + +160) 2013.6.13 +160.1) feature: 添加了 server_socket 类 +160.2) socket_stream: 对 get_ip 类的函数做了一定调整 +160.3) samples/benchmark: 增加了 client/server 两个用于测试 IO 压力的程序 + +159) 2013.6.6 +159.1) feature: HttpServletRequest/http_client 添加调试输出 HTTP 请求头的函数 + +158) 2013.5.13 +158.1) feature: master_thread 类增加了静态添加定时器功能 + +157) 2013.5.2 +157.1) feature: 增加了针对文件进行异步 IO 操作的类:aio_fstream +157.2) samples: 增加了针对新增类 aio_fstream 的测试例子: fs_benchmark + +156) 2013.4.17 +156.1) bugfix: master_thread.cpp 在测试环境下运行时,master_threads::thread_run +函数增加了缓冲区是否有可读数据的判断 + +155) 2013.4.5 +155.1) bugfix: ipc_service.cpp 中 thread_pool_main 函数应该调用 last_serror +而不应该调用 last_error +155.2) bugfix: 在 rpc_request::run 函数中发送了一个局部栈变量,而当主线程中 +的 rpc_client::on_message 通过 IO 收到此变量时可能它已经在子线程中销毁了, +可能造成内存非法访问问题,所以现在把此变量的生命周期改成与 rpc_request 相同 +从而防止 rpc_client::on_message 中引用了一个提前释放的变量 + +154) 2013.4.1 +154.1) HttpServletRequest.cpp: HttpServletRequest::getSession中生成 COOKIE +及 SESSION 的优先级做了调整 + +153) 2013.3.28 +153.1) feature: beanstalk 客户端连接增加了连接池类 beanstalk_pool + +152) 2013.3.23 +152.1) bugfix: HttpServletRequest::getPathInfo 方法中,在 CGI 模式下应该 +先根据 SCRIPT_NAME 环境变量取得,如果取不到再根据 PATH_INFO 环境变量获取 + +151) 2013.3.14 +151.1) feature: HttpServletRequest::getSession 增加了参数 sid +151.2) feature: memcache_session 类增加了一个构造函数 + +150) 2013.3.11 +150.1) bugfix: rpc.cpp, rpc_request::cond_wait 调用过程中,如果函数 +acl_pthread_cond_wait 或 acl_pthread_cond_timedwait 返回非 0 值,则应该 +解锁,否则会造成 rpc_request::cond_signal 因为无法获得锁而阻塞 + +149) 2013.2.25 +149.1) bugfix: ipc 模块,当 aio_handle 为 WIN32 窗口消息事件引擎时,不应 +调用套接口的监听过程 +149.2) feature: ipc 模块简化了接口 +149.3) samples/gui_rpc: 更新了部分代码 + +148) 2013.2.24 +148.1) 将 db_pool 类变成基类,增加了 mysql_pool 和 sqlite_pool 两个子类 + +147) 2013.2.8 +147.1) feature: 添加了 url_coder 类,用于 url 的编码与解码 +147.2) http/: 将 HttpCookie 类从 http_header 类的头文件中剥离形成单独的类 + +146) 2013.2.5 +146.1) feature: beanstalk.cpp,当网络重连时,watch 及 use 命令会被自动调用 + +145) 2013.1.31 +145.1) feature: beanstalk 类增加了几个方法 +145.2) wizard: 模板生成中的模板增加了几个方法 + +145) 2013.1.27 +145.1) feature: 增加了文件队列的操作库 queue/ + +144) 2013.1.26 +144.1) beanstalk: 优化了接口实现方案 + +143) 2013.1.25 +143.1) feature: 添加了针对 beanstalkd 客户端通讯协议的支持 +143.2) samples: 添加了测试 beanstalk 客户端通讯库的例子 + +142) 2013.1.13 +142.1) lib_acl_cpp: 将头文件进行了分类,使之更加模块化,也便于将头文件放在系统目录下 + +141) 2012.12.31 +141.1) feature: master_threads.hpp 增加了 thread_on_timeout() 虚函数 + +140) 2012.12.28 +140.1) bugfix: string.cpp 类中的 left()/right() 有误 + +139) 2012.12.17 +139.1) bugfix: session.cpp, vbuf_new() 中的去掉了 assert() 语句 + +138) 2012.12.14 +138.1) feature: socket_stream.cpp: get_peer()/get_local() 增加了一个控制参数, +允许用户获得 IP:PORT 或 IP 格式的地址 +138.2) feature: socket_stream.cpp, 增加了两个函数 get_peer_ip/get_local_ip + +137) 2012.12.10 +137.1) performance: session 类增加了本地对象的缓存机制,提高了查询/添加/删除 +的性能 + +136) 2012.12.7 +136.1) feature: session 类增加了延迟方式修改数据,这样当针对某一 SID 号 +做多次修改、添加操作时,只当最后 flush 后才真正连接后端的 cache 服务器, +从而大大提高了整体性能 +136.2) string: 完善了一下构造函数 +136.3) samples: samples/session 增加了对延迟修改 session 的测试示例 + +135) 2012.12.6 +135.1) bugfix: db/db_mysql.cpp, 连接 mysql 时的地址有错 + +134) 2012.11.27 +134.1) feature: 增加了单体模板类 singleton.hpp +134.2) samples: 增加了单例的测试示例 samples/singleton + +133) 2012.11.8 +133.1) class istream: 修改了 gets_peek/read_peek 的参数接口;增加了 readn_peek 函数 + +132) 2012.9.7 +132.1) 为了避免一些不兼容性及编译问题,去掉了大部分类中的 noncopyable 继承关系 + +131) 2012.9.6 +131.1) feature: 添加了 noncopyable 类,子类只需继承该类便可阻止类对象赋值 +131.2) 大部分类均继承了 noncopyable 类,可以在编译期有效地阻止类对象直接赋值 + +130) 2012.8.21 +130.1) feature: stream 类中添加了 set_rw_timeout/get_rw_timeout +130.2) socket_stream: 去掉了 unbind_vstream,因为基类 stream 有类似函数 + +129) 2012.8.18 +129.1) samples/http_client: VC 工程文件中动态连接方式的连接库有误 + +*128*) 2012.8.17 1.1.1.2 release 版本正式发布!~ + +127) 2012.8.16 +127.1) performance: rpc, ipc_service 内部的 ipc 消息连接流允许采用长连接方式, +从而提高了消息传递的效率 + +126) 2012.8.15 +126.1) http_response.cpp: get_body() 当长度 < 0 且 HTTP 请求方法为 GET/CONNECT +时,则也应返回 true +126.2) samples: http_server 用来测试 rpc 通讯模式下半非阻塞方式的功能 + +125) 2012.8.14 +125.1) doxygen 检查出一些头文件中注释不准确的地方 +125.2) 准备发布正式版本了:) + +124) 2012.8.13 +124.1) feature: 因为 md5 算法经常会被使用,所以封装了一个 md5 算法类,见 md5.cpp +124.2) samples: md5 示例测试新增的 md5 功能类 + +123) 2012.8.2 +123.1) aio_handle: 将定时器的接口进行了相应调整,使之更加明晰 + +122) 2012.7.30 +122.1) feature: socket_stream 类增加了 unbind_stream 方法 + +121) 2012.7.26 +121.1) bugfix: xml.cpp 的 xml 类中,多处存在内存泄露及内存非法释放的问题, +这些问题均由 valgrind 查出 + +120) 2012.7.25 +120.1) bugfix: rpc.cpp 中如果 cond_signal 调用时间早于 cond_wait 时,则会 +因为线程锁及线程条件变量未被初始化而出错,所以这两个变量应该在构造函数内 +进行初始化;同时还增加了 cond_count_ 作为 cond_wait 是否应该等待的条件 + +119) 2012.7.20 +119.1) feature: 增加了 http_utils,专门用于一些常用的工具类功能 +119.2) feature: 增加了 http_download,专门用于支持断点续传方式的文件下载 + +118) 2012.7.19 +118.1) feature: http_request/http_header 增加了对 Range 的支持 + +117) 2012.7.16 +117.1) feature: http_request, 增加了方法:set_charset/read_body,从而可以 +循环读取服务器返回的压缩数据,并进行解压,同时可以转换为本地字符集 +117.2) bugfix: http_client, read_response_body(char* buf, size_t size) 中, +当在读响应头且自动启动了解压模块时,而该函数却不能进行解压处理(也不会调用 +zlib_stream::unzip_finish 过程),这会造成 zlib 库的内存泄露 +117.3) bugfix: rpc.cpp, rpc_request::cond_wait 加锁/解锁顺序不对 +117.4) feature: string.cpp, 增加了 split2 函数,用于返回 vector 格式数据 + +116.1) 2012.7.12 +116.1) string 类中的 split 函数的返回值由原来的 std::list 改为 std::vector, +这样更便于用户使用 + +115) 2012.7.10 +115.1) compile: 消除了例子中的几个编译问题 + +114) 2012.7.5 +114.1) feature: rcp.hpp 增加了 cond_wait/cond_signal 方法,便于主线程向处于等待 +状态的子线程发送消息 + +113) 2012.7.4 +113.1) feature: socket_stream.h 增加了 ACL_SOCKET unbind_sock() 方法,将套接字 +与流对象解绑,从而将流对象的释放与套接字的关闭分开 + +112) 2012.7.2 +112.1) bugfix: aio_istream.cpp 中,函数 aio_istream::gets 和 aio_istream::read +当输入的超时时间为 timeout 为 0 时,则会延用之前设置的超时时间,应该是把超时时间 +设置为 0 +112.2) samples/rpc_download: 进一步优化,同时使用 valgrind 检查出库本身一些问题 +112.3) samples/gui_rpc: 该例子采用基于 WIN32 窗口消息方式,实现阻塞式下载过程与 +窗口消息结合的功能 + +111) 2012.7.1 +111.1) bugfix: http_request.cpp/http_response.cpp 中的 get_body(char*, size_t) +有一处手误,返回值给的不对 +111.2) samples: rpc_download 该例子以一个完整的 HTTP 下载为例,测试了 rpc 功能 +模块的可用性 + +110) 2012.6.30 +110.1) feature: rpc_request 类增加了两个有用的方法: rpc_signal/rpc_wakeup, +从而可以在调用子类的 rpc_run 方法时,允许子类在子线程中边处理边向主线程发 +消息,主线程收到消息后启用 rpc_request::rpc_wakeup 处理中间结果 +110.2) rpc_request 的方法 rpc_callback 改为 rpc_onover,同时 rpc_onover 的 +权限范围被限定为 protected,为了保证在 rpc_service 中可以访问,将 rpc_service +和 rpc_client 加为 rpc_request 的友元类 + +109) 2012.6.28 +109.1) feature: 增加了 ipc/rpc.cpp,从而进一步扩展了 IPC 类,使非阻塞线程 +与阻塞线程之间的通信更为方便 + +108) 2012.6.26 +108.1) feature: http_header/HttpCookie 两个类中,在关设置的方法增加了本 +对象的引用,以便于用户可以连续对该对象的设置操作 +108.2) bugfix: HttpServletRequest::readHeader,有一处没有判断指针为 NULL +的问题 + +107) 2012.6.21 +107.1) bugfix: samples/cgi_upload 在循环读数据时有内存越界问题 +107.2) feature: src/http/http_header 增加了 set_request_mode 方法用于手工 +设置是请求头还是响应头 +107.3) HttpServletResponse: 在创建 http_header 时调用 set_request_mode +指定了响应头方式 +107.4) samples/: cgi, cgi_upload 添加了单独服务运行方式,以方便进行调试 +107.5) feature: HttpServletResponse 类增加了方法 setKeepAlive 以及 +getHttpHeader() + +106) 2012.6.20 +106.1) http 模块中的一些接口重新优化了一下,涉及的文件有:HttpServlet, +HttpServletRequest, HttpServleResponse, HttpSession +106.2) session 类重新设计了一下,该类成为纯虚类,增加了 memcache_session +类,用来实现当缓存为 memcached 时的 session 功能,将来还可以再增加对redis +的支持 +106.3) samples: cgi/cgi_upload/http_servlet/session 稍微修改一下,以适应上面的修改 + +105) 2012.6.19 +105.1) bugfix: master_conf.c 中在 reset 函数中,在释放字符串类型的变量时, +如果该变量未被赋值,则不应释放 +105.2) feature: master_base 增加了接口 daemon_mode 用来判断是否是由 acl_master +控制的后台服务器模式 +105.3) bugfix: http_header::build_request 方法内部对 URL 编码方式有误, +不应对整个 URL 参数进行 URL 编码,而应该针对每一个参数分别进行 URL 编码 +105.4) bugfix: http_request::get_cookie 第一次被调用时应该先调用一下 +http_request::create_cookies + +104) 2012.6.15 +104.1) samples: 增加了 samples/http_request 测试用例 + +103) 2012.6.13 +103.1) feature: 增加了 http_pipe 类,用于以管道流方式处理 HTTP 协议数据 +103.2) feature: http_request/http_response 增加了一些功能函数 +103.3) samples: 增加了 samples/http_response 测试用例 + +102) 2012.6.12 +102.1) feature: session/HttpSession 增加了设置 session 过期的方法 +102.2) 去掉了有些源程序中在 WIN32 平台下对 snprintf 的定义,因为其包含的 +头文件 lib_acl.h 中已经定义过了 + +101) 2012.6.11 +101.1) feature: session/HttpSession 增加了允许存取二进制属性对象的接口 + +100) 2012.6.8 +100.1) feature: session 添加了 del 接口 +100.2) feature: HttpServletRequest 类添加了 setCookie 函数 +100.2) bugfix: HttpSession 在第一次添加 session 时如果浏览器没有 session +标识,则设置了 session 后立即取该值会因为没有那个 session cookie 而取不到 +100.2) samples: 添加了 http_test, session 两个例子 +99) 2012.6.7 +99.1) feature: 将 session 单独形成一个类,使 HttpSession 继承 session 类 +99.2) locker: 修改了相关的接口,使之更合理 +99.3) HttpServlet: 增加了当未知请求方法时的处理虚函数 doUnkown + +98) 2012.6.5 +98.1) feature: http_request/http_response 两个类的功能进一步得到完善 +98.2) http_header: 添加了 reset 方法,可以重置内部状态 +98.3) featur: http_header->HttpCookie 添加了 setCookie 函数用来分析来自 +于服务器响应的 Set-Cookie 中内容 + +97) 2012.6.3 +97.1) feature: 增加了 master_conf 类用于读取配置文件,同时将 master_base 类中 +有关配置的部分放置在 master_conf 中处理 +97.2) compile: 在 AS6/CS6 上编译通过 + +96) 2012.6.1 +96.1) feature: db_handle 增加了 escape_string 用于将数据库的字段中的特殊字符 +进行转义以防止 SQL 注入攻击 +96.2) feature: db_handle/db_pool 重新建立了二者实例对象之间的关联关系 + +95) 2012.5.31 +95.1) feature: xml, 增加了 getFirstElementByTag/getFirstElementByTags,从而更 +方便用户操作 xml 对象 + +94) 2012.5.28 +94.1) bugfix: mime/internal/mime_state_parse.cpp: 因为之前增加了 body_data_end +做为某个 MIME 结点数据体的结尾,当邮件体不是 MULTIPART 格式时,body_data_end 也 +应该赋值才对。 + +93) 2012.5.26 +93.1) linux 平台下默认将对 polarssl 库的依赖去掉了 + +92) 2012.5.18: 1.1.1.0 BETA 版本发布 +92.1) http 模块功能已经比较丰富了,基本可以替代传统的 CGI 方式,用户在使用 +时可以象使用 java servlet 一样方便了,GOOD WORK! + +91) 2012.5.17 +91.1) 修改了 mime/ 相关模块,从而可以使 http_mime 类支持文件上传了 + +90) 2012.5.16 +90.1) http/: 增加了 http_mime 类,支持文件上传功能 + +89) 2012.5.15 +89.1) http/: HttpServlet 类增加了对参数等的支持 +89.2) http_client: 在调用第二个构建函数时,rw_timeout_ 没有赋初始值(valgrind +检查出该错误) + +88) 2012.5.13 +88.1) http/: 增加了针对 CGI 的部分支持 + +88) 2012.5.10 +88.1) feature: 增加了 HttpServlet, HttpServletRequest, HttpServletResponse, +HttpSession 等类,可以用作 CGI 开发 +88.2) 去掉了 HTTP_COOKIE 结构, 增加了 HttpCookie 类 +88.3) 增加了 samples/http_servlet 例子 + +87) 2012.5.2 +87.1) http_client: 增加了 get_ostream/get_istream 接口,去掉了冗余的 write +接口,用户可以直接调用 http_client::get_ostream().write 来达到写的目的 + +86) 2012.4.26 +86.1) feature: xml.hpp 中增加了 xml_attr 类,同时给 xml_node 类增加了用 +来遍历结点所有属性的功能 + +85) 2012.4.24 +85.1) feature: json 增加了 get_json() 函数,xml 增加了 get_xml 函数 +85.2) feature: json/xml 都增加了 first_child/next_child 用于某个结点遍历 +子结点的函数,同时增加了 get_parent() 函数 + +84) 2012.4.22 +84.1) feature: json/xml 均增加了一些非常有用的接口函数,从而更容易地创建 +json/xml 对象,可以参考相关的例子 + +83) 2012.4.21 +83.1) feature: json/xml 都增加了用于结点遍历的 first_node/next_node 接口 +83.2) feature: master/ 框架,在 acl_cpp 库使用 acl 库中的 master 框架时, +用户的程序中不再需要包含 lib_acl.h 头文件,只需要包含 lib_acl.hpp 头文件 +即可,这样使用户在使用 acl_cpp 库时可以不用再了解 acl 库的知识,同时在编译 +时更为方便(只需要链接 lib_acl.a 库即可) + +82) 2012.4.20 +82.1) feature: 添加 json 库的封装及相关功能 +82.2) samples: samples/json + +81) 2012.4.17 +81.1) feature: xml 库添加了创建 xml 对象序列号的功能 + +80) 2012.4.12 +80.1) bugfix: master 框架下 master_proc, master_trigger 服务器模板需要 +添加 acl_watchdog_pat() 过程通知 acl_master 进程子进程还正常; 在 +master_base.hpp 中添加了一个新的成员变量:daemon_mode_ 来表明是单独运行 +模式还是后台进程模式 + +79) 2012.4.11 +79.1) compile: 调整了在 WIN32 下 VC2010 编译工程 + +78) 2012.4.3 +78.1) feature: http_header 即可以作为 HTTP 请求头,又可作为 HTTP 响应头 + +77) 2012.4.2 +77.1) feature: http_client 丰富了一些函数接口,使该类即可以用作请求端的 +HTTP 客户端流,又可以用作响应端的 HTTP 客户端流 + +76) 2012.4.1 +76.1) bugfix: string.cpp, 在CS4/AS4 上的 g++ 无法区分变参类型的接口,如 +format(const char* fmt, ...); format(const char* fmt, va_list ap), +所以导致了 string.cpp 的 format, format_append 的错误匹配,所以增加了 +vformat(const char* fmt, va_list ap) + +75) 2012.3.18 +75.1) Makefile: 在 samples/ 下增加了一个统一的 Makefile.in, 所有的示例的 +Makefile 文件都大大简化 +75.2) bugfix: string.cpp 类中的 parse_xxx() 使用了临时的栈变量,现在统一 +改成了线程局部存储变量 +75.3) feature: 增加了 db_service_mysql 类,从而增加了对 mysql 数据库服务 +的支持 +75.4) db_service: 将 db_service 定义为基类,增加了 db_service_sqlite 用于 +支持 sqlite 数据库 + +74) 2012.3.16 +74.1) bugfix: mem_cache.cpp 在 set 命令时有个BUG,已修复 + +73) 2012.3.13 +73.1) Makefile: 指定了 mysql 头文件的路径为: include/mysql +73.2) feature: db_mysql.cpp 支持本地字符集 + +72) 2012.3.7 +72.1) compile: 在编译动态库时可以指定链接路径,用法如下: +make shared rpath=xxx; 仅编译动态库 +或 make rpath=xxx; 同时编译动态库及静态库存 + +71) 2012.2.18 +71.1) 将根目录下的 mime 目录移到 src/mime/internal/ 目录下 + +70) 2012.2.15 +70.1) src/stdlib/mem_cache.cpp: 实现了部分常用的 memcached 协议 + +69) 2012.2.14 +69.1) src/ 目录重新规划了目录结构,从而显得更为清晰 + +68) 2012.1.19 +68.1) feature: http_client/http_header, 允许接收来自于服务器的压缩数据并进行解压 +68.2) samples: http_client2, 该例子用来测试 http_client 类 + +67) 2012.1.18 +67.1) feature: log.hpp: 增加了接口 stdout_open 当未打开日志流时,通过此 +函数用来将日志信息输出至标准输出 +67.2) log.hpp: 将 open 函数的参数设置了缺省的值 +67.3) feature: zlib_stream 增加了针对 HTTP 传输过程中解压 gzip 数据的支持 + +66) 2012.1.10 : 1.1.0.0 版本发布了!!!!!!! +66.1) feature: master_aio.cpp, 该库封装了 acl_master 服务器框架中的 +单线程非阻塞模板 +66.2) feature: master_proc.cpp, 该库封装了 acl_master 服务器框架中的 +进程池模板 +66.3) feature: master_trigger.cpp, 该库封装了 acl_master 服务器框架中的 +触发器模板 +66.3) samples: samples/master_aio, samples/master_proc, samples/master_trigger + +65) 2012.1.8 +65.1) feature: master_threads 类完善了一些接口调用 + +64) 2012.1.6 +64.1) feature: master_threads.cpp, 该库封装了 acl_master 服务器框架中的多 +线程处理模板 +64.2) samples: samples/master_threads,测试用例 + +63) 2011.12.21 +63.1) feature: db_handle.cpp,其中的 db_handle 类增加了三个函数,方便用户在 +数据库查询后直接获得结果集:get_first_row()/0, get_rows()/2, get_rows()/0 + +62) 2011.12.7 +62.1) feature: 增加了 db_mysql.cpp,该类从 db_handle 继续,从而使 db_handle +可以支持 mysql 了,但该类在 WIN32 使用时会有点问题,因为目前还没有找到合适的 +libmysql.lib/libmysql.dll,所以在 WIN32 使用该类时,建议使用 acl_cpp 的静态库 +62.2) feature: 增加了 db_pool.cpp,该类实现了数据库连接池的功能 +62.3) samples: samples/mysql,用来测试新加的 db_mysql 类 + +61) 2011.10.5 +61.1) feature: 从 glib 中摘取了一段代码 win_iconv.cpp 用于支持 win32 环境下 +的字符集转换功能,这样在 win32 下 acl_cpp 库既可以使用 iconv.dll 进行字符集 +的转换,同时也可以通过在 acl_cpp 的编译开关定义 USE_WIN_ICONV 使用 win32 原 +生的字符集转换功能。感谢 glib 中 win_iconv.cpp 的作者使用 win32 的原生 API +模拟了 iconv 库的功能。 + +60) 2011.10.3 +60.1) mime.cpp: save_mail, get_image, get_images 三个函数增加了几个默认参数 + +59) 2011.9.15 +59.1) malloc.cpp, malloc.hpp:将针对 new, delete 的重载去掉,而作为条件编译保留 + +58) 2011.9.12 +58.1) feature: 重载了 new, delete,这样便于调用 acl 库的内存池切片库 + +57) 2011.9.5 +57.1) string: 将 push_back 调用做为二进制字符添加,这样象 mime_code 等类 +中调用 push_back 时就不会出错了 + +56) 2011.9.4 +56.1) 重新设计了 pipe_stream 基础类,将原来的 push 和 pop 合为一个函数 +push_pop,其它相应的子类做相应修改 +56.2) bugfix: 因为 string 类对二进制及纯字符做了存储区分,所以导致了 +调用 push_back 等函数的调用会出错,其中 mime_code 类就因此而出错 + +55) 2011.9.3 +55.1) feature: zlib_stream,支持 pipe_stream 方式 +55.2) samples: samples/zlib 增加了支持 pipe_stream 的测试 +55.3) bugfix: charset_conv 当源字符集为 utf-8 时,针对 utf-8 的前缀判断有 +问题 + +54) 2011.9.2 +54.1) feature: zlib,增加了对 zlib 库的封装,既支持流式压缩与解压缩,同时 +又支持一次性压缩与解压缩,并且在 WIN32 平台下是动态加载 zlib.dll 的 +54.2) samples: samples/zlib 为测试新的 zlib 库的例子 + +53) 2011.8.26 +53.1) feature: mime 解析完毕后,允许从内存中转储邮件数据解析结果,原来在 +转储解析结果时只能是从源文件中抽取数据;影响的类有 mime_node, mime_body +53.2) samples: mime 例子增加了针对 53.1) 新特性的测试用例 + +52) 2011.8.18 +52.1) ipc_service 基类支持基于 WIN32 窗口消息方式的 IPC 通信,其它基于此 +类的继承类 dns_service, http_service, db_service 均支持了 WIN32 窗口消息 +的 IPC 通信方式; 当然,子类可以自行选择 IPC 通信方式是采用 IO 消息方式还 +是 WIN32 窗口消息方式 +52.2) samples: wn_dbservice 实例,用来检测 db_service 的功能以及 db_service +的 WIN32 消息的 IPC 通信功能 +52.3) feature: 对于 iconv.dll, sqlite3.dll 调用的方式改为动态加载模式 + +51) 2011.8.14 +51.1) 增加了 db_handle/db_sqlite 类,从而可以方便数据库的操作过程 +51.2) 增加了 db_service 类,从而可以将数据库操作过程在子线程中处理,保证 +了主线程仍然为非阻塞过程 + +50) 2011.7.22 +50.1) final_tpl.hpp: 增加了类似于 java 中 final 功能的禁止继承的模板类 + +49) 2011.7.19 +49.1) 修改了 acl::xml 中有关 XML 解析的方法,同时增加了一些注释,方便用户使用 +49.2) feature: ssl_aio_stream/ssl_stream 允许来回切换流为 SSL 流或非 SSL 流 + +48) 2011.7.18 +48.1) 增加了 WIN32 平台下的版本号资源 + +47) 2011.7.16 +47.1) 消除了异步IO的回调类中的多重继承问题 + +46) 2011.7.3-7.6 +46.1) feature: 增加了新类对象 ssl_aio_stream,该类支持基于 polarssl 的加密 +传输,不过目前该类对象仅支持客户端连接流,该类是支持非阻塞IO的SSL加密流对象 +46.2) bugfix: ssl_stream(基于 polarssl 的阻塞流) 类对象修改了几处可能的问题 + +45) 2011.6.29 +45.1) aio_stream/aio_istream/aio_ostream: 在添加回调类对象时,内部会动态 +分配内存块用来存储这些对象,这样在类对象的回调中如果用户即调用删除回调类 +对象的函数,这些动态分配的内存区并不会被误删除,从而可以保证之后对这些存 +储对象的访问不至于出现非法访问的问题 + +44) 2011.6.28 +44.1) feature: +aio_stream 类: 增加了 del_close_callback/del_timeout_callback + /disable_close_callback/disable_timeout_callback +aio_ostream 类: 增加了 del_write_callback/disable_write_callback +aio_istream 类: 增加了 del_read_callback/disable_read_callback + +43) 2011.6.24 +43.1) http_header: 去掉了类构造函数的两个无用的参数(domain 和 port) +43.2) http_request: 在类构造函数中添加了 domain, port 两个参数 + +42) 2011.6.23 +42.1) 将 http_stream.c/http_stream.h 改名为 http_client.c/http_client.h + +41) 2011.6.22 +41.1) 修改了 Doxygen 报错的一些头文件中的注释 + +40) 2011.6.21 +40.1) 为了与 VC 编辑器兼容,将所有的源文件和头文件都转成 DOS 方式,即回车 +换行采用 \r\n,主要是 VIM 比较智能,它能根据文件的换行格式自动选取,而VC +就比较弱,虽然VC识别\n,但添加换行时只会添加\r\n + +39) 2011.6.16 +39.1) 修改了一下 VC 的工程文件 +39.2) http_request, dns_result_callback 两个 类增加了 destroy 虚接口, +以便于在子类中进行销毁类对象 +39.3) bugfix: aio_handle.cpp, aio_timer_callback::del_task 不应该在调用 +tasks_.erase(it); 之后的循环外再次判断 it == tasks_.end(),因为 iterator +被删除后 it 也就没有任何意义了 + +38) 2011.6.15 +38.1) 为了便于使用 VC 自带的比较弱知的 NEW 宏来检查内存泄漏,不得不把内部 +所有的 new 都改成 NEW;在 acl_stafx.hpp 中添加了 WIN23 下的 NEW 宏定义 +38.2) feature: 增加了类接口 aio_delay_free,这样子类只要继承该类,就可以 +在异步引擎中被延迟释放;同时,将 aio_timer_callback 做为 aio_delay_free 的 +子类;将 aio_handle 中的 delay_free_timer 改为 delay_free,从而使该功能成 +为一个更为通用的功能 + +37) 2011.6.13 +37.1) HttpClient 创建了 vc2010 下的工程 + +36) 2011.6.10 +36.1) 调整了一下在 VC 开始环境的工程 + +35) 2011.6.9 +35.1) feature: 增加了 http_service 类,可以方便进行HTTP请求处理过程 +35.2) ipc_service: 优化了一些处理过程 + +34) 2011.6.1 +34.1) feature: 异步定时器支持子类定时器可以设置多个定时消息事件 + +33) 2011.5.23 +33.1) feature: win32 下支持 iconv 了 + +32) 2011.5.16 +32.1) 将所有与定时器相关的精度由秒级提高到微秒级 + +31) 2011.5.13 +31.1) bugfix: aio_ostream.cpp 中的类 aio_timer_writer::timer_callback() +中使用了一个无效的 iterator 进行判断 +31.2) compile: 将 acl_stdafx.hpp 放在 src/ 目录下,以保持私有性 +31.3) compile: 将VC链接时的警告去(/EDITANDCONTINUE, /OPT:ICF),只需要 +打开增量链接就可以了 + +30) 2011.5.12 +30.1) feature: 增加了类 rfc822,用于解析对符合 rfc822 规范的邮件内容(如 +邮件地址, 日期) 进行解析 +30.2) samples: 增加了测试程序 samples/rfc822 + +29) 2011.5.6 +29.1) feature: aio_stream 类增加了 get_astream() 接口可以获得 ACL_ASTREAM 对象 + +28) 2011.5.2 +28.1) feature: xml.hpp, 增加了 get_xml_node() 函数 +28.2) feature: stream.hpp, 增加了 get_vstream() 函数 +28.3) feature: socket_stream.hpp, 增加了 open(ACL_VSTREAM*) 函数 + +27) 2011.4.21 +27.1) mime/header_opts.cpp: 去掉了 header_opts_begin, header_opts_cleanup +两个函数,在内部增加了 acl_pthread_once, atexit 两个系统调用,可以保证内部 +的全局静态对象仅被初始化一次,且当程序退出时会自动释放该对象 +27.2) mime.cpp: mime::init(), mime::cleanup() 已经没有用处了,将来将会被去掉 + +26) 2011.4.15 +26.1) xml: 增加了几个功能函数,方便取得 XML 对象中的相关属性值 +26.2) acl_stdafx.hpp: 去掉了 *.hpp 包含 + +25) 2011.4.14 +25.1) handlersocket: 增加了单独的 hsproto 类,专门用于协议处理 + +24) 2011.4.9 +24.1) handlersocket, hsclient: 增加了因网络IO问题出错的重试功能 +24.2) 修复了在高版本 gcc 上的编译错误 + +23) 2011.4.7-4.8 +23.1) handlersocket: 优化了代码,并修复了一些问题,现在 handlersocket 主要由 +hspool, hsclient, hstable, hsrow 四个类组成 + +22) 2011.3.31 +22.1) bugfix: log.hpp 中的函数名可能会造成 VC2003 在函数重载解析后出错而导致 +在运行时程序出现不可预知问题,所以将 log.hpp 中的函数名区分开,而不采用C++中 +函数名的重载方式 + +21) 2011.3.28 +21.1) aio_xxx: 增加了异步流的功能,并修改了延迟读的 BUG + +20) 2011.3.25 +20.1) aio_handle.cpp: 当异步句柄为 WIN GUI 消息时,允许用户绑定自定义的消息号 + +19) 2011.3.16-3.20 +19.1) feature: 在异步流的基础上增加了 ipc_xxx 等相关功能类,这些类可以保证 +在不同线程或不同进程之间进行异步通信 +19.2) feature: 在 ipc_xxx 基础上增加了 ipc_manager 类,该类可以保证主线程为 +非阻塞过程,而子线程是阻塞过程,子线程通过 ipc 方式与主线程进行通信 +19.3) feature: 在 ipc_manager 的基础上增加了 DNS 异步查询的功能类,该类的特 +点是主线程是非阻塞的,而查询子线程是阻塞的,查询子线程通过 ipc_xxx 方式将结 +果通知主线程 + +18) 2011.3.14 +18.1) feature: aio_ostream/aio_istream 增加了延迟写/读的功能,方便网络限速 + +17) 2011.3.13 +17.1) aio_handle: 增加了针对 WIN32 界面消息的支持 +17.2) aio_handle: 增加了定时器功能 + +16) 2011.3.10 +16.1) aio_xxx: 基本上成熟,可以使用了:) +16.2) string.cpp: 增加了二进制流及文件流的区分功能 + +15) 2011.3.8 +15.1) aio: 继续完善 + +14) 2011.3.1 +14.1) 完善了非阻塞IO的函数库 + +13) 2011.2.26-27 +13.1) feature: 添加了异步非阻塞流的支持,增加了如下几个文件: +aio_stream.cpp, aio_socket_stream.cpp, aio_ostream.cpp, +aio_istream.cpp, aio_listen_stream.cpp + +12) 2011.2.25 +12.1) 修改了所有头文件,减少了使用 #include 的包含数量 + +11) 2011.2.23 +11.1) feature: rfc2047, 增加了编码函数 +11.2) feature: mime_base64, mime_xxcode, mime_uucode, mime_quoted_printable +增加了静态编码及静态解码的函数 +11.3) bugfix: mem_cache, 采用 rfc2047 编码来处理协议中键值的特殊字符 + +10) 2011.2.22 +10.1) mem_cache: 对 key 键值进行了简单的编码处理,以免与 memcached 协议的 +分隔符有冲突 + +9) 2011.2.19 +9.1) bugfix: header_opts.cpp,内部使了一个线程不安全的静态变量 + +8) 2011.2.17 +8.1) feature: mem_cache, 增加了更新存在键时间截的接口 + +7) 2011.2.14 +7.1) feature: mem_cache 类封装了 libmemcached 的一些函数 +7.2) samples: mem_cache/ + +6) 2011.2.12 +6.1) feature: hsclient 该类增加了一些方便使用的函数接口 + +5) 2011.2.10 +5.1) feature: 增加了对 handlersocket 的协议支持, hsclient.cpp + +4) 2011.1.28 +4.1) feature: mime_head.cpp, 增加了 header_values()/2, 用于获得对就相同名称 +的多个字段的值集合 + +3) 2011.1.26 +3.1) bugfix: mime.cpp, body_node(), 中查找邮件正文时如果不存在HTML格式的 +正文时会有问题 + +2) 2011.1.14 +2.1) bugfix: mime_state_parse.cpp, 当邮件为非 multipart 时,结点的 +body_end 不对,应该是当前偏移量值 curr_off - 1 而不是 curr_off,因为 +curr_off 指的是文件中的下一个要处理的位置。 + +1) 2011.1.11 +1.1) acl_wrap1.0 release + diff --git a/lib_acl_cpp/include/acl_cpp/acl_cpp_define.hpp b/lib_acl_cpp/include/acl_cpp/acl_cpp_define.hpp new file mode 100644 index 000000000..ba8b409e1 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/acl_cpp_define.hpp @@ -0,0 +1,32 @@ +#pragma once + +#ifndef ACL_CPP_API +# ifdef ACL_CPP_DLL +# ifdef ACL_CPP_EXPORTS +# define ACL_CPP_API __declspec(dllexport) +# else +# define ACL_CPP_API __declspec(dllimport) +# endif +# else +# define ACL_CPP_API +# endif +#endif +#include +#include +#include +#include + +#ifdef WIN32 +# pragma warning(disable:4251) +//# if !defined(VC2003) && !defined(VC6) +//extern "C" { FILE _iob[3] = {__iob_func()[0], __iob_func()[1], __iob_func()[2]}; } +//extern "C" { FILE _iob[3]; } +//# endif +# ifndef ssize_t +# define ssize_t long +# endif +#else +# ifdef HAVE_MEMCACHED +# undef HAVE_MEMCACHED +# endif +#endif diff --git a/lib_acl_cpp/include/acl_cpp/acl_cpp_init.hpp b/lib_acl_cpp/include/acl_cpp/acl_cpp_init.hpp new file mode 100644 index 000000000..fb3ac1c43 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/acl_cpp_init.hpp @@ -0,0 +1,17 @@ +#pragma once +#include "acl_cpp_define.hpp" + +namespace acl +{ + + /** + * 在 WIN32 dos 窗口下,如果需要使用套接口操作, + * 则需要先调用此函数进行初始化 + */ + ACL_CPP_API void acl_cpp_init(void); + +#ifdef WIN32 + ACL_CPP_API void open_dos(void); +#endif + +} diff --git a/lib_acl_cpp/include/acl_cpp/acl_cpp_test.hpp b/lib_acl_cpp/include/acl_cpp/acl_cpp_test.hpp new file mode 100644 index 000000000..18eb96c51 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/acl_cpp_test.hpp @@ -0,0 +1,9 @@ +#pragma once +#include "acl_cpp_define.hpp" + +namespace acl +{ + ACL_CPP_API void test_logger(void); + ACL_CPP_API void test_snprintf(void); +} + diff --git a/lib_acl_cpp/include/acl_cpp/beanstalk/beanstalk.hpp b/lib_acl_cpp/include/acl_cpp/beanstalk/beanstalk.hpp new file mode 100644 index 000000000..c35e80198 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/beanstalk/beanstalk.hpp @@ -0,0 +1,301 @@ +#pragma once +#include +#include +#include "acl_cpp/acl_cpp_define.hpp" +#include "acl_cpp/stream/socket_stream.hpp" + +struct ACL_ARGV; + +namespace acl { + +/** + * 消息 ID 号从 1 开始递增(参加 beanstalkd 的 job.c 源程序中的如下内容: + * static uint64 next_id = 1; 及 make_job_with_id() 中的 + * if (id) { + * j->r.id = id; + * if (id >= next_id) next_id = id + 1; + * } else { + * j->r.id = next_id++; + * } + * 消息优先级 pri 的取值范围为 0 ~ 4,294,968,295(最大无符号整数值),值越小 + * 则优先级别越高,最高级别为 0 级 + * 消息体默认最大长度为 65,535(最大无符号 short 值),该值可以在启动 beanstalkd 指定 + * 更多内容请参考本项目 doc/ 目录下的 + * 本类中的命令过程内部会自动进行连接操作,在重连过程中,如果之前设置了 watch 及 use + * 队列,则会自动重试这些命令过程,所以一般来说不用显式调用 open 过程;当用户调用了 + * close 函数后,不仅断开了与 beanstalkd 服务器的连接,同时会清除本类对象中存储的 + * use 及 watch 队列 + */ +class ACL_CPP_API beanstalk +{ +public: + /** + * 构造函数 + * @param addr {const char*} beanstalkd 地址,格式:ip:port/domain:port + * @param conn_timeout {int} 连接服务器的超时时间(秒) + * @param retry {bool} 如果连接断了是否自动重连 + */ + beanstalk(const char* addr, int conn_timeout, bool retry = true); + ~beanstalk(); + + ///////////////////////////////////////////////////////////////////// + // 生产者调用的接口 + + /** + * 选择所用的发送管道 + * @param tube {const char*} 管道名称 + * @return {bool} 是否成功 + */ + bool use(const char* tube); + + /** + * 向所选管道或缺省管理中发送消息 + * @param data {const void*} 消息数据地址,可以是二进制 + * @param len {size_t} data 数据体长度 + * @param pri {unsigned} 优先级,值越小,优先级越高 + * @param delay {unsigned} 表示将job放入ready队列需要等待的秒数 + * @param ttr {unsigned} 表示允许一个worker执行该消息的秒数 + * @return {unsigned long long} 返回所添加消息的消息号, + * 如果返回值 > 0 则表示添加成功,若 == 0 则表示添加失败 + * (查看 beanstalkd 源码,可以看出消息号从 1 开始增加) + */ + unsigned long long put(const void* data, size_t len, + unsigned pri = 1024, unsigned delay = 0, unsigned ttr = 60); + + /** + * 以格式字符串方式向所选管道或缺省管理中发送消息 + * @param pri {unsigned} 优先级,值越小,优先级越高 + * @param delay {unsigned} 表示将job放入ready队列需要等待的秒数 + * @param ttr {unsigned} 表示允许一个worker执行该消息的秒数 + * @param fmt {const char*} 格式字符串 + * @return {unsigned long long} 返回所添加消息的消息号, + * 如果返回值 > 0 则表示添加成功,若 == 0 则表示添加失败 + * (查看 beanstalkd 源码,可以看出消息号从 1 开始增加) + */ + unsigned long long format_put(unsigned pri, unsigned delay, unsigned ttr, + const char* fmt, ...); + unsigned long long vformat_put(const char* fmt, va_list ap, + unsigned pri = 1024, unsigned delay = 0, unsigned ttr = 60); + + /** + * 以格式字符串方式向所选管道或缺省管理中发送消息,其中的 + * 的 pri, delay, ttr 采用默认值 + * @param fmt {const char*} 格式字符串 + * @return {unsigned long long} 返回所添加消息的消息号, + * 如果返回值 > 0 则表示添加成功,若 == 0 则表示添加失败 + * (查看 beanstalkd 源码,可以看出消息号从 1 开始增加) + */ + unsigned long long format_put(const char* fmt, ...); + + ///////////////////////////////////////////////////////////////////// + // 消费者调用的接口 + + /** + * 选择读取消息的管道,将其加入监控管理列表中, + * 不调用本函数,则使用缺省的管道(default) + * @param tube {const char*} 消息管道名称 + * @return {unsigned} 返回值为关注的消息管道数, 返回值 > 0 则表示成功 + */ + unsigned watch(const char* tube); + + /** + * 取消关注(watch)一个接收消息的管道(tube) + * @param tube {const char*} 消息管道名称 + * @return {unsigned} 返回值为剩余的消息关注管道数, 返回值 > 0 则表示 + * 成功(因至少要关注一个缺省消息管道,所以正确情况下该返回值至少为 1), + * 如果返回值为 0 则说明输入的管道并未被关注或取消关注失败 + */ + unsigned ignore(const char* tube); + + /** + * 取消关注所有的接收消息的管道 + * @return {unsigned} 返回值为剩余的消息关注管道数, 返回值 > 0 则表示 + * 成功(因至少要关注一个缺省消息管道,所以正确情况下该返回值至少为 1), + * 返回 0 表示取消关注失败 + */ + unsigned ignore_all(); + + /** + * 从消息输出管道中获取一条消息,但并不删除消息,可以设置 + * 等待超时,如果设为 -1 则永远阻塞等待消息可用 + * @param buf {string&} 存储获得的一条消息,函数内部会先清空该缓冲区 + * @param timeout {int} 等待队列服务器返回消息的超时值,当为 -1 + * 时,则无限期等待,当 > 0 时,则在该时间内若没有消息,则返回, + * 当 == 0 时,则立即返回一条消息或返回超时 + * @return {unsigned long long} 返回所取得的消息号,若返回值 > 0 + * 表示正确取到一个消息,否则说明出错或超时没有消息可用 + */ + unsigned long long reserve(string& buf, int timeout = -1); + + /** + * 从队列服务器中删除指定 ID 号的消息 + * @param id {unsigned long long} 消息号 + * @return {bool} 是否成功删除 + */ + bool delete_id(unsigned long long id); + + /** + * 将一个已经被获取的消息重新放回ready队列(并将job状态置为 "ready"), + * 让该消息可以被其它连接获得 + * @param id {unsigned long long} 消息号 + * @param pri {unsigned} 优先级别 + * @param delay {unsigned} 在该消息被放入ready队列之前需要等待的秒数 + * @return {bool} 是否成功 + */ + bool release(unsigned long long id, unsigned pri = 1024, + unsigned delay = 0); + + /** + * 将一个消息的状态置为 "buried", Buried 消息被放在一个FIFO的链表中, + * 在客户端调用kick命令之前,这些消息将不会被服务端处理 + * @param id {unsigned long long} 消息号 + * @param pri {unsigned int} 优先级别 + * @return {bool} 是否成功 + */ + bool bury(unsigned long long id, unsigned pri = 1024); + + /** + * 允许一个worker请求在一个消息获取更多执行的时间。这对于那些需要 + * 长时间完成的消息是非常有用的,但同时也可能利用TTR的优势将一个消息 + * 从一个无法完成工作的worker处移走。一个worker可以通过该命令来告诉 + * 服务端它还在执行该job (比如:在收到DEADLINE_SOON是可以发生给命令) + * @param id {unsigned long long} 消息号 + * @return {bool} 是否成功 + */ + bool touch(unsigned long long id); + + ///////////////////////////////////////////////////////////////////// + // 其它接口 + + /** + * 连接 beanstalkd 服务器,通常情况下不需要显示地调用该函数,上述命令 + * 会自动根据需要自动调用本函数 + * @return {bool} 否成功 + */ + bool open(); + + /** + * 显示关闭与 beanstalkd 的连接,当该类实例析构时会尝试调用关闭过程, + * 调用本函数后,类对象内部的 tube_used_ 及 tubes_watched_ 会被释放 + */ + void close(); + + /** + * 显示通知 beanstalkd 服务器退出连接(服务器收到此命令后会立即关闭连接) + */ + void quit(); + + /** + * 获取消息队列中指定的消息号的数据 + * @param buf {string&} 如果消息存在则存储该条消息,函数内部会先清空该缓冲区 + * @param id {unsigned long long} 指定的消息号 + * @return {unsigned long long} 返回取得的 ready 状态消息号, + * 若返回值 > 0 则说明取得了一个消息,否则表示没有消息可用 + */ + unsigned long long peek(string& buf, unsigned long long id); + + /** + * 获得当前关注 (watch) 管道中的一条 ready 状态消息, + * 如果消息不存在也立即返回 + * @param buf {string&} 如果消息存在则存储该条消息,函数内部会先清空该缓冲区 + * @return {unsigned long long} 返回取得的 ready 状态消息号, + * 若返回值 > 0 则说明取得了一个消息,否则表示没有消息可用 + */ + unsigned long long peek_ready(string& buf); + + /** + * 获得当前关注 (watch) 管道中的一条 delayed 状态消息, + * 如果消息不存在也立即返回 + * @param buf {string&} 如果消息存在则存储该条消息,函数内部会先清空该缓冲区 + * @return {unsigned long long} 返回取得的 delayed 状态消息号, + * 若返回值 > 0 则说明取得了一个消息,否则表示没有消息可用 + */ + unsigned long long peek_delayed(string& buf); + + /** + * 获得当前关注 (watch) 管道中的一条 buried 状态消息, + * 如果消息不存在也立即返回 + * @param buf {string&} 如果消息存在则存储该条消息,函数内部会先清空该缓冲区 + * @return {unsigned long long} 返回取得的 buried 状态消息号, + * 若返回值 > 0 则说明取得了一个消息,否则表示没有消息可用 + */ + unsigned long long peek_buried(string& buf); + + /** + * 该命令只能针对当前正在使用的tube执行;它将 buried + * 或者 delayed 状态的消息移动到 ready 队列 + * @param n {unsigned} 表示每次 kick 消息的上限, + * 服务端将最多 kick 的消息数量 + * @return {int} 表示本次kick操作作用消息的数目,返回 -1 表示出错 + */ + int kick(unsigned n); + + /** + * 获得客户当前正在使用的消息管道 + * @param buf {string&} 存储当前使用的消息管道,函数内部会先清空该缓冲区 + * @return {bool} 是否成功获得 + */ + bool list_tube_used(string&buf); + + /** + * 获得已经存在的所有消息管道(tube)的列表集合 + * @param buf {string&} 存储结果,函数内部会先清空该缓冲区 + * @return {bool} 是否成功获得 + */ + bool list_tubes(string& buf); + + /** + * 获得当前关注(watch)的消息管道的集合 + * @param buf {string&} 存储结果,函数内部会先清空该缓冲区 + * @return {bool} 是否成功获得 + */ + bool list_tubes_watched(string& buf); + + /** + * 给定时间内暂停从指定消息管道(tube)中获取消息 + * @param tube {const char*} 消息管道名 + * @param delay {unsigned} 指定时间段 + * @return {bool} 是否成功 + */ + bool pause_tube(const char* tube, unsigned delay); + + ///////////////////////////////////////////////////////////////////// + // 公共接口 + const char* get_error() const + { + return errbuf_; + } + + socket_stream& get_conn() + { + return conn_; + } + + /** + * 返回构造函数中 beanstalkd 的服务器地址,格式:ip:port + * @return {const char*} 永远返回非空的 beanstalkd 服务器地址 + */ + const char* get_addr() const + { + return addr_; + } +private: + char* addr_; + int timeout_; + bool retry_; + char errbuf_[128]; + char* tube_used_; + std::vector tubes_watched_; + acl::socket_stream conn_; + unsigned long long peek_fmt(string& buf, const char* fmt, ...); + bool list_tubes_fmt(string& buf, const char* fmt, ...); + + unsigned ignore_one(const char* tube); + bool beanstalk_open(); + bool beanstalk_use(); + unsigned beanstalk_watch(const char* tube); + ACL_ARGV* beanstalk_request(const string& cmdline, + const void* data = NULL, size_t len = 0); +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/beanstalk/beanstalk_pool.hpp b/lib_acl_cpp/include/acl_cpp/beanstalk/beanstalk_pool.hpp new file mode 100644 index 000000000..d21c82632 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/beanstalk/beanstalk_pool.hpp @@ -0,0 +1,50 @@ +#pragma once +#include + +namespace acl { + +class beanstalk; +class locker; + +/** + * beanstalk 客户端连接池,可以同时连接不同的 beanstalkd 服务器, + * 每个 beanstalkd 有多个连接,内部自动加锁;但不控制连接数限制, + * 用户应自行控制连接池的最大连接上限 + */ +class beanstalk_pool +{ +public: + beanstalk_pool(); + ~beanstalk_pool(); + + /** + * 从连接池中取得一个 beanstalkd 的客户端连接 + * @param addr {const char*} beanstalkd 服务地址(domain:port) + * @param clean_watch {bool} 在取得连接对象后是否自动取消所有的 + * 已关注队列 + * @param conn_timeout {int} 连接 beanstalkd 的超时时间 + * @return {beanstalk*} 返回非空表示正常,否则表示出错 + */ + beanstalk* peek(const char* addr, bool clean_watch = true, + int conn_timeout = 60); + + /** + * 将不用的 beanstalkd 连接放回到连接池中 + * @param client {beanstalk*} beanstalkd 客户端连接 + * @param clean_watch {bool} 是否取消已经关注的队列 + * @param keep {bool} 如果为 true 则将 client 放回至连接池, + * 否则释放该连接 + */ + void put(beanstalk* client, bool clean_watch = true, + bool keep = true); +private: + locker* lock_; + typedef std::multimap bspool; + typedef bspool::const_iterator pool_cit; + typedef bspool::iterator pool_it; + typedef std::pair pool_range; + + bspool pool_; +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/connpool/connect_client.hpp b/lib_acl_cpp/include/acl_cpp/connpool/connect_client.hpp new file mode 100644 index 000000000..9e5a7dfc2 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/connpool/connect_client.hpp @@ -0,0 +1,38 @@ +#pragma once + +namespace acl +{ + +class connect_client +{ +public: + connect_client() : when_(0) {} + virtual ~connect_client() {} + + /** + * 获得该连接对象最近一次被使用的时间截 + * @return {time_t} + */ + time_t get_when() + { + return when_; + } + + /** + * 设置该连接对象当前被使用的时间截 + */ + void set_when(time_t when) + { + when_ = when; + } + + /** + * 纯虚函数,子类必须实现此函数用于连接服务器 + * @return {bool} 是否连接成功 + */ + virtual bool open() = 0; +private: + time_t when_; +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/connpool/connect_manager.hpp b/lib_acl_cpp/include/acl_cpp/connpool/connect_manager.hpp new file mode 100644 index 000000000..74aaa449e --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/connpool/connect_manager.hpp @@ -0,0 +1,106 @@ +#pragma once +#include + +namespace acl +{ + +class connect_pool; + +/** + * connect pool 服务管理器,有获取连接池等功能 + */ +class connect_manager +{ +public: + connect_manager(); + virtual ~connect_manager(); + + /** + * 初始化所有服务器的连接池,该函数内部调用 set 过程添加每个服务的连接池 + * @param default_addr {const char*} 缺省的服务器地址,如果非空, + * 则在查询时优先使用此服务器 + * @param addr_list {const char*} 所有服务器列表,可以为空 + * 格式:IP:PORT:COUNT|IP:PORT:COUNT ... + * 如:127.0.0.1:7777:50|192.168.1.1:7777:10|127.0.0.1:7778 + * @param default_count {int} 当 addr_list 中分隔的某个服务没有 + * COUNT 信息时便用此值 + * 注:default_addr 和 addr_list 不能同时为空 + */ + void init(const char* default_addr, const char* addr_list, + int default_count); + + /** + * 添加服务器的客户端连接池 + * @param addr {const char*} 服务器地址(ip:port) + * @param count {int} 连接池数量限制 + * @return {connect_pool&} 返回新添加的连接池对象 + */ + connect_pool& set(const char* addr, int count); + + /** + * 获得某个服务器的连接池 + * @param addr {const char*} redis 服务器地址(ip:port) + * @return {connect_pool*} 返回空表示没有此服务 + */ + connect_pool* get(const char* addr); + + /** + * 在读操作时,从连接池集群中获得一个连接池 + * @return {connect_pool*} 返回一个连接池,返回 NULL 表示根据随机方式 + * 无法获取有效连接池,应用需要重试其它方式 + */ + connect_pool* peek(); + + /** + * 获得所有的服务器的连接池,该连接池中包含缺省的服务连接池 + * @return {std::vector&} + */ + std::vector& get_pools() + { + return pools_; + } + + /** + * 获得缺省的服务器连接池 + * @return {connect_pool*} + */ + connect_pool* get_default_pool() + { + return default_pool_; + } + + /** + * 初始化定时器,该定时器会定期打印当前所有服务器集群的访问统计 + * @param inter {int} 定时器的输出间隔 + */ + void statistics_settimer(int inter = 1); + + /** + * 打印当前所有 redis 连接池的访问量 + */ + void statistics(); + +protected: + /** + * 纯虚函数,子类必须实现此函数用来创建连接池对象 + * @param addr {const char*} 服务器监听地址,格式:ip:port + * @param count {int} 连接池的大小限制 + */ + virtual connect_pool* create_pool(const char* addr, int count) = 0; +private: + static void statistics_record(int, void* ctx); + void statistics_timer(); +private: + string default_addr_; // 缺省的服务地址 + connect_pool* default_pool_; // 缺省的服务连接池 + std::vector pools_; // 所有的服务连接池 + size_t service_size_; // 缓存住当前总的服务器集群数量 + size_t service_idx_; // 下一个要访问的的下标值 + locker lock_; // 访问 pools_ 时的互斥锁 + int stat_inter_; // 统计访问量的定时器间隔 + + // 设置除缺省服务之外的服务器集群 + void set_service_list(const char* addr_list, int count); +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/connpool/connect_pool.hpp b/lib_acl_cpp/include/acl_cpp/connpool/connect_pool.hpp new file mode 100644 index 000000000..7e73bda3d --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/connpool/connect_pool.hpp @@ -0,0 +1,140 @@ +#pragma once +#include +#include "acl_cpp/stdlib/locker.hpp" + +namespace acl +{ + +class connect_client; + +/** + * 客户端连接池类,实现对连接池的动态管理,该类为纯虚类,需要子类实现 + * 纯虚函数 create_connect 用于创建与服务端的一个连接 + */ +class connect_pool +{ +public: + /** + * 构造函数 + * @param addr {const char*} 服务器监听地址,格式:ip:port(domain:port) + * @param count {int} 连接池最大连接个数限制 + * @param retry_inter {int} 当连接断开后,重新再次打开连接的时间间隔(秒), + * 当该值 <= 0 时表示允许连接断开后可以立即重连,否则必须超过该时间间隔后才 + * 允许断开重连 + */ + connect_pool(const char* addr, int count, int retry_inter = 0); + virtual ~connect_pool(); + + /** + * 设置连接池中空闲连接的空闲生存周期 + * @param ttl {time_t} 空闲连接的生存周期,当该值 < 0 则表示空闲连接不过期, + * == 0 时表示立刻过期,> 0 表示空闲该时间段后将被释放 + * @return {connect_pool&} + */ + connect_pool& set_idle_ttl(time_t ttl); + + /** + * 从连接池中尝试性获取一个连接,当服务器不可用、距上次服务端连接异常时间间隔 + * 未过期或连接池连接个数达到连接上限则将返回 NULL;当创建一个新的与服务器的 + * 连接时失败,则该连接池会被置为不可用状态 + * @return {connect_client*} 如果为空则表示该服务器连接池对象不可用 + */ + connect_client* peek(); + + /** + * 释放一个连接至连接池中,当该连接池对应的服务器不可用或调用者希望关闭该连接时, + * 则该连接将会被直接释放 + * @param conn {redis_client*} + * @param keep {bool} 是否针对该连接保持长连接 + */ + void put(connect_client* conn, bool keep = true); + + /** + * 检查连接池中空闲的连接,将过期的连接释放掉 + * @param ttl {time_t} 空闲时间间隔超过此值的连接将被释放 + * @param exclusive {bool} 内部是否需要加锁 + * @return {int} 被释放的空闲连接个数 + */ + int check_idle(time_t ttl, bool exclusive = true); + + /** + * 设置连接池的存活状态 + * @param ok {bool} 设置该连接是否正常 + */ + void set_alive(bool ok /* true | false */); + + /** + * 获取连接池的服务器地址 + * @return {const char*} 返回非空地址 + */ + const char* get_addr() const + { + return addr_; + } + + /** + * 获取连接池最大连接数限制 + * @return {int} + */ + int get_count() const + { + return count_; + } + + /** + * 重置统计计数器 + * @param inter {int} 统计的时间间隔 + */ + void reset_statistics(int inter) + { + time_t now = time(NULL); + lock_.lock(); + if (now - last_ >= inter) + { + last_ = now; + current_used_ = 0; + } + lock_.unlock(); + } + + /** + * 获取该连接池总共被使用的次数 + */ + unsigned long long get_total_used() const + { + return total_used_; + } + + /** + * 获取该连接池当前的使用次数 + * @return {unsigned long long} + */ + unsigned long long get_current_used() const + { + return current_used_; + } + +protected: + virtual connect_client* create_connect() = 0; + +protected: + // 是否属正常 + bool alive_; + // 有问题的服务器的可以重试的时间间隔,不可用连接池对象再次被启用的时间间隔 + int retry_inter_; + time_t last_dead_; // 该连接池对象上次不可用时的时间截 + char addr_[64]; // 连接池对应的服务器地址,IP:PORT + int max_; // 最大连接数 + int count_; // 当前的连接数 + time_t idle_ttl_; // 空闲连接的生命周期 + time_t last_check_; // 上次检查空闲连接的时间截 + int check_inter_; // 检查空闲连接的时间间隔 + + locker lock_; // 访问 pool_ 时的互斥锁 + unsigned long long total_used_; // 该连接池的所有访问量 + unsigned long long current_used_; // 某时间段内的访问量 + time_t last_; // 上次记录的时间截 + std::list pool_; // 连接池集合 +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/db/db_handle.hpp b/lib_acl_cpp/include/acl_cpp/db/db_handle.hpp new file mode 100644 index 000000000..d671268b3 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/db/db_handle.hpp @@ -0,0 +1,398 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include +#include "acl_cpp/stdlib/string.hpp" + +namespace acl { + +/** + * 数据库查询结果集的行记录类型定义 + */ +class ACL_CPP_API db_row +{ +public: + /** + * 构造函数 + * @param names {const std::vector&} 数据库表中字段名列表 + */ + db_row(const std::vector& names); + ~db_row(); + + /** + * 取得数据表中的某个对应下标值的字段名 + * @param ifield {size_t} 下标值 + * @return {const char*} 返回空说明该下标值越界 + */ + const char* field_name(size_t ifield) const; + + /** + * 从查询结果的记录行中根据字段名取得相应的字段值 + * @param name {const char*} 数据表的字段名 + * @return {const char*} 对应的字段值,为空则表示字段值不存在或 + * 字段名非法 + */ + const char* field_value(const char* name) const; + + /** + * 从查询结果的记录行中根据字段名取得相应的字段值, + * 功能与 field_value 相同 + * @param name {const char*} 数据表的字段名 + * @return {const char*} 对应的字段值,为空则表示字段值不存在或 + * 字段名非法 + */ + const char* operator[](const char* name) const; + + /** + * 从查询结果的记录行中取得对应下标的字段值 + * @param ifield {size_t} 下标值,该值应 < 字段名的个数 + * @return {const char*} 对应的字段值,为空则表示下标值非法或 + * 字段值不存在 + */ + const char* field_value(size_t ifield) const; + + /** + * 从查询结果的记录行中取得对应下标的字段值,功能与 field_value 相同 + * @param ifield {size_t} 下标值,该值应 < 字段名的个数 + * @return {const char*} 对应的字段值,为空则表示下标值非法或 + * 字段值不存在 + */ + const char* operator[](size_t ifield) const; + + /** + * 从查询结果的记录行中取得对应下标的整数类型的字段值 + * @param ifield {size_t} 下标值 + * @param null_value {int} 当结果为空时,返回此值表示未有相应结果 + * @return {int} 当返回值与用户输入的 null_value 值相同时表明没有查到结果 + */ + int field_int(size_t ifield, int null_value = 0) const; + + /** + * 从查询结果的记录行中取得字段名的整数类型的字段值 + * @param name {const char*} 下标值 + * @param null_value {int} 当结果为空时,返回此值表示未有相应结果 + * @return {int} 当返回值与用户输入的 null_value 值相同时表明没有查到结果 + */ + int field_int(const char* name, int null_value = 0) const; + + + /** + * 从查询结果的记录行中取得对应下标的整数类型的字段值 + * @param ifield {size_t} 下标值 + * @param null_value {acl_int64} 当结果为空时,返回此值表示未有相应结果 + * @return {acl_int64} 当返回值与用户输入的 null_value 值相同时表明没有查到结果 + */ +#ifdef WIN32 + __int64 field_int64(size_t ifield, __int64 null_value = 0) const; +#else + long long int field_int64(size_t ifield, long long int null_value = 0) const; +#endif + + /** + * 从查询结果的记录行中取得字段名的整数类型的字段值 + * @param name {const char*} 下标值 + * @param null_value {acl_int64} 当结果为空时,返回此值表示未有相应结果 + * @return {acl_int64} 当返回值与用户输入的 null_value 值相同时表明没有查到结果 + */ +#ifdef WIN32 + __int64 field_int64(const char* name, __int64 null_value = 0) const; +#else + long long int field_int64(const char* name, long long int null_value = 0) const; +#endif + + /** + * 从查询结果的记录行中取得对应下标的字符串类型的字段值 + * @param ifield {size_t} 下标值 + * @return {const char*} 当返回值 NULL 时表明没有查到结果 + */ + const char* field_string(size_t ifield) const; + + /** + * 从查询结果的记录行中取得字段名的字符串类型的字段值 + * @param name {const char*} 下标值 + * @return {const char*} 当返回值 NULL 时表明没有查到结果 + */ + const char* field_string(const char* name) const; + + /** + * 向记录行添加一个字段值,添加字段值的顺序应该与字段名的顺序一致 + * @param value {const char*} 该行记录的某个字段值 + */ + void push_back(const char* value); + + /** + * 行记录中字段值的个数 + * @return {size_t} + */ + size_t length() const; +protected: +private: + // 数据表的字段名集合的引用 + const std::vector& names_; + + // 数据结果行的字段集合 + std::vector values_; +}; + +/** + * 数据库查询结果的行记录集合类型定义 + */ +class ACL_CPP_API db_rows +{ +public: + db_rows(); + virtual ~db_rows(); + + /** + * 从查询的行记录集合中根据表字段名对应的字段值取出结果记录集合 + * @param name {const char*} 数据表字段名(不区分大小写) + * @param value {const char*} 数据表字段值(区分大小写) + * @return {const std::vector&} 返回行记录集合类型对象, + * 可以通过调用 db_rows.empty() 来判断结果是否为空 + */ + const std::vector& get_rows( + const char* name, const char* value); + + /** + * 取得所有的查询结果集 + * @return {const std::vector&} 返回行记录集合类型对象, + * 可以通过调用 db_rows.empty() 来判断结果是否为空 + */ + const std::vector& get_rows() const; + + /** + * 从查询的行记录集合中根据索引下标取得对应的某行记录 + * @param idx {size_t} 索引下标,该值应该 < 结果集大小 + * @return {const db_row*} 返回空表示输入下标值非法或字段值本身 + * 为空 + */ + const db_row* operator[](size_t idx) const; + + /** + * 判断结果集是否为空 + * @return {bool} 是否为空 + */ + bool empty() const; + + /** + * 结果集的行记录个数 + * @return {size_t} 行记录个数 + */ + size_t length() const; +protected: + // 数据表字段名 + std::vector names_; + + // 查询结果行集合,其中的元素 db_row 必须是动态添加进去的, + // 因为在本类对象析构时会自动 delete rows_ 中的所有元素对象 + std::vector rows_; + + // 临时结果行集合 + std::vector rows_tmp_; +private: +}; + +class db_pool; + +/** + * 数据库操作句柄对象类型 + */ +class ACL_CPP_API db_handle +{ +public: + db_handle(void); + virtual ~db_handle(void); + + /** + * 返回数据库的类型描述 + * @return {const char*} + */ + virtual const char* dbtype() const = 0; + + /** + * 获得上次数据库操作的出错错误号 + * @return {int} + */ + virtual int get_errno() const + { + return -1; + } + + /** + * 获得上次数据库操作的出错错描述 + * @return {const char*} + */ + virtual const char* get_error() const + { + return "unkonwn error"; + } + + /** + * 纯虚接口,子类必须实现此接口用于打开数据库 + * @param local_charset {const char*} 本地字符集 + * @return {bool} 打开是否成功 + */ + virtual bool open(const char* local_charset = "GBK") = 0; + + /** + * 数据库是否已经打开了 + * @return {bool} 返回 true 表明数据库已经打开了 + */ + virtual bool is_opened() const = 0; + + /** + * 纯虚接口,子类必须实现此接口用于判断数据表是否存在 + * @return {bool} 是否存在 + */ + virtual bool tbl_exists(const char* tbl_name) = 0; + + /** + * 纯虚接口,子类必须实现此接口用于关闭数据库 + * @return {bool} 关闭是否成功 + */ + virtual bool close() = 0; + + /** + * 纯虚接口,子类必须实现此接口用于执行 SQL 语句 + * @param sql {const char*} 标准的 SQL 语句,非空,并且一定得要注册该 + * SQL 语句必须经过转义处理,以防止 SQL 注入攻击 + * @return {bool} 执行是否成功 + */ + virtual bool sql_select(const char* sql) = 0; + + /** + * 纯虚接口,子类必须实现此接口用于执行 SQL 语句 + * @param sql {const char*} 标准的 SQL 语句,非空,并且一定得要注册该 + * SQL 语句必须经过转义处理,以防止 SQL 注入攻击 + * @return {bool} 执行是否成功 + */ + virtual bool sql_update(const char* sql) = 0; + + /** + * 虚接口,为防止 sql 注入,用户应针对字符串字段调用此函数将一些特殊 + * 字符进行转义,该接口对常见的特殊字符进行了转义,子类也可以实现自己 + * 的转义方法 + * @param in {const char*} 输入字符串 + * @param len {size_t} 字符串长度 + * @param out {string&} 存储转换结果 + * @return {string&} 子类应该返回输入的缓冲区的引用,以便于用户在拼接 + * SQL 的时候比较方便 + */ + virtual string& escape_string(const char* in, size_t len, string& out); + + /** + * 上次 sql 操作影响的记录行数 + * @return {int} 影响的行数,-1 表示出错 + */ + virtual int affect_count() const = 0; + + ////////////////////////////////////////////////////////////////////////// + + /** + * 获得执行 SQL 语句后的结果 + * @return {const db_rows*},返回结果若非空,则用完后需要调用 + * free_result() 以释放结果对象 + */ + const db_rows* get_result() const; + + /** + * 从查询的行记录集合中根据表字段名对应的字段值取出结果记录集合 + * @param name {const char*} 数据表字段名(不区分大小写) + * @param value {const char*} 数据表字段值(区分大小写) + * @return {const std::vector*} 返回行记录集合类型对象, + * 若返回结果集非空,则必须调用 free_result() 以释放结果对象 + */ + const std::vector* get_rows( + const char* name, const char* value); + + /** + * 取得所有的查询结果集 + * @return {const std::vector*} 返回行记录集合类型对象, + * 若返回结果集非空,则必须调用 free_result() 以释放结果对象 + */ + const std::vector* get_rows() const; + + /** + * 获得执行 SQL 语句后的第一行结果,这对于唯一键的数据查询时显得比较便捷些 + * @return {const db_row*} 返回空表示查询结果为空,如果返回结果非空,则必须 + * 调用 free_result() 函数来释放中间的结果内存,否则会引起内存泄露 + */ + const db_row* get_first_row() const; + + /** + * 释放上次查询的结果,当查询完成后,必须调用该函数来释放 + * 不次查询的结果,该函数被多次调用并无害处,因为当第一次 + * 调用时会自动将内部变量 result_ 置空 + */ + void free_result(); + + /** + * 获得某个对应下标值的行记录 + * @param idx {size_t} 下标值,必须小于查询结果的总数 + * @return {const db_row*} 结果,如果为空,则有可能是下标越界, + * 也有可能是结果为空 + */ + const db_row* operator[](size_t idx) const; + + /** + * 取得查询(sql_select)结果的行记录数 + * @return {size_t} 结果行记录数,若为 0 则表示结果为空 + */ + size_t length() const; + + /** + * 查询(sql_select)执行完后结果是否为空 + * @return {bool} 返回 true 表示查询结果为空 + */ + bool empty() const; + + /** + * 输出数据库查询结果 + * @param max {size_t} 输出至屏幕的行记录数的最大值限制,如果该值为 0 + * 则输出所有的结果集 + */ + void print_out(size_t max = 0) const; + + ///////////////////////////////////////////////////////////////// + /** + * 设置本实例的唯一 ID + * @param id {const char*} 唯一 ID + * @return {db_handle&} + */ + db_handle& set_id(const char* id); + + /** + * 获得本实例的唯一 ID + * @return {const char*} 为空时,表示未曾设置过唯一ID + */ + const char* get_id() const + { + return id_; + } + + /** + * 设置本数据库连接句柄当前被使用的时间 + * @param now {time_t} + * @return {db_handle&} + */ + db_handle& set_when(time_t now); + + /** + * 获得该连接句柄上次被使用的时间 + * @return {time_t} + */ + time_t get_when() const + { + return when_; + } +protected: + // 临时结果对象 + db_rows* result_; + + // 实例唯一 ID + char* id_; + + // 该数据库连接句柄最近被使用的时间 + time_t when_; +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/db/db_mysql.hpp b/lib_acl_cpp/include/acl_cpp/db/db_mysql.hpp new file mode 100644 index 000000000..a80851f52 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/db/db_mysql.hpp @@ -0,0 +1,124 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include "acl_cpp/db/db_handle.hpp" + +typedef struct st_mysql MYSQL; + +namespace acl { + +class ACL_CPP_API db_mysql : public db_handle +{ +public: + db_mysql(const char* dbaddr, const char* dbname, + const char* dbuser, const char* dbpass, + unsigned long dbflags = 0, bool auto_commit = true, + int conn_timeout = 60, int rw_timeout = 60); + ~db_mysql(void); + + /** + * 获得 mysql 客户端库的版本号 + * @return {unsigned long} + */ + unsigned long mysql_libversion() const; + + /** + * 获得 mysql 客户端库的信息 + * @return {const char*} + */ + const char* mysql_client_info() const; + + /** + * 直接获得 mysql 的连接句柄,如果返回 NULL 则表示 mysql 还没有打开 + * 或出错时内部自动关闭了 mysql 连接 + * @return {MYSQL*} + */ + MYSQL* get_conn() const + { + return conn_; + } + + /************************************************************************/ + /* 以下为基类 db_handle 的虚接口 */ + /************************************************************************/ + + /** + * 返回数据库的类型描述 + * @return {const char*} + */ + virtual const char* dbtype() const; + + /** + * 获得上次数据库操作的出错错误号 + * @return {int} + */ + virtual int get_errno() const; + + /** + * 获得上次数据库操作的出错错描述 + * @return {const char*} + */ + virtual const char* get_error() const; + + /** + * 基类 db_handle 的纯虚接口 + * @param local_charset {const char*} 本地字符集 + * @return {bool} 打开是否成功 + */ + virtual bool open(const char* local_charset = "GBK"); + + /** + * 基类 db_handle 的纯虚接口,数据库是否已经打开了 + * @return {bool} 返回 true 表明数据库已经打开了 + */ + virtual bool is_opened() const; + + /** + * 基类 db_handle 的纯虚接口 + * @return {bool} 关闭是否成功 + */ + virtual bool close(void); + + /** + * 基类 db_handle 的纯虚接口,子类必须实现此接口用于判断数据表是否存在 + * @return {bool} 是否存在 + */ + virtual bool tbl_exists(const char* tbl_name); + + /** + * 基类 db_handle 的纯虚接口 + * @param sql {const char*} 标准的 SQL 语句,非空,并且一定得要注册该 + * SQL 语句必须经过转义处理,以防止 SQL 注入攻击 + * @return {bool} 执行是否成功 + */ + virtual bool sql_select(const char* sql); + + /** + * 基类 db_handle 的纯虚接口 + * @param sql {const char*} 标准的 SQL 语句,非空,并且一定得要注册该 + * SQL 语句必须经过转义处理,以防止 SQL 注入攻击 + * @return {bool} 执行是否成功 + */ + virtual bool sql_update(const char* sql); + + /** + * 基类 db_handle 的纯虚接口:上次 sql 操作影响的记录行数 + * @return {int} 影响的行数,-1 表示出错 + */ + virtual int affect_count() const; +protected: +private: + char* dbaddr_; // 数据库监听地址 + char* dbname_; // 数据库名 + char* dbuser_; // 数据库账号 + char* dbpass_; // 数据库账号密码 + + unsigned long dbflags_; + int conn_timeout_; + int rw_timeout_; + bool auto_commit_; + MYSQL* conn_; + + bool sane_mysql_query(const char* sql); +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/db/db_pool.hpp b/lib_acl_cpp/include/acl_cpp/db/db_pool.hpp new file mode 100644 index 000000000..b977e7b47 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/db/db_pool.hpp @@ -0,0 +1,104 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include + +namespace acl { + +class db_handle; +class locker; + +class db_pool +{ +public: + /** + * 数据库构造函数 + * @param dblimit {int} 数据库连接池的最大连接数限制 + */ + db_pool(int dblimit = 64); + virtual ~db_pool(); + + /** + * 从数据库中连接池获得一个数据库连接,该函数返回的数据库 + * 连接对象用完后必须调用 db_pool->put(db_handle*) 将连接 + * 归还至数据库连接池,由该函数获得的连接句柄不能 delete, + * 否则会造成连接池的内部计数器出错 + * @return {db_handle*} 返回空,则表示出错 + */ + db_handle* peek(); + + /** + * 将数据库连接放回至连接池中,当从数据库连接池中获得连接 + * 句柄用完后应该通过该函数放回,不能直接 delete,因为那样 + * 会导致连接池的内部记数发生错误 + * @param conn {db_handle*} 数据库连接句柄,该连接句柄可以 + * 是由 peek 创建的,也可以单独动态创建的 + * @param keep {bool} 归还给连接池的数据库连接句柄是否继续 + * 保持连接,如果否,则内部会自动删除该连接句柄 + */ + void put(db_handle* conn, bool keep = true); + + /** + * 将数据库连接池中的过期连接释放掉,以减少对后端数据库的连接数 + * @param ttl {time_t} 当数据库连接的空闲时间大于等于此值时 + * 该连接将被释放;当 idle 为 0 时则需要释放所有的数据库连接; + * 当为 -1 时则不进行释放连接操作 + * @param exclusive {bool} 内部是否需要加互斥锁 + * @return {int} 被释放的数据库连接的个数(>= 0) + */ + int check_idle(time_t ttl, bool exclusive = true); + + /** + * 设置连接池中空闲连接的生存周期,当通过本函数设置了数据库空闲连接 + * 的生存周期后(idle >= 0),则当用户调用 db_pool::put 时会自动检查 + * 过期连接并关闭,否则内部空闲连接一直保持 + * @param idle {int} 连接池中空闲连接的连接存活时间,当该值 + * 为 -1 时,表示不处理空闲连接,为 0 时表示内部不保留任何长连接 + * @return {db_pool&} + */ + db_pool& set_idle(int idle); + + /** + * 设置自动检查空闲连接的时间间隔,缺省值为 30 秒 + * @param n {int} 时间间隔 + * @return {db_pool&} + */ + db_pool& set_check_inter(int n); + + /** + * 获得当前数据库连接池的最大连接数限制 + * @return {int} + */ + int get_dblimit() const + { + return dblimit_; + } + + /** + * 获得当前数据库连接池当前的连接数 + * @return {int} + */ + int get_dbcount() const + { + return dbcount_; + } +protected: + /** + * 纯虚函数:创建 DB 的方法 + * @return {db_handle*} + */ + virtual db_handle* create() = 0; +private: + std::list pool_; + int dblimit_; // 连接池的最大连接数限制 + int dbcount_; // 当前已经打开的连接数 + locker* locker_; + char id_[128]; // 本类实例的唯一 ID 标识 + time_t ttl_; // 连接池中空闲连接被释放的超时值 + time_t last_check_; // 上次检查空闲连接的时间截 + int check_inter_; // 检查空闲连接的时间间隔 + + // 设置本实例的唯一 ID 标识 + void set_id(); +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/db/db_service.hpp b/lib_acl_cpp/include/acl_cpp/db/db_service.hpp new file mode 100644 index 000000000..e88465eba --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/db/db_service.hpp @@ -0,0 +1,117 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include +#include "acl_cpp/ipc/ipc_service.hpp" +#include "acl_cpp/stdlib/string.hpp" + +namespace acl { + +typedef enum +{ + DB_OK, + DB_ERR_OPEN, + DB_ERR_EXEC_SQL, +} db_status; + +////////////////////////////////////////////////////////////////////////// + +class db_rows; + +class ACL_CPP_API db_query +{ +public: + db_query(void) {} + virtual ~db_query(void) {} + + virtual void on_error(db_status status) = 0; + virtual void on_ok(const db_rows* rows, int affected) = 0; + + /** + * 当任务处理完毕或出错时,内部处理过程会自动调用 destroy 接口, + * 子类可以在该接口内进行一些释放过程,尤其当该对象是动态创建时, + * 子类应该在该函数内 delete this 以删除自己,因为该函数最终肯定 + * 会被调用,所以子类不应在其它地方进行析构操作 + */ + virtual void destroy(void) {} +protected: +private: +}; + +////////////////////////////////////////////////////////////////////////// + +class db_handle; +class aio_socket_stream; + +/** + * 数据库服务类,该类是一个异步数据库操作管理类,该类对象所在的线程必须是 + * 一个非阻塞的线程过程 + */ +class ACL_CPP_API db_service : public ipc_service +{ +public: + /** + * 当为 sqlite 数据库时的构造函数 + * @param dblimit {size_t} 数据库连接池的个数限制 + * @param nthread {int} 子线程池的最大线程数 + * @param win32_gui {bool} 是否是窗口类的消息,如果是,则内部的 + * 通讯模式自动设置为基于 WIN32 的消息,否则依然采用通用的套接 + * 口通讯方式 + */ + db_service(size_t dblimit = 100, int nthread = 2, bool win32_gui = false); + virtual ~db_service(void); + + /** + * 异步执行 SQL 查询语句 + * @param sql {const char*} 要执行的标准 SQL 语句 + * @param query {db_query*} 用来接收执行结果的类对象 + */ + void sql_select(const char* sql, db_query* query); + + /** + * 异步执行 SQL 更新语句 + * @param sql {const char*} 要执行的标准 SQL 语句 + * @param query {db_query*} 用来接收执行结果的类对象 + */ + void sql_update(const char* sql, db_query* query); + + /** + * 向数据库连接池中添加连接对象 + * @param db {db_handle*} 数据库连接对象 + */ + void push_back(db_handle* db); +protected: + /** + * 需要子类实现此函数用来创建数据库对象 + * @return {db_handle*} + */ + virtual db_handle* db_create() = 0; + + /** + * 基类虚函数,当有新连接到达时基类回调此函数 + * @param client {aio_socket_stream*} 接收到的新的客户端连接 + */ + virtual void on_accept(aio_socket_stream* client); + +#ifdef WIN32 + /** + * 基类虚函数,当收到来自于子线程的 win32 消息时的回调函数 + * @param hWnd {HWND} 窗口句柄 + * @param msg {UINT} 用户自定义消息号 + * @param wParam {WPARAM} 参数 + * @param lParam {LPARAM} 参数 + */ + virtual void win32_proc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); +#endif + +private: + // 数据库引擎池 + std::list dbpool_; + + // 数据库连接池的个数限制 + size_t dblimit_; + + // 当前数据库连接池的个数 + size_t dbsize_; +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/db/db_service_mysql.hpp b/lib_acl_cpp/include/acl_cpp/db/db_service_mysql.hpp new file mode 100644 index 000000000..b37883236 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/db/db_service_mysql.hpp @@ -0,0 +1,56 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include "acl_cpp/stdlib/string.hpp" +#include "acl_cpp/db/db_service.hpp" + +namespace acl { + +class ACL_CPP_API db_service_mysql : public db_service +{ + /** + * 当为 mysql 数据库时的构造函数 + * @param dbaddr {const char*} mysql 服务器地址 + * @param dbname {const char*} 数据库名 + * @param dbuser {const char*} 数据库用户名 + * @param dbpass {const char*} 数据库用户密码 + * @param dbflags {unsigned long} 数据库连接标志位 + * @param auto_commit {bool} 数据修改时是否自动提交 + * @param conn_timeout {int} 数据库连接超时时间 + * @param rw_timeout {int} 数据库操作时IO读写超时时间 + * @param dblimit {size_t} 数据库连接池的个数限制 + * @param nthread {int} 子线程池的最大线程数 + * @param win32_gui {bool} 是否是窗口类的消息,如果是,则内部的 + * 通讯模式自动设置为基于 WIN32 的消息,否则依然采用通用的套接 + * 口通讯方式 + */ + db_service_mysql(const char* dbaddr, const char* dbname, + const char* dbuser, const char* dbpass, + unsigned long dbflags = 0, bool auto_commit = true, + int conn_timeout = 60, int rw_timeout = 60, + size_t dblimit = 100, int nthread = 2, bool win32_gui = false); + + ~db_service_mysql(void); + +private: + // 数据库服务器地址 + string dbaddr_; + // 数据库名 + string dbname_; + // 数据库用户名 + string dbuser_; + // 数据库用户密码 + string dbpass_; + // 数据库连接标志位 + unsigned long dbflags_; + // 修改数据时是否自动提交数据 + bool auto_commit_; + // 连接数据库超时时间 + int conn_timeout_; + // 数据库操作时的读写超时时间 + int rw_timeout_; + + // 基类纯虚函数 + virtual db_handle* db_create(void); +}; + +} diff --git a/lib_acl_cpp/include/acl_cpp/db/db_service_sqlite.hpp b/lib_acl_cpp/include/acl_cpp/db/db_service_sqlite.hpp new file mode 100644 index 000000000..b367c29a5 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/db/db_service_sqlite.hpp @@ -0,0 +1,35 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include "acl_cpp/stdlib/string.hpp" +#include "acl_cpp/db/db_service.hpp" + +namespace acl { + +class ACL_CPP_API db_service_sqlite : public db_service +{ +public: + /** + * 当为 sqlite 数据库时的构造函数 + * @param dbname {const char*} 数据库名 + * @param dbfile {const char*} 数据库文件名(对于一些内嵌数据库有用) + * @param dblimit {size_t} 数据库连接池的个数限制 + * @param nthread {int} 子线程池的最大线程数 + * @param win32_gui {bool} 是否是窗口类的消息,如果是,则内部的 + * 通讯模式自动设置为基于 WIN32 的消息,否则依然采用通用的套接 + * 口通讯方式 + */ + db_service_sqlite(const char* dbname, const char* dbfile, + size_t dblimit = 100, int nthread = 2, bool win32_gui = false); + ~db_service_sqlite(); + +private: + // 数据库名称 + string dbname_; + // sqlite 数据库文件名 + string dbfile_; + + // 基类纯虚函数 + virtual db_handle* db_create(void); +}; + +} diff --git a/lib_acl_cpp/include/acl_cpp/db/db_sqlite.hpp b/lib_acl_cpp/include/acl_cpp/db/db_sqlite.hpp new file mode 100644 index 000000000..300304003 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/db/db_sqlite.hpp @@ -0,0 +1,151 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include "acl_cpp/stdlib/string.hpp" +#include "acl_cpp/db/db_handle.hpp" + +typedef struct sqlite3 sqlite3; + +namespace acl { + +class charset_conv; + +class ACL_CPP_API db_sqlite : public db_handle +{ +public: + db_sqlite(const char* dbfile); + ~db_sqlite(void); + + /** + * 返回当前的 sqlite 的版本信息 + */ + const char* version(void) const; + + /** + * 当数据库打开后通过此函数对数据库的操作引擎进行配置, + * 进行配置的内容需要严格遵循 sqlite 本身的配置选项要求 + * @param pragma {const char*} 配置选项内容,格式为: + * PRAGMA xxx=xxx + * 如:PRAGMA synchronous = NORMAL + * @return {bool} 配置数据库是否成功 + */ + bool set_conf(const char* pragma); + + /** + * 当数据库打开调用此函数获得数据引擎的配置选项 + * @param pragma {const char*} 配置选项内容,格式为: + * PRAGMA xxx + * 如:PRAGMA synchronous + * @param out {string&} 如果返回值非空则存储结果 + * @return {const char*} 为空则说明该配置不存在或数据库未打开 + */ + const char* get_conf(const char* pragma, string& out); + + /** + * 在数据库打开的情况下输入数据库引擎的配置选项 + * @param pragma {const char*} 指定的配置选项,如果该参数为空, + * 则输出所有的配置选项,格式为:PRAGMA xxx,如:PRAGMA synchronous + */ + void show_conf(const char* pragma = NULL); + + /** + * 自数据库打开后所有的影响的记录行数 + * @return {int} 影响的行数,-1 表示出错 + */ + int affect_total_count() const; + + /** + * 直接获得 sqlite 的句柄,如果返回 NULL 则表示 sqlite 还没有打开 + * 或出错时内部自动关闭了 sqlite + * @return {sqlite3*} + */ + sqlite3* get_conn() const + { + return db_; + } + + /************************************************************************/ + /* 以下为基类 db_handle 的虚接口 */ + /************************************************************************/ + + /** + * 返回数据库的类型描述 + * @return {const char*} + */ + virtual const char* dbtype() const; + + /** + * 获得上次数据库操作的出错错误号 + * @return {int} + */ + virtual int get_errno() const; + + /** + * 获得上次数据库操作的出错错描述 + * @return {const char*} + */ + virtual const char* get_error() const; + + /** + * 基类 db_handle 的纯虚接口 + * @param local_charset {const char*} 本地字符集 + * @return {bool} 打开是否成功 + */ + virtual bool open(const char* local_charset = "GBK"); + + /** + * 基类 db_handle 的纯虚接口,数据库是否已经打开了 + * @return {bool} 返回 true 表明数据库已经打开了 + */ + virtual bool is_opened() const; + + /** + * 基类 db_handle 的纯虚接口 + * @return {bool} 关闭是否成功 + */ + virtual bool close(void); + + /** + * 基类 db_handle 的纯虚接口,子类必须实现此接口用于判断数据表是否存在 + * @return {bool} 是否存在 + */ + virtual bool tbl_exists(const char* tbl_name); + + /** + * 基类 db_handle 的纯虚接口 + * @param sql {const char*} 标准的 SQL 语句,非空,并且一定得要注册该 + * SQL 语句必须经过转义处理,以防止 SQL 注入攻击 + * @return {bool} 执行是否成功 + */ + virtual bool sql_select(const char* sql); + + /** + * 基类 db_handle 的纯虚接口 + * @param sql {const char*} 标准的 SQL 语句,非空,并且一定得要注册该 + * SQL 语句必须经过转义处理,以防止 SQL 注入攻击 + * @return {bool} 执行是否成功 + */ + virtual bool sql_update(const char* sql); + + /** + * 基类 db_handle 的纯虚接口:上次 sql 操作影响的记录行数 + * @return {int} 影响的行数,-1 表示出错 + */ + virtual int affect_count() const; +private: + // sqlite 引擎 + sqlite3* db_; + + // 数据存储文件 + string dbfile_; + + // 字符集转码器 + charset_conv* conv_; + + // 本地字符集 + string local_charset_; + + // 真正执行SQL查询的函数 + bool exec_sql(const char* sql); +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/db/mysql_pool.hpp b/lib_acl_cpp/include/acl_cpp/db/mysql_pool.hpp new file mode 100644 index 000000000..54f6a46af --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/db/mysql_pool.hpp @@ -0,0 +1,45 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include "acl_cpp/db/db_pool.hpp" + +namespace acl { + +class db_handle; + +class mysql_pool : public acl::db_pool +{ +public: + /** + * 采用 mysql 数据库时的构造函数 + * @param dbaddr {const char*} mysql 服务器地址,格式:IP:PORT, + * 在 UNIX 平台下可以为 UNIX 域套接口 + * @param dbname {const char*} 数据库名 + * @param dbuser {const char*} 数据库用户 + * @param dbpass {const char*} 数据库用户密码 + * @param dblimit {int} 数据库连接池的最大连接数限制 + * @param dbflags {unsigned long} mysql 标记位 + * @param auto_commit {bool} 是否自动提交 + * @param conn_timeout {int} 连接数据库超时时间(秒) + * @param rw_timeout {int} 与数据库通信时的IO时间(秒) + */ + mysql_pool(const char* dbaddr, const char* dbname, + const char* dbuser, const char* dbpass, + int dblimit = 64, unsigned long dbflags = 0, + bool auto_commit = true, int conn_timeout = 60, + int rw_timeout = 60); + ~mysql_pool(); +protected: + // 基类虚函数:创建数据库连接句柄 + virtual db_handle* create(); +private: + char* dbaddr_; // 数据库监听地址 + char* dbname_; // 数据库名 + char* dbuser_; // 数据库账号 + char* dbpass_; // 数据库账号密码 + unsigned long dbflags_; + int conn_timeout_; + int rw_timeout_; + bool auto_commit_; +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/db/sqlite_pool.hpp b/lib_acl_cpp/include/acl_cpp/db/sqlite_pool.hpp new file mode 100644 index 000000000..06860e0d1 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/db/sqlite_pool.hpp @@ -0,0 +1,27 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include "acl_cpp/db/db_pool.hpp" + +namespace acl { + +class db_handle; + +class sqlite_pool : public acl::db_pool +{ +public: + /** + * 构造函数 + * @param dbfile {const char*} sqlite 数据库的数据文件 + * @param dblimit {int} 数据库连接池最大连接数限制 + */ + sqlite_pool(const char* dbfile, int dblimit = 64); + ~sqlite_pool(); +protected: + // 基类虚函数:创建数据库连接句柄 + virtual db_handle* create(); +private: + // sqlite 数据文件名 + char* dbfile_; +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/hsocket/hsclient.hpp b/lib_acl_cpp/include/acl_cpp/hsocket/hsclient.hpp new file mode 100644 index 000000000..ab1606b65 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/hsocket/hsclient.hpp @@ -0,0 +1,199 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include +#include +#include "acl_cpp/stdlib/string.hpp" +#include "acl_cpp/stream/socket_stream.hpp" +#include "acl_cpp/hsocket/hsproto.hpp" + +struct ACL_ARGV; + +namespace acl { + +class hsrow; +class hstable; + +class ACL_CPP_API hsclient +{ +public: + /** + * 构造函数 + * @param addr {const char*} handlersocket 插件在 Mysql 上的监听地址, + * @param cache_enable {bool} 内部是否启用行缓存功能 + * @param retry_enable {bool} 当因为网络原因出错时是否需要重试 + * 格式为:ip:port + */ + hsclient(const char* addr, bool cache_enable = true, bool retry_enable = true); + ~hsclient(); + + /** + * 查询与所给字段值匹配的结果 + * @param values {const char*[]} 匹配字段值数组,字段值的加入顺序应与 open + * 函数中 flds 中各个字段的顺序相同 + * @param num {int} values 数组长度,该值不应超过构造函数中 flds 所含有的 + * 字段个数 + * @param cond {const char*} 匹配条件,可以为: + * = 等于; >= 大于等于; > 大于; < 小于; <= 小于等于 + * @param nlimit {int} 结果集个数限制,0 表示不限制个数 + * @param noffset {int} 结果集开始位置(0表示从第一个结果开始) + * @return {const std::verctor&} 返回结果集 + */ + const std::vector& get(const char* values[], int num, + const char* cond = "=", int nlimit = 0, int noffset = 0); + + /** + * 查询与所给字段值匹配的结果 + * @param first_value {const char*} 为对应于构造函数中 flds 字段集中 + * 的第一个字段的字段值 + * @param ... {const char*} 参数列表,最后一个参数为 NULL 表示结束 + * @return {const std::verctor&} 返回结果集 + */ + const std::vector& get(const char* first_value, ...); + + /** + * 更新数据库表中匹配字段的数值 + * @param values {const char*[]} 匹配字段值数组,字段值的加入顺序应与 open + * 函数中 flds 中各个字段的顺序相同 + * @param num {int} values 数组长度,该值不应超过构造函数中 flds 所含有的 + * 字段个数 + * @param to_values {cosnt *[]} 匹配字段新值,字段值的顺序应与 open 方法中 + * 的字段顺序相同 + * @param to_num {int} to_values 数组长度 + * @param cond {const char*} 匹配条件,可以为: + * = 等于; >= 大于等于; > 大于; < 小于; <= 小于等于 + * @param nlimit {int} 结果集个数限制,0 表示不限制个数 + * @param noffset {int} 结果集开始位置(0表示从第一个结果开始) + * @return {bool} 更新是否成功 + */ + bool mod(const char* values[], int num, + const char* to_values[], int to_num, + const char* cond = "=", int nlimit = 0, int noffset = 0); + + /** + * 删除数据库表中匹配字段的记录 + * @param values {const char*[]} 匹配字段值数组,字段值的加入顺序应与 open + * 函数中 flds 中各个字段的顺序相同 + * @param num {int} values 数组长度,该值不应超过构造函数中 flds 所含有的 + * 字段个数 + * @param cond {const char*} 匹配条件,可以为: + * = 等于; >= 大于等于; > 大于; < 小于; <= 小于等于 + * @param nlimit {int} 删除数据的个数, 0 表示不限制 + * @param noffset {int} 结果集开始位置(0表示从第一个结果开始) + * @return {bool} 更新是否成功 + */ + bool del(const char* values[], int num, const char* cond = "=", + int nlimit = 0, int noffset = 0); + + /** + * 删除数据库表中匹配字段的记录 + * @param first_value {const char*} 为对应于构造函数中 flds 字段集中 + * 的第一个字段的字段值 + * @param ... {const char*} 参数列表,最后一个参数为 NULL 表示结束 + * @return {bool} 添加记录是否成功 + */ + bool fmt_del(const char* first_value, ...); + + /** + * 向数据库添加新记录 + * @param values {const char*[]} 匹配字段值数组,字段值的加入顺序应与构造 + * 函数中 flds 中各个字段的顺序相同 + * @param num {int} values 数组长度,该值不应超过构造函数中 flds 所含有的 + * 字段个数 + * @return {bool} 添加记录是否成功 + */ + bool add(const char* values[], int num); + + /** + * 向数据库中添加新记录 + * @param first_value {const char*} 为对应于构造函数中 flds 字段集中 + * 的第一个字段的字段值 + * @param ... {const char*} 参数列表,最后一个参数为 NULL 表示结束 + * @return {bool} 添加记录是否成功 + */ + bool fmt_add(const char* first_value, ...); + + /** + * 设置是否进行调试 + * @param on {bool} true 则表示进行调试,会将一些中间信息记入日志中 + */ + void debug_enable(bool on); + + /** + * 打开数据库表 + * @param dbn {const char*} 数据库名称 + * @param tbl {const char*} 数据库表名 + * @param idx {const char*} 索引字段名 + * @param flds {const char*} 要打开的数据字段名集合,格式为 + * 由分隔符 ",; \t" 分隔的字段名称,如:user_id,user_name,user_mail + * @param auto_open {bool} 当表未打开是否自动打开 + * @return {bool} true 表示正常打开,否则表示打开表失败 + */ + bool open_tbl(const char* dbn, const char* tbl, + const char* idx, const char* flds, bool auto_open = true); + + /** + * 获得连接地址 + * @return {const char*} 永不为空 + */ + const char* get_addr() const; + + /** + * 获得出错错误号 + * @return {int} + */ + int get_error() const; + + /** + * 获得出错错误信息描述 + * @param errnum {int} 由 get_error 获得的错误号 + * @return {const char*} + */ + const char* get_serror(int errnum) const; + + /** + * 获得上次出错时的错误描述信息 + * @return {const char*} + */ + const char* get_last_serror() const; + + /** + * 获得当前 hsclient 对象所用的 id 号 + * @return {int} + */ + int get_id() const; +private: + bool debugOn_; + char* addr_; + hsproto proto_; + bool retry_enable_; + int id_max_; + hstable* tbl_curr_; + string buf_; + + // 服务器连接流 + socket_stream stream_; + std::map tables_; + + char cond_def_[2]; + int error_; + const char* serror_; + + // 打开数据库连接 + bool open_tbl(const char* dbn, const char* tbl, + const char* idx, const char* flds, const char* key); + + // 当读写数据库连接流出错时需要调用此函数来关闭连接流及释放 + // 表对象 + void close_stream(); + + // 清理内部打开的数据库表的对象 + void clear_tables(); + + // 向数据库发送查询命令并取得结果数据 + bool query(const char* oper, const char* values[], int num, + const char* limit_offset, char mop, + const char* to_values[], int to_num); + bool chat(); +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/hsocket/hserror.hpp b/lib_acl_cpp/include/acl_cpp/hsocket/hserror.hpp new file mode 100644 index 000000000..fbe042fb6 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/hsocket/hserror.hpp @@ -0,0 +1,23 @@ +#pragma once + +#define HS_ERR_INVALID_REPLY -7 // 服务器返回数据错误 +#define HS_ERR_EMPTY -6 // 服务器返回数据为空 +#define HS_ERR_PARAMS -5 // 输入参数错误 +#define HS_ERR_NOT_OPEN -4 // 表未打开 +#define HS_ERR_READ -3 // 读数据失败 +#define HS_ERR_WRITE -2 // 写数据失败 +#define HS_ERR_CONN -1 // 连接失败 +#define HS_ERR_OK 0 // 正确 + +namespace acl { + +class hserror +{ +public: + hserror(); + ~hserror(); + + static const char* get_serror(int errnum); +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/hsocket/hspool.hpp b/lib_acl_cpp/include/acl_cpp/hsocket/hspool.hpp new file mode 100644 index 000000000..f0ace3c73 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/hsocket/hspool.hpp @@ -0,0 +1,55 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include + +struct ACL_HTABLE; + +namespace acl { + +class hsclient; +class locker; + +class ACL_CPP_API hspool +{ +public: + /** + * 构造函数 + * @param addr_rw {const char*} handlersocket 插件在 Mysql 上的监听地址, + * 格式为:ip:port,注:该地址是 handlersocket 的读写地址 + * @param addr_rd {const char*} handlersocket 插件在 Mysql 上的监听地址, + * 格式为:ip:port,注:该地址是 handlersocket 的只读地址 + * @param cache_enable {bool} 是否内部自动启用行对象缓存机制 + * @param retry_enable {bool} 当因为网络原因而出错时是否需要进行重试 + */ + hspool(const char* addr_rw, const char* addr_rd = NULL, + bool cache_enable = true, bool retry_enable = true); + + ~hspool(); + + /** + * 从连接池中获得连接对象 + * @param dbn {const char*} 数据库名称 + * @param tbl {const char*} 数据库表名 + * @param idx {const char*} 索引字段名 + * @param flds {const char*} 要打开的数据字段名集合,格式为 + * 由分隔符 ",; \t" 分隔的字段名称,如:user_id,user_name,user_mail + * @param readonly {bool} 是否仅以只读方式打开 + */ + hsclient* peek(const char* dbn, const char* tbl, + const char* idx, const char* flds, bool readonly = false); + + /** + * 归还连接对象 + * @param client {hsclient*} + */ + void put(hsclient* client); +private: + char* addr_rw_; + char* addr_rd_; + bool cache_enable_; + bool retry_enable_; + std::list pool_; + locker* locker_; +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/hsocket/hsproto.hpp b/lib_acl_cpp/include/acl_cpp/hsocket/hsproto.hpp new file mode 100644 index 000000000..b417ab68d --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/hsocket/hsproto.hpp @@ -0,0 +1,196 @@ +#pragma once +#include + +namespace acl { + +class string; +class hsrow; + +class hsproto +{ +public: + hsproto(bool cache_enable); + ~hsproto(); + + /** + * 创建打开数据库索引的请求协议数据 + * @param out {string&} 存储请求协议结果 + * @param id {int} 对应打开索引的表ID号 + * @param dbn {const char*} 数据库名称 + * @param tbl {const char*} 数据库表名 + * @param idx {const char*} 索引字段名 + * @param flds {const char*} 要打开的数据字段名集合,格式为 + * 由分隔符 ",; \t" 分隔的字段名称,如:user_id,user_name,user_mail + * @return {bool} 是否成功 + */ + static bool build_open(string& out, int id, + const char* dbn, const char* tbl, + const char* idx, const char* flds); + + /** + * 创建查询数据库记录的请求协议数据 + * @param out {string&} 存储请求协议结果 + * @param id {int} 对应打开索引的表ID号 + * @param values {const char*[]} 匹配字段值数组,字段值的加入顺序应与打开索引 + * 中各个字段的顺序相同 + * @param num {int} values 数组长度,该值不应超过在打开索引时的字段个数 + * @param cond {const char*} 匹配条件,可以为: + * = 等于; >= 大于等于; > 大于; < 小于; <= 小于等于 + * @param nlimit {int} 结果集个数限制,0 表示不限制个数 + * @param noffset {int} 结果集开始位置(0表示从第一个结果开始) + * @return {bool} 是否成功 + */ + static bool build_get(string& out, int id, + const char* values[], int num, + const char* cond = "=", int nlimit = 0, int noffset = 0); + + /** + * 创建查询数据库记录的请求协议数据 + * @param out {string&} 存储请求协议数据 + * @param id {int} 对应打开索引的表ID号 + * @param nfld {int} 在打开索引时字段个数 + * @param first_value {const char*} 第一个参数 + * @param ... {const char*} 参数列表,最后一个参数为 NULL 表示结束 + * @return {bool} 是否成功 + */ + static bool build_get(string& out, int id, + int nfld, const char* first_value, ...); + + /** + * 创建修改数据库记录的请求协议数据 + * @param out {string&} 存储请求协议数据 + * @param id {int} 对应打开索引的表ID号 + * @param values {const char*[]} 匹配字段值数组,字段值的加入顺序应与打开索引 + * 中各个字段的顺序相同 + * @param num {int} values 数组长度,该值不应超过在打开索引时的字段个数 + * @param to_values {cosnt *[]} 匹配字段新值,字段值的顺序应与 open 方法中 + * 的字段顺序相同 + * @param to_num {int} to_values 数组长度 + * @param cond {const char*} 匹配条件,可以为: + * @param nlimit {int} 结果集个数限制,0 表示不限制个数 + * @param noffset {int} 结果集开始位置(0表示从第一个结果开始) + * @return {bool} 是否成功 + */ + static bool build_mod(string& out, int id, + const char* values[], int num, + const char* to_values[], int to_num, + const char* cond = "=", int nlimit = 0, int noffset = 0); + + /** + * 创建删除数据库记录的请求协议数据 + * @param out {string&} 存储请求协议数据 + * @param id {int} 对应打开索引的表ID号 + * @param values {const char*[]} 匹配字段值数组,字段值的加入顺序应与打开索引 + * 中各个字段的顺序相同 + * @param num {int} values 数组长度,该值不应超过在打开索引时的字段个数 + * @param cond {const char*} 匹配条件,可以为: + * @param nlimit {int} 结果集个数限制,0 表示不限制个数 + * @param noffset {int} 结果集开始位置(0表示从第一个结果开始) + * @return {bool} 是否成功 + */ + static bool build_del(string& out, int id, const char* values[], + int num, const char* cond = "=", + int nlimit = 0, int noffset = 0); + + /** + * 创建删除数据库记录的请求协议数据 + * @param out {string&} 存储请求协议数据 + * @param id {int} 对应打开索引的表ID号 + * @param nfld {int} 在打开索引时字段个数 + * @param first_value {const char*} 第一个参数 + * @param ... {const char*} 参数列表,最后一个参数为 NULL 表示结束 + * @return {bool} 是否成功 + */ + static bool build_del(string& out, int id, + int nfld, const char* first_value, ...); + + /** + * 创建添加数据库记录的请求协议数据 + * @param out {string&} 存储请求协议数据 + * @param id {int} 对应打开索引的表ID号 + * @param values {const char*[]} 匹配字段值数组,字段值的加入顺序应与打开索引 + * 中各个字段的顺序相同 + * @param num {int} values 数组长度,该值不应超过在打开索引时的字段个数 + * @return {bool} 是否成功 + */ + static bool build_add(string& out, int id, + const char* values[], int num); + + /** + * 创建添加数据库记录的请求协议数据 + * @param out {string&} 存储请求协议数据 + * @param id {int} 对应打开索引的表ID号 + * @param nfld {int} 在打开索引时字段个数 + * @param first_value {const char*} 第一个参数 + * @param ... {const char*} 参数列表,最后一个参数为 NULL 表示结束 + * @return {bool} 是否成功 + */ + static bool build_add(string& out, int id, + int nfld, const char* first_value, ...); + + /** + * 通用的创建数据库处理的请求协议数据 + * @param out {string&} 存储请求协议数据 + * @param id {int} 对应打开索引的表ID号 + * @param oper {const char*} 操作方式,对应的操作符为: + * 添加: + + * 查询: =, >, >=, <, <= + * 修改: =, >, >=, <, <= + * 删除: =, >, >=, <, <= + * @param values {const char*[]} 匹配字段值数组,字段值的加入顺序应与打开索引 + * 中各个字段的顺序相同 + * @param num {int} values 数组长度,该值不应超过在打开索引时的字段个数 + * @param limit_offset {const char*} 要求的查询范围 + * @param mop {char} 仅针对删除,修改操作有效,其对应的操作符分别为: + * D: 删除, U: 修改 + * @param to_values {const char*[]} 目标值指针数组 + * @param to_num {int} to_values 数组的长度 + */ + static void build_request(string& out, int id, const char* oper, + const char* values[], int num, + const char* limit_offset, char mop, + const char* to_values[], int to_num); + + /** + * 分析数据库的返回数据 + * @param nfld {int} 打开的表的元素个数 + * @param in {string&} 从数据库读到的数据行, 尾部应该不包含 "\r\n" + * @param errnum_out {int&} 存储处理过程的出错号,参见: hserror.hpp + * @param serror_out {const char*&} 存储处理过程的出错描述信息 + * @return {bool} 分析是否成功 + */ + bool parse_respond(int nfld, string& in, + int& errnum_out, const char*& serror_out); + + /** + * 当执行查询语句时,可以通过此函数获得查询的结果集 + * @return {const std::vector&} + */ + const std::vector& get(); + + /** + * 当用户用完查询结果集后进行第二次查询时调用此函数清理上次查询结果 + */ + void reset(); +private: + bool debugOn_; + bool cache_enable_; + int nfld_; + int ntoken_; + char* buf_ptr_; + + // 查询结果集 + std::vector rows_; + + // 行记录对象缓存,当行记录对象用完后,为了保证内存 + // 复用,将不再使用的行记录对象进行缓存,以备后用 + std::vector rows_cache_; + + // 清除行缓存对象集合 + void clear_cache(); + + // 获得下一个查询结果 + hsrow* get_next_row(); +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/hsocket/hsrow.hpp b/lib_acl_cpp/include/acl_cpp/hsocket/hsrow.hpp new file mode 100644 index 000000000..b8c984a97 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/hsocket/hsrow.hpp @@ -0,0 +1,44 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include + +namespace acl { + +class string; + +class ACL_CPP_API hsrow +{ +public: + /** + * 构造函数 + * @param ncolum {int} 数据库查询时每条记录的列数 + */ + hsrow(int ncolum); + ~hsrow(); + + /** + * 重置数据查询时第条记录的列数 + * @param ncolum {int} 数据库查询时每条记录的列数 + */ + void reset(int ncolum); + + /** + * 向该查询记录中添加列数值 + * @param value {const char*} 列值 + * @param dlen {size_t} 列值长度 + */ + void push_back(const char* value, size_t dlen); + + /** + * 取得查询记录 + * @return {const std::vector&} + */ + const std::vector& get_row() const; +private: + std::vector row_; + int ncolum_; + int icolum_; + string* colums_; +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/hsocket/hstable.hpp b/lib_acl_cpp/include/acl_cpp/hsocket/hstable.hpp new file mode 100644 index 000000000..2751f5b69 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/hsocket/hstable.hpp @@ -0,0 +1,24 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" + +namespace acl { + +class ACL_CPP_API hstable +{ +public: + hstable(int id, const char* dbn, const char* tbl, + const char* idx, const char* flds); + ~hstable(); + +private: + friend class hsclient; + int id_; + char* dbn_; + char* tbl_; + char* idx_; + char* flds_; + int nfld_; + char** values_; +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/http/HttpCookie.hpp b/lib_acl_cpp/include/acl_cpp/http/HttpCookie.hpp new file mode 100644 index 000000000..28eee697c --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/http/HttpCookie.hpp @@ -0,0 +1,150 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include +#include "acl_cpp/http/http_type.hpp" + +namespace acl { + +/** + * http 协议头中 cookie 对象类 + */ +class ACL_CPP_API HttpCookie +{ +public: + /** + * 构造函数,该类对象必须动态创建,且必须调用 destroy 来释放类对象 + * @param name {const char*} cookie 名,为非空字符串且字符串长度 > 0 + * @param value {const char*} cookie 值,指针非空,字符串长度可以为 0 + * 注:如果输入的两个参数不符合条件,内部将会产生断言 + */ + HttpCookie(const char* name, const char* value); + + /** + * 当使用该构造函数时,可以使用 setCookie 来添加 cookie 项 + */ + HttpCookie(void); + + /** + * 对于 Set-Cookie: xxx=xxx; domain=xxx; expires=xxx; path=xxx; max-age=xxx; ... + * 类的数据进行分析 + * @param value {const char*} 类似于 xxx=xxx; domain=xxx; ... 内容 + * @return {bool} 传入的数据是否合法 + */ + bool setCookie(const char* value); + + /** + * 动态创建的类对象通过此函数释放 + */ + void destroy(); + + /** + * 设置 cookie 的作用域 + * @param domain {const char*} cookie 作用域 + * @return {HttpCookie&} 返回本对象的引用,便于用户连续操作 + */ + HttpCookie& setDomain(const char* domain); + + /** + * 设置 cookie 的 path 字段 + * @param path {const char*} path 字段值 + * @return {HttpCookie&} 返回本对象的引用,便于用户连续操作 + */ + HttpCookie& setPath(const char* path); + + /** + * 设置 cookie 的过期时间段,即用当前时间加输入的时间即为 cookie + * 的过期时间 + * @param timeout {time_t} 过期时间值(单位为秒),当前时间加该时间 + * 即 cookie 的过期时间 + * @return {HttpCookie&} 返回本对象的引用,便于用户连续操作 + */ + HttpCookie& setExpires(time_t timeout); + + /** + * 设置 cookie 的过期时间截字符串 + * @param expires {const char*} 过期时间截 + * @return {HttpCookie&} 返回本对象的引用,便于用户连续操作 + */ + HttpCookie& setExpires(const char* expires); + + /** + * 设置 cookie 的生存周期 + * @param max_age {int} 生存秒数 + * @return {HttpCookie&} 返回本对象的引用,便于用户连续操作 + */ + HttpCookie& setMaxAge(int max_age); + + /** + * 添加与该 cookie 对象其它属性值 + * @param name {const char*} 属性名 + * @param value {const char*} 属性值 + * @return {HttpCookie&} 返回本对象的引用,便于用户连续操作 + */ + HttpCookie& add(const char* name, const char* value); + + /** + * 获得 cookie 名称,取决于构建函数输入值 + * @return {const char*} 为长度大于 0 的字符串,永远非空指针 + * 注:用户必须在调用 HttpCookie(const char*, const char*) 构造 + * 或调用 setCookie(const char*) 成功后才可以调用该函数, + * 否则返回的数据是 "\0" + */ + const char* getName(void) const; + + /** + * 获得 cookie 值,取决于构造函数输入值 + * @return {const char*} 非空指针,有可能是空字符串("\0") + */ + const char* getValue(void) const; + + /** + * 获得字符串格式的过期时间 + * @return {const char*} 非空指针,返回值为 "\0" 表示不存在 + */ + const char* getExpires(void) const; + + /** + * 获得 cookie 作用域 + * @return {const char*} 非空指针,返回值为 "\0" 表示不存在 + */ + const char* getDomain(void) const; + + /** + * 获得 cookie 的存储路径 + * @return {const char*} 非空指针,返回值为 "\0" 表示不存在 + */ + const char* getPath(void) const; + + /** + * 获得 cookie 的生存周期 + * @return {int} 返回 -1 时表示没有该 Max-Age 字段 + */ + int getMaxAge(void) const; + + /** + * 获得对应参数名的参数值 + * @param name {const char*} 参数名 + * @param case_insensitive {bool} 是否区分大小写,true 表示 + * 不区分大小写 + * @return {const char*} 非空指针,返回值为 "\0" 表示不存在 + */ + const char* getParam(const char* name, + bool case_insensitive = true) const; + + /** + * 获得该 cookie 对象的除 cookie 名及 cookie 值之外的 + * 所有属性及属性值 + * @return {const std::list&} + */ + const std::list& getParams(void) const; +private: + char dummy_[1]; + char* name_; + char* value_; + std::list params_; + + ~HttpCookie(void); + bool splitNameValue(char* data, HTTP_PARAM* param); +}; + +} // namespace acl end diff --git a/lib_acl_cpp/include/acl_cpp/http/HttpServlet.hpp b/lib_acl_cpp/include/acl_cpp/http/HttpServlet.hpp new file mode 100644 index 000000000..fbc088820 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/http/HttpServlet.hpp @@ -0,0 +1,139 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/http/http_header.hpp" + +namespace acl { + +class socket_stream; +class session; +class HttpServletRequest; +class HttpServletResponse; + +/** + * 处理 HTTP 客户端请求的基类,子类需要继承该类 + */ +class ACL_CPP_API HttpServlet +{ +public: + HttpServlet(void); + virtual ~HttpServlet(void) = 0; + + /** + * 设置本地字符集,如果设置了本地字符集,则在接收 HTTP 请求 + * 数据时,会自动将请求的字符集转为本地字符集 + * @param charset {const char*} 本地字符集,如果该指针为空, + * 则清除本地字符集 + */ + void setLocalCharset(const char* charset); + + /** + * 设置 HTTP 会话过程的 IO 读写超时时间 + * @param rw_timeout {int} 读写超时时间(秒) + */ + void setRwTimeout(int rw_timeout); + + /** + * HttpServlet 对象开始运行,接收 HTTP 请求,并回调以下 doXXX 虚函数 + * @param session {session&} 存储 session 数据的对象 + * @param stream {socket_stream*} 当在 acl_master 服务器框架控制下 + * 运行时,该参数必须非空;当在 apache 下以 CGI 方式运行时,该参数 + * 设为 NULL;另外,该函数内部不会关闭流连接,应用应自行处理流对象 + * 的关闭情况,这样可以方便与 acl_master 架构结合 + * @param body_parse {bool} 针对 POST 方法,该参数指定是否需要 + * 读取 HTTP 请求数据体并按 n/v 方式进行分析;当为 true 则内 + * 部会读取 HTTP 请求体数据,并进行分析,当用户调用 getParameter + * 时,不仅可以获得 URL 中的参数,同时可以获得 POST 数据体中 + * 的参数;当该参数为 false 时则不读取数据体 + * @param body_limit {int} 针对 POST 方法,当数据体为文本参数 + * 类型时,此参数限制数据体的长度;当数据体为数据流或 MIME + * 格式或 body_read 为 false,此参数无效 + * @return {bool} 返回处理结果 + */ + bool doRun(session& session, socket_stream* stream = NULL, + bool body_parse = true, int body_limit = 102400); + + /** + * HttpServlet 对象开始运行,接收 HTTP 请求,并回调以下 doXXX 虚函数, + * 调用本函数意味着采用 memcached 来存储 session 数据 + * @param memcached_addr {const char*} memcached 服务器地址,格式:IP:PORT + * @param stream {socket_stream*} 含义同上 + * @param body_parse {bool} 含义同上 + * @param body_limit {int} 含义同上 + * @return {bool} 返回处理结果 + */ + bool doRun(const char* memcached_addr = "127.0.0.1:11211", + socket_stream* stream = NULL, + bool body_parse = true, int body_limit = 102400); + + /** + * 当 HTTP 请求为 GET 方式时的虚函数 + */ + virtual bool doGet(HttpServletRequest&, HttpServletResponse&) + { + logger_error("child not implement doGet yet!"); + return false; + } + + /** + * 当 HTTP 请求为 POST 方式时的虚函数 + */ + virtual bool doPost(HttpServletRequest&, HttpServletResponse&) + { + logger_error("child not implement doPost yet!"); + return false; + } + + /** + * 当 HTTP 请求为 PUT 方式时的虚函数 + */ + virtual bool doPut(HttpServletRequest&, HttpServletResponse&) + { + logger_error("child not implement doPut yet!"); + return false; + } + + /** + * 当 HTTP 请求为 CONNECT 方式时的虚函数 + */ + virtual bool doConnect(HttpServletRequest&, HttpServletResponse&) + { + logger_error("child not implement doConnect yet!"); + return false; + } + + /** + * 当 HTTP 请求为 PURGE 方式时的虚函数,该方法在清除 SQUID 的缓存 + * 时会用到 + */ + virtual bool doPurge(HttpServletRequest&, HttpServletResponse&) + { + logger_error("child not implement doPurge yet!"); + return false; + } + + /** + * 当 HTTP 请求方法未知时的虚函数 + */ + virtual bool doUnknown(HttpServletRequest&, HttpServletResponse&) + { + logger_error("child not implement doUnknown yet!"); + return false; + } + + /** + * 当 HTTP 请求出错时的虚函数 + */ + virtual bool doError(HttpServletRequest&, HttpServletResponse&) + { + logger_error("child not implement doError yet!"); + return false; + } + +protected: +private: + char local_charset_[32]; + int rw_timeout_; +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/http/HttpServletRequest.hpp b/lib_acl_cpp/include/acl_cpp/http/HttpServletRequest.hpp new file mode 100644 index 000000000..287998021 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/http/HttpServletRequest.hpp @@ -0,0 +1,269 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include +#include "acl_cpp/http/http_header.hpp" +#include "acl_cpp/http/http_ctype.hpp" +#include "acl_cpp/http/http_type.hpp" + +namespace acl { + +class istream; +class ostream; +class socket_stream; +class http_client; +class http_mime; +class session; +class HttpSession; +class HttpCookie; +class HttpServletResponse; + +/** + * 与 HTTP 客户端请求相关的类,该类不应被继承,用户也不需要 + * 定义或创建该类对象 + */ +class ACL_CPP_API HttpServletRequest +{ +public: + /** + * 构造函数 + * @param res {HttpServletResponse&} + * @param store {session&} 存储会话数据的对象 + * @param stream {socket_stream&} 数据流,内部不会主动关闭流 + * @param local_charset {const char*} 本地字符集,该值非空时, + * 内部会自动将 HTTP 请求的数据转换为本地字符集,否则不转换 + * @param body_parse {bool} 针对 POST 方法,该参数指定是否需要 + * 读取 HTTP 请求数据体并按 n/v 方式进行分析;当为 true 则内 + * 部会读取 HTTP 请求体数据,并进行分析,当用户调用 getParameter + * 时,不仅可以获得 URL 中的参数,同时可以获得 POST 数据体中 + * 的参数;当该参数为 false 时则不读取数据体,把读数据体的任务 + * 交给子类处理 + * @param body_limit {int} 针对 POST 方法,当数据体为文本参数 + * 类型时,此参数限制数据体的长度;当数据体为数据流或 MIME + * 格式或 body_read 为 false,此参数无效 + */ + HttpServletRequest(HttpServletResponse& res, session& store, + socket_stream& stream, const char* local_charset = NULL, + bool body_parse = true, int body_limit = 102400); + ~HttpServletRequest(void); + + /** + * 获得 HTTP 客户端请求方法:GET, POST, PUT, CONNECT, PURGE + * @return {http_method_t} + */ + http_method_t getMethod(void) const; + + /** + * 获得 HTTP 客户端请求的所有 cookie 对象集合 + * @return {const std::vector&} + */ + const std::vector& getCookies(void) const; + + /** + * 获得 HTTP 客户端请求的某个 cookie 值 + * @param name {const char*} cookie 名称,必须非空 + * @return {const char*} cookie 值,当返回 NULL 时表示 + * cookie 值不存在 + */ + const char* getCookieValue(const char* name) const; + + /** + * 给 HTTP 请求对象添加 cookie 对象 + * @param name {const char*} cookie 名,非空字符串 + * @param value {const char*} cookie 值,非空字符串 + */ + void setCookie(const char* name, const char* value); + + /** + * 获得 HTTP 请求头中的某个字段值 + * @param name {const char*} HTTP 请求头中的字段名,非空 + * @return {const char*} HTTP 请求头中的字段值,返回 NULL + * 时表示不存在 + */ + const char* getHeader(const char* name) const; + + /** + * 获得 HTTP GET 请求方式 URL 中的参数部分,即 ? 后面的部分 + * @return {const char*} 没有进行URL 解码的请求参数部分, + * 返回 NULL 则表示 URL 中没有参数 + */ + const char* getQueryString(void) const; + + /** + * 获得 http://test.com.cn/cgi-bin/test?name=value 中的 + * /cgi-bin/test 路径部分 + * @return {const char*} 返回空表示不存在? + */ + const char* getPathInfo(void) const; + + /** + * 获得 http://test.com.cn/cgi-bin/test?name=value 中的 + * /cgi-bin/test?name=value 路径部分 + * @return {const char*} 返回空表示不存在? + */ + const char* getRequestUri(void) const; + + /** + * 获得与该 HTTP 会话相关的 HttpSession 对象引用 + * @param create {bool} 当 session 不存在时是否在缓存服务器自动创建; + * 当某客户端的 session 不存在且该参数为 false 时,则该函数返 + * 回的 session 对象会因没有被真正创建而无法进行读写操作 + * @param sid {const char*} 当 session 不存在,且 create 参数非空时, + * 如果 sid 非空,则使用此值设置用户的唯一会话,同时添加进客户端的 + * cookie 中 + * @return {HttpSession&} + * 注:优先级,浏览器 COOKIE > create = true > sid != NULL + */ + HttpSession& getSession(bool create = true, const char* sid = NULL); + + /** + * 获得与 HTTP 客户端连接关联的输入流对象引用 + * @return {istream&} + */ + istream& getInputStream(void) const; + + /** + * 获得 HTTP 请求数据的数据长度 + * @return {acl_int64} 返回 -1 表示可能为 GET 方法, + * 或 HTTP 请求头中没有 Content-Length 字段 + */ +#ifdef WIN32 + __int64 getContentLength(void) const; +#else + long long int getContentLength(void) const; +#endif + /** + * 获得 HTTP 请求头中 Content-Type: text/html; charset=gb2312 + * Content-Type 的字段值 + * @param part {bool} 如果为 true 则返回 text,否则返回完整的 + * 值,如:text/html; charset=gb2312 + * @return {const char*} 返回 NULL 表示 Content-Type 字段不存在 + */ + const char* getContentType(bool part = true) const; + + /** + * 获得 HTTP 请求头中的 Content-Type: text/html; charset=gb2312 + * 中的 charset 字段值 gb2312 + * @return {const char*} 返回 NULL 表示 Content-Type 字段 或 + * charset=xxx 不存在 + */ + const char* getCharacterEncoding(void) const; + + /** + * 返回本地的字段字符集 + * @ return {const char*} 返回 NULL 表示没有设置本地字符集 + */ + const char* getLocalCharset(void) const; + + /** + * 返回 HTTP 连接的本地 IP 地址 + * @return {const char*} 返回空,表示无法获得 + */ + const char* getLocalAddr(void) const; + + /** + * 返回 HTTP 连接的本地 PORT 号 + * @return {unsigned short} 返回 0 表示无法获得 + */ + unsigned short getLocalPort(void) const; + + /** + * 返回 HTTP 连接的远程客户端 IP 地址 + * @return {const char*} 返回空,表示无法获得 + */ + const char* getRemoteAddr(void) const; + + /** + * 返回 HTTP 连接的远程客户端 PORT 号 + * @return {unsigned short} 返回 0 表示无法获得 + */ + unsigned short getRemotePort(void) const; + + /** + * 获得 HTTP 请求中的参数值,该值已经被 URL 解码且 + * 转换成本地要求的字符集;针对 GET 方法,则是获得 + * URL 中 ? 后面的参数值;针对 POST 方法,则可以获得 + * URL 中 ? 后面的参数值或请求体中的参数值 + */ + const char* getParameter(const char* name) const; + + /** + * 当 HTTP 请求头中的 Content-Type 为 + * multipart/form-data; boundary=xxx 格式时,说明为文件上传 + * 数据类型,则可以通过此函数获得 http_mime 对象 + * @return {const http_mime*} 返回 NULL 则说明没有 MIME 对象, + * 返回的值用户不能手工释放,因为在 HttpServletRequest 的析 + * 构中会自动释放 + */ + http_mime* getHttpMime(void) const; + + /** + * 获得 HTTP 请求数据的类型 + * @return {http_request_t},一般对 POST 方法中的上传 + * 文件应用而言,需要调用该函数获得是否是上传数据类型, + * 当该函数返回 HTTP_REQUEST_OTHER 时,用户可以通过调用 + * getContentType 获得具体的类型字符串 + */ + http_request_t getRequestType(void) const; + + /** + * 获得 HTTP 请求页面的 referer URL + * @return {const char*} 为 NULL 则说明用户直接访问本 URL + */ + const char* getRequestReferer(void) const; + + /** + * 获得根据 HTTP 请求头获得的 http_ctype 对象 + * @return {const http_ctype&} + */ + const http_ctype& getHttpCtype(void) const; + + /* + * 当 HTTP 请求为 POST 方法,通过本函数设置读 HTTP 数据体的 + * IO 超时时间值(秒) + * @param rw_timeout {int} 读数据体时的超时时间(秒) + */ + void setRwTimeout(int rw_timeout); + + /** + * 获得上次出错的错误号 + * @return {http_request_error_t} + */ + http_request_error_t getLastError(void) const; + + /** + * 将 HTTP 请求头输出至流中(文件流或网络流) + * @param out {ostream&} + * @param prompt {const char*} 提示内容 + */ + void fprint_header(ostream& out, const char* prompt); +private: + http_request_error_t req_error_; + char cookie_name_[64]; + HttpServletResponse& res_; + session& store_; + HttpSession* http_session_; + socket_stream& stream_; + bool body_parse_; + int body_limit_; + + std::vector cookies_; + bool cookies_inited_; + http_client* client_; + http_method_t method_; + bool cgi_mode_; + http_ctype content_type_; + char localAddr_[32]; + char remoteAddr_[32]; + char localCharset_[32]; + int rw_timeout_; + std::vector params_; + http_request_t request_type_; + http_mime* mime_; + + bool readHeaderCalled_; + bool readHeader(void); + + void parseParameters(const char* str); +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/http/HttpServletResponse.hpp b/lib_acl_cpp/include/acl_cpp/http/HttpServletResponse.hpp new file mode 100644 index 000000000..86529c886 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/http/HttpServletResponse.hpp @@ -0,0 +1,150 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" + +namespace acl { + +class string; +class ostream; +class socket_stream; +class http_header; +class HttpCookie; +class HttpServlet; + +/** + * 与 HTTP 客户端响应相关的类,该类不应被继承,用户也不需要 + * 定义或创建该类对象 + */ +class ACL_CPP_API HttpServletResponse +{ +public: + /** + * 构造函数 + * @param stream {socket_stream&} 数据流,内部不会自动关闭流 + */ + HttpServletResponse(socket_stream& stream); + ~HttpServletResponse(void); + + /** + * 设置 HTTP 响应数据体的长度 + * @param n {acl_int64} 数据体长度 + */ +#ifdef WIN32 + HttpServletResponse& setContentLength(__int64 n); +#else + HttpServletResponse& setContentLength(long long int n); +#endif + + /** + * 设置与 HTTP 客户端保持联系长连接 + * @param on {bool} + */ + HttpServletResponse& setKeepAlive(bool on); + + /** + * 设置 HTTP 响应数据体的 Content-Type 字段值,可字段值可以为: + * text/html 或 text/html; charset=utf8 格式 + * @param value {const char*} 字段值 + */ + HttpServletResponse& setContentType(const char* value); + + /** + * 设置 HTTP 响应数据体中字符集,当已经在 setContentType 设置 + * 了字符集,则就不必再调用本函数设置字符集 + * @param charset {const char*} 响应体数据的字符集 + */ + HttpServletResponse& setCharacterEncoding(const char* charset); + + /** + * 设置 HTTP 响应头中的日期格式的字段 + * @param name {const char*} HTTP 响应头中的字段名 + * @param value {time_t} 时间值 + */ + HttpServletResponse& setDateHeader(const char* name, time_t value); + + /** + * 设置 HTTP 响应头中的字符串格式字段 + * @param name {const char*} HTTP 响应头中的字段名 + * @param value {const char*} 字段值 + */ + HttpServletResponse& setHeader(const char* name, const char* value); + + /** + * 设置 HTTP 响应头中的整数格式字段 + * @param name {const char*} HTTP 响应头中的字段名 + * @param value {int} 字段值 + */ + HttpServletResponse& setHeader(const char* name, int value); + + /** + * 设置 HTTP 响应头中的状态码:1xx, 2xx, 3xx, 4xx, 5xx + * @param status {int} HTTP 响应状态码, 如:200 + */ + HttpServletResponse& setStatus(int status); + + /** + * 设置为 CGI 模式,用户一般不需手工设置,因为 HttpServlet 类 + * 会自动设置是否是 CGI 模式 + * @param on {bool} 是否是 CGI 模式 + */ + HttpServletResponse& setCgiMode(bool on); + + /** + * 设置 HTTP 响应头中的重定向 location 字段 + * @param location {const char*} URL,非空 + * @param status {int} HTTP 响应状态码,一般为 3xx 类 + */ + HttpServletResponse& setRedirect(const char* location, int status = 302); + + /** + * 添加 cookie 对象,该对象必须是动态分配的,且用户自己不能 + * 再显示释放该对象,因为内部会自动释放 + * @param cookie {HttpCookie*} + */ + HttpServletResponse& addCookie(HttpCookie* cookie); + + /** + * 添加 cookie + * @param name {const char*} cookie 名 + * @param value {const char*} cookie 值 + * @param domain {const char*} cookie 存储域 + * @param path {const char*} cookie 存储路径 + * @param expires {time_t} cookie 过期时间间隔,当当前时间加 + * 该值为 cookie 的过期时间截(秒) + */ + HttpServletResponse& addCookie(const char* name, const char* value, + const char* domain = NULL, const char* path = NULL, + time_t expires = 0); + + /** + * 将 url 进行 url 编码 + * @param out {string&} 存储编码后的结果 + * @param url {const char*} 未编码前原始的 url + */ + void encodeUrl(string& out, const char* url); + + /** + * 获得 HTTP 响应头 + * @return {http_header&} + */ + http_header& getHttpHeader(void) const; + + /** + * 发送 HTTP 响应头,用户应该发送数据体前调用此函数将 HTTP + * 响应头发送给客户端 + */ + bool sendHeader(void); + + /** + * 获得 HTTP 响应对象的输出流对象,用户在调用 sendHeader 发送 + * 完 HTTP 响应头后,通过该输出流来发送 HTTP 数据体 + * @return {ostream&} + */ + ostream& getOutputStream(void) const; +private: + socket_stream& stream_; + http_header* header_; + char charset_[32]; + char content_type_[32]; +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/http/HttpSession.hpp b/lib_acl_cpp/include/acl_cpp/http/HttpSession.hpp new file mode 100644 index 000000000..720f37790 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/http/HttpSession.hpp @@ -0,0 +1,91 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include + +namespace acl { + +class session; + +/** + * 服务端 HttpSession 类,目前该类的数据存储只能支持存在 memcached 上 + */ +class ACL_CPP_API HttpSession +{ +public: + /** + * 构造函数 + * @param session {session&} 缓存对象 + */ + HttpSession(session& session); + virtual ~HttpSession(void); + + /** + * 获得客户端在服务端存储的 session 的字符串属性值 + * @param name {const char*} session 属性名,非空 + * @return {const char*} session 属性值,返回地址永远非空指针,用户 + * 可以通过判断返回地址是否为空串("\0")来判断是否存在或出错 + * 注:该函数返回非空数据后,用户应该立刻保留此返回值,因为下次 + * 的其它函数调用可能会清除该临时返回数据 + */ + virtual const char* getAttribute(const char* name) const; + + /** + * 获得客户端在服务端存储的 session 的二进制属性值 + * @param name {const char*} session 属性名,非空 + * @param size {size_t*} 该参数非空且属性值非空时,该指针地址 + * 存储返回属性值的大小 + * @return {const void*} session 属性值,为空指针时说明不存在 + * 或内部查询失败 + * 注:该函数返回非空数据后,用户应该立刻保留此返回值,因为下次 + * 的其它函数调用可能会清除该临时返回数据 + */ + virtual const void* getAttribute(const char* name, size_t* size) const; + + /** + * 在设置服务端设置 session 的字符串属性值 + * @param name {const char*} session 属性名,非空 + * @param value {const char*} session 属性值,非空 + * @return {bool} 返回 false 说明设置失败 + */ + virtual bool setAttribute(const char* name, const char* value); + + /** + * 在设置服务端设置 session 的二进制属性值 + * @param name {const char*} session 属性名,非空 + * @param value {const void*} session 属性值,非空 + * @param len {size_t} value 数据长度 + * @return {bool} 返回 false 说明设置失败 + */ + virtual bool setAttribute(const char* name, const void* value, size_t len); + + /** + * 删除客户端 session 中的某个属性值 + * @param name {const char*} session 属性名,非空 + * @return {bool} 删除是否成功 + */ + virtual bool removeAttribute(const char* name); + + /** + * 设置 session 在缓存服务器上的生存周期 + * @param ttl {time_t} 生存周期(秒) + * @return {bool} 是否成功 + */ + virtual bool setMaxAge(time_t ttl); + + /** + * 使 session 从服务端的缓存中删除即使 session 失效 + * @return {bool} 是否使 session 失效 + */ + virtual bool invalidate(void); + + /** + * 获得所产生的 session ID 标识 + * @return {const char*} 永远返回以 '\0' 结尾的非空指针 + */ + const char* getSid(void) const; + +protected: + session& session_; +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/http/http_client.hpp b/lib_acl_cpp/include/acl_cpp/http/http_client.hpp new file mode 100644 index 000000000..0d3acad7f --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/http/http_client.hpp @@ -0,0 +1,292 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" + +struct HTTP_HDR_RES; +struct HTTP_RES; +struct HTTP_HDR_REQ; +struct HTTP_REQ; + +namespace acl { + +class string; +class zlib_stream; +class socket_stream; +class ostream; +class istream; +class http_header; + +/** + * 该类的用处:1、当 HTTP 客户端向服务器请求数据时;2、当 HTTP 服务端接收 + * 到 HTTP 客户端连接时创建一个对应的 HTTP 客户端流对象 + * 该客户端流对象可以支持长连接 + */ +class ACL_CPP_API http_client +{ +public: + + /** + * 缺省的构造函数,使用此构造函数创建的 HTTP 客户端对象,需要显示地 + * 调用 http_client::open 来打开数据流 + */ + http_client(void); + + /** + * 根据已经连接成功的连接流对象创建 HTTP 客户端对象,但需要注意的是, + * 当该 http_client 对象销毁时,传入的 client 流对象并不会被销毁,需 + * 要应用自己销毁,否则会造成资源泄露 + * @param client {socket_stream*} HTTP 连接流对象,可以是请求端的流, + * 也可以是响应端的流;在本类对象被销毁时该流对象并不会被销毁,所以 + * 用户需自行释放之 + * @param rw_timeout {int} IO 读写超时时间(秒) + * @param is_request {bool} 是请求端还是响应端的客户端流 + * @param unzip {bool} 当用来读取服务器的响应数据时,如果服务器返回的 + * 数据体为压缩数据时,该参数控制在调用下面的函数时是否自动解压缩: + * read_body(string&, bool, int*) + */ + http_client(socket_stream* client, int rw_timeout = 120, + bool is_request = false, bool unzip = true); + + virtual ~http_client(void); + + /** + * 在支持长连接的多次请求中,可以手工调用此函数清除中间的数据对象, + * 当然这不是必须的,因为在多次调用 read_head 时,read_head 会自动 + * 调用 reset 来清除上次请求过程中的是间对象 + */ + void reset(void); + + /** + * 连接远程 HTTP 服务器 + * @param addr {const char*} 服务器地址,格式:IP:PORT 或 DOMAIN:PORT + * @param conn_timeout {int} 连接超时时间(秒) + * @param rw_timeout {int} 读写超时时间(秒) + * @param unzip {bool} 当服务器返回的数据体为压缩数据时是否自动解压缩 + * @param use_ssl {bool} 是否采用 SSL 加密传输方式 + * @return {bool} 连接是否成功 + */ + bool open(const char* addr, int conn_timeout = 60, int rw_timeout = 60, + bool unzip = true, bool use_ssl = false); + + /** + * 写 HTTP 请求头数据至输出流中 + * @param header {http_header&} + * @return {int} 真实写入的数据量, 返回 -1 表示出错 + */ + int write(const http_header& header); + + /** + * 当调用 http_client(socket_stream*, bool) 构造函数创建 + * 或用 http_client(void) 构建同时调用 open 打开数据流时 + * 可以调用本函数获得输出数据流句柄 + * @return {ostream&} 返回输出流的引用,如果该流并不存在, + * 则内部自动会产生断言,提示使用者应先将流打开 + */ + ostream& get_ostream(void) const; + + /** + * 当调用 http_client(socket_stream*, bool) 构造函数创建 + * 或用 http_client(void) 构建同时调用 open 打开数据流时 + * 可以调用本函数获得输入数据流句柄 + * @return {istream&} 返回输入流的引用,如果该流并不存在, + * 则内部自动会产生断言,提示使用者应先将流打开 + */ + istream& get_istream(void) const; + + /** + * 当调用 http_client(socket_stream*, bool) 构造函数创建 + * 或用 http_client(void) 构建同时调用 open 打开数据流时 + * 可以调用本函数获得数据流句柄 + * @return {socket_stream&} 返回流的引用,如果该流并不存在, + * 则内部自动会产生断言,提示使用者应先将流打开 + */ + socket_stream& get_stream(void) const; + + /** + * 从 HTTP 服务器读取响应头数据或从 HTTP 客户端读取请求数据, + * 在长连接的多次请求中,后续的请求会自动清除上次的中间数据对象 + * @return {bool} 是否成功 + */ + bool read_head(void); + + /** + * 获得 HTTP 请求的数据体或响应的数据体长度 + * @return {int64) 返回值若为 -1 则表明 HTTP 头不存在或没有长度字段 + */ +#ifdef WIN32 + __int64 body_length(void) const; +#else + long long int body_length(void) const; +#endif + + /** + * HTTP 数据流(请求流或响应流是否允许保持长连接) + * @return {bool} + */ + bool keep_alive(void) const; + + /** + * 获得 HTTP 请求头或响应头中某个字段名的字段值 + * @param name {const char*} 字段名 + * @return {const char*} 字段值,为空时表示不存在 + */ + const char* header_value(const char* name) const; + + /** + * 获得 HTTP 服务器返回的 HTTP 响应状态: + * 1xx, 2xx, 3xx, 4xx, 5xx + * @return {int} 若返回值为 -1 则表示出错,或该会话过程 + * 不是向 HTTP 服务器请求数据过程 + */ + int response_status(void) const; + + /** + * 获得 HTTP 客户端请求的 HOST 字段值 + * @return {const char*} 返回 NULL 表示不存在该字段 + */ + const char* request_host(void) const; + + /** + * 获得 HTTP 客户端请求的 PORT 端口号 + * @return {int} 返回 -1 表示不存在 + */ + int request_port(void) const; + + /** + * 获得 HTTP 客户端请求的 HTTP 方法:GET, POST, CONNECT + * @return {const char*} 返回值为空表示不存在 + */ + const char* request_method(void) const; + + /** + * 获得 HTTP 客户端请求的 URL 中除去 HTTP://domain 后的内容 + * 如:对于 http://test.com.cn/cgi-bin/test?name=value,则该 + * 函数应该返回:/cgi-bin/test?name=value + * @return {const char*} 返回 NULL 表示不存在 + */ + const char* request_url(void) const; + + /** + * 获得 HTTP 客户端请求的 URL 中的相对路径(不包含主机部分), + * 如:对于 http://test.com.cn/cgi-bin/test?name=value,则该 + * 函数应该返回:/path/test.cgi + * @return {const char*} 返回 NULL 表示不存在 + */ + const char* request_path(void) const; + + /** + * 获得 HTTP 客户端请求的 URL 中的所有参数,如: + * http://test.com.cn/cgi-bin/test?name=value,则该函数应该返回: + * name=value + * @return {const char*} 返回 NULL 表示不存在 + */ + const char* request_params(void) const; + + /** + * 获得 HTTP 客户端请求的 URL 中指定的参数值,如: + * http://test.com.cn/cgi-bin/test?name=value,则通过该函数可以 + * 获得 name 参数的值为 value + * @param name {const char*} 参数名 + * @return {const char*} 参数值,返回 NULL 表示不存在 + */ + const char* request_param(const char* name) const; + + /** + * 获得 HTTP 客户端请求头中的 cookie 值 + * @param name {const char*} cookie 名 + * @return {const char*} cookie 值,返回 NULL 则表示不存在 + */ + const char* request_cookie(const char* name) const; + + /** + * 从 HTTP 服务器读取响应体数据或从 HTTP 客户端读取请求体数据, + * 只有调用此函数才能进行解压操作 + * @param out {string&} 存储数据体的缓冲区 + * @param clean {bool} 在接收数据前是否自动清空 buf 缓冲区 + * @param real_size {int*} 若该指针非空,则记录真正读到的数据长度, + * 通过该指针返回的数据值永远 >= 0 + * @return {int} 返回值含义如下: + * > 0: 表示已经读到的数据,并且数据还未读完 + * == 0: 如果返回值为此值,则必须调用 body_finish 函数来判断是否 + * 已经读完 HTTP 响应体数据,如果已经读完,则同时表明还可以继续 + * 保持长连接 + * < 0: 表示连接关闭 + * 注:read_body 的两个函数不能混用; + * 当为解压缩数据时,则返回的值为解压缩后的数据长度 + */ + int read_body(string& out, bool clean = true, int* real_size = NULL); + + /** + * 从 HTTP 服务器读取响应体数据或从 HTTP 客户端读取请求体数据, + * 该函数不能对数据进行解压 + * @param buf {char*} 存储数据体的缓冲区,不能为空 + * @param size {size_t} buf 缓冲区长度 + * @return {int} 返回值含义如下: + * > 0: 表示已经读到的数据,并且数据还未读完 + * == 0: 表示已经读完 HTTP 响应体数据,但连接并未关闭 + * < 0: 表示连接关闭 + */ + int read_body(char* buf, size_t size); + + /** + * 判断是否已经读完 HTTP 响应数据体 + * @return {bool} + */ + bool body_finish(void) const; + + /** + * 取得通过 read_head 读到的 HTTP 响应头对象,且当传入缓冲区 + * 非空时,将 HTTP 响应头数据拷贝至缓冲区 + * @param buf {string*} 非空时用来存储 HTTP 响应头数据 + * @return {const HTTP_HDR_RES*} HTTP 响应头对象,如果为空,则说明 + * 未读到响应头数据 + */ + const HTTP_HDR_RES* get_respond_head(string* buf); + + /** + * 取得通过 read_head 读到的 HTTP 请求头对象,且当传入缓冲区 + * 非空时,将 HTTP 请求头数据拷贝至缓冲区 + * @param buf {string*} 非空时用来存储 HTTP 请求头数据 + * @return {const HTTP_HDR_REQ*} HTTP 请求头对象,如果为空,则说明 + * 未读到请求头数据 + */ + const HTTP_HDR_REQ* get_request_head(string* buf); + + /** + * 输出服务器返回的 HTTP 响应头信息至标准输出 + * @param prompt {const char*} 若非空则随同 HTTP 头信息一起输出 + */ + void print_header(const char* prompt); + + /** + * 输出服务器返回的 HTTP 响应头信息至输出流中 + * @param out {ostream&} 输出流,可以是文件流,也可以是网络流 + * @param prompt {const char*} 若非空则随同 HTTP 头信息一起输出 + */ + void fprint_header(ostream& out, const char* prompt); + +protected: +private: + socket_stream* stream_; // HTTP 数据流 + bool stream_fixed_; // 是否允许释放 stream_ 流对象 + + HTTP_HDR_RES* hdr_res_; // HTTP 头响应对象 + struct HTTP_RES* res_; // HTTP 响应对象 + HTTP_HDR_REQ* hdr_req_; // HTTP 头请求对象 + struct HTTP_REQ* req_; // HTTP 请求对象 + int rw_timeout_; // IO 读写超时时间 + bool unzip_; // 是否对压缩数据进行解压缩 + zlib_stream* zstream_; // 解压对象 + bool is_request_; // 是否是客户请求端 + int gzip_header_left_; // gzip 头剩余的长度 + int last_ret_; // 数据读完后记录最后的返回值 + bool body_finish_; // 是否已经读完 HTTP 响应体数据 + + bool read_request_head(void); + bool read_response_head(void); + int read_request_body(char* buf, size_t size); + int read_response_body(char* buf, size_t size); + int read_request_body(string& out, bool clean, int* real_size); + int read_response_body(string& out, bool clean, int* real_size); +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/http/http_ctype.hpp b/lib_acl_cpp/include/acl_cpp/http/http_ctype.hpp new file mode 100644 index 000000000..47b9b8f61 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/http/http_ctype.hpp @@ -0,0 +1,75 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include "acl_cpp/stdlib/string.hpp" + +namespace acl { + +/** + * 与 HTTP 头中的 Content-Type 相关的类定义,可以分析如下数据: + * Content-Type: application/x-www-form-urlencoded + * Content-Type: multipart/form-data; boundary=xxx + * Content-Type: application/octet-stream + * Content-Type: text/html; charset=utf8 + * Content-Type: xxx/xxx; name=xxx + * ... + */ +class ACL_CPP_API http_ctype +{ +public: + http_ctype(void); + ~http_ctype(void); + + /** + * 分析 HTTP 头中 Content-Type 字段值 + * @param cp {const char*} Content-Type 字段值,如: + * application/x-www-form-urlencoded + * multipart/form-data; boundary=xxx + * application/octet-stream + * @return {bool} 输入数据是否合法 + */ + bool parse(const char* cp); + + /** + * 获得 Content-Type 字段值 text/html; charset=utf8 中的 text + * @return {const char*} 返回 NULL 说明没有该数据,一般是因为 + * parse 失败导致的 + */ + const char* get_ctype(void) const; + + /** + * 获得 Content-Type 字段值 text/html; charset=utf8 中的 text + * @return {const char*} 返回 NULL 说明没有该数据 + */ + const char* get_stype(void) const; + + /** + * 获得 Content-Type 字段值 multipart/form-data; boundary=xxx + * 中的 boundary 的值 xxx + * @return {const char*} 返回 NULL 说明没有该数据 + */ + const char* get_bound(void) const; + + /** + * 获得 Content-Type: xxx/xxx; name=name_xxx + * 中的 name 的值 name_xxx + * @return {const char*} 返回 NULL 说明没有该数据 + */ + const char* get_name(void) const; + + /** + * 获得 Content-Type 字段值 text/html; charset=utf8 中的 utf8 + * @return {const char*} 返回 NULL 说明没有该数据 + */ + const char* get_charset(void) const; +protected: +private: + char* ctype_; + char* stype_; + char* name_; + char* charset_; + string* bound_; + + void reset(void); +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/http/http_download.hpp b/lib_acl_cpp/include/acl_cpp/http/http_download.hpp new file mode 100644 index 000000000..cf3e568ed --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/http/http_download.hpp @@ -0,0 +1,127 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" + +namespace acl { + +class http_client; +class http_request; +class http_header; + +class ACL_CPP_API http_download +{ +public: + /** + * 构造函数 + * @param url {const char*} 文件在服务器上的 url 地址 + * @param addr {const char*} 非空时,设置服务器地址(格式为: + * ip[|domain]:port,否则服务器地址从 url 中提取 + */ + http_download(const char* url, const char* addr = NULL); + virtual ~http_download(); + + /** + * 在调用 run 之前可以通过本函数获得请求头对象,便于用户设置 + * 自己的请求头字段(但 set_method/set_range 是内部自动设置的) + * @return {http_header*} 返回 NULL 表示输入的 URL 非法 + */ + http_header* request_header() const; + + /** + * 调用此函数可以获得 http_request 对象,便于设置或查询请求头 + * 或返回数据中的参数 + * @return {http_request*} 返回 NULL 表示输入的 URL 非法 + */ + http_request* request() const; + + /** + * 下载文件,当 range_from >= 0 且 range_to >= range_from 时自动 + * 采用分段下载方式,否则采用全部下载方式 + * @param range_from {acl_int64} 下载起始偏移位置,下标从 0 开始, + * 当该值 >= 0 且 range_to >= 本值时才采用分段下载方式 + * @param range_to {acl_int64} 下载结束偏移位置 + * @param req_body {const char*} 请求的数据体 + * @param len {size_t} req_body 非空时指明其长度 + * @return {bool} 下载是否成功,如果返回 true 则表示下载成功,否则 + * 可能是输入参数非法,或 URL 不存在,或服务器不支持断点传输,或 + * 在下载过程中子类返回 false 禁止继续下载 + */ +#ifdef WIN32 + bool get(__int64 range_from = -1, __int64 range_to = -1, + const char* req_body = NULL, size_t len = 0); +#else + bool get(long long int range_from = -1, long long int range_to = -1, + const char* req_body = NULL, size_t len = 0); +#endif + + /** + * 重置内部请求状态 + * @param url {const char*} 非空时则用此 URL 替代构造函数中输入的 URL, + * 否则依然使用构造函数中使用的 url + * @param addr {const char*} 非空时,设置服务器地址(格式为: + * ip[|domain]:port,否则服务器地址从 url 中提取 + * @return {bool} 返回 false 表示 url 非法 + */ + bool reset(const char* url = NULL, const char* addr = NULL); + + /** + * 取得由构造函数或 reset 函数输入的 url + * @return {const char*} 返回 NULL 表示输入的 url 非法 + */ + const char* get_url() const; + + /** + * 取得由构造函数或 reset 函数输入的 url 所得到的服务器地址,格式为: + * ip[|domain]:port + * @return {const char*} 返回 NULL 表示输入的 url 非法 + */ + const char* get_addr() const; + +protected: + /** + * 当发送完 HTTP 请求数据后,读到 HTTP 服务器响应头后的回调函数 + * @param conn {http_client*} + * @return {bool} 若子类返回 false 则停止继续下载 + */ + virtual bool on_response(http_client* conn); + + /** + * 当得到服务器返回完整文件长度后的回调函数 + * @param n {__int64} 完整文件长度 + * @return {bool} 若子类返回 false 则停止继续下载 + */ +#ifdef WIN32 + virtual bool on_length(__int64 n); +#else + virtual bool on_length(long long int n); +#endif + + /** + * 下载过程中,边下载边通知子类下载的数据及数据长度 + * @param data {const void*} 下载的数据地址 + * @param len {size_t} 下载的数据长度 + * @return {bool} 若子类返回 false 则停止继续下载 + */ + virtual bool on_save(const void* data, size_t len) = 0; + +private: + char* url_; + char addr_[128]; + http_request* req_; + + // 从头开始下载整个文件 + bool save_total(const char* body, size_t len); + + // 断点下载部分文件 +#ifdef WIN32 + bool save_range(const char* body, size_t len, + __int64 range_from, __int64 range_to); +#else + bool save_range(const char* body, size_t len, + long long int range_from, long long int range_to); +#endif + + // 开始下载 + bool save(http_request* req); +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/http/http_header.hpp b/lib_acl_cpp/include/acl_cpp/http/http_header.hpp new file mode 100644 index 000000000..b5730b8d5 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/http/http_header.hpp @@ -0,0 +1,287 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include +#include "acl_cpp/http/http_type.hpp" + +struct HTTP_HDR_RES; +struct HTTP_HDR_ENTRY; + +namespace acl { + +class string; +class HttpCookie; + +/** + * HTTP 头类,可以构建请求头或响应头 + */ +class ACL_CPP_API http_header +{ +public: + http_header(void); + + /** + * HTTP 请求头构造函数 + * @param url {const char*} 请求的 url, + * 该 url 不能包含 ? 以及 ? 后面的参数部分,如果想添加该 url 的参数, + * 应该通过调用 add_param 完成,url 格式 + * 如: http://www.test.com/, /cgi-bin/test.cgi, + * http://www.test.com/cgi-bin/test.cgi + * 不能为: http://www.test.com/cgi-bin/test.cgi?name=value 或 + * /cgi-bin/test.cgi?name=value,因为其中的 name=value 参数 + * 必须由 add_param 来添加 + */ + http_header(const char* url); + + /** + * HTTP 响应头构造函数 + * @param status {int} 状态字如:1xx, 2xx, 3xx, 4xx, 5xx + */ + http_header(int status); + virtual ~http_header(void); + + /** + * 重置 HTTP 头信息同时将上次的临时资源释放 + */ + void reset(void); + + ////////////////////////////////////////////////////////////////////////// + // HTTP 请求与 HTTP 响应通用的方法函数 + ////////////////////////////////////////////////////////////////////////// + + /** + * 设置 HTTP 头是客户端的请求头还是服务器的响应头 + * @param onoff {bool} true 表示是请求头,否则表示响应头 + * @return {http_header&} 返回本对象的引用,便于用户连续操作 + */ + http_header& set_request_mode(bool onoff); + + /** + * 向 HTTP 头中添加字段 + * @param name {const char*} 字段名 + * @param value {const char*} 字段值 + * @return {http_header&} 返回本对象的引用,便于用户连续操作 + */ + http_header& add_entry(const char* name, const char* value); + + /** + * 设置 HTTP 头中的 Content-Length 字段 + * @param n {int64} 设置值 + * @return {http_header&} 返回本对象的引用,便于用户连续操作 + */ +#ifdef WIN32 + http_header& set_content_length(__int64 n); +#else + http_header& set_content_length(long long int n); +#endif + + /** + * 设置 HTTP 头中的 Content-Type 字段 + * @param value {const char*} 设置值 + * @return {http_header&} 返回本对象的引用,便于用户连续操作 + */ + http_header& set_content_type(const char* value); + + /** + * 设置 HTTP 头中的 Connection 字段,是否保持长连接 + * 不过,目前并未真正支持长连接,即使设置了该标志位, + * 则得到响应数据后也会主动关闭连接 + * @param on {bool} 是否保持长连接 + * @return {http_header&} 返回本对象的引用,便于用户连续操作 + */ + http_header& set_keep_alive(bool on); + + /** + * 向 HTTP 头中添加 cookie + * @param name {const char*} cookie 名 + * @param value {const char*} cookie 值 + * @param domain {const char*} 所属域 + * @param path {const char*} 存储路径 + * @param expires {time_t} 过期时间,当该值为 0 时表示不过期, + * > 0 时,则从现在起再增加 expires 即为过期时间,单位为秒 + * @return {http_header&} 返回本对象的引用,便于用户连续操作 + */ + http_header& add_cookie(const char* name, const char* value, + const char* domain = NULL, const char* path = NULL, + time_t expires = 0); + + /** + * 向 HTTP 头中添加 cookie + * @param cookie {http_cookie*} 必须是动态分配的 cookie 对象 + * @return {http_header&} 返回本对象的引用,便于用户连续操作 + */ + http_header& add_cookie(HttpCookie* cookie); + + /** + * 将整型的日期转换为 rfc1123 字符串格式的日期 + */ + static void date_format(char* out, size_t size, time_t t); + + /** + * 判断是否是 HTTP 请求头 + * @return {bool} 返回 false 表明是 HTTP 响应头 + */ + bool is_request(void) const; + + ////////////////////////////////////////////////////////////////////////// + // HTTP 请求方法函数 + ////////////////////////////////////////////////////////////////////////// + + /** + * 创建 HTTP 请求头数据 + * @param buf {string&} 存储结果数据 + * @return {bool} 创建请求头中否成功 + */ + bool build_request(string& buf) const; + + /** + * 设置请求的 URL,该 URL 不能包含 ? 以及 ? 后面的参数部分, + * 如果想添加该 URL 的参数,应该通过调用 add_param 完成,url 格式 + * 如: http://www.test.com/, /cgi-bin/test.cgi, + * http://www.test.com/cgi-bin/test.cgi + * 不能为: http://www.test.com/cgi-bin/test.cgi?name=value 或 + * /cgi-bin/test.cgi?name=value,因为其中的 name=value 参数必须由 add_param + * 来添加 + * @param url {const char*} 请求的 url + * @return {http_header&} 返回本对象的引用,便于用户连续操作 + */ + http_header& set_url(const char* url); + + /** + * 设置 HTTP 请求头的 HOST 字段 + * @param value {const char*} 请求头的 HOST 字段值 + * @return {http_header&} 返回本对象的引用,便于用户连续操作 + */ + http_header& set_host(const char* value); + + /** + * 设置 HTTP 协议的请求方法,如果不调用此函数,则默认用 GET 方法 + * @param method {http_method_t} HTTP 请求方法 + * @return {http_header&} 返回本对象的引用,便于用户连续操作 + */ + http_header& set_method(http_method_t method); + + /** + * 设置 HTTP 请求头中 Range 字段,用于分段请求数据,多用于 + * 支持断点续传的 WEB 服务器中 + * @param from {http_off_t} 起始偏移位置,下标从 0 开始,该 + * 值当 >= 0 时才有效 + * @param to {http_off_t} 请求结束偏移位置,下标从 0 开始, + * 当该值输入 < 0 时,则认为是请求从起始位置开始至最终长度 + * 位置 + * @return {http_header&} 返回本对象的引用,便于用户连续操作 + */ +#ifdef WIN32 + http_header& set_range(__int64 from, __int64 to); +#else + http_header& set_range(long long int from, long long int to); +#endif + + /** + * 获得由 set_range 设置的分段请求位置值 + * @param from {http_off_t*} 非空时存储起始位置偏移 + * @param to {http_off_t*} 非空时存储结束位置偏移 + */ +#ifdef WIN32 + void get_range(__int64* from, __int64* to); +#else + void get_range(long long int* from, long long int* to); +#endif + + /** + * 设置 HTTP 请求头中是否允许接收压缩数据,对应的 HTTP 头字段为: + * Accept-Encoding: gzip, deflate,但目前仅支持 gzip 格式 + * @param on {bool} 如果为 true 则自动添加 HTTP 压缩头请求 + * @return {http_header&} 返回本对象的引用,便于用户连续操作 + */ + http_header& accept_gzip(bool on); + + /** + * 向请求的 URL 中添加参数对 + * @param name {const char*} 参数名 + * @param value {const char*} 参数值 + * @return {http_header&} 返回本对象的引用,便于用户连续操作 + */ + http_header& add_param(const char* name, const char* value); + + /** + * url 重定向 + * @param url {const char*} 重定向的 URL,格式为: + * http://xxx.xxx.xxx/xxx 或 /xxx + * 如果是前者,则自动从中取出 HOST 字段,如果是后者,则 + * 延用之前的 HOST + */ + bool redirect(const char* url); + + /** + * 设置重定向次数,如果该值 == 0 则不主动进行重定向,否则 + * 进行重定向且重定向的次数由该值决定 + * @param n {int} 允许重定向的次数 + * @return {http_header&} 返回本对象的引用,便于用户连续操作 + */ + http_header& set_redirect(unsigned int n = 5); + + /** + * 获取通过 set_redirect 设置的允许的最大重定向次数 + * @return {unsigned int} + */ + unsigned int get_redirect(void) const; + + /** + * 当需要重定向时,会主动调用此函数允许子类做一些重置工作 + */ + virtual void redicrect_reset(void) {} + + ////////////////////////////////////////////////////////////////////////// + // HTTP 响应方法函数 + ////////////////////////////////////////////////////////////////////////// + + /** + * 创建 HTTP 响应头数据 + * @param buf {string&} 存储结果数据 + * @return {bool} 创建响应头中否成功 + */ + bool build_response(string& buf) const; + + /** + * 设置 HTTP 响应头中的响应状态字 + * @param status {int} 状态字如:1xx, 2xx, 3xx, 4xx, 5xx + * @return {http_header&} 返回本对象的引用,便于用户连续操作 + */ + http_header& set_status(int status); + + /** + * 设置是否用来生成 CGI 格式的响应头 + * @param on {bool} 是否 CGI 格式响应头 + * @return {http_header&} 返回本对象的引用,便于用户连续操作 + */ + http_header& set_cgi_mode(bool on); + +protected: +private: + //char* domain_; // HTTP 服务器域名 + unsigned short port_; // HTTP 服务器端口 + char* url_; // HTTP 请求的 URL + std::list params_; // 请求参数集合 + std::list cookies_; // cookies 集合 + std::list entries_; // HTTP 请求头中各字段集合 + http_method_t method_; // HTTP 请求的方法 + bool keep_alive_; // 是否保持长连接 + unsigned int nredirect_; // 最大重定向的次数限制 + bool accept_compress_; // 是否接收压缩数据 + int status_; // 响应头的状态字 + bool is_request_; // 是请求头还是响应头 + bool cgi_mode_; // 是否 CGI 响应头 +#ifdef WIN32 + __int64 range_from_; // 请求头中,range 起始位置 + __int64 range_to_; // 请求头中,range 结束位置 +#else + long long int range_from_; // 请求头中,range 起始位置 + long long int range_to_; // 请求头中,range 结束位置 +#endif + + void init(void); // 初始化 + void clear(void); + void build_common(string& buf) const; // 构建通用头 +}; + +} // namespace acl end diff --git a/lib_acl_cpp/include/acl_cpp/http/http_mime.hpp b/lib_acl_cpp/include/acl_cpp/http/http_mime.hpp new file mode 100644 index 000000000..a7797a337 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/http/http_mime.hpp @@ -0,0 +1,127 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include +#include +#include "acl_cpp/stdlib/string.hpp" +#include "acl_cpp/mime/mime_attach.hpp" +#include "acl_cpp/http/http_type.hpp" + +struct MIME_STATE; +struct MIME_NODE; + +namespace acl { + +/** + * http mime 结点类,继承关系: + * http_mime_node : mime_attach : mime_node + * 常用函数功能: + * http_mime_node::get_mime_type 获得该结点的类型 + * mime_node::get_name: 获得该结点的名称 + * mime_attach::get_filename: 当结点为上传文件类型时,此函数 + * 获得上传文件的文件名 + * http_mime_node::get_value: 当结点为参数类型时,此函数获得 + * 参数值 + */ +class ACL_CPP_API http_mime_node : public mime_attach +{ +public: + /** + * @param path {const char*} 原始文件存放路径,不能为空 + * @param node {MIME_NODE*} 对应的 MIME 结点,非空 + * @param decodeIt {bool} 是否对 MIME 结点的头部数据 + * 或数据体数据进行解码 + * @param toCharset {const char*} 本机的字符集 + * @param off {off_t} 偏移数据位置 + */ + http_mime_node(const char* path, const MIME_NODE* node, + bool decodeIt = true, const char* toCharset = "gb2312", + off_t off = 0); + ~http_mime_node(void); + + /** + * 获得该结点的类型 + * @return {http_mime_t} + */ + http_mime_t get_mime_type(void) const; + + /** + * 当 get_mime_type 返回的类型为 HTTP_MIME_PARAM 时,可以 + * 调用此函数获得参数值;参数名可以通过基类的 get_name() 获得 + * @return {const char*} 返回 NULL 表示参数不存在 + */ + const char* get_value(void) const; +protected: +private: + http_mime_t mime_type_; + char* param_value_; + + void load_param(const char* path); +}; + +////////////////////////////////////////////////////////////////////////// + +/** + * http mime 解析器,该解析器为流式解析器,用户在使用时可以每次仅输入 + * 部分数据给 update 函数,当该函数返回 true 时表示解析完成且解析正确 + */ +class ACL_CPP_API http_mime +{ +public: + /** + * 构建函数 + * @param boundary {const char*} 分隔符,不能为空 + * @param local_charset {const char*} 本地字符集,非空时会自动将 + * 参数内容转为本地字符集 + */ + http_mime(const char* boundary, const char* local_charset = "gb2312"); + ~http_mime(void); + + /** + * 设置 MIME 数据的存储路径,当分析完 MIME 数据后,如果想要 + * 从中提取数据,则必须给出该 MIME 的原始数据的存储位置,否则 + * 无法获得相应数据,即 save_xxx/get_nodes/get_node 函数均无法 + * 正常使用 + * @param path {const char*} 文件路径名, 如果该参数为空, 则不能 + * 获得数据体数据, 也不能调用 save_xxx 相关的接口 + */ + void set_saved_path(const char* path); + + /** + * 调用此函数进行流式方式解析数据体内容 + * @param data {const char*} 数据体(可能是数据头也可能是数据体, + * 并且不必是完整的数据行) + * @param len {size_t} data 数据长度 + * @return {bool} 针对 multipart 数据, 返回 true 表示解析完毕; + * 对于非 multipart 文件, 该返回值永远为 false, 没有任何意义, + * 需要调用者自己判断数据体的结束位置 + * 注意: 调用完此函数后一定需要调用 update_end 函数通知解析器 + * 解析完毕 + */ + bool update(const char* data, size_t len); + + /** + * 获得所有的 MIME 结点 + * @return {const std::list&} + */ + const std::list& get_nodes(void) const; + + /** + * 根据变量名取得 HTTP MIME 结点 + * @param name {const char*} 变量名 + * @return {const http_mime_node*} 返回空则说明对应变量名的结点 + * 不存在 + */ + const http_mime_node* get_node(const char* name) const; +protected: +private: + char* boundary_; + char* save_path_; + off_t off_; + MIME_STATE* mime_state_; + std::list mime_nodes_; + char local_charset_[32]; + bool decode_on_; + bool parsed_; +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/http/http_pipe.hpp b/lib_acl_cpp/include/acl_cpp/http/http_pipe.hpp new file mode 100644 index 000000000..888f73ac0 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/http/http_pipe.hpp @@ -0,0 +1,29 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include "acl_cpp/stdlib/pipe_stream.hpp" + +namespace acl { + +class charset_conv; +class pipe_stream; + +class http_pipe +{ +public: + http_pipe(void); + virtual ~http_pipe(void); + void set_charset(charset_conv* conv); + bool set_charset(const char* from, const char* to); + void append(pipe_stream* ps); + void reset(); + bool update(const char* in, size_t len); + bool update_end(void); + + pipe_manager& get_manager(void); +protected: +private: + pipe_manager manager_; + charset_conv* conv_; +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/http/http_request.hpp b/lib_acl_cpp/include/acl_cpp/http/http_request.hpp new file mode 100644 index 000000000..bebf01746 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/http/http_request.hpp @@ -0,0 +1,253 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include +#include "acl_cpp/http/http_header.hpp" +#include "acl_cpp/connpool/connect_client.hpp" + +namespace acl { + +class http_client; +class http_pipe; +class socket_stream; +class charset_conv; +class xml; +class json; + +/** + * HTTP 客户端请求类,该类对象支持长连接,同时当连接断时会自动重试 + */ +class ACL_CPP_API http_request : public connect_client +{ +public: + /** + * 构造函数:通过该构造函数传入的 socket_stream 流对象并 + * 不会被关闭,需要调用者自己关闭 + * @param client {socket_stream*} 数据连接流,非空, + * 在本类对象被销毁时该流对象并不会被销毁,所以用户需自行释放 + * @param conn_timeout {int} 如果传入的流关闭,则内部会 + * 自动重试,此时需要该值表示连接服务器的超时时间(秒), + * 至于重连流的 IO 读写超时时间是从 输入的流中继承的 + * @param unzip {bool} 是否对服务器响应的数据自动进行解压 + * 注:当该类实例被多次使用时,用户应该在每次调用前调用 + * request_header::http_header::reset() + */ + http_request(socket_stream* client, int conn_timeout = 60, + bool unzip = true); + + /** + * 构造函数:该构造函数内部创建的 socket_stream 流会自行关闭 + * @param addr {const char*} WEB 服务器地址 + * @param conn_timeout {int} 远程连接服务器超时时间(秒) + * @param rw_timeout {int} IO 读写超时时间(秒) + * @param unzip {bool} 是否对服务器响应的数据自动进行解压 + */ + http_request(const char* addr, int conn_timeout = 60, + int rw_timeout = 60, bool unzip = true); + + virtual ~http_request(void); + + /** + * 设置在读取服务响应数据时是否针对压缩数据进行解压 + * @param on {bool} + * @return {http_request&} + */ + http_request& set_unzip(bool on); + + /** + * 获得 HTTP 请求头对象,然后在返回的 HTTP 请求头对象中添加 + * 自己的请求头字段或 http_header::reset()重置请求头状态, + * 参考:http_header 类 + * @return {http_header&} + */ + http_header& request_header(void); + + /** + * 向 HTTP 服务器发送 HTTP 请求头及 HTTP 请求体,同时从 + * HTTP 服务器读取 HTTP 响应头,对于长连接,当连接中断时 + * 会再重试一次,在调用下面的几个 get_body 函数前必须先 + * 调用本函数; + * 正常情况下,该函数在发送完请求数据后会读 HTTP 响应头, + * 所以用户在本函数返回 true 后可以调用:get_body() 或 + * http_request::get_clinet()->read_body(char*, size_t) + * 继续读 HTTP 响应的数据体 + * @param data {const char*} 发送的数据体地址,非空时自动按 + * POST 方法发送,否则按 GET 方法发送 + * @param len {size_} data 非空时指定 data 数据长度 + * @return {bool} 发送请求数据及读 HTTP 响应头数据是否成功 + */ + bool request(const char* data, size_t len); + + /** + * 当调用 request 成功后调用本函数,读取服务器响应体数据 + * 并将结果存储于规定的 xml 对象中 + * @param out {xml&} HTTP 响应体数据存储于该 xml 对象中 + * @param to_charset {const char*} 当该项非空,内部自动 + * 将数据转成该字符集存储于 xml 对象中 + * @return {bool} 读数据是否成功 + * 注:当响应数据体特别大时不应用此函数,以免内存耗光 + */ + bool get_body(xml& out, const char* to_charset = NULL); + + /** + * 当调用 request 成功后调用本函数,读取服务器响应体数据 + * 并将结果存储于规定的 json 对象中 + * @param out {json&} HTTP 响应体数据存储于该 json 对象中 + * @param to_charset {const char*} 当该项非空,内部自动 + * 将数据转成该字符集存储于 json 对象中 + * @return {bool} 读数据是否成功 + * 注:当响应数据体特别大时不应用此函数,以免内存耗光 + */ + bool get_body(json& out, const char* to_charset = NULL); + + /* + * 当调用 request 成功后调用本函数,读取服务器全部响应数据 + * 存储于输入的缓冲区中 + * @param out {string&} 存储响应数据体 + * @param to_charset {const char*} 当该项非空,内部自动 + * 将数据转成该字符集存储于 out 对象中 + * 注:当响应数据体特别大时不应用此函数,以免内存耗光 + */ + bool get_body(string& out, const char* to_charset = NULL); + + /* + * 当调用 request 成功后调用本函数,读取服务器响应数据并 + * 存储于输入的缓冲区中,可以循环调用本函数,直至数据读完了, + * @param buf {char*} 存储部分响应数据体 + * @param size {size_t} buf 缓冲区大小 + * @return {int} 返回值 == 0 表示正常读完毕,< 0 表示服务器 + * 关闭连接,> 0 表示已经读到的数据,用户应该一直读数据直到 + * 返回值 <= 0 为止 + * 注:该函数读到的是原始 HTTP 数据体数据,不做解压和字符集 + * 解码,用户自己根据需要进行处理 + */ + int get_body(char* buf, size_t size); + + /** + * 在调用 read_body 之前,通过此函数设置本地字符集,从而使数据 + * 边接收边转换 + * @param to_charset {const char*} 本地字符集 + */ + void set_charset(const char* to_charset); + + /** + * 当调用 request 成功后调用本函数读 HTTP 响应数据体,可以循环调用 + * 本函数,本函数内部自动对压缩数据进行解压,如果在调用本函数之前 + * 调用 set_charset 设置了本地字符集,则还同时对数据进行字符集转码 + * 操作 + * @param out {string&} 存储结果数据 + * @param clean {bool} 每次调用本函数时,是否要求先自动将缓冲区 out + * 的数据清空 + * @param real_size {int*} 当该指针非空时,存储解压前读到的真正数据 + * 长度,如果在构造函数中指定了非自动解压模式且读到的数据 > 0,则该 + * 值存储的长度值应该与本函数返回值相同;当读出错或未读到任何数据时, + * 该值存储的长度值为 0 + * @return {int} == 0 表示读完毕,可能连接并未关闭;>0 表示本次读操作 + * 读到的数据长度(当为解压后的数据时,则表示为解压之后的数据长度, + * 与真实读到的数据不同,真实读到的数据长度应该通过参数 real_size 来 + * 获得); < 0 表示数据流关闭,此时若 real_size 非空,则 real_size 存 + * 储的值应该为 0 + */ + int read_body(string& out, bool clean = false, + int* real_size = NULL); + + /** + * 当通过 http_request::request_header().set_range() 设置了 + * range 的请求时,此函数检查服务器返回的数据是否支持 range + * @return {bool} + */ + bool support_range(void) const; + +#ifdef WIN32 + /** + * 当调用了 http_request::request_header().set_range() 且读取服务器 + * 返回的数据头后,此函数用来获得支持分段功能的起始偏移位置 + * @return {acl_int64} 若服务器不支持 range 方式,则返回值 < 0 + */ + __int64 get_range_from(void) const; + + /** + * 当调用了 http_request::request_header().set_range() 且读取服务器 + * 返回的数据头后,此函数用来获得支持分段功能结束偏移位置 + * @return {acl_int64} 若服务器不支持 range 方式,则返回值 < 0 + */ + __int64 get_range_to(void) const; + + /** + * 当调用了 http_request::request_header().set_range() 且读取服务器 + * 返回的数据头后,此函数用来获得支持分段功能的整个数据体大小,该值 + * 即代表 HTTP 响应数据体大小 + * @return {acl_int64} 若服务器不支持 range 方式,则返回值 < 0 + */ + __int64 get_range_max(void) const; +#else + long long int get_range_from(void) const; + long long int get_range_to(void) const; + long long int get_range_max(void) const; +#endif + + /** + * 获得服务器返回的 Set-Cookie 的集合 + * @return {const std::vector*} 返回空表示 + * 没有 cookie 对象或连接流为空 + */ + const std::vector* get_cookies(void) const; + + /** + * 获得服务器返回的 Set-Cookie 设置的某个 cookie 对象 + * @param name {const char*} cookie 名 + * @param case_insensitive {bool} 是否区分大小写,true 表示 + * 不区分大小写 + * @return {const HttpCookie*} 返回 NULL 表示不存在 + */ + const HttpCookie* get_cookie(const char* name, + bool case_insensitive = true) const; + + /** + * 获得 http_client HTTP 连接流,可以通过返回的对象获得 + * 服务器响应的头部分数据,参考:http_client 类 + * @return {http_client*} 当返回空时表示流出错了 + */ + http_client* get_client(void) const; + + /** + * 重置请求状态,在同一个连接的多次请求时会调用此函数 + */ + void reset(void); + +protected: + /** + * 基类 connect_client 的纯虚函数,显式地调用本函数用来打开与服务端的连接 + * @reutrn {bool} 连接是否成功 + */ + virtual bool open(); + +private: + char addr_[64]; + bool keep_alive_; + int conn_timeout_; + int rw_timeout_; + bool unzip_; + charset_conv* conv_; + http_client* client_; + http_header header_; + bool cookie_inited_; + std::vector* cookies_; +#ifdef WIN32 + __int64 range_from_; + __int64 range_to_; + __int64 range_max_; +#else + long long int range_from_; + long long int range_to_; + long long int range_max_; +#endif + + bool send_request(const char* data, size_t len); + bool try_open(bool* reuse_conn); + void close(void); + void create_cookies(void); + http_pipe* get_pipe(const char* to_charset); + void check_range(void); +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/http/http_request_pool.hpp b/lib_acl_cpp/include/acl_cpp/http/http_request_pool.hpp new file mode 100644 index 000000000..a79cdff23 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/http/http_request_pool.hpp @@ -0,0 +1,47 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include "acl_cpp/connpool/connect_pool.hpp" + +namespace acl +{ + +/** + * http 客户端连接池类,该类父类为 connect_pool,该类只需实现父类中的虚函数 + * create_connect 便拥有了连接池父类 connect_pool 的功能;另外,该类创建 + * 的连接对象是 http_reuqest 对象,所以在调用 connect_pool::peek 时返回 + * 的便是 http_request 类,调用者需要将 peek 返回的类对象强制转为 http_request + * 类对象,便可以使用 http_request 类折所有功能,其中 http_reuqest 类为 + * connect_client 的子类 + */ +class http_reuqest_pool : public connect_pool +{ +public: + /** + * 构造函数 + * @param addr {const char*} 服务器监听地址,格式:ip:port(domain:port) + * @param count {int} 连接池最大连接个数限制 + * @param retry_inter {int} 当连接断开后,重新再次打开连接的时间间隔(秒), + * 当该值 <= 0 时表示允许连接断开后可以立即重连,否则必须超过该时间间隔后才 + * 允许断开重连 + */ + http_reuqest_pool(const char* addr, int count, int retry_inter = 0); + ~http_reuqest_pool(); + + /** + * 设置网络连接超时时间及网络 IO 读写超时时间(秒) + * @param conn_timeout {int} 连接超时时间 + * @param rw_timeout {int} 网络 IO 读写超时时间(秒) + * @return {http_request_pool&} + */ + http_reuqest_pool& set_timeout(int conn_timeout = 30, int rw_timeout = 60); + +protected: + // 基类纯虚函数 + virtual connect_client* create_connect(); + +private: + int conn_timeout_; + int rw_timeout_; +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/http/http_response.hpp b/lib_acl_cpp/include/acl_cpp/http/http_response.hpp new file mode 100644 index 000000000..0037160e5 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/http/http_response.hpp @@ -0,0 +1,130 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include "acl_cpp/http/http_header.hpp" + +namespace acl { + +class http_client; +class http_pipe; +class socket_stream; +class xml; +class json; + +class ACL_CPP_API http_response +{ +public: + /** + * 构造函数:通过该构造函数传入的 socket_stream 流对象并 + * 不会被关闭,需要调用者自己关闭 + * @param client {socket_stream*} 数据连接流,非空 + * 注:该类实例在长连接时可以被多次使用,但一定得注意使用 + * 顺序:get_body->response + */ + http_response(socket_stream* client); + virtual ~http_response(void); + + ////////////////////////////////////////////////////////////////////////// + // 与读取请求数据相关的方法 + + /** + * 读取 HTTP 请求客户端的 HTTP 请求头,在调用本方法后才可以调用 get_body + * @return {bool} 是否成功 + */ + bool read_header(); + + /** + * 读取 xml 格式的 HTTP 请求数据体,调用完此函数后应该调用 + * response 给客户端返回响应数据;该函数每次被调用时,内部的 + * 对象会被初始化,所以该函数可以在多个会话中被多次调用 + * @param out {xml&} 将 HTTP 请求体数据存储于该 xml 对象中 + * @param to_charset {const char*} 当该项非空,内部自动 + * 将数据转成该字符集存储于 xml 对象中 + * @return {bool} 是否正常 + * 注:必须首先调用 read_header 后才能调用本函数 + * 当请求数据体特别大时不应用此函数,以免内存耗光 + */ + bool get_body(xml& out, const char* to_charset = NULL); + + /** + * 读取 json 格式的 HTTP 请求数据体,调用完此函数后应该调用 + * response 给客户端返回响应数据;该函数每次被调用时,内部的 + * 对象会被初始化,所以该函数可以在多个会话中被多次调用 + * @param out {json&} 将 HTTP 请求体数据存储于该 json 对象中 + * @param to_charset {const char*} 当该项非空,内部自动 + * 将数据转成该字符集存储于 json 对象中 + * @return {bool} 是否正常 + * 注:必须首先调用 read_header 后才能调用本函数 + * 当请求数据体特别大时不应用此函数,以免内存耗光 + */ + bool get_body(json& out, const char* to_charset = NULL); + + /* + * 读取 HTTP 全部请求体数据并存储于输入的缓冲区中 + * @param out {string&} 存储请求数据体 + * @param to_charset {const char*} 当该项非空,内部自动 + * 将数据转成该字符集存储于 out 对象中 + * 注:当请求数据体特别大时不应用此函数,以免内存耗光 + * 必须首先调用 read_header 后才能调用本函数 + */ + bool get_body(string& out, const char* to_charset = NULL); + + /* + * 读取 HTTP 请求体数据并存储于输入的缓冲区中,可以循环 + * 调用本函数,直至数据读完了, + * @param buf {char*} 存储部分请求体数据 + * @param size {size_t} buf 缓冲区大小 + * @return {int} 返回值 == 0 表示正常读完毕,< 0 表示客户端 + * 关闭连接,> 0 表示已经读到的数据,用户应该一直读数据直到 + * 返回值 <= 0 为止 + * 注:该函数读到的是原始 HTTP 数据体数据,不做解压和字符集 + * 解码,用户自己根据需要进行处理 + * 必须首先调用 read_header 后才能调用本函数 + */ + int get_body(char* buf, size_t size); + + ////////////////////////////////////////////////////////////////////////// + // 与数据响应相关的方法函数 + + /** + * 获得 HTTP 响应头对象,然后在返回的 HTTP 响应头对象中添加 + * 自己的响应头字段或 http_header::reset()重置响应头状态, + * 参考:http_header 类 + * @return {http_header&} + */ + http_header& response_header(void); + + /** + * 向 HTTP 客户端发送响应数据,在调用本函数前,必须先调用 + * get_body 获得 HTTP 客户端的请求数据 + * @param body {const char*} 数据体地址 + * @param len {size_t} body 非空时表明 body 数据长度 + * @param status {int} HTTP 响应码:1xx, 2xx, 3xx, 4xx, 5xx + * @param keep_alive {bool} 是否与客户端保持长连接 + * @return {bool} 发送是否成功 + */ + bool response(const char* body, size_t len, + int status = 200, bool keep_alive = true); + + ////////////////////////////////////////////////////////////////////////// + + /** + * 获得 http_client HTTP 连接流,可以通过返回的对象获得 + * 客户端请求头的部分数据,参考:http_client 类 + * @return {http_client*} 当返回空时表示流出错了 + */ + http_client* get_client(void) const; + + /** + * 关闭 HTTP 连接流 + */ + void close(void); +protected: +private: + bool debug_; + bool header_ok_; + http_client* client_; + http_header header_; + http_pipe* get_pipe(const char* to_charset); +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/http/http_service.hpp b/lib_acl_cpp/include/acl_cpp/http/http_service.hpp new file mode 100644 index 000000000..9734cc73f --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/http/http_service.hpp @@ -0,0 +1,149 @@ +#pragma once +#include "acl_cpp/stream/aio_handle.hpp" +#include "acl_cpp/ipc/ipc_service.hpp" +#include "acl_cpp/http/http_header.hpp" + +namespace acl { + +class string; + +/** + * HTTP 服务请求类,子类必须继承该类 + */ +class ACL_CPP_API http_service_request : public http_header +{ +public: + /** + * 构造函数 + * @param domain {const char*} HTTP 服务器的域名(也可以是IP),非空 + * 如果传入了空值,则会 fatal + * @param port {unsigned short} HTTP 服务端口 + */ + http_service_request(const char* domain, unsigned short port); + + /** + * 获得由构造函数输入的 domain + * @return {const char*} 永不为空 + */ + const char* get_domain(void) const; + + /** + * 获得由构造函数输入的 port + * @return {unsigned short} + */ + unsigned short get_port(void) const; + + /** + * 当任务处理完毕或出错时,内部处理过程会自动调用 destroy 接口, + * 子类可以在该接口内进行一些释放过程,尤其当该对象是动态创建时, + * 子类应该在该函数内 delete this 以删除自己,因为该函数最终肯定 + * 会被调用,所以子类不应在其它地方进行析构操作 + */ + virtual void destroy(void) {} + + ////////////////////////////////////////////////////////////////////////// + // 子类必须实现如此虚接口 + + /** + * 获得 HTTP 请求体数据,该函数会在请求过程中被循环调用,直到返回的数据对象 + * 中的数据为空 + * @return {const string*} 请求体结果数据,如果返回空指针或返回的缓冲区对象 + * 的数据为空(即 string->empty()) 则表示 HTTP 请求体数据结束 + * 注意:与其它函数不同,该虚接口是另外的子线程中被调用的,所以如果子类实 + * 现了该接口,如果需要调用与原有线程具备竞争的资源时应该注意加锁保护 + */ + virtual const string* get_body(void); + + /** + * 当获得 HTTP 服务器的 HTTP 响应头时的回调接口 + * @param addr {const char*} 与服务器之间的连接地址,格式:IP:PORT + * @param hdr {const HTTP_HDR_RES*} HTTP 响应头,该结构定义参见: + * acl_project/lib_protocol/include/http/lib_http_struct.h + */ + virtual void on_hdr(const char* addr, const HTTP_HDR_RES* hdr) = 0; + + /** + * 当获得 HTTP 服务器的 HTTP 响应体时的回调接口,当 HTTP 响应体数据 + * 比较大时,该回调会被多次调用,直到出错(会调用 on_error)或数据读完 + * 时,该回调的两个参数均 0,当 data 及 dlen 均为 0 时,表明读 HTTP + * 响应体结束 + * @param data {const char*} 某次读操作时 HTTP 响应体数据 + * @param dlen {size_t} 某次读操作时 HTTP 响应体数据长度 + * 注:如果 HTTP 响应只有头数据而没有数据体,则也会调用该函数通知用户 + * HTTP 会话结束 + */ + virtual void on_body(const char* data, size_t dlen) = 0; + + /** + * 在 HTTP 请求或响应过程中如果出错,则会调用此接口,通知子类出错, + * 在调用此接口后 + * @param errnum {http_status_t} 出错码 + */ + virtual void on_error(http_status_t errnum) = 0; +protected: + virtual ~http_service_request(void); +private: + char* domain_; + unsigned short port_; +}; + +class aio_socket_stream; + +class ACL_CPP_API http_service : public ipc_service +{ +public: + /** + * 构造函数 + * @param nthread {int} 如果该值 > 1 则内部自动采用线程池,否则 + * 则是一个请求一个线程 + * @param nwait {int} 当异步引擎采用 ENGINE_WINMSG 时,为了避免 + * 因任务线程发送的数据消息过快而阻塞了主线程的 WIN32 消息循环, + * 在任务线程发送数据消息时自动休眠的毫秒数;对于其它异步引擎, + * 该值也可以用于限速功能 + * @param win32_gui {bool} 是否是窗口类的消息,如果是,则内部的 + * 通讯模式自动设置为基于 WIN32 的消息,否则依然采用通用的套接 + * 口通讯方式 + */ + http_service(int nthread = 1, int nwait = 1, bool win32_gui = false); + ~http_service(void); + + /** + * 应用调用此函数开始 HTTP 会话过程,由 http_service 类对象负责 + * 向服务器异步发出 HTTP 请求,同时异步读取来自于 HTTP 服务器的响应 + * @param req {http_service_request*} HTTP 请求类对象 + */ + void do_request(http_service_request* req); +protected: +#ifdef WIN32 + /** + * 基类虚函数,当收到来自于子线程的 win32 消息时的回调函数 + * @param hWnd {HWND} 窗口句柄 + * @param msg {UINT} 用户自定义消息号 + * @param wParam {WPARAM} 参数 + * @param lParam {LPARAM} 参数 + */ + virtual void win32_proc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); +#endif + /** + * 基类虚函数,当有新连接到达时基类回调此函数 + * @param client {aio_socket_stream*} 接收到的新的客户端连接 + */ + virtual void on_accept(aio_socket_stream* client); + + /** + * 基类虚函数,当监听流成功打开后的回调函数 + * @param addr {const char*} 实际的监听地址,格式:IP:PORT + */ + virtual void on_open(const char*addr); + + /** + * 基类虚函数,当监听流关闭时的回调函数 + */ + virtual void on_close(void); +private: + char* addr_; + int nwait_; + aio_handle_type handle_type_; +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/http/http_type.hpp b/lib_acl_cpp/include/acl_cpp/http/http_type.hpp new file mode 100644 index 000000000..7808fe90b --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/http/http_type.hpp @@ -0,0 +1,72 @@ +#pragma once + +namespace acl { + +struct HTTP_PARAM +{ + char* name; + char* value; +}; + +// HTTP 响应状态 +typedef enum +{ + HTTP_OK, // 一切正常 + HTTP_ERR_DNS, // 域名解析失败 + HTTP_ERR_CONN, // 连接服务器失败 + HTTP_ERR_REQ, // 创建请求协议失败 + HTTP_ERR_READ, // 读数据失败 + HTTP_ERR_SEND, // 写数据失败 + HTTP_ERR_TIMO, // 读写数据超时 + HTTP_ERR_READ_HDR, // 读 HTTP 响应头失败 + HTTP_ERR_READ_BODY, // 读 HTTP 响应体失败 + HTTP_ERR_INVALID_HDR, // HTTP 响应头无效 + HTTP_ERR_UNKNOWN, // 出现了未知错误 + HTTP_ERR_REDIRECT_MAX, // HTTP 响应头中重定向次数太多 +} http_status_t; + +// HTTP 请求方法 +typedef enum +{ + HTTP_METHOD_UNKNOWN, // 未知方法 + HTTP_METHOD_GET, // GET 方法 + HTTP_METHOD_POST, // POST 方法 + HTTP_METHOD_PUT, // PUT 方法 + HTTP_METHOD_CONNECT, // CONNECT 方法 + HTTP_METHOD_PURGE // PURGE 方法 +} http_method_t; + +typedef enum +{ + // Content-Type: application/x-www-form-urlencoded + HTTP_REQUEST_NORMAL, + + // Content-Type: multipart/form-data; boundary=xxx + HTTP_REQUEST_MULTIPART_FORM, + + // Content-Type: application/octet-stream + HTTP_REQUEST_OCTET_STREAM, + + // 其它类型 + HTTP_REQUEST_OTHER +} http_request_t; + +typedef enum +{ + // ok + HTTP_REQ_OK, + + // network io error + HTTP_REQ_ERR_IO, + + // invalid request method + HTTP_REQ_ERR_METHOD +} http_request_error_t; + +typedef enum +{ + HTTP_MIME_PARAM, // http mime 结点为参数类型 + HTTP_MIME_FILE // http mime 结点为文件类型 +} http_mime_t; + +} // namespace acl end diff --git a/lib_acl_cpp/include/acl_cpp/http/http_utils.hpp b/lib_acl_cpp/include/acl_cpp/http/http_utils.hpp new file mode 100644 index 000000000..88b966ad8 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/http/http_utils.hpp @@ -0,0 +1,22 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" + +namespace acl { + +class ACL_CPP_API http_utils +{ +public: + http_utils() {} + ~http_utils() {} + + /** + * 从完整的 url 中获得 WEB 服务器地址,格式:ip/domain:port + * @param url {const char*} HTTP url,非空 + * @param out {char*} 存储结果 + * @param size {size_t} out 缓冲区大小 + * @return {bool} 是否成功获得 + */ + static bool get_addr(const char* url, char* out, size_t size); +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/ipc/ipc_client.hpp b/lib_acl_cpp/include/acl_cpp/ipc/ipc_client.hpp new file mode 100644 index 000000000..968879f12 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/ipc/ipc_client.hpp @@ -0,0 +1,171 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include +#include "acl_cpp/stream/aio_socket_stream.hpp" + +namespace acl { + +typedef struct MSG_HDR +{ + int nMsg; + int dlen; +} MSG_HDR; + +typedef enum +{ + IO_WAIT_HDR, + IO_WAIT_DAT +} io_status; + +class aio_handle; +class ipc_adapter; +class aio_socket_stream; +class socket_stream; + +/** + * 异步IP消息类 + */ +class ACL_CPP_API ipc_client : private aio_open_callback +{ +public: + + ipc_client(); + virtual ~ipc_client(); + + /** + * 直接销毁接口,子类可以重载该接口 + */ + virtual void destroy() + { + delete this; + } + + /** + * 当调用 open 函数连接消息服务器成功时调用此函数 + */ + virtual void on_open() {} + + /** + * 当异步流关闭时的回调接口 + */ + virtual void on_close() {} + + /** + * 当收到消息时的回调函数,子类必须实现该接口 + * @param nMsg {int} 用户添加的自定义消息值 + * @param data {void*} 消息数据 + * @param dlen {int} 消息数据的长度 + */ + virtual void on_message(int nMsg, void* data, int dlen); + + /** + * 与消息服务器之间建立连接并创建异步流 + * @param handle {aio_handle*} 异步引擎句柄 + * @param addr {const char*} 消息服务器监听地址,格式为: + * IP:PORT(支持WIN32/UNIX),unix_path (仅支持UNIX) + * @param timeout {int} 连接超时时间 + */ + bool open(aio_handle* handle, const char* addr, int timeout); + + /** + * 异步流已经建立,调用此函数完成 ipc_client 连接过程 + * @param client {aio_socket_stream*} 异步连接流 + */ + void open(aio_socket_stream* client); + + /** + * 与消息服务器之间建立连接并创建同步流 + * @param addr {const char*} 消息服务器监听地址,格式为: + * IP:PORT(支持WIN32/UNIX),unix_path (仅支持UNIX) + * @param timeout {int} 连接超时时间 + */ + bool open(const char* addr, int timeout); + + /** + * 同步流已经建立,调用此函数完成 ipc_client 连接过程 + * @param client {socket_stream*} 异步连接流 + */ + void open(socket_stream* client); + + /** + * 消息流已经创建,调用此函数打开 IPC 通道 + */ + void wait(); + + /** + * 主动关闭消息流 + */ + void close(); + + /** + * 连接流是否正常打开着 + * @return {bool} + */ + bool active() const; + + /** + * 添加指定消息的回调过程对象 + * @param nMsg {int} 消息号 + */ + void append_message(int nMsg); + + /** + * 删除指定消息的回调过程对象 + * @param nMsg {int} 消息号 + */ + void delete_message(int nMsg); + + /** + * 发送消息 + * @param nMsg {int} 消息号 + * @param data {const void*} 数据 + * @param dlen {int} 数据长度 + */ + void send_message(int nMsg, const void* data, int dlen); + + /** + * 获得异步流句柄 + * @return {aio_socket_stream*} + */ + aio_socket_stream* get_async_stream() const; + + /** + * 获得异步引擎句柄 + */ + aio_handle& get_handle() const; + + /** + * 获得同步流够本 + * @return {socket_stream*} + */ + socket_stream* get_sync_stream() const; +protected: + /** + * 触发消息过程 + * @param nMsg {int} 消息ID + * @param data {void*} 接收到的消息数据地址 + * @param dlen {int} 接收到的消息数据长度 + */ + void trigger(int nMsg, void* data, int dlen); +private: + char* addr_; + std::list messages_; + aio_handle* handle_; + aio_socket_stream* async_stream_; + socket_stream* sync_stream_; + socket_stream* sync_stream_inner_; + bool closing_; + + io_status status_; + MSG_HDR hdr_; + + // 基类虚函数 + + virtual bool read_callback(char* data, int len); + virtual bool write_callback(); + virtual void close_callback(); + virtual bool timeout_callback(); + virtual bool open_callback(); +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/ipc/ipc_server.hpp b/lib_acl_cpp/include/acl_cpp/ipc/ipc_server.hpp new file mode 100644 index 000000000..8e3d34494 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/ipc/ipc_server.hpp @@ -0,0 +1,102 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include "acl_cpp/stream/aio_listen_stream.hpp" + +namespace acl { + +class aio_handle; +class aio_listen_stream; + +/** + * 异步消息服务端,纯虚类 + */ +class ACL_CPP_API ipc_server : private aio_accept_callback +{ +public: + ipc_server(); + + virtual ~ipc_server(); + + /** + * 打开异步监听服务流 + * @param handle {aio_handle*} 异步引擎句柄,非空 + * @param addr {const char*} 监听地址 + * @return {bool} 监听是否成功 + */ + bool open(aio_handle* handle, const char* addr = "127.0.0.1:0"); + + /** + * 当 open 成功后通过此函数获得监听地址 + * @return {const char*} 监听地址,格式为: IP:PORT + */ + const char* get_addr() const; + + /** + * 获得异步流句柄 + * @return {aio_listen_stream*} + */ + aio_listen_stream* get_stream() const; + + /** + * 获得异步引擎句柄 + */ + aio_handle& get_handle() const; + +protected: + /** + * 当监听流成功打开后的回调函数 + * @param addr {const char*} 实际的监听地址,格式:IP:PORT + */ + virtual void on_open(const char*addr) + { + (void) addr; + } + + /** + * 当监听流关闭时的回调函数 + */ + virtual void on_close() {} + + /** + * 当异步监听流获得一个客户端连接后的回调函数 + * @param client {aio_socket_stream*} 客户端 IPC 流 + */ + virtual void on_accept(aio_socket_stream* client) + { + (void) client; + } + +#ifdef WIN32 + /** + * 对于基于 WIN32 窗口消息的情况,当调用 open 时,则内部 + * 会自动调用 create_windows 过程 + */ + virtual bool create_window() + { + return false; + } +#endif + +private: + aio_handle* handle_; + aio_listen_stream* sstream_; + + /** + * 基类虚函数,当有新连接到达后调用此回调过程 + * @param client {aio_socket_stream*} 异步客户端流 + * @return {bool} 返回 true 以通知监听流继续监听 + */ + virtual bool accept_callback(aio_socket_stream* client); + + /** + * 基类虚函数,当监听流关闭时的回调过程 + */ + virtual void close_callback(); + + /** + * 基类虚函数,当监听流超时的回调过程 + */ + virtual bool timeout_callback(); +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/ipc/ipc_service.hpp b/lib_acl_cpp/include/acl_cpp/ipc/ipc_service.hpp new file mode 100644 index 000000000..c7ae2a943 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/ipc/ipc_service.hpp @@ -0,0 +1,121 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include "acl_cpp/stdlib/locker.hpp" +#include "acl_cpp/ipc/ipc_server.hpp" + +struct acl_pthread_pool_t; + +namespace acl { + +class ipc_client; + +class ACL_CPP_API ipc_request +{ +public: + ipc_request(); + virtual ~ipc_request(); + + /** + * 虚接口,子类实现此类用于处理具体的任务,该接口适用 + * 于采用 IO 消息的模式 + */ + virtual void run(ipc_client* ipc); + +#ifdef WIN32 + /** + * 虚接口,子类实现此类用于处理具体的任务,该接口适用 + * 于采用 WIN32 消息的模式 + */ + virtual void run(HWND hWnd); + + /** + * 设置 WIN32 窗口句柄 + * @param hWnd {HWND} 窗口句柄 + */ + void set_hwnd(HWND hWnd) + { + hWnd_ = hWnd; + } + + /** + * 获得 WIN32 窗口句柄 + * @return {HWND} 窗口句柄 + */ + HWND get_hwnd(void) const + { + return (hWnd_); + } +#endif +private: +#ifdef WIN32 + HWND hWnd_; +#endif +}; + +class ACL_CPP_API ipc_service : public ipc_server +{ +public: + /** + * 构造函数 + * @param nthread {int} 如果该值 > 1 则内部自动采用线程池,否则 + * 则是一个请求一个线程 + * @param ipc_keep {bool} 内部 IPC 消息流是否保持长连接,保持长 + * 连接有助于提高消息传递的效率 + */ + ipc_service(int nthread, bool ipc_keep = true); + + virtual ~ipc_service(); + +#ifdef WIN32 + /** + * 当采用 WIN32 消息模式时,子类需要实现此虚接口用于处理具体的 + * 消息过程,子类必须实现该接口 + * @param hWnd {HWND} 窗口句柄 + * @param msg {UINT} 用户自定义消息号 + * @param wParam {WPARAM} 参数 + * @param lParam {LPARAM} 参数 + */ + virtual void win32_proc(HWND hWnd, UINT msg, + WPARAM wParam, LPARAM lParam); +#endif + + /** + * 从 ipc 消息流连接池中取得一个连接 + * @return {ipc_client*} 返回 NULL 表示无法连接消息服务器 + */ + ipc_client* peek_conn(); + + /** + * 将用完的 ipc 消息连接放回连接池中 + * @param conn {ipc_client*} ipc 消息连接流 + */ + void push_conn(ipc_client* conn); +protected: + /** + * 子类调用此函数发送请求服务 + * @param req {ipc_request*} + */ + void request(ipc_request* req); +private: + bool ipc_keep_; + acl_pthread_pool_t* thread_pool_; +#ifdef WIN32 + HWND hWnd_; + HINSTANCE hInstance_; + + /** + * 基类虚函数:Windows 消息方式下,创建隐藏窗口句柄 + */ + virtual bool create_window(void); + + /** + * 基类虚函数:Windows 消息方式下,关闭隐藏窗口句柄 + */ + virtual void close_window(void); +#endif + + locker lock_; + std::list conn_pool_; +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/ipc/rpc.hpp b/lib_acl_cpp/include/acl_cpp/ipc/rpc.hpp new file mode 100644 index 000000000..cefd52aef --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/ipc/rpc.hpp @@ -0,0 +1,166 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include "acl_cpp/ipc/ipc_service.hpp" +#ifdef WIN32 + struct acl_pthread_mutex_t; + struct acl_pthread_cond_t; +#else +# include +# ifndef acl_pthread_mutex_t +# define acl_pthread_mutex_t pthread_mutex_t +# endif +# ifndef acl_pthread_cond_t +# define acl_pthread_cond_t pthread_cond_t +# endif +#endif + +namespace acl { + +class ipc_client; +class rpc_client; +class rpc_service; + +class rpc_request; +struct RPC_DAT +{ + rpc_request* req; + void* ctx; +}; + +class ACL_CPP_API rpc_request : public ipc_request +{ +public: + rpc_request(void); + virtual ~rpc_request(void); + +protected: + friend class rpc_client; + friend class rpc_service; + + /** + * 在主线程中被调用,子类必须实现此接口, + * 当子线程处理完请求任务后该接口将被调用,所以该类对象只能 + * 是当本接口调用后才能被释放,禁止在调用本接口前释放本类对象 + */ + virtual void rpc_onover(void) = 0; + + /** + * 虚接口:当子线程调用本对象的 rpc_signal 时,在主线程中会 + * 调用本接口,通知在任务未完成前(即调用 rpc_onover 前)收到 + * 子线程运行的中间状态信息;内部自动支持套接口或 WIN32 窗口 + * 消息;应用场景,例如,对于 HTTP 下载应用,在子线程中可以 + * 一边下载,一边向主线程发送(调用 rpc_signal 方法)下载进程, + * 则主线程会调用本类实例的此方法来处理此消息 + */ + virtual void rpc_wakeup(void* ctx) { (void) ctx; } + +protected: + /** + * 在子线程中被调用,子类必须实现此接口,用于处理具体任务 + */ + virtual void rpc_run(void) = 0; + + /** + * 在子线程中被调用,内部自动支持套接口或 WIN32 窗口消息 + * 子类实例的 rpc_run 方法中可以多次调用此方法向主线程的 + * 本类实例发送消息,主线程中调用本对象 rpc_wakeup 方法 + * @param ctx {void*} 传递的参数指针,一般应该是动态地址 + * 比较好,这样可以避免同一个参数被重复覆盖的问题 + */ + void rpc_signal(void* ctx); + + /** + * 当子线程调用 rpc_signal 给主线程后,调用本方法可以等待 + * 主线程发来下一步指令 + * @param timeout {int} 等待超时时间(毫秒),当该值为 0 时 + * 则采用非阻塞等待模式,当该值为 < 0 时,则采用完全阻塞 + * 等待模式(即一直等到主线程发送 cond_signal 通知),当该 + * 值 > 0 时,则等待的最大超时时间为 timeout 毫秒 + * @return {bool} 返回 true 表示收到主线程发来的通知信号, + * 否则,需要调用 cond_wait_timeout 判断是否是超时引起的 + */ + bool cond_wait(int timeout = -1); + + /** + * 当 cond_wait 返回 false 时,应用应该调用本方法判断是否 + * 是因为等待超时引起的 + * @return {bool} 是否是等待超时 + */ + bool cond_wait_timeout() const + { + return wait_timedout_; + } + + /** + * 当子线程调用 cond_wait 时,在主线程中调用本方法通知子线程 + * “醒来” + * @return {bool} 当有子线程调用 cond_wait 时本函数通知子线程 + * “醒来”并且返回 true,否则返回 false + */ + bool cond_signal(void); + +private: + RPC_DAT dat_; + ipc_client* ipc_; + int cond_count_; + acl_pthread_mutex_t* lock_; + acl_pthread_cond_t* cond_; + bool wait_timedout_; + + // 基类 ipc_request 虚函数,在子线程中被调用 + virtual void run(ipc_client* ipc); +#ifdef WIN32 + /** + * 虚接口,子类实现此类用于处理具体的任务,该接口适用 + * 于采用 WIN32 消息的模式 + * @param hWnd {HWND} WIN2 窗口句柄 + */ + virtual void run(HWND hWnd); +#endif +}; + +////////////////////////////////////////////////////////////////////////// + +class aio_socket_stream; + +class ACL_CPP_API rpc_service : public ipc_service +{ +public: + /** + * 构造函数 + * @param nthread {int} 如果该值 > 1 则内部自动采用线程池,否则 + * 则是一个请求一个线程 + * @param ipc_keep {bool} 内部 IPC 消息流是否保持长连接,保持长 + * 连接有助于提高消息传递的效率 + */ + rpc_service(int nthread, bool ipc_keep = true) + : ipc_service(nthread, ipc_keep) {} + ~rpc_service(void) {} + + /** + * 主线程中运行:将请求任务放入子线程池的任务请求队列中,当线程池 + * 中的一个子线程接收到该任务后便调用 rpc_request::rpc_run 方法调 + * 用子类的方法,当任务处理完毕后给主线程发消息,在主线程中再调用 + * rpc_request::rpc_callback + * @param req {rpc_request*} rpc_request 子类实例,非空 + */ + void rpc_fork(rpc_request* req); + +private: + // 基类虚函数:主线程对象接收到子线程消息的 + // ipc 连接请求时的回调函数 + virtual void on_accept(aio_socket_stream* client); + +#ifdef WIN32 + /** + * 基类虚函数,当收到来自于子线程的 win32 消息时的回调函数 + * @param hWnd {HWND} 窗口句柄 + * @param msg {UINT} 用户自定义消息号 + * @param wParam {WPARAM} 参数 + * @param lParam {LPARAM} 参数 + */ + virtual void win32_proc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); +#endif +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/lib_acl.hpp b/lib_acl_cpp/include/acl_cpp/lib_acl.hpp new file mode 100644 index 000000000..7abfa8adb --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/lib_acl.hpp @@ -0,0 +1,116 @@ +#pragma once + +#include "acl_cpp/acl_cpp_define.hpp" +#include "acl_cpp/acl_cpp_init.hpp" +#include "acl_cpp/acl_cpp_test.hpp" + +#include "acl_cpp/stdlib/noncopyable.hpp" +#include "acl_cpp/stdlib/singleton.hpp" +#include "acl_cpp/stdlib/snprintf.hpp" +#include "acl_cpp/stdlib/dns_service.hpp" +#include "acl_cpp/stdlib/final_tpl.hpp" +#include "acl_cpp/stdlib/json.hpp" +#include "acl_cpp/stdlib/locker.hpp" +#include "acl_cpp/stdlib/log.hpp" +//#include "malloc.hpp" +#include "acl_cpp/stdlib/pipe_stream.hpp" +#include "acl_cpp/stdlib/string.hpp" +#include "acl_cpp/stdlib/util.hpp" +#include "acl_cpp/stdlib/xml.hpp" +#include "acl_cpp/stdlib/zlib_stream.hpp" +#include "acl_cpp/stdlib/md5.hpp" +#include "acl_cpp/stdlib/charset_conv.hpp" +#include "acl_cpp/stdlib/escape.hpp" +#include "acl_cpp/stdlib/pipe_stream.hpp" +#include "acl_cpp/stdlib/url_coder.hpp" + +#include "acl_cpp/memcache/memcache.hpp" +#include "acl_cpp/memcache/memcache_pool.hpp" + +#include "acl_cpp/session/session.hpp" +#include "acl_cpp/session/memcache_session.hpp" + +#include "acl_cpp/stream/stream.hpp" +#include "acl_cpp/stream/istream.hpp" +#include "acl_cpp/stream/ostream.hpp" +#include "acl_cpp/stream/fstream.hpp" +#include "acl_cpp/stream/ifstream.hpp" +#include "acl_cpp/stream/ofstream.hpp" +#include "acl_cpp/stream/socket_stream.hpp" +#include "acl_cpp/stream/server_socket.hpp" +#include "acl_cpp/stream/ssl_stream.hpp" + +#include "acl_cpp/stream/aio_handle.hpp" +#include "acl_cpp/stream/aio_stream.hpp" +#include "acl_cpp/stream/aio_istream.hpp" +#include "acl_cpp/stream/aio_ostream.hpp" +#include "acl_cpp/stream/aio_listen_stream.hpp" +#include "acl_cpp/stream/aio_socket_stream.hpp" +#include "acl_cpp/stream/aio_fstream.hpp" + +#include "acl_cpp/ipc/ipc_client.hpp" +#include "acl_cpp/ipc/ipc_server.hpp" +#include "acl_cpp/ipc/ipc_service.hpp" +#include "acl_cpp/ipc/rpc.hpp" + +#include "acl_cpp/http/http_client.hpp" +#include "acl_cpp/http/http_header.hpp" +#include "acl_cpp/http/http_pipe.hpp" +#include "acl_cpp/http/http_request.hpp" +#include "acl_cpp/http/http_response.hpp" +#include "acl_cpp/http/http_service.hpp" +#include "acl_cpp/http/http_mime.hpp" +#include "acl_cpp/http/HttpCookie.hpp" +#include "acl_cpp/http/HttpServlet.hpp" +#include "acl_cpp/http/HttpSession.hpp" +#include "acl_cpp/http/HttpServletRequest.hpp" +#include "acl_cpp/http/HttpServletResponse.hpp" +#include "acl_cpp/http/http_download.hpp" +#include "acl_cpp/http/http_utils.hpp" +#include "acl_cpp/http/http_request_pool.hpp" + +#include "acl_cpp/db/db_handle.hpp" +#include "acl_cpp/db/db_mysql.hpp" +#include "acl_cpp/db/db_pool.hpp" +#include "acl_cpp/db/mysql_pool.hpp" +#include "acl_cpp/db/sqlite_pool.hpp" +#include "acl_cpp/db/db_service.hpp" +#include "acl_cpp/db/db_service_mysql.hpp" +#include "acl_cpp/db/db_service_sqlite.hpp" +#include "acl_cpp/db/db_sqlite.hpp" + +#include "acl_cpp/hsocket/hspool.hpp" +#include "acl_cpp/hsocket/hsclient.hpp" +#include "acl_cpp/hsocket/hstable.hpp" +#include "acl_cpp/hsocket/hsrow.hpp" + +#include "acl_cpp/beanstalk/beanstalk.hpp" +#include "acl_cpp/beanstalk/beanstalk_pool.hpp" + +#include "acl_cpp/mime/mime_define.hpp" +#include "acl_cpp/mime/mime_attach.hpp" +#include "acl_cpp/mime/mime_base64.hpp" +#include "acl_cpp/mime/mime_body.hpp" +#include "acl_cpp/mime/mime_code.hpp" +#include "acl_cpp/mime/mime_head.hpp" +#include "acl_cpp/mime/mime.hpp" +#include "acl_cpp/mime/mime_image.hpp" +#include "acl_cpp/mime/mime_node.hpp" +#include "acl_cpp/mime/mime_quoted_printable.hpp" +#include "acl_cpp/mime/mime_uucode.hpp" +#include "acl_cpp/mime/mime_xxcode.hpp" +#include "acl_cpp/mime/rfc2047.hpp" +#include "acl_cpp/mime/rfc822.hpp" + +#include "acl_cpp/master/master_threads.hpp" +#include "acl_cpp/master/master_aio.hpp" +#include "acl_cpp/master/master_proc.hpp" +#include "acl_cpp/master/master_trigger.hpp" +#include "acl_cpp/master/master_conf.hpp" + +#include "acl_cpp/queue/queue_manager.hpp" +#include "acl_cpp/queue/queue_file.hpp" + +#include "acl_cpp/connpool/connect_client.hpp" +#include "acl_cpp/connpool/connect_pool.hpp" +#include "acl_cpp/connpool/connect_manager.hpp" diff --git a/lib_acl_cpp/include/acl_cpp/master/master_aio.hpp b/lib_acl_cpp/include/acl_cpp/master/master_aio.hpp new file mode 100644 index 000000000..0810c4a3d --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/master/master_aio.hpp @@ -0,0 +1,82 @@ +#pragma once +#include "acl_cpp/stream/aio_handle.hpp" +#include "acl_cpp/stream/aio_listen_stream.hpp" +#include "acl_cpp/master/master_base.hpp" + +namespace acl { + +class aio_handle; +class aio_socket_stream; + +/** + * acl_master 服务器框架中单线程非阻塞方式的模板类,该类对象只能有一个实例运行 + */ +class ACL_CPP_API master_aio : public master_base, + public aio_accept_callback +{ +public: + /** + * 开始运行,调用该函数是指该服务进程是在 acl_master 服务框架 + * 控制之下运行,一般用于生产机状态 + * @param argc {int} 从 main 中传递的第一个参数,表示参数个数 + * @param argv {char**} 从 main 中传递的第二个参数 + */ + void run_daemon(int argc, char** argv); + + /** + * 在单独运行时的处理函数,用户可以调用此函数进行一些必要的调试工作 + * @param addr {const char*} 服务监听地址 + * @param path {const char*} 配置文件全路径 + * @param ht {aio_handle_type} 事件引擎的类型 + * @return {bool} 监听是否成功 + */ + bool run_alone(const char* addr, const char* path = NULL, + aio_handle_type ht = ENGINE_SELECT); + + /** + * 获得异步IO的事件引擎句柄,通过此句柄,用户可以设置定时器等功能 + * @return {aio_handle*} + */ + aio_handle* get_handle() const; + + /** + * 在 run_alone 模式下,通知服务器框架关闭引擎,退出程序 + */ + void stop(); +protected: + master_aio(); + virtual ~master_aio(); + + /** + * 纯虚函数:当接收到一个客户端连接时调用此函数 + * @param stream {aio_socket_stream*} 新接收到的客户端异步流对象 + * @return {bool} 该函数如果返回 false 则通知服务器框架不再接收 + * 远程客户端连接,否则继续接收客户端连接 + */ + virtual bool on_accept(aio_socket_stream* stream) = 0; +private: + /** + * 基类 aio_accept_callback 的虚函数实现 + * @param client {aio_socket_stream*} 异步客户端流 + * @return {bool} 返回 true 以通知监听流继续监听 + */ + virtual bool accept_callback(aio_socket_stream* client); +private: +#ifdef WIN32 + // 当接收到一个客户端连接时回调此函数 + static int service_main(SOCKET, void*); +#else + static int service_main(int, void*); +#endif + + // 当进程切换用户身份后调用的回调函数 + static void service_pre_jail(void*); + + // 当进程切换用户身份后调用的回调函数 + static void service_init(void*); + + // 当进程退出时调用的回调函数 + static void service_exit(void*); +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/master/master_base.hpp b/lib_acl_cpp/include/acl_cpp/master/master_base.hpp new file mode 100644 index 000000000..d3801913b --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/master/master_base.hpp @@ -0,0 +1,68 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include "acl_cpp/master/master_conf.hpp" + +namespace acl +{ + +class ACL_CPP_API master_base +{ +public: + /** + * 设置 bool 类型的配置项 + * @param table {master_bool_tbl*} + */ + void set_cfg_bool(master_bool_tbl* table); + + /** + * 设置 int 类型的配置项 + * @param table {master_int_tbl*} + */ + void set_cfg_int(master_int_tbl* table); + + /** + * 设置 int64 类型的配置项 + * @param table {master_int64_tbl*} + */ + void set_cfg_int64(master_int64_tbl* table); + + /** + * 设置 字符串 类型的配置项 + * @param table {master_str_tbl*} + */ + void set_cfg_str(master_str_tbl* table); + + /** + * 判断是否是由 acl_master 控制的 daemon 模式 + * @return {bool} + */ + bool daemon_mode(void) const; +protected: + bool daemon_mode_; + bool proc_inited_; + + master_base(); + virtual ~master_base(); + + /** + * 当进程切换用户身份前调用的回调函数,可以在此函数中做一些 + * 用户身份为 root 的权限操作 + */ + virtual void proc_pre_jail() {} + + /** + * 当进程切换用户身份后调用的回调函数,此函数被调用时,进程 + * 的权限为普通受限级别 + */ + virtual void proc_on_init() {} + + /** + * 当进程退出前调用的回调函数 + */ + virtual void proc_on_exit() {} + + // 配置对象 + master_conf conf_; +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/master/master_conf.hpp b/lib_acl_cpp/include/acl_cpp/master/master_conf.hpp new file mode 100644 index 000000000..3a899c3fe --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/master/master_conf.hpp @@ -0,0 +1,122 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" + +struct ACL_XINETD_CFG_PARSER; +struct ACL_CFG_INT_TABLE; +struct ACL_CFG_INT64_TABLE; +struct ACL_CFG_STR_TABLE; +struct ACL_CFG_BOOL_TABLE; + +namespace acl { + +typedef struct master_int_tbl +{ + const char *name; + int defval; + int *target; + int min; + int max; +} master_int_tbl; + +typedef struct master_str_tbl +{ + const char *name; + const char *defval; + char **target; +} master_str_tbl; + +typedef struct master_bool_tbl +{ + const char *name; + int defval; + int *target; +} master_bool_tbl; + +typedef struct master_int64_tbl +{ + const char *name; +#ifdef WIN32 + __int64 defval; + __int64 *target; + __int64 min; + __int64 max; +#else + long long int defval; + long long int *target; + long long int min; + long long int max; +#endif +} master_int64_tbl; + +class master_base; + +class master_conf +{ +public: + master_conf(); + ~master_conf(); + + /** + * 设置 bool 类型的配置项 + * @param table {master_bool_tbl*} + */ + void set_cfg_bool(master_bool_tbl* table); + + /** + * 设置 int 类型的配置项 + * @param table {master_int_tbl*} + */ + void set_cfg_int(master_int_tbl* table); + + /** + * 设置 int64 类型的配置项 + * @param table {master_int64_tbl*} + */ + void set_cfg_int64(master_int64_tbl* table); + + /** + * 设置 字符串 类型的配置项 + * @param table {master_str_tbl*} + */ + void set_cfg_str(master_str_tbl* table); + + /** + * 加载配置文件 + * @param path {const char*} 配置文件全路径 + */ + void load(const char* path); + + /** + * 重置配置解析器状态,释放之前分配的资源,调用此函数后, + * 之前获得的字符串配置项的内存将会被释放,所以禁止再用; + * 调用该函数后,则该配置解析器对象可以再次使用解析其它 + * 配置文件 + */ + void reset(void); + + ACL_CFG_INT_TABLE* get_int_cfg() const; + ACL_CFG_INT64_TABLE* get_int64_cfg() const; + ACL_CFG_STR_TABLE* get_str_cfg() const; + ACL_CFG_BOOL_TABLE* get_bool_cfg() const; +protected: +private: + bool cfg_loaded_; + + ACL_XINETD_CFG_PARSER* cfg_; + ACL_CFG_INT_TABLE* int_cfg_; + ACL_CFG_INT64_TABLE* int64_cfg_; + ACL_CFG_STR_TABLE* str_cfg_; + ACL_CFG_BOOL_TABLE* bool_cfg_; + + master_int_tbl* int_tbl_; + master_str_tbl* str_tbl_; + master_bool_tbl* bool_tbl_; + master_int64_tbl* int64_tbl_; + + void load_str(void); + void load_bool(void); + void load_int(void); + void load_int64(void); +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/master/master_proc.hpp b/lib_acl_cpp/include/acl_cpp/master/master_proc.hpp new file mode 100644 index 000000000..b0e3b994b --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/master/master_proc.hpp @@ -0,0 +1,57 @@ +#pragma once +#include "acl_cpp/master/master_base.hpp" + +struct ACL_VSTREAM; + +namespace acl { + +class socket_stream; + +/** + * acl_master 服务器框架中进程方式的模板类,该类对象只能有一个实例运行 + */ +class ACL_CPP_API master_proc : public master_base +{ +public: + /** + * 开始运行,调用该函数是指该服务进程是在 acl_master 服务框架 + * 控制之下运行,一般用于生产机状态 + * @param argc {int} 从 main 中传递的第一个参数,表示参数个数 + * @param argv {char**} 从 main 中传递的第二个参数 + */ + void run_daemon(int argc, char** argv); + + /** + * 在单独运行时的处理函数,用户可以调用此函数进行一些必要的调试工作 + * @param addr {const char*} 服务监听地址 + * @param path {const char*} 配置文件全路径 + * @param count {int} 当该值 > 0 时,则接收的连接次数达到此值且完成 + * 后,该函数将返回,否则一直循环接收远程连接 + * @return {bool} 监听是否成功 + */ + bool run_alone(const char* addr, const char* path = NULL, int count = 1); +protected: + master_proc(); + virtual ~master_proc(); + + /** + * 纯虚函数:当接收到一个客户端连接时调用此函数 + * @param stream {aio_socket_stream*} 新接收到的客户端异步流对象 + * 注:该函数返回后,流连接将会被关闭,用户不应主动关闭该流 + */ + virtual void on_accept(socket_stream* stream) = 0; +private: + // 当接收到一个客户端连接时回调此函数 + static void service_main(ACL_VSTREAM *stream, char *service, char **argv); + + // 当进程切换用户身份后调用的回调函数 + static void service_pre_jail(char* service, char** argv); + + // 当进程切换用户身份后调用的回调函数 + static void service_init(char* service, char** argv); + + // 当进程退出时调用的回调函数 + static void service_exit(char* service, char** argv); +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/master/master_threads.hpp b/lib_acl_cpp/include/acl_cpp/master/master_threads.hpp new file mode 100644 index 000000000..f3ab57cf9 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/master/master_threads.hpp @@ -0,0 +1,154 @@ +#pragma once +#include "acl_cpp/master/master_base.hpp" + +struct ACL_VSTREAM; + +namespace acl { + +class socket_stream; + +/** + * 线程池服务器框架类,该类为纯虚类,子类需要实现其中的纯虚函数, + * 每一个进程仅能有一个该类对象实例,否则程序会被终止 + */ +class ACL_CPP_API master_threads : public master_base +{ +public: + /** + * 开始运行,调用该函数是指该服务进程是在 acl_master 服务框架 + * 控制之下运行,一般用于生产机状态 + * @param argc {int} 从 main 中传递的第一个参数,表示参数个数 + * @param argv {char**} 从 main 中传递的第二个参数 + */ + void run_daemon(int argc, char** argv); + + /** + * 在单独运行时的处理函数,用户可以调用此函数进行一些必要的调试工作 + * @param addr {const char*} 服务监听地址 + * @param path {const char*} 配置文件全路径 + * @param count {unsigned int} 循环服务的次数,达到此值后函数自动返回; + * 若该值为 0 则表示程序一直循环处理外来请求而不返回 + * @param threads_count {int} 当该值大于 1 时表示自动采用线程池方式, + * 该值只有当 count != 1 时才有效,即若 count == 1 则仅运行一次就返回 + * 且不会启动线程处理客户端请求 + * @return {bool} 监听是否成功 + */ + bool run_alone(const char* addr, const char* path = NULL, + unsigned int count = 1, int threads_count = 1); +protected: + // 该类不能直接被实例化 + master_threads(); + virtual ~master_threads() {} + + /** + * 纯虚函数:当某个客户端连接有数据可读或关闭或出错时调用此函数 + * @param stream {socket_stream*} + * @return {bool} 返回 false 则表示当函数返回后需要关闭连接, + * 否则表示需要保持长连接,如果该流出错,则应用应该返回 false + */ + virtual bool thread_on_read(socket_stream* stream) = 0; + + /** + * 当线程池中的某个线程获得一个连接时的回调函数, + * 子类可以做一些初始化工作 + * @param stream {socket_stream*} + * @return {bool} 如果返回 false 则表示子类要求关闭连接,而不 + * 必将该连接再传递至 thread_main 过程 + * 注:当本函数返回 false 流关闭时并不调用 thread_on_close 过程 + */ + virtual bool thread_on_accept(socket_stream* stream) { (void) stream; return true; } + + /** + * 当某个网络连接的 IO 读写超时时的回调函数,如果该函数返回 true 则表示继续等待下一次 + * 读写,否则则希望关闭该连接 + * @param stream {socket_stream*} + * @return {bool} 如果返回 false 则表示子类要求关闭连接,否则则要求继续监听该连接 + */ + virtual bool thread_on_timeout(socket_stream* stream) { (void) stream; return false; } + + /** + * 当与某个线程绑定的连接关闭时的回调函数 + * @param stream {socket_stream*} + * 注:当在 thread_on_accept 返回 false 后流关闭时该函数并不会 + * 被调用 + */ + virtual void thread_on_close(socket_stream* stream) { (void) stream; } + + /** + * 当线程池中一个新线程被创建时的回调函数 + */ + virtual void thread_on_init() {} + + /** + * 当线程池中一个线程退出时的回调函数 + */ + virtual void thread_on_exit() {} +public: + /** + * 设置进程级别的定时器,该定时器只有当 proc_on_init 回调过程中 + * 被设置才会生效且该定时器仅被调用一次,如果需要循环定时器,则 + * 需要在定时器内再次设置 + * @param callback {void (*)(int, void*)} 定时器回调函数 + * @param ctx {void*} callback 被调用时的第二个参数 + * @param delay {int} 定时器被循环触发的时间间隔(秒) + */ + static void proc_set_timer(void (*callback)(int, void*), void* ctx, int delay); + + /** + * 删除进程级别的定时器 + * @param callback {void (*)(int, void*)} 定时器回调函数 + * @param ctx {void*} callback 被调用时的第二个参数 + */ + static void proc_del_timer(void (*callback)(int, void*), void* ctx); +private: + // 处理客户端请求 + void do_serivce(ACL_VSTREAM* client); + + // 仅运行一次 + void run_once(ACL_VSTREAM* sstream); + + // 线程开始创建后的回调函数 + static int thread_begin(void* arg); + + // 线程结束运行前的回调函数 + static void thread_finish(void* arg); + + // 多线程情况下的处理函数 + static void thread_run(void* arg); + + // 多线程方式并行处理 + void run_parallel(ACL_VSTREAM* sstream, unsigned int count, + int threads_count); + + // 单线程方式串行处理 + void run_serial(ACL_VSTREAM* sstream, unsigned int count); + + // 当接收到一个客户端连接时回调此函数 + static int service_main(ACL_VSTREAM*, void*); + + // 当接收到一个客户连接时的回调函数,可以进行一些初始化 + static int service_on_accept(ACL_VSTREAM*); + + // 当客户端连接读写超时时的回调函数 + static int service_on_timeout(ACL_VSTREAM*, void*); + + // 当客户端连接关闭时的回调函数 + static void service_on_close(ACL_VSTREAM*, void*); + + // 当进程切换用户身份后调用的回调函数 + static void service_pre_jail(void*); + + // 当进程切换用户身份后调用的回调函数 + static void service_init(void*); + + // 当进程退出时调用的回调函数 + static void service_exit(void*); + + // 当线程创建后调用的回调函数 + static void thread_init(void*); + + // 当线程退出前调用的回调函数 + static void thread_exit(void*); +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/master/master_trigger.hpp b/lib_acl_cpp/include/acl_cpp/master/master_trigger.hpp new file mode 100644 index 000000000..db048e4c6 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/master/master_trigger.hpp @@ -0,0 +1,50 @@ +#pragma once +#include "acl_cpp/master/master_base.hpp" + +namespace acl { + +/** + * acl_master 服务器框架中触发器的模板类,该类对象只能有一个实例运行 + */ +class ACL_CPP_API master_trigger : public master_base +{ +public: + /** + * 开始运行,调用该函数是指该服务进程是在 acl_master 服务框架 + * 控制之下运行,一般用于生产机状态 + * @param argc {int} 从 main 中传递的第一个参数,表示参数个数 + * @param argv {char**} 从 main 中传递的第二个参数 + */ + void run_daemon(int argc, char** argv); + + /** + * 在单独运行时的处理函数,用户可以调用此函数进行一些必要的调试工作 + * @param path {const char*} 配置文件全路径 + * @param count {int} 当该值 > 0 时,则接收的连接次数达到此值且完成 + * 后,该函数将返回,否则一直循环接收远程连接 + * @param interval {int} 触发器时间间隔(秒) + */ + void run_alone(const char* path = NULL, int count = 1, int interval = 1); +protected: + master_trigger(); + virtual ~master_trigger(); + + /** + * 当触发器时间到时调用此函数 + */ + virtual void on_trigger() = 0; +private: + // 当触发器时间到时由 acl_master 框架回调此函数 + static void service_main(char*, int, char*, char**); + + // 当进程切换用户身份后调用的回调函数 + static void service_pre_jail(char*, char**); + + // 当进程切换用户身份后调用的回调函数 + static void service_init(char*, char**); + + // 当进程退出时调用的回调函数 + static void service_exit(char*, char**); +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/memcache/memcache.hpp b/lib_acl_cpp/include/acl_cpp/memcache/memcache.hpp new file mode 100644 index 000000000..23a5898af --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/memcache/memcache.hpp @@ -0,0 +1,197 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include +#include "acl_cpp/connpool/connect_client.hpp" +#include "acl_cpp/stdlib/string.hpp" +#include "acl_cpp/mime/rfc2047.hpp" + +namespace acl { + +class socket_stream; + +typedef class memcache mem_cache; + +/** + * memcached 客户端通信协议库,支持长连接与自动重连 + */ +class ACL_CPP_API memcache : public connect_client +{ +public: + /** + * 构造函数 + * @param addr {const char*} memcached 服务器监听地址,格式为: + * ip:port,如: 127.0.0.1:11211 + * @param conn_timeout {int} 连接超时时间(秒) + * @param rw_timeout {int} IO 读写超时时间(秒) + */ + memcache(const char* addr = "127.0.0.1:11211", + int conn_timeout = 180, int rw_timeout = 300); + + ~memcache(); + + /** + * 设置 key 的前缀,即实际的 key 将由 该前缀+原始key 组成,缺省时不设前缀, + * 当多个应用共用同一个 memcached 服务时,建议应用设置自身的 key 前缀,这样 + * 可以避免与其它应用的 key 产生重复问题 + * @param keypre {const char*} 非空时设置 key 前缀,否则取消 key 前缀 + * @return {memcache&} + */ + memcache& set_prefix(const char* keypre); + + /** + * 在保持的长连接中断时是否要求自动重连,缺省为自动重连 + * @param onoff {bool} 为 true 时表示长连接意外断开后自动重连 + * @return {memcache&} + */ + memcache& auto_retry(bool onoff); + + /** + * 设置是否针对 KEY 键值进行编码,缺少时不对 key 编码,当应用的 key 中可能 + * 会有特殊字符或二进制值时,建议调用此函数对 key 进行编码 + * @parma onoff {bool} 为 true 表示内部需要对 key 进行编码 + * @return {memcache&} + */ + memcache& encode_key(bool onoff); + + /** + * 向 memcached 中修改或添加新的数据缓存对象 + * @param key {const char*} 键值 + * @param klen {size_t} key 键值长度 + * @param dat {const void*} 数据 + * @param dlen {size_t} data 数据长度 + * @param timeout {time_t} 缓存超时时间(秒) + * @param flags {unsigned short} 附属的标志位 + * @return {bool} 是否成功 + */ + bool set(const char* key, size_t klen, + const void* dat, size_t dlen, + time_t timeout = 0, unsigned short flags = 0); + + /** + * 向 memcached 中修改或添加新的数据缓存对象 + * @param key {const char*} 字符串键值 + * @param dat {const void*} 数据 + * @param dlen {size_t} data 数据长度 + * @param timeout {time_t} 缓存超时时间(秒) + * @param flags {unsigned short} 附属的标志位 + * @return {bool} 是否成功 + */ + bool set(const char* key, const void* dat, size_t dlen, + time_t timeout = 0, unsigned short flags = 0); + + /** + * 更新 memcached 中已经存在的键的过期日期,因为目前 libmemcached 没有 + * 提供此接口,所以该函数实现的方式是先调用 get 取出对应键的值,然后再 + * 调用 set 重新设置该键的值及过期时间 + * @param key {const char*} 键值 + * @param klen {size_t} key 键值长度 + * @param timeout {time_t} 过期时间(秒) + * @return {bool} 是否成功 + */ + bool set(const char* key, size_t klen, time_t timeout = 0); + + /** + * 更新 memcached 中已经存在的键的过期日期,因为目前 libmemcached 没有 + * 提供此接口,所以该函数实现的方式是先调用 get 取出对应键的值,然后再 + * 调用 set 重新设置该键的值及过期时间 + * @param key {const char*} 字符串键值 + * @param timeout {time_t} 过期时间(秒) + * @return {bool} 是否成功 + */ + bool set(const char* key, time_t timeout = 0); + + /** + * 从 memcached 中获得对应键值的缓存数据 + * @param key {const char*} 字符串键值 + * @param klen {size_t} 键值长度 + * @param buf {string&} 存储结果的缓冲区,内部首先会清空该缓冲区 + * @param flags {unsigned short*} 存储附属的标志位 + * @return {bool} 返回 true 表示正确获得结果值,否则表示键值对应的 + * 数据不存在或出错 + */ + bool get(const char* key, size_t klen, string& buf, + unsigned short* flags = NULL); + + /** + * 从 memcached 中获得对应键值的缓存数据 + * @param key {const char*} 字符串键值 + * @param buf {string&} 存储结果的缓冲区,内部首先会清空该缓冲区 + * @param flags {unsigned short*} 存储附属的标志位 + * @return {bool} 返回 true 表示正确获得结果值,否则表示键值对应的 + * 数据不存在或出错 + */ + bool get(const char* key, string& buf, unsigned short* flags = NULL); + + /** + * 从 memcached 中删除数据 + * @param key {const char*} 键值 + * @param klen {size_t} 键值长度 + * @return {bool} 删除是否成功 + */ + bool del(const char* key, size_t klen); + + /** + * 从 memcached 中删除数据 + * @param key {const char*} 字符串键值 + * @return {bool} 删除是否成功 + */ + bool del(const char* key); + + /** + * 获得上次操作 memcached 错误描述信息 + * @return {const char*} 错误描述信息,永不为空 + */ + const char* last_serror() const; + + /** + * 获得上次操作 memcached 的错误号 + * @return {int} 错误号 + */ + int last_error() const; + + /** + * 打开与 memcached 的连接, 因为 set/get/del 操作都会自动打开与 + * memcached 的连接,所以不必显示地调用此函数来打开与 memcached + * 的连接 + * @return {bool} 打开是否成功 + */ + virtual bool open(); + + /** + * 关闭与 memcached 的连接,一般该函数不需要调用,因为类对象在 + * 析构时会自动调用此函数 + */ + void close(); + + /** + * 列出 memcached 连接的一些属性,调试用 + */ + void property_list(); + +private: + bool set(const string& key, const void* dat, size_t dlen, + time_t timeout, unsigned short flags); + bool get(const string& key, string& buf, unsigned short* flags); + const string& get_key(const char* key, size_t klen); + + string* keypre_; + rfc2047 coder_; + int conn_timeout_; + int rw_timeout_; + bool encode_key_; + + bool opened_; + bool retry_; + char* addr_; + char* ip_; + int port_; + int enum_; + string ebuf_; + string kbuf_; + + socket_stream* conn_; + string line_; + bool error_happen(const char* line); +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/memcache/memcache_pool.hpp b/lib_acl_cpp/include/acl_cpp/memcache/memcache_pool.hpp new file mode 100644 index 000000000..cef589826 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/memcache/memcache_pool.hpp @@ -0,0 +1,39 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include "acl_cpp/connpool/connect_pool.hpp" + +namespace acl +{ + +/** + * memcache 客户端连接池类,该类父类为 connect_pool,该类只需实现父类中的虚函数 + * create_connect 便拥有了连接池父类 connect_pool 的功能;另外,该类创建 + * 的连接对象是 memcache 对象,所以在调用 connect_pool::peek 时返回 + * 的便是 http_request 类,调用者需要将 peek 返回的类对象强制转为 memcache + * 类对象,便可以使用 memcache 类折所有功能,其中 memcache 类为 + * connect_client 的子类 + */ +class memcache_pool : public connect_pool +{ +public: + memcache_pool(const char* addr, int count, int retry_inter = 0); + ~memcache_pool(); + + /** + * 设置网络连接超时时间及网络 IO 读写超时时间(秒) + * @param conn_timeout {int} 连接超时时间 + * @param rw_timeout {int} 网络 IO 读写超时时间(秒) + * @return {memcache_pool&} + */ + memcache_pool& set_timeout(int conn_timeout = 30, int rw_timeout = 60); + +protected: + // 基类纯虚函数 + virtual connect_client* create_connect(); + +private: + int conn_timeout_; + int rw_timeout_; +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/mime/mime.hpp b/lib_acl_cpp/include/acl_cpp/mime/mime.hpp new file mode 100644 index 000000000..188143fbe --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/mime/mime.hpp @@ -0,0 +1,456 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include +#include +#include "acl_cpp/mime/mime_head.hpp" + +struct MIME_STATE; + +namespace acl { + +class string; +class mime_node; +class mime_attach; +class mime_body; +class mime_image; +class ifstream; +class fstream; + +class ACL_CPP_API mime +{ +public: + mime(); + ~mime(); + + ///////////////////////////////////////////////////////////////////// + // 与邮件解析相关的函数 + + /** + * 当用同一个MIME解析器对多封邮件解析时, 需要调用此函数清理之前 + * 解析过程中产生的内存, 虽然多次调用该函数无害, 但为了不影响 + * 效率, 最好在利用该解析器解析下一封邮件前调用该函数 + */ + mime& reset(void); + + /** + * 调用者可以手工调用此函数以触发分析邮件头过程 + */ + void primary_head_finish(void); + + /** + * 调用流式分析时用此函数判断邮件头是否解析完毕 + * @return {bool} 是否邮件头解析完毕 + */ + bool primary_head_ok() const; + + /** + * 开始进行流式解析过程, 该函数内部会自动调用 reset() 函数以重置解析 + * 器状态 + * @param path {const char*} 邮件文件路径名, 如果该参数为空, 则不能 + * 获得邮件体数据, 也不能调用 save_xxx 相关的接口 + */ + void update_begin(const char* path); + + /** + * 调用此函数进行流式方式解析邮件内容, 如果仅想解析邮件头, 则可以用此 + * 接口解析完邮件头后调用 update_end() 接口即可, 如果想要解析完整的一 + * 封邮件, 则需要不断地调用此函数直到本函数返回 true 表示 multipart 格式 + * 的邮件解析完毕; 如果不是 multipart 格式邮件, 则此函数不可能会回返 true, + * 调用者需要自行判断邮件的结束位置 + * @param data {const char*} 邮件数据(可能是邮件头也可能是邮件体, 并且 + * 不必是完整的数据行) + * @param len {size_t} data 数据长度 + * @return {bool} 针对 multipart 邮件, 返回 true 表示该封邮件结束完毕; + * 对于非 multipart 邮件, 该返回值永远为 false, 没有任何意义, 需要调用 + * 者自己判断邮件的结束位置 + * 注意: 调用完此函数后一定需要调用 update_end 函数通知解析器解析完毕 + */ + bool update(const char* data, size_t len); + + /** + * 在采用流式解析结束后必须调用此函数 + */ + void update_end(void); + + /** + * 调用此函数解析磁盘上的一封邮件 + * @param file_path {const char*} 邮件文件路径 + * @return {bool} 如果返回 false 说明源邮件文件无法打开 + */ + bool parse(const char* file_path); + + /** + * 将邮件解析结果另存为另一个文件名 + * @param out {fstream&} 目标流对象 + * @return {bool} 是否成功 + */ + bool save_as(fstream& out); + + /** + * 将邮件解析结果另存为另一个文件中 + * @param file_path {const char*} 目标文件名 + * @return {bool} 是否成功 + */ + bool save_as(const char* file_path); + + /** + * 邮件解析完毕后,按客户显示的方式将解析结果保存于磁盘, + * 用户可以使用浏览器打开该 html 页面 + * @param path {const char*} 页面保存路径 + * @param filename {const char*} 目标文件名 + * @param enableDecode {bool} 转储时是否自动进行解码 + * @param toCharset {const char*} 目标字符集 + * @param off {off_t} 调用者希望给邮件结点附加的相对偏移量 + * @return {bool} 是否成功 + */ + bool save_mail(const char* path, const char* filename, + bool enableDecode = true, const char* toCharset = "gb2312", + off_t off = 0); + + /** + * 获得邮件正文结点 + * @param htmlFirst {bool} 优先获得HTML格式的文本;否则优先获得 + * 纯文本,且如果只有HTML文本则转换为纯文本 + * @param enableDecode {bool} 转储时是否对原文进行解码 + * @param toCharset {const char*} 目标字符集 + * @param off {off_t} 调用者希望给邮件体结点附加的相对偏移量 + * @return {mime_body*} 若未找到正文内容则返回 NULL + */ + mime_body* get_body_node(bool htmlFirst, bool enableDecode = true, + const char* toCharset = "gb2312", off_t off = 0); + + /** + * 获得所有的 mime 结点列表 + * @param enableDecode {bool} 转储时是否自动进行解码 + * @param off {off_t} 调用者希望给邮件结点附加的相对偏移量 + * @return {const std::list&} + */ + const std::list& get_mime_nodes( + bool enableDecode = true, off_t off = 0); + + /** + * 获得附件列表 + * @param enableDecode {bool} 转储时是否自动进行解码 + * @param off {off_t} 调用者希望给邮件结点附加的相对偏移量 + * @return {const std::list&} + */ + const std::list& get_attachments( + bool enableDecode = true, off_t off = 0); + + /** + * 获得图片列表 + * @param enableDecode {bool} 转储时是否自动进行解码 + * @param toCharset {const char*} 目标字符集 + * @param off {off_t} 调用者希望给邮件结点附加的相对偏移量 + * @return {const std::list&} + */ + const std::list& get_images(bool enableDecode = true, + const char* toCharset = "gb2312", off_t off = 0); + mime_image* get_image(const char* cld, bool enableDecode = true, + const char* toCharset = "gb2312", off_t off = 0); + + /** + * 调试MIME解析结果 + * @param save_path {const char*} 存储 MIME 解析结果的路径 + * @param decode {bool} 是否对原文进行解码 + */ + void mime_debug(const char* save_path, bool decode = true); + + ///////////////////////////////////////////////////////////////////// + // 和邮件头相关的函数 + + /** + * 设置发件人 + * @param addr {const char*} 邮件地址 + * @return {mime&} + */ + mime& set_sender(const char* addr) + { + m_primaryHeader.set_returnpath(addr); + return (*this); + } + + /** + * 设置发件人: From: zhengshuxin@51iker.com + * @param addr {const char*} 邮件地址 + * @return {mime&} + */ + mime& set_from(const char* addr) + { + m_primaryHeader.set_from(addr); + return (*this); + } + + /** + * 设置邮件回地址: Reply-To: zhengshuxin@51iker.com + * @param addr {const char*} 邮件地址 + * @return {mime&} + */ + mime& set_replyto(const char* addr) + { + m_primaryHeader.set_replyto(addr); + return (*this); + } + + /** + * 设置邮件反复地址 Return-Path: + * @param addr {const char*} 邮件地址 + * @return {mime&} + */ + mime& set_returnpath(const char* addr) + { + m_primaryHeader.set_returnpath(addr); + return (*this); + } + + /** + * 设置邮件主题: Subject: test + * @param s {const char*} 邮件主题 + * @return {mime&} + */ + mime& set_subject(const char* s) + { + m_primaryHeader.set_subject(s); + return (*this); + } + + /** + * 添加邮件接收人: To: + * @param addr {const char*} 邮件地址 + * @return {mime&} + */ + mime& add_to(const char* addr) + { + m_primaryHeader.add_to(addr); + return (*this); + } + + /** + * 添加邮件抄送者: CC: + * @param addr {const char* addr} 邮件地址 + * @return {mime&} + */ + mime& add_cc(const char* addr) + { + m_primaryHeader.add_cc(addr); + return (*this); + } + + /** + * 添加邮件密送者: BCC: + * @param addr {const char* addr} 邮件地址 + * @return {mime&} + */ + mime& add_bcc(const char* addr) + { + m_primaryHeader.add_bcc(addr); + return (*this); + } + + /** + * 添加邮件接收者: CC: + * @param addr {const char* addr} 邮件地址 + * @return {mime&} + */ + mime& add_rcpt(const char* addr) + { + m_primaryHeader.add_rcpt(addr); + return (*this); + } + + /** + * 添加邮件头的字段 + * @param name {const char*} 字段名 + * @param value {const char*} 字段值 + * @return {mime&} + */ + mime& add_header(const char* name, const char* value) + { + m_primaryHeader.add_header(name, value); + return (*this); + } + + /** + * 设置邮件头的内容类型: Content-Type: text/plain + * @param ctype {size_t} 主类型 + * @param stype {size_t} 子类型 + * @return {mime&} + */ + mime& set_type(size_t ctype, size_t stype) + { + m_primaryHeader.set_type(ctype, stype); + return (*this); + } + + /** + * 设置邮件头部的分隔符 + * @param s {const char*} 分隔串 + * @return {mime&} + */ + mime& set_boundary(const char* s) + { + m_primaryHeader.set_boundary(s); + return (*this); + } + + /** + * 获得发件人 + * @return {const string&} 如果返回对象的内容为空 + * (调用 string::empty()) 则表示没有此字段 + */ + const string& sender(void) const + { + return (m_primaryHeader.sender()); + } + + /** + * 获得发件人 + * @return {const string&} 如果返回对象的内容为空 + * (调用 string::empty()) 则表示没有此字段 + */ + const string& from(void) const + { + return (m_primaryHeader.from()); + } + + /** + * 获得回复邮件地址 + * @return {const string&} 如果返回对象的内容为空 + * (调用 string::empty()) 则表示没有此字段 + */ + const string& replyto(void) const + { + return (m_primaryHeader.replyto()); + } + + /** + * 获得回复邮件地址 + * @return {const string&} 如果返回对象的内容为空 + * (调用 string::empty()) 则表示没有此字段 + */ + const string& returnpath(void) const + { + return (m_primaryHeader.returnpath()); + } + + /** + * 获得邮件主题 + * @return {const string&} 如果返回对象的内容为空 + * (调用 string::empty()) 则表示没有此字段 + */ + const string& subject(void) const + { + return (m_primaryHeader.subject()); + } + + /** + * 获得收件人列表: To: xxx@xxx.com + * @return {const std::list&) 如果返回对象的内容为空 + * (调用 std::list::empty()) 则表示没有此字段 + */ + const std::list& to_list(void) const + { + return (m_primaryHeader.to_list()); + } + + /** + * 获得抄送人列表: To: xxx@xxx.com + * @return {const std::list&) 如果返回对象的内容为空 + * (调用 std::list::empty()) 则表示没有此字段 + */ + const std::list& cc_list(void) const + { + return (m_primaryHeader.cc_list()); + } + + /** + * 获得暗送人列表: To: xxx@xxx.com + * @return {const std::list&) 如果返回对象的内容为空 + * (调用 std::list::empty()) 则表示没有此字段 + */ + const std::list& bcc_list(void) const + { + return (m_primaryHeader.bcc_list()); + } + + /** + * 获得收件人列表: + * To: xxx@xxx.xxx, CC: xxx@xxx.xxx, BCC: xxx@xxx.xxx + * @return {const std::list&) 如果返回对象的内容为空 + * (调用 std::list::empty()) 则表示没有此字段 + */ + const std::list& rcpt_list(void) const + { + return (m_primaryHeader.rcpt_list()); + } + + /** + * 获得邮件头的各个字段列表 + * @return {const std::list&) + */ + const std::list& header_list(void) const + { + return (m_primaryHeader.header_list()); + } + + /** + * 查询邮件头对应字段名的字段值 + * @param name {const char*} 字段名 + * @return {const char*} 字段值, 为空时表示不存在 + */ + const char* header_value(const char* name) const + { + return (m_primaryHeader.header_value(name)); + } + + /** + * 查询邮件头对应字段名的字段值集合 + * @param name {const char*} 字段名 + * @param values {std::list*} 存储对应的结果集 + * @return {int} 字段值集合的个数 + */ + int header_values(const char* name, std::list* values) const + { + return (m_primaryHeader.header_values(name, values)); + } + + /** + * 获得邮件头中关于 Content-Type: text/html 中的 text 字段 + * @return {const char*} 永远返回非空值 + */ + const char* get_ctype() const + { + return m_primaryHeader.get_ctype(); + } + + /** + * 获得邮件头中关于 Content-Type: text/html 中的 html 字段 + * @return {const char*} 永远返回非空值 + */ + const char* get_stype() const + { + return m_primaryHeader.get_stype(); + } + + /** + * 获得邮件头 + * @return {const mime_head&} + */ + const mime_head& primary_header(void) const + { + return (m_primaryHeader); + } + +private: + mime_head m_primaryHeader; + + MIME_STATE* m_pMimeState; + bool m_bPrimaryHeadFinish; + char* m_pFilePath; + mime_body* m_pBody; + std::list* m_pNodes; + std::list* m_pAttaches; + std::list* m_pImages; +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/mime/mime_attach.hpp b/lib_acl_cpp/include/acl_cpp/mime/mime_attach.hpp new file mode 100644 index 000000000..0eef037b0 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/mime/mime_attach.hpp @@ -0,0 +1,27 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include "acl_cpp/stdlib/string.hpp" +#include "acl_cpp/mime/mime_node.hpp" + +namespace acl { + +class ACL_CPP_API mime_attach : public mime_node +{ +public: + mime_attach(const char* emailFile, const MIME_NODE* node, + bool enableDecode = true, const char* toCharset = "gb2312", + off_t off = 0); + + virtual ~mime_attach(); + + /** + * 获得附件的文件名 + * @return {const char*} 返回值为 NULL 则说明没有找到文件名 + */ + const char* get_filename() const; + +private: + string m_filename; +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/mime/mime_base64.hpp b/lib_acl_cpp/include/acl_cpp/mime/mime_base64.hpp new file mode 100644 index 000000000..2f2184f98 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/mime/mime_base64.hpp @@ -0,0 +1,41 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include "acl_cpp/mime/mime_code.hpp" + +namespace acl { + +class ACL_CPP_API mime_base64 : public mime_code +{ +public: + mime_base64(); + + /** + * 构造函数 + * @param addCrlf {bool} 非流式编码时是否在末尾添加 "\r\n" + * @param addInvalid {bool} 流式解码时是否遇到非法字符是否原样拷贝 + */ + mime_base64(bool addCrlf, bool addInvalid); + ~mime_base64(); + + /** + * 静态编码函数,直接将输入数据进行编码同时存入用户缓冲区 + * 用户缓冲区 + * @param in {const char*} 输入数据地址 + * @param n {int} 输入数据长度 + * @param out {string*} 存储结果的缓冲区 + */ + static void encode(const char* in, int n, string* out); + + /** + * 静态解码函数,直接将输入数据进行解析并存入用户缓冲区 + * @param in {const char*} 输入数据地址 + * @param n {int} 数据长度 + * @param out {string*} 存储解析结果 + */ + static void decode(const char* in, int n, string* out); + +protected: +private: +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/mime/mime_body.hpp b/lib_acl_cpp/include/acl_cpp/mime/mime_body.hpp new file mode 100644 index 000000000..8b7e42285 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/mime/mime_body.hpp @@ -0,0 +1,121 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include "acl_cpp/mime/mime_node.hpp" + +struct MIME_NODE; + +namespace acl { + +class pipe_manager; +class ostream; +class pipe_string; +class string; + +class ACL_CPP_API mime_body : public mime_node +{ +public: + /** + * 构造函数 + * @param emailFile {const char*} 存储邮件内容的源文件,可以 + * 为空,但当为空时在调用 save_body 函数时,则不能指定源文件 + * @param node {const MIME_NODE*} 邮件中的某个结点对象 + * @param htmlFirst {bool} 是否在提取内容时优先提取 HTML 数据 + * @param enableDecode {bool} 当邮件内容为 base64/qp 等编译格式 + * 时是否需要自动进行解码 + * @param toCharset {const char*} 缺省的目标字符集,如果目标 + * 字符集与源字符集不同,则进行字符集转换 + * @param off {off_t} 邮件内容在整个数据中的起始位置中附加的 + * 相对偏移量,以便于用户可以在邮件内容前面加自己的私有数据 + */ + mime_body(const char* emailFile, const MIME_NODE* node, + bool htmlFirst = true, bool enableDecode = true, + const char* toCharset = "gb2312", off_t off = 0) + : mime_node(emailFile, node, enableDecode, toCharset, off) + , m_htmlFirst(htmlFirst) + { + } + + ~mime_body() {} + + /** + * 设置是否仅提取 HTML 数据, 如果为 true 则优先提取 HTML 数据, + * 当不存在 HTML 数据时才会提取纯文本数据; 如果为 false 则优先 + * 提取纯文本数据, 如果仅有 HTML 数据时则会从该 HTML 数据中抽 + * 取出纯文本数据 + * @param htmlFirst {bool} + */ + void set_status(bool htmlFirst) + { + m_htmlFirst = htmlFirst; + } + + /** + * 转储邮件正文内容于管道流中 + * @param out {pipe_manager&} 管道流管理器 + * @param src {const char*} 邮件内容的起始地址,如果为空指针, + * 则从构造函数中所提供的 emailFile 的文件中提取邮件内容 + * @param len {int} 邮件内容的数据长度,如果为0,则从构造 + * 函数中所提供的 emailFile 的文件中提取邮件内容 + * @return {bool} 是否成功 + */ + bool save_body(pipe_manager& out, const char* src = NULL, + int len = 0); + + /** + * 转储邮件正文内容于输出流中 + * @param out {ostream&} 输出流 + * @param src {const char*} 邮件内容的起始地址,如果为空指针, + * 则从构造函数中所提供的 emailFile 的文件中提取邮件内容 + * @param len {int} 邮件内容的数据长度,如果为0,则从构造 + * 函数中所提供的 emailFile 的文件中提取邮件内容 + * @return {bool} 是否成功 + */ + bool save_body(ostream& out, const char* src = NULL, + int len = 0); + + /** + * 转储邮件正文内容于目标文件中 + * @param file_path {const char*} 目标文件名 + * @param src {const char*} 邮件内容的起始地址,如果为空指针, + * 则从构造函数中所提供的 emailFile 的文件中提取邮件内容 + * @param len {int} 邮件内容的数据长度,如果为0,则从构造 + * 函数中所提供的 emailFile 的文件中提取邮件内容 + * @return {bool} 是否成功 + */ + bool save_body(const char* file_path, const char* src = NULL, + int len = 0); + + /** + * 转储邮件正文内容于管道缓冲区内 + * @param out {pipe_string&} 管道缓冲区 + * @param src {const char*} 邮件内容的起始地址,如果为空指针, + * 则从构造函数中所提供的 emailFile 的文件中提取邮件内容 + * @param len {int} 邮件内容的数据长度,如果为0,则从构造 + * 函数中所提供的 emailFile 的文件中提取邮件内容 + * @return {bool} 是否成功 + */ + bool save_body(pipe_string& out, const char* src = NULL, + int len = 0); + + /** + * 转储邮件正文内容于缓冲区中 + * @param out {string&} 缓冲区 + * @param src {const char*} 邮件内容的起始地址,如果为空指针, + * 则从构造函数中所提供的 emailFile 的文件中提取邮件内容 + * @param len {int} 邮件内容的数据长度,如果为0,则从构造 + * 函数中所提供的 emailFile 的文件中提取邮件内容 + * @return {bool} 是否成功 + */ + bool save_body(string& out, const char* src = NULL, + int len = 0); + + /** + * 判断结点头部类型中的从类型是否 MIME_STYPE_HTML 类型 + * @return {bool} + */ + bool html_stype() const; +private: + bool m_htmlFirst; +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/mime/mime_code.hpp b/lib_acl_cpp/include/acl_cpp/mime/mime_code.hpp new file mode 100644 index 000000000..0f8cc6396 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/mime/mime_code.hpp @@ -0,0 +1,149 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include "acl_cpp/stdlib/pipe_stream.hpp" + +namespace acl { + class string; + +class ACL_CPP_API mime_code : public pipe_stream +{ +public: + mime_code(); + + /** + * 构造函数 + * @param addCrlf {bool} 非流式编码时是否在末尾添加 "\r\n" + * @param addInvalid {bool} 流式解码时是否遇到非法字符是否原样拷贝 + */ + mime_code(bool addCrlf, bool addInvalid); + virtual ~mime_code() = 0; + + /* 流式编码函数,使用方法: encode_update->encode_update->...->encode_finish */ + + /** + * 编码过程, 添加源数据, 结果存于 out 中, 如果输入的 + * 数据不满足编码时缓存条件, 则内部仅临时缓存而不做编码 + * @param src {const char*} 源数据地址 + * @param n {int} 源数据长度 + * @param out {string*} 存储编码结果, 可以通过比较 + * 调用此函数前后的 out->length() 来判断该函数是进行了 + * 编码过程还是临时缓存过程; 如果使用了 out 中的结果数据, + * 则用完后应该调用 out->clear() 清空用过的数据 + */ + virtual void encode_update(const char *src, int n, + string* out); + + /** + * 编码结束后需要调用此函数来对可能存在于临时缓存中的 + * 源数据进行最后的编码 + * @param out {string*} 存储编码结果, 可以通过比较 + * 调用此函数前后的 out->length() 来判断该函数是进行了 + * 编码过程还是临时缓存过程; 如果使用了 out 中的结果数据, + * 则用完后应该调用 out->clear() 清空用过的数据 + */ + virtual void encode_finish(string* out); + + /* 流式解码函数,使用方法: decode_update->decode_update->...->decode_finish */ + + /** + * 解码过程, 添加经过编码的数据, 经本函数后进行解码, 如果 + * 输入的数据不满足解码时的字节数条件, 则内部仅是临时缓存 + * 该数据, 等满足解码条件时才进行解码 + * @param src {const char*} 经过编码后的数据 + * @param n {int} 数据长度 + * @param out {string*} 存储解码结果, 可以通过比较 + * 调用此函数前后的 out->length() 来判断该函数是进行了 + * 解码过程还是临时缓存过程; 如果使用了 out 中的结果数据, + * 则用完后应该调用 out->clear() 清空用过的数据 + */ + virtual void decode_update(const char *src, int n, string* out); + + /** + * 解码结束后需要调用此函数来对可能存在于临时缓存中的 + * 源数据进行最后的解码 + * @param out {string*} 存储解码结果, 可以通过比较 + * 调用此函数前后的 out->length() 来判断该函数是进行了 + * 解码过程还是临时缓存过程; 如果使用了 out 中的结果数据, + * 则用完后应该调用 out->clear() 清空用过的数据 + */ + virtual void decode_finish(string* out); + + /** + * 重置内部缓冲区 + */ + virtual void reset(); + + /** + * 在编码过程中设置是否自动在每个编码段添加 "\r\n" + * @param on {bool} + */ + virtual void add_crlf(bool on); + + /** + * 在解码过程中如果遇到非法字符是否将其添加在解码结果中 + * @param on {bool} + */ + virtual void add_invalid(bool on); + + /** + * 根据输入的编码表生成相应的解码表 + * @param toTab {const unsigned char*} 编码表字符串 + * @param out {string*} 存储结果 + */ + static void create_decode_tab(const unsigned char *toTab, string *out); + + /** + * 如果子类未重载以上虚函数而因此使用基类的以上默认虚函数时 + * 则子类必须调用此函数设置自己的编码表, 解码表及填充字符 + * @param toTab {const unsigned char*} 编码表 + * @param unTab {const unsigned char*} 解码表 + * @param fillChar {unsigned char} 填充字符 + */ + void init(const unsigned char* toTab, + const unsigned char* unTab, unsigned char fillChar); + + /** + * 设置转码器的工作状态,因为该转码器由编码器和解码器组成, + * 所以在使用 pipe_stream 方式工作时必须指定该转码器的状态 + * 以指定是处于编码器状态还是解码器状态 + * @param encoding {bool} 如果为 true 表示为编码器状态,否则 + * 为解码器状态 + */ + void set_status(bool encoding = true); + + // pipe_stream 虚函数重载 + + virtual int push_pop(const char* in, size_t len, + string* out, size_t max = 0); + virtual int pop_end(string* out, size_t max = 0); + virtual void clear(); + + /** + * 静态函数,根据编码类型 MIME_ENC_XXX (参见:mime_define.hpp) 获得 + * 对应的编解码对象,当有当 encoding 类型为 MIME_ENC_QP, + * MIME_ENC_BASE64, MIME_ENC_UUCODE, MIME_ENC_XXCODE + * @param encoding {int} 编码类型,只能为 MIME_ENC_QP, MIME_ENC_BASE64, + * MIME_ENC_UUCODE, MIME_ENC_XXCODE + * @param warn_unsupport {bool} 当未找到匹配的编码对象时是否记录警告信息 + * @return {mime_code*} 编码对象,当未找到匹配的编码类型时返回 NULL + */ + static mime_code* create(int encoding, bool warn_unsupport = true); + +private: + void encode(string* out); + void decode(string* out); + + char m_encodeBuf[57]; + int m_encodeCnt; + char m_decodeBuf[76]; + int m_decodeCnt; + bool m_addCrLf; + bool m_addInvalid; + bool m_encoding; + const unsigned char *m_toTab; + const unsigned char *m_unTab; + unsigned char m_fillChar; + string* m_pBuf; +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/mime/mime_define.hpp b/lib_acl_cpp/include/acl_cpp/mime/mime_define.hpp new file mode 100644 index 000000000..16737fd18 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/mime/mime_define.hpp @@ -0,0 +1,40 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" + +/* + * Content types and subtypes that we care about, either because we have to, + * or because we want to filter out broken MIME messages. + */ + +#define MIME_CTYPE_OTHER 0 +#define MIME_CTYPE_TEXT 1 +#define MIME_CTYPE_MESSAGE 2 +#define MIME_CTYPE_MULTIPART 3 +#define MIME_CTYPE_IMAGE 4 +#define MIME_CTYPE_APPLICATION 5 +#define MIME_CTYPE_MAX MIME_CTYPE_APPLICATION + +#define MIME_STYPE_OTHER 0 +#define MIME_STYPE_PLAIN 1 +#define MIME_STYPE_HTML 2 +#define MIME_STYPE_RFC822 3 +#define MIME_STYPE_PARTIAL 4 +#define MIME_STYPE_EXTERN_BODY 5 +#define MIME_STYPE_JPEG 6 +#define MIME_STYPE_GIF 7 +#define MIME_STYPE_BMP 8 +#define MIME_STYPE_PNG 9 +#define MIME_STYPE_OCTET_STREAM 10 +#define MIME_STYPE_MIXED 11 +#define MIME_STYPE_ALTERNATIVE 12 +#define MIME_STYPE_RELATED 13 +#define MIME_STYPE_MAX MIME_STYPE_RELATED + +#define MIME_ENC_OTHER 0 +#define MIME_ENC_QP 1 /* encoding + domain */ +#define MIME_ENC_BASE64 2 /* encoding + domain */ +#define MIME_ENC_7BIT 7 /* domain only */ +#define MIME_ENC_8BIT 8 /* domain only */ +#define MIME_ENC_BINARY 9 /* domain only */ +#define MIME_ENC_UUCODE 10 /* encoding + domain */ +#define MIME_ENC_XXCODE 11 /* encoding + domain */ diff --git a/lib_acl_cpp/include/acl_cpp/mime/mime_head.hpp b/lib_acl_cpp/include/acl_cpp/mime/mime_head.hpp new file mode 100644 index 000000000..e65ca4338 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/mime/mime_head.hpp @@ -0,0 +1,72 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include + +namespace acl { + +class string; + +typedef struct HEADER +{ + char *name; + char *value; +} HEADER; + +class ACL_CPP_API mime_head +{ +public: + mime_head(); + ~mime_head(); + + const string& get_boundary(void) const; + const char* get_ctype() const; + const char* get_stype() const; + const string& sender(void) const; + const string& from(void) const; + const string& replyto(void) const; + const string& returnpath(void) const; + const string& subject(void) const; + const std::list& to_list(void) const; + const std::list& cc_list(void) const; + const std::list& bcc_list(void) const; + const std::list& rcpt_list(void) const; + const std::list& header_list(void) const; + const char* header_value(const char* name) const; + int header_values(const char* name, std::list* values) const; + + mime_head& set_sender(const char*); + mime_head& set_from(const char*); + mime_head& set_replyto(const char*); + mime_head& set_returnpath(const char*); + mime_head& set_subject(const char*); + mime_head& add_to(const char*); + mime_head& add_cc(const char*); + mime_head& add_bcc(const char*); + mime_head& add_rcpt(const char*); + mime_head& add_header(const char*, const char*); + mime_head& set_type(size_t, size_t); + mime_head& set_boundary(const char*); + + void build_head(string& buf, bool clean); + + mime_head& reset(void); + +protected: +private: + string* m_boundary; + std::list* m_rcpts; + std::list* m_tos; + std::list* m_ccs; + std::list* m_bccs; + std::list* m_headers; + string* m_sender; + string* m_from; + string* m_replyto; + string* m_returnpath; + string* m_subject; + + size_t m_ctype; + size_t m_stype; +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/mime/mime_image.hpp b/lib_acl_cpp/include/acl_cpp/mime/mime_image.hpp new file mode 100644 index 000000000..f2e72dd06 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/mime/mime_image.hpp @@ -0,0 +1,22 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include "acl_cpp/mime/mime_node.hpp" + +namespace acl { + +class ACL_CPP_API mime_image : public mime_node +{ +public: + mime_image(const char* emailFile, const MIME_NODE* node, + bool enableDecode = true, const char* toCharset = "gb2312", + off_t off = 0) + : mime_node(emailFile, node, enableDecode, toCharset, off) + { + } + + ~mime_image() {} + + const char* get_location() const; +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/mime/mime_node.hpp b/lib_acl_cpp/include/acl_cpp/mime/mime_node.hpp new file mode 100644 index 000000000..f48318ffd --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/mime/mime_node.hpp @@ -0,0 +1,248 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include +#include "acl_cpp/stdlib/string.hpp" + +struct MIME_NODE; + +namespace acl { + +class pipe_manager; +class ostream; +class ifstream; + +class ACL_CPP_API mime_node +{ +public: + /** + * 构造函数 + * @param emailFile {const char*} 存储邮件内容的源文件,可以 + * 为空,但当为空时在调用 save_body 函数时,则不能指定源文件 + * @param node {const MIME_NODE*} 邮件中的某个结点对象 + * @param enableDecode {bool} 当邮件内容为 base64/qp 等编码格式 + * 时是否需要自动进行解码 + * @param toCharset {const char*} 缺省的目标字符集,如果目标 + * 字符集与源字符集不同,则进行字符集转换 + * @param off {off_t} 邮件内容在整个数据中的起始位置中附加的 + * 相对偏移量,以便于用户可以在邮件内容前面加自己的私有数据 + */ + mime_node(const char* emailFile, const MIME_NODE* node, + bool enableDecode = true, const char* toCharset = "gb2312", + off_t off = 0); + virtual ~mime_node(); + + /** + * 获得 MIME 结点中 Content-Type 值中的 name 字段值 + * @return {const char*} 如果为空则表示没有该字段值 + */ + const char* get_name() const + { + if (m_name.empty()) + return (NULL); + return (m_name.c_str()); + } + + /** + * 获得 Content-Type 中的主类型,如: Content-Type: image/jpeg, 则本 + * 函数返回 MIME_CTYPE_IMAGE (在 mime_define.hpp 中定义) + * @return {int} 返回 mime_define.hpp 中定义的 MIME_CTYPE_XXX + */ + int get_ctype() const + { + return (m_ctype); + } + + /** + * 获得 Content-Type 中的从类型,如: Content-Type: image/jpeg, 则本 + * 函数返回 MIME_STYPE_JPEG (在 mime_define.hpp 中定义) + * @return {int} 返回 mime_define.hpp 中定义的 MIME_STYPE_XXX + */ + int get_stype() const + { + return (m_stype); + } + + /** + * 获得传输编码类型 (对应于 Content-Transfer-Encoding) + * @return {int} 返回 mime_define.hpp 中定义的 MIME_ENC_XXX + */ + int get_encoding() const + { + return (m_encoding); + } + + /** + * 获得结点字符集字符串(对应于 Content-Type 中的 charset 字段) + * @return {const char*} 为空则表示没有该字段 + */ + const char* get_charset() const + { + return (m_charset); + } + + /** + * 获得目标字符集, 由用户在构造函数中传入 + * @return {const char*} 为空则表示用户未设置 + */ + const char* get_toCharset() const + { + if (m_toCharset[0]) + return (m_toCharset); + else + return (NULL); + } + + /** + * 获得本结点在邮件中的起始偏移量 + * @return {off_t} + */ + off_t get_bodyBegin() const + { + return (m_bodyBegin); + } + + /** + * 获得本结点在邮件中的结束偏移量 + * @return {off_t} + */ + off_t get_bodyEnd() const + { + return (m_bodyEnd); + } + + /** + * 获得本结点头部中某个字段的值 + * @param name {const char*} 字段名, 如: Content-Type + * @return {const char*} 为空则表示不存在 + */ + const char* header_value(const char* name) const; + + /** + * 转储本结点内容于指定的管道流中 + * @param out {pipe_manager&} + * @return {bool} 是否成功 + */ + bool save(pipe_manager& out) const; + + /** + * 转储本结点内容于指定的管道流中 + * @param out {pipe_manager&} + * @param src {const char*} 邮件内容的起始地址,如果为空指针, + * 则从构造函数中所提供的 emailFile 的文件中提取邮件内容 + * @param len {int} 邮件内容的数据长度,如果为0,则从构造 + * 函数中所提供的 emailFile 的文件中提取邮件内容 + * @return {bool} 是否成功 + */ + bool save(pipe_manager& out, const char* src, int len) const; + + /** + * 转储本结点内容于指定的输出流中 + * @param out {ostream&} 流出流 + * @param src {const char*} 邮件内容的起始地址,如果为空指针, + * 则从构造函数中所提供的 emailFile 的文件中提取邮件内容 + * @param len {int} 邮件内容的数据长度,如果为0,则从构造 + * 函数中所提供的 emailFile 的文件中提取邮件内容 + * @return {bool} 是否成功 + */ + bool save(ostream& out, const char* src = NULL, int len = 0) const; + + /** + * 转储本结点内容于指定的文件中 + * @param outFile {const char*} 目标文件名 + * @param src {const char*} 邮件内容的起始地址,如果为空指针, + * 则从构造函数中所提供的 emailFile 的文件中提取邮件内容 + * @param len {int} 邮件内容的数据长度,如果为0,则从构造 + * 函数中所提供的 emailFile 的文件中提取邮件内容 + * @return {bool} 是否成功 + */ + bool save(const char* outFile, const char* src = NULL, int len = 0) const; + + /** + * 转储本结点内容于缓冲区中 + * @param out {string&} 缓冲区 + * @param src {const char*} 邮件内容的起始地址,如果为空指针, + * 则从构造函数中所提供的 emailFile 的文件中提取邮件内容 + * @param len {int} 邮件内容的数据长度,如果为0,则从构造 + * 函数中所提供的 emailFile 的文件中提取邮件内容 + * @return {bool} 是否成功 + */ + bool save(string& out, const char* src, int len) const; + + /** + * 获得本结点对应的父结点对象 + * @return {mime_node*} 为空则表示本结点没有父结点(则说明 + * 本结点为邮件的根结点); 否则则返回的父结点需要在用完后 + * delete 掉以释放相应内存 + */ + mime_node* get_parent() const; + + /** + * 判断本结点是否有父结点 + * @return {bool} true 则表示有父结点, 否则表示没有 + */ + bool has_parent() const; + + /** + * 获得父结点的主类型 (MIME_CTYPE_XXX), 如果为 MIME_CTYPE_OTHER + * 则说明父结点不存在或父结点的主类型未知 + * @return {int} MIME_CTYPE_XXX + */ + int parent_ctype() const; + + /** + * 获得父结点的从类型 (MIME_STYPE_XXX), 如果为 MIME_STYPE_OTHER + * 则说明父结点不存在或父结点的从类型未知 + * @return {int} MIME_STYPE_XXX + */ + int parent_stype() const; + + /** + * 获得父结点的编码类型 (MIME_ENC_XXX), 如果返回值为 MIME_ENC_OTHER + * 则说明父结点不存在或父结点的编码类型未知 + * @return {int} MIME_ENC_XXX + */ + int parent_encoding() const; + + /** + * 获得父结点的字符集类型, 如果返回值为空则说明父结点不存在或父结点 + * 中没有字符集类型 + * @return {const char*} + */ + char* parent_charset() const; + + /** + * 获得父结点的数据体起始偏移量 + * @return {off_t} 返回值为 -1 表示父结点不存在 + */ + off_t parent_bodyBegin() const; + + /** + * 获得父结点的数据体结束偏移量 + * @return {off_t} 返回值为 -1 表示父结点不存在 + */ + off_t parent_bodyEnd() const; + + /** + * 获得父结点头部中某个字段名对应的字段值, 如: Content-Type + * @param name {const char*} 字段名 + * @return {const char*} 字段值, 返回空则说明父结点不存在 + * 或父结点头部中不存在该字段 + */ + const char* parent_header_value(const char* name) const; + +protected: + bool m_enableDecode; + string m_name; + string m_emailFile; + int m_ctype; // mime_define.hpp + int m_stype; // mime_define.hpp + int m_encoding; // mime_define.hpp + char m_charset[32]; + char m_toCharset[32]; + off_t m_bodyBegin; + off_t m_bodyEnd; + const MIME_NODE* m_pMimeNode; + mime_node* m_pParent; +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/mime/mime_quoted_printable.hpp b/lib_acl_cpp/include/acl_cpp/mime/mime_quoted_printable.hpp new file mode 100644 index 000000000..120b89bfd --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/mime/mime_quoted_printable.hpp @@ -0,0 +1,121 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include "acl_cpp/mime/mime_code.hpp" + +namespace acl { + +class string; + +class ACL_CPP_API mime_quoted_printable : public mime_code +{ +public: + mime_quoted_printable(); + + /** + * 构造函数 + * @param addCrlf {bool} 非流式编码时是否在末尾添加 "\r\n" + * @param addInvalid {bool} 流式解码时是否遇到非法字符是否原样拷贝 + */ + mime_quoted_printable(bool addCrlf, bool addInvalid); + ~mime_quoted_printable(); + + // 基类的虚函数重载 + + /* 流式编码函数,使用方法: encode_update->encode_update->...->encode_finish */ + + /** + * 流式编码函数 + * @param src {const char*} 原始数据 + * @param n {int} src 数据长度 + * @param out {string*} 存储编码结果,可以通过 out->empty() + * 来测试 out 中是否有结果数据,用 out->length() 获得 out 中结果 + * 数据的长度,注意当用完 out 中的结果数据后一定要调用 out->clear() + * 来清空用过的结果数据;也可以多次调用该函数后,在最后调用 + * encode_finish 后一次性取出所有数据 + */ + void encode_update(const char *src, int n, string* out); + + /** + * 流式编码结束函数,调用该函数后,取出最后的结果数据 + * @param out {string*} 存储编码结果,可以通过 out->empty() + * 来测试 out 中是否有结果数据,用 out->length() 获得 out 中结果 + * 数据的长度,注意当用完 out 中的结果数据后一定要调用 out->clear() + * 来清空用过的结果数据 + */ + void encode_finish(string* out); + + /* 流式解码函数,使用方法: decode_update->decode_update->...->decode_finish */ + + /** + * 流式解码函数 + * @param src {const char*} 原始数据 + * @param n {int} src 数据长度 + * @param out {string*} 存储解码结果,可以通过 out->empty() + * 来测试 out 中是否有结果数据,用 out->length() 获得 out 中结果 + * 数据的长度,注意当用完 out 中的结果数据后一定要调用 out->clear() + * 来清空用过的结果数据;也可以多次调用该函数后,在最后调用 + * decode_finish 后一次性取出所有数据 + */ + void decode_update(const char *src, int n, string* out); + + /** + * 流式解码结束函数,调用该函数后,取出最后的结果数据 + * @param out {string*} 存储解码结果,可以通过 out->empty() + * 来测试 out 中是否有结果数据,用 out->length() 获得 out 中结果 + * 数据的长度,注意当用完 out 中的结果数据后一定要调用 out->clear() + * 来清空用过的结果数据 + */ + void decode_finish(string* out); + + /** + * 静态编码函数,直接将输入数据进行编码同时存入用户缓冲区 + * 用户缓冲区 + * @param in {const char*} 输入数据地址 + * @param n {int} 输入数据长度 + * @param out {string*} 存储结果的缓冲区 + */ + static void encode(const char* in, int n, string* out); + + /** + * 静态解码函数,直接将输入数据进行解析并存入用户缓冲区 + * @param in {const char*} 输入数据地址 + * @param n {int} 数据长度 + * @param out {string*} 存储解析结果 + */ + static void decode(const char* in, int n, string* out); + + /** + * 重置编、解码器状态 + */ + void reset(); + + /** + * 设置在编码结束时是否添加 "\r\n" + * @param on {bool} + */ + void add_crlf(bool on); + + /** + * 设置在解码过程中是否拷贝非法字符 + * @param on {bool} + */ + void add_invalid(bool on); + +protected: +private: + void encode(string* out); + void decode(string* out); + + bool hex_decode(unsigned char first, unsigned char second, + unsigned int *result); + + char m_encodeBuf[72]; + int m_encodeCnt; + char m_decodeBuf[144]; + int m_decodeCnt; + bool m_addCrLf; + bool m_addInvalid; +}; + +} // namespace acl + diff --git a/lib_acl_cpp/include/acl_cpp/mime/mime_uucode.hpp b/lib_acl_cpp/include/acl_cpp/mime/mime_uucode.hpp new file mode 100644 index 000000000..df52c839e --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/mime/mime_uucode.hpp @@ -0,0 +1,41 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include "acl_cpp/mime/mime_code.hpp" + +namespace acl { + +class ACL_CPP_API mime_uucode : public mime_code +{ +public: + mime_uucode(); + + /** + * 构造函数 + * @param addCrlf {bool} 非流式编码时是否在末尾添加 "\r\n" + * @param addInvalid {bool} 流式解码时是否遇到非法字符是否原样拷贝 + */ + mime_uucode(bool addCrlf, bool addInvalid); + ~mime_uucode(); + + /** + * 静态编码函数,直接将输入数据进行编码同时存入用户缓冲区 + * 用户缓冲区 + * @param in {const char*} 输入数据地址 + * @param n {int} 输入数据长度 + * @param out {string*} 存储结果的缓冲区 + */ + static void encode(const char* in, int n, string* out); + + /** + * 静态解码函数,直接将输入数据进行解析并存入用户缓冲区 + * @param in {const char*} 输入数据地址 + * @param n {int} 数据长度 + * @param out {string*} 存储解析结果 + */ + static void decode(const char* in, int n, string* out); + +protected: +private: +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/mime/mime_xxcode.hpp b/lib_acl_cpp/include/acl_cpp/mime/mime_xxcode.hpp new file mode 100644 index 000000000..d55e644ae --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/mime/mime_xxcode.hpp @@ -0,0 +1,41 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include "acl_cpp/mime/mime_code.hpp" + +namespace acl { + +class ACL_CPP_API mime_xxcode : public mime_code +{ +public: + mime_xxcode(); + + /** + * 构造函数 + * @param addCrlf {bool} 非流式编码时是否在末尾添加 "\r\n" + * @param addInvalid {bool} 流式解码时是否遇到非法字符是否原样拷贝 + */ + mime_xxcode(bool addCrlf, bool addInvalid); + ~mime_xxcode(); + + /** + * 静态编码函数,直接将输入数据进行编码同时存入用户缓冲区 + * 用户缓冲区 + * @param in {const char*} 输入数据地址 + * @param n {int} 输入数据长度 + * @param out {string*} 存储结果的缓冲区 + */ + static void encode(const char* in, int n, string* out); + + /** + * 静态解码函数,直接将输入数据进行解析并存入用户缓冲区 + * @param in {const char*} 输入数据地址 + * @param n {int} 数据长度 + * @param out {string*} 存储解析结果 + */ + static void decode(const char* in, int n, string* out); + +protected: +private: +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/mime/rfc2047.hpp b/lib_acl_cpp/include/acl_cpp/mime/rfc2047.hpp new file mode 100644 index 000000000..9ea07de1f --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/mime/rfc2047.hpp @@ -0,0 +1,138 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include + +namespace acl { + +class string; +class mime_code; + +struct rfc2047_entry +{ + string* pData; // 数据内容 + string* pCharset; // 字符集 + char coding; // 编码格式,B 表示 BASE64, Q 表示 QP +}; + +class ACL_CPP_API rfc2047 +{ +public: + /** + * 构造函数 + * @param strip_sp {bool} 在解码过程中是否去掉回车换行符及每行开头的空格及TAB + * @param addCrlf {bool} 在编码过程中当数据比较长时是否自动添加 "\r\n" + */ + rfc2047(bool strip_sp = false, bool addCrlf = true); + ~rfc2047(); + + /** + * 流式解析数据, 可以循环调用此函数, 每次添加部分数据 + * 直至添加完毕 + * @param in {const char*} 输入源字符串 + * @param n {int} in 输入串的长度 + */ + void decode_update(const char* in, int n); + + /** + * 将 rfc2047 解析结果转换成指定的字符集字符串, 如果不能 + * 正确转换则保留源串内容 + * @param to_charset {const char*} 目标字符集 + * @param out {string*} 存储转换结果 + * @param addInvalid {bool} 当为 true 时,则转码过程中如果遇到了 + * 非法字符集,则直接拷贝,否则则跳过,默认情况下是直接拷贝 + * @return {bool} 转换是否成功 + */ + bool decode_finish(const char* to_charset, string* out, + bool addInvalid = true); + + /** + * rfc2047 编码过程中添加数据 + * @param in {const char*} 输入数据 + * @param n {int} in 数据长度 + * @param out {string*} 存储编码结果 + * @param charset {const char*} 输入数据的字符集类型 + * @param coding {char} 编码类型,支持的编码类型有: + * B: base64, Q: quoted_printable + * @return {bool} 检查输入参数是否正确且编码是否成功 + */ + bool encode_update(const char* in, int n, string* out, + const char* charset = "gb2312", char coding = 'B'); + + /** + * 将 encode_update 添加的数据进行编码后存储于用户指定缓冲区 + * @param out {string*} 存储编码结果的用户缓冲区 + * @return {bool} 是否成功 + */ + bool encode_finish(string* out); + + /** + * 静态编码器 + * @param in {const char*} 输入数据地址 + * @param n {int} 数据长度 + * @param out {string*} 存储编码结果的缓冲区 + * @param charset {const char*} 输入数据的字符集 + * @param coding {char} 编码类型,支持的编码类型有: + * B: base64, Q: quoted_printable + * @param addCrlf {bool} 在编码过程中当数据比较长时是否自动添加 "\r\n" + * @return {bool} 编码是否成功 + */ + static bool encode(const char* in, int n, string* out, + const char* charset = "gb2312", char coding = 'B', + bool addCrlf = true); + + /** + * 静态解码器 + * @param in {const char*} 输入数据地址 + * @param n {int} 数据长度 + * @param out {string*} 存储解码结果的缓冲区 + * @param to_charset {const char*} 目标字符集 + * @param strip_sp {bool} 是否去掉回车换行符及每行开头的空格及TAB + * @param addInvalid {bool} 当为 true 时,则转码过程中如果遇到了 + * 非法字符集,则直接拷贝,否则则跳过,默认情况下是直接拷贝 + * @return {bool} 解码是否成功 + */ + static bool decode(const char* in, int n, string* out, + const char* to_charset = "gb2312", bool strip_sp = false, + bool addInvalid = true); + + /** + * 将解析结果以链表的形式给出 + * @return {const std::list&} + */ + const std::list& get_list(void) const; + + /** + * 重置解析器状态后, 该解析器可再次使用 + * @param strip_sp {bool} 是否去掉回车换行符及每行开头的空格及TAB + */ + void reset(bool strip_sp = false); + + /** + * 调试输出解析结果 + */ + void debug_rfc2047(void) const; + +protected: +private: + std::list m_List; + rfc2047_entry* m_pCurrentEntry; + mime_code* m_coder; + int m_status; + bool m_stripSp; + bool m_addCrlf; + char m_lastCh; + +public: + // 以下函数仅内部使用 + + int status_next(const char* s, int n); + int status_data(const char* s, int n); + int status_charset(const char* s, int n); + int status_coding(const char* s, int n); + int status_equal_question(const char* s, int n); + int status_question_first(const char* s, int n); + int status_question_second(const char* s, int n); + int status_question_equal(const char* s, int n); +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/mime/rfc822.hpp b/lib_acl_cpp/include/acl_cpp/mime/rfc822.hpp new file mode 100644 index 000000000..196456e68 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/mime/rfc822.hpp @@ -0,0 +1,97 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include +#include + +namespace acl { + +/** + * 邮件地址 + */ +struct rfc822_addr +{ + char* addr; // 邮件地址,格式为: xxx@xxx.xxx + char* comment; // 邮件备注 +}; + +typedef enum +{ + tzone_gmt, + tzone_cst +} tzone_t; + +class ACL_CPP_API rfc822 +{ +public: + rfc822(); + ~rfc822(); + + /** + * 解析符合 RFC822 标准的时间格式 + * @param in {const char*} 时间字符串,如: + * Wed, 11 May 2011 09:44:37 +0800 (CST) + * Wed, 11 May 2011 16:17:39 GMT + */ + time_t parse_date(const char *in); + + /** + * 生成符合 RFC822 标准的时间格式 + * @param t {time_t} + * @param out {char*} 存储转换结果 + * @param size {size_t} out 空间大小 + * @param zone {tzone_t} 所在时区 + */ + void mkdate(time_t t, char* out, size_t size, tzone_t zone = tzone_cst); + + /** + * 生成东八区的时间格式 + * @param t {time_t} + * @param out {char*} 存储转换结果 + * @param size {size_t} out 空间大小 + */ + void mkdate_cst(time_t t, char* out, size_t size); + + /** + * 生成格林威治时间的时间格式 + * @param t {time_t} + * @param out {char*} 存储转换结果 + * @param size {size_t} out 空间大小 + */ + void mkdate_gmt(time_t t, char* out, size_t size); + + /** + * 解析邮件地址列表,将符合 RFC822 标准的邮件地址列表解析成 + * 人能正常看懂的邮件地址列表,同时将用户名注释部分进行 + * RFC2047解码 + * @param in {const char*} RFC822 格式的邮件地址列表,如: + * "=?gb2312?B?1dSx+A==?= ;\r\n" + * "\t\"=?GB2312?B?t+vBosn6?=\" ;\r\n" + * "\t\"zhengshuxin3\";\"zhengshuxin4\" ;" + * ";;" + * @return {const std::list&} 解析结果 + */ + const std::list& parse_addrs(const char* in); + + /** + * 解析一个符合 RFC822 标准的邮件地址,同时将用户名注释部分按 + * RFC2047 标准进行解码 + * @param in {const char*} RFC822 格式的邮件地址 + * @return {const rfc822_addr*} 返回 NULL 表明输入的邮件地址不符合 + * RFC822 规范 + */ + const rfc822_addr* parse_addr(const char* in); + + /** + * 检查邮件地址是否合法 + * @param in {const char*} RFC822 格式的邮件地址 + * @return {bool} + */ + bool check_addr(const char* in); + +private: + std::list addrs_; + + void reset(); +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/queue/queue_file.hpp b/lib_acl_cpp/include/acl_cpp/queue/queue_file.hpp new file mode 100644 index 000000000..4727b325b --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/queue/queue_file.hpp @@ -0,0 +1,221 @@ +#pragma once +#include +#include "acl_cpp/queue/queue_manager.hpp" +#include "acl_cpp/stdlib/string.hpp" +#include "acl_cpp/stdlib/locker.hpp" + +#ifndef MAXPATH255 +#define MAXPATH255 255 +#endif + +namespace acl { + +class fstream; + +class ACL_CPP_API queue_file +{ +public: + queue_file(); + + /** + * 获得文件流指针 + * @return {acl::fstream*} 文件流指针, 如果为 NULL 则说明文件还未打开 + */ + fstream* get_fstream(void) const; + + /** + * 获得文件创建时间 + * @return {time_t}, 返回自 1970 年以来的秒数, 如果返回值为 (time_t) -1, + * 则表示出错 + */ + time_t get_ctime(void) const; + + /** + * 向文件中写数据 + * @param data {const void*} 数据地址 + * @param len {size} 数据长度 + * @return {bool} 写数据是否成功 + */ + bool write(const void* data, size_t len); + int format(const char* fmt, ...); + int vformat(const char* fmt, va_list ap); + + /** + * 从文件中读取数据 + * @param buf {void*} 缓存地址 + * @param len {size_t} buf 大小 + * @return {int} 读取的数据长度, -1: 表示读结束或读失败或输入参数错误, + * 应该关闭该文件对象, > 0: 表示成功 + */ + int read(void* buf, size_t len); + + /** + * 取得本队列文件的键值, 该值即是队列文件的部分文件名(不含路径, + * 扩展名) + * @return {const char*} 队列文件键值 + */ + const char* key(void) const + { + return m_partName; + } + + /** + * 获得队列文件的访问全路径 + * @return {const char*} + */ + const char* get_filePath(void) const + { + return m_filePath.c_str(); + } + + /** + * 获得队列文件的根路径部分(不含队列目录) + * @return {const char*} + */ + const char* get_home(void) const + { + return m_home; + } + + /** + * 获得该队列文件的队列名 + * @return {const char*} 队列名称 + */ + const char* get_queueName(void) const + { + return m_queueName; + } + + /** + * 获得队列子目录 + * @return {const char*} 队列子目录名 + */ + const char* get_queueSub(void) const + { + return m_queueSub; + } + + /** + * 获得该队列文件的扩展名 + * @return {const char*} 扩展名称 + */ + const char* get_extName(void) const + { + return m_extName; + } + + /** + * 获得已经写入的数据大小尺寸 + * @return {size_t} + */ + size_t get_fileSize() const + { + return nwriten_; + } + +private: + friend class queue_manager; + + ~queue_file(); + + /** + * 创建新的队列文件, 创建完毕后会自动创建该文件的加锁对象 + * 可以直接调用该文件的 lock()/unlock() + * @param home {const char*} 队列文件所在根路径 + * @param queueName {const char*} 队列名 + * @param extName {const char*} 队列文件扩展名 + * @param width {unsigned} 队列二级目录的个数 + * @return {bool} 创建新队列文件是否成功, 如果返回 false 则说明 + * 输入的 path 或 extName 非法 + */ + bool create(const char* home, const char* queueName, + const char* extName, unsigned width); + + /** + * 打开已经存在的队列文件, 打开后会自动创建该文件的加锁对象, + * 可以直接调用该文件的 lock()/unlock() + * @param filePath {const char*} 队列文件路径 + * @return {bool} 打开队列文件是否成功 + */ + bool open(const char* filePath); + bool open(const char* home, const char* queueName, const char* queueSub, + const char* partName, const char* extName); + + /** + * 关闭当前文件句柄 + */ + void close(); + + /** + * 从磁盘上删除本队列文件 + * @return {bool} 删除是否成功 + */ + bool remove(); + + /** + * 将队列文件从当前队列中移至目标队列中 + * @param queueName {const char*} 目标队列名称 + * @param extName {const char*} 目标扩展名称 + * @return {bool} 移动文件是否成功 + */ + bool move_file(const char* queueName, const char* extName); + + /** + * 设置队列名 + * @param queueName {const char*} 队列名称 + */ + void set_queueName(const char* queueName); + + /** + * 设置队列文件的扩展名 + */ + void set_extName(const char* extName); + + /** + * 对当前队列文件对象加锁(包括互斥锁及文件锁) + * @return {bool} 加锁是否成功 + */ + bool lock(void); + + /** + * 对当前队列文件对象解锁(包括互斥锁及文件锁) + * @return {bool} 解锁是否成功 + */ + bool unlock(void); + +private: + // 文件流对象 + fstream* m_fp; + + // 队列文件相对于队列根目录的全路径名 + string m_filePath; + + // 队列文件的根路径 + char m_home[MAXPATH255]; + + // 队列名称 + char m_queueName[32]; + + // 队列下的子目录 + char m_queueSub[32]; + + // 队列文件名, 不包括路径, 也不包括文件的扩展名 + char m_partName[MAXPATH255]; + + // 队列文件的扩展名 + char m_extName[32]; + + // 加锁对象 + locker m_locker; + + // 当前文件是否已经被加锁了 + bool m_bLocked; + + // 文件锁是否已经打开了 + bool m_bLockerOpened; + + // 已经写入的文件尺寸大小 + size_t nwriten_; +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/queue/queue_manager.hpp b/lib_acl_cpp/include/acl_cpp/queue/queue_manager.hpp new file mode 100644 index 000000000..5a19aa6f6 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/queue/queue_manager.hpp @@ -0,0 +1,209 @@ +#pragma once +#include +#include "acl_cpp/stdlib/string.hpp" +#include "acl_cpp/stdlib/locker.hpp" +#include "acl_cpp/queue/queue_file.hpp" + +typedef struct ACL_SCAN_DIR ACL_SCAN_DIR; +typedef struct ACL_SCAN_DIR ACL_SCAN_DIR; +typedef struct ACL_SCAN_DIR ACL_SCAN_DIR; + +namespace acl { + +class queue_file; + +class ACL_CPP_API queue_manager +{ +public: + /** + * 队列对象的构造函数 + * @param home {const char*} 队列的根目录 + * @param queueName {const char*} 该队列对象的队列名称 + */ + queue_manager(const char* home, const char* queueName, + unsigned sub_width = 2); + ~queue_manager(); + + /** + * 获得队列名 + * @return {const char*} + */ + const char* get_queueName() const; + + /** + * 获得队列根目录 + * @return {const char*} + */ + const char* get_home() const; + + /** + * 创建队列文件 + * @param extName {const char*} 队列文件扩展名 + * @return {queue_file*} 队列文件对象, 永远非NULL, 该返回值 + * 为动态创建的, 所以用完后需要 delete 以释放其所占内存 + */ + queue_file* create_file(const char* extName); + + /** + * 打开磁盘上存在的队列文件用于读/写 + * @param path {const char*} 队列文件名 + * @param no_cache {bool} 为 true 时,要求在缓存中该文件对应的 KEY + * 必须不存在,如果存在则返回 NULL 表示该文件正被锁定; 当该参数为 + * false 时,则可以直接使用缓存中的对象 + * @return {queue_file*} 队列文件对象, 出错或不存在则返回 NULL + */ + queue_file* open_file(const char* path, bool no_cache = true); + + /** + * 关闭队列文件句柄, 并释放该文件对象,并不删除文件 + * @param fp {queue_file*} 队列文件对象 + * @return {bool} 关闭是否成功 + */ + bool close_file(queue_file* fp); + + /** + * 从磁盘上删除队列文件, 并释放该文件对象 + * 自己删除该对象 + * @param fp {queue_file*} 队列文件对象 + * @return {bool} 删除文件是否成功 + */ + bool delete_file(queue_file* fp); + + /** + * 修改文件的扩展名 + * @param fp {queue_file*} 队列文件对象 + * @param extname {const char*} 新的扩展名 + * @return {bool} 修改文件扩展名是否成功 + */ + bool rename_extname(queue_file* fp, const char* extName); + + /** + * 将队列文件移至目标队列中, 移动成功后, 文件对象内部内容将会发生改变 + * @param fp {queue_file*} 队列文件对象 + * @param queueName {const char*} 目标队列名 + * @param extName {const char*} 文件扩展名 + * @return {bool} 移动队列文件是否成功, 如果移动失败, 则调用者应用调用 + * close_file 关闭该队列文件对象, 该文件将会被定时扫描任务移走 + */ + bool move_file(queue_file* fp, const char* queueName, const char* extName); + + /** + * 将一个队列文件对象移至目标队列对象中 + * @param fp {queue_file*} 队列文件对象 + * @param toQueue {queue_manager*} 目标队列对象 + * @param extName {const char*} 文件扩展名 + * @return {bool} 移动队列文件是否成功, 如果移动失败, 则调用者应用调用 + * close_file 关闭该队列文件对象, 该文件将会被定时扫描任务移走 + */ + bool move_file(queue_file* fp, queue_manager* toQueue, const char* extName); + + /** + * 从磁盘上删除本队列文件, 删除成功后该队列文件句柄已经被删除, 不可再用, + * 即使删除文件失败, 该队列文件对象也被释放, 只是从磁盘上删除该文件失败, + * 所以调用此函数后 fp 不能再次使用 + * @param fp {queue_file*} + * @return {bool} 删除是否成功 + */ + bool remove(queue_file* fp); + + /** + * 检查所给文件名是否正在被使用 + * @param fileName {const char*} 文件名 + * @return {bool} 是否被使用 + */ + bool busy(const char* fileName); + + /** + * 在队列对象的缓存中查找某个队列文件对象 + * @param key {const char*} 队列文件的部分文件名(不含路径及扩展名) + * @return {queue_file*} 返回 NULL 则表示未查到 + */ + queue_file* cache_find(const char* key); + + /** + * 向队列对象的缓存中添加某个队列文件对象 + * @param fp {queue_file*} 队列文件对象 + * @return {bool} 添加是否成功, 若失败则说明该对象或其对应的键值 + * 已经存在于缓存中 + */ + bool cache_add(queue_file* fp); + + /** + * 从队列对象的缓存中删除某个队列文件对象 + * @param key {const char*} 队列文件对象的键值 + * @return {bool} 删除是否成功, 若失败则说明该队列文件对象不存在 + */ + bool cache_del(const char* key); + + /*-------------------- 与队列扫描相关的函数 ------------------------*/ + + /** + * 打开磁盘扫描队列 + * @param scanSub {bool} 是否递归扫描子目录 + * @return {bool} 打开队列是否成功 + */ + bool scan_open(bool scanSub = true); + + /** + * 关闭扫描队列 + */ + void scan_close(); + + /** + * 获得磁盘队列中的下一个队列文件, 若扫描完毕则返回空 + * @return {queue_file*} 扫描的队列文件对象, 返回空则表示扫描完毕 + * 或出错,非空对象一定要在用完后 delete 以释放内部分配的资源 + */ + queue_file* scan_next(void); + + /** + * 根据文件路径分析出队列名, 文件名(不含路径及扩展名部分), 文件扩展名 + * @param filePath {const char*} 文件全路径名 + * @param home {acl::string*} 存储文件所在的根目录 + * @param queueName {acl::string*} 存储文件所在的队列名 + * @param queueSub {acl::string*} 存储文件的队列子目录 + * @param partName {acl::string*} 存储文件的文件名部分(不含路径及扩展名) + * @param extName {acl::string*} 存储文件的扩展名部分 + */ + static bool parse_filePath(const char* filePath, acl::string* home, + string* queueName, string* queueSub, + string* partName, string* extName); + + /** + * 根据文件名称(含扩展名但不含路径), 分析出文件名(不含路径及扩展名), + * 和文件扩展名称 + */ + static bool parse_fileName(const char* fileName, acl::string* partName, + string* extName); + + /** + * 分析路径, 从中提取出队列名称 + */ + static bool parse_path(const char* path, acl::string* home, + string* queueName, acl::string* queueSub); + + /** + * 根据部分文件名(不含目录及扩展名)计算出其队列子目录路径(以数字表示) + * @param partName {const char*} 部分文件名 + * @param width {unsigned} 队列二级目录的个数 + * @return {unsigned int} 队列子目录路径(以数字表示) + */ + static unsigned int hash_queueSub(const char* partName, unsigned width); + +protected: +private: + bool cache_check(queue_file* fp); + + //typedef struct ACL_SCAN_DIR ACL_SCAN_DIR; + + // 扫描目录的句柄 + ACL_SCAN_DIR* m_scanDir; + string m_home; + string m_queueName; + unsigned sub_width_; + + std::map m_queueList; + locker m_queueLocker; +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/redis/redis_client.hpp b/lib_acl_cpp/include/acl_cpp/redis/redis_client.hpp new file mode 100644 index 000000000..232af296f --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/redis/redis_client.hpp @@ -0,0 +1,29 @@ +#pragma once +#include +#include "acl_cpp/stream/socket_stream.hpp" +#include "acl_cpp/redis/redis_response.hpp" + +namespace acl { + +class redis_client +{ +public: + redis_client(const char* addr, int conn_timeout = 60, int rw_timeout = 30, + bool retry = true); + ~redis_client(); + + bool open(); + void close(); + const std::vector& request(const char* cmd, + const void* data, size_t len); + void clear(); +private: + socket_stream conn_; + char* addr_; + int conn_timeout_; + int rw_timeout_; + bool retry_; + std::vector res_; +}; + +} // end namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/redis/redis_key.hpp b/lib_acl_cpp/include/acl_cpp/redis/redis_key.hpp new file mode 100644 index 000000000..07a7c877b --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/redis/redis_key.hpp @@ -0,0 +1,23 @@ +#pragma once +#include +#include "acl_cpp/stdlib/string.hpp" + +namespace acl { + +class redis_key +{ +public: + redis_key() {} + ~redis_key() {} + + bool del_keys(const char* first_key, ...); + int get_keys(const char* pattern, std::vector& out); + bool if_exists(const char* key); + redis_key_t get_key_type(const char* key); + bool set_ttl(const char* key, int n); + int get_ttl(const char* key); + bool set_expireat(const char* key, time_t stamp); + bool set_persist(const char*); +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/redis/redis_response.hpp b/lib_acl_cpp/include/acl_cpp/redis/redis_response.hpp new file mode 100644 index 000000000..2ff1279f8 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/redis/redis_response.hpp @@ -0,0 +1,39 @@ +#pragma once +#include "acl_cpp/stdlib/string.hpp" + +typedef enum +{ + REDIS_KEY_NULL, + REDIS_KEY_STR, + REDIS_KEY_LIST, + REDIS_KEY_SET, + REDIS_KEY_ZSET, + REDIS_KEY_HASH +} redis_key_t; + +namespace acl +{ + +class redis_response +{ +public: + redis_response() {} + ~redis_response() {} + + bool isString() + { + return type == REDIS_KEY_STR; + } + +private: + redis_key_t type; + unsigned count; + union + { + string* value; + long long intval; + redis_response* values; + }; +}; + +} // end namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/session/memcache_session.hpp b/lib_acl_cpp/include/acl_cpp/session/memcache_session.hpp new file mode 100644 index 000000000..6eac96945 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/session/memcache_session.hpp @@ -0,0 +1,64 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include "acl_cpp/session/session.hpp" + +namespace acl { + +class memcache; + +/** + * session 类,该类使用 memcached 存储 session 数据 + */ +class ACL_CPP_API memcache_session : public session +{ +public: + /** + * 构造函数 + * @param cache_addr {const char*} memcached 服务地址,格式: + * IP:PORT,不能为空 + * @param prefix {const char*} 在 memcached 存储的键值的前缀 + * @param conn_timeout {int} 连接 memcached 的超时时间(秒) + * @param rw_timeout {int} 与 memcached 通讯的 IO 超时时间(秒) + * @param ttl {time_t} 生存周期(秒) + * @param sid {const char*} session 对应的 sid,当为空时,内部 + * 会自动生成一个,其它说明请参考基类 session 的说明 + * @param encode_key {bool} 是否对存储于 memcached 的键值进行编码 + */ + memcache_session(const char* cache_addr, int conn_timeout = 180, + int rw_timeout = 300, const char* prefix = NULL, + time_t ttl = 0, const char* sid = NULL, bool encode_key = true); + + /** + * 以输入的 memcached 的连接对象为参数的构造函数 + * @param cache {memcache*} 输入的 memcached 连接对象 + * @param auth_free {bool} 当该参数为 true 时,则要求该 + * memcached_session 对象析构函数中释放传入的 cache 对象; + * 否则则禁止在 memcached_session 的析构函数中释放 cache 对象 + * @param ttl {time_t} 生存周期(秒) + * @param sid {const char*} session 对应的 sid,当为空时,内部 + * 会自动生成一个,其它说明请参考基类 session 的说明 + */ + memcache_session(memcache* cache, bool auto_free = false, + time_t ttl = 0, const char* sid = NULL); + + ~memcache_session(void); + +private: + // 基类纯虚函数,从 memcached 中获得数据 + virtual bool get_data(const char* sid, string& buf); + + // 基类纯虚函数,向 memcached 中添加或修改数据 + virtual bool set_data(const char* sid, const char* buf, + size_t len, time_t ttl); + + // 基类纯虚函数,从 memcached 中删除数据 + virtual bool del_data(const char* sid); + + //重新设置 session 在缓存服务器上的缓存时间 + virtual bool set_timeout(const char* sid, time_t ttl); +private: + memcache* cache_; + bool auth_free_; +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/session/session.hpp b/lib_acl_cpp/include/acl_cpp/session/session.hpp new file mode 100644 index 000000000..4cb2170c1 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/session/session.hpp @@ -0,0 +1,208 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include +#include "acl_cpp/stdlib/string.hpp" + +namespace acl { + +// 用来存储属性值的缓冲区对象定义,这主要是为了兼容属性值 +// 可以为二进制的情形而增加的结构类型 +typedef enum +{ + TODO_NUL, + TODO_SET, + TODO_DEL +} todo_t; + +struct VBUF +{ + size_t len; + size_t size; + todo_t todo; + char buf[1]; +}; + +/** + * session 类,该类使用 memcached 存储 session 数据 + */ +class ACL_CPP_API session +{ +public: + /** + * 当构造函数的参数 sid 非空时,则该 session 对象使用该 + * sid;否则内部会自动生成一个 sid,用户应该通过 get_sid() + * 获得这个自动生成的 sid 以便于每次查询该 sid 对应的数据 + * @param ttl {time_t} 指定 session 的生存周期(秒) + * @param sid {const char*} 非空时,则 session 的 sid 使 + * 该值,否则内部会产生一个随机的 session sid,该随机的 + * sid 可以通过调用 get_sid() 获得;当然在使用过程中,用户 + * 也可以通过 set_sid() 修改本对象的 session sid; + * 此外,如果该 sid 为空,则如果用户查查找某个 sid 对应的 + * 数据,则用户必须先调用 set_sid() + */ + session(time_t ttl = 0, const char* sid = NULL); + virtual ~session(void); + + /** + * 重置内部状态,清理掉一些临时数据 + */ + void reset(void); + + /** + * 获得本 session 对象的唯一 ID 标识 + * @return {const char*} 非空 + */ + virtual const char* get_sid(void) const; + + /** + * 设置本 session 对象的唯一 ID 标识 + * @param sid {const char*} 非空 + * 注:调用本函数后,会自动清除之前的中间缓存数据 + */ + void set_sid(const char* sid); + + /** + * 当调用 session 类的 set/set_ttl 时,如果最后一个参数 delay 为 true, + * 则必须通过调用本函数将数据真正进行更新 + * @return {bool} 数据更新是否成功 + */ + bool flush(); + + /** + * 向 session 中添加新的字符串属性,同时设置该 + * session 的过期时间间隔(秒) + * @param name {const char*} session 名,非空 + * @param value {const char*} session 值,非空 + * @param delay {bool} 当为 true 时,则延迟发送更新指令到后端的 + * 缓存服务器,当用户调用了 session::flush 后再进行数据更新,这 + * 样可以提高传输效率;当为 false 时,则立刻更新数据 + * @return {bool} 返回 false 表示出错 + */ + bool set(const char* name, const char* value, bool delay = false); + + /** + * 向 session 中添加新的属性对象,同时设置该 + * session 的过期时间间隔(秒) + * @param name {const char*} session 属性名,非空 + * @param value {const char*} session 属性值,非空 + * @param len {size_t} value 值长度 + * @param delay {bool} 当为 true 时,则延迟发送更新指令到后端的 + * 缓存服务器,当用户调用了 session::flush 后再进行数据更新,这 + * 样可以提高传输效率;当为 false 时,则立刻更新数据 + * @return {bool} 返回 false 表示出错 + */ + bool set(const char* name, const void* value, size_t len, bool delay = false); + + /** + * 从 session 中取得字符串类型属性值 + * @param name {const char*} session 属性名,非空 + * @param local_cached {bool} 当本 session 对象从后端 cache 服务器 + * 取过一次数据后,如果该参数为 true,则连续调用本函数时,所用数据 + * 是本对象缓存的数据,而不是每次都要从后端取;否则,则每调用本函数 + * 都将从后端 cache 服务器取数据 + * @return {const char*} session 属性值,返回的指针地址永远非空,用户 + * 可以通过判断返回的是否是空串(即: "\0")来判断出错或不存在 + * 注:该函数返回非空数据后,用户应该立刻保留此返回值,因为下次 + * 的其它函数调用可能会清除该临时返回数据 + */ + const char* get(const char* name, bool local_cached = false); + + /** + * 从 session 中取得二进制数据类型的属性值 + * @param name {const char*} session 属性名,非空 + * @param local_cached {bool} 当本 session 对象从后端 cache 服务器 + * 取过一次数据后,如果该参数为 true,则连续调用本函数时,所用数据 + * 是本对象缓存的数据,而不是每次都要从后端取;否则,则每调用本函数 + * 都将从后端 cache 服务器取数据 + * @return {const VBUF*} session 属性值,返回空时表示出错或不存在 + * 注:该函数返回非空数据后,用户应该立刻保留此返回值,因为下次 + * 的其它函数调用可能会清除该临时返回数据 + */ + const VBUF* get_vbuf(const char* name, bool local_cached = false); + + /** + * 从 session 中删除指定属性值,当所有的变量都删除 + * 时会将整个对象从 memcached 中删除 + * @param name {const char*} session 属性名,非空 + * @param delay {bool} 当为 true 时,则延迟发送更新指令到后端的 + * 缓存服务器,当用户调用了 session::flush 后再进行数据更新,这 + * 样可以提高传输效率;当为 false 时,则立刻更新数据 + * @return {bool} true 表示成功(含不存在情况),false 表示删除失败 + */ + bool del(const char* name, bool delay = false); + + /** + * 重新设置 session 在缓存服务器上的缓存时间 + * @param ttl {time_t} 生存周期(秒) + * @param delay {bool} 当为 true 时,则延迟发送更新指令到后端的 + * 缓存服务器,当用户调用了 session::flush 后再进行数据更新,这 + * 样可以提高传输效率;当为 false 时,则立刻更新数据 + * @return {bool} 设置是否成功 + */ + bool set_ttl(time_t ttl, bool delay = true); + + /** + * 获得本 session 对象中记录的 session 生存周期;该值有可能 + * 与真正存储在缓存服务器的时间不一致,因为有可能其它的实例 + * 重新设置了 session 在缓存服务器上的生存周期 + * @return {time_t} + */ + time_t get_ttl(void) const; + + /** + * 使 session 从服务端的缓存中删除即使 session 失效 + * @return {bool} 是否使 session 失效 + */ + bool remove(void); + +protected: + // 获得对应 sid 的数据 + virtual bool get_data(const char* sid, string& buf) = 0; + + // 设置对应 sid 的数据 + virtual bool set_data(const char* sid, const char* buf, + size_t len, time_t ttl) = 0; + + // 删除对应 sid 的数据 + virtual bool del_data(const char* sid) = 0; + + // 设置对应 sid 数据的过期时间 + virtual bool set_timeout(const char* sid, time_t ttl) = 0; + +private: + time_t ttl_; + VBUF* sid_; + + // 该变量主要用在 set_ttl 函数中,如果推测该 sid_ 只是新产生的 + // 且还没有在后端 cache 服务端存储,则 set_ttl 不会立即更新后端 + // 的 cache 服务器 + bool sid_saved_; + bool dirty_; + std::map attrs_; + std::map attrs_cache_; + + // 将 session 数据序列化 + static void serialize(const std::map& attrs, string& out); + + static void serialize(const char* name, const void* value, + size_t len, string& buf); + + // 将 session 数据反序列化 + static void deserialize(string& buf, std::map& attrs); + + // 清空 session 属性集合 + static void attrs_clear(std::map& attrs); + + // 分配内存对象 + static VBUF* vbuf_new(const void* str, size_t len, todo_t todo); + + // 对内存对象赋值,如果内存对象空间不够,则重新分配 + // 内存,调用者必须用返回值做为新的内存对象,该对象 + // 可能是原有的内存对象,也有可能是新的内存对象 + static VBUF* vbuf_set(VBUF* buf, const void* str, size_t len, todo_t todo); + + // 释放内存对象 + static void vbuf_free(VBUF* buf); +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/stdlib/charset_conv.hpp b/lib_acl_cpp/include/acl_cpp/stdlib/charset_conv.hpp new file mode 100644 index 000000000..71c096837 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/stdlib/charset_conv.hpp @@ -0,0 +1,104 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" + +#include "acl_cpp/stdlib/string.hpp" +#include "acl_cpp/stdlib/pipe_stream.hpp" + +struct ACL_VSTRING; + +namespace acl { + +class ACL_CPP_API charset_conv : public pipe_stream +{ +public: + charset_conv(); + ~charset_conv(); + + /** + * 设置是否允许将无效的字符集直接拷贝 + * @param onoff {bool} 当为 true 时,则转码过程中如果遇到了 + * 非法字符集,则直接拷贝,否则则跳过,默认情况下是直接拷贝 + */ + void set_add_invalid(bool onoff); + + /** + * 转换函数 + * @param fromCharset {const char*} 源字符集 + * @param toCharset {const char*} 目标字符集 + * @param in {const char*} 输入的源数据地址(非空) + * @param n {size_t} 输入源数据的长度(>0) + * @param out {string*} 存储转换结果 + * @return {bool} 转换是否成功 + */ + bool convert(const char* fromCharset, const char* toCharset, + const char* in, size_t n, string* out); + + /** + * 如果转换失败, 该函数返回出错原因 + * @return {const char*} 出错原因 + */ + const char* serror(void) const; + + /** + * 重置转码状态, 该解析器便可重复使用, 但在再次使用前需要调用 + * set(from, to) 设置源字符集与目标字符集 + */ + void reset(void); + + /* 流式分析过程:update_begin->update->update ... ->update_finish */ + + /** + * 初始化流式分析的相关参数 + * @param fromCharset {const char*} 源字符集 + * @param toCharset {const char*} 目标字符集 + * @return {bool} 初始化是否成功 + */ + bool update_begin(const char* fromCharset, const char* toCharset); + + /** + * 以流式方式进行字符集转换 + * @param in {const char*} 源字符串 + * @param len {size_t} in 字符串长度 + * @param out {string*} 存储转换结果 + * @return {bool} 当前转换过程是否成功 + */ + bool update(const char* in, size_t len, string* out); + + /** + * 流式转换结束后需要调用此函数提取最后的转换结果 + * @param out {string*} 存储转换结果 + */ + void update_finish(string* out); + + /** + * 创建字符集转换器 + * @param fromCharset {const char*} 源字符集 + * @param toCharset {const char*} 目标字符集 + * @return {charset_conv*} 如果输入参数非法,或源字符集 + * 与目标字符集相同,或不支持两个字符集间的转换则返回NULL, + * 用完后需要调用 delete 删除 + */ + static charset_conv* create(const char* fromCharset, + const char* toCharset); + + // pipe_stream 虚函数重载 + + virtual int push_pop(const char* in, size_t len, + string* out, size_t max = 0); + virtual int pop_end(string* out, size_t max = 0); + virtual void clear(); + +protected: +private: + bool m_addInvalid; // 如果遇到无效的字符集,是否直接拷贝 + string m_errmsg; + string* m_pBuf; + char m_fromCharset[32]; + char m_toCharset[32]; + void* m_iconv; + ACL_VSTRING* m_pInBuf; + ACL_VSTRING* m_pOutBuf; + const char* m_pUtf8Pre; +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/stdlib/dns_service.hpp b/lib_acl_cpp/include/acl_cpp/stdlib/dns_service.hpp new file mode 100644 index 000000000..0c14b0afc --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/stdlib/dns_service.hpp @@ -0,0 +1,109 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include +#include "acl_cpp/ipc/ipc_service.hpp" +#include "acl_cpp/stdlib/string.hpp" +#include "acl_cpp/stream/aio_handle.hpp" + +namespace acl +{ + +class ACL_CPP_API dns_res +{ +public: + dns_res(const char* domain) : domain_(domain) {} + ~dns_res() { ips_.clear(); } + + string domain_; + std::list ips_; +protected: +private: +}; + +class ACL_CPP_API dns_result_callback +{ +public: + dns_result_callback(const char* domain) : domain_(domain) {} + + /** + * 当任务处理完毕或出错时,内部处理过程会自动调用 destroy 接口, + * 子类可以在该接口内进行一些释放过程,尤其当该对象是动态创建时, + * 子类应该在该函数内 delete this 以删除自己,因为该函数最终肯定 + * 会被调用,所以子类不应在其它地方进行析构操作 + */ + virtual void destroy(void) {} + + /** + * 子类实现此接口,以获得查询结果,如果 res.ips_.size() == 0 + * 则说明查询结果为空 + * @param domain {const char*} 用户输入的查询的域名 + * @param res {const dns_res&} 查询结果集 + * 注:在该回调中不得删除 dns_service 对象,否则将会造成 + * 内存非法访问,因为该回调是在 dns_service 中被调用的, + * 在该函数返回后 dns_service 对象还会继续使用 + */ + virtual void on_result(const char* domain, const dns_res& res) = 0; + + /** + * 获得在构造函数中设置的域名值 + */ + const string& get_domain() const { return (domain_); } +protected: + virtual ~dns_result_callback() {} +private: + string domain_; +}; + +class ipc_client; + +class ACL_CPP_API dns_service + : public ipc_service + , public aio_delay_free +{ +public: + /** + * 构造函数 + * @param nthread {int} 如果该值 > 1 则内部自动采用线程池,否则 + * 则是一个请求一个线程 + * @param win32_gui {bool} 是否是窗口类的消息,如果是,则内部的 + * 通讯模式自动设置为基于 WIN32 的消息,否则依然采用通用的套接 + * 口通讯方式 + */ + dns_service(int nthread = 1, bool win32_gui = false); + ~dns_service(); + + /** + * 开始域名解析过程 + * @param callback {dns_result_callback*} 当解析完毕后回调此类的 + * 的回调函数 on_result + */ + void lookup(dns_result_callback* callback); + + /** + * 当查询线程完成域名解析后会通知主线程的查询对象,该查询对象会 + * 调用本回调函数通知主类查询结果 + * @param res {const dns_res&} 查询结果集 + */ + void on_result(const dns_res& res); +protected: + /** + * 基类虚函数,当有新连接到达时基类回调此函数 + * @param client {aio_socket_stream*} 接收到的新的客户端连接 + */ + virtual void on_accept(aio_socket_stream* client); + +#ifdef WIN32 + /** + * 基类虚函数,当收到来自于子线程的 win32 消息时的回调函数 + * @param hWnd {HWND} 窗口句柄 + * @param msg {UINT} 用户自定义消息号 + * @param wParam {WPARAM} 参数 + * @param lParam {LPARAM} 参数 + */ + virtual void win32_proc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); +#endif +private: + std::list callbacks_; +}; + +} diff --git a/lib_acl_cpp/include/acl_cpp/stdlib/escape.hpp b/lib_acl_cpp/include/acl_cpp/stdlib/escape.hpp new file mode 100644 index 000000000..9c8581b10 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/stdlib/escape.hpp @@ -0,0 +1,10 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" + +namespace acl { +class string; + +ACL_CPP_API void escape(const char* in, size_t len, string& out); +ACL_CPP_API bool unescape(const char* in, size_t len, string& out); + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/stdlib/final_tpl.hpp b/lib_acl_cpp/include/acl_cpp/stdlib/final_tpl.hpp new file mode 100644 index 000000000..abf963303 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/stdlib/final_tpl.hpp @@ -0,0 +1,56 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" + +namespace acl { + +#ifdef WIN32 +template +class final_tpl_base +{ + friend TDerive; + friend TProvider; +private: + final_tpl_base() {} + ~final_tpl_base() {} +}; +#else +template +class identity +{ +public: + typedef T me; +}; + +template +class final_tpl_base +{ + friend class identity::me; + friend class identity::me; +private: + final_tpl_base() {} + ~final_tpl_base() {} +}; +#endif + +/* + * 提供禁止派生的功能,需要此功能的类可以从final_tpl派生, + * 并将类名作为模板参数传递 + * @example: + * class my_final_class : public acl::final_tpl + * { + * public: + * my_final_class() {} + * ~my_final_class() {} + * } + * 这样就保证了 my_final_class 是不能被继承的 + */ +template +class final_tpl : virtual public final_tpl_base > +{ +public: + final_tpl() {} + ~final_tpl() {} +}; + +} diff --git a/lib_acl_cpp/include/acl_cpp/stdlib/json.hpp b/lib_acl_cpp/include/acl_cpp/stdlib/json.hpp new file mode 100644 index 000000000..e651aec6a --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/stdlib/json.hpp @@ -0,0 +1,327 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include +#include +#include "acl_cpp/stdlib/pipe_stream.hpp" + +struct ACL_JSON_NODE; +struct ACL_JSON; +struct ACL_ITER; + +/** + * 对 ACL 库中 json 解析库的封装,方便 C++ 用户使用,如果不太注重性能因素, + * 可以直接使用该类,如果在服务端执行且非常注重性能,建议直接使用 ACL 库的 + * json 解析器,因为该类也是调用了 ACL 库中的 json 解析过程,并且有二次拷贝 + * 过程,可能会稍微影响一些性能,但对于一般的应用这点影响是微不足道的 + */ + +namespace acl { + +class json; + +/** + * json 结点,该类对象必须以 json.create_node() 方式创建 + */ +class ACL_CPP_API json_node +{ +public: + /** + * 取得本 json 结点的标签名 + * @return {const char*} 返回 json 结点标签名,如果返回空,则说明 + * 调用者需要判断返回值 + */ + const char* tag_name(void) const; + + /** + * 返回该 json 结点的文本标签值 + * @return {const char*} 返回空说明没有文本标签值 + */ + const char* get_text(void) const; + + /** + * 给本 json 结点添加 json_node 子结点对象 + * @param child {json_node*} 子结点对象 + * @param return_child {bool} 是否需要本函数返回新创建的子结点的引用 + * @return {json_node&} return_child 为 true 时返回子结点的引用, + * 否则返回本 json 结点对象的引用 + */ + json_node& add_child(json_node* child, bool return_child = false); + + /** + * 给本 json 结点添加 json_node 子结点对象 + * @param child {json_node&} 子结点对象 + * @param return_child {bool} 是否需要本函数返回新创建的子结点的引用 + * @return {json_node&} return_child 为 true 时返回子结点的引用, + * 否则返回本 json 结点对象的引用 + */ + json_node& add_child(json_node& child, bool return_child = false); + + /** + * 创建一个 json 结点对象,并将之添加为本 json 结点的子结点 + * @param as_array {bool} 是否数组对象 + * @param return_child {bool} 是否需要本函数返回新创建的子结点的引用 + * @return {json_node&} return_child 为 true 时创建的新结点的引用, + * 否则返回本 json 结点对象的引用 + */ + json_node& add_child(bool as_array = false, bool return_child = false); + + /** + * 创建一个 json 结点对象,并将之添加为本 json 结点的子结点 + * @param tag {const char*} 标签名 + * @param value {const char*} 标签值 + * @param return_child {bool} 是否需要本函数返回新创建的子结点的引用 + * @return {json_node&} return_child 为 true 时创建的新结点的引用, + * 否则返回本 json 结点对象的引用 + */ + json_node& add_child(const char* tag, const char* value, + bool return_child = false); + + /** + * 创建一个 json 结点对象,并将之添加为本 json 结点的子结点 + * @param tag {const char*} 标签名 + * @param node {json_node*} 标签值指针 + * @param return_child {bool} 是否需要本函数返回新创建的子结点的引用 + * @return {json_node&} return_child 为 true 时创建的新结点的引用, + * 否则返回本 json 结点对象的引用 + */ + json_node& add_child(const char* tag, json_node* node, + bool return_child = false); + + /** + * 创建一个 json 结点对象,并将之添加为本 json 结点的子结点 + * @param tag {const char*} 标签名 + * @param node {json_node&} 标签值引用 + * @param return_child {bool} 是否需要本函数返回新创建的子结点的引用 + * @return {json_node&} return_child 为 true 时创建的新结点的引用, + * 否则返回本 json 结点对象的引用 + */ + json_node& add_child(const char* tag, json_node& node, + bool return_child = false); + + /** + * @return {json_node&} 返回本结点的父结点引用 + */ + json_node& get_parent(void) const; + + /** + * 获得本结点的第一个子结点,需要遍历子结点时必须首先调用此函数 + * @return {json_node*} 返回空表示没有子结点 + */ + json_node* first_child(void); + + /** + * 获得本结点的下一个子结点 + * @return {json_node*} 返回空表示遍历过程结束 + */ + json_node* next_child(void); + + /** + * 返回该 json 结点在整个 json 树中的深度 + * @return {int} + */ + int depth(void) const; + + /** + * 返回该 json 结点的下一级子结点的个数 + * @return {int} 永远 >= 0 + */ + int children_count(void) const; + + /** + * 获得 json 对象的引用 + * @return {json&} + */ + json& get_json(void) const; + + /** + * 取出对应于 ACL 库中的 json 结点对象 + * @return {ACL_JSON_NODE*} 返回结点对象,注:该结点用户不能单独释放 + */ + ACL_JSON_NODE* get_json_node() const; +private: + friend class json; + /** + * 构造函数,要求该对象必须只能由 json 对象创建 + * @param node {ACL_JSON_NODE*} ACL 库中的 ACL_JSON_NODE 结构对象 + */ + json_node(ACL_JSON_NODE* node, json* json_ptr); + + /** + * 要求该对象必须是动态创建的 + */ + ~json_node(void); + + /** + * 设置 json 结点 + * @param node {ACL_JSON_NODE*} + */ + void set_json_node(ACL_JSON_NODE* node); + +private: + ACL_JSON_NODE* node_me_; + json* json_; + json_node* parent_; + json_node* parent_saved_; + json_node* child_; + ACL_ITER* iter_; +}; + +class ACL_CPP_API json : public pipe_stream +{ +public: + /** + * 构造函数 + * @param data {const char*} json 格式的字符串,可以是完整的 + * json 字符串,也可以是部分的 json 字符串,也可以是空指针, + * 无论如何,用户依然可以用部分或完整的 json 字符串调用 update + * 函数,在调用 update 过程中解析 json;其实,当构造函数的 + * 的 data 参数非空时,它也会调用 update + */ + json(const char* data = NULL); + ~json(void); + + json& part_word(bool on); + + /** + * 以流式方式循环调用本函数添加 json 数据,也可以一次性添加 + * 完整的 json 数据,如果是重复使用该 json 解析器解析多个 json + * 对象,则应该在解析下一个 json 对象前调用 reset() 方法来清 + * 除上一次的解析结果 + * @param data {const char*} json 数据 + */ + void update(const char* data); + + /** + * 重置 json 解析器状态,该 json 对象可以用来对多个 json 数据 + * 进行解析,在反复使用本 json 解析器前,需要调用本函数重置 + * 内部 json 解析器状态,清除上一次的解析结果 + */ + void reset(void); + + /** + * 从 json 对象中取得某个标签名的所有结点集合 + * @param tag {const char*} 标签名(不区分大小写) + * @return {const std::vector&} 返回结果集的对象引用, + * 如果查询结果为空,则该集合为空,即:empty() == true + * 注:返回的数组中的 json_node 结点数据可以修改,但不能删除该结点, + * 因为该库内部有自动删除的机制 + */ + const std::vector& getElementsByTagName(const char* tag) const; + + /** + * 从 json 对象中获得所有的与给定多级标签名相同的 json 结点的集合 + * @param tags {const char*} 多级标签名,由 '/' 分隔各级标签名,如针对 json 数据: + * { 'root': [ + * 'first': { 'second': { 'third': 'test1' } }, + * 'first': { 'second': { 'third': 'test2' } }, + * 'first': { 'second': { 'third': 'test3' } } + * ] + * } + * 可以通过多级标签名:root/first/second/third 一次性查出所有符合条件的结点 + * @return {const std::vector&} 符合条件的 json 结点集合, + * 如果查询结果为空,则该集合为空,即:empty() == true + * 注:返回的数组中的 json_node 结点数据可以修改,但不能删除该结点, + * 因为该库内部有自动删除的机制 + */ + const std::vector& getElementsByTags(const char* tags) const; + + /** + * 取得 acl 库中的 ACL_JSON 对象 + * @return {ACL_JSON*} 该值不可能为空,注意用户可以修改该对象的值, + * 但不可以释放该对象 + */ + ACL_JSON* get_json(void) const; + + /** + * 创建一个 json_node 叶结点对象,该结点对象的格式为:tag_name: "tag_value" + * @param tag {const char*} 标签名 + * @param value {const char*} 标签值 + * @return {json_node&} 新产生的 json_node 对象不需要用户手工释放,因为在 + * json 对象被释放时这些结点会自动被释放,当然用户也可以在不用时调用 + * reset 来释放这些 json_node 结点对象 + */ + json_node& create_node(const char* tag, const char* value); + + /** + * 创建一个 json_node 结点容器对象,该对象没有标签, + * 该结点对象的格式为:"{}" 或数组对象 "[]" + * @param as_array {bool} 是否数组对象 + * @return {json_node&} 新产生的 json_node 对象不需要用户手工释放,因为在 + * json 对象被释放时这些结点会自动被释放,当然用户也可以在不用时调用 + * reset 来释放这些 json_node 结点对象 + */ + json_node& create_node(bool as_array = false); + + /** + * 创建一个 json_node 结点对象,该结点对象的格式为:tag_name: {} + * 或 tag_name: [] + * @param tag {const char*} 标签名 + * @param node {json_node*} json 结点对象作为标签值 + * @return {json_node&} 新产生的 json_node 对象不需要用户手工释放,因为在 + * json 对象被释放时这些结点会自动被释放,当然用户也可以在不用时调用 + * reset 来释放这些 json_node 结点对象 + */ + json_node& create_node(const char* tag, json_node* node); + + /** + * 创建一个 json_node 结点对象,该结点对象的格式为:tag_name: {} + * 或 tag_name: [] + * @param tag {const char*} 标签名 + * @param node {json_node&} json 结点对象作为标签值 + * @return {json_node&} 新产生的 json_node 对象不需要用户手工释放,因为在 + * json 对象被释放时这些结点会自动被释放,当然用户也可以在不用时调用 + * reset 来释放这些 json_node 结点对象 + */ + json_node& create_node(const char* tag, json_node& node); + + /** + * 获得根结点对象 + * @return {json_node&} + */ + json_node& get_root(); + + /** + * 开始遍历该 json 对象并获得第一个结点 + * @return {json_node*} 返回空表示该 json 对象为空结点 + * 注:返回的结点对象用户不能手工释放,因为该对象被 + * 内部库自动释放 + */ + json_node* first_node(void); + + /** + * 遍历该 json 对象的下一个 json 结点 + * @return {json_node*} 返回空表示遍历完毕 + * 注:返回的结点对象用户不能手工释放,因为该对象被 + * 内部库自动释放 + */ + json_node* next_node(void); + + /** + * 将 json 对象树转成字符串 + * @param out {string&} 存储转换结果的缓冲区 + */ + void build_json(string& out); + + // pipe_stream 虚函数重载 + + virtual int push_pop(const char* in, size_t len, + string* out, size_t max = 0); + virtual int pop_end(string* out, size_t max = 0); + virtual void clear(void); +private: + // 对应于 acl 库中的 ACL_JSON 对象 + ACL_JSON *json_; + // json 对象树中的根结点对象 + json_node* root_; + // 由该 json 容器分配的 json 结点集合 + std::list nodes_; + // 临时的 json 结点对象 + json_node* node_tmp_; + // 临时的 json 结点查询结果集 + std::vector nodes_tmp_; + // 缓冲区 + string* buf_; + ACL_ITER* iter_; +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/stdlib/locker.hpp b/lib_acl_cpp/include/acl_cpp/stdlib/locker.hpp new file mode 100644 index 000000000..77211f34a --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/stdlib/locker.hpp @@ -0,0 +1,82 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include +#ifndef WIN32 +#include +#endif + +#ifdef WIN32 +struct acl_pthread_mutex_t; +#else +# ifndef acl_pthread_mutex_t +# define acl_pthread_mutex_t pthread_mutex_t +# endif +#endif + +namespace acl { + +/** + * 互斥锁,可以同时创建文件锁和线程锁,也可以只创建一种锁 + */ +class ACL_CPP_API locker +{ +public: + /** + * 构造函数 + * @param use_mutex {bool} 是否创建线程锁 + * @param nowait {bool} 是否一直等待至加锁成功 + * (包括线程锁和文件锁) + */ + locker(bool use_mutex = true, bool nowait = false); + virtual ~locker(); + + /** + * 根据文件路径创建文件锁 + * @param file_path {const char*} 文件路径,非空 + * @return {bool} 是否成功 + * 注:此函数与下面的 open 函数仅能同时调用一个 + */ + bool open(const char* file_path); + + /** + * 根据文件句柄创建文件锁 + * @param fh {int} 文件句柄 + * @return {bool} 是否成功 + */ +#ifdef WIN32 + bool open(void* fh); +#else + bool open(int fh); +#endif + + /** + * 针对已经打开的锁(包括线程锁和文件锁)进行加锁 + * @return {bool} 加锁是否成功 + */ + bool lock(); + + /** + * 针对已经打开的锁(包括线程锁和文件锁)进行解锁 + * @return {bool} 解锁是否成功 + */ + bool unlock(); +protected: +private: + void init_mutex(void); + +#ifndef WIN32 + pthread_mutexattr_t mutexAttr_; +#endif + acl_pthread_mutex_t* pMutex_; + + char* pFile_; +#ifdef WIN32 + void* fHandle_; +#else + int fHandle_; +#endif + bool myFHandle_; + bool nowait_; +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/stdlib/log.hpp b/lib_acl_cpp/include/acl_cpp/stdlib/log.hpp new file mode 100644 index 000000000..8466e7aba --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/stdlib/log.hpp @@ -0,0 +1,172 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include + +#define logger_open acl::log::open +#define logger_close acl::log::close + +#if defined(VC2003) || defined(VC2002) || defined(VC6) +#define logger acl::log::msg1 +#define logger_warn acl::log::warn1 +#define logger_error acl::log::error1 +#define logger_fatal acl::log::fatal1 +#define logger_debug acl::log::msg3 +#elif defined(WIN32) +#define logger(fmt, ...) \ + acl::log::msg4(__FILE__, __LINE__, __FUNCTION__, fmt, __VA_ARGS__) +#define logger_warn(fmt, ...) \ + acl::log::warn4(__FILE__, __LINE__, __FUNCTION__, fmt, __VA_ARGS__) +#define logger_error(fmt, ...) \ + acl::log::error4(__FILE__, __LINE__, __FUNCTION__, fmt, __VA_ARGS__) +#define logger_fatal(fmt, ...) \ + acl::log::fatal4(__FILE__, __LINE__, __FUNCTION__, fmt, __VA_ARGS__) +#define logger_debug(section, level, fmt, ...) \ + acl::log::msg6(section, level, __FILE__, __LINE__, __FUNCTION__, fmt, __VA_ARGS__) +#else +#define logger(fmt, args...) \ + acl::log::msg4(__FILE__, __LINE__, __FUNCTION__, fmt, ##args) +#define logger_warn(fmt, args...) \ + acl::log::warn4(__FILE__, __LINE__, __FUNCTION__, fmt, ##args) +#define logger_error(fmt, args...) \ + acl::log::error4(__FILE__, __LINE__, __FUNCTION__, fmt, ##args) +#define logger_fatal(fmt, args...) \ + acl::log::fatal4(__FILE__, __LINE__, __FUNCTION__, fmt, ##args) +#define logger_debug(section, level, fmt, args...) \ + acl::log::msg6(section, level, __FILE__, __LINE__, __FUNCTION__, fmt, ##args) +#endif + +namespace acl { + +class string; + +class ACL_CPP_API log +{ +public: + /** + * 打开日志文件, 在程序初始化里调用本函数一次 + * @param recipients {const char*} 日志接收器列表,由 "|" 分隔,接收器 + * 可以是本地文件或远程套接口,如: + * /tmp/test.log|UDP:127.0.0.1:12345|TCP:127.0.0.1:12345|UNIX:/tmp/test.sock + * 该配置要求将所有日志同时发给 /tmp/test.log, UDP:127.0.0.1:12345, + * TCP:127.0.0.1:12345 和 UNIX:/tmp/test.sock 四个日志接收器对象 + * @param procname 程序名, 如: test + * @param cfg 日志配置, 格式为: {section}:{level}; {section}:{level}; ... + * 如: 100:2; 101:3; 102: 4, 表示只记录标识为 100/级别 < 2, + * 以及标识为 101/级别 < 3, 以及标识为 102/级别 < 4 的日志项 + */ + static void open(const char* recipients, const char* procname = "unknown", + const char* cfg = NULL); + + /** + * 程序退出前调用此函数关闭日志 + */ + static void close(void); + + /** + * 当未通过 open 打开日志流而调用记日志等相关函数时是否需要将信息 + * 输出至标准输出 + * @param onoff {bool} + */ + static void stdout_open(bool onoff); + + /** + * 日志记录函数 + */ + + static void msg1(const char* fmt, ...); + static void vmsg2(const char* fmt, va_list ap); + static void msg4(const char* fname, int line, const char* func, + const char* fmt, ...); + static void vmsg5(const char* fname, int line, const char* func, + const char* fmt, va_list ap); + static void msg3(size_t section, size_t level, const char* fmt, ...); + static void vmsg4(size_t section, size_t level, const char* fmt, va_list ap); + static void msg6(size_t section, size_t level, const char* fname, + int line, const char* func, const char* fmt, ...); + static void vmsg7(size_t section, size_t level, const char* fname, + int line, const char* func, const char* fmt, va_list ap); + + static void warn1(const char* fmt, ...); + static void vwarn2(const char* fmt, va_list ap); + static void warn4(const char* fname, int line, const char* func, + const char* fmt, ...); + static void vwarn5(const char* fname, int line, const char* func, + const char* fmt, va_list ap); + + static void error1(const char* fmt, ...); + static void verror2(const char* fmt, va_list ap); + static void error4(const char* fname, int line, const char* func, + const char* fmt, ...); + static void verror5(const char* fname, int line, const char* func, + const char* fmt, va_list ap); + + static void fatal1(const char* fmt, ...); + static void vfatal2(const char* fmt, va_list ap); + static void fatal4(const char* fname, int line, const char* func, + const char* fmt, ...); + static void vfatal5(const char* fname, int line, const char* func, + const char* fmt, va_list ap); + + /************************************************************************/ + /* 示例 */ + /************************************************************************/ + static void logger_test1(void) + { +#define DEBUG_BASE 100 +#define DEBUG_TEST1 (DEBUG_BASE + 1) +#define DEBUG_TEST2 (DEBUG_BASE + 2) +#define DEBUG_TEST3 (DEBUG_BASE + 3) + + const char* logfile = "test.log", *procname = "test"; + const char* cfg = "101:2; 102:3; 103:2"; + + // 在程序初始化时打开日志 + logger_open(logfile, procname, cfg); + +#if defined(VC2003) || defined(VC2002) || defined(VC6) + + // 会写日志 + + logger("%s(%d), %s: %s", __FILE__, __LINE__, __FUNCTION__, "zsx"); + + logger_debug(DEBUG_TEST1, 1, "%s(%d), %s: hello world11(%s)!", + __FILE__, __LINE__, __FUNCTION__, "zsx"); + logger_debug(DEBUG_TEST2, 3, "%s(%d), %s: hello world12(%s)!", + __FILE__, __LINE__, __FUNCTION__, "zsx"); + logger_debug(DEBUG_TEST3, 2, "%s(%d), %s: hello world13(%s)!", + __FILE__, __LINE__, __FUNCTION__, "zsx"); + + // 不会写日志 + + logger_debug(DEBUG_TEST1, 3, "%s(%d), %s: hello world21(%s)!", + __FILE__, __LINE__, __FUNCTION__, "zsx"); + +#else // VC2005, VC2008, VC2010 + + // 会写日志 + + logger("error(%s)!", "zsx"); + + logger_debug(DEBUG_TEST1, 1, "hello world11(%s)!", "zsx"); + logger_debug(DEBUG_TEST2, 3, "hello world12(%s)!", "zsx"); + logger_debug(DEBUG_TEST3, 2, "hello world13(%s)!", "zsx"); + + // 不会写日志 + + logger_debug(DEBUG_TEST1, 3, "hello world21(%s)!", "zsx"); + +#endif + + // 程序结束前关闭日志 + logger_close(); + } + static void logger_test2(void) + { + logger("logger ok!"); + logger_warn("logger_warn ok!"); + logger_error("logger_error ok!"); + logger_fatal("logger_fatal ok!"); + } +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/stdlib/malloc.hpp b/lib_acl_cpp/include/acl_cpp/stdlib/malloc.hpp new file mode 100644 index 000000000..0e267c087 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/stdlib/malloc.hpp @@ -0,0 +1,45 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" + +#ifdef HOOK_NEW + +#ifdef WIN32 +# ifdef NDEBUG +void* operator new(size_t n); +void operator delete(void *p); +# endif +#else +#include +void* operator new(size_t n) throw (std::bad_alloc); +void operator delete(void *p) throw(); +#endif + +#endif + +namespace acl { + +ACL_CPP_API void acl_slice_init(void); + +/** + * 内存分配函数 + * @param size {size_t} 需要分配的尺寸大小 + * @param filename {const char*} 源程序名字 + * @param funcname {const char*} 函数名 + * @param lineno {int} 源程序行号 + * @return {void*} 分配的内存地址,如果分配内存失败,则直接abort + */ +ACL_CPP_API void* acl_new(size_t size, const char* filename, + const char* funcname, int lineno); + + +/** + * 释放内存函数 + * @param ptr {void*} 内存地址 + * @param filename {const char*} 源程序名字 + * @param funcname {const char*} 函数名 + * @param lineno {int} 源程序行号 + */ +ACL_CPP_API void acl_delete(void *ptr, const char* filename, + const char* funcname, int lineno); + +} diff --git a/lib_acl_cpp/include/acl_cpp/stdlib/md5.hpp b/lib_acl_cpp/include/acl_cpp/stdlib/md5.hpp new file mode 100644 index 000000000..3a6502355 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/stdlib/md5.hpp @@ -0,0 +1,133 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" + +namespace acl { + +class istream; + +class ACL_CPP_API md5 +{ +public: + md5(); + ~md5(); + + /** + * 可以循环调用此函数添加需要被 md5 的数据 + * @param dat {const void*} 数据地址 + * @param len {size_t} dat 数据长度 + * @return {md5&} + */ + md5& update(const void* dat, size_t len); + + /** + * 必须调用本函数表示 md5 过程结束 + * @return {md5&} + */ + md5& finish(); + + /** + * 重置 md5 算法器的状态,从而允许重复使用同一个 md5 对象 + * @return {md5&} + */ + md5& reset(); + + /** + * 获得二进制格式的 md5 结果值 + * @return {const char*} 返回值永远非空,且缓冲区长度为 16 字节 + */ + const char* get_digest() const; + + /** + * 获得以字符串形式表示的 m5 结果值 + * @return {const char*} 返回值永远非空,且以 \0 结尾,且字符串 + * 长度为 32 字节 + */ + const char* get_string() const; + + /** + * 将数据用 md5 算法计算签名值,取得 128 位 (即 16 字节) 二进制结果 + * @param dat {const void*} 源数据 + * @param dlen {size_t} dat 数据长度 + * @param key {const char*} 非空时做为键数据 + * @param klen {size_t} key 非空时表示 key 的长度 + * @param out {void*} 存储 md5 结果 + * @param size {size_t} out 大小,至少应该为 16 字节 + * @return {const char*} 返回存储结果的地址(即 buf 地址) + */ + static const char* md5_digest(const void *dat, size_t dlen, + const void *key, size_t klen, void* out, size_t size); + + /** + * 将数据用 md5 算法计算签名值,取得字符串形式的结果 + * @param dat {const void*} 源数据 + * @param dlen {size_t} dat 数据长度 + * @param key {const char*} 非空时做为键数据 + * @param klen {size_t} key 非空时表示 key 的长度 + * @param out {void*} 存储 md5 结果 + * @param size {size_t} out 大小,至少应该为 33 字节 + * @return {const char*} 返回存储结果的地址(即 buf 地址), + * 且返回值为以 \0 结尾的 32 字节长度(不含 \0)字符串 + */ + static const char* md5_string(const void *dat, size_t dlen, + const void *key, size_t klen, char* out, size_t size); + + /** + * 将文件中的内容用 md5 算法计算签名值,并取得字符串形式结果 + * @param path {const char*} 文件全路径 + * @param key {const char*} 非空时做为键数据 + * @param klen {size_t} key 非空时表示 key 的长度 + * @param out {void*} 存储 md5 结果 + * @param size {size_t} out 大小,至少应该为 33 字节 + * @return {int64) 返回所读取的文件数据的长度,下列情况下返回 -1 + * 1) 打开文件失败 + * 2) 未从文件中读到数据 + * 3) out 缓冲区大小 size 小于 33 字节长度 + */ +#ifdef WIN32 + static __int64 md5_file(const char* path, const void *key, + size_t klen, char* out, size_t size); +#else + static long long int md5_file(const char* path, const void *key, + size_t klen, char* out, size_t size); +#endif + + /** + * 将文件中的内容用 md5 算法计算签名值,并取得字符串形式结果 + * @param in {istream&} 输入文件流 + * @param key {const char*} 非空时做为键数据 + * @param klen {size_t} key 非空时表示 key 的长度 + * @param out {void*} 存储 md5 结果 + * @param size {size_t} out 大小,至少应该为 33 字节 + * @return {int64) 返回所读取的文件数据的长度,下列情况下返回 -1: + * 1) 未从输入流中读取数据时 + * 2) out 缓冲区大小 size 小于 33 字节长度 + */ +#ifdef WIN32 + static __int64 md5_file(istream& in, const void *key, + size_t klen, char* out, size_t size); +#else + static long long int md5_file(istream& in, const void *key, + size_t klen, char* out, size_t size); +#endif + + /** + * 将 16 字节长度的 MD5 二进制结果转换为 32 字节长度的字符串 + * @param in {const void*} 128 位(即 16 字节)的 md5 值,即 in 的数据长度 + * 至少应该 >= 16,否则会引起内存起越界 + * @param out {char*} 存储字符串形式的结果 + * @param size {size_t} out 内存大小,至少为 33 字节,否则内部产生断言 + * @return {const char*} 返回存储结果的地址(即 out 地址), + * 且返回值为以 \0 结尾的 32 字节长度(不含 \0)字符串 + */ + static const char* hex_encode(const void *in, char* out, size_t size); + +private: + unsigned int buf_[4]; + unsigned int bytes_[2]; + unsigned int in_[16]; + + unsigned char digest_[16]; + unsigned char digest_s_[33]; +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/stdlib/noncopyable.hpp b/lib_acl_cpp/include/acl_cpp/stdlib/noncopyable.hpp new file mode 100644 index 000000000..3f4dccc80 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/stdlib/noncopyable.hpp @@ -0,0 +1,16 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" + +namespace acl { + +class ACL_CPP_API noncopyable +{ +protected: + noncopyable() {} + ~noncopyable() {} +private: + noncopyable( const noncopyable& ); + const noncopyable& operator=( const noncopyable& ); +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/stdlib/pipe_stream.hpp b/lib_acl_cpp/include/acl_cpp/stdlib/pipe_stream.hpp new file mode 100644 index 000000000..8037d8828 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/stdlib/pipe_stream.hpp @@ -0,0 +1,165 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include +#include "acl_cpp/stdlib/string.hpp" + +namespace acl { + +/** + * 双向输入输出缓冲管道流, 该流不仅可接收输入数据,同时还可输出所 + * 输入的数据,纯虚基类,子类需要实现三个接口函数 + */ +class ACL_CPP_API pipe_stream +{ +public: + pipe_stream() {} + virtual ~pipe_stream() {} + + /** + * 数据输入输出接口 + * @param in {const char*} 输入数据的地址 + * @param len {size_t} 输入数据长度 + * @param out {string*} 存储输出结果缓冲区,不能为空 + * @param max {size_t} 希望接收到输出结果的长度限制,如果为0则 + * 表示没有限制,输出结果都存储在 out 缓冲区中 + * @return {int} 输出数据的长度,如果 < 0 则表示出错 + */ + virtual int push_pop(const char* in, size_t len, + string* out, size_t max = 0) = 0; + + /** + * 最后处理的输出数据接口 + * @param out {string*} 存储输出结果缓冲区,不能为空 + * @param max {size_t} 希望接收到输出结果的长度限制,如果为0则 + * 表示没有限制,输出结果都存储在 out 缓冲区中 + * @return {int} 输出数据的长度,如果 < 0 则表示出错 + */ + virtual int pop_end(string* out, size_t max = 0) = 0; + + /** + * 清空内部缓冲区 + */ + virtual void clear() {} +}; + +/** + * 字符串处理双向管理流 + */ +class ACL_CPP_API pipe_string : public pipe_stream +{ +public: + pipe_string(); + pipe_string(string& s); + virtual ~pipe_string(); + + // pipe_stream 基类中的四个虚函数 + virtual int push_pop(const char* in, size_t len, + string* out, size_t max = 0); + virtual int pop_end(string* out, size_t max = 0); + virtual void clear() + { + m_pBuf->clear(); + m_pos = 0; + } + + string& get_buf() const + { + return (*m_pBuf); + } + + char* c_str() const + { + return (m_pBuf->c_str()); + } + + size_t length() const + { + return (m_pBuf->length()); + } + + bool empty() const + { + return (m_pBuf->empty()); + } + +private: + string* m_pBuf; + string* m_pSavedBufPtr; + size_t m_pos; +}; + +/** + * 管道流管理器,该类管理所有的管理流,将数据依次传递给所有管理流的 + * 输入接口,同时从所有管道流的输出接口中获得数据然后再将数据传递给 + * 下一个管道流的输入接口,以此类推,直到最后一个管道流 + */ +class ACL_CPP_API pipe_manager +{ +public: + pipe_manager(); + ~pipe_manager(); + + /** + * 以尾部添加的方式注册新的管道流处理器 + * @param stream {pipe_stream*} 管道流处理器对象 + * @return {bool} 如果该管道流处理器对象已经存在则返回 false + */ + bool push_back(pipe_stream* stream); + + /** + * 以头部添加的方式注册新的管道流处理器 + * @param stream {pipe_stream*} 管道流处理器对象 + * @return {bool} 如果该管道流处理器对象已经存在则返回 false + */ + bool push_front(pipe_stream* stream); + + /** + * 应用向管道流管理器添加新数据,由该管理器依次传递给所有已注册管道流 + * 处理器,同时从已注册管道流处理器接收处理结果,依次传递给下一个 + * @param src {const char*} 待处理的数据地址 + * @param len {size_t} src 数据长度 + * @param out {pipe_stream*} 如果非空,则该管道处理器将是最后一个只接收 + * 输入而不进行输出的管道处理器 + * @return {bool} 是否有错误发生 + */ + bool update(const char* src, size_t len, pipe_stream* out = NULL); + + /** + * 最后必须调用一次该函数,以使有些管道的缓冲区里的数据可以一次性地 + * 刷新至最后的管道中 + * @param out {pipe_stream*} 如果非空,则该管道处理器将是最后一个只接收 + * 输入而不进行输出的管道处理器 + * @return {bool} 是否有错误发生 + */ + bool update_end(pipe_stream* out = NULL); + + pipe_manager& operator<<(const string&); + pipe_manager& operator<<(const string*); + pipe_manager& operator<<(const char*); +#ifdef WIN32 + pipe_manager& operator<<(__int64); + pipe_manager& operator<<(unsigned __int64); +#else + pipe_manager& operator<<(long long int); + pipe_manager& operator<<(unsigned long long int); +#endif + pipe_manager& operator<<(long); + pipe_manager& operator<<(unsigned long); + pipe_manager& operator<<(int); + pipe_manager& operator<<(unsigned int); + pipe_manager& operator<<(short); + pipe_manager& operator<<(unsigned short); + pipe_manager& operator<<(char); + pipe_manager& operator<<(unsigned char); + + char* c_str() const; + size_t length() const; + void clear(); + +private: + std::list m_streams; + string* m_pBuf1, *m_pBuf2; + pipe_string* m_pPipeStream; +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/stdlib/singleton.hpp b/lib_acl_cpp/include/acl_cpp/stdlib/singleton.hpp new file mode 100644 index 000000000..cc16d03fe --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/stdlib/singleton.hpp @@ -0,0 +1,208 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include +#include "acl_cpp/stdlib/noncopyable.hpp" + +// singleton.hpp +// +// Copyright David Abrahams 2006. Original version +// +// Copyright Robert Ramey 2007. Changes made to permit +// application throughout the serialization library. +// +// Distributed under the Boost +// Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// The intention here is to define a template which will convert +// any class into a singleton with the following features: +// +// a) initialized before first use. +// b) thread-safe for const access to the class +// c) non-locking +// +// In order to do this, +// a) Initialize dynamically when used. +// b) Require that all singletons be initialized before main +// is called or any entry point into the shared library is invoked. +// This guarentees no race condition for initialization. +// In debug mode, we assert that no non-const functions are called +// after main is invoked. + +namespace acl { + +#ifdef WIN32 +# pragma warning(push) +# pragma warning(disable : 4511 4512) +#endif + +////////////////////////////////////////////////////////////////////// +// Provides a dynamically-initialized (singleton) instance of T in a +// way that avoids LNK1179 on vc6. See http://tinyurl.com/ljdp8 or +// http://lists.boost.org/Archives/boost/2006/05/105286.php for +// details. +// + +// singletons created by this code are guarenteed to be unique +// within the executable or shared library which creates them. +// This is sufficient and in fact ideal for the serialization library. +// The singleton is created when the module is loaded and destroyed +// when the module is unloaded. + +// This base class has two functions. + +// First it provides a module handle for each singleton indicating +// the executable or shared library in which it was created. This +// turns out to be necessary and sufficient to implement the tables +// used by serialization library. + +// Second, it provides a mechanism to detect when a non-const function +// is called after initialization. + +// make a singleton to lock/unlock all singletons for alteration. +// The intent is that all singletons created/used by this code +// are to be initialized before main is called. A test program +// can lock all the singletons when main is entereed. This any +// attempt to retieve a mutable instances while locked will +// generate a assertion if compiled for debug. + +class singleton_module : public noncopyable +{ +public: + static void lock() + { + get_lock() = true; + } + + static void unlock() + { + get_lock() = false; + } + + static bool is_locked() { + return get_lock(); + } +private: + static bool& get_lock() + { + static bool lock_ = false; + return lock_; + } +}; + +template +class singleton_wrapper : public T +{ +public: + static bool destroyed_; + ~singleton_wrapper() + { + destroyed_ = true; + } +}; + +template +bool singleton_wrapper< T >::destroyed_ = false; + +/** + * 单例模板类,用VC2010或GCC编译时,单例对象在 main 函数之前被执行, + * 所以它是线程安全的;但在 VC2003 编译成 release 版本时且打开了优化 + * 开关,则有可能是线程不安全的,此时不能保证单例对象的构造函数在 + * main 之前执行. + * 使用举例如下: + * class singleton_test : public acl::singleton + * { + * public: + * singleton_test() {} + * ~singleton_test() {} + * singleton_test& init() { return *this; } + * }; + + * int main() + * { + * singleton_test& test = singleton_test::get_instance(); + * test.init(); + * ... + * return 0; + * } + */ +template +class singleton : public singleton_module +{ +public: + ACL_CPP_API static T& get_instance() + { + static singleton_wrapper< T > t; + // refer to instance, causing it to be instantiated (and + // initialized at startup on working compilers) + assert(!singleton_wrapper< T >::destroyed_); + use(instance_); + return static_cast(t); + } + + ACL_CPP_API static bool is_destroyed() + { + return singleton_wrapper< T >::destroyed_; + } + +private: + ACL_CPP_API static T& instance_; + // include this to provoke instantiation at pre-execution time + static void use(T const &) {} +}; + +template +T& singleton< T >::instance_ = singleton< T >::get_instance(); + +////////////////////////////////////////////////////////////////////////// + +/** + * 上面的实现在 VC2003 的 release 编译时如果打开了优化开关,则不能保证单例 + * 的构造函数先于 main 执行,如果是在 VC2003 下编译单例程序且在多个线程下 + * 都用单例对象时,建议使用如下的单例模板类,示例如下: + * class singleton_test + * { + * public: + * singleton_test() {} + * ~singleton_test() {} + * singleton_test& init() { return *this; } + * }; + + * int main() + * { + * singleton_test& test = acl::singleton2::get_instance(); + * test.init(); + * ... + * return 0; + * } + * + */ +template +struct singleton2 +{ +private: + struct object_creator + { + object_creator() { singleton2::get_instance(); } + inline void do_nothing() const {}; + }; + static object_creator create_object; + +public: + typedef T object_type; + static object_type & get_instance() + { + static object_type obj; + create_object.do_nothing(); + return obj; + } +}; + +template +typename singleton2::object_creator singleton2::create_object; + +#ifdef WIN32 +#pragma warning(pop) +#endif + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/stdlib/snprintf.hpp b/lib_acl_cpp/include/acl_cpp/stdlib/snprintf.hpp new file mode 100644 index 000000000..75344945a --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/stdlib/snprintf.hpp @@ -0,0 +1,14 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" + +#ifdef WIN32 +#include + +namespace acl { + +ACL_CPP_API int snprintf(char *buf, size_t size, const char *fmt, ...); +ACL_CPP_API int vsnprintf(char *buf, size_t size, const char *fmt, va_list ap); + +} + +#endif diff --git a/lib_acl_cpp/include/acl_cpp/stdlib/string.hpp b/lib_acl_cpp/include/acl_cpp/stdlib/string.hpp new file mode 100644 index 000000000..464681374 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/stdlib/string.hpp @@ -0,0 +1,1001 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include +#include +#include + +struct ACL_VSTRING; + +namespace acl { + +/** + * 该类为字符串处理类,支持大部分 std::string 中的功能,同时支持其不支持的一些 + * 功能;该类内部自动保证最后一个字符为 \0 + */ +class ACL_CPP_API string +{ +public: + /** + * 构造函数 + * @param n {size_t} 初始时分配的内存大小 + * @param bin {bool} 是否以二进制方式构建缓冲区对象,该值为 true 时, + * 则当调用 += int|int64|short|char 或调用 << int|int64|short|char + * 时,则按二进制方式处理,否则按文本方式处理 + */ + string(size_t n = 64, bool bin = false); + + /** + * 构造函数 + * @param s {const string&} 源字符串对象,初始化后的类对象内部自动复制该字符串 + */ + string(const string& s); + + /** + * 构造函数 + * @param s {const char*} 内部自动用该字符串初始化类对象,s 必须是以 \0 结尾 + */ + string(const char* s); + + /** + * 构造函数 + * @param s {const char*} 源缓冲内容 + * @param n {size_t} s 缓冲区数据长度 + */ + string(const void* s, size_t n); + ~string(void); + + /** + * 设置字符串类对象为二进制处理模式 + * @param bin {bool} 当该值为 true 时,则设置字符串类对象为二进制处理方式; + * 否则为文本方式;该值为 true 时,则当调用 += int|int64|short|char + * 或调用 << int|int64|short|char 时,则按二进制方式处理,否则按文本方式处理 + */ + void set_bin(bool bin); + + /** + * 判断当前字符串类对象是否为二进制处理方式 + * @return {bool} 返回值为 true 时则表示为二进制方式 + */ + bool get_bin() const; + + /** + * 根据字符数组下标获得指定位置的字符,输入参数必须为合法值,否则则内部产生断言 + * @param n {size_t} 指定的位置(该值 >= 0 且 < 字符串长度),如果越界,则产生断言 + * @return {char} 返回指定位置的字符 + */ + char operator[](size_t n); + + /** + * 根据字符数组下标获得指定位置的字符,输入参数必须为合法值,否则则内部产生断言 + * @param n {int} 指定的位置(该值 >= 0 且 < 字符串长度),如果越界,则产生断言 + * @return {char} 返回指定位置的字符 + */ + char operator[](int n); + + /** + * 对目标字符串类对象赋值 + * @param s {const char*} 源字符串 + * @return {string&} 返回当前字符串类对象的引用,便于对该类对象连续进行操作 + */ + string& operator=(const char* s); + + /** + * 对目标字符串类对象赋值 + * @param s {const string&} 源字符串对象 + * @return {string&} 返回当前字符串类对象的引用,便于对该类对象连续进行操作 + */ + string& operator=(const string&); + + /** + * 对目标字符串类对象赋值 + * @param s {const string*} 源字符串对象 + * @return {string&} 返回当前字符串类对象的引用,便于对该类对象连续进行操作 + */ + string& operator=(const string*); + +#ifdef WIN32 + /** + * 对目标字符串类对象赋值 + * @param n {long long int} 源 64 位符号长整数,若字符串对象的当前状态为 + * 二进制模式,则该函数便会以二进制方式赋值给字符串对象,否则以文本方式赋值给 + * 字符串对象;关于二进制模式还是文本方式,其含义参见 set_bin(bool) + * @return {string&} 返回当前字符串类对象的引用,便于对该类对象连续进行操作 + */ + string& operator=(__int64 n); + + /** + * 对目标字符串类对象赋值 + * @param n {unsinged long long int} 源 64 位无符号长整数,若字符串对象 + * 的当前状态为二进制模式,则该函数便会以二进制方式赋值给字符串对象,否则以文本方式 + * 赋值给字符串对象;关于二进制模式还是文本方式,其含义参见 set_bin(bool) + * @return {string&} 返回当前字符串类对象的引用,便于对该类对象连续进行操作 + */ + string& operator=(unsigned __int64); +#else + string& operator=(long long int); + string& operator=(unsigned long long int); +#endif + + /** + * 对目标字符串类对象赋值 + * @param n {char} 源有符号字符;若字符串对象的当前状态为二进制模式,则该函数 + * 便会以二进制方式赋值给字符串对象,否则以文本方式赋值给字符串对象;关于二进制模 + * 式还是文本方式,其含义参见 set_bin(bool) + * @return {string&} 返回当前字符串类对象的引用,便于对该类对象连续进行操作 + */ + string& operator=(char n); + + /** + * 对目标字符串类对象赋值 + * @param n {char} 源无符号字符;若字符串对象的当前状态为二进制模式,则该函数 + * 便会以二进制方式赋值给字符串对象,否则以文本方式赋值给字符串对象;关于二进制模 + * 式还是文本方式,其含义参见 set_bin(bool) + * @return {string&} 返回当前字符串类对象的引用,便于对该类对象连续进行操作 + */ + string& operator=(unsigned char n); + + /** + * 对目标字符串类对象赋值 + * @param n {char} 源有符号长整型;若字符串对象的当前状态为二进制模式,则该函数 + * 便会以二进制方式赋值给字符串对象,否则以文本方式赋值给字符串对象;关于二进制模 + * 式还是文本方式,其含义参见 set_bin(bool) + * @return {string&} 返回当前字符串类对象的引用,便于对该类对象连续进行操作 + */ + string& operator=(long n); + + /** + * 对目标字符串类对象赋值 + * @param n {char} 源无符号长整型;若字符串对象的当前状态为二进制模式,则该函数 + * 便会以二进制方式赋值给字符串对象,否则以文本方式赋值给字符串对象;关于二进制模 + * 式还是文本方式,其含义参见 set_bin(bool) + * @return {string&} 返回当前字符串类对象的引用,便于对该类对象连续进行操作 + */ + string& operator=(unsigned long n); + + /** + * 对目标字符串类对象赋值 + * @param n {char} 源有符号整型;若字符串对象的当前状态为二进制模式,则该函数 + * 便会以二进制方式赋值给字符串对象,否则以文本方式赋值给字符串对象;关于二进制模 + * 式还是文本方式,其含义参见 set_bin(bool) + * @return {string&} 返回当前字符串类对象的引用,便于对该类对象连续进行操作 + */ + string& operator=(int n); + + /** + * 对目标字符串类对象赋值 + * @param n {char} 源无符号整型;若字符串对象的当前状态为二进制模式,则该函数 + * 便会以二进制方式赋值给字符串对象,否则以文本方式赋值给字符串对象;关于二进制模 + * 式还是文本方式,其含义参见 set_bin(bool) + * @return {string&} 返回当前字符串类对象的引用,便于对该类对象连续进行操作 + */ + string& operator=(unsigned int n); + + /** + * 对目标字符串类对象赋值 + * @param n {char} 源有符号短整型;若字符串对象的当前状态为二进制模式,则该函数 + * 便会以二进制方式赋值给字符串对象,否则以文本方式赋值给字符串对象;关于二进制模 + * 式还是文本方式,其含义参见 set_bin(bool) + * @return {string&} 返回当前字符串类对象的引用,便于对该类对象连续进行操作 + */ + string& operator=(short n); + + /** + * 对目标字符串类对象赋值 + * @param n {char} 源无符号短整型;若字符串对象的当前状态为二进制模式,则该函数 + * 便会以二进制方式赋值给字符串对象,否则以文本方式赋值给字符串对象;关于二进制模 + * 式还是文本方式,其含义参见 set_bin(bool) + * @return {string&} 返回当前字符串类对象的引用,便于对该类对象连续进行操作 + */ + string& operator=(unsigned short n); + + /** + * 向目标字符串对象尾部添加字符串 + * @param s {const char*} 源字符串指针 + * @return {string&} 目标字符串对象的引用 + */ + string& operator+=(const char* s); + + /** + * 向目标字符串对象尾部添加字符串 + * @param s {const string&} 源字符串对象引用 + * @return {string&} 目标字符串对象的引用 + */ + string& operator+=(const string& s); + + /** + * 向目标字符串对象尾部添加字符串 + * @param s {const string*} 源字符串对象指针 + * @return {string&} 目标字符串对象的引用 + */ + string& operator+=(const string*); +#ifdef WIN32 + /** + * 向目标字符串对象尾部添加有符号长整型数字,当为目标字符串对象为 + * 二进制方式时,则按二进制数字方式添加;否则按文本方式添加 + * @param n {long long int} 源 64 位有符号整数 + * @return {string&} 目标字符串对象的引用 + */ + string& operator+=(__int64 n); + + /** + * 向目标字符串对象尾部添加无符号长整型数字,当为目标字符串对象为 + * 二进制方式时,则按二进制数字方式添加;否则按文本方式添加 + * @param n {long long int} 源 64 位无符号整数 + * @return {string&} 目标字符串对象的引用 + */ + string& operator+=(unsigned __int64 n); +#else + string& operator+=(long long int n); + string& operator+=(unsigned long long int n); +#endif + + /** + * 向目标字符串对象尾部添加有符号长整型数字,当为目标字符串对象为 + * 二进制方式时,则按二进制数字方式添加;否则按文本方式添加 + * @param n {long} 源有符号长整数 + * @return {string&} 目标字符串对象的引用 + */ + string& operator+=(long n); + + /** + * 向目标字符串对象尾部添加无符号长整型数字,当为目标字符串对象为 + * 二进制方式时,则按二进制数字方式添加;否则按文本方式添加 + * @param n {long} 源无符号长整数 + * @return {string&} 目标字符串对象的引用 + */ + string& operator+=(unsigned long n); + + /** + * 向目标字符串对象尾部添加有符号整型数字,当为目标字符串对象为 + * 二进制方式时,则按二进制数字方式添加;否则按文本方式添加 + * @param n {long} 源有符号整数 + * @return {string&} 目标字符串对象的引用 + */ + string& operator+=(int n); + + /** + * 向目标字符串对象尾部添加无符号整型数字,当为目标字符串对象为 + * 二进制方式时,则按二进制数字方式添加;否则按文本方式添加 + * @param n {long} 源无符号整数 + * @return {string&} 目标字符串对象的引用 + */ + string& operator+=(unsigned int n); + + /** + * 向目标字符串对象尾部添加有符号短整型数字,当为目标字符串对象为 + * 二进制方式时,则按二进制数字方式添加;否则按文本方式添加 + * @param n {long} 源有符号短整数 + * @return {string&} 目标字符串对象的引用 + */ + string& operator+=(short n); + + /** + * 向目标字符串对象尾部添加无符号短整型数字,当为目标字符串对象为 + * 二进制方式时,则按二进制数字方式添加;否则按文本方式添加 + * @param n {long} 源无符号短整数 + * @return {string&} 目标字符串对象的引用 + */ + string& operator+=(unsigned short); + + /** + * 向目标字符串对象尾部添加有符号字符,当为目标字符串对象为 + * 二进制方式时,则按二进制数字方式添加;否则按文本方式添加 + * @param n {long} 源有符号字符 + * @return {string&} 目标字符串对象的引用 + */ + string& operator+=(char n); + + /** + * 向目标字符串对象尾部添加无符号字符,当为目标字符串对象为 + * 二进制方式时,则按二进制数字方式添加;否则按文本方式添加 + * @param n {long} 源无符号字符 + * @return {string&} 目标字符串对象的引用 + */ + string& operator+=(unsigned char n); + + /** + * 向目标字符串对象尾部添加字符串 + * @param s {const string&} 源字符串对象引用 + * @return {string&} 目标字符串对象的引用 + */ + string& operator<<(const string& s); + + /** + * 向目标字符串对象尾部添加字符串 + * @param s {const string*} 源字符串对象指针 + * @return {string&} 目标字符串对象的引用 + */ + string& operator<<(const string* s); + + /** + * 向目标字符串对象尾部添加字符串 + * @param s {const char*} 源字符串指针 + * @return {string&} 目标字符串对象的引用 + */ + string& operator<<(const char* s); +#ifdef WIN32 + /** + * 向目标字符串对象尾部添加有符号长整型数字,当为目标字符串对象为 + * 二进制方式时,则按二进制数字方式添加;否则按文本方式添加 + * @param n {long long int} 源 64 位有符号整数 + * @return {string&} 目标字符串对象的引用 + */ + string& operator<<(__int64 n); + + /** + * 向目标字符串对象尾部添加无符号长整型数字,当为目标字符串对象为 + * 二进制方式时,则按二进制数字方式添加;否则按文本方式添加 + * @param n {long long int} 源 64 位无符号整数 + * @return {string&} 目标字符串对象的引用 + */ + string& operator<<(unsigned __int64 n); +#else + string& operator<<(long long int n); + string& operator<<(unsigned long long int n); +#endif + + /** + * 向目标字符串对象尾部添加有符号长整型数字,当为目标字符串对象为 + * 二进制方式时,则按二进制数字方式添加;否则按文本方式添加 + * @param n {long} 源有符号长整数 + * @return {string&} 目标字符串对象的引用 + */ + string& operator<<(long n); + + /** + * 向目标字符串对象尾部添加无符号长整型数字,当为目标字符串对象为 + * 二进制方式时,则按二进制数字方式添加;否则按文本方式添加 + * @param n {long} 源无符号长整数 + * @return {string&} 目标字符串对象的引用 + */ + string& operator<<(unsigned long n); + + /** + * 向目标字符串对象尾部添加有符号整型数字,当为目标字符串对象为 + * 二进制方式时,则按二进制数字方式添加;否则按文本方式添加 + * @param n {long} 源有符号整数 + * @return {string&} 目标字符串对象的引用 + */ + string& operator<<(int n); + + /** + * 向目标字符串对象尾部添加无符号整型数字,当为目标字符串对象为 + * 二进制方式时,则按二进制数字方式添加;否则按文本方式添加 + * @param n {long} 源无符号整数 + * @return {string&} 目标字符串对象的引用 + */ + string& operator<<(unsigned int n); + + /** + * 向目标字符串对象尾部添加有符号短整型数字,当为目标字符串对象为 + * 二进制方式时,则按二进制数字方式添加;否则按文本方式添加 + * @param n {long} 源有符号短整数 + * @return {string&} 目标字符串对象的引用 + */ + string& operator<<(short n); + + /** + * 向目标字符串对象尾部添加无符号短整型数字,当为目标字符串对象为 + * 二进制方式时,则按二进制数字方式添加;否则按文本方式添加 + * @param n {long} 源无符号短整数 + * @return {string&} 目标字符串对象的引用 + */ + string& operator<<(unsigned short n); + + /** + * 向目标字符串对象尾部添加有符号字符,当为目标字符串对象为 + * 二进制方式时,则按二进制数字方式添加;否则按文本方式添加 + * @param n {long} 源有符号字符 + * @return {string&} 目标字符串对象的引用 + */ + string& operator<<(char n); + + /** + * 向目标字符串对象尾部添加无符号字符,当为目标字符串对象为 + * 二进制方式时,则按二进制数字方式添加;否则按文本方式添加 + * @param n {long} 源无符号字符 + * @return {string&} 目标字符串对象的引用 + */ + string& operator<<(unsigned char n); + + /** + * 将字符串对象中的内容赋予目标字符串对象 + * @param s {string*} 目标字符串对象 + * @return {string&} 源字符串对象的引用 + */ + string& operator>>(string* s); +#ifdef WIN32 + /** + * 将字符串对象中的内容赋予目标 64 位有符号整数 + * @param n {string*} 目标 64 位有符号整数 + * @return {string&} 源字符串对象的引用 + */ + string& operator>>(__int64& n); + + /** + * 将字符串对象中的内容赋予目标 64 位无符号整数 + * @param n {string*} 目标 64 位无符号整数 + * @return {string&} 源字符串对象的引用 + */ + string& operator>>(unsigned __int64& n); +#else + string& operator>>(long long int&); + string& operator>>(unsigned long long int&); +#endif + + /** + * 将字符串对象中的内容赋予目标 32 位有符号整数 + * @param n {string*} 目标 32 位有符号整数 + * @return {string&} 源字符串对象的引用 + */ + string& operator>>(int& n); + + /** + * 将字符串对象中的内容赋予目标 32 位无符号整数 + * @param n {string*} 目标 32 位无符号整数 + * @return {string&} 源字符串对象的引用 + */ + string& operator>>(unsigned int& n); + + /** + * 将字符串对象中的内容赋予目标 16 位有符号整数 + * @param n {string*} 目标 16 位有符号整数 + * @return {string&} 源字符串对象的引用 + */ + string& operator>>(short& n); + + /** + * 将字符串对象中的内容赋予目标 16 位无符号整数 + * @param n {string*} 目标 16 位无符号整数 + * @return {string&} 源字符串对象的引用 + */ + string& operator>>(unsigned short& n); + + /** + * 将字符串对象中的内容赋予目标 8 位有符号字符 + * @param n {string*} 目标 16 位有符号字符 + * @return {string&} 源字符串对象的引用 + */ + string& operator>>(char& n); + + /** + * 将字符串对象中的内容赋予目标 8 位无符号字符 + * @param n {string*} 目标 16 位无符号字符 + * @return {string&} 源字符串对象的引用 + */ + string& operator>>(unsigned char& n); + + /** + * 判断当前字符串对象的内容与所给的字符串对象内容是否相等(内部区分大小写) + * @param s {const string&} 输入的字符串对象引用 + * @return {bool} 返回 true 表示字符串内容相同 + */ + bool operator==(const string& s) const; + + /** + * 判断当前字符串对象的内容与所给的字符串对象内容是否相等(内部区分大小写) + * @param s {const string&} 输入的字符串对象指针 + * @return {bool} 返回 true 表示字符串内容相同 + */ + bool operator==(const string* s) const; + + /** + * 判断当前字符串对象的内容与所给的字符串内容是否相等(内部区分大小写) + * @param s {const string&} 输入的字符串对象指针 + * @return {bool} 返回 true 表示字符串内容相同 + */ + bool operator==(const char* s) const; + + /** + * 判断当前字符串对象的内容与所给的字符串对象内容是否不等(内部区分大小写) + * @param s {const string&} 输入的字符串对象引用 + * @return {bool} 返回 true 表示字符串内容不同 + */ + bool operator!=(const string& s) const; + + /** + * 判断当前字符串对象的内容与所给的字符串对象内容是否不等(内部区分大小写) + * @param s {const string&} 输入的字符串对象指针 + * @return {bool} 返回 true 表示字符串内容不同 + */ + bool operator!=(const string* s) const; + + /** + * 判断当前字符串对象的内容与所给的字符串内容是否不等(内部区分大小写) + * @param s {const string&} 输入的字符串对象指针 + * @return {bool} 返回 true 表示字符串内容不同 + */ + bool operator!=(const char*) const; + + /** + * 判断当前字符串对象的内容是否小于所给的字符串对象内容(内部区分大小写) + * @param s {const string&} 输入的字符串对象引用 + * @return {bool} 返回 true 表示当前字符串对象的内容小于输入的字符串 + * 对象内容 + */ + bool operator<(const string&) const; + + /** + * 判断当前字符串对象的内容是否大于所给的字符串对象内容(内部区分大小写) + * @param s {const string&} 输入的字符串对象引用 + * @return {bool} 返回 true 表示当前字符串对象的内容大于输入的字符串 + * 对象内容 + */ + bool operator>(const string&) const; + + /** + * 将当前字符串对象直接转为字符串指针(即将内部缓冲区直接导出) + * @return {const char*} 返回值永远为非空指针,有可能为空串 + */ + operator const char*() const; + + /** + * 将当前字符串对象直接转为通用指针(即将内部缓冲区直接导出) + * @return {const char*} 返回值永远为非空指针 + */ + operator const void*() const; + + /** + * 将一个有符号字符添加进当前字符串对象的尾部 + * @param ch {char} 有符号字符 + * @return {string&} 当前字符串对象的引用 + */ + string& push_back(char ch); + + /** + * 比较两个字符串对象的内容是否相同(区分大小写) + * @param s {const string&} 输入的字符串对象的引用 + * @return {int} 0:表示二者相同; > 0:当前字符串内容大于输入的内容; + * < 0 :当前字符串内容小于输入的内容 + */ + int compare(const string& s) const; + + /** + * 比较两个字符串对象的内容是否相同(区分大小写) + * @param s {const string&} 输入的字符串对象的指针 + * @return {int} 0:表示二者相同; > 0:当前字符串内容大于输入的内容; + * < 0 :当前字符串内容小于输入的内容 + */ + int compare(const string* s) const; + + /** + * 比较两个字符串的内容是否相同 + * @param s {const string&} 输入的字符串对象的引用 + * @param case_sensitive {bool} 为 true 表示区分大小写 + * @return {int} 0:表示二者相同; > 0:当前字符串内容大于输入的内容; + * < 0 :当前字符串内容小于输入的内容 + */ + int compare(const char* s, bool case_sensitive = true) const; + + /** + * 比较当前对象的缓冲区内容是否与所给的缓冲区的内容相同 + * @param ptr {const void*} 输入的缓冲区地址 + * @param len {size_t} ptr 的缓冲区内数据长度 + * @return {int} 0:表示二者相同; > 0:当前对象缓冲区内容大于输入的内容; + * < 0 :当前对象缓冲内容小于输入的内容 + */ + int compare(const void* ptr, size_t len) const; + + /** + * 比较当前对象的缓冲区内容是否与所给的缓冲区的内容相同,限定比较数据长度 + * @param s {const void*} 输入的缓冲区地址 + * @param len {size_t} ptr 的缓冲区内数据长度 + * @param case_sensitive {bool} 为 true 表示区分大小写 + * @return {int} 0:表示二者相同; > 0:当前对象缓冲区内容大于输入的内容; + * < 0 :当前对象缓冲内容小于输入的内容 + */ + int ncompare(const char* s, size_t len, bool case_sensitive = true) const; + + /** + * 从尾部向前比较当前对象的缓冲区内容是否与所给的缓冲区的内容相同,限定比较数据长度 + * @param s {const void*} 输入的缓冲区地址 + * @param len {size_t} ptr 的缓冲区内数据长度 + * @param case_sensitive {bool} 为 true 表示区分大小写 + * @return {int} 0:表示二者相同; > 0:当前对象缓冲区内容大于输入的内容; + * < 0 :当前对象缓冲内容小于输入的内容 + */ + int rncompare(const char* s, size_t len, bool case_sensitive = true) const; + + /** + * 查找指定字符在当前对象缓冲区的位置(下标从 0 开始) + * @param n {char} 要查找的有符号字符 + * @return {int} 字符在缓冲区中的位置,若返回值 < 0 则表示不存在 + */ + int find(char n) const; + + /** + * 查找指定字符吕在当前对象缓冲区的起始位置(下标从 0 开始) + * @param needle {const char*} 要查找的有符号字符串 + * @param case_sensitive {bool} 为 true 表示区分大小写 + * @return {const char*} 字符串在缓冲区中的起始位置,若返回值为空指针则表示不存在 + */ + const char* find(const char* needle, bool case_sensitive=true) const; + + /** + * 从尾部向前查找指定字符吕在当前对象缓冲区的起始位置(下标从 0 开始) + * @param needle {const char*} 要查找的有符号字符串 + * @param case_sensitive {bool} 为 true 表示区分大小写 + * @return {const char*} 字符串在缓冲区中的起始位置,若返回值为空指针则表示不存在 + */ + const char* rfind(const char* needle, bool case_sensitive=true) const; + + /** + * 返回从当前字符串对象中缓冲区指定位置以左的内容 + * @param size_t {npos} 下标位置,当该值大于等于当前字符串的数据长度时, + * 则返回整个字符串对象;返回值不包含该值指定位置的字符内容 + * @return {const string} 返回值为一完整的对象,不需要单独释放,该函数的效率 + * 可能并不太高 + */ + const string left(size_t npos); + + /** + * 返回从当前字符串对象中缓冲区指定位置以右的内容 + * @param size_t {npos} 下标位置,当该值大于等于当前字符串的数据长度时, + * 则返回的字符串对象内容为空;返回值不包含该值指定位置的字符内容 + * @return {const string} 返回值为一完整的对象,不需要单独释放,该函数的效率 + * 可能并不太高 + */ + const string right(size_t npos); + + /** + * 将当前对象的缓冲内容拷贝一部分数据至目标缓冲内 + * @param buf {void*} 目标缓冲区地址 + * @param size {size_t} buf 缓冲区长度 + * @return {string&} 当前对象的引用 + */ + string& scan_buf(void* buf, size_t size); + + /** + * 返回当前对象缓冲区中第一个不含数据的尾部地址 + * @return {char*} 返回值为 NULL 则可能是内部出错了 + */ + char* buf_end(void); + + /** + * 返回当前对象缓冲区的起始地址 + * @return {void*} 返回地址永远非空 + */ + void* buf() const; + + /** + * 以字符串方式返回当前对象缓冲区的起始地址 + * @return {char*} 返回地址永远非空 + */ + char* c_str() const; + + /** + * 返回当前对象字符串的长度(不含\0) + * @return {size_t} 返回值 >= 0 + */ + size_t length() const; + + /** + * 返回当前对象字符串的长度(不含\0),功能与 length 相同 + * @return {size_t} 返回值 >= 0 + */ + size_t size() const; + + /** + * 返回当前对象的缓冲区的空间长度,该值 >= 缓冲区内数据长度 + * @return {size_t} 返回值 > 0 + */ + size_t capacity() const; + + /** + * 判断当前对象的缓冲区内数据长度是否为 0 + * @return {bool} 返回 true 表示数据为空 + */ + bool empty() const; + + /** + * 返回当前对象内部所用的 acl C 库中的 ACL_VSTRING 对象地址 + * @return {ACL_VSTRING*} 返回值永远非空 + */ + ACL_VSTRING* vstring(void) const; + + /** + * 将当前对象的缓冲区的下标位置移至指定位置 + * @param n {size_t} 目标下标位置,当该值 >= capacity 时,内部会 + * 重新分配更大些的内存 + * @return {string&} 当前对象的引用 + */ + string& set_offset(size_t n); + + /** + * 调用该函数可以预先保证所需要的缓冲区大小 + * @param n {size_t} 希望的缓冲区空间大小值 + * @return {string&} 当前对象的引用 + */ + string& space(size_t n); + + /** + * 将当前对象存储的字符串进行分割 + * @param sep {const char*} 进行分割时的分割标记 + * @return {const std::list&} 返回 list 格式的分割结果 + */ + const std::list& split(const char* sep); + + /** + * 将当前对象存储的字符串进行分割 + * @param sep {const char*} 进行分割时的分割标记 + * @return {const std::vector&} 返回 vector 格式的分割结果 + */ + const std::vector& split2(const char*); + + /** + * 以 '=' 为分隔符将当前对象存储的字符串分割成 name/value 对,分割时会自动 + * 去掉源字符串的起始处、结尾处以及分隔符 '=' 两边的空格及 TAB + * @return {const std::pair&} 如果当前对象存储的字符串 + * 不符合分割条件(即不是严格的 name=value格式),则返回的结果中字符串对象为空串 + */ + const std::pair& split_nameval(void); + + /** + * 将字符串拷贝到当前对象的缓冲区中 + * @param ptr {const char*} 源字符串地址,需以 '\0' 结束 + * @return {string&} 当前对象的引用 + */ + string& copy(const char* ptr); + + /** + * 将源数据的定长数据拷贝至当前对象的缓冲区中 + * @param ptr {const void*} 源数据地址 + * @param len {size_t} ptr 源数据长度 + * @return {string&} 当前对象的引用 + */ + string& copy(const void* ptr, size_t len); + + /** + * 将源字符串的数据移动至当前对象的缓冲区中,内部会自动判断源数据 + * 地址是否就在当前对象的缓冲区中 + * @param src {const char*} 源数据地址 + * @return {string&} 当前对象的引用 + */ + string& memmove(const char* src); + + /** + * 将源字符串的数据移动至当前对象的缓冲区中,内部会自动判断源数据 + * 地址是否就在当前对象的缓冲区中 + * @param src {const char*} 源数据地址 + * @param len {size_t} 移动数据的长度 + * @return {string&} 当前对象的引用 + */ + string& memmove(const char* src, size_t len); + + /** + * 将指定字符串添加在当前对象数据缓冲区数据的尾部 + * @param s {const string&} 源数据对象引用 + * @return {string&} 当前对象的引用 + */ + string& append(const string& s); + + /** + * 将指定字符串添加在当前对象数据缓冲区数据的尾部 + * @param s {const string&} 源数据对象指针 + * @return {string&} 当前对象的引用 + */ + string& append(const string* s); + + /** + * 将指定字符串添加在当前对象数据缓冲区数据的尾部 + * @param s {const string&} 源数据对象指针 + * @return {string&} 当前对象的引用 + */ + string& append(const char* s); + + /** + * 将指定缓冲区中的数据添加在当前对象数据缓冲区数据的尾部 + * @param ptr {const void*} 源数据对象指针 + * @param len {size_t} ptr 数据长度 + * @return {string&} 当前对象的引用 + */ + string& append(const void* ptr, size_t len); + + /** + * 将指定字符串数据添加在当前对象数据缓冲区数据的首部 + * @param s {const char*} 源数据地址 + * @return {string&} 当前对象的引用 + */ + string& prepend(const char* s); + + /** + * 将指定内存数据添加在当前对象数据缓冲区数据的首部 + * @param ptr {const void*} 源数据地址 + * @param len {size_t} ptr 数据长度 + * @return {string&} 当前对象的引用 + */ + string& prepend(const void* ptr, size_t len); + + /** + * 将内存数据插入指定下标位置开始的当前对象缓冲区中 + * @param start {size_t} 当前对象缓冲区的开始插入下标值 + * @param ptr {const void*} 内存数据的地址 + * @param len {size_t} 内存数据的长度 + * @return {string&} 当前对象的引用 + */ + string& insert(size_t start, const void* ptr, size_t len); + + /** + * 带格式方式的添加数据(类似于 sprintf 接口方式) + * @param fmt {const char*} 格式字符串 + * @param ... 变参数据 + * @return {string&} 当前对象的引用 + */ + string& format(const char* fmt, ...); + + /** + * 带格式方式的添加数据(类似于 vsprintf 接口方式) + * @param fmt {const char*} 格式字符串 + * @param ap {va_list} 变参数据 + * @return {string&} 当前对象的引用 + */ + string& vformat(const char* fmt, va_list ap); + + /** + * 带格式方式在当前对象的尾部添加数据 + * @param fmt {const char*} 格式字符串 + * @param ... 变参数据 + * @return {string&} 当前对象的引用 + */ + string& format_append(const char* fmt, ...); + + /** + * 带格式方式在当前对象的尾部添加数据 + * @param fmt {const char*} 格式字符串 + * @param ap {va_list} 变参数据 + * @return {string&} 当前对象的引用 + */ + string& vformat_append(const char* fmt, va_list ap); + + /** + * 将当前对象中的数据的字符进行替换 + * @param from {char} 源字符 + * @param to {char} 目标字符 + * @return {string&} 当前对象的引用 + */ + string& replace(char from, char to); + + /** + * 将当前对象的数据截短,缓冲区内部移动下标指针地址 + * @param n {size_t} 数据截短后的数据长度,如果该值 >= 当前缓冲区 + * 数据长度,则内部不做任何变化 + * @return {string&} 当前对象的引用 + */ + string& truncate(size_t n); + + /** + * 在当前对象的缓冲区数据中去掉指定的字符串内容,在处理过程中会发生数据移动情况 + * @param needle {const char*} 指定需要去掉的字符串数据 + * @param each {bool} 是否去掉所有的指定字符串数据 + * @return {string&} 当前对象的引用 + */ + string& strip(const char* needle, bool each = false); + + /** + * 清空当前对象的数据缓冲区 + * @return {string&} 当前对象的引用 + */ + string& clear(); + + /** + * 将当前对象的数据缓冲区中的数据均转为小写 + * @return {string&} 当前对象的引用 + */ + string& lower(void); + + /** + * 将当前对象的数据缓冲区中的数据均转为大写 + * @return {string&} 当前对象的引用 + */ + string& upper(void); + + /** + * 将当前对象的数据缓冲区中的数据进行 base64 转码 + * @return {string&} 当前对象的引用 + */ + string& base64_encode(void); + + /** + * 将输入的源数据进行 base64 转码并存入当前对象的缓冲区中 + * @param ptr {const void*} 源数据的地址 + * @param len {size_t} 源数据长度 + * @return {string&} 当前对象的引用 + */ + string& base64_encode(const void* ptr, size_t len); + + /** + * 如果当前对象的缓冲区中的数据是经 base64 编码的,则此函数将这些数据进行解码 + * @return {string&} 当前对象的引用 + */ + string& base64_decode(void); + + /** + * 将输入的 base64 编码的数据进行解码并存入当前对象的缓冲区中 + * @param s {const char*} 经 base64 编码的源数据 + * @return {string&} 当前对象的引用 + */ + string& base64_decode(const char* s); + + /** + * 将输入的 base64 编码的数据进行解码并存入当前对象的缓冲区中 + * @param ptr {const void*} 经 base64 编码的源数据 + * @param len {size_t} ptr 数据长度 + * @return {string&} 当前对象的引用 + */ + string& base64_decode(const void* ptr, size_t len); + + /** + * 将输入的源数据进行 url 编码并存入当前对象的缓冲区中 + * @param s {const char*} 源数据 + * @return {string&} 当前对象的引用 + */ + string& url_encode(const char* s); + + /** + * 将输入的用 url 编码的源数据解码并存入当前对象的缓冲区中 + * @param s {const char*} 经 url 编码的源数据 + * @return {string&} 当前对象的引用 + */ + string& url_decode(const char* s); + + /** + * 将源数据进行 H2B 编码并存入当前对象的缓冲区中 + * @param s {const void*} 源数据地址 + * @param len {size_t} 源数据长度 + * @return {string&} 当前对象的引用 + */ + string& hex_encode(const void* s, size_t len); + + /** + * 将源数据进行 H2B 解码并存入当前对象的缓冲区中 + * @param s {const char*} 源数据地址 + * @param len {size_t} 源数据长度 + * @return {string&} 当前对象的引用 + */ + string& hex_decode(const char* s, size_t len); + + /** + * 将 32 位有符号整数转为字符串存 + * @param n {int} 32 位有符号整数 + * @return {const string&} 转换结果对象的引用 + */ + static const string& parse_int(int n); + + /** + * 将 32 位无符号整数转为字符串存 + * @param n {int} 32 位无符号整数 + * @return {const string&} 转换结果对象的引用 + */ + static const string& parse_int(unsigned int n); +#ifdef WIN32 + static const string& parse_int64(__int64 n); + + + static const string& parse_int64(unsigned __int64 n); +#else + /** + * 将 64 位有符号整数转为字符串存 + * @param n {long long int} 64 位有符号整数 + * @return {const string&} 转换结果对象的引用 + */ + static const string& parse_int64(long long int); + + /** + * 将 64 位无符号整数转为字符串存 + * @param n {unsigned long long int} 64 位无符号整数 + * @return {const string&} 转换结果对象的引用 + */ + static const string& parse_int64(unsigned long long int); +#endif + +private: + bool m_bin; + void init(size_t len); + ACL_VSTRING* m_pVbf; + const char* m_ptr; + std::list* m_psList; + std::vector* m_psList2; + std::pair* m_psPair; +}; + +} // namespce acl diff --git a/lib_acl_cpp/include/acl_cpp/stdlib/url_coder.hpp b/lib_acl_cpp/include/acl_cpp/stdlib/url_coder.hpp new file mode 100644 index 000000000..cfa4aa1a5 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/stdlib/url_coder.hpp @@ -0,0 +1,115 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include + +namespace acl { + +class string; + +struct URL_NV +{ + char* name; + char* value; +}; + +class ACL_CPP_API url_coder +{ +public: + /** + * 构造函数 + * @param nocase {bool} 当为 true 时表示参数名不区别大小写 + */ + url_coder(bool nocase = true); + + /** + * 构造函数,通过类实例对象构造 + * @param coder {const url_coder&} + */ + url_coder(const url_coder& coder); + + ~url_coder(); + + /** + * 将存储于 params_ 数组中的数据进行 url 编码 + * @param buf {string&} 存储编码后的结果 + * @param clean {bool} 是否清空传入的 buf 缓冲区 + */ + void encode(string& buf, bool clean = true) const; + + /** + * 获得将数组对象转换为编码后的字符串对象 + * @return {const string&} + */ + const string& to_string() const; + + /** + * 解析以 URL 编码的字符串 + * @param str {const char*} url 编码形式的字符串 + */ + void decode(const char* str); + + /** + * 采用 url 编码时,调用此函数添加变量 + * @param name {const char*} 变量名 + * @param value 变量值 + * @param override {bool} 如果存在同名变量是否直接覆盖 + * @return 返回 url_coder 对象的引用 + */ + url_coder& set(const char* name, const char* value, + bool override = true); + url_coder& set(const char* name, int value, bool override = true); + url_coder& set(const char* name, bool override, const char* fmt, ...); + url_coder& set(const char* name, const char* fmt, va_list ap, + bool override = true); + + /** + * 获得 URL 解码后 params_ 数组中某个变量名的值 + * @param name {const char*} 变量名 + * @return {const char*} 返回 NULL 表示不存在 + */ + const char* get(const char* name) const; + + /** + * 获得 URL 解码后 params_ 数组中某个变量名的值 + * @param name {const char*} 变量名 + * @return {const char*} 返回 NULL 表示不存在 + */ + const char* operator[](const char* name) const; + + /** + * URL 编码器对象的拷贝 + * @param coder {const url_coder&} URL 源编码器对象 + * @return {const url_coder&} + */ + const url_coder& operator =(const url_coder& coder); + + /** + * 获得参数数组对象 + * @return {std::vector&} + */ + const std::vector& get_params() const + { + return params_; + } + + /** + * 从 params_ 参数数组中删除某个变量 + * @param name {const char*} 变量名 + * @return {bool} 返回 true 表示删除成功,否则表示不存在 + */ + bool del(const char* name); + + /** + * 重置解析器状态,清除内部缓存 + */ + void reset(); + +private: + bool nocase_; + std::vector params_; + string* buf_; + + void free_param(URL_NV*); +}; + +} // namespace acl end diff --git a/lib_acl_cpp/include/acl_cpp/stdlib/util.hpp b/lib_acl_cpp/include/acl_cpp/stdlib/util.hpp new file mode 100644 index 000000000..e5d32c90a --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/stdlib/util.hpp @@ -0,0 +1,48 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" + +namespace acl +{ + +/** + * 获得上次系统调用出错时的错误号 + * @return {int} 错误号 + */ +ACL_CPP_API int last_error(void); + +/** + * 手工设置错误号 + * @param errnum {int} 错误号 + */ +ACL_CPP_API void set_error(int errnum); + +/** + * 获得上次系统调用出错时的错误描述信息,该函数内部采用了线程局部变量,所以是线程 + * 安全的,但使用起来更简单些 + * @return {const char *} 返回错误提示信息 + */ +ACL_CPP_API const char* last_serror(void); + +/** + * 获得上次系统调用出错时的错误描述信息 + * @param buf {char*} 存储错误描述信息的内存缓冲区 + * @param size {int} buffer 的空间大小 + * @return {const char*} 返回的地址应与 buffer 相同 + */ +ACL_CPP_API const char* last_serror(char* buf, size_t size); + +/** + * 类似于标准C的 strerror, 但该函数是跨平台且是线程安全的,获得对应某个错误 + * 号的错误描述信息 + * @param errnum {int} 错误号 + * @param buf {char*} 存储错误描述信息的内存缓冲区 + * @param size {int} buffer 缓冲区的大小 + * @return {const char*} 返回的地址应与 buffer 相同 +*/ +ACL_CPP_API const char* string_error(int errnum, char* buf, size_t size); + +ACL_CPP_API int strncasecmp_(const char *s1, const char *s2, size_t n); +ACL_CPP_API void assert_(bool n); +ACL_CPP_API void meter_time(const char *filename, int line, const char *info); + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/stdlib/vld.h b/lib_acl_cpp/include/acl_cpp/stdlib/vld.h new file mode 100644 index 000000000..c5f124de2 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/stdlib/vld.h @@ -0,0 +1,98 @@ +//////////////////////////////////////////////////////////////////////////////// +// $Id: vld.h,v 1.27 2006/11/12 18:09:20 dmouldin Exp $ +// +// Visual Leak Detector (Version 1.9d) - Import Library Header +// Copyright (c) 2006 Dan Moulding +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +// +// See COPYING.txt for the full terms of the GNU Lesser General Public License. +// +//////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#ifdef _DEBUG + +#pragma comment(lib, "vld.lib") + +// Force a symbolic reference to the global VisualLeakDetector class object from +// the DLL. This enusres that the DLL is loaded and linked with the program, +// even if no code otherwise imports any of the DLL's exports. +#pragma comment(linker, "/include:__imp_?vld@@3VVisualLeakDetector@@A") + +//////////////////////////////////////////////////////////////////////////////// +// +// Visual Leak Detector APIs +// + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +// VLDDisable - Disables Visual Leak Detector's memory leak detection at +// runtime. If memory leak detection is already disabled, then calling this +// function has no effect. +// +// Note: In multithreaded programs, this function operates on a per-thread +// basis. In other words, if you call this function from one thread, then +// memory leak detection is only disabled for that thread. If memory leak +// detection is enabled for other threads, then it will remain enabled for +// those other threads. It was designed to work this way to insulate you, +// the programmer, from having to ensure thread synchronization when calling +// VLDEnable() and VLDDisable(). Without this, calling these two functions +// unsychronized could result in unpredictable and unintended behavior. +// But this also means that if you want to disable memory leak detection +// process-wide, then you need to call this function from every thread in +// the process. +// +// Return Value: +// +// None. +// +__declspec(dllimport) void VLDDisable (); + +// VLDEnable - Enables Visual Leak Detector's memory leak detection at runtime. +// If memory leak detection is already enabled, which it is by default, then +// calling this function has no effect. +// +// Note: In multithreaded programs, this function operates on a per-thread +// basis. In other words, if you call this function from one thread, then +// memory leak detection is only enabled for that thread. If memory leak +// detection is disabled for other threads, then it will remain disabled for +// those other threads. It was designed to work this way to insulate you, +// the programmer, from having to ensure thread synchronization when calling +// VLDEnable() and VLDDisable(). Without this, calling these two functions +// unsychronized could result in unpredictable and unintended behavior. +// But this also means that if you want to enable memory leak detection +// process-wide, then you need to call this function from every thread in +// the process. +// +// Return Value: +// +// None. +// +__declspec(dllimport) void VLDEnable (); + +#ifdef __cplusplus +} +#endif // __cplusplus + +#else // !_DEBUG + +#define VLDEnable() +#define VLDDisable() + +#endif // _DEBUG \ No newline at end of file diff --git a/lib_acl_cpp/include/acl_cpp/stdlib/xml.hpp b/lib_acl_cpp/include/acl_cpp/stdlib/xml.hpp new file mode 100644 index 000000000..b99901773 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/stdlib/xml.hpp @@ -0,0 +1,434 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include +#include +#include "acl_cpp/stdlib/string.hpp" +#include "acl_cpp/stdlib/pipe_stream.hpp" + +struct ACL_XML; +struct ACL_XML_NODE; +struct ACL_XML_ATTR; +struct ACL_TOKEN; +struct ACL_ITER; + +/** + * 对 ACL 库中 XML 解析库的封装,方便 C++ 用户使用,如果不太注重性能因素, + * 可以直接使用该类,如果在服务端执行且非常注重性能,建议直接使用 ACL 库的 + * XML 解析器,因为该类也是调用了 ACL 库中的 XML 解析过程,并且有二次拷贝 + * 过程,可能会稍微影响一些性能,但对于一般的应用这点影响是微不足道的 + */ + +namespace acl { + +class xml; +class xml_node; + +class ACL_CPP_API xml_attr +{ +public: + /** + * 获得属性名 + * @return {const char*} 属性名,永远不会返回空指针,返回值 + * 有可能为 "\0" + */ + const char* get_name(void) const; + + /** + * 获得属性值 + * @return {const char*} 属性值,永远不会返回空指针,返回值 + * 有可能为 "\0" + */ + const char* get_value(void) const; +private: + friend class xml_node; + + xml_node* node_; + ACL_XML_ATTR* attr_; + + xml_attr(void); + ~xml_attr(void); +}; + +class ACL_CPP_API xml_node +{ +public: + /** + * 取得本 XML 结点的标签名 + * @return {const char*} 返回 XML 结点标签名,如果返回空,则说明 + * 不存在标签?xxxx,以防万一,调用者需要判断返回值 + */ + const char* tag_name(void) const; + + /** + * 如果该 XML 结点的 ID 号属性不存在,则返回空指针 + * @return {const char*} 当 ID 属性存在时返回对应的值,否则返回空 + */ + const char* id(void) const; + + /** + * 返回该 XML 结点的正文内容 + * @return {const char*} 返回空说明没有正文内容 + */ + const char* text(void) const; + + /** + * 返回该 XML 结点的某个属性值 + * @param name {const char*} 属性名 + * @return {const char*} 属性值,如果返回空则说明该属性不存在 + */ + const char* attr_value(const char* name) const; + + /** + * 返回该 XML 结点的某个属性值的便捷写法 + * @param name {const char*} 属性名 + * @return {const char*} 属性值,如果返回空则说明该属性不存在 + */ + const char* operator[](const char* name) const; + + /** + * 遍历结点的所有属性时,需要调用此函数来获得第一个属性对象 + * @return {const xml_attr*} 返回第一个属性对象,若为空,则表示 + * 该结点没有属性 + */ + const xml_attr* first_attr(void) const; + + /** + * 遍历结点的所有属性时,调用本函数获得下一个属性对象 + * @return {const xml_attr*} 返回下一下属性对象,若为空,则表示 + * 遍历完毕 + */ + const xml_attr* next_attr(void) const; + + /** + * 添加 XML 结点属性 + * @param name {const char*} 属性名 + * @param value {const char*} 属性值 + * @return {xml_node&} + */ + xml_node& add_attr(const char* name, const char* value); + + /** + * 添加 XML 结点属性 + * @param name {const char*} 属性名 + * @param n {char} 属性值 + * @return {xml_node&} + */ + xml_node& add_attr(const char* name, char n); + + /** + * 添加 XML 结点属性 + * @param name {const char*} 属性名 + * @param n {int} 属性值 + * @return {xml_node&} + */ + xml_node& add_attr(const char* name, int n); + + /** + * 添加 XML 结点属性 + * @param name {const char*} 属性名 + * @param n {size_t} 属性值 + * @return {xml_node&} + */ + xml_node& add_attr(const char* name, size_t n); + + /** + * 添加 XML 结点属性 + * @param name {const char*} 属性名 + * @param n {acl_int64} 属性值 + * @return {xml_node&} + */ +#ifdef WIN32 + xml_node& add_attr(const char* name, __int64 n); +#else + xml_node& add_attr(const char* name, long long int n); +#endif + + /** + * 设置 xml 结点的文本内容 + * @param str {const char*} 字符串内容 + * @return {xml_node&} + */ + xml_node& set_text(const char* str); + + /** + * 给本 xml 结点添加 xml_node 子结点对象 + * @param child {xml_node*} 子结点对象 + * @param return_child {bool} 是否需要本函数返回新创建的子结点的引用 + * @return {xml_node&} return_child 为 true 返回子结点的引用, + * 否则返回本 xml 结点引用 + */ + xml_node& add_child(xml_node* child, bool return_child = false); + + /** + * 给本 xml 结点添加 xml_node 子结点对象 + * @param child {xml_node&} 子结点对象 + * @param return_child {bool} 是否需要本函数返回新创建的子结点的引用 + * @return {xml_node&} return_child 为 true 返回子结点的引用, + * 否则返回本 xml 结点引用 + */ + xml_node& add_child(xml_node& child, bool return_child = false); + + /** + * 给本 xml 结点添加 xml_node 子结点对象 + * @param tag {const char* tag} 子结点对象的标签名 + * @param return_child {bool} 是否需要本函数返回新创建的子结点的引用 + * @param str {const char*} 文本字符串 + * @return {xml_node&} return_child 为 true 返回子结点的引用, + * 否则返回本 xml 结点引用 + */ + xml_node& add_child(const char* tag, bool return_child = false, + const char* str = NULL); + + /** + * 获得本结点的父级结点对象的引用 + * @return {xml_node&} + */ + xml_node& get_parent(void) const; + + /** + * 获得本结点的第一个子结点,需要遍历子结点时必须首先调用此函数 + * @return {xml_node*} 返回空表示没有子结点 + */ + xml_node* first_child(void); + + /** + * 获得本结点的下一个子结点 + * @return {xml_node*} 返回空表示遍历过程结束 + */ + xml_node* next_child(void); + + /** + * 返回该 XML 结点在整个 XML 树中的深度 + * @return {int} + */ + int depth(void) const; + + /** + * 返回该 xml 结点的下一级子结点的个数 + * @return {int} 永远 >= 0 + */ + int children_count(void) const; + + /** + * 获得 xml 对象的引用 + * @return {xml&} + */ + xml& get_xml(void) const; + + /** + * 取出对应于 ACL 库中的 XML 结点对象 + * @return {ACL_XML_NODE*} 返回结点对象,注:该结点用户不能单独释放 + */ + ACL_XML_NODE* get_xml_node() const; + +private: + friend class xml; + + /** + * xml 结点构造函数 + * @param node {ACL_XML_NODE*} 参见 acl 库 acl_xml.h中的头文件,非空 + * @param xml_ptr {xml*} xml 树对象,非空 + */ + xml_node(ACL_XML_NODE* node, xml* xml_ptr); + + /** + * 要求该对象必须是动态创建的 + */ + ~xml_node(void); + + /** + * 设置 xml 结点 + * @param node {ACL_XML_NODE*} + */ + void set_xml_node(ACL_XML_NODE* node); + +private: + ACL_XML_NODE *node_; + xml* xml_; + xml_node* parent_; + xml_node* parent_saved_; + xml_node* child_; + ACL_ITER* child_iter_; + xml_attr* attr_; + ACL_ITER* attr_iter_; +}; + +class string; + +class ACL_CPP_API xml : public pipe_stream +{ +public: + /** + * 构造函数 + * @param data {const char*} xml 格式的字符串,可以是完整的 + * xml 字符串,也可以是部分的 xml 字符串,也可以是空指针, + * 无论如何,用户依然可以用部分或完整的 xml 字符串调用 update + * 函数,在调用 update 过程中解析 xml;其实,当构造函数的 + * 的 data 参数非空时,它也会调用 update + */ + xml(const char* data = NULL); + ~xml(void); + + xml& part_word(bool on); + xml& ignore_slash(bool on); + + /** + * 以流式方式循环调用本函数添加 XML 数据,也可以一次性添加 + * 完整的 XML 数据,如果是重复使用该 XML 解析器解析多个 XML + * 对象,则应该在解析下一个 XML 对象前调用 reset() 方法来清 + * 除上一次的解析结果 + * @param data {const char*} xml 数据 + */ + void update(const char* data); + + /** + * 重置 XML 解析器状态,该 XML 对象可以用来对多个 XML 数据 + * 进行解析,在反复使用本 XML 解析器前,需要调用本函数重置 + * 内部 XML 解析器状态,清除上一次的解析结果 + */ + void reset(void); + + /** + * 从解析的 XML 原始数据中仅提取文本部分 + * @return {const string&} 返回结果缓冲区的引用,该引用是内 + * 部变量,用户不需要释放 + */ + const string& getText(void); + + /** + * 从 XML 对象中取得某个标签名的所有结点集合 + * @param tag {const char*} 标签名(不区分大小写) + * @return {const std::vector&} 返回结果集的对象引用, + * 如果查询结果为空,则该集合为空,即:empty() == true + * 注:返回的数组中的 xml_node 结点数据可以修改,但不能删除该结点, + * 因为该库内部有自动删除的机制 + */ + const std::vector& getElementsByTagName(const char* tag) const; + + /** + * 从 xml 对象中获得对应标签名的第一个 xml 结点对象 + * @param tag {const char*} 标签名(不区分大小写) + * @return {const xml_node*} 返回空表明该标签对应的 xml 结点不存在 + */ + const xml_node* getFirstElementByTag(const char* tag) const; + + /** + * 从 xml 对象中获得所有的与给定多级标签名相同的 xml 结点的集合 + * @param tags {const char*} 多级标签名,由 '/' 分隔各级标签名,如针对 xml 数据: + * text1 ... + * text2 ... + * text3 ... + * 可以通过多级标签名:root/first/second/third 一次性查出所有符合条件的结点 + * @return {const std::vector&} 符合条件的 xml 结点集合, + * 如果查询结果为空,则该集合为空,即:empty() == true + * 注:返回的数组中的 xml_node 结点数据可以修改,但不能删除该结点, + * 因为该库内部有自动删除的机制 + */ + const std::vector& getElementsByTags(const char* tags) const; + + /** + * 从 xml 对象中获得指定多级标签名的第一个 xml 结点 + * @param tags {const char*} 多级标签名,由 '/' 分隔各级标签名,如针对 xml 数据: + * text1 ... + * text2 ... + * text3 ... + * 可以通过多级标签名:root/first/second/third 一次性查出所有符合条件的结点 + * @return {const xml_node*} 返回空表示不存在 + */ + const xml_node* getFirstElementByTags(const char* tags) const; + + /** + * 从 xml 对象中获得所有的与给定属性名 name 的属性值相同的 xml 结点元素集合 + * @param value {const char*} 属性名为 name 的属性值 + * @return {const std::vector&} 返回结果集的对象引用, + * 如果查询结果为空,则该集合为空,即:empty() == true + * 注:返回的数组中的 xml_node 结点数据可以修改,但不能删除该结点, + * 因为该库内部有自动删除的机制 + */ + const std::vector& getElementsByName(const char* value) const; + + /** + * 从 xml 对象中获得所有给定属性名及属性值的 xml 结点元素集合 + * @param name {const char*} 属性名 + * @param value {const char*} 属性值 + * @return {const std::vector&} 返回结果集的对象引用, + * 如果查询结果为空,则该集合为空,即:empty() == true + */ + const std::vector& getElementsByAttr( + const char* name, const char* value) const; + + /** + * 从 xml 对象中获得指定 id 值的 xml 结点元素 + * @param id {const char*} id 值 + * @return {const xml_node*} xml 结点元素, 若返回 NULL 则表示没有符合 + * 条件的 xml 结点, 返回值不需要释放 + */ + const xml_node* getElementById(const char* id) const; + + /** + * 取得 acl 库中的 ACL_XML 对象 + * @return {ACL_XML*} 该值不可能为空,注意用户可以修改该对象的值, + * 但不可以释放该对象 + */ + ACL_XML* get_xml(void) const; + + /** + * 创建一个 xml_node 结点对象 + * @param tag {const char*} 标签名 + * @param text {const char*} 文本字符串 + * @return {xml_node*} 新产生的 xml_node 对象不需要用户手工释放,因为在 + * xml 对象被释放时这些结点会自动被释放,当然用户也可以在不用时调用 + * reset 来释放这些 xml_node 结点对象 + */ + xml_node& create_node(const char* tag, const char* text = NULL); + + /** + * 获得根结点对象,但需要注意,该结点为虚结点,里面不存放任何数据, + * 它是所有 xml 结点对象的最顶层父对象 + * @return {xml_node&} + */ + xml_node& get_root(); + + /** + * 开始遍历该 xml 对象并获得第一个结点 + * @return {xml_node*} 返回空表示该 xml 对象为空结点 + * 注:返回的结点对象用户不能手工释放,因为该对象被 + * 内部库自动释放 + */ + xml_node* first_node(void); + + /** + * 遍历该 xml 对象的下一个 xml 结点 + * @return {xml_node*} 返回空表示遍历完毕 + * 注:返回的结点对象用户不能手工释放,因为该对象被 + * 内部库自动释放 + */ + xml_node* next_node(void); + + /** + * 将 xml 对象树转成字符串 + * @param out {string&} 存储转换结果的缓冲区 + */ + void build_xml(string& out); + + // pipe_stream 虚函数重载 + + virtual int push_pop(const char* in, size_t len, + string* out, size_t max = 0); + virtual int pop_end(string* out, size_t max = 0); + virtual void clear(void); + +private: + ACL_XML *xml_; + xml_node* node_; + xml_node* root_; + std::vector elements_; + string* buf_; + //bool dummyRootAdded_; + + ACL_TOKEN* m_pTokenTree; + std::list nodes_; + ACL_ITER* iter_; +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/stdlib/zlib_stream.hpp b/lib_acl_cpp/include/acl_cpp/stdlib/zlib_stream.hpp new file mode 100644 index 000000000..cd4874af6 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/stdlib/zlib_stream.hpp @@ -0,0 +1,204 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include "acl_cpp/stdlib/pipe_stream.hpp" + +typedef struct z_stream_s z_stream; + +namespace acl { + +/** + * 压缩级别类型定义,该集合定义了压缩速度及压缩比的一个可选方式 + * 所选的压缩值越高,则压缩比会更大,但压缩速度会越低 + */ +typedef enum +{ + zlib_default = -1, // 缺省的压缩比 + zlib_level0 = 0, // 最低的压缩比,其实就是不压缩 + zlib_best_speed = 1, // 压缩速度最快的压缩比 + zlib_level1 = zlib_best_speed, + zlib_level2 = 2, + zlib_level3 = 3, + zlib_level4 = 4, + zlib_level5 = 5, + zlib_level6 = 6, + zlib_level7 = 7, + zlib_level8 = 8, + zlib_best_compress = 9, // 最高的压缩比,最低的压缩速度 + zlib_level9 = zlib_best_compress +} zlib_level_t; + +/** + * 压缩或解压过程中的缓存模式,即在压缩或解压过程中是否立刻刷新 + * 到缓冲区为了获得比较高的压缩比,应该选择 zlib_flush_off 方式 + */ +typedef enum +{ + zlib_flush_off = 0, // 不立即刷新至用户缓存 + zlib_flush_partial = 1, // 刷新部分至用户缓存 + zlib_flush_sync = 2, // 同步刷新 + zlib_flush_full = 3, // 完全刷新 + zlib_flush_finish = 4 // 完全刷新并停止压缩或解压过程 +} zlib_flush_t; + +class string; + +class ACL_CPP_API zlib_stream : public pipe_stream +{ +public: + zlib_stream(); + ~zlib_stream(); + + /** + * 非流式压缩 + * @param in {const char*} 源数据 + * @param len {int} 源数据长度 + * @param out {string*} 存储压缩结果的用户缓冲区 + * @param level {zlib_level_t} 压缩级别,级别越高则压缩比越高, + * 但压缩速度越低 + * @return {bool} 压缩过程是否成功 + */ + bool zlib_compress(const char* in, int len, string* out, + zlib_level_t level = zlib_default); + + /** + * 非流式解压缩 + * @param in {const char*} 源压缩数据 + * @param len {int} 源数据长度 + * @param out {string*} 存储解压缩结果的用户缓冲区 + * @param have_zlib_header {bool} 是否有 zlib_header 头,对 + * HTTP 传输协议而言应该将此值设为 false + * @param wsize {int} 解压过程中的滑动窗口大小 + * @return {bool} 解压缩过程是否成功 + */ + bool zlib_uncompress(const char* in, int len, string* out, + bool have_zlib_header = true, int wsize = 15); + + /////////////////////////////////////////////////////////////// + // + // 以下为流式压缩和流式解压缩过程 + // + /////////////////////////////////////////////////////////////// + + /** + * 开始压缩过程,如果采用流式压缩方式,则调用顺序必须是: + * zip_begin->zip_update->zip_finish,如果中间任何一个 + * 过程失败,则应该调用 zip_reset + * @param level {zlib_level_t} 压缩级别,级别越高,则压缩比 + * 越高,但压缩速度越低 + * @return {bool} 压缩初始化过程是否成功,失败的原因一般 + * 应该是输入的参数非法 + */ + bool zip_begin(zlib_level_t level = zlib_default); + + /** + * 循环调用此函数对源数据进行压缩 + * @param in {const char*} 源数据 + * @param len {int} 源数据长度 + * @param out {string*} 用户缓冲区,该函数以添加方式往用户 + * 提供的缓冲区中添加压缩的结果,用户应该自行判断调用本函数 + * 前后的缓冲区长度,以确定由该函数添加的数据长度,由于所 + * 选择的 zlib_flush_t 的不同,该缓冲区中数据可能未必存取 + * 所有的结果 + * @param flag {zlib_flush_t} 压缩过程中的数据缓冲方式 + * zlib_flush_off: 数据结果可能不会立即刷新至用户缓冲区, + * zlib 库本身决定刷新的方式,从而可能会获得较高的压缩比 + * zlib_flush_partial: 数据结果可能会部分刷新至用户缓冲区 + * zlib_flush_sync: 数据数据同步刷新至用户缓冲区 + * zlib_flush_full: 将 zlib 库缓冲数据结果全部刷新至用户缓冲区 + * zlib_flush_finish: 调用本参数后表明压缩过程结束,同时会将 + * 所有结果数据刷新至用户缓冲区,一般该参数不需要调用,因为在 + * 调用 zip_finish 后,会自动将所有的缓冲数据刷新至用户缓冲区 + * @return {bool} 压缩过程是否失败 + */ + bool zip_update(const char* in, int len, string* out, + zlib_flush_t flag = zlib_flush_off); + + /** + * 调用本函数表示压缩过程结束 + * @param out {string} 用户缓冲区,该函数会将 zlib 库缓冲区中 + * 的数据以添加的方式都刷新至用户缓冲区 + * @return {bool} 是否成功 + */ + bool zip_finish(string* out); + + /** + * 重置压缩器状态,一般只有当压缩过程出错时才会调用本函数 + * @return {bool} 是否成功 + */ + bool zip_reset(); + + /** + * 开始解压缩过程,如果采用流式解压缩方式,则调用顺序必须是: + * unzip_begin->unzip_update->unzip_finish,如果中间任何一个 + * 过程失败,则应该调用 unzip_reset + * @param have_zlib_header {bool} 是否有 zlib_header 头,对 + * HTTP 传输协议而言应该将此值设为 false + * @param wsize {int} 解压过程中的滑动窗口大小 + * @return {bool} 解压缩初始化过程是否成功,失败的原因一般 + * 应该是输入的参数非法 + */ + bool unzip_begin(bool have_zlib_header = true, int wsize = 15); + + /** + * 循环调用此函数对源数据进行解压缩 + * @param in {const char*} 压缩的源数据 + * @param len {int} 源数据长度 + * @param out {string*} 用户缓冲区,该函数以添加方式往用户 + * 提供的缓冲区中添加解压的结果,用户应该自行判断调用本函数 + * 前后的缓冲区长度,以确定由该函数添加的数据长度,由于所 + * 选择的 zlib_flush_t 的不同,该缓冲区中数据可能未必存取 + * 所有的结果 + * @param flag {zlib_flush_t} 解压缩过程中的数据缓冲方式 + * zlib_flush_off: 数据结果可能不会立即刷新至用户缓冲区, + * zlib 库本身决定刷新的方式 + * zlib_flush_partial: 数据结果可能会部分刷新至用户缓冲区 + * zlib_flush_sync: 数据数据同步刷新至用户缓冲区 + * zlib_flush_full: 将 zlib 库缓冲数据结果全部刷新至用户缓冲区 + * zlib_flush_finish: 调用本参数后表明解压缩过程结束,同时会将 + * 所有结果数据刷新至用户缓冲区,一般该参数不需要调用,因为在 + * 调用 zip_finish 后,会自动将所有的缓冲数据刷新至用户缓冲区 + * @return {bool} 解压缩过程是否失败 + */ + bool unzip_update(const char* in, int len, string* out, + zlib_flush_t flag = zlib_flush_off); + + /** + * 调用本函数表示解压缩过程结束 + * @param out {string} 用户缓冲区,该函数会将 zlib 库缓冲区中 + * 的数据以添加的方式都刷新至用户缓冲区 + * @return {bool} 是否成功 + */ + bool unzip_finish(string* out); + + /** + * 重置解压缩器状态,一般只有当解压缩过程出错时才会调用本函数 + * @return {bool} 是否成功 + */ + bool unzip_reset(); + + /////////////////////////////////////////////////////////////// + + bool pipe_zip_begin(zlib_level_t level = zlib_default, + zlib_flush_t flag = zlib_flush_off); + bool pipe_unzip_begin(zlib_flush_t flag = zlib_flush_off); + + // pipe_stream 虚函数重载 + + virtual int push_pop(const char* in, size_t len, + string* out, size_t max = 0); + virtual int pop_end(string* out, size_t max = 0); + virtual void clear(); +protected: +private: + z_stream* zstream_; + bool finished_; + bool is_compress_; + zlib_flush_t flush_; + + bool update(int (*func)(z_stream*, int), zlib_flush_t flag, + const char* in, int len, string* out); + bool flush_out(int (*func)(z_stream*, int), + zlib_flush_t flag, string* out); +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/stream/aio_fstream.hpp b/lib_acl_cpp/include/acl_cpp/stream/aio_fstream.hpp new file mode 100644 index 000000000..7cb07d407 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/stream/aio_fstream.hpp @@ -0,0 +1,91 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include "acl_cpp/stream/aio_istream.hpp" +#include "acl_cpp/stream/aio_ostream.hpp" + +namespace acl { + +class fstream; + +/** + * 异步文件读写流,该类对象只可用在 UNIX 系统中 + */ +class ACL_CPP_API aio_fstream + : public aio_istream + , public aio_ostream +{ +public: + /** + * 构造函数 + * @param handle {aio_handle*} 异步事件句柄 + */ + aio_fstream(aio_handle* handle); + +#ifdef WIN32 + aio_fstream(aio_handle* handle, HANDLE fd, unsigned int oflags = 0600); +#else + aio_fstream(aio_handle* handle, int fd, unsigned int oflags = 0600); +#endif + + /** + * 根据文件路径打开文件流, 这是最基础的打开文件的方式 + * @param path {const char*} 文件名 + * @param oflags {unsigned int} 标志位, We're assuming that O_RDONLY: 0x0000, + * O_WRONLY: 0x0001, O_RDWR: 0x0002, O_APPEND: 0x0008, O_CREAT: 0x0100, + * O_TRUNC: 0x0200, O_EXCL: 0x0400; just for win32, O_TEXT: 0x4000, + * O_BINARY: 0x8000, O_RAW: O_BINARY, O_SEQUENTIAL: 0x0020, O_RANDOM: 0x0010. + * @param mode {int} 打开文件句柄时的模式(如: 0600) + * @return {bool} 打开文件是否成功 + */ + bool open(const char* path, unsigned int oflags, unsigned int mode); + + /** + * 以读/写方式打开文件流,当文件不存在时则创建新文件,当文件存在时则 + * 将文件清空, 文件属性为 0700 + * @param path {const char*} 文件名 + * @param mode {int} 打开文件句柄时的模式(如: 0600) + * @return {bool} 打开文件是否成功 + */ + bool open_trunc(const char* path, unsigned int mode = 0600); + + /** + * 以读/写方式建新文件,文件属性为 0600, 若文件不存在则创建新文件,若存在则 + * 打开旧文件 + * @param mode {int} 打开文件句柄时的模式(如: 0600) + * @return {bool} 文件创建是否成功 + */ + bool create(const char* path, unsigned int mode = 0600); + + /** + * 以只读方式打开已经存在的文件 + * @param path {const char*} 文件名 + * @return {bool} 打开文件是否成功 + */ + bool open_read(const char* path); + + /** + * 以只写方式打开文件,如果文件不存在则创建新文件,如果文件 + * 存在,则将文件内容清空 + * @param path {const char*} 文件名 + * @return {bool} 是否成功 + */ + bool open_write(const char* path); + + /** + * 以尾部添加方式打开文件,如果文件不存在则创建新文件 + * @param path {const char*} 文件名 + * @return {bool} 是否成功 + */ + bool open_append(const char* path); + +protected: + ~aio_fstream(); + /** + * 通过此函数来动态释放只能在堆上分配的异步流类对象 + */ + virtual void destroy(); + +private: +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/stream/aio_handle.hpp b/lib_acl_cpp/include/acl_cpp/stream/aio_handle.hpp new file mode 100644 index 000000000..b586ef6d8 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/stream/aio_handle.hpp @@ -0,0 +1,343 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include "acl_cpp/stdlib/noncopyable.hpp" +#include +#include +//#include "string.hpp" + +struct ACL_AIO; + +namespace acl +{ + +/** + * 需要被延迟释放的类继承此类后,可以调用 aio_handle:delay_free 来到达 + * 延迟销毁的目的,避免了在递归过程中被立即释放时的对象被提前释放的问题 + */ +class ACL_CPP_API aio_delay_free +{ +public: + aio_delay_free(void); + virtual ~aio_delay_free(void); + + /** + * 判定定时器是否正处于锁定状态,处于锁定状态的定时器是 + * 不能被删除的,否则会造成内存严重错误 + * @return {bool} 是否处于锁定状态,处于锁定状态的对象是 + * 不允许被销毁的 + */ + bool locked(void) const; + + /** + * 允许子类设置子类对象的锁定对象,这样在定时器处理过程中就不会 + * 自动调用子类对象的销毁过程 + */ + void set_locked(void); + + /** + * 允许子类取消类对象的锁定状态 + */ + void unset_locked(void); + + /** + * 销毁函数,在内部类 aio_timer_delay_free 对象中对需要做延迟释放 + * 的类进行销毁 + */ + virtual void destroy(void) {} +private: + bool locked_; + bool locked_fixed_; +}; + +class aio_timer_task; +class aio_handle; + +/** + * 定时器的回调类 + */ +class ACL_CPP_API aio_timer_callback : public aio_delay_free +{ +public: + /** + * 构造函数 + * @param keep {bool} 该定时器是否允许自动重启 + */ + aio_timer_callback(bool keep = false); + virtual ~aio_timer_callback(void); + + /** + * 当定时器里的任务数为空时的回调函数, + * 子类可以在其中释放,一旦该函数被调用, + * 则意味着该定时器及其中的所有定时任务都从 + * 定时器集合中被删除 + * 该函数被触发的条件有三个: + * 1) 定时器所有的任务数为 0 时(如, + * del_timer(aio_timer_callback*, unsigned int) 被 + * 调用且任务数为 0 时) + * 2) 当 aio_handle 没有设置重复定时器且该定时器中 + * 有一个定时任务被触发后 + * 3) 当 del_timer(aio_timer_callback*) 被调用后 + */ + virtual void destroy(void) {} + + /** + * 定时器里的任务是否为空 + * @return {bool} + */ + bool empty(void) const; + + /** + * 定时器里的任务个数 + * @return {size_t} + */ + size_t length(void) const; + + /** + * 该定时器是否是自动重启的 + * @param on {bool} + */ + void keep_timer(bool on); + + /** + * 判断该定时器是否是自动重启的 + * @return {bool} + */ + bool keep_timer(void) const; + + /** + * 清空定时器里的定时任务 + * @return {int} 被清除的定时任务的个数 + */ + int clear(void); + +protected: + friend class aio_handle; + + /** + * 子类必须实现此回调函数,注:子类或调用者禁止在 + * timer_callback 内部调用 aio_timer_callback 的析构 + * 函数,否则将会酿成大祸 + * @param id {unsigned int} 对应某个任务的 ID 号 + */ + virtual void timer_callback(unsigned int id) = 0; + + /************************************************************************/ + /* 子类可以调用如下函数添加一些新的定时器任务 ID 号 */ + /************************************************************************/ +#ifdef WIN32 + __int64 present_; + + /** + * 针对本定时器增加新的任务ID号,这样便可以通过一个定时器启动 + * 多个定时任务 + * @param id {unsigned int} 定时器定时任务ID号 + * @param delay {__int64} 每隔多久自动触发该定时器,同时将对应的定时器定时 + * 任务ID号传回(微秒级) + * @return {__int64} 距离本定时器的第一个将会触发的定时任务ID还多久(微秒级) + */ + __int64 set_task(unsigned int id, __int64 delay); + + /** + * 删除定时器中某个消息ID对应的定时任务 + * @param {unsigned int} 定时任务ID + * @return {__int64} 距离本定时器的第一个将会触发的定时任务ID还多久(微秒级) + */ + __int64 del_task(unsigned int id); +#else + long long int present_; + long long int set_task(unsigned int id, long long int delay); + long long int del_task(unsigned int id); +#endif + + /** + * 设置当前定时器的时间截 + */ + void set_time(void); +private: + aio_handle* handle_; + size_t length_; + std::list tasks_; + bool keep_; // 该定时器是否允许自动重启 + bool destroy_on_unlock_; // 解锁后是否 destroy +#ifdef WIN32 + __int64 set_task(aio_timer_task* task); + __int64 trigger(void); +#else + long long int set_task(aio_timer_task* task); + long long int trigger(void); +#endif +}; + +// 事件引擎类型 +typedef enum +{ + ENGINE_SELECT, // select 模式(支持所有平台) + ENGINE_POLL, // poll 模式(仅 UNIX 平台) + ENGINE_KERNEL, // kernel 模式(win32: iocp, Linux: epoll, FreeBsd: kqueue, Solaris: devpoll + ENGINE_WINMSG // win32 GUI 消息模式 +} aio_handle_type; + +/** + * 非阻塞IO的事件引擎类,该类封装了系统的 select/poll/epoll/kqueue/devpoll/iocp, + */ + +class aio_timer_delay_free; + +class ACL_CPP_API aio_handle : private noncopyable +{ +public: + /** + * 构造函数,会自动创建IO事件引擎,并且在析构函数中会自动释放 + * @param engine_type {aio_handle_type} 所采用的引擎类型 + * ENGINE_SELECT: select 方式,支持 win32/unix 平台 + * ENGINE_POLL: poll 方式,支持 unix 平台 + * ENGINE_KERNEL: 自动根据各个系统平台所支持的高效内核引擎进行设置 + * ENGINE_WINMSG: win32 界面消息方式,支持 win32 平台 + * @param nMsg {unsigned int} 若 engine_type 为 ENGINE_WINMSG,当该值 + * 大于 0 时,该异步句柄便与该消息绑定,否则与缺省消息绑定; + * 当 engine_type 为非 ENGINE_WINMSG 时,该值对其它异步句柄不起作用 + * + */ + aio_handle(aio_handle_type engine_type = ENGINE_SELECT, unsigned int nMsg = 0); + + /** + * 构造函数,调用者将 ACL_AIO 句柄传进,而在类的析构函数中并不会 + * 自动释放该 ACL_AIO 句柄 + * @param handle {ACL_AIO*} ACL_AIO 句柄 + */ + aio_handle(ACL_AIO* handle); + + virtual ~aio_handle(); + + /** + * 针对异步读流,设置是否是连续读,该配置项将会被所有的基于 + * 该异步引擎句柄的异步读流所继承,一般 aio_handle 类对象在缺省 + * 情况下是连续读的 + * @param onoff {bool} 设置是否是连续读 + */ + void keep_read(bool onoff); + + /** + * 获得异步引擎句柄是否设置了持续读数据的功能 + * @return {bool} + */ + bool keep_read() const; + + /** + * 设置定时器 + * @param callback {aio_timer_callback*} 定时器回调函数类对象 + * @param delay {int64} 定时器时间间隔(微秒) + * @param id {unsigned int} 定时器某个任务的 ID 号 + * @return {int64} 定时器生效时间(从1970.1.1以来的微秒数) + */ +#ifdef WIN32 + __int64 set_timer(aio_timer_callback* callback, + __int64 delay, unsigned int id = 0); +#else + long long int set_timer(aio_timer_callback* callback, + long long int delay, unsigned int id = 0); +#endif + + /** + * 删除定时器的所有定时任务事件 + * @param callback {aio_timer_callback*} 定时器回调函数类对象 + * @return {time_t} 定时器生效时间(从1970.1.1以来的微秒数) + */ +#ifdef WIN32 + __int64 del_timer(aio_timer_callback* callback); +#else + long long int del_timer(aio_timer_callback* callback); +#endif + + /** + * 删除定时器中某个指定 ID 号的定时任务 + * @param callback {aio_timer_callback*} 定时器回调函数类对象 + * @param id {unsigned int} 定时器某个任务的 ID 号 + * @return {time_t} 定时器生效时间(从1970.1.1以来的微秒数) + */ +#ifdef WIN32 + __int64 del_timer(aio_timer_callback* callback, unsigned int id); +#else + long long del_timer(aio_timer_callback* callback, unsigned int id); +#endif + + /** + * 当定时器处于锁定状态时,用户因为无法释放该定时器而造成内存泄露, + * 通过此函数,可以将处于锁定状态的定时器当处于未锁定状态时被事件 + * 引擎延期释放(调用 aio_delay_free::destroy()),从而可以避免 + * 内存泄露问题 + * @param callback {aio_delay_free*} + */ + void delay_free(aio_delay_free* callback); + + /** + * 获得 ACL_AIO 句柄 + * @return {ACL_AIO*} + */ + ACL_AIO* get_handle(void) const; + + /** + * 获得异步引擎的类型 + * @return {aio_handle_type} + */ + aio_handle_type get_engine_type(void) const; + + /** + * 获得当前处于监控的异步流的数量 + * @return {int} + */ + int length() const; + + /** + * 检查所有异步流的状态,并触发准备的异步流的处理过程 + * @return {bool} 是否应中止异步引擎 + */ + bool check(); + + /** + * 通知异步流引擎中止 + */ + void stop(); + + /** + * 重置异步引擎的内部状态 + */ + void reset(); + +protected: + friend class aio_stream; + + /** + * 异步流个数加 1 + */ + void increase(); + + /** + * 当异步流个数加 1 时的回调虚函数 + */ + virtual void on_increase() {} + + /** + * 异步流个数减 1 + */ + void decrease(); + + /** + * 当异步流个数减 1 时的回调虚函数 + */ + virtual void on_decrease() {} + +private: + ACL_AIO* aio_; + bool inner_alloc_; + bool stop_; + int nstream_; + aio_handle_type engine_type_; + aio_timer_delay_free* delay_free_timer_; + + void destroy_timer(aio_timer_callback* callback); + static void on_timer_callback(int event_type, + aio_timer_callback *callback); +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/stream/aio_istream.hpp b/lib_acl_cpp/include/acl_cpp/stream/aio_istream.hpp new file mode 100644 index 000000000..917057d8e --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/stream/aio_istream.hpp @@ -0,0 +1,196 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include "acl_cpp/stream/aio_handle.hpp" +#include "acl_cpp/stream/aio_stream.hpp" + +namespace acl +{ +class aio_istream; + +/** + * 延迟异步读数据类,基类为 aio_timer_callback (see aio_handle.hpp), + * 所谓延迟异步读,就是把异步读流(aio_istream)放在定时器中,将该异 + * 步流的异步读操作解除绑定(即从 aio_handle 的监控中解除),当指定 + * 时间到达后再启动异步读操作(在 timer_callback 回调中再重新将异步 + * 流的异步读操作绑定),同时该定时器自动销毁(调用 destroy 方法), + * 所以如果用户继承了 aio_timer_reader 类,且子类不是在堆上分配的, + * 则必须重载 destroy方法,同时在子类的 destroy 中执行与资源释放的 + * 相关操作,如果子类未重载 destroy,则当定时器结束后内部会自动调用 + * 基类 aio_timer_reader 的 destroy--该类调用了 delete this,此时就 + * 会导致非法内存释放操作) + * + */ +class ACL_CPP_API aio_timer_reader : public aio_timer_callback +{ +public: + aio_timer_reader() {} + + /** + * 在 aio_istream 中调用此函数以释放类对象,子类应该实现该函数 + */ + virtual void destroy() + { + delete this; + } +protected: + virtual ~aio_timer_reader() {} + /** + * 延迟读数据时的回调函数,从 aio_timer_callback 类中继承而来 + */ + virtual void timer_callback(unsigned int id); +private: + // 允许 aio_istream 可以直接修改本类的私有成员变量 + friend class aio_istream; + + aio_istream* in_; + int read_delayed_; + bool delay_gets_; + int delay_timeout_; + bool delay_nonl_; + int delay_count_; +}; + +/** + * 异步读数据流类定义,该类只能在堆上被实例化,在析构时需要调用 close + * 函数以释放该类对象 + */ +class ACL_CPP_API aio_istream : virtual public aio_stream +{ +public: + /** + * 构造函数 + * @param handle {aio_handle*} 异步事件引擎句柄 + */ + aio_istream(aio_handle* handle); + + /** + * 添加异可读时的回调类对象指针,如果该回调类对象已经存在,则只是 + * 使该对象处于打开可用状态 + * @param callback {aio_callback*} 继承 aio_callback 的子类回调类对象, + * 当异步流有数据时会先调用此回调类对象中的 read_callback 接口 + */ + void add_read_callback(aio_callback* callback); + + /** + * 从读回调对象集合中删除 + * @param callback {aio_read_callback*} 被删除的回调对象, + * 若该值为空,则删除所有的回调对象 + * @return {int} 返回被从回调对象集合中删除的回调对象的个数 + */ + + /** + * 从读回调对象集合中删除回调对象 + * @param callback {aio_callback*} 从 aio_callback 继承的子类对象指针, + * 若该值为空,则删除所有的读回调对象 + * @return {int} 返回被从回调对象集合中删除的回调对象的个数 + */ + int del_read_callback(aio_callback* callback = NULL); + + /** + * 禁止回调对象类集合中的某个回调类对象,但并不从回调类对象 + * 集合中删除,只是不被调用而已 + * @param callback {aio_callback*} 从 aio_callback 继承的子类对象指针, + * 若该值为空,则禁止所有的读回调对象 + * @return {int} 返回被从回调对象集合中禁用的回调对象的个数 + */ + int disable_read_callback(aio_callback* callback = NULL); + + /** + * 启用所有的回调对象被调用 + * @param callback {aio_callback*} 从 aio_callback 继承的子类对象指针, + * 若该值为空,则启用所有的读回调对象 + * @return {int} 返回被启用的回调对象的个数 + */ + int enable_read_callback(aio_callback* callback = NULL); + + /** + * 异步读取一行数据,当延迟异步读时,如果连续调用此过程, + * 则只有最后一个延迟读操作生效 + * @param timeout {int} 读超时时间(秒),若为 0 则表示 + * 永远等待直到读到完整一行数据或出错 + * @param nonl {bool} 是否自动去掉尾部的回车换行符 + * @param delay {int64} 如果对方发送数据比较快时,此参数 + * 大于 0 时可以延迟接收对方的数据,该值控制延迟读数据 + * 的时间(单位为微秒) + * @param callback {aio_timer_reader*} 定时器到达时的回调函数类对象, + * 当 delay > 0,如果该值为空,则采用缺省的对象 + */ +#ifdef WIN32 + void gets(int timeout = 0, bool nonl = true, + __int64 delay = 0, aio_timer_reader* callback = NULL); +#else + void gets(int timeout = 0, bool nonl = true, + long long int delay = 0, aio_timer_reader* callback = NULL); +#endif + + /** + * 异步读取数据,当延迟异步读时,如果连续调用此过程, + * 则只有最后一个延迟读操作生效 + * @param count {int} 所要求读到的数据量,如果为 0 则只要有数据 + * 可读就返回,否则直到读超时或读出错或读满足所要求的字节数 + * @param timeout {int} 读超时时间(秒),若为 0 则表示 + * 永远等待直到读到所要求的数据或出错 + * @param delay {int64} 如果对方发送数据比较快时,此参数 + * 大于 0 时可以延迟接收对方的数据,该值控制延迟读数据 + * 的时间(单位为微秒) + * @param callback {aio_timer_reader*} 定时器到达时的回调函数类对象, + * 如果该值为空,则采用缺省的对象 + */ +#ifdef WIN32 + void read(int count = 0, int timeout = 0, + __int64 delay = 0, aio_timer_reader* callback = NULL); +#else + void read(int count = 0, int timeout = 0, + long long int delay = 0, aio_timer_reader* callback = NULL); +#endif + + /** + * 异步等待连接流可读,该函数设置异步流的读监听状态,当有数据可读 + * 时,回调函数被触发,由用户自己负责数据的读取 + * @param timeout {int} 读超时时间(秒),当该值为 0 时,则没有读超时 + */ + void read_wait(int timeout = 0); + + /** + * 禁止异步流的异步读状态,将该异步流从异步引擎的监控中 + * 移除,直到用户调用任何一个异步读操作(此时,异步引擎会 + * 自动重新监控该流的可读状态) + */ + void disable_read(); + + /** + * 设置流是否采用连接读功能 + * @param onoff {bool} + */ + void keep_read(bool onoff); + + /** + * 获得流是否是设置了连续读功能 + * @return {bool} + */ + bool keep_read() const; + +protected: + virtual ~aio_istream(); + + /** + * 释放动态类对象的虚函数 + */ + virtual void destroy(); + + /** + * 注册可读的回调函数 + */ + void hook_read(); + +private: + friend class aio_timer_reader; + aio_timer_reader* timer_reader_; + std::list read_callbacks_; + bool read_hooked_; + + static int read_callback(ACL_ASTREAM*, void*, char*, int); + static int read_wakeup(ACL_ASTREAM* stream, void* ctx); +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/stream/aio_listen_stream.hpp b/lib_acl_cpp/include/acl_cpp/stream/aio_listen_stream.hpp new file mode 100644 index 000000000..97d961dbb --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/stream/aio_listen_stream.hpp @@ -0,0 +1,81 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include "acl_cpp/stream/aio_stream.hpp" + +namespace acl +{ + +class aio_socket_stream; + +/** + * 当异步监听流接收到新的客户端流时调用此回调类中的回调函数, + * 该类为纯虚类,要求子类必须实现 accept_callback 回调过程 + */ +class ACL_CPP_API aio_accept_callback : public aio_callback +{ +public: + aio_accept_callback() {} + virtual ~aio_accept_callback() {} + + /** + * 当接收到新的客户端流时的回调函数 + * @param client {aio_socket_stream*} 客户端异步连接流, + * 可以对此流进行读写操作 + * @return {bool} 如果希望关闭该异步监听流,可以返回 false, + * 一般不应返回 false + */ + virtual bool accept_callback(aio_socket_stream* client) = 0; +protected: +private: +}; + +/** + * 异步监听网络流,该类接收来自于客户端的外来连接,同时该类只能 + * 在堆上分配,不能在栈分配,应用可以调用 close 主动关闭流,流关闭 + * 后该异步流对象自动释放,无需调用 delete 删除该类对象 + * + */ +class ACL_CPP_API aio_listen_stream : public aio_stream +{ +public: + /** + * 构造函数,用以构造异步监听流 + * @param handle {aio_handle*} 异步引擎句柄 + */ + aio_listen_stream(aio_handle* handle); + + /** + * 添加异步监听流接收到新客户端流时的回调函数 + * @param callback {aio_accept_callback*} + */ + void add_accept_callback(aio_accept_callback* callback); + + /** + * 开始监听某个指定地址,可以为网络套接口,也可以为域套接口, + * @param addr {const char*} 监听地址,TCP监听地址或域监听地址 + * 格式: + * 针对TCP连接:IP:PORT,如:127.0.0.1:9001 + * 针对域套接口:{path},如:/tmp/my.sock + * @return {bool} 监听是否成功 + */ + bool open(const char* addr); + + /** + * 获得服务器监听地址 + * @return {const char*} + */ + const char* get_addr() const; + + virtual void destroy(); +protected: + virtual ~aio_listen_stream(); +private: + bool accept_hooked_; + char addr_[256]; + std::list accept_callbacks_; + + void hook_accept(); + static int accept_callback(ACL_ASTREAM*, void*); +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/stream/aio_ostream.hpp b/lib_acl_cpp/include/acl_cpp/stream/aio_ostream.hpp new file mode 100644 index 000000000..abad9386f --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/stream/aio_ostream.hpp @@ -0,0 +1,170 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include +#include "acl_cpp/stdlib/string.hpp" +#include "acl_cpp/stream/aio_handle.hpp" +#include "acl_cpp/stream/aio_stream.hpp" + +namespace acl +{ + +class aio_ostream; + +/** + * 延迟异步写数据类,基类为 aio_timer_callback (see aio_handle.hpp), + * 所谓延迟异步写,就是把异步写流(aio_ostream)放在定时器中,将该异 + * 步流的异步写操作解除绑定(即从 aio_handle 的监控中解除),当指定 + * 时间到达后再启动异步写操作(在 timer_callback 回调中再重新将异步 + * 流的异步写操作绑定),同时该定时器自动销毁(调用 destroy 方法), + * 所以如果用户继承了 aio_timer_writer 类,且子类不是在堆上分配的, + * 则必须重载 destroy方法,同时在子类的 destroy 中执行与资源释放的 + * 相关操作,如果子类未重载 destroy,则当定时器结束后内部会自动调用 + * 基类 aio_timer_writer 的 destroy--该类调用了 delete this,此时就 + * 会导致非法内存释放操作) + * + */ +class ACL_CPP_API aio_timer_writer : public aio_timer_callback +{ +public: + aio_timer_writer(); + + /** + * 在 aio_istream 中调用此函数以释放类对象,子类应该实现该函数 + */ + virtual void destroy() + { + delete this; + } + +protected: + virtual ~aio_timer_writer(); + + /** + * 延迟读数据时的回调函数,从 aio_timer_callback 类中继承而来 + */ + virtual void timer_callback(unsigned int id); +private: + friend class aio_ostream; + + aio_ostream* out_; + int write_delayed_; + acl::string buf_; +}; + +/** + * 异步写数据流类定义,该类只能在堆上被实例化,在析构时需要调用 close + * 函数以释放该类对象 + */ +class ACL_CPP_API aio_ostream : virtual public aio_stream +{ +public: + /** + * 构造函数 + * @param handle {aio_handle*} 异步事件引擎句柄 + */ + aio_ostream(aio_handle* handle); + + /** + * 添加异可写时的回调类对象指针,如果该回调类对象已经存在,则只是 + * 使该对象处于打开可用状态 + * @param callback {aio_callback*} 继承 aio_callback 的子类回调类对象, + * 当异步流有数据时会先调用此回调类对象中的 write_callback 接口 + */ + void add_write_callback(aio_callback* callback); + + /** + * 从写回调对象集合中删除 + * @param callback {aio_callback*} 被删除的写回调对象, + * 若该值为空,则删除所有的回调写对象 + * @return {int} 返回被从回调对象集合中删除的回调对象的个数 + */ + int del_write_callback(aio_callback* callback = NULL); + + /** + * 禁止回调对象类集合中的某个回调类对象,但并不从回调类对象 + * 集合中删除,只是不被调用而已 + * @param callback {aio_callback*} 被禁用的写回调对象, + * 若该值为空,则禁用所有的写回调对象 + * @return {int} 返回被从回调对象集合中禁用的回调对象的个数 + */ + int disable_write_callback(aio_callback* callback = NULL); + + /** + * 启用所有的回调对象被调用 + * @param callback {aio_callback*} 启用指定的写回调对象, + * 如果该值为空,则启用所有的写回调对象 + * @return {int} 返回被启用的写回调对象的个数 + */ + int enable_write_callback(aio_callback* callback = NULL); + + /** + * 异步写规定字节数的数据,当完全写成功或出错或超时时会 + * 调用用户注册的回调函数,在延迟异步写时,当在一个函数 + * 内连续调用此过程时,每个延迟异步写操作会被加入延迟写 + * 的队列中,以保证每个延迟异步写操作都可在各自的定时器 + * 到达时被执行 + * @param data {const void*} 数据地址 + * @param len {int} 数据长度 + * @param delay {int64} 如果该值 > 0 则采用延迟发送的模式(单位为微秒) + * @param callback {aio_timer_writer*} 定时器到达时的回调函数类对象, + */ +#ifdef WIN32 + void write(const void* data, int len, __int64 delay = 0, + aio_timer_writer* callback = NULL); +#else + void write(const void* data, int len, long long int delay = 0, + aio_timer_writer* callback = NULL); +#endif + + /** + * 格式化方式异步写数据,当完全写成功或出错或超时时会 + * 调用用户注册的回调函数 + * @param fmt {const char*} 格式字符串 + */ + void format(const char* fmt, ...); + + /** + * 格式化方式异步写数据,当完全写成功或出错或超时时会 + * 调用用户注册的回调函数 + * @param fmt {const char*} 格式字符串 + * @param ap {va_list} 数据值列表 + */ + void vformat(const char* fmt, va_list ap); + + /** + * 异步等待连接流可写,该函数设置异步流的写监听状态,当有可写时, + * 回调函数被触发,由用户自己负责数据的读取 + * @param timeout {int} 写超时时间(秒),当该值为 0 时,则没有写超时 + */ + void write_wait(int timeout = 0); + + /** + * 禁止异步流的异步写状态,则将该异步流从异步引擎的监控 + * 事件中移除,直到用户调用任何一个写操作时会自动打开异 + * 步写状态(此时该流会重新被异步引擎监控) + */ + void disable_write(); +protected: + virtual ~aio_ostream(); + + /** + * 释放动态类对象的虚函数 + */ + virtual void destroy(); + + /** + * hook 写过程 + */ + void hook_write(); + +private: + friend class aio_timer_writer; + std::list timer_writers_; + std::list write_callbacks_; + bool write_hooked_; + + static int write_callback(ACL_ASTREAM*, void*); + static int write_wakup(ACL_ASTREAM*, void*); +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/stream/aio_socket_stream.hpp b/lib_acl_cpp/include/acl_cpp/stream/aio_socket_stream.hpp new file mode 100644 index 000000000..d4c688b64 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/stream/aio_socket_stream.hpp @@ -0,0 +1,137 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#ifdef WIN32 +# include +#endif +#include "acl_cpp/stream/aio_istream.hpp" +#include "acl_cpp/stream/aio_ostream.hpp" + +namespace acl +{ + +/** + * 当异步客户端流异步连接远程服务器时的回调函数类,该类为纯虚类, + * 要求子类必须实现 open_callback 回调过程 + */ +class ACL_CPP_API aio_open_callback : public aio_callback +{ +public: + aio_open_callback() {} + virtual ~aio_open_callback() {} + + virtual bool open_callback() = 0; +protected: +private: +}; + +struct AIO_OPEN_CALLBACK +{ + aio_open_callback* callback; + bool enable; +}; + +class aio_handle; + +/** + * 网络异步流类,该类继承了异步读写流,同时该类只能在堆上分配, + * 不能在栈上分配,并且该类结束时应用不必释放该类对象,因为异步流 + * 框架内部会自动释放该类对象,应用可以调用 close 主动关闭流 + */ +class ACL_CPP_API aio_socket_stream + : public aio_istream + , public aio_ostream +{ +public: + /** + * 构造函数,创建网络异步客户端流 + * @param handle {aio_handle*} 异步引擎句柄 + * @param stream {ACL_ASTREAM*} 非阻塞流 + * @param opened {bool} 该流是否已经与服务端正常建立了连接,如果是则自动 + * hook 读写过程及关闭/超时过程,否则仅 hook 关闭/超时过程 + */ + aio_socket_stream(aio_handle* handle, ACL_ASTREAM* stream, bool opened = false); + + /** + * 构造函数,创建网络异步客户端流,并 hook 读写过程及关闭/超时过程 + * @param handle {aio_handle*} 异步引擎句柄 + * @param fd {ACL_SOCKET} 连接套接口句柄 + */ +#ifdef WIN32 + aio_socket_stream(aio_handle* handle, SOCKET fd); +#else + aio_socket_stream(aio_handle* handle, int fd); +#endif + + /** + * 打开与远程服务器的连接,并自动 hook 流的关闭、超时以及连接成功 + * 时的回调处理过程 + * @param handle {aio_handle*} 异步引擎句柄 + * @param addr {const char*} 远程服务器的地址,地址格式为: + * 针对TCP:IP:Port 或 针对域套接口:{filePath} + * @param timeout {int} 连接超时时间(秒) + * @return {bool} 如果连接立即返回失败则该函数返回 false,如果返回 + * true 只是表示正处于连接过程中,至于连接是否超时或连接是否失败 + * 应通过回调函数来判断 + */ + static aio_socket_stream* open(aio_handle* handle, + const char* addr, int timeout); + + /** + * 添加针对 open 函数的回调过程 + * @param callback {aio_open_callback*} 回调函数 + */ + void add_open_callback(aio_open_callback* callback); + + /** + * 从 open 回调对象集合中删除 + * @param callback {aio_open_callback*} 被删除的回调对象,若该 + * 值为空,则删除所有的回调对象 + * @return {int} 返回被从回调对象集合中删除的回调对象的个数 + */ + int del_open_callback(aio_open_callback* callback = NULL); + + /** + * 禁止回调对象类集合中的某个回调类对象,但并不从回调类对象 + * 集合中删除,只是不被调用而已 + * @param callback {aio_open_callback*} 被禁止的回调对象,若该 + * 值为空,则禁止所有的回调对象 + * @return {int} 返回被从回调对象集合中禁用的回调对象的个数 + */ + int disable_open_callback(aio_open_callback* callback = NULL); + + /** + * 启用所有的回调对象被调用 + * @param callback {aio_open_callback*} 启用指定的回调对象, + * 如果该值为空,则启用所有的回调对象 + * @return {int} 返回被启用的回调对象的个数 + */ + int enable_open_callback(aio_open_callback* callback = NULL); + + /** + * 针对 open 过程,判断是否已经连接成功 + * @return {bool} 返回 true 表示连接成功,否则表示还连接成功 + */ + bool is_opened() const; + +protected: + virtual ~aio_socket_stream(); + + /** + * 通过此函数来动态释放只能在堆上分配的异步流类对象 + */ + virtual void destroy(); + + /** + * 注册流连接成功的回调过程 + */ + void hook_open(); + +private: + bool opened_; // 针对 open 函数而言表示连接是否成功 + bool open_hooked_; + std::list open_callbacks_; + + static int open_callback(ACL_ASTREAM*, void*); +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/stream/aio_stream.hpp b/lib_acl_cpp/include/acl_cpp/stream/aio_stream.hpp new file mode 100644 index 000000000..0d0a06e4a --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/stream/aio_stream.hpp @@ -0,0 +1,231 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include +#ifdef WIN32 +#include +#endif + +struct ACL_ASTREAM; +struct ACL_VSTREAM; + +namespace acl +{ + +/** + * 异步流回调类 + */ +class ACL_CPP_API aio_callback +{ +public: + aio_callback(void) {} + virtual ~aio_callback(void) {}; + + virtual void close_callback() {} + virtual bool timeout_callback() + { + return false; + } + + /** + * 读回调虚函数,该回调函数当满足了类 aio_istream 实例中的 + * gets/read 的可读条件后被调用,由异步框架内部将符合条件的数 + * 据读出,直接传递给用户的子类 + * @param data {char*} 读到的数据的指针地址 + * @param len {int} 读到的数据长度(> 0) + * @return {bool} 该函数返回 false 通知异步引擎关闭该异步流 + */ + virtual bool read_callback(char* data, int len) + { + (void) data; + (void) len; + return true; + } + + /** + * 读回调虚函数,该回调函数当满足了类 aio_istream 实例中的 + * read_wait 的可读条件即异步流中有数据可读时被调用;当超时时会 + * 调用 timeout_callback,流异常被关闭时会调用 close_callback + */ + virtual bool read_wakeup() + { + return true; + } + + /** + * 写成功后的回调虚函数 + * @return {bool} 该函数返回 false 通知异步引擎关闭该异步流 + */ + virtual bool write_callback() + { + return true; + } + + /** + * 读回调虚函数,该回调函数当满足了类 aio_ostream 实例中的 + * write_wait 的可写条件即异步流可写时被调用;当超时时会 + * 调用 timeout_callback,流异常被关闭时会调用 close_callback + */ + virtual bool write_wakeup() + { + return true; + } +protected: +private: +}; + +struct AIO_CALLBACK +{ + aio_callback* callback; + bool enable; +}; + +class aio_handle; + +/** + * 异步流基类,该类为纯虚类,不能被直接实例化,只能被子类继承使用 + * 该类只能在堆上分配,不能在栈上分配 + */ +class ACL_CPP_API aio_stream +{ +public: + /** + * 构造函数 + * @param handle {aio_handle*} + */ + aio_stream(aio_handle* handle); + + /** + * 关闭异步流 + */ + void close(); + + /** + * 添加关闭时的回调类对象指针,如果该回调类对象已经存在,则只是 + * 使该对象处于打开可用状态 + * @param callback {aio_callback*} 继承 aio_callback 的子类回调类对象, + * 当异步流关闭前会先调用此回调类对象中的 close_callback 接口 + */ + void add_close_callback(aio_callback* callback); + + /** + * 添加超时时的回调类对象指针,如果该回调类对象已经存在,则只是 + * 使该对象处于打开可用状态 + * @param callback {aio_callback*} 继承 aio_callback 的子类回调类对象, + * 当异步流关闭前会先调用此回调类对象中的 timeout_callback 接口 + */ + void add_timeout_callback(aio_callback* callback); + + /** + * 删除关闭时的回调类对象指针 + * @param callback {aio_callback*} 从 aio_callback 继承的子类对象指针, + * 若该值为空,则删除所有的关闭回调对象 + * @return {int} 返回被从回调对象集合中删除的回调对象的个数 + */ + int del_close_callback(aio_callback* callback = NULL); + + /** + * 删除超时时的回调类对象指针 + * @param callback {aio_callback*} 从 aio_callback 继承的子类对象指针, + * 若该值为空,则删除所有的超时回调对象 + * @return {int} 返回被从回调对象集合中删除的回调对象的个数 + */ + int del_timeout_callback(aio_callback* callback = NULL); + + /** + * 禁止关闭的回调类对象,但并不从关闭对象集合中删除 + * @param callback {aio_callback*} 从 aio_callback 继承的子类对象指针, + * 若该值为空,则禁止所有的关闭回调对象 + * @return {int} 返回被从回调对象集合中禁用的回调对象的个数 + */ + int disable_close_callback(aio_callback* callback = NULL); + + /** + * 禁止超时的回调类对象,但并不从超时对象集合中删除 + * @param callback {aio_callback*} 从 aio_callback 继承的子类对象指针, + * 若该值为空,则禁止所有的超时回调对象 + * @return {int} 返回被从回调对象集合中禁用的回调对象的个数 + */ + int disable_timeout_callback(aio_callback* callback = NULL); + + /** + * 启用所有的回调对象被调用 + * @param callback {aio_callback*} 启用指定的回调对象,如果该值为空, + * 则启用所有的关闭回调对象 + * @return {int} 返回被启用的回调对象的个数 + */ + int enable_close_callback(aio_callback* callback = NULL); + + /** + * 启用所有的回调对象被调用 + * @param callback {aio_callback*} 启用指定的回调对象,如果该值为空, + * 则启用所有的超时回调对象 + * @return {int} 返回被启用的回调对象的个数 + */ + int enable_timeout_callback(aio_callback* callback = NULL); + + /** + * 获得异步流对象 ACL_ASTREAM + * @return {ACL_ASTREAM*} + */ + ACL_ASTREAM* get_astream() const; + + /** + * 获得异步流对象中的同步流对象 ACL_VSTREAM + * @return {ACL_VSTREAM*} + */ + ACL_VSTREAM* get_vstream() const; + + /** + * 获得异步流中的 SOCKET 描述符 + * @return {ACL_SOCKET} 若不存在则返回 -1(UNIX) 或 INVALID_SOCKET(win32) + */ +#ifdef WIN32 + SOCKET get_socket() const; + SOCKET sock_handle() const +#else + int get_socket() const; + int sock_handle() const +#endif + { + return get_socket(); + } + + /** + * 获得异步流事件句柄 + * @return {aio_handle&} + */ + aio_handle& get_handle() const; + + /** + * 判断流是否处于 hooked 状态 + * @return {bool} + */ + bool is_hooked() const; + +protected: + aio_handle* handle_; + ACL_ASTREAM* stream_; + + virtual ~aio_stream(); + + /** + * 通过此函数来动态释放只能在堆上分配的异步流类对象 + */ + virtual void destroy(); + + /** + * 子类应在创建成功后调用该函数通知基类增加异步流句柄数, + * 同时 hook 流关闭及流超时时的回调过程 + */ + void hook_error(); + +private: + bool error_hooked_; + std::list close_callbacks_; + std::list timeout_callbacks_; + + static int close_callback(ACL_ASTREAM*, void*); + static int timeout_callback(ACL_ASTREAM*, void*); +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/stream/fstream.hpp b/lib_acl_cpp/include/acl_cpp/stream/fstream.hpp new file mode 100644 index 000000000..c43b63d3c --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/stream/fstream.hpp @@ -0,0 +1,71 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include "acl_cpp/stream/istream.hpp" +#include "acl_cpp/stream/ostream.hpp" + +namespace acl { + +class string; + +class ACL_CPP_API fstream + : public istream + , public ostream +{ +public: + fstream(void); + virtual ~fstream(void); + + /** + * 根据文件路径打开文件流, 这是最基础的打开文件的方式 + * @param path {const char*} 文件名 + * @param oflags {unsigned int} 标志位, We're assuming that O_RDONLY: 0x0000, + * O_WRONLY: 0x0001, O_RDWR: 0x0002, O_APPEND: 0x0008, O_CREAT: 0x0100, + * O_TRUNC: 0x0200, O_EXCL: 0x0400; just for win32, O_TEXT: 0x4000, + * O_BINARY: 0x8000, O_RAW: O_BINARY, O_SEQUENTIAL: 0x0020, O_RANDOM: 0x0010. + * @param mode {int} 打开文件句柄时的模式(如: 0600) + * @return {bool} 打开文件是否成功 + */ + bool open(const char* path, unsigned int oflags, int mode); + + /** + * 以读/写方式打开文件流,当文件不存在时则创建新文件,当文件存在时则 + * 将文件清空, 文件属性为 0700 + * @param path {const char*} 文件名 + * @return {bool} 打开文件是否成功 + */ + bool open_trunc(const char* path); + + /** + * 以读/写方式建新文件,文件属性为 0700, 若文件不存在则创建新文件,若存在则 + * 打开旧文件 + * @return {bool} 文件创建是否成功 + */ + bool create(const char* path); + + /** + * 关闭文件流,同时关闭文件句柄 + * @return {bool} 关闭是否成功 + */ + bool close(); + +#ifdef WIN32 + void open(void* fh, unsigned int oflags); + __int64 fseek(__int64 offset, int whence); + bool ftruncate(__int64 length); + __int64 fsize(void) const; + void* file_handle() const; +#else + void open(int fh, unsigned int oflags); + long long int fseek(long long int offset, int whence); + bool ftruncate(long long int length); + long long int fsize(void) const; + int file_handle() const; +#endif + /** + * 获得文件的全路径 + * @return {const char*} 若返回空则表示文件还未打开或出错 + */ + const char* file_path() const; +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/stream/ifstream.hpp b/lib_acl_cpp/include/acl_cpp/stream/ifstream.hpp new file mode 100644 index 000000000..1d835794e --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/stream/ifstream.hpp @@ -0,0 +1,39 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include "acl_cpp/stream/fstream.hpp" + +namespace acl { + +class string; + +class ACL_CPP_API ifstream: public fstream +{ +public: + ifstream() {} + virtual ~ifstream() {} + + /** + * 以只读方式打开已经存在的文件 + * @param path {const char*} 文件名 + * @return {bool} 打开文件是否成功 + */ + bool open_read(const char* path); + + /** + * 从打开的文件流中加载该文件中的所有内容到用户指定缓冲区内 + * @param s {string*} 用户缓冲区 + * @return {bool} 是否成功 + */ + bool load(string* s); + + /** + * 加载文件中的数据至用户指定缓冲区, 该函数是静态成员变量, + * 可直接使用 + * @param path {const char*} 文件名 + * @param s {string*} 用户缓冲区 + * @return {bool} 是否成功 + */ + static bool load(const char* path, string* s); +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/stream/istream.hpp b/lib_acl_cpp/include/acl_cpp/stream/istream.hpp new file mode 100644 index 000000000..4e6552736 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/stream/istream.hpp @@ -0,0 +1,197 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include +#include "acl_cpp/stream/stream.hpp" + +namespace acl { + +class string; + +/** + * 输入流操作类,如果想确切知道输入流是否关闭或出错或读到了文件流的 + * 尾部,应通过调用 stream->eof() 来进行判断 + */ + +class ACL_CPP_API istream : virtual public stream +{ +public: + istream() {} + virtual ~istream() {} + + int read(); + + /** + * 从输入流中读数据 + * @param buf {void*} 用户缓冲区 + * @param size {size_t} 用户缓冲区长度 + * @param loop {bool} 是否读满 size 后才返回 + * @return {int} 读操作结果, -1 表示关闭或出错, > 0 表示成功 + */ + int read(void* buf, size_t size, bool loop = true); + + /** + * 从输入流读数据直至读到所要求的字符串或出错才返回 + * @param buf {void*} 用户缓冲区 + * @param size_inout {size_t*} 作为参数时 *size_inout 表示缓冲 buf + * 的空间大小,函数返回后记录存储于 buf 中的数据长度 + * @param tag {const char*} 要求读到的字符串 + * @param taglen {size_t} tag 字符串的长度 + * @return {bool} 是否读到所要求的字符串数据 + */ + + bool readtags(void *buf, size_t* size_inout, const char *tag, size_t taglen); + + /** + * 从输入流中读到一行数据 + * @param buf {void*} 用户缓冲区 + * @param size_inout {size_t*} 作为参数时 *size_inout 表示缓冲 buf + * 的空间大小,函数返回后记录存储于 buf 中的数据长度 + * @param nonl {bool} 如果为 true 则会将读到的一行数据尾部的 "\r\n" + * 或 "\n" 去掉,*size_inout 存储的数据长度是去掉 "\r\n" 或 "\n" 后 + * 的长度;否则,保留数据行中的 "\r\n" 或 "\n",同时 *size_inout 存 + * 储的是包含 "\r\n" 或 "\n" 的数据长度 + * @return {bool} 是否读到了一行数据, 出错则返回 false; 对文件输入流而 + * 言,如果读到的数据是最后一部分数据且这部分数据不含 "\r\n" 或 "\n" + * 则也会返回 false, 调用者需要检查 *size_inout 值是否大于 0 + * 来确定是否读到了最后一部分数据 + */ + bool gets(void* buf, size_t* size_inout, bool nonl = true); + + /** + * 从输入流中读一个 64 位整数 + * @param n {acl_int64&} 64 位整数 + * @param loop {bool} 是否阻塞式读完8个字节 + * @return {bool} 是否读取成功 + */ +#ifdef WIN32 + bool read(__int64& n, bool loop = true); +#else + bool read(long long int& n, bool loop = true); +#endif + + /** + * 从输入流中读一个 32 位整数 + * @param n {int&} 32 位整数 + * @param loop {bool} 是否阻塞式读完4个字节 + * @return {bool} 是否读取成功 + */ + bool read(int& n, bool loop = true); + + /** + * 从输入流中读一个 16 位整数 + * @param n {short&} 16 位整数 + * @param loop {bool} 是否阻塞式读完2个字节 + * @return {bool} 是否读取成功 + */ + bool read(short& n, bool loop = true); + + /** + * 从输入流中读取一个字节 + * @param ch {char&} + * @return {bool} 读取是否成功 + */ + bool read(char& ch); + + /** + * 从输入流中读数据至缓冲区中 + * @param s {string*} 缓冲区,内部会首先自动清空该缓冲区 + * @param loop {bool} 是否阻塞式读满整个缓冲,缓冲区 + * 的容量为 s.capacity() + * @return {bool} 读数据是否成功 + */ + bool read(string& s, bool loop = true); + + /** + * 从输入流中读数据至缓冲区中 + * @param s {string*} 缓冲区,内部会首先自动清空该缓冲区 + * @param max {size_t} 希望读到的数据的最大值 + * @param loop {bool} 是否读到要求的 max 字节数为止 + * @return {bool} 读数据是否成功 + */ + bool read(string& s, size_t max, bool loop = true); + + /** + * 从输入流中读一行数据至缓冲区中 + * @param s {string&} 缓冲区,内部会首先自动清空该缓冲区 + * @param nonl {bool} 是否保留所读行数据中的 "\r\n" 或 "\n" + * @return {bool} 是否读到了一行数据 + * 1)如果返回 true 则说明读到了完整一行数据;如果该行数据中只有 + * "\r\n" 或 "\n",则 s 的内容为空,即:s.empty() == true + * 2)如果返回 false 则说明读关闭且未读到一行数据,此时 s 中有可能 + * 存储着部分数据,需要用 if (s.empty() == true) 判断一下 + */ + bool gets(string& s, bool nonl = true); + + /** + * 从输入流中读数据直到读到要求的字符串数据作为分隔符的数据, + * 读取的数据的最后部分应该是该字符串 + * @param s {string&} 缓冲区,内部会首先自动清空该缓冲区 + * @param tag {const string&} 要求读的字符串数据 + * @return {bool} 是否读到要求的字符串数据 + */ + bool readtags(string& s, const string& tag); + + /** + * 从输入流中读一个字节数据 + * @return {int} 所读字节的 ASCII 码值 + */ + int getch(void); + + /** + * 向输入流中放加一个字节的数据 + * @param ch {int} 一个字符的 ASCII 码值 + * @return {int} 如果返回值与 ch 值相同则表示正确,否则表示出错 + */ + int ugetch(int ch); + + /** + * 尝试性从输入流中读取一行数据 + * @param buf {string&} 缓冲区 + * @param nonl {bool} 是否保留所读行数据中的 "\r\n" 或 "\n" + * @param clear {bool} 是否内部自动清空 buf 缓冲区 + * @return {bool} 是否读了一行数据; 如果返回 false 并不表示输入 + * 流结束,只是表示未读到一个完整行数据,应该通过调用 stream->eof() + * 来检查输入流是否关闭,另外,如果仅读到了部分数据,则 buf 会存储 + * 这些部分数据 + */ + bool gets_peek(string& buf, bool nonl = true, bool clear = false); + + /** + * 尝试性从输入流中读取数据 + * @param buf {string&} 缓冲区 + * @param clear {bool} 函数开始时是否内部自动清空 buf 缓冲区 + * @return {bool} 是否读到数据, 如果返回 false 仅 表示未读完所要求 + * 的数据长度,应该通过调用 stream->eof() 来检查输入流是否关闭 + */ + bool read_peek(string& buf, bool clear = false); + + /** + * 尝试性从输入流中读取指定长度的数据 + * @param buf {string&} 缓冲区 + * @param cnt {size_t} 要求读到的数据长度 + * @param clear {bool} 函数开始时是否内部自动清空 buf 缓冲区 + * @return {bool} 是否读到所要求数据长度的数据, 如果返回 false 仅 + * 表示未读完所要求的数据长度,应该通过调用 stream->eof() 来检查 + * 输入流是否关闭 + */ + bool readn_peek(string& buf, size_t cnt, bool clear = false); + + /* 以下几个函数重载了输入操作符,它们都是阻塞式操作过程,且需要 + * 调用 stream->eof() 来判断输入流是否关闭或是否读到了文件尾 + */ + + istream& operator>>(string& s); +#ifdef WIN32 + istream& operator>>(__int64& n); +#else + istream& operator>>(long long int& n); +#endif + istream& operator>>(int& n); + istream& operator>>(short& n); + istream& operator>>(char& ch); + +protected: +private: +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/stream/ofstream.hpp b/lib_acl_cpp/include/acl_cpp/stream/ofstream.hpp new file mode 100644 index 000000000..5cb863dca --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/stream/ofstream.hpp @@ -0,0 +1,29 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include "acl_cpp/stream/fstream.hpp" + +namespace acl { + +class ACL_CPP_API ofstream : public fstream +{ +public: + ofstream(); + virtual ~ofstream(); + + /** + * 以只写方式打开文件,如果文件不存在则创建新文件,如果文件 + * 存在,则将文件内容清空 + * @param path {const char*} 文件名 + * @return {bool} 是否成功 + */ + bool open_write(const char* path); + + /** + * 以尾部添加方式打开文件,如果文件不存在则创建新文件 + * @param path {const char*} 文件名 + * @return {bool} 是否成功 + */ + bool open_append(const char* path); +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/stream/ostream.hpp b/lib_acl_cpp/include/acl_cpp/stream/ostream.hpp new file mode 100644 index 000000000..a18480518 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/stream/ostream.hpp @@ -0,0 +1,139 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include "acl_cpp/stream/stream.hpp" +#include "acl_cpp/stdlib/pipe_stream.hpp" + +namespace acl { + +class string; + +/** + * 输入流处理过程类,调用者想确切知道输出流是否出错或是否关闭, + * 应该调用 stream->eof() 来进行判断 + */ + +class ACL_CPP_API ostream + : virtual public stream + , public pipe_stream +{ +public: + ostream() {} + virtual ~ostream() {} + + /** + * 写数据至输出流中 + * @param v {const struct iovec*} + * @param count {int} 数组 v 的元素个数 + * @param loop {bool} 是否保证数据全部输出才返回,如果为 true, + * 则该函数直至数据全部输出或出错才会返回;否则仅写一次便返回, + * 但并不保证数据全部写完 + * @return {int} 真实写入的数据量, 返回 -1 表示出错 + */ + int writev(const struct iovec *v, int count, bool loop = true); + + /** + * 写数据至输出流中 + * @param data {const void*} 数据指针地址 + * @param size {size_t} data 数据长度(字节) + * @param loop {bool} 是否保证数据全部输出才返回,如果为 true, + * 则该函数直至数据全部输出或出错才会返回;否则仅写一次便返回, + * 但并不保证数据全部写完 + * @return {int} 真实写入的数据量, 返回 -1 表示出错 + */ + int write(const void* data, size_t size, bool loop = true); + + /** + * 带格式方式写数据,类似于 vfprintf,保证数据全部写入 + * @param fmt {const char*} 格式字符串 + * @param ap {va_list} 变参列表 + * @return {int} 真实写入的数据长度,返回 -1 表示出错 + */ + int vformat(const char* fmt, va_list ap); + + /** + * 带格式方式写数据,类似于 fprintf,保证数据全部写入 + * @param fmt {const char*} 变参格式字符串 + * @return {int} 真实写入的数据长度,返回 -1 表示出错 + */ + int format(const char* fmt, ...); + + /** + * 写入一个 64 位整数 + * @param n {acl_int64} 64 位数据 + * @return {int} 写入的数据长度,返回 -1 表示出错 + */ +#ifdef WIN32 + int write(__int64 n); +#else + int write(long long int n); +#endif + + /** + * 写入一个 32 位整数 + * @param n {int} 32 位整数 + * @return {int} 写入的数据长度,返回 -1 表示出错 + */ + int write(int n); + + /** + * 写入一个 16 位短整数 + * @param n {int} 16 位整数 + * @return {int} 写入的数据长度,返回 -1 表示出错 + */ + int write(short n); + + /** + * 写一个字节 + * @param ch {char} + * @return {int} 写入的数据长度,返回 -1 表示出错 + */ + int write(char ch); + + /** + * 输出缓冲区中的数据 + * @param s {const string&} + * @param loop {bool} 是否要求全部输出完才返回 + * @return {int} 输出数据的长度,返回 -1 表示出错 + */ + int write(const string& s, bool loop = true); + + /** + * 输出一行字符串数据,在所给字符串后添加 "\r\n" + * @param s {const char*} 字符串指针,必须以 '\0' 结尾 + * @return {int} 输出数据的长度,返回 -1 表示出错 + */ + int puts(const char* s); + + /** + * 以下几个函数为输出操作符重载函数,且都是阻塞输出过程, + * 如果想判断输出流是否出错或关闭应该调用 stream->eof() + * 来进行判断 + */ + + ostream& operator<<(const string& s); + ostream& operator<<(const char* s); +#ifdef WIN32 + ostream& operator<<(__int64 n); +#else + ostream& operator<<(long long int n); +#endif + ostream& operator<<(int n); + ostream& operator<<(short n); + ostream& operator<<(char ch); + + // pipe_stream 几个虚函数 + // 因为是输出流,所以仅实现一个 + virtual int push_pop(const char* in, size_t len, + string* out = NULL, size_t max = 0); + virtual int pop_end(string* out, size_t max = 0) + { + (void) out; + (void) max; + return (0); + } + +protected: +private: +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/stream/server_socket.hpp b/lib_acl_cpp/include/acl_cpp/stream/server_socket.hpp new file mode 100644 index 000000000..c3a9e9df6 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/stream/server_socket.hpp @@ -0,0 +1,79 @@ +#pragma once + +namespace acl { + +class socket_stream; + +/** + * 服务端监听套接口类,接收客户端连接,并创建客户端流连接对象 + */ +class server_socket +{ +public: + /** + * 构造函数 + * @param backlog {int} 监听套接口队列长度 + * @param block {bool} 是阻塞模式还是非阻塞模式 + */ + server_socket(int backlog = 128, bool block = true); + ~server_socket(); + + /** + * 开始监听给定服务端地址 + * @param addr {const char*} 服务器监听地址,格式为: + * ip:port;在 unix 环境下,还可以是域套接口,格式为: + * /path/xxx + * @return {bool} 监听是否成功 + */ + bool open(const char* addr); + + /** + * 关闭已经打开的监听套接口 + * @return {bool} 是否正常关闭 + */ + bool close(); + + /** + * 接收客户端连接并创建客户端连接流 + * @param timeout {int} 在阻塞模式下,当该值 > 0 时,采用超时 + * 方式接收客户端连接,若在指定时间内未获得客户端连接,则返回 NULL + * @return {socket_stream*} 返回空表示接收失败 + */ + socket_stream* accept(int timeout = 0); + + /** + * 获得监听的地址 + * @return {const char*} 返回值非空指针 + */ + const char* get_addr() const + { + return addr_; + } + + /** + * 当正常监听服务器地址后调用本函数可以获得监听套接口 + * @return {int} + */ +#ifdef WIN32 + SOCKET sock_handle() const +#else + int sock_handle() const +#endif + { + return fd_; + } + +private: + int backlog_; + bool block_; + bool unix_sock_; + char addr_[64]; + +#ifdef WIN32 + SOCKET fd_; +#else + int fd_; +#endif +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/stream/socket_stream.hpp b/lib_acl_cpp/include/acl_cpp/stream/socket_stream.hpp new file mode 100644 index 000000000..4d74f88c1 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/stream/socket_stream.hpp @@ -0,0 +1,120 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#ifdef WIN32 +#include +#endif +#include "acl_cpp/stream/istream.hpp" +#include "acl_cpp/stream/ostream.hpp" + +struct ACL_VSTREAM; + +namespace acl { + +class ACL_CPP_API socket_stream + : public istream + , public ostream +{ +public: + socket_stream(); + virtual ~socket_stream(); + + /** + * 根据套接字打开的一个网络流 + * @param fd 套接字 + * @return {bool} 连接是否成功 + */ +#ifdef WIN32 + bool open(SOCKET fd); +#else + bool open(int fd); +#endif + + /** + * 根据 ACL_VSTREAM 流打开网络流 + * @param vstream {ACL_VSTREAM*} + * @return {bool} 连接是否成功 + */ + bool open(ACL_VSTREAM* vstream); + + /** + * 连接远程服务器并打开网络连接流 + * @param addr {const char*} 远程服务器监听地址, 格式: IP:PORT, + * 对UNIX平台, 该地址还可以为域套接口地址, 如: /tmp/mysock + * @param conn_timeout {int} 连接超时时间(秒) + * @param rw_timeout {int} 读写超时时间(秒) + * @return {bool} 连接是否成功 + */ + bool open(const char* addr, int conn_timeout, int rw_timeout); + + /** + * 关闭网络连接流 + * @return {bool} 关闭是否成功 + */ + bool close(); + + /** + * 获得网络连接流的套接字连接句柄 + * @return {ACL_SOCKET} 若出错,则返回 - 1(UNIX 平台) + * 或 INVALID_SOCKET(win32平台) + */ +#ifdef WIN32 + SOCKET sock_handle() const; +#else + int sock_handle() const; +#endif + + /** + * 解绑套接字与流对象的绑定关系,同时将套接字返回给用户,即 + * 将该套接字的管理权交给用户,本流对象在释放时不会关闭该套 + * 接字,但用户接管该套接字后用完后必须将其关闭 + * 解绑后除了 close/open 的调用有意义外,其它的调用(包括流对 + * 象读写在内)都无意义 + * @return {ACL_SOCKET} 返回 ACL_SOCKET_INVALID 表示该流对象 + * 已经将套接字解绑 + */ +#ifdef WIN32 + SOCKET unbind_sock(); +#else + int unbind_sock(); +#endif + + /** + * 获得远程连接的地址 + * @param full {bool} 是否获得完整地址,即:IP:PORT,如果该参数 + * 为 false,则仅返回 IP,否则返回 IP:PORT + * @return {const char*} 远程连接地址,若返回值 == '\0' 则表示 + * 无法获得远程连接地址 + */ + const char* get_peer(bool full = false) const; + + /** + * 获得远程连接的 IP 地址 + * @return {const char*} 远程连接地址,若返回值 == '\0' 则表示 + * 无法获得远程连接地址 + */ + const char* get_peer_ip() const; + + /** + * 获得连接的本地地址 + * @param full {bool} 是否获得完整地址,即:IP:PORT,如果该参数 + * 为 false,则仅返回 IP,否则返回 IP:PORT + * @return {const char*} 该连接的本地地址,若返回值 == "" 则表示 + * 无法获得本地地址 + */ + const char* get_local(bool full = false) const; + + /** + * 获得连接的本地 IP 地址 + * @return {const char*} 该连接的本地地址,若返回值 == "" 则表示 + * 无法获得本地地址 + */ + const char* get_local_ip() const; +protected: +private: + char dummy_[1]; + char peer_ip_[33]; + char local_ip_[33]; + const char* get_ip(const char* addr, char* buf, size_t size); +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/stream/ssl_aio_stream.hpp b/lib_acl_cpp/include/acl_cpp/stream/ssl_aio_stream.hpp new file mode 100644 index 000000000..d6188abf8 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/stream/ssl_aio_stream.hpp @@ -0,0 +1,96 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include "acl_cpp/stream/aio_socket_stream.hpp" + +typedef struct _ssl_session ssl_session; +typedef struct _ssl_context ssl_context; + +namespace acl +{ + +class ACL_CPP_API ssl_aio_stream + : public aio_socket_stream + , public aio_open_callback +{ +public: + /** + * 构造函数,创建网络异步客户端流 + * @param handle {aio_handle*} 异步引擎句柄 + * @param stream {ACL_ASTREAM*} 非阻塞流 + * @param opened {bool} 该流是否已经与服务端正常建立了连接,如果是则自动 + * hook 读写过程及关闭/超时过程,否则仅 hook 关闭/超时过程 + * @param use_ssl {bool} 是否使用 SSL 套接口 + */ + ssl_aio_stream(aio_handle* handle, ACL_ASTREAM* stream, + bool opened = false, bool use_ssl = true); + + /** + * 构造函数,创建网络异步客户端流,并 hook 读写过程及关闭/超时过程 + * @param handle {aio_handle*} 异步引擎句柄 + * @param fd {ACL_SOCKET} 连接套接口句柄 + * @param use_ssl {bool} 是否使用 SSL 套接口 + */ +#ifdef WIN32 + ssl_aio_stream(aio_handle* handle, SOCKET fd, bool use_ssl = true); +#else + ssl_aio_stream(aio_handle* handle, int fd, bool use_ssl = true); +#endif + + /** + * 打开与远程服务器的连接,并自动 hook 流的关闭、超时以及连接成功 + * 时的回调处理过程 + * @param handle {aio_handle*} 异步引擎句柄 + * @param addr {const char*} 远程服务器的地址,地址格式为: + * 针对TCP:IP:Port 或 针对域套接口:{filePath} + * @param timeout {int} 连接超时时间(秒) + * @param use_ssl {bool} 是否使用 SSL 套接口 + * @return {bool} 如果连接立即返回失败则该函数返回 false,如果返回 + * true 只是表示正处于连接过程中,至于连接是否超时或连接是否失败 + * 应通过回调函数来判断 + */ + static ssl_aio_stream* open(aio_handle* handle, + const char* addr, int timeout, bool use_ssl = true); + + /** + * 该函数用来对已经打开的流进行操作,以允许后期将流设为 SSL 模式 + * 或非 SSL 模式 + * @param on {bool} 是否启用 SSL 模式,当该参数为 false 时,如果 + * 当前流已经是 SSL 模式,则关闭 SSL 模式,如果当前流为非 SSL + * 模式,则直接返回;当该参数为 true 时,如果当前流已经是 SSL + * 模式,则直接返回,如果当前流为非 SSL 模式,则打开 SSL 模式 + * @return {bool} + */ + bool open_ssl(bool on); + +protected: + virtual ~ssl_aio_stream(); + + /** + * 基类 aio_open_callback 的虚接口 + */ + virtual bool open_callback(); +private: + ssl_context* ssl_; + ssl_session* ssn_; + void* hs_; + + bool ssl_client_init(); + + static int __read(void *ctx, unsigned char *buf, size_t len); + static int __send(void *ctx, const unsigned char *buf, size_t len); + +#ifdef WIN32 + static int __ssl_read(SOCKET fd, void *buf, size_t len, + int timeout, void *ctx); + static int __ssl_send(SOCKET fd, const void *buf, size_t len, + int timeout, void *ctx); +#else + static int __ssl_read(int fd, void *buf, size_t len, + int timeout, void *ctx); + static int __ssl_send(int fd, const void *buf, size_t len, + int timeout, void *ctx); +#endif + void clear(void); +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/stream/ssl_stream.hpp b/lib_acl_cpp/include/acl_cpp/stream/ssl_stream.hpp new file mode 100644 index 000000000..d06b5a2fe --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/stream/ssl_stream.hpp @@ -0,0 +1,86 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" +#include "acl_cpp/stream/socket_stream.hpp" + +typedef struct _ssl_session ssl_session; +typedef struct _ssl_context ssl_context; + +namespace acl +{ + +class ACL_CPP_API ssl_stream : public socket_stream +{ +public: + ssl_stream(void); + virtual ~ssl_stream(void); + + /** + * 根据套接字打开的一个网络流 + * @param fd 套接字 + * @param use_ssl {bool} 是否采用 SSL 连接方式 + * @return {bool} 连接是否成功 + */ +#ifdef WIN32 + bool open_ssl(SOCKET fd, bool use_ssl = true); +#else + bool open_ssl(int fd, bool use_ssl = true); +#endif + + /** + * 根据 ACL_VSTREAM 流打开网络流 + * @param vstream {ACL_VSTREAM*} + * @param use_ssl {bool} 是否采用 SSL 加密传输方式 + * @return {bool} 连接是否成功 + */ + bool open_ssl(ACL_VSTREAM* vstream, bool use_ssl = true); + + /** + * 连接远程服务器并打开网络连接流 + * @param addr {const char*} 远程服务器监听地址, 格式: IP:PORT, + * 对UNIX平台, 该地址还可以为域套接口地址, 如: /tmp/mysock + * @param conn_timeout {int} 连接超时时间(秒) + * @param rw_timeout {int} 读写超时时间(秒) + * @param use_ssl {bool} 是否采用 SSL 加密传输方式 + * @return {bool} 连接是否成功 + */ + bool open_ssl(const char* addr, int conn_timeout, + int rw_timeout, bool use_ssl = true); + + /** + * 该函数用来对已经打开的流进行操作,以允许后期将流设为 SSL 模式 + * 或非 SSL 模式 + * @param on {bool} 是否启用 SSL 模式,当该参数为 false 时,如果 + * 当前流已经是 SSL 模式,则关闭 SSL 模式,如果当前流为非 SSL + * 模式,则直接返回;当该参数为 true 时,如果当前流已经是 SSL + * 模式,则直接返回,如果当前流为非 SSL 模式,则打开 SSL 模式 + * @return {bool} + */ + bool open_ssl(bool on); + +protected: +private: + ssl_context* ssl_; + ssl_session* ssn_; + void* hs_; + + bool ssl_client_init(void); + + static int __read(void *ctx, unsigned char *buf, size_t len); + static int __send(void *ctx, const unsigned char *buf, size_t len); + +#ifdef WIN32 + static int __ssl_read(SOCKET fd, void *buf, size_t len, + int timeout, void *ctx); + static int __ssl_send(SOCKET fd, const void *buf, size_t len, + int timeout, void *ctx); +#else + static int __ssl_read(int fd, void *buf, size_t len, + int timeout, void *ctx); + static int __ssl_send(int fd, const void *buf, size_t len, + int timeout, void *ctx); +#endif + + void clear(void); +}; + +} // namespace acl diff --git a/lib_acl_cpp/include/acl_cpp/stream/stream.hpp b/lib_acl_cpp/include/acl_cpp/stream/stream.hpp new file mode 100644 index 000000000..20913a516 --- /dev/null +++ b/lib_acl_cpp/include/acl_cpp/stream/stream.hpp @@ -0,0 +1,89 @@ +#pragma once +#include "acl_cpp/acl_cpp_define.hpp" + +struct ACL_VSTREAM; + +namespace acl { + +class ACL_CPP_API stream +{ +public: + stream(void); + virtual ~stream(void) = 0; + + /** + * 纯虚函数, 本类不能直接被实例化, 要求子类必须实现流关闭函数 + * @return {bool} true: 关闭成功; false: 关闭失败 + */ + virtual bool close(void) = 0; + + /** + * 判断流是否已经结束 + * @return {bool} true: 流已经结束; false: 流未结束 + */ + bool eof(void) const; + + /** + * 当前流是否处理打开状态 + * @return {bool} true: 流已经打开; false: 流未打开 + */ + bool opened(void) const; + + /** + * 获得当前流的 ACL_VSTREAM 流对象 + * @return {ACL_VSTREAM*} + */ + ACL_VSTREAM* get_vstream() const; + + /** + * 解绑 ACL_VSTREAM 与流对象的绑定关系,同时将 ACL_VSTREAM 返回 + * 给用户,即将该 ACL_VSTREAM的管理权交给用户,本流对象在释放时 + * 不会关闭该 ACL_VSTREAM ,但用户接管该 ACL_VSTREAM 后用完后 + * 必须将其关闭;解绑后除了 close/open 的调用有意义外,其它的调用 + * (包括流对象读写在内)都无意义 + * @return {ACL_VSTREAM} 返回 NULL 表示流对象已经将 ACL_VSTREAM 解绑 + */ + ACL_VSTREAM* unbind(); + + /** + * 打开流对象,如果流已经打开,则不会重复打开 + */ + void open_stream(void); + + /** + * 重新打开流对象,如果流已经打开则先释放流对象再打开 + */ + void reopen_stream(void); + + /** + * 设置流的绑定对象 + * @param ctx {void*} + */ + void set_ctx(void* ctx); + + /** + * 获得与流绑定的对象 + * @return {void*} + */ + void* get_ctx() const; + + /** + * 设置流的读写超时时间 + * @param n {int} 超时时间(单位: 秒) + */ + void set_rw_timeout(int n); + + /** + * 获得当前流的读写超时时间 + * @return {int} 获得流的读写超时时间(秒) + */ + int get_rw_timeout(void) const; +protected: + ACL_VSTREAM *m_pStream; + bool m_bEof; + bool m_bOpened; + + void* ctx_; +}; + +} // namespace acl diff --git a/lib_acl_cpp/lib/keep b/lib_acl_cpp/lib/keep new file mode 100644 index 000000000..139597f9c --- /dev/null +++ b/lib_acl_cpp/lib/keep @@ -0,0 +1,2 @@ + + diff --git a/lib_acl_cpp/lib_acl_cpp_vc2003.rc b/lib_acl_cpp/lib_acl_cpp_vc2003.rc new file mode 100644 index 000000000..480dc4c62 --- /dev/null +++ b/lib_acl_cpp/lib_acl_cpp_vc2003.rc @@ -0,0 +1,102 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource_vc2003.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// 中文(中华人民共和国) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) +#ifdef _WIN32 +LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED +#pragma code_page(936) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource_vc2003.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,1,1,2 + PRODUCTVERSION 1,1,1,2 + FILEFLAGSMASK 0x17L +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x7L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "080404b0" + BEGIN + VALUE "CompanyName", "zsx" + VALUE "FileDescription", "acl_cpp 库" + VALUE "FileVersion", "1, 1, 1, 2" + VALUE "InternalName", "lib_acl_" + VALUE "LegalCopyright", "acl_cpp (C) 2011" + VALUE "OriginalFilename", "lib_acl_cpp.lib" + VALUE "ProductName", "acl_cpp 库" + VALUE "ProductVersion", "1, 1, 1, 2" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x804, 1200 + END +END + +#endif // 中文(中华人民共和国) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/lib_acl_cpp/lib_acl_cpp_vc2003.vcproj b/lib_acl_cpp/lib_acl_cpp_vc2003.vcproj new file mode 100644 index 000000000..639bb09b0 --- /dev/null +++ b/lib_acl_cpp/lib_acl_cpp_vc2003.vcproj @@ -0,0 +1,1148 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_acl_cpp/lib_acl_cpp_vc2010.rc b/lib_acl_cpp/lib_acl_cpp_vc2010.rc new file mode 100644 index 000000000..d8b1d4aa3 --- /dev/null +++ b/lib_acl_cpp/lib_acl_cpp_vc2010.rc @@ -0,0 +1,101 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource_vc2010.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Chinese (Simplified, PRC) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) +LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED +#pragma code_page(936) + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource_vc2010.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,1,1,2 + PRODUCTVERSION 1,1,1,2 + FILEFLAGSMASK 0x17L +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x7L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "080404b0" + BEGIN + VALUE "Comments", "通用的C++库" + VALUE "CompanyName", "zsx" + VALUE "FileDescription", "lib_acl_cpp 库" + VALUE "FileVersion", "1.1.1.2" + VALUE "InternalName", "lib_acl_cpp" + VALUE "LegalCopyright", "版权所有 (C) 2011" + VALUE "OriginalFilename", "lib_acl_cpp.lib" + VALUE "ProductName", " lib_acl_cpp 库" + VALUE "ProductVersion", "1.1.1.2" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x804, 1200 + END +END + +#endif // Chinese (Simplified, PRC) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/lib_acl_cpp/lib_acl_cpp_vc2010.vcxproj b/lib_acl_cpp/lib_acl_cpp_vc2010.vcxproj new file mode 100644 index 000000000..a76f06ac9 --- /dev/null +++ b/lib_acl_cpp/lib_acl_cpp_vc2010.vcxproj @@ -0,0 +1,445 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + Releasedll + Win32 + + + Release + Win32 + + + + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + lib_acl_cpp + Win32Proj + lib_acl_cpp + + + + DynamicLibrary + MultiByte + + + DynamicLibrary + MultiByte + + + StaticLibrary + MultiByte + + + StaticLibrary + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + .\ + Debug\ + .\ + Release\ + .\ + $(Configuration)\ + .\ + $(Configuration)\ + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + $(ProjectName)_vc2010d + $(ProjectName)_d + $(ProjectName) + true + $(ProjectName)_vc2010 + + + + Disabled + .\include;..\lib_acl\include;..\lib_protocol\include;..\include\sqlite;..\include\zlib;..\include\mysql;..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_LIB;_MT;_CRT_SECURE_NO_WARNINGS;USE_WIN_ICONV;HAS_SQLITE;HAS_MYSQL;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Use + acl_stdafx.hpp + $(IntDir)$(TargetName).pch + $(OutDir)$(ProjectName)_vc2010d.pdb + Level3 + true + ProgramDatabase + + + $(OutDir)$(ProjectName)_vc2010d.lib + MachineX86 + + + copy $(TargetName).lib ..\dist\lib\win32\$(TargetName).lib /Y +copy $(TargetName).pdb ..\dist\lib\win32\$(TargetName).pdb /Y + + + + + .\include;..\lib_acl\include;..\lib_protocol\include;..\include\sqlite;..\include\zlib;..\include\mysql;..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;USE_WIN_ICONV;HAS_SQLITE;HAS_MYSQL;%(PreprocessorDefinitions) + MultiThreaded + Use + acl_stdafx.hpp + $(OutDir)$(ProjectName)_vc2010.pdb + Level3 + ProgramDatabase + + + $(OutDir)$(ProjectName)_vc2010.lib + MachineX86 + + + copy $(TargetName).lib ..\dist\lib\win32\$(TargetName).lib /Y +copy $(TargetName).pdb ..\dist\lib\win32\$(TargetName).pdb /Y + + + + + Disabled + .\include;..\lib_acl\include;..\lib_protocol\include;..\include\sqlite;..\include\zlib;..\include\mysql;..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_LIB;_MT;ACL_DLL;ACL_CPP_DLL;ACL_CPP_EXPORTS;USE_WIN_ICONV;_CRT_SECURE_NO_WARNINGS;HAS_SQLITE;HAS_MYSQL;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Use + acl_stdafx.hpp + $(IntDir)$(TargetName).pch + $(OutDir)$(ProjectName)_d.pdb + Level3 + true + ProgramDatabase + + + lib_protocol_d.lib;lib_acl_d.lib;polarssl.lib;%(AdditionalDependencies) + $(OutDir)$(ProjectName)_d.dll + ..\lib\win32;..\dist\lib\win32;%(AdditionalLibraryDirectories) + $(OutDir)$(TargetName).lib + true + libcmtd;libcmt;libc + true + true + + + copy $(TargetName).lib ..\dist\lib\win32\$(TargetName).lib /Y +copy $(TargetName).dll ..\dist\lib\win32\$(TargetName).dll /Y +copy $(TargetName).pdb ..\dist\lib\win32\$(TargetName).pdb /Y + + + + + + Disabled + .\include;..\lib_acl\include;..\lib_protocol\include;..\include\sqlite;..\include\zlib;..\include\mysql;.\src;..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;_MT;ACL_DLL;ACL_CPP_DLL;ACL_CPP_EXPORTS;USE_WIN_ICONV;_CRT_SECURE_NO_WARNINGS;HAS_SQLITE;HAS_MYSQL;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDLL + Use + acl_stdafx.hpp + $(IntDir)$(TargetName).pch + $(OutDir)$(ProjectName).pdb + Level3 + true + ProgramDatabase + + + lib_protocol.lib;lib_acl.lib;polarssl.lib;%(AdditionalDependencies) + $(OutDir)$(ProjectName).dll + ..\lib\win32;..\dist\lib\win32;%(AdditionalLibraryDirectories) + $(OutDir)$(TargetName).lib + libcmt;libc + + + copy $(TargetName).lib ..\dist\lib\win32\$(TargetName).lib /Y +copy $(TargetName).dll ..\dist\lib\win32\$(TargetName).dll /Y +copy $(TargetName).pdb ..\dist\lib\win32\$(TargetName).pdb /Y + + + + + + + + Create + Create + Create + Create + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib_acl_cpp/lib_acl_cpp_vc2010.vcxproj.filters b/lib_acl_cpp/lib_acl_cpp_vc2010.vcxproj.filters new file mode 100644 index 000000000..0948b1169 --- /dev/null +++ b/lib_acl_cpp/lib_acl_cpp_vc2010.vcxproj.filters @@ -0,0 +1,802 @@ +锘 + + + + src + + + src + + + src + + + src\mime + + + src\mime + + + src\mime + + + src\mime + + + src\mime + + + src\mime + + + src\mime + + + src\mime + + + src\mime + + + src\mime + + + src\mime + + + src\mime + + + src\mime + + + src\master + + + src\master + + + src\master + + + src\master + + + src\master + + + src\ipc + + + src\ipc + + + src\ipc + + + src\http + + + src\http + + + src\http + + + src\hsocket + + + src\hsocket + + + src\hsocket + + + src\hsocket + + + src\hsocket + + + src\hsocket + + + src\db + + + src\db + + + src\db + + + src\db + + + src\db + + + src\stdlib + + + src\stdlib + + + src\stdlib + + + src\stdlib + + + src\stdlib + + + src\stdlib + + + src\stdlib + + + src\stdlib + + + src\stdlib + + + src\stdlib + + + src\stream + + + src\stream + + + src\stream + + + src\stream + + + src\stream + + + src\stream + + + src\stream + + + src\stream + + + src\stream + + + src\stream + + + src\stream + + + src\stream + + + src\stream + + + src\stream + + + src\stream + + + src\mime\internal + + + src\mime\internal + + + src\mime\internal + + + src\mime\internal + + + src\mime\internal + + + src\mime\internal + + + src\mime\internal + + + src\mime\internal + + + src\mime\internal + + + src\mime\internal + + + src\mime\internal + + + src\mime\internal + + + src\mime\internal + + + src\stdlib\internal + + + src\db + + + src\db + + + src\stdlib + + + src\http + + + src\http + + + src\http + + + src\http + + + src\http + + + src\http + + + src\stdlib + + + src\http + + + src\http + + + src\http + + + src\ipc + + + src\master + + + src\http + + + src\http + + + src\stdlib + + + src\stdlib + + + src\session + + + src\session + + + src\beanstalk + + + src\queue + + + src\queue + + + src\http + + + src\stdlib + + + src\beanstalk + + + src\stream + + + src\stream + + + src\connpool + + + src\connpool + + + src\memcache + + + src\memcache + + + src\http + + + + + src + + + include + + + src\mime\internal + + + src\mime\internal + + + src\mime\internal + + + src\mime\internal + + + src\mime\internal + + + src\mime\internal + + + src\mime\internal + + + src\mime\internal + + + src\mime\internal + + + src\mime\internal + + + src\mime\internal + + + src\stdlib\internal + + + include\db + + + include\db + + + include\db + + + include\db + + + include\db + + + include\db + + + include\db + + + include\hsocket + + + include\hsocket + + + include\hsocket + + + include\hsocket + + + include\hsocket + + + include\hsocket + + + include\http + + + include\http + + + include\http + + + include\http + + + include\http + + + include\http + + + include\http + + + include\http + + + include\http + + + include\http + + + include\http + + + include\http + + + include\http + + + include\http + + + include\ipc + + + include\ipc + + + include\ipc + + + include\ipc + + + include\master + + + include\master + + + include\master + + + include\master + + + include\master + + + include\master + + + include\mime + + + include\mime + + + include\mime + + + include\mime + + + include\mime + + + include\mime + + + include\mime + + + include\mime + + + include\mime + + + include\mime + + + include\mime + + + include\mime + + + include\mime + + + include\mime + + + include\session + + + include\session + + + include\stdlib + + + include\stdlib + + + include\stdlib + + + include\stdlib + + + include\stdlib + + + include\stdlib + + + include\stdlib + + + include\stdlib + + + include\stdlib + + + include\stdlib + + + include\stdlib + + + include\stdlib + + + include\stdlib + + + include\stdlib + + + include\stdlib + + + include\stdlib + + + include\stdlib + + + include\stdlib + + + include\stream + + + include\stream + + + include\stream + + + include\stream + + + include\stream + + + include\stream + + + include\stream + + + include\stream + + + include\stream + + + include\stream + + + include\stream + + + include\stream + + + include\stream + + + include\stream + + + include\stream + + + include + + + include + + + include + + + include + + + include\beanstalk + + + include\queue + + + include\queue + + + include\stdlib + + + include\http + + + include\http + + + include\beanstalk + + + include\stream + + + include\stream + + + include\memcache + + + include\memcache + + + include\http + + + include\connpool + + + include\connpool + + + include\connpool + + + + + + + + + + + + {fd48fd8e-6d1f-453d-83ab-0ae0e780ea61} + + + {b32c2c23-ff56-49c9-b06e-111bf76f87d6} + + + {0c83d5a8-6836-4441-b274-df0457c53aa3} + + + {24be489e-2733-452f-9b03-15e89bfd00e9} + + + {d7d5c4e2-0bc4-4bb0-8a3f-280f38dffab1} + + + {d1887d6c-21ec-475b-bd00-1cdcc9a7638c} + + + {366c4a7a-52da-4c30-a5ff-4c1e0b55ca42} + + + {85c18bb9-83f9-43f3-b1a9-b90050bb7c9d} + + + {4d7baa9e-dfb8-4492-9755-34465cebaea9} + + + {8f2915a6-bdde-4405-a2aa-bde292765fe3} + + + {9f12de7c-d7c3-420f-9a60-9793db211ac3} + + + {f9db895a-582c-48a4-b774-1ab5720f9504} + + + {0018e60b-eb12-4931-bacc-873d9120d5f6} + + + {1e5a6664-4abc-450f-a90e-b6f54005a9ec} + + + {07e43147-2b00-4c35-bb54-e2236ccd10b4} + + + {bac1b5f2-f852-431e-9a1a-8e766ef41628} + + + {3fba5f16-8e84-4f34-a790-7cddab50bd01} + + + {81cebce6-9d46-42ef-8fa7-b7bdde75874b} + + + {7602c164-8abb-437a-9d62-2ef30121b955} + + + {3ad8990a-bc3b-45e5-a95d-b39874cbd89b} + + + {9610edea-3618-48cb-b775-679afa95c809} + + + {38eae937-c68c-41ec-8f96-045799bf54f3} + + + {3514e29b-4004-4e16-a72f-fd84cb24d059} + + + {e12b6c03-0697-416d-864a-6a026e3453a7} + + + {10c86744-c545-4b37-a494-7d4a5b1a1174} + + + {c6a1206e-5f76-4734-921d-2f535db47f05} + + + {9660da6b-1d05-48a9-8d15-b459f15a14ce} + + + {e9c69b7b-6c6c-4e0b-98af-1742e14371a8} + + + {1df40883-a4d1-44f2-84bf-87f3d46fc8b5} + + + {9cf41123-21b3-46aa-bca8-5943eadfc59d} + + + {7033a23c-1d75-4ee8-b6f4-751c1877f60d} + + + {91040771-66ce-4530-816d-10b9166321a2} + + + \ No newline at end of file diff --git a/lib_acl_cpp/lib_acl_cpp_vc2010.vcxproj.user b/lib_acl_cpp/lib_acl_cpp_vc2010.vcxproj.user new file mode 100644 index 000000000..ace9a86ac --- /dev/null +++ b/lib_acl_cpp/lib_acl_cpp_vc2010.vcxproj.user @@ -0,0 +1,3 @@ +锘 + + \ No newline at end of file diff --git a/lib_acl_cpp/lib_acl_cpp_vc2012.vcxproj b/lib_acl_cpp/lib_acl_cpp_vc2012.vcxproj new file mode 100644 index 000000000..c2c102e40 --- /dev/null +++ b/lib_acl_cpp/lib_acl_cpp_vc2012.vcxproj @@ -0,0 +1,454 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + Releasedll + Win32 + + + Release + Win32 + + + + {6EC1F44E-6A6A-48E9-B699-D7E89B63C8DC} + lib_acl_cpp + Win32Proj + lib_acl_cpp + + + + DynamicLibrary + MultiByte + v110 + + + DynamicLibrary + MultiByte + v110 + + + StaticLibrary + MultiByte + v110 + + + StaticLibrary + MultiByte + v110 + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + .\ + Debug\ + .\ + Release\ + .\ + $(Configuration)\ + .\ + $(Configuration)\ + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + $(ProjectName)_vc2012d + $(ProjectName)_d + $(ProjectName) + true + $(ProjectName)_vc2012 + + + + Disabled + .\include;..\lib_acl\include;..\lib_protocol\include;..\include\sqlite;..\include\zlib;..\include\mysql;..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_LIB;_MT;_CRT_SECURE_NO_WARNINGS;USE_WIN_ICONV;HAS_SQLITE;HAS_MYSQL;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Use + acl_stdafx.hpp + $(IntDir)$(TargetName).pch + $(OutDir)$(ProjectName)_vc2012d.pdb + Level3 + true + ProgramDatabase + + + $(OutDir)$(ProjectName)_vc2012d.lib + MachineX86 + + + copy $(TargetName).lib ..\dist\lib\win32\$(TargetName).lib /Y +copy $(TargetName).pdb ..\dist\lib\win32\$(TargetName).pdb /Y + + + + + .\include;..\lib_acl\include;..\lib_protocol\include;..\include\sqlite;..\include\zlib;..\include\mysql;..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;USE_WIN_ICONV;HAS_SQLITE;HAS_MYSQL;%(PreprocessorDefinitions) + MultiThreaded + Use + acl_stdafx.hpp + $(OutDir)$(ProjectName)_vc2012.pdb + Level3 + ProgramDatabase + + + $(OutDir)$(ProjectName)_vc2012.lib + MachineX86 + + + copy $(TargetName).lib ..\dist\lib\win32\$(TargetName).lib /Y +copy $(TargetName).pdb ..\dist\lib\win32\$(TargetName).pdb /Y + + + + + Disabled + .\include;..\lib_acl\include;..\lib_protocol\include;..\include\sqlite;..\include\zlib;..\include\mysql;..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_LIB;_MT;ACL_DLL;ACL_CPP_DLL;ACL_CPP_EXPORTS;USE_WIN_ICONV;_CRT_SECURE_NO_WARNINGS;HAS_SQLITE;HAS_MYSQL;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Use + acl_stdafx.hpp + $(IntDir)$(TargetName).pch + $(OutDir)$(ProjectName)_d.pdb + Level3 + true + ProgramDatabase + + + lib_protocol_d.lib;lib_acl_d.lib;polarssl.lib;%(AdditionalDependencies) + $(OutDir)$(ProjectName)_d.dll + ..\lib\win32;..\dist\lib\win32;%(AdditionalLibraryDirectories) + $(OutDir)$(TargetName).lib + true + libcmtd;libcmt;libc + true + true + + + copy $(TargetName).lib ..\dist\lib\win32\$(TargetName).lib /Y +copy $(TargetName).dll ..\dist\lib\win32\$(TargetName).dll /Y +copy $(TargetName).pdb ..\dist\lib\win32\$(TargetName).pdb /Y + + + + + + Disabled + .\include;..\lib_acl\include;..\lib_protocol\include;..\include\sqlite;..\include\zlib;..\include\mysql;.\src;..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;_MT;ACL_DLL;ACL_CPP_DLL;ACL_CPP_EXPORTS;USE_WIN_ICONV;_CRT_SECURE_NO_WARNINGS;HAS_SQLITE;HAS_MYSQL;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDLL + Use + acl_stdafx.hpp + $(IntDir)$(TargetName).pch + $(OutDir)$(ProjectName).pdb + Level3 + true + ProgramDatabase + + + lib_protocol.lib;lib_acl.lib;polarssl.lib;%(AdditionalDependencies) + $(OutDir)$(ProjectName).dll + ..\lib\win32;..\dist\lib\win32;%(AdditionalLibraryDirectories) + $(OutDir)$(TargetName).lib + libcmt;libc + + + copy $(TargetName).lib ..\dist\lib\win32\$(TargetName).lib /Y +copy $(TargetName).dll ..\dist\lib\win32\$(TargetName).dll /Y +copy $(TargetName).pdb ..\dist\lib\win32\$(TargetName).pdb /Y + + + + + + + + Create + Create + Create + Create + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib_acl_cpp/lib_acl_cpp_vc2012.vcxproj.filters b/lib_acl_cpp/lib_acl_cpp_vc2012.vcxproj.filters new file mode 100644 index 000000000..7f64dc4c0 --- /dev/null +++ b/lib_acl_cpp/lib_acl_cpp_vc2012.vcxproj.filters @@ -0,0 +1,815 @@ +锘 + + + + src + + + src + + + src + + + src\mime + + + src\mime + + + src\mime + + + src\mime + + + src\mime + + + src\mime + + + src\mime + + + src\mime + + + src\mime + + + src\mime + + + src\mime + + + src\mime + + + src\mime + + + src\master + + + src\master + + + src\master + + + src\master + + + src\master + + + src\ipc + + + src\ipc + + + src\ipc + + + src\http + + + src\http + + + src\http + + + src\hsocket + + + src\hsocket + + + src\hsocket + + + src\hsocket + + + src\hsocket + + + src\hsocket + + + src\db + + + src\db + + + src\db + + + src\db + + + src\db + + + src\stdlib + + + src\stdlib + + + src\stdlib + + + src\stdlib + + + src\stdlib + + + src\stdlib + + + src\stdlib + + + src\stdlib + + + src\stdlib + + + src\stdlib + + + src\stream + + + src\stream + + + src\stream + + + src\stream + + + src\stream + + + src\stream + + + src\stream + + + src\stream + + + src\stream + + + src\stream + + + src\stream + + + src\stream + + + src\stream + + + src\stream + + + src\stream + + + src\mime\internal + + + src\mime\internal + + + src\mime\internal + + + src\mime\internal + + + src\mime\internal + + + src\mime\internal + + + src\mime\internal + + + src\mime\internal + + + src\mime\internal + + + src\mime\internal + + + src\mime\internal + + + src\mime\internal + + + src\mime\internal + + + src\stdlib\internal + + + src\db + + + src\db + + + src\stdlib + + + src\http + + + src\http + + + src\http + + + src\http + + + src\http + + + src\http + + + src\stdlib + + + src\http + + + src\http + + + src\http + + + src\ipc + + + src\master + + + src\http + + + src\http + + + src\stdlib + + + src\stdlib + + + src\session + + + src\session + + + src\beanstalk + + + src\queue + + + src\queue + + + src\http + + + src\stdlib + + + src\beanstalk + + + src\stream + + + src\stream + + + src\db + + + src\db + + + src\connpool + + + src\connpool + + + src\http + + + src\memcache + + + src\memcache + + + + + src + + + include + + + src\mime\internal + + + src\mime\internal + + + src\mime\internal + + + src\mime\internal + + + src\mime\internal + + + src\mime\internal + + + src\mime\internal + + + src\mime\internal + + + src\mime\internal + + + src\mime\internal + + + src\mime\internal + + + src\stdlib\internal + + + include\db + + + include\db + + + include\db + + + include\db + + + include\db + + + include\db + + + include\db + + + include\hsocket + + + include\hsocket + + + include\hsocket + + + include\hsocket + + + include\hsocket + + + include\hsocket + + + include\http + + + include\http + + + include\http + + + include\http + + + include\http + + + include\http + + + include\http + + + include\http + + + include\http + + + include\http + + + include\http + + + include\http + + + include\http + + + include\http + + + include\ipc + + + include\ipc + + + include\ipc + + + include\ipc + + + include\master + + + include\master + + + include\master + + + include\master + + + include\master + + + include\master + + + include\mime + + + include\mime + + + include\mime + + + include\mime + + + include\mime + + + include\mime + + + include\mime + + + include\mime + + + include\mime + + + include\mime + + + include\mime + + + include\mime + + + include\mime + + + include\mime + + + include\session + + + include\session + + + include\stdlib + + + include\stdlib + + + include\stdlib + + + include\stdlib + + + include\stdlib + + + include\stdlib + + + include\stdlib + + + include\stdlib + + + include\stdlib + + + include\stdlib + + + include\stdlib + + + include\stdlib + + + include\stdlib + + + include\stdlib + + + include\stdlib + + + include\stdlib + + + include\stdlib + + + include\stdlib + + + include\stream + + + include\stream + + + include\stream + + + include\stream + + + include\stream + + + include\stream + + + include\stream + + + include\stream + + + include\stream + + + include\stream + + + include\stream + + + include\stream + + + include\stream + + + include\stream + + + include\stream + + + include + + + include + + + include + + + include + + + include\beanstalk + + + include\queue + + + include\queue + + + include\stdlib + + + include\http + + + include\http + + + include\beanstalk + + + include\stream + + + include\stream + + + include\db + + + include\db + + + include\connpool + + + include\connpool + + + include\connpool + + + include\http + + + include\memcache + + + include\memcache + + + + + + + + + + + + + {fd48fd8e-6d1f-453d-83ab-0ae0e780ea61} + + + {b32c2c23-ff56-49c9-b06e-111bf76f87d6} + + + {0c83d5a8-6836-4441-b274-df0457c53aa3} + + + {24be489e-2733-452f-9b03-15e89bfd00e9} + + + {d7d5c4e2-0bc4-4bb0-8a3f-280f38dffab1} + + + {d1887d6c-21ec-475b-bd00-1cdcc9a7638c} + + + {366c4a7a-52da-4c30-a5ff-4c1e0b55ca42} + + + {85c18bb9-83f9-43f3-b1a9-b90050bb7c9d} + + + {4d7baa9e-dfb8-4492-9755-34465cebaea9} + + + {8f2915a6-bdde-4405-a2aa-bde292765fe3} + + + {9f12de7c-d7c3-420f-9a60-9793db211ac3} + + + {f9db895a-582c-48a4-b774-1ab5720f9504} + + + {0018e60b-eb12-4931-bacc-873d9120d5f6} + + + {1e5a6664-4abc-450f-a90e-b6f54005a9ec} + + + {07e43147-2b00-4c35-bb54-e2236ccd10b4} + + + {bac1b5f2-f852-431e-9a1a-8e766ef41628} + + + {3fba5f16-8e84-4f34-a790-7cddab50bd01} + + + {81cebce6-9d46-42ef-8fa7-b7bdde75874b} + + + {7602c164-8abb-437a-9d62-2ef30121b955} + + + {3ad8990a-bc3b-45e5-a95d-b39874cbd89b} + + + {9610edea-3618-48cb-b775-679afa95c809} + + + {38eae937-c68c-41ec-8f96-045799bf54f3} + + + {3514e29b-4004-4e16-a72f-fd84cb24d059} + + + {e12b6c03-0697-416d-864a-6a026e3453a7} + + + {10c86744-c545-4b37-a494-7d4a5b1a1174} + + + {c6a1206e-5f76-4734-921d-2f535db47f05} + + + {9660da6b-1d05-48a9-8d15-b459f15a14ce} + + + {e9c69b7b-6c6c-4e0b-98af-1742e14371a8} + + + {1df40883-a4d1-44f2-84bf-87f3d46fc8b5} + + + {9cf41123-21b3-46aa-bca8-5943eadfc59d} + + + {558e804c-bb2d-4045-81fd-d650d1a5e166} + + + {477f1b57-f0e0-4eb7-9343-8f13a8618463} + + + \ No newline at end of file diff --git a/lib_acl_cpp/resource_vc2003.h b/lib_acl_cpp/resource_vc2003.h new file mode 100644 index 000000000..e499d19d3 --- /dev/null +++ b/lib_acl_cpp/resource_vc2003.h @@ -0,0 +1,15 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by lib_acl_cpp_vc2003.rc +// + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/lib_acl_cpp/resource_vc2010.h b/lib_acl_cpp/resource_vc2010.h new file mode 100644 index 000000000..a43153608 --- /dev/null +++ b/lib_acl_cpp/resource_vc2010.h @@ -0,0 +1,15 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by lib_acl_cpp_vc2010.rc +// + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/lib_acl_cpp/samples/HttpClient/HttpClient.aps b/lib_acl_cpp/samples/HttpClient/HttpClient.aps new file mode 100644 index 000000000..c41c1f8f4 Binary files /dev/null and b/lib_acl_cpp/samples/HttpClient/HttpClient.aps differ diff --git a/lib_acl_cpp/samples/HttpClient/HttpClient.cpp b/lib_acl_cpp/samples/HttpClient/HttpClient.cpp new file mode 100644 index 000000000..bb09cea65 --- /dev/null +++ b/lib_acl_cpp/samples/HttpClient/HttpClient.cpp @@ -0,0 +1,79 @@ +// HttpClient.cpp : 定义应用程序的类行为。 +// + +#include "stdafx.h" +#include "HttpClient.h" +#include "HttpClientDlg.h" +// +//#ifdef _DEBUG +//#define new DEBUG_NEW +//#endif + + +// CHttpClientApp + +BEGIN_MESSAGE_MAP(CHttpClientApp, CWinApp) + ON_COMMAND(ID_HELP, CWinApp::OnHelp) +END_MESSAGE_MAP() + + +// CHttpClientApp 构造 + +CHttpClientApp::CHttpClientApp() +{ + // TODO: 在此处添加构造代码, + // 将所有重要的初始化放置在 InitInstance 中 +} + + +// 唯一的一个 CHttpClientApp 对象 + +CHttpClientApp theApp; + + +// CHttpClientApp 初始化 + +BOOL CHttpClientApp::InitInstance() +{ + // 如果一个运行在 Windows XP 上的应用程序清单指定要 + // 使用 ComCtl32.dll 版本 6 或更高版本来启用可视化方式, + //则需要 InitCommonControls()。否则,将无法创建窗口。 + InitCommonControls(); + + CWinApp::InitInstance(); + + if (!AfxSocketInit()) + { + AfxMessageBox(IDP_SOCKETS_INIT_FAILED); + return FALSE; + } + + AfxEnableControlContainer(); + + // 标准初始化 + // 如果未使用这些功能并希望减小 + // 最终可执行文件的大小,则应移除下列 + // 不需要的特定初始化例程 + // 更改用于存储设置的注册表项 + // TODO: 应适当修改该字符串, + // 例如修改为公司或组织名 + SetRegistryKey(_T("应用程序向导生成的本地应用程序")); + + CHttpClientDlg dlg; + m_pMainWnd = &dlg; + INT_PTR nResponse = dlg.DoModal(); + if (nResponse == IDOK) + { + // TODO: 在此放置处理何时用“确定”来关闭 + //对话框的代码 + } + else if (nResponse == IDCANCEL) + { + // TODO: 在此放置处理何时用“取消”来关闭 + //对话框的代码 + } + + // 由于对话框已关闭,所以将返回 FALSE 以便退出应用程序, + // 而不是启动应用程序的消息泵。 + return FALSE; +} diff --git a/lib_acl_cpp/samples/HttpClient/HttpClient.h b/lib_acl_cpp/samples/HttpClient/HttpClient.h new file mode 100644 index 000000000..045986591 --- /dev/null +++ b/lib_acl_cpp/samples/HttpClient/HttpClient.h @@ -0,0 +1,31 @@ +// HttpClient.h : PROJECT_NAME 应用程序的主头文件 +// + +#pragma once + +#ifndef __AFXWIN_H__ + #error 在包含用于 PCH 的此文件之前包含“stdafx.h” +#endif + +#include "resource.h" // 主符号 + + +// CHttpClientApp: +// 有关此类的实现,请参阅 HttpClient.cpp +// + +class CHttpClientApp : public CWinApp +{ +public: + CHttpClientApp(); + +// 重写 + public: + virtual BOOL InitInstance(); + +// 实现 + + DECLARE_MESSAGE_MAP() +}; + +extern CHttpClientApp theApp; diff --git a/lib_acl_cpp/samples/HttpClient/HttpClient.rc b/lib_acl_cpp/samples/HttpClient/HttpClient.rc new file mode 100644 index 000000000..09e05a6c6 --- /dev/null +++ b/lib_acl_cpp/samples/HttpClient/HttpClient.rc @@ -0,0 +1,201 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// 中文(中华人民共和国) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) +#ifdef _WIN32 +LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED +#pragma code_page(936) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "#define _AFX_NO_SPLITTER_RESOURCES\r\n" + "#define _AFX_NO_OLE_RESOURCES\r\n" + "#define _AFX_NO_TRACKER_RESOURCES\r\n" + "#define _AFX_NO_PROPERTY_RESOURCES\r\n" + "\r\n" + "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)\r\n" + "LANGUAGE 4, 2\r\n" + "#pragma code_page(936)\r\n" + "#include ""res\\HttpClient.rc2"" // 非 Microsoft Visual C++ 编辑过的资源\r\n" + "#include ""afxres.rc"" // 标准组件\r\n" + "#endif\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDR_MAINFRAME ICON "res\\HttpClient.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_ABOUTBOX DIALOGEX 0, 0, 235, 55 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | + WS_SYSMENU +CAPTION "关于 HttpClient" +FONT 9, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + ICON IDR_MAINFRAME,IDC_STATIC,11,17,20,20 + LTEXT "HttpClient Version 1.0",IDC_STATIC,40,10,119,8, + SS_NOPREFIX + LTEXT "Copyright (C) 2011",IDC_STATIC,40,25,119,8 + DEFPUSHBUTTON "确定",IDOK,178,7,50,16,WS_GROUP +END + +IDD_HTTPCLIENT_DIALOG DIALOGEX 0, 0, 320, 200 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | + WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_APPWINDOW +CAPTION "HttpClient" +FONT 9, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + DEFPUSHBUTTON "确定",IDOK,263,7,50,16 + PUSHBUTTON "取消",IDCANCEL,263,25,50,16 + PUSHBUTTON "开始下载",IDC_DOWNLOAD,94,147,50,14 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "080403a8" + BEGIN + VALUE "CompanyName", "TODO: <公司名>" + VALUE "FileDescription", "TODO: <文件说明>" + VALUE "FileVersion", "1.0.0.1" + VALUE "InternalName", "HttpClient.exe" + VALUE "LegalCopyright", "TODO: (C) <公司名>。保留所有权利。" + VALUE "OriginalFilename", "HttpClient.exe" + VALUE "ProductName", "TODO: <产品名>" + VALUE "ProductVersion", "1.0.0.1" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "翻译", 0x804, 936 + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_ABOUTBOX, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 228 + TOPMARGIN, 7 + BOTTOMMARGIN, 48 + END + + IDD_HTTPCLIENT_DIALOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 313 + TOPMARGIN, 7 + BOTTOMMARGIN, 193 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + IDS_ABOUTBOX "关于 HttpClient(&A)..." + IDP_SOCKETS_INIT_FAILED "Windows 套接字初始化失败。" +END + +#endif // 中文(中华人民共和国) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +#define _AFX_NO_SPLITTER_RESOURCES +#define _AFX_NO_OLE_RESOURCES +#define _AFX_NO_TRACKER_RESOURCES +#define _AFX_NO_PROPERTY_RESOURCES + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) +LANGUAGE 4, 2 +#pragma code_page(936) +#include "res\HttpClient.rc2" // 非 Microsoft Visual C++ 编辑过的资源 +#include "afxres.rc" // 标准组件 +#endif + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/lib_acl_cpp/samples/HttpClient/HttpClient.vcproj b/lib_acl_cpp/samples/HttpClient/HttpClient.vcproj new file mode 100644 index 000000000..ac5854c71 --- /dev/null +++ b/lib_acl_cpp/samples/HttpClient/HttpClient.vcproj @@ -0,0 +1,341 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_acl_cpp/samples/HttpClient/HttpClient.vcxproj b/lib_acl_cpp/samples/HttpClient/HttpClient.vcxproj new file mode 100644 index 000000000..e8cb9adff --- /dev/null +++ b/lib_acl_cpp/samples/HttpClient/HttpClient.vcxproj @@ -0,0 +1,261 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + Releasedll + Win32 + + + Release + Win32 + + + Template + Win32 + + + + {C0A7DB86-EF13-4A3E-9F34-8950521C9675} + MFCProj + + + + Application + Dynamic + MultiByte + + + Application + Dynamic + MultiByte + + + Application + Static + MultiByte + + + Application + Dynamic + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + Debug\ + Debug\ + true + true + Release\ + Release\ + Release\ + Release\ + false + false + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + + + + + + Disabled + ..\..\..\lib_protocol\include;..\..\..\lib_acl\include;..\..\include;%(AdditionalIncludeDirectories) + WIN32;_WINDOWS;_DEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + true + Use + Level3 + EditAndContinue + + + lib_acl_d.lib;lib_protocol_d.lib;lib_acl_cpp_d.lib;%(AdditionalDependencies) + ..\..\..\lib\win32;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + %(IgnoreSpecificDefaultLibraries) + true + Windows + MachineX86 + + + _DEBUG;%(PreprocessorDefinitions) + false + + + _DEBUG;%(PreprocessorDefinitions) + 0x0804 + $(IntDir);%(AdditionalIncludeDirectories) + + + + + Disabled + ..\..\..\lib_protocol\include;..\..\..\lib_acl\include;..\..\include;%(AdditionalIncludeDirectories) + WIN32;_WINDOWS;_DEBUG;ACL_CPP_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + true + Use + Level3 + EditAndContinue + + + lib_acl_d.lib;lib_protocol_d.lib;lib_acl_cpp_d.lib;%(AdditionalDependencies) + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + libcmtd;%(IgnoreSpecificDefaultLibraries) + true + Windows + MachineX86 + + + _DEBUG;%(PreprocessorDefinitions) + false + + + _DEBUG;%(PreprocessorDefinitions) + 0x0804 + $(IntDir);%(AdditionalIncludeDirectories) + + + + + WIN32;_WINDOWS;NDEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + false + MultiThreadedDLL + true + Use + Level3 + ProgramDatabase + ..\..\..\lib_protocol\include;..\..\..\lib_acl\include;..\..\include;%(AdditionalIncludeDirectories) + + + true + Windows + true + true + MachineX86 + ..\..\lib;..\..\..\dist\lib\win32 + lib_acl.lib;lib_protocol.lib;lib_acl_cpp.lib;%(AdditionalDependencies) + libcmt + + + NDEBUG;%(PreprocessorDefinitions) + false + + + NDEBUG;%(PreprocessorDefinitions) + 0x0804 + $(IntDir);%(AdditionalIncludeDirectories) + + + + + WIN32;_WINDOWS;NDEBUG;ACL_CPP_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + false + MultiThreadedDLL + true + Use + Level3 + ProgramDatabase + ..\..\..\lib_protocol\include;..\..\..\lib_acl\include;..\..\include;%(AdditionalIncludeDirectories) + + + true + Windows + true + true + MachineX86 + ..\..\lib;..\..\..\dist\lib\win32 + lib_acl.lib;lib_protocol.lib;lib_acl_cpp.lib;%(AdditionalDependencies) + libcmt + + + NDEBUG;%(PreprocessorDefinitions) + false + + + NDEBUG;%(PreprocessorDefinitions) + 0x0804 + $(IntDir);%(AdditionalIncludeDirectories) + + + copy ..\..\..\dist\lib\win32\lib_acl.dll $(OutDir)\ /Y +copy ..\..\..\dist\lib\win32\lib_acl_cpp.dll $(OutDir)\ /Y + + + + + + + + Create + Create + Create + Create + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib_acl_cpp/samples/HttpClient/HttpClientDlg.cpp b/lib_acl_cpp/samples/HttpClient/HttpClientDlg.cpp new file mode 100644 index 000000000..dae93bd2e --- /dev/null +++ b/lib_acl_cpp/samples/HttpClient/HttpClientDlg.cpp @@ -0,0 +1,226 @@ +// HttpClientDlg.cpp : 实现文件 +// + +#include "stdafx.h" +#include "acl_cpp/stdlib/string.hpp" +#include "acl_cpp/stream/aio_handle.hpp" +#include "HttpClient.h" +#include "HttpClientDlg.h" +#include "HttpDownload.h" +#include ".\httpclientdlg.h" + +//#ifdef _DEBUG +//#define new DEBUG_NEW +//#endif + + +// 用于应用程序“关于”菜单项的 CAboutDlg 对话框 + +class CAboutDlg : public CDialog +{ +public: + CAboutDlg(); + +// 对话框数据 + enum { IDD = IDD_ABOUTBOX }; + + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 + +// 实现 +protected: + DECLARE_MESSAGE_MAP() +}; + +CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) +{ +} + +void CAboutDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); +} + +BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) +END_MESSAGE_MAP() + + +// CHttpClientDlg 对话框 + + + +CHttpClientDlg::CHttpClientDlg(CWnd* pParent /*=NULL*/) + : CDialog(CHttpClientDlg::IDD, pParent) + , handle_(acl::ENGINE_WINMSG) + , service_(NULL) +{ + m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); +} + +CHttpClientDlg::~CHttpClientDlg() +{ + if (service_) + { + delete service_; + + // service_ 会与一个异步IO绑定,当删除后并不会立即关闭 + // 该异步 IO,因为异步引擎采用延迟关闭机制,所以需要调 + // 用 handle_check() 来主动释放延迟释放队列里的异步 IO + handle_.check(); + } +} + +void CHttpClientDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); +} + +BEGIN_MESSAGE_MAP(CHttpClientDlg, CDialog) + ON_WM_SYSCOMMAND() + ON_WM_PAINT() + ON_WM_QUERYDRAGICON() + //}}AFX_MSG_MAP + ON_BN_CLICKED(IDC_DOWNLOAD, OnBnClickedDownload) + ON_MESSAGE(WM_USER_DOWNLOAD_OVER, OnDownloadOk) +END_MESSAGE_MAP() + + +// CHttpClientDlg 消息处理程序 + +BOOL CHttpClientDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + // 将\“关于...\”菜单项添加到系统菜单中。 + + // IDM_ABOUTBOX 必须在系统命令范围内。 + ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); + ASSERT(IDM_ABOUTBOX < 0xF000); + + CMenu* pSysMenu = GetSystemMenu(FALSE); + if (pSysMenu != NULL) + { + CString strAboutMenu; + strAboutMenu.LoadString(IDS_ABOUTBOX); + if (!strAboutMenu.IsEmpty()) + { + pSysMenu->AppendMenu(MF_SEPARATOR); + pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); + } + } + + // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动 + // 执行此操作 + SetIcon(m_hIcon, TRUE); // 设置大图标 + SetIcon(m_hIcon, FALSE); // 设置小图标 + + // TODO: 在此添加额外的初始化代码 + + FILE *fp; + AllocConsole(); + fp = freopen("CONOUT$","w+t",stdout); + + service_ = NEW acl::http_service(2, 0, true); + // 使消息服务器监听 127.0.0.1 的地址 + //if (service_->open(&handle_) == false) + //{ + // printf(">>open message service error!\n"); + // delete service_; + // service_ = NULL; + //} + + return TRUE; // 除非设置了控件的焦点,否则返回 TRUE +} + +void CHttpClientDlg::OnSysCommand(UINT nID, LPARAM lParam) +{ + if ((nID & 0xFFF0) == IDM_ABOUTBOX) + { + CAboutDlg dlgAbout; + dlgAbout.DoModal(); + } + else + { + CDialog::OnSysCommand(nID, lParam); + } +} + +// 如果向对话框添加最小化按钮,则需要下面的代码 +// 来绘制该图标。对于使用文档/视图模型的 MFC 应用程序, +// 这将由框架自动完成。 + +void CHttpClientDlg::OnPaint() +{ + if (IsIconic()) + { + CPaintDC dc(this); // 用于绘制的设备上下文 + + SendMessage(WM_ICONERASEBKGND, reinterpret_cast(dc.GetSafeHdc()), 0); + + // 使图标在工作矩形中居中 + int cxIcon = GetSystemMetrics(SM_CXICON); + int cyIcon = GetSystemMetrics(SM_CYICON); + CRect rect; + GetClientRect(&rect); + int x = (rect.Width() - cxIcon + 1) / 2; + int y = (rect.Height() - cyIcon + 1) / 2; + + // 绘制图标 + dc.DrawIcon(x, y, m_hIcon); + } + else + { + CDialog::OnPaint(); + } +} + +//当用户拖动最小化窗口时系统调用此函数取得光标显示。 +HCURSOR CHttpClientDlg::OnQueryDragIcon() +{ + return static_cast(m_hIcon); +} + +void CHttpClientDlg::OnBnClickedDownload() +{ + // TODO: 在此添加控件通知处理程序代码 + + if (service_ == NULL) + { + printf("service_ null\r\n"); + return; + } + + // 创建 HTTP 请求过程 + acl::string domain; + domain = "www.banmau.com"; + //domain = "192.168.1.229"; + //domain = "www.renwou.net"; + CHttpDownload* req = NEW CHttpDownload(domain.c_str(), 80, &handle_); + req->SetHWnd(this->GetSafeHwnd()); + //req->set_url("/index.html"); + req->set_url("/download/banma_install.exe"); + req->set_host(domain); + req->set_keep_alive(false); + req->set_method(acl::HTTP_METHOD_GET); + req->add_cookie("x-cookie-name", "cookie-value"); + //req->set_redirect(1); // 设置自动重定向的次数限制 + + // 通知异步消息服务器处理该 HTTP 请求过程 + + ////////////////////////////////////////////////////////////////////////// + //acl::string buf; + //req->build_request(buf); + //printf("-----------------------------------------------\n"); + //printf("%s", buf.c_str()); + //printf("-----------------------------------------------\n"); + ////////////////////////////////////////////////////////////////////////// + + GetDlgItem(IDC_DOWNLOAD)->EnableWindow(FALSE); + service_->do_request(req); +} + +LRESULT CHttpClientDlg::OnDownloadOk(WPARAM wParam, LPARAM lParam) +{ + GetDlgItem(IDC_DOWNLOAD)->EnableWindow(TRUE); + return (0); +} \ No newline at end of file diff --git a/lib_acl_cpp/samples/HttpClient/HttpClientDlg.h b/lib_acl_cpp/samples/HttpClient/HttpClientDlg.h new file mode 100644 index 000000000..d565ae652 --- /dev/null +++ b/lib_acl_cpp/samples/HttpClient/HttpClientDlg.h @@ -0,0 +1,40 @@ +// HttpClientDlg.h : 头文件 +// + +#pragma once +#include "acl_cpp/stream/aio_handle.hpp" +#include "acl_cpp/http/http_service.hpp" + +// CHttpClientDlg 对话框 +class CHttpClientDlg : public CDialog +{ +// 构造 +public: + CHttpClientDlg(CWnd* pParent = NULL); // 标准构造函数 + ~CHttpClientDlg(); + +// 对话框数据 + enum { IDD = IDD_HTTPCLIENT_DIALOG }; + + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 + + +// 实现 +protected: + HICON m_hIcon; + + // 生成的消息映射函数 + virtual BOOL OnInitDialog(); + afx_msg void OnSysCommand(UINT nID, LPARAM lParam); + afx_msg void OnPaint(); + afx_msg HCURSOR OnQueryDragIcon(); + DECLARE_MESSAGE_MAP() +public: + afx_msg void OnBnClickedDownload(); + afx_msg LRESULT OnDownloadOk(WPARAM wParam, LPARAM lParam); + +private: + acl::aio_handle handle_; + acl::http_service* service_; +}; diff --git a/lib_acl_cpp/samples/HttpClient/HttpClient_vc2012.vcxproj b/lib_acl_cpp/samples/HttpClient/HttpClient_vc2012.vcxproj new file mode 100644 index 000000000..930f47870 --- /dev/null +++ b/lib_acl_cpp/samples/HttpClient/HttpClient_vc2012.vcxproj @@ -0,0 +1,266 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + Releasedll + Win32 + + + Release + Win32 + + + Template + Win32 + + + + {C0A7DB86-EF13-4A3E-9F34-8950521C9675} + MFCProj + HttpClient + + + + Application + Dynamic + MultiByte + v110 + + + Application + Dynamic + MultiByte + v110 + + + Application + Static + MultiByte + v110 + + + Application + Dynamic + MultiByte + v110 + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + Debug\ + Debug\ + true + true + Release\ + Release\ + Release\ + Release\ + false + false + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + + + + + + Disabled + ..\..\..\lib_protocol\include;..\..\..\lib_acl\include;..\..\include;%(AdditionalIncludeDirectories) + WIN32;_WINDOWS;_DEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + true + Use + Level3 + EditAndContinue + + + lib_acl_d.lib;lib_protocol_d.lib;lib_acl_cpp_d.lib;%(AdditionalDependencies) + ..\..\..\lib\win32;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + %(IgnoreSpecificDefaultLibraries) + true + Windows + MachineX86 + + + _DEBUG;%(PreprocessorDefinitions) + false + + + _DEBUG;%(PreprocessorDefinitions) + 0x0804 + $(IntDir);%(AdditionalIncludeDirectories) + + + + + Disabled + ..\..\..\lib_protocol\include;..\..\..\lib_acl\include;..\..\include;%(AdditionalIncludeDirectories) + WIN32;_WINDOWS;_DEBUG;ACL_CPP_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + true + Use + Level3 + EditAndContinue + + + lib_acl_d.lib;lib_protocol_d.lib;lib_acl_cpp_d.lib;%(AdditionalDependencies) + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + libcmtd;%(IgnoreSpecificDefaultLibraries) + true + Windows + MachineX86 + + + _DEBUG;%(PreprocessorDefinitions) + false + + + _DEBUG;%(PreprocessorDefinitions) + 0x0804 + $(IntDir);%(AdditionalIncludeDirectories) + + + + + WIN32;_WINDOWS;NDEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + false + MultiThreadedDLL + true + Use + Level3 + ProgramDatabase + ..\..\..\lib_protocol\include;..\..\..\lib_acl\include;..\..\include;%(AdditionalIncludeDirectories) + + + true + Windows + true + true + MachineX86 + ..\..\lib;..\..\..\dist\lib\win32 + lib_acl.lib;lib_protocol.lib;lib_acl_cpp.lib;%(AdditionalDependencies) + libcmt + + + NDEBUG;%(PreprocessorDefinitions) + false + + + NDEBUG;%(PreprocessorDefinitions) + 0x0804 + $(IntDir);%(AdditionalIncludeDirectories) + + + + + WIN32;_WINDOWS;NDEBUG;ACL_CPP_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + false + MultiThreadedDLL + true + Use + Level3 + ProgramDatabase + ..\..\..\lib_protocol\include;..\..\..\lib_acl\include;..\..\include;%(AdditionalIncludeDirectories) + + + true + Windows + true + true + MachineX86 + ..\..\lib;..\..\..\dist\lib\win32 + lib_acl.lib;lib_protocol.lib;lib_acl_cpp.lib;%(AdditionalDependencies) + libcmt + + + NDEBUG;%(PreprocessorDefinitions) + false + + + NDEBUG;%(PreprocessorDefinitions) + 0x0804 + $(IntDir);%(AdditionalIncludeDirectories) + + + copy ..\..\..\dist\lib\win32\lib_acl.dll $(OutDir)\ /Y +copy ..\..\..\dist\lib\win32\lib_acl_cpp.dll $(OutDir)\ /Y + + + + + + + + Create + Create + Create + Create + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib_acl_cpp/samples/HttpClient/HttpDownload.cpp b/lib_acl_cpp/samples/HttpClient/HttpDownload.cpp new file mode 100644 index 000000000..9020128b6 --- /dev/null +++ b/lib_acl_cpp/samples/HttpClient/HttpDownload.cpp @@ -0,0 +1,98 @@ +#include "StdAfx.h" +#include "acl_cpp/stream/aio_handle.hpp" +#include "acl_cpp/stdlib/string.hpp" + +#include ".\httpdownload.h" + +CHttpDownload::CHttpDownload(const char* domain, unsigned short port, + acl::aio_handle* handle) +: acl::http_service_request(domain, port) +, handle_(handle) +{ + read_length_ = 0; +#ifdef WIN32 + hWnd_ = 0; +#endif +} + +CHttpDownload::~CHttpDownload(void) +{ +#ifdef WIN32 + acl::aio_handle_type handle_type = handle_->get_engine_type(); + if (handle_type == acl::ENGINE_WINMSG) + { + ASSERT(hWnd_); + ::PostMessage(hWnd_, WM_USER_DOWNLOAD_OVER, 0, 0); + } + else + handle_->stop(); +#else + // 通知异步事件引擎完全退出 + handle_->stop(); +#endif +} + +void CHttpDownload::destroy() +{ + delete this; +} + +#ifdef WIN32 +void CHttpDownload::SetHWnd(HWND hWnd) +{ + hWnd_ = hWnd; +} +#endif + +const acl::string* CHttpDownload::get_body() +{ + return (NULL); +} + +void CHttpDownload::on_hdr(const char* addr, const HTTP_HDR_RES* hdr) +{ + printf(">>server addr: %s, http reply status: %d\n", + addr, hdr->reply_status); + http_hdr_print(&hdr->hdr, "http reply hdr"); + content_length_ = hdr->hdr.content_length; + if (content_length_ > 0) + { + if (out_.open_write("test.exe") == false) + printf("create file error(%s)\n", + acl_last_serror()); + } + time(&begin_); +} + +void CHttpDownload::on_body(const char* data, size_t dlen) +{ + if (data == NULL && dlen == 0) + { +#ifdef WIN32 + printf("\n>> http reply body over, total: %I64d, %I64d\n", + content_length_, read_length_); +#else + printf("\n>> http reply body over, total: %lld, %lld\n", + content_length_, read_length_); +#endif + // 出错后,因为本类对象是动态分配的,所以需要在此处释放 + time_t end = time(NULL); + printf(">>spent %d seconds\n", (int)(end - begin_)); + return; + } + read_length_ += dlen; + http_off_t n = (read_length_ * 100) / content_length_; +#ifdef WIN32 + printf("%I64d%%\r", n); +#else + printf("%lld%%\r", n); +#endif + + if (out_.opened()) + out_.write(data, dlen); +} + +void CHttpDownload::on_error(acl::http_status_t errnum) +{ + printf(">> error: %d\n", (int) errnum); +} \ No newline at end of file diff --git a/lib_acl_cpp/samples/HttpClient/HttpDownload.h b/lib_acl_cpp/samples/HttpClient/HttpDownload.h new file mode 100644 index 000000000..5807beb43 --- /dev/null +++ b/lib_acl_cpp/samples/HttpClient/HttpDownload.h @@ -0,0 +1,47 @@ +#pragma once +#include "lib_acl.h" +#include "lib_protocol.h" // http 协议相关 +#include "acl_cpp/stream/ofstream.hpp" +#include "acl_cpp/http/http_service.hpp" + +class acl::string; +class acl::aio_handle; + +class CHttpDownload : public acl::http_service_request +{ +public: + CHttpDownload(const char* domain, unsigned short port, + acl::aio_handle* handle); + +#ifdef WIN32 + void SetHWnd(HWND hWnd); +#endif + + // 基类虚接口:销毁过程,由 http_service 类处理完毕后自动调用该回调 + virtual void destroy(); + +protected: + ~CHttpDownload(void); + + ////////////////////////////////////////////////////////////////////////// + // 基类虚接口 + + // 获得HTTP请求的数据体时的回调接口,注意该函数的调用空间与其它函数不在同 + // 一个线程空间,所以如果该函数访问与其它函数相同的资源时需要注意互斥 + virtual const acl::string* get_body(); + // 正常读到 HTTP 响应头时的回调接口 + virtual void on_hdr(const char* addr, const HTTP_HDR_RES* hdr); + // 正常读 HTTP 响应体时的回调函数 + virtual void on_body(const char* data, size_t dlen); + // 当请求或响应失败时的回调函数 + virtual void on_error(acl::http_status_t errnum); +private: + acl::ofstream out_; + acl::aio_handle* handle_; +#ifdef WIN32 + HWND hWnd_; +#endif + http_off_t read_length_; + http_off_t content_length_; + time_t begin_; +}; diff --git a/lib_acl_cpp/samples/HttpClient/ReadMe.txt b/lib_acl_cpp/samples/HttpClient/ReadMe.txt new file mode 100644 index 000000000..14705bc48 --- /dev/null +++ b/lib_acl_cpp/samples/HttpClient/ReadMe.txt @@ -0,0 +1,85 @@ +================================================================================ + MICROSOFT 基础类库: HttpClient 项目概述 +=============================================================================== + +应用程序向导已为您创建了此 HttpClient 应用程序。此应用程序 +不仅介绍了使用 Microsoft 基础类的基本知识, +而且是编写应用程序的起点。 + +此文件包含组成 HttpClient 应用程序的每个文件的内容摘要。 + +HttpClient.vcproj + 这是使用“应用程序向导”生成的 VC++ 项目的主项目文件。 + 它包含有关生成文件的 Visual C++ 版本的信息,以及 + 有关用“应用程序向导”所选择的平台、配置和 + 项目功能的信息。 + +HttpClient.h + 这是应用程序的主头文件。 它包含其他 + 项目特定的头文件(包括 Resource.h),并声明 + CHttpClientApp 应用程序类。 + +HttpClient.cpp + 这是包含应用程序 + 类 CHttpClientApp 的主应用程序源文件。 + +HttpClient.rc + 这是程序使用的所有 Microsoft Windows 资源 + 的列表。 它包含存储在 RES 子目录中 + 的图标、位图和光标。 可直接在 Microsoft + Visual C++ 中编辑此文件。 项目资源包含在 2052 中。 + +res\HttpClient.ico + 这是一个图标文件,用作应用程序的图标。 此 + 图标包含在主资源文件 HttpClient.rc 中。 + +res\HttpClient.rc2 + 此文件包含不由 Microsoft + Visual C++ 编辑的资源。 应将所有不能由 + 资源编辑器编辑的资源放在此文件中。 + +///////////////////////////////////////////////////////////////////////////// + +应用程序向导将创建一个对话框类: +HttpClientDlg.h、HttpClientDlg.cpp - 对话框 + 这些文件包含 CHttpClientDlg 类。 此类定义 + 应用程序主对话框的行为。 此对话框的模板包含在 + HttpClient.rc 中,而此文件可以在 Microsoft Visual C++ 中进行编辑。 +///////////////////////////////////////////////////////////////////////////// + +其他功能: + +ActiveX 控件 + 应用程序支持使用 ActiveX 控件。 + +Windows 套接字 + 应用程序支持在 TCP/IP 网络上建立通讯。 +///////////////////////////////////////////////////////////////////////////// + +其他标准文件: + +StdAfx.h、StdAfx.cpp + 这些文件用于生成名为 HttpClient.pch 的预编译头文件 (PCH) + 和名为 StdAfx.obj 的预编译类型文件。 + +Resource.h + 这是标准头文件,它定义新资源 ID。 + Microsoft Visual C++ 将读取并更新此文件。 + +///////////////////////////////////////////////////////////////////////////// + +其他说明: + +应用程序向导使用“TODO:” 来指示 +应添加或自定义的源代码部分。 + +如果应用程序在共享 DLL 中使用 MFC,且应用程序使用的语言不是 +操作系统的当前语言,则需要从 Microsoft Visual C++ 光盘上 +Win\System 目录下将相应的本地化资源 MFC70XXX.DLL +复制到计算机的 system 或 system32 目录下, +并将其重命名为 MFCLOC.DLL。 (“XXX”代表 +语言缩写。 例如,MFC70DEU.DLL 包含翻译成 +德语的资源。) 如果不这样做,应用程序的某些 UI 元素 +将保留为操作系统的语言。 + +///////////////////////////////////////////////////////////////////////////// diff --git a/lib_acl_cpp/samples/HttpClient/res/HttpClient.ico b/lib_acl_cpp/samples/HttpClient/res/HttpClient.ico new file mode 100644 index 000000000..8a84ca3d3 Binary files /dev/null and b/lib_acl_cpp/samples/HttpClient/res/HttpClient.ico differ diff --git a/lib_acl_cpp/samples/HttpClient/res/HttpClient.manifest b/lib_acl_cpp/samples/HttpClient/res/HttpClient.manifest new file mode 100644 index 000000000..903cb1835 --- /dev/null +++ b/lib_acl_cpp/samples/HttpClient/res/HttpClient.manifest @@ -0,0 +1,22 @@ + + + +鍦ㄦ璇存槑搴旂敤绋嬪簭 + + + + + + diff --git a/lib_acl_cpp/samples/HttpClient/res/HttpClient.rc2 b/lib_acl_cpp/samples/HttpClient/res/HttpClient.rc2 new file mode 100644 index 000000000..ff7d9ded1 --- /dev/null +++ b/lib_acl_cpp/samples/HttpClient/res/HttpClient.rc2 @@ -0,0 +1,13 @@ +// +// HttpClient.RC2 - Microsoft Visual C++ 不会直接编辑的资源 +// + +#ifdef APSTUDIO_INVOKED +#error 此文件不能由 Microsoft Visual C++ 编辑 +#endif //APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// 在此处添加手动编辑的资源... + +///////////////////////////////////////////////////////////////////////////// diff --git a/lib_acl_cpp/samples/HttpClient/resource.h b/lib_acl_cpp/samples/HttpClient/resource.h new file mode 100644 index 000000000..94be9c21b --- /dev/null +++ b/lib_acl_cpp/samples/HttpClient/resource.h @@ -0,0 +1,23 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by HttpClient.rc +// +#define IDM_ABOUTBOX 0x0010 +#define IDD_ABOUTBOX 100 +#define IDS_ABOUTBOX 101 +#define IDD_HTTPCLIENT_DIALOG 102 +#define IDP_SOCKETS_INIT_FAILED 103 +#define IDR_MAINFRAME 128 +#define IDC_BUTTON1 1000 +#define IDC_DOWNLOAD 1000 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 129 +#define _APS_NEXT_COMMAND_VALUE 32771 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/lib_acl_cpp/samples/HttpClient/stdafx.cpp b/lib_acl_cpp/samples/HttpClient/stdafx.cpp new file mode 100644 index 000000000..526bc2992 --- /dev/null +++ b/lib_acl_cpp/samples/HttpClient/stdafx.cpp @@ -0,0 +1,7 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// HttpClient.pch 将是预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + + diff --git a/lib_acl_cpp/samples/HttpClient/stdafx.h b/lib_acl_cpp/samples/HttpClient/stdafx.h new file mode 100644 index 000000000..f729de208 --- /dev/null +++ b/lib_acl_cpp/samples/HttpClient/stdafx.h @@ -0,0 +1,128 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是经常使用但不常更改的 +// 项目特定的包含文件 + +#pragma once + +#ifdef VC2003 + +#ifndef VC_EXTRALEAN +#define VC_EXTRALEAN // 从 Windows 标头中排除不常使用的资料 +#endif + +// 如果您必须使用下列所指定的平台之前的平台,则修改下面的定义。 +// 有关不同平台的相应值的最新信息,请参考 MSDN。 +#ifndef WINVER // 允许使用 Windows 95 和 Windows NT 4 或更高版本的特定功能。 +#define WINVER 0x0400 //为 Windows98 和 Windows 2000 及更新版本改变为适当的值。 +#endif + +#ifndef _WIN32_WINNT // 允许使用 Windows NT 4 或更高版本的特定功能。 +#define _WIN32_WINNT 0x0400 //为 Windows98 和 Windows 2000 及更新版本改变为适当的值。 +#endif + +#ifndef _WIN32_WINDOWS // 允许使用 Windows 98 或更高版本的特定功能。 +#define _WIN32_WINDOWS 0x0410 //为 Windows Me 及更新版本改变为适当的值。 +#endif + +#ifndef _WIN32_IE // 允许使用 IE 4.0 或更高版本的特定功能。 +#define _WIN32_IE 0x0400 //为 IE 5.0 及更新版本改变为适当的值。 +#endif + +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // 某些 CString 构造函数将是显式的 + +// 关闭 MFC 对某些常见但经常被安全忽略的警告消息的隐藏 +#define _AFX_ALL_WARNINGS + +#include // MFC 核心和标准组件 +#include // MFC 扩展 +#include // MFC 自动化类 + +#include // Internet Explorer 4 公共控件的 MFC 支持 +#ifndef _AFX_NO_AFXCMN_SUPPORT +#include // Windows 公共控件的 MFC 支持 +#endif // _AFX_NO_AFXCMN_SUPPORT + +#include // MFC 套接字扩展 + +////////////////////////////////////////////////////////////////////////////////////// +#else +// stdafx.h : 标准系统包含文件的包含文件, +// 或是经常使用但不常更改的 +// 特定于项目的包含文件 + +#pragma once + +#ifndef _SECURE_ATL +#define _SECURE_ATL 1 +#endif + +#ifndef VC_EXTRALEAN +#define VC_EXTRALEAN // 从 Windows 头中排除极少使用的资料 +#endif + +// 包括 SDKDDKVer.h 将定义最高版本的可用 Windows 平台。 + +// 如果要为以前的 Windows 平台生成应用程序,请包括 WinSDKVer.h,并将 +// WIN32_WINNT 宏设置为要支持的平台,然后再包括 SDKDDKVer.h。 + +#include + +//#ifndef _CRTDBG_MAP_ALLOC +//#define _CRTDBG_MAP_ALLOC +//#include +//#include +//#endif + +//#ifdef _DEBUG +//#define NEW new(_NORMAL_BLOCK, __FILE__, __LINE__) +//// Replace _NORMAL_BLOCK with _CLIENT_BLOCK if you want the +////allocations to be of _CLIENT_BLOCK type +//#else +//#define NEW new +//#endif // _DEBUG + +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // 某些 CString 构造函数将是显式的 + +// 关闭 MFC 对某些常见但经常可放心忽略的警告消息的隐藏 +#define _AFX_ALL_WARNINGS + +#include // MFC 核心组件和标准组件 +#include // MFC 扩展 + + +#include // MFC 自动化类 + + +#ifndef _AFX_NO_OLE_SUPPORT +#include // MFC 对 Internet Explorer 4 公共控件的支持 +#endif +#ifndef _AFX_NO_AFXCMN_SUPPORT +#include // MFC 对 Windows 公共控件的支持 +#endif // _AFX_NO_AFXCMN_SUPPORT + +#include // 功能区和控件条的 MFC 支持 +#include + +#include +//#ifndef _CRTDBG_MAP_ALLOC +//# define _CRTDBG_MAP_ALLOC +//# include +//# include +//#endif + +#endif // VC2003 + +//自定义消息值 + +#define WM_USER_DOWNLOAD_OVER WM_USER + 100 + +#ifdef _DEBUG +# ifndef _CRTDBG_MAP_ALLOC +# define _CRTDBG_MAP_ALLOC +# include +# include +# endif +# define NEW new(_NORMAL_BLOCK, __FILE__, __LINE__) +# else +# define NEW new +#endif // _DEBUG diff --git a/lib_acl_cpp/samples/Makefile b/lib_acl_cpp/samples/Makefile new file mode 100644 index 000000000..a10188c60 --- /dev/null +++ b/lib_acl_cpp/samples/Makefile @@ -0,0 +1,97 @@ +all: + @(cd string; make) + @(cd fstream; make) + @(cd xml; make) + @(cd json; make) + @(cd mime; make) + @(cd socket_stream; make) + @(cd mime_base64; make) + @(cd mime_xxcode; make) + @(cd mime_qp; make) + @(cd charset; make) + @(cd rfc2047; make) + @(cd rfc822; make) +# @(cd hsclient; make) + @(cd mem_cache; make) + @(cd logger; make) +# @(cd pipe_stream; make) + @(cd aio_server; make) + @(cd aio_client; make) + @(cd aio_ipc; make) + @(cd aio_dns; make) + @(cd socket_client; make) + @(cd http_client; make) +# @(cd http_client2; make) + @(cd final_class; make) + @(cd zlib; make) + @(cd http_servlet; make) + @(cd cgi; make) + @(cd cgi_upload; make) + @(cd http_mime; make) + @(cd http_test; make) + @(cd session; make) + @(cd http_response; make) + @(cd rpc_download; make) + @(cd md5; make) + @(cd http_server; make) + @(cd beanstalk; make) + @(cd master_http_rpc; make) + @(cd master_http_aio; make) + @(cd master_http_threads; make) + @(cd master_trigger; make) + @(cd master_aio; make) + @(cd master_proc; make) + @(cd master_threads; make) + @(cd benchmark; make) + @(cd fs_benchmark; make) + @(cd http_request_pool; make) + @(cd memcache_pool; make) + +clean: + @(cd string; make clean) + @(cd fstream; make clean) + @(cd xml; make clean) + @(cd json; make clean) + @(cd mime; make clean) + @(cd socket_stream; make clean) + @(cd mime_base64; make clean) + @(cd mime_xxcode; make clean) + @(cd mime_qp; make clean) + @(cd charset; make clean) + @(cd rfc2047; make clean) + @(cd rfc822; make clean) +# @(cd hsclient; make clean) + @(cd mem_cache; make clean) + @(cd logger; make clean) +# @(cd pipe_stream; make clean) + @(cd aio_server; make clean) + @(cd aio_client; make clean) + @(cd aio_ipc; make clean) + @(cd aio_dns; make clean) + @(cd socket_client; make clean) + @(cd http_client; make clean) + @(cd http_client2; make clean) + @(cd final_class; make clean) + @(cd zlib; make clean) + @(cd http_servlet; make clean) + @(cd cgi; make clean) + @(cd cgi_upload; make clean) + @(cd http_mime; make clean) + @(cd http_test; make clean) + @(cd session; make clean) + @(cd http_response; make clean) + @(cd rpc_download; make clean) + @(cd md5; make clean) + @(cd http_server; make clean) + @(cd beanstalk; make clean) + @(cd master_http_rpc; make clean) + @(cd master_http_aio; make clean) + @(cd master_http_threads; make clean) + @(cd master_trigger; make clean) + @(cd master_aio; make clean) + @(cd master_proc; make clean) + @(cd master_threads; make clean) + @(cd benchmark; make clean) + @(cd fs_benchmark; make clean) + @(cd http_request_pool; make clean) + @(cd memcache_pool; make clean) diff --git a/lib_acl_cpp/samples/Makefile.in b/lib_acl_cpp/samples/Makefile.in new file mode 100644 index 000000000..3edc79c5f --- /dev/null +++ b/lib_acl_cpp/samples/Makefile.in @@ -0,0 +1,96 @@ +CC = g++ + +CFLAGS = -c -g -W -Wall -Wcast-qual -Wcast-align \ +-Wno-long-long \ +-Wpointer-arith -Werror -Wshadow -O3 \ +-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO + +#-Waggregate-return +########################################################### +#Check system: +# Linux, SunOS, Solaris, BSD variants, AIX, HP-UX +SYSLIB = -lpthread -lcrypt +CHECKSYSRES = @echo "Unknow system type!";exit 1 +UNIXNAME = $(shell uname -sm) + +ifeq ($(CC),) + CC = gcc +endif + +# For FreeBSD +ifeq ($(findstring FreeBSD, $(UNIXNAME)), FreeBSD) + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DFREEBSD -D_REENTRANT + SYSLIB = -lcrypt -lpthread +endif + +#Path for Linux +ifeq ($(findstring Linux, $(UNIXNAME)), Linux) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DLINUX2 -D_REENTRANT +endif + +#Path for SunOS +ifeq ($(findstring SunOS, $(UNIXNAME)), SunOS) + ifeq ($(findstring 86, $(UNIXNAME)), 86) + SYSLIB += -lsocket -lnsl -lrt + endif + ifeq ($(findstring sun4u, $(UNIXNAME)), sun4u) + SYSLIB += -lsocket -lnsl -lrt + endif + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DSUNOS5 -D_REENTRANT +endif + +#Path for HP-UX +ifeq ($(findstring HP-UX, $(UNIXNAME)), HP-UX) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DHP_UX -DHPUX11 + PLAT_NAME=hp-ux +endif + +#Find system type. +ifneq ($(SYSPATH),) + CHECKSYSRES = @echo "System is $(shell uname -sm)" +endif +########################################################### + +CFLAGS += -I. -I../../include -I../../../lib_acl/include -I../../../lib_protocol/include +EXTLIBS = +LDFLAGS = -L../../lib -l_acl_cpp -L../../../lib_protocol/lib -l_protocol -L../../../lib_acl/lib -l_acl \ + $(EXTLIBS) $(SYSLIB) + +COMPILE = $(CC) $(CFLAGS) +LINK = $(CC) $(OBJ) $(LDFLAGS) +########################################################### +OBJ_PATH = . + +#Project's objs +SRC = $(wildcard *.cpp) $(UTIL) +OBJ = $(patsubst %.cpp, $(OBJ_PATH)/%.o, $(notdir $(SRC))) + +$(OBJ_PATH)/%.o: %.cpp + $(COMPILE) $< -o $@ +$(OBJ_PATH)/%.o: ../%.cpp + $(COMPILE) $< -o $@ + +.PHONY = all clean +all: RM $(OBJ) + $(LINK) -o $(PROG) + @echo "" + @echo "All ok! Output:$(PROG)" + @echo "" +RM: + rm -f $(PROG) +clean: + rm -f $(PROG) + rm -f $(OBJ) +########################################################### diff --git a/lib_acl_cpp/samples/acl_cpp_test/ReadMe.txt b/lib_acl_cpp/samples/acl_cpp_test/ReadMe.txt new file mode 100644 index 000000000..258535460 --- /dev/null +++ b/lib_acl_cpp/samples/acl_cpp_test/ReadMe.txt @@ -0,0 +1,31 @@ +======================================================================== + 控制台应用程序 : acl_cpp_test 项目概况 +======================================================================== + +应用程序向导已为您创建了这个 acl_cpp_test 应用程序。 +此文件包含组成 acl_cpp_test 应用程序 +的每个文件的内容摘要。 + + +acl_cpp_test.vcproj + 这是用应用程序向导生成的 VC++ 项目的主项目文件。 + 它包含有关生成此文件的 Visual C++ 版本的信息,以及 + 有关用应用程序向导选择的 + 平台、配置和项目功能的信息。 + +acl_cpp_test.cpp + 这是主应用程序源文件。 + +///////////////////////////////////////////////////////////////////////////// +其他标准文件: + +StdAfx.h、StdAfx.cpp + 这些文件用于生成名为 acl_cpp_test.pch + 的预编译头(PCH)文件以及名为 StdAfx.obj 的预编译类型文件。 + +///////////////////////////////////////////////////////////////////////////// +其他注释: + +应用程序向导使用 "TODO:" 注释指示应添加或自定义的源代码部分。 + +///////////////////////////////////////////////////////////////////////////// diff --git a/lib_acl_cpp/samples/acl_cpp_test/acl_cpp_test.cpp b/lib_acl_cpp/samples/acl_cpp_test/acl_cpp_test.cpp new file mode 100644 index 000000000..2f2969d41 --- /dev/null +++ b/lib_acl_cpp/samples/acl_cpp_test/acl_cpp_test.cpp @@ -0,0 +1,52 @@ +// acl_cpp_test.cpp : 定义控制台应用程序的入口点。 +// + +#include "stdafx.h" +#include "acl_cpp/acl_cpp_test.hpp" +#include "acl_cpp/stdlib/noncopyable.hpp" + +using namespace acl; + +class A : private noncopyable +{ +public: + A() {} + virtual ~A() {} +protected: +private: +}; + +class B : public A +{ +public: + B() {} + virtual ~B() {} +protected: +private: +}; + +class C : public B +{ +public: + C() {} + ~C() {} +protected: +private: +}; + +int main(int argc, char* argv[]) +{ + test_snprintf(); +#ifdef WIN32 + getchar(); +#endif + + //A a1, a2; + //a2 = a1; + //B b1, b2(b1); + //b2 = b2; + //C c1, c2; + //c2 = c1; + + return 0; +} diff --git a/lib_acl_cpp/samples/acl_cpp_test/acl_cpp_test.vcproj b/lib_acl_cpp/samples/acl_cpp_test/acl_cpp_test.vcproj new file mode 100644 index 000000000..9ae5e254f --- /dev/null +++ b/lib_acl_cpp/samples/acl_cpp_test/acl_cpp_test.vcproj @@ -0,0 +1,269 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_acl_cpp/samples/acl_cpp_test/stdafx.cpp b/lib_acl_cpp/samples/acl_cpp_test/stdafx.cpp new file mode 100644 index 000000000..fd04320da --- /dev/null +++ b/lib_acl_cpp/samples/acl_cpp_test/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// acl_cpp_test.pch 将成为预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + +// TODO: 在 STDAFX.H 中 +//引用任何所需的附加头文件,而不是在此文件中引用 diff --git a/lib_acl_cpp/samples/acl_cpp_test/stdafx.h b/lib_acl_cpp/samples/acl_cpp_test/stdafx.h new file mode 100644 index 000000000..ff452917c --- /dev/null +++ b/lib_acl_cpp/samples/acl_cpp_test/stdafx.h @@ -0,0 +1,11 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是常用但不常更改的项目特定的包含文件 +// + +#pragma once + + +#include +#include + +// TODO: 在此处引用程序要求的附加头文件 diff --git a/lib_acl_cpp/samples/aio_client/Makefile b/lib_acl_cpp/samples/aio_client/Makefile new file mode 100644 index 000000000..5be50623a --- /dev/null +++ b/lib_acl_cpp/samples/aio_client/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = aio_client diff --git a/lib_acl_cpp/samples/aio_client/aio_client.vcproj b/lib_acl_cpp/samples/aio_client/aio_client.vcproj new file mode 100644 index 000000000..1462ea994 --- /dev/null +++ b/lib_acl_cpp/samples/aio_client/aio_client.vcproj @@ -0,0 +1,241 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_acl_cpp/samples/aio_client/aio_client.vcxproj b/lib_acl_cpp/samples/aio_client/aio_client.vcxproj new file mode 100644 index 000000000..fdc6f7750 --- /dev/null +++ b/lib_acl_cpp/samples/aio_client/aio_client.vcxproj @@ -0,0 +1,190 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + Releasedll + Win32 + + + Release + Win32 + + + + {9A04F86E-D4CB-45ED-9BB6-9939B9400B6F} + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + true + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;lib_acl_vc2010d.lib;lib_acl_cpp_vc2010d.lib;%(AdditionalDependencies) + $(OutDir)aio_client.exe + ..\..\..\lib\win32;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)aio_client.pdb + Console + MachineX86 + + + + + + + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;lib_acl_vc2010.lib;lib_acl_cpp_vc2010.lib;%(AdditionalDependencies) + $(OutDir)aio_client.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + + + + + + + Disabled + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;lib_acl_d.lib;lib_acl_cpp_d.lib;%(AdditionalDependencies) + $(OutDir)aio_client.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)aio_client.pdb + Console + MachineX86 + + + + + Disabled + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;lib_acl.lib;lib_acl_cpp.lib;%(AdditionalDependencies) + $(OutDir)aio_client.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + libcmt;%(IgnoreSpecificDefaultLibraries) + true + $(OutDir)aio_client.pdb + Console + MachineX86 + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib_acl_cpp/samples/aio_client/aio_client_vc2012.vcxproj b/lib_acl_cpp/samples/aio_client/aio_client_vc2012.vcxproj new file mode 100644 index 000000000..301636c33 --- /dev/null +++ b/lib_acl_cpp/samples/aio_client/aio_client_vc2012.vcxproj @@ -0,0 +1,195 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + Releasedll + Win32 + + + Release + Win32 + + + + {9A04F86E-D4CB-45ED-9BB6-9939B9400B6F} + Win32Proj + aio_client + + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + true + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + $(OutDir)aio_client.exe + ..\..\..\lib\win32;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)aio_client.pdb + Console + MachineX86 + + + lib_acl_vc2012d.lib;lib_acl_cpp_vc2012d.lib;%(AdditionalDependencies) + + + + + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;lib_acl_vc2012.lib;lib_acl_cpp_vc2012.lib;%(AdditionalDependencies) + $(OutDir)aio_client.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + + + + + + + Disabled + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;lib_acl_d.lib;lib_acl_cpp_d.lib;%(AdditionalDependencies) + $(OutDir)aio_client.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)aio_client.pdb + Console + MachineX86 + + + + + Disabled + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;lib_acl.lib;lib_acl_cpp.lib;%(AdditionalDependencies) + $(OutDir)aio_client.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + libcmt;%(IgnoreSpecificDefaultLibraries) + true + $(OutDir)aio_client.pdb + Console + MachineX86 + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib_acl_cpp/samples/aio_client/main.cpp b/lib_acl_cpp/samples/aio_client/main.cpp new file mode 100644 index 000000000..26e701f2b --- /dev/null +++ b/lib_acl_cpp/samples/aio_client/main.cpp @@ -0,0 +1,334 @@ +#include +#include +#include "lib_acl.h" +#include "acl_cpp/acl_cpp_init.hpp" +#include "acl_cpp/stdlib/string.hpp" +#include "acl_cpp/stdlib/util.hpp" +#include "acl_cpp/stream/aio_handle.hpp" +#include "acl_cpp/stream/aio_socket_stream.hpp" + +#ifdef WIN32 +# ifndef snprintf +# define snprintf _snprintf +# endif +#endif + +using namespace acl; + +typedef struct +{ + char addr[64]; + aio_handle* handle; + int connect_timeout; + int read_timeout; + int nopen_limit; + int nopen_total; + int nwrite_limit; + int nwrite_total; + int nread_total; + int id_begin; + bool debug; +} IO_CTX; + +static bool connect_server(IO_CTX* ctx, int id); + +/** + * 客户端异步连接流回调函数类 + */ +class client_io_callback : public aio_open_callback +{ +public: + /** + * 构造函数 + * @param ctx {IO_CTX*} + * @param client {aio_socket_stream*} 异步连接流 + * @param id {int} 本流的ID号 + */ + client_io_callback(IO_CTX* ctx, aio_socket_stream* client, int id) + : client_(client) + , ctx_(ctx) + , nwrite_(0) + , id_(id) + { + } + + ~client_io_callback() + { + std::cout << ">>>ID: " << id_ << ", io_callback deleted now!" << std::endl; + } + + /** + * 基类虚函数, 当异步流读到所要求的数据时调用此回调函数 + * @param data {char*} 读到的数据地址 + * @param len {int} 读到的数据长度 + * @return {bool} 返回给调用者 true 表示继续,否则表示需要关闭异步流 + */ + bool read_callback(char* data, int len) + { + (void) data; + (void) len; + + ctx_->nread_total++; + + if (ctx_->debug) + { + if (nwrite_ < 10) + std::cout << "gets(" << nwrite_ << "): " << data; + else if (nwrite_ % 2000 == 0) + std::cout << ">>ID: " << id_ << ", I: " + << nwrite_ << "; "<< data; + } + + // 如果收到服务器的退出消息,则也应退出 + if (acl::strncasecmp_(data, "quit", 4) == 0) + { + // 向服务器发送数据 + client_->format("Bye!\r\n"); + // 关闭异步流连接 + client_->close(); + return (true); + } + + if (nwrite_ >= ctx_->nwrite_limit) + { + if (ctx_->debug) + std::cout << "ID: " << id_ + << ", nwrite: " << nwrite_ + << ", nwrite_limit: " << ctx_->nwrite_limit + << ", quiting ..." << std::endl; + + // 向服务器发送退出消息 + client_->format("quit\r\n"); + client_->close(); + } + else + { + char buf[256]; + snprintf(buf, sizeof(buf), "hello world: %d\n", nwrite_); + client_->write(buf, (int) strlen(buf)); + + // 向服务器发送数据 + //client_->format("hello world: %d\n", nwrite_); + } + + return (true); + } + + /** + * 基类虚函数, 当异步流写成功时调用此回调函数 + * @return {bool} 返回给调用者 true 表示继续,否则表示需要关闭异步流 + */ + bool write_callback() + { + ctx_->nwrite_total++; + nwrite_++; + + // 从服务器读一行数据 + client_->gets(ctx_->read_timeout, false); + return (true); + } + + /** + * 基类虚函数, 当该异步流关闭时调用此回调函数 + */ + void close_callback() + { + if (client_->is_opened() == false) + { + std::cout << "Id: " << id_ << " connect " + << ctx_->addr << " error: " + << acl::last_serror(); + + // 如果是第一次连接就失败,则退出 + if (ctx_->nopen_total == 0) + { + std::cout << ", first connect error, quit"; + /* 获得异步引擎句柄,并设置为退出状态 */ + client_->get_handle().stop(); + } + std::cout << std::endl; + delete this; + return; + } + + /* 获得异步引擎中受监控的异步流个数 */ + int nleft = client_->get_handle().length(); + if (ctx_->nopen_total == ctx_->nopen_limit && nleft == 1) + { + std::cout << "Id: " << id_ << " stop now! nstream: " + << nleft << std::endl; + /* 获得异步引擎句柄,并设置为退出状态 */ + client_->get_handle().stop(); + } + + // 必须在此处删除该动态分配的回调类对象以防止内存泄露 + delete this; + } + + /** + * 基类虚函数,当异步流超时时调用此函数 + * @return {bool} 返回给调用者 true 表示继续,否则表示需要关闭异步流 + */ + bool timeout_callback() + { + std::cout << "Connect " << ctx_->addr << " Timeout ..." << std::endl; + client_->close(); + return (false); + } + + /** + * 基类虚函数, 当异步连接成功后调用此函数 + * @return {bool} 返回给调用者 true 表示继续,否则表示需要关闭异步流 + */ + bool open_callback() + { + // 连接成功,设置IO读写回调函数 + client_->add_read_callback(this); + client_->add_write_callback(this); + ctx_->nopen_total++; + + acl::assert_(id_ > 0); + if (ctx_->nopen_total < ctx_->nopen_limit) + { + // 开始进行下一个连接过程 + if (connect_server(ctx_, id_ + 1) == false) + std::cout << "connect error!" << std::endl; + } + + // 异步向服务器发送数据 + //client_->format("hello world: %d\n", nwrite_); + char buf[256]; + snprintf(buf, sizeof(buf), "hello world: %d\n", nwrite_); + client_->write(buf, (int) strlen(buf)); + + // 异步从服务器读取一行数据 + client_->gets(ctx_->read_timeout, false); + + // 表示继续异步过程 + return (true); + } + +protected: +private: + aio_socket_stream* client_; + IO_CTX* ctx_; + int nwrite_; + int id_; +}; + +static bool connect_server(IO_CTX* ctx, int id) +{ + // 开始异步连接远程服务器 + aio_socket_stream* stream = aio_socket_stream::open(ctx->handle, + ctx->addr, ctx->connect_timeout); + if (stream == NULL) + { + std::cout << "connect " << ctx->addr << " error!" << std::endl; + std::cout << "stoping ..." << std::endl; + if (id == 0) + ctx->handle->stop(); + return (false); + } + + // 创建连接后的回调函数类 + client_io_callback* callback = new client_io_callback(ctx, stream, id); + + // 添加连接成功的回调函数类 + stream->add_open_callback(callback); + + // 添加连接失败后回调函数类 + stream->add_close_callback(callback); + + // 添加连接超时的回调函数类 + stream->add_timeout_callback(callback); + return (true); +} + +static void usage(const char* procname) +{ + printf("usage: %s -h[help] -l server_addr -c nconnect" + " -n io_max -k[use kernel event: epoll/kqueue/devpoll" + " -t connect_timeout -d[debug]\n", procname); +} + +int main(int argc, char* argv[]) +{ + bool use_kernel = false; + int ch; + IO_CTX ctx; + + memset(&ctx, 0, sizeof(ctx)); + ctx.connect_timeout = 5; + ctx.nopen_limit = 10; + ctx.id_begin = 1; + ctx.nwrite_limit = 10; + ctx.debug = false; + snprintf(ctx.addr, sizeof(ctx.addr), "127.0.0.1:9001"); + + while ((ch = getopt(argc, argv, "hc:n:kl:dt:")) > 0) + { + switch (ch) + { + case 'c': + ctx.nopen_limit = atoi(optarg); + if (ctx.nopen_limit <= 0) + ctx.nopen_limit = 10; + break; + case 'n': + ctx.nwrite_limit = atoi(optarg); + if (ctx.nwrite_limit <= 0) + ctx.nwrite_limit = 10; + break; + case 'h': + usage(argv[0]); + return (0); + case 'k': + use_kernel = true; + break; + case 'l': + snprintf(ctx.addr, sizeof(ctx.addr), "%s", optarg); + break; + case 'd': + ctx.debug = true; + break; + case 't': + ctx.connect_timeout = atoi(optarg); + break; + default: + break; + } + } + + acl::meter_time(__FUNCTION__, __LINE__, "-----BEGIN-----"); + acl::acl_cpp_init(); + + aio_handle handle(use_kernel ? ENGINE_KERNEL : ENGINE_SELECT); + ctx.handle = &handle; + + if (connect_server(&ctx, ctx.id_begin) == false) + { + std::cout << "enter any key to exit." << std::endl; + getchar(); + return (1); + } + + std::cout << "Connect " << ctx.addr << " ..." << std::endl; + + while (true) + { + // 如果返回 false 则表示不再继续,需要退出 + if (handle.check() == false) + break; + } + + acl::string buf; + + buf << "total open: " << ctx.nopen_total + << ", total write: " << ctx.nwrite_total + << ", total read: " << ctx.nread_total; + + acl::meter_time(__FUNCTION__, __LINE__, buf.c_str()); + + return (0); +} + diff --git a/lib_acl_cpp/samples/aio_client/valgrind.sh b/lib_acl_cpp/samples/aio_client/valgrind.sh new file mode 100644 index 000000000..98be0c473 --- /dev/null +++ b/lib_acl_cpp/samples/aio_client/valgrind.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +valgrind --show-reachable=yes --tool=memcheck --leak-check=yes -v ./aio_client -k diff --git a/lib_acl_cpp/samples/aio_dns/Makefile b/lib_acl_cpp/samples/aio_dns/Makefile new file mode 100644 index 000000000..b890c4707 --- /dev/null +++ b/lib_acl_cpp/samples/aio_dns/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = aio_dns diff --git a/lib_acl_cpp/samples/aio_dns/aio_dns.vcproj b/lib_acl_cpp/samples/aio_dns/aio_dns.vcproj new file mode 100644 index 000000000..c38707026 --- /dev/null +++ b/lib_acl_cpp/samples/aio_dns/aio_dns.vcproj @@ -0,0 +1,242 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_acl_cpp/samples/aio_dns/aio_dns.vcxproj b/lib_acl_cpp/samples/aio_dns/aio_dns.vcxproj new file mode 100644 index 000000000..7ee3846ec --- /dev/null +++ b/lib_acl_cpp/samples/aio_dns/aio_dns.vcxproj @@ -0,0 +1,189 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + Releasedll + Win32 + + + Release + Win32 + + + + {BE2DF8B2-2DCD-4F32-99B9-0B0CA24BFAD9} + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + true + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;lib_acl_vc2010d.lib;lib_acl_cpp_vc2010d.lib;%(AdditionalDependencies) + $(OutDir)aio_dns.exe + ..\..\..\lib\win32;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)aio_dns.pdb + Console + MachineX86 + + + + + + + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;lib_acl_vc2010.lib;lib_acl_cpp_vc2010.lib;%(AdditionalDependencies) + $(OutDir)aio_dns.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + + + + + + + Disabled + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;lib_acl_d.lib;lib_acl_cpp_d.lib;%(AdditionalDependencies) + $(OutDir)aio_dns.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)aio_dns.pdb + Console + MachineX86 + + + + + Disabled + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;lib_acl.lib;lib_acl_cpp.lib;%(AdditionalDependencies) + $(OutDir)aio_dns.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)aio_dns.pdb + Console + MachineX86 + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib_acl_cpp/samples/aio_dns/aio_dns_vc2012.vcxproj b/lib_acl_cpp/samples/aio_dns/aio_dns_vc2012.vcxproj new file mode 100644 index 000000000..3ac33e813 --- /dev/null +++ b/lib_acl_cpp/samples/aio_dns/aio_dns_vc2012.vcxproj @@ -0,0 +1,194 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + Releasedll + Win32 + + + Release + Win32 + + + + {BE2DF8B2-2DCD-4F32-99B9-0B0CA24BFAD9} + Win32Proj + aio_dns + + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + true + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;lib_acl_vc2012d.lib;lib_acl_cpp_vc2012d.lib;%(AdditionalDependencies) + $(OutDir)aio_dns.exe + ..\..\..\lib\win32;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)aio_dns.pdb + Console + MachineX86 + + + + + + + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;lib_acl_vc2012.lib;lib_acl_cpp_vc2012.lib;%(AdditionalDependencies) + $(OutDir)aio_dns.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + + + + + + + Disabled + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;lib_acl_d.lib;lib_acl_cpp_d.lib;%(AdditionalDependencies) + $(OutDir)aio_dns.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)aio_dns.pdb + Console + MachineX86 + + + + + Disabled + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;lib_acl.lib;lib_acl_cpp.lib;%(AdditionalDependencies) + $(OutDir)aio_dns.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)aio_dns.pdb + Console + MachineX86 + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib_acl_cpp/samples/aio_dns/main.cpp b/lib_acl_cpp/samples/aio_dns/main.cpp new file mode 100644 index 000000000..288c0df1d --- /dev/null +++ b/lib_acl_cpp/samples/aio_dns/main.cpp @@ -0,0 +1,148 @@ +#include "lib_acl.h" +#ifndef WIN32 +#include +#endif +#include +#include "acl_cpp/stream/aio_handle.hpp" +#include "acl_cpp/stdlib/dns_service.hpp" + +using namespace acl; + +static void usage(const char* procname) +{ + printf("usage: %s -h[help] -t[use thread]\n", procname); +} + +static int __ncount = 0; + +class dns_result : public dns_result_callback +{ +public: + dns_result(const char* domain) + : dns_result_callback(domain) + { + + } + + ~dns_result() + { + + } + + virtual void destroy() + { + delete this; + __ncount--; + } + + virtual void on_result(const char* domain, const dns_res& res) + { + std::cout << "result: domain: " << domain; + if (res.ips_.size() == 0) + { + std::cout << ": null" << std::endl; + return; + } + + std::cout << std::endl; + + std::list::const_iterator cit = res.ips_.begin(); + for (; cit != res.ips_.end(); cit++) + std::cout << "\t" << (*cit).c_str(); + std::cout << std::endl; + } +}; + +int main(int argc, char* argv[]) +{ + int ch, nthreads = 2; + + while ((ch = getopt(argc, argv, "ht:")) > 0) + { + switch (ch) + { + case 'h': + usage(argv[0]); + return (0); + case 't': + nthreads = atoi(optarg); + break; + default: + break; + } + } + + acl_init(); + + aio_handle handle; + + const char* domain = "www.baidu.com"; + dns_service* server = new dns_service(nthreads); + + // 使消息服务器监听 127.0.0.1 的地址 + if (server->open(&handle) == false) + { + delete server; + std::cout << "open server error!" << std::endl; + getchar(); + return (1); + } + + dns_result* result = new dns_result(domain); + server->lookup(result); + __ncount++; + + result = new dns_result(domain); + server->lookup(result); + __ncount++; + + result = new dns_result(domain); + server->lookup(result); + __ncount++; + + domain = "www.sina.com"; + result = new dns_result(domain); + server->lookup(result); + __ncount++; + + domain = "www.51iker.com"; + result = new dns_result(domain); + server->lookup(result); + __ncount++; + + domain = "www.hexun.com"; + result = new dns_result(domain); + server->lookup(result); + __ncount++; + + domain = "www.com.dummy"; + result = new dns_result(domain); + server->lookup(result); + __ncount++; + + result = new dns_result(domain); + server->lookup(result); + __ncount++; + + result = new dns_result(domain); + server->lookup(result); + __ncount++; + + while (true) + { + if (handle.check() == false) + { + std::cout << "stop now!" << std::endl; + break; + } + if (__ncount == 0) + break; + } + + delete server; + handle.check(); + + std::cout << "server stopped!" << std::endl; + getchar(); + return (0); +} diff --git a/lib_acl_cpp/samples/aio_dns/valgrind.sh b/lib_acl_cpp/samples/aio_dns/valgrind.sh new file mode 100644 index 000000000..366081f21 --- /dev/null +++ b/lib_acl_cpp/samples/aio_dns/valgrind.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +valgrind --show-reachable=yes --tool=memcheck --leak-check=yes -v ./aio_dns -t 10 diff --git a/lib_acl_cpp/samples/aio_ipc/Makefile b/lib_acl_cpp/samples/aio_ipc/Makefile new file mode 100644 index 000000000..503c06c77 --- /dev/null +++ b/lib_acl_cpp/samples/aio_ipc/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = aio_ipc diff --git a/lib_acl_cpp/samples/aio_ipc/aio_ipc.vcproj b/lib_acl_cpp/samples/aio_ipc/aio_ipc.vcproj new file mode 100644 index 000000000..f9261b426 --- /dev/null +++ b/lib_acl_cpp/samples/aio_ipc/aio_ipc.vcproj @@ -0,0 +1,240 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_acl_cpp/samples/aio_ipc/aio_ipc.vcxproj b/lib_acl_cpp/samples/aio_ipc/aio_ipc.vcxproj new file mode 100644 index 000000000..7e0c1bfc7 --- /dev/null +++ b/lib_acl_cpp/samples/aio_ipc/aio_ipc.vcxproj @@ -0,0 +1,189 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + Releasedll + Win32 + + + Release + Win32 + + + + {956FA905-A77F-41FE-A4BE-C3BD3B5B3E83} + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + true + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;lib_acl_vc2010d.lib;lib_acl_cpp_vc2010d.lib;%(AdditionalDependencies) + $(OutDir)aio_ipc.exe + ..\..\..\lib\win32;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)aio_ipc.pdb + Console + MachineX86 + + + + + + + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;lib_acl_vc2010.lib;lib_acl_cpp_vc2010.lib;%(AdditionalDependencies) + $(OutDir)aio_ipc.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + + + + + + + Disabled + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;lib_acl_d.lib;lib_acl_cpp_d.lib;%(AdditionalDependencies) + $(OutDir)aio_ipc.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)aio_ipc.pdb + Console + MachineX86 + + + + + Disabled + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;lib_acl.lib;lib_acl_cpp.lib;%(AdditionalDependencies) + $(OutDir)aio_ipc.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)aio_ipc.pdb + Console + MachineX86 + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib_acl_cpp/samples/aio_ipc/aio_ipc_vc2012.vcxproj b/lib_acl_cpp/samples/aio_ipc/aio_ipc_vc2012.vcxproj new file mode 100644 index 000000000..cdd6ab77a --- /dev/null +++ b/lib_acl_cpp/samples/aio_ipc/aio_ipc_vc2012.vcxproj @@ -0,0 +1,194 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + Releasedll + Win32 + + + Release + Win32 + + + + {956FA905-A77F-41FE-A4BE-C3BD3B5B3E83} + Win32Proj + aio_ipc + + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + true + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;lib_acl_vc2012d.lib;lib_acl_cpp_vc2012d.lib;%(AdditionalDependencies) + $(OutDir)aio_ipc.exe + ..\..\..\lib\win32;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)aio_ipc.pdb + Console + MachineX86 + + + + + + + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;lib_acl_vc2012.lib;lib_acl_cpp_vc2012.lib;%(AdditionalDependencies) + $(OutDir)aio_ipc.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + + + + + + + Disabled + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;lib_acl_d.lib;lib_acl_cpp_d.lib;%(AdditionalDependencies) + $(OutDir)aio_ipc.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)aio_ipc.pdb + Console + MachineX86 + + + + + Disabled + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;lib_acl.lib;lib_acl_cpp.lib;%(AdditionalDependencies) + $(OutDir)aio_ipc.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)aio_ipc.pdb + Console + MachineX86 + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib_acl_cpp/samples/aio_ipc/main.cpp b/lib_acl_cpp/samples/aio_ipc/main.cpp new file mode 100644 index 000000000..2950e4273 --- /dev/null +++ b/lib_acl_cpp/samples/aio_ipc/main.cpp @@ -0,0 +1,238 @@ +#include "lib_acl.h" +#ifndef WIN32 +#include +#endif +#include +#include "acl_cpp/stream/aio_handle.hpp" +#include "acl_cpp/ipc/ipc_server.hpp" +#include "acl_cpp/ipc/ipc_client.hpp" + +using namespace acl; + +#define MSG_REQ 1 +#define MSG_RES 2 +#define MSG_STOP 3 + +class test_client1 : public ipc_client +{ +public: + test_client1() + { + + } + + ~test_client1() + { + + } + + virtual void on_open() + { + // 添加消息回调对象 + this->append_message(MSG_RES); + + // 向消息服务器发送请求消息 + this->send_message(MSG_REQ, NULL, 0); + + // 异步等待消息 + wait(); + } + + virtual void on_close() + { + delete this; + } + + virtual void on_message(int nMsg, void* data, int dlen) + { + (void) data; + (void) dlen; + std::cout << "test_client1 on message:" << nMsg << std::endl; + this->send_message(MSG_STOP, NULL, 0); + this->delete_message(MSG_RES); + this->get_handle().stop(); + this->close(); + } +protected: +private: +}; + +// 子线程处理过程 + +static bool client_main(aio_handle* handle, const char* addr) +{ + // 创建消息连接 + ipc_client* ipc = new test_client1(); + + // 连接消息服务器 + if (ipc->open(handle, addr, 0) == false) + { + std::cout << "open " << addr << " error!" << std::endl; + delete ipc; + return (false); + } + + return (true); +} + +static void* thread_callback(void *ctx) +{ + const char* addr = (const char*) ctx; + aio_handle handle; + + if (client_main(&handle, addr) == false) + { + handle.check(); + return (NULL); + } + + // 消息循环 + while (true) + { + if (handle.check() == false) + break; + } + + handle.check(); + + return (NULL); +} + +class test_client2 : public ipc_client +{ +public: + test_client2() + { + + } + + ~test_client2() + { + + } + + virtual void on_close() + { + delete this; + } + + virtual void on_message(int nMsg, void* data, int dlen) + { + (void) data; + (void) dlen; + + std::cout << "test_client2 on message:" << nMsg << std::endl; + + if (nMsg == MSG_STOP) + { + this->close(); + this->get_handle().stop(); + } + else + // 回应客户端消息 + this->send_message(MSG_RES, NULL, 0); + } +protected: +private: +}; + +class test_server : public ipc_server +{ +public: + test_server() + { + + } + + ~test_server() + { + + } + + void on_accept(aio_socket_stream* client) + { + ipc_client* ipc = new test_client2(); + + // 打开异步IPC过程 + ipc->open(client); + + // 添加消息回调对象 + ipc->append_message(MSG_REQ); + ipc->append_message(MSG_STOP); + ipc->wait(); + } +protected: +private: +}; + +static void usage(const char* procname) +{ + printf("usage: %s -h[help] -t[use thread]\n", procname); +} + +int main(int argc, char* argv[]) +{ + int ch; + bool use_thread = false; + + while ((ch = getopt(argc, argv, "ht")) > 0) + { + switch (ch) + { + case 'h': + usage(argv[0]); + return (0); + case 't': + use_thread = true; + break; + default: + break; + } + } + + acl_init(); + + aio_handle handle; + + ipc_server* server = new test_server(); + + // 使消息服务器监听 127.0.0.1 的地址 + if (server->open(&handle, "127.0.0.1:0") == false) + { + delete server; + std::cout << "open server error!" << std::endl; + getchar(); + return (1); + } + + char addr[256]; +#ifdef WIN32 + _snprintf(addr, sizeof(addr), "%s", server->get_addr()); +#else + snprintf(addr, sizeof(addr), "%s", server->get_addr()); +#endif + + if (use_thread) + { + acl_pthread_t tid; + acl_pthread_create(&tid, NULL, thread_callback, addr); + } + else + client_main(&handle, addr); + + while (true) + { + if (handle.check() == false) + { + std::cout << "stop now!" << std::endl; + break; + } + } + + delete server; + handle.check(); + + std::cout << "server stopped!" << std::endl; + getchar(); + return (0); +} diff --git a/lib_acl_cpp/samples/aio_server/Makefile b/lib_acl_cpp/samples/aio_server/Makefile new file mode 100644 index 000000000..1756e9358 --- /dev/null +++ b/lib_acl_cpp/samples/aio_server/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = aio_server diff --git a/lib_acl_cpp/samples/aio_server/aio_server.vcproj b/lib_acl_cpp/samples/aio_server/aio_server.vcproj new file mode 100644 index 000000000..7768b6d40 --- /dev/null +++ b/lib_acl_cpp/samples/aio_server/aio_server.vcproj @@ -0,0 +1,240 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_acl_cpp/samples/aio_server/aio_server.vcxproj b/lib_acl_cpp/samples/aio_server/aio_server.vcxproj new file mode 100644 index 000000000..6c446934b --- /dev/null +++ b/lib_acl_cpp/samples/aio_server/aio_server.vcxproj @@ -0,0 +1,189 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + Releasedll + Win32 + + + Release + Win32 + + + + {225D0BFA-64D7-4F8F-951E-36A494CF6178} + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + true + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;lib_acl_vc2010d.lib;lib_acl_cpp_vc2010d.lib;%(AdditionalDependencies) + $(OutDir)aio_server.exe + ..\..\..\lib\win32;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)aio_server.pdb + Console + MachineX86 + + + + + + + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;lib_acl_vc2010.lib;lib_acl_cpp_vc2010.lib;%(AdditionalDependencies) + $(OutDir)aio_server.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + + + + + + + Disabled + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;lib_acl_d.lib;lib_acl_cpp_d.lib;%(AdditionalDependencies) + $(OutDir)aio_server.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)aio_server.pdb + Console + MachineX86 + + + + + Disabled + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;lib_acl.lib;lib_acl_cpp.lib;%(AdditionalDependencies) + $(OutDir)aio_server.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)aio_server.pdb + Console + MachineX86 + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib_acl_cpp/samples/aio_server/aio_server_vc2012.vcxproj b/lib_acl_cpp/samples/aio_server/aio_server_vc2012.vcxproj new file mode 100644 index 000000000..4742de460 --- /dev/null +++ b/lib_acl_cpp/samples/aio_server/aio_server_vc2012.vcxproj @@ -0,0 +1,194 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + Releasedll + Win32 + + + Release + Win32 + + + + {225D0BFA-64D7-4F8F-951E-36A494CF6178} + Win32Proj + aio_server + + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + true + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;lib_acl_vc2012d.lib;lib_acl_cpp_vc2012d.lib;%(AdditionalDependencies) + $(OutDir)aio_server.exe + ..\..\..\lib\win32;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)aio_server.pdb + Console + MachineX86 + + + + + + + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;lib_acl_vc2012.lib;lib_acl_cpp_vc2012.lib;%(AdditionalDependencies) + $(OutDir)aio_server.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + + + + + + + Disabled + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;lib_acl_d.lib;lib_acl_cpp_d.lib;%(AdditionalDependencies) + $(OutDir)aio_server.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)aio_server.pdb + Console + MachineX86 + + + + + Disabled + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;lib_acl.lib;lib_acl_cpp.lib;%(AdditionalDependencies) + $(OutDir)aio_server.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)aio_server.pdb + Console + MachineX86 + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib_acl_cpp/samples/aio_server/main.cpp b/lib_acl_cpp/samples/aio_server/main.cpp new file mode 100644 index 000000000..1b985331d --- /dev/null +++ b/lib_acl_cpp/samples/aio_server/main.cpp @@ -0,0 +1,316 @@ +#include +#include +#include "lib_acl.h" +#include "acl_cpp/stream/aio_handle.hpp" +#include "acl_cpp/stream/aio_istream.hpp" +#include "acl_cpp/stream/aio_listen_stream.hpp" +#include "acl_cpp/stream/aio_socket_stream.hpp" + +using namespace acl; + +/** + * 延迟读回调处理类 + */ +class timer_reader: public aio_timer_reader +{ +public: + timer_reader(int delay) + { + delay_ = delay; + std::cout << "timer_reader init, delay: " << delay << std::endl; + } + + ~timer_reader() + { + } + + // aio_timer_reader 的子类必须重载 destroy 方法 + void destroy() + { + std::cout << "timer_reader delete, delay: " << delay_ << std::endl; + delete this; + } + + // 重载基类回调方法 + virtual void timer_callback(unsigned int id) + { + std::cout << "timer_reader(" << id + << "): timer_callback, delay: " << delay_ << std::endl; + + // 调用基类的处理过程 + aio_timer_reader::timer_callback(id); + } + +private: + int delay_; +}; + +/** + * 延迟写回调处理类 + */ +class timer_writer: public aio_timer_writer +{ +public: + timer_writer(int delay) + { + delay_ = delay; + std::cout << "timer_writer init, delay: " << delay << std::endl; + } + + ~timer_writer() + { + } + + // aio_timer_reader 的子类必须重载 destroy 方法 + void destroy() + { + std::cout << "timer_writer delete, delay: " << delay_ << std::endl; + delete this; + } + + // 重载基类回调方法 + virtual void timer_callback(unsigned int id) + { + std::cout << "timer_writer(" << id << "): timer_callback, delay: " + << delay_ << std::endl; + + // 调用基类的处理过程 + aio_timer_writer::timer_callback(id); + } + +private: + int delay_; +}; + +/** + * 异步客户端流的回调类的子类 + */ +class io_callback : public aio_callback +{ +public: + io_callback(aio_socket_stream* client) + : client_(client) + , i_(0) + { + } + + ~io_callback() + { + std::cout << "delete io_callback now ..." << std::endl; + } + + /** + * 实现父类中的虚函数,客户端流的读成功回调过程 + * @param data {char*} 读到的数据地址 + * @param len {int} 读到的数据长度 + * @return {bool} 返回 true 表示继续,否则希望关闭该异步流 + */ + bool read_callback(char* data, int len) + { + i_++; + if (i_ < 10) + std::cout << ">>gets(i:" << i_ << "): " << data; + + // 如果远程客户端希望退出,则关闭之 + if (strncasecmp(data, "quit", 4) == 0) + { + client_->format("Bye!\r\n"); + client_->close(); + } + + // 如果远程客户端希望服务端也关闭,则中止异步事件过程 + else if (strncasecmp(data, "stop", 4) == 0) + { + client_->format("Stop now!\r\n"); + client_->close(); // 关闭远程异步流 + + // 通知异步引擎关闭循环过程 + client_->get_handle().stop(); + } + + // 向远程客户端回写收到的数据 + + int delay = 0; + + if (strncasecmp(data, "write_delay", strlen("write_delay")) == 0) + { + // 延迟写过程 + + const char* ptr = data + strlen("write_delay"); + delay = atoi(ptr); + if (delay > 0) + { + std::cout << ">> write delay " << delay + << " second ..." << std::endl; + timer_writer* timer = new timer_writer(delay); + client_->write(data, len, delay * 1000000, timer); + client_->gets(10, false); + return (true); + } + } + else if (strncasecmp(data, "read_delay", strlen("read_delay")) == 0) + { + // 延迟读过程 + + const char* ptr = data + strlen("read_delay"); + delay = atoi(ptr); + if (delay > 0) + { + client_->write(data, len); + std::cout << ">> read delay " << delay + << " second ..." << std::endl; + timer_reader* timer = new timer_reader(delay); + client_->gets(10, false, delay * 1000000, timer); + return (true); + } + } + + client_->write(data, len); + //client_->gets(10, false); + return (true); + } + + /** + * 实现父类中的虚函数,客户端流的写成功回调过程 + * @return {bool} 返回 true 表示继续,否则希望关闭该异步流 + */ + bool write_callback() + { + return (true); + } + + /** + * 实现父类中的虚函数,客户端流的超时回调过程 + */ + void close_callback() + { + // 必须在此处删除该动态分配的回调类对象以防止内存泄露 + delete this; + } + + /** + * 实现父类中的虚函数,客户端流的超时回调过程 + * @return {bool} 返回 true 表示继续,否则希望关闭该异步流 + */ + bool timeout_callback() + { + std::cout << "Timeout ..." << std::endl; + return (true); + } + +private: + aio_socket_stream* client_; + int i_; +}; + +/** + * 异步监听流的回调类的子类 + */ +class io_accept_callback : public aio_accept_callback +{ +public: + io_accept_callback() {} + ~io_accept_callback() + { + printf(">>io_accept_callback over!\n"); + } + + /** + * 基类虚函数,当有新连接到达后调用此回调过程 + * @param client {aio_socket_stream*} 异步客户端流 + * @return {bool} 返回 true 以通知监听流继续监听 + */ + bool accept_callback(aio_socket_stream* client) + { + // 创建异步客户端流的回调对象并与该异步流进行绑定 + io_callback* callback = new io_callback(client); + + // 注册异步流的读回调过程 + client->add_read_callback(callback); + + // 注册异步流的写回调过程 + client->add_write_callback(callback); + + // 注册异步流的关闭回调过程 + client->add_close_callback(callback); + + // 注册异步流的超时回调过程 + client->add_timeout_callback(callback); + + // 从异步流读一行数据 + client->gets(10, false); + return (true); + } +}; + +static void usage(const char* procname) +{ + printf("usage: %s -h[help] -k[use kernel event: epoll/iocp/kqueue/devpool]\n", procname); +} + +int main(int argc, char* argv[]) +{ + bool use_kernel = true; + int ch; + + while ((ch = getopt(argc, argv, "hk")) > 0) + { + switch (ch) + { + case 'h': + usage(argv[0]); + return (0); + case 'k': + use_kernel = true; + break; + default: + break; + } + } + + // 构建异步引擎类对象 + aio_handle handle(use_kernel ? ENGINE_KERNEL : ENGINE_SELECT); + + // 创建监听异步流 + aio_listen_stream* sstream = new aio_listen_stream(&handle); + const char* addr = "127.0.0.1:9001"; + + // 初始化ACL库(尤其是在WIN32下一定要调用此函数,在UNIX平台下可不调用) + acl_init(); + + // 监听指定的地址 + if (sstream->open(addr) == false) + { + std::cout << "open " << addr << " error!" << std::endl; + sstream->close(); + // XXX: 为了保证能关闭监听流,应在此处再 check 一下 + handle.check(); + + getchar(); + return (1); + } + + // 创建回调类对象,当有新连接到达时自动调用此类对象的回调过程 + io_accept_callback callback; + sstream->add_accept_callback(&callback); + std::cout << "Listen: " << addr << " ok!" << std::endl; + +#if 1 + while (true) + { + // 如果返回 false 则表示不再继续,需要退出 + if (handle.check() == false) + { + std::cout << "aio_server stop now ..." << std::endl; + break; + } + } +#endif + // 关闭监听流并释放流对象 + sstream->close(); + + // XXX: 为了保证能关闭监听流,应在此处再 check 一下 + handle.check(); + + return (0); +} diff --git a/lib_acl_cpp/samples/aio_server/valgrind.sh b/lib_acl_cpp/samples/aio_server/valgrind.sh new file mode 100644 index 000000000..512eeaeb8 --- /dev/null +++ b/lib_acl_cpp/samples/aio_server/valgrind.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +valgrind --show-reachable=yes --tool=memcheck --leak-check=yes -v ./aio_server -k diff --git a/lib_acl_cpp/samples/beanstalk/Makefile b/lib_acl_cpp/samples/beanstalk/Makefile new file mode 100644 index 000000000..578c883a2 --- /dev/null +++ b/lib_acl_cpp/samples/beanstalk/Makefile @@ -0,0 +1,4 @@ +UTIL = $(wildcard ../*.cpp) +PROG = beanstalk +include ../Makefile.in +CFLAGS += -I../ diff --git a/lib_acl_cpp/samples/beanstalk/ReadMe.txt b/lib_acl_cpp/samples/beanstalk/ReadMe.txt new file mode 100644 index 000000000..5105330cc --- /dev/null +++ b/lib_acl_cpp/samples/beanstalk/ReadMe.txt @@ -0,0 +1,31 @@ +======================================================================== + 控制台应用程序 : beanstalk 项目概况 +======================================================================== + +应用程序向导已为您创建了这个 beanstalk 应用程序。 +此文件包含组成 beanstalk 应用程序 +的每个文件的内容摘要。 + + +beanstalk.vcproj + 这是用应用程序向导生成的 VC++ 项目的主项目文件。 + 它包含有关生成此文件的 Visual C++ 版本的信息,以及 + 有关用应用程序向导选择的 + 平台、配置和项目功能的信息。 + +beanstalk.cpp + 这是主应用程序源文件。 + +///////////////////////////////////////////////////////////////////////////// +其他标准文件: + +StdAfx.h、StdAfx.cpp + 这些文件用于生成名为 beanstalk.pch + 的预编译头(PCH)文件以及名为 StdAfx.obj 的预编译类型文件。 + +///////////////////////////////////////////////////////////////////////////// +其他注释: + +应用程序向导使用 "TODO:" 注释指示应添加或自定义的源代码部分。 + +///////////////////////////////////////////////////////////////////////////// diff --git a/lib_acl_cpp/samples/beanstalk/beanstalk.cpp b/lib_acl_cpp/samples/beanstalk/beanstalk.cpp new file mode 100644 index 000000000..373c4bcf7 --- /dev/null +++ b/lib_acl_cpp/samples/beanstalk/beanstalk.cpp @@ -0,0 +1,154 @@ +// beanstalk.cpp : 定义控制台应用程序的入口点。 +// + +#include "stdafx.h" +#include "util.h" + +static char __addr[64]; +static const char* __tube = "zsxxsz"; +static int __max = 100; + +// 消息生产者线程 +static void* producer(void* ctx) +{ + (void) ctx; + + // beanstalk 客户端连接对象 + acl::beanstalk conn(__addr, 10); + + // 指定消息目标队列 + if (conn.use(__tube) == false) + { + printf("use %s error\r\n", __tube); + return NULL; + } + else + printf("use %s ok\r\n", __tube); + + acl::string data; + unsigned long long id; + for (int i = 0; i < __max; i++) + { + data.format("hello-%d", i); + // 向 beanstalkd 消息服务器发送消息 + if ((id = conn.put(data.c_str(), data.length())) == 0) + { + printf("put %s failed\r\n", data.c_str()); + return NULL; + } + else if (i < 10) + printf("put %s ok, id: %llu, len: %d\r\n", + data.c_str(), id, (int) data.length()); + } + + return NULL; +} + +// 接收队列消息的消费者线程 +static void* consumer(void* ctx) +{ + (void) ctx; + + acl::beanstalk conn(__addr, 10); + // 从指定消息队列中接收消息 + if (conn.watch(__tube) == false) + { + printf("watch %s faile\r\n", __tube); + return NULL; + } + + acl::string buf; + unsigned long long id; + struct timeval begin, end; + gettimeofday(&begin, NULL); + ACL_METER_TIME("begin"); + for (int i = 0; i < __max; i++) + { + // 接收一条消息 + if ((id = conn.reserve(buf)) == 0) + { + printf("reserve failed\r\n"); + return NULL; + } + else if (i < 10) + printf("reserved: %s\r\n", buf.c_str()); + + // 删除接收到的消息 + if (conn.delete_id(id) == false) + { + printf("delete id %llu failed\r\n", id); + return NULL; + } + else if (i < 10) + printf("delete id %llu ok\r\n", id); + if (i % 1000 == 0) + { + buf.format_append("; total: %d, curr: %d, id: %ld", + __max, i, id); + ACL_METER_TIME(buf.c_str()); + } + } + + gettimeofday(&end, NULL); + double n = util::stamp_sub(&end, &begin); + printf("total get: %d, spent: %0.2f ms, speed: %0.2f\r\n", + __max, n, (__max * 1000) /(n > 0 ? n : 1)); + return NULL; +} + +static void test1() +{ + acl_pthread_attr_t attr; + acl_pthread_t tid1, tid2; + + acl_pthread_attr_init(&attr); + acl_pthread_attr_setdetachstate(&attr, 0); + + acl_pthread_create(&tid1, &attr, consumer, NULL); + acl_pthread_create(&tid2, &attr, producer, NULL); + + acl_pthread_join(tid1, NULL); + acl_pthread_join(tid2, NULL); +} + +static void usage(const char* procname) +{ + printf("usage: %s -h [help] -s beanstalk_addr [127.0.0.1:11300] -n max_count\r\n", procname); +} + +int main(int argc, char* argv[]) +{ +#if WIN32 + acl::acl_cpp_init(); +#endif + snprintf(__addr, sizeof(__addr), "127.0.0.1:11300"); + int ch; + while ((ch = getopt(argc, argv, "hs:n:")) > 0) + { + switch (ch) + { + case 'h': + usage(argv[0]); + return 0; + case 's': + snprintf(__addr, sizeof(__addr), "%s", optarg); + break; + case 'n': + __max = atoi(optarg); + if (__max <= 0) + __max = 1; + break; + default: + break; + } + } + + test1(); + +#ifdef WIN32 + printf("enter any key to exit\r\n"); + getchar(); +#endif + return 0; +} + diff --git a/lib_acl_cpp/samples/beanstalk/beanstalk.vcproj b/lib_acl_cpp/samples/beanstalk/beanstalk.vcproj new file mode 100644 index 000000000..de9955b1a --- /dev/null +++ b/lib_acl_cpp/samples/beanstalk/beanstalk.vcproj @@ -0,0 +1,269 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_acl_cpp/samples/beanstalk/stdafx.cpp b/lib_acl_cpp/samples/beanstalk/stdafx.cpp new file mode 100644 index 000000000..cdec0e11a --- /dev/null +++ b/lib_acl_cpp/samples/beanstalk/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// beanstalk.pch 将成为预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + +// TODO: 在 STDAFX.H 中 +//引用任何所需的附加头文件,而不是在此文件中引用 diff --git a/lib_acl_cpp/samples/beanstalk/stdafx.h b/lib_acl_cpp/samples/beanstalk/stdafx.h new file mode 100644 index 000000000..4b8305d29 --- /dev/null +++ b/lib_acl_cpp/samples/beanstalk/stdafx.h @@ -0,0 +1,14 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是常用但不常更改的项目特定的包含文件 +// + +#pragma once + +#include "lib_acl.h" +#include "acl_cpp/lib_acl.hpp" + +// TODO: 在此处引用程序要求的附加头文件 + +#ifdef WIN32 +#define snprintf _snprintf +#endif diff --git a/lib_acl_cpp/samples/beanstalk/valgrind.sh b/lib_acl_cpp/samples/beanstalk/valgrind.sh new file mode 100644 index 000000000..b14acd9e0 --- /dev/null +++ b/lib_acl_cpp/samples/beanstalk/valgrind.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +valgrind --tool=memcheck --leak-check=yes -v ./beanstalk diff --git a/lib_acl_cpp/samples/benchmark/Makefile b/lib_acl_cpp/samples/benchmark/Makefile new file mode 100644 index 000000000..23e28c340 --- /dev/null +++ b/lib_acl_cpp/samples/benchmark/Makefile @@ -0,0 +1,12 @@ +.PHONY = all clean + +all: + @(cd client; make) + @(cd server; make) + @(cd connect; make) + @(cd accept; make) +clean: + @(cd client; make clean) + @(cd server; make clean) + @(cd connect; make clean) + @(cd accept; make clean) diff --git a/lib_acl_cpp/samples/benchmark/Makefile.in b/lib_acl_cpp/samples/benchmark/Makefile.in new file mode 100644 index 000000000..384ea7731 --- /dev/null +++ b/lib_acl_cpp/samples/benchmark/Makefile.in @@ -0,0 +1,96 @@ +CC = g++ + +CFLAGS = -c -g -W -Wall -Wcast-qual -Wcast-align \ +-Wno-long-long \ +-Wpointer-arith -Werror -Wshadow -O3 \ +-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO + +#-Waggregate-return +########################################################### +#Check system: +# Linux, SunOS, Solaris, BSD variants, AIX, HP-UX +SYSLIB = -lpthread -lcrypt +CHECKSYSRES = @echo "Unknow system type!";exit 1 +UNIXNAME = $(shell uname -sm) + +ifeq ($(CC),) + CC = gcc +endif + +# For FreeBSD +ifeq ($(findstring FreeBSD, $(UNIXNAME)), FreeBSD) + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DFREEBSD -D_REENTRANT + SYSLIB = -lcrypt -lpthread +endif + +#Path for Linux +ifeq ($(findstring Linux, $(UNIXNAME)), Linux) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DLINUX2 -D_REENTRANT +endif + +#Path for SunOS +ifeq ($(findstring SunOS, $(UNIXNAME)), SunOS) + ifeq ($(findstring 86, $(UNIXNAME)), 86) + SYSLIB += -lsocket -lnsl -lrt + endif + ifeq ($(findstring sun4u, $(UNIXNAME)), sun4u) + SYSLIB += -lsocket -lnsl -lrt + endif + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DSUNOS5 -D_REENTRANT +endif + +#Path for HP-UX +ifeq ($(findstring HP-UX, $(UNIXNAME)), HP-UX) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DHP_UX -DHPUX11 + PLAT_NAME=hp-ux +endif + +#Find system type. +ifneq ($(SYSPATH),) + CHECKSYSRES = @echo "System is $(shell uname -sm)" +endif +########################################################### + +CFLAGS += -I. -I../.. -I../../../include -I../../../../lib_acl/include -I../../../../lib_protocol/include +EXTLIBS = +LDFLAGS = -L../../../lib -l_acl_cpp -L../../../../lib_protocol/lib -l_protocol -L../../../../lib_acl/lib -l_acl \ + $(EXTLIBS) $(SYSLIB) + +COMPILE = $(CC) $(CFLAGS) +LINK = $(CC) $(OBJ) $(LDFLAGS) +########################################################### +OBJ_PATH = . + +#Project's objs +SRC = $(wildcard *.cpp) $(wildcard ../../*.cpp) +OBJ = $(patsubst %.cpp, $(OBJ_PATH)/%.o, $(notdir $(SRC))) + +$(OBJ_PATH)/%.o: %.cpp + $(COMPILE) $< -o $@ +$(OBJ_PATH)/%.o: ../../%.cpp + $(COMPILE) $< -o $@ + +.PHONY = all clean +all: RM $(OBJ) + $(LINK) -o $(PROG) + @echo "" + @echo "All ok! Output:$(PROG)" + @echo "" +RM: + rm -f $(PROG) +clean: + rm -f $(PROG) + rm -f $(OBJ) +########################################################### diff --git a/lib_acl_cpp/samples/benchmark/accept/Makefile b/lib_acl_cpp/samples/benchmark/accept/Makefile new file mode 100644 index 000000000..93cccf710 --- /dev/null +++ b/lib_acl_cpp/samples/benchmark/accept/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = accept diff --git a/lib_acl_cpp/samples/benchmark/accept/main.cpp b/lib_acl_cpp/samples/benchmark/accept/main.cpp new file mode 100644 index 000000000..3c8c2c3b8 --- /dev/null +++ b/lib_acl_cpp/samples/benchmark/accept/main.cpp @@ -0,0 +1,64 @@ +#include "stdafx.h" + +static void usage(const char* procname) +{ + printf("usage: %s -h[help] -s addr[127.0.0.1:8088] -n max_client[100]\r\n", procname); +} + +int main(int argc, char* argv[]) +{ + int ch, max = 100; + acl::string addr("127.0.0.1:8088"); + + while ((ch = getopt(argc, argv, "hs:n:")) > 0) + { + switch (ch) + { + case 'h': + usage(argv[0]); + return 0; + case 's': + addr = optarg; + break; + case 'n': + max = atoi(optarg); + break; + default: + usage(argv[0]); + return 0; + } + } + + acl::server_socket server; + if (server.open(addr) == false) + { + printf("can't listen %s, %s\r\n", addr.c_str(), acl::last_serror()); + return 1; + } + else + printf("listen %s ok\r\n", addr.c_str()); + + std::list clients; + for (int i = 0; i < max; i++) + { + acl::socket_stream* conn = server.accept(); + if (conn == NULL) + { + printf("accept error %s\r\n", acl::last_serror()); + break; + } + clients.push_back(conn); + printf("accept one ok, max: %d, curr: %d, fd: %d\r\n", + max, i, conn->sock_handle()); + } + + printf("enter any key to exist\r\n"); + getchar(); + + std::list::iterator it = clients.begin(); + for (; it != clients.end(); ++it) + delete (*it); + + printf("Over now\r\n"); + return 0; +} diff --git a/lib_acl_cpp/samples/benchmark/accept/stdafx.cpp b/lib_acl_cpp/samples/benchmark/accept/stdafx.cpp new file mode 100644 index 000000000..cdec0e11a --- /dev/null +++ b/lib_acl_cpp/samples/benchmark/accept/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// beanstalk.pch 将成为预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + +// TODO: 在 STDAFX.H 中 +//引用任何所需的附加头文件,而不是在此文件中引用 diff --git a/lib_acl_cpp/samples/benchmark/accept/stdafx.h b/lib_acl_cpp/samples/benchmark/accept/stdafx.h new file mode 100644 index 000000000..4b8305d29 --- /dev/null +++ b/lib_acl_cpp/samples/benchmark/accept/stdafx.h @@ -0,0 +1,14 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是常用但不常更改的项目特定的包含文件 +// + +#pragma once + +#include "lib_acl.h" +#include "acl_cpp/lib_acl.hpp" + +// TODO: 在此处引用程序要求的附加头文件 + +#ifdef WIN32 +#define snprintf _snprintf +#endif diff --git a/lib_acl_cpp/samples/benchmark/client/Makefile b/lib_acl_cpp/samples/benchmark/client/Makefile new file mode 100644 index 000000000..172f87db9 --- /dev/null +++ b/lib_acl_cpp/samples/benchmark/client/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = client diff --git a/lib_acl_cpp/samples/benchmark/client/main.cpp b/lib_acl_cpp/samples/benchmark/client/main.cpp new file mode 100644 index 000000000..f7dbaa2ba --- /dev/null +++ b/lib_acl_cpp/samples/benchmark/client/main.cpp @@ -0,0 +1,187 @@ +#include "stdafx.h" +#include "util.h" + +static int __max = 10; +static int __len = 100; + +static void handle_connection(acl::socket_stream& conn) +{ + acl::string rbuf, wbuf; + + for (int i = 0; i < __len; i++) + wbuf += 'X'; + wbuf += "\r\n"; + + struct timeval begin; + gettimeofday(&begin, NULL); + + for (int i = 0; i < __max; i++) + { + if (conn.write(wbuf) == -1) + { + printf("write to server error\r\n"); + break; + } + + if (conn.gets(rbuf) == false) + { + printf("readline from server error\r\n"); + break; + } + if (i < 10 && !rbuf.empty()) + printf("readline: %s\r\n", rbuf.c_str()); + + if (i % 1000 == 0) + { + char tmp[64]; + snprintf(tmp, sizeof(tmp), "total: %d, curr: %d", __max, i); + ACL_METER_TIME(tmp); + } + } + + struct timeval end; + gettimeofday(&end, NULL); + + double n = util::stamp_sub(&end, &begin); + printf("total get: %d, spent: %0.2f ms, speed: %0.2f\r\n", + __max, n, (__max * 1000) /(n > 0 ? n : 1)); +} + +static void* thread_read(void* ctx) +{ + acl::socket_stream* conn = (acl::socket_stream*) ctx; + acl::string buf; + + struct timeval begin; + gettimeofday(&begin, NULL); + + int i; + for (i = 0; i < __max; i++) + { + if (conn->gets(buf, false) == false) + { + printf("readline from client over!\r\n"); + break; + } + if (i % 10000 == 0) + printf("read count: %d, readline: %s", i, buf.c_str()); + } + + struct timeval end; + gettimeofday(&end, NULL); + + double n = util::stamp_sub(&end, &begin); + printf("total read: %d, spent: %0.2f ms, speed: %0.2f\r\n", + i, n, (i * 1000) /(n > 0 ? n : 1)); + + return NULL; +} + +static void* thread_write(void* ctx) +{ + acl::socket_stream* conn = (acl::socket_stream*) ctx; + acl::string buf; + + int i; + for (i = 0; i < __len; i++) + buf += 'X'; + buf += "\r\n"; + + struct timeval begin; + gettimeofday(&begin, NULL); + + for (i = 0; i < __max; i++) + { + if (conn->write(buf) == -1) + { + printf("write to client finish!\r\n"); + break; + } + } + + struct timeval end; + gettimeofday(&end, NULL); + + double n = util::stamp_sub(&end, &begin); + printf("total write: %d, spent: %0.2f ms, speed: %0.2f\r\n", + i, n, (i * 1000) /(n > 0 ? n : 1)); + + return NULL; +} + +static void usage(const char* procname) +{ + printf("usage: %s -h [help]\r\n" + "\t-s server_addr[127.0.0.1:8888]\r\n" + "\t-n max_loop[10]\r\n" + "\t-p [separate read/write]\r\n" + "\t-l package_length[100]\r\n", procname); +} + +int main(int argc, char* argv[]) +{ + acl::acl_cpp_init(); + + acl::string addr("127.0.0.1:8888"); + int ch; + bool separate = false; + + while ((ch = getopt(argc, argv, "hs:n:l:p")) > 0 ) + { + switch (ch) + { + case 'h': + usage(argv[0]); + return 0; + case 's': + addr = optarg; + break; + case 'n': + __max = atoi(optarg); + if (__max < 1) + __max = 1; + break; + case 'l': + __len = atoi(optarg); + if (__len <= 0) + __len = 10; + break; + case 'p': + separate = true; + break; + default: + usage(argv[0]); + return 0; + } + } + + acl::socket_stream conn; + if (conn.open(addr, 30, 30) == false) + { + printf("connect %s error\r\n", addr.c_str()); + return -1; + } + + if (!separate) + { + handle_connection(conn); + return 0; + } + + acl_pthread_attr_t attr; + acl_pthread_attr_init(&attr); + acl_pthread_attr_setdetachstate(&attr, 0); + + acl_pthread_t tid_read, tid_write; + + acl_pthread_create(&tid_read, &attr, thread_read, &conn); + acl_pthread_create(&tid_write, &attr, thread_write, &conn); + + acl_pthread_join(tid_read, NULL); + acl_pthread_join(tid_write, NULL); + + printf("enter any key to exit\r\n"); + getchar(); + + return 0; +} diff --git a/lib_acl_cpp/samples/benchmark/client/stdafx.cpp b/lib_acl_cpp/samples/benchmark/client/stdafx.cpp new file mode 100644 index 000000000..cdec0e11a --- /dev/null +++ b/lib_acl_cpp/samples/benchmark/client/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// beanstalk.pch 将成为预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + +// TODO: 在 STDAFX.H 中 +//引用任何所需的附加头文件,而不是在此文件中引用 diff --git a/lib_acl_cpp/samples/benchmark/client/stdafx.h b/lib_acl_cpp/samples/benchmark/client/stdafx.h new file mode 100644 index 000000000..4b8305d29 --- /dev/null +++ b/lib_acl_cpp/samples/benchmark/client/stdafx.h @@ -0,0 +1,14 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是常用但不常更改的项目特定的包含文件 +// + +#pragma once + +#include "lib_acl.h" +#include "acl_cpp/lib_acl.hpp" + +// TODO: 在此处引用程序要求的附加头文件 + +#ifdef WIN32 +#define snprintf _snprintf +#endif diff --git a/lib_acl_cpp/samples/benchmark/connect/Makefile b/lib_acl_cpp/samples/benchmark/connect/Makefile new file mode 100644 index 000000000..c1b506c27 --- /dev/null +++ b/lib_acl_cpp/samples/benchmark/connect/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = connect diff --git a/lib_acl_cpp/samples/benchmark/connect/main.cpp b/lib_acl_cpp/samples/benchmark/connect/main.cpp new file mode 100644 index 000000000..427f1c7d6 --- /dev/null +++ b/lib_acl_cpp/samples/benchmark/connect/main.cpp @@ -0,0 +1,59 @@ +#include "stdafx.h" + +static void usage(const char* procname) +{ + printf("usage: %s -h[help] -s server_addr[127.0.0.1:8088] -n max_connect[100]\r\n", procname); +} + +int main(int argc, char* argv[]) +{ + int ch, max = 100; + acl::string addr("127.0.0.1:8088"); + + while ((ch = getopt(argc, argv, "hs:n:")) > 0) + { + switch (ch) + { + case 'h': + usage(argv[0]); + return 0; + case 's': + addr = optarg; + break; + case 'n': + max = atoi(optarg); + break; + default: + usage(argv[0]); + return 0; + } + } + + + std::list clients; + + for (int i = 0; i < max; i++) + { + acl::socket_stream* client = new acl::socket_stream(); + if (client->open(addr, 10, 10) == false) + { + printf("connect %s error %s\r\n", + addr.c_str(), acl::last_serror()); + break; + } + else + printf("connect %s ok, fd: %d, max: %d, curr: %d\r\n", + addr.c_str(), client->sock_handle(), max, i); + clients.push_back(client); + } + + printf("enter any key to exist\r\n"); + getchar(); + + std::list::iterator it = clients.begin(); + for (; it != clients.end(); ++it) + delete (*it); + + printf("Over now\r\n"); + return 0; +} diff --git a/lib_acl_cpp/samples/benchmark/connect/stdafx.cpp b/lib_acl_cpp/samples/benchmark/connect/stdafx.cpp new file mode 100644 index 000000000..cdec0e11a --- /dev/null +++ b/lib_acl_cpp/samples/benchmark/connect/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// beanstalk.pch 将成为预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + +// TODO: 在 STDAFX.H 中 +//引用任何所需的附加头文件,而不是在此文件中引用 diff --git a/lib_acl_cpp/samples/benchmark/connect/stdafx.h b/lib_acl_cpp/samples/benchmark/connect/stdafx.h new file mode 100644 index 000000000..4b8305d29 --- /dev/null +++ b/lib_acl_cpp/samples/benchmark/connect/stdafx.h @@ -0,0 +1,14 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是常用但不常更改的项目特定的包含文件 +// + +#pragma once + +#include "lib_acl.h" +#include "acl_cpp/lib_acl.hpp" + +// TODO: 在此处引用程序要求的附加头文件 + +#ifdef WIN32 +#define snprintf _snprintf +#endif diff --git a/lib_acl_cpp/samples/benchmark/server/Makefile b/lib_acl_cpp/samples/benchmark/server/Makefile new file mode 100644 index 000000000..19cf1996e --- /dev/null +++ b/lib_acl_cpp/samples/benchmark/server/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = server diff --git a/lib_acl_cpp/samples/benchmark/server/main.cpp b/lib_acl_cpp/samples/benchmark/server/main.cpp new file mode 100644 index 000000000..89e5c364a --- /dev/null +++ b/lib_acl_cpp/samples/benchmark/server/main.cpp @@ -0,0 +1,173 @@ +#include "stdafx.h" +#include "util.h" + +static void handle_connection(acl::socket_stream* conn) +{ + acl::string buf; + int i = 0; + + struct timeval begin; + gettimeofday(&begin, NULL); + + while (true) + { + if (conn->gets(buf, false) == false) + { + printf("readline from client over!\r\n"); + break; + } + if (conn->write(buf) == -1) + { + printf("write to client error\r\n"); + break; + } + + if (i % 1000 == 0) + printf("read count: %d, readline: %s", i, buf.c_str()); + i++; + } + + struct timeval end; + gettimeofday(&end, NULL); + + double n = util::stamp_sub(&end, &begin); + printf("total get: %d, spent: %0.2f ms, speed: %0.2f\r\n", + i, n, (i * 1000) /(n > 0 ? n : 1)); +} + +static void* thread_read(void* ctx) +{ + acl::socket_stream* conn = (acl::socket_stream*) ctx; + acl::string buf; + + struct timeval begin; + gettimeofday(&begin, NULL); + + int i = 0; + + while (true) + { + if (conn->gets(buf, false) == false) + { + printf("readline from client over!\r\n"); + break; + } + if (i % 10000 == 0) + printf("read count: %d, readline: %s", i, buf.c_str()); + i++; + } + + struct timeval end; + gettimeofday(&end, NULL); + + double n = util::stamp_sub(&end, &begin); + printf("total read: %d, spent: %0.2f ms, speed: %0.2f\r\n", + i, n, (i * 1000) /(n > 0 ? n : 1)); + + return NULL; +} + +static void* thread_write(void* ctx) +{ + acl::socket_stream* conn = (acl::socket_stream*) ctx; + acl::string buf("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\r\n"); + + struct timeval begin; + gettimeofday(&begin, NULL); + + int i = 0; + while (true) + { + if (conn->write(buf) == -1) + { + printf("write to client finish!\r\n"); + break; + } + i++; + } + + struct timeval end; + gettimeofday(&end, NULL); + + double n = util::stamp_sub(&end, &begin); + printf("total write: %d, spent: %0.2f ms, speed: %0.2f\r\n", + i, n, (i * 1000) /(n > 0 ? n : 1)); + + return NULL; +} + +static void usage(const char* procname) +{ + printf("usage: %s -h [help]\r\n" + "\t-s server_addr[127.0.0.1:8888]\r\n" + "\t-p [separate read/write in two thread]\r\n", procname); +} + +int main(int argc, char* argv[]) +{ + acl::acl_cpp_init(); + + acl::string addr("127.0.0.1:8888"); + int ch; + bool separate = false; + + while ((ch = getopt(argc, argv, "hs:p")) > 0 ) + { + switch (ch) + { + case 'h': + usage(argv[0]); + return 0; + case 's': + addr = optarg; + break; + case 'p': + separate = true; + break; + default: + usage(argv[0]); + return 0; + } + } + + acl::server_socket server; + if (server.open(addr) == false) + { + printf("listen %s error\r\n", addr.c_str()); + return -1; + } + else + printf("listen %s ok\r\n", addr.c_str()); + + // 鎺ユ敹涓涓鎴风杩炴帴 + acl::socket_stream* conn = server.accept(); + if (conn == NULL) + { + printf("accept error %s\r\n", acl::last_serror()); + return -1; + } + else + printf("accept on client: %s\r\n", conn->get_peer()); + + if (!separate) + { + handle_connection(conn); + delete conn; + return 0; + } + + acl_pthread_attr_t attr; + acl_pthread_attr_init(&attr); + acl_pthread_attr_setdetachstate(&attr, 0); + + acl_pthread_t tid_read, tid_write; + + acl_pthread_create(&tid_read, &attr, thread_read, conn); + acl_pthread_create(&tid_write, &attr, thread_write, conn); + + acl_pthread_join(tid_read, NULL); + acl_pthread_join(tid_write, NULL); + + delete conn; + return 0; +} diff --git a/lib_acl_cpp/samples/benchmark/server/stdafx.cpp b/lib_acl_cpp/samples/benchmark/server/stdafx.cpp new file mode 100644 index 000000000..cdec0e11a --- /dev/null +++ b/lib_acl_cpp/samples/benchmark/server/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// beanstalk.pch 将成为预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + +// TODO: 在 STDAFX.H 中 +//引用任何所需的附加头文件,而不是在此文件中引用 diff --git a/lib_acl_cpp/samples/benchmark/server/stdafx.h b/lib_acl_cpp/samples/benchmark/server/stdafx.h new file mode 100644 index 000000000..4b8305d29 --- /dev/null +++ b/lib_acl_cpp/samples/benchmark/server/stdafx.h @@ -0,0 +1,14 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是常用但不常更改的项目特定的包含文件 +// + +#pragma once + +#include "lib_acl.h" +#include "acl_cpp/lib_acl.hpp" + +// TODO: 在此处引用程序要求的附加头文件 + +#ifdef WIN32 +#define snprintf _snprintf +#endif diff --git a/lib_acl_cpp/samples/cgi/Makefile b/lib_acl_cpp/samples/cgi/Makefile new file mode 100644 index 000000000..11ebcac17 --- /dev/null +++ b/lib_acl_cpp/samples/cgi/Makefile @@ -0,0 +1,4 @@ +include ../Makefile.in +#EXTLIBS = -lpolarssl +EXTLIBS = -lz +PROG = http_servlet diff --git a/lib_acl_cpp/samples/cgi/cgi.html b/lib_acl_cpp/samples/cgi/cgi.html new file mode 100644 index 000000000..7d967f00a --- /dev/null +++ b/lib_acl_cpp/samples/cgi/cgi.html @@ -0,0 +1,8 @@ + + +
+
+
+
+ + diff --git a/lib_acl_cpp/samples/cgi/cgi.vcproj b/lib_acl_cpp/samples/cgi/cgi.vcproj new file mode 100644 index 000000000..693be081d --- /dev/null +++ b/lib_acl_cpp/samples/cgi/cgi.vcproj @@ -0,0 +1,240 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_acl_cpp/samples/cgi/http_servlet.cpp b/lib_acl_cpp/samples/cgi/http_servlet.cpp new file mode 100644 index 000000000..ade33c495 --- /dev/null +++ b/lib_acl_cpp/samples/cgi/http_servlet.cpp @@ -0,0 +1,156 @@ +// http_servlet.cpp : 定义控制台应用程序的入口点。 +// + +#include "acl_cpp/lib_acl.hpp" + +using namespace acl; + +////////////////////////////////////////////////////////////////////////// + +class http_servlet : public HttpServlet +{ +public: + http_servlet(void) + { + + } + + ~http_servlet(void) + { + + } + + virtual bool doUnknown(HttpServletRequest&, HttpServletResponse& res) + { + res.setStatus(400); + res.setContentType("text/xml; charset=gb2312"); + // 发送 http 响应头 + if (res.sendHeader() == false) + return false; + // 发送 http 响应体 + string buf("\r\n"); + (void) res.getOutputStream().write(buf); + return false; + } + + virtual bool doGet(HttpServletRequest& req, HttpServletResponse& res) + { + return doPost(req, res); + } + + virtual bool doPost(HttpServletRequest& req, HttpServletResponse& res) + { + const char* sid = req.getSession().getAttribute("sid"); + if (*sid == 0) + req.getSession().setAttribute("sid", "xxxxxx"); + sid = req.getSession().getAttribute("sid"); + + const char* cookie1 = req.getCookieValue("name1"); + const char* cookie2 = req.getCookieValue("name2"); + + // 创建 HTTP 响应头 + res.addCookie("name1", "value1"); + res.addCookie("name2", "value2", ".test.com", "/", 3600 * 24); +// res.setStatus(400); // 可以设置返回的状态码 + + // 两种方式都可以设置字符集 + if (0) + res.setContentType("text/xml; charset=gb2312"); + else + { + res.setContentType("text/xml"); + res.setCharacterEncoding("gb2312"); + } + + const char* param1 = req.getParameter("name1"); + const char* param2 = req.getParameter("name2"); + + // 创建 xml 格式的数据体 + xml body; + body.get_root().add_child("root", true) + .add_child("sessions", true) + .add_child("session", true) + .add_attr("sid", sid ? sid : "null") + .get_parent() + .get_parent() + .add_child("cookies", true) + .add_child("cookie", true) + .add_attr("name1", cookie1 ? cookie1 : "null") + .get_parent() + .add_child("cookie", true) + .add_attr("name2", cookie2 ? cookie2 : "null") + .get_parent() + .get_parent() + .add_child("params", true) + .add_child("param", true) + .add_attr("name1", param1 ? param1 : "null") + .get_parent() + .add_child("param", true) + .add_attr("name2", param2 ? param2 : "null"); + string buf; + body.build_xml(buf); + + // 发送 http 响应头 + if (res.sendHeader() == false) + return false; + // 发送 http 响应体 + if (res.getOutputStream().write(buf) == -1) + return false; + return true; + } +protected: +private: +}; + +////////////////////////////////////////////////////////////////////////// + +static void do_run(socket_stream* stream) +{ + memcache_session session("127.0.0.1:11211"); + http_servlet servlet; + servlet.setLocalCharset("gb2312"); + servlet.doRun(session, stream); +} + +// 服务器方式运行时的服务类 +class master_service : public master_proc +{ +public: + master_service() {} + ~master_service() {} +protected: + virtual void on_accept(socket_stream* stream) + { + do_run(stream); + } +}; + +// WEB 服务模式 +static void do_alone(void) +{ + master_service service; + printf("listen: 0.0.0.0:8888 ...\r\n"); + service.run_alone("0.0.0.0:8888", NULL, 1); // 单独运行方式 +} + +// WEB CGI 模式 +static void do_cgi(void) +{ + do_run(NULL); +} + +int main(int argc, char* argv[]) +{ +#ifdef WIN32 + acl::acl_cpp_init(); +#endif + + // 开始运行 + if (argc >= 2 && strcmp(argv[1], "alone") == 0) + do_alone(); + else + do_cgi(); + + return 0; +} + diff --git a/lib_acl_cpp/samples/cgi/valgrind.sh b/lib_acl_cpp/samples/cgi/valgrind.sh new file mode 100644 index 000000000..7dfcd52e3 --- /dev/null +++ b/lib_acl_cpp/samples/cgi/valgrind.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +#valgrind --tool=memcheck --leak-check=yes --track-origins=yes -v ./http_servlet alone +valgrind --tool=memcheck --leak-check=yes -v ./http_servlet alone diff --git a/lib_acl_cpp/samples/cgi_upload/Makefile b/lib_acl_cpp/samples/cgi_upload/Makefile new file mode 100644 index 000000000..5fb5de492 --- /dev/null +++ b/lib_acl_cpp/samples/cgi_upload/Makefile @@ -0,0 +1,4 @@ +include ../Makefile.in +#EXTLIBS = -lpolarssl +EXTLIBS = -lz +PROG = upload diff --git a/lib_acl_cpp/samples/cgi_upload/cgi_upload.vcproj b/lib_acl_cpp/samples/cgi_upload/cgi_upload.vcproj new file mode 100644 index 000000000..96d73944f --- /dev/null +++ b/lib_acl_cpp/samples/cgi_upload/cgi_upload.vcproj @@ -0,0 +1,273 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_acl_cpp/samples/cgi_upload/main.cpp b/lib_acl_cpp/samples/cgi_upload/main.cpp new file mode 100644 index 000000000..e77aeaed9 --- /dev/null +++ b/lib_acl_cpp/samples/cgi_upload/main.cpp @@ -0,0 +1,312 @@ +// main.cpp : 定义控制台应用程序的入口点。 +// +#include "stdafx.h" +#include +#include "acl_cpp/lib_acl.hpp" + +using namespace acl; + +////////////////////////////////////////////////////////////////////////// + +class http_servlet : public HttpServlet +{ +public: + http_servlet(void) + { + param1_ = NULL; + param2_ = NULL; + param3_ = NULL; + file1_ = NULL; + file2_ = NULL; + file3_ = NULL; + } + + ~http_servlet(void) + { + } + + // GET 方法 + virtual bool doGet(HttpServletRequest& req, HttpServletResponse& res) + { + return doPost(req, res); + } + + // POST 方法 + virtual bool doPost(HttpServletRequest& req, HttpServletResponse& res) + { + // 如果 session 项不存在,则设置 + const char* sid = req.getSession().getAttribute("sid"); + if (*sid == 0) + req.getSession().setAttribute("sid", "xxxxxx"); + + // 创建 HTTP 响应头 + res.addCookie("name1", "value1"); + res.addCookie("name2", "value2", ".test.com", "/", 3600 * 24); +// res.setStatus(400); // 可以设置返回的状态码 + + // 两种方式都可以设置字符集 + if (0) + res.setContentType("text/xml; charset=gb2312"); + else + { + res.setContentType("text/xml"); + res.setCharacterEncoding("gb2312"); + } + + // 获得 HTTP 请求的数据类型,正常的参数类型,即 name&value 方式 + // 还是 MIME 数据类型,还是数据流类型 + http_request_t request_type = req.getRequestType(); + if (request_type == HTTP_REQUEST_NORMAL) + return doParams(req, res); + else if (request_type == HTTP_REQUEST_MULTIPART_FORM) + return doUpload(req, res); + assert(request_type == HTTP_REQUEST_OCTET_STREAM); + return doOctetStream(req, res); + } + + bool doResponse(HttpServletRequest& req, HttpServletResponse& res) + { + // 获得浏览器传来的 cookie 值 + const char* cookie1 = req.getCookieValue("name1"); + const char* cookie2 = req.getCookieValue("name2"); + + // 获得 sid session 值 + const char* sid = req.getSession().getAttribute("sid"); + + // 创建 xml 格式的数据体 + xml body; + body.get_root().add_child("root", true) + .add_child("content_type", true) + .add_attr("type", (int) req.getRequestType()) + .get_parent() + .add_child("sessions", true) + .add_child("session", true) + .add_attr("sid", sid ? sid : "null") + .get_parent() + .get_parent() + .add_child("cookies", true) + .add_child("cookie", true) + .add_attr("name1", cookie1 ? cookie1 : "null") + .get_parent() + .add_child("cookie", true) + .add_attr("name2", cookie2 ? cookie2 : "null") + .get_parent() + .get_parent() + .add_child("params", true) + .add_child("param", true) + .add_attr("name1", param1_ ? param1_ : "null") + .get_parent() + .add_child("param", true) + .add_attr("name2", param2_ ? param2_ : "null") + .get_parent() + .add_child("param", true) + .add_attr("name3", param3_ ? param3_ : "null") + .get_parent() + .get_parent() + .add_child("files", true) + .add_child("file", true) + .add_attr("filename", file1_ ? file1_ : "null") + .get_parent() + .add_child("file", true) + .add_attr("filename", file2_ ? file2_ : "null") + .get_parent() + .add_child("file", true) + .add_attr("filename", file3_ ? file3_ : "null"); + string buf; + body.build_xml(buf); + + // 发送 http 响应头 + if (res.sendHeader() == false) + return false; + // 发送 http 响应体 + if (res.getOutputStream().write(buf) == -1) + return false; + return true; + } + + // GET 方式或 POST 方式且满足: + // Content-Type: application/x-www-form-urlencoded + bool doParams(HttpServletRequest& req, HttpServletResponse& res) + { + param1_ = req.getParameter("name1"); + param2_ = req.getParameter("name2"); + param3_ = req.getParameter("name2"); + return doResponse(req, res); + } + + // POST 方式且满足: + // Content-Type: multipart/form-data; boundary=xxx + bool doUpload(HttpServletRequest& req, HttpServletResponse& res) + { + // 先获得 Content-Type 对应的 http_ctype 对象 + http_mime* mime = req.getHttpMime(); + if (mime == NULL) + { + logger_error("http_mime null"); + return false; + } + + // 获得数据体的长度 + long long int len = req.getContentLength(); + if (len <= 0) + { + logger_error("body empty"); + return false; + } + + // 获得输入流 + istream& in = req.getInputStream(); + char buf[8192]; + int ret; + bool n = false; + + const char* filepath = "./var/mime_file"; + ofstream out; + out.open_write(filepath); + + // 设置原始文件存入路径 + mime->set_saved_path(filepath); + + // 读取 HTTP 客户端请求数据 + while (len > 0) + { + ret = in.read(buf, sizeof(buf), false); + if (ret == -1) + { + logger_error("read POST data error"); + return false; + } + out.write(buf, ret); + + len -= ret; + + // 将读得到的数据输入至解析器进行解析 + if (mime->update(buf, ret) == true) + { + n = true; + break; + } + } + out.close(); + + if (len != 0 || n == false) + logger_warn("not read all data from client"); + + param1_ = req.getParameter("name1"); + param2_ = req.getParameter("name2"); + param3_ = req.getParameter("name3"); + + string path; + + // 遍历所有的 MIME 结点,找出其中为文件结点的部分进行转储 + const std::list& nodes = mime->get_nodes(); + std::list::const_iterator cit = nodes.begin(); + for (; cit != nodes.end(); ++cit) + { + const char* name = (*cit)->get_name(); + http_mime_t mime_type = (*cit)->get_mime_type(); + if (mime_type == HTTP_MIME_FILE) + { + const char* filename = (*cit)->get_filename(); + if (filename == NULL) + { + logger("filename null"); + continue; + } + + if (strcmp(name, "file1") == 0) + file1_ = filename; + else if (strcmp(name, "file2") == 0) + file2_ = filename; + else if (strcmp(name, "file3") == 0) + file3_ = filename; + path.format("./var/%s", filename); + (void) (*cit)->save(path.c_str()); + } + } + + // 查找上载的某个文件并转储 + const http_mime_node* node = mime->get_node("file1"); + if (node && node->get_mime_type() == HTTP_MIME_FILE) + { + const char* ptr = node->get_filename(); + if (ptr) + { + path.format("./var/1_%s", ptr); + (void) node->save(path.c_str()); + } + } + return doResponse(req, res); + } + + // POST 方式且满足: + // Content-Type: application/octet-stream + bool doOctetStream(HttpServletRequest&, HttpServletResponse&) + { + return false; + } + +protected: +private: + const char* param1_; + const char* param2_; + const char* param3_; + const char* file1_; + const char* file2_; + const char* file3_; +}; + +////////////////////////////////////////////////////////////////////////// + +static void do_run(socket_stream* stream) +{ + memcache_session session("127.0.0.1:11211"); + http_servlet servlet; + servlet.setLocalCharset("gb2312"); + servlet.doRun(session, stream); +} + +// 服务器方式运行时的服务类 +class master_service : public master_proc +{ +public: + master_service() {} + ~master_service() {} +protected: + virtual void on_accept(socket_stream* stream) + { + do_run(stream); + } +}; + +// WEB 服务模式 +static void do_alone(void) +{ + master_service service; + printf("listen: 0.0.0.0:8888 ...\r\n"); + service.run_alone("0.0.0.0:8888", NULL, 1); // 单独运行方式 +} + +// WEB CGI 模式 +static void do_cgi(void) +{ + do_run(NULL); +} + +////////////////////////////////////////////////////////////////////////// + +int main(int argc, char* argv[]) +{ +#ifdef WIN32 + acl::acl_cpp_init(); +#endif + + // 开始运行 + if (argc >= 2 && strcmp(argv[1], "alone") == 0) + do_alone(); + else + do_cgi(); + + return 0; +} + diff --git a/lib_acl_cpp/samples/cgi_upload/stdafx.cpp b/lib_acl_cpp/samples/cgi_upload/stdafx.cpp new file mode 100644 index 000000000..05fa0d509 --- /dev/null +++ b/lib_acl_cpp/samples/cgi_upload/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// cgi_upload.pch 将成为预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + +// TODO: 在 STDAFX.H 中 +//引用任何所需的附加头文件,而不是在此文件中引用 diff --git a/lib_acl_cpp/samples/cgi_upload/stdafx.h b/lib_acl_cpp/samples/cgi_upload/stdafx.h new file mode 100644 index 000000000..9024458d0 --- /dev/null +++ b/lib_acl_cpp/samples/cgi_upload/stdafx.h @@ -0,0 +1,11 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是常用但不常更改的项目特定的包含文件 +// + +#pragma once + + +//#include +//#include + +// TODO: 在此处引用程序要求的附加头文件 diff --git a/lib_acl_cpp/samples/cgi_upload/upload.html b/lib_acl_cpp/samples/cgi_upload/upload.html new file mode 100644 index 000000000..22069c77e --- /dev/null +++ b/lib_acl_cpp/samples/cgi_upload/upload.html @@ -0,0 +1,18 @@ + + + + + + +
+
+
+文件一:
+文件二:
+文件三:
+

+
+ + diff --git a/lib_acl_cpp/samples/cgi_upload/valgrind.sh b/lib_acl_cpp/samples/cgi_upload/valgrind.sh new file mode 100644 index 000000000..55809f043 --- /dev/null +++ b/lib_acl_cpp/samples/cgi_upload/valgrind.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +#valgrind --tool=memcheck --leak-check=yes --track-origins=yes -v ./upload alone +valgrind --tool=memcheck --leak-check=yes -v ./upload alone diff --git a/lib_acl_cpp/samples/charset/Makefile b/lib_acl_cpp/samples/charset/Makefile new file mode 100644 index 000000000..67c6aff8d --- /dev/null +++ b/lib_acl_cpp/samples/charset/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = charset diff --git a/lib_acl_cpp/samples/charset/big5.txt b/lib_acl_cpp/samples/charset/big5.txt new file mode 100644 index 000000000..d6473c2a9 --- /dev/null +++ b/lib_acl_cpp/samples/charset/big5.txt @@ -0,0 +1 @@ +い瓣 \ No newline at end of file diff --git a/lib_acl_cpp/samples/charset/gb.txt b/lib_acl_cpp/samples/charset/gb.txt new file mode 100644 index 000000000..dc37916ae --- /dev/null +++ b/lib_acl_cpp/samples/charset/gb.txt @@ -0,0 +1,7 @@ +北京艾克赛乐科技有限公司 (www.51iker.com)注册资金一千万元,自2007年1月成立以来,一直致力于通信及互联网行业的技术研发和技术服务。 + +作为一家国家认定的从事增值电信领域及IT服务领域的高新技术企业和双软认证企业,艾克赛乐先后自主研发了基于领先云技术的"任我游"大型企业邮局系统、基于ipv6技术的大型服务器后台网管平台--"斑马线"产品。 系列专业IDC增值服务产品投入市场的很短时间内,迅速得到了广大用户的使用和认可。 + +艾克赛乐的企业发展目标定位为"国内最大的IDC增值服务提供商",和各大基础运营商建立了广泛的战略合作伙伴关系。 一期投资几千万元在北京自主建设了超万平米的超大型数据中心(IDC),先后和中华网、奇虎网、和讯网、北京广播电台、智联招聘、海量科技等等多家大型网站建立了IDC合作和门户运维合作关系。 + +公司拥有雄厚的领先技术研发实力,拥有10年以上大型门户网站工作经验的一流的技术团队和完善的客户服务体系。 经过多年的运营和发展,艾克赛乐人在大型数据中心(IDC)增值服务领域、大型网站运维外包服务领域、互联网应用开发等方面积累了丰富的运营经验。 diff --git a/lib_acl_cpp/samples/charset/gb2.txt b/lib_acl_cpp/samples/charset/gb2.txt new file mode 100644 index 000000000..fe6a2186b --- /dev/null +++ b/lib_acl_cpp/samples/charset/gb2.txt @@ -0,0 +1,9 @@ +  近日,国内互联网再起风波,国内中文百科网站互动百科宣布公司已正式向国家工商总局提交了针对百度的反垄断调查的申请书,请求依法对百度进行立案调查、责令百度立即停止滥用市场支配地位的行为并处以7.9亿元人民币的罚款。就此事件,记者采访了多位法律界人士。在这些法律专业人士看来,互动百科此次对百度发起的“垄断”调查申请,几乎没有获胜可能。 + +  北京市律师协会信息网络法律专业委员会副主任孙彦律师表示,《反垄断法》主要是为了预防和制止垄断行为,《反垄断法》中所称的垄断行为,主要包括“经营者达成垄断协议”、“滥用市场支配地位”,“具有或者可能具有排除及限制竞争效果”等几种情况。此次互动百科指责百度“垄断”,主要应该是想控诉其“滥用市场支配地位”。不过,孙律师明确指出,“占有较高市场份额不等于具有市场支配地位,需要综合其他多种因素共同分析。而且,需要特别强调的是,反垄断法并不禁止经营者具有市场支配地位,而是禁止具有市场支配地位的经营者滥用市场支配地位,从事排除、限制竞争的行为。” + +  另一位不愿透露姓名的法律专家也表示了类似的观点。他指出,根据此前类似案例的经验,目前互动百科显然缺乏有力的事实和证据支持。互动百科几乎没有获胜可能,而对于“这种借助法律途径,意图打压竞争对手的不正当竞争行为,执法和司法层面均已高度警惕。” + +  记者获悉,截止到日前,国家工商总局还未正式受理互动百科针对百度反垄断的申请。而据一位互联网业内人士表示,现在不少互联网公司的纠纷案都是炒作成分占比较大,主要是借机提升知名度,从而通过吸引眼球带来流量。 + +  据了解,互动百科在2009年曾获得DCM 3000万美元风投,但成立六年来一直亏损运营。有关专家认为,通过此种方式“扭亏为盈”的可能性不大。 diff --git a/lib_acl_cpp/samples/charset/main.cpp b/lib_acl_cpp/samples/charset/main.cpp new file mode 100644 index 000000000..9e27d3a4d --- /dev/null +++ b/lib_acl_cpp/samples/charset/main.cpp @@ -0,0 +1,389 @@ +#include +#include "lib_acl.h" +#include "acl_cpp/stdlib/charset_conv.hpp" +#include "acl_cpp/mime/mime_base64.hpp" +#include "acl_cpp/stream/fstream.hpp" +#include "acl_cpp/stream/ifstream.hpp" +#include + +static int test1(void) +{ + const char* s = "中国人民共和国"; + acl::charset_conv conv; + acl::string out, out2, out3; + acl::fstream out_fp; + acl::mime_base64 encoder; + + ///////////////////////////////////////////////////////////////////// + + + if (conv.convert("gb2312", "utf-8", s, strlen(s), &out) == false) + { + printf("convert from gb2312 to utf-8 error\n"); + getchar(); + return (1); + } + printf("ok, gb2312 to utf-8(%d): %s\n\n", (int) out.length(), out.c_str()); + + if (out_fp.open_trunc("gbutf8_1.txt")) + { + out_fp << out.c_str(); + out_fp.close(); + } + + /// + + encoder.encode_update(out.c_str(), out.length(), &out3); + encoder.encode_finish(&out3); + printf("ok, utf-8's base64: %s\n", out3.c_str()); + + if (out_fp.open_trunc("gbutf8.txt")) + { + out_fp << (char) 0xef << (char) 0xbb << (char) 0xbf + << out.c_str() << "\r\n"; + out_fp << out.c_str(); + out_fp.close(); + } + + if (conv.convert("utf-8", "gb2312", out, out.length(), &out2) == false) + { + printf("convert from utf-8 to gb2312 error\n"); + getchar(); + return (1); + } + printf("ok, utf-8 to gb2312: %s\n", out2.c_str()); + + ///////////////////////////////////////////////////////////////////// + + out.clear(); + if (conv.convert("gb2312", "big5", s, strlen(s), &out) == false) + { + printf("convert from gb2312 to big5 error\n"); + getchar(); + return (1); + } + printf("ok, gb2312 to big5: %s\n", out.c_str()); + + out3.clear(); + encoder.encode_update(out.c_str(), out.length(), &out3); + encoder.encode_finish(&out3); + printf("ok, big5's base64: %s\n", out3.c_str()); + + if (out_fp.open_trunc("big5.txt")) + { + out_fp << out.c_str(); + out_fp.close(); + } + + out2.clear(); + if (conv.convert("big5", "gb2312", out, out.length(), &out2) == false) + { + printf("convert from big5 to gb2312 error\n"); + getchar(); + return (1); + } + printf("ok, big5 to gb2312: %s\n", out2.c_str()); + + ///////////////////////////////////////////////////////////////////// + + out.clear(); + if (conv.convert("gb2312", "hz", s, strlen(s), &out) == false) + { + printf("convert from gb2312 to hz error\n"); + getchar(); + return (1); + } + printf("ok, gb2312 to hz: %s, %d, %d\n", out.c_str(), (int) strlen(s), + (int) out.length()); + + out2.clear(); + if (conv.convert("hz", "gb2312", out, out.length(), &out2) == false) + { + printf("convert from hz to gb2312 error\n"); + getchar(); + return (1); + } + printf("ok, hz to gb2312: %s, len: %d\n", out2.c_str(), (int) out2.length()); + + /////////////////////// 流式解析过程测试 /////////////////////// + + ///////////////////////////////////////////////////////////////////// + + out.clear(); + const char* ptr = s; + + if (conv.update_begin("GB2312", "UTF-8") == false) + return (1); + conv.update(ptr, strlen(ptr), &out); + conv.update_finish(&out); + printf(">> from gdb2312 to utf-8: %s\n\n", out.c_str()); + + /* + out2.clear(); + if (conv.update_begin("UNICODE", "UTF-8") == false) + return (1); + conv.update(out.c_str(), out.length(), &out2); + conv.update_finish(&out2); + + printf(">> from gb2312 to utf-8: %s\n", out2.c_str()); + return (0); + */ + + out2.clear(); + out << " hello world!"; + ptr = out.c_str(); + if (conv.update_begin("utf-8", "gb2312") == false) + return (1); + while (*ptr) + { + conv.update(ptr, strlen(ptr), &out2); + break; + ptr++; + } + conv.update_finish(&out2); + printf(">> from utf-8 to gb2312: %s\n", out2.c_str()); + + ///////////////////////////////////////////////////////////////////// + + out.clear(); + ptr = s; + + if (conv.update_begin("GB2312", "BIG5") == false) + return (1); + conv.update(ptr, strlen(ptr), &out); + conv.update_finish(&out); + printf(">> from gdb2312 to big5: %s\n", out.c_str()); + + out2.clear(); + out << " hello world!"; + ptr = out.c_str(); + if (conv.update_begin("BIG5", "GB2312") == false) + return (1); + while (*ptr) + { + conv.update(ptr, strlen(ptr), &out2); + break; + ptr++; + } + conv.update_finish(&out2); + printf(">> from BIG5 to gb2312: %s\n", out2.c_str()); + + ///////////////////////////////////////////////////////////////////// + + getchar(); + return (0); +} + +static int test2(const char* filepath) +{ + acl::string buf1; + + if (acl::ifstream::load(filepath, &buf1) == false) + { + printf("load %s error\n", filepath); + return (-1); + } + + acl::charset_conv conv; + + acl::string buf2; + if (conv.convert("gb18030", "utf-8", buf1.c_str(), + buf1.length(), &buf2) == false) + { + printf("convert from gb18030 to utf-8 error\n"); + return (-1); + } + + acl::string buf3; + if (conv.convert("utf-8", "gb18030", buf2.c_str(), + buf2.length(), &buf3) == false) + { + printf("convert from utf-8 to gb18030 error\n"); + return (-1); + } + + if (buf1 != buf3) + { + printf("convert failed\n"); + assert(0); + return (-1); + } + else + { + printf("convert ok(tid: %u)\n", (unsigned int) acl_pthread_self()); + return (0); + } +} + +static void test3_thread_callback(void* ctx) +{ + const char* filepath = (const char*) ctx; + + test2(filepath); +} + +static int test3(char* filepath, int nthreads, int count) +{ + acl_pthread_pool_t* pool = acl_thread_pool_create(nthreads, 60); + + for (int i = 0; i < count; i++) + acl_pthread_pool_add(pool, test3_thread_callback, filepath); + + printf("Over now, current threads: %d\n", acl_pthread_pool_size(pool)); + acl_pthread_pool_destroy(pool); + return (0); +} + +static void test_unicode(void) +{ + acl::charset_conv conv; + acl::string in, out; + char i8; + short i16; + int i32, k = 0; + bool ret; + + goto TAG; + + i16 = 32; + in.copy((const void*) &i16, 2); + ret = conv.convert("UNICODE", "gb18030", in.c_str(), in.length(), &out); + if (ret == true) + { + if (out.length() == 1) + { + memcpy(&i8, out.c_str(), out.length()); + k = i8; + } + else if (out.length() == 2) + { + memcpy(&i16, out.c_str(), out.length()); + k = i16; + } + else if (out.length() > 2) + { + k = out.length() > sizeof(i32) ? sizeof(i32) : out.length(); + memcpy(&i32, out.c_str(), k); + k = i32; + } + + printf(">>result: %d, len: %d, %c%c\n", k, (int) out.length(), (int) k >> 8, k & 0xff); + } + else + printf("convert error\n"); + + printf("-------------------\n"); + +TAG: + + i16 = 0xc2f3; + i16 = 33296; +#if 0 + i16 = 17320; + i16 = 53558; + i16 = 43681; + ret = conv.convert("gb18030", "UCS-2", (char*) &i16, 2, &out); +#else + i16 = 8211; + i16 = 8212; + i16 = 8801; + ret = conv.convert("UCS-2", "gb18030", (char*) &i16, 2, &out); +#endif + + printf(">>>>8801: %c\n", (unsigned char) 34); + if (ret == true) + { + if (out.length() == 1) + { + memcpy(&i8, out.c_str(), out.length()); + k = i8; + } + else if (out.length() == 2) + { + memcpy(&i16, out.c_str(), out.length()); + k = i16; + } + else if (out.length() > 2) + { + k = out.length() > sizeof(i32) ? sizeof(i32) : out.length(); + memcpy(&i32, out.c_str(), k); + printf(">>>k: %u, %s\n", k, out.c_str()); + k = i32 >> 24 | ((i32 >> 16) & 0xff) << 8 | ((i32 >>8) & 0xff) << 16 | (i32&0xff) << 24; + printf(">>>k2: %u, i32: %u\n", k, i32); + } + + printf(">>result: %u, len: %d, %c%c\n", (unsigned short) k, (int) out.length(), (int) k >> 8, k & 0xff); + } + else + printf("convert error\n"); +} + +static void usage(const char* procname) +{ + printf("usage: %s -h[help] -t test1|test2|test3 -f filepath -c nthreads -n count\n", procname); +} + +int main(int argc, char* argv[]) +{ + int ch, nthreads = 1, count = 10; + char buf[256], filepath[256]; + + if (0) + { + test_unicode(); + return 0; + } + + filepath[0] = 0; + while ((ch = getopt(argc, argv, "ht:f:n:c:")) > 0) + { + switch (ch) + { + case 'h': + usage(argv[0]); + return (0); + case 't': + snprintf(buf, sizeof(buf), "%s", optarg); + break; + case 'f': + snprintf(filepath, sizeof(filepath), "%s", optarg); + break; + case 'n': + count = atoi(optarg); + break; + case 'c': + nthreads = atoi(optarg); + break; + default: + break; + } + } + + if (strcasecmp(buf, "test1") == 0) + return (test1()); + else if (strcasecmp(buf, "test2") == 0) + { + if (filepath[0] == 0) + { + usage(argv[0]); + return (1); + } + return (test2(filepath)); + } + else if (strcasecmp(buf, "test3") == 0) + { + if (filepath[0] == 0) + { + usage(argv[0]); + return (1); + } + if (nthreads <= 0) + nthreads = 1; + if (count <= 10) + count = 10; + return (test3(filepath, nthreads, count)); + } + else + usage(argv[0]); + return (0); +} diff --git a/lib_acl_cpp/samples/charset/valgrind.sh b/lib_acl_cpp/samples/charset/valgrind.sh new file mode 100644 index 000000000..0c3bc446f --- /dev/null +++ b/lib_acl_cpp/samples/charset/valgrind.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +valgrind --tool=memcheck --leak-check=yes -v ./charset -t test2 diff --git a/lib_acl_cpp/samples/db_service/Makefile b/lib_acl_cpp/samples/db_service/Makefile new file mode 100644 index 000000000..2dc33cfca --- /dev/null +++ b/lib_acl_cpp/samples/db_service/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = db_service diff --git a/lib_acl_cpp/samples/db_service/ReadMe.txt b/lib_acl_cpp/samples/db_service/ReadMe.txt new file mode 100644 index 000000000..88ffd34b7 --- /dev/null +++ b/lib_acl_cpp/samples/db_service/ReadMe.txt @@ -0,0 +1,31 @@ +======================================================================== + 控制台应用程序 : db_service 项目概况 +======================================================================== + +应用程序向导已为您创建了这个 db_service 应用程序。 +此文件包含组成 db_service 应用程序 +的每个文件的内容摘要。 + + +db_service.vcproj + 这是用应用程序向导生成的 VC++ 项目的主项目文件。 + 它包含有关生成此文件的 Visual C++ 版本的信息,以及 + 有关用应用程序向导选择的 + 平台、配置和项目功能的信息。 + +db_service.cpp + 这是主应用程序源文件。 + +///////////////////////////////////////////////////////////////////////////// +其他标准文件: + +StdAfx.h、StdAfx.cpp + 这些文件用于生成名为 db_service.pch + 的预编译头(PCH)文件以及名为 StdAfx.obj 的预编译类型文件。 + +///////////////////////////////////////////////////////////////////////////// +其他注释: + +应用程序向导使用 "TODO:" 注释指示应添加或自定义的源代码部分。 + +///////////////////////////////////////////////////////////////////////////// diff --git a/lib_acl_cpp/samples/db_service/db_service.cpp b/lib_acl_cpp/samples/db_service/db_service.cpp new file mode 100644 index 000000000..b8395f9a9 --- /dev/null +++ b/lib_acl_cpp/samples/db_service/db_service.cpp @@ -0,0 +1,152 @@ +// db_service.cpp : 定义控制台应用程序的入口点。 +// + +#include "stdafx.h" +#include +#include "acl_cpp/acl_cpp_init.hpp" +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/stdlib/string.hpp" +#include "acl_cpp/stream/aio_handle.hpp" +#include "acl_cpp/db/db_handle.hpp" +#include "acl_cpp/db/db_sqlite.hpp" +#include "acl_cpp/db/db_service_sqlite.hpp" + +class myquery : public acl::db_query +{ +public: + myquery(int id) : id_(id) + { + + } + + ~myquery() + { + + } + + virtual void on_error(acl::db_status status) + { + printf("%s:%d\r\n", __FUNCTION__, __LINE__); + + (void) status; + printf(">>on error, id: %d\r\n", id_); + } + + virtual void on_ok(const acl::db_rows* rows, int affected) + { + (void) rows; + (void) affected; + printf(">>on ok, id: %d\r\n", id_); + } + + virtual void destroy() + { + delete this; + } +protected: +private: + int id_; +}; + +static acl::string __dbfile("测试.db"); + +const char* CREATE_TBL = +"create table group_tbl\r\n" +"(\r\n" +"group_name varchar(128) not null,\r\n" +"uvip_tbl varchar(32) not null default 'uvip_tbl',\r\n" +"access_tbl varchar(32) not null default 'access_tbl',\r\n" +"access_week_tbl varchar(32) not null default 'access_week_tbl',\r\n" +"access_month_tbl varchar(32) not null default 'access_month_tbl',\r\n" +"update_date date not null default '1970-1-1',\r\n" +"disable integer not null default 0,\r\n" +"add_by_hand integer not null default 0,\r\n" +"class_level integer not null default 0,\r\n" +"primary key(group_name, class_level)\r\n" +")"; + +static bool tbl_create(acl::db_handle& db) +{ + if (db.tbl_exists("group_tbl")) + return (true); + if (db.sql_update(CREATE_TBL) == false) + { + printf("sql error\r\n"); + return (false); + } + else + { + printf("create table ok\r\n"); + return (true); + } +} + +static bool create_db(void) +{ + acl::db_sqlite db(__dbfile); + + if (db.open() == false) + { + printf("open dbfile: %s error\r\n", __dbfile.c_str()); + return (false); + } + db.show_conf(); + return (tbl_create(db)); +} + +int main(void) +{ + acl::acl_cpp_init(); +#ifdef WIN32 + acl::open_dos(); +#endif + + logger_open("dbservice.log", "dbservice", "all:0"); + + if (create_db() == false) + { + getchar(); + return (1); + } + + acl::aio_handle handle; + acl::db_service* server = new acl::db_service_sqlite("DB_TEST", __dbfile, 100, 2); + + // 使消息服务器监听 127.0.0.1 的地址 + if (server->open(&handle) == false) + { + delete server; + std::cout << "open server error!" << std::endl; + getchar(); + return (1); + } + + acl::string sql; + myquery* query; + + for (int i = 0; i < 100; i++) + { + query = new myquery(i); + sql.format("insert into group_tbl('group_name', 'uvip_tbl')" + " values('中国人-%d', 'test')", i); + server->sql_update(sql.c_str(), query); + } + + while (true) + { + if (handle.check() == false) + { + std::cout << "stop now!" << std::endl; + break; + } + } + + delete server; + handle.check(); + + std::cout << "server stopped!" << std::endl; + + getchar(); + return (0); +} + diff --git a/lib_acl_cpp/samples/db_service/db_service.vcproj b/lib_acl_cpp/samples/db_service/db_service.vcproj new file mode 100644 index 000000000..302bf4d6b --- /dev/null +++ b/lib_acl_cpp/samples/db_service/db_service.vcproj @@ -0,0 +1,279 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_acl_cpp/samples/db_service/stdafx.cpp b/lib_acl_cpp/samples/db_service/stdafx.cpp new file mode 100644 index 000000000..5a46ffeb9 --- /dev/null +++ b/lib_acl_cpp/samples/db_service/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// db_service.pch 将成为预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + +// TODO: 在 STDAFX.H 中 +//引用任何所需的附加头文件,而不是在此文件中引用 diff --git a/lib_acl_cpp/samples/db_service/stdafx.h b/lib_acl_cpp/samples/db_service/stdafx.h new file mode 100644 index 000000000..12dfecdeb --- /dev/null +++ b/lib_acl_cpp/samples/db_service/stdafx.h @@ -0,0 +1,7 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是常用但不常更改的项目特定的包含文件 +// + +#pragma once + +// TODO: 在此处引用程序要求的附加头文件 diff --git a/lib_acl_cpp/samples/db_service/valgrind.sh b/lib_acl_cpp/samples/db_service/valgrind.sh new file mode 100644 index 000000000..0649a9047 --- /dev/null +++ b/lib_acl_cpp/samples/db_service/valgrind.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +valgrind --tool=memcheck --leak-check=yes -v ./sqlite_test diff --git a/lib_acl_cpp/samples/dbpool/Makefile b/lib_acl_cpp/samples/dbpool/Makefile new file mode 100644 index 000000000..851213272 --- /dev/null +++ b/lib_acl_cpp/samples/dbpool/Makefile @@ -0,0 +1,103 @@ +SHELL = /bin/sh +CC = gcc +CC = g++ +AR = ar +ARFL = rv +#ARFL = cru +RANLIB = ranlib + +CFLAGS = -c -g -W -Wall -Wcast-qual -Wcast-align \ +-Wno-long-long \ +-Wpointer-arith -Werror -Wshadow -O2 \ +-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO +#-Waggregate-return +########################################################### +#Check system: +# Linux, SunOS, Solaris, BSD variants, AIX, HP-UX +SYSLIB = -lpthread -lcrypt -lz +CHECKSYSRES = @echo "Unknow system type!";exit 1 +UNIXNAME = $(shell uname -sm) + +ifeq ($(CC),) + CC = gcc +endif + +# For FreeBSD +ifeq ($(findstring FreeBSD, $(UNIXNAME)), FreeBSD) + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DFREEBSD -D_REENTRANT + SYSLIB = -lcrypt -lpthread +endif + +#Path for Linux +ifeq ($(findstring Linux, $(UNIXNAME)), Linux) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DLINUX2 -D_REENTRANT +endif + +#Path for SunOS +ifeq ($(findstring SunOS, $(UNIXNAME)), SunOS) + ifeq ($(findstring 86, $(UNIXNAME)), 86) + SYSLIB += -lsocket -lnsl -lrt + endif + ifeq ($(findstring sun4u, $(UNIXNAME)), sun4u) + SYSLIB += -lsocket -lnsl -lrt + endif + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DSUNOS5 -D_REENTRANT +endif + +#Path for HP-UX +ifeq ($(findstring HP-UX, $(UNIXNAME)), HP-UX) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DHP_UX -DHPUX11 + PLAT_NAME=hp-ux +endif + +#Find system type. +ifneq ($(SYSPATH),) + CHECKSYSRES = @echo "System is $(shell uname -sm)" +endif +########################################################### + +CFLAGS += $(INC_COMPILE) + +INC_COMPILE = -I../../include -I../../../lib_acl/include -I../../../include/mysql +LIB_COMPILE = -L../../lib -l_acl_cpp -L/opt/import_lib/lib -l_acl \ + -lmysqlclient_r -ldl + +########################################################### +OUT_PATH = . +OBJ_PATH_DST = $(OUT_PATH) + +#Project's objs +SRC = $(wildcard *.cpp) +OBJ = $(patsubst %.cpp, $(OBJ_PATH_DST)/%.o, $(notdir $(SRC))) +########################################################### + +PROG = dbpool + +.PHONY = all clean +COMPILE = $(CC) $(CFLAGS) + +$(PROG): $(OBJ) + $(CC) $(OBJ) $(LIB_COMPILE) $(SYSLIB) -o $(OBJ_PATH_DST)/$(PROG) + @echo "" + @echo "All ok! Output:$(PROG)" + @echo "" +# fifo +$(OBJ_PATH_DST)/%.o: %.cpp + $(COMPILE) $< -o $@ + +clean: + rm -f $(PROG) + rm -f $(OBJ) + diff --git a/lib_acl_cpp/samples/dbpool/main.cpp b/lib_acl_cpp/samples/dbpool/main.cpp new file mode 100644 index 000000000..c86ac6897 --- /dev/null +++ b/lib_acl_cpp/samples/dbpool/main.cpp @@ -0,0 +1,37 @@ +#include "stdafx.h" + +using namespace acl; + +int main(void) +{ + db_pool *dp = new mysql_pool("127.0.0.1:3306", "test_db", "zsxxsz", + "111111"); + + std::list dbs; + + // 璁剧疆绌洪棽杩炴帴鐨勭敓瀛樺懆鏈 + dp->set_idle(1); + for (int i = 0; i < 10; i++) + { + db_handle* dh = dp->peek(); + dbs.push_back(dh); + } + + std::list::iterator it = dbs.begin(); + for (; it != dbs.end(); ++it) + { + dp->put(*it); + //sleep(1); + } + + dbs.clear(); + + printf("dbpool count: %d\r\n", dp->get_dbcount()); + sleep(2); + db_handle* dh = dp->peek(); + dp->put(dh); + printf("dbpool count: %d\r\n", dp->get_dbcount()); + delete dp; + + return 0; +} diff --git a/lib_acl_cpp/samples/dbpool/stdafx.cpp b/lib_acl_cpp/samples/dbpool/stdafx.cpp new file mode 100644 index 000000000..3f9a6a49e --- /dev/null +++ b/lib_acl_cpp/samples/dbpool/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// mysql.pch 将成为预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + +// TODO: 在 STDAFX.H 中 +//引用任何所需的附加头文件,而不是在此文件中引用 diff --git a/lib_acl_cpp/samples/dbpool/stdafx.h b/lib_acl_cpp/samples/dbpool/stdafx.h new file mode 100644 index 000000000..29692ed5b --- /dev/null +++ b/lib_acl_cpp/samples/dbpool/stdafx.h @@ -0,0 +1,12 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是常用但不常更改的项目特定的包含文件 +// + +#pragma once + + +#include +//#include + +// TODO: 在此处引用程序要求的附加头文件 +#include "acl_cpp/lib_acl.hpp" diff --git a/lib_acl_cpp/samples/dbpool/valgrind.sh b/lib_acl_cpp/samples/dbpool/valgrind.sh new file mode 100644 index 000000000..7572c4b2e --- /dev/null +++ b/lib_acl_cpp/samples/dbpool/valgrind.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +valgrind --tool=memcheck --leak-check=yes -v ./dbpool diff --git a/lib_acl_cpp/samples/final_class/Makefile b/lib_acl_cpp/samples/final_class/Makefile new file mode 100644 index 000000000..984c76121 --- /dev/null +++ b/lib_acl_cpp/samples/final_class/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = final_class diff --git a/lib_acl_cpp/samples/final_class/final_class.cpp b/lib_acl_cpp/samples/final_class/final_class.cpp new file mode 100644 index 000000000..780905d0b --- /dev/null +++ b/lib_acl_cpp/samples/final_class/final_class.cpp @@ -0,0 +1,40 @@ +// final_class.cpp : 定义控制台应用程序的入口点。 +// + +#include "stdafx.h" +#include +#include "acl_cpp/stdlib/final_tpl.hpp" +//#include "lib_acl.hpp" + +class CMyFinalClass : public acl::final_tpl +{ +public: + CMyFinalClass(int n) : dummy_(n) {} + ~CMyFinalClass() {} + + void Test() + { + printf("hello, I'm the final class\n"); + } +protected: +private: + int dummy_; +}; + +class CMyClass //: CMyFinalClass +{ +public: + CMyClass() {} + ~CMyClass() {} +}; + +int main(void) +{ + CMyFinalClass m(1); + m.Test(); + + printf(">>enter any key to exit ...\n"); + getchar(); + return 0; +} + diff --git a/lib_acl_cpp/samples/final_class/final_class.vcproj b/lib_acl_cpp/samples/final_class/final_class.vcproj new file mode 100644 index 000000000..8a949f512 --- /dev/null +++ b/lib_acl_cpp/samples/final_class/final_class.vcproj @@ -0,0 +1,263 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_acl_cpp/samples/final_class/final_class.vcxproj b/lib_acl_cpp/samples/final_class/final_class.vcxproj new file mode 100644 index 000000000..0cf4c71de --- /dev/null +++ b/lib_acl_cpp/samples/final_class/final_class.vcxproj @@ -0,0 +1,179 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + ReleaseDll + Win32 + + + Release + Win32 + + + + {840C2263-DF87-4FD2-8964-EF81B74695FE} + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;VC2003;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Use + Level3 + ProgramDatabase + + + $(OutDir)final_class.exe + true + $(OutDir)final_class.pdb + Console + MachineX86 + + + + + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;VC2003;%(PreprocessorDefinitions) + MultiThreaded + Use + Level3 + ProgramDatabase + + + $(OutDir)final_class.exe + true + Console + true + true + MachineX86 + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;VC2003;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Use + Level3 + ProgramDatabase + + + $(OutDir)final_class.exe + true + $(OutDir)final_class.pdb + Console + MachineX86 + + + + + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;VC2003;%(PreprocessorDefinitions) + MultiThreadedDLL + Use + Level3 + ProgramDatabase + + + $(OutDir)final_class.exe + true + Console + true + true + MachineX86 + + + + + + Create + Create + Create + Create + + + + + + + + + + + + \ No newline at end of file diff --git a/lib_acl_cpp/samples/final_class/final_class.vcxproj.filters b/lib_acl_cpp/samples/final_class/final_class.vcxproj.filters new file mode 100644 index 000000000..707efba88 --- /dev/null +++ b/lib_acl_cpp/samples/final_class/final_class.vcxproj.filters @@ -0,0 +1,33 @@ +锘 + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx + + + + + 婧愭枃浠 + + + 婧愭枃浠 + + + + + 澶存枃浠 + + + + + + \ No newline at end of file diff --git a/lib_acl_cpp/samples/final_class/final_class_vc2012.vcxproj b/lib_acl_cpp/samples/final_class/final_class_vc2012.vcxproj new file mode 100644 index 000000000..5bc9949d2 --- /dev/null +++ b/lib_acl_cpp/samples/final_class/final_class_vc2012.vcxproj @@ -0,0 +1,184 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + ReleaseDll + Win32 + + + Release + Win32 + + + + {840C2263-DF87-4FD2-8964-EF81B74695FE} + Win32Proj + final_class + + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Use + Level3 + ProgramDatabase + + + $(OutDir)final_class.exe + true + $(OutDir)final_class.pdb + Console + MachineX86 + + + + + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + Use + Level3 + ProgramDatabase + + + $(OutDir)final_class.exe + true + Console + true + true + MachineX86 + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Use + Level3 + ProgramDatabase + + + $(OutDir)final_class.exe + true + $(OutDir)final_class.pdb + Console + MachineX86 + + + + + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDLL + Use + Level3 + ProgramDatabase + + + $(OutDir)final_class.exe + true + Console + true + true + MachineX86 + + + + + + Create + Create + Create + Create + + + + + + + + + + + + \ No newline at end of file diff --git a/lib_acl_cpp/samples/final_class/stdafx.cpp b/lib_acl_cpp/samples/final_class/stdafx.cpp new file mode 100644 index 000000000..0c522faac --- /dev/null +++ b/lib_acl_cpp/samples/final_class/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// final_class.pch 将成为预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + +// TODO: 在 STDAFX.H 中 +//引用任何所需的附加头文件,而不是在此文件中引用 diff --git a/lib_acl_cpp/samples/final_class/stdafx.h b/lib_acl_cpp/samples/final_class/stdafx.h new file mode 100644 index 000000000..5d66dc1cf --- /dev/null +++ b/lib_acl_cpp/samples/final_class/stdafx.h @@ -0,0 +1,10 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是常用但不常更改的项目特定的包含文件 +// + +#pragma once + + +#include + +// TODO: 在此处引用程序要求的附加头文件 diff --git a/lib_acl_cpp/samples/flock/flock.vcproj b/lib_acl_cpp/samples/flock/flock.vcproj new file mode 100644 index 000000000..06e7a77cc --- /dev/null +++ b/lib_acl_cpp/samples/flock/flock.vcproj @@ -0,0 +1,240 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_acl_cpp/samples/flock/flock.vcxproj b/lib_acl_cpp/samples/flock/flock.vcxproj new file mode 100644 index 000000000..573f3e4a1 --- /dev/null +++ b/lib_acl_cpp/samples/flock/flock.vcxproj @@ -0,0 +1,189 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + Releasedll + Win32 + + + Release + Win32 + + + + {5F4063AD-B591-4C64-ADEA-609968A83550} + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + true + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + ws2_32.lib;lib_acl_vc2010d.lib;lib_acl_cpp_vc2010d.lib;%(AdditionalDependencies) + $(OutDir)flock.exe + ..\..\..\lib\win32;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)flock.pdb + Console + MachineX86 + + + + + + + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;lib_acl_vc2010.lib;lib_acl_cpp_vc2010.lib;%(AdditionalDependencies) + $(OutDir)flock.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + ws2_32.lib;lib_acl_d.lib;lib_acl_cpp_d.lib;%(AdditionalDependencies) + $(OutDir)flock.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)flock.pdb + Console + MachineX86 + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + lib_acl.lib;lib_acl_cpp.lib;ws2_32.lib;%(AdditionalDependencies) + $(OutDir)flock.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)flock.pdb + Console + MachineX86 + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib_acl_cpp/samples/flock/flock_vc2012.vcxproj b/lib_acl_cpp/samples/flock/flock_vc2012.vcxproj new file mode 100644 index 000000000..c28bce93b --- /dev/null +++ b/lib_acl_cpp/samples/flock/flock_vc2012.vcxproj @@ -0,0 +1,194 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + Releasedll + Win32 + + + Release + Win32 + + + + {5F4063AD-B591-4C64-ADEA-609968A83550} + Win32Proj + flock + + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + true + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + ws2_32.lib;lib_acl_vc2012d.lib;lib_acl_cpp_vc2012d.lib;%(AdditionalDependencies) + $(OutDir)flock.exe + ..\..\..\lib\win32;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)flock.pdb + Console + MachineX86 + + + + + + + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;lib_acl_vc2012.lib;lib_acl_cpp_vc2012.lib;%(AdditionalDependencies) + $(OutDir)flock.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + ws2_32.lib;lib_acl_d.lib;lib_acl_cpp_d.lib;%(AdditionalDependencies) + $(OutDir)flock.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)flock.pdb + Console + MachineX86 + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + lib_acl.lib;lib_acl_cpp.lib;ws2_32.lib;%(AdditionalDependencies) + $(OutDir)flock.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)flock.pdb + Console + MachineX86 + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib_acl_cpp/samples/flock/main.cpp b/lib_acl_cpp/samples/flock/main.cpp new file mode 100644 index 000000000..c6904a15f --- /dev/null +++ b/lib_acl_cpp/samples/flock/main.cpp @@ -0,0 +1,33 @@ +#include "acl_cpp/stdlib/locker.hpp" +#include "acl_cpp/stream/fstream.hpp" +#include +#include + +int main(void) +{ + acl::fstream fp; + + if (fp.open("test.lock", O_RDWR, 0600) == false) { + printf("open file error\n"); + getchar(); + return (1); + } + + acl::locker locker; + + if (locker.open(fp.file_handle()) == false) { + printf("open lock error\n"); + getchar(); + return (1); + } + if (locker.lock() == true) { + printf("lock ok\n"); + } else { + printf("lock error\n"); + } + + printf("enter any key to exit\n"); + getchar(); + return (0); +} + diff --git a/lib_acl_cpp/samples/fs_benchmark/Makefile b/lib_acl_cpp/samples/fs_benchmark/Makefile new file mode 100644 index 000000000..1455d81b1 --- /dev/null +++ b/lib_acl_cpp/samples/fs_benchmark/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = fs_benchmark diff --git a/lib_acl_cpp/samples/fs_benchmark/ReadMe.txt b/lib_acl_cpp/samples/fs_benchmark/ReadMe.txt new file mode 100644 index 000000000..cdcd3b3b6 --- /dev/null +++ b/lib_acl_cpp/samples/fs_benchmark/ReadMe.txt @@ -0,0 +1,31 @@ +======================================================================== + 控制台应用程序 : fs_benchmark 项目概况 +======================================================================== + +应用程序向导已为您创建了这个 fs_benchmark 应用程序。 +此文件包含组成 fs_benchmark 应用程序 +的每个文件的内容摘要。 + + +fs_benchmark.vcproj + 这是用应用程序向导生成的 VC++ 项目的主项目文件。 + 它包含有关生成此文件的 Visual C++ 版本的信息,以及 + 有关用应用程序向导选择的 + 平台、配置和项目功能的信息。 + +fs_benchmark.cpp + 这是主应用程序源文件。 + +///////////////////////////////////////////////////////////////////////////// +其他标准文件: + +StdAfx.h、StdAfx.cpp + 这些文件用于生成名为 fs_benchmark.pch + 的预编译头(PCH)文件以及名为 StdAfx.obj 的预编译类型文件。 + +///////////////////////////////////////////////////////////////////////////// +其他注释: + +应用程序向导使用 "TODO:" 注释指示应添加或自定义的源代码部分。 + +///////////////////////////////////////////////////////////////////////////// diff --git a/lib_acl_cpp/samples/fs_benchmark/fs_benchmark.cpp b/lib_acl_cpp/samples/fs_benchmark/fs_benchmark.cpp new file mode 100644 index 000000000..2cc0e7d04 --- /dev/null +++ b/lib_acl_cpp/samples/fs_benchmark/fs_benchmark.cpp @@ -0,0 +1,247 @@ +// fs_benchmark.cpp : 定义控制台应用程序的入口点。 +// + +#include "stdafx.h" +#include + +static int __nfiles = 10, __length = 102400, __parallel = 100; +static char __path[256]; +static char __data[1024]; +static bool __kernel_event = false; + +static __thread int __nok = 0; + +////////////////////////////////////////////////////////////////////////// + +class async_file : public acl::aio_callback +{ +public: + async_file(acl::aio_handle* handle, const char* path, int ibegin) + : handle_(handle) + , path_(path) + , nfiles_(__nfiles) + , ifile_(0) + , ibegin_(ibegin) + , nwrite_(0) + , delay_(1) + , fp_(NULL) + { + + } + ~async_file() + { + + } + + // 只写方式创建文件 + bool open_write() + { + fp_ = new acl::aio_fstream(handle_); + filepath_.format("%s/%lu_%d_%d", path_.c_str(), + (unsigned long) acl_pthread_self(), ibegin_, ifile_++); + if (fp_->open_write(filepath_.c_str()) == false) + { + printf("open file %s error: %s\r\n", + filepath_.c_str(), acl::last_serror()); + return false; + } + + // 添加写成功的回调函数 + fp_->add_write_callback(this); + + // 添加关闭的回调函数 + fp_->add_close_callback(this); + + // 1 秒后启动写过程 + fp_->write(__data, sizeof(__data), delay_ * 1000000); + return true; + } +protected: + bool read_callback(char*, int) + { + return true; + } + + bool write_callback() + { + nwrite_ += sizeof(__data); + + if (nwrite_ >= __length) + { + printf("write one file(%s) ok, nwrite: %d\r\n", + filepath_.c_str(), nwrite_); + + return false; // 返回 false 以使框架关闭该流对象 + } + fp_->write(__data, sizeof(__data)); + return true; + } + + void close_callback() + { + // 必须在此处删除该动态分配的回调类对象以防止内存泄露 + if (ifile_ >= nfiles_) + { + printf("write %s over!, ifile: %d, nfiles: %d\r\n", + filepath_.c_str(), ifile_, nfiles_); + delete this; + __nok++; + } + else + { + //printf("ifile_: %d, nfiles_: %d\r\n", ifile_, nfiles_); + nwrite_ = 0; + delay_ = 0; + + // 重新打开一个新的异步流句柄 + if (open_write() == false) + { + printf("open file error\r\n"); + exit (1); + } + } + } + + bool timeout_callback() + { + return (true); + } +private: + acl::aio_handle* handle_; + acl::string path_; + acl::string filepath_; + int nfiles_; + int ifile_; + int ibegin_; + int nwrite_; + int delay_; + acl::aio_fstream* fp_; +}; + +static void thread_main(void*) +{ + printf("%s: thread: %ld\r\n", __FUNCTION__, + (unsigned long) acl_pthread_self()); + acl::aio_handle* handle; + + // 每个线程创建单独的异步事件句柄 + handle = new acl::aio_handle(__kernel_event ? + acl::ENGINE_KERNEL : acl::ENGINE_SELECT); + + int i; + for (i = 0; i < __parallel; i++) + { + async_file* fp = new async_file(handle, __path, i); + if (fp->open_write() == false) + { + printf("open file error: %s\r\n", acl::last_serror()); + delete fp; + break; + } + } + + if (i == 0) + { + printf("thread(%lu) no file opened!\r\n", (unsigned long) + acl_pthread_self()); + delete handle; + return; + } + + // 进入异步事件循环过程 + while (true) + { + if (handle->check() == false) + break; + if (__nok == __parallel) + { + printf("%s: thread(%lu) over, total: %d\r\n", __FUNCTION__, + (unsigned long) acl_pthread_self(), __nok); + break; + } + } + + // 因为 IO 句柄是延迟释放的,所以需要再次检查一遍 + handle->check(); + + // 销毁异步事件句柄 + delete handle; +} + +static void usage(const char* proc) +{ + printf("usage: %s -h[help]\r\n" + " -n thread_count\r\n" + " -P parallel [#writer object]\r\n" + " -c file_count per writer object\r\n" + " -l file_length\r\n" + " -k [use kernel event, default: false]\r\n" + " -p path [default: var/]\r\n", proc); +} + +int main(int argc, char* argv[]) +{ +#ifdef WIN32 + acl::acl_cpp_init(); +#endif + logger_open("fs_benchmark.log", "fs_benchmark"); + + int ch; + int nthreads = 2; + + snprintf(__path, sizeof(__path), "var/%d", (int) getpid()); + while ((ch = getopt(argc, argv, "hn:c:l:kp:P:")) > 0) + { + switch (ch) + { + case 'h': + usage(argv[0]); + return 0; + case 'n': + nthreads = atoi(optarg); + break; + case 'c': + __nfiles = atoi(optarg); + break; + case 'l': + __length = atoi(optarg); + break; + case 'k': + __kernel_event = true; + break; + case 'p': + snprintf(__path, sizeof(__path), "%s/%d", optarg, (int) getpid()); + break; + case 'P': + __parallel = atoi(optarg); + if (__parallel <= 0) + __parallel = 1; + break; + default: + break; + } + } + + for (size_t i = 0; i < sizeof(__data); i++) + { + __data[i] = 'X'; + } + + acl_make_dirs(__path, 0700); + + // 创建线程池句柄 + acl_pthread_pool_t* tp = acl_thread_pool_create(nthreads, 0); + + // 添加线程处理任务 + for (int i = 0; i < nthreads; i++) + acl_pthread_pool_add(tp, thread_main, NULL); + + // 销毁线程池 + acl_pthread_pool_destroy(tp); + +#ifdef WIN32 + printf("enter any key to exit\r\n"); + getchar(); +#endif + return 0; +} diff --git a/lib_acl_cpp/samples/fs_benchmark/fs_benchmark.vcproj b/lib_acl_cpp/samples/fs_benchmark/fs_benchmark.vcproj new file mode 100644 index 000000000..83078a2c8 --- /dev/null +++ b/lib_acl_cpp/samples/fs_benchmark/fs_benchmark.vcproj @@ -0,0 +1,263 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_acl_cpp/samples/fs_benchmark/stdafx.cpp b/lib_acl_cpp/samples/fs_benchmark/stdafx.cpp new file mode 100644 index 000000000..a0bd31a4f --- /dev/null +++ b/lib_acl_cpp/samples/fs_benchmark/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// fs_benchmark.pch 将成为预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + +// TODO: 在 STDAFX.H 中 +//引用任何所需的附加头文件,而不是在此文件中引用 diff --git a/lib_acl_cpp/samples/fs_benchmark/stdafx.h b/lib_acl_cpp/samples/fs_benchmark/stdafx.h new file mode 100644 index 000000000..852808e33 --- /dev/null +++ b/lib_acl_cpp/samples/fs_benchmark/stdafx.h @@ -0,0 +1,14 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是常用但不常更改的项目特定的包含文件 +// + +#pragma once + +// TODO: 在此处引用程序要求的附加头文件 +#include "lib_acl.h" +#include "acl_cpp/lib_acl.hpp" + +#ifdef WIN32 +#include +#define snprintf _snprintf +#endif diff --git a/lib_acl_cpp/samples/fstream/Makefile b/lib_acl_cpp/samples/fstream/Makefile new file mode 100644 index 000000000..677bfa1c1 --- /dev/null +++ b/lib_acl_cpp/samples/fstream/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = fstream diff --git a/lib_acl_cpp/samples/fstream/fstream.vcproj b/lib_acl_cpp/samples/fstream/fstream.vcproj new file mode 100644 index 000000000..96f58239d --- /dev/null +++ b/lib_acl_cpp/samples/fstream/fstream.vcproj @@ -0,0 +1,240 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_acl_cpp/samples/fstream/fstream.vcxproj b/lib_acl_cpp/samples/fstream/fstream.vcxproj new file mode 100644 index 000000000..c430c322e --- /dev/null +++ b/lib_acl_cpp/samples/fstream/fstream.vcxproj @@ -0,0 +1,189 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + Releasedll + Win32 + + + Release + Win32 + + + + {7680672C-4C9B-4BE8-8BAE-BB23B951AAA0} + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + true + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + ws2_32.lib;lib_acl_vc2010d.lib;lib_acl_cpp_vc2010d.lib;%(AdditionalDependencies) + $(OutDir)fstream.exe + ..\..\..\lib\win32;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)fstream.pdb + Console + MachineX86 + + + + + + + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;lib_acl_vc2010.lib;lib_acl_cpp_vc2010.lib;%(AdditionalDependencies) + $(OutDir)fstream.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + + + + + + + Disabled + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + lib_acl_d.lib;lib_acl_cpp_d.lib;ws2_32.lib;%(AdditionalDependencies) + $(OutDir)fstream.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)fstream.pdb + Console + MachineX86 + + + + + Disabled + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + lib_acl.lib;lib_acl_cpp.lib;ws2_32.lib;%(AdditionalDependencies) + $(OutDir)fstream.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)fstream.pdb + Console + MachineX86 + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib_acl_cpp/samples/fstream/fstream_vc2012.vcxproj b/lib_acl_cpp/samples/fstream/fstream_vc2012.vcxproj new file mode 100644 index 000000000..e864d9b17 --- /dev/null +++ b/lib_acl_cpp/samples/fstream/fstream_vc2012.vcxproj @@ -0,0 +1,194 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + Releasedll + Win32 + + + Release + Win32 + + + + {7680672C-4C9B-4BE8-8BAE-BB23B951AAA0} + Win32Proj + fstream + + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + true + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + ws2_32.lib;lib_acl_vc2012d.lib;lib_acl_cpp_vc2012d.lib;%(AdditionalDependencies) + $(OutDir)fstream.exe + ..\..\..\lib\win32;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)fstream.pdb + Console + MachineX86 + + + + + + + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;lib_acl_vc2012.lib;lib_acl_cpp_vc2012.lib;%(AdditionalDependencies) + $(OutDir)fstream.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + + + + + + + Disabled + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + lib_acl_d.lib;lib_acl_cpp_d.lib;ws2_32.lib;%(AdditionalDependencies) + $(OutDir)fstream.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)fstream.pdb + Console + MachineX86 + + + + + Disabled + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + lib_acl.lib;lib_acl_cpp.lib;ws2_32.lib;%(AdditionalDependencies) + $(OutDir)fstream.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)fstream.pdb + Console + MachineX86 + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib_acl_cpp/samples/fstream/main.cpp b/lib_acl_cpp/samples/fstream/main.cpp new file mode 100644 index 000000000..6f44a070b --- /dev/null +++ b/lib_acl_cpp/samples/fstream/main.cpp @@ -0,0 +1,60 @@ +#include "lib_acl.h" +#include "acl_cpp/stream/ifstream.hpp" +#include "acl_cpp/stdlib/locker.hpp" +#include +#include + +static void test_stdio(void) +{ + acl::string buf; + acl::ifstream in; + in.open(0, O_RDONLY); + + if (in.gets(buf)) + printf(">>>>ok, gets: %s\n", buf.c_str()); + else + printf(">>>gets error, %s\n", acl_last_serror()); +} + +int main(void) +{ + test_stdio(); + + acl::string path("test.eml"); + + acl::ifstream fp; + + if (fp.open_read(path) == false) { + //if (fp.open(path.c_str(), O_RDWR, 0600) == false) { + printf("open %s error(%s)\n", path.c_str(), acl_last_serror()); + getchar(); + return (-1); + } + + acl::locker locker; + if (locker.open(fp.file_handle()) == false) { + printf("open %s's lock error\n", path.c_str()); + getchar(); + return (-1); + } + if (locker.lock() == true) + printf("first lock %s ok\n", path.c_str()); + else + printf("first lock %s error(%s)\n", path.c_str(), acl_last_serror()); + if (locker.lock() == true) + printf("second lock %s ok\n", path.c_str()); + else + printf("second lock %s error(%s)\n", path.c_str(), acl_last_serror()); + + acl::string buf; + while (1) { + if (fp.gets(buf, false) == false) + break; + printf("%s", buf.c_str()); + } + + getchar(); + fp.close(); + + return (0); +} diff --git a/lib_acl_cpp/samples/fstream/test.eml b/lib_acl_cpp/samples/fstream/test.eml new file mode 100644 index 000000000..dd8b9d6d6 --- /dev/null +++ b/lib_acl_cpp/samples/fstream/test.eml @@ -0,0 +1,524 @@ +X-Uidl: 1285394662.10985_3.localhost&&mail.51iker.com +Return-Path: +Delivered-To: zhengshuxin@51iker.com +Received: by 51iker.com (zebra mail for UNIX, from userid 500) + id 769B2274687; Sat, 25 Sep 2010 14:04:22 +0800 (CST) +Date: Sat, 25 Sep 2010 06:04:22 GMT +From: 郑树新 +To: "zhengshuxin" +Subject: ddd +Mime-version: 1.0 +Content-Type: multipart/mixed; charset="GB2312"; boundary="=_0_10978_1285394661" +Message-Id: <20100925060422.769B2274687@51iker.com> + +This is a multi-part message in MIME format. + +--=_0_10978_1285394661 +Content-Type: text/html; charset="GB2312" +Content-Transfer-Encoding: base64 + +ZGRkZA== + + +--=_0_10978_1285394661 +Content-Type: application/octet-stream; + name="=?GB2312?B?uavKvS54bHN4?=" +Content-Disposition: attachment; + filename="=?GB2312?B?uavKvS54bHN4?=" +Content-Transfer-Encoding: base64 + +UEsDBBQABgAIAAAAIQA5GAaU8gEAAGgLAAATANQBW0NvbnRlbnRfVHlwZXNdLnhtbCCi0AEooAAC +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAMRWXW/aMBR9n7T/EPl1IoZ2m6aJ0Ae2Pm6V2v0A174QC8e2fN0W/v1uAkQlomHgaH0hfPmc ++3HO9Z3erCuTPUNA7WzBJvmYZWClU9ouC/bn4Xb0jWUYhVXCOAsF2wCym9nHD9OHjQfM6LTFgpUx ++u+coyyhEpg7D5Z+WbhQiUgfw5J7IVdiCfxqPP7KpbMRbBzFGoPNpj9gIZ5MzH6u6ettJI/asmy+ +/V9NVTDhvdFSRAqUP1vVIRm5xUJLUE4+VQSdow8gFJYAsTK5D5oYwz3ESIkh47Ppb0o6aAXZnQjx +l6iIga8Nj5QBbF8nOeWQFEQD9qlGeZsQ48YAJlMd5rsFPcEsS8ocefP4nByACuKFakvFbgDP4P7y +jtxX78h9/Z+5dx1CvnszWM/3vT5i4wAGz7PQblDkdLLxOpbaYw9Dv0f7vffiwurRuVVyIzruq6dO +Xglt93G/MWxq/mZEIW8e6R05DKTFPxHH60mQPvXOmwRdVQ7myBM5d3kHc2MfL11Pd8F55HSZJYsO +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 +NDi7Tm9y9oRpl7fnSGPanN02SmSh9MzZ9bVIh7fnSZh3eTud2Hu8vUTofc6eh+la+Uf6acD/2CLv +74a83Sb0EW+nJ23M2+n8NuHtDmn7lLfTJdqMszuGQ0bQnLPr89kLb6cL+QVvp5fikrPrix7X5f02 +WWi5GIxyrkm5o0944f6MhNuuOKdg0cEHOO65wD0Tpx3sUwn2a9hjsfWPQbh/I9wo8esEm1eOftU/ +xptdwju60+rV667Or/vjJXWALSDwetgowDtj3JARfYbNIZEKd3Lf/SDw365/7WAriwfbMLIGvF3Y ++n5w/QO4m/PqAzbQpM73ezj8ubWJ3pdkxJaZ8j8AAAD//wMAUEsDBBQABgAIAAAAIQA5MbWR2wAA +ANABAAAjAAAAeGwvd29ya3NoZWV0cy9fcmVscy9zaGVldDEueG1sLnJlbHOskc1qwzAMgO+DvoPR +vXbSwxijTi9j0OvaPYBnK4lZIhtLW9e3n3coLKWwy276QZ8+oe3ua57UJxaOiSy0ugGF5FOINFh4 +PT6vH0CxOApuSoQWzsiw61Z32xecnNQhHmNmVSnEFkaR/GgM+xFnxzplpNrpU5md1LQMJjv/7gY0 +m6a5N+U3A7oFU+2DhbIPG1DHc66b/2anvo8en5L/mJHkxgoTijvVyyrSlQHFgtaXGl+CVldlMLdt +2v+0ySWSYDmgSJXihdVVz1zlrX6L9CNpFn/ovgEAAP//AwBQSwMEFAAGAAgAAAAhAJuFhlxAAwAA +FAkAABgAAAB4bC93b3Jrc2hlZXRzL3NoZWV0Mi54bWyMVtty2yAQfe9M/4HhvbpatuOx3antOHGu +naaXZyohi6kkVCBx2q/vAooj4YymerClc3YPy8KyzD8+VyV6okIyXi9w6AUY0TrlGav3C/zt6/bD +FCOpSJ2Rktd0gf9QiT8u37+bH7j4JQtKFQKFWi5woVQz832ZFrQi0uMNrYHJuaiIgk+x92UjKMmM +U1X6URCM/YqwGluFmfgfDZ7nLKUbnj5WtFZWRNCSKIhfFqyReDnPGHB6QkjQfIE/hbP7GPvLuRn5 +O6MH2XlHeiI/Of+liV22wAEoSFrSVEsiAn9PdE3LEoRGkIvfVnOkBf2jYvf9RX1rpv5ZoIzm5LFU +X/jhkrJ9oSDPsZdogZSXYA2/qGI6/RhV5Nn8H1imCngD6CeVasu0F0bpo1S8+tGSJgarYSLZEEWW +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 +PYBnK4lZIhtLW9e3n3coLKWwy276QZ8+oe3ua57UJxaOiSxsdAMKyacQabDwenxeP4BicRTclAgt +nJFh163uti84OalDPMbMqlKILYwi+dEY9iPOjnXKSLXTpzI7qWkZTHb+3Q1o2qa5N+U3A7oFU+2D +hbIPLajjOdfNf7NT30ePT8l/zEhyY4UJxZ3qZRXpyoBiQetLjS9Bq6symNs2m/+0ySWSYDmgSJXi +hdVVz1zlrX6L9CNpFn/ovgEAAP//AwBQSwMEFAAGAAgAAAAhACbt6oe7AAAAJQEAACMAAAB4bC9k +cmF3aW5ncy9fcmVscy9kcmF3aW5nMi54bWwucmVsc4SPzQrCMBCE74LvEPZu0vYgIk16EaFX0QdY +0u0PtknIRtG3N+BFQfA07A77zU7dPJZZ3Cny5J2GUhYgyFnfTW7QcDkfNzsQnNB1OHtHGp7E0Jj1 +qj7RjCkf8TgFFpniWMOYUtgrxXakBVn6QC47vY8LpjzGQQW0VxxIVUWxVfGTAeaLKdpOQ2y7EsT5 +GXLyf7bv+8nSwdvbQi79iFB2xJgyEONASYOU7w2/pZL5WVCmVl/lzAsAAP//AwBQSwMEFAAGAAgA +AAAhAJqjvBLEAAAArQEAACMAAAB4bC9kcmF3aW5ncy9fcmVscy9kcmF3aW5nNC54bWwucmVsc7yQ +zwrCMAyH74LvUHK3nUNFZJ0XEXYVfYDQZX9wa0tTRd/egggKgjdPIQn5fh8ptrdxEFcK3DurYS4z +EGSNq3vbajgd97M1CI5oaxycJQ13YtiW00lxoAFjOuKu9ywSxbKGLka/UYpNRyOydJ5s2jQujBhT +G1rl0ZyxJZVn2UqFdwaUH0xR1RpCVecgjnefkn+zXdP0hnbOXEay8UuEMh2GmIAYWooapHxO+FmW +MsmC+u4x/5/H4uWhPp5cPgAAAP//AwBQSwMEFAAGAAgAAAAhAG1UidS9AAAAKwEAACMAAAB4bC93 +b3Jrc2hlZXRzL19yZWxzL3NoZWV0NC54bWwucmVsc4SPzQoCMQyE74LvUHK3XUVEZLteRPAq6wOE +NvuDu21p6t/b28uCguAtk5BvZsr9cxzEnSL33mlYygIEOeNt71oNl/q42ILghM7i4B1peBHDvprP +yjMNmPITd31gkSmONXQphZ1SbDoakaUP5PKl8XHElGVsVUBzxZbUqig2Kn4yoPpiipPVEE92CaJ+ +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 +idS9AAAAKwEAACMAAAAAAAAAAAAAAAAA0yIAAHhsL3dvcmtzaGVldHMvX3JlbHMvc2hlZXQ0Lnht +bC5yZWxzUEsBAi0AFAAGAAgAAAAhAAGIzwa7AAAAJQEAACMAAAAAAAAAAAAAAAAA0SMAAHhsL2Ry +YXdpbmdzL19yZWxzL2RyYXdpbmczLnhtbC5yZWxzUEsBAi0AFAAGAAgAAAAhAPxK3HvbAAAA0AEA +ACMAAAAAAAAAAAAAAAAAzSQAAHhsL3dvcmtzaGVldHMvX3JlbHMvc2hlZXQzLnhtbC5yZWxzUEsB +Ai0AFAAGAAgAAAAhAOj21sh4BAAA9hIAABQAAAAAAAAAAAAAAAAA6SUAAHhsL2NoYXJ0cy9jaGFy +dDQueG1sUEsBAi0AFAAGAAgAAAAhAPPCoGj4AQAADwcAABgAAAAAAAAAAAAAAAAAkyoAAHhsL2Ry +YXdpbmdzL2RyYXdpbmc0LnhtbFBLAQItABQABgAIAAAAIQAF59nzJwMAAEkJAAAUAAAAAAAAAAAA +AAAAAMEsAAB4bC9jaGFydHMvY2hhcnQzLnhtbFBLAQItABQABgAIAAAAIQDVNnv0pgEAAPQDAAAY +AAAAAAAAAAAAAAAAABowAAB4bC9kcmF3aW5ncy9kcmF3aW5nMS54bWxQSwECLQAUAAYACAAAACEA +wDrW1kwBAABCBQAAFAAAAAAAAAAAAAAAAAD2MQAAeGwvc2hhcmVkU3RyaW5ncy54bWxQSwECLQAU +AAYACAAAACEAHZr55ukCAADTCgAADQAAAAAAAAAAAAAAAAB0MwAAeGwvc3R5bGVzLnhtbFBLAQIt +ABQABgAIAAAAIQDQVdxPiQYAAFQbAAATAAAAAAAAAAAAAAAAAIg2AAB4bC90aGVtZS90aGVtZTEu +eG1sUEsBAi0AFAAGAAgAAAAhADORuEqrBgAA7RwAABQAAAAAAAAAAAAAAAAAQj0AAHhsL2NoYXJ0 +cy9jaGFydDEueG1sUEsBAi0AFAAGAAgAAAAhAGPRM+y9DAAAh0AAABgAAAAAAAAAAAAAAAAAH0QA +AHhsL3dvcmtzaGVldHMvc2hlZXQxLnhtbFBLAQItABQABgAIAAAAIQBw6dAmsQEAAPQDAAAYAAAA +AAAAAAAAAAAAABJRAAB4bC9kcmF3aW5ncy9kcmF3aW5nMi54bWxQSwECLQAUAAYACAAAACEAcMXK +XFUDAABkCgAAFAAAAAAAAAAAAAAAAAD5UgAAeGwvY2hhcnRzL2NoYXJ0Mi54bWxQSwECLQAUAAYA +CAAAACEAJ25LzrIBAAD1AwAAGAAAAAAAAAAAAAAAAACAVgAAeGwvZHJhd2luZ3MvZHJhd2luZzMu +eG1sUEsBAi0AFAAGAAgAAAAhACz/UXcgAwAA8RAAABAAAAAAAAAAAAAAAAAAaFgAAHhsL2NhbGND +aGFpbi54bWxQSwECLQAUAAYACAAAACEABcuMSkcAAABsAQAAJwAAAAAAAAAAAAAAAAC2WwAAeGwv +cHJpbnRlclNldHRpbmdzL3ByaW50ZXJTZXR0aW5nczMuYmluUEsBAi0AFAAGAAgAAAAhAEk0ylMo +AQAANAQAACcAAAAAAAAAAAAAAAAAQlwAAHhsL3ByaW50ZXJTZXR0aW5ncy9wcmludGVyU2V0dGlu +Z3MxLmJpblBLAQItABQABgAIAAAAIQAFy4xKRwAAAGwBAAAnAAAAAAAAAAAAAAAAAK9dAAB4bC9w +cmludGVyU2V0dGluZ3MvcHJpbnRlclNldHRpbmdzMi5iaW5QSwECLQAUAAYACAAAACEASk+xCUAB +AABRAgAAEQAAAAAAAAAAAAAAAAA7XgAAZG9jUHJvcHMvY29yZS54bWxQSwECLQAUAAYACAAAACEA +1mh9W64BAABaAwAAEAAAAAAAAAAAAAAAAACyYAAAZG9jUHJvcHMvYXBwLnhtbFBLBQYAAAAAIgAi +AHkJAACWYwAAAAA= + +--=_0_10978_1285394661-- + + diff --git a/lib_acl_cpp/samples/gui_rpc/ReadMe.txt b/lib_acl_cpp/samples/gui_rpc/ReadMe.txt new file mode 100644 index 000000000..2d1264083 --- /dev/null +++ b/lib_acl_cpp/samples/gui_rpc/ReadMe.txt @@ -0,0 +1,85 @@ +================================================================================ + MICROSOFT 基础类库: gui_rpc 项目概述 +=============================================================================== + +应用程序向导已为您创建了此 gui_rpc 应用程序。此应用程序 +不仅介绍了使用 Microsoft 基础类的基本知识, +而且是编写应用程序的起点。 + +此文件包含组成 gui_rpc 应用程序的每个文件的内容摘要。 + +gui_rpc.vcproj + 这是使用“应用程序向导”生成的 VC++ 项目的主项目文件。 + 它包含有关生成文件的 Visual C++ 版本的信息,以及 + 有关用“应用程序向导”所选择的平台、配置和 + 项目功能的信息。 + +gui_rpc.h + 这是应用程序的主头文件。 它包含其他 + 项目特定的头文件(包括 Resource.h),并声明 + Cgui_rpcApp 应用程序类。 + +gui_rpc.cpp + 这是包含应用程序 + 类 Cgui_rpcApp 的主应用程序源文件。 + +gui_rpc.rc + 这是程序使用的所有 Microsoft Windows 资源 + 的列表。 它包含存储在 RES 子目录中 + 的图标、位图和光标。 可直接在 Microsoft + Visual C++ 中编辑此文件。 项目资源包含在 2052 中。 + +res\gui_rpc.ico + 这是一个图标文件,用作应用程序的图标。 此 + 图标包含在主资源文件 gui_rpc.rc 中。 + +res\gui_rpc.rc2 + 此文件包含不由 Microsoft + Visual C++ 编辑的资源。 应将所有不能由 + 资源编辑器编辑的资源放在此文件中。 + +///////////////////////////////////////////////////////////////////////////// + +应用程序向导将创建一个对话框类: +gui_rpcDlg.h、gui_rpcDlg.cpp - 对话框 + 这些文件包含 Cgui_rpcDlg 类。 此类定义 + 应用程序主对话框的行为。 此对话框的模板包含在 + gui_rpc.rc 中,而此文件可以在 Microsoft Visual C++ 中进行编辑。 +///////////////////////////////////////////////////////////////////////////// + +其他功能: + +ActiveX 控件 + 应用程序支持使用 ActiveX 控件。 + +Windows 套接字 + 应用程序支持在 TCP/IP 网络上建立通讯。 +///////////////////////////////////////////////////////////////////////////// + +其他标准文件: + +StdAfx.h、StdAfx.cpp + 这些文件用于生成名为 gui_rpc.pch 的预编译头文件 (PCH) + 和名为 StdAfx.obj 的预编译类型文件。 + +Resource.h + 这是标准头文件,它定义新资源 ID。 + Microsoft Visual C++ 将读取并更新此文件。 + +///////////////////////////////////////////////////////////////////////////// + +其他说明: + +应用程序向导使用“TODO:” 来指示 +应添加或自定义的源代码部分。 + +如果应用程序在共享 DLL 中使用 MFC,且应用程序使用的语言不是 +操作系统的当前语言,则需要从 Microsoft Visual C++ 光盘上 +Win\System 目录下将相应的本地化资源 MFC70XXX.DLL +复制到计算机的 system 或 system32 目录下, +并将其重命名为 MFCLOC.DLL。 (“XXX”代表 +语言缩写。 例如,MFC70DEU.DLL 包含翻译成 +德语的资源。) 如果不这样做,应用程序的某些 UI 元素 +将保留为操作系统的语言。 + +///////////////////////////////////////////////////////////////////////////// diff --git a/lib_acl_cpp/samples/gui_rpc/gui_rpc.cpp b/lib_acl_cpp/samples/gui_rpc/gui_rpc.cpp new file mode 100644 index 000000000..8192a3f42 --- /dev/null +++ b/lib_acl_cpp/samples/gui_rpc/gui_rpc.cpp @@ -0,0 +1,79 @@ +// gui_rpc.cpp : 定义应用程序的类行为。 +// + +#include "stdafx.h" +#include "gui_rpc.h" +#include "gui_rpcDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#endif + + +// Cgui_rpcApp + +BEGIN_MESSAGE_MAP(Cgui_rpcApp, CWinApp) + ON_COMMAND(ID_HELP, CWinApp::OnHelp) +END_MESSAGE_MAP() + + +// Cgui_rpcApp 构造 + +Cgui_rpcApp::Cgui_rpcApp() +{ + // TODO: 在此处添加构造代码, + // 将所有重要的初始化放置在 InitInstance 中 +} + + +// 唯一的一个 Cgui_rpcApp 对象 + +Cgui_rpcApp theApp; + + +// Cgui_rpcApp 初始化 + +BOOL Cgui_rpcApp::InitInstance() +{ + // 如果一个运行在 Windows XP 上的应用程序清单指定要 + // 使用 ComCtl32.dll 版本 6 或更高版本来启用可视化方式, + //则需要 InitCommonControls()。否则,将无法创建窗口。 + InitCommonControls(); + + CWinApp::InitInstance(); + + if (!AfxSocketInit()) + { + AfxMessageBox(IDP_SOCKETS_INIT_FAILED); + return FALSE; + } + + AfxEnableControlContainer(); + + // 标准初始化 + // 如果未使用这些功能并希望减小 + // 最终可执行文件的大小,则应移除下列 + // 不需要的特定初始化例程 + // 更改用于存储设置的注册表项 + // TODO: 应适当修改该字符串, + // 例如修改为公司或组织名 + SetRegistryKey(_T("应用程序向导生成的本地应用程序")); + + Cgui_rpcDlg dlg; + m_pMainWnd = &dlg; + INT_PTR nResponse = dlg.DoModal(); + if (nResponse == IDOK) + { + // TODO: 在此放置处理何时用“确定”来关闭 + //对话框的代码 + } + else if (nResponse == IDCANCEL) + { + // TODO: 在此放置处理何时用“取消”来关闭 + //对话框的代码 + } + + // 由于对话框已关闭,所以将返回 FALSE 以便退出应用程序, + // 而不是启动应用程序的消息泵。 + return FALSE; +} diff --git a/lib_acl_cpp/samples/gui_rpc/gui_rpc.h b/lib_acl_cpp/samples/gui_rpc/gui_rpc.h new file mode 100644 index 000000000..19638a23b --- /dev/null +++ b/lib_acl_cpp/samples/gui_rpc/gui_rpc.h @@ -0,0 +1,31 @@ +// gui_rpc.h : PROJECT_NAME 应用程序的主头文件 +// + +#pragma once + +#ifndef __AFXWIN_H__ + #error 在包含用于 PCH 的此文件之前包含“stdafx.h” +#endif + +#include "resource.h" // 主符号 + + +// Cgui_rpcApp: +// 有关此类的实现,请参阅 gui_rpc.cpp +// + +class Cgui_rpcApp : public CWinApp +{ +public: + Cgui_rpcApp(); + +// 重写 + public: + virtual BOOL InitInstance(); + +// 实现 + + DECLARE_MESSAGE_MAP() +}; + +extern Cgui_rpcApp theApp; diff --git a/lib_acl_cpp/samples/gui_rpc/gui_rpc.rc b/lib_acl_cpp/samples/gui_rpc/gui_rpc.rc new file mode 100644 index 000000000..a4fd25069 --- /dev/null +++ b/lib_acl_cpp/samples/gui_rpc/gui_rpc.rc @@ -0,0 +1,211 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// 中文(中华人民共和国) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) +#ifdef _WIN32 +LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED +#pragma code_page(936) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "#define _AFX_NO_SPLITTER_RESOURCES\r\n" + "#define _AFX_NO_OLE_RESOURCES\r\n" + "#define _AFX_NO_TRACKER_RESOURCES\r\n" + "#define _AFX_NO_PROPERTY_RESOURCES\r\n" + "\r\n" + "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)\r\n" + "LANGUAGE 4, 2\r\n" + "#pragma code_page(936)\r\n" + "#include ""res\\gui_rpc.rc2"" // 非 Microsoft Visual C++ 编辑过的资源\r\n" + "#include ""afxres.rc"" // 标准组件\r\n" + "#endif\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDR_MAINFRAME ICON "res\\gui_rpc.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_ABOUTBOX DIALOGEX 0, 0, 235, 55 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | + WS_SYSMENU +CAPTION "关于 gui_rpc" +FONT 9, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + ICON IDR_MAINFRAME,IDC_STATIC,11,17,20,20 + LTEXT "gui_rpc Version 1.0",IDC_STATIC,40,10,119,8,SS_NOPREFIX + LTEXT "Copyright (C) 2012",IDC_STATIC,40,25,119,8 + DEFPUSHBUTTON "确定",IDOK,178,7,50,16,WS_GROUP +END + +IDD_GUI_RPC_DIALOG DIALOGEX 0, 0, 446, 299 +STYLE DS_SETFONT | DS_FIXEDSYS | DS_CENTER | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | + WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +EXSTYLE WS_EX_APPWINDOW +CAPTION "gui_rpc" +FONT 9, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + EDITTEXT IDC_URL,72,21,293,14,ES_AUTOHSCROLL + EDITTEXT IDC_IP,72,46,77,15,ES_AUTOHSCROLL + EDITTEXT IDC_PORT,160,46,22,14,ES_AUTOHSCROLL + DEFPUSHBUTTON "开始运行",IDC_BUTTON_RUN,272,271,50,14 + PUSHBUTTON "清空",IDC_CLEAR,331,271,50,14 + PUSHBUTTON "退出",IDOK,389,271,50,15 + LTEXT "URL:",IDC_STATIC,46,23,15,13 + EDITTEXT IDC_REQ,29,95,172,165,ES_MULTILINE | ES_AUTOVSCROLL | + ES_AUTOHSCROLL | ES_WANTRETURN | WS_VSCROLL | WS_HSCROLL + EDITTEXT IDC_RES,227,95,190,164,ES_MULTILINE | ES_AUTOHSCROLL | + WS_VSCROLL | WS_HSCROLL + LTEXT "服务器地址:",IDC_STATIC,22,47,43,13 + GROUPBOX "响应头",IDC_STATIC_RES,221,75,201,193,WS_GROUP + GROUPBOX "请求头",IDC_STATIC_REQ,23,74,186,195,WS_GROUP +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "080403a8" + BEGIN + VALUE "CompanyName", "TODO: <公司名>" + VALUE "FileDescription", "TODO: <文件说明>" + VALUE "FileVersion", "1.0.0.1" + VALUE "InternalName", "gui_rpc.exe" + VALUE "LegalCopyright", "TODO: (C) <公司名>。保留所有权利。" + VALUE "OriginalFilename", "gui_rpc.exe" + VALUE "ProductName", "TODO: <产品名>" + VALUE "ProductVersion", "1.0.0.1" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "翻译", 0x804, 936 + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_ABOUTBOX, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 228 + TOPMARGIN, 7 + BOTTOMMARGIN, 48 + END + + IDD_GUI_RPC_DIALOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 439 + TOPMARGIN, 7 + BOTTOMMARGIN, 292 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + IDS_ABOUTBOX "关于 gui_rpc(&A)..." + IDP_SOCKETS_INIT_FAILED "Windows 套接字初始化失败。" +END + +#endif // 中文(中华人民共和国) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +#define _AFX_NO_SPLITTER_RESOURCES +#define _AFX_NO_OLE_RESOURCES +#define _AFX_NO_TRACKER_RESOURCES +#define _AFX_NO_PROPERTY_RESOURCES + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) +LANGUAGE 4, 2 +#pragma code_page(936) +#include "res\gui_rpc.rc2" // 非 Microsoft Visual C++ 编辑过的资源 +#include "afxres.rc" // 标准组件 +#endif + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/lib_acl_cpp/samples/gui_rpc/gui_rpc.vcproj b/lib_acl_cpp/samples/gui_rpc/gui_rpc.vcproj new file mode 100644 index 000000000..abe9bf057 --- /dev/null +++ b/lib_acl_cpp/samples/gui_rpc/gui_rpc.vcproj @@ -0,0 +1,251 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_acl_cpp/samples/gui_rpc/gui_rpcDlg.cpp b/lib_acl_cpp/samples/gui_rpc/gui_rpcDlg.cpp new file mode 100644 index 000000000..021e17a3a --- /dev/null +++ b/lib_acl_cpp/samples/gui_rpc/gui_rpcDlg.cpp @@ -0,0 +1,381 @@ +// gui_rpcDlg.cpp : 实现文件 +// + +#include "stdafx.h" +#include "gui_rpc.h" +#include "rpc/rpc_manager.h" +#include "rpc/http_download.h" +#include "gui_rpcDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#endif + + +// 用于应用程序“关于”菜单项的 CAboutDlg 对话框 + +class CAboutDlg : public CDialog +{ +public: + CAboutDlg(); + +// 对话框数据 + enum { IDD = IDD_ABOUTBOX }; + + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 + +// 实现 +protected: + DECLARE_MESSAGE_MAP() +}; + +CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) +{ +} + +void CAboutDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); +} + +BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) +END_MESSAGE_MAP() + + +// Cgui_rpcDlg 对话框 + + + +Cgui_rpcDlg::Cgui_rpcDlg(CWnd* pParent /*=NULL*/) + : CDialog(Cgui_rpcDlg::IDD, pParent) +{ + m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); +} + +Cgui_rpcDlg::~Cgui_rpcDlg() +{ +} + +void Cgui_rpcDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + DDX_Control(pDX, IDC_REQ, m_reqCtlEdit); + DDX_Control(pDX, IDC_RES, m_resCtlEdit); + DDX_Text(pDX, IDC_IP, m_serverIp); + DDX_Text(pDX, IDC_PORT, m_serverPort); +} + +BEGIN_MESSAGE_MAP(Cgui_rpcDlg, CDialog) + ON_WM_SYSCOMMAND() + ON_WM_PAINT() + ON_WM_QUERYDRAGICON() + //}}AFX_MSG_MAP + ON_BN_CLICKED(IDC_BUTTON_RUN, OnBnClickedButtonRun) + ON_BN_CLICKED(IDC_CLEAR, OnBnClickedClear) + ON_WM_SIZE() + ON_EN_CHANGE(IDC_URL, OnEnChangeUrl) +END_MESSAGE_MAP() + + +// Cgui_rpcDlg 消息处理程序 + +BOOL Cgui_rpcDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + BOOL bOk = m_resizer.Hook(this); + ASSERT(bOk == TRUE); + + // 将\“关于...\”菜单项添加到系统菜单中。 + + // IDM_ABOUTBOX 必须在系统命令范围内。 + ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); + ASSERT(IDM_ABOUTBOX < 0xF000); + + CMenu* pSysMenu = GetSystemMenu(FALSE); + if (pSysMenu != NULL) + { + CString strAboutMenu; + strAboutMenu.LoadString(IDS_ABOUTBOX); + if (!strAboutMenu.IsEmpty()) + { + pSysMenu->AppendMenu(MF_SEPARATOR); + pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); + } + } + + bOk = m_resizer.SetAnchor(IDC_URL, ANCHOR_HORIZONTALLY); + ASSERT( bOk); + + bOk = m_resizer.CreateSplitContainer(_T("MySplitter"), IDC_STATIC_REQ, IDC_STATIC_RES); + ASSERT( bOk ); + + //bOk = m_resizer.SetAnchor(IDC_STATIC_REQ, ANCHOR_ALL | ANCHOR_PRIORITY_RIGHT); + //ASSERT( bOk ); + //bOk = m_resizer.SetAnchor(IDC_STATIC_RES, ANCHOR_ALL | ANCHOR_PRIORITY_BOTTOM); + //ASSERT( bOk ); + + //bOk = m_resizer.SetMinimumSize(IDC_STATIC_REQ, CSize(150, 100)); + //ASSERT( bOk ); + //bOk = m_resizer.SetMinimumSize(IDC_STATIC_RES, CSize(150, 100)); + //ASSERT( bOk ); + + bOk = m_resizer.SetAnchor(_T("MySplitter"), ANCHOR_ALL); + ASSERT( bOk ); + + bOk = m_resizer.SetShowSplitterGrip(_T("MySplitter"), TRUE); + ASSERT( bOk); + + bOk = m_resizer.SetParent(IDC_REQ, IDC_STATIC_REQ); + ASSERT( bOk); + bOk = m_resizer.SetParent(IDC_RES, IDC_STATIC_RES); + ASSERT( bOk); + + bOk = m_resizer.SetAnchor(IDC_REQ, ANCHOR_LEFT | ANCHOR_ALL ); + ASSERT( bOk); + bOk = m_resizer.SetAnchor(IDC_RES, ANCHOR_RIGHT | ANCHOR_ALL); + ASSERT( bOk); + + bOk = m_resizer.SetAnchor(IDOK, ANCHOR_RIGHT | ANCHOR_BOTTOM); + ASSERT(bOk == TRUE); + bOk = m_resizer.SetAnchor(IDC_BUTTON_RUN, ANCHOR_RIGHT | ANCHOR_BOTTOM); + ASSERT(bOk == TRUE); + bOk = m_resizer.SetAnchor(IDC_CLEAR, ANCHOR_RIGHT | ANCHOR_BOTTOM); + ASSERT(bOk == TRUE); + + //GetClientRect(&m_rect); + + // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动 + // 执行此操作 + SetIcon(m_hIcon, TRUE); // 设置大图标 + SetIcon(m_hIcon, FALSE); // 设置小图标 + + GetDlgItem(IDC_PORT)->SetWindowText("80"); + + // 添加状态栏 + int aWidths[3] = {50, 300, -1}; + m_wndMeterBar.SetParts(3, aWidths); + + m_wndMeterBar.Create(WS_CHILD | WS_VISIBLE | WS_BORDER + | CCS_BOTTOM | SBARS_SIZEGRIP, + CRect(0,0,0,0), this, 0); + m_wndMeterBar.SetText("就绪", 0, 0); + m_wndMeterBar.SetText("", 1, 0); + m_wndMeterBar.SetText("", 2, 0); + + //ShowWindow(SW_MINIMIZE); + + // TODO: 在此添加额外的初始化代码 + + m_resizer.SetShowResizeGrip(TRUE); + + bOk = m_resizer.InvokeOnResized(); + ASSERT( bOk); + + return TRUE; // 除非设置了控件的焦点,否则返回 TRUE +} + +void Cgui_rpcDlg::OnSysCommand(UINT nID, LPARAM lParam) +{ + if ((nID & 0xFFF0) == IDM_ABOUTBOX) + { + CAboutDlg dlgAbout; + dlgAbout.DoModal(); + } + else + { + CDialog::OnSysCommand(nID, lParam); + } +} + +// 如果向对话框添加最小化按钮,则需要下面的代码 +// 来绘制该图标。对于使用文档/视图模型的 MFC 应用程序, +// 这将由框架自动完成。 + +void Cgui_rpcDlg::OnPaint() +{ + if (IsIconic()) + { + CPaintDC dc(this); // 用于绘制的设备上下文 + + SendMessage(WM_ICONERASEBKGND, reinterpret_cast(dc.GetSafeHdc()), 0); + + // 使图标在工作矩形中居中 + int cxIcon = GetSystemMetrics(SM_CXICON); + int cyIcon = GetSystemMetrics(SM_CYICON); + CRect rect; + GetClientRect(&rect); + int x = (rect.Width() - cxIcon + 1) / 2; + int y = (rect.Height() - cyIcon + 1) / 2; + + // 绘制图标 + dc.DrawIcon(x, y, m_hIcon); + } + else + { + CDialog::OnPaint(); + } + + // 设置 URL 栏焦点 + GetDlgItem(IDC_URL)->SetFocus(); +} + +//当用户拖动最小化窗口时系统调用此函数取得光标显示。 +HCURSOR Cgui_rpcDlg::OnQueryDragIcon() +{ + return static_cast(m_hIcon); +} + +void Cgui_rpcDlg::OnBnClickedButtonRun() +{ + // TODO: 在此添加控件通知处理程序代码 + CString url; + GetDlgItem(IDC_URL)->GetWindowText(url); + if (url.GetLength() == 0) + { + MessageBox("请输入正确的 URL!"); + return; + } + const char* ptr = url.GetString(); + if (strncasecmp(ptr, "http://", sizeof("http://") - 1) != 0) + url = "http://" + url; + + CString addr; + GetDlgItem(IDC_IP)->GetWindowText(addr); + if (addr.GetLength() == 0) + { + MessageBox("请输入正确的服务器地址!"); + return; + } + + CString port; + GetDlgItem(IDC_PORT)->GetWindowText(port); + + addr.AppendFormat(":%s", port.GetString()); + + // 在主线程中创建一个 HTTP 下载过程 + http_download* down = new http_download(addr.GetString(), + url.GetString(), this); + + // 通过子线程开始一个 HTTP 下载过程 + rpc_manager::get_instance().fork(down); + + // 虽然可以同时发起多个 HTTP 下载过程,但此处为了简单,先禁止下一个 + // HTTP 下载任务,直至上一个任务完毕 + GetDlgItem(IDC_BUTTON_RUN)->EnableWindow(false); +} + +void Cgui_rpcDlg::OnBnClickedClear() +{ + // TODO: 在此添加控件通知处理程序代码 + m_reqCtlEdit.SetSel(0, m_reqCtlEdit.GetWindowTextLength()); + m_reqCtlEdit.ReplaceSel(""); + m_resCtlEdit.SetSel(0, m_resCtlEdit.GetWindowTextLength()); + m_resCtlEdit.ReplaceSel(""); + m_wndMeterBar.GetProgressCtrl().SetPos(0); +} + +void Cgui_rpcDlg::OnSize(UINT nType, int cx, int cy) +{ + CDialog::OnSize(nType, cx, cy); + + //创建对话框时,控件还没有创建,因此不能改变其大小(必须加上这两行代码) + if(!IsWindowVisible()) + return; + + // TODO: 在此处添加消息处理程序代码 + if (m_wndMeterBar.GetSafeHwnd()) + { + int aWidths[3] = {cx / 3, cx / 3, -1}; + m_wndMeterBar.SetParts(3, aWidths); + m_wndMeterBar.SetText("就绪", 0, 0); + m_wndMeterBar.SetText("就绪2", 1, 0); //SBT_NOBORDERS); + m_wndMeterBar.SetText("", 2, SBT_NOBORDERS); + + m_wndMeterBar.SendMessage(WM_SIZE, nType, MAKELONG(cy, cx)); + } +} + +void Cgui_rpcDlg::OnEnChangeUrl() +{ + // TODO: 如果该控件是 RICHEDIT 控件,则它将不会 + // 发送该通知,除非重写 CDialog::OnInitDialog() + // 函数并调用 CRichEditCtrl().SetEventMask(), + // 同时将 ENM_CHANGE 标志“或”运算到掩码中。 + + // TODO: 在此添加控件通知处理程序代码 + CString url; + GetDlgItem(IDC_URL)->GetWindowText(url); + if (url.GetLength() == 0) + return; + url.MakeLower(); + char* ptr = url.GetBuffer(); +#define SKIP_SP(x) do { if (*(x) == ' ' || *(x) == '\t') (x)++; } while(0) + SKIP_SP(ptr); + if (*ptr == 0 || strlen(ptr) <= sizeof("http://") - 1) + return; + if (strncmp(ptr, "http://", sizeof("http://") - 1) == 0) + ptr += sizeof("http://") - 1; + if (*ptr == 0) + { + GetDlgItem(IDC_IP)->SetWindowText(""); + return; + } + CString addr = ptr; + int pos = addr.Find('/'); + if (pos >= 0) + addr.Truncate(pos); + CString port = "80"; + pos = addr.Find(':'); + if (pos >= 0) + { + port = addr.Mid(pos + 1); + addr.Truncate(pos); + } + GetDlgItem(IDC_IP)->SetWindowText(addr.GetString()); + if (port.GetLength() > 0) + GetDlgItem(IDC_PORT)->SetWindowText(port.GetString()); +} + +////////////////////////////////////////////////////////////////////////// + +void Cgui_rpcDlg::OnDownloading(long long int content_length, + long long int total_read) +{ + if (content_length > 0) + { + int nStept; + + nStept = (int) ((total_read * 100) / (content_length)); + m_wndMeterBar.GetProgressCtrl().SetPos(nStept); + } + + CString msg; + msg.Format("共 %I64d 字节", total_read); + m_wndMeterBar.SetText(msg, 1, 0); +} + +void Cgui_rpcDlg::OnDownloadOver(long long int total_read, double spent) +{ + CString msg; + msg.Format("共 %I64d 字节,耗时 %.3f 毫秒", total_read, spent); + m_wndMeterBar.SetText(msg, 1, 0); + GetDlgItem(IDC_BUTTON_RUN)->EnableWindow(true); +} + +void Cgui_rpcDlg::SetRequestHdr(const char* hdr) +{ + if (hdr == NULL || *hdr == 0) + return; + m_reqCtlEdit.SetSel(0, m_reqCtlEdit.GetWindowTextLength()); + m_reqCtlEdit.ReplaceSel(hdr); +} + +void Cgui_rpcDlg::SetResponseHdr(const char* hdr) +{ + if (hdr == NULL || *hdr == 0) + return; + m_resCtlEdit.SetSel(0, m_resCtlEdit.GetWindowTextLength()); + m_resCtlEdit.ReplaceSel(hdr); +} diff --git a/lib_acl_cpp/samples/gui_rpc/gui_rpcDlg.h b/lib_acl_cpp/samples/gui_rpc/gui_rpcDlg.h new file mode 100644 index 000000000..65524a08c --- /dev/null +++ b/lib_acl_cpp/samples/gui_rpc/gui_rpcDlg.h @@ -0,0 +1,65 @@ +// gui_rpcDlg.h : 头文件 +// + +#pragma once +#include "MeterBar.h" +#include "rpc/http_download.h" + +// Cgui_rpcDlg 对话框 +class Cgui_rpcDlg : public CDialog + , public rpc_callback +{ +// 构造 +public: + Cgui_rpcDlg(CWnd* pParent = NULL); // 标准构造函数 + ~Cgui_rpcDlg(); + +// 对话框数据 + enum { IDD = IDD_GUI_RPC_DIALOG }; + + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 + +// 实现 +protected: + HICON m_hIcon; + + // 生成的消息映射函数 + virtual BOOL OnInitDialog(); + afx_msg void OnSysCommand(UINT nID, LPARAM lParam); + afx_msg void OnPaint(); + afx_msg HCURSOR OnQueryDragIcon(); + DECLARE_MESSAGE_MAP() + +protected: + CMeterBar m_wndMeterBar; + +private: + CWndResizer m_resizer; + //CRect m_rect; //用于保存对话框大小变化前的大小 + + CEdit m_reqCtlEdit; + CEdit m_resCtlEdit; + + CString m_serverIp; + CString m_serverPort; + +public: + // 基类 rpc_callback 虚函数 + + // 设置 HTTP 请求头数据虚函数 + virtual void SetRequestHdr(const char* hdr); + // 设置 HTTP 响应头数据虚函数 + virtual void SetResponseHdr(const char* hdr); + // 下载过程中的回调函数虚函数 + virtual void OnDownloading(long long int content_length, + long long int total_read); + // 下载完成时的回调函数虚函数 + virtual void OnDownloadOver(long long int total_read, + double spent); +public: + afx_msg void OnBnClickedButtonRun(); + afx_msg void OnBnClickedClear(); + afx_msg void OnSize(UINT nType, int cx, int cy); + afx_msg void OnEnChangeUrl(); +}; diff --git a/lib_acl_cpp/samples/gui_rpc/res/gui_rpc.ico b/lib_acl_cpp/samples/gui_rpc/res/gui_rpc.ico new file mode 100644 index 000000000..8a84ca3d3 Binary files /dev/null and b/lib_acl_cpp/samples/gui_rpc/res/gui_rpc.ico differ diff --git a/lib_acl_cpp/samples/gui_rpc/res/gui_rpc.manifest b/lib_acl_cpp/samples/gui_rpc/res/gui_rpc.manifest new file mode 100644 index 000000000..972fe65b7 --- /dev/null +++ b/lib_acl_cpp/samples/gui_rpc/res/gui_rpc.manifest @@ -0,0 +1,22 @@ + + + +鍦ㄦ璇存槑搴旂敤绋嬪簭 + + + + + + diff --git a/lib_acl_cpp/samples/gui_rpc/res/gui_rpc.rc2 b/lib_acl_cpp/samples/gui_rpc/res/gui_rpc.rc2 new file mode 100644 index 000000000..de82d02ea --- /dev/null +++ b/lib_acl_cpp/samples/gui_rpc/res/gui_rpc.rc2 @@ -0,0 +1,13 @@ +// +// gui_rpc.RC2 - Microsoft Visual C++ 不会直接编辑的资源 +// + +#ifdef APSTUDIO_INVOKED +#error 此文件不能由 Microsoft Visual C++ 编辑 +#endif //APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// 在此处添加手动编辑的资源... + +///////////////////////////////////////////////////////////////////////////// diff --git a/lib_acl_cpp/samples/gui_rpc/resource.h b/lib_acl_cpp/samples/gui_rpc/resource.h new file mode 100644 index 000000000..303d07d57 --- /dev/null +++ b/lib_acl_cpp/samples/gui_rpc/resource.h @@ -0,0 +1,32 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by gui_rpc.rc +// +#define IDM_ABOUTBOX 0x0010 +#define IDD_ABOUTBOX 100 +#define IDS_ABOUTBOX 101 +#define IDD_GUI_RPC_DIALOG 102 +#define IDP_SOCKETS_INIT_FAILED 103 +#define IDR_MAINFRAME 128 +#define IDC_EDIT1 1000 +#define IDC_URL 1000 +#define IDC_BUTTON_RUN 1002 +#define IDC_REQ 1004 +#define IDC_RES 1005 +#define IDC_CLEAR 1006 +#define IDC_EDIT2 1007 +#define IDC_IP 1007 +#define IDC_PORT 1008 +#define IDC_STATIC_REQ 1009 +#define IDC_STATIC_RES 1010 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 129 +#define _APS_NEXT_COMMAND_VALUE 32771 +#define _APS_NEXT_CONTROL_VALUE 1011 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/lib_acl_cpp/samples/gui_rpc/rpc/http_download.cpp b/lib_acl_cpp/samples/gui_rpc/rpc/http_download.cpp new file mode 100644 index 000000000..6ea861491 --- /dev/null +++ b/lib_acl_cpp/samples/gui_rpc/rpc/http_download.cpp @@ -0,0 +1,174 @@ +#include "stdafx.h" +#include +#include "http_download.h" + +// 由子线程动态创建的 DOWN_CTX 对象的数据类型 +typedef enum +{ + CTX_T_REQ_HDR, // 为 HTTP 请求头数据 + CTX_T_RES_HDR, // 为 HTTP 响应头数据 + CTX_T_CONTENT_LENGTH, // 为 HTTP 响应体的长度 + CTX_T_PARTIAL_LENGTH, // 为 HTTP 下载数据体的长度 + CTX_T_END +} ctx_t; + +// 子线程动态创建的数据对象,主线程接收此数据 +struct DOWN_CTX +{ + ctx_t type; + long long int length; +}; + +// 用来精确计算时间截间隔的函数,精确到毫秒级别 +static double stamp_sub(const struct timeval *from, + const struct timeval *sub_by) +{ + struct timeval res; + + memcpy(&res, from, sizeof(struct timeval)); + + res.tv_usec -= sub_by->tv_usec; + if (res.tv_usec < 0) + { + --res.tv_sec; + res.tv_usec += 1000000; + } + + res.tv_sec -= sub_by->tv_sec; + return (res.tv_sec * 1000.0 + res.tv_usec/1000.0); +} + +////////////////////////////////////////////////////////////////////////// + +// 子线程处理函数 +void http_download::rpc_run() +{ + acl::http_request req(addr_); // HTTP 请求对象 + // 设置 HTTP 请求头信息 + req.request_header().set_url(url_.c_str()) + .set_content_type("text/html") + .set_host(addr_.c_str()) + .set_method(acl::HTTP_METHOD_GET); + + req.request_header().build_request(req_hdr_); + DOWN_CTX* ctx = new DOWN_CTX; + ctx->type = CTX_T_REQ_HDR; + rpc_signal(ctx); // 通知主线程 HTTP 请求头数据 + + struct timeval begin, end;; + gettimeofday(&begin, NULL); + + // 发送 HTTP 请求数据 + if (req.request(NULL, 0) == false) + { + logger_error("send request error"); + error_ = false; + gettimeofday(&end, NULL); + total_spent_ = stamp_sub(&end, &begin); + return; + } + + // 获得 HTTP 请求的连接对象 + acl::http_client* conn = req.get_client(); + assert(conn); + + (void) conn->get_respond_head(&res_hdr_); + ctx = new DOWN_CTX; + ctx->type = CTX_T_RES_HDR; + rpc_signal(ctx); // 通知主线程 HTTP 响应头数据 + + ctx = new DOWN_CTX; + ctx->type = CTX_T_CONTENT_LENGTH; + + ctx->length = conn->body_length(); // 获得 HTTP 响应数据的数据体长度 + content_length_ = ctx->length; + rpc_signal(ctx); // 通知主线程 HTTP 响应体数据长度 + + acl::string buf(8192); + int real_size; + while (true) + { + // 读 HTTP 响应数据体 + int ret = req.read_body(buf, true, &real_size); + if (ret <= 0) + { + ctx = new DOWN_CTX; + ctx->type = CTX_T_END; + ctx->length = ret; + rpc_signal(ctx); // 通知主线程下载完毕 + break; + } + ctx = new DOWN_CTX; + ctx->type = CTX_T_PARTIAL_LENGTH; + ctx->length = real_size; + // 通知主线程当前已经下载的大小 + rpc_signal(ctx); + } + + // 计算下载过程总时长 + gettimeofday(&end, NULL); + total_spent_ = stamp_sub(&end, &begin); + + // 至此,子线程运行完毕,主线程的 rpc_onover 过程将被调用 +} + +////////////////////////////////////////////////////////////////////////// + +http_download::http_download(const char* addr, const char* url, + rpc_callback* callback) + : addr_(addr) + , url_(url) + , callback_(callback) + , error_(false) + , total_read_(0) + , content_length_(0) + , total_spent_(0) +{ + +} + +////////////////////////////////////////////////////////////////////////// + +// 主线程处理过程,收到子线程任务完成的消息 +void http_download::rpc_onover() +{ + logger("http download(%s) over, 共 %I64d 字节,耗时 %.3f 毫秒", + url_.c_str(), total_read_, total_spent_); + callback_->OnDownloadOver(total_read_, total_spent_); + delete this; // 销毁本对象 +} + +// 主线程处理过程,收到子线程的通知消息 +void http_download::rpc_wakeup(void* ctx) +{ + DOWN_CTX* down_ctx = (DOWN_CTX*) ctx; + + // 根据子线程中传来的不同的下载阶段进行处理 + + switch (down_ctx->type) + { + case CTX_T_REQ_HDR: + callback_->SetRequestHdr(req_hdr_.c_str()); + break; + case CTX_T_RES_HDR: + callback_->SetResponseHdr(res_hdr_.c_str()); + break; + case CTX_T_CONTENT_LENGTH: + break; + case CTX_T_PARTIAL_LENGTH: + total_read_ += down_ctx->length; + callback_->OnDownloading(content_length_, total_read_); + break; + case CTX_T_END: + logger("%s: read over", addr_.c_str()); + break; + default: + logger_error("%s: ERROR", addr_.c_str()); + break; + } + + // 删除在子线程中动态分配的对象 + delete down_ctx; +} + +////////////////////////////////////////////////////////////////////////// diff --git a/lib_acl_cpp/samples/gui_rpc/rpc/http_download.h b/lib_acl_cpp/samples/gui_rpc/rpc/http_download.h new file mode 100644 index 000000000..d0f8dc41c --- /dev/null +++ b/lib_acl_cpp/samples/gui_rpc/rpc/http_download.h @@ -0,0 +1,64 @@ +#pragma once + +////////////////////////////////////////////////////////////////////////// + +// 纯虚类,子类须实现该类中的纯虚接口 +class rpc_callback +{ +public: + rpc_callback() {} + virtual ~rpc_callback() {} + + // 设置 HTTP 请求头数据虚函数 + virtual void SetRequestHdr(const char* hdr) = 0; + // 设置 HTTP 响应头数据虚函数 + virtual void SetResponseHdr(const char* hdr) = 0; + // 下载过程中的回调函数虚函数 + virtual void OnDownloading(long long int content_length, + long long int total_read) = 0; + // 下载完成时的回调函数虚函数 + virtual void OnDownloadOver(long long int total_read, + double spent) = 0; +}; + +////////////////////////////////////////////////////////////////////////// + +/** + * http 请求过程类,该类对象在子线程中发起远程 HTTP 请求过程,将处理结果 + * 返回给主线程 + */ +class http_download : public acl::rpc_request +{ +public: + /** + * 构造函数 + * @param addr {const char*} HTTP 服务器地址,格式:domain:port + * @param url {const char*} http url 地址 + * @param callback {rpc_callback*} http 请求结果通过此类对象 + * 通知主线程过程 + */ + http_download(const char* addr, const char* url, + rpc_callback* callback); +protected: + ~http_download() {} + + // 基类虚函数:子线程处理函数 + virtual void rpc_run(); + + // 基类虚函数:主线程处理过程,收到子线程任务完成的消息 + virtual void rpc_onover(); + + // 基类虚函数:主线程处理过程,收到子线程的通知消息 + virtual void rpc_wakeup(void* ctx); +private: + acl::string addr_; + acl::string url_; + acl::string req_hdr_; + acl::string res_hdr_; + bool error_; + long long int total_read_; + long long int content_length_; + double total_spent_; + + rpc_callback* callback_; +}; diff --git a/lib_acl_cpp/samples/gui_rpc/rpc/rpc_manager.cpp b/lib_acl_cpp/samples/gui_rpc/rpc/rpc_manager.cpp new file mode 100644 index 000000000..914e70f89 --- /dev/null +++ b/lib_acl_cpp/samples/gui_rpc/rpc/rpc_manager.cpp @@ -0,0 +1,29 @@ +#include "stdafx.h" +#include "rpc_manager.h" + +rpc_manager::rpc_manager(int max_threads /* = 10 */) +{ + // 因为本类实例是单例,会在程序 main 之前被调用, + // 所以需要在此类中打开日志 + logger_open("gui_rpc.log", "gui_rpc"); + // 创建非阻塞框架句柄,并采用 WIN32 消息模式:acl::ENGINE_WINMSG + handle_ = new acl::aio_handle(acl::ENGINE_WINMSG); + // 创建 rpc 服务对象 + service_ = new acl::rpc_service(max_threads); + // 打开消息服务 + if (service_->open(handle_) == false) + logger_fatal("open service error: %s", acl::last_serror()); +} + +rpc_manager::~rpc_manager() +{ + delete service_; + handle_->check(); + delete handle_; + logger("rpc service destroy ok!"); +} + +void rpc_manager::fork(acl::rpc_request* req) +{ + service_->rpc_fork(req); +} diff --git a/lib_acl_cpp/samples/gui_rpc/rpc/rpc_manager.h b/lib_acl_cpp/samples/gui_rpc/rpc/rpc_manager.h new file mode 100644 index 000000000..77ac016e0 --- /dev/null +++ b/lib_acl_cpp/samples/gui_rpc/rpc/rpc_manager.h @@ -0,0 +1,27 @@ +#pragma once + +/** + * 本类对象将阻塞任务交给子线程处理;为了方便使用,将该类声明为单例类 + */ +class rpc_manager : public acl::singleton +{ +public: + /** + * 构造函数 + * @param max_threads {int} 子线程池的最大线程数量 + */ + rpc_manager(int max_threads = 10); + ~rpc_manager(); + + /** + * 发起一个阻塞过程,将该过程交由子线程处理 + * @param req {acl::rpc_request*} 阻塞任务对象 + */ + void fork(acl::rpc_request* req); +protected: +private: + // 异步消息句柄 + acl::aio_handle* handle_; + // 异步 RPC 通信服务句柄 + acl::rpc_service* service_; +}; diff --git a/lib_acl_cpp/samples/gui_rpc/stdafx.cpp b/lib_acl_cpp/samples/gui_rpc/stdafx.cpp new file mode 100644 index 000000000..f4df0272b --- /dev/null +++ b/lib_acl_cpp/samples/gui_rpc/stdafx.cpp @@ -0,0 +1,7 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// gui_rpc.pch 将是预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + + diff --git a/lib_acl_cpp/samples/gui_rpc/stdafx.h b/lib_acl_cpp/samples/gui_rpc/stdafx.h new file mode 100644 index 000000000..fe51563d2 --- /dev/null +++ b/lib_acl_cpp/samples/gui_rpc/stdafx.h @@ -0,0 +1,54 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是经常使用但不常更改的 +// 项目特定的包含文件 + +#pragma once + +#ifndef VC_EXTRALEAN +#define VC_EXTRALEAN // 从 Windows 标头中排除不常使用的资料 +#endif + +// 如果您必须使用下列所指定的平台之前的平台,则修改下面的定义。 +// 有关不同平台的相应值的最新信息,请参考 MSDN。 +#ifndef WINVER // 允许使用 Windows 95 和 Windows NT 4 或更高版本的特定功能。 +#define WINVER 0x0400 //为 Windows98 和 Windows 2000 及更新版本改变为适当的值。 +#endif + +#ifndef _WIN32_WINNT // 允许使用 Windows NT 4 或更高版本的特定功能。 +#define _WIN32_WINNT 0x0400 //为 Windows98 和 Windows 2000 及更新版本改变为适当的值。 +#endif + +#ifndef _WIN32_WINDOWS // 允许使用 Windows 98 或更高版本的特定功能。 +#define _WIN32_WINDOWS 0x0410 //为 Windows Me 及更新版本改变为适当的值。 +#endif + +#ifndef _WIN32_IE // 允许使用 IE 4.0 或更高版本的特定功能。 +#define _WIN32_IE 0x0400 //为 IE 5.0 及更新版本改变为适当的值。 +#endif + +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // 某些 CString 构造函数将是显式的 + +// 关闭 MFC 对某些常见但经常被安全忽略的警告消息的隐藏 +#define _AFX_ALL_WARNINGS + +#include // MFC 核心和标准组件 +#include // MFC 扩展 +#include // MFC 自动化类 +#include // Internet Explorer 4 公共控件的 MFC 支持 +#ifndef _AFX_NO_AFXCMN_SUPPORT +#include // Windows 公共控件的 MFC 支持 +//#include // MFC support for ribbons and control bars +#include +#include +#include +#include +//#include + +#endif // _AFX_NO_AFXCMN_SUPPORT + +#include // MFC 套接字扩展 +#include "WndResizer.h" +#include "acl_cpp/lib_acl.hpp" +#include "lib_acl.h" + +////////////////////////////////////////////////////////////////////////// diff --git a/lib_acl_cpp/samples/gui_rpc/ui/MeterBar.cpp b/lib_acl_cpp/samples/gui_rpc/ui/MeterBar.cpp new file mode 100644 index 000000000..067c9d241 --- /dev/null +++ b/lib_acl_cpp/samples/gui_rpc/ui/MeterBar.cpp @@ -0,0 +1,80 @@ +// MeterBar.cpp : 实现文件 +// + +#include "stdafx.h" +#include "MeterBar.h" + +// CMeterBar + +IMPLEMENT_DYNAMIC(CMeterBar, CStatusBarCtrl) +CMeterBar::CMeterBar() +: m_pWidths(NULL) +{ +} + +CMeterBar::~CMeterBar() +{ + delete m_pWidths; +} + + +BEGIN_MESSAGE_MAP(CMeterBar, CStatusBarCtrl) + ON_WM_CREATE() + ON_WM_SIZE() +END_MESSAGE_MAP() + +BOOL CMeterBar::SetParts(int nParts, int* pWidths) +{ + m_nParts = nParts; + m_pWidths = new int[nParts]; + int i; + for (i = 0; i < nParts; i++) + { + m_pWidths[i] = pWidths[i]; + } + return (TRUE); +} + +// CMeterBar 消息处理程序 + + +int CMeterBar::OnCreate(LPCREATESTRUCT lpCreateStruct) +{ + if (CStatusBarCtrl::OnCreate(lpCreateStruct) == -1) + return -1; + + ASSERT(m_pWidths); + CStatusBarCtrl::SetParts(m_nParts, m_pWidths); + //int tmp; + //int n = GetParts(0, &tmp); + + // TODO: 在此添加您专用的创建代码 + //m_meter.Create(WS_CHILD | WS_VISIBLE, CRect(0, 0, 0, 0), this, 101); + //m_meter.Create("Press start timer to see me go", + // WS_VISIBLE | WS_CHILD | WS_EX_CLIENTEDGE, CRect(0, 0, 0, 0), this, (HMENU) 101); + static CString className = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW); + DWORD dwExStyle = WS_EX_STATICEDGE; //WS_EX_CLIENTEDGE | WS_EX_STATICEDGE; + m_meter.CreateEx(dwExStyle, className, + "Press start timer to see me go", WS_VISIBLE | WS_CHILD, + CRect(0, 0, 0, 0), this, 101); + + m_meter.SetRange(0, 100); + m_meter.SetPos(0); + //m_meter.SetStep(1); + + return 0; +} + +void CMeterBar::OnSize(UINT nType, int cx, int cy) +{ + CStatusBarCtrl::OnSize(nType, cx, cy); + + // TODO: 在此处添加消息处理程序代码 + int nTemp; + int nCount = GetParts(0, &nTemp); + if (nCount > 0) { + CRect r; + GetRect(nCount - 1, r); + m_meter.MoveWindow(r); + } +} diff --git a/lib_acl_cpp/samples/gui_rpc/ui/MeterBar.h b/lib_acl_cpp/samples/gui_rpc/ui/MeterBar.h new file mode 100644 index 000000000..9dac6109d --- /dev/null +++ b/lib_acl_cpp/samples/gui_rpc/ui/MeterBar.h @@ -0,0 +1,33 @@ +#pragma once +#include "afxcmn.h" +#include "MeterCtrl.h" + +// CMeterBar + +class CMeterBar : public CStatusBarCtrl +{ + DECLARE_DYNAMIC(CMeterBar) + +public: + CMeterBar(); + virtual ~CMeterBar(); + + BOOL SetParts(int nParts, int* pWidths); + + CMeterCtrl& GetProgressCtrl() { + return m_meter; + } + +protected: + DECLARE_MESSAGE_MAP() + //CProgressCtrl m_meter; + CMeterCtrl m_meter; +public: + afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); + afx_msg void OnSize(UINT nType, int cx, int cy); +private: + int *m_pWidths; + int m_nParts; +}; + + diff --git a/lib_acl_cpp/samples/gui_rpc/ui/MeterCtrl.cpp b/lib_acl_cpp/samples/gui_rpc/ui/MeterCtrl.cpp new file mode 100644 index 000000000..d63709e69 --- /dev/null +++ b/lib_acl_cpp/samples/gui_rpc/ui/MeterCtrl.cpp @@ -0,0 +1,169 @@ +// MeterCtrl.cpp : 实现文件 +// + +#include "stdafx.h" +#include ".\Meterctrl.h" + + +// CMeterCtrl + +IMPLEMENT_DYNAMIC(CMeterCtrl, CWnd) +CMeterCtrl::CMeterCtrl() +: m_nLower(0) +, m_nUpper(0) +, m_nPos(0) +{ +} + +CMeterCtrl::~CMeterCtrl() +{ +} + + +BEGIN_MESSAGE_MAP(CMeterCtrl, CWnd) + ON_WM_PAINT() + ON_WM_ERASEBKGND() +END_MESSAGE_MAP() + + + +// CMeterCtrl 消息处理程序 + + +void CMeterCtrl::OnPaint() +{ + CPaintDC dc(this); // device context for painting + // TODO: 在此处添加消息处理程序代码 + // 不为绘图消息调用 CWnd::OnPaint() + CRect rClient; + GetClientRect(rClient); + CRect rLeft = rClient; + CRect rRight = rClient; + UINT nRange = m_nUpper - m_nLower; + + rLeft.right = (LONG)(((m_nPos - m_nLower) * rClient.Width())/ nRange); + rRight.left = rLeft.right; + + CRgn rgnLeft, rgnRight; + rgnLeft.CreateRectRgnIndirect(rLeft); + rgnRight.CreateRectRgnIndirect(rRight); + + CBrush *pBrush = CBrush::FromHandle(GetSysColorBrush(COLOR_HIGHLIGHT)); + dc.FillRect(rLeft, pBrush); + CString msg; + +// msg.Format(">>left=%d, right=%d, top=%d, bottom=%d, nrange=%d, width=%d, npos=%d, nlower=%d", +// rLeft.left, rLeft.right, rLeft.top, rLeft.bottom, +// nRange, rClient.Width(), m_nPos, m_nLower); +// AfxMessageBox(msg); + + //CString strCaption; + //GetWindowText(strCaption); + + //strCaption.Format("%d%% (%d)", ((m_nPos - m_nLower) * 100)/ nRange, m_nPos); + + dc.SelectClipRgn(&rgnLeft); + dc.SetBkMode(TRANSPARENT); + dc.SetTextColor(GetSysColor(COLOR_HIGHLIGHTTEXT)); + dc.DrawText(m_sCaption, rClient, DT_BOTTOM | DT_CENTER); + dc.SelectClipRgn(&rgnRight); + dc.SetTextColor(GetSysColor(COLOR_HIGHLIGHT)); + dc.DrawText(m_sCaption, rClient, DT_BOTTOM | DT_CENTER); +} + +BOOL CMeterCtrl::OnEraseBkgnd(CDC* pDC) +{ + // TODO: 在此添加消息处理程序代码和/或调用默认值 + CRect r; + GetClientRect(r); + CBrush *pBrush = CBrush::FromHandle(GetSysColorBrush(COLOR_BTNFACE)); + pDC->FillRect(r, pBrush); + + return TRUE; +// return CWnd::OnEraseBkgnd(pDC); +} + +BOOL CMeterCtrl::Create(LPCTSTR lpszWindowName, DWORD dwStyle, + const RECT& rect, CWnd* pParentWnd, HMENU nID) +{ + // TODO: 在此添加专用代码和/或调用基类 + static CString className = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW); + + return CWnd::CreateEx(WS_EX_STATICEDGE, //WS_EX_CLIENTEDGE | WS_EX_STATICEDGE, + className, lpszWindowName, dwStyle, + rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, + pParentWnd->GetSafeHwnd(), (HMENU) nID); + +// return CWnd::Create(lpszClassName, lpszWindowName, dwStyle, +// rect, pParentWnd, nID, pContext); +} + +BOOL CMeterCtrl::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName, + LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, + CWnd* pParentWnd, UINT nID, LPVOID lpParam) +{ + // TODO: 在此添加专用代码和/或调用基类 + + static CString className = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW); + + return CWnd::CreateEx(dwExStyle, //WS_EX_CLIENTEDGE | WS_EX_STATICEDGE, + lpszClassName, lpszWindowName, dwStyle, + rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, + pParentWnd->GetSafeHwnd(), (HMENU) nID); + + //return CWnd::CreateEx(dwExStyle, lpszClassName, lpszWindowName, + // dwStyle, rect, pParentWnd, nID, lpParam); +} + +UINT CMeterCtrl::SetPos(UINT nPos) +{ + ASSERT(nPos >= m_nLower && nPos <= m_nUpper); + + UINT nRange = m_nUpper - m_nLower; + UINT nOld = m_nPos; + m_nPos = nPos; + + m_sCaption.Format("%d%% (%d)", ((m_nPos - m_nLower) * 100)/ nRange, m_nPos); + InvalidateMeater(); + + return nOld; +} + +void CMeterCtrl::SetRange(UINT nLower, UINT nUpper) +{ + ASSERT(nLower >= 0 && nLower < 0xffff); + ASSERT(nUpper > nLower && nUpper < 0xffff); + + m_nLower = nLower; + m_nUpper = nUpper; + + InvalidateMeater(); +} + +void CMeterCtrl::StepIt(void) +{ + m_nPos++; + if (m_nPos > m_nUpper) + m_nPos = m_nLower; + + InvalidateMeater(); +} + +void CMeterCtrl::SetText(CString& msg) +{ + m_sCaption = msg; + InvalidateMeater(); +} + +void CMeterCtrl::SetText(const char* pMsg) +{ + m_sCaption = pMsg; + InvalidateMeater(); +} + +void CMeterCtrl::InvalidateMeater(void) +{ + CRect r; + GetClientRect(r); + InvalidateRect(r); +} diff --git a/lib_acl_cpp/samples/gui_rpc/ui/MeterCtrl.h b/lib_acl_cpp/samples/gui_rpc/ui/MeterCtrl.h new file mode 100644 index 000000000..49cc9dd9a --- /dev/null +++ b/lib_acl_cpp/samples/gui_rpc/ui/MeterCtrl.h @@ -0,0 +1,38 @@ +#pragma once + + +// CMeterCtrl + +class CMeterCtrl : public CWnd +{ + DECLARE_DYNAMIC(CMeterCtrl) + +public: + CMeterCtrl(); + virtual ~CMeterCtrl(); + +protected: + DECLARE_MESSAGE_MAP() +public: + afx_msg void OnPaint(); + afx_msg BOOL OnEraseBkgnd(CDC* pDC); + //virtual BOOL Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext = NULL); + virtual BOOL Create(LPCTSTR lpszWindowName, DWORD dwStyle, + const RECT& rect, CWnd* pParentWnd, HMENU nID); + virtual BOOL CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName, + LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, + CWnd* pParentWnd, UINT nID, LPVOID lpParam = NULL); + UINT SetPos(UINT nPos); + void SetRange(UINT nLower, UINT nUpper); + void StepIt(void); + void SetText(CString& msg); + void SetText(const char* pMsg); +protected: + void InvalidateMeater(void); + UINT m_nLower; + UINT m_nUpper; + UINT m_nPos; + CString m_sCaption; +}; + + diff --git a/lib_acl_cpp/samples/gui_rpc/ui/WndResizer.cpp b/lib_acl_cpp/samples/gui_rpc/ui/WndResizer.cpp new file mode 100644 index 000000000..2561f9c93 --- /dev/null +++ b/lib_acl_cpp/samples/gui_rpc/ui/WndResizer.cpp @@ -0,0 +1,2690 @@ +/* +DISCLAIMER + +Auther: Mizan Rahman +Original publication location: http://www.codeproject.com/KB/dialog/WndResizer.aspx + +This work is provided under the terms and condition described in The Code Project Open License (CPOL) +(http://www.codeproject.com/info/cpol10.aspx) + +This disclaimer should not be removed and should exist in any reproduction of this work. +*/ + +#include "StdAfx.h" +#include "WndResizer.h" + + + +static CMap WndResizerData; + + +///////////////////////////// CWndResizer +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +CWndResizer::CWndResizer(void) +{ + m_pHookedWnd = NULL; + m_pfnWndProc = NULL; + root.Name = _T("_root"); + m_pCaptured = NULL; + m_hOldCursor = NULL; + m_splitterOffset = 0; + +} + +CWndResizer::~CWndResizer(void) +{ + +} +void CWndResizer::GetTrueClientRect(CWnd * pWnd, CRect * prc) +{ + int nMin = 0; + int nMax = 0; + int nCur = 0; + + pWnd->GetClientRect(prc); + + if ( (pWnd->GetStyle() & WS_HSCROLL) > 0) + { + pWnd->GetScrollRange(SB_HORZ, &nMin, &nMax); + nCur = pWnd->GetScrollPos(SB_HORZ); + prc->right = prc->left + nMax; + prc->OffsetRect( -nCur , 0); + } + + if ( (pWnd->GetStyle() & WS_VSCROLL) > 0) + { + pWnd->GetScrollRange(SB_VERT, &nMin, &nMax); + nCur = pWnd->GetScrollPos(SB_VERT); + prc->bottom = prc->top + nMax; + prc->OffsetRect(0, -nCur); + } +} +void CWndResizer::EnsureRootMinMax() +{ + if (root.Width() < root.MinSize.cx) + { + root.right = root.left + root.MinSize.cx; + } + if (root.Width() > root.MaxSize.cx) + { + root.right = root.left + root.MaxSize.cx; + } + + if (root.Height() < root.MinSize.cy) + { + root.bottom = root.top + root.MinSize.cy; + } + if (root.Height() > root.MaxSize.cy) + { + root.bottom = root.top + root.MaxSize.cy; + } +} + +void CWndResizer::OnSize(UINT nType, int cx, int cy) +{ + GetTrueClientRect(m_pHookedWnd, &root); + EnsureRootMinMax(); + root.OnResized(); + ResizeUI(&root); +} +void CWndResizer::OnScroll() +{ + GetTrueClientRect(m_pHookedWnd, &root); + EnsureRootMinMax(); + root.OnResized(); + ResizeUI(&root); +} +BOOL CWndResizer::Hook(CWnd * pParent) +{ + ASSERT( m_pHookedWnd == NULL ); + + m_pHookedWnd = pParent; + + GetTrueClientRect(m_pHookedWnd, &root); + + root.m_pHookWnd = m_pHookedWnd; + + // create the resize gripper panel + CRect rcResziGrip(&root); + int cx = ::GetSystemMetrics(SM_CXHSCROLL); + int cy = ::GetSystemMetrics(SM_CYVSCROLL); + rcResziGrip.DeflateRect(root.Width() - cx, root.Height() - cy, 0, 0); + CGripperPanel * pResizeGripper = new CGripperPanel(&rcResziGrip); + pResizeGripper->SetAnchor( ANCHOR_RIGHT | ANCHOR_BOTTOM ); + pResizeGripper->Name = _T("_resizeGrip"); + root.AddChild( pResizeGripper ); + + WndResizerData.SetAt(m_pHookedWnd->m_hWnd, this); + + m_pfnWndProc = (WNDPROC)::SetWindowLongPtr(m_pHookedWnd->m_hWnd, GWLP_WNDPROC, (LONG_PTR)WindowProc); + return TRUE; +} +BOOL CWndResizer::Hook(CWnd * pParent, CSize & size) +{ + ASSERT( m_pHookedWnd == NULL ); + + m_pHookedWnd = pParent; + + GetTrueClientRect(m_pHookedWnd, &root); + root.right = root.left + size.cx; + root.bottom = root.top + size.cy; + root.m_pHookWnd = m_pHookedWnd; + + // create the resize gripper panel + CRect rcResziGrip(&root); + int cx = ::GetSystemMetrics(SM_CXHSCROLL); + int cy = ::GetSystemMetrics(SM_CYVSCROLL); + rcResziGrip.DeflateRect(root.Width() - cx, root.Height() - cy, 0, 0); + CGripperPanel * pResizeGripper = new CGripperPanel(&rcResziGrip); + pResizeGripper->SetAnchor( ANCHOR_RIGHT | ANCHOR_BOTTOM ); + pResizeGripper->Name = _T("_resizeGrip"); + root.AddChild( pResizeGripper ); + + WndResizerData.SetAt(m_pHookedWnd->m_hWnd, this); + + m_pfnWndProc = (WNDPROC)::SetWindowLongPtr(m_pHookedWnd->m_hWnd, GWLP_WNDPROC, (LONG_PTR)WindowProc); + return TRUE; +} + +void CWndResizer::ResizeUI(CPanel * pRoot) +{ + CPanelList panels; + GetUIPanels(pRoot, &panels, FALSE); + + POSITION pos = NULL; + + if (panels.GetCount() > 0) + { + HDWP hDWP = ::BeginDeferWindowPos((int) panels.GetCount()); + ASSERT( hDWP != NULL); + pos = panels.GetHeadPosition(); + while (pos != NULL) + { + CUIPanel * pPanel = (CUIPanel *) panels.GetNext(pos); + + ::DeferWindowPos(hDWP, m_pHookedWnd->GetDlgItem(pPanel->m_uID)->m_hWnd, NULL, + pPanel->left , pPanel->top , pPanel->Width(), pPanel->Height(), + SWP_NOACTIVATE | SWP_NOZORDER ); + + } + BOOL bOk = ::EndDeferWindowPos(hDWP); + ASSERT( bOk ); + m_pHookedWnd->InvalidateRect(pRoot, FALSE); + } + + panels.RemoveAll(); + GetUIPanels(pRoot, &panels, TRUE); + pos = panels.GetHeadPosition(); + while (pos != NULL) + { + CUIPanel * pPanel = (CUIPanel *) panels.GetNext(pos); + m_pHookedWnd->GetDlgItem(pPanel->m_uID)->MoveWindow(pPanel); + } +} + + +void CWndResizer::OnLButtonDown(UINT nFlags, CPoint point) +{ + UpdateSplitterOffset(point); +} +void CWndResizer::OnMouseMove(UINT nFlags, CPoint point) +{ + if (m_pCaptured != NULL ) + { + if ((nFlags & MK_LBUTTON) <= 0) + { + CPoint ptScreen = point; + m_pHookedWnd->ClientToScreen(&ptScreen); + HWND hWndFromPoint = ::WindowFromPoint(ptScreen); + if (m_pCaptured->PtInRect( point ) == FALSE || hWndFromPoint != m_pHookedWnd->m_hWnd) + { + ::ReleaseCapture(); + m_pCaptured = NULL; + HCURSOR hCur = ::SetCursor(m_hOldCursor); + ::DestroyCursor( hCur ); + m_hOldCursor = NULL; + } + } + } + + if (m_pCaptured == NULL ) + { + m_pCaptured = FindSplitterFromPoint(&root, point); + if (m_pCaptured != NULL) + { + m_pHookedWnd->SetCapture(); + LPCTSTR cursor = NULL; + CSplitContainer * pSplitContainer = (CSplitContainer *)m_pCaptured->Parent; + if (pSplitContainer->m_Orientation == SPLIT_CONTAINER_H) + { + cursor = IDC_SIZEWE; + } + else + { + cursor = IDC_SIZENS; + } + HCURSOR hCur = AfxGetApp()->LoadStandardCursor(cursor); + HCURSOR m_hOldCursor = ::SetCursor(hCur); + } + } + + if (m_pCaptured != NULL && (nFlags & MK_LBUTTON) > 0) + { + CSplitContainer * pSplitterContainer = (CSplitContainer *) m_pCaptured->Parent; + + if (pSplitterContainer->m_Orientation == SPLIT_CONTAINER_H) + { + pSplitterContainer->SetSplitterPosition( point.x - m_splitterOffset); + } + else + { + pSplitterContainer->SetSplitterPosition( point.y - m_splitterOffset); + } + UpdateSplitterOffset(point); + + ResizeUI(pSplitterContainer); + + } +} +void CWndResizer::OnLButtonUp(UINT nFlags, CPoint point) +{ + OnMouseMove(nFlags, point); +} +void CWndResizer::UpdateSplitterOffset(CPoint ptCurr) +{ + if (m_pCaptured == NULL ) + { + return; + } + if (((CSplitContainer *)m_pCaptured->Parent)->m_Orientation == SPLIT_CONTAINER_H) + { + if ( ptCurr.x < m_pCaptured->left) + { + m_splitterOffset = 0; + } + else if ( ptCurr.x > m_pCaptured->right) + { + m_splitterOffset = m_pCaptured->Width(); + } + else + { + m_splitterOffset = ptCurr.x - m_pCaptured->left; + } + } + else + { + if ( ptCurr.y < m_pCaptured->top) + { + m_splitterOffset = 0; + } + else if ( ptCurr.y > m_pCaptured->bottom) + { + m_splitterOffset = m_pCaptured->Height(); + } + else + { + m_splitterOffset = ptCurr.y - m_pCaptured->top; + } + } +} +void CWndResizer::OnSizing(UINT fwSide, LPRECT pRect) +{ + + CRect * prc = (CRect *) pRect; + + CRect rcMin(0, 0, root.MinSize.cx, root.MinSize.cy); + CRect rcMax(0, 0, root.MaxSize.cx, root.MaxSize.cy); + + LONG_PTR style = GetWindowLongPtr(m_pHookedWnd->m_hWnd , GWL_STYLE); + LONG_PTR styleEx = GetWindowLongPtr(m_pHookedWnd->m_hWnd, GWL_EXSTYLE); + + ::AdjustWindowRectEx(&rcMin, (DWORD) style, (m_pHookedWnd->GetMenu() != NULL), (DWORD) styleEx); + ::AdjustWindowRectEx(&rcMax, (DWORD) style, (m_pHookedWnd->GetMenu() != NULL), (DWORD) styleEx); + + switch (fwSide) + { + case WMSZ_BOTTOM: + if (prc->Height() < rcMin.Height() ) + { + prc->bottom = prc->top + rcMin.Height(); + } + if (prc->Height() > rcMax.Height() ) + { + prc->bottom = prc->top + rcMax.Height(); + } + break; + case WMSZ_BOTTOMLEFT: + if (prc->Height() < rcMin.Height() ) + { + prc->bottom = prc->top + rcMin.Height(); + } + if (prc->Width() < rcMin.Width() ) + { + prc->left = prc->right - rcMin.Width(); + } + + if (prc->Height() > rcMax.Height() ) + { + prc->bottom = prc->top + rcMax.Height(); + } + if (prc->Width() > rcMax.Width() ) + { + prc->left = prc->right - rcMax.Width(); + } + break; + case WMSZ_BOTTOMRIGHT: + if (prc->Height() < rcMin.Height() ) + { + prc->bottom = prc->top + rcMin.Height(); + } + if (prc->Width() < rcMin.Width() ) + { + prc->right = prc->left + rcMin.Width(); + } + + if (prc->Height() > rcMax.Height() ) + { + prc->bottom = prc->top + rcMax.Height(); + } + if (prc->Width() > rcMax.Width() ) + { + prc->right = prc->left + rcMax.Width(); + } + + break; + case WMSZ_LEFT: + if (prc->Width() < rcMin.Width() ) + { + prc->left = prc->right - rcMin.Width(); + } + + if (prc->Width() > rcMax.Width() ) + { + prc->left = prc->right - rcMax.Width(); + } + break; + case WMSZ_RIGHT: + if (prc->Width() < rcMin.Width() ) + { + prc->right = prc->left + rcMin.Width(); + } + + if (prc->Width() > rcMax.Width() ) + { + prc->right = prc->left + rcMax.Width(); + } + break; + case WMSZ_TOP: + if (prc->Height() < rcMin.Height() ) + { + prc->top = prc->bottom - rcMin.Height(); + } + + if (prc->Height() > rcMax.Height() ) + { + prc->top = prc->bottom - rcMax.Height(); + } + break; + case WMSZ_TOPLEFT: + if (prc->Height() < rcMin.Height() ) + { + prc->top = prc->bottom - rcMin.Height(); + } + if (prc->Width() < rcMin.Width() ) + { + prc->left = prc->right - rcMin.Width(); + } + + + if (prc->Height() > rcMax.Height() ) + { + prc->top = prc->bottom - rcMax.Height(); + } + if (prc->Width() > rcMax.Width() ) + { + prc->left = prc->right - rcMax.Width(); + } + break; + case WMSZ_TOPRIGHT: + if (prc->Height() < rcMin.Height() ) + { + prc->top = prc->bottom - rcMin.Height(); + } + if (prc->Width() < rcMin.Width() ) + { + prc->right = prc->left + rcMin.Width(); + } + + if (prc->Height() > rcMax.Height() ) + { + prc->top = prc->bottom - rcMax.Height(); + } + if (prc->Width() > rcMax.Width() ) + { + prc->right = prc->left + rcMax.Width(); + } + break; + } + +} + +void CWndResizer::OnPaint() +{ + if (m_pHookedWnd == NULL) + { + return; + } + CPaintDC dc(m_pHookedWnd); // device context for painting + + CPanelList panelList; + GetVisualPanels(&root, &panelList); + POSITION pos = panelList.GetHeadPosition(); + while (pos != NULL) + { + CVisualPanel * pPanel = (CVisualPanel *) panelList.GetNext(pos); + if (pPanel->m_bVisible) + { + pPanel->Draw(&dc); + } + } + +} + + +BOOL CWndResizer::SetAnchor(LPCTSTR panelName, UINT uAnchor) +{ + // container must already exist + CPanel * pPanel = NULL; + if ( (pPanel = FindPanelByName(&root, panelName)) == NULL) + { + return FALSE; + } + + return pPanel->SetAnchor(uAnchor); +} + +BOOL CWndResizer::SetAnchor(UINT uID, UINT uAnchor) +{ + ASSERT(m_pHookedWnd != NULL); + + CUIPanel * pPanel = GetUIPanel(uID); + + if (pPanel == NULL) + { + return FALSE; + } + pPanel->SetAnchor(uAnchor); + + return TRUE; +} +BOOL CWndResizer::GetAnchor(LPCTSTR panelName, UINT & anchor) +{ + CPanel * pPanel = NULL; + if ( (pPanel = FindPanelByName(&root, panelName)) == NULL) // name of parent must already exist + { + return FALSE; + } + + anchor = pPanel->Anchor; + return TRUE; +} +BOOL CWndResizer::GetAnchor(UINT uID, UINT & anchor) +{ + CPanel * pPanel = NULL; + if ( (pPanel = FindPanelByName(&root, IdToName(uID))) == NULL) // name of parent must already exist + { + return FALSE; + } + + anchor = pPanel->Anchor; + return TRUE; +} +///////////////////////////////////////////////////////////////////////////////////////////////////////// + +BOOL CWndResizer::SetDock(LPCTSTR panelName, UINT uDock) +{ + // container must already exist + CPanel * pPanel = NULL; + if ( (pPanel = FindPanelByName(&root, panelName)) == NULL) + { + return FALSE; + } + + pPanel->Dock = uDock ; + return TRUE; +} + +BOOL CWndResizer::SetDock(UINT uID, UINT uDock) +{ + ASSERT(m_pHookedWnd != NULL); + + CUIPanel * pPanel = GetUIPanel(uID); + + if (pPanel == NULL) + { + return FALSE; + } + pPanel->Dock = uDock; + + return TRUE; +} +BOOL CWndResizer::GetDock(LPCTSTR panelName, UINT & uDock) +{ + CPanel * pPanel = NULL; + if ( (pPanel = FindPanelByName(&root, panelName)) == NULL) // name of parent must already exist + { + return FALSE; + } + + uDock = pPanel->Dock; + return TRUE; +} +BOOL CWndResizer::GetDock(UINT uID, UINT & uDock) +{ + CPanel * pPanel = NULL; + if ( (pPanel = FindPanelByName(&root, IdToName(uID))) == NULL) // name of parent must already exist + { + return FALSE; + } + + uDock = pPanel->Dock; + return TRUE; +} + + +////////////////////// +BOOL CWndResizer::SetParent(LPCTSTR panelName, LPCTSTR parentName) +{ + ASSERT(m_pHookedWnd != NULL); + + + // now make sure parentName is OK + CPanel * pParent = NULL; + if ( (pParent = FindPanelByName(&root, parentName)) == NULL) // name of parent must already exist + { + return FALSE; + } + + // make sure panelName exist + CPanel * pPanel = NULL; + if ((pPanel = FindPanelByName(&root, panelName)) == NULL) + { + return FALSE; + } + + return pParent->AddChild(pPanel); +} +BOOL CWndResizer::SetParent(UINT uID, LPCTSTR parentName) +{ + ASSERT(m_pHookedWnd != NULL); + + // now make sure parentName is OK + CPanel * pParent = NULL; + if ( (pParent = FindPanelByName(&root, parentName)) == NULL) // name of parent must already exist + { + return FALSE; + } + CPanel * pPanel = NULL; + + // first see if it is already defined + if ((pPanel = FindPanelByName(&root, IdToName(uID))) == NULL) + { + if ((pPanel = CreateUIPanel(uID)) == NULL) + { + return FALSE; + } + } + + return pParent->AddChild(pPanel); + +} + +BOOL CWndResizer::SetParent(LPCTSTR panelName, UINT uParentID) +{ + ASSERT(m_pHookedWnd != NULL); + + // now make sure parentName is OK + CPanel * pParent = GetUIPanel(uParentID); + if ( pParent == NULL) // name of parent must already exist + { + return FALSE; + } + + // make sure panelName exist + CPanel * pPanel = NULL; + if ((pPanel = FindPanelByName(&root, panelName)) == NULL) + { + return FALSE; + } + + return pParent->AddChild(pPanel); + +} +BOOL CWndResizer::SetParent(UINT uID, UINT uParentID) +{ + CPanel * pParent = GetUIPanel(uParentID); + if (pParent == NULL) + { + return FALSE; + } + CPanel * pPanel = GetUIPanel(uID);; + if (pParent == NULL) + { + return FALSE; + } + + return pParent->AddChild( pPanel ); + +} + + +BOOL CWndResizer::GetParent(LPCTSTR panelName, CString & parentName) +{ + CPanel * pPanel = NULL; + if ( (pPanel = FindPanelByName(&root, panelName)) == NULL) + { + return FALSE; + } + + parentName = pPanel->Parent->Name; + return TRUE; +} +BOOL CWndResizer::GetParent(UINT uID, CString & parentName) +{ + CPanel * pPanel = NULL; + if ( (pPanel = FindPanelByName(&root, IdToName(uID))) == NULL) // name of parent must already exist + { + return FALSE; + } + + parentName = pPanel->Parent->Name; + return TRUE; +} + +BOOL CWndResizer::SetFixedPanel(LPCTSTR splitContainerName, short panel) +{ + CPanel * pContainer = FindPanelByName(&root, splitContainerName); + if (pContainer == NULL) + { + return FALSE; + } + CSplitContainer * pSplitContainer = dynamic_cast( pContainer ); + if (pSplitContainer == NULL) + { + return FALSE; + } + + pSplitContainer->SetFixedPanel(panel); + return TRUE; +} +BOOL CWndResizer::GetFixedPanel(LPCTSTR splitContainerName, short & panel) +{ + CPanel * pContainer = FindPanelByName(&root, splitContainerName); + if (pContainer == NULL) + { + return FALSE; + } + CSplitContainer * pSplitContainer = dynamic_cast (pContainer); + if (pSplitContainer == NULL) + { + return FALSE; + } + panel = pSplitContainer->GetFixedPanel(); + return TRUE; + +} + +BOOL CWndResizer::SetIsSplitterFixed(LPCTSTR splitContainerName, BOOL fixed) +{ + CPanel * pContainer = FindPanelByName(&root, splitContainerName); + if (pContainer == NULL) + { + return FALSE; + } + CSplitContainer * pSplitContainer = dynamic_cast (pContainer); + if (pSplitContainer == NULL) + { + return FALSE; + } + pSplitContainer->SetIsSplitterFixed( fixed ); + return TRUE; +} +BOOL CWndResizer::GetIsSplitterFixed(LPCTSTR splitContainerName, BOOL &fixed) +{ + CPanel * pContainer = FindPanelByName(&root, splitContainerName); + if (pContainer == NULL) + { + return FALSE; + } + CSplitContainer * pSplitContainer = dynamic_cast (pContainer); + if (pSplitContainer == NULL) + { + return FALSE; + } + fixed = pSplitContainer->GetIsSplitterFixed(); + return TRUE; +} + + + +BOOL CWndResizer::SetShowSplitterGrip(LPCTSTR splitContainerName, BOOL bShow) +{ + CPanel * pContainer = FindPanelByName(&root, splitContainerName); + if (pContainer == NULL) + { + return FALSE; + } + CSplitContainer * pSplitContainer = dynamic_cast (pContainer); + if (pSplitContainer == NULL) + { + return FALSE; + } + pSplitContainer->SetShowSplitterGrip( bShow ); + return TRUE; +} +BOOL CWndResizer::GetShowSplitterGrip(LPCTSTR splitContainerName, BOOL &bShow) +{ + CPanel * pContainer = FindPanelByName(&root, splitContainerName); + if (pContainer == NULL) + { + return FALSE; + } + CSplitContainer * pSplitContainer = dynamic_cast (pContainer); + if (pSplitContainer == NULL) + { + return FALSE; + } + bShow = pSplitContainer->GetShowSplitterGrip(); + return TRUE; +} + + + + +///////////////////////// +BOOL CWndResizer::SetMinimumSize( LPCTSTR panelName, CSize & size) +{ + CPanel * pPanel = NULL; + + if ( (pPanel = FindPanelByName(&root, panelName)) == NULL) + { + return FALSE; + } + return pPanel->SetMinSize( size ); +} +BOOL CWndResizer::SetMinimumSize(UINT uID, CSize & size) +{ + CPanel * pPanel = NULL; + + if ( (pPanel = FindPanelByName(&root, IdToName(uID))) == NULL) + { + if ((pPanel = CreateUIPanel(uID)) == NULL) + { + return FALSE; + } + } + + return pPanel->SetMinSize( size ); +} + +BOOL CWndResizer::GetMinimumSize(LPCTSTR panelName, CSize & size) +{ + CPanel * pPanel = NULL; + + if ( (pPanel = FindPanelByName(&root, panelName)) == NULL) + { + return FALSE; + } + + size = pPanel->MinSize; + return TRUE; +} +BOOL CWndResizer::GetMinimumSize(UINT uID, CSize & size) +{ + const CPanel * pPanel = NULL; + + if ( (pPanel = FindPanelByName(&root, IdToName(uID))) == NULL) + { + return FALSE; + } + + size = pPanel->MinSize; + return TRUE; +} +BOOL CWndResizer::SetMaximumSize(UINT uID, CSize & size) +{ + CPanel * pPanel = NULL; + + if ( (pPanel = FindPanelByName(&root, IdToName(uID))) == NULL) + { + return FALSE; + } + + return pPanel->SetMaxSize(size); +} + +BOOL CWndResizer::SetMaximumSize( LPCTSTR panelName, CSize & size) +{ + CPanel * pPanel = NULL; + + if ( (pPanel = FindPanelByName(&root, panelName)) == NULL) + { + return FALSE; + } + + return pPanel->SetMaxSize(size); + +} +BOOL CWndResizer::GetMaximumSize( LPCTSTR panelName, CSize & size) +{ + CPanel * pPanel = NULL; + if ( (pPanel = FindPanelByName(&root, panelName)) == NULL) + { + return FALSE; + } + + size = pPanel->MaxSize; + return TRUE; +} +BOOL CWndResizer::GetMaximumSize( UINT uID, CSize & size) +{ + CPanel * pPanel = NULL; + if ( (pPanel = FindPanelByName(&root, IdToName(uID))) == NULL) + { + return FALSE; + } + + size = pPanel->MaxSize; + return TRUE; +} +void CWndResizer::SetShowResizeGrip(BOOL show) +{ + CGripperPanel * pPanel = (CGripperPanel *)FindPanelByName(&root, _T("_resizeGrip")); + ASSERT(pPanel != NULL); + if ( pPanel->m_bVisible != show ) + { + pPanel->m_bVisible = show; + m_pHookedWnd->Invalidate(TRUE); + } +} +BOOL CWndResizer::GetShowResizeGrip() +{ + CGripperPanel * pPanel = (CGripperPanel *)FindPanelByName(&root, _T("_resizeGrip")); + ASSERT(pPanel != NULL); + return pPanel->m_bVisible ; + +} +void CWndResizer::OnDestroy() +{ + if (m_pHookedWnd != NULL) + { + Unhook(); + } +} + +BOOL CWndResizer::Unhook() +{ + ASSERT( m_pHookedWnd != NULL ); + if (m_pHookedWnd == NULL ) + { + return FALSE; //hasent been hooked + } + + WNDPROC pWndProc = (WNDPROC)::SetWindowLongPtr(m_pHookedWnd->m_hWnd, GWLP_WNDPROC, (LONG_PTR)m_pfnWndProc); + WndResizerData.RemoveKey(m_pHookedWnd->m_hWnd); + root.m_pHookWnd = NULL; + m_pHookedWnd = NULL; + + // destroy all chilldren + while(root.Children.GetCount() > 0 ) + { + CPanel * pChild = root.Children.RemoveHead(); + delete pChild; + } + return TRUE; +} + + +LRESULT CALLBACK CWndResizer::WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + CWndResizer * pResizer = NULL; + WndResizerData.Lookup(hWnd, pResizer); + ASSERT( pResizer != NULL); + + + switch (uMsg) + { + case WM_SIZE: + { + int cx = 0; + int cy = 0; + cx = LOWORD(lParam); + cy = HIWORD(lParam); + pResizer->OnSize((UINT) wParam, cx, cy); + } + break; + case WM_SIZING: + pResizer->OnSizing((UINT) wParam, (LPRECT)lParam); + break; + case WM_DESTROY: + pResizer->OnDestroy(); + break; + case WM_MOUSEMOVE: + pResizer->OnMouseMove((UINT) wParam, CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); + break; + case WM_LBUTTONDOWN: + pResizer->OnLButtonDown((UINT) wParam, CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); + break; + case WM_LBUTTONUP: + pResizer->OnLButtonUp((UINT) wParam, CPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); + break; + case WM_PAINT: + pResizer->OnPaint(); + break; + case WM_HSCROLL: + case WM_VSCROLL: + pResizer->OnScroll(); + break; + + //case WM_ERASEBKGND: + // return FALSE; + // break; + default: + break; + } + + return ::CallWindowProc(pResizer->m_pfnWndProc, hWnd, uMsg, wParam, lParam); + + +} + + + +BOOL CWndResizer::CreateSplitContainer(LPCTSTR panelName, LPCTSTR panelNameA, LPCTSTR panelNameB) +{ + CPanel * pPanel = NULL; + if ((pPanel = FindPanelByName(&root, panelName)) != NULL) + { + return FALSE; + } + + CPanel * pPanelA = NULL; + if ((pPanelA = FindPanelByName(&root, panelNameA)) == NULL) + { + return FALSE; + } + + + CPanel * pPanelB = NULL; + if ((pPanelB = FindPanelByName(&root, panelNameB)) == NULL) + { + return FALSE; + } + + + if (pPanelA == pPanelB) // two panel cannot be same + { + return FALSE; + } + + + CPanel * pSplitterContainer = CSplitContainer::Create(pPanelA, pPanelB); + if (pSplitterContainer == NULL) + { + return FALSE; + } + pSplitterContainer->Name = panelName; + + return root.AddChild(pSplitterContainer); +} + + + +BOOL CWndResizer::CreateSplitContainer(LPCTSTR panelName, LPCTSTR panelNameA, UINT panelIDB) +{ + CPanel * pPanel = NULL; + if ((pPanel = FindPanelByName(&root, panelName)) != NULL) + { + return FALSE; + } + + CPanel * pPanelA = NULL; + if ((pPanelA = FindPanelByName(&root, panelNameA)) == NULL) + { + return FALSE; + } + + CPanel * pPanelB = GetUIPanel(panelIDB); + if (pPanelB == NULL ) + { + return FALSE; + } + + + if (pPanelA == pPanelB) // two panel cannot be same + { + return FALSE; + } + + // first lets make sure the two CRect are properly set + + CPanel * pSplitterContainer = CSplitContainer::Create(pPanelA, pPanelB); + if (pSplitterContainer == NULL) + { + return FALSE; + } + pSplitterContainer->Name = panelName; + + return root.AddChild(pSplitterContainer); + +} + + +BOOL CWndResizer::CreateSplitContainer(LPCTSTR panelName, UINT panelIDA, LPCTSTR panelNameB) +{ + CPanel * pPanel = NULL; + if ((pPanel = FindPanelByName(&root, panelName)) != NULL) + { + return FALSE; + } + + CPanel * pPanelA = GetUIPanel(panelIDA); + if (pPanelA == NULL ) + { + return FALSE; + } + + + CPanel * pPanelB = NULL; + if ((pPanelB = FindPanelByName(&root, panelNameB)) == NULL) + { + return FALSE; + } + + if (pPanelA == pPanelB) // two panel cannot be same + { + return FALSE; + } + + CPanel * pSplitterContainer = CSplitContainer::Create(pPanelA, pPanelB); + if (pSplitterContainer == NULL) + { + return FALSE; + } + pSplitterContainer->Name.Append(panelName); + + return root.AddChild(pSplitterContainer); + +} + + + +BOOL CWndResizer::CreateSplitContainer(LPCTSTR panelName, UINT panelIDA, UINT panelIDB) +{ + CPanel * pPanel = NULL; + if ((pPanel = FindPanelByName(&root, panelName)) != NULL) + { + return FALSE; + } + + CPanel * pPanelA = GetUIPanel(panelIDA); + if (pPanelA == NULL ) + { + return FALSE; + } + + + CPanel * pPanelB = GetUIPanel(panelIDB); + if (pPanelB == NULL ) + { + return FALSE; + } + + if (pPanelA == pPanelB) // two panel cannot be same + { + return FALSE; + } + + CPanel * pSplitterContainer = CSplitContainer::Create(pPanelA, pPanelB); + if (pSplitterContainer == NULL) + { + return FALSE; + } + pSplitterContainer->Name = panelName; + + return root.AddChild(pSplitterContainer); + +} + +BOOL CWndResizer::SetSplitterPosition(LPCTSTR splitContainerName, UINT position) +{ + ASSERT(m_pHookedWnd != NULL); + CPanel * pPanel = NULL; + if ((pPanel = FindPanelByName(&root, splitContainerName)) == NULL) + { + return FALSE; + } + CSplitContainer * pContainer = dynamic_cast ( pPanel); + if (pContainer == NULL) + { + return FALSE; + } + pContainer->SetSplitterPosition( (int) position); + ResizeUI( pContainer ); + return TRUE; +} +BOOL CWndResizer::GetSplitterPosition(LPCTSTR splitContainerName, UINT & position) +{ + ASSERT(m_pHookedWnd != NULL); + CPanel * pPanel = NULL; + if ((pPanel = FindPanelByName(&root, splitContainerName)) == NULL) + { + return FALSE; + } + CSplitContainer * pContainer = dynamic_cast ( pPanel); + if (pContainer == NULL) + { + return FALSE; + } + position = (UINT) pContainer->GetSplitterPosition(); + return TRUE; +} + +BOOL CWndResizer::CreatePanel(UINT uID) +{ + ASSERT(m_pHookedWnd != NULL); + if (FindPanelByName(&root, IdToName(uID)) != NULL) + { + return FALSE; + } + CUIPanel * pPanel = GetUIPanel(uID); + ASSERT(pPanel != NULL); + + pPanel->m_bOle = TRUE; + + return TRUE; +} + +BOOL CWndResizer::SetFlowDirection(LPCTSTR flowPanelName, short direction) +{ + ASSERT(m_pHookedWnd != NULL); + CPanel * pPanel = NULL; + if ((pPanel = FindPanelByName(&root, flowPanelName)) == NULL) + { + return FALSE; + } + CFlowLayoutPanel * pFlowLayout = dynamic_cast ( pPanel); + if (pFlowLayout == NULL) + { + return FALSE; + } + pFlowLayout->SetFlowDirection( direction == 1 ? LEFT_TO_RIGHT : TOP_TO_BOTTOM); + return TRUE; +} +BOOL CWndResizer::GetFlowDirection(LPCTSTR flowPanelName, short &direction) +{ + ASSERT(m_pHookedWnd != NULL); + CPanel * pPanel = NULL; + if ((pPanel = FindPanelByName(&root, flowPanelName)) == NULL) + { + return FALSE; + } + CFlowLayoutPanel * pFlowLayout = dynamic_cast ( pPanel); + if (pFlowLayout == NULL) + { + return FALSE; + } + direction = (pFlowLayout->GetFlowDirection() == LEFT_TO_RIGHT ? 1 : 2); + return TRUE; +} + +BOOL CWndResizer::SetFlowItemSpacingX(LPCTSTR flowPanelName, int nSpacing) +{ + ASSERT(m_pHookedWnd != NULL); + CPanel * pPanel = NULL; + if ((pPanel = FindPanelByName(&root, flowPanelName)) == NULL) + { + return FALSE; + } + CFlowLayoutPanel * pFlowLayout = dynamic_cast ( pPanel); + if (pFlowLayout == NULL) + { + return FALSE; + } + pFlowLayout->SetItemSpacingX(nSpacing); + return TRUE; +} +BOOL CWndResizer::GetFlowItemSpacingX(LPCTSTR flowPanelName, int &nSpacing) +{ + ASSERT(m_pHookedWnd != NULL); + CPanel * pPanel = NULL; + if ((pPanel = FindPanelByName(&root, flowPanelName)) == NULL) + { + return FALSE; + } + CFlowLayoutPanel * pFlowLayout = dynamic_cast ( pPanel); + if (pFlowLayout == NULL) + { + return FALSE; + } + nSpacing = pFlowLayout->GetItemSpacingX(); + return TRUE; +} + +BOOL CWndResizer::SetFlowItemSpacingY(LPCTSTR flowPanelName, int nSpacing) +{ + ASSERT(m_pHookedWnd != NULL); + CPanel * pPanel = NULL; + if ((pPanel = FindPanelByName(&root, flowPanelName)) == NULL) + { + return FALSE; + } + CFlowLayoutPanel * pFlowLayout = dynamic_cast ( pPanel); + if (pFlowLayout == NULL) + { + return FALSE; + } + pFlowLayout->SetItemSpacingY(nSpacing); + return TRUE; + +} + +BOOL CWndResizer::GetFlowItemSpacingY(LPCTSTR flowPanelName, int &nSpacing) +{ + ASSERT(m_pHookedWnd != NULL); + CPanel * pPanel = NULL; + if ((pPanel = FindPanelByName(&root, flowPanelName)) == NULL) + { + return FALSE; + } + CFlowLayoutPanel * pFlowLayout = dynamic_cast ( pPanel); + if (pFlowLayout == NULL) + { + return FALSE; + } + nSpacing = pFlowLayout->GetItemSpacingY(); + return TRUE; + +} + + +BOOL CWndResizer::CreateFlowLayoutPanel(LPCTSTR panelName, const CRect * prcPanel) +{ + if (FindPanelByName(&root, panelName) != NULL) + { + return FALSE; + } + + CPanel * pPanel = new CFlowLayoutPanel(prcPanel); + pPanel->Name = panelName; + return root.AddChild(pPanel); + +} +BOOL CWndResizer::CreateFlowLayoutPanel(LPCTSTR panelName, const CUIntArray * parrID, BOOL setAsChildren) +{ + ASSERT(m_pHookedWnd != NULL); + + CRect rcFinal(0, 0, 0, 0); + for(int i = 0; i < parrID->GetCount(); i++) + { + CRect rc(0, 0, 0, 0); + m_pHookedWnd->GetDlgItem(parrID->GetAt(i))->GetWindowRect(&rc); + m_pHookedWnd->ScreenToClient(&rc); + rcFinal.UnionRect(&rcFinal, &rc); + } + + BOOL bOk = CreateFlowLayoutPanel(panelName, &rcFinal); + if (bOk == FALSE) + { + return FALSE; + } + + if ( setAsChildren ) + { + CPanel * pPanel = FindPanelByName(&root, panelName); + for(int i = 0; i < parrID->GetCount(); i++) + { + if (FindPanelByName(&root, IdToName(parrID->GetAt(i))) != NULL) + { + bOk = root.RemoveChild(pPanel); + ASSERT( bOk ); + delete pPanel; + return FALSE; + } + CUIPanel * pUIPanel = GetUIPanel(parrID->GetAt(i)); + ASSERT( pUIPanel != NULL); + bOk = pPanel->AddChild( pUIPanel ); + ASSERT( bOk ); + } + } + return TRUE; +} + +BOOL CWndResizer::CreatePanel(LPCTSTR panelName, const CRect * prcPanel) +{ + if (FindPanelByName(&root, panelName) != NULL) + { + return FALSE; + } + + CPanel * pPanel = new CPanel(prcPanel); + pPanel->Name = panelName; + return root.AddChild(pPanel); + +} +BOOL CWndResizer::CreatePanel(LPCTSTR panelName, const CUIntArray * parrID, BOOL setAsChildren) +{ + ASSERT(m_pHookedWnd != NULL); + + CRect rcFinal(0, 0, 0, 0); + for(int i = 0; i < parrID->GetCount(); i++) + { + CRect rc(0, 0, 0, 0); + m_pHookedWnd->GetDlgItem(parrID->GetAt(i))->GetWindowRect(&rc); + m_pHookedWnd->ScreenToClient(&rc); + rcFinal.UnionRect(&rcFinal, &rc); + } + + BOOL bOk = CreatePanel(panelName, &rcFinal); + if (bOk == FALSE) + { + return FALSE; + } + + if ( setAsChildren ) + { + CPanel * pPanel = FindPanelByName(&root, panelName); + for(int i = 0; i < parrID->GetCount(); i++) + { + if (FindPanelByName(&root, IdToName(parrID->GetAt(i))) != NULL) + { + bOk = root.RemoveChild(pPanel); + ASSERT( bOk ); + delete pPanel; + return FALSE; + } + CUIPanel * pUIPanel = GetUIPanel(parrID->GetAt(i)); + ASSERT( pUIPanel != NULL); + bOk = pPanel->AddChild( pUIPanel ); + ASSERT( bOk ); + } + } + return TRUE; +} + +CPanel * CWndResizer::FindPanelByName(CPanel * pRoot, LPCTSTR name) +{ + if (CString(name).GetLength() == 0) + { + return NULL; + } + + if (pRoot == NULL ) + { + return NULL; + } + + if (pRoot->Name.CompareNoCase(name) == 0 ) + { + return pRoot; + } + else + { + POSITION pos = pRoot->Children.GetHeadPosition(); + while(pos != NULL) + { + CPanel * pChild = pRoot->Children.GetNext(pos); + CPanel * pFound = FindPanelByName(pChild, name); + if (pFound != NULL ) + { + return pFound; + } + } + } + + return NULL; +} +void CWndResizer::GetUIPanels(CPanel * pRoot, CPanelList * pList, BOOL bOle) +{ + if (pRoot == NULL ) + { + return ; + } + + CUIPanel * pUIPanel = dynamic_cast ( pRoot); + + if (pUIPanel != NULL && pUIPanel->m_bOle == bOle) + { + pList->AddTail( pRoot ); + } + + // try the childreen + POSITION pos = pRoot->Children.GetHeadPosition(); + while(pos != NULL) + { + CPanel * pChild = pRoot->Children.GetNext(pos); + GetUIPanels(pChild, pList, bOle); + + } + +} + +void CWndResizer::GetVisualPanels(CPanel * pRoot, CPanelList * pList) +{ + if (pRoot == NULL ) + { + return ; + } + + CVisualPanel * pUIPanel = dynamic_cast ( pRoot); + + if (pUIPanel != NULL) + { + pList->AddTail( pRoot ); + } + + // try the childreen + POSITION pos = pRoot->Children.GetHeadPosition(); + while(pos != NULL) + { + CPanel * pChild = pRoot->Children.GetNext(pos); + GetVisualPanels(pChild, pList); + } +} + + +CPanel * CWndResizer::FindSplitterFromPoint(CPanel * pRoot, CPoint point) +{ + if (pRoot == NULL ) + { + return NULL; + } + + CSpitterPanel * pSpitterPanel = dynamic_cast(pRoot); + + if (pSpitterPanel != NULL && pRoot->PtInRect(point) == TRUE ) + { + CSplitContainer * pContainer = (CSplitContainer *)pRoot->Parent; + if (!pContainer->GetIsSplitterFixed()) + { + CPoint ptScreen = point; + m_pHookedWnd->ClientToScreen(&ptScreen); + HWND hWndFromPoint = ::WindowFromPoint(ptScreen); + if (m_pHookedWnd->m_hWnd == hWndFromPoint) + { + return pRoot; + } + } + } + + // try the childreen + POSITION pos = pRoot->Children.GetHeadPosition(); + while(pos != NULL) + { + CPanel * pChild = pRoot->Children.GetNext(pos); + CPanel * pFound = FindSplitterFromPoint(pChild, point); + if (pFound != NULL ) + { + return pFound; + } + } + + + return NULL; +} + +CString CWndResizer::IdToName(UINT uID) +{ + CString sName; + sName.Format(_T("%d"), uID); + return sName; +} + +CUIPanel * CWndResizer::CreateUIPanel(UINT uID) +{ + ASSERT(m_pHookedWnd != NULL); + CWnd * pWnd = m_pHookedWnd->GetDlgItem(uID); + + if ( pWnd == NULL ) + { + return NULL; + } + CRect rc(0, 0, 0, 0); + pWnd->GetWindowRect( &rc ); + m_pHookedWnd->ScreenToClient( &rc ); + + CUIPanel * pPanel = new CUIPanel(&rc, uID); + pPanel->Name = IdToName(uID); + return pPanel ; +} + +CUIPanel * CWndResizer::GetUIPanel(UINT uID) +{ + CUIPanel * pPanel = NULL; + if ((pPanel = (CUIPanel *)FindPanelByName(&root, IdToName(uID))) == NULL) + { + pPanel = CreateUIPanel(uID); + if (pPanel != NULL) + { + root.AddChild( pPanel ); + } + } + return pPanel; +} + +BOOL CWndResizer::InvokeOnResized() +{ + ASSERT(m_pHookedWnd != NULL); + + OnSize(0, 0, 0); + return TRUE; +} + + +CString CWndResizer::GetDebugInfo() +{ + ASSERT(m_pHookedWnd != NULL); + + CString sInfo; + CString sIndent; + + GetDebugInfo(&root, sInfo, sIndent); + + return sInfo; +} +void CWndResizer::GetDebugInfo(CPanel * pRoot, CString & info, CString indent) +{ + if (pRoot == NULL ) + { + return ; + } + + info.Append(_T("\n")); + info.Append(indent); + info.Append(pRoot->ToString() ); + + indent.Append(_T(" ")); + for(int i = 0; i < pRoot->Children.GetCount(); i++) + { + CPanel * pChild = pRoot->Children.GetAt(pRoot->Children.FindIndex(i)); + GetDebugInfo(pChild, info, indent); + } + +} + + +///////////////////////////// CPanel +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +CPanel::CPanel() : CRect(0, 0, 0, 0) +{ + Init(); +} +CPanel::CPanel(const CRect * prc) : CRect(prc) +{ + Init(); +} +void CPanel::Init() +{ + Parent = NULL; + LeftOffset = 0; + TopOffset = 0; + RightOffset = 0; + BottomOffset = 0; + MinSize.SetSize(10, 10); + MaxSize.SetSize(100000, 100000); + Anchor =(ANCHOR_LEFT | ANCHOR_TOP); + Dock = DOCK_NONE; +} + +CPanel::~CPanel() +{ + while(Children.GetCount() > 0 ) + { + delete Children.RemoveHead(); + } +} +void CPanel::OnResized() +{ + BOOL bOk = FALSE; + CRect rcEmpty(this); // available area for docking. ininitally it is the entire area + + POSITION pos = Children.GetHeadPosition(); + while(pos != NULL) + { + CPanel * pChild = Children.GetNext(pos); + + if (pChild->Dock != DOCK_NONE) + { + switch(pChild->Dock) + { + case DOCK_LEFT: + pChild->SetRect(rcEmpty.left, rcEmpty.top, rcEmpty.left + pChild->Width(), rcEmpty.bottom); + bOk = rcEmpty.SubtractRect(&rcEmpty, pChild); + // ASSERT( bOk ); + break; + case DOCK_TOP: + pChild->SetRect(rcEmpty.left, rcEmpty.top, rcEmpty.right, rcEmpty.top + pChild->Height()); + bOk = rcEmpty.SubtractRect(&rcEmpty, pChild); + // ASSERT( bOk ); + break; + case DOCK_RIGHT: + pChild->SetRect(rcEmpty.right - pChild->Width(), rcEmpty.top, rcEmpty.right, rcEmpty.bottom); + bOk = rcEmpty.SubtractRect(&rcEmpty, pChild); + // ASSERT( bOk ); + break; + case DOCK_BOTTOM: + pChild->SetRect(rcEmpty.left, rcEmpty.bottom - pChild->Height(), rcEmpty.right, rcEmpty.bottom); + bOk = rcEmpty.SubtractRect(&rcEmpty, pChild); + // ASSERT( bOk ); + break; + case DOCK_FILL: + pChild->SetRect(rcEmpty.left, rcEmpty.top, rcEmpty.right, rcEmpty.bottom); + break; + } + pChild->OnResized(); + + // if docking is in action, then we igonre anchor, therefore we continue + continue; + } + + CRect rc(0, 0, 0, 0); + if ((pChild->Anchor & ANCHOR_HORIZONTALLY_CENTERED) == ANCHOR_HORIZONTALLY_CENTERED ) + { + rc.left = this->left + ((int)( (this->Width() - pChild->Width()) / 2)); + rc.right = rc.left + pChild->Width(); + + BOOL bReposition = FALSE; + if (pChild->MinSize.cx > rc.Width() ) + { + bReposition = TRUE; + rc.right = rc.left + pChild->MinSize.cx; + } + if (pChild->MaxSize.cx < rc.Width() ) + { + bReposition = TRUE; + rc.right = rc.left + pChild->MaxSize.cx; + } + + if (bReposition) + { + int nWidth = rc.Width(); + rc.left = (int)( (this->Width() - nWidth) / 2) ; + rc.right = rc.left + nWidth; + } + } + else if ((pChild->Anchor & ANCHOR_HORIZONTALLY) == ANCHOR_HORIZONTALLY ) + { + rc.left = this->left + pChild->LeftOffset; + rc.right = this->right - pChild->RightOffset; + + // we will be left anchor if minsize or maxsize does not match + // (giving ANCHOR_LEFT priority over ANCHOR_RIGHT) + if ((pChild->Anchor & ANCHOR_PRIORITY_RIGHT) == ANCHOR_PRIORITY_RIGHT) + { + if (pChild->MinSize.cx > rc.Width() ) + { + rc.left = rc.right - pChild->MinSize.cx; + } + if (pChild->MaxSize.cx < rc.Width() ) + { + rc.left = rc.right - pChild->MaxSize.cx; + } + + } + else + { + if (pChild->MinSize.cx > rc.Width() ) + { + rc.right = rc.left + pChild->MinSize.cx; + } + if (pChild->MaxSize.cx < rc.Width() ) + { + rc.right = rc.left + pChild->MaxSize.cx; + } + } + } + else if ((pChild->Anchor & ANCHOR_RIGHT) == ANCHOR_RIGHT ) + { + rc.right = this->right - pChild->RightOffset; + rc.left = rc.right - pChild->Width(); + + if (pChild->MinSize.cx > rc.Width() ) + { + rc.left = rc.right - pChild->MinSize.cx; + } + if (pChild->MaxSize.cx < rc.Width() ) + { + rc.left = rc.right - pChild->MaxSize.cx; + } + } + else if ((pChild->Anchor & ANCHOR_LEFT) == ANCHOR_LEFT ) + { + rc.left = this->left + pChild->LeftOffset; + rc.right = rc.left + pChild->Width(); + + if (pChild->MinSize.cx > rc.Width() ) + { + rc.right = rc.left + pChild->MinSize.cx; + } + if (pChild->MaxSize.cx < rc.Width() ) + { + rc.right = rc.left + pChild->MaxSize.cx; + } + } + else + { + // it should never be here + ASSERT( FALSE ); + } + + + if ((pChild->Anchor & ANCHOR_VERTICALLY_CENTERED) == ANCHOR_VERTICALLY_CENTERED ) + { + rc.top = this->top + ((int)( (this->Height() - pChild->Height()) / 2)); + rc.bottom = rc.top + pChild->Height(); + + BOOL bReposition = FALSE; + if (pChild->MinSize.cy > rc.Height() ) + { + bReposition = TRUE; + rc.bottom = rc.top + pChild->MinSize.cy; + } + if (pChild->MaxSize.cy < rc.Height() ) + { + bReposition = TRUE; + rc.bottom = rc.top + pChild->MaxSize.cy; + } + + if (bReposition) + { + int nHeight = rc.Height(); + rc.top = (int)( (this->Height() - nHeight) / 2); + rc.bottom = rc.top + nHeight; + } + } + else if ((pChild->Anchor & ANCHOR_VERTICALLY ) == ANCHOR_VERTICALLY ) + { + rc.top = this->top + pChild->TopOffset; + rc.bottom = this->bottom - pChild->BottomOffset; + + if ((pChild->Anchor & ANCHOR_PRIORITY_BOTTOM) == ANCHOR_PRIORITY_BOTTOM) + { + if (pChild->MinSize.cy > rc.Height() ) + { + rc.top = rc.bottom - pChild->MinSize.cy; + } + if (pChild->MaxSize.cy < rc.Height() ) + { + rc.top = rc.bottom - pChild->MaxSize.cy; + } + } + else + { + if (pChild->MinSize.cy > rc.Height() ) + { + rc.bottom = rc.top + pChild->MinSize.cy; + } + if (pChild->MaxSize.cy < rc.Height() ) + { + rc.bottom = rc.top + pChild->MaxSize.cy; + } + } + } + else if ((pChild->Anchor & ANCHOR_BOTTOM) == ANCHOR_BOTTOM ) + { + rc.bottom = this->bottom - pChild->BottomOffset; + rc.top = rc.bottom - pChild->Height(); + + if (pChild->MinSize.cy > rc.Height() ) + { + rc.top = rc.bottom - pChild->MinSize.cy; + } + if (pChild->MaxSize.cy < rc.Height() ) + { + rc.top = rc.bottom - pChild->MaxSize.cy; + } + } + else if ((pChild->Anchor & ANCHOR_TOP) == ANCHOR_TOP ) + { + rc.top = this->top + pChild->TopOffset; + rc.bottom = rc.top + pChild->Height(); + + if (pChild->MinSize.cy > rc.Height() ) + { + rc.bottom = rc.top + pChild->MinSize.cy; + } + if (pChild->MaxSize.cy < rc.Height() ) + { + rc.bottom = rc.top + pChild->MaxSize.cy; + } + } + else + { + // it should never be here + ASSERT( FALSE ); + } + pChild->SetRect(rc.TopLeft(), rc.BottomRight()); + + pChild->OnResized(); + + } +} +BOOL CPanel::AddChild(CPanel * pChild) +{ + if (pChild->Parent != NULL) + { + BOOL bOk = pChild->Parent->RemoveChild(pChild); + if (bOk == FALSE) + { + return FALSE; + } + } + pChild->LeftOffset = pChild->left - this->left; + pChild->TopOffset = pChild->top - this->top; + pChild->RightOffset = this->right - pChild->right; + pChild->BottomOffset = this->bottom - pChild->bottom; + + pChild->Parent = this; + + Children.AddTail( pChild ); + return TRUE; +} + +BOOL CPanel::RemoveChild(CPanel * pChild) +{ + POSITION pos = Children.Find(pChild); + if (pos == NULL) + { + return FALSE; + } + Children.RemoveAt(pos); + return TRUE; + +} + +BOOL CPanel::SetMinSize(CSize & size) +{ + if (MaxSize.cx < size.cx) + { + return FALSE; + } + if (MaxSize.cy < size.cy) + { + return FALSE; + } + + MinSize = size; + return TRUE; +} +BOOL CPanel::SetMaxSize(CSize & size) +{ + if (MinSize.cx > size.cx) + { + return FALSE; + } + if (MinSize.cy > size.cy) + { + return FALSE; + } + + MaxSize = size; + return TRUE; +} + +BOOL CPanel::SetAnchor(UINT anchor) +{ + if ((anchor & ANCHOR_VERTICALLY_CENTERED) <= 0 ) + { + if ((anchor & ANCHOR_TOP) <= 0 ) + { + if ((anchor & ANCHOR_BOTTOM) <= 0 ) + { + anchor |= ANCHOR_TOP; // default + } + } + } + + if ((anchor & ANCHOR_HORIZONTALLY_CENTERED) <= 0 ) + { + if ((anchor & ANCHOR_LEFT) <= 0 ) + { + if ((anchor & ANCHOR_RIGHT) <= 0 ) + { + anchor |= ANCHOR_LEFT; // default + } + } + } + Anchor = anchor; + + return TRUE; +} +CString CPanel::ToString() +{ + CString sFormat(_T("Name(%s), Type(%s), Anchor(%d), Size(w:%d, h:%d), Area(l:%d, t:%d, r:%d, b:%d), MinSize(w:%d, h:%d), MaxSize(w:%d, h:%d), Parent(%s), ChildrenCount(%d)")); + + CString sTo; + sTo.Format(sFormat, Name, GetTypeName(), Anchor, Width(), Height(), left, top, right, bottom, MinSize.cx, MinSize.cy, MaxSize.cx, MaxSize.cy, (Parent == NULL? _T("NULL") : Parent->Name), Children.GetCount()); + return sTo; +} +CString CPanel::GetTypeName() +{ + return _T("CPanel"); +} + +CWnd * CPanel::GetHookedWnd() +{ + if (Parent != NULL) + { + return Parent->GetHookedWnd(); + } + return NULL; +} + +///////////////////////////// CSplitContainer +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +CSplitContainer::CSplitContainer(CSplitPanel * pPanelA, CSplitPanel * pPanelB, SplitterOrientation type) : CPanel() +{ + m_IsSplitterFixed = FALSE; + m_FixedPanel = 0; + + m_pPanelA = NULL; + m_pPanelB = NULL; + m_pSplitter = NULL; + + m_Orientation = type; + m_pPanelA = pPanelA; + m_pPanelB = pPanelB; + UnionRect(m_pPanelA, m_pPanelB); + + CRect rc(0, 0, 0, 0); + GetSplitArea(&rc); + m_pSplitter = new CSpitterPanel(&rc, type); + m_pSplitter->m_pGrippePanel->m_bVisible = FALSE; + + + if (m_Orientation == SPLIT_CONTAINER_H) + { + m_pPanelA->Anchor = (ANCHOR_LEFT | ANCHOR_TOP | ANCHOR_BOTTOM); + m_pPanelB->Anchor = (ANCHOR_RIGHT | ANCHOR_TOP | ANCHOR_BOTTOM); + } + else + { + m_pPanelA->Anchor = (ANCHOR_LEFT | ANCHOR_TOP | ANCHOR_RIGHT); + m_pPanelB->Anchor = (ANCHOR_LEFT | ANCHOR_BOTTOM | ANCHOR_RIGHT); + } + + m_nSplitterSize = GetSplitterSize(m_pPanelA, m_pPanelB); + + BOOL bOk = AddChild(m_pPanelA); + ASSERT( bOk); + + bOk = AddChild(m_pSplitter); + ASSERT( bOk); + + bOk = AddChild(m_pPanelB); + ASSERT( bOk); + + UpdateRatio(); +} + +CSplitContainer::~CSplitContainer() +{ + +} + +void CSplitContainer::OnResized() +{ + CPanel::OnResized(); + + if (m_Orientation == SPLIT_CONTAINER_H) + { + if (Width() < MinSize.cx) + { + return; + } + + if (m_FixedPanel == 1 ) // left panel is fixed + { + m_pPanelB->left = m_pPanelA->right + m_nSplitterSize; + + if (m_pPanelB->MinSize.cx > m_pPanelB->Width() ) + { + m_pPanelB->left = m_pPanelB->right - m_pPanelB->MinSize.cx; + m_pPanelA->right = m_pPanelB->left - m_nSplitterSize; + } + } + else if (m_FixedPanel == 2 ) // right panel is fixed + { + m_pPanelA->right = m_pPanelB->left - m_nSplitterSize; + + if (m_pPanelA->MinSize.cx > m_pPanelA->Width() ) + { + m_pPanelA->right = m_pPanelA->left + m_pPanelA->MinSize.cx; + m_pPanelB->left = m_pPanelA->right + m_nSplitterSize; + } + } + else + { + m_pPanelA->right = (LONG) ((double)m_pPanelA->left + ((double)this->Width() * m_nRatio)); + + if (m_pPanelA->MinSize.cx > m_pPanelA->Width() ) + { + m_pPanelA->right = m_pPanelA->left + m_pPanelA->MinSize.cx; + } + + m_pPanelB->left = m_pPanelA->right + m_nSplitterSize; + + if (m_pPanelB->MinSize.cx > m_pPanelB->Width() ) + { + m_pPanelB->left = m_pPanelB->right - m_pPanelB->MinSize.cx; + m_pPanelA->right = m_pPanelB->left - m_nSplitterSize; + } + } + + } + else /*if (m_Orientation == SPLIT_CONTAINER_V)*/ + { + if (Height() < MinSize.cy) + { + return; + } + + if (m_FixedPanel == 1 ) // top panel is fixed + { + m_pPanelB->top = m_pPanelA->bottom + m_nSplitterSize; + + if (m_pPanelB->MinSize.cy > m_pPanelB->Height() ) + { + m_pPanelB->top = m_pPanelB->bottom - m_pPanelB->MinSize.cy; + m_pPanelA->bottom = m_pPanelB->top - m_nSplitterSize; + } + } + else if (m_FixedPanel == 2 ) // bottom panel is fixed + { + m_pPanelA->bottom = m_pPanelB->top - m_nSplitterSize; + + if (m_pPanelA->MinSize.cy > m_pPanelA->Height() ) + { + m_pPanelA->bottom = m_pPanelA->top + m_pPanelA->MinSize.cy; + m_pPanelB->top = m_pPanelA->bottom + m_nSplitterSize; + } + } + else + { + m_pPanelA->bottom = (LONG) ((double)m_pPanelA->top + ((double)this->Height() * m_nRatio)); + + if (m_pPanelA->MinSize.cy > m_pPanelA->Height() ) + { + m_pPanelA->bottom = m_pPanelA->top + m_pPanelA->MinSize.cy; + } + + m_pPanelB->top = m_pPanelA->bottom + m_nSplitterSize; + + if (m_pPanelB->MinSize.cy > m_pPanelB->Height() ) + { + m_pPanelB->top = m_pPanelB->bottom - m_pPanelB->MinSize.cy; + m_pPanelA->bottom = m_pPanelB->top - m_nSplitterSize; + } + } + + + } + + GetSplitArea(m_pSplitter); + m_pPanelA->OnResized(); + m_pPanelB->OnResized(); + m_pSplitter->OnResized(); + +} +void CSplitContainer::SetSplitterPosition(int leftOfSplitter) +{ + + short nFixedPanel = m_FixedPanel; + m_FixedPanel = 0; + if (m_Orientation == SPLIT_CONTAINER_H ) + { + m_pPanelA->right = leftOfSplitter; + m_pPanelB->left = m_pPanelA->right + m_nSplitterSize; + } + else + { + m_pPanelA->bottom = leftOfSplitter; + m_pPanelB->top = m_pPanelA->bottom + m_nSplitterSize; + } + UpdateRatio(); + + OnResized(); + + UpdateRatio(); + m_FixedPanel = nFixedPanel; + +} +int CSplitContainer::GetSplitterPosition() +{ + if (m_Orientation == SPLIT_CONTAINER_H ) + { + return m_pPanelA->right; + } + else + { + return m_pPanelA->bottom; + } +} +BOOL CSplitContainer::AddChild(CPanel * prc) +{ + if (Children.GetCount() == 3) + { + return FALSE; + } + return CPanel::AddChild(prc); + +} +BOOL CSplitContainer::RemoveChild(CPanel * prc) +{ + return FALSE; // cannot remove child from split container +} + +void CSplitContainer::GetSplitArea(CRect * pSplitterPanel) +{ + + if (m_Orientation == SPLIT_CONTAINER_H) + { + pSplitterPanel->left = m_pPanelA->right; + pSplitterPanel->top = this->top; + pSplitterPanel->right = m_pPanelB->left; + pSplitterPanel->bottom = this->bottom; + } + else // vertical + { + pSplitterPanel->left = this->left; + pSplitterPanel->top = m_pPanelA->bottom; + pSplitterPanel->right = this->right; + pSplitterPanel->bottom = m_pPanelB->top; + } +} +int CSplitContainer::GetSplitterSize(CPanel * m_pPanelA, CPanel * m_pPanelB) +{ + if (m_Orientation == SPLIT_CONTAINER_H) + { + int nWidth = m_pPanelB->left - m_pPanelA->right; + return nWidth; + } + else // vertical + { + int nHeight = m_pPanelB->top - m_pPanelA->bottom; + return nHeight; + } +} + + + + +void CSplitContainer::UpdateRatio() +{ + + if (m_Orientation == SPLIT_CONTAINER_H ) + { + m_nRatio = (double)m_pPanelA->Width() / (double)this->Width(); + } + else + { + m_nRatio = (double)m_pPanelA->Height() / (double)this->Height(); + } + +} + +CSplitContainer * CSplitContainer::Create(CPanel * pPanelA, CPanel * pPanelB) +{ + CSplitPanel * pSplitPanelA = dynamic_cast( pPanelA ); + if (pSplitPanelA != NULL) + { + return NULL; // already a part of a CSplitContainer + } + + CSplitPanel * pSplitPanelB = dynamic_cast( pPanelB ); + if (pSplitPanelB != NULL) + { + return NULL; // already a part of a CSplitContainer + } + + CRect rcDest(0, 0, 0, 0); + SplitterOrientation orien = SPLIT_CONTAINER_H; + + if (::IntersectRect(&rcDest, pPanelA, pPanelB) == TRUE) // invalid spliter container, a spliter continer's two panel cannot intersect each other + { + return NULL; + } + + + if (pPanelA->right < pPanelB->left) + { + orien = SPLIT_CONTAINER_H; + } + else if (pPanelA->bottom < pPanelB->top) + { + orien = SPLIT_CONTAINER_V; + } + else + { + return NULL; + } + if (pPanelA->Parent != NULL) + { + if (pPanelA->Parent->RemoveChild( pPanelA ) == FALSE) + { + return NULL; + } + } + if (pPanelB->Parent != NULL) + { + if (pPanelB->Parent->RemoveChild( pPanelB ) == FALSE) + { + return NULL; + } + } + + pSplitPanelA = new CSplitPanel( pPanelA ); + pSplitPanelB = new CSplitPanel( pPanelB ); + + + CSplitContainer * pSpliter = new CSplitContainer(pSplitPanelA, pSplitPanelB, orien); + return pSpliter; + +} + +CString CSplitContainer::GetTypeName() +{ + return _T("CSplitContainer"); +} + +void CSplitContainer::SetFixedPanel(short nFixedPanel /* 1=left/top; 2=right/bototm; other=no fixed panel */) +{ + m_FixedPanel = nFixedPanel; +} +short CSplitContainer::GetFixedPanel() +{ + return m_FixedPanel; +} +void CSplitContainer::SetIsSplitterFixed(BOOL bFixed) +{ + m_IsSplitterFixed = bFixed; +} +BOOL CSplitContainer::GetIsSplitterFixed() +{ + return m_IsSplitterFixed; +} +void CSplitContainer::SetShowSplitterGrip(BOOL bShow) +{ + m_pSplitter->m_pGrippePanel->m_bVisible = bShow; +} +BOOL CSplitContainer::GetShowSplitterGrip() +{ + return m_pSplitter->m_pGrippePanel->m_bVisible; +} + + +///////////////////////////// CRootPanel +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +CRootPanel::CRootPanel() : CPanel() +{ + m_pHookWnd = NULL; +} +CRootPanel::~CRootPanel() +{ + +} +CWnd * CRootPanel::GetHookedWnd() +{ + return m_pHookWnd; +} +CString CRootPanel::GetTypeName() +{ + return _T("CRootPanel"); +} +///////////////////////////// CUIPanel +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +CUIPanel::CUIPanel(const CRect * prc, UINT uID) : CPanel(prc) +{ + m_uID = uID; + m_bOle = FALSE; +} +CUIPanel::~CUIPanel() +{ + +} +CString CUIPanel::GetTypeName() +{ + return _T("CUIPanel"); +} + +///////////////////////////// CVisualPanel +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +CVisualPanel::CVisualPanel() : CPanel() +{ + m_bVisible = FALSE; + m_rcPrev.SetRect(0, 0, 0, 0); +} +CVisualPanel::CVisualPanel(const CRect * prc) : CPanel(prc) +{ + m_bVisible = FALSE; + m_rcPrev.SetRect(this->left, this->top, this->right, this->bottom); +} +CVisualPanel::~CVisualPanel() +{ + + +} +void CVisualPanel::Draw(CDC * pDC) +{ + +} +CString CVisualPanel::GetTypeName() +{ + return _T("CVisualPanel"); +} +void CVisualPanel::OnResized() +{ + CWnd * pWnd = NULL; + if ((pWnd = GetHookedWnd()) != NULL) + { + pWnd->InvalidateRect( &m_rcPrev, FALSE ); + pWnd->InvalidateRect( this, FALSE ); + } + m_rcPrev.SetRect(this->left, this->top, this->right, this->bottom); +} + +///////////////////////////// CGripperPanel +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +enum SCROLLBARPARTS { + SBP_ARROWBTN = 1, + SBP_THUMBBTNHORZ = 2, + SBP_THUMBBTNVERT = 3, + SBP_LOWERTRACKHORZ = 4, + SBP_UPPERTRACKHORZ = 5, + SBP_LOWERTRACKVERT = 6, + SBP_UPPERTRACKVERT = 7, + SBP_GRIPPERHORZ = 8, + SBP_GRIPPERVERT = 9, + SBP_SIZEBOX = 10, +}; +CGripperPanel::CGripperPanel() : CVisualPanel() +{ + m_hTheme = NULL; + m_iPartId = SBP_SIZEBOX; + m_iStateId = 5; //SZB_HALFBOTTOMRIGHTALIGN; + m_sClassName = _T("SCROLLBAR"); +} +CGripperPanel::CGripperPanel(const CRect * prc) : CVisualPanel(prc) +{ + m_hTheme = NULL; + m_iPartId = SBP_SIZEBOX; + m_iStateId = 5; //SZB_HALFBOTTOMRIGHTALIGN; + m_sClassName = _T("SCROLLBAR"); +} +CGripperPanel::~CGripperPanel() +{ + if (m_hTheme != NULL) + { + HRESULT lres = ::CloseThemeData(m_hTheme); + ASSERT(SUCCEEDED(lres) == TRUE); + m_hTheme = NULL; + } +} +void CGripperPanel::Draw(CDC * pDC) +{ + if (m_hTheme == NULL) + { + CWnd * pHookedWnd = GetHookedWnd(); + if (pHookedWnd == NULL) + { + return; + } + m_hTheme = ::OpenThemeData(pHookedWnd->m_hWnd, m_sClassName.AllocSysString()); + } + + if (m_hTheme == NULL) + { + BOOL bOk = pDC->DrawFrameControl(this, DFC_SCROLL, DFCS_SCROLLSIZEGRIP ); + ASSERT( bOk ); + } + else + { + HRESULT lres = ::DrawThemeBackground(m_hTheme, pDC->m_hDC, m_iPartId, m_iStateId, this, this); + ASSERT(SUCCEEDED(lres) == TRUE); + } +} + +CString CGripperPanel::GetTypeName() +{ + return _T("CGripperPanel"); +} + +///////////////////////////// CSplitterGripperPanel +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +CSplitterGripperPanel::CSplitterGripperPanel(SplitterOrientation type) : CVisualPanel() +{ + m_OrienType = type; +} +CSplitterGripperPanel::~CSplitterGripperPanel() +{ + +} +void CSplitterGripperPanel::Draw(CDC * pDC) +{ + CPen penDark(PS_SOLID, 1, ::GetSysColor(COLOR_3DSHADOW)); + CPen penWhite(PS_SOLID, 1, RGB(255, 255, 255)); + + if (m_OrienType == SPLIT_CONTAINER_H ) + { + CPen * pOrigPen = pDC->SelectObject(&penWhite); + + CRect rc(0, 0, 0, 0); + rc.SetRect(left + 1, top + 1, left + 3, top + 3); + while(rc.bottom <= bottom) + { + pDC->Rectangle(&rc); + rc.OffsetRect(0, 4); + } + + pDC->SelectObject(&penDark); + rc.SetRect(left, top, left + 2, top + 2); + while(rc.bottom <= bottom) + { + pDC->Rectangle(&rc); + rc.OffsetRect(0, 4); + } + + pDC->SelectObject(pOrigPen); + + } + else + { + CPen * pOrigPen = pDC->SelectObject(&penWhite); + + CRect rc(0, 0, 0, 0); + rc.SetRect(left + 1, top + 1, left + 3, top + 3); + while(rc.right <= right) + { + pDC->Rectangle(&rc); + rc.OffsetRect(4, 0); + } + + pDC->SelectObject(&penDark); + rc.SetRect(left, top, left + 2, top + 2); + while(rc.right <= right) + { + pDC->Rectangle(&rc); + rc.OffsetRect(4, 0); + } + + pDC->SelectObject(pOrigPen); + } +} + +CString CSplitterGripperPanel::GetTypeName() +{ + return _T("CSplitterGripperPanel"); +} + + +///////////////////////////// CSpitterPanel +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +CSpitterPanel::CSpitterPanel(const CRect * prc, SplitterOrientation type) : CPanel(prc) +{ + m_OrienType = type; + m_pGrippePanel = NULL; + + if (m_pGrippePanel == NULL) + { + m_pGrippePanel = new CSplitterGripperPanel(type); + if (m_OrienType == SPLIT_CONTAINER_H ) + { + m_pGrippePanel->SetRect(0, 0, 3, 12); + } + else + { + m_pGrippePanel->SetRect(0, 0, 12, 3); + } + m_pGrippePanel->SetAnchor ( ANCHOR_HORIZONTALLY_CENTERED | ANCHOR_VERTICALLY_CENTERED ); + m_pGrippePanel->SetMinSize(CSize(2,2)); + BOOL bOk = AddChild(m_pGrippePanel); + ASSERT( bOk); + } +} +CSpitterPanel::CSpitterPanel(SplitterOrientation type) : CPanel() +{ + m_OrienType = type; + m_pGrippePanel = NULL; + +} + +CSpitterPanel::~CSpitterPanel() +{ + +} + + +CString CSpitterPanel::GetTypeName() +{ + return _T("CSpitterPanel"); +} +///////////////////////////// CSpitPanel +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +CSplitPanel::CSplitPanel(CPanel * pPanel) : CPanel(pPanel) +{ + pPanel->LeftOffset = 0; + pPanel->TopOffset = 0; + pPanel->RightOffset = 0; + pPanel->BottomOffset = 0; + pPanel->Anchor = ANCHOR_ALL; + Name = pPanel->Name; + pPanel->Name = _T(""); + m_pOriginalPanel = pPanel; + MaxSize = pPanel->MaxSize; + MinSize = pPanel->MinSize; + Children.AddTail( pPanel ); +} + +CSplitPanel::~CSplitPanel() +{ + +} + +BOOL CSplitPanel::SetAnchor(UINT anchor) +{ + return FALSE; +} + +BOOL CSplitPanel::AddChild(CPanel * prc) +{ + return m_pOriginalPanel->AddChild(prc); +} +BOOL CSplitPanel::RemoveChild(CPanel * prc) +{ + return m_pOriginalPanel->RemoveChild(prc); +} + + +CString CSplitPanel::GetTypeName() +{ + return _T("CSplitPanel"); +} + +///////////////////////////// CFlowLayoutPanel +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +CFlowLayoutPanel::CFlowLayoutPanel() : CPanel() +{ + m_nItemSpacingX = 0; + m_nItemSpacingY = 0; + m_nFlowDirection = LEFT_TO_RIGHT; +} +CFlowLayoutPanel::CFlowLayoutPanel(const CRect * prc) : CPanel(prc) +{ + m_nItemSpacingX = 0; + m_nItemSpacingY = 0; + m_nFlowDirection = LEFT_TO_RIGHT; +} +CFlowLayoutPanel::~CFlowLayoutPanel() +{ + +} +void CFlowLayoutPanel::OnResized() +{ + int max = 0; // maximimum height of a item in the row in case of left-to-right, otherwise maximum width of a item + int x = left; + int y = top; + POSITION pos = Children.GetHeadPosition(); + + // first one will be at the top-left corner, no matter what + if (pos != NULL) + { + CPanel * pPanel = Children.GetNext(pos); + pPanel->MoveToXY(x, y); + pPanel->OnResized(); + + if (m_nFlowDirection == LEFT_TO_RIGHT) + { + x += pPanel->Width() + m_nItemSpacingX; + max = (pPanel->Height() > max ? pPanel->Height() : max); + } + else + { + y += pPanel->Height() + m_nItemSpacingY; + max = (pPanel->Width() > max ? pPanel->Width() : max); + } + } + + + if (m_nFlowDirection == LEFT_TO_RIGHT) + { + while(pos != NULL) + { + CPanel * pPanel = Children.GetNext(pos); + // check to see if it is to wrap + if (x + pPanel->Width() > right) + { + x = left; + y += (max + m_nItemSpacingY); + max = 0; + } + + pPanel->MoveToXY(x, y); + pPanel->OnResized(); + + x += pPanel->Width() + m_nItemSpacingX; + max = (pPanel->Height() > max ? pPanel->Height() : max); + } + } + else + { + while(pos != NULL) + { + CPanel * pPanel = Children.GetNext(pos); + // check to see if it is to wrap + if (y + pPanel->Height() > bottom) + { + x += (max + m_nItemSpacingX); + y = top; + max = 0; + } + + pPanel->MoveToXY(x, y); + pPanel->OnResized(); + + y += pPanel->Height() + m_nItemSpacingY; + max = (pPanel->Width() > max ? pPanel->Width() : max); + } + + } +} +CString CFlowLayoutPanel::GetTypeName() +{ + return _T("CFlowLayoutPanel"); + +} +void CFlowLayoutPanel::SetFlowDirection(FlowDirection direction) +{ + m_nFlowDirection = direction; +} +FlowDirection CFlowLayoutPanel::GetFlowDirection() +{ + return m_nFlowDirection; +} +void CFlowLayoutPanel::SetItemSpacingX(int nSpace) +{ + m_nItemSpacingX = nSpace; +} +int CFlowLayoutPanel::GetItemSpacingX() +{ + return m_nItemSpacingX; +} +void CFlowLayoutPanel::SetItemSpacingY(int nSpace) +{ + m_nItemSpacingY = nSpace; +} +int CFlowLayoutPanel::GetItemSpacingY() +{ + return m_nItemSpacingY; +} + diff --git a/lib_acl_cpp/samples/gui_rpc/ui/WndResizer.h b/lib_acl_cpp/samples/gui_rpc/ui/WndResizer.h new file mode 100644 index 000000000..c4e4a00bd --- /dev/null +++ b/lib_acl_cpp/samples/gui_rpc/ui/WndResizer.h @@ -0,0 +1,350 @@ +/* +DISCLAIMER + +Auther: Mizan Rahman +Original publication location: http://www.codeproject.com/KB/dialog/WndResizer.aspx + +This work is provided under the terms and condition described in The Code Project Open License (CPOL) +(http://www.codeproject.com/info/cpol10.aspx) + +This disclaimer should not be removed and should exist in any reproduction of this work. +*/ + +#pragma once +#include + + +#define ANCHOR_LEFT 1 +#define ANCHOR_TOP 2 +#define ANCHOR_RIGHT 4 +#define ANCHOR_BOTTOM 8 +#define ANCHOR_HORIZONTALLY_CENTERED 16 +#define ANCHOR_VERTICALLY_CENTERED 32 +#define ANCHOR_PRIORITY_RIGHT 64 // by defualt, left has higher priority +#define ANCHOR_PRIORITY_BOTTOM 128 // by defualt, top has higher priority +#define ANCHOR_VERTICALLY (ANCHOR_TOP | ANCHOR_BOTTOM) +#define ANCHOR_HORIZONTALLY (ANCHOR_LEFT | ANCHOR_RIGHT) +#define ANCHOR_ALL (ANCHOR_VERTICALLY | ANCHOR_HORIZONTALLY) + +#define DOCK_NONE 0 +#define DOCK_LEFT 1 +#define DOCK_TOP 2 +#define DOCK_RIGHT 3 +#define DOCK_BOTTOM 4 +#define DOCK_FILL 5 + +class CPanel; + +typedef CList CPanelList; + +typedef enum tagSplitterOrientation +{ + // a horizontal splitter container panel + SPLIT_CONTAINER_H = 1, + // a vertical splitter contianer panel + SPLIT_CONTAINER_V = 2, + +} SplitterOrientation; + +typedef enum tagFlowDirection +{ + // left to right flow direction + LEFT_TO_RIGHT = 3, + // top to bottom flow direction + TOP_TO_BOTTOM = 4, + +} FlowDirection; + +class CPanel : public CRect +{ +public: + CPanel(); + CPanel(const CRect * prc); + virtual ~CPanel(); + UINT Anchor; + UINT Dock; + CString Name; + CPanel * Parent; + CPanelList Children; + int LeftOffset; + int TopOffset; + int RightOffset; + int BottomOffset; + CSize MinSize; + CSize MaxSize; + virtual void OnResized(); + virtual BOOL AddChild(CPanel * prc); + virtual BOOL RemoveChild(CPanel * prc); + virtual BOOL SetAnchor(UINT anchor); + virtual BOOL SetMinSize(CSize & size); + virtual BOOL SetMaxSize(CSize & size); + virtual CString ToString(); + virtual CString GetTypeName(); + virtual CWnd * GetHookedWnd(); +private: + void Init(); +}; + +class CRootPanel : public CPanel +{ +public: + CRootPanel(); + ~CRootPanel(); + virtual CWnd * GetHookedWnd(); + CWnd * m_pHookWnd; + virtual CString GetTypeName(); +}; + +class CUIPanel : public CPanel +{ +public: + CUIPanel(const CRect * prc, UINT uID); + ~CUIPanel(); + UINT m_uID; // could be a resource ID or a HWND + BOOL m_bOle; // TRUE= m_uID is an ID of an ActiveX or OLE control, FALSE=regular windows control + virtual CString GetTypeName(); +}; + + +class CVisualPanel : public CPanel +{ +public: + CVisualPanel(); + CVisualPanel(const CRect * prc); + ~CVisualPanel(); + virtual void Draw(CDC * pDC); + BOOL m_bVisible; + virtual CString GetTypeName(); + virtual void OnResized(); +private: + CRect m_rcPrev; +}; + +class CGripperPanel : public CVisualPanel +{ +public: + CGripperPanel(); + CGripperPanel(const CRect * prc); + ~CGripperPanel(); + virtual void Draw(CDC * pDC); + virtual CString GetTypeName(); +private: + HTHEME m_hTheme; + int m_iPartId; + int m_iStateId; + CString m_sClassName; +}; + +class CSplitterGripperPanel : public CVisualPanel +{ +public: + CSplitterGripperPanel(SplitterOrientation type); + ~CSplitterGripperPanel(); + virtual void Draw(CDC * pDC); + virtual CString GetTypeName(); +private: + SplitterOrientation m_OrienType; +}; + +class CSplitPanel : public CPanel +{ +public: + CSplitPanel(CPanel * pPanel); + ~CSplitPanel(); + virtual BOOL SetAnchor(UINT anchor); + virtual BOOL AddChild(CPanel * prc); + virtual BOOL RemoveChild(CPanel * prc); + virtual CString GetTypeName(); +private: + CPanel * m_pOriginalPanel; +}; + + +class CSpitterPanel : public CPanel +{ +public: + CSpitterPanel(SplitterOrientation type); + CSpitterPanel(const CRect * prc, SplitterOrientation type); + ~CSpitterPanel(); + virtual CString GetTypeName(); + CSplitterGripperPanel * m_pGrippePanel; +private: + SplitterOrientation m_OrienType; +}; + + +class CSplitContainer : public CPanel +{ +public: + CSplitContainer(CSplitPanel * pPanelA, CSplitPanel * pPanelB, SplitterOrientation type); + ~CSplitContainer(); + virtual void OnResized(); + virtual BOOL AddChild(CPanel * prc); + virtual BOOL RemoveChild(CPanel * prc); + virtual CString GetTypeName(); + void SetSplitterPosition(int leftOfSpliter /* or topOfSpliter if vertical */); + int GetSplitterPosition(); + void SetFixedPanel(short nFixedPanel /* 1=left or top; 2=right or bototm; other=no fixed panel */); + short GetFixedPanel(); + void SetIsSplitterFixed(BOOL bFixed); + BOOL GetIsSplitterFixed(); + void SetShowSplitterGrip(BOOL bShow); + BOOL GetShowSplitterGrip(); + + static CSplitContainer * Create(CPanel * pPanelA, CPanel * pPanelB); + + SplitterOrientation m_Orientation; +private: + BOOL m_IsSplitterFixed; + short m_FixedPanel; // 1=left or top panel; 2=right or bottom panel, otherwise no fixed panel + + double m_nRatio; + int m_nSplitterSize; // for horizontal, it is the splitter width, otherwise it is the splitter height + void GetSplitArea(CRect * pSplitterPanel); + int GetSplitterSize(CPanel * pLeftPanel, CPanel * pRightPanel); + void UpdateRatio(); + + CSplitPanel * m_pPanelA; + CSplitPanel * m_pPanelB; + CSpitterPanel * m_pSplitter; +}; + +class CFlowLayoutPanel : public CPanel +{ +public: + CFlowLayoutPanel(); + CFlowLayoutPanel(const CRect * prc); + ~CFlowLayoutPanel(); + virtual void OnResized(); + virtual CString GetTypeName(); + void SetFlowDirection(FlowDirection direction); + FlowDirection GetFlowDirection(); + void SetItemSpacingX(int nSpace); + int GetItemSpacingX(); + void SetItemSpacingY(int nSpace); + int GetItemSpacingY(); + +private: + int m_nItemSpacingX; + int m_nItemSpacingY; + FlowDirection m_nFlowDirection; +}; + +class CWndResizer +{ +public: + CWndResizer(void); + ~CWndResizer(void); +private: + +public: + BOOL SetAnchor(LPCTSTR panelName, UINT anchor); + BOOL SetAnchor(UINT panelID, UINT anchor); + BOOL GetAnchor(LPCTSTR panelName, UINT & anchor); + BOOL GetAnchor(UINT panelID, UINT & anchor); + + + BOOL SetDock(LPCTSTR panelName, UINT anchor); + BOOL SetDock(UINT panelID, UINT anchor); + BOOL GetDock(LPCTSTR panelName, UINT & anchor); + BOOL GetDock(UINT panelID, UINT & anchor); + + BOOL SetFixedPanel(LPCTSTR splitContainerName, short panel); + BOOL GetFixedPanel(LPCTSTR splitContainerName, short & panel); + + BOOL SetIsSplitterFixed(LPCTSTR splitContainerName, BOOL fixed); + BOOL GetIsSplitterFixed(LPCTSTR splitContainerName, BOOL &fixed); + + BOOL SetFlowDirection(LPCTSTR flowPanelName, short direction); + BOOL GetFlowDirection(LPCTSTR flowPanelName, short &direction); + + BOOL SetFlowItemSpacingX(LPCTSTR flowPanelName, int nSpacing); + BOOL GetFlowItemSpacingX(LPCTSTR flowPanelName, int &nSpacing); + + BOOL SetFlowItemSpacingY(LPCTSTR flowPanelName, int nSpacing); + BOOL GetFlowItemSpacingY(LPCTSTR flowPanelName, int &nSpacing); + + + BOOL SetShowSplitterGrip(LPCTSTR splitContainerName, BOOL bShow); + BOOL GetShowSplitterGrip(LPCTSTR splitContainerName, BOOL & bShow); + + BOOL SetParent(LPCTSTR panelName, LPCTSTR parentName); + BOOL SetParent(UINT panelID, LPCTSTR parentName); + BOOL SetParent(LPCTSTR panelName, UINT parentID); + BOOL SetParent(UINT panelID, UINT parentID); + BOOL GetParent(LPCTSTR panelName, CString & parentName); + BOOL GetParent(UINT panelID, CString & parentName); + + BOOL SetMinimumSize(LPCTSTR panelName, CSize & size); + BOOL SetMinimumSize(UINT panelID, CSize & size); + BOOL GetMinimumSize(LPCTSTR panelName, CSize & size) ; + BOOL GetMinimumSize(UINT panelID, CSize & size) ; + + BOOL SetMaximumSize(LPCTSTR panelName, CSize & size); + BOOL SetMaximumSize(UINT panelID, CSize & size); + BOOL GetMaximumSize(LPCTSTR panelName, CSize & size) ; + BOOL GetMaximumSize(UINT panelID, CSize & size) ; + + void SetShowResizeGrip(BOOL show = TRUE); + BOOL GetShowResizeGrip(); + BOOL Hook(CWnd * pWnd); + BOOL Hook(CWnd * pWnd, CSize & size); + BOOL Unhook(); + + BOOL CreateFlowLayoutPanel(LPCTSTR panelName, const CRect * prcPanel); + BOOL CreateFlowLayoutPanel(LPCTSTR panelName, const CUIntArray * parrID, BOOL setAsChildren = FALSE); + + BOOL CreatePanel(LPCTSTR panelName, const CRect * prcPanel); + BOOL CreatePanel(LPCTSTR panelName, const CUIntArray * parrID, BOOL setAsChildren = FALSE); + + BOOL CreatePanel(UINT uID); + + BOOL CreateSplitContainer(LPCTSTR splitContainerName, LPCTSTR panelNameA, LPCTSTR panelNameB); + BOOL CreateSplitContainer(LPCTSTR splitContainerName, LPCTSTR panelNameA, UINT panelIDB); + BOOL CreateSplitContainer(LPCTSTR splitContainerName, UINT panelIDA, UINT panelIDB); + BOOL CreateSplitContainer(LPCTSTR splitContainerName, UINT panelIDA, LPCTSTR panelNameB); + + // useful for persisting UI layout + BOOL SetSplitterPosition(LPCTSTR splitContainerName, UINT position); + BOOL GetSplitterPosition(LPCTSTR splitContainerName, UINT & position); + + BOOL InvokeOnResized(); + + CString GetDebugInfo(); + +private: + + CWnd * m_pHookedWnd; + CRootPanel root; + CPanel * m_pCaptured; + HCURSOR m_hOldCursor; + int m_splitterOffset; + + void OnPaint(); + void OnSize(UINT nType, int cx, int cy); + void OnSizing(UINT fwSide, LPRECT pRect); + void OnScroll(); + void OnDestroy(); + void OnLButtonDown(UINT nFlags, CPoint point); + void OnMouseMove(UINT nFlags, CPoint point); + void OnLButtonUp(UINT nFlags, CPoint point); + + CWndResizer::CPanel * FindPanelByName(CPanel * pRoot, LPCTSTR name); + CWndResizer::CPanel * FindSplitterFromPoint(CPanel * pRoot, CPoint point); + void GetUIPanels(CPanel * pRoot, CPanelList * pList, BOOL bOle); + void GetVisualPanels(CPanel * pRoot, CPanelList * pList); + + void ResizeUI(CPanel * pRoot); + + CString IdToName(UINT uID); + CWndResizer::CUIPanel * CreateUIPanel(UINT uID); + CWndResizer::CUIPanel * GetUIPanel(UINT uID); + + void UpdateSplitterOffset(CPoint ptCurr); + void GetDebugInfo(CPanel * pRoot, CString & info, CString indent); + void GetTrueClientRect(CWnd * pWnd, CRect * prc); + void EnsureRootMinMax(); + + WNDPROC m_pfnWndProc; + static LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); +}; diff --git a/lib_acl_cpp/samples/hsclient/Makefile b/lib_acl_cpp/samples/hsclient/Makefile new file mode 100644 index 000000000..4246d136a --- /dev/null +++ b/lib_acl_cpp/samples/hsclient/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = hsclient diff --git a/lib_acl_cpp/samples/hsclient/main.cpp b/lib_acl_cpp/samples/hsclient/main.cpp new file mode 100644 index 000000000..3a2c70c75 --- /dev/null +++ b/lib_acl_cpp/samples/hsclient/main.cpp @@ -0,0 +1,570 @@ +#include "lib_acl.h" // just for ACL_METER_TIME +#include "log.hpp" +#include "hsrow.hpp" +#include "hsclient.hpp" +#include "hspool.hpp" +#include +#include +#include +#include + +static ACL_DB_POOL *__db_pool = NULL; +static bool debug_on = false; + +static void usage(const char* procname) +{ + printf("usage: %s -h[help] -s addr -m -a[add] -q[find] -g[find2] -Q[pool find] -u[update] -U[pool update] -n num\n", procname); +} + +static void dbconn_init(const char *addr, const char *name, const char *usr, + const char *pass, int dbpool_max, int dbping, int dbtimeout) +{ + const char *myname = "dbconn_init"; + ACL_DB_INFO db_info; + + memset(&db_info, 0, sizeof(ACL_DB_INFO)); + + ACL_SAFE_STRNCPY(db_info.db_addr, addr, sizeof(db_info.db_addr)); + ACL_SAFE_STRNCPY(db_info.db_name, name, sizeof(db_info.db_name)); + ACL_SAFE_STRNCPY(db_info.db_user, usr, sizeof(db_info.db_user)); + ACL_SAFE_STRNCPY(db_info.db_pass, pass, sizeof(db_info.db_pass)); + + db_info.db_max = dbpool_max; + db_info.ping_inter = dbping; + db_info.timeout_inter = dbtimeout; + db_info.auto_commit = 1; + + //db_info.db_before_connect = db_before_connect; + //db_info.db_after_connect = db_after_connect; + + __db_pool = acl_dbpool_create("mysql", &db_info); + + if (__db_pool == NULL) + acl_msg_fatal("%s(%d): init db pool error", myname, __LINE__); + +} + +static ACL_DB_HANDLE *dbconn_get(void) +{ + const char *myname = "dbconn_get"; + ACL_DB_HANDLE *db_handle; + + if (__db_pool == NULL) + acl_msg_fatal("%s(%d): db pool null", myname, __LINE__); + + db_handle = acl_dbpool_peek(__db_pool); + if (db_handle == NULL) + acl_msg_fatal("%s(%d): get db conn error", myname, __LINE__); + + return (db_handle); +} + +static void dbconn_put(ACL_DB_HANDLE *db_handle) +{ + const char *myname = "dbconn_put"; + + if (db_handle == NULL) + acl_msg_fatal("%s(%d): input null", myname, __LINE__); + + acl_dbpool_release(db_handle); +} + +static void my_find(const char* db_addr, int num) +{ + const char* db_name = "test", *db_user = "root", *db_pass = ""; + int db_max = 10, db_ping = 100, db_timeout = 1000; + + dbconn_init(db_addr, db_name, db_user, db_pass, db_max, db_ping, db_timeout); + + ACL_DB_HANDLE* db_handle = dbconn_get(); + ACL_SQL_RES *sql_res; + ACL_ITER iter; + char sql[1024]; + int error; + + for (int i = 0; i < num; i++) + { + snprintf(sql, sizeof(sql), "select user_id, user_name, user_email from user where user_id=%d", i); + sql_res = acl_dbsql_select(db_handle, sql, &error); + if (sql_res == NULL) + { + printf("over now, i: %d, num: %d\n", i, num); + break; + } + if (i > 10) + { + acl_dbsql_free_result(db_handle, sql_res); + if (i % 10000 == 0) + { + snprintf(sql, sizeof(sql), "find, num: %d\n", i); + ACL_METER_TIME(sql); + } + continue; + } + printf(">>results:\n"); + acl_foreach(iter, sql_res) + { + const char **my_row = (const char**) iter.data; + printf("\t%s\t%s\t%s\n", my_row[0], my_row[1], my_row[2]); + } + acl_dbsql_free_result(db_handle, sql_res); + } + + dbconn_put(db_handle); +} + +static void hs_insert(const char* addr, int num, bool enable_cache) +{ + const char* dbn = "test", *tbl = "user", *idx = "PRIMARY"; + const char* flds = "user_id,user_name,user_email"; + const char* bufs[3]; + char buf1[256], buf2[256], buf3[256]; + acl::hsclient client(addr, enable_cache); + + if (client.open_tbl(dbn, tbl, idx, flds) == false) + { + printf("connect %s error\n", addr); + return; + } + + for (int i = 0; i < num; i++) + { + snprintf(buf1, sizeof(buf1), "%d", i); + snprintf(buf2, sizeof(buf2), "zsxxsz%d", i); + snprintf(buf3, sizeof(buf3), "zsxxsz%d@test.com", i); + bufs[0] = buf1; + bufs[1] = buf2; + bufs[2] = buf3; + if (client.add(bufs, 3) == false) + { + printf(">>insert error: %d, %s\n", client.get_error(), + client.get_last_serror()); + break; + } + if (i < 10) + printf(">>insert %s,%s,%s ok\n", buf1, buf2, buf3); + if (i % 10000 == 0) + { + snprintf(buf1, sizeof(buf1), "insert num: %d\n", i); + ACL_METER_TIME(buf1); + } + } +} + +static void hs_dump(const std::vector& rows) +{ + std::vector::const_iterator cit_row; + std::vector::const_iterator cit_colum; + + cit_row = rows.begin(); + + for (; cit_row != rows.end(); cit_row++) + { + cit_colum = (*cit_row)->get_row().begin(); + + printf(">>results:\n"); + + for (; cit_colum != (*cit_row)->get_row().end(); + cit_colum++) + { + printf("\t|%s|", *cit_colum); + } + + printf("\n"); + } +} + +static void hs_find(const char* addr, int num, bool enable_cache) +{ + const char* dbn = "test", *tbl = "user", *idx = "user_name"; + const char* flds = "user_id,user_name,user_email"; + const char* bufs[2]; + char buf[256]; + acl::hsclient client(addr, enable_cache); + + if (client.open_tbl(dbn, tbl, idx, flds) == false) + { + printf("connect %s error\n", addr); + return; + } + + printf(">>dbn: %s, tbl: %s, idx: %s, flds: %s\n", dbn, tbl, idx, flds); + + for (int i = 0; i < num; i++) + { + snprintf(buf, sizeof(buf), "zsxxsz%d", i); + bufs[0] = buf; + + const std::vector& rows = + client.get(bufs, 1, "=", 1, 0); + if (rows.empty()) + { + printf("find(%s) error:%s(%d)\n", + buf, client.get_last_serror(), client.get_error()); + break; + } + + if (i > 0 && i % 10000 == 0) + { + snprintf(buf, sizeof(buf), "find, num: %d\n", i); + ACL_METER_TIME(buf); + } + if (i > 1000) + continue; + hs_dump(rows); + } +} + +static void hs_find2(const char* addr, int num, bool enable_cache) +{ + const char* dbn = "test", *tbl = "user", *idx = "PRIMARY"; + const char* flds = "user_id,user_name,user_email"; + char buf[256]; + acl::hsclient client(addr, enable_cache); + + if (client.open_tbl(dbn, tbl, idx, flds) == false) + { + printf("open %s error: %s\n", addr, client.get_last_serror()); + return; + } + + for (int i = 0; i < num; i++) + { + snprintf(buf, sizeof(buf), "%d", i); + + const std::vector& rows = + client.get(buf, NULL); + if (rows.empty()) + { + printf("find(%s) error\n", buf); + break; + } + + + if (i % 10000 == 0) + { + snprintf(buf, sizeof(buf), "find, num: %d\n", i); + ACL_METER_TIME(buf); + } + if (i > 1000) + continue; + + hs_dump(rows); + } +} + +static void hs_update(const char* addr, int num, bool enable_cache) +{ + const char* dbn = "test", *tbl = "user", *idx = "PRIMARY"; + const char* flds = "user_name,user_email"; + const char* bufs[2], *bufs_to[2]; + char buf[256], buf_to1[256], buf_to2[256]; + acl::hsclient client(addr, enable_cache); + + if (client.open_tbl(dbn, tbl, idx, flds) == false) + { + printf("connect %s error: %s(%d)\n", + addr, client.get_last_serror(), client.get_error()); + return; + } + + printf(">>dbn: %s, tbl: %s, idx: %s, flds: %s\n", dbn, tbl, idx, flds); + + for (int i = 0; i < num; i++) + { + snprintf(buf, sizeof(buf), "%d", i); + bufs[0] = buf; + + snprintf(buf_to1, sizeof(buf_to1), "zsxxsz_%d", i); + snprintf(buf_to2, sizeof(buf_to2), "zsxxsz_%d@test.com", i); + bufs_to[0] = buf_to1; + bufs_to[1] = buf_to2; + + if (client.mod(bufs, 1, bufs_to, 2) == false) + { + printf("update error: %s(%d)\n", + client.get_last_serror(), client.get_error()); + break; + } + + if (i > 0 && i % 10000 == 0) + { + snprintf(buf, sizeof(buf), "update, num: %d\n", i); + ACL_METER_TIME(buf); + } + if (i > 100) + continue; + printf(">> update num: %d ok\n", i); + } +} + +static void hspool_find(const char* addr, int num, bool enable_cache) +{ + const char* dbn = "test", *tbl = "user", *idx; + const char* flds = "user_id,user_name,user_email"; + char buf[256]; + const char* addr_rd = "192.168.1.232:9998"; + acl::hspool pool(addr, addr_rd, enable_cache); + acl::hsclient* client; + + idx = "PRIMARY"; + for (int i = 0; i < 10; i++) + { + client = pool.peek(dbn, tbl, idx, flds); + if (client == NULL) + { + printf("peek error\n"); + break; + } + printf(">>read addr: %s\n", client->get_addr()); + pool.put(client); + } + + printf("========================================================\n"); + + for (int i = 0; i < 10; i++) + { + client = pool.peek(dbn, tbl, idx, flds); + if (client == NULL) + { + printf("peek error\n"); + break; + } + printf(">>read/write addr: %s\n", client->get_addr()); + pool.put(client); + } + + ////////////////////////////////////////////////////////////////////// + + printf("========================================================\n"); + idx = "PRIMARY"; + for (int i = 0; i < num; i++) + { + snprintf(buf, sizeof(buf), "%d", i); + + client = pool.peek(dbn, tbl, idx, flds); + if (client == NULL) + { + printf("peek error\n"); + break; + } + + const std::vector& rows = + client->get(buf, NULL); + if (rows.empty()) + { + printf("find(%s) error\n", buf); + pool.put(client); + break; + } + + + if (i > 0 && i % 10000 == 0) + { + snprintf(buf, sizeof(buf), "find, num: %d\n", i); + ACL_METER_TIME(buf); + } + if (i <= 10) + { + printf(">>hs_id: %d, key: %s ", client->get_id(), buf); + hs_dump(rows); + } + pool.put(client); + } + + ////////////////////////////////////////////////////////////////////// + + printf("========================================================\n"); + idx = "user_name"; + for (int i = 0; i < num; i++) + { + snprintf(buf, sizeof(buf), "zsxxsz%d", i); + + client = pool.peek(dbn, tbl, idx, flds); + if (client == NULL) + { + printf("peek error\n"); + break; + } + + const std::vector& rows = + client->get(buf, NULL); + if (rows.empty()) + { + printf("find(%s) error\n", buf); + pool.put(client); + break; + } + + + if (i > 0 && i % 10000 == 0) + { + snprintf(buf, sizeof(buf), "find, num: %d\n", i); + ACL_METER_TIME(buf); + } + if (i <= 10) + { + printf(">>hs_id: %d, key: %s ", client->get_id(), buf); + hs_dump(rows); + } + pool.put(client); + } + + ////////////////////////////////////////////////////////////////////// + + printf("========================================================\n"); + idx = "PRIMARY"; + for (int i = 0; i < num; i++) + { + snprintf(buf, sizeof(buf), "%d", i); + + client = pool.peek(dbn, tbl, idx, flds); + if (client == NULL) + { + printf("peek error\n"); + break; + } + + const std::vector& rows = + client->get(buf, NULL); + if (rows.empty()) + { + printf("find(%s) error\n", buf); + pool.put(client); + break; + } + + + if (i > 0 && i % 10000 == 0) + { + snprintf(buf, sizeof(buf), "find, num: %d\n", i); + ACL_METER_TIME(buf); + } + if (i <= 10) + { + printf(">>hs_id: %d, key: %s ", client->get_id(), buf); + hs_dump(rows); + } + pool.put(client); + } +} + +static void hspool_update(const char* addr, int num, bool enable_cache) +{ + const char* dbn = "test", *tbl = "user", *idx; + const char* flds = "user_name,user_email"; + const char* bufs[2], *bufs_to[2]; + char buf[256], buf_to1[256], buf_to2[256]; + const char* addr_rd = "192.168.1.232:9998"; + acl::hspool pool(addr, addr_rd, enable_cache); + acl::hsclient* client; + + idx = "PRIMARY"; + for (int i = 0; i < num; i++) + { + snprintf(buf, sizeof(buf), "%d", i); + + client = pool.peek(dbn, tbl, idx, flds); + if (client == NULL) + { + printf("peek error\n"); + break; + } + + snprintf(buf, sizeof(buf), "%d", i); + bufs[0] = buf; + + snprintf(buf_to1, sizeof(buf_to1), "zsxxsz_%d", i); + snprintf(buf_to2, sizeof(buf_to2), "zsxxsz_%d@test.com", i); + bufs_to[0] = buf_to1; + bufs_to[1] = buf_to2; + + if (client->mod(bufs, 1, bufs_to, 2) == false) + { + printf("update error: %s(%d)\n", + client->get_last_serror(), client->get_error()); + break; + } + + if (i > 0 && i % 10000 == 0) + { + snprintf(buf, sizeof(buf), "update, num: %d\n", i); + ACL_METER_TIME(buf); + } + if (i <= 10) + printf(">>update, num: %d, hs_id: %d, key: %s\n", + i, client->get_id(), buf); + pool.put(client); + } +} + +int main(int argc, char *argv[]) +{ + int ch, num = 10; + char* addr = strdup("127.0.0.1:19999"); + void (*func)(const char* addr, int num, bool enable_cache) = NULL; + bool use_mysql = false, enable_cache = false; + + while ((ch = getopt(argc, argv, "hs:aqgQuUn:mdc")) > 0) + { + switch (ch) + { + case 'h': + usage(argv[0]); + return (0); + case 's': + free(addr); + addr = strdup(optarg); + break; + case 'a': + func = hs_insert; + break; + case 'q': + func = hs_find; + break; + case 'g': + func = hs_find2; + break; + case 'Q': + func = hspool_find; + break; + case 'u': + func = hs_update; + break; + case 'U': + func = hspool_update; + break; + case 'n': + num = atoi(optarg); + break; + case 'm': + use_mysql = true; + break; + case 'd': + debug_on = true; + break; + case 'c': + enable_cache = true; + break; + default: + break; + } + } + + if (use_mysql) + { + printf("mysql\n"); + my_find(addr, num); + return (0); + } + + logger_open("test.log", "test", "all:2"); + + if (func != NULL) + func(addr, num, enable_cache); + else + usage(argv[0]); + + free(addr); + return (0); +} diff --git a/lib_acl_cpp/samples/hsclient/user.sql b/lib_acl_cpp/samples/hsclient/user.sql new file mode 100644 index 000000000..2f8965d7d --- /dev/null +++ b/lib_acl_cpp/samples/hsclient/user.sql @@ -0,0 +1,9 @@ +use test; +create table user +( + user_id integer not null, + user_name varchar(256) not null, + user_email varchar(256) not null, + primary key(user_id), + index(user_name) +) diff --git a/lib_acl_cpp/samples/hsclient/valgrind.sh b/lib_acl_cpp/samples/hsclient/valgrind.sh new file mode 100644 index 000000000..42dc66e2e --- /dev/null +++ b/lib_acl_cpp/samples/hsclient/valgrind.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +#valgrind --tool=memcheck --leak-check=yes -v ./hsclient -s 124.238.255.29:19999 -Q +valgrind --tool=memcheck --leak-check=yes -v ./hsclient -s 192.168.1.232:9999 -n 2 -q diff --git a/lib_acl_cpp/samples/http_client/Makefile b/lib_acl_cpp/samples/http_client/Makefile new file mode 100644 index 000000000..1792a5110 --- /dev/null +++ b/lib_acl_cpp/samples/http_client/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = http_client diff --git a/lib_acl_cpp/samples/http_client/http_client.vcproj b/lib_acl_cpp/samples/http_client/http_client.vcproj new file mode 100644 index 000000000..4994f0679 --- /dev/null +++ b/lib_acl_cpp/samples/http_client/http_client.vcproj @@ -0,0 +1,234 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_acl_cpp/samples/http_client/http_client.vcxproj b/lib_acl_cpp/samples/http_client/http_client.vcxproj new file mode 100644 index 000000000..bb43c8fdd --- /dev/null +++ b/lib_acl_cpp/samples/http_client/http_client.vcxproj @@ -0,0 +1,164 @@ +锘 + + + + Debugdll + Win32 + + + Debug + Win32 + + + Releasedll + Win32 + + + Release + Win32 + + + + + + + {467619C7-C100-47B9-9A3B-7246A542EDC9} + Win32Proj + http_client + + + + Application + true + Unicode + + + Application + true + Unicode + + + Application + false + true + Unicode + + + Application + false + true + Unicode + + + + + + + + + + + + + + + + + + + true + + + true + + + false + + + false + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + ..\..\..\lib_protocol\include;..\..\..\lib_acl\include;..\..\include + MultiThreadedDebug + + + Console + true + ..\..\..\lib\win32;..\..\..\dist\lib\win32 + lib_acl_vc2010d.lib;lib_protocol_vc2010d.lib;lib_acl_cpp_vc2010d.lib;%(AdditionalDependencies) + + + + + + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;ACL_CPP_DLL;%(PreprocessorDefinitions) + ..\..\..\lib_protocol\include;..\..\..\lib_acl\include;..\..\include + MultiThreadedDebugDLL + + + Console + true + ..\..\lib;..\..\..\dist\lib\win32 + lib_acl_d.lib;lib_protocol_d.lib;lib_acl_cpp_d.lib;%(AdditionalDependencies) + + + libcmtd + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + ..\..\..\lib_protocol\include;..\..\..\lib_acl\include;..\..\include + MultiThreaded + + + Console + true + true + true + + + ..\..\lib;..\..\..\dist\lib\win32 + lib_acl_vc2010.lib;lib_protocol_vc2003.lib;lib_acl_cpp_vc2010.lib;%(AdditionalDependencies) + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;ACL_CPP_DLL;%(PreprocessorDefinitions) + ..\..\..\lib_protocol\include;..\..\..\lib_acl\include;..\..\include + + + Console + true + true + true + libcmt + ..\..\lib;..\..\..\dist\lib\win32 + lib_acl.lib;lib_protocol.lib;lib_acl_cpp.lib;%(AdditionalDependencies) + + + + + + \ No newline at end of file diff --git a/lib_acl_cpp/samples/http_client/http_client_vc2012.vcxproj b/lib_acl_cpp/samples/http_client/http_client_vc2012.vcxproj new file mode 100644 index 000000000..7178524a9 --- /dev/null +++ b/lib_acl_cpp/samples/http_client/http_client_vc2012.vcxproj @@ -0,0 +1,169 @@ +锘 + + + + Debugdll + Win32 + + + Debug + Win32 + + + Releasedll + Win32 + + + Release + Win32 + + + + + + + {467619C7-C100-47B9-9A3B-7246A542EDC9} + Win32Proj + http_client + http_client + + + + Application + true + Unicode + v110 + + + Application + true + Unicode + v110 + + + Application + false + true + Unicode + v110 + + + Application + false + true + Unicode + v110 + + + + + + + + + + + + + + + + + + + true + + + true + + + false + + + false + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + ..\..\..\lib_protocol\include;..\..\..\lib_acl\include;..\..\include + MultiThreadedDebug + + + Console + true + ..\..\..\lib\win32;..\..\..\dist\lib\win32 + lib_acl_vc2012d.lib;lib_protocol_vc2012d.lib;lib_acl_cpp_vc2012d.lib;%(AdditionalDependencies) + + + + + + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;ACL_CPP_DLL;%(PreprocessorDefinitions) + ..\..\..\lib_protocol\include;..\..\..\lib_acl\include;..\..\include + MultiThreadedDebugDLL + + + Console + true + ..\..\lib;..\..\..\dist\lib\win32 + lib_acl_d.lib;lib_protocol_d.lib;lib_acl_cpp_d.lib;%(AdditionalDependencies) + + + libcmtd + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + ..\..\..\lib_protocol\include;..\..\..\lib_acl\include;..\..\include + MultiThreaded + + + Console + true + true + true + + + ..\..\lib;..\..\..\dist\lib\win32 + lib_acl_vc2012.lib;lib_protocol_vc2003.lib;lib_acl_cpp_vc2012.lib;%(AdditionalDependencies) + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;ACL_CPP_DLL;%(PreprocessorDefinitions) + ..\..\..\lib_protocol\include;..\..\..\lib_acl\include;..\..\include + + + Console + true + true + true + libcmt + ..\..\lib;..\..\..\dist\lib\win32 + lib_acl.lib;lib_protocol.lib;lib_acl_cpp.lib;%(AdditionalDependencies) + + + + + + \ No newline at end of file diff --git a/lib_acl_cpp/samples/http_client/main.cpp b/lib_acl_cpp/samples/http_client/main.cpp new file mode 100644 index 000000000..e18fdca88 --- /dev/null +++ b/lib_acl_cpp/samples/http_client/main.cpp @@ -0,0 +1,164 @@ +#include +#include + +#include "lib_acl.h" +#include "lib_protocol.h" // http 协议相关 +#include "acl_cpp/stream/aio_handle.hpp" +#include "acl_cpp/stdlib/string.hpp" +#include "acl_cpp/stream/ofstream.hpp" +#include "acl_cpp/acl_cpp_init.hpp" +#include "acl_cpp/http/http_service.hpp" + +class http_request : public acl::http_service_request +{ +public: + http_request(const char* domain, unsigned short port, + acl::aio_handle* handle) + : acl::http_service_request(domain, port) + , handle_(handle) + { + read_length_ = 0; + } + + ~http_request(void) + { + // 通知异步事件引擎完全退出 + handle_->stop(); + } +protected: + ////////////////////////////////////////////////////////////////////////// + // 基类虚接口 + + virtual const acl::string* get_body() + { + return (NULL); + } + + // 正常读到 HTTP 响应头时的回调接口 + virtual void on_hdr(const char* addr, const HTTP_HDR_RES* hdr) + { + printf(">>server addr: %s, http reply status: %d\n", + addr, hdr->reply_status); + http_hdr_print(&hdr->hdr, "http reply hdr"); + content_length_ = hdr->hdr.content_length; + if (content_length_ > 0) + { + if (out_.open_write("test.exe") == false) + printf("create file error(%s)\n", + acl_last_serror()); + } + time(&begin_); + } + + // 正常读 HTTP 响应体时的回调函数 + virtual void on_body(const char* data, size_t dlen) + { + if (data == NULL && dlen == 0) + { +#ifdef WIN32 + printf("\n>> http reply body over, total: %I64d, %I64d\n", + content_length_, read_length_); +#else + printf("\n>> http reply body over, total: %lld, %lld\n", + content_length_, read_length_); +#endif + // 出错后,因为本类对象是动态分配的,所以需要在此处释放 + time_t end = time(NULL); + printf(">>spent %d seconds\n", (int)(end - begin_)); + + return; + } + read_length_ += dlen; + http_off_t n = (read_length_ * 100) / content_length_; +#ifdef WIN32 + printf("%I64d%%\r", n); +#else + printf("%lld%%\r", n); +#endif + + if (out_.opened()) + out_.write(data, dlen); + } + + // 当请求或响应失败时的回调函数 + virtual void on_error(acl::http_status_t errnum) + { + printf(">> error: %d\n", (int) errnum); + + // 出错后,因为本类对象是动态分配的,所以需要在此处释放 + } + + virtual void destroy() + { + delete this; + } + +private: + acl::ofstream out_; + acl::aio_handle* handle_; + http_off_t read_length_; + http_off_t content_length_; + time_t begin_; +}; + +int main() +{ +#ifdef WIN32 + acl::acl_cpp_init(); +#endif + + acl::aio_handle handle(acl::ENGINE_SELECT); + acl::http_service* service = new acl::http_service(); + + // 使消息服务器监听 127.0.0.1 的地址 + if (service->open(&handle) == false) + { + printf(">>open message service error!\n"); + printf(">>enter any key to quit\n"); + getchar(); + return (1); + } + + + // 创建 HTTP 请求过程 + acl::string domain; + domain = "www.banmau.com"; + //domain = "192.168.1.229"; + //domain = "www.renwou.net"; + http_request* req = new http_request(domain.c_str(), 80, &handle); + req->set_url("/index.html"); + //req->set_url("/download/banmau_install.exe"); + req->set_host(domain); + req->set_keep_alive(false); + req->set_method(acl::HTTP_METHOD_GET); + req->add_cookie("x-cookie-name", "cookie-value"); + //req->set_redirect(1); // 设置自动重定向的次数限制 + + // 通知异步消息服务器处理该 HTTP 请求过程 + + ////////////////////////////////////////////////////////////////////////// + //acl::string buf; + //req->build_request(buf); + //printf("-----------------------------------------------\n"); + //printf("%s", buf.c_str()); + //printf("-----------------------------------------------\n"); + ////////////////////////////////////////////////////////////////////////// + + service->do_request(req); + + while (true) + { + if (handle.check() == false) + { + printf(">>quit aio process\n"); + break; + } + } + + delete service; + handle.check(); + + printf(">>enter any key to exist\n"); + getchar(); + return (0); +} diff --git a/lib_acl_cpp/samples/http_client/valgrind.sh b/lib_acl_cpp/samples/http_client/valgrind.sh new file mode 100644 index 000000000..1e9c3cb01 --- /dev/null +++ b/lib_acl_cpp/samples/http_client/valgrind.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +valgrind --tool=memcheck --leak-check=yes --show-reachable=yes -v ./http_client diff --git a/lib_acl_cpp/samples/http_client2/Makefile b/lib_acl_cpp/samples/http_client2/Makefile new file mode 100644 index 000000000..52ce6705e --- /dev/null +++ b/lib_acl_cpp/samples/http_client2/Makefile @@ -0,0 +1,3 @@ +include ../Makefile.in +EXTLIBS = -lpolarssl +PROG = http_client diff --git a/lib_acl_cpp/samples/http_client2/ReadMe.txt b/lib_acl_cpp/samples/http_client2/ReadMe.txt new file mode 100644 index 000000000..efd4d207f --- /dev/null +++ b/lib_acl_cpp/samples/http_client2/ReadMe.txt @@ -0,0 +1,31 @@ +======================================================================== + 控制台应用程序 : http_client2 项目概况 +======================================================================== + +应用程序向导已为您创建了这个 http_client2 应用程序。 +此文件包含组成 http_client2 应用程序 +的每个文件的内容摘要。 + + +http_client2.vcproj + 这是用应用程序向导生成的 VC++ 项目的主项目文件。 + 它包含有关生成此文件的 Visual C++ 版本的信息,以及 + 有关用应用程序向导选择的 + 平台、配置和项目功能的信息。 + +http_client2.cpp + 这是主应用程序源文件。 + +///////////////////////////////////////////////////////////////////////////// +其他标准文件: + +StdAfx.h、StdAfx.cpp + 这些文件用于生成名为 http_client2.pch + 的预编译头(PCH)文件以及名为 StdAfx.obj 的预编译类型文件。 + +///////////////////////////////////////////////////////////////////////////// +其他注释: + +应用程序向导使用 "TODO:" 注释指示应添加或自定义的源代码部分。 + +///////////////////////////////////////////////////////////////////////////// diff --git a/lib_acl_cpp/samples/http_client2/http_client2.cpp b/lib_acl_cpp/samples/http_client2/http_client2.cpp new file mode 100644 index 000000000..32cadc923 --- /dev/null +++ b/lib_acl_cpp/samples/http_client2/http_client2.cpp @@ -0,0 +1,93 @@ +// http_client2.cpp : 定义控制台应用程序的入口点。 +// + +#include "stdafx.h" + +static void get_url(const char* url, const char* host, + const char* addr, const char* tofile) +{ + acl::http_header header; + + header.set_method(acl::HTTP_METHOD_GET); + header.set_url(url); + header.set_content_type("text/xml; charset=utf-8"); + header.set_host(host); + header.set_keep_alive(true); + header.add_entry("User-Agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)"); + header.add_entry("Accept", "*/*"); + header.add_entry("Cache-Control", "no-cache"); + header.accept_gzip(true); + + acl::http_client client; + printf("begin connect %s\r\n", addr); + if (client.open(addr, 10, 10) == false) + { + printf("open %s error\r\n", addr); + return; + } + + acl::string buf; + + header.build_request(buf); + printf("--------------------request------------------\r\n"); + printf("%s\r\n", buf.c_str()); + + if (client.write(header) == -1) + { + printf("write request header error\r\n"); + return; + } + if (client.read_head() == false) + { + printf("read response header error\r\n"); + return; + } + + client.print_header("response header"); + + acl::ofstream fp; + fp.open_write(tofile); + while (true) + { + int ret = client.read_body(buf); + if (ret < 0) + { + printf("connect closed now\r\n"); + break; + } + else if (ret == 0) + { + printf("over now\r\n"); + break; + } + fp.write(buf); + } +} + +int main(int argc, char* argv[]) +{ + (void) argc; (void) argv; + acl::acl_cpp_init(); // 必须先初始化 + + //const char* url = "http://www.sina.com.cn/"; + //const char* host = "www.sina.com.cn"; + //const char* addr = "www.sina.com.cn:80"; + + get_url("http://www.sina.com.cn/", "www.sina.com.cn", + "www.sina.com.cn:80", "sina.txt"); + get_url("http://www.hexun.com/", "www.hexun.com", + "www.hexun.com:80", "hexun.txt"); + + acl::http_header header(400); + acl::string buf; + header.set_content_length(1000); + header.set_keep_alive(true); + header.add_entry("name", "value"); + header.build_response(buf); + printf("[%s]\r\n", buf.c_str()); + + printf("enter any key to exist\r\n"); + getchar(); + + return 0; +} diff --git a/lib_acl_cpp/samples/http_client2/http_client2.vcproj b/lib_acl_cpp/samples/http_client2/http_client2.vcproj new file mode 100644 index 000000000..61611a718 --- /dev/null +++ b/lib_acl_cpp/samples/http_client2/http_client2.vcproj @@ -0,0 +1,278 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_acl_cpp/samples/http_client2/stdafx.cpp b/lib_acl_cpp/samples/http_client2/stdafx.cpp new file mode 100644 index 000000000..d4507fdce --- /dev/null +++ b/lib_acl_cpp/samples/http_client2/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// http_client2.pch 将成为预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + +// TODO: 在 STDAFX.H 中 +//引用任何所需的附加头文件,而不是在此文件中引用 diff --git a/lib_acl_cpp/samples/http_client2/stdafx.h b/lib_acl_cpp/samples/http_client2/stdafx.h new file mode 100644 index 000000000..153076a38 --- /dev/null +++ b/lib_acl_cpp/samples/http_client2/stdafx.h @@ -0,0 +1,12 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是常用但不常更改的项目特定的包含文件 +// + +#pragma once + + +//#include +//#include +#include "acl_cpp/lib_acl.hpp" + +// TODO: 在此处引用程序要求的附加头文件 diff --git a/lib_acl_cpp/samples/http_client2/valgrind.sh b/lib_acl_cpp/samples/http_client2/valgrind.sh new file mode 100644 index 000000000..8fa110536 --- /dev/null +++ b/lib_acl_cpp/samples/http_client2/valgrind.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +valgrind --tool=memcheck --leak-check=yes -v ./http_client diff --git a/lib_acl_cpp/samples/http_mime/Makefile b/lib_acl_cpp/samples/http_mime/Makefile new file mode 100644 index 000000000..52bd1139f --- /dev/null +++ b/lib_acl_cpp/samples/http_mime/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = http_mime diff --git a/lib_acl_cpp/samples/http_mime/http_mime.cpp b/lib_acl_cpp/samples/http_mime/http_mime.cpp new file mode 100644 index 000000000..1f3ad5c47 --- /dev/null +++ b/lib_acl_cpp/samples/http_mime/http_mime.cpp @@ -0,0 +1,82 @@ +// http_mime.cpp : 定义控制台应用程序的入口点。 +// + +#include "stdafx.h" +#include "acl_cpp/lib_acl.hpp" + +static void test(const char* path, const char* boundary) +{ + acl::http_mime mime(boundary); + mime.set_saved_path(path); + acl::string buf; + + if (acl::ifstream::load(path, &buf) == false) + { + printf("load %s error\r\n", path); + return; + } + + mime.update(buf.c_str(), buf.length()); +#if 0 + const std::list& nodes = mime.get_nodes(); + std::list::const_iterator cit = nodes.begin(); + for (; cit != nodes.end(); ++cit) + { + acl::http_mime_node* node = *cit; + if (node->get_mime_type() == acl::HTTP_MIME_PARAM) + { + const char* name = node->get_name(); + const char* value = node->get_value(); + printf("name: %s, value: %s\r\n", name ? name : "null", + value ? value : "null"); + } + else if (node->get_mime_type() == acl::HTTP_MIME_FILE) + { + const char* filename = node->get_filename(); + printf("filename: %s\r\n", filename ? filename : "null"); + node->save(filename); + } + } +#else + printf("length: %d\r\n", (int) buf.length()); + const std::list& nodes = mime.get_nodes(); + std::list::const_iterator cit = nodes.begin(); + for (; cit != nodes.end(); ++cit) + { + const char* n1, *f, *v; + n1 = (*cit)->get_name(); + f = (*cit)->get_filename(); + v = (*cit)->get_value(); + printf(">>>name: %s, value: %s, file: %s
\r\n", + n1 ? n1 : "null", v ? v : "null", f ? f : "null"); + } + + const acl::http_mime_node* node = mime.get_node("filename"); + if (node == NULL || node->get_mime_type() != acl::HTTP_MIME_FILE) + { + printf("filename not found\r\n"); + return; + } + const char* ptr = node->get_filename(); + if (ptr == NULL || *ptr == 0) + printf("filename's value null\r\n"); + else + printf("filename: %s\r\n", ptr); +#endif +} + +int main(int argc, char* argv[]) +{ + const char* path = "./tmp.txt"; +// const char* boundary = "-----------------------------5169208281820"; +// const char* boundary = "------WebKitFormBoundaryztuvecMyltzibUyI"; + const char* boundary = "--gvdrLIiwm31yiNkOc7Hr3HdHouL22D-P_49Q"; + if (argc >= 2) + path = argv[1]; + test(path, boundary); +#ifdef WIN32 + printf("enter any key to exit ...\r\n"); + getchar(); +#endif + return 0; +} diff --git a/lib_acl_cpp/samples/http_mime/http_mime.vcproj b/lib_acl_cpp/samples/http_mime/http_mime.vcproj new file mode 100644 index 000000000..6d9b4d638 --- /dev/null +++ b/lib_acl_cpp/samples/http_mime/http_mime.vcproj @@ -0,0 +1,268 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_acl_cpp/samples/http_mime/stdafx.cpp b/lib_acl_cpp/samples/http_mime/stdafx.cpp new file mode 100644 index 000000000..706ab8c43 --- /dev/null +++ b/lib_acl_cpp/samples/http_mime/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// http_mime.pch 将成为预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + +// TODO: 在 STDAFX.H 中 +//引用任何所需的附加头文件,而不是在此文件中引用 diff --git a/lib_acl_cpp/samples/http_mime/stdafx.h b/lib_acl_cpp/samples/http_mime/stdafx.h new file mode 100644 index 000000000..12dfecdeb --- /dev/null +++ b/lib_acl_cpp/samples/http_mime/stdafx.h @@ -0,0 +1,7 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是常用但不常更改的项目特定的包含文件 +// + +#pragma once + +// TODO: 在此处引用程序要求的附加头文件 diff --git a/lib_acl_cpp/samples/http_mime/tmp.txt b/lib_acl_cpp/samples/http_mime/tmp.txt new file mode 100644 index 000000000..b5d99f68a --- /dev/null +++ b/lib_acl_cpp/samples/http_mime/tmp.txt @@ -0,0 +1,17 @@ + +-----------------------------5169208281820 +Content-Disposition: form-data; name="file_1"; filename="" +Content-Type: application/octet-stream + + +-----------------------------5169208281820 +Content-Disposition: form-data; name="file_0"; filename="test.txt" +Content-Type: text/plain + +hello world! + +-----------------------------5169208281820 +Content-Disposition: form-data; name="oper" + +upload +-----------------------------5169208281820-- diff --git a/lib_acl_cpp/samples/http_request/Makefile b/lib_acl_cpp/samples/http_request/Makefile new file mode 100644 index 000000000..61099e9f6 --- /dev/null +++ b/lib_acl_cpp/samples/http_request/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = http_request diff --git a/lib_acl_cpp/samples/http_request/json.txt b/lib_acl_cpp/samples/http_request/json.txt new file mode 100644 index 000000000..f1dca5a79 --- /dev/null +++ b/lib_acl_cpp/samples/http_request/json.txt @@ -0,0 +1 @@ +{"error_code": "ok", "error_msg": "ok", data: [{ "name": "郑树新", "pass": "zsx1" }, { "name": "郑树新", "pass": "zsx2" }]} diff --git a/lib_acl_cpp/samples/http_request/json_utf8.txt b/lib_acl_cpp/samples/http_request/json_utf8.txt new file mode 100644 index 000000000..c210a14c7 --- /dev/null +++ b/lib_acl_cpp/samples/http_request/json_utf8.txt @@ -0,0 +1,5 @@ +{ "error_code": "ok", "error_msg": "ok", data: [ + {"name":"涓浗", "pass": "xxx1"}, + {"name":"涓浗", "pass": "xxx1"}, + {"name":"涓浗", "pass": "xxx1"} +]} diff --git a/lib_acl_cpp/samples/http_request/main.cpp b/lib_acl_cpp/samples/http_request/main.cpp new file mode 100644 index 000000000..30a366c62 --- /dev/null +++ b/lib_acl_cpp/samples/http_request/main.cpp @@ -0,0 +1,203 @@ +// http_servlet.cpp : 定义控制台应用程序的入口点。 +// +#include +#include +#include "lib_acl.hpp" + +using namespace acl; + +////////////////////////////////////////////////////////////////////////// + +class http_request_test +{ +public: + http_request_test(const char* server_addr, const char* file, + const char* stype, const char* charset) + { + server_addr_= server_addr; + file_ = file; + stype_ = stype; + charset_ = charset; + to_charset_ = "gb2312"; + } + + ~http_request_test() {} + + bool run(void) + { + string body; + if (ifstream::load(file_, &body) == false) + { + logger_error("load %s error", file_.c_str()); + return false; + } + + http_request req(server_addr_); + + // 添加 HTTP 请求头字段 + + string ctype("text/"); + ctype << stype_ << "; charset=" << charset_; + + http_header& hdr = req.request_header(); // 请求头对象的引用 + hdr.set_url("/"); + hdr.set_content_type(ctype); + + // 发送 HTTP 请求数据 + if (req.request(body.c_str(), body.length()) == false) + { + logger_error("send http request to %s error", + server_addr_.c_str()); + return false; + } + + // 取出 HTTP 响应头的数据字段 + http_client* client = req.get_client(); + assert(client); + const char* p = client->header_value("Content-Type"); + if (p == NULL || *p == 0) + { + logger_error("no Content-Type"); + return false; + } + + // 分析 HTTP 响应头的数据类型 + http_ctype content_type; + content_type.parse(p); + + // 响应头数据类型的子类型 + const char* stype = content_type.get_stype(); + + bool ret; + if (stype == NULL) + ret = do_plain(req); + else if (strcasecmp(stype, "xml") == 0) + ret = do_xml(req); + else if (strcasecmp(stype, "json") == 0) + ret = do_json(req); + else + ret = do_plain(req); + if (ret == true) + printf("read ok!\r\n"); + return ret; + } + +private: + // 处理 text/plain 类型数据 + bool do_plain(http_request& req) + { + string body; + if (req.get_body(body, to_charset_) == false) + { + logger_error("get http body error"); + return false; + } + printf("body:\r\n(%s)\r\n", body.c_str()); + return true; + } + + // 处理 text/xml 类型数据 + bool do_xml(http_request& req) + { + xml body; + if (req.get_body(body, to_charset_) == false) + { + logger_error("get http body error"); + return false; + } + xml_node* node = body.first_node(); + while (node) + { + const char* tag = node->tag_name(); + const char* name = node->attr_value("name"); + const char* pass = node->attr_value("pass"); + printf(">>tag: %s, name: %s, pass: %s\r\n", + tag ? tag : "null", + name ? name : "null", + pass ? pass : "null"); + node = body.next_node(); + } + return true; + } + + // 处理 text/json 类型数据 + bool do_json(http_request& req) + { + json body; + if (req.get_body(body, to_charset_) == false) + { + logger_error("get http body error"); + return false; + } + + json_node* node = body.first_node(); + while (node) + { + if (node->tag_name()) + { + printf("tag: %s", node->tag_name()); + if (node->get_text()) + printf(", value: %s\r\n", node->get_text()); + else + printf("\r\n"); + } + node = body.next_node(); + } + return true; + } + +private: + string server_addr_; // web 服务器地址 + string file_; // 本地请求的数据文件 + string stype_; // 请求数据的子数据类型 + string charset_; // 本地请求数据文件的字符集 + string to_charset_; // 将服务器响应数据转为本地字符集 +}; + +////////////////////////////////////////////////////////////////////////// + +static void usage(const char* procname) +{ + printf("usage: %s -h[help]\r\n", procname); + printf("options:\r\n"); + printf("\t-f request file\r\n"); + printf("\t-t request stype[xml/json/plain]\r\n"); + printf("\t-c request file's charset[gb2312/utf-8]\r\n"); +} + +int main(int argc, char* argv[]) +{ + int ch; + string server_addr("127.0.0.1:8888"), file("./xml.txt"); + string stype("xml"), charset("gb2312"); + + while ((ch = getopt(argc, argv, "hs:f:t:c:")) > 0) + { + switch (ch) + { + case 'h': + usage(argv[0]); + return 0; + case 'f': + file = optarg; + break; + case 't': + stype = optarg; + break; + case 'c': + charset = optarg; + break; + default: + usage(argv[0]); + return 0; + } + } + + // 开始运行 + log::stdout_open(true); + http_request_test test(server_addr, file, stype, charset); + test.run(); + + return 0; +} + diff --git a/lib_acl_cpp/samples/http_request/valgrind.sh b/lib_acl_cpp/samples/http_request/valgrind.sh new file mode 100644 index 000000000..a8ba02ba0 --- /dev/null +++ b/lib_acl_cpp/samples/http_request/valgrind.sh @@ -0,0 +1,6 @@ +#!/bin/sh + +#valgrind --tool=memcheck --leak-check=yes --show-reachable=yes -v ./http_request -f xml.txt -t xml +valgrind --tool=memcheck --leak-check=yes --show-reachable=yes -v ./http_request -f xml_utf8.txt -t xml -c utf-8 +#valgrind --tool=memcheck --leak-check=yes --show-reachable=yes -v ./http_request -f json.txt -t json +#valgrind --tool=memcheck --leak-check=yes --show-reachable=yes -v ./http_request -f json_utf8.txt -t json -c utf-8 diff --git a/lib_acl_cpp/samples/http_request/xml.txt b/lib_acl_cpp/samples/http_request/xml.txt new file mode 100644 index 000000000..10a0a72b0 --- /dev/null +++ b/lib_acl_cpp/samples/http_request/xml.txt @@ -0,0 +1,7 @@ + + + + + + + diff --git a/lib_acl_cpp/samples/http_request/xml_utf8.txt b/lib_acl_cpp/samples/http_request/xml_utf8.txt new file mode 100644 index 000000000..28d798f96 --- /dev/null +++ b/lib_acl_cpp/samples/http_request/xml_utf8.txt @@ -0,0 +1,7 @@ + + + + + + + diff --git a/lib_acl_cpp/samples/http_request_pool/Makefile b/lib_acl_cpp/samples/http_request_pool/Makefile new file mode 100644 index 000000000..b7e514bdd --- /dev/null +++ b/lib_acl_cpp/samples/http_request_pool/Makefile @@ -0,0 +1,3 @@ +include ../Makefile.in +LDFLAGS += -lz +PROG = http_request_pool diff --git a/lib_acl_cpp/samples/http_request_pool/http_request_pool.vcproj b/lib_acl_cpp/samples/http_request_pool/http_request_pool.vcproj new file mode 100644 index 000000000..92d224ab0 --- /dev/null +++ b/lib_acl_cpp/samples/http_request_pool/http_request_pool.vcproj @@ -0,0 +1,279 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_acl_cpp/samples/http_request_pool/http_request_pool_vc2012.vcxproj b/lib_acl_cpp/samples/http_request_pool/http_request_pool_vc2012.vcxproj new file mode 100644 index 000000000..0c8744ed3 --- /dev/null +++ b/lib_acl_cpp/samples/http_request_pool/http_request_pool_vc2012.vcxproj @@ -0,0 +1,199 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + ReleaseDll + Win32 + + + Release + Win32 + + + + {58FE3581-C997-4BD5-9AC6-AEEB54A43D2C} + Win32Proj + http_request_pool + + + + Application + v110 + MultiByte + + + Application + v110 + MultiByte + + + Application + v110 + MultiByte + + + Application + v110 + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>11.0.50727.1 + + + Debug\ + Debug\ + true + + + Release\ + Release\ + false + + + $(Configuration)\ + $(Configuration)\ + false + + + $(Configuration)\ + $(Configuration)\ + true + + + + Disabled + ..\..\..\lib_acl_cpp\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Use + Level3 + EditAndContinue + + + lib_acl_cpp_vc2012d.lib;lib_acl_vc2012d.lib;lib_protocol_vc2012d.lib;%(AdditionalDependencies) + $(OutDir)http_request_pool.exe + ..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)http_request_pool.pdb + Console + MachineX86 + false + + + + + ..\..\..\lib_acl_cpp\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + Use + Level3 + ProgramDatabase + + + lib_acl_cpp_vc2012.lib;lib_acl_vc2012.lib;lib_protocol_vc2012.lib;%(AdditionalDependencies) + $(OutDir)http_request_pool.exe + ..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + + + + + ..\..\..\lib_acl_cpp\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_CPP_DLL;%(PreprocessorDefinitions) + MultiThreadedDLL + Use + Level3 + ProgramDatabase + + + lib_acl_cpp_dll.lib;lib_acl.lib;lib_protocol.lib;%(AdditionalDependencies) + $(OutDir)http_request_pool.exe + ..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + + + copy ..\..\..\dist\lib\win32\lib_acl.dll $(OutDir) /Y +copy ..\..\..\dist\lib\win32\lib_acl_cpp_dll.dll $(OutDir) /Y +copy ..\..\..\dist\lib\win32\lib_protocol.dll $(OutDir) /Y + + + + + Disabled + ..\..\..\lib_acl_cpp\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_CPP_DLL;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Use + Level3 + EditAndContinue + + + lib_acl_cppd_dll.lib;lib_acl_d.lib;lib_protocol_d.lib;%(AdditionalDependencies) + $(OutDir)http_request_pool.exe + ..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)http_request_pool.pdb + Console + MachineX86 + + + copy ..\..\..\dist\lib\win32\lib_acl_d.dll $(OutDir) /Y +copy ..\..\..\dist\lib\win32\lib_acl_cppd_dll.dll $(OutDir) /Y +copy ..\..\..\dist\lib\win32\lib_protocol_d.dll $(OutDir) /Y + + + + + + Create + Create + Create + Create + + + + + + + + + + + + \ No newline at end of file diff --git a/lib_acl_cpp/samples/http_request_pool/http_request_pool_vc2012.vcxproj.filters b/lib_acl_cpp/samples/http_request_pool/http_request_pool_vc2012.vcxproj.filters new file mode 100644 index 000000000..9618f1e58 --- /dev/null +++ b/lib_acl_cpp/samples/http_request_pool/http_request_pool_vc2012.vcxproj.filters @@ -0,0 +1,33 @@ +锘 + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx + + + + + 婧愭枃浠 + + + 婧愭枃浠 + + + + + 澶存枃浠 + + + + + + \ No newline at end of file diff --git a/lib_acl_cpp/samples/http_request_pool/main.cpp b/lib_acl_cpp/samples/http_request_pool/main.cpp new file mode 100644 index 000000000..dbd1f5e02 --- /dev/null +++ b/lib_acl_cpp/samples/http_request_pool/main.cpp @@ -0,0 +1,161 @@ +#include "stdafx.h" + +using namespace acl; + +static int __loop_count = 10; +static connect_pool* __conn_pool = NULL; +static acl_pthread_pool_t* __thr_pool = NULL; +static bool __unzip = false; + +// 初始化过程 +static void init(const char* addr, int count) +{ + // 创建 HTTP 请求连接池对象 + __conn_pool = new http_reuqest_pool(addr, count); + + // 创建线程池 + __thr_pool = acl_thread_pool_create(count, 60); +} + +// 进程退出前清理资源 +static void end(void) +{ + // 销毁线程池 + acl_pthread_pool_destroy(__thr_pool); + + // 销毁连接池 + delete __conn_pool; +} + +// HTTP 请求过程,向服务器发送请求后从服务器读取响应数据 +static bool http_get(http_request* conn, int n) +{ + // 创建 HTTP 请求头数据 + http_header& header = conn->request_header(); + header.set_url("/") + .set_keep_alive(true) + .set_method(HTTP_METHOD_GET) + .accept_gzip(__unzip); + + printf("%lu--%d: begin send request\r\n", acl_pthread_self(), n); + // 发送 HTTP 请求数据同时接收 HTTP 响应头 + if (conn->request(NULL, 0) == false) + { + printf("%lu--%d: send GET request error\r\n", + acl_pthread_self(), n); + return false; + } + + char buf[8192]; + int ret, length = 0; + + // 接收 HTTP 响应体数据 + while (true) + { + ret = conn->get_body(buf, sizeof(buf)); + if (ret == 0) + break; + else if (ret < 0) + { + printf("%lu--%d: error, length: %d\r\n", + acl_pthread_self(), n, length); + return false; + } + length += ret; + if (0) + printf("%lu--%d: read length: %d, %d\r\n", + acl_pthread_self(), n, length, ret); + } + printf("%lu--%d: read body over, length: %d\r\n", + acl_pthread_self(), n, length); + return true; +} + +// 线程处理过程 +static void thread_main(void*) +{ + for (int i = 0; i < __loop_count; i++) + { + // 从连接池中获取一个 HTTP 连接 + http_request* conn = (http_request*) __conn_pool->peek(); + if (conn == NULL) + { + printf("peek connect failed\r\n"); + break; + } + + // 需要对获得的连接重置状态,以清除上次请求过程的临时数据 + else + conn->reset(); + // 开始新的 HTTP 请求过程 + if (http_get(conn, i) == false) + { + printf("one request failed, close connection\r\n"); + // 错误连接需要关闭 + __conn_pool->put(conn, false); + } + else + __conn_pool->put(conn, true); + } +} + +static void run(int cocurrent) +{ + // 向线程池中添加任务 + for (int i = 0; i < cocurrent; i++) + acl_pthread_pool_add(__thr_pool, thread_main, NULL); +} + +static void usage(const char* procname) +{ + printf("usage: %s -h [help]\r\n" + " -s http_server_addr [www.sina.com.cn:80]\r\n" + " -z [unzip response body, default: false]\r\n" + " -c cocurrent [default: 10]\r\n" + " -n loop_count[default: 10]\r\n", procname); +} + +int main(int argc, char* argv[]) +{ + int ch, cocurrent = 10; + string addr("www.sina.com.cn:80"); + + // 初始化 acl 库 + acl::acl_cpp_init(); + + while ((ch = getopt(argc, argv, "hs:n:c:z")) > 0) + { + switch (ch) + { + case 'h': + usage(argv[0]); + return 0; + case 's': + addr = optarg; + break; + case 'c': + cocurrent = atoi(optarg); + break; + case 'n': + __loop_count = atoi(optarg); + break; + case 'z': + __unzip = true; + break; + default: + usage(argv[0]); + return 0; + } + } + + init(addr, cocurrent); + run(cocurrent); + end(); + +#ifdef WIN32 + printf("enter any key to exit...\r\n"); + getchar(); +#endif + + return 0; +} diff --git a/lib_acl_cpp/samples/http_request_pool/stdafx.cpp b/lib_acl_cpp/samples/http_request_pool/stdafx.cpp new file mode 100644 index 000000000..3a8a20e11 --- /dev/null +++ b/lib_acl_cpp/samples/http_request_pool/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// master_threads.pch 将成为预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + +// TODO: 在 STDAFX.H 中 +//引用任何所需的附加头文件,而不是在此文件中引用 diff --git a/lib_acl_cpp/samples/http_request_pool/stdafx.h b/lib_acl_cpp/samples/http_request_pool/stdafx.h new file mode 100644 index 000000000..c33ad33cd --- /dev/null +++ b/lib_acl_cpp/samples/http_request_pool/stdafx.h @@ -0,0 +1,19 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是常用但不常更改的项目特定的包含文件 +// + +#pragma once + + +//#include +//#include + +// TODO: 在此处引用程序要求的附加头文件 + +#include "lib_acl.h" +#include "acl_cpp/lib_acl.hpp" + +#ifdef WIN32 +#define snprintf _snprintf +#endif + diff --git a/lib_acl_cpp/samples/http_request_pool/valgrind.sh b/lib_acl_cpp/samples/http_request_pool/valgrind.sh new file mode 100644 index 000000000..f9433ef5f --- /dev/null +++ b/lib_acl_cpp/samples/http_request_pool/valgrind.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +valgrind --tool=memcheck --leak-check=yes -v ./http_request_pool -c 2 -n 2 diff --git a/lib_acl_cpp/samples/http_response/Makefile b/lib_acl_cpp/samples/http_response/Makefile new file mode 100644 index 000000000..6308a9f04 --- /dev/null +++ b/lib_acl_cpp/samples/http_response/Makefile @@ -0,0 +1,3 @@ +include ../Makefile.in +EXTLIBS = -lz +PROG = http_response diff --git a/lib_acl_cpp/samples/http_response/json.txt b/lib_acl_cpp/samples/http_response/json.txt new file mode 100644 index 000000000..05e8067fc --- /dev/null +++ b/lib_acl_cpp/samples/http_response/json.txt @@ -0,0 +1,6 @@ +POST / HTTP/1.1 +HOST: 127.0.0.1:8888 +Content-Type: text/json; charset=gb2312 +Content-Length: 124 + +{"error_code": "ok", "error_msg": "ok", data: [{ "name": "郑树新", "pass": "zsx1" }, { "name": "郑树新", "pass": "zsx2" }]} diff --git a/lib_acl_cpp/samples/http_response/json_utf8.txt b/lib_acl_cpp/samples/http_response/json_utf8.txt new file mode 100644 index 000000000..164ddced0 --- /dev/null +++ b/lib_acl_cpp/samples/http_response/json_utf8.txt @@ -0,0 +1,10 @@ +POST / HTTP/1.1 +HOST: 127.0.0.1:8888 +Content-Type: text/json; charset=utf-8 +Content-Length: 159 + +{ "error_code": "ok", "error_msg": "ok", data: [ + {"name":"涓浗", "pass": "xxx1"}, + {"name":"涓浗", "pass": "xxx1"}, + {"name":"涓浗", "pass": "xxx1"} +]} diff --git a/lib_acl_cpp/samples/http_response/main.cpp b/lib_acl_cpp/samples/http_response/main.cpp new file mode 100644 index 000000000..aa109f169 --- /dev/null +++ b/lib_acl_cpp/samples/http_response/main.cpp @@ -0,0 +1,249 @@ +// http_servlet.cpp : 定义控制台应用程序的入口点。 +// +#include +#include "acl_cpp/lib_acl.hpp" + +static void (*format)(const char*, ...) = acl::log::msg1; + +using namespace acl; + +////////////////////////////////////////////////////////////////////////// + +class master_service : public master_proc +{ +public: + master_service(const char* to_charset = "gb2312") + { + local_charset_ = to_charset; + } + + ~master_service() {} + + void set_charset(const char* to_charset) + { + local_charset_ = to_charset; + } + +protected: + // 当接收到客户端连接流后回调的虚接口 + virtual void on_accept(socket_stream* stream) + { + http_response res(stream); + + // 读客户端的 HTTP 请求头 + if (res.read_header() == false) + { + const char* ptr = "read request header error"; + res.response(ptr, strlen(ptr), 400, false); + return; + } + + // 从 HTTP 请求头中取出 Content-Type 字段值 + // Content-Type: text/xml; charset=utf-8 + http_client* client = res.get_client(); + assert(client); + const char* p = client->header_value("Content-Type"); + if (p == NULL || *p == 0) + { + const char* ptr = "no Content-Type"; + res.response(ptr, strlen(ptr), 400, false); + return; + } + + // 从 HTTP 请求头中取得数据类型中的子类型 + // 如果请求头中有:Content-Type: text/xml; charset=utf-8 + // 则 get_stype 取得 xml 子类型 + http_ctype content_type; + content_type.parse(p); + const char* stype = content_type.get_stype(); + const char* req_charset = content_type.get_charset(); + + bool ret; + string err; + + // 根据子类型的不同调用不同的处理过程 + + if (stype == NULL) + ret = do_plain(res, req_charset, err); + + // text/xml 格式 + else if (strcasecmp(stype, "xml") == 0) + ret = do_xml(res, req_charset, err); + + // text/json 格式 + else if (strcasecmp(stype, "json") == 0) + ret = do_json(res, req_charset, err); + else + ret = do_plain(res, req_charset, err); + if (ret == false) + res.response(err.c_str(), err.length()); + } + +private: + // 处理 text/plain 数据体 + bool do_plain(http_response& res, const char* req_charset, string& err) + { + string body; + if (res.get_body(body, local_charset_) == false) + { + err += "get_body error"; + return false; + } + printf("body:\r\n(%s)\r\n", body.c_str()); + + // 设置响应头字段 + http_header& header = res.response_header(); + string ctype("text/plain"); + if (req_charset) + { + ctype << "; charset=" << req_charset; + header.set_content_type(ctype); + } + else + header.set_content_type(ctype); + + printf(">>ctype: %s\r\n", ctype.c_str()); + + // 发送响应体数据 + return response_body(res, body, req_charset); + } + + // 处理 text/xml 数据体 + bool do_xml(http_response& res, const char* req_charset, string& err) + { + xml body; + if (res.get_body(body, local_charset_) == false) + { + err += "get_body error"; + return false; + } + xml_node* node = body.first_node(); + while (node) + { + const char* tag = node->tag_name(); + const char* name = node->attr_value("name"); + const char* pass = node->attr_value("pass"); + printf(">>tag: %s, name: %s, pass: %s\r\n", + tag ? tag : "null", + name ? name : "null", + pass ? pass : "null"); + node = body.next_node(); + } + + // 设置响应头字段 + http_header& header = res.response_header(); + string ctype("text/xml"); + if (req_charset) + { + ctype << "; charset=" << req_charset; + header.set_content_type(ctype); + } + else + header.set_content_type(ctype); + + printf(">>ctype: %s\r\n", ctype.c_str()); + + // 构建响应体数据,并发送响应体数据 + string buf; + body.build_xml(buf); + + // 发送响应体数据 + return response_body(res, buf, req_charset); + } + + // 处理 text/json 数据 + bool do_json(http_response& res, const char* req_charset, string& err) + { + json body; + if (res.get_body(body, local_charset_) == false) + { + err += "get_body error"; + return false; + } + + json_node* node = body.first_node(); + while (node) + { + if (node->tag_name()) + { + printf("tag: %s", node->tag_name()); + if (node->get_text()) + printf(", value: %s\r\n", node->get_text()); + else + printf("\r\n"); + } + node = body.next_node(); + } + + // 设置响应头字段 + http_header& header = res.response_header(); + string ctype("text/json"); + if (req_charset) + { + ctype << "; charset=" << req_charset; + header.set_content_type(ctype); + } + else + header.set_content_type(ctype); + + printf(">>ctype: %s\r\n", ctype.c_str()); + + // 构建响应体数据,并发送响应体数据 + string buf; + body.build_json(buf); + + // 发送响应体数据 + return response_body(res, buf, req_charset); + } + + bool response_body(http_response& res, const string& body, + const char* req_charset) + { + // 如果本地字符集与请求字符集相同,则直接发送 + if (local_charset_ == req_charset) + return res.response(body.c_str(), body.length()); + + // 不一致时,则需要进行转码 + string buf; + charset_conv conv; + if (conv.convert(local_charset_, req_charset, + body.c_str(), body.length(), &buf) == false) + { + logger_error("charset convert from %s to %s error", + local_charset_.c_str(), req_charset); + return false; + } + + printf(">>response\r\n(%s)\r\n", buf.c_str()); + return res.response(buf.c_str(), buf.length()); + } + +private: + string local_charset_; +}; + +////////////////////////////////////////////////////////////////////////// + +int main(int argc, char* argv[]) +{ +#ifdef WIN32 + acl::acl_cpp_init(); +#endif + master_service service; // 服务器单例对象 + + // 开始运行 + + if (argc >= 2 && strcmp(argv[1], "alone") == 0) + { + if (argc >= 3) + service.set_charset(argv[2]); + + format = (void (*)(const char*, ...)) printf; + printf("listen: 0.0.0.0:8888 ...\r\n"); + service.run_alone("0.0.0.0:8888", NULL, 1); // 单独运行方式 + } + else + service.run_daemon(argc, argv); // acl_master 控制模式运行 + + return 0; +} diff --git a/lib_acl_cpp/samples/http_response/valgrind.sh b/lib_acl_cpp/samples/http_response/valgrind.sh new file mode 100644 index 000000000..f7b66922f --- /dev/null +++ b/lib_acl_cpp/samples/http_response/valgrind.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +valgrind --tool=memcheck --leak-check=yes --show-reachable=yes -v ./http_response alone diff --git a/lib_acl_cpp/samples/http_response/xml.txt b/lib_acl_cpp/samples/http_response/xml.txt new file mode 100644 index 000000000..915b96112 --- /dev/null +++ b/lib_acl_cpp/samples/http_response/xml.txt @@ -0,0 +1,12 @@ +POST / HTTP/1.1 +HOST: 127.0.0.1:8888 +Content-Type: text/xml; charset=gb2312 +Content-Length: 154 + + + + + + + + diff --git a/lib_acl_cpp/samples/http_response/xml_utf8.txt b/lib_acl_cpp/samples/http_response/xml_utf8.txt new file mode 100644 index 000000000..64aa41ab8 --- /dev/null +++ b/lib_acl_cpp/samples/http_response/xml_utf8.txt @@ -0,0 +1,12 @@ +POST / HTTP/1.1 +HOST: 127.0.0.1:8888 +Content-Type: text/xml; charset=utf-8 +Content-Length: 153 + + + + + + + + diff --git a/lib_acl_cpp/samples/http_server/Makefile b/lib_acl_cpp/samples/http_server/Makefile new file mode 100644 index 000000000..84b2acd08 --- /dev/null +++ b/lib_acl_cpp/samples/http_server/Makefile @@ -0,0 +1,4 @@ +include ../Makefile.in +#EXTLIBS = -lpolarssl +EXTLIBS = -lz +PROG = http_server diff --git a/lib_acl_cpp/samples/http_server/ReadMe.txt b/lib_acl_cpp/samples/http_server/ReadMe.txt new file mode 100644 index 000000000..b4f9ca766 --- /dev/null +++ b/lib_acl_cpp/samples/http_server/ReadMe.txt @@ -0,0 +1,31 @@ +======================================================================== + 控制台应用程序 : http_server 项目概况 +======================================================================== + +应用程序向导已为您创建了这个 http_server 应用程序。 +此文件包含组成 http_server 应用程序 +的每个文件的内容摘要。 + + +http_server.vcproj + 这是用应用程序向导生成的 VC++ 项目的主项目文件。 + 它包含有关生成此文件的 Visual C++ 版本的信息,以及 + 有关用应用程序向导选择的 + 平台、配置和项目功能的信息。 + +http_server.cpp + 这是主应用程序源文件。 + +///////////////////////////////////////////////////////////////////////////// +其他标准文件: + +StdAfx.h、StdAfx.cpp + 这些文件用于生成名为 http_server.pch + 的预编译头(PCH)文件以及名为 StdAfx.obj 的预编译类型文件。 + +///////////////////////////////////////////////////////////////////////////// +其他注释: + +应用程序向导使用 "TODO:" 注释指示应添加或自定义的源代码部分。 + +///////////////////////////////////////////////////////////////////////////// diff --git a/lib_acl_cpp/samples/http_server/http_rpc.cpp b/lib_acl_cpp/samples/http_server/http_rpc.cpp new file mode 100644 index 000000000..4c54319ad --- /dev/null +++ b/lib_acl_cpp/samples/http_server/http_rpc.cpp @@ -0,0 +1,111 @@ +#include "stdafx.h" +#include "rpc_stats.h" +#include "http_rpc.h" + +http_rpc::http_rpc(acl::aio_socket_stream* client, unsigned buf_size) +: proc_quit_(false) +, handle_(client->get_handle()) +, client_(client) +, buf_size_(buf_size) +{ + res_buf_ = (char*) acl_mymalloc(buf_size + 1); + unsigned i; + for (i = 0; i < buf_size; i++) + res_buf_[i] = 'x'; + res_buf_[i] = 0; +} + +http_rpc::~http_rpc() +{ + acl_myfree(res_buf_); +} + +void http_rpc::rpc_onover() +{ + // 减少 rpc 计数 + rpc_del(); + + if (!proc_quit_ && keep_alive_) + { + rpc_read_wait_add(); + + // 监控异步流是否可读 + client_->read_wait(10); + } + else + // 关闭异步流对象 + client_->close(); + + // 客户端发来了要求服务器程序退出的命令 + if (proc_quit_) + handle_.stop(); +} + +// 调用 service_.rpc_fork 后,由 RPC 框架在子线程中调用本函数 +// 来处理本地其它模块发来的请求信息 +void http_rpc::rpc_run() +{ + // 打开阻塞流对象 + socket_stream stream; + + // 必须用 get_vstream() 获得的 ACL_VSTREAM 流对象做参数 + // 来打开 stream 对象,因为在 acl_cpp 和 acl 中的阻塞流 + // 和非阻塞流最终都是基于 ACL_VSTREAM,而 ACL_VSTREAM 流 + // 内部维护着了一个读/写缓冲区,所以在长连接的数据处理中, + // 必须每次将 ACL_VSTREAM 做为内部流的缓冲流来对待 + ACL_VSTREAM* vstream = client_->get_vstream(); + ACL_VSTREAM_SET_RWTIMO(vstream, 10); + (void) stream.open(vstream); + + rpc_req_add(); + + // 开始处理该 HTTP 请求 + handle_conn(&stream); + + rpc_req_del(); + + // 将 ACL_VSTREAM 与阻塞流对象解绑定,这样才能保证当释放阻塞流对象时 + // 不会关闭与请求者的连接,因为该连接本身是属于非阻塞流对象的,需要采 + // 用异步流关闭方式进行关闭 + stream.unbind(); +} + +void http_rpc::handle_conn(socket_stream* stream) +{ + // HTTP 响应对象构造 + http_response res(stream); + // 响应数据体为 xml 格式 + res.response_header().set_content_type("text/html"); + + // 读 HTTP 请求头 + if (res.read_header() == false) + { + keep_alive_ = false; + return; + } + + string buf; + // 读 HTTP 请求体数据 + if (res.get_body(buf) == false) + { + keep_alive_ = false; + return; + } + + http_client* client = res.get_client(); + + // 判断客户端是否希望保持长连接 + keep_alive_ = client->keep_alive(); + + // 返回数据给客户端 + + res.response(res_buf_, buf_size_, 200, keep_alive_); + + // 取得客户端的命令 + const char* action = client->request_param("action"); + if (action && (strcasecmp(action, "stop") == 0 + || strcasecmp(action, "quit") == 0)) + { + proc_quit_ = true; + } +} diff --git a/lib_acl_cpp/samples/http_server/http_rpc.h b/lib_acl_cpp/samples/http_server/http_rpc.h new file mode 100644 index 000000000..cde73d5d6 --- /dev/null +++ b/lib_acl_cpp/samples/http_server/http_rpc.h @@ -0,0 +1,31 @@ +#pragma once +#include "acl_cpp/ipc/rpc.hpp" +#include "acl_cpp/stream/aio_socket_stream.hpp" +#include "acl_cpp/stream/socket_stream.hpp" +//class acl::aio_socket_stream; +//class acl::socket_stream; + +class http_rpc : public acl::rpc_request +{ +public: + http_rpc(acl::aio_socket_stream* client, unsigned buf_size); + ~http_rpc(); + +protected: + // 子线程处理函数 + virtual void rpc_run(); + + // 主线程处理过程,收到子线程任务完成的消息 + virtual void rpc_onover(); + +private: + bool proc_quit_; // 程序是否应该退出 + acl::aio_handle& handle_; // 异步框架引擎 + acl::aio_socket_stream* client_; // 客户端连接流 + bool keep_alive_; // 是否与客户端保持长连接 + char* res_buf_; // 存放返回给客户端数据的缓冲区 + unsigned buf_size_; // res_buf_ 的空间大小 + + // 在子线程中以阻塞方式处理客户端请求 + void handle_conn(acl::socket_stream* stream); +}; diff --git a/lib_acl_cpp/samples/http_server/http_server.cpp b/lib_acl_cpp/samples/http_server/http_server.cpp new file mode 100644 index 000000000..5d4bb647f --- /dev/null +++ b/lib_acl_cpp/samples/http_server/http_server.cpp @@ -0,0 +1,289 @@ +// http_server.cpp : 定义控制台应用程序的入口点。 +// + +#include "stdafx.h" +#include +#include "rpc_manager.h" +#include "rpc_stats.h" +#include "http_rpc.h" + +static int var_data_size = 1024; + +////////////////////////////////////////////////////////////////////////// + +/** + * 异步客户端流的回调类的子类 + */ +class handle_io : public aio_callback +{ +public: + handle_io(aio_socket_stream* client) + : client_(client) + { + http_ = new http_rpc(client_, (unsigned) var_data_size); + } + + ~handle_io() + { + delete http_; + std::cout << "delete io_callback now ..." << std::endl; + } + + bool write_callback() + { + return (true); + } + + /** + * 实现父类中的虚函数,客户端流的超时回调过程 + */ + void close_callback() + { + std::cout << "Closed now." << std::endl; + + // 必须在此处删除该动态分配的回调类对象以防止内存泄露 + delete this; + } + + /** + * 实现父类中的虚函数,客户端流的超时回调过程 + * @return {bool} 返回 true 表示继续,否则希望关闭该异步流 + */ + bool timeout_callback() + { + std::cout << "Timeout ..." << std::endl; + return (false); + } + + virtual bool read_wakeup() + { + // 测试状态 + rpc_read_wait_del(); + rpc_add(); + + // 从异步监听集合中去掉对该异步流的监控 + client_->disable_read(); + + // 发起一个 http 会话过程 + rpc_manager::get_instance().fork(http_); + + return true; + } + +private: + aio_socket_stream* client_; + http_rpc* http_; +}; + +////////////////////////////////////////////////////////////////////////// + +/** + * 异步监听流的回调类的子类 + */ +class handle_accept : public aio_accept_callback +{ +public: + handle_accept(bool preread) + : preread_(preread) + { + } + + ~handle_accept() + { + printf(">>io_accept_callback over!\n"); + } + + /** + * 基类虚函数,当有新连接到达后调用此回调过程 + * @param client {aio_socket_stream*} 异步客户端流 + * @return {bool} 返回 true 以通知监听流继续监听 + */ + bool accept_callback(acl::aio_socket_stream* client) + { + // 如果允许在主线程中预读,则设置流的预读标志位 + if (preread_) + { + ACL_VSTREAM* vstream = client->get_vstream(); + vstream->flag |= ACL_VSTREAM_FLAG_PREREAD; + } + + // 创建异步客户端流的回调对象并与该异步流进行绑定 + handle_io* callback = new handle_io(client); + + // 注册异步流的读回调过程 + client->add_read_callback(callback); + + // 注册异步流的写回调过程 + client->add_write_callback(callback); + + // 注册异步流的关闭回调过程 + client->add_close_callback(callback); + + // 注册异步流的超时回调过程 + client->add_timeout_callback(callback); + + rpc_read_wait_add(); + + // 监控异步流是否可读 + client->read_wait(10); + + return (true); + } + +private: + bool preread_; +}; + +static void usage(const char* procname) +{ + printf("usage: %s \r\n" + " -h[help]\r\n" + " -p[preread in main thread]\r\n" + " -l listen_addr[127.0.0.1:9001]\r\n" + " -m[use mempool]\r\n" + " -k[use kernel engine]\r\n" + " -n data size response\r\n" + " -N thread pool limit\r\n" + " -r rpc_addr\r\n" + " -v[enable stdout]\r\n", procname); +} + +int main(int argc, char* argv[]) +{ +#ifdef WIN32 + acl_cpp_init(); +#endif + + bool preread = false; + char addr[32], rpc_addr[32], ch; + bool use_mempool = false; + bool use_kernel = false; + bool enable_stdout = false; + int nthreads = 20; + + snprintf(addr, sizeof(addr), "127.0.0.1:9001"); + snprintf(rpc_addr, sizeof(rpc_addr), "127.0.0.1:0"); + + while ((ch = getopt(argc, argv, "vkhpms:n:N:r:")) > 0) + { + switch (ch) + { + case 'h': + usage(argv[0]); + return 0; + case 's': + snprintf(addr, sizeof(addr), "%s", optarg); + break; + case 'p': + preread = true; + break; + case 'm': + use_mempool = true; + break; + case 'k': + use_kernel = true; + break; + case 'n': + var_data_size = atoi(optarg); + if (var_data_size <= 0) + var_data_size = 1024; + break; + case 'N': + nthreads = atoi(optarg); + if (nthreads <= 0) + nthreads = 10; + break; + case 'v': + enable_stdout = true; + break; + case 'r': + snprintf(rpc_addr, sizeof(rpc_addr), "%s", optarg); + break; + default: + break; + } + } + + // 是否采用线程局部内存池 + if (use_mempool) + acl_mem_slice_init(8, 1024, 100000, + ACL_SLICE_FLAG_GC2 | + ACL_SLICE_FLAG_RTGC_OFF | + ACL_SLICE_FLAG_LP64_ALIGN); + + rpc_stats_init(); + + // 允许日志信息输出至屏幕 + if (enable_stdout) + log::stdout_open(true); + + // 异步通信框架句柄,采用 select 系统 api + aio_handle* handle = new aio_handle(use_kernel ? ENGINE_KERNEL : ENGINE_SELECT); + + // 创建监听异步流 + aio_listen_stream* sstream = new aio_listen_stream(handle); + + // 监听指定的地址 + if (sstream->open(addr) == false) + { + std::cout << "open " << addr << " error!" << std::endl; + sstream->close(); + // XXX: 为了保证能关闭监听流,应在此处再 check 一下 + handle->check(); +#ifdef WIN32 + getchar(); +#endif + return 1; + } + + // 初始化异步 RPC 通信服务句柄 + rpc_manager::get_instance().init(handle, nthreads, rpc_addr); + + // 创建回调类对象,当有新连接到达时自动调用此类对象的回调过程 + handle_accept callback(preread); + // 将回调处理类对象与异步监听流绑定 + sstream->add_accept_callback(&callback); + + std::cout << "Listen: " << addr << " ok!" << std::endl; + + time_t last = time(NULL), now; + while (true) + { + // 如果返回 false 则表示不再继续,需要退出 + if (handle->check() == false) + { + std::cout << "aio_server stop now ..." << std::endl; + break; + } + + time(&now); + if (now - last >= 1) + { + printf("\r\n------------------------------\r\n"); + rpc_out(); // 输出当前 rpc 队列的数量 + rpc_req_out(); + rpc_read_wait_out(); + last = now; + } + } + + // 关闭监听流并释放流对象 + sstream->close(); + + // 关闭 RPC 服务 + rpc_manager::get_instance().finish(); + + // XXX: 为了保证能关闭监听流,应在此处再 check 一下 + handle->check(); + delete handle; + + rpc_stats_finish(); + + if (use_mempool) + { + acl_mem_slice_gc(); + acl_mem_slice_destroy(); + } + + return 0; +} diff --git a/lib_acl_cpp/samples/http_server/http_server.vcproj b/lib_acl_cpp/samples/http_server/http_server.vcproj new file mode 100644 index 000000000..fc907fc18 --- /dev/null +++ b/lib_acl_cpp/samples/http_server/http_server.vcproj @@ -0,0 +1,296 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_acl_cpp/samples/http_server/rpc_manager.cpp b/lib_acl_cpp/samples/http_server/rpc_manager.cpp new file mode 100644 index 000000000..1687858ac --- /dev/null +++ b/lib_acl_cpp/samples/http_server/rpc_manager.cpp @@ -0,0 +1,40 @@ +#include "stdafx.h" +#include "rpc_manager.h" + +rpc_manager::rpc_manager() +: handle_(NULL) +, service_(NULL) +{ +} + +rpc_manager::~rpc_manager() +{ +} + + +void rpc_manager::init(acl::aio_handle* handle, int max_threads /* = 10 */, + const char* rpc_addr /* = NULL */) +{ + handle_ = handle; + + // 创建 rpc 服务对象 + service_ = new acl::rpc_service(max_threads); + // 打开消息服务 + if (service_->open(handle_, rpc_addr) == false) + logger_fatal("open service error: %s", acl::last_serror()); +} + +void rpc_manager::finish() +{ + if (service_) + { + delete service_; + if (handle_) + handle_->check(); + } +} + +void rpc_manager::fork(acl::rpc_request* req) +{ + service_->rpc_fork(req); +} diff --git a/lib_acl_cpp/samples/http_server/rpc_manager.h b/lib_acl_cpp/samples/http_server/rpc_manager.h new file mode 100644 index 000000000..5e41fef0a --- /dev/null +++ b/lib_acl_cpp/samples/http_server/rpc_manager.h @@ -0,0 +1,33 @@ +#pragma once + +/** + * 本类对象将阻塞任务交给子线程处理;为了方便使用,将该类声明为单例类 + */ +class rpc_manager : public acl::singleton +{ +public: + rpc_manager(); + ~rpc_manager(); + + /** + * 初始化函数 + * @param handle {acl::aio_handle*} 异步引擎句柄 + * @param max_threads {int} 子线程池的最大线程数量 + * @param rpc_addr {const char*} RPC 通道监听地址 + */ + void init(acl::aio_handle*, int max_threads = 10, + const char* rpc_addr = NULL); + + void finish(); + + /** + * 发起一个阻塞过程,将该过程交由子线程处理 + * @param req {acl::rpc_request*} 阻塞任务对象 + */ + void fork(acl::rpc_request* req); +private: + // 异步消息句柄 + acl::aio_handle* handle_; + // 异步 RPC 通信服务句柄 + acl::rpc_service* service_; +}; diff --git a/lib_acl_cpp/samples/http_server/rpc_stats.cpp b/lib_acl_cpp/samples/http_server/rpc_stats.cpp new file mode 100644 index 000000000..936fe1323 --- /dev/null +++ b/lib_acl_cpp/samples/http_server/rpc_stats.cpp @@ -0,0 +1,74 @@ +#include "stdafx.h" +#include "rpc_stats.h" + +static int __count = 0; + +void rpc_add() +{ + __count++; +} + +void rpc_del() +{ + __count--; +} + +void rpc_out() +{ + printf(">> rpc_count: %d\r\n", __count); +} + +////////////////////////////////////////////////////////////////////////// + +static locker* __lock = NULL; +static int __req = 0; + +void rpc_stats_init() +{ + __lock = new locker(); +} + +void rpc_stats_finish() +{ + delete __lock; +} + +void rpc_req_add() +{ + __lock->lock(); + __req++; + __lock->unlock(); +} + +void rpc_req_del() +{ + __lock->lock(); + __req--; + __lock->unlock(); +} + +void rpc_req_out() +{ + __lock->lock(); + printf(">> req_count: %d\r\n", __req); + __lock->unlock(); +} + +////////////////////////////////////////////////////////////////////////// + +static int __read_wait = 0; + +void rpc_read_wait_add() +{ + __read_wait++; +} + +void rpc_read_wait_del() +{ + __read_wait--; +} + +void rpc_read_wait_out() +{ + printf(">> read wait count: %d\r\n", __read_wait); +} diff --git a/lib_acl_cpp/samples/http_server/rpc_stats.h b/lib_acl_cpp/samples/http_server/rpc_stats.h new file mode 100644 index 000000000..5045a24ba --- /dev/null +++ b/lib_acl_cpp/samples/http_server/rpc_stats.h @@ -0,0 +1,16 @@ +#pragma once + +void rpc_stats_init(); +void rpc_stats_finish(); + +void rpc_add(); +void rpc_del(); +void rpc_out(); + +void rpc_req_add(); +void rpc_req_del(); +void rpc_req_out(); + +void rpc_read_wait_add(); +void rpc_read_wait_del(); +void rpc_read_wait_out(); diff --git a/lib_acl_cpp/samples/http_server/stdafx.cpp b/lib_acl_cpp/samples/http_server/stdafx.cpp new file mode 100644 index 000000000..2617e0858 --- /dev/null +++ b/lib_acl_cpp/samples/http_server/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// http_server.pch 将成为预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + +// TODO: 在 STDAFX.H 中 +//引用任何所需的附加头文件,而不是在此文件中引用 diff --git a/lib_acl_cpp/samples/http_server/stdafx.h b/lib_acl_cpp/samples/http_server/stdafx.h new file mode 100644 index 000000000..f217760d1 --- /dev/null +++ b/lib_acl_cpp/samples/http_server/stdafx.h @@ -0,0 +1,12 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是常用但不常更改的项目特定的包含文件 +// + +#pragma once + +// TODO: 在此处引用程序要求的附加头文件 + +#include "lib_acl.h" +#include "acl_cpp/lib_acl.hpp" + +using namespace acl; diff --git a/lib_acl_cpp/samples/http_server/valgrind.sh b/lib_acl_cpp/samples/http_server/valgrind.sh new file mode 100644 index 000000000..f5d3f0acc --- /dev/null +++ b/lib_acl_cpp/samples/http_server/valgrind.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +#valgrind --tool=memcheck --leak-check=yes --track-origins=yes -v ./http_server +valgrind --tool=memcheck --leak-check=yes -v ./http_server -k diff --git a/lib_acl_cpp/samples/http_servlet/Makefile b/lib_acl_cpp/samples/http_servlet/Makefile new file mode 100644 index 000000000..11ebcac17 --- /dev/null +++ b/lib_acl_cpp/samples/http_servlet/Makefile @@ -0,0 +1,4 @@ +include ../Makefile.in +#EXTLIBS = -lpolarssl +EXTLIBS = -lz +PROG = http_servlet diff --git a/lib_acl_cpp/samples/http_servlet/ReadMe.txt b/lib_acl_cpp/samples/http_servlet/ReadMe.txt new file mode 100644 index 000000000..677ee3ddd --- /dev/null +++ b/lib_acl_cpp/samples/http_servlet/ReadMe.txt @@ -0,0 +1,31 @@ +======================================================================== + 控制台应用程序 : http_servlet 项目概况 +======================================================================== + +应用程序向导已为您创建了这个 http_servlet 应用程序。 +此文件包含组成 http_servlet 应用程序 +的每个文件的内容摘要。 + + +http_servlet.vcproj + 这是用应用程序向导生成的 VC++ 项目的主项目文件。 + 它包含有关生成此文件的 Visual C++ 版本的信息,以及 + 有关用应用程序向导选择的 + 平台、配置和项目功能的信息。 + +http_servlet.cpp + 这是主应用程序源文件。 + +///////////////////////////////////////////////////////////////////////////// +其他标准文件: + +StdAfx.h、StdAfx.cpp + 这些文件用于生成名为 http_servlet.pch + 的预编译头(PCH)文件以及名为 StdAfx.obj 的预编译类型文件。 + +///////////////////////////////////////////////////////////////////////////// +其他注释: + +应用程序向导使用 "TODO:" 注释指示应添加或自定义的源代码部分。 + +///////////////////////////////////////////////////////////////////////////// diff --git a/lib_acl_cpp/samples/http_servlet/http_servlet.cpp b/lib_acl_cpp/samples/http_servlet/http_servlet.cpp new file mode 100644 index 000000000..c10a542e0 --- /dev/null +++ b/lib_acl_cpp/samples/http_servlet/http_servlet.cpp @@ -0,0 +1,135 @@ +// http_servlet.cpp : 定义控制台应用程序的入口点。 +// + +#include "stdafx.h" +#include "acl_cpp/lib_acl.hpp" + +static void (*format)(const char*, ...) = acl::log::msg1; + +using namespace acl; + +////////////////////////////////////////////////////////////////////////// + +class http_servlet : public HttpServlet +{ +public: + http_servlet(void) + { + + } + + ~http_servlet(void) + { + + } + + virtual bool doGet(HttpServletRequest& req, HttpServletResponse& res) + { + return doPost(req, res); + } + + virtual bool doPost(HttpServletRequest& req, HttpServletResponse& res) + { + const char* sid = req.getSession().getAttribute("sid"); + if (*sid == 0) + req.getSession().setAttribute("sid", "xxxxxx"); + sid = req.getSession().getAttribute("sid"); + + const char* cookie1 = req.getCookieValue("name1"); + const char* cookie2 = req.getCookieValue("name2"); + + // 创建 HTTP 响应头 + res.addCookie("name1", "value1"); + res.addCookie("name2", "value2", ".test.com", "/", 3600 * 24); + + // 设置响应头的状态码 + //res.setStatus(200); + + // 两种方式都可以设置字符集 + if (0) + res.setContentType("text/xml; charset=gb2312"); + else + { + res.setContentType("text/xml"); + res.setCharacterEncoding("gb2312"); + } + + const char* param1 = req.getParameter("name1"); + const char* param2 = req.getParameter("name2"); + + // 创建 xml 格式的数据体 + xml body; + body.get_root().add_child("root", true) + .add_child("sessions", true) + .add_child("session", true) + .add_attr("sid", sid ? sid : "null") + .get_parent() + .get_parent() + .add_child("cookies", true) + .add_child("cookie", true) + .add_attr("name1", cookie1 ? cookie1 : "null") + .get_parent() + .add_child("cookie", true) + .add_attr("name2", cookie2 ? cookie2 : "null") + .get_parent() + .get_parent() + .add_child("params", true) + .add_child("param", true) + .add_attr("name1", param1 ? param1 : "null") + .get_parent() + .add_child("param", true) + .add_attr("name2", param2 ? param2 : "null"); + + string buf; + body.build_xml(buf); + + // 发送 http 响应头 + if (res.sendHeader() == false) + return false; + // 发送 http 响应体 + if (res.getOutputStream().write(buf) == -1) + return false; + return true; + } +protected: +private: +}; + +////////////////////////////////////////////////////////////////////////// + +class master_service : public master_proc +{ +public: + master_service() {} + ~master_service() {} +protected: + virtual void on_accept(socket_stream* stream) + { + memcache_session session("127.0.0.1:11211"); + http_servlet servlet; + servlet.setLocalCharset("gb2312"); + servlet.doRun(session, stream); + } +}; + +////////////////////////////////////////////////////////////////////////// + +int main(int argc, char* argv[]) +{ + acl::acl_cpp_init(); + master_service service; + + // 开始运行 + + if (argc >= 2 && strcmp(argv[1], "alone") == 0) + { + format = (void (*)(const char*, ...)) printf; + printf("listen: 0.0.0.0:8888 ...\r\n"); + service.run_alone("0.0.0.0:8888", NULL, 1); // 单独运行方式 + } + else + service.run_daemon(argc, argv); // acl_master 控制模式运行 + + return 0; +} + diff --git a/lib_acl_cpp/samples/http_servlet/http_servlet.vcproj b/lib_acl_cpp/samples/http_servlet/http_servlet.vcproj new file mode 100644 index 000000000..ec49d119f --- /dev/null +++ b/lib_acl_cpp/samples/http_servlet/http_servlet.vcproj @@ -0,0 +1,271 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_acl_cpp/samples/http_servlet/stdafx.cpp b/lib_acl_cpp/samples/http_servlet/stdafx.cpp new file mode 100644 index 000000000..a661c4e28 --- /dev/null +++ b/lib_acl_cpp/samples/http_servlet/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// http_servlet.pch 将成为预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + +// TODO: 在 STDAFX.H 中 +//引用任何所需的附加头文件,而不是在此文件中引用 diff --git a/lib_acl_cpp/samples/http_servlet/stdafx.h b/lib_acl_cpp/samples/http_servlet/stdafx.h new file mode 100644 index 000000000..b98553f2c --- /dev/null +++ b/lib_acl_cpp/samples/http_servlet/stdafx.h @@ -0,0 +1,11 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是常用但不常更改的项目特定的包含文件 +// + +#pragma once + + +#include +//#include + +// TODO: 在此处引用程序要求的附加头文件 diff --git a/lib_acl_cpp/samples/http_servlet/test.txt b/lib_acl_cpp/samples/http_servlet/test.txt new file mode 100644 index 000000000..2b45a0ae2 --- /dev/null +++ b/lib_acl_cpp/samples/http_servlet/test.txt @@ -0,0 +1,14 @@ +POST /cgi-bin/test/http_servlet?name1=%CD%E2%B9%FA%C8%CB HTTP/1.1 +Host: 127.0.0.1 +User-Agent: Mozilla/5.0 (Windows NT 5.1; rv:12.0) Gecko/20100101 Firefox/12.0 +Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 +Accept-Language: zh-cn,en-us;q=0.7,en;q=0.3 +Accept-Encoding: gzip, deflate +Connection: keep-alive +Referer: http://127.0.0.1/test/ +Cookie: acl_session=1336957885.98220.1804289383; name1=value1; doxygen_width=300 +Cache-Control: max-age=0 +Content-Length: 62 +Content-Type: application/x-www-form-urlencoded + +name2=%26%2320013%3B%26%2322269%3B%26%2320154%3B&submit=submit diff --git a/lib_acl_cpp/samples/http_servlet/valgrind.sh b/lib_acl_cpp/samples/http_servlet/valgrind.sh new file mode 100644 index 000000000..7dfcd52e3 --- /dev/null +++ b/lib_acl_cpp/samples/http_servlet/valgrind.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +#valgrind --tool=memcheck --leak-check=yes --track-origins=yes -v ./http_servlet alone +valgrind --tool=memcheck --leak-check=yes -v ./http_servlet alone diff --git a/lib_acl_cpp/samples/http_test/Makefile b/lib_acl_cpp/samples/http_test/Makefile new file mode 100644 index 000000000..e49a2829c --- /dev/null +++ b/lib_acl_cpp/samples/http_test/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = http_test diff --git a/lib_acl_cpp/samples/http_test/main.cpp b/lib_acl_cpp/samples/http_test/main.cpp new file mode 100644 index 000000000..bc4cac018 --- /dev/null +++ b/lib_acl_cpp/samples/http_test/main.cpp @@ -0,0 +1,33 @@ +#include +#include "acl_cpp/lib_acl.hpp" + +using namespace acl; + +int main(void) +{ + const char* data = "U_TRS1=000000f6.66721803.4fd1681c.8c48b73a; path=/; expires=Mon, 06-Jun-22 02:49:00 GMT; domain=.sina.com.cn"; + HttpCookie* cookie = new HttpCookie(); + + printf("Set-Cookie: %s\r\n", data); + + if (cookie->setCookie(data) == false) + { + printf("parse cookie(%s) error\r\n", data); + cookie->destroy(); + return -1; + } + + printf("cookie name: %s\r\n", cookie->getName()); + printf("cookie value: %s\r\n", cookie->getValue()); + printf("domain: %s\r\n", cookie->getDomain()); + printf("path: %s\r\n", cookie->getPath()); + printf("max-age: %d\r\n", cookie->getMaxAge()); + + const std::list& params = cookie->getParams(); + std::list::const_iterator cit = params.begin(); + for (; cit != params.end(); ++cit) + printf(">>%s=%s\r\n", (*cit)->name, (*cit)->value); + + cookie->destroy(); + return 0; +} diff --git a/lib_acl_cpp/samples/http_test/valgrind.sh b/lib_acl_cpp/samples/http_test/valgrind.sh new file mode 100644 index 000000000..6a74ce812 --- /dev/null +++ b/lib_acl_cpp/samples/http_test/valgrind.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +valgrind --tool=memcheck --leak-check=yes -v ./http_test diff --git a/lib_acl_cpp/samples/json/Makefile b/lib_acl_cpp/samples/json/Makefile new file mode 100644 index 000000000..52aff8258 --- /dev/null +++ b/lib_acl_cpp/samples/json/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = json diff --git a/lib_acl_cpp/samples/json/json.cpp b/lib_acl_cpp/samples/json/json.cpp new file mode 100644 index 000000000..f27075104 --- /dev/null +++ b/lib_acl_cpp/samples/json/json.cpp @@ -0,0 +1,224 @@ +// json.cpp : 定义控制台应用程序的入口点。 +// + +#include "stdafx.h" +#include +#include +#include "acl_cpp/stdlib/string.hpp" +#include "acl_cpp/stdlib/json.hpp" + +using namespace std; + +static void test(void) +{ + static const char* data = \ + "{ 'menu name': {\r\n" + " 'id:file': 'file',\r\n" + " 'value': 'File',\r\n" + " 'popup': {\r\n" + " 'menuitem1': [\r\n" + " {'value': 'New1', 'onclick': 'CreateNewDoc()'},\r\n" + " {'value': 'Open1', 'onclick': 'OpenDoc()'},\r\n" + " {'value': 'Close1', 'onclick': 'CloseDoc()'}\r\n" + " ],\r\n" + " 'menuname': 'hello world',\r\n" + " 'inner': { 'value' : 'new ', 'value' : 'open' },\r\n" + " 'menuitem2': [\r\n" + " {'value': 'New2', 'onclick': 'CreateNewDoc()'},\r\n" + " {'value': 'Open2', 'onclick': 'OpenDoc()'},\r\n" + " {'value': 'Close2', 'onclick': 'CloseDoc()'},\r\n" + " {{'value': 'Help2', 'onclick': 'Help()'}}" + " ]\r\n" + " }\r\n" + " }\r\n," + " 'help': 'hello world!',\r\n" + " 'menuitem2': [\r\n" + " {'value': 'New3', 'onclick': 'CreateNewDoc()'},\r\n" + " {'value': 'Open3', 'onclick': 'OpenDoc()'},\r\n" + " {'value': 'Close3', 'onclick': 'CloseDoc()'},\r\n" + " [{'value': 'Save3', 'onclick': 'SaveDoc()'}]" + " ]\r\n" + "}\r\n"; + acl::json json; + + json.update(data); + const vector& elements = json.getElementsByTagName("value"); + + if (!elements.empty()) + { + vector::const_iterator cit = elements.begin(); + for (; cit != elements.end(); ++cit) + { + acl::json_node *node = *cit; + printf("tagname: %s, text: %s\n", node->tag_name() ? node->tag_name() : "", + node->get_text() ? node->get_text() : ""); + } + } + + //const vector& menuitem1 = json.getElementsByTagName("menuitem1"); + const vector& menuitem1 = json.getElementsByTags("menu name/popup/menuitem1"); + if (!menuitem1.empty()) + { + vector::const_iterator cit = menuitem1.begin(); + for (; cit != menuitem1.end(); ++cit) + { + acl::json_node* node = (*cit)->first_child(); + printf("tag: %s\r\n", (*cit)->tag_name()); + while (node) + { + acl::json_node* nv = node->first_child(); + while (nv) + { + printf("tag: %s, value: %s; ", nv->tag_name(), + nv->get_text()); + nv = node->next_child(); + } + printf("\r\n"); + node = (*cit)->next_child(); + } + } + } + + json.reset(); + + ////////////////////////////////////////////////////////////////////////// + + acl::json_node& root = json.get_root(); + acl::json_node *node0, *node1, *node2, *node3; + + node0 = &json.create_node(); + root.add_child(node0); + + node1 = &json.create_node("name1", "value1"); + node0->add_child(node1); + + node1 = &json.create_node("name2", "value2"); + node0->add_child(node1); + + node1 = &json.create_node(); + node2 = &json.create_node("name3", "value3"); + node1->add_child(node2); + node2 = &json.create_node("name4", node1); + node0->add_child(node2); + + //////////////////////////////////////////////////////////////////////////// + + node1 = &json.create_node(true); + node2 = &json.create_node("name5", node1); + node0->add_child(node2); + + node3 = &json.create_node("name6", "value6"); + node1->add_child(node3); + + node3 = &json.create_node("name7", "value7"); + node1->add_child(node3); + + node3 = &json.create_node(); + node1->add_child(node3); + + node1 = &json.create_node("name8", "value8"); + node2 = &json.create_node("name9", "value9"); + (*node3).add_child(node1).add_child(node2); + + ////////////////////////////////////////////////////////////////////////// + + acl::json_node& node_a = + json.create_node("name12", + json.create_node() + .add_child(json.create_node("name12_1_1", "value12_1_1")) + .add_child(json.create_node("name12_1_2", "value12_1_2")) + .add_child(json.create_node("name12_1_3", "value12_1_3")) + .add_child(json.create_node("name12_1_4", "value12_1_4"))); + acl::json_node& node_b = + json.create_node() + .add_child(json.create_node("name13_1", "value13_1")) + .add_child(json.create_node("name13_2", "value13_2")) + .add_child(json.create_node("name13_3", "value13_3")); + acl::json_node& node_c = + json.create_node() + .add_child(json.create_node("name14_1", "value14_1")); + acl::json_node& node_d = + json.create_node() + .add_child(json.create_node("name15_1", "value15_1")); + acl::json_node& node_e = + json.create_node() + .add_child(json.create_node("name15_2", "value15_2")); + + node0->add_child(node_a) + .add_child(node_b) + .add_child(node_c) + .add_child(node_d) + .add_child(node_e) + .add_child(json.create_node("name16", "value16")) + .add_child(json.create_node("name17", "value17")) + .add_child(json.create_node("name18", "value18")); + + ////////////////////////////////////////////////////////////////////////// + node0->add_child("name19", "value19") + .add_child("name20", "value20") + .add_child("name21", "value21"); + (*node0).add_child("name23", + json.create_node() + .add_child("name24", "value24") + .add_child("name24_1", "value24_1")) + .add_child(true, true).add_child("name25", "value25") + .add_child("name26", "value26") + .add_child("name27", "value27") + .get_parent() + .add_child("name28", "value28") + .add_child("name29", "value29") + .add_child("name30", "value30"); + ////////////////////////////////////////////////////////////////////////// + + // 遍历所有有标签名的结点 + + printf("----------------------------------------------------------\r\n"); + acl::json_node* iter = json.first_node(); + while (iter) + { + if (iter->tag_name()) + { + printf("tag: %s", iter->tag_name()); + if (iter->get_text()) + printf(", value: %s\r\n", iter->get_text()); + else + printf("\r\n"); + } + iter = json.next_node(); + } + + printf("------------------root first level child---------\r\n"); + iter = node0->first_child(); + while (iter) + { + if (iter->tag_name()) + printf("tag: %s", iter->tag_name()); + if (iter->get_text()) + printf(", text: %s\r\n", iter->get_text()); + else + printf("\r\n"); + iter = node0->next_child(); + } + + ////////////////////////////////////////////////////////////////////////// + + printf("-------------------------------------------------\r\n"); + + acl::string buf; + json.build_json(buf); + + printf("-----------------json------------------------\r\n"); + printf("%s\r\n", buf.c_str()); +} + +int main(int argc, char* argv[]) +{ + (void) argc; + (void) argv; + + test(); + printf("enter any key to exit\r\n"); + getchar(); + return 0; +} + diff --git a/lib_acl_cpp/samples/json/json.vcproj b/lib_acl_cpp/samples/json/json.vcproj new file mode 100644 index 000000000..9facf6cd3 --- /dev/null +++ b/lib_acl_cpp/samples/json/json.vcproj @@ -0,0 +1,271 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_acl_cpp/samples/json/stdafx.cpp b/lib_acl_cpp/samples/json/stdafx.cpp new file mode 100644 index 000000000..4f379fc9f --- /dev/null +++ b/lib_acl_cpp/samples/json/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// json.pch 将成为预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + +// TODO: 在 STDAFX.H 中 +//引用任何所需的附加头文件,而不是在此文件中引用 diff --git a/lib_acl_cpp/samples/json/stdafx.h b/lib_acl_cpp/samples/json/stdafx.h new file mode 100644 index 000000000..9024458d0 --- /dev/null +++ b/lib_acl_cpp/samples/json/stdafx.h @@ -0,0 +1,11 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是常用但不常更改的项目特定的包含文件 +// + +#pragma once + + +//#include +//#include + +// TODO: 在此处引用程序要求的附加头文件 diff --git a/lib_acl_cpp/samples/json/valgrind.sh b/lib_acl_cpp/samples/json/valgrind.sh new file mode 100644 index 000000000..af5f0c6e2 --- /dev/null +++ b/lib_acl_cpp/samples/json/valgrind.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +valgrind --tool=memcheck --leak-check=yes -v ./json diff --git a/lib_acl_cpp/samples/logger/Makefile b/lib_acl_cpp/samples/logger/Makefile new file mode 100644 index 000000000..ca4ac7240 --- /dev/null +++ b/lib_acl_cpp/samples/logger/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = logger diff --git a/lib_acl_cpp/samples/logger/main.cpp b/lib_acl_cpp/samples/logger/main.cpp new file mode 100644 index 000000000..732ec665d --- /dev/null +++ b/lib_acl_cpp/samples/logger/main.cpp @@ -0,0 +1,11 @@ +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/acl_cpp_test.hpp" + +int main(void) +{ + logger_open("test.log", "logger", "all:1"); + + logger("logger opened!"); + acl::log::logger_test1(); + return (0); +} diff --git a/lib_acl_cpp/samples/master_aio/Makefile b/lib_acl_cpp/samples/master_aio/Makefile new file mode 100644 index 000000000..84a000845 --- /dev/null +++ b/lib_acl_cpp/samples/master_aio/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = master_aio diff --git a/lib_acl_cpp/samples/master_aio/ReadMe.txt b/lib_acl_cpp/samples/master_aio/ReadMe.txt new file mode 100644 index 000000000..3bf8d370f --- /dev/null +++ b/lib_acl_cpp/samples/master_aio/ReadMe.txt @@ -0,0 +1,31 @@ +======================================================================== + 控制台应用程序 : master_aio 项目概况 +======================================================================== + +应用程序向导已为您创建了这个 master_aio 应用程序。 +此文件包含组成 master_aio 应用程序 +的每个文件的内容摘要。 + + +master_aio.vcproj + 这是用应用程序向导生成的 VC++ 项目的主项目文件。 + 它包含有关生成此文件的 Visual C++ 版本的信息,以及 + 有关用应用程序向导选择的 + 平台、配置和项目功能的信息。 + +master_aio.cpp + 这是主应用程序源文件。 + +///////////////////////////////////////////////////////////////////////////// +其他标准文件: + +StdAfx.h、StdAfx.cpp + 这些文件用于生成名为 master_aio.pch + 的预编译头(PCH)文件以及名为 StdAfx.obj 的预编译类型文件。 + +///////////////////////////////////////////////////////////////////////////// +其他注释: + +应用程序向导使用 "TODO:" 注释指示应添加或自定义的源代码部分。 + +///////////////////////////////////////////////////////////////////////////// diff --git a/lib_acl_cpp/samples/master_aio/aio_echo.cf b/lib_acl_cpp/samples/master_aio/aio_echo.cf new file mode 100644 index 000000000..0abd2d194 --- /dev/null +++ b/lib_acl_cpp/samples/master_aio/aio_echo.cf @@ -0,0 +1,94 @@ + +service server { +# 进程是否禁止运行 + master_disable = yes +# 服务地址及端口号 + master_service = 5200 + +# 服务监听为域套接口 +# master_service = aio_echo.sock +# 服务类型 + master_type = inet + +# 当子进程异常退出时,如果该值非空,则将子进程异常退出的消息通知该服务 +# master_notify_addr = 127.0.0.1:5801 +# 邮件通知接收者 +# master_notify_recipients = zhengshuxin@hotmail.com + +# 是否允许延迟接受客户端连接,如果为0则表示关闭该功能,如果大于0则表示打开此功能 +# 并且此值代表延迟接受连接的超时值,超过此值时如果客户端依然没有发来数据,则操作 +# 系统会在系统层直接关闭该连接 +# master_defer_accept = 0 +# master_type = unix +# 是否只允许私有访问, 如果为 y, 则域套接口创建在 {install_path}/var/log/private/ 目录下, +# 如果为 n, 则域套接口创建在 {install_path}/var/log/public/ 目录下, + master_private = n + master_unpriv = n +# 是否需要 chroot: n -- no, y -- yes + master_chroot = n +# 每隔多长时间触发一次,单位为秒(仅对 trigger 模式有效) + master_wakeup = - +# 最大进程数 + master_maxproc = 5 +# 进程程序名 + master_command = master_aio +# 进程启动参数,只能为: -u [是否允许以某普通用户的身份运行] + master_args = +# 传递给服务子进程的环境变量, 可以通过 getenv("SERVICE_ENV") 获得此值 + master_env = mempool_limit:512000000, mempool_use_mutex:true +# master_env = logme:FALSE, priority:E_LOG_INFO, action:E_LOG_PER_DAY, flush:sync_flush, imit_size:512,\ +# sync_action:E_LOG_SEM, sem_name:/tmp/aio_echo.sem +# 进程日志记录文件 + master_log = {install_path}/var/log/aio_echo.log + +# 是否允许产生 core 文件 +# aio_enable_core = 1 +# 每个进程实例处理连接数的最大次数,超过此值后进程实例主动退出 + aio_use_limit = 0 +# 每个进程实例的空闲超时时间,超过此值后进程实例主动退出 + aio_idle_limit = 0 +# 记录进程PID的位置(对于多进程实例来说没有意义) + aio_pid_dir = {install_path}/var/pid +# 进程运行时所在的路径 + aio_queue_dir = {install_path}/var +# 读写超时时间, 单位为秒 + aio_rw_timeout = 120 +# 读缓冲区的缓冲区大小 + aio_buf_size = 8192 +# 每次 accept 时的循环接收的最大次数 + aio_max_accept = 25 +# 每个进程当一次接收的连接数达到此值时需要通知 acl_master 一下 + aio_min_notify = 1 +# 进程运行时的用户身份 + aio_owner = root + +# 用 select 进行循环时的时间间隔 +# 单位为秒 + aio_delay_sec = 1 +# 单位为微秒 + aio_delay_usec = 500 +# 采用事件循环的方式: select(default), poll, kernel(epoll/devpoll/kqueue) + aio_event_mode = select +# 是否将 socket 接收与IO功能分开: yes/no, 如果为 yes 可以大大提高 accept() 速度 + aio_accept_alone = yes +# 线程池的最大线程数, 如果该值为0则表示采用单线程非阻塞模式. + aio_max_threads = 0 +# 每个线程的空闲时间. + aio_thread_idle_limit = 60 + +# 允许访问的客户端IP地址范围 + aio_access_allow = 127.0.0.1:255.255.255.255, 127.0.0.1:127.0.0.1 + +# 当 acl_master 退出时,如果该值置1则该程序不等所有连接处理完毕便立即退出 + aio_quick_abort = 1 +############################################################################ +# 应用自己的配置选项 + +# 每个客户端连接的空闲时间. + client_idle_limit = 60 +# 是否输出当前的内存状态信息 + debug_mem = 1 +# 是否发送欢迎信息 + send_banner = 0 +} + diff --git a/lib_acl_cpp/samples/master_aio/master_aio.cpp b/lib_acl_cpp/samples/master_aio/master_aio.cpp new file mode 100644 index 000000000..236a4b110 --- /dev/null +++ b/lib_acl_cpp/samples/master_aio/master_aio.cpp @@ -0,0 +1,350 @@ +// master_aio.cpp : 定义控制台应用程序的入口点。 +// + +#include "stdafx.h" +#include "acl_cpp/lib_acl.hpp" + +static char *var_cfg_debug_msg; + +static acl::master_str_tbl var_conf_str_tab[] = { + { "debug_msg", "test_msg", &var_cfg_debug_msg }, + + { 0, 0, 0 } +}; + +static int var_cfg_debug_enable; +static int var_cfg_keep_alive; +static int var_cfg_send_banner; + +static acl::master_bool_tbl var_conf_bool_tab[] = { + { "debug_enable", 1, &var_cfg_debug_enable }, + { "keep_alive", 1, &var_cfg_keep_alive }, + { "send_banner", 1, &var_cfg_send_banner }, + + { 0, 0, 0 } +}; + +static int var_cfg_io_timeout; + +static acl::master_int_tbl var_conf_int_tab[] = { + { "io_timeout", 120, &var_cfg_io_timeout, 0, 0 }, + + { 0, 0 , 0 , 0, 0 } +}; + +static void (*format)(const char*, ...) = acl::log::msg1; + +using namespace acl; + +////////////////////////////////////////////////////////////////////////// +/** + * 延迟读回调处理类 + */ +class timer_reader: public aio_timer_reader +{ +public: + timer_reader(int delay) + { + delay_ = delay; + format("timer_reader init, delay: %d\r\n", delay); + } + + ~timer_reader() + { + } + + // aio_timer_reader 的子类必须重载 destroy 方法 + void destroy() + { + format("timer_reader delete, delay: %d\r\n", delay_); + delete this; + } + + // 重载基类回调方法 + virtual void timer_callback(unsigned int id) + { + format("timer_reader(%u): timer_callback, delay: %d\r\n", id, delay_); + + // 调用基类的处理过程 + aio_timer_reader::timer_callback(id); + } + +private: + int delay_; +}; + +/** + * 延迟写回调处理类 + */ +class timer_writer: public aio_timer_writer +{ +public: + timer_writer(int delay) + { + delay_ = delay; + format("timer_writer init, delay: %d\r\n", delay); + } + + ~timer_writer() + { + } + + // aio_timer_reader 的子类必须重载 destroy 方法 + void destroy() + { + format("timer_writer delete, delay: %d\r\n", delay_); + delete this; + } + + // 重载基类回调方法 + virtual void timer_callback(unsigned int id) + { + format("timer_writer(%u): timer_callback, delay: %u\r\n", id, delay_); + + // 调用基类的处理过程 + aio_timer_writer::timer_callback(id); + } + +private: + int delay_; +}; + +class timer_test : public aio_timer_callback +{ +public: + timer_test() : aio_timer_callback(true) {} + ~timer_test() {} +protected: + // 基类纯虚函数 + virtual void timer_callback(unsigned int id) + { + format("id: %u\r\n", id); + } + + virtual void destroy(void) + { + delete this; + format("timer delete now\r\n"); + } +private: +}; +/** + * 异步客户端流的回调类的子类 + */ +class io_callback : public aio_callback +{ +public: + io_callback(aio_socket_stream* client) + : client_(client) + , i_(0) + { + } + + ~io_callback() + { + format("delete io_callback now ...\r\n"); + } + + /** + * 实现父类中的虚函数,客户端流的读成功回调过程 + * @param data {char*} 读到的数据地址 + * @param len {int} 读到的数据长度 + * @return {bool} 返回 true 表示继续,否则希望关闭该异步流 + */ + virtual bool read_callback(char* data, int len) + { + if (++i_ < 10) + format(">>gets(i: %d): %s\r\n", i_, data); + + // 如果远程客户端希望退出,则关闭之 + if (strncmp(data, "quit", 4) == 0) + { + client_->format("Bye!\r\n"); + client_->close(); + } + + // 如果远程客户端希望服务端也关闭,则中止异步事件过程 + else if (strncmp(data, "stop", 4) == 0) + { + client_->format("Stop now!\r\n"); + client_->close(); // 关闭远程异步流 + + // 通知异步引擎关闭循环过程 + client_->get_handle().stop(); + } + + // 向远程客户端回写收到的数据 + + int delay = 0; + + if (strncmp(data, "write_delay", strlen("write_delay")) == 0) + { + // 延迟写过程 + + const char* ptr = data + strlen("write_delay"); + delay = atoi(ptr); + if (delay > 0) + { + format(">> write delay %d second ...\r\n", delay); + timer_writer* timer = new timer_writer(delay); + client_->write(data, len, delay * 1000000, timer); + client_->gets(10, false); + return (true); + } + } + else if (strncmp(data, "read_delay", strlen("read_delay")) == 0) + { + // 延迟读过程 + + const char* ptr = data + strlen("read_delay"); + delay = atoi(ptr); + if (delay > 0) + { + client_->write(data, len); + format(">> read delay %d second ...\r\n", delay); + timer_reader* timer = new timer_reader(delay); + client_->gets(10, false, delay * 1000000, timer); + return (true); + } + } + + client_->write(data, len); + //client_->gets(10, false); + return (true); + } + + /** + * 实现父类中的虚函数,客户端流的写成功回调过程 + * @return {bool} 返回 true 表示继续,否则希望关闭该异步流 + */ + virtual bool write_callback() + { + return (true); + } + + /** + * 实现父类中的虚函数,客户端流的超时回调过程 + */ + virtual void close_callback() + { + // 必须在此处删除该动态分配的回调类对象以防止内存泄露 + delete this; + } + + /** + * 实现父类中的虚函数,客户端流的超时回调过程 + * @return {bool} 返回 true 表示继续,否则希望关闭该异步流 + */ + virtual bool timeout_callback() + { + format("Timeout ...\r\n"); + return (true); + } + +private: + aio_socket_stream* client_; + int i_; +}; + +////////////////////////////////////////////////////////////////////////// + +class master_aio_test : public master_aio +{ +public: + master_aio_test() { timer_test_ = new timer_test(); } + + ~master_aio_test() { } + +protected: + // 基类纯虚函数:当接收到一个新的连接时调用此函数 + virtual bool on_accept(aio_socket_stream* client) + { + // 创建异步客户端流的回调对象并与该异步流进行绑定 + io_callback* callback = new io_callback(client); + + // 注册异步流的读回调过程 + client->add_read_callback(callback); + + // 注册异步流的写回调过程 + client->add_write_callback(callback); + + // 注册异步流的关闭回调过程 + client->add_close_callback(callback); + + // 注册异步流的超时回调过程 + client->add_timeout_callback(callback); + + // 写欢迎信息 + if (var_cfg_send_banner) + client->format("hello, you're welcome\r\n"); + + // 从异步流读一行数据 + client->gets(10, false); + //client->read(); + return true; + } + + // 基类虚函数:服务进程切换用户身份前调用此函数 + virtual void proc_pre_jail() + { + format("proc_pre_jail\r\n"); + // 只有当程序启动后才能获得异步引擎句柄 + handle_ = get_handle(); + //handle_->keep_timer(true); // 允许定时器被重复触发 + // 设置第一个定时任务,每隔1秒触发一次,定时任务ID为0 + handle_->set_timer(timer_test_, 1000000, 0); + } + + // 基类虚函数:服务进程切换用户身份后调用此函数 + virtual void proc_on_init() + { + format("proc init\r\n"); + // 设置第二个定时任务,每隔2秒触发一次,定时任务ID为1 + handle_->set_timer(timer_test_, 2000000, 1); + } + + // 基类虚函数:服务进程退出前调用此函数 + virtual void proc_on_exit() + { + format("proc exit\r\n"); + } +private: + timer_test* timer_test_; + aio_handle* handle_; +}; +////////////////////////////////////////////////////////////////////////// + +int main(int argc, char* argv[]) +{ +#if 0 + int base = 8, nslice = 1024, nalloc_gc = 1000000; + unsigned int slice_flag = ACL_SLICE_FLAG_GC2 | ACL_SLICE_FLAG_RTGC_OFF; + + acl_mem_slice_init(base, nslice, nalloc_gc, slice_flag); +#endif + + master_aio_test ma; + + // 设置配置参数表 + ma.set_cfg_int(var_conf_int_tab); + ma.set_cfg_int64(NULL); + ma.set_cfg_str(var_conf_str_tab); + ma.set_cfg_bool(var_conf_bool_tab); + + // 开始运行 + + if (argc >= 2 && strcmp(argv[1], "alone") == 0) + { + const char* addr = "127.0.0.1:8888"; + + if (argc >= 3) + addr = argv[2]; + + format = (void (*)(const char*, ...)) printf; + format("listen: %s now\r\n", addr); + ma.run_alone(addr); // 单独运行方式 + } + else + ma.run_daemon(argc, argv); // acl_master 控制模式运行 + return 0; +} diff --git a/lib_acl_cpp/samples/master_aio/master_aio.vcproj b/lib_acl_cpp/samples/master_aio/master_aio.vcproj new file mode 100644 index 000000000..9d35a8c26 --- /dev/null +++ b/lib_acl_cpp/samples/master_aio/master_aio.vcproj @@ -0,0 +1,269 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_acl_cpp/samples/master_aio/stdafx.cpp b/lib_acl_cpp/samples/master_aio/stdafx.cpp new file mode 100644 index 000000000..3d16d64d7 --- /dev/null +++ b/lib_acl_cpp/samples/master_aio/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// master_aio.pch 将成为预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + +// TODO: 在 STDAFX.H 中 +//引用任何所需的附加头文件,而不是在此文件中引用 diff --git a/lib_acl_cpp/samples/master_aio/stdafx.h b/lib_acl_cpp/samples/master_aio/stdafx.h new file mode 100644 index 000000000..b98553f2c --- /dev/null +++ b/lib_acl_cpp/samples/master_aio/stdafx.h @@ -0,0 +1,11 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是常用但不常更改的项目特定的包含文件 +// + +#pragma once + + +#include +//#include + +// TODO: 在此处引用程序要求的附加头文件 diff --git a/lib_acl_cpp/samples/master_aio/valgrind.sh b/lib_acl_cpp/samples/master_aio/valgrind.sh new file mode 100644 index 000000000..f13094cac --- /dev/null +++ b/lib_acl_cpp/samples/master_aio/valgrind.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +valgrind --tool=memcheck --leak-check=yes -v ./master_aio alone diff --git a/lib_acl_cpp/samples/master_http_aio/Makefile b/lib_acl_cpp/samples/master_http_aio/Makefile new file mode 100644 index 000000000..e011fe444 --- /dev/null +++ b/lib_acl_cpp/samples/master_http_aio/Makefile @@ -0,0 +1,3 @@ +include ../Makefile.in +EXTLIBS = -lz +PROG = master_http_aio diff --git a/lib_acl_cpp/samples/master_http_aio/http_client.cpp b/lib_acl_cpp/samples/master_http_aio/http_client.cpp new file mode 100644 index 000000000..c9f9211f5 --- /dev/null +++ b/lib_acl_cpp/samples/master_http_aio/http_client.cpp @@ -0,0 +1,57 @@ +#include "stdafx.h" +#include "http_client.h" + +http_client::http_client(acl::aio_socket_stream* conn, int buf_size) +: conn_(conn) +, res_body_(buf_size) +{ + stream_ = conn->get_astream(); + for (int i = 0; i < buf_size; i++) + res_body_ << 'X'; + res_hdr_.format("HTTP/1.1 200 OK\r\n" + "Content-Length: %d\r\n" + "Connection: keep-alive\r\n\r\n", + buf_size); +} + +http_client::~http_client() +{ +} + +bool http_client::write_callback() +{ + return true; +} + +bool http_client::timeout_callback() +{ + return false; +} + +void http_client::close_callback() +{ + logger("connection closed now, fd: %d", conn_->get_socket()); + delete this; +} + +bool http_client::read_wakeup() +{ + while (true) + { + ACL_VSTRING* buf = acl_aio_gets_nonl_peek(stream_); + if (buf == NULL) + return true; + if (ACL_VSTRING_LEN(buf) > 0) + { + ACL_VSTRING_RESET(buf); + } + else + { + break; + } + } + + conn_->write(res_hdr_.c_str(), (int) res_hdr_.length()); + conn_->write(res_body_.c_str(), (int) res_body_.length()); + return true; +} diff --git a/lib_acl_cpp/samples/master_http_aio/http_client.h b/lib_acl_cpp/samples/master_http_aio/http_client.h new file mode 100644 index 000000000..821616e8a --- /dev/null +++ b/lib_acl_cpp/samples/master_http_aio/http_client.h @@ -0,0 +1,21 @@ +#pragma once + +class http_rpc; + +class http_client : public acl::aio_callback +{ +public: + http_client(acl::aio_socket_stream* conn, int buf_size); + ~http_client(); + +private: + virtual bool read_wakeup(); + virtual bool write_callback(); + virtual bool timeout_callback(); + virtual void close_callback(); +private: + acl::aio_socket_stream* conn_; + ACL_ASTREAM* stream_; + acl::string res_hdr_; + acl::string res_body_; +}; diff --git a/lib_acl_cpp/samples/master_http_aio/main.cpp b/lib_acl_cpp/samples/master_http_aio/main.cpp new file mode 100644 index 000000000..1a625cd07 --- /dev/null +++ b/lib_acl_cpp/samples/master_http_aio/main.cpp @@ -0,0 +1,30 @@ +#include "stdafx.h" +#include "master_service.h" + +int main(int argc, char* argv[]) +{ + // 初始化 acl 库 + acl::acl_cpp_init(); + acl::log::stdout_open(true); + + master_service& ms = acl::singleton2::get_instance(); + + // 设置配置参数表 + ms.set_cfg_int(var_conf_int_tab); + ms.set_cfg_bool(var_conf_bool_tab); + + // 开始运行 + + if (argc >= 2 && strcmp(argv[1], "alone") == 0) + { + const char* addr = "127.0.0.1:8888"; + if (argc >= 3) + addr = argv[2]; + printf("listen on: %s\r\n", addr); + ms.run_alone(addr, NULL, acl::ENGINE_SELECT); // 单独运行方式 + } + else + ms.run_daemon(argc, argv); // acl_master 控制模式运行 + + return 0; +} diff --git a/lib_acl_cpp/samples/master_http_aio/master_http_aio.cf b/lib_acl_cpp/samples/master_http_aio/master_http_aio.cf new file mode 100644 index 000000000..83fe55727 --- /dev/null +++ b/lib_acl_cpp/samples/master_http_aio/master_http_aio.cf @@ -0,0 +1,92 @@ + +service master_http_aio { +# 进程是否禁止运行 + master_disable = no +# 服务地址及端口号 + master_service = 5200 + +# 服务监听为域套接口 +# master_service = aio_echo.sock +# 服务类型 + master_type = inet + +# 当子进程异常退出时,如果该值非空,则将子进程异常退出的消息通知该服务 +# master_notify_addr = 127.0.0.1:5801 +# 邮件通知接收者 +# master_notify_recipients = zhengshuxin@hotmail.com + +# 是否允许延迟接受客户端连接,如果为0则表示关闭该功能,如果大于0则表示打开此功能 +# 并且此值代表延迟接受连接的超时值,超过此值时如果客户端依然没有发来数据,则操作 +# 系统会在系统层直接关闭该连接 +# master_defer_accept = 0 +# master_type = unix +# 是否只允许私有访问, 如果为 y, 则域套接口创建在 {install_path}/var/log/private/ 目录下, +# 如果为 n, 则域套接口创建在 {install_path}/var/log/public/ 目录下, + master_private = n + master_unpriv = n +# 是否需要 chroot: n -- no, y -- yes + master_chroot = n +# 每隔多长时间触发一次,单位为秒(仅对 trigger 模式有效) + master_wakeup = - +# 最大进程数 + master_maxproc = 5 +# 进程程序名 + master_command = master_http_aio +# 进程启动参数,只能为: -u [是否允许以某普通用户的身份运行] + master_args = +# 传递给服务子进程的环境变量, 可以通过 getenv("SERVICE_ENV") 获得此值 +# master_env = mempool_limit:512000000, mempool_use_mutex:true +# master_env = logme:FALSE, priority:E_LOG_INFO, action:E_LOG_PER_DAY, flush:sync_flush, imit_size:512,\ +# sync_action:E_LOG_SEM, sem_name:/tmp/aio_echo.sem +# 进程日志记录文件 + master_log = {install_path}/var/log/master_http_aio + +# 是否允许产生 core 文件 +# aio_enable_core = 1 +# 每个进程实例处理连接数的最大次数,超过此值后进程实例主动退出 + aio_use_limit = 0 +# 每个进程实例的空闲超时时间,超过此值后进程实例主动退出 + aio_idle_limit = 0 +# 记录进程PID的位置(对于多进程实例来说没有意义) + aio_pid_dir = {install_path}/var/pid +# 进程运行时所在的路径 + aio_queue_dir = {install_path}/var +# 读写超时时间, 单位为秒 + aio_rw_timeout = 120 +# 读缓冲区的缓冲区大小 + aio_buf_size = 8192 +# 每次 accept 时的循环接收的最大次数 + aio_max_accept = 25 +# 每个进程当一次接收的连接数达到此值时需要通知 acl_master 一下 + aio_min_notify = 1 +# 进程运行时的用户身份 + aio_owner = root + +# 用 select 进行循环时的时间间隔 +# 单位为秒 + aio_delay_sec = 1 +# 单位为微秒 + aio_delay_usec = 500 +# 采用事件循环的方式: select(default), poll, kernel(epoll/devpoll/kqueue) + aio_event_mode = kernel +# 是否将 socket 接收与IO功能分开: yes/no, 如果为 yes 可以大大提高 accept() 速度 + aio_accept_alone = yes +# 线程池的最大线程数, 如果该值为0则表示采用单线程非阻塞模式. + aio_max_threads = 0 +# 每个线程的空闲时间. + aio_thread_idle_limit = 60 + +# 允许访问的客户端IP地址范围 + aio_access_allow = 127.0.0.1:255.255.255.255, 127.0.0.1:127.0.0.1 + +# 当 acl_master 退出时,如果该值置1则该程序不等所有连接处理完毕便立即退出 + aio_quick_abort = 1 +############################################################################ +# 应用自己的配置选项 + +# 响应体的数据长度 + buf_size = 1024 +# 是否启用预读过程 + preread = 1 +} + diff --git a/lib_acl_cpp/samples/master_http_aio/master_service.cpp b/lib_acl_cpp/samples/master_http_aio/master_service.cpp new file mode 100644 index 000000000..aade8355e --- /dev/null +++ b/lib_acl_cpp/samples/master_http_aio/master_service.cpp @@ -0,0 +1,72 @@ +#include "stdafx.h" +#include "http_client.h" +#include "master_service.h" + +//////////////////////////////////////////////////////////////////////////////// +// 配置内容项 + +int var_cfg_preread; +acl::master_bool_tbl var_conf_bool_tab[] = { + { "preread", 1, &var_cfg_preread }, + + { 0, 0, 0 } +}; + +int var_cfg_buf_size; +acl::master_int_tbl var_conf_int_tab[] = { + { "buf_size", 1024, &var_cfg_buf_size, 0, 0 }, + + { 0, 0 , 0 , 0, 0 } +}; + +//////////////////////////////////////////////////////////////////////////////// + +master_service::master_service() +{ +} + +master_service::~master_service() +{ +} + +bool master_service::on_accept(acl::aio_socket_stream* client) +{ + //acl_tcp_nodelay(client->get_socket(), 1); + + // 如果允许在主线程中预读,则设置流的预读标志位 + if (var_cfg_preread) + { + ACL_VSTREAM* vstream = client->get_vstream(); + vstream->flag |= ACL_VSTREAM_FLAG_PREREAD; + } + + // 创建异步客户端流的回调对象并与该异步流进行绑定 + http_client* callback = new http_client(client, var_cfg_buf_size); + + // 注册异步流的读回调过程 + client->add_read_callback(callback); + + // 注册异步流的写回调过程 + client->add_write_callback(callback); + + // 注册异步流的关闭回调过程 + client->add_close_callback(callback); + + // 注册异步流的超时回调过程 + client->add_timeout_callback(callback); + + client->keep_read(true); + + // 监控异步流是否可读 + client->read_wait(0); + + return true; +} + +void master_service::proc_on_init() +{ +} + +void master_service::proc_on_exit() +{ +} diff --git a/lib_acl_cpp/samples/master_http_aio/master_service.h b/lib_acl_cpp/samples/master_http_aio/master_service.h new file mode 100644 index 000000000..ef315bfec --- /dev/null +++ b/lib_acl_cpp/samples/master_http_aio/master_service.h @@ -0,0 +1,40 @@ +#pragma once +#include "acl_cpp/master/master_aio.hpp" +#include "acl_cpp/master/master_conf.hpp" + +//////////////////////////////////////////////////////////////////////////////// +// 配置内容项 + +extern acl::master_bool_tbl var_conf_bool_tab[]; +extern acl::master_int_tbl var_conf_int_tab[]; + +//////////////////////////////////////////////////////////////////////////////// + +//class acl::aio_socket_stream; + +class master_service : public acl::master_aio +{ +public: + master_service(); + ~master_service(); + +protected: + /** + * 纯虚函数:当接收到一个客户端连接时调用此函数 + * @param stream {aio_socket_stream*} 新接收到的客户端异步流对象 + * @return {bool} 该函数如果返回 false 则通知服务器框架不再接收 + * 远程客户端连接,否则继续接收客户端连接 + */ + bool on_accept(acl::aio_socket_stream* stream); + + /** + * 当进程切换用户身份后调用的回调函数,此函数被调用时,进程 + * 的权限为普通受限级别 + */ + virtual void proc_on_init(); + + /** + * 当进程退出前调用的回调函数 + */ + virtual void proc_on_exit(); +}; diff --git a/lib_acl_cpp/samples/master_http_aio/stdafx.cpp b/lib_acl_cpp/samples/master_http_aio/stdafx.cpp new file mode 100644 index 000000000..3a8a20e11 --- /dev/null +++ b/lib_acl_cpp/samples/master_http_aio/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// master_threads.pch 将成为预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + +// TODO: 在 STDAFX.H 中 +//引用任何所需的附加头文件,而不是在此文件中引用 diff --git a/lib_acl_cpp/samples/master_http_aio/stdafx.h b/lib_acl_cpp/samples/master_http_aio/stdafx.h new file mode 100644 index 000000000..0acde2ab3 --- /dev/null +++ b/lib_acl_cpp/samples/master_http_aio/stdafx.h @@ -0,0 +1,14 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是常用但不常更改的项目特定的包含文件 +// + +#pragma once + + +//#include +//#include + +// TODO: 在此处引用程序要求的附加头文件 + +#include "lib_acl.h" +#include "acl_cpp/lib_acl.hpp" diff --git a/lib_acl_cpp/samples/master_http_rpc/Makefile b/lib_acl_cpp/samples/master_http_rpc/Makefile new file mode 100644 index 000000000..7e7fdeda9 --- /dev/null +++ b/lib_acl_cpp/samples/master_http_rpc/Makefile @@ -0,0 +1,3 @@ +include ../Makefile.in +EXTLIBS = -lz +PROG = master_http_rpc diff --git a/lib_acl_cpp/samples/master_http_rpc/gc_timer.cpp b/lib_acl_cpp/samples/master_http_rpc/gc_timer.cpp new file mode 100644 index 000000000..12d09dfe5 --- /dev/null +++ b/lib_acl_cpp/samples/master_http_rpc/gc_timer.cpp @@ -0,0 +1,35 @@ +#include "stdafx.h" +#include "gc_timer.h" + +gc_timer::gc_timer(acl::aio_handle& handle) +: acl::aio_timer_callback(true) +, handle_(handle) +{ +} + +gc_timer::~gc_timer() +{ +} + +void gc_timer::destroy() +{ + delete this; +} + +void gc_timer::start(int delay) +{ + // 璁剧疆瀹氭椂鍣紝灏嗙杞崲涓哄井濡 + handle_.set_timer(this, delay * 1000000); +} + +void gc_timer::stop() +{ + handle_.del_timer(this); +} + +void gc_timer::timer_callback(unsigned int) +{ + int n = acl_mem_slice_gc(); + if (n > 0) + logger("slice_gc: %d", n); +} diff --git a/lib_acl_cpp/samples/master_http_rpc/gc_timer.h b/lib_acl_cpp/samples/master_http_rpc/gc_timer.h new file mode 100644 index 000000000..c694a897b --- /dev/null +++ b/lib_acl_cpp/samples/master_http_rpc/gc_timer.h @@ -0,0 +1,18 @@ +#pragma once + +class gc_timer : public acl::aio_timer_callback +{ +public: + gc_timer(acl::aio_handle& handle); + + void start(int delay); + void stop(); +private: + ~gc_timer(); + + acl::aio_handle& handle_; + + // 鍩虹被绾櫄鍑芥暟 + virtual void timer_callback(unsigned int id); + virtual void destroy(void); +}; diff --git a/lib_acl_cpp/samples/master_http_rpc/global.h b/lib_acl_cpp/samples/master_http_rpc/global.h new file mode 100644 index 000000000..056f6472c --- /dev/null +++ b/lib_acl_cpp/samples/master_http_rpc/global.h @@ -0,0 +1,18 @@ +#pragma once + +//////////////////////////////////////////////////////////////////////////////// +// 閰嶇疆鍐呭椤 + +extern char *var_cfg_rpc_addr; +extern acl::master_str_tbl var_conf_str_tab[]; + +extern int var_cfg_preread; +extern acl::master_bool_tbl var_conf_bool_tab[]; + +extern int var_cfg_nthreads_limit; +extern int var_cfg_echo_length; +extern acl::master_int_tbl var_conf_int_tab[]; + +//////////////////////////////////////////////////////////////////////////////// + +extern bool var_mem_slice_on; diff --git a/lib_acl_cpp/samples/master_http_rpc/http_client.cpp b/lib_acl_cpp/samples/master_http_rpc/http_client.cpp new file mode 100644 index 000000000..766819f4e --- /dev/null +++ b/lib_acl_cpp/samples/master_http_rpc/http_client.cpp @@ -0,0 +1,47 @@ +#include "stdafx.h" +#include "rpc_manager.h" +#include "rpc_stats.h" +#include "http_rpc.h" +#include "http_client.h" + +http_client::http_client(acl::aio_socket_stream* conn) +: conn_(conn) +{ + http_ = new http_rpc(conn_, (unsigned) var_cfg_echo_length); +} + +http_client::~http_client() +{ + delete http_; +} + +bool http_client::write_callback() +{ + return true; +} + +bool http_client::timeout_callback() +{ + return false; +} + +void http_client::close_callback() +{ + //logger("connection closed now, fd: %d", conn_->get_socket()); + delete this; +} + +bool http_client::read_wakeup() +{ + // 娴嬭瘯鐘舵 + rpc_read_wait_del(); + rpc_add(); + + // 鍏堢姝㈠紓姝ユ祦鐩戞帶 + conn_->disable_read(); + + // 鍙戣捣涓涓 http 浼氳瘽杩囩▼ + rpc_manager::get_instance().fork(http_); + + return true; +} diff --git a/lib_acl_cpp/samples/master_http_rpc/http_client.h b/lib_acl_cpp/samples/master_http_rpc/http_client.h new file mode 100644 index 000000000..01648bf2f --- /dev/null +++ b/lib_acl_cpp/samples/master_http_rpc/http_client.h @@ -0,0 +1,19 @@ +#pragma once + +class http_rpc; + +class http_client : public acl::aio_callback +{ +public: + http_client(acl::aio_socket_stream* conn); + ~http_client(); + +private: + virtual bool read_wakeup(); + virtual bool write_callback(); + virtual bool timeout_callback(); + virtual void close_callback(); +private: + acl::aio_socket_stream* conn_; + http_rpc* http_; +}; diff --git a/lib_acl_cpp/samples/master_http_rpc/http_rpc.cpp b/lib_acl_cpp/samples/master_http_rpc/http_rpc.cpp new file mode 100644 index 000000000..cadd28682 --- /dev/null +++ b/lib_acl_cpp/samples/master_http_rpc/http_rpc.cpp @@ -0,0 +1,98 @@ +#include "stdafx.h" +#include "rpc_stats.h" +#include "http_rpc.h" + +http_rpc::http_rpc(acl::aio_socket_stream* client, unsigned buf_size) +: client_(client) +, buf_size_(buf_size) +{ + res_buf_ = (char*) acl_mymalloc(buf_size + 1); + unsigned i; + for (i = 0; i < buf_size; i++) + res_buf_[i] = 'x'; + res_buf_[i] = 0; +} + +http_rpc::~http_rpc() +{ + //logger("rpc_request destroyed!"); + acl_myfree(res_buf_); +} + +// 调用 service_.rpc_fork 后,由 RPC 框架在子线程中调用本函数 +// 来处理本地其它模块发来的请求信息 +void http_rpc::rpc_run() +{ + // 打开阻塞流对象 + acl::socket_stream stream; + + // 必须用 get_vstream() 获得的 ACL_VSTREAM 流对象做参数 + // 来打开 stream 对象,因为在 acl_cpp 和 acl 中的阻塞流 + // 和非阻塞流最终都是基于 ACL_VSTREAM,而 ACL_VSTREAM 流 + // 内部维护着了一个读/写缓冲区,所以在长连接的数据处理中, + // 必须每次将 ACL_VSTREAM 做为内部流的缓冲流来对待 + ACL_VSTREAM* vstream = client_->get_vstream(); + ACL_VSTREAM_SET_RWTIMO(vstream, 10); + (void) stream.open(vstream); + + rpc_req_add(); + + // 开始处理该 HTTP 请求 + handle_conn(&stream); + + rpc_req_del(); + + // 将 ACL_VSTREAM 与阻塞流对象解绑定,这样才能保证当释放阻塞流对象时 + // 不会关闭与请求者的连接,因为该连接本身是属于非阻塞流对象的,需要采 + // 用异步流关闭方式进行关闭 + stream.unbind(); +} + +void http_rpc::handle_conn(acl::socket_stream* stream) +{ + // HTTP 响应对象构造 + acl::http_response res(stream); + // 响应数据体为 xml 格式 + res.response_header().set_content_type("text/html"); + + // 读 HTTP 请求头 + if (res.read_header() == false) + { + keep_alive_ = false; + return; + } + + acl::string buf; + // 读 HTTP 请求体数据 + if (res.get_body(buf) == false) + { + keep_alive_ = false; + return; + } + + acl::http_client* client = res.get_client(); + + // 判断客户端是否希望保持长连接 + keep_alive_ = client->keep_alive(); + + // 返回数据给客户端 + + res.response(res_buf_, buf_size_, 200, keep_alive_); +} + +void http_rpc::rpc_onover() +{ + // 减少 rpc 计数 + rpc_del(); + + if (keep_alive_) + { + rpc_read_wait_add(); + + // 监控异步流是否可读 + client_->read_wait(10); + } + else + // 关闭异步流对象 + client_->close(); +} diff --git a/lib_acl_cpp/samples/master_http_rpc/http_rpc.h b/lib_acl_cpp/samples/master_http_rpc/http_rpc.h new file mode 100644 index 000000000..ba9be8f65 --- /dev/null +++ b/lib_acl_cpp/samples/master_http_rpc/http_rpc.h @@ -0,0 +1,24 @@ +#pragma once + +class http_rpc : public acl::rpc_request +{ +public: + http_rpc(acl::aio_socket_stream* client, unsigned buf_size); + ~http_rpc(); + +protected: + // 子线程处理函数 + virtual void rpc_run(); + + // 主线程处理过程,收到子线程任务完成的消息 + virtual void rpc_onover(); + +private: + acl::aio_socket_stream* client_; // 客户端连接流 + bool keep_alive_; // 是否与客户端保持长连接 + char* res_buf_; // 存放返回给客户端数据的缓冲区 + unsigned buf_size_; // res_buf_ 的空间大小 + + // 在子线程中以阻塞方式处理客户端请求 + void handle_conn(acl::socket_stream* stream); +}; diff --git a/lib_acl_cpp/samples/master_http_rpc/main.cpp b/lib_acl_cpp/samples/master_http_rpc/main.cpp new file mode 100644 index 000000000..2f286e047 --- /dev/null +++ b/lib_acl_cpp/samples/master_http_rpc/main.cpp @@ -0,0 +1,39 @@ +#include "stdafx.h" +#include "master_service.h" + +bool var_mem_slice_on = false; + +int main(int argc, char* argv[]) +{ + if (0) + { + var_mem_slice_on = true; + acl_mem_slice_init(8, 1024, 100000, + ACL_SLICE_FLAG_GC2 | + ACL_SLICE_FLAG_RTGC_OFF | + ACL_SLICE_FLAG_LP64_ALIGN); + } + + // 初始化 acl 库 + acl::acl_cpp_init(); + + master_service& ms = acl::singleton2::get_instance(); + + // 设置配置参数表 + ms.set_cfg_int(var_conf_int_tab); + ms.set_cfg_str(var_conf_str_tab); + ms.set_cfg_bool(var_conf_bool_tab); + + // 开始运行 + + if (argc >= 2 && strcmp(argv[1], "alone") == 0) + { + const char* addr = "127.0.0.1:8888"; + printf("listen on: %s\r\n", addr); + ms.run_alone(addr, NULL, acl::ENGINE_SELECT); // 单独运行方式 + } + else + ms.run_daemon(argc, argv); // acl_master 控制模式运行 + + return 0; +} diff --git a/lib_acl_cpp/samples/master_http_rpc/master_http_rpc.cf b/lib_acl_cpp/samples/master_http_rpc/master_http_rpc.cf new file mode 100644 index 000000000..cacdf6136 --- /dev/null +++ b/lib_acl_cpp/samples/master_http_rpc/master_http_rpc.cf @@ -0,0 +1,97 @@ + +service master_http_rpc { +# 进程是否禁止运行 + master_disable = no +# 服务地址及端口号 + master_service = 10080 + +# 服务监听为域套接口 +# master_service = aio_echo.sock +# 服务类型 + master_type = inet + +# 当子进程异常退出时,如果该值非空,则将子进程异常退出的消息通知该服务 +# master_notify_addr = 127.0.0.1:5801 +# 邮件通知接收者 +# master_notify_recipients = zhengshuxin@hotmail.com + +# 是否允许延迟接受客户端连接,如果为0则表示关闭该功能,如果大于0则表示打开此功能 +# 并且此值代表延迟接受连接的超时值,超过此值时如果客户端依然没有发来数据,则操作 +# 系统会在系统层直接关闭该连接 +# master_defer_accept = 0 +# master_type = unix +# 是否只允许私有访问, 如果为 y, 则域套接口创建在 {install_path}/var/log/private/ 目录下, +# 如果为 n, 则域套接口创建在 {install_path}/var/log/public/ 目录下, + master_private = n + master_unpriv = n +# 是否需要 chroot: n -- no, y -- yes + master_chroot = n +# 每隔多长时间触发一次,单位为秒(仅对 trigger 模式有效) + master_wakeup = - +# 最大进程数 + master_maxproc = 1 +# 预启动的子进程数量 + master_prefork = 1 +# 进程程序名 + master_command = master_http_rpc +# 进程启动参数,只能为: -u [是否允许以某普通用户的身份运行] + master_args = +# 传递给服务子进程的环境变量, 可以通过 getenv("SERVICE_ENV") 获得此值 +# master_env = mempool_limit:512000000, mempool_use_mutex:true +# master_env = logme:FALSE, priority:E_LOG_INFO, action:E_LOG_PER_DAY, flush:sync_flush, imit_size:512,\ +# sync_action:E_LOG_SEM, sem_name:/tmp/aio_echo.sem +# 进程日志记录文件 + master_log = {install_path}/var/log/master_http_rpc + +# 是否允许产生 core 文件 +# aio_enable_core = 1 +# 每个进程实例处理连接数的最大次数,超过此值后进程实例主动退出 + aio_use_limit = 0 +# 每个进程实例的空闲超时时间,超过此值后进程实例主动退出 + aio_idle_limit = 0 +# 记录进程PID的位置(对于多进程实例来说没有意义) + aio_pid_dir = {install_path}/var/pid +# 进程运行时所在的路径 + aio_queue_dir = {install_path}/var +# 读写超时时间, 单位为秒 + aio_rw_timeout = 120 +# 读缓冲区的缓冲区大小 + aio_buf_size = 8192 +# 每次 accept 时的循环接收的最大次数 + aio_max_accept = 25 +# 每个进程当一次接收的连接数达到此值时需要通知 acl_master 一下 + aio_min_notify = 1 +# 进程运行时的用户身份 + aio_owner = root + +# 用 select 进行循环时的时间间隔 +# 单位为秒 + aio_delay_sec = 1 +# 单位为微秒 + aio_delay_usec = 500 +# 采用事件循环的方式: select(default), poll, kernel(epoll/devpoll/kqueue) + aio_event_mode = kernel +# 是否将 socket 接收与IO功能分开: yes/no, 如果为 yes 可以大大提高 accept() 速度 + aio_accept_alone = yes +# 线程池的最大线程数, 如果该值为0则表示采用单线程非阻塞模式. + aio_max_threads = 0 +# 每个线程的空闲时间. + aio_thread_idle_limit = 60 + +# 允许访问的客户端IP地址范围 + aio_access_allow = 127.0.0.1:255.255.255.255, 127.0.0.1:127.0.0.1 + +# 当 acl_master 退出时,如果该值置1则该程序不等所有连接处理完毕便立即退出 + aio_quick_abort = 1 +############################################################################ +# 应用自己的配置选项 + +# 内部 rpc 通信的监听地址 +# rpc_addr = /opt/acl/var/private/http_rpc.sock +# 是否针对 HTTP 客户端采取预读方式 + preread = 1 +# rpc 线程池中最大线程数量限制 + nthreads_limit = 4 +# 响应 HTTP 客户端的数据体长度 + echo_length = 1024 +} diff --git a/lib_acl_cpp/samples/master_http_rpc/master_service.cpp b/lib_acl_cpp/samples/master_http_rpc/master_service.cpp new file mode 100644 index 000000000..434779523 --- /dev/null +++ b/lib_acl_cpp/samples/master_http_rpc/master_service.cpp @@ -0,0 +1,104 @@ +#include "stdafx.h" +#include +#include "gc_timer.h" +#include "rpc_stats.h" +#include "rpc_timer.h" +#include "rpc_manager.h" +#include "http_client.h" +#include "master_service.h" + +//////////////////////////////////////////////////////////////////////////////// +// 配置内容项 + +char *var_cfg_rpc_addr; +acl::master_str_tbl var_conf_str_tab[] = { + { "rpc_addr", "127.0.0.1:0", &var_cfg_rpc_addr }, + + { 0, 0, 0 } +}; + +int var_cfg_preread; +acl::master_bool_tbl var_conf_bool_tab[] = { + { "preread", 1, &var_cfg_preread }, + + { 0, 0, 0 } +}; + +int var_cfg_nthreads_limit; +int var_cfg_echo_length; +acl::master_int_tbl var_conf_int_tab[] = { + { "nthreads_limit", 4, &var_cfg_nthreads_limit, 0, 0 }, + { "echo_length", 1024, &var_cfg_echo_length, 0, 0 }, + + { 0, 0 , 0 , 0, 0 } +}; + +//////////////////////////////////////////////////////////////////////////////// + +master_service::master_service() +{ +} + +master_service::~master_service() +{ +} + +bool master_service::on_accept(acl::aio_socket_stream* client) +{ + // 如果允许在主线程中预读,则设置流的预读标志位 + if (var_cfg_preread) + { + ACL_VSTREAM* vstream = client->get_vstream(); + vstream->flag |= ACL_VSTREAM_FLAG_PREREAD; + } + + // 创建异步客户端流的回调对象并与该异步流进行绑定 + http_client* callback = new http_client(client); + + // 注册异步流的读回调过程 + client->add_read_callback(callback); + + // 注册异步流的写回调过程 + client->add_write_callback(callback); + + // 注册异步流的关闭回调过程 + client->add_close_callback(callback); + + // 注册异步流的超时回调过程 + client->add_timeout_callback(callback); + + rpc_read_wait_add(); + + // 监控异步流是否可读 + client->read_wait(0); + + return true; +} + +void master_service::proc_on_init() +{ + rpc_stats_init(); + + // get aio_handle from master_aio + acl::aio_handle* handle = get_handle(); + assert(handle != NULL); + + // init rpc service + rpc_manager::get_instance().init(handle, var_cfg_nthreads_limit, + var_cfg_rpc_addr); + + // start one timer to logger the rpc status + rpc_timer* timer = new rpc_timer(*handle); + timer->start(1); + + if (var_mem_slice_on) + { + gc_timer* gt = new gc_timer(*handle); + gt->start(2); + } +} + +void master_service::proc_on_exit() +{ + rpc_manager::get_instance().finish(); +} diff --git a/lib_acl_cpp/samples/master_http_rpc/master_service.h b/lib_acl_cpp/samples/master_http_rpc/master_service.h new file mode 100644 index 000000000..ae3f4d6b2 --- /dev/null +++ b/lib_acl_cpp/samples/master_http_rpc/master_service.h @@ -0,0 +1,28 @@ +#pragma once + +class master_service : public acl::master_aio +{ +public: + master_service(); + ~master_service(); + +protected: + /** + * 纯虚函数:当接收到一个客户端连接时调用此函数 + * @param stream {aio_socket_stream*} 新接收到的客户端异步流对象 + * @return {bool} 该函数如果返回 false 则通知服务器框架不再接收 + * 远程客户端连接,否则继续接收客户端连接 + */ + bool on_accept(acl::aio_socket_stream* stream); + + /** + * 当进程切换用户身份后调用的回调函数,此函数被调用时,进程 + * 的权限为普通受限级别 + */ + virtual void proc_on_init(); + + /** + * 当进程退出前调用的回调函数 + */ + virtual void proc_on_exit(); +}; diff --git a/lib_acl_cpp/samples/master_http_rpc/rpc_manager.cpp b/lib_acl_cpp/samples/master_http_rpc/rpc_manager.cpp new file mode 100644 index 000000000..0fd021156 --- /dev/null +++ b/lib_acl_cpp/samples/master_http_rpc/rpc_manager.cpp @@ -0,0 +1,41 @@ +#include "stdafx.h" +#include "rpc_manager.h" + +rpc_manager::rpc_manager() +: handle_(NULL) +, service_(NULL) +{ +} + +rpc_manager::~rpc_manager() +{ + logger("rpc service destroy ok!"); +} + + +void rpc_manager::init(acl::aio_handle* handle, int max_threads /* = 10 */, + const char* rpc_addr /* = NULL */) +{ + handle_ = handle; + + // 创建 rpc 服务对象 + service_ = new acl::rpc_service(max_threads); + // 打开消息服务 + if (service_->open(handle_, rpc_addr) == false) + logger_fatal("open service error: %s", acl::last_serror()); +} + +void rpc_manager::finish() +{ + if (service_) + { + delete service_; + if (handle_) + handle_->check(); + } +} + +void rpc_manager::fork(acl::rpc_request* req) +{ + service_->rpc_fork(req); +} diff --git a/lib_acl_cpp/samples/master_http_rpc/rpc_manager.h b/lib_acl_cpp/samples/master_http_rpc/rpc_manager.h new file mode 100644 index 000000000..5e41fef0a --- /dev/null +++ b/lib_acl_cpp/samples/master_http_rpc/rpc_manager.h @@ -0,0 +1,33 @@ +#pragma once + +/** + * 本类对象将阻塞任务交给子线程处理;为了方便使用,将该类声明为单例类 + */ +class rpc_manager : public acl::singleton +{ +public: + rpc_manager(); + ~rpc_manager(); + + /** + * 初始化函数 + * @param handle {acl::aio_handle*} 异步引擎句柄 + * @param max_threads {int} 子线程池的最大线程数量 + * @param rpc_addr {const char*} RPC 通道监听地址 + */ + void init(acl::aio_handle*, int max_threads = 10, + const char* rpc_addr = NULL); + + void finish(); + + /** + * 发起一个阻塞过程,将该过程交由子线程处理 + * @param req {acl::rpc_request*} 阻塞任务对象 + */ + void fork(acl::rpc_request* req); +private: + // 异步消息句柄 + acl::aio_handle* handle_; + // 异步 RPC 通信服务句柄 + acl::rpc_service* service_; +}; diff --git a/lib_acl_cpp/samples/master_http_rpc/rpc_stats.cpp b/lib_acl_cpp/samples/master_http_rpc/rpc_stats.cpp new file mode 100644 index 000000000..f4fc3d189 --- /dev/null +++ b/lib_acl_cpp/samples/master_http_rpc/rpc_stats.cpp @@ -0,0 +1,69 @@ +#include "stdafx.h" +#include "rpc_stats.h" + +static int __count = 0; + +void rpc_add() +{ + __count++; +} + +void rpc_del() +{ + __count--; +} + +void rpc_out() +{ + logger(">> rpc_count: %d <<", __count); +} + +////////////////////////////////////////////////////////////////////////// + +static acl::locker* __lock; +static int __req = 0; + +void rpc_stats_init() +{ + __lock = new acl::locker(); +} + +void rpc_req_add() +{ + __lock->lock(); + __req++; + __lock->unlock(); +} + +void rpc_req_del() +{ + __lock->lock(); + __req--; + __lock->unlock(); +} + +void rpc_req_out() +{ + __lock->lock(); + logger(">> req_count: %d <<", __req); + __lock->unlock(); +} + +////////////////////////////////////////////////////////////////////////// + +static int __read_wait = 0; + +void rpc_read_wait_add() +{ + __read_wait++; +} + +void rpc_read_wait_del() +{ + __read_wait--; +} + +void rpc_read_wait_out() +{ + logger(">> read wait count: %d <<", __read_wait); +} diff --git a/lib_acl_cpp/samples/master_http_rpc/rpc_stats.h b/lib_acl_cpp/samples/master_http_rpc/rpc_stats.h new file mode 100644 index 000000000..4c3251b03 --- /dev/null +++ b/lib_acl_cpp/samples/master_http_rpc/rpc_stats.h @@ -0,0 +1,15 @@ +#pragma once + +void rpc_stats_init(); + +void rpc_add(); +void rpc_del(); +void rpc_out(); + +void rpc_req_add(); +void rpc_req_del(); +void rpc_req_out(); + +void rpc_read_wait_add(); +void rpc_read_wait_del(); +void rpc_read_wait_out(); diff --git a/lib_acl_cpp/samples/master_http_rpc/rpc_timer.cpp b/lib_acl_cpp/samples/master_http_rpc/rpc_timer.cpp new file mode 100644 index 000000000..8cb2099db --- /dev/null +++ b/lib_acl_cpp/samples/master_http_rpc/rpc_timer.cpp @@ -0,0 +1,36 @@ +#include "stdafx.h" +#include "rpc_stats.h" +#include "rpc_timer.h" + +rpc_timer::rpc_timer(acl::aio_handle& handle) +: acl::aio_timer_callback(true) +, handle_(handle) +{ +} + +rpc_timer::~rpc_timer() +{ +} + +void rpc_timer::destroy() +{ + delete this; +} + +void rpc_timer::start(int delay) +{ + // 璁剧疆瀹氭椂鍣紝灏嗙杞崲涓哄井濡 + handle_.set_timer(this, delay * 1000000); +} + +void rpc_timer::stop() +{ + handle_.del_timer(this); +} + +void rpc_timer::timer_callback(unsigned int) +{ + rpc_out(); // 杈撳嚭褰撳墠 rpc 闃熷垪鐨勬暟閲 + rpc_req_out(); + rpc_read_wait_out(); +} diff --git a/lib_acl_cpp/samples/master_http_rpc/rpc_timer.h b/lib_acl_cpp/samples/master_http_rpc/rpc_timer.h new file mode 100644 index 000000000..6e32b9733 --- /dev/null +++ b/lib_acl_cpp/samples/master_http_rpc/rpc_timer.h @@ -0,0 +1,18 @@ +#pragma once + +class rpc_timer : public acl::aio_timer_callback +{ +public: + rpc_timer(acl::aio_handle& handle); + + void start(int delay); + void stop(); +private: + ~rpc_timer(); + + acl::aio_handle& handle_; + + // 鍩虹被绾櫄鍑芥暟 + virtual void timer_callback(unsigned int id); + virtual void destroy(void); +}; diff --git a/lib_acl_cpp/samples/master_http_rpc/stdafx.cpp b/lib_acl_cpp/samples/master_http_rpc/stdafx.cpp new file mode 100644 index 000000000..3a8a20e11 --- /dev/null +++ b/lib_acl_cpp/samples/master_http_rpc/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// master_threads.pch 将成为预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + +// TODO: 在 STDAFX.H 中 +//引用任何所需的附加头文件,而不是在此文件中引用 diff --git a/lib_acl_cpp/samples/master_http_rpc/stdafx.h b/lib_acl_cpp/samples/master_http_rpc/stdafx.h new file mode 100644 index 000000000..4e0adb4e0 --- /dev/null +++ b/lib_acl_cpp/samples/master_http_rpc/stdafx.h @@ -0,0 +1,15 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是常用但不常更改的项目特定的包含文件 +// + +#pragma once + + +//#include +//#include + +// TODO: 在此处引用程序要求的附加头文件 + +#include "lib_acl.h" +#include "acl_cpp/lib_acl.hpp" +#include "global.h" diff --git a/lib_acl_cpp/samples/master_http_threads/Makefile b/lib_acl_cpp/samples/master_http_threads/Makefile new file mode 100644 index 000000000..330f8fe4a --- /dev/null +++ b/lib_acl_cpp/samples/master_http_threads/Makefile @@ -0,0 +1,3 @@ +include ../Makefile.in +EXTLIBS = -lz +PROG = master_http_threads diff --git a/lib_acl_cpp/samples/master_http_threads/main.cpp b/lib_acl_cpp/samples/master_http_threads/main.cpp new file mode 100644 index 000000000..ce5fe315a --- /dev/null +++ b/lib_acl_cpp/samples/master_http_threads/main.cpp @@ -0,0 +1,36 @@ +#include "stdafx.h" +#include "master_service.h" + +int main(int argc, char* argv[]) +{ +#if 0 + acl_mem_slice_init(8, 1024, 100000, + ACL_SLICE_FLAG_GC2 | + ACL_SLICE_FLAG_RTGC_OFF | + ACL_SLICE_FLAG_LP64_ALIGN); +#endif + + // 初始化 acl 库 + acl::acl_cpp_init(); + + master_service& ms = acl::singleton2::get_instance(); + + // 设置配置参数表 + ms.set_cfg_int(var_conf_int_tab); + ms.set_cfg_int64(var_conf_int64_tab); + ms.set_cfg_str(var_conf_str_tab); + ms.set_cfg_bool(var_conf_bool_tab); + + // 开始运行 + + if (argc >= 2 && strcmp(argv[1], "alone") == 0) + { + const char* addr = "127.0.0.1:8888"; + printf("listen on: %s\r\n", addr); + ms.run_alone(addr, NULL, 5); // 单独运行方式 + } + else + ms.run_daemon(argc, argv); // acl_master 控制模式运行 + + return 0; +} diff --git a/lib_acl_cpp/samples/master_http_threads/master_http_threads.cf b/lib_acl_cpp/samples/master_http_threads/master_http_threads.cf new file mode 100644 index 000000000..bdfa43ea9 --- /dev/null +++ b/lib_acl_cpp/samples/master_http_threads/master_http_threads.cf @@ -0,0 +1,114 @@ + +service master_http_threads { +# 进程是否禁止运行 + master_disable = no +# 服务地址及端口号 + master_service = 127.0.0.1:5001 + +# 服务监听为域套接口 +# master_service = aio_echo.sock +# 服务类型 + master_type = inet +# master_type = unix + +# 当子进程异常退出时,如果该值非空,则将子进程异常退出的消息通知该服务 +# master_notify_addr = 127.0.0.1:5801 +# 邮件通知接收者 +# master_notify_recipients = zhengshuxin@hotmail.com + +# 是否允许延迟接受客户端连接,如果为0则表示关闭该功能,如果大于0则表示打开此功能 +# 并且此值代表延迟接受连接的超时值,超过此值时如果客户端依然没有发来数据,则操作 +# 系统会在系统层直接关闭该连接 +# master_defer_accept = 0 +# 是否只允许私有访问, 如果为 y, 则域套接口创建在 {install_path}/var/log/private/ 目录下, +# 如果为 n, 则域套接口创建在 {install_path}/var/log/public/ 目录下, + master_private = n + master_unpriv = n +# 是否需要 chroot: n -- no, y -- yes + master_chroot = n +# 每隔多长时间触发一次,单位为秒(仅对 trigger 模式有效) + master_wakeup = - +# 最大进程数 + master_maxproc = 1 +# 进程程序名 + master_command = master_http_threads +# 进程日志记录文件 + master_log = {install_path}/var/log/master_http_threads +# 进程启动参数,只能为: -u [是否允许以某普通用户的身份运行] +# master_args = +# 传递给服务子进程的环境变量, 可以通过 getenv("SERVICE_ENV") 获得此值 +# master_env = mempool_limit:512000000 +# master_env = logme:FALSE, priority:E_LOG_INFO, action:E_LOG_PER_DAY, flush:sync_flush, imit_size:512,\ +# sync_action:E_LOG_SEM, sem_name:/tmp/ioctl_echo.sem + +# 是否允许产生 core 文件 +# ioctl_enable_core = 1 +# 每个进程实例处理连接数的最大次数,超过此值后进程实例主动退出 + ioctl_use_limit = 100 +# 每个进程实例的空闲超时时间,超过此值后进程实例主动退出 + ioctl_idle_limit = 120 +# 记录进程PID的位置(对于多进程实例来说没有意义) + ioctl_pid_dir = {install_path}/var/pid +# 进程运行时所在的路径 + ioctl_queue_dir = {install_path}/var +# 读写超时时间, 单位为秒 + ioctl_rw_timeout = 120 +# 读缓冲区的缓冲区大小 + ioctl_buf_size = 8192 +# 每次 accept 时的循环接收的最大次数 + ioctl_max_accept = 25 +# 在并发访问量非常低的情况下,如访问量在 10 次/秒 以下时,可以找开此值(即赋为1),以加速事件循环过程, +# 从而防止服务进程阻塞在 select 上的时间过长而影响访问速度 +# ioctl_enable_dog = 0 +# 进程运行时的用户身份 + ioctl_owner = root + +# 用 select 进行循环时的时间间隔 +# 单位为秒 + ioctl_delay_sec = 0 +# 单位为微秒 + ioctl_delay_usec = 500 + +# 采用事件循环的方式: select(default), poll, kernel(epoll/devpoll/kqueue) + ioctl_event_mode = kernel + +# 线程池的最大线程数 + ioctl_max_threads = 250 +# 线程的堆栈空间大小,单位为字节,0表示使用系统缺省值 + ioctl_stacksize = 0 +# 允许访问 udserver 的客户端IP地址范围 + ioctl_access_allow = 127.0.0.1:255.255.255.255, 127.0.0.1:127.0.0.1 + +# 当 acl_master 退出时,如果该值置1则该程序不等所有连接处理完毕便立即退出 + ioctl_quick_abort = 1 + +## app_main.c 需要的参数项 +# 客户端连接的最大空闲时间阀值 + app_client_idle_limit = 12 + +############################################################################ +# 应用自己的配置选项 + +# mysql 服务地址 +# mysql_dbaddr = /tmp/mysql.sock +# mysql_dbaddr = 10.0.250.199:3306 +# 连接 mysql 数据库的连接池的最大值 +# mysql_dbmax = 200 +# ping mysql 连接的间隔时间, 以秒为单位 +# mysql_dbping = 10 +# mysql 连接空闲的时间间隔, 以秒为单位 +# mysql_dbtimeout = 30 + +# 数据库名称 +# mysql_dbname = ioctl_db +# 数据库访问用户 +# mysql_dbuser = ioctl_user +# 数据库用户访问密码 +# mysql_dbpass = 111111 + +# 是否输出当前内存的状态信息 +# debug_mem = 1 +# 是否在一个线程中连接读 +# loop_read = 1 +} + diff --git a/lib_acl_cpp/samples/master_http_threads/master_service.cpp b/lib_acl_cpp/samples/master_http_threads/master_service.cpp new file mode 100644 index 000000000..c2b3ccedf --- /dev/null +++ b/lib_acl_cpp/samples/master_http_threads/master_service.cpp @@ -0,0 +1,113 @@ +#include "stdafx.h" +#include "master_service.h" + +//////////////////////////////////////////////////////////////////////////////// +// 配置内容项 + +char *var_cfg_str; +acl::master_str_tbl var_conf_str_tab[] = { + { "str", "test_msg", &var_cfg_str }, + + { 0, 0, 0 } +}; + +int var_cfg_bool; +acl::master_bool_tbl var_conf_bool_tab[] = { + { "bool", 1, &var_cfg_bool }, + + { 0, 0, 0 } +}; + +int var_cfg_buf_size; +acl::master_int_tbl var_conf_int_tab[] = { + { "buf_size", 1024, &var_cfg_buf_size, 0, 0 }, + + { 0, 0 , 0 , 0, 0 } +}; + +long long int var_cfg_int64; +acl::master_int64_tbl var_conf_int64_tab[] = { + { "int64", 120, &var_cfg_int64, 0, 0 }, + + { 0, 0 , 0 , 0, 0 } +}; + +//////////////////////////////////////////////////////////////////////////////// + +master_service::master_service() +: res_buf_(NULL) +{ +} + +master_service::~master_service() +{ + if (res_buf_) + acl_myfree(res_buf_); +} + +bool master_service::thread_on_read(acl::socket_stream* stream) +{ + acl::http_response res(stream); + // 响应数据体为 xml 格式 + res.response_header().set_content_type("text/html"); + + // 读 HTTP 请求头 + if (res.read_header() == false) + return false; + + acl::string buf; + // 读 HTTP 请求体数据 + if (res.get_body(buf) == false) + return false; + + acl::http_client* client = res.get_client(); + + // 判断客户端是否希望保持长连接 + bool keep_alive = client->keep_alive(); + + // 返回数据给客户端 + + if (res.response(res_buf_, var_cfg_buf_size, 200, keep_alive) == false) + return false; + + return keep_alive ? true : false; +} + +bool master_service::thread_on_accept(acl::socket_stream* conn) +{ + if (0) + acl_tcp_so_linger(conn->sock_handle(), 1, 0); + return true; +} + +bool master_service::thread_on_timeout(acl::socket_stream*) +{ + return false; +} + +void master_service::thread_on_close(acl::socket_stream*) +{ +} + +void master_service::thread_on_init() +{ +} + +void master_service::thread_on_exit() +{ +} + +void master_service::proc_on_init() +{ + if (var_cfg_buf_size <= 0) + var_cfg_buf_size = 1024; + res_buf_ = (char*) acl_mymalloc(var_cfg_buf_size + 1); + int i; + for (i = 0; i < var_cfg_buf_size; i++) + res_buf_[i] = 'X'; + res_buf_[i] = 0; +} + +void master_service::proc_on_exit() +{ +} diff --git a/lib_acl_cpp/samples/master_http_threads/master_service.h b/lib_acl_cpp/samples/master_http_threads/master_service.h new file mode 100644 index 000000000..281e86382 --- /dev/null +++ b/lib_acl_cpp/samples/master_http_threads/master_service.h @@ -0,0 +1,86 @@ +#pragma once +#include "acl_cpp/master/master_threads.hpp" +#include "acl_cpp/master/master_conf.hpp" + +//////////////////////////////////////////////////////////////////////////////// +// 配置内容项 + +extern char *var_cfg_str; +extern acl::master_str_tbl var_conf_str_tab[]; + +extern int var_cfg_bool; +extern acl::master_bool_tbl var_conf_bool_tab[]; + +extern int var_cfg_buf_size; +extern acl::master_int_tbl var_conf_int_tab[]; + +extern long long int var_cfg_int64; +extern acl::master_int64_tbl var_conf_int64_tab[]; + +//////////////////////////////////////////////////////////////////////////////// + +//class acl::socket_stream; + +class master_service : public acl::master_threads +{ +public: + master_service(); + ~master_service(); + +protected: + /** + * 纯虚函数:当某个客户端连接有数据可读或关闭或出错时调用此函数 + * @param stream {socket_stream*} + * @return {bool} 返回 false 则表示当函数返回后需要关闭连接, + * 否则表示需要保持长连接,如果该流出错,则应用应该返回 false + */ + virtual bool thread_on_read(acl::socket_stream* stream); + + /** + * 当线程池中的某个线程获得一个连接时的回调函数, + * 子类可以做一些初始化工作 + * @param stream {socket_stream*} + * @return {bool} 如果返回 false 则表示子类要求关闭连接,而不 + * 必将该连接再传递至 thread_main 过程 + */ + virtual bool thread_on_accept(acl::socket_stream* stream); + + /** + * 当某个网络连接的 IO 读写超时时的回调函数,如果该函数返回 true 则表示继续等待下一次 + * 读写,否则则希望关闭该连接 + * @param stream {socket_stream*} + * @return {bool} 如果返回 false 则表示子类要求关闭连接,而不 + * 必将该连接再传递至 thread_main 过程 + */ + virtual bool thread_on_timeout(acl::socket_stream* stream); + + /** + * 当与某个线程绑定的连接关闭时的回调函数 + * @param stream {socket_stream*} + */ + virtual void thread_on_close(acl::socket_stream* stream); + + /** + * 当线程池中一个新线程被创建时的回调函数 + */ + virtual void thread_on_init(); + + /** + * 当线程池中一个线程退出时的回调函数 + */ + virtual void thread_on_exit(); + + /** + * 当进程切换用户身份后调用的回调函数,此函数被调用时,进程 + * 的权限为普通受限级别 + */ + virtual void proc_on_init(); + + /** + * 当进程退出前调用的回调函数 + */ + virtual void proc_on_exit(); + +private: + char* res_buf_; +}; diff --git a/lib_acl_cpp/samples/master_http_threads/stdafx.cpp b/lib_acl_cpp/samples/master_http_threads/stdafx.cpp new file mode 100644 index 000000000..3a8a20e11 --- /dev/null +++ b/lib_acl_cpp/samples/master_http_threads/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// master_threads.pch 将成为预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + +// TODO: 在 STDAFX.H 中 +//引用任何所需的附加头文件,而不是在此文件中引用 diff --git a/lib_acl_cpp/samples/master_http_threads/stdafx.h b/lib_acl_cpp/samples/master_http_threads/stdafx.h new file mode 100644 index 000000000..0acde2ab3 --- /dev/null +++ b/lib_acl_cpp/samples/master_http_threads/stdafx.h @@ -0,0 +1,14 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是常用但不常更改的项目特定的包含文件 +// + +#pragma once + + +//#include +//#include + +// TODO: 在此处引用程序要求的附加头文件 + +#include "lib_acl.h" +#include "acl_cpp/lib_acl.hpp" diff --git a/lib_acl_cpp/samples/master_proc/Makefile b/lib_acl_cpp/samples/master_proc/Makefile new file mode 100644 index 000000000..892192830 --- /dev/null +++ b/lib_acl_cpp/samples/master_proc/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = master_proc diff --git a/lib_acl_cpp/samples/master_proc/ReadMe.txt b/lib_acl_cpp/samples/master_proc/ReadMe.txt new file mode 100644 index 000000000..e8009228a --- /dev/null +++ b/lib_acl_cpp/samples/master_proc/ReadMe.txt @@ -0,0 +1,31 @@ +======================================================================== + 控制台应用程序 : master_proc 项目概况 +======================================================================== + +应用程序向导已为您创建了这个 master_proc 应用程序。 +此文件包含组成 master_proc 应用程序 +的每个文件的内容摘要。 + + +master_proc.vcproj + 这是用应用程序向导生成的 VC++ 项目的主项目文件。 + 它包含有关生成此文件的 Visual C++ 版本的信息,以及 + 有关用应用程序向导选择的 + 平台、配置和项目功能的信息。 + +master_proc.cpp + 这是主应用程序源文件。 + +///////////////////////////////////////////////////////////////////////////// +其他标准文件: + +StdAfx.h、StdAfx.cpp + 这些文件用于生成名为 master_proc.pch + 的预编译头(PCH)文件以及名为 StdAfx.obj 的预编译类型文件。 + +///////////////////////////////////////////////////////////////////////////// +其他注释: + +应用程序向导使用 "TODO:" 注释指示应添加或自定义的源代码部分。 + +///////////////////////////////////////////////////////////////////////////// diff --git a/lib_acl_cpp/samples/master_proc/master_proc.cpp b/lib_acl_cpp/samples/master_proc/master_proc.cpp new file mode 100644 index 000000000..66c88c693 --- /dev/null +++ b/lib_acl_cpp/samples/master_proc/master_proc.cpp @@ -0,0 +1,137 @@ +// master_proc.cpp : 定义控制台应用程序的入口点。 +// + +#include "stdafx.h" +#include "acl_cpp/lib_acl.hpp" + +static char *var_cfg_debug_msg; + +static acl::master_str_tbl var_conf_str_tab[] = { + { "debug_msg", "test_msg", &var_cfg_debug_msg }, + + { 0, 0, 0 } +}; + +static int var_cfg_debug_enable; + +static acl::master_bool_tbl var_conf_bool_tab[] = { + { "debug_enable", 1, &var_cfg_debug_enable }, + + { 0, 0, 0 } +}; + +static int var_cfg_io_timeout; + +static acl::master_int_tbl var_conf_int_tab[] = { + { "io_timeout", 120, &var_cfg_io_timeout, 0, 0 }, + + { 0, 0 , 0 , 0, 0 } +}; + +static void (*format)(const char*, ...) = acl::log::msg1; + +////////////////////////////////////////////////////////////////////////// +using namespace acl; + +class master_proc_test : public master_proc +{ +public: + master_proc_test() {} + ~master_proc_test() {} +protected: + /** + * 基类纯虚函数:当接收到一个客户端连接时调用此函数 + * @param stream {aio_socket_stream*} 新接收到的客户端异步流对象 + * 注:该函数返回后,流连接将会被关闭,用户不应主动关闭该流 + */ + virtual void on_accept(socket_stream* stream) + { + if (stream->format("hello, you're welcome!\r\n") == -1) + return; + while (true) + { + if (on_read(stream) == false) + break; + } + } + + bool on_read(socket_stream* stream) + { + string buf; + if (stream->gets(buf) == false) + { + format("gets error: %s", acl::last_serror()); + return false; + } + if (buf == "quit") + { + stream->puts("bye!"); + return false; + } + + if (buf.empty()) + { + if (stream->write("\r\n") == -1) + { + format("write 1 error: %s", acl::last_serror()); + return false; + } + } + else if (stream->write(buf) == -1) + { + format("write 2 error: %s, buf(%s), len: %d", + acl::last_serror(), buf.c_str(), (int) buf.length()); + return false; + } + else if (stream->write("\r\n") == -1) + { + format("write 3 client error: %s", acl::last_serror()); + return false; + } + return true; + } + + // 基类虚函数:服务进程切换用户身份前调用此函数 + virtual void proc_pre_jail() + { + format("proc_pre_jail\r\n"); + } + + // 基类虚函数:服务进程切换用户身份后调用此函数 + virtual void proc_on_init() + { + format("proc init\r\n"); + } + + // 基类虚函数:服务进程退出前调用此函数 + virtual void proc_on_exit() + { + format("proc exit\r\n"); + } +private: +}; +////////////////////////////////////////////////////////////////////////// + +int main(int argc, char* argv[]) +{ + master_proc_test& mp = singleton2::get_instance(); + + // 设置配置参数表 + mp.set_cfg_int(var_conf_int_tab); + mp.set_cfg_int64(NULL); + mp.set_cfg_str(var_conf_str_tab); + mp.set_cfg_bool(var_conf_bool_tab); + + // 开始运行 + + if (argc >= 2 && strcmp(argv[1], "alone") == 0) + { + format = (void (*)(const char*, ...)) printf; + mp.run_alone("127.0.0.1:8888", NULL, 5); // 单独运行方式 + } + else + mp.run_daemon(argc, argv); // acl_master 控制模式运行 + + return 0; +} + diff --git a/lib_acl_cpp/samples/master_proc/master_proc.vcproj b/lib_acl_cpp/samples/master_proc/master_proc.vcproj new file mode 100644 index 000000000..adb498e77 --- /dev/null +++ b/lib_acl_cpp/samples/master_proc/master_proc.vcproj @@ -0,0 +1,269 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_acl_cpp/samples/master_proc/single_echo.cf b/lib_acl_cpp/samples/master_proc/single_echo.cf new file mode 100644 index 000000000..f0c6fb7c1 --- /dev/null +++ b/lib_acl_cpp/samples/master_proc/single_echo.cf @@ -0,0 +1,69 @@ +# service type private unpriv chroot wakeup maxproc command + args + +service single +{ +# 进程是否禁止运行 + master_disable = yes +# 服务地址及端口号 + master_service = :5003 +# 服务监听为域套接口 +# master_service = single_echo.sock +# 服务类型 + master_type = inet +# master_type = unix + +# 当子进程异常退出时,如果该值非空,则将子进程异常退出的消息通知该服务 +# master_notify_addr = 127.0.0.1:5801 +# 邮件通知接收者 +# master_notify_recipients = zhengshuxin@hotmail.com + +# 是否允许延迟接受客户端连接,如果为0则表示关闭该功能,如果大于0则表示打开此功能 +# 并且此值代表延迟接受连接的超时值,超过此值时如果客户端依然没有发来数据,则操作 +# 系统会在系统层直接关闭该连接 +# master_defer_accept = 0 +# 是否只允许私有访问, 如果为 y, 则域套接口创建在 {install_path}/var/log/private/ 目录下, +# 如果为 n, 则域套接口创建在 {install_path}/var/log/public/ 目录下, + master_private = n + master_unpriv = n +# 是否需要 chroot: n -- no, y -- yes + master_chroot = n +# 每隔多长时间触发一次,单位为秒(仅对 trigger 模式有效) + master_wakeup = - +# 最大进程数 + master_maxproc = 10 +# 进程程序名 + master_command = master_proc +# 进程启动参数,只能为: -u [是否允许以某普通用户的身份运行] +# master_args = +# 进程日志记录文件 + master_log = {install_path}/var/log/single_echo.log +# 传递给服务子进程的环境变量, 可以通过 getenv("SERVICE_ENV") 获得此值 + master_env = logme:FALSE, priority:E_LOG_INFO, action:E_LOG_PER_DAY, flush:sync_flush, imit_size:512,\ + sync_action:E_LOG_SEM, sem_name:/tmp/single_echo.sem + +# 是否允许产生 core 文件 +# single_enable_core = 1 +# 每个进程实例处理连接数的最大次数,超过此值后进程实例主动退出 + single_use_limit = 250 +# 每个进程实例的空闲超时时间,超过此值后进程实例主动退出 +# single_idle_limit = 180 +# 记录进程PID的位置(对于多进程实例来说没有意义) + single_pid_dir = {install_path}/var/pid +# 进程运行时所在的路径 + single_queue_dir = {install_path}/var +# 读写超时时间, 单位为秒 + single_rw_timeout = 1800 +# 读缓冲区的缓冲区大小 + single_buf_size = 8192 +# 进程运行时的用户身份 + single_owner = root + +# single_in_flow_delay = 1 +# single_owner = owner +# 用 select 进行循环时的时间间隔 +# 单位为秒 +# single_delay_sec = 1 +# 单位为微秒 +# single_delay_usec = 5000 +# single_daemon_timeout = 1800 +} diff --git a/lib_acl_cpp/samples/master_proc/stdafx.cpp b/lib_acl_cpp/samples/master_proc/stdafx.cpp new file mode 100644 index 000000000..bf035a491 --- /dev/null +++ b/lib_acl_cpp/samples/master_proc/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// master_proc.pch 将成为预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + +// TODO: 在 STDAFX.H 中 +//引用任何所需的附加头文件,而不是在此文件中引用 diff --git a/lib_acl_cpp/samples/master_proc/stdafx.h b/lib_acl_cpp/samples/master_proc/stdafx.h new file mode 100644 index 000000000..b98553f2c --- /dev/null +++ b/lib_acl_cpp/samples/master_proc/stdafx.h @@ -0,0 +1,11 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是常用但不常更改的项目特定的包含文件 +// + +#pragma once + + +#include +//#include + +// TODO: 在此处引用程序要求的附加头文件 diff --git a/lib_acl_cpp/samples/master_proc/valgrind.sh b/lib_acl_cpp/samples/master_proc/valgrind.sh new file mode 100644 index 000000000..4d52baf1a --- /dev/null +++ b/lib_acl_cpp/samples/master_proc/valgrind.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +valgrind --tool=memcheck --leak-check=yes -v ./master_proc alone diff --git a/lib_acl_cpp/samples/master_threads/Makefile b/lib_acl_cpp/samples/master_threads/Makefile new file mode 100644 index 000000000..edee1db11 --- /dev/null +++ b/lib_acl_cpp/samples/master_threads/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = master_threads diff --git a/lib_acl_cpp/samples/master_threads/ReadMe.txt b/lib_acl_cpp/samples/master_threads/ReadMe.txt new file mode 100644 index 000000000..1d81b94fd --- /dev/null +++ b/lib_acl_cpp/samples/master_threads/ReadMe.txt @@ -0,0 +1,31 @@ +======================================================================== + 控制台应用程序 : master_threads 项目概况 +======================================================================== + +应用程序向导已为您创建了这个 master_threads 应用程序。 +此文件包含组成 master_threads 应用程序 +的每个文件的内容摘要。 + + +master_threads.vcproj + 这是用应用程序向导生成的 VC++ 项目的主项目文件。 + 它包含有关生成此文件的 Visual C++ 版本的信息,以及 + 有关用应用程序向导选择的 + 平台、配置和项目功能的信息。 + +master_threads.cpp + 这是主应用程序源文件。 + +///////////////////////////////////////////////////////////////////////////// +其他标准文件: + +StdAfx.h、StdAfx.cpp + 这些文件用于生成名为 master_threads.pch + 的预编译头(PCH)文件以及名为 StdAfx.obj 的预编译类型文件。 + +///////////////////////////////////////////////////////////////////////////// +其他注释: + +应用程序向导使用 "TODO:" 注释指示应添加或自定义的源代码部分。 + +///////////////////////////////////////////////////////////////////////////// diff --git a/lib_acl_cpp/samples/master_threads/ioctl_echo.cf b/lib_acl_cpp/samples/master_threads/ioctl_echo.cf new file mode 100644 index 000000000..14c5c849d --- /dev/null +++ b/lib_acl_cpp/samples/master_threads/ioctl_echo.cf @@ -0,0 +1,114 @@ + +service server { +# 进程是否禁止运行 + master_disable = no +# 服务地址及端口号 + master_service = 127.0.0.1:5001 + +# 服务监听为域套接口 +# master_service = aio_echo.sock +# 服务类型 + master_type = inet +# master_type = unix + +# 当子进程异常退出时,如果该值非空,则将子进程异常退出的消息通知该服务 +# master_notify_addr = 127.0.0.1:5801 +# 邮件通知接收者 +# master_notify_recipients = zhengshuxin@hotmail.com + +# 是否允许延迟接受客户端连接,如果为0则表示关闭该功能,如果大于0则表示打开此功能 +# 并且此值代表延迟接受连接的超时值,超过此值时如果客户端依然没有发来数据,则操作 +# 系统会在系统层直接关闭该连接 +# master_defer_accept = 0 +# 是否只允许私有访问, 如果为 y, 则域套接口创建在 {install_path}/var/log/private/ 目录下, +# 如果为 n, 则域套接口创建在 {install_path}/var/log/public/ 目录下, + master_private = n + master_unpriv = n +# 是否需要 chroot: n -- no, y -- yes + master_chroot = n +# 每隔多长时间触发一次,单位为秒(仅对 trigger 模式有效) + master_wakeup = - +# 最大进程数 + master_maxproc = 1 +# 进程程序名 + master_command = master_threads +# 进程日志记录文件 + master_log = {install_path}/var/log/ioctl_echo.log +# 进程启动参数,只能为: -u [是否允许以某普通用户的身份运行] +# master_args = +# 传递给服务子进程的环境变量, 可以通过 getenv("SERVICE_ENV") 获得此值 + master_env = mempool_limit:512000000 +# master_env = logme:FALSE, priority:E_LOG_INFO, action:E_LOG_PER_DAY, flush:sync_flush, imit_size:512,\ +# sync_action:E_LOG_SEM, sem_name:/tmp/ioctl_echo.sem + +# 是否允许产生 core 文件 +# ioctl_enable_core = 1 +# 每个进程实例处理连接数的最大次数,超过此值后进程实例主动退出 + ioctl_use_limit = 100 +# 每个进程实例的空闲超时时间,超过此值后进程实例主动退出 + ioctl_idle_limit = 120 +# 记录进程PID的位置(对于多进程实例来说没有意义) + ioctl_pid_dir = {install_path}/var/pid +# 进程运行时所在的路径 + ioctl_queue_dir = {install_path}/var +# 读写超时时间, 单位为秒 + ioctl_rw_timeout = 120 +# 读缓冲区的缓冲区大小 + ioctl_buf_size = 8192 +# 每次 accept 时的循环接收的最大次数 + ioctl_max_accept = 25 +# 在并发访问量非常低的情况下,如访问量在 10 次/秒 以下时,可以找开此值(即赋为1),以加速事件循环过程, +# 从而防止服务进程阻塞在 select 上的时间过长而影响访问速度 +# ioctl_enable_dog = 0 +# 进程运行时的用户身份 + ioctl_owner = root + +# 用 select 进行循环时的时间间隔 +# 单位为秒 + ioctl_delay_sec = 0 +# 单位为微秒 + ioctl_delay_usec = 500 + +# 采用事件循环的方式: select(default), poll, kernel(epoll/devpoll/kqueue) + ioctl_event_mode = select + +# 线程池的最大线程数 + ioctl_max_threads = 250 +# 线程的堆栈空间大小,单位为字节,0表示使用系统缺省值 + ioctl_stacksize = 0 +# 允许访问 udserver 的客户端IP地址范围 + ioctl_access_allow = 127.0.0.1:255.255.255.255, 127.0.0.1:127.0.0.1 + +# 当 acl_master 退出时,如果该值置1则该程序不等所有连接处理完毕便立即退出 + ioctl_quick_abort = 1 + +## app_main.c 需要的参数项 +# 客户端连接的最大空闲时间阀值 + app_client_idle_limit = 12 + +############################################################################ +# 应用自己的配置选项 + +# mysql 服务地址 +# mysql_dbaddr = /tmp/mysql.sock +# mysql_dbaddr = 10.0.250.199:3306 +# 连接 mysql 数据库的连接池的最大值 +# mysql_dbmax = 200 +# ping mysql 连接的间隔时间, 以秒为单位 +# mysql_dbping = 10 +# mysql 连接空闲的时间间隔, 以秒为单位 +# mysql_dbtimeout = 30 + +# 数据库名称 +# mysql_dbname = ioctl_db +# 数据库访问用户 +# mysql_dbuser = ioctl_user +# 数据库用户访问密码 +# mysql_dbpass = 111111 + +# 是否输出当前内存的状态信息 + debug_mem = 1 +# 是否在一个线程中连接读 + loop_read = 1 +} + diff --git a/lib_acl_cpp/samples/master_threads/master_threads.cpp b/lib_acl_cpp/samples/master_threads/master_threads.cpp new file mode 100644 index 000000000..5e3b5d2ae --- /dev/null +++ b/lib_acl_cpp/samples/master_threads/master_threads.cpp @@ -0,0 +1,195 @@ +// master_threads.cpp : 定义控制台应用程序的入口点。 +// + +#include "stdafx.h" +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/stdlib/util.hpp" +#include "acl_cpp/master/master_threads.hpp" +#include "acl_cpp/stream/socket_stream.hpp" + +static char *var_cfg_debug_msg; + +static acl::master_str_tbl var_conf_str_tab[] = { + { "debug_msg", "test_msg", &var_cfg_debug_msg }, + + { 0, 0, 0 } +}; + +static int var_cfg_debug_enable; +static int var_cfg_keep_alive; +static int var_cfg_loop; + +static acl::master_bool_tbl var_conf_bool_tab[] = { + { "debug_enable", 1, &var_cfg_debug_enable }, + { "keep_alive", 1, &var_cfg_keep_alive }, + { "loop_read", 1, &var_cfg_loop }, + + { 0, 0, 0 } +}; + +static int var_cfg_io_timeout; + +static acl::master_int_tbl var_conf_int_tab[] = { + { "io_timeout", 120, &var_cfg_io_timeout, 0, 0 }, + + { 0, 0 , 0 , 0, 0 } +}; + +static void (*format)(const char*, ...) = acl::log::msg1; + +////////////////////////////////////////////////////////////////////////// + +class master_threads_test : public acl::master_threads +{ +public: + master_threads_test() + { + + } + + ~master_threads_test() + { + + } + +protected: + // 基类纯虚函数:当客户端连接有数据可读或关闭时回调此函数,返回 true 表示 + // 继续与客户端保持长连接,否则表示需要关闭客户端连接 + virtual bool thread_on_read(acl::socket_stream* stream) + { + while (true) + { + if (on_read(stream) == false) + return false; + if (var_cfg_loop == 0) + break; + } + return true; + } + + bool on_read(acl::socket_stream* stream) + { + format("%s(%d)", __FILE__, __LINE__); + acl::string buf; + if (stream->gets(buf) == false) + { + format("gets error: %s", acl::last_serror()); + format("%s(%d)", __FILE__, __LINE__); + return false; + } + if (buf == "quit") + { + stream->puts("bye!"); + return false; + } + + if (buf.empty()) + { + if (stream->write("\r\n") == -1) + { + format("write 1 error: %s", acl::last_serror()); + return false; + } + } + else if (stream->write(buf) == -1) + { + format("write 2 error: %s, buf(%s), len: %d", + acl::last_serror(), buf.c_str(), (int) buf.length()); + return false; + } + else if (stream->write("\r\n") == -1) + { + format("write 3 client error: %s", acl::last_serror()); + return false; + } + return true; + } + + // 基类虚函数:当接收到一个客户端请求时,调用此函数,允许 + // 子类事先对客户端连接进行处理,返回 true 表示继续,否则 + // 要求关闭该客户端连接 + virtual bool thread_on_accept(acl::socket_stream* stream) + { + format("accept one client, peer: %s, local: %s, var_cfg_io_timeout: %d\r\n", + stream->get_peer(), stream->get_local(), var_cfg_io_timeout); + if (stream->format("hello, you're welcome!\r\n") == -1) + return false; + return true; + } + + // 基类虚函数:当客户端连接关闭时调用此函数 + virtual void thread_on_close(acl::socket_stream*) + { + format("client closed now\r\n"); + } + + // 基类虚函数:当线程池创建一个新线程时调用此函数 + virtual void thread_on_init() + { +#ifdef WIN32 + format("thread init: tid: %lu\r\n", GetCurrentThreadId()); +#else + format("thread init: tid: %lu\r\n", pthread_self()); +#endif + } + + // 基类虚函数:当线程池中的一个线程退出时调用此函数 + virtual void thread_on_exit() + { +#ifdef WIN32 + format("thread exit: tid: %lu\r\n", GetCurrentThreadId()); +#else + format("thread exit: tid: %lu\r\n", pthread_self()); +#endif + } + + // 基类虚函数:服务进程切换用户身份前调用此函数 + virtual void proc_pre_jail() + { + format("proc_pre_jail\r\n"); + } + + // 基类虚函数:服务进程切换用户身份后调用此函数 + virtual void proc_on_init() + { + format("proc init\r\n"); + } + + // 基类虚函数:服务进程退出前调用此函数 + virtual void proc_on_exit() + { + format("proc exit\r\n"); + } +private: +}; + +int main(int argc, char* argv[]) +{ +#if 0 + int base = 8, nslice = 1024, nalloc_gc = 1000000; + unsigned int slice_flag = ACL_SLICE_FLAG_GC2 | ACL_SLICE_FLAG_RTGC_OFF; + + acl_mem_slice_init(base, nslice, nalloc_gc, slice_flag); +#endif + + master_threads_test mt; + + // 设置配置参数表 + mt.set_cfg_int(var_conf_int_tab); + mt.set_cfg_int64(NULL); + mt.set_cfg_str(var_conf_str_tab); + mt.set_cfg_bool(var_conf_bool_tab); + + // 开始运行 + + if (argc >= 2 && strcmp(argv[1], "alone") == 0) + { + format = (void (*)(const char*, ...)) printf; + format("listen: 127.0.0.1:8888\r\n"); + mt.run_alone("127.0.0.1:8888", NULL, 2, 10); // 单独运行方式 + } + else + mt.run_daemon(argc, argv); // acl_master 控制模式运行 + return 0; +} + diff --git a/lib_acl_cpp/samples/master_threads/master_threads.vcproj b/lib_acl_cpp/samples/master_threads/master_threads.vcproj new file mode 100644 index 000000000..cb77f07ff --- /dev/null +++ b/lib_acl_cpp/samples/master_threads/master_threads.vcproj @@ -0,0 +1,269 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_acl_cpp/samples/master_threads/stdafx.cpp b/lib_acl_cpp/samples/master_threads/stdafx.cpp new file mode 100644 index 000000000..3a8a20e11 --- /dev/null +++ b/lib_acl_cpp/samples/master_threads/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// master_threads.pch 将成为预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + +// TODO: 在 STDAFX.H 中 +//引用任何所需的附加头文件,而不是在此文件中引用 diff --git a/lib_acl_cpp/samples/master_threads/stdafx.h b/lib_acl_cpp/samples/master_threads/stdafx.h new file mode 100644 index 000000000..b98553f2c --- /dev/null +++ b/lib_acl_cpp/samples/master_threads/stdafx.h @@ -0,0 +1,11 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是常用但不常更改的项目特定的包含文件 +// + +#pragma once + + +#include +//#include + +// TODO: 在此处引用程序要求的附加头文件 diff --git a/lib_acl_cpp/samples/master_threads/valgrind.sh b/lib_acl_cpp/samples/master_threads/valgrind.sh new file mode 100644 index 000000000..5dfac7119 --- /dev/null +++ b/lib_acl_cpp/samples/master_threads/valgrind.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +valgrind --tool=memcheck --leak-check=yes -v ./master_threads alone diff --git a/lib_acl_cpp/samples/master_trigger/Makefile b/lib_acl_cpp/samples/master_trigger/Makefile new file mode 100644 index 000000000..175ddb92e --- /dev/null +++ b/lib_acl_cpp/samples/master_trigger/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = master_trigger diff --git a/lib_acl_cpp/samples/master_trigger/ReadMe.txt b/lib_acl_cpp/samples/master_trigger/ReadMe.txt new file mode 100644 index 000000000..4eb099c0a --- /dev/null +++ b/lib_acl_cpp/samples/master_trigger/ReadMe.txt @@ -0,0 +1,31 @@ +======================================================================== + 控制台应用程序 : master_trigger 项目概况 +======================================================================== + +应用程序向导已为您创建了这个 master_trigger 应用程序。 +此文件包含组成 master_trigger 应用程序 +的每个文件的内容摘要。 + + +master_trigger.vcproj + 这是用应用程序向导生成的 VC++ 项目的主项目文件。 + 它包含有关生成此文件的 Visual C++ 版本的信息,以及 + 有关用应用程序向导选择的 + 平台、配置和项目功能的信息。 + +master_trigger.cpp + 这是主应用程序源文件。 + +///////////////////////////////////////////////////////////////////////////// +其他标准文件: + +StdAfx.h、StdAfx.cpp + 这些文件用于生成名为 master_trigger.pch + 的预编译头(PCH)文件以及名为 StdAfx.obj 的预编译类型文件。 + +///////////////////////////////////////////////////////////////////////////// +其他注释: + +应用程序向导使用 "TODO:" 注释指示应添加或自定义的源代码部分。 + +///////////////////////////////////////////////////////////////////////////// diff --git a/lib_acl_cpp/samples/master_trigger/master_trigger.cpp b/lib_acl_cpp/samples/master_trigger/master_trigger.cpp new file mode 100644 index 000000000..fafe30799 --- /dev/null +++ b/lib_acl_cpp/samples/master_trigger/master_trigger.cpp @@ -0,0 +1,93 @@ +// master_trigger.cpp : 定义控制台应用程序的入口点。 +// + +#include "stdafx.h" +#include "acl_cpp/lib_acl.hpp" + +static char *var_cfg_debug_msg; + +static acl::master_str_tbl var_conf_str_tab[] = { + { "debug_msg", "test_msg", &var_cfg_debug_msg }, + + { 0, 0, 0 } +}; + +static int var_cfg_debug_enable; + +static acl::master_bool_tbl var_conf_bool_tab[] = { + { "debug_enable", 1, &var_cfg_debug_enable }, + + { 0, 0, 0 } +}; + +static int var_cfg_io_timeout; + +static acl::master_int_tbl var_conf_int_tab[] = { + { "io_timeout", 120, &var_cfg_io_timeout, 0, 0 }, + + { 0, 0 , 0 , 0, 0 } +}; + +static void (*format)(const char*, ...) = acl::log::msg1; + +////////////////////////////////////////////////////////////////////////// +using namespace acl; + +class master_trigger_test : public master_trigger +{ +public: + master_trigger_test() {} + ~master_trigger_test() {} + +protected: + // 基类纯虚函数:当触发器时间到时调用此函数 + virtual void on_trigger() + { + format("on trigger now\r\n"); + } + + // 基类虚函数:服务进程切换用户身份前调用此函数 + virtual void proc_pre_jail() + { + format("proc_pre_jail\r\n"); + } + + // 基类虚函数:服务进程切换用户身份后调用此函数 + virtual void proc_on_init() + { + format("proc init\r\n"); + } + + // 基类虚函数:服务进程退出前调用此函数 + virtual void proc_on_exit() + { + format("proc exit\r\n"); + } +protected: +private: +}; +////////////////////////////////////////////////////////////////////////// + +int main(int argc, char* argv[]) +{ + master_trigger_test mt; + + // 设置配置参数表 + mt.set_cfg_int(var_conf_int_tab); + mt.set_cfg_int64(NULL); + mt.set_cfg_str(var_conf_str_tab); + mt.set_cfg_bool(var_conf_bool_tab); + + // 开始运行 + + if (argc >= 2 && strcmp(argv[1], "alone") == 0) + { + format = (void (*)(const char*, ...)) printf; + mt.run_alone(NULL, 5, 1); // 单独运行方式 + } + else + mt.run_daemon(argc, argv); // acl_master 控制模式运行 + + return 0; +} + diff --git a/lib_acl_cpp/samples/master_trigger/master_trigger.vcproj b/lib_acl_cpp/samples/master_trigger/master_trigger.vcproj new file mode 100644 index 000000000..aaaf3f069 --- /dev/null +++ b/lib_acl_cpp/samples/master_trigger/master_trigger.vcproj @@ -0,0 +1,269 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_acl_cpp/samples/master_trigger/stdafx.cpp b/lib_acl_cpp/samples/master_trigger/stdafx.cpp new file mode 100644 index 000000000..21663c8e8 --- /dev/null +++ b/lib_acl_cpp/samples/master_trigger/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// master_trigger.pch 将成为预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + +// TODO: 在 STDAFX.H 中 +//引用任何所需的附加头文件,而不是在此文件中引用 diff --git a/lib_acl_cpp/samples/master_trigger/stdafx.h b/lib_acl_cpp/samples/master_trigger/stdafx.h new file mode 100644 index 000000000..b98553f2c --- /dev/null +++ b/lib_acl_cpp/samples/master_trigger/stdafx.h @@ -0,0 +1,11 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是常用但不常更改的项目特定的包含文件 +// + +#pragma once + + +#include +//#include + +// TODO: 在此处引用程序要求的附加头文件 diff --git a/lib_acl_cpp/samples/master_trigger/trigger.cf b/lib_acl_cpp/samples/master_trigger/trigger.cf new file mode 100644 index 000000000..5d7ab6ad4 --- /dev/null +++ b/lib_acl_cpp/samples/master_trigger/trigger.cf @@ -0,0 +1,58 @@ +# service type private unpriv chroot wakeup maxproc command + args + +service trigger +{ +# 进程是否禁止运行 + master_disable = yes +# 服务监听为域套接口 + master_service = trigger.sock +# 服务类型 + master_type = unix + +# 当子进程异常退出时,如果该值非空,则将子进程异常退出的消息通知该服务 +# master_notify_addr = 127.0.0.1:5801 +# 邮件通知接收者 +# master_notify_recipients = zhengshuxin@hotmail.com + +# 是否只允许私有访问, 如果为 y, 则域套接口创建在 {install_path}/var/log/private/ 目录下, +# 如果为 n, 则域套接口创建在 {install_path}/var/log/public/ 目录下, + master_private = y + master_unpriv = n +# 是否需要 chroot: n -- no, y -- yes + master_chroot = n +# 每隔多长时间触发一次,单位为秒(仅对 trigger 模式有效) + master_wakeup = 4 +# 最大进程数 + master_maxproc = 10 +# 进程程序名 + master_command = master_trigger +# 进程启动参数,只能为: -u [是否允许以某普通用户的身份运行] +# master_args = +# 进程日志记录文件 + master_log = {install_path}/var/log/trigger.log +# 传递给服务子进程的环境变量, 可以通过 getenv("SERVICE_ENV") 获得此值 +# master_env = logme:FALSE, priority:E_LOG_INFO, action:E_LOG_PER_DAY, flush:sync_flush, imit_size:512,\ +# sync_action:E_LOG_SEM, sem_name:/tmp/trigger.sem + +# 是否允许产生 core 文件 +# trigger_enable_core = 1 +# 每个进程实例处理连接数的最大次数,超过此值后进程实例主动退出 + trigger_use_limit = 250 +# 记录进程PID的位置(对于多进程实例来说没有意义) + trigger_pid_dir = {install_path}/var/pid +# 进程运行时所在的路径 + trigger_queue_dir = {install_path}/var +# 读写超时时间, 单位为秒 + trigger_rw_timeout = 1800 +# 读缓冲区的缓冲区大小 + trigger_buf_size = 8192 + +# 进程运行时的用户身份 + trigger_owner = owner +# 用 select 进行循环时的时间间隔 +# 单位为秒 +# trigger_delay_sec = 1 +# 单位为微秒 +# trigger_delay_usec = 5000 +# trigger_daemon_timeout = 1800 +} diff --git a/lib_acl_cpp/samples/master_trigger/valgrind.sh b/lib_acl_cpp/samples/master_trigger/valgrind.sh new file mode 100644 index 000000000..e2e1cd58c --- /dev/null +++ b/lib_acl_cpp/samples/master_trigger/valgrind.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +valgrind --tool=memcheck --leak-check=yes -v ./master_trigger alone diff --git a/lib_acl_cpp/samples/md5/Makefile b/lib_acl_cpp/samples/md5/Makefile new file mode 100644 index 000000000..47f956f92 --- /dev/null +++ b/lib_acl_cpp/samples/md5/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = md5 diff --git a/lib_acl_cpp/samples/md5/main.cpp b/lib_acl_cpp/samples/md5/main.cpp new file mode 100644 index 000000000..56c85d489 --- /dev/null +++ b/lib_acl_cpp/samples/md5/main.cpp @@ -0,0 +1,28 @@ +// md5.cpp : 定义控制台应用程序的入口点。 +// + +#include "stdafx.h" +#include +#include "acl_cpp/stdlib/md5.hpp" +#include "md5_c.h" + +int main() +{ + const char* s = "中国人民银行!"; + const char* key = "zsxxsz"; + char buf1[33], buf2[33]; + + acl::md5::md5_string(s, strlen(s), key, strlen(key), + buf1, sizeof(buf1)); + printf("first md5: %s\r\n", buf1); + + md5_string(s, key, strlen(key), buf2, sizeof(buf2)); + printf("second md5: %s\r\n", buf2); + + assert(strcmp(buf1, buf2) == 0); + +#ifdef WIN32 + getchar(); +#endif + return 0; +} diff --git a/lib_acl_cpp/samples/md5/md5.vcproj b/lib_acl_cpp/samples/md5/md5.vcproj new file mode 100644 index 000000000..f72fb43fe --- /dev/null +++ b/lib_acl_cpp/samples/md5/md5.vcproj @@ -0,0 +1,275 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_acl_cpp/samples/md5/md5.vcxproj b/lib_acl_cpp/samples/md5/md5.vcxproj new file mode 100644 index 000000000..833548e98 --- /dev/null +++ b/lib_acl_cpp/samples/md5/md5.vcxproj @@ -0,0 +1,197 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + ReleaseDll + Win32 + + + Release + Win32 + + + + {B8029C89-9870-4EE4-ADD0-E7852E0D1810} + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Use + Level3 + ProgramDatabase + + + lib_acl_vc2010d.lib;lib_acl_cpp_vc2010d.lib;%(AdditionalDependencies) + $(OutDir)md5.exe + ..\..\..\lib\win32;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)md5.pdb + Console + MachineX86 + + + + + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + Use + Level3 + ProgramDatabase + + + lib_acl_vc2010.lib;lib_acl_cpp_vc2010.lib;%(AdditionalDependencies) + $(OutDir)md5.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;ACL_CPP_DLL;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Use + Level3 + ProgramDatabase + + + $(OutDir)md5.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)md5.pdb + Console + MachineX86 + lib_acl_cpp_d.lib;%(AdditionalDependencies) + + + + + + + + + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_CPP_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreadedDLL + Use + Level3 + ProgramDatabase + + + $(OutDir)md5.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + lib_acl_cpp.lib;%(AdditionalDependencies) + + + + + + + + + + + Create + Create + Create + Create + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib_acl_cpp/samples/md5/md5.vcxproj.filters b/lib_acl_cpp/samples/md5/md5.vcxproj.filters new file mode 100644 index 000000000..56d40a1c4 --- /dev/null +++ b/lib_acl_cpp/samples/md5/md5.vcxproj.filters @@ -0,0 +1,39 @@ +锘 + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx + + + + + 婧愭枃浠 + + + 婧愭枃浠 + + + 婧愭枃浠 + + + + + 澶存枃浠 + + + 澶存枃浠 + + + + + + \ No newline at end of file diff --git a/lib_acl_cpp/samples/md5/md5_c.cpp b/lib_acl_cpp/samples/md5/md5_c.cpp new file mode 100644 index 000000000..3ebad1f2c --- /dev/null +++ b/lib_acl_cpp/samples/md5/md5_c.cpp @@ -0,0 +1,292 @@ +/* MS VisualStudio Projects are monolithic, so we need the following + * #if to exclude the MD5 code from compile process when we are + * building the SSL support. + */ +#include "stdafx.h" +#include +#include +#include "md5_c.h" +#include + +#ifdef WORDS_BIGENDIAN +void byteSwap(uint32_t * buf, unsigned words) +{ + uint8_t *p = (uint8_t *) buf; + + do { + *buf++ = (uint32_t) ((unsigned) p[3] << 8 | p[2]) << 16 | + ((unsigned) p[1] << 8 | p[0]); + p += 4; + } while (--words); +} +#else +#define byteSwap(buf,words) +#endif + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +void md5_init(md5_ctx *ctx) +{ + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bytes[0] = 0; + ctx->bytes[1] = 0; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void md5_update(md5_ctx *ctx, const void *_buf, unsigned len) +{ + const uint8_t *buf = (const uint8_t *) _buf; + uint32_t t; + + /* Update byte count */ + + t = ctx->bytes[0]; + if ((ctx->bytes[0] = t + len) < t) + ctx->bytes[1]++; /* Carry from low to high */ + + t = 64 - (t & 0x3f); /* Space available in ctx->in (at least 1) */ + if (t > len) { + memcpy((uint8_t *) ctx->in + 64 - t, buf, len); + return; + } + /* First chunk is an odd size */ + memcpy((uint8_t *) ctx->in + 64 - t, buf, t); + byteSwap(ctx->in, 16); + md5_transform(ctx->buf, ctx->in); + buf += t; + len -= t; + + /* Process data in 64-byte chunks */ + while (len >= 64) { + memcpy(ctx->in, buf, 64); + byteSwap(ctx->in, 16); + md5_transform(ctx->buf, ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + memcpy(ctx->in, buf, len); +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +void md5_final(unsigned char digest[16], md5_ctx *ctx) +{ + int count = ctx->bytes[0] & 0x3f; /* Number of bytes in ctx->in */ + uint8_t *p = (uint8_t *) ctx->in + count; + + /* Set the first char of padding to 0x80. There is always room. */ + *p++ = 0x80; + + /* Bytes of padding needed to make 56 bytes (-8..55) */ + count = 56 - 1 - count; + + if (count < 0) { /* Padding forces an extra block */ + memset(p, 0, count + 8); + byteSwap(ctx->in, 16); + md5_transform(ctx->buf, ctx->in); + p = (uint8_t *) ctx->in; + count = 56; + } + memset(p, 0, count); + byteSwap(ctx->in, 14); + + /* Append length in bits and transform */ + ctx->in[14] = ctx->bytes[0] << 3; + ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29; + md5_transform(ctx->buf, ctx->in); + + byteSwap(ctx->buf, 4); + memcpy(digest, ctx->buf, 16); + memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ +} + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f,w,x,y,z,in,s) \ + (w += f(x,y,z) + in, w = (w<>(32-s)) + x) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +void md5_transform(uint32_t buf[4], uint32_t const in[16]) +{ + register uint32_t a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +const char* md5_key(const char *s, size_t s_len, const char *k, size_t len, + void* buf, size_t size) +{ + md5_ctx context; + unsigned char digest[16]; + + assert(size >= 16); + + md5_init(&context); + if (k != NULL && len > 0) + md5_update(&context, (const unsigned char *) k, (unsigned int) len); + md5_update(&context, (const unsigned char*) s, (unsigned int) s_len); + md5_final(digest, &context); + memcpy(buf, digest, size); + return ((const char*) buf); +} + +const char* md5_string(const char *s, const char *k, size_t klen, + char* buf, size_t size) +{ + md5_ctx context; + unsigned char digest[16]; + char output1[34], *ptr; + unsigned int len = (unsigned int) strlen(s); + size_t i, n; + + md5_init(&context); + if (k != NULL && klen > 0) + md5_update(&context, (const unsigned char *) k, (unsigned int) klen); + md5_update(&context, (const unsigned char*) s, len); + md5_final(digest, &context); + + for (i = 0; i < 16; i++) { + sprintf(&(output1[2 * i]), "%02x", (unsigned char) digest[i]); + sprintf(&(output1[2 * i + 1]), "%02x", + (unsigned char) (digest[i] << 4)); + } + + ptr = buf; + size--; /* left one byte for '\0' */ + n = size > 32 ? 32 : size; + + for(i = 0; i < n; i++) + *ptr++ = output1[i]; + *ptr = '\0'; + + return (buf); +} + +const char* md5_key2string(const unsigned char *s, size_t s_len, + char* buf, size_t size) +{ + size_t i, n; + char output1[34], *ptr; + unsigned char digest[16]; + + assert(s_len == 16); + assert(size >= 32); + memcpy(digest, s, 16); + + for (i = 0; i < 16; i++) { + sprintf(&(output1[2 * i]), "%02x", (unsigned char) digest[i]); + sprintf(&(output1[2 * i + 1]), "%02x", + (unsigned char) (digest[i] << 4)); + } + + ptr = buf; + size--; /* left one byte for '\0' */ + n = size > 32 ? 32 : size; + + for(i = 0; i < n; i++) + *ptr++ = output1[i]; + *ptr = '\0'; + + return (buf); +} + diff --git a/lib_acl_cpp/samples/md5/md5_c.h b/lib_acl_cpp/samples/md5/md5_c.h new file mode 100644 index 000000000..7a4796241 --- /dev/null +++ b/lib_acl_cpp/samples/md5/md5_c.h @@ -0,0 +1,23 @@ +#pragma once + +#include + +typedef unsigned int uint32_t; +typedef unsigned char uint8_t; + +typedef struct md5_ctx { + uint32_t buf[4]; + uint32_t bytes[2]; + uint32_t in[16]; +} md5_ctx; + +void md5_init(md5_ctx *context); +void mf5_update(md5_ctx *context, const void *buf, unsigned len); +void md5_final(uint8_t digest[16], md5_ctx *context); +void md5_transform(uint32_t buf[4], uint32_t const in[16]); +const char* md5_key(const char *s, size_t s_len, const char *k, size_t len, + void* buf, size_t size); +const char* md5_string(const char *s, const char *k, size_t len, + char* buf, size_t size); +const char* md5_key2string(const unsigned char *s, size_t len, + char* buf, size_t size); diff --git a/lib_acl_cpp/samples/md5/md5_vc2012.vcxproj b/lib_acl_cpp/samples/md5/md5_vc2012.vcxproj new file mode 100644 index 000000000..cc2ab922e --- /dev/null +++ b/lib_acl_cpp/samples/md5/md5_vc2012.vcxproj @@ -0,0 +1,202 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + ReleaseDll + Win32 + + + Release + Win32 + + + + {B8029C89-9870-4EE4-ADD0-E7852E0D1810} + Win32Proj + md5 + + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Use + Level3 + ProgramDatabase + + + lib_acl_vc2012d.lib;lib_acl_cpp_vc2012d.lib;%(AdditionalDependencies) + $(OutDir)md5.exe + ..\..\..\lib\win32;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)md5.pdb + Console + MachineX86 + + + + + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + Use + Level3 + ProgramDatabase + + + lib_acl_vc2012.lib;lib_acl_cpp_vc2012.lib;%(AdditionalDependencies) + $(OutDir)md5.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;ACL_CPP_DLL;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Use + Level3 + ProgramDatabase + + + $(OutDir)md5.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)md5.pdb + Console + MachineX86 + lib_acl_cpp_d.lib;%(AdditionalDependencies) + + + + + + + + + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_CPP_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreadedDLL + Use + Level3 + ProgramDatabase + + + $(OutDir)md5.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + lib_acl_cpp.lib;%(AdditionalDependencies) + + + + + + + + + + + Create + Create + Create + Create + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib_acl_cpp/samples/md5/stdafx.cpp b/lib_acl_cpp/samples/md5/stdafx.cpp new file mode 100644 index 000000000..e02fe9e86 --- /dev/null +++ b/lib_acl_cpp/samples/md5/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// md5.pch 将成为预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + +// TODO: 在 STDAFX.H 中 +//引用任何所需的附加头文件,而不是在此文件中引用 diff --git a/lib_acl_cpp/samples/md5/stdafx.h b/lib_acl_cpp/samples/md5/stdafx.h new file mode 100644 index 000000000..9024458d0 --- /dev/null +++ b/lib_acl_cpp/samples/md5/stdafx.h @@ -0,0 +1,11 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是常用但不常更改的项目特定的包含文件 +// + +#pragma once + + +//#include +//#include + +// TODO: 在此处引用程序要求的附加头文件 diff --git a/lib_acl_cpp/samples/md5/valgrind.sh b/lib_acl_cpp/samples/md5/valgrind.sh new file mode 100644 index 000000000..e34108cff --- /dev/null +++ b/lib_acl_cpp/samples/md5/valgrind.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +valgrind --tool=memcheck --leak-check=yes -v ./md5 diff --git a/lib_acl_cpp/samples/mem_cache/Makefile b/lib_acl_cpp/samples/mem_cache/Makefile new file mode 100644 index 000000000..ed16e47f9 --- /dev/null +++ b/lib_acl_cpp/samples/mem_cache/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = mem_cache diff --git a/lib_acl_cpp/samples/mem_cache/main.cpp b/lib_acl_cpp/samples/mem_cache/main.cpp new file mode 100644 index 000000000..6d74b878f --- /dev/null +++ b/lib_acl_cpp/samples/mem_cache/main.cpp @@ -0,0 +1,224 @@ +#include "lib_acl.h" +#include "acl_cpp/memcache/memcache.hpp" +#include "acl_cpp/stdlib/string.hpp" +#include +#include +#include + +static time_t __timeout = 100; +static const char* __key = "test"; + +static void usage(const char* procname) +{ + printf("usage: %s -h[help] -l addr -g[get] -s[set] -d[del] -m[update timeout] -n num -t timeout -T nthread\n", procname); +} + +static void get(const char* addr, int id, int num) +{ + acl::mem_cache client(addr); + acl::string buf, key; + int i; + + client.set_prefix(__key); + + for (i = 0; i < num; i++) + { + key.format("key:%d:%d", id, i); + if (client.get(key.c_str(), buf) == false) + break; + if (i <= 100) + printf("GET: %s, %s\n", key.c_str(), buf.c_str()); + if (i % 10000 == 0) + { + char tmp[256]; + snprintf(tmp, sizeof(tmp), "GET, i: %d, num: %d", i, num); + ACL_METER_TIME(tmp); + } + } + printf("OVER: total: %d\n", i); +} + +static void mod(const char* addr, int id, int num) +{ + acl::mem_cache client(addr); + acl::string key; + int i; + + client.set_prefix(__key); + + for (i = 0; i < num; i++) + { + key.format("key:%d:%d", id, i); + if (client.set(key.c_str(), __timeout) == false) + break; + if (i <= 100) + printf("UPDATE: %s, timeout: %d\n", key.c_str(), (int) __timeout); + if (i % 10000 == 0) + { + char tmp[256]; + snprintf(tmp, sizeof(tmp), "SET, i: %d, num: %d\n", i, num); + ACL_METER_TIME(tmp); + } + } + printf("OVER: total: %d\n", i); +} + +static void set(const char* addr, int id, int num) +{ + acl::mem_cache client(addr); + acl::string buf, key; + int i; + + client.set_prefix(__key); + + for (i = 0; i < num; i++) + { + key.format("key:%d:%d", id, i); + buf.format("dat:%d, sp( ), tab(\t), eq(=);", i); + if (client.set(key.c_str(), buf, buf.length(), __timeout) == false) + { + printf("SET error: %s\n", client.last_serror()); + break; + } + if (i <= 100) + printf("SET: %s\n", key.c_str()); + if (i % 10000 == 0) + { + char tmp[256]; + snprintf(tmp, sizeof(tmp), "SET, i: %d, num: %d, timeout: %d", + i, num, (int) __timeout); + ACL_METER_TIME(tmp); + } + } + client.property_list(); + printf("OVER: total: %d, timeout: %d\n", i, (int) __timeout); +} + +static void del(const char* addr, int id, int num) +{ + acl::mem_cache client(addr); + acl::string key; + int i; + + client.set_prefix(__key); + + for (i = 0; i < num; i++) + { + key.format("key:%d:%d", id, i); + if (client.del(key.c_str()) == false) + break; + if (i <= 100) + printf("DEL: %s\n", key.c_str()); + if (i % 10000 == 0) + { + char tmp[256]; + snprintf(tmp, sizeof(tmp), "DEL, i: %d, num: %d", i, num); + ACL_METER_TIME(tmp); + } + } + printf("OVER: total: %d\n", i); +} + +typedef struct +{ + void (*fn)(const char* addr, int id, int num); + int id; + int num; + const char* addr; +} CTX; + +static void thread_main(void *arg) +{ + CTX *ctx = (CTX*) arg; + + ctx->fn(ctx->addr, ctx->id, ctx->num); + acl_myfree(ctx); +} + +static void test1(void) +{ + acl::mem_cache client("127.0.0.1:16815", 180, 300); + acl::string buf, key("F6B7AB8F24790F6224DEC0D674FFAC4D"); + + client.set_prefix("WEBMAIL").auto_retry(false).encode_key(false); + + if (client.get(key.c_str(), buf) == false) + printf("error\r\n"); + else + printf("ok\r\n"); + exit(0); +} + +int main(int argc, char* argv[]) +{ + if (0) + test1(); + + int ch, num = 10, nthread = 1; + char addr[256]; + void (*func)(const char* addr, int id, int num) = NULL; + + snprintf(addr, sizeof(addr), "127.0.0.1:11211"); + + while ((ch = getopt(argc, argv, "hl:gsdmn:t:T:")) > 0) + { + switch (ch) + { + case 'h': + usage(argv[0]); + return (0); + case 'l': + snprintf(addr, sizeof(addr), "%s", optarg); + break; + case 'g': + func = get; + break; + case 's': + func = set; + break; + case 'm': + func = mod; + break; + case 'd': + func = del; + break; + case 'n': + num = atoi(optarg); + break; + case 't': + __timeout = atoi(optarg); + break; + case 'T': + nthread = atoi(optarg); + break; + default: + break; + } + } + + printf("server: %s\n", addr); + + if (func == NULL) + usage(argv[0]); + else + { + if (nthread <= 1) + func(addr, 0, num); + else + { + acl_pthread_pool_t* pool = acl_thread_pool_create(nthread, 100); + for (int i = 0; i < nthread; i++) + { + CTX* ctx = (CTX*) acl_mycalloc(1, sizeof(CTX)); + ctx->fn = func; + ctx->addr = addr; + ctx->num = num; + ctx->id = i; + acl_pthread_pool_add(pool, thread_main, ctx); + } + + acl_pthread_pool_destroy(pool); + } + } + return (0); +} diff --git a/lib_acl_cpp/samples/mem_cache/valgrind.sh b/lib_acl_cpp/samples/mem_cache/valgrind.sh new file mode 100644 index 000000000..db02057e7 --- /dev/null +++ b/lib_acl_cpp/samples/mem_cache/valgrind.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +valgrind --track-origins=yes --tool=memcheck --leak-check=yes -v ./mem_cache -g -n 10 diff --git a/lib_acl_cpp/samples/memcache_pool/Makefile b/lib_acl_cpp/samples/memcache_pool/Makefile new file mode 100644 index 000000000..240926676 --- /dev/null +++ b/lib_acl_cpp/samples/memcache_pool/Makefile @@ -0,0 +1,3 @@ +include ../Makefile.in +LDFLAGS += -lz +PROG = memcache_pool diff --git a/lib_acl_cpp/samples/memcache_pool/main.cpp b/lib_acl_cpp/samples/memcache_pool/main.cpp new file mode 100644 index 000000000..262282bcf --- /dev/null +++ b/lib_acl_cpp/samples/memcache_pool/main.cpp @@ -0,0 +1,138 @@ +#include "stdafx.h" + +using namespace acl; + +static int __loop_count = 10; +static connect_pool* __conn_pool = NULL; +static acl_pthread_pool_t* __thr_pool = NULL; + +// 初始化过程 +static void init(const char* addr, int count) +{ + // 创建 HTTP 请求连接池对象 + __conn_pool = new memcache_pool(addr, count); + + // 创建线程池 + __thr_pool = acl_thread_pool_create(count, 60); +} + +// 进程退出前清理资源 +static void end(void) +{ + // 销毁线程池 + acl_pthread_pool_destroy(__thr_pool); + + // 销毁连接池 + delete __conn_pool; +} + +// MEMCACHE 请求过程,向服务器发送请求后从服务器读取响应数据 +static bool memcache_get(memcache* conn, const char* key) +{ + string buf; + + if (conn->get(key, buf) == false) + { + printf("get key: %s error\r\n", key); + return false; + } + + return true; +} + +// 线程处理过程 +static void thread_main(void* ctx) +{ + char* key = (char*) ctx; + + for (int i = 0; i < __loop_count; i++) + { + // 从连接池中获取一个 HTTP 连接 + memcache* conn = (memcache*) __conn_pool->peek(); + if (conn == NULL) + { + printf("peek connect failed\r\n"); + break; + } + + // 开始新的 HTTP 请求过程 + if (memcache_get(conn, key) == false) + { + printf("one request failed, close connection\r\n"); + // 错误连接需要关闭 + __conn_pool->put(conn, false); + } + else + __conn_pool->put(conn, true); + if (i % 1000 == 0) + printf("%lu--%d: read body over\r\n", acl_pthread_self(), i); + } +} + +static void run(int cocurrent, char* key) +{ + // 向线程池中添加任务 + for (int i = 0; i < cocurrent; i++) + acl_pthread_pool_add(__thr_pool, thread_main, key); +} + +static void usage(const char* procname) +{ + printf("usage: %s -h [help]\r\n" + " -s memcache_server_addr [127.0.0.1:11211\r\n" + " -k key\r\n" + " -c cocurrent [default: 10]\r\n" + " -n loop_count[default: 10]\r\n", procname); +} + +int main(int argc, char* argv[]) +{ + int ch, cocurrent = 10; + string addr("127.0.0.1:11211"); + string key; + + // 初始化 acl 库 + acl::acl_cpp_init(); + + while ((ch = getopt(argc, argv, "hs:n:c:k:")) > 0) + { + switch (ch) + { + case 'h': + usage(argv[0]); + return 0; + case 's': + addr = optarg; + break; + case 'c': + cocurrent = atoi(optarg); + break; + case 'n': + __loop_count = atoi(optarg); + break; + case 'k': + key = optarg; + break; + default: + usage(argv[0]); + return 0; + } + } + + if (key.empty()) + { + usage(argv[0]); + return 0; + } + + init(addr, cocurrent); + run(cocurrent, key.c_str()); + end(); + +#ifdef WIN32 + printf("enter any key to exit...\r\n"); + getchar(); +#endif + + return 0; +} diff --git a/lib_acl_cpp/samples/memcache_pool/memcache_pool.vcproj b/lib_acl_cpp/samples/memcache_pool/memcache_pool.vcproj new file mode 100644 index 000000000..8a73b5170 --- /dev/null +++ b/lib_acl_cpp/samples/memcache_pool/memcache_pool.vcproj @@ -0,0 +1,279 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_acl_cpp/samples/memcache_pool/memcache_pool_vc2012.vcxproj b/lib_acl_cpp/samples/memcache_pool/memcache_pool_vc2012.vcxproj new file mode 100644 index 000000000..96791e763 --- /dev/null +++ b/lib_acl_cpp/samples/memcache_pool/memcache_pool_vc2012.vcxproj @@ -0,0 +1,199 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + ReleaseDll + Win32 + + + Release + Win32 + + + + {1F3F3884-7F9B-4BA1-8CA3-61E6758A7193} + Win32Proj + memcache_pool + + + + Application + v110 + MultiByte + + + Application + v110 + MultiByte + + + Application + v110 + MultiByte + + + Application + v110 + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>11.0.50727.1 + + + Debug\ + Debug\ + true + + + Release\ + Release\ + false + + + $(Configuration)\ + $(Configuration)\ + false + + + $(Configuration)\ + $(Configuration)\ + true + + + + Disabled + ..\..\..\lib_acl_cpp\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Use + Level3 + EditAndContinue + + + lib_acl_cpp_vc2012d.lib;lib_acl_vc2012d.lib;lib_protocol_vc2012d.lib;%(AdditionalDependencies) + $(OutDir)memcache_pool.exe + ..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)memcache_pool.pdb + Console + MachineX86 + false + + + + + ..\..\..\lib_acl_cpp\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + Use + Level3 + ProgramDatabase + + + lib_acl_cpp_vc2012.lib;lib_acl_vc2012.lib;lib_protocol_vc2012.lib;%(AdditionalDependencies) + $(OutDir)memcache_pool.exe + ..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + + + + + ..\..\..\lib_acl_cpp\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_CPP_DLL;%(PreprocessorDefinitions) + MultiThreadedDLL + Use + Level3 + ProgramDatabase + + + lib_acl_cpp_dll.lib;lib_acl.lib;lib_protocol.lib;%(AdditionalDependencies) + $(OutDir)memcache_pool.exe + ..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + + + copy ..\..\..\dist\lib\win32\lib_acl.dll $(OutDir) /Y +copy ..\..\..\dist\lib\win32\lib_acl_cpp_dll.dll $(OutDir) /Y +copy ..\..\..\dist\lib\win32\lib_protocol.dll $(OutDir) /Y + + + + + Disabled + ..\..\..\lib_acl_cpp\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_CPP_DLL;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Use + Level3 + EditAndContinue + + + lib_acl_cppd_dll.lib;lib_acl_d.lib;lib_protocol_d.lib;%(AdditionalDependencies) + $(OutDir)memcache_pool.exe + ..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)memcache_pool.pdb + Console + MachineX86 + + + copy ..\..\..\dist\lib\win32\lib_acl_d.dll $(OutDir) /Y +copy ..\..\..\dist\lib\win32\lib_acl_cppd_dll.dll $(OutDir) /Y +copy ..\..\..\dist\lib\win32\lib_protocol_d.dll $(OutDir) /Y + + + + + + Create + Create + Create + Create + + + + + + + + + + + + \ No newline at end of file diff --git a/lib_acl_cpp/samples/memcache_pool/memcache_pool_vc2012.vcxproj.filters b/lib_acl_cpp/samples/memcache_pool/memcache_pool_vc2012.vcxproj.filters new file mode 100644 index 000000000..9618f1e58 --- /dev/null +++ b/lib_acl_cpp/samples/memcache_pool/memcache_pool_vc2012.vcxproj.filters @@ -0,0 +1,33 @@ +锘 + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx + + + + + 婧愭枃浠 + + + 婧愭枃浠 + + + + + 澶存枃浠 + + + + + + \ No newline at end of file diff --git a/lib_acl_cpp/samples/memcache_pool/stdafx.cpp b/lib_acl_cpp/samples/memcache_pool/stdafx.cpp new file mode 100644 index 000000000..3a8a20e11 --- /dev/null +++ b/lib_acl_cpp/samples/memcache_pool/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// master_threads.pch 将成为预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + +// TODO: 在 STDAFX.H 中 +//引用任何所需的附加头文件,而不是在此文件中引用 diff --git a/lib_acl_cpp/samples/memcache_pool/stdafx.h b/lib_acl_cpp/samples/memcache_pool/stdafx.h new file mode 100644 index 000000000..c33ad33cd --- /dev/null +++ b/lib_acl_cpp/samples/memcache_pool/stdafx.h @@ -0,0 +1,19 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是常用但不常更改的项目特定的包含文件 +// + +#pragma once + + +//#include +//#include + +// TODO: 在此处引用程序要求的附加头文件 + +#include "lib_acl.h" +#include "acl_cpp/lib_acl.hpp" + +#ifdef WIN32 +#define snprintf _snprintf +#endif + diff --git a/lib_acl_cpp/samples/memcache_pool/valgrind.sh b/lib_acl_cpp/samples/memcache_pool/valgrind.sh new file mode 100644 index 000000000..e47a4a57a --- /dev/null +++ b/lib_acl_cpp/samples/memcache_pool/valgrind.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +valgrind --tool=memcheck --leak-check=yes -v ./memcache_pool -c 2 -n 2 diff --git a/lib_acl_cpp/samples/mime/Makefile b/lib_acl_cpp/samples/mime/Makefile new file mode 100644 index 000000000..6abfc532a --- /dev/null +++ b/lib_acl_cpp/samples/mime/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = mime diff --git a/lib_acl_cpp/samples/mime/ReadMe.txt b/lib_acl_cpp/samples/mime/ReadMe.txt new file mode 100644 index 000000000..6705b5521 --- /dev/null +++ b/lib_acl_cpp/samples/mime/ReadMe.txt @@ -0,0 +1,31 @@ +======================================================================== + 控制台应用程序 : mime 项目概况 +======================================================================== + +应用程序向导已为您创建了这个 mime 应用程序。 +此文件包含组成 mime 应用程序 +的每个文件的内容摘要。 + + +mime.vcproj + 这是用应用程序向导生成的 VC++ 项目的主项目文件。 + 它包含有关生成此文件的 Visual C++ 版本的信息,以及 + 有关用应用程序向导选择的 + 平台、配置和项目功能的信息。 + +mime.cpp + 这是主应用程序源文件。 + +///////////////////////////////////////////////////////////////////////////// +其他标准文件: + +StdAfx.h、StdAfx.cpp + 这些文件用于生成名为 mime.pch + 的预编译头(PCH)文件以及名为 StdAfx.obj 的预编译类型文件。 + +///////////////////////////////////////////////////////////////////////////// +其他注释: + +应用程序向导使用 "TODO:" 注释指示应添加或自定义的源代码部分。 + +///////////////////////////////////////////////////////////////////////////// diff --git a/lib_acl_cpp/samples/mime/email12.eml b/lib_acl_cpp/samples/mime/email12.eml new file mode 100644 index 000000000..f442d4b76 --- /dev/null +++ b/lib_acl_cpp/samples/mime/email12.eml @@ -0,0 +1,635 @@ +S +X-Uidl: 1279858190.4190_3.localhost&&mail.51iker.com +Return-Path: +Delivered-To: all1@51iker.com +Received: from SKY-20100331OBQ (unknown [123.122.99.3]) + by 51iker.com (ikmail) with ESMTP id 125B1343207; + Fri, 23 Jul 2010 12:09:49 +0800 (CST) +Date: Fri, 23 Jul 2010 12:06:22 +0800 +From: "=?gb2312?B?yMvBptfK1LSyvw==?=" +To: "all1" , "all2" , + "all3" +Subject: =?gb2312?B?zajWqg==?= +Message-ID: <201007231206178906633@51iker.com> +X-mailer: Foxmail 6, 15, 201, 22 [cn] +Mime-Version: 1.0 +Content-Type: multipart/related; + boundary="=====002_Dragon224480308877_====="; + type="multipart/alternative" +X-Csmail-Path: elaowange@gmail.comelaowange@gmail.comelaowange@gmail.com83622990@qq.comelaowange@gmail.comlike51iker@163.comelaowange@gmail.comelaowange@gmail.comlike51iker@163.com +This is a multi-part message in MIME format. +--=====002_Dragon224480308877_===== +Content-Type: multipart/alternative; + boundary="=====003_Dragon224480308877_=====" +--=====003_Dragon224480308877_===== +Content-Type: text/plain; + charset="gb2312" +Content-Transfer-Encoding: base64 +DQoNCg0KIA0KuPfOu82s0aejug0KDQogICAgICDTydPauavLvsewts7Ksbzks/bP1rn91dXD97XI +tefG98noyqnU2s7eyMvKsbryv6rG9KOsz8Kw4MqxvOTDxbSwzrS52LXI0tey+sn6sLLIq9L+u7zA +4M7KzOKjrA0KDQq5yrmry77X9rP2yOfPwrnmtqihow0KICAgIA0KICAgICAxLs/CsOC688frudix +1bj2yMu158TUtefUtLXI0rvH0LXnxvfJ6MqpoaMNCiAgICAgDQogICAgMi7I59P2tb2807Dgu/LM +2Mriz8Kw4MqxvOSjrMfr1+6689K7uPbA67+quavLvrXEzazRp9fUvvW9q8PFtLC52LrDo6zS+8uu +u/q159S0sM619KOsv9W197nYDQoNCrHVoaMNCg0KICAgINLyztKyv8PF1NrDv8zsz8Kw4Lrzu+G9 +q8v509DTw7XnyeixuLyw1dXD98noyqm4utTwudix1aOsy/nS1NDovNOw4LXEzazRp9TZtM7KudPD +x+vSu7aovavS1MnPDQoNCsv50qrH88rCz+64utTwudix1aOswOvLvsqxyLexo7mry76088PFudix +1brD1NnA67+qoaMNCg0KICAgIMjns/bP1s7eyMvH6b/2yrGjrMPFtLC158b3zrS52LHVo6y+rbn9 +tfey6brLyrW686OstbHKwsjLvau0ptLUNTDUqrejv+7S1Mq+vq/KvqGjDQoNCjIwMTAtMDctMjMg +DQoNCg0KDQrIy8Gm18rUtLK/IA0K +--=====003_Dragon224480308877_===== +Content-Type: text/html; + charset="gb2312" +Content-Transfer-Encoding: base64 +PCFET0NUWVBFIEhUTUwgUFVCTElDICItLy9XM0MvL0RURCBIVE1MIDQuMCBUcmFuc2l0aW9uYWwv +L0VOIj4NCjxIVE1MIHhtbG5zOm8gPSAidXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTpvZmZpY2U6 +b2ZmaWNlIj48SEVBRD4NCjxNRVRBIGh0dHAtZXF1aXY9Q29udGVudC1UeXBlIGNvbnRlbnQ9InRl +eHQvaHRtbDsgY2hhcnNldD1nYjIzMTIiPg0KPFNUWUxFIHR5cGU9dGV4dC9jc3M+Qk9EWSB7DQoJ +UEFERElORy1SSUdIVDogMHB4OyBQQURESU5HLUxFRlQ6IDBweDsgUEFERElORy1CT1RUT006IDBw +eDsgTUFSR0lOOiAwcHg7IFBBRERJTkctVE9QOiAwcHgNCn0NCkJMT0NLUVVPVEUgew0KCU1BUkdJ +Ti1UT1A6IDBweDsgTUFSR0lOLUJPVFRPTTogMHB4OyBNQVJHSU4tTEVGVDogMmVtDQp9DQpPTCB7 +DQoJTUFSR0lOLVRPUDogMHB4OyBNQVJHSU4tQk9UVE9NOiAwcHgNCn0NClVMIHsNCglNQVJHSU4t +VE9QOiAwcHg7IE1BUkdJTi1CT1RUT006IDBweA0KfQ0KPC9TVFlMRT4NCg0KPE1FVEEgY29udGVu +dD0iTVNIVE1MIDYuMDAuMjkwMC41OTQ1IiBuYW1lPUdFTkVSQVRPUj48L0hFQUQ+DQo8Qk9EWSBz +dHlsZT0iTUFSR0lOLVRPUDogMHB4OyBNQVJHSU4tTEVGVDogMHB4OyBNQVJHSU4tUklHSFQ6IDBw +eCI+PCEtLSA1Ml8zMDI5MDNfZTExNDE1ZjEyNjc4MWJmIC0tPg0KPFRBQkxFIGlkPVRhYmxlXzAx +IA0Kc3R5bGU9IkJBQ0tHUk9VTkQ6ICNmZmY7IEZPTlQtRkFNSUxZOiBWZXJkYW5hLCBBcmlhbCwg +SGVsdmV0aWNhLCBzYW5zLXNlcmlmIiANCmNlbGxTcGFjaW5nPTAgY2VsbFBhZGRpbmc9MCB3aWR0 +aD0iOTkuOTklIiBib3JkZXI9MD4NCiAgPFRCT0RZPg0KICA8VFI+DQogICAgPFREIHZBbGlnbj10 +b3AgYmFja2dyb3VuZD1jaWQ6X18xQEZveG1haWwubmV0PjxJTUcgaGVpZ2h0PTEgDQogICAgICBz +cmM9ImNpZDpfXzBARm94bWFpbC5uZXQiIHdpZHRoPTQ5PjwvVEQ+DQogICAgPFREIHZBbGlnbj10 +b3AgYmFja2dyb3VuZD1jaWQ6X18yQEZveG1haWwubmV0Pg0KICAgICAgPFRBQkxFIGNlbGxTcGFj +aW5nPTAgY2VsbFBhZGRpbmc9MCB3aWR0aD04NyBib3JkZXI9MD4NCiAgICAgICAgPFRCT0RZPg0K +ICAgICAgICA8VFI+DQogICAgICAgICAgPFREIGJhY2tncm91bmQ9Y2lkOl9fMTBARm94bWFpbC5u +ZXQ+PElNRyBoZWlnaHQ9NTAgDQogICAgICAgICAgICBzcmM9ImNpZDpfXzBARm94bWFpbC5uZXQi +IHdpZHRoPTg3PjwvVEQ+PC9UUj48L1RCT0RZPjwvVEFCTEU+PC9URD4NCiAgICA8VEQgdkFsaWdu +PXRvcCBiYWNrZ3JvdW5kPWNpZDpfXzNARm94bWFpbC5uZXQ+PElNRyBoZWlnaHQ9NTAgDQogICAg +ICBzcmM9ImNpZDpfXzBARm94bWFpbC5uZXQiIHdpZHRoPTg0PjwvVEQ+PC9UUj4NCiAgPFRSPg0K +ICAgIDxURCB2QWxpZ249dG9wIGFsaWduPXJpZ2h0IGJhY2tncm91bmQ9Y2lkOl9fNEBGb3htYWls +Lm5ldD4NCiAgICAgIDxUQUJMRSBjZWxsU3BhY2luZz0wIGNlbGxQYWRkaW5nPTAgd2lkdGg9NTAg +Ym9yZGVyPTA+DQogICAgICAgIDxUQk9EWT4NCiAgICAgICAgPFRSPg0KICAgICAgICAgIDxURCBi +YWNrZ3JvdW5kPWNpZDpfXzExQEZveG1haWwubmV0PjxJTUcgaGVpZ2h0PTEzNCANCiAgICAgICAg +ICAgIHNyYz0iY2lkOl9fMEBGb3htYWlsLm5ldCIgd2lkdGg9NDk+PC9URD48L1RSPjwvVEJPRFk+ +PC9UQUJMRT48L1REPg0KICAgIDxURCANCiAgICBzdHlsZT0iUEFERElORy1SSUdIVDogNTBweDsg +QkFDS0dST1VORC1QT1NJVElPTjogcmlnaHQgYm90dG9tOyBQQURESU5HLUxFRlQ6IDQwcHg7IFBB +RERJTkctQk9UVE9NOiA2MHB4OyBQQURESU5HLVRPUDogNDBweDsgQkFDS0dST1VORC1SRVBFQVQ6 +IG5vLXJlcGVhdDsgSEVJR0hUOiAzMDBweCIgDQogICAgdkFsaWduPXRvcCB3aWR0aD0iMTAwJSIg +YmFja2dyb3VuZD1jaWQ6X181QEZveG1haWwubmV0IGJnQ29sb3I9I2ZmZmNmMz4NCiAgICAgIDxU +QUJMRSBzdHlsZT0iTUFSR0lOLVRPUDogMHB4OyBjZWxscGFkZGluZzogMHB4OyBjZWxsc3BhY2lu +ZzogMHB4IiANCiAgICAgIHdpZHRoPSIxMDAlIiB2YWxpZ249InRvcCI+DQogICAgICAgIDxUQk9E +WT4NCiAgICAgICAgPFRSPg0KICAgICAgICAgIDxURCBzdHlsZT0iTElORS1IRUlHSFQ6IDE2MCUi +Pg0KICAgICAgICAgICAgPERJViANCiAgICAgICAgICAgIHN0eWxlPSJXSURUSDogMTAwJTsgV09S +RC1CUkVBSzogYnJlYWstYWxsOyBXSElURS1TUEFDRTogbm9ybWFsIj48Rk9OVCANCiAgICAgICAg +ICAgIGZhY2U9VmVyZGFuYSBjb2xvcj0jMDAwMDgwIHNpemU9Mj4NCiAgICAgICAgICAgIDxESVY+ +DQogICAgICAgICAgICA8RElWPjxGT05UIHNpemU9Mz48L0ZPTlQ+PC9ESVY+PEZPTlQgY29sb3I9 +IzAwMDAwMCANCiAgICAgICAgICAgIHNpemU9ND4mbmJzcDs8L0ZPTlQ+PC9ESVY+DQogICAgICAg +ICAgICA8RElWPjxGT05UIGNvbG9yPSNjMGMwYzA+DQogICAgICAgICAgICA8RElWPjxGT05UIGNv +bG9yPSMwMDAwMDAgc2l6ZT00Prj3zrvNrNGno7o8L0ZPTlQ+PC9ESVY+DQogICAgICAgICAgICA8 +RElWPjxGT05UIGNvbG9yPSMwMDAwMDAgc2l6ZT00PjwvRk9OVD4mbmJzcDs8L0RJVj4NCiAgICAg +ICAgICAgIDxESVY+PEZPTlQgY29sb3I9IzAwMDAwMCANCiAgICAgICAgICAgIHNpemU9ND4mbmJz +cDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDvTydPauavLvsewts7Ksbzks/bP1rn91dXD +97XItefG98noyqnU2s7eyMvKsbryv6rG9KOsz8Kw4MqxvOTDxbSwzrS52LXI0tey+sn6sLLIq9L+ +u7zA4M7KzOKjrDwvRk9OVD48L0RJVj4NCiAgICAgICAgICAgIDxESVY+PEZPTlQgY29sb3I9IzAw +MDAwMCBzaXplPTQ+PC9GT05UPiZuYnNwOzwvRElWPg0KICAgICAgICAgICAgPERJVj48Rk9OVCBj +b2xvcj0jMDAwMDAwIHNpemU9ND65yrmry77X9rP2yOfPwrnmtqihozwvRk9OVD48L0RJVj4NCiAg +ICAgICAgICAgIDxESVY+PEZPTlQgY29sb3I9IzAwMDAwMCANCnNpemU9ND4mbmJzcDsmbmJzcDsm +bmJzcDsmbmJzcDs8L0ZPTlQ+PC9ESVY+DQogICAgICAgICAgICA8RElWPjxGT05UIGNvbG9yPSMw +MDAwMDAgDQogICAgICAgICAgICBzaXplPTQ+Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7 +MS7PwrDguvPH67nYsdW49sjLtefE1LXn1LS1yNK7x9C158b3yejKqaGjPC9GT05UPjwvRElWPg0K +ICAgICAgICAgICAgPERJVj48Rk9OVCBjb2xvcj0jMDAwMDAwIHNpemU9ND4mbmJzcDsmbmJzcDsm +bmJzcDsmbmJzcDsgDQogICAgICAgICAgICA8L0ZPTlQ+PC9ESVY+DQogICAgICAgICAgICA8RElW +PjxGT05UIGNvbG9yPSMwMDAwMDAgc2l6ZT00PiZuYnNwOyZuYnNwOyZuYnNwOyANCiAgICAgICAg +ICAgIDIuyOfT9rW9vNOw4LvyzNjK4s/CsODKsbzko6zH69fuuvPSu7j2wOu/qrmry761xM2s0afX +1L71vavDxbSwudi6w6Os0vvLrrv6tefUtLDOtfSjrL/Vtfe52DwvRk9OVD48L0RJVj4NCiAgICAg +ICAgICAgIDxESVY+PEZPTlQgY29sb3I9IzAwMDAwMCBzaXplPTQ+PC9GT05UPiZuYnNwOzwvRElW +Pg0KICAgICAgICAgICAgPERJVj48Rk9OVCBjb2xvcj0jMDAwMDAwIHNpemU9ND6x1aGjPC9GT05U +PjwvRElWPg0KICAgICAgICAgICAgPERJVj48Rk9OVCBjb2xvcj0jMDAwMDAwIHNpemU9ND48L0ZP +TlQ+Jm5ic3A7PC9ESVY+DQogICAgICAgICAgICA8RElWPjxGT05UIGNvbG9yPSMwMDAwMDAgDQog +ICAgICAgICAgICBzaXplPTQ+Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A70vLO0rK/w8XU2sO/zOzP +wrDguvO74b2ry/nT0NPDtefJ6LG4vLDV1cP3yejKqbi61PC52LHVo6zL+dLU0Oi807DgtcTNrNGn +1Nm0zsq508PH69K7tqi9q9LUyc88L0ZPTlQ+PC9ESVY+DQogICAgICAgICAgICA8RElWPjxGT05U +IGNvbG9yPSMwMDAwMDAgc2l6ZT00PjwvRk9OVD4mbmJzcDs8L0RJVj4NCiAgICAgICAgICAgIDxE +SVY+PEZPTlQgY29sb3I9IzAwMDAwMCANCiAgICAgICAgICAgIHNpemU9ND7L+dKqx/PKws/uuLrU +8LnYsdWjrMDry77Ksci3saO5q8u+tPPDxbnYsdW6w9TZwOu/qqGjPC9GT05UPjwvRElWPg0KICAg +ICAgICAgICAgPERJVj48Rk9OVCBjb2xvcj0jMDAwMDAwIHNpemU9ND48L0ZPTlQ+Jm5ic3A7PC9E +SVY+DQogICAgICAgICAgICA8RElWPjxGT05UIGNvbG9yPSMwMDAwMDAgc2l6ZT00PiZuYnNwOyZu +YnNwOyZuYnNwOyA8Rk9OVCANCiAgICAgICAgICAgIGNvbG9yPSNmZjAwMDA+PFNUUk9ORz7I57P2 +z9bO3sjLx+m/9sqxo6zDxbSwtefG9860udix1aOsvq25/bX3sum6y8q1uvOjrLWxysLIy72rtKbS +1DUw1Kq3o7/u0tTKvr6vyr6hozwvU1RST05HPjwvRk9OVD48L0ZPTlQ+PC9ESVY+PEJSPjIwMTAt +MDctMjMgDQogICAgICAgICAgICA8L0ZPTlQ+PC9ESVY+DQogICAgICAgICAgICA8RElWIGFsaWdu +PWxlZnQ+DQogICAgICAgICAgICA8SFIgc3R5bGU9IldJRFRIOiAxMjJweDsgSEVJR0hUOiAycHgi +IGFsaWduPWxlZnQgU0laRT0yPg0KICAgICAgICAgICAgPC9ESVY+DQogICAgICAgICAgICA8RElW +PjxGT05UIGNvbG9yPSNjMGMwYzA+PFNQQU4+yMvBptfK1LSyvzwvU1BBTj4gDQogICAgICAgICAg +ICA8L0RJVj48L0ZPTlQ+PC9ESVY+PC9GT05UPjwvVEQ+PC9UUj48L1RCT0RZPjwvVEFCTEU+PC9U +RD4NCiAgICA8VEQgdkFsaWduPWJvdHRvbSBiYWNrZ3JvdW5kPWNpZDpfXzZARm94bWFpbC5uZXQ+ +DQogICAgICA8VEFCTEUgY2VsbFNwYWNpbmc9MCBjZWxsUGFkZGluZz0wIHdpZHRoPSIxMDAlIiBi +b3JkZXI9MD4NCiAgICAgICAgPFRCT0RZPg0KICAgICAgICA8VFI+DQogICAgICAgICAgPFREIGJh +Y2tncm91bmQ9Y2lkOl9fMTJARm94bWFpbC5uZXQ+PElNRyBoZWlnaHQ9MzU3IA0KICAgICAgICAg +ICAgc3JjPSJjaWQ6X18wQEZveG1haWwubmV0IiB3aWR0aD04ND48L1REPjwvVFI+PC9UQk9EWT48 +L1RBQkxFPjwvVEQ+PC9UUj4NCiAgPFRSPg0KICAgIDxURCB2QWxpZ249dG9wIGJhY2tncm91bmQ9 +Y2lkOl9fN0BGb3htYWlsLm5ldD48SU1HIGhlaWdodD0xIA0KICAgICAgc3JjPSJjaWQ6X18wQEZv +eG1haWwubmV0IiB3aWR0aD00OT48L1REPg0KICAgIDxURCB2QWxpZ249dG9wIGFsaWduPXJpZ2h0 +IGJhY2tncm91bmQ9Y2lkOl9fOEBGb3htYWlsLm5ldD4NCiAgICAgIDxUQUJMRSBjZWxsU3BhY2lu +Zz0wIGNlbGxQYWRkaW5nPTAgd2lkdGg9MTI1IGJvcmRlcj0wPg0KICAgICAgICA8VEJPRFk+DQog +ICAgICAgIDxUUj4NCiAgICAgICAgICA8VEQgYmFja2dyb3VuZD1jaWQ6X18xM0BGb3htYWlsLm5l +dD48SU1HIGhlaWdodD01OCANCiAgICAgICAgICAgIHNyYz0iY2lkOl9fMEBGb3htYWlsLm5ldCIg +d2lkdGg9MTI1PjwvVEQ+PC9UUj48L1RCT0RZPjwvVEFCTEU+PC9URD4NCiAgICA8VEQgdkFsaWdu +PXRvcCBiYWNrZ3JvdW5kPWNpZDpfXzlARm94bWFpbC5uZXQ+PElNRyBoZWlnaHQ9NTggDQogICAg +ICBzcmM9ImNpZDpfXzBARm94bWFpbC5uZXQiIHdpZHRoPTg0PjwvVEQ+PC9UUj48L1RCT0RZPjwv +VEFCTEU+PC9CT0RZPjwvSFRNTD4NCg== +--=====003_Dragon224480308877_=====-- +--=====002_Dragon224480308877_===== +Content-Type: image/gif; + name="spacer.gif" +Content-Transfer-Encoding: base64 +Content-ID: <__0@Foxmail.net> +R0lGODlhAQABAPAAAAAAAP///yH5BAEAAAEALAAAAAABAAEAAAICTAEAOw== +--=====002_Dragon224480308877_===== +Content-Type: image/jpeg; + name="tl.jpg" +Content-Transfer-Encoding: base64 +Content-ID: <__1@Foxmail.net> +/9j/4AAQSkZJRgABAgAAZABkAAD/7AARRHVja3kAAQAEAAAAPAAA/+4ADkFkb2JlAGTAAAAAAf/b +AIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoKDBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxsc +Hx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f +Hx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgAMgAzAwERAAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAA +AAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAAAQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIG +AnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPBUtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6Oz +NhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dn +d4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZqbnJ2en5KjpKWmp6ipqqusra6voRAAICAQID +BQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEyobHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LC +B3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaW +prbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq ++v/aAAwDAQACEQMRAD8A55mY4rsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVaqMVdyGK +XchireKHYq7FV1rbXF5cC3t1q5FWJNFVR1Zj2AxtKcpo2iwEJPJNdzU39MiKOvgKhmP3jButrvqP +l6tPqk5Ph62+/h8O/wBGK2t+q+XP+WWb/kd28fs4N1tJMkh2KrZDRcUpro7+hphZKCW5cln7hEPE +D765FSvLctyB02oAOnhTChVJ5x1NS67g/rqO21T/AJ7lDuT15V3rX6aca/d/t4qkmKXYqpT/AGTi +Upnp3/HNtz2o/wDycbIqUS6BAKmrHcqAdh8/H6MKHRtuR2pv1pt1+4H7sVXbVpy2p+NK4bVJsVdi +qlP9k4lKaab/AMc23+Tf8nWyKlFftJ1+wvXp0OEsQ1+12+y3y79P44Eqfb9v/M4Vf//Z +--=====002_Dragon224480308877_===== +Content-Type: image/jpeg; + name="t_bg.jpg" +Content-Transfer-Encoding: base64 +Content-ID: <__2@Foxmail.net> +/9j/4AAQSkZJRgABAgAAZABkAAD/7AARRHVja3kAAQAEAAAAPAAA/+4ADkFkb2JlAGTAAAAAAf/b +AIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoKDBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxsc +Hx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f +Hx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgAMgAHAwERAAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAA +AAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAAAQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIG +AnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPBUtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6Oz +NhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dn +d4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZqbnJ2en5KjpKWmp6ipqqusra6voRAAICAQID +BQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEyobHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LC +B3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaW +prbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq ++v/aAAwDAQACEQMRAD8A55mY4rsVa5DFKc/VvL3/ACyz/wDI3/m3I7pUcKuxVZ/wWKv/2Q== +--=====002_Dragon224480308877_===== +Content-Type: image/jpeg; + name="tr.jpg" +Content-Transfer-Encoding: base64 +Content-ID: <__3@Foxmail.net> +/9j/4AAQSkZJRgABAgAAZABkAAD/7AARRHVja3kAAQAEAAAAPAAA/+4ADkFkb2JlAGTAAAAAAf/b +AIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoKDBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxsc +Hx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f +Hx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgAMgBWAwERAAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAA +AAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAAAQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIG +AnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPBUtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6Oz +NhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dn +d4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZqbnJ2en5KjpKWmp6ipqqusra6voRAAICAQID +BQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEyobHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LC +B3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaW +prbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq ++v/aAAwDAQACEQMRAD8A55mY4rsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdir +sVa5DFLuQxQ3irsVdirsVdirsVdirsVdiqcfVvL3/LLP/wAjf+bcjuyabTtCmHGJp7STszFZU+kU +Vvxx3VK7u1nsp/RmoaiqSKaq6+KnCCghZhQ7FXYq7FXYq7FXYq7FUywMnYqtvj6umujbtARJEfDc +Bh9IwKlkTVXJIX4odirsVdirsVdirsVTLAydiqldf7x3H/GM/rGAqllv9kZIIVsUOxV2KuxV2Kux +V2KplgZOxVSu/wDeK4/4xn9YwKllv9kZIIVsUOxV2KuxV2KuxV2Kv//Z +--=====002_Dragon224480308877_===== +Content-Type: image/jpeg; + name="m_bgl.jpg" +Content-Transfer-Encoding: base64 +Content-ID: <__4@Foxmail.net> +/9j/4AAQSkZJRgABAgAAZABkAAD/7AARRHVja3kAAQAEAAAAPAAA/+4ADkFkb2JlAGTAAAAAAf/b +AIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoKDBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxsc +Hx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f +Hx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgABQAzAwERAAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAA +AAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAAAQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIG +AnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPBUtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6Oz +NhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dn +d4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZqbnJ2en5KjpKWmp6ipqqusra6voRAAICAQID +BQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEyobHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LC +B3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaW +prbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq ++v/aAAwDAQACEQMRAD8A55mY4rsVUp/snEpTCw/459v8n/5ONkQlXwq7FVL9r/Z/8a4Ff//Z +--=====002_Dragon224480308877_===== +Content-Type: image/jpeg; + name="m.jpg" +Content-Transfer-Encoding: base64 +Content-ID: <__5@Foxmail.net> +/9j/4AAQSkZJRgABAgAAZABkAAD/7AARRHVja3kAAQAEAAAAPAAA/+4ADkFkb2JlAGTAAAAAAf/b +AIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoKDBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxsc +Hx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f +Hx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgAzwCtAwERAAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAA +AAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAAAQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIG +AnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPBUtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6Oz +NhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dn +d4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZqbnJ2en5KjpKWmp6ipqqusra6voRAAICAQID +BQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEyobHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LC +B3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaW +prbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq ++v/aAAwDAQACEQMRAD8A9S5SydirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVY +JP5zif8AOyy8opKAIdAu76dK/ammu7ZYl/1ljhkb5NhrZWd4FdirsVdirsVdirsVdirsVdirsVdi +rsVdirsVdirsVdirsVdirsVfCP8Aytr/AKyT/wAcet/uN/Sn1bnX4f0dT6nyp/xg+OnjllbIfd2V +pdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirBPzw83f4U/K3X9VR+F21ubSyIPx +evdH0UZfdOfP6MIG6vzrptmRw+m2D9T8xmbsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirs +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 +irsVdirsVdir/9k= +--=====002_Dragon224480308877_===== +Content-Type: image/jpeg; + name="m_bgr.jpg" +Content-Transfer-Encoding: base64 +Content-ID: <__6@Foxmail.net> +/9j/4AAQSkZJRgABAgAAZABkAAD/7AARRHVja3kAAQAEAAAAPAAA/+4ADkFkb2JlAGTAAAAAAf/b +AIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoKDBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxsc +Hx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f +Hx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgABQBWAwERAAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAA +AAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAAAQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIG +AnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPBUtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6Oz +NhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dn +d4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZqbnJ2en5KjpKWmp6ipqqusra6voRAAICAQID +BQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEyobHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LC +B3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaW +prbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq ++v/aAAwDAQACEQMRAD8AhcX92vyzLcdfiqld/wC8Vx/xjP6xgVLLf7IyQQrYodirsVdirsVdirsV +f//Z +--=====002_Dragon224480308877_===== +Content-Type: image/jpeg; + name="dl.jpg" +Content-Transfer-Encoding: base64 +Content-ID: <__7@Foxmail.net> +/9j/4AAQSkZJRgABAgAAZABkAAD/7AARRHVja3kAAQAEAAAAPAAA/+4ADkFkb2JlAGTAAAAAAf/b +AIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoKDBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxsc +Hx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f +Hx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgAOgAzAwERAAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAA +AAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAAAQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIG +AnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPBUtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6Oz +NhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dn +d4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZqbnJ2en5KjpKWmp6ipqqusra6voRAAICAQID +BQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEyobHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LC +B3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaW +prbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq ++v/aAAwDAQACEQMRAD8A55mY4rsVUp/snEpTCw/459v8n/5ONkQlXwq7FWqD+OKpdhYuxVSn+ycS +lMLD/jn2/wAn/wCTjZEJV8KuxV2KpbhYuxVSn+ycSlMLD/jn2/yf/k42RCVfCrsVdiqW4WLsVUp/ +snEpTDTz/uPt/YP/AMnGyISr4VdirsVS3CxdiqyUVXFLenXax1t5DShLIfEHqP45FKZggio3GFW8 +VdiqW4WLsVcRXFULPb8tx1wEJBU1ur+LYNyHvWv3imRpla79Jah4D8f647q79Jah4D8f64qjMmwd +irsVdTFVpjU4pa9JcVa9FcVVMUOxV2KuxV2KuxV2Kv8A/9k= +--=====002_Dragon224480308877_===== +Content-Type: image/jpeg; + name="d_bg.jpg" +Content-Transfer-Encoding: base64 +Content-ID: <__8@Foxmail.net> +/9j/4AAQSkZJRgABAgAAZABkAAD/7AARRHVja3kAAQAEAAAAPAAA/+4ADkFkb2JlAGTAAAAAAf/b +AIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoKDBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxsc +Hx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f +Hx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgAOgAFAwERAAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAA +AAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAAAQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIG +AnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPBUtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6Oz +NhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dn +d4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZqbnJ2en5KjpKWmp6ipqqusra6voRAAICAQID +BQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEyobHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LC +B3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaW +prbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq ++v/aAAwDAQACEQMRAD8AhH1S3rXgK+OZVOOrYVdirsVdiqQ/pLUPAfj/AFyKUR6K5NiqYof/2Q== +--=====002_Dragon224480308877_===== +Content-Type: image/jpeg; + name="dr.jpg" +Content-Transfer-Encoding: base64 +Content-ID: <__9@Foxmail.net> +/9j/4AAQSkZJRgABAgAAZABkAAD/7AARRHVja3kAAQAEAAAAPAAA/+4ADkFkb2JlAGTAAAAAAf/b +AIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoKDBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxsc +Hx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f +Hx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgAOgBWAwERAAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAA +AAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAAAQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIG +AnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPBUtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6Oz +NhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dn +d4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZqbnJ2en5KjpKWmp6ipqqusra6voRAAICAQID +BQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEyobHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LC +B3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaW +prbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq ++v/aAAwDAQACEQMRAD8Ai0pJUctqV23+yTUD3zLLiBT5t1rufpOBLV1IWsbjuAhoep6iv0t164So +Sq2BCAEbgDcV+YP09cIQVaPdlqepFa+5xUqrykEopoQN/H7u2SQpyUZQ56+21QP6HIlKw9cUr3Pw +H3A36e36sUNltlPQJXxFa09jirjK9Q33demFCOIYN0PL8en398gzcdtjsT2PXFVG73srj/jGfnTb ++uJVBWy8kCnZuiMRQEHxwhiVxVl2YU5dz0/DCrYLtTkSQdgST7djircm3Fa7gbntU0xKrN9idgNy +cUtkhq9vEHt2wK2iymvCq0+0SeNK9vwwodSXlSp51pXeuKps6cfsmoO4O24psegxVqrGMjwNCp2G +4NDt8sCoW8Wlnc03BjND074CyS+3H7sbU3A6D9eEIKsjsBsTTphQuPIMwB+ID4ytPCp33PfCqm32 +zTffamBLYjLMVWldzvsO+9caRbjHRuKk0qQSBUinU/xw0q9yBTl8CdlUKQK9uvtih1ADy5bEV5bV +6UxpbRqsUqFPXr3r4VyDJytxII7dfele+/bFVt6VOnTj9sR8T7itP4DCVCW228e+34dPniENgkMD ++0KGhwqqNJVdiwJoCN/p74rTokVmIIrUdK9x/DtiFK8CMN8INSCpWvsaGtPGhwoWlvgB3NfiIFRU +GhFaHYb9MFqt9So22Xw9sbTSzb0+O1K/TT/OmFUyNR1G9Kkfq6ZBLalADzJA7MOxH+3ilAapeIY/ +q0NWMlOZ6/CDXvTviqhbjgoU7dCBT+mFCpQ9dz0r88KGjTFKtErL8XMR17bdNu1Rt0whiWmCkgEU +rQGvTiT2Y9t8Sq6gKOGID1JFQd6b9QPEHrTEqFAb/wAMCV4A9M7Hl1p93tiqAXVNRO1B8qt/XIbs +3fWr+SgLbHuAa9/EntjS2uhgoeR3J3ZjuT7nCGKJCkCv0fqySrwwP6yMULaUHyIr9PTFK+P1eJVR +UdxWmx79R4YUFcQUPqRihUhqVB/yh06jpgKAtcUJUCoAG+1aClP4YpUwfbAlcKemdvlt/n44UKa2 +60LGgBGw7mv0+2NJt3EAnan+3irgMVXAnp1xVtloR4Hp4064q2G33/z7YqvQoo3Hzb28PHCEFsmP +Yii1qQQTXx8fo6YUNIoCt7UB8CBQV/DAlaY6khd/6YFaCNQjjv1pXtils/bXr0/hiqliru2KtjCq +p+z9A6fIfhgVTOKr06r/AJnEKXL/AJ+PfChpen0fT174FVE+w3+xwq7/AHZ/nTpgV//Z +--=====002_Dragon224480308877_===== +Content-Type: image/jpeg; + name="t_ml.jpg" +Content-Transfer-Encoding: base64 +Content-ID: <__10@Foxmail.net> +/9j/4AAQSkZJRgABAgAAZABkAAD/7AARRHVja3kAAQAEAAAAPAAA/+4ADkFkb2JlAGTAAAAAAf/b +AIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoKDBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxsc +Hx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f +Hx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgAMgBXAwERAAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAA +AAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAAAQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIG +AnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPBUtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6Oz +NhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dn +d4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZqbnJ2en5KjpKWmp6ipqqusra6voRAAICAQID +BQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEyobHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LC +B3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaW +prbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq ++v/aAAwDAQACEQMRAD8A55mY4rsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdir +sVa5DFLuQxV3IYq7kMVdyGKu5DFXchiruQxV3IYq7kMVdyGKp2bTy6P+PWf/AJG/825HdK9bLy4V +J+qzjrQ+sKbf7HFFtNZ+XQoP1Wevf994/wCxx3W1v1Ty7/yyzf8AI4f0x3S2tn5eP/HrP/yO/sx3 +Rar9Q8t8qG0nG1aer79OnhhRa0WHl2n+8k5Pek1fb+Xrtim3fUPLhNDazpX7PKUj3/lxpFtLY+Xm +6Ws5p1pN/wA2747ptabPy9SotZyPETf824Ftb9V8u/8ALLP/AMjf7Md0rGpyNBt7/wCfjiWLcbhW +HIfCdj9PXEKuP2ClOR5KB4nbYj6MKuiRTxJ3Wu9NyaUO34YFcgAZiV27qPn0X9WFV3GVmNRuepG4 +Phv3GFC5uPw0IJ6GlCK0B2+knAqxpmrtQA0r03798bSAsRiCPE7Gg/z8cVpdId+fTl18K9D9+KqF +cWSoxJJY9Tv40r164ChsKX2VeR7gdhT3oBtiEL1WRQDTemzAhhtuOh8cNIttnAqRWhoQfAN1K/Ti +rS1CigAbfcdgu3v/ALWKu4Kwrs1aAGlN228N8VW8v4V98UuCksF6Ek79vc4FWtRTsTQdyKYqtYnp +hSFuKW26H7XQ/ryKFVP7sfa+032vmPs/5WSCC2n/AD2/2PX6cUBbP9o9enb/AFR9r/KwJWj7Dfa+ +nr/tYQpXz9f92dT9rp2/HCgLU7/a7frGRS2ftr169+n2j1whVNug+1/n4e2BIU/+C+nril3/AAWF +X//Z +--=====002_Dragon224480308877_===== +Content-Type: image/jpeg; + name="m_tl.jpg" +Content-Transfer-Encoding: base64 +Content-ID: <__11@Foxmail.net> +/9j/4AAQSkZJRgABAgAAZABkAAD/7AARRHVja3kAAQAEAAAAPAAA/+4ADkFkb2JlAGTAAAAAAf/b +AIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoKDBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxsc +Hx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f +Hx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgAhgAzAwERAAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAA +AAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAAAQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIG +AnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPBUtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6Oz +NhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dn +d4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZqbnJ2en5KjpKWmp6ipqqusra6voRAAICAQID +BQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEyobHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LC +B3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaW +prbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq ++v/aAAwDAQACEQMRAD8A55mY4rsVUp/snEpTPTWpptuPZz/yUbfIqUVz5JQjYACu/wCoe2FDYKgE +DuCD91Dt712xVTr8VKn+8r+10418cCpVkldiqlP9k4lKcaWYxpdsKVdleg2/363XAEFWkUFeajwB +XY07Ajb+GJULKdPl3wJW8jy7f3leg60+eKErySuxVSn+ycSlNNNYnTbUeCvT3/esfGmRUop9ot+r +dD7V7fMgYSxCylemBksovP8A2fHp244oSzJK7FVKf7JxKU20ug0y1PGtQ9e3+7W603pgCCrycuZL +fa25fs9q0p264q0Aa0HU7ADv7DxwJUaH1KVHLly6/wCRX9WGkJdhV2KqU/2TiUptppppds4oaI6k +HtWV9+382RClXADsQCAd6VrUn+2nfChUReLowatQRsDsSCB1+YwoUfWXlWv+7uXXbpTw6+/8cFql +OFLsVUp/snEpTPTv+Obb/wCq/wDydbIqUVCSGDAcwPtDp2I74QgtvQHmvvXsQadx4/51xKAsp8VK +mnrcKb/y1r0617f8LilKcKuxVSn+ycSlM9OH+422J6Uc+1BK2RUotZyFoWI6UNTX2rTjhCC5vEGv +T2PjvUeOJUKfM8qUFOfOtO/Gv3V2wKlWSV2KqU/2TiUprph/3GW467N93qsaZFSioTwrU7+Han+f +uMKF5R+OzE9qEUBB+Z/rhQhafHXkft8abUpxpgTaWYVdiqlP9k4lKZad/wAc629g/wDycbIqUSKk +kAVPX/bxVdxNK/sjfkK06dq9cKFPk3KtT9unU9eNKf2YqleFXYqpT/ZOJSmenf8AHOtvk/8AycbI +qUUKU4VohO/jTfqcKHSsT8PRR0HbFQh670ptz6U9q0+VcCUvySHYqpT/AGTiUpppgJ063A8H/wCT +j5FSjOBodtyNh7dskxUiCd/HYHf/AD64EqXpjl1/b8P8n540lLsKHYqpT/ZOJSm+lMBpltXwcAf8 +9H3PtgCCiOQ3ANOQ3Y9SMKFlZCSATttQEfw2pXwwJUa/H1/3Z/xrgSl2SQ7FVKf7JxKU40sf7i7U +j7Xxg9O8j0r36jAEFWaQg7D5nff8cbWlOp5V7n/P6cbTSly+Lv8A3lf+F/XiqX4UOxVSn+ycSlNN +Np+jbceKv2r1lbIqVc7n3J2+eKrWFDSoNPDCqjX4v+en/GuBKByTF2KqU/2TiUppptP0bb+PF/8A +k42RClXZvDCqwscVUf2v9n/xrgSgskxdiqlP9k4lKZad/wAc+2Hs/wDycbIhSrstN64VW4pUv2v9 +n/xrgVBZJi7FVKf7JxKUy07/AI59t4Uf/k4+AKVZ68jXrXFWsUqX7X+z/wCNcCv/2Q== +--=====002_Dragon224480308877_===== +Content-Type: image/jpeg; + name="m_dr.jpg" +Content-Transfer-Encoding: base64 +Content-ID: <__12@Foxmail.net> +/9j/4AAQSkZJRgABAgAAZABkAAD/7AARRHVja3kAAQAEAAAAPAAA/+4ADkFkb2JlAGTAAAAAAf/b +AIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoKDBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxsc +Hx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f +Hx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgBZQBWAwERAAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAA +AAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAAAQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIG +AnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPBUtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6Oz +NhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dn +d4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZqbnJ2en5KjpKWmp6ipqqusra6voRAAICAQID +BQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEyobHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LC +B3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaW +prbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq ++v/aAAwDAQACEQMRAD8AhcX92vyzLcdfiqld/wC8Vx/xjP6xgVLLf7IyQQrYoUL29t7K1kubhuMU +Yqx7+wHucSaSBbzjWPNWp6jK3GRre2r8EMZI2/yiPtHMaUyW8QAUdJ8xajp90kgmeSEEepCzEqy9 +9j0PvgjMhTEF6lFIksSSoao6hlPiCKjMpoXYodiqPi/u1+WBkvxVSu/94rj/AIxn9YwKllv9kZII +VsUKukWXk3zJcy6Rf+td3luxYwxCYIpG1Kxfabr7DMDVZZA7cnM0+MEb809uPyU/KOWJRcahqeiT +sOKzSIzW/M9ORkiP/ExmNHPJvlhHR55+YH5Ja75WC3VheQ69pUiepHdWoo/H+Zoqvt/qM3vTL45Q +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 +qKVwodNXglfs1NfnT/briqn+749Tyrt88Uv/2Q== +--=====002_Dragon224480308877_===== +Content-Type: image/jpeg; + name="d_mr.jpg" +Content-Transfer-Encoding: base64 +Content-ID: <__13@Foxmail.net> +/9j/4AAQSkZJRgABAgAAZABkAAD/7AARRHVja3kAAQAEAAAAPAAA/+4ADkFkb2JlAGTAAAAAAf/b +AIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoKDBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxsc +Hx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f +Hx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgAOgB9AwERAAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAA +AAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAAAQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIG +AnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPBUtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6Oz +NhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dn +d4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZqbnJ2en5KjpKWmp6ipqqusra6voRAAICAQID +BQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEyobHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LC +B3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaW +prbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq ++v/aAAwDAQACEQMRAD8Ag/1K2/kGZVOPbvqVt/IMaW3fUrb+QY0tu+pW38gxpbd9Stv5BjS276lb +fyDGlt31K2/kGNLbvqVt/IMaW2xZWx/3WMaW2/qVrT+7GNLapDY2u59MbAk/QMaQSuW0tmbeNKE0 +K7U6eOGkWsawtQxHAU7VG9CKiv35Gk22lla1NIxsPDDSkrha2iybxjYU4/7eKG/qlrXhwWhblTt1 +rSlKfjhVbiydirsVdirsVdirsVcMVXLTFC8qCKj6V/pihoBlYUqG7UrX8MCV6AULNsqj4q9OnQ9d +zhCCtZiXZj1J3wFWxsK9z74q0V6n764qqejccCd+NB8NRWnTphpbQ2LJ2KuxV2KuxV2KuxVsAHvT +FC5Vod/86Yquatf8xhQvQuQQT8ABLH2A36U7Yq41Kjkak04qNupFSANuxwFCnSv07j+uBkvEXwcz +spqB860qQK++EItuJWBNV3+yC1AKgivU0PSmNK3Va05tzJp0Faj6ae/XCxQ2BsdirsVdirsVdirY +FRihcgoe3y/z9sQpVHKh+S1oadev3dMUOYbAj8cVDS0B3FQRQ9K0IptirTPUkVLDt22NTT8cVpUA +jChmBpQhjXuD12GGkOB+GNBtuaHtTc/Om56eGBVpYA9Kg9/boNqlaY2lr1O9N/H/AD3xtaUcWTYF +cUOIGKtha+2KtlaCoHbY9jTFV6olWBPsp6/iPmMULBgSuQLvyr8vvwocxNTtT+wUxVtSSD/w1PDF +WipXY9en+f34q0q8jQb+JrSm3XAlWoVUKTzUV2WlV3qe/TJMVm4BJ3FQCaderHY+IpXfAl03HkGV +uQbaoqKUFANwDiVWbdciljv6S1DrQfj/AFxZNjUtQ8BX6f647q3+kdQ32Hj+1/XHdXLqepCvED72 +/r747oXfpHUCOgBpvuTXt447rs02qaidyASd+/fc9/njuuy39J6h4D/hv647pbXUtQ32H4/1xQ3+ +ktQ8APvH8cd1b/SOpBqFRUfP+uO6t/pPUCBso8ev6q47qs/SepAjYA7HuOoGw398d1VTqWpk0ZR7 +bmv3V2w7oWjUtQBbYUpXuP1H6MG6Vp1PUqgUHt16b++O67NfpK/p0X/hv64N1RCwr0pljFswL1p1 +/XirvSX+n8MVbESCpA+nwxVd6MRFdhXod6+GFDaWyVPTpsexHf7q4ra026H7PU9BgpbaEAWvw08M +UtmAdCPnjS2v9EOm4Fe1OlQOv4YoWGIBiKdD0+X9uKu9JDud9/xOBKrwhOxUUBqK9B9AAH4ZIIWv +BEalKHrtv+FTWuKrpbdOVBvt8J70AoO3gP140i1L0Er7dK/2dcjTK1y9/l/TCrY+z9H9cKrDgVte +g+eKrv2j9Pz6jChod/menXp/nTAq9P2v9U/LrhVo/aH0YFafr9C/8RGFC4fa7/aHXr1GKWpeuBVo +64Et9+/b7OFC7uf8x1/zpirY/ufp/wCNv91++FV3+7/2Ptf7Hr/n/ssCv//Z +--=====002_Dragon224480308877_=====-- \ No newline at end of file diff --git a/lib_acl_cpp/samples/mime/mime.cpp b/lib_acl_cpp/samples/mime/mime.cpp new file mode 100644 index 000000000..14f476c2a --- /dev/null +++ b/lib_acl_cpp/samples/mime/mime.cpp @@ -0,0 +1,497 @@ +// mime.cpp : 定义控制台应用程序的入口点。 +// + +#include "stdafx.h" +#include "lib_acl.h" +#ifdef WIN32 +#include +#else +#include +#endif +#include +#include +#include +#include "acl_cpp/stdlib/string.hpp" +#include "acl_cpp/stream/ifstream.hpp" +#include "acl_cpp/stream/ofstream.hpp" +#include "acl_cpp/stdlib/charset_conv.hpp" +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/mime/mime.hpp" +#include "acl_cpp/mime/mime_body.hpp" +#include "acl_cpp/mime/rfc2047.hpp" +#include "acl_cpp/mime/mime_attach.hpp" + +#include "pipeline_string.h" + +using namespace std; +using namespace acl; + +static void header_out(const acl::mime* mime) +{ + printf("sender addr: %s\n", mime->sender().c_str()); + printf("from addr: %s\n", mime->from().c_str()); + printf("replyto addr: %s\n", mime->replyto().c_str()); + printf("returnpath addr: %s\n", mime->returnpath().c_str()); + + const list& rcpts = mime->rcpt_list(); + list::const_iterator cit; + + for (cit = rcpts.begin(); cit != rcpts.end(); cit++) + { + const char* addr = *cit; + printf("rcpt addr: %s\n", addr); + } + + const list& tos = mime->to_list(); + for (cit = tos.begin(); cit != tos.end(); cit++) + { + const char* addr = *cit; + printf("to addr: %s\n", addr); + } + + const list& ccs = mime->cc_list(); + for (cit = ccs.begin(); cit != ccs.end(); cit++) + { + const char* addr = *cit; + printf("cc addr: %s\n", addr); + } + + const char* to = mime->header_value("To"); + acl::string out; + if (to) + rfc2047::decode(to, (int) strlen(to), &out); + printf(">>>>To: %s, %s\n", to ? to : "null", out.c_str()); +} + +// 解析邮件并输出邮件头信息 +static void test_mime_header(acl::mime& mime, const char* path) +{ + // 以下仅解析邮件头部分 + + printf("\r\n"); + ACL_METER_TIME("---------------parse header begin--------------------"); + acl::ifstream fp; + if (fp.open_read(path) == false) { + printf("open %s error %s\n", path, strerror(errno)); + return; + } + acl::string buf; + const char* ptr; + size_t n; + + // 开始邮件解析过程 + mime.update_begin(path); // update_begin 内部会自动调用 reset() + + while (1) { + if (fp.gets(buf, false) == false) + break; + if (buf == "\r\n" || buf == "\n") + break; + + ptr = buf.c_str(); + + n = buf.length(); + + // 如果返回 true 表示头部解析完毕, 为了使该函数返回 true, + // 必须保证调用此函数的最后一行数据为 "\r\n" 即空行 + + (void) mime.update(ptr, n); + } + + mime.update_end(); + + header_out(&mime); + ACL_METER_TIME("---------------parse header end --------------------"); +} + +// 将邮件正文内容保存在磁盘上 +// 将邮件正文内容保存在缓冲区中 +// 采用管道流模式将邮件正文内容进行字符集转换,且保存在磁盘上 +// 将邮件中的附件保存在磁盘上 +// 将解析后的邮件再重新组合并保存在磁盘上 +static void mime_test1(acl::mime& mime, const char* path, bool htmlFirst) +{ + mime.reset(); + + acl::string buf; + acl::ofstream fp_out; + acl::mime_body* pBody = NULL; + + printf("\r\n>>> %s: path: %s\n", __FUNCTION__, path); + + ACL_METER_TIME("---------------parse begin --------------------"); + + if (mime.parse(path) == false) + { + printf("mime parse %s error\n", path); + return; + } + + ACL_METER_TIME("---------------parse end --------------------"); + + pBody = mime.get_body_node(htmlFirst, true, "iso-2022-jp"); + + ////////////////////////////////////////////////////////////////////// + + // 将邮件正文内容保存在磁盘上 + + printf("\r\n"); + + ACL_METER_TIME("---------------save_body begin--------------------"); + + header_out(&mime); + mime.mime_debug("./var"); + + buf = "./var/"; + buf += path; + mime.save_as(buf.c_str()); + + if (pBody) + pBody->save_body("./var/body_gb.txt"); + + ACL_METER_TIME("---------------save_body end --------------------"); + + ////////////////////////////////////////////////////////////////////// + + // 将邮件正文内容保存在缓冲区中 + + if (pBody) + { + acl::string buf1; + pBody->save_body(buf1); + + if (fp_out.open_write("./var/body_string.txt")) + { + fp_out.write(buf1.c_str(), buf1.length()); + fp_out.close(); + } + } + + ////////////////////////////////////////////////////////////////////// + + // 将邮件正文内容以 utf-8 存在磁盘上 + if (pBody) + { + printf("\r\n"); + ACL_METER_TIME("---------------save_body begin--------------------"); + acl::charset_conv jp2utf8; + jp2utf8.update_begin("iso-2022-jp", "utf-8"); + + acl::pipe_string pipe_out; + pipeline_string pipeline; + acl::pipe_manager manager; + + manager.push_front(&pipe_out); + manager.push_front(&jp2utf8); + manager.push_front(&pipeline); + + pBody->save(manager); + + ACL_METER_TIME("---------------save_body end1 --------------------"); + + acl::string& sbuf = pipe_out.get_buf(); + + fp_out.close(); + + if (fp_out.open_write("./var/body_utf8.txt")) + { + fp_out.write(sbuf.c_str(), sbuf.length()); + fp_out.close(); + } + + ACL_METER_TIME("---------------save_body end2 --------------------"); + } + + ////////////////////////////////////////////////////////////////////// + + // 采用管道流模式将邮件正文内容进行字符集转换,且保存在磁盘上 + + if (pBody) + { + printf("\r\n"); + ACL_METER_TIME("---------------save_body begin--------------------"); + acl::charset_conv utf8ToGb, gbToBig5; + utf8ToGb.update_begin("utf-8", "gbk"); + gbToBig5.update_begin("gbk", "big5"); + + acl::pipe_string pipe_out; + acl::pipe_manager manager; + + manager.push_front(&pipe_out); + manager.push_front(&gbToBig5); + manager.push_front(&utf8ToGb); + + pBody->save(manager); + + ACL_METER_TIME("---------------save_body end1 --------------------"); + + acl::string& sbuf = pipe_out.get_buf(); + + fp_out.close(); + + if (fp_out.open_write("./var/body_big5.txt")) + { + fp_out.write(sbuf.c_str(), sbuf.length()); + fp_out.close(); + } + + ACL_METER_TIME("---------------save_body end2 --------------------"); + } + + ////////////////////////////////////////////////////////////////////// + + // 将邮件中的附件保存在磁盘上 + + printf("---------------------------------------------------------\r\n"); + printf(">>>> saving attach file now ...\r\n"); + const std::list& attaches = mime.get_attachments(); + std::list::const_iterator cit = attaches.begin(); + for (; cit != attaches.end(); cit++) + { + buf = "./var/"; + buf << (*cit)->get_filename(); + + acl::string attach_name; + acl::rfc2047 rfc2047; + rfc2047.reset(true); + rfc2047.decode_update(buf, (int) buf.length()); + rfc2047.decode_finish("utf-8", &attach_name); + + printf(">>> attach file: |%s|, len: %d\n", + attach_name.c_str(), (int) attach_name.length()); + + (*cit)->save(attach_name.c_str()); + } + + printf(">>>> saved attach file ok ...\r\n"); + ////////////////////////////////////////////////////////////////////// + + // 将解析后的邮件再重新组合并保存在磁盘上 + + mime.save_mail("./var", "test.html"); +} + +// 将位于文件中的邮件内容进行解析,并将邮件体数据转储于另一个内存缓冲中 +static void mime_test2(acl::mime& mime, const char* path) +{ + // 以下仅解析邮件头部分 + + printf("\r\n"); + ACL_METER_TIME("---------------parse mail begin--------------------"); + acl::ifstream fp; + if (fp.open_read(path) == false) { + printf("open %s error %s\n", path, strerror(errno)); + return; + } + acl::string buf; + const char* ptr; + size_t n; + + // 开始邮件解析过程 + mime.update_begin(path); + + while (1) { + if (fp.gets(buf, false) == false) + break; + ptr = buf.c_str(); + n = buf.length(); + + // 如果返回 true 表示头部解析完毕, 为了使该函数返回 true, + // 必须保证调用此函数的最后一行数据为 "\r\n" 即空行 + + //printf(">>>>%s", ptr); + if (mime.update(ptr, n) == true) + { + printf(">>> parse over, last line: %s\n", ptr); + break; + } + buf.clear(); + } + + // 必须调用 update_end + mime.update_end(); + + acl::mime_body* pBody; + pBody = mime.get_body_node(false); + if (pBody) + { + acl::string buf2; + pBody->save_body(buf2); + printf(">>>>>>>body: %s\n", buf2.c_str()); + } + + header_out(&mime); + ACL_METER_TIME("---------------parse mail end --------------------"); +} + +// 将位于内存中的邮件内容进行解析,并将邮件体数据转储于另一个内存缓冲中 +static void mime_test3(acl::mime& mime, const char* path) +{ + // 以下仅解析邮件头部分 + + printf("\r\n"); + ACL_METER_TIME("---------------parse mail begin--------------------"); + acl::string buf; + + if (acl::ifstream::load(path, &buf) == false) + { + printf("load %s error %s\n", path, strerror(errno)); + return; + } + + // 开始邮件解析过程 + mime.reset(); + if (mime.update(buf.c_str(), buf.length()) != true) + { + printf("mime parse error\r\n"); + return; + } + + // 必须调用 update_end + mime.update_end(); + + acl::mime_body* pBody; + pBody = mime.get_body_node(false); + if (pBody) + { + acl::string out; + if (pBody->save_body(out, buf.c_str(), (ssize_t) buf.length()) == false) + printf(">>>>save_body to buffer error\r\n"); + else + printf(">>>>>>>body: %s\n", out.c_str()); + } + else + printf(">>>> no body\r\n"); + + header_out(&mime); + ACL_METER_TIME("---------------parse mail end --------------------"); +} + +// 带偏移量的MIME解析过程,并将邮件体数据转储于另一个文件中 +static void mime_test4(acl::mime& mime, const char* path) +{ + mime.reset(); + acl::ifstream in; + if (in.open_read(path) == false) + { + printf("open %s error %s\n", path, strerror(errno)); + return; + } + acl::string buf; + size_t off = 0; + + // 先读文件头, 并略过文件头 + while (true) + { + if (in.gets(buf, false) == false) + break; + + off += buf.length(); + + if (buf == "\n" || buf == "\r\n") + { + buf.clear(); + break; + } + buf.clear(); + } + + // 开始解析邮件头及邮件体部分 + + mime.update_begin(path); + // 开始读邮件 + while (true) + { + if (in.gets(buf, false) == false) + break; + mime.update(buf.c_str(), buf.length()); + buf.clear(); + } + mime.update_end(); + + printf("\n-----------------------------------------------------\n\n"); + acl::mime_body* pBody = mime.get_body_node(false, true, "gb2312", (off_t) off); + if (pBody) + { + acl::string buf2; + pBody->save_body(buf2); + printf(">>>>>>>body(%d): %s\n", (int) off, buf2.c_str()); + } +} + +////////////////////////////////////////////////////////////////////////// + +static void usage(const char* procname) +{ + + printf("usage: %s [options]\r\n" + " -h [help]\r\n" + " -s [html first, or text first]\r\n" + " -t test0/test1/test2/test3/test4\r\n" + " -f mail_file\r\n", procname); + + printf("test0: 解析邮件并输出邮件头信息\r\n" + "test1: 将邮件正文内容保存在磁盘上\r\n" + "\t将邮件正文内容保存在缓冲区中\r\n" + "\t采用管道流模式将邮件正文内容进行字符集转换,且保存在磁盘上\r\n" + "\t将邮件中的附件保存在磁盘上\r\n" + "\t将解析后的邮件再重新组合并保存在磁盘上\r\n"); + printf("test2: 将位于文件中的邮件内容进行解析,并将邮件体数据转储于另一个内存缓冲中\r\n"); + printf("test3: 将位于内存中的邮件内容进行解析,并将邮件体数据转储于另一个内存缓冲中\r\n"); + printf("test4: 带偏移量的MIME解析过程,并将邮件体数据转储于另一个文件中(例子:test16.eml)\r\n"); +} + +int main(int argc, char* argv[]) +{ + char ch; + bool htmlFirst = false; + acl::string path("test.eml"); + acl::string cmd("test1"); + + while ((ch = (char) getopt(argc, argv, "hst:f:")) > 0) + { + switch (ch) + { + case 'h': + usage(argv[0]); + return (0); + case 's': + htmlFirst = true; + break; + case 't': + cmd = optarg; + break; + case 'f': + path = optarg; + break; + default: + break; + } + } + + logger_open("test.log", "mime", "all:1"); + + acl::mime mime; + + ////////////////////////////////////////////////////////////////////// + + if (cmd == "test0") + test_mime_header(mime, path.c_str()); + else if (cmd == "test1") + mime_test1(mime, path.c_str(), htmlFirst); + else if (cmd == "test2") + mime_test2(mime, path.c_str()); + else if (cmd == "test3") + mime_test3(mime, path.c_str()); + else if (cmd == "test4") + mime_test4(mime, path.c_str()); + else + printf(">>> unknown cmd: %s\n", cmd.c_str()); + + ////////////////////////////////////////////////////////////////////// + + printf("enter any key to exit\r\n"); + logger_close(); + getchar(); + return 0; +} diff --git a/lib_acl_cpp/samples/mime/mime.vcproj b/lib_acl_cpp/samples/mime/mime.vcproj new file mode 100644 index 000000000..8130805ef --- /dev/null +++ b/lib_acl_cpp/samples/mime/mime.vcproj @@ -0,0 +1,279 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_acl_cpp/samples/mime/mime.vcxproj b/lib_acl_cpp/samples/mime/mime.vcxproj new file mode 100644 index 000000000..d9c200b1b --- /dev/null +++ b/lib_acl_cpp/samples/mime/mime.vcxproj @@ -0,0 +1,203 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + Releasedll + Win32 + + + Release + Win32 + + + + {52AA7352-CE48-4F60-B92D-1EB16A79FE54} + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + true + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\include;..\..\mime;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Use + Level3 + ProgramDatabase + + + ws2_32.lib;lib_acl_vc2010d.lib;lib_acl_cpp_vc2010d.lib;%(AdditionalDependencies) + $(OutDir)mime.exe + ..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)mime.pdb + Console + MachineX86 + + + + + + true + + + + + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + Use + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;lib_acl_vc2010.lib;lib_acl_cpp_vc2010.lib;%(AdditionalDependencies) + $(OutDir)mime.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + + + + + + + Disabled + ..\..\include;..\..\mime;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Use + Level3 + ProgramDatabase + + + lib_acl_d.lib;lib_acl_cpp_d.lib;ws2_32.lib;%(AdditionalDependencies) + $(OutDir)mime.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)mime.pdb + Console + MachineX86 + + + + + Disabled + ..\..\include;..\..\mime;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDLL + Use + Level3 + ProgramDatabase + + + lib_acl.lib;lib_acl_cpp.lib;ws2_32.lib;%(AdditionalDependencies) + $(OutDir)mime.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)mime.pdb + Console + MachineX86 + + + + + + + + + + + Create + Create + Create + Create + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib_acl_cpp/samples/mime/mime_nest.in b/lib_acl_cpp/samples/mime/mime_nest.in new file mode 100644 index 000000000..26fd6dada --- /dev/null +++ b/lib_acl_cpp/samples/mime/mime_nest.in @@ -0,0 +1,69 @@ +content-type: multipart/mixed; boundary=foobar + +--foobar +content-type: multipart/mixed; boundary=foobar + +--foobar +content-type: multipart/mixed; boundary=foobar + +--foobar +content-type: multipart/mixed; boundary=foobar + +--foobar +content-type: multipart/mixed; boundary=foobar + +--foobar +content-type: multipart/mixed; boundary=foobar + +--foobar +content-type: multipart/mixed; boundary=foobar + +--foobar +content-type: multipart/mixed; boundary=foobar + +--foobar +content-type: multipart/mixed; boundary=foobar + +--foobar +content-type: multipart/mixed; boundary=foobar + +--foobar +content-type: multipart/mixed; boundary=foobar + +--foobar +content-type: multipart/mixed; boundary=foobar + +--foobar +content-type: multipart/mixed; boundary=foobar + +--foobar +content-type: multipart/mixed; boundary=foobar + +--foobar +content-type: multipart/mixed; boundary=foobar + +--foobar +content-type: multipart/mixed; boundary=foobar + +--foobar +content-type: multipart/mixed; boundary=foobar + +--foobar +content-type: multipart/mixed; boundary=foobar + +--foobar +content-type: multipart/mixed; boundary=foobar + +--foobar +content-type: multipart/mixed; boundary=foobar + +--foobar +content-type: multipart/mixed; boundary=foobar + +--foobar +content-type: multipart/mixed; boundary=foobar + +--foobar +content-type: multipart/mixed; boundary=foobar + +--foobar diff --git a/lib_acl_cpp/samples/mime/mime_vc2012.vcxproj b/lib_acl_cpp/samples/mime/mime_vc2012.vcxproj new file mode 100644 index 000000000..d28cacb74 --- /dev/null +++ b/lib_acl_cpp/samples/mime/mime_vc2012.vcxproj @@ -0,0 +1,208 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + Releasedll + Win32 + + + Release + Win32 + + + + {52AA7352-CE48-4F60-B92D-1EB16A79FE54} + Win32Proj + mime + + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + true + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\include;..\..\mime;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Use + Level3 + ProgramDatabase + + + ws2_32.lib;lib_acl_vc2012d.lib;lib_acl_cpp_vc2012d.lib;%(AdditionalDependencies) + $(OutDir)mime.exe + ..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)mime.pdb + Console + MachineX86 + + + + + + true + + + + + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + Use + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;lib_acl_vc2012.lib;lib_acl_cpp_vc2012.lib;%(AdditionalDependencies) + $(OutDir)mime.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + + + + + + + Disabled + ..\..\include;..\..\mime;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Use + Level3 + ProgramDatabase + + + lib_acl_d.lib;lib_acl_cpp_d.lib;ws2_32.lib;%(AdditionalDependencies) + $(OutDir)mime.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)mime.pdb + Console + MachineX86 + + + + + Disabled + ..\..\include;..\..\mime;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDLL + Use + Level3 + ProgramDatabase + + + lib_acl.lib;lib_acl_cpp.lib;ws2_32.lib;%(AdditionalDependencies) + $(OutDir)mime.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)mime.pdb + Console + MachineX86 + + + + + + + + + + + Create + Create + Create + Create + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib_acl_cpp/samples/mime/pipeline_string.cpp b/lib_acl_cpp/samples/mime/pipeline_string.cpp new file mode 100644 index 000000000..6cc47299f --- /dev/null +++ b/lib_acl_cpp/samples/mime/pipeline_string.cpp @@ -0,0 +1,70 @@ +#include "stdafx.h" +#include "pipeline_string.h" + +using namespace acl; + +pipeline_string::pipeline_string() +: strip_sp_(false) +{ + +} + +pipeline_string::~pipeline_string() +{ + +} + +void pipeline_string::clear() +{ + strip_sp_ = false; +} + +int pipeline_string::push_pop(const char* in, size_t len, + string* out, size_t /* = 0 */) +{ + int n = 0; + + // 有些邮件系统在组包时可能会因添加回车而把 + // 字符集弄乱了,所以此处尝试去年回车与行首 + // 空格,此纠错方式仅针对 HTML 格式的正文内容 + while (len > 0) + { + if ((*in) == '\r' || (*in) == '\n') + { + strip_sp_ = true; + in++; + len--; + while (len > 0 && (*in == '\r' || *in == '\n')) + { + in++; + len--; + } + } + else if (strip_sp_) + { + strip_sp_ = false; + while (len > 0 && (*in == ' ' || *in == '\t')) + { + in++; + len--; + } + } + else + { + (*out) << *((const unsigned char*) in); + in++; + len--; + n++; + } + + } + + return n; +} + +int pipeline_string::pop_end(string* out, size_t max /* = 0 */) +{ + (void) out; + (void) max; + return 0; +} diff --git a/lib_acl_cpp/samples/mime/pipeline_string.h b/lib_acl_cpp/samples/mime/pipeline_string.h new file mode 100644 index 000000000..32c395b6b --- /dev/null +++ b/lib_acl_cpp/samples/mime/pipeline_string.h @@ -0,0 +1,40 @@ +#pragma once +#include "acl_cpp/stdlib/pipe_stream.hpp" + +//class acl::string; + +class pipeline_string : public acl::pipe_stream +{ +public: + pipeline_string(); + ~pipeline_string(); + +protected: + /** + * 数据输入输出接口 + * @param in {const char*} 输入数据的地址 + * @param len {size_t} 输入数据长度 + * @param out {string*} 存储输出结果缓冲区,不能为空 + * @param max {size_t} 希望接收到输出结果的长度限制,如果为0则 + * 表示没有限制,输出结果都存储在 out 缓冲区中 + * @return {int} 输出数据的长度,如果 < 0 则表示出错 + */ + virtual int push_pop(const char* in, size_t len, + acl::string* out, size_t max = 0); + + /** + * 最后处理的输出数据接口 + * @param out {string*} 存储输出结果缓冲区,不能为空 + * @param max {size_t} 希望接收到输出结果的长度限制,如果为0则 + * 表示没有限制,输出结果都存储在 out 缓冲区中 + * @return {int} 输出数据的长度,如果 < 0 则表示出错 + */ + virtual int pop_end(acl::string* out, size_t max = 0); + + /** + * 清空内部缓冲区 + */ + virtual void clear(); +private: + bool strip_sp_; +}; diff --git a/lib_acl_cpp/samples/mime/stdafx.cpp b/lib_acl_cpp/samples/mime/stdafx.cpp new file mode 100644 index 000000000..f9a89d0fa --- /dev/null +++ b/lib_acl_cpp/samples/mime/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// mime.pch 将成为预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + +// TODO: 在 STDAFX.H 中 +//引用任何所需的附加头文件,而不是在此文件中引用 diff --git a/lib_acl_cpp/samples/mime/stdafx.h b/lib_acl_cpp/samples/mime/stdafx.h new file mode 100644 index 000000000..ec4c85075 --- /dev/null +++ b/lib_acl_cpp/samples/mime/stdafx.h @@ -0,0 +1,11 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是常用但不常更改的项目特定的包含文件 +// + +#pragma once + +// +//#include +//#include + +// TODO: 在此处引用程序要求的附加头文件 diff --git a/lib_acl_cpp/samples/mime/test1.eml b/lib_acl_cpp/samples/mime/test1.eml new file mode 100644 index 000000000..dd8b9d6d6 --- /dev/null +++ b/lib_acl_cpp/samples/mime/test1.eml @@ -0,0 +1,524 @@ +X-Uidl: 1285394662.10985_3.localhost&&mail.51iker.com +Return-Path: +Delivered-To: zhengshuxin@51iker.com +Received: by 51iker.com (zebra mail for UNIX, from userid 500) + id 769B2274687; Sat, 25 Sep 2010 14:04:22 +0800 (CST) +Date: Sat, 25 Sep 2010 06:04:22 GMT +From: 郑树新 +To: "zhengshuxin" +Subject: ddd +Mime-version: 1.0 +Content-Type: multipart/mixed; charset="GB2312"; boundary="=_0_10978_1285394661" +Message-Id: <20100925060422.769B2274687@51iker.com> + +This is a multi-part message in MIME format. + +--=_0_10978_1285394661 +Content-Type: text/html; charset="GB2312" +Content-Transfer-Encoding: base64 + +ZGRkZA== + + +--=_0_10978_1285394661 +Content-Type: application/octet-stream; + name="=?GB2312?B?uavKvS54bHN4?=" +Content-Disposition: attachment; + filename="=?GB2312?B?uavKvS54bHN4?=" +Content-Transfer-Encoding: base64 + +UEsDBBQABgAIAAAAIQA5GAaU8gEAAGgLAAATANQBW0NvbnRlbnRfVHlwZXNdLnhtbCCi0AEooAAC +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAMRWXW/aMBR9n7T/EPl1IoZ2m6aJ0Ae2Pm6V2v0A174QC8e2fN0W/v1uAkQlomHgaH0hfPmc ++3HO9Z3erCuTPUNA7WzBJvmYZWClU9ouC/bn4Xb0jWUYhVXCOAsF2wCym9nHD9OHjQfM6LTFgpUx ++u+coyyhEpg7D5Z+WbhQiUgfw5J7IVdiCfxqPP7KpbMRbBzFGoPNpj9gIZ5MzH6u6ettJI/asmy+ +/V9NVTDhvdFSRAqUP1vVIRm5xUJLUE4+VQSdow8gFJYAsTK5D5oYwz3ESIkh47Ppb0o6aAXZnQjx +l6iIga8Nj5QBbF8nOeWQFEQD9qlGeZsQ48YAJlMd5rsFPcEsS8ocefP4nByACuKFakvFbgDP4P7y +jtxX78h9/Z+5dx1CvnszWM/3vT5i4wAGz7PQblDkdLLxOpbaYw9Dv0f7vffiwurRuVVyIzruq6dO +Xglt93G/MWxq/mZEIW8e6R05DKTFPxHH60mQPvXOmwRdVQ7myBM5d3kHc2MfL11Pd8F55HSZJYsO +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 +NDi7Tm9y9oRpl7fnSGPanN02SmSh9MzZ9bVIh7fnSZh3eTud2Hu8vUTofc6eh+la+Uf6acD/2CLv +74a83Sb0EW+nJ23M2+n8NuHtDmn7lLfTJdqMszuGQ0bQnLPr89kLb6cL+QVvp5fikrPrix7X5f02 +WWi5GIxyrkm5o0944f6MhNuuOKdg0cEHOO65wD0Tpx3sUwn2a9hjsfWPQbh/I9wo8esEm1eOftU/ +xptdwju60+rV667Or/vjJXWALSDwetgowDtj3JARfYbNIZEKd3Lf/SDw365/7WAriwfbMLIGvF3Y ++n5w/QO4m/PqAzbQpM73ezj8ubWJ3pdkxJaZ8j8AAAD//wMAUEsDBBQABgAIAAAAIQA5MbWR2wAA +ANABAAAjAAAAeGwvd29ya3NoZWV0cy9fcmVscy9zaGVldDEueG1sLnJlbHOskc1qwzAMgO+DvoPR +vXbSwxijTi9j0OvaPYBnK4lZIhtLW9e3n3coLKWwy276QZ8+oe3ua57UJxaOiSy0ugGF5FOINFh4 +PT6vH0CxOApuSoQWzsiw61Z32xecnNQhHmNmVSnEFkaR/GgM+xFnxzplpNrpU5md1LQMJjv/7gY0 +m6a5N+U3A7oFU+2DhbIPG1DHc66b/2anvo8en5L/mJHkxgoTijvVyyrSlQHFgtaXGl+CVldlMLdt +2v+0ySWSYDmgSJXihdVVz1zlrX6L9CNpFn/ovgEAAP//AwBQSwMEFAAGAAgAAAAhAJuFhlxAAwAA +FAkAABgAAAB4bC93b3Jrc2hlZXRzL3NoZWV0Mi54bWyMVtty2yAQfe9M/4HhvbpatuOx3antOHGu +naaXZyohi6kkVCBx2q/vAooj4YymerClc3YPy8KyzD8+VyV6okIyXi9w6AUY0TrlGav3C/zt6/bD +FCOpSJ2Rktd0gf9QiT8u37+bH7j4JQtKFQKFWi5woVQz832ZFrQi0uMNrYHJuaiIgk+x92UjKMmM +U1X6URCM/YqwGluFmfgfDZ7nLKUbnj5WtFZWRNCSKIhfFqyReDnPGHB6QkjQfIE/hbP7GPvLuRn5 +O6MH2XlHeiI/Of+liV22wAEoSFrSVEsiAn9PdE3LEoRGkIvfVnOkBf2jYvf9RX1rpv5ZoIzm5LFU +X/jhkrJ9oSDPsZdogZSXYA2/qGI6/RhV5Nn8H1imCngD6CeVasu0F0bpo1S8+tGSJgarYSLZEEWW +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 +PYBnK4lZIhtLW9e3n3coLKWwy276QZ8+oe3ua57UJxaOiSxsdAMKyacQabDwenxeP4BicRTclAgt +nJFh163uti84OalDPMbMqlKILYwi+dEY9iPOjnXKSLXTpzI7qWkZTHb+3Q1o2qa5N+U3A7oFU+2D +hbIPLajjOdfNf7NT30ePT8l/zEhyY4UJxZ3qZRXpyoBiQetLjS9Bq6symNs2m/+0ySWSYDmgSJXi +hdVVz1zlrX6L9CNpFn/ovgEAAP//AwBQSwMEFAAGAAgAAAAhACbt6oe7AAAAJQEAACMAAAB4bC9k +cmF3aW5ncy9fcmVscy9kcmF3aW5nMi54bWwucmVsc4SPzQrCMBCE74LvEPZu0vYgIk16EaFX0QdY +0u0PtknIRtG3N+BFQfA07A77zU7dPJZZ3Cny5J2GUhYgyFnfTW7QcDkfNzsQnNB1OHtHGp7E0Jj1 +qj7RjCkf8TgFFpniWMOYUtgrxXakBVn6QC47vY8LpjzGQQW0VxxIVUWxVfGTAeaLKdpOQ2y7EsT5 +GXLyf7bv+8nSwdvbQi79iFB2xJgyEONASYOU7w2/pZL5WVCmVl/lzAsAAP//AwBQSwMEFAAGAAgA +AAAhAJqjvBLEAAAArQEAACMAAAB4bC9kcmF3aW5ncy9fcmVscy9kcmF3aW5nNC54bWwucmVsc7yQ +zwrCMAyH74LvUHK3nUNFZJ0XEXYVfYDQZX9wa0tTRd/egggKgjdPIQn5fh8ptrdxEFcK3DurYS4z +EGSNq3vbajgd97M1CI5oaxycJQ13YtiW00lxoAFjOuKu9ywSxbKGLka/UYpNRyOydJ5s2jQujBhT +G1rl0ZyxJZVn2UqFdwaUH0xR1RpCVecgjnefkn+zXdP0hnbOXEay8UuEMh2GmIAYWooapHxO+FmW +MsmC+u4x/5/H4uWhPp5cPgAAAP//AwBQSwMEFAAGAAgAAAAhAG1UidS9AAAAKwEAACMAAAB4bC93 +b3Jrc2hlZXRzL19yZWxzL3NoZWV0NC54bWwucmVsc4SPzQoCMQyE74LvUHK3XUVEZLteRPAq6wOE +NvuDu21p6t/b28uCguAtk5BvZsr9cxzEnSL33mlYygIEOeNt71oNl/q42ILghM7i4B1peBHDvprP +yjMNmPITd31gkSmONXQphZ1SbDoakaUP5PKl8XHElGVsVUBzxZbUqig2Kn4yoPpiipPVEE92CaJ+ +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 +idS9AAAAKwEAACMAAAAAAAAAAAAAAAAA0yIAAHhsL3dvcmtzaGVldHMvX3JlbHMvc2hlZXQ0Lnht +bC5yZWxzUEsBAi0AFAAGAAgAAAAhAAGIzwa7AAAAJQEAACMAAAAAAAAAAAAAAAAA0SMAAHhsL2Ry +YXdpbmdzL19yZWxzL2RyYXdpbmczLnhtbC5yZWxzUEsBAi0AFAAGAAgAAAAhAPxK3HvbAAAA0AEA +ACMAAAAAAAAAAAAAAAAAzSQAAHhsL3dvcmtzaGVldHMvX3JlbHMvc2hlZXQzLnhtbC5yZWxzUEsB +Ai0AFAAGAAgAAAAhAOj21sh4BAAA9hIAABQAAAAAAAAAAAAAAAAA6SUAAHhsL2NoYXJ0cy9jaGFy +dDQueG1sUEsBAi0AFAAGAAgAAAAhAPPCoGj4AQAADwcAABgAAAAAAAAAAAAAAAAAkyoAAHhsL2Ry +YXdpbmdzL2RyYXdpbmc0LnhtbFBLAQItABQABgAIAAAAIQAF59nzJwMAAEkJAAAUAAAAAAAAAAAA +AAAAAMEsAAB4bC9jaGFydHMvY2hhcnQzLnhtbFBLAQItABQABgAIAAAAIQDVNnv0pgEAAPQDAAAY +AAAAAAAAAAAAAAAAABowAAB4bC9kcmF3aW5ncy9kcmF3aW5nMS54bWxQSwECLQAUAAYACAAAACEA +wDrW1kwBAABCBQAAFAAAAAAAAAAAAAAAAAD2MQAAeGwvc2hhcmVkU3RyaW5ncy54bWxQSwECLQAU +AAYACAAAACEAHZr55ukCAADTCgAADQAAAAAAAAAAAAAAAAB0MwAAeGwvc3R5bGVzLnhtbFBLAQIt +ABQABgAIAAAAIQDQVdxPiQYAAFQbAAATAAAAAAAAAAAAAAAAAIg2AAB4bC90aGVtZS90aGVtZTEu +eG1sUEsBAi0AFAAGAAgAAAAhADORuEqrBgAA7RwAABQAAAAAAAAAAAAAAAAAQj0AAHhsL2NoYXJ0 +cy9jaGFydDEueG1sUEsBAi0AFAAGAAgAAAAhAGPRM+y9DAAAh0AAABgAAAAAAAAAAAAAAAAAH0QA +AHhsL3dvcmtzaGVldHMvc2hlZXQxLnhtbFBLAQItABQABgAIAAAAIQBw6dAmsQEAAPQDAAAYAAAA +AAAAAAAAAAAAABJRAAB4bC9kcmF3aW5ncy9kcmF3aW5nMi54bWxQSwECLQAUAAYACAAAACEAcMXK +XFUDAABkCgAAFAAAAAAAAAAAAAAAAAD5UgAAeGwvY2hhcnRzL2NoYXJ0Mi54bWxQSwECLQAUAAYA +CAAAACEAJ25LzrIBAAD1AwAAGAAAAAAAAAAAAAAAAACAVgAAeGwvZHJhd2luZ3MvZHJhd2luZzMu +eG1sUEsBAi0AFAAGAAgAAAAhACz/UXcgAwAA8RAAABAAAAAAAAAAAAAAAAAAaFgAAHhsL2NhbGND +aGFpbi54bWxQSwECLQAUAAYACAAAACEABcuMSkcAAABsAQAAJwAAAAAAAAAAAAAAAAC2WwAAeGwv +cHJpbnRlclNldHRpbmdzL3ByaW50ZXJTZXR0aW5nczMuYmluUEsBAi0AFAAGAAgAAAAhAEk0ylMo +AQAANAQAACcAAAAAAAAAAAAAAAAAQlwAAHhsL3ByaW50ZXJTZXR0aW5ncy9wcmludGVyU2V0dGlu +Z3MxLmJpblBLAQItABQABgAIAAAAIQAFy4xKRwAAAGwBAAAnAAAAAAAAAAAAAAAAAK9dAAB4bC9w +cmludGVyU2V0dGluZ3MvcHJpbnRlclNldHRpbmdzMi5iaW5QSwECLQAUAAYACAAAACEASk+xCUAB +AABRAgAAEQAAAAAAAAAAAAAAAAA7XgAAZG9jUHJvcHMvY29yZS54bWxQSwECLQAUAAYACAAAACEA +1mh9W64BAABaAwAAEAAAAAAAAAAAAAAAAACyYAAAZG9jUHJvcHMvYXBwLnhtbFBLBQYAAAAAIgAi +AHkJAACWYwAAAAA= + +--=_0_10978_1285394661-- + + diff --git a/lib_acl_cpp/samples/mime/test10.eml b/lib_acl_cpp/samples/mime/test10.eml new file mode 100644 index 000000000..d43927c92 --- /dev/null +++ b/lib_acl_cpp/samples/mime/test10.eml @@ -0,0 +1,100 @@ +Return-Path: +Delivered-To: zhengshuxin@51iker.com +Received: from iker-f954f96714 (unknown [123.122.116.217]) + by 51iker.com (zebra mail for UNIX) with ESMTP id 1450127465C + for ; Mon, 6 Dec 2010 18:11:43 +0800 (CST) +Date: Mon, 6 Dec 2010 18:09:46 +0800 +From: "zhengshuxin" +To: "zhengshuxin" +Subject: =?gb2312?B?se248dPKvP4=?= +Message-ID: <201012061809418902219@51iker.com> +X-mailer: Foxmail 6, 15, 201, 23 [cn] +Mime-Version: 1.0 +Content-Type: multipart/alternative; + boundary="=====003_Dragon438074882516_=====" + + +This is a multi-part message in MIME format. + +--=====003_Dragon438074882516_===== +Content-Type: text/plain; + charset="gb2312" +Content-Transfer-Encoding: base64 + +se248bHqzOIxserM4jKx6sziM7HqzOI0serM4jUNCtDVw/vE6sHk0NSx8LXY1rfTyrHgDQoNCg0K +MjAxMC0xMi0wNiANCg0KDQoNCnpoZW5nc2h1eGluIA0K + +--=====003_Dragon438074882516_===== +Content-Type: text/html; + charset="gb2312" +Content-Transfer-Encoding: base64 + +PCFET0NUWVBFIEhUTUwgUFVCTElDICItLy9XM0MvL0RURCBIVE1MIDQuMCBUcmFuc2l0aW9uYWwv +L0VOIj4NCjxIVE1MPjxIRUFEPg0KPE1FVEEgaHR0cC1lcXVpdj1Db250ZW50LVR5cGUgY29udGVu +dD0idGV4dC9odG1sOyBjaGFyc2V0PWdiMjMxMiI+DQo8TUVUQSBjb250ZW50PSJNU0hUTUwgNi4w +MC42MDAwLjE3MDgwIiBuYW1lPUdFTkVSQVRPUj48TElOSyANCmhyZWY9IkJMT0NLUVVPVEV7bWFy +Z2luLVRvcDogMHB4OyBtYXJnaW4tQm90dG9tOiAwcHg7IG1hcmdpbi1MZWZ0OiAyZW19IiANCnJl +bD1zdHlsZXNoZWV0PjwvSEVBRD4NCjxCT0RZIHN0eWxlPSJGT05ULVNJWkU6IDEwcHQ7IE1BUkdJ +TjogMTBweDsgRk9OVC1GQU1JTFk6IHZlcmRhbmEiPg0KPERJVj48Rk9OVCBmYWNlPVZlcmRhbmEg +c2l6ZT0yPg0KPFRBQkxFIA0Kc3R5bGU9IkJPUkRFUi1SSUdIVDogbWVkaXVtIG5vbmU7IEJPUkRF +Ui1UT1A6IG1lZGl1bSBub25lOyBGT05ULVNJWkU6IDEwcHQ7IEJPUkRFUi1MRUZUOiBtZWRpdW0g +bm9uZTsgQk9SREVSLUJPVFRPTTogbWVkaXVtIG5vbmU7IEJPUkRFUi1DT0xMQVBTRTogY29sbGFw +c2UiIA0KYm9yZGVyQ29sb3I9IzAwMDAwMCBjZWxsU3BhY2luZz0wIGNlbGxQYWRkaW5nPTIgd2lk +dGg9IjUwJSIgYm9yZGVyPTE+DQogIDxDQVBUSU9OPjxGT05UIGZhY2U9VmVyZGFuYSBzaXplPTU+ +PFNUUk9ORz6x7bjxPC9TVFJPTkc+PC9GT05UPjwvQ0FQVElPTj4NCiAgPFRCT0RZPg0KICA8VFI+ +DQogICAgPFREIA0KICAgIHN0eWxlPSJCT1JERVItUklHSFQ6ICMwMDAwMDAgMXB4IHNvbGlkOyBC +T1JERVItVE9QOiAjMDAwMDAwIDFweCBzb2xpZDsgQk9SREVSLUxFRlQ6ICMwMDAwMDAgMXB4IHNv +bGlkOyBCT1JERVItQk9UVE9NOiAjMDAwMDAwIDFweCBzb2xpZCIgDQogICAgbm9XcmFwIHdpZHRo +PSIyMCUiPjxGT05UIHN0eWxlPSJCQUNLR1JPVU5ELUNPTE9SOiAjZmYwMDAwIiBmYWNlPVZlcmRh +bmEgDQogICAgICBzaXplPTU+DQogICAgICA8RElWPrHqzOIxPC9ESVY+PC9GT05UPjwvVEQ+DQog +ICAgPFREIA0KICAgIHN0eWxlPSJCT1JERVItUklHSFQ6ICMwMDAwMDAgMXB4IHNvbGlkOyBCT1JE +RVItVE9QOiAjMDAwMDAwIDFweCBzb2xpZDsgQk9SREVSLUxFRlQ6ICMwMDAwMDAgMXB4IHNvbGlk +OyBCT1JERVItQk9UVE9NOiAjMDAwMDAwIDFweCBzb2xpZCIgDQogICAgbm9XcmFwIHdpZHRoPSIy +MCUiPjxGT05UIHN0eWxlPSJCQUNLR1JPVU5ELUNPTE9SOiAjZmYwMDAwIiBmYWNlPVZlcmRhbmEg +DQogICAgICBzaXplPTU+DQogICAgICA8RElWPrHqzOIyPC9ESVY+PC9GT05UPjwvVEQ+DQogICAg +PFREIA0KICAgIHN0eWxlPSJCT1JERVItUklHSFQ6ICMwMDAwMDAgMXB4IHNvbGlkOyBCT1JERVIt +VE9QOiAjMDAwMDAwIDFweCBzb2xpZDsgQk9SREVSLUxFRlQ6ICMwMDAwMDAgMXB4IHNvbGlkOyBC +T1JERVItQk9UVE9NOiAjMDAwMDAwIDFweCBzb2xpZCIgDQogICAgbm9XcmFwIHdpZHRoPSIyMCUi +PjxGT05UIHN0eWxlPSJCQUNLR1JPVU5ELUNPTE9SOiAjZmYwMDAwIiBmYWNlPVZlcmRhbmEgDQog +ICAgICBzaXplPTU+DQogICAgICA8RElWPrHqzOIzPC9ESVY+PC9GT05UPjwvVEQ+DQogICAgPFRE +IA0KICAgIHN0eWxlPSJCT1JERVItUklHSFQ6ICMwMDAwMDAgMXB4IHNvbGlkOyBCT1JERVItVE9Q +OiAjMDAwMDAwIDFweCBzb2xpZDsgQk9SREVSLUxFRlQ6ICMwMDAwMDAgMXB4IHNvbGlkOyBCT1JE +RVItQk9UVE9NOiAjMDAwMDAwIDFweCBzb2xpZCIgDQogICAgbm9XcmFwIHdpZHRoPSIyMCUiPjxG +T05UIHN0eWxlPSJCQUNLR1JPVU5ELUNPTE9SOiAjZmYwMDAwIiBmYWNlPVZlcmRhbmEgDQogICAg +ICBzaXplPTU+DQogICAgICA8RElWPrHqzOI0PC9ESVY+PC9GT05UPjwvVEQ+DQogICAgPFREIA0K +ICAgIHN0eWxlPSJCT1JERVItUklHSFQ6ICMwMDAwMDAgMXB4IHNvbGlkOyBCT1JERVItVE9QOiAj +MDAwMDAwIDFweCBzb2xpZDsgQk9SREVSLUxFRlQ6ICMwMDAwMDAgMXB4IHNvbGlkOyBCT1JERVIt +Qk9UVE9NOiAjMDAwMDAwIDFweCBzb2xpZCIgDQogICAgbm9XcmFwIHdpZHRoPSIyMCUiPjxGT05U +IHN0eWxlPSJCQUNLR1JPVU5ELUNPTE9SOiAjZmYwMDAwIiBmYWNlPVZlcmRhbmEgDQogICAgICBz +aXplPTU+DQogICAgICA8RElWPrHqzOI1PC9ESVY+PC9GT05UPjwvVEQ+PC9UUj4NCiAgPFRSPg0K +ICAgIDxURCANCiAgICBzdHlsZT0iQk9SREVSLVJJR0hUOiAjMDAwMDAwIDFweCBzb2xpZDsgQk9S +REVSLVRPUDogIzAwMDAwMCAxcHggc29saWQ7IEJPUkRFUi1MRUZUOiAjMDAwMDAwIDFweCBzb2xp +ZDsgQk9SREVSLUJPVFRPTTogIzAwMDAwMCAxcHggc29saWQiIA0KICAgIG5vV3JhcCB3aWR0aD0i +MjAlIj48Rk9OVCBmYWNlPVZlcmRhbmEgc2l6ZT01Pg0KICAgICAgPERJVj7Q1cP7PC9ESVY+PC9G +T05UPjwvVEQ+DQogICAgPFREIA0KICAgIHN0eWxlPSJCT1JERVItUklHSFQ6ICMwMDAwMDAgMXB4 +IHNvbGlkOyBCT1JERVItVE9QOiAjMDAwMDAwIDFweCBzb2xpZDsgQk9SREVSLUxFRlQ6ICMwMDAw +MDAgMXB4IHNvbGlkOyBCT1JERVItQk9UVE9NOiAjMDAwMDAwIDFweCBzb2xpZCIgDQogICAgbm9X +cmFwIHdpZHRoPSIyMCUiPjxGT05UIGZhY2U9VmVyZGFuYSBzaXplPTU+DQogICAgICA8RElWPsTq +weQ8L0RJVj48L0ZPTlQ+PC9URD4NCiAgICA8VEQgDQogICAgc3R5bGU9IkJPUkRFUi1SSUdIVDog +IzAwMDAwMCAxcHggc29saWQ7IEJPUkRFUi1UT1A6ICMwMDAwMDAgMXB4IHNvbGlkOyBCT1JERVIt +TEVGVDogIzAwMDAwMCAxcHggc29saWQ7IEJPUkRFUi1CT1RUT006ICMwMDAwMDAgMXB4IHNvbGlk +IiANCiAgICBub1dyYXAgd2lkdGg9IjIwJSI+PEZPTlQgZmFjZT1WZXJkYW5hIHNpemU9NT4NCiAg +ICAgIDxESVY+0NSx8DwvRElWPjwvRk9OVD48L1REPg0KICAgIDxURCANCiAgICBzdHlsZT0iQk9S +REVSLVJJR0hUOiAjMDAwMDAwIDFweCBzb2xpZDsgQk9SREVSLVRPUDogIzAwMDAwMCAxcHggc29s +aWQ7IEJPUkRFUi1MRUZUOiAjMDAwMDAwIDFweCBzb2xpZDsgQk9SREVSLUJPVFRPTTogIzAwMDAw +MCAxcHggc29saWQiIA0KICAgIG5vV3JhcCB3aWR0aD0iMjAlIj48Rk9OVCBmYWNlPVZlcmRhbmEg +c2l6ZT01Pg0KICAgICAgPERJVj612Na3PC9ESVY+PC9GT05UPjwvVEQ+DQogICAgPFREIA0KICAg +IHN0eWxlPSJCT1JERVItUklHSFQ6ICMwMDAwMDAgMXB4IHNvbGlkOyBCT1JERVItVE9QOiAjMDAw +MDAwIDFweCBzb2xpZDsgQk9SREVSLUxFRlQ6ICMwMDAwMDAgMXB4IHNvbGlkOyBCT1JERVItQk9U +VE9NOiAjMDAwMDAwIDFweCBzb2xpZCIgDQogICAgbm9XcmFwIHdpZHRoPSIyMCUiPjxGT05UIGZh +Y2U9VmVyZGFuYSBzaXplPTU+DQogICAgICA8RElWPtPKseA8L0RJVj48L0ZPTlQ+PC9URD48L1RS +PjwvVEJPRFk+PC9UQUJMRT48L0ZPTlQ+PC9ESVY+DQo8RElWPjxGT05UIGZhY2U9VmVyZGFuYSBz +aXplPTI+PC9GT05UPiZuYnNwOzwvRElWPg0KPERJViBhbGlnbj1sZWZ0PjxGT05UIGZhY2U9VmVy +ZGFuYSBjb2xvcj0jYzBjMGMwIHNpemU9Mj4yMDEwLTEyLTA2IA0KPC9GT05UPjwvRElWPjxGT05U +IGZhY2U9VmVyZGFuYSBzaXplPTI+DQo8SFIgc3R5bGU9IldJRFRIOiAxMjJweDsgSEVJR0hUOiAy +cHgiIGFsaWduPWxlZnQgU0laRT0yPg0KDQo8RElWPjxGT05UIGZhY2U9VmVyZGFuYSBjb2xvcj0j +YzBjMGMwIHNpemU9Mj48U1BBTj56aGVuZ3NodXhpbjwvU1BBTj4gDQo8L0ZPTlQ+PC9ESVY+PC9G +T05UPjwvQk9EWT48L0hUTUw+DQo= + +--=====003_Dragon438074882516_=====-- + diff --git a/lib_acl_cpp/samples/mime/test11.eml b/lib_acl_cpp/samples/mime/test11.eml new file mode 100644 index 000000000..f1d77901d --- /dev/null +++ b/lib_acl_cpp/samples/mime/test11.eml @@ -0,0 +1,561 @@ +Received: from mta8.263.net (mx3sym3 [127.0.0.1]) + by mta7.263.net (Postfix) with ESMTP id C611685746D + for ; Tue, 7 Dec 2010 03:03:47 +0800 (CST) +X-KSVirus-check:0 +X-ABS-CHECKED:0 +Received: from n62.eefocus.com (mx3sym3 [127.0.0.1]) + by mta8.263.net (Postfix) with ESMTP id 74414D069E + for ; Tue, 7 Dec 2010 03:03:47 +0800 (CST) +X-SENDER-IP:211.100.26.62 +X-LOGIN-NAME: +X-ATTACHMENT-NUM:0 +X-SENDER:newsletter@n62.eefocus.com +X-DNS-TYPE:1 +Received: from n62.eefocus.com (n62.eefocus.com [211.100.26.62]) + by mta8.263.net (Postfix) whith ESMTP id 221076NYS49; + Tue, 07 Dec 2010 03:03:47 +0800 (CST) +Received: from localhost.localdomain (unknown [211.100.26.57]) + by n62.eefocus.com (Postfix) with ESMTPA id EBF9EBE91B + for ; Tue, 7 Dec 2010 03:02:50 +0800 (CST) +Date: Mon, 6 Dec 2010 19:03:26 +0000 +To: whouseit +From: =?utf-8?B?5LiO6Z2e572R?= +Reply-to: =?utf-8?B?5LiO6Z2e572R?= +Subject: =?utf-8?B?5LiA6aKX54OC6Iu55p6c5byV5Y+R55qE6KGA5qGI44CQ5LiO6Z2e572R5q+P5ZGo6YCf6YCSIE5vLjE1MeOAkQ==?= +Message-ID: +X-Priority: 3 +X-Mailer: PHPMailer (phpmailer.sourceforge.net) [version 2.0.0 rc1] +MIME-Version: 1.0 +Content-Transfer-Encoding: base64 +Content-Type: text/html; charset="utf-8" + +PCFET0NUWVBFIGh0bWwgUFVCTElDICItLy9XM0MvL0RURCBYSFRNTCAxLjAgVHJhbnNpdGlvbmFs +Ly9FTiIgImh0dHA6Ly93d3cudzMub3JnL1RSL3hodG1sMS9EVEQveGh0bWwxLXRyYW5zaXRpb25h +bC5kdGQiPg0KPGh0bWwgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGh0bWwiPg0KPGhl +YWQ+DQo8bWV0YSBodHRwLWVxdWl2PSJDb250ZW50LVR5cGUiIGNvbnRlbnQ9InRleHQvaHRtbDsg +Y2hhcnNldD11dGYtOCIgLz4NCjx0aXRsZT7kuI7pnZ7nvZHmr4/lkajnlLXlrZDotYTorq88L3Rp +dGxlPg0KPHN0eWxlIHR5cGU9InRleHQvY3NzIj4NCjwhLS0NCmJvZHkgeyBtYXJnaW46MDtmb250 +LXNpemU6MTJweDt9DQouZWN4ZXhwbGFpbnsgd2lkdGg6NzkycHg7IG1hcmdpbjowIGF1dG87IGJh +Y2tncm91bmQ6I2ZmZjsgdGV4dC1pbmRlbnQ6MjBweDt9DQouZWN4ZXhwbGFpbiBhLC5lY3hleHBs +YWluIGE6aG92ZXJ7IGNvbG9yOiMxMDU0OTE7fQ0KLS0+DQo8L3N0eWxlPg0KPC9oZWFkPg0KDQo8 +Ym9keSBzdHlsZT0id2lkdGg6NzYwcHg7IG1hcmdpbjowIGF1dG87Ij4NCjx0YWJsZSB3aWR0aD0i +NzYwIiBib3JkZXI9IjAiIGFsaWduPSJjZW50ZXIiIGNlbGxwYWRkaW5nPSIxMCIgY2VsbHNwYWNp +bmc9IjAiIGJnY29sb3I9IiNGRkZGRkYiPg0KICA8dHI+DQogICAgPHRkIHN0eWxlPSJmb250LXNp +emU6MzBweDtmb250LXdlaWdodDpib2xkOyI+5LiO6Z2e572R5q+P5ZGo55S15a2Q6LWE6K6vPC90 +ZD4NCg0KICAgIDx0ZCBzdHlsZT0iZm9udC1zaXplOjEycHg7Ij48Zm9ybSBhY3Rpb249Imh0dHA6 +Ly93d3cuZGF0YXNoZWV0NS5jb20vdmlld3MtTUFYMjMyLUFsbC5odG1sIiBtZXRob2Q9InBvc3Qi +IHRhcmdldD0iX2JsYW5rIj48ZGl2IGFsaWduPSJyaWdodCI+DQogICAgICAgIDxpbnB1dCBpZD0i +VGV4dEJveDEiIG5hbWU9IlRleHRCb3gxIiB0eXBlPSJ0ZXh0IiB2YWx1ZT0iTUFYMjMyIiBzdHls +ZT0iY29sb3I6Izk5OTsgd2lkdGg6MjQwcHg7YmFja2dyb3VuZDojRkZGRkZBIG5vbmUgcmVwZWF0 +IHNjcm9sbCAwIDA7dGV4dC1pbmRlbnQ6IDhweDsgaGVpZ2h0OjE2cHg7IGxpbmUtaGVpZ2h0OjE2 +cHg7dmVydGljYWwtYWxpZ246bWlkZGxlOyIvPiANCiAgICAgICAgPGlucHV0IG5hbWU9IuaPkOS6 +pCIgdHlwZT0ic3VibWl0IiBzdHlsZT0idmVydGljYWwtYWxpZ246bWlkZGxlOyIgdmFsdWU9IuWF +g+S7tuafpeivoiAiLz4NCiAgICA8L2Rpdj48L2Zvcm0+PC90ZD4NCiAgPC90cj4NCjwvdGFibGU+ +DQo8dGFibGUgd2lkdGg9Ijc2MCIgYm9yZGVyPSIwIiBhbGlnbj0iY2VudGVyIiBjZWxscGFkZGlu +Zz0iOCIgY2VsbHNwYWNpbmc9IjAiIGJnY29sb3I9IiNDQzAwMDAiPg0KICA8dHI+DQogICAgPHRk +IHN0eWxlPSIgY29sb3I6I2ZmZjtmb250LXNpemU6MTJweDsiPjIwMTDlubQxMuaciDAy5pel44CA +56ysMTUx5pyf44CARUVGT0NVU+e8lui+kemDqDwvdGQ+DQogICAgPHRkIHN0eWxlPSIgY29sb3I6 +I2ZmZjtmb250LXNpemU6MTJweDsiPjxkaXYgYWxpZ249InJpZ2h0Ij48YSBocmVmPSJodHRwOi8v +YW5hbHl0aWNzLmVlZm9jdXMuY29tL2NsaWNrL2VETV83MjZfODk0QkY3RDVEMkRFQ0QxOC8/dXJs +PWh0dHAlM0ElMkYlMkZ3d3cuZWVmb2N1cy5jb20lMkYiIHRhcmdldD0iX2JsYW5rIiBzdHlsZT0i +Y29sb3I6I2ZmZjsiPuS4jumdnue9kemmlumhtTwvYT4gfCA8YSBocmVmPSJodHRwOi8vYW5hbHl0 +aWNzLmVlZm9jdXMuY29tL2NsaWNrL2VETV83MjZfODk0QkY3RDVEMkRFQ0QxOC8/dXJsPWh0dHAl +M0ElMkYlMkZ3d3cuZWVmb2N1cy5jb20lMkZwYXNzcG9ydCUyRmluZGV4LnBocCUzRmFjdCUzRHJl +Z2lzdGVyIiB0YXJnZXQ9Il9ibGFuayIgc3R5bGU9ImNvbG9yOiNmZmY7Ij7liqDlhaXkuI7pnZ7n +vZHlj4rnpL7ljLrnvqQ8L2E+IHwgPGEgaHJlZj0iaHR0cDovL2FuYWx5dGljcy5lZWZvY3VzLmNv +bS9jbGljay9lRE1fNzI2Xzg5NEJGN0Q1RDJERUNEMTgvP3VybD1odHRwJTNBJTJGJTJGd3d3LmVl +Zm9jdXMuY29tJTJGdmVuZG9yJTJGIiB0YXJnZXQ9Il9ibGFuayIgc3R5bGU9ImNvbG9yOiNmZmY7 +Ij7kuI7pnZ7npL7ljLo8L2E+IDwvZGl2PjwvdGQ+DQoNCiAgPC90cj4NCjwvdGFibGU+DQo8dGFi +bGUgd2lkdGg9Ijc2MCIgYm9yZGVyPSIwIiBhbGlnbj0iY2VudGVyIiBjZWxscGFkZGluZz0iMCIg +Y2VsbHNwYWNpbmc9IjAiIHN0eWxlPSJtYXJnaW46NnB4IGF1dG87Ij4NCiAgPHRyPg0KICAgIDx0 +ZCBiYWNrZ3JvdW5kPSJodHRwOi8vd3d3LmVlZm9jdXMuY29tL2ltYWdlcy9waWMveGlsaW54MDEy +Ml83NjA5MC5naWYiIGhlaWdodD0iOTAiPjxhIGhyZWY9Imh0dHA6Ly9hbmFseXRpY3MuZWVmb2N1 +cy5jb20vY2xpY2svZURNXzcyNl84OTRCRjdENUQyREVDRDE4Lz91cmw9aHR0cCUzQSUyRiUyRnhp +bGlueC5lZWZvY3VzLmNvbSUyRnRlbXBsYXRlJTJGeGlsaW54JTJGYmxvZ19tYXRjaC5odG1sIiB0 +YXJnZXQ9Il9ibGFuayI+PGltZyBzcmM9Imh0dHA6Ly93d3cuZWVmb2N1cy5jb20vaW1hZ2VzL3Bp +Yy94aWxpbngwMTIyXzc2MDkwLmdpZiIgYm9yZGVyPSIwIiAvPjwvYT48L3RkPg0KICA8L3RyPg0K +PC90YWJsZT4NCjx0YWJsZSB3aWR0aD0iNzYwIiBib3JkZXI9IjAiIGFsaWduPSJjZW50ZXIiIGNl +bGxwYWRkaW5nPSIwIiBjZWxsc3BhY2luZz0iMCI+DQoNCiAgPHRyPg0KICAgIDx0ZCB3aWR0aD0i +NDkwIiB2YWxpZ249InRvcCIgYmdjb2xvcj0iI0ZGRkZGRiIgc3R5bGU9ImJvcmRlci1yaWdodDox +cHggc29saWQgI2NjYzsgcGFkZGluZy1yaWdodDo4cHg7Ij48dGFibGUgd2lkdGg9IjEwMCUiIGJv +cmRlcj0iMCIgYWxpZ249ImNlbnRlciIgY2VsbHBhZGRpbmc9IjAiIGNlbGxzcGFjaW5nPSIwIj4N +CiAgICAgIDx0cj4NCiAgICAgICAgPHRkIGhlaWdodD0iMjQiIGJnY29sb3I9IiNFRUVFRUUiPjxi +IHN0eWxlPSJsaW5lLWhlaWdodDoyNHB4OyBwYWRkaW5nLWxlZnQ6MTBweDtmb250LXNpemU6MTRw +eDsgY29sb3I6IzkwMDsiPuaWsOmXu+WktOadoTwvYj48L3RkPg0KDQogICAgICA8L3RyPg0KICAg +ICAgPHRyPg0KICAgICAgICA8dGQgc3R5bGU9InBhZGRpbmctbGVmdDoxMHB4OyI+PGEgaHJlZj0i +aHR0cDovL2FuYWx5dGljcy5lZWZvY3VzLmNvbS9jbGljay9lRE1fNzI2Xzg5NEJGN0Q1RDJERUNE +MTgvP3VybD1odHRwJTNBJTJGJTJGd3d3LmVlZm9jdXMuY29tJTJGbGVzbGllMjA3NCUyRmJsb2cl +MkYxMC0xMiUyRjE5OTYzM181MjM4ZC5odG1sIiB0YXJnZXQ9Il9ibGFuayIgc3R5bGU9ImNvbG9y +OiMxMDU0OTE7IGZvbnQtd2VpZ2h0OmJvbGQ7IGxpbmUtaGVpZ2h0OjMwcHg7Zm9udC1zaXplOjEy +cHg7IiB0aXRsZT0iIj7kuIDpopfng4Loi7nmnpzlvJXlj5HnmoTooYDmoYg8L2E+PC90ZD4NCiAg +ICAgIDwvdHI+DQogICAgICA8dHI+DQogICAgICAgIDx0ZCAgc3R5bGU9InBhZGRpbmctbGVmdDox +MHB4OyBjb2xvcjojMzMzOyBsaW5lLWhlaWdodDoyMHB4O2ZvbnQtc2l6ZToxMnB4OyI+PGEgaHJl +Zj0iaHR0cDovL2FuYWx5dGljcy5lZWZvY3VzLmNvbS9jbGljay9lRE1fNzI2Xzg5NEJGN0Q1RDJE +RUNEMTgvP3VybD1odHRwJTNBJTJGJTJGd3d3LmVlZm9jdXMuY29tJTJGbGVzbGllMjA3NCUyRmJs +b2clMkYxMC0xMiUyRjE5OTYzM181MjM4ZC5odG1sIiB0YXJnZXQ9Il9ibGFuayIgc3R5bGU9ImNv +bG9yOiMzMzM7IHRleHQtZGVjb3JhdGlvbjpub25lOyI+5o2u6K+077yM6L+Z5piv5LiW5LiK5pyA +6YGl6L+c6Led56a755qE5pyA5paw54mI5pys77ya5Lik5Liq5Lq65LiA6LW35omL54m15omL5Ye6 +6Zeo77yM5ZCR5bem6L2s77yM5L2g5Y675Lmw6Iu55p6c5Zub5Luj77yM5ZCR5Y+z6L2s77yM5oiR +5Y675Lmw5Zub6KKL6Iu55p6c44CC56eB5LiL6YeM5oiR5LiA55u05reh5a6a55qE5Lul5Li677yM +aVBob25l5Zyo5rCR6Ze054ix5oCO5LmI55av6YO95LiN5Li66L+H77yM5q+V56uf6YKj6YO95piv +5LiA576k5rKh6KeB6L+H5LiW6Z2i55qEUOawkeWYm+OAguS9huaYr++8jOiHs+S7iuS7pOaIkeaX +oOazleebuOS/oeeahOaYr+KApuKApjwvYT48L3RkPg0KICAgICAgPC90cj4NCiAgICA8L3RhYmxl +Pg0KDQogICAgICA8dGFibGUgd2lkdGg9IjEwMCUiIGJvcmRlcj0iMCIgYWxpZ249ImNlbnRlciIg +Y2VsbHBhZGRpbmc9IjAiIGNlbGxzcGFjaW5nPSIwIiBzdHlsZT0iIG1hcmdpbi10b3A6MTBweDsi +Pg0KICAgICAgICA8dHI+DQogICAgICAgICAgPHRkIGhlaWdodD0iMjQiIGJnY29sb3I9IiNFRUVF +RUUiPjxiIHN0eWxlPSJsaW5lLWhlaWdodDoyNHB4OyBwYWRkaW5nLWxlZnQ6MTBweDtmb250LXNp +emU6MTRweDsgY29sb3I6IzkwMDsiPue8lui+keaOqOiNkDwvYj48L3RkPg0KICAgICAgICA8L3Ry +Pg0KICAgICAgICA8dHI+DQogICAgICAgICAgPHRkIHN0eWxlPSJwYWRkaW5nLWxlZnQ6MTBweDsi +PjxhIGhyZWY9Imh0dHA6Ly9hbmFseXRpY3MuZWVmb2N1cy5jb20vY2xpY2svZURNXzcyNl84OTRC +RjdENUQyREVDRDE4Lz91cmw9aHR0cCUzQSUyRiUyRnd3dy5lZWZvY3VzLmNvbSUyRnBvd2VyZW4l +MkZibG9nJTJGMTAtMTElMkYxOTkzNTRfYzYxYTcuaHRtbCIgdGFyZ2V0PSJfYmxhbmsiIHN0eWxl +PSJjb2xvcjojMTA1NDkxOyBmb250LXdlaWdodDpib2xkOyBsaW5lLWhlaWdodDozMHB4O2ZvbnQt +c2l6ZToxMnB4OyIgdGl0bGU9IiI+5ZCs5YeM5Yqb5bCU54m56auY566h6K+06K+055S15rqQ6YKj +5Lqb5LqL5YS/PC9hPjwvdGQ+DQogICAgICAgIDwvdHI+DQoNCiAgICAgICAgPHRyPg0KICAgICAg +ICAgIDx0ZCAgc3R5bGU9InBhZGRpbmctbGVmdDoxMHB4OyBjb2xvcjojMzMzOyBsaW5lLWhlaWdo +dDoyMHB4O2ZvbnQtc2l6ZToxMnB4OyI+PGEgaHJlZj0iaHR0cDovL2FuYWx5dGljcy5lZWZvY3Vz +LmNvbS9jbGljay9lRE1fNzI2Xzg5NEJGN0Q1RDJERUNEMTgvP3VybD1odHRwJTNBJTJGJTJGd3d3 +LmVlZm9jdXMuY29tJTJGcG93ZXJlbiUyRmJsb2clMkYxMC0xMSUyRjE5OTM1NF9jNjFhNy5odG1s +IiB0YXJnZXQ9Il9ibGFuayIgc3R5bGU9ImNvbG9yOiMzMzM7IHRleHQtZGVjb3JhdGlvbjpub25l +OyI+5Lu75L2V57O757uf5Lit55qE5Yqf6ICX6YO95b+F6aG75Lul5Lik56eN5pa55byP6Kej5Yaz +77yM6aaW5YWI77yM6Leo5pW05Liq6LSf6L2955S15rWB6IyD5Zu05pyA5aSn6ZmQ5bqm5Zyw5o+Q +6auY6L2s5o2i5pWI546H77yM5YW25qyh77yM6ZmN5L2OIERDL0RDIOi9rOaNouWZqOWcqOaJgOac +ieW3peS9nOaooeW8j+aXtueahOmdmeaAgeeUtea1geKApuKApjwvYT48L3RkPg0KICAgICAgICA8 +L3RyPg0KCQkgPHRyPg0KICAgICAgICAgIDx0ZCBzdHlsZT0icGFkZGluZy1sZWZ0OjEwcHg7Ij48 +YSBocmVmPSJodHRwOi8vYW5hbHl0aWNzLmVlZm9jdXMuY29tL2NsaWNrL2VETV83MjZfODk0QkY3 +RDVEMkRFQ0QxOC8/dXJsPWh0dHAlM0ElMkYlMkZ3d3cuZWVmb2N1cy5jb20lMkZnYWRnZXQlMkZi +bG9nJTJGMTAtMTIlMkYxOTk2NDVfNGVjMzguaHRtbCIgdGFyZ2V0PSJfYmxhbmsiIHN0eWxlPSJj +b2xvcjojMTA1NDkxOyBmb250LXdlaWdodDpib2xkOyBsaW5lLWhlaWdodDozMHB4O2ZvbnQtc2l6 +ZToxMnB4OyIgdGl0bGU9IiI+TWVlR2/ot6/lnKjkvZXmlrnvvJ88L2E+PC90ZD4NCiAgICAgICAg +PC90cj4NCiAgICAgICAgPHRyPg0KICAgICAgICAgIDx0ZCAgc3R5bGU9InBhZGRpbmctbGVmdDox +MHB4OyBjb2xvcjojMzMzOyBsaW5lLWhlaWdodDoyMHB4O2ZvbnQtc2l6ZToxMnB4OyI+PGEgaHJl +Zj0iaHR0cDovL2FuYWx5dGljcy5lZWZvY3VzLmNvbS9jbGljay9lRE1fNzI2Xzg5NEJGN0Q1RDJE +RUNEMTgvP3VybD1odHRwJTNBJTJGJTJGd3d3LmVlZm9jdXMuY29tJTJGZ2FkZ2V0JTJGYmxvZyUy +RjEwLTEyJTJGMTk5NjQ1XzRlYzM4Lmh0bWwiIHRhcmdldD0iX2JsYW5rIiBzdHlsZT0iY29sb3I6 +IzMzMzsgdGV4dC1kZWNvcmF0aW9uOm5vbmU7Ij5NZWVHb+aYr+S4gOS4quW+iOaciei2o+eahOaW +sOeUn+S7o+enu+WKqOezu+e7n+W5s+WPsO+8jOS9huaYr+ebruWJjei/mOayoeacieaJi+acuuWP +r+S7peWuieijheWwneivle+8jOaJgOS7peW+iOmavuWIpOaWrei/meS4quezu+e7n+aYr+WQpuaL +peaciei2s+Wkn+eahOa9nOWKm+WcqOW4guWcuuS4reeqgeWbtOOAguaLpeaciUludGVs5ZKM6K+6 +5Z+65Lqa5Lik5Liq4oCm4oCmPC9hPjwvdGQ+DQogICAgICAgIDwvdHI+DQoJCTx0cj4NCgkJICA8 +dGQ+PHRhYmxlIHdpZHRoPSI0NDciIGJvcmRlcj0iMCIgYWxpZ249ImNlbnRlciIgY2VsbHBhZGRp +bmc9IjUiIGNlbGxzcGFjaW5nPSIwIiBzdHlsZT0ibWFyZ2luOjEwcHggMDsgYmFja2dyb3VuZDoj +RkFGQUZBOyBib3JkZXI6MXB4IHNvbGlkICNERkRGREY7Ij4NCiAgICAgICAgICAgIDx0cj4NCiAg +ICAgICAgICAgICAgPHRkIHdpZHRoPSI3OCIgdmFsaWduPSJ0b3AiPjxiIHN0eWxlPSIgY29sb3I6 +IzkwMDsgbGluZS1oZWlnaHQ6MjBweDtmb250LXNpemU6MTJweDsiPuOAkOeDreeCuea0u+WKqOOA +kTwvYj48L3RkPg0KICAgICAgICAgICAgICA8dGQgdmFsaWduPSJ0b3AiIHN0eWxlPSJsaW5lLWhl +aWdodDoyMHB4OyI+PGEgaHJlZj0iaHR0cDovL2FuYWx5dGljcy5lZWZvY3VzLmNvbS9jbGljay9l +RE1fNzI2Xzg5NEJGN0Q1RDJERUNEMTgvP3VybD1odHRwJTNBJTJGJTJGd3d3LmVlZm9jdXMuY29t +JTJGc3VydmV5JTJGNTgiIHRhcmdldD0iX2JsYW5rIiB0aXRsZT0iIiBzdHlsZT0iY29sb3I6IzEw +NTQ5MTtmb250LXNpemU6MTJweDsiPlJG56S+5Yy6MjAxMeW5tOe6v+S4i+a0u+WKqOaEj+WQkeiw +g+afpTwvYT48YnIgLz4NCiAgICAgICAgICAgICAgICA8YSBocmVmPSJodHRwOi8vYW5hbHl0aWNz +LmVlZm9jdXMuY29tL2NsaWNrL2VETV83MjZfODk0QkY3RDVEMkRFQ0QxOC8/dXJsPWh0dHAlM0El +MkYlMkZ3d3cuZWVmb2N1cy5jb20lMkZzdXJ2ZXklMkY1NyIgdGFyZ2V0PSJfYmxhbmsiIHRpdGxl +PSIiIHN0eWxlPSJjb2xvcjojMTA1NDkxO2ZvbnQtc2l6ZToxMnB4OyI+UmFtdHJvbuiHquWKqOa4 +qeihpeaXtumSn+aZtueJh+agt+eJh+eUs+ivtzwvYT48YnIgLz4NCg0KICAgICAgICAgICAgICAg +IDxhIGhyZWY9Imh0dHA6Ly9hbmFseXRpY3MuZWVmb2N1cy5jb20vY2xpY2svZURNXzcyNl84OTRC +RjdENUQyREVDRDE4Lz91cmw9aHR0cCUzQSUyRiUyRnd3dy5lZWZvY3VzLmNvbSUyRmFsbGtub3cl +MkZibG9nJTJGMTAtMTElMkYxOTkzMDZfYzk3NDQuaHRtbCIgdGFyZ2V0PSJfYmxhbmsiIHRpdGxl +PSIiIHN0eWxlPSJjb2xvcjojMTA1NDkxO2ZvbnQtc2l6ZToxMnB4OyI+44CQ5pyJ5aWW56ue54yc +MTLmnJ/jgJHnlLvlm77lt6XlhbfpgqPkupvkuovlhL88L2E+PC90ZD4NCiAgICAgICAgICAgIDwv +dHI+DQogICAgICAgICAgPC90YWJsZT48L3RkPg0KCSAgICA8L3RyPg0KCQk8dHI+DQoJCSAgPHRk +IHN0eWxlPSJwYWRkaW5nLWxlZnQ6MTBweDsiPg0KCQkgIDx1bCBzdHlsZT0iIGxpc3Qtc3R5bGUt +dHlwZTpub25lO21hcmdpbjowOyBwYWRkaW5nOjA7IGxpbmUtaGVpZ2h0OjI0cHg7ICI+DQoJCQk8 +bGkgc3R5bGU9ImJhY2tncm91bmQ6dXJsKGh0dHA6Ly93d3cuZWVmb2N1cy5jb20vaW1hZ2VzL2Rv +dC5naWYpIG5vLXJlcGVhdCBsZWZ0IDVweDsgcGFkZGluZy1sZWZ0OjE1cHg7Zm9udC1zaXplOjEy +cHg7Ij48YSBocmVmPSJodHRwOi8vYW5hbHl0aWNzLmVlZm9jdXMuY29tL2NsaWNrL2VETV83MjZf +ODk0QkY3RDVEMkRFQ0QxOC8/dXJsPWh0dHAlM0ElMkYlMkZ3d3cuZWVmb2N1cy5jb20lMkZsaXpo +YW8lMkZibG9nJTJGMTAtMTIlMkYxOTk1ODJfNmI4ZGMuaHRtbCIgdGFyZ2V0PSJfYmxhbmsiIHRp +dGxlPSIiIHN0eWxlPSJjb2xvcjojMTA1NDkxO2ZvbnQtc2l6ZToxMnB4OyI+44CQ5bWM5YWl57O7 +57uf44CR6K+E6K6677ya5omL5py65Y6C5ZWG56Gs5Lu25Y2H57qn5o2i5Luj5q2l5LyQ5piO5pi+ +5YGP57yTPC9hPjwvbGk+DQoNCgkJCTxsaSBzdHlsZT0iYmFja2dyb3VuZDp1cmwoaHR0cDovL3d3 +dy5lZWZvY3VzLmNvbS9pbWFnZXMvZG90LmdpZikgbm8tcmVwZWF0IGxlZnQgNXB4OyBwYWRkaW5n +LWxlZnQ6MTVweDtmb250LXNpemU6MTJweDsiPjxhIGhyZWY9Imh0dHA6Ly9hbmFseXRpY3MuZWVm +b2N1cy5jb20vY2xpY2svZURNXzcyNl84OTRCRjdENUQyREVDRDE4Lz91cmw9aHR0cCUzQSUyRiUy +Rm5ld3MuZWVmb2N1cy5jb20lMkZhcnRpY2xlJTJGMTAtMTElMkYyNjEyOTEwMTQ5OTYuaHRtbCUz +RnNvcnQlM0QxNzcxXzE3NzNfMF8wIiB0YXJnZXQ9Il9ibGFuayIgdGl0bGU9IiIgc3R5bGU9ImNv +bG9yOiMxMDU0OTE7Zm9udC1zaXplOjEycHg7Ij7jgJDnvZHnu5zpgJrkv6HjgJHlr4zlo6vpgJrm +raPlvI/mjqjlh7rnp4HmnInkupHmnI3liqE8L2E+PC9saT4NCgkJCTxsaSBzdHlsZT0iYmFja2dy +b3VuZDp1cmwoaHR0cDovL3d3dy5lZWZvY3VzLmNvbS9pbWFnZXMvZG90LmdpZikgbm8tcmVwZWF0 +IGxlZnQgNXB4OyBwYWRkaW5nLWxlZnQ6MTVweDtmb250LXNpemU6MTJweDsiPjxhIGhyZWY9Imh0 +dHA6Ly9hbmFseXRpY3MuZWVmb2N1cy5jb20vY2xpY2svZURNXzcyNl84OTRCRjdENUQyREVDRDE4 +Lz91cmw9aHR0cCUzQSUyRiUyRmF2ci5lZWZvY3VzLmNvbSUyRmFydGljbGUlMkYxMC0xMSUyRjgz +MzE0MTI5MDY3NjY1Mi5odG1sJTNGc29ydCUzRDEwOThfMTA5OV8wXzAiIHRhcmdldD0iX2JsYW5r +IiB0aXRsZT0iIiBzdHlsZT0iY29sb3I6IzEwNTQ5MTtmb250LXNpemU6MTJweDsiPuOAkOW1jOWF +peezu+e7n+OAkUNvcnRleHQgTeW+ruaOp+WItuWZqOmHjeWumuS5ieW4guWcuuW8leihjOS4mua0 +l+eJjDwvYT48L2xpPg0KCQkJPGxpIHN0eWxlPSJiYWNrZ3JvdW5kOnVybChodHRwOi8vd3d3LmVl +Zm9jdXMuY29tL2ltYWdlcy9kb3QuZ2lmKSBuby1yZXBlYXQgbGVmdCA1cHg7IHBhZGRpbmctbGVm +dDoxNXB4O2ZvbnQtc2l6ZToxMnB4OyI+PGEgaHJlZj0iaHR0cDovL2FuYWx5dGljcy5lZWZvY3Vz +LmNvbS9jbGljay9lRE1fNzI2Xzg5NEJGN0Q1RDJERUNEMTgvP3VybD1odHRwJTNBJTJGJTJGcmFt +dHJvbi5lZWZvY3VzLmNvbSUyRmFydGljbGUlMkYxMC0xMSUyRjExMzAyNDEyOTA5NTA5NjguaHRt +bCUzRnNvcnQlM0QxMTI4XzE0OThfMF8wIiB0YXJnZXQ9Il9ibGFuayIgdGl0bGU9IiIgc3R5bGU9 +ImNvbG9yOiMxMDU0OTE7Zm9udC1zaXplOjEycHg7Ij7jgJDlrZjlgqjmioDmnK/jgJHkvKDnu5/n +moTno4HniYfnoaznm5jlsIborqnkvY3kuo7lm7rmgIHnoaznm5g8L2E+PC9saT4NCgkJICA8L3Vs +PgkJICA8L3RkPg0KCSAgICA8L3RyPg0KICAgICAgPC90YWJsZT4NCiAgICAgIDx0YWJsZSB3aWR0 +aD0iMTAwJSIgYm9yZGVyPSIwIiBhbGlnbj0iY2VudGVyIiBjZWxscGFkZGluZz0iMCIgY2VsbHNw +YWNpbmc9IjAiIHN0eWxlPSIgbWFyZ2luLXRvcDoxMHB4OyI+DQogICAgICAgIDx0cj4NCiAgICAg +ICAgICA8dGQgaGVpZ2h0PSIyNCIgYmdjb2xvcj0iI0VFRUVFRSI+PGIgc3R5bGU9ImxpbmUtaGVp +Z2h0OjI0cHg7IHBhZGRpbmctbGVmdDoxMHB4O2ZvbnQtc2l6ZToxNHB4OyBjb2xvcjojOTAwOyI+ +5oqA5pyv5paH6JCDPC9iPjwvdGQ+DQogICAgICAgIDwvdHI+DQogICAgICAgIDx0cj4NCiAgICAg +ICAgICA8dGQgc3R5bGU9InBhZGRpbmctbGVmdDoxMHB4OyI+PGEgaHJlZj0iaHR0cDovL2FuYWx5 +dGljcy5lZWZvY3VzLmNvbS9jbGljay9lRE1fNzI2Xzg5NEJGN0Q1RDJERUNEMTgvP3VybD1odHRw +JTNBJTJGJTJGZnJlZXNjYWxlLmVlZm9jdXMuY29tJTJGYXJ0aWNsZSUyRjEwLTExJTJGMTEzMDI0 +MTI5MDk0OTg2Ny5odG1sJTNGc29ydCUzRDExMzJfMTUyNV8wXzAiIHRhcmdldD0iX2JsYW5rIiBz +dHlsZT0iY29sb3I6IzEwNTQ5MTsgZm9udC13ZWlnaHQ6Ym9sZDsgbGluZS1oZWlnaHQ6MzBweDtm +b250LXNpemU6MTJweDsiIHRpdGxlPSIiPkhETUnmjqXlj6PnmoRFU0TpmLLmiqQ8L2E+PC90ZD4N +CiAgICAgICAgPC90cj4NCiAgICAgICAgPHRyPg0KICAgICAgICAgIDx0ZCAgc3R5bGU9InBhZGRp +bmctbGVmdDoxMHB4OyBjb2xvcjojMzMzO2ZvbnQtc2l6ZToxMnB4OyBsaW5lLWhlaWdodDoyMHB4 +OyI+PGEgaHJlZj0iaHR0cDovL2FuYWx5dGljcy5lZWZvY3VzLmNvbS9jbGljay9lRE1fNzI2Xzg5 +NEJGN0Q1RDJERUNEMTgvP3VybD1odHRwJTNBJTJGJTJGZnJlZXNjYWxlLmVlZm9jdXMuY29tJTJG +YXJ0aWNsZSUyRjEwLTExJTJGMTEzMDI0MTI5MDk0OTg2Ny5odG1sJTNGc29ydCUzRDExMzJfMTUy +NV8wXzAiIHRhcmdldD0iX2JsYW5rIiBzdHlsZT0iY29sb3I6IzMzMzsgdGV4dC1kZWNvcmF0aW9u +Om5vbmU7Ij5IRE1J5o6l5Y+j5piv6auY5riF5aSa5aqS5L2T5o6l5Y+jLOS7juebruWJjeeahOi2 +i+WKv+adpeeci++8jOmFjeWkh0hETUnmjqXlj6PjgIHnlJroh7PmlbTlkIjnlLXop4blip/og73m +mK/mtrLmmbbmmL7npLrlmajnmoTkuIDnp43lj5HlsZXotovlir/kuYvkuIDjgILpmo/nnYDnm67l +iY3luILpnaLkuIrotormnaXotorlpJrpmYTluKbigKbigKY8L2E+PC90ZD4NCiAgICAgICAgPC90 +cj4NCiAgICAgICAgPHRyPg0KICAgICAgICAgIDx0ZCBzdHlsZT0icGFkZGluZy1sZWZ0OjEwcHg7 +Ij48dWwgc3R5bGU9IiBsaXN0LXN0eWxlLXR5cGU6bm9uZTttYXJnaW46MDsgcGFkZGluZzowOyBs +aW5lLWhlaWdodDoyNHB4OyAiPg0KICAgICAgICAgICAgICA8bGkgc3R5bGU9ImJhY2tncm91bmQ6 +dXJsKGh0dHA6Ly93d3cuZWVmb2N1cy5jb20vaW1hZ2VzL2RvdC5naWYpIG5vLXJlcGVhdCBsZWZ0 +IDVweDsgcGFkZGluZy1sZWZ0OjE1cHg7Zm9udC1zaXplOjEycHg7Ij48YSBocmVmPSJodHRwOi8v +YW5hbHl0aWNzLmVlZm9jdXMuY29tL2NsaWNrL2VETV83MjZfODk0QkY3RDVEMkRFQ0QxOC8/dXJs +PWh0dHAlM0ElMkYlMkZ3d3cuZWVmb2N1cy5jb20lMkZhcnRpY2xlJTJGMTAtMTElMkY5MzI3MDEy +OTA4NjMwMDQuaHRtbCUzRnNvcnQlM0QxMTExXzExMThfMTQyN18wIiB0YXJnZXQ9Il9ibGFuayIg +dGl0bGU9IiIgc3R5bGU9ImNvbG9yOiMxMDU0OTE7Ij7jgJDmqKHmi5/nlLXmupDjgJHpm4bmiJDl +notVU0LlhYXnlLXnq6/lj6PnmoTnlLXmupDlvIDlhbM8L2E+PC9saT4NCiAgICAgICAgICAgIDxs +aSBzdHlsZT0iYmFja2dyb3VuZDp1cmwoaHR0cDovL3d3dy5lZWZvY3VzLmNvbS9pbWFnZXMvZG90 +LmdpZikgbm8tcmVwZWF0IGxlZnQgNXB4OyBwYWRkaW5nLWxlZnQ6MTVweDtmb250LXNpemU6MTJw +eDsiPjxhIGhyZWY9Imh0dHA6Ly9hbmFseXRpY3MuZWVmb2N1cy5jb20vY2xpY2svZURNXzcyNl84 +OTRCRjdENUQyREVDRDE4Lz91cmw9aHR0cCUzQSUyRiUyRm5ld3MuZWVmb2N1cy5jb20lMkZhcnRp +Y2xlJTJGMTAtMTElMkYyNjEyOTEwMTg3NjIuaHRtbCUzRnNvcnQlM0QxNzcxXzE3NzNfMF8wIiB0 +YXJnZXQ9Il9ibGFuayIgdGl0bGU9IiIgc3R5bGU9ImNvbG9yOiMxMDU0OTE7Ij7jgJDltYzlhaXn +s7vnu5/jgJFTVOmbhuaIkOS8oOaEn+WZqOaWueahiOWunueOsOeUteWtkOe9l+ebmOWKn+iDvTwv +YT48L2xpPg0KICAgICAgICAgICAgPGxpIHN0eWxlPSJiYWNrZ3JvdW5kOnVybChodHRwOi8vd3d3 +LmVlZm9jdXMuY29tL2ltYWdlcy9kb3QuZ2lmKSBuby1yZXBlYXQgbGVmdCA1cHg7IHBhZGRpbmct +bGVmdDoxNXB4O2ZvbnQtc2l6ZToxMnB4OyI+PGEgaHJlZj0iaHR0cDovL2FuYWx5dGljcy5lZWZv +Y3VzLmNvbS9jbGljay9lRE1fNzI2Xzg5NEJGN0Q1RDJERUNEMTgvP3VybD1odHRwJTNBJTJGJTJG +d3d3LmVlZm9jdXMuY29tJTJGYXJ0aWNsZSUyRjEwLTEyJTJGMjEzOTc3MTI5MTI2MDg2My5odG1s +JTNGc29ydCUzRDExMTFfMTEyMl8xNDY3XzAiIHRhcmdldD0iX2JsYW5rIiB0aXRsZT0iIiBzdHls +ZT0iY29sb3I6IzEwNTQ5MTsiPuOAkOa1i+ivlea1i+mHj+OAkeWcqExhYlZJRVcgMjAxMOS4rei9 +u+advuWunueOsOWQjOatpea1i+mHjzwvYT48L2xpPg0KICAgICAgICAgICAgPGxpIHN0eWxlPSJi +YWNrZ3JvdW5kOnVybChodHRwOi8vd3d3LmVlZm9jdXMuY29tL2ltYWdlcy9kb3QuZ2lmKSBuby1y +ZXBlYXQgbGVmdCA1cHg7IHBhZGRpbmctbGVmdDoxNXB4O2ZvbnQtc2l6ZToxMnB4OyI+PGEgaHJl +Zj0iaHR0cDovL2FuYWx5dGljcy5lZWZvY3VzLmNvbS9jbGljay9lRE1fNzI2Xzg5NEJGN0Q1RDJE +RUNEMTgvP3VybD1odHRwJTNBJTJGJTJGd3d3LmVlZm9jdXMuY29tJTJGYXJ0aWNsZSUyRjEwLTEy +JTJGNDIyOTIxMjkxMjY3NTU0Lmh0bWwlM0Zzb3J0JTNEMTExMV8xMTE5XzE0MzhfMCIgdGFyZ2V0 +PSJfYmxhbmsiIHRpdGxlPSIiIHN0eWxlPSJjb2xvcjojMTA1NDkxOyI+44CQ5qih5ouf55S15rqQ +44CR5Z+65LqO55Ge6JCo6auY5Y6LTU9T5Zyo5byA5Y+R5Lqn5ZOB5rOo5oSP6KaB54K5PC9hPjwv +bGk+DQogICAgICAgICAgICA8bGkgc3R5bGU9ImJhY2tncm91bmQ6dXJsKGh0dHA6Ly93d3cuZWVm +b2N1cy5jb20vaW1hZ2VzL2RvdC5naWYpIG5vLXJlcGVhdCBsZWZ0IDVweDsgcGFkZGluZy1sZWZ0 +OjE1cHg7Zm9udC1zaXplOjEycHg7Ij48YSBocmVmPSJodHRwOi8vYW5hbHl0aWNzLmVlZm9jdXMu +Y29tL2NsaWNrL2VETV83MjZfODk0QkY3RDVEMkRFQ0QxOC8/dXJsPWh0dHAlM0ElMkYlMkZ3d3cu +ZWVmb2N1cy5jb20lMkZhcnRpY2xlJTJGMTAtMTElMkYyMDc1NTIxMjkxMDg5NzY5Lmh0bWwlM0Zz +b3J0JTNEMTExMV8xMTI1XzBfMCIgdGFyZ2V0PSJfYmxhbmsiIHRpdGxlPSIiIHN0eWxlPSJjb2xv +cjojMTA1NDkxOyI+44CQ5bWM5YWl57O757uf44CR5Yeg56eN5bi455So55qE5Y2V54mH5py657O7 +57ufUkFN5rWL6K+V5pa55rOV56CU56m2PC9hPjwvbGk+DQogICAgICAgICAgPC91bD48L3RkPg0K +ICAgICAgICA8L3RyPg0KICAgICAgPC90YWJsZT4NCiAgICAgIDx0YWJsZSB3aWR0aD0iMTAwJSIg +Ym9yZGVyPSIwIiBhbGlnbj0iY2VudGVyIiBjZWxscGFkZGluZz0iMCIgY2VsbHNwYWNpbmc9IjAi +IHN0eWxlPSIgbWFyZ2luLXRvcDoxMHB4OyI+DQogICAgICAgIDx0cj4NCiAgICAgICAgICA8dGQg +aGVpZ2h0PSIyNCIgYmdjb2xvcj0iI0VFRUVFRSI+PGIgc3R5bGU9ImxpbmUtaGVpZ2h0OjI0cHg7 +IHBhZGRpbmctbGVmdDoxMHB4O2ZvbnQtc2l6ZToxNHB4OyBjb2xvcjojOTAwOyI+5LiT6L6R5o6o +6I2QPC9iPjwvdGQ+DQogICAgICAgIDwvdHI+DQogICAgICAgIDx0cj4NCiAgICAgICAgICA8dGQg +c3R5bGU9InBhZGRpbmctbGVmdDoxMHB4OyI+PGEgaHJlZj0iaHR0cDovL2FuYWx5dGljcy5lZWZv +Y3VzLmNvbS9jbGljay9lRE1fNzI2Xzg5NEJGN0Q1RDJERUNEMTgvP3VybD1odHRwJTNBJTJGJTJG +d3d3LmVlZm9jdXMuY29tJTJGdGVtcGxhdGUlMkZ0b3BpYyUyRndvbGZzb24td204OTU4Lmh0bWwi +IHRhcmdldD0iX2JsYW5rIiBzdHlsZT0iY29sb3I6IzEwNTQ5MTsgZm9udC13ZWlnaHQ6Ym9sZDsg +bGluZS1oZWlnaHQ6MzBweDtmb250LXNpemU6MTJweDsiIHRpdGxlPSIiPuaWsOWTgeS4k+mimO+8 +muasp+iDnFdNODk1OCBBdWRpbyBIdWI8L2E+PC90ZD4NCiAgICAgICAgPC90cj4NCiAgICAgICAg +PHRyPg0KICAgICAgICAgIDx0ZCAgc3R5bGU9InBhZGRpbmctbGVmdDoxMHB4OyBjb2xvcjojMzMz +O2ZvbnQtc2l6ZToxMnB4OyBsaW5lLWhlaWdodDoyMHB4OyI+PGEgaHJlZj0iaHR0cDovL2FuYWx5 +dGljcy5lZWZvY3VzLmNvbS9jbGljay9lRE1fNzI2Xzg5NEJGN0Q1RDJERUNEMTgvP3VybD1odHRw +JTNBJTJGJTJGd3d3LmVlZm9jdXMuY29tJTJGdGVtcGxhdGUlMkZ0b3BpYyUyRndvbGZzb24td204 +OTU4Lmh0bWwiIHRhcmdldD0iX2JsYW5rIiBzdHlsZT0iY29sb3I6IzMzMzsgdGV4dC1kZWNvcmF0 +aW9uOm5vbmU7Ij4g6L+Z5qy+5aSa6YCa6YGT6LaF5L2O5Yqf6ICX6Z+z6aKR5Lit5b+D6Kej5Yaz +5pa55qGI5Zyo5pWw5a2X5qih5ouf6L2s5o2i5ZmoKERBQynlm57mlL7mnJ/pl7Tlj6/ku6Xmj5Dk +vpsxMDBkQuS/oeWZquavlChTTlIp77yM5ZCM5pe25YW25YaF572u55qE56uL5L2T5aOwRC9BQuex +u+aJrOWjsOWZqOmpseWKqOWZqOKApuKApjwvYT48L3RkPg0KICAgICAgICA8L3RyPg0KICAgICAg +ICA8dHI+DQogICAgICAgICAgPHRkIHN0eWxlPSJwYWRkaW5nLWxlZnQ6MTBweDsiPjxhIGhyZWY9 +Imh0dHA6Ly9hbmFseXRpY3MuZWVmb2N1cy5jb20vY2xpY2svZURNXzcyNl84OTRCRjdENUQyREVD +RDE4Lz91cmw9aHR0cCUzQSUyRiUyRnd3dy5lZWZvY3VzLmNvbSUyRmJvb2slMkY0MTU1MjIxMTAz +MzgxZGZlJTJGIiB0YXJnZXQ9Il9ibGFuayIgc3R5bGU9ImNvbG9yOiMxMDU0OTE7IGZvbnQtd2Vp +Z2h0OmJvbGQ7IGxpbmUtaGVpZ2h0OjMwcHg7Zm9udC1zaXplOjEycHg7IiB0aXRsZT0iIj7jgIpG +UEdB5pWw5a2X5L+h5Y+35aSE55CG5Y6f55CG5Y+K5a6e546w44CLPC9hPjwvdGQ+DQogICAgICAg +IDwvdHI+DQogICAgICAgIDx0cj4NCiAgICAgICAgICA8dGQgIHN0eWxlPSJwYWRkaW5nLWxlZnQ6 +MTBweDsgY29sb3I6IzMzMzsgbGluZS1oZWlnaHQ6MjBweDtmb250LXNpemU6MTJweDsiPjxhIGhy +ZWY9Imh0dHA6Ly9hbmFseXRpY3MuZWVmb2N1cy5jb20vY2xpY2svZURNXzcyNl84OTRCRjdENUQy +REVDRDE4Lz91cmw9aHR0cCUzQSUyRiUyRnd3dy5lZWZvY3VzLmNvbSUyRmJvb2slMkY0MTU1MjIx +MTAzMzgxZGZlJTJGIiB0YXJnZXQ9Il9ibGFuayIgc3R5bGU9ImNvbG9yOiMzMzM7IHRleHQtZGVj +b3JhdGlvbjpub25lOyI+5pys5Lmm5Y+v5L2c5Li655u45YWz5LiT5Lia5byA6K6+RlBHQeaVsOWt +l+S/oeWPt+WkhOeQhuivvueoi+eahOacrOenkeWSjOeglOeptueUn+aVmeWtpuWPguiAg+S5pu+8 +jOS6puWPr+S9nOS4uuS7juS6i0ZQR0HmlbDlrZfkv6Hlj7flpITnkIbnm7jlhbPmlZnluIjjgIHn +oJTnqbbnlJ/lkoznp5HmioDkurrlkZjnmoToh6rlrablj4LogIPkuabigKbigKbigKY8L2E+PC90 +ZD4NCiAgICAgICAgPC90cj4NCiAgICAgIDwvdGFibGU+DQogICAgICA8dGFibGUgd2lkdGg9IjEw +MCUiIGJvcmRlcj0iMCIgYWxpZ249ImNlbnRlciIgY2VsbHBhZGRpbmc9IjAiIGNlbGxzcGFjaW5n +PSIwIiBzdHlsZT0iIG1hcmdpbi10b3A6MTBweDsiPg0KICAgICAgICA8dHI+DQogICAgICAgICAg +PHRkIGhlaWdodD0iMjQiIGJnY29sb3I9IiNFRUVFRUUiPjxiIHN0eWxlPSJsaW5lLWhlaWdodDoy +NHB4OyBwYWRkaW5nLWxlZnQ6MTBweDtmb250LXNpemU6MTRweDsgY29sb3I6IzkwMDsiPueUtei3 +r+aWueahiOeyvumAiTwvYj48L3RkPg0KICAgICAgICA8L3RyPg0KICAgICAgICA8dHI+DQogICAg +ICAgICAgPHRkIHN0eWxlPSJwYWRkaW5nLWxlZnQ6MTBweDsiPjxhIGhyZWY9Imh0dHA6Ly9hbmFs +eXRpY3MuZWVmb2N1cy5jb20vY2xpY2svZURNXzcyNl84OTRCRjdENUQyREVDRDE4Lz91cmw9aHR0 +cCUzQSUyRiUyRnd3dy5jbmR6ei5jb20lMkZzaGVldCUyRjE3Nzk0Lmh0bWwiIHRhcmdldD0iX2Js +YW5rIiBzdHlsZT0iY29sb3I6IzEwNTQ5MTsgZm9udC13ZWlnaHQ6Ym9sZDsgbGluZS1oZWlnaHQ6 +MzBweDtmb250LXNpemU6MTJweDsiIHRpdGxlPSIiPueUteiwg+iwkOiwg+mikeaUtumfs+acuueU +tei3rzwvYT48L3RkPg0KICAgICAgICA8L3RyPg0KICAgICAgICA8dHI+DQoNCiAgICAgICAgICA8 +dGQgIHN0eWxlPSJwYWRkaW5nLWxlZnQ6MTBweDsgY29sb3I6IzMzMztmb250LXNpemU6MTJweDsg +bGluZS1oZWlnaHQ6MjBweDsiPjxhIGhyZWY9Imh0dHA6Ly9hbmFseXRpY3MuZWVmb2N1cy5jb20v +Y2xpY2svZURNXzcyNl84OTRCRjdENUQyREVDRDE4Lz91cmw9aHR0cCUzQSUyRiUyRnd3dy5jbmR6 +ei5jb20lMkZzaGVldCUyRjE3Nzk0Lmh0bWwiIHRhcmdldD0iX2JsYW5rIiBzdHlsZT0iY29sb3I6 +IzMzMzsgdGV4dC1kZWNvcmF0aW9uOm5vbmU7Ij7ph4fnlKhDRDkwODgg6LCD6aKR5LiT55So6ZuG +5oiQ55S16Lev5p2l5Yi25L2c55S16LCD6LCQ6LCD6aKR5pS26Z+z5py677yM5YW35pyJ55S16Lev +566A5Y2V44CB5Yi25L2c5a655piT44CB6LCD6K+V5pa55L6/44CB5oCn6IO95Lu35qC85q+U6auY +44CB6Z+z6LSo5aW944CB5oiQ5pys5L2O44CB5L2T56ev5bCP562J54m554K54oCm4oCmPC9hPjwv +dGQ+DQogICAgICAgIDwvdHI+DQoJCTx0cj4NCiAgICAgICAgICA8dGQgc3R5bGU9InBhZGRpbmct +bGVmdDoxMHB4OyI+PGEgaHJlZj0iaHR0cDovL2FuYWx5dGljcy5lZWZvY3VzLmNvbS9jbGljay9l +RE1fNzI2Xzg5NEJGN0Q1RDJERUNEMTgvP3VybD1odHRwJTNBJTJGJTJGd3d3LmNuZHp6LmNvbSUy +RnNoZWV0JTJGMTY2MjUuaHRtbCIgdGFyZ2V0PSJfYmxhbmsiIHN0eWxlPSJjb2xvcjojMTA1NDkx +OyBmb250LXdlaWdodDpib2xkOyBsaW5lLWhlaWdodDozMHB4O2ZvbnQtc2l6ZToxMnB4OyIgdGl0 +bGU9IiI+6Ieq5Yi255qE5Y2V54mH5py654On5YaZ55S16LevPC9hPjwvdGQ+DQogICAgICAgIDwv +dHI+DQogICAgICAgIDx0cj4NCiAgICAgICAgICA8dGQgIHN0eWxlPSJwYWRkaW5nLWxlZnQ6MTBw +eDsgY29sb3I6IzMzMzsgbGluZS1oZWlnaHQ6MjBweDtmb250LXNpemU6MTJweDsiPjxhIGhyZWY9 +Imh0dHA6Ly9hbmFseXRpY3MuZWVmb2N1cy5jb20vY2xpY2svZURNXzcyNl84OTRCRjdENUQyREVD +RDE4Lz91cmw9aHR0cCUzQSUyRiUyRnd3dy5jbmR6ei5jb20lMkZzaGVldCUyRjE2NjI1Lmh0bWwi +IHRhcmdldD0iX2JsYW5rIiBzdHlsZT0iY29sb3I6IzMzMzsgdGV4dC1kZWNvcmF0aW9uOm5vbmU7 +Ij7oh6rlt7HliLbkvZzljZXniYfmnLrnmoTng6flhpnnlLXot6/vvIznroDljZXlrp7nlKjjgILl +j6ropoHnlLXot6/ov57mjqXmraPnoa7vvIzlr7nlhbblroPmlrnpnaLmsqHmnInku4DkuYjigKbi +gKY8L2E+PC90ZD4NCiAgICAgICAgPC90cj4NCgkJPHRyPg0KICAgICAgICAgIDx0ZCBzdHlsZT0i +cGFkZGluZy1sZWZ0OjEwcHg7Ij48YSBocmVmPSJodHRwOi8vYW5hbHl0aWNzLmVlZm9jdXMuY29t +L2NsaWNrL2VETV83MjZfODk0QkY3RDVEMkRFQ0QxOC8/dXJsPWh0dHAlM0ElMkYlMkZ3d3cuY25k +enouY29tJTJGc2hlZXQlMkYyMTQ0Lmh0bWwiIHRhcmdldD0iX2JsYW5rIiBzdHlsZT0iY29sb3I6 +IzEwNTQ5MTsgZm9udC13ZWlnaHQ6Ym9sZDsgbGluZS1oZWlnaHQ6MzBweDtmb250LXNpemU6MTJw +eDsiIHRpdGxlPSIiPuiHquWItuaRh+aRh+ajkuWOn+eQhuWbvjwvYT48L3RkPg0KICAgICAgICA8 +L3RyPg0KICAgICAgICA8dHI+DQogICAgICAgICAgPHRkICBzdHlsZT0icGFkZGluZy1sZWZ0OjEw +cHg7IGNvbG9yOiMzMzM7IGxpbmUtaGVpZ2h0OjIwcHg7Zm9udC1zaXplOjEycHg7Ij48YSBocmVm +PSJodHRwOi8vYW5hbHl0aWNzLmVlZm9jdXMuY29tL2NsaWNrL2VETV83MjZfODk0QkY3RDVEMkRF +Q0QxOC8/dXJsPWh0dHAlM0ElMkYlMkZ3d3cuY25kenouY29tJTJGc2hlZXQlMkYyMTQ0Lmh0bWwi +IHRhcmdldD0iX2JsYW5rIiBzdHlsZT0iY29sb3I6IzMzMzsgdGV4dC1kZWNvcmF0aW9uOm5vbmU7 +Ij7igJzmlbDnoIHmkYfmkYfmo5LigJ3mmK/ln7rkuo7kurrnnLzop4bop4nmmoLnlZnljp/nkIbj +gIHov5DnlKjmnIDmlrDkuJPliKnnlLXlrZDmioDmnK/noJTliLbogIzmiJDnmoTnur/pmLVMRUTo +v5DliqjmiJDlg4/nmoTpq5jnp5HmioDkuqflk4HigKbigKY8L2E+PC90ZD4NCiAgICAgICAgPC90 +cj4NCiAgICAgIDwvdGFibGU+DQoNCiAgICA8L3RkPg0KCSAgPHRkIHdpZHRoPSI4Ij48L3RkPg0K +ICAgIDx0ZCB3aWR0aD0iMjgwIiB2YWxpZ249InRvcCIgYmdjb2xvcj0iI0ZGRkZGRiI+PHRhYmxl +IHdpZHRoPSIxMDAlIiBib3JkZXI9IjAiIGFsaWduPSJjZW50ZXIiIGNlbGxwYWRkaW5nPSIwIiBj +ZWxsc3BhY2luZz0iMCI+DQogICAgICA8dHI+DQogICAgICAgIDx0ZCBoZWlnaHQ9IjI0IiBiZ2Nv +bG9yPSIjRUVFRUVFIj48YiBzdHlsZT0ibGluZS1oZWlnaHQ6MjRweDsgcGFkZGluZy1sZWZ0OjEw +cHg7Zm9udC1zaXplOjE0cHg7IGNvbG9yOiM5MDA7Ij7npL7ljLrnsr7pgIk8L2I+PC90ZD4NCiAg +ICAgIDwvdHI+DQogICAgICA8dHI+DQogICAgICAgIDx0ZCBzdHlsZT0icGFkZGluZy1sZWZ0OjEw +cHg7Ij48YSBocmVmPSJodHRwOi8vYW5hbHl0aWNzLmVlZm9jdXMuY29tL2NsaWNrL2VETV83MjZf +ODk0QkY3RDVEMkRFQ0QxOC8/dXJsPWh0dHAlM0ElMkYlMkZlbWJlZGRlZGludGVsLmVlZm9jdXMu +Y29tJTJGYXJ0aWNsZSUyRjEwLTExJTJGMjcxMjkwOTk3ODE5Lmh0bWwlM0Zzb3J0JTNEMTQ5XzBf +MF8wIiB0YXJnZXQ9Il9ibGFuayIgc3R5bGU9ImNvbG9yOiMxMDU0OTE7IGZvbnQtd2VpZ2h0OmJv +bGQ7IGxpbmUtaGVpZ2h0OjMwcHg7Zm9udC1zaXplOjEycHg7IiB0aXRsZT0iIj7lvIDmlL7mjqXl +j6Mg6Iux54m55bCU5YeM5Yqo6LiP5LiK5paw5b6B56iLPC9hPjwvdGQ+DQoNCiAgICAgIDwvdHI+ +DQogICAgICANCiAgICAgIDx0cj4NCiAgICAgICAgPHRkICBzdHlsZT0icGFkZGluZy1sZWZ0OjEw +cHg7IGNvbG9yOiMzMzM7IGxpbmUtaGVpZ2h0OjIwcHg7Zm9udC1zaXplOjEycHg7Ij48YSBocmVm +PSJodHRwOi8vYW5hbHl0aWNzLmVlZm9jdXMuY29tL2NsaWNrL2VETV83MjZfODk0QkY3RDVEMkRF +Q0QxOC8/dXJsPWh0dHAlM0ElMkYlMkZlbWJlZGRlZGludGVsLmVlZm9jdXMuY29tJTJGYXJ0aWNs +ZSUyRjEwLTExJTJGMjcxMjkwOTk3ODE5Lmh0bWwlM0Zzb3J0JTNEMTQ5XzBfMF8wIiB0YXJnZXQ9 +Il9ibGFuayIgc3R5bGU9ImNvbG9yOiMzMzM7IHRleHQtZGVjb3JhdGlvbjpub25lOyI+5b6I5bCR +5Zyo5ZOq5a62SUPoiq/niYfkvpvlupTllYbnmoTmtLvliqjkuIrkvJrlh7rnjrDmnInnq57kuonl +hbPns7vljoLllYbloZTlj7DllLHmiI/nmoTnjrDosaHjgILkuI3ov4fov5nnp43igKbigKY8L2E+ +PC90ZD4NCiAgICAgIDwvdHI+DQoJICA8dHI+DQogICAgICAgIDx0ZCAgc3R5bGU9InBhZGRpbmct +bGVmdDoxMHB4OyI+DQoJCQk8dWwgc3R5bGU9Imxpc3Qtc3R5bGUtdHlwZTpub25lOyBtYXJnaW46 +MDsgcGFkZGluZzowOyBsaW5lLWhlaWdodDoxOHB4OyI+DQoJCQkJPGxpIHN0eWxlPSJtYXJnaW46 +OHB4IDA7IGJhY2tncm91bmQ6dXJsKGh0dHA6Ly93d3cuZWVmb2N1cy5jb20vaW1hZ2VzL2RvdC5n +aWYpIG5vLXJlcGVhdCBsZWZ0IDVweDsgcGFkZGluZy1sZWZ0OjE1cHg7Zm9udC1zaXplOjEycHg7 +Ij48YSBocmVmPSJodHRwOi8vYW5hbHl0aWNzLmVlZm9jdXMuY29tL2NsaWNrL2VETV83MjZfODk0 +QkY3RDVEMkRFQ0QxOC8/dXJsPWh0dHAlM0ElMkYlMkZuZXdzLmVlZm9jdXMuY29tJTJGYXJ0aWNs +ZSUyRjEwLTExJTJGMjYxMjkxMDA1NTAxLmh0bWwlM0Zzb3J0JTNEMTc3MV8xNzczXzBfMCIgdGFy +Z2V0PSJfYmxhbmsiIHRpdGxlPSIiIHN0eWxlPSJjb2xvcjojMTA1NDkxOyI+44CQ5qih5ouf55S1 +5rqQ44CR55S15rqQ6K6+6K6h5bCP6LS05aOr77ya5pS55ZaE6LSf6L29556s5oCB5ZON5bqUPC9h +PjwvbGk+DQoNCgkJCQk8bGkgc3R5bGU9Im1hcmdpbjo4cHggMDtiYWNrZ3JvdW5kOnVybChodHRw +Oi8vd3d3LmVlZm9jdXMuY29tL2ltYWdlcy9kb3QuZ2lmKSBuby1yZXBlYXQgbGVmdCA1cHg7IHBh +ZGRpbmctbGVmdDoxNXB4O2ZvbnQtc2l6ZToxMnB4OyI+PGEgaHJlZj0iaHR0cDovL2FuYWx5dGlj +cy5lZWZvY3VzLmNvbS9jbGljay9lRE1fNzI2Xzg5NEJGN0Q1RDJERUNEMTgvP3VybD1odHRwJTNB +JTJGJTJGbnhwLmVlZm9jdXMuY29tJTJGYXJ0aWNsZSUyRjEwLTExJTJGMTk2MTUwMTI5MTExNjU5 +Ny5odG1sJTNGc29ydCUzRDkyMF85MjFfMTczOV8wIiB0YXJnZXQ9Il9ibGFuayIgdGl0bGU9IiIg +c3R5bGU9ImNvbG9yOiMxMDU0OTE7Ij7jgJDltYzlhaXns7vnu5/jgJFDb3J0ZXgtTTQvTTDlj4zm +oLjlvq7mjqfliLblmajnnoTlh4bmm7TlpJrmlrDlhbTlupTnlKg8L2E+PC9saT4NCgkJCQk8bGkg +c3R5bGU9Im1hcmdpbjo4cHggMDtiYWNrZ3JvdW5kOnVybChodHRwOi8vd3d3LmVlZm9jdXMuY29t +L2ltYWdlcy9kb3QuZ2lmKSBuby1yZXBlYXQgbGVmdCA1cHg7IHBhZGRpbmctbGVmdDoxNXB4O2Zv +bnQtc2l6ZToxMnB4OyI+PGEgaHJlZj0iaHR0cDovL2FuYWx5dGljcy5lZWZvY3VzLmNvbS9jbGlj +ay9lRE1fNzI2Xzg5NEJGN0Q1RDJERUNEMTgvP3VybD1odHRwJTNBJTJGJTJGdmlzaGF5LmVlZm9j +dXMuY29tJTJGdmlkZW8lMkZpbmRleC5waHAlM0ZhY3QlM0R2aWV3JTI2aWQlM0QxNTQ2IiB0YXJn +ZXQ9Il9ibGFuayIgdGl0bGU9IiIgc3R5bGU9ImNvbG9yOiMxMDU0OTE7Ij7jgJDop4bpopHku4vn +u43jgJHkvb/nlKjnrKzlha3ku6PliLbnqIvnmoTpq5jljos1MDBW6YeR5rCn5Y2K5Zy65pWI55S1 +5pm25L2T5LuL57uNPC9hPjwvbGk+DQoJCQkJPGxpIHN0eWxlPSJtYXJnaW46OHB4IDA7YmFja2dy +b3VuZDp1cmwoaHR0cDovL3d3dy5lZWZvY3VzLmNvbS9pbWFnZXMvZG90LmdpZikgbm8tcmVwZWF0 +IGxlZnQgNXB4OyBwYWRkaW5nLWxlZnQ6MTVweDtmb250LXNpemU6MTJweDsiPjxhIGhyZWY9Imh0 +dHA6Ly9hbmFseXRpY3MuZWVmb2N1cy5jb20vY2xpY2svZURNXzcyNl84OTRCRjdENUQyREVDRDE4 +Lz91cmw9aHR0cCUzQSUyRiUyRnd3dy5yYW10cm9uLW9ubGluZS5jbiUyRnRlbXBsYXRlJTJGcmFt +dHJvbiUyRmFjdGl2aXR5JTJGZXhwZXJ0Lmh0bWwiIHRhcmdldD0iX2JsYW5rIiB0aXRsZT0iIiBz +dHlsZT0iY29sb3I6IzEwNTQ5MTsiPuOAkOWtmOWCqOaKgOacr+OAkeWfuuehgOefpeivhu+8mkYt +UkFN5ZKMQkJTUkFN55qE5q+U6L6DPC9hPjwvbGk+DQoJCQkJPGxpIHN0eWxlPSJtYXJnaW46OHB4 +IDA7YmFja2dyb3VuZDp1cmwoaHR0cDovL3d3dy5lZWZvY3VzLmNvbS9pbWFnZXMvZG90LmdpZikg +bm8tcmVwZWF0IGxlZnQgNXB4OyBwYWRkaW5nLWxlZnQ6MTVweDtmb250LXNpemU6MTJweDsiPjxh +IGhyZWY9Imh0dHA6Ly9hbmFseXRpY3MuZWVmb2N1cy5jb20vY2xpY2svZURNXzcyNl84OTRCRjdE +NUQyREVDRDE4Lz91cmw9aHR0cCUzQSUyRiUyRmxpbmVhci5lZWZvY3VzLmNvbSUyRmFydGljbGUl +MkYxMC0xMSUyRjIyODcwMTEyOTEwNzc1NDMuaHRtbCUzRnNvcnQlM0QxOTI5XzE5MzBfMF8wIiB0 +YXJnZXQ9Il9ibGFuayIgdGl0bGU9IiIgc3R5bGU9ImNvbG9yOiMxMDU0OTE7Ij7jgJDni6znq4vl +hYPku7bjgJHnlLXlrZDlhYPlmajku7bkuIvkuIDkuKrop6bliqjngrnlnKjlk6rvvJ88L2E+PC9s +aT4NCgkJCQk8bGkgc3R5bGU9Im1hcmdpbjo4cHggMDtiYWNrZ3JvdW5kOnVybChodHRwOi8vd3d3 +LmVlZm9jdXMuY29tL2ltYWdlcy9kb3QuZ2lmKSBuby1yZXBlYXQgbGVmdCA1cHg7IHBhZGRpbmct +bGVmdDoxNXB4O2ZvbnQtc2l6ZToxMnB4OyI+PGEgaHJlZj0iaHR0cDovL2FuYWx5dGljcy5lZWZv +Y3VzLmNvbS9jbGljay9lRE1fNzI2Xzg5NEJGN0Q1RDJERUNEMTgvP3VybD1odHRwJTNBJTJGJTJG +cmYuZWVmb2N1cy5jb20lMkZhcnRpY2xlJTJGMTAtMTElMkY0MjI5MjEyOTA3NTAzMzguaHRtbCUz +RnNvcnQlM0QxMTExXzExMTlfMF8wIiB0YXJnZXQ9Il9ibGFuayIgdGl0bGU9IiIgc3R5bGU9ImNv +bG9yOiMxMDU0OTE7Ij7jgJDltYzlhaXns7vnu5/jgJHln7rkuo5BUk3nmoRHUFPmjqXmlLbmnLrn +moTorr7orqE8L2E+PC9saT4NCgkJCQk8bGkgc3R5bGU9Im1hcmdpbjo4cHggMDtiYWNrZ3JvdW5k +OnVybChodHRwOi8vd3d3LmVlZm9jdXMuY29tL2ltYWdlcy9kb3QuZ2lmKSBuby1yZXBlYXQgbGVm +dCA1cHg7IHBhZGRpbmctbGVmdDoxNXB4O2ZvbnQtc2l6ZToxMnB4OyI+PGEgaHJlZj0iaHR0cDov +L2FuYWx5dGljcy5lZWZvY3VzLmNvbS9jbGljay9lRE1fNzI2Xzg5NEJGN0Q1RDJERUNEMTgvP3Vy +bD1odHRwJTNBJTJGJTJGbGluZWFyLmVlZm9jdXMuY29tJTJGYXJ0aWNsZSUyRjEwLTExJTJGMjI4 +NzAxMTI5MDY2MTI5NS5odG1sJTNGc29ydCUzRDE5MjlfMTkzMV8wXzAiIHRhcmdldD0iX2JsYW5r +IiB0aXRsZT0iIiBzdHlsZT0iY29sb3I6IzEwNTQ5MTsiPuOAkOW1jOWFpeezu+e7n+OAkemSiOWv +ueiDjOWFieW6lOeUqOeahOWkmuagt+WMluino+WGs+aWueahiDwvYT48L2xpPg0KDQoJCQkJPGxp +IHN0eWxlPSJtYXJnaW46OHB4IDA7YmFja2dyb3VuZDp1cmwoaHR0cDovL3d3dy5lZWZvY3VzLmNv +bS9pbWFnZXMvZG90LmdpZikgbm8tcmVwZWF0IGxlZnQgNXB4OyBwYWRkaW5nLWxlZnQ6MTVweDtm +b250LXNpemU6MTJweDsiPjxhIGhyZWY9Imh0dHA6Ly9hbmFseXRpY3MuZWVmb2N1cy5jb20vY2xp +Y2svZURNXzcyNl84OTRCRjdENUQyREVDRDE4Lz91cmw9aHR0cCUzQSUyRiUyRnZpc2hheS5lZWZv +Y3VzLmNvbSUyRmFydGljbGUlMkYxMC0xMiUyRjI2MTI5MTE4NjQ5Mi5odG1sJTNGc29ydCUzRDIw +Ml8yMDNfMF8wIiB0YXJnZXQ9Il9ibGFuayIgdGl0bGU9IiIgc3R5bGU9ImNvbG9yOiMxMDU0OTE7 +Ij7jgJDni6znq4vlhYPku7bjgJFWaXNoYXnmjqjlh7rlhbfmnInmnoHlvLrmipflubLmibDog73l +ipvnmoTmlrDmrL7nuqLlpJbmjqXmlLblmag8L2E+PC9saT4NCgkJICAgIDwvdWw+DQoJCTwvdGQ+ +DQogICAgICA8L3RyPg0KICAgIDwvdGFibGU+DQogICAgICA8dGFibGUgd2lkdGg9IjEwMCUiIGJv +cmRlcj0iMCIgYWxpZ249ImNlbnRlciIgY2VsbHBhZGRpbmc9IjAiIGNlbGxzcGFjaW5nPSIwIiBz +dHlsZT0iIG1hcmdpbi10b3A6MTBweDsiPg0KICAgICAgICA8dHI+DQogICAgICAgICAgPHRkIGhl +aWdodD0iMjQiIGJnY29sb3I9IiNFRUVFRUUiPjxiIHN0eWxlPSJsaW5lLWhlaWdodDoyNHB4OyBw +YWRkaW5nLWxlZnQ6MTBweDtmb250LXNpemU6MTRweDsgY29sb3I6IzkwMDsiPuaYjuaYn+WNmuWu +ojwvYj48L3RkPg0KDQogICAgICAgIDwvdHI+DQogICAgICAgIDx0cj4NCiAgICAgICAgICA8dGQg +IHN0eWxlPSJwYWRkaW5nLWxlZnQ6MTBweDsiPjx1bCBzdHlsZT0ibGlzdC1zdHlsZS10eXBlOm5v +bmU7IG1hcmdpbjowOyBwYWRkaW5nOjA7IGxpbmUtaGVpZ2h0OjE4cHg7IGxpc3Qtc3R5bGUtcG9z +aXRpb246aW5zaWRlOyI+DQogICAgICAgICAgICAgIDxsaSBzdHlsZT0ibWFyZ2luOjhweCAwO2Jh +Y2tncm91bmQ6dXJsKGh0dHA6Ly93d3cuZWVmb2N1cy5jb20vaW1hZ2VzL2RvdC5naWYpIG5vLXJl +cGVhdCBsZWZ0IDVweDsgcGFkZGluZy1sZWZ0OjE1cHg7Zm9udC1zaXplOjEycHg7Ij48YSBocmVm +PSJodHRwOi8vYW5hbHl0aWNzLmVlZm9jdXMuY29tL2NsaWNrL2VETV83MjZfODk0QkY3RDVEMkRF +Q0QxOC8/dXJsPWh0dHAlM0ElMkYlMkZ3d3cuZWVmb2N1cy5jb20lMkZzYWlsbW9vbiUyRmJsb2cl +MkYxMC0xMiUyRjE5OTY5Nl9iMWRkZS5odG1sIiB0YXJnZXQ9Il9ibGFuayIgdGl0bGU9IiIgc3R5 +bGU9ImNvbG9yOiMxMDU0OTE7Ij7jgJDkuJPlrrbngrnor4TjgJHigJxHb29nbGUgVFblj4zph43o +uqvku70g5be+5bi86Iux6ZuE6L+Y5piv57qi6aKc56W45rC0PC9hPjwvbGk+DQogICAgICAgICAg +ICAgIDxsaSBzdHlsZT0ibWFyZ2luOjhweCAwO2JhY2tncm91bmQ6dXJsKGh0dHA6Ly93d3cuZWVm +b2N1cy5jb20vaW1hZ2VzL2RvdC5naWYpIG5vLXJlcGVhdCBsZWZ0IDVweDsgcGFkZGluZy1sZWZ0 +OjE1cHg7Zm9udC1zaXplOjEycHg7Ij48YSBocmVmPSJodHRwOi8vYW5hbHl0aWNzLmVlZm9jdXMu +Y29tL2NsaWNrL2VETV83MjZfODk0QkY3RDVEMkRFQ0QxOC8/dXJsPWh0dHAlM0ElMkYlMkZ3d3cu +ZWVmb2N1cy5jb20lMkZpbnRlbGluJTJGYmxvZyUyRjEwLTEyJTJGMTk5NjM2X2YyNDUwLmh0bWwi +IHRhcmdldD0iX2JsYW5rIiB0aXRsZT0iIiBzdHlsZT0iY29sb3I6IzEwNTQ5MTsiPuOAkOS6uueJ +qeS8oOiusOOAkeiLseeJueWwlOS9leeBq+mrmO+8muaIkeS4uuS4reWbveWutuW6reWBmueUteiE +kTwvYT48L2xpPg0KICAgICAgICAgICAgICA8bGkgc3R5bGU9Im1hcmdpbjo4cHggMDtiYWNrZ3Jv +dW5kOnVybChodHRwOi8vd3d3LmVlZm9jdXMuY29tL2ltYWdlcy9kb3QuZ2lmKSBuby1yZXBlYXQg +bGVmdCA1cHg7IHBhZGRpbmctbGVmdDoxNXB4O2ZvbnQtc2l6ZToxMnB4OyI+PGEgaHJlZj0iaHR0 +cDovL2FuYWx5dGljcy5lZWZvY3VzLmNvbS9jbGljay9lRE1fNzI2Xzg5NEJGN0Q1RDJERUNEMTgv +P3VybD1odHRwJTNBJTJGJTJGdG0uZWVmb2N1cy5jb20lMkZoYXBweXRlc3RpbmclMkZibG9nJTJG +MTAtMTElMkYxOTk0NzRfNDE3ZjYuaHRtbCIgdGFyZ2V0PSJfYmxhbmsiIHRpdGxlPSIiIHN0eWxl +PSJjb2xvcjojMTA1NDkxOyI+44CQ5Zu+5paH57qq5a6e44CR56GF5qOu5p6X5LitVGVrdHJvbml4 +IENhbXB1c+eahOWIm+aWsOawm+WbtOWSjOW8gOaUvuS6uuaWh+KAlOKAlOe+juWbveaAu+mDqOS5 +i+ihjOmaj+eslDwvYT48L2xpPg0KICAgICAgICAgICAgICA8bGkgc3R5bGU9Im1hcmdpbjo4cHgg +MDtiYWNrZ3JvdW5kOnVybChodHRwOi8vd3d3LmVlZm9jdXMuY29tL2ltYWdlcy9kb3QuZ2lmKSBu +by1yZXBlYXQgbGVmdCA1cHg7IHBhZGRpbmctbGVmdDoxNXB4O2ZvbnQtc2l6ZToxMnB4OyI+PGEg +aHJlZj0iaHR0cDovL2FuYWx5dGljcy5lZWZvY3VzLmNvbS9jbGljay9lRE1fNzI2Xzg5NEJGN0Q1 +RDJERUNEMTgvP3VybD1odHRwJTNBJTJGJTJGd3d3LmVlZm9jdXMuY29tJTJGbGluY2h1YW4lMkZi +bG9nJTJGMTAtMTIlMkYxOTk2MDhfNGUxOGMuaHRtbCIgdGFyZ2V0PSJfYmxhbmsiIHRpdGxlPSIi +IHN0eWxlPSJjb2xvcjojMTA1NDkxOyI+44CQ5Lqn5Lia5Yqo5oCB44CR5pm66IO95a625bGF77ya +5ouT6I2S6ICF55qE5pil5aSpPC9hPjwvbGk+DQoNCiAgICAgICAgICAgIDxsaSBzdHlsZT0ibWFy +Z2luOjhweCAwO2JhY2tncm91bmQ6dXJsKGh0dHA6Ly93d3cuZWVmb2N1cy5jb20vaW1hZ2VzL2Rv +dC5naWYpIG5vLXJlcGVhdCBsZWZ0IDVweDsgcGFkZGluZy1sZWZ0OjE1cHg7Zm9udC1zaXplOjEy +cHg7Ij48YSBocmVmPSJodHRwOi8vYW5hbHl0aWNzLmVlZm9jdXMuY29tL2NsaWNrL2VETV83MjZf +ODk0QkY3RDVEMkRFQ0QxOC8/dXJsPWh0dHAlM0ElMkYlMkZ3d3cuZWVmb2N1cy5jb20lMkZnb25n +eXUlMkZibG9nJTJGMTAtMTElMkYxOTkzNTdfOGFiM2MuaHRtbCIgdGFyZ2V0PSJfYmxhbmsiIHRp +dGxlPSIiIHN0eWxlPSJjb2xvcjojMTA1NDkxOyI+44CQ5Lqn5Lia6K+E6K6u44CR5LiJ5pif55qE +5bmz5p2/55S16ISR5pyJ5oiP5LmI77yfPC9hPjwvbGk+DQogICAgICAgICAgPC91bD48L3RkPg0K +ICAgICAgICA8L3RyPg0KICAgICAgPC90YWJsZT4NCiAgICAgIDx0YWJsZSB3aWR0aD0iMTAwJSIg +Ym9yZGVyPSIwIiBhbGlnbj0iY2VudGVyIiBjZWxscGFkZGluZz0iMCIgY2VsbHNwYWNpbmc9IjAi +IHN0eWxlPSIgbWFyZ2luLXRvcDoxMHB4OyI+DQogICAgICAgIDx0cj4NCiAgICAgICAgICA8dGQg +aGVpZ2h0PSIyNCIgYmdjb2xvcj0iI0VFRUVFRSI+PGIgc3R5bGU9ImxpbmUtaGVpZ2h0OjI0cHg7 +IHBhZGRpbmctbGVmdDoxMHB4O2ZvbnQtc2l6ZToxNHB4OyBjb2xvcjojOTAwOyI+5LiL6L295LiT +5Yy6PC9iPjwvdGQ+DQogICAgICAgIDwvdHI+DQoNCiAgICAgICAgPHRyPg0KICAgICAgICAgIDx0 +ZCAgc3R5bGU9InBhZGRpbmctbGVmdDoxMHB4OyI+PHVsIHN0eWxlPSJsaXN0LXN0eWxlLXR5cGU6 +bm9uZTsgbWFyZ2luOjA7IHBhZGRpbmc6MDsgbGluZS1oZWlnaHQ6MThweDsgbGlzdC1zdHlsZS1w +b3NpdGlvbjppbnNpZGU7Ij4NCiAgICAgICAgICAgICAgPGxpIHN0eWxlPSJtYXJnaW46OHB4IDA7 +YmFja2dyb3VuZDp1cmwoaHR0cDovL3d3dy5lZWZvY3VzLmNvbS9pbWFnZXMvZG90LmdpZikgbm8t +cmVwZWF0IGxlZnQgNXB4OyBwYWRkaW5nLWxlZnQ6MTVweDtmb250LXNpemU6MTJweDsiPjxhIGhy +ZWY9Imh0dHA6Ly9hbmFseXRpY3MuZWVmb2N1cy5jb20vY2xpY2svZURNXzcyNl84OTRCRjdENUQy +REVDRDE4Lz91cmw9aHR0cCUzQSUyRiUyRnZpc2hheS5lZWZvY3VzLmNvbSUyRnZlbmRvciUyRmRv +Y3VtZW50cy5waHAlM0ZhY3QlM0RmaWxlZG93biUyNmlkJTNEMTUyJTI2aW5mb2lkJTNENzk1NSIg +dGFyZ2V0PSJfYmxhbmsiIHRpdGxlPSIiIHN0eWxlPSJjb2xvcjojMTA1NDkxOyI+44CQ5qih5ouf +55S15rqQ44CR6auY5Y6L55S15rqQ566h55CG5Lit5YaF6YOo56iz5Y6L5Zmo55qE6K6+6K6hPC9h +PjwvbGk+DQogICAgICAgICAgICAgIDxsaSBzdHlsZT0ibWFyZ2luOjhweCAwO2JhY2tncm91bmQ6 +dXJsKGh0dHA6Ly93d3cuZWVmb2N1cy5jb20vaW1hZ2VzL2RvdC5naWYpIG5vLXJlcGVhdCBsZWZ0 +IDVweDsgcGFkZGluZy1sZWZ0OjE1cHg7Zm9udC1zaXplOjEycHg7Ij48YSBocmVmPSJodHRwOi8v +YW5hbHl0aWNzLmVlZm9jdXMuY29tL2NsaWNrL2VETV83MjZfODk0QkY3RDVEMkRFQ0QxOC8/dXJs +PWh0dHAlM0ElMkYlMkZwc29jLmVlZm9jdXMuY29tJTJGYmJzJTJGYXJ0aWNsZV84NDNfOTQyNTMu +aHRtbCIgdGFyZ2V0PSJfYmxhbmsiIHRpdGxlPSIiIHN0eWxlPSJjb2xvcjojMTA1NDkxOyI+44CQ +5qih5ouf55S16Lev44CRUFNvQ+eahOeUteWuueW8j+mdnuaOpeinpuaEn+W6lOaMiemUruiuvuiu +oTwvYT48L2xpPg0KICAgICAgICAgICAgICA8bGkgc3R5bGU9Im1hcmdpbjo4cHggMDtiYWNrZ3Jv +dW5kOnVybChodHRwOi8vd3d3LmVlZm9jdXMuY29tL2ltYWdlcy9kb3QuZ2lmKSBuby1yZXBlYXQg +bGVmdCA1cHg7IHBhZGRpbmctbGVmdDoxNXB4O2ZvbnQtc2l6ZToxMnB4OyI+PGEgaHJlZj0iaHR0 +cDovL2FuYWx5dGljcy5lZWZvY3VzLmNvbS9jbGljay9lRE1fNzI2Xzg5NEJGN0Q1RDJERUNEMTgv +P3VybD1odHRwJTNBJTJGJTJGcmYuZWVmb2N1cy5jb20lMkZiYnMlMkZhcnRpY2xlXzE1MF85MDU2 +My5odG1sIiB0YXJnZXQ9Il9ibGFuayIgdGl0bGU9IiIgc3R5bGU9ImNvbG9yOiMxMDU0OTE7Ij7j +gJDlsITpopHlvq7ms6LjgJFSRklE5oqA5pyv6LWE5paZ5YWx5Lqr5YWo6ZuGPC9hPjwvbGk+DQog +ICAgICAgICAgICA8bGkgc3R5bGU9Im1hcmdpbjo4cHggMDtiYWNrZ3JvdW5kOnVybChodHRwOi8v +d3d3LmVlZm9jdXMuY29tL2ltYWdlcy9kb3QuZ2lmKSBuby1yZXBlYXQgbGVmdCA1cHg7IHBhZGRp +bmctbGVmdDoxNXB4O2ZvbnQtc2l6ZToxMnB4OyI+PGEgaHJlZj0iaHR0cDovL2FuYWx5dGljcy5l +ZWZvY3VzLmNvbS9jbGljay9lRE1fNzI2Xzg5NEJGN0Q1RDJERUNEMTgvP3VybD1odHRwJTNBJTJG +JTJGdG0uZWVmb2N1cy5jb20lMkZiYnMlMkZhcnRpY2xlXzgxXzQ4NDUuaHRtbCIgdGFyZ2V0PSJf +YmxhbmsiIHRpdGxlPSIiIHN0eWxlPSJjb2xvcjojMTA1NDkxOyI+44CQ6LWE5rqQ5YWx5Lqr44CR +44CKSUPmtYvor5XmioDmnK/igJTigJTorr7orqHpqozor4HjgIvvvIjlhajmlofniYjvvIk8L2E+ +PC9saT4NCiAgICAgICAgICAgIDxsaSBzdHlsZT0ibWFyZ2luOjhweCAwO2JhY2tncm91bmQ6dXJs +KGh0dHA6Ly93d3cuZWVmb2N1cy5jb20vaW1hZ2VzL2RvdC5naWYpIG5vLXJlcGVhdCBsZWZ0IDVw +eDsgcGFkZGluZy1sZWZ0OjE1cHg7Zm9udC1zaXplOjEycHg7Ij48YSBocmVmPSJodHRwOi8vYW5h +bHl0aWNzLmVlZm9jdXMuY29tL2NsaWNrL2VETV83MjZfODk0QkY3RDVEMkRFQ0QxOC8/dXJsPWh0 +dHAlM0ElMkYlMkZ3d3cuZnJlZXNjYWxlaWMub3JnJTJGYmJzJTJGYXJ0aWNsZV8yNjVfMTAzODkx +Lmh0bWwiIHRhcmdldD0iX2JsYW5rIiB0aXRsZT0iIiBzdHlsZT0iY29sb3I6IzEwNTQ5MTsiPuOA +kOW1jOWFpeezu+e7n+OAkemjnuaAneWNoeWwlOWumOaWueS+i+eoi+KAlOKAlENBTuWSjExJTuS+ +i+eoizwvYT48L2xpPg0KDQoJCQk8bGkgc3R5bGU9Im1hcmdpbjo4cHggMDtiYWNrZ3JvdW5kOnVy +bChodHRwOi8vd3d3LmVlZm9jdXMuY29tL2ltYWdlcy9kb3QuZ2lmKSBuby1yZXBlYXQgbGVmdCA1 +cHg7IHBhZGRpbmctbGVmdDoxNXB4O2ZvbnQtc2l6ZToxMnB4OyI+PGEgaHJlZj0iaHR0cDovL2Fu +YWx5dGljcy5lZWZvY3VzLmNvbS9jbGljay9lRE1fNzI2Xzg5NEJGN0Q1RDJERUNEMTgvP3VybD1o +dHRwJTNBJTJGJTJGaW50ZXJzaWwuZWVmb2N1cy5jb20lMkZ2ZW5kb3IlMkZteXNwYWNlJTJGZG9j +dW1lbnRzLnBocCUzRmFjdCUzRGRvY3UlMjZvcCUzRHZpZXclMjZpZCUzRDcxNDIlMjZpbmZvaWQl +M0Q3OTQ3IiB0YXJnZXQ9Il9ibGFuayIgdGl0bGU9IiIgc3R5bGU9ImNvbG9yOiMxMDU0OTE7Ij7j +gJDotYTmupDlhbHkuqvjgJHni6znibnnmoTlkIzovbTnlLXnvIblhbHmqKHlmarlo7DmtojpmaTp +qbHliqjnlLXot6/orr7orqE8L2E+PC9saT4NCiAgICAgICAgICA8L3VsPjwvdGQ+DQogICAgICAg +IDwvdHI+DQogICAgICA8L3RhYmxlPg0KICAgICAgPHRhYmxlIHdpZHRoPSIxMDAlIiBib3JkZXI9 +IjAiIGFsaWduPSJjZW50ZXIiIGNlbGxwYWRkaW5nPSIwIiBjZWxsc3BhY2luZz0iMCIgc3R5bGU9 +IiBtYXJnaW4tdG9wOjEwcHg7Ij4NCiAgICAgICAgPHRyPg0KICAgICAgICAgIDx0ZCBoZWlnaHQ9 +IjI0IiBiZ2NvbG9yPSIjRUVFRUVFIj48YiBzdHlsZT0ibGluZS1oZWlnaHQ6MjRweDsgcGFkZGlu +Zy1sZWZ0OjEwcHg7Zm9udC1zaXplOjE0cHg7IGNvbG9yOiM5MDA7Ij7mi5vogZjmsYLogYw8L2I+ +PC90ZD4NCiAgICAgICAgPC90cj4NCg0KICAgICAgICA8dHI+DQogICAgICAgICAgPHRkICBzdHls +ZT0icGFkZGluZy1sZWZ0OjEwcHg7Ij48dWwgc3R5bGU9Imxpc3Qtc3R5bGUtdHlwZTpub25lOyBt +YXJnaW46MDsgcGFkZGluZzowOyBsaW5lLWhlaWdodDoxOHB4OyBsaXN0LXN0eWxlLXBvc2l0aW9u +Omluc2lkZTsiPg0KICAgICAgICAgICAgICA8bGkgc3R5bGU9Im1hcmdpbjo4cHggMDtiYWNrZ3Jv +dW5kOnVybChodHRwOi8vd3d3LmVlZm9jdXMuY29tL2ltYWdlcy9kb3QuZ2lmKSBuby1yZXBlYXQg +bGVmdCA1cHg7IHBhZGRpbmctbGVmdDoxNXB4O2ZvbnQtc2l6ZToxMnB4OyI+PGEgaHJlZj0iaHR0 +cDovL2FuYWx5dGljcy5lZWZvY3VzLmNvbS9jbGljay9lRE1fNzI2Xzg5NEJGN0Q1RDJERUNEMTgv +P3VybD1odHRwJTNBJTJGJTJGd3d3LmVlZm9jdXMuY29tJTJGam9iJTJGc2VhcmNobGlzdC5waHAl +M0ZhY3QlM0R2aWV3JTI2aWQlM0Q2MDYiIHRhcmdldD0iX2JsYW5rIiB0aXRsZT0iIiBzdHlsZT0i +Y29sb3I6IzEwNTQ5MTsiPumrmOe6p+mqjOivgeWSjOW6lOeUqOW3peeoi+W4iDwvYT48L2xpPg0K +ICAgICAgICAgICAgPGxpIHN0eWxlPSJtYXJnaW46OHB4IDA7YmFja2dyb3VuZDp1cmwoaHR0cDov +L3d3dy5lZWZvY3VzLmNvbS9pbWFnZXMvZG90LmdpZikgbm8tcmVwZWF0IGxlZnQgNXB4OyBwYWRk +aW5nLWxlZnQ6MTVweDtmb250LXNpemU6MTJweDsiPjxhIGhyZWY9Imh0dHA6Ly9hbmFseXRpY3Mu +ZWVmb2N1cy5jb20vY2xpY2svZURNXzcyNl84OTRCRjdENUQyREVDRDE4Lz91cmw9aHR0cCUzQSUy +RiUyRnd3dy5lZWZvY3VzLmNvbSUyRmpvYiUyRnNlYXJjaGxpc3QucGhwJTNGYWN0JTNEdmlldyUy +NmlkJTNENjA1IiB0YXJnZXQ9Il9ibGFuayIgdGl0bGU9IiIgc3R5bGU9ImNvbG9yOiMxMDU0OTE7 +Ij7luIPlsYDlsITpopHlt6XnqIvluIg8L2E+PC9saT4NCiAgICAgICAgICAgIDxsaSBzdHlsZT0i +bWFyZ2luOjhweCAwO2JhY2tncm91bmQ6dXJsKGh0dHA6Ly93d3cuZWVmb2N1cy5jb20vaW1hZ2Vz +L2RvdC5naWYpIG5vLXJlcGVhdCBsZWZ0IDVweDsgcGFkZGluZy1sZWZ0OjE1cHg7Zm9udC1zaXpl +OjEycHg7Ij48YSBocmVmPSJodHRwOi8vYW5hbHl0aWNzLmVlZm9jdXMuY29tL2NsaWNrL2VETV83 +MjZfODk0QkY3RDVEMkRFQ0QxOC8/dXJsPWh0dHAlM0ElMkYlMkZ3d3cuZWVmb2N1cy5jb20lMkZq +b2IlMkZzZWFyY2hsaXN0LnBocCUzRmFjdCUzRHZpZXclMjZpZCUzRDYwNCIgdGFyZ2V0PSJfYmxh +bmsiIHRpdGxlPSIiIHN0eWxlPSJjb2xvcjojMTA1NDkxOyI+6auY57qn6Iqv54mH54mI5Zu+5bel +56iL5biIPC9hPjwvbGk+DQogICAgICAgICAgPC91bD48L3RkPg0KICAgICAgICA8L3RyPg0KDQog +ICAgICA8L3RhYmxlPjwvdGQ+DQogIDwvdHI+DQogIDx0cj4NCiAgICA8dGQgaGVpZ2h0PSI0IiBj +b2xzcGFuPSIzIj48L3RkPg0KICA8L3RyPg0KPC90YWJsZT4NCjxkaXYgc3R5bGU9IndpZHRoOjc5 +MnB4O21hcmdpbjowIGF1dG87dGV4dC1pbmRlbnQ6MjBweDsgZm9udC1zaXplOjEycHg7Ij7lpoLm +npzmgqjkuI3mg7Pnu6fnu63mjqXmlLbmraTnsbvpgq7ku7bvvIzor7c8YSBocmVmPSJodHRwOi8v +d3d3LmVlZm9jdXMuY29tL25ld3NsZXR0ZXIvdW5TdWJzY3JpcHRpb24vP3VzZXI9ODk0QkY3RDVE +MkRFQ0QxOCIgdGFyZ2V0PSJfYmxhbmsiIHN0eWxlPSJjb2xvcjojMTA1NDkxOyIgPueCueWHu+i/ +memHjDwvYT7pgIDorqLjgII8L2Rpdj48aW1nIHNyYz0iaHR0cDovL2FuYWx5dGljcy5lZWZvY3Vz +LmNvbS9sb2FkL2VETV83MjZfODk0QkY3RDVEMkRFQ0QxOC8/dXJsPWh0dHAlM0ElMkYlMkZwaWMu +ZWVmb2N1cy5jb20lMkZpbWFnZXMlMkZiYXNpYyUyRmRvdC5naWYiIHdpZHRoPSIwIiBoZWlnaHQ9 +IjAiIC8+PC9ib2R5Pg0KDQo8L2h0bWw+DQoNCg== + + diff --git a/lib_acl_cpp/samples/mime/test12.eml b/lib_acl_cpp/samples/mime/test12.eml new file mode 100644 index 000000000..0034f93c8 --- /dev/null +++ b/lib_acl_cpp/samples/mime/test12.eml @@ -0,0 +1,16142 @@ +Return-Path: +Delivered-To: zhengshuxin@51iker.com +Received: from ikerf954f96714 (unknown [114.243.235.25]) + by 51iker.com (zebra mail for UNIX) with ESMTP id B0FF827465C + for ; Thu, 16 Dec 2010 10:41:25 +0800 (CST) +Message-ID: <8455B5BCFB754B9BBE9F1636E709B0EB@ikerf954f96714> +From: +To: +Subject: =?utf-8?B?5rWL6K+V6YKu5Lu2?= +Date: Thu, 16 Dec 2010 10:38:58 +0800 +MIME-Version: 1.0 +Content-Type: multipart/related; + type="multipart/alternative"; + boundary="----=_NextPart_000_0003_01CB9D0D.783DE8D0" +X-Priority: 3 +X-MSMail-Priority: Normal +X-Mailer: Microsoft Outlook Express 6.00.2900.5931 +X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2900.5931 + +This is a multi-part message in MIME format. + +------=_NextPart_000_0003_01CB9D0D.783DE8D0 +Content-Type: multipart/alternative; + boundary="----=_NextPart_001_0004_01CB9D0D.783DE8D0" + + +------=_NextPart_001_0004_01CB9D0D.783DE8D0 +Content-Type: text/plain; + charset="utf-8" +Content-Transfer-Encoding: base64 + +ICBhLi4gYS4uIOS7iuWkqeaYrzIwMTDlubQxMuaciDE25pelYS4uIOmmlumhtWEuLiDotYTorq9h +Li4g56m66Ze0YS4uIOiuuuWdm2EuLiDljZrlrqJhLi4g5LiL6L29YS4uIOe9keaRmGEuLiDnqIvl +uo/lkZhhLi4g6aG555uu5Lqk5piTYS4uIOS5puW6l2EuLiBDVE/kv7HkuZDpg6hhLi4gVFVQYS4u +IOWfueiureWFheeUtWEuLiDpq5jmoKFjbHViYS4uIOeglOWPkWEuLiDnp7vliqhhLi4gQ2hhbm5l +bDlhLi4gSmF2YWEuLiDlronlhahhLi4g5pWw5o2u5bqTYS4uIC5ORVRhLi4gV2Vi5byA5Y+RYS4u +IOS6keiuoeeul2EuLiDmnI3liqHlmahhLi4g55S15L+hSVRhLi4g5a2m55Sf5aSn5pys6JClYS4u +IOeMjuWktGEuLiAzR+WtpumZonxhLi4gSmF2YeWtpumZonxhLi4gLk5FVOWtpumZonxhLi4gUEhQ +5a2m6ZmifGEuLiBJQk0gZFd8YS4uIOiLseeJueWwlCDova/ku7Z8YS4uIOWuieiFvuiHs+W8unxh +Li4gTWVlR298YS4uIE9QaG9uZXxhLi4gRmxleC9BSVJ8YS4uIFZTMjAxMHxhLi4gUXR8YS4uIOeZ +vuW6puekvuWMunxhLi4gQmxhY2tCZXJyeXxhLi4gYmFkYXxhLi4g5LiJ5pifU01JfGEuLiDlpKnn +v7znqbrpl7RhLi4g44CQ6aG244CR5bqU5bGK55SfLOWFpeiBjOW5tOiWqjUtMTDkuIcNCiAgYi4u +IOaWsFZDKysgMjAxMOWbvuW9oua6kOeggeW6k+esrDPniYghDQogIGMuLiDkuI3mh4JDKyvkuI3m +mK/nnJ/mraPnmoTnqIvluo/lkZjvvIENCiAgZC4uIOaKpeWQjUlCTeW8gOWPkeiAheWkp+S8mui1 +ouWkmuenjeWkp+Wllg0KICBlLi4gQ29kZU1ldGVy6L2v5Lu25Yqg5a+G5oqA5pyv56CU6K6o5Lya +DQogIGEuLiBhLi4g5L2/55SoWE5B5qGG5p626L+b6KGMM0TmuLjmiI/lvIDlj5ENCiAgYi4uIFBI +UOWtpuS5oO+8jOWFiOWwseS4mu+8jOWQjuWIhuacn+i/mOasvg0KICBjLi4g5rC05rOi5pWI5bqU +QW5kcm9pZOa6kOeggQ0KICBkLi4gNjDkuIflpZbph5FWU+ebm+Wkp+eoi+W6j+i+vuS6uui1mw0K +ICBlLi4gOOWkqei9rOWeizNH77yM5pyI6JaqNEvlj5g4Sw0KICBhLi4gYS4uIOS7iuaXpeWktOad +oUZhY2Vib29rIENFT+W9k+mAiTIwMTDjgIrml7bku6PjgIvlubTluqbpo47kupHkurrniakNCltG +YWNlYm9va+S8sOWAvDPkuKrmnIjlop7plb83NyUg5Lyw5YC86L6+NDMw5Lq/576O5YWDXVvmr4/m +l6Xpgq7miqXvvJrosLfmrYzlkoxGYWNlYm9va+eahOaImOS6iV0NClvml7bku6PlkajliIrvvJrn +u7Tln7rop6Plr4blsIbotaLlvpfkv6Hmga/miJjkuoldW+OAiuaXtuS7o+WRqOWIiuOAi+ivhOWH +ujIwMTDlubTljYHlpKdpUGhvbmXlupTnlKhdDQoNClvljZrlrqJd6auY5pWI5a2Y5YKo5oqA5pyv +56CU56m2DQpb6auY5bm25Y+R6auY5rWB6YeP572R56uZ5p625p6EXVvlhbPkuo7mlbDmja7mjJbm +jpjlhbPogZTop4TliJnnmoRPcmFjbGXlrp7njrBdDQoNCuW+gOacn+WktOadoe+8mkdtYWls5LmL +54i277yaQ2hyb21lIE9T5p2l5pel5peg5aSaICAgIOWkqee/vOaVmeS9oOenu+WKqOW6lOeUqOiQ +peWIqeS5i+mBkw0K5pyA5paw5rS75YqoIHwg56iL5bqP5ZGY5p2C5b+XDQogIOiHqueUsSDliIbk +uqsg5YWx6LWiIOW8gOWIm+enu+WKqOS6kuiBlOe9keacquadpe+8jOWkqee/vOaVmeS9oOenu+WK +qOW6lOeUqOiQpeWIqeS5i+mBk++8gTEy5pyIMTfml6XvvIzljqbpl6jnq5njgIINCiAgT3BlbkZl +aW505ri45oiP5byA5Y+R6ICF576k6Iux5LyaDQogIOOAiueoi+W6j+WRmOOAi+WNgeW5tOiBlOaJ +i+ebm+Wkp+eJueaDoOa0u+WKqA0KICDnrKzkuZ3ln47luILljYPkuIfnjrDph5HlvoHpm4bnsr7l +k4HmuLjmiI/vvIENCiAg56ys5YWt5bGK56e75Yqo5LqS6IGU572RVE9QNTDor4TpgIkNCiAg5peg +57q/5LqS6IGU5Yib5Lia5a6e5oiY6K6y5bqnwrfljJfkuqwNCiAg44CK5pWP5o235byA5Y+R4oCU +5rWL6K+V566h55CG44CL5o+Q6Zeu6LWi5aWW54Ot6Zeo5oub6IGY6IGM5L2NDQogIOOAkOeAmuS/ +oeenkeaKgOOAkeivmuiBmCBXSU5ET1dTIEMrKyBXSU5ET1dTIEMj5Lit6auY57qn5byA5Y+R5bel +56iL5biI44CQ6YW35oiR6Z+z5LmQ55uS44CR6auY6Jaq6K+a6IGYIOa/gOaDheeIseWlveW3peS9 +nOiejeS4uuS4gOS9k+OAkOi+vuWGhembhuWbouOAkemrmOiWquivmuiBmEpBVkHorrLluIgu5bWM +5YWl5byP6K6y5biILjNH6K6y5biILuaKgOacr+aAu+ebkS7liIblhazlj7jmgLvnu4/nkIbjgJDl +pKnpmYXnvZHjgJHmgKXogZhKYXZh5bqU55So5p625p6E5biI44CB6auY57qnSmF2YeW3peeoi+W4 +iOOAgee9kemhteiuvuiuoeW4iOOAkOS4iua1t+mFt+WoseOAkemrmOiWquaApeiBmOacjeWKoeWZ +qOS4u+eoi+OAgeacjeWKoeWZqOeoi+W6j+OAkOWIm+aWsOW3peWcuuOAkeaKgOacr+exu+iBjOS9 +jeeDreaLm++8jOeri+WNs+WKoOWFpeWxnuS6juS9oOiHquW3seeahOWFrOWPuOOAkOWuveWoseaV +sOeggeOAkeivmuiBmEMrK+W6lOeUqOi9r+S7tuW3peeoi+W4iO+8iOWkmuWqkuS9ky/nvZHnu5zm +lrnlkJHvvInjgIEubmV05byA5Y+R5bel56iL5biI44CQ5ZuiODAw44CRTm8uMeWboui0reWvvOiI +quivmuiBmFJ1Ynkgb24gUmFpbHPpq5jmiYvvvIHjgJDnvo7lm73lm73lrrbku6rlmajjgJHor5ro +gZjpq5jnuqfova/ku7Yg5bel56iL5biIIOS/oeWPt+WkhOeQhui9r+S7tumDqOmXqOe7j+eQhuOA +kOa1meaxn+mpsOa1t+WunuS4muOAkeivmuiBmOmhueebrue7j+eQhu+8jFBIUCxNWVNRTCxTRU8s +5rWL6K+V77yM6L+Q57u077yM562W5YiS77yM6K6+6K6h562J6IGM44CQSW5mb3N5c+OAkeivmuiB +mO+8mkoyRUUg6aG555uu5Li7566hL++8iOi1hOa3se+8iei9r+S7tueglOWPkeW3peeoi+W4iC8u +TmV06LWE5rex6L2v5Lu256CU5Y+R5bel56iL5biI44CQ5YyX5Lqs6auY5oiQ6ZW/5YWs5Y+444CR +6auY6Jaq5oub6IGYLm5ldOWQhOe6p+eoi+W6j+WRmO+8jOasoui/juW6lOWxiueUn+OAkOmTtuih +jOmhueebruOAkeivmuiBmGphdmHliY3lj7Av5ZCO5Y+w5byA5Y+R5Lq65ZGY5aSa5ZCNIOWPilNB +U+aVsOaNruWIhuaekOWRmO+8jOassuivleS7jumAn++8geOAkOWMl+S6rOmXu+iogOenkeaKgOOA +keivmuiBmC5uZXTpq5jnuqflvIDlj5Hlt6XnqIvluIjjgIHmiYvmnLrova/ku7blvIDlj5Hlt6Xn +qIvluIjvvIjlupTlsYrmr5XkuJrnlJ/kvJjlhYjvvInjgJDkuIrmtbfnlLXlrZDllYbliqHlubPl +j7DjgJHph43ph5Hor5rogZgubmV0LGFzcCxqYXZhc2NyaXB06LWE5rex56iL5bqP5ZGY44CQRUbl +hajnkIPnoJTlj5HkuK3lv4PjgJHnmb7kuIflubTolqror5rmi5vmioDmnK/nsr7oi7HvvIzmlbDn +mb7ogYzkvY3ng63mi5vkuK3jgJBBbWF6b27jgJHkuprpqazpgIror5rogZjmioDmnK/kuJPlrrbv +vIHjgJDnvZHot6/ml7bku6PjgJHpq5jolqror5rogZhDKyvjgIEubmV05byA5Y+R5bel56iL5biI +44CQ5Lqs5Lic5ZWG5Z+O44CR6K+a6IGY5omL5py65byA5Y+R5bel56iL5biI77yM6L2v5Lu25byA +5Y+R5bel56iL5biI77yM5qyy6K+V5LuO6YCfIeOAkEF1dG9kZXNr44CR5qyn54m55YWL6L2v5Lu2 +KOS4reWbvSnor5rogZjova/ku7blvIDlj5Es5rWL6K+VLOeglOeptuWRmOOAkEdvb2dsZeOAkeiv +muaLm+aKgOacr+eyvuiLse+8jOWPsuS4iuS6uuaVsOacgOWkmuiBjOS9jeacgOW5vyHjgJDng63o +gZjjgJHmkJzni5DnlYXmuLjlhajlm73ng63mi5vlvIDlj5Hlt6XnqIvluIjjgJDngJrkv6Hnp5Hm +ioDjgJHor5rogZggV0lORE9XUyBDKysgV0lORE9XUyBDI+S4remrmOe6p+W8gOWPkeW3peeoi+W4 +iOOAkOmFt+aIkemfs+S5kOebkuOAkemrmOiWquivmuiBmCDmv4Dmg4XniLHlpb3lt6XkvZzono3k +uLrkuIDkvZPjgJDovr7lhoXpm4blm6LjgJHpq5jolqror5rogZhKQVZB6K6y5biILuW1jOWFpeW8 +j+iusuW4iC4zR+iusuW4iC7mioDmnK/mgLvnm5Eu5YiG5YWs5Y+45oC757uP55CG44CQ5aSp6ZmF +572R44CR5oCl6IGYSmF2YeW6lOeUqOaetuaehOW4iOOAgemrmOe6p0phdmHlt6XnqIvluIjjgIHn +vZHpobXorr7orqHluIjjgJDkuIrmtbfphbflqLHjgJHpq5jolqrmgKXogZjmnI3liqHlmajkuLvn +qIvjgIHmnI3liqHlmajnqIvluo/jgJDliJvmlrDlt6XlnLrjgJHmioDmnK/nsbvogYzkvY3ng63m +i5vvvIznq4vljbPliqDlhaXlsZ7kuo7kvaDoh6rlt7HnmoTlhazlj7jjgJDlrr3lqLHmlbDnoIHj +gJHor5rogZhDKyvlupTnlKjova/ku7blt6XnqIvluIjvvIjlpJrlqpLkvZMv572R57uc5pa55ZCR +77yJ44CBLm5ldOW8gOWPkeW3peeoi+W4iOOAkOWbojgwMOOAkU5vLjHlm6LotK3lr7zoiKror5ro +gZhSdWJ5IG9uIFJhaWxz6auY5omL77yB44CQ576O5Zu95Zu95a625Luq5Zmo44CR6K+a6IGY6auY +57qn6L2v5Lu2IOW3peeoi+W4iCDkv6Hlj7flpITnkIbova/ku7bpg6jpl6jnu4/nkIbjgJDmtZnm +sZ/pqbDmtbflrp7kuJrjgJHor5rogZjpobnnm67nu4/nkIbvvIxQSFAsTVlTUUwsU0VPLOa1i+iv +le+8jOi/kOe7tO+8jOetluWIku+8jOiuvuiuoeetieiBjOOAkEluZm9zeXPjgJHor5rogZjvvJpK +MkVFIOmhueebruS4u+euoS/vvIjotYTmt7HvvInova/ku7bnoJTlj5Hlt6XnqIvluIgvLk5ldOi1 +hOa3sei9r+S7tueglOWPkeW3peeoi+W4iOOAkOWMl+S6rOmrmOaIkOmVv+WFrOWPuOOAkemrmOiW +quaLm+iBmC5uZXTlkITnuqfnqIvluo/lkZjvvIzmrKLov47lupTlsYrnlJ/jgJDpk7booYzpobnn +m67jgJHor5rogZhqYXZh5YmN5Y+wL+WQjuWPsOW8gOWPkeS6uuWRmOWkmuWQjSDlj4pTQVPmlbDm +ja7liIbmnpDlkZjvvIzmrLLor5Xku47pgJ/vvIHjgJDljJfkuqzpl7voqIDnp5HmioDjgJHor5ro +gZgubmV06auY57qn5byA5Y+R5bel56iL5biI44CB5omL5py66L2v5Lu25byA5Y+R5bel56iL5biI +77yI5bqU5bGK5q+V5Lia55Sf5LyY5YWI77yJ44CQ5LiK5rW355S15a2Q5ZWG5Yqh5bmz5Y+w44CR +6YeN6YeR6K+a6IGYLm5ldCxhc3AsamF2YXNjcmlwdOi1hOa3seeoi+W6j+WRmOOAkEVG5YWo55CD +56CU5Y+R5Lit5b+D44CR55m+5LiH5bm06Jaq6K+a5oub5oqA5pyv57K+6Iux77yM5pWw55m+6IGM +5L2N54Ot5oub5Lit44CQQW1hem9u44CR5Lqa6ams6YCK6K+a6IGY5oqA5pyv5LiT5a6277yB44CQ +572R6Lev5pe25Luj44CR6auY6Jaq6K+a6IGYQysr44CBLm5ldOW8gOWPkeW3peeoi+W4iOOAkOS6 +rOS4nOWVhuWfjuOAkeivmuiBmOaJi+acuuW8gOWPkeW3peeoi+W4iO+8jOi9r+S7tuW8gOWPkeW3 +peeoi+W4iO+8jOassuivleS7jumAnyHjgJBBdXRvZGVza+OAkeasp+eJueWFi+i9r+S7tijkuK3l +m70p6K+a6IGY6L2v5Lu25byA5Y+RLOa1i+ivlSznoJTnqbblkZjjgJBHb29nbGXjgJHor5rmi5vm +ioDmnK/nsr7oi7HvvIzlj7LkuIrkurrmlbDmnIDlpJrogYzkvY3mnIDlub8h44CQ54Ot6IGY44CR +5pCc54uQ55WF5ri45YWo5Zu954Ot5oub5byA5Y+R5bel56iL5biI54m55Yir5o6o6I2QDQogIOaK +peWQjUlCTeW8gOWPkeiAheWkp+S8mui1ouWkmumHjeWkp+Wllg0KICDjgJDmnInlpZbjgJHlj4Lk +uI7lpKnnv7zosIPmn6Ug6LWi56We56eY56S8DQogIOWPguWKoOWIm+aWsOadr+i1ouaAu+minTIw +5LiH576O6YeRDQogIOOAkOacieWlluiwg+afpeOAkeS8geS4muWuieWFqOetiee6p+ivhOa1iw0K +ICDlj4LkuI5JRTnlpKfotZvlvpflpZbph5HotaLpvKDmoIcNCiAg44CQ56iL5bqP5o6o6I2Q44CR +572R56uZ5YaF5a65566h55CG57O757ufDQogIE1lZUdv5Lit5Zu95Yy65byA5Y+R6ICF56CU6K6o +5LyaDQogIE5va2lh5Li65LuA5LmI5LiN55SoQW5kcm8NCiAg6bih6IKL77yf6L+Y5piv5r2u5rWB +77yfDQogIOelnuWlh+eahFdlYlFRDQogIE1lZUdv5piv5LqS6IGU6K6h566X5Yib5paw5Yip5Zmo +DQogIOW3peWFt+aOqOiNkO+8muW7tumVv+eUteaxoOe7reiIquaXtumXtA0KICDoi7HnibnlsJTl +t6XlhbfmjqjojZDvvJror4TkvLDlpJrmoLjns7vnu5/mgKfotYTorq8gMTM2MuS6uueUs+ivt+WK +oOWFpSLpu5HpqaznqIvluo/lkZgi5b6F5a6hICDlvKDlrZ3npaVqYXZh5bCx5Lia5pS755Wl5pu0 +5aSaR2FydG5lcumihOiuoeS7iuW5tOWFqOeQg+S8geS4mlNhYVPmlLblhaXlop7plb8xNS43JeWk +muagt+WMluW6lOeUqOW4puadpeeuoeeQhuaMkeaImA0KICDnlLLpqqjmloflia/mgLvosIjono3l +kIjlupTnlKjova/ku7bkuInlpKfmiJjnlaXln7rnoYAg5omA5pyJ5Lqn5ZOB6Z2i5ZCR5LqR6K6h +566X5byA5Y+RDQogIOWVhuS4muWRqOWIiu+8mkNocm9tZSBPU+WumuS9jeaooeeziuWJjeaZr+m7 +r+a3oee8uuS5j+ekvuS6pOWSjOWunuaXtuW6lOeUqA0KICDpm4XomY5DRU/lt7TojKjmlL7lvIPo +v5vlhaXpmL/ph4zlt7Tlt7TokaPkuovkvJrpm4XomY7pm4flkZjnp7Dlt7Looqvop6Ppm4cNCiAg +6LC35q2M6aaW5bit5bel56iL5biI77ya5Z2a5oyB566X5rOV5Y6f5YiZIOS4jeaOuuS4u+inguiJ +suW9qeS4jeWBj+iikuS7u+S9leWTgeeJjA0KICDnibnnq4vni6zooYznmoTnqIvluo/lkZjvvJrn +u7Tln7rop6Plr4bliJvlp4vkurrpmL/moZHlpYfkvKDlpYfnu4/ljoblnY7lnbfmgJ3mg7Pmt7Hl +iLsNCiAg5Lia55WM5LiO5Lq654mpRmFjZWJvb2vmjqhGbWFpbOaMkeaImEVtYWlsIDYyJeWPl+iu +v+iAheS4jeiAg+iZkeekvuS6pOe9kee7nOWPmOi6q+mAmuiur+W5s+WPsA0KICDlvq7ova/lrpjm +lrnlrqPnp7DlsIbkuo4yMDEx5bm05LiL5Y2K5bm05Zyo5Lit5Zu95o6o5Ye6V2luZG93cyBQaG9u +ZSA3DQogIOivuuWfuuS6muaYjuW5tOaLn+WvueWhnuePreezu+e7n+i/m+ihjDTliLA15qyh5Y2H +57qn5aKe5Yqg5Li76aG16YWN572u54G15rS75oCnDQogIFtTRDIuMF3liJvmlrDlt6XlnLrolKHl +rabplZvvvJrpoobln5/or63oqIDnmoTorr7orqHkuI7lrp7ot7XlvILmraXnvJbnqIvmqKHlnovn +moTmvJTlj5gNCiAgQ2hyb21lIE9T5a+56LC35q2M5pyq5p2l5aKe6ZW/6Iez5YWz6YeN6KaB55qE +MTDkuKrnkIbnlLHln7rkuo5XZWLmk43kvZzns7vnu5/mmK/mnKrmnaUNCiAgW+aOqOiNkOmYheiv +u13miZPpgKDnp7vliqjlvIDlj5Hlm6LpmJ/nmoTkupTkuKrluLjop4Hor6/ljLrmnaXoh6pHb29n +bGXnp7vliqjlm6LpmJ/nmoTnu4/pqowNCiAg5oqA5pyv5LiO5Lqn5ZOB5Lit5Zu955S15L+h5aSp +57+856m66Ze05ZCI5L2c5LyZ5Ly05Lqk5rWB6K665Z2b77yI5Y6m6Zeo56uZ77yJ5Y+s5byA5b2T +5Yqo5ryr6YGH5LiK55S15L+hDQogIOaWsOa1quW+ruWNmuW8gOWPkeiAheWIm+aWsOWfuumHkeW8 +gOWni+aOpeWPl+eUs+ivt+WNleeslOaKlei1hDMwMOS4h1JNQuS7peS4iw0KICDnu7Tln7rop6Pl +r4bkuLvnq5nngrlXaWtpTGVha3Mub3Jn5Zyo576O5Zu95oGi5aSN6K6/6Zeu5YWo55CD5bu656uL +6LaFMTAwMOmVnOWDjw0KICDosLfmrYzkuLpBcGFjaGXmiYDmnInlvIDmupDpobnnm67mj5Dkvpvm +lrDnmoTlsZXnpLrpobXpnaLkuI3lho3nlLFBcGFjaGXnu4Tnu4fnm7TmjqXnrqHnkIYNCiAg5Y2D +5ZCN566h55CG6ICFU0QyQyAyMDEw57q16K665oqA5pyv5aSn5Yq/IOS4reWbveW8gOWPkeiAhei/ +juadpem7hOmHkeWNgeW5tA0KICBJQk3kuLrlvrflm73lvIDlj5Hmr4/np5Lov5DnrpczMDAw5LiH +5Lq/5qyh6LaF57qn6K6h566X5py66LaF6LaK5Lit5Zu95aSp5rKzMeWPtw0KICDotYTorq/liqjm +gIFhLi4g5bCx5LiaIuS4jeWBmuW8gOWPkeS4jei/mOasviLnmoTln7norq1hLi4g44CQ5Luj56CB +44CRV2luZG93cyBQaG9uZSA36IyD5L6L56iL5bqPYS4uIOWkqee/vOaVmeS9oOenu+WKqOW6lOeU +qOiQpeWIqeS5i+mBk2EuLiDorr/osIgg5b6u6L2v6ZKf5Y2r6LCISUU55Y+Y6Z2p5LiT6aKY5pu0 +5aSaYS4uIA0KICBUZWNo4oCiRWQgMjAxMGEuLiANCiAgSGFkb29w5oqA5pyv5LiT6aKYYS4uIA0K +ICDmjqLorqjova/ku7booYzkuLrop4TojINhLi4gDQogIEFkb2JlIE1BWCAyMDEwQ1NETuenu+WK +qOW+ruWNmiAgIOaIkeimgeWFs+azqCA+PuabtOWkmueyvuW9qeWGheWuue+8jOWwveWcqOenu+WK +qOmikemBkw0KICDliJjoiKrvvJrkurrmsJHmkJzntKLlrp7pmYXnoJTnqbbnmoTmmK/kurrmsJHo +oqvmkJzntKIuIC8vQOasp+iTrEFU56e75Yqo5LqS6IGU572ROuS8oOe7n+aQnOe0ouW8leaTju+8 +iOavlOWmguiwt+atjO+8ieeglOeptuaAjuS5iOiuqeWkp+WutuaQnOWHuuS/oeaBr++8jOWug+eg +lOeptuaAjuS5iOiuqeWkp+WutuaQnOS4jeWHuuS/oeaBr+OAgi7mnI3kuobmpbzkuLvjgIIgLy9A +d2FzYTrmnIDlkI7kuIDlj6Xkuq7kuobjgILjgIINCiAgOSBob3VycyBhZ28NCg0KICDnjovoiKpo +ZGbvvJpDTk5JQ+eahOS7o+eQhui/meW4ruWtmeWtkOS5n+S4jeWKqOWKqOiEkeWtkO+8jOavj+ma +lOS4gOauteaXtumXtOmDveiDveaOpeWIsOWQjOagt+eahOeUteivne+8jOivtOazleWujOWFqOS4 +gOiHtO+8jOmDveaYr+ivtOWIq+S6uuimgeaKouazqOS9oOeahOS6kuiBlOe9keWTgeeJjOKAlOKA +lOmAmueUqOe9keWdgO+8jOaIluiAheaYr+aKouazqOS9oOeahOenu+WKqOS6kuiBlOe9keWTgeeJ +jOKAlOKAlOaXoOe6v+e9keWdgO+8jOS9oOS4q+i/nuiKseagt+mDveaHkuW+l+aNou+8jOWHoOW5 +tOWmguS4gOaXpeeahOi/meagt+ihjOmql+OAguaIkeWunuWcqOW/jeaXoOWPr+W/je+8jOS9oOS7 +rOi/meW4ruWtmeWtkO+8jOadpeeCueS4k+S4mueyvuelnuWlveS4jeWlve+8nw0KICA5IGhvdXJz +IGFnbw0KDQogIOeXnuWtkDQyMDbvvJrjgIrkupLogZTnvZEv56e75Yqo5LqS6IGU572R5bCP5Zui +6Zif5Yib5LiaIOesrOS6jOmbhiDmsarljY7jgIsgaHR0cDovL3NpbmF1cmwuY24vaDR3M3pmDQog +IDkgaG91cnMgYWdvDQoNCiAg5p2O5ZCN5aSr77yaLy9A5qyn6JOsQVTnp7vliqjkupLogZTnvZE6 +MTDlubTkuoblkKfvvJ/pgqPkuInkur/pg6jkuZ/lpJ/niZvpgLznmoTkuobjgILkuI3nn6XpgZPm +nInlpJrlsJHpg6jmmK/lhoXplIDnmoTjgIINCiAgOSBob3VycyBhZ28NCg0KICDotbXmtIticnVj +Ze+8muadgOavkui9r+S7tuaDr+eUqOS8juS/qe+8jOiEseS6humprOeUsuS7lui/mOaYr+S5jOm+ +n+OAgiAvL0Dolpvom67lrZA65q2k6aOO5LiN5Y+v6ZW/77yM5ZOq5pyJ5Yy755Sf5YWI5pKS55eF +5q+S5YaN5rK755eF55qE44CC5bqU6K+l56uL5rOV5Lil56aB77yBIC8vQOasp+iTrEFU56e75Yqo +5LqS6IGU572ROiDpgKDnl4Xmr5Lml6nlsLHmmK/nlLXohJHooYzkuJrmg6/kvovjgILmiYvmnLro +oYzkuJrkuZ/kuI3kvovlpJblkKfjgIIgLy9A6LW15bKXOui9rOWPkeW+ruWNmg0KICA5IGhvdXJz +IGFnbw0K5pu05aSa56e75Yqo6LWE6K6vIOivt+i/m+WFpT4+5pu05aSa44CK56iL5bqP5ZGY44CL +5YGa5pyJ5biC5Zy65oCd57u055qE5byA5Y+R5Lq65ZGYDQogIFdhdHRzIFMuIEh1bXBocmV577ya +6L2v5Lu26LSo6YeP5LmL54i2DQogIOWuieWFqOato+WboOS6keiAjOaUueWPmA0KICDokovmtpvv +vJrmoqbmg7PnmoTljYHlubTmm7TlpJrng63ngrnotYTorq/mjpLooYznibnnq4vni6zooYznmoTn +qIvluo/lkZjvvJrnu7Tln7rop6Plr4bliJvlp4vkurrpmL/moZHlpYfkvKDlpYdHbWFpbOS5i+eI +tu+8mkNocm9tZSBPU+adpeaXpeaXoOWkmkxCU+WwhuaIkOS6kuiBlOe9keS4i+S4gOWcuuihgOiF +peaImCAy5bm05ZCO5biC5Zy66LaF55m+5Lq/5aSW5aqS6K+E6YCJ6L+H5Y67MjXlubQxMOWkp+m7 +keWuouaUu+WHu+S6i+S7tuW+rui9r+Wuo+W4g+WPiOS4gOmdnldpbmRvd3Pmk43kvZzns7vnu59W +ZXJ2ZUNocm9tZSBPU+eahOelnuenmOmtheWKm+iLueaenOW3peeoi+W4iOeUqOS5kOmrmOenr+ac +qOmHjeW7uuacgOWPpOiAgeiuoeeul+acuumYv+W4leWlh+WfuumHkeS8muassumAgOWHukphdmHl +p5TlkZjkvJog55Sy6aqo5paH5pyb5YW25LiJ5oCdMjAxMOW5tOa2iOi0ueeUteWtkOaKgOacrzIw +5Liq5pyA5aSn5aSx6LSl77yaQnV6euWxhemmluS6uuawkeaQnOe0ou+8muS4jeS4juWVhuS4muaQ +nOe0ouato+mdouernuS6iWEuLiBhLi4gfOabtOWkmuWtpuS5oOepuumXtA0KICAxMi0xNeiusuWg +giBMaW51eOezu+e7nw0KICAxMi0xNeiusuWggiDlnIblkajnjofnmoTov5HkvLzorqENCiAgMTIt +MTborrLloIIgTGludXjns7vnu58NCiAgMTItMTforrLloIIg5aSn5a2m55Sf6IGM5Lia55Sf5rav +DQogIOeslOiusCAuTmV05LmL5byA5rqQ5ZKM5LiN5byA5rqQ55qEDQogIOeslOiusCDkuIDkupvl +pKflhazlj7jnmoTlv4PnkIbmtYvor5XpopgNCiAg6K++5aCCIOS4i+Wtpuacn+eahOW1jOWFpeW8 +j+mAieS/ruivvumAieWQpg0KICBKYXZh6K++5aCCIOaVsOaNruaMluaOmOS6p+WTgeWSjOW3peWF +tw0KICAyMDEw5bWM5YWl5byP6KGM5Lia5bm057uI55uY54K56K6y5bqnDQogIOS4rei9r+mbhuWb +oue7meS4juS4reagh+i9r+S7tuWFqOmdouaUr+aMgQ0KICDpmo/ml7bpmo/lnLDlraboi7Hor63v +vJ/oi7HlrZrmiYvmnLrlupTnlKjmnaXluK7kvaAhDQogIElU6L6+5Lq677ya5pWZ5L2g546p6L2s +5aW95Y6L5Y6L57yp6L2v5Lu2DQogIOS6uuWkp+mHkeS7k+WKqeWKm+WNq+eUn+ihjOS4muS/oeaB +r+WMlnzmm7TlpJrpobnnm67nsr7pgIkNCiAg5py65Zmo6KeG6KeJLeminOiJsuWIhuexuw0KICBN +VEsgRkxBU0jmkq3mlL7lvJXmk47lvIDlj5ENCiAgUERG6Jma5ouf5omT5Y2w5py677yI6ZmQ5YyX +5Lqs77yJDQogIOW9qeelqOe9keermeeoi+W6j+WFqOWllw0KICBTVE0zMkYxMDPova/ku7blvIDl +j5ENCiAgYW5kcm9pZOWuouaIt+err+W8gOWPkQ0KICDpn7Pop4bpopHlub/mkq3mjqfku7YNCiAg +SU3ova/ku7bpobnnm67lpJbljIXlvIDlj5F85pu05aSa6LWE5rqQ57K+6YCJDQogIEPor63oqIDm +lbDmja7nu5PmnoTln7rmnKzmk43kvZwNCiAgcnVieTEzMTTkuIrkvKDmiJHopoHkuIrkvKANCiAg +5a2m55Sf5L2c5Lia566h55CG57O757ufIEpTUA0KICBmZW5neWFsaW5nZmx5eXnkuIrkvKDmiJHo +poHkuIrkvKANCiAgYysr57yW56iL5bi46YGH6Zeu6aKY5oC757uTDQogIGJ5cmdsNeS4iuS8oOaI +keimgeS4iuS8oA0KICBDIyDlr7zlh7pleGNlbCDlrp7kvovku6PnoIENCiAgb3VfeWFuZ3Blbmdm +ZWnkuIrkvKDmiJHopoHkuIrkvKANCiAgdmLoh6rliqjmjpLniYjnlJ/miJBXb3JkDQogIHRpMTI2 +5LiK5Lyg5oiR6KaB5LiK5Lyg5Y2a5a6i57K+6YCJIOOAkOaOqOiNkOOAkeWkqee/vOaVmeS9oOen +u+WKqOW6lOeUqOiQpeWIqeS5i+mBk+abtOWkmnNvc29fYmxvZ+WIq+iuqeWmiOWmiOeUn+awlOKA +lOKAlOa1heiwiOmVv+iAheeUqOaItw0KICDogIHpgpPkubHor4RHVUnlvIDlj5HmoYbmnrbmnKrm +naXotbDlkJENCiAg5bi46auY5Lyf5YGaSVTmg7PkuI3liqDnj63nnJ/nmoTlvojpmr4NCiAg5ZC0 +5rCR5LyB5Lia5paH5YyW5LiO4oCc6YWx5rK55YWa4oCdDQogIOS4geS6rk5ldEJlYW5zIOaXtuS6 +i+mAmuiur++8iOWIiuWPtyAjIDEyOSAtIERlYyAxNCwgMjAxMO+8iQ0KICDpvZDnkKhPcmFjbGUg +T3BlbiBXb3JsZOOAgUphdmFPbmXjgIFPcmFjbGUgRGV2ZWxvcGVyIOesrOS6jOaXpQ0KICDlvKDl +m73lqIFBbmRyb2lk5o+Q6auY56ys5Y2B5LqU56+H5LmLTGlzdFZpZXfoh6rpgILlupTlrp7njrDo +oajmoLwNCiAg5pyx6YeR54G/5Z+65LqO5a+56K+d5qGG55qE566A5Y2V5Y+M57yT5Yay57uY5Zu+ +5qGG5p62DQogIOeOi+eRvuWNjlN5bWJpYW5eM+eOr+Wig+WuieijheaJi+iusA0KICDotZbli4fm +tannlKggUHl0aG9uIOeahCBEZXNjcmlwdG9yIOeJueaAp+ino+WGs+S4gOS4quWPmOaAgeeahOmX +rumimA0KICBqYW1lc+OAiuWkp+mBk+iHs+eugOOAi+ivu+S5pueslOiusA0KICDlvKDkuq5BbmRy +b2lkIOW8gOWPkeWInee6p+WFpemXqO+8muazqOWGjOiwt+atjOWcsOWbviBBUEkg5a+G6ZKl5ZKM +5pi+56S66LC35q2M5Zyw5Zu+DQogIOaigeaWjOaYqOWkqeW+rui9r+S6mueglOmZouiHqueEtuiv +reiogOWkhOeQhue7hOeahOWRqOaYjuWNmuWjq+e7meaIkeS7rOWBmuS6huaKpeWRig0KICDlkJXl +u7rkvJ/kuIDkuKrkvJjnp4DnmoTnoJTlj5Hlm6LpmJ/lupTor6XlhbflpIfku4DkuYjnibnlvoEN +CiAgYXp1cmVjaGluYeeOsOWunuS4lueVjOeahFdpbmRvd3MgQXp1cmU6IOS4jklNUEFDVEHmgLvo +o4HvvIxLZXZpbiBMYW3nmoTorr/osIgNCiAg6YeR5pet5Lqu6Ieq5rWL5LiA5LiL5L2g55qESmF2 +YeaOjOaPoeW+l+aAjuS5iOagt++8nw0KICDpuY/lh4zkuInljYMoY3BpbmfkuLrku4DkuYjmsqHm +nInlpb3nlKjnmoRBbmRyb2lk5ri45oiP5byV5pOO77yfDQogIOWykeaWh+WInUZhY2Vib29r5LyY +5YyW5YiG5Lqr5ZCO6K6wDQogIOiWm+esm+eUqEMrK+WGmUphdmEgU3R5bGXnqIvluo8NCiAg55uW +5Zu95by6T3JhY2xl5pWw5o2u5bqT5oGi5aSNIDog5a2Y5YKo5pWF6Zqc5a+86Ie055qE5pWw5o2u +5o2f5Z2PDQogIOacsemHkeeBv0dESSvlrabkuaDkuYvnur/mgKfmuJDlj5jnlLvliLcNCiAg5ZGo +54ix5rCR57un5om/5LiO5re35ZCI77yM55Wl6LCI57O757uf55qE5p6E5bu65pa55byPDQogIOW8 +oOWuh+aPkuS7tuW8j+aetuaehOiuvuiuoeWunui3teS6jO+8muWfuuS6jlNpbHZlcmxpZ2h055qE +Qi9T5o+S5Lu25byP5p625p6E6K6+6K6h5pa55rOVDQogIOacsemHkeeBv+S6jOe7tOWbvuW9oue8 +lui+keS4reeCuemAieWPluetlueVpeeglOeptg0KICDpu4TpuY/nqItMaW51eOeOr+Wig+S4i+ea +hEMvQyvln7rnoYDosIPor5XmioDmnK8y4oCU4oCU56iL5bqP5o6n5Yi2DQogIOeZveaFp+WGrFvl +hajnqIvlu7rmqKFd57G75Zu+5ZKM5pe25bqP5Zu+55qE5byA5Y+R5YWz57O777yM5LuO55So5L6L +6LCI6LW355qE5YWo56iL5bu65qihDQogIGEuLiDlubTolqoxNS0yMOS4h+aApeaLm2phdmHorrLl +uIjvvIFhLi4g5aSp57+85pWZ5L2g56e75Yqo5bqU55So6JCl5Yip5LmL6YGTYS4uIOW/q+aNt+i9 +rOWei0FuZHJvaWTpq5jolqrkurrmiY1hLi4g5Y+y5LiK5pyA57uZ5Yqb55qE5YWN6LS5UEhQ6KeG +6aKR5pWZ56iL5pu05aSa5Y2a5a6i5LmL5pif5b6u6L2v5LqR6K6h566X5Lit5paH5Y2a5a6iDQog +IOacrOS4reaWh+WNmuWuoueUseW+rui9r+S6keiuoeeul0F6dXJl6K665Z2b5pSv5oyB5bCP57uE +5byA5Yqe44CC5YaF5a655LulV2luZG93cyBBenVyZSBQbGF0Zm9ybeS4uuS4u+OAgg0KICDorr/p +l67ku5bnmoTnqbrpl7TlnKhXaW5kb3dzIEF6dXJl5bmz5Y+w5LiK6YOo572y5pyN5YqhDQogIFdp +bmRvd3MgQXp1cmUgQ2xvdWRQb2xsIGZvcg0KICBUYWJsZSBTdG9yYWdl5a+55YiG6aG155qE5pSv +5oyBDQogIOWmguS9lemAieaLqeiZmuaLn+acuuinhOagvA0KICDlvIDlj5Hmi5PlsZXmkJzntKIt +5pWR5o+05bqU55So56iL5bqPDQogIOeOsOWunuS4lueVjOeahFdpbmRvd3MgQXp1cmXmm7TlpJpD +VE/kv7HkuZDpg6jmrKLov47lpKflrrbliqDlhaVDVE/kv7HkuZDpg6gs6L+Z5piv6Z2i5ZCR6auY +56uv5oqA5pyv566h55CG6ICF55qE56S+5Yy644CCW+aIkeimgeWKoOWFpV0NCiAgWzHkurrlm57l +pI1d5YWz5LqO6ICB5aSW5a6e55So55qE5Y6L57yp6L2v5Lu26Zeu6aKYDQogIFsxNOS6uuWbnuWk +jV3lvbzlvpflvrfpsoHlhYvjgIrnrqHnkIbnmoTlrp7ot7XjgIvmnK0NCiAgWzEx5Lq65Zue5aSN +Xei/kOiQpeexu+mhueebruS9nOS4uuWIm+S4muaAp+mhueebruavlA0KICBbM+S6uuWbnuWkjV3l +nKjnu4bliIbluILlnLrkuK3lr7vmib7liJvkuJrmnLrkvJoNCiAgWzLkurrlm57lpI1d5a+75rGC +6L2v5Lu25LiA5qy+fg0KICBbODLkurrlm57lpI1dMTHmnIgyNeaXpeaJi+acuuWuouaIt+err+S4 +k+WnlA0KICBbMOS6uuWbnuWkjV3kuK3ltYzljY/kvJrnrKzlm5vmnJ/igJzltYzlhaXlvI/kuI7n +iakNCiAgWzTkurrlm57lpI1d4oCc5LqR6K6h566X4oCd5bqU5LiN5bqU6K+l5piO56Gu6KeE6IyD +5pu05aSa54Ot5paH5o6S6KGM6Z2i5ZCR56iL5bqP5ZGY55qE5pWw5o2u5bqT6K6/6Zeu5oCn6IO9 +5LyY5YyW5rOV5YiZ6aG257qn56iL5bqP5ZGY55qE5b+D5b6XIC0gQ29kZXJzIGF0IFdvcmtMaW51 +eOeOr+Wig+S4i+eahEMvQysr5Z+656GA6LCD6K+V5oqA5pyvMeKAlOKAlOWIneatpeS6huinozIw +MTDlubTvvIxMaW51eOWkp+S6i+iusOW+geWPi+WQr+S6i+ato+aWh2xvYWRydW5uZXLkuK0gdGhp +bmt0aW1lIOWmguS9lei/kOeUqOmaj+acuuaXtumXtO+8jOW5tuimgeaKiuaXtumXtOWumuWcqOav +q+enkue6p2xpbnV4IOS4i+WPlui/m+eoi+WNoOeUqCBjcHUv5YaF5a2YIOacgOmrmOeahOWJjTEw +5Liq6L+b56iLamF2YeefpeivhueCueWmguS9leS4suaOpeaipuaDs+WNgeW5tC0t44CK56iL5bqP +5ZGY44CL5Y2B5bm05oSf5oOz5oiR5Lus5Li65LuA5LmI5LiN5Zac5qyi5oub6IGY5Z+56K6t5a2m +5qCh55qE5a2m55Sf77yfYS4uIGEuLiB85pu05aSa5Zu+5Lmm5o6S6KGM5qacDQogIGEuLiBIYWRv +b3DmnYPlqIHmjIfljZfvvIjkuK3mlofniYjvvInnqIvluo/lkZgoMjAxMOW5tDEy5pyI5YiKIOaA +u+esrDLkupLogZTnvZHov5DokKXmmbrmhafigJTpq5jlj6/nlKjlj6/mianlsZXnvZHnq5nmioBN +eVNRTOaKgOacr+WGheW5lTpJbm5vRELlrZjlpoLkvZXnrqHnkIbova/ku7bkvIHkuJoo56ysMueJ +iCnnrpfms5Xlr7zorrrvvIjljp/kuabnrKwy54mI77yJKDA55bm05bqm55WF5rex5YWl55CG6Kej +6K6h566X5py657O757ufKOWOn+S5puesrDLniYgpKFNFT+WunuaImOWvhueggeKAlDYw5aSp572R +56uZ5rWB6YeP5o+Q6auYSFRNTCA155So5oi35oyH5Y2XKOWPjOiJsuWNsOWIt++8jOWtpkphdmHn +vJbnqIvmgJ3mg7Mo56ysNOeJiCko57uP5YW45Zu+6Jma5ouf6Jyc572Q77ya5LuO5YO15bC4572R +57uc6L+96Liq5Yiw5YWl5L61DQogIOmdouWvuei2iuadpei2iuWkjeadgueahOmAg+mBv+aKgOac +r++8jOS7peWPiumHh+eUqOWKoOWvhuaKgOacr+adpeS/neaKpOe9kee7nOmAmuS/oe+8jOmYsuat +ouiiq+eqg+WQrOeahOWNj+iurui2iuadpei2ii4uLmpCUE005bel5L2c5rWB5bqU55So5byA5Y+R +5oyH5Y2XDQogIOacrOS5puWwhuS9v+aCqOW/q+mAn+S6huino+S7gOS5iOaYr+W3peS9nOa1geOA +gUJQTeWSjGpCUE3vvIzku6Xlj4rlroPku6znmoTlj5HlsZXljobnqIvjgILlvZPnhLbvvIzph43o +poEuLi5MaW51eOmCo+S6m+S6i+WEvw0KICDmnKzkuabln7rkuo4yLjYuMjLlhoXmoLjvvIzlr7lV +U0LlrZDns7vnu5/nmoTlpKfpg6jliIbmupDku6PnoIHpgJDooYzov5vooYzliIbmnpDvvIzns7vn +u5/lnLDpmJDph4rkuoYuLi7npL7ljLrmm7TlpJpDU0RO5oqA5pyv55ub5a60U0QyLjDlpKfkvJrl +nIbmu6Hnu5PmnZ8NCiAganY5U2lsdmVybGlnaHQvV1BGL1dQN+S4gOWRqOWtpuS5oOWvvOivuygx +MuaciDYtMTLmnIgxMikNCiAgZ3VndWRhMjAwOOaKilRFTVBEQuaUvuWIsOWGheWtmOmHjA0KICBp +bnZhbGlkYXRlMDAxMeWPpuexu+ijhemlsOS9oOeahFdpbmZvcm0gLSDlnKjnqpflj6PnmoTlt6bk +uIrop5LliqDkuIDkuKrlnKPor57luL0NCiAgemN0eW1qeFdpbkNFIDYuMCDpqbHliqjlvIDlj5Hj +gIHlhoXmoLjlrprliLbmlrnpnaLnmoTkuabkuLvopoHmnInpgqPkupvvvJ8NCiAgcGlnZzE4d2lu +ZG93cyB4cCDlkozomZrmi5/mnLrnmoTlm7Dmg5EgeWVhaA0KICBPbmVPbmNl5L+u5pS5aS5NWDUx +NSBFQk9PVOWkp+Wwjw0KICBseXNlcnZlcuiuqeS6uue6oOe7k+eahOS4ieWxguaetuaehA0KICBx +aXhpbmdoYWl0YW5nMTIz5b+F6K+777ya5aaC5L2V5oiQ5Li65LiA5ZCN5LyY56eA55qEQW5kcm9p +ZOW8gOWPkeiAhQ0KICDnpL7ljLrnsr7ljY435Lq65pS26JePMTDnp43noLTpmaTnvZHpobXorr7o +rqHluIjpmpznoo3nmoTlrp7nlKjmlrnms5UNCiAgNuS6uuaUtuiXj2xpbnV457yW56iL55qEMTA4 +56eN5aWH5rer5ben6K6hLTEyKOWtmOWCqOiuoeeulynnu60NCiAgNOS6uuaUtuiXj+S4uuS7gOS5 +iOivtOS6keiuoeeul+aYr+enu+WKqOeahOacquadpQ0KICAy5Lq65pS26JePMjAxMOW5tOa2iOi0 +ueeUteWtkOaKgOacrzIw5Liq5pyA5aSn5aSx6LSl77yaQnV6euWxhemmlg0KICA15Lq65pS26JeP +55SoQyDlhplKYXZhIFN0eWxl56iL5bqPDQogIDjkurrmlLbol4/oh6rmtYvkuIDkuIvkvaDnmoRK +YXZh5o6M5o+h5b6X5oCO5LmI5qC377yfDQogIDTkurrmlLbol4/ljY7kuLrpnaLor5Xpopjnrpfk +u4DkuYgs6L+Z5Liq6IOM5Lya5LqG5aSW5LyB6ZqP5L6/6L+bDQogIDPkurrmlLbol4/nqIvluo/l +kZjvvJrnvJbnqIvnu5nkvaDnjrDlrp7nlJ/mtLvluKbmnaXkuoblk6rkupvlnY/kuaDmg68NCiAg +NeS6uuaUtuiXj+e7p+aJv+S4jua3t+WQiO+8jOeVpeiwiOezu+e7n+eahOaehOW7uuaWueW8jw0K +ICDmnIDmlrDnvZHmkZjjgJDlhazlkYrjgJFDU0RO6auY5qCh5L+x5LmQ6YOo5Li75bit54Gr54Ot +5oub5Yuf5LitDQogIOOAkOWkqea0peOAkeWkqea0peiBjOS4muWkp+WtpkNTRE7pq5jmoKHkv7Hk +uZDpg6jmraPlvI/miJDnq4sNCiAg44CQ6am76ams5bqX44CR6buE5reu5a2m6Zmi56ys5LiA5pyf +5Zyo57q/6K6y5aCC5oiQ5Yqf5Li+5YqeDQogIOOAkOS/neWumuOAkeays+i9r0NTRE7pq5jmoKHk +v7HkuZDpg6jmraPlvI/miJDnq4sNCiAg44CQ5L+d5a6a44CRQ1NETumrmOagoeS/seS5kOmDqOiQ +veaIt+ays+WMl+mHkeiejeWtpumZog0KICDpq5jmoKFjbHVi5pu05aSa56S+5Yy65LmL5pif6JKL +5pmf77ya56S+5Yy65LiT5a62DQogIENTRE7lpKfniYjkuLss5b6u6L2v5pyA5pyJ5Lu35YC85LiT +5a6277yM5pOF6ZW/Lk5FVOOAgUFjdGl2ZVjjgIFBcHBsaWNhdGlvbg0KICDorr/pl67ku5bnmoTn +qbrpl7Tmm7TlpJrnpL7ljLrmlrDor53popjlt6XkvZzkuK3nmoTlsI/mj5Lmm7LvvIzop4Hor4ZD +U0RO6L6+5Lq6DQogIOWPkeWpmueFp++8jOaxguelneemj35+fu+8gQ0KICDvvIjovazvvInlm6Dk +uLrmiJHmmK/kvaDlqrPlpoflhL8NCiAg5a+55Zac5qyi55qE5Lq65pS+5byD6L+Y5piv57un57ut +77yf5oiR5b6I55+b55u+DQogIOWwj+aXtuWAmeiiq+e9mu+8jOW5sui/h+i/meenjeS6i+aDheea +hOerpemei+ivt+S4vuaJiw0KICDjgJDljJfkuqzjgJHlm5vlubTlt6XkvZznu4/pqoznnJ/nmoTo +g73mi784S+S5iO+8nw0KICDlsI/lvJ/mmI7lpKnkuIvljYjljrvohb7orq/pnaLor5UNCiAg5o6o +6I2Q5Yeg6YOo5Y2w5bqm55qE55S15b2xfn4NCiAg6ICB5p2/eXXlkZjlt6XnmoTlr7nor53vvIjm +kJ7ogIznnJ/vvIkNCiAg5bu66K6uY3NkbuW8gOS4gOS4queUt+aAp+WBpeW6t+adv+Wdl+abtOWk +mueoi+W6j+S6uueUn1NE6L2v5Lu25aSn5Lya5ZyG5ruh57uT5p2fIOWqkuS9k+aKpemBk+WPiueb +uOWFs+WBtuWSjOWBtueahOWQjOWtpuW8oOS6jOeLl++8iOi+g+WujOaVtOeJiO+8iemAg+emu+S4 +gOe6v+WfjuW4guWkp+Wutui/mOS8muS7juS6i+WOn+adpeaWueWQkeWQl++8n+aBouWkjUlF5Li6 +6buY6K6k5LiL6L295bel5YW35LuK5pel6LWb5LqL5o6o5LuL77ya5pu86IGUIFZTIOmYv+ajrue6 +s+WmguS9leaIkOS4uuS4gOWQjeS8mOengOeahEFuZHJvaWTlvIDlj5HogIVbI3c2VEN1c0tSdzZm +Q3ZNS1d3NmZDb01LQiNd5LqR57yW56CBU0QyLjDlpKfkvJrpmobph43lvIDluZUs56S+5Yy6546w +5Zy65Zu+5paH55u05pKt5aSn5a626L2s5q2j55qE5bel6LWE5pyJ5rKh5pyJ5a6e5Lmg55qE5pe2 +5YCZ5aSa77yf5YWl6KGM5LiA5bm05aSa5LuO5rKh5oSf5Y+X5Yiw6L2v5Lu25byA5Y+R5Zac5oKm +5ZCI5L2c5LyZ5Ly05paw5rWq56eR5oqA4oCUIOaQnOeLkElU4oCUIERvTmV3c+KAlCBaRE5ldOiH +s+mhtue9keKAlCDnrKzkuInlqpLkvZPigJQg5aSp5p6B572R4oCUIOiuoeS4lue9keKAlCDmiYvm +nLrkuYvlrrbigJQgNTHop4bpk4PigJQg546p572R5L2T6IKyIOKAlOaIkeimgeWcsOWbviDigJRK +b2huIEJyeWNlDQoNCum+meaLk+S6kuWKqOKAlCDkuIfoirHnrZLml4XmuLjigJQg6K+65Z+65Lqa +6K665Z2b4oCUIOeUteWtkOW3peeoi+KAlCDlvIDmupDkuJPlrrbnvZHigJQg6KeG6KeJ5Lit5Zu9 +4oCUIOWPpemFt+S+i+WPpeKAlCDkupLliqjnmb7np5HigJQgRE9JVOKAlCBEYXRhc2hlZXTigJQg +6LGG5LiB572R4oCUIOWlveWkp+Wkq+WcqOe6vw0KICDlhazlj7jnroDku4t85oub6LSk57qz5aOr +fOW5v+WRiuacjeWKoXzpk7booYzmsYfmrL7luJDlj7d86IGU57O75pa55byPfOeJiOadg+WjsOaY +jnzms5Xlvovpob7pl6586Zeu6aKY5oql5ZGKDQogICAgICANCiAg5a6i5oi35pyN5Yqh54Ot57q/ +77yaMDEwLTUxNjYxMjAy44CA6L+d5rOV5L+h5oGv5Li+5oql55S16K+d77yaMTM1NTIwMDk2ODkg +5Li+5oql6YKu566x77yad2VibWFzdGVyQGNzZG4ubmV0DQogIOWMl+S6rOW4guWFrOWuieWxgOac +nemYs+WIhuWxgOe9keebkeS4reW/g+Wkh+ahiOe8luWPt++8mjExMDEwNTA5Njkg5LqsSUNQ6K+B +MDcwNTk45Y+3DQogIOeUteS/oeS4muWKoeWuoeaJuVsyMDA3XeWtl+esrDM4MOWPtyDnlLXkv6Hk +uI7kv6Hmga/mnI3liqHkuJrliqHnu4/okKXorrjlj6/or4EwNzA1OTjlj7cNCiAg5YyX5Lqs5Yib +5paw5LmQ55+l5bm/5ZGK5pyJ6ZmQ5YWs5Y+4IOeJiOadg+aJgOaciQ0KICDkuJbnuqrkuZDnn6Uo +5YyX5LqsKee9kee7nOaKgOacr+aciemZkOWFrOWPuCDmj5DkvpvmioDmnK/mlK/mjIENCiAg5rGf +6IuP5LmQ55+l572R57uc5oqA5pyv5pyJ6ZmQ5YWs5Y+4IOaPkOS+m+WVhuWKoeaUr+aMgQ0KICBD +b3B5cmlnaHQgwqkgMTk5OS0yMDEwLCBDU0ROLk5FVCwgQWxsIFJpZ2h0cyBSZXNlcnZlZCBhLi4g +YS4uIOS7iuWkqeaYrzIwMTDlubQxMuaciDE25pelYS4uIOmmlumhtWEuLiDotYTorq9hLi4g56m6 +6Ze0YS4uIOiuuuWdm2EuLiDljZrlrqJhLi4g5LiL6L29YS4uIOe9keaRmGEuLiDnqIvluo/lkZhh +Li4g6aG555uu5Lqk5piTYS4uIOS5puW6l2EuLiBDVE/kv7HkuZDpg6hhLi4gVFVQYS4uIOWfueiu +reWFheeUtWEuLiDpq5jmoKFjbHViYS4uIOeglOWPkWEuLiDnp7vliqhhLi4gQ2hhbm5lbDlhLi4g +SmF2YWEuLiDlronlhahhLi4g5pWw5o2u5bqTYS4uIC5ORVRhLi4gV2Vi5byA5Y+RYS4uIOS6keiu +oeeul2EuLiDmnI3liqHlmahhLi4g55S15L+hSVRhLi4g5a2m55Sf5aSn5pys6JClYS4uIOeMjuWk +tGEuLiAzR+WtpumZonxhLi4gSmF2YeWtpumZonxhLi4gLk5FVOWtpumZonxhLi4gUEhQ5a2m6Zmi +fGEuLiBJQk0gZFd8YS4uIOiLseeJueWwlCDova/ku7Z8YS4uIOWuieiFvuiHs+W8unxhLi4gTWVl +R298YS4uIE9QaG9uZXxhLi4gRmxleC9BSVJ8YS4uIFZTMjAxMHxhLi4gUXR8YS4uIOeZvuW6puek +vuWMunxhLi4gQmxhY2tCZXJyeXxhLi4gYmFkYXxhLi4g5LiJ5pifU01JfGEuLiDlpKnnv7znqbrp +l7RhLi4g44CQ6aG244CR5bqU5bGK55SfLOWFpeiBjOW5tOiWqjUtMTDkuIcNCiAgYi4uIOaWsFZD +KysgMjAxMOWbvuW9oua6kOeggeW6k+esrDPniYghDQogIGMuLiDkuI3mh4JDKyvkuI3mmK/nnJ/m +raPnmoTnqIvluo/lkZjvvIENCiAgZC4uIOaKpeWQjUlCTeW8gOWPkeiAheWkp+S8mui1ouWkmuen +jeWkp+Wllg0KICBlLi4gQ29kZU1ldGVy6L2v5Lu25Yqg5a+G5oqA5pyv56CU6K6o5LyaDQogIGEu +LiBhLi4g5L2/55SoWE5B5qGG5p626L+b6KGMM0TmuLjmiI/lvIDlj5ENCiAgYi4uIFBIUOWtpuS5 +oO+8jOWFiOWwseS4mu+8jOWQjuWIhuacn+i/mOasvg0KICBjLi4g5rC05rOi5pWI5bqUQW5kcm9p +ZOa6kOeggQ0KICBkLi4gNjDkuIflpZbph5FWU+ebm+Wkp+eoi+W6j+i+vuS6uui1mw0KICBlLi4g +OOWkqei9rOWeizNH77yM5pyI6JaqNEvlj5g4Sw0KICBhLi4gYS4uIOS7iuaXpeWktOadoUZhY2Vi +b29rIENFT+W9k+mAiTIwMTDjgIrml7bku6PjgIvlubTluqbpo47kupHkurrniakNCltGYWNlYm9v +a+S8sOWAvDPkuKrmnIjlop7plb83NyUg5Lyw5YC86L6+NDMw5Lq/576O5YWDXVvmr4/ml6Xpgq7m +iqXvvJrosLfmrYzlkoxGYWNlYm9va+eahOaImOS6iV0NClvml7bku6PlkajliIrvvJrnu7Tln7ro +p6Plr4blsIbotaLlvpfkv6Hmga/miJjkuoldW+OAiuaXtuS7o+WRqOWIiuOAi+ivhOWHujIwMTDl +ubTljYHlpKdpUGhvbmXlupTnlKhdDQoNClvljZrlrqJd6auY5pWI5a2Y5YKo5oqA5pyv56CU56m2 +DQpb6auY5bm25Y+R6auY5rWB6YeP572R56uZ5p625p6EXVvlhbPkuo7mlbDmja7mjJbmjpjlhbPo +gZTop4TliJnnmoRPcmFjbGXlrp7njrBdDQoNCuW+gOacn+WktOadoe+8mkdtYWls5LmL54i277ya +Q2hyb21lIE9T5p2l5pel5peg5aSaICAgIOWkqee/vOaVmeS9oOenu+WKqOW6lOeUqOiQpeWIqeS5 +i+mBkw0K5pyA5paw5rS75YqoIHwg56iL5bqP5ZGY5p2C5b+XDQogIOiHqueUsSDliIbkuqsg5YWx +6LWiIOW8gOWIm+enu+WKqOS6kuiBlOe9keacquadpe+8jOWkqee/vOaVmeS9oOenu+WKqOW6lOeU +qOiQpeWIqeS5i+mBk++8gTEy5pyIMTfml6XvvIzljqbpl6jnq5njgIINCiAgT3BlbkZlaW505ri4 +5oiP5byA5Y+R6ICF576k6Iux5LyaDQogIOOAiueoi+W6j+WRmOOAi+WNgeW5tOiBlOaJi+ebm+Wk +p+eJueaDoOa0u+WKqA0KICDnrKzkuZ3ln47luILljYPkuIfnjrDph5HlvoHpm4bnsr7lk4HmuLjm +iI/vvIENCiAg56ys5YWt5bGK56e75Yqo5LqS6IGU572RVE9QNTDor4TpgIkNCiAg5peg57q/5LqS +6IGU5Yib5Lia5a6e5oiY6K6y5bqnwrfljJfkuqwNCiAg44CK5pWP5o235byA5Y+R4oCU5rWL6K+V +566h55CG44CL5o+Q6Zeu6LWi5aWW54Ot6Zeo5oub6IGY6IGM5L2NDQogIOOAkOeAmuS/oeenkeaK +gOOAkeivmuiBmCBXSU5ET1dTIEMrKyBXSU5ET1dTIEMj5Lit6auY57qn5byA5Y+R5bel56iL5biI +44CQ6YW35oiR6Z+z5LmQ55uS44CR6auY6Jaq6K+a6IGYIOa/gOaDheeIseWlveW3peS9nOiejeS4 +uuS4gOS9k+OAkOi+vuWGhembhuWbouOAkemrmOiWquivmuiBmEpBVkHorrLluIgu5bWM5YWl5byP +6K6y5biILjNH6K6y5biILuaKgOacr+aAu+ebkS7liIblhazlj7jmgLvnu4/nkIbjgJDlpKnpmYXn +vZHjgJHmgKXogZhKYXZh5bqU55So5p625p6E5biI44CB6auY57qnSmF2YeW3peeoi+W4iOOAgee9 +kemhteiuvuiuoeW4iOOAkOS4iua1t+mFt+WoseOAkemrmOiWquaApeiBmOacjeWKoeWZqOS4u+eo +i+OAgeacjeWKoeWZqOeoi+W6j+OAkOWIm+aWsOW3peWcuuOAkeaKgOacr+exu+iBjOS9jeeDreaL +m++8jOeri+WNs+WKoOWFpeWxnuS6juS9oOiHquW3seeahOWFrOWPuOOAkOWuveWoseaVsOeggeOA +keivmuiBmEMrK+W6lOeUqOi9r+S7tuW3peeoi+W4iO+8iOWkmuWqkuS9ky/nvZHnu5zmlrnlkJHv +vInjgIEubmV05byA5Y+R5bel56iL5biI44CQ5ZuiODAw44CRTm8uMeWboui0reWvvOiIquivmuiB +mFJ1Ynkgb24gUmFpbHPpq5jmiYvvvIHjgJDnvo7lm73lm73lrrbku6rlmajjgJHor5rogZjpq5jn +uqfova/ku7Yg5bel56iL5biIIOS/oeWPt+WkhOeQhui9r+S7tumDqOmXqOe7j+eQhuOAkOa1meax +n+mpsOa1t+WunuS4muOAkeivmuiBmOmhueebrue7j+eQhu+8jFBIUCxNWVNRTCxTRU8s5rWL6K+V +77yM6L+Q57u077yM562W5YiS77yM6K6+6K6h562J6IGM44CQSW5mb3N5c+OAkeivmuiBmO+8mkoy +RUUg6aG555uu5Li7566hL++8iOi1hOa3se+8iei9r+S7tueglOWPkeW3peeoi+W4iC8uTmV06LWE +5rex6L2v5Lu256CU5Y+R5bel56iL5biI44CQ5YyX5Lqs6auY5oiQ6ZW/5YWs5Y+444CR6auY6Jaq +5oub6IGYLm5ldOWQhOe6p+eoi+W6j+WRmO+8jOasoui/juW6lOWxiueUn+OAkOmTtuihjOmhueeb +ruOAkeivmuiBmGphdmHliY3lj7Av5ZCO5Y+w5byA5Y+R5Lq65ZGY5aSa5ZCNIOWPilNBU+aVsOaN +ruWIhuaekOWRmO+8jOassuivleS7jumAn++8geOAkOWMl+S6rOmXu+iogOenkeaKgOOAkeivmuiB +mC5uZXTpq5jnuqflvIDlj5Hlt6XnqIvluIjjgIHmiYvmnLrova/ku7blvIDlj5Hlt6XnqIvluIjv +vIjlupTlsYrmr5XkuJrnlJ/kvJjlhYjvvInjgJDkuIrmtbfnlLXlrZDllYbliqHlubPlj7DjgJHp +h43ph5Hor5rogZgubmV0LGFzcCxqYXZhc2NyaXB06LWE5rex56iL5bqP5ZGY44CQRUblhajnkIPn +oJTlj5HkuK3lv4PjgJHnmb7kuIflubTolqror5rmi5vmioDmnK/nsr7oi7HvvIzmlbDnmb7ogYzk +vY3ng63mi5vkuK3jgJBBbWF6b27jgJHkuprpqazpgIror5rogZjmioDmnK/kuJPlrrbvvIHjgJDn +vZHot6/ml7bku6PjgJHpq5jolqror5rogZhDKyvjgIEubmV05byA5Y+R5bel56iL5biI44CQ5Lqs +5Lic5ZWG5Z+O44CR6K+a6IGY5omL5py65byA5Y+R5bel56iL5biI77yM6L2v5Lu25byA5Y+R5bel +56iL5biI77yM5qyy6K+V5LuO6YCfIeOAkEF1dG9kZXNr44CR5qyn54m55YWL6L2v5Lu2KOS4reWb +vSnor5rogZjova/ku7blvIDlj5Es5rWL6K+VLOeglOeptuWRmOOAkEdvb2dsZeOAkeivmuaLm+aK +gOacr+eyvuiLse+8jOWPsuS4iuS6uuaVsOacgOWkmuiBjOS9jeacgOW5vyHjgJDng63ogZjjgJHm +kJzni5DnlYXmuLjlhajlm73ng63mi5vlvIDlj5Hlt6XnqIvluIjjgJDngJrkv6Hnp5HmioDjgJHo +r5rogZggV0lORE9XUyBDKysgV0lORE9XUyBDI+S4remrmOe6p+W8gOWPkeW3peeoi+W4iOOAkOmF +t+aIkemfs+S5kOebkuOAkemrmOiWquivmuiBmCDmv4Dmg4XniLHlpb3lt6XkvZzono3kuLrkuIDk +vZPjgJDovr7lhoXpm4blm6LjgJHpq5jolqror5rogZhKQVZB6K6y5biILuW1jOWFpeW8j+iusuW4 +iC4zR+iusuW4iC7mioDmnK/mgLvnm5Eu5YiG5YWs5Y+45oC757uP55CG44CQ5aSp6ZmF572R44CR +5oCl6IGYSmF2YeW6lOeUqOaetuaehOW4iOOAgemrmOe6p0phdmHlt6XnqIvluIjjgIHnvZHpobXo +rr7orqHluIjjgJDkuIrmtbfphbflqLHjgJHpq5jolqrmgKXogZjmnI3liqHlmajkuLvnqIvjgIHm +nI3liqHlmajnqIvluo/jgJDliJvmlrDlt6XlnLrjgJHmioDmnK/nsbvogYzkvY3ng63mi5vvvIzn +q4vljbPliqDlhaXlsZ7kuo7kvaDoh6rlt7HnmoTlhazlj7jjgJDlrr3lqLHmlbDnoIHjgJHor5ro +gZhDKyvlupTnlKjova/ku7blt6XnqIvluIjvvIjlpJrlqpLkvZMv572R57uc5pa55ZCR77yJ44CB +Lm5ldOW8gOWPkeW3peeoi+W4iOOAkOWbojgwMOOAkU5vLjHlm6LotK3lr7zoiKror5rogZhSdWJ5 +IG9uIFJhaWxz6auY5omL77yB44CQ576O5Zu95Zu95a625Luq5Zmo44CR6K+a6IGY6auY57qn6L2v +5Lu2IOW3peeoi+W4iCDkv6Hlj7flpITnkIbova/ku7bpg6jpl6jnu4/nkIbjgJDmtZnmsZ/pqbDm +tbflrp7kuJrjgJHor5rogZjpobnnm67nu4/nkIbvvIxQSFAsTVlTUUwsU0VPLOa1i+ivle+8jOi/ +kOe7tO+8jOetluWIku+8jOiuvuiuoeetieiBjOOAkEluZm9zeXPjgJHor5rogZjvvJpKMkVFIOmh +ueebruS4u+euoS/vvIjotYTmt7HvvInova/ku7bnoJTlj5Hlt6XnqIvluIgvLk5ldOi1hOa3sei9 +r+S7tueglOWPkeW3peeoi+W4iOOAkOWMl+S6rOmrmOaIkOmVv+WFrOWPuOOAkemrmOiWquaLm+iB +mC5uZXTlkITnuqfnqIvluo/lkZjvvIzmrKLov47lupTlsYrnlJ/jgJDpk7booYzpobnnm67jgJHo +r5rogZhqYXZh5YmN5Y+wL+WQjuWPsOW8gOWPkeS6uuWRmOWkmuWQjSDlj4pTQVPmlbDmja7liIbm +npDlkZjvvIzmrLLor5Xku47pgJ/vvIHjgJDljJfkuqzpl7voqIDnp5HmioDjgJHor5rogZgubmV0 +6auY57qn5byA5Y+R5bel56iL5biI44CB5omL5py66L2v5Lu25byA5Y+R5bel56iL5biI77yI5bqU +5bGK5q+V5Lia55Sf5LyY5YWI77yJ44CQ5LiK5rW355S15a2Q5ZWG5Yqh5bmz5Y+w44CR6YeN6YeR +6K+a6IGYLm5ldCxhc3AsamF2YXNjcmlwdOi1hOa3seeoi+W6j+WRmOOAkEVG5YWo55CD56CU5Y+R +5Lit5b+D44CR55m+5LiH5bm06Jaq6K+a5oub5oqA5pyv57K+6Iux77yM5pWw55m+6IGM5L2N54Ot +5oub5Lit44CQQW1hem9u44CR5Lqa6ams6YCK6K+a6IGY5oqA5pyv5LiT5a6277yB44CQ572R6Lev +5pe25Luj44CR6auY6Jaq6K+a6IGYQysr44CBLm5ldOW8gOWPkeW3peeoi+W4iOOAkOS6rOS4nOWV +huWfjuOAkeivmuiBmOaJi+acuuW8gOWPkeW3peeoi+W4iO+8jOi9r+S7tuW8gOWPkeW3peeoi+W4 +iO+8jOassuivleS7jumAnyHjgJBBdXRvZGVza+OAkeasp+eJueWFi+i9r+S7tijkuK3lm70p6K+a +6IGY6L2v5Lu25byA5Y+RLOa1i+ivlSznoJTnqbblkZjjgJBHb29nbGXjgJHor5rmi5vmioDmnK/n +sr7oi7HvvIzlj7LkuIrkurrmlbDmnIDlpJrogYzkvY3mnIDlub8h44CQ54Ot6IGY44CR5pCc54uQ +55WF5ri45YWo5Zu954Ot5oub5byA5Y+R5bel56iL5biI54m55Yir5o6o6I2QDQogIOaKpeWQjUlC +TeW8gOWPkeiAheWkp+S8mui1ouWkmumHjeWkp+Wllg0KICDjgJDmnInlpZbjgJHlj4LkuI7lpKnn +v7zosIPmn6Ug6LWi56We56eY56S8DQogIOWPguWKoOWIm+aWsOadr+i1ouaAu+minTIw5LiH576O +6YeRDQogIOOAkOacieWlluiwg+afpeOAkeS8geS4muWuieWFqOetiee6p+ivhOa1iw0KICDlj4Lk +uI5JRTnlpKfotZvlvpflpZbph5HotaLpvKDmoIcNCiAg44CQ56iL5bqP5o6o6I2Q44CR572R56uZ +5YaF5a65566h55CG57O757ufDQogIE1lZUdv5Lit5Zu95Yy65byA5Y+R6ICF56CU6K6o5LyaDQog +IE5va2lh5Li65LuA5LmI5LiN55SoQW5kcm8NCiAg6bih6IKL77yf6L+Y5piv5r2u5rWB77yfDQog +IOelnuWlh+eahFdlYlFRDQogIE1lZUdv5piv5LqS6IGU6K6h566X5Yib5paw5Yip5ZmoDQogIOW3 +peWFt+aOqOiNkO+8muW7tumVv+eUteaxoOe7reiIquaXtumXtA0KICDoi7HnibnlsJTlt6Xlhbfm +jqjojZDvvJror4TkvLDlpJrmoLjns7vnu5/mgKfotYTorq8gMTM2MuS6uueUs+ivt+WKoOWFpSLp +u5HpqaznqIvluo/lkZgi5b6F5a6hICDlvKDlrZ3npaVqYXZh5bCx5Lia5pS755Wl5pu05aSaR2Fy +dG5lcumihOiuoeS7iuW5tOWFqOeQg+S8geS4mlNhYVPmlLblhaXlop7plb8xNS43JeWkmuagt+WM +luW6lOeUqOW4puadpeeuoeeQhuaMkeaImA0KICDnlLLpqqjmloflia/mgLvosIjono3lkIjlupTn +lKjova/ku7bkuInlpKfmiJjnlaXln7rnoYAg5omA5pyJ5Lqn5ZOB6Z2i5ZCR5LqR6K6h566X5byA +5Y+RDQogIOWVhuS4muWRqOWIiu+8mkNocm9tZSBPU+WumuS9jeaooeeziuWJjeaZr+m7r+a3oee8 +uuS5j+ekvuS6pOWSjOWunuaXtuW6lOeUqA0KICDpm4XomY5DRU/lt7TojKjmlL7lvIPov5vlhaXp +mL/ph4zlt7Tlt7TokaPkuovkvJrpm4XomY7pm4flkZjnp7Dlt7Looqvop6Ppm4cNCiAg6LC35q2M +6aaW5bit5bel56iL5biI77ya5Z2a5oyB566X5rOV5Y6f5YiZIOS4jeaOuuS4u+inguiJsuW9qeS4 +jeWBj+iikuS7u+S9leWTgeeJjA0KICDnibnnq4vni6zooYznmoTnqIvluo/lkZjvvJrnu7Tln7ro +p6Plr4bliJvlp4vkurrpmL/moZHlpYfkvKDlpYfnu4/ljoblnY7lnbfmgJ3mg7Pmt7HliLsNCiAg +5Lia55WM5LiO5Lq654mpRmFjZWJvb2vmjqhGbWFpbOaMkeaImEVtYWlsIDYyJeWPl+iuv+iAheS4 +jeiAg+iZkeekvuS6pOe9kee7nOWPmOi6q+mAmuiur+W5s+WPsA0KICDlvq7ova/lrpjmlrnlrqPn +p7DlsIbkuo4yMDEx5bm05LiL5Y2K5bm05Zyo5Lit5Zu95o6o5Ye6V2luZG93cyBQaG9uZSA3DQog +IOivuuWfuuS6muaYjuW5tOaLn+WvueWhnuePreezu+e7n+i/m+ihjDTliLA15qyh5Y2H57qn5aKe +5Yqg5Li76aG16YWN572u54G15rS75oCnDQogIFtTRDIuMF3liJvmlrDlt6XlnLrolKHlrabplZvv +vJrpoobln5/or63oqIDnmoTorr7orqHkuI7lrp7ot7XlvILmraXnvJbnqIvmqKHlnovnmoTmvJTl +j5gNCiAgQ2hyb21lIE9T5a+56LC35q2M5pyq5p2l5aKe6ZW/6Iez5YWz6YeN6KaB55qEMTDkuKrn +kIbnlLHln7rkuo5XZWLmk43kvZzns7vnu5/mmK/mnKrmnaUNCiAgW+aOqOiNkOmYheivu13miZPp +gKDnp7vliqjlvIDlj5Hlm6LpmJ/nmoTkupTkuKrluLjop4Hor6/ljLrmnaXoh6pHb29nbGXnp7vl +iqjlm6LpmJ/nmoTnu4/pqowNCiAg5oqA5pyv5LiO5Lqn5ZOB5Lit5Zu955S15L+h5aSp57+856m6 +6Ze05ZCI5L2c5LyZ5Ly05Lqk5rWB6K665Z2b77yI5Y6m6Zeo56uZ77yJ5Y+s5byA5b2T5Yqo5ryr +6YGH5LiK55S15L+hDQogIOaWsOa1quW+ruWNmuW8gOWPkeiAheWIm+aWsOWfuumHkeW8gOWni+aO +peWPl+eUs+ivt+WNleeslOaKlei1hDMwMOS4h1JNQuS7peS4iw0KICDnu7Tln7rop6Plr4bkuLvn +q5nngrlXaWtpTGVha3Mub3Jn5Zyo576O5Zu95oGi5aSN6K6/6Zeu5YWo55CD5bu656uL6LaFMTAw +MOmVnOWDjw0KICDosLfmrYzkuLpBcGFjaGXmiYDmnInlvIDmupDpobnnm67mj5DkvpvmlrDnmoTl +sZXnpLrpobXpnaLkuI3lho3nlLFBcGFjaGXnu4Tnu4fnm7TmjqXnrqHnkIYNCiAg5Y2D5ZCN566h +55CG6ICFU0QyQyAyMDEw57q16K665oqA5pyv5aSn5Yq/IOS4reWbveW8gOWPkeiAhei/juadpem7 +hOmHkeWNgeW5tA0KICBJQk3kuLrlvrflm73lvIDlj5Hmr4/np5Lov5DnrpczMDAw5LiH5Lq/5qyh +6LaF57qn6K6h566X5py66LaF6LaK5Lit5Zu95aSp5rKzMeWPtw0KICDotYTorq/liqjmgIFhLi4g +5bCx5LiaIuS4jeWBmuW8gOWPkeS4jei/mOasviLnmoTln7norq1hLi4g44CQ5Luj56CB44CRV2lu +ZG93cyBQaG9uZSA36IyD5L6L56iL5bqPYS4uIOWkqee/vOaVmeS9oOenu+WKqOW6lOeUqOiQpeWI +qeS5i+mBk2EuLiDorr/osIgg5b6u6L2v6ZKf5Y2r6LCISUU55Y+Y6Z2p5LiT6aKY5pu05aSaYS4u +IA0KICBUZWNo4oCiRWQgMjAxMGEuLiANCiAgSGFkb29w5oqA5pyv5LiT6aKYYS4uIA0KICDmjqLo +rqjova/ku7booYzkuLrop4TojINhLi4gDQogIEFkb2JlIE1BWCAyMDEwQ1NETuenu+WKqOW+ruWN +miAgIOaIkeimgeWFs+azqCA+PuabtOWkmueyvuW9qeWGheWuue+8jOWwveWcqOenu+WKqOmikemB +kw0KICDliJjoiKrvvJrkurrmsJHmkJzntKLlrp7pmYXnoJTnqbbnmoTmmK/kurrmsJHooqvmkJzn +tKIuIC8vQOasp+iTrEFU56e75Yqo5LqS6IGU572ROuS8oOe7n+aQnOe0ouW8leaTju+8iOavlOWm +guiwt+atjO+8ieeglOeptuaAjuS5iOiuqeWkp+WutuaQnOWHuuS/oeaBr++8jOWug+eglOeptuaA +juS5iOiuqeWkp+WutuaQnOS4jeWHuuS/oeaBr+OAgi7mnI3kuobmpbzkuLvjgIIgLy9Ad2FzYTrm +nIDlkI7kuIDlj6Xkuq7kuobjgILjgIINCiAgOSBob3VycyBhZ28NCg0KICDnjovoiKpoZGbvvJpD +Tk5JQ+eahOS7o+eQhui/meW4ruWtmeWtkOS5n+S4jeWKqOWKqOiEkeWtkO+8jOavj+malOS4gOau +teaXtumXtOmDveiDveaOpeWIsOWQjOagt+eahOeUteivne+8jOivtOazleWujOWFqOS4gOiHtO+8 +jOmDveaYr+ivtOWIq+S6uuimgeaKouazqOS9oOeahOS6kuiBlOe9keWTgeeJjOKAlOKAlOmAmueU +qOe9keWdgO+8jOaIluiAheaYr+aKouazqOS9oOeahOenu+WKqOS6kuiBlOe9keWTgeeJjOKAlOKA +lOaXoOe6v+e9keWdgO+8jOS9oOS4q+i/nuiKseagt+mDveaHkuW+l+aNou+8jOWHoOW5tOWmguS4 +gOaXpeeahOi/meagt+ihjOmql+OAguaIkeWunuWcqOW/jeaXoOWPr+W/je+8jOS9oOS7rOi/meW4 +ruWtmeWtkO+8jOadpeeCueS4k+S4mueyvuelnuWlveS4jeWlve+8nw0KICA5IGhvdXJzIGFnbw0K +DQogIOeXnuWtkDQyMDbvvJrjgIrkupLogZTnvZEv56e75Yqo5LqS6IGU572R5bCP5Zui6Zif5Yib +5LiaIOesrOS6jOmbhiDmsarljY7jgIsgaHR0cDovL3NpbmF1cmwuY24vaDR3M3pmDQogIDkgaG91 +cnMgYWdvDQoNCiAg5p2O5ZCN5aSr77yaLy9A5qyn6JOsQVTnp7vliqjkupLogZTnvZE6MTDlubTk +uoblkKfvvJ/pgqPkuInkur/pg6jkuZ/lpJ/niZvpgLznmoTkuobjgILkuI3nn6XpgZPmnInlpJrl +sJHpg6jmmK/lhoXplIDnmoTjgIINCiAgOSBob3VycyBhZ28NCg0KICDotbXmtIticnVjZe+8muad +gOavkui9r+S7tuaDr+eUqOS8juS/qe+8jOiEseS6humprOeUsuS7lui/mOaYr+S5jOm+n+OAgiAv +L0Dolpvom67lrZA65q2k6aOO5LiN5Y+v6ZW/77yM5ZOq5pyJ5Yy755Sf5YWI5pKS55eF5q+S5YaN +5rK755eF55qE44CC5bqU6K+l56uL5rOV5Lil56aB77yBIC8vQOasp+iTrEFU56e75Yqo5LqS6IGU +572ROiDpgKDnl4Xmr5Lml6nlsLHmmK/nlLXohJHooYzkuJrmg6/kvovjgILmiYvmnLrooYzkuJrk +uZ/kuI3kvovlpJblkKfjgIIgLy9A6LW15bKXOui9rOWPkeW+ruWNmg0KICA5IGhvdXJzIGFnbw0K +5pu05aSa56e75Yqo6LWE6K6vIOivt+i/m+WFpT4+5pu05aSa44CK56iL5bqP5ZGY44CL5YGa5pyJ +5biC5Zy65oCd57u055qE5byA5Y+R5Lq65ZGYDQogIFdhdHRzIFMuIEh1bXBocmV577ya6L2v5Lu2 +6LSo6YeP5LmL54i2DQogIOWuieWFqOato+WboOS6keiAjOaUueWPmA0KICDokovmtpvvvJrmoqbm +g7PnmoTljYHlubTmm7TlpJrng63ngrnotYTorq/mjpLooYznibnnq4vni6zooYznmoTnqIvluo/l +kZjvvJrnu7Tln7rop6Plr4bliJvlp4vkurrpmL/moZHlpYfkvKDlpYdHbWFpbOS5i+eItu+8mkNo +cm9tZSBPU+adpeaXpeaXoOWkmkxCU+WwhuaIkOS6kuiBlOe9keS4i+S4gOWcuuihgOiFpeaImCAy +5bm05ZCO5biC5Zy66LaF55m+5Lq/5aSW5aqS6K+E6YCJ6L+H5Y67MjXlubQxMOWkp+m7keWuouaU +u+WHu+S6i+S7tuW+rui9r+Wuo+W4g+WPiOS4gOmdnldpbmRvd3Pmk43kvZzns7vnu59WZXJ2ZUNo +cm9tZSBPU+eahOelnuenmOmtheWKm+iLueaenOW3peeoi+W4iOeUqOS5kOmrmOenr+acqOmHjeW7 +uuacgOWPpOiAgeiuoeeul+acuumYv+W4leWlh+WfuumHkeS8muassumAgOWHukphdmHlp5TlkZjk +vJog55Sy6aqo5paH5pyb5YW25LiJ5oCdMjAxMOW5tOa2iOi0ueeUteWtkOaKgOacrzIw5Liq5pyA +5aSn5aSx6LSl77yaQnV6euWxhemmluS6uuawkeaQnOe0ou+8muS4jeS4juWVhuS4muaQnOe0ouat +o+mdouernuS6iWEuLiBhLi4gfOabtOWkmuWtpuS5oOepuumXtA0KICAxMi0xNeiusuWggiBMaW51 +eOezu+e7nw0KICAxMi0xNeiusuWggiDlnIblkajnjofnmoTov5HkvLzorqENCiAgMTItMTborrLl +oIIgTGludXjns7vnu58NCiAgMTItMTforrLloIIg5aSn5a2m55Sf6IGM5Lia55Sf5ravDQogIOes +lOiusCAuTmV05LmL5byA5rqQ5ZKM5LiN5byA5rqQ55qEDQogIOeslOiusCDkuIDkupvlpKflhazl +j7jnmoTlv4PnkIbmtYvor5XpopgNCiAg6K++5aCCIOS4i+Wtpuacn+eahOW1jOWFpeW8j+mAieS/ +ruivvumAieWQpg0KICBKYXZh6K++5aCCIOaVsOaNruaMluaOmOS6p+WTgeWSjOW3peWFtw0KICAy +MDEw5bWM5YWl5byP6KGM5Lia5bm057uI55uY54K56K6y5bqnDQogIOS4rei9r+mbhuWboue7meS4 +juS4reagh+i9r+S7tuWFqOmdouaUr+aMgQ0KICDpmo/ml7bpmo/lnLDlraboi7Hor63vvJ/oi7Hl +rZrmiYvmnLrlupTnlKjmnaXluK7kvaAhDQogIElU6L6+5Lq677ya5pWZ5L2g546p6L2s5aW95Y6L +5Y6L57yp6L2v5Lu2DQogIOS6uuWkp+mHkeS7k+WKqeWKm+WNq+eUn+ihjOS4muS/oeaBr+WMlnzm +m7TlpJrpobnnm67nsr7pgIkNCiAg5py65Zmo6KeG6KeJLeminOiJsuWIhuexuw0KICBNVEsgRkxB +U0jmkq3mlL7lvJXmk47lvIDlj5ENCiAgUERG6Jma5ouf5omT5Y2w5py677yI6ZmQ5YyX5Lqs77yJ +DQogIOW9qeelqOe9keermeeoi+W6j+WFqOWllw0KICBTVE0zMkYxMDPova/ku7blvIDlj5ENCiAg +YW5kcm9pZOWuouaIt+err+W8gOWPkQ0KICDpn7Pop4bpopHlub/mkq3mjqfku7YNCiAgSU3ova/k +u7bpobnnm67lpJbljIXlvIDlj5F85pu05aSa6LWE5rqQ57K+6YCJDQogIEPor63oqIDmlbDmja7n +u5PmnoTln7rmnKzmk43kvZwNCiAgcnVieTEzMTTkuIrkvKDmiJHopoHkuIrkvKANCiAg5a2m55Sf +5L2c5Lia566h55CG57O757ufIEpTUA0KICBmZW5neWFsaW5nZmx5eXnkuIrkvKDmiJHopoHkuIrk +vKANCiAgYysr57yW56iL5bi46YGH6Zeu6aKY5oC757uTDQogIGJ5cmdsNeS4iuS8oOaIkeimgeS4 +iuS8oA0KICBDIyDlr7zlh7pleGNlbCDlrp7kvovku6PnoIENCiAgb3VfeWFuZ3BlbmdmZWnkuIrk +vKDmiJHopoHkuIrkvKANCiAgdmLoh6rliqjmjpLniYjnlJ/miJBXb3JkDQogIHRpMTI25LiK5Lyg +5oiR6KaB5LiK5Lyg5Y2a5a6i57K+6YCJIOOAkOaOqOiNkOOAkeWkqee/vOaVmeS9oOenu+WKqOW6 +lOeUqOiQpeWIqeS5i+mBk+abtOWkmnNvc29fYmxvZ+WIq+iuqeWmiOWmiOeUn+awlOKAlOKAlOa1 +heiwiOmVv+iAheeUqOaItw0KICDogIHpgpPkubHor4RHVUnlvIDlj5HmoYbmnrbmnKrmnaXotbDl +kJENCiAg5bi46auY5Lyf5YGaSVTmg7PkuI3liqDnj63nnJ/nmoTlvojpmr4NCiAg5ZC05rCR5LyB +5Lia5paH5YyW5LiO4oCc6YWx5rK55YWa4oCdDQogIOS4geS6rk5ldEJlYW5zIOaXtuS6i+mAmuiu +r++8iOWIiuWPtyAjIDEyOSAtIERlYyAxNCwgMjAxMO+8iQ0KICDpvZDnkKhPcmFjbGUgT3BlbiBX +b3JsZOOAgUphdmFPbmXjgIFPcmFjbGUgRGV2ZWxvcGVyIOesrOS6jOaXpQ0KICDlvKDlm73lqIFB +bmRyb2lk5o+Q6auY56ys5Y2B5LqU56+H5LmLTGlzdFZpZXfoh6rpgILlupTlrp7njrDooajmoLwN +CiAg5pyx6YeR54G/5Z+65LqO5a+56K+d5qGG55qE566A5Y2V5Y+M57yT5Yay57uY5Zu+5qGG5p62 +DQogIOeOi+eRvuWNjlN5bWJpYW5eM+eOr+Wig+WuieijheaJi+iusA0KICDotZbli4fmtannlKgg +UHl0aG9uIOeahCBEZXNjcmlwdG9yIOeJueaAp+ino+WGs+S4gOS4quWPmOaAgeeahOmXrumimA0K +ICBqYW1lc+OAiuWkp+mBk+iHs+eugOOAi+ivu+S5pueslOiusA0KICDlvKDkuq5BbmRyb2lkIOW8 +gOWPkeWInee6p+WFpemXqO+8muazqOWGjOiwt+atjOWcsOWbviBBUEkg5a+G6ZKl5ZKM5pi+56S6 +6LC35q2M5Zyw5Zu+DQogIOaigeaWjOaYqOWkqeW+rui9r+S6mueglOmZouiHqueEtuivreiogOWk +hOeQhue7hOeahOWRqOaYjuWNmuWjq+e7meaIkeS7rOWBmuS6huaKpeWRig0KICDlkJXlu7rkvJ/k +uIDkuKrkvJjnp4DnmoTnoJTlj5Hlm6LpmJ/lupTor6XlhbflpIfku4DkuYjnibnlvoENCiAgYXp1 +cmVjaGluYeeOsOWunuS4lueVjOeahFdpbmRvd3MgQXp1cmU6IOS4jklNUEFDVEHmgLvoo4HvvIxL +ZXZpbiBMYW3nmoTorr/osIgNCiAg6YeR5pet5Lqu6Ieq5rWL5LiA5LiL5L2g55qESmF2YeaOjOaP +oeW+l+aAjuS5iOagt++8nw0KICDpuY/lh4zkuInljYMoY3BpbmfkuLrku4DkuYjmsqHmnInlpb3n +lKjnmoRBbmRyb2lk5ri45oiP5byV5pOO77yfDQogIOWykeaWh+WInUZhY2Vib29r5LyY5YyW5YiG +5Lqr5ZCO6K6wDQogIOiWm+esm+eUqEMrK+WGmUphdmEgU3R5bGXnqIvluo8NCiAg55uW5Zu95by6 +T3JhY2xl5pWw5o2u5bqT5oGi5aSNIDog5a2Y5YKo5pWF6Zqc5a+86Ie055qE5pWw5o2u5o2f5Z2P +DQogIOacsemHkeeBv0dESSvlrabkuaDkuYvnur/mgKfmuJDlj5jnlLvliLcNCiAg5ZGo54ix5rCR +57un5om/5LiO5re35ZCI77yM55Wl6LCI57O757uf55qE5p6E5bu65pa55byPDQogIOW8oOWuh+aP +kuS7tuW8j+aetuaehOiuvuiuoeWunui3teS6jO+8muWfuuS6jlNpbHZlcmxpZ2h055qEQi9T5o+S +5Lu25byP5p625p6E6K6+6K6h5pa55rOVDQogIOacsemHkeeBv+S6jOe7tOWbvuW9oue8lui+keS4 +reeCuemAieWPluetlueVpeeglOeptg0KICDpu4TpuY/nqItMaW51eOeOr+Wig+S4i+eahEMvQyvl +n7rnoYDosIPor5XmioDmnK8y4oCU4oCU56iL5bqP5o6n5Yi2DQogIOeZveaFp+WGrFvlhajnqIvl +u7rmqKFd57G75Zu+5ZKM5pe25bqP5Zu+55qE5byA5Y+R5YWz57O777yM5LuO55So5L6L6LCI6LW3 +55qE5YWo56iL5bu65qihDQogIGEuLiDlubTolqoxNS0yMOS4h+aApeaLm2phdmHorrLluIjvvIFh +Li4g5aSp57+85pWZ5L2g56e75Yqo5bqU55So6JCl5Yip5LmL6YGTYS4uIOW/q+aNt+i9rOWei0Fu +ZHJvaWTpq5jolqrkurrmiY1hLi4g5Y+y5LiK5pyA57uZ5Yqb55qE5YWN6LS5UEhQ6KeG6aKR5pWZ +56iL5pu05aSa5Y2a5a6i5LmL5pif5b6u6L2v5LqR6K6h566X5Lit5paH5Y2a5a6iDQogIOacrOS4 +reaWh+WNmuWuoueUseW+rui9r+S6keiuoeeul0F6dXJl6K665Z2b5pSv5oyB5bCP57uE5byA5Yqe +44CC5YaF5a655LulV2luZG93cyBBenVyZSBQbGF0Zm9ybeS4uuS4u+OAgg0KICDorr/pl67ku5bn +moTnqbrpl7TlnKhXaW5kb3dzIEF6dXJl5bmz5Y+w5LiK6YOo572y5pyN5YqhDQogIFdpbmRvd3Mg +QXp1cmUgQ2xvdWRQb2xsIGZvcg0KICBUYWJsZSBTdG9yYWdl5a+55YiG6aG155qE5pSv5oyBDQog +IOWmguS9lemAieaLqeiZmuaLn+acuuinhOagvA0KICDlvIDlj5Hmi5PlsZXmkJzntKIt5pWR5o+0 +5bqU55So56iL5bqPDQogIOeOsOWunuS4lueVjOeahFdpbmRvd3MgQXp1cmXmm7TlpJpDVE/kv7Hk +uZDpg6jmrKLov47lpKflrrbliqDlhaVDVE/kv7HkuZDpg6gs6L+Z5piv6Z2i5ZCR6auY56uv5oqA +5pyv566h55CG6ICF55qE56S+5Yy644CCW+aIkeimgeWKoOWFpV0NCiAgWzHkurrlm57lpI1d5YWz +5LqO6ICB5aSW5a6e55So55qE5Y6L57yp6L2v5Lu26Zeu6aKYDQogIFsxNOS6uuWbnuWkjV3lvbzl +vpflvrfpsoHlhYvjgIrnrqHnkIbnmoTlrp7ot7XjgIvmnK0NCiAgWzEx5Lq65Zue5aSNXei/kOiQ +peexu+mhueebruS9nOS4uuWIm+S4muaAp+mhueebruavlA0KICBbM+S6uuWbnuWkjV3lnKjnu4bl +iIbluILlnLrkuK3lr7vmib7liJvkuJrmnLrkvJoNCiAgWzLkurrlm57lpI1d5a+75rGC6L2v5Lu2 +5LiA5qy+fg0KICBbODLkurrlm57lpI1dMTHmnIgyNeaXpeaJi+acuuWuouaIt+err+S4k+WnlA0K +ICBbMOS6uuWbnuWkjV3kuK3ltYzljY/kvJrnrKzlm5vmnJ/igJzltYzlhaXlvI/kuI7niakNCiAg +WzTkurrlm57lpI1d4oCc5LqR6K6h566X4oCd5bqU5LiN5bqU6K+l5piO56Gu6KeE6IyD5pu05aSa +54Ot5paH5o6S6KGM6Z2i5ZCR56iL5bqP5ZGY55qE5pWw5o2u5bqT6K6/6Zeu5oCn6IO95LyY5YyW +5rOV5YiZ6aG257qn56iL5bqP5ZGY55qE5b+D5b6XIC0gQ29kZXJzIGF0IFdvcmtMaW51eOeOr+Wi +g+S4i+eahEMvQysr5Z+656GA6LCD6K+V5oqA5pyvMeKAlOKAlOWIneatpeS6huinozIwMTDlubTv +vIxMaW51eOWkp+S6i+iusOW+geWPi+WQr+S6i+ato+aWh2xvYWRydW5uZXLkuK0gdGhpbmt0aW1l +IOWmguS9lei/kOeUqOmaj+acuuaXtumXtO+8jOW5tuimgeaKiuaXtumXtOWumuWcqOavq+enkue6 +p2xpbnV4IOS4i+WPlui/m+eoi+WNoOeUqCBjcHUv5YaF5a2YIOacgOmrmOeahOWJjTEw5Liq6L+b +56iLamF2YeefpeivhueCueWmguS9leS4suaOpeaipuaDs+WNgeW5tC0t44CK56iL5bqP5ZGY44CL +5Y2B5bm05oSf5oOz5oiR5Lus5Li65LuA5LmI5LiN5Zac5qyi5oub6IGY5Z+56K6t5a2m5qCh55qE +5a2m55Sf77yfYS4uIGEuLiB85pu05aSa5Zu+5Lmm5o6S6KGM5qacDQogIGEuLiBIYWRvb3DmnYPl +qIHmjIfljZfvvIjkuK3mlofniYjvvInnqIvluo/lkZgoMjAxMOW5tDEy5pyI5YiKIOaAu+esrDLk +upLogZTnvZHov5DokKXmmbrmhafigJTpq5jlj6/nlKjlj6/mianlsZXnvZHnq5nmioBNeVNRTOaK +gOacr+WGheW5lTpJbm5vRELlrZjlpoLkvZXnrqHnkIbova/ku7bkvIHkuJoo56ysMueJiCnnrpfm +s5Xlr7zorrrvvIjljp/kuabnrKwy54mI77yJKDA55bm05bqm55WF5rex5YWl55CG6Kej6K6h566X +5py657O757ufKOWOn+S5puesrDLniYgpKFNFT+WunuaImOWvhueggeKAlDYw5aSp572R56uZ5rWB +6YeP5o+Q6auYSFRNTCA155So5oi35oyH5Y2XKOWPjOiJsuWNsOWIt++8jOWtpkphdmHnvJbnqIvm +gJ3mg7Mo56ysNOeJiCko57uP5YW45Zu+6Jma5ouf6Jyc572Q77ya5LuO5YO15bC4572R57uc6L+9 +6Liq5Yiw5YWl5L61DQogIOmdouWvuei2iuadpei2iuWkjeadgueahOmAg+mBv+aKgOacr++8jOS7 +peWPiumHh+eUqOWKoOWvhuaKgOacr+adpeS/neaKpOe9kee7nOmAmuS/oe+8jOmYsuatouiiq+eq +g+WQrOeahOWNj+iurui2iuadpei2ii4uLmpCUE005bel5L2c5rWB5bqU55So5byA5Y+R5oyH5Y2X +DQogIOacrOS5puWwhuS9v+aCqOW/q+mAn+S6huino+S7gOS5iOaYr+W3peS9nOa1geOAgUJQTeWS +jGpCUE3vvIzku6Xlj4rlroPku6znmoTlj5HlsZXljobnqIvjgILlvZPnhLbvvIzph43opoEuLi5M +aW51eOmCo+S6m+S6i+WEvw0KICDmnKzkuabln7rkuo4yLjYuMjLlhoXmoLjvvIzlr7lVU0LlrZDn +s7vnu5/nmoTlpKfpg6jliIbmupDku6PnoIHpgJDooYzov5vooYzliIbmnpDvvIzns7vnu5/lnLDp +mJDph4rkuoYuLi7npL7ljLrmm7TlpJpDU0RO5oqA5pyv55ub5a60U0QyLjDlpKfkvJrlnIbmu6Hn +u5PmnZ8NCiAganY5U2lsdmVybGlnaHQvV1BGL1dQN+S4gOWRqOWtpuS5oOWvvOivuygxMuaciDYt +MTLmnIgxMikNCiAgZ3VndWRhMjAwOOaKilRFTVBEQuaUvuWIsOWGheWtmOmHjA0KICBpbnZhbGlk +YXRlMDAxMeWPpuexu+ijhemlsOS9oOeahFdpbmZvcm0gLSDlnKjnqpflj6PnmoTlt6bkuIrop5Ll +iqDkuIDkuKrlnKPor57luL0NCiAgemN0eW1qeFdpbkNFIDYuMCDpqbHliqjlvIDlj5HjgIHlhoXm +oLjlrprliLbmlrnpnaLnmoTkuabkuLvopoHmnInpgqPkupvvvJ8NCiAgcGlnZzE4d2luZG93cyB4 +cCDlkozomZrmi5/mnLrnmoTlm7Dmg5EgeWVhaA0KICBPbmVPbmNl5L+u5pS5aS5NWDUxNSBFQk9P +VOWkp+Wwjw0KICBseXNlcnZlcuiuqeS6uue6oOe7k+eahOS4ieWxguaetuaehA0KICBxaXhpbmdo +YWl0YW5nMTIz5b+F6K+777ya5aaC5L2V5oiQ5Li65LiA5ZCN5LyY56eA55qEQW5kcm9pZOW8gOWP +keiAhQ0KICDnpL7ljLrnsr7ljY435Lq65pS26JePMTDnp43noLTpmaTnvZHpobXorr7orqHluIjp +mpznoo3nmoTlrp7nlKjmlrnms5UNCiAgNuS6uuaUtuiXj2xpbnV457yW56iL55qEMTA456eN5aWH +5rer5ben6K6hLTEyKOWtmOWCqOiuoeeulynnu60NCiAgNOS6uuaUtuiXj+S4uuS7gOS5iOivtOS6 +keiuoeeul+aYr+enu+WKqOeahOacquadpQ0KICAy5Lq65pS26JePMjAxMOW5tOa2iOi0ueeUteWt +kOaKgOacrzIw5Liq5pyA5aSn5aSx6LSl77yaQnV6euWxhemmlg0KICA15Lq65pS26JeP55SoQyDl +hplKYXZhIFN0eWxl56iL5bqPDQogIDjkurrmlLbol4/oh6rmtYvkuIDkuIvkvaDnmoRKYXZh5o6M +5o+h5b6X5oCO5LmI5qC377yfDQogIDTkurrmlLbol4/ljY7kuLrpnaLor5Xpopjnrpfku4DkuYgs +6L+Z5Liq6IOM5Lya5LqG5aSW5LyB6ZqP5L6/6L+bDQogIDPkurrmlLbol4/nqIvluo/lkZjvvJrn +vJbnqIvnu5nkvaDnjrDlrp7nlJ/mtLvluKbmnaXkuoblk6rkupvlnY/kuaDmg68NCiAgNeS6uuaU +tuiXj+e7p+aJv+S4jua3t+WQiO+8jOeVpeiwiOezu+e7n+eahOaehOW7uuaWueW8jw0KICDmnIDm +lrDnvZHmkZjjgJDlhazlkYrjgJFDU0RO6auY5qCh5L+x5LmQ6YOo5Li75bit54Gr54Ot5oub5Yuf +5LitDQogIOOAkOWkqea0peOAkeWkqea0peiBjOS4muWkp+WtpkNTRE7pq5jmoKHkv7HkuZDpg6jm +raPlvI/miJDnq4sNCiAg44CQ6am76ams5bqX44CR6buE5reu5a2m6Zmi56ys5LiA5pyf5Zyo57q/ +6K6y5aCC5oiQ5Yqf5Li+5YqeDQogIOOAkOS/neWumuOAkeays+i9r0NTRE7pq5jmoKHkv7HkuZDp +g6jmraPlvI/miJDnq4sNCiAg44CQ5L+d5a6a44CRQ1NETumrmOagoeS/seS5kOmDqOiQveaIt+ay +s+WMl+mHkeiejeWtpumZog0KICDpq5jmoKFjbHVi5pu05aSa56S+5Yy65LmL5pif6JKL5pmf77ya +56S+5Yy65LiT5a62DQogIENTRE7lpKfniYjkuLss5b6u6L2v5pyA5pyJ5Lu35YC85LiT5a6277yM +5pOF6ZW/Lk5FVOOAgUFjdGl2ZVjjgIFBcHBsaWNhdGlvbg0KICDorr/pl67ku5bnmoTnqbrpl7Tm +m7TlpJrnpL7ljLrmlrDor53popjlt6XkvZzkuK3nmoTlsI/mj5Lmm7LvvIzop4Hor4ZDU0RO6L6+ +5Lq6DQogIOWPkeWpmueFp++8jOaxguelneemj35+fu+8gQ0KICDvvIjovazvvInlm6DkuLrmiJHm +mK/kvaDlqrPlpoflhL8NCiAg5a+55Zac5qyi55qE5Lq65pS+5byD6L+Y5piv57un57ut77yf5oiR +5b6I55+b55u+DQogIOWwj+aXtuWAmeiiq+e9mu+8jOW5sui/h+i/meenjeS6i+aDheeahOerpeme +i+ivt+S4vuaJiw0KICDjgJDljJfkuqzjgJHlm5vlubTlt6XkvZznu4/pqoznnJ/nmoTog73mi784 +S+S5iO+8nw0KICDlsI/lvJ/mmI7lpKnkuIvljYjljrvohb7orq/pnaLor5UNCiAg5o6o6I2Q5Yeg +6YOo5Y2w5bqm55qE55S15b2xfn4NCiAg6ICB5p2/eXXlkZjlt6XnmoTlr7nor53vvIjmkJ7ogIzn +nJ/vvIkNCiAg5bu66K6uY3NkbuW8gOS4gOS4queUt+aAp+WBpeW6t+adv+Wdl+abtOWkmueoi+W6 +j+S6uueUn1NE6L2v5Lu25aSn5Lya5ZyG5ruh57uT5p2fIOWqkuS9k+aKpemBk+WPiuebuOWFs+WB +tuWSjOWBtueahOWQjOWtpuW8oOS6jOeLl++8iOi+g+WujOaVtOeJiO+8iemAg+emu+S4gOe6v+Wf +juW4guWkp+Wutui/mOS8muS7juS6i+WOn+adpeaWueWQkeWQl++8n+aBouWkjUlF5Li66buY6K6k +5LiL6L295bel5YW35LuK5pel6LWb5LqL5o6o5LuL77ya5pu86IGUIFZTIOmYv+ajrue6s+WmguS9 +leaIkOS4uuS4gOWQjeS8mOengOeahEFuZHJvaWTlvIDlj5HogIVbI3c2VEN1c0tSdzZmQ3ZNS1d3 +NmZDb01LQiNd5LqR57yW56CBU0QyLjDlpKfkvJrpmobph43lvIDluZUs56S+5Yy6546w5Zy65Zu+ +5paH55u05pKt5aSn5a626L2s5q2j55qE5bel6LWE5pyJ5rKh5pyJ5a6e5Lmg55qE5pe25YCZ5aSa +77yf5YWl6KGM5LiA5bm05aSa5LuO5rKh5oSf5Y+X5Yiw6L2v5Lu25byA5Y+R5Zac5oKm5ZCI5L2c +5LyZ5Ly05paw5rWq56eR5oqA4oCUIOaQnOeLkElU4oCUIERvTmV3c+KAlCBaRE5ldOiHs+mhtue9 +keKAlCDnrKzkuInlqpLkvZPigJQg5aSp5p6B572R4oCUIOiuoeS4lue9keKAlCDmiYvmnLrkuYvl +rrbigJQgNTHop4bpk4PigJQg546p572R5L2T6IKyIOKAlOaIkeimgeWcsOWbviDigJRKb2huIEJy +eWNlDQoNCum+meaLk+S6kuWKqOKAlCDkuIfoirHnrZLml4XmuLjigJQg6K+65Z+65Lqa6K665Z2b +4oCUIOeUteWtkOW3peeoi+KAlCDlvIDmupDkuJPlrrbnvZHigJQg6KeG6KeJ5Lit5Zu94oCUIOWP +pemFt+S+i+WPpeKAlCDkupLliqjnmb7np5HigJQgRE9JVOKAlCBEYXRhc2hlZXTigJQg6LGG5LiB +572R4oCUIOWlveWkp+Wkq+WcqOe6vw0KICDlhazlj7jnroDku4t85oub6LSk57qz5aOrfOW5v+WR +iuacjeWKoXzpk7booYzmsYfmrL7luJDlj7d86IGU57O75pa55byPfOeJiOadg+WjsOaYjnzms5Xl +vovpob7pl6586Zeu6aKY5oql5ZGKDQogICAgICANCiAg5a6i5oi35pyN5Yqh54Ot57q/77yaMDEw +LTUxNjYxMjAy44CA6L+d5rOV5L+h5oGv5Li+5oql55S16K+d77yaMTM1NTIwMDk2ODkg5Li+5oql +6YKu566x77yad2VibWFzdGVyQGNzZG4ubmV0DQogIOWMl+S6rOW4guWFrOWuieWxgOacnemYs+WI +huWxgOe9keebkeS4reW/g+Wkh+ahiOe8luWPt++8mjExMDEwNTA5Njkg5LqsSUNQ6K+BMDcwNTk4 +5Y+3DQogIOeUteS/oeS4muWKoeWuoeaJuVsyMDA3XeWtl+esrDM4MOWPtyDnlLXkv6HkuI7kv6Hm +ga/mnI3liqHkuJrliqHnu4/okKXorrjlj6/or4EwNzA1OTjlj7cNCiAg5YyX5Lqs5Yib5paw5LmQ +55+l5bm/5ZGK5pyJ6ZmQ5YWs5Y+4IOeJiOadg+aJgOaciQ0KICDkuJbnuqrkuZDnn6Uo5YyX5Lqs +Kee9kee7nOaKgOacr+aciemZkOWFrOWPuCDmj5DkvpvmioDmnK/mlK/mjIENCiAg5rGf6IuP5LmQ +55+l572R57uc5oqA5pyv5pyJ6ZmQ5YWs5Y+4IOaPkOS+m+WVhuWKoeaUr+aMgQ0KICBDb3B5cmln +aHQgwqkgMTk5OS0yMDEwLCBDU0ROLk5FVCwgQWxsIFJpZ2h0cyBSZXNlcnZlZCA= + +------=_NextPart_001_0004_01CB9D0D.783DE8D0 +Content-Type: text/html; + charset="utf-8" +Content-Transfer-Encoding: base64 + +77u/PCFET0NUWVBFIEhUTUwgUFVCTElDICItLy9XM0MvL0RURCBIVE1MIDQuMCBUcmFuc2l0aW9u +YWwvL0VOIj4NCjxIVE1MPjxIRUFEPg0KPE1FVEEgaHR0cC1lcXVpdj1Db250ZW50LVR5cGUgY29u +dGVudD0idGV4dC9odG1sOyBjaGFyc2V0PXV0Zi04Ij4NCjxNRVRBIGNvbnRlbnQ9Ik1TSFRNTCA2 +LjAwLjYwMDAuMTcwODAiIG5hbWU9R0VORVJBVE9SPg0KPFNUWUxFPjwvU1RZTEU+DQo8L0hFQUQ+ +DQo8Qk9EWSBiZ0NvbG9yPSNjMGMwYzA+DQo8RElWPjxGT05UIHNpemU9Mj48U1BBTiBjbGFzcz1B +cHBsZS1zdHlsZS1zcGFuIA0Kc3R5bGU9IldPUkQtU1BBQ0lORzogMHB4OyBGT05UOiBtZWRpdW0g +U2ltc3VuOyBURVhULVRSQU5TRk9STTogbm9uZTsgQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtSU5E +RU5UOiAwcHg7IFdISVRFLVNQQUNFOiBub3JtYWw7IExFVFRFUi1TUEFDSU5HOiBub3JtYWw7IEJP +UkRFUi1DT0xMQVBTRTogc2VwYXJhdGU7IG9ycGhhbnM6IDI7IHdpZG93czogMjsgLXdlYmtpdC1i +b3JkZXItaG9yaXpvbnRhbC1zcGFjaW5nOiAwcHg7IC13ZWJraXQtYm9yZGVyLXZlcnRpY2FsLXNw +YWNpbmc6IDBweDsgLXdlYmtpdC10ZXh0LWRlY29yYXRpb25zLWluLWVmZmVjdDogbm9uZTsgLXdl +YmtpdC10ZXh0LXNpemUtYWRqdXN0OiBhdXRvOyAtd2Via2l0LXRleHQtc3Ryb2tlLXdpZHRoOiAw +cHgiPjxTUEFOIA0KY2xhc3M9QXBwbGUtc3R5bGUtc3BhbiANCnN0eWxlPSJGT05ULVNJWkU6IDEy +cHg7IExJTkUtSEVJR0hUOiAxOHB4OyBGT05ULUZBTUlMWTogc2ltc3VuOyBURVhULUFMSUdOOiBj +ZW50ZXIiPg0KPERJViBjbGFzcz1tYWlud3JhcCANCnN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7 +IFBBRERJTkctTEVGVDogMHB4OyBQQURESU5HLUJPVFRPTTogNXB4OyBNQVJHSU46IDBweCBhdXRv +OyBXSURUSDogOTYwcHg7IFBBRERJTkctVE9QOiAwcHgiPg0KPERJViBjbGFzcz13cmFwcGVyIHN0 +eWxlPSJGTE9BVDogbGVmdDsgV0lEVEg6IDk2MHB4Ij4NCjxESVYgY2xhc3M9YmFubmVyX3RvcDEg +c3R5bGU9IkZMT0FUOiBsZWZ0OyBNQVJHSU46IDJweCAwcHg7IFdJRFRIOiA5NjBweCI+DQo8VUwg +DQpzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBQQURESU5HLUxFRlQ6IDBweDsgRkxPQVQ6IGxl +ZnQ7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBXSURUSDogOTYwcHg7IFBBRERJ +TkctVE9QOiAwcHg7IExJU1QtU1RZTEUtVFlQRTogbm9uZSI+DQogIDxMSSBjbGFzcz1sZWZ0YWQg +DQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IFBBRERJTkctTEVGVDogMHB4OyBGTE9BVDog +bGVmdDsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IFdJRFRIOiA3MzZweDsgUEFE +RElORy1UT1A6IDBweDsgSEVJR0hUOiA2MHB4Ij48QSANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCww +LDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBocmVmPSJodHRwOi8vei5jc2RuLm5ldC9n +bWNsaWNrLnBocD9iYW5uZXJpZD01NDMyJmFtcDt6b25laWQ9NDAyJmFtcDtzb3VyY2U9JmFtcDtk +ZXN0PWh0dHAlM0ElMkYlMkZiYW1ib29rLnByb2dyYW1tZXIuY29tLmNuJTJGIiANCiAgdGFyZ2V0 +PV9ibGFuaz48SU1HIHRpdGxlPSIiIA0KICBzdHlsZT0iQk9SREVSLVRPUC1XSURUSDogMHB4OyBC +T1JERVItTEVGVC1XSURUSDogMHB4OyBCT1JERVItQk9UVE9NLVdJRFRIOiAwcHg7IEJPUkRFUi1S +SUdIVC1XSURUSDogMHB4IiANCiAgaGVpZ2h0PTYwIGFsdD0iIiANCiAgc3JjPSJodHRwOi8vaW5m +by1kYXRhYmFzZS5jc2RuLm5ldC9VcGxvYWQvMjAxMC0xMi0xMC83MzVfNjBfemhlbmdkaW5nLmpw +ZyIgDQogIHdpZHRoPTczNSBib3JkZXI9MD48L0E+DQogIDxESVYgaWQ9YmVhY29uXzU0MzIgDQog +IHN0eWxlPSJMRUZUOiAwcHg7IFZJU0lCSUxJVFk6IGhpZGRlbjsgUE9TSVRJT046IGFic29sdXRl +OyBUT1A6IDBweCI+PElNRyANCiAgc3R5bGU9IkJPUkRFUi1UT1AtV0lEVEg6IDBweDsgQk9SREVS +LUxFRlQtV0lEVEg6IDBweDsgQk9SREVSLUJPVFRPTS1XSURUSDogMHB4OyBXSURUSDogMHB4OyBI +RUlHSFQ6IDBweDsgQk9SREVSLVJJR0hULVdJRFRIOiAwcHgiIA0KICBoZWlnaHQ9MCBhbHQ9IiIg +DQogIHNyYz0iaHR0cDovL3ouY3Nkbi5uZXQvZ21sb2cucGhwP2Jhbm5lcmlkPTU0MzImYW1wO2Ns +aWVudGlkPTE3MTImYW1wO3pmPSZhbXA7em9uZWlkPTQwMiZhbXA7c291cmNlPSZhbXA7YmxvY2s9 +MCZhbXA7Y2FwcGluZz0wJmFtcDtjYj03MmRjZWMwYTVkNGEzNjY1NjRmMmFjZDhmYjM1NzY2NiIg +DQogIHdpZHRoPTA+PC9ESVY+PC9MST4NCiAgPExJIGNsYXNzPXJpZ2h0YWQgDQogIHN0eWxlPSJQ +QURESU5HLVJJR0hUOiAwcHg7IFBBRERJTkctTEVGVDogMHB4OyBGTE9BVDogcmlnaHQ7IFBBRERJ +TkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBXSURUSDogMjEwcHg7IFBBRERJTkctVE9QOiAw +cHg7IEhFSUdIVDogNjBweCI+PEEgDQogIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1E +RUNPUkFUSU9OOiBub25lIiANCiAgaHJlZj0iaHR0cDovL3ouY3Nkbi5uZXQvZ21jbGljay5waHA/ +YmFubmVyaWQ9NTMyNiZhbXA7em9uZWlkPTQwMyZhbXA7c291cmNlPSZhbXA7ZGVzdD1odHRwJTNB +JTJGJTJGd3d3Lm1pY3Jvc29mdC5jb20lMkZ3ZWIlM0ZXVC5tY19pZCUzRGJhbi1uLWNuLXdhZy0t +Q1NETiIgDQogIHRhcmdldD1fYmxhbms+PElNRyB0aXRsZT0iIiANCiAgc3R5bGU9IkJPUkRFUi1U +T1AtV0lEVEg6IDBweDsgQk9SREVSLUxFRlQtV0lEVEg6IDBweDsgQk9SREVSLUJPVFRPTS1XSURU +SDogMHB4OyBCT1JERVItUklHSFQtV0lEVEg6IDBweCIgDQogIGhlaWdodD02MCBhbHQ9IiIgDQog +IHNyYz0iaHR0cDovL2luZm8tZGF0YWJhc2UuY3Nkbi5uZXQvVXBsb2FkLzIwMTAtMTEtMzAvd2Vi +XzIxMF82MF8xMTMwLmpwZyIgDQogIHdpZHRoPTIxMCBib3JkZXI9MD48L0E+DQogIDxESVYgaWQ9 +YmVhY29uXzUzMjYgDQogIHN0eWxlPSJMRUZUOiAwcHg7IFZJU0lCSUxJVFk6IGhpZGRlbjsgUE9T +SVRJT046IGFic29sdXRlOyBUT1A6IDBweCI+PElNRyANCiAgc3R5bGU9IkJPUkRFUi1UT1AtV0lE +VEg6IDBweDsgQk9SREVSLUxFRlQtV0lEVEg6IDBweDsgQk9SREVSLUJPVFRPTS1XSURUSDogMHB4 +OyBXSURUSDogMHB4OyBIRUlHSFQ6IDBweDsgQk9SREVSLVJJR0hULVdJRFRIOiAwcHgiIA0KICBo +ZWlnaHQ9MCBhbHQ9IiIgDQogIHNyYz0iaHR0cDovL3ouY3Nkbi5uZXQvZ21sb2cucGhwP2Jhbm5l +cmlkPTUzMjYmYW1wO2NsaWVudGlkPTE2NzcmYW1wO3pmPSZhbXA7em9uZWlkPTQwMyZhbXA7c291 +cmNlPSZhbXA7YmxvY2s9MCZhbXA7Y2FwcGluZz0wJmFtcDtjYj04OGMwM2Q5OGEzMTE2MTY5MGQ2 +ODI2ZTgzZTkyOTNhMCIgDQogIHdpZHRoPTA+PC9ESVY+PC9MST48L1VMPjwvRElWPg0KPERJViBj +bGFzcz0icGFnZXRvcF9ub3RpY2UgdHh0X2dyYXkiIA0Kc3R5bGU9IlBBRERJTkctUklHSFQ6IDVw +eDsgUEFERElORy1MRUZUOiA1cHg7IEZMT0FUOiBsZWZ0OyBQQURESU5HLUJPVFRPTTogMnB4OyBX +SURUSDogOTUwcHg7IENPTE9SOiByZ2IoMTAyLDEwMiwxMDIpOyBQQURESU5HLVRPUDogMnB4OyBC +QUNLR1JPVU5ELUNPTE9SOiByZ2IoMjQ1LDI0NSwyNDUpOyBURVhULUFMSUdOOiBsZWZ0OyBiYWNr +Z3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48Q0lURSAN +CmlkPWxvZ2luIHN0eWxlPSJGT05ULVNUWUxFOiBub3JtYWwiPjxBIA0Kc3R5bGU9IkNPTE9SOiBy +Z2IoMTAyLDEwMiwxMDIpOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KaHJlZj0iaHR0cDovL3Bh +c3Nwb3J0LmNzZG4ubmV0L0NTRE5Vc2VyUmVnaXN0ZXIuYXNweCIgdGFyZ2V0PV9ibGFuaz48SU1H +IA0KdGl0bGU95rOo5YaMIA0Kc3R5bGU9IkJPUkRFUi1UT1AtV0lEVEg6IDBweDsgQk9SREVSLUxF +RlQtV0lEVEg6IDBweDsgRkxPQVQ6IHJpZ2h0OyBCT1JERVItQk9UVE9NLVdJRFRIOiAwcHg7IE1B +UkdJTjogMHB4IDJweCAtM3B4OyBCT1JERVItUklHSFQtV0lEVEg6IDBweCIgDQphbHQ95rOo5YaM +IHNyYz0iaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMS5naWYiPjwv +QT48QSANCnN0eWxlPSJDT0xPUjogcmdiKDEwMiwxMDIsMTAyKTsgVEVYVC1ERUNPUkFUSU9OOiBu +b25lIiANCmhyZWY9Imh0dHA6Ly9wYXNzcG9ydC5jc2RuLm5ldC9Vc2VyTG9naW4uYXNweCIgdGFy +Z2V0PV9ibGFuaz48SU1HIHRpdGxlPeeZu+W9lSANCnN0eWxlPSJCT1JERVItVE9QLVdJRFRIOiAw +cHg7IEJPUkRFUi1MRUZULVdJRFRIOiAwcHg7IEZMT0FUOiByaWdodDsgQk9SREVSLUJPVFRPTS1X +SURUSDogMHB4OyBNQVJHSU46IDBweCAycHggLTNweDsgQk9SREVSLVJJR0hULVdJRFRIOiAwcHgi +IA0KYWx0PeeZu+W9lSBzcmM9Imh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4 +X3BpYzIuZ2lmIj48L0E+PC9DSVRFPuS7iuWkqeaYrzxFTSANCmlkPW5vd1RpbWUgc3R5bGU9IkZP +TlQtU1RZTEU6IG5vcm1hbCI+MjAxMOW5tDEy5pyIMTbml6U8L0VNPjxTUEFOIGlkPXNob3dpbmZv +IA0Kc3R5bGU9Ik1BUkdJTjogMHB4IDIwcHggMHB4IDQwcHgiPjwvU1BBTj48L0RJVj4NCjxESVYg +Y2xhc3M9Y3Nkbl9wdWJoZWFkZXIwOSANCnN0eWxlPSJCT1JERVItUklHSFQ6IHJnYigyMDQsMjA0 +LDIwNCkgMXB4IHNvbGlkOyBCT1JERVItVE9QOiByZ2IoMjA0LDIwNCwyMDQpIDFweCBzb2xpZDsg +RkxPQVQ6IGxlZnQ7IE1BUkdJTjogMnB4IDBweDsgQk9SREVSLUxFRlQ6IHJnYigyMDQsMjA0LDIw +NCkgMXB4IHNvbGlkOyBXSURUSDogOTU4cHg7IEJPUkRFUi1CT1RUT006IHJnYigyMDQsMjA0LDIw +NCkgMXB4IHNvbGlkOyBIRUlHSFQ6IDY4cHg7IFRFWFQtQUxJR046IGxlZnQiPg0KPERJViBjbGFz +cz1jc2RuX3B1YmhlYWRlcjA5X2xvZ28gc3R5bGU9IkZMT0FUOiBsZWZ0OyBXSURUSDogMTk0cHgi +PjxBIA0Kc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0K +aHJlZj0iaHR0cDovL3d3dy5jc2RuLm5ldC8iPjxJTUcgdGl0bGU9IkNTRE4gTG9nbyIgDQpzdHls +ZT0iQk9SREVSLVRPUC1XSURUSDogMHB4OyBCT1JERVItTEVGVC1XSURUSDogMHB4OyBCT1JERVIt +Qk9UVE9NLVdJRFRIOiAwcHg7IEJPUkRFUi1SSUdIVC1XSURUSDogMHB4IiANCmFsdD0iQ1NETiBM +b2dvIiANCnNyYz0iaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljbG9n +by5naWYiPjwvQT48L0RJVj4NCjxESVYgY2xhc3M9Y3Nkbl9wdWJoZWFkZXIwOV9uYXYgDQpzdHls +ZT0iRkxPQVQ6IHJpZ2h0OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24v +d3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljNC5naWYpOyBCT1JERVItTEVGVDogcmdiKDIwNCwyMDQs +MjA0KSAxcHggc29saWQ7IFdJRFRIOiA3NjNweDsgSEVJR0hUOiA2OHB4OyBiYWNrZ3JvdW5kLW9y +aWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj4NCjxVTCBjbGFzcz1yb3df +MSANCnN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IFBBRERJTkctTEVGVDogMHB4OyBGTE9BVDog +bGVmdDsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiA4cHggMHB4IDBweDsgV0lEVEg6IDc2 +M3B4OyBQQURESU5HLVRPUDogMHB4OyBMSVNULVNUWUxFLVRZUEU6IG5vbmUiPg0KICA8TEkgDQog +IHN0eWxlPSJQQURESU5HLVJJR0hUOiA5cHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDEwMCUgNTAl +OyBQQURESU5HLUxFRlQ6IDlweDsgRkxPQVQ6IGxlZnQ7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybCho +dHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMzLmdpZik7IFBBRERJTkct +Qk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBQQURESU5HLVRPUDogMHB4OyBiYWNrZ3JvdW5kLW9y +aWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgc3R5bGU9IkZP +TlQtV0VJR0hUOiBib2xkOyBDT0xPUjogcmdiKDEwLDYxLDE0MCk7IFRFWFQtREVDT1JBVElPTjog +bm9uZSIgDQogIGhyZWY9Imh0dHA6Ly93d3cuY3Nkbi5uZXQvIiB0YXJnZXQ9X2JsYW5rPummlumh +tTwvQT48L0xJPg0KICA8TEkgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiA5cHg7IEJBQ0tHUk9V +TkQtUE9TSVRJT046IDEwMCUgNTAlOyBQQURESU5HLUxFRlQ6IDlweDsgRkxPQVQ6IGxlZnQ7IEJB +Q0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRl +eF9waWMzLmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBQQURESU5HLVRP +UDogMHB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0 +aWFsIj48QSANCiAgc3R5bGU9IkZPTlQtV0VJR0hUOiBib2xkOyBDT0xPUjogcmdiKDEwLDYxLDE0 +MCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIGhyZWY9Imh0dHA6Ly9uZXdzLmNzZG4ubmV0 +LyIgdGFyZ2V0PV9ibGFuaz7otYTorq88L0E+PC9MST4NCiAgPExJIA0KICBzdHlsZT0iUEFERElO +Ry1SSUdIVDogOXB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAxMDAlIDUwJTsgUEFERElORy1MRUZU +OiA5cHg7IEZMT0FUOiBsZWZ0OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcu +Y24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMy5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBN +QVJHSU46IDBweDsgUEFERElORy1UT1A6IDBweDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7 +IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHN0eWxlPSJGT05ULVdFSUdIVDogYm9s +ZDsgQ09MT1I6IHJnYigxMCw2MSwxNDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBocmVm +PSJodHRwOi8vaGkuY3Nkbi5uZXQvIiB0YXJnZXQ9X2JsYW5rPuepuumXtDwvQT48L0xJPg0KICA8 +TEkgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiA5cHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDEw +MCUgNTAlOyBQQURESU5HLUxFRlQ6IDlweDsgRkxPQVQ6IGxlZnQ7IEJBQ0tHUk9VTkQtSU1BR0U6 +IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMzLmdpZik7IFBB +RERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBQQURESU5HLVRPUDogMHB4OyBiYWNrZ3Jv +dW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgc3R5 +bGU9IkZPTlQtV0VJR0hUOiBib2xkOyBDT0xPUjogcmdiKDEwLDYxLDE0MCk7IFRFWFQtREVDT1JB +VElPTjogbm9uZSIgDQogIGhyZWY9Imh0dHA6Ly9iYnMuY3Nkbi5uZXQvIiB0YXJnZXQ9X2JsYW5r +PuiuuuWdmzwvQT48L0xJPg0KICA8TEkgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiA5cHg7IEJB +Q0tHUk9VTkQtUE9TSVRJT046IDEwMCUgNTAlOyBQQURESU5HLUxFRlQ6IDlweDsgRkxPQVQ6IGxl +ZnQ7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2Nz +ZG5pbmRleF9waWMzLmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBQQURE +SU5HLVRPUDogMHB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlw +OiBpbml0aWFsIj48QSANCiAgc3R5bGU9IkZPTlQtV0VJR0hUOiBib2xkOyBDT0xPUjogcmdiKDEw +LDYxLDE0MCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIGhyZWY9Imh0dHA6Ly9ibG9nLmNz +ZG4ubmV0LyIgdGFyZ2V0PV9ibGFuaz7ljZrlrqI8L0E+PC9MST4NCiAgPExJIA0KICBzdHlsZT0i +UEFERElORy1SSUdIVDogOXB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAxMDAlIDUwJTsgUEFERElO +Ry1MRUZUOiA5cHg7IEZMT0FUOiBsZWZ0OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2Nz +ZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMy5naWYpOyBQQURESU5HLUJPVFRPTTog +MHB4OyBNQVJHSU46IDBweDsgUEFERElORy1UT1A6IDBweDsgYmFja2dyb3VuZC1vcmlnaW46IGlu +aXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHN0eWxlPSJGT05ULVdFSUdI +VDogYm9sZDsgQ09MT1I6IHJnYigxMCw2MSwxNDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0K +ICBocmVmPSJodHRwOi8vZG93bmxvYWQuY3Nkbi5uZXQvIiB0YXJnZXQ9X2JsYW5rPuS4i+i9vTwv +QT48L0xJPg0KICA8TEkgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiA5cHg7IEJBQ0tHUk9VTkQt +UE9TSVRJT046IDEwMCUgNTAlOyBQQURESU5HLUxFRlQ6IDlweDsgRkxPQVQ6IGxlZnQ7IEJBQ0tH +Uk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9w +aWMzLmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBQQURESU5HLVRPUDog +MHB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFs +Ij48QSANCiAgc3R5bGU9IkZPTlQtV0VJR0hUOiBib2xkOyBDT0xPUjogcmdiKDEwLDYxLDE0MCk7 +IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIGhyZWY9Imh0dHA6Ly93ei5jc2RuLm5ldC8iIHRh +cmdldD1fYmxhbms+572R5pGYPC9BPjwvTEk+DQogIDxMSSANCiAgc3R5bGU9IlBBRERJTkctUklH +SFQ6IDlweDsgQkFDS0dST1VORC1QT1NJVElPTjogMTAwJSA1MCU7IFBBRERJTkctTEVGVDogOXB4 +OyBGTE9BVDogbGVmdDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3 +dy9pbWFnZXMvY3NkbmluZGV4X3BpYzMuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lO +OiAwcHg7IFBBRERJTkctVE9QOiAwcHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNr +Z3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICBzdHlsZT0iRk9OVC1XRUlHSFQ6IGJvbGQ7IENP +TE9SOiByZ2IoMTAsNjEsMTQwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgaHJlZj0iaHR0 +cDovL3d3dy5wcm9ncmFtbWVyLmNvbS5jbi8iIHRhcmdldD1fYmxhbms+56iL5bqP5ZGYPC9BPjwv +TEk+DQogIDxMSSANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDlweDsgQkFDS0dST1VORC1QT1NJ +VElPTjogMTAwJSA1MCU7IFBBRERJTkctTEVGVDogOXB4OyBGTE9BVDogbGVmdDsgQkFDS0dST1VO +RC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzMu +Z2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IFBBRERJTkctVE9QOiAwcHg7 +IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxB +IA0KICBzdHlsZT0iRk9OVC1XRUlHSFQ6IGJvbGQ7IENPTE9SOiByZ2IoMTAsNjEsMTQwKTsgVEVY +VC1ERUNPUkFUSU9OOiBub25lIiANCiAgaHJlZj0iaHR0cDovL3Byai5jc2RuLm5ldC8iIHRhcmdl +dD1fYmxhbms+6aG555uu5Lqk5piTPC9BPjwvTEk+DQogIDxMSSANCiAgc3R5bGU9IlBBRERJTkct +UklHSFQ6IDlweDsgQkFDS0dST1VORC1QT1NJVElPTjogMTAwJSA1MCU7IFBBRERJTkctTEVGVDog +OXB4OyBGTE9BVDogbGVmdDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNu +L3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzMuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFS +R0lOOiAwcHg7IFBBRERJTkctVE9QOiAwcHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBi +YWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICBzdHlsZT0iRk9OVC1XRUlHSFQ6IGJvbGQ7 +IENPTE9SOiByZ2IoMTAsNjEsMTQwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgaHJlZj0i +aHR0cDovL3d3dy5kZWFyYm9vay5jb20uY24vIiB0YXJnZXQ9X2JsYW5rPuS5puW6lzwvQT48L0xJ +Pg0KICA8TEkgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiA5cHg7IEJBQ0tHUk9VTkQtUE9TSVRJ +T046IDEwMCUgNTAlOyBQQURESU5HLUxFRlQ6IDlweDsgRkxPQVQ6IGxlZnQ7IEJBQ0tHUk9VTkQt +SU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMzLmdp +Zik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBQQURESU5HLVRPUDogMHB4OyBi +YWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSAN +CiAgc3R5bGU9IkZPTlQtV0VJR0hUOiBib2xkOyBDT0xPUjogcmdiKDEwLDYxLDE0MCk7IFRFWFQt +REVDT1JBVElPTjogbm9uZSIgDQogIGhyZWY9Imh0dHA6Ly9jdG8uY3Nkbi5uZXQvIiB0YXJnZXQ9 +X2JsYW5rPkNUT+S/seS5kOmDqDwvQT48L0xJPg0KICA8TEkgDQogIHN0eWxlPSJQQURESU5HLVJJ +R0hUOiA5cHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDEwMCUgNTAlOyBQQURESU5HLUxFRlQ6IDlw +eDsgRkxPQVQ6IGxlZnQ7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93 +d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMzLmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJ +TjogMHB4OyBQQURESU5HLVRPUDogMHB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFj +a2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgY2xhc3M9cmVkIA0KICBzdHlsZT0iRk9OVC1X +RUlHSFQ6IGJvbGQ7IENPTE9SOiByZ2IoMjU1LDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIg +DQogIGhyZWY9Imh0dHA6Ly90dXAuY3Nkbi5uZXQvIiB0YXJnZXQ9X2JsYW5rPlRVUDwvQT48L0xJ +Pg0KICA8TEkgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiA5cHg7IEJBQ0tHUk9VTkQtUE9TSVRJ +T046IDEwMCUgNTAlOyBQQURESU5HLUxFRlQ6IDlweDsgRkxPQVQ6IGxlZnQ7IEJBQ0tHUk9VTkQt +SU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMzLmdp +Zik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBQQURESU5HLVRPUDogMHB4OyBi +YWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSAN +CiAgc3R5bGU9IkZPTlQtV0VJR0hUOiBib2xkOyBDT0xPUjogcmdiKDEwLDYxLDE0MCk7IFRFWFQt +REVDT1JBVElPTjogbm9uZSIgDQogIGhyZWY9Imh0dHA6Ly9lZHUuY3Nkbi5uZXQvIiB0YXJnZXQ9 +X2JsYW5rPuWfueiureWFheeUtTwvQT48L0xJPg0KICA8TEkgY2xhc3M9bGFzdCANCiAgc3R5bGU9 +IlBBRERJTkctUklHSFQ6IDExcHg7IFBBRERJTkctTEVGVDogMTFweDsgRkxPQVQ6IGxlZnQ7IEJB +Q0tHUk9VTkQtSU1BR0U6IG5vbmU7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBQ +QURESU5HLVRPUDogMHB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1j +bGlwOiBpbml0aWFsIj48QSANCiAgc3R5bGU9IkZPTlQtV0VJR0hUOiBib2xkOyBDT0xPUjogcmdi +KDEwLDYxLDE0MCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIGhyZWY9Imh0dHA6Ly9zdHVk +ZW50LmNzZG4ubmV0L3NwYWNlLnBocD9kbz1tdGFnJmFtcDtpZD01IiANCiAgdGFyZ2V0PV9ibGFu +az7pq5jmoKFjbHViPC9BPjwvTEk+PC9VTD4NCjxVTCBjbGFzcz1yb3dfMiANCnN0eWxlPSJQQURE +SU5HLVJJR0hUOiAwcHg7IFBBRERJTkctTEVGVDogMHB4OyBGTE9BVDogbGVmdDsgUEFERElORy1C +T1RUT006IDBweDsgTUFSR0lOOiAxOHB4IDBweCAwcHg7IFdJRFRIOiA3NjNweDsgUEFERElORy1U +T1A6IDBweDsgTElTVC1TVFlMRS1UWVBFOiBub25lIj4NCiAgPExJIA0KICBzdHlsZT0iUEFERElO +Ry1SSUdIVDogMTBweDsgUEFERElORy1MRUZUOiAxMHB4OyBGTE9BVDogbGVmdDsgUEFERElORy1C +T1RUT006IDBweDsgTUFSR0lOOiAwcHg7IFZFUlRJQ0FMLUFMSUdOOiBib3R0b207IFBBRERJTkct +VE9QOiAwcHgiPjxBIA0KICBjbGFzcz1yZWQgDQogIHN0eWxlPSJGT05ULVdFSUdIVDogYm9sZDsg +Q09MT1I6IHJnYigyNTUsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgaHJlZj0iaHR0 +cDovL3NkLmNzZG4ubmV0LyIgdGFyZ2V0PV9ibGFuaz7noJTlj5E8L0E+PC9MST4NCiAgPExJIA0K +ICBzdHlsZT0iUEFERElORy1SSUdIVDogMTBweDsgUEFERElORy1MRUZUOiAxMHB4OyBGTE9BVDog +bGVmdDsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IFZFUlRJQ0FMLUFMSUdOOiBi +b3R0b207IFBBRERJTkctVE9QOiAwcHgiPjxBIA0KICBzdHlsZT0iRk9OVC1XRUlHSFQ6IGJvbGQ7 +IENPTE9SOiByZ2IoMTAsNjEsMTQwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgaHJlZj0i +aHR0cDovL21vYmlsZS5jc2RuLm5ldC8iIHRhcmdldD1fYmxhbms+56e75YqoPC9BPjwvTEk+DQog +IDxMSSANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDEwcHg7IFBBRERJTkctTEVGVDogMTBweDsg +RkxPQVQ6IGxlZnQ7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBWRVJUSUNBTC1B +TElHTjogYm90dG9tOyBQQURESU5HLVRPUDogMHB4Ij48QSANCiAgc3R5bGU9IkZPTlQtV0VJR0hU +OiBib2xkOyBDT0xPUjogcmdiKDEwLDYxLDE0MCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQog +IGhyZWY9Imh0dHA6Ly9jOS5jc2RuLmh1ZG9uZy5jb20vIiB0YXJnZXQ9X2JsYW5rPkNoYW5uZWw5 +PC9BPjwvTEk+DQogIDxMSSANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDEwcHg7IFBBRERJTkct +TEVGVDogMTBweDsgRkxPQVQ6IGxlZnQ7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4 +OyBWRVJUSUNBTC1BTElHTjogYm90dG9tOyBQQURESU5HLVRPUDogMHB4Ij48QSANCiAgc3R5bGU9 +IkZPTlQtV0VJR0hUOiBib2xkOyBDT0xPUjogcmdiKDEwLDYxLDE0MCk7IFRFWFQtREVDT1JBVElP +Tjogbm9uZSIgDQogIGhyZWY9Imh0dHA6Ly9qYXZhLmNzZG4ubmV0LyIgdGFyZ2V0PV9ibGFuaz5K +YXZhPC9BPjwvTEk+DQogIDxMSSANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDEwcHg7IFBBRERJ +TkctTEVGVDogMTBweDsgRkxPQVQ6IGxlZnQ7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjog +MHB4OyBWRVJUSUNBTC1BTElHTjogYm90dG9tOyBQQURESU5HLVRPUDogMHB4Ij48QSANCiAgc3R5 +bGU9IkZPTlQtV0VJR0hUOiBib2xkOyBDT0xPUjogcmdiKDEwLDYxLDE0MCk7IFRFWFQtREVDT1JB +VElPTjogbm9uZSIgDQogIGhyZWY9Imh0dHA6Ly9zZWN1cml0eS5jc2RuLm5ldC8iIHRhcmdldD1f +Ymxhbms+5a6J5YWoPC9BPjwvTEk+DQogIDxMSSANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDEw +cHg7IFBBRERJTkctTEVGVDogMTBweDsgRkxPQVQ6IGxlZnQ7IFBBRERJTkctQk9UVE9NOiAwcHg7 +IE1BUkdJTjogMHB4OyBWRVJUSUNBTC1BTElHTjogYm90dG9tOyBQQURESU5HLVRPUDogMHB4Ij48 +QSANCiAgc3R5bGU9IkZPTlQtV0VJR0hUOiBib2xkOyBDT0xPUjogcmdiKDEwLDYxLDE0MCk7IFRF +WFQtREVDT1JBVElPTjogbm9uZSIgDQogIGhyZWY9Imh0dHA6Ly9kYXRhYmFzZS5jc2RuLm5ldC8i +IHRhcmdldD1fYmxhbms+5pWw5o2u5bqTPC9BPjwvTEk+DQogIDxMSSANCiAgc3R5bGU9IlBBRERJ +TkctUklHSFQ6IDEwcHg7IFBBRERJTkctTEVGVDogMTBweDsgRkxPQVQ6IGxlZnQ7IFBBRERJTkct +Qk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBWRVJUSUNBTC1BTElHTjogYm90dG9tOyBQQURESU5H +LVRPUDogMHB4Ij48QSANCiAgc3R5bGU9IkZPTlQtV0VJR0hUOiBib2xkOyBDT0xPUjogcmdiKDEw +LDYxLDE0MCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIGhyZWY9Imh0dHA6Ly9kb3RuZXQu +Y3Nkbi5uZXQvIiB0YXJnZXQ9X2JsYW5rPi5ORVQ8L0E+PC9MST4NCiAgPExJIA0KICBzdHlsZT0i +UEFERElORy1SSUdIVDogMTBweDsgUEFERElORy1MRUZUOiAxMHB4OyBGTE9BVDogbGVmdDsgUEFE +RElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IFZFUlRJQ0FMLUFMSUdOOiBib3R0b207IFBB +RERJTkctVE9QOiAwcHgiPjxBIA0KICBzdHlsZT0iRk9OVC1XRUlHSFQ6IGJvbGQ7IENPTE9SOiBy +Z2IoMTAsNjEsMTQwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgaHJlZj0iaHR0cDovL3dl +YmRldi5jc2RuLm5ldC8iIHRhcmdldD1fYmxhbms+V2Vi5byA5Y+RPC9BPjwvTEk+DQogIDxMSSAN +CiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDEwcHg7IFBBRERJTkctTEVGVDogMTBweDsgRkxPQVQ6 +IGxlZnQ7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBWRVJUSUNBTC1BTElHTjog +Ym90dG9tOyBQQURESU5HLVRPUDogMHB4Ij48QSANCiAgc3R5bGU9IkZPTlQtV0VJR0hUOiBib2xk +OyBDT0xPUjogcmdiKDEwLDYxLDE0MCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIGhyZWY9 +Imh0dHA6Ly9jbG91ZC5jc2RuLm5ldC8iIHRhcmdldD1fYmxhbms+5LqR6K6h566XPC9BPjwvTEk+ +DQogIDxMSSANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDEwcHg7IFBBRERJTkctTEVGVDogMTBw +eDsgRkxPQVQ6IGxlZnQ7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBWRVJUSUNB +TC1BTElHTjogYm90dG9tOyBQQURESU5HLVRPUDogMHB4Ij48QSANCiAgc3R5bGU9IkZPTlQtV0VJ +R0hUOiBib2xkOyBDT0xPUjogcmdiKDEwLDYxLDE0MCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIg +DQogIGhyZWY9Imh0dHA6Ly9zZXJ2ZXIuY3Nkbi5uZXQvIiB0YXJnZXQ9X2JsYW5rPuacjeWKoeWZ +qDwvQT48L0xJPg0KICA8TEkgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAxMHB4OyBQQURESU5H +LUxFRlQ6IDEwcHg7IEZMT0FUOiBsZWZ0OyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBw +eDsgVkVSVElDQUwtQUxJR046IGJvdHRvbTsgUEFERElORy1UT1A6IDBweCI+PEEgDQogIHN0eWxl +PSJGT05ULVdFSUdIVDogYm9sZDsgQ09MT1I6IHJnYigxMCw2MSwxNDApOyBURVhULURFQ09SQVRJ +T046IG5vbmUiIA0KICBocmVmPSJodHRwOi8vdGVsZWNvbS1pdC5jc2RuLm5ldC8iIHRhcmdldD1f +Ymxhbms+55S15L+hSVQ8L0E+PC9MST4NCiAgPExJIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDog +MTBweDsgUEFERElORy1MRUZUOiAxMHB4OyBGTE9BVDogbGVmdDsgUEFERElORy1CT1RUT006IDBw +eDsgTUFSR0lOOiAwcHg7IFZFUlRJQ0FMLUFMSUdOOiBib3R0b207IFBBRERJTkctVE9QOiAwcHgi +PjxBIA0KICBzdHlsZT0iRk9OVC1XRUlHSFQ6IGJvbGQ7IENPTE9SOiByZ2IoMTAsNjEsMTQwKTsg +VEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgaHJlZj0iaHR0cDovL3N0dWRlbnQuY3Nkbi5uZXQv +IiB0YXJnZXQ9X2JsYW5rPuWtpueUn+Wkp+acrOiQpTwvQT48L0xJPg0KICA8TEkgDQogIHN0eWxl +PSJQQURESU5HLVJJR0hUOiAxMHB4OyBQQURESU5HLUxFRlQ6IDEwcHg7IEZMT0FUOiBsZWZ0OyBQ +QURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweDsgVkVSVElDQUwtQUxJR046IGJvdHRvbTsg +UEFERElORy1UT1A6IDBweCI+PEEgDQogIHN0eWxlPSJGT05ULVdFSUdIVDogYm9sZDsgQ09MT1I6 +IHJnYigxMCw2MSwxNDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBocmVmPSJodHRwOi8v +aHVudGVyLmNzZG4ubmV0LyIgdGFyZ2V0PV9ibGFuaz7njI7lpLQ8L0E+PC9MST48L1VMPjwvRElW +PjwvRElWPg0KPERJViBjbGFzcz0ibWFudWZhY3R1cmVyX2luZGV4IHR4dF9ncmF5IiANCnN0eWxl +PSJGTE9BVDogbGVmdDsgTUFSR0lOOiAwcHggMHB4IDJweDsgV0lEVEg6IDk2MHB4OyBDT0xPUjog +cmdiKDEwMiwxMDIsMTAyKTsgQkFDS0dST1VORC1DT0xPUjogcmdiKDI0NSwyNDUsMjQ1KTsgVEVY +VC1BTElHTjogbGVmdDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xp +cDogaW5pdGlhbCI+DQo8VUwgDQpzdHlsZT0iUEFERElORy1SSUdIVDogM3B4OyBQQURESU5HLUxF +RlQ6IDNweDsgRkxPQVQ6IGxlZnQ7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBX +SURUSDogOTU0cHg7IExJTkUtSEVJR0hUOiAyMXB4OyBQQURESU5HLVRPUDogMHB4OyBMSVNULVNU +WUxFLVRZUEU6IG5vbmUiPg0KICA8TEkgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IFBB +RERJTkctTEVGVDogMHB4OyBGTE9BVDogbGVmdDsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lO +OiAwcHg7IFBBRERJTkctVE9QOiAwcHgiPjxBIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogNHB4 +OyBQQURESU5HLUxFRlQ6IDRweDsgUEFERElORy1CT1RUT006IDBweDsgQ09MT1I6IHJnYigxMDIs +MTAyLDEwMik7IFBBRERJTkctVE9QOiAwcHg7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIGhy +ZWY9Imh0dHA6Ly8zZy5lZHUuY3Nkbi5uZXQvIiB0YXJnZXQ9X2JsYW5rPjNH5a2m6ZmiPC9BPnw8 +L0xJPg0KICA8TEkgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IFBBRERJTkctTEVGVDog +MHB4OyBGTE9BVDogbGVmdDsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IFBBRERJ +TkctVE9QOiAwcHgiPjxBIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogNHB4OyBQQURESU5HLUxF +RlQ6IDRweDsgUEFERElORy1CT1RUT006IDBweDsgQ09MT1I6IHJnYigxMDIsMTAyLDEwMik7IFBB +RERJTkctVE9QOiAwcHg7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIGhyZWY9Imh0dHA6Ly93 +d3cuaXRjYXN0LmNuLyIgdGFyZ2V0PV9ibGFuaz5KYXZh5a2m6ZmiPC9BPnw8L0xJPg0KICA8TEkg +DQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IFBBRERJTkctTEVGVDogMHB4OyBGTE9BVDog +bGVmdDsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IFBBRERJTkctVE9QOiAwcHgi +PjxBIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogNHB4OyBQQURESU5HLUxFRlQ6IDRweDsgUEFE +RElORy1CT1RUT006IDBweDsgQ09MT1I6IHJnYigxMDIsMTAyLDEwMik7IFBBRERJTkctVE9QOiAw +cHg7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIGhyZWY9Imh0dHA6Ly9uZXQuaXRjYXN0LmNu +LyIgdGFyZ2V0PV9ibGFuaz4uTkVU5a2m6ZmiPC9BPnw8L0xJPg0KICA8TEkgDQogIHN0eWxlPSJQ +QURESU5HLVJJR0hUOiAwcHg7IFBBRERJTkctTEVGVDogMHB4OyBGTE9BVDogbGVmdDsgUEFERElO +Ry1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IFBBRERJTkctVE9QOiAwcHgiPjxBIA0KICBzdHls +ZT0iUEFERElORy1SSUdIVDogNHB4OyBQQURESU5HLUxFRlQ6IDRweDsgUEFERElORy1CT1RUT006 +IDBweDsgQ09MT1I6IHJnYigxMDIsMTAyLDEwMik7IFBBRERJTkctVE9QOiAwcHg7IFRFWFQtREVD +T1JBVElPTjogbm9uZSIgDQogIGhyZWY9Imh0dHA6Ly93d3cubGFtcGJyb3RoZXIubmV0LyIgdGFy +Z2V0PV9ibGFuaz5QSFDlrabpmaI8L0E+fDwvTEk+DQogIDxMSSANCiAgc3R5bGU9IlBBRERJTkct +UklHSFQ6IDBweDsgUEFERElORy1MRUZUOiAwcHg7IEZMT0FUOiBsZWZ0OyBQQURESU5HLUJPVFRP +TTogMHB4OyBNQVJHSU46IDBweDsgUEFERElORy1UT1A6IDBweCI+PEEgDQogIHN0eWxlPSJQQURE +SU5HLVJJR0hUOiA0cHg7IFBBRERJTkctTEVGVDogNHB4OyBQQURESU5HLUJPVFRPTTogMHB4OyBD +T0xPUjogcmdiKDEwMiwxMDIsMTAyKTsgUEFERElORy1UT1A6IDBweDsgVEVYVC1ERUNPUkFUSU9O +OiBub25lIiANCiAgaHJlZj0iaHR0cDovL2libS5jc2RuLm5ldC8iIHRhcmdldD1fYmxhbms+SUJN +IGRXPC9BPnw8L0xJPg0KICA8TEkgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IFBBRERJ +TkctTEVGVDogMHB4OyBGTE9BVDogbGVmdDsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAw +cHg7IFBBRERJTkctVE9QOiAwcHgiPjxBIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogNHB4OyBQ +QURESU5HLUxFRlQ6IDRweDsgUEFERElORy1CT1RUT006IDBweDsgQ09MT1I6IHJnYigxMDIsMTAy +LDEwMik7IFBBRERJTkctVE9QOiAwcHg7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIGhyZWY9 +Imh0dHA6Ly9pbnRlbC5jc2RuLm5ldC8iIHRhcmdldD1fYmxhbms+6Iux54m55bCUIOi9r+S7tjwv +QT58PC9MST4NCiAgPExJIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBQQURESU5HLUxF +RlQ6IDBweDsgRkxPQVQ6IGxlZnQ7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBQ +QURESU5HLVRPUDogMHB4Ij48QSANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDRweDsgUEFERElO +Ry1MRUZUOiA0cHg7IFBBRERJTkctQk9UVE9NOiAwcHg7IENPTE9SOiByZ2IoMTAyLDEwMiwxMDIp +OyBQQURESU5HLVRPUDogMHB4OyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBocmVmPSJodHRw +Oi8vZy5jc2RuLm5ldC81MDI0MzU5IiB0YXJnZXQ9X2JsYW5rPuWuieiFvjwvQT48QSANCiAgc3R5 +bGU9IlBBRERJTkctUklHSFQ6IDRweDsgUEFERElORy1MRUZUOiA0cHg7IFBBRERJTkctQk9UVE9N +OiAwcHg7IENPTE9SOiByZ2IoMTAyLDEwMiwxMDIpOyBQQURESU5HLVRPUDogMHB4OyBURVhULURF +Q09SQVRJT046IG5vbmUiIA0KICBocmVmPSJodHRwOi8veGVvbi5jc2RuLm5ldC8iIHRhcmdldD1f +Ymxhbms+6Iez5by6PC9BPnw8L0xJPg0KICA8TEkgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAw +cHg7IFBBRERJTkctTEVGVDogMHB4OyBGTE9BVDogbGVmdDsgUEFERElORy1CT1RUT006IDBweDsg +TUFSR0lOOiAwcHg7IFBBRERJTkctVE9QOiAwcHgiPjxBIA0KICBzdHlsZT0iUEFERElORy1SSUdI +VDogNHB4OyBQQURESU5HLUxFRlQ6IDRweDsgUEFERElORy1CT1RUT006IDBweDsgQ09MT1I6IHJn +YigxMDIsMTAyLDEwMik7IFBBRERJTkctVE9QOiAwcHg7IFRFWFQtREVDT1JBVElPTjogbm9uZSIg +DQogIGhyZWY9Imh0dHA6Ly9tZWVnb3pvbmUuY3Nkbi5uZXQvIiB0YXJnZXQ9X2JsYW5rPk1lZUdv +PC9BPnw8L0xJPg0KICA8TEkgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IFBBRERJTkct +TEVGVDogMHB4OyBGTE9BVDogbGVmdDsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7 +IFBBRERJTkctVE9QOiAwcHgiPjxBIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogNHB4OyBQQURE +SU5HLUxFRlQ6IDRweDsgUEFERElORy1CT1RUT006IDBweDsgQ09MT1I6IHJnYigxMDIsMTAyLDEw +Mik7IFBBRERJTkctVE9QOiAwcHg7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIGhyZWY9Imh0 +dHA6Ly9vcGhvbmUuY3Nkbi5uZXQvbWluaXNpdGUiIHRhcmdldD1fYmxhbms+T1Bob25lPC9BPnw8 +L0xJPg0KICA8TEkgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IFBBRERJTkctTEVGVDog +MHB4OyBGTE9BVDogbGVmdDsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IFBBRERJ +TkctVE9QOiAwcHgiPjxBIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogNHB4OyBQQURESU5HLUxF +RlQ6IDRweDsgUEFERElORy1CT1RUT006IDBweDsgQ09MT1I6IHJnYigxMDIsMTAyLDEwMik7IFBB +RERJTkctVE9QOiAwcHg7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIGhyZWY9Imh0dHA6Ly9m +bGV4LmNzZG4ubmV0LyIgdGFyZ2V0PV9ibGFuaz5GbGV4L0FJUjwvQT58PC9MST4NCiAgPExJIA0K +ICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBQQURESU5HLUxFRlQ6IDBweDsgRkxPQVQ6IGxl +ZnQ7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBQQURESU5HLVRPUDogMHB4Ij48 +QSANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDRweDsgUEFERElORy1MRUZUOiA0cHg7IFBBRERJ +TkctQk9UVE9NOiAwcHg7IENPTE9SOiByZ2IoMTAyLDEwMiwxMDIpOyBQQURESU5HLVRPUDogMHB4 +OyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBocmVmPSJodHRwOi8vc3ViamVjdC5jc2RuLm5l +dC9WUzIwMTBfdGVjLyIgdGFyZ2V0PV9ibGFuaz5WUzIwMTA8L0E+fDwvTEk+DQogIDxMSSANCiAg +c3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgUEFERElORy1MRUZUOiAwcHg7IEZMT0FUOiBsZWZ0 +OyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweDsgUEFERElORy1UT1A6IDBweCI+PEEg +DQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiA0cHg7IFBBRERJTkctTEVGVDogNHB4OyBQQURESU5H +LUJPVFRPTTogMHB4OyBDT0xPUjogcmdiKDEwMiwxMDIsMTAyKTsgUEFERElORy1UT1A6IDBweDsg +VEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgaHJlZj0iaHR0cDovL3F0LmNzZG4ubmV0LyIgdGFy +Z2V0PV9ibGFuaz5RdDwvQT58PC9MST4NCiAgPExJIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDog +MHB4OyBQQURESU5HLUxFRlQ6IDBweDsgRkxPQVQ6IGxlZnQ7IFBBRERJTkctQk9UVE9NOiAwcHg7 +IE1BUkdJTjogMHB4OyBQQURESU5HLVRPUDogMHB4Ij48QSANCiAgc3R5bGU9IlBBRERJTkctUklH +SFQ6IDRweDsgUEFERElORy1MRUZUOiA0cHg7IFBBRERJTkctQk9UVE9NOiAwcHg7IENPTE9SOiBy +Z2IoMTAyLDEwMiwxMDIpOyBQQURESU5HLVRPUDogMHB4OyBURVhULURFQ09SQVRJT046IG5vbmUi +IA0KICBocmVmPSJodHRwOi8vYmFpZHUuY3Nkbi5uZXQvIiB0YXJnZXQ9X2JsYW5rPueZvuW6puek +vuWMujwvQT58PC9MST4NCiAgPExJIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBQQURE +SU5HLUxFRlQ6IDBweDsgRkxPQVQ6IGxlZnQ7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjog +MHB4OyBQQURESU5HLVRPUDogMHB4Ij48QSANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDRweDsg +UEFERElORy1MRUZUOiA0cHg7IFBBRERJTkctQk9UVE9NOiAwcHg7IENPTE9SOiByZ2IoMTAyLDEw +MiwxMDIpOyBQQURESU5HLVRPUDogMHB4OyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBocmVm +PSJodHRwOi8vYmxhY2tiZXJyeS5jc2RuLm5ldC8iIHRhcmdldD1fYmxhbms+QmxhY2tCZXJyeTwv +QT58PC9MST4NCiAgPExJIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBQQURESU5HLUxF +RlQ6IDBweDsgRkxPQVQ6IGxlZnQ7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBQ +QURESU5HLVRPUDogMHB4Ij48QSANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDRweDsgUEFERElO +Ry1MRUZUOiA0cHg7IFBBRERJTkctQk9UVE9NOiAwcHg7IENPTE9SOiByZ2IoMTAyLDEwMiwxMDIp +OyBQQURESU5HLVRPUDogMHB4OyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBocmVmPSJodHRw +Oi8vYmFkYS5jc2RuLm5ldC8iIHRhcmdldD1fYmxhbms+YmFkYTwvQT58PC9MST4NCiAgPExJIA0K +ICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBQQURESU5HLUxFRlQ6IDBweDsgRkxPQVQ6IGxl +ZnQ7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBQQURESU5HLVRPUDogMHB4Ij48 +QSANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDRweDsgUEFERElORy1MRUZUOiA0cHg7IFBBRERJ +TkctQk9UVE9NOiAwcHg7IENPTE9SOiByZ2IoMTAyLDEwMiwxMDIpOyBQQURESU5HLVRPUDogMHB4 +OyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBocmVmPSJodHRwOi8vc21pLmNzZG4ubmV0LyIg +dGFyZ2V0PV9ibGFuaz7kuInmmJ9TTUk8L0E+fDwvTEk+DQogIDxMSSANCiAgc3R5bGU9IlBBRERJ +TkctUklHSFQ6IDBweDsgUEFERElORy1MRUZUOiAwcHg7IEZMT0FUOiBsZWZ0OyBQQURESU5HLUJP +VFRPTTogMHB4OyBNQVJHSU46IDBweDsgUEFERElORy1UT1A6IDBweCI+PEEgDQogIGNsYXNzPXJl +ZCANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDRweDsgUEFERElORy1MRUZUOiA0cHg7IFBBRERJ +TkctQk9UVE9NOiAwcHg7IENPTE9SOiByZ2IoMjU1LDAsMCk7IFBBRERJTkctVE9QOiAwcHg7IFRF +WFQtREVDT1JBVElPTjogbm9uZSIgDQogIGhyZWY9Imh0dHA6Ly8xODl3b3Jrcy5jc2RuLm5ldC8i +IHRhcmdldD1fYmxhbms+5aSp57+856m66Ze0PC9BPjwvTEk+PC9VTD48L0RJVj4NCjxESVYgY2xh +c3M9YmFubmVyX3RvcDIgDQpzdHlsZT0iQk9SREVSLVJJR0hUOiByZ2IoMjA0LDIwNCwyMDQpIDFw +eCBzb2xpZDsgUEFERElORy1SSUdIVDogNXB4OyBCT1JERVItVE9QOiByZ2IoMjA0LDIwNCwyMDQp +IDFweCBzb2xpZDsgUEFERElORy1MRUZUOiA1cHg7IEZMT0FUOiBsZWZ0OyBQQURESU5HLUJPVFRP +TTogMHB4OyBCT1JERVItTEVGVDogcmdiKDIwNCwyMDQsMjA0KSAxcHggc29saWQ7IFdJRFRIOiA5 +NDhweDsgUEFERElORy1UT1A6IDRweDsgQk9SREVSLUJPVFRPTTogcmdiKDIwNCwyMDQsMjA0KSAx +cHggc29saWQ7IFRFWFQtQUxJR046IGxlZnQiPg0KPFVMIGNsYXNzPSJsaXN0dHh0YWRfbGVmdCB0 +eHRfZGVlcGJsdWUiIA0Kc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgUEFERElORy1MRUZUOiAw +cHg7IEZMT0FUOiBsZWZ0OyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDNweCAwcHggMHB4 +OyBXSURUSDogMTg1cHg7IENPTE9SOiByZ2IoMCw1MSwyMDQpOyBQQURESU5HLVRPUDogMHB4OyBM +SVNULVNUWUxFLVRZUEU6IG5vbmUiPg0KICA8TEkgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAw +cHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDBweCA4cHg7IFBBRERJTkctTEVGVDogOXB4OyBCQUNL +R1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhf +cGljNS5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweDsgUEFERElORy1UT1A6 +IDBweDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlh +bCI+PEEgDQogIHN0eWxlPSJDT0xPUjogcmdiKDAsNTEsMjA0KTsgVEVYVC1ERUNPUkFUSU9OOiBu +b25lIiANCiAgaHJlZj0iaHR0cDovL3ouY3Nkbi5uZXQvZ21jbGljay5waHA/YmFubmVyaWQ9MzQ2 +OSZhbXA7em9uZWlkPTQxMSZhbXA7c291cmNlPSZhbXA7ZGVzdD1odHRwJTNBJTJGJTJGd3d3LmVt +YmVkdS5vcmclMkZrb3ViZWklMkZpbmRleC5odG0iIA0KICB0YXJnZXQ9X2JsYW5rPuOAkOmhtuOA +keW6lOWxiueUnyzlhaXogYzlubTolqo1LTEw5LiHPC9BPjwvTEk+DQogIDxMSSANCiAgc3R5bGU9 +IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMHB4IDhweDsgUEFERElO +Ry1MRUZUOiA5cHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cv +aW1hZ2VzL2NzZG5pbmRleF9waWM1LmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjog +MHB4OyBQQURESU5HLVRPUDogMHB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dy +b3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCw1MSwyMDQpOyBU +RVhULURFQ09SQVRJT046IG5vbmUiIA0KICBocmVmPSJodHRwOi8vei5jc2RuLm5ldC9nbWNsaWNr +LnBocD9iYW5uZXJpZD00ODU2JmFtcDt6b25laWQ9NDEyJmFtcDtzb3VyY2U9JmFtcDtkZXN0PWh0 +dHAlM0ElMkYlMkZ3d3cudWNhbmNvZGUubmV0JTJGY3NtYWluLmh0bSIgDQogIHRhcmdldD1fYmxh +bms+5pawVkMrKyAyMDEw5Zu+5b2i5rqQ56CB5bqT56ysM+eJiCE8L0E+PC9MST4NCiAgPExJIA0K +ICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAwcHggOHB4 +OyBQQURESU5HLUxFRlQ6IDlweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1n +LmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzUuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsg +TUFSR0lOOiAwcHg7IFBBRERJTkctVE9QOiAwcHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFs +OyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDUx +LDIwNCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIGhyZWY9Imh0dHA6Ly96LmNzZG4ubmV0 +L2dtY2xpY2sucGhwP2Jhbm5lcmlkPTUwMzYmYW1wO3pvbmVpZD00MTMmYW1wO3NvdXJjZT0mYW1w +O2Rlc3Q9aHR0cCUzQSUyRiUyRnd3dy5ianRhcmVuYS5jb20lMkZjcHguaHRtbCIgDQogIHRhcmdl +dD1fYmxhbms+5LiN5oeCQysr5LiN5piv55yf5q2j55qE56iL5bqP5ZGY77yBPC9BPjwvTEk+DQog +IDxMSSANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjog +MHB4IDhweDsgUEFERElORy1MRUZUOiA5cHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8v +Y3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWM1LmdpZik7IFBBRERJTkctQk9UVE9N +OiAwcHg7IE1BUkdJTjogMHB4OyBQQURESU5HLVRPUDogMHB4OyBiYWNrZ3JvdW5kLW9yaWdpbjog +aW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgc3R5bGU9IkNPTE9SOiBy +Z2IoMCw1MSwyMDQpOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBocmVmPSJodHRwOi8vei5j +c2RuLm5ldC9nbWNsaWNrLnBocD9iYW5uZXJpZD01NDI0JmFtcDt6b25laWQ9NDE0JmFtcDtzb3Vy +Y2U9JmFtcDtkZXN0PWh0dHAlM0ElMkYlMkZldmVudHMudW5pc2ZhaXIuY29tJTJGcnQlMkZpYm0l +N0VyYXRpb25hbCUyRmluZGV4LmpzcCUzRmxjJTNEemglMjZjYyUzRGNuJTI2Y29kZSUzRGNzZG4i +IA0KICB0YXJnZXQ9X2JsYW5rPuaKpeWQjUlCTeW8gOWPkeiAheWkp+S8mui1ouWkmuenjeWkp+Wl +ljwvQT48L0xJPg0KICA8TEkgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9V +TkQtUE9TSVRJT046IDBweCA4cHg7IFBBRERJTkctTEVGVDogOXB4OyBCQUNLR1JPVU5ELUlNQUdF +OiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljNS5naWYpOyBQ +QURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweDsgUEFERElORy1UT1A6IDBweDsgYmFja2dy +b3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHN0 +eWxlPSJDT0xPUjogcmdiKDAsNTEsMjA0KTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgaHJl +Zj0iaHR0cDovL3ouY3Nkbi5uZXQvZ21jbGljay5waHA/YmFubmVyaWQ9NTM1MiZhbXA7em9uZWlk +PTQxNSZhbXA7c291cmNlPSZhbXA7ZGVzdD1odHRwJTNBJTJGJTJGd3d3LndpYnUuY29tLmNuJTJG +TmV3V2ViJTJGd2lidSUyRmV2ZW50cy5waHAuaHRtIiANCiAgdGFyZ2V0PV9ibGFuaz5Db2RlTWV0 +ZXLova/ku7bliqDlr4bmioDmnK/noJTorqjkvJo8L0E+PC9MST48L1VMPg0KPFVMIGNsYXNzPWxp +c3RhZF9taWQgDQpzdHlsZT0iUEFERElORy1SSUdIVDogOXB4OyBQQURESU5HLUxFRlQ6IDlweDsg +RkxPQVQ6IGxlZnQ7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBXSURUSDogNTYw +cHg7IFBBRERJTkctVE9QOiAwcHg7IExJU1QtU1RZTEUtVFlQRTogbm9uZSI+DQogIDxMSSANCiAg +c3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgUEFERElORy1MRUZUOiAwcHg7IFBBRERJTkctQk9U +VE9NOiAwcHg7IE1BUkdJTjogMHB4OyBQQURESU5HLVRPUDogMHB4Ij48QSANCiAgc3R5bGU9IkNP +TE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBocmVmPSJodHRwOi8v +ei5jc2RuLm5ldC9nbWNsaWNrLnBocD9iYW5uZXJpZD01MzE3JmFtcDt6b25laWQ9NDA0JmFtcDtz +b3VyY2U9JmFtcDtkZXN0PWh0dHAlM0ElMkYlMkZvcGVyLjE4OXdvcmtzLmNvbSUyRm5ld3MlMkZQ +cm9tb3Rpb24uanNwIiANCiAgdGFyZ2V0PV9ibGFuaz48SU1HIHRpdGxlPSIiIA0KICBzdHlsZT0i +Qk9SREVSLVRPUC1XSURUSDogMHB4OyBCT1JERVItTEVGVC1XSURUSDogMHB4OyBCT1JERVItQk9U +VE9NLVdJRFRIOiAwcHg7IEJPUkRFUi1SSUdIVC1XSURUSDogMHB4IiANCiAgaGVpZ2h0PTk1IGFs +dD0iIiANCiAgc3JjPSJodHRwOi8vaW5mby1kYXRhYmFzZS5jc2RuLm5ldC9VcGxvYWQvMjAxMC0x +MS0yMy81NjBfOTVfd3JfMTEyMy5naWYiIA0KICB3aWR0aD01NjAgYm9yZGVyPTA+PC9BPg0KICA8 +RElWIGlkPWJlYWNvbl81MzE3IA0KICBzdHlsZT0iTEVGVDogMHB4OyBWSVNJQklMSVRZOiBoaWRk +ZW47IFBPU0lUSU9OOiBhYnNvbHV0ZTsgVE9QOiAwcHgiPjxJTUcgDQogIHN0eWxlPSJCT1JERVIt +VE9QLVdJRFRIOiAwcHg7IEJPUkRFUi1MRUZULVdJRFRIOiAwcHg7IEJPUkRFUi1CT1RUT00tV0lE +VEg6IDBweDsgV0lEVEg6IDBweDsgSEVJR0hUOiAwcHg7IEJPUkRFUi1SSUdIVC1XSURUSDogMHB4 +IiANCiAgaGVpZ2h0PTAgYWx0PSIiIA0KICBzcmM9Imh0dHA6Ly96LmNzZG4ubmV0L2dtbG9nLnBo +cD9iYW5uZXJpZD01MzE3JmFtcDtjbGllbnRpZD0xNTQ4JmFtcDt6Zj0mYW1wO3pvbmVpZD00MDQm +YW1wO3NvdXJjZT0mYW1wO2Jsb2NrPTAmYW1wO2NhcHBpbmc9MCZhbXA7Y2I9MmY0ZDFlOTdlMjc1 +ZTYzOTgxNDQzNjQzZmVmODhjMDEiIA0KICB3aWR0aD0wPjwvRElWPjwvTEk+PC9VTD4NCjxVTCBj +bGFzcz0ibGlzdHR4dGFkX2xlZnQgdHh0X2RlZXBibHVlIiANCnN0eWxlPSJQQURESU5HLVJJR0hU +OiAwcHg7IFBBRERJTkctTEVGVDogMHB4OyBGTE9BVDogbGVmdDsgUEFERElORy1CT1RUT006IDBw +eDsgTUFSR0lOOiAzcHggMHB4IDBweDsgV0lEVEg6IDE4NXB4OyBDT0xPUjogcmdiKDAsNTEsMjA0 +KTsgUEFERElORy1UT1A6IDBweDsgTElTVC1TVFlMRS1UWVBFOiBub25lIj4NCiAgPExJIA0KICBz +dHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAwcHggOHB4OyBQ +QURESU5HLUxFRlQ6IDlweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNu +L3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzUuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFS +R0lOOiAwcHg7IFBBRERJTkctVE9QOiAwcHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBi +YWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDUxLDIw +NCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIGhyZWY9Imh0dHA6Ly96LmNzZG4ubmV0L2dt +Y2xpY2sucGhwP2Jhbm5lcmlkPTU0NDImYW1wO3pvbmVpZD00MTYmYW1wO3NvdXJjZT0mYW1wO2Rl +c3Q9aHR0cCUzQSUyRiUyRm1zZG4ubWljcm9zb2Z0LmNvbSUyRnpoLWNuJTJGd2luZG93c3Bob25l +JTJGZGVmYXVsdC5hc3B4JTNGb2NpZCUzRGJhbi1uLWNuLXdwNy0tY3NkbisiIA0KICB0YXJnZXQ9 +X2JsYW5rPuS9v+eUqFhOQeahhuaetui/m+ihjDNE5ri45oiP5byA5Y+RPC9BPjwvTEk+DQogIDxM +SSANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMHB4 +IDhweDsgUEFERElORy1MRUZUOiA5cHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3Nk +bmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWM1LmdpZik7IFBBRERJTkctQk9UVE9NOiAw +cHg7IE1BUkdJTjogMHB4OyBQQURESU5HLVRPUDogMHB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5p +dGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgc3R5bGU9IkNPTE9SOiByZ2Io +MCw1MSwyMDQpOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBocmVmPSJodHRwOi8vei5jc2Ru +Lm5ldC9nbWNsaWNrLnBocD9iYW5uZXJpZD01MjEyJmFtcDt6b25laWQ9NDE3JmFtcDtzb3VyY2U9 +JmFtcDtkZXN0PWh0dHAlM0ElMkYlMkZ3d3cubGFtcGJyb3RoZXIubmV0JTJGaW50cm8uaHRtbCIg +DQogIHRhcmdldD1fYmxhbms+UEhQ5a2m5Lmg77yM5YWI5bCx5Lia77yM5ZCO5YiG5pyf6L+Y5qy+ +PC9BPjwvTEk+DQogIDxMSSANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VO +RC1QT1NJVElPTjogMHB4IDhweDsgUEFERElORy1MRUZUOiA5cHg7IEJBQ0tHUk9VTkQtSU1BR0U6 +IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWM1LmdpZik7IFBB +RERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBQQURESU5HLVRPUDogMHB4OyBiYWNrZ3Jv +dW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgc3R5 +bGU9IkNPTE9SOiByZ2IoMCw1MSwyMDQpOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBocmVm +PSJodHRwOi8vei5jc2RuLm5ldC9nbWNsaWNrLnBocD9iYW5uZXJpZD01NDA5JmFtcDt6b25laWQ9 +NDE4JmFtcDtzb3VyY2U9JmFtcDtkZXN0PWh0dHAlM0ElMkYlMkZnLmNzZG4ubmV0JTJGNTE2MzUw +MCIgDQogIHRhcmdldD1fYmxhbms+5rC05rOi5pWI5bqUQW5kcm9pZOa6kOeggTwvQT48L0xJPg0K +ICA8TEkgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046 +IDBweCA4cHg7IFBBRERJTkctTEVGVDogOXB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDov +L2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljNS5naWYpOyBQQURESU5HLUJPVFRP +TTogMHB4OyBNQVJHSU46IDBweDsgUEFERElORy1UT1A6IDBweDsgYmFja2dyb3VuZC1vcmlnaW46 +IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHN0eWxlPSJDT0xPUjog +cmdiKDAsNTEsMjA0KTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgaHJlZj0iaHR0cDovL3ou +Y3Nkbi5uZXQvZ21jbGljay5waHA/YmFubmVyaWQ9NTM3NyZhbXA7em9uZWlkPTQxOSZhbXA7c291 +cmNlPSZhbXA7ZGVzdD0raHR0cCUzQSUyRiUyRmJhbWJvb2suc2RvLmNvbSUyRmluZGV4LmFzcHgl +M0ZhZGlkJTNEMTAxMCUyNnJlZGlyZWN1cmwlM0RodHRwJTNBJTJGJTJGZXZlbnRzLmNzZG4ubmV0 +JTJGQkFNQk9PSyUyRmluZGV4Lmh0bSsiIA0KICB0YXJnZXQ9X2JsYW5rPjYw5LiH5aWW6YeRVlPn +m5vlpKfnqIvluo/ovr7kurrotZs8L0E+PC9MST4NCiAgPExJIA0KICBzdHlsZT0iUEFERElORy1S +SUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAwcHggOHB4OyBQQURESU5HLUxFRlQ6IDlw +eDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3Nk +bmluZGV4X3BpYzUuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IFBBRERJ +TkctVE9QOiAwcHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6 +IGluaXRpYWwiPjxBIA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDUxLDIwNCk7IFRFWFQtREVDT1JB +VElPTjogbm9uZSIgDQogIGhyZWY9Imh0dHA6Ly96LmNzZG4ubmV0L2dtY2xpY2sucGhwP2Jhbm5l +cmlkPTQ3NzgmYW1wO3pvbmVpZD00MjAmYW1wO3NvdXJjZT0mYW1wO2Rlc3Q9aHR0cCUzQSUyRiUy +Rnd3dy5pdGNhc3QuY24lMkZpdGNhc3Rfc3RhdGljJTJGM0cuaHRtbCIgDQogIHRhcmdldD1fYmxh +bms+OOWkqei9rOWeizNH77yM5pyI6JaqNEvlj5g4SzwvQT48L0xJPjwvVUw+PC9ESVY+DQo8RElW +IGNsYXNzPWJhbm5lcl90b3AzIA0Kc3R5bGU9IkZMT0FUOiBsZWZ0OyBNQVJHSU46IDJweCAwcHg7 +IFdJRFRIOiA5NjBweDsgVEVYVC1BTElHTjogbGVmdCI+DQo8VUwgDQpzdHlsZT0iUEFERElORy1S +SUdIVDogMHB4OyBQQURESU5HLUxFRlQ6IDBweDsgRkxPQVQ6IGxlZnQ7IFBBRERJTkctQk9UVE9N +OiAwcHg7IE1BUkdJTjogMHB4OyBXSURUSDogOTYwcHg7IFBBRERJTkctVE9QOiAwcHg7IExJU1Qt +U1RZTEUtVFlQRTogbm9uZTsgSEVJR0hUOiA2MHB4Ij4NCiAgPExJIGNsYXNzPWxlZnQgDQogIHN0 +eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IERJU1BMQVk6IGlubGluZTsgUEFERElORy1MRUZUOiAw +cHg7IEZMT0FUOiBsZWZ0OyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweCAxMHB4IDBw +eCAwcHg7IFBBRERJTkctVE9QOiAwcHgiPjxBIA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7 +IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIGhyZWY9Imh0dHA6Ly96LmNzZG4ubmV0L2dtY2xp +Y2sucGhwP2Jhbm5lcmlkPTUzNjYmYW1wO3pvbmVpZD00MDUmYW1wO3NvdXJjZT0mYW1wO2Rlc3Q9 +aHR0cCUzQSUyRiUyRnd3dy5vcGhvbmVzZG4uY29tJTJGcHJvamVjdCUyRmluZGV4IiANCiAgdGFy +Z2V0PV9ibGFuaz48SU1HIHRpdGxlPSIiIA0KICBzdHlsZT0iQk9SREVSLVRPUC1XSURUSDogMHB4 +OyBCT1JERVItTEVGVC1XSURUSDogMHB4OyBCT1JERVItQk9UVE9NLVdJRFRIOiAwcHg7IEJPUkRF +Ui1SSUdIVC1XSURUSDogMHB4IiANCiAgaGVpZ2h0PTYwIGFsdD0iIiANCiAgc3JjPSJodHRwOi8v +aW5mby1kYXRhYmFzZS5jc2RuLm5ldC9VcGxvYWQvMjAxMC0xMS0xNy80NzVfNjBfb3Bob25lei5q +cGciIA0KICB3aWR0aD00NzUgYm9yZGVyPTA+PC9BPg0KICA8RElWIGlkPWJlYWNvbl81MzY2IA0K +ICBzdHlsZT0iTEVGVDogMHB4OyBWSVNJQklMSVRZOiBoaWRkZW47IFBPU0lUSU9OOiBhYnNvbHV0 +ZTsgVE9QOiAwcHgiPjxJTUcgDQogIHN0eWxlPSJCT1JERVItVE9QLVdJRFRIOiAwcHg7IEJPUkRF +Ui1MRUZULVdJRFRIOiAwcHg7IEJPUkRFUi1CT1RUT00tV0lEVEg6IDBweDsgV0lEVEg6IDBweDsg +SEVJR0hUOiAwcHg7IEJPUkRFUi1SSUdIVC1XSURUSDogMHB4IiANCiAgaGVpZ2h0PTAgYWx0PSIi +IA0KICBzcmM9Imh0dHA6Ly96LmNzZG4ubmV0L2dtbG9nLnBocD9iYW5uZXJpZD01MzY2JmFtcDtj +bGllbnRpZD0xNjgzJmFtcDt6Zj0mYW1wO3pvbmVpZD00MDUmYW1wO3NvdXJjZT0mYW1wO2Jsb2Nr +PTAmYW1wO2NhcHBpbmc9MCZhbXA7Y2I9ZTgyZDExNTFjYjFhMmUwY2NmYTBmMmVlYjY2YTUwOWUi +IA0KICB3aWR0aD0wPjwvRElWPjwvTEk+DQogIDxMSSBjbGFzcz1yaWdodCANCiAgc3R5bGU9IlBB +RERJTkctUklHSFQ6IDBweDsgUEFERElORy1MRUZUOiAwcHg7IEZMT0FUOiByaWdodDsgUEFERElO +Ry1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IFdJRFRIOiA0NzVweDsgUEFERElORy1UT1A6IDBw +eCI+PEEgDQogIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25l +IiANCiAgaHJlZj0iaHR0cDovL3ouY3Nkbi5uZXQvZ21jbGljay5waHA/YmFubmVyaWQ9NDczOCZh +bXA7em9uZWlkPTQwNiZhbXA7c291cmNlPSZhbXA7ZGVzdD1odHRwJTNBJTJGJTJGam9icy5jbmNj +LmNuJTJGIiANCiAgdGFyZ2V0PV9ibGFuaz48SU1HIHRpdGxlPSIiIA0KICBzdHlsZT0iQk9SREVS +LVRPUC1XSURUSDogMHB4OyBCT1JERVItTEVGVC1XSURUSDogMHB4OyBCT1JERVItQk9UVE9NLVdJ +RFRIOiAwcHg7IEJPUkRFUi1SSUdIVC1XSURUSDogMHB4IiANCiAgaGVpZ2h0PTYwIGFsdD0iIiBz +cmM9Imh0dHA6Ly96aS5jc2RuLm5ldC9yZW40NzUtNjAuZ2lmIiB3aWR0aD00NzUgDQpib3JkZXI9 +MD48L0E+DQogIDxESVYgaWQ9YmVhY29uXzQ3MzggDQogIHN0eWxlPSJMRUZUOiAwcHg7IFZJU0lC +SUxJVFk6IGhpZGRlbjsgUE9TSVRJT046IGFic29sdXRlOyBUT1A6IDBweCI+PElNRyANCiAgc3R5 +bGU9IkJPUkRFUi1UT1AtV0lEVEg6IDBweDsgQk9SREVSLUxFRlQtV0lEVEg6IDBweDsgQk9SREVS +LUJPVFRPTS1XSURUSDogMHB4OyBXSURUSDogMHB4OyBIRUlHSFQ6IDBweDsgQk9SREVSLVJJR0hU +LVdJRFRIOiAwcHgiIA0KICBoZWlnaHQ9MCBhbHQ9IiIgDQogIHNyYz0iaHR0cDovL3ouY3Nkbi5u +ZXQvZ21sb2cucGhwP2Jhbm5lcmlkPTQ3MzgmYW1wO2NsaWVudGlkPTE0NjcmYW1wO3pmPSZhbXA7 +em9uZWlkPTQwNiZhbXA7c291cmNlPSZhbXA7YmxvY2s9MCZhbXA7Y2FwcGluZz0wJmFtcDtjYj0z +NGIxNzMxYmEzODhmMjQ2OTE1NTk1MzhiNDlmMjIyMCIgDQogIHdpZHRoPTA+PC9ESVY+PC9MST48 +L1VMPjwvRElWPg0KPERJViBjbGFzcz1wYWdlY29uX2xheWVyMSANCnN0eWxlPSJGTE9BVDogbGVm +dDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3Nk +bmluZGV4X3BpYzYuZ2lmKTsgV0lEVEg6IDk2MHB4OyBQT1NJVElPTjogcmVsYXRpdmU7IGJhY2tn +cm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPg0KPERJViBj +bGFzcz0icGFnZWNvbl9sYXllcjFfbGVmdCBoc2xpY2UiIGlkPWNzZG5oZWFkbGluZSANCnN0eWxl +PSJCT1JERVItVE9QOiByZ2IoMTc1LDE3NSwxNzUpIDFweCBzb2xpZDsgRElTUExBWTogaW5saW5l +OyBGTE9BVDogbGVmdDsgTUFSR0lOOiAwcHggMHB4IDBweCAxcHg7IFdJRFRIOiA1MzVweDsgVEVY +VC1BTElHTjogbGVmdCI+PFNQQU4gDQpzdHlsZT0iRElTUExBWTogYmxvY2s7IEJBQ0tHUk9VTkQt +SU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWM3Lmdp +Zik7IFdJRFRIOiA1MzVweDsgUE9TSVRJT046IHJlbGF0aXZlOyBIRUlHSFQ6IDI2cHg7IGJhY2tn +cm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxDSVRFIA0K +c3R5bGU9IlBBRERJTkctUklHSFQ6IDVweDsgRElTUExBWTogaW5saW5lOyBQQURESU5HLUxFRlQ6 +IDVweDsgRkxPQVQ6IGxlZnQ7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogM3B4IDBweCAw +cHggNXB4OyBDT0xPUjogcmdiKDI1NSwyNTUsMjU1KTsgTElORS1IRUlHSFQ6IDE5cHg7IFBBRERJ +TkctVE9QOiAwcHg7IEZPTlQtU1RZTEU6IG5vcm1hbDsgQkFDS0dST1VORC1DT0xPUjogcmdiKDIx +OCwzNywyOCk7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGlu +aXRpYWwiPuS7iuaXpeWktOadoTwvQ0lURT48REZOIA0Kc3R5bGU9IkZMT0FUOiByaWdodDsgTUFS +R0lOOiAwcHg7IEZPTlQtU1RZTEU6IG5vcm1hbCI+PC9ERk4+PC9TUEFOPg0KPERJViBjbGFzcz0i +bGF5ZXIxX2NvbnRlbnRzIGVudHJ5LWNvbnRlbnQiIA0Kc3R5bGU9IlBBRERJTkctUklHSFQ6IDE1 +cHg7IFBBRERJTkctTEVGVDogMTVweDsgUEFERElORy1CT1RUT006IDBweDsgUEFERElORy1UT1A6 +IDEwcHgiPg0KPEgxIGNsYXNzPXR4dF9ibGFjayANCnN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7 +IFBBRERJTkctTEVGVDogMHB4OyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDdweCAwcHg7 +IEZPTlQ6IGJvbGQgMTdweCAnTWljcm9zb2Z0IFlhaGVpJywgc2Fucy1zZXJpZjsgQ09MT1I6IHJn +YigwLDAsMCk7IFBBRERJTkctVE9QOiAwcHgiPjxBIA0KdGl0bGU9IkZhY2Vib29rIENFT+W9k+mA +iTIwMTDjgIrml7bku6PjgIvlubTluqbpo47kupHkurrniakiIA0Kc3R5bGU9IkNPTE9SOiByZ2Io +MCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlz +LDcxKTsgDQpocmVmPSJodHRwOi8vbmV3cy5jc2RuLm5ldC9hLzIwMTAxMjE2LzI4Mzk4Mi5odG1s +IiB0YXJnZXQ9X2JsYW5rPkZhY2Vib29rIA0KQ0VP5b2T6YCJMjAxMOOAiuaXtuS7o+OAi+W5tOW6 +pumjjuS6keS6uueJqTwvQT48L0gxPg0KPFAgY2xhc3M9ImhvdGxpbmsgdHh0X2JsdWUiIA0Kc3R5 +bGU9IlBBRERJTkctUklHSFQ6IDBweDsgUEFERElORy1MRUZUOiAwcHg7IFBBRERJTkctQk9UVE9N +OiAwcHg7IE1BUkdJTjogMnB4IDBweCAwcHg7IENPTE9SOiByZ2IoNTEsNTEsNTEpOyBMSU5FLUhF +SUdIVDogMjFweDsgUEFERElORy1UT1A6IDBweCI+PEEgDQpzdHlsZT0iUEFERElORy1SSUdIVDog +M3B4OyBQQURESU5HLUxFRlQ6IDBweDsgUEFERElORy1CT1RUT006IDBweDsgQ09MT1I6IHJnYigx +LDk1LDE4Mik7IFBBRERJTkctVE9QOiAwcHg7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQpvbmNs +aWNrPUxvZ0NsaWNrQ291bnQodGhpcyw3MSk7IA0KaHJlZj0iaHR0cDovL25ld3MuY3Nkbi5uZXQv +YS8yMDEwMTIxNS8yODM2ODQuaHRtbCIgDQp0YXJnZXQ9X2JsYW5rPltGYWNlYm9va+S8sOWAvDPk +uKrmnIjlop7plb83NyUg5Lyw5YC86L6+NDMw5Lq/576O5YWDXTwvQT48QSANCnN0eWxlPSJQQURE +SU5HLVJJR0hUOiAzcHg7IFBBRERJTkctTEVGVDogMHB4OyBQQURESU5HLUJPVFRPTTogMHB4OyBD +T0xPUjogcmdiKDEsOTUsMTgyKTsgUEFERElORy1UT1A6IDBweDsgVEVYVC1ERUNPUkFUSU9OOiBu +b25lIiANCm9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDcxKTsgDQpocmVmPSJodHRwOi8vbmV3 +cy5jc2RuLm5ldC9hLzIwMTAxMjA3LzI4MzExNy5odG1sIiANCnRhcmdldD1fYmxhbms+W+avj+aX +pemCruaKpe+8muiwt+atjOWSjEZhY2Vib29r55qE5oiY5LqJXTwvQT48QlI+PEEgDQpzdHlsZT0i +UEFERElORy1SSUdIVDogM3B4OyBQQURESU5HLUxFRlQ6IDBweDsgUEFERElORy1CT1RUT006IDBw +eDsgQ09MT1I6IHJnYigxLDk1LDE4Mik7IFBBRERJTkctVE9QOiAwcHg7IFRFWFQtREVDT1JBVElP +Tjogbm9uZSIgDQpvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw3MSk7IA0KaHJlZj0iaHR0cDov +L2Nsb3VkLmNzZG4ubmV0L2EvMjAxMDEyMDkvMjgzMjg5Lmh0bWwiIA0KdGFyZ2V0PV9ibGFuaz5b +5pe25Luj5ZGo5YiK77ya57u05Z+66Kej5a+G5bCG6LWi5b6X5L+h5oGv5oiY5LqJXTwvQT48QSAN +CnN0eWxlPSJQQURESU5HLVJJR0hUOiAzcHg7IFBBRERJTkctTEVGVDogMHB4OyBQQURESU5HLUJP +VFRPTTogMHB4OyBDT0xPUjogcmdiKDEsOTUsMTgyKTsgUEFERElORy1UT1A6IDBweDsgVEVYVC1E +RUNPUkFUSU9OOiBub25lIiANCm9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDcxKTsgDQpocmVm +PSJodHRwOi8vbW9iaWxlLmNzZG4ubmV0L24vMjAxMDEyMTMvMjgzNDc4Lmh0bWwiIA0KdGFyZ2V0 +PV9ibGFuaz5b44CK5pe25Luj5ZGo5YiK44CL6K+E5Ye6MjAxMOW5tOWNgeWkp2lQaG9uZeW6lOeU +qF08L0E+PC9QPg0KPEgxIGNsYXNzPXR4dF9ibGFjayANCnN0eWxlPSJQQURESU5HLVJJR0hUOiAw +cHg7IFBBRERJTkctTEVGVDogMHB4OyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDdweCAw +cHg7IEZPTlQ6IGJvbGQgMTdweCAnTWljcm9zb2Z0IFlhaGVpJywgc2Fucy1zZXJpZjsgQ09MT1I6 +IHJnYigwLDAsMCk7IFBBRERJTkctVE9QOiAwcHgiPjxBIA0KdGl0bGU9W+WNmuWuol3pq5jmlYjl +rZjlgqjmioDmnK/noJTnqbYgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJ +T046IG5vbmUiIA0Kb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsNzEpOyANCmhyZWY9Imh0dHA6 +Ly9ibG9nLmNzZG4ubmV0L2xpdWJlbi9hcmNoaXZlLzIwMTAvMTIvMDgvNjA2NDA0NS5hc3B4IiAN +CnRhcmdldD1fYmxhbms+W+WNmuWuol3pq5jmlYjlrZjlgqjmioDmnK/noJTnqbY8L0E+PC9IMT4N +CjxQIGNsYXNzPSJob3RsaW5rIHR4dF9ibHVlIiANCnN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7 +IFBBRERJTkctTEVGVDogMHB4OyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDJweCAwcHgg +MHB4OyBDT0xPUjogcmdiKDUxLDUxLDUxKTsgTElORS1IRUlHSFQ6IDIxcHg7IFBBRERJTkctVE9Q +OiAwcHgiPjxBIA0Kc3R5bGU9IlBBRERJTkctUklHSFQ6IDNweDsgUEFERElORy1MRUZUOiAwcHg7 +IFBBRERJTkctQk9UVE9NOiAwcHg7IENPTE9SOiByZ2IoMSw5NSwxODIpOyBQQURESU5HLVRPUDog +MHB4OyBURVhULURFQ09SQVRJT046IG5vbmUiIA0Kb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMs +NzEpOyANCmhyZWY9Imh0dHA6Ly9ibG9nLmNzZG4ubmV0L1NtYXJ0VG9ueS9hcmNoaXZlLzIwMTAv +MDkvMDkvNTg3NDQ4NS5hc3B4IiANCnRhcmdldD1fYmxhbms+W+mrmOW5tuWPkemrmOa1gemHj+e9 +keermeaetuaehF08L0E+PEEgDQpzdHlsZT0iUEFERElORy1SSUdIVDogM3B4OyBQQURESU5HLUxF +RlQ6IDBweDsgUEFERElORy1CT1RUT006IDBweDsgQ09MT1I6IHJnYigxLDk1LDE4Mik7IFBBRERJ +TkctVE9QOiAwcHg7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQpvbmNsaWNrPUxvZ0NsaWNrQ291 +bnQodGhpcyw3MSk7IA0KaHJlZj0iaHR0cDovL2Jsb2cuY3Nkbi5uZXQvYmFvcWlhbmd3YW5nL2Fy +Y2hpdmUvMjAxMC8wNy8wOC81NzIwNzMwLmFzcHgiIA0KdGFyZ2V0PV9ibGFuaz5b5YWz5LqO5pWw +5o2u5oyW5o6Y5YWz6IGU6KeE5YiZ55qET3JhY2xl5a6e546wXTwvQT48L1A+DQo8UCBjbGFzcz1y +ZXZpZXcgDQpzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBQQURESU5HLUxFRlQ6IDBweDsgRk9O +VC1TSVpFOiAxMnB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3 +L2ltYWdlcy9jc2RuaW5kZXhfcGljMzIuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lO +OiA1cHggMHB4OyBDT0xPUjogcmdiKDUxLDUxLDUxKTsgTElORS1IRUlHSFQ6IDIzcHg7IFBBRERJ +TkctVE9QOiAwcHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6 +IGluaXRpYWwiPuW+gOacn+WktOadoe+8mjxBIA0KdGl0bGU9IkdtYWls5LmL54i277yaQ2hyb21l +IE9T5p2l5pel5peg5aSaIiANCnN0eWxlPSJQQURESU5HLVJJR0hUOiAzcHg7IFBBRERJTkctTEVG +VDogM3B4OyBQQURESU5HLUJPVFRPTTogMHB4OyBDT0xPUjogcmdiKDAsMCwwKTsgUEFERElORy1U +T1A6IDBweDsgVEVYVC1ERUNPUkFUSU9OOiB1bmRlcmxpbmUiIA0Kb25jbGljaz1Mb2dDbGlja0Nv +dW50KHRoaXMsNzEpOyANCmhyZWY9Imh0dHA6Ly9uZXdzLmNzZG4ubmV0L2EvMjAxMDEyMTUvMjgz +NjY2Lmh0bWwiIHRhcmdldD1fYmxhbms+R21haWzkuYvniLbvvJpDaHJvbWUgDQpPU+adpeaXpeaX +oOWkmjwvQT4mbmJzcDsmbmJzcDsmbmJzcDs8U1BBTiBjbGFzcz1BcHBsZS1jb252ZXJ0ZWQtc3Bh +Y2U+Jm5ic3A7PC9TUEFOPjxBIA0KdGl0bGU95aSp57+85pWZ5L2g56e75Yqo5bqU55So6JCl5Yip +5LmL6YGTIA0Kc3R5bGU9IlBBRERJTkctUklHSFQ6IDNweDsgUEFERElORy1MRUZUOiAzcHg7IFBB +RERJTkctQk9UVE9NOiAwcHg7IENPTE9SOiByZ2IoMCwwLDApOyBQQURESU5HLVRPUDogMHB4OyBU +RVhULURFQ09SQVRJT046IHVuZGVybGluZSIgDQpvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw3 +MSk7IGhyZWY9Imh0dHA6Ly9nLmNzZG4ubmV0LzUxNjY3NTYiIA0KdGFyZ2V0PV9ibGFuaz7lpKnn +v7zmlZnkvaDnp7vliqjlupTnlKjokKXliKnkuYvpgZM8L0E+PC9QPjwvRElWPjwvRElWPg0KPERJ +ViBjbGFzcz1wYWdlY29uX2xheWVyMV9yaWcgDQpzdHlsZT0iQk9SREVSLVRPUDogcmdiKDIwNCwy +MDQsMjAyKSAxcHggc29saWQ7IERJU1BMQVk6IGlubGluZTsgRkxPQVQ6IHJpZ2h0OyBNQVJHSU46 +IDBweCAxcHggMHB4IDBweDsgV0lEVEg6IDQxN3B4Ij4NCjxPQkpFQ1QgDQpjb2RlQmFzZT1odHRw +Oi8vZnBkb3dubG9hZC5tYWNyb21lZGlhLmNvbS9wdWIvc2hvY2t3YXZlL2NhYnMvZmxhc2gvc3dm +bGFzaC5jYWJ2ZXJzaW9uPTYsMCwwLDAgDQpoZWlnaHQ9MjE1IHdpZHRoPTQxNyBjbGFzc2lkPWNs +c2lkOmQyN2NkYjZlLWFlNmQtMTFjZi05NmI4LTQ0NDU1MzU0MDAwMD4NCjxlbWJlZCB3bW9kZT0i +dHJhbnNwYXJlbnQiIHNyYz0iaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9mb2N1cy5zd2Yi +IA0KZmxhc2h2YXJzPSJwaWNzPWh0dHA6Ly9pbWFnZXMuY3Nkbi5uZXQvMjAxMDEyMTMvNDE1XzIx +NV85Y2l0eV8xMjEzbi5qcGd8aHR0cDovL2ltYWdlcy5jc2RuLm5ldC8yMDEwMTIxMy80MTVfMjE1 +X2dvbmdqLmpwZ3xodHRwOi8vaW1hZ2VzLmNzZG4ubmV0LzIwMTAxMjAzLzQxNV8yMTVfZnguanBn +fGh0dHA6Ly9pbWFnZXMuY3Nkbi5uZXQvMjAxMDEyMTQvaG1fNDE1XzIxNV9zZDEyMTQuanBnfGh0 +dHA6Ly9pbWFnZXMuY3Nkbi5uZXQvMjAxMDEyMDMvNDE1XzIxNV8xMTAzLmpwZ3xodHRwOi8vaW1h +Z2VzLmNzZG4ubmV0LzIwMTAxMjEzLzQxNV8yMTVfYmJiYnMuanBnJmFtcDtsaW5rcz1odHRwOi8v +Zy5jc2RuLm5ldC81MTY2OTE0fGh0dHA6Ly9nLmNzZG4ubmV0LzUxNjQyNjB8aHR0cDovL2cuY3Nk +bi5uZXQvNTE2NTkxMXxodHRwOi8vZy5jc2RuLm5ldC81MTY2NDYxfGh0dHA6Ly9nLmNzZG4ubmV0 +LzUxNjUzOTZ8aHR0cDovL2cuY3Nkbi5uZXQvNTE2NzEzMCZhbXA7dGV4dHM9Q1NETuWbvueJh+aW +sOmXu3xDU0RO5Zu+54mH5bm/5ZGKfENTRE7lm77niYflub/lkYp8Q1NETuWbvueJh+W5v+WRinxD +U0RO5Zu+54mH5bm/5ZGKfENTRE7lm77niYflub/lkYomYW1wO3BpY193aWR0aD00MTcmYW1wO3Bp +Y19oZWlnaHQ9MjE1JmFtcDtzaG93X3RleHQ9MCZhbXA7dHh0Y29sb3I9MDAwMDAwJmFtcDtiZ2Nv +bG9yPUZGRkZGRiZhbXA7YnV0dG9uX3Bvcz00JmFtcDtzdG9wX3RpbWU9NDAwMCIgDQpxdWFsaXR5 +PSJoaWdoIiB3aWR0aD0iNDE3IiBoZWlnaHQ9IjIxNSIgYWxsb3dzY3JpcHRhY2Nlc3M9InNhbWVE +b21haW4iIA0KdHlwZT0iYXBwbGljYXRpb24veC1zaG9ja3dhdmUtZmxhc2giIA0KcGx1Z2luc3Bh +Z2U9Imh0dHA6Ly93d3cubWFjcm9tZWRpYS5jb20vZ28vZ2V0Zmxhc2hwbGF5ZXIiPjwvT0JKRUNU +PjwvRElWPjwvRElWPg0KPERJViBjbGFzcz1wYWdlY29uX2xheWVyMWJ0bSANCnN0eWxlPSJDTEVB +UjogYm90aDsgT1ZFUkZMT1ctWTogaGlkZGVuOyBGT05ULVNJWkU6IDFweDsgQkFDS0dST1VORC1J +TUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzZfYnRt +LmdpZik7IE9WRVJGTE9XLVg6IGhpZGRlbjsgSEVJR0hUOiA1cHg7IGJhY2tncm91bmQtb3JpZ2lu +OiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjwvRElWPg0KPERJViBjbGFzcz1w +YWdlY29uX2xheWVyMiANCnN0eWxlPSJGTE9BVDogbGVmdDsgQkFDS0dST1VORC1JTUFHRTogdXJs +KGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzMzLmdpZik7IE1BUkdJ +TjogM3B4IDBweCAwcHg7IFdJRFRIOiA5NjBweDsgUE9TSVRJT046IHJlbGF0aXZlOyBURVhULUFM +SUdOOiBsZWZ0OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBp +bml0aWFsIj4NCjxESVYgY2xhc3M9cGFnZV8wOXNpZGViYXJ3cmFwIA0Kc3R5bGU9IlBBRERJTkct +UklHSFQ6IDBweDsgQk9SREVSLVRPUDogcmdiKDIwNCwyMDQsMjA0KSAxcHggc29saWQ7IERJU1BM +QVk6IGlubGluZTsgUEFERElORy1MRUZUOiAwcHg7IEZMT0FUOiByaWdodDsgUEFERElORy1CT1RU +T006IDZweDsgTUFSR0lOOiAwcHggMXB4IDBweCAwcHg7IFdJRFRIOiAyMDhweDsgUEFERElORy1U +T1A6IDBweDsgVEVYVC1BTElHTjogbGVmdCI+DQo8RElWIGNsYXNzPXNpZGViYXJfY29uIA0Kc3R5 +bGU9IkRJU1BMQVk6IGlubGluZTsgRkxPQVQ6IGxlZnQ7IE1BUkdJTjogNnB4IDNweCAycHg7IFdJ +RFRIOiAyMDJweCI+DQo8SDQgY2xhc3M9dHh0XzEyIGlkPW1lbnUzIA0Kc3R5bGU9IlBBRERJTkct +UklHSFQ6IDBweDsgUEFERElORy1MRUZUOiAzcHg7IEZPTlQtU0laRTogMTJweDsgUEFERElORy1C +T1RUT006IDVweDsgTUFSR0lOOiAwcHg7IFBBRERJTkctVE9QOiAwcHg7IEJPUkRFUi1CT1RUT006 +IHJnYigyMDQsMjA0LDIwNCkgMXB4IHNvbGlkOyBQT1NJVElPTjogcmVsYXRpdmUiPjxBIA0KY2xh +c3M9Y3VycmVudDEgb25tb3VzZW92ZXI9c2V0VGFiKDMsMCkgDQpzdHlsZT0iQ09MT1I6IHJnYigx +LDk1LDE4Mik7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgb25jbGljaz0icmV0dXJuIGZhbHNlIiAN +CmhyZWY9Imh0dHA6Ly93d3cuY3Nkbi5uZXQvIyI+5pyA5paw5rS75YqoPC9BPjxTUEFOIA0KY2xh +c3M9QXBwbGUtY29udmVydGVkLXNwYWNlPiZuYnNwOzwvU1BBTj58PFNQQU4gDQpjbGFzcz1BcHBs +ZS1jb252ZXJ0ZWQtc3BhY2U+Jm5ic3A7PC9TUEFOPjxBIG9ubW91c2VvdmVyPXNldFRhYigzLDEp +IA0Kc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIG9uY2xp +Y2s9InJldHVybiBmYWxzZSIgDQpocmVmPSJodHRwOi8vd3d3LmNzZG4ubmV0LyMiPueoi+W6j+WR +mOadguW/lzwvQT48L0g0Pg0KPERJViBpZD1tYWluMz4NCjxESVY+DQo8REwgY2xhc3M9c2Vzc2lv +bl9zdHlsZSANCnN0eWxlPSJQQURESU5HLVJJR0hUOiAzcHg7IFBBRERJTkctTEVGVDogM3B4OyBG +TE9BVDogbGVmdDsgUEFERElORy1CT1RUT006IDVweDsgTUFSR0lOOiAycHggMHB4IDBweDsgV0lE +VEg6IDE5NnB4OyBQQURESU5HLVRPUDogMTBweDsgQk9SREVSLUJPVFRPTTogcmdiKDIwNCwyMDQs +MjA0KSAxcHggc29saWQ7IEJBQ0tHUk9VTkQtQ09MT1I6IHJnYigyNTUsMjU1LDI1NSk7IGJhY2tn +cm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPg0KICA8RFQg +Y2xhc3M9Y2xlYXJkaXYgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IFBBRERJTkctTEVG +VDogMHB4OyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweCAwcHggOXB4OyBQQURESU5H +LVRPUDogMHB4Ij48QSANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJ +T046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw3Nyk7IGhyZWY9Imh0dHA6 +Ly9nLmNzZG4ubmV0LzUxNjY5MTgiIA0KICB0YXJnZXQ9X2JsYW5rPjxJTUcgdGl0bGU9IiIgDQog +IHN0eWxlPSJCT1JERVItUklHSFQ6IHJnYigyMDQsMjA0LDIwNCkgMXB4IHNvbGlkOyBQQURESU5H +LVJJR0hUOiAycHg7IEJPUkRFUi1UT1A6IHJnYigyMDQsMjA0LDIwNCkgMXB4IHNvbGlkOyBQQURE +SU5HLUxFRlQ6IDJweDsgRkxPQVQ6IGxlZnQ7IFBBRERJTkctQk9UVE9NOiAycHg7IE1BUkdJTjog +MHB4IDZweCAwcHggMHB4OyBCT1JERVItTEVGVDogcmdiKDIwNCwyMDQsMjA0KSAxcHggc29saWQ7 +IFBBRERJTkctVE9QOiAycHg7IEJPUkRFUi1CT1RUT006IHJnYigyMDQsMjA0LDIwNCkgMXB4IHNv +bGlkIiANCiAgaGVpZ2h0PTY4IGFsdD0iIiBzcmM9Imh0dHA6Ly9pbWFnZXMuY3Nkbi5uZXQvMjAx +MDEyMTAvNTZfNzJfdHkuanBnIiANCiAgd2lkdGg9NTI+PC9BPuiHqueUsSDliIbkuqsg5YWx6LWi +IOW8gOWIm+enu+WKqOS6kuiBlOe9keacquadpe+8jOWkqee/vOaVmeS9oOenu+WKqOW6lOeUqOiQ +peWIqeS5i+mBk++8gTEy5pyIMTfml6XvvIzljqbpl6jnq5njgII8L0RUPg0KICA8REQgDQogIHN0 +eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDJweCA3cHg7IFBB +RERJTkctTEVGVDogMTJweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNu +L3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzUuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFS +R0lOOiAwcHg7IExJTkUtSEVJR0hUOiAxOXB4OyBQQURESU5HLVRPUDogMHB4OyBiYWNrZ3JvdW5k +LW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgdGl0bGU9 +T3BlbkZlaW505ri45oiP5byA5Y+R6ICF576k6Iux5LyaIHN0eWxlPSJDT0xPUjogcmdiKDAsMCww +KTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMs +NzcpOyBocmVmPSJodHRwOi8vZy5jc2RuLm5ldC81MTY2OTE1IiANCiAgdGFyZ2V0PV9ibGFuaz5P +cGVuRmVpbnTmuLjmiI/lvIDlj5HogIXnvqToi7HkvJo8L0E+PC9ERD4NCiAgPEREIA0KICBzdHls +ZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAycHggN3B4OyBQQURE +SU5HLUxFRlQ6IDEycHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93 +d3cvaW1hZ2VzL2NzZG5pbmRleF9waWM1LmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJ +TjogMHB4OyBMSU5FLUhFSUdIVDogMTlweDsgUEFERElORy1UT1A6IDBweDsgYmFja2dyb3VuZC1v +cmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxlPeOA +iueoi+W6j+WRmOOAi+WNgeW5tOiBlOaJi+ebm+Wkp+eJueaDoOa0u+WKqCBzdHlsZT0iQ09MT1I6 +IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tD +b3VudCh0aGlzLDc3KTsgaHJlZj0iaHR0cDovL2cuY3Nkbi5uZXQvNTE2NjQ2NCIgDQogIHRhcmdl +dD1fYmxhbms+44CK56iL5bqP5ZGY44CL5Y2B5bm06IGU5omL55ub5aSn54m55oOg5rS75YqoPC9B +PjwvREQ+DQogIDxERCANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1Q +T1NJVElPTjogMnB4IDdweDsgUEFERElORy1MRUZUOiAxMnB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1 +cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljNS5naWYpOyBQQURE +SU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweDsgTElORS1IRUlHSFQ6IDE5cHg7IFBBRERJTkct +VE9QOiAwcHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGlu +aXRpYWwiPjxBIA0KICB0aXRsZT3nrKzkuZ3ln47luILljYPkuIfnjrDph5HlvoHpm4bnsr7lk4Hm +uLjmiI/vvIEgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUi +IA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw3Nyk7IGhyZWY9Imh0dHA6Ly9nLmNzZG4u +bmV0LzUxNjY5MzIiIA0KICB0YXJnZXQ9X2JsYW5rPuesrOS5neWfjuW4guWNg+S4h+eOsOmHkeW+ +gembhueyvuWTgea4uOaIj++8gTwvQT48L0REPg0KICA8REQgDQogIHN0eWxlPSJQQURESU5HLVJJ +R0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDJweCA3cHg7IFBBRERJTkctTEVGVDogMTJw +eDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3Nk +bmluZGV4X3BpYzUuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IExJTkUt +SEVJR0hUOiAxOXB4OyBQQURESU5HLVRPUDogMHB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlh +bDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgdGl0bGU956ys5YWt5bGK56e75Yqo +5LqS6IGU572RVE9QNTDor4TpgIkgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09S +QVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw3Nyk7IGhyZWY9Imh0 +dHA6Ly9nLmNzZG4ubmV0LzUxNjU3NzYiIA0KICB0YXJnZXQ9X2JsYW5rPuesrOWFreWxiuenu+WK +qOS6kuiBlOe9kVRPUDUw6K+E6YCJPC9BPjwvREQ+DQogIDxERCANCiAgc3R5bGU9IlBBRERJTkct +UklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMnB4IDdweDsgUEFERElORy1MRUZUOiAx +MnB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9j +c2RuaW5kZXhfcGljNS5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweDsgTElO +RS1IRUlHSFQ6IDE5cHg7IFBBRERJTkctVE9QOiAwcHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0 +aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0aXRsZT3ml6Dnur/kupLogZTl +iJvkuJrlrp7miJjorrLluqfCt+WMl+S6rCBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQt +REVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDc3KTsgaHJl +Zj0iaHR0cDovL2cuY3Nkbi5uZXQvNTE2NTIwMCIgDQogIHRhcmdldD1fYmxhbms+5peg57q/5LqS +6IGU5Yib5Lia5a6e5oiY6K6y5bqnwrfljJfkuqw8L0E+PC9ERD4NCiAgPEREIA0KICBzdHlsZT0i +UEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAycHggN3B4OyBQQURESU5H +LUxFRlQ6IDEycHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cv +aW1hZ2VzL2NzZG5pbmRleF9waWM1LmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjog +MHB4OyBMSU5FLUhFSUdIVDogMTlweDsgUEFERElORy1UT1A6IDBweDsgYmFja2dyb3VuZC1vcmln +aW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxlPeOAiuaV +j+aNt+W8gOWPkeKAlOa1i+ivleeuoeeQhuOAi+aPkOmXrui1ouWlliBzdHlsZT0iQ09MT1I6IHJn +YigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3Vu +dCh0aGlzLDc3KTsgDQogIGhyZWY9Imh0dHA6Ly9iYnMuY2hpbmF0ZXN0aW5nLmNuLzg2LTE4MDIx +NS5odG1sIiANCiAgdGFyZ2V0PV9ibGFuaz7jgIrmlY/mjbflvIDlj5HigJTmtYvor5XnrqHnkIbj +gIvmj5Dpl67otaLlpZY8L0E+PC9ERD4NCiAgPEREIGNsYXNzPW5vYmcgDQogIHN0eWxlPSJQQURE +SU5HLVJJR0hUOiAwcHg7IFBBRERJTkctTEVGVDogMnB4OyBCQUNLR1JPVU5ELUlNQUdFOiBub25l +OyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDZweCAwcHggMHB4OyBMSU5FLUhFSUdIVDog +MTlweDsgUEFERElORy1UT1A6IDBweDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tn +cm91bmQtY2xpcDogaW5pdGlhbCI+PC9ERD48L0RMPjwvRElWPjwvRElWPjwvRElWPg0KPERJViBj +bGFzcz1zaWRlYmFyX2NvbiANCnN0eWxlPSJESVNQTEFZOiBpbmxpbmU7IEZMT0FUOiBsZWZ0OyBN +QVJHSU46IDZweCAzcHggMnB4OyBXSURUSDogMjAycHgiPg0KPEg0IGNsYXNzPXR4dF8xMiANCnN0 +eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IFBBRERJTkctTEVGVDogM3B4OyBGT05ULVNJWkU6IDEy +cHg7IFBBRERJTkctQk9UVE9NOiA1cHg7IE1BUkdJTjogMHB4OyBQQURESU5HLVRPUDogMHB4OyBC +T1JERVItQk9UVE9NOiByZ2IoMjA0LDIwNCwyMDQpIDFweCBzb2xpZDsgUE9TSVRJT046IHJlbGF0 +aXZlIj48U1BBTiANCmNsYXNzPXR4dF9ncmF5IA0Kc3R5bGU9IkZPTlQtV0VJR0hUOiBub3JtYWw7 +IEZMT0FUOiByaWdodDsgQ09MT1I6IHJnYigxMDIsMTAyLDEwMikiPjwvU1BBTj7ng63pl6jmi5vo +gZjogYzkvY08L0g0Pg0KPERJViBjbGFzcz1yZWNydWl0ZnVsbCANCnN0eWxlPSJQQURESU5HLVJJ +R0hUOiAzcHg7IE9WRVJGTE9XLVk6IGhpZGRlbjsgUEFERElORy1MRUZUOiAzcHg7IEZMT0FUOiBs +ZWZ0OyBPVkVSRkxPVy1YOiBoaWRkZW47IFBBRERJTkctQk9UVE9NOiA1cHg7IE1BUkdJTjogMnB4 +IDBweCAwcHg7IFdJRFRIOiAxOTZweDsgUEFERElORy1UT1A6IDEwcHg7IEJPUkRFUi1CT1RUT006 +IHJnYigyMDQsMjA0LDIwNCkgMXB4IHNvbGlkOyBIRUlHSFQ6IDI1MnB4OyBCQUNLR1JPVU5ELUNP +TE9SOiByZ2IoMjU1LDI1NSwyNTUpOyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dy +b3VuZC1jbGlwOiBpbml0aWFsIj4NCjxETCBjbGFzcz1yZWNydWl0IGlkPW1hcnF1ZWVib3gwIA0K +c3R5bGU9IkJPUkRFUi1UT1AtV0lEVEg6IDBweDsgUEFERElORy1SSUdIVDogMHB4OyBPVkVSRkxP +Vy1ZOiBoaWRkZW47IFBBRERJTkctTEVGVDogMHB4OyBCT1JERVItTEVGVC1XSURUSDogMHB4OyBG +TE9BVDogbGVmdDsgT1ZFUkZMT1ctWDogaGlkZGVuOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJH +SU46IDBweDsgV0lEVEg6IDE5NnB4OyBQQURESU5HLVRPUDogMHB4OyBCT1JERVItQk9UVE9NOiBy +Z2IoMjA0LDIwNCwyMDQpIDBweCBzb2xpZDsgSEVJR0hUOiAyNTJweDsgQkFDS0dST1VORC1DT0xP +UjogcmdiKDI1NSwyNTUsMjU1KTsgQk9SREVSLVJJR0hULVdJRFRIOiAwcHg7IGJhY2tncm91bmQt +b3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPg0KICA8REQgDQogIHN0 +eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDJweCA3cHg7IE9W +RVJGTE9XLVk6IGhpZGRlbjsgUEFERElORy1MRUZUOiAxMnB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1 +cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljNS5naWYpOyBPVkVS +RkxPVy1YOiBoaWRkZW47IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4IDBweCA2cHg7 +IExJTkUtSEVJR0hUOiAxOXB4OyBQQURESU5HLVRPUDogMHB4OyBIRUlHSFQ6IDM2cHg7IGJhY2tn +cm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0 +aXRsZT0i44CQ54Ca5L+h56eR5oqA44CR6K+a6IGYIFdJTkRPV1MgQysrIFdJTkRPV1MgQyPkuK3p +q5jnuqflvIDlj5Hlt6XnqIvluIgiIA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQt +REVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDkzKTsgaHJl +Zj0iaHR0cDovL2cuY3Nkbi5uZXQvNTE2NzQ1NyIgDQogIHRhcmdldD1fYmxhbms+44CQ54Ca5L+h +56eR5oqA44CR6K+a6IGYIFdJTkRPV1MgQysrIFdJTkRPV1MgQyPkuK3pq5jnuqflvIDlj5Hlt6Xn +qIvluIg8L0E+PC9ERD4NCiAgPEREIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNL +R1JPVU5ELVBPU0lUSU9OOiAycHggN3B4OyBPVkVSRkxPVy1ZOiBoaWRkZW47IFBBRERJTkctTEVG +VDogMTJweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFn +ZXMvY3NkbmluZGV4X3BpYzUuZ2lmKTsgT1ZFUkZMT1ctWDogaGlkZGVuOyBQQURESU5HLUJPVFRP +TTogMHB4OyBNQVJHSU46IDBweCAwcHggNnB4OyBMSU5FLUhFSUdIVDogMTlweDsgUEFERElORy1U +T1A6IDBweDsgSEVJR0hUOiAzNnB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dy +b3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgdGl0bGU9IuOAkOmFt+aIkemfs+S5kOebkuOAkemr +mOiWquivmuiBmCDmv4Dmg4XniLHlpb3lt6XkvZzono3kuLrkuIDkvZMiIA0KICBzdHlsZT0iQ09M +T1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xp +Y2tDb3VudCh0aGlzLDkzKTsgaHJlZj0iaHR0cDovL2cuY3Nkbi5uZXQvNTE2NzQ1NCIgDQogIHRh +cmdldD1fYmxhbms+44CQ6YW35oiR6Z+z5LmQ55uS44CR6auY6Jaq6K+a6IGYIOa/gOaDheeIseWl +veW3peS9nOiejeS4uuS4gOS9kzwvQT48L0REPg0KICA8REQgDQogIHN0eWxlPSJQQURESU5HLVJJ +R0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDJweCA3cHg7IE9WRVJGTE9XLVk6IGhpZGRl +bjsgUEFERElORy1MRUZUOiAxMnB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5p +bWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljNS5naWYpOyBPVkVSRkxPVy1YOiBoaWRkZW47 +IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4IDBweCA2cHg7IExJTkUtSEVJR0hUOiAx +OXB4OyBQQURESU5HLVRPUDogMHB4OyBIRUlHSFQ6IDM2cHg7IGJhY2tncm91bmQtb3JpZ2luOiBp +bml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0aXRsZT3jgJDovr7lhoXp +m4blm6LjgJHpq5jolqror5rogZhKQVZB6K6y5biILuW1jOWFpeW8j+iusuW4iC4zR+iusuW4iC7m +ioDmnK/mgLvnm5Eu5YiG5YWs5Y+45oC757uP55CGIA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAs +MCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlz +LDkzKTsgaHJlZj0iaHR0cDovL2cuY3Nkbi5uZXQvNTE2NzQxNCIgDQogIHRhcmdldD1fYmxhbms+ +44CQ6L6+5YaF6ZuG5Zui44CR6auY6Jaq6K+a6IGYSkFWQeiusuW4iC7ltYzlhaXlvI/orrLluIgu +M0forrLluIgu5oqA5pyv5oC755uRLuWIhuWFrOWPuOaAu+e7j+eQhjwvQT48L0REPg0KICA8REQg +DQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDJweCA3 +cHg7IE9WRVJGTE9XLVk6IGhpZGRlbjsgUEFERElORy1MRUZUOiAxMnB4OyBCQUNLR1JPVU5ELUlN +QUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljNS5naWYp +OyBPVkVSRkxPVy1YOiBoaWRkZW47IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4IDBw +eCA2cHg7IExJTkUtSEVJR0hUOiAxOXB4OyBQQURESU5HLVRPUDogMHB4OyBIRUlHSFQ6IDM2cHg7 +IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxB +IA0KICB0aXRsZT3jgJDlpKnpmYXnvZHjgJHmgKXogZhKYXZh5bqU55So5p625p6E5biI44CB6auY +57qnSmF2YeW3peeoi+W4iOOAgee9kemhteiuvuiuoeW4iCANCiAgc3R5bGU9IkNPTE9SOiByZ2Io +MCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQo +dGhpcyw5Myk7IGhyZWY9Imh0dHA6Ly9nLmNzZG4ubmV0LzUxNjY5MTciIA0KICB0YXJnZXQ9X2Js +YW5rPuOAkOWkqemZhee9keOAkeaApeiBmEphdmHlupTnlKjmnrbmnoTluIjjgIHpq5jnuqdKYXZh +5bel56iL5biI44CB572R6aG16K6+6K6h5biIPC9BPjwvREQ+DQogIDxERCANCiAgc3R5bGU9IlBB +RERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMnB4IDdweDsgT1ZFUkZMT1ct +WTogaGlkZGVuOyBQQURESU5HLUxFRlQ6IDEycHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRw +Oi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWM1LmdpZik7IE9WRVJGTE9XLVg6 +IGhpZGRlbjsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHggMHB4IDZweDsgTElORS1I +RUlHSFQ6IDE5cHg7IFBBRERJTkctVE9QOiAwcHg7IEhFSUdIVDogMzZweDsgYmFja2dyb3VuZC1v +cmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxlPeOA +kOS4iua1t+mFt+WoseOAkemrmOiWquaApeiBmOacjeWKoeWZqOS4u+eoi+OAgeacjeWKoeWZqOeo +i+W6jyBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQog +IG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDkzKTsgaHJlZj0iaHR0cDovL2cuY3Nkbi5uZXQv +NTE2NjkxMyIgDQogIHRhcmdldD1fYmxhbms+44CQ5LiK5rW36YW35aix44CR6auY6Jaq5oCl6IGY +5pyN5Yqh5Zmo5Li756iL44CB5pyN5Yqh5Zmo56iL5bqPPC9BPjwvREQ+DQogIDxERCANCiAgc3R5 +bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMnB4IDdweDsgT1ZF +UkZMT1ctWTogaGlkZGVuOyBQQURESU5HLUxFRlQ6IDEycHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVy +bChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWM1LmdpZik7IE9WRVJG +TE9XLVg6IGhpZGRlbjsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHggMHB4IDZweDsg +TElORS1IRUlHSFQ6IDE5cHg7IFBBRERJTkctVE9QOiAwcHg7IEhFSUdIVDogMzZweDsgYmFja2dy +b3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRp +dGxlPeOAkOWIm+aWsOW3peWcuuOAkeaKgOacr+exu+iBjOS9jeeDreaLm++8jOeri+WNs+WKoOWF +peWxnuS6juS9oOiHquW3seeahOWFrOWPuCANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBU +RVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw5Myk7 +IGhyZWY9Imh0dHA6Ly9nLmNzZG4ubmV0LzUxNjY3NTUiIA0KICB0YXJnZXQ9X2JsYW5rPuOAkOWI +m+aWsOW3peWcuuOAkeaKgOacr+exu+iBjOS9jeeDreaLm++8jOeri+WNs+WKoOWFpeWxnuS6juS9 +oOiHquW3seeahOWFrOWPuDwvQT48L0REPg0KICA8REQgDQogIHN0eWxlPSJQQURESU5HLVJJR0hU +OiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDJweCA3cHg7IE9WRVJGTE9XLVk6IGhpZGRlbjsg +UEFERElORy1MRUZUOiAxMnB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcu +Y24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljNS5naWYpOyBPVkVSRkxPVy1YOiBoaWRkZW47IFBB +RERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4IDBweCA2cHg7IExJTkUtSEVJR0hUOiAxOXB4 +OyBQQURESU5HLVRPUDogMHB4OyBIRUlHSFQ6IDM2cHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0 +aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0aXRsZT3jgJDlrr3lqLHmlbDn +oIHjgJHor5rogZhDKyvlupTnlKjova/ku7blt6XnqIvluIjvvIjlpJrlqpLkvZMv572R57uc5pa5 +5ZCR77yJ44CBLm5ldOW8gOWPkeW3peeoi+W4iCANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDAp +OyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw5 +Myk7IGhyZWY9Imh0dHA6Ly9nLmNzZG4ubmV0LzUxNjU4OTkiIA0KICB0YXJnZXQ9X2JsYW5rPuOA +kOWuveWoseaVsOeggeOAkeivmuiBmEMrK+W6lOeUqOi9r+S7tuW3peeoi+W4iO+8iOWkmuWqkuS9 +ky/nvZHnu5zmlrnlkJHvvInjgIEubmV05byA5Y+R5bel56iL5biIPC9BPjwvREQ+DQogIDxERCAN +CiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMnB4IDdw +eDsgT1ZFUkZMT1ctWTogaGlkZGVuOyBQQURESU5HLUxFRlQ6IDEycHg7IEJBQ0tHUk9VTkQtSU1B +R0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWM1LmdpZik7 +IE9WRVJGTE9XLVg6IGhpZGRlbjsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHggMHB4 +IDZweDsgTElORS1IRUlHSFQ6IDE5cHg7IFBBRERJTkctVE9QOiAwcHg7IEhFSUdIVDogMzZweDsg +YmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEg +DQogIHRpdGxlPSLjgJDlm6I4MDDjgJFOby4x5Zui6LSt5a+86Iiq6K+a6IGYUnVieSBvbiBSYWls +c+mrmOaJi++8gSIgDQogIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9O +OiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsOTMpOyBocmVmPSJodHRwOi8v +Zy5jc2RuLm5ldC81MTY1ODc2IiANCiAgdGFyZ2V0PV9ibGFuaz7jgJDlm6I4MDDjgJFOby4x5Zui +6LSt5a+86Iiq6K+a6IGYUnVieSBvbiBSYWlsc+mrmOaJi++8gTwvQT48L0REPg0KICA8REQgDQog +IHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDJweCA3cHg7 +IE9WRVJGTE9XLVk6IGhpZGRlbjsgUEFERElORy1MRUZUOiAxMnB4OyBCQUNLR1JPVU5ELUlNQUdF +OiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljNS5naWYpOyBP +VkVSRkxPVy1YOiBoaWRkZW47IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4IDBweCA2 +cHg7IExJTkUtSEVJR0hUOiAxOXB4OyBQQURESU5HLVRPUDogMHB4OyBIRUlHSFQ6IDM2cHg7IGJh +Y2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0K +ICB0aXRsZT0i44CQ576O5Zu95Zu95a625Luq5Zmo44CR6K+a6IGY6auY57qn6L2v5Lu2ICDlt6Xn +qIvluIggIOS/oeWPt+WkhOeQhui9r+S7tumDqOmXqOe7j+eQhiIgDQogIHN0eWxlPSJDT0xPUjog +cmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0Nv +dW50KHRoaXMsOTMpOyBocmVmPSJodHRwOi8vZy5jc2RuLm5ldC81MTY1Njg5IiANCiAgdGFyZ2V0 +PV9ibGFuaz7jgJDnvo7lm73lm73lrrbku6rlmajjgJHor5rogZjpq5jnuqfova/ku7Yg5bel56iL +5biIIOS/oeWPt+WkhOeQhui9r+S7tumDqOmXqOe7j+eQhjwvQT48L0REPg0KICA8REQgDQogIHN0 +eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDJweCA3cHg7IE9W +RVJGTE9XLVk6IGhpZGRlbjsgUEFERElORy1MRUZUOiAxMnB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1 +cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljNS5naWYpOyBPVkVS +RkxPVy1YOiBoaWRkZW47IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4IDBweCA2cHg7 +IExJTkUtSEVJR0hUOiAxOXB4OyBQQURESU5HLVRPUDogMHB4OyBIRUlHSFQ6IDM2cHg7IGJhY2tn +cm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0 +aXRsZT3jgJDmtZnmsZ/pqbDmtbflrp7kuJrjgJHor5rogZjpobnnm67nu4/nkIbvvIxQSFAsTVlT +UUwsU0VPLOa1i+ivle+8jOi/kOe7tO+8jOetluWIku+8jOiuvuiuoeetieiBjCANCiAgc3R5bGU9 +IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxv +Z0NsaWNrQ291bnQodGhpcyw5Myk7IGhyZWY9Imh0dHA6Ly9nLmNzZG4ubmV0LzUxNjU2NjUiIA0K +ICB0YXJnZXQ9X2JsYW5rPuOAkOa1meaxn+mpsOa1t+WunuS4muOAkeivmuiBmOmhueebrue7j+eQ +hu+8jFBIUCxNWVNRTCxTRU8s5rWL6K+V77yM6L+Q57u077yM562W5YiS77yM6K6+6K6h562J6IGM +PC9BPjwvREQ+DQogIDxERCANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VO +RC1QT1NJVElPTjogMnB4IDdweDsgT1ZFUkZMT1ctWTogaGlkZGVuOyBQQURESU5HLUxFRlQ6IDEy +cHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2Nz +ZG5pbmRleF9waWM1LmdpZik7IE9WRVJGTE9XLVg6IGhpZGRlbjsgUEFERElORy1CT1RUT006IDBw +eDsgTUFSR0lOOiAwcHggMHB4IDZweDsgTElORS1IRUlHSFQ6IDE5cHg7IFBBRERJTkctVE9QOiAw +cHg7IEhFSUdIVDogMzZweDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQt +Y2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxlPSLjgJBJbmZvc3lz44CR6K+a6IGY77yaSjJFRSDp +obnnm67kuLvnrqEv77yI6LWE5rex77yJ6L2v5Lu256CU5Y+R5bel56iL5biILy5OZXTotYTmt7Ho +va/ku7bnoJTlj5Hlt6XnqIvluIgiIA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQt +REVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDkzKTsgaHJl +Zj0iaHR0cDovL2cuY3Nkbi5uZXQvNTE2NTU0OCIgDQogIHRhcmdldD1fYmxhbms+44CQSW5mb3N5 +c+OAkeivmuiBmO+8mkoyRUUg6aG555uu5Li7566hL++8iOi1hOa3se+8iei9r+S7tueglOWPkeW3 +peeoi+W4iC8uTmV06LWE5rex6L2v5Lu256CU5Y+R5bel56iL5biIPC9BPjwvREQ+DQogIDxERCAN +CiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMnB4IDdw +eDsgT1ZFUkZMT1ctWTogaGlkZGVuOyBQQURESU5HLUxFRlQ6IDEycHg7IEJBQ0tHUk9VTkQtSU1B +R0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWM1LmdpZik7 +IE9WRVJGTE9XLVg6IGhpZGRlbjsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHggMHB4 +IDZweDsgTElORS1IRUlHSFQ6IDE5cHg7IFBBRERJTkctVE9QOiAwcHg7IEhFSUdIVDogMzZweDsg +YmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEg +DQogIHRpdGxlPeOAkOWMl+S6rOmrmOaIkOmVv+WFrOWPuOOAkemrmOiWquaLm+iBmC5uZXTlkITn +uqfnqIvluo/lkZjvvIzmrKLov47lupTlsYrnlJ8gDQogIHN0eWxlPSJDT0xPUjogcmdiKDAsMCww +KTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMs +OTMpOyBocmVmPSJodHRwOi8vZy5jc2RuLm5ldC81MTY1NDA3IiANCiAgdGFyZ2V0PV9ibGFuaz7j +gJDljJfkuqzpq5jmiJDplb/lhazlj7jjgJHpq5jolqrmi5vogZgubmV05ZCE57qn56iL5bqP5ZGY +77yM5qyi6L+O5bqU5bGK55SfPC9BPjwvREQ+DQogIDxERCANCiAgc3R5bGU9IlBBRERJTkctUklH +SFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMnB4IDdweDsgT1ZFUkZMT1ctWTogaGlkZGVu +OyBQQURESU5HLUxFRlQ6IDEycHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3Nkbmlt +Zy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWM1LmdpZik7IE9WRVJGTE9XLVg6IGhpZGRlbjsg +UEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHggMHB4IDZweDsgTElORS1IRUlHSFQ6IDE5 +cHg7IFBBRERJTkctVE9QOiAwcHg7IEhFSUdIVDogMzZweDsgYmFja2dyb3VuZC1vcmlnaW46IGlu +aXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxlPSLjgJDpk7booYzp +obnnm67jgJHor5rogZhqYXZh5YmN5Y+wL+WQjuWPsOW8gOWPkeS6uuWRmOWkmuWQjSDlj4pTQVPm +lbDmja7liIbmnpDlkZjvvIzmrLLor5Xku47pgJ/vvIEiIA0KICBzdHlsZT0iQ09MT1I6IHJnYigw +LDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0 +aGlzLDkzKTsgaHJlZj0iaHR0cDovL2cuY3Nkbi5uZXQvNTE2NTE5OSIgDQogIHRhcmdldD1fYmxh +bms+44CQ6ZO26KGM6aG555uu44CR6K+a6IGYamF2YeWJjeWPsC/lkI7lj7DlvIDlj5HkurrlkZjl +pJrlkI0g5Y+KU0FT5pWw5o2u5YiG5p6Q5ZGY77yM5qyy6K+V5LuO6YCf77yBPC9BPjwvREQ+DQog +IDxERCANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjog +MnB4IDdweDsgT1ZFUkZMT1ctWTogaGlkZGVuOyBQQURESU5HLUxFRlQ6IDEycHg7IEJBQ0tHUk9V +TkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWM1 +LmdpZik7IE9WRVJGTE9XLVg6IGhpZGRlbjsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAw +cHggMHB4IDZweDsgTElORS1IRUlHSFQ6IDE5cHg7IFBBRERJTkctVE9QOiAwcHg7IEhFSUdIVDog +MzZweDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlh +bCI+PEEgDQogIHRpdGxlPeOAkOWMl+S6rOmXu+iogOenkeaKgOOAkeivmuiBmC5uZXTpq5jnuqfl +vIDlj5Hlt6XnqIvluIjjgIHmiYvmnLrova/ku7blvIDlj5Hlt6XnqIvluIjvvIjlupTlsYrmr5Xk +uJrnlJ/kvJjlhYjvvIkgDQogIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFU +SU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsOTMpOyBocmVmPSJodHRw +Oi8vZy5jc2RuLm5ldC81MTY0NzA3IiANCiAgdGFyZ2V0PV9ibGFuaz7jgJDljJfkuqzpl7voqIDn +p5HmioDjgJHor5rogZgubmV06auY57qn5byA5Y+R5bel56iL5biI44CB5omL5py66L2v5Lu25byA +5Y+R5bel56iL5biI77yI5bqU5bGK5q+V5Lia55Sf5LyY5YWI77yJPC9BPjwvREQ+DQogIDxERCAN +CiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMnB4IDdw +eDsgT1ZFUkZMT1ctWTogaGlkZGVuOyBQQURESU5HLUxFRlQ6IDEycHg7IEJBQ0tHUk9VTkQtSU1B +R0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWM1LmdpZik7 +IE9WRVJGTE9XLVg6IGhpZGRlbjsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHggMHB4 +IDZweDsgTElORS1IRUlHSFQ6IDE5cHg7IFBBRERJTkctVE9QOiAwcHg7IEhFSUdIVDogMzZweDsg +YmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEg +DQogIHRpdGxlPeOAkOS4iua1t+eUteWtkOWVhuWKoeW5s+WPsOOAkemHjemHkeivmuiBmC5uZXQs +YXNwLGphdmFzY3JpcHTotYTmt7HnqIvluo/lkZggDQogIHN0eWxlPSJDT0xPUjogcmdiKDAsMCww +KTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMs +OTMpOyBocmVmPSJodHRwOi8vZy5jc2RuLm5ldC81MTY0NjcxIiANCiAgdGFyZ2V0PV9ibGFuaz7j +gJDkuIrmtbfnlLXlrZDllYbliqHlubPlj7DjgJHph43ph5Hor5rogZgubmV0LGFzcCxqYXZhc2Ny +aXB06LWE5rex56iL5bqP5ZGYPC9BPjwvREQ+DQogIDxERCANCiAgc3R5bGU9IlBBRERJTkctUklH +SFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMnB4IDdweDsgT1ZFUkZMT1ctWTogaGlkZGVu +OyBQQURESU5HLUxFRlQ6IDEycHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3Nkbmlt +Zy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWM1LmdpZik7IE9WRVJGTE9XLVg6IGhpZGRlbjsg +UEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHggMHB4IDZweDsgTElORS1IRUlHSFQ6IDE5 +cHg7IFBBRERJTkctVE9QOiAwcHg7IEhFSUdIVDogMzZweDsgYmFja2dyb3VuZC1vcmlnaW46IGlu +aXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxlPeOAkEVG5YWo55CD +56CU5Y+R5Lit5b+D44CR55m+5LiH5bm06Jaq6K+a5oub5oqA5pyv57K+6Iux77yM5pWw55m+6IGM +5L2N54Ot5oub5LitIA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElP +Tjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDkzKTsgaHJlZj0iaHR0cDov +L2cuY3Nkbi5uZXQvNTE2NDAzNCIgDQogIHRhcmdldD1fYmxhbms+44CQRUblhajnkIPnoJTlj5Hk +uK3lv4PjgJHnmb7kuIflubTolqror5rmi5vmioDmnK/nsr7oi7HvvIzmlbDnmb7ogYzkvY3ng63m +i5vkuK08L0E+PC9ERD4NCiAgPEREIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNL +R1JPVU5ELVBPU0lUSU9OOiAycHggN3B4OyBPVkVSRkxPVy1ZOiBoaWRkZW47IFBBRERJTkctTEVG +VDogMTJweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFn +ZXMvY3NkbmluZGV4X3BpYzUuZ2lmKTsgT1ZFUkZMT1ctWDogaGlkZGVuOyBQQURESU5HLUJPVFRP +TTogMHB4OyBNQVJHSU46IDBweCAwcHggNnB4OyBMSU5FLUhFSUdIVDogMTlweDsgUEFERElORy1U +T1A6IDBweDsgSEVJR0hUOiAzNnB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dy +b3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgdGl0bGU944CQQW1hem9u44CR5Lqa6ams6YCK6K+a +6IGY5oqA5pyv5LiT5a6277yBIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFU +SU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsOTMpOyBocmVmPSJodHRw +Oi8vZy5jc2RuLm5ldC81MTY2OTE2IiANCiAgdGFyZ2V0PV9ibGFuaz7jgJBBbWF6b27jgJHkuprp +qazpgIror5rogZjmioDmnK/kuJPlrrbvvIE8L0E+PC9ERD4NCiAgPEREIA0KICBzdHlsZT0iUEFE +RElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAycHggN3B4OyBPVkVSRkxPVy1Z +OiBoaWRkZW47IFBBRERJTkctTEVGVDogMTJweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6 +Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzUuZ2lmKTsgT1ZFUkZMT1ctWDog +aGlkZGVuOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweCAwcHggNnB4OyBMSU5FLUhF +SUdIVDogMTlweDsgUEFERElORy1UT1A6IDBweDsgSEVJR0hUOiAzNnB4OyBiYWNrZ3JvdW5kLW9y +aWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgdGl0bGU944CQ +572R6Lev5pe25Luj44CR6auY6Jaq6K+a6IGYQysr44CBLm5ldOW8gOWPkeW3peeoi+W4iCBzdHls +ZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9 +TG9nQ2xpY2tDb3VudCh0aGlzLDkzKTsgaHJlZj0iaHR0cDovL2cuY3Nkbi5uZXQvNTE2MzM2OSIg +DQogIHRhcmdldD1fYmxhbms+44CQ572R6Lev5pe25Luj44CR6auY6Jaq6K+a6IGYQysr44CBLm5l +dOW8gOWPkeW3peeoi+W4iDwvQT48L0REPg0KICA8REQgDQogIHN0eWxlPSJQQURESU5HLVJJR0hU +OiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDJweCA3cHg7IE9WRVJGTE9XLVk6IGhpZGRlbjsg +UEFERElORy1MRUZUOiAxMnB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcu +Y24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljNS5naWYpOyBPVkVSRkxPVy1YOiBoaWRkZW47IFBB +RERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4IDBweCA2cHg7IExJTkUtSEVJR0hUOiAxOXB4 +OyBQQURESU5HLVRPUDogMHB4OyBIRUlHSFQ6IDM2cHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0 +aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0aXRsZT3jgJDkuqzkuJzllYbl +n47jgJHor5rogZjmiYvmnLrlvIDlj5Hlt6XnqIvluIjvvIzova/ku7blvIDlj5Hlt6XnqIvluIjv +vIzmrLLor5Xku47pgJ8hIA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JB +VElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDkzKTsgaHJlZj0iaHR0 +cDovL2cuY3Nkbi5uZXQvNTE2Mjk5MCIgDQogIHRhcmdldD1fYmxhbms+44CQ5Lqs5Lic5ZWG5Z+O +44CR6K+a6IGY5omL5py65byA5Y+R5bel56iL5biI77yM6L2v5Lu25byA5Y+R5bel56iL5biI77yM +5qyy6K+V5LuO6YCfITwvQT48L0REPg0KICA8REQgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAw +cHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDJweCA3cHg7IE9WRVJGTE9XLVk6IGhpZGRlbjsgUEFE +RElORy1MRUZUOiAxMnB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24v +d3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljNS5naWYpOyBPVkVSRkxPVy1YOiBoaWRkZW47IFBBRERJ +TkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4IDBweCA2cHg7IExJTkUtSEVJR0hUOiAxOXB4OyBQ +QURESU5HLVRPUDogMHB4OyBIRUlHSFQ6IDM2cHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFs +OyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0aXRsZT3jgJBBdXRvZGVza+OAkeas +p+eJueWFi+i9r+S7tijkuK3lm70p6K+a6IGY6L2v5Lu25byA5Y+RLOa1i+ivlSznoJTnqbblkZgg +DQogIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAg +b25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsOTMpOyBocmVmPSJodHRwOi8vZy5jc2RuLm5ldC81 +MTYyOTY2IiANCiAgdGFyZ2V0PV9ibGFuaz7jgJBBdXRvZGVza+OAkeasp+eJueWFi+i9r+S7tijk +uK3lm70p6K+a6IGY6L2v5Lu25byA5Y+RLOa1i+ivlSznoJTnqbblkZg8L0E+PC9ERD4NCiAgPERE +IA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAycHgg +N3B4OyBPVkVSRkxPVy1ZOiBoaWRkZW47IFBBRERJTkctTEVGVDogMTJweDsgQkFDS0dST1VORC1J +TUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzUuZ2lm +KTsgT1ZFUkZMT1ctWDogaGlkZGVuOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweCAw +cHggNnB4OyBMSU5FLUhFSUdIVDogMTlweDsgUEFERElORy1UT1A6IDBweDsgSEVJR0hUOiAzNnB4 +OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48 +QSANCiAgdGl0bGU944CQR29vZ2xl44CR6K+a5oub5oqA5pyv57K+6Iux77yM5Y+y5LiK5Lq65pWw +5pyA5aSa6IGM5L2N5pyA5bm/ISANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURF +Q09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw5Myk7IGhyZWY9 +Imh0dHA6Ly9nLmNzZG4ubmV0LzUxNjI1OTkiIA0KICB0YXJnZXQ9X2JsYW5rPuOAkEdvb2dsZeOA +keivmuaLm+aKgOacr+eyvuiLse+8jOWPsuS4iuS6uuaVsOacgOWkmuiBjOS9jeacgOW5vyE8L0E+ +PC9ERD4NCiAgPEREIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBP +U0lUSU9OOiAycHggN3B4OyBPVkVSRkxPVy1ZOiBoaWRkZW47IFBBRERJTkctTEVGVDogMTJweDsg +QkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3Nkbmlu +ZGV4X3BpYzUuZ2lmKTsgT1ZFUkZMT1ctWDogaGlkZGVuOyBQQURESU5HLUJPVFRPTTogMHB4OyBN +QVJHSU46IDBweCAwcHggNnB4OyBMSU5FLUhFSUdIVDogMTlweDsgUEFERElORy1UT1A6IDBweDsg +SEVJR0hUOiAzNnB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlw +OiBpbml0aWFsIj48QSANCiAgdGl0bGU944CQ54Ot6IGY44CR5pCc54uQ55WF5ri45YWo5Zu954Ot +5oub5byA5Y+R5bel56iL5biIIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFU +SU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsOTMpOyBocmVmPSJodHRw +Oi8vZy5jc2RuLm5ldC81MTU3OTc5IiANCiAgdGFyZ2V0PV9ibGFuaz7jgJDng63ogZjjgJHmkJzn +i5DnlYXmuLjlhajlm73ng63mi5vlvIDlj5Hlt6XnqIvluIg8L0E+PC9ERD4NCiAgPEREIA0KICBz +dHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAycHggN3B4OyBP +VkVSRkxPVy1ZOiBoaWRkZW47IFBBRERJTkctTEVGVDogMTJweDsgQkFDS0dST1VORC1JTUFHRTog +dXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzUuZ2lmKTsgT1ZF +UkZMT1ctWDogaGlkZGVuOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweCAwcHggNnB4 +OyBMSU5FLUhFSUdIVDogMTlweDsgUEFERElORy1UT1A6IDBweDsgSEVJR0hUOiAzNnB4OyBiYWNr +Z3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAg +dGl0bGU9IuOAkOeAmuS/oeenkeaKgOOAkeivmuiBmCBXSU5ET1dTIEMrKyBXSU5ET1dTIEMj5Lit +6auY57qn5byA5Y+R5bel56iL5biIIiANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhU +LURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw5Myk7IGhy +ZWY9Imh0dHA6Ly9nLmNzZG4ubmV0LzUxNjc0NTciIA0KICB0YXJnZXQ9X2JsYW5rPuOAkOeAmuS/ +oeenkeaKgOOAkeivmuiBmCBXSU5ET1dTIEMrKyBXSU5ET1dTIEMj5Lit6auY57qn5byA5Y+R5bel +56iL5biIPC9BPjwvREQ+DQogIDxERCANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFD +S0dST1VORC1QT1NJVElPTjogMnB4IDdweDsgT1ZFUkZMT1ctWTogaGlkZGVuOyBQQURESU5HLUxF +RlQ6IDEycHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1h +Z2VzL2NzZG5pbmRleF9waWM1LmdpZik7IE9WRVJGTE9XLVg6IGhpZGRlbjsgUEFERElORy1CT1RU +T006IDBweDsgTUFSR0lOOiAwcHggMHB4IDZweDsgTElORS1IRUlHSFQ6IDE5cHg7IFBBRERJTkct +VE9QOiAwcHg7IEhFSUdIVDogMzZweDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tn +cm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxlPSLjgJDphbfmiJHpn7PkuZDnm5LjgJHp +q5jolqror5rogZgg5r+A5oOF54ix5aW95bel5L2c6J6N5Li65LiA5L2TIiANCiAgc3R5bGU9IkNP +TE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0Ns +aWNrQ291bnQodGhpcyw5Myk7IGhyZWY9Imh0dHA6Ly9nLmNzZG4ubmV0LzUxNjc0NTQiIA0KICB0 +YXJnZXQ9X2JsYW5rPuOAkOmFt+aIkemfs+S5kOebkuOAkemrmOiWquivmuiBmCDmv4Dmg4XniLHl +pb3lt6XkvZzono3kuLrkuIDkvZM8L0E+PC9ERD4NCiAgPEREIA0KICBzdHlsZT0iUEFERElORy1S +SUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAycHggN3B4OyBPVkVSRkxPVy1ZOiBoaWRk +ZW47IFBBRERJTkctTEVGVDogMTJweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2Ru +aW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzUuZ2lmKTsgT1ZFUkZMT1ctWDogaGlkZGVu +OyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweCAwcHggNnB4OyBMSU5FLUhFSUdIVDog +MTlweDsgUEFERElORy1UT1A6IDBweDsgSEVJR0hUOiAzNnB4OyBiYWNrZ3JvdW5kLW9yaWdpbjog +aW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgdGl0bGU944CQ6L6+5YaF +6ZuG5Zui44CR6auY6Jaq6K+a6IGYSkFWQeiusuW4iC7ltYzlhaXlvI/orrLluIguM0forrLluIgu +5oqA5pyv5oC755uRLuWIhuWFrOWPuOaAu+e7j+eQhiANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCww +LDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhp +cyw5Myk7IGhyZWY9Imh0dHA6Ly9nLmNzZG4ubmV0LzUxNjc0MTQiIA0KICB0YXJnZXQ9X2JsYW5r +PuOAkOi+vuWGhembhuWbouOAkemrmOiWquivmuiBmEpBVkHorrLluIgu5bWM5YWl5byP6K6y5biI +LjNH6K6y5biILuaKgOacr+aAu+ebkS7liIblhazlj7jmgLvnu4/nkIY8L0E+PC9ERD4NCiAgPERE +IA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAycHgg +N3B4OyBPVkVSRkxPVy1ZOiBoaWRkZW47IFBBRERJTkctTEVGVDogMTJweDsgQkFDS0dST1VORC1J +TUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzUuZ2lm +KTsgT1ZFUkZMT1ctWDogaGlkZGVuOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweCAw +cHggNnB4OyBMSU5FLUhFSUdIVDogMTlweDsgUEFERElORy1UT1A6IDBweDsgSEVJR0hUOiAzNnB4 +OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48 +QSANCiAgdGl0bGU944CQ5aSp6ZmF572R44CR5oCl6IGYSmF2YeW6lOeUqOaetuaehOW4iOOAgemr +mOe6p0phdmHlt6XnqIvluIjjgIHnvZHpobXorr7orqHluIggDQogIHN0eWxlPSJDT0xPUjogcmdi +KDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50 +KHRoaXMsOTMpOyBocmVmPSJodHRwOi8vZy5jc2RuLm5ldC81MTY2OTE3IiANCiAgdGFyZ2V0PV9i +bGFuaz7jgJDlpKnpmYXnvZHjgJHmgKXogZhKYXZh5bqU55So5p625p6E5biI44CB6auY57qnSmF2 +YeW3peeoi+W4iOOAgee9kemhteiuvuiuoeW4iDwvQT48L0REPg0KICA8REQgDQogIHN0eWxlPSJQ +QURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDJweCA3cHg7IE9WRVJGTE9X +LVk6IGhpZGRlbjsgUEFERElORy1MRUZUOiAxMnB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0 +cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljNS5naWYpOyBPVkVSRkxPVy1Y +OiBoaWRkZW47IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4IDBweCA2cHg7IExJTkUt +SEVJR0hUOiAxOXB4OyBQQURESU5HLVRPUDogMHB4OyBIRUlHSFQ6IDM2cHg7IGJhY2tncm91bmQt +b3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0aXRsZT3j +gJDkuIrmtbfphbflqLHjgJHpq5jolqrmgKXogZjmnI3liqHlmajkuLvnqIvjgIHmnI3liqHlmajn +qIvluo8gc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0K +ICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw5Myk7IGhyZWY9Imh0dHA6Ly9nLmNzZG4ubmV0 +LzUxNjY5MTMiIA0KICB0YXJnZXQ9X2JsYW5rPuOAkOS4iua1t+mFt+WoseOAkemrmOiWquaApeiB +mOacjeWKoeWZqOS4u+eoi+OAgeacjeWKoeWZqOeoi+W6jzwvQT48L0REPg0KICA8REQgDQogIHN0 +eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDJweCA3cHg7IE9W +RVJGTE9XLVk6IGhpZGRlbjsgUEFERElORy1MRUZUOiAxMnB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1 +cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljNS5naWYpOyBPVkVS +RkxPVy1YOiBoaWRkZW47IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4IDBweCA2cHg7 +IExJTkUtSEVJR0hUOiAxOXB4OyBQQURESU5HLVRPUDogMHB4OyBIRUlHSFQ6IDM2cHg7IGJhY2tn +cm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0 +aXRsZT3jgJDliJvmlrDlt6XlnLrjgJHmioDmnK/nsbvogYzkvY3ng63mi5vvvIznq4vljbPliqDl +haXlsZ7kuo7kvaDoh6rlt7HnmoTlhazlj7ggDQogIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsg +VEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsOTMp +OyBocmVmPSJodHRwOi8vZy5jc2RuLm5ldC81MTY2NzU1IiANCiAgdGFyZ2V0PV9ibGFuaz7jgJDl +iJvmlrDlt6XlnLrjgJHmioDmnK/nsbvogYzkvY3ng63mi5vvvIznq4vljbPliqDlhaXlsZ7kuo7k +vaDoh6rlt7HnmoTlhazlj7g8L0E+PC9ERD4NCiAgPEREIA0KICBzdHlsZT0iUEFERElORy1SSUdI +VDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAycHggN3B4OyBPVkVSRkxPVy1ZOiBoaWRkZW47 +IFBBRERJTkctTEVGVDogMTJweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1n +LmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzUuZ2lmKTsgT1ZFUkZMT1ctWDogaGlkZGVuOyBQ +QURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweCAwcHggNnB4OyBMSU5FLUhFSUdIVDogMTlw +eDsgUEFERElORy1UT1A6IDBweDsgSEVJR0hUOiAzNnB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5p +dGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgdGl0bGU944CQ5a695aix5pWw +56CB44CR6K+a6IGYQysr5bqU55So6L2v5Lu25bel56iL5biI77yI5aSa5aqS5L2TL+e9kee7nOaW +ueWQke+8ieOAgS5uZXTlvIDlj5Hlt6XnqIvluIggDQogIHN0eWxlPSJDT0xPUjogcmdiKDAsMCww +KTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMs +OTMpOyBocmVmPSJodHRwOi8vZy5jc2RuLm5ldC81MTY1ODk5IiANCiAgdGFyZ2V0PV9ibGFuaz7j +gJDlrr3lqLHmlbDnoIHjgJHor5rogZhDKyvlupTnlKjova/ku7blt6XnqIvluIjvvIjlpJrlqpLk +vZMv572R57uc5pa55ZCR77yJ44CBLm5ldOW8gOWPkeW3peeoi+W4iDwvQT48L0REPg0KICA8REQg +DQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDJweCA3 +cHg7IE9WRVJGTE9XLVk6IGhpZGRlbjsgUEFERElORy1MRUZUOiAxMnB4OyBCQUNLR1JPVU5ELUlN +QUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljNS5naWYp +OyBPVkVSRkxPVy1YOiBoaWRkZW47IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4IDBw +eCA2cHg7IExJTkUtSEVJR0hUOiAxOXB4OyBQQURESU5HLVRPUDogMHB4OyBIRUlHSFQ6IDM2cHg7 +IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxB +IA0KICB0aXRsZT0i44CQ5ZuiODAw44CRTm8uMeWboui0reWvvOiIquivmuiBmFJ1Ynkgb24gUmFp +bHPpq5jmiYvvvIEiIA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElP +Tjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDkzKTsgaHJlZj0iaHR0cDov +L2cuY3Nkbi5uZXQvNTE2NTg3NiIgDQogIHRhcmdldD1fYmxhbms+44CQ5ZuiODAw44CRTm8uMeWb +oui0reWvvOiIquivmuiBmFJ1Ynkgb24gUmFpbHPpq5jmiYvvvIE8L0E+PC9ERD4NCiAgPEREIA0K +ICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAycHggN3B4 +OyBPVkVSRkxPVy1ZOiBoaWRkZW47IFBBRERJTkctTEVGVDogMTJweDsgQkFDS0dST1VORC1JTUFH +RTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzUuZ2lmKTsg +T1ZFUkZMT1ctWDogaGlkZGVuOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweCAwcHgg +NnB4OyBMSU5FLUhFSUdIVDogMTlweDsgUEFERElORy1UT1A6IDBweDsgSEVJR0hUOiAzNnB4OyBi +YWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSAN +CiAgdGl0bGU9IuOAkOe+juWbveWbveWutuS7quWZqOOAkeivmuiBmOmrmOe6p+i9r+S7tiAg5bel +56iL5biIICDkv6Hlj7flpITnkIbova/ku7bpg6jpl6jnu4/nkIYiIA0KICBzdHlsZT0iQ09MT1I6 +IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tD +b3VudCh0aGlzLDkzKTsgaHJlZj0iaHR0cDovL2cuY3Nkbi5uZXQvNTE2NTY4OSIgDQogIHRhcmdl +dD1fYmxhbms+44CQ576O5Zu95Zu95a625Luq5Zmo44CR6K+a6IGY6auY57qn6L2v5Lu2IOW3peeo +i+W4iCDkv6Hlj7flpITnkIbova/ku7bpg6jpl6jnu4/nkIY8L0E+PC9ERD4NCiAgPEREIA0KICBz +dHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAycHggN3B4OyBP +VkVSRkxPVy1ZOiBoaWRkZW47IFBBRERJTkctTEVGVDogMTJweDsgQkFDS0dST1VORC1JTUFHRTog +dXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzUuZ2lmKTsgT1ZF +UkZMT1ctWDogaGlkZGVuOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweCAwcHggNnB4 +OyBMSU5FLUhFSUdIVDogMTlweDsgUEFERElORy1UT1A6IDBweDsgSEVJR0hUOiAzNnB4OyBiYWNr +Z3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAg +dGl0bGU944CQ5rWZ5rGf6amw5rW35a6e5Lia44CR6K+a6IGY6aG555uu57uP55CG77yMUEhQLE1Z +U1FMLFNFTyzmtYvor5XvvIzov5Dnu7TvvIznrZbliJLvvIzorr7orqHnrYnogYwgDQogIHN0eWxl +PSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1M +b2dDbGlja0NvdW50KHRoaXMsOTMpOyBocmVmPSJodHRwOi8vZy5jc2RuLm5ldC81MTY1NjY1IiAN +CiAgdGFyZ2V0PV9ibGFuaz7jgJDmtZnmsZ/pqbDmtbflrp7kuJrjgJHor5rogZjpobnnm67nu4/n +kIbvvIxQSFAsTVlTUUwsU0VPLOa1i+ivle+8jOi/kOe7tO+8jOetluWIku+8jOiuvuiuoeetieiB +jDwvQT48L0REPg0KICA8REQgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9V +TkQtUE9TSVRJT046IDJweCA3cHg7IE9WRVJGTE9XLVk6IGhpZGRlbjsgUEFERElORy1MRUZUOiAx +MnB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9j +c2RuaW5kZXhfcGljNS5naWYpOyBPVkVSRkxPVy1YOiBoaWRkZW47IFBBRERJTkctQk9UVE9NOiAw +cHg7IE1BUkdJTjogMHB4IDBweCA2cHg7IExJTkUtSEVJR0hUOiAxOXB4OyBQQURESU5HLVRPUDog +MHB4OyBIRUlHSFQ6IDM2cHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5k +LWNsaXA6IGluaXRpYWwiPjxBIA0KICB0aXRsZT0i44CQSW5mb3N5c+OAkeivmuiBmO+8mkoyRUUg +6aG555uu5Li7566hL++8iOi1hOa3se+8iei9r+S7tueglOWPkeW3peeoi+W4iC8uTmV06LWE5rex +6L2v5Lu256CU5Y+R5bel56iL5biIIiANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhU +LURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw5Myk7IGhy +ZWY9Imh0dHA6Ly9nLmNzZG4ubmV0LzUxNjU1NDgiIA0KICB0YXJnZXQ9X2JsYW5rPuOAkEluZm9z +eXPjgJHor5rogZjvvJpKMkVFIOmhueebruS4u+euoS/vvIjotYTmt7HvvInova/ku7bnoJTlj5Hl +t6XnqIvluIgvLk5ldOi1hOa3sei9r+S7tueglOWPkeW3peeoi+W4iDwvQT48L0REPg0KICA8REQg +DQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDJweCA3 +cHg7IE9WRVJGTE9XLVk6IGhpZGRlbjsgUEFERElORy1MRUZUOiAxMnB4OyBCQUNLR1JPVU5ELUlN +QUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljNS5naWYp +OyBPVkVSRkxPVy1YOiBoaWRkZW47IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4IDBw +eCA2cHg7IExJTkUtSEVJR0hUOiAxOXB4OyBQQURESU5HLVRPUDogMHB4OyBIRUlHSFQ6IDM2cHg7 +IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxB +IA0KICB0aXRsZT3jgJDljJfkuqzpq5jmiJDplb/lhazlj7jjgJHpq5jolqrmi5vogZgubmV05ZCE +57qn56iL5bqP5ZGY77yM5qyi6L+O5bqU5bGK55SfIA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAs +MCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlz +LDkzKTsgaHJlZj0iaHR0cDovL2cuY3Nkbi5uZXQvNTE2NTQwNyIgDQogIHRhcmdldD1fYmxhbms+ +44CQ5YyX5Lqs6auY5oiQ6ZW/5YWs5Y+444CR6auY6Jaq5oub6IGYLm5ldOWQhOe6p+eoi+W6j+WR +mO+8jOasoui/juW6lOWxiueUnzwvQT48L0REPg0KICA8REQgDQogIHN0eWxlPSJQQURESU5HLVJJ +R0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDJweCA3cHg7IE9WRVJGTE9XLVk6IGhpZGRl +bjsgUEFERElORy1MRUZUOiAxMnB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5p +bWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljNS5naWYpOyBPVkVSRkxPVy1YOiBoaWRkZW47 +IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4IDBweCA2cHg7IExJTkUtSEVJR0hUOiAx +OXB4OyBQQURESU5HLVRPUDogMHB4OyBIRUlHSFQ6IDM2cHg7IGJhY2tncm91bmQtb3JpZ2luOiBp +bml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0aXRsZT0i44CQ6ZO26KGM +6aG555uu44CR6K+a6IGYamF2YeWJjeWPsC/lkI7lj7DlvIDlj5HkurrlkZjlpJrlkI0g5Y+KU0FT +5pWw5o2u5YiG5p6Q5ZGY77yM5qyy6K+V5LuO6YCf77yBIiANCiAgc3R5bGU9IkNPTE9SOiByZ2Io +MCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQo +dGhpcyw5Myk7IGhyZWY9Imh0dHA6Ly9nLmNzZG4ubmV0LzUxNjUxOTkiIA0KICB0YXJnZXQ9X2Js +YW5rPuOAkOmTtuihjOmhueebruOAkeivmuiBmGphdmHliY3lj7Av5ZCO5Y+w5byA5Y+R5Lq65ZGY +5aSa5ZCNIOWPilNBU+aVsOaNruWIhuaekOWRmO+8jOassuivleS7jumAn++8gTwvQT48L0REPg0K +ICA8REQgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046 +IDJweCA3cHg7IE9WRVJGTE9XLVk6IGhpZGRlbjsgUEFERElORy1MRUZUOiAxMnB4OyBCQUNLR1JP +VU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGlj +NS5naWYpOyBPVkVSRkxPVy1YOiBoaWRkZW47IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjog +MHB4IDBweCA2cHg7IExJTkUtSEVJR0hUOiAxOXB4OyBQQURESU5HLVRPUDogMHB4OyBIRUlHSFQ6 +IDM2cHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRp +YWwiPjxBIA0KICB0aXRsZT3jgJDljJfkuqzpl7voqIDnp5HmioDjgJHor5rogZgubmV06auY57qn +5byA5Y+R5bel56iL5biI44CB5omL5py66L2v5Lu25byA5Y+R5bel56iL5biI77yI5bqU5bGK5q+V +5Lia55Sf5LyY5YWI77yJIA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JB +VElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDkzKTsgaHJlZj0iaHR0 +cDovL2cuY3Nkbi5uZXQvNTE2NDcwNyIgDQogIHRhcmdldD1fYmxhbms+44CQ5YyX5Lqs6Ze76KiA +56eR5oqA44CR6K+a6IGYLm5ldOmrmOe6p+W8gOWPkeW3peeoi+W4iOOAgeaJi+acuui9r+S7tuW8 +gOWPkeW3peeoi+W4iO+8iOW6lOWxiuavleS4mueUn+S8mOWFiO+8iTwvQT48L0REPg0KICA8REQg +DQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDJweCA3 +cHg7IE9WRVJGTE9XLVk6IGhpZGRlbjsgUEFERElORy1MRUZUOiAxMnB4OyBCQUNLR1JPVU5ELUlN +QUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljNS5naWYp +OyBPVkVSRkxPVy1YOiBoaWRkZW47IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4IDBw +eCA2cHg7IExJTkUtSEVJR0hUOiAxOXB4OyBQQURESU5HLVRPUDogMHB4OyBIRUlHSFQ6IDM2cHg7 +IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxB +IA0KICB0aXRsZT3jgJDkuIrmtbfnlLXlrZDllYbliqHlubPlj7DjgJHph43ph5Hor5rogZgubmV0 +LGFzcCxqYXZhc2NyaXB06LWE5rex56iL5bqP5ZGYIA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAs +MCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlz +LDkzKTsgaHJlZj0iaHR0cDovL2cuY3Nkbi5uZXQvNTE2NDY3MSIgDQogIHRhcmdldD1fYmxhbms+ +44CQ5LiK5rW355S15a2Q5ZWG5Yqh5bmz5Y+w44CR6YeN6YeR6K+a6IGYLm5ldCxhc3AsamF2YXNj +cmlwdOi1hOa3seeoi+W6j+WRmDwvQT48L0REPg0KICA8REQgDQogIHN0eWxlPSJQQURESU5HLVJJ +R0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDJweCA3cHg7IE9WRVJGTE9XLVk6IGhpZGRl +bjsgUEFERElORy1MRUZUOiAxMnB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5p +bWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljNS5naWYpOyBPVkVSRkxPVy1YOiBoaWRkZW47 +IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4IDBweCA2cHg7IExJTkUtSEVJR0hUOiAx +OXB4OyBQQURESU5HLVRPUDogMHB4OyBIRUlHSFQ6IDM2cHg7IGJhY2tncm91bmQtb3JpZ2luOiBp +bml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0aXRsZT3jgJBFRuWFqOeQ +g+eglOWPkeS4reW/g+OAkeeZvuS4h+W5tOiWquivmuaLm+aKgOacr+eyvuiLse+8jOaVsOeZvuiB +jOS9jeeDreaLm+S4rSANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJ +T046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw5Myk7IGhyZWY9Imh0dHA6 +Ly9nLmNzZG4ubmV0LzUxNjQwMzQiIA0KICB0YXJnZXQ9X2JsYW5rPuOAkEVG5YWo55CD56CU5Y+R +5Lit5b+D44CR55m+5LiH5bm06Jaq6K+a5oub5oqA5pyv57K+6Iux77yM5pWw55m+6IGM5L2N54Ot +5oub5LitPC9BPjwvREQ+DQogIDxERCANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFD +S0dST1VORC1QT1NJVElPTjogMnB4IDdweDsgT1ZFUkZMT1ctWTogaGlkZGVuOyBQQURESU5HLUxF +RlQ6IDEycHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1h +Z2VzL2NzZG5pbmRleF9waWM1LmdpZik7IE9WRVJGTE9XLVg6IGhpZGRlbjsgUEFERElORy1CT1RU +T006IDBweDsgTUFSR0lOOiAwcHggMHB4IDZweDsgTElORS1IRUlHSFQ6IDE5cHg7IFBBRERJTkct +VE9QOiAwcHg7IEhFSUdIVDogMzZweDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tn +cm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxlPeOAkEFtYXpvbuOAkeS6mumprOmAiuiv +muiBmOaKgOacr+S4k+Wutu+8gSBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JB +VElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDkzKTsgaHJlZj0iaHR0 +cDovL2cuY3Nkbi5uZXQvNTE2NjkxNiIgDQogIHRhcmdldD1fYmxhbms+44CQQW1hem9u44CR5Lqa +6ams6YCK6K+a6IGY5oqA5pyv5LiT5a6277yBPC9BPjwvREQ+DQogIDxERCANCiAgc3R5bGU9IlBB +RERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMnB4IDdweDsgT1ZFUkZMT1ct +WTogaGlkZGVuOyBQQURESU5HLUxFRlQ6IDEycHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRw +Oi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWM1LmdpZik7IE9WRVJGTE9XLVg6 +IGhpZGRlbjsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHggMHB4IDZweDsgTElORS1I +RUlHSFQ6IDE5cHg7IFBBRERJTkctVE9QOiAwcHg7IEhFSUdIVDogMzZweDsgYmFja2dyb3VuZC1v +cmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxlPeOA +kOe9kei3r+aXtuS7o+OAkemrmOiWquivmuiBmEMrK+OAgS5uZXTlvIDlj5Hlt6XnqIvluIggc3R5 +bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNr +PUxvZ0NsaWNrQ291bnQodGhpcyw5Myk7IGhyZWY9Imh0dHA6Ly9nLmNzZG4ubmV0LzUxNjMzNjki +IA0KICB0YXJnZXQ9X2JsYW5rPuOAkOe9kei3r+aXtuS7o+OAkemrmOiWquivmuiBmEMrK+OAgS5u +ZXTlvIDlj5Hlt6XnqIvluIg8L0E+PC9ERD4NCiAgPEREIA0KICBzdHlsZT0iUEFERElORy1SSUdI +VDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAycHggN3B4OyBPVkVSRkxPVy1ZOiBoaWRkZW47 +IFBBRERJTkctTEVGVDogMTJweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1n +LmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzUuZ2lmKTsgT1ZFUkZMT1ctWDogaGlkZGVuOyBQ +QURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweCAwcHggNnB4OyBMSU5FLUhFSUdIVDogMTlw +eDsgUEFERElORy1UT1A6IDBweDsgSEVJR0hUOiAzNnB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5p +dGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgdGl0bGU944CQ5Lqs5Lic5ZWG +5Z+O44CR6K+a6IGY5omL5py65byA5Y+R5bel56iL5biI77yM6L2v5Lu25byA5Y+R5bel56iL5biI +77yM5qyy6K+V5LuO6YCfISANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09S +QVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw5Myk7IGhyZWY9Imh0 +dHA6Ly9nLmNzZG4ubmV0LzUxNjI5OTAiIA0KICB0YXJnZXQ9X2JsYW5rPuOAkOS6rOS4nOWVhuWf +juOAkeivmuiBmOaJi+acuuW8gOWPkeW3peeoi+W4iO+8jOi9r+S7tuW8gOWPkeW3peeoi+W4iO+8 +jOassuivleS7jumAnyE8L0E+PC9ERD4NCiAgPEREIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDog +MHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAycHggN3B4OyBPVkVSRkxPVy1ZOiBoaWRkZW47IFBB +RERJTkctTEVGVDogMTJweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNu +L3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzUuZ2lmKTsgT1ZFUkZMT1ctWDogaGlkZGVuOyBQQURE +SU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweCAwcHggNnB4OyBMSU5FLUhFSUdIVDogMTlweDsg +UEFERElORy1UT1A6IDBweDsgSEVJR0hUOiAzNnB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlh +bDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgdGl0bGU944CQQXV0b2Rlc2vjgJHm +rKfnibnlhYvova/ku7Yo5Lit5Zu9KeivmuiBmOi9r+S7tuW8gOWPkSzmtYvor5Us56CU56m25ZGY +IA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQog +IG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDkzKTsgaHJlZj0iaHR0cDovL2cuY3Nkbi5uZXQv +NTE2Mjk2NiIgDQogIHRhcmdldD1fYmxhbms+44CQQXV0b2Rlc2vjgJHmrKfnibnlhYvova/ku7Yo +5Lit5Zu9KeivmuiBmOi9r+S7tuW8gOWPkSzmtYvor5Us56CU56m25ZGYPC9BPjwvREQ+DQogIDxE +RCANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMnB4 +IDdweDsgT1ZFUkZMT1ctWTogaGlkZGVuOyBQQURESU5HLUxFRlQ6IDEycHg7IEJBQ0tHUk9VTkQt +SU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWM1Lmdp +Zik7IE9WRVJGTE9XLVg6IGhpZGRlbjsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHgg +MHB4IDZweDsgTElORS1IRUlHSFQ6IDE5cHg7IFBBRERJTkctVE9QOiAwcHg7IEhFSUdIVDogMzZw +eDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+ +PEEgDQogIHRpdGxlPeOAkEdvb2dsZeOAkeivmuaLm+aKgOacr+eyvuiLse+8jOWPsuS4iuS6uuaV +sOacgOWkmuiBjOS9jeacgOW5vyEgDQogIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1E +RUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsOTMpOyBocmVm +PSJodHRwOi8vZy5jc2RuLm5ldC81MTYyNTk5IiANCiAgdGFyZ2V0PV9ibGFuaz7jgJBHb29nbGXj +gJHor5rmi5vmioDmnK/nsr7oi7HvvIzlj7LkuIrkurrmlbDmnIDlpJrogYzkvY3mnIDlub8hPC9B +PjwvREQ+DQogIDxERCANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1Q +T1NJVElPTjogMnB4IDdweDsgT1ZFUkZMT1ctWTogaGlkZGVuOyBQQURESU5HLUxFRlQ6IDEycHg7 +IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5p +bmRleF9waWM1LmdpZik7IE9WRVJGTE9XLVg6IGhpZGRlbjsgUEFERElORy1CT1RUT006IDBweDsg +TUFSR0lOOiAwcHggMHB4IDZweDsgTElORS1IRUlHSFQ6IDE5cHg7IFBBRERJTkctVE9QOiAwcHg7 +IEhFSUdIVDogMzZweDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xp +cDogaW5pdGlhbCI+PEEgDQogIHRpdGxlPeOAkOeDreiBmOOAkeaQnOeLkOeVhea4uOWFqOWbveeD +reaLm+W8gOWPkeW3peeoi+W4iCBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JB +VElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDkzKTsgaHJlZj0iaHR0 +cDovL2cuY3Nkbi5uZXQvNTE1Nzk3OSIgDQogIHRhcmdldD1fYmxhbms+44CQ54Ot6IGY44CR5pCc +54uQ55WF5ri45YWo5Zu954Ot5oub5byA5Y+R5bel56iL5biIPC9BPjwvREQ+PC9ETD48L0RJVj48 +L0RJVj4NCjxESVYgY2xhc3M9c2lkZWJhcl9jb24gDQpzdHlsZT0iRElTUExBWTogaW5saW5lOyBG +TE9BVDogbGVmdDsgTUFSR0lOOiA2cHggM3B4IDJweDsgV0lEVEg6IDIwMnB4Ij4NCjxINCBjbGFz +cz10eHRfMTIgDQpzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBQQURESU5HLUxFRlQ6IDNweDsg +Rk9OVC1TSVpFOiAxMnB4OyBQQURESU5HLUJPVFRPTTogNXB4OyBNQVJHSU46IDBweDsgUEFERElO +Ry1UT1A6IDBweDsgQk9SREVSLUJPVFRPTTogcmdiKDIwNCwyMDQsMjA0KSAxcHggc29saWQ7IFBP +U0lUSU9OOiByZWxhdGl2ZSI+PFNQQU4gDQpjbGFzcz10eHRfZ3JheSANCnN0eWxlPSJGT05ULVdF +SUdIVDogbm9ybWFsOyBGTE9BVDogcmlnaHQ7IENPTE9SOiByZ2IoMTAyLDEwMiwxMDIpIj48L1NQ +QU4+54m55Yir5o6o6I2QPC9IND4NCjxETCBjbGFzcz1zZXNzaW9uX3N0eWxlIA0Kc3R5bGU9IlBB +RERJTkctUklHSFQ6IDNweDsgUEFERElORy1MRUZUOiAzcHg7IEZMT0FUOiBsZWZ0OyBQQURESU5H +LUJPVFRPTTogNXB4OyBNQVJHSU46IDJweCAwcHggMHB4OyBXSURUSDogMTk2cHg7IFBBRERJTkct +VE9QOiAxMHB4OyBCT1JERVItQk9UVE9NOiByZ2IoMjA0LDIwNCwyMDQpIDFweCBzb2xpZDsgQkFD +S0dST1VORC1DT0xPUjogcmdiKDI1NSwyNTUsMjU1KTsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRp +YWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+DQogIDxERCANCiAgc3R5bGU9IlBBRERJTkct +UklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMnB4IDdweDsgUEFERElORy1MRUZUOiAx +MnB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9j +c2RuaW5kZXhfcGljNS5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweDsgTElO +RS1IRUlHSFQ6IDE5cHg7IFBBRERJTkctVE9QOiAwcHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0 +aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0aXRsZT3miqXlkI1JQk3lvIDl +j5HogIXlpKfkvJrotaLlpJrph43lpKflpZYgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhU +LURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw5Myk7IGhy +ZWY9Imh0dHA6Ly9nLmNzZG4ubmV0LzUxNjY5MzAiIA0KICB0YXJnZXQ9X2JsYW5rPuaKpeWQjUlC +TeW8gOWPkeiAheWkp+S8mui1ouWkmumHjeWkp+WlljwvQT48L0REPg0KICA8REQgDQogIHN0eWxl +PSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDJweCA3cHg7IFBBRERJ +TkctTEVGVDogMTJweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3 +dy9pbWFnZXMvY3NkbmluZGV4X3BpYzUuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lO +OiAwcHg7IExJTkUtSEVJR0hUOiAxOXB4OyBQQURESU5HLVRPUDogMHB4OyBiYWNrZ3JvdW5kLW9y +aWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgdGl0bGU9IuOA +kOacieWlluOAkeWPguS4juWkqee/vOiwg+afpSDotaLnpZ7np5jnpLzlk4HvvIEiIHN0eWxlPSJD +T0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dD +bGlja0NvdW50KHRoaXMsOTMpOyBocmVmPSJodHRwOi8vZy5jc2RuLm5ldC81MTY1OTA4IiANCiAg +dGFyZ2V0PV9ibGFuaz7jgJDmnInlpZbjgJHlj4LkuI7lpKnnv7zosIPmn6Ug6LWi56We56eY56S8 +PC9BPjwvREQ+DQogIDxERCANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VO +RC1QT1NJVElPTjogMnB4IDdweDsgUEFERElORy1MRUZUOiAxMnB4OyBCQUNLR1JPVU5ELUlNQUdF +OiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljNS5naWYpOyBQ +QURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweDsgTElORS1IRUlHSFQ6IDE5cHg7IFBBRERJ +TkctVE9QOiAwcHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6 +IGluaXRpYWwiPjxBIA0KICB0aXRsZT3lj4LliqDliJvmlrDmna/otaLmgLvpop0yMOS4h+e+jumH +kSBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9u +Y2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDkzKTsgaHJlZj0iaHR0cDovL2cuY3Nkbi5uZXQvNTE2 +NTc2NiIgDQogIHRhcmdldD1fYmxhbms+5Y+C5Yqg5Yib5paw5p2v6LWi5oC76aKdMjDkuIfnvo7p +h5E8L0E+PC9ERD4NCiAgPEREIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JP +VU5ELVBPU0lUSU9OOiAycHggN3B4OyBQQURESU5HLUxFRlQ6IDEycHg7IEJBQ0tHUk9VTkQtSU1B +R0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWM1LmdpZik7 +IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBMSU5FLUhFSUdIVDogMTlweDsgUEFE +RElORy1UT1A6IDBweDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xp +cDogaW5pdGlhbCI+PEEgDQogIHRpdGxlPeOAkOacieWlluiwg+afpeOAkeS8geS4muWuieWFqOet +iee6p+ivhOa1iyBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9u +ZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDkzKTsgaHJlZj0iaHR0cDovL2cuY3Nk +bi5uZXQvNTE2NTU0NSIgDQogIHRhcmdldD1fYmxhbms+44CQ5pyJ5aWW6LCD5p+l44CR5LyB5Lia +5a6J5YWo562J57qn6K+E5rWLPC9BPjwvREQ+DQogIDxERCANCiAgc3R5bGU9IlBBRERJTkctUklH +SFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMnB4IDdweDsgUEFERElORy1MRUZUOiAxMnB4 +OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2Ru +aW5kZXhfcGljNS5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweDsgTElORS1I +RUlHSFQ6IDE5cHg7IFBBRERJTkctVE9QOiAwcHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFs +OyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0aXRsZT3lj4LkuI5JRTnlpKfotZvl +vpflpZbph5HotaLpvKDmoIcgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJ +T046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw5Myk7IGhyZWY9Imh0dHA6 +Ly9nLmNzZG4ubmV0LzUxNjUxOTYiIA0KICB0YXJnZXQ9X2JsYW5rPuWPguS4jklFOeWkp+i1m+W+ +l+WllumHkei1oum8oOaghzwvQT48L0REPg0KICA8REQgDQogIHN0eWxlPSJQQURESU5HLVJJR0hU +OiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDJweCA3cHg7IFBBRERJTkctTEVGVDogMTJweDsg +QkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3Nkbmlu +ZGV4X3BpYzUuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IExJTkUtSEVJ +R0hUOiAxOXB4OyBQQURESU5HLVRPUDogMHB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsg +YmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgdGl0bGU944CQ56iL5bqP5o6o6I2Q44CR +572R56uZ5YaF5a65566h55CG57O757ufIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1E +RUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsOTMpOyBocmVm +PSJodHRwOi8vZy5jc2RuLm5ldC81MTY1MTk1IiANCiAgdGFyZ2V0PV9ibGFuaz7jgJDnqIvluo/m +jqjojZDjgJHnvZHnq5nlhoXlrrnnrqHnkIbns7vnu588L0E+PC9ERD4NCiAgPEREIA0KICBzdHls +ZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAycHggN3B4OyBQQURE +SU5HLUxFRlQ6IDEycHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93 +d3cvaW1hZ2VzL2NzZG5pbmRleF9waWM1LmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJ +TjogMHB4OyBMSU5FLUhFSUdIVDogMTlweDsgUEFERElORy1UT1A6IDBweDsgYmFja2dyb3VuZC1v +cmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxlPSJN +ZWVHb+S4reWbveWMuuW8gOWPkeiAheeglOiuqOS8miDnjrDlnLrnm7Tlh7siIHN0eWxlPSJDT0xP +UjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlj +a0NvdW50KHRoaXMsOTMpOyBocmVmPSJodHRwOi8vZy5jc2RuLm5ldC81MTY1MDc5IiANCiAgdGFy +Z2V0PV9ibGFuaz5NZWVHb+S4reWbveWMuuW8gOWPkeiAheeglOiuqOS8mjwvQT48L0REPg0KICA8 +REQgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDJw +eCA3cHg7IFBBRERJTkctTEVGVDogMTJweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9j +c2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzUuZ2lmKTsgUEFERElORy1CT1RUT006 +IDBweDsgTUFSR0lOOiAwcHg7IExJTkUtSEVJR0hUOiAxOXB4OyBQQURESU5HLVRPUDogMHB4OyBi +YWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSAN +CiAgdGl0bGU9Tm9raWHkuLrku4DkuYjkuI3nlKhBbmRyb2lk77yfIHN0eWxlPSJDT0xPUjogcmdi +KDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50 +KHRoaXMsOTMpOyBocmVmPSJodHRwOi8vZy5jc2RuLm5ldC81MTU4MTE2IiANCiAgdGFyZ2V0PV9i +bGFuaz5Ob2tpYeS4uuS7gOS5iOS4jeeUqEFuZHJvPC9BPjwvREQ+DQogIDxERCANCiAgc3R5bGU9 +IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMnB4IDdweDsgUEFERElO +Ry1MRUZUOiAxMnB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3 +L2ltYWdlcy9jc2RuaW5kZXhfcGljNS5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46 +IDBweDsgTElORS1IRUlHSFQ6IDE5cHg7IFBBRERJTkctVE9QOiAwcHg7IGJhY2tncm91bmQtb3Jp +Z2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0aXRsZT3puKHo +govvvJ/ov5jmmK/mva7mtYHvvJ8gc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09S +QVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw5Myk7IGhyZWY9Imh0 +dHA6Ly9nLmNzZG4ubmV0LzUxNjcxMjciIA0KICB0YXJnZXQ9X2JsYW5rPum4oeiCi++8n+i/mOaY +r+a9rua1ge+8nzwvQT48L0REPg0KICA8REQgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7 +IEJBQ0tHUk9VTkQtUE9TSVRJT046IDJweCA3cHg7IFBBRERJTkctTEVGVDogMTJweDsgQkFDS0dS +T1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3Bp +YzUuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IExJTkUtSEVJR0hUOiAx +OXB4OyBQQURESU5HLVRPUDogMHB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dy +b3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgdGl0bGU9IuelnuWlh+eahFdlYlFRICIgc3R5bGU9 +IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxv +Z0NsaWNrQ291bnQodGhpcyw5Myk7IGhyZWY9Imh0dHA6Ly9nLmNzZG4ubmV0LzUxNTczMTYiIA0K +ICB0YXJnZXQ9X2JsYW5rPuelnuWlh+eahFdlYlFRPC9BPjwvREQ+DQogIDxERCANCiAgc3R5bGU9 +IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMnB4IDdweDsgUEFERElO +Ry1MRUZUOiAxMnB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3 +L2ltYWdlcy9jc2RuaW5kZXhfcGljNS5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46 +IDBweDsgTElORS1IRUlHSFQ6IDE5cHg7IFBBRERJTkctVE9QOiAwcHg7IGJhY2tncm91bmQtb3Jp +Z2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0aXRsZT0iTWVl +R2/mmK/kupLogZTorqHnrpfliJvmlrDliKnlmaggIiBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7 +IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDkz +KTsgaHJlZj0iaHR0cDovL2cuY3Nkbi5uZXQvNTE2NDI2OCIgDQogIHRhcmdldD1fYmxhbms+TWVl +R2/mmK/kupLogZTorqHnrpfliJvmlrDliKnlmag8L0E+PC9ERD4NCiAgPEREIA0KICBzdHlsZT0i +UEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAycHggN3B4OyBQQURESU5H +LUxFRlQ6IDEycHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cv +aW1hZ2VzL2NzZG5pbmRleF9waWM1LmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjog +MHB4OyBMSU5FLUhFSUdIVDogMTlweDsgUEFERElORy1UT1A6IDBweDsgYmFja2dyb3VuZC1vcmln +aW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxlPeW3peWF +t+aOqOiNkO+8muW7tumVv+eUteaxoOe7reiIquaXtumXtCBzdHlsZT0iQ09MT1I6IHJnYigwLDAs +MCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlz +LDkzKTsgaHJlZj0iaHR0cDovL2cuY3Nkbi5uZXQvNTE2NDE1MyIgDQogIHRhcmdldD1fYmxhbms+ +5bel5YW35o6o6I2Q77ya5bu26ZW/55S15rGg57ut6Iiq5pe26Ze0PC9BPjwvREQ+DQogIDxERCAN +CiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMnB4IDdw +eDsgUEFERElORy1MRUZUOiAxMnB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5p +bWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljNS5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4 +OyBNQVJHSU46IDBweDsgTElORS1IRUlHSFQ6IDE5cHg7IFBBRERJTkctVE9QOiAwcHg7IGJhY2tn +cm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0 +aXRsZT3oi7HnibnlsJTlt6XlhbfmjqjojZDvvJror4TkvLDlpJrmoLjns7vnu5/mgKfog70gc3R5 +bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNr +PUxvZ0NsaWNrQ291bnQodGhpcyw5Myk7IGhyZWY9Imh0dHA6Ly9nLmNzZG4ubmV0LzUxNjQxNTUi +IA0KICB0YXJnZXQ9X2JsYW5rPuiLseeJueWwlOW3peWFt+aOqOiNkO+8muivhOS8sOWkmuaguOez +u+e7n+aApzwvQT48L0REPjwvREw+PC9ESVY+PC9ESVY+DQo8RElWIGNsYXNzPXBhZ2VibG9jazJf +d3JhcCBzdHlsZT0iRkxPQVQ6IGxlZnQ7IFdJRFRIOiA3MzVweCI+DQo8RElWIGNsYXNzPXBhZ2Vj +b25fbGF5ZXIyX2xlZnQgDQpzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBESVNQTEFZOiBpbmxp +bmU7IFBBRERJTkctTEVGVDogMHB4OyBGTE9BVDogbGVmdDsgUEFERElORy1CT1RUT006IDVweDsg +TUFSR0lOOiAwcHggMHB4IDBweCAxcHg7IFdJRFRIOiA0NzBweDsgUEFERElORy1UT1A6IDBweCI+ +DQo8SDYgDQpzdHlsZT0iQ0xFQVI6IGJvdGg7IFBBRERJTkctUklHSFQ6IDBweDsgQk9SREVSLVRP +UDogcmdiKDIwNCwyMDQsMjA0KSAxcHggc29saWQ7IFBBRERJTkctTEVGVDogMTBweDsgRk9OVC1T +SVpFOiAxNHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2lt +YWdlcy9jc2RuaW5kZXhfcGljMTEuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAw +cHg7IFBBRERJTkctVE9QOiA1cHg7IFBPU0lUSU9OOiByZWxhdGl2ZTsgSEVJR0hUOiAyOXB4OyBi +YWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj7otYTo +rq88U1BBTiANCmNsYXNzPXR4dF9ibGFjayANCnN0eWxlPSJGT05ULVdFSUdIVDogbm9ybWFsOyBG +T05ULVNJWkU6IDEycHg7IE1BUkdJTjogMHB4IDBweCAwcHggMTVweDsgQ09MT1I6IHJnYigwLDAs +MCkiPiZuYnNwOzxBIA0Kc3R5bGU9IlBBRERJTkctUklHSFQ6IDNweDsgUEFERElORy1MRUZUOiAz +cHg7IFBBRERJTkctQk9UVE9NOiAwcHg7IENPTE9SOiByZ2IoMCwwLDApOyBQQURESU5HLVRPUDog +MHB4OyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KaHJlZj0iaHR0cDovL2VkdS5jc2RuLm5ldC9o +ZWltYS8iPjEzNjLkurrnlLPor7fliqDlhaUi6buR6ams56iL5bqP5ZGYIuW+heWuoTwvQT4mbmJz +cDsmbmJzcDs8QSANCnN0eWxlPSJQQURESU5HLVJJR0hUOiAzcHg7IFBBRERJTkctTEVGVDogM3B4 +OyBQQURESU5HLUJPVFRPTTogMHB4OyBDT0xPUjogcmdiKDAsMCwwKTsgUEFERElORy1UT1A6IDBw +eDsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCmhyZWY9Imh0dHA6Ly93d3cuaXRjYXN0LmNuL2l0 +Y2FzdF9zdGF0aWMvamF2YWp6MS5odG0iPuW8oOWtneelpWphdmHlsLHkuJrmlLvnlaU8L0E+PC9T +UEFOPjxFTSANCmNsYXNzPXR4dF9ibHVlIA0Kc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFD +S0dST1VORC1QT1NJVElPTjogMHB4IDRweDsgUEFERElORy1MRUZUOiAxMHB4OyBGT05ULVdFSUdI +VDogbm9ybWFsOyBGT05ULVNJWkU6IDEycHg7IExFRlQ6IDQxMHB4OyBCQUNLR1JPVU5ELUlNQUdF +OiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMTIuZ2lmKTsg +UEFERElORy1CT1RUT006IDBweDsgQ09MT1I6IHJnYigxLDk1LDE4Mik7IFBBRERJTkctVE9QOiAw +cHg7IEZPTlQtU1RZTEU6IG5vcm1hbDsgUE9TSVRJT046IGFic29sdXRlOyBUT1A6IDZweDsgYmFj +a2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQpz +dHlsZT0iUEFERElORy1SSUdIVDogM3B4OyBQQURESU5HLUxFRlQ6IDNweDsgUEFERElORy1CT1RU +T006IDBweDsgQ09MT1I6IHJnYigxLDk1LDE4Mik7IFBBRERJTkctVE9QOiAwcHg7IFRFWFQtREVD +T1JBVElPTjogdW5kZXJsaW5lIiANCmhyZWY9Imh0dHA6Ly9uZXdzLmNzZG4ubmV0LyIgdGFyZ2V0 +PV9ibGFuaz7mm7TlpJo8L0E+PC9FTT48L0g2Pg0KPERJViBjbGFzcz1wYWdlY29uX2xheWVyMl9s +ZWZ0Y29uIA0Kc3R5bGU9IlBBRERJTkctUklHSFQ6IDEwcHg7IFBBRERJTkctTEVGVDogMTBweDsg +RkxPQVQ6IGxlZnQ7IFBBRERJTkctQk9UVE9NOiA1cHg7IFdJRFRIOiA0NTBweDsgUEFERElORy1U +T1A6IDVweCI+DQo8REwgDQpzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBQQURESU5HLUxFRlQ6 +IDBweDsgUEFERElORy1CT1RUT006IDJweDsgTUFSR0lOOiAzcHggMHB4OyBMSU5FLUhFSUdIVDog +MjFweDsgUEFERElORy1UT1A6IDBweDsgUE9TSVRJT046IHJlbGF0aXZlIj4NCiAgPERUIGNsYXNz +PXR4dF9ibGFjayANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJ +VElPTjogMHB4IDhweDsgUEFERElORy1MRUZUOiAxMHB4OyBGT05ULVNJWkU6IDE0cHg7IEJBQ0tH +Uk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9w +aWMyNi5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDNweCAwcHg7IENPTE9SOiBy +Z2IoMCwwLDApOyBQQURESU5HLVRPUDogMHB4OyBQT1NJVElPTjogcmVsYXRpdmU7IGJhY2tncm91 +bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICBzdHls +ZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9 +TG9nQ2xpY2tDb3VudCh0aGlzLDcyKTsgDQogIGhyZWY9Imh0dHA6Ly9jbG91ZC5jc2RuLm5ldC9h +LzIwMTAxMjE1LzI4MzY4OC5odG1sIiANCiAgdGFyZ2V0PV9ibGFuaz5HYXJ0bmVy6aKE6K6h5LuK +5bm05YWo55CD5LyB5LiaU2FhU+aUtuWFpeWinumVvzE1LjclPC9BPjxTUEFOIGNsYXNzPXR4dF9i +bHVlIA0KICBzdHlsZT0iRk9OVC1TSVpFOiAxMnB4OyBNQVJHSU46IDBweCAwcHggMHB4IDhweDsg +Q09MT1I6IHJnYigxLDk1LDE4MikiPjxBIA0KICBzdHlsZT0iQ09MT1I6IHJnYigxLDk1LDE4Mik7 +IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIGhyZWY9Imh0dHA6Ly9jbG91ZC5jc2RuLm5ldC8i +IHRhcmdldD1fYmxhbms+5aSa5qC35YyW5bqU55So5bim5p2l566h55CG5oyR5oiYPC9BPjwvU1BB +Tj48L0RUPg0KICA8RFQgY2xhc3M9dHh0X2JsYWNrIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDog +MHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAwcHggOHB4OyBQQURESU5HLUxFRlQ6IDEwcHg7IEZP +TlQtU0laRTogMTRweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3 +dy9pbWFnZXMvY3NkbmluZGV4X3BpYzI2LmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJ +TjogM3B4IDBweDsgQ09MT1I6IHJnYigwLDAsMCk7IFBBRERJTkctVE9QOiAwcHg7IFBPU0lUSU9O +OiByZWxhdGl2ZTsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDog +aW5pdGlhbCI+PEEgDQogIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9O +OiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsNzIpOyANCiAgaHJlZj0iaHR0 +cDovL25ld3MuY3Nkbi5uZXQvYS8yMDEwMTIxNS8yODM5NzAuaHRtbCIgDQogIHRhcmdldD1fYmxh +bms+55Sy6aqo5paH5Ymv5oC76LCI6J6N5ZCI5bqU55So6L2v5Lu25LiJ5aSn5oiY55Wl5Z+656GA +IOaJgOacieS6p+WTgemdouWQkeS6keiuoeeul+W8gOWPkTwvQT48U1BBTiBjbGFzcz10eHRfYmx1 +ZSANCiAgc3R5bGU9IkZPTlQtU0laRTogMTJweDsgTUFSR0lOOiAwcHggMHB4IDBweCA4cHg7IENP +TE9SOiByZ2IoMSw5NSwxODIpIj48QSANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMSw5NSwxODIpOyBU +RVhULURFQ09SQVRJT046IG5vbmUiIA0KICBocmVmPSJodHRwOi8vbmV3cy5jc2RuLm5ldC9hLzIw +MTAxMjE1LzI4Mzk3MC5odG1sIiANCiAgdGFyZ2V0PV9ibGFuaz48L0E+PC9TUEFOPjwvRFQ+DQog +IDxEVCBjbGFzcz10eHRfYmxhY2sgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tH +Uk9VTkQtUE9TSVRJT046IDBweCA4cHg7IFBBRERJTkctTEVGVDogMTBweDsgRk9OVC1TSVpFOiAx +NHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9j +c2RuaW5kZXhfcGljMjYuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAzcHggMHB4 +OyBDT0xPUjogcmdiKDAsMCwwKTsgUEFERElORy1UT1A6IDBweDsgUE9TSVRJT046IHJlbGF0aXZl +OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48 +QSANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0K +ICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw3Mik7IA0KICBocmVmPSJodHRwOi8vY2xvdWQu +Y3Nkbi5uZXQvYS8yMDEwMTIxNS8yODM2ODEuaHRtbCIgdGFyZ2V0PV9ibGFuaz7llYbkuJrlkajl +iIrvvJpDaHJvbWUgDQogIE9T5a6a5L2N5qih57OK5YmN5pmv6buv5rehPC9BPjxTUEFOIGNsYXNz +PXR4dF9ibHVlIA0KICBzdHlsZT0iRk9OVC1TSVpFOiAxMnB4OyBNQVJHSU46IDBweCAwcHggMHB4 +IDhweDsgQ09MT1I6IHJnYigxLDk1LDE4MikiPjxBIA0KICBzdHlsZT0iQ09MT1I6IHJnYigxLDk1 +LDE4Mik7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIGhyZWY9Imh0dHA6Ly9jbG91ZC5jc2Ru +Lm5ldC8iIHRhcmdldD1fYmxhbms+57y65LmP56S+5Lqk5ZKM5a6e5pe25bqU55SoPC9BPjwvU1BB +Tj48L0RUPg0KICA8RFQgY2xhc3M9dHh0X2JsYWNrIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDog +MHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAwcHggOHB4OyBQQURESU5HLUxFRlQ6IDEwcHg7IEZP +TlQtU0laRTogMTRweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3 +dy9pbWFnZXMvY3NkbmluZGV4X3BpYzI2LmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJ +TjogM3B4IDBweDsgQ09MT1I6IHJnYigwLDAsMCk7IFBBRERJTkctVE9QOiAwcHg7IFBPU0lUSU9O +OiByZWxhdGl2ZTsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDog +aW5pdGlhbCI+PEEgDQogIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9O +OiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsNzIpOyANCiAgaHJlZj0iaHR0 +cDovL25ld3MuY3Nkbi5uZXQvYS8yMDEwMTIxNS8yODM2ODAuaHRtbCIgDQogIHRhcmdldD1fYmxh +bms+6ZuF6JmOQ0VP5be06Iyo5pS+5byD6L+b5YWl6Zi/6YeM5be05be06JGj5LqL5LyaPC9BPjxT +UEFOIGNsYXNzPXR4dF9ibHVlIA0KICBzdHlsZT0iRk9OVC1TSVpFOiAxMnB4OyBNQVJHSU46IDBw +eCAwcHggMHB4IDhweDsgQ09MT1I6IHJnYigxLDk1LDE4MikiPjxBIA0KICBzdHlsZT0iQ09MT1I6 +IHJnYigxLDk1LDE4Mik7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIGhyZWY9Imh0dHA6Ly9u +ZXdzLmNzZG4ubmV0L2EvMjAxMDEyMTUvMjgzNjgyLmh0bWwiIA0KICB0YXJnZXQ9X2JsYW5rPumb +heiZjumbh+WRmOensOW3suiiq+ino+mbhzwvQT48L1NQQU4+PC9EVD4NCiAgPERUIGNsYXNzPXR4 +dF9ibGFjayANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElP +TjogMHB4IDhweDsgUEFERElORy1MRUZUOiAxMHB4OyBGT05ULVNJWkU6IDE0cHg7IEJBQ0tHUk9V +TkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMy +Ni5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDNweCAwcHg7IENPTE9SOiByZ2Io +MCwwLDApOyBQQURESU5HLVRPUDogMHB4OyBQT1NJVElPTjogcmVsYXRpdmU7IGJhY2tncm91bmQt +b3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICBzdHlsZT0i +Q09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9n +Q2xpY2tDb3VudCh0aGlzLDcyKTsgDQogIGhyZWY9Imh0dHA6Ly9uZXdzLmNzZG4ubmV0L2EvMjAx +MDEyMTUvMjgzNjc3Lmh0bWwiIA0KICB0YXJnZXQ9X2JsYW5rPuiwt+atjOmmluW4reW3peeoi+W4 +iO+8muWdmuaMgeeul+azleWOn+WImSDkuI3mjrrkuLvop4LoibLlvak8L0E+PFNQQU4gY2xhc3M9 +dHh0X2JsdWUgDQogIHN0eWxlPSJGT05ULVNJWkU6IDEycHg7IE1BUkdJTjogMHB4IDBweCAwcHgg +OHB4OyBDT0xPUjogcmdiKDEsOTUsMTgyKSI+PEEgDQogIHN0eWxlPSJDT0xPUjogcmdiKDEsOTUs +MTgyKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgaHJlZj0iaHR0cDovL25ld3MuY3Nkbi5u +ZXQvIiB0YXJnZXQ9X2JsYW5rPuS4jeWBj+iikuS7u+S9leWTgeeJjDwvQT48L1NQQU4+PC9EVD4N +CiAgPERUIGNsYXNzPXR4dF9ibGFjayANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFD +S0dST1VORC1QT1NJVElPTjogMHB4IDhweDsgUEFERElORy1MRUZUOiAxMHB4OyBGT05ULVNJWkU6 +IDE0cHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2Vz +L2NzZG5pbmRleF9waWMyNi5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDNweCAw +cHg7IENPTE9SOiByZ2IoMCwwLDApOyBQQURESU5HLVRPUDogMHB4OyBQT1NJVElPTjogcmVsYXRp +dmU7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwi +PjxBIA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIg +DQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDcyKTsgDQogIGhyZWY9Imh0dHA6Ly9uZXdz +LmNzZG4ubmV0L2EvMjAxMDEyMTUvMjgzNjY3Lmh0bWwiIA0KICB0YXJnZXQ9X2JsYW5rPueJueer +i+eLrOihjOeahOeoi+W6j+WRmO+8mue7tOWfuuino+WvhuWIm+Wni+S6uumYv+ahkeWlh+S8oOWl +hzwvQT48U1BBTiBjbGFzcz10eHRfYmx1ZSANCiAgc3R5bGU9IkZPTlQtU0laRTogMTJweDsgTUFS +R0lOOiAwcHggMHB4IDBweCA4cHg7IENPTE9SOiByZ2IoMSw5NSwxODIpIj48QSANCiAgc3R5bGU9 +IkNPTE9SOiByZ2IoMSw5NSwxODIpOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBocmVmPSJo +dHRwOi8vbmV3cy5jc2RuLm5ldC9hLzIwMTAxMjE1LzI4MzY2Ny5odG1sIiANCiAgdGFyZ2V0PV9i +bGFuaz7nu4/ljoblnY7lnbfmgJ3mg7Pmt7HliLs8L0E+PC9TUEFOPjwvRFQ+DQogIDxERCBjbGFz +cz1uZXdzX3R5cGVhIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBQQURESU5HLUxFRlQ6 +IDBweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMv +Y3NkbmluZGV4X3BpYzQ2LmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogLTNweCAw +cHggMTBweDsgUEFERElORy1UT1A6IDBweDsgUE9TSVRJT046IHJlbGF0aXZlOyBIRUlHSFQ6IDE5 +cHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwi +PjxFTSANCiAgc3R5bGU9IkxFRlQ6IDM4MnB4OyBDT0xPUjogcmdiKDI1NSwyNTUsMjU1KTsgRk9O +VC1TVFlMRTogbm9ybWFsOyBQT1NJVElPTjogYWJzb2x1dGU7IFRPUDogMnB4Ij7kuJrnlYzkuI7k +urrniak8L0VNPjwvREQ+DQogIDxEVCBjbGFzcz10eHRfYmxhY2sgDQogIHN0eWxlPSJQQURESU5H +LVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDBweCA4cHg7IFBBRERJTkctTEVGVDog +MTBweDsgRk9OVC1TSVpFOiAxNHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5p +bWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMjYuZ2lmKTsgUEFERElORy1CT1RUT006IDBw +eDsgTUFSR0lOOiAzcHggMHB4OyBDT0xPUjogcmdiKDAsMCwwKTsgUEFERElORy1UT1A6IDBweDsg +UE9TSVRJT046IHJlbGF0aXZlOyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3Vu +ZC1jbGlwOiBpbml0aWFsIj48QSANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURF +Q09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw3Myk7IA0KICBo +cmVmPSJodHRwOi8vbmV3cy5jc2RuLm5ldC9hLzIwMTAxMjE1LzI4MzY5My5odG1sIiANCiAgdGFy +Z2V0PV9ibGFuaz5GYWNlYm9va+aOqEZtYWls5oyR5oiYRW1haWwgNjIl5Y+X6K6/6ICF5LiN6ICD +6JmRPC9BPjxTUEFOIGNsYXNzPXR4dF9ibHVlIA0KICBzdHlsZT0iRk9OVC1TSVpFOiAxMnB4OyBN +QVJHSU46IDBweCAwcHggMHB4IDhweDsgQ09MT1I6IHJnYigxLDk1LDE4MikiPjxBIA0KICBzdHls +ZT0iQ09MT1I6IHJnYigxLDk1LDE4Mik7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIGhyZWY9 +Imh0dHA6Ly9uZXdzLmNzZG4ubmV0LyIgdGFyZ2V0PV9ibGFuaz7npL7kuqTnvZHnu5zlj5jouqvp +gJrorq/lubPlj7A8L0E+PC9TUEFOPjwvRFQ+DQogIDxEVCBjbGFzcz10eHRfYmxhY2sgDQogIHN0 +eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDBweCA4cHg7IFBB +RERJTkctTEVGVDogMTBweDsgRk9OVC1TSVpFOiAxNHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwo +aHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMjYuZ2lmKTsgUEFERElO +Ry1CT1RUT006IDBweDsgTUFSR0lOOiAzcHggMHB4OyBDT0xPUjogcmdiKDAsMCwwKTsgUEFERElO +Ry1UT1A6IDBweDsgUE9TSVRJT046IHJlbGF0aXZlOyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlh +bDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCww +LDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhp +cyw3Myk7IA0KICBocmVmPSJodHRwOi8vbW9iaWxlLmNzZG4ubmV0L24vMjAxMDEyMTUvMjgzNjc2 +Lmh0bWwiIA0KICB0YXJnZXQ9X2JsYW5rPuW+rui9r+WumOaWueWuo+ensOWwhuS6jjIwMTHlubTk +uIvljYrlubTlnKjkuK3lm73mjqjlh7pXaW5kb3dzIFBob25lIDc8L0E+PFNQQU4gY2xhc3M9dHh0 +X2JsdWUgDQogIHN0eWxlPSJGT05ULVNJWkU6IDEycHg7IE1BUkdJTjogMHB4IDBweCAwcHggOHB4 +OyBDT0xPUjogcmdiKDEsOTUsMTgyKSI+PEEgDQogIHN0eWxlPSJDT0xPUjogcmdiKDEsOTUsMTgy +KTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgaHJlZj0iaHR0cDovL3d3dy5jc2RuLm5ldC8i +IHRhcmdldD1fYmxhbms+PC9BPjwvU1BBTj48L0RUPg0KICA8RFQgY2xhc3M9dHh0X2JsYWNrIA0K +ICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAwcHggOHB4 +OyBQQURESU5HLUxFRlQ6IDEwcHg7IEZPTlQtU0laRTogMTRweDsgQkFDS0dST1VORC1JTUFHRTog +dXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzI2LmdpZik7IFBB +RERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogM3B4IDBweDsgQ09MT1I6IHJnYigwLDAsMCk7IFBB +RERJTkctVE9QOiAwcHg7IFBPU0lUSU9OOiByZWxhdGl2ZTsgYmFja2dyb3VuZC1vcmlnaW46IGlu +aXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHN0eWxlPSJDT0xPUjogcmdi +KDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50 +KHRoaXMsNzMpOyANCiAgaHJlZj0iaHR0cDovL21vYmlsZS5jc2RuLm5ldC9uLzIwMTAxMjE1LzI4 +MzY3My5odG1sIiANCiAgdGFyZ2V0PV9ibGFuaz7or7rln7rkuprmmI7lubTmi5/lr7nloZ7nj63n +s7vnu5/ov5vooYw05YiwNeasoeWNh+e6pzwvQT48U1BBTiBjbGFzcz10eHRfYmx1ZSANCiAgc3R5 +bGU9IkZPTlQtU0laRTogMTJweDsgTUFSR0lOOiAwcHggMHB4IDBweCA4cHg7IENPTE9SOiByZ2Io +MSw5NSwxODIpIj48QSANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMSw5NSwxODIpOyBURVhULURFQ09S +QVRJT046IG5vbmUiIA0KICBocmVmPSJodHRwOi8vbW9iaWxlLmNzZG4ubmV0LyIgdGFyZ2V0PV9i +bGFuaz7lop7liqDkuLvpobXphY3nva7ngbXmtLvmgKc8L0E+PC9TUEFOPjwvRFQ+DQogIDxEVCBj +bGFzcz10eHRfYmxhY2sgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQt +UE9TSVRJT046IDBweCA4cHg7IFBBRERJTkctTEVGVDogMTBweDsgRk9OVC1TSVpFOiAxNHB4OyBC +QUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5k +ZXhfcGljMjYuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAzcHggMHB4OyBDT0xP +UjogcmdiKDAsMCwwKTsgUEFERElORy1UT1A6IDBweDsgUE9TSVRJT046IHJlbGF0aXZlOyBiYWNr +Z3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAg +c3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNs +aWNrPUxvZ0NsaWNrQ291bnQodGhpcyw3Myk7IA0KICBocmVmPSJodHRwOi8vbmV3cy5jc2RuLm5l +dC9hLzIwMTAxMjExLzI4MzQ2MC5odG1sIiANCiAgdGFyZ2V0PV9ibGFuaz5bU0QyLjBd5Yib5paw +5bel5Zy66JSh5a2m6ZWb77ya6aKG5Z+f6K+t6KiA55qE6K6+6K6h5LiO5a6e6Le1PC9BPjxTUEFO +IGNsYXNzPXR4dF9ibHVlIA0KICBzdHlsZT0iRk9OVC1TSVpFOiAxMnB4OyBNQVJHSU46IDBweCAw +cHggMHB4IDhweDsgQ09MT1I6IHJnYigxLDk1LDE4MikiPjxBIA0KICBzdHlsZT0iQ09MT1I6IHJn +YigxLDk1LDE4Mik7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIGhyZWY9Imh0dHA6Ly9uZXdz +LmNzZG4ubmV0L2EvMjAxMDEyMTEvMjgzNDU5Lmh0bWwiIA0KICB0YXJnZXQ9X2JsYW5rPuW8guat +pee8lueoi+aooeWei+eahOa8lOWPmDwvQT48L1NQQU4+PC9EVD4NCiAgPERUIGNsYXNzPXR4dF9i +bGFjayANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjog +MHB4IDhweDsgUEFERElORy1MRUZUOiAxMHB4OyBGT05ULVNJWkU6IDE0cHg7IEJBQ0tHUk9VTkQt +SU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMyNi5n +aWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDNweCAwcHg7IENPTE9SOiByZ2IoMCww +LDApOyBQQURESU5HLVRPUDogMHB4OyBQT1NJVElPTjogcmVsYXRpdmU7IGJhY2tncm91bmQtb3Jp +Z2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICBzdHlsZT0iQ09M +T1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xp +Y2tDb3VudCh0aGlzLDczKTsgDQogIGhyZWY9Imh0dHA6Ly9uZXdzLmNzZG4ubmV0L2EvMjAxMDEy +MTUvMjgzNjcyLmh0bWwiIHRhcmdldD1fYmxhbms+Q2hyb21lIA0KICBPU+Wvueiwt+atjOacquad +peWinumVv+iHs+WFs+mHjeimgeeahDEw5Liq55CG55SxPC9BPjxTUEFOIGNsYXNzPXR4dF9ibHVl +IA0KICBzdHlsZT0iRk9OVC1TSVpFOiAxMnB4OyBNQVJHSU46IDBweCAwcHggMHB4IDhweDsgQ09M +T1I6IHJnYigxLDk1LDE4MikiPjxBIA0KICBzdHlsZT0iQ09MT1I6IHJnYigxLDk1LDE4Mik7IFRF +WFQtREVDT1JBVElPTjogbm9uZSIgDQogIGhyZWY9Imh0dHA6Ly9uZXdzLmNzZG4ubmV0LyIgdGFy +Z2V0PV9ibGFuaz7ln7rkuo5XZWLmk43kvZzns7vnu5/mmK/mnKrmnaU8L0E+PC9TUEFOPjwvRFQ+ +DQogIDxEVCBjbGFzcz10eHRfYmxhY2sgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJB +Q0tHUk9VTkQtUE9TSVRJT046IDBweCA4cHg7IFBBRERJTkctTEVGVDogMTBweDsgRk9OVC1TSVpF +OiAxNHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdl +cy9jc2RuaW5kZXhfcGljMjYuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAzcHgg +MHB4OyBDT0xPUjogcmdiKDAsMCwwKTsgUEFERElORy1UT1A6IDBweDsgUE9TSVRJT046IHJlbGF0 +aXZlOyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFs +Ij48QSANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUi +IA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw3Myk7IA0KICBocmVmPSJodHRwOi8vbW9i +aWxlLmNzZG4ubmV0L24vMjAxMDEyMTUvMjgzNjYzLmh0bWwiIA0KICB0YXJnZXQ9X2JsYW5rPlvm +jqjojZDpmIXor7td5omT6YCg56e75Yqo5byA5Y+R5Zui6Zif55qE5LqU5Liq5bi46KeB6K+v5Yy6 +PC9BPjxTUEFOIGNsYXNzPXR4dF9ibHVlIA0KICBzdHlsZT0iRk9OVC1TSVpFOiAxMnB4OyBNQVJH +SU46IDBweCAwcHggMHB4IDhweDsgQ09MT1I6IHJnYigxLDk1LDE4MikiPjxBIA0KICBzdHlsZT0i +Q09MT1I6IHJnYigxLDk1LDE4Mik7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIGhyZWY9Imh0 +dHA6Ly9tb2JpbGUuY3Nkbi5uZXQvbi8yMDEwMTIxNS8yODM2NjMuaHRtbCIgDQogIHRhcmdldD1f +Ymxhbms+5p2l6IeqR29vZ2xl56e75Yqo5Zui6Zif55qE57uP6aqMPC9BPjwvU1BBTj48L0RUPg0K +ICA8REQgY2xhc3M9bmV3c190eXBlYSANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgUEFE +RElORy1MRUZUOiAwcHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93 +d3cvaW1hZ2VzL2NzZG5pbmRleF9waWM0Ni5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJH +SU46IC0zcHggMHB4IDEwcHg7IFBBRERJTkctVE9QOiAwcHg7IFBPU0lUSU9OOiByZWxhdGl2ZTsg +SEVJR0hUOiAxOXB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlw +OiBpbml0aWFsIj48RU0gDQogIHN0eWxlPSJMRUZUOiAzODJweDsgQ09MT1I6IHJnYigyNTUsMjU1 +LDI1NSk7IEZPTlQtU1RZTEU6IG5vcm1hbDsgUE9TSVRJT046IGFic29sdXRlOyBUT1A6IDJweCI+ +5oqA5pyv5LiO5Lqn5ZOBPC9FTT48L0REPg0KICA8RFQgY2xhc3M9dHh0X2JsYWNrIA0KICBzdHls +ZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAwcHggOHB4OyBQQURE +SU5HLUxFRlQ6IDEwcHg7IEZPTlQtU0laRTogMTRweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0 +dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzI2LmdpZik7IFBBRERJTkct +Qk9UVE9NOiAwcHg7IE1BUkdJTjogM3B4IDBweDsgQ09MT1I6IHJnYigwLDAsMCk7IFBBRERJTkct +VE9QOiAwcHg7IFBPU0lUSU9OOiByZWxhdGl2ZTsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7 +IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHN0eWxlPSJDT0xPUjogcmdiKDAsMCww +KTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMs +NzQpOyANCiAgaHJlZj0iaHR0cDovL3ZpcG5ld3MuY3Nkbi5uZXQvQWN0aXZpdGllcy5hc3B4P3Bv +aW50aWQ9MjAxMF8xMV8yM18xMzA0MzI4MjgiIA0KICB0YXJnZXQ9X2JsYW5rPuS4reWbveeUteS/ +oeWkqee/vOepuumXtOWQiOS9nOS8meS8tOS6pOa1geiuuuWdm++8iOWOpumXqOerme+8ieWPrOW8 +gDwvQT48U1BBTiBjbGFzcz10eHRfYmx1ZSANCiAgc3R5bGU9IkZPTlQtU0laRTogMTJweDsgTUFS +R0lOOiAwcHggMHB4IDBweCA4cHg7IENPTE9SOiByZ2IoMSw5NSwxODIpIj48QSANCiAgc3R5bGU9 +IkNPTE9SOiByZ2IoMSw5NSwxODIpOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBocmVmPSJo +dHRwOi8vdmlwbmV3cy5jc2RuLm5ldC9BY3Rpdml0aWVzLmFzcHg/cG9pbnRpZD0yMDEwXzExXzIz +XzEzMDQzMjgyOCIgDQogIHRhcmdldD1fYmxhbms+5b2T5Yqo5ryr6YGH5LiK55S15L+hPC9BPjwv +U1BBTj48L0RUPg0KICA8RFQgY2xhc3M9dHh0X2JsYWNrIA0KICBzdHlsZT0iUEFERElORy1SSUdI +VDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAwcHggOHB4OyBQQURESU5HLUxFRlQ6IDEwcHg7 +IEZPTlQtU0laRTogMTRweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNu +L3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzI2LmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1B +UkdJTjogM3B4IDBweDsgQ09MT1I6IHJnYigwLDAsMCk7IFBBRERJTkctVE9QOiAwcHg7IFBPU0lU +SU9OOiByZWxhdGl2ZTsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xp +cDogaW5pdGlhbCI+PEEgDQogIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFU +SU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsNzQpOyANCiAgaHJlZj0i +aHR0cDovL25ld3MuY3Nkbi5uZXQvYS8yMDEwMTIxNS8yODM5NjYuaHRtbCIgDQogIHRhcmdldD1f +Ymxhbms+5paw5rWq5b6u5Y2a5byA5Y+R6ICF5Yib5paw5Z+66YeR5byA5aeL5o6l5Y+X55Sz6K+3 +PC9BPjxTUEFOIGNsYXNzPXR4dF9ibHVlIA0KICBzdHlsZT0iRk9OVC1TSVpFOiAxMnB4OyBNQVJH +SU46IDBweCAwcHggMHB4IDhweDsgQ09MT1I6IHJnYigxLDk1LDE4MikiPjxBIA0KICBzdHlsZT0i +Q09MT1I6IHJnYigxLDk1LDE4Mik7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIGhyZWY9Imh0 +dHA6Ly9uZXdzLmNzZG4ubmV0LyIgdGFyZ2V0PV9ibGFuaz7ljZXnrJTmipXotYQzMDDkuIdSTULk +u6XkuIs8L0E+PC9TUEFOPjwvRFQ+DQogIDxEVCBjbGFzcz10eHRfYmxhY2sgDQogIHN0eWxlPSJQ +QURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDBweCA4cHg7IFBBRERJTkct +TEVGVDogMTBweDsgRk9OVC1TSVpFOiAxNHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDov +L2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMjYuZ2lmKTsgUEFERElORy1CT1RU +T006IDBweDsgTUFSR0lOOiAzcHggMHB4OyBDT0xPUjogcmdiKDAsMCwwKTsgUEFERElORy1UT1A6 +IDBweDsgUE9TSVRJT046IHJlbGF0aXZlOyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFj +a2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBU +RVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw3NCk7 +IA0KICBocmVmPSJodHRwOi8vY2xvdWQuY3Nkbi5uZXQvYS8yMDEwMTIxNS8yODM2NzguaHRtbCIg +DQogIHRhcmdldD1fYmxhbms+57u05Z+66Kej5a+G5Li756uZ54K5V2lraUxlYWtzLm9yZ+WcqOe+ +juWbveaBouWkjeiuv+mXrjwvQT48U1BBTiBjbGFzcz10eHRfYmx1ZSANCiAgc3R5bGU9IkZPTlQt +U0laRTogMTJweDsgTUFSR0lOOiAwcHggMHB4IDBweCA4cHg7IENPTE9SOiByZ2IoMSw5NSwxODIp +Ij48QSANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMSw5NSwxODIpOyBURVhULURFQ09SQVRJT046IG5v +bmUiIA0KICBocmVmPSJodHRwOi8vY2xvdWQuY3Nkbi5uZXQvIiB0YXJnZXQ9X2JsYW5rPuWFqOeQ +g+W7uueri+i2hTEwMDDplZzlg488L0E+PC9TUEFOPjwvRFQ+DQogIDxEVCBjbGFzcz10eHRfYmxh +Y2sgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDBw +eCA4cHg7IFBBRERJTkctTEVGVDogMTBweDsgRk9OVC1TSVpFOiAxNHB4OyBCQUNLR1JPVU5ELUlN +QUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMjYuZ2lm +KTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAzcHggMHB4OyBDT0xPUjogcmdiKDAsMCww +KTsgUEFERElORy1UT1A6IDBweDsgUE9TSVRJT046IHJlbGF0aXZlOyBiYWNrZ3JvdW5kLW9yaWdp +bjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgc3R5bGU9IkNPTE9S +OiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNr +Q291bnQodGhpcyw3NCk7IA0KICBocmVmPSJodHRwOi8vY2xvdWQuY3Nkbi5uZXQvYS8yMDEwMTIx +NS8yODM2NjkuaHRtbCIgDQogIHRhcmdldD1fYmxhbms+6LC35q2M5Li6QXBhY2hl5omA5pyJ5byA +5rqQ6aG555uu5o+Q5L6b5paw55qE5bGV56S66aG16Z2iPC9BPjxTUEFOIGNsYXNzPXR4dF9ibHVl +IA0KICBzdHlsZT0iRk9OVC1TSVpFOiAxMnB4OyBNQVJHSU46IDBweCAwcHggMHB4IDhweDsgQ09M +T1I6IHJnYigxLDk1LDE4MikiPjxBIA0KICBzdHlsZT0iQ09MT1I6IHJnYigxLDk1LDE4Mik7IFRF +WFQtREVDT1JBVElPTjogbm9uZSIgDQogIGhyZWY9Imh0dHA6Ly9jbG91ZC5jc2RuLm5ldC8iIHRh +cmdldD1fYmxhbms+5LiN5YaN55SxQXBhY2hl57uE57uH55u05o6l566h55CGPC9BPjwvU1BBTj48 +L0RUPg0KICA8RFQgY2xhc3M9dHh0X2JsYWNrIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4 +OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAwcHggOHB4OyBQQURESU5HLUxFRlQ6IDEwcHg7IEZPTlQt +U0laRTogMTRweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9p +bWFnZXMvY3NkbmluZGV4X3BpYzI2LmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjog +M3B4IDBweDsgQ09MT1I6IHJnYigwLDAsMCk7IFBBRERJTkctVE9QOiAwcHg7IFBPU0lUSU9OOiBy +ZWxhdGl2ZTsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5p +dGlhbCI+PEEgDQogIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBu +b25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsNzQpOyANCiAgaHJlZj0iaHR0cDov +L25ld3MuY3Nkbi5uZXQvYS8yMDEwMTIxMy8yODM1NDUuaHRtbCIgdGFyZ2V0PV9ibGFuaz7ljYPl +kI3nrqHnkIbogIVTRDJDIA0KICAyMDEw57q16K665oqA5pyv5aSn5Yq/IOS4reWbveW8gOWPkeiA +hei/juadpem7hOmHkeWNgeW5tDwvQT48U1BBTiBjbGFzcz10eHRfYmx1ZSANCiAgc3R5bGU9IkZP +TlQtU0laRTogMTJweDsgTUFSR0lOOiAwcHggMHB4IDBweCA4cHg7IENPTE9SOiByZ2IoMSw5NSwx +ODIpIj48QSANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMSw5NSwxODIpOyBURVhULURFQ09SQVRJT046 +IG5vbmUiIA0KICBocmVmPSJodHRwOi8vd3d3LmNzZG4ubmV0LyIgdGFyZ2V0PV9ibGFuaz48L0E+ +PC9TUEFOPjwvRFQ+DQogIDxEVCBjbGFzcz10eHRfYmxhY2sgDQogIHN0eWxlPSJQQURESU5HLVJJ +R0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDBweCA4cHg7IFBBRERJTkctTEVGVDogMTBw +eDsgRk9OVC1TSVpFOiAxNHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcu +Y24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMjYuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsg +TUFSR0lOOiAzcHggMHB4OyBDT0xPUjogcmdiKDAsMCwwKTsgUEFERElORy1UT1A6IDBweDsgUE9T +SVRJT046IHJlbGF0aXZlOyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1j +bGlwOiBpbml0aWFsIj48QSANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09S +QVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw3NCk7IA0KICBocmVm +PSJodHRwOi8vY2xvdWQuY3Nkbi5uZXQvYS8yMDEwMTIxNS8yODM2NjguaHRtbCIgDQogIHRhcmdl +dD1fYmxhbms+SUJN5Li65b635Zu95byA5Y+R5q+P56eS6L+Q566XMzAwMOS4h+S6v+asoei2hee6 +p+iuoeeul+acujwvQT48U1BBTiBjbGFzcz10eHRfYmx1ZSANCiAgc3R5bGU9IkZPTlQtU0laRTog +MTJweDsgTUFSR0lOOiAwcHggMHB4IDBweCA4cHg7IENPTE9SOiByZ2IoMSw5NSwxODIpIj48QSAN +CiAgc3R5bGU9IkNPTE9SOiByZ2IoMSw5NSwxODIpOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0K +ICBocmVmPSJodHRwOi8vY2xvdWQuY3Nkbi5uZXQvIiB0YXJnZXQ9X2JsYW5rPui2hei2iuS4reWb +veWkqeayszHlj7c8L0E+PC9TUEFOPjwvRFQ+DQogIDxERCBjbGFzcz1uZXdzX3R5cGVhIA0KICBz +dHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBQQURESU5HLUxFRlQ6IDBweDsgQkFDS0dST1VORC1J +TUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzQ2Lmdp +Zik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogLTNweCAwcHggMTBweDsgUEFERElORy1U +T1A6IDBweDsgUE9TSVRJT046IHJlbGF0aXZlOyBIRUlHSFQ6IDE5cHg7IGJhY2tncm91bmQtb3Jp +Z2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxERk4gDQogIHN0eWxlPSJM +RUZUOiAzODlweDsgQ09MT1I6IHJnYigyNTUsMjU1LDI1NSk7IEZPTlQtU1RZTEU6IG5vcm1hbDsg +UE9TSVRJT046IGFic29sdXRlOyBUT1A6IDJweCI+6LWE6K6v5Yqo5oCBPC9ERk4+PC9ERD48L0RM +PjwvRElWPg0KPERJViBjbGFzcz1idXNpbmVzc3R4dGFkIA0Kc3R5bGU9IlBBRERJTkctUklHSFQ6 +IDBweDsgRElTUExBWTogaW5saW5lOyBQQURESU5HLUxFRlQ6IDBweDsgRkxPQVQ6IGxlZnQ7IFBB +RERJTkctQk9UVE9NOiA1cHg7IE1BUkdJTjogLTZweCAxMHB4IDNweDsgV0lEVEg6IDQ1MHB4OyBQ +QURESU5HLVRPUDogNXB4Ij4NCjxVTCBjbGFzcz10eHRfZGVwZ3JheSANCnN0eWxlPSJQQURESU5H +LVJJR0hUOiAwcHg7IFBBRERJTkctTEVGVDogMHB4OyBGTE9BVDogbGVmdDsgUEFERElORy1CT1RU +T006IDBweDsgTUFSR0lOOiAwcHg7IFdJRFRIOiA0NTBweDsgQ09MT1I6IHJnYig1MSw1MSw1MSk7 +IFBBRERJTkctVE9QOiAwcHg7IExJU1QtU1RZTEUtVFlQRTogbm9uZSI+DQogIDxMSSANCiAgc3R5 +bGU9IlBBRERJTkctUklHSFQ6IDBweDsgRElTUExBWTogaW5saW5lOyBQQURESU5HLUxFRlQ6IDBw +eDsgRkxPQVQ6IGxlZnQ7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4IDVweDsgV0lE +VEg6IDIxNXB4OyBQQURESU5HLVRPUDogMHB4Ij48QSANCiAgc3R5bGU9IkNPTE9SOiByZ2IoNTEs +NTEsNTEpOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBocmVmPSJodHRwOi8vei5jc2RuLm5l +dC9nbWNsaWNrLnBocD9iYW5uZXJpZD01NDEwJmFtcDt6b25laWQ9NDIxJmFtcDtzb3VyY2U9JmFt +cDtkZXN0PWh0dHAlM0ElMkYlMkZlZHUuY3Nkbi5uZXQlMkZoZWltYSUyRiIgDQogIHRhcmdldD1f +Ymxhbms+5bCx5LiaIuS4jeWBmuW8gOWPkeS4jei/mOasviLnmoTln7norq08L0E+PC9MST4NCiAg +PExJIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBESVNQTEFZOiBpbmxpbmU7IFBBRERJ +TkctTEVGVDogMHB4OyBGTE9BVDogbGVmdDsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAw +cHggNXB4OyBXSURUSDogMjE1cHg7IFBBRERJTkctVE9QOiAwcHgiPjxBIA0KICBzdHlsZT0iQ09M +T1I6IHJnYig1MSw1MSw1MSk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIGhyZWY9Imh0dHA6 +Ly96LmNzZG4ubmV0L2dtY2xpY2sucGhwP2Jhbm5lcmlkPTU0MDQmYW1wO3pvbmVpZD00MjMmYW1w +O3NvdXJjZT0mYW1wO2Rlc3Q9aHR0cCUzQSUyRiUyRm1zZG4ubWljcm9zb2Z0LmNvbSUyRnpoLWNu +JTJGd2luZG93c3Bob25lJTJGZGVmYXVsdC5hc3B4JTNGb2NpZCUzRGJhbi1uLWNuLXdwNy0tY3Nk +bisiIA0KICB0YXJnZXQ9X2JsYW5rPuOAkOS7o+eggeOAkVdpbmRvd3MgUGhvbmUgN+iMg+S+i+eo +i+W6jzwvQT48L0xJPg0KICA8TEkgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IERJU1BM +QVk6IGlubGluZTsgUEFERElORy1MRUZUOiAwcHg7IEZMT0FUOiBsZWZ0OyBQQURESU5HLUJPVFRP +TTogMHB4OyBNQVJHSU46IDBweCA1cHg7IFdJRFRIOiAyMTVweDsgUEFERElORy1UT1A6IDBweCI+ +PEEgDQogIHN0eWxlPSJDT0xPUjogcmdiKDUxLDUxLDUxKTsgVEVYVC1ERUNPUkFUSU9OOiBub25l +IiANCiAgaHJlZj0iaHR0cDovL3ouY3Nkbi5uZXQvZ21jbGljay5waHA/YmFubmVyaWQ9NTQwMSZh +bXA7em9uZWlkPTQyMiZhbXA7c291cmNlPSZhbXA7ZGVzdD1odHRwJTNBJTJGJTJGMTg5d29ya3Mu +Y3Nkbi5uZXQlMkYrIiANCiAgdGFyZ2V0PV9ibGFuaz7lpKnnv7zmlZnkvaDnp7vliqjlupTnlKjo +kKXliKnkuYvpgZM8L0E+PC9MST4NCiAgPExJIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4 +OyBESVNQTEFZOiBpbmxpbmU7IFBBRERJTkctTEVGVDogMHB4OyBGTE9BVDogbGVmdDsgUEFERElO +Ry1CT1RUT006IDBweDsgTUFSR0lOOiAwcHggNXB4OyBXSURUSDogMjE1cHg7IFBBRERJTkctVE9Q +OiAwcHgiPjxBIA0KICBzdHlsZT0iQ09MT1I6IHJnYig1MSw1MSw1MSk7IFRFWFQtREVDT1JBVElP +Tjogbm9uZSIgDQogIGhyZWY9Imh0dHA6Ly96LmNzZG4ubmV0L2dtY2xpY2sucGhwP2Jhbm5lcmlk +PTUzNjAmYW1wO3pvbmVpZD00MjQmYW1wO3NvdXJjZT0mYW1wO2Rlc3Q9aHR0cCUzQSUyRiUyRmM5 +LmNzZG4uaHVkb25nLmNvbSUyRiIgDQogIHRhcmdldD1fYmxhbms+6K6/6LCIIOW+rui9r+mSn+WN +q+iwiElFOeWPmOmdqTwvQT48L0xJPjwvVUw+PC9ESVY+DQo8SDYgDQpzdHlsZT0iQ0xFQVI6IGJv +dGg7IFBBRERJTkctUklHSFQ6IDBweDsgQk9SREVSLVRPUDogcmdiKDIwNCwyMDQsMjA0KSAxcHgg +c29saWQ7IFBBRERJTkctTEVGVDogMTBweDsgRk9OVC1TSVpFOiAxNHB4OyBCQUNLR1JPVU5ELUlN +QUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMTEuZ2lm +KTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IFBBRERJTkctVE9QOiA1cHg7IFBP +U0lUSU9OOiByZWxhdGl2ZTsgSEVJR0hUOiAyOXB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlh +bDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj7kuJPpopg8U1BBTiANCmNsYXNzPXR4dF9ibGFj +ayANCnN0eWxlPSJGT05ULVdFSUdIVDogbm9ybWFsOyBGT05ULVNJWkU6IDEycHg7IE1BUkdJTjog +MHB4IDBweCAwcHggMTVweDsgQ09MT1I6IHJnYigwLDAsMCkiPjwvU1BBTj48Q0lURSANCmNsYXNz +PXR4dF9ibHVlIA0Kc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElP +TjogMHB4IDZweDsgUEFERElORy1MRUZUOiAxMHB4OyBGT05ULVdFSUdIVDogbm9ybWFsOyBGT05U +LVNJWkU6IDEycHg7IExFRlQ6IDQyMHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2Nz +ZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMTIuZ2lmKTsgUEFERElORy1CT1RUT006 +IDBweDsgQ09MT1I6IHJnYigxLDk1LDE4Mik7IFBBRERJTkctVE9QOiAwcHg7IEZPTlQtU1RZTEU6 +IG5vcm1hbDsgUE9TSVRJT046IGFic29sdXRlOyBUT1A6IDVweDsgYmFja2dyb3VuZC1vcmlnaW46 +IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQpzdHlsZT0iQ09MT1I6IHJn +YigxLDk1LDE4Mik7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQpocmVmPSJodHRwOi8vY3Nkbmhv +bWVwYWdlLmNzZG4ubmV0L2NfbmV3c3N1YmplY3QvbW9yZSIgDQp0YXJnZXQ9X2JsYW5rPuabtOWk +mjwvQT48L0NJVEU+PC9INj4NCjxESVYgY2xhc3M9cGFnZWNvbl9sYXllcjJfbGVmdGNvbiANCnN0 +eWxlPSJQQURESU5HLVJJR0hUOiAxMHB4OyBQQURESU5HLUxFRlQ6IDEwcHg7IEZMT0FUOiBsZWZ0 +OyBQQURESU5HLUJPVFRPTTogNXB4OyBXSURUSDogNDUwcHg7IFBBRERJTkctVE9QOiA1cHgiPg0K +PFVMIA0Kc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgT1ZFUkZMT1ctWTogaGlkZGVuOyBQQURE +SU5HLUxFRlQ6IDBweDsgRkxPQVQ6IGxlZnQ7IE9WRVJGTE9XLVg6IGhpZGRlbjsgUEFERElORy1C +T1RUT006IDBweDsgTUFSR0lOOiAwcHg7IFdJRFRIOiA0NTBweDsgUEFERElORy1UT1A6IDZweDsg +TElTVC1TVFlMRS1UWVBFOiBub25lIj4NCiAgPExJIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDog +MHB4OyBESVNQTEFZOiBpbmxpbmU7IFBBRERJTkctTEVGVDogMHB4OyBGTE9BVDogbGVmdDsgUEFE +RElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHggOHB4OyBQQURESU5HLVRPUDogMHB4Ij48QSAN +CiAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBv +bmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw3NSk7IGhyZWY9Imh0dHA6Ly9nLmNzZG4ubmV0LzUx +NjY2NDMiIA0KICB0YXJnZXQ9X2JsYW5rPjxJTUcgdGl0bGU9IiIgDQogIHN0eWxlPSJCT1JERVIt +UklHSFQ6IHJnYigyMDQsMjA0LDIwNCkgMXB4IHNvbGlkOyBQQURESU5HLVJJR0hUOiAwcHg7IEJP +UkRFUi1UT1A6IHJnYigyMDQsMjA0LDIwNCkgMXB4IHNvbGlkOyBQQURESU5HLUxFRlQ6IDBweDsg +UEFERElORy1CT1RUT006IDZweDsgQk9SREVSLUxFRlQ6IHJnYigyMDQsMjA0LDIwNCkgMXB4IHNv +bGlkOyBQQURESU5HLVRPUDogNnB4OyBCT1JERVItQk9UVE9NOiByZ2IoMjA0LDIwNCwyMDQpIDFw +eCBzb2xpZCIgDQogIGhlaWdodD0xMzIgYWx0PSIiIHNyYz0iaHR0cDovL2ltYWdlcy5jc2RuLm5l +dC8yMDEwMTIwMy/pppbpobXkuJPpopgwMi5qcGciIA0KICB3aWR0aD05Mz48L0E+PFNQQU4gY2xh +c3M9dHh0X2JsdWUgDQogIHN0eWxlPSJESVNQTEFZOiBibG9jazsgTUFSR0lOOiA1cHggMHB4IDBw +eDsgQ09MT1I6IHJnYigxLDk1LDE4Mik7IFRFWFQtQUxJR046IGNlbnRlciI+PEEgDQogIHN0eWxl +PSJDT0xPUjogcmdiKDEsOTUsMTgyKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGlj +az1Mb2dDbGlja0NvdW50KHRoaXMsNzUpOyBocmVmPSJodHRwOi8vZy5jc2RuLm5ldC81MTY2NjQz +IiANCiAgdGFyZ2V0PV9ibGFuaz5UZWNo4oCiRWQgMjAxMDwvQT48L1NQQU4+PC9MST4NCiAgPExJ +IA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBESVNQTEFZOiBpbmxpbmU7IFBBRERJTkct +TEVGVDogMHB4OyBGTE9BVDogbGVmdDsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHgg +OHB4OyBQQURESU5HLVRPUDogMHB4Ij48QSANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBU +RVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw3NSk7 +IGhyZWY9Imh0dHA6Ly9nLmNzZG4ubmV0LzUxNjU0OTYiIA0KICB0YXJnZXQ9X2JsYW5rPjxJTUcg +dGl0bGU9IiIgDQogIHN0eWxlPSJCT1JERVItUklHSFQ6IHJnYigyMDQsMjA0LDIwNCkgMXB4IHNv +bGlkOyBQQURESU5HLVJJR0hUOiAwcHg7IEJPUkRFUi1UT1A6IHJnYigyMDQsMjA0LDIwNCkgMXB4 +IHNvbGlkOyBQQURESU5HLUxFRlQ6IDBweDsgUEFERElORy1CT1RUT006IDZweDsgQk9SREVSLUxF +RlQ6IHJnYigyMDQsMjA0LDIwNCkgMXB4IHNvbGlkOyBQQURESU5HLVRPUDogNnB4OyBCT1JERVIt +Qk9UVE9NOiByZ2IoMjA0LDIwNCwyMDQpIDFweCBzb2xpZCIgDQogIGhlaWdodD0xMzIgYWx0PSIi +IHNyYz0iaHR0cDovL2ltYWdlcy5jc2RuLm5ldC8yMDEwMTEzMC8yLmpwZyIgDQogIHdpZHRoPTkz +PjwvQT48U1BBTiBjbGFzcz10eHRfYmx1ZSANCiAgc3R5bGU9IkRJU1BMQVk6IGJsb2NrOyBNQVJH +SU46IDVweCAwcHggMHB4OyBDT0xPUjogcmdiKDEsOTUsMTgyKTsgVEVYVC1BTElHTjogY2VudGVy +Ij48QSANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMSw5NSwxODIpOyBURVhULURFQ09SQVRJT046IG5v +bmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw3NSk7IGhyZWY9Imh0dHA6Ly9nLmNz +ZG4ubmV0LzUxNjU0OTYiIA0KICB0YXJnZXQ9X2JsYW5rPkhhZG9vcOaKgOacr+S4k+mimDwvQT48 +L1NQQU4+PC9MST4NCiAgPExJIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBESVNQTEFZ +OiBpbmxpbmU7IFBBRERJTkctTEVGVDogMHB4OyBGTE9BVDogbGVmdDsgUEFERElORy1CT1RUT006 +IDBweDsgTUFSR0lOOiAwcHggOHB4OyBQQURESU5HLVRPUDogMHB4Ij48QSANCiAgc3R5bGU9IkNP +TE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0Ns +aWNrQ291bnQodGhpcyw3NSk7IGhyZWY9Imh0dHA6Ly9zdWJqZWN0LmNzZG4ubmV0L2NsaWVudC8i +IA0KICB0YXJnZXQ9X2JsYW5rPjxJTUcgdGl0bGU9IiIgDQogIHN0eWxlPSJCT1JERVItUklHSFQ6 +IHJnYigyMDQsMjA0LDIwNCkgMXB4IHNvbGlkOyBQQURESU5HLVJJR0hUOiAwcHg7IEJPUkRFUi1U +T1A6IHJnYigyMDQsMjA0LDIwNCkgMXB4IHNvbGlkOyBQQURESU5HLUxFRlQ6IDBweDsgUEFERElO +Ry1CT1RUT006IDZweDsgQk9SREVSLUxFRlQ6IHJnYigyMDQsMjA0LDIwNCkgMXB4IHNvbGlkOyBQ +QURESU5HLVRPUDogNnB4OyBCT1JERVItQk9UVE9NOiByZ2IoMjA0LDIwNCwyMDQpIDFweCBzb2xp +ZCIgDQogIGhlaWdodD0xMzIgYWx0PSIiIHNyYz0iaHR0cDovL2ltYWdlcy5jc2RuLm5ldC8yMDEw +MTEyMy8zUV85MC0xMzAuanBnIiANCiAgd2lkdGg9OTM+PC9BPjxTUEFOIGNsYXNzPXR4dF9ibHVl +IA0KICBzdHlsZT0iRElTUExBWTogYmxvY2s7IE1BUkdJTjogNXB4IDBweCAwcHg7IENPTE9SOiBy +Z2IoMSw5NSwxODIpOyBURVhULUFMSUdOOiBjZW50ZXIiPjxBIA0KICBzdHlsZT0iQ09MT1I6IHJn +YigxLDk1LDE4Mik7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tD +b3VudCh0aGlzLDc1KTsgaHJlZj0iaHR0cDovL3N1YmplY3QuY3Nkbi5uZXQvY2xpZW50LyIgDQog +IHRhcmdldD1fYmxhbms+5o6i6K6o6L2v5Lu26KGM5Li66KeE6IyDPC9BPjwvU1BBTj48L0xJPg0K +ICA8TEkgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IERJU1BMQVk6IGlubGluZTsgUEFE +RElORy1MRUZUOiAwcHg7IEZMT0FUOiBsZWZ0OyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46 +IDBweCA4cHg7IFBBRERJTkctVE9QOiAwcHgiPjxBIA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAs +MCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlz +LDc1KTsgaHJlZj0iaHR0cDovL2cuY3Nkbi5uZXQvNTE2MzI2NiIgDQogIHRhcmdldD1fYmxhbms+ +PElNRyB0aXRsZT0iIiANCiAgc3R5bGU9IkJPUkRFUi1SSUdIVDogcmdiKDIwNCwyMDQsMjA0KSAx +cHggc29saWQ7IFBBRERJTkctUklHSFQ6IDBweDsgQk9SREVSLVRPUDogcmdiKDIwNCwyMDQsMjA0 +KSAxcHggc29saWQ7IFBBRERJTkctTEVGVDogMHB4OyBQQURESU5HLUJPVFRPTTogNnB4OyBCT1JE +RVItTEVGVDogcmdiKDIwNCwyMDQsMjA0KSAxcHggc29saWQ7IFBBRERJTkctVE9QOiA2cHg7IEJP +UkRFUi1CT1RUT006IHJnYigyMDQsMjA0LDIwNCkgMXB4IHNvbGlkIiANCiAgaGVpZ2h0PTEzMiBh +bHQ9IiIgc3JjPSJodHRwOi8vaW1hZ2VzLmNzZG4ubmV0LzIwMTAxMTEwL0Fkb2JlTWF4MjAxMC5q +cGciIA0KICB3aWR0aD05Mz48L0E+PFNQQU4gY2xhc3M9dHh0X2JsdWUgDQogIHN0eWxlPSJESVNQ +TEFZOiBibG9jazsgTUFSR0lOOiA1cHggMHB4IDBweDsgQ09MT1I6IHJnYigxLDk1LDE4Mik7IFRF +WFQtQUxJR046IGNlbnRlciI+PEEgDQogIHN0eWxlPSJDT0xPUjogcmdiKDEsOTUsMTgyKTsgVEVY +VC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsNzUpOyBo +cmVmPSJodHRwOi8vZy5jc2RuLm5ldC81MTYzMjY2IiANCiAgdGFyZ2V0PV9ibGFuaz5BZG9iZSBN +QVggMjAxMDwvQT48L1NQQU4+PC9MST48L1VMPjwvRElWPjwvRElWPg0KPERJViBjbGFzcz1wYWdl +Y29uX2xheWVyMl9taWQgDQpzdHlsZT0iQk9SREVSLVRPUDogcmdiKDIwNCwyMDQsMjA0KSAxcHgg +c29saWQ7IERJU1BMQVk6IGlubGluZTsgRkxPQVQ6IGxlZnQ7IE1BUkdJTjogMHB4IDBweCAwcHgg +NXB4OyBXSURUSDogMjU5cHg7IFRFWFQtQUxJR046IGxlZnQiPg0KPEg0IA0Kc3R5bGU9IlBBRERJ +TkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMTAwJSAwJTsgRElTUExBWTogaW5s +aW5lOyBQQURESU5HLUxFRlQ6IDEwcHg7IEZPTlQtU0laRTogMTRweDsgRkxPQVQ6IGxlZnQ7IEJB +Q0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL3BpY195anN0 +aXRiZy5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweDsgV0lEVEg6IDI0OXB4 +OyBDT0xPUjogcmdiKDI1NSwyNTUsMjU1KTsgTElORS1IRUlHSFQ6IDI5cHg7IFBBRERJTkctVE9Q +OiAwcHg7IFBPU0lUSU9OOiByZWxhdGl2ZTsgQkFDS0dST1VORC1DT0xPUjogcmdiKDYsODksMTc4 +KTsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+ +Q1NETuenu+WKqOW+ruWNmiZuYnNwOyZuYnNwOyZuYnNwOzxBIA0KY2xhc3M9Zm9udHNpemUgDQpz +dHlsZT0iRk9OVC1XRUlHSFQ6IG5vcm1hbDsgRk9OVC1TSVpFOiAxMnB4OyBDT0xPUjogcmdiKDI1 +NSwyNTUsMjU1KTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCmhyZWY9Imh0dHA6Ly90LnNpbmEu +Y29tLmNuL2NzZG5tb2JpbGUiPuaIkeimgeWFs+azqCAmZ3Q7Jmd0OzwvQT48L0g0Pg0KPERMIGNs +YXNzPXlqc19saXN0IGlkPWRpdnlqcyANCnN0eWxlPSJQQURESU5HLVJJR0hUOiAxMHB4OyBCQUNL +R1JPVU5ELVBPU0lUSU9OOiAwJSAwJTsgT1ZFUkZMT1ctWTogaGlkZGVuOyBESVNQTEFZOiBpbmxp +bmU7IFBBRERJTkctTEVGVDogMTBweDsgRkxPQVQ6IGxlZnQ7IEJBQ0tHUk9VTkQtSU1BR0U6IHVy +bChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL3BpY195anNiZy5naWYpOyBPVkVSRkxPVy1Y +OiBoaWRkZW47IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBXSURUSDogMjM4cHg7 +IFBBRERJTkctVE9QOiAxMHB4OyBIRUlHSFQ6IDM5MHB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5p +dGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj4NCiAgPERUIGNsYXNzPXR4dF9ibHVlIA0K +ICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBQQURESU5HLUxFRlQ6IDBweDsgRk9OVC1XRUlH +SFQ6IGJvbGQ7IFBBRERJTkctQk9UVE9NOiA1cHg7IE1BUkdJTjogMHB4OyBDT0xPUjogcmdiKDEs +OTUsMTgyKTsgUEFERElORy1UT1A6IDVweCI+PEEgDQogIHN0eWxlPSJDT0xPUjogcmdiKDEsOTUs +MTgyKTsgVEVYVC1ERUNPUkFUSU9OOiB1bmRlcmxpbmUiIA0KICBocmVmPSJodHRwOi8vbW9iaWxl +LmNzZG4ubmV0LyI+5pu05aSa57K+5b2p5YaF5a6577yM5bC95Zyo56e75Yqo6aKR6YGTPC9BPjwv +RFQ+DQogIDxERCBpZD00NDgyNTkzNDI1IA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBC +QUNLR1JPVU5ELVBPU0lUSU9OOiAzcHggMTJweDsgRElTUExBWTogYmxvY2s7IFBBRERJTkctTEVG +VDogMTRweDsgQkFDS0dST1VORC1BVFRBQ0hNRU5UOiBzY3JvbGw7IEJBQ0tHUk9VTkQtSU1BR0U6 +IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMyMy5naWYpOyBQ +QURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweDsgTElORS1IRUlHSFQ6IDIxcHg7IFBBRERJ +TkctVE9QOiA1cHg7IEJBQ0tHUk9VTkQtQ09MT1I6IHRyYW5zcGFyZW50OyBiYWNrZ3JvdW5kLW9y +aWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj4NCiAgPFAgY2xhc3M9dG9w +IA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBPVkVSRkxPVy1ZOiBoaWRkZW47IFBBRERJ +TkctTEVGVDogMHB4OyBPVkVSRkxPVy1YOiBoaWRkZW47IFBBRERJTkctQk9UVE9NOiAwcHg7IE1B +UkdJTjogMHB4OyBQQURESU5HLVRPUDogMHB4OyBIRUlHSFQ6IDQwcHgiPjxTUEFOIA0KICBjbGFz +cz10eHRfYmx1ZSBzdHlsZT0iQ09MT1I6IHJnYigxLDk1LDE4MikiPjxBIA0KICBzdHlsZT0iQ09M +T1I6IHJnYigxLDk1LDE4Mik7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIGhyZWY9Imh0dHA6 +Ly90LnNpbmEuY29tLmNuLzE3MTA5MDAzNDEiPuWImOiIqjwvQT7vvJo8L1NQQU4+5Lq65rCR5pCc +57Si5a6e6ZmF56CU56m255qE5piv5Lq65rCR6KKr5pCc57SiLiANCiAgLy9A5qyn6JOsQVTnp7vl +iqjkupLogZTnvZE65Lyg57uf5pCc57Si5byV5pOO77yI5q+U5aaC6LC35q2M77yJ56CU56m25oCO +5LmI6K6p5aSn5a625pCc5Ye65L+h5oGv77yM5a6D56CU56m25oCO5LmI6K6p5aSn5a625pCc5LiN +5Ye65L+h5oGv44CCLuacjeS6hualvOS4u+OAgiAvL0B3YXNhOuacgOWQjuS4gOWPpeS6ruS6huOA +guOAgjwvUD4NCiAgPFAgY2xhc3M9ImJ0bXRpbWUgdHh0X2JsdWUiIHRpdGxlPSIyMDEwLTEyLTE2 +IDAxOjA5OjIyIiANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJ +VElPTjogNTAlIDEwMCU7IFBBRERJTkctTEVGVDogMHB4OyBCQUNLR1JPVU5ELUFUVEFDSE1FTlQ6 +IHNjcm9sbDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFn +ZXMvY3NkbmluZGV4X3BpYzE0LmdpZik7IFBBRERJTkctQk9UVE9NOiAzcHg7IE1BUkdJTjogMHB4 +OyBDT0xPUjogcmdiKDEsOTUsMTgyKTsgUEFERElORy1UT1A6IDJweDsgQkFDS0dST1VORC1DT0xP +UjogdHJhbnNwYXJlbnQ7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNs +aXA6IGluaXRpYWwiPjkgDQogIGhvdXJzIGFnbzwvUD48L0REPg0KICA8REQgaWQ9NDQ4MjU5MzY2 +OSANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogM3B4 +IDEycHg7IERJU1BMQVk6IGJsb2NrOyBQQURESU5HLUxFRlQ6IDE0cHg7IEJBQ0tHUk9VTkQtQVRU +QUNITUVOVDogc2Nyb2xsOyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24v +d3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMjMuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFS +R0lOOiAwcHg7IExJTkUtSEVJR0hUOiAyMXB4OyBQQURESU5HLVRPUDogNXB4OyBCQUNLR1JPVU5E +LUNPTE9SOiB0cmFuc3BhcmVudDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91 +bmQtY2xpcDogaW5pdGlhbCI+DQogIDxQIGNsYXNzPXRvcCANCiAgc3R5bGU9IlBBRERJTkctUklH +SFQ6IDBweDsgT1ZFUkZMT1ctWTogaGlkZGVuOyBQQURESU5HLUxFRlQ6IDBweDsgT1ZFUkZMT1ct +WDogaGlkZGVuOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweDsgUEFERElORy1UT1A6 +IDBweDsgSEVJR0hUOiA0MHB4Ij48U1BBTiANCiAgY2xhc3M9dHh0X2JsdWUgc3R5bGU9IkNPTE9S +OiByZ2IoMSw5NSwxODIpIj48QSANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMSw5NSwxODIpOyBURVhU +LURFQ09SQVRJT046IG5vbmUiIA0KICBocmVmPSJodHRwOi8vdC5zaW5hLmNvbS5jbi8xNDAxMzY1 +NTc0Ij7njovoiKpoZGY8L0E+77yaPC9TUEFOPkNOTklD55qE5Luj55CG6L+Z5biu5a2Z5a2Q5Lmf +5LiN5Yqo5Yqo6ISR5a2Q77yM5q+P6ZqU5LiA5q615pe26Ze06YO96IO95o6l5Yiw5ZCM5qC355qE +55S16K+d77yM6K+05rOV5a6M5YWo5LiA6Ie077yM6YO95piv6K+05Yir5Lq66KaB5oqi5rOo5L2g +55qE5LqS6IGU572R5ZOB54mM4oCU4oCU6YCa55So572R5Z2A77yM5oiW6ICF5piv5oqi5rOo5L2g +55qE56e75Yqo5LqS6IGU572R5ZOB54mM4oCU4oCU5peg57q/572R5Z2A77yM5L2g5Lir6L+e6Iqx +5qC36YO95oeS5b6X5o2i77yM5Yeg5bm05aaC5LiA5pel55qE6L+Z5qC36KGM6aqX44CC5oiR5a6e +5Zyo5b+N5peg5Y+v5b+N77yM5L2g5Lus6L+Z5biu5a2Z5a2Q77yM5p2l54K55LiT5Lia57K+56We +5aW95LiN5aW977yfPC9QPg0KICA8UCBjbGFzcz0iYnRtdGltZSB0eHRfYmx1ZSIgdGl0bGU9IjIw +MTAtMTItMTYgMDE6MDk6MjQiIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JP +VU5ELVBPU0lUSU9OOiA1MCUgMTAwJTsgUEFERElORy1MRUZUOiAwcHg7IEJBQ0tHUk9VTkQtQVRU +QUNITUVOVDogc2Nyb2xsOyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24v +d3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMTQuZ2lmKTsgUEFERElORy1CT1RUT006IDNweDsgTUFS +R0lOOiAwcHg7IENPTE9SOiByZ2IoMSw5NSwxODIpOyBQQURESU5HLVRPUDogMnB4OyBCQUNLR1JP +VU5ELUNPTE9SOiB0cmFuc3BhcmVudDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tn +cm91bmQtY2xpcDogaW5pdGlhbCI+OSANCiAgaG91cnMgYWdvPC9QPjwvREQ+DQogIDxERCBpZD00 +NDgyNTk1OTM5IA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lU +SU9OOiAzcHggMTJweDsgRElTUExBWTogYmxvY2s7IFBBRERJTkctTEVGVDogMTRweDsgQkFDS0dS +T1VORC1BVFRBQ0hNRU5UOiBzY3JvbGw7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3Nk +bmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMyMy5naWYpOyBQQURESU5HLUJPVFRPTTog +MHB4OyBNQVJHSU46IDBweDsgTElORS1IRUlHSFQ6IDIxcHg7IFBBRERJTkctVE9QOiA1cHg7IEJB +Q0tHUk9VTkQtQ09MT1I6IHRyYW5zcGFyZW50OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsg +YmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj4NCiAgPFAgY2xhc3M9dG9wIA0KICBzdHlsZT0iUEFE +RElORy1SSUdIVDogMHB4OyBPVkVSRkxPVy1ZOiBoaWRkZW47IFBBRERJTkctTEVGVDogMHB4OyBP +VkVSRkxPVy1YOiBoaWRkZW47IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBQQURE +SU5HLVRPUDogMHB4OyBIRUlHSFQ6IDQwcHgiPjxTUEFOIA0KICBjbGFzcz10eHRfYmx1ZSBzdHls +ZT0iQ09MT1I6IHJnYigxLDk1LDE4MikiPjxBIA0KICBzdHlsZT0iQ09MT1I6IHJnYigxLDk1LDE4 +Mik7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIGhyZWY9Imh0dHA6Ly90LnNpbmEuY29tLmNu +LzE4ODUxNzU5NzciPueXnuWtkDQyMDY8L0E+77yaPC9TUEFOPuOAiuS6kuiBlOe9kS/np7vliqjk +upLogZTnvZHlsI/lm6LpmJ/liJvkuJog56ys5LqM6ZuGIA0KICDmsarljY7jgIsgaHR0cDovL3Np +bmF1cmwuY24vaDR3M3pmPC9QPg0KICA8UCBjbGFzcz0iYnRtdGltZSB0eHRfYmx1ZSIgdGl0bGU9 +IjIwMTAtMTItMTYgMDE6MDk6MzkiIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNL +R1JPVU5ELVBPU0lUSU9OOiA1MCUgMTAwJTsgUEFERElORy1MRUZUOiAwcHg7IEJBQ0tHUk9VTkQt +QVRUQUNITUVOVDogc2Nyb2xsOyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcu +Y24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMTQuZ2lmKTsgUEFERElORy1CT1RUT006IDNweDsg +TUFSR0lOOiAwcHg7IENPTE9SOiByZ2IoMSw5NSwxODIpOyBQQURESU5HLVRPUDogMnB4OyBCQUNL +R1JPVU5ELUNPTE9SOiB0cmFuc3BhcmVudDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJh +Y2tncm91bmQtY2xpcDogaW5pdGlhbCI+OSANCiAgaG91cnMgYWdvPC9QPjwvREQ+DQogIDxERCBp +ZD00NDgyNjE0OTQ3IA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBP +U0lUSU9OOiAzcHggMTJweDsgRElTUExBWTogYmxvY2s7IFBBRERJTkctTEVGVDogMTRweDsgQkFD +S0dST1VORC1BVFRBQ0hNRU5UOiBzY3JvbGw7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8v +Y3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMyMy5naWYpOyBQQURESU5HLUJPVFRP +TTogMHB4OyBNQVJHSU46IDBweDsgTElORS1IRUlHSFQ6IDIxcHg7IFBBRERJTkctVE9QOiA1cHg7 +IEJBQ0tHUk9VTkQtQ09MT1I6IHRyYW5zcGFyZW50OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlh +bDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj4NCiAgPFAgY2xhc3M9dG9wIA0KICBzdHlsZT0i +UEFERElORy1SSUdIVDogMHB4OyBPVkVSRkxPVy1ZOiBoaWRkZW47IFBBRERJTkctTEVGVDogMHB4 +OyBPVkVSRkxPVy1YOiBoaWRkZW47IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBQ +QURESU5HLVRPUDogMHB4OyBIRUlHSFQ6IDQwcHgiPjxTUEFOIA0KICBjbGFzcz10eHRfYmx1ZSBz +dHlsZT0iQ09MT1I6IHJnYigxLDk1LDE4MikiPjxBIA0KICBzdHlsZT0iQ09MT1I6IHJnYigxLDk1 +LDE4Mik7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIGhyZWY9Imh0dHA6Ly90LnNpbmEuY29t +LmNuLzE2NDE5NDQyNzIiPuadjuWQjeWkqzwvQT7vvJo8L1NQQU4+Ly9A5qyn6JOsQVTnp7vliqjk +upLogZTnvZE6MTDlubTkuoblkKfvvJ/pgqPkuInkur/pg6jkuZ/lpJ/niZvpgLznmoTkuobjgILk +uI3nn6XpgZPmnInlpJrlsJHpg6jmmK/lhoXplIDnmoTjgII8L1A+DQogIDxQIGNsYXNzPSJidG10 +aW1lIHR4dF9ibHVlIiB0aXRsZT0iMjAxMC0xMi0xNiAwMToxMTo0NyIgDQogIHN0eWxlPSJQQURE +SU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDUwJSAxMDAlOyBQQURESU5HLUxF +RlQ6IDBweDsgQkFDS0dST1VORC1BVFRBQ0hNRU5UOiBzY3JvbGw7IEJBQ0tHUk9VTkQtSU1BR0U6 +IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMxNC5naWYpOyBQ +QURESU5HLUJPVFRPTTogM3B4OyBNQVJHSU46IDBweDsgQ09MT1I6IHJnYigxLDk1LDE4Mik7IFBB +RERJTkctVE9QOiAycHg7IEJBQ0tHUk9VTkQtQ09MT1I6IHRyYW5zcGFyZW50OyBiYWNrZ3JvdW5k +LW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj45IA0KICBob3VycyBh +Z288L1A+PC9ERD4NCiAgPEREIGlkPTQ0ODI2MjE1NzEgDQogIHN0eWxlPSJQQURESU5HLVJJR0hU +OiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDNweCAxMnB4OyBESVNQTEFZOiBibG9jazsgUEFE +RElORy1MRUZUOiAxNHB4OyBCQUNLR1JPVU5ELUFUVEFDSE1FTlQ6IHNjcm9sbDsgQkFDS0dST1VO +RC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzIz +LmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBMSU5FLUhFSUdIVDogMjFw +eDsgUEFERElORy1UT1A6IDVweDsgQkFDS0dST1VORC1DT0xPUjogdHJhbnNwYXJlbnQ7IGJhY2tn +cm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPg0KICA8UCBj +bGFzcz10b3AgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IE9WRVJGTE9XLVk6IGhpZGRl +bjsgUEFERElORy1MRUZUOiAwcHg7IE9WRVJGTE9XLVg6IGhpZGRlbjsgUEFERElORy1CT1RUT006 +IDBweDsgTUFSR0lOOiAwcHg7IFBBRERJTkctVE9QOiAwcHg7IEhFSUdIVDogNDBweCI+PFNQQU4g +DQogIGNsYXNzPXR4dF9ibHVlIHN0eWxlPSJDT0xPUjogcmdiKDEsOTUsMTgyKSI+PEEgDQogIHN0 +eWxlPSJDT0xPUjogcmdiKDEsOTUsMTgyKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgaHJl +Zj0iaHR0cDovL3Quc2luYS5jb20uY24vMTYwMTg4ODM2NyI+6LW15rSLYnJ1Y2U8L0E+77yaPC9T +UEFOPuadgOavkui9r+S7tuaDr+eUqOS8juS/qe+8jOiEseS6humprOeUsuS7lui/mOaYr+S5jOm+ +n+OAgiANCiAgLy9A6Jab6Juu5a2QOuatpOmjjuS4jeWPr+mVv++8jOWTquacieWMu+eUn+WFiOaS +kueXheavkuWGjeayu+eXheeahOOAguW6lOivpeeri+azleS4peemge+8gSAvL0DmrKfok6xBVOen +u+WKqOS6kuiBlOe9kTog6YCg55eF5q+S5pep5bCx5piv55S16ISR6KGM5Lia5oOv5L6L44CC5omL +5py66KGM5Lia5Lmf5LiN5L6L5aSW5ZCn44CCIA0KICAvL0DotbXlspc66L2s5Y+R5b6u5Y2aPC9Q +Pg0KICA8UCBjbGFzcz0iYnRtdGltZSB0eHRfYmx1ZSIgdGl0bGU9IjIwMTAtMTItMTYgMDE6MTI6 +MzEiIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiA1 +MCUgMTAwJTsgUEFERElORy1MRUZUOiAwcHg7IEJBQ0tHUk9VTkQtQVRUQUNITUVOVDogc2Nyb2xs +OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2Ru +aW5kZXhfcGljMTQuZ2lmKTsgUEFERElORy1CT1RUT006IDNweDsgTUFSR0lOOiAwcHg7IENPTE9S +OiByZ2IoMSw5NSwxODIpOyBQQURESU5HLVRPUDogMnB4OyBCQUNLR1JPVU5ELUNPTE9SOiB0cmFu +c3BhcmVudDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5p +dGlhbCI+OSANCiAgaG91cnMgYWdvPC9QPjwvREQ+PC9ETD4NCjxESVYgY2xhc3M9bW9yZSANCnN0 +eWxlPSJQQURESU5HLVJJR0hUOiAxMHB4OyBQQURESU5HLUxFRlQ6IDEwcHg7IEZMT0FUOiBsZWZ0 +OyBQQURESU5HLUJPVFRPTTogMTBweDsgV0lEVEg6IDIzOHB4OyBQQURESU5HLVRPUDogMHB4OyBU +RVhULUFMSUdOOiByaWdodCI+5pu05aSa56e75Yqo6LWE6K6vPFNQQU4gDQpjbGFzcz1BcHBsZS1j +b252ZXJ0ZWQtc3BhY2U+Jm5ic3A7PC9TUEFOPjxBIGNsYXNzPXR4dF9ibHVlIA0Kc3R5bGU9IkZP +TlQtV0VJR0hUOiBib2xkOyBDT0xPUjogcmdiKDEsOTUsMTgyKTsgVEVYVC1ERUNPUkFUSU9OOiB1 +bmRlcmxpbmUiIA0KaHJlZj0iaHR0cDovL3Quc2luYS5jb20uY24vY3Nkbm1vYmlsZSI+6K+36L+b +5YWlJmd0OyZndDs8L0E+PC9ESVY+DQo8SDMgDQpzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBC +QUNLR1JPVU5ELVBPU0lUSU9OOiAwcHggMHB4OyBESVNQTEFZOiBpbmxpbmU7IFBBRERJTkctTEVG +VDogMjBweDsgRk9OVC1TSVpFOiAxNHB4OyBGTE9BVDogbGVmdDsgQkFDS0dST1VORC1JTUFHRTog +dXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzE1LmdpZik7IFBB +RERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4IDBweCA3cHg7IFdJRFRIOiAyMzlweDsgTElO +RS1IRUlHSFQ6IDMwcHg7IFBBRERJTkctVE9QOiAwcHg7IFBPU0lUSU9OOiByZWxhdGl2ZTsgYmFj +a2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PFNQQU4g +DQpjbGFzcz0idHh0XzEyIHR4dF9ncmF5IiANCnN0eWxlPSJGT05ULVdFSUdIVDogbm9ybWFsOyBG +T05ULVNJWkU6IDEycHg7IEZMT0FUOiByaWdodDsgTUFSR0lOOiAycHggN3B4IDBweCAwcHg7IENP +TE9SOiByZ2IoMTAyLDEwMiwxMDIpIj48QSANCnN0eWxlPSJDT0xPUjogcmdiKDEwMiwxMDIsMTAy +KTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCmhyZWY9Imh0dHA6Ly93d3cucHJvZ3JhbW1lci5j +b20uY24vIiB0YXJnZXQ9X2JsYW5rPuabtOWkmjwvQT48L1NQQU4+44CK56iL5bqP5ZGY44CLPC9I +Mz4NCjxETCBjbGFzcz1zdHlsZTMgDQpzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBESVNQTEFZ +OiBpbmxpbmU7IFBBRERJTkctTEVGVDogMHB4OyBGTE9BVDogbGVmdDsgUEFERElORy1CT1RUT006 +IDBweDsgTUFSR0lOOiA1cHggMTBweDsgV0lEVEg6IDIzOXB4OyBQQURESU5HLVRPUDogMHB4Ij4N +CiAgPEREIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9O +OiAzcHggN3B4OyBQQURESU5HLUxFRlQ6IDE0cHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRw +Oi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMyMy5naWYpOyBQQURESU5HLUJP +VFRPTTogMHB4OyBNQVJHSU46IDBweDsgTElORS1IRUlHSFQ6IDIxcHg7IFBBRERJTkctVE9QOiAw +cHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwi +PjxBIA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIg +DQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDE2NCk7IA0KICBocmVmPSJodHRwOi8vd3d3 +LnByb2dyYW1tZXIuY29tLmNuLzQ0NDgvIj7lgZrmnInluILlnLrmgJ3nu7TnmoTlvIDlj5Hkurrl +kZg8L0E+PC9ERD4NCiAgPEREIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JP +VU5ELVBPU0lUSU9OOiAzcHggN3B4OyBQQURESU5HLUxFRlQ6IDE0cHg7IEJBQ0tHUk9VTkQtSU1B +R0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMyMy5naWYp +OyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweDsgTElORS1IRUlHSFQ6IDIxcHg7IFBB +RERJTkctVE9QOiAwcHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNs +aXA6IGluaXRpYWwiPjxBIA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JB +VElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDE2NCk7IA0KICBocmVm +PSJodHRwOi8vd3d3LnByb2dyYW1tZXIuY29tLmNuLzQ0NDQvIj5XYXR0cyBTLiBIdW1waHJlee+8 +mui9r+S7tui0qOmHj+S5i+eItjwvQT48L0REPg0KICA8REQgDQogIHN0eWxlPSJQQURESU5HLVJJ +R0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDNweCA3cHg7IFBBRERJTkctTEVGVDogMTRw +eDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3Nk +bmluZGV4X3BpYzIzLmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBMSU5F +LUhFSUdIVDogMjFweDsgUEFERElORy1UT1A6IDBweDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRp +YWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHN0eWxlPSJDT0xPUjogcmdiKDAs +MCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRo +aXMsMTY0KTsgDQogIGhyZWY9Imh0dHA6Ly93d3cucHJvZ3JhbW1lci5jb20uY24vNDQ0MS8iPuWu +ieWFqOato+WboOS6keiAjOaUueWPmDwvQT48L0REPg0KICA8REQgDQogIHN0eWxlPSJQQURESU5H +LVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDNweCA3cHg7IFBBRERJTkctTEVGVDog +MTRweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMv +Y3NkbmluZGV4X3BpYzIzLmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBM +SU5FLUhFSUdIVDogMjFweDsgUEFERElORy1UT1A6IDBweDsgYmFja2dyb3VuZC1vcmlnaW46IGlu +aXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHN0eWxlPSJDT0xPUjogcmdi +KDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50 +KHRoaXMsMTY0KTsgDQogIGhyZWY9Imh0dHA6Ly93d3cucHJvZ3JhbW1lci5jb20uY24vNDQzOC8i +PuiSi+a2m++8muaipuaDs+eahOWNgeW5tDwvQT48L0REPjwvREw+DQo8SDMgDQpzdHlsZT0iUEFE +RElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAwcHggMHB4OyBESVNQTEFZOiBp +bmxpbmU7IFBBRERJTkctTEVGVDogMjBweDsgRk9OVC1TSVpFOiAxNHB4OyBGTE9BVDogbGVmdDsg +QkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3Nkbmlu +ZGV4X3BpYzE1LmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4IDBweCA3cHg7 +IFdJRFRIOiAyMzlweDsgTElORS1IRUlHSFQ6IDMwcHg7IFBBRERJTkctVE9QOiAwcHg7IFBPU0lU +SU9OOiByZWxhdGl2ZTsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xp +cDogaW5pdGlhbCI+PFNQQU4gDQpjbGFzcz0idHh0XzEyIHR4dF9ncmF5IiANCnN0eWxlPSJGT05U +LVdFSUdIVDogbm9ybWFsOyBGT05ULVNJWkU6IDEycHg7IEZMT0FUOiByaWdodDsgTUFSR0lOOiAy +cHggN3B4IDBweCAwcHg7IENPTE9SOiByZ2IoMTAyLDEwMiwxMDIpIj48QSANCnN0eWxlPSJDT0xP +UjogcmdiKDEwMiwxMDIsMTAyKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCmhyZWY9Imh0dHA6 +Ly9uZXdzLmNzZG4ubmV0LyIgdGFyZ2V0PV9ibGFuaz7mm7TlpJo8L0E+PC9TUEFOPueDreeCuei1 +hOiur+aOkuihjDwvSDM+DQo8REwgY2xhc3M9InN0eWxlMiB0eHRfYmxhY2siIA0Kc3R5bGU9IlBB +RERJTkctUklHSFQ6IDBweDsgRElTUExBWTogaW5saW5lOyBQQURESU5HLUxFRlQ6IDBweDsgRkxP +QVQ6IGxlZnQ7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogNXB4IDEwcHg7IFdJRFRIOiAy +MzlweDsgQ09MT1I6IHJnYigwLDAsMCk7IFBBRERJTkctVE9QOiAwcHgiPg0KICA8RFQgY2xhc3M9 +dG9wMSANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjog +MHB4IDNweDsgT1ZFUkZMT1ctWTogaGlkZGVuOyBQQURESU5HLUxFRlQ6IDI0cHg7IEJBQ0tHUk9V +TkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMz +NS5naWYpOyBPVkVSRkxPVy1YOiBoaWRkZW47IFBBRERJTkctQk9UVE9NOiAxcHg7IE1BUkdJTjog +MHB4OyBXSURUSDogMjEwcHg7IFBBRERJTkctVE9QOiA0cHg7IFdISVRFLVNQQUNFOiBub3dyYXA7 +IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxB +IA0KICB0aXRsZT3nibnnq4vni6zooYznmoTnqIvluo/lkZjvvJrnu7Tln7rop6Plr4bliJvlp4vk +urrpmL/moZHlpYfkvKDlpYcgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJ +T046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcywxMDUpOyANCiAgaHJlZj0i +aHR0cDovL25ld3MuY3Nkbi5uZXQvYS8yMDEwMTIxNS8yODM2NjcuaHRtbCIgDQogIHRhcmdldD1f +Ymxhbms+54m556uL54us6KGM55qE56iL5bqP5ZGY77ya57u05Z+66Kej5a+G5Yib5aeL5Lq66Zi/ +5qGR5aWH5Lyg5aWHPC9BPjwvRFQ+DQogIDxEVCBjbGFzcz10b3AyIA0KICBzdHlsZT0iUEFERElO +Ry1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAwcHggM3B4OyBPVkVSRkxPVy1ZOiBo +aWRkZW47IFBBRERJTkctTEVGVDogMjRweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9j +c2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzM2LmdpZik7IE9WRVJGTE9XLVg6IGhp +ZGRlbjsgUEFERElORy1CT1RUT006IDFweDsgTUFSR0lOOiAwcHg7IFdJRFRIOiAyMTBweDsgUEFE +RElORy1UT1A6IDRweDsgV0hJVEUtU1BBQ0U6IG5vd3JhcDsgYmFja2dyb3VuZC1vcmlnaW46IGlu +aXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxlPSJHbWFpbOS5i+eI +tu+8mkNocm9tZSBPU+adpeaXpeaXoOWkmiIgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhU +LURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcywxMDUpOyAN +CiAgaHJlZj0iaHR0cDovL25ld3MuY3Nkbi5uZXQvYS8yMDEwMTIxNS8yODM2NjYuaHRtbCIgDQog +IHRhcmdldD1fYmxhbms+R21haWzkuYvniLbvvJpDaHJvbWUgT1PmnaXml6Xml6DlpJo8L0E+PC9E +VD4NCiAgPERUIGNsYXNzPXRvcDMgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tH +Uk9VTkQtUE9TSVRJT046IDBweCAzcHg7IE9WRVJGTE9XLVk6IGhpZGRlbjsgUEFERElORy1MRUZU +OiAyNHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdl +cy9jc2RuaW5kZXhfcGljMzcuZ2lmKTsgT1ZFUkZMT1ctWDogaGlkZGVuOyBQQURESU5HLUJPVFRP +TTogMXB4OyBNQVJHSU46IDBweDsgV0lEVEg6IDIxMHB4OyBQQURESU5HLVRPUDogNHB4OyBXSElU +RS1TUEFDRTogbm93cmFwOyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1j +bGlwOiBpbml0aWFsIj48QSANCiAgdGl0bGU9IkxCU+WwhuaIkOS6kuiBlOe9keS4i+S4gOWcuuih +gOiFpeaImCAy5bm05ZCO5biC5Zy66LaF55m+5Lq/IiANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCww +LDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhp +cywxMDUpOyANCiAgaHJlZj0iaHR0cDovL25ld3MuY3Nkbi5uZXQvYS8yMDEwMTIxNC8yODM1OTMu +aHRtbCIgDQogIHRhcmdldD1fYmxhbms+TEJT5bCG5oiQ5LqS6IGU572R5LiL5LiA5Zy66KGA6IWl +5oiYIDLlubTlkI7luILlnLrotoXnmb7kur88L0E+PC9EVD4NCiAgPERUIGNsYXNzPXRvcDQgDQog +IHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDBweCAzcHg7 +IE9WRVJGTE9XLVk6IGhpZGRlbjsgUEFERElORy1MRUZUOiAyNHB4OyBCQUNLR1JPVU5ELUlNQUdF +OiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMzguZ2lmKTsg +T1ZFUkZMT1ctWDogaGlkZGVuOyBQQURESU5HLUJPVFRPTTogMXB4OyBNQVJHSU46IDBweDsgV0lE +VEg6IDIxMHB4OyBQQURESU5HLVRPUDogNHB4OyBXSElURS1TUEFDRTogbm93cmFwOyBiYWNrZ3Jv +dW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgdGl0 +bGU95aSW5aqS6K+E6YCJ6L+H5Y67MjXlubQxMOWkp+m7keWuouaUu+WHu+S6i+S7tiBzdHlsZT0i +Q09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9n +Q2xpY2tDb3VudCh0aGlzLDEwNSk7IA0KICBocmVmPSJodHRwOi8vY2xvdWQuY3Nkbi5uZXQvYS8y +MDEwMTIxNC8yODM1NzcuaHRtbCIgDQogIHRhcmdldD1fYmxhbms+5aSW5aqS6K+E6YCJ6L+H5Y67 +MjXlubQxMOWkp+m7keWuouaUu+WHu+S6i+S7tjwvQT48L0RUPg0KICA8RFQgY2xhc3M9dG9wNSAN +CiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMHB4IDNw +eDsgT1ZFUkZMT1ctWTogaGlkZGVuOyBQQURESU5HLUxFRlQ6IDI0cHg7IEJBQ0tHUk9VTkQtSU1B +R0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMzOS5naWYp +OyBPVkVSRkxPVy1YOiBoaWRkZW47IFBBRERJTkctQk9UVE9NOiAxcHg7IE1BUkdJTjogMHB4OyBX +SURUSDogMjEwcHg7IFBBRERJTkctVE9QOiA0cHg7IFdISVRFLVNQQUNFOiBub3dyYXA7IGJhY2tn +cm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0 +aXRsZT3lvq7ova/lrqPluIPlj4jkuIDpnZ5XaW5kb3dz5pON5L2c57O757ufVmVydmUgc3R5bGU9 +IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxv +Z0NsaWNrQ291bnQodGhpcywxMDUpOyANCiAgaHJlZj0iaHR0cDovL25ld3MuY3Nkbi5uZXQvYS8y +MDEwMTIxMy8yODM1MzYuaHRtbCIgDQogIHRhcmdldD1fYmxhbms+5b6u6L2v5a6j5biD5Y+I5LiA +6Z2eV2luZG93c+aTjeS9nOezu+e7n1ZlcnZlPC9BPjwvRFQ+DQogIDxEVCBjbGFzcz10b3A2IA0K +ICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAwcHggM3B4 +OyBPVkVSRkxPVy1ZOiBoaWRkZW47IFBBRERJTkctTEVGVDogMjRweDsgQkFDS0dST1VORC1JTUFH +RTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzQwLmdpZik7 +IE9WRVJGTE9XLVg6IGhpZGRlbjsgUEFERElORy1CT1RUT006IDFweDsgTUFSR0lOOiAwcHg7IFdJ +RFRIOiAyMTBweDsgUEFERElORy1UT1A6IDRweDsgV0hJVEUtU1BBQ0U6IG5vd3JhcDsgYmFja2dy +b3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRp +dGxlPSJDaHJvbWUgT1PnmoTnpZ7np5jprYXlipsiIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsg +VEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsMTA1 +KTsgDQogIGhyZWY9Imh0dHA6Ly9jbG91ZC5jc2RuLm5ldC9hLzIwMTAxMjEzLzI4MzQ3Mi5odG1s +IiB0YXJnZXQ9X2JsYW5rPkNocm9tZSANCiAgT1PnmoTnpZ7np5jprYXlips8L0E+PC9EVD4NCiAg +PERUIGNsYXNzPXRvcDcgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQt +UE9TSVRJT046IDBweCAzcHg7IE9WRVJGTE9XLVk6IGhpZGRlbjsgUEFERElORy1MRUZUOiAyNHB4 +OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2Ru +aW5kZXhfcGljNDEuZ2lmKTsgT1ZFUkZMT1ctWDogaGlkZGVuOyBQQURESU5HLUJPVFRPTTogMXB4 +OyBNQVJHSU46IDBweDsgV0lEVEg6IDIxMHB4OyBQQURESU5HLVRPUDogNHB4OyBXSElURS1TUEFD +RTogbm93cmFwOyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBp +bml0aWFsIj48QSANCiAgdGl0bGU96Iu55p6c5bel56iL5biI55So5LmQ6auY56ev5pyo6YeN5bu6 +5pyA5Y+k6ICB6K6h566X5py6IHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFU +SU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsMTA1KTsgDQogIGhyZWY9 +Imh0dHA6Ly9uZXdzLmNzZG4ubmV0L2EvMjAxMDEyMTMvMjgzNDc5Lmh0bWwiIA0KICB0YXJnZXQ9 +X2JsYW5rPuiLueaenOW3peeoi+W4iOeUqOS5kOmrmOenr+acqOmHjeW7uuacgOWPpOiAgeiuoeeu +l+acujwvQT48L0RUPg0KICA8RFQgY2xhc3M9dG9wOCANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6 +IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMHB4IDNweDsgT1ZFUkZMT1ctWTogaGlkZGVuOyBQ +QURESU5HLUxFRlQ6IDI0cHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5j +bi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWM0Mi5naWYpOyBPVkVSRkxPVy1YOiBoaWRkZW47IFBB +RERJTkctQk9UVE9NOiAxcHg7IE1BUkdJTjogMHB4OyBXSURUSDogMjEwcHg7IFBBRERJTkctVE9Q +OiA0cHg7IFdISVRFLVNQQUNFOiBub3dyYXA7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBi +YWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0aXRsZT0i6Zi/5biV5aWH5Z+66YeR5Lya +5qyy6YCA5Ye6SmF2YeWnlOWRmOS8miDnlLLpqqjmlofmnJvlhbbkuInmgJ0iIA0KICBzdHlsZT0i +Q09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9n +Q2xpY2tDb3VudCh0aGlzLDEwNSk7IA0KICBocmVmPSJodHRwOi8vamF2YS5jc2RuLm5ldC9hLzIw +MTAxMjEzLzI4MzQ4MC5odG1sIiANCiAgdGFyZ2V0PV9ibGFuaz7pmL/luJXlpYfln7rph5HkvJrm +rLLpgIDlh7pKYXZh5aeU5ZGY5LyaIOeUsumqqOaWh+acm+WFtuS4ieaAnTwvQT48L0RUPg0KICA8 +RFQgY2xhc3M9dG9wOSANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1Q +T1NJVElPTjogMHB4IDNweDsgT1ZFUkZMT1ctWTogaGlkZGVuOyBQQURESU5HLUxFRlQ6IDI0cHg7 +IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5p +bmRleF9waWM0My5naWYpOyBPVkVSRkxPVy1YOiBoaWRkZW47IFBBRERJTkctQk9UVE9NOiAxcHg7 +IE1BUkdJTjogMHB4OyBXSURUSDogMjEwcHg7IFBBRERJTkctVE9QOiA0cHg7IFdISVRFLVNQQUNF +OiBub3dyYXA7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGlu +aXRpYWwiPjxBIA0KICB0aXRsZT0yMDEw5bm05raI6LS555S15a2Q5oqA5pyvMjDkuKrmnIDlpKfl +pLHotKXvvJpCdXp65bGF6aaWIA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVD +T1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDEwNSk7IA0KICBo +cmVmPSJodHRwOi8vbmV3cy5jc2RuLm5ldC9hLzIwMTAxMjEzLzI4MzQ2NS5odG1sIiANCiAgdGFy +Z2V0PV9ibGFuaz4yMDEw5bm05raI6LS555S15a2Q5oqA5pyvMjDkuKrmnIDlpKflpLHotKXvvJpC +dXp65bGF6aaWPC9BPjwvRFQ+DQogIDxEVCBjbGFzcz10b3AxMCANCiAgc3R5bGU9IlBBRERJTkct +UklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMHB4IDNweDsgT1ZFUkZMT1ctWTogaGlk +ZGVuOyBQQURESU5HLUxFRlQ6IDI0cHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3Nk +bmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWM0NC5naWYpOyBPVkVSRkxPVy1YOiBoaWRk +ZW47IFBBRERJTkctQk9UVE9NOiAxcHg7IE1BUkdJTjogMHB4OyBXSURUSDogMjEwcHg7IFBBRERJ +TkctVE9QOiA0cHg7IFdISVRFLVNQQUNFOiBub3dyYXA7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0 +aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0aXRsZT3kurrmsJHmkJzntKLv +vJrkuI3kuI7llYbkuJrmkJzntKLmraPpnaLnq57kuokgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDAp +OyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcywx +MDUpOyANCiAgaHJlZj0iaHR0cDovL25ld3MuY3Nkbi5uZXQvYS8yMDEwMTIxMC8yODMzNjkuaHRt +bCIgDQogIHRhcmdldD1fYmxhbms+5Lq65rCR5pCc57Si77ya5LiN5LiO5ZWG5Lia5pCc57Si5q2j +6Z2i56ue5LqJPC9BPjwvRFQ+PC9ETD48L0RJVj48L0RJVj48L0RJVj4NCjxESVYgY2xhc3M9cGFn +ZWNvbl9sYXllcjJidG0gDQpzdHlsZT0iQkFDS0dST1VORC1QT1NJVElPTjogNTAlIDEwMCU7IEZP +TlQtU0laRTogMXB4OyBGTE9BVDogbGVmdDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9j +c2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzQ1LmdpZik7IFdJRFRIOiA5NjBweDsg +SEVJR0hUOiAxcHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6 +IGluaXRpYWwiPjwvRElWPg0KPERJViBjbGFzcz1idXNpbmVzc2FkIA0Kc3R5bGU9IkZMT0FUOiBs +ZWZ0OyBNQVJHSU46IDRweCAwcHggMHB4OyBXSURUSDogOTYwcHg7IFBPU0lUSU9OOiByZWxhdGl2 +ZTsgVEVYVC1BTElHTjogbGVmdCI+DQo8VUwgDQpzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBQ +QURESU5HLUxFRlQ6IDBweDsgRkxPQVQ6IGxlZnQ7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJ +TjogMHB4OyBXSURUSDogOTYwcHg7IFBBRERJTkctVE9QOiAwcHg7IExJU1QtU1RZTEUtVFlQRTog +bm9uZSI+DQogIDxMSSBjbGFzcz1sZWZ0YWQgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7 +IFBBRERJTkctTEVGVDogMHB4OyBGTE9BVDogbGVmdDsgUEFERElORy1CT1RUT006IDBweDsgTUFS +R0lOOiAwcHg7IFdJRFRIOiA3MzVweDsgUEFERElORy1UT1A6IDBweCI+PEEgDQogIHN0eWxlPSJD +T0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgaHJlZj0iaHR0cDov +L3ouY3Nkbi5uZXQvZ21jbGljay5waHA/YmFubmVyaWQ9NTQzMyZhbXA7em9uZWlkPTQwNyZhbXA7 +c291cmNlPSZhbXA7ZGVzdD1odHRwJTNBJTJGJTJGd3d3LmludGVsc29mdHdhcmVjaGFubmVsLmNv +bSUyRiIgDQogIHRhcmdldD1fYmxhbms+PElNRyB0aXRsZT0iIiANCiAgc3R5bGU9IkJPUkRFUi1U +T1AtV0lEVEg6IDBweDsgQk9SREVSLUxFRlQtV0lEVEg6IDBweDsgQk9SREVSLUJPVFRPTS1XSURU +SDogMHB4OyBCT1JERVItUklHSFQtV0lEVEg6IDBweCIgDQogIGhlaWdodD05MCBhbHQ9IiIgDQog +IHNyYz0iaHR0cDovL2luZm8tZGF0YWJhc2UuY3Nkbi5uZXQvVXBsb2FkLzIwMTAtMTItMTAvNzM1 +XzkwX2FubmllLmpwZyIgDQogIHdpZHRoPTczNSBib3JkZXI9MD48L0E+DQogIDxESVYgaWQ9YmVh +Y29uXzU0MzMgDQogIHN0eWxlPSJMRUZUOiAwcHg7IFZJU0lCSUxJVFk6IGhpZGRlbjsgUE9TSVRJ +T046IGFic29sdXRlOyBUT1A6IDBweCI+PElNRyANCiAgc3R5bGU9IkJPUkRFUi1UT1AtV0lEVEg6 +IDBweDsgQk9SREVSLUxFRlQtV0lEVEg6IDBweDsgQk9SREVSLUJPVFRPTS1XSURUSDogMHB4OyBX +SURUSDogMHB4OyBIRUlHSFQ6IDBweDsgQk9SREVSLVJJR0hULVdJRFRIOiAwcHgiIA0KICBoZWln +aHQ9MCBhbHQ9IiIgDQogIHNyYz0iaHR0cDovL3ouY3Nkbi5uZXQvZ21sb2cucGhwP2Jhbm5lcmlk +PTU0MzMmYW1wO2NsaWVudGlkPTE3MDMmYW1wO3pmPSZhbXA7em9uZWlkPTQwNyZhbXA7c291cmNl +PSZhbXA7YmxvY2s9MCZhbXA7Y2FwcGluZz0wJmFtcDtjYj1iY2E3ZDRmMTg3OGJmMmFhNmJiMjk4 +NGFlZWUxNjRjYyIgDQogIHdpZHRoPTA+PC9ESVY+PC9MST4NCiAgPExJIGNsYXNzPXJpZ2h0YWQg +DQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IFBBRERJTkctTEVGVDogMHB4OyBGTE9BVDog +cmlnaHQ7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBXSURUSDogMjEwcHg7IFBB +RERJTkctVE9QOiAwcHgiPjxBIA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVD +T1JBVElPTjogbm9uZSIgDQogIGhyZWY9Imh0dHA6Ly96LmNzZG4ubmV0L2dtY2xpY2sucGhwP2Jh +bm5lcmlkPTU0MDAmYW1wO3pvbmVpZD00MDgmYW1wO3NvdXJjZT0mYW1wO2Rlc3Q9aHR0cCUzQSUy +RiUyRjE4OXdvcmtzLmNzZG4ubmV0JTJGKyIgDQogIHRhcmdldD1fYmxhbms+PElNRyB0aXRsZT0i +IiANCiAgc3R5bGU9IkJPUkRFUi1UT1AtV0lEVEg6IDBweDsgQk9SREVSLUxFRlQtV0lEVEg6IDBw +eDsgQk9SREVSLUJPVFRPTS1XSURUSDogMHB4OyBCT1JERVItUklHSFQtV0lEVEg6IDBweCIgDQog +IGhlaWdodD05MCBhbHQ9IiIgDQogIHNyYz0iaHR0cDovL2luZm8tZGF0YWJhc2UuY3Nkbi5uZXQv +VXBsb2FkLzIwMTAtMTItMDMvMjEwXzkwXzExMDMuZ2lmIiANCiAgd2lkdGg9MjEwIGJvcmRlcj0w +PjwvQT4NCiAgPERJViBpZD1iZWFjb25fNTQwMCANCiAgc3R5bGU9IkxFRlQ6IDBweDsgVklTSUJJ +TElUWTogaGlkZGVuOyBQT1NJVElPTjogYWJzb2x1dGU7IFRPUDogMHB4Ij48SU1HIA0KICBzdHls +ZT0iQk9SREVSLVRPUC1XSURUSDogMHB4OyBCT1JERVItTEVGVC1XSURUSDogMHB4OyBCT1JERVIt +Qk9UVE9NLVdJRFRIOiAwcHg7IFdJRFRIOiAwcHg7IEhFSUdIVDogMHB4OyBCT1JERVItUklHSFQt +V0lEVEg6IDBweCIgDQogIGhlaWdodD0wIGFsdD0iIiANCiAgc3JjPSJodHRwOi8vei5jc2RuLm5l +dC9nbWxvZy5waHA/YmFubmVyaWQ9NTQwMCZhbXA7Y2xpZW50aWQ9MTY5OSZhbXA7emY9JmFtcDt6 +b25laWQ9NDA4JmFtcDtzb3VyY2U9JmFtcDtibG9jaz0wJmFtcDtjYXBwaW5nPTAmYW1wO2NiPTNj +ZTJlMDQ2MTYyZGM0MmY3M2Y4NDczMWFmYmJhNzcxIiANCiAgd2lkdGg9MD48L0RJVj48L0xJPjwv +VUw+PC9ESVY+DQo8RElWIGNsYXNzPXBhZ2Vjb25fbGF5ZXIyIA0Kc3R5bGU9IkZMT0FUOiBsZWZ0 +OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2Ru +aW5kZXhfcGljMzMuZ2lmKTsgTUFSR0lOOiAzcHggMHB4IDBweDsgV0lEVEg6IDk2MHB4OyBQT1NJ +VElPTjogcmVsYXRpdmU7IFRFWFQtQUxJR046IGxlZnQ7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0 +aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPg0KPERJViBjbGFzcz1wYWdlXzA5c2lkZWJh +cndyYXAgDQpzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCT1JERVItVE9QOiByZ2IoMjA0LDIw +NCwyMDQpIDFweCBzb2xpZDsgRElTUExBWTogaW5saW5lOyBQQURESU5HLUxFRlQ6IDBweDsgRkxP +QVQ6IHJpZ2h0OyBQQURESU5HLUJPVFRPTTogNnB4OyBNQVJHSU46IDBweCAxcHggMHB4IDBweDsg +V0lEVEg6IDIwOHB4OyBQQURESU5HLVRPUDogMHB4OyBURVhULUFMSUdOOiBsZWZ0Ij4NCjxESVYg +Y2xhc3M9c2lkZWJhcl9jb24gDQpzdHlsZT0iRElTUExBWTogaW5saW5lOyBGTE9BVDogbGVmdDsg +TUFSR0lOOiA2cHggM3B4IDJweDsgV0lEVEg6IDIwMnB4Ij4NCjxINCBjbGFzcz10eHRfMTIgDQpz +dHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBQQURESU5HLUxFRlQ6IDNweDsgRk9OVC1TSVpFOiAx +MnB4OyBQQURESU5HLUJPVFRPTTogNXB4OyBNQVJHSU46IDBweDsgUEFERElORy1UT1A6IDBweDsg +Qk9SREVSLUJPVFRPTTogcmdiKDIwNCwyMDQsMjA0KSAxcHggc29saWQ7IFBPU0lUSU9OOiByZWxh +dGl2ZSI+PFNQQU4gDQpjbGFzcz10eHRfZ3JheSANCnN0eWxlPSJGT05ULVdFSUdIVDogbm9ybWFs +OyBGTE9BVDogcmlnaHQ7IENPTE9SOiByZ2IoMTAyLDEwMiwxMDIpIj58PEEgDQpzdHlsZT0iUEFE +RElORy1SSUdIVDogMHB4OyBQQURESU5HLUxFRlQ6IDVweDsgUEFERElORy1CT1RUT006IDBweDsg +Q09MT1I6IHJnYigxMDIsMTAyLDEwMik7IFBBRERJTkctVE9QOiAwcHg7IFRFWFQtREVDT1JBVElP +Tjogbm9uZSIgDQpocmVmPSJodHRwOi8vc3R1ZGVudC5jc2RuLm5ldC8iIHRhcmdldD1fYmxhbms+ +5pu05aSaPC9BPjwvU1BBTj7lrabkuaDnqbrpl7Q8L0g0Pg0KPERMIGNsYXNzPXNlc3Npb25fc3R5 +bGUgDQpzdHlsZT0iUEFERElORy1SSUdIVDogM3B4OyBQQURESU5HLUxFRlQ6IDNweDsgRkxPQVQ6 +IGxlZnQ7IFBBRERJTkctQk9UVE9NOiA1cHg7IE1BUkdJTjogMnB4IDBweCAwcHg7IFdJRFRIOiAx +OTZweDsgUEFERElORy1UT1A6IDEwcHg7IEJPUkRFUi1CT1RUT006IHJnYigyMDQsMjA0LDIwNCkg +MXB4IHNvbGlkOyBCQUNLR1JPVU5ELUNPTE9SOiByZ2IoMjU1LDI1NSwyNTUpOyBiYWNrZ3JvdW5k +LW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj4NCiAgPEREIA0KICBz +dHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAycHggN3B4OyBQ +QURESU5HLUxFRlQ6IDEycHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5j +bi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWM1LmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1B +UkdJTjogMHB4OyBMSU5FLUhFSUdIVDogMTlweDsgUEFERElORy1UT1A6IDBweDsgYmFja2dyb3Vu +ZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxl +PSIxMi0xNeiusuWggiBMaW51eOezu+e7n+W8leWvvOa1geeoi++8iOS4iu+8iSIgDQogIHN0eWxl +PSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1M +b2dDbGlja0NvdW50KHRoaXMsOTUpOyANCiAgaHJlZj0iaHR0cDovL3N0dWRlbnQuY3Nkbi5uZXQv +c3BhY2UucGhwP2RvPW9ubGluZXJvb20mYW1wO2lkPTIxNiIgDQogIHRhcmdldD1fYmxhbms+MTIt +MTXorrLloIIgTGludXjns7vnu588L0E+PC9ERD4NCiAgPEREIGNsYXNzPSJzb3VyY2Vfc3R5IHR4 +dF9ibGFjayIgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IFBBRERJTkctTEVGVDogMTJw +eDsgQkFDS0dST1VORC1JTUFHRTogbm9uZTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAw +cHg7IENPTE9SOiByZ2IoMCwwLDApOyBMSU5FLUhFSUdIVDogMTlweDsgUEFERElORy1UT1A6IDBw +eDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+ +PEVNIA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IEZPTlQtU1RZTEU6IG5vcm1hbCI+PC9F +TT48L0REPg0KICA8REQgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQt +UE9TSVRJT046IDJweCA3cHg7IFBBRERJTkctTEVGVDogMTJweDsgQkFDS0dST1VORC1JTUFHRTog +dXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzUuZ2lmKTsgUEFE +RElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IExJTkUtSEVJR0hUOiAxOXB4OyBQQURESU5H +LVRPUDogMHB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBp +bml0aWFsIj48QSANCiAgdGl0bGU9IjEyLTE16K6y5aCCIOWchuWRqOeOh+eahOi/keS8vOiuoeeu +lyIgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBv +bmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw5NSk7IA0KICBocmVmPSJodHRwOi8vc3R1ZGVudC5j +c2RuLm5ldC9zcGFjZS5waHA/ZG89b25saW5lcm9vbSZhbXA7aWQ9MjIxIiANCiAgdGFyZ2V0PV9i +bGFuaz4xMi0xNeiusuWggiDlnIblkajnjofnmoTov5HkvLzorqE8L0E+PC9ERD4NCiAgPEREIGNs +YXNzPSJzb3VyY2Vfc3R5IHR4dF9ibGFjayIgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7 +IFBBRERJTkctTEVGVDogMTJweDsgQkFDS0dST1VORC1JTUFHRTogbm9uZTsgUEFERElORy1CT1RU +T006IDBweDsgTUFSR0lOOiAwcHg7IENPTE9SOiByZ2IoMCwwLDApOyBMSU5FLUhFSUdIVDogMTlw +eDsgUEFERElORy1UT1A6IDBweDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91 +bmQtY2xpcDogaW5pdGlhbCI+PEVNIA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IEZPTlQt +U1RZTEU6IG5vcm1hbCI+PC9FTT48L0REPg0KICA8REQgDQogIHN0eWxlPSJQQURESU5HLVJJR0hU +OiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDJweCA3cHg7IFBBRERJTkctTEVGVDogMTJweDsg +QkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3Nkbmlu +ZGV4X3BpYzUuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IExJTkUtSEVJ +R0hUOiAxOXB4OyBQQURESU5HLVRPUDogMHB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsg +YmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgdGl0bGU9IjEyLTE26K6y5aCCIExpbnV4 +57O757uf5byV5a+85rWB56iL77yI5LiL77yJIiANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDAp +OyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw5 +NSk7IA0KICBocmVmPSJodHRwOi8vc3R1ZGVudC5jc2RuLm5ldC9zcGFjZS5waHA/ZG89b25saW5l +cm9vbSZhbXA7aWQ9MjE3IiANCiAgdGFyZ2V0PV9ibGFuaz4xMi0xNuiusuWggiBMaW51eOezu+e7 +nzwvQT48L0REPg0KICA8REQgY2xhc3M9InNvdXJjZV9zdHkgdHh0X2JsYWNrIiANCiAgc3R5bGU9 +IlBBRERJTkctUklHSFQ6IDBweDsgUEFERElORy1MRUZUOiAxMnB4OyBCQUNLR1JPVU5ELUlNQUdF +OiBub25lOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweDsgQ09MT1I6IHJnYigwLDAs +MCk7IExJTkUtSEVJR0hUOiAxOXB4OyBQQURESU5HLVRPUDogMHB4OyBiYWNrZ3JvdW5kLW9yaWdp +bjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48RU0gDQogIHN0eWxlPSJDT0xP +UjogcmdiKDAsMCwwKTsgRk9OVC1TVFlMRTogbm9ybWFsIj48L0VNPjwvREQ+DQogIDxERCANCiAg +c3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMnB4IDdweDsg +UEFERElORy1MRUZUOiAxMnB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcu +Y24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljNS5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBN +QVJHSU46IDBweDsgTElORS1IRUlHSFQ6IDE5cHg7IFBBRERJTkctVE9QOiAwcHg7IGJhY2tncm91 +bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0aXRs +ZT0iMTItMTforrLloIIg5aSn5a2m55Sf6IGM5Lia55Sf5rav6KeE5YiSIiBzdHlsZT0iQ09MT1I6 +IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tD +b3VudCh0aGlzLDk1KTsgDQogIGhyZWY9Imh0dHA6Ly9zdHVkZW50LmNzZG4ubmV0L3NwYWNlLnBo +cD9kbz1vbmxpbmVyb29tJmFtcDtpZD0yMTkiIA0KICB0YXJnZXQ9X2JsYW5rPjEyLTE36K6y5aCC +IOWkp+WtpueUn+iBjOS4mueUn+a2rzwvQT48L0REPg0KICA8REQgY2xhc3M9InNvdXJjZV9zdHkg +dHh0X2JsYWNrIiANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgUEFERElORy1MRUZUOiAx +MnB4OyBCQUNLR1JPVU5ELUlNQUdFOiBub25lOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46 +IDBweDsgQ09MT1I6IHJnYigwLDAsMCk7IExJTkUtSEVJR0hUOiAxOXB4OyBQQURESU5HLVRPUDog +MHB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFs +Ij48RU0gDQogIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgRk9OVC1TVFlMRTogbm9ybWFsIj48 +L0VNPjwvREQ+DQogIDxERCANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VO +RC1QT1NJVElPTjogMnB4IDdweDsgUEFERElORy1MRUZUOiAxMnB4OyBCQUNLR1JPVU5ELUlNQUdF +OiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljNS5naWYpOyBQ +QURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweDsgTElORS1IRUlHSFQ6IDE5cHg7IFBBRERJ +TkctVE9QOiAwcHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6 +IGluaXRpYWwiPjxBIA0KICB0aXRsZT0i56yU6K6wIC5OZXTkuYvlvIDmupDlkozkuI3lvIDmupDn +moTog4zlkI4iIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25l +IiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsOTUpOyANCiAgaHJlZj0iaHR0cDovL3N0 +dWRlbnQuY3Nkbi5uZXQvbGluay5waHA/dXJsPWh0dHA6Ly9zdHVkZW50LmNzZG4ubmV0JTJGc3Bh +Y2UucGhwJTNGdWlkJTNEMzkwMTclMjZkbyUzRGJsb2clMjZpZCUzRDUyMjY0IiANCiAgdGFyZ2V0 +PV9ibGFuaz7nrJTorrAgLk5ldOS5i+W8gOa6kOWSjOS4jeW8gOa6kOeahDwvQT48L0REPg0KICA8 +REQgY2xhc3M9InNvdXJjZV9zdHkgdHh0X2JsYWNrIiANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6 +IDBweDsgUEFERElORy1MRUZUOiAxMnB4OyBCQUNLR1JPVU5ELUlNQUdFOiBub25lOyBQQURESU5H +LUJPVFRPTTogMHB4OyBNQVJHSU46IDBweDsgQ09MT1I6IHJnYigwLDAsMCk7IExJTkUtSEVJR0hU +OiAxOXB4OyBQQURESU5HLVRPUDogMHB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFj +a2dyb3VuZC1jbGlwOiBpbml0aWFsIj48RU0gDQogIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsg +Rk9OVC1TVFlMRTogbm9ybWFsIj48L0VNPjwvREQ+DQogIDxERCANCiAgc3R5bGU9IlBBRERJTkct +UklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMnB4IDdweDsgUEFERElORy1MRUZUOiAx +MnB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9j +c2RuaW5kZXhfcGljNS5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweDsgTElO +RS1IRUlHSFQ6IDE5cHg7IFBBRERJTkctVE9QOiAwcHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0 +aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0aXRsZT0i56yU6K6wIOS4gOS6 +m+Wkp+WFrOWPuOeahOW/g+eQhua1i+ivlemimCIgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBU +RVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw5NSk7 +IA0KICBocmVmPSJodHRwOi8vc3R1ZGVudC5jc2RuLm5ldC9saW5rLnBocD91cmw9aHR0cDovL3N0 +dWRlbnQuY3Nkbi5uZXQlMkZzcGFjZS5waHAlM0Z1aWQlM0Q0NDcyMiUyNmRvJTNEYmxvZyUyNmlk +JTNENTIyNDEiIA0KICB0YXJnZXQ9X2JsYW5rPueslOiusCDkuIDkupvlpKflhazlj7jnmoTlv4Pn +kIbmtYvor5Xpopg8L0E+PC9ERD4NCiAgPEREIGNsYXNzPSJzb3VyY2Vfc3R5IHR4dF9ibGFjayIg +DQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IFBBRERJTkctTEVGVDogMTJweDsgQkFDS0dS +T1VORC1JTUFHRTogbm9uZTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IENPTE9S +OiByZ2IoMCwwLDApOyBMSU5FLUhFSUdIVDogMTlweDsgUEFERElORy1UT1A6IDBweDsgYmFja2dy +b3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEVNIA0KICBz +dHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IEZPTlQtU1RZTEU6IG5vcm1hbCI+PC9FTT48L0REPg0K +ICA8REQgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046 +IDJweCA3cHg7IFBBRERJTkctTEVGVDogMTJweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6 +Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzUuZ2lmKTsgUEFERElORy1CT1RU +T006IDBweDsgTUFSR0lOOiAwcHg7IExJTkUtSEVJR0hUOiAxOXB4OyBQQURESU5HLVRPUDogMHB4 +OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48 +QSANCiAgdGl0bGU9IuivvuWggiDkuIvlrabmnJ/nmoTltYzlhaXlvI/pgInkv67or77pgInlkKbv +vJ8iIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAg +b25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsOTUpOyANCiAgaHJlZj0iaHR0cDovL3N0dWRlbnQu +Y3Nkbi5uZXQvbGluay5waHA/dXJsPWh0dHA6Ly9zdHVkZW50LmNzZG4ubmV0JTJGc3BhY2UucGhw +JTNGZG8lM0R0aHJlYWQlMjZpZCUzRDQxMDIyIiANCiAgdGFyZ2V0PV9ibGFuaz7or77loIIg5LiL +5a2m5pyf55qE5bWM5YWl5byP6YCJ5L+u6K++6YCJ5ZCmPC9BPjwvREQ+DQogIDxERCBjbGFzcz0i +c291cmNlX3N0eSB0eHRfYmxhY2siIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBQQURE +SU5HLUxFRlQ6IDEycHg7IEJBQ0tHUk9VTkQtSU1BR0U6IG5vbmU7IFBBRERJTkctQk9UVE9NOiAw +cHg7IE1BUkdJTjogMHB4OyBDT0xPUjogcmdiKDAsMCwwKTsgTElORS1IRUlHSFQ6IDE5cHg7IFBB +RERJTkctVE9QOiAwcHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNs +aXA6IGluaXRpYWwiPjxFTSANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBGT05ULVNUWUxF +OiBub3JtYWwiPjwvRU0+PC9ERD4NCiAgPEREIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4 +OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAycHggN3B4OyBQQURESU5HLUxFRlQ6IDEycHg7IEJBQ0tH +Uk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9w +aWM1LmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBMSU5FLUhFSUdIVDog +MTlweDsgUEFERElORy1UT1A6IDBweDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tn +cm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxlPSJKYXZh6K++5aCCIOaVsOaNruaMluaO +mCIgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBv +bmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw5NSk7IA0KICBocmVmPSJodHRwOi8vc3R1ZGVudC5j +c2RuLm5ldC9saW5rLnBocD91cmw9aHR0cDovL3N0dWRlbnQuY3Nkbi5uZXQlMkZzcGFjZS5waHAl +M0ZkbyUzRHRocmVhZCUyNmlkJTNENDEwMDAiIA0KICB0YXJnZXQ9X2JsYW5rPkphdmHor77loIIg +5pWw5o2u5oyW5o6YPC9BPjwvREQ+DQogIDxERCBjbGFzcz0ic291cmNlX3N0eSB0eHRfYmxhY2si +IA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBQQURESU5HLUxFRlQ6IDEycHg7IEJBQ0tH +Uk9VTkQtSU1BR0U6IG5vbmU7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBDT0xP +UjogcmdiKDAsMCwwKTsgTElORS1IRUlHSFQ6IDE5cHg7IFBBRERJTkctVE9QOiAwcHg7IGJhY2tn +cm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxFTSANCiAg +c3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBGT05ULVNUWUxFOiBub3JtYWwiPjwvRU0+PC9ERD48 +L0RMPjwvRElWPg0KPERJViBjbGFzcz1zaWRlYmFyX2NvbiANCnN0eWxlPSJESVNQTEFZOiBpbmxp +bmU7IEZMT0FUOiBsZWZ0OyBNQVJHSU46IDZweCAzcHggMnB4OyBXSURUSDogMjAycHgiPg0KPEg0 +IGNsYXNzPXR4dF8xMiANCnN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IFBBRERJTkctTEVGVDog +M3B4OyBGT05ULVNJWkU6IDEycHg7IFBBRERJTkctQk9UVE9NOiA1cHg7IE1BUkdJTjogMHB4OyBQ +QURESU5HLVRPUDogMHB4OyBCT1JERVItQk9UVE9NOiByZ2IoMjA0LDIwNCwyMDQpIDFweCBzb2xp +ZDsgUE9TSVRJT046IHJlbGF0aXZlIj48U1BBTiANCmNsYXNzPXR4dF9ncmF5IA0Kc3R5bGU9IkZP +TlQtV0VJR0hUOiBub3JtYWw7IEZMT0FUOiByaWdodDsgQ09MT1I6IHJnYigxMDIsMTAyLDEwMiki +PjwvU1BBTj7kuqflk4Hlkozlt6Xlhbc8L0g0Pg0KPERMIGNsYXNzPXNlc3Npb25fc3R5bGUgDQpz +dHlsZT0iUEFERElORy1SSUdIVDogM3B4OyBQQURESU5HLUxFRlQ6IDNweDsgRkxPQVQ6IGxlZnQ7 +IFBBRERJTkctQk9UVE9NOiA1cHg7IE1BUkdJTjogMnB4IDBweCAwcHg7IFdJRFRIOiAxOTZweDsg +UEFERElORy1UT1A6IDEwcHg7IEJPUkRFUi1CT1RUT006IHJnYigyMDQsMjA0LDIwNCkgMXB4IHNv +bGlkOyBCQUNLR1JPVU5ELUNPTE9SOiByZ2IoMjU1LDI1NSwyNTUpOyBiYWNrZ3JvdW5kLW9yaWdp +bjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj4NCiAgPEREIA0KICBzdHlsZT0i +UEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAycHggN3B4OyBQQURESU5H +LUxFRlQ6IDEycHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cv +aW1hZ2VzL2NzZG5pbmRleF9waWM1LmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjog +MHB4OyBMSU5FLUhFSUdIVDogMTlweDsgUEFERElORy1UT1A6IDBweDsgYmFja2dyb3VuZC1vcmln +aW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxlPTIwMTDl +tYzlhaXlvI/ooYzkuJrlubTnu4jnm5jngrnorrLluqcgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDAp +OyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw5 +NCk7IGhyZWY9Imh0dHA6Ly9nLmNzZG4ubmV0LzUxNjc0NzAiIA0KICB0YXJnZXQ9X2JsYW5rPjIw +MTDltYzlhaXlvI/ooYzkuJrlubTnu4jnm5jngrnorrLluqc8L0E+PC9ERD4NCiAgPEREIA0KICBz +dHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAycHggN3B4OyBQ +QURESU5HLUxFRlQ6IDEycHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5j +bi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWM1LmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1B +UkdJTjogMHB4OyBMSU5FLUhFSUdIVDogMTlweDsgUEFERElORy1UT1A6IDBweDsgYmFja2dyb3Vu +ZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxl +PeS4rei9r+mbhuWboue7meS4juS4reagh+i9r+S7tuWFqOmdouaUr+aMgSBzdHlsZT0iQ09MT1I6 +IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tD +b3VudCh0aGlzLDk0KTsgaHJlZj0iaHR0cDovL2cuY3Nkbi5uZXQvNTExMzMzNiIgDQogIHRhcmdl +dD1fYmxhbms+5Lit6L2v6ZuG5Zui57uZ5LiO5Lit5qCH6L2v5Lu25YWo6Z2i5pSv5oyBPC9BPjwv +REQ+DQogIDxERCANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJ +VElPTjogMnB4IDdweDsgUEFERElORy1MRUZUOiAxMnB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwo +aHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljNS5naWYpOyBQQURESU5H +LUJPVFRPTTogMHB4OyBNQVJHSU46IDBweDsgTElORS1IRUlHSFQ6IDE5cHg7IFBBRERJTkctVE9Q +OiAwcHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRp +YWwiPjxBIA0KICB0aXRsZT3pmo/ml7bpmo/lnLDlraboi7Hor63vvJ/oi7HlrZrmiYvmnLrlupTn +lKjmnaXluK7kvaAhIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBu +b25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsOTQpOyBocmVmPSJodHRwOi8vZy5j +c2RuLm5ldC81MTY2NTQ1IiANCiAgdGFyZ2V0PV9ibGFuaz7pmo/ml7bpmo/lnLDlraboi7Hor63v +vJ/oi7HlrZrmiYvmnLrlupTnlKjmnaXluK7kvaAhPC9BPjwvREQ+DQogIDxERCANCiAgc3R5bGU9 +IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMnB4IDdweDsgUEFERElO +Ry1MRUZUOiAxMnB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3 +L2ltYWdlcy9jc2RuaW5kZXhfcGljNS5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46 +IDBweDsgTElORS1IRUlHSFQ6IDE5cHg7IFBBRERJTkctVE9QOiAwcHg7IGJhY2tncm91bmQtb3Jp +Z2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0aXRsZT1JVOi+ +vuS6uu+8muaVmeS9oOeOqei9rOWlveWOi+WOi+e8qei9r+S7tiBzdHlsZT0iQ09MT1I6IHJnYigw +LDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0 +aGlzLDk0KTsgaHJlZj0iaHR0cDovL2cuY3Nkbi5uZXQvNTE1NzMzMyIgDQogIHRhcmdldD1fYmxh +bms+SVTovr7kurrvvJrmlZnkvaDnjqnovazlpb3ljovljovnvKnova/ku7Y8L0E+PC9ERD4NCiAg +PEREIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAy +cHggN3B4OyBQQURESU5HLUxFRlQ6IDEycHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8v +Y3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWM1LmdpZik7IFBBRERJTkctQk9UVE9N +OiAwcHg7IE1BUkdJTjogMHB4OyBMSU5FLUhFSUdIVDogMTlweDsgUEFERElORy1UT1A6IDBweDsg +YmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEg +DQogIHRpdGxlPeS6uuWkp+mHkeS7k+WKqeWKm+WNq+eUn+ihjOS4muS/oeaBr+WMliBzdHlsZT0i +Q09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9n +Q2xpY2tDb3VudCh0aGlzLDk0KTsgaHJlZj0iaHR0cDovL2cuY3Nkbi5uZXQvNTEwNjAwOCIgDQog +IHRhcmdldD1fYmxhbms+5Lq65aSn6YeR5LuT5Yqp5Yqb5Y2r55Sf6KGM5Lia5L+h5oGv5YyWPC9B +PjwvREQ+PC9ETD48L0RJVj4NCjxESVYgY2xhc3M9c2lkZWJhcl9jb24gDQpzdHlsZT0iRElTUExB +WTogaW5saW5lOyBGTE9BVDogbGVmdDsgTUFSR0lOOiA2cHggM3B4IDJweDsgV0lEVEg6IDIwMnB4 +Ij4NCjxINCBjbGFzcz10eHRfMTIgDQpzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBQQURESU5H +LUxFRlQ6IDNweDsgRk9OVC1TSVpFOiAxMnB4OyBQQURESU5HLUJPVFRPTTogNXB4OyBNQVJHSU46 +IDBweDsgUEFERElORy1UT1A6IDBweDsgQk9SREVSLUJPVFRPTTogcmdiKDIwNCwyMDQsMjA0KSAx +cHggc29saWQ7IFBPU0lUSU9OOiByZWxhdGl2ZSI+PFNQQU4gDQpjbGFzcz10eHRfZ3JheSANCnN0 +eWxlPSJGT05ULVdFSUdIVDogbm9ybWFsOyBGTE9BVDogcmlnaHQ7IENPTE9SOiByZ2IoMTAyLDEw +MiwxMDIpIj58PEEgDQpzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBQQURESU5HLUxFRlQ6IDVw +eDsgUEFERElORy1CT1RUT006IDBweDsgQ09MT1I6IHJnYigxMDIsMTAyLDEwMik7IFBBRERJTkct +VE9QOiAwcHg7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQpocmVmPSJodHRwOi8vcHJqLmNzZG4u +bmV0LyIgdGFyZ2V0PV9ibGFuaz7mm7TlpJo8L0E+PC9TUEFOPumhueebrueyvumAiTwvSDQ+DQo8 +REwgY2xhc3M9c2Vzc2lvbl9zdHlsZSANCnN0eWxlPSJQQURESU5HLVJJR0hUOiAzcHg7IFBBRERJ +TkctTEVGVDogM3B4OyBGTE9BVDogbGVmdDsgUEFERElORy1CT1RUT006IDVweDsgTUFSR0lOOiAy +cHggMHB4IDBweDsgV0lEVEg6IDE5NnB4OyBQQURESU5HLVRPUDogMTBweDsgQk9SREVSLUJPVFRP +TTogcmdiKDIwNCwyMDQsMjA0KSAxcHggc29saWQ7IEJBQ0tHUk9VTkQtQ09MT1I6IHJnYigyNTUs +MjU1LDI1NSk7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGlu +aXRpYWwiPg0KICA8REQgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQt +UE9TSVRJT046IDJweCA3cHg7IFBBRERJTkctTEVGVDogMTJweDsgQkFDS0dST1VORC1JTUFHRTog +dXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzUuZ2lmKTsgUEFE +RElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IExJTkUtSEVJR0hUOiAxOXB4OyBQQURESU5H +LVRPUDogMHB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBp +bml0aWFsIj48L0REPg0KICA8REQgY2xhc3M9amlhbiANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6 +IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMHB4IDNweDsgUEFERElORy1MRUZUOiAyMXB4OyBC +QUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5k +ZXhfcGljdGV4dDAyLmdpZik7IFBBRERJTkctQk9UVE9NOiAzcHg7IE1BUkdJTjogMHB4OyBMSU5F +LUhFSUdIVDogMTlweDsgUEFERElORy1UT1A6IDNweDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRp +YWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxlPSLmnLrlmajop4bop4kt +6aKc6Imy5YiG57G7ICIgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046 +IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw5Nik7IA0KICBocmVmPSJodHRw +Oi8vcHJqLmNzZG4ubmV0L3Byb2pkZXRhaWwuYXNweD9wb2ludGlkPTI0OTI3IiANCiAgdGFyZ2V0 +PV9ibGFuaz7mnLrlmajop4bop4kt6aKc6Imy5YiG57G7PC9BPjwvREQ+DQogIDxERCBjbGFzcz1s +aWFuIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAw +cHggM3B4OyBQQURESU5HLUxFRlQ6IDIxcHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8v +Y3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWN0ZXh0MDEuZ2lmKTsgUEFERElORy1C +T1RUT006IDNweDsgTUFSR0lOOiAwcHg7IExJTkUtSEVJR0hUOiAxOXB4OyBQQURESU5HLVRPUDog +M3B4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFs +Ij48QSANCiAgdGl0bGU9Ik1USyBGTEFTSOaSreaUvuW8leaTjuW8gOWPkSIgc3R5bGU9IkNPTE9S +OiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNr +Q291bnQodGhpcyw5Nik7IA0KICBocmVmPSJodHRwOi8vcHJqLmNzZG4ubmV0L3Byb2pkZXRhaWwu +YXNweD9wb2ludGlkPTI0Nzg4IiB0YXJnZXQ9X2JsYW5rPk1USyANCiAgRkxBU0jmkq3mlL7lvJXm +k47lvIDlj5E8L0E+PC9ERD4NCiAgPEREIGNsYXNzPWxpYW4gDQogIHN0eWxlPSJQQURESU5HLVJJ +R0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDBweCAzcHg7IFBBRERJTkctTEVGVDogMjFw +eDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3Nk +bmluZGV4X3BpY3RleHQwMS5naWYpOyBQQURESU5HLUJPVFRPTTogM3B4OyBNQVJHSU46IDBweDsg +TElORS1IRUlHSFQ6IDE5cHg7IFBBRERJTkctVE9QOiAzcHg7IGJhY2tncm91bmQtb3JpZ2luOiBp +bml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0aXRsZT0iUERG6Jma5ouf +5omT5Y2w5py677yI6ZmQ5YyX5Lqs77yJICIgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhU +LURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw5Nik7IA0K +ICBocmVmPSJodHRwOi8vcHJqLmNzZG4ubmV0L3Byb2pkZXRhaWwuYXNweD9wb2ludGlkPTI0NDA2 +IiANCiAgdGFyZ2V0PV9ibGFuaz5QREbomZrmi5/miZPljbDmnLrvvIjpmZDljJfkuqzvvIk8L0E+ +PC9ERD4NCiAgPEREIGNsYXNzPWxpYW4gDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJB +Q0tHUk9VTkQtUE9TSVRJT046IDBweCAzcHg7IFBBRERJTkctTEVGVDogMjFweDsgQkFDS0dST1VO +RC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpY3Rl +eHQwMS5naWYpOyBQQURESU5HLUJPVFRPTTogM3B4OyBNQVJHSU46IDBweDsgTElORS1IRUlHSFQ6 +IDE5cHg7IFBBRERJTkctVE9QOiAzcHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNr +Z3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0aXRsZT0i5b2p56Wo572R56uZ56iL5bqP5YWo +5aWXICIgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0K +ICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw5Nik7IA0KICBocmVmPSJodHRwOi8vcHJqLmNz +ZG4ubmV0L3Byb2pkZXRhaWwuYXNweD9wb2ludGlkPTI0OTM0IiANCiAgdGFyZ2V0PV9ibGFuaz7l +vannpajnvZHnq5nnqIvluo/lhajlpZc8L0E+PC9ERD4NCiAgPEREIGNsYXNzPWppYW4gDQogIHN0 +eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDBweCAzcHg7IFBB +RERJTkctTEVGVDogMjFweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNu +L3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpY3RleHQwMi5naWYpOyBQQURESU5HLUJPVFRPTTogM3B4 +OyBNQVJHSU46IDBweDsgTElORS1IRUlHSFQ6IDE5cHg7IFBBRERJTkctVE9QOiAzcHg7IGJhY2tn +cm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0 +aXRsZT0iU1RNMzJGMTAz6L2v5Lu25byA5Y+RICIgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBU +RVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw5Nik7 +IA0KICBocmVmPSJodHRwOi8vcHJqLmNzZG4ubmV0L3Byb2pkZXRhaWwuYXNweD9wb2ludGlkPTI0 +NzYzIiANCiAgdGFyZ2V0PV9ibGFuaz5TVE0zMkYxMDPova/ku7blvIDlj5E8L0E+PC9ERD4NCiAg +PEREIGNsYXNzPWppYW4gDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQt +UE9TSVRJT046IDBweCAzcHg7IFBBRERJTkctTEVGVDogMjFweDsgQkFDS0dST1VORC1JTUFHRTog +dXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpY3RleHQwMi5naWYp +OyBQQURESU5HLUJPVFRPTTogM3B4OyBNQVJHSU46IDBweDsgTElORS1IRUlHSFQ6IDE5cHg7IFBB +RERJTkctVE9QOiAzcHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNs +aXA6IGluaXRpYWwiPjxBIA0KICB0aXRsZT0iYW5kcm9pZOWuouaIt+err+W8gOWPkSAiIHN0eWxl +PSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1M +b2dDbGlja0NvdW50KHRoaXMsOTYpOyANCiAgaHJlZj0iaHR0cDovL3Byai5jc2RuLm5ldC9wcm9q +ZGV0YWlsLmFzcHg/cG9pbnRpZD0yNDgxNCIgDQogIHRhcmdldD1fYmxhbms+YW5kcm9pZOWuouaI +t+err+W8gOWPkTwvQT48L0REPg0KICA8REQgY2xhc3M9amlhbiANCiAgc3R5bGU9IlBBRERJTkct +UklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMHB4IDNweDsgUEFERElORy1MRUZUOiAy +MXB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9j +c2RuaW5kZXhfcGljdGV4dDAyLmdpZik7IFBBRERJTkctQk9UVE9NOiAzcHg7IE1BUkdJTjogMHB4 +OyBMSU5FLUhFSUdIVDogMTlweDsgUEFERElORy1UT1A6IDNweDsgYmFja2dyb3VuZC1vcmlnaW46 +IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxlPSLpn7Pop4bp +opHlub/mkq3mjqfku7YgIiBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElP +Tjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDk2KTsgDQogIGhyZWY9Imh0 +dHA6Ly9wcmouY3Nkbi5uZXQvcHJvamRldGFpbC5hc3B4P3BvaW50aWQ9MjUwMzgiIA0KICB0YXJn +ZXQ9X2JsYW5rPumfs+inhumikeW5v+aSreaOp+S7tjwvQT48L0REPg0KICA8REQgY2xhc3M9bGlh +biANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMHB4 +IDNweDsgUEFERElORy1MRUZUOiAyMXB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2Nz +ZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljdGV4dDAxLmdpZik7IFBBRERJTkctQk9U +VE9NOiAzcHg7IE1BUkdJTjogMHB4OyBMSU5FLUhFSUdIVDogMTlweDsgUEFERElORy1UT1A6IDNw +eDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+ +PEEgDQogIHRpdGxlPSJJTei9r+S7tumhueebruWkluWMheW8gOWPkSAiIHN0eWxlPSJDT0xPUjog +cmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0Nv +dW50KHRoaXMsOTYpOyANCiAgaHJlZj0iaHR0cDovL3Byai5jc2RuLm5ldC9wcm9qZGV0YWlsLmFz +cHg/cG9pbnRpZD0yNTEzNSIgDQogIHRhcmdldD1fYmxhbms+SU3ova/ku7bpobnnm67lpJbljIXl +vIDlj5E8L0E+PC9ERD48L0RMPjwvRElWPg0KPERJViBjbGFzcz1zaWRlYmFyX2NvbiANCnN0eWxl +PSJESVNQTEFZOiBpbmxpbmU7IEZMT0FUOiBsZWZ0OyBNQVJHSU46IDZweCAzcHggMnB4OyBXSURU +SDogMjAycHgiPg0KPEg0IGNsYXNzPXR4dF8xMiANCnN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7 +IFBBRERJTkctTEVGVDogM3B4OyBGT05ULVNJWkU6IDEycHg7IFBBRERJTkctQk9UVE9NOiA1cHg7 +IE1BUkdJTjogMHB4OyBQQURESU5HLVRPUDogMHB4OyBCT1JERVItQk9UVE9NOiByZ2IoMjA0LDIw +NCwyMDQpIDFweCBzb2xpZDsgUE9TSVRJT046IHJlbGF0aXZlIj48U1BBTiANCmNsYXNzPXR4dF9n +cmF5IA0Kc3R5bGU9IkZPTlQtV0VJR0hUOiBub3JtYWw7IEZMT0FUOiByaWdodDsgQ09MT1I6IHJn +YigxMDIsMTAyLDEwMikiPnw8QSANCnN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IFBBRERJTkct +TEVGVDogNXB4OyBQQURESU5HLUJPVFRPTTogMHB4OyBDT0xPUjogcmdiKDEwMiwxMDIsMTAyKTsg +UEFERElORy1UT1A6IDBweDsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCmhyZWY9Imh0dHA6Ly9k +b3dubG9hZC5jc2RuLm5ldC8iIHRhcmdldD1fYmxhbms+5pu05aSaPC9BPjwvU1BBTj7otYTmupDn +sr7pgIk8L0g0Pg0KPERMIGNsYXNzPXNlc3Npb25fc3R5bGUgDQpzdHlsZT0iUEFERElORy1SSUdI +VDogM3B4OyBQQURESU5HLUxFRlQ6IDNweDsgRkxPQVQ6IGxlZnQ7IFBBRERJTkctQk9UVE9NOiA1 +cHg7IE1BUkdJTjogMnB4IDBweCAwcHg7IFdJRFRIOiAxOTZweDsgUEFERElORy1UT1A6IDEwcHg7 +IEJPUkRFUi1CT1RUT006IHJnYigyMDQsMjA0LDIwNCkgMXB4IHNvbGlkOyBCQUNLR1JPVU5ELUNP +TE9SOiByZ2IoMjU1LDI1NSwyNTUpOyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dy +b3VuZC1jbGlwOiBpbml0aWFsIj4NCiAgPEREIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4 +OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAycHggN3B4OyBQQURESU5HLUxFRlQ6IDEycHg7IEJBQ0tH +Uk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9w +aWM1LmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBMSU5FLUhFSUdIVDog +MTlweDsgUEFERElORy1UT1A6IDBweDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tn +cm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxlPUPor63oqIDmlbDmja7nu5PmnoTln7rm +nKzmk43kvZwgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUi +IA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcywxMDMpOyANCiAgaHJlZj0iaHR0cDovL2Rv +d25sb2FkLmNzZG4ubmV0L3NvdXJjZS8yOTA3ODEzIiANCiAgdGFyZ2V0PV9ibGFuaz5D6K+t6KiA +5pWw5o2u57uT5p6E5Z+65pys5pON5L2cPC9BPjwvREQ+DQogIDxERCBjbGFzcz0ic291cmNlX3N0 +eSB0eHRfYmxhY2siIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBQQURESU5HLUxFRlQ6 +IDEycHg7IEJBQ0tHUk9VTkQtSU1BR0U6IG5vbmU7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJ +TjogMHB4OyBDT0xPUjogcmdiKDAsMCwwKTsgTElORS1IRUlHSFQ6IDE5cHg7IFBBRERJTkctVE9Q +OiAwcHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRp +YWwiPjxFTSANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBGT05ULVNUWUxFOiBub3JtYWwi +PnJ1YnkxMzE05LiK5LygPC9FTT48QSANCiAgc3R5bGU9Ik1BUkdJTjogMHB4IDBweCAwcHggMTVw +eDsgQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9 +TG9nQ2xpY2tDb3VudCh0aGlzLDEwMyk7IA0KaHJlZj0iaHR0cDovL2Rvd25sb2FkLmNzZG4ubmV0 +LyI+5oiR6KaB5LiK5LygPC9BPjwvREQ+DQogIDxERCANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6 +IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMnB4IDdweDsgUEFERElORy1MRUZUOiAxMnB4OyBC +QUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5k +ZXhfcGljNS5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweDsgTElORS1IRUlH +SFQ6IDE5cHg7IFBBRERJTkctVE9QOiAwcHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBi +YWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0aXRsZT0i5a2m55Sf5L2c5Lia566h55CG +57O757ufIEpTUCIgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5v +bmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcywxMDMpOyANCiAgaHJlZj0iaHR0cDov +L2Rvd25sb2FkLmNzZG4ubmV0L3NvdXJjZS8yOTA3NzcyIiB0YXJnZXQ9X2JsYW5rPuWtpueUn+S9 +nOS4mueuoeeQhuezu+e7nyANCiAgSlNQPC9BPjwvREQ+DQogIDxERCBjbGFzcz0ic291cmNlX3N0 +eSB0eHRfYmxhY2siIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBQQURESU5HLUxFRlQ6 +IDEycHg7IEJBQ0tHUk9VTkQtSU1BR0U6IG5vbmU7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJ +TjogMHB4OyBDT0xPUjogcmdiKDAsMCwwKTsgTElORS1IRUlHSFQ6IDE5cHg7IFBBRERJTkctVE9Q +OiAwcHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRp +YWwiPjxFTSANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBGT05ULVNUWUxFOiBub3JtYWwi +PmZlbmd5YWxpbmdmbHl5eeS4iuS8oDwvRU0+PEEgDQogIHN0eWxlPSJNQVJHSU46IDBweCAwcHgg +MHB4IDE1cHg7IENPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBv +bmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcywxMDMpOyANCmhyZWY9Imh0dHA6Ly9kb3dubG9hZC5j +c2RuLm5ldC8iPuaIkeimgeS4iuS8oDwvQT48L0REPg0KICA8REQgDQogIHN0eWxlPSJQQURESU5H +LVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDJweCA3cHg7IFBBRERJTkctTEVGVDog +MTJweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMv +Y3NkbmluZGV4X3BpYzUuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IExJ +TkUtSEVJR0hUOiAxOXB4OyBQQURESU5HLVRPUDogMHB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5p +dGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgdGl0bGU9Yysr57yW56iL5bi4 +6YGH6Zeu6aKY5oC757uTIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9O +OiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsMTAzKTsgDQogIGhyZWY9Imh0 +dHA6Ly9kb3dubG9hZC5jc2RuLm5ldC9zb3VyY2UvMjkwNzU5NiIgDQogIHRhcmdldD1fYmxhbms+ +Yysr57yW56iL5bi46YGH6Zeu6aKY5oC757uTPC9BPjwvREQ+DQogIDxERCBjbGFzcz0ic291cmNl +X3N0eSB0eHRfYmxhY2siIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBQQURESU5HLUxF +RlQ6IDEycHg7IEJBQ0tHUk9VTkQtSU1BR0U6IG5vbmU7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1B +UkdJTjogMHB4OyBDT0xPUjogcmdiKDAsMCwwKTsgTElORS1IRUlHSFQ6IDE5cHg7IFBBRERJTkct +VE9QOiAwcHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGlu +aXRpYWwiPjxFTSANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBGT05ULVNUWUxFOiBub3Jt +YWwiPmJ5cmdsNeS4iuS8oDwvRU0+PEEgDQogIHN0eWxlPSJNQVJHSU46IDBweCAwcHggMHB4IDE1 +cHg7IENPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNr +PUxvZ0NsaWNrQ291bnQodGhpcywxMDMpOyANCmhyZWY9Imh0dHA6Ly9kb3dubG9hZC5jc2RuLm5l +dC8iPuaIkeimgeS4iuS8oDwvQT48L0REPg0KICA8REQgDQogIHN0eWxlPSJQQURESU5HLVJJR0hU +OiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDJweCA3cHg7IFBBRERJTkctTEVGVDogMTJweDsg +QkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3Nkbmlu +ZGV4X3BpYzUuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IExJTkUtSEVJ +R0hUOiAxOXB4OyBQQURESU5HLVRPUDogMHB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsg +YmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgdGl0bGU9IkMjIOWvvOWHumV4Y2VsIOWu +nuS+i+S7o+eggSIgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5v +bmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcywxMDMpOyANCiAgaHJlZj0iaHR0cDov +L2Rvd25sb2FkLmNzZG4ubmV0L3NvdXJjZS8yOTA3NDkwIiB0YXJnZXQ9X2JsYW5rPkMjIOWvvOWH +umV4Y2VsIA0KICDlrp7kvovku6PnoIE8L0E+PC9ERD4NCiAgPEREIGNsYXNzPSJzb3VyY2Vfc3R5 +IHR4dF9ibGFjayIgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IFBBRERJTkctTEVGVDog +MTJweDsgQkFDS0dST1VORC1JTUFHRTogbm9uZTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lO +OiAwcHg7IENPTE9SOiByZ2IoMCwwLDApOyBMSU5FLUhFSUdIVDogMTlweDsgUEFERElORy1UT1A6 +IDBweDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlh +bCI+PEVNIA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IEZPTlQtU1RZTEU6IG5vcm1hbCI+ +b3VfeWFuZ3BlbmdmZWnkuIrkvKA8L0VNPjxBIA0KICBzdHlsZT0iTUFSR0lOOiAwcHggMHB4IDBw +eCAxNXB4OyBDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25j +bGljaz1Mb2dDbGlja0NvdW50KHRoaXMsMTAzKTsgDQpocmVmPSJodHRwOi8vZG93bmxvYWQuY3Nk +bi5uZXQvIj7miJHopoHkuIrkvKA8L0E+PC9ERD4NCiAgPEREIA0KICBzdHlsZT0iUEFERElORy1S +SUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAycHggN3B4OyBQQURESU5HLUxFRlQ6IDEy +cHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2Nz +ZG5pbmRleF9waWM1LmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBMSU5F +LUhFSUdIVDogMTlweDsgUEFERElORy1UT1A6IDBweDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRp +YWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxlPXZi6Ieq5Yqo5o6S54mI +55Sf5oiQV29yZCBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9u +ZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDEwMyk7IA0KICBocmVmPSJodHRwOi8v +ZG93bmxvYWQuY3Nkbi5uZXQvc291cmNlLzI5MDcwMTEiIA0KICB0YXJnZXQ9X2JsYW5rPnZi6Ieq +5Yqo5o6S54mI55Sf5oiQV29yZDwvQT48L0REPg0KICA8REQgY2xhc3M9InNvdXJjZV9zdHkgdHh0 +X2JsYWNrIiANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgUEFERElORy1MRUZUOiAxMnB4 +OyBCQUNLR1JPVU5ELUlNQUdFOiBub25lOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBw +eDsgQ09MT1I6IHJnYigwLDAsMCk7IExJTkUtSEVJR0hUOiAxOXB4OyBQQURESU5HLVRPUDogMHB4 +OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48 +RU0gDQogIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgRk9OVC1TVFlMRTogbm9ybWFsIj50aTEy +NuS4iuS8oDwvRU0+PEEgDQogIHN0eWxlPSJNQVJHSU46IDBweCAwcHggMHB4IDE1cHg7IENPTE9S +OiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNr +Q291bnQodGhpcywxMDMpOyANCmhyZWY9Imh0dHA6Ly9kb3dubG9hZC5jc2RuLm5ldC8iPuaIkeim +geS4iuS8oDwvQT48L0REPjwvREw+PC9ESVY+PC9ESVY+DQo8RElWIGNsYXNzPXBhZ2VibG9jazJf +d3JhcCBzdHlsZT0iRkxPQVQ6IGxlZnQ7IFdJRFRIOiA3MzVweCI+DQo8RElWIGNsYXNzPXBhZ2Vj +b25fbGF5ZXIyX2xlZnQgDQpzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBESVNQTEFZOiBpbmxp +bmU7IFBBRERJTkctTEVGVDogMHB4OyBGTE9BVDogbGVmdDsgUEFERElORy1CT1RUT006IDVweDsg +TUFSR0lOOiAwcHggMHB4IDBweCAxcHg7IFdJRFRIOiA0NzBweDsgUEFERElORy1UT1A6IDBweCI+ +DQo8SDYgDQpzdHlsZT0iQ0xFQVI6IGJvdGg7IFBBRERJTkctUklHSFQ6IDBweDsgQk9SREVSLVRP +UDogcmdiKDIwNCwyMDQsMjA0KSAxcHggc29saWQ7IFBBRERJTkctTEVGVDogMTBweDsgRk9OVC1T +SVpFOiAxNHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2lt +YWdlcy9jc2RuaW5kZXhfcGljMTEuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAw +cHg7IFBBRERJTkctVE9QOiA1cHg7IFBPU0lUSU9OOiByZWxhdGl2ZTsgSEVJR0hUOiAyOXB4OyBi +YWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj7ljZrl +rqLnsr7pgIk8U1BBTiANCmNsYXNzPXR4dF9ibGFjayANCnN0eWxlPSJGT05ULVdFSUdIVDogbm9y +bWFsOyBGT05ULVNJWkU6IDEycHg7IE1BUkdJTjogMHB4IDBweCAwcHggMTVweDsgQ09MT1I6IHJn +YigwLDAsMCkiPjxTUEFOIA0KY2xhc3M9QXBwbGUtY29udmVydGVkLXNwYWNlPiZuYnNwOzwvU1BB +Tj48QSB0aXRsZT3jgJDmjqjojZDjgJHlpKnnv7zmlZnkvaDnp7vliqjlupTnlKjokKXliKnkuYvp +gZMgDQpzdHlsZT0iUEFERElORy1SSUdIVDogM3B4OyBQQURESU5HLUxFRlQ6IDNweDsgUEFERElO +Ry1CT1RUT006IDBweDsgQ09MT1I6IHJnYigwLDAsMCk7IFBBRERJTkctVE9QOiAwcHg7IFRFWFQt +REVDT1JBVElPTjogbm9uZSIgDQpocmVmPSJodHRwOi8vZy5jc2RuLm5ldC81MTY1Njk2IiB0YXJn +ZXQ9X2JsYW5rPuOAkOaOqOiNkOOAkeWkqee/vOaVmeS9oOenu+WKqOW6lOeUqOiQpeWIqeS5i+mB +kzwvQT48L1NQQU4+PEVNIA0KY2xhc3M9dHh0X2JsdWUgDQpzdHlsZT0iUEFERElORy1SSUdIVDog +MHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAwcHggNHB4OyBQQURESU5HLUxFRlQ6IDEwcHg7IEZP +TlQtV0VJR0hUOiBub3JtYWw7IEZPTlQtU0laRTogMTJweDsgTEVGVDogNDEwcHg7IEJBQ0tHUk9V +TkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMx +Mi5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBDT0xPUjogcmdiKDEsOTUsMTgyKTsgUEFERElO +Ry1UT1A6IDBweDsgRk9OVC1TVFlMRTogbm9ybWFsOyBQT1NJVElPTjogYWJzb2x1dGU7IFRPUDog +NnB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFs +Ij48QSANCnN0eWxlPSJQQURESU5HLVJJR0hUOiAzcHg7IFBBRERJTkctTEVGVDogM3B4OyBQQURE +SU5HLUJPVFRPTTogMHB4OyBDT0xPUjogcmdiKDEsOTUsMTgyKTsgUEFERElORy1UT1A6IDBweDsg +VEVYVC1ERUNPUkFUSU9OOiB1bmRlcmxpbmUiIA0KaHJlZj0iaHR0cDovL2Jsb2cuY3Nkbi5uZXQv +IiB0YXJnZXQ9X2JsYW5rPuabtOWkmjwvQT48L0VNPjwvSDY+DQo8RElWIGNsYXNzPXBhZ2Vjb25f +bGF5ZXIyX2xlZnRjb24gDQpzdHlsZT0iUEFERElORy1SSUdIVDogMTBweDsgUEFERElORy1MRUZU +OiAxMHB4OyBGTE9BVDogbGVmdDsgUEFERElORy1CT1RUT006IDVweDsgV0lEVEg6IDQ1MHB4OyBQ +QURESU5HLVRPUDogNXB4Ij4NCjxETCANCnN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IFBBRERJ +TkctTEVGVDogMHB4OyBQQURESU5HLUJPVFRPTTogMnB4OyBNQVJHSU46IDNweCAwcHg7IExJTkUt +SEVJR0hUOiAyMXB4OyBQQURESU5HLVRPUDogMHB4OyBQT1NJVElPTjogcmVsYXRpdmUiPg0KICA8 +RFQgY2xhc3M9dHh0X2JsYWNrIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JP +VU5ELVBPU0lUSU9OOiAwcHggOHB4OyBQQURESU5HLUxFRlQ6IDEwcHg7IEZPTlQtU0laRTogMTRw +eDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3Nk +bmluZGV4X3BpYzI2LmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogM3B4IDBweDsg +Q09MT1I6IHJnYigwLDAsMCk7IFBBRERJTkctVE9QOiAwcHg7IFBPU0lUSU9OOiByZWxhdGl2ZTsg +YmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PENJ +VEUgDQogIGNsYXNzPSJ0eHRfYmx1ZSB0eHRfMTIiIA0KICBzdHlsZT0iRk9OVC1TSVpFOiAxMnB4 +OyBGTE9BVDogcmlnaHQ7IENPTE9SOiByZ2IoMSw5NSwxODIpOyBGT05ULVNUWUxFOiBub3JtYWwi +PjxBIA0KICBzdHlsZT0iQ09MT1I6IHJnYigxLDk1LDE4Mik7IFRFWFQtREVDT1JBVElPTjogdW5k +ZXJsaW5lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsNzkpOyBocmVmPSJodHRwOi8v +YmxvZy5jc2RuLm5ldC9zb3NvX2Jsb2ciIA0KICB0YXJnZXQ9X2JsYW5rPnNvc29fYmxvZzwvQT48 +L0NJVEU+PEEgdGl0bGU95Yir6K6p5aaI5aaI55Sf5rCU4oCU4oCU5rWF6LCI6ZW/6ICF55So5oi3 +IA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQog +IG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDc5KTsgDQogIGhyZWY9Imh0dHA6Ly9ibG9nLmNz +ZG4ubmV0L3Nvc29fYmxvZy9hcmNoaXZlLzIwMTAvMTIvMTQvNjA3NTA0NC5hc3B4IiANCiAgdGFy +Z2V0PV9ibGFuaz7liKvorqnlpojlpojnlJ/msJTigJTigJTmtYXosIjplb/ogIXnlKjmiLc8L0E+ +PC9EVD4NCiAgPERUIGNsYXNzPXR4dF9ibGFjayANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBw +eDsgQkFDS0dST1VORC1QT1NJVElPTjogMHB4IDhweDsgUEFERElORy1MRUZUOiAxMHB4OyBGT05U +LVNJWkU6IDE0cHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cv +aW1hZ2VzL2NzZG5pbmRleF9waWMyNi5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46 +IDNweCAwcHg7IENPTE9SOiByZ2IoMCwwLDApOyBQQURESU5HLVRPUDogMHB4OyBQT1NJVElPTjog +cmVsYXRpdmU7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGlu +aXRpYWwiPjxDSVRFIA0KICBjbGFzcz0idHh0X2JsdWUgdHh0XzEyIiANCiAgc3R5bGU9IkZPTlQt +U0laRTogMTJweDsgRkxPQVQ6IHJpZ2h0OyBDT0xPUjogcmdiKDEsOTUsMTgyKTsgRk9OVC1TVFlM +RTogbm9ybWFsIj48QSANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMSw5NSwxODIpOyBURVhULURFQ09S +QVRJT046IHVuZGVybGluZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDc5KTsgaHJl +Zj0iaHR0cDovL2Jsb2cuY3Nkbi5uZXQvTG9hZGVuIiANCiAgdGFyZ2V0PV9ibGFuaz7ogIHpgpM8 +L0E+PC9DSVRFPjxBIHRpdGxlPeS5seivhEdVSeW8gOWPkeahhuaetuacquadpei1sOWQkSANCiAg +c3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNs +aWNrPUxvZ0NsaWNrQ291bnQodGhpcyw3OSk7IA0KICBocmVmPSJodHRwOi8vYmxvZy5jc2RuLm5l +dC9Mb2FkZW4vYXJjaGl2ZS8yMDEwLzEyLzExLzYwNjk4NDIuYXNweCIgDQogIHRhcmdldD1fYmxh +bms+5Lmx6K+ER1VJ5byA5Y+R5qGG5p625pyq5p2l6LWw5ZCRPC9BPjwvRFQ+DQogIDxEVCBjbGFz +cz10eHRfYmxhY2sgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9T +SVRJT046IDBweCA4cHg7IFBBRERJTkctTEVGVDogMTBweDsgRk9OVC1TSVpFOiAxNHB4OyBCQUNL +R1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhf +cGljMjYuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAzcHggMHB4OyBDT0xPUjog +cmdiKDAsMCwwKTsgUEFERElORy1UT1A6IDBweDsgUE9TSVRJT046IHJlbGF0aXZlOyBiYWNrZ3Jv +dW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48Q0lURSANCiAg +Y2xhc3M9InR4dF9ibHVlIHR4dF8xMiIgDQogIHN0eWxlPSJGT05ULVNJWkU6IDEycHg7IEZMT0FU +OiByaWdodDsgQ09MT1I6IHJnYigxLDk1LDE4Mik7IEZPTlQtU1RZTEU6IG5vcm1hbCI+PEEgDQog +IHN0eWxlPSJDT0xPUjogcmdiKDEsOTUsMTgyKTsgVEVYVC1ERUNPUkFUSU9OOiB1bmRlcmxpbmUi +IA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw3OSk7IGhyZWY9Imh0dHA6Ly9ibG9nLmNz +ZG4ubmV0L2NoZ2Fvd2VpIiANCiAgdGFyZ2V0PV9ibGFuaz7luLjpq5jkvJ88L0E+PC9DSVRFPjxB +IHRpdGxlPeWBmklU5oOz5LiN5Yqg54+t55yf55qE5b6I6Zq+IA0KICBzdHlsZT0iQ09MT1I6IHJn +YigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3Vu +dCh0aGlzLDc5KTsgDQogIGhyZWY9Imh0dHA6Ly9ibG9nLmNzZG4ubmV0L2NoZ2Fvd2VpL2FyY2hp +dmUvMjAxMC8xMi8wOC82MDY0MjAwLmFzcHgiIA0KICB0YXJnZXQ9X2JsYW5rPuWBmklU5oOz5LiN +5Yqg54+t55yf55qE5b6I6Zq+PC9BPjwvRFQ+DQogIDxEVCBjbGFzcz10eHRfYmxhY2sgDQogIHN0 +eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDBweCA4cHg7IFBB +RERJTkctTEVGVDogMTBweDsgRk9OVC1TSVpFOiAxNHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwo +aHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMjYuZ2lmKTsgUEFERElO +Ry1CT1RUT006IDBweDsgTUFSR0lOOiAzcHggMHB4OyBDT0xPUjogcmdiKDAsMCwwKTsgUEFERElO +Ry1UT1A6IDBweDsgUE9TSVRJT046IHJlbGF0aXZlOyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlh +bDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48Q0lURSANCiAgY2xhc3M9InR4dF9ibHVlIHR4 +dF8xMiIgDQogIHN0eWxlPSJGT05ULVNJWkU6IDEycHg7IEZMT0FUOiByaWdodDsgQ09MT1I6IHJn +YigxLDk1LDE4Mik7IEZPTlQtU1RZTEU6IG5vcm1hbCI+PEEgDQogIHN0eWxlPSJDT0xPUjogcmdi +KDEsOTUsMTgyKTsgVEVYVC1ERUNPUkFUSU9OOiB1bmRlcmxpbmUiIA0KICBvbmNsaWNrPUxvZ0Ns +aWNrQ291bnQodGhpcyw3OSk7IGhyZWY9Imh0dHA6Ly9ibG9nLmNzZG4ubmV0L3dtbm90aGluZyIg +DQogIHRhcmdldD1fYmxhbms+5ZC05rCRPC9BPjwvQ0lURT48QSB0aXRsZT3kvIHkuJrmlofljJbk +uI7igJzphbHmsrnlhZrigJ0gDQogIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNP +UkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsNzkpOyANCiAgaHJl +Zj0iaHR0cDovL2Jsb2cuY3Nkbi5uZXQvd21ub3RoaW5nL2FyY2hpdmUvMjAxMC8xMi8wOS82MDY1 +OTM4LmFzcHgiIA0KICB0YXJnZXQ9X2JsYW5rPuS8geS4muaWh+WMluS4juKAnOmFseayueWFmuKA +nTwvQT48L0RUPg0KICA8RFQgY2xhc3M9dHh0X2JsYWNrIA0KICBzdHlsZT0iUEFERElORy1SSUdI +VDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAwcHggOHB4OyBQQURESU5HLUxFRlQ6IDEwcHg7 +IEZPTlQtU0laRTogMTRweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNu +L3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzI2LmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1B +UkdJTjogM3B4IDBweDsgQ09MT1I6IHJnYigwLDAsMCk7IFBBRERJTkctVE9QOiAwcHg7IFBPU0lU +SU9OOiByZWxhdGl2ZTsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xp +cDogaW5pdGlhbCI+PENJVEUgDQogIGNsYXNzPSJ0eHRfYmx1ZSB0eHRfMTIiIA0KICBzdHlsZT0i +Rk9OVC1TSVpFOiAxMnB4OyBGTE9BVDogcmlnaHQ7IENPTE9SOiByZ2IoMSw5NSwxODIpOyBGT05U +LVNUWUxFOiBub3JtYWwiPjxBIA0KICBzdHlsZT0iQ09MT1I6IHJnYigxLDk1LDE4Mik7IFRFWFQt +REVDT1JBVElPTjogdW5kZXJsaW5lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsNzkp +OyBocmVmPSJodHRwOi8vaGkuY3Nkbi5uZXQvREw4ODI1MC9wcm9maWxlIiANCiAgdGFyZ2V0PV9i +bGFuaz7kuIHkuq48L0E+PC9DSVRFPjxBIHRpdGxlPSJOZXRCZWFucyDml7bkuovpgJrorq/vvIjl +iIrlj7cgIyAxMjkgLSBEZWMgMTQsIDIwMTDvvIkiIA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAs +MCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlz +LDc5KTsgDQogIGhyZWY9Imh0dHA6Ly9ibG9nLmNzZG4ubmV0L0RMODgyNTAvYXJjaGl2ZS8yMDEw +LzEyLzE0LzYwNzY1NjMuYXNweCIgDQogIHRhcmdldD1fYmxhbms+TmV0QmVhbnMg5pe25LqL6YCa +6K6v77yI5YiK5Y+3ICMgMTI5IC0gRGVjIDE0LCAyMDEw77yJPC9BPjwvRFQ+DQogIDxEVCBjbGFz +cz10eHRfYmxhY2sgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9T +SVRJT046IDBweCA4cHg7IFBBRERJTkctTEVGVDogMTBweDsgRk9OVC1TSVpFOiAxNHB4OyBCQUNL +R1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhf +cGljMjYuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAzcHggMHB4OyBDT0xPUjog +cmdiKDAsMCwwKTsgUEFERElORy1UT1A6IDBweDsgUE9TSVRJT046IHJlbGF0aXZlOyBiYWNrZ3Jv +dW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48Q0lURSANCiAg +Y2xhc3M9InR4dF9ibHVlIHR4dF8xMiIgDQogIHN0eWxlPSJGT05ULVNJWkU6IDEycHg7IEZMT0FU +OiByaWdodDsgQ09MT1I6IHJnYigxLDk1LDE4Mik7IEZPTlQtU1RZTEU6IG5vcm1hbCI+PEEgDQog +IHN0eWxlPSJDT0xPUjogcmdiKDEsOTUsMTgyKTsgVEVYVC1ERUNPUkFUSU9OOiB1bmRlcmxpbmUi +IA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw3OSk7IGhyZWY9Imh0dHA6Ly9oaS5jc2Ru +Lm5ldC93b25kZXI0L3Byb2ZpbGUiIA0KICB0YXJnZXQ9X2JsYW5rPum9kOeQqDwvQT48L0NJVEU+ +PEEgDQogIHRpdGxlPSJPcmFjbGUgT3BlbiBXb3JsZOOAgUphdmFPbmXjgIFPcmFjbGUgRGV2ZWxv +cGVyIOesrOS6jOaXpSIgDQogIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFU +SU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsNzkpOyANCiAgaHJlZj0i +aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd29uZGVyNC9hcmNoaXZlLzIwMTAvMTIvMTQvNjA3NjE4OC5h +c3B4IiANCiAgdGFyZ2V0PV9ibGFuaz5PcmFjbGUgT3BlbiBXb3JsZOOAgUphdmFPbmXjgIFPcmFj +bGUgRGV2ZWxvcGVyIOesrOS6jOaXpTwvQT48L0RUPg0KICA8RFQgY2xhc3M9dHh0X2JsYWNrIA0K +ICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAwcHggOHB4 +OyBQQURESU5HLUxFRlQ6IDEwcHg7IEZPTlQtU0laRTogMTRweDsgQkFDS0dST1VORC1JTUFHRTog +dXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzI2LmdpZik7IFBB +RERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogM3B4IDBweDsgQ09MT1I6IHJnYigwLDAsMCk7IFBB +RERJTkctVE9QOiAwcHg7IFBPU0lUSU9OOiByZWxhdGl2ZTsgYmFja2dyb3VuZC1vcmlnaW46IGlu +aXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PENJVEUgDQogIGNsYXNzPSJ0eHRfYmx1 +ZSB0eHRfMTIiIA0KICBzdHlsZT0iRk9OVC1TSVpFOiAxMnB4OyBGTE9BVDogcmlnaHQ7IENPTE9S +OiByZ2IoMSw5NSwxODIpOyBGT05ULVNUWUxFOiBub3JtYWwiPjxBIA0KICBzdHlsZT0iQ09MT1I6 +IHJnYigxLDk1LDE4Mik7IFRFWFQtREVDT1JBVElPTjogdW5kZXJsaW5lIiANCiAgb25jbGljaz1M +b2dDbGlja0NvdW50KHRoaXMsNzkpOyBocmVmPSJodHRwOi8vaGkuY3Nkbi5uZXQvaGVsbG9ndi9w +cm9maWxlIiANCiAgdGFyZ2V0PV9ibGFuaz7lvKDlm73lqIE8L0E+PC9DSVRFPjxBIHRpdGxlPSIg +QW5kcm9pZOaPkOmrmOesrOWNgeS6lOevh+S5i0xpc3RWaWV36Ieq6YCC5bqU5a6e546w6KGo5qC8 +IiANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0K +ICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw3OSk7IA0KICBocmVmPSJodHRwOi8vYmxvZy5j +c2RuLm5ldC9oZWxsb2d2L2FyY2hpdmUvMjAxMC8xMi8xNC82MDc1MDE0LmFzcHgiIA0KICB0YXJn +ZXQ9X2JsYW5rPkFuZHJvaWTmj5Dpq5jnrKzljYHkupTnr4fkuYtMaXN0Vmlld+iHqumAguW6lOWu +nueOsOihqOagvDwvQT48L0RUPg0KICA8RFQgY2xhc3M9dHh0X2JsYWNrIA0KICBzdHlsZT0iUEFE +RElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAwcHggOHB4OyBQQURESU5HLUxF +RlQ6IDEwcHg7IEZPTlQtU0laRTogMTRweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9j +c2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzI2LmdpZik7IFBBRERJTkctQk9UVE9N +OiAwcHg7IE1BUkdJTjogM3B4IDBweDsgQ09MT1I6IHJnYigwLDAsMCk7IFBBRERJTkctVE9QOiAw +cHg7IFBPU0lUSU9OOiByZWxhdGl2ZTsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tn +cm91bmQtY2xpcDogaW5pdGlhbCI+PENJVEUgDQogIGNsYXNzPSJ0eHRfYmx1ZSB0eHRfMTIiIA0K +ICBzdHlsZT0iRk9OVC1TSVpFOiAxMnB4OyBGTE9BVDogcmlnaHQ7IENPTE9SOiByZ2IoMSw5NSwx +ODIpOyBGT05ULVNUWUxFOiBub3JtYWwiPjxBIA0KICBzdHlsZT0iQ09MT1I6IHJnYigxLDk1LDE4 +Mik7IFRFWFQtREVDT1JBVElPTjogdW5kZXJsaW5lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50 +KHRoaXMsNzkpOyBocmVmPSJodHRwOi8vaGkuY3Nkbi5uZXQvY2xldmVyMTAxL3Byb2ZpbGUiIA0K +ICB0YXJnZXQ9X2JsYW5rPuacsemHkeeBvzwvQT48L0NJVEU+PEEgdGl0bGU95Z+65LqO5a+56K+d +5qGG55qE566A5Y2V5Y+M57yT5Yay57uY5Zu+5qGG5p62IA0KICBzdHlsZT0iQ09MT1I6IHJnYigw +LDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0 +aGlzLDc5KTsgDQogIGhyZWY9Imh0dHA6Ly9ibG9nLmNzZG4ubmV0L2NsZXZlcjEwMS9hcmNoaXZl +LzIwMTAvMTIvMTMvNjA3Mzc5MS5hc3B4IiANCiAgdGFyZ2V0PV9ibGFuaz7ln7rkuo7lr7nor53m +oYbnmoTnroDljZXlj4znvJPlhrLnu5jlm77moYbmnrY8L0E+PC9EVD4NCiAgPERUIGNsYXNzPXR4 +dF9ibGFjayANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElP +TjogMHB4IDhweDsgUEFERElORy1MRUZUOiAxMHB4OyBGT05ULVNJWkU6IDE0cHg7IEJBQ0tHUk9V +TkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMy +Ni5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDNweCAwcHg7IENPTE9SOiByZ2Io +MCwwLDApOyBQQURESU5HLVRPUDogMHB4OyBQT1NJVElPTjogcmVsYXRpdmU7IGJhY2tncm91bmQt +b3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxDSVRFIA0KICBjbGFz +cz0idHh0X2JsdWUgdHh0XzEyIiANCiAgc3R5bGU9IkZPTlQtU0laRTogMTJweDsgRkxPQVQ6IHJp +Z2h0OyBDT0xPUjogcmdiKDEsOTUsMTgyKTsgRk9OVC1TVFlMRTogbm9ybWFsIj48QSANCiAgc3R5 +bGU9IkNPTE9SOiByZ2IoMSw5NSwxODIpOyBURVhULURFQ09SQVRJT046IHVuZGVybGluZSIgDQog +IG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDc5KTsgaHJlZj0iaHR0cDovL2hpLmNzZG4ubmV0 +L2F4bWFuL3Byb2ZpbGUiIA0KICB0YXJnZXQ9X2JsYW5rPueOi+eRvuWNjjwvQT48L0NJVEU+PEEg +dGl0bGU9U3ltYmlhbl4z546v5aKD5a6J6KOF5omL6K6wIA0KICBzdHlsZT0iQ09MT1I6IHJnYigw +LDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0 +aGlzLDc5KTsgDQogIGhyZWY9Imh0dHA6Ly9ibG9nLmNzZG4ubmV0L2F4bWFuL2FyY2hpdmUvMjAx +MC8xMi8wMi82MDUxMjM1LmFzcHgiIA0KICB0YXJnZXQ9X2JsYW5rPlN5bWJpYW5eM+eOr+Wig+Wu +ieijheaJi+iusDwvQT48L0RUPg0KICA8REQgY2xhc3M9bmV3c190eXBlYXMgDQogIHN0eWxlPSJQ +QURESU5HLVJJR0hUOiAwcHg7IFBBRERJTkctTEVGVDogMHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1 +cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljNDZuZXcuZ2lmKTsg +UEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAtM3B4IDBweCAxMHB4OyBQQURESU5HLVRPUDog +MHB4OyBQT1NJVElPTjogcmVsYXRpdmU7IEhFSUdIVDogMTlweDsgYmFja2dyb3VuZC1vcmlnaW46 +IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PC9ERD4NCiAgPERUIGNsYXNzPXR4 +dF9ibGFjayANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElP +TjogMHB4IDhweDsgUEFERElORy1MRUZUOiAxMHB4OyBGT05ULVNJWkU6IDE0cHg7IEJBQ0tHUk9V +TkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMy +Ni5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDNweCAwcHg7IENPTE9SOiByZ2Io +MCwwLDApOyBQQURESU5HLVRPUDogMHB4OyBQT1NJVElPTjogcmVsYXRpdmU7IGJhY2tncm91bmQt +b3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxDSVRFIA0KICBjbGFz +cz0idHh0X2JsdWUgdHh0XzEyIiANCiAgc3R5bGU9IkZPTlQtU0laRTogMTJweDsgRkxPQVQ6IHJp +Z2h0OyBDT0xPUjogcmdiKDEsOTUsMTgyKTsgRk9OVC1TVFlMRTogbm9ybWFsIj48QSANCiAgc3R5 +bGU9IkNPTE9SOiByZ2IoMSw5NSwxODIpOyBURVhULURFQ09SQVRJT046IHVuZGVybGluZSIgDQog +IG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDc5KTsgaHJlZj0iaHR0cDovL2hpLmNzZG4ubmV0 +L2xhbnBoYWRheS9wcm9maWxlIiANCiAgdGFyZ2V0PV9ibGFuaz7otZbli4fmtak8L0E+PC9DSVRF +PjxBIHRpdGxlPSLnlKggUHl0aG9uIOeahCBEZXNjcmlwdG9yIOeJueaAp+ino+WGs+S4gOS4quWP +mOaAgeeahOmXrumimCIgDQogIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFU +SU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsNzkpOyANCiAgaHJlZj0i +aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGFucGhhZGF5L2FyY2hpdmUvMjAxMC8xMi8wMi82MDUxMjAx +LmFzcHgiIA0KICB0YXJnZXQ9X2JsYW5rPueUqCBQeXRob24g55qEIERlc2NyaXB0b3Ig54m55oCn +6Kej5Yaz5LiA5Liq5Y+Y5oCB55qE6Zeu6aKYPC9BPjwvRFQ+DQogIDxEVCBjbGFzcz10eHRfYmxh +Y2sgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDBw +eCA4cHg7IFBBRERJTkctTEVGVDogMTBweDsgRk9OVC1TSVpFOiAxNHB4OyBCQUNLR1JPVU5ELUlN +QUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMjYuZ2lm +KTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAzcHggMHB4OyBDT0xPUjogcmdiKDAsMCww +KTsgUEFERElORy1UT1A6IDBweDsgUE9TSVRJT046IHJlbGF0aXZlOyBiYWNrZ3JvdW5kLW9yaWdp +bjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48Q0lURSANCiAgY2xhc3M9InR4 +dF9ibHVlIHR4dF8xMiIgDQogIHN0eWxlPSJGT05ULVNJWkU6IDEycHg7IEZMT0FUOiByaWdodDsg +Q09MT1I6IHJnYigxLDk1LDE4Mik7IEZPTlQtU1RZTEU6IG5vcm1hbCI+PEEgDQogIHN0eWxlPSJD +T0xPUjogcmdiKDEsOTUsMTgyKTsgVEVYVC1ERUNPUkFUSU9OOiB1bmRlcmxpbmUiIA0KICBvbmNs +aWNrPUxvZ0NsaWNrQ291bnQodGhpcyw3OSk7IGhyZWY9Imh0dHA6Ly9oaS5jc2RuLm5ldC9zdXBl +cmNoMDA1NC9wcm9maWxlIiANCiAgdGFyZ2V0PV9ibGFuaz5qYW1lczwvQT48L0NJVEU+PEEgdGl0 +bGU944CK5aSn6YGT6Iez566A44CL6K+75Lmm56yU6K6wIA0KICBzdHlsZT0iQ09MT1I6IHJnYigw +LDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0 +aGlzLDc5KTsgDQogIGhyZWY9Imh0dHA6Ly9ibG9nLmNzZG4ubmV0L3N1cGVyY2gwMDU0L2FyY2hp +dmUvMjAxMC8xMi8wMS82MDQ5MDE0LmFzcHgiIA0KICB0YXJnZXQ9X2JsYW5rPuOAiuWkp+mBk+iH +s+eugOOAi+ivu+S5pueslOiusDwvQT48L0RUPg0KICA8RFQgY2xhc3M9dHh0X2JsYWNrIA0KICBz +dHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAwcHggOHB4OyBQ +QURESU5HLUxFRlQ6IDEwcHg7IEZPTlQtU0laRTogMTRweDsgQkFDS0dST1VORC1JTUFHRTogdXJs +KGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzI2LmdpZik7IFBBRERJ +TkctQk9UVE9NOiAwcHg7IE1BUkdJTjogM3B4IDBweDsgQ09MT1I6IHJnYigwLDAsMCk7IFBBRERJ +TkctVE9QOiAwcHg7IFBPU0lUSU9OOiByZWxhdGl2ZTsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRp +YWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PENJVEUgDQogIGNsYXNzPSJ0eHRfYmx1ZSB0 +eHRfMTIiIA0KICBzdHlsZT0iRk9OVC1TSVpFOiAxMnB4OyBGTE9BVDogcmlnaHQ7IENPTE9SOiBy +Z2IoMSw5NSwxODIpOyBGT05ULVNUWUxFOiBub3JtYWwiPjxBIA0KICBzdHlsZT0iQ09MT1I6IHJn +YigxLDk1LDE4Mik7IFRFWFQtREVDT1JBVElPTjogdW5kZXJsaW5lIiANCiAgb25jbGljaz1Mb2dD +bGlja0NvdW50KHRoaXMsNzkpOyBocmVmPSJodHRwOi8vaGkuY3Nkbi5uZXQvY2hldW5nbWluZS9w +cm9maWxlIiANCiAgdGFyZ2V0PV9ibGFuaz7lvKDkuq48L0E+PC9DSVRFPjxBIHRpdGxlPSJBbmRy +b2lkIOW8gOWPkeWInee6p+WFpemXqO+8muazqOWGjOiwt+atjOWcsOWbviBBUEkg5a+G6ZKl5ZKM +5pi+56S66LC35q2M5Zyw5Zu+IiANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURF +Q09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw3OSk7IA0KICBo +cmVmPSJodHRwOi8vYmxvZy5jc2RuLm5ldC9jaGV1bmdtaW5lL2FyY2hpdmUvMjAxMC8xMi8wMS82 +MDQ4NzM2LmFzcHgiIA0KICB0YXJnZXQ9X2JsYW5rPkFuZHJvaWQg5byA5Y+R5Yid57qn5YWl6Zeo +77ya5rOo5YaM6LC35q2M5Zyw5Zu+IEFQSSDlr4bpkqXlkozmmL7npLrosLfmrYzlnLDlm748L0E+ +PC9EVD4NCiAgPERUIGNsYXNzPXR4dF9ibGFjayANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBw +eDsgQkFDS0dST1VORC1QT1NJVElPTjogMHB4IDhweDsgUEFERElORy1MRUZUOiAxMHB4OyBGT05U +LVNJWkU6IDE0cHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cv +aW1hZ2VzL2NzZG5pbmRleF9waWMyNi5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46 +IDNweCAwcHg7IENPTE9SOiByZ2IoMCwwLDApOyBQQURESU5HLVRPUDogMHB4OyBQT1NJVElPTjog +cmVsYXRpdmU7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGlu +aXRpYWwiPjxDSVRFIA0KICBjbGFzcz0idHh0X2JsdWUgdHh0XzEyIiANCiAgc3R5bGU9IkZPTlQt +U0laRTogMTJweDsgRkxPQVQ6IHJpZ2h0OyBDT0xPUjogcmdiKDEsOTUsMTgyKTsgRk9OVC1TVFlM +RTogbm9ybWFsIj48QSANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMSw5NSwxODIpOyBURVhULURFQ09S +QVRJT046IHVuZGVybGluZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDc5KTsgaHJl +Zj0iaHR0cDovL2hpLmNzZG4ubmV0L3Blbm55bGlhbmcvcHJvZmlsZSIgDQogIHRhcmdldD1fYmxh +bms+5qKB5paMPC9BPjwvQ0lURT48QSB0aXRsZT3mmKjlpKnlvq7ova/kuprnoJTpmaLoh6rnhLbo +r63oqIDlpITnkIbnu4TnmoTlkajmmI7ljZrlo6vnu5nmiJHku6zlgZrkuobmiqXlkYogDQogIHN0 +eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGlj +az1Mb2dDbGlja0NvdW50KHRoaXMsNzkpOyANCiAgaHJlZj0iaHR0cDovL2Jsb2cuY3Nkbi5uZXQv +cGVubnlsaWFuZy9hcmNoaXZlLzIwMTAvMTIvMDEvNjA0ODYwMC5hc3B4IiANCiAgdGFyZ2V0PV9i +bGFuaz7mmKjlpKnlvq7ova/kuprnoJTpmaLoh6rnhLbor63oqIDlpITnkIbnu4TnmoTlkajmmI7l +jZrlo6vnu5nmiJHku6zlgZrkuobmiqXlkYo8L0E+PC9EVD4NCiAgPERUIGNsYXNzPXR4dF9ibGFj +ayANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMHB4 +IDhweDsgUEFERElORy1MRUZUOiAxMHB4OyBGT05ULVNJWkU6IDE0cHg7IEJBQ0tHUk9VTkQtSU1B +R0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMyNi5naWYp +OyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDNweCAwcHg7IENPTE9SOiByZ2IoMCwwLDAp +OyBQQURESU5HLVRPUDogMHB4OyBQT1NJVElPTjogcmVsYXRpdmU7IGJhY2tncm91bmQtb3JpZ2lu +OiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxDSVRFIA0KICBjbGFzcz0idHh0 +X2JsdWUgdHh0XzEyIiANCiAgc3R5bGU9IkZPTlQtU0laRTogMTJweDsgRkxPQVQ6IHJpZ2h0OyBD +T0xPUjogcmdiKDEsOTUsMTgyKTsgRk9OVC1TVFlMRTogbm9ybWFsIj48QSANCiAgc3R5bGU9IkNP +TE9SOiByZ2IoMSw5NSwxODIpOyBURVhULURFQ09SQVRJT046IHVuZGVybGluZSIgDQogIG9uY2xp +Y2s9TG9nQ2xpY2tDb3VudCh0aGlzLDc5KTsgaHJlZj0iaHR0cDovL2hpLmNzZG4ubmV0L2Rhdmlk +X2x2L3Byb2ZpbGUiIA0KICB0YXJnZXQ9X2JsYW5rPuWQleW7uuS8nzwvQT48L0NJVEU+PEEgdGl0 +bGU9IuS4gOS4quS8mOengOeahOeglOWPkeWboumYn+W6lOivpeWFt+Wkh+S7gOS5iOeJueW+gSAi +IA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQog +IG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDc5KTsgDQogIGhyZWY9Imh0dHA6Ly9ibG9nLmNz +ZG4ubmV0L2RhdmlkX2x2L2FyY2hpdmUvMjAxMC8xMi8xMy82MDczMDM0LmFzcHgiIA0KICB0YXJn +ZXQ9X2JsYW5rPuS4gOS4quS8mOengOeahOeglOWPkeWboumYn+W6lOivpeWFt+Wkh+S7gOS5iOeJ +ueW+gTwvQT48L0RUPg0KICA8RFQgY2xhc3M9dHh0X2JsYWNrIA0KICBzdHlsZT0iUEFERElORy1S +SUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAwcHggOHB4OyBQQURESU5HLUxFRlQ6IDEw +cHg7IEZPTlQtU0laRTogMTRweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1n +LmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzI2LmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7 +IE1BUkdJTjogM3B4IDBweDsgQ09MT1I6IHJnYigwLDAsMCk7IFBBRERJTkctVE9QOiAwcHg7IFBP +U0lUSU9OOiByZWxhdGl2ZTsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQt +Y2xpcDogaW5pdGlhbCI+PENJVEUgDQogIGNsYXNzPSJ0eHRfYmx1ZSB0eHRfMTIiIA0KICBzdHls +ZT0iRk9OVC1TSVpFOiAxMnB4OyBGTE9BVDogcmlnaHQ7IENPTE9SOiByZ2IoMSw5NSwxODIpOyBG +T05ULVNUWUxFOiBub3JtYWwiPjxBIA0KICBzdHlsZT0iQ09MT1I6IHJnYigxLDk1LDE4Mik7IFRF +WFQtREVDT1JBVElPTjogdW5kZXJsaW5lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMs +NzkpOyBocmVmPSJodHRwOi8vaGkuY3Nkbi5uZXQvYXp1cmVjaGluYS9wcm9maWxlIiANCiAgdGFy +Z2V0PV9ibGFuaz5henVyZWNoaW5hPC9BPjwvQ0lURT48QSANCiAgdGl0bGU9IueOsOWunuS4lueV +jOeahFdpbmRvd3MgQXp1cmU6IOS4jklNUEFDVEHmgLvoo4HvvIxLZXZpbiBMYW3nmoTorr/osIgi +IA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQog +IG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDc5KTsgDQogIGhyZWY9Imh0dHA6Ly9ibG9nLmNz +ZG4ubmV0L2F6dXJlY2hpbmEvYXJjaGl2ZS8yMDEwLzEyLzEzLzYwNzI3NDQuYXNweCIgDQogIHRh +cmdldD1fYmxhbms+546w5a6e5LiW55WM55qEV2luZG93cyBBenVyZTog5LiOSU1QQUNUQeaAu+ij +ge+8jEtldmluIExhbeeahOiuv+iwiDwvQT48L0RUPg0KICA8RFQgY2xhc3M9dHh0X2JsYWNrIA0K +ICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAwcHggOHB4 +OyBQQURESU5HLUxFRlQ6IDEwcHg7IEZPTlQtU0laRTogMTRweDsgQkFDS0dST1VORC1JTUFHRTog +dXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzI2LmdpZik7IFBB +RERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogM3B4IDBweDsgQ09MT1I6IHJnYigwLDAsMCk7IFBB +RERJTkctVE9QOiAwcHg7IFBPU0lUSU9OOiByZWxhdGl2ZTsgYmFja2dyb3VuZC1vcmlnaW46IGlu +aXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PENJVEUgDQogIGNsYXNzPSJ0eHRfYmx1 +ZSB0eHRfMTIiIA0KICBzdHlsZT0iRk9OVC1TSVpFOiAxMnB4OyBGTE9BVDogcmlnaHQ7IENPTE9S +OiByZ2IoMSw5NSwxODIpOyBGT05ULVNUWUxFOiBub3JtYWwiPjxBIA0KICBzdHlsZT0iQ09MT1I6 +IHJnYigxLDk1LDE4Mik7IFRFWFQtREVDT1JBVElPTjogdW5kZXJsaW5lIiANCiAgb25jbGljaz1M +b2dDbGlja0NvdW50KHRoaXMsNzkpOyBocmVmPSJodHRwOi8vaGkuY3Nkbi5uZXQvYml0ZmFuL3By +b2ZpbGUiIA0KICB0YXJnZXQ9X2JsYW5rPumHkeaXreS6rjwvQT48L0NJVEU+PEEgdGl0bGU96Ieq +5rWL5LiA5LiL5L2g55qESmF2YeaOjOaPoeW+l+aAjuS5iOagt++8nyANCiAgc3R5bGU9IkNPTE9S +OiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNr +Q291bnQodGhpcyw3OSk7IA0KICBocmVmPSJodHRwOi8vYmxvZy5jc2RuLm5ldC9iaXRmYW4vYXJj +aGl2ZS8yMDEwLzEyLzEzLzYwNzI2OTAuYXNweCIgDQogIHRhcmdldD1fYmxhbms+6Ieq5rWL5LiA +5LiL5L2g55qESmF2YeaOjOaPoeW+l+aAjuS5iOagt++8nzwvQT48L0RUPg0KICA8RFQgY2xhc3M9 +dHh0X2JsYWNrIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lU +SU9OOiAwcHggOHB4OyBQQURESU5HLUxFRlQ6IDEwcHg7IEZPTlQtU0laRTogMTRweDsgQkFDS0dS +T1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3Bp +YzI2LmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogM3B4IDBweDsgQ09MT1I6IHJn +YigwLDAsMCk7IFBBRERJTkctVE9QOiAwcHg7IFBPU0lUSU9OOiByZWxhdGl2ZTsgYmFja2dyb3Vu +ZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PENJVEUgDQogIGNs +YXNzPSJ0eHRfYmx1ZSB0eHRfMTIiIA0KICBzdHlsZT0iRk9OVC1TSVpFOiAxMnB4OyBGTE9BVDog +cmlnaHQ7IENPTE9SOiByZ2IoMSw5NSwxODIpOyBGT05ULVNUWUxFOiBub3JtYWwiPjxBIA0KICBz +dHlsZT0iQ09MT1I6IHJnYigxLDk1LDE4Mik7IFRFWFQtREVDT1JBVElPTjogdW5kZXJsaW5lIiAN +CiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsNzkpOyBocmVmPSJodHRwOi8vaGkuY3Nkbi5u +ZXQvY3BpbmcxOTgyL3Byb2ZpbGUiIA0KICB0YXJnZXQ9X2JsYW5rPum5j+WHjOS4ieWNgyhjcGlu +ZzwvQT48L0NJVEU+PEEgdGl0bGU95Li65LuA5LmI5rKh5pyJ5aW955So55qEQW5kcm9pZOa4uOaI +j+W8leaTju+8nyANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046 +IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw3OSk7IA0KICBocmVmPSJodHRw +Oi8vYmxvZy5jc2RuLm5ldC9jcGluZzE5ODIvYXJjaGl2ZS8yMDEwLzEyLzEyLzYwNzIxODguYXNw +eCIgDQogIHRhcmdldD1fYmxhbms+5Li65LuA5LmI5rKh5pyJ5aW955So55qEQW5kcm9pZOa4uOaI +j+W8leaTju+8nzwvQT48L0RUPg0KICA8RFQgY2xhc3M9dHh0X2JsYWNrIA0KICBzdHlsZT0iUEFE +RElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAwcHggOHB4OyBQQURESU5HLUxF +RlQ6IDEwcHg7IEZPTlQtU0laRTogMTRweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9j +c2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzI2LmdpZik7IFBBRERJTkctQk9UVE9N +OiAwcHg7IE1BUkdJTjogM3B4IDBweDsgQ09MT1I6IHJnYigwLDAsMCk7IFBBRERJTkctVE9QOiAw +cHg7IFBPU0lUSU9OOiByZWxhdGl2ZTsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tn +cm91bmQtY2xpcDogaW5pdGlhbCI+PENJVEUgDQogIGNsYXNzPSJ0eHRfYmx1ZSB0eHRfMTIiIA0K +ICBzdHlsZT0iRk9OVC1TSVpFOiAxMnB4OyBGTE9BVDogcmlnaHQ7IENPTE9SOiByZ2IoMSw5NSwx +ODIpOyBGT05ULVNUWUxFOiBub3JtYWwiPjxBIA0KICBzdHlsZT0iQ09MT1I6IHJnYigxLDk1LDE4 +Mik7IFRFWFQtREVDT1JBVElPTjogdW5kZXJsaW5lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50 +KHRoaXMsNzkpOyBocmVmPSJodHRwOi8vaGkuY3Nkbi5uZXQvY2Vud2VuY2h1NzkvcHJvZmlsZSIg +DQogIHRhcmdldD1fYmxhbms+5bKR5paH5YidPC9BPjwvQ0lURT48QSB0aXRsZT1GYWNlYm9va+S8 +mOWMluWIhuS6q+WQjuiusCANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09S +QVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw3OSk7IA0KICBocmVm +PSJodHRwOi8vYmxvZy5jc2RuLm5ldC9jZW53ZW5jaHU3OS9hcmNoaXZlLzIwMTAvMTIvMTIvNjA3 +MTI5OC5hc3B4IiANCiAgdGFyZ2V0PV9ibGFuaz5GYWNlYm9va+S8mOWMluWIhuS6q+WQjuiusDwv +QT48L0RUPg0KICA8REQgY2xhc3M9bmV3c190eXBlYXMgDQogIHN0eWxlPSJQQURESU5HLVJJR0hU +OiAwcHg7IFBBRERJTkctTEVGVDogMHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2Nz +ZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljNDZuZXcuZ2lmKTsgUEFERElORy1CT1RU +T006IDBweDsgTUFSR0lOOiAtM3B4IDBweCAxMHB4OyBQQURESU5HLVRPUDogMHB4OyBQT1NJVElP +TjogcmVsYXRpdmU7IEhFSUdIVDogMTlweDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJh +Y2tncm91bmQtY2xpcDogaW5pdGlhbCI+PC9ERD4NCiAgPERUIGNsYXNzPXR4dF9ibGFjayANCiAg +c3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMHB4IDhweDsg +UEFERElORy1MRUZUOiAxMHB4OyBGT05ULVNJWkU6IDE0cHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVy +bChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMyNi5naWYpOyBQQURE +SU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDNweCAwcHg7IENPTE9SOiByZ2IoMCwwLDApOyBQQURE +SU5HLVRPUDogMHB4OyBQT1NJVElPTjogcmVsYXRpdmU7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0 +aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxDSVRFIA0KICBjbGFzcz0idHh0X2JsdWUg +dHh0XzEyIiANCiAgc3R5bGU9IkZPTlQtU0laRTogMTJweDsgRkxPQVQ6IHJpZ2h0OyBDT0xPUjog +cmdiKDEsOTUsMTgyKTsgRk9OVC1TVFlMRTogbm9ybWFsIj48QSANCiAgc3R5bGU9IkNPTE9SOiBy +Z2IoMSw5NSwxODIpOyBURVhULURFQ09SQVRJT046IHVuZGVybGluZSIgDQogIG9uY2xpY2s9TG9n +Q2xpY2tDb3VudCh0aGlzLDc5KTsgaHJlZj0iaHR0cDovL2hpLmNzZG4ubmV0L2thYmluaS9wcm9m +aWxlIiANCiAgdGFyZ2V0PV9ibGFuaz7olpvnrJs8L0E+PC9DSVRFPjxBIHRpdGxlPSLnlKhDKyvl +hplKYXZhIFN0eWxl56iL5bqPIiANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURF +Q09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw3OSk7IA0KICBo +cmVmPSJodHRwOi8vYmxvZy5jc2RuLm5ldC9rYWJpbmkvYXJjaGl2ZS8yMDEwLzEyLzA1LzYwNTY2 +MTMuYXNweCIgDQogIHRhcmdldD1fYmxhbms+55SoQysr5YaZSmF2YSBTdHlsZeeoi+W6jzwvQT48 +L0RUPg0KICA8RFQgY2xhc3M9dHh0X2JsYWNrIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4 +OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAwcHggOHB4OyBQQURESU5HLUxFRlQ6IDEwcHg7IEZPTlQt +U0laRTogMTRweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9p +bWFnZXMvY3NkbmluZGV4X3BpYzI2LmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjog +M3B4IDBweDsgQ09MT1I6IHJnYigwLDAsMCk7IFBBRERJTkctVE9QOiAwcHg7IFBPU0lUSU9OOiBy +ZWxhdGl2ZTsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5p +dGlhbCI+PENJVEUgDQogIGNsYXNzPSJ0eHRfYmx1ZSB0eHRfMTIiIA0KICBzdHlsZT0iRk9OVC1T +SVpFOiAxMnB4OyBGTE9BVDogcmlnaHQ7IENPTE9SOiByZ2IoMSw5NSwxODIpOyBGT05ULVNUWUxF +OiBub3JtYWwiPjxBIA0KICBzdHlsZT0iQ09MT1I6IHJnYigxLDk1LDE4Mik7IFRFWFQtREVDT1JB +VElPTjogdW5kZXJsaW5lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsNzkpOyBocmVm +PSJodHRwOi8vaGkuY3Nkbi5uZXQvZXlnbGUvcHJvZmlsZSIgDQogIHRhcmdldD1fYmxhbms+55uW +5Zu95by6PC9BPjwvQ0lURT48QSB0aXRsZT0iT3JhY2xl5pWw5o2u5bqT5oGi5aSNIDog5a2Y5YKo +5pWF6Zqc5a+86Ie055qE5pWw5o2u5o2f5Z2PIiANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDAp +OyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw3 +OSk7IA0KICBocmVmPSJodHRwOi8vYmxvZy5jc2RuLm5ldC9leWdsZS9hcmNoaXZlLzIwMTAvMTIv +MDQvNjA1NDU2My5hc3B4IiANCiAgdGFyZ2V0PV9ibGFuaz5PcmFjbGXmlbDmja7lupPmgaLlpI0g +OiDlrZjlgqjmlYXpmpzlr7zoh7TnmoTmlbDmja7mjZ/lnY88L0E+PC9EVD4NCiAgPERUIGNsYXNz +PXR4dF9ibGFjayANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJ +VElPTjogMHB4IDhweDsgUEFERElORy1MRUZUOiAxMHB4OyBGT05ULVNJWkU6IDE0cHg7IEJBQ0tH +Uk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9w +aWMyNi5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDNweCAwcHg7IENPTE9SOiBy +Z2IoMCwwLDApOyBQQURESU5HLVRPUDogMHB4OyBQT1NJVElPTjogcmVsYXRpdmU7IGJhY2tncm91 +bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxDSVRFIA0KICBj +bGFzcz0idHh0X2JsdWUgdHh0XzEyIiANCiAgc3R5bGU9IkZPTlQtU0laRTogMTJweDsgRkxPQVQ6 +IHJpZ2h0OyBDT0xPUjogcmdiKDEsOTUsMTgyKTsgRk9OVC1TVFlMRTogbm9ybWFsIj48QSANCiAg +c3R5bGU9IkNPTE9SOiByZ2IoMSw5NSwxODIpOyBURVhULURFQ09SQVRJT046IHVuZGVybGluZSIg +DQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDc5KTsgaHJlZj0iaHR0cDovL2hpLmNzZG4u +bmV0L2NsZXZlcjEwMS9wcm9maWxlIiANCiAgdGFyZ2V0PV9ibGFuaz7mnLHph5Hngb88L0E+PC9D +SVRFPjxBIHRpdGxlPUdESSvlrabkuaDkuYvnur/mgKfmuJDlj5jnlLvliLcgDQogIHN0eWxlPSJD +T0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dD +bGlja0NvdW50KHRoaXMsNzkpOyANCiAgaHJlZj0iaHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2xldmVy +MTAxL2FyY2hpdmUvMjAxMC8xMi8wOC82MDYzNjk3LmFzcHgiIA0KICB0YXJnZXQ9X2JsYW5rPkdE +SSvlrabkuaDkuYvnur/mgKfmuJDlj5jnlLvliLc8L0E+PC9EVD4NCiAgPERUIGNsYXNzPXR4dF9i +bGFjayANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjog +MHB4IDhweDsgUEFERElORy1MRUZUOiAxMHB4OyBGT05ULVNJWkU6IDE0cHg7IEJBQ0tHUk9VTkQt +SU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMyNi5n +aWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDNweCAwcHg7IENPTE9SOiByZ2IoMCww +LDApOyBQQURESU5HLVRPUDogMHB4OyBQT1NJVElPTjogcmVsYXRpdmU7IGJhY2tncm91bmQtb3Jp +Z2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxDSVRFIA0KICBjbGFzcz0i +dHh0X2JsdWUgdHh0XzEyIiANCiAgc3R5bGU9IkZPTlQtU0laRTogMTJweDsgRkxPQVQ6IHJpZ2h0 +OyBDT0xPUjogcmdiKDEsOTUsMTgyKTsgRk9OVC1TVFlMRTogbm9ybWFsIj48QSANCiAgc3R5bGU9 +IkNPTE9SOiByZ2IoMSw5NSwxODIpOyBURVhULURFQ09SQVRJT046IHVuZGVybGluZSIgDQogIG9u +Y2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDc5KTsgaHJlZj0iaHR0cDovL2hpLmNzZG4ubmV0L2Fp +bWluZ29vL3Byb2ZpbGUiIA0KICB0YXJnZXQ9X2JsYW5rPuWRqOeIseawkTwvQT48L0NJVEU+PEEg +dGl0bGU957un5om/5LiO5re35ZCI77yM55Wl6LCI57O757uf55qE5p6E5bu65pa55byPIA0KICBz +dHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xp +Y2s9TG9nQ2xpY2tDb3VudCh0aGlzLDc5KTsgDQogIGhyZWY9Imh0dHA6Ly9ibG9nLmNzZG4ubmV0 +L2FpbWluZ29vL2FyY2hpdmUvMjAxMC8xMi8wOC82MDYyOTk3LmFzcHgiIA0KICB0YXJnZXQ9X2Js +YW5rPue7p+aJv+S4jua3t+WQiO+8jOeVpeiwiOezu+e7n+eahOaehOW7uuaWueW8jzwvQT48L0RU +Pg0KICA8RFQgY2xhc3M9dHh0X2JsYWNrIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBC +QUNLR1JPVU5ELVBPU0lUSU9OOiAwcHggOHB4OyBQQURESU5HLUxFRlQ6IDEwcHg7IEZPTlQtU0la +RTogMTRweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFn +ZXMvY3NkbmluZGV4X3BpYzI2LmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogM3B4 +IDBweDsgQ09MT1I6IHJnYigwLDAsMCk7IFBBRERJTkctVE9QOiAwcHg7IFBPU0lUSU9OOiByZWxh +dGl2ZTsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlh +bCI+PENJVEUgDQogIGNsYXNzPSJ0eHRfYmx1ZSB0eHRfMTIiIA0KICBzdHlsZT0iRk9OVC1TSVpF +OiAxMnB4OyBGTE9BVDogcmlnaHQ7IENPTE9SOiByZ2IoMSw5NSwxODIpOyBGT05ULVNUWUxFOiBu +b3JtYWwiPjxBIA0KICBzdHlsZT0iQ09MT1I6IHJnYigxLDk1LDE4Mik7IFRFWFQtREVDT1JBVElP +TjogdW5kZXJsaW5lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsNzkpOyBocmVmPSJo +dHRwOi8vaGkuY3Nkbi5uZXQvYmVuaWFvMjc3L3Byb2ZpbGUiIA0KICB0YXJnZXQ9X2JsYW5rPuW8 +oOWuhzwvQT48L0NJVEU+PEEgdGl0bGU9IuaPkuS7tuW8j+aetuaehOiuvuiuoeWunui3teS6jO+8 +muWfuuS6jlNpbHZlcmxpZ2h055qEQi9T5o+S5Lu25byP5p625p6E6K6+6K6h5pa55rOVICIgDQog +IHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25j +bGljaz1Mb2dDbGlja0NvdW50KHRoaXMsNzkpOyANCiAgaHJlZj0iaHR0cDovL2Jsb2cuY3Nkbi5u +ZXQvYmVuaWFvMjc3L2FyY2hpdmUvMjAxMC8xMi8wNy82MDU5NjU3LmFzcHgiIA0KICB0YXJnZXQ9 +X2JsYW5rPuaPkuS7tuW8j+aetuaehOiuvuiuoeWunui3teS6jO+8muWfuuS6jlNpbHZlcmxpZ2h0 +55qEQi9T5o+S5Lu25byP5p625p6E6K6+6K6h5pa55rOVPC9BPjwvRFQ+DQogIDxEVCBjbGFzcz10 +eHRfYmxhY2sgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJ +T046IDBweCA4cHg7IFBBRERJTkctTEVGVDogMTBweDsgRk9OVC1TSVpFOiAxNHB4OyBCQUNLR1JP +VU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGlj +MjYuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAzcHggMHB4OyBDT0xPUjogcmdi +KDAsMCwwKTsgUEFERElORy1UT1A6IDBweDsgUE9TSVRJT046IHJlbGF0aXZlOyBiYWNrZ3JvdW5k +LW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48Q0lURSANCiAgY2xh +c3M9InR4dF9ibHVlIHR4dF8xMiIgDQogIHN0eWxlPSJGT05ULVNJWkU6IDEycHg7IEZMT0FUOiBy +aWdodDsgQ09MT1I6IHJnYigxLDk1LDE4Mik7IEZPTlQtU1RZTEU6IG5vcm1hbCI+PEEgDQogIHN0 +eWxlPSJDT0xPUjogcmdiKDEsOTUsMTgyKTsgVEVYVC1ERUNPUkFUSU9OOiB1bmRlcmxpbmUiIA0K +ICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw3OSk7IGhyZWY9Imh0dHA6Ly9oaS5jc2RuLm5l +dC9jbGV2ZXIxMDEvcHJvZmlsZSIgDQogIHRhcmdldD1fYmxhbms+5pyx6YeR54G/PC9BPjwvQ0lU +RT48QSB0aXRsZT3kuoznu7Tlm77lvaLnvJbovpHkuK3ngrnpgInlj5bnrZbnlaXnoJTnqbYgDQog +IHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25j +bGljaz1Mb2dDbGlja0NvdW50KHRoaXMsNzkpOyANCiAgaHJlZj0iaHR0cDovL2Jsb2cuY3Nkbi5u +ZXQvY2xldmVyMTAxL2FyY2hpdmUvMjAxMC8xMi8wNi82MDU4OTk0LmFzcHgiIA0KICB0YXJnZXQ9 +X2JsYW5rPuS6jOe7tOWbvuW9oue8lui+keS4reeCuemAieWPluetlueVpeeglOeptjwvQT48L0RU +Pg0KICA8RFQgY2xhc3M9dHh0X2JsYWNrIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBC +QUNLR1JPVU5ELVBPU0lUSU9OOiAwcHggOHB4OyBQQURESU5HLUxFRlQ6IDEwcHg7IEZPTlQtU0la +RTogMTRweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFn +ZXMvY3NkbmluZGV4X3BpYzI2LmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogM3B4 +IDBweDsgQ09MT1I6IHJnYigwLDAsMCk7IFBBRERJTkctVE9QOiAwcHg7IFBPU0lUSU9OOiByZWxh +dGl2ZTsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlh +bCI+PENJVEUgDQogIGNsYXNzPSJ0eHRfYmx1ZSB0eHRfMTIiIA0KICBzdHlsZT0iRk9OVC1TSVpF +OiAxMnB4OyBGTE9BVDogcmlnaHQ7IENPTE9SOiByZ2IoMSw5NSwxODIpOyBGT05ULVNUWUxFOiBu +b3JtYWwiPjxBIA0KICBzdHlsZT0iQ09MT1I6IHJnYigxLDk1LDE4Mik7IFRFWFQtREVDT1JBVElP +TjogdW5kZXJsaW5lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsNzkpOyBocmVmPSJo +dHRwOi8vaGkuY3Nkbi5uZXQvZ251aHBjL3Byb2ZpbGUiIA0KICB0YXJnZXQ9X2JsYW5rPum7hOm5 +j+eoizwvQT48L0NJVEU+PEEgdGl0bGU9TGludXjnjq/looPkuIvnmoRDL0Mr5Z+656GA6LCD6K+V +5oqA5pyvMuKAlOKAlOeoi+W6j+aOp+WItiANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBU +RVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw3OSk7 +IA0KICBocmVmPSJodHRwOi8vYmxvZy5jc2RuLm5ldC9nbnVocGMvYXJjaGl2ZS8yMDEwLzEyLzA2 +LzYwNTc4MDkuYXNweCIgDQogIHRhcmdldD1fYmxhbms+TGludXjnjq/looPkuIvnmoRDL0Mr5Z+6 +56GA6LCD6K+V5oqA5pyvMuKAlOKAlOeoi+W6j+aOp+WItjwvQT48L0RUPg0KICA8RFQgY2xhc3M9 +dHh0X2JsYWNrIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lU +SU9OOiAwcHggOHB4OyBQQURESU5HLUxFRlQ6IDEwcHg7IEZPTlQtU0laRTogMTRweDsgQkFDS0dS +T1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3Bp +YzI2LmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogM3B4IDBweDsgQ09MT1I6IHJn +YigwLDAsMCk7IFBBRERJTkctVE9QOiAwcHg7IFBPU0lUSU9OOiByZWxhdGl2ZTsgYmFja2dyb3Vu +ZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PENJVEUgDQogIGNs +YXNzPSJ0eHRfYmx1ZSB0eHRfMTIiIA0KICBzdHlsZT0iRk9OVC1TSVpFOiAxMnB4OyBGTE9BVDog +cmlnaHQ7IENPTE9SOiByZ2IoMSw5NSwxODIpOyBGT05ULVNUWUxFOiBub3JtYWwiPjxBIA0KICBz +dHlsZT0iQ09MT1I6IHJnYigxLDk1LDE4Mik7IFRFWFQtREVDT1JBVElPTjogdW5kZXJsaW5lIiAN +CiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsNzkpOyBocmVmPSJodHRwOi8vaGkuY3Nkbi5u +ZXQvcWluZ3J1bi9wcm9maWxlIiANCiAgdGFyZ2V0PV9ibGFuaz7nmb3mhaflhqw8L0E+PC9DSVRF +PjxBIHRpdGxlPVvlhajnqIvlu7rmqKFd57G75Zu+5ZKM5pe25bqP5Zu+55qE5byA5Y+R5YWz57O7 +77yM5LuO55So5L6L6LCI6LW355qE5YWo56iL5bu65qihIA0KICBzdHlsZT0iQ09MT1I6IHJnYigw +LDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0 +aGlzLDc5KTsgDQogIGhyZWY9Imh0dHA6Ly9ibG9nLmNzZG4ubmV0L3FpbmdydW4vYXJjaGl2ZS8y +MDEwLzEyLzEyLzYwNzA5OTQuYXNweCIgDQogIHRhcmdldD1fYmxhbms+W+WFqOeoi+W7uuaooV3n +sbvlm77lkozml7bluo/lm77nmoTlvIDlj5HlhbPns7vvvIzku47nlKjkvovosIjotbfnmoTlhajn +qIvlu7rmqKE8L0E+PC9EVD4NCiAgPEREIGNsYXNzPW5ld3NfdHlwZWFzIA0KICBzdHlsZT0iUEFE +RElORy1SSUdIVDogMHB4OyBQQURESU5HLUxFRlQ6IDBweDsgQkFDS0dST1VORC1JTUFHRTogdXJs +KGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzQ2bmV3LmdpZik7IFBB +RERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogLTNweCAwcHggMTBweDsgUEFERElORy1UT1A6IDBw +eDsgUE9TSVRJT046IHJlbGF0aXZlOyBIRUlHSFQ6IDE5cHg7IGJhY2tncm91bmQtb3JpZ2luOiBp +bml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjwvREQ+PC9ETD48L0RJVj4NCjxESVYg +Y2xhc3M9YnVzaW5lc3N0eHRhZCANCnN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IERJU1BMQVk6 +IGlubGluZTsgUEFERElORy1MRUZUOiAwcHg7IEZMT0FUOiBsZWZ0OyBQQURESU5HLUJPVFRPTTog +NXB4OyBNQVJHSU46IC02cHggMTBweCAzcHg7IFdJRFRIOiA0NTBweDsgUEFERElORy1UT1A6IDVw +eCI+DQo8VUwgY2xhc3M9dHh0X2RlcGdyYXkgDQpzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBQ +QURESU5HLUxFRlQ6IDBweDsgRkxPQVQ6IGxlZnQ7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJ +TjogMHB4OyBXSURUSDogNDUwcHg7IENPTE9SOiByZ2IoNTEsNTEsNTEpOyBQQURESU5HLVRPUDog +MHB4OyBMSVNULVNUWUxFLVRZUEU6IG5vbmUiPg0KICA8TEkgDQogIHN0eWxlPSJQQURESU5HLVJJ +R0hUOiAwcHg7IERJU1BMQVk6IGlubGluZTsgUEFERElORy1MRUZUOiAwcHg7IEZMT0FUOiBsZWZ0 +OyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweCA1cHg7IFdJRFRIOiAyMTVweDsgUEFE +RElORy1UT1A6IDBweCI+PEEgDQogIHN0eWxlPSJDT0xPUjogcmdiKDUxLDUxLDUxKTsgVEVYVC1E +RUNPUkFUSU9OOiBub25lIiANCiAgaHJlZj0iaHR0cDovL3ouY3Nkbi5uZXQvZ21jbGljay5waHA/ +YmFubmVyaWQ9NDc3NyZhbXA7em9uZWlkPTQyNSZhbXA7c291cmNlPSZhbXA7ZGVzdD1odHRwJTNB +JTJGJTJGd3d3Lml0Y2FzdC5jbiUyRml0Y2FzdF9zdGF0aWMlMkZlbXBsb3lUZWFjaGVyLmh0bSIg +DQogIHRhcmdldD1fYmxhbms+5bm06JaqMTUtMjDkuIfmgKXmi5tqYXZh6K6y5biI77yBPC9BPjwv +TEk+DQogIDxMSSANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgRElTUExBWTogaW5saW5l +OyBQQURESU5HLUxFRlQ6IDBweDsgRkxPQVQ6IGxlZnQ7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1B +UkdJTjogMHB4IDVweDsgV0lEVEg6IDIxNXB4OyBQQURESU5HLVRPUDogMHB4Ij48QSANCiAgc3R5 +bGU9IkNPTE9SOiByZ2IoNTEsNTEsNTEpOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBocmVm +PSJodHRwOi8vei5jc2RuLm5ldC9nbWNsaWNrLnBocD9iYW5uZXJpZD01NDA4JmFtcDt6b25laWQ9 +NDI3JmFtcDtzb3VyY2U9JmFtcDtkZXN0PWh0dHAlM0ElMkYlMkYxODl3b3Jrcy5jc2RuLm5ldCUy +RisiIA0KICB0YXJnZXQ9X2JsYW5rPuWkqee/vOaVmeS9oOenu+WKqOW6lOeUqOiQpeWIqeS5i+mB +kzwvQT48L0xJPg0KICA8TEkgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IERJU1BMQVk6 +IGlubGluZTsgUEFERElORy1MRUZUOiAwcHg7IEZMT0FUOiBsZWZ0OyBQQURESU5HLUJPVFRPTTog +MHB4OyBNQVJHSU46IDBweCA1cHg7IFdJRFRIOiAyMTVweDsgUEFERElORy1UT1A6IDBweCI+PEEg +DQogIHN0eWxlPSJDT0xPUjogcmdiKDUxLDUxLDUxKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiAN +CiAgaHJlZj0iaHR0cDovL3ouY3Nkbi5uZXQvZ21jbGljay5waHA/YmFubmVyaWQ9NTIxMyZhbXA7 +em9uZWlkPTQyNiZhbXA7c291cmNlPSZhbXA7ZGVzdD1odHRwJTNBJTJGJTJGM2cuZWR1LmNzZG4u +bmV0JTJGa2VjaGVuZyUyRkFuZHJvaWQuaHRtbCIgDQogIHRhcmdldD1fYmxhbms+5b+r5o236L2s +5Z6LQW5kcm9pZOmrmOiWquS6uuaJjTwvQT48L0xJPg0KICA8TEkgDQogIHN0eWxlPSJQQURESU5H +LVJJR0hUOiAwcHg7IERJU1BMQVk6IGlubGluZTsgUEFERElORy1MRUZUOiAwcHg7IEZMT0FUOiBs +ZWZ0OyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweCA1cHg7IFdJRFRIOiAyMTVweDsg +UEFERElORy1UT1A6IDBweCI+PEEgDQogIHN0eWxlPSJDT0xPUjogcmdiKDUxLDUxLDUxKTsgVEVY +VC1ERUNPUkFUSU9OOiBub25lIiANCiAgaHJlZj0iaHR0cDovL3ouY3Nkbi5uZXQvZ21jbGljay5w +aHA/YmFubmVyaWQ9NTI5NSZhbXA7em9uZWlkPTQyOCZhbXA7c291cmNlPSZhbXA7ZGVzdD1odHRw +JTNBJTJGJTJGd3d3LmxhbXBicm90aGVyLm5ldCUyRnZpZGVvLmh0bWwiIA0KICB0YXJnZXQ9X2Js +YW5rPuWPsuS4iuacgOe7meWKm+eahOWFjei0uVBIUOinhumikeaVmeeoizwvQT48L0xJPjwvVUw+ +PC9ESVY+PC9ESVY+DQo8RElWIGNsYXNzPXBhZ2Vjb25fbGF5ZXIyX21pZCANCnN0eWxlPSJCT1JE +RVItVE9QOiByZ2IoMjA0LDIwNCwyMDQpIDFweCBzb2xpZDsgRElTUExBWTogaW5saW5lOyBGTE9B +VDogbGVmdDsgTUFSR0lOOiAwcHggMHB4IDBweCA1cHg7IFdJRFRIOiAyNTlweDsgVEVYVC1BTElH +TjogbGVmdCI+DQo8SDMgDQpzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBP +U0lUSU9OOiAwcHggMHB4OyBESVNQTEFZOiBpbmxpbmU7IFBBRERJTkctTEVGVDogMjBweDsgRk9O +VC1TSVpFOiAxNHB4OyBGTE9BVDogbGVmdDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9j +c2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzE1LmdpZik7IFBBRERJTkctQk9UVE9N +OiAwcHg7IE1BUkdJTjogMHB4IDBweCA3cHg7IFdJRFRIOiAyMzlweDsgTElORS1IRUlHSFQ6IDMw +cHg7IFBBRERJTkctVE9QOiAwcHg7IFBPU0lUSU9OOiByZWxhdGl2ZTsgYmFja2dyb3VuZC1vcmln +aW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PFNQQU4gDQpjbGFzcz0idHh0 +XzEyIHR4dF9ncmF5IiANCnN0eWxlPSJGT05ULVdFSUdIVDogbm9ybWFsOyBGT05ULVNJWkU6IDEy +cHg7IEZMT0FUOiByaWdodDsgTUFSR0lOOiAycHggN3B4IDBweCAwcHg7IENPTE9SOiByZ2IoMTAy +LDEwMiwxMDIpIj48QSANCnN0eWxlPSJDT0xPUjogcmdiKDEwMiwxMDIsMTAyKTsgVEVYVC1ERUNP +UkFUSU9OOiBub25lIiANCmhyZWY9Imh0dHA6Ly9ibG9nLmNzZG4ubmV0LyI+5pu05aSaPC9BPjwv +U1BBTj7ljZrlrqLkuYvmmJ88L0gzPg0KPERMIGNsYXNzPWV4cGVydHNob3cgDQpzdHlsZT0iUEFE +RElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiA1MCUgMTAwJTsgRElTUExBWTog +aW5saW5lOyBQQURESU5HLUxFRlQ6IDBweDsgRkxPQVQ6IGxlZnQ7IEJBQ0tHUk9VTkQtSU1BR0U6 +IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMxNC5naWYpOyBQ +QURESU5HLUJPVFRPTTogM3B4OyBNQVJHSU46IDZweCAxMHB4IDBweDsgV0lEVEg6IDIzOXB4OyBQ +QURESU5HLVRPUDogMHB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1j +bGlwOiBpbml0aWFsIj4NCiAgPEREIGNsYXNzPXBpY3MgDQogIHN0eWxlPSJQQURESU5HLVJJR0hU +OiAwcHg7IFBBRERJTkctTEVGVDogMHB4OyBGTE9BVDogbGVmdDsgQkFDS0dST1VORC1JTUFHRTog +dXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzQ3LmdpZik7IFBB +RERJTkctQk9UVE9NOiAzcHg7IE1BUkdJTjogMHB4IDZweCAwcHggMHB4OyBXSURUSDogOTNweDsg +UEFERElORy1UT1A6IDBweDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQt +Y2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxlPeW+rui9r+S6keiuoeeul+S4reaWh+WNmuWuoiBz +dHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xp +Y2s9TG9nQ2xpY2tDb3VudCh0aGlzLDgxKTsgaHJlZj0iaHR0cDovL2Jsb2cuY3Nkbi5uZXQvYXp1 +cmVjaGluYSIgDQogIHRhcmdldD1fYmxhbms+PElNRyB0aXRsZT0iIiANCiAgc3R5bGU9IkJPUkRF +Ui1SSUdIVDogcmdiKDAsMCwwKSAxcHggc29saWQ7IEJPUkRFUi1UT1A6IHJnYigwLDAsMCkgMXB4 +IHNvbGlkOyBCT1JERVItTEVGVDogcmdiKDAsMCwwKSAxcHggc29saWQ7IFdJRFRIOiA4NnB4OyBC +T1JERVItQk9UVE9NOiByZ2IoMCwwLDApIDFweCBzb2xpZDsgSEVJR0hUOiA4NnB4IiANCiAgYWx0 +PSIiIHNyYz0iaHR0cDovL2F2YXRhci5jc2RuLm5ldC82L0EvNi8xX2F6dXJlY2hpbmEuanBnIiB3 +aWR0aD04Nj48L0E+PC9ERD4NCiAgPEREIGNsYXNzPXR4dF9ibHVlIA0KICBzdHlsZT0iUEFERElO +Ry1SSUdIVDogMHB4OyBQQURESU5HLUxFRlQ6IDBweDsgUEFERElORy1CT1RUT006IDNweDsgTUFS +R0lOOiAwcHg7IENPTE9SOiByZ2IoMSw5NSwxODIpOyBQQURESU5HLVRPUDogMHB4Ij48QSANCiAg +dGl0bGU95b6u6L2v5LqR6K6h566X5Lit5paH5Y2a5a6iIHN0eWxlPSJDT0xPUjogcmdiKDEsOTUs +MTgyKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRo +aXMsODEpOyBocmVmPSJodHRwOi8vYmxvZy5jc2RuLm5ldC9henVyZWNoaW5hIiANCiAgdGFyZ2V0 +PV9ibGFuaz7lvq7ova/kupHorqHnrpfkuK3mlofljZrlrqI8L0E+PC9ERD4NCiAgPEREIA0KICBz +dHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBQQURESU5HLUxFRlQ6IDBweDsgUEFERElORy1CT1RU +T006IDNweDsgTUFSR0lOOiAwcHg7IFBBRERJTkctVE9QOiAwcHgiPuacrOS4reaWh+WNmuWuoueU +seW+rui9r+S6keiuoeeul0F6dXJl6K665Z2b5pSv5oyB5bCP57uE5byA5Yqe44CC5YaF5a655Lul +V2luZG93cyANCiAgQXp1cmUgUGxhdGZvcm3kuLrkuLvjgII8L0REPg0KICA8REQgY2xhc3M9ImFz +ayB0eHRfYmx1ZSIgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiA1cHg7IFBBRERJTkctTEVGVDog +MHB4OyBGTE9BVDogcmlnaHQ7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBDT0xP +UjogcmdiKDEsOTUsMTgyKTsgUEFERElORy1UT1A6IDBweCI+PEEgDQogIHRpdGxlPeW+rui9r+S6 +keiuoeeul+S4reaWh+WNmuWuoiBzdHlsZT0iQ09MT1I6IHJnYigxLDk1LDE4Mik7IFRFWFQtREVD +T1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDgxKTsgaHJlZj0i +aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYXp1cmVjaGluYSIgDQogIHRhcmdldD1fYmxhbms+6K6/6Zeu +5LuW55qE56m66Ze0PC9BPjwvREQ+PC9ETD4NCjxETCBjbGFzcz1zdHlsZTMgDQpzdHlsZT0iUEFE +RElORy1SSUdIVDogMHB4OyBESVNQTEFZOiBpbmxpbmU7IFBBRERJTkctTEVGVDogMHB4OyBGTE9B +VDogbGVmdDsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiA1cHggMTBweDsgV0lEVEg6IDIz +OXB4OyBQQURESU5HLVRPUDogMHB4Ij4NCiAgPEREIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDog +MHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAzcHggN3B4OyBQQURESU5HLUxFRlQ6IDE0cHg7IEJB +Q0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRl +eF9waWMyMy5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweDsgTElORS1IRUlH +SFQ6IDIxcHg7IFBBRERJTkctVE9QOiAwcHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBi +YWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0aXRsZT0i5ZyoV2luZG93cyBBenVyZeW5 +s+WPsOS4iumDqOe9suacjeWKoSIgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09S +QVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw4MSk7IA0KICBocmVm +PSJodHRwOi8vYmxvZy5jc2RuLm5ldC9henVyZWNoaW5hL2FyY2hpdmUvMjAxMC8wNS8xNi81NTk3 +NjU4LmFzcHgiPuWcqFdpbmRvd3MgDQogIEF6dXJl5bmz5Y+w5LiK6YOo572y5pyN5YqhPC9BPjwv +REQ+DQogIDxERCANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJ +VElPTjogM3B4IDdweDsgUEFERElORy1MRUZUOiAxNHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwo +aHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMjMuZ2lmKTsgUEFERElO +Ry1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IExJTkUtSEVJR0hUOiAyMXB4OyBQQURESU5HLVRP +UDogMHB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0 +aWFsIj48QSANCiAgdGl0bGU9IldpbmRvd3MgQXp1cmUgQ2xvdWRQb2xsIGZvciBGYWNlYm9va+WP +keW4gyIgDQogIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25l +IiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsODEpOyANCiAgaHJlZj0iaHR0cDovL2Js +b2cuY3Nkbi5uZXQvYXp1cmVjaGluYS9hcmNoaXZlLzIwMTAvMDUvMTYvNTU5NzY2Mi5hc3B4Ij5X +aW5kb3dzIA0KICBBenVyZSBDbG91ZFBvbGwgZm9yPC9BPjwvREQ+DQogIDxERCANCiAgc3R5bGU9 +IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogM3B4IDdweDsgUEFERElO +Ry1MRUZUOiAxNHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3 +L2ltYWdlcy9jc2RuaW5kZXhfcGljMjMuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lO +OiAwcHg7IExJTkUtSEVJR0hUOiAyMXB4OyBQQURESU5HLVRPUDogMHB4OyBiYWNrZ3JvdW5kLW9y +aWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgdGl0bGU9IlRh +YmxlIFN0b3JhZ2Xlr7nliIbpobXnmoTmlK/mjIEiIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsg +VEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsODEp +OyANCiAgaHJlZj0iaHR0cDovL2Jsb2cuY3Nkbi5uZXQvYXp1cmVjaGluYS9hcmNoaXZlLzIwMTAv +MDUvMTYvNTU5NzY0Mi5hc3B4Ij5UYWJsZSANCiAgU3RvcmFnZeWvueWIhumhteeahOaUr+aMgTwv +QT48L0REPg0KICA8REQgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQt +UE9TSVRJT046IDNweCA3cHg7IFBBRERJTkctTEVGVDogMTRweDsgQkFDS0dST1VORC1JTUFHRTog +dXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzIzLmdpZik7IFBB +RERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBMSU5FLUhFSUdIVDogMjFweDsgUEFERElO +Ry1UT1A6IDBweDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDog +aW5pdGlhbCI+PEEgDQogIHRpdGxlPeWmguS9lemAieaLqeiZmuaLn+acuuinhOagvCBzdHlsZT0i +Q09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9n +Q2xpY2tDb3VudCh0aGlzLDgxKTsgDQogIGhyZWY9Imh0dHA6Ly9ibG9nLmNzZG4ubmV0L2F6dXJl +Y2hpbmEvYXJjaGl2ZS8yMDEwLzA1LzE2LzU1OTc2MzEuYXNweCI+5aaC5L2V6YCJ5oup6Jma5ouf +5py66KeE5qC8PC9BPjwvREQ+DQogIDxERCANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsg +QkFDS0dST1VORC1QT1NJVElPTjogM3B4IDdweDsgUEFERElORy1MRUZUOiAxNHB4OyBCQUNLR1JP +VU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGlj +MjMuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IExJTkUtSEVJR0hUOiAy +MXB4OyBQQURESU5HLVRPUDogMHB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dy +b3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgdGl0bGU95byA5Y+R5ouT5bGV5pCc57SiLeaVkeaP +tOW6lOeUqOeoi+W6jyBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjog +bm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDgxKTsgDQogIGhyZWY9Imh0dHA6 +Ly9ibG9nLmNzZG4ubmV0L2F6dXJlY2hpbmEvYXJjaGl2ZS8yMDEwLzA1LzE2LzU1OTc2MjMuYXNw +eCI+5byA5Y+R5ouT5bGV5pCc57SiLeaVkeaPtOW6lOeUqOeoi+W6jzwvQT48L0REPg0KICA8REQg +DQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDNweCA3 +cHg7IFBBRERJTkctTEVGVDogMTRweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2Ru +aW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzIzLmdpZik7IFBBRERJTkctQk9UVE9NOiAw +cHg7IE1BUkdJTjogMHB4OyBMSU5FLUhFSUdIVDogMjFweDsgUEFERElORy1UT1A6IDBweDsgYmFj +a2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQog +IHRpdGxlPSLnjrDlrp7kuJbnlYznmoRXaW5kb3dzIEF6dXJlIiBzdHlsZT0iQ09MT1I6IHJnYigw +LDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0 +aGlzLDgxKTsgDQogIGhyZWY9Imh0dHA6Ly9ibG9nLmNzZG4ubmV0L2F6dXJlY2hpbmEvYXJjaGl2 +ZS8yMDEwLzA1LzE2LzU1OTc2MjAuYXNweCI+546w5a6e5LiW55WM55qEV2luZG93cyANCiAgQXp1 +cmU8L0E+PC9ERD48L0RMPg0KPEgzIA0Kc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dS +T1VORC1QT1NJVElPTjogMHB4IDBweDsgRElTUExBWTogaW5saW5lOyBQQURESU5HLUxFRlQ6IDIw +cHg7IEZPTlQtU0laRTogMTRweDsgRkxPQVQ6IGxlZnQ7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybCho +dHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMxNS5naWYpOyBQQURESU5H +LUJPVFRPTTogMHB4OyBNQVJHSU46IDBweCAwcHggN3B4OyBXSURUSDogMjM5cHg7IExJTkUtSEVJ +R0hUOiAzMHB4OyBQQURESU5HLVRPUDogMHB4OyBQT1NJVElPTjogcmVsYXRpdmU7IGJhY2tncm91 +bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxTUEFOIA0KY2xh +c3M9InR4dF8xMiB0eHRfZ3JheSIgDQpzdHlsZT0iRk9OVC1XRUlHSFQ6IG5vcm1hbDsgRk9OVC1T +SVpFOiAxMnB4OyBGTE9BVDogcmlnaHQ7IE1BUkdJTjogMnB4IDdweCAwcHggMHB4OyBDT0xPUjog +cmdiKDEwMiwxMDIsMTAyKSI+PEEgDQpzdHlsZT0iQ09MT1I6IHJnYigxMDIsMTAyLDEwMik7IFRF +WFQtREVDT1JBVElPTjogbm9uZSIgDQpocmVmPSJodHRwOi8vY3RvLmNzZG4ubmV0LyI+5pu05aSa +PC9BPjwvU1BBTj5DVE/kv7HkuZDpg6g8L0gzPg0KPERMIGNsYXNzPWN0b3Nob3cgDQpzdHlsZT0i +UEFERElORy1SSUdIVDogMHB4OyBESVNQTEFZOiBpbmxpbmU7IFBBRERJTkctTEVGVDogMHB4OyBG +TE9BVDogbGVmdDsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHggMTBweDsgV0lEVEg6 +IDIzOXB4OyBQQURESU5HLVRPUDogMHB4Ij4NCiAgPERUIA0KICBzdHlsZT0iUEFERElORy1SSUdI +VDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiA1MCUgMTAwJTsgUEFERElORy1MRUZUOiAwcHg7 +IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5p +bmRleF9waWMxNC5naWYpOyBQQURESU5HLUJPVFRPTTogM3B4OyBNQVJHSU46IDBweCAwcHggNXB4 +OyBQQURESU5HLVRPUDogMHB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3Vu +ZC1jbGlwOiBpbml0aWFsIj7mrKLov47lpKflrrbliqDlhaVDVE/kv7HkuZDpg6gs6L+Z5piv6Z2i +5ZCR6auY56uv5oqA5pyv566h55CG6ICF55qE56S+5Yy644CCPEVNIA0KICBjbGFzcz10eHRfYmx1 +ZSBzdHlsZT0iQ09MT1I6IHJnYigxLDk1LDE4Mik7IEZPTlQtU1RZTEU6IG5vcm1hbCI+PEEgDQog +IHN0eWxlPSJDT0xPUjogcmdiKDEsOTUsMTgyKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAg +b25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsODMpOyBocmVmPSJodHRwOi8vY3RvLmNzZG4ubmV0 +LyIgDQogIHRhcmdldD1fYmxhbms+W+aIkeimgeWKoOWFpV08L0E+PC9FTT48L0RUPg0KICA8REQg +DQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDNweCA3 +cHg7IFBBRERJTkctTEVGVDogMTRweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2Ru +aW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzIzLmdpZik7IFBBRERJTkctQk9UVE9NOiAw +cHg7IE1BUkdJTjogMHB4OyBMSU5FLUhFSUdIVDogMjFweDsgUEFERElORy1UT1A6IDBweDsgYmFj +a2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+WzHkurrl +m57lpI1dPEEgDQogIGNsYXNzPXR4dF9ibHVlIHRpdGxlPeWFs+S6juiAgeWkluWunueUqOeahOWO +i+e8qei9r+S7tumXrumimCANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgUEFERElORy1M +RUZUOiAzcHg7IFBBRERJTkctQk9UVE9NOiAwcHg7IENPTE9SOiByZ2IoMSw5NSwxODIpOyBQQURE +SU5HLVRPUDogMHB4OyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNr +Q291bnQodGhpcyw4Myk7IA0KICBocmVmPSJodHRwOi8vY3RvLmNzZG4ubmV0L0hvdF9EaXNjdXNz +LmFzcHg/TmFtZT15YW5nemhpd3UmYW1wO3BvaW50aWQ9NDExNSIgDQogIHRhcmdldD1fYmxhbms+ +5YWz5LqO6ICB5aSW5a6e55So55qE5Y6L57yp6L2v5Lu26Zeu6aKYPC9BPjwvREQ+DQogIDxERCAN +CiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogM3B4IDdw +eDsgUEFERElORy1MRUZUOiAxNHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5p +bWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMjMuZ2lmKTsgUEFERElORy1CT1RUT006IDBw +eDsgTUFSR0lOOiAwcHg7IExJTkUtSEVJR0hUOiAyMXB4OyBQQURESU5HLVRPUDogMHB4OyBiYWNr +Z3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj5bMTTkurrl +m57lpI1dPEEgDQogIGNsYXNzPXR4dF9ibHVlIHRpdGxlPeW9vOW+l+W+t+mygeWFi+OAiueuoeeQ +hueahOWunui3teOAi+acreiusCANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgUEFERElO +Ry1MRUZUOiAzcHg7IFBBRERJTkctQk9UVE9NOiAwcHg7IENPTE9SOiByZ2IoMSw5NSwxODIpOyBQ +QURESU5HLVRPUDogMHB4OyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0Ns +aWNrQ291bnQodGhpcyw4Myk7IA0KICBocmVmPSJodHRwOi8vY3RvLmNzZG4ubmV0L0hvdF9EaXNj +dXNzLmFzcHg/TmFtZT1mZW5nZ3VveGluJmFtcDtwb2ludGlkPTQwODAiIA0KICB0YXJnZXQ9X2Js +YW5rPuW9vOW+l+W+t+mygeWFi+OAiueuoeeQhueahOWunui3teOAi+acrTwvQT48L0REPg0KICA8 +REQgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDNw +eCA3cHg7IFBBRERJTkctTEVGVDogMTRweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9j +c2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzIzLmdpZik7IFBBRERJTkctQk9UVE9N +OiAwcHg7IE1BUkdJTjogMHB4OyBMSU5FLUhFSUdIVDogMjFweDsgUEFERElORy1UT1A6IDBweDsg +YmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+WzEx +5Lq65Zue5aSNXTxBIA0KICBjbGFzcz10eHRfYmx1ZSB0aXRsZT3ov5DokKXnsbvpobnnm67kvZzk +uLrliJvkuJrmgKfpobnnm67mr5TovoPpgILlkIggDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAw +cHg7IFBBRERJTkctTEVGVDogM3B4OyBQQURESU5HLUJPVFRPTTogMHB4OyBDT0xPUjogcmdiKDEs +OTUsMTgyKTsgUEFERElORy1UT1A6IDBweDsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25j +bGljaz1Mb2dDbGlja0NvdW50KHRoaXMsODMpOyANCiAgaHJlZj0iaHR0cDovL2N0by5jc2RuLm5l +dC9Ib3RfRGlzY3Vzcy5hc3B4P05hbWU9bGNuc3kmYW1wO3BvaW50aWQ9NDA4NyIgDQogIHRhcmdl +dD1fYmxhbms+6L+Q6JCl57G76aG555uu5L2c5Li65Yib5Lia5oCn6aG555uu5q+UPC9BPjwvREQ+ +DQogIDxERCANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElP +TjogM3B4IDdweDsgUEFERElORy1MRUZUOiAxNHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0 +cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMjMuZ2lmKTsgUEFERElORy1C +T1RUT006IDBweDsgTUFSR0lOOiAwcHg7IExJTkUtSEVJR0hUOiAyMXB4OyBQQURESU5HLVRPUDog +MHB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFs +Ij5bM+S6uuWbnuWkjV08QSANCiAgY2xhc3M9dHh0X2JsdWUgdGl0bGU95Zyo57uG5YiG5biC5Zy6 +5Lit5a+75om+5Yib5Lia5py65LyaIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBQQURE +SU5HLUxFRlQ6IDNweDsgUEFERElORy1CT1RUT006IDBweDsgQ09MT1I6IHJnYigxLDk1LDE4Mik7 +IFBBRERJTkctVE9QOiAwcHg7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9n +Q2xpY2tDb3VudCh0aGlzLDgzKTsgDQogIGhyZWY9Imh0dHA6Ly9jdG8uY3Nkbi5uZXQvSG90X0Rp +c2N1c3MuYXNweD9OYW1lPWxjbnN5JmFtcDtwb2ludGlkPTQxMTIiIA0KICB0YXJnZXQ9X2JsYW5r +PuWcqOe7huWIhuW4guWcuuS4reWvu+aJvuWIm+S4muacuuS8mjwvQT48L0REPg0KICA8REQgDQog +IHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDNweCA3cHg7 +IFBBRERJTkctTEVGVDogMTRweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1n +LmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzIzLmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7 +IE1BUkdJTjogMHB4OyBMSU5FLUhFSUdIVDogMjFweDsgUEFERElORy1UT1A6IDBweDsgYmFja2dy +b3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+WzLkurrlm57l +pI1dPEEgDQogIGNsYXNzPXR4dF9ibHVlIHRpdGxlPeWvu+axgui9r+S7tuS4gOasvn4gDQogIHN0 +eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IFBBRERJTkctTEVGVDogM3B4OyBQQURESU5HLUJPVFRP +TTogMHB4OyBDT0xPUjogcmdiKDEsOTUsMTgyKTsgUEFERElORy1UT1A6IDBweDsgVEVYVC1ERUNP +UkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsODMpOyANCiAgaHJl +Zj0iaHR0cDovL2N0by5jc2RuLm5ldC9Ib3RfRGlzY3Vzcy5hc3B4P05hbWU9emhhbmctY2hlbmcm +YW1wO3BvaW50aWQ9NDEwNCIgDQogIHRhcmdldD1fYmxhbms+5a+75rGC6L2v5Lu25LiA5qy+fjwv +QT48L0REPg0KICA8REQgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQt +UE9TSVRJT046IDNweCA3cHg7IFBBRERJTkctTEVGVDogMTRweDsgQkFDS0dST1VORC1JTUFHRTog +dXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzIzLmdpZik7IFBB +RERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBMSU5FLUhFSUdIVDogMjFweDsgUEFERElO +Ry1UT1A6IDBweDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDog +aW5pdGlhbCI+Wzgy5Lq65Zue5aSNXTxBIA0KICBjbGFzcz10eHRfYmx1ZSB0aXRsZT0xMeaciDI1 +5pel5omL5py65a6i5oi356uv5LiT5aeU5Lya5YyX5Lqs5rS75Yqo5YWN6LS55oql5ZCN5Y+C5Yqg +77ya6Iux54m55bCU55u45YWz6LSf6LSj5Lq65YiG5LqrTWVlR2/miJjnlaXlj5HlsZXmlrnlkJHl +j4rkvZPns7vmnrbmnoTlkozmioDmnK8gDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IFBB +RERJTkctTEVGVDogM3B4OyBQQURESU5HLUJPVFRPTTogMHB4OyBDT0xPUjogcmdiKDEsOTUsMTgy +KTsgUEFERElORy1UT1A6IDBweDsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1M +b2dDbGlja0NvdW50KHRoaXMsODMpOyANCiAgaHJlZj0iaHR0cDovL2N0by5jc2RuLm5ldC9Ib3Rf +RGlzY3Vzcy5hc3B4P05hbWU9YWRtaW4mYW1wO3BvaW50aWQ9NDA0NiIgDQogIHRhcmdldD1fYmxh +bms+MTHmnIgyNeaXpeaJi+acuuWuouaIt+err+S4k+WnlDwvQT48L0REPg0KICA8REQgDQogIHN0 +eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDNweCA3cHg7IFBB +RERJTkctTEVGVDogMTRweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNu +L3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzIzLmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1B +UkdJTjogMHB4OyBMSU5FLUhFSUdIVDogMjFweDsgUEFERElORy1UT1A6IDBweDsgYmFja2dyb3Vu +ZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+WzDkurrlm57lpI1d +PEEgDQogIGNsYXNzPXR4dF9ibHVlIHRpdGxlPeS4reW1jOWNj+S8muesrOWbm+acn+KAnOW1jOWF +peW8j+S4jueJqeiBlOe9keKAneS4u+mimOiuuuWdm+WwhuS6jjEy5pyIMjXml6XlnKjljJfkuqzk +uL7ooYwgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IFBBRERJTkctTEVGVDogM3B4OyBQ +QURESU5HLUJPVFRPTTogMHB4OyBDT0xPUjogcmdiKDEsOTUsMTgyKTsgUEFERElORy1UT1A6IDBw +eDsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMs +ODMpOyANCiAgaHJlZj0iaHR0cDovL2N0by5jc2RuLm5ldC9Ib3RfRGlzY3Vzcy5hc3B4P05hbWU9 +Y2VzaWEmYW1wO3BvaW50aWQ9NDExOCIgDQogIHRhcmdldD1fYmxhbms+5Lit5bWM5Y2P5Lya56ys +5Zub5pyf4oCc5bWM5YWl5byP5LiO54mpPC9BPjwvREQ+DQogIDxERCANCiAgc3R5bGU9IlBBRERJ +TkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogM3B4IDdweDsgUEFERElORy1MRUZU +OiAxNHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdl +cy9jc2RuaW5kZXhfcGljMjMuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7 +IExJTkUtSEVJR0hUOiAyMXB4OyBQQURESU5HLVRPUDogMHB4OyBiYWNrZ3JvdW5kLW9yaWdpbjog +aW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj5bNOS6uuWbnuWkjV08QSANCiAgY2xh +c3M9dHh0X2JsdWUgdGl0bGU94oCc5LqR6K6h566X4oCd5bqU5LiN5bqU6K+l5piO56Gu6KeE6IyD +IA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBQQURESU5HLUxFRlQ6IDNweDsgUEFERElO +Ry1CT1RUT006IDBweDsgQ09MT1I6IHJnYigxLDk1LDE4Mik7IFBBRERJTkctVE9QOiAwcHg7IFRF +WFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDgzKTsg +DQogIGhyZWY9Imh0dHA6Ly9jdG8uY3Nkbi5uZXQvSG90X0Rpc2N1c3MuYXNweD9OYW1lPWZ1ZG9u +Z3NoZW5nJmFtcDtwb2ludGlkPTQwODMiIA0KICB0YXJnZXQ9X2JsYW5rPuKAnOS6keiuoeeul+KA +neW6lOS4jeW6lOivpeaYjuehruinhOiMgzwvQT48L0REPjwvREw+DQo8SDMgDQpzdHlsZT0iUEFE +RElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAwcHggMHB4OyBESVNQTEFZOiBp +bmxpbmU7IFBBRERJTkctTEVGVDogMjBweDsgRk9OVC1TSVpFOiAxNHB4OyBGTE9BVDogbGVmdDsg +QkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3Nkbmlu +ZGV4X3BpYzE1LmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4IDBweCA3cHg7 +IFdJRFRIOiAyMzlweDsgTElORS1IRUlHSFQ6IDMwcHg7IFBBRERJTkctVE9QOiAwcHg7IFBPU0lU +SU9OOiByZWxhdGl2ZTsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xp +cDogaW5pdGlhbCI+PFNQQU4gDQpjbGFzcz0idHh0XzEyIHR4dF9ncmF5IiANCnN0eWxlPSJGT05U +LVdFSUdIVDogbm9ybWFsOyBGT05ULVNJWkU6IDEycHg7IEZMT0FUOiByaWdodDsgTUFSR0lOOiAy +cHggN3B4IDBweCAwcHg7IENPTE9SOiByZ2IoMTAyLDEwMiwxMDIpIj48QSANCnN0eWxlPSJDT0xP +UjogcmdiKDEwMiwxMDIsMTAyKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCmhyZWY9Imh0dHA6 +Ly9ibG9nLmNzZG4ubmV0LyI+5pu05aSaPC9BPjwvU1BBTj7ng63mlofmjpLooYw8L0gzPg0KPERM +IGNsYXNzPSJzdHlsZTIgdHh0X2JsYWNrIiANCnN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IERJ +U1BMQVk6IGlubGluZTsgUEFERElORy1MRUZUOiAwcHg7IEZMT0FUOiBsZWZ0OyBQQURESU5HLUJP +VFRPTTogMHB4OyBNQVJHSU46IDVweCAxMHB4OyBXSURUSDogMjM5cHg7IENPTE9SOiByZ2IoMCww +LDApOyBQQURESU5HLVRPUDogMHB4Ij4NCiAgPERUIGNsYXNzPXRvcDEgDQogIHN0eWxlPSJQQURE +SU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDBweCAzcHg7IE9WRVJGTE9XLVk6 +IGhpZGRlbjsgUEFERElORy1MRUZUOiAyNHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDov +L2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMzUuZ2lmKTsgT1ZFUkZMT1ctWDog +aGlkZGVuOyBQQURESU5HLUJPVFRPTTogMXB4OyBNQVJHSU46IDBweDsgV0lEVEg6IDIxMHB4OyBQ +QURESU5HLVRPUDogNHB4OyBXSElURS1TUEFDRTogbm93cmFwOyBiYWNrZ3JvdW5kLW9yaWdpbjog +aW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgdGl0bGU96Z2i5ZCR56iL +5bqP5ZGY55qE5pWw5o2u5bqT6K6/6Zeu5oCn6IO95LyY5YyW5rOV5YiZIHN0eWxlPSJDT0xPUjog +cmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0Nv +dW50KHRoaXMsODIpOyANCiAgaHJlZj0iaHR0cDovL2Jsb2cuY3Nkbi5uZXQveXpzaW5kL2FyY2hp +dmUvMjAxMC8xMi8wNi82MDU5MjA5LmFzcHgiIA0KICB0YXJnZXQ9X2JsYW5rPumdouWQkeeoi+W6 +j+WRmOeahOaVsOaNruW6k+iuv+mXruaAp+iDveS8mOWMluazleWImTwvQT48L0RUPg0KICA8RFQg +Y2xhc3M9dG9wMiANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJ +VElPTjogMHB4IDNweDsgT1ZFUkZMT1ctWTogaGlkZGVuOyBQQURESU5HLUxFRlQ6IDI0cHg7IEJB +Q0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRl +eF9waWMzNi5naWYpOyBPVkVSRkxPVy1YOiBoaWRkZW47IFBBRERJTkctQk9UVE9NOiAxcHg7IE1B +UkdJTjogMHB4OyBXSURUSDogMjEwcHg7IFBBRERJTkctVE9QOiA0cHg7IFdISVRFLVNQQUNFOiBu +b3dyYXA7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRp +YWwiPjxBIA0KICB0aXRsZT0i6aG257qn56iL5bqP5ZGY55qE5b+D5b6XIC0gQ29kZXJzIGF0IFdv +cmsiIA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIg +DQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDgyKTsgDQogIGhyZWY9Imh0dHA6Ly9ibG9n +LmNzZG4ubmV0L1NvZnR3YXJlVGVhY2hlci9hcmNoaXZlLzIwMTAvMTEvMjcvNjAzOTkwMS5hc3B4 +IiANCiAgdGFyZ2V0PV9ibGFuaz7pobbnuqfnqIvluo/lkZjnmoTlv4PlvpcgLSBDb2RlcnMgYXQg +V29yazwvQT48L0RUPg0KICA8RFQgY2xhc3M9dG9wMyANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6 +IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMHB4IDNweDsgT1ZFUkZMT1ctWTogaGlkZGVuOyBQ +QURESU5HLUxFRlQ6IDI0cHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5j +bi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMzNy5naWYpOyBPVkVSRkxPVy1YOiBoaWRkZW47IFBB +RERJTkctQk9UVE9NOiAxcHg7IE1BUkdJTjogMHB4OyBXSURUSDogMjEwcHg7IFBBRERJTkctVE9Q +OiA0cHg7IFdISVRFLVNQQUNFOiBub3dyYXA7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBi +YWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0aXRsZT1MaW51eOeOr+Wig+S4i+eahEMv +Qysr5Z+656GA6LCD6K+V5oqA5pyvMeKAlOKAlOWIneatpeS6huinoyANCiAgc3R5bGU9IkNPTE9S +OiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNr +Q291bnQodGhpcyw4Mik7IA0KICBocmVmPSJodHRwOi8vYmxvZy5jc2RuLm5ldC9nbnVocGMvYXJj +aGl2ZS8yMDEwLzEyLzAzLzYwNTE4NjcuYXNweCIgDQogIHRhcmdldD1fYmxhbms+TGludXjnjq/l +ooPkuIvnmoRDL0MrK+WfuuehgOiwg+ivleaKgOacrzHigJTigJTliJ3mraXkuobop6M8L0E+PC9E +VD4NCiAgPERUIGNsYXNzPXRvcDQgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tH +Uk9VTkQtUE9TSVRJT046IDBweCAzcHg7IE9WRVJGTE9XLVk6IGhpZGRlbjsgUEFERElORy1MRUZU +OiAyNHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdl +cy9jc2RuaW5kZXhfcGljMzguZ2lmKTsgT1ZFUkZMT1ctWDogaGlkZGVuOyBQQURESU5HLUJPVFRP +TTogMXB4OyBNQVJHSU46IDBweDsgV0lEVEg6IDIxMHB4OyBQQURESU5HLVRPUDogNHB4OyBXSElU +RS1TUEFDRTogbm93cmFwOyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1j +bGlwOiBpbml0aWFsIj48QSANCiAgdGl0bGU9MjAxMOW5tO+8jExpbnV45aSn5LqL6K6wIHN0eWxl +PSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1M +b2dDbGlja0NvdW50KHRoaXMsODIpOyANCiAgaHJlZj0iaHR0cDovL2Jsb2cuY3Nkbi5uZXQveXVh +bm1lbmcwMDEvYXJjaGl2ZS8yMDEwLzEyLzAxLzYwNDY4MjYuYXNweCIgDQogIHRhcmdldD1fYmxh +bms+MjAxMOW5tO+8jExpbnV45aSn5LqL6K6wPC9BPjwvRFQ+DQogIDxEVCBjbGFzcz10b3A1IA0K +ICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAwcHggM3B4 +OyBPVkVSRkxPVy1ZOiBoaWRkZW47IFBBRERJTkctTEVGVDogMjRweDsgQkFDS0dST1VORC1JTUFH +RTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzM5LmdpZik7 +IE9WRVJGTE9XLVg6IGhpZGRlbjsgUEFERElORy1CT1RUT006IDFweDsgTUFSR0lOOiAwcHg7IFdJ +RFRIOiAyMTBweDsgUEFERElORy1UT1A6IDRweDsgV0hJVEUtU1BBQ0U6IG5vd3JhcDsgYmFja2dy +b3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRp +dGxlPeW+geWPi+WQr+S6i+ato+aWhyBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVD +T1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDgyKTsgDQogIGhy +ZWY9Imh0dHA6Ly9ibG9nLmNzZG4ubmV0L3hpYW94aWFveXVuZHVvL2FyY2hpdmUvMjAxMC8xMi8w +Mi82MDUxMzY1LmFzcHgiIA0KICB0YXJnZXQ9X2JsYW5rPuW+geWPi+WQr+S6i+ato+aWhzwvQT48 +L0RUPg0KICA8RFQgY2xhc3M9dG9wNiANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFD +S0dST1VORC1QT1NJVElPTjogMHB4IDNweDsgT1ZFUkZMT1ctWTogaGlkZGVuOyBQQURESU5HLUxF +RlQ6IDI0cHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1h +Z2VzL2NzZG5pbmRleF9waWM0MC5naWYpOyBPVkVSRkxPVy1YOiBoaWRkZW47IFBBRERJTkctQk9U +VE9NOiAxcHg7IE1BUkdJTjogMHB4OyBXSURUSDogMjEwcHg7IFBBRERJTkctVE9QOiA0cHg7IFdI +SVRFLVNQQUNFOiBub3dyYXA7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5k +LWNsaXA6IGluaXRpYWwiPjxBIA0KICB0aXRsZT0ibG9hZHJ1bm5lcuS4rSB0aGlua3RpbWUg5aaC +5L2V6L+Q55So6ZqP5py65pe26Ze077yM5bm26KaB5oqK5pe26Ze05a6a5Zyo5q+r56eS57qnIiAN +CiAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBv +bmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw4Mik7IA0KICBocmVmPSJodHRwOi8vYmxvZy5jc2Ru +Lm5ldC9uYW1lc2xpdS9hcmNoaXZlLzIwMTAvMTEvMzAvNjA0NDI5NS5hc3B4IiANCiAgdGFyZ2V0 +PV9ibGFuaz5sb2FkcnVubmVy5LitIHRoaW5rdGltZSDlpoLkvZXov5DnlKjpmo/mnLrml7bpl7Tv +vIzlubbopoHmiorml7bpl7TlrprlnKjmr6vnp5Lnuqc8L0E+PC9EVD4NCiAgPERUIGNsYXNzPXRv +cDcgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDBw +eCAzcHg7IE9WRVJGTE9XLVk6IGhpZGRlbjsgUEFERElORy1MRUZUOiAyNHB4OyBCQUNLR1JPVU5E +LUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljNDEu +Z2lmKTsgT1ZFUkZMT1ctWDogaGlkZGVuOyBQQURESU5HLUJPVFRPTTogMXB4OyBNQVJHSU46IDBw +eDsgV0lEVEg6IDIxMHB4OyBQQURESU5HLVRPUDogNHB4OyBXSElURS1TUEFDRTogbm93cmFwOyBi +YWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSAN +CiAgdGl0bGU9ImxpbnV4IOS4i+WPlui/m+eoi+WNoOeUqCBjcHUv5YaF5a2YIOacgOmrmOeahOWJ +jTEw5Liq6L+b56iLIiANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJ +T046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw4Mik7IA0KICBocmVmPSJo +dHRwOi8vYmxvZy5jc2RuLm5ldC9uYW1lc2xpdS9hcmNoaXZlLzIwMTAvMTEvMjYvNjAzNzk3Mi5h +c3B4IiANCiAgdGFyZ2V0PV9ibGFuaz5saW51eCDkuIvlj5bov5vnqIvljaDnlKggY3B1L+WGheWt +mCDmnIDpq5jnmoTliY0xMOS4qui/m+eoizwvQT48L0RUPg0KICA8RFQgY2xhc3M9dG9wOCANCiAg +c3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMHB4IDNweDsg +T1ZFUkZMT1ctWTogaGlkZGVuOyBQQURESU5HLUxFRlQ6IDI0cHg7IEJBQ0tHUk9VTkQtSU1BR0U6 +IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWM0Mi5naWYpOyBP +VkVSRkxPVy1YOiBoaWRkZW47IFBBRERJTkctQk9UVE9NOiAxcHg7IE1BUkdJTjogMHB4OyBXSURU +SDogMjEwcHg7IFBBRERJTkctVE9QOiA0cHg7IFdISVRFLVNQQUNFOiBub3dyYXA7IGJhY2tncm91 +bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0aXRs +ZT1qYXZh55+l6K+G54K55aaC5L2V5Liy5o6lIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVY +VC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsODIpOyAN +CiAgaHJlZj0iaHR0cDovL2Jsb2cuY3Nkbi5uZXQvYml0ZmFuL2FyY2hpdmUvMjAxMC8xMi8wMy82 +MDUyMzEwLmFzcHgiIA0KICB0YXJnZXQ9X2JsYW5rPmphdmHnn6Xor4bngrnlpoLkvZXkuLLmjqU8 +L0E+PC9EVD4NCiAgPERUIGNsYXNzPXRvcDkgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7 +IEJBQ0tHUk9VTkQtUE9TSVRJT046IDBweCAzcHg7IE9WRVJGTE9XLVk6IGhpZGRlbjsgUEFERElO +Ry1MRUZUOiAyNHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3 +L2ltYWdlcy9jc2RuaW5kZXhfcGljNDMuZ2lmKTsgT1ZFUkZMT1ctWDogaGlkZGVuOyBQQURESU5H +LUJPVFRPTTogMXB4OyBNQVJHSU46IDBweDsgV0lEVEg6IDIxMHB4OyBQQURESU5HLVRPUDogNHB4 +OyBXSElURS1TUEFDRTogbm93cmFwOyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dy +b3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgdGl0bGU95qKm5oOz5Y2B5bm0LS3jgIrnqIvluo/l +kZjjgIvljYHlubTmhJ/mg7Mgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJ +T046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw4Mik7IA0KICBocmVmPSJo +dHRwOi8vYmxvZy5jc2RuLm5ldC9qaWFuZ3Rhby9hcmNoaXZlLzIwMTAvMTEvMTgvNjAxODU2NC5h +c3B4IiANCiAgdGFyZ2V0PV9ibGFuaz7moqbmg7PljYHlubQtLeOAiueoi+W6j+WRmOOAi+WNgeW5 +tOaEn+aDszwvQT48L0RUPg0KICA8RFQgY2xhc3M9dG9wMTAgDQogIHN0eWxlPSJQQURESU5HLVJJ +R0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDBweCAzcHg7IE9WRVJGTE9XLVk6IGhpZGRl +bjsgUEFERElORy1MRUZUOiAyNHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5p +bWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljNDQuZ2lmKTsgT1ZFUkZMT1ctWDogaGlkZGVu +OyBQQURESU5HLUJPVFRPTTogMXB4OyBNQVJHSU46IDBweDsgV0lEVEg6IDIxMHB4OyBQQURESU5H +LVRPUDogNHB4OyBXSElURS1TUEFDRTogbm93cmFwOyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlh +bDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgdGl0bGU95oiR5Lus5Li65LuA5LmI +5LiN5Zac5qyi5oub6IGY5Z+56K6t5a2m5qCh55qE5a2m55Sf77yfIHN0eWxlPSJDT0xPUjogcmdi +KDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50 +KHRoaXMsODIpOyANCiAgaHJlZj0iaHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2hnYW93ZWkvYXJjaGl2 +ZS8yMDEwLzExLzE2LzYwMTM1NTQuYXNweCIgDQogIHRhcmdldD1fYmxhbms+5oiR5Lus5Li65LuA +5LmI5LiN5Zac5qyi5oub6IGY5Z+56K6t5a2m5qCh55qE5a2m55Sf77yfPC9BPjwvRFQ+PC9ETD48 +L0RJVj48L0RJVj48L0RJVj4NCjxESVYgY2xhc3M9cGFnZWNvbl9sYXllcjJidG0gDQpzdHlsZT0i +QkFDS0dST1VORC1QT1NJVElPTjogNTAlIDEwMCU7IEZPTlQtU0laRTogMXB4OyBGTE9BVDogbGVm +dDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3Nk +bmluZGV4X3BpYzQ1LmdpZik7IFdJRFRIOiA5NjBweDsgSEVJR0hUOiAxcHg7IGJhY2tncm91bmQt +b3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjwvRElWPg0KPERJVj4N +CjxESVYgY2xhc3M9YnVzaW5lc3NhZCANCnN0eWxlPSJGTE9BVDogbGVmdDsgTUFSR0lOOiA0cHgg +MHB4IDBweDsgV0lEVEg6IDk2MHB4OyBQT1NJVElPTjogcmVsYXRpdmU7IFRFWFQtQUxJR046IGxl +ZnQiPg0KPFVMIA0Kc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgUEFERElORy1MRUZUOiAwcHg7 +IEZMT0FUOiBsZWZ0OyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweDsgV0lEVEg6IDk2 +MHB4OyBQQURESU5HLVRPUDogMHB4OyBMSVNULVNUWUxFLVRZUEU6IG5vbmUiPg0KICA8TEkgY2xh +c3M9bGVmdGFkIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBQQURESU5HLUxFRlQ6IDBw +eDsgRkxPQVQ6IGxlZnQ7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBXSURUSDog +NzM1cHg7IFBBRERJTkctVE9QOiAwcHgiPjxBIA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7 +IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIGhyZWY9Imh0dHA6Ly96LmNzZG4ubmV0L2dtY2xp +Y2sucGhwP2Jhbm5lcmlkPTU0MjUmYW1wO3pvbmVpZD00MDkmYW1wO3NvdXJjZT0mYW1wO2Rlc3Q9 +aHR0cCUzQSUyRiUyRnd3dy5jaGluYS1wdWIuY29tJTJGU1RBVElDMDclMkYxMDA5JTJGanNqX3Fo +d29yeDFfMTAwOTA5LmFzcCIgDQogIHRhcmdldD1fYmxhbms+PElNRyB0aXRsZT0iIiANCiAgc3R5 +bGU9IkJPUkRFUi1UT1AtV0lEVEg6IDBweDsgQk9SREVSLUxFRlQtV0lEVEg6IDBweDsgQk9SREVS +LUJPVFRPTS1XSURUSDogMHB4OyBCT1JERVItUklHSFQtV0lEVEg6IDBweCIgDQogIGhlaWdodD05 +MCBhbHQ9IiIgDQogIHNyYz0iaHR0cDovL2luZm8tZGF0YWJhc2UuY3Nkbi5uZXQvVXBsb2FkLzIw +MTAtMTItMDkvNzM1XzkwXzEyMDkuanBnIiANCiAgd2lkdGg9NzM1IGJvcmRlcj0wPjwvQT4NCiAg +PERJViBpZD1iZWFjb25fNTQyNSANCiAgc3R5bGU9IkxFRlQ6IDBweDsgVklTSUJJTElUWTogaGlk +ZGVuOyBQT1NJVElPTjogYWJzb2x1dGU7IFRPUDogMHB4Ij48SU1HIA0KICBzdHlsZT0iQk9SREVS +LVRPUC1XSURUSDogMHB4OyBCT1JERVItTEVGVC1XSURUSDogMHB4OyBCT1JERVItQk9UVE9NLVdJ +RFRIOiAwcHg7IFdJRFRIOiAwcHg7IEhFSUdIVDogMHB4OyBCT1JERVItUklHSFQtV0lEVEg6IDBw +eCIgDQogIGhlaWdodD0wIGFsdD0iIiANCiAgc3JjPSJodHRwOi8vei5jc2RuLm5ldC9nbWxvZy5w +aHA/YmFubmVyaWQ9NTQyNSZhbXA7Y2xpZW50aWQ9MTcwNyZhbXA7emY9JmFtcDt6b25laWQ9NDA5 +JmFtcDtzb3VyY2U9JmFtcDtibG9jaz0wJmFtcDtjYXBwaW5nPTAmYW1wO2NiPTQ0ZWVmNTM5NmYw +ZjZlNGQ4NTRhYzlhODg0YzI2ZDhlIiANCiAgd2lkdGg9MD48L0RJVj48L0xJPg0KICA8TEkgY2xh +c3M9cmlnaHRhZCANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgUEFERElORy1MRUZUOiAw +cHg7IEZMT0FUOiByaWdodDsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IFdJRFRI +OiAyMTBweDsgUEFERElORy1UT1A6IDBweCI+PEEgDQogIHN0eWxlPSJDT0xPUjogcmdiKDAsMCww +KTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgaHJlZj0iaHR0cDovL3ouY3Nkbi5uZXQvZ21j +bGljay5waHA/YmFubmVyaWQ9NTI3MSZhbXA7em9uZWlkPTQxMCZhbXA7c291cmNlPSZhbXA7ZGVz +dD1odHRwJTNBJTJGJTJGZGluZ3l1ZS5wcm9ncmFtbWVyLmNvbS5jbiUyRiIgDQogIHRhcmdldD1f +Ymxhbms+PElNRyB0aXRsZT0iIiANCiAgc3R5bGU9IkJPUkRFUi1UT1AtV0lEVEg6IDBweDsgQk9S +REVSLUxFRlQtV0lEVEg6IDBweDsgQk9SREVSLUJPVFRPTS1XSURUSDogMHB4OyBCT1JERVItUklH +SFQtV0lEVEg6IDBweCIgDQogIGhlaWdodD05MCBhbHQ9IiIgDQogIHNyYz0iaHR0cDovL2luZm8t +ZGF0YWJhc2UuY3Nkbi5uZXQvVXBsb2FkLzIwMTAtMTAtMjkvMjEwXzkwemhlbmdkaW5nbmV3Lmpw +ZyIgDQogIHdpZHRoPTIxMCBib3JkZXI9MD48L0E+DQogIDxESVYgaWQ9YmVhY29uXzUyNzEgDQog +IHN0eWxlPSJMRUZUOiAwcHg7IFZJU0lCSUxJVFk6IGhpZGRlbjsgUE9TSVRJT046IGFic29sdXRl +OyBUT1A6IDBweCI+PElNRyANCiAgc3R5bGU9IkJPUkRFUi1UT1AtV0lEVEg6IDBweDsgQk9SREVS +LUxFRlQtV0lEVEg6IDBweDsgQk9SREVSLUJPVFRPTS1XSURUSDogMHB4OyBXSURUSDogMHB4OyBI +RUlHSFQ6IDBweDsgQk9SREVSLVJJR0hULVdJRFRIOiAwcHgiIA0KICBoZWlnaHQ9MCBhbHQ9IiIg +DQogIHNyYz0iaHR0cDovL3ouY3Nkbi5uZXQvZ21sb2cucGhwP2Jhbm5lcmlkPTUyNzEmYW1wO2Ns +aWVudGlkPTE1MTgmYW1wO3pmPSZhbXA7em9uZWlkPTQxMCZhbXA7c291cmNlPSZhbXA7YmxvY2s9 +MCZhbXA7Y2FwcGluZz0wJmFtcDtjYj1kOTE4ZjQwZTJiODM1YjllMDZmODVjZmY0YjhjMGQ5YiIg +DQogIHdpZHRoPTA+PC9ESVY+PC9MST48L1VMPjwvRElWPjwvRElWPg0KPERJViBjbGFzcz1wYWdl +Y29uX2xheWVyMiANCnN0eWxlPSJGTE9BVDogbGVmdDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0 +dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzMzLmdpZik7IE1BUkdJTjog +M3B4IDBweCAwcHg7IFdJRFRIOiA5NjBweDsgUE9TSVRJT046IHJlbGF0aXZlOyBURVhULUFMSUdO +OiBsZWZ0OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0 +aWFsIj4NCjxESVYgY2xhc3M9cGFnZV8wOXNpZGViYXJ3cmFwIA0Kc3R5bGU9IlBBRERJTkctUklH +SFQ6IDBweDsgQk9SREVSLVRPUDogcmdiKDIwNCwyMDQsMjA0KSAxcHggc29saWQ7IERJU1BMQVk6 +IGlubGluZTsgUEFERElORy1MRUZUOiAwcHg7IEZMT0FUOiByaWdodDsgUEFERElORy1CT1RUT006 +IDZweDsgTUFSR0lOOiAwcHggMXB4IDBweCAwcHg7IFdJRFRIOiAyMDhweDsgUEFERElORy1UT1A6 +IDBweDsgVEVYVC1BTElHTjogbGVmdCI+DQo8RElWIGNsYXNzPXNpZGViYXJfY29uIA0Kc3R5bGU9 +IkRJU1BMQVk6IGlubGluZTsgRkxPQVQ6IGxlZnQ7IE1BUkdJTjogNnB4IDNweCAycHg7IFdJRFRI +OiAyMDJweCI+DQo8SDQgY2xhc3M9dHh0XzEyIA0Kc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsg +UEFERElORy1MRUZUOiAzcHg7IEZPTlQtU0laRTogMTJweDsgUEFERElORy1CT1RUT006IDVweDsg +TUFSR0lOOiAwcHg7IFBBRERJTkctVE9QOiAwcHg7IEJPUkRFUi1CT1RUT006IHJnYigyMDQsMjA0 +LDIwNCkgMXB4IHNvbGlkOyBQT1NJVElPTjogcmVsYXRpdmUiPjxTUEFOIA0KY2xhc3M9dHh0X2dy +YXkgDQpzdHlsZT0iRk9OVC1XRUlHSFQ6IG5vcm1hbDsgRkxPQVQ6IHJpZ2h0OyBDT0xPUjogcmdi +KDEwMiwxMDIsMTAyKSI+fDxBIA0Kc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgUEFERElORy1M +RUZUOiA1cHg7IFBBRERJTkctQk9UVE9NOiAwcHg7IENPTE9SOiByZ2IoMTAyLDEwMiwxMDIpOyBQ +QURESU5HLVRPUDogMHB4OyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KaHJlZj0iaHR0cDovL3d3 +dy5kZWFyYm9vay5jb20uY24vIiB0YXJnZXQ9X2JsYW5rPuabtOWkmjwvQT48L1NQQU4+5Zu+5Lmm +5o6S6KGM5qacPC9IND4NCjxESVYgY2xhc3M9Ym9va3NfdGFiIA0Kc3R5bGU9IlBBRERJTkctUklH +SFQ6IDBweDsgRElTUExBWTogaW5saW5lOyBQQURESU5HLUxFRlQ6IDBweDsgRkxPQVQ6IGxlZnQ7 +IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBXSURUSDogMjAycHg7IFBBRERJTkct +VE9QOiAwcHgiPg0KPFVMIA0Kc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgUEFERElORy1MRUZU +OiAwcHg7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMnB4IDBweCAwcHg7IFBBRERJTkct +VE9QOiAwcHg7IExJU1QtU1RZTEUtVFlQRTogbm9uZSI+DQogIDxMSSBpZD1tYWluMiANCiAgc3R5 +bGU9IlBBRERJTkctUklHSFQ6IDBweDsgUEFERElORy1MRUZUOiAwcHg7IFBBRERJTkctQk9UVE9N +OiAwcHg7IE1BUkdJTjogMHB4OyBQQURESU5HLVRPUDogMHB4Ij4NCiAgPERJVj4NCiAgPERMIGNs +YXNzPWJvb2t0b3AgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAzcHg7IFBBRERJTkctTEVGVDog +M3B4OyBGTE9BVDogbGVmdDsgUEFERElORy1CT1RUT006IDVweDsgTUFSR0lOOiAycHggMHB4IDBw +eDsgV0lEVEg6IDE5NnB4OyBQQURESU5HLVRPUDogMTBweDsgQk9SREVSLUJPVFRPTTogcmdiKDIw +NCwyMDQsMjA0KSAxcHggc29saWQ7IEJBQ0tHUk9VTkQtQ09MT1I6IHJnYigyNTUsMjU1LDI1NSk7 +IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPg0K +ICAgIDxEVCBjbGFzcz10b3AxIA0KICAgIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tH +Uk9VTkQtUE9TSVRJT046IDBweCAzcHg7IE9WRVJGTE9XLVk6IGhpZGRlbjsgUEFERElORy1MRUZU +OiAyMXB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdl +cy9jc2RuaW5kZXhfcGljMzUuZ2lmKTsgT1ZFUkZMT1ctWDogaGlkZGVuOyBQQURESU5HLUJPVFRP +TTogM3B4OyBNQVJHSU46IDBweDsgV0lEVEg6IDE3MHB4OyBQQURESU5HLVRPUDogM3B4OyBXSElU +RS1TUEFDRTogbm93cmFwOyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1j +bGlwOiBpbml0aWFsIj48QSANCiAgICB0aXRsZT1IYWRvb3DmnYPlqIHmjIfljZfvvIjkuK3mlofn +iYjvvIkgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0K +ICAgIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDk3KTsgaHJlZj0iaHR0cDovL3d3dy5jaGlu +YS1wdWIuY29tLzE5NjIwMCIgDQogICAgdGFyZ2V0PV9ibGFuaz5IYWRvb3DmnYPlqIHmjIfljZfv +vIjkuK3mlofniYjvvIk8L0E+PC9EVD4NCiAgICA8RFQgY2xhc3M9dG9wMiANCiAgICBzdHlsZT0i +UEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAwcHggM3B4OyBPVkVSRkxP +Vy1ZOiBoaWRkZW47IFBBRERJTkctTEVGVDogMjFweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0 +dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzM2LmdpZik7IE9WRVJGTE9X +LVg6IGhpZGRlbjsgUEFERElORy1CT1RUT006IDNweDsgTUFSR0lOOiAwcHg7IFdJRFRIOiAxNzBw +eDsgUEFERElORy1UT1A6IDNweDsgV0hJVEUtU1BBQ0U6IG5vd3JhcDsgYmFja2dyb3VuZC1vcmln +aW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogICAgdGl0bGU9Iueo +i+W6j+WRmCgyMDEw5bm0MTLmnIjliIog5oC756ysMjE45pyfKSIgDQogICAgc3R5bGU9IkNPTE9S +OiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICAgIG9uY2xpY2s9TG9nQ2xp +Y2tDb3VudCh0aGlzLDk3KTsgaHJlZj0iaHR0cDovL3d3dy5jaGluYS1wdWIuY29tLzU0MTkxIiAN +CiAgICB0YXJnZXQ9X2JsYW5rPueoi+W6j+WRmCgyMDEw5bm0MTLmnIjliIog5oC756ysMjwvQT48 +L0RUPg0KICAgIDxEVCBjbGFzcz10b3AzIA0KICAgIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7 +IEJBQ0tHUk9VTkQtUE9TSVRJT046IDBweCAzcHg7IE9WRVJGTE9XLVk6IGhpZGRlbjsgUEFERElO +Ry1MRUZUOiAyMXB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3 +L2ltYWdlcy9jc2RuaW5kZXhfcGljMzcuZ2lmKTsgT1ZFUkZMT1ctWDogaGlkZGVuOyBQQURESU5H +LUJPVFRPTTogM3B4OyBNQVJHSU46IDBweDsgV0lEVEg6IDE3MHB4OyBQQURESU5HLVRPUDogM3B4 +OyBXSElURS1TUEFDRTogbm93cmFwOyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dy +b3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgICB0aXRsZT3kupLogZTnvZHov5DokKXmmbrmhafi +gJTpq5jlj6/nlKjlj6/mianlsZXnvZHnq5nmioDmnK/lrp7miJjvvIjpooTllK7pmLbmrrXniYjm +nYPljbPovpPlh7rlj7Dmub7vvIkgDQogICAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhU +LURFQ09SQVRJT046IG5vbmUiIA0KICAgIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDk3KTsg +aHJlZj0iaHR0cDovL3d3dy5jaGluYS1wdWIuY29tLzE5NzE5MyIgDQogICAgdGFyZ2V0PV9ibGFu +az7kupLogZTnvZHov5DokKXmmbrmhafigJTpq5jlj6/nlKjlj6/mianlsZXnvZHnq5nmioA8L0E+ +PC9EVD4NCiAgICA8RFQgY2xhc3M9dG9wNCANCiAgICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4 +OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAwcHggM3B4OyBPVkVSRkxPVy1ZOiBoaWRkZW47IFBBRERJ +TkctTEVGVDogMjFweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3 +dy9pbWFnZXMvY3NkbmluZGV4X3BpYzM4LmdpZik7IE9WRVJGTE9XLVg6IGhpZGRlbjsgUEFERElO +Ry1CT1RUT006IDNweDsgTUFSR0lOOiAwcHg7IFdJRFRIOiAxNzBweDsgUEFERElORy1UT1A6IDNw +eDsgV0hJVEUtU1BBQ0U6IG5vd3JhcDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tn +cm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogICAgdGl0bGU9TXlTUUzmioDmnK/lhoXluZU6SW5u +b0RC5a2Y5YKo5byV5pOOKOefpeWQjU15U1FM5pyN5Yqh5Y6C5ZWGUGVyY29uYeWFrOWPuENUT+S9 +nOW6jykgDQogICAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5v +bmUiIA0KICAgIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDk3KTsgaHJlZj0iaHR0cDovL3d3 +dy5jaGluYS1wdWIuY29tLzE5NzIyMCIgDQogICAgdGFyZ2V0PV9ibGFuaz5NeVNRTOaKgOacr+WG +heW5lTpJbm5vRELlrZg8L0E+PC9EVD4NCiAgICA8RFQgY2xhc3M9dG9wNSANCiAgICBzdHlsZT0i +UEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAwcHggM3B4OyBPVkVSRkxP +Vy1ZOiBoaWRkZW47IFBBRERJTkctTEVGVDogMjFweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0 +dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzM5LmdpZik7IE9WRVJGTE9X +LVg6IGhpZGRlbjsgUEFERElORy1CT1RUT006IDNweDsgTUFSR0lOOiAwcHg7IFdJRFRIOiAxNzBw +eDsgUEFERElORy1UT1A6IDNweDsgV0hJVEUtU1BBQ0U6IG5vd3JhcDsgYmFja2dyb3VuZC1vcmln +aW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogICAgdGl0bGU95aaC +5L2V566h55CG6L2v5Lu25LyB5LiaKOesrDLniYgpIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsg +VEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw5 +Nyk7IGhyZWY9Imh0dHA6Ly93d3cuY2hpbmEtcHViLmNvbS8xOTc0MDciIA0KICAgIHRhcmdldD1f +Ymxhbms+5aaC5L2V566h55CG6L2v5Lu25LyB5LiaKOesrDLniYgpPC9BPjwvRFQ+DQogICAgPERU +IGNsYXNzPXRvcDYgDQogICAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1Q +T1NJVElPTjogMHB4IDNweDsgT1ZFUkZMT1ctWTogaGlkZGVuOyBQQURESU5HLUxFRlQ6IDIxcHg7 +IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5p +bmRleF9waWM0MC5naWYpOyBPVkVSRkxPVy1YOiBoaWRkZW47IFBBRERJTkctQk9UVE9NOiAzcHg7 +IE1BUkdJTjogMHB4OyBXSURUSDogMTcwcHg7IFBBRERJTkctVE9QOiAzcHg7IFdISVRFLVNQQUNF +OiBub3dyYXA7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGlu +aXRpYWwiPjxBIA0KICAgIHRpdGxlPeeul+azleWvvOiuuu+8iOWOn+S5puesrDLniYjvvIkoMDnl +ubTluqbnlYXplIDmppxOTy4yKSgwOOW5tOW6pueVhemUgOamnE5PLjIpKOiiq+OAiueoi+W6j+WR +mOOAi+etieacuuaehOivhOmAieS4ujIwMDblubTmnIDlj5for7vogIXllpzniLHnmoTljYHlpKdJ +VOWbvuS5puS5i+S4gCkgDQogICAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09S +QVRJT046IG5vbmUiIA0KICAgIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDk3KTsgaHJlZj0i +aHR0cDovL3d3dy5jaGluYS1wdWIuY29tLzMxNzAxIiANCiAgICB0YXJnZXQ9X2JsYW5rPueul+az +leWvvOiuuu+8iOWOn+S5puesrDLniYjvvIkoMDnlubTluqbnlYU8L0E+PC9EVD4NCiAgICA8RFQg +Y2xhc3M9dG9wNyANCiAgICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBP +U0lUSU9OOiAwcHggM3B4OyBPVkVSRkxPVy1ZOiBoaWRkZW47IFBBRERJTkctTEVGVDogMjFweDsg +QkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3Nkbmlu +ZGV4X3BpYzQxLmdpZik7IE9WRVJGTE9XLVg6IGhpZGRlbjsgUEFERElORy1CT1RUT006IDNweDsg +TUFSR0lOOiAwcHg7IFdJRFRIOiAxNzBweDsgUEFERElORy1UT1A6IDNweDsgV0hJVEUtU1BBQ0U6 +IG5vd3JhcDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5p +dGlhbCI+PEEgDQogICAgdGl0bGU95rex5YWl55CG6Kej6K6h566X5py657O757ufKOWOn+S5pues +rDLniYgpKOS4iuW4guS4gOWRqO+8jOmUgOmHj+i/h+WNgykgDQogICAgc3R5bGU9IkNPTE9SOiBy +Z2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICAgIG9uY2xpY2s9TG9nQ2xpY2tD +b3VudCh0aGlzLDk3KTsgaHJlZj0iaHR0cDovL3d3dy5jaGluYS1wdWIuY29tLzE5NzE2NyIgDQog +ICAgdGFyZ2V0PV9ibGFuaz7mt7HlhaXnkIbop6PorqHnrpfmnLrns7vnu58o5Y6f5Lmm56ysMueJ +iCkoPC9BPjwvRFQ+DQogICAgPERUIGNsYXNzPXRvcDggDQogICAgc3R5bGU9IlBBRERJTkctUklH +SFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMHB4IDNweDsgT1ZFUkZMT1ctWTogaGlkZGVu +OyBQQURESU5HLUxFRlQ6IDIxcHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3Nkbmlt +Zy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWM0Mi5naWYpOyBPVkVSRkxPVy1YOiBoaWRkZW47 +IFBBRERJTkctQk9UVE9NOiAzcHg7IE1BUkdJTjogMHB4OyBXSURUSDogMTcwcHg7IFBBRERJTkct +VE9QOiAzcHg7IFdISVRFLVNQQUNFOiBub3dyYXA7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFs +OyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICAgIHRpdGxlPVNFT+WunuaImOWvhueg +geKAlDYw5aSp572R56uZ5rWB6YeP5o+Q6auYMjDlgI0gc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDAp +OyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICAgIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlz +LDk3KTsgaHJlZj0iaHR0cDovL3d3dy5jaGluYS1wdWIuY29tLzE5NzIwMCIgDQogICAgdGFyZ2V0 +PV9ibGFuaz5TRU/lrp7miJjlr4bnoIHigJQ2MOWkqee9keermea1gemHj+aPkOmrmDwvQT48L0RU +Pg0KICAgIDxEVCBjbGFzcz10b3A5IA0KICAgIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJB +Q0tHUk9VTkQtUE9TSVRJT046IDBweCAzcHg7IE9WRVJGTE9XLVk6IGhpZGRlbjsgUEFERElORy1M +RUZUOiAyMXB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2lt +YWdlcy9jc2RuaW5kZXhfcGljNDMuZ2lmKTsgT1ZFUkZMT1ctWDogaGlkZGVuOyBQQURESU5HLUJP +VFRPTTogM3B4OyBNQVJHSU46IDBweDsgV0lEVEg6IDE3MHB4OyBQQURESU5HLVRPUDogM3B4OyBX +SElURS1TUEFDRTogbm93cmFwOyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3Vu +ZC1jbGlwOiBpbml0aWFsIj48QSANCiAgICB0aXRsZT0iSFRNTCA155So5oi35oyH5Y2XKOWPjOiJ +suWNsOWIt++8jOWtpuS5oOWSjOaOjOaPoeacgOaWsFdlYuW8gOWPkeaKgOacr0hUTUwgNSkiIA0K +ICAgIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAg +ICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw5Nyk7IGhyZWY9Imh0dHA6Ly93d3cuY2hpbmEt +cHViLmNvbS8xOTcxNzYiIA0KICAgIHRhcmdldD1fYmxhbms+SFRNTCA155So5oi35oyH5Y2XKOWP +jOiJsuWNsOWIt++8jOWtpjwvQT48L0RUPg0KICAgIDxEVCBjbGFzcz10b3AxMCANCiAgICBzdHls +ZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAwcHggM3B4OyBPVkVS +RkxPVy1ZOiBoaWRkZW47IFBBRERJTkctTEVGVDogMjFweDsgQkFDS0dST1VORC1JTUFHRTogdXJs +KGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzQ0LmdpZik7IE9WRVJG +TE9XLVg6IGhpZGRlbjsgUEFERElORy1CT1RUT006IDNweDsgTUFSR0lOOiAwcHg7IFdJRFRIOiAx +NzBweDsgUEFERElORy1UT1A6IDNweDsgV0hJVEUtU1BBQ0U6IG5vd3JhcDsgYmFja2dyb3VuZC1v +cmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogICAgdGl0bGU9 +SmF2Yee8lueoi+aAneaDsyjnrKw054mIKSjnu4/lhbjlm77kuabmnIDmlrDniYjmnKwpKDA55bm0 +5bqm55WF6ZSA5qacVE9QNTApKDA45bm05bqm55WF6ZSA5qacTk8uOCkgDQogICAgc3R5bGU9IkNP +TE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICAgIG9uY2xpY2s9TG9n +Q2xpY2tDb3VudCh0aGlzLDk3KTsgaHJlZj0iaHR0cDovL3d3dy5jaGluYS1wdWIuY29tLzM0ODM4 +IiANCiAgICB0YXJnZXQ9X2JsYW5rPkphdmHnvJbnqIvmgJ3mg7Mo56ysNOeJiCko57uP5YW45Zu+ +PC9BPjwvRFQ+PC9ETD48L0RJVj48L0xJPjwvVUw+PC9ESVY+DQo8REwgY2xhc3M9c2Vzc2lvbl9z +dHlsZSANCnN0eWxlPSJQQURESU5HLVJJR0hUOiAzcHg7IFBBRERJTkctTEVGVDogM3B4OyBGTE9B +VDogbGVmdDsgUEFERElORy1CT1RUT006IDVweDsgTUFSR0lOOiAycHggMHB4IDBweDsgV0lEVEg6 +IDE5NnB4OyBQQURESU5HLVRPUDogMTBweDsgQk9SREVSLUJPVFRPTTogcmdiKDIwNCwyMDQsMjA0 +KSAxcHggc29saWQ7IEJBQ0tHUk9VTkQtQ09MT1I6IHJnYigyNTUsMjU1LDI1NSk7IGJhY2tncm91 +bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPg0KICA8RFQgY2xh +c3M9ImJvb2t0aXQgdHh0X2JsdWUiIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBQQURE +SU5HLUxFRlQ6IDBweDsgRkxPQVQ6IG5vbmU7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjog +M3B4IDBweDsgQ09MT1I6IHJnYigxLDk1LDE4Mik7IFBBRERJTkctVE9QOiAwcHgiPjxBIA0KICB0 +aXRsZT3omZrmi5/onJznvZDvvJrku47lg7XlsLjnvZHnu5zov73ouKrliLDlhaXkvrXmo4DmtYsg +c3R5bGU9IkNPTE9SOiByZ2IoMSw5NSwxODIpOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBv +bmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw5OCk7IA0KICBocmVmPSJodHRwOi8vY2xvdWQuY3Nk +bi5uZXQvYS8yMDEwLzEyMTQvMjgzNjE2Lmh0bWwiIA0KICB0YXJnZXQ9X2JsYW5rPuiZmuaLn+ic +nOe9kO+8muS7juWDteWwuOe9kee7nOi/vei4quWIsOWFpeS+tTwvQT48L0RUPg0KICA8RFQgDQog +IHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IFBBRERJTkctTEVGVDogMHB4OyBQQURESU5HLUJP +VFRPTTogMHB4OyBNQVJHSU46IDBweCAwcHggOXB4OyBQQURESU5HLVRPUDogMHB4Ij48SU1HIA0K +ICB0aXRsZT0iIiANCiAgc3R5bGU9IkJPUkRFUi1SSUdIVDogcmdiKDIwNCwyMDQsMjA0KSAxcHgg +c29saWQ7IFBBRERJTkctUklHSFQ6IDJweDsgQk9SREVSLVRPUDogcmdiKDIwNCwyMDQsMjA0KSAx +cHggc29saWQ7IFBBRERJTkctTEVGVDogMnB4OyBGTE9BVDogbGVmdDsgUEFERElORy1CT1RUT006 +IDJweDsgTUFSR0lOOiAwcHggNnB4IDBweCAwcHg7IEJPUkRFUi1MRUZUOiByZ2IoMjA0LDIwNCwy +MDQpIDFweCBzb2xpZDsgUEFERElORy1UT1A6IDJweDsgQk9SREVSLUJPVFRPTTogcmdiKDIwNCwy +MDQsMjA0KSAxcHggc29saWQiIA0KICBoZWlnaHQ9NjggYWx0PSIiIA0KICBzcmM9Imh0dHA6Ly9h +cnRpY2xlcy5jc2RuLm5ldC91cGxvYWRzL2FsbGltZy8xMDEyMTQvNzlfMTMxMTIwMTE0MS5qcGci +IA0KICB3aWR0aD01Mj7pnaLlr7notormnaXotorlpI3mnYLnmoTpgIPpgb/mioDmnK/vvIzku6Xl +j4rph4fnlKjliqDlr4bmioDmnK/mnaXkv53miqTnvZHnu5zpgJrkv6HvvIzpmLLmraLooqvnqoPl +kKznmoTljY/orq7otormnaXotoouLi48L0RUPjwvREw+DQo8REwgY2xhc3M9c2Vzc2lvbl9zdHls +ZSANCnN0eWxlPSJQQURESU5HLVJJR0hUOiAzcHg7IFBBRERJTkctTEVGVDogM3B4OyBGTE9BVDog +bGVmdDsgUEFERElORy1CT1RUT006IDVweDsgTUFSR0lOOiAycHggMHB4IDBweDsgV0lEVEg6IDE5 +NnB4OyBQQURESU5HLVRPUDogMTBweDsgQk9SREVSLUJPVFRPTTogcmdiKDIwNCwyMDQsMjA0KSAx +cHggc29saWQ7IEJBQ0tHUk9VTkQtQ09MT1I6IHJnYigyNTUsMjU1LDI1NSk7IGJhY2tncm91bmQt +b3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPg0KICA8RFQgY2xhc3M9 +ImJvb2t0aXQgdHh0X2JsdWUiIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBQQURESU5H +LUxFRlQ6IDBweDsgRkxPQVQ6IG5vbmU7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogM3B4 +IDBweDsgQ09MT1I6IHJnYigxLDk1LDE4Mik7IFBBRERJTkctVE9QOiAwcHgiPjxBIA0KICB0aXRs +ZT1qQlBNNOW3peS9nOa1geW6lOeUqOW8gOWPkeaMh+WNlyBzdHlsZT0iQ09MT1I6IHJnYigxLDk1 +LDE4Mik7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0 +aGlzLDk4KTsgDQogIGhyZWY9Imh0dHA6Ly9qYXZhLmNzZG4ubmV0L2EvMjAxMDExMTIvMjgxOTE1 +Lmh0bWwiIA0KICB0YXJnZXQ9X2JsYW5rPmpCUE005bel5L2c5rWB5bqU55So5byA5Y+R5oyH5Y2X +PC9BPjwvRFQ+DQogIDxEVCANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgUEFERElORy1M +RUZUOiAwcHg7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4IDBweCA5cHg7IFBBRERJ +TkctVE9QOiAwcHgiPjxJTUcgDQogIHRpdGxlPSIiIA0KICBzdHlsZT0iQk9SREVSLVJJR0hUOiBy +Z2IoMjA0LDIwNCwyMDQpIDFweCBzb2xpZDsgUEFERElORy1SSUdIVDogMnB4OyBCT1JERVItVE9Q +OiByZ2IoMjA0LDIwNCwyMDQpIDFweCBzb2xpZDsgUEFERElORy1MRUZUOiAycHg7IEZMT0FUOiBs +ZWZ0OyBQQURESU5HLUJPVFRPTTogMnB4OyBNQVJHSU46IDBweCA2cHggMHB4IDBweDsgQk9SREVS +LUxFRlQ6IHJnYigyMDQsMjA0LDIwNCkgMXB4IHNvbGlkOyBQQURESU5HLVRPUDogMnB4OyBCT1JE +RVItQk9UVE9NOiByZ2IoMjA0LDIwNCwyMDQpIDFweCBzb2xpZCIgDQogIGhlaWdodD02OCBhbHQ9 +IiIgc3JjPSJodHRwOi8vaW1hZ2VzLmNzZG4ubmV0LzIwMTAxMTEyL2pCUE005bel5L2c5rWB5bqU +55So5byA5Y+R5oyH5Y2XLTMlMjAuanBnIiANCiAgd2lkdGg9NTI+5pys5Lmm5bCG5L2/5oKo5b+r +6YCf5LqG6Kej5LuA5LmI5piv5bel5L2c5rWB44CBQlBN5ZKMakJQTe+8jOS7peWPiuWug+S7rOea +hOWPkeWxleWOhueoi+OAguW9k+eEtu+8jOmHjeimgS4uLjwvRFQ+PC9ETD4NCjxETCBjbGFzcz1z +ZXNzaW9uX3N0eWxlIA0Kc3R5bGU9IlBBRERJTkctUklHSFQ6IDNweDsgUEFERElORy1MRUZUOiAz +cHg7IEZMT0FUOiBsZWZ0OyBQQURESU5HLUJPVFRPTTogNXB4OyBNQVJHSU46IDJweCAwcHggMHB4 +OyBXSURUSDogMTk2cHg7IFBBRERJTkctVE9QOiAxMHB4OyBCT1JERVItQk9UVE9NOiByZ2IoMjA0 +LDIwNCwyMDQpIDFweCBzb2xpZDsgQkFDS0dST1VORC1DT0xPUjogcmdiKDI1NSwyNTUsMjU1KTsg +YmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+DQog +IDxEVCBjbGFzcz0iYm9va3RpdCB0eHRfYmx1ZSIgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAw +cHg7IFBBRERJTkctTEVGVDogMHB4OyBGTE9BVDogbm9uZTsgUEFERElORy1CT1RUT006IDBweDsg +TUFSR0lOOiAzcHggMHB4OyBDT0xPUjogcmdiKDEsOTUsMTgyKTsgUEFERElORy1UT1A6IDBweCI+ +PEEgDQogIHRpdGxlPUxpbnV46YKj5Lqb5LqL5YS/IHN0eWxlPSJDT0xPUjogcmdiKDEsOTUsMTgy +KTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMs +OTgpOyANCiAgaHJlZj0iaHR0cDovL2phdmEuY3Nkbi5uZXQvYS8yMDEwMDgxMi8yNzgxMTcuaHRt +bCIgDQogIHRhcmdldD1fYmxhbms+TGludXjpgqPkupvkuovlhL88L0E+PC9EVD4NCiAgPERUIA0K +ICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBQQURESU5HLUxFRlQ6IDBweDsgUEFERElORy1C +T1RUT006IDBweDsgTUFSR0lOOiAwcHggMHB4IDlweDsgUEFERElORy1UT1A6IDBweCI+PElNRyAN +CiAgdGl0bGU9IiIgDQogIHN0eWxlPSJCT1JERVItUklHSFQ6IHJnYigyMDQsMjA0LDIwNCkgMXB4 +IHNvbGlkOyBQQURESU5HLVJJR0hUOiAycHg7IEJPUkRFUi1UT1A6IHJnYigyMDQsMjA0LDIwNCkg +MXB4IHNvbGlkOyBQQURESU5HLUxFRlQ6IDJweDsgRkxPQVQ6IGxlZnQ7IFBBRERJTkctQk9UVE9N +OiAycHg7IE1BUkdJTjogMHB4IDZweCAwcHggMHB4OyBCT1JERVItTEVGVDogcmdiKDIwNCwyMDQs +MjA0KSAxcHggc29saWQ7IFBBRERJTkctVE9QOiAycHg7IEJPUkRFUi1CT1RUT006IHJnYigyMDQs +MjA0LDIwNCkgMXB4IHNvbGlkIiANCiAgaGVpZ2h0PTY4IGFsdD0iIiBzcmM9Imh0dHA6Ly9pbWFn +ZXMuY3Nkbi5uZXQvMjAxMDA4MTIvTGludXjpgqPkupvkuovlhL8tMi5qcGciIA0KICB3aWR0aD01 +Mj7mnKzkuabln7rkuo4yLjYuMjLlhoXmoLjvvIzlr7lVU0LlrZDns7vnu5/nmoTlpKfpg6jliIbm +upDku6PnoIHpgJDooYzov5vooYzliIbmnpDvvIzns7vnu5/lnLDpmJDph4rkuoYuLi48L0RUPjwv +REw+PC9ESVY+PC9ESVY+DQo8RElWIGNsYXNzPXBhZ2VibG9jazJfd3JhcCBzdHlsZT0iRkxPQVQ6 +IGxlZnQ7IFdJRFRIOiA3MzVweCI+DQo8RElWIGNsYXNzPXBhZ2Vjb25fbGF5ZXIyX2xlZnQgDQpz +dHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBESVNQTEFZOiBpbmxpbmU7IFBBRERJTkctTEVGVDog +MHB4OyBGTE9BVDogbGVmdDsgUEFERElORy1CT1RUT006IDVweDsgTUFSR0lOOiAwcHggMHB4IDBw +eCAxcHg7IFdJRFRIOiA0NzBweDsgUEFERElORy1UT1A6IDBweCI+DQo8SDYgDQpzdHlsZT0iQ0xF +QVI6IGJvdGg7IFBBRERJTkctUklHSFQ6IDBweDsgQk9SREVSLVRPUDogcmdiKDIwNCwyMDQsMjA0 +KSAxcHggc29saWQ7IFBBRERJTkctTEVGVDogMTBweDsgRk9OVC1TSVpFOiAxNHB4OyBCQUNLR1JP +VU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGlj +MTEuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IFBBRERJTkctVE9QOiA1 +cHg7IFBPU0lUSU9OOiByZWxhdGl2ZTsgSEVJR0hUOiAyOXB4OyBiYWNrZ3JvdW5kLW9yaWdpbjog +aW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj7npL7ljLo8RU0gDQpjbGFzcz10eHRf +Ymx1ZSANCnN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDBw +eCA0cHg7IFBBRERJTkctTEVGVDogMTBweDsgRk9OVC1XRUlHSFQ6IG5vcm1hbDsgRk9OVC1TSVpF +OiAxMnB4OyBMRUZUOiA0MTBweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1n +LmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzEyLmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7 +IENPTE9SOiByZ2IoMSw5NSwxODIpOyBQQURESU5HLVRPUDogMHB4OyBGT05ULVNUWUxFOiBub3Jt +YWw7IFBPU0lUSU9OOiBhYnNvbHV0ZTsgVE9QOiA2cHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0 +aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0Kc3R5bGU9IlBBRERJTkctUklHSFQ6 +IDNweDsgUEFERElORy1MRUZUOiAzcHg7IFBBRERJTkctQk9UVE9NOiAwcHg7IENPTE9SOiByZ2Io +MSw5NSwxODIpOyBQQURESU5HLVRPUDogMHB4OyBURVhULURFQ09SQVRJT046IHVuZGVybGluZSIg +DQpocmVmPSJodHRwOi8vYmJzLmNzZG4ubmV0LyIgdGFyZ2V0PV9ibGFuaz7mm7TlpJo8L0E+PC9F +TT48L0g2Pg0KPERJViBjbGFzcz1wYWdlY29uX2xheWVyMl9sZWZ0Y29uIA0Kc3R5bGU9IlBBRERJ +TkctUklHSFQ6IDEwcHg7IFBBRERJTkctTEVGVDogMTBweDsgRkxPQVQ6IGxlZnQ7IFBBRERJTkct +Qk9UVE9NOiA1cHg7IFdJRFRIOiA0NTBweDsgUEFERElORy1UT1A6IDVweCI+DQo8REwgDQpzdHls +ZT0iUEFERElORy1SSUdIVDogMHB4OyBQQURESU5HLUxFRlQ6IDBweDsgUEFERElORy1CT1RUT006 +IDJweDsgTUFSR0lOOiAzcHggMHB4OyBMSU5FLUhFSUdIVDogMjFweDsgUEFERElORy1UT1A6IDBw +eDsgUE9TSVRJT046IHJlbGF0aXZlIj4NCiAgPERUIGNsYXNzPXR4dF9ibGFjayANCiAgc3R5bGU9 +IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMHB4IDhweDsgUEFERElO +Ry1MRUZUOiAxMHB4OyBGT05ULVNJWkU6IDE0cHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRw +Oi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMyNi5naWYpOyBQQURESU5HLUJP +VFRPTTogMHB4OyBNQVJHSU46IDNweCAwcHg7IENPTE9SOiByZ2IoMCwwLDApOyBQQURESU5HLVRP +UDogMHB4OyBQT1NJVElPTjogcmVsYXRpdmU7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBi +YWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxDSVRFIA0KICBjbGFzcz0idHh0X2JsdWUgdHh0XzEy +IiANCiAgc3R5bGU9IkZPTlQtU0laRTogMTJweDsgRkxPQVQ6IHJpZ2h0OyBDT0xPUjogcmdiKDEs +OTUsMTgyKTsgRk9OVC1TVFlMRTogbm9ybWFsIj48QSANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMSw5 +NSwxODIpOyBURVhULURFQ09SQVRJT046IHVuZGVybGluZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tD +b3VudCh0aGlzLDg0KTsgaHJlZj0iaHR0cDovL2hpLmNzZG4ubmV0L0NTRE4iIA0KICB0YXJnZXQ9 +X2JsYW5rPkNTRE48L0E+PC9DSVRFPjxBIHRpdGxlPeaKgOacr+ebm+WutFNEMi4w5aSn5Lya5ZyG +5ruh57uT5p2fIA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjog +bm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDg0KTsgDQogIGhyZWY9Imh0dHA6 +Ly90b3BpYy5jc2RuLm5ldC91LzIwMTAxMjA5LzA5L2QwODAxZjZhLTczZjQtNDI2ZC04OGZiLThk +NzJiOTNiNTQ5OS5odG1sIiANCiAgdGFyZ2V0PV9ibGFuaz7mioDmnK/nm5vlrrRTRDIuMOWkp+S8 +muWchua7oee7k+adnzwvQT48L0RUPg0KICA8RFQgY2xhc3M9dHh0X2JsYWNrIA0KICBzdHlsZT0i +UEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAwcHggOHB4OyBQQURESU5H +LUxFRlQ6IDEwcHg7IEZPTlQtU0laRTogMTRweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6 +Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzI2LmdpZik7IFBBRERJTkctQk9U +VE9NOiAwcHg7IE1BUkdJTjogM3B4IDBweDsgQ09MT1I6IHJnYigwLDAsMCk7IFBBRERJTkctVE9Q +OiAwcHg7IFBPU0lUSU9OOiByZWxhdGl2ZTsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJh +Y2tncm91bmQtY2xpcDogaW5pdGlhbCI+PENJVEUgDQogIGNsYXNzPSJ0eHRfYmx1ZSB0eHRfMTIi +IA0KICBzdHlsZT0iRk9OVC1TSVpFOiAxMnB4OyBGTE9BVDogcmlnaHQ7IENPTE9SOiByZ2IoMSw5 +NSwxODIpOyBGT05ULVNUWUxFOiBub3JtYWwiPjxBIA0KICBzdHlsZT0iQ09MT1I6IHJnYigxLDk1 +LDE4Mik7IFRFWFQtREVDT1JBVElPTjogdW5kZXJsaW5lIiANCiAgb25jbGljaz1Mb2dDbGlja0Nv +dW50KHRoaXMsODQpOyBocmVmPSJodHRwOi8vaGkuY3Nkbi5uZXQvanY5IiANCiAgdGFyZ2V0PV9i +bGFuaz5qdjk8L0E+PC9DSVRFPjxBIHRpdGxlPSJTaWx2ZXJsaWdodC9XUEYvV1A35LiA5ZGo5a2m +5Lmg5a+86K+7KDEy5pyINi0xMuaciDEyKSAiIA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7 +IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDg0 +KTsgDQogIGhyZWY9Imh0dHA6Ly90b3BpYy5jc2RuLm5ldC91LzIwMTAxMjEzLzE0L0M2Nzg0OTI5 +LTJCQTUtNDNEQS04QjIzLTBDMURDNjhFNEJEOC5odG1sIiANCiAgdGFyZ2V0PV9ibGFuaz5TaWx2 +ZXJsaWdodC9XUEYvV1A35LiA5ZGo5a2m5Lmg5a+86K+7KDEy5pyINi0xMuaciDEyKTwvQT48L0RU +Pg0KICA8RFQgY2xhc3M9dHh0X2JsYWNrIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBC +QUNLR1JPVU5ELVBPU0lUSU9OOiAwcHggOHB4OyBQQURESU5HLUxFRlQ6IDEwcHg7IEZPTlQtU0la +RTogMTRweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFn +ZXMvY3NkbmluZGV4X3BpYzI2LmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogM3B4 +IDBweDsgQ09MT1I6IHJnYigwLDAsMCk7IFBBRERJTkctVE9QOiAwcHg7IFBPU0lUSU9OOiByZWxh +dGl2ZTsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlh +bCI+PENJVEUgDQogIGNsYXNzPSJ0eHRfYmx1ZSB0eHRfMTIiIA0KICBzdHlsZT0iRk9OVC1TSVpF +OiAxMnB4OyBGTE9BVDogcmlnaHQ7IENPTE9SOiByZ2IoMSw5NSwxODIpOyBGT05ULVNUWUxFOiBu +b3JtYWwiPjxBIA0KICBzdHlsZT0iQ09MT1I6IHJnYigxLDk1LDE4Mik7IFRFWFQtREVDT1JBVElP +TjogdW5kZXJsaW5lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsODQpOyBocmVmPSJo +dHRwOi8vaGkuY3Nkbi5uZXQvZ3VndWRhMjAwOCIgDQogIHRhcmdldD1fYmxhbms+Z3VndWRhMjAw +ODwvQT48L0NJVEU+PEEgdGl0bGU95oqKVEVNUERC5pS+5Yiw5YaF5a2Y6YeMIA0KICBzdHlsZT0i +Q09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9n +Q2xpY2tDb3VudCh0aGlzLDg0KTsgDQogIGhyZWY9Imh0dHA6Ly90b3BpYy5jc2RuLm5ldC91LzIw +MTAxMjEzLzEzL0YxRDFEMTg5LUU1NzItNEY0Qy1CODZBLTI3NkFGMkZBM0E2RC5odG1sIiANCiAg +dGFyZ2V0PV9ibGFuaz7miopURU1QRELmlL7liLDlhoXlrZjph4w8L0E+PC9EVD4NCiAgPERUIGNs +YXNzPXR4dF9ibGFjayANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1Q +T1NJVElPTjogMHB4IDhweDsgUEFERElORy1MRUZUOiAxMHB4OyBGT05ULVNJWkU6IDE0cHg7IEJB +Q0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRl +eF9waWMyNi5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDNweCAwcHg7IENPTE9S +OiByZ2IoMCwwLDApOyBQQURESU5HLVRPUDogMHB4OyBQT1NJVElPTjogcmVsYXRpdmU7IGJhY2tn +cm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxDSVRFIA0K +ICBjbGFzcz0idHh0X2JsdWUgdHh0XzEyIiANCiAgc3R5bGU9IkZPTlQtU0laRTogMTJweDsgRkxP +QVQ6IHJpZ2h0OyBDT0xPUjogcmdiKDEsOTUsMTgyKTsgRk9OVC1TVFlMRTogbm9ybWFsIj48QSAN +CiAgc3R5bGU9IkNPTE9SOiByZ2IoMSw5NSwxODIpOyBURVhULURFQ09SQVRJT046IHVuZGVybGlu +ZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDg0KTsgaHJlZj0iaHR0cDovL2hpLmNz +ZG4ubmV0L2ludmFsaWRhdGUwMDExIiANCiAgdGFyZ2V0PV9ibGFuaz5pbnZhbGlkYXRlMDAxMTwv +QT48L0NJVEU+PEEgDQogIHRpdGxlPSLlj6bnsbvoo4XppbDkvaDnmoRXaW5mb3JtIC0g5Zyo56qX +5Y+j55qE5bem5LiK6KeS5Yqg5LiA5Liq5Zyj6K+e5bi9IiANCiAgc3R5bGU9IkNPTE9SOiByZ2Io +MCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQo +dGhpcyw4NCk7IA0KICBocmVmPSJodHRwOi8vdG9waWMuY3Nkbi5uZXQvdS8yMDEwMTIxMy8xMC9G +RjE3MUQwMi0xRThELTQyQTAtQUE1RC1CQUFEMTIyQjc3QUMuaHRtbCIgDQogIHRhcmdldD1fYmxh +bms+5Y+m57G76KOF6aWw5L2g55qEV2luZm9ybSAtIOWcqOeql+WPo+eahOW3puS4iuinkuWKoOS4 +gOS4quWco+ivnuW4vTwvQT48L0RUPg0KICA8RFQgY2xhc3M9dHh0X2JsYWNrIA0KICBzdHlsZT0i +UEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAwcHggOHB4OyBQQURESU5H +LUxFRlQ6IDEwcHg7IEZPTlQtU0laRTogMTRweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6 +Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzI2LmdpZik7IFBBRERJTkctQk9U +VE9NOiAwcHg7IE1BUkdJTjogM3B4IDBweDsgQ09MT1I6IHJnYigwLDAsMCk7IFBBRERJTkctVE9Q +OiAwcHg7IFBPU0lUSU9OOiByZWxhdGl2ZTsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJh +Y2tncm91bmQtY2xpcDogaW5pdGlhbCI+PENJVEUgDQogIGNsYXNzPSJ0eHRfYmx1ZSB0eHRfMTIi +IA0KICBzdHlsZT0iRk9OVC1TSVpFOiAxMnB4OyBGTE9BVDogcmlnaHQ7IENPTE9SOiByZ2IoMSw5 +NSwxODIpOyBGT05ULVNUWUxFOiBub3JtYWwiPjxBIA0KICBzdHlsZT0iQ09MT1I6IHJnYigxLDk1 +LDE4Mik7IFRFWFQtREVDT1JBVElPTjogdW5kZXJsaW5lIiANCiAgb25jbGljaz1Mb2dDbGlja0Nv +dW50KHRoaXMsODQpOyBocmVmPSJodHRwOi8vaGkuY3Nkbi5uZXQvemN0eW1qeCIgDQogIHRhcmdl +dD1fYmxhbms+emN0eW1qeDwvQT48L0NJVEU+PEEgdGl0bGU9IldpbkNFIDYuMCDpqbHliqjlvIDl +j5HjgIHlhoXmoLjlrprliLbmlrnpnaLnmoTkuabkuLvopoHmnInpgqPkupvvvJ8iIA0KICBzdHls +ZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9 +TG9nQ2xpY2tDb3VudCh0aGlzLDg0KTsgDQogIGhyZWY9Imh0dHA6Ly90b3BpYy5jc2RuLm5ldC91 +LzIwMTAxMjEyLzE2LzFFNUNCNzAzLTk1QzYtNDYyNS1CQTNCLTFCNjkzQUQwMkI5MS5odG1sIiAN +CiAgdGFyZ2V0PV9ibGFuaz5XaW5DRSA2LjAg6amx5Yqo5byA5Y+R44CB5YaF5qC45a6a5Yi25pa5 +6Z2i55qE5Lmm5Li76KaB5pyJ6YKj5Lqb77yfPC9BPjwvRFQ+DQogIDxEVCBjbGFzcz10eHRfYmxh +Y2sgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDBw +eCA4cHg7IFBBRERJTkctTEVGVDogMTBweDsgRk9OVC1TSVpFOiAxNHB4OyBCQUNLR1JPVU5ELUlN +QUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMjYuZ2lm +KTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAzcHggMHB4OyBDT0xPUjogcmdiKDAsMCww +KTsgUEFERElORy1UT1A6IDBweDsgUE9TSVRJT046IHJlbGF0aXZlOyBiYWNrZ3JvdW5kLW9yaWdp +bjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48Q0lURSANCiAgY2xhc3M9InR4 +dF9ibHVlIHR4dF8xMiIgDQogIHN0eWxlPSJGT05ULVNJWkU6IDEycHg7IEZMT0FUOiByaWdodDsg +Q09MT1I6IHJnYigxLDk1LDE4Mik7IEZPTlQtU1RZTEU6IG5vcm1hbCI+PEEgDQogIHN0eWxlPSJD +T0xPUjogcmdiKDEsOTUsMTgyKTsgVEVYVC1ERUNPUkFUSU9OOiB1bmRlcmxpbmUiIA0KICBvbmNs +aWNrPUxvZ0NsaWNrQ291bnQodGhpcyw4NCk7IGhyZWY9Imh0dHA6Ly9oaS5jc2RuLm5ldC9waWdn +MTgiIA0KICB0YXJnZXQ9X2JsYW5rPnBpZ2cxODwvQT48L0NJVEU+PEEgdGl0bGU9IndpbmRvd3Mg +eHAg5ZKM6Jma5ouf5py655qE5Zuw5oORICAgeWVhaCIgDQogIHN0eWxlPSJDT0xPUjogcmdiKDAs +MCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRo +aXMsODQpOyANCiAgaHJlZj0iaHR0cDovL3RvcGljLmNzZG4ubmV0L3UvMjAxMDEyMDgvMTYvN0Q2 +RUQ3RDEtNDg2RS00MjgxLUE2RjktNzJFMTk5Rjg0NDgyLmh0bWwiIA0KICB0YXJnZXQ9X2JsYW5r +PndpbmRvd3MgeHAg5ZKM6Jma5ouf5py655qE5Zuw5oORIHllYWg8L0E+PC9EVD4NCiAgPERUIGNs +YXNzPXR4dF9ibGFjayANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1Q +T1NJVElPTjogMHB4IDhweDsgUEFERElORy1MRUZUOiAxMHB4OyBGT05ULVNJWkU6IDE0cHg7IEJB +Q0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRl +eF9waWMyNi5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDNweCAwcHg7IENPTE9S +OiByZ2IoMCwwLDApOyBQQURESU5HLVRPUDogMHB4OyBQT1NJVElPTjogcmVsYXRpdmU7IGJhY2tn +cm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxDSVRFIA0K +ICBjbGFzcz0idHh0X2JsdWUgdHh0XzEyIiANCiAgc3R5bGU9IkZPTlQtU0laRTogMTJweDsgRkxP +QVQ6IHJpZ2h0OyBDT0xPUjogcmdiKDEsOTUsMTgyKTsgRk9OVC1TVFlMRTogbm9ybWFsIj48QSAN +CiAgc3R5bGU9IkNPTE9SOiByZ2IoMSw5NSwxODIpOyBURVhULURFQ09SQVRJT046IHVuZGVybGlu +ZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDg0KTsgaHJlZj0iaHR0cDovL2hpLmNz +ZG4ubmV0L09uZU9uY2UiIA0KICB0YXJnZXQ9X2JsYW5rPk9uZU9uY2U8L0E+PC9DSVRFPjxBIHRp +dGxlPSLkv67mlLlpLk1YNTE1IEVCT09U5aSn5bCPIiANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCww +LDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhp +cyw4NCk7IA0KICBocmVmPSJodHRwOi8vdG9waWMuY3Nkbi5uZXQvdS8yMDEwMTIxMC8xNC8yODZE +QUE1RC0yMTUyLTQ1QzItQTQ3Qy1FQkE5NzNCODYwRkIuaHRtbCIgDQogIHRhcmdldD1fYmxhbms+ +5L+u5pS5aS5NWDUxNSBFQk9PVOWkp+WwjzwvQT48L0RUPg0KICA8RFQgY2xhc3M9dHh0X2JsYWNr +IA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAwcHgg +OHB4OyBQQURESU5HLUxFRlQ6IDEwcHg7IEZPTlQtU0laRTogMTRweDsgQkFDS0dST1VORC1JTUFH +RTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzI2LmdpZik7 +IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogM3B4IDBweDsgQ09MT1I6IHJnYigwLDAsMCk7 +IFBBRERJTkctVE9QOiAwcHg7IFBPU0lUSU9OOiByZWxhdGl2ZTsgYmFja2dyb3VuZC1vcmlnaW46 +IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PENJVEUgDQogIGNsYXNzPSJ0eHRf +Ymx1ZSB0eHRfMTIiIA0KICBzdHlsZT0iRk9OVC1TSVpFOiAxMnB4OyBGTE9BVDogcmlnaHQ7IENP +TE9SOiByZ2IoMSw5NSwxODIpOyBGT05ULVNUWUxFOiBub3JtYWwiPjxBIA0KICBzdHlsZT0iQ09M +T1I6IHJnYigxLDk1LDE4Mik7IFRFWFQtREVDT1JBVElPTjogdW5kZXJsaW5lIiANCiAgb25jbGlj +az1Mb2dDbGlja0NvdW50KHRoaXMsODQpOyBocmVmPSJodHRwOi8vaGkuY3Nkbi5uZXQvbHlzZXJ2 +ZXIiIA0KICB0YXJnZXQ9X2JsYW5rPmx5c2VydmVyPC9BPjwvQ0lURT48QSB0aXRsZT3orqnkurrn +uqDnu5PnmoTkuInlsYLmnrbmnoQgDQogIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1E +RUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsODQpOyANCiAg +aHJlZj0iaHR0cDovL3RvcGljLmNzZG4ubmV0L3UvMjAxMDEyMTAvMTEvREY4RUNBOEYtRUM2QS00 +RjNFLUEzOTItRThDMzFGRTg3RkE4Lmh0bWwiIA0KICB0YXJnZXQ9X2JsYW5rPuiuqeS6uue6oOe7 +k+eahOS4ieWxguaetuaehDwvQT48L0RUPg0KICA8RFQgY2xhc3M9dHh0X2JsYWNrIA0KICBzdHls +ZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAwcHggOHB4OyBQQURE +SU5HLUxFRlQ6IDEwcHg7IEZPTlQtU0laRTogMTRweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0 +dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzI2LmdpZik7IFBBRERJTkct +Qk9UVE9NOiAwcHg7IE1BUkdJTjogM3B4IDBweDsgQ09MT1I6IHJnYigwLDAsMCk7IFBBRERJTkct +VE9QOiAwcHg7IFBPU0lUSU9OOiByZWxhdGl2ZTsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7 +IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PENJVEUgDQogIGNsYXNzPSJ0eHRfYmx1ZSB0eHRf +MTIiIA0KICBzdHlsZT0iRk9OVC1TSVpFOiAxMnB4OyBGTE9BVDogcmlnaHQ7IENPTE9SOiByZ2Io +MSw5NSwxODIpOyBGT05ULVNUWUxFOiBub3JtYWwiPjxBIA0KICBzdHlsZT0iQ09MT1I6IHJnYigx +LDk1LDE4Mik7IFRFWFQtREVDT1JBVElPTjogdW5kZXJsaW5lIiANCiAgb25jbGljaz1Mb2dDbGlj +a0NvdW50KHRoaXMsODQpOyBocmVmPSJodHRwOi8vaGkuY3Nkbi5uZXQvcWl4aW5naGFpdGFuZzEy +MyIgDQogIHRhcmdldD1fYmxhbms+cWl4aW5naGFpdGFuZzEyMzwvQT48L0NJVEU+PEEgdGl0bGU9 +5b+F6K+777ya5aaC5L2V5oiQ5Li65LiA5ZCN5LyY56eA55qEQW5kcm9pZOW8gOWPkeiAhSANCiAg +c3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNs +aWNrPUxvZ0NsaWNrQ291bnQodGhpcyw4NCk7IA0KICBocmVmPSJodHRwOi8vdG9waWMuY3Nkbi5u +ZXQvdS8yMDEwMTIwOS8xNS9FMzAxQTRDRC0zRDM2LTRFNEItOTgwOS0xNTVGNDlEQjlDNDguaHRt +bCIgDQogIHRhcmdldD1fYmxhbms+5b+F6K+777ya5aaC5L2V5oiQ5Li65LiA5ZCN5LyY56eA55qE +QW5kcm9pZOW8gOWPkeiAhTwvQT48L0RUPg0KICA8REQgY2xhc3M9bmV3c190eXBlYSANCiAgc3R5 +bGU9IlBBRERJTkctUklHSFQ6IDBweDsgUEFERElORy1MRUZUOiAwcHg7IEJBQ0tHUk9VTkQtSU1B +R0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWM0Ni5naWYp +OyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IC0zcHggMHB4IDEwcHg7IFBBRERJTkctVE9Q +OiAwcHg7IFBPU0lUSU9OOiByZWxhdGl2ZTsgSEVJR0hUOiAxOXB4OyBiYWNrZ3JvdW5kLW9yaWdp +bjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48REZOIA0KICBzdHlsZT0iTEVG +VDogMzg5cHg7IENPTE9SOiByZ2IoMjU1LDI1NSwyNTUpOyBGT05ULVNUWUxFOiBub3JtYWw7IFBP +U0lUSU9OOiBhYnNvbHV0ZTsgVE9QOiAycHgiPuekvuWMuueyvuWNjjwvREZOPjwvREQ+DQogIDxE +VCBjbGFzcz10eHRfYmxhY2sgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9V +TkQtUE9TSVRJT046IDBweCA4cHg7IFBBRERJTkctTEVGVDogMTBweDsgRk9OVC1TSVpFOiAxNHB4 +OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2Ru +aW5kZXhfcGljMjYuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAzcHggMHB4OyBD +T0xPUjogcmdiKDAsMCwwKTsgUEFERElORy1UT1A6IDBweDsgUE9TSVRJT046IHJlbGF0aXZlOyBi +YWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48Q0lU +RSANCiAgY2xhc3M9InR4dF9ibHVlIHR4dF8xMiIgDQogIHN0eWxlPSJGT05ULVNJWkU6IDEycHg7 +IEZMT0FUOiByaWdodDsgQ09MT1I6IHJnYigxLDk1LDE4Mik7IEZPTlQtU1RZTEU6IG5vcm1hbCI+ +N+S6uuaUtuiXjzwvQ0lURT48QSANCiAgdGl0bGU9MTDnp43noLTpmaTnvZHpobXorr7orqHluIjp +mpznoo3nmoTlrp7nlKjmlrnms5Ugc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09S +QVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw4NSk7IA0KICBocmVm +PSJodHRwOi8vc2QuY3Nkbi5uZXQvYS8yMDEwMTIxMy8yODM0NzQuaHRtbCIgDQogIHRhcmdldD1f +Ymxhbms+MTDnp43noLTpmaTnvZHpobXorr7orqHluIjpmpznoo3nmoTlrp7nlKjmlrnms5U8L0E+ +PC9EVD4NCiAgPERUIGNsYXNzPXR4dF9ibGFjayANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBw +eDsgQkFDS0dST1VORC1QT1NJVElPTjogMHB4IDhweDsgUEFERElORy1MRUZUOiAxMHB4OyBGT05U +LVNJWkU6IDE0cHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cv +aW1hZ2VzL2NzZG5pbmRleF9waWMyNi5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46 +IDNweCAwcHg7IENPTE9SOiByZ2IoMCwwLDApOyBQQURESU5HLVRPUDogMHB4OyBQT1NJVElPTjog +cmVsYXRpdmU7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGlu +aXRpYWwiPjxDSVRFIA0KICBjbGFzcz0idHh0X2JsdWUgdHh0XzEyIiANCiAgc3R5bGU9IkZPTlQt +U0laRTogMTJweDsgRkxPQVQ6IHJpZ2h0OyBDT0xPUjogcmdiKDEsOTUsMTgyKTsgRk9OVC1TVFlM +RTogbm9ybWFsIj425Lq65pS26JePPC9DSVRFPjxBIA0KICB0aXRsZT1saW51eOe8lueoi+eahDEw +OOenjeWlh+a3q+W3p+iuoS0xMijlrZjlgqjorqHnrpcp57utIA0KICBzdHlsZT0iQ09MT1I6IHJn +YigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3Vu +dCh0aGlzLDg1KTsgDQogIGhyZWY9Imh0dHA6Ly9ibG9nLmNzZG4ubmV0L3Blbm55bGlhbmcvYXJj +aGl2ZS8yMDEwLzEyLzEwLzYwNjczMDcuYXNweCIgDQogIHRhcmdldD1fYmxhbms+bGludXjnvJbn +qIvnmoQxMDjnp43lpYfmt6vlt6forqEtMTIo5a2Y5YKo6K6h566XKee7rTwvQT48L0RUPg0KICA8 +RFQgY2xhc3M9dHh0X2JsYWNrIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JP +VU5ELVBPU0lUSU9OOiAwcHggOHB4OyBQQURESU5HLUxFRlQ6IDEwcHg7IEZPTlQtU0laRTogMTRw +eDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3Nk +bmluZGV4X3BpYzI2LmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogM3B4IDBweDsg +Q09MT1I6IHJnYigwLDAsMCk7IFBBRERJTkctVE9QOiAwcHg7IFBPU0lUSU9OOiByZWxhdGl2ZTsg +YmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PENJ +VEUgDQogIGNsYXNzPSJ0eHRfYmx1ZSB0eHRfMTIiIA0KICBzdHlsZT0iRk9OVC1TSVpFOiAxMnB4 +OyBGTE9BVDogcmlnaHQ7IENPTE9SOiByZ2IoMSw5NSwxODIpOyBGT05ULVNUWUxFOiBub3JtYWwi +PjTkurrmlLbol488L0NJVEU+PEEgDQogIHRpdGxlPeS4uuS7gOS5iOivtOS6keiuoeeul+aYr+en +u+WKqOeahOacquadpSBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjog +bm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDg1KTsgDQogIGhyZWY9Imh0dHA6 +Ly9tb2JpbGUuY3Nkbi5uZXQvbi8yMDEwMTIxMy8yODM0NzAuaHRtbCIgDQogIHRhcmdldD1fYmxh +bms+5Li65LuA5LmI6K+05LqR6K6h566X5piv56e75Yqo55qE5pyq5p2lPC9BPjwvRFQ+DQogIDxE +VCBjbGFzcz10eHRfYmxhY2sgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9V +TkQtUE9TSVRJT046IDBweCA4cHg7IFBBRERJTkctTEVGVDogMTBweDsgRk9OVC1TSVpFOiAxNHB4 +OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2Ru +aW5kZXhfcGljMjYuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAzcHggMHB4OyBD +T0xPUjogcmdiKDAsMCwwKTsgUEFERElORy1UT1A6IDBweDsgUE9TSVRJT046IHJlbGF0aXZlOyBi +YWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48Q0lU +RSANCiAgY2xhc3M9InR4dF9ibHVlIHR4dF8xMiIgDQogIHN0eWxlPSJGT05ULVNJWkU6IDEycHg7 +IEZMT0FUOiByaWdodDsgQ09MT1I6IHJnYigxLDk1LDE4Mik7IEZPTlQtU1RZTEU6IG5vcm1hbCI+ +MuS6uuaUtuiXjzwvQ0lURT48QSANCiAgdGl0bGU9MjAxMOW5tOa2iOi0ueeUteWtkOaKgOacrzIw +5Liq5pyA5aSn5aSx6LSl77yaQnV6euWxhemmliANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDAp +OyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw4 +NSk7IA0KICBocmVmPSJodHRwOi8vbmV3cy5jc2RuLm5ldC9hLzIwMTAxMjEzLzI4MzQ2NS5odG1s +IiANCiAgdGFyZ2V0PV9ibGFuaz4yMDEw5bm05raI6LS555S15a2Q5oqA5pyvMjDkuKrmnIDlpKfl +pLHotKXvvJpCdXp65bGF6aaWPC9BPjwvRFQ+DQogIDxEVCBjbGFzcz10eHRfYmxhY2sgDQogIHN0 +eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDBweCA4cHg7IFBB +RERJTkctTEVGVDogMTBweDsgRk9OVC1TSVpFOiAxNHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwo +aHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMjYuZ2lmKTsgUEFERElO +Ry1CT1RUT006IDBweDsgTUFSR0lOOiAzcHggMHB4OyBDT0xPUjogcmdiKDAsMCwwKTsgUEFERElO +Ry1UT1A6IDBweDsgUE9TSVRJT046IHJlbGF0aXZlOyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlh +bDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48Q0lURSANCiAgY2xhc3M9InR4dF9ibHVlIHR4 +dF8xMiIgDQogIHN0eWxlPSJGT05ULVNJWkU6IDEycHg7IEZMT0FUOiByaWdodDsgQ09MT1I6IHJn +YigxLDk1LDE4Mik7IEZPTlQtU1RZTEU6IG5vcm1hbCI+NeS6uuaUtuiXjzwvQ0lURT48QSANCiAg +dGl0bGU9IueUqEMgIOWGmUphdmEgU3R5bGXnqIvluo8iIHN0eWxlPSJDT0xPUjogcmdiKDAsMCww +KTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMs +ODUpOyANCiAgaHJlZj0iaHR0cDovL2Jsb2cuY3Nkbi5uZXQva2FiaW5pL2FyY2hpdmUvMjAxMC8x +Mi8wNS82MDU2NjEzLmFzcHgiIA0KICB0YXJnZXQ9X2JsYW5rPueUqEMg5YaZSmF2YSBTdHlsZeeo +i+W6jzwvQT48L0RUPg0KICA8RFQgY2xhc3M9dHh0X2JsYWNrIA0KICBzdHlsZT0iUEFERElORy1S +SUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAwcHggOHB4OyBQQURESU5HLUxFRlQ6IDEw +cHg7IEZPTlQtU0laRTogMTRweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1n +LmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzI2LmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7 +IE1BUkdJTjogM3B4IDBweDsgQ09MT1I6IHJnYigwLDAsMCk7IFBBRERJTkctVE9QOiAwcHg7IFBP +U0lUSU9OOiByZWxhdGl2ZTsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQt +Y2xpcDogaW5pdGlhbCI+PENJVEUgDQogIGNsYXNzPSJ0eHRfYmx1ZSB0eHRfMTIiIA0KICBzdHls +ZT0iRk9OVC1TSVpFOiAxMnB4OyBGTE9BVDogcmlnaHQ7IENPTE9SOiByZ2IoMSw5NSwxODIpOyBG +T05ULVNUWUxFOiBub3JtYWwiPjjkurrmlLbol488L0NJVEU+PEEgDQogIHRpdGxlPeiHqua1i+S4 +gOS4i+S9oOeahEphdmHmjozmj6HlvpfmgI7kuYjmoLfvvJ8gc3R5bGU9IkNPTE9SOiByZ2IoMCww +LDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhp +cyw4NSk7IA0KICBocmVmPSJodHRwOi8vYmxvZy5jc2RuLm5ldC9iaXRmYW4vYXJjaGl2ZS8yMDEw +LzEyLzEzLzYwNzI2OTAuYXNweCIgDQogIHRhcmdldD1fYmxhbms+6Ieq5rWL5LiA5LiL5L2g55qE +SmF2YeaOjOaPoeW+l+aAjuS5iOagt++8nzwvQT48L0RUPg0KICA8RFQgY2xhc3M9dHh0X2JsYWNr +IA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAwcHgg +OHB4OyBQQURESU5HLUxFRlQ6IDEwcHg7IEZPTlQtU0laRTogMTRweDsgQkFDS0dST1VORC1JTUFH +RTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzI2LmdpZik7 +IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogM3B4IDBweDsgQ09MT1I6IHJnYigwLDAsMCk7 +IFBBRERJTkctVE9QOiAwcHg7IFBPU0lUSU9OOiByZWxhdGl2ZTsgYmFja2dyb3VuZC1vcmlnaW46 +IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PENJVEUgDQogIGNsYXNzPSJ0eHRf +Ymx1ZSB0eHRfMTIiIA0KICBzdHlsZT0iRk9OVC1TSVpFOiAxMnB4OyBGTE9BVDogcmlnaHQ7IENP +TE9SOiByZ2IoMSw5NSwxODIpOyBGT05ULVNUWUxFOiBub3JtYWwiPjTkurrmlLbol488L0NJVEU+ +PEEgDQogIHRpdGxlPeWNjuS4uumdouivlemimOeul+S7gOS5iCzov5nkuKrog4zkvJrkuoblpJbk +vIHpmo/kvr/ov5sgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5v +bmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw4NSk7IA0KICBocmVmPSJodHRwOi8v +YmxvZy5jc2RuLm5ldC9saWppZXJzb244L2FyY2hpdmUvMjAxMC8xMC8yOC81OTcwODc0LmFzcHgi +IA0KICB0YXJnZXQ9X2JsYW5rPuWNjuS4uumdouivlemimOeul+S7gOS5iCzov5nkuKrog4zkvJrk +uoblpJbkvIHpmo/kvr/ov5s8L0E+PC9EVD4NCiAgPERUIGNsYXNzPXR4dF9ibGFjayANCiAgc3R5 +bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMHB4IDhweDsgUEFE +RElORy1MRUZUOiAxMHB4OyBGT05ULVNJWkU6IDE0cHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybCho +dHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMyNi5naWYpOyBQQURESU5H +LUJPVFRPTTogMHB4OyBNQVJHSU46IDNweCAwcHg7IENPTE9SOiByZ2IoMCwwLDApOyBQQURESU5H +LVRPUDogMHB4OyBQT1NJVElPTjogcmVsYXRpdmU7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFs +OyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxDSVRFIA0KICBjbGFzcz0idHh0X2JsdWUgdHh0 +XzEyIiANCiAgc3R5bGU9IkZPTlQtU0laRTogMTJweDsgRkxPQVQ6IHJpZ2h0OyBDT0xPUjogcmdi +KDEsOTUsMTgyKTsgRk9OVC1TVFlMRTogbm9ybWFsIj4z5Lq65pS26JePPC9DSVRFPjxBIA0KICB0 +aXRsZT3nqIvluo/lkZjvvJrnvJbnqIvnu5nkvaDnjrDlrp7nlJ/mtLvluKbmnaXkuoblk6rkupvl +nY/kuaDmg68gc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUi +IA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw4NSk7IA0KICBocmVmPSJodHRwOi8vYmxv +Zy5jc2RuLm5ldC9NYWNfY20vYXJjaGl2ZS8yMDEwLzExLzA5LzU5OTc0NzcuYXNweCIgDQogIHRh +cmdldD1fYmxhbms+56iL5bqP5ZGY77ya57yW56iL57uZ5L2g546w5a6e55Sf5rS75bim5p2l5LqG +5ZOq5Lqb5Z2P5Lmg5oOvPC9BPjwvRFQ+DQogIDxEVCBjbGFzcz10eHRfYmxhY2sgDQogIHN0eWxl +PSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDBweCA4cHg7IFBBRERJ +TkctTEVGVDogMTBweDsgRk9OVC1TSVpFOiAxNHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0 +cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMjYuZ2lmKTsgUEFERElORy1C +T1RUT006IDBweDsgTUFSR0lOOiAzcHggMHB4OyBDT0xPUjogcmdiKDAsMCwwKTsgUEFERElORy1U +T1A6IDBweDsgUE9TSVRJT046IHJlbGF0aXZlOyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsg +YmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48Q0lURSANCiAgY2xhc3M9InR4dF9ibHVlIHR4dF8x +MiIgDQogIHN0eWxlPSJGT05ULVNJWkU6IDEycHg7IEZMT0FUOiByaWdodDsgQ09MT1I6IHJnYigx +LDk1LDE4Mik7IEZPTlQtU1RZTEU6IG5vcm1hbCI+NeS6uuaUtuiXjzwvQ0lURT48QSANCiAgdGl0 +bGU957un5om/5LiO5re35ZCI77yM55Wl6LCI57O757uf55qE5p6E5bu65pa55byPIHN0eWxlPSJD +T0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dD +bGlja0NvdW50KHRoaXMsODUpOyANCiAgaHJlZj0iaHR0cDovL2Jsb2cuY3Nkbi5uZXQvYWltaW5n +b28vYXJjaGl2ZS8yMDEwLzEyLzA4LzYwNjI5OTcuYXNweCIgDQogIHRhcmdldD1fYmxhbms+57un +5om/5LiO5re35ZCI77yM55Wl6LCI57O757uf55qE5p6E5bu65pa55byPPC9BPjwvRFQ+DQogIDxE +RCBjbGFzcz1uZXdzX3R5cGVhIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBQQURESU5H +LUxFRlQ6IDBweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9p +bWFnZXMvY3NkbmluZGV4X3BpYzQ2LmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjog +LTNweCAwcHggMTBweDsgUEFERElORy1UT1A6IDBweDsgUE9TSVRJT046IHJlbGF0aXZlOyBIRUlH +SFQ6IDE5cHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGlu +aXRpYWwiPjxERk4gDQogIHN0eWxlPSJMRUZUOiAzODlweDsgQ09MT1I6IHJnYigyNTUsMjU1LDI1 +NSk7IEZPTlQtU1RZTEU6IG5vcm1hbDsgUE9TSVRJT046IGFic29sdXRlOyBUT1A6IDJweCI+5pyA +5paw572R5pGYPC9ERk4+PC9ERD4NCiAgPERUIGNsYXNzPXR4dF9ibGFjayANCiAgc3R5bGU9IlBB +RERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMHB4IDhweDsgUEFERElORy1M +RUZUOiAxMHB4OyBGT05ULVNJWkU6IDE0cHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8v +Y3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMyNi5naWYpOyBQQURESU5HLUJPVFRP +TTogMHB4OyBNQVJHSU46IDNweCAwcHg7IENPTE9SOiByZ2IoMCwwLDApOyBQQURESU5HLVRPUDog +MHB4OyBQT1NJVElPTjogcmVsYXRpdmU7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNr +Z3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0aXRsZT3jgJDlhazlkYrjgJFDU0RO6auY5qCh +5L+x5LmQ6YOo5Li75bit54Gr54Ot5oub5Yuf5LitIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsg +VEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsMTA3 +KTsgDQogIGhyZWY9Imh0dHA6Ly9zdHVkZW50LmNzZG4ubmV0L3NwYWNlLnBocD91aWQ9OTk2NDI2 +JmFtcDtkbz10aHJlYWQmYW1wO2lkPTM1Nzc4IiANCiAgdGFyZ2V0PV9ibGFuaz7jgJDlhazlkYrj +gJFDU0RO6auY5qCh5L+x5LmQ6YOo5Li75bit54Gr54Ot5oub5Yuf5LitPC9BPjwvRFQ+DQogIDxE +VCBjbGFzcz10eHRfYmxhY2sgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9V +TkQtUE9TSVRJT046IDBweCA4cHg7IFBBRERJTkctTEVGVDogMTBweDsgRk9OVC1TSVpFOiAxNHB4 +OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2Ru +aW5kZXhfcGljMjYuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAzcHggMHB4OyBD +T0xPUjogcmdiKDAsMCwwKTsgUEFERElORy1UT1A6IDBweDsgUE9TSVRJT046IHJlbGF0aXZlOyBi +YWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSAN +CiAgdGl0bGU944CQ5aSp5rSl44CR5aSp5rSl6IGM5Lia5aSn5a2mQ1NETumrmOagoeS/seS5kOmD +qOato+W8j+aIkOeriyBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjog +bm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDEwNyk7IA0KICBocmVmPSJodHRw +Oi8vc3R1ZGVudC5jc2RuLm5ldC9zcGFjZS5waHA/dWlkPTk5NjQyNiZhbXA7ZG89dGhyZWFkJmFt +cDtpZD00MDc4NSIgDQogIHRhcmdldD1fYmxhbms+44CQ5aSp5rSl44CR5aSp5rSl6IGM5Lia5aSn +5a2mQ1NETumrmOagoeS/seS5kOmDqOato+W8j+aIkOerizwvQT48L0RUPg0KICA8RFQgY2xhc3M9 +dHh0X2JsYWNrIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lU +SU9OOiAwcHggOHB4OyBQQURESU5HLUxFRlQ6IDEwcHg7IEZPTlQtU0laRTogMTRweDsgQkFDS0dS +T1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3Bp +YzI2LmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogM3B4IDBweDsgQ09MT1I6IHJn +YigwLDAsMCk7IFBBRERJTkctVE9QOiAwcHg7IFBPU0lUSU9OOiByZWxhdGl2ZTsgYmFja2dyb3Vu +ZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxl +PeOAkOmpu+mprOW6l+OAkem7hOa3ruWtpumZouesrOS4gOacn+WcqOe6v+iusuWgguaIkOWKn+S4 +vuWKniBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQog +IG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDEwNyk7IA0KICBocmVmPSJodHRwOi8vc3R1ZGVu +dC5jc2RuLm5ldC9zcGFjZS5waHA/dWlkPTk5NjQyNiZhbXA7ZG89dGhyZWFkJmFtcDtpZD00MDQ2 +MSIgDQogIHRhcmdldD1fYmxhbms+44CQ6am76ams5bqX44CR6buE5reu5a2m6Zmi56ys5LiA5pyf +5Zyo57q/6K6y5aCC5oiQ5Yqf5Li+5YqePC9BPjwvRFQ+DQogIDxEVCBjbGFzcz10eHRfYmxhY2sg +DQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDBweCA4 +cHg7IFBBRERJTkctTEVGVDogMTBweDsgRk9OVC1TSVpFOiAxNHB4OyBCQUNLR1JPVU5ELUlNQUdF +OiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMjYuZ2lmKTsg +UEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAzcHggMHB4OyBDT0xPUjogcmdiKDAsMCwwKTsg +UEFERElORy1UT1A6IDBweDsgUE9TSVRJT046IHJlbGF0aXZlOyBiYWNrZ3JvdW5kLW9yaWdpbjog +aW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgdGl0bGU944CQ5L+d5a6a +44CR5rKz6L2vQ1NETumrmOagoeS/seS5kOmDqOato+W8j+aIkOeriyBzdHlsZT0iQ09MT1I6IHJn +YigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3Vu +dCh0aGlzLDEwNyk7IA0KICBocmVmPSJodHRwOi8vc3R1ZGVudC5jc2RuLm5ldC9zcGFjZS5waHA/ +dWlkPTk5NjQyNiZhbXA7ZG89dGhyZWFkJmFtcDtpZD00MDI5OSIgDQogIHRhcmdldD1fYmxhbms+ +44CQ5L+d5a6a44CR5rKz6L2vQ1NETumrmOagoeS/seS5kOmDqOato+W8j+aIkOerizwvQT48L0RU +Pg0KICA8RFQgY2xhc3M9dHh0X2JsYWNrIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBC +QUNLR1JPVU5ELVBPU0lUSU9OOiAwcHggOHB4OyBQQURESU5HLUxFRlQ6IDEwcHg7IEZPTlQtU0la +RTogMTRweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFn +ZXMvY3NkbmluZGV4X3BpYzI2LmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogM3B4 +IDBweDsgQ09MT1I6IHJnYigwLDAsMCk7IFBBRERJTkctVE9QOiAwcHg7IFBPU0lUSU9OOiByZWxh +dGl2ZTsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlh +bCI+PEEgDQogIHRpdGxlPeOAkOS/neWumuOAkUNTRE7pq5jmoKHkv7HkuZDpg6jokL3miLfmsrPl +jJfph5Hono3lrabpmaIgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046 +IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcywxMDcpOyANCiAgaHJlZj0iaHR0 +cDovL3N0dWRlbnQuY3Nkbi5uZXQvc3BhY2UucGhwP3VpZD05OTY0MjYmYW1wO2RvPXRocmVhZCZh +bXA7aWQ9NDA1MDMiIA0KICB0YXJnZXQ9X2JsYW5rPuOAkOS/neWumuOAkUNTRE7pq5jmoKHkv7Hk +uZDpg6jokL3miLfmsrPljJfph5Hono3lrabpmaI8L0E+PC9EVD4NCiAgPEREIGNsYXNzPW5ld3Nf +dHlwZWEgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IFBBRERJTkctTEVGVDogMHB4OyBC +QUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5k +ZXhfcGljNDYuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAtM3B4IDBweCAxMHB4 +OyBQQURESU5HLVRPUDogMHB4OyBQT1NJVElPTjogcmVsYXRpdmU7IEhFSUdIVDogMTlweDsgYmFj +a2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PERGTiAN +CiAgc3R5bGU9IkxFRlQ6IDM4OXB4OyBDT0xPUjogcmdiKDI1NSwyNTUsMjU1KTsgRk9OVC1TVFlM +RTogbm9ybWFsOyBQT1NJVElPTjogYWJzb2x1dGU7IFRPUDogMnB4Ij7pq5jmoKFjbHViPC9ERk4+ +PC9ERD48L0RMPjwvRElWPjwvRElWPg0KPERJViBjbGFzcz1wYWdlY29uX2xheWVyMl9taWQgDQpz +dHlsZT0iQk9SREVSLVRPUDogcmdiKDIwNCwyMDQsMjA0KSAxcHggc29saWQ7IERJU1BMQVk6IGlu +bGluZTsgRkxPQVQ6IGxlZnQ7IE1BUkdJTjogMHB4IDBweCAwcHggNXB4OyBXSURUSDogMjU5cHg7 +IFRFWFQtQUxJR046IGxlZnQiPg0KPEgzIA0Kc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFD +S0dST1VORC1QT1NJVElPTjogMHB4IDBweDsgRElTUExBWTogaW5saW5lOyBQQURESU5HLUxFRlQ6 +IDIwcHg7IEZPTlQtU0laRTogMTRweDsgRkxPQVQ6IGxlZnQ7IEJBQ0tHUk9VTkQtSU1BR0U6IHVy +bChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMxNS5naWYpOyBQQURE +SU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweCAwcHggN3B4OyBXSURUSDogMjM5cHg7IExJTkUt +SEVJR0hUOiAzMHB4OyBQQURESU5HLVRPUDogMHB4OyBQT1NJVElPTjogcmVsYXRpdmU7IGJhY2tn +cm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxTUEFOIA0K +Y2xhc3M9InR4dF8xMiB0eHRfZ3JheSIgDQpzdHlsZT0iRk9OVC1XRUlHSFQ6IG5vcm1hbDsgRk9O +VC1TSVpFOiAxMnB4OyBGTE9BVDogcmlnaHQ7IE1BUkdJTjogMnB4IDdweCAwcHggMHB4OyBDT0xP +UjogcmdiKDEwMiwxMDIsMTAyKSI+PEEgDQpzdHlsZT0iQ09MT1I6IHJnYigxMDIsMTAyLDEwMik7 +IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQpocmVmPSJodHRwOi8vYmJzLmNzZG4ubmV0LyIgdGFy +Z2V0PV9ibGFuaz7mm7TlpJo8L0E+PC9TUEFOPuekvuWMuuS5i+aYnzwvSDM+DQo8REwgY2xhc3M9 +ZXhwZXJ0c2hvdyANCnN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJ +T046IDUwJSAxMDAlOyBESVNQTEFZOiBpbmxpbmU7IFBBRERJTkctTEVGVDogMHB4OyBGTE9BVDog +bGVmdDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMv +Y3NkbmluZGV4X3BpYzE0LmdpZik7IFBBRERJTkctQk9UVE9NOiAzcHg7IE1BUkdJTjogNnB4IDEw +cHggMHB4OyBXSURUSDogMjM5cHg7IFBBRERJTkctVE9QOiAwcHg7IGJhY2tncm91bmQtb3JpZ2lu +OiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPg0KICA8REQgY2xhc3M9cGljcyAN +CiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgUEFERElORy1MRUZUOiAwcHg7IEZMT0FUOiBs +ZWZ0OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9j +c2RuaW5kZXhfcGljNDcuZ2lmKTsgUEFERElORy1CT1RUT006IDNweDsgTUFSR0lOOiAwcHggNnB4 +IDBweCAwcHg7IFdJRFRIOiA5M3B4OyBQQURESU5HLVRPUDogMHB4OyBiYWNrZ3JvdW5kLW9yaWdp +bjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgdGl0bGU96JKL5pmf +77ya56S+5Yy65LiT5a62IHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9O +OiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsODcpOyBocmVmPSJodHRwOi8v +aGkuY3Nkbi5uZXQvamlhbmdzaGVuZyIgDQogIHRhcmdldD1fYmxhbms+PElNRyB0aXRsZT0iIiAN +CiAgc3R5bGU9IkJPUkRFUi1SSUdIVDogcmdiKDAsMCwwKSAxcHggc29saWQ7IEJPUkRFUi1UT1A6 +IHJnYigwLDAsMCkgMXB4IHNvbGlkOyBCT1JERVItTEVGVDogcmdiKDAsMCwwKSAxcHggc29saWQ7 +IFdJRFRIOiA4NnB4OyBCT1JERVItQk9UVE9NOiByZ2IoMCwwLDApIDFweCBzb2xpZDsgSEVJR0hU +OiA4NnB4IiANCiAgaGVpZ2h0PTg2IGFsdD0iIiBzcmM9Imh0dHA6Ly9hdmF0YXIucHJvZmlsZS5j +c2RuLm5ldC9GL0UvOC8xX2ppYW5nc2hlbmcuanBnIiANCiAgd2lkdGg9ODY+PC9BPjwvREQ+DQog +IDxERCBjbGFzcz10eHRfYmx1ZSANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgUEFERElO +Ry1MRUZUOiAwcHg7IFBBRERJTkctQk9UVE9NOiAzcHg7IE1BUkdJTjogMHB4OyBDT0xPUjogcmdi +KDEsOTUsMTgyKTsgUEFERElORy1UT1A6IDBweCI+PEEgDQogIHRpdGxlPeiSi+aZn++8muekvuWM +uuS4k+WutiBzdHlsZT0iQ09MT1I6IHJnYigxLDk1LDE4Mik7IFRFWFQtREVDT1JBVElPTjogbm9u +ZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDg3KTsgaHJlZj0iaHR0cDovL2hpLmNz +ZG4ubmV0L2ppYW5nc2hlbmciIA0KICB0YXJnZXQ9X2JsYW5rPuiSi+aZn++8muekvuWMuuS4k+Wu +tjwvQT48L0REPg0KICA8REQgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IFBBRERJTkct +TEVGVDogMHB4OyBQQURESU5HLUJPVFRPTTogM3B4OyBNQVJHSU46IDBweDsgUEFERElORy1UT1A6 +IDBweCI+Q1NETuWkp+eJiOS4uyzlvq7ova/mnIDmnInku7flgLzkuJPlrrbvvIzmk4Xplb8uTkVU +44CBQWN0aXZlWOOAgUFwcGxpY2F0aW9uPC9ERD4NCiAgPEREIGNsYXNzPSJhc2sgdHh0X2JsdWUi +IA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogNXB4OyBQQURESU5HLUxFRlQ6IDBweDsgRkxPQVQ6 +IHJpZ2h0OyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweDsgQ09MT1I6IHJnYigxLDk1 +LDE4Mik7IFBBRERJTkctVE9QOiAwcHgiPjxBIA0KICB0aXRsZT3okovmmZ/vvJrnpL7ljLrkuJPl +rrYgc3R5bGU9IkNPTE9SOiByZ2IoMSw5NSwxODIpOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0K +ICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw4Nyk7IGhyZWY9Imh0dHA6Ly9oaS5jc2RuLm5l +dC9qaWFuZ3NoZW5nIiANCiAgdGFyZ2V0PV9ibGFuaz7orr/pl67ku5bnmoTnqbrpl7Q8L0E+PC9E +RD48L0RMPg0KPEgzIA0Kc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJ +VElPTjogMHB4IDBweDsgRElTUExBWTogaW5saW5lOyBQQURESU5HLUxFRlQ6IDIwcHg7IEZPTlQt +U0laRTogMTRweDsgRkxPQVQ6IGxlZnQ7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3Nk +bmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMxNS5naWYpOyBQQURESU5HLUJPVFRPTTog +MHB4OyBNQVJHSU46IDBweCAwcHggN3B4OyBXSURUSDogMjM5cHg7IExJTkUtSEVJR0hUOiAzMHB4 +OyBQQURESU5HLVRPUDogMHB4OyBQT1NJVElPTjogcmVsYXRpdmU7IGJhY2tncm91bmQtb3JpZ2lu +OiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxTUEFOIA0KY2xhc3M9InR4dF8x +MiB0eHRfZ3JheSIgDQpzdHlsZT0iRk9OVC1XRUlHSFQ6IG5vcm1hbDsgRk9OVC1TSVpFOiAxMnB4 +OyBGTE9BVDogcmlnaHQ7IE1BUkdJTjogMnB4IDdweCAwcHggMHB4OyBDT0xPUjogcmdiKDEwMiwx +MDIsMTAyKSI+PEEgDQpzdHlsZT0iQ09MT1I6IHJnYigxMDIsMTAyLDEwMik7IFRFWFQtREVDT1JB +VElPTjogbm9uZSIgDQpocmVmPSJodHRwOi8vYmJzLmNzZG4ubmV0LyIgdGFyZ2V0PV9ibGFuaz7m +m7TlpJo8L0E+PC9TUEFOPuekvuWMuuaWsOivnemimDwvSDM+DQo8REwgY2xhc3M9InN0eWxlMyB0 +eHRfYmxhY2siIA0Kc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgRElTUExBWTogaW5saW5lOyBQ +QURESU5HLUxFRlQ6IDBweDsgRkxPQVQ6IGxlZnQ7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJ +TjogNXB4IDEwcHg7IFdJRFRIOiAyMzlweDsgQ09MT1I6IHJnYigwLDAsMCk7IFBBRERJTkctVE9Q +OiAwcHgiPg0KICA8REQgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQt +UE9TSVRJT046IDNweCA3cHg7IFBBRERJTkctTEVGVDogMTRweDsgQkFDS0dST1VORC1JTUFHRTog +dXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzIzLmdpZik7IFBB +RERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBMSU5FLUhFSUdIVDogMjFweDsgUEFERElO +Ry1UT1A6IDBweDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDog +aW5pdGlhbCI+PEEgDQogIHRpdGxlPeW3peS9nOS4reeahOWwj+aPkuabsu+8jOingeivhkNTRE7o +vr7kurogc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0K +ICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw4OCk7IA0KICBocmVmPSJodHRwOi8vdG9waWMu +Y3Nkbi5uZXQvdS8yMDEwMTIxNS8xNy83YTk5ZDM3Zi1lZjEzLTQ4NTQtOGFjMy1kM2RhNDFmNzgw +ODcuaHRtbCIgDQogIHRhcmdldD1fYmxhbms+5bel5L2c5Lit55qE5bCP5o+S5puy77yM6KeB6K+G +Q1NETui+vuS6ujwvQT48L0REPg0KICA8REQgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7 +IEJBQ0tHUk9VTkQtUE9TSVRJT046IDNweCA3cHg7IFBBRERJTkctTEVGVDogMTRweDsgQkFDS0dS +T1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3Bp +YzIzLmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBMSU5FLUhFSUdIVDog +MjFweDsgUEFERElORy1UT1A6IDBweDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tn +cm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxlPeWPkeWpmueFp++8jOaxguelneemj35+ +fu+8gSBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQog +IG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDg4KTsgDQogIGhyZWY9Imh0dHA6Ly90b3BpYy5j +c2RuLm5ldC91LzIwMTAxMjE0LzE0LzliNDgwZTA3LTI1Y2MtNDU2Yy1hZGRhLWFkYWU1ZTkyZGRk +Ni5odG1sIiANCiAgdGFyZ2V0PV9ibGFuaz7lj5HlqZrnhafvvIzmsYLnpZ3npo9+fn7vvIE8L0E+ +PC9ERD4NCiAgPEREIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBP +U0lUSU9OOiAzcHggN3B4OyBQQURESU5HLUxFRlQ6IDE0cHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVy +bChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMyMy5naWYpOyBQQURE +SU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweDsgTElORS1IRUlHSFQ6IDIxcHg7IFBBRERJTkct +VE9QOiAwcHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGlu +aXRpYWwiPjxBIA0KICB0aXRsZT3vvIjovazvvInlm6DkuLrmiJHmmK/kvaDlqrPlpoflhL8gc3R5 +bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNr +PUxvZ0NsaWNrQ291bnQodGhpcyw4OCk7IA0KICBocmVmPSJodHRwOi8vdG9waWMuY3Nkbi5uZXQv +dS8yMDEwMTIxNC8xMC81ZTA0ZWQ3Yy0yZjkyLTRhZDQtOGZkOS0xZjhlOWUwMTNkOTAuaHRtbCIg +DQogIHRhcmdldD1fYmxhbms+77yI6L2s77yJ5Zug5Li65oiR5piv5L2g5aqz5aaH5YS/PC9BPjwv +REQ+DQogIDxERCANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJ +VElPTjogM3B4IDdweDsgUEFERElORy1MRUZUOiAxNHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwo +aHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMjMuZ2lmKTsgUEFERElO +Ry1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IExJTkUtSEVJR0hUOiAyMXB4OyBQQURESU5HLVRP +UDogMHB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0 +aWFsIj48QSANCiAgdGl0bGU95a+55Zac5qyi55qE5Lq65pS+5byD6L+Y5piv57un57ut77yf5oiR +5b6I55+b55u+IHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25l +IiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsODgpOyANCiAgaHJlZj0iaHR0cDovL3Rv +cGljLmNzZG4ubmV0L3UvMjAxMDEyMTQvMTUvNTFlYmY4OWQtOTNlNi00NWQ0LTg2ODktNDRhMjc2 +NjExNDdlLmh0bWwiIA0KICB0YXJnZXQ9X2JsYW5rPuWvueWWnOasoueahOS6uuaUvuW8g+i/mOaY +r+e7p+e7re+8n+aIkeW+iOefm+ebvjwvQT48L0REPg0KICA8REQgDQogIHN0eWxlPSJQQURESU5H +LVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDNweCA3cHg7IFBBRERJTkctTEVGVDog +MTRweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMv +Y3NkbmluZGV4X3BpYzIzLmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBM +SU5FLUhFSUdIVDogMjFweDsgUEFERElORy1UT1A6IDBweDsgYmFja2dyb3VuZC1vcmlnaW46IGlu +aXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxlPeWwj+aXtuWAmeii +q+e9mu+8jOW5sui/h+i/meenjeS6i+aDheeahOerpemei+ivt+S4vuaJiyBzdHlsZT0iQ09MT1I6 +IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tD +b3VudCh0aGlzLDg4KTsgDQogIGhyZWY9Imh0dHA6Ly90b3BpYy5jc2RuLm5ldC91LzIwMTAxMjE1 +LzEyL2ZlM2MzZDU0LWE3Y2ItNDlkOS1iNjZkLWQ1YTk1NWQxOTZkZC5odG1sIiANCiAgdGFyZ2V0 +PV9ibGFuaz7lsI/ml7blgJnooqvnvZrvvIzlubLov4fov5nnp43kuovmg4XnmoTnq6Xpnovor7fk +uL7miYs8L0E+PC9ERD4NCiAgPEREIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNL +R1JPVU5ELVBPU0lUSU9OOiAzcHggN3B4OyBQQURESU5HLUxFRlQ6IDE0cHg7IEJBQ0tHUk9VTkQt +SU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMyMy5n +aWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweDsgTElORS1IRUlHSFQ6IDIxcHg7 +IFBBRERJTkctVE9QOiAwcHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5k +LWNsaXA6IGluaXRpYWwiPjxBIA0KICB0aXRsZT3jgJDljJfkuqzjgJHlm5vlubTlt6XkvZznu4/p +qoznnJ/nmoTog73mi784S+S5iO+8nyBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVD +T1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDg4KTsgDQogIGhy +ZWY9Imh0dHA6Ly90b3BpYy5jc2RuLm5ldC91LzIwMTAxMjE1LzEwL2ExNjg4Nzk4LWZjZmQtNGE1 +ZS05ZDY1LTEyOTA3MTlhNTdkNC5odG1sIiANCiAgdGFyZ2V0PV9ibGFuaz7jgJDljJfkuqzjgJHl +m5vlubTlt6XkvZznu4/pqoznnJ/nmoTog73mi784S+S5iO+8nzwvQT48L0REPg0KICA8REQgDQog +IHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDNweCA3cHg7 +IFBBRERJTkctTEVGVDogMTRweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1n +LmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzIzLmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7 +IE1BUkdJTjogMHB4OyBMSU5FLUhFSUdIVDogMjFweDsgUEFERElORy1UT1A6IDBweDsgYmFja2dy +b3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRp +dGxlPeWwj+W8n+aYjuWkqeS4i+WNiOWOu+iFvuiur+mdouivlSBzdHlsZT0iQ09MT1I6IHJnYigw +LDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0 +aGlzLDg4KTsgDQogIGhyZWY9Imh0dHA6Ly90b3BpYy5jc2RuLm5ldC91LzIwMTAxMjE1LzA5LzNj +YzdhYzE5LTI3ZTUtNDc3NS1hNWY0LWZhMGJjNjA2NjIxNi5odG1sIiANCiAgdGFyZ2V0PV9ibGFu +az7lsI/lvJ/mmI7lpKnkuIvljYjljrvohb7orq/pnaLor5U8L0E+PC9ERD4NCiAgPEREIA0KICBz +dHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAzcHggN3B4OyBQ +QURESU5HLUxFRlQ6IDE0cHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5j +bi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMyMy5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBN +QVJHSU46IDBweDsgTElORS1IRUlHSFQ6IDIxcHg7IFBBRERJTkctVE9QOiAwcHg7IGJhY2tncm91 +bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0aXRs +ZT3mjqjojZDlh6Dpg6jljbDluqbnmoTnlLXlvbF+fiBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7 +IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDg4 +KTsgDQogIGhyZWY9Imh0dHA6Ly90b3BpYy5jc2RuLm5ldC91LzIwMTAxMjE1LzE2L2FkNTRhYTg0 +LWNiMGUtNDk1OC05YTc5LWM4OWJhYWUwYWRlZC5odG1sIiANCiAgdGFyZ2V0PV9ibGFuaz7mjqjo +jZDlh6Dpg6jljbDluqbnmoTnlLXlvbF+fjwvQT48L0REPg0KICA8REQgDQogIHN0eWxlPSJQQURE +SU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDNweCA3cHg7IFBBRERJTkctTEVG +VDogMTRweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFn +ZXMvY3NkbmluZGV4X3BpYzIzLmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4 +OyBMSU5FLUhFSUdIVDogMjFweDsgUEFERElORy1UT1A6IDBweDsgYmFja2dyb3VuZC1vcmlnaW46 +IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxlPeiAgeadv3l1 +5ZGY5bel55qE5a+56K+d77yI5pCe6ICM55yf77yJIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsg +VEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsODgp +OyANCiAgaHJlZj0iaHR0cDovL3RvcGljLmNzZG4ubmV0L3UvMjAxMDEyMTYvMDAvYTM0ZmE1YzQt +MjY4MC00NmUzLWE4ZjUtOGM2ZmMyNmJmYjY0Lmh0bWwiIA0KICB0YXJnZXQ9X2JsYW5rPuiAgead +v3l15ZGY5bel55qE5a+56K+d77yI5pCe6ICM55yf77yJPC9BPjwvREQ+DQogIDxERCANCiAgc3R5 +bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogM3B4IDdweDsgUEFE +RElORy1MRUZUOiAxNHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24v +d3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMjMuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFS +R0lOOiAwcHg7IExJTkUtSEVJR0hUOiAyMXB4OyBQQURESU5HLVRPUDogMHB4OyBiYWNrZ3JvdW5k +LW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgdGl0bGU9 +5bu66K6uY3NkbuW8gOS4gOS4queUt+aAp+WBpeW6t+adv+WdlyBzdHlsZT0iQ09MT1I6IHJnYigw +LDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0 +aGlzLDg4KTsgDQogIGhyZWY9Imh0dHA6Ly90b3BpYy5jc2RuLm5ldC91LzIwMTAxMjE1LzE1Lzgx +MjJlYmI0LTY5ODItNDI4Ni04ZWJlLTQyM2ExNWZjN2EwOC5odG1sIiANCiAgdGFyZ2V0PV9ibGFu +az7lu7rorq5jc2Ru5byA5LiA5Liq55S35oCn5YGl5bq35p2/5Z2XPC9BPjwvREQ+PC9ETD4NCjxI +MyANCnN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDBweCAw +cHg7IERJU1BMQVk6IGlubGluZTsgUEFERElORy1MRUZUOiAyMHB4OyBGT05ULVNJWkU6IDE0cHg7 +IEZMT0FUOiBsZWZ0OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3 +L2ltYWdlcy9jc2RuaW5kZXhfcGljMTUuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lO +OiAwcHggMHB4IDdweDsgV0lEVEg6IDIzOXB4OyBMSU5FLUhFSUdIVDogMzBweDsgUEFERElORy1U +T1A6IDBweDsgUE9TSVRJT046IHJlbGF0aXZlOyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsg +YmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48U1BBTiANCmNsYXNzPSJ0eHRfMTIgdHh0X2dyYXki +IA0Kc3R5bGU9IkZPTlQtV0VJR0hUOiBub3JtYWw7IEZPTlQtU0laRTogMTJweDsgRkxPQVQ6IHJp +Z2h0OyBNQVJHSU46IDJweCA3cHggMHB4IDBweDsgQ09MT1I6IHJnYigxMDIsMTAyLDEwMikiPjxB +IA0Kc3R5bGU9IkNPTE9SOiByZ2IoMTAyLDEwMiwxMDIpOyBURVhULURFQ09SQVRJT046IG5vbmUi +IA0KaHJlZj0iaHR0cDovL2Jicy5jc2RuLm5ldC8iIHRhcmdldD1fYmxhbms+5pu05aSaPC9BPjwv +U1BBTj7nqIvluo/kurrnlJ88L0gzPg0KPERMIGNsYXNzPSJzdHlsZTIgdHh0X2JsYWNrIiANCnN0 +eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IERJU1BMQVk6IGlubGluZTsgUEFERElORy1MRUZUOiAw +cHg7IEZMT0FUOiBsZWZ0OyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDVweCAxMHB4OyBX +SURUSDogMjM5cHg7IENPTE9SOiByZ2IoMCwwLDApOyBQQURESU5HLVRPUDogMHB4Ij4NCiAgPERU +IGNsYXNzPXRvcDEgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9T +SVRJT046IDBweCAzcHg7IE9WRVJGTE9XLVk6IGhpZGRlbjsgUEFERElORy1MRUZUOiAyNHB4OyBC +QUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5k +ZXhfcGljMzUuZ2lmKTsgT1ZFUkZMT1ctWDogaGlkZGVuOyBQQURESU5HLUJPVFRPTTogMXB4OyBN +QVJHSU46IDBweDsgV0lEVEg6IDIxMHB4OyBQQURESU5HLVRPUDogNHB4OyBXSElURS1TUEFDRTog +bm93cmFwOyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0 +aWFsIj48QSANCiAgdGl0bGU9IlNE6L2v5Lu25aSn5Lya5ZyG5ruh57uT5p2fIOWqkuS9k+aKpemB +k+WPiuebuOWFsyIgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5v +bmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw4OSk7IA0KICBocmVmPSJodHRwOi8v +dG9waWMuY3Nkbi5uZXQvdS8yMDEwMTIxNS8xNS8yNzlFMjM1Ri0xRjNDLTREQTEtQjJGQi00OUEw +ODU2QzRGQkMuaHRtbCIgDQogIHRhcmdldD1fYmxhbms+U0Tova/ku7blpKfkvJrlnIbmu6Hnu5Pm +nZ8g5aqS5L2T5oql6YGT5Y+K55u45YWzPC9BPjwvRFQ+DQogIDxEVCBjbGFzcz10b3AyIA0KICBz +dHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAwcHggM3B4OyBP +VkVSRkxPVy1ZOiBoaWRkZW47IFBBRERJTkctTEVGVDogMjRweDsgQkFDS0dST1VORC1JTUFHRTog +dXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzM2LmdpZik7IE9W +RVJGTE9XLVg6IGhpZGRlbjsgUEFERElORy1CT1RUT006IDFweDsgTUFSR0lOOiAwcHg7IFdJRFRI +OiAyMTBweDsgUEFERElORy1UT1A6IDRweDsgV0hJVEUtU1BBQ0U6IG5vd3JhcDsgYmFja2dyb3Vu +ZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxl +PeWBtuWSjOWBtueahOWQjOWtpuW8oOS6jOeLl++8iOi+g+WujOaVtOeJiO+8iSBzdHlsZT0iQ09M +T1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xp +Y2tDb3VudCh0aGlzLDg5KTsgDQogIGhyZWY9Imh0dHA6Ly90b3BpYy5jc2RuLm5ldC91LzIwMTAx +MjE0LzE3LzNBRTlFMzczLTQzNDItNDA0MS1CRTM4LUU5OTkzQUUxMzAwQi5odG1sIiANCiAgdGFy +Z2V0PV9ibGFuaz7lgbblkozlgbbnmoTlkIzlrablvKDkuozni5fvvIjovoPlrozmlbTniYjvvIk8 +L0E+PC9EVD4NCiAgPERUIGNsYXNzPXRvcDMgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7 +IEJBQ0tHUk9VTkQtUE9TSVRJT046IDBweCAzcHg7IE9WRVJGTE9XLVk6IGhpZGRlbjsgUEFERElO +Ry1MRUZUOiAyNHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3 +L2ltYWdlcy9jc2RuaW5kZXhfcGljMzcuZ2lmKTsgT1ZFUkZMT1ctWDogaGlkZGVuOyBQQURESU5H +LUJPVFRPTTogMXB4OyBNQVJHSU46IDBweDsgV0lEVEg6IDIxMHB4OyBQQURESU5HLVRPUDogNHB4 +OyBXSElURS1TUEFDRTogbm93cmFwOyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dy +b3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgdGl0bGU96YCD56a75LiA57q/5Z+O5biC5aSn5a62 +6L+Y5Lya5LuO5LqL5Y6f5p2l5pa55ZCR5ZCX77yfIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsg +VEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsODkp +OyANCiAgaHJlZj0iaHR0cDovL3RvcGljLmNzZG4ubmV0L3UvMjAxMDEyMTIvMjIvQ0U3MkY2ODMt +MDcyNy00QkJBLUI5OTQtQzM1QzE5Mjc2MjQ3Lmh0bWwiIA0KICB0YXJnZXQ9X2JsYW5rPumAg+em +u+S4gOe6v+WfjuW4guWkp+Wutui/mOS8muS7juS6i+WOn+adpeaWueWQkeWQl++8nzwvQT48L0RU +Pg0KICA8RFQgY2xhc3M9dG9wNCANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dS +T1VORC1QT1NJVElPTjogMHB4IDNweDsgT1ZFUkZMT1ctWTogaGlkZGVuOyBQQURESU5HLUxFRlQ6 +IDI0cHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2Vz +L2NzZG5pbmRleF9waWMzOC5naWYpOyBPVkVSRkxPVy1YOiBoaWRkZW47IFBBRERJTkctQk9UVE9N +OiAxcHg7IE1BUkdJTjogMHB4OyBXSURUSDogMjEwcHg7IFBBRERJTkctVE9QOiA0cHg7IFdISVRF +LVNQQUNFOiBub3dyYXA7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNs +aXA6IGluaXRpYWwiPjxBIA0KICB0aXRsZT3mgaLlpI1JReS4uum7mOiupOS4i+i9veW3peWFtyBz +dHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xp +Y2s9TG9nQ2xpY2tDb3VudCh0aGlzLDg5KTsgDQogIGhyZWY9Imh0dHA6Ly90b3BpYy5jc2RuLm5l +dC91LzIwMTAxMjEzLzExLzIxMTMwNTI0LTEyQjQtNDY2Mi1BRTQ3LTUxNjk0Njk4QjM4Mi5odG1s +IiANCiAgdGFyZ2V0PV9ibGFuaz7mgaLlpI1JReS4uum7mOiupOS4i+i9veW3peWFtzwvQT48L0RU +Pg0KICA8RFQgY2xhc3M9dG9wNSANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dS +T1VORC1QT1NJVElPTjogMHB4IDNweDsgT1ZFUkZMT1ctWTogaGlkZGVuOyBQQURESU5HLUxFRlQ6 +IDI0cHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2Vz +L2NzZG5pbmRleF9waWMzOS5naWYpOyBPVkVSRkxPVy1YOiBoaWRkZW47IFBBRERJTkctQk9UVE9N +OiAxcHg7IE1BUkdJTjogMHB4OyBXSURUSDogMjEwcHg7IFBBRERJTkctVE9QOiA0cHg7IFdISVRF +LVNQQUNFOiBub3dyYXA7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNs +aXA6IGluaXRpYWwiPjxBIA0KICB0aXRsZT0i5LuK5pel6LWb5LqL5o6o5LuL77ya5pu86IGUIFZT +IOmYv+ajrue6syIgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5v +bmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw4OSk7IA0KICBocmVmPSJodHRwOi8v +dG9waWMuY3Nkbi5uZXQvdS8yMDEwMTIxMy8xMy9CN0Y0RTQ2Qy02QTA0LTRDQTUtQjlCOC0zMEUw +OTAxQkE4MzYuaHRtbCIgDQogIHRhcmdldD1fYmxhbms+5LuK5pel6LWb5LqL5o6o5LuL77ya5pu8 +6IGUIFZTIOmYv+ajrue6szwvQT48L0RUPg0KICA8RFQgY2xhc3M9dG9wNiANCiAgc3R5bGU9IlBB +RERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMHB4IDNweDsgT1ZFUkZMT1ct +WTogaGlkZGVuOyBQQURESU5HLUxFRlQ6IDI0cHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRw +Oi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWM0MC5naWYpOyBPVkVSRkxPVy1Y +OiBoaWRkZW47IFBBRERJTkctQk9UVE9NOiAxcHg7IE1BUkdJTjogMHB4OyBXSURUSDogMjEwcHg7 +IFBBRERJTkctVE9QOiA0cHg7IFdISVRFLVNQQUNFOiBub3dyYXA7IGJhY2tncm91bmQtb3JpZ2lu +OiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0aXRsZT3lpoLkvZXm +iJDkuLrkuIDlkI3kvJjnp4DnmoRBbmRyb2lk5byA5Y+R6ICFIHN0eWxlPSJDT0xPUjogcmdiKDAs +MCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRo +aXMsODkpOyANCiAgaHJlZj0iaHR0cDovL3RvcGljLmNzZG4ubmV0L3UvMjAxMDEyMDkvMTUvRTMw +MUE0Q0QtM0QzNi00RTRCLTk4MDktMTU1RjQ5REI5QzQ4Lmh0bWwiIA0KICB0YXJnZXQ9X2JsYW5r +PuWmguS9leaIkOS4uuS4gOWQjeS8mOengOeahEFuZHJvaWTlvIDlj5HogIU8L0E+PC9EVD4NCiAg +PERUIGNsYXNzPXRvcDcgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQt +UE9TSVRJT046IDBweCAzcHg7IE9WRVJGTE9XLVk6IGhpZGRlbjsgUEFERElORy1MRUZUOiAyNHB4 +OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2Ru +aW5kZXhfcGljNDEuZ2lmKTsgT1ZFUkZMT1ctWDogaGlkZGVuOyBQQURESU5HLUJPVFRPTTogMXB4 +OyBNQVJHSU46IDBweDsgV0lEVEg6IDIxMHB4OyBQQURESU5HLVRPUDogNHB4OyBXSElURS1TUEFD +RTogbm93cmFwOyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBp +bml0aWFsIj48QSANCiAgdGl0bGU9WyN3NlRDdXNLUnc2ZkN2TUtXdzZmQ29NS0IjXeS6kee8lueg +gSANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0K +ICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw4OSk7IA0KICBocmVmPSJodHRwOi8vdG9waWMu +Y3Nkbi5uZXQvdS8yMDEwMTIxMi8xMi8yQTMwNDNDNC1ENDA3LTQ3NDgtOTVDMy1BNUQwOTNDMjgx +M0UuaHRtbCIgDQogIHRhcmdldD1fYmxhbms+WyN3NlRDdXNLUnc2ZkN2TUtXdzZmQ29NS0IjXeS6 +kee8lueggTwvQT48L0RUPg0KICA8RFQgY2xhc3M9dG9wOCANCiAgc3R5bGU9IlBBRERJTkctUklH +SFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMHB4IDNweDsgT1ZFUkZMT1ctWTogaGlkZGVu +OyBQQURESU5HLUxFRlQ6IDI0cHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3Nkbmlt +Zy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWM0Mi5naWYpOyBPVkVSRkxPVy1YOiBoaWRkZW47 +IFBBRERJTkctQk9UVE9NOiAxcHg7IE1BUkdJTjogMHB4OyBXSURUSDogMjEwcHg7IFBBRERJTkct +VE9QOiA0cHg7IFdISVRFLVNQQUNFOiBub3dyYXA7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFs +OyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0aXRsZT1TRDIuMOWkp+S8mumahumH +jeW8gOW5lSznpL7ljLrnjrDlnLrlm77mlofnm7Tmkq0gc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDAp +OyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw4 +OSk7IA0KICBocmVmPSJodHRwOi8vdG9waWMuY3Nkbi5uZXQvdS8yMDEwMTIwOS8wOS9EMDgwMUY2 +QS03M0Y0LTQyNkQtODhGQi04RDcyQjkzQjU0OTkuaHRtbCIgDQogIHRhcmdldD1fYmxhbms+U0Qy +LjDlpKfkvJrpmobph43lvIDluZUs56S+5Yy6546w5Zy65Zu+5paH55u05pKtPC9BPjwvRFQ+DQog +IDxEVCBjbGFzcz10b3A5IA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5E +LVBPU0lUSU9OOiAwcHggM3B4OyBPVkVSRkxPVy1ZOiBoaWRkZW47IFBBRERJTkctTEVGVDogMjRw +eDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3Nk +bmluZGV4X3BpYzQzLmdpZik7IE9WRVJGTE9XLVg6IGhpZGRlbjsgUEFERElORy1CT1RUT006IDFw +eDsgTUFSR0lOOiAwcHg7IFdJRFRIOiAyMTBweDsgUEFERElORy1UT1A6IDRweDsgV0hJVEUtU1BB +Q0U6IG5vd3JhcDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDog +aW5pdGlhbCI+PEEgDQogIHRpdGxlPeWkp+Wutui9rOato+eahOW3pei1hOacieayoeacieWunuS5 +oOeahOaXtuWAmeWkmu+8nyBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElP +Tjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDg5KTsgDQogIGhyZWY9Imh0 +dHA6Ly90b3BpYy5jc2RuLm5ldC91LzIwMTAxMjA4LzExL0M2RkZFN0JELTNBQTktNDlDRi1CMEEx +LTY1NzUyMEIxRTI0QS5odG1sIiANCiAgdGFyZ2V0PV9ibGFuaz7lpKflrrbovazmraPnmoTlt6Xo +tYTmnInmsqHmnInlrp7kuaDnmoTml7blgJnlpJrvvJ88L0E+PC9EVD4NCiAgPERUIGNsYXNzPXRv +cDEwIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAw +cHggM3B4OyBPVkVSRkxPVy1ZOiBoaWRkZW47IFBBRERJTkctTEVGVDogMjRweDsgQkFDS0dST1VO +RC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzQ0 +LmdpZik7IE9WRVJGTE9XLVg6IGhpZGRlbjsgUEFERElORy1CT1RUT006IDFweDsgTUFSR0lOOiAw +cHg7IFdJRFRIOiAyMTBweDsgUEFERElORy1UT1A6IDRweDsgV0hJVEUtU1BBQ0U6IG5vd3JhcDsg +YmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEg +DQogIHRpdGxlPeWFpeihjOS4gOW5tOWkmuS7juayoeaEn+WPl+WIsOi9r+S7tuW8gOWPkeWWnOaC +piBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9u +Y2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDg5KTsgDQogIGhyZWY9Imh0dHA6Ly90b3BpYy5jc2Ru +Lm5ldC91LzIwMTAxMjA0LzE4L0NEMUFGRUJFLUQxMkMtNDdDRC1CMURGLURBOEVDQjUxNTdENy5o +dG1sIiANCiAgdGFyZ2V0PV9ibGFuaz7lhaXooYzkuIDlubTlpJrku47msqHmhJ/lj5fliLDova/k +u7blvIDlj5HllpzmgqY8L0E+PC9EVD48L0RMPjwvRElWPjwvRElWPjwvRElWPg0KPERJViBjbGFz +cz1wYWdlY29uX2xheWVyMmJ0bSANCnN0eWxlPSJCQUNLR1JPVU5ELVBPU0lUSU9OOiA1MCUgMTAw +JTsgRk9OVC1TSVpFOiAxcHg7IEZMT0FUOiBsZWZ0OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0 +cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljNDUuZ2lmKTsgV0lEVEg6IDk2 +MHB4OyBIRUlHSFQ6IDFweDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQt +Y2xpcDogaW5pdGlhbCI+PC9ESVY+DQo8RElWIGNsYXNzPWZyaWVuZGxpbmsgDQpzdHlsZT0iQk9S +REVSLVJJR0hUOiByZ2IoMjA0LDIwNCwyMDQpIDFweCBzb2xpZDsgUEFERElORy1SSUdIVDogNnB4 +OyBCT1JERVItVE9QOiByZ2IoMjA0LDIwNCwyMDQpIDFweCBzb2xpZDsgUEFERElORy1MRUZUOiA2 +cHg7IEZMT0FUOiBsZWZ0OyBQQURESU5HLUJPVFRPTTogM3B4OyBNQVJHSU46IDNweCAwcHggMHB4 +OyBCT1JERVItTEVGVDogcmdiKDIwNCwyMDQsMjA0KSAxcHggc29saWQ7IFdJRFRIOiA5NDZweDsg +UEFERElORy1UT1A6IDNweDsgQk9SREVSLUJPVFRPTTogcmdiKDIwNCwyMDQsMjA0KSAxcHggc29s +aWQiPg0KPFAgDQpzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBQQURESU5HLUxFRlQ6IDBweDsg +UEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IENPTE9SOiByZ2IoMTAyLDEwMiwxMDIp +OyBQQURESU5HLVRPUDogMHB4Ij48U1BBTiANCnN0eWxlPSJGT05ULVdFSUdIVDogYm9sZDsgTUFS +R0lOOiAwcHggNnB4IDBweCAwcHg7IENPTE9SOiByZ2IoMCwwLDApIj7lkIjkvZzkvJnkvLQ8L1NQ +QU4+PEEgDQpzdHlsZT0iUEFERElORy1SSUdIVDogM3B4OyBQQURESU5HLUxFRlQ6IDNweDsgUEFE +RElORy1CT1RUT006IDBweDsgQ09MT1I6IHJnYigxMDIsMTAyLDEwMik7IFBBRERJTkctVE9QOiAw +cHg7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQpocmVmPSJodHRwOi8vdGVjaC5zaW5hLmNvbS5j +bi8iIHRhcmdldD1ibGFuaz7mlrDmtarnp5HmioA8L0E+4oCUPFNQQU4gDQpjbGFzcz1BcHBsZS1j +b252ZXJ0ZWQtc3BhY2U+Jm5ic3A7PC9TUEFOPjxBIA0Kc3R5bGU9IlBBRERJTkctUklHSFQ6IDNw +eDsgUEFERElORy1MRUZUOiAzcHg7IFBBRERJTkctQk9UVE9NOiAwcHg7IENPTE9SOiByZ2IoMTAy +LDEwMiwxMDIpOyBQQURESU5HLVRPUDogMHB4OyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KaHJl +Zj0iaHR0cDovL2l0LnNvaHUuY29tLyIgdGFyZ2V0PWJsYW5rPuaQnOeLkElUPC9BPuKAlDxTUEFO +IA0KY2xhc3M9QXBwbGUtY29udmVydGVkLXNwYWNlPiZuYnNwOzwvU1BBTj48QSANCnN0eWxlPSJQ +QURESU5HLVJJR0hUOiAzcHg7IFBBRERJTkctTEVGVDogM3B4OyBQQURESU5HLUJPVFRPTTogMHB4 +OyBDT0xPUjogcmdiKDEwMiwxMDIsMTAyKTsgUEFERElORy1UT1A6IDBweDsgVEVYVC1ERUNPUkFU +SU9OOiBub25lIiANCmhyZWY9Imh0dHA6Ly93d3cuZG9uZXdzLmNvbS8iIHRhcmdldD1ibGFuaz5E +b05ld3M8L0E+4oCUPFNQQU4gDQpjbGFzcz1BcHBsZS1jb252ZXJ0ZWQtc3BhY2U+Jm5ic3A7PC9T +UEFOPjxBIA0Kc3R5bGU9IlBBRERJTkctUklHSFQ6IDNweDsgUEFERElORy1MRUZUOiAzcHg7IFBB +RERJTkctQk9UVE9NOiAwcHg7IENPTE9SOiByZ2IoMTAyLDEwMiwxMDIpOyBQQURESU5HLVRPUDog +MHB4OyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KaHJlZj0iaHR0cDovL3d3dy56ZG5ldC5jb20u +Y24vIiB0YXJnZXQ9Ymxhbms+WkROZXToh7PpobbnvZE8L0E+4oCUPFNQQU4gDQpjbGFzcz1BcHBs +ZS1jb252ZXJ0ZWQtc3BhY2U+Jm5ic3A7PC9TUEFOPjxBIA0Kc3R5bGU9IlBBRERJTkctUklHSFQ6 +IDNweDsgUEFERElORy1MRUZUOiAzcHg7IFBBRERJTkctQk9UVE9NOiAwcHg7IENPTE9SOiByZ2Io +MTAyLDEwMiwxMDIpOyBQQURESU5HLVRPUDogMHB4OyBURVhULURFQ09SQVRJT046IG5vbmUiIA0K +aHJlZj0iaHR0cDovL3d3dy50aGV0aGlyZG1lZGlhLmNvbS8iIHRhcmdldD1ibGFuaz7nrKzkuInl +qpLkvZM8L0E+4oCUPFNQQU4gDQpjbGFzcz1BcHBsZS1jb252ZXJ0ZWQtc3BhY2U+Jm5ic3A7PC9T +UEFOPjxBIA0Kc3R5bGU9IlBBRERJTkctUklHSFQ6IDNweDsgUEFERElORy1MRUZUOiAzcHg7IFBB +RERJTkctQk9UVE9NOiAwcHg7IENPTE9SOiByZ2IoMTAyLDEwMiwxMDIpOyBQQURESU5HLVRPUDog +MHB4OyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KaHJlZj0iaHR0cDovL3d3dy55ZXNreS5jb20v +IiB0YXJnZXQ9Ymxhbms+5aSp5p6B572RPC9BPuKAlDxTUEFOIA0KY2xhc3M9QXBwbGUtY29udmVy +dGVkLXNwYWNlPiZuYnNwOzwvU1BBTj48QSANCnN0eWxlPSJQQURESU5HLVJJR0hUOiAzcHg7IFBB +RERJTkctTEVGVDogM3B4OyBQQURESU5HLUJPVFRPTTogMHB4OyBDT0xPUjogcmdiKDEwMiwxMDIs +MTAyKTsgUEFERElORy1UT1A6IDBweDsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCmhyZWY9Imh0 +dHA6Ly93d3cuY2N3LmNvbS5jbi8iIHRhcmdldD1ibGFuaz7orqHkuJbnvZE8L0E+4oCUPFNQQU4g +DQpjbGFzcz1BcHBsZS1jb252ZXJ0ZWQtc3BhY2U+Jm5ic3A7PC9TUEFOPjxBIA0Kc3R5bGU9IlBB +RERJTkctUklHSFQ6IDNweDsgUEFERElORy1MRUZUOiAzcHg7IFBBRERJTkctQk9UVE9NOiAwcHg7 +IENPTE9SOiByZ2IoMTAyLDEwMiwxMDIpOyBQQURESU5HLVRPUDogMHB4OyBURVhULURFQ09SQVRJ +T046IG5vbmUiIA0KaHJlZj0iaHR0cDovL3d3dy5pbW9iaWxlLmNvbS5jbi8iPuaJi+acuuS5i+Wu +tjwvQT7igJQ8U1BBTiANCmNsYXNzPUFwcGxlLWNvbnZlcnRlZC1zcGFjZT4mbmJzcDs8L1NQQU4+ +PEEgDQpzdHlsZT0iUEFERElORy1SSUdIVDogM3B4OyBQQURESU5HLUxFRlQ6IDNweDsgUEFERElO +Ry1CT1RUT006IDBweDsgQ09MT1I6IHJnYigxMDIsMTAyLDEwMik7IFBBRERJTkctVE9QOiAwcHg7 +IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQpocmVmPSJodHRwOi8vd3d3LjUxc2hpbGluZy5jb20v +IiB0YXJnZXQ9Ymxhbms+NTHop4bpk4M8L0E+4oCUPFNQQU4gDQpjbGFzcz1BcHBsZS1jb252ZXJ0 +ZWQtc3BhY2U+Jm5ic3A7PC9TUEFOPjxBIA0Kc3R5bGU9IlBBRERJTkctUklHSFQ6IDNweDsgUEFE +RElORy1MRUZUOiAzcHg7IFBBRERJTkctQk9UVE9NOiAwcHg7IENPTE9SOiByZ2IoMTAyLDEwMiwx +MDIpOyBQQURESU5HLVRPUDogMHB4OyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KaHJlZj0iaHR0 +cDovL3d3dy5va3dhbi5jb20vIiB0YXJnZXQ9Ymxhbms+546p572R5L2T6IKyPC9BPjxTUEFOIA0K +Y2xhc3M9QXBwbGUtY29udmVydGVkLXNwYWNlPiZuYnNwOzwvU1BBTj7igJQ8QSANCnN0eWxlPSJQ +QURESU5HLVJJR0hUOiAzcHg7IFBBRERJTkctTEVGVDogM3B4OyBQQURESU5HLUJPVFRPTTogMHB4 +OyBDT0xPUjogcmdiKDEwMiwxMDIsMTAyKTsgUEFERElORy1UT1A6IDBweDsgVEVYVC1ERUNPUkFU +SU9OOiBub25lIiANCmhyZWY9Imh0dHA6Ly93d3cuNTFkaXR1LmNvbS8iIHRhcmdldD1ibGFuaz7m +iJHopoHlnLDlm748L0E+PFNQQU4gDQpjbGFzcz1BcHBsZS1jb252ZXJ0ZWQtc3BhY2U+Jm5ic3A7 +PC9TUEFOPuKAlDxBIA0Kc3R5bGU9IlBBRERJTkctUklHSFQ6IDNweDsgUEFERElORy1MRUZUOiAz +cHg7IFBBRERJTkctQk9UVE9NOiAwcHg7IENPTE9SOiByZ2IoMTAyLDEwMiwxMDIpOyBQQURESU5H +LVRPUDogMHB4OyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KaHJlZj0iaHR0cDovL3d3dy5qb2hu +YnJ5Y2UuY29tLmNuLyIgdGFyZ2V0PWJsYW5rPkpvaG4gQnJ5Y2U8L0E+PC9QPg0KPFAgDQpzdHls +ZT0iUEFERElORy1SSUdIVDogMHB4OyBQQURESU5HLUxFRlQ6IDBweDsgUEFERElORy1CT1RUT006 +IDBweDsgTUFSR0lOOiAwcHg7IENPTE9SOiByZ2IoMTAyLDEwMiwxMDIpOyBQQURESU5HLVRPUDog +MHB4Ij48QSANCnN0eWxlPSJQQURESU5HLVJJR0hUOiAzcHg7IFBBRERJTkctTEVGVDogM3B4OyBQ +QURESU5HLUJPVFRPTTogMHB4OyBDT0xPUjogcmdiKDEwMiwxMDIsMTAyKTsgUEFERElORy1UT1A6 +IDBweDsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCmhyZWY9Imh0dHA6Ly93d3cubG9uZ3R1by5j +b20vIiB0YXJnZXQ9Ymxhbms+6b6Z5ouT5LqS5YqoPC9BPuKAlDxTUEFOIA0KY2xhc3M9QXBwbGUt +Y29udmVydGVkLXNwYWNlPiZuYnNwOzwvU1BBTj48QSANCnN0eWxlPSJQQURESU5HLVJJR0hUOiAz +cHg7IFBBRERJTkctTEVGVDogM3B4OyBQQURESU5HLUJPVFRPTTogMHB4OyBDT0xPUjogcmdiKDEw +MiwxMDIsMTAyKTsgUEFERElORy1UT1A6IDBweDsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCmhy +ZWY9Imh0dHA6Ly93d3cudXV0dXUuY29tLyIgdGFyZ2V0PWJsYW5rPuS4h+iKseetkuaXhea4uDwv +QT7igJQ8U1BBTiANCmNsYXNzPUFwcGxlLWNvbnZlcnRlZC1zcGFjZT4mbmJzcDs8L1NQQU4+PEEg +DQpzdHlsZT0iUEFERElORy1SSUdIVDogM3B4OyBQQURESU5HLUxFRlQ6IDNweDsgUEFERElORy1C +T1RUT006IDBweDsgQ09MT1I6IHJnYigxMDIsMTAyLDEwMik7IFBBRERJTkctVE9QOiAwcHg7IFRF +WFQtREVDT1JBVElPTjogbm9uZSIgDQpocmVmPSJodHRwOi8vd3d3LmZvcnVtLm5va2lhLmNvbS5j +bi8iIHRhcmdldD1ibGFuaz7or7rln7rkuprorrrlnZs8L0E+4oCUPFNQQU4gDQpjbGFzcz1BcHBs +ZS1jb252ZXJ0ZWQtc3BhY2U+Jm5ic3A7PC9TUEFOPjxBIA0Kc3R5bGU9IlBBRERJTkctUklHSFQ6 +IDNweDsgUEFERElORy1MRUZUOiAzcHg7IFBBRERJTkctQk9UVE9NOiAwcHg7IENPTE9SOiByZ2Io +MTAyLDEwMiwxMDIpOyBQQURESU5HLVRPUDogMHB4OyBURVhULURFQ09SQVRJT046IG5vbmUiIA0K +aHJlZj0iaHR0cDovL3d3dy5lZXdvcmxkLmNvbS5jbi8iIHRhcmdldD1ibGFuaz7nlLXlrZDlt6Xn +qIs8L0E+4oCUPFNQQU4gDQpjbGFzcz1BcHBsZS1jb252ZXJ0ZWQtc3BhY2U+Jm5ic3A7PC9TUEFO +PjxBIA0Kc3R5bGU9IlBBRERJTkctUklHSFQ6IDNweDsgUEFERElORy1MRUZUOiAzcHg7IFBBRERJ +TkctQk9UVE9NOiAwcHg7IENPTE9SOiByZ2IoMTAyLDEwMiwxMDIpOyBQQURESU5HLVRPUDogMHB4 +OyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KaHJlZj0iaHR0cDovL3d3dy5vcGVuMm0uY29tLyIg +dGFyZ2V0PWJsYW5rPuW8gOa6kOS4k+Wutue9kTwvQT7igJQ8U1BBTiANCmNsYXNzPUFwcGxlLWNv +bnZlcnRlZC1zcGFjZT4mbmJzcDs8L1NQQU4+PEEgDQpzdHlsZT0iUEFERElORy1SSUdIVDogM3B4 +OyBQQURESU5HLUxFRlQ6IDNweDsgUEFERElORy1CT1RUT006IDBweDsgQ09MT1I6IHJnYigxMDIs +MTAyLDEwMik7IFBBRERJTkctVE9QOiAwcHg7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQpocmVm +PSJodHRwOi8vd3d3LmNoaW5hdmlzdWFsLmNvbS8iIHRhcmdldD1ibGFuaz7op4bop4nkuK3lm708 +L0E+4oCUPFNQQU4gDQpjbGFzcz1BcHBsZS1jb252ZXJ0ZWQtc3BhY2U+Jm5ic3A7PC9TUEFOPjxB +IA0Kc3R5bGU9IlBBRERJTkctUklHSFQ6IDNweDsgUEFERElORy1MRUZUOiAzcHg7IFBBRERJTkct +Qk9UVE9NOiAwcHg7IENPTE9SOiByZ2IoMTAyLDEwMiwxMDIpOyBQQURESU5HLVRPUDogMHB4OyBU +RVhULURFQ09SQVRJT046IG5vbmUiIA0KaHJlZj0iaHR0cDovL3d3dy5qdWt1dS5jb20vIiB0YXJn +ZXQ9Ymxhbms+5Y+l6YW35L6L5Y+lPC9BPuKAlDxTUEFOIA0KY2xhc3M9QXBwbGUtY29udmVydGVk +LXNwYWNlPiZuYnNwOzwvU1BBTj48QSANCnN0eWxlPSJQQURESU5HLVJJR0hUOiAzcHg7IFBBRERJ +TkctTEVGVDogM3B4OyBQQURESU5HLUJPVFRPTTogMHB4OyBDT0xPUjogcmdiKDEwMiwxMDIsMTAy +KTsgUEFERElORy1UT1A6IDBweDsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCmhyZWY9Imh0dHA6 +Ly93d3cuaHVkb25nLmNvbS8iIHRhcmdldD1ibGFuaz7kupLliqjnmb7np5E8L0E+4oCUPFNQQU4g +DQpjbGFzcz1BcHBsZS1jb252ZXJ0ZWQtc3BhY2U+Jm5ic3A7PC9TUEFOPjxBIA0Kc3R5bGU9IlBB +RERJTkctUklHSFQ6IDNweDsgUEFERElORy1MRUZUOiAzcHg7IFBBRERJTkctQk9UVE9NOiAwcHg7 +IENPTE9SOiByZ2IoMTAyLDEwMiwxMDIpOyBQQURESU5HLVRPUDogMHB4OyBURVhULURFQ09SQVRJ +T046IG5vbmUiIA0KaHJlZj0iaHR0cDovL3d3dy5kb2l0LmNvbS5jbi8iIHRhcmdldD1ibGFuaz5E +T0lUPC9BPuKAlDxTUEFOIA0KY2xhc3M9QXBwbGUtY29udmVydGVkLXNwYWNlPiZuYnNwOzwvU1BB +Tj48QSANCnN0eWxlPSJQQURESU5HLVJJR0hUOiAzcHg7IFBBRERJTkctTEVGVDogM3B4OyBQQURE +SU5HLUJPVFRPTTogMHB4OyBDT0xPUjogcmdiKDEwMiwxMDIsMTAyKTsgUEFERElORy1UT1A6IDBw +eDsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCmhyZWY9Imh0dHA6Ly93d3cuZWVkYXRhc2hlZXQu +Y29tLyIgdGFyZ2V0PWJsYW5rPkRhdGFzaGVldDwvQT7igJQ8U1BBTiANCmNsYXNzPUFwcGxlLWNv +bnZlcnRlZC1zcGFjZT4mbmJzcDs8L1NQQU4+PEEgDQpzdHlsZT0iUEFERElORy1SSUdIVDogM3B4 +OyBQQURESU5HLUxFRlQ6IDNweDsgUEFERElORy1CT1RUT006IDBweDsgQ09MT1I6IHJnYigxMDIs +MTAyLDEwMik7IFBBRERJTkctVE9QOiAwcHg7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQpocmVm +PSJodHRwOi8vd3d3LmRvY2luLmNvbS8iIHRhcmdldD1ibGFuaz7osYbkuIHnvZE8L0E+4oCUPFNQ +QU4gDQpjbGFzcz1BcHBsZS1jb252ZXJ0ZWQtc3BhY2U+Jm5ic3A7PC9TUEFOPjxBIA0Kc3R5bGU9 +IlBBRERJTkctUklHSFQ6IDNweDsgUEFERElORy1MRUZUOiAzcHg7IFBBRERJTkctQk9UVE9NOiAw +cHg7IENPTE9SOiByZ2IoMTAyLDEwMiwxMDIpOyBQQURESU5HLVRPUDogMHB4OyBURVhULURFQ09S +QVRJT046IG5vbmUiIA0KaHJlZj0iaHR0cDovL3d3dy5oYW9kZi5jb20vIiB0YXJnZXQ9Ymxhbms+ +5aW95aSn5aSr5Zyo57q/PC9BPjwvUD48L0RJVj4NCjxESVYgY2xhc3M9cHViX2Zvb3RlciANCnN0 +eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJPUkRFUi1UT1A6IHJnYigyMDQsMjA0LDIwNCkgMXB4 +IHNvbGlkOyBQQURESU5HLUxFRlQ6IDBweDsgRkxPQVQ6IGxlZnQ7IFBBRERJTkctQk9UVE9NOiAz +cHg7IE1BUkdJTjogNXB4IDBweCAwcHg7IFdJRFRIOiA5NjBweDsgUEFERElORy1UT1A6IDNweCI+ +DQo8REwgDQpzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBPVkVSRkxPVy1ZOiBoaWRkZW47IFBB +RERJTkctTEVGVDogMHB4OyBPVkVSRkxPVy1YOiBoaWRkZW47IFBBRERJTkctQk9UVE9NOiAzcHg7 +IE1BUkdJTjogMHB4OyBQQURESU5HLVRPUDogM3B4Ij4NCiAgPEREIGNsYXNzPWJhY2tibHVlIA0K +ICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBQQURESU5HLUxFRlQ6IDBweDsgUEFERElORy1C +T1RUT006IDVweDsgTUFSR0lOOiAwcHg7IENPTE9SOiByZ2IoMjU1LDI1NSwyNTUpOyBQQURESU5H +LVRPUDogNXB4OyBCQUNLR1JPVU5ELUNPTE9SOiByZ2IoMTUwLDE5NSwyMzQpOyBiYWNrZ3JvdW5k +LW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgc3R5bGU9 +IlBBRERJTkctUklHSFQ6IDVweDsgUEFERElORy1MRUZUOiA1cHg7IEZPTlQtV0VJR0hUOiBib2xk +OyBQQURESU5HLUJPVFRPTTogMHB4OyBDT0xPUjogcmdiKDI1NSwyNTUsMjU1KTsgUEFERElORy1U +T1A6IDBweDsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgaHJlZj0iaHR0cDovL3d3dy5jc2Ru +Lm5ldC9jb21wYW55L2Fib3V0Lmh0bWwiIHRhcmdldD1fYmxhbms+5YWs5Y+4566A5LuLPC9BPnw8 +QSANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDVweDsgUEFERElORy1MRUZUOiA1cHg7IEZPTlQt +V0VJR0hUOiBib2xkOyBQQURESU5HLUJPVFRPTTogMHB4OyBDT0xPUjogcmdiKDI1NSwyNTUsMjU1 +KTsgUEFERElORy1UT1A6IDBweDsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgaHJlZj0iaHR0 +cDovL3d3dy5jc2RuLm5ldC9jb21wYW55L3JlY3J1aXQuaHRtbCIgdGFyZ2V0PV9ibGFuaz7mi5vo +tKTnurPlo6s8L0E+fDxBIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogNXB4OyBQQURESU5HLUxF +RlQ6IDVweDsgRk9OVC1XRUlHSFQ6IGJvbGQ7IFBBRERJTkctQk9UVE9NOiAwcHg7IENPTE9SOiBy +Z2IoMjU1LDI1NSwyNTUpOyBQQURESU5HLVRPUDogMHB4OyBURVhULURFQ09SQVRJT046IG5vbmUi +IA0KICBocmVmPSJodHRwOi8vd3d3LmNzZG4ubmV0L2NvbXBhbnkvbWFya2V0aW5nLmh0bWwiIHRh +cmdldD1fYmxhbms+5bm/5ZGK5pyN5YqhPC9BPnw8QSANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6 +IDVweDsgUEFERElORy1MRUZUOiA1cHg7IEZPTlQtV0VJR0hUOiBib2xkOyBQQURESU5HLUJPVFRP +TTogMHB4OyBDT0xPUjogcmdiKDI1NSwyNTUsMjU1KTsgUEFERElORy1UT1A6IDBweDsgVEVYVC1E +RUNPUkFUSU9OOiBub25lIiANCiAgaHJlZj0iaHR0cDovL3d3dy5jc2RuLm5ldC9jb21wYW55L2Fj +Y291bnQuaHRtbCIgdGFyZ2V0PV9ibGFuaz7pk7booYzmsYfmrL7luJDlj7c8L0E+fDxBIA0KICBz +dHlsZT0iUEFERElORy1SSUdIVDogNXB4OyBQQURESU5HLUxFRlQ6IDVweDsgRk9OVC1XRUlHSFQ6 +IGJvbGQ7IFBBRERJTkctQk9UVE9NOiAwcHg7IENPTE9SOiByZ2IoMjU1LDI1NSwyNTUpOyBQQURE +SU5HLVRPUDogMHB4OyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBocmVmPSJodHRwOi8vd3d3 +LmNzZG4ubmV0L2NvbXBhbnkvY29udGFjdC5odG1sIiB0YXJnZXQ9X2JsYW5rPuiBlOezu+aWueW8 +jzwvQT58PEEgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiA1cHg7IFBBRERJTkctTEVGVDogNXB4 +OyBGT05ULVdFSUdIVDogYm9sZDsgUEFERElORy1CT1RUT006IDBweDsgQ09MT1I6IHJnYigyNTUs +MjU1LDI1NSk7IFBBRERJTkctVE9QOiAwcHg7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIGhy +ZWY9Imh0dHA6Ly93d3cuY3Nkbi5uZXQvY29tcGFueS9zdGF0ZW1lbnQuaHRtbCIgdGFyZ2V0PV9i +bGFuaz7niYjmnYPlo7DmmI48L0E+fDxBIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogNXB4OyBQ +QURESU5HLUxFRlQ6IDVweDsgRk9OVC1XRUlHSFQ6IGJvbGQ7IFBBRERJTkctQk9UVE9NOiAwcHg7 +IENPTE9SOiByZ2IoMjU1LDI1NSwyNTUpOyBQQURESU5HLVRPUDogMHB4OyBURVhULURFQ09SQVRJ +T046IG5vbmUiIA0KICBocmVmPSJodHRwOi8vd3d3LmNzZG4ubmV0L2NvbXBhbnkvbGF5ZXIuaHRt +bCIgdGFyZ2V0PV9ibGFuaz7ms5Xlvovpob7pl648L0E+fDxBIA0KICBzdHlsZT0iUEFERElORy1S +SUdIVDogNXB4OyBQQURESU5HLUxFRlQ6IDVweDsgRk9OVC1XRUlHSFQ6IGJvbGQ7IFBBRERJTkct +Qk9UVE9NOiAwcHg7IENPTE9SOiByZ2IoMjU1LDI1NSwyNTUpOyBQQURESU5HLVRPUDogMHB4OyBU +RVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPSJ3aW5kb3cubG9jYXRpb24uaHJlZj0n +bWFpJysnbHRvOicrJ3dlYm1hJysnc3RlckBjJysnc2RuLm4nKydldD9zdWJqZWN0PVJlcG9ydCBU +byBDU0ROJztyZXR1cm4gZmFsc2UiIA0KICBocmVmPSJodHRwOi8vd3d3LmNzZG4ubmV0LyMiPumX +rumimOaKpeWRijwvQT48L0REPg0KICA8RFQgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7 +IFBBRERJTkctTEVGVDogMHB4OyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweDsgUEFE +RElORy1UT1A6IDVweDsgVEVYVC1BTElHTjogY2VudGVyIj48QSANCiAgc3R5bGU9IlBBRERJTkct +UklHSFQ6IDBweDsgRElTUExBWTogaW5saW5lOyBQQURESU5HLUxFRlQ6IDBweDsgUEFERElORy1C +T1RUT006IDBweDsgTUFSR0lOOiA1cHg7IENPTE9SOiByZ2IoMCwwLDApOyBQQURESU5HLVRPUDog +MHB4OyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBocmVmPSJodHRwOi8vd3d3Lml0cnVzdC5v +cmcuY24vIiB0YXJnZXQ9X2JsYW5rPjxJTUcgdGl0bGU9IiIgDQogIHN0eWxlPSJCT1JERVItUklH +SFQ6IHJnYigyMDQsMjA0LDIwNCkgMXB4IHNvbGlkOyBCT1JERVItVE9QOiByZ2IoMjA0LDIwNCwy +MDQpIDFweCBzb2xpZDsgQk9SREVSLUxFRlQ6IHJnYigyMDQsMjA0LDIwNCkgMXB4IHNvbGlkOyBX +SURUSDogMTE1cHg7IEJPUkRFUi1CT1RUT006IHJnYigyMDQsMjA0LDIwNCkgMXB4IHNvbGlkOyBI +RUlHSFQ6IDQ1cHgiIA0KICBhbHQ9IiIgc3JjPSJodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2Vz +L2xpbmtfbG9nbzAxLmdpZiI+PC9BPjxTUEFOIA0KICBjbGFzcz1BcHBsZS1jb252ZXJ0ZWQtc3Bh +Y2U+Jm5ic3A7PC9TUEFOPjxBIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBESVNQTEFZ +OiBpbmxpbmU7IFBBRERJTkctTEVGVDogMHB4OyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46 +IDVweDsgQ09MT1I6IHJnYigwLDAsMCk7IFBBRERJTkctVE9QOiAwcHg7IFRFWFQtREVDT1JBVElP +Tjogbm9uZSIgDQogIGhyZWY9Imh0dHA6Ly93d3cuaGQzMTUuZ292LmNuL2JlaWFuL3ZpZXcuYXNw +P2JpYW5oYW89MDEwMjAyMDAxMDMyMTAwMDEwIiANCiAgdGFyZ2V0PV9ibGFuaz48SU1HIHRpdGxl +PSIiIA0KICBzdHlsZT0iQk9SREVSLVJJR0hUOiByZ2IoMjA0LDIwNCwyMDQpIDFweCBzb2xpZDsg +Qk9SREVSLVRPUDogcmdiKDIwNCwyMDQsMjA0KSAxcHggc29saWQ7IEJPUkRFUi1MRUZUOiByZ2Io +MjA0LDIwNCwyMDQpIDFweCBzb2xpZDsgV0lEVEg6IDExNXB4OyBCT1JERVItQk9UVE9NOiByZ2Io +MjA0LDIwNCwyMDQpIDFweCBzb2xpZDsgSEVJR0hUOiA0NXB4IiANCiAgYWx0PSIiIHNyYz0iaHR0 +cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9saW5rX2xvZ28wMi5naWYiPjwvQT48U1BBTiANCiAg +Y2xhc3M9QXBwbGUtY29udmVydGVkLXNwYWNlPiZuYnNwOzwvU1BBTj48QSANCiAgc3R5bGU9IlBB +RERJTkctUklHSFQ6IDBweDsgRElTUExBWTogaW5saW5lOyBQQURESU5HLUxFRlQ6IDBweDsgUEFE +RElORy1CT1RUT006IDBweDsgTUFSR0lOOiA1cHg7IENPTE9SOiByZ2IoMCwwLDApOyBQQURESU5H +LVRPUDogMHB4OyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBocmVmPSJodHRwOi8vbmV0LmNo +aW5hLmNvbS5jbi9pbmRleC5odG0iIHRhcmdldD1fYmxhbms+PElNRyB0aXRsZT0iIiANCiAgc3R5 +bGU9IkJPUkRFUi1SSUdIVDogcmdiKDIwNCwyMDQsMjA0KSAxcHggc29saWQ7IEJPUkRFUi1UT1A6 +IHJnYigyMDQsMjA0LDIwNCkgMXB4IHNvbGlkOyBCT1JERVItTEVGVDogcmdiKDIwNCwyMDQsMjA0 +KSAxcHggc29saWQ7IFdJRFRIOiAxMTVweDsgQk9SREVSLUJPVFRPTTogcmdiKDIwNCwyMDQsMjA0 +KSAxcHggc29saWQ7IEhFSUdIVDogNDVweCIgDQogIGFsdD0iIiBzcmM9Imh0dHA6Ly9jc2RuaW1n +LmNuL3d3dy9pbWFnZXMvbGlua19sb2dvMDMuZ2lmIj48L0E+PFNQQU4gDQogIGNsYXNzPUFwcGxl +LWNvbnZlcnRlZC1zcGFjZT4mbmJzcDs8L1NQQU4+PEEgDQogIHN0eWxlPSJQQURESU5HLVJJR0hU +OiAwcHg7IERJU1BMQVk6IGlubGluZTsgUEFERElORy1MRUZUOiAwcHg7IFBBRERJTkctQk9UVE9N +OiAwcHg7IE1BUkdJTjogNXB4OyBDT0xPUjogcmdiKDAsMCwwKTsgUEFERElORy1UT1A6IDBweDsg +VEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgaHJlZj0iaHR0cDovL3d3dy5uZXRiai5vcmcuY24v +IiB0YXJnZXQ9X2JsYW5rPjxJTUcgdGl0bGU9IiIgDQogIHN0eWxlPSJCT1JERVItUklHSFQ6IHJn +YigyMDQsMjA0LDIwNCkgMXB4IHNvbGlkOyBCT1JERVItVE9QOiByZ2IoMjA0LDIwNCwyMDQpIDFw +eCBzb2xpZDsgQk9SREVSLUxFRlQ6IHJnYigyMDQsMjA0LDIwNCkgMXB4IHNvbGlkOyBXSURUSDog +MTE1cHg7IEJPUkRFUi1CT1RUT006IHJnYigyMDQsMjA0LDIwNCkgMXB4IHNvbGlkOyBIRUlHSFQ6 +IDQ1cHgiIA0KICBhbHQ9IiIgc3JjPSJodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2xpbmtf +bG9nbzA0LmdpZiI+PC9BPjxTUEFOIA0KICBjbGFzcz1BcHBsZS1jb252ZXJ0ZWQtc3BhY2U+Jm5i +c3A7PC9TUEFOPjxBIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBESVNQTEFZOiBpbmxp +bmU7IFBBRERJTkctTEVGVDogMHB4OyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDVweDsg +Q09MT1I6IHJnYigwLDAsMCk7IFBBRERJTkctVE9QOiAwcHg7IFRFWFQtREVDT1JBVElPTjogbm9u +ZSIgDQogIGhyZWY9Imh0dHA6Ly93d3cuYmouY3liZXJwb2xpY2UuY24vaW5kZXguaHRtIiB0YXJn +ZXQ9X2JsYW5rPjxJTUcgdGl0bGU9IiIgDQogIHN0eWxlPSJCT1JERVItUklHSFQ6IHJnYigyMDQs +MjA0LDIwNCkgMXB4IHNvbGlkOyBCT1JERVItVE9QOiByZ2IoMjA0LDIwNCwyMDQpIDFweCBzb2xp +ZDsgQk9SREVSLUxFRlQ6IHJnYigyMDQsMjA0LDIwNCkgMXB4IHNvbGlkOyBXSURUSDogMTE1cHg7 +IEJPUkRFUi1CT1RUT006IHJnYigyMDQsMjA0LDIwNCkgMXB4IHNvbGlkOyBIRUlHSFQ6IDQ1cHgi +IA0KICBhbHQ9IiIgc3JjPSJodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2xpbmtfbG9nbzA1 +LmdpZiI+PC9BPjwvRFQ+DQogIDxERCANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgUEFE +RElORy1MRUZUOiAwcHg7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBQQURESU5H +LVRPUDogMHB4Ij7lrqLmiLfmnI3liqHng63nur/vvJowMTAtNTE2NjEyMDLjgIDov53ms5Xkv6Hm +ga/kuL7miqXnlLXor53vvJoxMzU1MjAwOTY4OSANCiAg5Li+5oql6YKu566x77yaPEEgDQogIHN0 +eWxlPSJQQURESU5HLVJJR0hUOiA1cHg7IFBBRERJTkctTEVGVDogNXB4OyBQQURESU5HLUJPVFRP +TTogMHB4OyBDT0xPUjogcmdiKDAsMCwwKTsgUEFERElORy1UT1A6IDBweDsgVEVYVC1ERUNPUkFU +SU9OOiBub25lIiANCiAgb25jbGljaz0id2luZG93LmxvY2F0aW9uLmhyZWY9J21haScrJ2x0bzon +Kyd3ZWJtYScrJ3N0ZXJAYycrJ3Nkbi5uJysnZXQ/c3ViamVjdD1SZXBvcnQgVG8gQ1NETic7cmV0 +dXJuIGZhbHNlIiANCiAgaHJlZj0iaHR0cDovL3d3dy5jc2RuLm5ldC8jIj53ZWJtYXN0ZXJAY3Nk +bi5uZXQ8L0E+PC9ERD4NCiAgPEREIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBQQURE +SU5HLUxFRlQ6IDBweDsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IFBBRERJTkct +VE9QOiAwcHgiPuWMl+S6rOW4guWFrOWuieWxgOacnemYs+WIhuWxgOe9keebkeS4reW/g+Wkh+ah +iOe8luWPt++8mjExMDEwNTA5Njk8U1BBTiANCiAgY2xhc3M9QXBwbGUtY29udmVydGVkLXNwYWNl +PiZuYnNwOzwvU1BBTj48QSANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDVweDsgUEFERElORy1M +RUZUOiA1cHg7IFBBRERJTkctQk9UVE9NOiAwcHg7IENPTE9SOiByZ2IoMCwwLDApOyBQQURESU5H +LVRPUDogMHB4OyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBocmVmPSJodHRwOi8vd3d3Lm1p +aWJlaWFuLmdvdi5jbi8iIHRhcmdldD1fYmxhbms+5LqsSUNQ6K+BMDcwNTk45Y+3PC9BPjwvREQ+ +DQogIDxERCANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgUEFERElORy1MRUZUOiAwcHg7 +IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBQQURESU5HLVRPUDogMHB4Ij48QSAN +CiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDVweDsgUEFERElORy1MRUZUOiA1cHg7IFBBRERJTkct +Qk9UVE9NOiAwcHg7IENPTE9SOiByZ2IoMCwwLDApOyBQQURESU5HLVRPUDogMHB4OyBURVhULURF +Q09SQVRJT046IG5vbmUiIA0KICBocmVmPSJodHRwOi8vd3d3LmNzZG4ubmV0L2NvbXBhbnkvaWNw +Lmh0bWwiPueUteS/oeS4muWKoeWuoeaJuVsyMDA3XeWtl+esrDM4MOWPtzwvQT48U1BBTiANCiAg +Y2xhc3M9QXBwbGUtY29udmVydGVkLXNwYWNlPiZuYnNwOzwvU1BBTj48QSANCiAgc3R5bGU9IlBB +RERJTkctUklHSFQ6IDVweDsgUEFERElORy1MRUZUOiA1cHg7IFBBRERJTkctQk9UVE9NOiAwcHg7 +IENPTE9SOiByZ2IoMCwwLDApOyBQQURESU5HLVRPUDogMHB4OyBURVhULURFQ09SQVRJT046IG5v +bmUiIA0KICBocmVmPSJodHRwOi8vd3d3LmNzZG4ubmV0L2NvbXBhbnkvcGlmdS5odG1sIj7nlLXk +v6HkuI7kv6Hmga/mnI3liqHkuJrliqHnu4/okKXorrjlj6/or4EwNzA1OTjlj7c8L0E+PC9ERD4N +CiAgPEREIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBQQURESU5HLUxFRlQ6IDBweDsg +UEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IFBBRERJTkctVE9QOiAwcHgiPuWMl+S6 +rOWIm+aWsOS5kOefpeW5v+WRiuaciemZkOWFrOWPuCANCiAg54mI5p2D5omA5pyJPC9ERD4NCiAg +PEREIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBQQURESU5HLUxFRlQ6IDBweDsgUEFE +RElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IFBBRERJTkctVE9QOiAwcHgiPuS4lue6quS5 +kOefpSjljJfkuqwp572R57uc5oqA5pyv5pyJ6ZmQ5YWs5Y+4IA0KICDmj5DkvpvmioDmnK/mlK/m +jIE8L0REPg0KICA8REQgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IFBBRERJTkctTEVG +VDogMHB4OyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweDsgUEFERElORy1UT1A6IDBw +eCI+5rGf6IuP5LmQ55+l572R57uc5oqA5pyv5pyJ6ZmQ5YWs5Y+4IA0KICDmj5DkvpvllYbliqHm +lK/mjIE8L0REPg0KICA8REQgY2xhc3M9c21hbGwgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAw +cHg7IFBBRERJTkctTEVGVDogMHB4OyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweDsg +UEFERElORy1UT1A6IDBweCI+Q29weXJpZ2h0IA0KICDCqSAxOTk5LTIwMTAsIENTRE4uTkVULCBB +bGwgUmlnaHRzIFJlc2VydmVkPC9ERD48L0RMPjwvRElWPjwvRElWPjwvRElWPjxJTUcgDQpzdHls +ZT0iQk9SREVSLVRPUC1XSURUSDogMHB4OyBCT1JERVItTEVGVC1XSURUSDogMHB4OyBCT1JERVIt +Qk9UVE9NLVdJRFRIOiAwcHg7IEJPUkRFUi1SSUdIVC1XSURUSDogMHB4IiANCmhlaWdodD0wIHNy +Yz0iaHR0cDovL2NvdW50ZXIuY3Nkbi5uZXQvcHYuYXNweD9pZD0xOCIgd2lkdGg9MCBib3JkZXI9 +MD48U1BBTiANCmNsYXNzPUFwcGxlLWNvbnZlcnRlZC1zcGFjZT4mbmJzcDs8L1NQQU4+PElNRyAN +CnN0eWxlPSJCT1JERVItVE9QLVdJRFRIOiAwcHg7IEJPUkRFUi1MRUZULVdJRFRIOiAwcHg7IEJP +UkRFUi1CT1RUT00tV0lEVEg6IDBweDsgQk9SREVSLVJJR0hULVdJRFRIOiAwcHgiIA0KaGVpZ2h0 +PTEgYWx0PSIiIA0Kc3JjPSJodHRwOi8vY3ExNDQuY3Nkbi5uZXQvdmlzaXRsb2cucGhwP3NjcmVl +bj0xMDI0eDc2OCZhbXA7aG9zdD13d3cuY3Nkbi5uZXQmYW1wO2Jyb3dzZXI9TmV0c2NhcGUlMjA1 +JTIwJmFtcDtvcz1XaW5kb3dzJmFtcDt1cmw9aHR0cDovL3d3dy5jc2RuLm5ldC8iIA0Kd2lkdGg9 +MSBib3JkZXI9MD48SUZSQU1FIGlkPW15ZnJhbWUgYm9yZGVyPTAgbmFtZT1teWZyYW1lIA0Kc3Jj +PSJodHRwOi8vd3d3LmNzZG4ubmV0L2dnbW0vZGQzMzMuaHRtIiBmcmFtZUJvcmRlcj1ubyB3aWR0 +aD0wIHNjcm9sbGluZz1ubyANCmhlaWdodD0wPjwvSUZSQU1FPjxTUEFOIGNsYXNzPUFwcGxlLXN0 +eWxlLXNwYW4gDQpzdHlsZT0iV09SRC1TUEFDSU5HOiAwcHg7IEZPTlQ6IG1lZGl1bSBTaW1zdW47 +IFRFWFQtVFJBTlNGT1JNOiBub25lOyBDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1JTkRFTlQ6IDBw +eDsgV0hJVEUtU1BBQ0U6IG5vcm1hbDsgTEVUVEVSLVNQQUNJTkc6IG5vcm1hbDsgQk9SREVSLUNP +TExBUFNFOiBzZXBhcmF0ZTsgb3JwaGFuczogMjsgd2lkb3dzOiAyOyAtd2Via2l0LWJvcmRlci1o +b3Jpem9udGFsLXNwYWNpbmc6IDBweDsgLXdlYmtpdC1ib3JkZXItdmVydGljYWwtc3BhY2luZzog +MHB4OyAtd2Via2l0LXRleHQtZGVjb3JhdGlvbnMtaW4tZWZmZWN0OiBub25lOyAtd2Via2l0LXRl +eHQtc2l6ZS1hZGp1c3Q6IGF1dG87IC13ZWJraXQtdGV4dC1zdHJva2Utd2lkdGg6IDBweCI+PFNQ +QU4gDQpjbGFzcz1BcHBsZS1zdHlsZS1zcGFuIA0Kc3R5bGU9IkZPTlQtU0laRTogMTJweDsgTElO +RS1IRUlHSFQ6IDE4cHg7IEZPTlQtRkFNSUxZOiBzaW1zdW47IFRFWFQtQUxJR046IGNlbnRlciI+ +DQo8RElWIGNsYXNzPW1haW53cmFwIA0Kc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgUEFERElO +Ry1MRUZUOiAwcHg7IFBBRERJTkctQk9UVE9NOiA1cHg7IE1BUkdJTjogMHB4IGF1dG87IFdJRFRI +OiA5NjBweDsgUEFERElORy1UT1A6IDBweCI+DQo8RElWIGNsYXNzPXdyYXBwZXIgc3R5bGU9IkZM +T0FUOiBsZWZ0OyBXSURUSDogOTYwcHgiPg0KPERJViBjbGFzcz1iYW5uZXJfdG9wMSBzdHlsZT0i +RkxPQVQ6IGxlZnQ7IE1BUkdJTjogMnB4IDBweDsgV0lEVEg6IDk2MHB4Ij4NCjxVTCANCnN0eWxl +PSJQQURESU5HLVJJR0hUOiAwcHg7IFBBRERJTkctTEVGVDogMHB4OyBGTE9BVDogbGVmdDsgUEFE +RElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IFdJRFRIOiA5NjBweDsgUEFERElORy1UT1A6 +IDBweDsgTElTVC1TVFlMRS1UWVBFOiBub25lIj4NCiAgPExJIGNsYXNzPWxlZnRhZCANCiAgc3R5 +bGU9IlBBRERJTkctUklHSFQ6IDBweDsgUEFERElORy1MRUZUOiAwcHg7IEZMT0FUOiBsZWZ0OyBQ +QURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweDsgV0lEVEg6IDczNnB4OyBQQURESU5HLVRP +UDogMHB4OyBIRUlHSFQ6IDYwcHgiPjxBIA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRF +WFQtREVDT1JBVElPTjogbm9uZSIgDQogIGhyZWY9Imh0dHA6Ly96LmNzZG4ubmV0L2dtY2xpY2su +cGhwP2Jhbm5lcmlkPTU0MzImYW1wO3pvbmVpZD00MDImYW1wO3NvdXJjZT0mYW1wO2Rlc3Q9aHR0 +cCUzQSUyRiUyRmJhbWJvb2sucHJvZ3JhbW1lci5jb20uY24lMkYiIA0KICB0YXJnZXQ9X2JsYW5r +PjxJTUcgdGl0bGU9IiIgDQogIHN0eWxlPSJCT1JERVItVE9QLVdJRFRIOiAwcHg7IEJPUkRFUi1M +RUZULVdJRFRIOiAwcHg7IEJPUkRFUi1CT1RUT00tV0lEVEg6IDBweDsgQk9SREVSLVJJR0hULVdJ +RFRIOiAwcHgiIA0KICBoZWlnaHQ9NjAgYWx0PSIiIA0KICBzcmM9Imh0dHA6Ly9pbmZvLWRhdGFi +YXNlLmNzZG4ubmV0L1VwbG9hZC8yMDEwLTEyLTEwLzczNV82MF96aGVuZ2RpbmcuanBnIiANCiAg +d2lkdGg9NzM1IGJvcmRlcj0wPjwvQT4NCiAgPERJViBpZD1iZWFjb25fNTQzMiANCiAgc3R5bGU9 +IkxFRlQ6IDBweDsgVklTSUJJTElUWTogaGlkZGVuOyBQT1NJVElPTjogYWJzb2x1dGU7IFRPUDog +MHB4Ij48SU1HIA0KICBzdHlsZT0iQk9SREVSLVRPUC1XSURUSDogMHB4OyBCT1JERVItTEVGVC1X +SURUSDogMHB4OyBCT1JERVItQk9UVE9NLVdJRFRIOiAwcHg7IFdJRFRIOiAwcHg7IEhFSUdIVDog +MHB4OyBCT1JERVItUklHSFQtV0lEVEg6IDBweCIgDQogIGhlaWdodD0wIGFsdD0iIiANCiAgc3Jj +PSJodHRwOi8vei5jc2RuLm5ldC9nbWxvZy5waHA/YmFubmVyaWQ9NTQzMiZhbXA7Y2xpZW50aWQ9 +MTcxMiZhbXA7emY9JmFtcDt6b25laWQ9NDAyJmFtcDtzb3VyY2U9JmFtcDtibG9jaz0wJmFtcDtj +YXBwaW5nPTAmYW1wO2NiPTcyZGNlYzBhNWQ0YTM2NjU2NGYyYWNkOGZiMzU3NjY2IiANCiAgd2lk +dGg9MD48L0RJVj48L0xJPg0KICA8TEkgY2xhc3M9cmlnaHRhZCANCiAgc3R5bGU9IlBBRERJTkct +UklHSFQ6IDBweDsgUEFERElORy1MRUZUOiAwcHg7IEZMT0FUOiByaWdodDsgUEFERElORy1CT1RU +T006IDBweDsgTUFSR0lOOiAwcHg7IFdJRFRIOiAyMTBweDsgUEFERElORy1UT1A6IDBweDsgSEVJ +R0hUOiA2MHB4Ij48QSANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJ +T046IG5vbmUiIA0KICBocmVmPSJodHRwOi8vei5jc2RuLm5ldC9nbWNsaWNrLnBocD9iYW5uZXJp +ZD01MzI2JmFtcDt6b25laWQ9NDAzJmFtcDtzb3VyY2U9JmFtcDtkZXN0PWh0dHAlM0ElMkYlMkZ3 +d3cubWljcm9zb2Z0LmNvbSUyRndlYiUzRldULm1jX2lkJTNEYmFuLW4tY24td2FnLS1DU0ROIiAN +CiAgdGFyZ2V0PV9ibGFuaz48SU1HIHRpdGxlPSIiIA0KICBzdHlsZT0iQk9SREVSLVRPUC1XSURU +SDogMHB4OyBCT1JERVItTEVGVC1XSURUSDogMHB4OyBCT1JERVItQk9UVE9NLVdJRFRIOiAwcHg7 +IEJPUkRFUi1SSUdIVC1XSURUSDogMHB4IiANCiAgaGVpZ2h0PTYwIGFsdD0iIiANCiAgc3JjPSJo +dHRwOi8vaW5mby1kYXRhYmFzZS5jc2RuLm5ldC9VcGxvYWQvMjAxMC0xMS0zMC93ZWJfMjEwXzYw +XzExMzAuanBnIiANCiAgd2lkdGg9MjEwIGJvcmRlcj0wPjwvQT4NCiAgPERJViBpZD1iZWFjb25f +NTMyNiANCiAgc3R5bGU9IkxFRlQ6IDBweDsgVklTSUJJTElUWTogaGlkZGVuOyBQT1NJVElPTjog +YWJzb2x1dGU7IFRPUDogMHB4Ij48SU1HIA0KICBzdHlsZT0iQk9SREVSLVRPUC1XSURUSDogMHB4 +OyBCT1JERVItTEVGVC1XSURUSDogMHB4OyBCT1JERVItQk9UVE9NLVdJRFRIOiAwcHg7IFdJRFRI +OiAwcHg7IEhFSUdIVDogMHB4OyBCT1JERVItUklHSFQtV0lEVEg6IDBweCIgDQogIGhlaWdodD0w +IGFsdD0iIiANCiAgc3JjPSJodHRwOi8vei5jc2RuLm5ldC9nbWxvZy5waHA/YmFubmVyaWQ9NTMy +NiZhbXA7Y2xpZW50aWQ9MTY3NyZhbXA7emY9JmFtcDt6b25laWQ9NDAzJmFtcDtzb3VyY2U9JmFt +cDtibG9jaz0wJmFtcDtjYXBwaW5nPTAmYW1wO2NiPTg4YzAzZDk4YTMxMTYxNjkwZDY4MjZlODNl +OTI5M2EwIiANCiAgd2lkdGg9MD48L0RJVj48L0xJPjwvVUw+PC9ESVY+DQo8RElWIGNsYXNzPSJw +YWdldG9wX25vdGljZSB0eHRfZ3JheSIgDQpzdHlsZT0iUEFERElORy1SSUdIVDogNXB4OyBQQURE +SU5HLUxFRlQ6IDVweDsgRkxPQVQ6IGxlZnQ7IFBBRERJTkctQk9UVE9NOiAycHg7IFdJRFRIOiA5 +NTBweDsgQ09MT1I6IHJnYigxMDIsMTAyLDEwMik7IFBBRERJTkctVE9QOiAycHg7IEJBQ0tHUk9V +TkQtQ09MT1I6IHJnYigyNDUsMjQ1LDI0NSk7IFRFWFQtQUxJR046IGxlZnQ7IGJhY2tncm91bmQt +b3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxDSVRFIA0KaWQ9bG9n +aW4gc3R5bGU9IkZPTlQtU1RZTEU6IG5vcm1hbCI+PEEgDQpzdHlsZT0iQ09MT1I6IHJnYigxMDIs +MTAyLDEwMik7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQpocmVmPSJodHRwOi8vcGFzc3BvcnQu +Y3Nkbi5uZXQvQ1NETlVzZXJSZWdpc3Rlci5hc3B4IiB0YXJnZXQ9X2JsYW5rPjxJTUcgDQp0aXRs +ZT3ms6jlhowgDQpzdHlsZT0iQk9SREVSLVRPUC1XSURUSDogMHB4OyBCT1JERVItTEVGVC1XSURU +SDogMHB4OyBGTE9BVDogcmlnaHQ7IEJPUkRFUi1CT1RUT00tV0lEVEg6IDBweDsgTUFSR0lOOiAw +cHggMnB4IC0zcHg7IEJPUkRFUi1SSUdIVC1XSURUSDogMHB4IiANCmFsdD3ms6jlhowgc3JjPSJo +dHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMxLmdpZiI+PC9BPjxBIA0K +c3R5bGU9IkNPTE9SOiByZ2IoMTAyLDEwMiwxMDIpOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0K +aHJlZj0iaHR0cDovL3Bhc3Nwb3J0LmNzZG4ubmV0L1VzZXJMb2dpbi5hc3B4IiB0YXJnZXQ9X2Js +YW5rPjxJTUcgdGl0bGU955m75b2VIA0Kc3R5bGU9IkJPUkRFUi1UT1AtV0lEVEg6IDBweDsgQk9S +REVSLUxFRlQtV0lEVEg6IDBweDsgRkxPQVQ6IHJpZ2h0OyBCT1JERVItQk9UVE9NLVdJRFRIOiAw +cHg7IE1BUkdJTjogMHB4IDJweCAtM3B4OyBCT1JERVItUklHSFQtV0lEVEg6IDBweCIgDQphbHQ9 +55m75b2VIHNyYz0iaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMi5n +aWYiPjwvQT48L0NJVEU+5LuK5aSp5pivPEVNIA0KaWQ9bm93VGltZSBzdHlsZT0iRk9OVC1TVFlM +RTogbm9ybWFsIj4yMDEw5bm0MTLmnIgxNuaXpTwvRU0+PFNQQU4gaWQ9c2hvd2luZm8gDQpzdHls +ZT0iTUFSR0lOOiAwcHggMjBweCAwcHggNDBweCI+PC9TUEFOPjwvRElWPg0KPERJViBjbGFzcz1j +c2RuX3B1YmhlYWRlcjA5IA0Kc3R5bGU9IkJPUkRFUi1SSUdIVDogcmdiKDIwNCwyMDQsMjA0KSAx +cHggc29saWQ7IEJPUkRFUi1UT1A6IHJnYigyMDQsMjA0LDIwNCkgMXB4IHNvbGlkOyBGTE9BVDog +bGVmdDsgTUFSR0lOOiAycHggMHB4OyBCT1JERVItTEVGVDogcmdiKDIwNCwyMDQsMjA0KSAxcHgg +c29saWQ7IFdJRFRIOiA5NThweDsgQk9SREVSLUJPVFRPTTogcmdiKDIwNCwyMDQsMjA0KSAxcHgg +c29saWQ7IEhFSUdIVDogNjhweDsgVEVYVC1BTElHTjogbGVmdCI+DQo8RElWIGNsYXNzPWNzZG5f +cHViaGVhZGVyMDlfbG9nbyBzdHlsZT0iRkxPQVQ6IGxlZnQ7IFdJRFRIOiAxOTRweCI+PEEgDQpz +dHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQpocmVmPSJo +dHRwOi8vd3d3LmNzZG4ubmV0LyI+PElNRyB0aXRsZT0iQ1NETiBMb2dvIiANCnN0eWxlPSJCT1JE +RVItVE9QLVdJRFRIOiAwcHg7IEJPUkRFUi1MRUZULVdJRFRIOiAwcHg7IEJPUkRFUi1CT1RUT00t +V0lEVEg6IDBweDsgQk9SREVSLVJJR0hULVdJRFRIOiAwcHgiIA0KYWx0PSJDU0ROIExvZ28iIA0K +c3JjPSJodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWNsb2dvLmdpZiI+ +PC9BPjwvRElWPg0KPERJViBjbGFzcz1jc2RuX3B1YmhlYWRlcjA5X25hdiANCnN0eWxlPSJGTE9B +VDogcmlnaHQ7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1h +Z2VzL2NzZG5pbmRleF9waWM0LmdpZik7IEJPUkRFUi1MRUZUOiByZ2IoMjA0LDIwNCwyMDQpIDFw +eCBzb2xpZDsgV0lEVEg6IDc2M3B4OyBIRUlHSFQ6IDY4cHg7IGJhY2tncm91bmQtb3JpZ2luOiBp +bml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPg0KPFVMIGNsYXNzPXJvd18xIA0Kc3R5 +bGU9IlBBRERJTkctUklHSFQ6IDBweDsgUEFERElORy1MRUZUOiAwcHg7IEZMT0FUOiBsZWZ0OyBQ +QURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDhweCAwcHggMHB4OyBXSURUSDogNzYzcHg7IFBB +RERJTkctVE9QOiAwcHg7IExJU1QtU1RZTEUtVFlQRTogbm9uZSI+DQogIDxMSSANCiAgc3R5bGU9 +IlBBRERJTkctUklHSFQ6IDlweDsgQkFDS0dST1VORC1QT1NJVElPTjogMTAwJSA1MCU7IFBBRERJ +TkctTEVGVDogOXB4OyBGTE9BVDogbGVmdDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9j +c2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzMuZ2lmKTsgUEFERElORy1CT1RUT006 +IDBweDsgTUFSR0lOOiAwcHg7IFBBRERJTkctVE9QOiAwcHg7IGJhY2tncm91bmQtb3JpZ2luOiBp +bml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICBzdHlsZT0iRk9OVC1XRUlH +SFQ6IGJvbGQ7IENPTE9SOiByZ2IoMTAsNjEsMTQwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiAN +CiAgaHJlZj0iaHR0cDovL3d3dy5jc2RuLm5ldC8iIHRhcmdldD1fYmxhbms+6aaW6aG1PC9BPjwv +TEk+DQogIDxMSSANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDlweDsgQkFDS0dST1VORC1QT1NJ +VElPTjogMTAwJSA1MCU7IFBBRERJTkctTEVGVDogOXB4OyBGTE9BVDogbGVmdDsgQkFDS0dST1VO +RC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzMu +Z2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IFBBRERJTkctVE9QOiAwcHg7 +IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxB +IA0KICBzdHlsZT0iRk9OVC1XRUlHSFQ6IGJvbGQ7IENPTE9SOiByZ2IoMTAsNjEsMTQwKTsgVEVY +VC1ERUNPUkFUSU9OOiBub25lIiANCiAgaHJlZj0iaHR0cDovL25ld3MuY3Nkbi5uZXQvIiB0YXJn +ZXQ9X2JsYW5rPui1hOiurzwvQT48L0xJPg0KICA8TEkgDQogIHN0eWxlPSJQQURESU5HLVJJR0hU +OiA5cHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDEwMCUgNTAlOyBQQURESU5HLUxFRlQ6IDlweDsg +RkxPQVQ6IGxlZnQ7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cv +aW1hZ2VzL2NzZG5pbmRleF9waWMzLmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjog +MHB4OyBQQURESU5HLVRPUDogMHB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dy +b3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgc3R5bGU9IkZPTlQtV0VJR0hUOiBib2xkOyBDT0xP +UjogcmdiKDEwLDYxLDE0MCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIGhyZWY9Imh0dHA6 +Ly9oaS5jc2RuLm5ldC8iIHRhcmdldD1fYmxhbms+56m66Ze0PC9BPjwvTEk+DQogIDxMSSANCiAg +c3R5bGU9IlBBRERJTkctUklHSFQ6IDlweDsgQkFDS0dST1VORC1QT1NJVElPTjogMTAwJSA1MCU7 +IFBBRERJTkctTEVGVDogOXB4OyBGTE9BVDogbGVmdDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0 +dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzMuZ2lmKTsgUEFERElORy1C +T1RUT006IDBweDsgTUFSR0lOOiAwcHg7IFBBRERJTkctVE9QOiAwcHg7IGJhY2tncm91bmQtb3Jp +Z2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICBzdHlsZT0iRk9O +VC1XRUlHSFQ6IGJvbGQ7IENPTE9SOiByZ2IoMTAsNjEsMTQwKTsgVEVYVC1ERUNPUkFUSU9OOiBu +b25lIiANCiAgaHJlZj0iaHR0cDovL2Jicy5jc2RuLm5ldC8iIHRhcmdldD1fYmxhbms+6K665Z2b +PC9BPjwvTEk+DQogIDxMSSANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDlweDsgQkFDS0dST1VO +RC1QT1NJVElPTjogMTAwJSA1MCU7IFBBRERJTkctTEVGVDogOXB4OyBGTE9BVDogbGVmdDsgQkFD +S0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4 +X3BpYzMuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IFBBRERJTkctVE9Q +OiAwcHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRp +YWwiPjxBIA0KICBzdHlsZT0iRk9OVC1XRUlHSFQ6IGJvbGQ7IENPTE9SOiByZ2IoMTAsNjEsMTQw +KTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgaHJlZj0iaHR0cDovL2Jsb2cuY3Nkbi5uZXQv +IiB0YXJnZXQ9X2JsYW5rPuWNmuWuojwvQT48L0xJPg0KICA8TEkgDQogIHN0eWxlPSJQQURESU5H +LVJJR0hUOiA5cHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDEwMCUgNTAlOyBQQURESU5HLUxFRlQ6 +IDlweDsgRkxPQVQ6IGxlZnQ7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5j +bi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMzLmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1B +UkdJTjogMHB4OyBQQURESU5HLVRPUDogMHB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsg +YmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgc3R5bGU9IkZPTlQtV0VJR0hUOiBib2xk +OyBDT0xPUjogcmdiKDEwLDYxLDE0MCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIGhyZWY9 +Imh0dHA6Ly9kb3dubG9hZC5jc2RuLm5ldC8iIHRhcmdldD1fYmxhbms+5LiL6L29PC9BPjwvTEk+ +DQogIDxMSSANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDlweDsgQkFDS0dST1VORC1QT1NJVElP +TjogMTAwJSA1MCU7IFBBRERJTkctTEVGVDogOXB4OyBGTE9BVDogbGVmdDsgQkFDS0dST1VORC1J +TUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzMuZ2lm +KTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IFBBRERJTkctVE9QOiAwcHg7IGJh +Y2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0K +ICBzdHlsZT0iRk9OVC1XRUlHSFQ6IGJvbGQ7IENPTE9SOiByZ2IoMTAsNjEsMTQwKTsgVEVYVC1E +RUNPUkFUSU9OOiBub25lIiANCiAgaHJlZj0iaHR0cDovL3d6LmNzZG4ubmV0LyIgdGFyZ2V0PV9i +bGFuaz7nvZHmkZg8L0E+PC9MST4NCiAgPExJIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogOXB4 +OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAxMDAlIDUwJTsgUEFERElORy1MRUZUOiA5cHg7IEZMT0FU +OiBsZWZ0OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdl +cy9jc2RuaW5kZXhfcGljMy5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweDsg +UEFERElORy1UT1A6IDBweDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQt +Y2xpcDogaW5pdGlhbCI+PEEgDQogIHN0eWxlPSJGT05ULVdFSUdIVDogYm9sZDsgQ09MT1I6IHJn +YigxMCw2MSwxNDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBocmVmPSJodHRwOi8vd3d3 +LnByb2dyYW1tZXIuY29tLmNuLyIgdGFyZ2V0PV9ibGFuaz7nqIvluo/lkZg8L0E+PC9MST4NCiAg +PExJIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogOXB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAx +MDAlIDUwJTsgUEFERElORy1MRUZUOiA5cHg7IEZMT0FUOiBsZWZ0OyBCQUNLR1JPVU5ELUlNQUdF +OiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMy5naWYpOyBQ +QURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweDsgUEFERElORy1UT1A6IDBweDsgYmFja2dy +b3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHN0 +eWxlPSJGT05ULVdFSUdIVDogYm9sZDsgQ09MT1I6IHJnYigxMCw2MSwxNDApOyBURVhULURFQ09S +QVRJT046IG5vbmUiIA0KICBocmVmPSJodHRwOi8vcHJqLmNzZG4ubmV0LyIgdGFyZ2V0PV9ibGFu +az7pobnnm67kuqTmmJM8L0E+PC9MST4NCiAgPExJIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDog +OXB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAxMDAlIDUwJTsgUEFERElORy1MRUZUOiA5cHg7IEZM +T0FUOiBsZWZ0OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2lt +YWdlcy9jc2RuaW5kZXhfcGljMy5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBw +eDsgUEFERElORy1UT1A6IDBweDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91 +bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHN0eWxlPSJGT05ULVdFSUdIVDogYm9sZDsgQ09MT1I6 +IHJnYigxMCw2MSwxNDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBocmVmPSJodHRwOi8v +d3d3LmRlYXJib29rLmNvbS5jbi8iIHRhcmdldD1fYmxhbms+5Lmm5bqXPC9BPjwvTEk+DQogIDxM +SSANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDlweDsgQkFDS0dST1VORC1QT1NJVElPTjogMTAw +JSA1MCU7IFBBRERJTkctTEVGVDogOXB4OyBGTE9BVDogbGVmdDsgQkFDS0dST1VORC1JTUFHRTog +dXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzMuZ2lmKTsgUEFE +RElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IFBBRERJTkctVE9QOiAwcHg7IGJhY2tncm91 +bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICBzdHls +ZT0iRk9OVC1XRUlHSFQ6IGJvbGQ7IENPTE9SOiByZ2IoMTAsNjEsMTQwKTsgVEVYVC1ERUNPUkFU +SU9OOiBub25lIiANCiAgaHJlZj0iaHR0cDovL2N0by5jc2RuLm5ldC8iIHRhcmdldD1fYmxhbms+ +Q1RP5L+x5LmQ6YOoPC9BPjwvTEk+DQogIDxMSSANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDlw +eDsgQkFDS0dST1VORC1QT1NJVElPTjogMTAwJSA1MCU7IFBBRERJTkctTEVGVDogOXB4OyBGTE9B +VDogbGVmdDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFn +ZXMvY3NkbmluZGV4X3BpYzMuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7 +IFBBRERJTkctVE9QOiAwcHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5k +LWNsaXA6IGluaXRpYWwiPjxBIA0KICBjbGFzcz1yZWQgDQogIHN0eWxlPSJGT05ULVdFSUdIVDog +Ym9sZDsgQ09MT1I6IHJnYigyNTUsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgaHJl +Zj0iaHR0cDovL3R1cC5jc2RuLm5ldC8iIHRhcmdldD1fYmxhbms+VFVQPC9BPjwvTEk+DQogIDxM +SSANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDlweDsgQkFDS0dST1VORC1QT1NJVElPTjogMTAw +JSA1MCU7IFBBRERJTkctTEVGVDogOXB4OyBGTE9BVDogbGVmdDsgQkFDS0dST1VORC1JTUFHRTog +dXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzMuZ2lmKTsgUEFE +RElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IFBBRERJTkctVE9QOiAwcHg7IGJhY2tncm91 +bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICBzdHls +ZT0iRk9OVC1XRUlHSFQ6IGJvbGQ7IENPTE9SOiByZ2IoMTAsNjEsMTQwKTsgVEVYVC1ERUNPUkFU +SU9OOiBub25lIiANCiAgaHJlZj0iaHR0cDovL2VkdS5jc2RuLm5ldC8iIHRhcmdldD1fYmxhbms+ +5Z+56K6t5YWF55S1PC9BPjwvTEk+DQogIDxMSSBjbGFzcz1sYXN0IA0KICBzdHlsZT0iUEFERElO +Ry1SSUdIVDogMTFweDsgUEFERElORy1MRUZUOiAxMXB4OyBGTE9BVDogbGVmdDsgQkFDS0dST1VO +RC1JTUFHRTogbm9uZTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IFBBRERJTkct +VE9QOiAwcHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGlu +aXRpYWwiPjxBIA0KICBzdHlsZT0iRk9OVC1XRUlHSFQ6IGJvbGQ7IENPTE9SOiByZ2IoMTAsNjEs +MTQwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgaHJlZj0iaHR0cDovL3N0dWRlbnQuY3Nk +bi5uZXQvc3BhY2UucGhwP2RvPW10YWcmYW1wO2lkPTUiIA0KICB0YXJnZXQ9X2JsYW5rPumrmOag +oWNsdWI8L0E+PC9MST48L1VMPg0KPFVMIGNsYXNzPXJvd18yIA0Kc3R5bGU9IlBBRERJTkctUklH +SFQ6IDBweDsgUEFERElORy1MRUZUOiAwcHg7IEZMT0FUOiBsZWZ0OyBQQURESU5HLUJPVFRPTTog +MHB4OyBNQVJHSU46IDE4cHggMHB4IDBweDsgV0lEVEg6IDc2M3B4OyBQQURESU5HLVRPUDogMHB4 +OyBMSVNULVNUWUxFLVRZUEU6IG5vbmUiPg0KICA8TEkgDQogIHN0eWxlPSJQQURESU5HLVJJR0hU +OiAxMHB4OyBQQURESU5HLUxFRlQ6IDEwcHg7IEZMT0FUOiBsZWZ0OyBQQURESU5HLUJPVFRPTTog +MHB4OyBNQVJHSU46IDBweDsgVkVSVElDQUwtQUxJR046IGJvdHRvbTsgUEFERElORy1UT1A6IDBw +eCI+PEEgDQogIGNsYXNzPXJlZCANCiAgc3R5bGU9IkZPTlQtV0VJR0hUOiBib2xkOyBDT0xPUjog +cmdiKDI1NSwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBocmVmPSJodHRwOi8vc2Qu +Y3Nkbi5uZXQvIiB0YXJnZXQ9X2JsYW5rPueglOWPkTwvQT48L0xJPg0KICA8TEkgDQogIHN0eWxl +PSJQQURESU5HLVJJR0hUOiAxMHB4OyBQQURESU5HLUxFRlQ6IDEwcHg7IEZMT0FUOiBsZWZ0OyBQ +QURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweDsgVkVSVElDQUwtQUxJR046IGJvdHRvbTsg +UEFERElORy1UT1A6IDBweCI+PEEgDQogIHN0eWxlPSJGT05ULVdFSUdIVDogYm9sZDsgQ09MT1I6 +IHJnYigxMCw2MSwxNDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBocmVmPSJodHRwOi8v +bW9iaWxlLmNzZG4ubmV0LyIgdGFyZ2V0PV9ibGFuaz7np7vliqg8L0E+PC9MST4NCiAgPExJIA0K +ICBzdHlsZT0iUEFERElORy1SSUdIVDogMTBweDsgUEFERElORy1MRUZUOiAxMHB4OyBGTE9BVDog +bGVmdDsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IFZFUlRJQ0FMLUFMSUdOOiBi +b3R0b207IFBBRERJTkctVE9QOiAwcHgiPjxBIA0KICBzdHlsZT0iRk9OVC1XRUlHSFQ6IGJvbGQ7 +IENPTE9SOiByZ2IoMTAsNjEsMTQwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgaHJlZj0i +aHR0cDovL2M5LmNzZG4uaHVkb25nLmNvbS8iIHRhcmdldD1fYmxhbms+Q2hhbm5lbDk8L0E+PC9M +ST4NCiAgPExJIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMTBweDsgUEFERElORy1MRUZUOiAx +MHB4OyBGTE9BVDogbGVmdDsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IFZFUlRJ +Q0FMLUFMSUdOOiBib3R0b207IFBBRERJTkctVE9QOiAwcHgiPjxBIA0KICBzdHlsZT0iRk9OVC1X +RUlHSFQ6IGJvbGQ7IENPTE9SOiByZ2IoMTAsNjEsMTQwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25l +IiANCiAgaHJlZj0iaHR0cDovL2phdmEuY3Nkbi5uZXQvIiB0YXJnZXQ9X2JsYW5rPkphdmE8L0E+ +PC9MST4NCiAgPExJIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMTBweDsgUEFERElORy1MRUZU +OiAxMHB4OyBGTE9BVDogbGVmdDsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IFZF +UlRJQ0FMLUFMSUdOOiBib3R0b207IFBBRERJTkctVE9QOiAwcHgiPjxBIA0KICBzdHlsZT0iRk9O +VC1XRUlHSFQ6IGJvbGQ7IENPTE9SOiByZ2IoMTAsNjEsMTQwKTsgVEVYVC1ERUNPUkFUSU9OOiBu +b25lIiANCiAgaHJlZj0iaHR0cDovL3NlY3VyaXR5LmNzZG4ubmV0LyIgdGFyZ2V0PV9ibGFuaz7l +ronlhag8L0E+PC9MST4NCiAgPExJIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMTBweDsgUEFE +RElORy1MRUZUOiAxMHB4OyBGTE9BVDogbGVmdDsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lO +OiAwcHg7IFZFUlRJQ0FMLUFMSUdOOiBib3R0b207IFBBRERJTkctVE9QOiAwcHgiPjxBIA0KICBz +dHlsZT0iRk9OVC1XRUlHSFQ6IGJvbGQ7IENPTE9SOiByZ2IoMTAsNjEsMTQwKTsgVEVYVC1ERUNP +UkFUSU9OOiBub25lIiANCiAgaHJlZj0iaHR0cDovL2RhdGFiYXNlLmNzZG4ubmV0LyIgdGFyZ2V0 +PV9ibGFuaz7mlbDmja7lupM8L0E+PC9MST4NCiAgPExJIA0KICBzdHlsZT0iUEFERElORy1SSUdI +VDogMTBweDsgUEFERElORy1MRUZUOiAxMHB4OyBGTE9BVDogbGVmdDsgUEFERElORy1CT1RUT006 +IDBweDsgTUFSR0lOOiAwcHg7IFZFUlRJQ0FMLUFMSUdOOiBib3R0b207IFBBRERJTkctVE9QOiAw +cHgiPjxBIA0KICBzdHlsZT0iRk9OVC1XRUlHSFQ6IGJvbGQ7IENPTE9SOiByZ2IoMTAsNjEsMTQw +KTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgaHJlZj0iaHR0cDovL2RvdG5ldC5jc2RuLm5l +dC8iIHRhcmdldD1fYmxhbms+Lk5FVDwvQT48L0xJPg0KICA8TEkgDQogIHN0eWxlPSJQQURESU5H +LVJJR0hUOiAxMHB4OyBQQURESU5HLUxFRlQ6IDEwcHg7IEZMT0FUOiBsZWZ0OyBQQURESU5HLUJP +VFRPTTogMHB4OyBNQVJHSU46IDBweDsgVkVSVElDQUwtQUxJR046IGJvdHRvbTsgUEFERElORy1U +T1A6IDBweCI+PEEgDQogIHN0eWxlPSJGT05ULVdFSUdIVDogYm9sZDsgQ09MT1I6IHJnYigxMCw2 +MSwxNDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBocmVmPSJodHRwOi8vd2ViZGV2LmNz +ZG4ubmV0LyIgdGFyZ2V0PV9ibGFuaz5XZWLlvIDlj5E8L0E+PC9MST4NCiAgPExJIA0KICBzdHls +ZT0iUEFERElORy1SSUdIVDogMTBweDsgUEFERElORy1MRUZUOiAxMHB4OyBGTE9BVDogbGVmdDsg +UEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IFZFUlRJQ0FMLUFMSUdOOiBib3R0b207 +IFBBRERJTkctVE9QOiAwcHgiPjxBIA0KICBzdHlsZT0iRk9OVC1XRUlHSFQ6IGJvbGQ7IENPTE9S +OiByZ2IoMTAsNjEsMTQwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgaHJlZj0iaHR0cDov +L2Nsb3VkLmNzZG4ubmV0LyIgdGFyZ2V0PV9ibGFuaz7kupHorqHnrpc8L0E+PC9MST4NCiAgPExJ +IA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMTBweDsgUEFERElORy1MRUZUOiAxMHB4OyBGTE9B +VDogbGVmdDsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IFZFUlRJQ0FMLUFMSUdO +OiBib3R0b207IFBBRERJTkctVE9QOiAwcHgiPjxBIA0KICBzdHlsZT0iRk9OVC1XRUlHSFQ6IGJv +bGQ7IENPTE9SOiByZ2IoMTAsNjEsMTQwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgaHJl +Zj0iaHR0cDovL3NlcnZlci5jc2RuLm5ldC8iIHRhcmdldD1fYmxhbms+5pyN5Yqh5ZmoPC9BPjwv +TEk+DQogIDxMSSANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDEwcHg7IFBBRERJTkctTEVGVDog +MTBweDsgRkxPQVQ6IGxlZnQ7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBWRVJU +SUNBTC1BTElHTjogYm90dG9tOyBQQURESU5HLVRPUDogMHB4Ij48QSANCiAgc3R5bGU9IkZPTlQt +V0VJR0hUOiBib2xkOyBDT0xPUjogcmdiKDEwLDYxLDE0MCk7IFRFWFQtREVDT1JBVElPTjogbm9u +ZSIgDQogIGhyZWY9Imh0dHA6Ly90ZWxlY29tLWl0LmNzZG4ubmV0LyIgdGFyZ2V0PV9ibGFuaz7n +lLXkv6FJVDwvQT48L0xJPg0KICA8TEkgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAxMHB4OyBQ +QURESU5HLUxFRlQ6IDEwcHg7IEZMT0FUOiBsZWZ0OyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJH +SU46IDBweDsgVkVSVElDQUwtQUxJR046IGJvdHRvbTsgUEFERElORy1UT1A6IDBweCI+PEEgDQog +IHN0eWxlPSJGT05ULVdFSUdIVDogYm9sZDsgQ09MT1I6IHJnYigxMCw2MSwxNDApOyBURVhULURF +Q09SQVRJT046IG5vbmUiIA0KICBocmVmPSJodHRwOi8vc3R1ZGVudC5jc2RuLm5ldC8iIHRhcmdl +dD1fYmxhbms+5a2m55Sf5aSn5pys6JClPC9BPjwvTEk+DQogIDxMSSANCiAgc3R5bGU9IlBBRERJ +TkctUklHSFQ6IDEwcHg7IFBBRERJTkctTEVGVDogMTBweDsgRkxPQVQ6IGxlZnQ7IFBBRERJTkct +Qk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBWRVJUSUNBTC1BTElHTjogYm90dG9tOyBQQURESU5H +LVRPUDogMHB4Ij48QSANCiAgc3R5bGU9IkZPTlQtV0VJR0hUOiBib2xkOyBDT0xPUjogcmdiKDEw +LDYxLDE0MCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIGhyZWY9Imh0dHA6Ly9odW50ZXIu +Y3Nkbi5uZXQvIiB0YXJnZXQ9X2JsYW5rPueMjuWktDwvQT48L0xJPjwvVUw+PC9ESVY+PC9ESVY+ +DQo8RElWIGNsYXNzPSJtYW51ZmFjdHVyZXJfaW5kZXggdHh0X2dyYXkiIA0Kc3R5bGU9IkZMT0FU +OiBsZWZ0OyBNQVJHSU46IDBweCAwcHggMnB4OyBXSURUSDogOTYwcHg7IENPTE9SOiByZ2IoMTAy +LDEwMiwxMDIpOyBCQUNLR1JPVU5ELUNPTE9SOiByZ2IoMjQ1LDI0NSwyNDUpOyBURVhULUFMSUdO +OiBsZWZ0OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0 +aWFsIj4NCjxVTCANCnN0eWxlPSJQQURESU5HLVJJR0hUOiAzcHg7IFBBRERJTkctTEVGVDogM3B4 +OyBGTE9BVDogbGVmdDsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IFdJRFRIOiA5 +NTRweDsgTElORS1IRUlHSFQ6IDIxcHg7IFBBRERJTkctVE9QOiAwcHg7IExJU1QtU1RZTEUtVFlQ +RTogbm9uZSI+DQogIDxMSSANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgUEFERElORy1M +RUZUOiAwcHg7IEZMT0FUOiBsZWZ0OyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweDsg +UEFERElORy1UT1A6IDBweCI+PEEgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiA0cHg7IFBBRERJ +TkctTEVGVDogNHB4OyBQQURESU5HLUJPVFRPTTogMHB4OyBDT0xPUjogcmdiKDEwMiwxMDIsMTAy +KTsgUEFERElORy1UT1A6IDBweDsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgaHJlZj0iaHR0 +cDovLzNnLmVkdS5jc2RuLm5ldC8iIHRhcmdldD1fYmxhbms+M0flrabpmaI8L0E+fDwvTEk+DQog +IDxMSSANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgUEFERElORy1MRUZUOiAwcHg7IEZM +T0FUOiBsZWZ0OyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweDsgUEFERElORy1UT1A6 +IDBweCI+PEEgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiA0cHg7IFBBRERJTkctTEVGVDogNHB4 +OyBQQURESU5HLUJPVFRPTTogMHB4OyBDT0xPUjogcmdiKDEwMiwxMDIsMTAyKTsgUEFERElORy1U +T1A6IDBweDsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgaHJlZj0iaHR0cDovL3d3dy5pdGNh +c3QuY24vIiB0YXJnZXQ9X2JsYW5rPkphdmHlrabpmaI8L0E+fDwvTEk+DQogIDxMSSANCiAgc3R5 +bGU9IlBBRERJTkctUklHSFQ6IDBweDsgUEFERElORy1MRUZUOiAwcHg7IEZMT0FUOiBsZWZ0OyBQ +QURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweDsgUEFERElORy1UT1A6IDBweCI+PEEgDQog +IHN0eWxlPSJQQURESU5HLVJJR0hUOiA0cHg7IFBBRERJTkctTEVGVDogNHB4OyBQQURESU5HLUJP +VFRPTTogMHB4OyBDT0xPUjogcmdiKDEwMiwxMDIsMTAyKTsgUEFERElORy1UT1A6IDBweDsgVEVY +VC1ERUNPUkFUSU9OOiBub25lIiANCiAgaHJlZj0iaHR0cDovL25ldC5pdGNhc3QuY24vIiB0YXJn +ZXQ9X2JsYW5rPi5ORVTlrabpmaI8L0E+fDwvTEk+DQogIDxMSSANCiAgc3R5bGU9IlBBRERJTkct +UklHSFQ6IDBweDsgUEFERElORy1MRUZUOiAwcHg7IEZMT0FUOiBsZWZ0OyBQQURESU5HLUJPVFRP +TTogMHB4OyBNQVJHSU46IDBweDsgUEFERElORy1UT1A6IDBweCI+PEEgDQogIHN0eWxlPSJQQURE +SU5HLVJJR0hUOiA0cHg7IFBBRERJTkctTEVGVDogNHB4OyBQQURESU5HLUJPVFRPTTogMHB4OyBD +T0xPUjogcmdiKDEwMiwxMDIsMTAyKTsgUEFERElORy1UT1A6IDBweDsgVEVYVC1ERUNPUkFUSU9O +OiBub25lIiANCiAgaHJlZj0iaHR0cDovL3d3dy5sYW1wYnJvdGhlci5uZXQvIiB0YXJnZXQ9X2Js +YW5rPlBIUOWtpumZojwvQT58PC9MST4NCiAgPExJIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDog +MHB4OyBQQURESU5HLUxFRlQ6IDBweDsgRkxPQVQ6IGxlZnQ7IFBBRERJTkctQk9UVE9NOiAwcHg7 +IE1BUkdJTjogMHB4OyBQQURESU5HLVRPUDogMHB4Ij48QSANCiAgc3R5bGU9IlBBRERJTkctUklH +SFQ6IDRweDsgUEFERElORy1MRUZUOiA0cHg7IFBBRERJTkctQk9UVE9NOiAwcHg7IENPTE9SOiBy +Z2IoMTAyLDEwMiwxMDIpOyBQQURESU5HLVRPUDogMHB4OyBURVhULURFQ09SQVRJT046IG5vbmUi +IA0KICBocmVmPSJodHRwOi8vaWJtLmNzZG4ubmV0LyIgdGFyZ2V0PV9ibGFuaz5JQk0gZFc8L0E+ +fDwvTEk+DQogIDxMSSANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgUEFERElORy1MRUZU +OiAwcHg7IEZMT0FUOiBsZWZ0OyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweDsgUEFE +RElORy1UT1A6IDBweCI+PEEgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiA0cHg7IFBBRERJTkct +TEVGVDogNHB4OyBQQURESU5HLUJPVFRPTTogMHB4OyBDT0xPUjogcmdiKDEwMiwxMDIsMTAyKTsg +UEFERElORy1UT1A6IDBweDsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgaHJlZj0iaHR0cDov +L2ludGVsLmNzZG4ubmV0LyIgdGFyZ2V0PV9ibGFuaz7oi7HnibnlsJQg6L2v5Lu2PC9BPnw8L0xJ +Pg0KICA8TEkgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IFBBRERJTkctTEVGVDogMHB4 +OyBGTE9BVDogbGVmdDsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IFBBRERJTkct +VE9QOiAwcHgiPjxBIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogNHB4OyBQQURESU5HLUxFRlQ6 +IDRweDsgUEFERElORy1CT1RUT006IDBweDsgQ09MT1I6IHJnYigxMDIsMTAyLDEwMik7IFBBRERJ +TkctVE9QOiAwcHg7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIGhyZWY9Imh0dHA6Ly9nLmNz +ZG4ubmV0LzUwMjQzNTkiIHRhcmdldD1fYmxhbms+5a6J6IW+PC9BPjxBIA0KICBzdHlsZT0iUEFE +RElORy1SSUdIVDogNHB4OyBQQURESU5HLUxFRlQ6IDRweDsgUEFERElORy1CT1RUT006IDBweDsg +Q09MT1I6IHJnYigxMDIsMTAyLDEwMik7IFBBRERJTkctVE9QOiAwcHg7IFRFWFQtREVDT1JBVElP +Tjogbm9uZSIgDQogIGhyZWY9Imh0dHA6Ly94ZW9uLmNzZG4ubmV0LyIgdGFyZ2V0PV9ibGFuaz7o +h7PlvLo8L0E+fDwvTEk+DQogIDxMSSANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgUEFE +RElORy1MRUZUOiAwcHg7IEZMT0FUOiBsZWZ0OyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46 +IDBweDsgUEFERElORy1UT1A6IDBweCI+PEEgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiA0cHg7 +IFBBRERJTkctTEVGVDogNHB4OyBQQURESU5HLUJPVFRPTTogMHB4OyBDT0xPUjogcmdiKDEwMiwx +MDIsMTAyKTsgUEFERElORy1UT1A6IDBweDsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgaHJl +Zj0iaHR0cDovL21lZWdvem9uZS5jc2RuLm5ldC8iIHRhcmdldD1fYmxhbms+TWVlR288L0E+fDwv +TEk+DQogIDxMSSANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgUEFERElORy1MRUZUOiAw +cHg7IEZMT0FUOiBsZWZ0OyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweDsgUEFERElO +Ry1UT1A6IDBweCI+PEEgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiA0cHg7IFBBRERJTkctTEVG +VDogNHB4OyBQQURESU5HLUJPVFRPTTogMHB4OyBDT0xPUjogcmdiKDEwMiwxMDIsMTAyKTsgUEFE +RElORy1UT1A6IDBweDsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgaHJlZj0iaHR0cDovL29w +aG9uZS5jc2RuLm5ldC9taW5pc2l0ZSIgdGFyZ2V0PV9ibGFuaz5PUGhvbmU8L0E+fDwvTEk+DQog +IDxMSSANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgUEFERElORy1MRUZUOiAwcHg7IEZM +T0FUOiBsZWZ0OyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweDsgUEFERElORy1UT1A6 +IDBweCI+PEEgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiA0cHg7IFBBRERJTkctTEVGVDogNHB4 +OyBQQURESU5HLUJPVFRPTTogMHB4OyBDT0xPUjogcmdiKDEwMiwxMDIsMTAyKTsgUEFERElORy1U +T1A6IDBweDsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgaHJlZj0iaHR0cDovL2ZsZXguY3Nk +bi5uZXQvIiB0YXJnZXQ9X2JsYW5rPkZsZXgvQUlSPC9BPnw8L0xJPg0KICA8TEkgDQogIHN0eWxl +PSJQQURESU5HLVJJR0hUOiAwcHg7IFBBRERJTkctTEVGVDogMHB4OyBGTE9BVDogbGVmdDsgUEFE +RElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IFBBRERJTkctVE9QOiAwcHgiPjxBIA0KICBz +dHlsZT0iUEFERElORy1SSUdIVDogNHB4OyBQQURESU5HLUxFRlQ6IDRweDsgUEFERElORy1CT1RU +T006IDBweDsgQ09MT1I6IHJnYigxMDIsMTAyLDEwMik7IFBBRERJTkctVE9QOiAwcHg7IFRFWFQt +REVDT1JBVElPTjogbm9uZSIgDQogIGhyZWY9Imh0dHA6Ly9zdWJqZWN0LmNzZG4ubmV0L1ZTMjAx +MF90ZWMvIiB0YXJnZXQ9X2JsYW5rPlZTMjAxMDwvQT58PC9MST4NCiAgPExJIA0KICBzdHlsZT0i +UEFERElORy1SSUdIVDogMHB4OyBQQURESU5HLUxFRlQ6IDBweDsgRkxPQVQ6IGxlZnQ7IFBBRERJ +TkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBQQURESU5HLVRPUDogMHB4Ij48QSANCiAgc3R5 +bGU9IlBBRERJTkctUklHSFQ6IDRweDsgUEFERElORy1MRUZUOiA0cHg7IFBBRERJTkctQk9UVE9N +OiAwcHg7IENPTE9SOiByZ2IoMTAyLDEwMiwxMDIpOyBQQURESU5HLVRPUDogMHB4OyBURVhULURF +Q09SQVRJT046IG5vbmUiIA0KICBocmVmPSJodHRwOi8vcXQuY3Nkbi5uZXQvIiB0YXJnZXQ9X2Js +YW5rPlF0PC9BPnw8L0xJPg0KICA8TEkgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IFBB +RERJTkctTEVGVDogMHB4OyBGTE9BVDogbGVmdDsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lO +OiAwcHg7IFBBRERJTkctVE9QOiAwcHgiPjxBIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogNHB4 +OyBQQURESU5HLUxFRlQ6IDRweDsgUEFERElORy1CT1RUT006IDBweDsgQ09MT1I6IHJnYigxMDIs +MTAyLDEwMik7IFBBRERJTkctVE9QOiAwcHg7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIGhy +ZWY9Imh0dHA6Ly9iYWlkdS5jc2RuLm5ldC8iIHRhcmdldD1fYmxhbms+55m+5bqm56S+5Yy6PC9B +Pnw8L0xJPg0KICA8TEkgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IFBBRERJTkctTEVG +VDogMHB4OyBGTE9BVDogbGVmdDsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IFBB +RERJTkctVE9QOiAwcHgiPjxBIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogNHB4OyBQQURESU5H +LUxFRlQ6IDRweDsgUEFERElORy1CT1RUT006IDBweDsgQ09MT1I6IHJnYigxMDIsMTAyLDEwMik7 +IFBBRERJTkctVE9QOiAwcHg7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIGhyZWY9Imh0dHA6 +Ly9ibGFja2JlcnJ5LmNzZG4ubmV0LyIgdGFyZ2V0PV9ibGFuaz5CbGFja0JlcnJ5PC9BPnw8L0xJ +Pg0KICA8TEkgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IFBBRERJTkctTEVGVDogMHB4 +OyBGTE9BVDogbGVmdDsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IFBBRERJTkct +VE9QOiAwcHgiPjxBIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogNHB4OyBQQURESU5HLUxFRlQ6 +IDRweDsgUEFERElORy1CT1RUT006IDBweDsgQ09MT1I6IHJnYigxMDIsMTAyLDEwMik7IFBBRERJ +TkctVE9QOiAwcHg7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIGhyZWY9Imh0dHA6Ly9iYWRh +LmNzZG4ubmV0LyIgdGFyZ2V0PV9ibGFuaz5iYWRhPC9BPnw8L0xJPg0KICA8TEkgDQogIHN0eWxl +PSJQQURESU5HLVJJR0hUOiAwcHg7IFBBRERJTkctTEVGVDogMHB4OyBGTE9BVDogbGVmdDsgUEFE +RElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IFBBRERJTkctVE9QOiAwcHgiPjxBIA0KICBz +dHlsZT0iUEFERElORy1SSUdIVDogNHB4OyBQQURESU5HLUxFRlQ6IDRweDsgUEFERElORy1CT1RU +T006IDBweDsgQ09MT1I6IHJnYigxMDIsMTAyLDEwMik7IFBBRERJTkctVE9QOiAwcHg7IFRFWFQt +REVDT1JBVElPTjogbm9uZSIgDQogIGhyZWY9Imh0dHA6Ly9zbWkuY3Nkbi5uZXQvIiB0YXJnZXQ9 +X2JsYW5rPuS4ieaYn1NNSTwvQT58PC9MST4NCiAgPExJIA0KICBzdHlsZT0iUEFERElORy1SSUdI +VDogMHB4OyBQQURESU5HLUxFRlQ6IDBweDsgRkxPQVQ6IGxlZnQ7IFBBRERJTkctQk9UVE9NOiAw +cHg7IE1BUkdJTjogMHB4OyBQQURESU5HLVRPUDogMHB4Ij48QSANCiAgY2xhc3M9cmVkIA0KICBz +dHlsZT0iUEFERElORy1SSUdIVDogNHB4OyBQQURESU5HLUxFRlQ6IDRweDsgUEFERElORy1CT1RU +T006IDBweDsgQ09MT1I6IHJnYigyNTUsMCwwKTsgUEFERElORy1UT1A6IDBweDsgVEVYVC1ERUNP +UkFUSU9OOiBub25lIiANCiAgaHJlZj0iaHR0cDovLzE4OXdvcmtzLmNzZG4ubmV0LyIgdGFyZ2V0 +PV9ibGFuaz7lpKnnv7znqbrpl7Q8L0E+PC9MST48L1VMPjwvRElWPg0KPERJViBjbGFzcz1iYW5u +ZXJfdG9wMiANCnN0eWxlPSJCT1JERVItUklHSFQ6IHJnYigyMDQsMjA0LDIwNCkgMXB4IHNvbGlk +OyBQQURESU5HLVJJR0hUOiA1cHg7IEJPUkRFUi1UT1A6IHJnYigyMDQsMjA0LDIwNCkgMXB4IHNv +bGlkOyBQQURESU5HLUxFRlQ6IDVweDsgRkxPQVQ6IGxlZnQ7IFBBRERJTkctQk9UVE9NOiAwcHg7 +IEJPUkRFUi1MRUZUOiByZ2IoMjA0LDIwNCwyMDQpIDFweCBzb2xpZDsgV0lEVEg6IDk0OHB4OyBQ +QURESU5HLVRPUDogNHB4OyBCT1JERVItQk9UVE9NOiByZ2IoMjA0LDIwNCwyMDQpIDFweCBzb2xp +ZDsgVEVYVC1BTElHTjogbGVmdCI+DQo8VUwgY2xhc3M9Imxpc3R0eHRhZF9sZWZ0IHR4dF9kZWVw +Ymx1ZSIgDQpzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBQQURESU5HLUxFRlQ6IDBweDsgRkxP +QVQ6IGxlZnQ7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogM3B4IDBweCAwcHg7IFdJRFRI +OiAxODVweDsgQ09MT1I6IHJnYigwLDUxLDIwNCk7IFBBRERJTkctVE9QOiAwcHg7IExJU1QtU1RZ +TEUtVFlQRTogbm9uZSI+DQogIDxMSSANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFD +S0dST1VORC1QT1NJVElPTjogMHB4IDhweDsgUEFERElORy1MRUZUOiA5cHg7IEJBQ0tHUk9VTkQt +SU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWM1Lmdp +Zik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBQQURESU5HLVRPUDogMHB4OyBi +YWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSAN +CiAgc3R5bGU9IkNPTE9SOiByZ2IoMCw1MSwyMDQpOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0K +ICBocmVmPSJodHRwOi8vei5jc2RuLm5ldC9nbWNsaWNrLnBocD9iYW5uZXJpZD0zNDY5JmFtcDt6 +b25laWQ9NDExJmFtcDtzb3VyY2U9JmFtcDtkZXN0PWh0dHAlM0ElMkYlMkZ3d3cuZW1iZWR1Lm9y +ZyUyRmtvdWJlaSUyRmluZGV4Lmh0bSIgDQogIHRhcmdldD1fYmxhbms+44CQ6aG244CR5bqU5bGK +55SfLOWFpeiBjOW5tOiWqjUtMTDkuIc8L0E+PC9MST4NCiAgPExJIA0KICBzdHlsZT0iUEFERElO +Ry1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAwcHggOHB4OyBQQURESU5HLUxFRlQ6 +IDlweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMv +Y3NkbmluZGV4X3BpYzUuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IFBB +RERJTkctVE9QOiAwcHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNs +aXA6IGluaXRpYWwiPjxBIA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDUxLDIwNCk7IFRFWFQtREVD +T1JBVElPTjogbm9uZSIgDQogIGhyZWY9Imh0dHA6Ly96LmNzZG4ubmV0L2dtY2xpY2sucGhwP2Jh +bm5lcmlkPTQ4NTYmYW1wO3pvbmVpZD00MTImYW1wO3NvdXJjZT0mYW1wO2Rlc3Q9aHR0cCUzQSUy +RiUyRnd3dy51Y2FuY29kZS5uZXQlMkZjc21haW4uaHRtIiANCiAgdGFyZ2V0PV9ibGFuaz7mlrBW +QysrIDIwMTDlm77lvaLmupDnoIHlupPnrKwz54mIITwvQT48L0xJPg0KICA8TEkgDQogIHN0eWxl +PSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDBweCA4cHg7IFBBRERJ +TkctTEVGVDogOXB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3 +L2ltYWdlcy9jc2RuaW5kZXhfcGljNS5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46 +IDBweDsgUEFERElORy1UT1A6IDBweDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tn +cm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHN0eWxlPSJDT0xPUjogcmdiKDAsNTEsMjA0KTsg +VEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgaHJlZj0iaHR0cDovL3ouY3Nkbi5uZXQvZ21jbGlj +ay5waHA/YmFubmVyaWQ9NTAzNiZhbXA7em9uZWlkPTQxMyZhbXA7c291cmNlPSZhbXA7ZGVzdD1o +dHRwJTNBJTJGJTJGd3d3LmJqdGFyZW5hLmNvbSUyRmNweC5odG1sIiANCiAgdGFyZ2V0PV9ibGFu +az7kuI3mh4JDKyvkuI3mmK/nnJ/mraPnmoTnqIvluo/lkZjvvIE8L0E+PC9MST4NCiAgPExJIA0K +ICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAwcHggOHB4 +OyBQQURESU5HLUxFRlQ6IDlweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1n +LmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzUuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsg +TUFSR0lOOiAwcHg7IFBBRERJTkctVE9QOiAwcHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFs +OyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDUx +LDIwNCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIGhyZWY9Imh0dHA6Ly96LmNzZG4ubmV0 +L2dtY2xpY2sucGhwP2Jhbm5lcmlkPTU0MjQmYW1wO3pvbmVpZD00MTQmYW1wO3NvdXJjZT0mYW1w +O2Rlc3Q9aHR0cCUzQSUyRiUyRmV2ZW50cy51bmlzZmFpci5jb20lMkZydCUyRmlibSU3RXJhdGlv +bmFsJTJGaW5kZXguanNwJTNGbGMlM0R6aCUyNmNjJTNEY24lMjZjb2RlJTNEY3NkbiIgDQogIHRh +cmdldD1fYmxhbms+5oql5ZCNSUJN5byA5Y+R6ICF5aSn5Lya6LWi5aSa56eN5aSn5aWWPC9BPjwv +TEk+DQogIDxMSSANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJ +VElPTjogMHB4IDhweDsgUEFERElORy1MRUZUOiA5cHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybCho +dHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWM1LmdpZik7IFBBRERJTkct +Qk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBQQURESU5HLVRPUDogMHB4OyBiYWNrZ3JvdW5kLW9y +aWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgc3R5bGU9IkNP +TE9SOiByZ2IoMCw1MSwyMDQpOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBocmVmPSJodHRw +Oi8vei5jc2RuLm5ldC9nbWNsaWNrLnBocD9iYW5uZXJpZD01MzUyJmFtcDt6b25laWQ9NDE1JmFt +cDtzb3VyY2U9JmFtcDtkZXN0PWh0dHAlM0ElMkYlMkZ3d3cud2lidS5jb20uY24lMkZOZXdXZWIl +MkZ3aWJ1JTJGZXZlbnRzLnBocC5odG0iIA0KICB0YXJnZXQ9X2JsYW5rPkNvZGVNZXRlcui9r+S7 +tuWKoOWvhuaKgOacr+eglOiuqOS8mjwvQT48L0xJPjwvVUw+DQo8VUwgY2xhc3M9bGlzdGFkX21p +ZCANCnN0eWxlPSJQQURESU5HLVJJR0hUOiA5cHg7IFBBRERJTkctTEVGVDogOXB4OyBGTE9BVDog +bGVmdDsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IFdJRFRIOiA1NjBweDsgUEFE +RElORy1UT1A6IDBweDsgTElTVC1TVFlMRS1UWVBFOiBub25lIj4NCiAgPExJIA0KICBzdHlsZT0i +UEFERElORy1SSUdIVDogMHB4OyBQQURESU5HLUxFRlQ6IDBweDsgUEFERElORy1CT1RUT006IDBw +eDsgTUFSR0lOOiAwcHg7IFBBRERJTkctVE9QOiAwcHgiPjxBIA0KICBzdHlsZT0iQ09MT1I6IHJn +YigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIGhyZWY9Imh0dHA6Ly96LmNzZG4u +bmV0L2dtY2xpY2sucGhwP2Jhbm5lcmlkPTUzMTcmYW1wO3pvbmVpZD00MDQmYW1wO3NvdXJjZT0m +YW1wO2Rlc3Q9aHR0cCUzQSUyRiUyRm9wZXIuMTg5d29ya3MuY29tJTJGbmV3cyUyRlByb21vdGlv +bi5qc3AiIA0KICB0YXJnZXQ9X2JsYW5rPjxJTUcgdGl0bGU9IiIgDQogIHN0eWxlPSJCT1JERVIt +VE9QLVdJRFRIOiAwcHg7IEJPUkRFUi1MRUZULVdJRFRIOiAwcHg7IEJPUkRFUi1CT1RUT00tV0lE +VEg6IDBweDsgQk9SREVSLVJJR0hULVdJRFRIOiAwcHgiIA0KICBoZWlnaHQ9OTUgYWx0PSIiIA0K +ICBzcmM9Imh0dHA6Ly9pbmZvLWRhdGFiYXNlLmNzZG4ubmV0L1VwbG9hZC8yMDEwLTExLTIzLzU2 +MF85NV93cl8xMTIzLmdpZiIgDQogIHdpZHRoPTU2MCBib3JkZXI9MD48L0E+DQogIDxESVYgaWQ9 +YmVhY29uXzUzMTcgDQogIHN0eWxlPSJMRUZUOiAwcHg7IFZJU0lCSUxJVFk6IGhpZGRlbjsgUE9T +SVRJT046IGFic29sdXRlOyBUT1A6IDBweCI+PElNRyANCiAgc3R5bGU9IkJPUkRFUi1UT1AtV0lE +VEg6IDBweDsgQk9SREVSLUxFRlQtV0lEVEg6IDBweDsgQk9SREVSLUJPVFRPTS1XSURUSDogMHB4 +OyBXSURUSDogMHB4OyBIRUlHSFQ6IDBweDsgQk9SREVSLVJJR0hULVdJRFRIOiAwcHgiIA0KICBo +ZWlnaHQ9MCBhbHQ9IiIgDQogIHNyYz0iaHR0cDovL3ouY3Nkbi5uZXQvZ21sb2cucGhwP2Jhbm5l +cmlkPTUzMTcmYW1wO2NsaWVudGlkPTE1NDgmYW1wO3pmPSZhbXA7em9uZWlkPTQwNCZhbXA7c291 +cmNlPSZhbXA7YmxvY2s9MCZhbXA7Y2FwcGluZz0wJmFtcDtjYj0yZjRkMWU5N2UyNzVlNjM5ODE0 +NDM2NDNmZWY4OGMwMSIgDQogIHdpZHRoPTA+PC9ESVY+PC9MST48L1VMPg0KPFVMIGNsYXNzPSJs +aXN0dHh0YWRfbGVmdCB0eHRfZGVlcGJsdWUiIA0Kc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsg +UEFERElORy1MRUZUOiAwcHg7IEZMT0FUOiBsZWZ0OyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJH +SU46IDNweCAwcHggMHB4OyBXSURUSDogMTg1cHg7IENPTE9SOiByZ2IoMCw1MSwyMDQpOyBQQURE +SU5HLVRPUDogMHB4OyBMSVNULVNUWUxFLVRZUEU6IG5vbmUiPg0KICA8TEkgDQogIHN0eWxlPSJQ +QURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDBweCA4cHg7IFBBRERJTkct +TEVGVDogOXB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2lt +YWdlcy9jc2RuaW5kZXhfcGljNS5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBw +eDsgUEFERElORy1UT1A6IDBweDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91 +bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHN0eWxlPSJDT0xPUjogcmdiKDAsNTEsMjA0KTsgVEVY +VC1ERUNPUkFUSU9OOiBub25lIiANCiAgaHJlZj0iaHR0cDovL3ouY3Nkbi5uZXQvZ21jbGljay5w +aHA/YmFubmVyaWQ9NTQ0MiZhbXA7em9uZWlkPTQxNiZhbXA7c291cmNlPSZhbXA7ZGVzdD1odHRw +JTNBJTJGJTJGbXNkbi5taWNyb3NvZnQuY29tJTJGemgtY24lMkZ3aW5kb3dzcGhvbmUlMkZkZWZh +dWx0LmFzcHglM0ZvY2lkJTNEYmFuLW4tY24td3A3LS1jc2RuKyIgDQogIHRhcmdldD1fYmxhbms+ +5L2/55SoWE5B5qGG5p626L+b6KGMM0TmuLjmiI/lvIDlj5E8L0E+PC9MST4NCiAgPExJIA0KICBz +dHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAwcHggOHB4OyBQ +QURESU5HLUxFRlQ6IDlweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNu +L3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzUuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFS +R0lOOiAwcHg7IFBBRERJTkctVE9QOiAwcHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBi +YWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDUxLDIw +NCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIGhyZWY9Imh0dHA6Ly96LmNzZG4ubmV0L2dt +Y2xpY2sucGhwP2Jhbm5lcmlkPTUyMTImYW1wO3pvbmVpZD00MTcmYW1wO3NvdXJjZT0mYW1wO2Rl +c3Q9aHR0cCUzQSUyRiUyRnd3dy5sYW1wYnJvdGhlci5uZXQlMkZpbnRyby5odG1sIiANCiAgdGFy +Z2V0PV9ibGFuaz5QSFDlrabkuaDvvIzlhYjlsLHkuJrvvIzlkI7liIbmnJ/ov5jmrL48L0E+PC9M +ST4NCiAgPExJIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lU +SU9OOiAwcHggOHB4OyBQQURESU5HLUxFRlQ6IDlweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0 +dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzUuZ2lmKTsgUEFERElORy1C +T1RUT006IDBweDsgTUFSR0lOOiAwcHg7IFBBRERJTkctVE9QOiAwcHg7IGJhY2tncm91bmQtb3Jp +Z2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICBzdHlsZT0iQ09M +T1I6IHJnYigwLDUxLDIwNCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIGhyZWY9Imh0dHA6 +Ly96LmNzZG4ubmV0L2dtY2xpY2sucGhwP2Jhbm5lcmlkPTU0MDkmYW1wO3pvbmVpZD00MTgmYW1w +O3NvdXJjZT0mYW1wO2Rlc3Q9aHR0cCUzQSUyRiUyRmcuY3Nkbi5uZXQlMkY1MTYzNTAwIiANCiAg +dGFyZ2V0PV9ibGFuaz7msLTms6LmlYjlupRBbmRyb2lk5rqQ56CBPC9BPjwvTEk+DQogIDxMSSAN +CiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMHB4IDhw +eDsgUEFERElORy1MRUZUOiA5cHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3Nkbmlt +Zy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWM1LmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7 +IE1BUkdJTjogMHB4OyBQQURESU5HLVRPUDogMHB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlh +bDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCw1 +MSwyMDQpOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBocmVmPSJodHRwOi8vei5jc2RuLm5l +dC9nbWNsaWNrLnBocD9iYW5uZXJpZD01Mzc3JmFtcDt6b25laWQ9NDE5JmFtcDtzb3VyY2U9JmFt +cDtkZXN0PStodHRwJTNBJTJGJTJGYmFtYm9vay5zZG8uY29tJTJGaW5kZXguYXNweCUzRmFkaWQl +M0QxMDEwJTI2cmVkaXJlY3VybCUzRGh0dHAlM0ElMkYlMkZldmVudHMuY3Nkbi5uZXQlMkZCQU1C +T09LJTJGaW5kZXguaHRtKyIgDQogIHRhcmdldD1fYmxhbms+NjDkuIflpZbph5FWU+ebm+Wkp+eo +i+W6j+i+vuS6uui1mzwvQT48L0xJPg0KICA8TEkgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAw +cHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDBweCA4cHg7IFBBRERJTkctTEVGVDogOXB4OyBCQUNL +R1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhf +cGljNS5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweDsgUEFERElORy1UT1A6 +IDBweDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlh +bCI+PEEgDQogIHN0eWxlPSJDT0xPUjogcmdiKDAsNTEsMjA0KTsgVEVYVC1ERUNPUkFUSU9OOiBu +b25lIiANCiAgaHJlZj0iaHR0cDovL3ouY3Nkbi5uZXQvZ21jbGljay5waHA/YmFubmVyaWQ9NDc3 +OCZhbXA7em9uZWlkPTQyMCZhbXA7c291cmNlPSZhbXA7ZGVzdD1odHRwJTNBJTJGJTJGd3d3Lml0 +Y2FzdC5jbiUyRml0Y2FzdF9zdGF0aWMlMkYzRy5odG1sIiANCiAgdGFyZ2V0PV9ibGFuaz445aSp +6L2s5Z6LM0fvvIzmnIjolqo0S+WPmDhLPC9BPjwvTEk+PC9VTD48L0RJVj4NCjxESVYgY2xhc3M9 +YmFubmVyX3RvcDMgDQpzdHlsZT0iRkxPQVQ6IGxlZnQ7IE1BUkdJTjogMnB4IDBweDsgV0lEVEg6 +IDk2MHB4OyBURVhULUFMSUdOOiBsZWZ0Ij4NCjxVTCANCnN0eWxlPSJQQURESU5HLVJJR0hUOiAw +cHg7IFBBRERJTkctTEVGVDogMHB4OyBGTE9BVDogbGVmdDsgUEFERElORy1CT1RUT006IDBweDsg +TUFSR0lOOiAwcHg7IFdJRFRIOiA5NjBweDsgUEFERElORy1UT1A6IDBweDsgTElTVC1TVFlMRS1U +WVBFOiBub25lOyBIRUlHSFQ6IDYwcHgiPg0KICA8TEkgY2xhc3M9bGVmdCANCiAgc3R5bGU9IlBB +RERJTkctUklHSFQ6IDBweDsgRElTUExBWTogaW5saW5lOyBQQURESU5HLUxFRlQ6IDBweDsgRkxP +QVQ6IGxlZnQ7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4IDEwcHggMHB4IDBweDsg +UEFERElORy1UT1A6IDBweCI+PEEgDQogIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1E +RUNPUkFUSU9OOiBub25lIiANCiAgaHJlZj0iaHR0cDovL3ouY3Nkbi5uZXQvZ21jbGljay5waHA/ +YmFubmVyaWQ9NTM2NiZhbXA7em9uZWlkPTQwNSZhbXA7c291cmNlPSZhbXA7ZGVzdD1odHRwJTNB +JTJGJTJGd3d3Lm9waG9uZXNkbi5jb20lMkZwcm9qZWN0JTJGaW5kZXgiIA0KICB0YXJnZXQ9X2Js +YW5rPjxJTUcgdGl0bGU9IiIgDQogIHN0eWxlPSJCT1JERVItVE9QLVdJRFRIOiAwcHg7IEJPUkRF +Ui1MRUZULVdJRFRIOiAwcHg7IEJPUkRFUi1CT1RUT00tV0lEVEg6IDBweDsgQk9SREVSLVJJR0hU +LVdJRFRIOiAwcHgiIA0KICBoZWlnaHQ9NjAgYWx0PSIiIA0KICBzcmM9Imh0dHA6Ly9pbmZvLWRh +dGFiYXNlLmNzZG4ubmV0L1VwbG9hZC8yMDEwLTExLTE3LzQ3NV82MF9vcGhvbmV6LmpwZyIgDQog +IHdpZHRoPTQ3NSBib3JkZXI9MD48L0E+DQogIDxESVYgaWQ9YmVhY29uXzUzNjYgDQogIHN0eWxl +PSJMRUZUOiAwcHg7IFZJU0lCSUxJVFk6IGhpZGRlbjsgUE9TSVRJT046IGFic29sdXRlOyBUT1A6 +IDBweCI+PElNRyANCiAgc3R5bGU9IkJPUkRFUi1UT1AtV0lEVEg6IDBweDsgQk9SREVSLUxFRlQt +V0lEVEg6IDBweDsgQk9SREVSLUJPVFRPTS1XSURUSDogMHB4OyBXSURUSDogMHB4OyBIRUlHSFQ6 +IDBweDsgQk9SREVSLVJJR0hULVdJRFRIOiAwcHgiIA0KICBoZWlnaHQ9MCBhbHQ9IiIgDQogIHNy +Yz0iaHR0cDovL3ouY3Nkbi5uZXQvZ21sb2cucGhwP2Jhbm5lcmlkPTUzNjYmYW1wO2NsaWVudGlk +PTE2ODMmYW1wO3pmPSZhbXA7em9uZWlkPTQwNSZhbXA7c291cmNlPSZhbXA7YmxvY2s9MCZhbXA7 +Y2FwcGluZz0wJmFtcDtjYj1lODJkMTE1MWNiMWEyZTBjY2ZhMGYyZWViNjZhNTA5ZSIgDQogIHdp +ZHRoPTA+PC9ESVY+PC9MST4NCiAgPExJIGNsYXNzPXJpZ2h0IA0KICBzdHlsZT0iUEFERElORy1S +SUdIVDogMHB4OyBQQURESU5HLUxFRlQ6IDBweDsgRkxPQVQ6IHJpZ2h0OyBQQURESU5HLUJPVFRP +TTogMHB4OyBNQVJHSU46IDBweDsgV0lEVEg6IDQ3NXB4OyBQQURESU5HLVRPUDogMHB4Ij48QSAN +CiAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBo +cmVmPSJodHRwOi8vei5jc2RuLm5ldC9nbWNsaWNrLnBocD9iYW5uZXJpZD00NzM4JmFtcDt6b25l +aWQ9NDA2JmFtcDtzb3VyY2U9JmFtcDtkZXN0PWh0dHAlM0ElMkYlMkZqb2JzLmNuY2MuY24lMkYi +IA0KICB0YXJnZXQ9X2JsYW5rPjxJTUcgdGl0bGU9IiIgDQogIHN0eWxlPSJCT1JERVItVE9QLVdJ +RFRIOiAwcHg7IEJPUkRFUi1MRUZULVdJRFRIOiAwcHg7IEJPUkRFUi1CT1RUT00tV0lEVEg6IDBw +eDsgQk9SREVSLVJJR0hULVdJRFRIOiAwcHgiIA0KICBoZWlnaHQ9NjAgYWx0PSIiIHNyYz0iaHR0 +cDovL3ppLmNzZG4ubmV0L3JlbjQ3NS02MC5naWYiIHdpZHRoPTQ3NSANCmJvcmRlcj0wPjwvQT4N +CiAgPERJViBpZD1iZWFjb25fNDczOCANCiAgc3R5bGU9IkxFRlQ6IDBweDsgVklTSUJJTElUWTog +aGlkZGVuOyBQT1NJVElPTjogYWJzb2x1dGU7IFRPUDogMHB4Ij48SU1HIA0KICBzdHlsZT0iQk9S +REVSLVRPUC1XSURUSDogMHB4OyBCT1JERVItTEVGVC1XSURUSDogMHB4OyBCT1JERVItQk9UVE9N +LVdJRFRIOiAwcHg7IFdJRFRIOiAwcHg7IEhFSUdIVDogMHB4OyBCT1JERVItUklHSFQtV0lEVEg6 +IDBweCIgDQogIGhlaWdodD0wIGFsdD0iIiANCiAgc3JjPSJodHRwOi8vei5jc2RuLm5ldC9nbWxv +Zy5waHA/YmFubmVyaWQ9NDczOCZhbXA7Y2xpZW50aWQ9MTQ2NyZhbXA7emY9JmFtcDt6b25laWQ9 +NDA2JmFtcDtzb3VyY2U9JmFtcDtibG9jaz0wJmFtcDtjYXBwaW5nPTAmYW1wO2NiPTM0YjE3MzFi +YTM4OGYyNDY5MTU1OTUzOGI0OWYyMjIwIiANCiAgd2lkdGg9MD48L0RJVj48L0xJPjwvVUw+PC9E +SVY+DQo8RElWIGNsYXNzPXBhZ2Vjb25fbGF5ZXIxIA0Kc3R5bGU9IkZMT0FUOiBsZWZ0OyBCQUNL +R1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhf +cGljNi5naWYpOyBXSURUSDogOTYwcHg7IFBPU0lUSU9OOiByZWxhdGl2ZTsgYmFja2dyb3VuZC1v +cmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+DQo8RElWIGNsYXNzPSJw +YWdlY29uX2xheWVyMV9sZWZ0IGhzbGljZSIgaWQ9Y3NkbmhlYWRsaW5lIA0Kc3R5bGU9IkJPUkRF +Ui1UT1A6IHJnYigxNzUsMTc1LDE3NSkgMXB4IHNvbGlkOyBESVNQTEFZOiBpbmxpbmU7IEZMT0FU +OiBsZWZ0OyBNQVJHSU46IDBweCAwcHggMHB4IDFweDsgV0lEVEg6IDUzNXB4OyBURVhULUFMSUdO +OiBsZWZ0Ij48U1BBTiANCnN0eWxlPSJESVNQTEFZOiBibG9jazsgQkFDS0dST1VORC1JTUFHRTog +dXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzcuZ2lmKTsgV0lE +VEg6IDUzNXB4OyBQT1NJVElPTjogcmVsYXRpdmU7IEhFSUdIVDogMjZweDsgYmFja2dyb3VuZC1v +cmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PENJVEUgDQpzdHlsZT0i +UEFERElORy1SSUdIVDogNXB4OyBESVNQTEFZOiBpbmxpbmU7IFBBRERJTkctTEVGVDogNXB4OyBG +TE9BVDogbGVmdDsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAzcHggMHB4IDBweCA1cHg7 +IENPTE9SOiByZ2IoMjU1LDI1NSwyNTUpOyBMSU5FLUhFSUdIVDogMTlweDsgUEFERElORy1UT1A6 +IDBweDsgRk9OVC1TVFlMRTogbm9ybWFsOyBCQUNLR1JPVU5ELUNPTE9SOiByZ2IoMjE4LDM3LDI4 +KTsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+ +5LuK5pel5aS05p2hPC9DSVRFPjxERk4gDQpzdHlsZT0iRkxPQVQ6IHJpZ2h0OyBNQVJHSU46IDBw +eDsgRk9OVC1TVFlMRTogbm9ybWFsIj48L0RGTj48L1NQQU4+DQo8RElWIGNsYXNzPSJsYXllcjFf +Y29udGVudHMgZW50cnktY29udGVudCIgDQpzdHlsZT0iUEFERElORy1SSUdIVDogMTVweDsgUEFE +RElORy1MRUZUOiAxNXB4OyBQQURESU5HLUJPVFRPTTogMHB4OyBQQURESU5HLVRPUDogMTBweCI+ +DQo8SDEgY2xhc3M9dHh0X2JsYWNrIA0Kc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgUEFERElO +Ry1MRUZUOiAwcHg7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogN3B4IDBweDsgRk9OVDog +Ym9sZCAxN3B4ICdNaWNyb3NvZnQgWWFoZWknLCBzYW5zLXNlcmlmOyBDT0xPUjogcmdiKDAsMCww +KTsgUEFERElORy1UT1A6IDBweCI+PEEgDQp0aXRsZT0iRmFjZWJvb2sgQ0VP5b2T6YCJMjAxMOOA +iuaXtuS7o+OAi+W5tOW6pumjjuS6keS6uueJqSIgDQpzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7 +IFRFWFQtREVDT1JBVElPTjogbm9uZSIgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsNzEpOyAN +CmhyZWY9Imh0dHA6Ly9uZXdzLmNzZG4ubmV0L2EvMjAxMDEyMTYvMjgzOTgyLmh0bWwiIHRhcmdl +dD1fYmxhbms+RmFjZWJvb2sgDQpDRU/lvZPpgIkyMDEw44CK5pe25Luj44CL5bm05bqm6aOO5LqR +5Lq654mpPC9BPjwvSDE+DQo8UCBjbGFzcz0iaG90bGluayB0eHRfYmx1ZSIgDQpzdHlsZT0iUEFE +RElORy1SSUdIVDogMHB4OyBQQURESU5HLUxFRlQ6IDBweDsgUEFERElORy1CT1RUT006IDBweDsg +TUFSR0lOOiAycHggMHB4IDBweDsgQ09MT1I6IHJnYig1MSw1MSw1MSk7IExJTkUtSEVJR0hUOiAy +MXB4OyBQQURESU5HLVRPUDogMHB4Ij48QSANCnN0eWxlPSJQQURESU5HLVJJR0hUOiAzcHg7IFBB +RERJTkctTEVGVDogMHB4OyBQQURESU5HLUJPVFRPTTogMHB4OyBDT0xPUjogcmdiKDEsOTUsMTgy +KTsgUEFERElORy1UT1A6IDBweDsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCm9uY2xpY2s9TG9n +Q2xpY2tDb3VudCh0aGlzLDcxKTsgDQpocmVmPSJodHRwOi8vbmV3cy5jc2RuLm5ldC9hLzIwMTAx +MjE1LzI4MzY4NC5odG1sIiANCnRhcmdldD1fYmxhbms+W0ZhY2Vib29r5Lyw5YC8M+S4quaciOWi +numVvzc3JSDkvLDlgLzovr40MzDkur/nvo7lhYNdPC9BPjxBIA0Kc3R5bGU9IlBBRERJTkctUklH +SFQ6IDNweDsgUEFERElORy1MRUZUOiAwcHg7IFBBRERJTkctQk9UVE9NOiAwcHg7IENPTE9SOiBy +Z2IoMSw5NSwxODIpOyBQQURESU5HLVRPUDogMHB4OyBURVhULURFQ09SQVRJT046IG5vbmUiIA0K +b25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsNzEpOyANCmhyZWY9Imh0dHA6Ly9uZXdzLmNzZG4u +bmV0L2EvMjAxMDEyMDcvMjgzMTE3Lmh0bWwiIA0KdGFyZ2V0PV9ibGFuaz5b5q+P5pel6YKu5oql +77ya6LC35q2M5ZKMRmFjZWJvb2vnmoTmiJjkuoldPC9BPjxCUj48QSANCnN0eWxlPSJQQURESU5H +LVJJR0hUOiAzcHg7IFBBRERJTkctTEVGVDogMHB4OyBQQURESU5HLUJPVFRPTTogMHB4OyBDT0xP +UjogcmdiKDEsOTUsMTgyKTsgUEFERElORy1UT1A6IDBweDsgVEVYVC1ERUNPUkFUSU9OOiBub25l +IiANCm9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDcxKTsgDQpocmVmPSJodHRwOi8vY2xvdWQu +Y3Nkbi5uZXQvYS8yMDEwMTIwOS8yODMyODkuaHRtbCIgDQp0YXJnZXQ9X2JsYW5rPlvml7bku6Pl +kajliIrvvJrnu7Tln7rop6Plr4blsIbotaLlvpfkv6Hmga/miJjkuoldPC9BPjxBIA0Kc3R5bGU9 +IlBBRERJTkctUklHSFQ6IDNweDsgUEFERElORy1MRUZUOiAwcHg7IFBBRERJTkctQk9UVE9NOiAw +cHg7IENPTE9SOiByZ2IoMSw5NSwxODIpOyBQQURESU5HLVRPUDogMHB4OyBURVhULURFQ09SQVRJ +T046IG5vbmUiIA0Kb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsNzEpOyANCmhyZWY9Imh0dHA6 +Ly9tb2JpbGUuY3Nkbi5uZXQvbi8yMDEwMTIxMy8yODM0NzguaHRtbCIgDQp0YXJnZXQ9X2JsYW5r +PlvjgIrml7bku6PlkajliIrjgIvor4Tlh7oyMDEw5bm05Y2B5aSnaVBob25l5bqU55SoXTwvQT48 +L1A+DQo8SDEgY2xhc3M9dHh0X2JsYWNrIA0Kc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgUEFE +RElORy1MRUZUOiAwcHg7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogN3B4IDBweDsgRk9O +VDogYm9sZCAxN3B4ICdNaWNyb3NvZnQgWWFoZWknLCBzYW5zLXNlcmlmOyBDT0xPUjogcmdiKDAs +MCwwKTsgUEFERElORy1UT1A6IDBweCI+PEEgDQp0aXRsZT1b5Y2a5a6iXemrmOaViOWtmOWCqOaK +gOacr+eglOeptiBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9u +ZSIgDQpvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw3MSk7IA0KaHJlZj0iaHR0cDovL2Jsb2cu +Y3Nkbi5uZXQvbGl1YmVuL2FyY2hpdmUvMjAxMC8xMi8wOC82MDY0MDQ1LmFzcHgiIA0KdGFyZ2V0 +PV9ibGFuaz5b5Y2a5a6iXemrmOaViOWtmOWCqOaKgOacr+eglOeptjwvQT48L0gxPg0KPFAgY2xh +c3M9ImhvdGxpbmsgdHh0X2JsdWUiIA0Kc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgUEFERElO +Ry1MRUZUOiAwcHg7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMnB4IDBweCAwcHg7IENP +TE9SOiByZ2IoNTEsNTEsNTEpOyBMSU5FLUhFSUdIVDogMjFweDsgUEFERElORy1UT1A6IDBweCI+ +PEEgDQpzdHlsZT0iUEFERElORy1SSUdIVDogM3B4OyBQQURESU5HLUxFRlQ6IDBweDsgUEFERElO +Ry1CT1RUT006IDBweDsgQ09MT1I6IHJnYigxLDk1LDE4Mik7IFBBRERJTkctVE9QOiAwcHg7IFRF +WFQtREVDT1JBVElPTjogbm9uZSIgDQpvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw3MSk7IA0K +aHJlZj0iaHR0cDovL2Jsb2cuY3Nkbi5uZXQvU21hcnRUb255L2FyY2hpdmUvMjAxMC8wOS8wOS81 +ODc0NDg1LmFzcHgiIA0KdGFyZ2V0PV9ibGFuaz5b6auY5bm25Y+R6auY5rWB6YeP572R56uZ5p62 +5p6EXTwvQT48QSANCnN0eWxlPSJQQURESU5HLVJJR0hUOiAzcHg7IFBBRERJTkctTEVGVDogMHB4 +OyBQQURESU5HLUJPVFRPTTogMHB4OyBDT0xPUjogcmdiKDEsOTUsMTgyKTsgUEFERElORy1UT1A6 +IDBweDsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCm9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlz +LDcxKTsgDQpocmVmPSJodHRwOi8vYmxvZy5jc2RuLm5ldC9iYW9xaWFuZ3dhbmcvYXJjaGl2ZS8y +MDEwLzA3LzA4LzU3MjA3MzAuYXNweCIgDQp0YXJnZXQ9X2JsYW5rPlvlhbPkuo7mlbDmja7mjJbm +jpjlhbPogZTop4TliJnnmoRPcmFjbGXlrp7njrBdPC9BPjwvUD4NCjxQIGNsYXNzPXJldmlldyAN +CnN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IFBBRERJTkctTEVGVDogMHB4OyBGT05ULVNJWkU6 +IDEycHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2Vz +L2NzZG5pbmRleF9waWMzMi5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDVweCAw +cHg7IENPTE9SOiByZ2IoNTEsNTEsNTEpOyBMSU5FLUhFSUdIVDogMjNweDsgUEFERElORy1UT1A6 +IDBweDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlh +bCI+5b6A5pyf5aS05p2h77yaPEEgDQp0aXRsZT0iR21haWzkuYvniLbvvJpDaHJvbWUgT1PmnaXm +l6Xml6DlpJoiIA0Kc3R5bGU9IlBBRERJTkctUklHSFQ6IDNweDsgUEFERElORy1MRUZUOiAzcHg7 +IFBBRERJTkctQk9UVE9NOiAwcHg7IENPTE9SOiByZ2IoMCwwLDApOyBQQURESU5HLVRPUDogMHB4 +OyBURVhULURFQ09SQVRJT046IHVuZGVybGluZSIgDQpvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhp +cyw3MSk7IA0KaHJlZj0iaHR0cDovL25ld3MuY3Nkbi5uZXQvYS8yMDEwMTIxNS8yODM2NjYuaHRt +bCIgdGFyZ2V0PV9ibGFuaz5HbWFpbOS5i+eItu+8mkNocm9tZSANCk9T5p2l5pel5peg5aSaPC9B +PiZuYnNwOyZuYnNwOyZuYnNwOzxTUEFOIGNsYXNzPUFwcGxlLWNvbnZlcnRlZC1zcGFjZT4mbmJz +cDs8L1NQQU4+PEEgDQp0aXRsZT3lpKnnv7zmlZnkvaDnp7vliqjlupTnlKjokKXliKnkuYvpgZMg +DQpzdHlsZT0iUEFERElORy1SSUdIVDogM3B4OyBQQURESU5HLUxFRlQ6IDNweDsgUEFERElORy1C +T1RUT006IDBweDsgQ09MT1I6IHJnYigwLDAsMCk7IFBBRERJTkctVE9QOiAwcHg7IFRFWFQtREVD +T1JBVElPTjogdW5kZXJsaW5lIiANCm9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDcxKTsgaHJl +Zj0iaHR0cDovL2cuY3Nkbi5uZXQvNTE2Njc1NiIgDQp0YXJnZXQ9X2JsYW5rPuWkqee/vOaVmeS9 +oOenu+WKqOW6lOeUqOiQpeWIqeS5i+mBkzwvQT48L1A+PC9ESVY+PC9ESVY+DQo8RElWIGNsYXNz +PXBhZ2Vjb25fbGF5ZXIxX3JpZyANCnN0eWxlPSJCT1JERVItVE9QOiByZ2IoMjA0LDIwNCwyMDIp +IDFweCBzb2xpZDsgRElTUExBWTogaW5saW5lOyBGTE9BVDogcmlnaHQ7IE1BUkdJTjogMHB4IDFw +eCAwcHggMHB4OyBXSURUSDogNDE3cHgiPg0KPE9CSkVDVCANCmNvZGVCYXNlPWh0dHA6Ly9mcGRv +d25sb2FkLm1hY3JvbWVkaWEuY29tL3B1Yi9zaG9ja3dhdmUvY2Ficy9mbGFzaC9zd2ZsYXNoLmNh +YnZlcnNpb249NiwwLDAsMCANCmhlaWdodD0yMTUgd2lkdGg9NDE3IGNsYXNzaWQ9Y2xzaWQ6ZDI3 +Y2RiNmUtYWU2ZC0xMWNmLTk2YjgtNDQ0NTUzNTQwMDAwPg0KPGVtYmVkIHdtb2RlPSJ0cmFuc3Bh +cmVudCIgc3JjPSJodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2ZvY3VzLnN3ZiIgDQpmbGFz +aHZhcnM9InBpY3M9aHR0cDovL2ltYWdlcy5jc2RuLm5ldC8yMDEwMTIxMy80MTVfMjE1XzljaXR5 +XzEyMTNuLmpwZ3xodHRwOi8vaW1hZ2VzLmNzZG4ubmV0LzIwMTAxMjEzLzQxNV8yMTVfZ29uZ2ou +anBnfGh0dHA6Ly9pbWFnZXMuY3Nkbi5uZXQvMjAxMDEyMDMvNDE1XzIxNV9meC5qcGd8aHR0cDov +L2ltYWdlcy5jc2RuLm5ldC8yMDEwMTIxNC9obV80MTVfMjE1X3NkMTIxNC5qcGd8aHR0cDovL2lt +YWdlcy5jc2RuLm5ldC8yMDEwMTIwMy80MTVfMjE1XzExMDMuanBnfGh0dHA6Ly9pbWFnZXMuY3Nk +bi5uZXQvMjAxMDEyMTMvNDE1XzIxNV9iYmJicy5qcGcmYW1wO2xpbmtzPWh0dHA6Ly9nLmNzZG4u +bmV0LzUxNjY5MTR8aHR0cDovL2cuY3Nkbi5uZXQvNTE2NDI2MHxodHRwOi8vZy5jc2RuLm5ldC81 +MTY1OTExfGh0dHA6Ly9nLmNzZG4ubmV0LzUxNjY0NjF8aHR0cDovL2cuY3Nkbi5uZXQvNTE2NTM5 +NnxodHRwOi8vZy5jc2RuLm5ldC81MTY3MTMwJmFtcDt0ZXh0cz1DU0RO5Zu+54mH5paw6Ze7fENT +RE7lm77niYflub/lkYp8Q1NETuWbvueJh+W5v+WRinxDU0RO5Zu+54mH5bm/5ZGKfENTRE7lm77n +iYflub/lkYp8Q1NETuWbvueJh+W5v+WRiiZhbXA7cGljX3dpZHRoPTQxNyZhbXA7cGljX2hlaWdo +dD0yMTUmYW1wO3Nob3dfdGV4dD0wJmFtcDt0eHRjb2xvcj0wMDAwMDAmYW1wO2JnY29sb3I9RkZG +RkZGJmFtcDtidXR0b25fcG9zPTQmYW1wO3N0b3BfdGltZT00MDAwIiANCnF1YWxpdHk9ImhpZ2gi +IHdpZHRoPSI0MTciIGhlaWdodD0iMjE1IiBhbGxvd3NjcmlwdGFjY2Vzcz0ic2FtZURvbWFpbiIg +DQp0eXBlPSJhcHBsaWNhdGlvbi94LXNob2Nrd2F2ZS1mbGFzaCIgDQpwbHVnaW5zcGFnZT0iaHR0 +cDovL3d3dy5tYWNyb21lZGlhLmNvbS9nby9nZXRmbGFzaHBsYXllciI+PC9PQkpFQ1Q+PC9ESVY+ +PC9ESVY+DQo8RElWIGNsYXNzPXBhZ2Vjb25fbGF5ZXIxYnRtIA0Kc3R5bGU9IkNMRUFSOiBib3Ro +OyBPVkVSRkxPVy1ZOiBoaWRkZW47IEZPTlQtU0laRTogMXB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1 +cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljNl9idG0uZ2lmKTsg +T1ZFUkZMT1ctWDogaGlkZGVuOyBIRUlHSFQ6IDVweDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRp +YWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PC9ESVY+DQo8RElWIGNsYXNzPXBhZ2Vjb25f +bGF5ZXIyIA0Kc3R5bGU9IkZMT0FUOiBsZWZ0OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDov +L2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMzMuZ2lmKTsgTUFSR0lOOiAzcHgg +MHB4IDBweDsgV0lEVEg6IDk2MHB4OyBQT1NJVElPTjogcmVsYXRpdmU7IFRFWFQtQUxJR046IGxl +ZnQ7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwi +Pg0KPERJViBjbGFzcz1wYWdlXzA5c2lkZWJhcndyYXAgDQpzdHlsZT0iUEFERElORy1SSUdIVDog +MHB4OyBCT1JERVItVE9QOiByZ2IoMjA0LDIwNCwyMDQpIDFweCBzb2xpZDsgRElTUExBWTogaW5s +aW5lOyBQQURESU5HLUxFRlQ6IDBweDsgRkxPQVQ6IHJpZ2h0OyBQQURESU5HLUJPVFRPTTogNnB4 +OyBNQVJHSU46IDBweCAxcHggMHB4IDBweDsgV0lEVEg6IDIwOHB4OyBQQURESU5HLVRPUDogMHB4 +OyBURVhULUFMSUdOOiBsZWZ0Ij4NCjxESVYgY2xhc3M9c2lkZWJhcl9jb24gDQpzdHlsZT0iRElT +UExBWTogaW5saW5lOyBGTE9BVDogbGVmdDsgTUFSR0lOOiA2cHggM3B4IDJweDsgV0lEVEg6IDIw +MnB4Ij4NCjxINCBjbGFzcz10eHRfMTIgaWQ9bWVudTMgDQpzdHlsZT0iUEFERElORy1SSUdIVDog +MHB4OyBQQURESU5HLUxFRlQ6IDNweDsgRk9OVC1TSVpFOiAxMnB4OyBQQURESU5HLUJPVFRPTTog +NXB4OyBNQVJHSU46IDBweDsgUEFERElORy1UT1A6IDBweDsgQk9SREVSLUJPVFRPTTogcmdiKDIw +NCwyMDQsMjA0KSAxcHggc29saWQ7IFBPU0lUSU9OOiByZWxhdGl2ZSI+PEEgDQpjbGFzcz1jdXJy +ZW50MSBvbm1vdXNlb3Zlcj1zZXRUYWIoMywwKSANCnN0eWxlPSJDT0xPUjogcmdiKDEsOTUsMTgy +KTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiBvbmNsaWNrPSJyZXR1cm4gZmFsc2UiIA0KaHJlZj0i +aHR0cDovL3d3dy5jc2RuLm5ldC8jIj7mnIDmlrDmtLvliqg8L0E+PFNQQU4gDQpjbGFzcz1BcHBs +ZS1jb252ZXJ0ZWQtc3BhY2U+Jm5ic3A7PC9TUEFOPnw8U1BBTiANCmNsYXNzPUFwcGxlLWNvbnZl +cnRlZC1zcGFjZT4mbmJzcDs8L1NQQU4+PEEgb25tb3VzZW92ZXI9c2V0VGFiKDMsMSkgDQpzdHls +ZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgb25jbGljaz0icmV0 +dXJuIGZhbHNlIiANCmhyZWY9Imh0dHA6Ly93d3cuY3Nkbi5uZXQvIyI+56iL5bqP5ZGY5p2C5b+X +PC9BPjwvSDQ+DQo8RElWIGlkPW1haW4zPg0KPERJVj4NCjxETCBjbGFzcz1zZXNzaW9uX3N0eWxl +IA0Kc3R5bGU9IlBBRERJTkctUklHSFQ6IDNweDsgUEFERElORy1MRUZUOiAzcHg7IEZMT0FUOiBs +ZWZ0OyBQQURESU5HLUJPVFRPTTogNXB4OyBNQVJHSU46IDJweCAwcHggMHB4OyBXSURUSDogMTk2 +cHg7IFBBRERJTkctVE9QOiAxMHB4OyBCT1JERVItQk9UVE9NOiByZ2IoMjA0LDIwNCwyMDQpIDFw +eCBzb2xpZDsgQkFDS0dST1VORC1DT0xPUjogcmdiKDI1NSwyNTUsMjU1KTsgYmFja2dyb3VuZC1v +cmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+DQogIDxEVCBjbGFzcz1j +bGVhcmRpdiANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgUEFERElORy1MRUZUOiAwcHg7 +IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4IDBweCA5cHg7IFBBRERJTkctVE9QOiAw +cHgiPjxBIA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9u +ZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDc3KTsgaHJlZj0iaHR0cDovL2cuY3Nk +bi5uZXQvNTE2NjkxOCIgDQogIHRhcmdldD1fYmxhbms+PElNRyB0aXRsZT0iIiANCiAgc3R5bGU9 +IkJPUkRFUi1SSUdIVDogcmdiKDIwNCwyMDQsMjA0KSAxcHggc29saWQ7IFBBRERJTkctUklHSFQ6 +IDJweDsgQk9SREVSLVRPUDogcmdiKDIwNCwyMDQsMjA0KSAxcHggc29saWQ7IFBBRERJTkctTEVG +VDogMnB4OyBGTE9BVDogbGVmdDsgUEFERElORy1CT1RUT006IDJweDsgTUFSR0lOOiAwcHggNnB4 +IDBweCAwcHg7IEJPUkRFUi1MRUZUOiByZ2IoMjA0LDIwNCwyMDQpIDFweCBzb2xpZDsgUEFERElO +Ry1UT1A6IDJweDsgQk9SREVSLUJPVFRPTTogcmdiKDIwNCwyMDQsMjA0KSAxcHggc29saWQiIA0K +ICBoZWlnaHQ9NjggYWx0PSIiIHNyYz0iaHR0cDovL2ltYWdlcy5jc2RuLm5ldC8yMDEwMTIxMC81 +Nl83Ml90eS5qcGciIA0KICB3aWR0aD01Mj48L0E+6Ieq55SxIOWIhuS6qyDlhbHotaIg5byA5Yib +56e75Yqo5LqS6IGU572R5pyq5p2l77yM5aSp57+85pWZ5L2g56e75Yqo5bqU55So6JCl5Yip5LmL +6YGT77yBMTLmnIgxN+aXpe+8jOWOpumXqOermeOAgjwvRFQ+DQogIDxERCANCiAgc3R5bGU9IlBB +RERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMnB4IDdweDsgUEFERElORy1M +RUZUOiAxMnB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2lt +YWdlcy9jc2RuaW5kZXhfcGljNS5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBw +eDsgTElORS1IRUlHSFQ6IDE5cHg7IFBBRERJTkctVE9QOiAwcHg7IGJhY2tncm91bmQtb3JpZ2lu +OiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0aXRsZT1PcGVuRmVp +bnTmuLjmiI/lvIDlj5HogIXnvqToi7HkvJogc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhU +LURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw3Nyk7IGhy +ZWY9Imh0dHA6Ly9nLmNzZG4ubmV0LzUxNjY5MTUiIA0KICB0YXJnZXQ9X2JsYW5rPk9wZW5GZWlu +dOa4uOaIj+W8gOWPkeiAhee+pOiLseS8mjwvQT48L0REPg0KICA8REQgDQogIHN0eWxlPSJQQURE +SU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDJweCA3cHg7IFBBRERJTkctTEVG +VDogMTJweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFn +ZXMvY3NkbmluZGV4X3BpYzUuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7 +IExJTkUtSEVJR0hUOiAxOXB4OyBQQURESU5HLVRPUDogMHB4OyBiYWNrZ3JvdW5kLW9yaWdpbjog +aW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgdGl0bGU944CK56iL5bqP +5ZGY44CL5Y2B5bm06IGU5omL55ub5aSn54m55oOg5rS75YqoIHN0eWxlPSJDT0xPUjogcmdiKDAs +MCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRo +aXMsNzcpOyBocmVmPSJodHRwOi8vZy5jc2RuLm5ldC81MTY2NDY0IiANCiAgdGFyZ2V0PV9ibGFu +az7jgIrnqIvluo/lkZjjgIvljYHlubTogZTmiYvnm5vlpKfnibnmg6DmtLvliqg8L0E+PC9ERD4N +CiAgPEREIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9O +OiAycHggN3B4OyBQQURESU5HLUxFRlQ6IDEycHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRw +Oi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWM1LmdpZik7IFBBRERJTkctQk9U +VE9NOiAwcHg7IE1BUkdJTjogMHB4OyBMSU5FLUhFSUdIVDogMTlweDsgUEFERElORy1UT1A6IDBw +eDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+ +PEEgDQogIHRpdGxlPeesrOS5neWfjuW4guWNg+S4h+eOsOmHkeW+gembhueyvuWTgea4uOaIj++8 +gSBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9u +Y2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDc3KTsgaHJlZj0iaHR0cDovL2cuY3Nkbi5uZXQvNTE2 +NjkzMiIgDQogIHRhcmdldD1fYmxhbms+56ys5Lmd5Z+O5biC5Y2D5LiH546w6YeR5b6B6ZuG57K+ +5ZOB5ri45oiP77yBPC9BPjwvREQ+DQogIDxERCANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBw +eDsgQkFDS0dST1VORC1QT1NJVElPTjogMnB4IDdweDsgUEFERElORy1MRUZUOiAxMnB4OyBCQUNL +R1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhf +cGljNS5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweDsgTElORS1IRUlHSFQ6 +IDE5cHg7IFBBRERJTkctVE9QOiAwcHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNr +Z3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0aXRsZT3nrKzlha3lsYrnp7vliqjkupLogZTn +vZFUT1A1MOivhOmAiSBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjog +bm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDc3KTsgaHJlZj0iaHR0cDovL2cu +Y3Nkbi5uZXQvNTE2NTc3NiIgDQogIHRhcmdldD1fYmxhbms+56ys5YWt5bGK56e75Yqo5LqS6IGU +572RVE9QNTDor4TpgIk8L0E+PC9ERD4NCiAgPEREIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDog +MHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAycHggN3B4OyBQQURESU5HLUxFRlQ6IDEycHg7IEJB +Q0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRl +eF9waWM1LmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBMSU5FLUhFSUdI +VDogMTlweDsgUEFERElORy1UT1A6IDBweDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJh +Y2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxlPeaXoOe6v+S6kuiBlOWIm+S4muWu +nuaImOiusuW6p8K35YyX5LqsIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFU +SU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsNzcpOyBocmVmPSJodHRw +Oi8vZy5jc2RuLm5ldC81MTY1MjAwIiANCiAgdGFyZ2V0PV9ibGFuaz7ml6Dnur/kupLogZTliJvk +uJrlrp7miJjorrLluqfCt+WMl+S6rDwvQT48L0REPg0KICA8REQgDQogIHN0eWxlPSJQQURESU5H +LVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDJweCA3cHg7IFBBRERJTkctTEVGVDog +MTJweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMv +Y3NkbmluZGV4X3BpYzUuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IExJ +TkUtSEVJR0hUOiAxOXB4OyBQQURESU5HLVRPUDogMHB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5p +dGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgdGl0bGU944CK5pWP5o235byA +5Y+R4oCU5rWL6K+V566h55CG44CL5o+Q6Zeu6LWi5aWWIHN0eWxlPSJDT0xPUjogcmdiKDAsMCww +KTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMs +NzcpOyANCiAgaHJlZj0iaHR0cDovL2Jicy5jaGluYXRlc3RpbmcuY24vODYtMTgwMjE1Lmh0bWwi +IA0KICB0YXJnZXQ9X2JsYW5rPuOAiuaVj+aNt+W8gOWPkeKAlOa1i+ivleeuoeeQhuOAi+aPkOmX +rui1ouWlljwvQT48L0REPg0KICA8REQgY2xhc3M9bm9iZyANCiAgc3R5bGU9IlBBRERJTkctUklH +SFQ6IDBweDsgUEFERElORy1MRUZUOiAycHg7IEJBQ0tHUk9VTkQtSU1BR0U6IG5vbmU7IFBBRERJ +TkctQk9UVE9NOiAwcHg7IE1BUkdJTjogNnB4IDBweCAwcHg7IExJTkUtSEVJR0hUOiAxOXB4OyBQ +QURESU5HLVRPUDogMHB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1j +bGlwOiBpbml0aWFsIj48L0REPjwvREw+PC9ESVY+PC9ESVY+PC9ESVY+DQo8RElWIGNsYXNzPXNp +ZGViYXJfY29uIA0Kc3R5bGU9IkRJU1BMQVk6IGlubGluZTsgRkxPQVQ6IGxlZnQ7IE1BUkdJTjog +NnB4IDNweCAycHg7IFdJRFRIOiAyMDJweCI+DQo8SDQgY2xhc3M9dHh0XzEyIA0Kc3R5bGU9IlBB +RERJTkctUklHSFQ6IDBweDsgUEFERElORy1MRUZUOiAzcHg7IEZPTlQtU0laRTogMTJweDsgUEFE +RElORy1CT1RUT006IDVweDsgTUFSR0lOOiAwcHg7IFBBRERJTkctVE9QOiAwcHg7IEJPUkRFUi1C +T1RUT006IHJnYigyMDQsMjA0LDIwNCkgMXB4IHNvbGlkOyBQT1NJVElPTjogcmVsYXRpdmUiPjxT +UEFOIA0KY2xhc3M9dHh0X2dyYXkgDQpzdHlsZT0iRk9OVC1XRUlHSFQ6IG5vcm1hbDsgRkxPQVQ6 +IHJpZ2h0OyBDT0xPUjogcmdiKDEwMiwxMDIsMTAyKSI+PC9TUEFOPueDremXqOaLm+iBmOiBjOS9 +jTwvSDQ+DQo8RElWIGNsYXNzPXJlY3J1aXRmdWxsIA0Kc3R5bGU9IlBBRERJTkctUklHSFQ6IDNw +eDsgT1ZFUkZMT1ctWTogaGlkZGVuOyBQQURESU5HLUxFRlQ6IDNweDsgRkxPQVQ6IGxlZnQ7IE9W +RVJGTE9XLVg6IGhpZGRlbjsgUEFERElORy1CT1RUT006IDVweDsgTUFSR0lOOiAycHggMHB4IDBw +eDsgV0lEVEg6IDE5NnB4OyBQQURESU5HLVRPUDogMTBweDsgQk9SREVSLUJPVFRPTTogcmdiKDIw +NCwyMDQsMjA0KSAxcHggc29saWQ7IEhFSUdIVDogMjUycHg7IEJBQ0tHUk9VTkQtQ09MT1I6IHJn +YigyNTUsMjU1LDI1NSk7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNs +aXA6IGluaXRpYWwiPg0KPERMIGNsYXNzPXJlY3J1aXQgaWQ9bWFycXVlZWJveDAgDQpzdHlsZT0i +Qk9SREVSLVRPUC1XSURUSDogMHB4OyBQQURESU5HLVJJR0hUOiAwcHg7IE9WRVJGTE9XLVk6IGhp +ZGRlbjsgUEFERElORy1MRUZUOiAwcHg7IEJPUkRFUi1MRUZULVdJRFRIOiAwcHg7IEZMT0FUOiBs +ZWZ0OyBPVkVSRkxPVy1YOiBoaWRkZW47IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4 +OyBXSURUSDogMTk2cHg7IFBBRERJTkctVE9QOiAwcHg7IEJPUkRFUi1CT1RUT006IHJnYigyMDQs +MjA0LDIwNCkgMHB4IHNvbGlkOyBIRUlHSFQ6IDI1MnB4OyBCQUNLR1JPVU5ELUNPTE9SOiByZ2Io +MjU1LDI1NSwyNTUpOyBCT1JERVItUklHSFQtV0lEVEg6IDBweDsgYmFja2dyb3VuZC1vcmlnaW46 +IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+DQogIDxERCANCiAgc3R5bGU9IlBB +RERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMnB4IDdweDsgT1ZFUkZMT1ct +WTogaGlkZGVuOyBQQURESU5HLUxFRlQ6IDEycHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRw +Oi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWM1LmdpZik7IE9WRVJGTE9XLVg6 +IGhpZGRlbjsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHggMHB4IDZweDsgTElORS1I +RUlHSFQ6IDE5cHg7IFBBRERJTkctVE9QOiAwcHg7IEhFSUdIVDogMzZweDsgYmFja2dyb3VuZC1v +cmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxlPSLj +gJDngJrkv6Hnp5HmioDjgJHor5rogZggV0lORE9XUyBDKysgV0lORE9XUyBDI+S4remrmOe6p+W8 +gOWPkeW3peeoi+W4iCIgDQogIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFU +SU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsOTMpOyBocmVmPSJodHRw +Oi8vZy5jc2RuLm5ldC81MTY3NDU3IiANCiAgdGFyZ2V0PV9ibGFuaz7jgJDngJrkv6Hnp5HmioDj +gJHor5rogZggV0lORE9XUyBDKysgV0lORE9XUyBDI+S4remrmOe6p+W8gOWPkeW3peeoi+W4iDwv +QT48L0REPg0KICA8REQgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQt +UE9TSVRJT046IDJweCA3cHg7IE9WRVJGTE9XLVk6IGhpZGRlbjsgUEFERElORy1MRUZUOiAxMnB4 +OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2Ru +aW5kZXhfcGljNS5naWYpOyBPVkVSRkxPVy1YOiBoaWRkZW47IFBBRERJTkctQk9UVE9NOiAwcHg7 +IE1BUkdJTjogMHB4IDBweCA2cHg7IExJTkUtSEVJR0hUOiAxOXB4OyBQQURESU5HLVRPUDogMHB4 +OyBIRUlHSFQ6IDM2cHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNs +aXA6IGluaXRpYWwiPjxBIA0KICB0aXRsZT0i44CQ6YW35oiR6Z+z5LmQ55uS44CR6auY6Jaq6K+a +6IGYIOa/gOaDheeIseWlveW3peS9nOiejeS4uuS4gOS9kyIgDQogIHN0eWxlPSJDT0xPUjogcmdi +KDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50 +KHRoaXMsOTMpOyBocmVmPSJodHRwOi8vZy5jc2RuLm5ldC81MTY3NDU0IiANCiAgdGFyZ2V0PV9i +bGFuaz7jgJDphbfmiJHpn7PkuZDnm5LjgJHpq5jolqror5rogZgg5r+A5oOF54ix5aW95bel5L2c +6J6N5Li65LiA5L2TPC9BPjwvREQ+DQogIDxERCANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBw +eDsgQkFDS0dST1VORC1QT1NJVElPTjogMnB4IDdweDsgT1ZFUkZMT1ctWTogaGlkZGVuOyBQQURE +SU5HLUxFRlQ6IDEycHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93 +d3cvaW1hZ2VzL2NzZG5pbmRleF9waWM1LmdpZik7IE9WRVJGTE9XLVg6IGhpZGRlbjsgUEFERElO +Ry1CT1RUT006IDBweDsgTUFSR0lOOiAwcHggMHB4IDZweDsgTElORS1IRUlHSFQ6IDE5cHg7IFBB +RERJTkctVE9QOiAwcHg7IEhFSUdIVDogMzZweDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7 +IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxlPeOAkOi+vuWGhembhuWbouOA +kemrmOiWquivmuiBmEpBVkHorrLluIgu5bWM5YWl5byP6K6y5biILjNH6K6y5biILuaKgOacr+aA +u+ebkS7liIblhazlj7jmgLvnu4/nkIYgDQogIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVY +VC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsOTMpOyBo +cmVmPSJodHRwOi8vZy5jc2RuLm5ldC81MTY3NDE0IiANCiAgdGFyZ2V0PV9ibGFuaz7jgJDovr7l +hoXpm4blm6LjgJHpq5jolqror5rogZhKQVZB6K6y5biILuW1jOWFpeW8j+iusuW4iC4zR+iusuW4 +iC7mioDmnK/mgLvnm5Eu5YiG5YWs5Y+45oC757uP55CGPC9BPjwvREQ+DQogIDxERCANCiAgc3R5 +bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMnB4IDdweDsgT1ZF +UkZMT1ctWTogaGlkZGVuOyBQQURESU5HLUxFRlQ6IDEycHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVy +bChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWM1LmdpZik7IE9WRVJG +TE9XLVg6IGhpZGRlbjsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHggMHB4IDZweDsg +TElORS1IRUlHSFQ6IDE5cHg7IFBBRERJTkctVE9QOiAwcHg7IEhFSUdIVDogMzZweDsgYmFja2dy +b3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRp +dGxlPeOAkOWkqemZhee9keOAkeaApeiBmEphdmHlupTnlKjmnrbmnoTluIjjgIHpq5jnuqdKYXZh +5bel56iL5biI44CB572R6aG16K6+6K6h5biIIA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7 +IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDkz +KTsgaHJlZj0iaHR0cDovL2cuY3Nkbi5uZXQvNTE2NjkxNyIgDQogIHRhcmdldD1fYmxhbms+44CQ +5aSp6ZmF572R44CR5oCl6IGYSmF2YeW6lOeUqOaetuaehOW4iOOAgemrmOe6p0phdmHlt6XnqIvl +uIjjgIHnvZHpobXorr7orqHluIg8L0E+PC9ERD4NCiAgPEREIA0KICBzdHlsZT0iUEFERElORy1S +SUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAycHggN3B4OyBPVkVSRkxPVy1ZOiBoaWRk +ZW47IFBBRERJTkctTEVGVDogMTJweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2Ru +aW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzUuZ2lmKTsgT1ZFUkZMT1ctWDogaGlkZGVu +OyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweCAwcHggNnB4OyBMSU5FLUhFSUdIVDog +MTlweDsgUEFERElORy1UT1A6IDBweDsgSEVJR0hUOiAzNnB4OyBiYWNrZ3JvdW5kLW9yaWdpbjog +aW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgdGl0bGU944CQ5LiK5rW3 +6YW35aix44CR6auY6Jaq5oCl6IGY5pyN5Yqh5Zmo5Li756iL44CB5pyN5Yqh5Zmo56iL5bqPIHN0 +eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGlj +az1Mb2dDbGlja0NvdW50KHRoaXMsOTMpOyBocmVmPSJodHRwOi8vZy5jc2RuLm5ldC81MTY2OTEz +IiANCiAgdGFyZ2V0PV9ibGFuaz7jgJDkuIrmtbfphbflqLHjgJHpq5jolqrmgKXogZjmnI3liqHl +majkuLvnqIvjgIHmnI3liqHlmajnqIvluo88L0E+PC9ERD4NCiAgPEREIA0KICBzdHlsZT0iUEFE +RElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAycHggN3B4OyBPVkVSRkxPVy1Z +OiBoaWRkZW47IFBBRERJTkctTEVGVDogMTJweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6 +Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzUuZ2lmKTsgT1ZFUkZMT1ctWDog +aGlkZGVuOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweCAwcHggNnB4OyBMSU5FLUhF +SUdIVDogMTlweDsgUEFERElORy1UT1A6IDBweDsgSEVJR0hUOiAzNnB4OyBiYWNrZ3JvdW5kLW9y +aWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgdGl0bGU944CQ +5Yib5paw5bel5Zy644CR5oqA5pyv57G76IGM5L2N54Ot5oub77yM56uL5Y2z5Yqg5YWl5bGe5LqO +5L2g6Ieq5bex55qE5YWs5Y+4IA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVD +T1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDkzKTsgaHJlZj0i +aHR0cDovL2cuY3Nkbi5uZXQvNTE2Njc1NSIgDQogIHRhcmdldD1fYmxhbms+44CQ5Yib5paw5bel +5Zy644CR5oqA5pyv57G76IGM5L2N54Ot5oub77yM56uL5Y2z5Yqg5YWl5bGe5LqO5L2g6Ieq5bex +55qE5YWs5Y+4PC9BPjwvREQ+DQogIDxERCANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsg +QkFDS0dST1VORC1QT1NJVElPTjogMnB4IDdweDsgT1ZFUkZMT1ctWTogaGlkZGVuOyBQQURESU5H +LUxFRlQ6IDEycHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cv +aW1hZ2VzL2NzZG5pbmRleF9waWM1LmdpZik7IE9WRVJGTE9XLVg6IGhpZGRlbjsgUEFERElORy1C +T1RUT006IDBweDsgTUFSR0lOOiAwcHggMHB4IDZweDsgTElORS1IRUlHSFQ6IDE5cHg7IFBBRERJ +TkctVE9QOiAwcHg7IEhFSUdIVDogMzZweDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJh +Y2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxlPeOAkOWuveWoseaVsOeggeOAkeiv +muiBmEMrK+W6lOeUqOi9r+S7tuW3peeoi+W4iO+8iOWkmuWqkuS9ky/nvZHnu5zmlrnlkJHvvInj +gIEubmV05byA5Y+R5bel56iL5biIIA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQt +REVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDkzKTsgaHJl +Zj0iaHR0cDovL2cuY3Nkbi5uZXQvNTE2NTg5OSIgDQogIHRhcmdldD1fYmxhbms+44CQ5a695aix +5pWw56CB44CR6K+a6IGYQysr5bqU55So6L2v5Lu25bel56iL5biI77yI5aSa5aqS5L2TL+e9kee7 +nOaWueWQke+8ieOAgS5uZXTlvIDlj5Hlt6XnqIvluIg8L0E+PC9ERD4NCiAgPEREIA0KICBzdHls +ZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAycHggN3B4OyBPVkVS +RkxPVy1ZOiBoaWRkZW47IFBBRERJTkctTEVGVDogMTJweDsgQkFDS0dST1VORC1JTUFHRTogdXJs +KGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzUuZ2lmKTsgT1ZFUkZM +T1ctWDogaGlkZGVuOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweCAwcHggNnB4OyBM +SU5FLUhFSUdIVDogMTlweDsgUEFERElORy1UT1A6IDBweDsgSEVJR0hUOiAzNnB4OyBiYWNrZ3Jv +dW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgdGl0 +bGU9IuOAkOWbojgwMOOAkU5vLjHlm6LotK3lr7zoiKror5rogZhSdWJ5IG9uIFJhaWxz6auY5omL +77yBIiANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUi +IA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw5Myk7IGhyZWY9Imh0dHA6Ly9nLmNzZG4u +bmV0LzUxNjU4NzYiIA0KICB0YXJnZXQ9X2JsYW5rPuOAkOWbojgwMOOAkU5vLjHlm6LotK3lr7zo +iKror5rogZhSdWJ5IG9uIFJhaWxz6auY5omL77yBPC9BPjwvREQ+DQogIDxERCANCiAgc3R5bGU9 +IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMnB4IDdweDsgT1ZFUkZM +T1ctWTogaGlkZGVuOyBQQURESU5HLUxFRlQ6IDEycHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybCho +dHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWM1LmdpZik7IE9WRVJGTE9X +LVg6IGhpZGRlbjsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHggMHB4IDZweDsgTElO +RS1IRUlHSFQ6IDE5cHg7IFBBRERJTkctVE9QOiAwcHg7IEhFSUdIVDogMzZweDsgYmFja2dyb3Vu +ZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxl +PSLjgJDnvo7lm73lm73lrrbku6rlmajjgJHor5rogZjpq5jnuqfova/ku7YgIOW3peeoi+W4iCAg +5L+h5Y+35aSE55CG6L2v5Lu26YOo6Zeo57uP55CGIiANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCww +LDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhp +cyw5Myk7IGhyZWY9Imh0dHA6Ly9nLmNzZG4ubmV0LzUxNjU2ODkiIA0KICB0YXJnZXQ9X2JsYW5r +PuOAkOe+juWbveWbveWutuS7quWZqOOAkeivmuiBmOmrmOe6p+i9r+S7tiDlt6XnqIvluIgg5L+h +5Y+35aSE55CG6L2v5Lu26YOo6Zeo57uP55CGPC9BPjwvREQ+DQogIDxERCANCiAgc3R5bGU9IlBB +RERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMnB4IDdweDsgT1ZFUkZMT1ct +WTogaGlkZGVuOyBQQURESU5HLUxFRlQ6IDEycHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRw +Oi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWM1LmdpZik7IE9WRVJGTE9XLVg6 +IGhpZGRlbjsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHggMHB4IDZweDsgTElORS1I +RUlHSFQ6IDE5cHg7IFBBRERJTkctVE9QOiAwcHg7IEhFSUdIVDogMzZweDsgYmFja2dyb3VuZC1v +cmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxlPeOA +kOa1meaxn+mpsOa1t+WunuS4muOAkeivmuiBmOmhueebrue7j+eQhu+8jFBIUCxNWVNRTCxTRU8s +5rWL6K+V77yM6L+Q57u077yM562W5YiS77yM6K6+6K6h562J6IGMIA0KICBzdHlsZT0iQ09MT1I6 +IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tD +b3VudCh0aGlzLDkzKTsgaHJlZj0iaHR0cDovL2cuY3Nkbi5uZXQvNTE2NTY2NSIgDQogIHRhcmdl +dD1fYmxhbms+44CQ5rWZ5rGf6amw5rW35a6e5Lia44CR6K+a6IGY6aG555uu57uP55CG77yMUEhQ +LE1ZU1FMLFNFTyzmtYvor5XvvIzov5Dnu7TvvIznrZbliJLvvIzorr7orqHnrYnogYw8L0E+PC9E +RD4NCiAgPEREIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lU +SU9OOiAycHggN3B4OyBPVkVSRkxPVy1ZOiBoaWRkZW47IFBBRERJTkctTEVGVDogMTJweDsgQkFD +S0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4 +X3BpYzUuZ2lmKTsgT1ZFUkZMT1ctWDogaGlkZGVuOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJH +SU46IDBweCAwcHggNnB4OyBMSU5FLUhFSUdIVDogMTlweDsgUEFERElORy1UT1A6IDBweDsgSEVJ +R0hUOiAzNnB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBp +bml0aWFsIj48QSANCiAgdGl0bGU9IuOAkEluZm9zeXPjgJHor5rogZjvvJpKMkVFIOmhueebruS4 +u+euoS/vvIjotYTmt7HvvInova/ku7bnoJTlj5Hlt6XnqIvluIgvLk5ldOi1hOa3sei9r+S7tueg +lOWPkeW3peeoi+W4iCIgDQogIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFU +SU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsOTMpOyBocmVmPSJodHRw +Oi8vZy5jc2RuLm5ldC81MTY1NTQ4IiANCiAgdGFyZ2V0PV9ibGFuaz7jgJBJbmZvc3lz44CR6K+a +6IGY77yaSjJFRSDpobnnm67kuLvnrqEv77yI6LWE5rex77yJ6L2v5Lu256CU5Y+R5bel56iL5biI +Ly5OZXTotYTmt7Hova/ku7bnoJTlj5Hlt6XnqIvluIg8L0E+PC9ERD4NCiAgPEREIA0KICBzdHls +ZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAycHggN3B4OyBPVkVS +RkxPVy1ZOiBoaWRkZW47IFBBRERJTkctTEVGVDogMTJweDsgQkFDS0dST1VORC1JTUFHRTogdXJs +KGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzUuZ2lmKTsgT1ZFUkZM +T1ctWDogaGlkZGVuOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweCAwcHggNnB4OyBM +SU5FLUhFSUdIVDogMTlweDsgUEFERElORy1UT1A6IDBweDsgSEVJR0hUOiAzNnB4OyBiYWNrZ3Jv +dW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgdGl0 +bGU944CQ5YyX5Lqs6auY5oiQ6ZW/5YWs5Y+444CR6auY6Jaq5oub6IGYLm5ldOWQhOe6p+eoi+W6 +j+WRmO+8jOasoui/juW6lOWxiueUnyANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhU +LURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw5Myk7IGhy +ZWY9Imh0dHA6Ly9nLmNzZG4ubmV0LzUxNjU0MDciIA0KICB0YXJnZXQ9X2JsYW5rPuOAkOWMl+S6 +rOmrmOaIkOmVv+WFrOWPuOOAkemrmOiWquaLm+iBmC5uZXTlkITnuqfnqIvluo/lkZjvvIzmrKLo +v47lupTlsYrnlJ88L0E+PC9ERD4NCiAgPEREIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4 +OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAycHggN3B4OyBPVkVSRkxPVy1ZOiBoaWRkZW47IFBBRERJ +TkctTEVGVDogMTJweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3 +dy9pbWFnZXMvY3NkbmluZGV4X3BpYzUuZ2lmKTsgT1ZFUkZMT1ctWDogaGlkZGVuOyBQQURESU5H +LUJPVFRPTTogMHB4OyBNQVJHSU46IDBweCAwcHggNnB4OyBMSU5FLUhFSUdIVDogMTlweDsgUEFE +RElORy1UT1A6IDBweDsgSEVJR0hUOiAzNnB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsg +YmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgdGl0bGU9IuOAkOmTtuihjOmhueebruOA +keivmuiBmGphdmHliY3lj7Av5ZCO5Y+w5byA5Y+R5Lq65ZGY5aSa5ZCNIOWPilNBU+aVsOaNruWI +huaekOWRmO+8jOassuivleS7jumAn++8gSIgDQogIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsg +VEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsOTMp +OyBocmVmPSJodHRwOi8vZy5jc2RuLm5ldC81MTY1MTk5IiANCiAgdGFyZ2V0PV9ibGFuaz7jgJDp +k7booYzpobnnm67jgJHor5rogZhqYXZh5YmN5Y+wL+WQjuWPsOW8gOWPkeS6uuWRmOWkmuWQjSDl +j4pTQVPmlbDmja7liIbmnpDlkZjvvIzmrLLor5Xku47pgJ/vvIE8L0E+PC9ERD4NCiAgPEREIA0K +ICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAycHggN3B4 +OyBPVkVSRkxPVy1ZOiBoaWRkZW47IFBBRERJTkctTEVGVDogMTJweDsgQkFDS0dST1VORC1JTUFH +RTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzUuZ2lmKTsg +T1ZFUkZMT1ctWDogaGlkZGVuOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweCAwcHgg +NnB4OyBMSU5FLUhFSUdIVDogMTlweDsgUEFERElORy1UT1A6IDBweDsgSEVJR0hUOiAzNnB4OyBi +YWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSAN +CiAgdGl0bGU944CQ5YyX5Lqs6Ze76KiA56eR5oqA44CR6K+a6IGYLm5ldOmrmOe6p+W8gOWPkeW3 +peeoi+W4iOOAgeaJi+acuui9r+S7tuW8gOWPkeW3peeoi+W4iO+8iOW6lOWxiuavleS4mueUn+S8 +mOWFiO+8iSANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5v +bmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw5Myk7IGhyZWY9Imh0dHA6Ly9nLmNz +ZG4ubmV0LzUxNjQ3MDciIA0KICB0YXJnZXQ9X2JsYW5rPuOAkOWMl+S6rOmXu+iogOenkeaKgOOA +keivmuiBmC5uZXTpq5jnuqflvIDlj5Hlt6XnqIvluIjjgIHmiYvmnLrova/ku7blvIDlj5Hlt6Xn +qIvluIjvvIjlupTlsYrmr5XkuJrnlJ/kvJjlhYjvvIk8L0E+PC9ERD4NCiAgPEREIA0KICBzdHls +ZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAycHggN3B4OyBPVkVS +RkxPVy1ZOiBoaWRkZW47IFBBRERJTkctTEVGVDogMTJweDsgQkFDS0dST1VORC1JTUFHRTogdXJs +KGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzUuZ2lmKTsgT1ZFUkZM +T1ctWDogaGlkZGVuOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweCAwcHggNnB4OyBM +SU5FLUhFSUdIVDogMTlweDsgUEFERElORy1UT1A6IDBweDsgSEVJR0hUOiAzNnB4OyBiYWNrZ3Jv +dW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgdGl0 +bGU944CQ5LiK5rW355S15a2Q5ZWG5Yqh5bmz5Y+w44CR6YeN6YeR6K+a6IGYLm5ldCxhc3AsamF2 +YXNjcmlwdOi1hOa3seeoi+W6j+WRmCANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhU +LURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw5Myk7IGhy +ZWY9Imh0dHA6Ly9nLmNzZG4ubmV0LzUxNjQ2NzEiIA0KICB0YXJnZXQ9X2JsYW5rPuOAkOS4iua1 +t+eUteWtkOWVhuWKoeW5s+WPsOOAkemHjemHkeivmuiBmC5uZXQsYXNwLGphdmFzY3JpcHTotYTm +t7HnqIvluo/lkZg8L0E+PC9ERD4NCiAgPEREIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4 +OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAycHggN3B4OyBPVkVSRkxPVy1ZOiBoaWRkZW47IFBBRERJ +TkctTEVGVDogMTJweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3 +dy9pbWFnZXMvY3NkbmluZGV4X3BpYzUuZ2lmKTsgT1ZFUkZMT1ctWDogaGlkZGVuOyBQQURESU5H +LUJPVFRPTTogMHB4OyBNQVJHSU46IDBweCAwcHggNnB4OyBMSU5FLUhFSUdIVDogMTlweDsgUEFE +RElORy1UT1A6IDBweDsgSEVJR0hUOiAzNnB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsg +YmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgdGl0bGU944CQRUblhajnkIPnoJTlj5Hk +uK3lv4PjgJHnmb7kuIflubTolqror5rmi5vmioDmnK/nsr7oi7HvvIzmlbDnmb7ogYzkvY3ng63m +i5vkuK0gDQogIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25l +IiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsOTMpOyBocmVmPSJodHRwOi8vZy5jc2Ru +Lm5ldC81MTY0MDM0IiANCiAgdGFyZ2V0PV9ibGFuaz7jgJBFRuWFqOeQg+eglOWPkeS4reW/g+OA +keeZvuS4h+W5tOiWquivmuaLm+aKgOacr+eyvuiLse+8jOaVsOeZvuiBjOS9jeeDreaLm+S4rTwv +QT48L0REPg0KICA8REQgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQt +UE9TSVRJT046IDJweCA3cHg7IE9WRVJGTE9XLVk6IGhpZGRlbjsgUEFERElORy1MRUZUOiAxMnB4 +OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2Ru +aW5kZXhfcGljNS5naWYpOyBPVkVSRkxPVy1YOiBoaWRkZW47IFBBRERJTkctQk9UVE9NOiAwcHg7 +IE1BUkdJTjogMHB4IDBweCA2cHg7IExJTkUtSEVJR0hUOiAxOXB4OyBQQURESU5HLVRPUDogMHB4 +OyBIRUlHSFQ6IDM2cHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNs +aXA6IGluaXRpYWwiPjxBIA0KICB0aXRsZT3jgJBBbWF6b27jgJHkuprpqazpgIror5rogZjmioDm +nK/kuJPlrrbvvIEgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5v +bmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw5Myk7IGhyZWY9Imh0dHA6Ly9nLmNz +ZG4ubmV0LzUxNjY5MTYiIA0KICB0YXJnZXQ9X2JsYW5rPuOAkEFtYXpvbuOAkeS6mumprOmAiuiv +muiBmOaKgOacr+S4k+Wutu+8gTwvQT48L0REPg0KICA8REQgDQogIHN0eWxlPSJQQURESU5HLVJJ +R0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDJweCA3cHg7IE9WRVJGTE9XLVk6IGhpZGRl +bjsgUEFERElORy1MRUZUOiAxMnB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5p +bWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljNS5naWYpOyBPVkVSRkxPVy1YOiBoaWRkZW47 +IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4IDBweCA2cHg7IExJTkUtSEVJR0hUOiAx +OXB4OyBQQURESU5HLVRPUDogMHB4OyBIRUlHSFQ6IDM2cHg7IGJhY2tncm91bmQtb3JpZ2luOiBp +bml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0aXRsZT3jgJDnvZHot6/m +l7bku6PjgJHpq5jolqror5rogZhDKyvjgIEubmV05byA5Y+R5bel56iL5biIIHN0eWxlPSJDT0xP +UjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlj +a0NvdW50KHRoaXMsOTMpOyBocmVmPSJodHRwOi8vZy5jc2RuLm5ldC81MTYzMzY5IiANCiAgdGFy +Z2V0PV9ibGFuaz7jgJDnvZHot6/ml7bku6PjgJHpq5jolqror5rogZhDKyvjgIEubmV05byA5Y+R +5bel56iL5biIPC9BPjwvREQ+DQogIDxERCANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsg +QkFDS0dST1VORC1QT1NJVElPTjogMnB4IDdweDsgT1ZFUkZMT1ctWTogaGlkZGVuOyBQQURESU5H +LUxFRlQ6IDEycHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cv +aW1hZ2VzL2NzZG5pbmRleF9waWM1LmdpZik7IE9WRVJGTE9XLVg6IGhpZGRlbjsgUEFERElORy1C +T1RUT006IDBweDsgTUFSR0lOOiAwcHggMHB4IDZweDsgTElORS1IRUlHSFQ6IDE5cHg7IFBBRERJ +TkctVE9QOiAwcHg7IEhFSUdIVDogMzZweDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJh +Y2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxlPeOAkOS6rOS4nOWVhuWfjuOAkeiv +muiBmOaJi+acuuW8gOWPkeW3peeoi+W4iO+8jOi9r+S7tuW8gOWPkeW3peeoi+W4iO+8jOassuiv +leS7jumAnyEgDQogIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBu +b25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsOTMpOyBocmVmPSJodHRwOi8vZy5j +c2RuLm5ldC81MTYyOTkwIiANCiAgdGFyZ2V0PV9ibGFuaz7jgJDkuqzkuJzllYbln47jgJHor5ro +gZjmiYvmnLrlvIDlj5Hlt6XnqIvluIjvvIzova/ku7blvIDlj5Hlt6XnqIvluIjvvIzmrLLor5Xk +u47pgJ8hPC9BPjwvREQ+DQogIDxERCANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFD +S0dST1VORC1QT1NJVElPTjogMnB4IDdweDsgT1ZFUkZMT1ctWTogaGlkZGVuOyBQQURESU5HLUxF +RlQ6IDEycHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1h +Z2VzL2NzZG5pbmRleF9waWM1LmdpZik7IE9WRVJGTE9XLVg6IGhpZGRlbjsgUEFERElORy1CT1RU +T006IDBweDsgTUFSR0lOOiAwcHggMHB4IDZweDsgTElORS1IRUlHSFQ6IDE5cHg7IFBBRERJTkct +VE9QOiAwcHg7IEhFSUdIVDogMzZweDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tn +cm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxlPeOAkEF1dG9kZXNr44CR5qyn54m55YWL +6L2v5Lu2KOS4reWbvSnor5rogZjova/ku7blvIDlj5Es5rWL6K+VLOeglOeptuWRmCANCiAgc3R5 +bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNr +PUxvZ0NsaWNrQ291bnQodGhpcyw5Myk7IGhyZWY9Imh0dHA6Ly9nLmNzZG4ubmV0LzUxNjI5NjYi +IA0KICB0YXJnZXQ9X2JsYW5rPuOAkEF1dG9kZXNr44CR5qyn54m55YWL6L2v5Lu2KOS4reWbvSno +r5rogZjova/ku7blvIDlj5Es5rWL6K+VLOeglOeptuWRmDwvQT48L0REPg0KICA8REQgDQogIHN0 +eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDJweCA3cHg7IE9W +RVJGTE9XLVk6IGhpZGRlbjsgUEFERElORy1MRUZUOiAxMnB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1 +cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljNS5naWYpOyBPVkVS +RkxPVy1YOiBoaWRkZW47IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4IDBweCA2cHg7 +IExJTkUtSEVJR0hUOiAxOXB4OyBQQURESU5HLVRPUDogMHB4OyBIRUlHSFQ6IDM2cHg7IGJhY2tn +cm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0 +aXRsZT3jgJBHb29nbGXjgJHor5rmi5vmioDmnK/nsr7oi7HvvIzlj7LkuIrkurrmlbDmnIDlpJro +gYzkvY3mnIDlub8hIA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElP +Tjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDkzKTsgaHJlZj0iaHR0cDov +L2cuY3Nkbi5uZXQvNTE2MjU5OSIgDQogIHRhcmdldD1fYmxhbms+44CQR29vZ2xl44CR6K+a5oub +5oqA5pyv57K+6Iux77yM5Y+y5LiK5Lq65pWw5pyA5aSa6IGM5L2N5pyA5bm/ITwvQT48L0REPg0K +ICA8REQgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046 +IDJweCA3cHg7IE9WRVJGTE9XLVk6IGhpZGRlbjsgUEFERElORy1MRUZUOiAxMnB4OyBCQUNLR1JP +VU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGlj +NS5naWYpOyBPVkVSRkxPVy1YOiBoaWRkZW47IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjog +MHB4IDBweCA2cHg7IExJTkUtSEVJR0hUOiAxOXB4OyBQQURESU5HLVRPUDogMHB4OyBIRUlHSFQ6 +IDM2cHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRp +YWwiPjxBIA0KICB0aXRsZT3jgJDng63ogZjjgJHmkJzni5DnlYXmuLjlhajlm73ng63mi5vlvIDl +j5Hlt6XnqIvluIggc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5v +bmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw5Myk7IGhyZWY9Imh0dHA6Ly9nLmNz +ZG4ubmV0LzUxNTc5NzkiIA0KICB0YXJnZXQ9X2JsYW5rPuOAkOeDreiBmOOAkeaQnOeLkOeVhea4 +uOWFqOWbveeDreaLm+W8gOWPkeW3peeoi+W4iDwvQT48L0REPg0KICA8REQgDQogIHN0eWxlPSJQ +QURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDJweCA3cHg7IE9WRVJGTE9X +LVk6IGhpZGRlbjsgUEFERElORy1MRUZUOiAxMnB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0 +cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljNS5naWYpOyBPVkVSRkxPVy1Y +OiBoaWRkZW47IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4IDBweCA2cHg7IExJTkUt +SEVJR0hUOiAxOXB4OyBQQURESU5HLVRPUDogMHB4OyBIRUlHSFQ6IDM2cHg7IGJhY2tncm91bmQt +b3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0aXRsZT0i +44CQ54Ca5L+h56eR5oqA44CR6K+a6IGYIFdJTkRPV1MgQysrIFdJTkRPV1MgQyPkuK3pq5jnuqfl +vIDlj5Hlt6XnqIvluIgiIA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JB +VElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDkzKTsgaHJlZj0iaHR0 +cDovL2cuY3Nkbi5uZXQvNTE2NzQ1NyIgDQogIHRhcmdldD1fYmxhbms+44CQ54Ca5L+h56eR5oqA +44CR6K+a6IGYIFdJTkRPV1MgQysrIFdJTkRPV1MgQyPkuK3pq5jnuqflvIDlj5Hlt6XnqIvluIg8 +L0E+PC9ERD4NCiAgPEREIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5E +LVBPU0lUSU9OOiAycHggN3B4OyBPVkVSRkxPVy1ZOiBoaWRkZW47IFBBRERJTkctTEVGVDogMTJw +eDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3Nk +bmluZGV4X3BpYzUuZ2lmKTsgT1ZFUkZMT1ctWDogaGlkZGVuOyBQQURESU5HLUJPVFRPTTogMHB4 +OyBNQVJHSU46IDBweCAwcHggNnB4OyBMSU5FLUhFSUdIVDogMTlweDsgUEFERElORy1UT1A6IDBw +eDsgSEVJR0hUOiAzNnB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1j +bGlwOiBpbml0aWFsIj48QSANCiAgdGl0bGU9IuOAkOmFt+aIkemfs+S5kOebkuOAkemrmOiWquiv +muiBmCDmv4Dmg4XniLHlpb3lt6XkvZzono3kuLrkuIDkvZMiIA0KICBzdHlsZT0iQ09MT1I6IHJn +YigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3Vu +dCh0aGlzLDkzKTsgaHJlZj0iaHR0cDovL2cuY3Nkbi5uZXQvNTE2NzQ1NCIgDQogIHRhcmdldD1f +Ymxhbms+44CQ6YW35oiR6Z+z5LmQ55uS44CR6auY6Jaq6K+a6IGYIOa/gOaDheeIseWlveW3peS9 +nOiejeS4uuS4gOS9kzwvQT48L0REPg0KICA8REQgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAw +cHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDJweCA3cHg7IE9WRVJGTE9XLVk6IGhpZGRlbjsgUEFE +RElORy1MRUZUOiAxMnB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24v +d3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljNS5naWYpOyBPVkVSRkxPVy1YOiBoaWRkZW47IFBBRERJ +TkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4IDBweCA2cHg7IExJTkUtSEVJR0hUOiAxOXB4OyBQ +QURESU5HLVRPUDogMHB4OyBIRUlHSFQ6IDM2cHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFs +OyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0aXRsZT3jgJDovr7lhoXpm4blm6Lj +gJHpq5jolqror5rogZhKQVZB6K6y5biILuW1jOWFpeW8j+iusuW4iC4zR+iusuW4iC7mioDmnK/m +gLvnm5Eu5YiG5YWs5Y+45oC757uP55CGIA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRF +WFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDkzKTsg +aHJlZj0iaHR0cDovL2cuY3Nkbi5uZXQvNTE2NzQxNCIgDQogIHRhcmdldD1fYmxhbms+44CQ6L6+ +5YaF6ZuG5Zui44CR6auY6Jaq6K+a6IGYSkFWQeiusuW4iC7ltYzlhaXlvI/orrLluIguM0forrLl +uIgu5oqA5pyv5oC755uRLuWIhuWFrOWPuOaAu+e7j+eQhjwvQT48L0REPg0KICA8REQgDQogIHN0 +eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDJweCA3cHg7IE9W +RVJGTE9XLVk6IGhpZGRlbjsgUEFERElORy1MRUZUOiAxMnB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1 +cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljNS5naWYpOyBPVkVS +RkxPVy1YOiBoaWRkZW47IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4IDBweCA2cHg7 +IExJTkUtSEVJR0hUOiAxOXB4OyBQQURESU5HLVRPUDogMHB4OyBIRUlHSFQ6IDM2cHg7IGJhY2tn +cm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0 +aXRsZT3jgJDlpKnpmYXnvZHjgJHmgKXogZhKYXZh5bqU55So5p625p6E5biI44CB6auY57qnSmF2 +YeW3peeoi+W4iOOAgee9kemhteiuvuiuoeW4iCANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDAp +OyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw5 +Myk7IGhyZWY9Imh0dHA6Ly9nLmNzZG4ubmV0LzUxNjY5MTciIA0KICB0YXJnZXQ9X2JsYW5rPuOA +kOWkqemZhee9keOAkeaApeiBmEphdmHlupTnlKjmnrbmnoTluIjjgIHpq5jnuqdKYXZh5bel56iL +5biI44CB572R6aG16K6+6K6h5biIPC9BPjwvREQ+DQogIDxERCANCiAgc3R5bGU9IlBBRERJTkct +UklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMnB4IDdweDsgT1ZFUkZMT1ctWTogaGlk +ZGVuOyBQQURESU5HLUxFRlQ6IDEycHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3Nk +bmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWM1LmdpZik7IE9WRVJGTE9XLVg6IGhpZGRl +bjsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHggMHB4IDZweDsgTElORS1IRUlHSFQ6 +IDE5cHg7IFBBRERJTkctVE9QOiAwcHg7IEhFSUdIVDogMzZweDsgYmFja2dyb3VuZC1vcmlnaW46 +IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxlPeOAkOS4iua1 +t+mFt+WoseOAkemrmOiWquaApeiBmOacjeWKoeWZqOS4u+eoi+OAgeacjeWKoeWZqOeoi+W6jyBz +dHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xp +Y2s9TG9nQ2xpY2tDb3VudCh0aGlzLDkzKTsgaHJlZj0iaHR0cDovL2cuY3Nkbi5uZXQvNTE2Njkx +MyIgDQogIHRhcmdldD1fYmxhbms+44CQ5LiK5rW36YW35aix44CR6auY6Jaq5oCl6IGY5pyN5Yqh +5Zmo5Li756iL44CB5pyN5Yqh5Zmo56iL5bqPPC9BPjwvREQ+DQogIDxERCANCiAgc3R5bGU9IlBB +RERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMnB4IDdweDsgT1ZFUkZMT1ct +WTogaGlkZGVuOyBQQURESU5HLUxFRlQ6IDEycHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRw +Oi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWM1LmdpZik7IE9WRVJGTE9XLVg6 +IGhpZGRlbjsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHggMHB4IDZweDsgTElORS1I +RUlHSFQ6IDE5cHg7IFBBRERJTkctVE9QOiAwcHg7IEhFSUdIVDogMzZweDsgYmFja2dyb3VuZC1v +cmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxlPeOA +kOWIm+aWsOW3peWcuuOAkeaKgOacr+exu+iBjOS9jeeDreaLm++8jOeri+WNs+WKoOWFpeWxnuS6 +juS9oOiHquW3seeahOWFrOWPuCANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURF +Q09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw5Myk7IGhyZWY9 +Imh0dHA6Ly9nLmNzZG4ubmV0LzUxNjY3NTUiIA0KICB0YXJnZXQ9X2JsYW5rPuOAkOWIm+aWsOW3 +peWcuuOAkeaKgOacr+exu+iBjOS9jeeDreaLm++8jOeri+WNs+WKoOWFpeWxnuS6juS9oOiHquW3 +seeahOWFrOWPuDwvQT48L0REPg0KICA8REQgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7 +IEJBQ0tHUk9VTkQtUE9TSVRJT046IDJweCA3cHg7IE9WRVJGTE9XLVk6IGhpZGRlbjsgUEFERElO +Ry1MRUZUOiAxMnB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3 +L2ltYWdlcy9jc2RuaW5kZXhfcGljNS5naWYpOyBPVkVSRkxPVy1YOiBoaWRkZW47IFBBRERJTkct +Qk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4IDBweCA2cHg7IExJTkUtSEVJR0hUOiAxOXB4OyBQQURE +SU5HLVRPUDogMHB4OyBIRUlHSFQ6IDM2cHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBi +YWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0aXRsZT3jgJDlrr3lqLHmlbDnoIHjgJHo +r5rogZhDKyvlupTnlKjova/ku7blt6XnqIvluIjvvIjlpJrlqpLkvZMv572R57uc5pa55ZCR77yJ +44CBLm5ldOW8gOWPkeW3peeoi+W4iCANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhU +LURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw5Myk7IGhy +ZWY9Imh0dHA6Ly9nLmNzZG4ubmV0LzUxNjU4OTkiIA0KICB0YXJnZXQ9X2JsYW5rPuOAkOWuveWo +seaVsOeggeOAkeivmuiBmEMrK+W6lOeUqOi9r+S7tuW3peeoi+W4iO+8iOWkmuWqkuS9ky/nvZHn +u5zmlrnlkJHvvInjgIEubmV05byA5Y+R5bel56iL5biIPC9BPjwvREQ+DQogIDxERCANCiAgc3R5 +bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMnB4IDdweDsgT1ZF +UkZMT1ctWTogaGlkZGVuOyBQQURESU5HLUxFRlQ6IDEycHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVy +bChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWM1LmdpZik7IE9WRVJG +TE9XLVg6IGhpZGRlbjsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHggMHB4IDZweDsg +TElORS1IRUlHSFQ6IDE5cHg7IFBBRERJTkctVE9QOiAwcHg7IEhFSUdIVDogMzZweDsgYmFja2dy +b3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRp +dGxlPSLjgJDlm6I4MDDjgJFOby4x5Zui6LSt5a+86Iiq6K+a6IGYUnVieSBvbiBSYWlsc+mrmOaJ +i++8gSIgDQogIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25l +IiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsOTMpOyBocmVmPSJodHRwOi8vZy5jc2Ru +Lm5ldC81MTY1ODc2IiANCiAgdGFyZ2V0PV9ibGFuaz7jgJDlm6I4MDDjgJFOby4x5Zui6LSt5a+8 +6Iiq6K+a6IGYUnVieSBvbiBSYWlsc+mrmOaJi++8gTwvQT48L0REPg0KICA8REQgDQogIHN0eWxl +PSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDJweCA3cHg7IE9WRVJG +TE9XLVk6IGhpZGRlbjsgUEFERElORy1MRUZUOiAxMnB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwo +aHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljNS5naWYpOyBPVkVSRkxP +Vy1YOiBoaWRkZW47IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4IDBweCA2cHg7IExJ +TkUtSEVJR0hUOiAxOXB4OyBQQURESU5HLVRPUDogMHB4OyBIRUlHSFQ6IDM2cHg7IGJhY2tncm91 +bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0aXRs +ZT0i44CQ576O5Zu95Zu95a625Luq5Zmo44CR6K+a6IGY6auY57qn6L2v5Lu2ICDlt6XnqIvluIgg +IOS/oeWPt+WkhOeQhui9r+S7tumDqOmXqOe7j+eQhiIgDQogIHN0eWxlPSJDT0xPUjogcmdiKDAs +MCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRo +aXMsOTMpOyBocmVmPSJodHRwOi8vZy5jc2RuLm5ldC81MTY1Njg5IiANCiAgdGFyZ2V0PV9ibGFu +az7jgJDnvo7lm73lm73lrrbku6rlmajjgJHor5rogZjpq5jnuqfova/ku7Yg5bel56iL5biIIOS/ +oeWPt+WkhOeQhui9r+S7tumDqOmXqOe7j+eQhjwvQT48L0REPg0KICA8REQgDQogIHN0eWxlPSJQ +QURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDJweCA3cHg7IE9WRVJGTE9X +LVk6IGhpZGRlbjsgUEFERElORy1MRUZUOiAxMnB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0 +cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljNS5naWYpOyBPVkVSRkxPVy1Y +OiBoaWRkZW47IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4IDBweCA2cHg7IExJTkUt +SEVJR0hUOiAxOXB4OyBQQURESU5HLVRPUDogMHB4OyBIRUlHSFQ6IDM2cHg7IGJhY2tncm91bmQt +b3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0aXRsZT3j +gJDmtZnmsZ/pqbDmtbflrp7kuJrjgJHor5rogZjpobnnm67nu4/nkIbvvIxQSFAsTVlTUUwsU0VP +LOa1i+ivle+8jOi/kOe7tO+8jOetluWIku+8jOiuvuiuoeetieiBjCANCiAgc3R5bGU9IkNPTE9S +OiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNr +Q291bnQodGhpcyw5Myk7IGhyZWY9Imh0dHA6Ly9nLmNzZG4ubmV0LzUxNjU2NjUiIA0KICB0YXJn +ZXQ9X2JsYW5rPuOAkOa1meaxn+mpsOa1t+WunuS4muOAkeivmuiBmOmhueebrue7j+eQhu+8jFBI +UCxNWVNRTCxTRU8s5rWL6K+V77yM6L+Q57u077yM562W5YiS77yM6K6+6K6h562J6IGMPC9BPjwv +REQ+DQogIDxERCANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJ +VElPTjogMnB4IDdweDsgT1ZFUkZMT1ctWTogaGlkZGVuOyBQQURESU5HLUxFRlQ6IDEycHg7IEJB +Q0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRl +eF9waWM1LmdpZik7IE9WRVJGTE9XLVg6IGhpZGRlbjsgUEFERElORy1CT1RUT006IDBweDsgTUFS +R0lOOiAwcHggMHB4IDZweDsgTElORS1IRUlHSFQ6IDE5cHg7IFBBRERJTkctVE9QOiAwcHg7IEhF +SUdIVDogMzZweDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDog +aW5pdGlhbCI+PEEgDQogIHRpdGxlPSLjgJBJbmZvc3lz44CR6K+a6IGY77yaSjJFRSDpobnnm67k +uLvnrqEv77yI6LWE5rex77yJ6L2v5Lu256CU5Y+R5bel56iL5biILy5OZXTotYTmt7Hova/ku7bn +oJTlj5Hlt6XnqIvluIgiIA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JB +VElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDkzKTsgaHJlZj0iaHR0 +cDovL2cuY3Nkbi5uZXQvNTE2NTU0OCIgDQogIHRhcmdldD1fYmxhbms+44CQSW5mb3N5c+OAkeiv +muiBmO+8mkoyRUUg6aG555uu5Li7566hL++8iOi1hOa3se+8iei9r+S7tueglOWPkeW3peeoi+W4 +iC8uTmV06LWE5rex6L2v5Lu256CU5Y+R5bel56iL5biIPC9BPjwvREQ+DQogIDxERCANCiAgc3R5 +bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMnB4IDdweDsgT1ZF +UkZMT1ctWTogaGlkZGVuOyBQQURESU5HLUxFRlQ6IDEycHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVy +bChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWM1LmdpZik7IE9WRVJG +TE9XLVg6IGhpZGRlbjsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHggMHB4IDZweDsg +TElORS1IRUlHSFQ6IDE5cHg7IFBBRERJTkctVE9QOiAwcHg7IEhFSUdIVDogMzZweDsgYmFja2dy +b3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRp +dGxlPeOAkOWMl+S6rOmrmOaIkOmVv+WFrOWPuOOAkemrmOiWquaLm+iBmC5uZXTlkITnuqfnqIvl +uo/lkZjvvIzmrKLov47lupTlsYrnlJ8gDQogIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVY +VC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsOTMpOyBo +cmVmPSJodHRwOi8vZy5jc2RuLm5ldC81MTY1NDA3IiANCiAgdGFyZ2V0PV9ibGFuaz7jgJDljJfk +uqzpq5jmiJDplb/lhazlj7jjgJHpq5jolqrmi5vogZgubmV05ZCE57qn56iL5bqP5ZGY77yM5qyi +6L+O5bqU5bGK55SfPC9BPjwvREQ+DQogIDxERCANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBw +eDsgQkFDS0dST1VORC1QT1NJVElPTjogMnB4IDdweDsgT1ZFUkZMT1ctWTogaGlkZGVuOyBQQURE +SU5HLUxFRlQ6IDEycHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93 +d3cvaW1hZ2VzL2NzZG5pbmRleF9waWM1LmdpZik7IE9WRVJGTE9XLVg6IGhpZGRlbjsgUEFERElO +Ry1CT1RUT006IDBweDsgTUFSR0lOOiAwcHggMHB4IDZweDsgTElORS1IRUlHSFQ6IDE5cHg7IFBB +RERJTkctVE9QOiAwcHg7IEhFSUdIVDogMzZweDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7 +IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxlPSLjgJDpk7booYzpobnnm67j +gJHor5rogZhqYXZh5YmN5Y+wL+WQjuWPsOW8gOWPkeS6uuWRmOWkmuWQjSDlj4pTQVPmlbDmja7l +iIbmnpDlkZjvvIzmrLLor5Xku47pgJ/vvIEiIA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7 +IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDkz +KTsgaHJlZj0iaHR0cDovL2cuY3Nkbi5uZXQvNTE2NTE5OSIgDQogIHRhcmdldD1fYmxhbms+44CQ +6ZO26KGM6aG555uu44CR6K+a6IGYamF2YeWJjeWPsC/lkI7lj7DlvIDlj5HkurrlkZjlpJrlkI0g +5Y+KU0FT5pWw5o2u5YiG5p6Q5ZGY77yM5qyy6K+V5LuO6YCf77yBPC9BPjwvREQ+DQogIDxERCAN +CiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMnB4IDdw +eDsgT1ZFUkZMT1ctWTogaGlkZGVuOyBQQURESU5HLUxFRlQ6IDEycHg7IEJBQ0tHUk9VTkQtSU1B +R0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWM1LmdpZik7 +IE9WRVJGTE9XLVg6IGhpZGRlbjsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHggMHB4 +IDZweDsgTElORS1IRUlHSFQ6IDE5cHg7IFBBRERJTkctVE9QOiAwcHg7IEhFSUdIVDogMzZweDsg +YmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEg +DQogIHRpdGxlPeOAkOWMl+S6rOmXu+iogOenkeaKgOOAkeivmuiBmC5uZXTpq5jnuqflvIDlj5Hl +t6XnqIvluIjjgIHmiYvmnLrova/ku7blvIDlj5Hlt6XnqIvluIjvvIjlupTlsYrmr5XkuJrnlJ/k +vJjlhYjvvIkgDQogIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBu +b25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsOTMpOyBocmVmPSJodHRwOi8vZy5j +c2RuLm5ldC81MTY0NzA3IiANCiAgdGFyZ2V0PV9ibGFuaz7jgJDljJfkuqzpl7voqIDnp5HmioDj +gJHor5rogZgubmV06auY57qn5byA5Y+R5bel56iL5biI44CB5omL5py66L2v5Lu25byA5Y+R5bel +56iL5biI77yI5bqU5bGK5q+V5Lia55Sf5LyY5YWI77yJPC9BPjwvREQ+DQogIDxERCANCiAgc3R5 +bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMnB4IDdweDsgT1ZF +UkZMT1ctWTogaGlkZGVuOyBQQURESU5HLUxFRlQ6IDEycHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVy +bChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWM1LmdpZik7IE9WRVJG +TE9XLVg6IGhpZGRlbjsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHggMHB4IDZweDsg +TElORS1IRUlHSFQ6IDE5cHg7IFBBRERJTkctVE9QOiAwcHg7IEhFSUdIVDogMzZweDsgYmFja2dy +b3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRp +dGxlPeOAkOS4iua1t+eUteWtkOWVhuWKoeW5s+WPsOOAkemHjemHkeivmuiBmC5uZXQsYXNwLGph +dmFzY3JpcHTotYTmt7HnqIvluo/lkZggDQogIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVY +VC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsOTMpOyBo +cmVmPSJodHRwOi8vZy5jc2RuLm5ldC81MTY0NjcxIiANCiAgdGFyZ2V0PV9ibGFuaz7jgJDkuIrm +tbfnlLXlrZDllYbliqHlubPlj7DjgJHph43ph5Hor5rogZgubmV0LGFzcCxqYXZhc2NyaXB06LWE +5rex56iL5bqP5ZGYPC9BPjwvREQ+DQogIDxERCANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBw +eDsgQkFDS0dST1VORC1QT1NJVElPTjogMnB4IDdweDsgT1ZFUkZMT1ctWTogaGlkZGVuOyBQQURE +SU5HLUxFRlQ6IDEycHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93 +d3cvaW1hZ2VzL2NzZG5pbmRleF9waWM1LmdpZik7IE9WRVJGTE9XLVg6IGhpZGRlbjsgUEFERElO +Ry1CT1RUT006IDBweDsgTUFSR0lOOiAwcHggMHB4IDZweDsgTElORS1IRUlHSFQ6IDE5cHg7IFBB +RERJTkctVE9QOiAwcHg7IEhFSUdIVDogMzZweDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7 +IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxlPeOAkEVG5YWo55CD56CU5Y+R +5Lit5b+D44CR55m+5LiH5bm06Jaq6K+a5oub5oqA5pyv57K+6Iux77yM5pWw55m+6IGM5L2N54Ot +5oub5LitIA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9u +ZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDkzKTsgaHJlZj0iaHR0cDovL2cuY3Nk +bi5uZXQvNTE2NDAzNCIgDQogIHRhcmdldD1fYmxhbms+44CQRUblhajnkIPnoJTlj5HkuK3lv4Pj +gJHnmb7kuIflubTolqror5rmi5vmioDmnK/nsr7oi7HvvIzmlbDnmb7ogYzkvY3ng63mi5vkuK08 +L0E+PC9ERD4NCiAgPEREIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5E +LVBPU0lUSU9OOiAycHggN3B4OyBPVkVSRkxPVy1ZOiBoaWRkZW47IFBBRERJTkctTEVGVDogMTJw +eDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3Nk +bmluZGV4X3BpYzUuZ2lmKTsgT1ZFUkZMT1ctWDogaGlkZGVuOyBQQURESU5HLUJPVFRPTTogMHB4 +OyBNQVJHSU46IDBweCAwcHggNnB4OyBMSU5FLUhFSUdIVDogMTlweDsgUEFERElORy1UT1A6IDBw +eDsgSEVJR0hUOiAzNnB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1j +bGlwOiBpbml0aWFsIj48QSANCiAgdGl0bGU944CQQW1hem9u44CR5Lqa6ams6YCK6K+a6IGY5oqA +5pyv5LiT5a6277yBIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBu +b25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsOTMpOyBocmVmPSJodHRwOi8vZy5j +c2RuLm5ldC81MTY2OTE2IiANCiAgdGFyZ2V0PV9ibGFuaz7jgJBBbWF6b27jgJHkuprpqazpgIro +r5rogZjmioDmnK/kuJPlrrbvvIE8L0E+PC9ERD4NCiAgPEREIA0KICBzdHlsZT0iUEFERElORy1S +SUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAycHggN3B4OyBPVkVSRkxPVy1ZOiBoaWRk +ZW47IFBBRERJTkctTEVGVDogMTJweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2Ru +aW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzUuZ2lmKTsgT1ZFUkZMT1ctWDogaGlkZGVu +OyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweCAwcHggNnB4OyBMSU5FLUhFSUdIVDog +MTlweDsgUEFERElORy1UT1A6IDBweDsgSEVJR0hUOiAzNnB4OyBiYWNrZ3JvdW5kLW9yaWdpbjog +aW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgdGl0bGU944CQ572R6Lev +5pe25Luj44CR6auY6Jaq6K+a6IGYQysr44CBLm5ldOW8gOWPkeW3peeoi+W4iCBzdHlsZT0iQ09M +T1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xp +Y2tDb3VudCh0aGlzLDkzKTsgaHJlZj0iaHR0cDovL2cuY3Nkbi5uZXQvNTE2MzM2OSIgDQogIHRh +cmdldD1fYmxhbms+44CQ572R6Lev5pe25Luj44CR6auY6Jaq6K+a6IGYQysr44CBLm5ldOW8gOWP +keW3peeoi+W4iDwvQT48L0REPg0KICA8REQgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7 +IEJBQ0tHUk9VTkQtUE9TSVRJT046IDJweCA3cHg7IE9WRVJGTE9XLVk6IGhpZGRlbjsgUEFERElO +Ry1MRUZUOiAxMnB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3 +L2ltYWdlcy9jc2RuaW5kZXhfcGljNS5naWYpOyBPVkVSRkxPVy1YOiBoaWRkZW47IFBBRERJTkct +Qk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4IDBweCA2cHg7IExJTkUtSEVJR0hUOiAxOXB4OyBQQURE +SU5HLVRPUDogMHB4OyBIRUlHSFQ6IDM2cHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBi +YWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0aXRsZT3jgJDkuqzkuJzllYbln47jgJHo +r5rogZjmiYvmnLrlvIDlj5Hlt6XnqIvluIjvvIzova/ku7blvIDlj5Hlt6XnqIvluIjvvIzmrLLo +r5Xku47pgJ8hIA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjog +bm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDkzKTsgaHJlZj0iaHR0cDovL2cu +Y3Nkbi5uZXQvNTE2Mjk5MCIgDQogIHRhcmdldD1fYmxhbms+44CQ5Lqs5Lic5ZWG5Z+O44CR6K+a +6IGY5omL5py65byA5Y+R5bel56iL5biI77yM6L2v5Lu25byA5Y+R5bel56iL5biI77yM5qyy6K+V +5LuO6YCfITwvQT48L0REPg0KICA8REQgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJB +Q0tHUk9VTkQtUE9TSVRJT046IDJweCA3cHg7IE9WRVJGTE9XLVk6IGhpZGRlbjsgUEFERElORy1M +RUZUOiAxMnB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2lt +YWdlcy9jc2RuaW5kZXhfcGljNS5naWYpOyBPVkVSRkxPVy1YOiBoaWRkZW47IFBBRERJTkctQk9U +VE9NOiAwcHg7IE1BUkdJTjogMHB4IDBweCA2cHg7IExJTkUtSEVJR0hUOiAxOXB4OyBQQURESU5H +LVRPUDogMHB4OyBIRUlHSFQ6IDM2cHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNr +Z3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0aXRsZT3jgJBBdXRvZGVza+OAkeasp+eJueWF +i+i9r+S7tijkuK3lm70p6K+a6IGY6L2v5Lu25byA5Y+RLOa1i+ivlSznoJTnqbblkZggDQogIHN0 +eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGlj +az1Mb2dDbGlja0NvdW50KHRoaXMsOTMpOyBocmVmPSJodHRwOi8vZy5jc2RuLm5ldC81MTYyOTY2 +IiANCiAgdGFyZ2V0PV9ibGFuaz7jgJBBdXRvZGVza+OAkeasp+eJueWFi+i9r+S7tijkuK3lm70p +6K+a6IGY6L2v5Lu25byA5Y+RLOa1i+ivlSznoJTnqbblkZg8L0E+PC9ERD4NCiAgPEREIA0KICBz +dHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAycHggN3B4OyBP +VkVSRkxPVy1ZOiBoaWRkZW47IFBBRERJTkctTEVGVDogMTJweDsgQkFDS0dST1VORC1JTUFHRTog +dXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzUuZ2lmKTsgT1ZF +UkZMT1ctWDogaGlkZGVuOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweCAwcHggNnB4 +OyBMSU5FLUhFSUdIVDogMTlweDsgUEFERElORy1UT1A6IDBweDsgSEVJR0hUOiAzNnB4OyBiYWNr +Z3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAg +dGl0bGU944CQR29vZ2xl44CR6K+a5oub5oqA5pyv57K+6Iux77yM5Y+y5LiK5Lq65pWw5pyA5aSa +6IGM5L2N5pyA5bm/ISANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJ +T046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw5Myk7IGhyZWY9Imh0dHA6 +Ly9nLmNzZG4ubmV0LzUxNjI1OTkiIA0KICB0YXJnZXQ9X2JsYW5rPuOAkEdvb2dsZeOAkeivmuaL +m+aKgOacr+eyvuiLse+8jOWPsuS4iuS6uuaVsOacgOWkmuiBjOS9jeacgOW5vyE8L0E+PC9ERD4N +CiAgPEREIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9O +OiAycHggN3B4OyBPVkVSRkxPVy1ZOiBoaWRkZW47IFBBRERJTkctTEVGVDogMTJweDsgQkFDS0dS +T1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3Bp +YzUuZ2lmKTsgT1ZFUkZMT1ctWDogaGlkZGVuOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46 +IDBweCAwcHggNnB4OyBMSU5FLUhFSUdIVDogMTlweDsgUEFERElORy1UT1A6IDBweDsgSEVJR0hU +OiAzNnB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0 +aWFsIj48QSANCiAgdGl0bGU944CQ54Ot6IGY44CR5pCc54uQ55WF5ri45YWo5Zu954Ot5oub5byA +5Y+R5bel56iL5biIIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBu +b25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsOTMpOyBocmVmPSJodHRwOi8vZy5j +c2RuLm5ldC81MTU3OTc5IiANCiAgdGFyZ2V0PV9ibGFuaz7jgJDng63ogZjjgJHmkJzni5DnlYXm +uLjlhajlm73ng63mi5vlvIDlj5Hlt6XnqIvluIg8L0E+PC9ERD48L0RMPjwvRElWPjwvRElWPg0K +PERJViBjbGFzcz1zaWRlYmFyX2NvbiANCnN0eWxlPSJESVNQTEFZOiBpbmxpbmU7IEZMT0FUOiBs +ZWZ0OyBNQVJHSU46IDZweCAzcHggMnB4OyBXSURUSDogMjAycHgiPg0KPEg0IGNsYXNzPXR4dF8x +MiANCnN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IFBBRERJTkctTEVGVDogM3B4OyBGT05ULVNJ +WkU6IDEycHg7IFBBRERJTkctQk9UVE9NOiA1cHg7IE1BUkdJTjogMHB4OyBQQURESU5HLVRPUDog +MHB4OyBCT1JERVItQk9UVE9NOiByZ2IoMjA0LDIwNCwyMDQpIDFweCBzb2xpZDsgUE9TSVRJT046 +IHJlbGF0aXZlIj48U1BBTiANCmNsYXNzPXR4dF9ncmF5IA0Kc3R5bGU9IkZPTlQtV0VJR0hUOiBu +b3JtYWw7IEZMT0FUOiByaWdodDsgQ09MT1I6IHJnYigxMDIsMTAyLDEwMikiPjwvU1BBTj7nibnl +iKvmjqjojZA8L0g0Pg0KPERMIGNsYXNzPXNlc3Npb25fc3R5bGUgDQpzdHlsZT0iUEFERElORy1S +SUdIVDogM3B4OyBQQURESU5HLUxFRlQ6IDNweDsgRkxPQVQ6IGxlZnQ7IFBBRERJTkctQk9UVE9N +OiA1cHg7IE1BUkdJTjogMnB4IDBweCAwcHg7IFdJRFRIOiAxOTZweDsgUEFERElORy1UT1A6IDEw +cHg7IEJPUkRFUi1CT1RUT006IHJnYigyMDQsMjA0LDIwNCkgMXB4IHNvbGlkOyBCQUNLR1JPVU5E +LUNPTE9SOiByZ2IoMjU1LDI1NSwyNTUpOyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFj +a2dyb3VuZC1jbGlwOiBpbml0aWFsIj4NCiAgPEREIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDog +MHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAycHggN3B4OyBQQURESU5HLUxFRlQ6IDEycHg7IEJB +Q0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRl +eF9waWM1LmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBMSU5FLUhFSUdI +VDogMTlweDsgUEFERElORy1UT1A6IDBweDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJh +Y2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxlPeaKpeWQjUlCTeW8gOWPkeiAheWk +p+S8mui1ouWkmumHjeWkp+WlliBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JB +VElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDkzKTsgaHJlZj0iaHR0 +cDovL2cuY3Nkbi5uZXQvNTE2NjkzMCIgDQogIHRhcmdldD1fYmxhbms+5oql5ZCNSUJN5byA5Y+R +6ICF5aSn5Lya6LWi5aSa6YeN5aSn5aWWPC9BPjwvREQ+DQogIDxERCANCiAgc3R5bGU9IlBBRERJ +TkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMnB4IDdweDsgUEFERElORy1MRUZU +OiAxMnB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdl +cy9jc2RuaW5kZXhfcGljNS5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweDsg +TElORS1IRUlHSFQ6IDE5cHg7IFBBRERJTkctVE9QOiAwcHg7IGJhY2tncm91bmQtb3JpZ2luOiBp +bml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0aXRsZT0i44CQ5pyJ5aWW +44CR5Y+C5LiO5aSp57+86LCD5p+lIOi1ouelnuenmOekvOWTge+8gSIgc3R5bGU9IkNPTE9SOiBy +Z2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291 +bnQodGhpcyw5Myk7IGhyZWY9Imh0dHA6Ly9nLmNzZG4ubmV0LzUxNjU5MDgiIA0KICB0YXJnZXQ9 +X2JsYW5rPuOAkOacieWlluOAkeWPguS4juWkqee/vOiwg+afpSDotaLnpZ7np5jnpLw8L0E+PC9E +RD4NCiAgPEREIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lU +SU9OOiAycHggN3B4OyBQQURESU5HLUxFRlQ6IDEycHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybCho +dHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWM1LmdpZik7IFBBRERJTkct +Qk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBMSU5FLUhFSUdIVDogMTlweDsgUEFERElORy1UT1A6 +IDBweDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlh +bCI+PEEgDQogIHRpdGxlPeWPguWKoOWIm+aWsOadr+i1ouaAu+minTIw5LiH576O6YeRIHN0eWxl +PSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1M +b2dDbGlja0NvdW50KHRoaXMsOTMpOyBocmVmPSJodHRwOi8vZy5jc2RuLm5ldC81MTY1NzY2IiAN +CiAgdGFyZ2V0PV9ibGFuaz7lj4LliqDliJvmlrDmna/otaLmgLvpop0yMOS4h+e+jumHkTwvQT48 +L0REPg0KICA8REQgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9T +SVRJT046IDJweCA3cHg7IFBBRERJTkctTEVGVDogMTJweDsgQkFDS0dST1VORC1JTUFHRTogdXJs +KGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzUuZ2lmKTsgUEFERElO +Ry1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IExJTkUtSEVJR0hUOiAxOXB4OyBQQURESU5HLVRP +UDogMHB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0 +aWFsIj48QSANCiAgdGl0bGU944CQ5pyJ5aWW6LCD5p+l44CR5LyB5Lia5a6J5YWo562J57qn6K+E +5rWLIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAg +b25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsOTMpOyBocmVmPSJodHRwOi8vZy5jc2RuLm5ldC81 +MTY1NTQ1IiANCiAgdGFyZ2V0PV9ibGFuaz7jgJDmnInlpZbosIPmn6XjgJHkvIHkuJrlronlhajn +rYnnuqfor4TmtYs8L0E+PC9ERD4NCiAgPEREIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4 +OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAycHggN3B4OyBQQURESU5HLUxFRlQ6IDEycHg7IEJBQ0tH +Uk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9w +aWM1LmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBMSU5FLUhFSUdIVDog +MTlweDsgUEFERElORy1UT1A6IDBweDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tn +cm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxlPeWPguS4jklFOeWkp+i1m+W+l+WllumH +kei1oum8oOaghyBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9u +ZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDkzKTsgaHJlZj0iaHR0cDovL2cuY3Nk +bi5uZXQvNTE2NTE5NiIgDQogIHRhcmdldD1fYmxhbms+5Y+C5LiOSUU55aSn6LWb5b6X5aWW6YeR +6LWi6byg5qCHPC9BPjwvREQ+DQogIDxERCANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsg +QkFDS0dST1VORC1QT1NJVElPTjogMnB4IDdweDsgUEFERElORy1MRUZUOiAxMnB4OyBCQUNLR1JP +VU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGlj +NS5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweDsgTElORS1IRUlHSFQ6IDE5 +cHg7IFBBRERJTkctVE9QOiAwcHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3Jv +dW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0aXRsZT3jgJDnqIvluo/mjqjojZDjgJHnvZHnq5nl +hoXlrrnnrqHnkIbns7vnu58gc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJ +T046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw5Myk7IGhyZWY9Imh0dHA6 +Ly9nLmNzZG4ubmV0LzUxNjUxOTUiIA0KICB0YXJnZXQ9X2JsYW5rPuOAkOeoi+W6j+aOqOiNkOOA +kee9keermeWGheWuueeuoeeQhuezu+e7nzwvQT48L0REPg0KICA8REQgDQogIHN0eWxlPSJQQURE +SU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDJweCA3cHg7IFBBRERJTkctTEVG +VDogMTJweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFn +ZXMvY3NkbmluZGV4X3BpYzUuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7 +IExJTkUtSEVJR0hUOiAxOXB4OyBQQURESU5HLVRPUDogMHB4OyBiYWNrZ3JvdW5kLW9yaWdpbjog +aW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgdGl0bGU9Ik1lZUdv5Lit +5Zu95Yy65byA5Y+R6ICF56CU6K6o5LyaIOeOsOWcuuebtOWHuyIgc3R5bGU9IkNPTE9SOiByZ2Io +MCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQo +dGhpcyw5Myk7IGhyZWY9Imh0dHA6Ly9nLmNzZG4ubmV0LzUxNjUwNzkiIA0KICB0YXJnZXQ9X2Js +YW5rPk1lZUdv5Lit5Zu95Yy65byA5Y+R6ICF56CU6K6o5LyaPC9BPjwvREQ+DQogIDxERCANCiAg +c3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMnB4IDdweDsg +UEFERElORy1MRUZUOiAxMnB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcu +Y24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljNS5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBN +QVJHSU46IDBweDsgTElORS1IRUlHSFQ6IDE5cHg7IFBBRERJTkctVE9QOiAwcHg7IGJhY2tncm91 +bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0aXRs +ZT1Ob2tpYeS4uuS7gOS5iOS4jeeUqEFuZHJvaWTvvJ8gc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDAp +OyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw5 +Myk7IGhyZWY9Imh0dHA6Ly9nLmNzZG4ubmV0LzUxNTgxMTYiIA0KICB0YXJnZXQ9X2JsYW5rPk5v +a2lh5Li65LuA5LmI5LiN55SoQW5kcm88L0E+PC9ERD4NCiAgPEREIA0KICBzdHlsZT0iUEFERElO +Ry1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAycHggN3B4OyBQQURESU5HLUxFRlQ6 +IDEycHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2Vz +L2NzZG5pbmRleF9waWM1LmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBM +SU5FLUhFSUdIVDogMTlweDsgUEFERElORy1UT1A6IDBweDsgYmFja2dyb3VuZC1vcmlnaW46IGlu +aXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxlPem4oeiCi++8n+i/ +mOaYr+a9rua1ge+8nyBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjog +bm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDkzKTsgaHJlZj0iaHR0cDovL2cu +Y3Nkbi5uZXQvNTE2NzEyNyIgDQogIHRhcmdldD1fYmxhbms+6bih6IKL77yf6L+Y5piv5r2u5rWB +77yfPC9BPjwvREQ+DQogIDxERCANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dS +T1VORC1QT1NJVElPTjogMnB4IDdweDsgUEFERElORy1MRUZUOiAxMnB4OyBCQUNLR1JPVU5ELUlN +QUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljNS5naWYp +OyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweDsgTElORS1IRUlHSFQ6IDE5cHg7IFBB +RERJTkctVE9QOiAwcHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNs +aXA6IGluaXRpYWwiPjxBIA0KICB0aXRsZT0i56We5aWH55qEV2ViUVEgIiBzdHlsZT0iQ09MT1I6 +IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tD +b3VudCh0aGlzLDkzKTsgaHJlZj0iaHR0cDovL2cuY3Nkbi5uZXQvNTE1NzMxNiIgDQogIHRhcmdl +dD1fYmxhbms+56We5aWH55qEV2ViUVE8L0E+PC9ERD4NCiAgPEREIA0KICBzdHlsZT0iUEFERElO +Ry1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAycHggN3B4OyBQQURESU5HLUxFRlQ6 +IDEycHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2Vz +L2NzZG5pbmRleF9waWM1LmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBM +SU5FLUhFSUdIVDogMTlweDsgUEFERElORy1UT1A6IDBweDsgYmFja2dyb3VuZC1vcmlnaW46IGlu +aXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxlPSJNZWVHb+aYr+S6 +kuiBlOiuoeeul+WIm+aWsOWIqeWZqCAiIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1E +RUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsOTMpOyBocmVm +PSJodHRwOi8vZy5jc2RuLm5ldC81MTY0MjY4IiANCiAgdGFyZ2V0PV9ibGFuaz5NZWVHb+aYr+S6 +kuiBlOiuoeeul+WIm+aWsOWIqeWZqDwvQT48L0REPg0KICA8REQgDQogIHN0eWxlPSJQQURESU5H +LVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDJweCA3cHg7IFBBRERJTkctTEVGVDog +MTJweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMv +Y3NkbmluZGV4X3BpYzUuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IExJ +TkUtSEVJR0hUOiAxOXB4OyBQQURESU5HLVRPUDogMHB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5p +dGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgdGl0bGU95bel5YW35o6o6I2Q +77ya5bu26ZW/55S15rGg57ut6Iiq5pe26Ze0IHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVY +VC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsOTMpOyBo +cmVmPSJodHRwOi8vZy5jc2RuLm5ldC81MTY0MTUzIiANCiAgdGFyZ2V0PV9ibGFuaz7lt6Xlhbfm +jqjojZDvvJrlu7bplb/nlLXmsaDnu63oiKrml7bpl7Q8L0E+PC9ERD4NCiAgPEREIA0KICBzdHls +ZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAycHggN3B4OyBQQURE +SU5HLUxFRlQ6IDEycHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93 +d3cvaW1hZ2VzL2NzZG5pbmRleF9waWM1LmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJ +TjogMHB4OyBMSU5FLUhFSUdIVDogMTlweDsgUEFERElORy1UT1A6IDBweDsgYmFja2dyb3VuZC1v +cmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxlPeiL +seeJueWwlOW3peWFt+aOqOiNkO+8muivhOS8sOWkmuaguOezu+e7n+aAp+iDvSBzdHlsZT0iQ09M +T1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xp +Y2tDb3VudCh0aGlzLDkzKTsgaHJlZj0iaHR0cDovL2cuY3Nkbi5uZXQvNTE2NDE1NSIgDQogIHRh +cmdldD1fYmxhbms+6Iux54m55bCU5bel5YW35o6o6I2Q77ya6K+E5Lyw5aSa5qC457O757uf5oCn +PC9BPjwvREQ+PC9ETD48L0RJVj48L0RJVj4NCjxESVYgY2xhc3M9cGFnZWJsb2NrMl93cmFwIHN0 +eWxlPSJGTE9BVDogbGVmdDsgV0lEVEg6IDczNXB4Ij4NCjxESVYgY2xhc3M9cGFnZWNvbl9sYXll +cjJfbGVmdCANCnN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IERJU1BMQVk6IGlubGluZTsgUEFE +RElORy1MRUZUOiAwcHg7IEZMT0FUOiBsZWZ0OyBQQURESU5HLUJPVFRPTTogNXB4OyBNQVJHSU46 +IDBweCAwcHggMHB4IDFweDsgV0lEVEg6IDQ3MHB4OyBQQURESU5HLVRPUDogMHB4Ij4NCjxINiAN +CnN0eWxlPSJDTEVBUjogYm90aDsgUEFERElORy1SSUdIVDogMHB4OyBCT1JERVItVE9QOiByZ2Io +MjA0LDIwNCwyMDQpIDFweCBzb2xpZDsgUEFERElORy1MRUZUOiAxMHB4OyBGT05ULVNJWkU6IDE0 +cHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2Nz +ZG5pbmRleF9waWMxMS5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweDsgUEFE +RElORy1UT1A6IDVweDsgUE9TSVRJT046IHJlbGF0aXZlOyBIRUlHSFQ6IDI5cHg7IGJhY2tncm91 +bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPui1hOiurzxTUEFO +IA0KY2xhc3M9dHh0X2JsYWNrIA0Kc3R5bGU9IkZPTlQtV0VJR0hUOiBub3JtYWw7IEZPTlQtU0la +RTogMTJweDsgTUFSR0lOOiAwcHggMHB4IDBweCAxNXB4OyBDT0xPUjogcmdiKDAsMCwwKSI+Jm5i +c3A7PEEgDQpzdHlsZT0iUEFERElORy1SSUdIVDogM3B4OyBQQURESU5HLUxFRlQ6IDNweDsgUEFE +RElORy1CT1RUT006IDBweDsgQ09MT1I6IHJnYigwLDAsMCk7IFBBRERJTkctVE9QOiAwcHg7IFRF +WFQtREVDT1JBVElPTjogbm9uZSIgDQpocmVmPSJodHRwOi8vZWR1LmNzZG4ubmV0L2hlaW1hLyI+ +MTM2MuS6uueUs+ivt+WKoOWFpSLpu5HpqaznqIvluo/lkZgi5b6F5a6hPC9BPiZuYnNwOyZuYnNw +OzxBIA0Kc3R5bGU9IlBBRERJTkctUklHSFQ6IDNweDsgUEFERElORy1MRUZUOiAzcHg7IFBBRERJ +TkctQk9UVE9NOiAwcHg7IENPTE9SOiByZ2IoMCwwLDApOyBQQURESU5HLVRPUDogMHB4OyBURVhU +LURFQ09SQVRJT046IG5vbmUiIA0KaHJlZj0iaHR0cDovL3d3dy5pdGNhc3QuY24vaXRjYXN0X3N0 +YXRpYy9qYXZhanoxLmh0bSI+5byg5a2d56WlamF2YeWwseS4muaUu+eVpTwvQT48L1NQQU4+PEVN +IA0KY2xhc3M9dHh0X2JsdWUgDQpzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5E +LVBPU0lUSU9OOiAwcHggNHB4OyBQQURESU5HLUxFRlQ6IDEwcHg7IEZPTlQtV0VJR0hUOiBub3Jt +YWw7IEZPTlQtU0laRTogMTJweDsgTEVGVDogNDEwcHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybCho +dHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMxMi5naWYpOyBQQURESU5H +LUJPVFRPTTogMHB4OyBDT0xPUjogcmdiKDEsOTUsMTgyKTsgUEFERElORy1UT1A6IDBweDsgRk9O +VC1TVFlMRTogbm9ybWFsOyBQT1NJVElPTjogYWJzb2x1dGU7IFRPUDogNnB4OyBiYWNrZ3JvdW5k +LW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCnN0eWxlPSJQ +QURESU5HLVJJR0hUOiAzcHg7IFBBRERJTkctTEVGVDogM3B4OyBQQURESU5HLUJPVFRPTTogMHB4 +OyBDT0xPUjogcmdiKDEsOTUsMTgyKTsgUEFERElORy1UT1A6IDBweDsgVEVYVC1ERUNPUkFUSU9O +OiB1bmRlcmxpbmUiIA0KaHJlZj0iaHR0cDovL25ld3MuY3Nkbi5uZXQvIiB0YXJnZXQ9X2JsYW5r +PuabtOWkmjwvQT48L0VNPjwvSDY+DQo8RElWIGNsYXNzPXBhZ2Vjb25fbGF5ZXIyX2xlZnRjb24g +DQpzdHlsZT0iUEFERElORy1SSUdIVDogMTBweDsgUEFERElORy1MRUZUOiAxMHB4OyBGTE9BVDog +bGVmdDsgUEFERElORy1CT1RUT006IDVweDsgV0lEVEg6IDQ1MHB4OyBQQURESU5HLVRPUDogNXB4 +Ij4NCjxETCANCnN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IFBBRERJTkctTEVGVDogMHB4OyBQ +QURESU5HLUJPVFRPTTogMnB4OyBNQVJHSU46IDNweCAwcHg7IExJTkUtSEVJR0hUOiAyMXB4OyBQ +QURESU5HLVRPUDogMHB4OyBQT1NJVElPTjogcmVsYXRpdmUiPg0KICA8RFQgY2xhc3M9dHh0X2Js +YWNrIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAw +cHggOHB4OyBQQURESU5HLUxFRlQ6IDEwcHg7IEZPTlQtU0laRTogMTRweDsgQkFDS0dST1VORC1J +TUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzI2Lmdp +Zik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogM3B4IDBweDsgQ09MT1I6IHJnYigwLDAs +MCk7IFBBRERJTkctVE9QOiAwcHg7IFBPU0lUSU9OOiByZWxhdGl2ZTsgYmFja2dyb3VuZC1vcmln +aW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHN0eWxlPSJDT0xP +UjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlj +a0NvdW50KHRoaXMsNzIpOyANCiAgaHJlZj0iaHR0cDovL2Nsb3VkLmNzZG4ubmV0L2EvMjAxMDEy +MTUvMjgzNjg4Lmh0bWwiIA0KICB0YXJnZXQ9X2JsYW5rPkdhcnRuZXLpooTorqHku4rlubTlhajn +kIPkvIHkuJpTYWFT5pS25YWl5aKe6ZW/MTUuNyU8L0E+PFNQQU4gY2xhc3M9dHh0X2JsdWUgDQog +IHN0eWxlPSJGT05ULVNJWkU6IDEycHg7IE1BUkdJTjogMHB4IDBweCAwcHggOHB4OyBDT0xPUjog +cmdiKDEsOTUsMTgyKSI+PEEgDQogIHN0eWxlPSJDT0xPUjogcmdiKDEsOTUsMTgyKTsgVEVYVC1E +RUNPUkFUSU9OOiBub25lIiANCiAgaHJlZj0iaHR0cDovL2Nsb3VkLmNzZG4ubmV0LyIgdGFyZ2V0 +PV9ibGFuaz7lpJrmoLfljJblupTnlKjluKbmnaXnrqHnkIbmjJHmiJg8L0E+PC9TUEFOPjwvRFQ+ +DQogIDxEVCBjbGFzcz10eHRfYmxhY2sgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJB +Q0tHUk9VTkQtUE9TSVRJT046IDBweCA4cHg7IFBBRERJTkctTEVGVDogMTBweDsgRk9OVC1TSVpF +OiAxNHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdl +cy9jc2RuaW5kZXhfcGljMjYuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAzcHgg +MHB4OyBDT0xPUjogcmdiKDAsMCwwKTsgUEFERElORy1UT1A6IDBweDsgUE9TSVRJT046IHJlbGF0 +aXZlOyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFs +Ij48QSANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUi +IA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw3Mik7IA0KICBocmVmPSJodHRwOi8vbmV3 +cy5jc2RuLm5ldC9hLzIwMTAxMjE1LzI4Mzk3MC5odG1sIiANCiAgdGFyZ2V0PV9ibGFuaz7nlLLp +qqjmloflia/mgLvosIjono3lkIjlupTnlKjova/ku7bkuInlpKfmiJjnlaXln7rnoYAg5omA5pyJ +5Lqn5ZOB6Z2i5ZCR5LqR6K6h566X5byA5Y+RPC9BPjxTUEFOIGNsYXNzPXR4dF9ibHVlIA0KICBz +dHlsZT0iRk9OVC1TSVpFOiAxMnB4OyBNQVJHSU46IDBweCAwcHggMHB4IDhweDsgQ09MT1I6IHJn +YigxLDk1LDE4MikiPjxBIA0KICBzdHlsZT0iQ09MT1I6IHJnYigxLDk1LDE4Mik7IFRFWFQtREVD +T1JBVElPTjogbm9uZSIgDQogIGhyZWY9Imh0dHA6Ly9uZXdzLmNzZG4ubmV0L2EvMjAxMDEyMTUv +MjgzOTcwLmh0bWwiIA0KICB0YXJnZXQ9X2JsYW5rPjwvQT48L1NQQU4+PC9EVD4NCiAgPERUIGNs +YXNzPXR4dF9ibGFjayANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1Q +T1NJVElPTjogMHB4IDhweDsgUEFERElORy1MRUZUOiAxMHB4OyBGT05ULVNJWkU6IDE0cHg7IEJB +Q0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRl +eF9waWMyNi5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDNweCAwcHg7IENPTE9S +OiByZ2IoMCwwLDApOyBQQURESU5HLVRPUDogMHB4OyBQT1NJVElPTjogcmVsYXRpdmU7IGJhY2tn +cm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICBz +dHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xp +Y2s9TG9nQ2xpY2tDb3VudCh0aGlzLDcyKTsgDQogIGhyZWY9Imh0dHA6Ly9jbG91ZC5jc2RuLm5l +dC9hLzIwMTAxMjE1LzI4MzY4MS5odG1sIiB0YXJnZXQ9X2JsYW5rPuWVhuS4muWRqOWIiu+8mkNo +cm9tZSANCiAgT1PlrprkvY3mqKHns4rliY3mma/pu6/mt6E8L0E+PFNQQU4gY2xhc3M9dHh0X2Js +dWUgDQogIHN0eWxlPSJGT05ULVNJWkU6IDEycHg7IE1BUkdJTjogMHB4IDBweCAwcHggOHB4OyBD +T0xPUjogcmdiKDEsOTUsMTgyKSI+PEEgDQogIHN0eWxlPSJDT0xPUjogcmdiKDEsOTUsMTgyKTsg +VEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgaHJlZj0iaHR0cDovL2Nsb3VkLmNzZG4ubmV0LyIg +dGFyZ2V0PV9ibGFuaz7nvLrkuY/npL7kuqTlkozlrp7ml7blupTnlKg8L0E+PC9TUEFOPjwvRFQ+ +DQogIDxEVCBjbGFzcz10eHRfYmxhY2sgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJB +Q0tHUk9VTkQtUE9TSVRJT046IDBweCA4cHg7IFBBRERJTkctTEVGVDogMTBweDsgRk9OVC1TSVpF +OiAxNHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdl +cy9jc2RuaW5kZXhfcGljMjYuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAzcHgg +MHB4OyBDT0xPUjogcmdiKDAsMCwwKTsgUEFERElORy1UT1A6IDBweDsgUE9TSVRJT046IHJlbGF0 +aXZlOyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFs +Ij48QSANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUi +IA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw3Mik7IA0KICBocmVmPSJodHRwOi8vbmV3 +cy5jc2RuLm5ldC9hLzIwMTAxMjE1LzI4MzY4MC5odG1sIiANCiAgdGFyZ2V0PV9ibGFuaz7pm4Xo +mY5DRU/lt7TojKjmlL7lvIPov5vlhaXpmL/ph4zlt7Tlt7TokaPkuovkvJo8L0E+PFNQQU4gY2xh +c3M9dHh0X2JsdWUgDQogIHN0eWxlPSJGT05ULVNJWkU6IDEycHg7IE1BUkdJTjogMHB4IDBweCAw +cHggOHB4OyBDT0xPUjogcmdiKDEsOTUsMTgyKSI+PEEgDQogIHN0eWxlPSJDT0xPUjogcmdiKDEs +OTUsMTgyKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgaHJlZj0iaHR0cDovL25ld3MuY3Nk +bi5uZXQvYS8yMDEwMTIxNS8yODM2ODIuaHRtbCIgDQogIHRhcmdldD1fYmxhbms+6ZuF6JmO6ZuH +5ZGY56ew5bey6KKr6Kej6ZuHPC9BPjwvU1BBTj48L0RUPg0KICA8RFQgY2xhc3M9dHh0X2JsYWNr +IA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAwcHgg +OHB4OyBQQURESU5HLUxFRlQ6IDEwcHg7IEZPTlQtU0laRTogMTRweDsgQkFDS0dST1VORC1JTUFH +RTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzI2LmdpZik7 +IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogM3B4IDBweDsgQ09MT1I6IHJnYigwLDAsMCk7 +IFBBRERJTkctVE9QOiAwcHg7IFBPU0lUSU9OOiByZWxhdGl2ZTsgYmFja2dyb3VuZC1vcmlnaW46 +IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHN0eWxlPSJDT0xPUjog +cmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0Nv +dW50KHRoaXMsNzIpOyANCiAgaHJlZj0iaHR0cDovL25ld3MuY3Nkbi5uZXQvYS8yMDEwMTIxNS8y +ODM2NzcuaHRtbCIgDQogIHRhcmdldD1fYmxhbms+6LC35q2M6aaW5bit5bel56iL5biI77ya5Z2a +5oyB566X5rOV5Y6f5YiZIOS4jeaOuuS4u+inguiJsuW9qTwvQT48U1BBTiBjbGFzcz10eHRfYmx1 +ZSANCiAgc3R5bGU9IkZPTlQtU0laRTogMTJweDsgTUFSR0lOOiAwcHggMHB4IDBweCA4cHg7IENP +TE9SOiByZ2IoMSw5NSwxODIpIj48QSANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMSw5NSwxODIpOyBU +RVhULURFQ09SQVRJT046IG5vbmUiIA0KICBocmVmPSJodHRwOi8vbmV3cy5jc2RuLm5ldC8iIHRh +cmdldD1fYmxhbms+5LiN5YGP6KKS5Lu75L2V5ZOB54mMPC9BPjwvU1BBTj48L0RUPg0KICA8RFQg +Y2xhc3M9dHh0X2JsYWNrIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5E +LVBPU0lUSU9OOiAwcHggOHB4OyBQQURESU5HLUxFRlQ6IDEwcHg7IEZPTlQtU0laRTogMTRweDsg +QkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3Nkbmlu +ZGV4X3BpYzI2LmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogM3B4IDBweDsgQ09M +T1I6IHJnYigwLDAsMCk7IFBBRERJTkctVE9QOiAwcHg7IFBPU0lUSU9OOiByZWxhdGl2ZTsgYmFj +a2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQog +IHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25j +bGljaz1Mb2dDbGlja0NvdW50KHRoaXMsNzIpOyANCiAgaHJlZj0iaHR0cDovL25ld3MuY3Nkbi5u +ZXQvYS8yMDEwMTIxNS8yODM2NjcuaHRtbCIgDQogIHRhcmdldD1fYmxhbms+54m556uL54us6KGM +55qE56iL5bqP5ZGY77ya57u05Z+66Kej5a+G5Yib5aeL5Lq66Zi/5qGR5aWH5Lyg5aWHPC9BPjxT +UEFOIGNsYXNzPXR4dF9ibHVlIA0KICBzdHlsZT0iRk9OVC1TSVpFOiAxMnB4OyBNQVJHSU46IDBw +eCAwcHggMHB4IDhweDsgQ09MT1I6IHJnYigxLDk1LDE4MikiPjxBIA0KICBzdHlsZT0iQ09MT1I6 +IHJnYigxLDk1LDE4Mik7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIGhyZWY9Imh0dHA6Ly9u +ZXdzLmNzZG4ubmV0L2EvMjAxMDEyMTUvMjgzNjY3Lmh0bWwiIA0KICB0YXJnZXQ9X2JsYW5rPue7 +j+WOhuWdjuWdt+aAneaDs+a3seWIuzwvQT48L1NQQU4+PC9EVD4NCiAgPEREIGNsYXNzPW5ld3Nf +dHlwZWEgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IFBBRERJTkctTEVGVDogMHB4OyBC +QUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5k +ZXhfcGljNDYuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAtM3B4IDBweCAxMHB4 +OyBQQURESU5HLVRPUDogMHB4OyBQT1NJVElPTjogcmVsYXRpdmU7IEhFSUdIVDogMTlweDsgYmFj +a2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEVNIA0K +ICBzdHlsZT0iTEVGVDogMzgycHg7IENPTE9SOiByZ2IoMjU1LDI1NSwyNTUpOyBGT05ULVNUWUxF +OiBub3JtYWw7IFBPU0lUSU9OOiBhYnNvbHV0ZTsgVE9QOiAycHgiPuS4mueVjOS4juS6uueJqTwv +RU0+PC9ERD4NCiAgPERUIGNsYXNzPXR4dF9ibGFjayANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6 +IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMHB4IDhweDsgUEFERElORy1MRUZUOiAxMHB4OyBG +T05ULVNJWkU6IDE0cHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93 +d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMyNi5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJH +SU46IDNweCAwcHg7IENPTE9SOiByZ2IoMCwwLDApOyBQQURESU5HLVRPUDogMHB4OyBQT1NJVElP +TjogcmVsYXRpdmU7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6 +IGluaXRpYWwiPjxBIA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElP +Tjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDczKTsgDQogIGhyZWY9Imh0 +dHA6Ly9uZXdzLmNzZG4ubmV0L2EvMjAxMDEyMTUvMjgzNjkzLmh0bWwiIA0KICB0YXJnZXQ9X2Js +YW5rPkZhY2Vib29r5o6oRm1haWzmjJHmiJhFbWFpbCA2MiXlj5forr/ogIXkuI3ogIPomZE8L0E+ +PFNQQU4gY2xhc3M9dHh0X2JsdWUgDQogIHN0eWxlPSJGT05ULVNJWkU6IDEycHg7IE1BUkdJTjog +MHB4IDBweCAwcHggOHB4OyBDT0xPUjogcmdiKDEsOTUsMTgyKSI+PEEgDQogIHN0eWxlPSJDT0xP +UjogcmdiKDEsOTUsMTgyKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgaHJlZj0iaHR0cDov +L25ld3MuY3Nkbi5uZXQvIiB0YXJnZXQ9X2JsYW5rPuekvuS6pOe9kee7nOWPmOi6q+mAmuiur+W5 +s+WPsDwvQT48L1NQQU4+PC9EVD4NCiAgPERUIGNsYXNzPXR4dF9ibGFjayANCiAgc3R5bGU9IlBB +RERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMHB4IDhweDsgUEFERElORy1M +RUZUOiAxMHB4OyBGT05ULVNJWkU6IDE0cHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8v +Y3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMyNi5naWYpOyBQQURESU5HLUJPVFRP +TTogMHB4OyBNQVJHSU46IDNweCAwcHg7IENPTE9SOiByZ2IoMCwwLDApOyBQQURESU5HLVRPUDog +MHB4OyBQT1NJVElPTjogcmVsYXRpdmU7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNr +Z3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRF +WFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDczKTsg +DQogIGhyZWY9Imh0dHA6Ly9tb2JpbGUuY3Nkbi5uZXQvbi8yMDEwMTIxNS8yODM2NzYuaHRtbCIg +DQogIHRhcmdldD1fYmxhbms+5b6u6L2v5a6Y5pa55a6j56ew5bCG5LqOMjAxMeW5tOS4i+WNiuW5 +tOWcqOS4reWbveaOqOWHuldpbmRvd3MgUGhvbmUgNzwvQT48U1BBTiBjbGFzcz10eHRfYmx1ZSAN +CiAgc3R5bGU9IkZPTlQtU0laRTogMTJweDsgTUFSR0lOOiAwcHggMHB4IDBweCA4cHg7IENPTE9S +OiByZ2IoMSw5NSwxODIpIj48QSANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMSw5NSwxODIpOyBURVhU +LURFQ09SQVRJT046IG5vbmUiIA0KICBocmVmPSJodHRwOi8vd3d3LmNzZG4ubmV0LyIgdGFyZ2V0 +PV9ibGFuaz48L0E+PC9TUEFOPjwvRFQ+DQogIDxEVCBjbGFzcz10eHRfYmxhY2sgDQogIHN0eWxl +PSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDBweCA4cHg7IFBBRERJ +TkctTEVGVDogMTBweDsgRk9OVC1TSVpFOiAxNHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0 +cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMjYuZ2lmKTsgUEFERElORy1C +T1RUT006IDBweDsgTUFSR0lOOiAzcHggMHB4OyBDT0xPUjogcmdiKDAsMCwwKTsgUEFERElORy1U +T1A6IDBweDsgUE9TSVRJT046IHJlbGF0aXZlOyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsg +YmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDAp +OyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw3 +Myk7IA0KICBocmVmPSJodHRwOi8vbW9iaWxlLmNzZG4ubmV0L24vMjAxMDEyMTUvMjgzNjczLmh0 +bWwiIA0KICB0YXJnZXQ9X2JsYW5rPuivuuWfuuS6muaYjuW5tOaLn+WvueWhnuePreezu+e7n+i/ +m+ihjDTliLA15qyh5Y2H57qnPC9BPjxTUEFOIGNsYXNzPXR4dF9ibHVlIA0KICBzdHlsZT0iRk9O +VC1TSVpFOiAxMnB4OyBNQVJHSU46IDBweCAwcHggMHB4IDhweDsgQ09MT1I6IHJnYigxLDk1LDE4 +MikiPjxBIA0KICBzdHlsZT0iQ09MT1I6IHJnYigxLDk1LDE4Mik7IFRFWFQtREVDT1JBVElPTjog +bm9uZSIgDQogIGhyZWY9Imh0dHA6Ly9tb2JpbGUuY3Nkbi5uZXQvIiB0YXJnZXQ9X2JsYW5rPuWi +nuWKoOS4u+mhtemFjee9rueBtea0u+aApzwvQT48L1NQQU4+PC9EVD4NCiAgPERUIGNsYXNzPXR4 +dF9ibGFjayANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElP +TjogMHB4IDhweDsgUEFERElORy1MRUZUOiAxMHB4OyBGT05ULVNJWkU6IDE0cHg7IEJBQ0tHUk9V +TkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMy +Ni5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDNweCAwcHg7IENPTE9SOiByZ2Io +MCwwLDApOyBQQURESU5HLVRPUDogMHB4OyBQT1NJVElPTjogcmVsYXRpdmU7IGJhY2tncm91bmQt +b3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICBzdHlsZT0i +Q09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9n +Q2xpY2tDb3VudCh0aGlzLDczKTsgDQogIGhyZWY9Imh0dHA6Ly9uZXdzLmNzZG4ubmV0L2EvMjAx +MDEyMTEvMjgzNDYwLmh0bWwiIA0KICB0YXJnZXQ9X2JsYW5rPltTRDIuMF3liJvmlrDlt6XlnLro +lKHlrabplZvvvJrpoobln5/or63oqIDnmoTorr7orqHkuI7lrp7ot7U8L0E+PFNQQU4gY2xhc3M9 +dHh0X2JsdWUgDQogIHN0eWxlPSJGT05ULVNJWkU6IDEycHg7IE1BUkdJTjogMHB4IDBweCAwcHgg +OHB4OyBDT0xPUjogcmdiKDEsOTUsMTgyKSI+PEEgDQogIHN0eWxlPSJDT0xPUjogcmdiKDEsOTUs +MTgyKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgaHJlZj0iaHR0cDovL25ld3MuY3Nkbi5u +ZXQvYS8yMDEwMTIxMS8yODM0NTkuaHRtbCIgDQogIHRhcmdldD1fYmxhbms+5byC5q2l57yW56iL +5qih5Z6L55qE5ryU5Y+YPC9BPjwvU1BBTj48L0RUPg0KICA8RFQgY2xhc3M9dHh0X2JsYWNrIA0K +ICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAwcHggOHB4 +OyBQQURESU5HLUxFRlQ6IDEwcHg7IEZPTlQtU0laRTogMTRweDsgQkFDS0dST1VORC1JTUFHRTog +dXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzI2LmdpZik7IFBB +RERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogM3B4IDBweDsgQ09MT1I6IHJnYigwLDAsMCk7IFBB +RERJTkctVE9QOiAwcHg7IFBPU0lUSU9OOiByZWxhdGl2ZTsgYmFja2dyb3VuZC1vcmlnaW46IGlu +aXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHN0eWxlPSJDT0xPUjogcmdi +KDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50 +KHRoaXMsNzMpOyANCiAgaHJlZj0iaHR0cDovL25ld3MuY3Nkbi5uZXQvYS8yMDEwMTIxNS8yODM2 +NzIuaHRtbCIgdGFyZ2V0PV9ibGFuaz5DaHJvbWUgDQogIE9T5a+56LC35q2M5pyq5p2l5aKe6ZW/ +6Iez5YWz6YeN6KaB55qEMTDkuKrnkIbnlLE8L0E+PFNQQU4gY2xhc3M9dHh0X2JsdWUgDQogIHN0 +eWxlPSJGT05ULVNJWkU6IDEycHg7IE1BUkdJTjogMHB4IDBweCAwcHggOHB4OyBDT0xPUjogcmdi +KDEsOTUsMTgyKSI+PEEgDQogIHN0eWxlPSJDT0xPUjogcmdiKDEsOTUsMTgyKTsgVEVYVC1ERUNP +UkFUSU9OOiBub25lIiANCiAgaHJlZj0iaHR0cDovL25ld3MuY3Nkbi5uZXQvIiB0YXJnZXQ9X2Js +YW5rPuWfuuS6jldlYuaTjeS9nOezu+e7n+aYr+acquadpTwvQT48L1NQQU4+PC9EVD4NCiAgPERU +IGNsYXNzPXR4dF9ibGFjayANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VO +RC1QT1NJVElPTjogMHB4IDhweDsgUEFERElORy1MRUZUOiAxMHB4OyBGT05ULVNJWkU6IDE0cHg7 +IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5p +bmRleF9waWMyNi5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDNweCAwcHg7IENP +TE9SOiByZ2IoMCwwLDApOyBQQURESU5HLVRPUDogMHB4OyBQT1NJVElPTjogcmVsYXRpdmU7IGJh +Y2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0K +ICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9u +Y2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDczKTsgDQogIGhyZWY9Imh0dHA6Ly9tb2JpbGUuY3Nk +bi5uZXQvbi8yMDEwMTIxNS8yODM2NjMuaHRtbCIgDQogIHRhcmdldD1fYmxhbms+W+aOqOiNkOmY +heivu13miZPpgKDnp7vliqjlvIDlj5Hlm6LpmJ/nmoTkupTkuKrluLjop4Hor6/ljLo8L0E+PFNQ +QU4gY2xhc3M9dHh0X2JsdWUgDQogIHN0eWxlPSJGT05ULVNJWkU6IDEycHg7IE1BUkdJTjogMHB4 +IDBweCAwcHggOHB4OyBDT0xPUjogcmdiKDEsOTUsMTgyKSI+PEEgDQogIHN0eWxlPSJDT0xPUjog +cmdiKDEsOTUsMTgyKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgaHJlZj0iaHR0cDovL21v +YmlsZS5jc2RuLm5ldC9uLzIwMTAxMjE1LzI4MzY2My5odG1sIiANCiAgdGFyZ2V0PV9ibGFuaz7m +naXoh6pHb29nbGXnp7vliqjlm6LpmJ/nmoTnu4/pqow8L0E+PC9TUEFOPjwvRFQ+DQogIDxERCBj +bGFzcz1uZXdzX3R5cGVhIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBQQURESU5HLUxF +RlQ6IDBweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFn +ZXMvY3NkbmluZGV4X3BpYzQ2LmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogLTNw +eCAwcHggMTBweDsgUEFERElORy1UT1A6IDBweDsgUE9TSVRJT046IHJlbGF0aXZlOyBIRUlHSFQ6 +IDE5cHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRp +YWwiPjxFTSANCiAgc3R5bGU9IkxFRlQ6IDM4MnB4OyBDT0xPUjogcmdiKDI1NSwyNTUsMjU1KTsg +Rk9OVC1TVFlMRTogbm9ybWFsOyBQT1NJVElPTjogYWJzb2x1dGU7IFRPUDogMnB4Ij7mioDmnK/k +uI7kuqflk4E8L0VNPjwvREQ+DQogIDxEVCBjbGFzcz10eHRfYmxhY2sgDQogIHN0eWxlPSJQQURE +SU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDBweCA4cHg7IFBBRERJTkctTEVG +VDogMTBweDsgRk9OVC1TSVpFOiAxNHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2Nz +ZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMjYuZ2lmKTsgUEFERElORy1CT1RUT006 +IDBweDsgTUFSR0lOOiAzcHggMHB4OyBDT0xPUjogcmdiKDAsMCwwKTsgUEFERElORy1UT1A6IDBw +eDsgUE9TSVRJT046IHJlbGF0aXZlOyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dy +b3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhU +LURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw3NCk7IA0K +ICBocmVmPSJodHRwOi8vdmlwbmV3cy5jc2RuLm5ldC9BY3Rpdml0aWVzLmFzcHg/cG9pbnRpZD0y +MDEwXzExXzIzXzEzMDQzMjgyOCIgDQogIHRhcmdldD1fYmxhbms+5Lit5Zu955S15L+h5aSp57+8 +56m66Ze05ZCI5L2c5LyZ5Ly05Lqk5rWB6K665Z2b77yI5Y6m6Zeo56uZ77yJ5Y+s5byAPC9BPjxT +UEFOIGNsYXNzPXR4dF9ibHVlIA0KICBzdHlsZT0iRk9OVC1TSVpFOiAxMnB4OyBNQVJHSU46IDBw +eCAwcHggMHB4IDhweDsgQ09MT1I6IHJnYigxLDk1LDE4MikiPjxBIA0KICBzdHlsZT0iQ09MT1I6 +IHJnYigxLDk1LDE4Mik7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIGhyZWY9Imh0dHA6Ly92 +aXBuZXdzLmNzZG4ubmV0L0FjdGl2aXRpZXMuYXNweD9wb2ludGlkPTIwMTBfMTFfMjNfMTMwNDMy +ODI4IiANCiAgdGFyZ2V0PV9ibGFuaz7lvZPliqjmvKvpgYfkuIrnlLXkv6E8L0E+PC9TUEFOPjwv +RFQ+DQogIDxEVCBjbGFzcz10eHRfYmxhY2sgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7 +IEJBQ0tHUk9VTkQtUE9TSVRJT046IDBweCA4cHg7IFBBRERJTkctTEVGVDogMTBweDsgRk9OVC1T +SVpFOiAxNHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2lt +YWdlcy9jc2RuaW5kZXhfcGljMjYuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAz +cHggMHB4OyBDT0xPUjogcmdiKDAsMCwwKTsgUEFERElORy1UT1A6IDBweDsgUE9TSVRJT046IHJl +bGF0aXZlOyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0 +aWFsIj48QSANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5v +bmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw3NCk7IA0KICBocmVmPSJodHRwOi8v +bmV3cy5jc2RuLm5ldC9hLzIwMTAxMjE1LzI4Mzk2Ni5odG1sIiANCiAgdGFyZ2V0PV9ibGFuaz7m +lrDmtarlvq7ljZrlvIDlj5HogIXliJvmlrDln7rph5HlvIDlp4vmjqXlj5fnlLPor7c8L0E+PFNQ +QU4gY2xhc3M9dHh0X2JsdWUgDQogIHN0eWxlPSJGT05ULVNJWkU6IDEycHg7IE1BUkdJTjogMHB4 +IDBweCAwcHggOHB4OyBDT0xPUjogcmdiKDEsOTUsMTgyKSI+PEEgDQogIHN0eWxlPSJDT0xPUjog +cmdiKDEsOTUsMTgyKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgaHJlZj0iaHR0cDovL25l +d3MuY3Nkbi5uZXQvIiB0YXJnZXQ9X2JsYW5rPuWNleeslOaKlei1hDMwMOS4h1JNQuS7peS4izwv +QT48L1NQQU4+PC9EVD4NCiAgPERUIGNsYXNzPXR4dF9ibGFjayANCiAgc3R5bGU9IlBBRERJTkct +UklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMHB4IDhweDsgUEFERElORy1MRUZUOiAx +MHB4OyBGT05ULVNJWkU6IDE0cHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3Nkbmlt +Zy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMyNi5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4 +OyBNQVJHSU46IDNweCAwcHg7IENPTE9SOiByZ2IoMCwwLDApOyBQQURESU5HLVRPUDogMHB4OyBQ +T1NJVElPTjogcmVsYXRpdmU7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5k +LWNsaXA6IGluaXRpYWwiPjxBIA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVD +T1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDc0KTsgDQogIGhy +ZWY9Imh0dHA6Ly9jbG91ZC5jc2RuLm5ldC9hLzIwMTAxMjE1LzI4MzY3OC5odG1sIiANCiAgdGFy +Z2V0PV9ibGFuaz7nu7Tln7rop6Plr4bkuLvnq5nngrlXaWtpTGVha3Mub3Jn5Zyo576O5Zu95oGi +5aSN6K6/6ZeuPC9BPjxTUEFOIGNsYXNzPXR4dF9ibHVlIA0KICBzdHlsZT0iRk9OVC1TSVpFOiAx +MnB4OyBNQVJHSU46IDBweCAwcHggMHB4IDhweDsgQ09MT1I6IHJnYigxLDk1LDE4MikiPjxBIA0K +ICBzdHlsZT0iQ09MT1I6IHJnYigxLDk1LDE4Mik7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQog +IGhyZWY9Imh0dHA6Ly9jbG91ZC5jc2RuLm5ldC8iIHRhcmdldD1fYmxhbms+5YWo55CD5bu656uL +6LaFMTAwMOmVnOWDjzwvQT48L1NQQU4+PC9EVD4NCiAgPERUIGNsYXNzPXR4dF9ibGFjayANCiAg +c3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMHB4IDhweDsg +UEFERElORy1MRUZUOiAxMHB4OyBGT05ULVNJWkU6IDE0cHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVy +bChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMyNi5naWYpOyBQQURE +SU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDNweCAwcHg7IENPTE9SOiByZ2IoMCwwLDApOyBQQURE +SU5HLVRPUDogMHB4OyBQT1NJVElPTjogcmVsYXRpdmU7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0 +aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICBzdHlsZT0iQ09MT1I6IHJnYigw +LDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0 +aGlzLDc0KTsgDQogIGhyZWY9Imh0dHA6Ly9jbG91ZC5jc2RuLm5ldC9hLzIwMTAxMjE1LzI4MzY2 +OS5odG1sIiANCiAgdGFyZ2V0PV9ibGFuaz7osLfmrYzkuLpBcGFjaGXmiYDmnInlvIDmupDpobnn +m67mj5DkvpvmlrDnmoTlsZXnpLrpobXpnaI8L0E+PFNQQU4gY2xhc3M9dHh0X2JsdWUgDQogIHN0 +eWxlPSJGT05ULVNJWkU6IDEycHg7IE1BUkdJTjogMHB4IDBweCAwcHggOHB4OyBDT0xPUjogcmdi +KDEsOTUsMTgyKSI+PEEgDQogIHN0eWxlPSJDT0xPUjogcmdiKDEsOTUsMTgyKTsgVEVYVC1ERUNP +UkFUSU9OOiBub25lIiANCiAgaHJlZj0iaHR0cDovL2Nsb3VkLmNzZG4ubmV0LyIgdGFyZ2V0PV9i +bGFuaz7kuI3lho3nlLFBcGFjaGXnu4Tnu4fnm7TmjqXnrqHnkIY8L0E+PC9TUEFOPjwvRFQ+DQog +IDxEVCBjbGFzcz10eHRfYmxhY2sgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tH +Uk9VTkQtUE9TSVRJT046IDBweCA4cHg7IFBBRERJTkctTEVGVDogMTBweDsgRk9OVC1TSVpFOiAx +NHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9j +c2RuaW5kZXhfcGljMjYuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAzcHggMHB4 +OyBDT0xPUjogcmdiKDAsMCwwKTsgUEFERElORy1UT1A6IDBweDsgUE9TSVRJT046IHJlbGF0aXZl +OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48 +QSANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0K +ICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw3NCk7IA0KICBocmVmPSJodHRwOi8vbmV3cy5j +c2RuLm5ldC9hLzIwMTAxMjEzLzI4MzU0NS5odG1sIiB0YXJnZXQ9X2JsYW5rPuWNg+WQjeeuoeeQ +huiAhVNEMkMgDQogIDIwMTDnurXorrrmioDmnK/lpKflir8g5Lit5Zu95byA5Y+R6ICF6L+O5p2l +6buE6YeR5Y2B5bm0PC9BPjxTUEFOIGNsYXNzPXR4dF9ibHVlIA0KICBzdHlsZT0iRk9OVC1TSVpF +OiAxMnB4OyBNQVJHSU46IDBweCAwcHggMHB4IDhweDsgQ09MT1I6IHJnYigxLDk1LDE4MikiPjxB +IA0KICBzdHlsZT0iQ09MT1I6IHJnYigxLDk1LDE4Mik7IFRFWFQtREVDT1JBVElPTjogbm9uZSIg +DQogIGhyZWY9Imh0dHA6Ly93d3cuY3Nkbi5uZXQvIiB0YXJnZXQ9X2JsYW5rPjwvQT48L1NQQU4+ +PC9EVD4NCiAgPERUIGNsYXNzPXR4dF9ibGFjayANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBw +eDsgQkFDS0dST1VORC1QT1NJVElPTjogMHB4IDhweDsgUEFERElORy1MRUZUOiAxMHB4OyBGT05U +LVNJWkU6IDE0cHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cv +aW1hZ2VzL2NzZG5pbmRleF9waWMyNi5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46 +IDNweCAwcHg7IENPTE9SOiByZ2IoMCwwLDApOyBQQURESU5HLVRPUDogMHB4OyBQT1NJVElPTjog +cmVsYXRpdmU7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGlu +aXRpYWwiPjxBIA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjog +bm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDc0KTsgDQogIGhyZWY9Imh0dHA6 +Ly9jbG91ZC5jc2RuLm5ldC9hLzIwMTAxMjE1LzI4MzY2OC5odG1sIiANCiAgdGFyZ2V0PV9ibGFu +az5JQk3kuLrlvrflm73lvIDlj5Hmr4/np5Lov5DnrpczMDAw5LiH5Lq/5qyh6LaF57qn6K6h566X +5py6PC9BPjxTUEFOIGNsYXNzPXR4dF9ibHVlIA0KICBzdHlsZT0iRk9OVC1TSVpFOiAxMnB4OyBN +QVJHSU46IDBweCAwcHggMHB4IDhweDsgQ09MT1I6IHJnYigxLDk1LDE4MikiPjxBIA0KICBzdHls +ZT0iQ09MT1I6IHJnYigxLDk1LDE4Mik7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIGhyZWY9 +Imh0dHA6Ly9jbG91ZC5jc2RuLm5ldC8iIHRhcmdldD1fYmxhbms+6LaF6LaK5Lit5Zu95aSp5rKz +MeWPtzwvQT48L1NQQU4+PC9EVD4NCiAgPEREIGNsYXNzPW5ld3NfdHlwZWEgDQogIHN0eWxlPSJQ +QURESU5HLVJJR0hUOiAwcHg7IFBBRERJTkctTEVGVDogMHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1 +cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljNDYuZ2lmKTsgUEFE +RElORy1CT1RUT006IDBweDsgTUFSR0lOOiAtM3B4IDBweCAxMHB4OyBQQURESU5HLVRPUDogMHB4 +OyBQT1NJVElPTjogcmVsYXRpdmU7IEhFSUdIVDogMTlweDsgYmFja2dyb3VuZC1vcmlnaW46IGlu +aXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PERGTiANCiAgc3R5bGU9IkxFRlQ6IDM4 +OXB4OyBDT0xPUjogcmdiKDI1NSwyNTUsMjU1KTsgRk9OVC1TVFlMRTogbm9ybWFsOyBQT1NJVElP +TjogYWJzb2x1dGU7IFRPUDogMnB4Ij7otYTorq/liqjmgIE8L0RGTj48L0REPjwvREw+PC9ESVY+ +DQo8RElWIGNsYXNzPWJ1c2luZXNzdHh0YWQgDQpzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBE +SVNQTEFZOiBpbmxpbmU7IFBBRERJTkctTEVGVDogMHB4OyBGTE9BVDogbGVmdDsgUEFERElORy1C +T1RUT006IDVweDsgTUFSR0lOOiAtNnB4IDEwcHggM3B4OyBXSURUSDogNDUwcHg7IFBBRERJTkct +VE9QOiA1cHgiPg0KPFVMIGNsYXNzPXR4dF9kZXBncmF5IA0Kc3R5bGU9IlBBRERJTkctUklHSFQ6 +IDBweDsgUEFERElORy1MRUZUOiAwcHg7IEZMT0FUOiBsZWZ0OyBQQURESU5HLUJPVFRPTTogMHB4 +OyBNQVJHSU46IDBweDsgV0lEVEg6IDQ1MHB4OyBDT0xPUjogcmdiKDUxLDUxLDUxKTsgUEFERElO +Ry1UT1A6IDBweDsgTElTVC1TVFlMRS1UWVBFOiBub25lIj4NCiAgPExJIA0KICBzdHlsZT0iUEFE +RElORy1SSUdIVDogMHB4OyBESVNQTEFZOiBpbmxpbmU7IFBBRERJTkctTEVGVDogMHB4OyBGTE9B +VDogbGVmdDsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHggNXB4OyBXSURUSDogMjE1 +cHg7IFBBRERJTkctVE9QOiAwcHgiPjxBIA0KICBzdHlsZT0iQ09MT1I6IHJnYig1MSw1MSw1MSk7 +IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIGhyZWY9Imh0dHA6Ly96LmNzZG4ubmV0L2dtY2xp +Y2sucGhwP2Jhbm5lcmlkPTU0MTAmYW1wO3pvbmVpZD00MjEmYW1wO3NvdXJjZT0mYW1wO2Rlc3Q9 +aHR0cCUzQSUyRiUyRmVkdS5jc2RuLm5ldCUyRmhlaW1hJTJGIiANCiAgdGFyZ2V0PV9ibGFuaz7l +sLHkuJoi5LiN5YGa5byA5Y+R5LiN6L+Y5qy+IueahOWfueiurTwvQT48L0xJPg0KICA8TEkgDQog +IHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IERJU1BMQVk6IGlubGluZTsgUEFERElORy1MRUZU +OiAwcHg7IEZMT0FUOiBsZWZ0OyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweCA1cHg7 +IFdJRFRIOiAyMTVweDsgUEFERElORy1UT1A6IDBweCI+PEEgDQogIHN0eWxlPSJDT0xPUjogcmdi +KDUxLDUxLDUxKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgaHJlZj0iaHR0cDovL3ouY3Nk +bi5uZXQvZ21jbGljay5waHA/YmFubmVyaWQ9NTQwNCZhbXA7em9uZWlkPTQyMyZhbXA7c291cmNl +PSZhbXA7ZGVzdD1odHRwJTNBJTJGJTJGbXNkbi5taWNyb3NvZnQuY29tJTJGemgtY24lMkZ3aW5k +b3dzcGhvbmUlMkZkZWZhdWx0LmFzcHglM0ZvY2lkJTNEYmFuLW4tY24td3A3LS1jc2RuKyIgDQog +IHRhcmdldD1fYmxhbms+44CQ5Luj56CB44CRV2luZG93cyBQaG9uZSA36IyD5L6L56iL5bqPPC9B +PjwvTEk+DQogIDxMSSANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgRElTUExBWTogaW5s +aW5lOyBQQURESU5HLUxFRlQ6IDBweDsgRkxPQVQ6IGxlZnQ7IFBBRERJTkctQk9UVE9NOiAwcHg7 +IE1BUkdJTjogMHB4IDVweDsgV0lEVEg6IDIxNXB4OyBQQURESU5HLVRPUDogMHB4Ij48QSANCiAg +c3R5bGU9IkNPTE9SOiByZ2IoNTEsNTEsNTEpOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBo +cmVmPSJodHRwOi8vei5jc2RuLm5ldC9nbWNsaWNrLnBocD9iYW5uZXJpZD01NDAxJmFtcDt6b25l +aWQ9NDIyJmFtcDtzb3VyY2U9JmFtcDtkZXN0PWh0dHAlM0ElMkYlMkYxODl3b3Jrcy5jc2RuLm5l +dCUyRisiIA0KICB0YXJnZXQ9X2JsYW5rPuWkqee/vOaVmeS9oOenu+WKqOW6lOeUqOiQpeWIqeS5 +i+mBkzwvQT48L0xJPg0KICA8TEkgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IERJU1BM +QVk6IGlubGluZTsgUEFERElORy1MRUZUOiAwcHg7IEZMT0FUOiBsZWZ0OyBQQURESU5HLUJPVFRP +TTogMHB4OyBNQVJHSU46IDBweCA1cHg7IFdJRFRIOiAyMTVweDsgUEFERElORy1UT1A6IDBweCI+ +PEEgDQogIHN0eWxlPSJDT0xPUjogcmdiKDUxLDUxLDUxKTsgVEVYVC1ERUNPUkFUSU9OOiBub25l +IiANCiAgaHJlZj0iaHR0cDovL3ouY3Nkbi5uZXQvZ21jbGljay5waHA/YmFubmVyaWQ9NTM2MCZh +bXA7em9uZWlkPTQyNCZhbXA7c291cmNlPSZhbXA7ZGVzdD1odHRwJTNBJTJGJTJGYzkuY3Nkbi5o +dWRvbmcuY29tJTJGIiANCiAgdGFyZ2V0PV9ibGFuaz7orr/osIgg5b6u6L2v6ZKf5Y2r6LCISUU5 +5Y+Y6Z2pPC9BPjwvTEk+PC9VTD48L0RJVj4NCjxINiANCnN0eWxlPSJDTEVBUjogYm90aDsgUEFE +RElORy1SSUdIVDogMHB4OyBCT1JERVItVE9QOiByZ2IoMjA0LDIwNCwyMDQpIDFweCBzb2xpZDsg +UEFERElORy1MRUZUOiAxMHB4OyBGT05ULVNJWkU6IDE0cHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVy +bChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMxMS5naWYpOyBQQURE +SU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweDsgUEFERElORy1UT1A6IDVweDsgUE9TSVRJT046 +IHJlbGF0aXZlOyBIRUlHSFQ6IDI5cHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNr +Z3JvdW5kLWNsaXA6IGluaXRpYWwiPuS4k+mimDxTUEFOIA0KY2xhc3M9dHh0X2JsYWNrIA0Kc3R5 +bGU9IkZPTlQtV0VJR0hUOiBub3JtYWw7IEZPTlQtU0laRTogMTJweDsgTUFSR0lOOiAwcHggMHB4 +IDBweCAxNXB4OyBDT0xPUjogcmdiKDAsMCwwKSI+PC9TUEFOPjxDSVRFIA0KY2xhc3M9dHh0X2Js +dWUgDQpzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAwcHgg +NnB4OyBQQURESU5HLUxFRlQ6IDEwcHg7IEZPTlQtV0VJR0hUOiBub3JtYWw7IEZPTlQtU0laRTog +MTJweDsgTEVGVDogNDIwcHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5j +bi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMxMi5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBD +T0xPUjogcmdiKDEsOTUsMTgyKTsgUEFERElORy1UT1A6IDBweDsgRk9OVC1TVFlMRTogbm9ybWFs +OyBQT1NJVElPTjogYWJzb2x1dGU7IFRPUDogNXB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlh +bDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCnN0eWxlPSJDT0xPUjogcmdiKDEsOTUs +MTgyKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCmhyZWY9Imh0dHA6Ly9jc2RuaG9tZXBhZ2Uu +Y3Nkbi5uZXQvY19uZXdzc3ViamVjdC9tb3JlIiANCnRhcmdldD1fYmxhbms+5pu05aSaPC9BPjwv +Q0lURT48L0g2Pg0KPERJViBjbGFzcz1wYWdlY29uX2xheWVyMl9sZWZ0Y29uIA0Kc3R5bGU9IlBB +RERJTkctUklHSFQ6IDEwcHg7IFBBRERJTkctTEVGVDogMTBweDsgRkxPQVQ6IGxlZnQ7IFBBRERJ +TkctQk9UVE9NOiA1cHg7IFdJRFRIOiA0NTBweDsgUEFERElORy1UT1A6IDVweCI+DQo8VUwgDQpz +dHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBPVkVSRkxPVy1ZOiBoaWRkZW47IFBBRERJTkctTEVG +VDogMHB4OyBGTE9BVDogbGVmdDsgT1ZFUkZMT1ctWDogaGlkZGVuOyBQQURESU5HLUJPVFRPTTog +MHB4OyBNQVJHSU46IDBweDsgV0lEVEg6IDQ1MHB4OyBQQURESU5HLVRPUDogNnB4OyBMSVNULVNU +WUxFLVRZUEU6IG5vbmUiPg0KICA8TEkgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IERJ +U1BMQVk6IGlubGluZTsgUEFERElORy1MRUZUOiAwcHg7IEZMT0FUOiBsZWZ0OyBQQURESU5HLUJP +VFRPTTogMHB4OyBNQVJHSU46IDBweCA4cHg7IFBBRERJTkctVE9QOiAwcHgiPjxBIA0KICBzdHls +ZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9 +TG9nQ2xpY2tDb3VudCh0aGlzLDc1KTsgaHJlZj0iaHR0cDovL2cuY3Nkbi5uZXQvNTE2NjY0MyIg +DQogIHRhcmdldD1fYmxhbms+PElNRyB0aXRsZT0iIiANCiAgc3R5bGU9IkJPUkRFUi1SSUdIVDog +cmdiKDIwNCwyMDQsMjA0KSAxcHggc29saWQ7IFBBRERJTkctUklHSFQ6IDBweDsgQk9SREVSLVRP +UDogcmdiKDIwNCwyMDQsMjA0KSAxcHggc29saWQ7IFBBRERJTkctTEVGVDogMHB4OyBQQURESU5H +LUJPVFRPTTogNnB4OyBCT1JERVItTEVGVDogcmdiKDIwNCwyMDQsMjA0KSAxcHggc29saWQ7IFBB +RERJTkctVE9QOiA2cHg7IEJPUkRFUi1CT1RUT006IHJnYigyMDQsMjA0LDIwNCkgMXB4IHNvbGlk +IiANCiAgaGVpZ2h0PTEzMiBhbHQ9IiIgc3JjPSJodHRwOi8vaW1hZ2VzLmNzZG4ubmV0LzIwMTAx +MjAzL+mmlumhteS4k+mimDAyLmpwZyIgDQogIHdpZHRoPTkzPjwvQT48U1BBTiBjbGFzcz10eHRf +Ymx1ZSANCiAgc3R5bGU9IkRJU1BMQVk6IGJsb2NrOyBNQVJHSU46IDVweCAwcHggMHB4OyBDT0xP +UjogcmdiKDEsOTUsMTgyKTsgVEVYVC1BTElHTjogY2VudGVyIj48QSANCiAgc3R5bGU9IkNPTE9S +OiByZ2IoMSw5NSwxODIpOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0Ns +aWNrQ291bnQodGhpcyw3NSk7IGhyZWY9Imh0dHA6Ly9nLmNzZG4ubmV0LzUxNjY2NDMiIA0KICB0 +YXJnZXQ9X2JsYW5rPlRlY2jigKJFZCAyMDEwPC9BPjwvU1BBTj48L0xJPg0KICA8TEkgDQogIHN0 +eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IERJU1BMQVk6IGlubGluZTsgUEFERElORy1MRUZUOiAw +cHg7IEZMT0FUOiBsZWZ0OyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweCA4cHg7IFBB +RERJTkctVE9QOiAwcHgiPjxBIA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVD +T1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDc1KTsgaHJlZj0i +aHR0cDovL2cuY3Nkbi5uZXQvNTE2NTQ5NiIgDQogIHRhcmdldD1fYmxhbms+PElNRyB0aXRsZT0i +IiANCiAgc3R5bGU9IkJPUkRFUi1SSUdIVDogcmdiKDIwNCwyMDQsMjA0KSAxcHggc29saWQ7IFBB +RERJTkctUklHSFQ6IDBweDsgQk9SREVSLVRPUDogcmdiKDIwNCwyMDQsMjA0KSAxcHggc29saWQ7 +IFBBRERJTkctTEVGVDogMHB4OyBQQURESU5HLUJPVFRPTTogNnB4OyBCT1JERVItTEVGVDogcmdi +KDIwNCwyMDQsMjA0KSAxcHggc29saWQ7IFBBRERJTkctVE9QOiA2cHg7IEJPUkRFUi1CT1RUT006 +IHJnYigyMDQsMjA0LDIwNCkgMXB4IHNvbGlkIiANCiAgaGVpZ2h0PTEzMiBhbHQ9IiIgc3JjPSJo +dHRwOi8vaW1hZ2VzLmNzZG4ubmV0LzIwMTAxMTMwLzIuanBnIiANCiAgd2lkdGg9OTM+PC9BPjxT +UEFOIGNsYXNzPXR4dF9ibHVlIA0KICBzdHlsZT0iRElTUExBWTogYmxvY2s7IE1BUkdJTjogNXB4 +IDBweCAwcHg7IENPTE9SOiByZ2IoMSw5NSwxODIpOyBURVhULUFMSUdOOiBjZW50ZXIiPjxBIA0K +ICBzdHlsZT0iQ09MT1I6IHJnYigxLDk1LDE4Mik7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQog +IG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDc1KTsgaHJlZj0iaHR0cDovL2cuY3Nkbi5uZXQv +NTE2NTQ5NiIgDQogIHRhcmdldD1fYmxhbms+SGFkb29w5oqA5pyv5LiT6aKYPC9BPjwvU1BBTj48 +L0xJPg0KICA8TEkgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IERJU1BMQVk6IGlubGlu +ZTsgUEFERElORy1MRUZUOiAwcHg7IEZMT0FUOiBsZWZ0OyBQQURESU5HLUJPVFRPTTogMHB4OyBN +QVJHSU46IDBweCA4cHg7IFBBRERJTkctVE9QOiAwcHgiPjxBIA0KICBzdHlsZT0iQ09MT1I6IHJn +YigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3Vu +dCh0aGlzLDc1KTsgaHJlZj0iaHR0cDovL3N1YmplY3QuY3Nkbi5uZXQvY2xpZW50LyIgDQogIHRh +cmdldD1fYmxhbms+PElNRyB0aXRsZT0iIiANCiAgc3R5bGU9IkJPUkRFUi1SSUdIVDogcmdiKDIw +NCwyMDQsMjA0KSAxcHggc29saWQ7IFBBRERJTkctUklHSFQ6IDBweDsgQk9SREVSLVRPUDogcmdi +KDIwNCwyMDQsMjA0KSAxcHggc29saWQ7IFBBRERJTkctTEVGVDogMHB4OyBQQURESU5HLUJPVFRP +TTogNnB4OyBCT1JERVItTEVGVDogcmdiKDIwNCwyMDQsMjA0KSAxcHggc29saWQ7IFBBRERJTkct +VE9QOiA2cHg7IEJPUkRFUi1CT1RUT006IHJnYigyMDQsMjA0LDIwNCkgMXB4IHNvbGlkIiANCiAg +aGVpZ2h0PTEzMiBhbHQ9IiIgc3JjPSJodHRwOi8vaW1hZ2VzLmNzZG4ubmV0LzIwMTAxMTIzLzNR +XzkwLTEzMC5qcGciIA0KICB3aWR0aD05Mz48L0E+PFNQQU4gY2xhc3M9dHh0X2JsdWUgDQogIHN0 +eWxlPSJESVNQTEFZOiBibG9jazsgTUFSR0lOOiA1cHggMHB4IDBweDsgQ09MT1I6IHJnYigxLDk1 +LDE4Mik7IFRFWFQtQUxJR046IGNlbnRlciI+PEEgDQogIHN0eWxlPSJDT0xPUjogcmdiKDEsOTUs +MTgyKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRo +aXMsNzUpOyBocmVmPSJodHRwOi8vc3ViamVjdC5jc2RuLm5ldC9jbGllbnQvIiANCiAgdGFyZ2V0 +PV9ibGFuaz7mjqLorqjova/ku7booYzkuLrop4TojIM8L0E+PC9TUEFOPjwvTEk+DQogIDxMSSAN +CiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgRElTUExBWTogaW5saW5lOyBQQURESU5HLUxF +RlQ6IDBweDsgRkxPQVQ6IGxlZnQ7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4IDhw +eDsgUEFERElORy1UT1A6IDBweCI+PEEgDQogIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVY +VC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsNzUpOyBo +cmVmPSJodHRwOi8vZy5jc2RuLm5ldC81MTYzMjY2IiANCiAgdGFyZ2V0PV9ibGFuaz48SU1HIHRp +dGxlPSIiIA0KICBzdHlsZT0iQk9SREVSLVJJR0hUOiByZ2IoMjA0LDIwNCwyMDQpIDFweCBzb2xp +ZDsgUEFERElORy1SSUdIVDogMHB4OyBCT1JERVItVE9QOiByZ2IoMjA0LDIwNCwyMDQpIDFweCBz +b2xpZDsgUEFERElORy1MRUZUOiAwcHg7IFBBRERJTkctQk9UVE9NOiA2cHg7IEJPUkRFUi1MRUZU +OiByZ2IoMjA0LDIwNCwyMDQpIDFweCBzb2xpZDsgUEFERElORy1UT1A6IDZweDsgQk9SREVSLUJP +VFRPTTogcmdiKDIwNCwyMDQsMjA0KSAxcHggc29saWQiIA0KICBoZWlnaHQ9MTMyIGFsdD0iIiBz +cmM9Imh0dHA6Ly9pbWFnZXMuY3Nkbi5uZXQvMjAxMDExMTAvQWRvYmVNYXgyMDEwLmpwZyIgDQog +IHdpZHRoPTkzPjwvQT48U1BBTiBjbGFzcz10eHRfYmx1ZSANCiAgc3R5bGU9IkRJU1BMQVk6IGJs +b2NrOyBNQVJHSU46IDVweCAwcHggMHB4OyBDT0xPUjogcmdiKDEsOTUsMTgyKTsgVEVYVC1BTElH +TjogY2VudGVyIj48QSANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMSw5NSwxODIpOyBURVhULURFQ09S +QVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw3NSk7IGhyZWY9Imh0 +dHA6Ly9nLmNzZG4ubmV0LzUxNjMyNjYiIA0KICB0YXJnZXQ9X2JsYW5rPkFkb2JlIE1BWCAyMDEw +PC9BPjwvU1BBTj48L0xJPjwvVUw+PC9ESVY+PC9ESVY+DQo8RElWIGNsYXNzPXBhZ2Vjb25fbGF5 +ZXIyX21pZCANCnN0eWxlPSJCT1JERVItVE9QOiByZ2IoMjA0LDIwNCwyMDQpIDFweCBzb2xpZDsg +RElTUExBWTogaW5saW5lOyBGTE9BVDogbGVmdDsgTUFSR0lOOiAwcHggMHB4IDBweCA1cHg7IFdJ +RFRIOiAyNTlweDsgVEVYVC1BTElHTjogbGVmdCI+DQo8SDQgDQpzdHlsZT0iUEFERElORy1SSUdI +VDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAxMDAlIDAlOyBESVNQTEFZOiBpbmxpbmU7IFBB +RERJTkctTEVGVDogMTBweDsgRk9OVC1TSVpFOiAxNHB4OyBGTE9BVDogbGVmdDsgQkFDS0dST1VO +RC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvcGljX3lqc3RpdGJnLmdp +Zik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBXSURUSDogMjQ5cHg7IENPTE9S +OiByZ2IoMjU1LDI1NSwyNTUpOyBMSU5FLUhFSUdIVDogMjlweDsgUEFERElORy1UT1A6IDBweDsg +UE9TSVRJT046IHJlbGF0aXZlOyBCQUNLR1JPVU5ELUNPTE9SOiByZ2IoNiw4OSwxNzgpOyBiYWNr +Z3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj5DU0RO56e7 +5Yqo5b6u5Y2aJm5ic3A7Jm5ic3A7Jm5ic3A7PEEgDQpjbGFzcz1mb250c2l6ZSANCnN0eWxlPSJG +T05ULVdFSUdIVDogbm9ybWFsOyBGT05ULVNJWkU6IDEycHg7IENPTE9SOiByZ2IoMjU1LDI1NSwy +NTUpOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KaHJlZj0iaHR0cDovL3Quc2luYS5jb20uY24v +Y3Nkbm1vYmlsZSI+5oiR6KaB5YWz5rOoICZndDsmZ3Q7PC9BPjwvSDQ+DQo8REwgY2xhc3M9eWpz +X2xpc3QgaWQ9ZGl2eWpzIA0Kc3R5bGU9IlBBRERJTkctUklHSFQ6IDEwcHg7IEJBQ0tHUk9VTkQt +UE9TSVRJT046IDAlIDAlOyBPVkVSRkxPVy1ZOiBoaWRkZW47IERJU1BMQVk6IGlubGluZTsgUEFE +RElORy1MRUZUOiAxMHB4OyBGTE9BVDogbGVmdDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6 +Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvcGljX3lqc2JnLmdpZik7IE9WRVJGTE9XLVg6IGhpZGRl +bjsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IFdJRFRIOiAyMzhweDsgUEFERElO +Ry1UT1A6IDEwcHg7IEhFSUdIVDogMzkwcHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBi +YWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPg0KICA8RFQgY2xhc3M9dHh0X2JsdWUgDQogIHN0eWxl +PSJQQURESU5HLVJJR0hUOiAwcHg7IFBBRERJTkctTEVGVDogMHB4OyBGT05ULVdFSUdIVDogYm9s +ZDsgUEFERElORy1CT1RUT006IDVweDsgTUFSR0lOOiAwcHg7IENPTE9SOiByZ2IoMSw5NSwxODIp +OyBQQURESU5HLVRPUDogNXB4Ij48QSANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMSw5NSwxODIpOyBU +RVhULURFQ09SQVRJT046IHVuZGVybGluZSIgDQogIGhyZWY9Imh0dHA6Ly9tb2JpbGUuY3Nkbi5u +ZXQvIj7mm7TlpJrnsr7lvanlhoXlrrnvvIzlsL3lnKjnp7vliqjpopHpgZM8L0E+PC9EVD4NCiAg +PEREIGlkPTQ0ODI1OTM0MjUgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9V +TkQtUE9TSVRJT046IDNweCAxMnB4OyBESVNQTEFZOiBibG9jazsgUEFERElORy1MRUZUOiAxNHB4 +OyBCQUNLR1JPVU5ELUFUVEFDSE1FTlQ6IHNjcm9sbDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0 +dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzIzLmdpZik7IFBBRERJTkct +Qk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBMSU5FLUhFSUdIVDogMjFweDsgUEFERElORy1UT1A6 +IDVweDsgQkFDS0dST1VORC1DT0xPUjogdHJhbnNwYXJlbnQ7IGJhY2tncm91bmQtb3JpZ2luOiBp +bml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPg0KICA8UCBjbGFzcz10b3AgDQogIHN0 +eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IE9WRVJGTE9XLVk6IGhpZGRlbjsgUEFERElORy1MRUZU +OiAwcHg7IE9WRVJGTE9XLVg6IGhpZGRlbjsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAw +cHg7IFBBRERJTkctVE9QOiAwcHg7IEhFSUdIVDogNDBweCI+PFNQQU4gDQogIGNsYXNzPXR4dF9i +bHVlIHN0eWxlPSJDT0xPUjogcmdiKDEsOTUsMTgyKSI+PEEgDQogIHN0eWxlPSJDT0xPUjogcmdi +KDEsOTUsMTgyKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgaHJlZj0iaHR0cDovL3Quc2lu +YS5jb20uY24vMTcxMDkwMDM0MSI+5YiY6IiqPC9BPu+8mjwvU1BBTj7kurrmsJHmkJzntKLlrp7p +mYXnoJTnqbbnmoTmmK/kurrmsJHooqvmkJzntKIuIA0KICAvL0DmrKfok6xBVOenu+WKqOS6kuiB +lOe9kTrkvKDnu5/mkJzntKLlvJXmk47vvIjmr5TlpoLosLfmrYzvvInnoJTnqbbmgI7kuYjorqnl +pKflrrbmkJzlh7rkv6Hmga/vvIzlroPnoJTnqbbmgI7kuYjorqnlpKflrrbmkJzkuI3lh7rkv6Hm +ga/jgIIu5pyN5LqG5qW85Li744CCIC8vQHdhc2E65pyA5ZCO5LiA5Y+l5Lqu5LqG44CC44CCPC9Q +Pg0KICA8UCBjbGFzcz0iYnRtdGltZSB0eHRfYmx1ZSIgdGl0bGU9IjIwMTAtMTItMTYgMDE6MDk6 +MjIiIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiA1 +MCUgMTAwJTsgUEFERElORy1MRUZUOiAwcHg7IEJBQ0tHUk9VTkQtQVRUQUNITUVOVDogc2Nyb2xs +OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2Ru +aW5kZXhfcGljMTQuZ2lmKTsgUEFERElORy1CT1RUT006IDNweDsgTUFSR0lOOiAwcHg7IENPTE9S +OiByZ2IoMSw5NSwxODIpOyBQQURESU5HLVRPUDogMnB4OyBCQUNLR1JPVU5ELUNPTE9SOiB0cmFu +c3BhcmVudDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5p +dGlhbCI+OSANCiAgaG91cnMgYWdvPC9QPjwvREQ+DQogIDxERCBpZD00NDgyNTkzNjY5IA0KICBz +dHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAzcHggMTJweDsg +RElTUExBWTogYmxvY2s7IFBBRERJTkctTEVGVDogMTRweDsgQkFDS0dST1VORC1BVFRBQ0hNRU5U +OiBzY3JvbGw7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1h +Z2VzL2NzZG5pbmRleF9waWMyMy5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBw +eDsgTElORS1IRUlHSFQ6IDIxcHg7IFBBRERJTkctVE9QOiA1cHg7IEJBQ0tHUk9VTkQtQ09MT1I6 +IHRyYW5zcGFyZW50OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlw +OiBpbml0aWFsIj4NCiAgPFAgY2xhc3M9dG9wIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4 +OyBPVkVSRkxPVy1ZOiBoaWRkZW47IFBBRERJTkctTEVGVDogMHB4OyBPVkVSRkxPVy1YOiBoaWRk +ZW47IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBQQURESU5HLVRPUDogMHB4OyBI +RUlHSFQ6IDQwcHgiPjxTUEFOIA0KICBjbGFzcz10eHRfYmx1ZSBzdHlsZT0iQ09MT1I6IHJnYigx +LDk1LDE4MikiPjxBIA0KICBzdHlsZT0iQ09MT1I6IHJnYigxLDk1LDE4Mik7IFRFWFQtREVDT1JB +VElPTjogbm9uZSIgDQogIGhyZWY9Imh0dHA6Ly90LnNpbmEuY29tLmNuLzE0MDEzNjU1NzQiPueO +i+iIqmhkZjwvQT7vvJo8L1NQQU4+Q05OSUPnmoTku6PnkIbov5nluK7lrZnlrZDkuZ/kuI3liqjl +iqjohJHlrZDvvIzmr4/pmpTkuIDmrrXml7bpl7Tpg73og73mjqXliLDlkIzmoLfnmoTnlLXor53v +vIzor7Tms5XlrozlhajkuIDoh7TvvIzpg73mmK/or7TliKvkurropoHmiqLms6jkvaDnmoTkupLo +gZTnvZHlk4HniYzigJTigJTpgJrnlKjnvZHlnYDvvIzmiJbogIXmmK/miqLms6jkvaDnmoTnp7vl +iqjkupLogZTnvZHlk4HniYzigJTigJTml6Dnur/nvZHlnYDvvIzkvaDkuKvov57oirHmoLfpg73m +h5LlvpfmjaLvvIzlh6DlubTlpoLkuIDml6XnmoTov5nmoLfooYzpqpfjgILmiJHlrp7lnKjlv43m +l6Dlj6/lv43vvIzkvaDku6zov5nluK7lrZnlrZDvvIzmnaXngrnkuJPkuJrnsr7npZ7lpb3kuI3l +pb3vvJ88L1A+DQogIDxQIGNsYXNzPSJidG10aW1lIHR4dF9ibHVlIiB0aXRsZT0iMjAxMC0xMi0x +NiAwMTowOToyNCIgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9T +SVRJT046IDUwJSAxMDAlOyBQQURESU5HLUxFRlQ6IDBweDsgQkFDS0dST1VORC1BVFRBQ0hNRU5U +OiBzY3JvbGw7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1h +Z2VzL2NzZG5pbmRleF9waWMxNC5naWYpOyBQQURESU5HLUJPVFRPTTogM3B4OyBNQVJHSU46IDBw +eDsgQ09MT1I6IHJnYigxLDk1LDE4Mik7IFBBRERJTkctVE9QOiAycHg7IEJBQ0tHUk9VTkQtQ09M +T1I6IHRyYW5zcGFyZW50OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1j +bGlwOiBpbml0aWFsIj45IA0KICBob3VycyBhZ288L1A+PC9ERD4NCiAgPEREIGlkPTQ0ODI1OTU5 +MzkgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDNw +eCAxMnB4OyBESVNQTEFZOiBibG9jazsgUEFERElORy1MRUZUOiAxNHB4OyBCQUNLR1JPVU5ELUFU +VEFDSE1FTlQ6IHNjcm9sbDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNu +L3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzIzLmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1B +UkdJTjogMHB4OyBMSU5FLUhFSUdIVDogMjFweDsgUEFERElORy1UT1A6IDVweDsgQkFDS0dST1VO +RC1DT0xPUjogdHJhbnNwYXJlbnQ7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3Jv +dW5kLWNsaXA6IGluaXRpYWwiPg0KICA8UCBjbGFzcz10b3AgDQogIHN0eWxlPSJQQURESU5HLVJJ +R0hUOiAwcHg7IE9WRVJGTE9XLVk6IGhpZGRlbjsgUEFERElORy1MRUZUOiAwcHg7IE9WRVJGTE9X +LVg6IGhpZGRlbjsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IFBBRERJTkctVE9Q +OiAwcHg7IEhFSUdIVDogNDBweCI+PFNQQU4gDQogIGNsYXNzPXR4dF9ibHVlIHN0eWxlPSJDT0xP +UjogcmdiKDEsOTUsMTgyKSI+PEEgDQogIHN0eWxlPSJDT0xPUjogcmdiKDEsOTUsMTgyKTsgVEVY +VC1ERUNPUkFUSU9OOiBub25lIiANCiAgaHJlZj0iaHR0cDovL3Quc2luYS5jb20uY24vMTg4NTE3 +NTk3NyI+55ee5a2QNDIwNjwvQT7vvJo8L1NQQU4+44CK5LqS6IGU572RL+enu+WKqOS6kuiBlOe9 +keWwj+WboumYn+WIm+S4miDnrKzkuozpm4YgDQogIOaxquWNjuOAiyBodHRwOi8vc2luYXVybC5j +bi9oNHczemY8L1A+DQogIDxQIGNsYXNzPSJidG10aW1lIHR4dF9ibHVlIiB0aXRsZT0iMjAxMC0x +Mi0xNiAwMTowOTozOSIgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQt +UE9TSVRJT046IDUwJSAxMDAlOyBQQURESU5HLUxFRlQ6IDBweDsgQkFDS0dST1VORC1BVFRBQ0hN +RU5UOiBzY3JvbGw7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cv +aW1hZ2VzL2NzZG5pbmRleF9waWMxNC5naWYpOyBQQURESU5HLUJPVFRPTTogM3B4OyBNQVJHSU46 +IDBweDsgQ09MT1I6IHJnYigxLDk1LDE4Mik7IFBBRERJTkctVE9QOiAycHg7IEJBQ0tHUk9VTkQt +Q09MT1I6IHRyYW5zcGFyZW50OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3Vu +ZC1jbGlwOiBpbml0aWFsIj45IA0KICBob3VycyBhZ288L1A+PC9ERD4NCiAgPEREIGlkPTQ0ODI2 +MTQ5NDcgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046 +IDNweCAxMnB4OyBESVNQTEFZOiBibG9jazsgUEFERElORy1MRUZUOiAxNHB4OyBCQUNLR1JPVU5E +LUFUVEFDSE1FTlQ6IHNjcm9sbDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1n +LmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzIzLmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7 +IE1BUkdJTjogMHB4OyBMSU5FLUhFSUdIVDogMjFweDsgUEFERElORy1UT1A6IDVweDsgQkFDS0dS +T1VORC1DT0xPUjogdHJhbnNwYXJlbnQ7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNr +Z3JvdW5kLWNsaXA6IGluaXRpYWwiPg0KICA8UCBjbGFzcz10b3AgDQogIHN0eWxlPSJQQURESU5H +LVJJR0hUOiAwcHg7IE9WRVJGTE9XLVk6IGhpZGRlbjsgUEFERElORy1MRUZUOiAwcHg7IE9WRVJG +TE9XLVg6IGhpZGRlbjsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IFBBRERJTkct +VE9QOiAwcHg7IEhFSUdIVDogNDBweCI+PFNQQU4gDQogIGNsYXNzPXR4dF9ibHVlIHN0eWxlPSJD +T0xPUjogcmdiKDEsOTUsMTgyKSI+PEEgDQogIHN0eWxlPSJDT0xPUjogcmdiKDEsOTUsMTgyKTsg +VEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgaHJlZj0iaHR0cDovL3Quc2luYS5jb20uY24vMTY0 +MTk0NDI3MiI+5p2O5ZCN5aSrPC9BPu+8mjwvU1BBTj4vL0DmrKfok6xBVOenu+WKqOS6kuiBlOe9 +kToxMOW5tOS6huWQp++8n+mCo+S4ieS6v+mDqOS5n+Wkn+eJm+mAvOeahOS6huOAguS4jeefpemB +k+acieWkmuWwkemDqOaYr+WGhemUgOeahOOAgjwvUD4NCiAgPFAgY2xhc3M9ImJ0bXRpbWUgdHh0 +X2JsdWUiIHRpdGxlPSIyMDEwLTEyLTE2IDAxOjExOjQ3IiANCiAgc3R5bGU9IlBBRERJTkctUklH +SFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogNTAlIDEwMCU7IFBBRERJTkctTEVGVDogMHB4 +OyBCQUNLR1JPVU5ELUFUVEFDSE1FTlQ6IHNjcm9sbDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0 +dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzE0LmdpZik7IFBBRERJTkct +Qk9UVE9NOiAzcHg7IE1BUkdJTjogMHB4OyBDT0xPUjogcmdiKDEsOTUsMTgyKTsgUEFERElORy1U +T1A6IDJweDsgQkFDS0dST1VORC1DT0xPUjogdHJhbnNwYXJlbnQ7IGJhY2tncm91bmQtb3JpZ2lu +OiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjkgDQogIGhvdXJzIGFnbzwvUD48 +L0REPg0KICA8REQgaWQ9NDQ4MjYyMTU3MSANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsg +QkFDS0dST1VORC1QT1NJVElPTjogM3B4IDEycHg7IERJU1BMQVk6IGJsb2NrOyBQQURESU5HLUxF +RlQ6IDE0cHg7IEJBQ0tHUk9VTkQtQVRUQUNITUVOVDogc2Nyb2xsOyBCQUNLR1JPVU5ELUlNQUdF +OiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMjMuZ2lmKTsg +UEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IExJTkUtSEVJR0hUOiAyMXB4OyBQQURE +SU5HLVRPUDogNXB4OyBCQUNLR1JPVU5ELUNPTE9SOiB0cmFuc3BhcmVudDsgYmFja2dyb3VuZC1v +cmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+DQogIDxQIGNsYXNzPXRv +cCANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgT1ZFUkZMT1ctWTogaGlkZGVuOyBQQURE +SU5HLUxFRlQ6IDBweDsgT1ZFUkZMT1ctWDogaGlkZGVuOyBQQURESU5HLUJPVFRPTTogMHB4OyBN +QVJHSU46IDBweDsgUEFERElORy1UT1A6IDBweDsgSEVJR0hUOiA0MHB4Ij48U1BBTiANCiAgY2xh +c3M9dHh0X2JsdWUgc3R5bGU9IkNPTE9SOiByZ2IoMSw5NSwxODIpIj48QSANCiAgc3R5bGU9IkNP +TE9SOiByZ2IoMSw5NSwxODIpOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBocmVmPSJodHRw +Oi8vdC5zaW5hLmNvbS5jbi8xNjAxODg4MzY3Ij7otbXmtIticnVjZTwvQT7vvJo8L1NQQU4+5p2A +5q+S6L2v5Lu25oOv55So5LyO5L+p77yM6ISx5LqG6ams55Sy5LuW6L+Y5piv5LmM6b6f44CCIA0K +ICAvL0Dolpvom67lrZA65q2k6aOO5LiN5Y+v6ZW/77yM5ZOq5pyJ5Yy755Sf5YWI5pKS55eF5q+S +5YaN5rK755eF55qE44CC5bqU6K+l56uL5rOV5Lil56aB77yBIC8vQOasp+iTrEFU56e75Yqo5LqS +6IGU572ROiDpgKDnl4Xmr5Lml6nlsLHmmK/nlLXohJHooYzkuJrmg6/kvovjgILmiYvmnLrooYzk +uJrkuZ/kuI3kvovlpJblkKfjgIIgDQogIC8vQOi1teWylzrovazlj5Hlvq7ljZo8L1A+DQogIDxQ +IGNsYXNzPSJidG10aW1lIHR4dF9ibHVlIiB0aXRsZT0iMjAxMC0xMi0xNiAwMToxMjozMSIgDQog +IHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDUwJSAxMDAl +OyBQQURESU5HLUxFRlQ6IDBweDsgQkFDS0dST1VORC1BVFRBQ0hNRU5UOiBzY3JvbGw7IEJBQ0tH +Uk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9w +aWMxNC5naWYpOyBQQURESU5HLUJPVFRPTTogM3B4OyBNQVJHSU46IDBweDsgQ09MT1I6IHJnYigx +LDk1LDE4Mik7IFBBRERJTkctVE9QOiAycHg7IEJBQ0tHUk9VTkQtQ09MT1I6IHRyYW5zcGFyZW50 +OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj45 +IA0KICBob3VycyBhZ288L1A+PC9ERD48L0RMPg0KPERJViBjbGFzcz1tb3JlIA0Kc3R5bGU9IlBB +RERJTkctUklHSFQ6IDEwcHg7IFBBRERJTkctTEVGVDogMTBweDsgRkxPQVQ6IGxlZnQ7IFBBRERJ +TkctQk9UVE9NOiAxMHB4OyBXSURUSDogMjM4cHg7IFBBRERJTkctVE9QOiAwcHg7IFRFWFQtQUxJ +R046IHJpZ2h0Ij7mm7TlpJrnp7vliqjotYTorq88U1BBTiANCmNsYXNzPUFwcGxlLWNvbnZlcnRl +ZC1zcGFjZT4mbmJzcDs8L1NQQU4+PEEgY2xhc3M9dHh0X2JsdWUgDQpzdHlsZT0iRk9OVC1XRUlH +SFQ6IGJvbGQ7IENPTE9SOiByZ2IoMSw5NSwxODIpOyBURVhULURFQ09SQVRJT046IHVuZGVybGlu +ZSIgDQpocmVmPSJodHRwOi8vdC5zaW5hLmNvbS5jbi9jc2RubW9iaWxlIj7or7fov5vlhaUmZ3Q7 +Jmd0OzwvQT48L0RJVj4NCjxIMyANCnN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9V +TkQtUE9TSVRJT046IDBweCAwcHg7IERJU1BMQVk6IGlubGluZTsgUEFERElORy1MRUZUOiAyMHB4 +OyBGT05ULVNJWkU6IDE0cHg7IEZMT0FUOiBsZWZ0OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0 +cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMTUuZ2lmKTsgUEFERElORy1C +T1RUT006IDBweDsgTUFSR0lOOiAwcHggMHB4IDdweDsgV0lEVEg6IDIzOXB4OyBMSU5FLUhFSUdI +VDogMzBweDsgUEFERElORy1UT1A6IDBweDsgUE9TSVRJT046IHJlbGF0aXZlOyBiYWNrZ3JvdW5k +LW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48U1BBTiANCmNsYXNz +PSJ0eHRfMTIgdHh0X2dyYXkiIA0Kc3R5bGU9IkZPTlQtV0VJR0hUOiBub3JtYWw7IEZPTlQtU0la +RTogMTJweDsgRkxPQVQ6IHJpZ2h0OyBNQVJHSU46IDJweCA3cHggMHB4IDBweDsgQ09MT1I6IHJn +YigxMDIsMTAyLDEwMikiPjxBIA0Kc3R5bGU9IkNPTE9SOiByZ2IoMTAyLDEwMiwxMDIpOyBURVhU +LURFQ09SQVRJT046IG5vbmUiIA0KaHJlZj0iaHR0cDovL3d3dy5wcm9ncmFtbWVyLmNvbS5jbi8i +IHRhcmdldD1fYmxhbms+5pu05aSaPC9BPjwvU1BBTj7jgIrnqIvluo/lkZjjgIs8L0gzPg0KPERM +IGNsYXNzPXN0eWxlMyANCnN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IERJU1BMQVk6IGlubGlu +ZTsgUEFERElORy1MRUZUOiAwcHg7IEZMT0FUOiBsZWZ0OyBQQURESU5HLUJPVFRPTTogMHB4OyBN +QVJHSU46IDVweCAxMHB4OyBXSURUSDogMjM5cHg7IFBBRERJTkctVE9QOiAwcHgiPg0KICA8REQg +DQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDNweCA3 +cHg7IFBBRERJTkctTEVGVDogMTRweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2Ru +aW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzIzLmdpZik7IFBBRERJTkctQk9UVE9NOiAw +cHg7IE1BUkdJTjogMHB4OyBMSU5FLUhFSUdIVDogMjFweDsgUEFERElORy1UT1A6IDBweDsgYmFj +a2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQog +IHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25j +bGljaz1Mb2dDbGlja0NvdW50KHRoaXMsMTY0KTsgDQogIGhyZWY9Imh0dHA6Ly93d3cucHJvZ3Jh +bW1lci5jb20uY24vNDQ0OC8iPuWBmuacieW4guWcuuaAnee7tOeahOW8gOWPkeS6uuWRmDwvQT48 +L0REPg0KICA8REQgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9T +SVRJT046IDNweCA3cHg7IFBBRERJTkctTEVGVDogMTRweDsgQkFDS0dST1VORC1JTUFHRTogdXJs +KGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzIzLmdpZik7IFBBRERJ +TkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBMSU5FLUhFSUdIVDogMjFweDsgUEFERElORy1U +T1A6IDBweDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5p +dGlhbCI+PEEgDQogIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBu +b25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsMTY0KTsgDQogIGhyZWY9Imh0dHA6 +Ly93d3cucHJvZ3JhbW1lci5jb20uY24vNDQ0NC8iPldhdHRzIFMuIEh1bXBocmV577ya6L2v5Lu2 +6LSo6YeP5LmL54i2PC9BPjwvREQ+DQogIDxERCANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBw +eDsgQkFDS0dST1VORC1QT1NJVElPTjogM3B4IDdweDsgUEFERElORy1MRUZUOiAxNHB4OyBCQUNL +R1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhf +cGljMjMuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IExJTkUtSEVJR0hU +OiAyMXB4OyBQQURESU5HLVRPUDogMHB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFj +a2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBU +RVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcywxNjQp +OyANCiAgaHJlZj0iaHR0cDovL3d3dy5wcm9ncmFtbWVyLmNvbS5jbi80NDQxLyI+5a6J5YWo5q2j +5Zug5LqR6ICM5pS55Y+YPC9BPjwvREQ+DQogIDxERCANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6 +IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogM3B4IDdweDsgUEFERElORy1MRUZUOiAxNHB4OyBC +QUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5k +ZXhfcGljMjMuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IExJTkUtSEVJ +R0hUOiAyMXB4OyBQQURESU5HLVRPUDogMHB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsg +YmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDAp +OyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcywx +NjQpOyANCiAgaHJlZj0iaHR0cDovL3d3dy5wcm9ncmFtbWVyLmNvbS5jbi80NDM4LyI+6JKL5rab +77ya5qKm5oOz55qE5Y2B5bm0PC9BPjwvREQ+PC9ETD4NCjxIMyANCnN0eWxlPSJQQURESU5HLVJJ +R0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDBweCAwcHg7IERJU1BMQVk6IGlubGluZTsg +UEFERElORy1MRUZUOiAyMHB4OyBGT05ULVNJWkU6IDE0cHg7IEZMT0FUOiBsZWZ0OyBCQUNLR1JP +VU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGlj +MTUuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHggMHB4IDdweDsgV0lEVEg6 +IDIzOXB4OyBMSU5FLUhFSUdIVDogMzBweDsgUEFERElORy1UT1A6IDBweDsgUE9TSVRJT046IHJl +bGF0aXZlOyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0 +aWFsIj48U1BBTiANCmNsYXNzPSJ0eHRfMTIgdHh0X2dyYXkiIA0Kc3R5bGU9IkZPTlQtV0VJR0hU +OiBub3JtYWw7IEZPTlQtU0laRTogMTJweDsgRkxPQVQ6IHJpZ2h0OyBNQVJHSU46IDJweCA3cHgg +MHB4IDBweDsgQ09MT1I6IHJnYigxMDIsMTAyLDEwMikiPjxBIA0Kc3R5bGU9IkNPTE9SOiByZ2Io +MTAyLDEwMiwxMDIpOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KaHJlZj0iaHR0cDovL25ld3Mu +Y3Nkbi5uZXQvIiB0YXJnZXQ9X2JsYW5rPuabtOWkmjwvQT48L1NQQU4+54Ot54K56LWE6K6v5o6S +6KGMPC9IMz4NCjxETCBjbGFzcz0ic3R5bGUyIHR4dF9ibGFjayIgDQpzdHlsZT0iUEFERElORy1S +SUdIVDogMHB4OyBESVNQTEFZOiBpbmxpbmU7IFBBRERJTkctTEVGVDogMHB4OyBGTE9BVDogbGVm +dDsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiA1cHggMTBweDsgV0lEVEg6IDIzOXB4OyBD +T0xPUjogcmdiKDAsMCwwKTsgUEFERElORy1UT1A6IDBweCI+DQogIDxEVCBjbGFzcz10b3AxIA0K +ICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAwcHggM3B4 +OyBPVkVSRkxPVy1ZOiBoaWRkZW47IFBBRERJTkctTEVGVDogMjRweDsgQkFDS0dST1VORC1JTUFH +RTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzM1LmdpZik7 +IE9WRVJGTE9XLVg6IGhpZGRlbjsgUEFERElORy1CT1RUT006IDFweDsgTUFSR0lOOiAwcHg7IFdJ +RFRIOiAyMTBweDsgUEFERElORy1UT1A6IDRweDsgV0hJVEUtU1BBQ0U6IG5vd3JhcDsgYmFja2dy +b3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRp +dGxlPeeJueeri+eLrOihjOeahOeoi+W6j+WRmO+8mue7tOWfuuino+WvhuWIm+Wni+S6uumYv+ah +keWlh+S8oOWlhyBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9u +ZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDEwNSk7IA0KICBocmVmPSJodHRwOi8v +bmV3cy5jc2RuLm5ldC9hLzIwMTAxMjE1LzI4MzY2Ny5odG1sIiANCiAgdGFyZ2V0PV9ibGFuaz7n +ibnnq4vni6zooYznmoTnqIvluo/lkZjvvJrnu7Tln7rop6Plr4bliJvlp4vkurrpmL/moZHlpYfk +vKDlpYc8L0E+PC9EVD4NCiAgPERUIGNsYXNzPXRvcDIgDQogIHN0eWxlPSJQQURESU5HLVJJR0hU +OiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDBweCAzcHg7IE9WRVJGTE9XLVk6IGhpZGRlbjsg +UEFERElORy1MRUZUOiAyNHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcu +Y24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMzYuZ2lmKTsgT1ZFUkZMT1ctWDogaGlkZGVuOyBQ +QURESU5HLUJPVFRPTTogMXB4OyBNQVJHSU46IDBweDsgV0lEVEg6IDIxMHB4OyBQQURESU5HLVRP +UDogNHB4OyBXSElURS1TUEFDRTogbm93cmFwOyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsg +YmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgdGl0bGU9IkdtYWls5LmL54i277yaQ2hy +b21lIE9T5p2l5pel5peg5aSaIiBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JB +VElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDEwNSk7IA0KICBocmVm +PSJodHRwOi8vbmV3cy5jc2RuLm5ldC9hLzIwMTAxMjE1LzI4MzY2Ni5odG1sIiANCiAgdGFyZ2V0 +PV9ibGFuaz5HbWFpbOS5i+eItu+8mkNocm9tZSBPU+adpeaXpeaXoOWkmjwvQT48L0RUPg0KICA8 +RFQgY2xhc3M9dG9wMyANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1Q +T1NJVElPTjogMHB4IDNweDsgT1ZFUkZMT1ctWTogaGlkZGVuOyBQQURESU5HLUxFRlQ6IDI0cHg7 +IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5p +bmRleF9waWMzNy5naWYpOyBPVkVSRkxPVy1YOiBoaWRkZW47IFBBRERJTkctQk9UVE9NOiAxcHg7 +IE1BUkdJTjogMHB4OyBXSURUSDogMjEwcHg7IFBBRERJTkctVE9QOiA0cHg7IFdISVRFLVNQQUNF +OiBub3dyYXA7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGlu +aXRpYWwiPjxBIA0KICB0aXRsZT0iTEJT5bCG5oiQ5LqS6IGU572R5LiL5LiA5Zy66KGA6IWl5oiY +IDLlubTlkI7luILlnLrotoXnmb7kur8iIA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRF +WFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDEwNSk7 +IA0KICBocmVmPSJodHRwOi8vbmV3cy5jc2RuLm5ldC9hLzIwMTAxMjE0LzI4MzU5My5odG1sIiAN +CiAgdGFyZ2V0PV9ibGFuaz5MQlPlsIbmiJDkupLogZTnvZHkuIvkuIDlnLrooYDohaXmiJggMuW5 +tOWQjuW4guWcuui2heeZvuS6vzwvQT48L0RUPg0KICA8RFQgY2xhc3M9dG9wNCANCiAgc3R5bGU9 +IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMHB4IDNweDsgT1ZFUkZM +T1ctWTogaGlkZGVuOyBQQURESU5HLUxFRlQ6IDI0cHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybCho +dHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMzOC5naWYpOyBPVkVSRkxP +Vy1YOiBoaWRkZW47IFBBRERJTkctQk9UVE9NOiAxcHg7IE1BUkdJTjogMHB4OyBXSURUSDogMjEw +cHg7IFBBRERJTkctVE9QOiA0cHg7IFdISVRFLVNQQUNFOiBub3dyYXA7IGJhY2tncm91bmQtb3Jp +Z2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0aXRsZT3lpJbl +qpLor4TpgInov4fljrsyNeW5tDEw5aSn6buR5a6i5pS75Ye75LqL5Lu2IHN0eWxlPSJDT0xPUjog +cmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0Nv +dW50KHRoaXMsMTA1KTsgDQogIGhyZWY9Imh0dHA6Ly9jbG91ZC5jc2RuLm5ldC9hLzIwMTAxMjE0 +LzI4MzU3Ny5odG1sIiANCiAgdGFyZ2V0PV9ibGFuaz7lpJblqpLor4TpgInov4fljrsyNeW5tDEw +5aSn6buR5a6i5pS75Ye75LqL5Lu2PC9BPjwvRFQ+DQogIDxEVCBjbGFzcz10b3A1IA0KICBzdHls +ZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAwcHggM3B4OyBPVkVS +RkxPVy1ZOiBoaWRkZW47IFBBRERJTkctTEVGVDogMjRweDsgQkFDS0dST1VORC1JTUFHRTogdXJs +KGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzM5LmdpZik7IE9WRVJG +TE9XLVg6IGhpZGRlbjsgUEFERElORy1CT1RUT006IDFweDsgTUFSR0lOOiAwcHg7IFdJRFRIOiAy +MTBweDsgUEFERElORy1UT1A6IDRweDsgV0hJVEUtU1BBQ0U6IG5vd3JhcDsgYmFja2dyb3VuZC1v +cmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxlPeW+ +rui9r+Wuo+W4g+WPiOS4gOmdnldpbmRvd3Pmk43kvZzns7vnu59WZXJ2ZSBzdHlsZT0iQ09MT1I6 +IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tD +b3VudCh0aGlzLDEwNSk7IA0KICBocmVmPSJodHRwOi8vbmV3cy5jc2RuLm5ldC9hLzIwMTAxMjEz +LzI4MzUzNi5odG1sIiANCiAgdGFyZ2V0PV9ibGFuaz7lvq7ova/lrqPluIPlj4jkuIDpnZ5XaW5k +b3dz5pON5L2c57O757ufVmVydmU8L0E+PC9EVD4NCiAgPERUIGNsYXNzPXRvcDYgDQogIHN0eWxl +PSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDBweCAzcHg7IE9WRVJG +TE9XLVk6IGhpZGRlbjsgUEFERElORy1MRUZUOiAyNHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwo +aHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljNDAuZ2lmKTsgT1ZFUkZM +T1ctWDogaGlkZGVuOyBQQURESU5HLUJPVFRPTTogMXB4OyBNQVJHSU46IDBweDsgV0lEVEg6IDIx +MHB4OyBQQURESU5HLVRPUDogNHB4OyBXSElURS1TUEFDRTogbm93cmFwOyBiYWNrZ3JvdW5kLW9y +aWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgdGl0bGU9IkNo +cm9tZSBPU+eahOelnuenmOmtheWKmyIgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURF +Q09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcywxMDUpOyANCiAg +aHJlZj0iaHR0cDovL2Nsb3VkLmNzZG4ubmV0L2EvMjAxMDEyMTMvMjgzNDcyLmh0bWwiIHRhcmdl +dD1fYmxhbms+Q2hyb21lIA0KICBPU+eahOelnuenmOmtheWKmzwvQT48L0RUPg0KICA8RFQgY2xh +c3M9dG9wNyANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElP +TjogMHB4IDNweDsgT1ZFUkZMT1ctWTogaGlkZGVuOyBQQURESU5HLUxFRlQ6IDI0cHg7IEJBQ0tH +Uk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9w +aWM0MS5naWYpOyBPVkVSRkxPVy1YOiBoaWRkZW47IFBBRERJTkctQk9UVE9NOiAxcHg7IE1BUkdJ +TjogMHB4OyBXSURUSDogMjEwcHg7IFBBRERJTkctVE9QOiA0cHg7IFdISVRFLVNQQUNFOiBub3dy +YXA7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwi +PjxBIA0KICB0aXRsZT3oi7nmnpzlt6XnqIvluIjnlKjkuZDpq5jnp6/mnKjph43lu7rmnIDlj6To +gIHorqHnrpfmnLogc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5v +bmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcywxMDUpOyANCiAgaHJlZj0iaHR0cDov +L25ld3MuY3Nkbi5uZXQvYS8yMDEwMTIxMy8yODM0NzkuaHRtbCIgDQogIHRhcmdldD1fYmxhbms+ +6Iu55p6c5bel56iL5biI55So5LmQ6auY56ev5pyo6YeN5bu65pyA5Y+k6ICB6K6h566X5py6PC9B +PjwvRFQ+DQogIDxEVCBjbGFzcz10b3A4IA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBC +QUNLR1JPVU5ELVBPU0lUSU9OOiAwcHggM3B4OyBPVkVSRkxPVy1ZOiBoaWRkZW47IFBBRERJTkct +TEVGVDogMjRweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9p +bWFnZXMvY3NkbmluZGV4X3BpYzQyLmdpZik7IE9WRVJGTE9XLVg6IGhpZGRlbjsgUEFERElORy1C +T1RUT006IDFweDsgTUFSR0lOOiAwcHg7IFdJRFRIOiAyMTBweDsgUEFERElORy1UT1A6IDRweDsg +V0hJVEUtU1BBQ0U6IG5vd3JhcDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91 +bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxlPSLpmL/luJXlpYfln7rph5HkvJrmrLLpgIDl +h7pKYXZh5aeU5ZGY5LyaIOeUsumqqOaWh+acm+WFtuS4ieaAnSIgDQogIHN0eWxlPSJDT0xPUjog +cmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0Nv +dW50KHRoaXMsMTA1KTsgDQogIGhyZWY9Imh0dHA6Ly9qYXZhLmNzZG4ubmV0L2EvMjAxMDEyMTMv +MjgzNDgwLmh0bWwiIA0KICB0YXJnZXQ9X2JsYW5rPumYv+W4leWlh+WfuumHkeS8muassumAgOWH +ukphdmHlp5TlkZjkvJog55Sy6aqo5paH5pyb5YW25LiJ5oCdPC9BPjwvRFQ+DQogIDxEVCBjbGFz +cz10b3A5IA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9O +OiAwcHggM3B4OyBPVkVSRkxPVy1ZOiBoaWRkZW47IFBBRERJTkctTEVGVDogMjRweDsgQkFDS0dS +T1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3Bp +YzQzLmdpZik7IE9WRVJGTE9XLVg6IGhpZGRlbjsgUEFERElORy1CT1RUT006IDFweDsgTUFSR0lO +OiAwcHg7IFdJRFRIOiAyMTBweDsgUEFERElORy1UT1A6IDRweDsgV0hJVEUtU1BBQ0U6IG5vd3Jh +cDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+ +PEEgDQogIHRpdGxlPTIwMTDlubTmtojotLnnlLXlrZDmioDmnK8yMOS4quacgOWkp+Wksei0pe+8 +mkJ1enrlsYXpppYgDQogIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9O +OiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsMTA1KTsgDQogIGhyZWY9Imh0 +dHA6Ly9uZXdzLmNzZG4ubmV0L2EvMjAxMDEyMTMvMjgzNDY1Lmh0bWwiIA0KICB0YXJnZXQ9X2Js +YW5rPjIwMTDlubTmtojotLnnlLXlrZDmioDmnK8yMOS4quacgOWkp+Wksei0pe+8mkJ1enrlsYXp +ppY8L0E+PC9EVD4NCiAgPERUIGNsYXNzPXRvcDEwIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDog +MHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAwcHggM3B4OyBPVkVSRkxPVy1ZOiBoaWRkZW47IFBB +RERJTkctTEVGVDogMjRweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNu +L3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzQ0LmdpZik7IE9WRVJGTE9XLVg6IGhpZGRlbjsgUEFE +RElORy1CT1RUT006IDFweDsgTUFSR0lOOiAwcHg7IFdJRFRIOiAyMTBweDsgUEFERElORy1UT1A6 +IDRweDsgV0hJVEUtU1BBQ0U6IG5vd3JhcDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJh +Y2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxlPeS6uuawkeaQnOe0ou+8muS4jeS4 +juWVhuS4muaQnOe0ouato+mdouernuS6iSBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQt +REVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDEwNSk7IA0K +ICBocmVmPSJodHRwOi8vbmV3cy5jc2RuLm5ldC9hLzIwMTAxMjEwLzI4MzM2OS5odG1sIiANCiAg +dGFyZ2V0PV9ibGFuaz7kurrmsJHmkJzntKLvvJrkuI3kuI7llYbkuJrmkJzntKLmraPpnaLnq57k +uok8L0E+PC9EVD48L0RMPjwvRElWPjwvRElWPjwvRElWPg0KPERJViBjbGFzcz1wYWdlY29uX2xh +eWVyMmJ0bSANCnN0eWxlPSJCQUNLR1JPVU5ELVBPU0lUSU9OOiA1MCUgMTAwJTsgRk9OVC1TSVpF +OiAxcHg7IEZMT0FUOiBsZWZ0OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcu +Y24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljNDUuZ2lmKTsgV0lEVEg6IDk2MHB4OyBIRUlHSFQ6 +IDFweDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlh +bCI+PC9ESVY+DQo8RElWIGNsYXNzPWJ1c2luZXNzYWQgDQpzdHlsZT0iRkxPQVQ6IGxlZnQ7IE1B +UkdJTjogNHB4IDBweCAwcHg7IFdJRFRIOiA5NjBweDsgUE9TSVRJT046IHJlbGF0aXZlOyBURVhU +LUFMSUdOOiBsZWZ0Ij4NCjxVTCANCnN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IFBBRERJTkct +TEVGVDogMHB4OyBGTE9BVDogbGVmdDsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7 +IFdJRFRIOiA5NjBweDsgUEFERElORy1UT1A6IDBweDsgTElTVC1TVFlMRS1UWVBFOiBub25lIj4N +CiAgPExJIGNsYXNzPWxlZnRhZCANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgUEFERElO +Ry1MRUZUOiAwcHg7IEZMT0FUOiBsZWZ0OyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBw +eDsgV0lEVEg6IDczNXB4OyBQQURESU5HLVRPUDogMHB4Ij48QSANCiAgc3R5bGU9IkNPTE9SOiBy +Z2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBocmVmPSJodHRwOi8vei5jc2Ru +Lm5ldC9nbWNsaWNrLnBocD9iYW5uZXJpZD01NDMzJmFtcDt6b25laWQ9NDA3JmFtcDtzb3VyY2U9 +JmFtcDtkZXN0PWh0dHAlM0ElMkYlMkZ3d3cuaW50ZWxzb2Z0d2FyZWNoYW5uZWwuY29tJTJGIiAN +CiAgdGFyZ2V0PV9ibGFuaz48SU1HIHRpdGxlPSIiIA0KICBzdHlsZT0iQk9SREVSLVRPUC1XSURU +SDogMHB4OyBCT1JERVItTEVGVC1XSURUSDogMHB4OyBCT1JERVItQk9UVE9NLVdJRFRIOiAwcHg7 +IEJPUkRFUi1SSUdIVC1XSURUSDogMHB4IiANCiAgaGVpZ2h0PTkwIGFsdD0iIiANCiAgc3JjPSJo +dHRwOi8vaW5mby1kYXRhYmFzZS5jc2RuLm5ldC9VcGxvYWQvMjAxMC0xMi0xMC83MzVfOTBfYW5u +aWUuanBnIiANCiAgd2lkdGg9NzM1IGJvcmRlcj0wPjwvQT4NCiAgPERJViBpZD1iZWFjb25fNTQz +MyANCiAgc3R5bGU9IkxFRlQ6IDBweDsgVklTSUJJTElUWTogaGlkZGVuOyBQT1NJVElPTjogYWJz +b2x1dGU7IFRPUDogMHB4Ij48SU1HIA0KICBzdHlsZT0iQk9SREVSLVRPUC1XSURUSDogMHB4OyBC +T1JERVItTEVGVC1XSURUSDogMHB4OyBCT1JERVItQk9UVE9NLVdJRFRIOiAwcHg7IFdJRFRIOiAw +cHg7IEhFSUdIVDogMHB4OyBCT1JERVItUklHSFQtV0lEVEg6IDBweCIgDQogIGhlaWdodD0wIGFs +dD0iIiANCiAgc3JjPSJodHRwOi8vei5jc2RuLm5ldC9nbWxvZy5waHA/YmFubmVyaWQ9NTQzMyZh +bXA7Y2xpZW50aWQ9MTcwMyZhbXA7emY9JmFtcDt6b25laWQ9NDA3JmFtcDtzb3VyY2U9JmFtcDti +bG9jaz0wJmFtcDtjYXBwaW5nPTAmYW1wO2NiPWJjYTdkNGYxODc4YmYyYWE2YmIyOTg0YWVlZTE2 +NGNjIiANCiAgd2lkdGg9MD48L0RJVj48L0xJPg0KICA8TEkgY2xhc3M9cmlnaHRhZCANCiAgc3R5 +bGU9IlBBRERJTkctUklHSFQ6IDBweDsgUEFERElORy1MRUZUOiAwcHg7IEZMT0FUOiByaWdodDsg +UEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IFdJRFRIOiAyMTBweDsgUEFERElORy1U +T1A6IDBweCI+PEEgDQogIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9O +OiBub25lIiANCiAgaHJlZj0iaHR0cDovL3ouY3Nkbi5uZXQvZ21jbGljay5waHA/YmFubmVyaWQ9 +NTQwMCZhbXA7em9uZWlkPTQwOCZhbXA7c291cmNlPSZhbXA7ZGVzdD1odHRwJTNBJTJGJTJGMTg5 +d29ya3MuY3Nkbi5uZXQlMkYrIiANCiAgdGFyZ2V0PV9ibGFuaz48SU1HIHRpdGxlPSIiIA0KICBz +dHlsZT0iQk9SREVSLVRPUC1XSURUSDogMHB4OyBCT1JERVItTEVGVC1XSURUSDogMHB4OyBCT1JE +RVItQk9UVE9NLVdJRFRIOiAwcHg7IEJPUkRFUi1SSUdIVC1XSURUSDogMHB4IiANCiAgaGVpZ2h0 +PTkwIGFsdD0iIiANCiAgc3JjPSJodHRwOi8vaW5mby1kYXRhYmFzZS5jc2RuLm5ldC9VcGxvYWQv +MjAxMC0xMi0wMy8yMTBfOTBfMTEwMy5naWYiIA0KICB3aWR0aD0yMTAgYm9yZGVyPTA+PC9BPg0K +ICA8RElWIGlkPWJlYWNvbl81NDAwIA0KICBzdHlsZT0iTEVGVDogMHB4OyBWSVNJQklMSVRZOiBo +aWRkZW47IFBPU0lUSU9OOiBhYnNvbHV0ZTsgVE9QOiAwcHgiPjxJTUcgDQogIHN0eWxlPSJCT1JE +RVItVE9QLVdJRFRIOiAwcHg7IEJPUkRFUi1MRUZULVdJRFRIOiAwcHg7IEJPUkRFUi1CT1RUT00t +V0lEVEg6IDBweDsgV0lEVEg6IDBweDsgSEVJR0hUOiAwcHg7IEJPUkRFUi1SSUdIVC1XSURUSDog +MHB4IiANCiAgaGVpZ2h0PTAgYWx0PSIiIA0KICBzcmM9Imh0dHA6Ly96LmNzZG4ubmV0L2dtbG9n +LnBocD9iYW5uZXJpZD01NDAwJmFtcDtjbGllbnRpZD0xNjk5JmFtcDt6Zj0mYW1wO3pvbmVpZD00 +MDgmYW1wO3NvdXJjZT0mYW1wO2Jsb2NrPTAmYW1wO2NhcHBpbmc9MCZhbXA7Y2I9M2NlMmUwNDYx +NjJkYzQyZjczZjg0NzMxYWZiYmE3NzEiIA0KICB3aWR0aD0wPjwvRElWPjwvTEk+PC9VTD48L0RJ +Vj4NCjxESVYgY2xhc3M9cGFnZWNvbl9sYXllcjIgDQpzdHlsZT0iRkxPQVQ6IGxlZnQ7IEJBQ0tH +Uk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9w +aWMzMy5naWYpOyBNQVJHSU46IDNweCAwcHggMHB4OyBXSURUSDogOTYwcHg7IFBPU0lUSU9OOiBy +ZWxhdGl2ZTsgVEVYVC1BTElHTjogbGVmdDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJh +Y2tncm91bmQtY2xpcDogaW5pdGlhbCI+DQo8RElWIGNsYXNzPXBhZ2VfMDlzaWRlYmFyd3JhcCAN +CnN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJPUkRFUi1UT1A6IHJnYigyMDQsMjA0LDIwNCkg +MXB4IHNvbGlkOyBESVNQTEFZOiBpbmxpbmU7IFBBRERJTkctTEVGVDogMHB4OyBGTE9BVDogcmln +aHQ7IFBBRERJTkctQk9UVE9NOiA2cHg7IE1BUkdJTjogMHB4IDFweCAwcHggMHB4OyBXSURUSDog +MjA4cHg7IFBBRERJTkctVE9QOiAwcHg7IFRFWFQtQUxJR046IGxlZnQiPg0KPERJViBjbGFzcz1z +aWRlYmFyX2NvbiANCnN0eWxlPSJESVNQTEFZOiBpbmxpbmU7IEZMT0FUOiBsZWZ0OyBNQVJHSU46 +IDZweCAzcHggMnB4OyBXSURUSDogMjAycHgiPg0KPEg0IGNsYXNzPXR4dF8xMiANCnN0eWxlPSJQ +QURESU5HLVJJR0hUOiAwcHg7IFBBRERJTkctTEVGVDogM3B4OyBGT05ULVNJWkU6IDEycHg7IFBB +RERJTkctQk9UVE9NOiA1cHg7IE1BUkdJTjogMHB4OyBQQURESU5HLVRPUDogMHB4OyBCT1JERVIt +Qk9UVE9NOiByZ2IoMjA0LDIwNCwyMDQpIDFweCBzb2xpZDsgUE9TSVRJT046IHJlbGF0aXZlIj48 +U1BBTiANCmNsYXNzPXR4dF9ncmF5IA0Kc3R5bGU9IkZPTlQtV0VJR0hUOiBub3JtYWw7IEZMT0FU +OiByaWdodDsgQ09MT1I6IHJnYigxMDIsMTAyLDEwMikiPnw8QSANCnN0eWxlPSJQQURESU5HLVJJ +R0hUOiAwcHg7IFBBRERJTkctTEVGVDogNXB4OyBQQURESU5HLUJPVFRPTTogMHB4OyBDT0xPUjog +cmdiKDEwMiwxMDIsMTAyKTsgUEFERElORy1UT1A6IDBweDsgVEVYVC1ERUNPUkFUSU9OOiBub25l +IiANCmhyZWY9Imh0dHA6Ly9zdHVkZW50LmNzZG4ubmV0LyIgdGFyZ2V0PV9ibGFuaz7mm7TlpJo8 +L0E+PC9TUEFOPuWtpuS5oOepuumXtDwvSDQ+DQo8REwgY2xhc3M9c2Vzc2lvbl9zdHlsZSANCnN0 +eWxlPSJQQURESU5HLVJJR0hUOiAzcHg7IFBBRERJTkctTEVGVDogM3B4OyBGTE9BVDogbGVmdDsg +UEFERElORy1CT1RUT006IDVweDsgTUFSR0lOOiAycHggMHB4IDBweDsgV0lEVEg6IDE5NnB4OyBQ +QURESU5HLVRPUDogMTBweDsgQk9SREVSLUJPVFRPTTogcmdiKDIwNCwyMDQsMjA0KSAxcHggc29s +aWQ7IEJBQ0tHUk9VTkQtQ09MT1I6IHJnYigyNTUsMjU1LDI1NSk7IGJhY2tncm91bmQtb3JpZ2lu +OiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPg0KICA8REQgDQogIHN0eWxlPSJQ +QURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDJweCA3cHg7IFBBRERJTkct +TEVGVDogMTJweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9p +bWFnZXMvY3NkbmluZGV4X3BpYzUuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAw +cHg7IExJTkUtSEVJR0hUOiAxOXB4OyBQQURESU5HLVRPUDogMHB4OyBiYWNrZ3JvdW5kLW9yaWdp +bjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgdGl0bGU9IjEyLTE1 +6K6y5aCCIExpbnV457O757uf5byV5a+85rWB56iL77yI5LiK77yJIiANCiAgc3R5bGU9IkNPTE9S +OiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNr +Q291bnQodGhpcyw5NSk7IA0KICBocmVmPSJodHRwOi8vc3R1ZGVudC5jc2RuLm5ldC9zcGFjZS5w +aHA/ZG89b25saW5lcm9vbSZhbXA7aWQ9MjE2IiANCiAgdGFyZ2V0PV9ibGFuaz4xMi0xNeiusuWg +giBMaW51eOezu+e7nzwvQT48L0REPg0KICA8REQgY2xhc3M9InNvdXJjZV9zdHkgdHh0X2JsYWNr +IiANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgUEFERElORy1MRUZUOiAxMnB4OyBCQUNL +R1JPVU5ELUlNQUdFOiBub25lOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweDsgQ09M +T1I6IHJnYigwLDAsMCk7IExJTkUtSEVJR0hUOiAxOXB4OyBQQURESU5HLVRPUDogMHB4OyBiYWNr +Z3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48RU0gDQog +IHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgRk9OVC1TVFlMRTogbm9ybWFsIj48L0VNPjwvREQ+ +DQogIDxERCANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElP +TjogMnB4IDdweDsgUEFERElORy1MRUZUOiAxMnB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0 +cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljNS5naWYpOyBQQURESU5HLUJP +VFRPTTogMHB4OyBNQVJHSU46IDBweDsgTElORS1IRUlHSFQ6IDE5cHg7IFBBRERJTkctVE9QOiAw +cHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwi +PjxBIA0KICB0aXRsZT0iMTItMTXorrLloIIg5ZyG5ZGo546H55qE6L+R5Ly86K6h566XIiBzdHls +ZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9 +TG9nQ2xpY2tDb3VudCh0aGlzLDk1KTsgDQogIGhyZWY9Imh0dHA6Ly9zdHVkZW50LmNzZG4ubmV0 +L3NwYWNlLnBocD9kbz1vbmxpbmVyb29tJmFtcDtpZD0yMjEiIA0KICB0YXJnZXQ9X2JsYW5rPjEy +LTE16K6y5aCCIOWchuWRqOeOh+eahOi/keS8vOiuoTwvQT48L0REPg0KICA8REQgY2xhc3M9InNv +dXJjZV9zdHkgdHh0X2JsYWNrIiANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgUEFERElO +Ry1MRUZUOiAxMnB4OyBCQUNLR1JPVU5ELUlNQUdFOiBub25lOyBQQURESU5HLUJPVFRPTTogMHB4 +OyBNQVJHSU46IDBweDsgQ09MT1I6IHJnYigwLDAsMCk7IExJTkUtSEVJR0hUOiAxOXB4OyBQQURE +SU5HLVRPUDogMHB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlw +OiBpbml0aWFsIj48RU0gDQogIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgRk9OVC1TVFlMRTog +bm9ybWFsIj48L0VNPjwvREQ+DQogIDxERCANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsg +QkFDS0dST1VORC1QT1NJVElPTjogMnB4IDdweDsgUEFERElORy1MRUZUOiAxMnB4OyBCQUNLR1JP +VU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGlj +NS5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweDsgTElORS1IRUlHSFQ6IDE5 +cHg7IFBBRERJTkctVE9QOiAwcHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3Jv +dW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0aXRsZT0iMTItMTborrLloIIgTGludXjns7vnu5/l +vJXlr7zmtYHnqIvvvIjkuIvvvIkiIA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQt +REVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDk1KTsgDQog +IGhyZWY9Imh0dHA6Ly9zdHVkZW50LmNzZG4ubmV0L3NwYWNlLnBocD9kbz1vbmxpbmVyb29tJmFt +cDtpZD0yMTciIA0KICB0YXJnZXQ9X2JsYW5rPjEyLTE26K6y5aCCIExpbnV457O757ufPC9BPjwv +REQ+DQogIDxERCBjbGFzcz0ic291cmNlX3N0eSB0eHRfYmxhY2siIA0KICBzdHlsZT0iUEFERElO +Ry1SSUdIVDogMHB4OyBQQURESU5HLUxFRlQ6IDEycHg7IEJBQ0tHUk9VTkQtSU1BR0U6IG5vbmU7 +IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBDT0xPUjogcmdiKDAsMCwwKTsgTElO +RS1IRUlHSFQ6IDE5cHg7IFBBRERJTkctVE9QOiAwcHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0 +aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxFTSANCiAgc3R5bGU9IkNPTE9SOiByZ2Io +MCwwLDApOyBGT05ULVNUWUxFOiBub3JtYWwiPjwvRU0+PC9ERD4NCiAgPEREIA0KICBzdHlsZT0i +UEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAycHggN3B4OyBQQURESU5H +LUxFRlQ6IDEycHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cv +aW1hZ2VzL2NzZG5pbmRleF9waWM1LmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjog +MHB4OyBMSU5FLUhFSUdIVDogMTlweDsgUEFERElORy1UT1A6IDBweDsgYmFja2dyb3VuZC1vcmln +aW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxlPSIxMi0x +N+iusuWggiDlpKflrabnlJ/ogYzkuJrnlJ/mtq/op4TliJIiIHN0eWxlPSJDT0xPUjogcmdiKDAs +MCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRo +aXMsOTUpOyANCiAgaHJlZj0iaHR0cDovL3N0dWRlbnQuY3Nkbi5uZXQvc3BhY2UucGhwP2RvPW9u +bGluZXJvb20mYW1wO2lkPTIxOSIgDQogIHRhcmdldD1fYmxhbms+MTItMTforrLloIIg5aSn5a2m +55Sf6IGM5Lia55Sf5ravPC9BPjwvREQ+DQogIDxERCBjbGFzcz0ic291cmNlX3N0eSB0eHRfYmxh +Y2siIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBQQURESU5HLUxFRlQ6IDEycHg7IEJB +Q0tHUk9VTkQtSU1BR0U6IG5vbmU7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBD +T0xPUjogcmdiKDAsMCwwKTsgTElORS1IRUlHSFQ6IDE5cHg7IFBBRERJTkctVE9QOiAwcHg7IGJh +Y2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxFTSAN +CiAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBGT05ULVNUWUxFOiBub3JtYWwiPjwvRU0+PC9E +RD4NCiAgPEREIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lU +SU9OOiAycHggN3B4OyBQQURESU5HLUxFRlQ6IDEycHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybCho +dHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWM1LmdpZik7IFBBRERJTkct +Qk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBMSU5FLUhFSUdIVDogMTlweDsgUEFERElORy1UT1A6 +IDBweDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlh +bCI+PEEgDQogIHRpdGxlPSLnrJTorrAgLk5ldOS5i+W8gOa6kOWSjOS4jeW8gOa6kOeahOiDjOWQ +jiIgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBv +bmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw5NSk7IA0KICBocmVmPSJodHRwOi8vc3R1ZGVudC5j +c2RuLm5ldC9saW5rLnBocD91cmw9aHR0cDovL3N0dWRlbnQuY3Nkbi5uZXQlMkZzcGFjZS5waHAl +M0Z1aWQlM0QzOTAxNyUyNmRvJTNEYmxvZyUyNmlkJTNENTIyNjQiIA0KICB0YXJnZXQ9X2JsYW5r +PueslOiusCAuTmV05LmL5byA5rqQ5ZKM5LiN5byA5rqQ55qEPC9BPjwvREQ+DQogIDxERCBjbGFz +cz0ic291cmNlX3N0eSB0eHRfYmxhY2siIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBQ +QURESU5HLUxFRlQ6IDEycHg7IEJBQ0tHUk9VTkQtSU1BR0U6IG5vbmU7IFBBRERJTkctQk9UVE9N +OiAwcHg7IE1BUkdJTjogMHB4OyBDT0xPUjogcmdiKDAsMCwwKTsgTElORS1IRUlHSFQ6IDE5cHg7 +IFBBRERJTkctVE9QOiAwcHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5k +LWNsaXA6IGluaXRpYWwiPjxFTSANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBGT05ULVNU +WUxFOiBub3JtYWwiPjwvRU0+PC9ERD4NCiAgPEREIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDog +MHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAycHggN3B4OyBQQURESU5HLUxFRlQ6IDEycHg7IEJB +Q0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRl +eF9waWM1LmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBMSU5FLUhFSUdI +VDogMTlweDsgUEFERElORy1UT1A6IDBweDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJh +Y2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxlPSLnrJTorrAg5LiA5Lqb5aSn5YWs +5Y+455qE5b+D55CG5rWL6K+V6aKYIiBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVD +T1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDk1KTsgDQogIGhy +ZWY9Imh0dHA6Ly9zdHVkZW50LmNzZG4ubmV0L2xpbmsucGhwP3VybD1odHRwOi8vc3R1ZGVudC5j +c2RuLm5ldCUyRnNwYWNlLnBocCUzRnVpZCUzRDQ0NzIyJTI2ZG8lM0RibG9nJTI2aWQlM0Q1MjI0 +MSIgDQogIHRhcmdldD1fYmxhbms+56yU6K6wIOS4gOS6m+Wkp+WFrOWPuOeahOW/g+eQhua1i+iv +lemimDwvQT48L0REPg0KICA8REQgY2xhc3M9InNvdXJjZV9zdHkgdHh0X2JsYWNrIiANCiAgc3R5 +bGU9IlBBRERJTkctUklHSFQ6IDBweDsgUEFERElORy1MRUZUOiAxMnB4OyBCQUNLR1JPVU5ELUlN +QUdFOiBub25lOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweDsgQ09MT1I6IHJnYigw +LDAsMCk7IExJTkUtSEVJR0hUOiAxOXB4OyBQQURESU5HLVRPUDogMHB4OyBiYWNrZ3JvdW5kLW9y +aWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48RU0gDQogIHN0eWxlPSJD +T0xPUjogcmdiKDAsMCwwKTsgRk9OVC1TVFlMRTogbm9ybWFsIj48L0VNPjwvREQ+DQogIDxERCAN +CiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMnB4IDdw +eDsgUEFERElORy1MRUZUOiAxMnB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5p +bWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljNS5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4 +OyBNQVJHSU46IDBweDsgTElORS1IRUlHSFQ6IDE5cHg7IFBBRERJTkctVE9QOiAwcHg7IGJhY2tn +cm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0 +aXRsZT0i6K++5aCCIOS4i+Wtpuacn+eahOW1jOWFpeW8j+mAieS/ruivvumAieWQpu+8nyIgc3R5 +bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNr +PUxvZ0NsaWNrQ291bnQodGhpcyw5NSk7IA0KICBocmVmPSJodHRwOi8vc3R1ZGVudC5jc2RuLm5l +dC9saW5rLnBocD91cmw9aHR0cDovL3N0dWRlbnQuY3Nkbi5uZXQlMkZzcGFjZS5waHAlM0ZkbyUz +RHRocmVhZCUyNmlkJTNENDEwMjIiIA0KICB0YXJnZXQ9X2JsYW5rPuivvuWggiDkuIvlrabmnJ/n +moTltYzlhaXlvI/pgInkv67or77pgInlkKY8L0E+PC9ERD4NCiAgPEREIGNsYXNzPSJzb3VyY2Vf +c3R5IHR4dF9ibGFjayIgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IFBBRERJTkctTEVG +VDogMTJweDsgQkFDS0dST1VORC1JTUFHRTogbm9uZTsgUEFERElORy1CT1RUT006IDBweDsgTUFS +R0lOOiAwcHg7IENPTE9SOiByZ2IoMCwwLDApOyBMSU5FLUhFSUdIVDogMTlweDsgUEFERElORy1U +T1A6IDBweDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5p +dGlhbCI+PEVNIA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IEZPTlQtU1RZTEU6IG5vcm1h +bCI+PC9FTT48L0REPg0KICA8REQgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tH +Uk9VTkQtUE9TSVRJT046IDJweCA3cHg7IFBBRERJTkctTEVGVDogMTJweDsgQkFDS0dST1VORC1J +TUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzUuZ2lm +KTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IExJTkUtSEVJR0hUOiAxOXB4OyBQ +QURESU5HLVRPUDogMHB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1j +bGlwOiBpbml0aWFsIj48QSANCiAgdGl0bGU9IkphdmHor77loIIg5pWw5o2u5oyW5o6YIiBzdHls +ZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9 +TG9nQ2xpY2tDb3VudCh0aGlzLDk1KTsgDQogIGhyZWY9Imh0dHA6Ly9zdHVkZW50LmNzZG4ubmV0 +L2xpbmsucGhwP3VybD1odHRwOi8vc3R1ZGVudC5jc2RuLm5ldCUyRnNwYWNlLnBocCUzRmRvJTNE +dGhyZWFkJTI2aWQlM0Q0MTAwMCIgDQogIHRhcmdldD1fYmxhbms+SmF2YeivvuWggiDmlbDmja7m +jJbmjpg8L0E+PC9ERD4NCiAgPEREIGNsYXNzPSJzb3VyY2Vfc3R5IHR4dF9ibGFjayIgDQogIHN0 +eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IFBBRERJTkctTEVGVDogMTJweDsgQkFDS0dST1VORC1J +TUFHRTogbm9uZTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IENPTE9SOiByZ2Io +MCwwLDApOyBMSU5FLUhFSUdIVDogMTlweDsgUEFERElORy1UT1A6IDBweDsgYmFja2dyb3VuZC1v +cmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEVNIA0KICBzdHlsZT0i +Q09MT1I6IHJnYigwLDAsMCk7IEZPTlQtU1RZTEU6IG5vcm1hbCI+PC9FTT48L0REPjwvREw+PC9E +SVY+DQo8RElWIGNsYXNzPXNpZGViYXJfY29uIA0Kc3R5bGU9IkRJU1BMQVk6IGlubGluZTsgRkxP +QVQ6IGxlZnQ7IE1BUkdJTjogNnB4IDNweCAycHg7IFdJRFRIOiAyMDJweCI+DQo8SDQgY2xhc3M9 +dHh0XzEyIA0Kc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgUEFERElORy1MRUZUOiAzcHg7IEZP +TlQtU0laRTogMTJweDsgUEFERElORy1CT1RUT006IDVweDsgTUFSR0lOOiAwcHg7IFBBRERJTkct +VE9QOiAwcHg7IEJPUkRFUi1CT1RUT006IHJnYigyMDQsMjA0LDIwNCkgMXB4IHNvbGlkOyBQT1NJ +VElPTjogcmVsYXRpdmUiPjxTUEFOIA0KY2xhc3M9dHh0X2dyYXkgDQpzdHlsZT0iRk9OVC1XRUlH +SFQ6IG5vcm1hbDsgRkxPQVQ6IHJpZ2h0OyBDT0xPUjogcmdiKDEwMiwxMDIsMTAyKSI+PC9TUEFO +PuS6p+WTgeWSjOW3peWFtzwvSDQ+DQo8REwgY2xhc3M9c2Vzc2lvbl9zdHlsZSANCnN0eWxlPSJQ +QURESU5HLVJJR0hUOiAzcHg7IFBBRERJTkctTEVGVDogM3B4OyBGTE9BVDogbGVmdDsgUEFERElO +Ry1CT1RUT006IDVweDsgTUFSR0lOOiAycHggMHB4IDBweDsgV0lEVEg6IDE5NnB4OyBQQURESU5H +LVRPUDogMTBweDsgQk9SREVSLUJPVFRPTTogcmdiKDIwNCwyMDQsMjA0KSAxcHggc29saWQ7IEJB +Q0tHUk9VTkQtQ09MT1I6IHJnYigyNTUsMjU1LDI1NSk7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0 +aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPg0KICA8REQgDQogIHN0eWxlPSJQQURESU5H +LVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDJweCA3cHg7IFBBRERJTkctTEVGVDog +MTJweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMv +Y3NkbmluZGV4X3BpYzUuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IExJ +TkUtSEVJR0hUOiAxOXB4OyBQQURESU5HLVRPUDogMHB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5p +dGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgdGl0bGU9MjAxMOW1jOWFpeW8 +j+ihjOS4muW5tOe7iOebmOeCueiusuW6pyBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQt +REVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDk0KTsgaHJl +Zj0iaHR0cDovL2cuY3Nkbi5uZXQvNTE2NzQ3MCIgDQogIHRhcmdldD1fYmxhbms+MjAxMOW1jOWF +peW8j+ihjOS4muW5tOe7iOebmOeCueiusuW6pzwvQT48L0REPg0KICA8REQgDQogIHN0eWxlPSJQ +QURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDJweCA3cHg7IFBBRERJTkct +TEVGVDogMTJweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9p +bWFnZXMvY3NkbmluZGV4X3BpYzUuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAw +cHg7IExJTkUtSEVJR0hUOiAxOXB4OyBQQURESU5HLVRPUDogMHB4OyBiYWNrZ3JvdW5kLW9yaWdp +bjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgdGl0bGU95Lit6L2v +6ZuG5Zui57uZ5LiO5Lit5qCH6L2v5Lu25YWo6Z2i5pSv5oyBIHN0eWxlPSJDT0xPUjogcmdiKDAs +MCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRo +aXMsOTQpOyBocmVmPSJodHRwOi8vZy5jc2RuLm5ldC81MTEzMzM2IiANCiAgdGFyZ2V0PV9ibGFu +az7kuK3ova/pm4blm6Lnu5nkuI7kuK3moIfova/ku7blhajpnaLmlK/mjIE8L0E+PC9ERD4NCiAg +PEREIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAy +cHggN3B4OyBQQURESU5HLUxFRlQ6IDEycHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8v +Y3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWM1LmdpZik7IFBBRERJTkctQk9UVE9N +OiAwcHg7IE1BUkdJTjogMHB4OyBMSU5FLUhFSUdIVDogMTlweDsgUEFERElORy1UT1A6IDBweDsg +YmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEg +DQogIHRpdGxlPemaj+aXtumaj+WcsOWtpuiLseivre+8n+iLseWtmuaJi+acuuW6lOeUqOadpeW4 +ruS9oCEgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0K +ICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw5NCk7IGhyZWY9Imh0dHA6Ly9nLmNzZG4ubmV0 +LzUxNjY1NDUiIA0KICB0YXJnZXQ9X2JsYW5rPumaj+aXtumaj+WcsOWtpuiLseivre+8n+iLseWt +muaJi+acuuW6lOeUqOadpeW4ruS9oCE8L0E+PC9ERD4NCiAgPEREIA0KICBzdHlsZT0iUEFERElO +Ry1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAycHggN3B4OyBQQURESU5HLUxFRlQ6 +IDEycHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2Vz +L2NzZG5pbmRleF9waWM1LmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBM +SU5FLUhFSUdIVDogMTlweDsgUEFERElORy1UT1A6IDBweDsgYmFja2dyb3VuZC1vcmlnaW46IGlu +aXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxlPUlU6L6+5Lq677ya +5pWZ5L2g546p6L2s5aW95Y6L5Y6L57yp6L2v5Lu2IHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsg +VEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsOTQp +OyBocmVmPSJodHRwOi8vZy5jc2RuLm5ldC81MTU3MzMzIiANCiAgdGFyZ2V0PV9ibGFuaz5JVOi+ +vuS6uu+8muaVmeS9oOeOqei9rOWlveWOi+WOi+e8qei9r+S7tjwvQT48L0REPg0KICA8REQgDQog +IHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDJweCA3cHg7 +IFBBRERJTkctTEVGVDogMTJweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1n +LmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzUuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsg +TUFSR0lOOiAwcHg7IExJTkUtSEVJR0hUOiAxOXB4OyBQQURESU5HLVRPUDogMHB4OyBiYWNrZ3Jv +dW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgdGl0 +bGU95Lq65aSn6YeR5LuT5Yqp5Yqb5Y2r55Sf6KGM5Lia5L+h5oGv5YyWIHN0eWxlPSJDT0xPUjog +cmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0Nv +dW50KHRoaXMsOTQpOyBocmVmPSJodHRwOi8vZy5jc2RuLm5ldC81MTA2MDA4IiANCiAgdGFyZ2V0 +PV9ibGFuaz7kurrlpKfph5Hku5PliqnlipvljavnlJ/ooYzkuJrkv6Hmga/ljJY8L0E+PC9ERD48 +L0RMPjwvRElWPg0KPERJViBjbGFzcz1zaWRlYmFyX2NvbiANCnN0eWxlPSJESVNQTEFZOiBpbmxp +bmU7IEZMT0FUOiBsZWZ0OyBNQVJHSU46IDZweCAzcHggMnB4OyBXSURUSDogMjAycHgiPg0KPEg0 +IGNsYXNzPXR4dF8xMiANCnN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IFBBRERJTkctTEVGVDog +M3B4OyBGT05ULVNJWkU6IDEycHg7IFBBRERJTkctQk9UVE9NOiA1cHg7IE1BUkdJTjogMHB4OyBQ +QURESU5HLVRPUDogMHB4OyBCT1JERVItQk9UVE9NOiByZ2IoMjA0LDIwNCwyMDQpIDFweCBzb2xp +ZDsgUE9TSVRJT046IHJlbGF0aXZlIj48U1BBTiANCmNsYXNzPXR4dF9ncmF5IA0Kc3R5bGU9IkZP +TlQtV0VJR0hUOiBub3JtYWw7IEZMT0FUOiByaWdodDsgQ09MT1I6IHJnYigxMDIsMTAyLDEwMiki +Pnw8QSANCnN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IFBBRERJTkctTEVGVDogNXB4OyBQQURE +SU5HLUJPVFRPTTogMHB4OyBDT0xPUjogcmdiKDEwMiwxMDIsMTAyKTsgUEFERElORy1UT1A6IDBw +eDsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCmhyZWY9Imh0dHA6Ly9wcmouY3Nkbi5uZXQvIiB0 +YXJnZXQ9X2JsYW5rPuabtOWkmjwvQT48L1NQQU4+6aG555uu57K+6YCJPC9IND4NCjxETCBjbGFz +cz1zZXNzaW9uX3N0eWxlIA0Kc3R5bGU9IlBBRERJTkctUklHSFQ6IDNweDsgUEFERElORy1MRUZU +OiAzcHg7IEZMT0FUOiBsZWZ0OyBQQURESU5HLUJPVFRPTTogNXB4OyBNQVJHSU46IDJweCAwcHgg +MHB4OyBXSURUSDogMTk2cHg7IFBBRERJTkctVE9QOiAxMHB4OyBCT1JERVItQk9UVE9NOiByZ2Io +MjA0LDIwNCwyMDQpIDFweCBzb2xpZDsgQkFDS0dST1VORC1DT0xPUjogcmdiKDI1NSwyNTUsMjU1 +KTsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+ +DQogIDxERCANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElP +TjogMnB4IDdweDsgUEFERElORy1MRUZUOiAxMnB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0 +cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljNS5naWYpOyBQQURESU5HLUJP +VFRPTTogMHB4OyBNQVJHSU46IDBweDsgTElORS1IRUlHSFQ6IDE5cHg7IFBBRERJTkctVE9QOiAw +cHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwi +PjwvREQ+DQogIDxERCBjbGFzcz1qaWFuIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBC +QUNLR1JPVU5ELVBPU0lUSU9OOiAwcHggM3B4OyBQQURESU5HLUxFRlQ6IDIxcHg7IEJBQ0tHUk9V +TkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWN0 +ZXh0MDIuZ2lmKTsgUEFERElORy1CT1RUT006IDNweDsgTUFSR0lOOiAwcHg7IExJTkUtSEVJR0hU +OiAxOXB4OyBQQURESU5HLVRPUDogM3B4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFj +a2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgdGl0bGU9IuacuuWZqOinhuiniS3popzoibLl +iIbnsbsgIiBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIg +DQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDk2KTsgDQogIGhyZWY9Imh0dHA6Ly9wcmou +Y3Nkbi5uZXQvcHJvamRldGFpbC5hc3B4P3BvaW50aWQ9MjQ5MjciIA0KICB0YXJnZXQ9X2JsYW5r +PuacuuWZqOinhuiniS3popzoibLliIbnsbs8L0E+PC9ERD4NCiAgPEREIGNsYXNzPWxpYW4gDQog +IHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDBweCAzcHg7 +IFBBRERJTkctTEVGVDogMjFweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1n +LmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpY3RleHQwMS5naWYpOyBQQURESU5HLUJPVFRPTTog +M3B4OyBNQVJHSU46IDBweDsgTElORS1IRUlHSFQ6IDE5cHg7IFBBRERJTkctVE9QOiAzcHg7IGJh +Y2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0K +ICB0aXRsZT0iTVRLIEZMQVNI5pKt5pS+5byV5pOO5byA5Y+RIiBzdHlsZT0iQ09MT1I6IHJnYigw +LDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0 +aGlzLDk2KTsgDQogIGhyZWY9Imh0dHA6Ly9wcmouY3Nkbi5uZXQvcHJvamRldGFpbC5hc3B4P3Bv +aW50aWQ9MjQ3ODgiIHRhcmdldD1fYmxhbms+TVRLIA0KICBGTEFTSOaSreaUvuW8leaTjuW8gOWP +kTwvQT48L0REPg0KICA8REQgY2xhc3M9bGlhbiANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBw +eDsgQkFDS0dST1VORC1QT1NJVElPTjogMHB4IDNweDsgUEFERElORy1MRUZUOiAyMXB4OyBCQUNL +R1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhf +cGljdGV4dDAxLmdpZik7IFBBRERJTkctQk9UVE9NOiAzcHg7IE1BUkdJTjogMHB4OyBMSU5FLUhF +SUdIVDogMTlweDsgUEFERElORy1UT1A6IDNweDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7 +IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxlPSJQREbomZrmi5/miZPljbDm +nLrvvIjpmZDljJfkuqzvvIkgIiBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JB +VElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDk2KTsgDQogIGhyZWY9 +Imh0dHA6Ly9wcmouY3Nkbi5uZXQvcHJvamRldGFpbC5hc3B4P3BvaW50aWQ9MjQ0MDYiIA0KICB0 +YXJnZXQ9X2JsYW5rPlBERuiZmuaLn+aJk+WNsOacuu+8iOmZkOWMl+S6rO+8iTwvQT48L0REPg0K +ICA8REQgY2xhc3M9bGlhbiANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VO +RC1QT1NJVElPTjogMHB4IDNweDsgUEFERElORy1MRUZUOiAyMXB4OyBCQUNLR1JPVU5ELUlNQUdF +OiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljdGV4dDAxLmdp +Zik7IFBBRERJTkctQk9UVE9NOiAzcHg7IE1BUkdJTjogMHB4OyBMSU5FLUhFSUdIVDogMTlweDsg +UEFERElORy1UT1A6IDNweDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQt +Y2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxlPSLlvannpajnvZHnq5nnqIvluo/lhajlpZcgIiBz +dHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xp +Y2s9TG9nQ2xpY2tDb3VudCh0aGlzLDk2KTsgDQogIGhyZWY9Imh0dHA6Ly9wcmouY3Nkbi5uZXQv +cHJvamRldGFpbC5hc3B4P3BvaW50aWQ9MjQ5MzQiIA0KICB0YXJnZXQ9X2JsYW5rPuW9qeelqOe9 +keermeeoi+W6j+WFqOWllzwvQT48L0REPg0KICA8REQgY2xhc3M9amlhbiANCiAgc3R5bGU9IlBB +RERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMHB4IDNweDsgUEFERElORy1M +RUZUOiAyMXB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2lt +YWdlcy9jc2RuaW5kZXhfcGljdGV4dDAyLmdpZik7IFBBRERJTkctQk9UVE9NOiAzcHg7IE1BUkdJ +TjogMHB4OyBMSU5FLUhFSUdIVDogMTlweDsgUEFERElORy1UT1A6IDNweDsgYmFja2dyb3VuZC1v +cmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxlPSJT +VE0zMkYxMDPova/ku7blvIDlj5EgIiBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVD +T1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDk2KTsgDQogIGhy +ZWY9Imh0dHA6Ly9wcmouY3Nkbi5uZXQvcHJvamRldGFpbC5hc3B4P3BvaW50aWQ9MjQ3NjMiIA0K +ICB0YXJnZXQ9X2JsYW5rPlNUTTMyRjEwM+i9r+S7tuW8gOWPkTwvQT48L0REPg0KICA8REQgY2xh +c3M9amlhbiANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElP +TjogMHB4IDNweDsgUEFERElORy1MRUZUOiAyMXB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0 +cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljdGV4dDAyLmdpZik7IFBBRERJ +TkctQk9UVE9NOiAzcHg7IE1BUkdJTjogMHB4OyBMSU5FLUhFSUdIVDogMTlweDsgUEFERElORy1U +T1A6IDNweDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5p +dGlhbCI+PEEgDQogIHRpdGxlPSJhbmRyb2lk5a6i5oi356uv5byA5Y+RICIgc3R5bGU9IkNPTE9S +OiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNr +Q291bnQodGhpcyw5Nik7IA0KICBocmVmPSJodHRwOi8vcHJqLmNzZG4ubmV0L3Byb2pkZXRhaWwu +YXNweD9wb2ludGlkPTI0ODE0IiANCiAgdGFyZ2V0PV9ibGFuaz5hbmRyb2lk5a6i5oi356uv5byA +5Y+RPC9BPjwvREQ+DQogIDxERCBjbGFzcz1qaWFuIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDog +MHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAwcHggM3B4OyBQQURESU5HLUxFRlQ6IDIxcHg7IEJB +Q0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRl +eF9waWN0ZXh0MDIuZ2lmKTsgUEFERElORy1CT1RUT006IDNweDsgTUFSR0lOOiAwcHg7IExJTkUt +SEVJR0hUOiAxOXB4OyBQQURESU5HLVRPUDogM3B4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlh +bDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgdGl0bGU9Iumfs+inhumikeW5v+aS +reaOp+S7tiAiIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25l +IiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsOTYpOyANCiAgaHJlZj0iaHR0cDovL3By +ai5jc2RuLm5ldC9wcm9qZGV0YWlsLmFzcHg/cG9pbnRpZD0yNTAzOCIgDQogIHRhcmdldD1fYmxh +bms+6Z+z6KeG6aKR5bm/5pKt5o6n5Lu2PC9BPjwvREQ+DQogIDxERCBjbGFzcz1saWFuIA0KICBz +dHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAwcHggM3B4OyBQ +QURESU5HLUxFRlQ6IDIxcHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5j +bi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWN0ZXh0MDEuZ2lmKTsgUEFERElORy1CT1RUT006IDNw +eDsgTUFSR0lOOiAwcHg7IExJTkUtSEVJR0hUOiAxOXB4OyBQQURESU5HLVRPUDogM3B4OyBiYWNr +Z3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAg +dGl0bGU9IklN6L2v5Lu26aG555uu5aSW5YyF5byA5Y+RICIgc3R5bGU9IkNPTE9SOiByZ2IoMCww +LDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhp +cyw5Nik7IA0KICBocmVmPSJodHRwOi8vcHJqLmNzZG4ubmV0L3Byb2pkZXRhaWwuYXNweD9wb2lu +dGlkPTI1MTM1IiANCiAgdGFyZ2V0PV9ibGFuaz5JTei9r+S7tumhueebruWkluWMheW8gOWPkTwv +QT48L0REPjwvREw+PC9ESVY+DQo8RElWIGNsYXNzPXNpZGViYXJfY29uIA0Kc3R5bGU9IkRJU1BM +QVk6IGlubGluZTsgRkxPQVQ6IGxlZnQ7IE1BUkdJTjogNnB4IDNweCAycHg7IFdJRFRIOiAyMDJw +eCI+DQo8SDQgY2xhc3M9dHh0XzEyIA0Kc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgUEFERElO +Ry1MRUZUOiAzcHg7IEZPTlQtU0laRTogMTJweDsgUEFERElORy1CT1RUT006IDVweDsgTUFSR0lO +OiAwcHg7IFBBRERJTkctVE9QOiAwcHg7IEJPUkRFUi1CT1RUT006IHJnYigyMDQsMjA0LDIwNCkg +MXB4IHNvbGlkOyBQT1NJVElPTjogcmVsYXRpdmUiPjxTUEFOIA0KY2xhc3M9dHh0X2dyYXkgDQpz +dHlsZT0iRk9OVC1XRUlHSFQ6IG5vcm1hbDsgRkxPQVQ6IHJpZ2h0OyBDT0xPUjogcmdiKDEwMiwx +MDIsMTAyKSI+fDxBIA0Kc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgUEFERElORy1MRUZUOiA1 +cHg7IFBBRERJTkctQk9UVE9NOiAwcHg7IENPTE9SOiByZ2IoMTAyLDEwMiwxMDIpOyBQQURESU5H +LVRPUDogMHB4OyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KaHJlZj0iaHR0cDovL2Rvd25sb2Fk +LmNzZG4ubmV0LyIgdGFyZ2V0PV9ibGFuaz7mm7TlpJo8L0E+PC9TUEFOPui1hOa6kOeyvumAiTwv +SDQ+DQo8REwgY2xhc3M9c2Vzc2lvbl9zdHlsZSANCnN0eWxlPSJQQURESU5HLVJJR0hUOiAzcHg7 +IFBBRERJTkctTEVGVDogM3B4OyBGTE9BVDogbGVmdDsgUEFERElORy1CT1RUT006IDVweDsgTUFS +R0lOOiAycHggMHB4IDBweDsgV0lEVEg6IDE5NnB4OyBQQURESU5HLVRPUDogMTBweDsgQk9SREVS +LUJPVFRPTTogcmdiKDIwNCwyMDQsMjA0KSAxcHggc29saWQ7IEJBQ0tHUk9VTkQtQ09MT1I6IHJn +YigyNTUsMjU1LDI1NSk7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNs +aXA6IGluaXRpYWwiPg0KICA8REQgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tH +Uk9VTkQtUE9TSVRJT046IDJweCA3cHg7IFBBRERJTkctTEVGVDogMTJweDsgQkFDS0dST1VORC1J +TUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzUuZ2lm +KTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IExJTkUtSEVJR0hUOiAxOXB4OyBQ +QURESU5HLVRPUDogMHB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1j +bGlwOiBpbml0aWFsIj48QSANCiAgdGl0bGU9Q+ivreiogOaVsOaNrue7k+aehOWfuuacrOaTjeS9 +nCBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9u +Y2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDEwMyk7IA0KICBocmVmPSJodHRwOi8vZG93bmxvYWQu +Y3Nkbi5uZXQvc291cmNlLzI5MDc4MTMiIA0KICB0YXJnZXQ9X2JsYW5rPkPor63oqIDmlbDmja7n +u5PmnoTln7rmnKzmk43kvZw8L0E+PC9ERD4NCiAgPEREIGNsYXNzPSJzb3VyY2Vfc3R5IHR4dF9i +bGFjayIgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IFBBRERJTkctTEVGVDogMTJweDsg +QkFDS0dST1VORC1JTUFHRTogbm9uZTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7 +IENPTE9SOiByZ2IoMCwwLDApOyBMSU5FLUhFSUdIVDogMTlweDsgUEFERElORy1UT1A6IDBweDsg +YmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEVN +IA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IEZPTlQtU1RZTEU6IG5vcm1hbCI+cnVieTEz +MTTkuIrkvKA8L0VNPjxBIA0KICBzdHlsZT0iTUFSR0lOOiAwcHggMHB4IDBweCAxNXB4OyBDT0xP +UjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlj +a0NvdW50KHRoaXMsMTAzKTsgDQpocmVmPSJodHRwOi8vZG93bmxvYWQuY3Nkbi5uZXQvIj7miJHo +poHkuIrkvKA8L0E+PC9ERD4NCiAgPEREIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBC +QUNLR1JPVU5ELVBPU0lUSU9OOiAycHggN3B4OyBQQURESU5HLUxFRlQ6IDEycHg7IEJBQ0tHUk9V +TkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWM1 +LmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBMSU5FLUhFSUdIVDogMTlw +eDsgUEFERElORy1UT1A6IDBweDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91 +bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxlPSLlrabnlJ/kvZzkuJrnrqHnkIbns7vnu58g +SlNQIiBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQog +IG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDEwMyk7IA0KICBocmVmPSJodHRwOi8vZG93bmxv +YWQuY3Nkbi5uZXQvc291cmNlLzI5MDc3NzIiIHRhcmdldD1fYmxhbms+5a2m55Sf5L2c5Lia566h +55CG57O757ufIA0KICBKU1A8L0E+PC9ERD4NCiAgPEREIGNsYXNzPSJzb3VyY2Vfc3R5IHR4dF9i +bGFjayIgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IFBBRERJTkctTEVGVDogMTJweDsg +QkFDS0dST1VORC1JTUFHRTogbm9uZTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7 +IENPTE9SOiByZ2IoMCwwLDApOyBMSU5FLUhFSUdIVDogMTlweDsgUEFERElORy1UT1A6IDBweDsg +YmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEVN +IA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IEZPTlQtU1RZTEU6IG5vcm1hbCI+ZmVuZ3lh +bGluZ2ZseXl55LiK5LygPC9FTT48QSANCiAgc3R5bGU9Ik1BUkdJTjogMHB4IDBweCAwcHggMTVw +eDsgQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9 +TG9nQ2xpY2tDb3VudCh0aGlzLDEwMyk7IA0KaHJlZj0iaHR0cDovL2Rvd25sb2FkLmNzZG4ubmV0 +LyI+5oiR6KaB5LiK5LygPC9BPjwvREQ+DQogIDxERCANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6 +IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMnB4IDdweDsgUEFERElORy1MRUZUOiAxMnB4OyBC +QUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5k +ZXhfcGljNS5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweDsgTElORS1IRUlH +SFQ6IDE5cHg7IFBBRERJTkctVE9QOiAwcHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBi +YWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0aXRsZT1jKyvnvJbnqIvluLjpgYfpl67p +opjmgLvnu5Mgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUi +IA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcywxMDMpOyANCiAgaHJlZj0iaHR0cDovL2Rv +d25sb2FkLmNzZG4ubmV0L3NvdXJjZS8yOTA3NTk2IiANCiAgdGFyZ2V0PV9ibGFuaz5jKyvnvJbn +qIvluLjpgYfpl67popjmgLvnu5M8L0E+PC9ERD4NCiAgPEREIGNsYXNzPSJzb3VyY2Vfc3R5IHR4 +dF9ibGFjayIgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IFBBRERJTkctTEVGVDogMTJw +eDsgQkFDS0dST1VORC1JTUFHRTogbm9uZTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAw +cHg7IENPTE9SOiByZ2IoMCwwLDApOyBMSU5FLUhFSUdIVDogMTlweDsgUEFERElORy1UT1A6IDBw +eDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+ +PEVNIA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IEZPTlQtU1RZTEU6IG5vcm1hbCI+Ynly +Z2w15LiK5LygPC9FTT48QSANCiAgc3R5bGU9Ik1BUkdJTjogMHB4IDBweCAwcHggMTVweDsgQ09M +T1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xp +Y2tDb3VudCh0aGlzLDEwMyk7IA0KaHJlZj0iaHR0cDovL2Rvd25sb2FkLmNzZG4ubmV0LyI+5oiR +6KaB5LiK5LygPC9BPjwvREQ+DQogIDxERCANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsg +QkFDS0dST1VORC1QT1NJVElPTjogMnB4IDdweDsgUEFERElORy1MRUZUOiAxMnB4OyBCQUNLR1JP +VU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGlj +NS5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweDsgTElORS1IRUlHSFQ6IDE5 +cHg7IFBBRERJTkctVE9QOiAwcHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3Jv +dW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0aXRsZT0iQyMg5a+85Ye6ZXhjZWwg5a6e5L6L5Luj +56CBIiBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQog +IG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDEwMyk7IA0KICBocmVmPSJodHRwOi8vZG93bmxv +YWQuY3Nkbi5uZXQvc291cmNlLzI5MDc0OTAiIHRhcmdldD1fYmxhbms+QyMg5a+85Ye6ZXhjZWwg +DQogIOWunuS+i+S7o+eggTwvQT48L0REPg0KICA8REQgY2xhc3M9InNvdXJjZV9zdHkgdHh0X2Js +YWNrIiANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgUEFERElORy1MRUZUOiAxMnB4OyBC +QUNLR1JPVU5ELUlNQUdFOiBub25lOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweDsg +Q09MT1I6IHJnYigwLDAsMCk7IExJTkUtSEVJR0hUOiAxOXB4OyBQQURESU5HLVRPUDogMHB4OyBi +YWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48RU0g +DQogIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgRk9OVC1TVFlMRTogbm9ybWFsIj5vdV95YW5n +cGVuZ2ZlaeS4iuS8oDwvRU0+PEEgDQogIHN0eWxlPSJNQVJHSU46IDBweCAwcHggMHB4IDE1cHg7 +IENPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxv +Z0NsaWNrQ291bnQodGhpcywxMDMpOyANCmhyZWY9Imh0dHA6Ly9kb3dubG9hZC5jc2RuLm5ldC8i +PuaIkeimgeS4iuS8oDwvQT48L0REPg0KICA8REQgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAw +cHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDJweCA3cHg7IFBBRERJTkctTEVGVDogMTJweDsgQkFD +S0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4 +X3BpYzUuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IExJTkUtSEVJR0hU +OiAxOXB4OyBQQURESU5HLVRPUDogMHB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFj +a2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgdGl0bGU9dmLoh6rliqjmjpLniYjnlJ/miJBX +b3JkIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAg +b25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsMTAzKTsgDQogIGhyZWY9Imh0dHA6Ly9kb3dubG9h +ZC5jc2RuLm5ldC9zb3VyY2UvMjkwNzAxMSIgDQogIHRhcmdldD1fYmxhbms+dmLoh6rliqjmjpLn +iYjnlJ/miJBXb3JkPC9BPjwvREQ+DQogIDxERCBjbGFzcz0ic291cmNlX3N0eSB0eHRfYmxhY2si +IA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBQQURESU5HLUxFRlQ6IDEycHg7IEJBQ0tH +Uk9VTkQtSU1BR0U6IG5vbmU7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBDT0xP +UjogcmdiKDAsMCwwKTsgTElORS1IRUlHSFQ6IDE5cHg7IFBBRERJTkctVE9QOiAwcHg7IGJhY2tn +cm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxFTSANCiAg +c3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBGT05ULVNUWUxFOiBub3JtYWwiPnRpMTI25LiK5Lyg +PC9FTT48QSANCiAgc3R5bGU9Ik1BUkdJTjogMHB4IDBweCAwcHggMTVweDsgQ09MT1I6IHJnYigw +LDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0 +aGlzLDEwMyk7IA0KaHJlZj0iaHR0cDovL2Rvd25sb2FkLmNzZG4ubmV0LyI+5oiR6KaB5LiK5Lyg +PC9BPjwvREQ+PC9ETD48L0RJVj48L0RJVj4NCjxESVYgY2xhc3M9cGFnZWJsb2NrMl93cmFwIHN0 +eWxlPSJGTE9BVDogbGVmdDsgV0lEVEg6IDczNXB4Ij4NCjxESVYgY2xhc3M9cGFnZWNvbl9sYXll +cjJfbGVmdCANCnN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IERJU1BMQVk6IGlubGluZTsgUEFE +RElORy1MRUZUOiAwcHg7IEZMT0FUOiBsZWZ0OyBQQURESU5HLUJPVFRPTTogNXB4OyBNQVJHSU46 +IDBweCAwcHggMHB4IDFweDsgV0lEVEg6IDQ3MHB4OyBQQURESU5HLVRPUDogMHB4Ij4NCjxINiAN +CnN0eWxlPSJDTEVBUjogYm90aDsgUEFERElORy1SSUdIVDogMHB4OyBCT1JERVItVE9QOiByZ2Io +MjA0LDIwNCwyMDQpIDFweCBzb2xpZDsgUEFERElORy1MRUZUOiAxMHB4OyBGT05ULVNJWkU6IDE0 +cHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2Nz +ZG5pbmRleF9waWMxMS5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweDsgUEFE +RElORy1UT1A6IDVweDsgUE9TSVRJT046IHJlbGF0aXZlOyBIRUlHSFQ6IDI5cHg7IGJhY2tncm91 +bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPuWNmuWuoueyvumA +iTxTUEFOIA0KY2xhc3M9dHh0X2JsYWNrIA0Kc3R5bGU9IkZPTlQtV0VJR0hUOiBub3JtYWw7IEZP +TlQtU0laRTogMTJweDsgTUFSR0lOOiAwcHggMHB4IDBweCAxNXB4OyBDT0xPUjogcmdiKDAsMCww +KSI+PFNQQU4gDQpjbGFzcz1BcHBsZS1jb252ZXJ0ZWQtc3BhY2U+Jm5ic3A7PC9TUEFOPjxBIHRp +dGxlPeOAkOaOqOiNkOOAkeWkqee/vOaVmeS9oOenu+WKqOW6lOeUqOiQpeWIqeS5i+mBkyANCnN0 +eWxlPSJQQURESU5HLVJJR0hUOiAzcHg7IFBBRERJTkctTEVGVDogM3B4OyBQQURESU5HLUJPVFRP +TTogMHB4OyBDT0xPUjogcmdiKDAsMCwwKTsgUEFERElORy1UT1A6IDBweDsgVEVYVC1ERUNPUkFU +SU9OOiBub25lIiANCmhyZWY9Imh0dHA6Ly9nLmNzZG4ubmV0LzUxNjU2OTYiIHRhcmdldD1fYmxh +bms+44CQ5o6o6I2Q44CR5aSp57+85pWZ5L2g56e75Yqo5bqU55So6JCl5Yip5LmL6YGTPC9BPjwv +U1BBTj48RU0gDQpjbGFzcz10eHRfYmx1ZSANCnN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJB +Q0tHUk9VTkQtUE9TSVRJT046IDBweCA0cHg7IFBBRERJTkctTEVGVDogMTBweDsgRk9OVC1XRUlH +SFQ6IG5vcm1hbDsgRk9OVC1TSVpFOiAxMnB4OyBMRUZUOiA0MTBweDsgQkFDS0dST1VORC1JTUFH +RTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzEyLmdpZik7 +IFBBRERJTkctQk9UVE9NOiAwcHg7IENPTE9SOiByZ2IoMSw5NSwxODIpOyBQQURESU5HLVRPUDog +MHB4OyBGT05ULVNUWUxFOiBub3JtYWw7IFBPU0lUSU9OOiBhYnNvbHV0ZTsgVE9QOiA2cHg7IGJh +Y2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0K +c3R5bGU9IlBBRERJTkctUklHSFQ6IDNweDsgUEFERElORy1MRUZUOiAzcHg7IFBBRERJTkctQk9U +VE9NOiAwcHg7IENPTE9SOiByZ2IoMSw5NSwxODIpOyBQQURESU5HLVRPUDogMHB4OyBURVhULURF +Q09SQVRJT046IHVuZGVybGluZSIgDQpocmVmPSJodHRwOi8vYmxvZy5jc2RuLm5ldC8iIHRhcmdl +dD1fYmxhbms+5pu05aSaPC9BPjwvRU0+PC9INj4NCjxESVYgY2xhc3M9cGFnZWNvbl9sYXllcjJf +bGVmdGNvbiANCnN0eWxlPSJQQURESU5HLVJJR0hUOiAxMHB4OyBQQURESU5HLUxFRlQ6IDEwcHg7 +IEZMT0FUOiBsZWZ0OyBQQURESU5HLUJPVFRPTTogNXB4OyBXSURUSDogNDUwcHg7IFBBRERJTkct +VE9QOiA1cHgiPg0KPERMIA0Kc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgUEFERElORy1MRUZU +OiAwcHg7IFBBRERJTkctQk9UVE9NOiAycHg7IE1BUkdJTjogM3B4IDBweDsgTElORS1IRUlHSFQ6 +IDIxcHg7IFBBRERJTkctVE9QOiAwcHg7IFBPU0lUSU9OOiByZWxhdGl2ZSI+DQogIDxEVCBjbGFz +cz10eHRfYmxhY2sgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9T +SVRJT046IDBweCA4cHg7IFBBRERJTkctTEVGVDogMTBweDsgRk9OVC1TSVpFOiAxNHB4OyBCQUNL +R1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhf +cGljMjYuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAzcHggMHB4OyBDT0xPUjog +cmdiKDAsMCwwKTsgUEFERElORy1UT1A6IDBweDsgUE9TSVRJT046IHJlbGF0aXZlOyBiYWNrZ3Jv +dW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48Q0lURSANCiAg +Y2xhc3M9InR4dF9ibHVlIHR4dF8xMiIgDQogIHN0eWxlPSJGT05ULVNJWkU6IDEycHg7IEZMT0FU +OiByaWdodDsgQ09MT1I6IHJnYigxLDk1LDE4Mik7IEZPTlQtU1RZTEU6IG5vcm1hbCI+PEEgDQog +IHN0eWxlPSJDT0xPUjogcmdiKDEsOTUsMTgyKTsgVEVYVC1ERUNPUkFUSU9OOiB1bmRlcmxpbmUi +IA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw3OSk7IGhyZWY9Imh0dHA6Ly9ibG9nLmNz +ZG4ubmV0L3Nvc29fYmxvZyIgDQogIHRhcmdldD1fYmxhbms+c29zb19ibG9nPC9BPjwvQ0lURT48 +QSB0aXRsZT3liKvorqnlpojlpojnlJ/msJTigJTigJTmtYXosIjplb/ogIXnlKjmiLcgDQogIHN0 +eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGlj +az1Mb2dDbGlja0NvdW50KHRoaXMsNzkpOyANCiAgaHJlZj0iaHR0cDovL2Jsb2cuY3Nkbi5uZXQv +c29zb19ibG9nL2FyY2hpdmUvMjAxMC8xMi8xNC82MDc1MDQ0LmFzcHgiIA0KICB0YXJnZXQ9X2Js +YW5rPuWIq+iuqeWmiOWmiOeUn+awlOKAlOKAlOa1heiwiOmVv+iAheeUqOaItzwvQT48L0RUPg0K +ICA8RFQgY2xhc3M9dHh0X2JsYWNrIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNL +R1JPVU5ELVBPU0lUSU9OOiAwcHggOHB4OyBQQURESU5HLUxFRlQ6IDEwcHg7IEZPTlQtU0laRTog +MTRweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMv +Y3NkbmluZGV4X3BpYzI2LmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogM3B4IDBw +eDsgQ09MT1I6IHJnYigwLDAsMCk7IFBBRERJTkctVE9QOiAwcHg7IFBPU0lUSU9OOiByZWxhdGl2 +ZTsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+ +PENJVEUgDQogIGNsYXNzPSJ0eHRfYmx1ZSB0eHRfMTIiIA0KICBzdHlsZT0iRk9OVC1TSVpFOiAx +MnB4OyBGTE9BVDogcmlnaHQ7IENPTE9SOiByZ2IoMSw5NSwxODIpOyBGT05ULVNUWUxFOiBub3Jt +YWwiPjxBIA0KICBzdHlsZT0iQ09MT1I6IHJnYigxLDk1LDE4Mik7IFRFWFQtREVDT1JBVElPTjog +dW5kZXJsaW5lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsNzkpOyBocmVmPSJodHRw +Oi8vYmxvZy5jc2RuLm5ldC9Mb2FkZW4iIA0KICB0YXJnZXQ9X2JsYW5rPuiAgemCkzwvQT48L0NJ +VEU+PEEgdGl0bGU95Lmx6K+ER1VJ5byA5Y+R5qGG5p625pyq5p2l6LWw5ZCRIA0KICBzdHlsZT0i +Q09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9n +Q2xpY2tDb3VudCh0aGlzLDc5KTsgDQogIGhyZWY9Imh0dHA6Ly9ibG9nLmNzZG4ubmV0L0xvYWRl +bi9hcmNoaXZlLzIwMTAvMTIvMTEvNjA2OTg0Mi5hc3B4IiANCiAgdGFyZ2V0PV9ibGFuaz7kubHo +r4RHVUnlvIDlj5HmoYbmnrbmnKrmnaXotbDlkJE8L0E+PC9EVD4NCiAgPERUIGNsYXNzPXR4dF9i +bGFjayANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjog +MHB4IDhweDsgUEFERElORy1MRUZUOiAxMHB4OyBGT05ULVNJWkU6IDE0cHg7IEJBQ0tHUk9VTkQt +SU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMyNi5n +aWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDNweCAwcHg7IENPTE9SOiByZ2IoMCww +LDApOyBQQURESU5HLVRPUDogMHB4OyBQT1NJVElPTjogcmVsYXRpdmU7IGJhY2tncm91bmQtb3Jp +Z2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxDSVRFIA0KICBjbGFzcz0i +dHh0X2JsdWUgdHh0XzEyIiANCiAgc3R5bGU9IkZPTlQtU0laRTogMTJweDsgRkxPQVQ6IHJpZ2h0 +OyBDT0xPUjogcmdiKDEsOTUsMTgyKTsgRk9OVC1TVFlMRTogbm9ybWFsIj48QSANCiAgc3R5bGU9 +IkNPTE9SOiByZ2IoMSw5NSwxODIpOyBURVhULURFQ09SQVRJT046IHVuZGVybGluZSIgDQogIG9u +Y2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDc5KTsgaHJlZj0iaHR0cDovL2Jsb2cuY3Nkbi5uZXQv +Y2hnYW93ZWkiIA0KICB0YXJnZXQ9X2JsYW5rPuW4uOmrmOS8nzwvQT48L0NJVEU+PEEgdGl0bGU9 +5YGaSVTmg7PkuI3liqDnj63nnJ/nmoTlvojpmr4gDQogIHN0eWxlPSJDT0xPUjogcmdiKDAsMCww +KTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMs +NzkpOyANCiAgaHJlZj0iaHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2hnYW93ZWkvYXJjaGl2ZS8yMDEw +LzEyLzA4LzYwNjQyMDAuYXNweCIgDQogIHRhcmdldD1fYmxhbms+5YGaSVTmg7PkuI3liqDnj63n +nJ/nmoTlvojpmr48L0E+PC9EVD4NCiAgPERUIGNsYXNzPXR4dF9ibGFjayANCiAgc3R5bGU9IlBB +RERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMHB4IDhweDsgUEFERElORy1M +RUZUOiAxMHB4OyBGT05ULVNJWkU6IDE0cHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8v +Y3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMyNi5naWYpOyBQQURESU5HLUJPVFRP +TTogMHB4OyBNQVJHSU46IDNweCAwcHg7IENPTE9SOiByZ2IoMCwwLDApOyBQQURESU5HLVRPUDog +MHB4OyBQT1NJVElPTjogcmVsYXRpdmU7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNr +Z3JvdW5kLWNsaXA6IGluaXRpYWwiPjxDSVRFIA0KICBjbGFzcz0idHh0X2JsdWUgdHh0XzEyIiAN +CiAgc3R5bGU9IkZPTlQtU0laRTogMTJweDsgRkxPQVQ6IHJpZ2h0OyBDT0xPUjogcmdiKDEsOTUs +MTgyKTsgRk9OVC1TVFlMRTogbm9ybWFsIj48QSANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMSw5NSwx +ODIpOyBURVhULURFQ09SQVRJT046IHVuZGVybGluZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3Vu +dCh0aGlzLDc5KTsgaHJlZj0iaHR0cDovL2Jsb2cuY3Nkbi5uZXQvd21ub3RoaW5nIiANCiAgdGFy +Z2V0PV9ibGFuaz7lkLTmsJE8L0E+PC9DSVRFPjxBIHRpdGxlPeS8geS4muaWh+WMluS4juKAnOmF +seayueWFmuKAnSANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046 +IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw3OSk7IA0KICBocmVmPSJodHRw +Oi8vYmxvZy5jc2RuLm5ldC93bW5vdGhpbmcvYXJjaGl2ZS8yMDEwLzEyLzA5LzYwNjU5MzguYXNw +eCIgDQogIHRhcmdldD1fYmxhbms+5LyB5Lia5paH5YyW5LiO4oCc6YWx5rK55YWa4oCdPC9BPjwv +RFQ+DQogIDxEVCBjbGFzcz10eHRfYmxhY2sgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7 +IEJBQ0tHUk9VTkQtUE9TSVRJT046IDBweCA4cHg7IFBBRERJTkctTEVGVDogMTBweDsgRk9OVC1T +SVpFOiAxNHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2lt +YWdlcy9jc2RuaW5kZXhfcGljMjYuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAz +cHggMHB4OyBDT0xPUjogcmdiKDAsMCwwKTsgUEFERElORy1UT1A6IDBweDsgUE9TSVRJT046IHJl +bGF0aXZlOyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0 +aWFsIj48Q0lURSANCiAgY2xhc3M9InR4dF9ibHVlIHR4dF8xMiIgDQogIHN0eWxlPSJGT05ULVNJ +WkU6IDEycHg7IEZMT0FUOiByaWdodDsgQ09MT1I6IHJnYigxLDk1LDE4Mik7IEZPTlQtU1RZTEU6 +IG5vcm1hbCI+PEEgDQogIHN0eWxlPSJDT0xPUjogcmdiKDEsOTUsMTgyKTsgVEVYVC1ERUNPUkFU +SU9OOiB1bmRlcmxpbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw3OSk7IGhyZWY9 +Imh0dHA6Ly9oaS5jc2RuLm5ldC9ETDg4MjUwL3Byb2ZpbGUiIA0KICB0YXJnZXQ9X2JsYW5rPuS4 +geS6rjwvQT48L0NJVEU+PEEgdGl0bGU9Ik5ldEJlYW5zIOaXtuS6i+mAmuiur++8iOWIiuWPtyAj +IDEyOSAtIERlYyAxNCwgMjAxMO+8iSIgDQogIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVY +VC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsNzkpOyAN +CiAgaHJlZj0iaHR0cDovL2Jsb2cuY3Nkbi5uZXQvREw4ODI1MC9hcmNoaXZlLzIwMTAvMTIvMTQv +NjA3NjU2My5hc3B4IiANCiAgdGFyZ2V0PV9ibGFuaz5OZXRCZWFucyDml7bkuovpgJrorq/vvIjl +iIrlj7cgIyAxMjkgLSBEZWMgMTQsIDIwMTDvvIk8L0E+PC9EVD4NCiAgPERUIGNsYXNzPXR4dF9i +bGFjayANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjog +MHB4IDhweDsgUEFERElORy1MRUZUOiAxMHB4OyBGT05ULVNJWkU6IDE0cHg7IEJBQ0tHUk9VTkQt +SU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMyNi5n +aWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDNweCAwcHg7IENPTE9SOiByZ2IoMCww +LDApOyBQQURESU5HLVRPUDogMHB4OyBQT1NJVElPTjogcmVsYXRpdmU7IGJhY2tncm91bmQtb3Jp +Z2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxDSVRFIA0KICBjbGFzcz0i +dHh0X2JsdWUgdHh0XzEyIiANCiAgc3R5bGU9IkZPTlQtU0laRTogMTJweDsgRkxPQVQ6IHJpZ2h0 +OyBDT0xPUjogcmdiKDEsOTUsMTgyKTsgRk9OVC1TVFlMRTogbm9ybWFsIj48QSANCiAgc3R5bGU9 +IkNPTE9SOiByZ2IoMSw5NSwxODIpOyBURVhULURFQ09SQVRJT046IHVuZGVybGluZSIgDQogIG9u +Y2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDc5KTsgaHJlZj0iaHR0cDovL2hpLmNzZG4ubmV0L3dv +bmRlcjQvcHJvZmlsZSIgDQogIHRhcmdldD1fYmxhbms+6b2Q55CoPC9BPjwvQ0lURT48QSANCiAg +dGl0bGU9Ik9yYWNsZSBPcGVuIFdvcmxk44CBSmF2YU9uZeOAgU9yYWNsZSBEZXZlbG9wZXIg56ys +5LqM5pelIiANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5v +bmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw3OSk7IA0KICBocmVmPSJodHRwOi8v +YmxvZy5jc2RuLm5ldC93b25kZXI0L2FyY2hpdmUvMjAxMC8xMi8xNC82MDc2MTg4LmFzcHgiIA0K +ICB0YXJnZXQ9X2JsYW5rPk9yYWNsZSBPcGVuIFdvcmxk44CBSmF2YU9uZeOAgU9yYWNsZSBEZXZl +bG9wZXIg56ys5LqM5pelPC9BPjwvRFQ+DQogIDxEVCBjbGFzcz10eHRfYmxhY2sgDQogIHN0eWxl +PSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDBweCA4cHg7IFBBRERJ +TkctTEVGVDogMTBweDsgRk9OVC1TSVpFOiAxNHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0 +cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMjYuZ2lmKTsgUEFERElORy1C +T1RUT006IDBweDsgTUFSR0lOOiAzcHggMHB4OyBDT0xPUjogcmdiKDAsMCwwKTsgUEFERElORy1U +T1A6IDBweDsgUE9TSVRJT046IHJlbGF0aXZlOyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsg +YmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48Q0lURSANCiAgY2xhc3M9InR4dF9ibHVlIHR4dF8x +MiIgDQogIHN0eWxlPSJGT05ULVNJWkU6IDEycHg7IEZMT0FUOiByaWdodDsgQ09MT1I6IHJnYigx +LDk1LDE4Mik7IEZPTlQtU1RZTEU6IG5vcm1hbCI+PEEgDQogIHN0eWxlPSJDT0xPUjogcmdiKDEs +OTUsMTgyKTsgVEVYVC1ERUNPUkFUSU9OOiB1bmRlcmxpbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNr +Q291bnQodGhpcyw3OSk7IGhyZWY9Imh0dHA6Ly9oaS5jc2RuLm5ldC9oZWxsb2d2L3Byb2ZpbGUi +IA0KICB0YXJnZXQ9X2JsYW5rPuW8oOWbveWogTwvQT48L0NJVEU+PEEgdGl0bGU9IiBBbmRyb2lk +5o+Q6auY56ys5Y2B5LqU56+H5LmLTGlzdFZpZXfoh6rpgILlupTlrp7njrDooajmoLwiIA0KICBz +dHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xp +Y2s9TG9nQ2xpY2tDb3VudCh0aGlzLDc5KTsgDQogIGhyZWY9Imh0dHA6Ly9ibG9nLmNzZG4ubmV0 +L2hlbGxvZ3YvYXJjaGl2ZS8yMDEwLzEyLzE0LzYwNzUwMTQuYXNweCIgDQogIHRhcmdldD1fYmxh +bms+QW5kcm9pZOaPkOmrmOesrOWNgeS6lOevh+S5i0xpc3RWaWV36Ieq6YCC5bqU5a6e546w6KGo +5qC8PC9BPjwvRFQ+DQogIDxEVCBjbGFzcz10eHRfYmxhY2sgDQogIHN0eWxlPSJQQURESU5HLVJJ +R0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDBweCA4cHg7IFBBRERJTkctTEVGVDogMTBw +eDsgRk9OVC1TSVpFOiAxNHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcu +Y24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMjYuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsg +TUFSR0lOOiAzcHggMHB4OyBDT0xPUjogcmdiKDAsMCwwKTsgUEFERElORy1UT1A6IDBweDsgUE9T +SVRJT046IHJlbGF0aXZlOyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1j +bGlwOiBpbml0aWFsIj48Q0lURSANCiAgY2xhc3M9InR4dF9ibHVlIHR4dF8xMiIgDQogIHN0eWxl +PSJGT05ULVNJWkU6IDEycHg7IEZMT0FUOiByaWdodDsgQ09MT1I6IHJnYigxLDk1LDE4Mik7IEZP +TlQtU1RZTEU6IG5vcm1hbCI+PEEgDQogIHN0eWxlPSJDT0xPUjogcmdiKDEsOTUsMTgyKTsgVEVY +VC1ERUNPUkFUSU9OOiB1bmRlcmxpbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw3 +OSk7IGhyZWY9Imh0dHA6Ly9oaS5jc2RuLm5ldC9jbGV2ZXIxMDEvcHJvZmlsZSIgDQogIHRhcmdl +dD1fYmxhbms+5pyx6YeR54G/PC9BPjwvQ0lURT48QSB0aXRsZT3ln7rkuo7lr7nor53moYbnmoTn +roDljZXlj4znvJPlhrLnu5jlm77moYbmnrYgDQogIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsg +VEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsNzkp +OyANCiAgaHJlZj0iaHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2xldmVyMTAxL2FyY2hpdmUvMjAxMC8x +Mi8xMy82MDczNzkxLmFzcHgiIA0KICB0YXJnZXQ9X2JsYW5rPuWfuuS6juWvueivneahhueahOeu +gOWNleWPjOe8k+WGsue7mOWbvuahhuaetjwvQT48L0RUPg0KICA8RFQgY2xhc3M9dHh0X2JsYWNr +IA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAwcHgg +OHB4OyBQQURESU5HLUxFRlQ6IDEwcHg7IEZPTlQtU0laRTogMTRweDsgQkFDS0dST1VORC1JTUFH +RTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzI2LmdpZik7 +IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogM3B4IDBweDsgQ09MT1I6IHJnYigwLDAsMCk7 +IFBBRERJTkctVE9QOiAwcHg7IFBPU0lUSU9OOiByZWxhdGl2ZTsgYmFja2dyb3VuZC1vcmlnaW46 +IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PENJVEUgDQogIGNsYXNzPSJ0eHRf +Ymx1ZSB0eHRfMTIiIA0KICBzdHlsZT0iRk9OVC1TSVpFOiAxMnB4OyBGTE9BVDogcmlnaHQ7IENP +TE9SOiByZ2IoMSw5NSwxODIpOyBGT05ULVNUWUxFOiBub3JtYWwiPjxBIA0KICBzdHlsZT0iQ09M +T1I6IHJnYigxLDk1LDE4Mik7IFRFWFQtREVDT1JBVElPTjogdW5kZXJsaW5lIiANCiAgb25jbGlj +az1Mb2dDbGlja0NvdW50KHRoaXMsNzkpOyBocmVmPSJodHRwOi8vaGkuY3Nkbi5uZXQvYXhtYW4v +cHJvZmlsZSIgDQogIHRhcmdldD1fYmxhbms+546L55G+5Y2OPC9BPjwvQ0lURT48QSB0aXRsZT1T +eW1iaWFuXjPnjq/looPlronoo4XmiYvorrAgDQogIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsg +VEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsNzkp +OyANCiAgaHJlZj0iaHR0cDovL2Jsb2cuY3Nkbi5uZXQvYXhtYW4vYXJjaGl2ZS8yMDEwLzEyLzAy +LzYwNTEyMzUuYXNweCIgDQogIHRhcmdldD1fYmxhbms+U3ltYmlhbl4z546v5aKD5a6J6KOF5omL +6K6wPC9BPjwvRFQ+DQogIDxERCBjbGFzcz1uZXdzX3R5cGVhcyANCiAgc3R5bGU9IlBBRERJTkct +UklHSFQ6IDBweDsgUEFERElORy1MRUZUOiAwcHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRw +Oi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWM0Nm5ldy5naWYpOyBQQURESU5H +LUJPVFRPTTogMHB4OyBNQVJHSU46IC0zcHggMHB4IDEwcHg7IFBBRERJTkctVE9QOiAwcHg7IFBP +U0lUSU9OOiByZWxhdGl2ZTsgSEVJR0hUOiAxOXB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlh +bDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48L0REPg0KICA8RFQgY2xhc3M9dHh0X2JsYWNr +IA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAwcHgg +OHB4OyBQQURESU5HLUxFRlQ6IDEwcHg7IEZPTlQtU0laRTogMTRweDsgQkFDS0dST1VORC1JTUFH +RTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzI2LmdpZik7 +IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogM3B4IDBweDsgQ09MT1I6IHJnYigwLDAsMCk7 +IFBBRERJTkctVE9QOiAwcHg7IFBPU0lUSU9OOiByZWxhdGl2ZTsgYmFja2dyb3VuZC1vcmlnaW46 +IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PENJVEUgDQogIGNsYXNzPSJ0eHRf +Ymx1ZSB0eHRfMTIiIA0KICBzdHlsZT0iRk9OVC1TSVpFOiAxMnB4OyBGTE9BVDogcmlnaHQ7IENP +TE9SOiByZ2IoMSw5NSwxODIpOyBGT05ULVNUWUxFOiBub3JtYWwiPjxBIA0KICBzdHlsZT0iQ09M +T1I6IHJnYigxLDk1LDE4Mik7IFRFWFQtREVDT1JBVElPTjogdW5kZXJsaW5lIiANCiAgb25jbGlj +az1Mb2dDbGlja0NvdW50KHRoaXMsNzkpOyBocmVmPSJodHRwOi8vaGkuY3Nkbi5uZXQvbGFucGhh +ZGF5L3Byb2ZpbGUiIA0KICB0YXJnZXQ9X2JsYW5rPui1luWLh+a1qTwvQT48L0NJVEU+PEEgdGl0 +bGU9IueUqCBQeXRob24g55qEIERlc2NyaXB0b3Ig54m55oCn6Kej5Yaz5LiA5Liq5Y+Y5oCB55qE +6Zeu6aKYIiANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5v +bmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw3OSk7IA0KICBocmVmPSJodHRwOi8v +YmxvZy5jc2RuLm5ldC9sYW5waGFkYXkvYXJjaGl2ZS8yMDEwLzEyLzAyLzYwNTEyMDEuYXNweCIg +DQogIHRhcmdldD1fYmxhbms+55SoIFB5dGhvbiDnmoQgRGVzY3JpcHRvciDnibnmgKfop6PlhrPk +uIDkuKrlj5jmgIHnmoTpl67popg8L0E+PC9EVD4NCiAgPERUIGNsYXNzPXR4dF9ibGFjayANCiAg +c3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMHB4IDhweDsg +UEFERElORy1MRUZUOiAxMHB4OyBGT05ULVNJWkU6IDE0cHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVy +bChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMyNi5naWYpOyBQQURE +SU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDNweCAwcHg7IENPTE9SOiByZ2IoMCwwLDApOyBQQURE +SU5HLVRPUDogMHB4OyBQT1NJVElPTjogcmVsYXRpdmU7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0 +aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxDSVRFIA0KICBjbGFzcz0idHh0X2JsdWUg +dHh0XzEyIiANCiAgc3R5bGU9IkZPTlQtU0laRTogMTJweDsgRkxPQVQ6IHJpZ2h0OyBDT0xPUjog +cmdiKDEsOTUsMTgyKTsgRk9OVC1TVFlMRTogbm9ybWFsIj48QSANCiAgc3R5bGU9IkNPTE9SOiBy +Z2IoMSw5NSwxODIpOyBURVhULURFQ09SQVRJT046IHVuZGVybGluZSIgDQogIG9uY2xpY2s9TG9n +Q2xpY2tDb3VudCh0aGlzLDc5KTsgaHJlZj0iaHR0cDovL2hpLmNzZG4ubmV0L3N1cGVyY2gwMDU0 +L3Byb2ZpbGUiIA0KICB0YXJnZXQ9X2JsYW5rPmphbWVzPC9BPjwvQ0lURT48QSB0aXRsZT3jgIrl +pKfpgZPoh7PnroDjgIvor7vkuabnrJTorrAgDQogIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsg +VEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsNzkp +OyANCiAgaHJlZj0iaHR0cDovL2Jsb2cuY3Nkbi5uZXQvc3VwZXJjaDAwNTQvYXJjaGl2ZS8yMDEw +LzEyLzAxLzYwNDkwMTQuYXNweCIgDQogIHRhcmdldD1fYmxhbms+44CK5aSn6YGT6Iez566A44CL +6K+75Lmm56yU6K6wPC9BPjwvRFQ+DQogIDxEVCBjbGFzcz10eHRfYmxhY2sgDQogIHN0eWxlPSJQ +QURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDBweCA4cHg7IFBBRERJTkct +TEVGVDogMTBweDsgRk9OVC1TSVpFOiAxNHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDov +L2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMjYuZ2lmKTsgUEFERElORy1CT1RU +T006IDBweDsgTUFSR0lOOiAzcHggMHB4OyBDT0xPUjogcmdiKDAsMCwwKTsgUEFERElORy1UT1A6 +IDBweDsgUE9TSVRJT046IHJlbGF0aXZlOyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFj +a2dyb3VuZC1jbGlwOiBpbml0aWFsIj48Q0lURSANCiAgY2xhc3M9InR4dF9ibHVlIHR4dF8xMiIg +DQogIHN0eWxlPSJGT05ULVNJWkU6IDEycHg7IEZMT0FUOiByaWdodDsgQ09MT1I6IHJnYigxLDk1 +LDE4Mik7IEZPTlQtU1RZTEU6IG5vcm1hbCI+PEEgDQogIHN0eWxlPSJDT0xPUjogcmdiKDEsOTUs +MTgyKTsgVEVYVC1ERUNPUkFUSU9OOiB1bmRlcmxpbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291 +bnQodGhpcyw3OSk7IGhyZWY9Imh0dHA6Ly9oaS5jc2RuLm5ldC9jaGV1bmdtaW5lL3Byb2ZpbGUi +IA0KICB0YXJnZXQ9X2JsYW5rPuW8oOS6rjwvQT48L0NJVEU+PEEgdGl0bGU9IkFuZHJvaWQg5byA +5Y+R5Yid57qn5YWl6Zeo77ya5rOo5YaM6LC35q2M5Zyw5Zu+IEFQSSDlr4bpkqXlkozmmL7npLro +sLfmrYzlnLDlm74iIA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElP +Tjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDc5KTsgDQogIGhyZWY9Imh0 +dHA6Ly9ibG9nLmNzZG4ubmV0L2NoZXVuZ21pbmUvYXJjaGl2ZS8yMDEwLzEyLzAxLzYwNDg3MzYu +YXNweCIgDQogIHRhcmdldD1fYmxhbms+QW5kcm9pZCDlvIDlj5HliJ3nuqflhaXpl6jvvJrms6jl +hozosLfmrYzlnLDlm74gQVBJIOWvhumSpeWSjOaYvuekuuiwt+atjOWcsOWbvjwvQT48L0RUPg0K +ICA8RFQgY2xhc3M9dHh0X2JsYWNrIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNL +R1JPVU5ELVBPU0lUSU9OOiAwcHggOHB4OyBQQURESU5HLUxFRlQ6IDEwcHg7IEZPTlQtU0laRTog +MTRweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMv +Y3NkbmluZGV4X3BpYzI2LmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogM3B4IDBw +eDsgQ09MT1I6IHJnYigwLDAsMCk7IFBBRERJTkctVE9QOiAwcHg7IFBPU0lUSU9OOiByZWxhdGl2 +ZTsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+ +PENJVEUgDQogIGNsYXNzPSJ0eHRfYmx1ZSB0eHRfMTIiIA0KICBzdHlsZT0iRk9OVC1TSVpFOiAx +MnB4OyBGTE9BVDogcmlnaHQ7IENPTE9SOiByZ2IoMSw5NSwxODIpOyBGT05ULVNUWUxFOiBub3Jt +YWwiPjxBIA0KICBzdHlsZT0iQ09MT1I6IHJnYigxLDk1LDE4Mik7IFRFWFQtREVDT1JBVElPTjog +dW5kZXJsaW5lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsNzkpOyBocmVmPSJodHRw +Oi8vaGkuY3Nkbi5uZXQvcGVubnlsaWFuZy9wcm9maWxlIiANCiAgdGFyZ2V0PV9ibGFuaz7mooHm +low8L0E+PC9DSVRFPjxBIHRpdGxlPeaYqOWkqeW+rui9r+S6mueglOmZouiHqueEtuivreiogOWk +hOeQhue7hOeahOWRqOaYjuWNmuWjq+e7meaIkeS7rOWBmuS6huaKpeWRiiANCiAgc3R5bGU9IkNP +TE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0Ns +aWNrQ291bnQodGhpcyw3OSk7IA0KICBocmVmPSJodHRwOi8vYmxvZy5jc2RuLm5ldC9wZW5ueWxp +YW5nL2FyY2hpdmUvMjAxMC8xMi8wMS82MDQ4NjAwLmFzcHgiIA0KICB0YXJnZXQ9X2JsYW5rPuaY +qOWkqeW+rui9r+S6mueglOmZouiHqueEtuivreiogOWkhOeQhue7hOeahOWRqOaYjuWNmuWjq+e7 +meaIkeS7rOWBmuS6huaKpeWRijwvQT48L0RUPg0KICA8RFQgY2xhc3M9dHh0X2JsYWNrIA0KICBz +dHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAwcHggOHB4OyBQ +QURESU5HLUxFRlQ6IDEwcHg7IEZPTlQtU0laRTogMTRweDsgQkFDS0dST1VORC1JTUFHRTogdXJs +KGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzI2LmdpZik7IFBBRERJ +TkctQk9UVE9NOiAwcHg7IE1BUkdJTjogM3B4IDBweDsgQ09MT1I6IHJnYigwLDAsMCk7IFBBRERJ +TkctVE9QOiAwcHg7IFBPU0lUSU9OOiByZWxhdGl2ZTsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRp +YWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PENJVEUgDQogIGNsYXNzPSJ0eHRfYmx1ZSB0 +eHRfMTIiIA0KICBzdHlsZT0iRk9OVC1TSVpFOiAxMnB4OyBGTE9BVDogcmlnaHQ7IENPTE9SOiBy +Z2IoMSw5NSwxODIpOyBGT05ULVNUWUxFOiBub3JtYWwiPjxBIA0KICBzdHlsZT0iQ09MT1I6IHJn +YigxLDk1LDE4Mik7IFRFWFQtREVDT1JBVElPTjogdW5kZXJsaW5lIiANCiAgb25jbGljaz1Mb2dD +bGlja0NvdW50KHRoaXMsNzkpOyBocmVmPSJodHRwOi8vaGkuY3Nkbi5uZXQvZGF2aWRfbHYvcHJv +ZmlsZSIgDQogIHRhcmdldD1fYmxhbms+5ZCV5bu65LyfPC9BPjwvQ0lURT48QSB0aXRsZT0i5LiA +5Liq5LyY56eA55qE56CU5Y+R5Zui6Zif5bqU6K+l5YW35aSH5LuA5LmI54m55b6BICIgDQogIHN0 +eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGlj +az1Mb2dDbGlja0NvdW50KHRoaXMsNzkpOyANCiAgaHJlZj0iaHR0cDovL2Jsb2cuY3Nkbi5uZXQv +ZGF2aWRfbHYvYXJjaGl2ZS8yMDEwLzEyLzEzLzYwNzMwMzQuYXNweCIgDQogIHRhcmdldD1fYmxh +bms+5LiA5Liq5LyY56eA55qE56CU5Y+R5Zui6Zif5bqU6K+l5YW35aSH5LuA5LmI54m55b6BPC9B +PjwvRFQ+DQogIDxEVCBjbGFzcz10eHRfYmxhY2sgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAw +cHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDBweCA4cHg7IFBBRERJTkctTEVGVDogMTBweDsgRk9O +VC1TSVpFOiAxNHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3 +L2ltYWdlcy9jc2RuaW5kZXhfcGljMjYuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lO +OiAzcHggMHB4OyBDT0xPUjogcmdiKDAsMCwwKTsgUEFERElORy1UT1A6IDBweDsgUE9TSVRJT046 +IHJlbGF0aXZlOyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBp +bml0aWFsIj48Q0lURSANCiAgY2xhc3M9InR4dF9ibHVlIHR4dF8xMiIgDQogIHN0eWxlPSJGT05U +LVNJWkU6IDEycHg7IEZMT0FUOiByaWdodDsgQ09MT1I6IHJnYigxLDk1LDE4Mik7IEZPTlQtU1RZ +TEU6IG5vcm1hbCI+PEEgDQogIHN0eWxlPSJDT0xPUjogcmdiKDEsOTUsMTgyKTsgVEVYVC1ERUNP +UkFUSU9OOiB1bmRlcmxpbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw3OSk7IGhy +ZWY9Imh0dHA6Ly9oaS5jc2RuLm5ldC9henVyZWNoaW5hL3Byb2ZpbGUiIA0KICB0YXJnZXQ9X2Js +YW5rPmF6dXJlY2hpbmE8L0E+PC9DSVRFPjxBIA0KICB0aXRsZT0i546w5a6e5LiW55WM55qEV2lu +ZG93cyBBenVyZTog5LiOSU1QQUNUQeaAu+ijge+8jEtldmluIExhbeeahOiuv+iwiCIgDQogIHN0 +eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGlj +az1Mb2dDbGlja0NvdW50KHRoaXMsNzkpOyANCiAgaHJlZj0iaHR0cDovL2Jsb2cuY3Nkbi5uZXQv +YXp1cmVjaGluYS9hcmNoaXZlLzIwMTAvMTIvMTMvNjA3Mjc0NC5hc3B4IiANCiAgdGFyZ2V0PV9i +bGFuaz7njrDlrp7kuJbnlYznmoRXaW5kb3dzIEF6dXJlOiDkuI5JTVBBQ1RB5oC76KOB77yMS2V2 +aW4gTGFt55qE6K6/6LCIPC9BPjwvRFQ+DQogIDxEVCBjbGFzcz10eHRfYmxhY2sgDQogIHN0eWxl +PSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDBweCA4cHg7IFBBRERJ +TkctTEVGVDogMTBweDsgRk9OVC1TSVpFOiAxNHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0 +cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMjYuZ2lmKTsgUEFERElORy1C +T1RUT006IDBweDsgTUFSR0lOOiAzcHggMHB4OyBDT0xPUjogcmdiKDAsMCwwKTsgUEFERElORy1U +T1A6IDBweDsgUE9TSVRJT046IHJlbGF0aXZlOyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsg +YmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48Q0lURSANCiAgY2xhc3M9InR4dF9ibHVlIHR4dF8x +MiIgDQogIHN0eWxlPSJGT05ULVNJWkU6IDEycHg7IEZMT0FUOiByaWdodDsgQ09MT1I6IHJnYigx +LDk1LDE4Mik7IEZPTlQtU1RZTEU6IG5vcm1hbCI+PEEgDQogIHN0eWxlPSJDT0xPUjogcmdiKDEs +OTUsMTgyKTsgVEVYVC1ERUNPUkFUSU9OOiB1bmRlcmxpbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNr +Q291bnQodGhpcyw3OSk7IGhyZWY9Imh0dHA6Ly9oaS5jc2RuLm5ldC9iaXRmYW4vcHJvZmlsZSIg +DQogIHRhcmdldD1fYmxhbms+6YeR5pet5LquPC9BPjwvQ0lURT48QSB0aXRsZT3oh6rmtYvkuIDk +uIvkvaDnmoRKYXZh5o6M5o+h5b6X5oCO5LmI5qC377yfIA0KICBzdHlsZT0iQ09MT1I6IHJnYigw +LDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0 +aGlzLDc5KTsgDQogIGhyZWY9Imh0dHA6Ly9ibG9nLmNzZG4ubmV0L2JpdGZhbi9hcmNoaXZlLzIw +MTAvMTIvMTMvNjA3MjY5MC5hc3B4IiANCiAgdGFyZ2V0PV9ibGFuaz7oh6rmtYvkuIDkuIvkvaDn +moRKYXZh5o6M5o+h5b6X5oCO5LmI5qC377yfPC9BPjwvRFQ+DQogIDxEVCBjbGFzcz10eHRfYmxh +Y2sgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDBw +eCA4cHg7IFBBRERJTkctTEVGVDogMTBweDsgRk9OVC1TSVpFOiAxNHB4OyBCQUNLR1JPVU5ELUlN +QUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMjYuZ2lm +KTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAzcHggMHB4OyBDT0xPUjogcmdiKDAsMCww +KTsgUEFERElORy1UT1A6IDBweDsgUE9TSVRJT046IHJlbGF0aXZlOyBiYWNrZ3JvdW5kLW9yaWdp +bjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48Q0lURSANCiAgY2xhc3M9InR4 +dF9ibHVlIHR4dF8xMiIgDQogIHN0eWxlPSJGT05ULVNJWkU6IDEycHg7IEZMT0FUOiByaWdodDsg +Q09MT1I6IHJnYigxLDk1LDE4Mik7IEZPTlQtU1RZTEU6IG5vcm1hbCI+PEEgDQogIHN0eWxlPSJD +T0xPUjogcmdiKDEsOTUsMTgyKTsgVEVYVC1ERUNPUkFUSU9OOiB1bmRlcmxpbmUiIA0KICBvbmNs +aWNrPUxvZ0NsaWNrQ291bnQodGhpcyw3OSk7IGhyZWY9Imh0dHA6Ly9oaS5jc2RuLm5ldC9jcGlu +ZzE5ODIvcHJvZmlsZSIgDQogIHRhcmdldD1fYmxhbms+6bmP5YeM5LiJ5Y2DKGNwaW5nPC9BPjwv +Q0lURT48QSB0aXRsZT3kuLrku4DkuYjmsqHmnInlpb3nlKjnmoRBbmRyb2lk5ri45oiP5byV5pOO +77yfIA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIg +DQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDc5KTsgDQogIGhyZWY9Imh0dHA6Ly9ibG9n +LmNzZG4ubmV0L2NwaW5nMTk4Mi9hcmNoaXZlLzIwMTAvMTIvMTIvNjA3MjE4OC5hc3B4IiANCiAg +dGFyZ2V0PV9ibGFuaz7kuLrku4DkuYjmsqHmnInlpb3nlKjnmoRBbmRyb2lk5ri45oiP5byV5pOO +77yfPC9BPjwvRFQ+DQogIDxEVCBjbGFzcz10eHRfYmxhY2sgDQogIHN0eWxlPSJQQURESU5HLVJJ +R0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDBweCA4cHg7IFBBRERJTkctTEVGVDogMTBw +eDsgRk9OVC1TSVpFOiAxNHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcu +Y24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMjYuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsg +TUFSR0lOOiAzcHggMHB4OyBDT0xPUjogcmdiKDAsMCwwKTsgUEFERElORy1UT1A6IDBweDsgUE9T +SVRJT046IHJlbGF0aXZlOyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1j +bGlwOiBpbml0aWFsIj48Q0lURSANCiAgY2xhc3M9InR4dF9ibHVlIHR4dF8xMiIgDQogIHN0eWxl +PSJGT05ULVNJWkU6IDEycHg7IEZMT0FUOiByaWdodDsgQ09MT1I6IHJnYigxLDk1LDE4Mik7IEZP +TlQtU1RZTEU6IG5vcm1hbCI+PEEgDQogIHN0eWxlPSJDT0xPUjogcmdiKDEsOTUsMTgyKTsgVEVY +VC1ERUNPUkFUSU9OOiB1bmRlcmxpbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw3 +OSk7IGhyZWY9Imh0dHA6Ly9oaS5jc2RuLm5ldC9jZW53ZW5jaHU3OS9wcm9maWxlIiANCiAgdGFy +Z2V0PV9ibGFuaz7lspHmlofliJ08L0E+PC9DSVRFPjxBIHRpdGxlPUZhY2Vib29r5LyY5YyW5YiG +5Lqr5ZCO6K6wIA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjog +bm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDc5KTsgDQogIGhyZWY9Imh0dHA6 +Ly9ibG9nLmNzZG4ubmV0L2NlbndlbmNodTc5L2FyY2hpdmUvMjAxMC8xMi8xMi82MDcxMjk4LmFz +cHgiIA0KICB0YXJnZXQ9X2JsYW5rPkZhY2Vib29r5LyY5YyW5YiG5Lqr5ZCO6K6wPC9BPjwvRFQ+ +DQogIDxERCBjbGFzcz1uZXdzX3R5cGVhcyANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsg +UEFERElORy1MRUZUOiAwcHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5j +bi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWM0Nm5ldy5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4 +OyBNQVJHSU46IC0zcHggMHB4IDEwcHg7IFBBRERJTkctVE9QOiAwcHg7IFBPU0lUSU9OOiByZWxh +dGl2ZTsgSEVJR0hUOiAxOXB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3Vu +ZC1jbGlwOiBpbml0aWFsIj48L0REPg0KICA8RFQgY2xhc3M9dHh0X2JsYWNrIA0KICBzdHlsZT0i +UEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAwcHggOHB4OyBQQURESU5H +LUxFRlQ6IDEwcHg7IEZPTlQtU0laRTogMTRweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6 +Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzI2LmdpZik7IFBBRERJTkctQk9U +VE9NOiAwcHg7IE1BUkdJTjogM3B4IDBweDsgQ09MT1I6IHJnYigwLDAsMCk7IFBBRERJTkctVE9Q +OiAwcHg7IFBPU0lUSU9OOiByZWxhdGl2ZTsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJh +Y2tncm91bmQtY2xpcDogaW5pdGlhbCI+PENJVEUgDQogIGNsYXNzPSJ0eHRfYmx1ZSB0eHRfMTIi +IA0KICBzdHlsZT0iRk9OVC1TSVpFOiAxMnB4OyBGTE9BVDogcmlnaHQ7IENPTE9SOiByZ2IoMSw5 +NSwxODIpOyBGT05ULVNUWUxFOiBub3JtYWwiPjxBIA0KICBzdHlsZT0iQ09MT1I6IHJnYigxLDk1 +LDE4Mik7IFRFWFQtREVDT1JBVElPTjogdW5kZXJsaW5lIiANCiAgb25jbGljaz1Mb2dDbGlja0Nv +dW50KHRoaXMsNzkpOyBocmVmPSJodHRwOi8vaGkuY3Nkbi5uZXQva2FiaW5pL3Byb2ZpbGUiIA0K +ICB0YXJnZXQ9X2JsYW5rPuiWm+esmzwvQT48L0NJVEU+PEEgdGl0bGU9IueUqEMrK+WGmUphdmEg +U3R5bGXnqIvluo8iIA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElP +Tjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDc5KTsgDQogIGhyZWY9Imh0 +dHA6Ly9ibG9nLmNzZG4ubmV0L2thYmluaS9hcmNoaXZlLzIwMTAvMTIvMDUvNjA1NjYxMy5hc3B4 +IiANCiAgdGFyZ2V0PV9ibGFuaz7nlKhDKyvlhplKYXZhIFN0eWxl56iL5bqPPC9BPjwvRFQ+DQog +IDxEVCBjbGFzcz10eHRfYmxhY2sgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tH +Uk9VTkQtUE9TSVRJT046IDBweCA4cHg7IFBBRERJTkctTEVGVDogMTBweDsgRk9OVC1TSVpFOiAx +NHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9j +c2RuaW5kZXhfcGljMjYuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAzcHggMHB4 +OyBDT0xPUjogcmdiKDAsMCwwKTsgUEFERElORy1UT1A6IDBweDsgUE9TSVRJT046IHJlbGF0aXZl +OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48 +Q0lURSANCiAgY2xhc3M9InR4dF9ibHVlIHR4dF8xMiIgDQogIHN0eWxlPSJGT05ULVNJWkU6IDEy +cHg7IEZMT0FUOiByaWdodDsgQ09MT1I6IHJnYigxLDk1LDE4Mik7IEZPTlQtU1RZTEU6IG5vcm1h +bCI+PEEgDQogIHN0eWxlPSJDT0xPUjogcmdiKDEsOTUsMTgyKTsgVEVYVC1ERUNPUkFUSU9OOiB1 +bmRlcmxpbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw3OSk7IGhyZWY9Imh0dHA6 +Ly9oaS5jc2RuLm5ldC9leWdsZS9wcm9maWxlIiANCiAgdGFyZ2V0PV9ibGFuaz7nm5blm73lvLo8 +L0E+PC9DSVRFPjxBIHRpdGxlPSJPcmFjbGXmlbDmja7lupPmgaLlpI0gOiDlrZjlgqjmlYXpmpzl +r7zoh7TnmoTmlbDmja7mjZ/lnY8iIA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQt +REVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDc5KTsgDQog +IGhyZWY9Imh0dHA6Ly9ibG9nLmNzZG4ubmV0L2V5Z2xlL2FyY2hpdmUvMjAxMC8xMi8wNC82MDU0 +NTYzLmFzcHgiIA0KICB0YXJnZXQ9X2JsYW5rPk9yYWNsZeaVsOaNruW6k+aBouWkjSA6IOWtmOWC +qOaVhemanOWvvOiHtOeahOaVsOaNruaNn+WdjzwvQT48L0RUPg0KICA8RFQgY2xhc3M9dHh0X2Js +YWNrIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAw +cHggOHB4OyBQQURESU5HLUxFRlQ6IDEwcHg7IEZPTlQtU0laRTogMTRweDsgQkFDS0dST1VORC1J +TUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzI2Lmdp +Zik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogM3B4IDBweDsgQ09MT1I6IHJnYigwLDAs +MCk7IFBBRERJTkctVE9QOiAwcHg7IFBPU0lUSU9OOiByZWxhdGl2ZTsgYmFja2dyb3VuZC1vcmln +aW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PENJVEUgDQogIGNsYXNzPSJ0 +eHRfYmx1ZSB0eHRfMTIiIA0KICBzdHlsZT0iRk9OVC1TSVpFOiAxMnB4OyBGTE9BVDogcmlnaHQ7 +IENPTE9SOiByZ2IoMSw5NSwxODIpOyBGT05ULVNUWUxFOiBub3JtYWwiPjxBIA0KICBzdHlsZT0i +Q09MT1I6IHJnYigxLDk1LDE4Mik7IFRFWFQtREVDT1JBVElPTjogdW5kZXJsaW5lIiANCiAgb25j +bGljaz1Mb2dDbGlja0NvdW50KHRoaXMsNzkpOyBocmVmPSJodHRwOi8vaGkuY3Nkbi5uZXQvY2xl +dmVyMTAxL3Byb2ZpbGUiIA0KICB0YXJnZXQ9X2JsYW5rPuacsemHkeeBvzwvQT48L0NJVEU+PEEg +dGl0bGU9R0RJK+WtpuS5oOS5i+e6v+aAp+a4kOWPmOeUu+WItyANCiAgc3R5bGU9IkNPTE9SOiBy +Z2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291 +bnQodGhpcyw3OSk7IA0KICBocmVmPSJodHRwOi8vYmxvZy5jc2RuLm5ldC9jbGV2ZXIxMDEvYXJj +aGl2ZS8yMDEwLzEyLzA4LzYwNjM2OTcuYXNweCIgDQogIHRhcmdldD1fYmxhbms+R0RJK+WtpuS5 +oOS5i+e6v+aAp+a4kOWPmOeUu+WItzwvQT48L0RUPg0KICA8RFQgY2xhc3M9dHh0X2JsYWNrIA0K +ICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAwcHggOHB4 +OyBQQURESU5HLUxFRlQ6IDEwcHg7IEZPTlQtU0laRTogMTRweDsgQkFDS0dST1VORC1JTUFHRTog +dXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzI2LmdpZik7IFBB +RERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogM3B4IDBweDsgQ09MT1I6IHJnYigwLDAsMCk7IFBB +RERJTkctVE9QOiAwcHg7IFBPU0lUSU9OOiByZWxhdGl2ZTsgYmFja2dyb3VuZC1vcmlnaW46IGlu +aXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PENJVEUgDQogIGNsYXNzPSJ0eHRfYmx1 +ZSB0eHRfMTIiIA0KICBzdHlsZT0iRk9OVC1TSVpFOiAxMnB4OyBGTE9BVDogcmlnaHQ7IENPTE9S +OiByZ2IoMSw5NSwxODIpOyBGT05ULVNUWUxFOiBub3JtYWwiPjxBIA0KICBzdHlsZT0iQ09MT1I6 +IHJnYigxLDk1LDE4Mik7IFRFWFQtREVDT1JBVElPTjogdW5kZXJsaW5lIiANCiAgb25jbGljaz1M +b2dDbGlja0NvdW50KHRoaXMsNzkpOyBocmVmPSJodHRwOi8vaGkuY3Nkbi5uZXQvYWltaW5nb28v +cHJvZmlsZSIgDQogIHRhcmdldD1fYmxhbms+5ZGo54ix5rCRPC9BPjwvQ0lURT48QSB0aXRsZT3n +u6fmib/kuI7mt7flkIjvvIznlaXosIjns7vnu5/nmoTmnoTlu7rmlrnlvI8gDQogIHN0eWxlPSJD +T0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dD +bGlja0NvdW50KHRoaXMsNzkpOyANCiAgaHJlZj0iaHR0cDovL2Jsb2cuY3Nkbi5uZXQvYWltaW5n +b28vYXJjaGl2ZS8yMDEwLzEyLzA4LzYwNjI5OTcuYXNweCIgDQogIHRhcmdldD1fYmxhbms+57un +5om/5LiO5re35ZCI77yM55Wl6LCI57O757uf55qE5p6E5bu65pa55byPPC9BPjwvRFQ+DQogIDxE +VCBjbGFzcz10eHRfYmxhY2sgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9V +TkQtUE9TSVRJT046IDBweCA4cHg7IFBBRERJTkctTEVGVDogMTBweDsgRk9OVC1TSVpFOiAxNHB4 +OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2Ru +aW5kZXhfcGljMjYuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAzcHggMHB4OyBD +T0xPUjogcmdiKDAsMCwwKTsgUEFERElORy1UT1A6IDBweDsgUE9TSVRJT046IHJlbGF0aXZlOyBi +YWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48Q0lU +RSANCiAgY2xhc3M9InR4dF9ibHVlIHR4dF8xMiIgDQogIHN0eWxlPSJGT05ULVNJWkU6IDEycHg7 +IEZMT0FUOiByaWdodDsgQ09MT1I6IHJnYigxLDk1LDE4Mik7IEZPTlQtU1RZTEU6IG5vcm1hbCI+ +PEEgDQogIHN0eWxlPSJDT0xPUjogcmdiKDEsOTUsMTgyKTsgVEVYVC1ERUNPUkFUSU9OOiB1bmRl +cmxpbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw3OSk7IGhyZWY9Imh0dHA6Ly9o +aS5jc2RuLm5ldC9iZW5pYW8yNzcvcHJvZmlsZSIgDQogIHRhcmdldD1fYmxhbms+5byg5a6HPC9B +PjwvQ0lURT48QSB0aXRsZT0i5o+S5Lu25byP5p625p6E6K6+6K6h5a6e6Le15LqM77ya5Z+65LqO +U2lsdmVybGlnaHTnmoRCL1Pmj5Lku7blvI/mnrbmnoTorr7orqHmlrnms5UgIiANCiAgc3R5bGU9 +IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxv +Z0NsaWNrQ291bnQodGhpcyw3OSk7IA0KICBocmVmPSJodHRwOi8vYmxvZy5jc2RuLm5ldC9iZW5p +YW8yNzcvYXJjaGl2ZS8yMDEwLzEyLzA3LzYwNTk2NTcuYXNweCIgDQogIHRhcmdldD1fYmxhbms+ +5o+S5Lu25byP5p625p6E6K6+6K6h5a6e6Le15LqM77ya5Z+65LqOU2lsdmVybGlnaHTnmoRCL1Pm +j5Lku7blvI/mnrbmnoTorr7orqHmlrnms5U8L0E+PC9EVD4NCiAgPERUIGNsYXNzPXR4dF9ibGFj +ayANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMHB4 +IDhweDsgUEFERElORy1MRUZUOiAxMHB4OyBGT05ULVNJWkU6IDE0cHg7IEJBQ0tHUk9VTkQtSU1B +R0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMyNi5naWYp +OyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDNweCAwcHg7IENPTE9SOiByZ2IoMCwwLDAp +OyBQQURESU5HLVRPUDogMHB4OyBQT1NJVElPTjogcmVsYXRpdmU7IGJhY2tncm91bmQtb3JpZ2lu +OiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxDSVRFIA0KICBjbGFzcz0idHh0 +X2JsdWUgdHh0XzEyIiANCiAgc3R5bGU9IkZPTlQtU0laRTogMTJweDsgRkxPQVQ6IHJpZ2h0OyBD +T0xPUjogcmdiKDEsOTUsMTgyKTsgRk9OVC1TVFlMRTogbm9ybWFsIj48QSANCiAgc3R5bGU9IkNP +TE9SOiByZ2IoMSw5NSwxODIpOyBURVhULURFQ09SQVRJT046IHVuZGVybGluZSIgDQogIG9uY2xp +Y2s9TG9nQ2xpY2tDb3VudCh0aGlzLDc5KTsgaHJlZj0iaHR0cDovL2hpLmNzZG4ubmV0L2NsZXZl +cjEwMS9wcm9maWxlIiANCiAgdGFyZ2V0PV9ibGFuaz7mnLHph5Hngb88L0E+PC9DSVRFPjxBIHRp +dGxlPeS6jOe7tOWbvuW9oue8lui+keS4reeCuemAieWPluetlueVpeeglOeptiANCiAgc3R5bGU9 +IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxv +Z0NsaWNrQ291bnQodGhpcyw3OSk7IA0KICBocmVmPSJodHRwOi8vYmxvZy5jc2RuLm5ldC9jbGV2 +ZXIxMDEvYXJjaGl2ZS8yMDEwLzEyLzA2LzYwNTg5OTQuYXNweCIgDQogIHRhcmdldD1fYmxhbms+ +5LqM57u05Zu+5b2i57yW6L6R5Lit54K56YCJ5Y+W562W55Wl56CU56m2PC9BPjwvRFQ+DQogIDxE +VCBjbGFzcz10eHRfYmxhY2sgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9V +TkQtUE9TSVRJT046IDBweCA4cHg7IFBBRERJTkctTEVGVDogMTBweDsgRk9OVC1TSVpFOiAxNHB4 +OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2Ru +aW5kZXhfcGljMjYuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAzcHggMHB4OyBD +T0xPUjogcmdiKDAsMCwwKTsgUEFERElORy1UT1A6IDBweDsgUE9TSVRJT046IHJlbGF0aXZlOyBi +YWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48Q0lU +RSANCiAgY2xhc3M9InR4dF9ibHVlIHR4dF8xMiIgDQogIHN0eWxlPSJGT05ULVNJWkU6IDEycHg7 +IEZMT0FUOiByaWdodDsgQ09MT1I6IHJnYigxLDk1LDE4Mik7IEZPTlQtU1RZTEU6IG5vcm1hbCI+ +PEEgDQogIHN0eWxlPSJDT0xPUjogcmdiKDEsOTUsMTgyKTsgVEVYVC1ERUNPUkFUSU9OOiB1bmRl +cmxpbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw3OSk7IGhyZWY9Imh0dHA6Ly9o +aS5jc2RuLm5ldC9nbnVocGMvcHJvZmlsZSIgDQogIHRhcmdldD1fYmxhbms+6buE6bmP56iLPC9B +PjwvQ0lURT48QSB0aXRsZT1MaW51eOeOr+Wig+S4i+eahEMvQyvln7rnoYDosIPor5XmioDmnK8y +4oCU4oCU56iL5bqP5o6n5Yi2IA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVD +T1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDc5KTsgDQogIGhy +ZWY9Imh0dHA6Ly9ibG9nLmNzZG4ubmV0L2dudWhwYy9hcmNoaXZlLzIwMTAvMTIvMDYvNjA1Nzgw +OS5hc3B4IiANCiAgdGFyZ2V0PV9ibGFuaz5MaW51eOeOr+Wig+S4i+eahEMvQyvln7rnoYDosIPo +r5XmioDmnK8y4oCU4oCU56iL5bqP5o6n5Yi2PC9BPjwvRFQ+DQogIDxEVCBjbGFzcz10eHRfYmxh +Y2sgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDBw +eCA4cHg7IFBBRERJTkctTEVGVDogMTBweDsgRk9OVC1TSVpFOiAxNHB4OyBCQUNLR1JPVU5ELUlN +QUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMjYuZ2lm +KTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAzcHggMHB4OyBDT0xPUjogcmdiKDAsMCww +KTsgUEFERElORy1UT1A6IDBweDsgUE9TSVRJT046IHJlbGF0aXZlOyBiYWNrZ3JvdW5kLW9yaWdp +bjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48Q0lURSANCiAgY2xhc3M9InR4 +dF9ibHVlIHR4dF8xMiIgDQogIHN0eWxlPSJGT05ULVNJWkU6IDEycHg7IEZMT0FUOiByaWdodDsg +Q09MT1I6IHJnYigxLDk1LDE4Mik7IEZPTlQtU1RZTEU6IG5vcm1hbCI+PEEgDQogIHN0eWxlPSJD +T0xPUjogcmdiKDEsOTUsMTgyKTsgVEVYVC1ERUNPUkFUSU9OOiB1bmRlcmxpbmUiIA0KICBvbmNs +aWNrPUxvZ0NsaWNrQ291bnQodGhpcyw3OSk7IGhyZWY9Imh0dHA6Ly9oaS5jc2RuLm5ldC9xaW5n +cnVuL3Byb2ZpbGUiIA0KICB0YXJnZXQ9X2JsYW5rPueZveaFp+WGrDwvQT48L0NJVEU+PEEgdGl0 +bGU9W+WFqOeoi+W7uuaooV3nsbvlm77lkozml7bluo/lm77nmoTlvIDlj5HlhbPns7vvvIzku47n +lKjkvovosIjotbfnmoTlhajnqIvlu7rmqKEgDQogIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsg +VEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsNzkp +OyANCiAgaHJlZj0iaHR0cDovL2Jsb2cuY3Nkbi5uZXQvcWluZ3J1bi9hcmNoaXZlLzIwMTAvMTIv +MTIvNjA3MDk5NC5hc3B4IiANCiAgdGFyZ2V0PV9ibGFuaz5b5YWo56iL5bu65qihXeexu+WbvuWS +jOaXtuW6j+WbvueahOW8gOWPkeWFs+ezu++8jOS7jueUqOS+i+iwiOi1t+eahOWFqOeoi+W7uuao +oTwvQT48L0RUPg0KICA8REQgY2xhc3M9bmV3c190eXBlYXMgDQogIHN0eWxlPSJQQURESU5HLVJJ +R0hUOiAwcHg7IFBBRERJTkctTEVGVDogMHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDov +L2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljNDZuZXcuZ2lmKTsgUEFERElORy1C +T1RUT006IDBweDsgTUFSR0lOOiAtM3B4IDBweCAxMHB4OyBQQURESU5HLVRPUDogMHB4OyBQT1NJ +VElPTjogcmVsYXRpdmU7IEhFSUdIVDogMTlweDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7 +IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PC9ERD48L0RMPjwvRElWPg0KPERJViBjbGFzcz1i +dXNpbmVzc3R4dGFkIA0Kc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgRElTUExBWTogaW5saW5l +OyBQQURESU5HLUxFRlQ6IDBweDsgRkxPQVQ6IGxlZnQ7IFBBRERJTkctQk9UVE9NOiA1cHg7IE1B +UkdJTjogLTZweCAxMHB4IDNweDsgV0lEVEg6IDQ1MHB4OyBQQURESU5HLVRPUDogNXB4Ij4NCjxV +TCBjbGFzcz10eHRfZGVwZ3JheSANCnN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IFBBRERJTkct +TEVGVDogMHB4OyBGTE9BVDogbGVmdDsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7 +IFdJRFRIOiA0NTBweDsgQ09MT1I6IHJnYig1MSw1MSw1MSk7IFBBRERJTkctVE9QOiAwcHg7IExJ +U1QtU1RZTEUtVFlQRTogbm9uZSI+DQogIDxMSSANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBw +eDsgRElTUExBWTogaW5saW5lOyBQQURESU5HLUxFRlQ6IDBweDsgRkxPQVQ6IGxlZnQ7IFBBRERJ +TkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4IDVweDsgV0lEVEg6IDIxNXB4OyBQQURESU5HLVRP +UDogMHB4Ij48QSANCiAgc3R5bGU9IkNPTE9SOiByZ2IoNTEsNTEsNTEpOyBURVhULURFQ09SQVRJ +T046IG5vbmUiIA0KICBocmVmPSJodHRwOi8vei5jc2RuLm5ldC9nbWNsaWNrLnBocD9iYW5uZXJp +ZD00Nzc3JmFtcDt6b25laWQ9NDI1JmFtcDtzb3VyY2U9JmFtcDtkZXN0PWh0dHAlM0ElMkYlMkZ3 +d3cuaXRjYXN0LmNuJTJGaXRjYXN0X3N0YXRpYyUyRmVtcGxveVRlYWNoZXIuaHRtIiANCiAgdGFy +Z2V0PV9ibGFuaz7lubTolqoxNS0yMOS4h+aApeaLm2phdmHorrLluIjvvIE8L0E+PC9MST4NCiAg +PExJIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBESVNQTEFZOiBpbmxpbmU7IFBBRERJ +TkctTEVGVDogMHB4OyBGTE9BVDogbGVmdDsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAw +cHggNXB4OyBXSURUSDogMjE1cHg7IFBBRERJTkctVE9QOiAwcHgiPjxBIA0KICBzdHlsZT0iQ09M +T1I6IHJnYig1MSw1MSw1MSk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIGhyZWY9Imh0dHA6 +Ly96LmNzZG4ubmV0L2dtY2xpY2sucGhwP2Jhbm5lcmlkPTU0MDgmYW1wO3pvbmVpZD00MjcmYW1w +O3NvdXJjZT0mYW1wO2Rlc3Q9aHR0cCUzQSUyRiUyRjE4OXdvcmtzLmNzZG4ubmV0JTJGKyIgDQog +IHRhcmdldD1fYmxhbms+5aSp57+85pWZ5L2g56e75Yqo5bqU55So6JCl5Yip5LmL6YGTPC9BPjwv +TEk+DQogIDxMSSANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgRElTUExBWTogaW5saW5l +OyBQQURESU5HLUxFRlQ6IDBweDsgRkxPQVQ6IGxlZnQ7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1B +UkdJTjogMHB4IDVweDsgV0lEVEg6IDIxNXB4OyBQQURESU5HLVRPUDogMHB4Ij48QSANCiAgc3R5 +bGU9IkNPTE9SOiByZ2IoNTEsNTEsNTEpOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBocmVm +PSJodHRwOi8vei5jc2RuLm5ldC9nbWNsaWNrLnBocD9iYW5uZXJpZD01MjEzJmFtcDt6b25laWQ9 +NDI2JmFtcDtzb3VyY2U9JmFtcDtkZXN0PWh0dHAlM0ElMkYlMkYzZy5lZHUuY3Nkbi5uZXQlMkZr +ZWNoZW5nJTJGQW5kcm9pZC5odG1sIiANCiAgdGFyZ2V0PV9ibGFuaz7lv6vmjbfovazlnotBbmRy +b2lk6auY6Jaq5Lq65omNPC9BPjwvTEk+DQogIDxMSSANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6 +IDBweDsgRElTUExBWTogaW5saW5lOyBQQURESU5HLUxFRlQ6IDBweDsgRkxPQVQ6IGxlZnQ7IFBB +RERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4IDVweDsgV0lEVEg6IDIxNXB4OyBQQURESU5H +LVRPUDogMHB4Ij48QSANCiAgc3R5bGU9IkNPTE9SOiByZ2IoNTEsNTEsNTEpOyBURVhULURFQ09S +QVRJT046IG5vbmUiIA0KICBocmVmPSJodHRwOi8vei5jc2RuLm5ldC9nbWNsaWNrLnBocD9iYW5u +ZXJpZD01Mjk1JmFtcDt6b25laWQ9NDI4JmFtcDtzb3VyY2U9JmFtcDtkZXN0PWh0dHAlM0ElMkYl +MkZ3d3cubGFtcGJyb3RoZXIubmV0JTJGdmlkZW8uaHRtbCIgDQogIHRhcmdldD1fYmxhbms+5Y+y +5LiK5pyA57uZ5Yqb55qE5YWN6LS5UEhQ6KeG6aKR5pWZ56iLPC9BPjwvTEk+PC9VTD48L0RJVj48 +L0RJVj4NCjxESVYgY2xhc3M9cGFnZWNvbl9sYXllcjJfbWlkIA0Kc3R5bGU9IkJPUkRFUi1UT1A6 +IHJnYigyMDQsMjA0LDIwNCkgMXB4IHNvbGlkOyBESVNQTEFZOiBpbmxpbmU7IEZMT0FUOiBsZWZ0 +OyBNQVJHSU46IDBweCAwcHggMHB4IDVweDsgV0lEVEg6IDI1OXB4OyBURVhULUFMSUdOOiBsZWZ0 +Ij4NCjxIMyANCnN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046 +IDBweCAwcHg7IERJU1BMQVk6IGlubGluZTsgUEFERElORy1MRUZUOiAyMHB4OyBGT05ULVNJWkU6 +IDE0cHg7IEZMT0FUOiBsZWZ0OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcu +Y24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMTUuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsg +TUFSR0lOOiAwcHggMHB4IDdweDsgV0lEVEg6IDIzOXB4OyBMSU5FLUhFSUdIVDogMzBweDsgUEFE +RElORy1UT1A6IDBweDsgUE9TSVRJT046IHJlbGF0aXZlOyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5p +dGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48U1BBTiANCmNsYXNzPSJ0eHRfMTIgdHh0 +X2dyYXkiIA0Kc3R5bGU9IkZPTlQtV0VJR0hUOiBub3JtYWw7IEZPTlQtU0laRTogMTJweDsgRkxP +QVQ6IHJpZ2h0OyBNQVJHSU46IDJweCA3cHggMHB4IDBweDsgQ09MT1I6IHJnYigxMDIsMTAyLDEw +MikiPjxBIA0Kc3R5bGU9IkNPTE9SOiByZ2IoMTAyLDEwMiwxMDIpOyBURVhULURFQ09SQVRJT046 +IG5vbmUiIA0KaHJlZj0iaHR0cDovL2Jsb2cuY3Nkbi5uZXQvIj7mm7TlpJo8L0E+PC9TUEFOPuWN +muWuouS5i+aYnzwvSDM+DQo8REwgY2xhc3M9ZXhwZXJ0c2hvdyANCnN0eWxlPSJQQURESU5HLVJJ +R0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDUwJSAxMDAlOyBESVNQTEFZOiBpbmxpbmU7 +IFBBRERJTkctTEVGVDogMHB4OyBGTE9BVDogbGVmdDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0 +dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzE0LmdpZik7IFBBRERJTkct +Qk9UVE9NOiAzcHg7IE1BUkdJTjogNnB4IDEwcHggMHB4OyBXSURUSDogMjM5cHg7IFBBRERJTkct +VE9QOiAwcHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGlu +aXRpYWwiPg0KICA8REQgY2xhc3M9cGljcyANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsg +UEFERElORy1MRUZUOiAwcHg7IEZMT0FUOiBsZWZ0OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0 +cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljNDcuZ2lmKTsgUEFERElORy1C +T1RUT006IDNweDsgTUFSR0lOOiAwcHggNnB4IDBweCAwcHg7IFdJRFRIOiA5M3B4OyBQQURESU5H +LVRPUDogMHB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBp +bml0aWFsIj48QSANCiAgdGl0bGU95b6u6L2v5LqR6K6h566X5Lit5paH5Y2a5a6iIHN0eWxlPSJD +T0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dD +bGlja0NvdW50KHRoaXMsODEpOyBocmVmPSJodHRwOi8vYmxvZy5jc2RuLm5ldC9henVyZWNoaW5h +IiANCiAgdGFyZ2V0PV9ibGFuaz48SU1HIHRpdGxlPSIiIA0KICBzdHlsZT0iQk9SREVSLVJJR0hU +OiByZ2IoMCwwLDApIDFweCBzb2xpZDsgQk9SREVSLVRPUDogcmdiKDAsMCwwKSAxcHggc29saWQ7 +IEJPUkRFUi1MRUZUOiByZ2IoMCwwLDApIDFweCBzb2xpZDsgV0lEVEg6IDg2cHg7IEJPUkRFUi1C +T1RUT006IHJnYigwLDAsMCkgMXB4IHNvbGlkOyBIRUlHSFQ6IDg2cHgiIA0KICBhbHQ9IiIgc3Jj +PSJodHRwOi8vYXZhdGFyLmNzZG4ubmV0LzYvQS82LzFfYXp1cmVjaGluYS5qcGciIHdpZHRoPTg2 +PjwvQT48L0REPg0KICA8REQgY2xhc3M9dHh0X2JsdWUgDQogIHN0eWxlPSJQQURESU5HLVJJR0hU +OiAwcHg7IFBBRERJTkctTEVGVDogMHB4OyBQQURESU5HLUJPVFRPTTogM3B4OyBNQVJHSU46IDBw +eDsgQ09MT1I6IHJnYigxLDk1LDE4Mik7IFBBRERJTkctVE9QOiAwcHgiPjxBIA0KICB0aXRsZT3l +vq7ova/kupHorqHnrpfkuK3mlofljZrlrqIgc3R5bGU9IkNPTE9SOiByZ2IoMSw5NSwxODIpOyBU +RVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw4MSk7 +IGhyZWY9Imh0dHA6Ly9ibG9nLmNzZG4ubmV0L2F6dXJlY2hpbmEiIA0KICB0YXJnZXQ9X2JsYW5r +PuW+rui9r+S6keiuoeeul+S4reaWh+WNmuWuojwvQT48L0REPg0KICA8REQgDQogIHN0eWxlPSJQ +QURESU5HLVJJR0hUOiAwcHg7IFBBRERJTkctTEVGVDogMHB4OyBQQURESU5HLUJPVFRPTTogM3B4 +OyBNQVJHSU46IDBweDsgUEFERElORy1UT1A6IDBweCI+5pys5Lit5paH5Y2a5a6i55Sx5b6u6L2v +5LqR6K6h566XQXp1cmXorrrlnZvmlK/mjIHlsI/nu4TlvIDlip7jgILlhoXlrrnku6VXaW5kb3dz +IA0KICBBenVyZSBQbGF0Zm9ybeS4uuS4u+OAgjwvREQ+DQogIDxERCBjbGFzcz0iYXNrIHR4dF9i +bHVlIiANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDVweDsgUEFERElORy1MRUZUOiAwcHg7IEZM +T0FUOiByaWdodDsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IENPTE9SOiByZ2Io +MSw5NSwxODIpOyBQQURESU5HLVRPUDogMHB4Ij48QSANCiAgdGl0bGU95b6u6L2v5LqR6K6h566X +5Lit5paH5Y2a5a6iIHN0eWxlPSJDT0xPUjogcmdiKDEsOTUsMTgyKTsgVEVYVC1ERUNPUkFUSU9O +OiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsODEpOyBocmVmPSJodHRwOi8v +YmxvZy5jc2RuLm5ldC9henVyZWNoaW5hIiANCiAgdGFyZ2V0PV9ibGFuaz7orr/pl67ku5bnmoTn +qbrpl7Q8L0E+PC9ERD48L0RMPg0KPERMIGNsYXNzPXN0eWxlMyANCnN0eWxlPSJQQURESU5HLVJJ +R0hUOiAwcHg7IERJU1BMQVk6IGlubGluZTsgUEFERElORy1MRUZUOiAwcHg7IEZMT0FUOiBsZWZ0 +OyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDVweCAxMHB4OyBXSURUSDogMjM5cHg7IFBB +RERJTkctVE9QOiAwcHgiPg0KICA8REQgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJB +Q0tHUk9VTkQtUE9TSVRJT046IDNweCA3cHg7IFBBRERJTkctTEVGVDogMTRweDsgQkFDS0dST1VO +RC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzIz +LmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBMSU5FLUhFSUdIVDogMjFw +eDsgUEFERElORy1UT1A6IDBweDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91 +bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxlPSLlnKhXaW5kb3dzIEF6dXJl5bmz5Y+w5LiK +6YOo572y5pyN5YqhIiBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjog +bm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDgxKTsgDQogIGhyZWY9Imh0dHA6 +Ly9ibG9nLmNzZG4ubmV0L2F6dXJlY2hpbmEvYXJjaGl2ZS8yMDEwLzA1LzE2LzU1OTc2NTguYXNw +eCI+5ZyoV2luZG93cyANCiAgQXp1cmXlubPlj7DkuIrpg6jnvbLmnI3liqE8L0E+PC9ERD4NCiAg +PEREIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAz +cHggN3B4OyBQQURESU5HLUxFRlQ6IDE0cHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8v +Y3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMyMy5naWYpOyBQQURESU5HLUJPVFRP +TTogMHB4OyBNQVJHSU46IDBweDsgTElORS1IRUlHSFQ6IDIxcHg7IFBBRERJTkctVE9QOiAwcHg7 +IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxB +IA0KICB0aXRsZT0iV2luZG93cyBBenVyZSBDbG91ZFBvbGwgZm9yIEZhY2Vib29r5Y+R5biDIiAN +CiAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBv +bmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw4MSk7IA0KICBocmVmPSJodHRwOi8vYmxvZy5jc2Ru +Lm5ldC9henVyZWNoaW5hL2FyY2hpdmUvMjAxMC8wNS8xNi81NTk3NjYyLmFzcHgiPldpbmRvd3Mg +DQogIEF6dXJlIENsb3VkUG9sbCBmb3I8L0E+PC9ERD4NCiAgPEREIA0KICBzdHlsZT0iUEFERElO +Ry1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAzcHggN3B4OyBQQURESU5HLUxFRlQ6 +IDE0cHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2Vz +L2NzZG5pbmRleF9waWMyMy5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweDsg +TElORS1IRUlHSFQ6IDIxcHg7IFBBRERJTkctVE9QOiAwcHg7IGJhY2tncm91bmQtb3JpZ2luOiBp +bml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0aXRsZT0iVGFibGUgU3Rv +cmFnZeWvueWIhumhteeahOaUr+aMgSIgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURF +Q09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw4MSk7IA0KICBo +cmVmPSJodHRwOi8vYmxvZy5jc2RuLm5ldC9henVyZWNoaW5hL2FyY2hpdmUvMjAxMC8wNS8xNi81 +NTk3NjQyLmFzcHgiPlRhYmxlIA0KICBTdG9yYWdl5a+55YiG6aG155qE5pSv5oyBPC9BPjwvREQ+ +DQogIDxERCANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElP +TjogM3B4IDdweDsgUEFERElORy1MRUZUOiAxNHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0 +cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMjMuZ2lmKTsgUEFERElORy1C +T1RUT006IDBweDsgTUFSR0lOOiAwcHg7IExJTkUtSEVJR0hUOiAyMXB4OyBQQURESU5HLVRPUDog +MHB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFs +Ij48QSANCiAgdGl0bGU95aaC5L2V6YCJ5oup6Jma5ouf5py66KeE5qC8IHN0eWxlPSJDT0xPUjog +cmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0Nv +dW50KHRoaXMsODEpOyANCiAgaHJlZj0iaHR0cDovL2Jsb2cuY3Nkbi5uZXQvYXp1cmVjaGluYS9h +cmNoaXZlLzIwMTAvMDUvMTYvNTU5NzYzMS5hc3B4Ij7lpoLkvZXpgInmi6nomZrmi5/mnLrop4Tm +oLw8L0E+PC9ERD4NCiAgPEREIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JP +VU5ELVBPU0lUSU9OOiAzcHggN3B4OyBQQURESU5HLUxFRlQ6IDE0cHg7IEJBQ0tHUk9VTkQtSU1B +R0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMyMy5naWYp +OyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweDsgTElORS1IRUlHSFQ6IDIxcHg7IFBB +RERJTkctVE9QOiAwcHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNs +aXA6IGluaXRpYWwiPjxBIA0KICB0aXRsZT3lvIDlj5Hmi5PlsZXmkJzntKIt5pWR5o+05bqU55So +56iL5bqPIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiAN +CiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsODEpOyANCiAgaHJlZj0iaHR0cDovL2Jsb2cu +Y3Nkbi5uZXQvYXp1cmVjaGluYS9hcmNoaXZlLzIwMTAvMDUvMTYvNTU5NzYyMy5hc3B4Ij7lvIDl +j5Hmi5PlsZXmkJzntKIt5pWR5o+05bqU55So56iL5bqPPC9BPjwvREQ+DQogIDxERCANCiAgc3R5 +bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogM3B4IDdweDsgUEFE +RElORy1MRUZUOiAxNHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24v +d3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMjMuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFS +R0lOOiAwcHg7IExJTkUtSEVJR0hUOiAyMXB4OyBQQURESU5HLVRPUDogMHB4OyBiYWNrZ3JvdW5k +LW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgdGl0bGU9 +IueOsOWunuS4lueVjOeahFdpbmRvd3MgQXp1cmUiIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsg +VEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsODEp +OyANCiAgaHJlZj0iaHR0cDovL2Jsb2cuY3Nkbi5uZXQvYXp1cmVjaGluYS9hcmNoaXZlLzIwMTAv +MDUvMTYvNTU5NzYyMC5hc3B4Ij7njrDlrp7kuJbnlYznmoRXaW5kb3dzIA0KICBBenVyZTwvQT48 +L0REPjwvREw+DQo8SDMgDQpzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBP +U0lUSU9OOiAwcHggMHB4OyBESVNQTEFZOiBpbmxpbmU7IFBBRERJTkctTEVGVDogMjBweDsgRk9O +VC1TSVpFOiAxNHB4OyBGTE9BVDogbGVmdDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9j +c2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzE1LmdpZik7IFBBRERJTkctQk9UVE9N +OiAwcHg7IE1BUkdJTjogMHB4IDBweCA3cHg7IFdJRFRIOiAyMzlweDsgTElORS1IRUlHSFQ6IDMw +cHg7IFBBRERJTkctVE9QOiAwcHg7IFBPU0lUSU9OOiByZWxhdGl2ZTsgYmFja2dyb3VuZC1vcmln +aW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PFNQQU4gDQpjbGFzcz0idHh0 +XzEyIHR4dF9ncmF5IiANCnN0eWxlPSJGT05ULVdFSUdIVDogbm9ybWFsOyBGT05ULVNJWkU6IDEy +cHg7IEZMT0FUOiByaWdodDsgTUFSR0lOOiAycHggN3B4IDBweCAwcHg7IENPTE9SOiByZ2IoMTAy +LDEwMiwxMDIpIj48QSANCnN0eWxlPSJDT0xPUjogcmdiKDEwMiwxMDIsMTAyKTsgVEVYVC1ERUNP +UkFUSU9OOiBub25lIiANCmhyZWY9Imh0dHA6Ly9jdG8uY3Nkbi5uZXQvIj7mm7TlpJo8L0E+PC9T +UEFOPkNUT+S/seS5kOmDqDwvSDM+DQo8REwgY2xhc3M9Y3Rvc2hvdyANCnN0eWxlPSJQQURESU5H +LVJJR0hUOiAwcHg7IERJU1BMQVk6IGlubGluZTsgUEFERElORy1MRUZUOiAwcHg7IEZMT0FUOiBs +ZWZ0OyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweCAxMHB4OyBXSURUSDogMjM5cHg7 +IFBBRERJTkctVE9QOiAwcHgiPg0KICA8RFQgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7 +IEJBQ0tHUk9VTkQtUE9TSVRJT046IDUwJSAxMDAlOyBQQURESU5HLUxFRlQ6IDBweDsgQkFDS0dS +T1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3Bp +YzE0LmdpZik7IFBBRERJTkctQk9UVE9NOiAzcHg7IE1BUkdJTjogMHB4IDBweCA1cHg7IFBBRERJ +TkctVE9QOiAwcHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6 +IGluaXRpYWwiPuasoui/juWkp+WutuWKoOWFpUNUT+S/seS5kOmDqCzov5nmmK/pnaLlkJHpq5jn +q6/mioDmnK/nrqHnkIbogIXnmoTnpL7ljLrjgII8RU0gDQogIGNsYXNzPXR4dF9ibHVlIHN0eWxl +PSJDT0xPUjogcmdiKDEsOTUsMTgyKTsgRk9OVC1TVFlMRTogbm9ybWFsIj48QSANCiAgc3R5bGU9 +IkNPTE9SOiByZ2IoMSw5NSwxODIpOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNr +PUxvZ0NsaWNrQ291bnQodGhpcyw4Myk7IGhyZWY9Imh0dHA6Ly9jdG8uY3Nkbi5uZXQvIiANCiAg +dGFyZ2V0PV9ibGFuaz5b5oiR6KaB5Yqg5YWlXTwvQT48L0VNPjwvRFQ+DQogIDxERCANCiAgc3R5 +bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogM3B4IDdweDsgUEFE +RElORy1MRUZUOiAxNHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24v +d3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMjMuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFS +R0lOOiAwcHg7IExJTkUtSEVJR0hUOiAyMXB4OyBQQURESU5HLVRPUDogMHB4OyBiYWNrZ3JvdW5k +LW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj5bMeS6uuWbnuWkjV08 +QSANCiAgY2xhc3M9dHh0X2JsdWUgdGl0bGU95YWz5LqO6ICB5aSW5a6e55So55qE5Y6L57yp6L2v +5Lu26Zeu6aKYIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBQQURESU5HLUxFRlQ6IDNw +eDsgUEFERElORy1CT1RUT006IDBweDsgQ09MT1I6IHJnYigxLDk1LDE4Mik7IFBBRERJTkctVE9Q +OiAwcHg7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0 +aGlzLDgzKTsgDQogIGhyZWY9Imh0dHA6Ly9jdG8uY3Nkbi5uZXQvSG90X0Rpc2N1c3MuYXNweD9O +YW1lPXlhbmd6aGl3dSZhbXA7cG9pbnRpZD00MTE1IiANCiAgdGFyZ2V0PV9ibGFuaz7lhbPkuo7o +gIHlpJblrp7nlKjnmoTljovnvKnova/ku7bpl67popg8L0E+PC9ERD4NCiAgPEREIA0KICBzdHls +ZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAzcHggN3B4OyBQQURE +SU5HLUxFRlQ6IDE0cHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93 +d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMyMy5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJH +SU46IDBweDsgTElORS1IRUlHSFQ6IDIxcHg7IFBBRERJTkctVE9QOiAwcHg7IGJhY2tncm91bmQt +b3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPlsxNOS6uuWbnuWkjV08 +QSANCiAgY2xhc3M9dHh0X2JsdWUgdGl0bGU95b285b6X5b636bKB5YWL44CK566h55CG55qE5a6e +6Le144CL5pyt6K6wIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBQQURESU5HLUxFRlQ6 +IDNweDsgUEFERElORy1CT1RUT006IDBweDsgQ09MT1I6IHJnYigxLDk1LDE4Mik7IFBBRERJTkct +VE9QOiAwcHg7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3Vu +dCh0aGlzLDgzKTsgDQogIGhyZWY9Imh0dHA6Ly9jdG8uY3Nkbi5uZXQvSG90X0Rpc2N1c3MuYXNw +eD9OYW1lPWZlbmdndW94aW4mYW1wO3BvaW50aWQ9NDA4MCIgDQogIHRhcmdldD1fYmxhbms+5b28 +5b6X5b636bKB5YWL44CK566h55CG55qE5a6e6Le144CL5pytPC9BPjwvREQ+DQogIDxERCANCiAg +c3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogM3B4IDdweDsg +UEFERElORy1MRUZUOiAxNHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcu +Y24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMjMuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsg +TUFSR0lOOiAwcHg7IExJTkUtSEVJR0hUOiAyMXB4OyBQQURESU5HLVRPUDogMHB4OyBiYWNrZ3Jv +dW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj5bMTHkurrlm57l +pI1dPEEgDQogIGNsYXNzPXR4dF9ibHVlIHRpdGxlPei/kOiQpeexu+mhueebruS9nOS4uuWIm+S4 +muaAp+mhueebruavlOi+g+mAguWQiCANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgUEFE +RElORy1MRUZUOiAzcHg7IFBBRERJTkctQk9UVE9NOiAwcHg7IENPTE9SOiByZ2IoMSw5NSwxODIp +OyBQQURESU5HLVRPUDogMHB4OyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxv +Z0NsaWNrQ291bnQodGhpcyw4Myk7IA0KICBocmVmPSJodHRwOi8vY3RvLmNzZG4ubmV0L0hvdF9E +aXNjdXNzLmFzcHg/TmFtZT1sY25zeSZhbXA7cG9pbnRpZD00MDg3IiANCiAgdGFyZ2V0PV9ibGFu +az7ov5DokKXnsbvpobnnm67kvZzkuLrliJvkuJrmgKfpobnnm67mr5Q8L0E+PC9ERD4NCiAgPERE +IA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAzcHgg +N3B4OyBQQURESU5HLUxFRlQ6IDE0cHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3Nk +bmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMyMy5naWYpOyBQQURESU5HLUJPVFRPTTog +MHB4OyBNQVJHSU46IDBweDsgTElORS1IRUlHSFQ6IDIxcHg7IFBBRERJTkctVE9QOiAwcHg7IGJh +Y2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPlsz5Lq6 +5Zue5aSNXTxBIA0KICBjbGFzcz10eHRfYmx1ZSB0aXRsZT3lnKjnu4bliIbluILlnLrkuK3lr7vm +ib7liJvkuJrmnLrkvJogDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IFBBRERJTkctTEVG +VDogM3B4OyBQQURESU5HLUJPVFRPTTogMHB4OyBDT0xPUjogcmdiKDEsOTUsMTgyKTsgUEFERElO +Ry1UT1A6IDBweDsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0Nv +dW50KHRoaXMsODMpOyANCiAgaHJlZj0iaHR0cDovL2N0by5jc2RuLm5ldC9Ib3RfRGlzY3Vzcy5h +c3B4P05hbWU9bGNuc3kmYW1wO3BvaW50aWQ9NDExMiIgDQogIHRhcmdldD1fYmxhbms+5Zyo57uG +5YiG5biC5Zy65Lit5a+75om+5Yib5Lia5py65LyaPC9BPjwvREQ+DQogIDxERCANCiAgc3R5bGU9 +IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogM3B4IDdweDsgUEFERElO +Ry1MRUZUOiAxNHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3 +L2ltYWdlcy9jc2RuaW5kZXhfcGljMjMuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lO +OiAwcHg7IExJTkUtSEVJR0hUOiAyMXB4OyBQQURESU5HLVRPUDogMHB4OyBiYWNrZ3JvdW5kLW9y +aWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj5bMuS6uuWbnuWkjV08QSAN +CiAgY2xhc3M9dHh0X2JsdWUgdGl0bGU95a+75rGC6L2v5Lu25LiA5qy+fiANCiAgc3R5bGU9IlBB +RERJTkctUklHSFQ6IDBweDsgUEFERElORy1MRUZUOiAzcHg7IFBBRERJTkctQk9UVE9NOiAwcHg7 +IENPTE9SOiByZ2IoMSw5NSwxODIpOyBQQURESU5HLVRPUDogMHB4OyBURVhULURFQ09SQVRJT046 +IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw4Myk7IA0KICBocmVmPSJodHRw +Oi8vY3RvLmNzZG4ubmV0L0hvdF9EaXNjdXNzLmFzcHg/TmFtZT16aGFuZy1jaGVuZyZhbXA7cG9p +bnRpZD00MTA0IiANCiAgdGFyZ2V0PV9ibGFuaz7lr7vmsYLova/ku7bkuIDmrL5+PC9BPjwvREQ+ +DQogIDxERCANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElP +TjogM3B4IDdweDsgUEFERElORy1MRUZUOiAxNHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0 +cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMjMuZ2lmKTsgUEFERElORy1C +T1RUT006IDBweDsgTUFSR0lOOiAwcHg7IExJTkUtSEVJR0hUOiAyMXB4OyBQQURESU5HLVRPUDog +MHB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFs +Ij5bODLkurrlm57lpI1dPEEgDQogIGNsYXNzPXR4dF9ibHVlIHRpdGxlPTEx5pyIMjXml6XmiYvm +nLrlrqLmiLfnq6/kuJPlp5TkvJrljJfkuqzmtLvliqjlhY3otLnmiqXlkI3lj4LliqDvvJroi7Hn +ibnlsJTnm7jlhbPotJ/otKPkurrliIbkuqtNZWVHb+aImOeVpeWPkeWxleaWueWQkeWPiuS9k+ez +u+aetuaehOWSjOaKgOacryANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgUEFERElORy1M +RUZUOiAzcHg7IFBBRERJTkctQk9UVE9NOiAwcHg7IENPTE9SOiByZ2IoMSw5NSwxODIpOyBQQURE +SU5HLVRPUDogMHB4OyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNr +Q291bnQodGhpcyw4Myk7IA0KICBocmVmPSJodHRwOi8vY3RvLmNzZG4ubmV0L0hvdF9EaXNjdXNz +LmFzcHg/TmFtZT1hZG1pbiZhbXA7cG9pbnRpZD00MDQ2IiANCiAgdGFyZ2V0PV9ibGFuaz4xMeac +iDI15pel5omL5py65a6i5oi356uv5LiT5aeUPC9BPjwvREQ+DQogIDxERCANCiAgc3R5bGU9IlBB +RERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogM3B4IDdweDsgUEFERElORy1M +RUZUOiAxNHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2lt +YWdlcy9jc2RuaW5kZXhfcGljMjMuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAw +cHg7IExJTkUtSEVJR0hUOiAyMXB4OyBQQURESU5HLVRPUDogMHB4OyBiYWNrZ3JvdW5kLW9yaWdp +bjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj5bMOS6uuWbnuWkjV08QSANCiAg +Y2xhc3M9dHh0X2JsdWUgdGl0bGU95Lit5bWM5Y2P5Lya56ys5Zub5pyf4oCc5bWM5YWl5byP5LiO +54mp6IGU572R4oCd5Li76aKY6K665Z2b5bCG5LqOMTLmnIgyNeaXpeWcqOWMl+S6rOS4vuihjCAN +CiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgUEFERElORy1MRUZUOiAzcHg7IFBBRERJTkct +Qk9UVE9NOiAwcHg7IENPTE9SOiByZ2IoMSw5NSwxODIpOyBQQURESU5HLVRPUDogMHB4OyBURVhU +LURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw4Myk7IA0K +ICBocmVmPSJodHRwOi8vY3RvLmNzZG4ubmV0L0hvdF9EaXNjdXNzLmFzcHg/TmFtZT1jZXNpYSZh +bXA7cG9pbnRpZD00MTE4IiANCiAgdGFyZ2V0PV9ibGFuaz7kuK3ltYzljY/kvJrnrKzlm5vmnJ/i +gJzltYzlhaXlvI/kuI7niak8L0E+PC9ERD4NCiAgPEREIA0KICBzdHlsZT0iUEFERElORy1SSUdI +VDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAzcHggN3B4OyBQQURESU5HLUxFRlQ6IDE0cHg7 +IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5p +bmRleF9waWMyMy5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweDsgTElORS1I +RUlHSFQ6IDIxcHg7IFBBRERJTkctVE9QOiAwcHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFs +OyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPls05Lq65Zue5aSNXTxBIA0KICBjbGFzcz10eHRf +Ymx1ZSB0aXRsZT3igJzkupHorqHnrpfigJ3lupTkuI3lupTor6XmmI7noa7op4TojIMgDQogIHN0 +eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IFBBRERJTkctTEVGVDogM3B4OyBQQURESU5HLUJPVFRP +TTogMHB4OyBDT0xPUjogcmdiKDEsOTUsMTgyKTsgUEFERElORy1UT1A6IDBweDsgVEVYVC1ERUNP +UkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsODMpOyANCiAgaHJl +Zj0iaHR0cDovL2N0by5jc2RuLm5ldC9Ib3RfRGlzY3Vzcy5hc3B4P05hbWU9ZnVkb25nc2hlbmcm +YW1wO3BvaW50aWQ9NDA4MyIgDQogIHRhcmdldD1fYmxhbms+4oCc5LqR6K6h566X4oCd5bqU5LiN +5bqU6K+l5piO56Gu6KeE6IyDPC9BPjwvREQ+PC9ETD4NCjxIMyANCnN0eWxlPSJQQURESU5HLVJJ +R0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDBweCAwcHg7IERJU1BMQVk6IGlubGluZTsg +UEFERElORy1MRUZUOiAyMHB4OyBGT05ULVNJWkU6IDE0cHg7IEZMT0FUOiBsZWZ0OyBCQUNLR1JP +VU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGlj +MTUuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHggMHB4IDdweDsgV0lEVEg6 +IDIzOXB4OyBMSU5FLUhFSUdIVDogMzBweDsgUEFERElORy1UT1A6IDBweDsgUE9TSVRJT046IHJl +bGF0aXZlOyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0 +aWFsIj48U1BBTiANCmNsYXNzPSJ0eHRfMTIgdHh0X2dyYXkiIA0Kc3R5bGU9IkZPTlQtV0VJR0hU +OiBub3JtYWw7IEZPTlQtU0laRTogMTJweDsgRkxPQVQ6IHJpZ2h0OyBNQVJHSU46IDJweCA3cHgg +MHB4IDBweDsgQ09MT1I6IHJnYigxMDIsMTAyLDEwMikiPjxBIA0Kc3R5bGU9IkNPTE9SOiByZ2Io +MTAyLDEwMiwxMDIpOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KaHJlZj0iaHR0cDovL2Jsb2cu +Y3Nkbi5uZXQvIj7mm7TlpJo8L0E+PC9TUEFOPueDreaWh+aOkuihjDwvSDM+DQo8REwgY2xhc3M9 +InN0eWxlMiB0eHRfYmxhY2siIA0Kc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgRElTUExBWTog +aW5saW5lOyBQQURESU5HLUxFRlQ6IDBweDsgRkxPQVQ6IGxlZnQ7IFBBRERJTkctQk9UVE9NOiAw +cHg7IE1BUkdJTjogNXB4IDEwcHg7IFdJRFRIOiAyMzlweDsgQ09MT1I6IHJnYigwLDAsMCk7IFBB +RERJTkctVE9QOiAwcHgiPg0KICA8RFQgY2xhc3M9dG9wMSANCiAgc3R5bGU9IlBBRERJTkctUklH +SFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMHB4IDNweDsgT1ZFUkZMT1ctWTogaGlkZGVu +OyBQQURESU5HLUxFRlQ6IDI0cHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3Nkbmlt +Zy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMzNS5naWYpOyBPVkVSRkxPVy1YOiBoaWRkZW47 +IFBBRERJTkctQk9UVE9NOiAxcHg7IE1BUkdJTjogMHB4OyBXSURUSDogMjEwcHg7IFBBRERJTkct +VE9QOiA0cHg7IFdISVRFLVNQQUNFOiBub3dyYXA7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFs +OyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0aXRsZT3pnaLlkJHnqIvluo/lkZjn +moTmlbDmja7lupPorr/pl67mgKfog73kvJjljJbms5XliJkgc3R5bGU9IkNPTE9SOiByZ2IoMCww +LDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhp +cyw4Mik7IA0KICBocmVmPSJodHRwOi8vYmxvZy5jc2RuLm5ldC95enNpbmQvYXJjaGl2ZS8yMDEw +LzEyLzA2LzYwNTkyMDkuYXNweCIgDQogIHRhcmdldD1fYmxhbms+6Z2i5ZCR56iL5bqP5ZGY55qE +5pWw5o2u5bqT6K6/6Zeu5oCn6IO95LyY5YyW5rOV5YiZPC9BPjwvRFQ+DQogIDxEVCBjbGFzcz10 +b3AyIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAw +cHggM3B4OyBPVkVSRkxPVy1ZOiBoaWRkZW47IFBBRERJTkctTEVGVDogMjRweDsgQkFDS0dST1VO +RC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzM2 +LmdpZik7IE9WRVJGTE9XLVg6IGhpZGRlbjsgUEFERElORy1CT1RUT006IDFweDsgTUFSR0lOOiAw +cHg7IFdJRFRIOiAyMTBweDsgUEFERElORy1UT1A6IDRweDsgV0hJVEUtU1BBQ0U6IG5vd3JhcDsg +YmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEg +DQogIHRpdGxlPSLpobbnuqfnqIvluo/lkZjnmoTlv4PlvpcgLSBDb2RlcnMgYXQgV29yayIgDQog +IHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25j +bGljaz1Mb2dDbGlja0NvdW50KHRoaXMsODIpOyANCiAgaHJlZj0iaHR0cDovL2Jsb2cuY3Nkbi5u +ZXQvU29mdHdhcmVUZWFjaGVyL2FyY2hpdmUvMjAxMC8xMS8yNy82MDM5OTAxLmFzcHgiIA0KICB0 +YXJnZXQ9X2JsYW5rPumhtue6p+eoi+W6j+WRmOeahOW/g+W+lyAtIENvZGVycyBhdCBXb3JrPC9B +PjwvRFQ+DQogIDxEVCBjbGFzcz10b3AzIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBC +QUNLR1JPVU5ELVBPU0lUSU9OOiAwcHggM3B4OyBPVkVSRkxPVy1ZOiBoaWRkZW47IFBBRERJTkct +TEVGVDogMjRweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9p +bWFnZXMvY3NkbmluZGV4X3BpYzM3LmdpZik7IE9WRVJGTE9XLVg6IGhpZGRlbjsgUEFERElORy1C +T1RUT006IDFweDsgTUFSR0lOOiAwcHg7IFdJRFRIOiAyMTBweDsgUEFERElORy1UT1A6IDRweDsg +V0hJVEUtU1BBQ0U6IG5vd3JhcDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91 +bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxlPUxpbnV4546v5aKD5LiL55qEQy9DKyvln7rn +oYDosIPor5XmioDmnK8x4oCU4oCU5Yid5q2l5LqG6KejIA0KICBzdHlsZT0iQ09MT1I6IHJnYigw +LDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0 +aGlzLDgyKTsgDQogIGhyZWY9Imh0dHA6Ly9ibG9nLmNzZG4ubmV0L2dudWhwYy9hcmNoaXZlLzIw +MTAvMTIvMDMvNjA1MTg2Ny5hc3B4IiANCiAgdGFyZ2V0PV9ibGFuaz5MaW51eOeOr+Wig+S4i+ea +hEMvQysr5Z+656GA6LCD6K+V5oqA5pyvMeKAlOKAlOWIneatpeS6huinozwvQT48L0RUPg0KICA8 +RFQgY2xhc3M9dG9wNCANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1Q +T1NJVElPTjogMHB4IDNweDsgT1ZFUkZMT1ctWTogaGlkZGVuOyBQQURESU5HLUxFRlQ6IDI0cHg7 +IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5p +bmRleF9waWMzOC5naWYpOyBPVkVSRkxPVy1YOiBoaWRkZW47IFBBRERJTkctQk9UVE9NOiAxcHg7 +IE1BUkdJTjogMHB4OyBXSURUSDogMjEwcHg7IFBBRERJTkctVE9QOiA0cHg7IFdISVRFLVNQQUNF +OiBub3dyYXA7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGlu +aXRpYWwiPjxBIA0KICB0aXRsZT0yMDEw5bm077yMTGludXjlpKfkuovorrAgc3R5bGU9IkNPTE9S +OiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNr +Q291bnQodGhpcyw4Mik7IA0KICBocmVmPSJodHRwOi8vYmxvZy5jc2RuLm5ldC95dWFubWVuZzAw +MS9hcmNoaXZlLzIwMTAvMTIvMDEvNjA0NjgyNi5hc3B4IiANCiAgdGFyZ2V0PV9ibGFuaz4yMDEw +5bm077yMTGludXjlpKfkuovorrA8L0E+PC9EVD4NCiAgPERUIGNsYXNzPXRvcDUgDQogIHN0eWxl +PSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDBweCAzcHg7IE9WRVJG +TE9XLVk6IGhpZGRlbjsgUEFERElORy1MRUZUOiAyNHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwo +aHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMzkuZ2lmKTsgT1ZFUkZM +T1ctWDogaGlkZGVuOyBQQURESU5HLUJPVFRPTTogMXB4OyBNQVJHSU46IDBweDsgV0lEVEg6IDIx +MHB4OyBQQURESU5HLVRPUDogNHB4OyBXSElURS1TUEFDRTogbm93cmFwOyBiYWNrZ3JvdW5kLW9y +aWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgdGl0bGU95b6B +5Y+L5ZCv5LqL5q2j5paHIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9O +OiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsODIpOyANCiAgaHJlZj0iaHR0 +cDovL2Jsb2cuY3Nkbi5uZXQveGlhb3hpYW95dW5kdW8vYXJjaGl2ZS8yMDEwLzEyLzAyLzYwNTEz +NjUuYXNweCIgDQogIHRhcmdldD1fYmxhbms+5b6B5Y+L5ZCv5LqL5q2j5paHPC9BPjwvRFQ+DQog +IDxEVCBjbGFzcz10b3A2IA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5E +LVBPU0lUSU9OOiAwcHggM3B4OyBPVkVSRkxPVy1ZOiBoaWRkZW47IFBBRERJTkctTEVGVDogMjRw +eDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3Nk +bmluZGV4X3BpYzQwLmdpZik7IE9WRVJGTE9XLVg6IGhpZGRlbjsgUEFERElORy1CT1RUT006IDFw +eDsgTUFSR0lOOiAwcHg7IFdJRFRIOiAyMTBweDsgUEFERElORy1UT1A6IDRweDsgV0hJVEUtU1BB +Q0U6IG5vd3JhcDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDog +aW5pdGlhbCI+PEEgDQogIHRpdGxlPSJsb2FkcnVubmVy5LitIHRoaW5rdGltZSDlpoLkvZXov5Dn +lKjpmo/mnLrml7bpl7TvvIzlubbopoHmiorml7bpl7TlrprlnKjmr6vnp5LnuqciIA0KICBzdHls +ZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9 +TG9nQ2xpY2tDb3VudCh0aGlzLDgyKTsgDQogIGhyZWY9Imh0dHA6Ly9ibG9nLmNzZG4ubmV0L25h +bWVzbGl1L2FyY2hpdmUvMjAxMC8xMS8zMC82MDQ0Mjk1LmFzcHgiIA0KICB0YXJnZXQ9X2JsYW5r +PmxvYWRydW5uZXLkuK0gdGhpbmt0aW1lIOWmguS9lei/kOeUqOmaj+acuuaXtumXtO+8jOW5tuim +geaKiuaXtumXtOWumuWcqOavq+enkue6pzwvQT48L0RUPg0KICA8RFQgY2xhc3M9dG9wNyANCiAg +c3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMHB4IDNweDsg +T1ZFUkZMT1ctWTogaGlkZGVuOyBQQURESU5HLUxFRlQ6IDI0cHg7IEJBQ0tHUk9VTkQtSU1BR0U6 +IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWM0MS5naWYpOyBP +VkVSRkxPVy1YOiBoaWRkZW47IFBBRERJTkctQk9UVE9NOiAxcHg7IE1BUkdJTjogMHB4OyBXSURU +SDogMjEwcHg7IFBBRERJTkctVE9QOiA0cHg7IFdISVRFLVNQQUNFOiBub3dyYXA7IGJhY2tncm91 +bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0aXRs +ZT0ibGludXgg5LiL5Y+W6L+b56iL5Y2g55SoIGNwdS/lhoXlrZgg5pyA6auY55qE5YmNMTDkuKro +v5vnqIsiIA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9u +ZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDgyKTsgDQogIGhyZWY9Imh0dHA6Ly9i +bG9nLmNzZG4ubmV0L25hbWVzbGl1L2FyY2hpdmUvMjAxMC8xMS8yNi82MDM3OTcyLmFzcHgiIA0K +ICB0YXJnZXQ9X2JsYW5rPmxpbnV4IOS4i+WPlui/m+eoi+WNoOeUqCBjcHUv5YaF5a2YIOacgOmr +mOeahOWJjTEw5Liq6L+b56iLPC9BPjwvRFQ+DQogIDxEVCBjbGFzcz10b3A4IA0KICBzdHlsZT0i +UEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAwcHggM3B4OyBPVkVSRkxP +Vy1ZOiBoaWRkZW47IFBBRERJTkctTEVGVDogMjRweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0 +dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzQyLmdpZik7IE9WRVJGTE9X +LVg6IGhpZGRlbjsgUEFERElORy1CT1RUT006IDFweDsgTUFSR0lOOiAwcHg7IFdJRFRIOiAyMTBw +eDsgUEFERElORy1UT1A6IDRweDsgV0hJVEUtU1BBQ0U6IG5vd3JhcDsgYmFja2dyb3VuZC1vcmln +aW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxlPWphdmHn +n6Xor4bngrnlpoLkvZXkuLLmjqUgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09S +QVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw4Mik7IA0KICBocmVm +PSJodHRwOi8vYmxvZy5jc2RuLm5ldC9iaXRmYW4vYXJjaGl2ZS8yMDEwLzEyLzAzLzYwNTIzMTAu +YXNweCIgDQogIHRhcmdldD1fYmxhbms+amF2YeefpeivhueCueWmguS9leS4suaOpTwvQT48L0RU +Pg0KICA8RFQgY2xhc3M9dG9wOSANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dS +T1VORC1QT1NJVElPTjogMHB4IDNweDsgT1ZFUkZMT1ctWTogaGlkZGVuOyBQQURESU5HLUxFRlQ6 +IDI0cHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2Vz +L2NzZG5pbmRleF9waWM0My5naWYpOyBPVkVSRkxPVy1YOiBoaWRkZW47IFBBRERJTkctQk9UVE9N +OiAxcHg7IE1BUkdJTjogMHB4OyBXSURUSDogMjEwcHg7IFBBRERJTkctVE9QOiA0cHg7IFdISVRF +LVNQQUNFOiBub3dyYXA7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNs +aXA6IGluaXRpYWwiPjxBIA0KICB0aXRsZT3moqbmg7PljYHlubQtLeOAiueoi+W6j+WRmOOAi+WN +geW5tOaEn+aDsyBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9u +ZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDgyKTsgDQogIGhyZWY9Imh0dHA6Ly9i +bG9nLmNzZG4ubmV0L2ppYW5ndGFvL2FyY2hpdmUvMjAxMC8xMS8xOC82MDE4NTY0LmFzcHgiIA0K +ICB0YXJnZXQ9X2JsYW5rPuaipuaDs+WNgeW5tC0t44CK56iL5bqP5ZGY44CL5Y2B5bm05oSf5oOz +PC9BPjwvRFQ+DQogIDxEVCBjbGFzcz10b3AxMCANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBw +eDsgQkFDS0dST1VORC1QT1NJVElPTjogMHB4IDNweDsgT1ZFUkZMT1ctWTogaGlkZGVuOyBQQURE +SU5HLUxFRlQ6IDI0cHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93 +d3cvaW1hZ2VzL2NzZG5pbmRleF9waWM0NC5naWYpOyBPVkVSRkxPVy1YOiBoaWRkZW47IFBBRERJ +TkctQk9UVE9NOiAxcHg7IE1BUkdJTjogMHB4OyBXSURUSDogMjEwcHg7IFBBRERJTkctVE9QOiA0 +cHg7IFdISVRFLVNQQUNFOiBub3dyYXA7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNr +Z3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0aXRsZT3miJHku6zkuLrku4DkuYjkuI3llpzm +rKLmi5vogZjln7norq3lrabmoKHnmoTlrabnlJ/vvJ8gc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDAp +OyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw4 +Mik7IA0KICBocmVmPSJodHRwOi8vYmxvZy5jc2RuLm5ldC9jaGdhb3dlaS9hcmNoaXZlLzIwMTAv +MTEvMTYvNjAxMzU1NC5hc3B4IiANCiAgdGFyZ2V0PV9ibGFuaz7miJHku6zkuLrku4DkuYjkuI3l +lpzmrKLmi5vogZjln7norq3lrabmoKHnmoTlrabnlJ/vvJ88L0E+PC9EVD48L0RMPjwvRElWPjwv +RElWPjwvRElWPg0KPERJViBjbGFzcz1wYWdlY29uX2xheWVyMmJ0bSANCnN0eWxlPSJCQUNLR1JP +VU5ELVBPU0lUSU9OOiA1MCUgMTAwJTsgRk9OVC1TSVpFOiAxcHg7IEZMT0FUOiBsZWZ0OyBCQUNL +R1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhf +cGljNDUuZ2lmKTsgV0lEVEg6IDk2MHB4OyBIRUlHSFQ6IDFweDsgYmFja2dyb3VuZC1vcmlnaW46 +IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PC9ESVY+DQo8RElWPg0KPERJViBj +bGFzcz1idXNpbmVzc2FkIA0Kc3R5bGU9IkZMT0FUOiBsZWZ0OyBNQVJHSU46IDRweCAwcHggMHB4 +OyBXSURUSDogOTYwcHg7IFBPU0lUSU9OOiByZWxhdGl2ZTsgVEVYVC1BTElHTjogbGVmdCI+DQo8 +VUwgDQpzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBQQURESU5HLUxFRlQ6IDBweDsgRkxPQVQ6 +IGxlZnQ7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBXSURUSDogOTYwcHg7IFBB +RERJTkctVE9QOiAwcHg7IExJU1QtU1RZTEUtVFlQRTogbm9uZSI+DQogIDxMSSBjbGFzcz1sZWZ0 +YWQgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IFBBRERJTkctTEVGVDogMHB4OyBGTE9B +VDogbGVmdDsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IFdJRFRIOiA3MzVweDsg +UEFERElORy1UT1A6IDBweCI+PEEgDQogIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1E +RUNPUkFUSU9OOiBub25lIiANCiAgaHJlZj0iaHR0cDovL3ouY3Nkbi5uZXQvZ21jbGljay5waHA/ +YmFubmVyaWQ9NTQyNSZhbXA7em9uZWlkPTQwOSZhbXA7c291cmNlPSZhbXA7ZGVzdD1odHRwJTNB +JTJGJTJGd3d3LmNoaW5hLXB1Yi5jb20lMkZTVEFUSUMwNyUyRjEwMDklMkZqc2pfcWh3b3J4MV8x +MDA5MDkuYXNwIiANCiAgdGFyZ2V0PV9ibGFuaz48SU1HIHRpdGxlPSIiIA0KICBzdHlsZT0iQk9S +REVSLVRPUC1XSURUSDogMHB4OyBCT1JERVItTEVGVC1XSURUSDogMHB4OyBCT1JERVItQk9UVE9N +LVdJRFRIOiAwcHg7IEJPUkRFUi1SSUdIVC1XSURUSDogMHB4IiANCiAgaGVpZ2h0PTkwIGFsdD0i +IiANCiAgc3JjPSJodHRwOi8vaW5mby1kYXRhYmFzZS5jc2RuLm5ldC9VcGxvYWQvMjAxMC0xMi0w +OS83MzVfOTBfMTIwOS5qcGciIA0KICB3aWR0aD03MzUgYm9yZGVyPTA+PC9BPg0KICA8RElWIGlk +PWJlYWNvbl81NDI1IA0KICBzdHlsZT0iTEVGVDogMHB4OyBWSVNJQklMSVRZOiBoaWRkZW47IFBP +U0lUSU9OOiBhYnNvbHV0ZTsgVE9QOiAwcHgiPjxJTUcgDQogIHN0eWxlPSJCT1JERVItVE9QLVdJ +RFRIOiAwcHg7IEJPUkRFUi1MRUZULVdJRFRIOiAwcHg7IEJPUkRFUi1CT1RUT00tV0lEVEg6IDBw +eDsgV0lEVEg6IDBweDsgSEVJR0hUOiAwcHg7IEJPUkRFUi1SSUdIVC1XSURUSDogMHB4IiANCiAg +aGVpZ2h0PTAgYWx0PSIiIA0KICBzcmM9Imh0dHA6Ly96LmNzZG4ubmV0L2dtbG9nLnBocD9iYW5u +ZXJpZD01NDI1JmFtcDtjbGllbnRpZD0xNzA3JmFtcDt6Zj0mYW1wO3pvbmVpZD00MDkmYW1wO3Nv +dXJjZT0mYW1wO2Jsb2NrPTAmYW1wO2NhcHBpbmc9MCZhbXA7Y2I9NDRlZWY1Mzk2ZjBmNmU0ZDg1 +NGFjOWE4ODRjMjZkOGUiIA0KICB3aWR0aD0wPjwvRElWPjwvTEk+DQogIDxMSSBjbGFzcz1yaWdo +dGFkIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBQQURESU5HLUxFRlQ6IDBweDsgRkxP +QVQ6IHJpZ2h0OyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweDsgV0lEVEg6IDIxMHB4 +OyBQQURESU5HLVRPUDogMHB4Ij48QSANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhU +LURFQ09SQVRJT046IG5vbmUiIA0KICBocmVmPSJodHRwOi8vei5jc2RuLm5ldC9nbWNsaWNrLnBo +cD9iYW5uZXJpZD01MjcxJmFtcDt6b25laWQ9NDEwJmFtcDtzb3VyY2U9JmFtcDtkZXN0PWh0dHAl +M0ElMkYlMkZkaW5neXVlLnByb2dyYW1tZXIuY29tLmNuJTJGIiANCiAgdGFyZ2V0PV9ibGFuaz48 +SU1HIHRpdGxlPSIiIA0KICBzdHlsZT0iQk9SREVSLVRPUC1XSURUSDogMHB4OyBCT1JERVItTEVG +VC1XSURUSDogMHB4OyBCT1JERVItQk9UVE9NLVdJRFRIOiAwcHg7IEJPUkRFUi1SSUdIVC1XSURU +SDogMHB4IiANCiAgaGVpZ2h0PTkwIGFsdD0iIiANCiAgc3JjPSJodHRwOi8vaW5mby1kYXRhYmFz +ZS5jc2RuLm5ldC9VcGxvYWQvMjAxMC0xMC0yOS8yMTBfOTB6aGVuZ2RpbmduZXcuanBnIiANCiAg +d2lkdGg9MjEwIGJvcmRlcj0wPjwvQT4NCiAgPERJViBpZD1iZWFjb25fNTI3MSANCiAgc3R5bGU9 +IkxFRlQ6IDBweDsgVklTSUJJTElUWTogaGlkZGVuOyBQT1NJVElPTjogYWJzb2x1dGU7IFRPUDog +MHB4Ij48SU1HIA0KICBzdHlsZT0iQk9SREVSLVRPUC1XSURUSDogMHB4OyBCT1JERVItTEVGVC1X +SURUSDogMHB4OyBCT1JERVItQk9UVE9NLVdJRFRIOiAwcHg7IFdJRFRIOiAwcHg7IEhFSUdIVDog +MHB4OyBCT1JERVItUklHSFQtV0lEVEg6IDBweCIgDQogIGhlaWdodD0wIGFsdD0iIiANCiAgc3Jj +PSJodHRwOi8vei5jc2RuLm5ldC9nbWxvZy5waHA/YmFubmVyaWQ9NTI3MSZhbXA7Y2xpZW50aWQ9 +MTUxOCZhbXA7emY9JmFtcDt6b25laWQ9NDEwJmFtcDtzb3VyY2U9JmFtcDtibG9jaz0wJmFtcDtj +YXBwaW5nPTAmYW1wO2NiPWQ5MThmNDBlMmI4MzViOWUwNmY4NWNmZjRiOGMwZDliIiANCiAgd2lk +dGg9MD48L0RJVj48L0xJPjwvVUw+PC9ESVY+PC9ESVY+DQo8RElWIGNsYXNzPXBhZ2Vjb25fbGF5 +ZXIyIA0Kc3R5bGU9IkZMT0FUOiBsZWZ0OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2Nz +ZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMzMuZ2lmKTsgTUFSR0lOOiAzcHggMHB4 +IDBweDsgV0lEVEg6IDk2MHB4OyBQT1NJVElPTjogcmVsYXRpdmU7IFRFWFQtQUxJR046IGxlZnQ7 +IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPg0K +PERJViBjbGFzcz1wYWdlXzA5c2lkZWJhcndyYXAgDQpzdHlsZT0iUEFERElORy1SSUdIVDogMHB4 +OyBCT1JERVItVE9QOiByZ2IoMjA0LDIwNCwyMDQpIDFweCBzb2xpZDsgRElTUExBWTogaW5saW5l +OyBQQURESU5HLUxFRlQ6IDBweDsgRkxPQVQ6IHJpZ2h0OyBQQURESU5HLUJPVFRPTTogNnB4OyBN +QVJHSU46IDBweCAxcHggMHB4IDBweDsgV0lEVEg6IDIwOHB4OyBQQURESU5HLVRPUDogMHB4OyBU +RVhULUFMSUdOOiBsZWZ0Ij4NCjxESVYgY2xhc3M9c2lkZWJhcl9jb24gDQpzdHlsZT0iRElTUExB +WTogaW5saW5lOyBGTE9BVDogbGVmdDsgTUFSR0lOOiA2cHggM3B4IDJweDsgV0lEVEg6IDIwMnB4 +Ij4NCjxINCBjbGFzcz10eHRfMTIgDQpzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBQQURESU5H +LUxFRlQ6IDNweDsgRk9OVC1TSVpFOiAxMnB4OyBQQURESU5HLUJPVFRPTTogNXB4OyBNQVJHSU46 +IDBweDsgUEFERElORy1UT1A6IDBweDsgQk9SREVSLUJPVFRPTTogcmdiKDIwNCwyMDQsMjA0KSAx +cHggc29saWQ7IFBPU0lUSU9OOiByZWxhdGl2ZSI+PFNQQU4gDQpjbGFzcz10eHRfZ3JheSANCnN0 +eWxlPSJGT05ULVdFSUdIVDogbm9ybWFsOyBGTE9BVDogcmlnaHQ7IENPTE9SOiByZ2IoMTAyLDEw +MiwxMDIpIj58PEEgDQpzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBQQURESU5HLUxFRlQ6IDVw +eDsgUEFERElORy1CT1RUT006IDBweDsgQ09MT1I6IHJnYigxMDIsMTAyLDEwMik7IFBBRERJTkct +VE9QOiAwcHg7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQpocmVmPSJodHRwOi8vd3d3LmRlYXJi +b29rLmNvbS5jbi8iIHRhcmdldD1fYmxhbms+5pu05aSaPC9BPjwvU1BBTj7lm77kuabmjpLooYzm +ppw8L0g0Pg0KPERJViBjbGFzcz1ib29rc190YWIgDQpzdHlsZT0iUEFERElORy1SSUdIVDogMHB4 +OyBESVNQTEFZOiBpbmxpbmU7IFBBRERJTkctTEVGVDogMHB4OyBGTE9BVDogbGVmdDsgUEFERElO +Ry1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IFdJRFRIOiAyMDJweDsgUEFERElORy1UT1A6IDBw +eCI+DQo8VUwgDQpzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBQQURESU5HLUxFRlQ6IDBweDsg +UEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAycHggMHB4IDBweDsgUEFERElORy1UT1A6IDBw +eDsgTElTVC1TVFlMRS1UWVBFOiBub25lIj4NCiAgPExJIGlkPW1haW4yIA0KICBzdHlsZT0iUEFE +RElORy1SSUdIVDogMHB4OyBQQURESU5HLUxFRlQ6IDBweDsgUEFERElORy1CT1RUT006IDBweDsg +TUFSR0lOOiAwcHg7IFBBRERJTkctVE9QOiAwcHgiPg0KICA8RElWPg0KICA8REwgY2xhc3M9Ym9v +a3RvcCANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDNweDsgUEFERElORy1MRUZUOiAzcHg7IEZM +T0FUOiBsZWZ0OyBQQURESU5HLUJPVFRPTTogNXB4OyBNQVJHSU46IDJweCAwcHggMHB4OyBXSURU +SDogMTk2cHg7IFBBRERJTkctVE9QOiAxMHB4OyBCT1JERVItQk9UVE9NOiByZ2IoMjA0LDIwNCwy +MDQpIDFweCBzb2xpZDsgQkFDS0dST1VORC1DT0xPUjogcmdiKDI1NSwyNTUsMjU1KTsgYmFja2dy +b3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+DQogICAgPERU +IGNsYXNzPXRvcDEgDQogICAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1Q +T1NJVElPTjogMHB4IDNweDsgT1ZFUkZMT1ctWTogaGlkZGVuOyBQQURESU5HLUxFRlQ6IDIxcHg7 +IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5p +bmRleF9waWMzNS5naWYpOyBPVkVSRkxPVy1YOiBoaWRkZW47IFBBRERJTkctQk9UVE9NOiAzcHg7 +IE1BUkdJTjogMHB4OyBXSURUSDogMTcwcHg7IFBBRERJTkctVE9QOiAzcHg7IFdISVRFLVNQQUNF +OiBub3dyYXA7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGlu +aXRpYWwiPjxBIA0KICAgIHRpdGxlPUhhZG9vcOadg+WogeaMh+WNl++8iOS4reaWh+eJiO+8iSBz +dHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogICAgb25j +bGljaz1Mb2dDbGlja0NvdW50KHRoaXMsOTcpOyBocmVmPSJodHRwOi8vd3d3LmNoaW5hLXB1Yi5j +b20vMTk2MjAwIiANCiAgICB0YXJnZXQ9X2JsYW5rPkhhZG9vcOadg+WogeaMh+WNl++8iOS4reaW +h+eJiO+8iTwvQT48L0RUPg0KICAgIDxEVCBjbGFzcz10b3AyIA0KICAgIHN0eWxlPSJQQURESU5H +LVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDBweCAzcHg7IE9WRVJGTE9XLVk6IGhp +ZGRlbjsgUEFERElORy1MRUZUOiAyMXB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2Nz +ZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMzYuZ2lmKTsgT1ZFUkZMT1ctWDogaGlk +ZGVuOyBQQURESU5HLUJPVFRPTTogM3B4OyBNQVJHSU46IDBweDsgV0lEVEg6IDE3MHB4OyBQQURE +SU5HLVRPUDogM3B4OyBXSElURS1TUEFDRTogbm93cmFwOyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5p +dGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgICB0aXRsZT0i56iL5bqP5ZGY +KDIwMTDlubQxMuaciOWIiiDmgLvnrKwyMTjmnJ8pIiANCiAgICBzdHlsZT0iQ09MT1I6IHJnYigw +LDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogICAgb25jbGljaz1Mb2dDbGlja0NvdW50 +KHRoaXMsOTcpOyBocmVmPSJodHRwOi8vd3d3LmNoaW5hLXB1Yi5jb20vNTQxOTEiIA0KICAgIHRh +cmdldD1fYmxhbms+56iL5bqP5ZGYKDIwMTDlubQxMuaciOWIiiDmgLvnrKwyPC9BPjwvRFQ+DQog +ICAgPERUIGNsYXNzPXRvcDMgDQogICAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dS +T1VORC1QT1NJVElPTjogMHB4IDNweDsgT1ZFUkZMT1ctWTogaGlkZGVuOyBQQURESU5HLUxFRlQ6 +IDIxcHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2Vz +L2NzZG5pbmRleF9waWMzNy5naWYpOyBPVkVSRkxPVy1YOiBoaWRkZW47IFBBRERJTkctQk9UVE9N +OiAzcHg7IE1BUkdJTjogMHB4OyBXSURUSDogMTcwcHg7IFBBRERJTkctVE9QOiAzcHg7IFdISVRF +LVNQQUNFOiBub3dyYXA7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNs +aXA6IGluaXRpYWwiPjxBIA0KICAgIHRpdGxlPeS6kuiBlOe9kei/kOiQpeaZuuaFp+KAlOmrmOWP +r+eUqOWPr+aJqeWxlee9keermeaKgOacr+WunuaImO+8iOmihOWUrumYtuauteeJiOadg+WNs+i+ +k+WHuuWPsOa5vu+8iSANCiAgICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JB +VElPTjogbm9uZSIgDQogICAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsOTcpOyBocmVmPSJo +dHRwOi8vd3d3LmNoaW5hLXB1Yi5jb20vMTk3MTkzIiANCiAgICB0YXJnZXQ9X2JsYW5rPuS6kuiB +lOe9kei/kOiQpeaZuuaFp+KAlOmrmOWPr+eUqOWPr+aJqeWxlee9keermeaKgDwvQT48L0RUPg0K +ICAgIDxEVCBjbGFzcz10b3A0IA0KICAgIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tH +Uk9VTkQtUE9TSVRJT046IDBweCAzcHg7IE9WRVJGTE9XLVk6IGhpZGRlbjsgUEFERElORy1MRUZU +OiAyMXB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdl +cy9jc2RuaW5kZXhfcGljMzguZ2lmKTsgT1ZFUkZMT1ctWDogaGlkZGVuOyBQQURESU5HLUJPVFRP +TTogM3B4OyBNQVJHSU46IDBweDsgV0lEVEg6IDE3MHB4OyBQQURESU5HLVRPUDogM3B4OyBXSElU +RS1TUEFDRTogbm93cmFwOyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1j +bGlwOiBpbml0aWFsIj48QSANCiAgICB0aXRsZT1NeVNRTOaKgOacr+WGheW5lTpJbm5vRELlrZjl +gqjlvJXmk44o55+l5ZCNTXlTUUzmnI3liqHljoLllYZQZXJjb25h5YWs5Y+4Q1RP5L2c5bqPKSAN +CiAgICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQog +ICAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsOTcpOyBocmVmPSJodHRwOi8vd3d3LmNoaW5h +LXB1Yi5jb20vMTk3MjIwIiANCiAgICB0YXJnZXQ9X2JsYW5rPk15U1FM5oqA5pyv5YaF5bmVOklu +bm9EQuWtmDwvQT48L0RUPg0KICAgIDxEVCBjbGFzcz10b3A1IA0KICAgIHN0eWxlPSJQQURESU5H +LVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDBweCAzcHg7IE9WRVJGTE9XLVk6IGhp +ZGRlbjsgUEFERElORy1MRUZUOiAyMXB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2Nz +ZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMzkuZ2lmKTsgT1ZFUkZMT1ctWDogaGlk +ZGVuOyBQQURESU5HLUJPVFRPTTogM3B4OyBNQVJHSU46IDBweDsgV0lEVEg6IDE3MHB4OyBQQURE +SU5HLVRPUDogM3B4OyBXSElURS1TUEFDRTogbm93cmFwOyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5p +dGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgICB0aXRsZT3lpoLkvZXnrqHn +kIbova/ku7bkvIHkuJoo56ysMueJiCkgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURF +Q09SQVRJT046IG5vbmUiIA0KICAgIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDk3KTsgaHJl +Zj0iaHR0cDovL3d3dy5jaGluYS1wdWIuY29tLzE5NzQwNyIgDQogICAgdGFyZ2V0PV9ibGFuaz7l +poLkvZXnrqHnkIbova/ku7bkvIHkuJoo56ysMueJiCk8L0E+PC9EVD4NCiAgICA8RFQgY2xhc3M9 +dG9wNiANCiAgICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9O +OiAwcHggM3B4OyBPVkVSRkxPVy1ZOiBoaWRkZW47IFBBRERJTkctTEVGVDogMjFweDsgQkFDS0dS +T1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3Bp +YzQwLmdpZik7IE9WRVJGTE9XLVg6IGhpZGRlbjsgUEFERElORy1CT1RUT006IDNweDsgTUFSR0lO +OiAwcHg7IFdJRFRIOiAxNzBweDsgUEFERElORy1UT1A6IDNweDsgV0hJVEUtU1BBQ0U6IG5vd3Jh +cDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+ +PEEgDQogICAgdGl0bGU9566X5rOV5a+86K6677yI5Y6f5Lmm56ysMueJiO+8iSgwOeW5tOW6pueV +hemUgOamnE5PLjIpKDA45bm05bqm55WF6ZSA5qacTk8uMiko6KKr44CK56iL5bqP5ZGY44CL562J +5py65p6E6K+E6YCJ5Li6MjAwNuW5tOacgOWPl+ivu+iAheWWnOeIseeahOWNgeWkp0lU5Zu+5Lmm +5LmL5LiAKSANCiAgICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjog +bm9uZSIgDQogICAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsOTcpOyBocmVmPSJodHRwOi8v +d3d3LmNoaW5hLXB1Yi5jb20vMzE3MDEiIA0KICAgIHRhcmdldD1fYmxhbms+566X5rOV5a+86K66 +77yI5Y6f5Lmm56ysMueJiO+8iSgwOeW5tOW6pueVhTwvQT48L0RUPg0KICAgIDxEVCBjbGFzcz10 +b3A3IA0KICAgIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046 +IDBweCAzcHg7IE9WRVJGTE9XLVk6IGhpZGRlbjsgUEFERElORy1MRUZUOiAyMXB4OyBCQUNLR1JP +VU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGlj +NDEuZ2lmKTsgT1ZFUkZMT1ctWDogaGlkZGVuOyBQQURESU5HLUJPVFRPTTogM3B4OyBNQVJHSU46 +IDBweDsgV0lEVEg6IDE3MHB4OyBQQURESU5HLVRPUDogM3B4OyBXSElURS1TUEFDRTogbm93cmFw +OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48 +QSANCiAgICB0aXRsZT3mt7HlhaXnkIbop6PorqHnrpfmnLrns7vnu58o5Y6f5Lmm56ysMueJiCko +5LiK5biC5LiA5ZGo77yM6ZSA6YeP6L+H5Y2DKSANCiAgICBzdHlsZT0iQ09MT1I6IHJnYigwLDAs +MCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogICAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRo +aXMsOTcpOyBocmVmPSJodHRwOi8vd3d3LmNoaW5hLXB1Yi5jb20vMTk3MTY3IiANCiAgICB0YXJn +ZXQ9X2JsYW5rPua3seWFpeeQhuino+iuoeeul+acuuezu+e7nyjljp/kuabnrKwy54mIKSg8L0E+ +PC9EVD4NCiAgICA8RFQgY2xhc3M9dG9wOCANCiAgICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4 +OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAwcHggM3B4OyBPVkVSRkxPVy1ZOiBoaWRkZW47IFBBRERJ +TkctTEVGVDogMjFweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3 +dy9pbWFnZXMvY3NkbmluZGV4X3BpYzQyLmdpZik7IE9WRVJGTE9XLVg6IGhpZGRlbjsgUEFERElO +Ry1CT1RUT006IDNweDsgTUFSR0lOOiAwcHg7IFdJRFRIOiAxNzBweDsgUEFERElORy1UT1A6IDNw +eDsgV0hJVEUtU1BBQ0U6IG5vd3JhcDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tn +cm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogICAgdGl0bGU9U0VP5a6e5oiY5a+G56CB4oCUNjDl +pKnnvZHnq5nmtYHph4/mj5Dpq5gyMOWAjSBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQt +REVDT1JBVElPTjogbm9uZSIgDQogICAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsOTcpOyBo +cmVmPSJodHRwOi8vd3d3LmNoaW5hLXB1Yi5jb20vMTk3MjAwIiANCiAgICB0YXJnZXQ9X2JsYW5r +PlNFT+WunuaImOWvhueggeKAlDYw5aSp572R56uZ5rWB6YeP5o+Q6auYPC9BPjwvRFQ+DQogICAg +PERUIGNsYXNzPXRvcDkgDQogICAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VO +RC1QT1NJVElPTjogMHB4IDNweDsgT1ZFUkZMT1ctWTogaGlkZGVuOyBQQURESU5HLUxFRlQ6IDIx +cHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2Nz +ZG5pbmRleF9waWM0My5naWYpOyBPVkVSRkxPVy1YOiBoaWRkZW47IFBBRERJTkctQk9UVE9NOiAz +cHg7IE1BUkdJTjogMHB4OyBXSURUSDogMTcwcHg7IFBBRERJTkctVE9QOiAzcHg7IFdISVRFLVNQ +QUNFOiBub3dyYXA7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6 +IGluaXRpYWwiPjxBIA0KICAgIHRpdGxlPSJIVE1MIDXnlKjmiLfmjIfljZco5Y+M6Imy5Y2w5Yi3 +77yM5a2m5Lmg5ZKM5o6M5o+h5pyA5pawV2Vi5byA5Y+R5oqA5pyvSFRNTCA1KSIgDQogICAgc3R5 +bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICAgIG9uY2xp +Y2s9TG9nQ2xpY2tDb3VudCh0aGlzLDk3KTsgaHJlZj0iaHR0cDovL3d3dy5jaGluYS1wdWIuY29t +LzE5NzE3NiIgDQogICAgdGFyZ2V0PV9ibGFuaz5IVE1MIDXnlKjmiLfmjIfljZco5Y+M6Imy5Y2w +5Yi377yM5a2mPC9BPjwvRFQ+DQogICAgPERUIGNsYXNzPXRvcDEwIA0KICAgIHN0eWxlPSJQQURE +SU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDBweCAzcHg7IE9WRVJGTE9XLVk6 +IGhpZGRlbjsgUEFERElORy1MRUZUOiAyMXB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDov +L2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljNDQuZ2lmKTsgT1ZFUkZMT1ctWDog +aGlkZGVuOyBQQURESU5HLUJPVFRPTTogM3B4OyBNQVJHSU46IDBweDsgV0lEVEg6IDE3MHB4OyBQ +QURESU5HLVRPUDogM3B4OyBXSElURS1TUEFDRTogbm93cmFwOyBiYWNrZ3JvdW5kLW9yaWdpbjog +aW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgICB0aXRsZT1KYXZh57yW +56iL5oCd5oOzKOesrDTniYgpKOe7j+WFuOWbvuS5puacgOaWsOeJiOacrCkoMDnlubTluqbnlYXp +lIDmppxUT1A1MCkoMDjlubTluqbnlYXplIDmppxOTy44KSANCiAgICBzdHlsZT0iQ09MT1I6IHJn +YigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogICAgb25jbGljaz1Mb2dDbGlja0Nv +dW50KHRoaXMsOTcpOyBocmVmPSJodHRwOi8vd3d3LmNoaW5hLXB1Yi5jb20vMzQ4MzgiIA0KICAg +IHRhcmdldD1fYmxhbms+SmF2Yee8lueoi+aAneaDsyjnrKw054mIKSjnu4/lhbjlm748L0E+PC9E +VD48L0RMPjwvRElWPjwvTEk+PC9VTD48L0RJVj4NCjxETCBjbGFzcz1zZXNzaW9uX3N0eWxlIA0K +c3R5bGU9IlBBRERJTkctUklHSFQ6IDNweDsgUEFERElORy1MRUZUOiAzcHg7IEZMT0FUOiBsZWZ0 +OyBQQURESU5HLUJPVFRPTTogNXB4OyBNQVJHSU46IDJweCAwcHggMHB4OyBXSURUSDogMTk2cHg7 +IFBBRERJTkctVE9QOiAxMHB4OyBCT1JERVItQk9UVE9NOiByZ2IoMjA0LDIwNCwyMDQpIDFweCBz +b2xpZDsgQkFDS0dST1VORC1DT0xPUjogcmdiKDI1NSwyNTUsMjU1KTsgYmFja2dyb3VuZC1vcmln +aW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+DQogIDxEVCBjbGFzcz0iYm9v +a3RpdCB0eHRfYmx1ZSIgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IFBBRERJTkctTEVG +VDogMHB4OyBGTE9BVDogbm9uZTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAzcHggMHB4 +OyBDT0xPUjogcmdiKDEsOTUsMTgyKTsgUEFERElORy1UT1A6IDBweCI+PEEgDQogIHRpdGxlPeiZ +muaLn+icnOe9kO+8muS7juWDteWwuOe9kee7nOi/vei4quWIsOWFpeS+teajgOa1iyBzdHlsZT0i +Q09MT1I6IHJnYigxLDk1LDE4Mik7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9 +TG9nQ2xpY2tDb3VudCh0aGlzLDk4KTsgDQogIGhyZWY9Imh0dHA6Ly9jbG91ZC5jc2RuLm5ldC9h +LzIwMTAvMTIxNC8yODM2MTYuaHRtbCIgDQogIHRhcmdldD1fYmxhbms+6Jma5ouf6Jyc572Q77ya +5LuO5YO15bC4572R57uc6L+96Liq5Yiw5YWl5L61PC9BPjwvRFQ+DQogIDxEVCANCiAgc3R5bGU9 +IlBBRERJTkctUklHSFQ6IDBweDsgUEFERElORy1MRUZUOiAwcHg7IFBBRERJTkctQk9UVE9NOiAw +cHg7IE1BUkdJTjogMHB4IDBweCA5cHg7IFBBRERJTkctVE9QOiAwcHgiPjxJTUcgDQogIHRpdGxl +PSIiIA0KICBzdHlsZT0iQk9SREVSLVJJR0hUOiByZ2IoMjA0LDIwNCwyMDQpIDFweCBzb2xpZDsg +UEFERElORy1SSUdIVDogMnB4OyBCT1JERVItVE9QOiByZ2IoMjA0LDIwNCwyMDQpIDFweCBzb2xp +ZDsgUEFERElORy1MRUZUOiAycHg7IEZMT0FUOiBsZWZ0OyBQQURESU5HLUJPVFRPTTogMnB4OyBN +QVJHSU46IDBweCA2cHggMHB4IDBweDsgQk9SREVSLUxFRlQ6IHJnYigyMDQsMjA0LDIwNCkgMXB4 +IHNvbGlkOyBQQURESU5HLVRPUDogMnB4OyBCT1JERVItQk9UVE9NOiByZ2IoMjA0LDIwNCwyMDQp +IDFweCBzb2xpZCIgDQogIGhlaWdodD02OCBhbHQ9IiIgDQogIHNyYz0iaHR0cDovL2FydGljbGVz +LmNzZG4ubmV0L3VwbG9hZHMvYWxsaW1nLzEwMTIxNC83OV8xMzExMjAxMTQxLmpwZyIgDQogIHdp +ZHRoPTUyPumdouWvuei2iuadpei2iuWkjeadgueahOmAg+mBv+aKgOacr++8jOS7peWPiumHh+eU +qOWKoOWvhuaKgOacr+adpeS/neaKpOe9kee7nOmAmuS/oe+8jOmYsuatouiiq+eqg+WQrOeahOWN +j+iurui2iuadpei2ii4uLjwvRFQ+PC9ETD4NCjxETCBjbGFzcz1zZXNzaW9uX3N0eWxlIA0Kc3R5 +bGU9IlBBRERJTkctUklHSFQ6IDNweDsgUEFERElORy1MRUZUOiAzcHg7IEZMT0FUOiBsZWZ0OyBQ +QURESU5HLUJPVFRPTTogNXB4OyBNQVJHSU46IDJweCAwcHggMHB4OyBXSURUSDogMTk2cHg7IFBB +RERJTkctVE9QOiAxMHB4OyBCT1JERVItQk9UVE9NOiByZ2IoMjA0LDIwNCwyMDQpIDFweCBzb2xp +ZDsgQkFDS0dST1VORC1DT0xPUjogcmdiKDI1NSwyNTUsMjU1KTsgYmFja2dyb3VuZC1vcmlnaW46 +IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+DQogIDxEVCBjbGFzcz0iYm9va3Rp +dCB0eHRfYmx1ZSIgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IFBBRERJTkctTEVGVDog +MHB4OyBGTE9BVDogbm9uZTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAzcHggMHB4OyBD +T0xPUjogcmdiKDEsOTUsMTgyKTsgUEFERElORy1UT1A6IDBweCI+PEEgDQogIHRpdGxlPWpCUE00 +5bel5L2c5rWB5bqU55So5byA5Y+R5oyH5Y2XIHN0eWxlPSJDT0xPUjogcmdiKDEsOTUsMTgyKTsg +VEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsOTgp +OyANCiAgaHJlZj0iaHR0cDovL2phdmEuY3Nkbi5uZXQvYS8yMDEwMTExMi8yODE5MTUuaHRtbCIg +DQogIHRhcmdldD1fYmxhbms+akJQTTTlt6XkvZzmtYHlupTnlKjlvIDlj5HmjIfljZc8L0E+PC9E +VD4NCiAgPERUIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBQQURESU5HLUxFRlQ6IDBw +eDsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHggMHB4IDlweDsgUEFERElORy1UT1A6 +IDBweCI+PElNRyANCiAgdGl0bGU9IiIgDQogIHN0eWxlPSJCT1JERVItUklHSFQ6IHJnYigyMDQs +MjA0LDIwNCkgMXB4IHNvbGlkOyBQQURESU5HLVJJR0hUOiAycHg7IEJPUkRFUi1UT1A6IHJnYigy +MDQsMjA0LDIwNCkgMXB4IHNvbGlkOyBQQURESU5HLUxFRlQ6IDJweDsgRkxPQVQ6IGxlZnQ7IFBB +RERJTkctQk9UVE9NOiAycHg7IE1BUkdJTjogMHB4IDZweCAwcHggMHB4OyBCT1JERVItTEVGVDog +cmdiKDIwNCwyMDQsMjA0KSAxcHggc29saWQ7IFBBRERJTkctVE9QOiAycHg7IEJPUkRFUi1CT1RU +T006IHJnYigyMDQsMjA0LDIwNCkgMXB4IHNvbGlkIiANCiAgaGVpZ2h0PTY4IGFsdD0iIiBzcmM9 +Imh0dHA6Ly9pbWFnZXMuY3Nkbi5uZXQvMjAxMDExMTIvakJQTTTlt6XkvZzmtYHlupTnlKjlvIDl +j5HmjIfljZctMyUyMC5qcGciIA0KICB3aWR0aD01Mj7mnKzkuablsIbkvb/mgqjlv6vpgJ/kuobo +p6Pku4DkuYjmmK/lt6XkvZzmtYHjgIFCUE3lkoxqQlBN77yM5Lul5Y+K5a6D5Lus55qE5Y+R5bGV +5Y6G56iL44CC5b2T54S277yM6YeN6KaBLi4uPC9EVD48L0RMPg0KPERMIGNsYXNzPXNlc3Npb25f +c3R5bGUgDQpzdHlsZT0iUEFERElORy1SSUdIVDogM3B4OyBQQURESU5HLUxFRlQ6IDNweDsgRkxP +QVQ6IGxlZnQ7IFBBRERJTkctQk9UVE9NOiA1cHg7IE1BUkdJTjogMnB4IDBweCAwcHg7IFdJRFRI +OiAxOTZweDsgUEFERElORy1UT1A6IDEwcHg7IEJPUkRFUi1CT1RUT006IHJnYigyMDQsMjA0LDIw +NCkgMXB4IHNvbGlkOyBCQUNLR1JPVU5ELUNPTE9SOiByZ2IoMjU1LDI1NSwyNTUpOyBiYWNrZ3Jv +dW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj4NCiAgPERUIGNs +YXNzPSJib29rdGl0IHR4dF9ibHVlIiANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgUEFE +RElORy1MRUZUOiAwcHg7IEZMT0FUOiBub25lOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46 +IDNweCAwcHg7IENPTE9SOiByZ2IoMSw5NSwxODIpOyBQQURESU5HLVRPUDogMHB4Ij48QSANCiAg +dGl0bGU9TGludXjpgqPkupvkuovlhL8gc3R5bGU9IkNPTE9SOiByZ2IoMSw5NSwxODIpOyBURVhU +LURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw5OCk7IA0K +ICBocmVmPSJodHRwOi8vamF2YS5jc2RuLm5ldC9hLzIwMTAwODEyLzI3ODExNy5odG1sIiANCiAg +dGFyZ2V0PV9ibGFuaz5MaW51eOmCo+S6m+S6i+WEvzwvQT48L0RUPg0KICA8RFQgDQogIHN0eWxl +PSJQQURESU5HLVJJR0hUOiAwcHg7IFBBRERJTkctTEVGVDogMHB4OyBQQURESU5HLUJPVFRPTTog +MHB4OyBNQVJHSU46IDBweCAwcHggOXB4OyBQQURESU5HLVRPUDogMHB4Ij48SU1HIA0KICB0aXRs +ZT0iIiANCiAgc3R5bGU9IkJPUkRFUi1SSUdIVDogcmdiKDIwNCwyMDQsMjA0KSAxcHggc29saWQ7 +IFBBRERJTkctUklHSFQ6IDJweDsgQk9SREVSLVRPUDogcmdiKDIwNCwyMDQsMjA0KSAxcHggc29s +aWQ7IFBBRERJTkctTEVGVDogMnB4OyBGTE9BVDogbGVmdDsgUEFERElORy1CT1RUT006IDJweDsg +TUFSR0lOOiAwcHggNnB4IDBweCAwcHg7IEJPUkRFUi1MRUZUOiByZ2IoMjA0LDIwNCwyMDQpIDFw +eCBzb2xpZDsgUEFERElORy1UT1A6IDJweDsgQk9SREVSLUJPVFRPTTogcmdiKDIwNCwyMDQsMjA0 +KSAxcHggc29saWQiIA0KICBoZWlnaHQ9NjggYWx0PSIiIHNyYz0iaHR0cDovL2ltYWdlcy5jc2Ru +Lm5ldC8yMDEwMDgxMi9MaW51eOmCo+S6m+S6i+WEvy0yLmpwZyIgDQogIHdpZHRoPTUyPuacrOS5 +puWfuuS6jjIuNi4yMuWGheaguO+8jOWvuVVTQuWtkOezu+e7n+eahOWkp+mDqOWIhua6kOS7o+eg +gemAkOihjOi/m+ihjOWIhuaekO+8jOezu+e7n+WcsOmYkOmHiuS6hi4uLjwvRFQ+PC9ETD48L0RJ +Vj48L0RJVj4NCjxESVYgY2xhc3M9cGFnZWJsb2NrMl93cmFwIHN0eWxlPSJGTE9BVDogbGVmdDsg +V0lEVEg6IDczNXB4Ij4NCjxESVYgY2xhc3M9cGFnZWNvbl9sYXllcjJfbGVmdCANCnN0eWxlPSJQ +QURESU5HLVJJR0hUOiAwcHg7IERJU1BMQVk6IGlubGluZTsgUEFERElORy1MRUZUOiAwcHg7IEZM +T0FUOiBsZWZ0OyBQQURESU5HLUJPVFRPTTogNXB4OyBNQVJHSU46IDBweCAwcHggMHB4IDFweDsg +V0lEVEg6IDQ3MHB4OyBQQURESU5HLVRPUDogMHB4Ij4NCjxINiANCnN0eWxlPSJDTEVBUjogYm90 +aDsgUEFERElORy1SSUdIVDogMHB4OyBCT1JERVItVE9QOiByZ2IoMjA0LDIwNCwyMDQpIDFweCBz +b2xpZDsgUEFERElORy1MRUZUOiAxMHB4OyBGT05ULVNJWkU6IDE0cHg7IEJBQ0tHUk9VTkQtSU1B +R0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMxMS5naWYp +OyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweDsgUEFERElORy1UT1A6IDVweDsgUE9T +SVRJT046IHJlbGF0aXZlOyBIRUlHSFQ6IDI5cHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFs +OyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPuekvuWMujxFTSANCmNsYXNzPXR4dF9ibHVlIA0K +c3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMHB4IDRweDsg +UEFERElORy1MRUZUOiAxMHB4OyBGT05ULVdFSUdIVDogbm9ybWFsOyBGT05ULVNJWkU6IDEycHg7 +IExFRlQ6IDQxMHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3 +L2ltYWdlcy9jc2RuaW5kZXhfcGljMTIuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgQ09MT1I6 +IHJnYigxLDk1LDE4Mik7IFBBRERJTkctVE9QOiAwcHg7IEZPTlQtU1RZTEU6IG5vcm1hbDsgUE9T +SVRJT046IGFic29sdXRlOyBUT1A6IDZweDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJh +Y2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQpzdHlsZT0iUEFERElORy1SSUdIVDogM3B4OyBQ +QURESU5HLUxFRlQ6IDNweDsgUEFERElORy1CT1RUT006IDBweDsgQ09MT1I6IHJnYigxLDk1LDE4 +Mik7IFBBRERJTkctVE9QOiAwcHg7IFRFWFQtREVDT1JBVElPTjogdW5kZXJsaW5lIiANCmhyZWY9 +Imh0dHA6Ly9iYnMuY3Nkbi5uZXQvIiB0YXJnZXQ9X2JsYW5rPuabtOWkmjwvQT48L0VNPjwvSDY+ +DQo8RElWIGNsYXNzPXBhZ2Vjb25fbGF5ZXIyX2xlZnRjb24gDQpzdHlsZT0iUEFERElORy1SSUdI +VDogMTBweDsgUEFERElORy1MRUZUOiAxMHB4OyBGTE9BVDogbGVmdDsgUEFERElORy1CT1RUT006 +IDVweDsgV0lEVEg6IDQ1MHB4OyBQQURESU5HLVRPUDogNXB4Ij4NCjxETCANCnN0eWxlPSJQQURE +SU5HLVJJR0hUOiAwcHg7IFBBRERJTkctTEVGVDogMHB4OyBQQURESU5HLUJPVFRPTTogMnB4OyBN +QVJHSU46IDNweCAwcHg7IExJTkUtSEVJR0hUOiAyMXB4OyBQQURESU5HLVRPUDogMHB4OyBQT1NJ +VElPTjogcmVsYXRpdmUiPg0KICA8RFQgY2xhc3M9dHh0X2JsYWNrIA0KICBzdHlsZT0iUEFERElO +Ry1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAwcHggOHB4OyBQQURESU5HLUxFRlQ6 +IDEwcHg7IEZPTlQtU0laRTogMTRweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2Ru +aW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzI2LmdpZik7IFBBRERJTkctQk9UVE9NOiAw +cHg7IE1BUkdJTjogM3B4IDBweDsgQ09MT1I6IHJnYigwLDAsMCk7IFBBRERJTkctVE9QOiAwcHg7 +IFBPU0lUSU9OOiByZWxhdGl2ZTsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91 +bmQtY2xpcDogaW5pdGlhbCI+PENJVEUgDQogIGNsYXNzPSJ0eHRfYmx1ZSB0eHRfMTIiIA0KICBz +dHlsZT0iRk9OVC1TSVpFOiAxMnB4OyBGTE9BVDogcmlnaHQ7IENPTE9SOiByZ2IoMSw5NSwxODIp +OyBGT05ULVNUWUxFOiBub3JtYWwiPjxBIA0KICBzdHlsZT0iQ09MT1I6IHJnYigxLDk1LDE4Mik7 +IFRFWFQtREVDT1JBVElPTjogdW5kZXJsaW5lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRo +aXMsODQpOyBocmVmPSJodHRwOi8vaGkuY3Nkbi5uZXQvQ1NETiIgDQogIHRhcmdldD1fYmxhbms+ +Q1NETjwvQT48L0NJVEU+PEEgdGl0bGU95oqA5pyv55ub5a60U0QyLjDlpKfkvJrlnIbmu6Hnu5Pm +nZ8gDQogIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiAN +CiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsODQpOyANCiAgaHJlZj0iaHR0cDovL3RvcGlj +LmNzZG4ubmV0L3UvMjAxMDEyMDkvMDkvZDA4MDFmNmEtNzNmNC00MjZkLTg4ZmItOGQ3MmI5M2I1 +NDk5Lmh0bWwiIA0KICB0YXJnZXQ9X2JsYW5rPuaKgOacr+ebm+WutFNEMi4w5aSn5Lya5ZyG5ruh +57uT5p2fPC9BPjwvRFQ+DQogIDxEVCBjbGFzcz10eHRfYmxhY2sgDQogIHN0eWxlPSJQQURESU5H +LVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDBweCA4cHg7IFBBRERJTkctTEVGVDog +MTBweDsgRk9OVC1TSVpFOiAxNHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5p +bWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMjYuZ2lmKTsgUEFERElORy1CT1RUT006IDBw +eDsgTUFSR0lOOiAzcHggMHB4OyBDT0xPUjogcmdiKDAsMCwwKTsgUEFERElORy1UT1A6IDBweDsg +UE9TSVRJT046IHJlbGF0aXZlOyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3Vu +ZC1jbGlwOiBpbml0aWFsIj48Q0lURSANCiAgY2xhc3M9InR4dF9ibHVlIHR4dF8xMiIgDQogIHN0 +eWxlPSJGT05ULVNJWkU6IDEycHg7IEZMT0FUOiByaWdodDsgQ09MT1I6IHJnYigxLDk1LDE4Mik7 +IEZPTlQtU1RZTEU6IG5vcm1hbCI+PEEgDQogIHN0eWxlPSJDT0xPUjogcmdiKDEsOTUsMTgyKTsg +VEVYVC1ERUNPUkFUSU9OOiB1bmRlcmxpbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhp +cyw4NCk7IGhyZWY9Imh0dHA6Ly9oaS5jc2RuLm5ldC9qdjkiIA0KICB0YXJnZXQ9X2JsYW5rPmp2 +OTwvQT48L0NJVEU+PEEgdGl0bGU9IlNpbHZlcmxpZ2h0L1dQRi9XUDfkuIDlkajlrabkuaDlr7zo +r7soMTLmnIg2LTEy5pyIMTIpICIgDQogIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1E +RUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsODQpOyANCiAg +aHJlZj0iaHR0cDovL3RvcGljLmNzZG4ubmV0L3UvMjAxMDEyMTMvMTQvQzY3ODQ5MjktMkJBNS00 +M0RBLThCMjMtMEMxREM2OEU0QkQ4Lmh0bWwiIA0KICB0YXJnZXQ9X2JsYW5rPlNpbHZlcmxpZ2h0 +L1dQRi9XUDfkuIDlkajlrabkuaDlr7zor7soMTLmnIg2LTEy5pyIMTIpPC9BPjwvRFQ+DQogIDxE +VCBjbGFzcz10eHRfYmxhY2sgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9V +TkQtUE9TSVRJT046IDBweCA4cHg7IFBBRERJTkctTEVGVDogMTBweDsgRk9OVC1TSVpFOiAxNHB4 +OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2Ru +aW5kZXhfcGljMjYuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAzcHggMHB4OyBD +T0xPUjogcmdiKDAsMCwwKTsgUEFERElORy1UT1A6IDBweDsgUE9TSVRJT046IHJlbGF0aXZlOyBi +YWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48Q0lU +RSANCiAgY2xhc3M9InR4dF9ibHVlIHR4dF8xMiIgDQogIHN0eWxlPSJGT05ULVNJWkU6IDEycHg7 +IEZMT0FUOiByaWdodDsgQ09MT1I6IHJnYigxLDk1LDE4Mik7IEZPTlQtU1RZTEU6IG5vcm1hbCI+ +PEEgDQogIHN0eWxlPSJDT0xPUjogcmdiKDEsOTUsMTgyKTsgVEVYVC1ERUNPUkFUSU9OOiB1bmRl +cmxpbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw4NCk7IGhyZWY9Imh0dHA6Ly9o +aS5jc2RuLm5ldC9ndWd1ZGEyMDA4IiANCiAgdGFyZ2V0PV9ibGFuaz5ndWd1ZGEyMDA4PC9BPjwv +Q0lURT48QSB0aXRsZT3miopURU1QRELmlL7liLDlhoXlrZjph4wgDQogIHN0eWxlPSJDT0xPUjog +cmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0Nv +dW50KHRoaXMsODQpOyANCiAgaHJlZj0iaHR0cDovL3RvcGljLmNzZG4ubmV0L3UvMjAxMDEyMTMv +MTMvRjFEMUQxODktRTU3Mi00RjRDLUI4NkEtMjc2QUYyRkEzQTZELmh0bWwiIA0KICB0YXJnZXQ9 +X2JsYW5rPuaKilRFTVBEQuaUvuWIsOWGheWtmOmHjDwvQT48L0RUPg0KICA8RFQgY2xhc3M9dHh0 +X2JsYWNrIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9O +OiAwcHggOHB4OyBQQURESU5HLUxFRlQ6IDEwcHg7IEZPTlQtU0laRTogMTRweDsgQkFDS0dST1VO +RC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzI2 +LmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogM3B4IDBweDsgQ09MT1I6IHJnYigw +LDAsMCk7IFBBRERJTkctVE9QOiAwcHg7IFBPU0lUSU9OOiByZWxhdGl2ZTsgYmFja2dyb3VuZC1v +cmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PENJVEUgDQogIGNsYXNz +PSJ0eHRfYmx1ZSB0eHRfMTIiIA0KICBzdHlsZT0iRk9OVC1TSVpFOiAxMnB4OyBGTE9BVDogcmln +aHQ7IENPTE9SOiByZ2IoMSw5NSwxODIpOyBGT05ULVNUWUxFOiBub3JtYWwiPjxBIA0KICBzdHls +ZT0iQ09MT1I6IHJnYigxLDk1LDE4Mik7IFRFWFQtREVDT1JBVElPTjogdW5kZXJsaW5lIiANCiAg +b25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsODQpOyBocmVmPSJodHRwOi8vaGkuY3Nkbi5uZXQv +aW52YWxpZGF0ZTAwMTEiIA0KICB0YXJnZXQ9X2JsYW5rPmludmFsaWRhdGUwMDExPC9BPjwvQ0lU +RT48QSANCiAgdGl0bGU9IuWPpuexu+ijhemlsOS9oOeahFdpbmZvcm0gLSDlnKjnqpflj6PnmoTl +t6bkuIrop5LliqDkuIDkuKrlnKPor57luL0iIA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7 +IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDg0 +KTsgDQogIGhyZWY9Imh0dHA6Ly90b3BpYy5jc2RuLm5ldC91LzIwMTAxMjEzLzEwL0ZGMTcxRDAy +LTFFOEQtNDJBMC1BQTVELUJBQUQxMjJCNzdBQy5odG1sIiANCiAgdGFyZ2V0PV9ibGFuaz7lj6bn +sbvoo4XppbDkvaDnmoRXaW5mb3JtIC0g5Zyo56qX5Y+j55qE5bem5LiK6KeS5Yqg5LiA5Liq5Zyj +6K+e5bi9PC9BPjwvRFQ+DQogIDxEVCBjbGFzcz10eHRfYmxhY2sgDQogIHN0eWxlPSJQQURESU5H +LVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDBweCA4cHg7IFBBRERJTkctTEVGVDog +MTBweDsgRk9OVC1TSVpFOiAxNHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5p +bWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMjYuZ2lmKTsgUEFERElORy1CT1RUT006IDBw +eDsgTUFSR0lOOiAzcHggMHB4OyBDT0xPUjogcmdiKDAsMCwwKTsgUEFERElORy1UT1A6IDBweDsg +UE9TSVRJT046IHJlbGF0aXZlOyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3Vu +ZC1jbGlwOiBpbml0aWFsIj48Q0lURSANCiAgY2xhc3M9InR4dF9ibHVlIHR4dF8xMiIgDQogIHN0 +eWxlPSJGT05ULVNJWkU6IDEycHg7IEZMT0FUOiByaWdodDsgQ09MT1I6IHJnYigxLDk1LDE4Mik7 +IEZPTlQtU1RZTEU6IG5vcm1hbCI+PEEgDQogIHN0eWxlPSJDT0xPUjogcmdiKDEsOTUsMTgyKTsg +VEVYVC1ERUNPUkFUSU9OOiB1bmRlcmxpbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhp +cyw4NCk7IGhyZWY9Imh0dHA6Ly9oaS5jc2RuLm5ldC96Y3R5bWp4IiANCiAgdGFyZ2V0PV9ibGFu +az56Y3R5bWp4PC9BPjwvQ0lURT48QSB0aXRsZT0iV2luQ0UgNi4wIOmpseWKqOW8gOWPkeOAgeWG +heaguOWumuWItuaWuemdoueahOS5puS4u+imgeaciemCo+S6m++8nyIgDQogIHN0eWxlPSJDT0xP +UjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlj +a0NvdW50KHRoaXMsODQpOyANCiAgaHJlZj0iaHR0cDovL3RvcGljLmNzZG4ubmV0L3UvMjAxMDEy +MTIvMTYvMUU1Q0I3MDMtOTVDNi00NjI1LUJBM0ItMUI2OTNBRDAyQjkxLmh0bWwiIA0KICB0YXJn +ZXQ9X2JsYW5rPldpbkNFIDYuMCDpqbHliqjlvIDlj5HjgIHlhoXmoLjlrprliLbmlrnpnaLnmoTk +uabkuLvopoHmnInpgqPkupvvvJ88L0E+PC9EVD4NCiAgPERUIGNsYXNzPXR4dF9ibGFjayANCiAg +c3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMHB4IDhweDsg +UEFERElORy1MRUZUOiAxMHB4OyBGT05ULVNJWkU6IDE0cHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVy +bChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMyNi5naWYpOyBQQURE +SU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDNweCAwcHg7IENPTE9SOiByZ2IoMCwwLDApOyBQQURE +SU5HLVRPUDogMHB4OyBQT1NJVElPTjogcmVsYXRpdmU7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0 +aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxDSVRFIA0KICBjbGFzcz0idHh0X2JsdWUg +dHh0XzEyIiANCiAgc3R5bGU9IkZPTlQtU0laRTogMTJweDsgRkxPQVQ6IHJpZ2h0OyBDT0xPUjog +cmdiKDEsOTUsMTgyKTsgRk9OVC1TVFlMRTogbm9ybWFsIj48QSANCiAgc3R5bGU9IkNPTE9SOiBy +Z2IoMSw5NSwxODIpOyBURVhULURFQ09SQVRJT046IHVuZGVybGluZSIgDQogIG9uY2xpY2s9TG9n +Q2xpY2tDb3VudCh0aGlzLDg0KTsgaHJlZj0iaHR0cDovL2hpLmNzZG4ubmV0L3BpZ2cxOCIgDQog +IHRhcmdldD1fYmxhbms+cGlnZzE4PC9BPjwvQ0lURT48QSB0aXRsZT0id2luZG93cyB4cCDlkozo +mZrmi5/mnLrnmoTlm7Dmg5EgICB5ZWFoIiANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBU +RVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw4NCk7 +IA0KICBocmVmPSJodHRwOi8vdG9waWMuY3Nkbi5uZXQvdS8yMDEwMTIwOC8xNi83RDZFRDdEMS00 +ODZFLTQyODEtQTZGOS03MkUxOTlGODQ0ODIuaHRtbCIgDQogIHRhcmdldD1fYmxhbms+d2luZG93 +cyB4cCDlkozomZrmi5/mnLrnmoTlm7Dmg5EgeWVhaDwvQT48L0RUPg0KICA8RFQgY2xhc3M9dHh0 +X2JsYWNrIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9O +OiAwcHggOHB4OyBQQURESU5HLUxFRlQ6IDEwcHg7IEZPTlQtU0laRTogMTRweDsgQkFDS0dST1VO +RC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzI2 +LmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogM3B4IDBweDsgQ09MT1I6IHJnYigw +LDAsMCk7IFBBRERJTkctVE9QOiAwcHg7IFBPU0lUSU9OOiByZWxhdGl2ZTsgYmFja2dyb3VuZC1v +cmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PENJVEUgDQogIGNsYXNz +PSJ0eHRfYmx1ZSB0eHRfMTIiIA0KICBzdHlsZT0iRk9OVC1TSVpFOiAxMnB4OyBGTE9BVDogcmln +aHQ7IENPTE9SOiByZ2IoMSw5NSwxODIpOyBGT05ULVNUWUxFOiBub3JtYWwiPjxBIA0KICBzdHls +ZT0iQ09MT1I6IHJnYigxLDk1LDE4Mik7IFRFWFQtREVDT1JBVElPTjogdW5kZXJsaW5lIiANCiAg +b25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsODQpOyBocmVmPSJodHRwOi8vaGkuY3Nkbi5uZXQv +T25lT25jZSIgDQogIHRhcmdldD1fYmxhbms+T25lT25jZTwvQT48L0NJVEU+PEEgdGl0bGU9IuS/ +ruaUuWkuTVg1MTUgRUJPT1TlpKflsI8iIA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRF +WFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDg0KTsg +DQogIGhyZWY9Imh0dHA6Ly90b3BpYy5jc2RuLm5ldC91LzIwMTAxMjEwLzE0LzI4NkRBQTVELTIx +NTItNDVDMi1BNDdDLUVCQTk3M0I4NjBGQi5odG1sIiANCiAgdGFyZ2V0PV9ibGFuaz7kv67mlLlp +Lk1YNTE1IEVCT09U5aSn5bCPPC9BPjwvRFQ+DQogIDxEVCBjbGFzcz10eHRfYmxhY2sgDQogIHN0 +eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDBweCA4cHg7IFBB +RERJTkctTEVGVDogMTBweDsgRk9OVC1TSVpFOiAxNHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwo +aHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMjYuZ2lmKTsgUEFERElO +Ry1CT1RUT006IDBweDsgTUFSR0lOOiAzcHggMHB4OyBDT0xPUjogcmdiKDAsMCwwKTsgUEFERElO +Ry1UT1A6IDBweDsgUE9TSVRJT046IHJlbGF0aXZlOyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlh +bDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48Q0lURSANCiAgY2xhc3M9InR4dF9ibHVlIHR4 +dF8xMiIgDQogIHN0eWxlPSJGT05ULVNJWkU6IDEycHg7IEZMT0FUOiByaWdodDsgQ09MT1I6IHJn +YigxLDk1LDE4Mik7IEZPTlQtU1RZTEU6IG5vcm1hbCI+PEEgDQogIHN0eWxlPSJDT0xPUjogcmdi +KDEsOTUsMTgyKTsgVEVYVC1ERUNPUkFUSU9OOiB1bmRlcmxpbmUiIA0KICBvbmNsaWNrPUxvZ0Ns +aWNrQ291bnQodGhpcyw4NCk7IGhyZWY9Imh0dHA6Ly9oaS5jc2RuLm5ldC9seXNlcnZlciIgDQog +IHRhcmdldD1fYmxhbms+bHlzZXJ2ZXI8L0E+PC9DSVRFPjxBIHRpdGxlPeiuqeS6uue6oOe7k+ea +hOS4ieWxguaetuaehCANCiAgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJ +T046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw4NCk7IA0KICBocmVmPSJo +dHRwOi8vdG9waWMuY3Nkbi5uZXQvdS8yMDEwMTIxMC8xMS9ERjhFQ0E4Ri1FQzZBLTRGM0UtQTM5 +Mi1FOEMzMUZFODdGQTguaHRtbCIgDQogIHRhcmdldD1fYmxhbms+6K6p5Lq657qg57uT55qE5LiJ +5bGC5p625p6EPC9BPjwvRFQ+DQogIDxEVCBjbGFzcz10eHRfYmxhY2sgDQogIHN0eWxlPSJQQURE +SU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDBweCA4cHg7IFBBRERJTkctTEVG +VDogMTBweDsgRk9OVC1TSVpFOiAxNHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2Nz +ZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMjYuZ2lmKTsgUEFERElORy1CT1RUT006 +IDBweDsgTUFSR0lOOiAzcHggMHB4OyBDT0xPUjogcmdiKDAsMCwwKTsgUEFERElORy1UT1A6IDBw +eDsgUE9TSVRJT046IHJlbGF0aXZlOyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dy +b3VuZC1jbGlwOiBpbml0aWFsIj48Q0lURSANCiAgY2xhc3M9InR4dF9ibHVlIHR4dF8xMiIgDQog +IHN0eWxlPSJGT05ULVNJWkU6IDEycHg7IEZMT0FUOiByaWdodDsgQ09MT1I6IHJnYigxLDk1LDE4 +Mik7IEZPTlQtU1RZTEU6IG5vcm1hbCI+PEEgDQogIHN0eWxlPSJDT0xPUjogcmdiKDEsOTUsMTgy +KTsgVEVYVC1ERUNPUkFUSU9OOiB1bmRlcmxpbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQo +dGhpcyw4NCk7IGhyZWY9Imh0dHA6Ly9oaS5jc2RuLm5ldC9xaXhpbmdoYWl0YW5nMTIzIiANCiAg +dGFyZ2V0PV9ibGFuaz5xaXhpbmdoYWl0YW5nMTIzPC9BPjwvQ0lURT48QSB0aXRsZT3lv4Xor7vv +vJrlpoLkvZXmiJDkuLrkuIDlkI3kvJjnp4DnmoRBbmRyb2lk5byA5Y+R6ICFIA0KICBzdHlsZT0i +Q09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9n +Q2xpY2tDb3VudCh0aGlzLDg0KTsgDQogIGhyZWY9Imh0dHA6Ly90b3BpYy5jc2RuLm5ldC91LzIw +MTAxMjA5LzE1L0UzMDFBNENELTNEMzYtNEU0Qi05ODA5LTE1NUY0OURCOUM0OC5odG1sIiANCiAg +dGFyZ2V0PV9ibGFuaz7lv4Xor7vvvJrlpoLkvZXmiJDkuLrkuIDlkI3kvJjnp4DnmoRBbmRyb2lk +5byA5Y+R6ICFPC9BPjwvRFQ+DQogIDxERCBjbGFzcz1uZXdzX3R5cGVhIA0KICBzdHlsZT0iUEFE +RElORy1SSUdIVDogMHB4OyBQQURESU5HLUxFRlQ6IDBweDsgQkFDS0dST1VORC1JTUFHRTogdXJs +KGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzQ2LmdpZik7IFBBRERJ +TkctQk9UVE9NOiAwcHg7IE1BUkdJTjogLTNweCAwcHggMTBweDsgUEFERElORy1UT1A6IDBweDsg +UE9TSVRJT046IHJlbGF0aXZlOyBIRUlHSFQ6IDE5cHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0 +aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxERk4gDQogIHN0eWxlPSJMRUZUOiAzODlw +eDsgQ09MT1I6IHJnYigyNTUsMjU1LDI1NSk7IEZPTlQtU1RZTEU6IG5vcm1hbDsgUE9TSVRJT046 +IGFic29sdXRlOyBUT1A6IDJweCI+56S+5Yy657K+5Y2OPC9ERk4+PC9ERD4NCiAgPERUIGNsYXNz +PXR4dF9ibGFjayANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJ +VElPTjogMHB4IDhweDsgUEFERElORy1MRUZUOiAxMHB4OyBGT05ULVNJWkU6IDE0cHg7IEJBQ0tH +Uk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9w +aWMyNi5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDNweCAwcHg7IENPTE9SOiBy +Z2IoMCwwLDApOyBQQURESU5HLVRPUDogMHB4OyBQT1NJVElPTjogcmVsYXRpdmU7IGJhY2tncm91 +bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxDSVRFIA0KICBj +bGFzcz0idHh0X2JsdWUgdHh0XzEyIiANCiAgc3R5bGU9IkZPTlQtU0laRTogMTJweDsgRkxPQVQ6 +IHJpZ2h0OyBDT0xPUjogcmdiKDEsOTUsMTgyKTsgRk9OVC1TVFlMRTogbm9ybWFsIj435Lq65pS2 +6JePPC9DSVRFPjxBIA0KICB0aXRsZT0xMOenjeegtOmZpOe9kemhteiuvuiuoeW4iOmanOeijeea +hOWunueUqOaWueazlSBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjog +bm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDg1KTsgDQogIGhyZWY9Imh0dHA6 +Ly9zZC5jc2RuLm5ldC9hLzIwMTAxMjEzLzI4MzQ3NC5odG1sIiANCiAgdGFyZ2V0PV9ibGFuaz4x +MOenjeegtOmZpOe9kemhteiuvuiuoeW4iOmanOeijeeahOWunueUqOaWueazlTwvQT48L0RUPg0K +ICA8RFQgY2xhc3M9dHh0X2JsYWNrIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNL +R1JPVU5ELVBPU0lUSU9OOiAwcHggOHB4OyBQQURESU5HLUxFRlQ6IDEwcHg7IEZPTlQtU0laRTog +MTRweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMv +Y3NkbmluZGV4X3BpYzI2LmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogM3B4IDBw +eDsgQ09MT1I6IHJnYigwLDAsMCk7IFBBRERJTkctVE9QOiAwcHg7IFBPU0lUSU9OOiByZWxhdGl2 +ZTsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+ +PENJVEUgDQogIGNsYXNzPSJ0eHRfYmx1ZSB0eHRfMTIiIA0KICBzdHlsZT0iRk9OVC1TSVpFOiAx +MnB4OyBGTE9BVDogcmlnaHQ7IENPTE9SOiByZ2IoMSw5NSwxODIpOyBGT05ULVNUWUxFOiBub3Jt +YWwiPjbkurrmlLbol488L0NJVEU+PEEgDQogIHRpdGxlPWxpbnV457yW56iL55qEMTA456eN5aWH +5rer5ben6K6hLTEyKOWtmOWCqOiuoeeulynnu60gDQogIHN0eWxlPSJDT0xPUjogcmdiKDAsMCww +KTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMs +ODUpOyANCiAgaHJlZj0iaHR0cDovL2Jsb2cuY3Nkbi5uZXQvcGVubnlsaWFuZy9hcmNoaXZlLzIw +MTAvMTIvMTAvNjA2NzMwNy5hc3B4IiANCiAgdGFyZ2V0PV9ibGFuaz5saW51eOe8lueoi+eahDEw +OOenjeWlh+a3q+W3p+iuoS0xMijlrZjlgqjorqHnrpcp57utPC9BPjwvRFQ+DQogIDxEVCBjbGFz +cz10eHRfYmxhY2sgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9T +SVRJT046IDBweCA4cHg7IFBBRERJTkctTEVGVDogMTBweDsgRk9OVC1TSVpFOiAxNHB4OyBCQUNL +R1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhf +cGljMjYuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAzcHggMHB4OyBDT0xPUjog +cmdiKDAsMCwwKTsgUEFERElORy1UT1A6IDBweDsgUE9TSVRJT046IHJlbGF0aXZlOyBiYWNrZ3Jv +dW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48Q0lURSANCiAg +Y2xhc3M9InR4dF9ibHVlIHR4dF8xMiIgDQogIHN0eWxlPSJGT05ULVNJWkU6IDEycHg7IEZMT0FU +OiByaWdodDsgQ09MT1I6IHJnYigxLDk1LDE4Mik7IEZPTlQtU1RZTEU6IG5vcm1hbCI+NOS6uuaU +tuiXjzwvQ0lURT48QSANCiAgdGl0bGU95Li65LuA5LmI6K+05LqR6K6h566X5piv56e75Yqo55qE +5pyq5p2lIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiAN +CiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsODUpOyANCiAgaHJlZj0iaHR0cDovL21vYmls +ZS5jc2RuLm5ldC9uLzIwMTAxMjEzLzI4MzQ3MC5odG1sIiANCiAgdGFyZ2V0PV9ibGFuaz7kuLrk +u4DkuYjor7TkupHorqHnrpfmmK/np7vliqjnmoTmnKrmnaU8L0E+PC9EVD4NCiAgPERUIGNsYXNz +PXR4dF9ibGFjayANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJ +VElPTjogMHB4IDhweDsgUEFERElORy1MRUZUOiAxMHB4OyBGT05ULVNJWkU6IDE0cHg7IEJBQ0tH +Uk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9w +aWMyNi5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDNweCAwcHg7IENPTE9SOiBy +Z2IoMCwwLDApOyBQQURESU5HLVRPUDogMHB4OyBQT1NJVElPTjogcmVsYXRpdmU7IGJhY2tncm91 +bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxDSVRFIA0KICBj +bGFzcz0idHh0X2JsdWUgdHh0XzEyIiANCiAgc3R5bGU9IkZPTlQtU0laRTogMTJweDsgRkxPQVQ6 +IHJpZ2h0OyBDT0xPUjogcmdiKDEsOTUsMTgyKTsgRk9OVC1TVFlMRTogbm9ybWFsIj4y5Lq65pS2 +6JePPC9DSVRFPjxBIA0KICB0aXRsZT0yMDEw5bm05raI6LS555S15a2Q5oqA5pyvMjDkuKrmnIDl +pKflpLHotKXvvJpCdXp65bGF6aaWIA0KICBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQt +REVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDg1KTsgDQog +IGhyZWY9Imh0dHA6Ly9uZXdzLmNzZG4ubmV0L2EvMjAxMDEyMTMvMjgzNDY1Lmh0bWwiIA0KICB0 +YXJnZXQ9X2JsYW5rPjIwMTDlubTmtojotLnnlLXlrZDmioDmnK8yMOS4quacgOWkp+Wksei0pe+8 +mkJ1enrlsYXpppY8L0E+PC9EVD4NCiAgPERUIGNsYXNzPXR4dF9ibGFjayANCiAgc3R5bGU9IlBB +RERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMHB4IDhweDsgUEFERElORy1M +RUZUOiAxMHB4OyBGT05ULVNJWkU6IDE0cHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8v +Y3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMyNi5naWYpOyBQQURESU5HLUJPVFRP +TTogMHB4OyBNQVJHSU46IDNweCAwcHg7IENPTE9SOiByZ2IoMCwwLDApOyBQQURESU5HLVRPUDog +MHB4OyBQT1NJVElPTjogcmVsYXRpdmU7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNr +Z3JvdW5kLWNsaXA6IGluaXRpYWwiPjxDSVRFIA0KICBjbGFzcz0idHh0X2JsdWUgdHh0XzEyIiAN +CiAgc3R5bGU9IkZPTlQtU0laRTogMTJweDsgRkxPQVQ6IHJpZ2h0OyBDT0xPUjogcmdiKDEsOTUs +MTgyKTsgRk9OVC1TVFlMRTogbm9ybWFsIj415Lq65pS26JePPC9DSVRFPjxBIA0KICB0aXRsZT0i +55SoQyAg5YaZSmF2YSBTdHlsZeeoi+W6jyIgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhU +LURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw4NSk7IA0K +ICBocmVmPSJodHRwOi8vYmxvZy5jc2RuLm5ldC9rYWJpbmkvYXJjaGl2ZS8yMDEwLzEyLzA1LzYw +NTY2MTMuYXNweCIgDQogIHRhcmdldD1fYmxhbms+55SoQyDlhplKYXZhIFN0eWxl56iL5bqPPC9B +PjwvRFQ+DQogIDxEVCBjbGFzcz10eHRfYmxhY2sgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAw +cHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDBweCA4cHg7IFBBRERJTkctTEVGVDogMTBweDsgRk9O +VC1TSVpFOiAxNHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3 +L2ltYWdlcy9jc2RuaW5kZXhfcGljMjYuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lO +OiAzcHggMHB4OyBDT0xPUjogcmdiKDAsMCwwKTsgUEFERElORy1UT1A6IDBweDsgUE9TSVRJT046 +IHJlbGF0aXZlOyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBp +bml0aWFsIj48Q0lURSANCiAgY2xhc3M9InR4dF9ibHVlIHR4dF8xMiIgDQogIHN0eWxlPSJGT05U +LVNJWkU6IDEycHg7IEZMT0FUOiByaWdodDsgQ09MT1I6IHJnYigxLDk1LDE4Mik7IEZPTlQtU1RZ +TEU6IG5vcm1hbCI+OOS6uuaUtuiXjzwvQ0lURT48QSANCiAgdGl0bGU96Ieq5rWL5LiA5LiL5L2g +55qESmF2YeaOjOaPoeW+l+aAjuS5iOagt++8nyBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRF +WFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDg1KTsg +DQogIGhyZWY9Imh0dHA6Ly9ibG9nLmNzZG4ubmV0L2JpdGZhbi9hcmNoaXZlLzIwMTAvMTIvMTMv +NjA3MjY5MC5hc3B4IiANCiAgdGFyZ2V0PV9ibGFuaz7oh6rmtYvkuIDkuIvkvaDnmoRKYXZh5o6M +5o+h5b6X5oCO5LmI5qC377yfPC9BPjwvRFQ+DQogIDxEVCBjbGFzcz10eHRfYmxhY2sgDQogIHN0 +eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDBweCA4cHg7IFBB +RERJTkctTEVGVDogMTBweDsgRk9OVC1TSVpFOiAxNHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwo +aHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMjYuZ2lmKTsgUEFERElO +Ry1CT1RUT006IDBweDsgTUFSR0lOOiAzcHggMHB4OyBDT0xPUjogcmdiKDAsMCwwKTsgUEFERElO +Ry1UT1A6IDBweDsgUE9TSVRJT046IHJlbGF0aXZlOyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlh +bDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48Q0lURSANCiAgY2xhc3M9InR4dF9ibHVlIHR4 +dF8xMiIgDQogIHN0eWxlPSJGT05ULVNJWkU6IDEycHg7IEZMT0FUOiByaWdodDsgQ09MT1I6IHJn +YigxLDk1LDE4Mik7IEZPTlQtU1RZTEU6IG5vcm1hbCI+NOS6uuaUtuiXjzwvQ0lURT48QSANCiAg +dGl0bGU95Y2O5Li66Z2i6K+V6aKY566X5LuA5LmILOi/meS4quiDjOS8muS6huWkluS8gemaj+S+ +v+i/myBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQog +IG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDg1KTsgDQogIGhyZWY9Imh0dHA6Ly9ibG9nLmNz +ZG4ubmV0L2xpamllcnNvbjgvYXJjaGl2ZS8yMDEwLzEwLzI4LzU5NzA4NzQuYXNweCIgDQogIHRh +cmdldD1fYmxhbms+5Y2O5Li66Z2i6K+V6aKY566X5LuA5LmILOi/meS4quiDjOS8muS6huWkluS8 +gemaj+S+v+i/mzwvQT48L0RUPg0KICA8RFQgY2xhc3M9dHh0X2JsYWNrIA0KICBzdHlsZT0iUEFE +RElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAwcHggOHB4OyBQQURESU5HLUxF +RlQ6IDEwcHg7IEZPTlQtU0laRTogMTRweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9j +c2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzI2LmdpZik7IFBBRERJTkctQk9UVE9N +OiAwcHg7IE1BUkdJTjogM3B4IDBweDsgQ09MT1I6IHJnYigwLDAsMCk7IFBBRERJTkctVE9QOiAw +cHg7IFBPU0lUSU9OOiByZWxhdGl2ZTsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tn +cm91bmQtY2xpcDogaW5pdGlhbCI+PENJVEUgDQogIGNsYXNzPSJ0eHRfYmx1ZSB0eHRfMTIiIA0K +ICBzdHlsZT0iRk9OVC1TSVpFOiAxMnB4OyBGTE9BVDogcmlnaHQ7IENPTE9SOiByZ2IoMSw5NSwx +ODIpOyBGT05ULVNUWUxFOiBub3JtYWwiPjPkurrmlLbol488L0NJVEU+PEEgDQogIHRpdGxlPeeo +i+W6j+WRmO+8mue8lueoi+e7meS9oOeOsOWunueUn+a0u+W4puadpeS6huWTquS6m+Wdj+S5oOaD +ryBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9u +Y2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDg1KTsgDQogIGhyZWY9Imh0dHA6Ly9ibG9nLmNzZG4u +bmV0L01hY19jbS9hcmNoaXZlLzIwMTAvMTEvMDkvNTk5NzQ3Ny5hc3B4IiANCiAgdGFyZ2V0PV9i +bGFuaz7nqIvluo/lkZjvvJrnvJbnqIvnu5nkvaDnjrDlrp7nlJ/mtLvluKbmnaXkuoblk6rkupvl +nY/kuaDmg688L0E+PC9EVD4NCiAgPERUIGNsYXNzPXR4dF9ibGFjayANCiAgc3R5bGU9IlBBRERJ +TkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMHB4IDhweDsgUEFERElORy1MRUZU +OiAxMHB4OyBGT05ULVNJWkU6IDE0cHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3Nk +bmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMyNi5naWYpOyBQQURESU5HLUJPVFRPTTog +MHB4OyBNQVJHSU46IDNweCAwcHg7IENPTE9SOiByZ2IoMCwwLDApOyBQQURESU5HLVRPUDogMHB4 +OyBQT1NJVElPTjogcmVsYXRpdmU7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3Jv +dW5kLWNsaXA6IGluaXRpYWwiPjxDSVRFIA0KICBjbGFzcz0idHh0X2JsdWUgdHh0XzEyIiANCiAg +c3R5bGU9IkZPTlQtU0laRTogMTJweDsgRkxPQVQ6IHJpZ2h0OyBDT0xPUjogcmdiKDEsOTUsMTgy +KTsgRk9OVC1TVFlMRTogbm9ybWFsIj415Lq65pS26JePPC9DSVRFPjxBIA0KICB0aXRsZT3nu6fm +ib/kuI7mt7flkIjvvIznlaXosIjns7vnu5/nmoTmnoTlu7rmlrnlvI8gc3R5bGU9IkNPTE9SOiBy +Z2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291 +bnQodGhpcyw4NSk7IA0KICBocmVmPSJodHRwOi8vYmxvZy5jc2RuLm5ldC9haW1pbmdvby9hcmNo +aXZlLzIwMTAvMTIvMDgvNjA2Mjk5Ny5hc3B4IiANCiAgdGFyZ2V0PV9ibGFuaz7nu6fmib/kuI7m +t7flkIjvvIznlaXosIjns7vnu5/nmoTmnoTlu7rmlrnlvI88L0E+PC9EVD4NCiAgPEREIGNsYXNz +PW5ld3NfdHlwZWEgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IFBBRERJTkctTEVGVDog +MHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9j +c2RuaW5kZXhfcGljNDYuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAtM3B4IDBw +eCAxMHB4OyBQQURESU5HLVRPUDogMHB4OyBQT1NJVElPTjogcmVsYXRpdmU7IEhFSUdIVDogMTlw +eDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+ +PERGTiANCiAgc3R5bGU9IkxFRlQ6IDM4OXB4OyBDT0xPUjogcmdiKDI1NSwyNTUsMjU1KTsgRk9O +VC1TVFlMRTogbm9ybWFsOyBQT1NJVElPTjogYWJzb2x1dGU7IFRPUDogMnB4Ij7mnIDmlrDnvZHm +kZg8L0RGTj48L0REPg0KICA8RFQgY2xhc3M9dHh0X2JsYWNrIA0KICBzdHlsZT0iUEFERElORy1S +SUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAwcHggOHB4OyBQQURESU5HLUxFRlQ6IDEw +cHg7IEZPTlQtU0laRTogMTRweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1n +LmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzI2LmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7 +IE1BUkdJTjogM3B4IDBweDsgQ09MT1I6IHJnYigwLDAsMCk7IFBBRERJTkctVE9QOiAwcHg7IFBP +U0lUSU9OOiByZWxhdGl2ZTsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQt +Y2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxlPeOAkOWFrOWRiuOAkUNTRE7pq5jmoKHkv7HkuZDp +g6jkuLvluK3ngavng63mi5vli5/kuK0gc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURF +Q09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcywxMDcpOyANCiAg +aHJlZj0iaHR0cDovL3N0dWRlbnQuY3Nkbi5uZXQvc3BhY2UucGhwP3VpZD05OTY0MjYmYW1wO2Rv +PXRocmVhZCZhbXA7aWQ9MzU3NzgiIA0KICB0YXJnZXQ9X2JsYW5rPuOAkOWFrOWRiuOAkUNTRE7p +q5jmoKHkv7HkuZDpg6jkuLvluK3ngavng63mi5vli5/kuK08L0E+PC9EVD4NCiAgPERUIGNsYXNz +PXR4dF9ibGFjayANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJ +VElPTjogMHB4IDhweDsgUEFERElORy1MRUZUOiAxMHB4OyBGT05ULVNJWkU6IDE0cHg7IEJBQ0tH +Uk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9w +aWMyNi5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDNweCAwcHg7IENPTE9SOiBy +Z2IoMCwwLDApOyBQQURESU5HLVRPUDogMHB4OyBQT1NJVElPTjogcmVsYXRpdmU7IGJhY2tncm91 +bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0aXRs +ZT3jgJDlpKnmtKXjgJHlpKnmtKXogYzkuJrlpKflraZDU0RO6auY5qCh5L+x5LmQ6YOo5q2j5byP +5oiQ56uLIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiAN +CiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsMTA3KTsgDQogIGhyZWY9Imh0dHA6Ly9zdHVk +ZW50LmNzZG4ubmV0L3NwYWNlLnBocD91aWQ9OTk2NDI2JmFtcDtkbz10aHJlYWQmYW1wO2lkPTQw +Nzg1IiANCiAgdGFyZ2V0PV9ibGFuaz7jgJDlpKnmtKXjgJHlpKnmtKXogYzkuJrlpKflraZDU0RO +6auY5qCh5L+x5LmQ6YOo5q2j5byP5oiQ56uLPC9BPjwvRFQ+DQogIDxEVCBjbGFzcz10eHRfYmxh +Y2sgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDBw +eCA4cHg7IFBBRERJTkctTEVGVDogMTBweDsgRk9OVC1TSVpFOiAxNHB4OyBCQUNLR1JPVU5ELUlN +QUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMjYuZ2lm +KTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAzcHggMHB4OyBDT0xPUjogcmdiKDAsMCww +KTsgUEFERElORy1UT1A6IDBweDsgUE9TSVRJT046IHJlbGF0aXZlOyBiYWNrZ3JvdW5kLW9yaWdp +bjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgdGl0bGU944CQ6am7 +6ams5bqX44CR6buE5reu5a2m6Zmi56ys5LiA5pyf5Zyo57q/6K6y5aCC5oiQ5Yqf5Li+5YqeIHN0 +eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGlj +az1Mb2dDbGlja0NvdW50KHRoaXMsMTA3KTsgDQogIGhyZWY9Imh0dHA6Ly9zdHVkZW50LmNzZG4u +bmV0L3NwYWNlLnBocD91aWQ9OTk2NDI2JmFtcDtkbz10aHJlYWQmYW1wO2lkPTQwNDYxIiANCiAg +dGFyZ2V0PV9ibGFuaz7jgJDpqbvpqazlupfjgJHpu4Tmt67lrabpmaLnrKzkuIDmnJ/lnKjnur/o +rrLloILmiJDlip/kuL7lip48L0E+PC9EVD4NCiAgPERUIGNsYXNzPXR4dF9ibGFjayANCiAgc3R5 +bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMHB4IDhweDsgUEFE +RElORy1MRUZUOiAxMHB4OyBGT05ULVNJWkU6IDE0cHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybCho +dHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMyNi5naWYpOyBQQURESU5H +LUJPVFRPTTogMHB4OyBNQVJHSU46IDNweCAwcHg7IENPTE9SOiByZ2IoMCwwLDApOyBQQURESU5H +LVRPUDogMHB4OyBQT1NJVElPTjogcmVsYXRpdmU7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFs +OyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0aXRsZT3jgJDkv53lrprjgJHmsrPo +va9DU0RO6auY5qCh5L+x5LmQ6YOo5q2j5byP5oiQ56uLIHN0eWxlPSJDT0xPUjogcmdiKDAsMCww +KTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMs +MTA3KTsgDQogIGhyZWY9Imh0dHA6Ly9zdHVkZW50LmNzZG4ubmV0L3NwYWNlLnBocD91aWQ9OTk2 +NDI2JmFtcDtkbz10aHJlYWQmYW1wO2lkPTQwMjk5IiANCiAgdGFyZ2V0PV9ibGFuaz7jgJDkv53l +rprjgJHmsrPova9DU0RO6auY5qCh5L+x5LmQ6YOo5q2j5byP5oiQ56uLPC9BPjwvRFQ+DQogIDxE +VCBjbGFzcz10eHRfYmxhY2sgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9V +TkQtUE9TSVRJT046IDBweCA4cHg7IFBBRERJTkctTEVGVDogMTBweDsgRk9OVC1TSVpFOiAxNHB4 +OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2Ru +aW5kZXhfcGljMjYuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAzcHggMHB4OyBD +T0xPUjogcmdiKDAsMCwwKTsgUEFERElORy1UT1A6IDBweDsgUE9TSVRJT046IHJlbGF0aXZlOyBi +YWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSAN +CiAgdGl0bGU944CQ5L+d5a6a44CRQ1NETumrmOagoeS/seS5kOmDqOiQveaIt+ays+WMl+mHkeie +jeWtpumZoiBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIg +DQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDEwNyk7IA0KICBocmVmPSJodHRwOi8vc3R1 +ZGVudC5jc2RuLm5ldC9zcGFjZS5waHA/dWlkPTk5NjQyNiZhbXA7ZG89dGhyZWFkJmFtcDtpZD00 +MDUwMyIgDQogIHRhcmdldD1fYmxhbms+44CQ5L+d5a6a44CRQ1NETumrmOagoeS/seS5kOmDqOiQ +veaIt+ays+WMl+mHkeiejeWtpumZojwvQT48L0RUPg0KICA8REQgY2xhc3M9bmV3c190eXBlYSAN +CiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgUEFERElORy1MRUZUOiAwcHg7IEJBQ0tHUk9V +TkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWM0 +Ni5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IC0zcHggMHB4IDEwcHg7IFBBRERJ +TkctVE9QOiAwcHg7IFBPU0lUSU9OOiByZWxhdGl2ZTsgSEVJR0hUOiAxOXB4OyBiYWNrZ3JvdW5k +LW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48REZOIA0KICBzdHls +ZT0iTEVGVDogMzg5cHg7IENPTE9SOiByZ2IoMjU1LDI1NSwyNTUpOyBGT05ULVNUWUxFOiBub3Jt +YWw7IFBPU0lUSU9OOiBhYnNvbHV0ZTsgVE9QOiAycHgiPumrmOagoWNsdWI8L0RGTj48L0REPjwv +REw+PC9ESVY+PC9ESVY+DQo8RElWIGNsYXNzPXBhZ2Vjb25fbGF5ZXIyX21pZCANCnN0eWxlPSJC +T1JERVItVE9QOiByZ2IoMjA0LDIwNCwyMDQpIDFweCBzb2xpZDsgRElTUExBWTogaW5saW5lOyBG +TE9BVDogbGVmdDsgTUFSR0lOOiAwcHggMHB4IDBweCA1cHg7IFdJRFRIOiAyNTlweDsgVEVYVC1B +TElHTjogbGVmdCI+DQo8SDMgDQpzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5E +LVBPU0lUSU9OOiAwcHggMHB4OyBESVNQTEFZOiBpbmxpbmU7IFBBRERJTkctTEVGVDogMjBweDsg +Rk9OVC1TSVpFOiAxNHB4OyBGTE9BVDogbGVmdDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6 +Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzE1LmdpZik7IFBBRERJTkctQk9U +VE9NOiAwcHg7IE1BUkdJTjogMHB4IDBweCA3cHg7IFdJRFRIOiAyMzlweDsgTElORS1IRUlHSFQ6 +IDMwcHg7IFBBRERJTkctVE9QOiAwcHg7IFBPU0lUSU9OOiByZWxhdGl2ZTsgYmFja2dyb3VuZC1v +cmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PFNQQU4gDQpjbGFzcz0i +dHh0XzEyIHR4dF9ncmF5IiANCnN0eWxlPSJGT05ULVdFSUdIVDogbm9ybWFsOyBGT05ULVNJWkU6 +IDEycHg7IEZMT0FUOiByaWdodDsgTUFSR0lOOiAycHggN3B4IDBweCAwcHg7IENPTE9SOiByZ2Io +MTAyLDEwMiwxMDIpIj48QSANCnN0eWxlPSJDT0xPUjogcmdiKDEwMiwxMDIsMTAyKTsgVEVYVC1E +RUNPUkFUSU9OOiBub25lIiANCmhyZWY9Imh0dHA6Ly9iYnMuY3Nkbi5uZXQvIiB0YXJnZXQ9X2Js +YW5rPuabtOWkmjwvQT48L1NQQU4+56S+5Yy65LmL5pifPC9IMz4NCjxETCBjbGFzcz1leHBlcnRz +aG93IA0Kc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogNTAl +IDEwMCU7IERJU1BMQVk6IGlubGluZTsgUEFERElORy1MRUZUOiAwcHg7IEZMT0FUOiBsZWZ0OyBC +QUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5k +ZXhfcGljMTQuZ2lmKTsgUEFERElORy1CT1RUT006IDNweDsgTUFSR0lOOiA2cHggMTBweCAwcHg7 +IFdJRFRIOiAyMzlweDsgUEFERElORy1UT1A6IDBweDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRp +YWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+DQogIDxERCBjbGFzcz1waWNzIA0KICBzdHls +ZT0iUEFERElORy1SSUdIVDogMHB4OyBQQURESU5HLUxFRlQ6IDBweDsgRkxPQVQ6IGxlZnQ7IEJB +Q0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRl +eF9waWM0Ny5naWYpOyBQQURESU5HLUJPVFRPTTogM3B4OyBNQVJHSU46IDBweCA2cHggMHB4IDBw +eDsgV0lEVEg6IDkzcHg7IFBBRERJTkctVE9QOiAwcHg7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0 +aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0aXRsZT3okovmmZ/vvJrnpL7l +jLrkuJPlrrYgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUi +IA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw4Nyk7IGhyZWY9Imh0dHA6Ly9oaS5jc2Ru +Lm5ldC9qaWFuZ3NoZW5nIiANCiAgdGFyZ2V0PV9ibGFuaz48SU1HIHRpdGxlPSIiIA0KICBzdHls +ZT0iQk9SREVSLVJJR0hUOiByZ2IoMCwwLDApIDFweCBzb2xpZDsgQk9SREVSLVRPUDogcmdiKDAs +MCwwKSAxcHggc29saWQ7IEJPUkRFUi1MRUZUOiByZ2IoMCwwLDApIDFweCBzb2xpZDsgV0lEVEg6 +IDg2cHg7IEJPUkRFUi1CT1RUT006IHJnYigwLDAsMCkgMXB4IHNvbGlkOyBIRUlHSFQ6IDg2cHgi +IA0KICBoZWlnaHQ9ODYgYWx0PSIiIHNyYz0iaHR0cDovL2F2YXRhci5wcm9maWxlLmNzZG4ubmV0 +L0YvRS84LzFfamlhbmdzaGVuZy5qcGciIA0KICB3aWR0aD04Nj48L0E+PC9ERD4NCiAgPEREIGNs +YXNzPXR4dF9ibHVlIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBQQURESU5HLUxFRlQ6 +IDBweDsgUEFERElORy1CT1RUT006IDNweDsgTUFSR0lOOiAwcHg7IENPTE9SOiByZ2IoMSw5NSwx +ODIpOyBQQURESU5HLVRPUDogMHB4Ij48QSANCiAgdGl0bGU96JKL5pmf77ya56S+5Yy65LiT5a62 +IHN0eWxlPSJDT0xPUjogcmdiKDEsOTUsMTgyKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAg +b25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsODcpOyBocmVmPSJodHRwOi8vaGkuY3Nkbi5uZXQv +amlhbmdzaGVuZyIgDQogIHRhcmdldD1fYmxhbms+6JKL5pmf77ya56S+5Yy65LiT5a62PC9BPjwv +REQ+DQogIDxERCANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgUEFERElORy1MRUZUOiAw +cHg7IFBBRERJTkctQk9UVE9NOiAzcHg7IE1BUkdJTjogMHB4OyBQQURESU5HLVRPUDogMHB4Ij5D +U0RO5aSn54mI5Li7LOW+rui9r+acgOacieS7t+WAvOS4k+Wutu+8jOaThemVvy5ORVTjgIFBY3Rp +dmVY44CBQXBwbGljYXRpb248L0REPg0KICA8REQgY2xhc3M9ImFzayB0eHRfYmx1ZSIgDQogIHN0 +eWxlPSJQQURESU5HLVJJR0hUOiA1cHg7IFBBRERJTkctTEVGVDogMHB4OyBGTE9BVDogcmlnaHQ7 +IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBDT0xPUjogcmdiKDEsOTUsMTgyKTsg +UEFERElORy1UT1A6IDBweCI+PEEgDQogIHRpdGxlPeiSi+aZn++8muekvuWMuuS4k+WutiBzdHls +ZT0iQ09MT1I6IHJnYigxLDk1LDE4Mik7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xp +Y2s9TG9nQ2xpY2tDb3VudCh0aGlzLDg3KTsgaHJlZj0iaHR0cDovL2hpLmNzZG4ubmV0L2ppYW5n +c2hlbmciIA0KICB0YXJnZXQ9X2JsYW5rPuiuv+mXruS7lueahOepuumXtDwvQT48L0REPjwvREw+ +DQo8SDMgDQpzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAw +cHggMHB4OyBESVNQTEFZOiBpbmxpbmU7IFBBRERJTkctTEVGVDogMjBweDsgRk9OVC1TSVpFOiAx +NHB4OyBGTE9BVDogbGVmdDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNu +L3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzE1LmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1B +UkdJTjogMHB4IDBweCA3cHg7IFdJRFRIOiAyMzlweDsgTElORS1IRUlHSFQ6IDMwcHg7IFBBRERJ +TkctVE9QOiAwcHg7IFBPU0lUSU9OOiByZWxhdGl2ZTsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRp +YWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PFNQQU4gDQpjbGFzcz0idHh0XzEyIHR4dF9n +cmF5IiANCnN0eWxlPSJGT05ULVdFSUdIVDogbm9ybWFsOyBGT05ULVNJWkU6IDEycHg7IEZMT0FU +OiByaWdodDsgTUFSR0lOOiAycHggN3B4IDBweCAwcHg7IENPTE9SOiByZ2IoMTAyLDEwMiwxMDIp +Ij48QSANCnN0eWxlPSJDT0xPUjogcmdiKDEwMiwxMDIsMTAyKTsgVEVYVC1ERUNPUkFUSU9OOiBu +b25lIiANCmhyZWY9Imh0dHA6Ly9iYnMuY3Nkbi5uZXQvIiB0YXJnZXQ9X2JsYW5rPuabtOWkmjwv +QT48L1NQQU4+56S+5Yy65paw6K+d6aKYPC9IMz4NCjxETCBjbGFzcz0ic3R5bGUzIHR4dF9ibGFj +ayIgDQpzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBESVNQTEFZOiBpbmxpbmU7IFBBRERJTkct +TEVGVDogMHB4OyBGTE9BVDogbGVmdDsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiA1cHgg +MTBweDsgV0lEVEg6IDIzOXB4OyBDT0xPUjogcmdiKDAsMCwwKTsgUEFERElORy1UT1A6IDBweCI+ +DQogIDxERCANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElP +TjogM3B4IDdweDsgUEFERElORy1MRUZUOiAxNHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0 +cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMjMuZ2lmKTsgUEFERElORy1C +T1RUT006IDBweDsgTUFSR0lOOiAwcHg7IExJTkUtSEVJR0hUOiAyMXB4OyBQQURESU5HLVRPUDog +MHB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFs +Ij48QSANCiAgdGl0bGU95bel5L2c5Lit55qE5bCP5o+S5puy77yM6KeB6K+GQ1NETui+vuS6uiBz +dHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xp +Y2s9TG9nQ2xpY2tDb3VudCh0aGlzLDg4KTsgDQogIGhyZWY9Imh0dHA6Ly90b3BpYy5jc2RuLm5l +dC91LzIwMTAxMjE1LzE3LzdhOTlkMzdmLWVmMTMtNDg1NC04YWMzLWQzZGE0MWY3ODA4Ny5odG1s +IiANCiAgdGFyZ2V0PV9ibGFuaz7lt6XkvZzkuK3nmoTlsI/mj5Lmm7LvvIzop4Hor4ZDU0RO6L6+ +5Lq6PC9BPjwvREQ+DQogIDxERCANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dS +T1VORC1QT1NJVElPTjogM3B4IDdweDsgUEFERElORy1MRUZUOiAxNHB4OyBCQUNLR1JPVU5ELUlN +QUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMjMuZ2lm +KTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IExJTkUtSEVJR0hUOiAyMXB4OyBQ +QURESU5HLVRPUDogMHB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1j +bGlwOiBpbml0aWFsIj48QSANCiAgdGl0bGU95Y+R5ama54Wn77yM5rGC56Wd56aPfn5+77yBIHN0 +eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGlj +az1Mb2dDbGlja0NvdW50KHRoaXMsODgpOyANCiAgaHJlZj0iaHR0cDovL3RvcGljLmNzZG4ubmV0 +L3UvMjAxMDEyMTQvMTQvOWI0ODBlMDctMjVjYy00NTZjLWFkZGEtYWRhZTVlOTJkZGQ2Lmh0bWwi +IA0KICB0YXJnZXQ9X2JsYW5rPuWPkeWpmueFp++8jOaxguelneemj35+fu+8gTwvQT48L0REPg0K +ICA8REQgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046 +IDNweCA3cHg7IFBBRERJTkctTEVGVDogMTRweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6 +Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzIzLmdpZik7IFBBRERJTkctQk9U +VE9NOiAwcHg7IE1BUkdJTjogMHB4OyBMSU5FLUhFSUdIVDogMjFweDsgUEFERElORy1UT1A6IDBw +eDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+ +PEEgDQogIHRpdGxlPe+8iOi9rO+8ieWboOS4uuaIkeaYr+S9oOWqs+Wmh+WEvyBzdHlsZT0iQ09M +T1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xp +Y2tDb3VudCh0aGlzLDg4KTsgDQogIGhyZWY9Imh0dHA6Ly90b3BpYy5jc2RuLm5ldC91LzIwMTAx +MjE0LzEwLzVlMDRlZDdjLTJmOTItNGFkNC04ZmQ5LTFmOGU5ZTAxM2Q5MC5odG1sIiANCiAgdGFy +Z2V0PV9ibGFuaz7vvIjovazvvInlm6DkuLrmiJHmmK/kvaDlqrPlpoflhL88L0E+PC9ERD4NCiAg +PEREIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAz +cHggN3B4OyBQQURESU5HLUxFRlQ6IDE0cHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8v +Y3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMyMy5naWYpOyBQQURESU5HLUJPVFRP +TTogMHB4OyBNQVJHSU46IDBweDsgTElORS1IRUlHSFQ6IDIxcHg7IFBBRERJTkctVE9QOiAwcHg7 +IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxB +IA0KICB0aXRsZT3lr7nllpzmrKLnmoTkurrmlL7lvIPov5jmmK/nu6fnu63vvJ/miJHlvojnn5vn +m74gc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBv +bmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw4OCk7IA0KICBocmVmPSJodHRwOi8vdG9waWMuY3Nk +bi5uZXQvdS8yMDEwMTIxNC8xNS81MWViZjg5ZC05M2U2LTQ1ZDQtODY4OS00NGEyNzY2MTE0N2Uu +aHRtbCIgDQogIHRhcmdldD1fYmxhbms+5a+55Zac5qyi55qE5Lq65pS+5byD6L+Y5piv57un57ut +77yf5oiR5b6I55+b55u+PC9BPjwvREQ+DQogIDxERCANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6 +IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogM3B4IDdweDsgUEFERElORy1MRUZUOiAxNHB4OyBC +QUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5k +ZXhfcGljMjMuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IExJTkUtSEVJ +R0hUOiAyMXB4OyBQQURESU5HLVRPUDogMHB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsg +YmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgdGl0bGU95bCP5pe25YCZ6KKr572a77yM +5bmy6L+H6L+Z56eN5LqL5oOF55qE56ul6Z6L6K+35Li+5omLIHN0eWxlPSJDT0xPUjogcmdiKDAs +MCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRo +aXMsODgpOyANCiAgaHJlZj0iaHR0cDovL3RvcGljLmNzZG4ubmV0L3UvMjAxMDEyMTUvMTIvZmUz +YzNkNTQtYTdjYi00OWQ5LWI2NmQtZDVhOTU1ZDE5NmRkLmh0bWwiIA0KICB0YXJnZXQ9X2JsYW5r +PuWwj+aXtuWAmeiiq+e9mu+8jOW5sui/h+i/meenjeS6i+aDheeahOerpemei+ivt+S4vuaJizwv +QT48L0REPg0KICA8REQgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQt +UE9TSVRJT046IDNweCA3cHg7IFBBRERJTkctTEVGVDogMTRweDsgQkFDS0dST1VORC1JTUFHRTog +dXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzIzLmdpZik7IFBB +RERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBMSU5FLUhFSUdIVDogMjFweDsgUEFERElO +Ry1UT1A6IDBweDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDog +aW5pdGlhbCI+PEEgDQogIHRpdGxlPeOAkOWMl+S6rOOAkeWbm+W5tOW3peS9nOe7j+mqjOecn+ea +hOiDveaLvzhL5LmI77yfIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9O +OiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsODgpOyANCiAgaHJlZj0iaHR0 +cDovL3RvcGljLmNzZG4ubmV0L3UvMjAxMDEyMTUvMTAvYTE2ODg3OTgtZmNmZC00YTVlLTlkNjUt +MTI5MDcxOWE1N2Q0Lmh0bWwiIA0KICB0YXJnZXQ9X2JsYW5rPuOAkOWMl+S6rOOAkeWbm+W5tOW3 +peS9nOe7j+mqjOecn+eahOiDveaLvzhL5LmI77yfPC9BPjwvREQ+DQogIDxERCANCiAgc3R5bGU9 +IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogM3B4IDdweDsgUEFERElO +Ry1MRUZUOiAxNHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3 +L2ltYWdlcy9jc2RuaW5kZXhfcGljMjMuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lO +OiAwcHg7IExJTkUtSEVJR0hUOiAyMXB4OyBQQURESU5HLVRPUDogMHB4OyBiYWNrZ3JvdW5kLW9y +aWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgdGl0bGU95bCP +5byf5piO5aSp5LiL5Y2I5Y676IW+6K6v6Z2i6K+VIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsg +VEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsODgp +OyANCiAgaHJlZj0iaHR0cDovL3RvcGljLmNzZG4ubmV0L3UvMjAxMDEyMTUvMDkvM2NjN2FjMTkt +MjdlNS00Nzc1LWE1ZjQtZmEwYmM2MDY2MjE2Lmh0bWwiIA0KICB0YXJnZXQ9X2JsYW5rPuWwj+W8 +n+aYjuWkqeS4i+WNiOWOu+iFvuiur+mdouivlTwvQT48L0REPg0KICA8REQgDQogIHN0eWxlPSJQ +QURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDNweCA3cHg7IFBBRERJTkct +TEVGVDogMTRweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9p +bWFnZXMvY3NkbmluZGV4X3BpYzIzLmdpZik7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjog +MHB4OyBMSU5FLUhFSUdIVDogMjFweDsgUEFERElORy1UT1A6IDBweDsgYmFja2dyb3VuZC1vcmln +aW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxlPeaOqOiN +kOWHoOmDqOWNsOW6pueahOeUteW9sX5+IHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1E +RUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsODgpOyANCiAg +aHJlZj0iaHR0cDovL3RvcGljLmNzZG4ubmV0L3UvMjAxMDEyMTUvMTYvYWQ1NGFhODQtY2IwZS00 +OTU4LTlhNzktYzg5YmFhZTBhZGVkLmh0bWwiIA0KICB0YXJnZXQ9X2JsYW5rPuaOqOiNkOWHoOmD +qOWNsOW6pueahOeUteW9sX5+PC9BPjwvREQ+DQogIDxERCANCiAgc3R5bGU9IlBBRERJTkctUklH +SFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogM3B4IDdweDsgUEFERElORy1MRUZUOiAxNHB4 +OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2Ru +aW5kZXhfcGljMjMuZ2lmKTsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IExJTkUt +SEVJR0hUOiAyMXB4OyBQQURESU5HLVRPUDogMHB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlh +bDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgdGl0bGU96ICB5p2/eXXlkZjlt6Xn +moTlr7nor53vvIjmkJ7ogIznnJ/vvIkgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURF +Q09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw4OCk7IA0KICBo +cmVmPSJodHRwOi8vdG9waWMuY3Nkbi5uZXQvdS8yMDEwMTIxNi8wMC9hMzRmYTVjNC0yNjgwLTQ2 +ZTMtYThmNS04YzZmYzI2YmZiNjQuaHRtbCIgDQogIHRhcmdldD1fYmxhbms+6ICB5p2/eXXlkZjl +t6XnmoTlr7nor53vvIjmkJ7ogIznnJ/vvIk8L0E+PC9ERD4NCiAgPEREIA0KICBzdHlsZT0iUEFE +RElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAzcHggN3B4OyBQQURESU5HLUxF +RlQ6IDE0cHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1h +Z2VzL2NzZG5pbmRleF9waWMyMy5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBw +eDsgTElORS1IRUlHSFQ6IDIxcHg7IFBBRERJTkctVE9QOiAwcHg7IGJhY2tncm91bmQtb3JpZ2lu +OiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICB0aXRsZT3lu7rorq5j +c2Ru5byA5LiA5Liq55S35oCn5YGl5bq35p2/5Z2XIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsg +VEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsODgp +OyANCiAgaHJlZj0iaHR0cDovL3RvcGljLmNzZG4ubmV0L3UvMjAxMDEyMTUvMTUvODEyMmViYjQt +Njk4Mi00Mjg2LThlYmUtNDIzYTE1ZmM3YTA4Lmh0bWwiIA0KICB0YXJnZXQ9X2JsYW5rPuW7uuiu +rmNzZG7lvIDkuIDkuKrnlLfmgKflgaXlurfmnb/lnZc8L0E+PC9ERD48L0RMPg0KPEgzIA0Kc3R5 +bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjogMHB4IDBweDsgRElT +UExBWTogaW5saW5lOyBQQURESU5HLUxFRlQ6IDIwcHg7IEZPTlQtU0laRTogMTRweDsgRkxPQVQ6 +IGxlZnQ7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2Vz +L2NzZG5pbmRleF9waWMxNS5naWYpOyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweCAw +cHggN3B4OyBXSURUSDogMjM5cHg7IExJTkUtSEVJR0hUOiAzMHB4OyBQQURESU5HLVRPUDogMHB4 +OyBQT1NJVElPTjogcmVsYXRpdmU7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3Jv +dW5kLWNsaXA6IGluaXRpYWwiPjxTUEFOIA0KY2xhc3M9InR4dF8xMiB0eHRfZ3JheSIgDQpzdHls +ZT0iRk9OVC1XRUlHSFQ6IG5vcm1hbDsgRk9OVC1TSVpFOiAxMnB4OyBGTE9BVDogcmlnaHQ7IE1B +UkdJTjogMnB4IDdweCAwcHggMHB4OyBDT0xPUjogcmdiKDEwMiwxMDIsMTAyKSI+PEEgDQpzdHls +ZT0iQ09MT1I6IHJnYigxMDIsMTAyLDEwMik7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQpocmVm +PSJodHRwOi8vYmJzLmNzZG4ubmV0LyIgdGFyZ2V0PV9ibGFuaz7mm7TlpJo8L0E+PC9TUEFOPueo +i+W6j+S6uueUnzwvSDM+DQo8REwgY2xhc3M9InN0eWxlMiB0eHRfYmxhY2siIA0Kc3R5bGU9IlBB +RERJTkctUklHSFQ6IDBweDsgRElTUExBWTogaW5saW5lOyBQQURESU5HLUxFRlQ6IDBweDsgRkxP +QVQ6IGxlZnQ7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogNXB4IDEwcHg7IFdJRFRIOiAy +MzlweDsgQ09MT1I6IHJnYigwLDAsMCk7IFBBRERJTkctVE9QOiAwcHgiPg0KICA8RFQgY2xhc3M9 +dG9wMSANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElPTjog +MHB4IDNweDsgT1ZFUkZMT1ctWTogaGlkZGVuOyBQQURESU5HLUxFRlQ6IDI0cHg7IEJBQ0tHUk9V +TkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWMz +NS5naWYpOyBPVkVSRkxPVy1YOiBoaWRkZW47IFBBRERJTkctQk9UVE9NOiAxcHg7IE1BUkdJTjog +MHB4OyBXSURUSDogMjEwcHg7IFBBRERJTkctVE9QOiA0cHg7IFdISVRFLVNQQUNFOiBub3dyYXA7 +IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxB +IA0KICB0aXRsZT0iU0Tova/ku7blpKfkvJrlnIbmu6Hnu5PmnZ8g5aqS5L2T5oql6YGT5Y+K55u4 +5YWzIiBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQog +IG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDg5KTsgDQogIGhyZWY9Imh0dHA6Ly90b3BpYy5j +c2RuLm5ldC91LzIwMTAxMjE1LzE1LzI3OUUyMzVGLTFGM0MtNERBMS1CMkZCLTQ5QTA4NTZDNEZC +Qy5odG1sIiANCiAgdGFyZ2V0PV9ibGFuaz5TROi9r+S7tuWkp+S8muWchua7oee7k+adnyDlqpLk +vZPmiqXpgZPlj4rnm7jlhbM8L0E+PC9EVD4NCiAgPERUIGNsYXNzPXRvcDIgDQogIHN0eWxlPSJQ +QURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDBweCAzcHg7IE9WRVJGTE9X +LVk6IGhpZGRlbjsgUEFERElORy1MRUZUOiAyNHB4OyBCQUNLR1JPVU5ELUlNQUdFOiB1cmwoaHR0 +cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljMzYuZ2lmKTsgT1ZFUkZMT1ct +WDogaGlkZGVuOyBQQURESU5HLUJPVFRPTTogMXB4OyBNQVJHSU46IDBweDsgV0lEVEg6IDIxMHB4 +OyBQQURESU5HLVRPUDogNHB4OyBXSElURS1TUEFDRTogbm93cmFwOyBiYWNrZ3JvdW5kLW9yaWdp +bjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgdGl0bGU95YG25ZKM +5YG255qE5ZCM5a2m5byg5LqM54uX77yI6L6D5a6M5pW054mI77yJIHN0eWxlPSJDT0xPUjogcmdi +KDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50 +KHRoaXMsODkpOyANCiAgaHJlZj0iaHR0cDovL3RvcGljLmNzZG4ubmV0L3UvMjAxMDEyMTQvMTcv +M0FFOUUzNzMtNDM0Mi00MDQxLUJFMzgtRTk5OTNBRTEzMDBCLmh0bWwiIA0KICB0YXJnZXQ9X2Js +YW5rPuWBtuWSjOWBtueahOWQjOWtpuW8oOS6jOeLl++8iOi+g+WujOaVtOeJiO+8iTwvQT48L0RU +Pg0KICA8RFQgY2xhc3M9dG9wMyANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dS +T1VORC1QT1NJVElPTjogMHB4IDNweDsgT1ZFUkZMT1ctWTogaGlkZGVuOyBQQURESU5HLUxFRlQ6 +IDI0cHg7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2Vz +L2NzZG5pbmRleF9waWMzNy5naWYpOyBPVkVSRkxPVy1YOiBoaWRkZW47IFBBRERJTkctQk9UVE9N +OiAxcHg7IE1BUkdJTjogMHB4OyBXSURUSDogMjEwcHg7IFBBRERJTkctVE9QOiA0cHg7IFdISVRF +LVNQQUNFOiBub3dyYXA7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNs +aXA6IGluaXRpYWwiPjxBIA0KICB0aXRsZT3pgIPnprvkuIDnur/ln47luILlpKflrrbov5jkvJrk +u47kuovljp/mnaXmlrnlkJHlkJfvvJ8gc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBURVhULURF +Q09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw4OSk7IA0KICBo +cmVmPSJodHRwOi8vdG9waWMuY3Nkbi5uZXQvdS8yMDEwMTIxMi8yMi9DRTcyRjY4My0wNzI3LTRC +QkEtQjk5NC1DMzVDMTkyNzYyNDcuaHRtbCIgDQogIHRhcmdldD1fYmxhbms+6YCD56a75LiA57q/ +5Z+O5biC5aSn5a626L+Y5Lya5LuO5LqL5Y6f5p2l5pa55ZCR5ZCX77yfPC9BPjwvRFQ+DQogIDxE +VCBjbGFzcz10b3A0IA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBP +U0lUSU9OOiAwcHggM3B4OyBPVkVSRkxPVy1ZOiBoaWRkZW47IFBBRERJTkctTEVGVDogMjRweDsg +QkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3Nkbmlu +ZGV4X3BpYzM4LmdpZik7IE9WRVJGTE9XLVg6IGhpZGRlbjsgUEFERElORy1CT1RUT006IDFweDsg +TUFSR0lOOiAwcHg7IFdJRFRIOiAyMTBweDsgUEFERElORy1UT1A6IDRweDsgV0hJVEUtU1BBQ0U6 +IG5vd3JhcDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5p +dGlhbCI+PEEgDQogIHRpdGxlPeaBouWkjUlF5Li66buY6K6k5LiL6L295bel5YW3IHN0eWxlPSJD +T0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1Mb2dD +bGlja0NvdW50KHRoaXMsODkpOyANCiAgaHJlZj0iaHR0cDovL3RvcGljLmNzZG4ubmV0L3UvMjAx +MDEyMTMvMTEvMjExMzA1MjQtMTJCNC00NjYyLUFFNDctNTE2OTQ2OThCMzgyLmh0bWwiIA0KICB0 +YXJnZXQ9X2JsYW5rPuaBouWkjUlF5Li66buY6K6k5LiL6L295bel5YW3PC9BPjwvRFQ+DQogIDxE +VCBjbGFzcz10b3A1IA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBCQUNLR1JPVU5ELVBP +U0lUSU9OOiAwcHggM3B4OyBPVkVSRkxPVy1ZOiBoaWRkZW47IFBBRERJTkctTEVGVDogMjRweDsg +QkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvY3Nkbmlu +ZGV4X3BpYzM5LmdpZik7IE9WRVJGTE9XLVg6IGhpZGRlbjsgUEFERElORy1CT1RUT006IDFweDsg +TUFSR0lOOiAwcHg7IFdJRFRIOiAyMTBweDsgUEFERElORy1UT1A6IDRweDsgV0hJVEUtU1BBQ0U6 +IG5vd3JhcDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tncm91bmQtY2xpcDogaW5p +dGlhbCI+PEEgDQogIHRpdGxlPSLku4rml6XotZvkuovmjqjku4vvvJrmm7zogZQgVlMg6Zi/5qOu +57qzIiBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQog +IG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDg5KTsgDQogIGhyZWY9Imh0dHA6Ly90b3BpYy5j +c2RuLm5ldC91LzIwMTAxMjEzLzEzL0I3RjRFNDZDLTZBMDQtNENBNS1COUI4LTMwRTA5MDFCQTgz +Ni5odG1sIiANCiAgdGFyZ2V0PV9ibGFuaz7ku4rml6XotZvkuovmjqjku4vvvJrmm7zogZQgVlMg +6Zi/5qOu57qzPC9BPjwvRFQ+DQogIDxEVCBjbGFzcz10b3A2IA0KICBzdHlsZT0iUEFERElORy1S +SUdIVDogMHB4OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAwcHggM3B4OyBPVkVSRkxPVy1ZOiBoaWRk +ZW47IFBBRERJTkctTEVGVDogMjRweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2Ru +aW1nLmNuL3d3dy9pbWFnZXMvY3NkbmluZGV4X3BpYzQwLmdpZik7IE9WRVJGTE9XLVg6IGhpZGRl +bjsgUEFERElORy1CT1RUT006IDFweDsgTUFSR0lOOiAwcHg7IFdJRFRIOiAyMTBweDsgUEFERElO +Ry1UT1A6IDRweDsgV0hJVEUtU1BBQ0U6IG5vd3JhcDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRp +YWw7IGJhY2tncm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxlPeWmguS9leaIkOS4uuS4 +gOWQjeS8mOengOeahEFuZHJvaWTlvIDlj5HogIUgc3R5bGU9IkNPTE9SOiByZ2IoMCwwLDApOyBU +RVhULURFQ09SQVRJT046IG5vbmUiIA0KICBvbmNsaWNrPUxvZ0NsaWNrQ291bnQodGhpcyw4OSk7 +IA0KICBocmVmPSJodHRwOi8vdG9waWMuY3Nkbi5uZXQvdS8yMDEwMTIwOS8xNS9FMzAxQTRDRC0z +RDM2LTRFNEItOTgwOS0xNTVGNDlEQjlDNDguaHRtbCIgDQogIHRhcmdldD1fYmxhbms+5aaC5L2V +5oiQ5Li65LiA5ZCN5LyY56eA55qEQW5kcm9pZOW8gOWPkeiAhTwvQT48L0RUPg0KICA8RFQgY2xh +c3M9dG9wNyANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgQkFDS0dST1VORC1QT1NJVElP +TjogMHB4IDNweDsgT1ZFUkZMT1ctWTogaGlkZGVuOyBQQURESU5HLUxFRlQ6IDI0cHg7IEJBQ0tH +Uk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3NkbmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9w +aWM0MS5naWYpOyBPVkVSRkxPVy1YOiBoaWRkZW47IFBBRERJTkctQk9UVE9NOiAxcHg7IE1BUkdJ +TjogMHB4OyBXSURUSDogMjEwcHg7IFBBRERJTkctVE9QOiA0cHg7IFdISVRFLVNQQUNFOiBub3dy +YXA7IGJhY2tncm91bmQtb3JpZ2luOiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwi +PjxBIA0KICB0aXRsZT1bI3c2VEN1c0tSdzZmQ3ZNS1d3NmZDb01LQiNd5LqR57yW56CBIA0KICBz +dHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xp +Y2s9TG9nQ2xpY2tDb3VudCh0aGlzLDg5KTsgDQogIGhyZWY9Imh0dHA6Ly90b3BpYy5jc2RuLm5l +dC91LzIwMTAxMjEyLzEyLzJBMzA0M0M0LUQ0MDctNDc0OC05NUMzLUE1RDA5M0MyODEzRS5odG1s +IiANCiAgdGFyZ2V0PV9ibGFuaz5bI3c2VEN1c0tSdzZmQ3ZNS1d3NmZDb01LQiNd5LqR57yW56CB +PC9BPjwvRFQ+DQogIDxEVCBjbGFzcz10b3A4IA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4 +OyBCQUNLR1JPVU5ELVBPU0lUSU9OOiAwcHggM3B4OyBPVkVSRkxPVy1ZOiBoaWRkZW47IFBBRERJ +TkctTEVGVDogMjRweDsgQkFDS0dST1VORC1JTUFHRTogdXJsKGh0dHA6Ly9jc2RuaW1nLmNuL3d3 +dy9pbWFnZXMvY3NkbmluZGV4X3BpYzQyLmdpZik7IE9WRVJGTE9XLVg6IGhpZGRlbjsgUEFERElO +Ry1CT1RUT006IDFweDsgTUFSR0lOOiAwcHg7IFdJRFRIOiAyMTBweDsgUEFERElORy1UT1A6IDRw +eDsgV0hJVEUtU1BBQ0U6IG5vd3JhcDsgYmFja2dyb3VuZC1vcmlnaW46IGluaXRpYWw7IGJhY2tn +cm91bmQtY2xpcDogaW5pdGlhbCI+PEEgDQogIHRpdGxlPVNEMi4w5aSn5Lya6ZqG6YeN5byA5bmV +LOekvuWMuueOsOWcuuWbvuaWh+ebtOaSrSBzdHlsZT0iQ09MT1I6IHJnYigwLDAsMCk7IFRFWFQt +REVDT1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9TG9nQ2xpY2tDb3VudCh0aGlzLDg5KTsgDQog +IGhyZWY9Imh0dHA6Ly90b3BpYy5jc2RuLm5ldC91LzIwMTAxMjA5LzA5L0QwODAxRjZBLTczRjQt +NDI2RC04OEZCLThENzJCOTNCNTQ5OS5odG1sIiANCiAgdGFyZ2V0PV9ibGFuaz5TRDIuMOWkp+S8 +mumahumHjeW8gOW5lSznpL7ljLrnjrDlnLrlm77mlofnm7Tmkq08L0E+PC9EVD4NCiAgPERUIGNs +YXNzPXRvcDkgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJ +T046IDBweCAzcHg7IE9WRVJGTE9XLVk6IGhpZGRlbjsgUEFERElORy1MRUZUOiAyNHB4OyBCQUNL +R1JPVU5ELUlNQUdFOiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhf +cGljNDMuZ2lmKTsgT1ZFUkZMT1ctWDogaGlkZGVuOyBQQURESU5HLUJPVFRPTTogMXB4OyBNQVJH +SU46IDBweDsgV0lEVEg6IDIxMHB4OyBQQURESU5HLVRPUDogNHB4OyBXSElURS1TUEFDRTogbm93 +cmFwOyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFs +Ij48QSANCiAgdGl0bGU95aSn5a626L2s5q2j55qE5bel6LWE5pyJ5rKh5pyJ5a6e5Lmg55qE5pe2 +5YCZ5aSa77yfIHN0eWxlPSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25l +IiANCiAgb25jbGljaz1Mb2dDbGlja0NvdW50KHRoaXMsODkpOyANCiAgaHJlZj0iaHR0cDovL3Rv +cGljLmNzZG4ubmV0L3UvMjAxMDEyMDgvMTEvQzZGRkU3QkQtM0FBOS00OUNGLUIwQTEtNjU3NTIw +QjFFMjRBLmh0bWwiIA0KICB0YXJnZXQ9X2JsYW5rPuWkp+Wutui9rOato+eahOW3pei1hOacieay +oeacieWunuS5oOeahOaXtuWAmeWkmu+8nzwvQT48L0RUPg0KICA8RFQgY2xhc3M9dG9wMTAgDQog +IHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IEJBQ0tHUk9VTkQtUE9TSVRJT046IDBweCAzcHg7 +IE9WRVJGTE9XLVk6IGhpZGRlbjsgUEFERElORy1MRUZUOiAyNHB4OyBCQUNLR1JPVU5ELUlNQUdF +OiB1cmwoaHR0cDovL2NzZG5pbWcuY24vd3d3L2ltYWdlcy9jc2RuaW5kZXhfcGljNDQuZ2lmKTsg +T1ZFUkZMT1ctWDogaGlkZGVuOyBQQURESU5HLUJPVFRPTTogMXB4OyBNQVJHSU46IDBweDsgV0lE +VEg6IDIxMHB4OyBQQURESU5HLVRPUDogNHB4OyBXSElURS1TUEFDRTogbm93cmFwOyBiYWNrZ3Jv +dW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBpbml0aWFsIj48QSANCiAgdGl0 +bGU95YWl6KGM5LiA5bm05aSa5LuO5rKh5oSf5Y+X5Yiw6L2v5Lu25byA5Y+R5Zac5oKmIHN0eWxl +PSJDT0xPUjogcmdiKDAsMCwwKTsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgb25jbGljaz1M +b2dDbGlja0NvdW50KHRoaXMsODkpOyANCiAgaHJlZj0iaHR0cDovL3RvcGljLmNzZG4ubmV0L3Uv +MjAxMDEyMDQvMTgvQ0QxQUZFQkUtRDEyQy00N0NELUIxREYtREE4RUNCNTE1N0Q3Lmh0bWwiIA0K +ICB0YXJnZXQ9X2JsYW5rPuWFpeihjOS4gOW5tOWkmuS7juayoeaEn+WPl+WIsOi9r+S7tuW8gOWP +keWWnOaCpjwvQT48L0RUPjwvREw+PC9ESVY+PC9ESVY+PC9ESVY+DQo8RElWIGNsYXNzPXBhZ2Vj +b25fbGF5ZXIyYnRtIA0Kc3R5bGU9IkJBQ0tHUk9VTkQtUE9TSVRJT046IDUwJSAxMDAlOyBGT05U +LVNJWkU6IDFweDsgRkxPQVQ6IGxlZnQ7IEJBQ0tHUk9VTkQtSU1BR0U6IHVybChodHRwOi8vY3Nk +bmltZy5jbi93d3cvaW1hZ2VzL2NzZG5pbmRleF9waWM0NS5naWYpOyBXSURUSDogOTYwcHg7IEhF +SUdIVDogMXB4OyBiYWNrZ3JvdW5kLW9yaWdpbjogaW5pdGlhbDsgYmFja2dyb3VuZC1jbGlwOiBp +bml0aWFsIj48L0RJVj4NCjxESVYgY2xhc3M9ZnJpZW5kbGluayANCnN0eWxlPSJCT1JERVItUklH +SFQ6IHJnYigyMDQsMjA0LDIwNCkgMXB4IHNvbGlkOyBQQURESU5HLVJJR0hUOiA2cHg7IEJPUkRF +Ui1UT1A6IHJnYigyMDQsMjA0LDIwNCkgMXB4IHNvbGlkOyBQQURESU5HLUxFRlQ6IDZweDsgRkxP +QVQ6IGxlZnQ7IFBBRERJTkctQk9UVE9NOiAzcHg7IE1BUkdJTjogM3B4IDBweCAwcHg7IEJPUkRF +Ui1MRUZUOiByZ2IoMjA0LDIwNCwyMDQpIDFweCBzb2xpZDsgV0lEVEg6IDk0NnB4OyBQQURESU5H +LVRPUDogM3B4OyBCT1JERVItQk9UVE9NOiByZ2IoMjA0LDIwNCwyMDQpIDFweCBzb2xpZCI+DQo8 +UCANCnN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IFBBRERJTkctTEVGVDogMHB4OyBQQURESU5H +LUJPVFRPTTogMHB4OyBNQVJHSU46IDBweDsgQ09MT1I6IHJnYigxMDIsMTAyLDEwMik7IFBBRERJ +TkctVE9QOiAwcHgiPjxTUEFOIA0Kc3R5bGU9IkZPTlQtV0VJR0hUOiBib2xkOyBNQVJHSU46IDBw +eCA2cHggMHB4IDBweDsgQ09MT1I6IHJnYigwLDAsMCkiPuWQiOS9nOS8meS8tDwvU1BBTj48QSAN +CnN0eWxlPSJQQURESU5HLVJJR0hUOiAzcHg7IFBBRERJTkctTEVGVDogM3B4OyBQQURESU5HLUJP +VFRPTTogMHB4OyBDT0xPUjogcmdiKDEwMiwxMDIsMTAyKTsgUEFERElORy1UT1A6IDBweDsgVEVY +VC1ERUNPUkFUSU9OOiBub25lIiANCmhyZWY9Imh0dHA6Ly90ZWNoLnNpbmEuY29tLmNuLyIgdGFy +Z2V0PWJsYW5rPuaWsOa1quenkeaKgDwvQT7igJQ8U1BBTiANCmNsYXNzPUFwcGxlLWNvbnZlcnRl +ZC1zcGFjZT4mbmJzcDs8L1NQQU4+PEEgDQpzdHlsZT0iUEFERElORy1SSUdIVDogM3B4OyBQQURE +SU5HLUxFRlQ6IDNweDsgUEFERElORy1CT1RUT006IDBweDsgQ09MT1I6IHJnYigxMDIsMTAyLDEw +Mik7IFBBRERJTkctVE9QOiAwcHg7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQpocmVmPSJodHRw +Oi8vaXQuc29odS5jb20vIiB0YXJnZXQ9Ymxhbms+5pCc54uQSVQ8L0E+4oCUPFNQQU4gDQpjbGFz +cz1BcHBsZS1jb252ZXJ0ZWQtc3BhY2U+Jm5ic3A7PC9TUEFOPjxBIA0Kc3R5bGU9IlBBRERJTkct +UklHSFQ6IDNweDsgUEFERElORy1MRUZUOiAzcHg7IFBBRERJTkctQk9UVE9NOiAwcHg7IENPTE9S +OiByZ2IoMTAyLDEwMiwxMDIpOyBQQURESU5HLVRPUDogMHB4OyBURVhULURFQ09SQVRJT046IG5v +bmUiIA0KaHJlZj0iaHR0cDovL3d3dy5kb25ld3MuY29tLyIgdGFyZ2V0PWJsYW5rPkRvTmV3czwv +QT7igJQ8U1BBTiANCmNsYXNzPUFwcGxlLWNvbnZlcnRlZC1zcGFjZT4mbmJzcDs8L1NQQU4+PEEg +DQpzdHlsZT0iUEFERElORy1SSUdIVDogM3B4OyBQQURESU5HLUxFRlQ6IDNweDsgUEFERElORy1C +T1RUT006IDBweDsgQ09MT1I6IHJnYigxMDIsMTAyLDEwMik7IFBBRERJTkctVE9QOiAwcHg7IFRF +WFQtREVDT1JBVElPTjogbm9uZSIgDQpocmVmPSJodHRwOi8vd3d3LnpkbmV0LmNvbS5jbi8iIHRh +cmdldD1ibGFuaz5aRE5ldOiHs+mhtue9kTwvQT7igJQ8U1BBTiANCmNsYXNzPUFwcGxlLWNvbnZl +cnRlZC1zcGFjZT4mbmJzcDs8L1NQQU4+PEEgDQpzdHlsZT0iUEFERElORy1SSUdIVDogM3B4OyBQ +QURESU5HLUxFRlQ6IDNweDsgUEFERElORy1CT1RUT006IDBweDsgQ09MT1I6IHJnYigxMDIsMTAy +LDEwMik7IFBBRERJTkctVE9QOiAwcHg7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQpocmVmPSJo +dHRwOi8vd3d3LnRoZXRoaXJkbWVkaWEuY29tLyIgdGFyZ2V0PWJsYW5rPuesrOS4ieWqkuS9kzwv +QT7igJQ8U1BBTiANCmNsYXNzPUFwcGxlLWNvbnZlcnRlZC1zcGFjZT4mbmJzcDs8L1NQQU4+PEEg +DQpzdHlsZT0iUEFERElORy1SSUdIVDogM3B4OyBQQURESU5HLUxFRlQ6IDNweDsgUEFERElORy1C +T1RUT006IDBweDsgQ09MT1I6IHJnYigxMDIsMTAyLDEwMik7IFBBRERJTkctVE9QOiAwcHg7IFRF +WFQtREVDT1JBVElPTjogbm9uZSIgDQpocmVmPSJodHRwOi8vd3d3Lnllc2t5LmNvbS8iIHRhcmdl +dD1ibGFuaz7lpKnmnoHnvZE8L0E+4oCUPFNQQU4gDQpjbGFzcz1BcHBsZS1jb252ZXJ0ZWQtc3Bh +Y2U+Jm5ic3A7PC9TUEFOPjxBIA0Kc3R5bGU9IlBBRERJTkctUklHSFQ6IDNweDsgUEFERElORy1M +RUZUOiAzcHg7IFBBRERJTkctQk9UVE9NOiAwcHg7IENPTE9SOiByZ2IoMTAyLDEwMiwxMDIpOyBQ +QURESU5HLVRPUDogMHB4OyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KaHJlZj0iaHR0cDovL3d3 +dy5jY3cuY29tLmNuLyIgdGFyZ2V0PWJsYW5rPuiuoeS4lue9kTwvQT7igJQ8U1BBTiANCmNsYXNz +PUFwcGxlLWNvbnZlcnRlZC1zcGFjZT4mbmJzcDs8L1NQQU4+PEEgDQpzdHlsZT0iUEFERElORy1S +SUdIVDogM3B4OyBQQURESU5HLUxFRlQ6IDNweDsgUEFERElORy1CT1RUT006IDBweDsgQ09MT1I6 +IHJnYigxMDIsMTAyLDEwMik7IFBBRERJTkctVE9QOiAwcHg7IFRFWFQtREVDT1JBVElPTjogbm9u +ZSIgDQpocmVmPSJodHRwOi8vd3d3Lmltb2JpbGUuY29tLmNuLyI+5omL5py65LmL5a62PC9BPuKA +lDxTUEFOIA0KY2xhc3M9QXBwbGUtY29udmVydGVkLXNwYWNlPiZuYnNwOzwvU1BBTj48QSANCnN0 +eWxlPSJQQURESU5HLVJJR0hUOiAzcHg7IFBBRERJTkctTEVGVDogM3B4OyBQQURESU5HLUJPVFRP +TTogMHB4OyBDT0xPUjogcmdiKDEwMiwxMDIsMTAyKTsgUEFERElORy1UT1A6IDBweDsgVEVYVC1E +RUNPUkFUSU9OOiBub25lIiANCmhyZWY9Imh0dHA6Ly93d3cuNTFzaGlsaW5nLmNvbS8iIHRhcmdl +dD1ibGFuaz41MeinhumTgzwvQT7igJQ8U1BBTiANCmNsYXNzPUFwcGxlLWNvbnZlcnRlZC1zcGFj +ZT4mbmJzcDs8L1NQQU4+PEEgDQpzdHlsZT0iUEFERElORy1SSUdIVDogM3B4OyBQQURESU5HLUxF +RlQ6IDNweDsgUEFERElORy1CT1RUT006IDBweDsgQ09MT1I6IHJnYigxMDIsMTAyLDEwMik7IFBB +RERJTkctVE9QOiAwcHg7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQpocmVmPSJodHRwOi8vd3d3 +Lm9rd2FuLmNvbS8iIHRhcmdldD1ibGFuaz7njqnnvZHkvZPogrI8L0E+PFNQQU4gDQpjbGFzcz1B +cHBsZS1jb252ZXJ0ZWQtc3BhY2U+Jm5ic3A7PC9TUEFOPuKAlDxBIA0Kc3R5bGU9IlBBRERJTkct +UklHSFQ6IDNweDsgUEFERElORy1MRUZUOiAzcHg7IFBBRERJTkctQk9UVE9NOiAwcHg7IENPTE9S +OiByZ2IoMTAyLDEwMiwxMDIpOyBQQURESU5HLVRPUDogMHB4OyBURVhULURFQ09SQVRJT046IG5v +bmUiIA0KaHJlZj0iaHR0cDovL3d3dy41MWRpdHUuY29tLyIgdGFyZ2V0PWJsYW5rPuaIkeimgeWc +sOWbvjwvQT48U1BBTiANCmNsYXNzPUFwcGxlLWNvbnZlcnRlZC1zcGFjZT4mbmJzcDs8L1NQQU4+ +4oCUPEEgDQpzdHlsZT0iUEFERElORy1SSUdIVDogM3B4OyBQQURESU5HLUxFRlQ6IDNweDsgUEFE +RElORy1CT1RUT006IDBweDsgQ09MT1I6IHJnYigxMDIsMTAyLDEwMik7IFBBRERJTkctVE9QOiAw +cHg7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQpocmVmPSJodHRwOi8vd3d3LmpvaG5icnljZS5j +b20uY24vIiB0YXJnZXQ9Ymxhbms+Sm9obiBCcnljZTwvQT48L1A+DQo8UCANCnN0eWxlPSJQQURE +SU5HLVJJR0hUOiAwcHg7IFBBRERJTkctTEVGVDogMHB4OyBQQURESU5HLUJPVFRPTTogMHB4OyBN +QVJHSU46IDBweDsgQ09MT1I6IHJnYigxMDIsMTAyLDEwMik7IFBBRERJTkctVE9QOiAwcHgiPjxB +IA0Kc3R5bGU9IlBBRERJTkctUklHSFQ6IDNweDsgUEFERElORy1MRUZUOiAzcHg7IFBBRERJTkct +Qk9UVE9NOiAwcHg7IENPTE9SOiByZ2IoMTAyLDEwMiwxMDIpOyBQQURESU5HLVRPUDogMHB4OyBU +RVhULURFQ09SQVRJT046IG5vbmUiIA0KaHJlZj0iaHR0cDovL3d3dy5sb25ndHVvLmNvbS8iIHRh +cmdldD1ibGFuaz7pvpnmi5PkupLliqg8L0E+4oCUPFNQQU4gDQpjbGFzcz1BcHBsZS1jb252ZXJ0 +ZWQtc3BhY2U+Jm5ic3A7PC9TUEFOPjxBIA0Kc3R5bGU9IlBBRERJTkctUklHSFQ6IDNweDsgUEFE +RElORy1MRUZUOiAzcHg7IFBBRERJTkctQk9UVE9NOiAwcHg7IENPTE9SOiByZ2IoMTAyLDEwMiwx +MDIpOyBQQURESU5HLVRPUDogMHB4OyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KaHJlZj0iaHR0 +cDovL3d3dy51dXR1dS5jb20vIiB0YXJnZXQ9Ymxhbms+5LiH6Iqx562S5peF5ri4PC9BPuKAlDxT +UEFOIA0KY2xhc3M9QXBwbGUtY29udmVydGVkLXNwYWNlPiZuYnNwOzwvU1BBTj48QSANCnN0eWxl +PSJQQURESU5HLVJJR0hUOiAzcHg7IFBBRERJTkctTEVGVDogM3B4OyBQQURESU5HLUJPVFRPTTog +MHB4OyBDT0xPUjogcmdiKDEwMiwxMDIsMTAyKTsgUEFERElORy1UT1A6IDBweDsgVEVYVC1ERUNP +UkFUSU9OOiBub25lIiANCmhyZWY9Imh0dHA6Ly93d3cuZm9ydW0ubm9raWEuY29tLmNuLyIgdGFy +Z2V0PWJsYW5rPuivuuWfuuS6muiuuuWdmzwvQT7igJQ8U1BBTiANCmNsYXNzPUFwcGxlLWNvbnZl +cnRlZC1zcGFjZT4mbmJzcDs8L1NQQU4+PEEgDQpzdHlsZT0iUEFERElORy1SSUdIVDogM3B4OyBQ +QURESU5HLUxFRlQ6IDNweDsgUEFERElORy1CT1RUT006IDBweDsgQ09MT1I6IHJnYigxMDIsMTAy +LDEwMik7IFBBRERJTkctVE9QOiAwcHg7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQpocmVmPSJo +dHRwOi8vd3d3LmVld29ybGQuY29tLmNuLyIgdGFyZ2V0PWJsYW5rPueUteWtkOW3peeoizwvQT7i +gJQ8U1BBTiANCmNsYXNzPUFwcGxlLWNvbnZlcnRlZC1zcGFjZT4mbmJzcDs8L1NQQU4+PEEgDQpz +dHlsZT0iUEFERElORy1SSUdIVDogM3B4OyBQQURESU5HLUxFRlQ6IDNweDsgUEFERElORy1CT1RU +T006IDBweDsgQ09MT1I6IHJnYigxMDIsMTAyLDEwMik7IFBBRERJTkctVE9QOiAwcHg7IFRFWFQt +REVDT1JBVElPTjogbm9uZSIgDQpocmVmPSJodHRwOi8vd3d3Lm9wZW4ybS5jb20vIiB0YXJnZXQ9 +Ymxhbms+5byA5rqQ5LiT5a62572RPC9BPuKAlDxTUEFOIA0KY2xhc3M9QXBwbGUtY29udmVydGVk +LXNwYWNlPiZuYnNwOzwvU1BBTj48QSANCnN0eWxlPSJQQURESU5HLVJJR0hUOiAzcHg7IFBBRERJ +TkctTEVGVDogM3B4OyBQQURESU5HLUJPVFRPTTogMHB4OyBDT0xPUjogcmdiKDEwMiwxMDIsMTAy +KTsgUEFERElORy1UT1A6IDBweDsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCmhyZWY9Imh0dHA6 +Ly93d3cuY2hpbmF2aXN1YWwuY29tLyIgdGFyZ2V0PWJsYW5rPuinhuinieS4reWbvTwvQT7igJQ8 +U1BBTiANCmNsYXNzPUFwcGxlLWNvbnZlcnRlZC1zcGFjZT4mbmJzcDs8L1NQQU4+PEEgDQpzdHls +ZT0iUEFERElORy1SSUdIVDogM3B4OyBQQURESU5HLUxFRlQ6IDNweDsgUEFERElORy1CT1RUT006 +IDBweDsgQ09MT1I6IHJnYigxMDIsMTAyLDEwMik7IFBBRERJTkctVE9QOiAwcHg7IFRFWFQtREVD +T1JBVElPTjogbm9uZSIgDQpocmVmPSJodHRwOi8vd3d3Lmp1a3V1LmNvbS8iIHRhcmdldD1ibGFu +az7lj6Xphbfkvovlj6U8L0E+4oCUPFNQQU4gDQpjbGFzcz1BcHBsZS1jb252ZXJ0ZWQtc3BhY2U+ +Jm5ic3A7PC9TUEFOPjxBIA0Kc3R5bGU9IlBBRERJTkctUklHSFQ6IDNweDsgUEFERElORy1MRUZU +OiAzcHg7IFBBRERJTkctQk9UVE9NOiAwcHg7IENPTE9SOiByZ2IoMTAyLDEwMiwxMDIpOyBQQURE +SU5HLVRPUDogMHB4OyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KaHJlZj0iaHR0cDovL3d3dy5o +dWRvbmcuY29tLyIgdGFyZ2V0PWJsYW5rPuS6kuWKqOeZvuenkTwvQT7igJQ8U1BBTiANCmNsYXNz +PUFwcGxlLWNvbnZlcnRlZC1zcGFjZT4mbmJzcDs8L1NQQU4+PEEgDQpzdHlsZT0iUEFERElORy1S +SUdIVDogM3B4OyBQQURESU5HLUxFRlQ6IDNweDsgUEFERElORy1CT1RUT006IDBweDsgQ09MT1I6 +IHJnYigxMDIsMTAyLDEwMik7IFBBRERJTkctVE9QOiAwcHg7IFRFWFQtREVDT1JBVElPTjogbm9u +ZSIgDQpocmVmPSJodHRwOi8vd3d3LmRvaXQuY29tLmNuLyIgdGFyZ2V0PWJsYW5rPkRPSVQ8L0E+ +4oCUPFNQQU4gDQpjbGFzcz1BcHBsZS1jb252ZXJ0ZWQtc3BhY2U+Jm5ic3A7PC9TUEFOPjxBIA0K +c3R5bGU9IlBBRERJTkctUklHSFQ6IDNweDsgUEFERElORy1MRUZUOiAzcHg7IFBBRERJTkctQk9U +VE9NOiAwcHg7IENPTE9SOiByZ2IoMTAyLDEwMiwxMDIpOyBQQURESU5HLVRPUDogMHB4OyBURVhU +LURFQ09SQVRJT046IG5vbmUiIA0KaHJlZj0iaHR0cDovL3d3dy5lZWRhdGFzaGVldC5jb20vIiB0 +YXJnZXQ9Ymxhbms+RGF0YXNoZWV0PC9BPuKAlDxTUEFOIA0KY2xhc3M9QXBwbGUtY29udmVydGVk +LXNwYWNlPiZuYnNwOzwvU1BBTj48QSANCnN0eWxlPSJQQURESU5HLVJJR0hUOiAzcHg7IFBBRERJ +TkctTEVGVDogM3B4OyBQQURESU5HLUJPVFRPTTogMHB4OyBDT0xPUjogcmdiKDEwMiwxMDIsMTAy +KTsgUEFERElORy1UT1A6IDBweDsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCmhyZWY9Imh0dHA6 +Ly93d3cuZG9jaW4uY29tLyIgdGFyZ2V0PWJsYW5rPuixhuS4gee9kTwvQT7igJQ8U1BBTiANCmNs +YXNzPUFwcGxlLWNvbnZlcnRlZC1zcGFjZT4mbmJzcDs8L1NQQU4+PEEgDQpzdHlsZT0iUEFERElO +Ry1SSUdIVDogM3B4OyBQQURESU5HLUxFRlQ6IDNweDsgUEFERElORy1CT1RUT006IDBweDsgQ09M +T1I6IHJnYigxMDIsMTAyLDEwMik7IFBBRERJTkctVE9QOiAwcHg7IFRFWFQtREVDT1JBVElPTjog +bm9uZSIgDQpocmVmPSJodHRwOi8vd3d3Lmhhb2RmLmNvbS8iIHRhcmdldD1ibGFuaz7lpb3lpKfl +pKvlnKjnur88L0E+PC9QPjwvRElWPg0KPERJViBjbGFzcz1wdWJfZm9vdGVyIA0Kc3R5bGU9IlBB +RERJTkctUklHSFQ6IDBweDsgQk9SREVSLVRPUDogcmdiKDIwNCwyMDQsMjA0KSAxcHggc29saWQ7 +IFBBRERJTkctTEVGVDogMHB4OyBGTE9BVDogbGVmdDsgUEFERElORy1CT1RUT006IDNweDsgTUFS +R0lOOiA1cHggMHB4IDBweDsgV0lEVEg6IDk2MHB4OyBQQURESU5HLVRPUDogM3B4Ij4NCjxETCAN +CnN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IE9WRVJGTE9XLVk6IGhpZGRlbjsgUEFERElORy1M +RUZUOiAwcHg7IE9WRVJGTE9XLVg6IGhpZGRlbjsgUEFERElORy1CT1RUT006IDNweDsgTUFSR0lO +OiAwcHg7IFBBRERJTkctVE9QOiAzcHgiPg0KICA8REQgY2xhc3M9YmFja2JsdWUgDQogIHN0eWxl +PSJQQURESU5HLVJJR0hUOiAwcHg7IFBBRERJTkctTEVGVDogMHB4OyBQQURESU5HLUJPVFRPTTog +NXB4OyBNQVJHSU46IDBweDsgQ09MT1I6IHJnYigyNTUsMjU1LDI1NSk7IFBBRERJTkctVE9QOiA1 +cHg7IEJBQ0tHUk9VTkQtQ09MT1I6IHJnYigxNTAsMTk1LDIzNCk7IGJhY2tncm91bmQtb3JpZ2lu +OiBpbml0aWFsOyBiYWNrZ3JvdW5kLWNsaXA6IGluaXRpYWwiPjxBIA0KICBzdHlsZT0iUEFERElO +Ry1SSUdIVDogNXB4OyBQQURESU5HLUxFRlQ6IDVweDsgRk9OVC1XRUlHSFQ6IGJvbGQ7IFBBRERJ +TkctQk9UVE9NOiAwcHg7IENPTE9SOiByZ2IoMjU1LDI1NSwyNTUpOyBQQURESU5HLVRPUDogMHB4 +OyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBocmVmPSJodHRwOi8vd3d3LmNzZG4ubmV0L2Nv +bXBhbnkvYWJvdXQuaHRtbCIgdGFyZ2V0PV9ibGFuaz7lhazlj7jnroDku4s8L0E+fDxBIA0KICBz +dHlsZT0iUEFERElORy1SSUdIVDogNXB4OyBQQURESU5HLUxFRlQ6IDVweDsgRk9OVC1XRUlHSFQ6 +IGJvbGQ7IFBBRERJTkctQk9UVE9NOiAwcHg7IENPTE9SOiByZ2IoMjU1LDI1NSwyNTUpOyBQQURE +SU5HLVRPUDogMHB4OyBURVhULURFQ09SQVRJT046IG5vbmUiIA0KICBocmVmPSJodHRwOi8vd3d3 +LmNzZG4ubmV0L2NvbXBhbnkvcmVjcnVpdC5odG1sIiB0YXJnZXQ9X2JsYW5rPuaLm+i0pOe6s+Wj +qzwvQT58PEEgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiA1cHg7IFBBRERJTkctTEVGVDogNXB4 +OyBGT05ULVdFSUdIVDogYm9sZDsgUEFERElORy1CT1RUT006IDBweDsgQ09MT1I6IHJnYigyNTUs +MjU1LDI1NSk7IFBBRERJTkctVE9QOiAwcHg7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIGhy +ZWY9Imh0dHA6Ly93d3cuY3Nkbi5uZXQvY29tcGFueS9tYXJrZXRpbmcuaHRtbCIgdGFyZ2V0PV9i +bGFuaz7lub/lkYrmnI3liqE8L0E+fDxBIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogNXB4OyBQ +QURESU5HLUxFRlQ6IDVweDsgRk9OVC1XRUlHSFQ6IGJvbGQ7IFBBRERJTkctQk9UVE9NOiAwcHg7 +IENPTE9SOiByZ2IoMjU1LDI1NSwyNTUpOyBQQURESU5HLVRPUDogMHB4OyBURVhULURFQ09SQVRJ +T046IG5vbmUiIA0KICBocmVmPSJodHRwOi8vd3d3LmNzZG4ubmV0L2NvbXBhbnkvYWNjb3VudC5o +dG1sIiB0YXJnZXQ9X2JsYW5rPumTtuihjOaxh+asvuW4kOWPtzwvQT58PEEgDQogIHN0eWxlPSJQ +QURESU5HLVJJR0hUOiA1cHg7IFBBRERJTkctTEVGVDogNXB4OyBGT05ULVdFSUdIVDogYm9sZDsg +UEFERElORy1CT1RUT006IDBweDsgQ09MT1I6IHJnYigyNTUsMjU1LDI1NSk7IFBBRERJTkctVE9Q +OiAwcHg7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIGhyZWY9Imh0dHA6Ly93d3cuY3Nkbi5u +ZXQvY29tcGFueS9jb250YWN0Lmh0bWwiIHRhcmdldD1fYmxhbms+6IGU57O75pa55byPPC9BPnw8 +QSANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDVweDsgUEFERElORy1MRUZUOiA1cHg7IEZPTlQt +V0VJR0hUOiBib2xkOyBQQURESU5HLUJPVFRPTTogMHB4OyBDT0xPUjogcmdiKDI1NSwyNTUsMjU1 +KTsgUEFERElORy1UT1A6IDBweDsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAgaHJlZj0iaHR0 +cDovL3d3dy5jc2RuLm5ldC9jb21wYW55L3N0YXRlbWVudC5odG1sIiB0YXJnZXQ9X2JsYW5rPueJ +iOadg+WjsOaYjjwvQT58PEEgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiA1cHg7IFBBRERJTkct +TEVGVDogNXB4OyBGT05ULVdFSUdIVDogYm9sZDsgUEFERElORy1CT1RUT006IDBweDsgQ09MT1I6 +IHJnYigyNTUsMjU1LDI1NSk7IFBBRERJTkctVE9QOiAwcHg7IFRFWFQtREVDT1JBVElPTjogbm9u +ZSIgDQogIGhyZWY9Imh0dHA6Ly93d3cuY3Nkbi5uZXQvY29tcGFueS9sYXllci5odG1sIiB0YXJn +ZXQ9X2JsYW5rPuazleW+i+mhvumXrjwvQT58PEEgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiA1 +cHg7IFBBRERJTkctTEVGVDogNXB4OyBGT05ULVdFSUdIVDogYm9sZDsgUEFERElORy1CT1RUT006 +IDBweDsgQ09MT1I6IHJnYigyNTUsMjU1LDI1NSk7IFBBRERJTkctVE9QOiAwcHg7IFRFWFQtREVD +T1JBVElPTjogbm9uZSIgDQogIG9uY2xpY2s9IndpbmRvdy5sb2NhdGlvbi5ocmVmPSdtYWknKyds +dG86Jysnd2VibWEnKydzdGVyQGMnKydzZG4ubicrJ2V0P3N1YmplY3Q9UmVwb3J0IFRvIENTRE4n +O3JldHVybiBmYWxzZSIgDQogIGhyZWY9Imh0dHA6Ly93d3cuY3Nkbi5uZXQvIyI+6Zeu6aKY5oql +5ZGKPC9BPjwvREQ+DQogIDxEVCANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgUEFERElO +Ry1MRUZUOiAwcHg7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBQQURESU5HLVRP +UDogNXB4OyBURVhULUFMSUdOOiBjZW50ZXIiPjxBIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDog +MHB4OyBESVNQTEFZOiBpbmxpbmU7IFBBRERJTkctTEVGVDogMHB4OyBQQURESU5HLUJPVFRPTTog +MHB4OyBNQVJHSU46IDVweDsgQ09MT1I6IHJnYigwLDAsMCk7IFBBRERJTkctVE9QOiAwcHg7IFRF +WFQtREVDT1JBVElPTjogbm9uZSIgDQogIGhyZWY9Imh0dHA6Ly93d3cuaXRydXN0Lm9yZy5jbi8i +IHRhcmdldD1fYmxhbms+PElNRyB0aXRsZT0iIiANCiAgc3R5bGU9IkJPUkRFUi1SSUdIVDogcmdi +KDIwNCwyMDQsMjA0KSAxcHggc29saWQ7IEJPUkRFUi1UT1A6IHJnYigyMDQsMjA0LDIwNCkgMXB4 +IHNvbGlkOyBCT1JERVItTEVGVDogcmdiKDIwNCwyMDQsMjA0KSAxcHggc29saWQ7IFdJRFRIOiAx +MTVweDsgQk9SREVSLUJPVFRPTTogcmdiKDIwNCwyMDQsMjA0KSAxcHggc29saWQ7IEhFSUdIVDog +NDVweCIgDQogIGFsdD0iIiBzcmM9Imh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvbGlua19s +b2dvMDEuZ2lmIj48L0E+PFNQQU4gDQogIGNsYXNzPUFwcGxlLWNvbnZlcnRlZC1zcGFjZT4mbmJz +cDs8L1NQQU4+PEEgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IERJU1BMQVk6IGlubGlu +ZTsgUEFERElORy1MRUZUOiAwcHg7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogNXB4OyBD +T0xPUjogcmdiKDAsMCwwKTsgUEFERElORy1UT1A6IDBweDsgVEVYVC1ERUNPUkFUSU9OOiBub25l +IiANCiAgaHJlZj0iaHR0cDovL3d3dy5oZDMxNS5nb3YuY24vYmVpYW4vdmlldy5hc3A/Ymlhbmhh +bz0wMTAyMDIwMDEwMzIxMDAwMTAiIA0KICB0YXJnZXQ9X2JsYW5rPjxJTUcgdGl0bGU9IiIgDQog +IHN0eWxlPSJCT1JERVItUklHSFQ6IHJnYigyMDQsMjA0LDIwNCkgMXB4IHNvbGlkOyBCT1JERVIt +VE9QOiByZ2IoMjA0LDIwNCwyMDQpIDFweCBzb2xpZDsgQk9SREVSLUxFRlQ6IHJnYigyMDQsMjA0 +LDIwNCkgMXB4IHNvbGlkOyBXSURUSDogMTE1cHg7IEJPUkRFUi1CT1RUT006IHJnYigyMDQsMjA0 +LDIwNCkgMXB4IHNvbGlkOyBIRUlHSFQ6IDQ1cHgiIA0KICBhbHQ9IiIgc3JjPSJodHRwOi8vY3Nk +bmltZy5jbi93d3cvaW1hZ2VzL2xpbmtfbG9nbzAyLmdpZiI+PC9BPjxTUEFOIA0KICBjbGFzcz1B +cHBsZS1jb252ZXJ0ZWQtc3BhY2U+Jm5ic3A7PC9TUEFOPjxBIA0KICBzdHlsZT0iUEFERElORy1S +SUdIVDogMHB4OyBESVNQTEFZOiBpbmxpbmU7IFBBRERJTkctTEVGVDogMHB4OyBQQURESU5HLUJP +VFRPTTogMHB4OyBNQVJHSU46IDVweDsgQ09MT1I6IHJnYigwLDAsMCk7IFBBRERJTkctVE9QOiAw +cHg7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIGhyZWY9Imh0dHA6Ly9uZXQuY2hpbmEuY29t +LmNuL2luZGV4Lmh0bSIgdGFyZ2V0PV9ibGFuaz48SU1HIHRpdGxlPSIiIA0KICBzdHlsZT0iQk9S +REVSLVJJR0hUOiByZ2IoMjA0LDIwNCwyMDQpIDFweCBzb2xpZDsgQk9SREVSLVRPUDogcmdiKDIw +NCwyMDQsMjA0KSAxcHggc29saWQ7IEJPUkRFUi1MRUZUOiByZ2IoMjA0LDIwNCwyMDQpIDFweCBz +b2xpZDsgV0lEVEg6IDExNXB4OyBCT1JERVItQk9UVE9NOiByZ2IoMjA0LDIwNCwyMDQpIDFweCBz +b2xpZDsgSEVJR0hUOiA0NXB4IiANCiAgYWx0PSIiIHNyYz0iaHR0cDovL2NzZG5pbWcuY24vd3d3 +L2ltYWdlcy9saW5rX2xvZ28wMy5naWYiPjwvQT48U1BBTiANCiAgY2xhc3M9QXBwbGUtY29udmVy +dGVkLXNwYWNlPiZuYnNwOzwvU1BBTj48QSANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsg +RElTUExBWTogaW5saW5lOyBQQURESU5HLUxFRlQ6IDBweDsgUEFERElORy1CT1RUT006IDBweDsg +TUFSR0lOOiA1cHg7IENPTE9SOiByZ2IoMCwwLDApOyBQQURESU5HLVRPUDogMHB4OyBURVhULURF +Q09SQVRJT046IG5vbmUiIA0KICBocmVmPSJodHRwOi8vd3d3Lm5ldGJqLm9yZy5jbi8iIHRhcmdl +dD1fYmxhbms+PElNRyB0aXRsZT0iIiANCiAgc3R5bGU9IkJPUkRFUi1SSUdIVDogcmdiKDIwNCwy +MDQsMjA0KSAxcHggc29saWQ7IEJPUkRFUi1UT1A6IHJnYigyMDQsMjA0LDIwNCkgMXB4IHNvbGlk +OyBCT1JERVItTEVGVDogcmdiKDIwNCwyMDQsMjA0KSAxcHggc29saWQ7IFdJRFRIOiAxMTVweDsg +Qk9SREVSLUJPVFRPTTogcmdiKDIwNCwyMDQsMjA0KSAxcHggc29saWQ7IEhFSUdIVDogNDVweCIg +DQogIGFsdD0iIiBzcmM9Imh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvbGlua19sb2dvMDQu +Z2lmIj48L0E+PFNQQU4gDQogIGNsYXNzPUFwcGxlLWNvbnZlcnRlZC1zcGFjZT4mbmJzcDs8L1NQ +QU4+PEEgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IERJU1BMQVk6IGlubGluZTsgUEFE +RElORy1MRUZUOiAwcHg7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogNXB4OyBDT0xPUjog +cmdiKDAsMCwwKTsgUEFERElORy1UT1A6IDBweDsgVEVYVC1ERUNPUkFUSU9OOiBub25lIiANCiAg +aHJlZj0iaHR0cDovL3d3dy5iai5jeWJlcnBvbGljZS5jbi9pbmRleC5odG0iIHRhcmdldD1fYmxh +bms+PElNRyB0aXRsZT0iIiANCiAgc3R5bGU9IkJPUkRFUi1SSUdIVDogcmdiKDIwNCwyMDQsMjA0 +KSAxcHggc29saWQ7IEJPUkRFUi1UT1A6IHJnYigyMDQsMjA0LDIwNCkgMXB4IHNvbGlkOyBCT1JE +RVItTEVGVDogcmdiKDIwNCwyMDQsMjA0KSAxcHggc29saWQ7IFdJRFRIOiAxMTVweDsgQk9SREVS +LUJPVFRPTTogcmdiKDIwNCwyMDQsMjA0KSAxcHggc29saWQ7IEhFSUdIVDogNDVweCIgDQogIGFs +dD0iIiBzcmM9Imh0dHA6Ly9jc2RuaW1nLmNuL3d3dy9pbWFnZXMvbGlua19sb2dvMDUuZ2lmIj48 +L0E+PC9EVD4NCiAgPEREIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBQQURESU5HLUxF +RlQ6IDBweDsgUEFERElORy1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IFBBRERJTkctVE9QOiAw +cHgiPuWuouaIt+acjeWKoeeDree6v++8mjAxMC01MTY2MTIwMuOAgOi/neazleS/oeaBr+S4vuaK +peeUteivne+8mjEzNTUyMDA5Njg5IA0KICDkuL7miqXpgq7nrrHvvJo8QSANCiAgc3R5bGU9IlBB +RERJTkctUklHSFQ6IDVweDsgUEFERElORy1MRUZUOiA1cHg7IFBBRERJTkctQk9UVE9NOiAwcHg7 +IENPTE9SOiByZ2IoMCwwLDApOyBQQURESU5HLVRPUDogMHB4OyBURVhULURFQ09SQVRJT046IG5v +bmUiIA0KICBvbmNsaWNrPSJ3aW5kb3cubG9jYXRpb24uaHJlZj0nbWFpJysnbHRvOicrJ3dlYm1h +Jysnc3RlckBjJysnc2RuLm4nKydldD9zdWJqZWN0PVJlcG9ydCBUbyBDU0ROJztyZXR1cm4gZmFs +c2UiIA0KICBocmVmPSJodHRwOi8vd3d3LmNzZG4ubmV0LyMiPndlYm1hc3RlckBjc2RuLm5ldDwv +QT48L0REPg0KICA8REQgDQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IFBBRERJTkctTEVG +VDogMHB4OyBQQURESU5HLUJPVFRPTTogMHB4OyBNQVJHSU46IDBweDsgUEFERElORy1UT1A6IDBw +eCI+5YyX5Lqs5biC5YWs5a6J5bGA5pyd6Ziz5YiG5bGA572R55uR5Lit5b+D5aSH5qGI57yW5Y+3 +77yaMTEwMTA1MDk2OTxTUEFOIA0KICBjbGFzcz1BcHBsZS1jb252ZXJ0ZWQtc3BhY2U+Jm5ic3A7 +PC9TUEFOPjxBIA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogNXB4OyBQQURESU5HLUxFRlQ6IDVw +eDsgUEFERElORy1CT1RUT006IDBweDsgQ09MT1I6IHJnYigwLDAsMCk7IFBBRERJTkctVE9QOiAw +cHg7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQogIGhyZWY9Imh0dHA6Ly93d3cubWlpYmVpYW4u +Z292LmNuLyIgdGFyZ2V0PV9ibGFuaz7kuqxJQ1Dor4EwNzA1OTjlj7c8L0E+PC9ERD4NCiAgPERE +IA0KICBzdHlsZT0iUEFERElORy1SSUdIVDogMHB4OyBQQURESU5HLUxFRlQ6IDBweDsgUEFERElO +Ry1CT1RUT006IDBweDsgTUFSR0lOOiAwcHg7IFBBRERJTkctVE9QOiAwcHgiPjxBIA0KICBzdHls +ZT0iUEFERElORy1SSUdIVDogNXB4OyBQQURESU5HLUxFRlQ6IDVweDsgUEFERElORy1CT1RUT006 +IDBweDsgQ09MT1I6IHJnYigwLDAsMCk7IFBBRERJTkctVE9QOiAwcHg7IFRFWFQtREVDT1JBVElP +Tjogbm9uZSIgDQogIGhyZWY9Imh0dHA6Ly93d3cuY3Nkbi5uZXQvY29tcGFueS9pY3AuaHRtbCI+ +55S15L+h5Lia5Yqh5a6h5om5WzIwMDdd5a2X56ysMzgw5Y+3PC9BPjxTUEFOIA0KICBjbGFzcz1B +cHBsZS1jb252ZXJ0ZWQtc3BhY2U+Jm5ic3A7PC9TUEFOPjxBIA0KICBzdHlsZT0iUEFERElORy1S +SUdIVDogNXB4OyBQQURESU5HLUxFRlQ6IDVweDsgUEFERElORy1CT1RUT006IDBweDsgQ09MT1I6 +IHJnYigwLDAsMCk7IFBBRERJTkctVE9QOiAwcHg7IFRFWFQtREVDT1JBVElPTjogbm9uZSIgDQog +IGhyZWY9Imh0dHA6Ly93d3cuY3Nkbi5uZXQvY29tcGFueS9waWZ1Lmh0bWwiPueUteS/oeS4juS/ +oeaBr+acjeWKoeS4muWKoee7j+iQpeiuuOWPr+ivgTA3MDU5OOWPtzwvQT48L0REPg0KICA8REQg +DQogIHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IFBBRERJTkctTEVGVDogMHB4OyBQQURESU5H +LUJPVFRPTTogMHB4OyBNQVJHSU46IDBweDsgUEFERElORy1UT1A6IDBweCI+5YyX5Lqs5Yib5paw +5LmQ55+l5bm/5ZGK5pyJ6ZmQ5YWs5Y+4IA0KICDniYjmnYPmiYDmnIk8L0REPg0KICA8REQgDQog +IHN0eWxlPSJQQURESU5HLVJJR0hUOiAwcHg7IFBBRERJTkctTEVGVDogMHB4OyBQQURESU5HLUJP +VFRPTTogMHB4OyBNQVJHSU46IDBweDsgUEFERElORy1UT1A6IDBweCI+5LiW57qq5LmQ55+lKOWM +l+S6rCnnvZHnu5zmioDmnK/mnInpmZDlhazlj7ggDQogIOaPkOS+m+aKgOacr+aUr+aMgTwvREQ+ +DQogIDxERCANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgUEFERElORy1MRUZUOiAwcHg7 +IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBQQURESU5HLVRPUDogMHB4Ij7msZ/o +i4/kuZDnn6XnvZHnu5zmioDmnK/mnInpmZDlhazlj7ggDQogIOaPkOS+m+WVhuWKoeaUr+aMgTwv +REQ+DQogIDxERCBjbGFzcz1zbWFsbCANCiAgc3R5bGU9IlBBRERJTkctUklHSFQ6IDBweDsgUEFE +RElORy1MRUZUOiAwcHg7IFBBRERJTkctQk9UVE9NOiAwcHg7IE1BUkdJTjogMHB4OyBQQURESU5H +LVRPUDogMHB4Ij5Db3B5cmlnaHQgDQogIMKpIDE5OTktMjAxMCwgQ1NETi5ORVQsIEFsbCBSaWdo +dHMgUmVzZXJ2ZWQ8L0REPjwvREw+PC9ESVY+PC9ESVY+PC9ESVY+PElNRyANCnN0eWxlPSJCT1JE +RVItVE9QLVdJRFRIOiAwcHg7IEJPUkRFUi1MRUZULVdJRFRIOiAwcHg7IEJPUkRFUi1CT1RUT00t +V0lEVEg6IDBweDsgQk9SREVSLVJJR0hULVdJRFRIOiAwcHgiIA0KaGVpZ2h0PTAgc3JjPSJodHRw +Oi8vY291bnRlci5jc2RuLm5ldC9wdi5hc3B4P2lkPTE4IiB3aWR0aD0wIGJvcmRlcj0wPjxTUEFO +IA0KY2xhc3M9QXBwbGUtY29udmVydGVkLXNwYWNlPiZuYnNwOzwvU1BBTj48SU1HIA0Kc3R5bGU9 +IkJPUkRFUi1UT1AtV0lEVEg6IDBweDsgQk9SREVSLUxFRlQtV0lEVEg6IDBweDsgQk9SREVSLUJP +VFRPTS1XSURUSDogMHB4OyBCT1JERVItUklHSFQtV0lEVEg6IDBweCIgDQpoZWlnaHQ9MSBhbHQ9 +IiIgDQpzcmM9Imh0dHA6Ly9jcTE0NC5jc2RuLm5ldC92aXNpdGxvZy5waHA/c2NyZWVuPTEwMjR4 +NzY4JmFtcDtob3N0PXd3dy5jc2RuLm5ldCZhbXA7YnJvd3Nlcj1OZXRzY2FwZSUyMDUlMjAmYW1w +O29zPVdpbmRvd3MmYW1wO3VybD1odHRwOi8vd3d3LmNzZG4ubmV0LyIgDQp3aWR0aD0xIGJvcmRl +cj0wPjxJRlJBTUUgaWQ9bXlmcmFtZSBib3JkZXI9MCBuYW1lPW15ZnJhbWUgDQpzcmM9Imh0dHA6 +Ly93d3cuY3Nkbi5uZXQvZ2dtbS9kZDMzMy5odG0iIGZyYW1lQm9yZGVyPW5vIHdpZHRoPTAgc2Ny +b2xsaW5nPW5vIA0KaGVpZ2h0PTA+PC9JRlJBTUU+PC9TUEFOPjwvU1BBTj48L1NQQU4+PC9TUEFO +PjwvRk9OVD48L0RJVj48L0JPRFk+PC9IVE1MPg0K + +------=_NextPart_001_0004_01CB9D0D.783DE8D0-- + +------=_NextPart_000_0003_01CB9D0D.783DE8D0 +Content-Type: image/jpeg; + name="735_60_zhengding.jpg" +Content-Transfer-Encoding: base64 +Content-Location: http://info-database.csdn.net/Upload/2010-12-10/735_60_zhengding.jpg + +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 + +------=_NextPart_000_0003_01CB9D0D.783DE8D0 +Content-Type: application/octet-stream; + name="gmlog.php?bannerid=5432&clientid=1712&zf=&zoneid=402&source=&block=0&capping=0&cb=72dcec0a5d4a366564f2acd8fb357666" +Content-Transfer-Encoding: base64 +Content-Location: http://z.csdn.net/gmlog.php?bannerid=5432&clientid=1712&zf=&zoneid=402&source=&block=0&capping=0&cb=72dcec0a5d4a366564f2acd8fb357666 + +R0lGODlhAQABAIAAAAQCBAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw== + +------=_NextPart_000_0003_01CB9D0D.783DE8D0 +Content-Type: image/jpeg; + name="web_210_60_1130.jpg" +Content-Transfer-Encoding: base64 +Content-Location: http://info-database.csdn.net/Upload/2010-11-30/web_210_60_1130.jpg + +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 +3Yv/2Q== + +------=_NextPart_000_0003_01CB9D0D.783DE8D0 +Content-Type: application/octet-stream; + name="gmlog.php?bannerid=5326&clientid=1677&zf=&zoneid=403&source=&block=0&capping=0&cb=88c03d98a31161690d6826e83e9293a0" +Content-Transfer-Encoding: base64 +Content-Location: http://z.csdn.net/gmlog.php?bannerid=5326&clientid=1677&zf=&zoneid=403&source=&block=0&capping=0&cb=88c03d98a31161690d6826e83e9293a0 + +R0lGODlhAQABAIAAAAQCBAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw== + +------=_NextPart_000_0003_01CB9D0D.783DE8D0 +Content-Type: image/gif; + name="csdnindex_pic1.gif" +Content-Transfer-Encoding: base64 +Content-Location: http://csdnimg.cn/www/images/csdnindex_pic1.gif + +R0lGODlhJQARAOYAAPn3+fr59+jn6v78/7i4uJqZnOrq6uHg5ebn6e3o7Ojo6Pj4+wA0ZQAzaObm +5vr39sjHx+bo6uvq6PHx8eLi4Pz//ZiYmAEzZvn5/AEzZOvr5+jo6pmal/r6+u3t7ZuamOLk45qc +m5iamQAzYgA0Y////5qamv///f7////+//n5+f7+/vj4+OPj45ubm///+/3//pmbmv7+/P7//eLi +4uvp6uzq6/z///f395uZmv7/+v39/fj6+AIxaP/+/P7+///++f/++v//+vr4+fv//unr6urp6ePl +4//9+v7/++Tk5P/+/ezr6QIxZf3+//r4+/r6+JybmeTi4+rq7JmZmQQ0Z/b6++fn5+bo5/3/+v3+ +9u/r7O3p6u/p6eXj6AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5 +BAAAAAAALAAAAAAlABEAQAf/gBMEJgUfISZUJi4mijGMMZCOh4yUlIuMBBMuJTInnS8pGScNKydZ +FyUnLzKpFxUnDD4ZJQOiL0AlPygfgomMBSEFOSI5joY5OSEfJsFUhy4uwJRUVJkmJSUr2CUpPw0l +SdgjKSkXM0szFykwFygM2KisJyhZOS4eBh42NjUSNhdMttiQ0KBLgi0aujAByKWKgR4SpjThV8NA +EQ+Jsm07sY0bxxtLUqBYl0okihIofJRwcvJVihVRrmnLduLEDlojb/RA+SOFDBTtgKJosuQGKicV +UiwpYcGEChYqorLoEICECh4qrFxgwcMKjwBDMqh4wmBIAx4YtqrAEZWpCQdX/xwoUCA3ggABCBBs +0ItAwAa6CfRi2eBlr4ArVxS0oIGRAISZ3Cpwm4HixgmRJ4igmCGSsowVJjliQ4ECwqAdNXXcGiUE +iQ4kGV5oERLk1oseTRg0CdKkQe8gQjheRqRR24oBJTIQydCjwYUGIxjsHHAhJIMdDMiR8AEDcggq +27T9mEFCByodKUiAgzEvd+/cDUg0yNAAxroTNz64UNEhqgooLGDAAAYd9MDABQxIpwIGPIhVVQAM +sBBAD/7NRA1ULOCAwwIAJMjhEA9c8AQAODzAAgsZcHgBDhlkGCEOGO6wiAFz1SBAEVMYMMIUFyDI +AH0jXKBAA0UUkcEFGWjAHCwDRvCzmAcmOEaDEosdQYEUR7SgpZYgtADCAV6AQEELStCQ5Zhj0qCl +A6YFAgA7 + +------=_NextPart_000_0003_01CB9D0D.783DE8D0 +Content-Type: image/gif; + name="csdnindex_pic2.gif" +Content-Transfer-Encoding: base64 +Content-Location: http://csdnimg.cn/www/images/csdnindex_pic2.gif + +R0lGODlhJQARAOYAAAAzZeLi4Pj2+vz/////+vj5+ujn7P/8/+rq6u3t7eLj5fr//7i4uJqanOvq +6MfHyJmal+fn6vf29uTj4QAyaOPk3+bn6fn49gA0Zerq7Pj4+vf3+v3//JqamPr6++nr5ubm5uPk +4+Ll5Pn5/Ojo6Pn39f/++QEyY+bn6/f59+zr7fn69QA0Y////5qamv///f7///7+/v/+//n5+f7+ +//7//Zubm/r4+Zmbmv7+/JmZmf/+/Pj4+JuZmuvp6uXm6Ozr6Zmbl+Tk4vj6+ZuYmPDw8Pn59+fj +5OTk5O7q6u/p6efn5/39/fn7+vv6+JiZm5yanvn3+///9+jo6unr6Onr6vz4+QMyZeTn7P7/+f79 +++fl6Jebmubo5/z3+wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5 +BAAAAAAALAAAAAAlABEAQAf/gEUMODg2DS6ILj2LiY06OI2IkC46LjYuDEU2MTkvLzAEFFcDLFcU +FAAnLRg7BDkUHAdXOS0tLDUvJi0yLRw9gpUuQR1QPQ1cDR02HQ09LjgNUB3EiIZEQS5cEERPmTox +ni8HMDAUMi8UMBgtJzLtNC8cMju87LXiLwM1MdgqKkAIfKjwkQQBEAz+MCRRYhAAAB8OgFwBosTB +KQf/gFBJUClGjBaeWsCr9XEXkxe1UnK4twMkDJAt6LXAVjJGDQ4LyAFggQFDKhowPtIQCUNfDRYy +ZCwYIK7WExczePCY4eVGgRkzrgC4goEFAA8rZlyYYWRGTw8nmhQwwsPDkBVG/wZwsQGCxJIlBn5s +WfLDwN4uPyJgMYAiwpItGbosQUFlCwkDUywsETEhAxcGD1oIfVEj6FAOQPMRkFFjwEucMoIOENnC +9IsHDFy06JSDgBR0J05QMLGbRZYsBEJhoMDiFPEdwDmMHmqpBROPIGnUOIHhwAEOAGJkv36Agm6f +ADAw2RHjZQsYORBB37VLhjlyNeClo4GKAnhRALzXArVABqQZHnjAQ1lY3UCBEUMYMQIGNziRwlU3 +AMBDT1acgNUIN1xwwGqVSDBDCjNskEIKJZRAwQYSSHDBCRcIIIEAAtgnAAAbRHGCACUIsIEGN0Sh +hQ02ILAEAlU48AF1w6Gy1UEpAJDgAwII2AdABiQ44EMVJCDgQABCJNABZgpMoIACAShQAWVhKiDE +BCIEEEAFAUyARABHiElmAEhUoMARP8AWCAA7 + +------=_NextPart_000_0003_01CB9D0D.783DE8D0 +Content-Type: image/gif; + name="csdnindex_piclogo.gif" +Content-Transfer-Encoding: base64 +Content-Location: http://csdnimg.cn/www/images/csdnindex_piclogo.gif + +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 +xz72BZUCEggAOw== + +------=_NextPart_000_0003_01CB9D0D.783DE8D0 +Content-Type: image/gif; + name="560_95_wr_1123.gif" +Content-Transfer-Encoding: base64 +Content-Location: http://info-database.csdn.net/Upload/2010-11-23/560_95_wr_1123.gif + +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 +O8ImdMIn1EFHmiQpnD0qpD0r5EEs3LmAAAA7 + +------=_NextPart_000_0003_01CB9D0D.783DE8D0 +Content-Type: application/octet-stream; + name="gmlog.php?bannerid=5317&clientid=1548&zf=&zoneid=404&source=&block=0&capping=0&cb=2f4d1e97e275e63981443643fef88c01" +Content-Transfer-Encoding: base64 +Content-Location: http://z.csdn.net/gmlog.php?bannerid=5317&clientid=1548&zf=&zoneid=404&source=&block=0&capping=0&cb=2f4d1e97e275e63981443643fef88c01 + +R0lGODlhAQABAIAAAAQCBAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw== + +------=_NextPart_000_0003_01CB9D0D.783DE8D0 +Content-Type: image/jpeg; + name="475_60_ophonez.jpg" +Content-Transfer-Encoding: base64 +Content-Location: http://info-database.csdn.net/Upload/2010-11-17/475_60_ophonez.jpg + +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 + +------=_NextPart_000_0003_01CB9D0D.783DE8D0 +Content-Type: application/octet-stream; + name="gmlog.php?bannerid=5366&clientid=1683&zf=&zoneid=405&source=&block=0&capping=0&cb=e82d1151cb1a2e0ccfa0f2eeb66a509e" +Content-Transfer-Encoding: base64 +Content-Location: http://z.csdn.net/gmlog.php?bannerid=5366&clientid=1683&zf=&zoneid=405&source=&block=0&capping=0&cb=e82d1151cb1a2e0ccfa0f2eeb66a509e + +R0lGODlhAQABAIAAAAQCBAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw== + +------=_NextPart_000_0003_01CB9D0D.783DE8D0 +Content-Type: image/gif; + name="ren475-60.gif" +Content-Transfer-Encoding: base64 +Content-Location: http://zi.csdn.net/ren475-60.gif + +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 +XXfdbadddtjfoCIgADs= + +------=_NextPart_000_0003_01CB9D0D.783DE8D0 +Content-Type: application/octet-stream; + name="gmlog.php?bannerid=4738&clientid=1467&zf=&zoneid=406&source=&block=0&capping=0&cb=34b1731ba388f24691559538b49f2220" +Content-Transfer-Encoding: base64 +Content-Location: http://z.csdn.net/gmlog.php?bannerid=4738&clientid=1467&zf=&zoneid=406&source=&block=0&capping=0&cb=34b1731ba388f24691559538b49f2220 + +R0lGODlhAQABAIAAAAQCBAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw== + +------=_NextPart_000_0003_01CB9D0D.783DE8D0 +Content-Type: image/jpeg; + name="56_72_ty.jpg" +Content-Transfer-Encoding: base64 +Content-Location: http://images.csdn.net/20101210/56_72_ty.jpg + +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 + +------=_NextPart_000_0003_01CB9D0D.783DE8D0 +Content-Type: image/jpeg; + name="=?utf-8?B?6aaW6aG15LiT6aKYMDIuanBn?=" +Content-Transfer-Encoding: base64 +Content-Location: =?utf-8?B?aHR0cDovL2ltYWdlcy5jc2RuLm5ldC8yMDEwMTIwMy/pppbpobXkuJPpopgwMg==?= + =?utf-8?B?LmpwZw==?= + +/9j/4AAQSkZJRgABAgEBLAEsAAD/4RQSRXhpZgAATU0AKgAAAAgABwESAAMAAAABAAEAAAEaAAUA +AAABAAAAYgEbAAUAAAABAAAAagEoAAMAAAABAAIAAAExAAIAAAAbAAAAcgEyAAIAAAAUAAAAjYdp +AAQAAAABAAAApAAAANAAAAEsAAAAAQAAASwAAAABQWRvYmUgUGhvdG9zaG9wIENTIFdpbmRvd3MA +MjAxMDoxMjowMyAxODowNToyNgAAAAAAA6ABAAMAAAAB//8AAKACAAQAAAABAAAAXaADAAQAAAAB +AAAAkAAAAAAAAAAGAQMAAwAAAAEABgAAARoABQAAAAEAAAEeARsABQAAAAEAAAEmASgAAwAAAAEA +AgAAAgEABAAAAAEAAAEuAgIABAAAAAEAABLcAAAAAAAAAEgAAAABAAAASAAAAAH/2P/gABBKRklG +AAECAQBIAEgAAP/tAAxBZG9iZV9DTQAC/+4ADkFkb2JlAGSAAAAAAf/bAIQADAgICAkIDAkJDBEL +CgsRFQ8MDA8VGBMTFRMTGBEMDAwMDAwRDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAENCwsN +Dg0QDg4QFA4ODhQUDg4ODhQRDAwMDAwREQwMDAwMDBEMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwM +DAwM/8AAEQgAkABdAwEiAAIRAQMRAf/dAAQABv/EAT8AAAEFAQEBAQEBAAAAAAAAAAMAAQIEBQYH +CAkKCwEAAQUBAQEBAQEAAAAAAAAAAQACAwQFBgcICQoLEAABBAEDAgQCBQcGCAUDDDMBAAIRAwQh +EjEFQVFhEyJxgTIGFJGhsUIjJBVSwWIzNHKC0UMHJZJT8OHxY3M1FqKygyZEk1RkRcKjdDYX0lXi +ZfKzhMPTdePzRieUpIW0lcTU5PSltcXV5fVWZnaGlqa2xtbm9jdHV2d3h5ent8fX5/cRAAICAQIE +BAMEBQYHBwYFNQEAAhEDITESBEFRYXEiEwUygZEUobFCI8FS0fAzJGLhcoKSQ1MVY3M08SUGFqKy +gwcmNcLSRJNUoxdkRVU2dGXi8rOEw9N14/NGlKSFtJXE1OT0pbXF1eX1VmZ2hpamtsbW5vYnN0dX +Z3eHl6e3x//aAAwDAQACEQMRAD8AzDuk6nlN7vErSw+jX5ddVtb2tbZcanbp9gADvWf/AMH+aoO6 +TlBzWt2+8e3e5rJhvq2Fu530K2fSesvhlvT3Hv4rMeIWN78Gh7vEpe7xKv8A7G6hBisGBqA5pIMt +HpwD/Ofpa/Yis6Hkuqc91lTHSQwb2lrgGvtsd6gd+b6Tmf10uGXYqPMYgL44/bbl+7xKXu8Si21G +p5Zua+ADuYZGonlQgptsgIIsdWPu8Sl7vEqUFKClabY+7xKXu8SpQUoKVqtj7vEp/dB1PKeCnjSU +rRb/AP/QcMzqMGvIqte1tltjPSaCI2+lbv8A7b/T/wC20FmT1C0ekx9ln8lo3GNvp9hub+j9i0ru +o9Qb0XHcMm0E33MJDz9EMq2s/qtRbcfIx8bGx8TLpxGmplt02+nY+ywepusj3bGN9lSy67E0APxe +uGWh64w4pTmAfCEv0vQ4/wC0OoN09Z7S0bPAgaafvbvapfaep2fpw6xwaZ3hstBgs7N2fRe9azse +nNyentyrq8jI/SDLdU7cX11D1qvUeI/SOZvq3LOs6v1Gyz1GXvpb+ZVWSxjW9q2Vt9m1A6byPguh +MT0jjhderi2+aUPT6fVx+2xux2fsvCsrZ+mtsva4tEucG+nsb/Z3Km+t7HbXtLHDlrgQfuK1zl3Y +3QsQUH07LLbwbW6PDR6csY78ze76e1Re+7O6QHXuNt1OSyqqx5l221ria3WO/M317vckQDsdeEH/ +AJqYZZgEkDg9ycbv1fzkuH/BciCpvptrIFjHMJ1G4ET/AJy2sDBsxa8231KasvHeyiu2x42ML9zr +LK3+5vq7Gba07RacTJpz86nJqdU59QN3qPbc33VOq3e73/zb0hDTXQm1HmhxHhqUQQN/VLi4Zej/ +AB3DZVZY7bW1z3eDQSf+irhx2DoxtLIuGV6ZcR7tvp7tn+crOZffgVY+HiPdSDTXde9h2ue+wep7 +3t92ytjtjGKWTlW5XQWOvO+1mVtNp+k4en7PUd+e5n7yQAHEL1AUcs5cEgAISmKN+rh7kf1nGhPH +tPxCnCUaH4hR22CX/9E1duHbgDEyLHUvptfaxzWbw4Pa1rmfSbsd+jTm3BzaaRlWOxsihgq9QM9R +j2N/m9waQ9llbfYqZGpTQsX3PAHSvN7H2huJSBviFV6TL569P6X9dssvx8LMpvwS600mXutAaHn8 +5oraXba9ns9zlN9HRnONrMi2ph1GOatzx/wYt3Ct39dU4ShLj6UK7dknHqCJyEqoyHDch/W9Ke7I +rf0/GxhPqUvtc/wh+zbH+Yky+sdMtxTPqPvZaNNNrW2Md/1aBCJQ6tlzH2t3sBlzfH70OM39OH6f +KkxAjWpqRyf4XF7n/SSYOTRXXdi5Qd9myNsuZBcx7DNdrWu+n9JzXsStp6bXU708h+RafoBtfptH +nY57nOd/VYr7MvBN8tDayGNmwhoBEVfo/Y3+S9Cy3023PdU4Pb6D+O3u+j2Uhrh3Eq0HdgEzx3Uo +cVSl+6ZD/B/7tEbcHOppGVa7GyaGCr1Aw2MsY3+bnaQ9lrG+xLJysH9mNwcYPJZf6pseAC+WbC6A +Ts/kMVvHe6xlGN1Bwf8AarafRpIALKw73Ww2PSbc39Gxv+E/nEPIyrrMO3It2m7Hyg2nc0ENBbZv +q2kbfTZsr/Rok6X3Gunq07+paD6gKNRlcY8Xo4pemPB6OKUePi/uORCeND8Vt3GOo5uQI9arFbZW +YGjyylrrA36O5rXvcpbz6X23T7WcH1C+BO4XfZ/X/wCM+z/npvBrV9a2/rcDIeZPDxcP6PFv+lwe +7w/3f67/AP/SGkpEalKFgW9nbFJShKErVbFJShKErVbFO1zmztMSIPwKeEoRtSe/qObkNLbrS8Eg +zDQZH0fc1u5Nb1DMtex9lpc6o7mEgcnl5bG173fvvQYShHjl3P2rRjgKqERW2g67th/Us59zL3Wk +21ghroaNCNpaYb727f31D7ZlfaPtXqH1uN2nEbdmz6Hp7f8AB7diFCUaJccu5779VcEBtGO3Dt+j ++7/df//TLh4TM05AdY6p1UQ6Q1jGkxvs37W2Otc7ZVU2z/Sf9cs5/Rqseq7IxbS+sPL6HPdDRU3V +4P0vVc/1sXb9BBwcurFOSzIeBT7LhURPqOZZW/0v5e9tez3fQ3qzmdQwLcG3FF226yilpdtmtrqg +x99O6n2N+1XV7/0Tbff/AIX9J+hzYDGcYsC6/F6uUs3ujh4vbuOgHEOH0cR/wWuOlVOxcS995rdk +Oc6yzsK/zf0ZO9mxlORb6iB1DEOJY+o3MY11j2tY4udYxrTH6XbX/Y+irePn4xwK8ex1kMe31arL +HPe9oYP0OPVV6TW12fzTWW+pWhZljrM5mXvrozLHEZTLmFzarAPS9Yn07q3U2+x7H/4O7/PRMMZi +KA6LoSy8ZEr4Rx1Y/wAKHy8X+N/6sZ3dKqZm5tNd0VUC/wBFg9Xc0sd6bN7/AEdtn0f8G6xQbZhu +x7sd1AdlgurrtZZ6Y3QNv6DKey7dv/kq03Nxv2nm5OTk+pTZkOuxg3dYGlrn/Z7r9n0cXY79JT/O +/Q/RKrUctotsqAy7cUvsbfX/ADW8j1X5b7LNrr8hm79FV+Z/58RhDsNz0tbEzI9ZOggQZE448X97 +0cXq+dnm9Pq6bfsuaW2Vhj3UvuZte0sHqtZtd61dvrb9n84xSNOBn27cWo0sZj32EG9hLnNrNtE7 +bPb7m/pFKzJfeLMhrH2txmM9HLpLS5jxVWbKbWP/AJ2j1Pe7/RWJUZWflP8AVxxVZnGsNArDWVVt +ltlr7Xu20vyMnbs2f6P/AKB4YcWw+zVF5OAGRqcY1KXHKMYylH5pQ/8AVn/qtywbGhgO2xzjtDa3 +te8mNPbWXfTWgekvFfpNDx1GsGy7cCKSD7fsrbT+jbdV+99B9j/RQMqwV+kcWwNFbnh2O8P9SkOh +ttdttbf0uN/o37/U2KxZX0Y2NqF9ADWbTlBlrt9pPLmGv020N/m/Zb/wn/BJkcUBeg101P5Ms5y9 +JAlG7J4YSn8v7/8AV/u/P+g03MsrsfTdW6q2sw+t42uEiRolGihTLgbSAHWEuIAgCf3Wj81FjRVf +T7lfo3S8g7aXt/V4n//U26Og/S+0h0z7PaR8e6K36vUukVB5DeYHnC2rLbK2l225gaJcWtrOg935 +65m/qObeK7r77w6yp17W0saWU1S+ul17Wsd6nqOZ+l/cr/7bWd7OMCuG/N3cWXmcxJExECvH/mx/ +up8n6uE1EV1OdZ+bua4+fn4LNPRepBzWnCf7hJPp6DWPdorFuZmV2VttyLg/J9M12tbWKbBYW+p6 +P6M7PS3f+qkXHsyb3isZz66G2202OsZWSx1db7mWbtn6SixtT97PzEPahdAEfY2YnmIRuU4SHzWR +k/5vC59nSc+utznYwYQNw3BrZH7zA/a530mqR6N1EOcPsh9uhAZrIBP+b7Ht3qzVndabk+hud9pc +x7bA/a2up3qOq9T2Nr9Flfp7/wCW9FwGuxsgWdOq+i0NdVc4NOU0HYcrHdY7a2/1fUb6X+j/AOE9 +VAYge6+WTNEGzjurjXyH+9Lijwf1Wi3o3VCH/qRBaNBsBJ40bt/rKNvS86oVmzHaxj3Bu5zWgEni +N23crlfrdTrtycubXMubX+ksftqD/VPspoDfStb6dbGb99ar5FTsWi3JLHu9DIqbXL3kGo+s6zdI +2+5zKv8APSOIVYtMZ5OLhJjxAgGIHp4pbcMvc/rfuqHROpkGMQ+XsGoH50/uotPQOpOcC/EIDdpL +SzbMlm9o+j9Fr/3lXxmYdlT77bWOrxyXZID7Yta4/q9bmmtv+FGyx9f+AT492Zf6WNVabKqGbmmo +mp8vPptd+lG6+ui87Pd/gUhijpdm/FMve1qUY8PzGUJRr68fzfL/AOGO636usI/mnc9w4af2rFD9 +jYe2YdzH0X8xMfTWPRk20tZmtzGtLrbGWXAWPDhDX/0Syv0v0e/99b37V6j+wP2hss9b092+GbOd +vqbI3+nt96cMeL90bW1MkOZgYj3bE5jHfqjUyf3f03//1e0ed7HMcTtcCCJPBXOX9PzdtdBx7LH1 +VGlj63htVle576ftH0XM9Jz/AHM/wv8AIXQGwBRNvgszidrDllivhAN669/8FwK8XKqbZXRiXilz +67XUvLS1hrc173Ue/wDSPf8AR/4r/SKJZke/HqxbQLX3Ps3bC7fbU+mtuwO/RV113Of7nfpF0BsU +IYHusH0nQXHxgbP+pS42Yc1LW4DX+983y+r1PN59efdZi2ZdRqeygVlxb6gtdWTDnsZv9/p2s+ml +eXW4+Mxwcyuql1d1n2Vp0Nl15sq9rdn6O1v0X1reux/tGVXZ+5VbWXAwRvDdf+qRMQBmE2twnZSK +QxxHucWx6f7v6T3JcZs+LJ97AhD0C468I/R4uMacXG85XbfXhDCLXY5dYy8VgPmxrm3i1+2nY703 +s9CrZ/o02dsdTjltTqHUMa0PNdrYIe9/tsc9+yvbZ/XW90uzLdkWm1jC3Yxlrmk+11bdjGaja7d+ +fsVtzQ4OqfrtnbPcH6TUuOx+Cpc3w5Pk6icuGWlyHq/Reco6lfjVemyx99bnF2S97nN9Qbdhoxy/ +3VtZXf63q2fTs9P/AESEx9DMmwB9mU52O5tL3ss9Sp7/AG+9m5zdza3P9zPZ+etx2DiF270xwGxy +NNu32/2GKNZaMl7ntM1Aw86nbrA4+js/m0Pcl1rwSOYh6jGBsj1aiPF2tyGWZP2RlDb8kFlr3OsY +yyNhayvaPcx35j/YtSMn/mzH2Y7vT2ejDvo7tvqbZ9X6H6VXGWN9NxrPtfLpB0JPJUGv/QP1/Ob+ +SxHj/JiyZzLhIhXDkjPx+b+7/Wf/1ulbcHt3CRPY6EfFJ1oa0ucYAEk+QVdjyWNJ0LgDHxDU1p3V +vbyS0wD4xosTjd/gFpqckXMLgI2uLYmeDo7+0pm0BzWnl0xp4CdVn9NJGI2xwh9xL3ffDf8ANai2 +WubkY+sUlzvVdB/NG5g0/eS40yxjikB0v/mr4d1gyuoVOPFjSJAmHN8f6rGInU33txKmUP2W2Wgt +jmZDGR+7tc9qGyoHLsuDnbryNzTEfHjd3V3IrruYKXk7ND7TBlpDm6j+U1Li0KJEDJGVfu2K/djw +tjcGkw0CTrGkoV7iC2xuh408QkCANFF/uaRojxsMY0Qq0hwFzeHfTA7O/wDMlXt/SVPqcSWOa4be +0kfST02gO2v+g/RyhYCxxbz4HyQM2SMaNdtkXTw+rCZXZIe3duB05JPCluMKxiUeu479K289pP7q +0fSp9P0tjfT/AHY0SvT6JObhyChcjIHw1L//1+hdiW2FtjGmoOaB6ToOzaPoe1QOJlDhk+YI/vSr +yX11fTaCAQJkgeBDG/ut/M3pPy3Oc1tdoDGxr3MfvO1/6K5vjegHuDTSvItWjG+zRUN+7s1xPBPt +9v0VbttNdYpafNyrnKyjkj1DWa2glpDfd/V3Ib3ue4udySjxshiZEGVHr9W3jO9+790KxvnlUqrN +rY7nWUYPIA8xqh7iycdU5II8Ewfs1cZH5EEvKYuDtY1S9xbwMLXDeS36J1CK1wuq2/4RnHmg26sk +CCEFljmPDh2/IlxsnDY03DrdPcPs5gahxn4qzvXKdXdnG0PrL244ALXMkDcfp79v539ZB/bPVPsx +p9Q9v0se+I+ju/78ncRq0HlJEDKJA68Rj1D/AP/Z/+0Y1lBob3Rvc2hvcCAzLjAAOEJJTQQlAAAA +AAAQAAAAAAAAAAAAAAAAAAAAADhCSU0D7QAAAAAAEAEsAAAAAQACASwAAAABAAI4QklNBCYAAAAA +AA4AAAAAAAAAAAAAP4AAADhCSU0EDQAAAAAABAAAAHg4QklNBBkAAAAAAAQAAAAeOEJJTQPzAAAA +AAAJAAAAAAAAAAABADhCSU0ECgAAAAAAAQAAOEJJTScQAAAAAAAKAAEAAAAAAAAAAjhCSU0D9QAA +AAAASAAvZmYAAQBsZmYABgAAAAAAAQAvZmYAAQChmZoABgAAAAAAAQAyAAAAAQBaAAAABgAAAAAA +AQA1AAAAAQAtAAAABgAAAAAAAThCSU0D+AAAAAAAcAAA/////////////////////////////wPo +AAAAAP////////////////////////////8D6AAAAAD/////////////////////////////A+gA +AAAA/////////////////////////////wPoAAA4QklNBAAAAAAAAAIAAzhCSU0EAgAAAAAACgAA +AAAAAAAAAAA4QklNBAgAAAAAABAAAAABAAACQAAAAkAAAAAAOEJJTQQeAAAAAAAEAAAAADhCSU0E +GgAAAAADPwAAAAYAAAAAAAAAAAAAAJAAAABdAAAABWcqaAeYmAAtADgAAAABAAAAAAAAAAAAAAAA +AAAAAAAAAAEAAAAAAAAAAAAAAF0AAACQAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAA +AAAAEAAAAAEAAAAAAABudWxsAAAAAgAAAAZib3VuZHNPYmpjAAAAAQAAAAAAAFJjdDEAAAAEAAAA +AFRvcCBsb25nAAAAAAAAAABMZWZ0bG9uZwAAAAAAAAAAQnRvbWxvbmcAAACQAAAAAFJnaHRsb25n +AAAAXQAAAAZzbGljZXNWbExzAAAAAU9iamMAAAABAAAAAAAFc2xpY2UAAAASAAAAB3NsaWNlSURs +b25nAAAAAAAAAAdncm91cElEbG9uZwAAAAAAAAAGb3JpZ2luZW51bQAAAAxFU2xpY2VPcmlnaW4A +AAANYXV0b0dlbmVyYXRlZAAAAABUeXBlZW51bQAAAApFU2xpY2VUeXBlAAAAAEltZyAAAAAGYm91 +bmRzT2JqYwAAAAEAAAAAAABSY3QxAAAABAAAAABUb3AgbG9uZwAAAAAAAAAATGVmdGxvbmcAAAAA +AAAAAEJ0b21sb25nAAAAkAAAAABSZ2h0bG9uZwAAAF0AAAADdXJsVEVYVAAAAAEAAAAAAABudWxs +VEVYVAAAAAEAAAAAAABNc2dlVEVYVAAAAAEAAAAAAAZhbHRUYWdURVhUAAAAAQAAAAAADmNlbGxU +ZXh0SXNIVE1MYm9vbAEAAAAIY2VsbFRleHRURVhUAAAAAQAAAAAACWhvcnpBbGlnbmVudW0AAAAP +RVNsaWNlSG9yekFsaWduAAAAB2RlZmF1bHQAAAAJdmVydEFsaWduZW51bQAAAA9FU2xpY2VWZXJ0 +QWxpZ24AAAAHZGVmYXVsdAAAAAtiZ0NvbG9yVHlwZWVudW0AAAARRVNsaWNlQkdDb2xvclR5cGUA +AAAATm9uZQAAAAl0b3BPdXRzZXRsb25nAAAAAAAAAApsZWZ0T3V0c2V0bG9uZwAAAAAAAAAMYm90 +dG9tT3V0c2V0bG9uZwAAAAAAAAALcmlnaHRPdXRzZXRsb25nAAAAAAA4QklNBCgAAAAAAAwAAAAB +P/AAAAAAAAA4QklNBBEAAAAAAAEBADhCSU0EFAAAAAAABAAAAAw4QklNBAwAAAAAEvgAAAABAAAA +XQAAAJAAAAEYAACdgAAAEtwAGAAB/9j/4AAQSkZJRgABAgEASABIAAD/7QAMQWRvYmVfQ00AAv/u +AA5BZG9iZQBkgAAAAAH/2wCEAAwICAgJCAwJCQwRCwoLERUPDAwPFRgTExUTExgRDAwMDAwMEQwM +DAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwBDQsLDQ4NEA4OEBQODg4UFA4ODg4UEQwMDAwMEREM +DAwMDAwRDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDP/AABEIAJAAXQMBIgACEQEDEQH/3QAE +AAb/xAE/AAABBQEBAQEBAQAAAAAAAAADAAECBAUGBwgJCgsBAAEFAQEBAQEBAAAAAAAAAAEAAgME +BQYHCAkKCxAAAQQBAwIEAgUHBggFAwwzAQACEQMEIRIxBUFRYRMicYEyBhSRobFCIyQVUsFiMzRy +gtFDByWSU/Dh8WNzNRaisoMmRJNUZEXCo3Q2F9JV4mXys4TD03Xj80YnlKSFtJXE1OT0pbXF1eX1 +VmZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3EQACAgECBAQDBAUGBwcGBTUBAAIRAyExEgRBUWFxIhMF +MoGRFKGxQiPBUtHwMyRi4XKCkkNTFWNzNPElBhaisoMHJjXC0kSTVKMXZEVVNnRl4vKzhMPTdePz +RpSkhbSVxNTk9KW1xdXl9VZmdoaWprbG1ub2JzdHV2d3h5ent8f/2gAMAwEAAhEDEQA/AMw7pOp5 +Te7xK0sPo1+XXVbW9rW2XGp26fYAA71n/wDB/mqDuk5Qc1rdvvHt3uayYb6thbud9Ctn0nrL4Zb0 +9x7+KzHiFje/Boe7xKXu8Sr/AOxuoQYrBgagOaSDLR6cA/zn6Wv2IrOh5LqnPdZUx0kMG9pa4Br7 +bHeoHfm+k5n9dLhl2KjzGIC+OP225fu8Sl7vEottRqeWbmvgA7mGRqJ5UIKbbICCLHVj7vEpe7xK +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 +lGPD8xlCUa+vH83y/wDhjut+rrCP5p3PcOGn9qxQ/Y2HtmHcx9F/MTH01j0ZNtLWZrcxrS62xllw +Fjw4Q1/9Esr9L9Hv/fW9+1eo/sD9obLPW9Pdvhmznb6myN/p7fenDHi/dG1tTJDmYGI92xOYx36o +1Mn939N//9XtHnexzHE7XAgiTwVzl/T83bXQceyx9VRpY+t4bVZXue+n7R9FzPSc/wBzP8L/ACF0 +BsAUTb4LM4naw5ZYr4QDeuvf/BcCvFyqm2V0Yl4pc+u11Ly0tYa3Ne91Hv8A0j3/AEf+K/0iiWZH +vx6sW0C19z7N2wu321PprbsDv0Vdddzn+536RdAbFCGB7rB9J0Fx8YGz/qUuNmHNS1uA1/vfN8vq +9TzefXn3WYtmXUansoFZcW+oLXVkw57Gb/f6drPppXl1uPjMcHMrqpdXdZ9ladDZdebKva3Z+jtb +9F9a3rsf7RlV2fuVW1lwMEbw3X/qkTEAZhNrcJ2UikMcR7nFsen+7+k9yXGbPiyfewIQ9AuOvCP0 +eLjGnFxvOV2314Qwi12OXWMvFYD5sa5t4tftp2O9N7PQq2f6NNnbHU45bU6h1DGtDzXa2CHvf7bH +Pfsr22f11vdLsy3ZFptYwt2MZa5pPtdW3Yxmo2u3fn7Fbc0ODqn67Z2z3B+k1LjsfgqXN8OT5Oon +Lhlpch6v0XnKOpX41XpssffW5xdkve5zfUG3YaMcv91bWV3+t6tn07PT/wBEhMfQzJsAfZlOdjub +S97LPUqe/wBvvZuc3c2tz/cz2fnrcdg4hdu9McBscjTbt9v9hijWWjJe57TNQMPOp26wOPo7P5tD +3Jda8EjmIeoxgbI9WojxdrchlmT9kZQ2/JBZa9zrGMsjYWsr2j3Md+Y/2LUjJ/5sx9mO709now76 +O7b6m2fV+h+lVxljfTcaz7Xy6QdCTyVBr/0D9fzm/ksR4/yYsmcy4SIVw5Iz8fm/u/1n/9bpW3B7 +dwkT2OhHxSdaGtLnGABJPkFXY8ljSdC4Ax8Q1Nad1b28ktMA+MaLE43f4BaanJFzC4CNri2Jng6O +/tKZtAc1p5dMaeAnVZ/TSRiNscIfcS933w3/ADWotlrm5GPrFJc71XQfzRuYNP3kuNMsY4pAdL/5 +q+HdYMrqFTjxY0iQJhzfH+qxiJ1N97cSplD9ltloLY5mQxkfu7XPahsqBy7Lg5268jc0xHx43d1d +yK67mCl5OzQ+0wZaQ5uo/lNS4tCiRAyRlX7tiv3Y8LY3BpMNAk6xpKFe4gtsboeNPEJAgDRRf7mk +aI8bDGNEKtIcBc3h30wOzv8AzJV7f0lT6nEljmuG3tJH0k9NoDtr/oP0coWAscW8+B8kDNkjGjXb +ZF08PqwmV2SHt3bgdOSTwpbjCsYlHruO/StvPaT+6tH0qfT9LY30/wB2NEr0+iTm4cgoXIyB8NS/ +/9foXYlthbYxpqDmgek6Ds2j6HtUDiZQ4ZPmCP70q8l9dX02ggECZIHgQxv7rfzN6T8tznNbXaAx +sa9zH7ztf+iub43oB7g00ryLVoxvs0VDfu7NcTwT7fb9FW7bTXWKWnzcq5yso5I9Q1mtoJaQ33f1 +dyG97nuLncko8bIYmRBlR6/Vt4zvfu/dCsb55VKqza2O51lGDyAPMaoe4snHVOSCPBMH7NXGR+RB +LymLg7WNUvcW8DC1w3kt+idQitcLqtv+EZx5oNurJAghBZY5jw4dvyJcbJw2NNw63T3D7OYGocZ+ +Ks71ynV3ZxtD6y9uOAC1zJA3H6e/b+d/WQf2z1T7MafUPb9LHviPo7v+/J3EatB5SRAyiQOvEY9Q +/wD/2ThCSU0EIQAAAAAAUwAAAAEBAAAADwBBAGQAbwBiAGUAIABQAGgAbwB0AG8AcwBoAG8AcAAA +ABIAQQBkAG8AYgBlACAAUABoAG8AdABvAHMAaABvAHAAIABDAFMAAAABADhCSU0EBgAAAAAABwAE +AAAAAQEA/+EYBGh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8APD94cGFja2V0IGJlZ2luPSfv +u78nIGlkPSdXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQnPz4KPHg6eG1wbWV0YSB4bWxuczp4PSdh +ZG9iZTpuczptZXRhLycgeDp4bXB0az0nWE1QIHRvb2xraXQgMy4wLTI4LCBmcmFtZXdvcmsgMS42 +Jz4KPHJkZjpSREYgeG1sbnM6cmRmPSdodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1z +eW50YXgtbnMjJyB4bWxuczppWD0naHR0cDovL25zLmFkb2JlLmNvbS9pWC8xLjAvJz4KCiA8cmRm +OkRlc2NyaXB0aW9uIHJkZjphYm91dD0ndXVpZDpkOTdlNGY2Zi1mZWM0LTExZGYtYmQ1NC05ZmVh +YmQzMTllNzYnCiAgeG1sbnM6ZXhpZj0naHR0cDovL25zLmFkb2JlLmNvbS9leGlmLzEuMC8nPgog +IDxleGlmOkNvbG9yU3BhY2U+NDI5NDk2NzI5NTwvZXhpZjpDb2xvclNwYWNlPgogIDxleGlmOlBp +eGVsWERpbWVuc2lvbj45MzwvZXhpZjpQaXhlbFhEaW1lbnNpb24+CiAgPGV4aWY6UGl4ZWxZRGlt +ZW5zaW9uPjE0NDwvZXhpZjpQaXhlbFlEaW1lbnNpb24+CiA8L3JkZjpEZXNjcmlwdGlvbj4KCiA8 +cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0ndXVpZDpkOTdlNGY2Zi1mZWM0LTExZGYtYmQ1NC05 +ZmVhYmQzMTllNzYnCiAgeG1sbnM6cGRmPSdodHRwOi8vbnMuYWRvYmUuY29tL3BkZi8xLjMvJz4K +IDwvcmRmOkRlc2NyaXB0aW9uPgoKIDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSd1dWlkOmQ5 +N2U0ZjZmLWZlYzQtMTFkZi1iZDU0LTlmZWFiZDMxOWU3NicKICB4bWxuczpwaG90b3Nob3A9J2h0 +dHA6Ly9ucy5hZG9iZS5jb20vcGhvdG9zaG9wLzEuMC8nPgogIDxwaG90b3Nob3A6SGlzdG9yeT48 +L3Bob3Rvc2hvcDpIaXN0b3J5PgogPC9yZGY6RGVzY3JpcHRpb24+CgogPHJkZjpEZXNjcmlwdGlv +biByZGY6YWJvdXQ9J3V1aWQ6ZDk3ZTRmNmYtZmVjNC0xMWRmLWJkNTQtOWZlYWJkMzE5ZTc2Jwog +IHhtbG5zOnRpZmY9J2h0dHA6Ly9ucy5hZG9iZS5jb20vdGlmZi8xLjAvJz4KICA8dGlmZjpPcmll +bnRhdGlvbj4xPC90aWZmOk9yaWVudGF0aW9uPgogIDx0aWZmOlhSZXNvbHV0aW9uPjMwMC8xPC90 +aWZmOlhSZXNvbHV0aW9uPgogIDx0aWZmOllSZXNvbHV0aW9uPjMwMC8xPC90aWZmOllSZXNvbHV0 +aW9uPgogIDx0aWZmOlJlc29sdXRpb25Vbml0PjI8L3RpZmY6UmVzb2x1dGlvblVuaXQ+CiA8L3Jk +ZjpEZXNjcmlwdGlvbj4KCiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0ndXVpZDpkOTdlNGY2 +Zi1mZWM0LTExZGYtYmQ1NC05ZmVhYmQzMTllNzYnCiAgeG1sbnM6eGFwPSdodHRwOi8vbnMuYWRv +YmUuY29tL3hhcC8xLjAvJz4KICA8eGFwOkNyZWF0ZURhdGU+MjAxMC0xMi0wM1QxODowNToyNisw +ODowMDwveGFwOkNyZWF0ZURhdGU+CiAgPHhhcDpNb2RpZnlEYXRlPjIwMTAtMTItMDNUMTg6MDU6 +MjYrMDg6MDA8L3hhcDpNb2RpZnlEYXRlPgogIDx4YXA6TWV0YWRhdGFEYXRlPjIwMTAtMTItMDNU +MTg6MDU6MjYrMDg6MDA8L3hhcDpNZXRhZGF0YURhdGU+CiAgPHhhcDpDcmVhdG9yVG9vbD5BZG9i +ZSBQaG90b3Nob3AgQ1MgV2luZG93czwveGFwOkNyZWF0b3JUb29sPgogPC9yZGY6RGVzY3JpcHRp +b24+CgogPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9J3V1aWQ6ZDk3ZTRmNmYtZmVjNC0xMWRm +LWJkNTQtOWZlYWJkMzE5ZTc2JwogIHhtbG5zOnhhcE1NPSdodHRwOi8vbnMuYWRvYmUuY29tL3hh +cC8xLjAvbW0vJz4KICA8eGFwTU06RG9jdW1lbnRJRD5hZG9iZTpkb2NpZDpwaG90b3Nob3A6ZDk3 +ZTRmNmUtZmVjNC0xMWRmLWJkNTQtOWZlYWJkMzE5ZTc2PC94YXBNTTpEb2N1bWVudElEPgogPC9y +ZGY6RGVzY3JpcHRpb24+CgogPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9J3V1aWQ6ZDk3ZTRm +NmYtZmVjNC0xMWRmLWJkNTQtOWZlYWJkMzE5ZTc2JwogIHhtbG5zOmRjPSdodHRwOi8vcHVybC5v +cmcvZGMvZWxlbWVudHMvMS4xLyc+CiAgPGRjOmZvcm1hdD5pbWFnZS9qcGVnPC9kYzpmb3JtYXQ+ +CiA8L3JkZjpEZXNjcmlwdGlvbj4KCjwvcmRmOlJERj4KPC94OnhtcG1ldGE+CiAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAog +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAo8P3hwYWNrZXQgZW5kPSd3Jz8+ +/+4ADkFkb2JlAGQAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoKDBAMDAwMDAwQ +DAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAEHBwcNDA0YEBAYFA4ODhQUDg4ODhQRDAwMDAwR +EQwMDAwMDBEMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwM/8AAEQgAkABdAwERAAIRAQMRAf/d +AAQADP/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAAAQAC +AwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPBUtHh +MxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE1OT0 +ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZqbnJ +2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEyobHw +FMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp0+Pz +hJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+DlJ +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 + +------=_NextPart_000_0003_01CB9D0D.783DE8D0 +Content-Type: image/jpeg; + name="2.jpg" +Content-Transfer-Encoding: base64 +Content-Location: http://images.csdn.net/20101130/2.jpg + +/9j/4AAQSkZJRgABAgEASABIAAD/4RpfRXhpZgAATU0AKgAAAAgABwESAAMAAAABAAEAAAEaAAUA +AAABAAAAYgEbAAUAAAABAAAAagEoAAMAAAABAAIAAAExAAIAAAAUAAAAcgEyAAIAAAAUAAAAhodp +AAQAAAABAAAAnAAAAMgAAABIAAAAAQAAAEgAAAABQWRvYmUgUGhvdG9zaG9wIDcuMAAyMDEwOjEx +OjMwIDEzOjI2OjA3AAAAAAOgAQADAAAAAf//AACgAgAEAAAAAQAAAFqgAwAEAAAAAQAAAIIAAAAA +AAAABgEDAAMAAAABAAYAAAEaAAUAAAABAAABFgEbAAUAAAABAAABHgEoAAMAAAABAAIAAAIBAAQA +AAABAAABJgICAAQAAAABAAAZMQAAAAAAAABIAAAAAQAAAEgAAAAB/9j/4AAQSkZJRgABAgEASABI +AAD/7QAMQWRvYmVfQ00AAv/uAA5BZG9iZQBkgAAAAAH/2wCEAAwICAgJCAwJCQwRCwoLERUPDAwP +FRgTExUTExgRDAwMDAwMEQwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwBDQsLDQ4NEA4OEBQO +Dg4UFA4ODg4UEQwMDAwMEREMDAwMDAwRDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDP/AABEI +AIAAWQMBIgACEQEDEQH/3QAEAAb/xAE/AAABBQEBAQEBAQAAAAAAAAADAAECBAUGBwgJCgsBAAEF +AQEBAQEBAAAAAAAAAAEAAgMEBQYHCAkKCxAAAQQBAwIEAgUHBggFAwwzAQACEQMEIRIxBUFRYRMi +cYEyBhSRobFCIyQVUsFiMzRygtFDByWSU/Dh8WNzNRaisoMmRJNUZEXCo3Q2F9JV4mXys4TD03Xj +80YnlKSFtJXE1OT0pbXF1eX1VmZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3EQACAgECBAQDBAUGBwcG +BTUBAAIRAyExEgRBUWFxIhMFMoGRFKGxQiPBUtHwMyRi4XKCkkNTFWNzNPElBhaisoMHJjXC0kST +VKMXZEVVNnRl4vKzhMPTdePzRpSkhbSVxNTk9KW1xdXl9VZmdoaWprbG1ub2JzdHV2d3h5ent8f/ +2gAMAwEAAhEDEQA/AOt+rH1Y+rd/1b6Tdd0nCtttwsd9lj8epznOdVW573vdXuc9zlpf80/qr/5T +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 +9Fcnf1TqGL9X/qZgdNyji359eM23YGFxorx2PyC3167mN2ez8xavTuu5mI7KZn052aDbONY2ut7f +S2Vj6dDcb6V3rO97E6MJSBlEXR4fr8zHLNCExCR4SRxa6BoYx+tnS8SrAu6C2+rGqbU3J6fks2kN +G1rq8XK9C5v+cj/VjpWdd17I63nYVuJVVjsxsBmUWm0Elz8u8V1PtZT6ntZ/pHrQp+uGPdZfVX07 +P345aLA6kN+mC5hZNnub7UT/AJ0NGrum5wHlU0/g2xVMHwvBhynNixSjOV3rOQ9XzfNxLpc1Aijk +j9ocnqfTM/6v9Xu6r0vHszOmdTdu6jiUt9Sym/6Lc/Fx2+65lv8A2qpr/Sf4X/i69ON17ruYcWn7 +T07pjBOT1C+p1GQ9x19DpuPkjdT7f+1dlP8Axa2MT66Y2ZUMjG6bn2UOJDLPRa3dtO1zmtfa1+3c +ucs619bcXDzM3qV+TXbbmsZg4OO3Hc8UPeNtbG/Z7/Uu9Pd9KxGXwrBkz/eJY7nWvEP1cuH5ZSj+ +8g83CI4OMHXh4Yn1auxT/i56bjF32PqXUsVrzLhXczUn6Rc+yh9rtzv5a2OhfV7C6Gy/0LLsi/Lf +6mTlZL/UuscBtZvsDWN21t9tbWsQB9aWa7um57T2/Qg6ePssKCfrrg/bBhDBzzkFnqlgxzoz6Isc +7ft2OcNisDBwkyGMRkdDIRqUv8JXv4z/AJSJrX5noklif86av/K7P1/4Ef8ApRBxvrli5NZsp6d1 +BzWvfW6aACHVn07G62fmP9id7c/3T9iPexfvx/xg9CvlVfRzPrVjm+qq7CzMdl1jKW3W1AMD7XCq +n1Nj3va2y57Kt+36di+cUuCV1wm0+7jri448N1d6W//Uj0zJZd1npuQ8k4/QPq9jOtHZtllLbnR/ +LfRYxW8/GZR1/wCrHTqnOZmupf1Dqzml36Qbd7PUM7XsffTk1+l+Ytz6tfVLpGR0npvU7PW9bLws +J2VW2xwqt9LHpqqZdT9F9bWs+gtTqP1R6V1HqR6ra/IqzfTFAtptcyKxr6TWt9rWucVIMgAiNfSb +kwSwmRySsXOIhD+q8VldLx8j7T1bKqz89+Rf6VGNgvc0sqp/Vw702OZu/TMu9SzcidOpx8LDz8yj +C6hgPZVtjqD3O3E6tdQxz7P5t+3c9dRV9Quj01+lRkZ1VYJcGNyXxLjvedZ+m/3uTW/UHo99Tqcj +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 +nq1/2XGzLcai+u77JVi1W3txW1+jk0XbX+pS/wC1/pa7d9v+j9WlH+sf106wxr/2bXU2ptTWvfdT +c+1ltp2Vuocxrunu9Jr6/wBFkP8A5/8AR7Lf5tZuD0zoeO7MOP1rp2DbXbVd0rJbl0PeC2v0surM +b6nvx8r/AAtLLEXIPT8h9VX7W6OXVvFzr8i2osNjR7H01Y2XR6Hud+/+jSU6+D9aOrYZI66ylrGt +aWWU4+Zjk7T+mfc/qONi0N3M/wBB/wAIuYP+MH6xANjNe9xpBMNx4bkHn1N2BX+qt/7jV/pf/NpY +pGul3TbKcrqfTn5bvUJe3qVdzHlzXelH2h4fi11+2r02+oqeN0nC9RleTn9NuxmuBs29Qooc5rWN +aPSJbkXUWOtb+mf6n6Wn/RWfpElPp/1O6rd1foFOde57rHvta42mtzv0dj6ecanEq/M9v6H/ALc/ +nF84L336p9Y+rvSOhY+BkdW6bXdUbNwZmU2A7rH2Ncbf0HqPcx3vf6a8CSU//9n/7R7qUGhvdG9z +aG9wIDMuMAA4QklNBCUAAAAAABAAAAAAAAAAAAAAAAAAAAAAOEJJTQPtAAAAAAAQAEgAAAABAAIA +SAAAAAEAAjhCSU0EJgAAAAAADgAAAAAAAAAAAAA/gAAAOEJJTQQNAAAAAAAEAAAAeDhCSU0EGQAA +AAAABAAAAB44QklNA/MAAAAAAAkAAAAAAAAAAAEAOEJJTQQKAAAAAAABAAA4QklNJxAAAAAAAAoA +AQAAAAAAAAACOEJJTQP1AAAAAABIAC9mZgABAGxmZgAGAAAAAAABAC9mZgABAKGZmgAGAAAAAAAB +ADIAAAABAFoAAAAGAAAAAAABADUAAAABAC0AAAAGAAAAAAABOEJJTQP4AAAAAABwAAD///////// +////////////////////A+gAAAAA/////////////////////////////wPoAAAAAP////////// +//////////////////8D6AAAAAD/////////////////////////////A+gAADhCSU0ECAAAAAAA +EAAAAAEAAAJAAAACQAAAAAA4QklNBB4AAAAAAAQAAAAAOEJJTQQaAAAAAAM3AAAABgAAAAAAAAAA +AAAAggAAAFoAAAABADIAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAFoAAACCAAAA +AAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAEAAAAAAABudWxsAAAAAgAAAAZi +b3VuZHNPYmpjAAAAAQAAAAAAAFJjdDEAAAAEAAAAAFRvcCBsb25nAAAAAAAAAABMZWZ0bG9uZwAA +AAAAAAAAQnRvbWxvbmcAAACCAAAAAFJnaHRsb25nAAAAWgAAAAZzbGljZXNWbExzAAAAAU9iamMA +AAABAAAAAAAFc2xpY2UAAAASAAAAB3NsaWNlSURsb25nAAAAAAAAAAdncm91cElEbG9uZwAAAAAA +AAAGb3JpZ2luZW51bQAAAAxFU2xpY2VPcmlnaW4AAAANYXV0b0dlbmVyYXRlZAAAAABUeXBlZW51 +bQAAAApFU2xpY2VUeXBlAAAAAEltZyAAAAAGYm91bmRzT2JqYwAAAAEAAAAAAABSY3QxAAAABAAA +AABUb3AgbG9uZwAAAAAAAAAATGVmdGxvbmcAAAAAAAAAAEJ0b21sb25nAAAAggAAAABSZ2h0bG9u +ZwAAAFoAAAADdXJsVEVYVAAAAAEAAAAAAABudWxsVEVYVAAAAAEAAAAAAABNc2dlVEVYVAAAAAEA +AAAAAAZhbHRUYWdURVhUAAAAAQAAAAAADmNlbGxUZXh0SXNIVE1MYm9vbAEAAAAIY2VsbFRleHRU +RVhUAAAAAQAAAAAACWhvcnpBbGlnbmVudW0AAAAPRVNsaWNlSG9yekFsaWduAAAAB2RlZmF1bHQA +AAAJdmVydEFsaWduZW51bQAAAA9FU2xpY2VWZXJ0QWxpZ24AAAAHZGVmYXVsdAAAAAtiZ0NvbG9y +VHlwZWVudW0AAAARRVNsaWNlQkdDb2xvclR5cGUAAAAATm9uZQAAAAl0b3BPdXRzZXRsb25nAAAA +AAAAAApsZWZ0T3V0c2V0bG9uZwAAAAAAAAAMYm90dG9tT3V0c2V0bG9uZwAAAAAAAAALcmlnaHRP +dXRzZXRsb25nAAAAAAA4QklNBBEAAAAAAAEBADhCSU0EFAAAAAAABAAAAAM4QklNBAwAAAAAGU0A +AAABAAAAWQAAAIAAAAEMAACGAAAAGTEAGAAB/9j/4AAQSkZJRgABAgEASABIAAD/7QAMQWRvYmVf +Q00AAv/uAA5BZG9iZQBkgAAAAAH/2wCEAAwICAgJCAwJCQwRCwoLERUPDAwPFRgTExUTExgRDAwM +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 +r0rpB68cjNy29Q6XXW9tGPivJxnENa2yzIdW3du9R9vpNd/wCIyR4CLl/wB0iWHKcwlUO/X2xw/L +/wBNxfqlg59OF0rC6obW5mZnes9lribGV44f1BrfcS9tfqYWLv8A/DX/AAi8fX0t0n6vYPSnvtqd +bkZDwW/aMl5tsawwfQqe7+bq3N3v2fzn+E/m6180pnujivXh4eD+syfd5cG8eP3Pd/qX+7/iP//V +0W9fyv8Amz03p3TXWsbidPxreoZNDXGxrWUY9jen4jvTdX+0M31qvzv1bH/S2KXQvrD1bGdZmZlu +TmUUjZmVQ9wZU4MsxM/Cbfj41uR9la2/E6lU39Pdb6uX/oa7MVnSrH1dIsbh5F1QxMDKaKi4suv9 +CqsNdb6jaum+myrH+05TKbb7aVf6b0XqWSWUdRwcix92bkdRzH30tbjV2WYt9Dacd/2i59rK8x1H +2Z//AFz/AAaeOGtfFhmcnGBG6sdDw/1r/eXf9YOodYdk152VlNxcV32i2rBpAYWF09Orx8/HsdlW +WZFTsfKqZ6f/ABvp0ItX1n+sePk04bbc2y31G111Z2FVWx+4+ynJ6lTb6e/Ydnq1e/8A4P1Vm9W6 +N1zF6PndMw6zfi21uupazbW+qwWsyLt+39Llb6q/Rx9v/ELQqwcjqOdf1DCxrfsV3UMS+zLsca2l +uG2p/wCr4V9VWRufvsp3fQ9WpH08Pit/W+714Sf8Hgjwf9/NPf8AXnq2VXkDGuxsRjn21VvONmW2 +VBrizc99VTsV99dX6V/u9Kv+ooV/WLN6Xkusb1PI6oMSxrbcJ1L7B9leG2h32uqkVvzm178qvI9f +0L6v0Kz8TpvXm4udjWY2c0ZJHqDHuZjV1ua4u3YNtnreq3MZ/S7PTrVirC+sOBdWyim+u4txaT9l +aH4N1dTmNrtyX3O9XGsxsT1cW+pjP0j2V3/8Gh6a6XSf1hyamXADQoR9X970/KmxvrR1/wC35F2K +MrMrzKsm2ivbTZVsB2dKyMOuu3dS1r/0Way22xaHS/rD1HpLbMTqgycl17wcHJtDHMc847brcN17 +HNfv+3V5TK2Op/m/8Iufz/qxldQotwndPsacL7cacl5AYRYbsqkYONU9rsq/Id6dXqXenTV/ovWR +6MB2biZ/UMbH25pfRXiZVtTmvHp4lDLK6/tDWWek3KZYx36P+dQPDWm+i6Pu8Qv5fXuN/VHh/T/x +GeP1/qr8enJt6xkMr6k1r7nMp9UNGv2j7GyvHsdhehYPsPpbn2W/03/B+/d+quf1/I6jVj2ZP2nB +rxa8jI+0BvqsGR6v2Smu1ldVuTdW7Gf62RkMp31f4D11z/Sf21j9OqxMXE6gX12MtsqO0Culrh69 +FFzz+uW27/U9L9Hv2W+nbV+jXR/Vrpf1hHVH9YyH/ZsTLD2WYd43Xmqt132BroGzH2evZf8Azlv8 +76Nv76dLg4dKvRjx+97nq4uDX5v+bo9avlVfVS+VVG2X/9bvPqrTW/6r9GLhJOBi/wDnmtbAaAIH +AXMfVj6z/Vuj6t9Jpu6thVW1YWOyyt+RU1zXNqra9j2Os3Ne1y0v+dn1V/8ALnA/9iqf/SiSnRON +SXbi0SFS6r1GnDA9SDPih/8AOz6q/wDlzgf+xVP/AKUWF9YerdBzYOP1fAdH/dugf9VakpzM3665 +oyet01mvH9PGY/p1WS6hj2P2WCz7Oyr7b+0cq6307KMT+a/01+KtSv65eh0ejKyKWZVlmxgb06wZ +LnOLf0rrmOrwmY9lb/56hnq+iuQx8XFptzGYef0vFry31Cq77fU19HpO9b7ZX6b/AFHWuu9/2b1N +n/CK3Zj4xxX437b6V67bnP8Atrcqom42k2ZWbZTbf+hy3u/M/SUJKblX17z8nq1/2XGzLcai+u77 +JVi1W3txW1+jk0XbX+pS/wC1/pa7d9v+j9WlH+sf106wxr/2bXU2ptTWvfdTc+1ltp2Vuocxrunu +9Jr6/wBFkP8A5/8AR7Lf5tZuD0zoeO7MOP1rp2DbXbVd0rJbl0PeC2v0surMb6nvx8r/AAtLLEXI +PT8h9VX7W6OXVvFzr8i2osNjR7H01Y2XR6Hud+/+jSU6+D9aOrYZI66ylrGtaWWU4+Zjk7T+mfc/ +qONi0N3M/wBB/wAIuYP+MH6xANjNe9xpBMNx4bkHn1N2BX+qt/7jV/pf/NpYpGul3TbKcrqfTn5b +vUJe3qVdzHlzXelH2h4fi11+2r02+oqeN0nC9RleTn9NuxmuBs29Qooc5rWNaPSJbkXUWOtb+mf6 +n6Wn/RWfpElPp/1O6rd1foFOde57rHvta42mtzv0dj6ecanEq/M9v6H/ALc/nF84L336p9Y+rvSO +hY+BkdW6bXdUbNwZmU2A7rH2Ncbf0HqPcx3vf6a8CSU//9kAOEJJTQQhAAAAAABVAAAAAQEAAAAP +AEEAZABvAGIAZQAgAFAAaABvAHQAbwBzAGgAbwBwAAAAEwBBAGQAbwBiAGUAIABQAGgAbwB0AG8A +cwBoAG8AcAAgADcALgAwAAAAAQA4QklNBAYAAAAAAAcACAABAAEBAP/hEkhodHRwOi8vbnMuYWRv +YmUuY29tL3hhcC8xLjAvADw/eHBhY2tldCBiZWdpbj0n77u/JyBpZD0nVzVNME1wQ2VoaUh6cmVT +ek5UY3prYzlkJz8+Cjw/YWRvYmUteGFwLWZpbHRlcnMgZXNjPSJDUiI/Pgo8eDp4YXBtZXRhIHht +bG5zOng9J2Fkb2JlOm5zOm1ldGEvJyB4OnhhcHRrPSdYTVAgdG9vbGtpdCAyLjguMi0zMywgZnJh +bWV3b3JrIDEuNSc+CjxyZGY6UkRGIHhtbG5zOnJkZj0naHR0cDovL3d3dy53My5vcmcvMTk5OS8w +Mi8yMi1yZGYtc3ludGF4LW5zIycgeG1sbnM6aVg9J2h0dHA6Ly9ucy5hZG9iZS5jb20vaVgvMS4w +Lyc+CgogPHJkZjpEZXNjcmlwdGlvbiBhYm91dD0ndXVpZDo0MDg0OTIwZS1mYzQyLTExZGYtYmQz +ZC05YzYxMTY0MWEyODQnCiAgeG1sbnM6eGFwTU09J2h0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEu +MC9tbS8nPgogIDx4YXBNTTpEb2N1bWVudElEPmFkb2JlOmRvY2lkOnBob3Rvc2hvcDo0MDg0OTIw +OS1mYzQyLTExZGYtYmQzZC05YzYxMTY0MWEyODQ8L3hhcE1NOkRvY3VtZW50SUQ+CiA8L3JkZjpE +ZXNjcmlwdGlvbj4KCjwvcmRmOlJERj4KPC94OnhhcG1ldGE+CiAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAK +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +IAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAog +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgIAo8P3hwYWNrZXQgZW5kPSd3Jz8+/+4ADkFkb2Jl +AGRAAAAAAf/bAIQAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQIC +AgICAgICAgICAwMDAwMDAwMDAwEBAQEBAQEBAQEBAgIBAgIDAwMDAwMDAwMDAwMDAwMDAwMDAwMD +AwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMD/8AAEQgAggBaAwERAAIRAQMRAf/dAAQADP/EAMsA +AAIDAAMBAQEAAAAAAAAAAAgJBgcKAAQFAQMLAQABAwUBAQAAAAAAAAAAAAAABAYHAQIDBQgJChAA +AAYCAQMBAgUNCgoLAAAAAgMEBQYHAQgJABESEyEUMjMVFtoxQVEiNDYXGDi4GTk6YUJSYjfXeJhZ +CvDBI2MkZDVmWJqBQyVFRlZoeYmZShEAAgEDAwIEAwQGBwcFAAAAAQIDEQQFACEGEgcxQRMIUWEi +cTIUFYGh0UIjCfCRscHhFhfxUmJyM5MkotI0JVb/2gAMAwEAAhEDEQA/ANDXGVxlcbc942+PmdTr +j50gmk2mmkGqEsmMxlmqFDSOVSyVSOhoC8SGSyWQvEBWO77IH13WHKlq1UcapVKTRmmjEMQhZNGj +f/RO8WX9mnoB/U311/m56NGufoneLL+zT0A/qb66/wA3PRo1z9E7xZf2aegH9TfXX+bno0a5+id4 +sv7NPQD+pvrr/Nz0aNdFy4sOKJnQLHV244ePVsam1IpXuTk46f63okDehRkjUK1q5YprwtOkSJU5 +YhmGGCCAAA5znOMY6NVAJNAN9JOu574uZWtWQjjr4eOPzah7QuxzHJr8k+p9AV/qVAVKUWSl2c2c +dVR6y03dGZgXZDGE6wAxA7ZUh79OrjXDM3yq6W2xtq3TsS5B6QPjtudR1z3uvwXttjZr7kmWH4sA ++nbR/VLK3kvwSvxbQtOvHLApktC8yWKaKV8vPDjJkToTis0XTwluN75F7sicLfqOfy17AX7A+sYN +IIzGO/ph79T7Ye3my/Clsll5ml/4CqU/9Mn9uuMM571OTC8K4ThtpDaAVpcSMz08q9BFDTx2A1N4 +xUuruoj3B3HaTj447Nl9X3+UMcIn1ztfHzrLW91UQ4y13RsEUms2iUbgSiGTqslMhcE6ByWthKFY +1DUANMIEV5ZwwOd9pJ+L2z5LH3fr2CirVoekAEk9QpWlNwVG24qAaTJ2U9ztl3IzEHFeTYdcbyGY +fwWRi0MzDfoBbdWYbruQdxrRKn4o+K88ks8rjX4/jSTgFmkmg0410EEwowsIwDDnFcYxkIwi74z9 +jPUMbEAjXVwBFeo/V8Ph8tdj9E7xZf2aegH9TfXX+bnqmq6xBfinasf8NOv/AO2+/infyN11+Sx/ +w0/e5+T/AP7m/e5/qfRo1//Q188Tv6rLjT/oAab/AJutc9GjR/8ARo1zo0apaRbC05FrMZaZdpu3 +/hXkSfC1mr5uSujzKFiD0TFAnETa0oFo0jYSnLyMxSfkogoPj5jx5B7mjUR2V2/1w1BgCiydiLai +lbxzB5KBrTui33mTSh8V5wBvjENiTcFXI5ZJ3RQIJSdCgTHnmDF8HGMZzi+NJJGWOONmkJoABUk/ +o1azKgLyOqRAElmNAANySTtQDSRJH+MJyLuSKxNwGGVa76stLqqVVrogB+TFOtqR8WQmNFgbru7Q +djKk5xLCA9DX6VRhtQEZxlyEoUCyEMscS7ftI0d5m4zWv0oN6UPxpRj4g+SkU3NQOZe4vfEI15gu +E3IUhaNd7q1fCsFdumu3WfH4Aals1OZI0U3ssaQIUEEjDaQ3RyNQ1qKSR6Mo0pfh7g3tDYQla2tM +AIfZksIQZ6604Zb42wxsdtBAkExajFgFqPBasdzTXn13At89l83JevLNdwNQt0lpG6v3nK77nx28 +9Km2x2Tn4bPpaiqznWaqjdytE5SvtjsJkdNn5cnj5BSpsiEaenE1xQQnLm2escat92MV9i+xGcC7 +dJeT3FxPnsLxtMwsFteJJWSIq7K0YBCCp6ep/AHfp8t9bHiuHxmL4Zyfn2R449/ksddQCKG6V4YB +BKekzXKxjruCj0AQkLTZttBgoZrJUXu06GacvMpvt23EhxrNbEDkr29yVFUcS+crJ84dlpHIJCvW +nRR9QtiVWM8eTyyXc4SXxICfgPUOd1MhZcFjTDYiWaR72B/VhlkMqoWUqZSTVlkbqNYz9NKGlRro +rsFx3Ld5Zrbl3LMdFBBhr5ZbO+t4RbtKwJ67QBKK9vGtAhI6oz9NTXX9DKOtOWFgZGTJ41OGdoa2 +rCg32mHfJ6EhHk4wWfaIZoifLOfs565cC0LEef6tegx3Zj+6TsPhr2+q6NYA/p/nRo1//9HXzxO/ +qsuNP+gBpv8Am61z0aNH/wBGjXwWO+M475x3x274+rjo0aSfyy1BsKnrxkmutkctCSN07uuEA3RV +0C5I2LaV11ajzM4AMhVGyD1G9agRpH4pKc4pkSgpxUJTFOU4vVNFnCmya0F1B+OVja1NafHyr5kV +8aeWkGWGTbFZBMM0a5UxH0i/3Q3z8fLwNDT4aTrMt1eKnVEbbNSaukyC62kByeLJrope4HjYcx5w +XnGW1mk12pnJViRCFjGFChGuCErvkXn49TViM129xtnHcSTlZEUUSNAZCfM0Chtz41c7fLXImX4Z +375DfHG5Brh7eRqM3rILULXyA38PlpQmzXOlsZM061LB2eMUChczjvc1siVkTqfmIzDshIUhRnYT +RNiWGBFnyyMCwQBZ7989u/WtyfdnLTiW34zjo7e2H0mQ0d/lt4IR8vs1IXHfbfx209CXkl/PfXVe +oRx1SIN+9Un6mB8KGi+YGl+jO282GUFuExvuZL49IzsKVbzILZeHBhLLVe3Kk9jhaotMQlx5dsEF +FAAHHs7dsdRtf53kN6z/AJrm7mWQ+RZl+wBRqbMTw/ieFATD8asrZlFCRGpY082Yg11ZyrjSspC1 +I5pCrkaZsBMItae718hezXpgXp8+ZagkS5yLcyzC85z4mB7GfuZx1r47i6hdLmG4lWZG6lYO3Urf +EEnY63k9lbXNrcWN3j45LKYUkjaNSkgPky9NGH9BpiPEpuG8cUtnXBLJ3Vzts6yX4vihFhTloGmb +r4rtJGClaURTelkeBjmMcUGKQqlDaFYkNCcT5ACIWcdrbi4uby4mu7uaWa6kNXdiXZj4VY7+W2sV +ljLLF2cGNxOOjtbCIUSKNBHGor5KKD7fPW5/VHerVndiPOb9rhbTFOj49lOXLIqMtWxTqHHqQBEU +nlEOeyEL614ELPgE7JIkxhmMhAaLOM9Jw6mvSwNP6U+3WdkZDRhvouurtW6wB/T/ADo0a//S188T +v6rLjT/oAab/AJutc9GjR/8ARo1BbHs2uqgiTrPbUnUSriEsScap4lk3kLXGY82kADkYjFjs8KUi +InHiHPbGR98/WxnqjVoenx1UAk0A30qSY87OhjbHJJKanXXds8xRBmdn+USHXWirBmkJjTUyEGKH +BxkNlvLXGa2Z25OnLyYJQa7elgv29898YyhfJ42KaOCbIRLI3lWp+H3RU+Py1lW3lYBgm2k+bV2C +78vFLNGxe2UHk+oPGRAHpqsekIUlStqrc/biVhSqUMXfzHFAmcjqhgLoarMJamptyY6PZhwTDTwp +QhHjjf3Me7QdsM5hO0naSytM13vzA/hJK5S1x9uK+rf3rD7sMABNGP1EdIBO2nTguOG99e8vjTGR +Dcqfv7fdXcEn5DfXm8cOl2rEqQM16RTjVaqkZns5cNrmOylrmW3abg2h9VIndEkVOIeGVnLdCO4y +wDPwLwH5C7dw468cfd/7ju9OKurjgPJ/eHd5vMwpWS2weMWxskbx9OS5V4pXKn6Sek0p5mupM4rg +MTdqblcC0cNdi56uofLxpokNlOMjjybYfJLFU66nRt6yvQJkSWhBOcQlsllMjXltzKztSZhWIG8g +xa5KA5MOOxhMmKwM0f2oe2Yq7B++D3e23JMLxrE95pzjFidnkysizW1tbQIXklfrBdiqqQqAl3Yq +o8a62ua4bxtUMv5f/FfwC/r+XnqmY/wcV8yp0T+w7IbPVPIzyADdGaM2sY/M7SpM7Dy1BdnJqx8r +mJMZ8DDBF+AzA58MePbOZ4k/nB9+8ZkbuzsOOYXI2C16ZpbT0JJQDT1DGHYKH+8BWoB3FdaRO2tg +6Rn8ZKjMKhS29D8teTL+EOkgpHmdWpuBtIsQMraqdH19PmjU2lIW1GSMalesORMQBm4SAB547hEL +vjt2z37dK8Z/OB9zPIcxjcFxjt5gJc1dTLFFGsLepJI5AWNPq8WOw+3V0vbfGWkM09xkGWEA1Lb+ +A8v26HDiS3N0h0Pdtx4tCo27bi7NtCPA6gv+tm6WuVgbQwExeoNZ6gnxskSFRih32r3wnxdlS4ba +yHt2cLsCGaERQvcnind65te2uH5d3146/COVGBTd2V646jKR9616S7XCyVHppGGkr9JXwOojucR1 +X0tvi5RcW4OzDav2g+f6tM8p3lN3Gqab622HuwdTL/rVuFa4qlMWVhFneOA1PsR8Sq1FftSWeHvD +olvOsXh0AWyLX89I3C+U/I9NkxKHxFF3ZH3hcR71d4eednLPAtj81i7cXNqZJg0t1a1ozzw9I/DT +gEP+H6mdYyPU6WJAWZTjU2Lx8OQluKq5Ap0nxI+P7dJs+n+ddf6bGv/TcPrLyCWDrBxt6KjX1ce6 +xKHaOcckBqdijzkSZOdlb0urW+uk9dVaxCXEYa4mwp1iRwVvjkYIwxIhbu4Q5EcEPWk5JyPB8R49 +neVchv1t8FjbSS4uJDv0RxKWbYbljQBR5kjWe3tpbq4t7aEAyysFUE03Pz8tVrSXNJsDBrB5F3DZ +5oTWktqN8rmtdTaqpuOnR2I2xekhF8irte6pe3gKyS2jPkUrVl/KriXgRSBvJMOMIJDjt0zO1Pce +Hur2/wAF3MXBz4vj+StmuIEmZWb8OrELLIRQq7AA9O4FdidL8jjDYXklpHcrK6mhptRqVIqfH7dF +DXehLjdb637JctkiT7LXdJxN0nhenqpRhz1O1MMUhLVJIxFIKIQWqwpsxlBCQvkz4FSIw/1spywA +8RZ5B9zvvi7cdm4WxuRzh/NWr0WNqBJePSvSJAGX0Vk2ozEBSaUYjTl49xG/yVZ44isAWpdvDb4b +b7+HiTrwmfLTyfy57cRHYi/Fxq/PnCBR2nI01IGiG7329CjCgvC+SDRkkJVetVVTBPlEiaEoMJpA +7IDT1AhpSyyxaPPe4JuzXYBu83cPBHG8ryNt+IgsJ5jJKPWFbS2YgJ/5EsXTIyhaxRmlRJ1EZrXC +/mOZXF4+QOoahcCgUU+rx8waj5n5aKqyoMxWzKoQgf2pIfHoCrMkeGghKUVH0SwpsMZY2zIkJGCk +hBTS3mjwQWAGApy8Y8cYz2z188mW73c2y2b7j9y8nkS3LeSv6fqdRDxQeoHMcfmkYCrH0igIHn46 +mv8AILT0sbjbeMLZ21D4eJpuT8SSdzqvdhbCRazUa3y1nJLQskTmVXx5UEsvBSRLHJFOmWPOozAB +wLBZIUjoLIs4x9rjGO31Otf2d4u/eXubdcfy5Ml5e4zIyISxJ9eGzlmi3JrUum1fM6rm7g4DGRNa +ikXqIKAfFgP9uieVEpThGEmFgVJPWCaRjuEQTSyx+qlOALOMhwLx7Zxn63UHKZbcsFlKTiobyIPg +wPx05EAmjjbb1KAmorRqb/r0mbZnjz2a2R2th1vEbu3VVTHX8pYJTHGSFYbkFTxWHtBZucQpqrz1 +cGTawpA55CcveHkwxISlDkBZWRZDjr1E7R+7L2x9o/azneFp7dsdme7OVkeGaW9PWJY2ShuXugvq +w9JoI7eEqvmWrU6jW/43yO+z8d0mWdMcpqApAqa+Y+Hz+wU8tNKsENkIK8WIYG5pHKagalgzJQ/N +iM4WBtjWevGrTsJeS25U+vi9MUlSli/0ZKYdk4eBYLwHPBvAMpxE9wbDNZm1ntMXHdRSQwW8xTpc +zKR/5BrIkdsKzdW8j9AjBHVUPLIW13+XLbxkNIEoTSvV+j+34+Gl06facSCpNj9jX+2FUQs38OlQ +VlNbcziuI8xRlbbw5a/uRaI1AlKNSShahaTSxqVykODFZnYYy8d+3XYnui9zMvdrtvwbI8eyuVss +thuT5C3s5ZchNc3s9mbeJXuZJm6WjUyVCoo6U3Ct56amD49FZ5KXqQN106tgAKVrTbw213uZmOIX +nQmdG+BCNZBn+BzOLDKJLJC1usQlLM4NRqIgkACk4UgU3plhBgIQBz2xjt7OtR/LP5JkML7tuGTr +cu73omhlJYszepG9SzEkt1Hckk189Z+4NvEONzxxUADLQf8AL46UX9P86+sXXNWv/9TSjq3qlBtv +OD/QqnJSb83l0g0D0jfYnPW9AnUyCvrDi+vlbL4TYDCMY05oXqMOJeBFiAaUMRIzCsDDgec9a3L4 +nHZ3FZPCZi1SfE3cEkUsbAFWSRelgQQQfiK13prJFK0Ekcq/eRuofI6UDpxx6HUZymCidvIoI/qt +LaNd9lIIvis2s2ZtD1buwsmcYt85DmqysJS4UrRpkqlwwjbgqg4WHeQlRmMYx1w/7ieQ8s9svt75 +vyeTnU2Xis7FYcfbvbW9pb2iKyx28arESbiUsyGR/p61XdRvp34O3j5DlLS1e2o0s1WYV+FW/UNP +rf04pOgfm91WKg5kba7tLg4pjcFriSXxCpb1KxIb7cFK05aoQys/UCMOPsdfKze8wzua5pLzjkly +1/nHu0u5mmrJ6jo6yBGBP3D0qgANFXwFBTXSn4CJbEWNuOiARgADYgjw3/RSv6dJ/wBXNjZZqmzx +7jCsqLMqq9KgE3RTUQ1iIVsMc2mpt4WuCpJay8hOjVkRF+rdESpzNw5GYHBiUJpY/JaUHPqr7q75 +vd/xHtn39w2Z/L+zGMxMg5DGH9R8NlIz9cKwllE5vQY4rFlAH1EH6UfUZcdI45eZXHyWoORleqGm +3Sf2efh46b8gTKUiROSuVEuDjgsPyivTJcIkqtb/ANeemSYEZlOn9TvgvAhiF4YxnOc5znryHyFx +bXV3M1jBJFjQT6SO3UwT93ragBYjdqUFdhqUrYSGKP1tnG+39h0AXK8QlM45Nuj1KkSM1uqhc7NC +oAsgNJkTW6tS6Pe7mY+ApG7kFhL7e3Is9sddN+yOaaP3XdkY7dKxzZhYpVpUNBJHIkwI8wUJ+WtF +y/pOFuK0+P6jv+g0P26LmknpfIadq14dxGYelkBionoBou5xTsBlR4cCjcfVwaBRgWBYz7e/ULd1 +cbaYjuTzqysEH4BcrdGIAeEZmfp/VrZYKRpMTZO+7emN/wBHnqWv8ujMWOYE0ie0DUslTyTHY0kV +ndlsgfVABGFNLOkwER61ZkoGRiCAOfEGMiznGMdN/D8Xz3Iosrc4PDTXFrYwmW4ZF6o4Ix4ySuSA +orsPidhpTPeQW8saSyqpfYLt/WT8NSYwsZYvEwAixY+sPGcZxnGe2fZnHt7Z6b6sAWK/umlR5H+7 +SpXikAYEEa64CC8GmGllg9Y7wwaYXjHmb6WOxWDBBxjIvTwLsHv9THSj8VL6cUTEmNK9IPl1feAq +f3j9746r0oOo0AqPHSbuTd2kez04oTjVoz0ZFbGwE9ZHi0zGxV62akoSJOyB+ntgy0CfuNAynJ0A +G9OM708KVarBJXkZnGM+xf8AKT9vuWz/AHKv+8mZsJouL4qA/h5HjIWa5YFBGrHaqqxckV2Hz1Dv +czMWv4ePGQv/ABganfyppZP0/wA6+jbUGa//1dfHE/8AqsONT/2/9OPzdK56odwRo0mA/cqo5bzk +2QTWz2VMaitfWNv1ZHc7IqKcKwX7W1JKHKwldRsEnTZG2PUmboaeYBSFOYYWWqDkrz88ZDjzu/mY +W+M5H7Y+5HHbTMxvyzE2tvkpLFWDTrZCdVNy0YqVj66LUgfHw30++BSta53HTOhERk+95Hah/SBX +Tbce32ZDjAsY9v1+2fr4z9nP2evlKIZQrFz0kbH47eWumklDmSgP0tT7fmPlpduyUIums9nYVvFV +lVpNimiI0O40HOqWZzULRccfjbnMjpgvsqjHd2OJZHyRLjDSkjsxqzUpi5GlK9A/Aw+OewezHJu3 +fMeyfJ/brzTm7cTyd9yCPK2eUlDyY65kSEQLYZRUBkht4/qkhuUV1jkchkIqdMzMWl9Z5VcvAnrW +4Q1SlTWtQAP9gI8668hdvLeFirCIxrfopsB8vegEb5L9omYml6+huRYyXgIkiBc/yWcORBosZylQ +hJKGHGc+uHv362dn7bO1nEoHzPdv3K8akxQJEVrx9zkLy7Wtaq0ixQwIfDrk6iP9w6Rzcjys5WKw +w0iTvt1MtBT5mp2+zf56XRvFFr4h8Ri003Y3PxMQq5YjlxekkHjbdB4jeURh65I5uMQjsbZE7zIz +VDO4jRqcOLyt9yOPKAnPyHB2c47V9omM413S5Zl+D+1L2wXBykWOmiPKJHe9vMTNMjIt1NK5jgVG +QurRwJ1xq3XHUjeOu4HJMRw/FNl+f85tMZjSTUSsE66U2XxdyfgAaeJoPG46q5K51ccSbydeagfa +gW1GN7k1tJ9pcIGNvk1apm5Y9+/QuKMx4JZJF7oWTgspxbP+zGkzPgecd7A9M7ur7C/9EuVXFj7i +767un5BHFHi/yu0ufXW8eRYwz3MyC1ESlj1RSM0sw3VV8dbLjPcfFcqwyXfBb+1vLCGNXLJMhBjA +3YAN17+YKgjzGqYtDk9ad3OP2zsQKq11Nba2pX06atUolJ5Y0lYtcoDsVGpVKNdbVOMZmlROo4n9 +T5SZBKEb824yAWSxlmYF0+uI+wrm3tb9xHajMctz7ZX25zZKG4yd/HA7RQGJC6WmVtE9QLH6hVPV +KvGSdwDrYXHL4c9h72OBQMuqHp8AzbbBTt9vloEuM6QczlhXBDNbEO1coTWA4vSQiVxSyCYjfOKK +p1ijy5S52dcwUZx6mMK5FISUjRH2w5yAvcTDDj8l+mX5Z79zPtO9nHuE5Zetxvstbx8Y9KSafK2U +dxj4nuXeiwWtelLhlFXkcJ0LsBuTRkpyHkGGtk9TJVlJ2U9L028/hrTQ/wDHXyqzpGNgf+SerYI0 +K/8ARV7/AFXrGlSTPCAX2hw2w+QSpa1IHERec+JmSjQgFn4OeruLfytvaVxnK2mVl41fZAxGvp3N +wzxsf+Ief2awXPcHkl1H6ZuVQf8ACKf0Oj20c44KG0WQyl6hZspsu8rLJQhuLZW2Hb50XJaI28fr +pETu+DLAnZowgUZyJK0N5adARntnwEPGBdd98b45x/huCxvGOJ4O1x3HbROmG3t0Eca/E0HiT5k1 +J+OmjcXM11I007lpT56yEfT/ADrd6T6//9bSvrpS872K/u/+q1HVjYTxVVhWdxX6vxKHz5iWqW1w +YH1x1mrzDeP39EaQsSIXA4GEisZIwG4SnmeOcZ7dXxMqSK7iqDxGjSNGa3dd3rUONaWOsbZOOLev +VQxkkkEqmdtLfCsV5clenZVFXPCXJyMRIbFriwxlHnKXNOeoUK0y8eDvIzGcdfPr3O7Be5bsz7qs +/wBwuW2WR5z2l5I1xZ3lwhkka7xl7VTZTIOr0JLYFREOkRho1IO+pjtc1gb3j8EULJbZCAhlrsaj +x8fKlR86/HTotOthDNq9aqrvtSxFRtznLS5FPzUhPGtY/nLF3hZGpE5RRzGEv5Vh706t5itsUYD3 +GlODjP22M9eV3uL7Vx9k+7/M+21rfficbj7hWgc/S6w3EazRxTKSSk8SuElX/fB8qalTjWVOWxcV +wyEEAbnaoNaH9R3+FNQLcva1z1YDQytgrSZXO82jcCStCatrYltUWFJjZBG3xayhiiJ1VoUS1cnX +sYzBEiNLEMkI+2e/bqS/aR7Zsl7peQcv4RhspDY56DFme0nmDGBZEljDqxUEgFGYHb7xB1quVcmj +4+1tK31RnYgb/Gu39X69AfIOZ95d7OlmtdX6HbiyjZeMICRP9ZGRBkNXQAbiAGETjOlKV8NaGAhM +A3B+S1KksYy8ewOe/XUvI/5W2X7Sw2/Je+ffXiOC4esgrJLOwaZRu0cSU6y7AUXpUmp303o+4QyY +eHD4pnnO1aUA+0701Ye9PHxZu0iyt7sryYsKC1ohSgIG/VtOiD2xqlyg1WklwstExTe9ihb8mfBq +UxwVCdQiUYyV5iL9LAunr/Ll/mTcT9jvIO5fA8/wSfNduM9mxNHfWUqi6thETDE4jZR+It3iCu0Y +ZGO53JGoP9zPtsue/wBx/j5TkL43NY5HeOql4vrHSVkAPVuAPqWp332GkruMAVWlWGq+IDNJJWtx +veybrSNzNTnPVjo2x+OMaU86ao2uHnK1iVrd5IgacIDBIMkoV4MeYgZzny6+kj3nc54fkfaHku+B +xIyPGp7S1yVmsilmW5uEYWsq1LenJEWVj00II3r5cE+1Ow5Jxbvxne2ueHTLj4Z4qhAglUH74YAF +0bcr1VPz09Pi/wBa9Z7emnJJptbtO1zZFExm46ZuqBVLO2NufGaKOdn18qDKJBEG1eEw9g9+d42S +ZlWgETkKgYw+fcWcZ5F9l/Mc5z322cHzXKL9rzNF7qGd3oWbolqqy/FwCK9W5FK+A16B56BbDKMl +unQgQUprQnQusevOrsYPhuu9MV1TcbVn4VuDbAIs1sHyssxjIQrXpYjIC4PS0IM9sHKzTjMB9mBd +uuowAqpGqhY1FAoACj7AAAP0DWiO5LHxOr26u1TXOjRrAH9P86NGv//X188Tv6rLjT/oAab/AJut +c9GjUI5VdDIrvHqTdUMYqjpOabHirCTNFAza2Is2OJkNmKxOLLcchko0R7yyF5MEP0xFjySWoGEw +YBYwLGckMzRNsfpPiPL5Ejzp46CAa1Fa6SnrbtfKtLtcqo1j2B49t6aIf6Prhor0coj9WCvypHR4 +aEQgOMpaLDq9U8HrWp6dhmrseogLMLAP0xB7hznPz2+5r+WB7lOad5Ocd0MDyLBcgxeWycl0V9Vr +a4VHb6IzFIvSSiAISrmpBOwNNTVgOfYqyxkdk4MTJGAa77gAbH/DU00EYFe+XJW37CSOM3DKNd9Q +KWb3mrpTZtezirIit23n766IXl9jrHNGljcZW7watygpyVGCfdW8S0WAdxi79ei/sJ9tmQ7BdveS +XvMeH2+M59kLzoChkkkFmgXoXrSqhWlBc71PnsBpjcsza5i4Uw3PqQgePlX+vy8Ne5tLCJVxMbw3 +ZucUyv8AOdHN+HiOrL/cmRjc3d61g2CjrZhsZLJla5oSOLt+BOatoMp15+Qek0KsYEPsAWM50X8x +H2gX/uh4Jx7NcOuGTuBx31XSKoKXduwq8CqzBBMD9Ubnc7rXcarw3kv5BekSxBreQipNPp8q71r/ +AHeOqjM3Dvrdi10GsXH84w+2H2VNy98sHYZsMUyLWzV6K4M8EKmZSBmJT/PqcOQA5E1xtOsLOUi8 +RqBFk5FnHCftT/lnTcsvYeT92MLf8fwVlKEaCWPovL3xD+nUkQx08Zekk1onx08uSc+nSIQ4+UGV +jWo2AA8QfjXw1NYR/dy7vrOwna2YlvvGnmzZI6LJK+TywNWYjJJAVJngrAXpVH/d5a2NjIhNH5BT +gAnycQVnx9QWe+c+yHLfb7wLmPCsZ22v8nnrft5ZWsdvFjrfITR2pWL7rPGerqkp4mtK708tRXaX +sFnkpsxBi7UZN+qsvpr6lH+8OunUR8N9tNb4++NqTai2fdN/XHsCs2IvS5Y9DIGpkSSCNFZRGK1v +BBqlTLG2OIs61zLMVqHFaM9SsPPMNHnAQh8Q9+7q7Wdq+G9mOJDg/AbGS3wAuZLikkjSyNLIR1Mz +tuSQANqDbw1ZfXs1/P60rHwoB8NNe6kbSLXOjRrnRo1gD+n+dGjX/9BszpvNsRpzxZ8AEW1nTVMr +nOzdSaOU5IPwrxKSzZM2wEeqMTfJI+x1ji9hVyrG8NPuJRnqHKzE4SvIIgYyIIwnHZbfOdxeOdvg +r/i762muGcUpHDA8SMTXzZpQq+QO+9KFs82z54lw/PcoKoRaREqGJAZyp6Aab06hv8RsCK10wTX3 +k2i7a+XjG9v7jrSNvERsluj1bI45T1iwQ90hpcBiDo5SFyEomVroHwC6ZurknSnJFCYsCZIEIwCM +yLOJI5b2+yWKzE1jhMVe3FoirV+kuOoipAYIoNP+Uf36jvtr3cxvJeJY/Ncry+MscvMXrCsoXpVW +IWquxYEihoSfiPGgvdn5ZOPeQO0nYI9slF318hZyJPLGZqYZqrco8e5EDVNhTqkBGvXSjckxYjCP +LH+VAHOQ9+2emonFuRzSTRR4S5aWMgMAjVUkVAP6NSDPzfh1rBbXFxyaxS3mBMbGVArgGhKmtDQ7 +Gngde0Hk90iz5ZNuklIWEPmM9ZDJ8nILBjuIQxjMjGAgCAOM5Fn62Md+sp4fykVJ4/d0pX/pt5fo +1gTuFwSRgqcvxxYmg/jp4nYeeogycvnHTLMOR0M2Wjc4QNLmcyr3mGR6bSZhIdk2A+9t+HtnjSps +PUo8i8Tglmj9IWMhF2zjOOsNrxnkN9G8tnhbmWIEglUJFR4j7R56V5DmPE8VMltkuRWcFwyBgryq +rFTuGAJrQjcHwI0mxXzZbjGKORG43OMVHVOquuE3yyazP07oW0VErtqGp8Oab58vi9yuqEkrWl4U +FoDk3uTSlGAtfgoQRGA7jkDCdt0l4/nMzyBLu2ktUqq9IXrPTWgDKxJ6tvL7dt4j5T3kmi5hwvi3 +C2sL8ZGVxM/WXEcYagNUYBTQFj1E1FNhp18Y5R9HHVqRGq9hY6JWFEhEpcDYbYLA3up5qYAzXBnR +ubAoUAblQ+5hQMmnCAAQQ5GLOPLLEHEuTlQwwF3Qiv8A02/ZqVW55wlCyty3H9QND/Hj/wDdrruv +LXxxMT8yRV420rJtlMmHkEcjCvMiJkT74gOMNNaGQTDhzcUycBAsnHFFCKJ7Y8xB747p345no54b +aTD3AuJK9ClCGanj0jxNNLIeV8YuLO6yEHILR7GEgSSCVCiV8Opq0FfKvjqSD5O9FACwH8YaMjzn +Pb/JsU0H2z38e2fGNZ7Z79KP8o8q/wDzt3/22/ZpH/nzhP8A+rsP++n7dRhq5auPB+VPqNh2biL6 +qi7rhjkqdoZZouOj716AVOGl5KIjIjG9xEmFg3BRmAiyXnAsY8c4znDFxnkE8k0UOFuWkjNGARiV +PwPwOs8vMuJW6273HJbKNJk64y0qAOlSvUhJoy9QIqPMEeWvZT8o+iChxQtwtgGFHlerRoSnF0YJ +k1MiZQvVlIUnyk+OMdStTUQYqUAAI5SaUSX5eQxhDjIsXzcV5JbxSTT4K6SJRUkxtQAeZ28NWQc3 +4ddXEVrbcosJLiQ0VVmQlifAAV3Py1kF+n+daHTo1//R6VZTg+59tuG6DvDkUbVuhnBhq5c7uD3j +OUTDObWoGIpXFxcisdyilaOLNLeMAx4yMJJucByHGftpa7M4m1flk+baFRcQWjKZCASEZvpFfEAP +uQPHz8BrnH3OZmay7dvioH/jX11FEo8z0nqb7f3fnt89GBsrOrqp23+IauYVdMzxY26jrPbb2PrJ +5Vs7pGotRsaZWmTomePRvLSWdGGxUkWuCRKvLOCoOE2GiEIZge+HnxznHI+Qc7NrFcI2ON43SPTS +pjXqNC1KnYDz0wOb9o+3/EO1VxmpsEP8xx41W9QyPX8SwTpNK03YsKUp5aom5DbeZbA2Q2gkW+b7 +pjQIptCqcjSeDVvG5m4y5fXzQc2q5DMHBzjkjeTVZsrfXFuQEJ04sAKSDEYPGPAPUiZaCV8jlszP +nhZ4wOsSUhSSpXxbdGO/gf8Al1DOGOHlxfFuJW3A4s3n0tpLh/VneMQrM3WIkAdEH0hXLMRXrH6b +F1AvAqR4uOdM/IzP9zI3XECMXv8AGJRV7dAWyErj8LXdpkQHRLDIisXrlqGPLk3uwTDislCEMYcZ +CXnpbx24tKZW6i5Gb2OKL6lMCxdJFWr1CNa+G4qdvLWp5nhRAMJj5O2cOFuLi6oJEnEplAopjp6s +lB9XUDQbild9dN5tRDr5WcQrme3YLW0mJaW3JtjIDIY+x2DSW3Ngnd2C+xil4Ee6Na5G7rHaXyZW +NwQtqY1wOKAUMWPSDnGWLznOZrjmKwGNxcQF1NV5D6QkoDufFT4OWNfgR8dSr2u4JxHuHnudZjli +rPjrV1t7ZJJQhKoOhWFHDU6UGx28TrxNOZrdGxGoWlK7Z6RLLFsK+LVHY8nzJ2pCTnFc1+6yuzGB +qWNJCJMkw3koYS0AHgZOcGDXdhd8CD09ONm/yPGsEMlKGurqX1GqgT6VLOo6KClekDw8xXUc80ts +Fxnm3OTxWxS3x2NsvQiEblg00ypCxDkklyJHYUP7p1V+7+31jw7V9daVE7pCM3EsPchRQ9V6nwl7 +ruSqYPViKRusZKkNiVf8lutgIpC5qWkKg1W4CJLFheR6QfDHbMV8g5tyt+YZDHY2IJZLMIowIA1S +WCjcrvuTv4Cmp74h2a7Wp2/wWZz+Phlyb2frTO0/Sekqzmo6vpNKADxro6bSlSuHyuyreXENb5Lt +atTV/wAlP7g3EnDQzm03RQ6uQy1AADNbW45BViU5WAsYAARrBd+xYs56m7IyC2nusk6rJLY48tXp +FS8i1JA3ofoUUH2eeuW8NZDI2mH4/bs0VnlsyoYdQWsMNFFQSB96dh5mqeehQfr+s9DyC6Qa5a97 +tHbUQaY0A4XFuY6xl4rWx66jkvyzuoMQ2LSKANPuMTRkSIKbBCXKwSkok8gI85Mznzh3gHK+W57k +9lbZEdFoWkdx6AX6FWu7dIoKkb+Ouke7fartPwzg2UyWGxEX5qgjjhb1yzeqz0J6QxqekGopTfbR +DmTZC3DjuVd6x7WZp2n3bf0Mou54kUQhZTFVFcoD4k9uqaRzQOIqRI36GUoNO3qFmDcZNXgyDAhZ +xjp581zN1g+MZPK4wKb26vqR0XqNEohoKGqkIDXYbj5ajDtpxDD8x5xiOOclhV8NjcSpkVn6AGkU +yMC1Rv6s1OmtR06GbR+8r92rrfdRJNbMkdiVbLNjzdUNWJJLWZjJcHqJWRK2qk2yRqFbY0NrVLk6 +xdYKNR62ShkDGQZ9QIs460nHuQ5uTgnLsznRVUVki6o1jIPp0rsAWHWR46c/MO3fDLLuz214vw/G +LDLJNHNcdEheipL1A/ePSRGpJ8PnqEfT/OuV9d9a/9JkPGdwsqpZQFA7Zj2mWJW/cLQXQNjs+uj6 +WaHJybavhuo1Nw4uuYdYZ9gFKmFI8omg0atXhsGLJioQgFBMDgzLt4/zPJ8btb+0x0cVbhCpZgSQ +CCD00I+Nd60O/wAKR9zHttgOc3eGus887JYzCWONG6ULgg1cUPUKACm2w0xHajhvdr+3ZrfdeBbR +5qKR1Br4i1zrav3SjmqzYtGYcWc/qHBeWqVWJEXBU8LcyNSABg/YQUPIft/q9YONcqv+LX35hj4o +2ugGALgkDqFCaAjf9XiPM6Xc04Nh+d4eTBZl5Vx7shIjboY+maqK0NBXcim+3w1CK64eNnqzjqqN +M3I0geEZ8ml0pJUSjT+NOS9IomskcpY8NxKluuxnyc1kvLueJKE7BpxBIgl5MGEIez1su83KrKGS +BY7d4i7NRkrQsSxA+VTtqNMl7b+3mVulvJ/xscohjjPpShKiNAik1Rt+kUNKA/AeGv2sTh+2is2B +y+vH3kTYm9mmsddYy5r49pyytr6iQvCUaNYoaFyi+3BOicMEGZwAwZBuA9/aHPVbzvRyi8s7izMF +skUqlWKpQ0Ox/TTaprTRjfbf29xeQsslBLkHuLeRXUSTB1qpqAR0KafEAjUhScV24yROmT/pFIOt +GmTpyRrl2kTPhasGQSAnKxV8n7DoEIVKjw8h+iQUX5Zz4gDj2YUf638rYIJLS0cqKVZKn9f922kT +e1/tp6kskUuSjV2LdKXACipJoP4ZNBXapJ+Z1EXTh42qerAgdiLuRiNkuVeopo3NzOh0vZSo68pZ +23tbc85f0SjYBUrUHpSWcnKMxMoTDJz54zkYRiD0kl7y8qlubO79O3V4OrpAX6aMQdxXyp8fM6Ux +e23t7Hj8jjOq8aK5aIuzS1esJJjIagoR1EE03/QNWF+i22tCZk4rfSuAH59uDvxJkvq9+3bHkcHZ +MBucYx/Gxnt0s/1u5MSCcfZdQNa+n5/H7fn46Qr7X+ABCjZPLFCKEeulKfChiO3yNdQCPcNuyUNn +NnTSPcjY3XFquEUeXhpsPUuJSchhcovF0sXLSxE+OW5BfkmNmpCM5LQnFqhFYz3GcccI081DZd4u +U2lxf3MiwStcGrB12AHgAPCgG29f1nWyyHtw7eX9nhrJVuoI7GNkRo3Ac9bl2ZiysOosa1ULSgpQ +aX5y+V5tjxk6PzjZJp3QrSVy4yUwuuYHGS9R26HYcpVNHMwr3gp+PvKVN7asZI63uDgQJQ3KyRGp +AgEXnz742sPeTll/12lta2kTMhowTdfn8KD4eB1p7j219ubMR3d9c5K5iRwxSScFWp9RBCoreXkd +SrQiFGboMTBUOqm1tYJ4vrhR9bJrhsENaF3ic82dLAKUTW2GFHzavSmxY5KIjIHVef5HjPNNK8cA +wIXTz5f3Jl4ta8dx2DWC4YQH1GkXq+oUHy3PidRx287KLze/5lm+Zpe2LPe1gWJ1SsTFitdnqEUK +q+Bppv8AQfG3K4bYjDPNjNhUd+Ja8kbRMashcRqMFJRZnmLMBX8lyybEJrCsBwnK6Pnq/XaEQlCJ +rRLAYVmp1SotIajibk3dDkfJ8cMVcLDBYlqssS9PX8m+VdzTxIGp84X2Q4VwjM/5hx4u7jMBCqSX +Epk6ARQ9IoACRtXyBIA1le+n+dRzqYdf/9NwtEclB2vnFzxp1lTiWMvF0naF6pv765zOLyaWVzUN +L13r1Xo7ZuWykEUkkOdVjTFycEpG9qRuhDq9OastOkKNH3Dna4XETZq9NtESsKKXlk6eoRRqKl2F +RX4BQasTQVOmlzTl9hwzCnJ3SLNeySLDbW/WI3urh2ASGNirhSaks7L0RqC0hVd9SbWHmstx1loF +e4EIgtcVKoVrIC7SRlrCeV081NZbsnrqS0O9W9mT25ZrS0VrtFXM5w6s6xLk1DFHNQ2Mrq6HLXAI +i88+G/8AqfznH3LXFks7xyfwyhioV9Nn+ttpVYHaqoSEZupgNJrPmVOWf5Mz2OSwzMljDc24/ECZ +bnqD/iY4iIovqtXRkIfpeZQ00cQiRm1FbD5o7XvRfKqs12edYdd3uMzSemSGdyzY6PWLesSrCn5B +J2iVy951ZfKNRMbG3v4o8ncMmL5SIhNF1wVeFRJxxYydnguJ/nH4eV81ZRwMju6CUevGqhqs0ZWg +AIDGrAdBr1Co02Oc91jxAZC1h4Xmp7+OaKKGVrUixnllKFY0uRL1MXVmROmNm9YdPQ4BB+MH94MV +R1uSNsyQ6GXW+tyg4tYtoTdzLJOrHSYXnCbxVlrc61TZjgCbPbSIkCKNDnrnhS4iwSF08DAmBwX3 +GEtI7qaLkmLmijVmAWceo4AqAsYDDrYeCBzuadR8dL8H3Lny1xi7O77b8osrm4dEdpLEm2gZyFYv +cFoz6MZJ6pTCh6QWMY+7o0ZxzGs42awj6O1H2OtpUwn2fGoDKBv2p8RrudTWv3qTwsgzJ0u2pj9i +M0KWTyNGpTVauPJ13uYBKCkpgRFepitOI8jv7SG+s8b120i1U+rCtQCR4NICNwfEDSjL93O3WAy1 +3hM1yMwZK3kCSp+GvJOglVb70du6N9LA/QzDela1GhybuWLcWpXZzl+ztU6+L6CgLk1l2HKKmOk0 +bslwhT3Gm19fbWicKldkzVmb2OmXZxy1uTItdDniVkoXBxbvccENqF53GW4BlcVZ5C+/ExyW9v0n +yVmToDSOB1MB6bHp6SepwrsoFEEjQ4n3+4tynL8fwf5fc29/f+old5I4pvWMdvCz+nGWNwg9QyKn +pwl4o3ZqzPB1WHnor4rduR1HLrR1K/FmIuKS08mmzXO1LU+QhtZ4UllEevGVXGvlrtR8nr6YvJC1 +jE2EgZHJtcwlFlnOBoFpKRqNZQjGRXy5BDdNMyGDpYOFAqJA26sp8/u0OwLGoEqxZm/bkt3g5OPz +LiktUmS+EkZhd2Yq8DR1EkciEVH3+oVZljXpZ7A0u5myLRV5ZdpX6gK2lVj1VrleVCxSMuThFJHJ +YpfxdtGOUGLYZnOZE6WLIasxXSH5QemgtAmV/LZPk2o+wPWy5XFPi/yzqm6/xNnFP93p6fU6voO5 +qV6fvbVr90aS8W5TFyg8lEdmYTjsvc2Bq4f1TbdH8YUVegP17J9fTT77V2p1w5YNkLUQvEwZNbdZ +bMpeVGvn4KoDYQrwbJFHDEthrKugs5mlkx2qLqgc8WOz83rVj3GWuPMSqIsYynFW8DbxmKy3HZcF +yd7i7HJWl9EGmUN0lZQFVm6F+tEcMxNS6gD0l+tj0fUI8zXfLjWD5NneN5PDXRjspDH6qSWhLyJF +60o9CaeFkjCELBKXb8TKTDGgmARrm1O5EbqNvet9dpJqnUMicbZf5TlZZ+tbBc9YKGyv4A9oIlI7 +InNMS+n5ZGIhC4TMH0CMt0dLT9GRoFiZwYS1gVpKUSDknG7jAmNrrKRyo5YRgrMsjhCFc9LIUUKx +2Jlo6UdOoEa3nbzuVY89WaPH8cubaaBYzcMJLSW3hMyNJAvqpMs0jyRr9SragwS9UM4RkJ0/rpra +lHWAP6f50aNf/9QNKeZyIrVOskZKtGGwiP2HrNplauwimS1pRrrK5HVC+mKwiaCnmoFklyic7HMk +nHW4DWiCsbMUBtd1J64xaWM0ssby4zdXojkh9e1t8Qjhrh3SNnkjpX0qOGMinp2RVFGoeonpUwz3 +OxuHF1BfLjspkea3MBhxtvFNdpbQXC9QF3125RLSRRIQ9w8h6kATopUgjtfCCrZRq4jCzakp1Ntz +tZYqxppylWLVpDcsZ07SanXpN49U14QNjrd9E0p2Kx2HKZ3SSVrWLEw3AaIxSAS/ITHFksrNa8dv +chjXtYDeXw6EjS36/wAI0TlY5UVDUBq1DgkE9JO5rH3GeK2mT7iYnj3IocpfjC4JhPPcSZFYTl4r +uAPc2k0kw3aPpKNC6q/R1BfoBWCW0lmGqWs+3NWvFYhNsaU0c8r6tuWSNRt3ispmr2aRYEOp5xhU +qgsmiUSYK3rlGtXLkj4AxC6LEg3QZqhSMPuujw2fxmO43m7BLSOPJNDX1H6ZPVYOOlAjqV6VWtVI +P1ENv4q9uZcE5NyDubwPOzZK5uuMx3/SbeAvbiyjMEnqXDTRSpIZJJSiLIhDBCY6KtQ5GS5n+cWw +NhuRaxlllpGWzxsIK9b2fXhUgn1SJ40noueXY5LtgGGuCClMZmFUSkhaoSqpJjCNlTHtwE5aURZJ +7j5jcY/8NyKO4vLdsmy2Yij9JRMnSImlIkCVZXU/7/0hWSgAoY47N2OdN728ucXib+PjcUuZN3cL +dO9nN1yXUdujWxmKRyQyoQf4ILvIkxZmJYDnAcV4ZJ9nkMrg+mzbJJM9vsgrtZfWsia/p/F7YRzp +mjkxFbsbg0Mlc4a6seYYx5VMaVwCgEoPccKU5qkoZ2AanjEuOtcTdLkpMOvqoTA00Ylk6w9HWUU6 +gvT90bbkGpHg7O6dnn8ryjHzcatuYy/hnEd9FY3T2kDQGFmgezYyJEZmlP8AFf6jRCpCmhMta3aN +1e0ILAsGqNdpraEe1UqKPWU1bawlgjl/2Q5VCJxNqG3tbT5oxyWczZ/2Hg07dka4g4wDmwKoe1tD +maBUmIKwlytrjuQWSZW1ycQurGyKTCQdMkzQ/wDTdK/U5mUtQtVkEao29Nbbi2Wz3b7Nz8TyfGrs +4zOZkXFk1uTJb2cV5/8AIgnKD0oFspRH1KnSkzTyTR/SGJnciiFkOkxZaB1qu2x4Nf8ATez2xUCq ++tYomcrQlzbWVioKkZIqxP0ktQE1jtOUEyFRNSpPWuJ4lSZAnJTsSNRjOCcLLXOyWvGMXc/5hkiy +8L3IRRSWVlboVF/iEhIh07k+CgBBvrT5Lg0eS7qcnx/+nltdcRvbfHNPI1bW1jki9eSWT/x+h5rp +/V+kLVWdmadxSurCjSe0tiaXYZLPrGsiVO0J1E48b/QQZuUxBniM+uexzdjJM8z6WFpoUF9VOa+S +1CyHosN7k2NpI0w+6cZYxg6wcyzmXntcHZT3rta3GMtppFIUB5SWYuT01BJVTsQNvDS7s3wriFll +OcZmxwsUeUx/JslZW8oaQtDbIsSLCAZCpCrI4q6s/wBW7VoQNNGWvTsd1WsNyuOH6x2k5M1hzSxq +7q+c1ufYdhpppOFgZBbiJNUI47MZilYYfHo0sEqem9CmEqG1GmKgAJwnyY4cFeYjF8Trk/wU8KuW +iEqdTl5SC49Mh2AAFOpQKlTUAAVYXOcPy7lHdj0+N/ndheTwiK7a1n9KJYrVCsJNyrwxl2ZgfSkY +hRIOgli1HNceUnscnemKybVjXqGzbU+GtEq1WeZ1UDcjjVTwlushVS97zqXMskYSiK1eFsQeGtOF +Q3spRpS1Q5qCxqAuRKgnrRdwL3GXN1FY2M0CpZVVI4kPSwlEbsQygRDpNTRa1JIP1V09uwWI5Njs +Vd5rO2t9LNmCryz3UymVGtTcQxqY5GN03WvSoMgHSoUrWMqdawuo710PrAH9P86NGv/V0tcZuptR +zbja42Je/RSOuMgHopqC7Euy9jblrkkUqqBr1aIaRwUJzFabITzMix4DD2F7ce3qlB4030AkAgE0 +OmjsVJ1fHye7dBIejcRANCoeUUYZEbuf7x295ya6J0Ja03KjIe5mRGZyP9936KCtab6qWYihY01V +kk1Jq6UK1QnVlRK25wSLm5ybVCcs1I4NzmSYmXoFiYeBEqEaxKeMswseMhGAecZx2z26rqmqzzTm +rOpFdKq7rmuoZVEFdnZRInONwxiQsLQ4v69KiQq3pckRhJJVuapE2piRHGeQ/RILL+CAOMDMzGrM +S3zNdWJHHEgSKNVQeQAA3NTsKDc7n4nfSpl3Jjpg03FtBVcVrRDNc0vr+TbyKa1UvdZ9ILVmjKTM +vnNVDpFayrOYP0Kb60MjJIX2ULlC9rj5TgA1wJRFAwIy4JsD5E6oZR9S1qAP6fZq9K93S0gsDWGt +9i7aiBdNI18AqubOIr2r6VRmMQ9xtFCmcm9jry6rYriu4nbjQjfDfdgPsWGe3KxmJjw+nhal9WhX +6qUqdXLL9HVUqCN/h/joQZbzG6ZRi8JOy15HKUlkcjLzrAcpuZNstW0ESSxkuOZuMSs6QNiBdGFp +ktcNZERKJ0dWtE5uC9U3LBnDC2Jkp6jF3QaV89YzOoJSoIFPP4+Ovcund3jT06iR7nTuqTlK4PZ7 +G42dKJXqZAK/WwhUljyAhbHJVZMnFK42gQsj8jlZ5rWvKAvT4ShWmlg7Y8DT6nI6m3GwqT4fAfIf +DRWOEExxABiWPSAKk+LGlKk+ZNSab6/XV3ebWWYqI09yvQO8tYZk718smrrM7Iq6KfghUHH/ACZg +cdh1zCDH5LPD5E1u4VSQ0+MtWFyMhQIRYAlh9S0oF32rq9ZWcBSGAp5+GoA7/wB4zgNMyoyvmrWK +s4zAipHdjQwSdRa1uw1gOBU8rd403HLmOE6OTNDl5tQ1uKNby48pkba2mqgFPLk35AMzFyxbbH+n +9erHnofqHx3qfLb4ft047jA5E2TkmpCSXE0xKLQBXGJemhz9Bo/N57PXWJO58SjsqNY5m9TCjKWY +fnOjIkAMGBjRsoYhFeAy3Yw0RqcijL0mmro5PUFaayWfT/OrdZNf/9bXzxO/qsuNP+gBpv8Am61z +0aNH/wBGjXOjRpMHKE2TBc1J8sQVGQABjy9Aw3H78OcYyEPs+2xno0ax6yCu7OIufY494c9hbFl8 +mhEKrOqXRjh9kCYXueu8py/JqnmjLW62HESyrm2LiyxqFzg4AaEyR7OEoPyPBuScw8F8NJHQ9T7s +TTb9m2iKT1xepFFWRXUg17uZhmcbsvMzX6ySlAtk1Z1pHp6oIJp+o6Mm04k0nYJfWcFhUQblpwiV +QxR1QsMJMK94BjAqNQsCG2+OskWyMChqPL+ylf6DUO10499imq4NgZXDa/iU+ueqquqe3GOG2LXL +Udr9bqabOMuBcWvkaMfImbEj5QlYWtrAxOifKNc2rk2DDfDCzOB3dQpWu2sYiYOxoC4oflv4jV53 +9r442PDim4eqc5bbHmREVZUlYwNjouRWRXcZJc/lA2GYkkoUMMRjbWQxlGJFBbSuKE3mqxkIzQGY +94xjU0bZttZWXqQfRv8Ao1VTCzzO0I7O8OevMVpeSwKT/NOFxkWmTHQM/j8TRpzGMl9c7GQIFbZY +jk9GFqkxx7U4HgASV5Gmn+8ZNMq5puG/Xoi3qSoDD5U/XpUcN1RsSVqm9sf4NYcekcwxFDi3x4hl +ku2W0crdXzHzxeUsThcwUuceam9OlNeE5uSXxOE4QiiBmfa5y13qp0m9OtOoHqp8/n/hXz1uC/u7 +eup2tmuGx0PVuklf1S/aWTqgSV8ryeVg1StpaoRCI6wSmHxayIrGJWmjr6ztRJwRKPevI/JnYwOO +xQMMhqQfkNKIF6Qw+ekH/T/OrNZ9f//XHvU78ljWn9t9/J/pv8k78lj+TqOfk0/+n/8A8m/7ue59 +GjRAf8/50aNc/wCf86NGqEuf7i//AHBfvP5Z/uL6uP8AAPRo0NsV/wBsl/td/wAIX3q/7Z+Fn4v+ +N9n93o0atmWfcyT9tI+D/wCLPub4YPuT+L/j7dGjUjh/3MP9tr+Eb95/3N8EHw/438L9zt0aNUy5 +ff4X+2C/dH/eX3+fVD8X/rH+Pt0aNSO1viEX7ZR8QX/Kt8R+8+4v8x/B/wCjo0aiVY/fGT+19/dQ +v5Mfvj+t8T/rX2ejRo/CPiCf2/f4ov4j4j4GPif81/B/c6NGkDf/AH/fr/v8P/n+6NGv/9k= + +------=_NextPart_000_0003_01CB9D0D.783DE8D0 +Content-Type: image/jpeg; + name="3Q_90-130.jpg" +Content-Transfer-Encoding: base64 +Content-Location: http://images.csdn.net/20101123/3Q_90-130.jpg + +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 +Kfyxf8//2Q== + +------=_NextPart_000_0003_01CB9D0D.783DE8D0 +Content-Type: image/jpeg; + name="AdobeMax2010.jpg" +Content-Transfer-Encoding: base64 +Content-Location: http://images.csdn.net/20101110/AdobeMax2010.jpg + +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 + +------=_NextPart_000_0003_01CB9D0D.783DE8D0 +Content-Type: image/jpeg; + name="735_90_annie.jpg" +Content-Transfer-Encoding: base64 +Content-Location: http://info-database.csdn.net/Upload/2010-12-10/735_90_annie.jpg + +/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/sABFEdWNreQABAAQAAABGAAD/4QMpaHR0cDov +L25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENl +aGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4 +OnhtcHRrPSJBZG9iZSBYTVAgQ29yZSA1LjAtYzA2MCA2MS4xMzQ3NzcsIDIwMTAvMDIvMTItMTc6 +MzI6MDAgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5 +OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHht +bG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIgeG1sbnM6eG1wTU09Imh0dHA6 +Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUu +Y29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIFBo +b3Rvc2hvcCBDUzUgV2luZG93cyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo5MTJGRkJGRkQ0 +REMxMURGOTA4RkU3QzE4M0JGRjI4MyIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo5MTJGRkMw +MEQ0REMxMURGOTA4RkU3QzE4M0JGRjI4MyI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0 +YW5jZUlEPSJ4bXAuaWlkOjkxMkZGQkZERDREQzExREY5MDhGRTdDMTgzQkZGMjgzIiBzdFJlZjpk +b2N1bWVudElEPSJ4bXAuZGlkOjkxMkZGQkZFRDREQzExREY5MDhGRTdDMTgzQkZGMjgzIi8+IDwv +cmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJy +Ij8+/+IMWElDQ19QUk9GSUxFAAEBAAAMSExpbm8CEAAAbW50clJHQiBYWVogB84AAgAJAAYAMQAA +YWNzcE1TRlQAAAAASUVDIHNSR0IAAAAAAAAAAAAAAAAAAPbWAAEAAAAA0y1IUCAgAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARY3BydAAAAVAAAAAzZGVzYwAA +AYQAAABsd3RwdAAAAfAAAAAUYmtwdAAAAgQAAAAUclhZWgAAAhgAAAAUZ1hZWgAAAiwAAAAUYlhZ +WgAAAkAAAAAUZG1uZAAAAlQAAABwZG1kZAAAAsQAAACIdnVlZAAAA0wAAACGdmlldwAAA9QAAAAk +bHVtaQAAA/gAAAAUbWVhcwAABAwAAAAkdGVjaAAABDAAAAAMclRSQwAABDwAAAgMZ1RSQwAABDwA +AAgMYlRSQwAABDwAAAgMdGV4dAAAAABDb3B5cmlnaHQgKGMpIDE5OTggSGV3bGV0dC1QYWNrYXJk +IENvbXBhbnkAAGRlc2MAAAAAAAAAEnNSR0IgSUVDNjE5NjYtMi4xAAAAAAAAAAAAAAASc1JHQiBJ +RUM2MTk2Ni0yLjEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAFhZWiAAAAAAAADzUQABAAAAARbMWFlaIAAAAAAAAAAAAAAAAAAAAABYWVogAAAAAAAAb6IA +ADj1AAADkFhZWiAAAAAAAABimQAAt4UAABjaWFlaIAAAAAAAACSgAAAPhAAAts9kZXNjAAAAAAAA +ABZJRUMgaHR0cDovL3d3dy5pZWMuY2gAAAAAAAAAAAAAABZJRUMgaHR0cDovL3d3dy5pZWMuY2gA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZGVzYwAAAAAAAAAu +SUVDIDYxOTY2LTIuMSBEZWZhdWx0IFJHQiBjb2xvdXIgc3BhY2UgLSBzUkdCAAAAAAAAAAAAAAAu +SUVDIDYxOTY2LTIuMSBEZWZhdWx0IFJHQiBjb2xvdXIgc3BhY2UgLSBzUkdCAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAGRlc2MAAAAAAAAALFJlZmVyZW5jZSBWaWV3aW5nIENvbmRpdGlvbiBpbiBJRUM2 +MTk2Ni0yLjEAAAAAAAAAAAAAACxSZWZlcmVuY2UgVmlld2luZyBDb25kaXRpb24gaW4gSUVDNjE5 +NjYtMi4xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB2aWV3AAAAAAATpP4AFF8uABDPFAAD7cwA +BBMLAANcngAAAAFYWVogAAAAAABMCVYAUAAAAFcf521lYXMAAAAAAAAAAQAAAAAAAAAAAAAAAAAA +AAAAAAKPAAAAAnNpZyAAAAAAQ1JUIGN1cnYAAAAAAAAEAAAAAAUACgAPABQAGQAeACMAKAAtADIA +NwA7AEAARQBKAE8AVABZAF4AYwBoAG0AcgB3AHwAgQCGAIsAkACVAJoAnwCkAKkArgCyALcAvADB +AMYAywDQANUA2wDgAOUA6wDwAPYA+wEBAQcBDQETARkBHwElASsBMgE4AT4BRQFMAVIBWQFgAWcB +bgF1AXwBgwGLAZIBmgGhAakBsQG5AcEByQHRAdkB4QHpAfIB+gIDAgwCFAIdAiYCLwI4AkECSwJU +Al0CZwJxAnoChAKOApgCogKsArYCwQLLAtUC4ALrAvUDAAMLAxYDIQMtAzgDQwNPA1oDZgNyA34D +igOWA6IDrgO6A8cD0wPgA+wD+QQGBBMEIAQtBDsESARVBGMEcQR+BIwEmgSoBLYExATTBOEE8AT+ +BQ0FHAUrBToFSQVYBWcFdwWGBZYFpgW1BcUF1QXlBfYGBgYWBicGNwZIBlkGagZ7BowGnQavBsAG +0QbjBvUHBwcZBysHPQdPB2EHdAeGB5kHrAe/B9IH5Qf4CAsIHwgyCEYIWghuCIIIlgiqCL4I0gjn +CPsJEAklCToJTwlkCXkJjwmkCboJzwnlCfsKEQonCj0KVApqCoEKmAquCsUK3ArzCwsLIgs5C1EL +aQuAC5gLsAvIC+EL+QwSDCoMQwxcDHUMjgynDMAM2QzzDQ0NJg1ADVoNdA2ODakNww3eDfgOEw4u +DkkOZA5/DpsOtg7SDu4PCQ8lD0EPXg96D5YPsw/PD+wQCRAmEEMQYRB+EJsQuRDXEPURExExEU8R +bRGMEaoRyRHoEgcSJhJFEmQShBKjEsMS4xMDEyMTQxNjE4MTpBPFE+UUBhQnFEkUahSLFK0UzhTw +FRIVNBVWFXgVmxW9FeAWAxYmFkkWbBaPFrIW1hb6Fx0XQRdlF4kXrhfSF/cYGxhAGGUYihivGNUY ++hkgGUUZaxmRGbcZ3RoEGioaURp3Gp4axRrsGxQbOxtjG4obshvaHAIcKhxSHHscoxzMHPUdHh1H +HXAdmR3DHeweFh5AHmoelB6+HukfEx8+H2kflB+/H+ogFSBBIGwgmCDEIPAhHCFIIXUhoSHOIfsi +JyJVIoIiryLdIwojOCNmI5QjwiPwJB8kTSR8JKsk2iUJJTglaCWXJccl9yYnJlcmhya3JugnGCdJ +J3onqyfcKA0oPyhxKKIo1CkGKTgpaymdKdAqAio1KmgqmyrPKwIrNitpK50r0SwFLDksbiyiLNct +DC1BLXYtqy3hLhYuTC6CLrcu7i8kL1ovkS/HL/4wNTBsMKQw2zESMUoxgjG6MfIyKjJjMpsy1DMN +M0YzfzO4M/E0KzRlNJ402DUTNU01hzXCNf02NzZyNq426TckN2A3nDfXOBQ4UDiMOMg5BTlCOX85 +vDn5OjY6dDqyOu87LTtrO6o76DwnPGU8pDzjPSI9YT2hPeA+ID5gPqA+4D8hP2E/oj/iQCNAZECm +QOdBKUFqQaxB7kIwQnJCtUL3QzpDfUPARANER0SKRM5FEkVVRZpF3kYiRmdGq0bwRzVHe0fASAVI +S0iRSNdJHUljSalJ8Eo3Sn1KxEsMS1NLmkviTCpMcky6TQJNSk2TTdxOJU5uTrdPAE9JT5NP3VAn +UHFQu1EGUVBRm1HmUjFSfFLHUxNTX1OqU/ZUQlSPVNtVKFV1VcJWD1ZcVqlW91dEV5JX4FgvWH1Y +y1kaWWlZuFoHWlZaplr1W0VblVvlXDVchlzWXSddeF3JXhpebF69Xw9fYV+zYAVgV2CqYPxhT2Gi +YfViSWKcYvBjQ2OXY+tkQGSUZOllPWWSZedmPWaSZuhnPWeTZ+loP2iWaOxpQ2maafFqSGqfavdr +T2una/9sV2yvbQhtYG25bhJua27Ebx5veG/RcCtwhnDgcTpxlXHwcktypnMBc11zuHQUdHB0zHUo +dYV14XY+dpt2+HdWd7N4EXhueMx5KnmJeed6RnqlewR7Y3vCfCF8gXzhfUF9oX4BfmJ+wn8jf4R/ +5YBHgKiBCoFrgc2CMIKSgvSDV4O6hB2EgITjhUeFq4YOhnKG14c7h5+IBIhpiM6JM4mZif6KZIrK +izCLlov8jGOMyo0xjZiN/45mjs6PNo+ekAaQbpDWkT+RqJIRknqS45NNk7aUIJSKlPSVX5XJljSW +n5cKl3WX4JhMmLiZJJmQmfyaaJrVm0Kbr5wcnImc951kndKeQJ6unx2fi5/6oGmg2KFHobaiJqKW +owajdqPmpFakx6U4pammGqaLpv2nbqfgqFKoxKk3qamqHKqPqwKrdavprFys0K1ErbiuLa6hrxav +i7AAsHWw6rFgsdayS7LCszizrrQltJy1E7WKtgG2ebbwt2i34LhZuNG5SrnCuju6tbsuu6e8Ibyb +vRW9j74KvoS+/796v/XAcMDswWfB48JfwtvDWMPUxFHEzsVLxcjGRsbDx0HHv8g9yLzJOsm5yjjK +t8s2y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo +2WzZ8dp22vvbgNwF3IrdEN2W3hzeot8p36/gNuC94UThzOJT4tvjY+Pr5HPk/OWE5g3mlucf56no +Mui86Ubp0Opb6uXrcOv77IbtEe2c7ijutO9A78zwWPDl8XLx//KM8xnzp/Q09ML1UPXe9m32+/eK ++Bn4qPk4+cf6V/rn+3f8B/yY/Sn9uv5L/tz/bf///+4AJkFkb2JlAGTAAAAAAQMAFQQDBgoNAAAg +pAAALMEAAD4fAABXqf/bAIQABAMDAwMDBAMDBAYEAwQGBwUEBAUHCAYGBwYGCAoICQkJCQgKCgwM +DAwMCgwMDQ0MDBERERERFBQUFBQUFBQUFAEEBQUIBwgPCgoPFA4ODhQUFBQUFBQUFBQUFBQUFBQU +FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQU/8IAEQgAWgLfAwERAAIRAQMRAf/EAP4A +AQACAwEBAAAAAAAAAAAAAAEAAgQFBgMHAQEBAAMBAQEAAAAAAAAAAAAAAQMEBQIGBxAAAgICAQID +BgUDBAMAAAAAAgMBBAAFERITECEUUDEiMjMVMHA0NQZBQkMgI0Q2YBYmEQACAQIEAwQFCAgEBwAA +AAABAgMAESESQgQxQRNRYXEiEIGxMhRQkcFysiNzBXCh0VKCM0M04aKjJPBiwlODwxUSAAIBBAAE +BgIBAwUAAAAAAAABERAhMQJBURIiIFBhcYEycPChMGCRseFCEyMTAQACAQMDAgYDAQEBAQAAAAEA +ESExQVEQYZFxgSAw8KGxwUDR4VDxYHD/2gAMAwEAAhEDEQAAAcT7T8ulijYxEsihaCQhCEqClkkS +hYWeVGJVVFgEIsRBYSIBCLCIKLCQpVS0lFgQKKyQUFrLV6FFAWQBKKElCCRGAFq9VUlqsWsEootZ +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 + +------=_NextPart_000_0003_01CB9D0D.783DE8D0 +Content-Type: application/octet-stream; + name="gmlog.php?bannerid=5433&clientid=1703&zf=&zoneid=407&source=&block=0&capping=0&cb=bca7d4f1878bf2aa6bb2984aeee164cc" +Content-Transfer-Encoding: base64 +Content-Location: http://z.csdn.net/gmlog.php?bannerid=5433&clientid=1703&zf=&zoneid=407&source=&block=0&capping=0&cb=bca7d4f1878bf2aa6bb2984aeee164cc + +R0lGODlhAQABAIAAAAQCBAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw== + +------=_NextPart_000_0003_01CB9D0D.783DE8D0 +Content-Type: image/gif; + name="210_90_1103.gif" +Content-Transfer-Encoding: base64 +Content-Location: http://info-database.csdn.net/Upload/2010-12-03/210_90_1103.gif + +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 +8zTol0VwnTVN1Efaeg3OEYewKhAEADs= + +------=_NextPart_000_0003_01CB9D0D.783DE8D0 +Content-Type: application/octet-stream; + name="gmlog.php?bannerid=5400&clientid=1699&zf=&zoneid=408&source=&block=0&capping=0&cb=3ce2e046162dc42f73f84731afbba771" +Content-Transfer-Encoding: base64 +Content-Location: http://z.csdn.net/gmlog.php?bannerid=5400&clientid=1699&zf=&zoneid=408&source=&block=0&capping=0&cb=3ce2e046162dc42f73f84731afbba771 + +R0lGODlhAQABAIAAAAQCBAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw== + +------=_NextPart_000_0003_01CB9D0D.783DE8D0 +Content-Type: image/jpeg; + name="1_azurechina.jpg" +Content-Transfer-Encoding: base64 +Content-Location: http://avatar.csdn.net/6/A/6/1_azurechina.jpg + +/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcU +FhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSgBBwcHCggKEwoKEygaFhooKCgoKCgoKCgo +KCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKP/AABEIALQAtAMBEQACEQED +EQH/xAGiAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgsQAAIBAwMCBAMFBQQEAAABfQECAwAE +EQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZH +SElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1 +tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5+gEAAwEBAQEBAQEBAQAA +AAAAAAECAwQFBgcICQoLEQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGh +scEJIzNS8BVictEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlq +c3R1dnd4eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV +1tfY2dri4+Tl5ufo6ery8/T19vf4+fr/2gAMAwEAAhEDEQA/ANuvpT5EKAK93eW9ombiVI+M47n8 +KEm9gM99egziCKWT34AP9f0rRUpGc6kVuwi1hifns3x/stk/rih0mZ+2p9y9BeRTAbSUJOMMMHP9 +fwrNpotTT2LGaB3HZoLuFAwoAKACgAoAKACgAoAKACgAoAKACgAoA8c/aG/5gH/bx/7TrzMx+z8/ +0PXyr7fy/U9jr0zyAoJbOf1uL7XqEa9UiX9Tz/LFdFLRXOTEVeiLFnpwxwKHM5dzUh0skfdrJ1Bq +DZKukncA64Q/eyO3ek6isaRpy5kR5B3ybSEzxjtUJHS521YDnlCHHqKZSncXNBaZDc3lvaj9/NHH +6Ank/hQk3saXFs7uG8i82Bspz1GKGmnZgT0AFABQAUAFABQAUAFABQAUAFAHjn7Q3/MA/wC3j/2n +XmZj9n5/oevlX2/l+p7HXpnkDHPHXGeM0GU2U7WAzzvJj75zWrdlY85vndzr9K0jcASK5KlWx20M +Nfc6S20cY+7XK6p6UMKZni2FdO0snpJKfLX+v6VdGfOzLE01SjcyrTSWOkQMRzJmT8+n6AVt7X3m +c08O3TRi6hp5jJyOneumE7nBODgzndShlwcM/wCdbQsJVJLqcZq0U24hC/PGBxmuqFjupVLnoeh2 +os9MghA+4MH3I6n88mvPm7u5u92aFSAUAFABQAUAFABQAUAFABQAUAeOftDf8wD/ALeP/adeZmP2 +fn+h6+Vfb+X6nsdemeMyvMJJH2RK7vjooz14/lmqVlqzCrdqyLNjcWtlhp5Q5H8MP70/jtzj8amb +b2M4Ydwd56HQ2HjTSrcgTW2ooP732fI/TmuWeHqPZo9GliKUNGdt4e1zSdaBGl3sU0ijLRdJF+qH +kVxVaVSn8aPVpTjUXuM5Px2zaj4ltNMhP+rwn/An/wDrYrpw/uU3NnlY/wDe140Edbc2UccKRoPk +UYH0FcymehUpKxymtWYweK7aUzyMTSOG1SHBNd8GeU0c39l3ajG2P9Wd/wCPb9cVtN+6deFevodZ +GojiRR0AxXKdkNh9IYUAFABQAUAFABQAUAFABQAUAeOftDf8wD/t4/8AadeZmP2fn+h7GV/b+X6n +sLV6Z4jKd55rSCERRlDgnzG49jgdfxxVQV9TKdVQ0ubWj6N9rI+0XL/SJQg/XNZVJ8myCko1DpoP +BVnNH8lzcA/7WD/hXG8TJHbDLoz6sy9a8CXNsgvLWcb4cus0chjkjx3DDp/Krhioy92SIeBrUP3l +JmdoGtwWfiKLUNba4lBzumEe/BxjLgc4+grSrSbp8tMwweIi8R7Wqz1eG7ttQtRPZTxXED9JI2BB +rzbODsz6BtNXRz+tKNhrqpHm4lHn+sLmUgDJPpXpU9jwqi1MWK0YXUe8AHdvYZ5AA4BHbJIP/Aaq +c77HTh6bpxd92a1ZnShKZQtIAoAKACgAoAKACgAoAKACgDxz9ob/AJgH/bx/7TrzMx+z8/0PXyr7 +fy/U9iavTPFkZsd0J7t5QeCcD6DgVuoWVjzKjvJs63QJgGAzXHVR1Yadmd5pswIHNedUR71GZW8d +3v2fw1OqHmciL8+T+gNPDwvUDG1eSg7dTnPD3hOHU/DYuJGMVzJIxjbttHHP4g1vVxDhUsjhw+XR +rUE3uzGufDmr6LcvLaLKCeslpJ976gdfxFbqtTqKzMfq2IofAypdavreNs019/4CA/rtqoU6fQTq +VvtmLcySyktdfaH9fOl2Ifqi/wBRXQodjJ1eTql6F6GJYokVAicchVwB7Vne5aJHYRxl3OAoyaNj +VI+e/htqc9x8RbOWe5lMcjTOwaQ4/wBW5rxsNNusmz6DGU0qDSXYdo+syav8TP7QeaZbRZ5LsqGO +BHGpYcfRBTjU56/N0HUpKnhuTrt9533h3xJ4d0LwtPq0J1EQXFwQsd0wkllYD+HnGOa66VWlTp86 +ucFWhWrVVTdtDT0b4h6TqemaleeVcQSWKGWSBwNzL6jt14rSniozi32MqmBqQml3GW/xL0Ce2mnE +kyrBCJZAyDOScCMc8t9OPeksbSauN5fWTsSeE/H+m+IbyW08qazuVQyKs+MMo5JB+nNOjio1HbYW +IwVSir7mc3xS0/zjINNv20wTeSb4L+7z9P19az+uxvtp3L/s6Vt1fsbXizxtpnhzyElEt1dToHjh +gOSUPQk+la1cTGiY4fB1K+2iOb8Q/Euwn8Hzz6YZ476fdAIzjdC2PvnnpzwR3rGpjIuleO51Usvl +Graexwmn+Lxpek6RZaZLqUEi3BuNQk3DM2ccLz0wO9cir8kUoX8zunhvaSlOdvI9m17xA2n2tlLD +EQ91GZcSR79oABwRkc/OO/Y16k6tkvM8SnR520+h5t8drg3dj4anZdhcXGVznB/dg8/XNcGOd1F+ +v6HpZauVzXp+p6zr12LPTJXzgkYH1NexTV5JHhyMPSboECumaPMqKzOs0u82uDmuapC44Ts7naaV +qYwOa4alI9WjiCl40vWvTZWcfJJzj1J4FFGPJdjxlR1VCmjrbS4is7GC2jPyRRhB74Fczg27noqq +oJJdCjqGpgIea0p0jmq4hHF6xqHmE813U6djxq1XnZzDyCe8jQ9M5P0HNdL0jcypQ55JGouTyepr +A9FGP40vPsPhHV7jOCtrIB9SMD9TWNZ2ptnVho89WCPnlrKfTdI0S+sy63d99oUEdSvEeB+bfnXi +8jglJdT6LmU3KL6Gvaaeuh6h4oXILWFgbcn/AKaybIzj8S1aqHI5eSMpVPaqn5sv+GrNW8TeCbG/ +x9mFsbkK3QszyMP5IPwqqUf3lNT2M8RP91UlDfY3vH114ck0TX77RAH1OaSO1uZh5gHLAkc8H/V9 +q2rulyycdznwsKynGFTbdf18zG17w7Y2Gp+CtNaGOMXKxvdzHrIzOMgn9PxrKpSjF04m9KvOaqy7 +bG34lutIl+JUl1d38dvaafafZpwkTMW3K4P3QQMeYBz34rWo6ft7t6IxpQqLDWSu2zEaLUvB2m2N +za3lpq/hm/nBEMsIKuf9xxwcDqPSs7SoJNO8WbXjiJNNWkjd8IiC7+K3iG81AxxNYK6QK2AI0Q7c +j0wo/WtKVniJOfQwr3jhoqHU4+eQz6B4rvYFxbalqUUMA6ZO95P5Y/OuZv8AdyfdnYo2qU4PdL/g +Hbz20TfFvQdPJUR6ZYKuPcIcfzFdjivrEY9kcCk/qs5d2ek39jb3yILhX+TOCrFCM8EZHY13OCe5 +5sJuGx5F+0BEkEXhyKFQkUazoqr0AHl15uYK3L8/0PWytuXO35fqd54wt7vUJre1t1fYPnJCk/8A +1vzxXt0ZqF2zxeo7TNCmgQGZXf6yhD+QDfzonWb2JlSpvc1khmh/1cKn/tv/APY1nz9zB4en0uW7 +XU/KkCSCSKQ9BIMZ+h6H86lpMxdOUNUajz7dVM0h5tl4HuOP5nP4VildW7nS58ju+hYfW2I61fsT +F4lmZeamZBy1aKnYxnUbMO9vhg5NbQgRuVtEk+0XMj+p2D+Z/p+dKvpZHZh6dotm2by2E3km4iEu +cbdwzn0rm51sdag7XsVPEWjw69o9xp11LLHBNjcYiAeCD3+lTUpqpHkZrSqujJTRj/8ACFaUo0My +PNs0bJhDMMNznLceozWX1aPueRr9aqe//fMDUdI8GGTV47zxDGsmozCWf/SY8ggk4HHAyf0FYzp0 +dbz3OiFXE+61HbyHa7pvgrxBZ6daf25awyWcQhiliuI92wDoc9adSNCokufYKU8TRblybmu3gLRL +jw9a6XE8ws45hcFonGZmxjJOOeK0+q03FR6GX12qpuo9zR8W+FdP8UWcUF75kUkJzFNF95fUfStK +1GNVWZlh8TKg7or6P4H0bTNFu9NWN50vF2XEkp+d/TntjqKiGGpwi4dyqmMq1JqfYxdG+FunadqU +NzNfXV5DBJ5kNvIAFB6jPr+lZQwUIO7dzepmM5xslYu+J/h3pOv6qdQkmubWaQYmEJGJPz71pVwc +akuczoY6pRjybmheeC9Jn03TbBVlgtbGYTIkZHzv/t5HNU8NGSUOxnDF1Iyc+rDUvBumX/ie212Q +zLeQsr7VYbGK9MjFOVCM5qp1COKnCk6S2Olrc5jxz9ob/mAf9vH/ALTrzMx+z8/0PXyr7fy/U9jr +0zyAoAbighoa6Bhh1BHoaCbDJ1aRMKcZOSe9C0ZnOnzqxWeyvm/49Qlx7KwD/kefyrT2seuhh9Vq +PbUzL+HVociTTryP/eiIrSFSk9mP6nV6owriO+nk8tIjk9h8/wDLOPxrZTijeGH5NzpPDWmy2Vvm +4z5pzwff/wDUPyrlqz53obLaxnzeHLiTU3mBiKEFMkDod/z+u/5+nQ4z1xjidJ3udirLlsT+OPFt +r4V00TSjzbuXIggz94+p9AKeIrqir9RYbDOvKy2Mnwj8LvG/xWjj1PxHqB0XQZfmhj2HMi+qRZ6f +7TH6Zrx6tepU+JnvUcPTor3Eep6X+zF4FtYyLyXV75j3luAmPoEUVkbj9S/Zj8BXUe21OrWTf3or +kN/6GDQB5h4v+DvjT4bCXVfBeoyavpMWXkttv7xV75j6OPdefYVrTrSpv3GY1aFOsvfRP4A8Z23i +qxYFVg1GEfvoc8f7y+38q9fD4hVl5nhYvCug/I62uk5AoAKACgAoAKAPHP2hv+YB/wBvH/tOvMzH +7Pz/AEPXyr7fy/U9jr0zyAoAKACgLBQKw3FAcgrKp+8BQFiKeaG0t5Jp3jigjGWZjgAe9JtLVlKF +3ZHner/FvSba48rTbWe/KnG8Hy1P0zyfyriljqaeiuejTy2o1ebsZt18V7+5VLbSvD8ov5nCRK7G +TJ9AoAJNZSx+miN4ZZr77Ot+Hvwk8YeK/Hmma78RdM+y6RbgSGOZ0Bl28pH5YJIGeTkDjNcNSrKo +7yPQpUY0lywPrsKFAAGAOgFZmo6gAoAKAPiz416VbfDf46WupWI+z6ZqSC6kjjHChiVlAA7ZG7Hv +WtCp7OakY4ml7ak4Fpfir4YMm0z3IH94wHH+Nep9dpHi/wBnVjptD8RaTrik6XfQzkfMVBww+qnm +t6dWNT4Gc1SjUo/GjVrUyCgAoAKAPHP2hv8AmAf9vH/tOvMzH7Pz/Q9fKvt/L9T2OvTPICgBpIAy +TgepoGNE0ROBIh+hpXQWZxXiT4m6Do7vDA7X9ypwVt/uA+79PyzXLUxlOGi1O2ll9Wpq9EYll8Rf +EmrfNong+7uk65iSWb/0Fa5nmD6I6llcesxsnxR1LS5hH4h8M3Npk4+bfGfycU1mHdCnlfaRUfUL +r4teN9H8MaLJNaadcMDL5ijIwCzucHnAHAz1rHE4n2ui2OnB4T2Gstz678C/DXwr4HtFi0PS4RP/ +AB3UwEk8h93PT6DA9q4zuOwaKN3V2RSy9CRyKAJKACgAoAKACgDjfG3w48LeNruzufE2li8ntARG +3munBOcHaRkZ9aAKk3wi+H8tt9nfwlpQjxjKw7X/AO+xz+tAHknxG/ZytrO2fWPhvcXNnqdqDItl +JKXWXHOI2PIb6kg+1NNp3QpRUlZnK+HvAHxm8TJ5080OiQjgG+Cwlv8AgCIW/MCuh4ys+pyxwNCP +QqeKvDXxZ8AWz6jfvbaxpkXzTSW+JVQerDCyAe/SnHF1V1JlgKLW1ja8GeLrDxRYCSF1huk4lt2b +lT7eo969SjXjVV1uePiMNKg7PY6WtzmPHP2hv+YB/wBvH/tOvMzH7Pz/AEPXyr7fy/U9jr0zyDK8 +Ta5a+HdIl1C9J8teEUdZG7AVlVqKnHnZrQpSrT5EcT4L8A+MPjPK+pX96dI8ObiEZgWRsdo48jfj +uxP+FeLVxEqr1PoqOHp0V7qO51H9k608lTpfiq5juB1M9oGU/kwI/WsTc9G+GnwK8KeDIElubWPW +dXx813eRgqp/6ZxnIX68n3oA9XRVRQqABRwABwKAINQsrXUbV7a/tobq3fhopow6n6g0Acp4a+Gf +hDw34hm1zQ9EhstRlUqWjd9qA9dqE4XPsBQB2tABQAUAFABQAUAFABQAUAFABQAx0V1KsAVIwQRw +RQB86+Nv2YdJv7ue+8J6tNpNw7GRbaVPMhU+ikYZR/31QB5W9/4s+F/iCPR/HkM0unS8RXed4I/v +I/8AEPUHkfz7cPi3B2nqjz8TgY1FenozM/aAljnh8OSwuskcizujKchlPl4NaZg0+Vrz/QxyxOLm +n5fqezV6h455X46tJ/F/xS8N+Eo3dbeWSMPjtuPzt+CD+deTmE7yUT28sppU3Pufaulada6Tplrp ++nwpBZ2sYihiXoqgYArgPTLtABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAee/HXwvZ+K/ +hjrlvdovm2lvJe20h/5ZyxoSD+IyPoaAPhHWrya78F+H0mcsLa4u4Y89lxC2PzY1tNt0438/0Oen +BRqza62/U+oq98+ZOB0W5jsf2oPDM1wdkb4jDHuXjkjX9SBXjY7+KfQZd/BPsyuM7goAKACgAoAK +ACgAoAKACgAoAKACgAoAKACgAoAKACgDxP8Aaa+IVp4W8DXujWtxE2uarGbZYVb5o4WBDyEdhjIH +ufY0AfJXjDRptF8H+GY7pSk9w91cOh6rkRAD8lFdNam4U438/wBDkoVlVq1LdLfqfSde4fOHmfxj +0W6aKy8Q6WXS704guyfeVQchh/un+ftXBjqV1zroenltZQbpvqfSPwY+J2mfEPw9byLPFFrcKAXt +oWwwYdWUd0PXPbOK8k9s9JoAKACgAoAKACgAoAKACgAoAPxoAKACgAoAKACgAoA4b4ztrS/DDX5f +DNzJa6pFbmZZE4bYhDOFPYlA2KAPkv4Q6Haa2bjX9WmmvtRjmKYuDvAOAd5J6nnv0r0cDRjL32eV +mOIqQfs1sR/tDf8AMA/7eP8A2nTzH7Pz/QnKvt/L9T2OvTPIGsAwIIBB4INAzzbXPhm6an/aXhHU +X0m7ByFVmQIf9h15X6V59XApu9PQ9OjmTirVFc6H9nvxJ40vfjJJomseIr7UrOzt5vtUc0xmjIXA +BG7od7Lz17V5so8jaZ69OaqRU11PrioLCgAoAKACgClq1w9npl5cwoJJIYXkVD/EQCcUAeZ/s/8A +xMvPiToOo3OqWtvbXtjcCNhb52spGQcEk56igDN+NPxT1jwB438L2Fra2Uuk6gAblplbzP8AWBTt +IOBgHPQ0Ae1DkZoAWgAoAKACgAoAKACgDF8YX1vpfhTWL29Ki2gtJZJN3QgIeKAPjj4ARMNC1KU/ +ca4AH4Lz/MV6uAXus8XNH78UZ/7Q3/MA/wC3j/2nUZj9n5/oXlX2/l+p7HXpnkBQAUAc3+zBJGvx +y8bRP/rmhuCuR2Fymf5ivAr/AMSXqfUYb+DD0R9ZVibBQAUAFABQBFPEs0MkbdHUqfxoA8f+AHww +1b4c3fiQandWs1teyx/ZvJzkqm/kg9Pvjj2oA0vjb8KYviXHpDJqZ0640+RiJPK8wMjYyMZHPAxQ +B6dbp5UEcZYttUDJ70Acx478d+H/AALZQ3XiO9FukziOJFG+RvUhRzgdzQB00E0c8McsLh45FDKw +7g9DQBNQAUAFAENxMsEEkr52IpY4GeBQB4Lp37Ufg648/wC26frFoVJ8vESSeYO3RuCfT9aAPL/i +Z8V9Y+L7x+G/C2nTWejmQPO8rfNLjoZCOEQdcc5P5VpTpSqO0TKrVjSjzTOt8L6JB4e0S2062ORE +PnY9Wc9TXuUqapx5EfN1qrrVHNnmP7Q3/MA/7eP/AGnXDmP2fn+h6WVfb+X6nsdemeQFABQB5ro2 +rj4fftB2Wr3reVpeoHbNI3AEcg2sxPs4DH2FeLjI8tVvufQ4CfPRS7H2srBlDIQQRkEd65DtHUAF +ABQBwvxG+J3h34fS2MXiGadXu8lFhiLkKOpPtQBU0n40fD7U4w0XiixhJ7XRMBH/AH2BQBtJ8RfB +TLuHi/w7j/sJQ/8AxVAFS++KngSxhLzeLtFYDtDdpKfyQk0AeTeNf2mLESHT/AGl3GrahIfLimmj +Ijz/ALMY+d/0oAyPh78I/EfjzxGni34tvc+VkPFp8/yySYPAZf8AlnH/ALPU0AfTrtDZ2rM7JDbw +rkkkKqKB+gAoA5aX4meBoTGG8X+HzvbaNmoRPz74PH1NAHV288VzCs1vKksLjKujAhh6gigCegDx +z46/FnRvCXhnUdP07UILrxHcRPBDbRSBmtyRjfJj7uAcgHknFAHg/wALPBdtH4cNxrumwS3NzJ5i +LcQgskeMDr0zyfyr1sLh1yXqI8TG4uTqWpy0R6NZ2dtZQiGzt4reIfwxRhB+QrtSS0R5zm5u7ZPV +Enjn7Q3/ADAP+3j/ANp15mY/Z+f6Hr5V9v5fqex16Z5AUAFAHMeP/CsPirR/I3CK8hJa3kPY+h9j +/hXPiKKqxt1OrCYh0JX6FT4afHXVPAEEfhvx/p13dWtovlwTxbfORBwBgkLImOhz+deJKDg7M+ip +zjUV4s3fGn7TxvYBY/D/AEe6N9N8q3F6gJU/7ESk5P1P4Gkk3ohtpK7M7Qf2lfEegf6J468OfaJV +4E0WbZz9VIKn8MU5wcdGhQnGavB3Ohv/ANrDQkgzYeHNTmm/uzzRxL+Y3fyqSjrfDmo+CPj/AOGY +5dU0tXvbElZLSSUia2J7q4wSp9fbpkUAZOqfsu+DLklrG91ayP8AdEqyKPzGf1oAxG/ZP0fdlfE1 ++o9DboT/ADoA1tK/Za8IWsge/wBR1a9x/BvSNT+Qz+tAHq/g7wD4Y8IRKvh/R7W1kAwZtu6Vvq55 +oA6qgD5U/aI+Kj+J7lvAfgiQ3CzSeXfXMR4kIP8AqlP90Yyx/DpmqhBzdkTKSprmZytp8JdDGkRx +XbTm+2fPPHJj5/YdMV6qwMOWz3PEeZVee62KWneC/G3hiTHhLxXLbwZyUW4khH4oMg1zywEujOqG +Z0/totahpnxT1qMW+reMpvszDDKt3IAR7hQM/jQsBPq0U8zpdEy34T+GWmaLPHdX0h1C7U5UuuI1 +PqF7n611UsFGnq9WcOIzCpUVlojv67DgCgAoA8c/aG/5gH/bx/7TrzMx+z8/0PXyr7fy/U9jr0zy +AoAKACgCveWVreqFvbaG4QHIEsYcD86lwT3RSm4bMZZ6ZYWTlrKytbdzwTFEEJ/IUKMVsgdSU92W +JI0lUrIqOh6hhkU7CTsRJZWsZylrCD6iMUuVdh877nnWs+Ede8OeIjr/AMO7prGcr80ET7D7gA8F +TwdprzsRgne9M9bC49JclX7z0PwV+0sls66b8R9KuLG9T5Wu7aI4Pu8R5H4Z+grznFp2Z6sZKSuj +1/Qfix4F1yNGsPFGmBm6JcTeQ/8A3zJg0hmxJ408LxRl5PEmiKijJJvogB+tAHFeIfj58PdEEqLr +X9oToOIrGJpd59A/3P1oA8M8Y/Fnxt8UfO03whYvpGht8ssofEkg9Hl7D/ZXn61rTozqfCjGrXp0 +vjZo+BvBtj4WtMpia/cfvrgj9B6CvXw+HVFeZ4OJxcq78jqq6TlCgAoAKACgAoAKAPHP2hv+YB/2 +8f8AtOvMzH7Pz/Q9fKvt/L9T2OvTPICgAoAKACgAoAKACgAoAoato+navD5Wp2Vvcp0HmLkj6HqK +znTjP40XTqypu8HY4+9+E/hq4fdGLy2X0hm4/wDHga53gaTO2GY1l5lb/hT3h/8A5+tT/wC/sf8A +8RS+oUu7K/tOr2RsaV8OPDOnkMLD7TIP4rhjJ+nT9KuOEpx6GNTHVp9bHWwxJDGiQxpHGgwFUYAr +ptY5G76sfTEFABQAUAFABQAUAFAHjn7Q3/MA/wC3j/2nXmZj9n5/oevlX2/l+p7HXpnkBQAUAFAB +QAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFAHjn7Q3/ADAP+3j/ANp15mY/Z+f6Hr5V9v5f +qH/C7P8AqAf+Tv8A9ro/tH+7+P8AwA/sr+/+H/BD/hdn/UA/8nf/ALXR/aP938f+AH9lf3/w/wCC +H/C7P+oB/wCTv/2uj+0f7v4/8AP7K/v/AIf8EP8Ahdn/AFAP/J3/AO10f2j/AHfx/wCAH9lf3/w/ +4If8Ls/6gH/k7/8Aa6P7R/u/j/wA/sr+/wDh/wAEP+F2f9QD/wAnf/tdH9o/3fx/4Af2V/f/AA/4 +If8AC7P+oB/5O/8A2uj+0f7v4/8AAD+yv7/4f8EP+F2f9QD/AMnf/tdH9o/3fx/4Af2V/f8Aw/4I +f8Ls/wCoB/5O/wD2uj+0f7v4/wDAD+yv7/4f8EP+F2f9QD/yd/8AtdH9o/3fx/4Af2V/f/D/AIIf +8Ls/6gH/AJO//a6P7R/u/j/wA/sr+/8Ah/wQ/wCF2f8AUA/8nf8A7XR/aP8Ad/H/AIAf2V/f/D/g +h/wuz/qAf+Tv/wBro/tH+7+P/AD+yv7/AOH/AAQ/4XZ/1AP/ACd/+10f2j/d/H/gB/ZX9/8AD/gh +/wALs/6gH/k7/wDa6P7R/u/j/wAAP7K/v/h/wQ/4XZ/1AP8Ayd/+10f2j/d/H/gB/ZX9/wDD/gh/ +wuz/AKgH/k7/APa6P7R/u/j/AMAP7K/v/h/wQ/4XZ/1AP/J3/wC10f2j/d/H/gB/ZX9/8P8Agh/w +uz/qAf8Ak7/9ro/tH+7+P/AD+yv7/wCH/BD/AIXZ/wBQD/yd/wDtdH9o/wB38f8AgB/ZX9/8P+CH +/C7P+oB/5O//AGuj+0f7v4/8AP7K/v8A4f8ABD/hdn/UA/8AJ3/7XR/aP938f+AH9lf3/wAP+Ccd +8Q/G3/CY/wBn/wDEv+x/ZPM/5beZv3bf9kYxt/WubEYj29tLWOzC4X6vfW9z/9k= + +------=_NextPart_000_0003_01CB9D0D.783DE8D0 +Content-Type: image/jpeg; + name="735_90_1209.jpg" +Content-Transfer-Encoding: base64 +Content-Location: http://info-database.csdn.net/Upload/2010-12-09/735_90_1209.jpg + +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 +CAD2aEBp4HhQH//Z + +------=_NextPart_000_0003_01CB9D0D.783DE8D0 +Content-Type: application/octet-stream; + name="gmlog.php?bannerid=5425&clientid=1707&zf=&zoneid=409&source=&block=0&capping=0&cb=44eef5396f0f6e4d854ac9a884c26d8e" +Content-Transfer-Encoding: base64 +Content-Location: http://z.csdn.net/gmlog.php?bannerid=5425&clientid=1707&zf=&zoneid=409&source=&block=0&capping=0&cb=44eef5396f0f6e4d854ac9a884c26d8e + +R0lGODlhAQABAIAAAAQCBAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw== + +------=_NextPart_000_0003_01CB9D0D.783DE8D0 +Content-Type: image/jpeg; + name="210_90zhengdingnew.jpg" +Content-Transfer-Encoding: base64 +Content-Location: http://info-database.csdn.net/Upload/2010-10-29/210_90zhengdingnew.jpg + +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 + +------=_NextPart_000_0003_01CB9D0D.783DE8D0 +Content-Type: application/octet-stream; + name="gmlog.php?bannerid=5271&clientid=1518&zf=&zoneid=410&source=&block=0&capping=0&cb=d918f40e2b835b9e06f85cff4b8c0d9b" +Content-Transfer-Encoding: base64 +Content-Location: http://z.csdn.net/gmlog.php?bannerid=5271&clientid=1518&zf=&zoneid=410&source=&block=0&capping=0&cb=d918f40e2b835b9e06f85cff4b8c0d9b + +R0lGODlhAQABAIAAAAQCBAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw== + +------=_NextPart_000_0003_01CB9D0D.783DE8D0 +Content-Type: image/jpeg; + name="79_1311201141.jpg" +Content-Transfer-Encoding: base64 +Content-Location: http://articles.csdn.net/uploads/allimg/101214/79_1311201141.jpg + +/9j/4AAQSkZJRgABAgEASABIAAD/4QuJRXhpZgAATU0AKgAAAAgABwESAAMAAAABAAEAAAEaAAUA +AAABAAAAYgEbAAUAAAABAAAAagEoAAMAAAABAAIAAAExAAIAAAAbAAAAcgEyAAIAAAAUAAAAjYdp +AAQAAAABAAAApAAAANAAAABIAAAAAQAAAEgAAAABQWRvYmUgUGhvdG9zaG9wIENTIFdpbmRvd3MA +MjAxMDoxMjoxNCAxMzowNjozOAAAAAAAA6ABAAMAAAAB//8AAKACAAQAAAABAAAASqADAAQAAAAB +AAAAbAAAAAAAAAAGAQMAAwAAAAEABgAAARoABQAAAAEAAAEeARsABQAAAAEAAAEmASgAAwAAAAEA +AgAAAgEABAAAAAEAAAEuAgIABAAAAAEAAApTAAAAAAAAAEgAAAABAAAASAAAAAH/2P/gABBKRklG +AAECAQBIAEgAAP/tAAxBZG9iZV9DTQAC/+4ADkFkb2JlAGSAAAAAAf/bAIQADAgICAkIDAkJDBEL +CgsRFQ8MDA8VGBMTFRMTGBEMDAwMDAwRDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAENCwsN +Dg0QDg4QFA4ODhQUDg4ODhQRDAwMDAwREQwMDAwMDBEMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwM +DAwM/8AAEQgAbABKAwEiAAIRAQMRAf/dAAQABf/EAT8AAAEFAQEBAQEBAAAAAAAAAAMAAQIEBQYH +CAkKCwEAAQUBAQEBAQEAAAAAAAAAAQACAwQFBgcICQoLEAABBAEDAgQCBQcGCAUDDDMBAAIRAwQh +EjEFQVFhEyJxgTIGFJGhsUIjJBVSwWIzNHKC0UMHJZJT8OHxY3M1FqKygyZEk1RkRcKjdDYX0lXi +ZfKzhMPTdePzRieUpIW0lcTU5PSltcXV5fVWZnaGlqa2xtbm9jdHV2d3h5ent8fX5/cRAAICAQIE +BAMEBQYHBwYFNQEAAhEDITESBEFRYXEiEwUygZEUobFCI8FS0fAzJGLhcoKSQ1MVY3M08SUGFqKy +gwcmNcLSRJNUoxdkRVU2dGXi8rOEw9N14/NGlKSFtJXE1OT0pbXF1eX1VmZ2hpamtsbW5vYnN0dX +Z3eHl6e3x//aAAwDAQACEQMRAD8A9PycvHxWB97wxrnBonxJ29vj7/3EUEEAgyDqCFC3Houj1q22 +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 +Laf9f9yl9qw/9Izv38FIXY52Q5p9UkV+ZALnbf8ANSUj2n/X/cltP+v+5WNrfBLa3wSU19p/1/3J +bSrG1vgltb4JKa+0/wCv+5PtP+v+5H2t8Eto8ElP/9X1SAkQCITpJKadvT/0Lq6Xul5BJe950H7r +mu3NUaMG+uyhznhwqaWv91hJJ3RG+xzfzv8ACK8kkpSSSSSmnn9QGE6kek+31nbfYCY48AVVs67s +ssYaBtrc5u43VDUOcxvtc7279u9aySSnHb9YSWtLsYDdOgvpMQA5v+E/OWj9pP7n+C9X6Tf8zn/p +/wA2jaJ0lP8A/9n/7RBIUGhvdG9zaG9wIDMuMAA4QklNBCUAAAAAABAAAAAAAAAAAAAAAAAAAAAA +OEJJTQPtAAAAAAAQAEgAAAABAAIASAAAAAEAAjhCSU0EJgAAAAAADgAAAAAAAAAAAAA/gAAAOEJJ +TQQNAAAAAAAEAAAAeDhCSU0EGQAAAAAABAAAAB44QklNA/MAAAAAAAkAAAAAAAAAAAEAOEJJTQQK +AAAAAAABAAA4QklNJxAAAAAAAAoAAQAAAAAAAAACOEJJTQP1AAAAAABIAC9mZgABAGxmZgAGAAAA +AAABAC9mZgABAKGZmgAGAAAAAAABADIAAAABAFoAAAAGAAAAAAABADUAAAABAC0AAAAGAAAAAAAB +OEJJTQP4AAAAAABwAAD/////////////////////////////A+gAAAAA//////////////////// +/////////wPoAAAAAP////////////////////////////8D6AAAAAD///////////////////// +////////A+gAADhCSU0EAAAAAAAAAgABOEJJTQQCAAAAAAAEAAAAADhCSU0ECAAAAAAAEAAAAAEA +AAJAAAACQAAAAAA4QklNBB4AAAAAAAQAAAAAOEJJTQQaAAAAAAM/AAAABgAAAAAAAAAAAAAAbAAA +AEoAAAAFZypoB5iYAC0AMQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAASgAAAGwA +AAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAQAAAAAAAG51bGwAAAACAAAA +BmJvdW5kc09iamMAAAABAAAAAAAAUmN0MQAAAAQAAAAAVG9wIGxvbmcAAAAAAAAAAExlZnRsb25n +AAAAAAAAAABCdG9tbG9uZwAAAGwAAAAAUmdodGxvbmcAAABKAAAABnNsaWNlc1ZsTHMAAAABT2Jq +YwAAAAEAAAAAAAVzbGljZQAAABIAAAAHc2xpY2VJRGxvbmcAAAAAAAAAB2dyb3VwSURsb25nAAAA +AAAAAAZvcmlnaW5lbnVtAAAADEVTbGljZU9yaWdpbgAAAA1hdXRvR2VuZXJhdGVkAAAAAFR5cGVl +bnVtAAAACkVTbGljZVR5cGUAAAAASW1nIAAAAAZib3VuZHNPYmpjAAAAAQAAAAAAAFJjdDEAAAAE +AAAAAFRvcCBsb25nAAAAAAAAAABMZWZ0bG9uZwAAAAAAAAAAQnRvbWxvbmcAAABsAAAAAFJnaHRs +b25nAAAASgAAAAN1cmxURVhUAAAAAQAAAAAAAG51bGxURVhUAAAAAQAAAAAAAE1zZ2VURVhUAAAA +AQAAAAAABmFsdFRhZ1RFWFQAAAABAAAAAAAOY2VsbFRleHRJc0hUTUxib29sAQAAAAhjZWxsVGV4 +dFRFWFQAAAABAAAAAAAJaG9yekFsaWduZW51bQAAAA9FU2xpY2VIb3J6QWxpZ24AAAAHZGVmYXVs +dAAAAAl2ZXJ0QWxpZ25lbnVtAAAAD0VTbGljZVZlcnRBbGlnbgAAAAdkZWZhdWx0AAAAC2JnQ29s +b3JUeXBlZW51bQAAABFFU2xpY2VCR0NvbG9yVHlwZQAAAABOb25lAAAACXRvcE91dHNldGxvbmcA +AAAAAAAACmxlZnRPdXRzZXRsb25nAAAAAAAAAAxib3R0b21PdXRzZXRsb25nAAAAAAAAAAtyaWdo +dE91dHNldGxvbmcAAAAAADhCSU0EKAAAAAAADAAAAAE/8AAAAAAAADhCSU0EEQAAAAAAAQEAOEJJ +TQQUAAAAAAAEAAAAAjhCSU0EDAAAAAAKbwAAAAEAAABKAAAAbAAAAOAAAF6AAAAKUwAYAAH/2P/g +ABBKRklGAAECAQBIAEgAAP/tAAxBZG9iZV9DTQAC/+4ADkFkb2JlAGSAAAAAAf/bAIQADAgICAkI +DAkJDBELCgsRFQ8MDA8VGBMTFRMTGBEMDAwMDAwRDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwM +DAENCwsNDg0QDg4QFA4ODhQUDg4ODhQRDAwMDAwREQwMDAwMDBEMDAwMDAwMDAwMDAwMDAwMDAwM +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 +1vzVfDqHHQtJOvZNuxjp7PwS4R4I4j1tp1Q79KGOrdqza/mP349Ut2uQ31201C0h1rmmWhjTuJJ/ +d9X3bVoTjDT2T8lE2Ng+1haDzuHf5IGEf95cJy8fq0oe4+pkO/RnVwjZE/ml3qq7ilmyGPa5vI2m +Ymf5T0zzjlhbYyvbElpIjxHZLFGLDjjNraDG7041+O1GEQDvqicpEbaD7Gq+wjr9LPTdBxrPeB7d +X1n6X9laSZOjwa7/AKXF+FcKvdFVw/oe3v8A1uLif//T9OyKmvcCd0gcN4/Iolgn6LtO+s/kS93+ +spe7/WU0x1tcJmqWNT7Ktg3Mn6Ttxa4R+47ah/s9+v6a2TA/nD2/s/nIvu/1lL3f6ylwq4kbMK1h +DvVe6CNHWEjx/cVmLNYa2O3+sIXu/wBZS93+so0jiSxb3az7z/cpMbE+0N8I8ED3f6yl7kqVbZSV +b3f6yl7v9ZRQ/wD/1PTNp/1/3JbT/r/uRLL8at2yx7Wugug8wI3O/wCkojKwyQBYwl30dRrOmiSm +O0/6/wC5Laf9f9yl9qw/9Izv38FIXY52Q5p9UkV+ZALnbf8ANSUj2n/X/cltP+v+5WNrfBLa3wSU +19p/1/3JbSrG1vgltb4JKa+0/wCv+5PtP+v+5H2t8Eto8ElP/9X1SAkQCITpJKadvT/0Lq6Xul5B +Je950H7rmu3NUaMG+uyhznhwqaWv91hJJ3RG+xzfzv8ACK8kkpSSSSSmnn9QGE6kek+31nbfYCY4 +8AVVs67sssYaBtrc5u43VDUOcxvtc7279u9aySSnHb9YSWtLsYDdOgvpMQA5v+E/OWj9pP7n+C9X +6Tf8zn/p/wA2jaJ0lP8A/9kAOEJJTQQhAAAAAABTAAAAAQEAAAAPAEEAZABvAGIAZQAgAFAAaABv +AHQAbwBzAGgAbwBwAAAAEgBBAGQAbwBiAGUAIABQAGgAbwB0AG8AcwBoAG8AcAAgAEMAUwAAAAEA +OEJJTQQGAAAAAAAHAAgAAAABAQD/4RgCaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hw +YWNrZXQgYmVnaW49J++7vycgaWQ9J1c1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCc/Pgo8eDp4bXBt +ZXRhIHhtbG5zOng9J2Fkb2JlOm5zOm1ldGEvJyB4OnhtcHRrPSdYTVAgdG9vbGtpdCAzLjAtMjgs +IGZyYW1ld29yayAxLjYnPgo8cmRmOlJERiB4bWxuczpyZGY9J2h0dHA6Ly93d3cudzMub3JnLzE5 +OTkvMDIvMjItcmRmLXN5bnRheC1ucyMnIHhtbG5zOmlYPSdodHRwOi8vbnMuYWRvYmUuY29tL2lY +LzEuMC8nPgoKIDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSd1dWlkOmM2MmZhOGY4LTA3M2Yt +MTFlMC04MTE5LWE2ZWRjM2MyMGNjOScKICB4bWxuczpleGlmPSdodHRwOi8vbnMuYWRvYmUuY29t +L2V4aWYvMS4wLyc+CiAgPGV4aWY6Q29sb3JTcGFjZT40Mjk0OTY3Mjk1PC9leGlmOkNvbG9yU3Bh +Y2U+CiAgPGV4aWY6UGl4ZWxYRGltZW5zaW9uPjc0PC9leGlmOlBpeGVsWERpbWVuc2lvbj4KICA8 +ZXhpZjpQaXhlbFlEaW1lbnNpb24+MTA4PC9leGlmOlBpeGVsWURpbWVuc2lvbj4KIDwvcmRmOkRl +c2NyaXB0aW9uPgoKIDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSd1dWlkOmM2MmZhOGY4LTA3 +M2YtMTFlMC04MTE5LWE2ZWRjM2MyMGNjOScKICB4bWxuczpwZGY9J2h0dHA6Ly9ucy5hZG9iZS5j +b20vcGRmLzEuMy8nPgogPC9yZGY6RGVzY3JpcHRpb24+CgogPHJkZjpEZXNjcmlwdGlvbiByZGY6 +YWJvdXQ9J3V1aWQ6YzYyZmE4ZjgtMDczZi0xMWUwLTgxMTktYTZlZGMzYzIwY2M5JwogIHhtbG5z +OnBob3Rvc2hvcD0naHR0cDovL25zLmFkb2JlLmNvbS9waG90b3Nob3AvMS4wLyc+CiAgPHBob3Rv +c2hvcDpIaXN0b3J5PjwvcGhvdG9zaG9wOkhpc3Rvcnk+CiA8L3JkZjpEZXNjcmlwdGlvbj4KCiA8 +cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0ndXVpZDpjNjJmYThmOC0wNzNmLTExZTAtODExOS1h +NmVkYzNjMjBjYzknCiAgeG1sbnM6dGlmZj0naHR0cDovL25zLmFkb2JlLmNvbS90aWZmLzEuMC8n +PgogIDx0aWZmOk9yaWVudGF0aW9uPjE8L3RpZmY6T3JpZW50YXRpb24+CiAgPHRpZmY6WFJlc29s +dXRpb24+NzIvMTwvdGlmZjpYUmVzb2x1dGlvbj4KICA8dGlmZjpZUmVzb2x1dGlvbj43Mi8xPC90 +aWZmOllSZXNvbHV0aW9uPgogIDx0aWZmOlJlc29sdXRpb25Vbml0PjI8L3RpZmY6UmVzb2x1dGlv +blVuaXQ+CiA8L3JkZjpEZXNjcmlwdGlvbj4KCiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0n +dXVpZDpjNjJmYThmOC0wNzNmLTExZTAtODExOS1hNmVkYzNjMjBjYzknCiAgeG1sbnM6eGFwPSdo +dHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvJz4KICA8eGFwOkNyZWF0ZURhdGU+MjAxMC0xMi0x +NFQxMzowNjozOCswODowMDwveGFwOkNyZWF0ZURhdGU+CiAgPHhhcDpNb2RpZnlEYXRlPjIwMTAt +MTItMTRUMTM6MDY6MzgrMDg6MDA8L3hhcDpNb2RpZnlEYXRlPgogIDx4YXA6TWV0YWRhdGFEYXRl +PjIwMTAtMTItMTRUMTM6MDY6MzgrMDg6MDA8L3hhcDpNZXRhZGF0YURhdGU+CiAgPHhhcDpDcmVh +dG9yVG9vbD5BZG9iZSBQaG90b3Nob3AgQ1MgV2luZG93czwveGFwOkNyZWF0b3JUb29sPgogPC9y +ZGY6RGVzY3JpcHRpb24+CgogPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9J3V1aWQ6YzYyZmE4 +ZjgtMDczZi0xMWUwLTgxMTktYTZlZGMzYzIwY2M5JwogIHhtbG5zOnhhcE1NPSdodHRwOi8vbnMu +YWRvYmUuY29tL3hhcC8xLjAvbW0vJz4KICA8eGFwTU06RG9jdW1lbnRJRD5hZG9iZTpkb2NpZDpw +aG90b3Nob3A6YzYyZmE4ZjctMDczZi0xMWUwLTgxMTktYTZlZGMzYzIwY2M5PC94YXBNTTpEb2N1 +bWVudElEPgogPC9yZGY6RGVzY3JpcHRpb24+CgogPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9 +J3V1aWQ6YzYyZmE4ZjgtMDczZi0xMWUwLTgxMTktYTZlZGMzYzIwY2M5JwogIHhtbG5zOmRjPSdo +dHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyc+CiAgPGRjOmZvcm1hdD5pbWFnZS9qcGVn +PC9kYzpmb3JtYXQ+CiA8L3JkZjpEZXNjcmlwdGlvbj4KCjwvcmRmOlJERj4KPC94OnhtcG1ldGE+ +CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAK +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +IAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAo8P3hwYWNr +ZXQgZW5kPSd3Jz8+/+4ADkFkb2JlAGRAAAAAAf/bAIQAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB +AQEBAQEBAQEBAQEBAQEBAQEBAQICAgICAgICAgICAwMDAwMDAwMDAwEBAQEBAQEBAQEBAgIBAgID +AwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMD/8AAEQgAbABK +AwERAAIRAQMRAf/dAAQACv/EAaIAAAAGAgMBAAAAAAAAAAAAAAcIBgUECQMKAgEACwEAAAYDAQEB +AAAAAAAAAAAABgUEAwcCCAEJAAoLEAACAQMEAQMDAgMDAwIGCXUBAgMEEQUSBiEHEyIACDEUQTIj +FQlRQhZhJDMXUnGBGGKRJUOhsfAmNHIKGcHRNSfhUzaC8ZKiRFRzRUY3R2MoVVZXGrLC0uLyZIN0 +k4Rlo7PD0+MpOGbzdSo5OkhJSlhZWmdoaWp2d3h5eoWGh4iJipSVlpeYmZqkpaanqKmqtLW2t7i5 +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 + +------=_NextPart_000_0003_01CB9D0D.783DE8D0 +Content-Type: image/jpeg; + name="=?utf-8?B?akJQTTTlt6XkvZzmtYHlupTnlKjlvIDlj5HmjIfljZctMyUyMC5qcGc=?=" +Content-Transfer-Encoding: base64 +Content-Location: =?utf-8?B?aHR0cDovL2ltYWdlcy5jc2RuLm5ldC8yMDEwMTExMi9qQlBNNOW3pQ==?= + =?utf-8?B?5L2c5rWB5bqU55So5byA5Y+R5oyH5Y2XLTMlMjAuanBn?= + +/9j/4AAQSkZJRgABAQEBLAEsAAD/4Qs4RXhpZgAASUkqACYDAAAyMDEwOjA5OjE3IDE1OjU1OjMw +AAAAAABAQg8AAAAAAEBCDwAAAAAAQEIPAAAAAABAQg8AAAAAAEBCDwAAAAAAQEIPAAAAAABAQg8A +AAAAAEBCDwAAAAAAQEIPAAAAAABAQg8AAAAAAEBCDwAAAAAAQEIPAAAAAABAQg8AAAAAAEBCDwAA +AAAAQEIPAAAAAABAQg8AAAAAAEBCDwAAAAAAQEIPAAAAAABAQg8AMjAxMDowOToxNyAxNTo1NDoy +MgAyMDEwOjA5OjE3IDE1OjU0OjIyAAAAAABAQg8AAAAAAEBCDwAAAAAAQEIPAAAAAABAQg8AAAAA +AEBCDwAAAAAAQEIPAAAAAABAQg8AAAAAAEBCDwAAAAAAQEIPAAAAAABAQg8AAAAAAEBCDwAAAAAA +QEIPACgAmoIFAAEAAACkAAAAnYIFAAEAAACsAAAAIogDAAEAAAAAAAAAJ4gDAAIAAAAAAAAAAJAC +AAAAAAAAAAAAA5ACABQAAAC0AAAABJACABQAAADIAAAAApEFAAEAAADcAAAAAZIFAAEAAADkAAAA +ApIFAAEAAADsAAAAA5IFAAEAAAD0AAAABJIFAAEAAAD8AAAABZIFAAEAAAAEAQAABpIFAAEAAAAM +AQAAB5IDAAEAAAAAAAAACJIDAAEAAAAAAAAACZIDAAEAAAAAAAAACpIFAAEAAAAUAQAAkZICAAMA +AAAwMAAAkpICAAMAAAAwMAAAAaADAAEAAAD//wAAAqADAAEAAABPAgAAA6ADAAEAAADpAgAADqIF +AAEAAAAcAQAAD6IFAAEAAAAkAQAAEKIDAAEAAAAAAAAAFaIFAAEAAAAsAQAAF6IDAAEAAAAAAAAA +AKMDAAEAAAAAAAAAAaMDAAEAAAAAAAAAAqQDAAEAAAAAAAAAA6QDAAEAAAAAAAAABKQFAAEAAAA0 +AQAABaQDAAEAAAAAAAAABqQDAAEAAAAAAAAAB6QDAAEAAAAAAAAACKQDAAEAAAAAAAAACaQDAAEA +AAAAAAAACqQDAAEAAAAAAAAADKQDAAEAAAAAAAAAAAAAADwBAAAKABIBAwABAAAAAQAAACgBAwAB +AAAAAgAAADEBAgAEAAAAaVNlZTIBAgAUAAAACAAAAD4BBQACAAAAHAAAAD8BBQAGAAAALAAAABEC +BQADAAAAXAAAABMCAwABAAAAAAAAABQCBQAGAAAAdAAAAGmHBAABAAAAPAEAAF4KAAAAAAAAAQAA +AAAAAAABAAAACAAIAAgA/9j/4AAQSkZJRgABAQEBLAEsAAD/2wBDAAYEBQYFBAYGBQYHBwYIChAK +CgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoI +ChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgo +KCj/wAARCABEADQDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QA +tRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkK +FhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJ +ipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx +8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcF +BAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygp +KjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJma +oqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oA +DAMBAAIRAxEAPwD6L8V6Fpmt2cY1bT0vhA26NGLjBOAT8vPSuJHg3Qdw3eELcKw4O65P5/LxXqlF +axr1ILljJpepjLD0pvmlFN+iPKH8JeH1LAeDlJB6Yuf57a6OL4a+EWjUvoVuHIBIEkhAP512W9d+ +zcN393PP5U6q+s1v5397J+qUP5F9yOMf4aeEQjFdCgLY4G9+f/HqyrP4e6QbiP7R4V0+JAQS6XUj +EfhxXpFFL6zW/nf3sPqtD+RfcgFFFFYnQFcr8Sddl0Hwy8to6pfXUsdpbFuzucbvwUM34V086s8L +rG5jcqQrgA7Tjrg1wb6b/aOtWdv4i1ezvBbW7OkMQWPDZC+ZksW3kZBIwAMgdaLXE2lucM4uo4kn +trgG8EhkkV33SOo6nrnuOR3qSXxtcTWwtrDUJXkk24EMuSFJwee3THr6V6do9rp9jqd9I32RHlfE +QXaAIwB0P4c/Ss+80Pw+3iq2uXtdPSIxMWCRIFll3DaXwOSOSM0+VhzLuVfCniK5j/cTb7m2A+WR +gd4PGB7jB69sfl36ElQT1xXJ61aWcE6XdusM1tkfaLWJ8ErnO9Qp5I4yO4rorC/t72MtbSBgCQR0 +PHHQ80WYcyZbooopDA181eGtAs7+3hvLq0glDeII7N2Z23FGYZXb93Bz1619KmvJm8Gajpek22lW +N1BHdNqB1M3hjZ13IcqNvbA2565/GvQwNZU1JXs3b9TzMwoOq4O10r/pYq3fhHQV8XafHFpVj9ll +tL1mXLeQzxOAucnIKj73b0pPD3hfwlq7a41pbWctsl5EsEqMzIAIkklVTnlThx+NVbu28R3Df2nN +4gt91ukkAUabtAWUAsQvAy3HPWrfh/4eeJNN0zydM1+xitpm8/a1qxbLRlO/T5WIxXU58sPeq2fz +737ehxRhzT92ldb9O1u/e5JpHgzQz421x5dISXTIzFDbQKhKIxgErN/Ic92ql8DXt5PFviB7KEwW +7QoUjbqo3ng1rReBfGEWsS6nF4ntUuZV2OFgYIfkCA7M4zgDnGa0vhn4CvPCOoX1zd30F0LiJUAj +RgQQxOST9ampXh7GadTmbSS36b7mlKhU9tBqnypOTb067bHolFFFeOe4FchrltrMniSOa0s4Hskj +wsp27w+1scHtu2c5GOeD26+qs9mk88crSTqYzkBJWVT9QDg0XtsJpPc4G00nxNLb2kd9a2e4X3+k +ny48NDtjUFcf8D98fhUM/wDwndvps0FkknnR3R8l9kJzBsbaAO3O0EHnjIPNd6rWej26pcXbKrsd +rXMxZmOM4BY5PTpTxqmnk4+2W+eB98d6d2wUUtUjC8OzeJpPEFyNZt1i0sw5hIK5DjaMcc8/Mfwr +q8UgpaQwooooAKDRRQBXubS3utn2qCKbYcr5iBtpxjIz0NMXT7JWBW0gBHQ+WOKKKALYooooAKKK +KAP/2QARAP4ABAABAAAAAAAAAAABBAABAAAANAAAAAEBBAABAAAARAAAAAIBAwADAAAAtAMAAAMB +AwABAAAABgAAAAYBAwABAAAABgAAABEBBAABAAAAGwYAABUBAwABAAAAAwAAABYBBAABAAAARAAA +ABcBBAABAAAAQgQAABoBBQABAAAApAMAABsBBQABAAAArAMAACgBAwABAAAAAgAAAAACAwABAAAA +AQAAAAECBAABAAAAugMAAAICBAABAAAAowYAABICAwACAAAAAgACAAAAAAD/4QnaaHR0cDovL25z +LmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49J++7vycgaWQ9J1c1TTBNcENlaGlI +enJlU3pOVGN6a2M5ZCc/Pg0KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyI+PHJk +ZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgt +bnMjIj48cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0idXVpZDpmYWY1YmRkNS1iYTNkLTExZGEt +YWQzMS1kMzNkNzUxODJmMWIiIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4w +LyI+PHhtcDpDcmVhdG9yVG9vbD5BZG9iZSBQaG90b3Nob3AgQ1M0IFdpbmRvd3M8L3htcDpDcmVh +dG9yVG9vbD48eG1wOkNyZWF0ZURhdGU+MjAxMC0wOS0xN1QxNTo1NDoyMjwveG1wOkNyZWF0ZURh +dGU+PC9yZGY6RGVzY3JpcHRpb24+PC9yZGY6UkRGPjwveDp4bXBtZXRhPg0KICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8P3hwYWNrZXQgZW5kPSd3 +Jz8+/9sAQwAFAwQEBAMFBAQEBQUFBgcMCAcHBwcPCwsJDBEPEhIRDxERExYcFxMUGhURERghGBod +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 + +------=_NextPart_000_0003_01CB9D0D.783DE8D0 +Content-Type: image/jpeg; + name="=?utf-8?B?TGludXjpgqPkupvkuovlhL8tMi5qcGc=?=" +Content-Transfer-Encoding: base64 +Content-Location: =?utf-8?B?aHR0cDovL2ltYWdlcy5jc2RuLm5ldC8yMDEwMDgxMi9MaW51eOmCo+S6mw==?= + =?utf-8?B?5LqL5YS/LTIuanBn?= + +/9j/4AAQSkZJRgABAQEBLAEsAAD/4RKCRXhpZgAASUkqAN4CAAAsAQAAAQAAACwBAAABAAAAMjAx +MDowNjoyMiAxMDoyMjozNgAAAAAAQEIPAAAAAABAQg8AAAAAAEBCDwAAAAAAQEIPAAAAAABAQg8A +AAAAAEBCDwAAAAAAQEIPAAAAAABAQg8AAAAAAEBCDwAAAAAAQEIPAAAAAABAQg8AAAAAAEBCDwAA +AAAAQEIPAAAAAABAQg8AAAAAAEBCDwAAAAAAQEIPAAAAAABAQg8AAAAAAEBCDwAAAAAAQEIPAAAA +AABAQg8AAAAAAEBCDwAAAAAAQEIPAAAAAABAQg8AAAAAAEBCDwAAAAAAQEIPAAAAAABAQg8AAAAA +AEBCDwAAAAAAQEIPAAAAAABAQg8AAAAAAEBCDwAAAAAAQEIPACQAmoIFAAEAAAC0AAAAnYIFAAEA +AAC8AAAAIogDAAEAAAAAAAAAJ4gDAAIAAAAAAAAAAJACAAAAAAAAAAAAApEFAAEAAADEAAAAAZIF +AAEAAADMAAAAApIFAAEAAADUAAAAA5IFAAEAAADcAAAABJIFAAEAAADkAAAABZIFAAEAAADsAAAA +BpIFAAEAAAD0AAAAB5IDAAEAAAAAAAAACJIDAAEAAAAAAAAACZIDAAEAAAAAAAAACpIFAAEAAAD8 +AAAAAaADAAEAAAD//wAAAqADAAEAAABPAgAAA6ADAAEAAAD1AgAADqIFAAEAAAAEAQAAD6IFAAEA +AAAMAQAAEKIDAAEAAAAAAAAAFaIFAAEAAAAUAQAAF6IDAAEAAAAAAAAAAKMDAAEAAAAAAAAAAaMD +AAEAAAAAAAAAAqQDAAEAAAAAAAAAA6QDAAEAAAAAAAAABKQFAAEAAAAcAQAABaQDAAEAAAAAAAAA +BqQDAAEAAAAAAAAAB6QDAAEAAAAAAAAACKQDAAEAAAAAAAAACaQDAAEAAAAAAAAACqQDAAEAAAAA +AAAADKQDAAEAAAAAAAAAAAAAACQBAAAMABIBAwABAAAAAQAAABoBBQABAAAACAAAABsBBQABAAAA +EAAAACgBAwABAAAAAgAAADEBAgAEAAAAaVNlZTIBAgAUAAAAGAAAAD4BBQACAAAALAAAAD8BBQAG +AAAAPAAAABECBQADAAAAbAAAABMCAwABAAAAAAAAABQCBQAGAAAAhAAAAGmHBAABAAAAJAEAAKgR +AAAAAAAAAQAAAAAAAAABAAAACAAIAAgA/9j/4AAQSkZJRgABAQEBLAEsAAD/2wBDAAYEBQYFBAYG +BQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/ +2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgo +KCgoKCgoKCgoKCj/wAARCAB5AFoDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQF +BgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS +0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4 +eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi +4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREA +AgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl +8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImK +kpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP0 +9fb3+Pn6/9oADAMBAAIRAxEAPwD2e/itbC0kubthHBGNzuRwo9azBrOhFto1C2J9nFdtPYxyxlJU +Dp1waqDS7EDItlHfgV1+2fQ85UF1MpbWFlDdMjOCMGo5dNieRWDgYHSt8W8IGBGcdKDBFyfKPT0p ++2YvYHPrpcK4AYYBpF0yL5cSdOldELeIsB5fJNK9vErYMZOPT3pe2D2Bzq6UgQEyDA74pF0uIFT5 +g4OeldH5EWNvlnHTpSGCLP8Aqz27Ue2D2BiCyiPQjrin/wBnJ6fpWwIIxz5bdSfxqQRjAO1sGn7c +PYGJ/Zyen6Uf2cnp+lbqQhxkAj6077NR7cPYF9YmHVs/hSeS+Pv/AKVMzOCcLkUAuScrj0rjPQ5S +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 +AAAAAAABBAABAAAAWgAAAAEBBAABAAAAeQAAAAIBAwADAAAAhAMAAAMBAwABAAAABgAAAAYBAwAB +AAAABgAAABEBBAABAAAA6wUAABUBAwABAAAAAwAAABYBBAABAAAAeQAAABcBBAABAAAAvQsAABoB +BQABAAAAdAMAABsBBQABAAAAfAMAACgBAwABAAAAAgAAAAACAwABAAAAAQAAAAECBAABAAAAigMA +AAICBAABAAAAHg4AABICAwACAAAAAgACAAAAAAD/4U2faHR0cDovL25zLmFkb2JlLmNvbS94YXAv +MS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/ +PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJBZG9iZSBYTVAg +Q29yZSA0LjIuMi1jMDYzIDUzLjM1MjYyNCwgMjAwOC8wNy8zMC0xODoxMjoxOCAgICAgICAgIj4g +PHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50 +YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6ZGM9Imh0dHA6Ly9w +dXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20v +eGFwLzEuMC8iIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIiB4 +bWxuczpzdFJlZj0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlUmVm +IyIgeG1sbnM6c3RNZnM9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9NYW5pZmVz +dEl0ZW0jIiB4bWxuczpzdEV2dD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jl +c291cmNlRXZlbnQjIiB4bWxuczppbGx1c3RyYXRvcj0iaHR0cDovL25zLmFkb2JlLmNvbS9pbGx1 +c3RyYXRvci8xLjAvIiB4bWxuczp4bXBUUGc9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC90 +L3BnLyIgeG1sbnM6c3REaW09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9EaW1l +bnNpb25zIyIgeG1sbnM6c3RGbnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9G +b250IyIgeG1sbnM6eG1wRz0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL2cvIiB4bWxuczpw +aG90b3Nob3A9Imh0dHA6Ly9ucy5hZG9iZS5jb20vcGhvdG9zaG9wLzEuMC8iIHhtbG5zOnRpZmY9 +Imh0dHA6Ly9ucy5hZG9iZS5jb20vdGlmZi8xLjAvIiB4bWxuczpleGlmPSJodHRwOi8vbnMuYWRv +YmUuY29tL2V4aWYvMS4wLyIgZGM6Zm9ybWF0PSJpbWFnZS9qcGVnIiB4bXA6Q3JlYXRvclRvb2w9 +IkFkb2JlIElsbHVzdHJhdG9yIENTNCIgeG1wOkNyZWF0ZURhdGU9IjIwMTAtMDYtMjJUMTA6MTk6 +NDUrMDg6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDEwLTA2LTIyVDEwOjIyOjM2KzA4OjAwIiB4bXA6 +TWV0YWRhdGFEYXRlPSIyMDEwLTA2LTIyVDEwOjIyOjM2KzA4OjAwIiB4bXBNTTpEb2N1bWVudElE +PSJ4bXAuZGlkOkU3QjU3OUEwQTQ3RERGMTFBNzI2Q0JBQjhGMDA4RTRFIiB4bXBNTTpJbnN0YW5j +ZUlEPSJ4bXAuaWlkOkVGNTVGRDA1QTU3RERGMTFCQUUwQTcxMkMzMTE0OTcyIiB4bXBNTTpSZW5k +aXRpb25DbGFzcz0iZGVmYXVsdCIgeG1wTU06T3JpZ2luYWxEb2N1bWVudElEPSJ1dWlkOkE5RDE0 +QjVFQ0E2Q0RGMTFCNDFGQ0I5NDI1RjhFRUJEIiBpbGx1c3RyYXRvcjpTdGFydHVwUHJvZmlsZT0i +UHJpbnQiIHhtcFRQZzpOUGFnZXM9IjEiIHhtcFRQZzpIYXNWaXNpYmxlVHJhbnNwYXJlbmN5PSJU +cnVlIiB4bXBUUGc6SGFzVmlzaWJsZU92ZXJwcmludD0iRmFsc2UiIHBob3Rvc2hvcDpDb2xvck1v +ZGU9IjMiIHRpZmY6T3JpZW50YXRpb249IjEiIHRpZmY6WFJlc29sdXRpb249IjMwMDAwMDAvMTAw +MDAiIHRpZmY6WVJlc29sdXRpb249IjMwMDAwMDAvMTAwMDAiIHRpZmY6UmVzb2x1dGlvblVuaXQ9 +IjIiIHRpZmY6TmF0aXZlRGlnZXN0PSIyNTYsMjU3LDI1OCwyNTksMjYyLDI3NCwyNzcsMjg0LDUz +MCw1MzEsMjgyLDI4MywyOTYsMzAxLDMxOCwzMTksNTI5LDUzMiwzMDYsMjcwLDI3MSwyNzIsMzA1 +LDMxNSwzMzQzMjs2N0MxNzhDMTMwNkZBQTgwMDAxNUY3MkE1NUYzNkY0RCIgZXhpZjpQaXhlbFhE +aW1lbnNpb249IjU5MSIgZXhpZjpQaXhlbFlEaW1lbnNpb249Ijc1NyIgZXhpZjpDb2xvclNwYWNl +PSI2NTUzNSIgZXhpZjpOYXRpdmVEaWdlc3Q9IjM2ODY0LDQwOTYwLDQwOTYxLDM3MTIxLDM3MTIy +LDQwOTYyLDQwOTYzLDM3NTEwLDQwOTY0LDM2ODY3LDM2ODY4LDMzNDM0LDMzNDM3LDM0ODUwLDM0 +ODUyLDM0ODU1LDM0ODU2LDM3Mzc3LDM3Mzc4LDM3Mzc5LDM3MzgwLDM3MzgxLDM3MzgyLDM3Mzgz +LDM3Mzg0LDM3Mzg1LDM3Mzg2LDM3Mzk2LDQxNDgzLDQxNDg0LDQxNDg2LDQxNDg3LDQxNDg4LDQx +NDkyLDQxNDkzLDQxNDk1LDQxNzI4LDQxNzI5LDQxNzMwLDQxOTg1LDQxOTg2LDQxOTg3LDQxOTg4 +LDQxOTg5LDQxOTkwLDQxOTkxLDQxOTkyLDQxOTkzLDQxOTk0LDQxOTk1LDQxOTk2LDQyMDE2LDAs +Miw0LDUsNiw3LDgsOSwxMCwxMSwxMiwxMywxNCwxNSwxNiwxNywxOCwyMCwyMiwyMywyNCwyNSwy +NiwyNywyOCwzMDszQjcwMTRERDgzMDZFNTYxNzExRDI0M0FBN0JFNzA2MyI+IDxkYzp0aXRsZT4g +PHJkZjpBbHQ+IDxyZGY6bGkgeG1sOmxhbmc9IngtZGVmYXVsdCI+5omT5Y2wPC9yZGY6bGk+IDwv +cmRmOkFsdD4gPC9kYzp0aXRsZT4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9 +InV1aWQ6ZjFkZmVmYjUtZDY2Yy00ZjU4LTgzYTQtY2NjZGEzMGE3YzI1IiBzdFJlZjpkb2N1bWVu +dElEPSJ1dWlkOkE5RDE0QjVFQ0E2Q0RGMTFCNDFGQ0I5NDI1RjhFRUJEIiBzdFJlZjpvcmlnaW5h +bERvY3VtZW50SUQ9InV1aWQ6QTlEMTRCNUVDQTZDREYxMUI0MUZDQjk0MjVGOEVFQkQiIHN0UmVm +OnJlbmRpdGlvbkNsYXNzPSJkZWZhdWx0Ii8+IDx4bXBNTTpNYW5pZmVzdD4gPHJkZjpTZXE+IDxy +ZGY6bGk+IDxyZGY6RGVzY3JpcHRpb24gc3RNZnM6bGlua0Zvcm09IkVtYmVkQnlSZWZlcmVuY2Ui +PiA8c3RNZnM6cmVmZXJlbmNlIHN0UmVmOmZpbGVQYXRoPSJDOlxEb2N1bWVudHMgYW5kIFNldHRp +bmdzXEFkbWluaXN0cmF0b3Jc5qGM6Z2iXDI0OTM1NzNfMTQzNzIwMDE4XzIuanBnIiBzdFJlZjpp +bnN0YW5jZUlEPSJ4bXAuaWlkOkI0MjVCREI4NEM2RERGMTE5MkZEOEEwREZDMjgwRkQyIiBzdFJl +Zjpkb2N1bWVudElEPSJ4bXAuZGlkOkI0MjVCREI4NEM2RERGMTE5MkZEOEEwREZDMjgwRkQyIi8+ +IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpsaT4gPHJkZjpsaT4gPHJkZjpEZXNjcmlwdGlvbiBz +dE1mczpsaW5rRm9ybT0iRW1iZWRCeVJlZmVyZW5jZSI+IDxzdE1mczpyZWZlcmVuY2Ugc3RSZWY6 +ZmlsZVBhdGg9IkM6XERvY3VtZW50cyBhbmQgU2V0dGluZ3NcQWRtaW5pc3RyYXRvclzmoYzpnaJc +cWllLmpwZyIgc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo0QUNEM0IxQTI0NkRERjExOTJGRDhB +MERGQzI4MEZEMiIgc3RSZWY6ZG9jdW1lbnRJRD0idXVpZDpCNDE2M0ZFNDQyNURERjExOTJDNUNE +MTAyQjYyRDk4RiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6bGk+IDxyZGY6bGk+IDxyZGY6 +RGVzY3JpcHRpb24gc3RNZnM6bGlua0Zvcm09IkVtYmVkQnlSZWZlcmVuY2UiPiA8c3RNZnM6cmVm +ZXJlbmNlIHN0UmVmOmZpbGVQYXRoPSJGOlzmnY7njrLmlofku7Zc55+i6YeP5Zu+XDI5Ml8yOTgy +eDIwNTJfemNvb2wuY29tLmNuXzM3ODQyMTYuanBnIiBzdFJlZjppbnN0YW5jZUlEPSJ1dWlkOjQ2 +RUU4QTlFQ0M2Q0RGMTE5MDRGRTNDNTc3MkIwMDRFIiBzdFJlZjpkb2N1bWVudElEPSJ1dWlkOjQ1 +RUU4QTlFQ0M2Q0RGMTE5MDRGRTNDNTc3MkIwMDRFIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3Jk +ZjpsaT4gPHJkZjpsaT4gPHJkZjpEZXNjcmlwdGlvbiBzdE1mczpsaW5rRm9ybT0iRW1iZWRCeVJl +ZmVyZW5jZSI+IDxzdE1mczpyZWZlcmVuY2Ugc3RSZWY6ZmlsZVBhdGg9IkM6XERvY3VtZW50cyBh +bmQgU2V0dGluZ3NcQWRtaW5pc3RyYXRvclzmoYzpnaJccWllLmpwZyIgc3RSZWY6aW5zdGFuY2VJ +RD0ieG1wLmlpZDo0QUNEM0IxQTI0NkRERjExOTJGRDhBMERGQzI4MEZEMiIgc3RSZWY6ZG9jdW1l +bnRJRD0idXVpZDpCNDE2M0ZFNDQyNURERjExOTJDNUNEMTAyQjYyRDk4RiIvPiA8L3JkZjpEZXNj +cmlwdGlvbj4gPC9yZGY6bGk+IDxyZGY6bGk+IDxyZGY6RGVzY3JpcHRpb24gc3RNZnM6bGlua0Zv +cm09IkVtYmVkQnlSZWZlcmVuY2UiPiA8c3RNZnM6cmVmZXJlbmNlIHN0UmVmOmZpbGVQYXRoPSJD +OlxEb2N1bWVudHMgYW5kIFNldHRpbmdzXEFkbWluaXN0cmF0b3Jc5qGM6Z2iXHFpZS5qcGciIHN0 +UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6NEFDRDNCMUEyNDZEREYxMTkyRkQ4QTBERkMyODBGRDIi +IHN0UmVmOmRvY3VtZW50SUQ9InV1aWQ6QjQxNjNGRTQ0MjVEREYxMTkyQzVDRDEwMkI2MkQ5OEYi +Lz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOmxpPiA8cmRmOmxpPiA8cmRmOkRlc2NyaXB0aW9u +IHN0TWZzOmxpbmtGb3JtPSJFbWJlZEJ5UmVmZXJlbmNlIj4gPHN0TWZzOnJlZmVyZW5jZSBzdFJl +ZjpmaWxlUGF0aD0iRjpc5p2O546y5paH5Lu2XOefoumHj+WbvlwyOTJfMjk4MngyMDUyX3pjb29s +LmNvbS5jbl8zNzg0MjE2LmpwZyIgc3RSZWY6aW5zdGFuY2VJRD0idXVpZDo0NkVFOEE5RUNDNkNE +RjExOTA0RkUzQzU3NzJCMDA0RSIgc3RSZWY6ZG9jdW1lbnRJRD0idXVpZDo0NUVFOEE5RUNDNkNE +RjExOTA0RkUzQzU3NzJCMDA0RSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6bGk+IDxyZGY6 +bGk+IDxyZGY6RGVzY3JpcHRpb24gc3RNZnM6bGlua0Zvcm09IkVtYmVkQnlSZWZlcmVuY2UiPiA8 +c3RNZnM6cmVmZXJlbmNlIHN0UmVmOmZpbGVQYXRoPSJDOlxEb2N1bWVudHMgYW5kIFNldHRpbmdz +XEFkbWluaXN0cmF0b3Jc5qGM6Z2iXHFpZS5qcGciIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6 +NEFDRDNCMUEyNDZEREYxMTkyRkQ4QTBERkMyODBGRDIiIHN0UmVmOmRvY3VtZW50SUQ9InV1aWQ6 +QjQxNjNGRTQ0MjVEREYxMTkyQzVDRDEwMkI2MkQ5OEYiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwv +cmRmOmxpPiA8cmRmOmxpPiA8cmRmOkRlc2NyaXB0aW9uIHN0TWZzOmxpbmtGb3JtPSJFbWJlZEJ5 +UmVmZXJlbmNlIj4gPHN0TWZzOnJlZmVyZW5jZSBzdFJlZjpmaWxlUGF0aD0iQzpcRG9jdW1lbnRz +IGFuZCBTZXR0aW5nc1xBZG1pbmlzdHJhdG9yXOahjOmdolxxaWUuanBnIiBzdFJlZjppbnN0YW5j +ZUlEPSJ4bXAuaWlkOjRBQ0QzQjFBMjQ2RERGMTE5MkZEOEEwREZDMjgwRkQyIiBzdFJlZjpkb2N1 +bWVudElEPSJ1dWlkOkI0MTYzRkU0NDI1RERGMTE5MkM1Q0QxMDJCNjJEOThGIi8+IDwvcmRmOkRl +c2NyaXB0aW9uPiA8L3JkZjpsaT4gPC9yZGY6U2VxPiA8L3htcE1NOk1hbmlmZXN0PiA8eG1wTU06 +SGlzdG9yeT4gPHJkZjpTZXE+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJzYXZlZCIgc3RFdnQ6aW5z +dGFuY2VJRD0ieG1wLmlpZDpFN0I1NzlBMEE0N0RERjExQTcyNkNCQUI4RjAwOEU0RSIgc3RFdnQ6 +d2hlbj0iMjAxMC0wNi0yMlQxMDoxOTo0NiswODowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRv +YmUgSWxsdXN0cmF0b3IgQ1M0IiBzdEV2dDpjaGFuZ2VkPSIvIi8+IDxyZGY6bGkgc3RFdnQ6YWN0 +aW9uPSJzYXZlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDpFRjU1RkQwNUE1N0RERjExQkFF +MEE3MTJDMzExNDk3MiIgc3RFdnQ6d2hlbj0iMjAxMC0wNi0yMlQxMDoyMjozNiswODowMCIgc3RF +dnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIENTNCBXaW5kb3dzIiBzdEV2dDpjaGFu +Z2VkPSIvIi8+IDwvcmRmOlNlcT4gPC94bXBNTTpIaXN0b3J5PiA8eG1wVFBnOk1heFBhZ2VTaXpl +IHN0RGltOnc9IjIwMi45OTk4NDAiIHN0RGltOmg9IjI1OS45OTk5NzgiIHN0RGltOnVuaXQ9Ik1p +bGxpbWV0ZXJzIi8+IDx4bXBUUGc6Rm9udHM+IDxyZGY6QmFnPiA8cmRmOmxpIHN0Rm50OmZvbnRO +YW1lPSJUcmVidWNoZXRNUyIgc3RGbnQ6Zm9udEZhbWlseT0iVHJlYnVjaGV0IE1TIiBzdEZudDpm +b250RmFjZT0iUmVndWxhciIgc3RGbnQ6Zm9udFR5cGU9Ik9wZW4gVHlwZSIgc3RGbnQ6dmVyc2lv +blN0cmluZz0iVmVyc2lvbiAxLjIzIiBzdEZudDpjb21wb3NpdGU9IkZhbHNlIiBzdEZudDpmb250 +RmlsZU5hbWU9InRyZWJ1Yy5UVEYiLz4gPHJkZjpsaSBzdEZudDpmb250TmFtZT0iVGltZXNOZXdS +b21hblBTTVQiIHN0Rm50OmZvbnRGYW1pbHk9IlRpbWVzIE5ldyBSb21hbiIgc3RGbnQ6Zm9udEZh +Y2U9IlJlZ3VsYXIiIHN0Rm50OmZvbnRUeXBlPSJPcGVuIFR5cGUiIHN0Rm50OnZlcnNpb25TdHJp +bmc9IlZlcnNpb24gMy4wMCIgc3RGbnQ6Y29tcG9zaXRlPSJGYWxzZSIgc3RGbnQ6Zm9udEZpbGVO +YW1lPSJUSU1FUy5UVEYiLz4gPHJkZjpsaSBzdEZudDpmb250TmFtZT0iRlpYSDFKVy0tR0IxLTAi +IHN0Rm50OmZvbnRGYW1pbHk9IuaWueato+e7hum7keS4gOeugOS9kyIgc3RGbnQ6Zm9udEZhY2U9 +IlJlZ3VsYXIiIHN0Rm50OmZvbnRUeXBlPSJUcnVlVHlwZSIgc3RGbnQ6dmVyc2lvblN0cmluZz0i +NC4wMCIgc3RGbnQ6Y29tcG9zaXRlPSJGYWxzZSIgc3RGbnQ6Zm9udEZpbGVOYW1lPSLmlrnmraPn +u4bpu5HkuIDnroDkvZMudHRmIi8+IDxyZGY6bGkgc3RGbnQ6Zm9udE5hbWU9IkZaS1RKVy0tR0Ix +LTAiIHN0Rm50OmZvbnRGYW1pbHk9IuaWueato+alt+S9k+eugOS9kyIgc3RGbnQ6Zm9udEZhY2U9 +IlJlZ3VsYXIiIHN0Rm50OmZvbnRUeXBlPSJUcnVlVHlwZSIgc3RGbnQ6dmVyc2lvblN0cmluZz0i +Mi4wMCIgc3RGbnQ6Y29tcG9zaXRlPSJGYWxzZSIgc3RGbnQ6Zm9udEZpbGVOYW1lPSJGWktUSlcu +VFRGIi8+IDxyZGY6bGkgc3RGbnQ6Zm9udE5hbWU9IkZaSFRKVy0tR0IxLTAiIHN0Rm50OmZvbnRG +YW1pbHk9IuaWueato+m7keS9k+eugOS9kyIgc3RGbnQ6Zm9udEZhY2U9IlJlZ3VsYXIiIHN0Rm50 +OmZvbnRUeXBlPSJUcnVlVHlwZSIgc3RGbnQ6dmVyc2lvblN0cmluZz0iMi4wMCIgc3RGbnQ6Y29t +cG9zaXRlPSJGYWxzZSIgc3RGbnQ6Zm9udEZpbGVOYW1lPSJGWkhUSlcuVFRGIi8+IDxyZGY6bGkg +c3RGbnQ6Zm9udE5hbWU9IkZaREhUSlctLUdCMS0wIiBzdEZudDpmb250RmFtaWx5PSLmlrnmraPl +pKfpu5HnroDkvZMiIHN0Rm50OmZvbnRGYWNlPSJSZWd1bGFyIiBzdEZudDpmb250VHlwZT0iVHJ1 +ZVR5cGUiIHN0Rm50OnZlcnNpb25TdHJpbmc9IjEuMDAiIHN0Rm50OmNvbXBvc2l0ZT0iRmFsc2Ui +IHN0Rm50OmZvbnRGaWxlTmFtZT0iRlpESFRKVy5UVEYiLz4gPHJkZjpsaSBzdEZudDpmb250TmFt +ZT0iRlpEQlNKVy0tR0IxLTAiIHN0Rm50OmZvbnRGYW1pbHk9IuaWueato+Wkp+agh+Wui+eugOS9 +kyIgc3RGbnQ6Zm9udEZhY2U9IlJlZ3VsYXIiIHN0Rm50OmZvbnRUeXBlPSJUcnVlVHlwZSIgc3RG +bnQ6dmVyc2lvblN0cmluZz0iMS4wMCIgc3RGbnQ6Y29tcG9zaXRlPSJGYWxzZSIgc3RGbnQ6Zm9u +dEZpbGVOYW1lPSJGWkRCU0pXLlRURiIvPiA8cmRmOmxpIHN0Rm50OmZvbnROYW1lPSJGWkNDSEpX +LS1HQjEtMCIgc3RGbnQ6Zm9udEZhbWlseT0i5pa55q2j6LaF57KX6buR566A5L2TIiBzdEZudDpm +b250RmFjZT0iUmVndWxhciIgc3RGbnQ6Zm9udFR5cGU9IlRydWVUeXBlIiBzdEZudDp2ZXJzaW9u +U3RyaW5nPSIyLjAwIiBzdEZudDpjb21wb3NpdGU9IkZhbHNlIiBzdEZudDpmb250RmlsZU5hbWU9 +IkZaQ0NISlcuVFRGIi8+IDxyZGY6bGkgc3RGbnQ6Zm9udE5hbWU9IlNpbVN1biIgc3RGbnQ6Zm9u +dEZhbWlseT0i5a6L5L2TIiBzdEZudDpmb250RmFjZT0iUmVndWxhciIgc3RGbnQ6Zm9udFR5cGU9 +IlRydWVUeXBlIiBzdEZudDp2ZXJzaW9uU3RyaW5nPSJWZXJzaW9uIDMuMTIiIHN0Rm50OmNvbXBv +c2l0ZT0iRmFsc2UiIHN0Rm50OmZvbnRGaWxlTmFtZT0ic2ltc3VuLnR0YyIvPiA8L3JkZjpCYWc+ +IDwveG1wVFBnOkZvbnRzPiA8eG1wVFBnOlBsYXRlTmFtZXM+IDxyZGY6U2VxPiA8cmRmOmxpPkN5 +YW48L3JkZjpsaT4gPHJkZjpsaT5NYWdlbnRhPC9yZGY6bGk+IDxyZGY6bGk+WWVsbG93PC9yZGY6 +bGk+IDxyZGY6bGk+QmxhY2s8L3JkZjpsaT4gPC9yZGY6U2VxPiA8L3htcFRQZzpQbGF0ZU5hbWVz +PiA8eG1wVFBnOlN3YXRjaEdyb3Vwcz4gPHJkZjpTZXE+IDxyZGY6bGk+IDxyZGY6RGVzY3JpcHRp +b24geG1wRzpncm91cE5hbWU9Ium7mOiupOiJsuadv+e7hCIgeG1wRzpncm91cFR5cGU9IjAiPiA8 +eG1wRzpDb2xvcmFudHM+IDxyZGY6U2VxPiA8cmRmOmxpIHhtcEc6c3dhdGNoTmFtZT0i55m96Imy +IiB4bXBHOm1vZGU9IkNNWUsiIHhtcEc6dHlwZT0iUFJPQ0VTUyIgeG1wRzpjeWFuPSIwLjAwMDAw +MCIgeG1wRzptYWdlbnRhPSIwLjAwMDAwMCIgeG1wRzp5ZWxsb3c9IjAuMDAwMDAwIiB4bXBHOmJs +YWNrPSIwLjAwMDAwMCIvPiA8cmRmOmxpIHhtcEc6c3dhdGNoTmFtZT0i6buR6ImyIiB4bXBHOm1v +ZGU9IkNNWUsiIHhtcEc6dHlwZT0iUFJPQ0VTUyIgeG1wRzpjeWFuPSIwLjAwMDAwMCIgeG1wRzpt +YWdlbnRhPSIwLjAwMDAwMCIgeG1wRzp5ZWxsb3c9IjAuMDAwMDAwIiB4bXBHOmJsYWNrPSIxMDAu +MDAwMDAwIi8+IDxyZGY6bGkgeG1wRzpzd2F0Y2hOYW1lPSJDTVlLIOe6ouiJsiIgeG1wRzptb2Rl +PSJDTVlLIiB4bXBHOnR5cGU9IlBST0NFU1MiIHhtcEc6Y3lhbj0iMC4wMDAwMDAiIHhtcEc6bWFn +ZW50YT0iMTAwLjAwMDAwMCIgeG1wRzp5ZWxsb3c9IjEwMC4wMDAwMDAiIHhtcEc6YmxhY2s9IjAu +MDAwMDAwIi8+IDxyZGY6bGkgeG1wRzpzd2F0Y2hOYW1lPSJDTVlLIOm7hOiJsiIgeG1wRzptb2Rl +PSJDTVlLIiB4bXBHOnR5cGU9IlBST0NFU1MiIHhtcEc6Y3lhbj0iMC4wMDAwMDAiIHhtcEc6bWFn +ZW50YT0iMC4wMDAwMDAiIHhtcEc6eWVsbG93PSIxMDAuMDAwMDAwIiB4bXBHOmJsYWNrPSIwLjAw +MDAwMCIvPiA8cmRmOmxpIHhtcEc6c3dhdGNoTmFtZT0iQ01ZSyDnu7/oibIiIHhtcEc6bW9kZT0i +Q01ZSyIgeG1wRzp0eXBlPSJQUk9DRVNTIiB4bXBHOmN5YW49IjEwMC4wMDAwMDAiIHhtcEc6bWFn +ZW50YT0iMC4wMDAwMDAiIHhtcEc6eWVsbG93PSIxMDAuMDAwMDAwIiB4bXBHOmJsYWNrPSIwLjAw +MDAwMCIvPiA8cmRmOmxpIHhtcEc6c3dhdGNoTmFtZT0iQ01ZSyDpnZLoibIiIHhtcEc6bW9kZT0i +Q01ZSyIgeG1wRzp0eXBlPSJQUk9DRVNTIiB4bXBHOmN5YW49IjEwMC4wMDAwMDAiIHhtcEc6bWFn +ZW50YT0iMC4wMDAwMDAiIHhtcEc6eWVsbG93PSIwLjAwMDAwMCIgeG1wRzpibGFjaz0iMC4wMDAw +MDAiLz4gPHJkZjpsaSB4bXBHOnN3YXRjaE5hbWU9IkNNWUsg6JOd6ImyIiB4bXBHOm1vZGU9IkNN +WUsiIHhtcEc6dHlwZT0iUFJPQ0VTUyIgeG1wRzpjeWFuPSIxMDAuMDAwMDAwIiB4bXBHOm1hZ2Vu +dGE9IjEwMC4wMDAwMDAiIHhtcEc6eWVsbG93PSIwLjAwMDAwMCIgeG1wRzpibGFjaz0iMC4wMDAw +MDAiLz4gPHJkZjpsaSB4bXBHOnN3YXRjaE5hbWU9IkNNWUsg5rSL57qi6ImyIiB4bXBHOm1vZGU9 +IkNNWUsiIHhtcEc6dHlwZT0iUFJPQ0VTUyIgeG1wRzpjeWFuPSIwLjAwMDAwMCIgeG1wRzptYWdl +bnRhPSIxMDAuMDAwMDAwIiB4bXBHOnllbGxvdz0iMC4wMDAwMDAiIHhtcEc6YmxhY2s9IjAuMDAw +MDAwIi8+IDxyZGY6bGkgeG1wRzpzd2F0Y2hOYW1lPSJDPTE1IE09MTAwIFk9OTAgSz0xMCIgeG1w +Rzptb2RlPSJDTVlLIiB4bXBHOnR5cGU9IlBST0NFU1MiIHhtcEc6Y3lhbj0iMTQuOTk5OTk4IiB4 +bXBHOm1hZ2VudGE9IjEwMC4wMDAwMDAiIHhtcEc6eWVsbG93PSI5MC4wMDAwMDQiIHhtcEc6Ymxh +Y2s9IjEwLjAwMDAwMiIvPiA8cmRmOmxpIHhtcEc6c3dhdGNoTmFtZT0iQz0wIE09OTAgWT04NSBL +PTAiIHhtcEc6bW9kZT0iQ01ZSyIgeG1wRzp0eXBlPSJQUk9DRVNTIiB4bXBHOmN5YW49IjAuMDAw +MDAwIiB4bXBHOm1hZ2VudGE9IjkwLjAwMDAwNCIgeG1wRzp5ZWxsb3c9Ijg0Ljk5OTk5NiIgeG1w +RzpibGFjaz0iMC4wMDAwMDAiLz4gPHJkZjpsaSB4bXBHOnN3YXRjaE5hbWU9IkM9MCBNPTgwIFk9 +OTUgSz0wIiB4bXBHOm1vZGU9IkNNWUsiIHhtcEc6dHlwZT0iUFJPQ0VTUyIgeG1wRzpjeWFuPSIw +LjAwMDAwMCIgeG1wRzptYWdlbnRhPSI4MC4wMDAwMDEiIHhtcEc6eWVsbG93PSI5NC45OTk5OTki +IHhtcEc6YmxhY2s9IjAuMDAwMDAwIi8+IDxyZGY6bGkgeG1wRzpzd2F0Y2hOYW1lPSJDPTAgTT01 +MCBZPTEwMCBLPTAiIHhtcEc6bW9kZT0iQ01ZSyIgeG1wRzp0eXBlPSJQUk9DRVNTIiB4bXBHOmN5 +YW49IjAuMDAwMDAwIiB4bXBHOm1hZ2VudGE9IjUwLjAwMDAwMCIgeG1wRzp5ZWxsb3c9IjEwMC4w +MDAwMDAiIHhtcEc6YmxhY2s9IjAuMDAwMDAwIi8+IDxyZGY6bGkgeG1wRzpzd2F0Y2hOYW1lPSJD +PTAgTT0zNSBZPTg1IEs9MCIgeG1wRzptb2RlPSJDTVlLIiB4bXBHOnR5cGU9IlBST0NFU1MiIHht +cEc6Y3lhbj0iMC4wMDAwMDAiIHhtcEc6bWFnZW50YT0iMzUuMDAwMDAyIiB4bXBHOnllbGxvdz0i +ODQuOTk5OTk2IiB4bXBHOmJsYWNrPSIwLjAwMDAwMCIvPiA8cmRmOmxpIHhtcEc6c3dhdGNoTmFt +ZT0iQz01IE09MCBZPTkwIEs9MCIgeG1wRzptb2RlPSJDTVlLIiB4bXBHOnR5cGU9IlBST0NFU1Mi +IHhtcEc6Y3lhbj0iNS4wMDAwMDEiIHhtcEc6bWFnZW50YT0iMC4wMDAwMDAiIHhtcEc6eWVsbG93 +PSI5MC4wMDAwMDQiIHhtcEc6YmxhY2s9IjAuMDAwMDAwIi8+IDxyZGY6bGkgeG1wRzpzd2F0Y2hO +YW1lPSJDPTIwIE09MCBZPTEwMCBLPTAiIHhtcEc6bW9kZT0iQ01ZSyIgeG1wRzp0eXBlPSJQUk9D +RVNTIiB4bXBHOmN5YW49IjE5Ljk5OTk5OSIgeG1wRzptYWdlbnRhPSIwLjAwMDAwMCIgeG1wRzp5 +ZWxsb3c9IjEwMC4wMDAwMDAiIHhtcEc6YmxhY2s9IjAuMDAwMDAwIi8+IDxyZGY6bGkgeG1wRzpz +d2F0Y2hOYW1lPSJDPTUwIE09MCBZPTEwMCBLPTAiIHhtcEc6bW9kZT0iQ01ZSyIgeG1wRzp0eXBl +PSJQUk9DRVNTIiB4bXBHOmN5YW49IjUwLjAwMDAwMCIgeG1wRzptYWdlbnRhPSIwLjAwMDAwMCIg +eG1wRzp5ZWxsb3c9IjEwMC4wMDAwMDAiIHhtcEc6YmxhY2s9IjAuMDAwMDAwIi8+IDxyZGY6bGkg +eG1wRzpzd2F0Y2hOYW1lPSJDPTc1IE09MCBZPTEwMCBLPTAiIHhtcEc6bW9kZT0iQ01ZSyIgeG1w +Rzp0eXBlPSJQUk9DRVNTIiB4bXBHOmN5YW49Ijc1LjAwMDAwMCIgeG1wRzptYWdlbnRhPSIwLjAw +MDAwMCIgeG1wRzp5ZWxsb3c9IjEwMC4wMDAwMDAiIHhtcEc6YmxhY2s9IjAuMDAwMDAwIi8+IDxy +ZGY6bGkgeG1wRzpzd2F0Y2hOYW1lPSJDPTg1IE09MTAgWT0xMDAgSz0xMCIgeG1wRzptb2RlPSJD +TVlLIiB4bXBHOnR5cGU9IlBST0NFU1MiIHhtcEc6Y3lhbj0iODQuOTk5OTk2IiB4bXBHOm1hZ2Vu +dGE9IjEwLjAwMDAwMiIgeG1wRzp5ZWxsb3c9IjEwMC4wMDAwMDAiIHhtcEc6YmxhY2s9IjEwLjAw +MDAwMiIvPiA8cmRmOmxpIHhtcEc6c3dhdGNoTmFtZT0iQz05MCBNPTMwIFk9OTUgSz0zMCIgeG1w +Rzptb2RlPSJDTVlLIiB4bXBHOnR5cGU9IlBST0NFU1MiIHhtcEc6Y3lhbj0iOTAuMDAwMDA0IiB4 +bXBHOm1hZ2VudGE9IjMwLjAwMDAwMSIgeG1wRzp5ZWxsb3c9Ijk0Ljk5OTk5OSIgeG1wRzpibGFj +az0iMzAuMDAwMDAxIi8+IDxyZGY6bGkgeG1wRzpzd2F0Y2hOYW1lPSJDPTc1IE09MCBZPTc1IEs9 +MCIgeG1wRzptb2RlPSJDTVlLIiB4bXBHOnR5cGU9IlBST0NFU1MiIHhtcEc6Y3lhbj0iNzUuMDAw +MDAwIiB4bXBHOm1hZ2VudGE9IjAuMDAwMDAwIiB4bXBHOnllbGxvdz0iNzUuMDAwMDAwIiB4bXBH +OmJsYWNrPSIwLjAwMDAwMCIvPiA8cmRmOmxpIHhtcEc6c3dhdGNoTmFtZT0iQz04MCBNPTEwIFk9 +NDUgSz0wIiB4bXBHOm1vZGU9IkNNWUsiIHhtcEc6dHlwZT0iUFJPQ0VTUyIgeG1wRzpjeWFuPSI4 +MC4wMDAwMDEiIHhtcEc6bWFnZW50YT0iMTAuMDAwMDAyIiB4bXBHOnllbGxvdz0iNDQuOTk5OTk5 +IiB4bXBHOmJsYWNrPSIwLjAwMDAwMCIvPiA8cmRmOmxpIHhtcEc6c3dhdGNoTmFtZT0iQz03MCBN +PTE1IFk9MCBLPTAiIHhtcEc6bW9kZT0iQ01ZSyIgeG1wRzp0eXBlPSJQUk9DRVNTIiB4bXBHOmN5 +YW49IjY5Ljk5OTk5OSIgeG1wRzptYWdlbnRhPSIxNC45OTk5OTgiIHhtcEc6eWVsbG93PSIwLjAw +MDAwMCIgeG1wRzpibGFjaz0iMC4wMDAwMDAiLz4gPHJkZjpsaSB4bXBHOnN3YXRjaE5hbWU9IkM9 +ODUgTT01MCBZPTAgSz0wIiB4bXBHOm1vZGU9IkNNWUsiIHhtcEc6dHlwZT0iUFJPQ0VTUyIgeG1w +RzpjeWFuPSI4NC45OTk5OTYiIHhtcEc6bWFnZW50YT0iNTAuMDAwMDAwIiB4bXBHOnllbGxvdz0i +MC4wMDAwMDAiIHhtcEc6YmxhY2s9IjAuMDAwMDAwIi8+IDxyZGY6bGkgeG1wRzpzd2F0Y2hOYW1l +PSJDPTEwMCBNPTk1IFk9NSBLPTAiIHhtcEc6bW9kZT0iQ01ZSyIgeG1wRzp0eXBlPSJQUk9DRVNT +IiB4bXBHOmN5YW49IjEwMC4wMDAwMDAiIHhtcEc6bWFnZW50YT0iOTQuOTk5OTk5IiB4bXBHOnll +bGxvdz0iNS4wMDAwMDEiIHhtcEc6YmxhY2s9IjAuMDAwMDAwIi8+IDxyZGY6bGkgeG1wRzpzd2F0 +Y2hOYW1lPSJDPTEwMCBNPTEwMCBZPTI1IEs9MjUiIHhtcEc6bW9kZT0iQ01ZSyIgeG1wRzp0eXBl +PSJQUk9DRVNTIiB4bXBHOmN5YW49IjEwMC4wMDAwMDAiIHhtcEc6bWFnZW50YT0iMTAwLjAwMDAw +MCIgeG1wRzp5ZWxsb3c9IjI1LjAwMDAwMCIgeG1wRzpibGFjaz0iMjUuMDAwMDAwIi8+IDxyZGY6 +bGkgeG1wRzpzd2F0Y2hOYW1lPSJDPTc1IE09MTAwIFk9MCBLPTAiIHhtcEc6bW9kZT0iQ01ZSyIg +eG1wRzp0eXBlPSJQUk9DRVNTIiB4bXBHOmN5YW49Ijc1LjAwMDAwMCIgeG1wRzptYWdlbnRhPSIx +MDAuMDAwMDAwIiB4bXBHOnllbGxvdz0iMC4wMDAwMDAiIHhtcEc6YmxhY2s9IjAuMDAwMDAwIi8+ +IDxyZGY6bGkgeG1wRzpzd2F0Y2hOYW1lPSJDPTUwIE09MTAwIFk9MCBLPTAiIHhtcEc6bW9kZT0i +Q01ZSyIgeG1wRzp0eXBlPSJQUk9DRVNTIiB4bXBHOmN5YW49IjUwLjAwMDAwMCIgeG1wRzptYWdl +bnRhPSIxMDAuMDAwMDAwIiB4bXBHOnllbGxvdz0iMC4wMDAwMDAiIHhtcEc6YmxhY2s9IjAuMDAw +MDAwIi8+IDxyZGY6bGkgeG1wRzpzd2F0Y2hOYW1lPSJDPTM1IE09MTAwIFk9MzUgSz0xMCIgeG1w +Rzptb2RlPSJDTVlLIiB4bXBHOnR5cGU9IlBST0NFU1MiIHhtcEc6Y3lhbj0iMzUuMDAwMDAyIiB4 +bXBHOm1hZ2VudGE9IjEwMC4wMDAwMDAiIHhtcEc6eWVsbG93PSIzNS4wMDAwMDIiIHhtcEc6Ymxh +Y2s9IjEwLjAwMDAwMiIvPiA8cmRmOmxpIHhtcEc6c3dhdGNoTmFtZT0iQz0xMCBNPTEwMCBZPTUw +IEs9MCIgeG1wRzptb2RlPSJDTVlLIiB4bXBHOnR5cGU9IlBST0NFU1MiIHhtcEc6Y3lhbj0iMTAu +MDAwMDAyIiB4bXBHOm1hZ2VudGE9IjEwMC4wMDAwMDAiIHhtcEc6eWVsbG93PSI1MC4wMDAwMDAi +IHhtcEc6YmxhY2s9IjAuMDAwMDAwIi8+IDxyZGY6bGkgeG1wRzpzd2F0Y2hOYW1lPSJDPTAgTT05 +NSBZPTIwIEs9MCIgeG1wRzptb2RlPSJDTVlLIiB4bXBHOnR5cGU9IlBST0NFU1MiIHhtcEc6Y3lh +bj0iMC4wMDAwMDAiIHhtcEc6bWFnZW50YT0iOTQuOTk5OTk5IiB4bXBHOnllbGxvdz0iMTkuOTk5 +OTk5IiB4bXBHOmJsYWNrPSIwLjAwMDAwMCIvPiA8cmRmOmxpIHhtcEc6c3dhdGNoTmFtZT0iQz0y +NSBNPTI1IFk9NDAgSz0wIiB4bXBHOm1vZGU9IkNNWUsiIHhtcEc6dHlwZT0iUFJPQ0VTUyIgeG1w +RzpjeWFuPSIyNS4wMDAwMDAiIHhtcEc6bWFnZW50YT0iMjUuMDAwMDAwIiB4bXBHOnllbGxvdz0i +MzkuOTk5OTk4IiB4bXBHOmJsYWNrPSIwLjAwMDAwMCIvPiA8cmRmOmxpIHhtcEc6c3dhdGNoTmFt +ZT0iQz00MCBNPTQ1IFk9NTAgSz01IiB4bXBHOm1vZGU9IkNNWUsiIHhtcEc6dHlwZT0iUFJPQ0VT +UyIgeG1wRzpjeWFuPSIzOS45OTk5OTgiIHhtcEc6bWFnZW50YT0iNDQuOTk5OTk5IiB4bXBHOnll +bGxvdz0iNTAuMDAwMDAwIiB4bXBHOmJsYWNrPSI1LjAwMDAwMSIvPiA8cmRmOmxpIHhtcEc6c3dh +dGNoTmFtZT0iQz01MCBNPTUwIFk9NjAgSz0yNSIgeG1wRzptb2RlPSJDTVlLIiB4bXBHOnR5cGU9 +IlBST0NFU1MiIHhtcEc6Y3lhbj0iNTAuMDAwMDAwIiB4bXBHOm1hZ2VudGE9IjUwLjAwMDAwMCIg +eG1wRzp5ZWxsb3c9IjYwLjAwMDAwMiIgeG1wRzpibGFjaz0iMjUuMDAwMDAwIi8+IDxyZGY6bGkg +eG1wRzpzd2F0Y2hOYW1lPSJDPTU1IE09NjAgWT02NSBLPTQwIiB4bXBHOm1vZGU9IkNNWUsiIHht +cEc6dHlwZT0iUFJPQ0VTUyIgeG1wRzpjeWFuPSI1NS4wMDAwMDEiIHhtcEc6bWFnZW50YT0iNjAu +MDAwMDAyIiB4bXBHOnllbGxvdz0iNjQuOTk5OTk4IiB4bXBHOmJsYWNrPSIzOS45OTk5OTgiLz4g +PHJkZjpsaSB4bXBHOnN3YXRjaE5hbWU9IkM9MjUgTT00MCBZPTY1IEs9MCIgeG1wRzptb2RlPSJD +TVlLIiB4bXBHOnR5cGU9IlBST0NFU1MiIHhtcEc6Y3lhbj0iMjUuMDAwMDAwIiB4bXBHOm1hZ2Vu +dGE9IjM5Ljk5OTk5OCIgeG1wRzp5ZWxsb3c9IjY0Ljk5OTk5OCIgeG1wRzpibGFjaz0iMC4wMDAw +MDAiLz4gPHJkZjpsaSB4bXBHOnN3YXRjaE5hbWU9IkM9MzAgTT01MCBZPTc1IEs9MTAiIHhtcEc6 +bW9kZT0iQ01ZSyIgeG1wRzp0eXBlPSJQUk9DRVNTIiB4bXBHOmN5YW49IjMwLjAwMDAwMSIgeG1w +RzptYWdlbnRhPSI1MC4wMDAwMDAiIHhtcEc6eWVsbG93PSI3NS4wMDAwMDAiIHhtcEc6YmxhY2s9 +IjEwLjAwMDAwMiIvPiA8cmRmOmxpIHhtcEc6c3dhdGNoTmFtZT0iQz0zNSBNPTYwIFk9ODAgSz0y +NSIgeG1wRzptb2RlPSJDTVlLIiB4bXBHOnR5cGU9IlBST0NFU1MiIHhtcEc6Y3lhbj0iMzUuMDAw +MDAyIiB4bXBHOm1hZ2VudGE9IjYwLjAwMDAwMiIgeG1wRzp5ZWxsb3c9IjgwLjAwMDAwMSIgeG1w +RzpibGFjaz0iMjUuMDAwMDAwIi8+IDxyZGY6bGkgeG1wRzpzd2F0Y2hOYW1lPSJDPTQwIE09NjUg +WT05MCBLPTM1IiB4bXBHOm1vZGU9IkNNWUsiIHhtcEc6dHlwZT0iUFJPQ0VTUyIgeG1wRzpjeWFu +PSIzOS45OTk5OTgiIHhtcEc6bWFnZW50YT0iNjQuOTk5OTk4IiB4bXBHOnllbGxvdz0iOTAuMDAw +MDA0IiB4bXBHOmJsYWNrPSIzNS4wMDAwMDIiLz4gPHJkZjpsaSB4bXBHOnN3YXRjaE5hbWU9IkM9 +NDAgTT03MCBZPTEwMCBLPTUwIiB4bXBHOm1vZGU9IkNNWUsiIHhtcEc6dHlwZT0iUFJPQ0VTUyIg +eG1wRzpjeWFuPSIzOS45OTk5OTgiIHhtcEc6bWFnZW50YT0iNjkuOTk5OTk5IiB4bXBHOnllbGxv +dz0iMTAwLjAwMDAwMCIgeG1wRzpibGFjaz0iNTAuMDAwMDAwIi8+IDxyZGY6bGkgeG1wRzpzd2F0 +Y2hOYW1lPSJDPTUwIE09NzAgWT04MCBLPTcwIiB4bXBHOm1vZGU9IkNNWUsiIHhtcEc6dHlwZT0i +UFJPQ0VTUyIgeG1wRzpjeWFuPSI1MC4wMDAwMDAiIHhtcEc6bWFnZW50YT0iNjkuOTk5OTk5IiB4 +bXBHOnllbGxvdz0iODAuMDAwMDAxIiB4bXBHOmJsYWNrPSI2OS45OTk5OTkiLz4gPC9yZGY6U2Vx +PiA8L3htcEc6Q29sb3JhbnRzPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6bGk+IDxyZGY6bGk+ +IDxyZGY6RGVzY3JpcHRpb24geG1wRzpncm91cE5hbWU9IuaJk+WNsOminOiJsue7hCIgeG1wRzpn +cm91cFR5cGU9IjEiPiA8eG1wRzpDb2xvcmFudHM+IDxyZGY6U2VxPiA8cmRmOmxpIHhtcEc6c3dh +dGNoTmFtZT0iQz0wIE09MzAgWT03MCBLPTAiIHhtcEc6bW9kZT0iQ01ZSyIgeG1wRzp0eXBlPSJQ +Uk9DRVNTIiB4bXBHOmN5YW49IjAuMDAwMDAwIiB4bXBHOm1hZ2VudGE9IjMwLjAwMDAwMSIgeG1w +Rzp5ZWxsb3c9IjY5Ljk5OTk5OSIgeG1wRzpibGFjaz0iMC4wMDAwMDAiLz4gPHJkZjpsaSB4bXBH +OnN3YXRjaE5hbWU9IkM9NSBNPTcwIFk9OTAgSz0wIiB4bXBHOm1vZGU9IkNNWUsiIHhtcEc6dHlw +ZT0iUFJPQ0VTUyIgeG1wRzpjeWFuPSI1LjAwMDAwMSIgeG1wRzptYWdlbnRhPSI2OS45OTk5OTki +IHhtcEc6eWVsbG93PSI5MC4wMDAwMDQiIHhtcEc6YmxhY2s9IjAuMDAwMDAwIi8+IDxyZGY6bGkg +eG1wRzpzd2F0Y2hOYW1lPSJDPTUgTT05MCBZPTc1IEs9MCIgeG1wRzptb2RlPSJDTVlLIiB4bXBH +OnR5cGU9IlBST0NFU1MiIHhtcEc6Y3lhbj0iNS4wMDAwMDEiIHhtcEc6bWFnZW50YT0iOTAuMDAw +MDA0IiB4bXBHOnllbGxvdz0iNzUuMDAwMDAwIiB4bXBHOmJsYWNrPSIwLjAwMDAwMCIvPiA8cmRm +OmxpIHhtcEc6c3dhdGNoTmFtZT0iQz0zMCBNPTAgWT05NSBLPTAiIHhtcEc6bW9kZT0iQ01ZSyIg +eG1wRzp0eXBlPSJQUk9DRVNTIiB4bXBHOmN5YW49IjMwLjAwMDAwMSIgeG1wRzptYWdlbnRhPSIw +LjAwMDAwMCIgeG1wRzp5ZWxsb3c9Ijk0Ljk5OTk5OSIgeG1wRzpibGFjaz0iMC4wMDAwMDAiLz4g +PHJkZjpsaSB4bXBHOnN3YXRjaE5hbWU9IkM9NjAgTT01IFk9OTUgSz0wIiB4bXBHOm1vZGU9IkNN +WUsiIHhtcEc6dHlwZT0iUFJPQ0VTUyIgeG1wRzpjeWFuPSI2MC4wMDAwMDIiIHhtcEc6bWFnZW50 +YT0iNS4wMDAwMDEiIHhtcEc6eWVsbG93PSI5NC45OTk5OTkiIHhtcEc6YmxhY2s9IjAuMDAwMDAw +Ii8+IDxyZGY6bGkgeG1wRzpzd2F0Y2hOYW1lPSJDPTMwIE09MCBZPTEwIEs9MCIgeG1wRzptb2Rl +PSJDTVlLIiB4bXBHOnR5cGU9IlBST0NFU1MiIHhtcEc6Y3lhbj0iMzAuMDAwMDAxIiB4bXBHOm1h +Z2VudGE9IjAuMDAwMDAwIiB4bXBHOnllbGxvdz0iMTAuMDAwMDAyIiB4bXBHOmJsYWNrPSIwLjAw +MDAwMCIvPiA8cmRmOmxpIHhtcEc6c3dhdGNoTmFtZT0iQz02MCBNPTEwIFk9NSBLPTAiIHhtcEc6 +bW9kZT0iQ01ZSyIgeG1wRzp0eXBlPSJQUk9DRVNTIiB4bXBHOmN5YW49IjYwLjAwMDAwMiIgeG1w +RzptYWdlbnRhPSIxMC4wMDAwMDIiIHhtcEc6eWVsbG93PSI1LjAwMDAwMSIgeG1wRzpibGFjaz0i +MC4wMDAwMDAiLz4gPHJkZjpsaSB4bXBHOnN3YXRjaE5hbWU9IkM9ODAgTT01IFk9MTAgSz0wIiB4 +bXBHOm1vZGU9IkNNWUsiIHhtcEc6dHlwZT0iUFJPQ0VTUyIgeG1wRzpjeWFuPSI4MC4wMDAwMDEi +IHhtcEc6bWFnZW50YT0iNS4wMDAwMDEiIHhtcEc6eWVsbG93PSIxMC4wMDAwMDIiIHhtcEc6Ymxh +Y2s9IjAuMDAwMDAwIi8+IDwvcmRmOlNlcT4gPC94bXBHOkNvbG9yYW50cz4gPC9yZGY6RGVzY3Jp +cHRpb24+IDwvcmRmOmxpPiA8cmRmOmxpPiA8cmRmOkRlc2NyaXB0aW9uIHhtcEc6Z3JvdXBOYW1l +PSLngbDluqYiIHhtcEc6Z3JvdXBUeXBlPSIxIj4gPHhtcEc6Q29sb3JhbnRzPiA8cmRmOlNlcT4g +PHJkZjpsaSB4bXBHOnN3YXRjaE5hbWU9Iks9MTAwIiB4bXBHOm1vZGU9IkdSQVkiIHhtcEc6dHlw +ZT0iUFJPQ0VTUyIgeG1wRzpncmF5PSIyNTUiLz4gPHJkZjpsaSB4bXBHOnN3YXRjaE5hbWU9Iks9 +OTAiIHhtcEc6bW9kZT0iR1JBWSIgeG1wRzp0eXBlPSJQUk9DRVNTIiB4bXBHOmdyYXk9IjIyOSIv +PiA8cmRmOmxpIHhtcEc6c3dhdGNoTmFtZT0iSz04MCIgeG1wRzptb2RlPSJHUkFZIiB4bXBHOnR5 +cGU9IlBST0NFU1MiIHhtcEc6Z3JheT0iMjAzIi8+IDxyZGY6bGkgeG1wRzpzd2F0Y2hOYW1lPSJL +PTcwIiB4bXBHOm1vZGU9IkdSQVkiIHhtcEc6dHlwZT0iUFJPQ0VTUyIgeG1wRzpncmF5PSIxNzgi +Lz4gPHJkZjpsaSB4bXBHOnN3YXRjaE5hbWU9Iks9NjAiIHhtcEc6bW9kZT0iR1JBWSIgeG1wRzp0 +eXBlPSJQUk9DRVNTIiB4bXBHOmdyYXk9IjE1MiIvPiA8cmRmOmxpIHhtcEc6c3dhdGNoTmFtZT0i +Sz01MCIgeG1wRzptb2RlPSJHUkFZIiB4bXBHOnR5cGU9IlBST0NFU1MiIHhtcEc6Z3JheT0iMTI3 +Ii8+IDxyZGY6bGkgeG1wRzpzd2F0Y2hOYW1lPSJLPTQwIiB4bXBHOm1vZGU9IkdSQVkiIHhtcEc6 +dHlwZT0iUFJPQ0VTUyIgeG1wRzpncmF5PSIxMDEiLz4gPHJkZjpsaSB4bXBHOnN3YXRjaE5hbWU9 +Iks9MzAiIHhtcEc6bW9kZT0iR1JBWSIgeG1wRzp0eXBlPSJQUk9DRVNTIiB4bXBHOmdyYXk9Ijc2 +Ii8+IDxyZGY6bGkgeG1wRzpzd2F0Y2hOYW1lPSJLPTIwIiB4bXBHOm1vZGU9IkdSQVkiIHhtcEc6 +dHlwZT0iUFJPQ0VTUyIgeG1wRzpncmF5PSI1MCIvPiA8cmRmOmxpIHhtcEc6c3dhdGNoTmFtZT0i +Sz0xMCIgeG1wRzptb2RlPSJHUkFZIiB4bXBHOnR5cGU9IlBST0NFU1MiIHhtcEc6Z3JheT0iMjUi +Lz4gPHJkZjpsaSB4bXBHOnN3YXRjaE5hbWU9Iks9NSIgeG1wRzptb2RlPSJHUkFZIiB4bXBHOnR5 +cGU9IlBST0NFU1MiIHhtcEc6Z3JheT0iMTIiLz4gPC9yZGY6U2VxPiA8L3htcEc6Q29sb3JhbnRz +PiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6bGk+IDwvcmRmOlNlcT4gPC94bXBUUGc6U3dhdGNo +R3JvdXBzPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8P3hwYWNrZXQg +ZW5kPSJ3Ij8+/+0cAFBob3Rvc2hvcCAzLjAAOEJJTQQEAAAAAAAQHAIAAAIAABwCBQAEtPLToThC +SU0EJQAAAAAAELUh3zEtnkjQtuhmLg31Ht44QklNA+0AAAAAABABLAAAAAEAAQEsAAAAAQABOEJJ +TQQmAAAAAAAOAAAAAAAAAAAAAD+AAAA4QklNBA0AAAAAAAQAAAAeOEJJTQQZAAAAAAAEAAAAHjhC +SU0D8wAAAAAACQAAAAAAAAAAAQA4QklNJxAAAAAAAAoAAQAAAAAAAAACOEJJTQP1AAAAAABIAC9m +ZgABAGxmZgAGAAAAAAABAC9mZgABAKGZmgAGAAAAAAABADIAAAABAFoAAAAGAAAAAAABADUAAAAB +AC0AAAAGAAAAAAABOEJJTQP4AAAAAABwAAD/////////////////////////////A+gAAAAA//// +/////////////////////////wPoAAAAAP////////////////////////////8D6AAAAAD///// +////////////////////////A+gAADhCSU0ECAAAAAAAEAAAAAEAAAJAAAACQAAAAAA4QklNBB4A +AAAAAAQAAAAAOEJJTQQaAAAAAANFAAAABgAAAAAAAAAAAAAC9QAAAk8AAAAIAGwAaQBuAHUAeAAt +ADAAMQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAACTwAAAvUAAAAAAAAAAAAAAAAA +AAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAQAAAAAAAG51bGwAAAACAAAABmJvdW5kc09iamMA +AAABAAAAAAAAUmN0MQAAAAQAAAAAVG9wIGxvbmcAAAAAAAAAAExlZnRsb25nAAAAAAAAAABCdG9t +bG9uZwAAAvUAAAAAUmdodGxvbmcAAAJPAAAABnNsaWNlc1ZsTHMAAAABT2JqYwAAAAEAAAAAAAVz +bGljZQAAABIAAAAHc2xpY2VJRGxvbmcAAAAAAAAAB2dyb3VwSURsb25nAAAAAAAAAAZvcmlnaW5l +bnVtAAAADEVTbGljZU9yaWdpbgAAAA1hdXRvR2VuZXJhdGVkAAAAAFR5cGVlbnVtAAAACkVTbGlj +ZVR5cGUAAAAASW1nIAAAAAZib3VuZHNPYmpjAAAAAQAAAAAAAFJjdDEAAAAEAAAAAFRvcCBsb25n +AAAAAAAAAABMZWZ0bG9uZwAAAAAAAAAAQnRvbWxvbmcAAAL1AAAAAFJnaHRsb25nAAACTwAAAAN1 +cmxURVhUAAAAAQAAAAAAAG51bGxURVhUAAAAAQAAAAAAAE1zZ2VURVhUAAAAAQAAAAAABmFsdFRh +Z1RFWFQAAAABAAAAAAAOY2VsbFRleHRJc0hUTUxib29sAQAAAAhjZWxsVGV4dFRFWFQAAAABAAAA +AAAJaG9yekFsaWduZW51bQAAAA9FU2xpY2VIb3J6QWxpZ24AAAAHZGVmYXVsdAAAAAl2ZXJ0QWxp +Z25lbnVtAAAAD0VTbGljZVZlcnRBbGlnbgAAAAdkZWZhdWx0AAAAC2JnQ29sb3JUeXBlZW51bQAA +ABFFU2xpY2VCR0NvbG9yVHlwZQAAAABOb25lAAAACXRvcE91dHNldGxvbmcAAAAAAAAACmxlZnRP +dXRzZXRsb25nAAAAAAAAAAxib3R0b21PdXRzZXRsb25nAAAAAAAAAAtyaWdodE91dHNldGxvbmcA +AAAAADhCSU0EKAAAAAAADAAAAAI/8AAAAAAAADhCSU0EEQAAAAAAAQEAOEJJTQQUAAAAAAAEAAAA +AThCSU0EDAAAAAAWMAAAAAEAAAB9AAAAoAAAAXgAAOsAAAAWFAAYAAH/2P/gABBKRklGAAECAABI +AEgAAP/tAAxBZG9iZV9DTQAC/+4ADkFkb2JlAGSAAAAAAf/bAIQADAgICAkIDAkJDBELCgsRFQ8M +DA8VGBMTFRMTGBEMDAwMDAwRDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAENCwsNDg0QDg4Q +FA4ODhQUDg4ODhQRDAwMDAwREQwMDAwMDBEMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwM/8AA +EQgAoAB9AwEiAAIRAQMRAf/dAAQACP/EAT8AAAEFAQEBAQEBAAAAAAAAAAMAAQIEBQYHCAkKCwEA +AQUBAQEBAQEAAAAAAAAAAQACAwQFBgcICQoLEAABBAEDAgQCBQcGCAUDDDMBAAIRAwQhEjEFQVFh +EyJxgTIGFJGhsUIjJBVSwWIzNHKC0UMHJZJT8OHxY3M1FqKygyZEk1RkRcKjdDYX0lXiZfKzhMPT +dePzRieUpIW0lcTU5PSltcXV5fVWZnaGlqa2xtbm9jdHV2d3h5ent8fX5/cRAAICAQIEBAMEBQYH +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 +U4Q36DT5mj0F2z//2Q== + +------=_NextPart_000_0003_01CB9D0D.783DE8D0 +Content-Type: image/jpeg; + name="1_jiangsheng.jpg" +Content-Transfer-Encoding: base64 +Content-Location: http://avatar.profile.csdn.net/F/E/8/1_jiangsheng.jpg + +/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0a +HBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIy +MjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABkAGQDASIA +AhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQA +AAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3 +ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWm +p6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEA +AwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSEx +BhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElK +U1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3 +uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD3/tXE ++Nvij4e8EI8NzN9q1LblbKA5f/gR6IPrz6A1118JG065EMphlMTBJAAdhwcHn0618PzGO6urid5Z +ZmlZm8ydsvIeSXb8OfqR1pN2Glc2/HHxH13x3fM91I1vYJ/qrKFj5aD1b+83ufwxXPQ2ryWsESLm +S4cnj0HH+NVt4FuEUdTn6n1pYpblvkh3sQpUbecKeopO41Y0PsFusot4Q9w7Hb8gzubuF9h69Pft +VO5hkjlkhURqkYy2xsj/AL67n9K2LDQtaeBY7e3kje4IUPjB298nsv8AOt2TwTeCEWVvE0suA2W4 +Gem9v5Ae31rB1YxerN1SlJaI5jSrVbqwuYrhxDDCfNaQ9jjG0e5/pWYyKsm7DhTyrEdvWvVLT4eb +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 +60Yei/I4Y/CgooorYo//2Q== + +------=_NextPart_000_0003_01CB9D0D.783DE8D0 +Content-Type: image/gif; + name="link_logo01.gif" +Content-Transfer-Encoding: base64 +Content-Location: http://csdnimg.cn/www/images/link_logo01.gif + +R0lGODlhcgAyAPcAAAAAAP///2tpamlnaH59fn18fXl4eXZ1dnRzdHFwcXBvcG1sbYiHiIaFhoWE +hYSDhIKBgoB/gO7u+PDw+Pn5/f39//n5+vT09e/v8Onp6tzc3dra29jY2dfX2NTU1czMzcvLzLy8 +vbu7vLm5urW1trS0tbOztK+vsK6ur62trqenqKamp6WlpqOjpJubnJqam5iYmYuLjIqKi4mJioiI +iYeHiIWFhoODhIKCg4GBgtrb7uDh8b7B4cnL5s3P6NDS6tLU6+Xm9OTl8+jp9aWq1bW53bi83sHE +48fK5tbY7d3f8Ovs9oyUyZSbzZifz52j0aGn06et1quw2K2y2bC12+Lk8vHy+YONxYaPx4mSyI6X +y/P0+mx6u3WBvneDwHqGwX6Jw4eSyPb3/PX2+3F/vff4/FJmr1tus15xtWJ0t2R2uGd4uUlgq1Rq +sUpkrk5nsDlYpkJfq0djrTVYpzdbqDxdqSpTpDBWpfv8/iNPoSRSowA4lAA2khlOoR5PogA+lwA7 +lgA8lgA7lRNNoBNJnQBDmgBCmQBBmQA/mAdHnApHnQ5KngBHnQFJngFFmwdLn83Oz8TFxry9vrm6 +u7e4uf7///n6+vP09PLz8/Hy8vDx8enq6ufo6OXm5t/g4NXW1tLT09DR0c/Q0MjJycfIyMLDw7/A +wLq7u7i5uba3t7Gysq+wsK2urqytrausrKqrq6ipqaeoqKWmpqSlpaOkpKChoZ2enpaXl2FgX15d +XFxbWltaWVlYV1hXVlVTUlRSUVNRUFJQT1hWVVZUU0hERFRRUU9MTE1KSmFfX1tZWVZUVH59fXp5 +eXh3d3Rzc3JxcXBvb25tbWxra2tqamppaWloaGhnZ2dmZmZlZWVkZGRjY2NiYmJhYWFgYF9eXv7+ +/v39/fr6+vn5+fb29u3t7ezs7Ovr6+rq6unp6ePj4+Hh4d7e3pWVlZOTk5GRkZCQkI6Ojo2NjYyM +jIeHh4GBgX5+fnt7e3p6enh4eHd3d3V1dXR0dHNzc3Jycm5ubv///yH5BAEAAP8ALAAAAAByADIA +AAj/AAMIHEiwoMGDCBMqXMiwocOHECMqrDQESRQmZM68kePmDJksRI7sGCOxpMmTELcc+VKHkSA+ +exzRQQOmyRMoRKJIKXJEBwWUQIOeBOLFz589ewq5ceIjCQ8nX9K0cSPnzRkuYJzwCFJJqNevCH2c +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 + +------=_NextPart_000_0003_01CB9D0D.783DE8D0 +Content-Type: image/gif; + name="link_logo02.gif" +Content-Transfer-Encoding: base64 +Content-Location: http://csdnimg.cn/www/images/link_logo02.gif + +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 + +------=_NextPart_000_0003_01CB9D0D.783DE8D0 +Content-Type: image/gif; + name="link_logo04.gif" +Content-Transfer-Encoding: base64 +Content-Location: http://csdnimg.cn/www/images/link_logo04.gif + +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 +DggAOw== + +------=_NextPart_000_0003_01CB9D0D.783DE8D0-- + diff --git a/lib_acl_cpp/samples/mime/test13.eml b/lib_acl_cpp/samples/mime/test13.eml new file mode 100644 index 000000000..719877e4a --- /dev/null +++ b/lib_acl_cpp/samples/mime/test13.eml @@ -0,0 +1,9 @@ +mail:foo@localhost.localdomain +rcpt:admin@test.com + +From: +To: +Date: Fri, 17 Dec 2010 09:55:10 +0800 (CST) +Message-Id: <4f9f.0003.ffffffed@localhost.localdomain> + +XXXXXXXXXX \ No newline at end of file diff --git a/lib_acl_cpp/samples/mime/test14.eml b/lib_acl_cpp/samples/mime/test14.eml new file mode 100644 index 000000000..5a2b10e9b --- /dev/null +++ b/lib_acl_cpp/samples/mime/test14.eml @@ -0,0 +1,11 @@ +Return-Path: +Delivered-To: train_spam@renwou.com +Received: by 51zebra.com (zebra mail for UNIX, from userid 508) + id CADBE282C4D; Wed, 17 Nov 2010 16:46:55 +0800 (CST) +Date: Wed, 17 Nov 2010 08:46:55 GMT +From: +To: "admin" +Subject: =?GB2312?B?sKy/y8j8wNY=?= +Content-Type: text/plain; charset="GB2312" + +hello diff --git a/lib_acl_cpp/samples/mime/test15.eml b/lib_acl_cpp/samples/mime/test15.eml new file mode 100644 index 000000000..05bd1a600 --- /dev/null +++ b/lib_acl_cpp/samples/mime/test15.eml @@ -0,0 +1,23 @@ +Return-Path: +Delivered-To: zsxxsz@test.com +Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) + by 51zebra.com (zebra mail for UNIX) with SMTP id BA21B286C0B + for ; Wed, 12 Jan 2011 13:47:52 +0800 (CST) +From: +To: +Date: Wed, 12 Jan 2011 13:47:52 +0800 (CST) +Message-Id: <43e8.0003.0000@localhost.localdomain> + +1XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +2XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +3XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +4XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +5XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +6XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +7XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +8XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +9XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +0XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +1XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +2XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX diff --git a/lib_acl_cpp/samples/mime/test16.eml b/lib_acl_cpp/samples/mime/test16.eml new file mode 100644 index 000000000..dbccdbc9c --- /dev/null +++ b/lib_acl_cpp/samples/mime/test16.eml @@ -0,0 +1,12 @@ +mail:foo@localhost.localdomain +rcpt:zhujunxing@test.com + +From: +To: +Date: Thu, 13 Jan 2011 17:01:41 +0800 (CST) +Message-Id: <30be.0003.ffffffee@localhost.localdomain> +Subject: testmail1 + +1XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +2XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX \ No newline at end of file diff --git a/lib_acl_cpp/samples/mime/test17.eml b/lib_acl_cpp/samples/mime/test17.eml new file mode 100644 index 000000000..fe214f39c --- /dev/null +++ b/lib_acl_cpp/samples/mime/test17.eml @@ -0,0 +1,47 @@ +Received: from SNT125-W63 ([65.55.90.135]) by +snt0-omc3-s41.snt0.hotmail.com with Microsoft SMTPSVC(6.0.3790.4675); + Mon, 24 Jan 2011 22:56:19 -0800 +Message-ID: +Return-Path: zhengshuxin@hotmail.com +Content-Type: multipart/alternative; + boundary="_c6f0ecf0-3276-4861-9ce3-8810ea7e3544_" +X-Originating-IP: [123.122.115.249] +From: =?gb2312?B?1qPK99DC?= +To: "zsx" +Subject: ttt +Date: Tue, 25 Jan 2011 06:56:19 +0000 +Importance: Normal +MIME-Version: 1.0 +X-OriginalArrivalTime: 25 Jan 2011 06:56:19.0926 (UTC) +FILETIME=[F850F760:01CBBC5C] + +--_c6f0ecf0-3276-4861-9ce3-8810ea7e3544_ +Content-Type: text/plain; charset="gb2312" +Content-Transfer-Encoding: 8bit + + +ttt +--_c6f0ecf0-3276-4861-9ce3-8810ea7e3544_ +Content-Type: text/html; charset="gb2312" +Content-Transfer-Encoding: 8bit + + + + + + +ttt + +--_c6f0ecf0-3276-4861-9ce3-8810ea7e3544_-- + diff --git a/lib_acl_cpp/samples/mime/test18.eml b/lib_acl_cpp/samples/mime/test18.eml new file mode 100644 index 000000000..ad9642c26 --- /dev/null +++ b/lib_acl_cpp/samples/mime/test18.eml @@ -0,0 +1,172 @@ +Return-path: +Received: from ([<202.108.3.242>]) + by (Postfix) with LMTP id <35050> + Aug 28 2010 07:22:37 +0800 (CST) +Received: from ir5-172.sinamail.sina.com.cn (unknown [10.55.5.172]) + by mx3-24.sinamail.sina.com.cn (Postfix) with ESMTP id 967A711093D0 + for ; Sat, 28 Aug 2010 07:13:11 +0800 (CST) +Received-SPF: Pass identity=mailfrom; client-ip=209.144.21.188; + receiver=ir5-172.sinamail.sina.com.cn; + envelope-from="returns@g.cn.newenlighten.net"; + x-sender="returns@g.cn.newenlighten.net"; + x-conformance=spf_only; + x-record-type="v=spf1" +Received: from g.cn.newenlighten.net ([209.144.21.188]) + by ir5-172.sinamail.sina.com.cn with ESMTP; 28 Aug 2010 07:13:09 +0800 +Received: by g.cn.newenlighten.net (Postfix, from userid 0) + id C759433952E; Fri, 27 Aug 2010 03:59:47 -0500 (CDT) +To: synbada@sina.com +Subject: =?utf-8?B?5Lit56eL6IqC5LiN6YCB5pyI6aW85Yi45L2g5bCxT1VU5LqG?= +Message-ID: <1282899587_SectionID-27569_HitID-1282894000806_SiteID-6373_EmailID-7770665_DB-34_SID-37@cn.newenlighten.net> +List-Unsubscribe: +DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=cn.newenlighten.net; i=@cn.newenlighten.net; q=dns/txt; s=gcnmailerd; t=1282899517; h=From; bh=47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=; l=0; b=To0wpoOVesxBLRFnQTftJgxMNfx1LQRDN1WkAuzBwJo+jAL6Y/xm7LyojdBkaF7/fiFEn7x2orMrKpb/1OSAf+GCLw2xkASAAc6EHObvYDESVmSPDjJiEC1pkUOhIkH/QdbFhZ65MvFW4bt1NEDBVWMUhAA9ilFcAyGppgY4p/M= +From: "=?utf-8?B?5LyY5Yi4572R?=" +Mime-Version: 1.0 +Content-Type: multipart/alternative; + boundary="1991dde0f0753c600bc8cdf29d510f96" +Date: Fri, 27 Aug 2010 03:59:47 -0500 (CDT) + + +--1991dde0f0753c600bc8cdf29d510f96 +Content-Type: text/plain; charset=utf-8 +Content-Transfer-Encoding: quoted-printable + + =0A=E6=82=A8=E6=AD=A3=E5=9C=A8=E4=BD=BF=E7=94=A8=E7=9A=84=E9=82=AE=E4=BB= +=B6=E6=B5=8F=E8=A7=88=E5=B7=A5=E5=85=B7=E4=B8=8D=E6=94=AF=E6=8C=81HTML. =E6= +=83=B3=E8=A6=81=E6=9F=A5=E7=9C=8B=E6=9C=AC=E9=82=AE=E4=BB=B6, =E8=AF=B7=E7= +=82=B9=E5=87=BB=E4=B8=8B=E9=9D=A2=E7=9A=84=E9=93=BE=E6=8E=A5.=0Ahttp://g.cn= +.newenlighten.net/new/en_send_preview_iframe2.aspx?SID=3D37&NewsletterID=3D= +27569&SiteID=3D6373&EmailID=3D7770665&HitID=3D1282894000806&token=3D4b92f73= +c2fc2794ae16db6f12b6e04ba01df542a=0A=0A=E7=82=B9=E5=87=BB=E4=BB=A5=E4=B8=8B= +=E9=93=BE=E6=8E=A5,=E8=BF=9B=E8=A1=8C=E9=80=80=E8=AE=A2.=0Ahttp://g.cn.newe= +nlighten.net/RWCode/subscribe.asp?SID=3D37&SiteID=3D6373&Email=3Dsynbada@si= +na.com&HitID=3D1282894000806 +--1991dde0f0753c600bc8cdf29d510f96 +Content-Transfer-Encoding: quoted-printable +Content-Type: text/html; charset=utf-8 + + + + +优券网edm + + + + + + + + + + + + + + + + + + +
  + +
+ +
 
+ +
+=0A=0A=0A
=0A=0A=0A
=0A=09=0A=09=0A=0A=0A=0A=0A=0A
= +=0A=0A=0A=09=0A=09=09=0A=09=09=09=0A=09=09= +=0A=09=09=0A=09=09=09=0A=09= +=09=0A=09=09=0A=09=09=09=0A=09=09=0A= +=0A=0A=09
=0A=09=09=09= +=09=0A=09=09=09=09=09=0A=09=09=09=09=09=09=0A=09=09=09=09
=0A= +=09=09=09=09=09=09=09=0A=09=09=09=09= +=09=09=09=09=0A=09=09=09=09=09=09=09=09=09=0A=09=09=09=09=09=09= +=09=09=0A=09=09=09=09=09=09=09=09=0A=09=09=09=09=09=09=09=09=09 =0A=09=09=09=09=09=09=09=09=0A=09=09=09=09= +=09=09=09=09=0A=09=09=09=09=09=09=09=09=09=0A=09=09=09= +=09=09=09=09=09=0A=09=09=09=09=09=09=09
=0A=09= +=09=09=09=09=09=09=09=09=09=0A=09=09=09=09=09=09=09=09=09=09=0A=09=09=09=09=09=09=09=09=09=09= +=09=09=09=09=09=09=09=09=09=09=09=0A=09=09=09=09=09=09=09=09=09=09=09=0A=09=09=09=09=09=09=09=09=09=09= +=09=09=0A=09=09=09=09=09=09=09=09=09=09=09=09=09=09=09=09=09=09=09=09=09=09= +=09=09=0A=09=09=09=09=09=09=09=09=09=09=09=09=0A= +=09=09=09=09=09=09=09=09=09=09=09=09=0A=09=09=09=09=09=09=09=09=09=09=09=09= +=0A=09=09=09=09=09=09=09=09=09=09=09=09=09=09=09=09=09=09=09=09=09=09=09=09= +=0A=09=09=09=09=09=09=09=09=09=09=09=09=0A=09=09=09=09=09=09=09=09=09=09=09= +=09=0A=09=09=09=09=09=09=09=09=09=09=09=09=09=09=09=09=09=09=09=09=09=09=09= +=09=0A=09=09=09=09=09=09=09=09=09=09=09=09=0A=09=09=09=09=09=09=09=09=09=09= +=09=09=09=09=09=09=09=09=09=09=09=09=09=09=0A=09=09=09=09=09=09=09=09=09=09= +=09=09=0A=09=09=09=09=09=09=09=09=09=09=09=09=09=09=09=09=09=09=09=09=09=09= +=09=09=0A=09=09=09=09=09=09=09=09=09=09=09=09=0A=09=09=09=09=09=09=09=09=09= +=09=09=09=09=09=09=09=09=09=09=09=09=09=09=09=0A=09=09=09=09=09=09=09=09=09= +=09=09=09=0A=09=09=09=09=09=09=09=09=09=09=09=09=09=09=09=09=09=09=09=09=09= +=09=09=09=0A=09=09=09=09=09=09=09=09=09=09=09=0A=09=09=09=09=09=09=09= +=09=09=09
=0A=09=09=09=09=09=09=09=09=09=09=09=09=09取消订阅=0A=09=09=09= +=09=09=09=09=09=09=09=09=09
=0A=09=09=09=09=09=09=09=09=09
=0A=09= +=09=09=09=09=09=09=09=09=09=0A=09=09=09=09=09=09=09=09=09=09=09= +=0A=09=09=09=09=09=09=09=09=09=09=09=09=0A=09=09=09=09=09=09=09=09=09=09=09=09=0A=09=09=09=09=09=09=09=09=09=09=09=09=0A=09=09=09=09=09=09=09=09=09=09=09=0A=09=09=09=09= +=09=09=09=09=09=09
=0A=09=09=09=09=09=09=09= +=09=09=09=09=09powered by=0A=09=09=09=09=09=09=09=09=09= +=09=09=09 =0A=09=09=09= +=09=09=09=09=09=09=09=09=09=0A=09=09=09=09=09=09=09=09=09=09=09=09=09=0A= +=09=09=09=09=09=09=09=09=09=09=09=09=09=09=09=09=09=09=09=09=09=09=09=09=09= +=09=09uquanwang=0A=09=09=09=09=09=09=09=09=09=09=09=09= +=09=09=09=09=09=09=09=09=09=09=09=09=09=09=0A=09=09=09=09=09=09=09=09= +=09=09=09=09
=0A=09=09=09=09=09=09=09=09=09
=0A=09=09=09=09=09=09=0A=09=09=09=09=09
=0A=09=09=09
=0A=09=09=09
=0A=09=09=09=0A=09=09=09=0A=09=09=09=09=09=09=0A=09=09=09=09=09=09=0A=09=09= +=09=09=09=09=09=09=09=0A=09=09=09=0A=09=09=09
=0A=0A=0A=0A=0A=0A
=0A
=0A=0A=0A=0A=0A=0A=0A + + + + + + +--1991dde0f0753c600bc8cdf29d510f96-- + + diff --git a/lib_acl_cpp/samples/mime/test19.eml b/lib_acl_cpp/samples/mime/test19.eml new file mode 100644 index 000000000..e9729004b --- /dev/null +++ b/lib_acl_cpp/samples/mime/test19.eml @@ -0,0 +1,2252 @@ +Return-Path: +Delivered-To: 51ikerkaifa@51iker.com +Received: from mail.checjy.com (unknown [125.40.37.20]) + by 51iker.com (zebra mail for UNIX) with SMTP id A141E27463F + for <51ikerkaifa@51iker.com>; Fri, 24 Dec 2010 01:50:17 +0800 (CST) +Received: from WWW-4A2AEA23563 ([60.14.97.38]) + (envelope-sender ) + by 192.168.0.15 with ESMTP + for <51ikerkaifa@51iker.com>; Fri, 24 Dec 2010 01:47:29 +0800 +From: =?GB2312?B?y86y/dS2?= +Reply-To: "Mr.aejnt" +To: "51ikerkaifa" <51ikerkaifa@51iker.com> +Subject: =?GB2312?B?0+u/zbuns/W0zrz7w+bSqsHLveLExDm49s7KzOKjv2VRME45?= +Message-ID: <201012240147254386791@hn.kd.ny.adsl> +Date: Fri, 24 Dec 2010 01:47:25 +0800 +X-Mailer: Foxmail 6, 10, 201, 20 [cn] +MIME-Version: 1.0 +Content-Type: multipart/mixed; boundary="----=zeioty211_5706_231298841.667468" +X-Priority: 3 + +This is a multi-part message in MIME format. + +------=zeioty211_5706_231298841.667468 +Content-Type: text/plain; + charset="GB2312" +Content-Transfer-Encoding: base64 + +VmlVZ7i9vP7E2sjdzqqjug0KDQoNCg0KaVVnUzFRIM/6ytu+q9OiMszs0rvSubfov/HRtcG3IFBV +WkU= + +------=zeioty211_5706_231298841.667468 +Content-Type: text/plain; + name="Chmrwa2094.pdf" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; + filename="Chmrwa2094.pdf" + +JVBERi0xLjMNCiXS5dHyDQo2IDAgb2JqDQo8PCAvUHJvY1NldCBbL1BERiAvVGV4dCBdDQovRm9u +dCA8PA0KL1RUMiA0IDAgUg0KL1RUMSA1IDAgUg0KPj4NCj4+DQplbmRvYmoNCjcgMCBvYmoNCjw8 +L0xlbmd0aCAxNzE3DQovRmlsdGVyIC9GbGF0ZURlY29kZQ0KPj4NCnN0cmVhbQ0KeJy9WduKbEkR +fW/of6hHDzjHiMg7DkLeNuKb2I++HBhHGFBxUH9Ewd91RVbtqpre0Xa1w9hNUV27YmeuuKyIlbv/ ++vzUXp6fyonwW06eTqn4zxLL6eVPz0+/eHmRE59evn1++trX4amROCnicg+/Or18tyz4YvEz+bRf +ut5EcxvkcOPcSFp2kkv0nNn5ks4L3O8c8v3Ot3WJ+bg0e5+PGMiy7KMblvkrKoZxa+VofMKP4Z0b +U5xvlv2ng3eert79RC6JfCXux7kkrgcaZCSHbmXxNXHfyNNGOQkVKRSEiQfhGnOrjWrqnls8rBJz +fLXK6EMLguGRFxd0FY60OV9RaKPCxu2Vp9el16DXqNCk0Zxld3+N3JxAGci35Kbr93b73rBJVKU7 +1s27P6KO2UbtHQ2pW1++O55GSnwio3ASp6Pt700GIaR+Tn80/7lZFzKZs1FFVq63KeqBsbRV6zNh +5Sp+ZrgeH76Rmwwe4t+4wcDlCrIR89B8GFH6ZICTcazYGOgua0GwXEG9NKcNiTkMLjGS9Lxn0aU2 +tW6Oe/7ywOboxOySWh2cU6EyWRoVsGAxw6B1CsHypBtclRwyHAig7PnPQG/Qt4SNeTraqlEx1h0I +xIZy7AiAM5vE0XW2B4S6Lm4bfkudS/WygaLKKO0LqADZxkYFlMQ0ID+CUlPtKMRNO6lvrSMoZbWD +PnnRFukR2qIPVXi4oiHdmwsGyjgkPaRXVN13dlH7AVJtJuPoZYh37VqDffrN37/54x/MjHnPJZPv +6Cnonjru3AYX81T4188YAHC/cyftSrze/eyyFX+2m+y2EKQjTL7We7sj4F9/+f4fX77/xoZDtXQU +POK/tWOE/K1ykX1XF2gA+O8b/u5vX/787V/e2pEx22m4Klt0uuu+7nGdz2ZrWZ4fjb97LOQ+VRSU +i5ghgyaqimdYBETt7GiEa9GK0zpXb49xkbsB58KkHwcp1MHIq1YBxnoUUPIHmS81qCBavWhSU5tV +7JfsA667iKdNSuf7e/FFEHyjL+pNtC3fyPBOWVN8VdaP/1iZg1/G66Hx4ztkIDLHDrWH104QzGo0 +jBgOGfLZ1of82YK2ugyo5dHbeu+oB80LEpQgT0q4UO4iDkBVCID1Pa5hSAy9B6iEUvNUOFBAR5Jx +5BMGvK1a30N1lSGX3VW2oGQUadhjgX6XYNowRZxjqdwgM/I4ow9cd7QYNJlD6FoiOsI49mSjDWKi +de+h1ZX3GDKnyFmxY3i+8gKm0AcVtpwcl7YKPGDGmGicN9H4j8bOB79xm0m13RWdB/1TnzrWkcmg +yI+F+U9LhseireNo/C9Tehh+cTT9CpZfPg7GIgVNImnP0Q5GlUi7mEbzmut7/yMqAbV89bVAyoUm +K/pYb2VLZaPeX100Ubpi8yl+NPoqzLVC8JVzW0s7KvVGRbcPRVbdxOkgN2weuWzzKP2vaCD5C2dJ +7FpxYZSFIJQE5bezH0DZLVQdnxH3ZZNjoQQRaqKMNn/yh1FCJOo13XEXoB5jR1WOvgeq3WL5vc27 +bHfe5tf/qcOvLHT0T41DcF4khTWjS4nou/6nf6TgxCai5emdWAS5kKIyHxWLjm5M0nH0BuzjUsYR +Tv1SGcyoY07Wwc9FK08byK7COE8/Y79JnB9sl+w7eSJV2qQTimlEf17BOFPhqP+BYYfVkJW841rj +4pKpMzVoWyXuo5ZDxznXrdPiWTxCC204syV5je6IKn1gqHFrSyiCgBEj9dxeCyQWrvmQxhVpqOua +wAGCrNSD70JuxiV8YJDhWFuvpc8pKIXdiLyazuXJwr4rdjs+RRH3RlWbDOa2ncdBQVvzSQTHrMv5 +ZEUaQ1ib9NoRfmtfgX2GNIMqLxUEjr5BNJeBLDiy/Wd7lLyLCI05Qf/eEIXYNM/3SK42FyQ3GwsJ +2RX6MJIVk4sY3OOjPFwN2EC12++2S0Rqg3NTWPWthRJzyT6m6nHF+Rwf7Twc3ziMa4e8f9a1jx0f +wcGmldBojmaLIraeWWmfuIzPoz/erkhbmkeZ1/qHRFhshOzBAmcJrg8H+hDdzYjBvy1KIUFoIU5v +FyYQfG5HkPLG8+X3QO4H1Juy0OYVQOJszCwb4Ook51F9BMZ2zdr9K0PZctGjk1uia386Cpmj/Fwh +0ENuDdpprUltAaTcMrw7Rq3YvdWW6Jeqekhmr4iGzTC2ZHaNBh+sVXHcfmNV02/RB06xlOMDb7uj +mxIeBVKlofXoPwQuIgfvzoc5z/0l1PuD04M50ZMLhfaKbjghYA7bdDuvMV+en377/PQfUThWFg0K +ZW5kc3RyZWFtDQplbmRvYmoNCjIgMCBvYmoNCjw8L1R5cGUgL1BhZ2UNCi9QYXJlbnQgMSAwIFIN +Ci9SZXNvdXJjZXMgNiAwIFINCi9Db250ZW50cyBbNyAwIFJdDQovTWVkaWFCb3ggWzAgMCA1OTUg +ODQyXQ0KPj4NCmVuZG9iag0KOSAwIG9iag0KPDwgL1Byb2NTZXQgWy9QREYgL1RleHQgXQ0KL0Zv +bnQgPDwNCi9UVDEgNSAwIFINCi9UVDIgNCAwIFINCj4+DQo+Pg0KZW5kb2JqDQoxMCAwIG9iag0K +PDwvTGVuZ3RoIDEzODQNCi9GaWx0ZXIgL0ZsYXRlRGVjb2RlDQo+Pg0Kc3RyZWFtDQp4nJVYy44j +Nwy8DzD/4ONuDgkpUS9gkUCtxz3AfEMOAXLItyRAfjdF2e3xTNNeLwbG2K22SBaLpWr//fqyvb2+ +lBPhr5yETqnIzy6W09tfry+/vL3xiU9vf7y+fIk/n76e3v5cF93l4jdK3H7dr15v/ed4I0sX7mkc +b/7X2LUM99SurodMqVRj19N/RrqBauONG2e/+eHo/L3b4lM0i09m8X4wB5eeSzUPx5nnUwA8vSul +RDSmtasJAOUtc5R0LDxks/BsFt7d4NyDAkAejeU4OA2hnDy5lilwBcwOTU/7Ok0K4mY5Zmomqh1y +neWYqJCZaLES9XEjSqOTIJku3rXWWEJdSRYJuoZCCJnOtba58GSC1LbopRpIOmcmyGRCKWWggd01 +MDmnQTlOzY430PNyXcNgduhZ6FrH1xoK7tshu5jfCY7gkYibRx8dc4qcaePsEknKEl3S4MegxZqE +Oai3wZ2ICkgAXI+ho00xtnCR2oU2chCNRmlmEmK8BvASdLPttPIzBJKt7Omf7yHMZUnkLADCO3++ +8cBOIQDxHp1LXsIY7EBf7H8LihviPJVJCZxBw1zMqzMSyuZmn8co3tlR9rr2KJzDuEZRDkiYOv0+ +bYN9C/u1YwS2ZdrdUypFyskWxOe0Z0GSB1XXMJzZxxE4tkSxekVQI19Rdf1I9FCiXeOVSqUKJWWF +L6uOW7lQhKVW6R7DR43abNrOd8rdRkr5O5FE6mH34EXrWX2K0ElwlEMPLKkeI0RbVfwjNIHS9LNE +jxPIeV5zu7joW+SS2kLXRE7usENzlsgbYZ+V99acjNjWzmnOteNNnSRj7PcfozibIWLVdEUS4qF9 +AMvD0iHw9DYaiQjWNnO2At1jxAX3hVzsjN2gyx6TndOaYojdmlxEvL4vECZFM2DmauW7vZNs60p4 +VCdtkAeaERkhg1wVbZRUBKRdaCvKxj00u9dMjlmkO7oiQes/i+ma6jSCmwQu0kLYl7xxwEF16e85 +SgAs0x+jBPtwMc3ZPuXnM6R48UvqP0yJgHA4LNb6MZqXx3O3GIHJXbtCFzV/THSk7NgP31zJSwH2 +9aUpd/vIP+C9bjVz31HrcRtsxid1Yxk4HzqZ2gL478ziGMOHDpa68EGhx6ir5rbBUMzj3Plsa4lt +pXYtUf27RNkRJJnCNeN/g3lyBfbJ69rKImxQazn2DMvf6dkNsxG6qjrvO++7Lu35hOIxktj6Yjqx +D9FvMsBogfUTJ01OZ/30/vP6fhbu953PxDyOGbm7+uPSVeEgcetsqDEK44zfWtXPymUOEB91F9EN +U+FcuZlyzFFX+7Q7h+U7oJ9UN7yHj7sw5KpgV40lNRN1OQyoAfoLIxAcFWfY49++HpJI7y3+Ug1O +ISf4poBCslbxuZMfvMU9Frtgd/enR829MWgL5puxPwylAmXIgg27t6XBSgY99+8Jpc3V6ZXXKLOq +pt76oM+dsoOzfb6YwSechI4qp77DzCqveK9J2AHIFoztXmt1TJD0boW1xbgGRvNVTgonz2VbUh8M ++wib/7wZ14p0TBZ0dTY8NkwJMXCYSxJd6VXfaxYMv2dWCV35AcP6KaILqLVUiFPBOQYsC8ZJYl7M +wTVt7OPoYjPINniX6EAY21Z+F6C0US1rcHygoY8BGu16/8Xe2Bk4m0amHTtkgLMHjwFdp0p/RVij +i0dhmKT2fAZs8+yhUZKweX1djMPcLdvKQB/1mrb9RvSsyOUHXIv+pKSt9hOCoWaw6Ovy2SnN+xqp +FVRGo1y8GTTZfHtoJ6jygAVcB4TODh7BN+q9mvhfg+svHucDZJ9/Gn1NxTExzCZOEXsSznmNt9eX +319f/geLqQ/ODQplbmRzdHJlYW0NCmVuZG9iag0KOCAwIG9iag0KPDwvVHlwZSAvUGFnZQ0KL1Bh +cmVudCAxIDAgUg0KL1Jlc291cmNlcyA5IDAgUg0KL0NvbnRlbnRzIFsxMCAwIFJdDQovTWVkaWFC +b3ggWzAgMCA1OTUgODQyXQ0KPj4NCmVuZG9iag0KMTIgMCBvYmoNCjw8IC9Qcm9jU2V0IFsvUERG +IC9UZXh0IF0NCi9Gb250IDw8DQovVFQxIDUgMCBSDQovVFQyIDQgMCBSDQo+Pg0KPj4NCmVuZG9i +ag0KMTMgMCBvYmoNCjw8L0xlbmd0aCAxMjA2DQovRmlsdGVyIC9GbGF0ZURlY29kZQ0KPj4NCnN0 +cmVhbQ0KeJy1WMuOIzcMvBvwPzi3LBAkpES9gMUGevU9gL8hhwVyyLckQH43pGy125Z6ZtK7wVw8 +bZssUsViyX+eT+l6PoUL8F+4EFxcoJ+VDZfrH+fTL9crXvBy/f18+jF/uly/tkfq/ugzYNaIuRAW +Q5g9qJIQnUUPCXIirRZS2Xg0ZCBG/NIibHMZv+b6DDkuEhEWY8GoQBgUoTMUC3E8BboihAqUISr0 +oUUOkShlBc4ERF8EwZiF4JFFIwBojiiZCDhcIGDwejHmS69wLfqvsWhJN37w70l3GMtrBkQdgTR1 +3CNWpTYdwVTGVJcxlUJagEwkW1DStJao7BGNgZC1/N8+w884vZZWcmcXeTYm+OHTgAqeOLEhwAcB +Sr3gcpUzEzBUbZZTQLQV+VV73zOc+5kzB1A+O/THenugP52UEpKJqTQqv02vXaqoc+sVBpfAM8Wm +6a1/oRJZaGNgqpJD/v4U6lThOSsQE9PJLph8USqGEZ+BI+0hyCou+VHy9gt6wrclYsc1x6GP0Hgt +NeVILCtCZaVS5lPSc2x20jO9VAhOg6tlxIU0SEHZytj/IAF32dpy8FGoL0hVDzhNsFMRxj0RvsXG +ZJi7NSoFHoncm+JrnJ/mUG/nUM5pLiuopSxILr6dw8I0x4RTz3UwARJrleapcuRJu6da+nIZ85Ga +5qN5vnW18DqYrpfdutQrj+7L6zvz5746pmvNwBEplJauO9otqFhq9RIMFW1l3mSN6CU5kZoxYJjP +2yrpM5zk/REtMMqtdLhvD6RiCX3TByTrCVPo783xmiN43SEN7VhFprmHYFimGSM/iYJ3XctTnDN+ +vovTHNLYjtNHy74ASTP1iWj88k8TTEZTF+a3iTIb8E1B4xd+HUwH26RvMx0QSm7K6ypPkfP8ejJ2 +O2W+X+I7Z/aREnXw8xKFOBsrzIPqeVewJVpEI1XTJpvdY/du8/wzOXVmJTI3wfLAx5tcKdTBgBtN +jvZHBqCHbnYOS+XVgIybfamvzYtS8eiC7c9uNVR2Tsuor9qq0bIL4NYVq4FfW/Au81FBc7X3ZyNU +t2MRWO41L5abzAeHprDU27ZxxLWPkOhV8tn6rZAoek2B2RIsYtICiUytZEL6MHO6G+hB+qgKFXXV +mYOpzoD9zik7OpwVpkPmUomGqgPvzZphjf5BA7hrXDS8GuQ7027r3RRwkurWGemSqnyuYsNXe/RO +gcptZc8RPg1KLV6FEmVL8CZPz8O4jWLmt9wdg9Xji2N4KKgLkmOMrZ8X88RUzubnpYR1STMjHz6F +Z4kdV1/cfFcJLFBtwfAytHM46A/A4TNzcsK9ynY7656cz4xvaf777TKeuQMYO7Zvui9QpbJ7X2Aa +HTnKu20TXGBqEZzC6dbH9qvA+L7Oqvb3Rxh2ztYdq75HpXb7NjFPacJm5cgRbGyahG43bDmSim0T +yCrl8QYZe7ldA4ll42MLMd3K19yKWl8hz9ugjjD5IxCVcobXSbvMPsGT1fKfIOIRIr8SoneK+Ip4 +I4X8bvPyGVlgtuAURjhC256tjxNZYtqanZ8F9kapsE8vrPt7I+Xo0KTf3OrTJdobQp1eimfXdlHh +rUtnvZ5Pv51P/wJwzFPxDQplbmRzdHJlYW0NCmVuZG9iag0KMTEgMCBvYmoNCjw8L1R5cGUgL1Bh +Z2UNCi9QYXJlbnQgMSAwIFINCi9SZXNvdXJjZXMgMTIgMCBSDQovQ29udGVudHMgWzEzIDAgUl0N +Ci9NZWRpYUJveCBbMCAwIDU5NSA4NDJdDQo+Pg0KZW5kb2JqDQoxNSAwIG9iag0KPDwgL1Byb2NT +ZXQgWy9QREYgL1RleHQgXQ0KL0ZvbnQgPDwNCi9UVDIgNCAwIFINCi9UVDEgNSAwIFINCj4+DQo+ +Pg0KZW5kb2JqDQoxNiAwIG9iag0KPDwvTGVuZ3RoIDE4NTkNCi9GaWx0ZXIgL0ZsYXRlRGVjb2Rl +DQo+Pg0Kc3RyZWFtDQp4nMVZTW8cNwy9G/B/2N4SoE1EkfoqihYjzejWQwEfA/TWQ4Ee+lvaH9zH +2Z31xMONtU7ROjDsjEciRT4+Pmr/fHyoT48P5eTwr5zEnVKRDz6W09Mfjw8fn578iU5Pvz0+/OCo +hh9PT7+vT+ny9N3p/fbo+cUeogu+kMRM1GaiFCm76lvIEqpnaSS1eSetOj/X86Z7D1K8evD1Zh3P +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 +XQ0KPj4NCmVuZG9iag0KMTkgMCBvYmoNCjw8IC9Qcm9jU2V0IFsvUERGIC9UZXh0IF0NCi9Gb250 +IDw8DQovRjAgMTggMCBSDQo+Pg0KPj4NCmVuZG9iag0KMjAgMCBvYmoNCjw8L0xlbmd0aCA2MA0K +L0ZpbHRlciAvRmxhdGVEZWNvZGUNCj4+DQpzdHJlYW0NCnicK+Tlcgrh5bJQMABCCwVTUwMFY0M9 +Q3MzhZBcXi59NwMFQ4WQNF4uDVNNhZAsXi5XoOJAXi4AGD0J4g0KZW5kc3RyZWFtDQplbmRvYmoN +CjE3IDAgb2JqDQo8PC9UeXBlIC9QYWdlDQovUGFyZW50IDEgMCBSDQovUmVzb3VyY2VzIDE5IDAg +Ug0KL0NvbnRlbnRzIFsyMCAwIFJdDQovTWVkaWFCb3ggWzAgMCA1OTUgODQyXQ0KPj4NCmVuZG9i +ag0KMjEgMCBvYmoNCjw8L0NyZWF0b3IgKEFkb2JlIElsbHVzdHJhdG9yIDEwLjAxLjEpDQovQ3Jl +YXRpb25EYXRlIChEOjIwMTAxMjI0MDE0NjQ2KQ0KL1Byb2R1Y2VyIChBZG9iZSBQREYgbGlicmFy +eSA1LjAwKQ0KL0F1dGhvciAoKQ0KL1RpdGxlICjP+srbyMvUsdOmuMO+37G4tcQxMLj20MTMrFZn +UjEpDQovU3ViamVjdCAoTm9uZSkNCi9LZXl3b3JkcyAoKQ0KPj4NCmVuZG9iag0KMjIgMCBvYmoN +Cjw8IC9Qcm9jU2V0IFsvUERGIF0NCj4+DQplbmRvYmoNCjMgMCBvYmoNCjw8L1R5cGUgL1hPYmpl +Y3QNCi9TdWJ0eXBlIC9Gb3JtDQovUmVzb3VyY2VzIDIyIDAgUg0KL01hdHJpeCBbMSAwIDAgMSAw +IDAgXQ0KL0JCb3ggWzAgMCAxMCAzNzNdDQovTGVuZ3RoIDE0DQovRmlsdGVyIC9GbGF0ZURlY29k +ZQ0KPj4NCnN0cmVhbQ0KeJwr5OUK5OUCAAQsAPENCmVuZHN0cmVhbQ0KZW5kb2JqDQoxIDAgb2Jq +DQo8PC9UeXBlIC9QYWdlcw0KL0tpZHMgWw0KMiAwIFINCjggMCBSDQoxMSAwIFINCjE0IDAgUg0K +MTcgMCBSDQpdDQovQ291bnQgNQ0KPj4NCmVuZG9iag0KMjMgMCBvYmoNCjw8L1R5cGUgL0NhdGFs +b2cNCiAvUGFnZXMgMSAwIFINCi9QYWdlTGF5b3V0IC9TaW5nbGVQYWdlDQovUGFnZU1vZGUgL1Vz +ZU5vbmUNCj4+DQplbmRvYmoNCjI0IDAgb2JqDQo8PC9GaWx0ZXIgL0ZsYXRlRGVjb2RlIC9MZW5n +dGggNzcyOSAvTGVuZ3RoMSAxMTg3Mw0KPj4NCnN0cmVhbQ0KeNrtenl0XNWZ573vvXvfvtdbaq9S +SSqtrpJlq5CtoDJgwBCwWELYqr2xubFjWTgGA9OmJ82SpBPcnMPi5iQ400kcd84ZG68yDsTJmN09 +OB3jABHIk8aAk6OBP+jpZk6ra777qmTLgZnpv+af6ZJuvXvfVvd+y+/7fd97CCOENPQA4pG1au2K +0dtWffYi7DmKEDdn1cYNOdHkP4H+/4T2wm2jt69N/+CxjxAi43COfvuaTbe9fc8L18EYrmnz77h1 +xS3miStfR6jrt3B84A7YweGv3ohQtw3j1jvWbrgn9dqB+2E8H8aH16xbteLg4l9KMP5HGK9cu+Ke +0euX8OsQ6vkqjHNfW7H21nfem7wHxncjhIXRdXdteEL522UI9d4Hx+eNjt06+s6zS2GuvTthvBsa +h9h6EIrBeqCHE9Ao+r9+OL6xFQhFoiQrqqYbpmU7bszzYXeAwngCJRFKoTRCmejU7KzLcyiPUEuh +tQ2hdhgWOxDqRF3dPf+nn+ydg1AJ/b/6CNiB7y7445vz7UIL0TC6EC1Gl6LL0BXoGrQMrUC3oz9F +69AY2piL5dL1evPcDtQD5y76o3NvgXO/BudugHNT9Xr9d/A3Uf9t/a36b+on6sfrv67/qn60/ov6 +4foL9Z/VD9YP1PefjJ90mhr6t304mK+ACAK1IAnJSEEqWKuODGQiC9nIQS7o2kM+0xGKI6YlpqQM +6IfNvAUVUCtqA7UUYRWgFNQNa+lFc1Cp/u+f/68/6KdgXaPQhPq/1idhTMHCFLAuAyzLAavywaIS +YE0Ztud/exzO+Df8Vgb+XkUMQFKIq/8efQX1o/PQL+B+VVRBX0Jz0RCaqL+LvgrepYLtsvYYHLkX +ZrgGPDIHfwn4RTYH1sxdHT2XX3394ouS+fwNvbCIPnCrK9BeuDCBrtxrnKSYPocXMtSsZr1d4eHw +WHgyFEJ9p4Od5caoscXYZgiGcVLG8jhecGApP8J/zPN8qTZVGyzVjtTePVJDpeHp2nt95UpL+/x5 +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 +YPbgEUFxSQj83NY5uWv24EnNsDnH9S2iGBqePYC7t8DdH0K/bN6d3YzdFO7q988eLCKSIwSGSB0V +S8OzB88ousO5TswisqnO7qNoTaCcK2984+ll5tA/RjVU+OyYarxbeGBd9R7I1CZg1b+NXoLlot3s +pAnY29p8T7H+uRcWy+eMHkB90CrQVGgyNAOaBM1ujtnrtWloOjSzuc9s7rea17FWhtbfPI+DJjTv +Izb7cnM/Oxc1t2bzHkazxZrXaM0tO0bZtbixtI3QWs7MfSnLofAF+E/xZvxjfJiLczdw7/Ff4x8T +HOE/CR+QbXSY/jn9hXi++Lq0Sjomr5Y/U76i5tSX1d9q9+ic/jX9V8bz5oXmcWvA2mb9k73JyTu9 +zs3OtyOZlfFakE3jNU4LlSAsILwC/6r52wr6s6Zk2csmqNnnYLWk2WevnmjNPnsB1G72eZRFIXvB +V2Dv/igg+0afAwksavYF2L+02aew/4ZmnweqcfuisdUr1lx96+1fX7NiLOpHX1dcu2bNyEUXr1m9 +ckEu2vG5t1EXoTG0GlxkDboa3YpuB/hZA6OxWfvP9q5A18L3GojIF6GLYbsarUQLUG7WGU17Q/Ui +ANcXvrQbCYdDF8krblu9uq9cHpi/KIFtbKG5kPlY2EAdsDWbWw2y+YthqzfHBozDxv49F3eMAODU +H/wOSu+ae/nV1+96IH3DOKaL74CvwkXjWGA9gfVI1Fu8HHpsyJ0ZcmzIsyHHhjwbojNHERtiNkRs +iAsX4e7G538Bd7ANoA0KZW5kc3RyZWFtDQplbmRvYmoNCjI1IDAgb2JqDQo8PC9UeXBlIC9Gb250 +RGVzY3JpcHRvcg0KL0FzY2VudCA4NTkNCi9DYXBIZWlnaHQgNjY2DQovRGVzY2VudCAtMTQxDQov +RmxhZ3MgMzINCi9Gb250QkJveCBbMCAtMTQxIDk5NiA4NTVdDQovRm9udE5hbWUgL8vOzOUNCi9J +dGFsaWNBbmdsZSAwDQovU3RlbVYgODcNCi9Gb250RmlsZTIgMjQgMCBSDQo+Pg0KZW5kb2JqDQo1 +IDAgb2JqDQo8PC9UeXBlIC9Gb250DQovU3VidHlwZSAvVHJ1ZVR5cGUNCi9CYXNlRm9udCAvy87M +5Q0KL0ZpcnN0Q2hhciAzMg0KL0xhc3RDaGFyIDE1MQ0KL0VuY29kaW5nIC9XaW5BbnNpRW5jb2Rp +bmcNCi9Gb250RGVzY3JpcHRvciAyNSAwIFINCi9XaWR0aHMgWzUwMCANCjUwMCAwIDAgMCAwIDAg +MCA1MDAgNTAwIDUwMCAwIDUwMCA1MDAgNTAwIDUwMCA1MDAgDQo1MDAgNTAwIDUwMCA1MDAgNTAw +IDUwMCA1MDAgNTAwIDUwMCA1MDAgNTAwIDAgMCAwIDUwMCAwIA0KNTAwIDUwMCA1MDAgMCA1MDAg +MCAwIDUwMCAwIDUwMCAwIDAgNTAwIDAgMCAwIA0KMCAwIDUwMCAwIDAgMCAwIDAgMCAwIDAgMCAw +IDAgNTAwIDAgDQo1MDAgMCAwIDUwMCA1MDAgNTAwIDUwMCAwIDAgNTAwIDAgMCAwIDUwMCA1MDAg +MCANCjAgNTAwIDAgNTAwIDUwMCA1MDAgMCAwIDAgMCAwIDAgMCAwIDAgMCANCjAgMCAwIDAgMCAw +IDAgMCAwIDAgMCAwIDAgMCAwIDAgDQowIDAgNTAwIDUwMCAwIDAgNTAwIF0NCj4+DQplbmRvYmoN +CjI2IDAgb2JqDQo8PC9GaWx0ZXIgL0ZsYXRlRGVjb2RlIC9MZW5ndGggOTc2OTQgL0xlbmd0aDEg +MzExMDQwDQo+Pg0Kc3RyZWFtDQp42uzXDUBT5RoA4Pds/IkIiPyJ/GyDASriGL8iEsJUUEREOCKg +gqKSohKaEdfMzMpMy0zNkktq5E0jMjUlNTPzKhoKalEpP0qmXm8ZmXmVaLsfnNWYbLCNbQx438Nz +9n3nfNvZeM95v3OAAgBzWAlssM7KmpPBoqamkC3FhEf24tkZ4Ym7S0i7EqhpD2YvzMgZ7rjkCFAp +ZQB9QsjwTKuquHKgMskQCFqYkZeTHMNeTPohpM+ZvWwpx9SK3UD6yQCsYzm5c3IufzyJjJ/nSPbv +m5f99Fxpn/hTkLVwaV6/Vbt2ATuziRzv3tyceQtddmy8BUbHGsj4ftD8Xasl1eDR3CAhAWnjr6Cf +AQwMDAz9hidCOhbegXSp9x9xHoAyV4C8h8pVYANRghDqVq4rx7InoltZTmzSALnvZ9s+Ihf9rVKB +Wwh1b0bmrWQpcYC4C2AcIlUIYOKowEEAU0upnfLMLKVKNdPHqZW1rYhVY05qnHmjTN9y1VgEEAUy +/QIeUa4+ywipegCr8Z3UAGC9UwcaZPoXM2yKiMttDYgnDjJsndpR1TG7VTL2JgqUMhwK1HRbMces +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 +8ERzVqbx2KgPsDaUFUcDtSQxHpuKtWHZ2b271QJVGGArbkQReyKMhZIHWK0s+nmg/Rav2Rg3c3G3 ++vSoIcVzZhE2dd7TzMJ/7IUtxMP1vE5h+fs69uIX+qnBmb2BHfVRtH11WiuuCH8ex2bnmCQ/va6V +J/C3d/2sGeZTjJe0gC3s6K7j0nOcstld6wKxr29yOiao0sm34grO7jrmkOI8RuK3b+EsK9gN9nC9 +vLM1X6o4/6tYlZj36m419VgrDrEjR+BK9np5dLeaIp0n+yx4hLgXel6fdQYeL/J2M40PFWNmgXK8 +hbw9ASYN4zn//MpdfgK8yQ9gHTis+WB9q44XizDOvrM+fyL8zwT4m7eAU+l9553Y3zTy3U7uVruB +9Z8+rmeGr1esIOoCol26z3EPNA/gvNS1yl7y+6+X9G+X9KNL+vdL+s9L+o81/csl/cMl/ckl/dEl +/RlgcTgxNu4eMEhnwBe+/PZ3kKfPAPvzcv1/ffZPly//6bMvL2m+pHBJ/pLu//f7H/94/e7uktJ6 +7Uv6iUs6XNK7S1ou1/335e/j/37+7HN4jl8/vzzbDVJcn4fpkVJarw1G6vnq6W79Pq73YurvnNay +ntf/X/KbIXko++fr3/5bgrr5bP388t62fq5rfbxf39N6/a3t/Odre7y0919c0j9f0l9d0h9f0u9e +0m9c0h9c0j9e0u9d0p9e0l9e0t9e0m9f0u9f0l+vf3/rkv5+/f8l/eEl/c3L/T/6/g9+/Td/59d+ +9e2HD7/7Mz/3Wf0fnVr3fA0KZW5kc3RyZWFtDQplbmRvYmoNCjI3IDAgb2JqDQo8PC9UeXBlIC9G +b250RGVzY3JpcHRvcg0KL0FzY2VudCA4NTkNCi9DYXBIZWlnaHQgNjY2DQovRGVzY2VudCAtMTQx +DQovRmxhZ3MgMzINCi9Gb250QkJveCBbMCAtMTQxIDk5NiA4NTVdDQovRm9udE5hbWUgL8vOzOUN +Ci9JdGFsaWNBbmdsZSAwDQovU3RlbVYgODcNCi9Gb250RmlsZTIgMjYgMCBSDQo+Pg0KZW5kb2Jq +DQoyOCAwIG9iag0KPDwvVHlwZSAvRm9udA0KL0Jhc2VGb250IC/LzszlDQovU3VidHlwZSAvQ0lE +Rm9udFR5cGUyDQovQ0lEU3lzdGVtSW5mbyA8PC9PcmRlcmluZyhJZGVudGl0eSkvUmVnaXN0cnko +QWRvYmUpL1N1cHBsZW1lbnQgMD4+DQovRFcgMTAwMA0KL1dbODAzWzEwMDBdMjg0WzEwMDBdNDM3 +WzEwMDBdNDQ1WzEwMDBdNDQ3WzEwMDBdNDUxWzEwMDBdNDUyWzEwMDBdNDU3WzEwMDBdNDU4WzEw +MDBdNDYzWzEwMDBdNDY0WzEwMDBdOTgwWzEwMDBdOTgzWzEwMDBdOTg5WzEwMDBdOTkwWzEwMDBd +OTkxWzEwMDBdOTkzWzEwMDBdOTk0WzEwMDBdOTk5WzEwMDBdMTAwMFsxMDAwXTEwMDJbMTAwMF0x +MDA2WzEwMDBdMTAwOFsxMDAwXTEwMjJbMTAwMF0xMDI1WzEwMDBdMTAyOFsxMDAwXTEwMzhbMTAw +MF0xMDM5WzEwMDBdMTA0MlsxMDAwXTEwNTJbMTAwMF0xMDUzWzEwMDBdMTA1NlsxMDAwXTEwNjBb +MTAwMF0xMDczWzEwMDBdMTA3NVsxMDAwXTEwNzZbMTAwMF0xMDkyWzEwMDBdMTA5M1sxMDAwXTEx +MTRbMTAwMF0xMTE3WzEwMDBdMTExOVsxMDAwXTExMjBbMTAwMF0xMTI1WzEwMDBdMTEyNlsxMDAw +XTExMjhbMTAwMF0xMTM1WzEwMDBdMTE0NFsxMDAwXTExNDdbMTAwMF0xMTUyWzEwMDBdMTE1NFsx +MDAwXTExNjZbMTAwMF0xMTcyWzEwMDBdMTE3N1sxMDAwXTExODJbMTAwMF0xMTgzWzEwMDBdMTE4 +NlsxMDAwXTExOTJbMTAwMF0xMTk0WzEwMDBdMTE5NlsxMDAwXTEyMDdbMTAwMF0xMjA5WzEwMDBd +MTIxNFsxMDAwXTEyMTZbMTAwMF0xMjI3WzEwMDBdMTIzMVsxMDAwXTEyMzNbMTAwMF0xMjM3WzEw +MDBdMTI2MFsxMDAwXTEyNjJbMTAwMF0xMjY4WzEwMDBdMTI3MlsxMDAwXTEzMDZbMTAwMF0xMzEz +WzEwMDBdMTMxNVsxMDAwXTEzMjFbMTAwMF0xMzI3WzEwMDBdMTMyOFsxMDAwXTEzMzJbMTAwMF0x +MzYzWzEwMDBdMTM3NVsxMDAwXTEzOTFbMTAwMF0xNDU3WzEwMDBdMTQ2MVsxMDAwXTE1MDVbMTAw +MF0xNTE3WzEwMDBdMTU1NFsxMDAwXTE1ODJbMTAwMF0xNTg0WzEwMDBdMTY5OVsxMDAwXTE4MTVb +MTAwMF0xODE3WzEwMDBdMTgyMFsxMDAwXTE4NDlbMTAwMF0xODUyWzEwMDBdMTg1NlsxMDAwXTE4 +NTdbMTAwMF0xODYxWzEwMDBdMTg2M1sxMDAwXTE4NjRbMTAwMF0xODY3WzEwMDBdMTg3MVsxMDAw +XTE4ODFbMTAwMF0xODg5WzEwMDBdMTkwMVsxMDAwXTE5MDNbMTAwMF0xOTA0WzEwMDBdMTkyN1sx +MDAwXTE5MjlbMTAwMF0xOTQ2WzEwMDBdMTk3MlsxMDAwXTE5OThbMTAwMF0yMDEwWzEwMDBdMjAy +OVsxMDAwXTIwMzFbMTAwMF0yMDMzWzEwMDBdMjA0MFsxMDAwXTIwNDVbMTAwMF0yMDQ3WzEwMDBd +MjA1MlsxMDAwXTIwNThbMTAwMF0yMDgxWzEwMDBdMjE1OVsxMDAwXTIxNjJbMTAwMF0yMTYzWzEw +MDBdMjE2NFsxMDAwXTIxNjVbMTAwMF0yMTcyWzEwMDBdMjE3NFsxMDAwXTIxODFbMTAwMF0yMTk1 +WzEwMDBdMjIzMlsxMDAwXTIyODJbMTAwMF0yMjgzWzEwMDBdMjMxOFsxMDAwXTIzMTlbMTAwMF0y +MzI1WzEwMDBdMjMyN1sxMDAwXTIzMzFbMTAwMF0yMzM0WzEwMDBdMjMzOFsxMDAwXTIzNDVbMTAw +MF0yMzQ3WzEwMDBdMjM3M1sxMDAwXTIzNzZbMTAwMF0yMzk0WzEwMDBdMjM5OVsxMDAwXTI0MTlb +MTAwMF0yNDU0WzEwMDBdMjQ2MFsxMDAwXTI0NjVbMTAwMF0yNDY5WzEwMDBdMjQ3NVsxMDAwXTI0 +ODdbMTAwMF0yNDk5WzEwMDBdMjUwOFsxMDAwXTI1MjRbMTAwMF0yNTI4WzEwMDBdMjUyOVsxMDAw +XTI1MzBbMTAwMF0yNTMzWzEwMDBdMjUzOVsxMDAwXTI1NTRbMTAwMF0yNTYwWzEwMDBdMjU5MFsx +MDAwXTI2MDRbMTAwMF0yNjE0WzEwMDBdMjYzMVsxMDAwXTI2NDFbMTAwMF0yNjU2WzEwMDBdMjY4 +NFsxMDAwXTI3MDlbMTAwMF0yNzE2WzEwMDBdMjcyMVsxMDAwXTI3NTBbMTAwMF0yODE4WzEwMDBd +Mjg0MlsxMDAwXTI5MjhbMTAwMF0zMTMyWzEwMDBdMzI0N1sxMDAwXTMyNTBbMTAwMF0zMjUyWzEw +MDBdMzI1NFsxMDAwXTMyODFbMTAwMF0zMjgyWzEwMDBdMzI5MFsxMDAwXTMzMjRbMTAwMF0zMzMy +WzEwMDBdMzMzNVsxMDAwXTMzNDJbMTAwMF0zMzc0WzEwMDBdMzM4NlsxMDAwXTM1MDdbMTAwMF0z +NTMzWzEwMDBdMzUzNFsxMDAwXTM1NDZbMTAwMF0zNjQ3WzEwMDBdMzgwMFsxMDAwXTM4MDNbMTAw +MF0zODE4WzEwMDBdMzgyMlsxMDAwXTM4MjRbMTAwMF0zODM1WzEwMDBdMzgzN1sxMDAwXTM4Mzhb +MTAwMF0zODM5WzEwMDBdMzg0NVsxMDAwXTM4NDhbMTAwMF0zODcxWzEwMDBdMzkyMVsxMDAwXTM5 +MjZbMTAwMF0zOTk5WzEwMDBdNDAwNFsxMDAwXTQwMDdbMTAwMF00MDUxWzEwMDBdNDM4OFsxMDAw +XTQ0MTBbMTAwMF00NDI4WzEwMDBdNDQzN1sxMDAwXTQ0NDRbMTAwMF00NDQ1WzEwMDBdNDQ0N1sx +MDAwXTQ0NDhbMTAwMF00NDYyWzEwMDBdNDQ2NVsxMDAwXTQ0NjZbMTAwMF00NDcwWzEwMDBdNDQ4 +N1sxMDAwXTQ0ODhbMTAwMF00NDkwWzEwMDBdNDQ5M1sxMDAwXTQ0OTlbMTAwMF00NTEyWzEwMDBd +NDUzMVsxMDAwXTQ1NTdbMTAwMF00NTYwWzEwMDBdNDU3MFsxMDAwXTQ1NzRbMTAwMF00NTc5WzEw +MDBdNDU4MVsxMDAwXTQ2MTNbMTAwMF00NjI4WzEwMDBdNDY3N1sxMDAwXTQ4MDRbMTAwMF01MDE3 +WzEwMDBdNTA0MlsxMDAwXTUwNDZbMTAwMF01MDQ5WzEwMDBdNTA1MVsxMDAwXTUwNThbMTAwMF01 +MDYxWzEwMDBdNTA2MlsxMDAwXTUwNjRbMTAwMF01MDg0WzEwMDBdNTA5MlsxMDAwXTUxMTRbMTAw +MF01MTIyWzEwMDBdNTEzMlsxMDAwXTUxOTBbMTAwMF01MTkxWzEwMDBdNTE5MlsxMDAwXTUxOTRb +MTAwMF01MjAzWzEwMDBdNTIxMFsxMDAwXTUyMjRbMTAwMF01MjI1WzEwMDBdNTIyN1sxMDAwXTUy +NDJbMTAwMF01MjU5WzEwMDBdNTMzMlsxMDAwXTUzMzRbMTAwMF01MzM1WzEwMDBdNTMzNlsxMDAw +XTUzNDdbMTAwMF01MzUzWzEwMDBdNTM4MVsxMDAwXTUzOTBbMTAwMF01NDE1WzEwMDBdNTQ0NVsx +MDAwXTU0NjhbMTAwMF01NDcxWzEwMDBdNTQ4M1sxMDAwXTU1MTVbMTAwMF01NTI3WzEwMDBdNTUy +OVsxMDAwXTU1ODlbMTAwMF01NjAyWzEwMDBdNTYxN1sxMDAwXTU2MjdbMTAwMF01NjQ3WzEwMDBd +NTY5OVsxMDAwXTU3MDNbMTAwMF01NzI5WzEwMDBdNTc1NlsxMDAwXTU3ODVbMTAwMF01ODMxWzEw +MDBdNTg1OVsxMDAwXTU4NzVbMTAwMF01OTA3WzEwMDBdNTk4M1sxMDAwXTYwMzhbMTAwMF02MTE2 +WzEwMDBdNjExN1sxMDAwXTYxNTVbMTAwMF02MTYzWzEwMDBdNjE3NVsxMDAwXTYxODNbMTAwMF02 +MjAzWzEwMDBdNjIwOFsxMDAwXTYyMjhbMTAwMF02MjM4WzEwMDBdNjI0OVsxMDAwXTYyNjJbMTAw +MF02MjY1WzEwMDBdNjMxMFsxMDAwXTYzMTFbMTAwMF02MzE0WzEwMDBdNjMyMFsxMDAwXTYzMzNb +MTAwMF02MzUyWzEwMDBdNjM1N1sxMDAwXTY0NTVbMTAwMF02NTAyWzEwMDBdNjUyMVsxMDAwXTY1 +MjNbMTAwMF02NTI0WzEwMDBdNjU2NFsxMDAwXTY2NzBbMTAwMF02NzU4WzEwMDBdNjc4NVsxMDAw +XTY5MTVbMTAwMF02OTIyWzEwMDBdNjkzMFsxMDAwXTY5MzFbMTAwMF02OTQwWzEwMDBdNjk0OVsx +MDAwXTY5NTdbMTAwMF02OTgwWzEwMDBdNzAwM1sxMDAwXTcwNDFbMTAwMF03MDQzWzEwMDBdNzA1 +M1sxMDAwXTcwODNbMTAwMF03MDkyWzEwMDBdNzA5NFsxMDAwXTcwOTdbMTAwMF03MTE0WzEwMDBd +NzEzOFsxMDAwXTcxNDNbMTAwMF03MTcxWzEwMDBdNzIxNFsxMDAwXTcyMzRbMTAwMF03MjM1WzEw +MDBdNzM2NlsxMDAwXTczNjhbMTAwMF03Mzc4WzEwMDBdNzM4OFsxMDAwXTczODlbMTAwMF03Mzkz +WzEwMDBdNzQwN1sxMDAwXTc0MjRbMTAwMF03NDI3WzEwMDBdNzQzOFsxMDAwXTc0NjBbMTAwMF03 +NDgxWzEwMDBdNzQ5MVsxMDAwXTc1MjRbMTAwMF03NTMxWzEwMDBdNzUzNlsxMDAwXTc1NTBbMTAw +MF03NjQzWzEwMDBdNzY5MVsxMDAwXTc2OTJbMTAwMF03Njk2WzEwMDBdNzcwMlsxMDAwXTc3MDhb +MTAwMF04MDQ4WzEwMDBdODQzN1sxMDAwXTg0MzhbMTAwMF04NDQzWzEwMDBdODQ1NFsxMDAwXTg0 +NjZbMTAwMF04NTAyWzEwMDBdODUwM1sxMDAwXTg1MDVbMTAwMF04NTI3WzEwMDBdODU4NVsxMDAw +XTg2MTFbMTAwMF04NjE3WzEwMDBdODcxMlsxMDAwXTg4MTlbMTAwMF04ODIxWzEwMDBdODg3M1sx +MDAwXTg4OTJbMTAwMF04OTc1WzEwMDBdODk3N1sxMDAwXTg5OTFbMTAwMF04OTk0WzEwMDBdOTAx +OFsxMDAwXTkwMzVbMTAwMF05MDgyWzEwMDBdOTA5MVsxMDAwXTkxNTdbMTAwMF05MTc3WzEwMDBd +OTIxM1sxMDAwXTkyMTlbMTAwMF05MjU4WzEwMDBdOTMxNlsxMDAwXTkzOTdbMTAwMF05NDM0WzEw +MDBdOTQ0OFsxMDAwXTk2MjBbMTAwMF05ODY5WzEwMDBdOTg4NFsxMDAwXTEwMDQwWzEwMDBdMTAw +NDNbMTAwMF0xMDA5OVsxMDAwXTEwMjcyWzEwMDBdMTAzMTdbMTAwMF0xMDM5MFsxMDAwXTEwNDY2 +WzEwMDBdMTA1OTFbMTAwMF0xMDYyOFsxMDAwXTEwNjc2WzEwMDBdMTA2ODlbMTAwMF0xMDcxMVsx +MDAwXTEwNzE0WzEwMDBdMTA5OTVbMTAwMF0xMTAwNFsxMDAwXTExMDEzWzEwMDBdMTEwMTVbMTAw +MF0xMTAxN1sxMDAwXTExMDQwWzEwMDBdMTExMzlbMTAwMF0xMTM0NlsxMDAwXTExMzUyWzEwMDBd +MTE0MjJbMTAwMF0xMTQyOVsxMDAwXTExNDU4WzEwMDBdMTE0NjRbMTAwMF0xMTQ2OFsxMDAwXTEx +NDg3WzEwMDBdMTE1MDdbMTAwMF0xMTUyM1sxMDAwXTExNTM2WzEwMDBdMTE1NDBbMTAwMF0xMTYw +OFsxMDAwXTExNzA1WzEwMDBdMTE3MTlbMTAwMF0xMTg0MlsxMDAwXTEyMDQ2WzEwMDBdMTIwNDhb +MTAwMF0xMjEzMVsxMDAwXTEyMTgwWzEwMDBdMTIxODFbMTAwMF0xMjE5M1sxMDAwXTEyMTk3WzEw +MDBdMTIyMjdbMTAwMF0xMjIyOFsxMDAwXTEyMjM5WzEwMDBdMTIyNTVbMTAwMF0xMjI1OFsxMDAw +XTEyNDQ3WzEwMDBdMTI0NjZbMTAwMF0xMjUxN1sxMDAwXTEyNTQ0WzEwMDBdMTI1NzNbMTAwMF0x +MjU4NFsxMDAwXTEyNTg2WzEwMDBdMTI2MjZbMTAwMF0xMjYyOFsxMDAwXTEyNjYxWzEwMDBdMTI2 +OTlbMTAwMF0xMjk0NlsxMDAwXTEzMDA3WzEwMDBdMTMwNDRbMTAwMF0xMzA1OVsxMDAwXTEzNDQ2 +WzEwMDBdMTM0NTlbMTAwMF0xMzQ2M1sxMDAwXTEzNDY0WzEwMDBdMTM0NjZbMTAwMF0xMzQ3M1sx +MDAwXTEzNDc1WzEwMDBdMTM0NzlbMTAwMF0xMzQ4NVsxMDAwXTEzNDg4WzEwMDBdMTM0ODlbMTAw +MF0xMzQ5MVsxMDAwXTEzNTAxWzEwMDBdMTM1MDJbMTAwMF0xMzUwNVsxMDAwXTEzNTgyWzEwMDBd +MTM2MDVbMTAwMF0xMzY2NlsxMDAwXTEzNzgxWzEwMDBdMTM3ODNbMTAwMF0xMzc4NVsxMDAwXTEz +NzkyWzEwMDBdMTM4NTZbMTAwMF0xMzg2NFsxMDAwXTEzOTQxWzEwMDBdMTM5ODRbMTAwMF0xNDAw +MFsxMDAwXTE0MDMzWzEwMDBdMTQwNTNbMTAwMF0xNDIzNFsxMDAwXTE0MjcwWzEwMDBdMTQyNzlb +MTAwMF0xNDQwM1sxMDAwXTE0NTMzWzEwMDBdMTQ2MDJbMTAwMF0xNDY1OVsxMDAwXTE0NzMxWzEw +MDBdMTQ4NDFbMTAwMF0xNTM5N1sxMDAwXTE1NDA2WzEwMDBdMTU3MTNbMTAwMF0xNTg5MlsxMDAw +XTE1OTA0WzEwMDBdMTU5MzJbMTAwMF0xNTk5OVsxMDAwXTE2MjExWzEwMDBdMTYyMTNbMTAwMF0x +NjI3N1sxMDAwXTE2Mjc4WzEwMDBdMTYyODJbMTAwMF0xNjMxMVsxMDAwXTE2MzE0WzEwMDBdMTYz +NDBbMTAwMF0xNjU0M1sxMDAwXTE2NzU3WzEwMDBdMTY3NjBbMTAwMF0xNjc2NFsxMDAwXTE2NzY1 +WzEwMDBdMTY3NjlbMTAwMF0xNjc3MFsxMDAwXTE2Nzc0WzEwMDBdMTY3ODJbMTAwMF0xNjc4Nlsx +MDAwXTE2Nzg3WzEwMDBdMTY3OTJbMTAwMF0xNjc5NFsxMDAwXTE2Nzk3WzEwMDBdMTY4MDFbMTAw +MF0xNjgxN1sxMDAwXTE2ODIyWzEwMDBdMTY4MjVbMTAwMF0xNjgzNVsxMDAwXTE2ODQwWzEwMDBd +MTY4NDNbMTAwMF0xNjg1MFsxMDAwXTE2ODUzWzEwMDBdMTY4NjBbMTAwMF0xNjg2NlsxMDAwXTE2 +OTQ5WzEwMDBdMTcwMzJbMTAwMF0xNzEzOVsxMDAwXTE3MTQ1WzEwMDBdMTcxNTNbMTAwMF0xNzE2 +NVsxMDAwXTE3MTc2WzEwMDBdMTcxOTRbMTAwMF0xNzIyMFsxMDAwXTE3MjQ2WzEwMDBdMTcyNzFb +MTAwMF0xNzI4N1sxMDAwXTE3MzMxWzEwMDBdMTczNDdbMTAwMF0xNzcyOFsxMDAwXTE3NzQzWzEw +MDBdMTc3NjVbMTAwMF0xNzc4OVsxMDAwXTE3ODEwWzEwMDBdMTc4MTlbMTAwMF0xNzgyNlsxMDAw +XTE3ODM2WzEwMDBdMTc4MzdbMTAwMF0xNzgzOVsxMDAwXTE3ODQyWzEwMDBdMTc4NDNbMTAwMF0x +Nzg3OFsxMDAwXTE3ODg1WzEwMDBdMTc5MDJbMTAwMF0xNzkzNVsxMDAwXTE3OTQ3WzEwMDBdMTc5 +NTlbMTAwMF0xNzk5M1sxMDAwXTE4MDA0WzEwMDBdMTgwMzlbMTAwMF0xODA0MlsxMDAwXTE4MDUw +WzEwMDBdMTgxMDhbMTAwMF0xODEyOVsxMDAwXTE4MjE0WzEwMDBdMTgzMzZbMTAwMF0xODMzN1sx +MDAwXTE4MzM5WzEwMDBdMTgzNDFbMTAwMF0xOTA3N1sxMDAwXTE5MTU2WzEwMDBdMTkzODhbMTAw +MF0xOTM5NFsxMDAwXTE5NDAwWzEwMDBdMTk0NDNbMTAwMF0xOTQ2M1sxMDAwXTE5NDY2WzEwMDBd +MTk0NzVbMTAwMF0xOTQ4OVsxMDAwXTE5NDkyWzEwMDBdMTk1MTBbMTAwMF0xOTUxN1sxMDAwXTE5 +NjEwWzEwMDBdMTk2NDRbMTAwMF0xOTY2OFsxMDAwXTE5NzYyWzEwMDBdMTk3NjZbMTAwMF0yMDA0 +NVsxMDAwXTIwMDc2WzEwMDBdMjAxNDZbMTAwMF0yMDE5NlsxMDAwXTIwMzQ4WzEwMDBdMjA1NDRb +MTAwMF0yMDU3NlsxMDAwXTIwNjAwWzEwMDBdMjA2NTJbMTAwMF0yMTczNVsxMDAwXTcwMVsxMDAw +XTcwOFsxMDAwXTcwOVsxMDAwXTcxMlsxMDAwXTcxM1sxMDAwXTcyNlsxMDAwXTcyN1sxMDAwXTcz +MVsxMDAwXTc5OFsxMDAwXV0NCi9Gb250RGVzY3JpcHRvciAyNyAwIFINCj4+DQplbmRvYmoNCjI5 +IDAgb2JqDQo8PC9GaWx0ZXIgL0ZsYXRlRGVjb2RlIC9MZW5ndGggMzQxNA0KPj4NCnN0cmVhbQ0K +eJx9msmOnbcRRp9A73CXCbIQ5wEQBHAEvMiA2Mlelq4cAVGr0ZIXfvvw/86NjSCAFzZwxJ81sVgs +8vbr8d387unTt9vrv718ef/9/dvt46enDy/3r19+fnl/v/14/+nT082624dP7789SP9///nd8+31 +mfz9L1+/3T9/9/Txy+3Nm9ur138/o1+/vfxy+8MPP7g/mT/eXv/15cP95dPTT+dfgvvHP8+/fP/z +8/O/75/vT99u5vb27e3D/eOr1+PP757/8u7z/fZaE3/7xx9+eb7fnNg+lH/5cP/6/O79/eXd00/3 +2xtj7Xh7exPDym9v96cP/zv+yhrDvB8/vv/Xu5dXb4x3/nzvjI1vX/13tnO2iXq8KDYDTdHY0L4o +mSQalxRvjIUC5KAKIXM0qENbZNEwDSQpfl5SwjIGypCHJlShBTVoQ9Lgl4Um5KAFIdMicxUoQA1K +EBqIi98GGhBjTmPBoM9NCB+8gfjSP77ETi87g8Uyv6AhCgXC2yBvg0N7GBAaIho82iPavYc2xJeJ +LwOUHxQhRT5EfC8JQntBe8TqgtUJWwq2JKRUpKQEOYjo1gAhpSIlM9YYyx3KooKGhoZClBpRKsSz +E8+KRwOPaoUixJfj8SXaB9obMgcyG7ZMbGlEYhKJxqpMVqWTPctD6Fvo6+hb6Bv4sPBh4N/Gv4Et +G1sm67dZv6l4bnbVsVBk0U5GbjIybPm+Hb7vAsmHaOXDDvIhOgtNyEMbkg87RmhDsix6Aw0IfeRS +jEjJSCFDNhkSWenNSseO9on2jn9L/kXt1GjYqXFNkVXWJe2OaNgdyS1RlO9Jlh2SZal5EVUq22uN +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 ++y0Frj/Auf466Nc/6Hn/88vL/emb/oRIf9Fz/S3Pp6f7r39l9Pzl+fqzneu//wAdJcyRDQplbmRz +dHJlYW0NCmVuZG9iag0KNCAwIG9iag0KPDwvVHlwZSAvRm9udA0KL1N1YnR5cGUgL1R5cGUwDQov +QmFzZUZvbnQgL8vOzOUNCi9FbmNvZGluZyAvSWRlbnRpdHktSA0KL0Rlc2NlbmRhbnRGb250cyBb +MjggMCBSXQ0KL1RvVW5pY29kZSAyOSAwIFINCj4+DQplbmRvYmoNCjE4IDAgb2JqDQo8PC9UeXBl +IC9Gb250DQovU3VidHlwZSAvVHlwZTENCi9CYXNlRm9udCAvSGVsdmV0aWNhDQovRW5jb2Rpbmcg +L1dpbkFuc2lFbmNvZGluZw0KL0ZpcnN0Q2hhciAzMg0KL0xhc3RDaGFyIDI1NQ0KPj4NCmVuZG9i +ag0KeHJlZg0KMCAzMA0KMDAwMDAwMDAwMCA2NTUzNSBmDQowMDAwMDA4MDg3IDAwMDAwIG4NCjAw +MDAwMDE5MDAgMDAwMDAgbg0KMDAwMDAwNzkwMCAwMDAwMCBuDQowMDAwMTI1MDE2IDAwMDAwIG4N +CjAwMDAwMTYzMDEgMDAwMDAgbg0KMDAwMDAwMDAxNyAwMDAwMCBuDQowMDAwMDAwMTAzIDAwMDAw +IG4NCjAwMDAwMDM1NjQgMDAwMDAgbg0KMDAwMDAwMjAxMyAwMDAwMCBuDQowMDAwMDAyMDk5IDAw +MDAwIG4NCjAwMDAwMDUwNTIgMDAwMDAgbg0KMDAwMDAwMzY3OCAwMDAwMCBuDQowMDAwMDAzNzY1 +IDAwMDAwIG4NCjAwMDAwMDcxOTUgMDAwMDAgbg0KMDAwMDAwNTE2OCAwMDAwMCBuDQowMDAwMDA1 +MjU1IDAwMDAwIG4NCjAwMDAwMDc1MjUgMDAwMDAgbg0KMDAwMDEyNTE1NSAwMDAwMCBuDQowMDAw +MDA3MzExIDAwMDAwIG4NCjAwMDAwMDczODYgMDAwMDAgbg0KMDAwMDAwNzY0MSAwMDAwMCBuDQow +MDAwMDA3ODU3IDAwMDAwIG4NCjAwMDAwMDgxODQgMDAwMDAgbg0KMDAwMDAwODI4NCAwMDAwMCBu +DQowMDAwMDE2MTA4IDAwMDAwIG4NCjAwMDAwMTY4MTYgMDAwMDAgbg0KMDAwMDExNDYwNyAwMDAw +MCBuDQowMDAwMTE0ODAwIDAwMDAwIG4NCjAwMDAxMjE1MjIgMDAwMDAgbg0KdHJhaWxlcg0KPDwN +Ci9TaXplIDMwDQovUm9vdCAyMyAwIFINCi9JbmZvIDIxIDAgUg0KL0lEIFs8Njg0Mzk3YTBiMDY1 +MWZhZTFmYzgxOGVkZWY3M2RlNGU+PDY4NDM5N2EwYjA2NTFmYWUxZmM4MThlZGVmNzNkZTRlPl0N +Cj4+DQpzdGFydHhyZWYNCjEyNTI4OQ0KJSVFT0YNCg== + +------=zeioty211_5706_231298841.667468-- + diff --git a/lib_acl_cpp/samples/mime/test2.eml b/lib_acl_cpp/samples/mime/test2.eml new file mode 100644 index 000000000..6d657422a --- /dev/null +++ b/lib_acl_cpp/samples/mime/test2.eml @@ -0,0 +1,671 @@ +X-Uidl: 1284714126.19811_3.localhost&&mail.51iker.com +Return-Path: +Delivered-To: all1@51iker.com +Received: from SKY-20100331OBQ (unknown [123.122.115.98]) + by 51iker.com (zebra mail for UNIX) with ESMTP id 1D711274658; + Fri, 17 Sep 2010 17:02:06 +0800 (CST) +Date: Fri, 17 Sep 2010 17:01:33 +0800 +From: "=?gb2312?B?0NDV/rK/?=" +To: "all1" , + "all2" , + "all3" +Subject: =?gb2312?B?v7zH2s2o1qo=?= +Message-ID: <201009171701333901318@51iker.com> +Organization: =?gb2312?B?sbG+qbCsv8vI/MDWv8a8vNPQz965q8u+?= +X-mailer: Foxmail 6, 15, 201, 22 [cn] +Mime-Version: 1.0 +Content-Type: multipart/related; + boundary="=====002_Dragon104620023824_====="; + type="multipart/alternative" + +This is a multi-part message in MIME format. + +--=====002_Dragon104620023824_===== +Content-Type: multipart/alternative; + boundary="=====003_Dragon104620023824_=====" + + +--=====003_Dragon104620023824_===== +Content-Type: text/plain; + charset="gb2312" +Content-Transfer-Encoding: base64 + +DQoNCg0KIA0KuPfOu82s0aejug0KDQogICAgICCxvtTCv7zH2s2zvMbI1c6qMjDI1aOst7PH67j3 +zrvNrNGn1NoxOcjVz8Kw4Naux7C+ob/svau49sjL0OjSqsnqy9+1xMrC08nV0rK/w8XB7LW8yfPF ++s2oDQoNCrn9oaPT4sbasrvU2dDeuMS/vMfaoaMNCiAgICAgICANCiAgICAgIMHtt7PH67G+1MLT +0MfrxOq82aGiysK82aGisqG82bXEzazRp7K5t6LTyrz+uPiyv8PFwey1vMnzxfqyoteqt6K4+NDQ +1f6yv6Gj0LvQu7j3zrvNrNGnxeS6z6GjDQoNCsjn1Nq/vMfayNXOtMrVtb3S1MnP08q8/qOsztKy +v8PFvauwtNXVv7zH2tHPuPHWtNDQsrvU2df2yM66ztDeuMShow0KDQogICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICCwrL/LyPzA1tDQ1f6yvw0KMjAxMC0wOS0xNyANCg0KDQoNCtDQ1f6yvyANCg== + +--=====003_Dragon104620023824_===== +Content-Type: text/html; + charset="gb2312" +Content-Transfer-Encoding: base64 + +PCFET0NUWVBFIEhUTUwgUFVCTElDICItLy9XM0MvL0RURCBIVE1MIDQuMCBUcmFuc2l0aW9uYWwv +L0VOIj4NCjxIVE1MIHhtbG5zOm8gPSAidXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTpvZmZpY2U6 +b2ZmaWNlIj48SEVBRD4NCjxNRVRBIGh0dHAtZXF1aXY9Q29udGVudC1UeXBlIGNvbnRlbnQ9InRl +eHQvaHRtbDsgY2hhcnNldD1nYjIzMTIiPg0KPFNUWUxFIHR5cGU9dGV4dC9jc3M+Qk9EWSB7DQoJ +UEFERElORy1SSUdIVDogMHB4OyBQQURESU5HLUxFRlQ6IDBweDsgUEFERElORy1CT1RUT006IDBw +eDsgTUFSR0lOOiAwcHg7IFBBRERJTkctVE9QOiAwcHgNCn0NCkJMT0NLUVVPVEUgew0KCU1BUkdJ +Ti1UT1A6IDBweDsgTUFSR0lOLUJPVFRPTTogMHB4OyBNQVJHSU4tTEVGVDogMmVtDQp9DQpPTCB7 +DQoJTUFSR0lOLVRPUDogMHB4OyBNQVJHSU4tQk9UVE9NOiAwcHgNCn0NClVMIHsNCglNQVJHSU4t +VE9QOiAwcHg7IE1BUkdJTi1CT1RUT006IDBweA0KfQ0KPC9TVFlMRT4NCg0KPE1FVEEgY29udGVu +dD0iTVNIVE1MIDYuMDAuMjkwMC42MDAzIiBuYW1lPUdFTkVSQVRPUj48L0hFQUQ+DQo8Qk9EWSBz +dHlsZT0iTUFSR0lOLVRPUDogMHB4OyBNQVJHSU4tTEVGVDogMHB4OyBNQVJHSU4tUklHSFQ6IDBw +eCI+PCEtLSA1Ml8zMDI5MDNfZTExNDE1ZjEyNjc4MWJmIC0tPg0KPFRBQkxFIGlkPVRhYmxlXzAx +IA0Kc3R5bGU9IkJBQ0tHUk9VTkQ6ICNmZmY7IEZPTlQtRkFNSUxZOiBWZXJkYW5hLCBBcmlhbCwg +SGVsdmV0aWNhLCBzYW5zLXNlcmlmIiANCmNlbGxTcGFjaW5nPTAgY2VsbFBhZGRpbmc9MCB3aWR0 +aD0iOTkuOTklIiBib3JkZXI9MD4NCiAgPFRCT0RZPg0KICA8VFI+DQogICAgPFREIHZBbGlnbj10 +b3AgYmFja2dyb3VuZD1jaWQ6X18xQEZveG1haWwubmV0PjxJTUcgaGVpZ2h0PTEgDQogICAgICBz +cmM9ImNpZDpfXzBARm94bWFpbC5uZXQiIHdpZHRoPTQ5PjwvVEQ+DQogICAgPFREIHZBbGlnbj10 +b3AgYmFja2dyb3VuZD1jaWQ6X18yQEZveG1haWwubmV0Pg0KICAgICAgPFRBQkxFIGNlbGxTcGFj +aW5nPTAgY2VsbFBhZGRpbmc9MCB3aWR0aD04NyBib3JkZXI9MD4NCiAgICAgICAgPFRCT0RZPg0K +ICAgICAgICA8VFI+DQogICAgICAgICAgPFREIGJhY2tncm91bmQ9Y2lkOl9fMTBARm94bWFpbC5u +ZXQ+PElNRyBoZWlnaHQ9NTAgDQogICAgICAgICAgICBzcmM9ImNpZDpfXzBARm94bWFpbC5uZXQi +IHdpZHRoPTg3PjwvVEQ+PC9UUj48L1RCT0RZPjwvVEFCTEU+PC9URD4NCiAgICA8VEQgdkFsaWdu +PXRvcCBiYWNrZ3JvdW5kPWNpZDpfXzNARm94bWFpbC5uZXQ+PElNRyBoZWlnaHQ9NTAgDQogICAg +ICBzcmM9ImNpZDpfXzBARm94bWFpbC5uZXQiIHdpZHRoPTg0PjwvVEQ+PC9UUj4NCiAgPFRSPg0K +ICAgIDxURCB2QWxpZ249dG9wIGFsaWduPXJpZ2h0IGJhY2tncm91bmQ9Y2lkOl9fNEBGb3htYWls +Lm5ldD4NCiAgICAgIDxUQUJMRSBjZWxsU3BhY2luZz0wIGNlbGxQYWRkaW5nPTAgd2lkdGg9NTAg +Ym9yZGVyPTA+DQogICAgICAgIDxUQk9EWT4NCiAgICAgICAgPFRSPg0KICAgICAgICAgIDxURCBi +YWNrZ3JvdW5kPWNpZDpfXzExQEZveG1haWwubmV0PjxJTUcgaGVpZ2h0PTEzNCANCiAgICAgICAg +ICAgIHNyYz0iY2lkOl9fMEBGb3htYWlsLm5ldCIgd2lkdGg9NDk+PC9URD48L1RSPjwvVEJPRFk+ +PC9UQUJMRT48L1REPg0KICAgIDxURCANCiAgICBzdHlsZT0iUEFERElORy1SSUdIVDogNTBweDsg +QkFDS0dST1VORC1QT1NJVElPTjogcmlnaHQgYm90dG9tOyBQQURESU5HLUxFRlQ6IDQwcHg7IFBB +RERJTkctQk9UVE9NOiA2MHB4OyBQQURESU5HLVRPUDogNDBweDsgQkFDS0dST1VORC1SRVBFQVQ6 +IG5vLXJlcGVhdDsgSEVJR0hUOiAzMDBweCIgDQogICAgdkFsaWduPXRvcCB3aWR0aD0iMTAwJSIg +YmFja2dyb3VuZD1jaWQ6X181QEZveG1haWwubmV0IGJnQ29sb3I9I2ZmZmNmMz4NCiAgICAgIDxU +QUJMRSBzdHlsZT0iTUFSR0lOLVRPUDogMHB4OyBjZWxscGFkZGluZzogMHB4OyBjZWxsc3BhY2lu +ZzogMHB4IiANCiAgICAgIHdpZHRoPSIxMDAlIiB2YWxpZ249InRvcCI+DQogICAgICAgIDxUQk9E +WT4NCiAgICAgICAgPFRSPg0KICAgICAgICAgIDxURCBzdHlsZT0iTElORS1IRUlHSFQ6IDE2MCUi +Pg0KICAgICAgICAgICAgPERJViANCiAgICAgICAgICAgIHN0eWxlPSJXSURUSDogMTAwJTsgV09S +RC1CUkVBSzogYnJlYWstYWxsOyBXSElURS1TUEFDRTogbm9ybWFsIj48Rk9OVCANCiAgICAgICAg +ICAgIGZhY2U9VmVyZGFuYSBjb2xvcj0jMDAwMDgwIHNpemU9Mj4NCiAgICAgICAgICAgIDxESVY+ +DQogICAgICAgICAgICA8RElWPjxGT05UIHNpemU9Mz48L0ZPTlQ+PC9ESVY+Jm5ic3A7PC9ESVY+ +DQogICAgICAgICAgICA8RElWPjxGT05UIGNvbG9yPSNjMGMwYzA+DQogICAgICAgICAgICA8RElW +PjxGT05UIGNvbG9yPSMwMDAwMDAgc2l6ZT00Prj3zrvNrNGno7o8L0ZPTlQ+PC9ESVY+DQogICAg +ICAgICAgICA8RElWPjxGT05UIGNvbG9yPSMwMDAwMDAgc2l6ZT00PjwvRk9OVD4mbmJzcDs8L0RJ +Vj4NCiAgICAgICAgICAgIDxESVY+PEZPTlQgY29sb3I9IzAwMDAwMCANCiAgICAgICAgICAgIHNp +emU9ND4mbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDuxvtTCv7zH2s2zvMbI1c6q +MjDI1aOst7PH67j3zrvNrNGn1NoxOcjVz8Kw4Naux7C+ob/svau49sjL0OjSqsnqy9+1xMrC08nV +0rK/w8XB7LW8yfPF+s2oPC9GT05UPjwvRElWPg0KICAgICAgICAgICAgPERJVj48Rk9OVCBjb2xv +cj0jMDAwMDAwIHNpemU9ND48L0ZPTlQ+Jm5ic3A7PC9ESVY+DQogICAgICAgICAgICA8RElWPjxG +T05UIGNvbG9yPSMwMDAwMDAgc2l6ZT00Prn9oaM8L0ZPTlQ+PEZPTlQgY29sb3I9I2ZmMDAwMCAN +CiAgICAgICAgICAgIHNpemU9ND48U1RST05HPtPixtqyu9TZ0N64xL+8x9qhozwvU1RST05HPjwv +Rk9OVD48L0RJVj4NCiAgICAgICAgICAgIDxESVY+PEZPTlQgY29sb3I9IzAwMDAwMCBzaXplPTQ+ +Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7IA0KICAgICAgICAgICAgPC9GT05U +PjwvRElWPg0KICAgICAgICAgICAgPERJVj48Rk9OVCBjb2xvcj0jMDAwMDAwIHNpemU9ND4mbmJz +cDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsgDQogICAgICAgICAgICDB7bezx+uxvtTC09DH68Tq +vNmhosrCvNmhorKhvNm1xM2s0aeyubei08q8/rj4sr/DxcHstbzJ88X6sqLXqreiuPjQ0NX+sr+h +o9C70Lu49867zazRp8Xkus+hozwvRk9OVD48L0RJVj48Rk9OVCANCiAgICAgICAgICAgIGNvbG9y +PSMwMDAwMDAgc2l6ZT00PjwvRk9OVD4NCiAgICAgICAgICAgIDxESVY+PEZPTlQgY29sb3I9I2Mw +YzBjMD48Rk9OVCBjb2xvcj0jMDAwMDAwIA0KICAgICAgICAgICAgc2l6ZT00PjwvRk9OVD48L0ZP +TlQ+Jm5ic3A7PC9ESVY+DQogICAgICAgICAgICA8RElWPjxGT05UIGNvbG9yPSNjMGMwYzA+PEZP +TlQgY29sb3I9I2ZmMDAwMCANCiAgICAgICAgICAgIHNpemU9ND48U1RST05HPsjn1Nq/vMfayNXO +tMrVtb3S1MnP08q8/qOsztKyv8PFvauwtNXVv7zH2tHPuPHWtNDQsrvU2df2yM66ztDeuMShozwv +U1RST05HPjwvRk9OVD48L0ZPTlQ+PC9ESVY+DQogICAgICAgICAgICA8RElWPjxGT05UIGNvbG9y +PSNjMGMwYzA+PFNUUk9ORz48Rk9OVCBjb2xvcj0jZmYwMDAwIA0KICAgICAgICAgICAgc2l6ZT00 +PjwvRk9OVD48L1NUUk9ORz48L0ZPTlQ+Jm5ic3A7PC9ESVY+DQogICAgICAgICAgICA8RElWPjxG +T05UIGNvbG9yPSNjMGMwYzA+PFNUUk9ORz48Rk9OVCBjb2xvcj0jZmYwMDAwIA0KICAgICAgICAg +ICAgc2l6ZT00PiZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNw +OyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZu +YnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNw +OyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZu +YnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNw +OyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZu +YnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNw +OyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyAN +CiAgICAgICAgICAgIDxGT05UIA0KICAgICAgICAgICAgY29sb3I9IzAwMDAwMD6wrL/LyPzA1tDQ +1f6yvzwvRk9OVD48L0ZPTlQ+PC9TVFJPTkc+PC9GT05UPjxCUj4yMDEwLTA5LTE3IA0KICAgICAg +ICAgICAgPC9GT05UPjwvRElWPjwvRElWPg0KICAgICAgICAgICAgPERJViBhbGlnbj1sZWZ0Pg0K +ICAgICAgICAgICAgPEhSIHN0eWxlPSJXSURUSDogMTIycHg7IEhFSUdIVDogMnB4IiBhbGlnbj1s +ZWZ0IFNJWkU9Mj4NCiAgICAgICAgICAgIDwvRElWPg0KICAgICAgICAgICAgPERJVj48Rk9OVCBj +b2xvcj0jYzBjMGMwPjxTUEFOPtDQ1f6yvzwvU1BBTj4gDQogICAgICAgICAgPC9ESVY+PC9GT05U +PjwvRElWPjwvRk9OVD48L1REPjwvVFI+PC9UQk9EWT48L1RBQkxFPjwvVEQ+DQogICAgPFREIHZB +bGlnbj1ib3R0b20gYmFja2dyb3VuZD1jaWQ6X182QEZveG1haWwubmV0Pg0KICAgICAgPFRBQkxF +IGNlbGxTcGFjaW5nPTAgY2VsbFBhZGRpbmc9MCB3aWR0aD0iMTAwJSIgYm9yZGVyPTA+DQogICAg +ICAgIDxUQk9EWT4NCiAgICAgICAgPFRSPg0KICAgICAgICAgIDxURCBiYWNrZ3JvdW5kPWNpZDpf +XzEyQEZveG1haWwubmV0PjxJTUcgaGVpZ2h0PTM1NyANCiAgICAgICAgICAgIHNyYz0iY2lkOl9f +MEBGb3htYWlsLm5ldCIgd2lkdGg9ODQ+PC9URD48L1RSPjwvVEJPRFk+PC9UQUJMRT48L1REPjwv +VFI+DQogIDxUUj4NCiAgICA8VEQgdkFsaWduPXRvcCBiYWNrZ3JvdW5kPWNpZDpfXzdARm94bWFp +bC5uZXQ+PElNRyBoZWlnaHQ9MSANCiAgICAgIHNyYz0iY2lkOl9fMEBGb3htYWlsLm5ldCIgd2lk +dGg9NDk+PC9URD4NCiAgICA8VEQgdkFsaWduPXRvcCBhbGlnbj1yaWdodCBiYWNrZ3JvdW5kPWNp +ZDpfXzhARm94bWFpbC5uZXQ+DQogICAgICA8VEFCTEUgY2VsbFNwYWNpbmc9MCBjZWxsUGFkZGlu +Zz0wIHdpZHRoPTEyNSBib3JkZXI9MD4NCiAgICAgICAgPFRCT0RZPg0KICAgICAgICA8VFI+DQog +ICAgICAgICAgPFREIGJhY2tncm91bmQ9Y2lkOl9fMTNARm94bWFpbC5uZXQ+PElNRyBoZWlnaHQ9 +NTggDQogICAgICAgICAgICBzcmM9ImNpZDpfXzBARm94bWFpbC5uZXQiIHdpZHRoPTEyNT48L1RE +PjwvVFI+PC9UQk9EWT48L1RBQkxFPjwvVEQ+DQogICAgPFREIHZBbGlnbj10b3AgYmFja2dyb3Vu +ZD1jaWQ6X185QEZveG1haWwubmV0PjxJTUcgaGVpZ2h0PTU4IA0KICAgICAgc3JjPSJjaWQ6X18w +QEZveG1haWwubmV0IiB3aWR0aD04ND48L1REPjwvVFI+PC9UQk9EWT48L1RBQkxFPjwvQk9EWT48 +L0hUTUw+DQo= + +--=====003_Dragon104620023824_=====-- + +--=====002_Dragon104620023824_===== +Content-Type: image/gif; + name="spacer.gif" +Content-Transfer-Encoding: base64 +Content-ID: <__0@Foxmail.net> + +R0lGODlhAQABAPAAAAAAAP///yH5BAEAAAEALAAAAAABAAEAAAICTAEAOw== + +--=====002_Dragon104620023824_===== +Content-Type: image/jpeg; + name="tl.jpg" +Content-Transfer-Encoding: base64 +Content-ID: <__1@Foxmail.net> + +/9j/4AAQSkZJRgABAgAAZABkAAD/7AARRHVja3kAAQAEAAAAPAAA/+4ADkFkb2JlAGTAAAAAAf/b +AIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoKDBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxsc +Hx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f +Hx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgAMgAzAwERAAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAA +AAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAAAQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIG +AnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPBUtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6Oz +NhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dn +d4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZqbnJ2en5KjpKWmp6ipqqusra6voRAAICAQID +BQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEyobHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LC +B3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaW +prbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq ++v/aAAwDAQACEQMRAD8A55mY4rsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVaqMVdyGK +XchireKHYq7FV1rbXF5cC3t1q5FWJNFVR1Zj2AxtKcpo2iwEJPJNdzU39MiKOvgKhmP3jButrvqP +l6tPqk5Ph62+/h8O/wBGK2t+q+XP+WWb/kd28fs4N1tJMkh2KrZDRcUpro7+hphZKCW5cln7hEPE +D765FSvLctyB02oAOnhTChVJ5x1NS67g/rqO21T/AJ7lDuT15V3rX6aca/d/t4qkmKXYqpT/AGTi +Upnp3/HNtz2o/wDycbIqUS6BAKmrHcqAdh8/H6MKHRtuR2pv1pt1+4H7sVXbVpy2p+NK4bVJsVdi +qlP9k4lKaab/AMc23+Tf8nWyKlFftJ1+wvXp0OEsQ1+12+y3y79P44Eqfb9v/M4Vf//Z + +--=====002_Dragon104620023824_===== +Content-Type: image/jpeg; + name="t_bg.jpg" +Content-Transfer-Encoding: base64 +Content-ID: <__2@Foxmail.net> + +/9j/4AAQSkZJRgABAgAAZABkAAD/7AARRHVja3kAAQAEAAAAPAAA/+4ADkFkb2JlAGTAAAAAAf/b +AIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoKDBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxsc +Hx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f +Hx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgAMgAHAwERAAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAA +AAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAAAQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIG +AnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPBUtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6Oz +NhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dn +d4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZqbnJ2en5KjpKWmp6ipqqusra6voRAAICAQID +BQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEyobHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LC +B3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaW +prbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq ++v/aAAwDAQACEQMRAD8A55mY4rsVa5DFKc/VvL3/ACyz/wDI3/m3I7pUcKuxVZ/wWKv/2Q== + +--=====002_Dragon104620023824_===== +Content-Type: image/jpeg; + name="tr.jpg" +Content-Transfer-Encoding: base64 +Content-ID: <__3@Foxmail.net> + +/9j/4AAQSkZJRgABAgAAZABkAAD/7AARRHVja3kAAQAEAAAAPAAA/+4ADkFkb2JlAGTAAAAAAf/b +AIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoKDBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxsc +Hx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f +Hx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgAMgBWAwERAAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAA +AAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAAAQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIG +AnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPBUtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6Oz +NhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dn +d4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZqbnJ2en5KjpKWmp6ipqqusra6voRAAICAQID +BQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEyobHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LC +B3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaW +prbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq ++v/aAAwDAQACEQMRAD8A55mY4rsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdir +sVa5DFLuQxQ3irsVdirsVdirsVdirsVdiqcfVvL3/LLP/wAjf+bcjuyabTtCmHGJp7STszFZU+kU +Vvxx3VK7u1nsp/RmoaiqSKaq6+KnCCghZhQ7FXYq7FXYq7FXYq7FUywMnYqtvj6umujbtARJEfDc +Bh9IwKlkTVXJIX4odirsVdirsVdirsVTLAydiqldf7x3H/GM/rGAqllv9kZIIVsUOxV2KuxV2Kux +V2KplgZOxVSu/wDeK4/4xn9YwKllv9kZIIVsUOxV2KuxV2KuxV2Kv//Z + +--=====002_Dragon104620023824_===== +Content-Type: image/jpeg; + name="m_bgl.jpg" +Content-Transfer-Encoding: base64 +Content-ID: <__4@Foxmail.net> + +/9j/4AAQSkZJRgABAgAAZABkAAD/7AARRHVja3kAAQAEAAAAPAAA/+4ADkFkb2JlAGTAAAAAAf/b +AIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoKDBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxsc +Hx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f +Hx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgABQAzAwERAAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAA +AAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAAAQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIG +AnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPBUtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6Oz +NhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dn +d4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZqbnJ2en5KjpKWmp6ipqqusra6voRAAICAQID +BQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEyobHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LC +B3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaW +prbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq ++v/aAAwDAQACEQMRAD8A55mY4rsVUp/snEpTCw/459v8n/5ONkQlXwq7FVL9r/Z/8a4Ff//Z + +--=====002_Dragon104620023824_===== +Content-Type: image/jpeg; + name="m.jpg" +Content-Transfer-Encoding: base64 +Content-ID: <__5@Foxmail.net> + +/9j/4AAQSkZJRgABAgAAZABkAAD/7AARRHVja3kAAQAEAAAAPAAA/+4ADkFkb2JlAGTAAAAAAf/b +AIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoKDBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxsc +Hx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f +Hx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgAzwCtAwERAAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAA +AAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAAAQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIG +AnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPBUtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6Oz +NhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dn +d4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZqbnJ2en5KjpKWmp6ipqqusra6voRAAICAQID +BQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEyobHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LC +B3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaW +prbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq ++v/aAAwDAQACEQMRAD8A9S5SydirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVY +JP5zif8AOyy8opKAIdAu76dK/ammu7ZYl/1ljhkb5NhrZWd4FdirsVdirsVdirsVdirsVdirsVdi +rsVdirsVdirsVdirsVdirsVfCP8Aytr/AKyT/wAcet/uN/Sn1bnX4f0dT6nyp/xg+OnjllbIfd2V +pdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirBPzw83f4U/K3X9VR+F21ubSyIPx +evdH0UZfdOfP6MIG6vzrptmRw+m2D9T8xmbsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirs +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 +irsVdirsVdir/9k= + +--=====002_Dragon104620023824_===== +Content-Type: image/jpeg; + name="m_bgr.jpg" +Content-Transfer-Encoding: base64 +Content-ID: <__6@Foxmail.net> + +/9j/4AAQSkZJRgABAgAAZABkAAD/7AARRHVja3kAAQAEAAAAPAAA/+4ADkFkb2JlAGTAAAAAAf/b +AIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoKDBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxsc +Hx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f +Hx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgABQBWAwERAAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAA +AAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAAAQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIG +AnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPBUtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6Oz +NhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dn +d4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZqbnJ2en5KjpKWmp6ipqqusra6voRAAICAQID +BQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEyobHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LC +B3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaW +prbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq ++v/aAAwDAQACEQMRAD8AhcX92vyzLcdfiqld/wC8Vx/xjP6xgVLLf7IyQQrYodirsVdirsVdirsV +f//Z + +--=====002_Dragon104620023824_===== +Content-Type: image/jpeg; + name="dl.jpg" +Content-Transfer-Encoding: base64 +Content-ID: <__7@Foxmail.net> + +/9j/4AAQSkZJRgABAgAAZABkAAD/7AARRHVja3kAAQAEAAAAPAAA/+4ADkFkb2JlAGTAAAAAAf/b +AIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoKDBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxsc +Hx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f +Hx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgAOgAzAwERAAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAA +AAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAAAQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIG +AnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPBUtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6Oz +NhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dn +d4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZqbnJ2en5KjpKWmp6ipqqusra6voRAAICAQID +BQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEyobHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LC +B3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaW +prbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq ++v/aAAwDAQACEQMRAD8A55mY4rsVUp/snEpTCw/459v8n/5ONkQlXwq7FWqD+OKpdhYuxVSn+ycS +lMLD/jn2/wAn/wCTjZEJV8KuxV2KpbhYuxVSn+ycSlMLD/jn2/yf/k42RCVfCrsVdiqW4WLsVUp/ +snEpTDTz/uPt/YP/AMnGyISr4VdirsVS3CxdiqyUVXFLenXax1t5DShLIfEHqP45FKZggio3GFW8 +VdiqW4WLsVcRXFULPb8tx1wEJBU1ur+LYNyHvWv3imRpla79Jah4D8f647q79Jah4D8f64qjMmwd +irsVdTFVpjU4pa9JcVa9FcVVMUOxV2KuxV2KuxV2Kv8A/9k= + +--=====002_Dragon104620023824_===== +Content-Type: image/jpeg; + name="d_bg.jpg" +Content-Transfer-Encoding: base64 +Content-ID: <__8@Foxmail.net> + +/9j/4AAQSkZJRgABAgAAZABkAAD/7AARRHVja3kAAQAEAAAAPAAA/+4ADkFkb2JlAGTAAAAAAf/b +AIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoKDBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxsc +Hx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f +Hx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgAOgAFAwERAAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAA +AAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAAAQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIG +AnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPBUtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6Oz +NhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dn +d4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZqbnJ2en5KjpKWmp6ipqqusra6voRAAICAQID +BQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEyobHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LC +B3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaW +prbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq ++v/aAAwDAQACEQMRAD8AhH1S3rXgK+OZVOOrYVdirsVdiqQ/pLUPAfj/AFyKUR6K5NiqYof/2Q== + +--=====002_Dragon104620023824_===== +Content-Type: image/jpeg; + name="dr.jpg" +Content-Transfer-Encoding: base64 +Content-ID: <__9@Foxmail.net> + +/9j/4AAQSkZJRgABAgAAZABkAAD/7AARRHVja3kAAQAEAAAAPAAA/+4ADkFkb2JlAGTAAAAAAf/b +AIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoKDBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxsc +Hx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f +Hx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgAOgBWAwERAAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAA +AAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAAAQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIG +AnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPBUtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6Oz +NhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dn +d4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZqbnJ2en5KjpKWmp6ipqqusra6voRAAICAQID +BQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEyobHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LC +B3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaW +prbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq ++v/aAAwDAQACEQMRAD8Ai0pJUctqV23+yTUD3zLLiBT5t1rufpOBLV1IWsbjuAhoep6iv0t164So +Sq2BCAEbgDcV+YP09cIQVaPdlqepFa+5xUqrykEopoQN/H7u2SQpyUZQ56+21QP6HIlKw9cUr3Pw +H3A36e36sUNltlPQJXxFa09jirjK9Q33demFCOIYN0PL8en398gzcdtjsT2PXFVG73srj/jGfnTb ++uJVBWy8kCnZuiMRQEHxwhiVxVl2YU5dz0/DCrYLtTkSQdgST7djircm3Fa7gbntU0xKrN9idgNy +cUtkhq9vEHt2wK2iymvCq0+0SeNK9vwwodSXlSp51pXeuKps6cfsmoO4O24psegxVqrGMjwNCp2G +4NDt8sCoW8Wlnc03BjND074CyS+3H7sbU3A6D9eEIKsjsBsTTphQuPIMwB+ID4ytPCp33PfCqm32 +zTffamBLYjLMVWldzvsO+9caRbjHRuKk0qQSBUinU/xw0q9yBTl8CdlUKQK9uvtih1ADy5bEV5bV +6UxpbRqsUqFPXr3r4VyDJytxII7dfele+/bFVt6VOnTj9sR8T7itP4DCVCW228e+34dPniENgkMD ++0KGhwqqNJVdiwJoCN/p74rTokVmIIrUdK9x/DtiFK8CMN8INSCpWvsaGtPGhwoWlvgB3NfiIFRU +GhFaHYb9MFqt9So22Xw9sbTSzb0+O1K/TT/OmFUyNR1G9Kkfq6ZBLalADzJA7MOxH+3ilAapeIY/ +q0NWMlOZ6/CDXvTviqhbjgoU7dCBT+mFCpQ9dz0r88KGjTFKtErL8XMR17bdNu1Rt0whiWmCkgEU +rQGvTiT2Y9t8Sq6gKOGID1JFQd6b9QPEHrTEqFAb/wAMCV4A9M7Hl1p93tiqAXVNRO1B8qt/XIbs +3fWr+SgLbHuAa9/EntjS2uhgoeR3J3ZjuT7nCGKJCkCv0fqySrwwP6yMULaUHyIr9PTFK+P1eJVR +UdxWmx79R4YUFcQUPqRihUhqVB/yh06jpgKAtcUJUCoAG+1aClP4YpUwfbAlcKemdvlt/n44UKa2 +60LGgBGw7mv0+2NJt3EAnan+3irgMVXAnp1xVtloR4Hp4064q2G33/z7YqvQoo3Hzb28PHCEFsmP +Yii1qQQTXx8fo6YUNIoCt7UB8CBQV/DAlaY6khd/6YFaCNQjjv1pXtils/bXr0/hiqliru2KtjCq +p+z9A6fIfhgVTOKr06r/AJnEKXL/AJ+PfChpen0fT174FVE+w3+xwq7/AHZ/nTpgV//Z + +--=====002_Dragon104620023824_===== +Content-Type: image/jpeg; + name="t_ml.jpg" +Content-Transfer-Encoding: base64 +Content-ID: <__10@Foxmail.net> + +/9j/4AAQSkZJRgABAgAAZABkAAD/7AARRHVja3kAAQAEAAAAPAAA/+4ADkFkb2JlAGTAAAAAAf/b +AIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoKDBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxsc +Hx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f +Hx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgAMgBXAwERAAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAA +AAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAAAQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIG +AnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPBUtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6Oz +NhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dn +d4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZqbnJ2en5KjpKWmp6ipqqusra6voRAAICAQID +BQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEyobHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LC +B3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaW +prbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq ++v/aAAwDAQACEQMRAD8A55mY4rsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdir +sVa5DFLuQxV3IYq7kMVdyGKu5DFXchiruQxV3IYq7kMVdyGKp2bTy6P+PWf/AJG/825HdK9bLy4V +J+qzjrQ+sKbf7HFFtNZ+XQoP1Wevf994/wCxx3W1v1Ty7/yyzf8AI4f0x3S2tn5eP/HrP/yO/sx3 +Rar9Q8t8qG0nG1aer79OnhhRa0WHl2n+8k5Pek1fb+Xrtim3fUPLhNDazpX7PKUj3/lxpFtLY+Xm +6Ws5p1pN/wA2747ptabPy9SotZyPETf824Ftb9V8u/8ALLP/AMjf7Md0rGpyNBt7/wCfjiWLcbhW +HIfCdj9PXEKuP2ClOR5KB4nbYj6MKuiRTxJ3Wu9NyaUO34YFcgAZiV27qPn0X9WFV3GVmNRuepG4 +Phv3GFC5uPw0IJ6GlCK0B2+knAqxpmrtQA0r03798bSAsRiCPE7Gg/z8cVpdId+fTl18K9D9+KqF +cWSoxJJY9Tv40r164ChsKX2VeR7gdhT3oBtiEL1WRQDTemzAhhtuOh8cNIttnAqRWhoQfAN1K/Ti +rS1CigAbfcdgu3v/ALWKu4Kwrs1aAGlN228N8VW8v4V98UuCksF6Ek79vc4FWtRTsTQdyKYqtYnp +hSFuKW26H7XQ/ryKFVP7sfa+032vmPs/5WSCC2n/AD2/2PX6cUBbP9o9enb/AFR9r/KwJWj7Dfa+ +nr/tYQpXz9f92dT9rp2/HCgLU7/a7frGRS2ftr169+n2j1whVNug+1/n4e2BIU/+C+nril3/AAWF +X//Z + +--=====002_Dragon104620023824_===== +Content-Type: image/jpeg; + name="m_tl.jpg" +Content-Transfer-Encoding: base64 +Content-ID: <__11@Foxmail.net> + +/9j/4AAQSkZJRgABAgAAZABkAAD/7AARRHVja3kAAQAEAAAAPAAA/+4ADkFkb2JlAGTAAAAAAf/b +AIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoKDBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxsc +Hx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f +Hx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgAhgAzAwERAAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAA +AAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAAAQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIG +AnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPBUtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6Oz +NhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dn +d4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZqbnJ2en5KjpKWmp6ipqqusra6voRAAICAQID +BQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEyobHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LC +B3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaW +prbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq ++v/aAAwDAQACEQMRAD8A55mY4rsVUp/snEpTPTWpptuPZz/yUbfIqUVz5JQjYACu/wCoe2FDYKgE +DuCD91Dt712xVTr8VKn+8r+10418cCpVkldiqlP9k4lKcaWYxpdsKVdleg2/363XAEFWkUFeajwB +XY07Ajb+GJULKdPl3wJW8jy7f3leg60+eKErySuxVSn+ycSlNNNYnTbUeCvT3/esfGmRUop9ot+r +dD7V7fMgYSxCylemBksovP8A2fHp244oSzJK7FVKf7JxKU20ug0y1PGtQ9e3+7W603pgCCrycuZL +fa25fs9q0p264q0Aa0HU7ADv7DxwJUaH1KVHLly6/wCRX9WGkJdhV2KqU/2TiUptppppds4oaI6k +HtWV9+382RClXADsQCAd6VrUn+2nfChUReLowatQRsDsSCB1+YwoUfWXlWv+7uXXbpTw6+/8cFql +OFLsVUp/snEpTPTv+Obb/wCq/wDydbIqUVCSGDAcwPtDp2I74QgtvQHmvvXsQadx4/51xKAsp8VK +mnrcKb/y1r0617f8LilKcKuxVSn+ycSlM9OH+422J6Uc+1BK2RUotZyFoWI6UNTX2rTjhCC5vEGv +T2PjvUeOJUKfM8qUFOfOtO/Gv3V2wKlWSV2KqU/2TiUprph/3GW467N93qsaZFSioTwrU7+Han+f +uMKF5R+OzE9qEUBB+Z/rhQhafHXkft8abUpxpgTaWYVdiqlP9k4lKZad/wAc629g/wDycbIqUSKk +kAVPX/bxVdxNK/sjfkK06dq9cKFPk3KtT9unU9eNKf2YqleFXYqpT/ZOJSmenf8AHOtvk/8AycbI +qUUKU4VohO/jTfqcKHSsT8PRR0HbFQh670ptz6U9q0+VcCUvySHYqpT/AGTiUpppgJ063A8H/wCT +j5FSjOBodtyNh7dskxUiCd/HYHf/AD64EqXpjl1/b8P8n540lLsKHYqpT/ZOJSm+lMBpltXwcAf8 +9H3PtgCCiOQ3ANOQ3Y9SMKFlZCSATttQEfw2pXwwJUa/H1/3Z/xrgSl2SQ7FVKf7JxKU40sf7i7U +j7Xxg9O8j0r36jAEFWaQg7D5nff8cbWlOp5V7n/P6cbTSly+Lv8A3lf+F/XiqX4UOxVSn+ycSlNN +Np+jbceKv2r1lbIqVc7n3J2+eKrWFDSoNPDCqjX4v+en/GuBKByTF2KqU/2TiUppptP0bb+PF/8A +k42RClXZvDCqwscVUf2v9n/xrgSgskxdiqlP9k4lKZad/wAc+2Hs/wDycbIhSrstN64VW4pUv2v9 +n/xrgVBZJi7FVKf7JxKUy07/AI59t4Uf/k4+AKVZ68jXrXFWsUqX7X+z/wCNcCv/2Q== + +--=====002_Dragon104620023824_===== +Content-Type: image/jpeg; + name="m_dr.jpg" +Content-Transfer-Encoding: base64 +Content-ID: <__12@Foxmail.net> + +/9j/4AAQSkZJRgABAgAAZABkAAD/7AARRHVja3kAAQAEAAAAPAAA/+4ADkFkb2JlAGTAAAAAAf/b +AIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoKDBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxsc +Hx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f +Hx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgBZQBWAwERAAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAA +AAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAAAQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIG +AnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPBUtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6Oz +NhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dn +d4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZqbnJ2en5KjpKWmp6ipqqusra6voRAAICAQID +BQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEyobHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LC +B3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaW +prbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq ++v/aAAwDAQACEQMRAD8AhcX92vyzLcdfiqld/wC8Vx/xjP6xgVLLf7IyQQrYoUL29t7K1kubhuMU +Yqx7+wHucSaSBbzjWPNWp6jK3GRre2r8EMZI2/yiPtHMaUyW8QAUdJ8xajp90kgmeSEEepCzEqy9 +9j0PvgjMhTEF6lFIksSSoao6hlPiCKjMpoXYodiqPi/u1+WBkvxVSu/94rj/AIxn9YwKllv9kZII +VsUKukWXk3zJcy6Rf+td3luxYwxCYIpG1Kxfabr7DMDVZZA7cnM0+MEb809uPyU/KOWJRcahqeiT +sOKzSIzW/M9ORkiP/ExmNHPJvlhHR55+YH5Ja75WC3VheQ69pUiepHdWoo/H+Zoqvt/qM3vTL45Q +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 +qKVwodNXglfs1NfnT/briqn+749Tyrt88Uv/2Q== + +--=====002_Dragon104620023824_===== +Content-Type: image/jpeg; + name="d_mr.jpg" +Content-Transfer-Encoding: base64 +Content-ID: <__13@Foxmail.net> + +/9j/4AAQSkZJRgABAgAAZABkAAD/7AARRHVja3kAAQAEAAAAPAAA/+4ADkFkb2JlAGTAAAAAAf/b +AIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoKDBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxsc +Hx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f +Hx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgAOgB9AwERAAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAA +AAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAAAQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIG +AnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPBUtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6Oz +NhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dn +d4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZqbnJ2en5KjpKWmp6ipqqusra6voRAAICAQID +BQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEyobHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LC +B3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaW +prbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq ++v/aAAwDAQACEQMRAD8Ag/1K2/kGZVOPbvqVt/IMaW3fUrb+QY0tu+pW38gxpbd9Stv5BjS276lb +fyDGlt31K2/kGNLbvqVt/IMaW2xZWx/3WMaW2/qVrT+7GNLapDY2u59MbAk/QMaQSuW0tmbeNKE0 +K7U6eOGkWsawtQxHAU7VG9CKiv35Gk22lla1NIxsPDDSkrha2iybxjYU4/7eKG/qlrXhwWhblTt1 +rSlKfjhVbiydirsVdirsVdirsVcMVXLTFC8qCKj6V/pihoBlYUqG7UrX8MCV6AULNsqj4q9OnQ9d +zhCCtZiXZj1J3wFWxsK9z74q0V6n764qqejccCd+NB8NRWnTphpbQ2LJ2KuxV2KuxV2KuxVsAHvT +FC5Vod/86Yquatf8xhQvQuQQT8ABLH2A36U7Yq41Kjkak04qNupFSANuxwFCnSv07j+uBkvEXwcz +spqB860qQK++EItuJWBNV3+yC1AKgivU0PSmNK3Va05tzJp0Faj6ae/XCxQ2BsdirsVdirsVdirY +FRihcgoe3y/z9sQpVHKh+S1oadev3dMUOYbAj8cVDS0B3FQRQ9K0IptirTPUkVLDt22NTT8cVpUA +jChmBpQhjXuD12GGkOB+GNBtuaHtTc/Om56eGBVpYA9Kg9/boNqlaY2lr1O9N/H/AD3xtaUcWTYF +cUOIGKtha+2KtlaCoHbY9jTFV6olWBPsp6/iPmMULBgSuQLvyr8vvwocxNTtT+wUxVtSSD/w1PDF +WipXY9en+f34q0q8jQb+JrSm3XAlWoVUKTzUV2WlV3qe/TJMVm4BJ3FQCaderHY+IpXfAl03HkGV +uQbaoqKUFANwDiVWbdciljv6S1DrQfj/AFxZNjUtQ8BX6f647q3+kdQ32Hj+1/XHdXLqepCvED72 +/r747oXfpHUCOgBpvuTXt447rs02qaidyASd+/fc9/njuuy39J6h4D/hv647pbXUtQ32H4/1xQ3+ +ktQ8APvH8cd1b/SOpBqFRUfP+uO6t/pPUCBso8ev6q47qs/SepAjYA7HuOoGw398d1VTqWpk0ZR7 +bmv3V2w7oWjUtQBbYUpXuP1H6MG6Vp1PUqgUHt16b++O67NfpK/p0X/hv64N1RCwr0pljFswL1p1 +/XirvSX+n8MVbESCpA+nwxVd6MRFdhXod6+GFDaWyVPTpsexHf7q4ra026H7PU9BgpbaEAWvw08M +UtmAdCPnjS2v9EOm4Fe1OlQOv4YoWGIBiKdD0+X9uKu9JDud9/xOBKrwhOxUUBqK9B9AAH4ZIIWv +BEalKHrtv+FTWuKrpbdOVBvt8J70AoO3gP140i1L0Er7dK/2dcjTK1y9/l/TCrY+z9H9cKrDgVte +g+eKrv2j9Pz6jChod/menXp/nTAq9P2v9U/LrhVo/aH0YFafr9C/8RGFC4fa7/aHXr1GKWpeuBVo +64Et9+/b7OFC7uf8x1/zpirY/ufp/wCNv91++FV3+7/2Ptf7Hr/n/ssCv//Z + +--=====002_Dragon104620023824_=====-- + diff --git a/lib_acl_cpp/samples/mime/test21.eml b/lib_acl_cpp/samples/mime/test21.eml new file mode 100644 index 000000000..1512f3fa2 --- /dev/null +++ b/lib_acl_cpp/samples/mime/test21.eml @@ -0,0 +1,383 @@ +X-Uidl: 1298600829.10068_0.localhost&&122.49.0.202 +Return-Path: +Delivered-To: zhengshuxin@51iker.com +Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) + by mail.renwou.com (renwou mail for UNIX) with SMTP id ECD27B6008B; + Fri, 25 Feb 2011 10:27:08 +0800 (CST) +RENWOU-SPAM-Result: Innocent +RENWOU-SPAM-Processed: Fri Feb 25 10:27:08 2011 +RENWOU-SPAM-SIGNATURE: 1,4d67137c20238594819145,2 +RENWOU-SPAM-Confidence: 0.9993 +RENWOU-SPAM-Probability: 0.0000 +Message-ID: +From: "Jessy" +To: =?utf-8?B?6aG+5Lyf?= , + "ljs" , + "Dai Qingguo" , + "zhengshuxin" , + "wangwenhua" , + =?utf-8?B?6LW15YW1?= , + "cx" , + =?utf-8?B?5b6Q5Yia6L6J?= +Subject: =?utf-8?B?SURD572R56uZ5pS554mI5a6M5oiQ?= +Date: Fri, 25 Feb 2011 10:27:03 +0800 +MIME-Version: 1.0 +Content-Type: multipart/related; + type="multipart/alternative"; + boundary="----=_NextPart_000_0003_01CBD4D6.8B23A510" +X-Priority: 3 +X-MSMail-Priority: Normal +X-Mailer: Microsoft Outlook Express 6.00.2900.5931 +X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2900.5931 + +This is a multi-part message in MIME format. + +------=_NextPart_000_0003_01CBD4D6.8B23A510 +Content-Type: multipart/alternative; + boundary="----=_NextPart_001_0004_01CBD4D6.8B23A510" + + +------=_NextPart_001_0004_01CBD4D6.8B23A510 +Content-Type: text/plain; + charset="utf-8" +Content-Transfer-Encoding: base64 + +NTFpa2VySURD572R56uZKHd3dy41MWlrZXIuY29tKeeahOaUueeJiOWfuuacrOWujOaIkCzlpKfl +rrbmnInml7bpl7TnnIvnnIss5aSa5o+Q5bu66K6u57uZ5oiRLg0KDQo6KQ0K77u/IA0KDQoNCiAg +ICAgDQoNCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t +LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQrnjovlu7rli4sgDQoNCm1zbu+8mnR1cmJv +bmV0LmNvbUBob3RtYWlsLmNvbQ0K55S16K+d77yaMDEwLTYyMTYgMzY2Mw0K5Lyg55yf77yaMDEw +LTg1OTcgNDAxNCBleHQgODAwDQrpgq7nrrHvvJp3YW5namlhbnh1bkA1MWlrZXIuY29tDQoNCg0K +5YyX5Lqs6Im+5YWL6LWb5LmQ56eR5oqA5pyJ6ZmQ5YWs5Y+4DQpCZWlqaW5nIEFjY2VsZXJhdGUg +VGVjaG5vbG9neSBDby4sTHRkDQoNCuWcsOWdgO+8muWMl+S6rOW4giDmtbfmt4DljLog57Sr56u5 +6Zmi6LevIDY55Y+3IOS4reWbveWFteWZqOWkp+WOpiAxOTA45a6kIA== + +------=_NextPart_001_0004_01CBD4D6.8B23A510 +Content-Type: text/html; + charset="utf-8" +Content-Transfer-Encoding: base64 + +77u/PCFET0NUWVBFIEhUTUwgUFVCTElDICItLy9XM0MvL0RURCBIVE1MIDQuMCBUcmFuc2l0aW9u +YWwvL0VOIj4NCjxIVE1MPjxIRUFEPjxUSVRMRSBpZD1yaWRUaXRsZT41MWlrZXI8L1RJVExFPg0K +PE1FVEEgaHR0cC1lcXVpdj1Db250ZW50LVR5cGUgY29udGVudD0idGV4dC9odG1sOyBjaGFyc2V0 +PXV0Zi04Ij48QkFTRSANCmhyZWY9ImZpbGU6Ly9DOlxQcm9ncmFtIEZpbGVzXENvbW1vbiBGaWxl +c1xNaWNyb3NvZnQgU2hhcmVkXFN0YXRpb25lcnlcIj4NCjxNRVRBIGNvbnRlbnQ9Ik1TSFRNTCA2 +LjAwLjI5MDAuNjA1OCIgbmFtZT1HRU5FUkFUT1I+DQo8U1RZTEU+PC9TVFlMRT4NCjwvSEVBRD4N +CjxCT0RZIGJnQ29sb3I9I2ZmZmZmZj4NCjxESVY+SURD572R56uZKHd3dy41MWlrZXIuY29tKeea +hOaUueeJiOWfuuacrOWujOaIkCzlpKflrrbmnInml7bpl7TnnIvnnIss5aSa5o+Q5bu66K6u57uZ +5oiRLjwvRElWPg0KPERJVj4mbmJzcDs8L0RJVj4NCjxESVY+Oik8L0RJVj4NCjxESVY+77u/IDwv +RElWPg0KPERJVj4mbmJzcDs8L0RJVj4NCjxESVY+PC9ESVY+DQo8VEFCTEUgc3R5bGU9Ik1BUkdJ +Ti1MRUZUOiAyMHB4IiBjZWxsU3BhY2luZz0wIGNlbGxQYWRkaW5nPTAgd2lkdGg9ODAwIA0KICBi +b3JkZXI9MD48VEJPRFk+DQogIDxUUj4NCiAgICA8VEQ+DQogICAgICA8RElWIHN0eWxlPSJGTE9B +VDogcmlnaHQ7IFdJRFRIOiAxNDRweDsgSEVJR0hUOiAyMTFweCI+PEEgDQogICAgICBocmVmPSJo +dHRwOi8vd3d3LjUxaWtlci5jb20iIHRhcmdldD1fYmxhbms+PElNRyBoZWlnaHQ9MjExIA0KICAg +ICAgc3JjPSJjaWQ6MzRDMDg1ODlGMzVFNDRFQ0E2ODQwQ0I5NjMxRDI3QTlAUEMyMDA5MTEyNTEy +MDAiIHdpZHRoPTE0NCANCiAgICAgIGJvcmRlcj0wPjwvQT48L0RJVj4NCiAgICAgIDxESVYgaWQ9 +cmlkQm9keSBzdHlsZT0iTUFSR0lOLUxFRlQ6IDIwcHg7IFdJRFRIOiA2MTZweCI+DQogICAgICA8 +RElWPiZuYnNwOzwvRElWPjwvRElWPjwvVEQ+PC9UUj48L1RCT0RZPjwvVEFCTEU+DQo8SFIgDQpz +dHlsZT0iTUFSR0lOLUxFRlQ6IDIwcHg7IFdJRFRIOiA4MDBweDsgQ09MT1I6ICNjY2M7IEhFSUdI +VDogMXB4OyBURVhULUFMSUdOOiBsZWZ0Ij4NCg0KPERJViANCnN0eWxlPSJGT05ULVNJWkU6IDEy +cHg7IFdJRFRIOiA4MDBweDsgQ09MT1I6ICM4ODg7IEZPTlQtRkFNSUxZOiBWZXJkYW5hIj48Qj7n +jovlu7rli4s8L0I+IA0KPEJSPjxCUj5tc27vvJp0dXJib25ldC5jb21AaG90bWFpbC5jb208QlI+ +55S16K+d77yaMDEwLTYyMTYgMzY2MzxCUj7kvKDnnJ/vvJowMTAtODU5NyA0MDE0IGV4dCANCjgw +MDxCUj7pgq7nrrHvvJp3YW5namlhbnh1bkA1MWlrZXIuY29tPEJSPjxCUj48QlI+5YyX5Lqs6Im+ +5YWL6LWb5LmQ56eR5oqA5pyJ6ZmQ5YWs5Y+4PEJSPkJlaWppbmcgQWNjZWxlcmF0ZSANClRlY2hu +b2xvZ3kgQ28uLEx0ZDxCUj48QlI+5Zyw5Z2A77ya5YyX5Lqs5biCIOa1t+a3gOWMuiDntKvnq7np +maLot68gNjnlj7cg5Lit5Zu95YW15Zmo5aSn5Y6mIDE5MDjlrqQgPC9ESVY+PC9CT0RZPjwvSFRN +TD4NCg== + +------=_NextPart_001_0004_01CBD4D6.8B23A510-- + +------=_NextPart_000_0003_01CBD4D6.8B23A510 +Content-Type: image/jpeg; + name="mail_logo.jpg" +Content-Transfer-Encoding: base64 +Content-ID: <34C08589F35E44ECA6840CB9631D27A9@PC200911251200> + +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 + +------=_NextPart_000_0003_01CBD4D6.8B23A510-- + diff --git a/lib_acl_cpp/samples/mime/test3.eml b/lib_acl_cpp/samples/mime/test3.eml new file mode 100644 index 000000000..00b771a5e --- /dev/null +++ b/lib_acl_cpp/samples/mime/test3.eml @@ -0,0 +1,598 @@ +X-Uidl: 1285046919.25907_3.localhost&&mail.51iker.com +Return-Path: +Delivered-To: zhengshuxin@51iker.com +Received: from AiXing (unknown [123.122.109.242]) + by 51iker.com (zebra mail for UNIX) with ESMTP id C88002744FA + for ; Tue, 21 Sep 2010 13:28:34 +0800 (CST) +Date: Tue, 21 Sep 2010 13:26:52 +0800 +From: "=?gb2312?B?wu3KwMP0?=" +To: "=?gb2312?B?1qPK99DC?=" , + "=?gb2312?B?wu3KwMP0?=" , + "wangwenquan" , + "xuganghui" +Cc: "zhengshuxin" +Subject: =?gb2312?B?sr/Dxbmk1/fX3L3h?= +Message-ID: <201009211326464019855@51iker.com> +Organization: =?gb2312?B?sKy/y8j8wNY=?= +X-mailer: Foxmail 6, 15, 201, 23 [cn] +Mime-Version: 1.0 +Content-Type: multipart/mixed; + boundary="=====001_Dragon871617701054_=====" + +This is a multi-part message in MIME format. + +--=====001_Dragon871617701054_===== +Content-Type: multipart/alternative; + boundary="=====003_Dragon871617701054_=====" + + +--=====003_Dragon871617701054_===== +Content-Type: text/plain; + charset="gb2312" +Content-Transfer-Encoding: base64 + +DQoNCjIwMTAtMDktMjEgDQoNCg0KDQrC7crAw/QgDQo= + +--=====003_Dragon871617701054_===== +Content-Type: text/html; + charset="gb2312" +Content-Transfer-Encoding: base64 + +PCFET0NUWVBFIEhUTUwgUFVCTElDICItLy9XM0MvL0RURCBIVE1MIDQuMCBUcmFuc2l0aW9uYWwv +L0VOIj4NCjxIVE1MPjxIRUFEPg0KPE1FVEEgY29udGVudD0idGV4dC9odG1sOyBjaGFyc2V0PWdi +MjMxMiIgaHR0cC1lcXVpdj1Db250ZW50LVR5cGU+DQo8TUVUQSBuYW1lPUdFTkVSQVRPUiBjb250 +ZW50PSJNU0hUTUwgOC4wMC43NjAwLjE2NjI1Ij48TElOSyByZWw9c3R5bGVzaGVldCANCmhyZWY9 +IkJMT0NLUVVPVEV7bWFyZ2luLVRvcDogMHB4OyBtYXJnaW4tQm90dG9tOiAwcHg7IG1hcmdpbi1M +ZWZ0OiAyZW19Ij48L0hFQUQ+DQo8Qk9EWSBzdHlsZT0iTUFSR0lOOiAxMHB4OyBGT05ULUZBTUlM +WTogdmVyZGFuYTsgRk9OVC1TSVpFOiAxMHB0Ij4NCjxESVY+PEZPTlQgc2l6ZT0yIGZhY2U9VmVy +ZGFuYT48L0ZPTlQ+Jm5ic3A7PC9ESVY+DQo8RElWPjxGT05UIHNpemU9MiBmYWNlPVZlcmRhbmE+ +PC9GT05UPiZuYnNwOzwvRElWPg0KPERJViBhbGlnbj1sZWZ0PjxGT05UIGNvbG9yPSNjMGMwYzAg +c2l6ZT0yIGZhY2U9VmVyZGFuYT4yMDEwLTA5LTIxIA0KPC9GT05UPjwvRElWPjxGT05UIHNpemU9 +MiBmYWNlPVZlcmRhbmE+DQo8SFIgc3R5bGU9IldJRFRIOiAxMjJweDsgSEVJR0hUOiAycHgiIGFs +aWduPWxlZnQgU0laRT0yPg0KDQo8RElWPjxGT05UIGNvbG9yPSNjMGMwYzAgc2l6ZT0yIGZhY2U9 +VmVyZGFuYT48U1BBTj7C7crAw/Q8L1NQQU4+IA0KPC9GT05UPjwvRElWPjwvRk9OVD48L0JPRFk+ +PC9IVE1MPg0K + +--=====003_Dragon871617701054_=====-- +--=====001_Dragon871617701054_===== +Content-Type: application/octet-stream; + name="=?gb2312?B?sr/Dxbmk1/exqLjmMjAxMMTqMDnUwjIxyNUuZG9jeA==?=" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; + filename="=?gb2312?B?sr/Dxbmk1/exqLjmMjAxMMTqMDnUwjIxyNUuZG9jeA==?=" + +UEsDBBQABgAIAAAAIQDPt+102gEAAOkIAAATAAgCW0NvbnRlbnRfVHlwZXNdLnhtbCCiBAIooAAC +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC0 +lk9r20AQxe+FfAex1yKtk0MpxXIOSXtsAnWh1/XuyF6yf8TuOLa/fWelWC22kEKELgYh5jdP897s +enl/tCZ7hRC1dyW7LRYsAye90m5bst/rH/lXlkUUTgnjHZTsBJHdr24+LdenGmJG1S6WbIdYf+M8 +yh1YEQtfg6M3lQ9WID2GLa+FfBFb4HeLxRcuvUNwmGNisNXyiQQErSB7FgF/Ckt9uNxH9PaPNVwj +2Ofg63hXEJRlD211ElAyUddGS4Ekn786ddE691WlJSgv95YaFh008SCghvg5MXm/hoMPilfeo/MI +cXL3hKuDlxAjjdeaokMPieg0/xvE7WQpHfR6EI9Qib3B7PuRPGpjcbDVxdi1TWYe8/SGhtdTE8DE +i6IRr94iUlBl42fc6bqzp6fDcBjGbO0yMYwZz9SVqx3ZCu2GnG3i5fZ2A4HyMNnTKyEdelRExJOZ +I+Atd7Q9ODXThp3JQxLIr+Z44ZTPySZA2hoFKqdFf+8JEwGRAjDDAXMmD31+k8J0EkGYfq5cZbAF +j/ZHujiAN7/TRTSY0ZYVXSNrsTEw2fOej35Dj4o4wObXbO7/Bx8VsgOhZglACx7q3+2f9OEDZpyv +jVTds3W8+aOy+gsAAP//AwBQSwMEFAAGAAgAAAAhAB6RGrfzAAAATgIAAAsACAJfcmVscy8ucmVs +cyCiBAIooAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAACMkttKA0EMhu8F32HIfTfbCiLS2d5IoXci6wOEmewBdw7MpNq+vaMgulDbXub058tP +1puDm9Q7pzwGr2FZ1aDYm2BH32t4bbeLB1BZyFuagmcNR86waW5v1i88kZShPIwxq6Lis4ZBJD4i +ZjOwo1yFyL5UupAcSQlTj5HMG/WMq7q+x/RXA5qZptpZDWln70C1x1g2X9YOXTcafgpm79jLiRXI +B2Fv2S5iKmxJxnKNain1LBpsMM8lnZFirAo24Gmi1fVE/1+LjoUsCaEJic/zfHWcA1peD3TZonnH +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 +Bps1BSSNsK0yPYPb6wUXgHzgpuWjNZKBsXCoVk9l6/ctD9wH6+Q1SI1iQ8V6bRh81TQ77rJNjrfb +usZpkVzwMUl3OK+L9NQkNKPn8zegqDbxjGcwhDDtCfFikJr7tZ2kicPOOs1DRNcT23VKyMaKWUsT +yDOlORFz1Os3PUK15PndfpGdf8Ql2uzUfy13dR+V7R2fhk8gVUn+qBZ+eEX1AwAA//8DAFBLAwQU +AAYACAAAACEAUp+KsO0AAABKAQAAGAAoAGN1c3RvbVhtbC9pdGVtUHJvcHMxLnhtbCCiJAAooCAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABkkE9rwzAMxe+DfYege+L8aZetJClps0Bv +ZWywq3Hk1BBbwXbGYOy7z2G9dDuJJ6H3e1K1/9RT9IHWKTI1ZEkKERpBgzJjDW+vffwIkfPcDHwi +gzUYgn1zf1cNbjdwz50niyePOgoNFeqpq+Fru2379Ck7xMWxbONN9lzEh01Zxn3ed22bF8dQviEK +aBNsXA0X7+cdY05cUHOX0IwmDCVZzX2QdmQkpRLYkVg0Gs/yNH1gYgl4/a4naNY8v9svKN2tXKMt +Vv2jaCUsOZI+EaSvgKsxhY+c+YhnS7MD1lTsj/+qb+5vfgAAAP//AwBQSwMEFAAGAAgAAAAhAKnI +XKqMAAAA2gAAABMAKABjdXN0b21YbWwvaXRlbTIueG1sIKIkACigIAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAALJJsgrOLy1KTi1WCE7NSU0uSU0JLqnMSbVVinEMcNSLCPZRUgAL+CXm +AgWBYkoKFbk5ecVWSbZKGSUlBVb6+sXJGam5icV6+QWpeUC5tPyi3MQSILcoXT8/LS0zOdUlP7k0 +NzWvRN/IwMBMPykzKSczP70osSCjEmoYVYyys9GHe8aOlwsAAAD//wMAUEsDBBQABgAIAAAAIQBc +liciwwAAACgBAAAeAAgBY3VzdG9tWG1sL19yZWxzL2l0ZW0yLnhtbC5yZWxzIKIEASigAAEAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +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 + +--=====001_Dragon871617701054_=====-- + diff --git a/lib_acl_cpp/samples/mime/test4.eml b/lib_acl_cpp/samples/mime/test4.eml new file mode 100644 index 000000000..eaaf6769b --- /dev/null +++ b/lib_acl_cpp/samples/mime/test4.eml @@ -0,0 +1,58 @@ +X-Uidl: 1283351286.31845_3.localhost&&mail.51iker.com +Return-Path: +Delivered-To: zhengshuxin@51iker.com +Received: from zsx-a26d28113ab (unknown [61.50.134.240]) + by 51iker.com (zebra mail for UNIX) with ESMTP id 2C06327464F; + Wed, 1 Sep 2010 22:28:06 +0800 (CST) +Date: Wed, 1 Sep 2010 22:28:11 +0800 +From: "zhengshuxin" +To: "guozhaohui" +Cc: "zhengshuxin" +Subject: test +Message-ID: <201009012228098281227@51iker.com> +X-mailer: Foxmail 6, 15, 201, 22 [cn] +Mime-Version: 1.0 +Content-Type: multipart/alternative; + boundary="=====003_Dragon563032502010_=====" + + +This is a multi-part message in MIME format. + +--=====003_Dragon563032502010_===== +Content-Type: text/plain; + charset="us-ascii" +Content-Transfer-Encoding: 7bit + + + +2010-09-01 + + + +zhengshuxin + +--=====003_Dragon563032502010_===== +Content-Type: text/html; + charset="us-ascii" +Content-Transfer-Encoding: 7bit + + + + + + +
 
+
 
+
2010-09-01 +
+
+ +
zhengshuxin +
+ +--=====003_Dragon563032502010_=====-- + + + diff --git a/lib_acl_cpp/samples/mime/test5.eml b/lib_acl_cpp/samples/mime/test5.eml new file mode 100644 index 000000000..50a65162f --- /dev/null +++ b/lib_acl_cpp/samples/mime/test5.eml @@ -0,0 +1,8016 @@ +X-Uidl: 1283154800.28682_3.localhost&&mail.51iker.com +Return-Path: +Delivered-To: zhengshuxin@51iker.com +Received: from iker-f954f96714 (unknown [123.122.106.93]) + by 51iker.com (zebra mail for UNIX) with ESMTP id 64485274649 + for ; Mon, 30 Aug 2010 15:53:01 +0800 (CST) +Date: Mon, 30 Aug 2010 15:52:51 +0800 +From: "zhengshuxin" +To: "zhengshuxin" +References: <201008231000405866460@51iker.com>, + <201008301516258068718@51iker.com> +Subject: =?gb2312?B?Rnc6IL+0wcu/tM341b7T0Ly4uPbOysziLMfrv7S4vbz+?= +Message-ID: <201008301552500785144@51iker.com> +X-mailer: Foxmail 6, 15, 201, 23 [cn] +Mime-Version: 1.0 +Content-Type: multipart/mixed; + boundary="=====001_Dragon274075040732_=====" + +This is a multi-part message in MIME format. + +--=====001_Dragon274075040732_===== +Content-Type: multipart/alternative; + boundary="=====003_Dragon274075040732_=====" + + +--=====003_Dragon274075040732_===== +Content-Type: text/plain; + charset="gb2312" +Content-Transfer-Encoding: base64 + +DQoNCjIwMTAtMDgtMzANCg0KDQoNCnpoZW5nc2h1eGluDQoNCg0KDQq3orz+yMujuiB3YW5nd2Vu +aHVhDQq3osvNyrG85KO6IDIwMTAtMDgtMzAgMTU6MTY6NTINCsrVvP7Iy6O6IHpoZW5nc2h1eGlu +DQqzrcvNo7ogDQrW98zio7ogRnc6IL+0wcu/tM341b7T0Ly4uPbOysziLMfrv7S4vbz+DQoNCg0K +DQoyMDEwLTA4LTMwDQoNCg0KDQp3YW5nd2VuaHVhDQoNCg0KDQq3orz+yMujuiB3YW5nd2VuaHVh +DQq3osvNyrG85KO6IDIwMTAtMDgtMjMgMTA6MDA6NDANCsrVvP7Iy6O6IG1hc2hpbWluDQqzrcvN +o7ogDQrW98zio7ogv7TBy7+0zfjVvtPQvLi49s7KzOIsx+u/tLi9vP4NCg0KDQoNCjIwMTAtMDgt +MjMgDQoNCg0KDQp3YW5nd2VuaHVhIA0K + +--=====003_Dragon274075040732_===== +Content-Type: text/html; + charset="gb2312" +Content-Transfer-Encoding: base64 + +PCFET0NUWVBFIEhUTUwgUFVCTElDICItLy9XM0MvL0RURCBIVE1MIDQuMCBUcmFuc2l0aW9uYWwv +L0VOIj4NCjxIVE1MPjxIRUFEPg0KPE1FVEEgaHR0cC1lcXVpdj1Db250ZW50LVR5cGUgY29udGVu +dD0idGV4dC9odG1sOyBjaGFyc2V0PUdCMjMxMiI+DQo8TUVUQSBjb250ZW50PSJNU0hUTUwgNi4w +MC41NzMwLjEzIiBuYW1lPUdFTkVSQVRPUj48TElOSyANCmhyZWY9IkJMT0NLUVVPVEV7bWFyZ2lu +LVRvcDogMHB4OyBtYXJnaW4tQm90dG9tOiAwcHg7IG1hcmdpbi1MZWZ0OiAyZW19IiANCnJlbD1z +dHlsZXNoZWV0Pg0KPE1FVEEgY29udGVudD0iTVNIVE1MIDYuMDAuMjkwMC4yMTgwIiBuYW1lPUdF +TkVSQVRPUj4NCjxTVFlMRT5AZm9udC1mYWNlIHsNCglmb250LWZhbWlseTogy87M5TsNCn0NCkBm +b250LWZhY2Ugew0KCWZvbnQtZmFtaWx5OiBWZXJkYW5hOw0KfQ0KQGZvbnQtZmFjZSB7DQoJZm9u +dC1mYW1pbHk6IEDLzszlOw0KfQ0KQHBhZ2UgU2VjdGlvbjEge3NpemU6IDU5NS4zcHQgODQxLjlw +dDsgbWFyZ2luOiA3Mi4wcHQgOTAuMHB0IDcyLjBwdCA5MC4wcHQ7IGxheW91dC1ncmlkOiAxNS42 +cHQ7IH0NClAuTXNvTm9ybWFsIHsNCglURVhULUpVU1RJRlk6IGludGVyLWlkZW9ncmFwaDsgRk9O +VC1TSVpFOiAxMC41cHQ7IE1BUkdJTjogMGNtIDBjbSAwcHQ7IEZPTlQtRkFNSUxZOiAiVGltZXMg +TmV3IFJvbWFuIjsgVEVYVC1BTElHTjoganVzdGlmeQ0KfQ0KTEkuTXNvTm9ybWFsIHsNCglURVhU +LUpVU1RJRlk6IGludGVyLWlkZW9ncmFwaDsgRk9OVC1TSVpFOiAxMC41cHQ7IE1BUkdJTjogMGNt +IDBjbSAwcHQ7IEZPTlQtRkFNSUxZOiAiVGltZXMgTmV3IFJvbWFuIjsgVEVYVC1BTElHTjoganVz +dGlmeQ0KfQ0KRElWLk1zb05vcm1hbCB7DQoJVEVYVC1KVVNUSUZZOiBpbnRlci1pZGVvZ3JhcGg7 +IEZPTlQtU0laRTogMTAuNXB0OyBNQVJHSU46IDBjbSAwY20gMHB0OyBGT05ULUZBTUlMWTogIlRp +bWVzIE5ldyBSb21hbiI7IFRFWFQtQUxJR046IGp1c3RpZnkNCn0NCkE6bGluayB7DQoJQ09MT1I6 +IGJsdWU7IFRFWFQtREVDT1JBVElPTjogdW5kZXJsaW5lDQp9DQpTUEFOLk1zb0h5cGVybGluayB7 +DQoJQ09MT1I6IGJsdWU7IFRFWFQtREVDT1JBVElPTjogdW5kZXJsaW5lDQp9DQpBOnZpc2l0ZWQg +ew0KCUNPTE9SOiBwdXJwbGU7IFRFWFQtREVDT1JBVElPTjogdW5kZXJsaW5lDQp9DQpTUEFOLk1z +b0h5cGVybGlua0ZvbGxvd2VkIHsNCglDT0xPUjogcHVycGxlOyBURVhULURFQ09SQVRJT046IHVu +ZGVybGluZQ0KfQ0KU1BBTi5FbWFpbFN0eWxlMTcgew0KCUZPTlQtV0VJR0hUOiBub3JtYWw7IENP +TE9SOiB3aW5kb3d0ZXh0OyBGT05ULVNUWUxFOiBub3JtYWw7IEZPTlQtRkFNSUxZOiBWZXJkYW5h +OyBURVhULURFQ09SQVRJT046IG5vbmU7IG1zby1zdHlsZS10eXBlOiBwZXJzb25hbC1jb21wb3Nl +DQp9DQpESVYuU2VjdGlvbjEgew0KCXBhZ2U6IFNlY3Rpb24xDQp9DQpVTktOT1dOIHsNCglGT05U +LVNJWkU6IDEwcHQNCn0NCkJMT0NLUVVPVEUgew0KCU1BUkdJTi1UT1A6IDBweDsgTUFSR0lOLUJP +VFRPTTogMHB4OyBNQVJHSU4tTEVGVDogMmVtDQp9DQpPTCB7DQoJTUFSR0lOLVRPUDogMHB4OyBN +QVJHSU4tQk9UVE9NOiAwcHgNCn0NClVMIHsNCglNQVJHSU4tVE9QOiAwcHg7IE1BUkdJTi1CT1RU +T006IDBweA0KfQ0KPC9TVFlMRT4NCg0KPE1FVEEgY29udGVudD0iTVNIVE1MIDYuMDAuMjkwMC4y +MTgwIiBuYW1lPUdFTkVSQVRPUj4NCjxTVFlMRT5AZm9udC1mYWNlIHsNCglmb250LWZhbWlseTog +y87M5TsNCn0NCkBmb250LWZhY2Ugew0KCWZvbnQtZmFtaWx5OiBWZXJkYW5hOw0KfQ0KQGZvbnQt +ZmFjZSB7DQoJZm9udC1mYW1pbHk6IEDLzszlOw0KfQ0KQHBhZ2UgU2VjdGlvbjEge3NpemU6IDU5 +NS4zcHQgODQxLjlwdDsgbWFyZ2luOiA3Mi4wcHQgOTAuMHB0IDcyLjBwdCA5MC4wcHQ7IGxheW91 +dC1ncmlkOiAxNS42cHQ7IH0NClAuTXNvTm9ybWFsIHsNCglURVhULUpVU1RJRlk6IGludGVyLWlk +ZW9ncmFwaDsgRk9OVC1TSVpFOiAxMC41cHQ7IE1BUkdJTjogMGNtIDBjbSAwcHQ7IEZPTlQtRkFN +SUxZOiAiVGltZXMgTmV3IFJvbWFuIjsgVEVYVC1BTElHTjoganVzdGlmeQ0KfQ0KTEkuTXNvTm9y +bWFsIHsNCglURVhULUpVU1RJRlk6IGludGVyLWlkZW9ncmFwaDsgRk9OVC1TSVpFOiAxMC41cHQ7 +IE1BUkdJTjogMGNtIDBjbSAwcHQ7IEZPTlQtRkFNSUxZOiAiVGltZXMgTmV3IFJvbWFuIjsgVEVY +VC1BTElHTjoganVzdGlmeQ0KfQ0KRElWLk1zb05vcm1hbCB7DQoJVEVYVC1KVVNUSUZZOiBpbnRl +ci1pZGVvZ3JhcGg7IEZPTlQtU0laRTogMTAuNXB0OyBNQVJHSU46IDBjbSAwY20gMHB0OyBGT05U +LUZBTUlMWTogIlRpbWVzIE5ldyBSb21hbiI7IFRFWFQtQUxJR046IGp1c3RpZnkNCn0NCkE6bGlu +ayB7DQoJQ09MT1I6IGJsdWU7IFRFWFQtREVDT1JBVElPTjogdW5kZXJsaW5lDQp9DQpTUEFOLk1z +b0h5cGVybGluayB7DQoJQ09MT1I6IGJsdWU7IFRFWFQtREVDT1JBVElPTjogdW5kZXJsaW5lDQp9 +DQpBOnZpc2l0ZWQgew0KCUNPTE9SOiBwdXJwbGU7IFRFWFQtREVDT1JBVElPTjogdW5kZXJsaW5l +DQp9DQpTUEFOLk1zb0h5cGVybGlua0ZvbGxvd2VkIHsNCglDT0xPUjogcHVycGxlOyBURVhULURF +Q09SQVRJT046IHVuZGVybGluZQ0KfQ0KU1BBTi5FbWFpbFN0eWxlMTcgew0KCUZPTlQtV0VJR0hU +OiBub3JtYWw7IENPTE9SOiB3aW5kb3d0ZXh0OyBGT05ULVNUWUxFOiBub3JtYWw7IEZPTlQtRkFN +SUxZOiBWZXJkYW5hOyBURVhULURFQ09SQVRJT046IG5vbmU7IG1zby1zdHlsZS10eXBlOiBwZXJz +b25hbC1jb21wb3NlDQp9DQpESVYuU2VjdGlvbjEgew0KCXBhZ2U6IFNlY3Rpb24xDQp9DQpVTktO +T1dOIHsNCglGT05ULVNJWkU6IDEwcHQNCn0NCjwvU1RZTEU+DQo8L0hFQUQ+DQo8Qk9EWSBzdHls +ZT0iRk9OVC1TSVpFOiAxMHB0OyBNQVJHSU46IDEwcHg7IEZPTlQtRkFNSUxZOiB2ZXJkYW5hIj48 +Rk9OVCANCmZhY2U9VmVyZGFuYSBjb2xvcj0jMDAwMDAwIHNpemU9Mj4NCjxESVY+Jm5ic3A7PC9E +SVY+DQo8RElWPiZuYnNwOzwvRElWPg0KPERJVj48Rk9OVCBmYWNlPVZlcmRhbmEgY29sb3I9I2Mw +YzBjMCBzaXplPTI+MjAxMC0wOC0zMDwvRk9OVD48L0RJVj4NCjxESVYgYWxpZ249bGVmdD4NCjxI +UiBzdHlsZT0iV0lEVEg6IDEwMHB4IiBjb2xvcj0jYjVjNGRmIFNJWkU9MT4NCjwvRElWPg0KPERJ +Vj48Rk9OVCBmYWNlPVZlcmRhbmEgY29sb3I9I2MwYzBjMCANCnNpemU9Mj48U1BBTj56aGVuZ3No +dXhpbjwvU1BBTj48L0ZPTlQ+PC9ESVY+DQo8SFIgY29sb3I9I2I1YzRkZiBTSVpFPTE+DQoNCjxE +SVY+PEZPTlQgZmFjZT1WZXJkYW5hIHNpemU9Mj48U1RST05HPreivP7Iy6O6PC9TVFJPTkc+IHdh +bmd3ZW5odWE8L0ZPTlQ+PC9ESVY+DQo8RElWPjxGT05UIGZhY2U9VmVyZGFuYSBzaXplPTI+PFNU +Uk9ORz63osvNyrG85KO6PC9TVFJPTkc+IA0KMjAxMC0wOC0zMCZuYnNwOzE1OjE2OjUyPC9GT05U +PjwvRElWPg0KPERJVj48Rk9OVCBmYWNlPVZlcmRhbmEgc2l6ZT0yPjxTVFJPTkc+ytW8/sjLo7o8 +L1NUUk9ORz4gemhlbmdzaHV4aW48L0ZPTlQ+PC9ESVY+DQo8RElWPjxGT05UIGZhY2U9VmVyZGFu +YSBzaXplPTI+PFNUUk9ORz6zrcvNo7o8L1NUUk9ORz4gPC9GT05UPjwvRElWPg0KPERJVj48Rk9O +VCBmYWNlPVZlcmRhbmEgc2l6ZT0yPjxTVFJPTkc+1vfM4qO6PC9TVFJPTkc+IEZ3OiANCr+0wcu/ +tM341b7T0Ly4uPbOysziLMfrv7S4vbz+PC9GT05UPjwvRElWPg0KPERJVj4mbmJzcDs8L0RJVj4N +CjxESVY+PEZPTlQgZmFjZT1WZXJkYW5hIHNpemU9Mj48Rk9OVCBmYWNlPVZlcmRhbmEgY29sb3I9 +IzAwMDAwMCBzaXplPTI+DQo8RElWPiZuYnNwOzwvRElWPg0KPERJVj4mbmJzcDs8L0RJVj4NCjxE +SVY+PEZPTlQgZmFjZT1WZXJkYW5hIGNvbG9yPSNjMGMwYzAgc2l6ZT0yPjIwMTAtMDgtMzA8L0ZP +TlQ+PC9ESVY+DQo8RElWIGFsaWduPWxlZnQ+DQo8SFIgc3R5bGU9IldJRFRIOiAxMDBweCIgY29s +b3I9I2I1YzRkZiBTSVpFPTE+DQo8L0RJVj4NCjxESVY+PEZPTlQgZmFjZT1WZXJkYW5hIGNvbG9y +PSNjMGMwYzAgDQpzaXplPTI+PFNQQU4+d2FuZ3dlbmh1YTwvU1BBTj48L0ZPTlQ+PC9ESVY+DQo8 +SFIgY29sb3I9I2I1YzRkZiBTSVpFPTE+DQoNCjxESVY+PEZPTlQgZmFjZT1WZXJkYW5hIHNpemU9 +Mj48U1RST05HPreivP7Iy6O6PC9TVFJPTkc+IHdhbmd3ZW5odWE8L0ZPTlQ+PC9ESVY+DQo8RElW +PjxGT05UIGZhY2U9VmVyZGFuYSBzaXplPTI+PFNUUk9ORz63osvNyrG85KO6PC9TVFJPTkc+IA0K +MjAxMC0wOC0yMyZuYnNwOzEwOjAwOjQwPC9GT05UPjwvRElWPg0KPERJVj48Rk9OVCBmYWNlPVZl +cmRhbmEgc2l6ZT0yPjxTVFJPTkc+ytW8/sjLo7o8L1NUUk9ORz4gbWFzaGltaW48L0ZPTlQ+PC9E +SVY+DQo8RElWPjxGT05UIGZhY2U9VmVyZGFuYSBzaXplPTI+PFNUUk9ORz6zrcvNo7o8L1NUUk9O +Rz4gPC9GT05UPjwvRElWPg0KPERJVj48Rk9OVCBmYWNlPVZlcmRhbmEgc2l6ZT0yPjxTVFJPTkc+ +1vfM4qO6PC9TVFJPTkc+IL+0wcu/tM341b7T0Ly4uPbOysziLMfrv7S4vbz+PC9GT05UPjwvRElW +Pg0KPERJVj4mbmJzcDs8L0RJVj4NCjxESVY+PEZPTlQgZmFjZT1WZXJkYW5hIHNpemU9Mj4NCjxE +SVY+PEZPTlQgZmFjZT1WZXJkYW5hIHNpemU9Mj48L0ZPTlQ+Jm5ic3A7PC9ESVY+DQo8RElWPjxG +T05UIGZhY2U9VmVyZGFuYSBzaXplPTI+PC9GT05UPiZuYnNwOzwvRElWPg0KPERJViBhbGlnbj1s +ZWZ0PjxGT05UIGZhY2U9VmVyZGFuYSBjb2xvcj0jYzBjMGMwIHNpemU9Mj4yMDEwLTA4LTIzIA0K +PC9GT05UPjwvRElWPjxGT05UIGZhY2U9VmVyZGFuYSBzaXplPTI+DQo8SFIgc3R5bGU9IldJRFRI +OiAxMjJweDsgSEVJR0hUOiAycHgiIGFsaWduPWxlZnQgU0laRT0yPg0KDQo8RElWPjxGT05UIGZh +Y2U9VmVyZGFuYSBjb2xvcj0jYzBjMGMwIHNpemU9Mj48U1BBTj53YW5nd2VuaHVhPC9TUEFOPiAN +CjwvRk9OVD48L0RJVj48L0ZPTlQ+PC9GT05UPjwvRElWPjwvRk9OVD48L0ZPTlQ+PC9ESVY+PC9G +T05UPjwvQk9EWT48L0hUTUw+DQo= + +--=====003_Dragon274075040732_=====-- +--=====001_Dragon274075040732_===== +Content-Type: application/octet-stream; + name="mail-site.doc" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; + filename="mail-site.doc" + +0M8R4KGxGuEAAAAAAAAAAAAAAAAAAAAAPgADAP7/CQAGAAAAAAAAAAAAAAAHAAAAZwMAAAAAAAAA +EAAAaQMAAAEAAAD+////AAAAAGADAABhAwAAYgMAAGMDAABkAwAAZQMAAGYDAAD///////////// +//////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////s +pcEAJ2AJBAAA+FK/AAAAAAAAEAAAAAAABgAAhhYAAA4AYmpiaiSaJJoAAAAAAAAAAAAAAAAAAAAA +AAAECBYAMhoAAEbwAABG8AAAQQIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//w8AAAAA +AAAAAAD//w8AAAAAAAAAAAD//w8AAAAAAAAAAAAAAAAAAAAAAKQAAAAAAMgDAAAAAAAAyAMAAMgD +AAAAAAAAyAMAAAAAAADIAwAAAAAAAMgDAAAAAAAAyAMAABQAAAAAAAAAAAAAANwDAAAAAAAAxAsA +AAAAAADECwAAAAAAAMQLAAAAAAAAxAsAABwAAADgCwAAFAAAANwDAAAAAAAA5Q0AAEoBAAAADAAA +KAAAACgMAAAAAAAAKAwAAAAAAAAoDAAAAAAAACgMAAAAAAAAKAwAAAAAAAAoDAAAAAAAACgMAAAA +AAAAWA0AAAIAAABaDQAAAAAAAFoNAAAAAAAAWg0AAAAAAABaDQAAAAAAAFoNAAAAAAAAWg0AACQA +AAAvDwAAaAIAAJcRAAA+AAAAfg0AACEAAAAAAAAAAAAAAAAAAAAAAAAAyAMAAAAAAAAoDAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAoDAAAAAAAACgMAAAAAAAAKAwAAAAAAAAoDAAAAAAAAH4NAAAAAAAA +AAAAAAAAAADIAwAAAAAAAMgDAAAAAAAAKAwAAAAAAAAAAAAAAAAAACgMAAAAAAAAnw0AABYAAADg +DAAAAAAAAOAMAAAAAAAA4AwAAAAAAAAoDAAAUgAAAMgDAAAAAAAAKAwAAAAAAADIAwAAAAAAACgM +AAAAAAAAWA0AAAAAAAAAAAAAAAAAAOAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAKAwAAAAAAABYDQAAAAAAAAAAAAAAAAAA4AwAAAAAAAAAAAAA +AAAAAOAMAAAAAAAAyAMAAAAAAADIAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4AwAAAAAAAAoDAAAAAAAAPQLAAAMAAAAEKplHuBB +ywEAAAAAAAAAAMQLAAAAAAAAegwAADoAAADgDAAAAAAAAAAAAAAAAAAAWA0AAAAAAAC1DQAAMAAA +AOUNAAAAAAAA4AwAAAAAAADVEQAAAAAAALQMAAAiAAAAHRMAAAAAAADgDAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADg +DAAAFAAAANURAAAkAQAA+RIAACQAAADIAwAAAAAAAPQMAABkAAAAKAwAAAAAAAAoDAAAAAAAAOAM +AAAAAAAAKAwAAAAAAAAoDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAwA +AAAAAAAoDAAAAAAAACgMAAAAAAAAfg0AAAAAAAB+DQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAA1gwAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgMAAAA +AAAAKAwAAAAAAAAoDAAAAAAAAOUNAAAAAAAAKAwAAAAAAAAoDAAAAAAAACgMAAAAAAAAKAwAAAAA +AAAAAAAAAAAAANwDAAAAAAAA3AMAAAAAAADcAwAAZAQAAEAIAACEAwAA3AMAAAAAAADcAwAAAAAA +ANwDAAAAAAAAQAgAAAAAAADcAwAAAAAAANwDAAAAAAAA3AMAAAAAAADIAwAAAAAAAMgDAAAAAAAA +yAMAAAAAAADIAwAAAAAAAMgDAAAAAAAAyAMAAAAAAAD/////AAAAAAIADAEAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0AAQAN +AA0AAQANAA0ADQANAAEADQANAAEADQANAA0AAQANAA0ADQABAA0AAQANAA0ADQABAA0ADQDjTgZ0 +RlVhZ/ZOOgANAAkmIAAmewhU/Va2W/h2c1HVbItfATDVbMSJxImaW3dRB1n6Vyxnzk4aTkSNPGiE +dgFPGk4b/wsAADAgAPeL5ovGfoZO44nlTgtOUX/ZeoltylOEdoVRuVsa/wsAADAgABMAIABIAFkA +UABFAFIATABJAE4ASwAgACIAaAB0AHQAcAA6AC8ALwB3AHcAdwAuAG0AaQBpAC4AZwBvAHYALgBj +AG4ALwBtAGkAaQAvAHoAYwBmAGcALgBoAHQAbQBsACIAIABcAHQAIAAiAF8AYgBsAGEAbgBrACIA +IAAUAC1OTlO6ThFscVGMVP1W4U9vYKdOGk7okD9lVnvVbMSJFQALAAAwIAATACAASABZAFAARQBS +AEwASQBOAEsAIAAiAGgAdAB0AHAAOgAvAC8AdwB3AHcALgBjAG4AbgBpAGMALgBuAGUAdAAuAGMA +bgAvAGkAbgBkAGUAeAAvADAARgAvAGkAbgBkAGUAeAAuAGgAdABtACIAIABcAHQAIAAiAF8AYgBs +AGEAbgBrACIAIAAUAC1O/VaSTlSAUX/cfuFPb2AtTsNfP2VWe9VsxIkVAA0ACSYgAHdRB1nOThpO +kk5UgFF/+ldAeJReKHUaTqFShHb6Vyxn/YCbUgz/BVPsYiWEAJUBMA1noVIBMIBiL2eEdvpXLGdh +Z/ZOjFQgfSiNAjALAAkmIACUXlNf5WIJZ/pWmluEdp5SbFEwV7lwDP8oVyxnMFflYgln1GuDj4xb +hFWEdgCVLlVRf9x+Dk4gblOQAjALAAkmIAB3UQln1GuDjzBOzFuEdpJOVIBRf9x+gGIvZ89+jJoO +Tm+CfVmEdqJbN2INZ6FS/YCbUgIwDQANADN194tBbQt6OgANADEAATBRfwpO0GOkTjN194toiFVT +AjAI//eL5ovGfmtYmVF9WUSNmWUM/+VOv08OTqhgVID7fAn/CwAyAAEwNmUwUqhghHbjTgZ0RlUz +dfeLDlQRYuxOBlwaTyhXMgA0AA9c9mWFUQ5OqGBUgPt8LAB2XtBjpE74dnNRhHZEjZllLgALADMA +ATD7ThFirpAgblOQz34GdDZlMFJEjZlljFQgTx93DlTbj2VRoVs4aLZyAWAuAAsANAABMDN194sF +gM9+oVsFlvtOEWKukONOBnRGVU9Trou+jxBipIvvUw5UDP/3iwZc404GdE9TrotTYnBTDP9+e1db +1nbgekSWCk4BTxpOhHYlhBpOZ2JncQ1ZcFP2TnZexFvZfhFi7E4CMAsANQABMAAAAAAABgAAAggA +AAQIAAAICAAACggAABIIAAAUCAAAGAgAABoIAAAgCAAAIggAACgIAAAqCAAALAgAAC4IAAAwCAAA +NAgAADYIAAA4CAAASAgAAEoIAABMCAAAfggAAKgIAAD68Ovh69frzevD67nrr6qlm6WWgm9bSQAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACMWaOFOXQBCKg9DShAAT0oEAFFKBABeSgIAYUoQAHBo +R0dHACcWaOFOXQAwShAAQioPQ0oQAE9KBABRSgQAXkoCAGFKEABwaEdHRwAkFWjdDTwAFmjdDTwA +Q0oQAEtIAABPSgIAUUoCAF5KAgBhShAAACcVaN0NPAAWaN0NPABDShAAS0gAAE9KAwBRSgMAXkoD +AGFKEABvKAEJFmjdDTwAbygBEgNqcg0GABZomGkfAFUIAW8oAQAJFmiYaR8AbygBCRZo9354AG8o +ARIDahWzBQAWaPd+eABVCAFvKAEAEgNq7VEFABZo9CebAFUIAW8oAQASA2qsuQMAFmj0J5sAVQgB +bygBABIDaqZ0AgAWaPQnmwBVCAFvKAEAEgNqgxICABZo9CebAFUIAW8oAQASA2oUagEAFmj0J5sA +VQgBbygBAAkWaPQnmwBvKAESA2oAAAAAFmj0J5sAVQgBbygBAAkWaPEq0wBvKAEAFwAGAAACCAAA +BggAAAgIAAAMCAAADggAABAIAAASCAAAFggAABgIAAAcCAAAHggAACAIAAAkCAAAJggAACgIAAAs +CAAAMAgAADIIAAA0CAAAOAgAADoIAABICAAA+gkAAMgKAADKCgAA1goAAGIWAABkFgAAZhYAAP0A +AAAAAAAAAAAAAAD9AAAAAAAAAAAAAAAA/QAAAAAAAAAAAAAAAP0AAAAAAAAAAAAAAAD9AAAAAAAA +AAAAAAAA/QAAAAAAAAAAAAAAAP0AAAAAAAAAAAAAAAD9AAAAAAAAAAAAAAAA/QAAAAAAAAAAAAAA +AP0AAAAAAAAAAAAAAAD9AAAAAAAAAAAAAAAA/QAAAAAAAAAAAAAAAP0AAAAAAAAAAAAAAAD9AAAA +AAAAAAAAAAAA/QAAAAAAAAAAAAAAAP0AAAAAAAAAAAAAAAD9AAAAAAAAAAAAAAAA/QAAAAAAAAAA +AAAAAP0AAAAAAAAAAAAAAAD9AAAAAAAAAAAAAAAA/QAAAAAAAAAAAAAAAP0AAAAAAAAAAAAAAAD9 +AAAAAAAAAAAAAAAA/QAAAAAAAAAAAAAAAP0AAAAAAAAAAAAAAAD9AAAAAAAAAAAAAAAA/QAAAAAA +AAAAAAAAAP0AAAAAAAAAAAAAAAD9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAdAAYAAIYWAAD+ +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIBAQGoCAAAqggAACQJ +AAAmCQAARgkAAEgJAABOCQAAUAkAANgJAADaCQAA9gkAAPgJAAD6CQAA/AkAAP4JAABICgAASgoA +AEwKAABOCgAAjgoAAJAKAADGCgAA59Pnw+ex59Pnw+fTnYxzX0w4TDhMAAAAJxVo3Q08ABZo3Q08 +AENKEABLSAAAT0oDAFFKAwBeSgMAYUoQAG8oASQVaN0NPAAWaN0NPABDShAAS0gAAE9KAgBRSgIA +XkoCAGFKEAAAJxVoXg7aABZoBmmjADUIgUNKEABLSAAAT0oCAFFKAgBeSgIAYUoQADAVaF4O2gAW +aOFOXQAwShAANQiBQioPQ0oQAE9KBABRSgQAXkoCAGFKEABwaEdHRwAAIRZo4U5dAENKEABLSAAA +T0oDAFFKAwBeSgMAYUoQAG8oAScVaN0NPAAWaOFOXQBDShAAS0gAAE9KAwBRSgMAXkoDAGFKEABv +KAEjFmjhTl0AQioPQ0oQAE9KBABRSgQAXkoCAGFKEABwaEdHRwAeFmjhTl0AMEoPAENKEABPSgQA +UUoEAF5KAgBhShAAACYWaOFOXQBCKg9DShAAT0oEAFFKBABeSgIAYUoQAG8oAXBoR0dHAAAvA2oA +AAAAFmjhTl0AQioPQ0oQAE9KBABRSgQAVQgBXkoCAGFKEABvKAFwaEdHRwAAFcYKAADKCgAA1goA +ANgKAADaCgAA6goAABQLAABYCwAAXgsAAGQLAACICwAAigsAAJwLAACiCwAA/AsAAAAWAAAGFgAA +YBYAAHAWAAByFgAAfhYAAIAWAACCFgAAhhYAAO7p1sa11qTWk9aC1pPWgJPW6Xt2e3FsAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkWaJhpHwBvKAEJFmitGCcAbygBCRZo +qWZuAG8oAQkWaEFc5ABvKAEDVQgBIRZoVS6CAENKEABLSAAAT0oCAFFKAgBeSgIAYUoQAG8oASEW +aJ5zWwBDShAAS0gAAE9KAgBRSgIAXkoCAGFKEABvKAEhFmjjBCIAQ0oQAEtIAABPSgIAUUoCAF5K +AgBhShAAbygBIRZovGFIAENKEABLSAAAT0oCAFFKAgBeSgIAYUoQAG8oAR4WaLxhSABDShAAS0gA +AE9KAgBRSgIAXkoCAGFKEAAAJBVo3Q08ABZo3Q08AENKEABLSAAAT0oCAFFKAgBeSgIAYUoQAAAJ +FmjdDTwAbygBIRZo3Q08AENKEABLSAAAT0oCAFFKAgBeSgIAYUoQAG8oAQAX+04RYq6QNmUwUjN1 +94sFgIR2fntyf09TrosM/89+oVs4aOBl74sOVAz/BlxPU66L1nbgesRb3lYATv1O2X75W7llDP92 +XgBfGpDjTgZ0EF73U4xUGpDld+NOBnRGVQIwDQANAA0AVID7fBFi7E4NAA0A0GOkTuFPb2B1mGKX +DQANAA0ADQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABmFgAAcBYAAHIWAACA +FgAAghYAAIQWAACGFgAA/QAAAAAAAAAAAAAAAP0AAAAAAAAAAAAAAAD9AAAAAAAAAAAAAAAA/QAA +AAAAAAAAAAAAAP0AAAAAAAAAAAAAAAD9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAABjAAMZA4ATJQAgAfsIIu +ILDGQSGwCAcisAgHI5CgBSSQoAUlsAAAF7BTAxiw4AMMkKkBAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +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 +AAAAAAAAAAAAAAAAAAAAAIYCEQASAAEAnAAPAAQAAAADAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE4AAEDx/wIATgAMBAAAAAAAAAAA +AgBja4dlAAALAAAAAyQDMSQAYSQDACQAQ0oVAEtIAgBQSgMAX0gBBGFKGABtSAkEbkgECHNICQR0 +SAQIAAAAAAAAAAAAAAAAAAAAAAAAJABBQPL/oQAkAAwFAAAAAAAAAAAGANiepIu1az2EV1tTTwAA +AABCAGlA8/+zAEIADAUAAAAAAAAAAAQAbmYakGiIPGgAABwAF/YDAAA01gYAAQoDbAA01gYAAQUD +AABh9gMAAAIACwAAACAAa0D0/8EAIAAABQAAAAAAAAAAAwDgZRdSaIgAAAIAAAAAAAAAKABVQKIA +8QAoAAwAAADdDTwAAAADAIWN/pSlYwAACQA+KgFwaAAA/wAAIgD+b6IAAQEiAAwAAADhTl0AAAAC +AGIAMQAAAAYANQiBXAiBAAAAAEECAAAIAAAaAAAHAP////8AAAAAAQAAAAMAAAAEAAAABgAAAAcA +AAAIAAAACQAAAAsAAAAMAAAADgAAAA8AAAAQAAAAEgAAABMAAAAUAAAAFgAAABgAAAAZAAAAGgAA +ABwAAAAdAAAAJAAAAP0AAABkAQAAZQEAAGsBAAAvAgAAMAIAADECAAA2AgAANwIAAD4CAAA/AgAA +QAIAAEMCAACYAAAAADAAAAAAAAAAgAAAAIAAAAAAAAAAAAAAmAAAAAAwAAAAAAAAAIAAAACAAAAA +AAAAAAAAAJgAAAAAMAAAAAAAAACAAAAAgAAAAAAAAAAAAACYAAAAADAAAAAAAAAAgAAAAIAAAAAA +AAAAAAAAmAAAAAAwAAAAAAAAAIAAAACAAAAAAAAAAAAAAJgAAAAAMAAAAAAAAACAAAAAgAAAAAAA +AAAAAACYAAAAADAAAAAAAAAAgAAAAIAAAAAAAAAAAAAAmAAAAAAwAAAAAAAAAIAAAACAAAAAAAAA +AAAAAJgAAAAAMAAAAAAAAACAAAAAgAAAAAAAAAAAAACYAAAAADAAAAAAAAAAgAAAAIAAAAAAAAAA +AAAAmAAAAAAwAAAAAAAAAIAAAACAAAAAAAAAAAAAAJgAAAAAMAAAAAAAAACAAAAAgAAAAAAAAAAA +AACYAAAAADAAAAAAAAAAgAAAAIAAAAAAAAAAAAAAmAAAAAAwAAAAAAAAAIAAAACAAAAAAAAAAAAA +AJgAAAAAMAAAAAAAAACAAAAAgAAAAAAAAAAAAACYAAAAADAAAAAAAAAAgAAAAIAAAAAAAAAAAAAA +mAAAAAAwAAAAAAAAAIAAAACAAAAAAAAAAAAAAJgAAAAAMAAAAAAAAACAAAAAgAAAAAAAAAAAAACY +AAAAADAAAAAAAAAAgAAAAIAAAAAAAAAAAAAAmAAAAAAwAAAAAAAAAIAAAACAAAAAAAAAAAAAAJgA +AAAAMAAAAAAAAACAAAAAgAAAAAAAAAAAAACYAAAAADAAAAAAAAAAgAAAAIAAAAAAAAAAAAAAmAAA +AAAwAAAAAAAAAIAAAACAAAAAAAAAAAAAAJgAAAAAMAAAAAAAAACAAAAAgAAAAAAAAAAAAACYAAAA +ADAAAAAAAAAAgAAAAIAAAAAAAAAAAAAAmAAAAAAwAAAAAAAAAIAAAACAAAAAAAAAAAAAAJgAAAAA +MAAAAAAAAACAAAAAgAAAAAAAAAAAAACYAAAAADAAAAAAAAAAgAAAAIAAAAAAAAAAAAAAmAAAAAAw +AAAAAAAAAIAAAACAAAAAAAAAAAAAAJgAAAAAMAAAAAAAAACAAAAAgAAAAAAAAAAAAACYAAAAADAA +AAAAAAAAgAAAAIAAAAAAAAAAAAAAmAAAAAAwAAAAAAAAAIAAAACAAAAAAAAAAAAAAJgAAAAAMAAA +AAAAAACAAAAAgAAAAAAAAAAAAACYAAAAADAAAAAAAAAAgAAAAIAAAAAAAAAAAAAAmAAAAAAwAAAA +AAAAAIAAAACAAAAAAAAAAAAAAAAAAAABAAAAAwAAAAQAAAAGAAAABwAAAAgAAAAJAAAACwAAAAwA +AAAOAAAADwAAABAAAAASAAAAEwAAABQAAAAWAAAAGAAAABkAAAAaAAAAHAAAAB0AAAAkAAAA/QAA +AGQBAABlAQAAawEAAC8CAABDAgAAqpEAMAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAB6qRADAAAAAA +AAAAAAEAAAAAAAAAAAAAAAAAAAeqkQAwAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAHqpEAMAAAAAAA +AAAAAQAAAAAAAAAAAAAAAAAAB6qRADAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAeqkQAwAAAAAAAA +AAABAAAAAAAAAAAAAAAAAAAHqpEAMAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAB6qRADAAAAAAAAAA +AAEAAAAAAAAAAAAAAAAAAAeqkQAwAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAHqpEAMAAAAAAAAAAA +AQAAAAAAAAAAAAAAAAAAB6qRADAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAeqkQAwAAAAAAAAAAAB +AAAAAAAAAAAAAAAAAAAHqpEAMAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAB6qRADAAAAAAAAAAAAEA +AAAAAAAAAAAAAAAAAAeqkQAwAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAHqpEAMAAAAAAAAAAAAQAA +AAAAAAAAAAAAAAAAB6rRADAAEAAAAAAAAAIAAAACAAAAAAAAAAAAAAeq0QAwABAAAAAAAAACAAAA +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 +QAAAAACgnMjNQcsBQAAAAAByiRXgQcsBAwAAAAEAAAADAAAAVgAAAAMAAADrAQAAAwAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP7/ +AAAGAQIAAAAAAAAAAAAAAAAAAAAAAAIAAAAC1c3VnC4bEJOXCAArLPmuRAAAAAXVzdWcLhsQk5cI +ACss+a7wAAAArAAAAAoAAAABAAAAWAAAAA8AAABgAAAABQAAAGwAAAAGAAAAdAAAABEAAAB8AAAA +FwAAAIQAAAALAAAAjAAAABAAAACUAAAAEwAAAJwAAAAWAAAApAAAAAIAAACoAwAAHgAAAAQAAAAA +AAAAAwAAAAQAAAADAAAAAQAAAAMAAABAAgAAAwAAAA8nCwALAAAAAAAAAAsAAAAAAAAACwAAAAAA +AAALAAAAAAAAAFQBAAADAAAAAAAAACAAAAABAAAAOAAAAAIAAABAAAAAAQAAAAIAAAAMAAAAX1BJ +RF9ITElOS1MAAgAAAKgDAABBAAAADAEAAAwAAAADAAAAZwAhAAMAAAADAAAAAwAAAAAAAAADAAAA +BQAAAB8AAAArAAAAaAB0AHQAcAA6AC8ALwB3AHcAdwAuAGMAbgBuAGkAYwAuAG4AZQB0AC4AYwBu +AC8AaQBuAGQAZQB4AC8AMABGAC8AaQBuAGQAZQB4AC4AaAB0AG0AAAAAAB8AAAABAAAAAAB3DgMA +AAB6ADUAAwAAAAAAAAADAAAAAAAAAAMAAAAFAAAAHwAAACQAAABoAHQAdABwADoALwAvAHcAdwB3 +AC4AbQBpAGkALgBnAG8AdgAuAGMAbgAvAG0AaQBpAC8AegBjAGYAZwAuAGgAdABtAGwAAAAfAAAA +AQAAAAAAdw4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAgAAAAMA +AAAEAAAABQAAAAYAAAAHAAAACAAAAAkAAAAKAAAACwAAAAwAAAANAAAA/v///w8AAAAQAAAAEQAA +ABIAAAATAAAAFAAAABUAAAAWAAAAFwAAABgAAAAZAAAAGgAAABsAAAAcAAAAHQAAAB4AAAAfAAAA +IAAAACEAAAAiAAAAIwAAACQAAAAlAAAAJgAAACcAAAAoAAAAKQAAACoAAAArAAAALAAAAC0AAAAu +AAAALwAAADAAAAAxAAAAMgAAADMAAAA0AAAANQAAADYAAAA3AAAAOAAAADkAAAA6AAAAOwAAADwA +AAA9AAAAPgAAAD8AAABAAAAAQQAAAEIAAABDAAAARAAAAEUAAABGAAAARwAAAEgAAABJAAAASgAA +AEsAAABMAAAATQAAAE4AAABPAAAAUAAAAFEAAABSAAAAUwAAAFQAAABVAAAAVgAAAFcAAABYAAAA +WQAAAFoAAABbAAAAXAAAAF0AAABeAAAAXwAAAGAAAABhAAAAYgAAAGMAAABkAAAAZQAAAGYAAABn +AAAAaAAAAGkAAABqAAAAawAAAGwAAABtAAAAbgAAAG8AAABwAAAAcQAAAHIAAABzAAAAdAAAAHUA +AAB2AAAAdwAAAHgAAAB5AAAAegAAAHsAAAB8AAAAfQAAAH4AAAB/AAAAgAAAAIEAAACCAAAAgwAA +AIQAAACFAAAAhgAAAIcAAACIAAAAiQAAAIoAAACLAAAAjAAAAI0AAACOAAAAjwAAAJAAAACRAAAA +kgAAAJMAAACUAAAAlQAAAJYAAACXAAAAmAAAAJkAAACaAAAAmwAAAJwAAACdAAAAngAAAJ8AAACg +AAAAoQAAAKIAAACjAAAApAAAAKUAAACmAAAApwAAAKgAAACpAAAAqgAAAKsAAACsAAAArQAAAK4A +AACvAAAAsAAAALEAAACyAAAAswAAALQAAAC1AAAAtgAAALcAAAC4AAAAuQAAALoAAAC7AAAAvAAA +AL0AAAC+AAAAvwAAAMAAAADBAAAAwgAAAMMAAADEAAAAxQAAAMYAAADHAAAAyAAAAMkAAADKAAAA +ywAAAMwAAADNAAAAzgAAAM8AAADQAAAA0QAAANIAAADTAAAA1AAAANUAAADWAAAA1wAAANgAAADZ +AAAA2gAAANsAAADcAAAA3QAAAN4AAADfAAAA4AAAAOEAAADiAAAA4wAAAOQAAADlAAAA5gAAAOcA +AADoAAAA6QAAAOoAAADrAAAA7AAAAO0AAADuAAAA7wAAAPAAAADxAAAA8gAAAPMAAAD0AAAA9QAA +APYAAAD3AAAA+AAAAPkAAAD6AAAA+wAAAPwAAAD9AAAA/gAAAP8AAAAAAQAAAQEAAAIBAAADAQAA +BAEAAAUBAAAGAQAABwEAAAgBAAAJAQAACgEAAAsBAAAMAQAADQEAAA4BAAAPAQAAEAEAABEBAAAS +AQAAEwEAABQBAAAVAQAAFgEAABcBAAAYAQAAGQEAABoBAAAbAQAAHAEAAB0BAAAeAQAAHwEAACAB +AAAhAQAAIgEAACMBAAAkAQAAJQEAACYBAAAnAQAAKAEAACkBAAAqAQAAKwEAACwBAAAtAQAALgEA +AC8BAAAwAQAAMQEAADIBAAAzAQAANAEAADUBAAA2AQAANwEAADgBAAA5AQAAOgEAADsBAAA8AQAA +PQEAAD4BAAA/AQAAQAEAAEEBAABCAQAAQwEAAEQBAABFAQAARgEAAEcBAABIAQAASQEAAEoBAABL +AQAATAEAAE0BAABOAQAATwEAAFABAABRAQAAUgEAAFMBAABUAQAAVQEAAFYBAABXAQAAWAEAAFkB +AABaAQAAWwEAAFwBAABdAQAAXgEAAF8BAABgAQAAYQEAAGIBAABjAQAAZAEAAGUBAABmAQAAZwEA +AGgBAABpAQAAagEAAGsBAABsAQAAbQEAAG4BAABvAQAAcAEAAHEBAAByAQAAcwEAAHQBAAB1AQAA +dgEAAHcBAAB4AQAAeQEAAHoBAAB7AQAAfAEAAH0BAAB+AQAAfwEAAIABAACBAQAAggEAAIMBAACE +AQAAhQEAAIYBAACHAQAAiAEAAIkBAACKAQAAiwEAAIwBAACNAQAAjgEAAI8BAACQAQAAkQEAAJIB +AACTAQAAlAEAAJUBAACWAQAAlwEAAJgBAACZAQAAmgEAAJsBAACcAQAAnQEAAJ4BAACfAQAAoAEA +AKEBAACiAQAAowEAAKQBAAClAQAApgEAAKcBAACoAQAAqQEAAKoBAACrAQAArAEAAK0BAACuAQAA +rwEAALABAACxAQAAsgEAALMBAAC0AQAAtQEAALYBAAC3AQAAuAEAALkBAAC6AQAAuwEAALwBAAC9 +AQAAvgEAAL8BAADAAQAAwQEAAMIBAADDAQAAxAEAAMUBAADGAQAAxwEAAMgBAADJAQAAygEAAMsB +AADMAQAAzQEAAM4BAADPAQAA0AEAANEBAADSAQAA0wEAANQBAADVAQAA1gEAANcBAADYAQAA2QEA +ANoBAADbAQAA3AEAAN0BAADeAQAA3wEAAOABAADhAQAA4gEAAOMBAADkAQAA5QEAAOYBAADnAQAA +6AEAAOkBAADqAQAA6wEAAOwBAADtAQAA7gEAAO8BAADwAQAA8QEAAPIBAADzAQAA9AEAAPUBAAD2 +AQAA9wEAAPgBAAD5AQAA+gEAAPsBAAD8AQAA/QEAAP4BAAD/AQAAAAIAAAECAAACAgAAAwIAAAQC +AAAFAgAABgIAAAcCAAAIAgAACQIAAAoCAAALAgAADAIAAA0CAAAOAgAADwIAABACAAARAgAAEgIA +ABMCAAAUAgAAFQIAABYCAAAXAgAAGAIAABkCAAAaAgAAGwIAABwCAAAdAgAAHgIAAB8CAAAgAgAA +IQIAACICAAAjAgAAJAIAACUCAAAmAgAAJwIAACgCAAApAgAAKgIAACsCAAAsAgAALQIAAC4CAAAv +AgAAMAIAADECAAAyAgAAMwIAADQCAAA1AgAANgIAADcCAAA4AgAAOQIAADoCAAA7AgAAPAIAAD0C +AAA+AgAAPwIAAEACAABBAgAAQgIAAEMCAABEAgAARQIAAEYCAABHAgAASAIAAEkCAABKAgAASwIA +AEwCAABNAgAATgIAAE8CAABQAgAAUQIAAFICAABTAgAAVAIAAFUCAABWAgAAVwIAAFgCAABZAgAA +WgIAAFsCAABcAgAAXQIAAF4CAABfAgAAYAIAAGECAABiAgAAYwIAAGQCAABlAgAAZgIAAGcCAABo +AgAAaQIAAGoCAABrAgAAbAIAAG0CAABuAgAAbwIAAHACAABxAgAAcgIAAHMCAAB0AgAAdQIAAHYC +AAB3AgAAeAIAAHkCAAB6AgAAewIAAHwCAAB9AgAAfgIAAH8CAACAAgAAgQIAAIICAACDAgAAhAIA +AIUCAACGAgAAhwIAAIgCAACJAgAAigIAAIsCAACMAgAAjQIAAI4CAACPAgAAkAIAAJECAACSAgAA +kwIAAJQCAACVAgAAlgIAAJcCAACYAgAAmQIAAJoCAACbAgAAnAIAAJ0CAACeAgAAnwIAAKACAACh +AgAAogIAAKMCAACkAgAApQIAAKYCAACnAgAAqAIAAKkCAACqAgAAqwIAAKwCAACtAgAArgIAAK8C +AACwAgAAsQIAALICAACzAgAAtAIAALUCAAC2AgAAtwIAALgCAAC5AgAAugIAALsCAAC8AgAAvQIA +AL4CAAC/AgAAwAIAAMECAADCAgAAwwIAAMQCAADFAgAAxgIAAMcCAADIAgAAyQIAAMoCAADLAgAA +zAIAAM0CAADOAgAAzwIAANACAADRAgAA0gIAANMCAADUAgAA1QIAANYCAADXAgAA2AIAANkCAADa +AgAA2wIAANwCAADdAgAA3gIAAN8CAADgAgAA4QIAAOICAADjAgAA5AIAAOUCAADmAgAA5wIAAOgC +AADpAgAA6gIAAOsCAADsAgAA7QIAAO4CAADvAgAA8AIAAPECAADyAgAA8wIAAPQCAAD1AgAA9gIA +APcCAAD4AgAA+QIAAPoCAAD7AgAA/AIAAP0CAAD+AgAA/wIAAAADAAABAwAAAgMAAAMDAAAEAwAA +BQMAAAYDAAAHAwAACAMAAAkDAAAKAwAACwMAAAwDAAANAwAADgMAAA8DAAAQAwAAEQMAABIDAAAT +AwAAFAMAABUDAAAWAwAAFwMAABgDAAAZAwAAGgMAABsDAAAcAwAAHQMAAB4DAAAfAwAAIAMAACED +AAAiAwAAIwMAACQDAAAlAwAAJgMAACcDAAAoAwAAKQMAACoDAAArAwAALAMAAC0DAAAuAwAALwMA +ADADAAAxAwAAMgMAADMDAAA0AwAANQMAADYDAAA3AwAAOAMAADkDAAA6AwAAOwMAADwDAAA9AwAA +PgMAAD8DAABAAwAAQQMAAEIDAABDAwAARAMAAEUDAAD+////RwMAAEgDAABJAwAASgMAAEsDAABM +AwAATQMAAE4DAABPAwAA/v///1EDAABSAwAAUwMAAFQDAABVAwAAVgMAAFcDAAD+////WQMAAFoD +AABbAwAAXAMAAF0DAABeAwAAXwMAAP7////9/////f////3////9/////f////3////9////aAMA +AP7////+/////v////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////1IAbwBvAHQAIABFAG4AdABy +AHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWAAUB//////// +//8DAAAABgkCAAAAAADAAAAAAAAARgAAAAAAAAAAAAAAACCVbx7gQcsBagMAAIAAAAAAAAAARABh +AHQAYQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAoAAgH///////////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO +AAAAGW8GAAAAAAAxAFQAYQBiAGwAZQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAADgACAQEAAAAGAAAA/////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAEYDAAAdEwAAAAAAAFcAbwByAGQARABvAGMAdQBtAGUAbgB0AAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaAAIBAgAAAAUAAAD/////AAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADIaAAAAAAAABQBTAHUAbQBtAGEAcgB5AEkA +bgBmAG8AcgBtAGEAdABpAG8AbgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAgH///////// +//////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQAwAAABAAAAAAAAAFAEQA +bwBjAHUAbQBlAG4AdABTAHUAbQBtAGEAcgB5AEkAbgBmAG8AcgBtAGEAdABpAG8AbgAAAAAAAAAA +AAAAOAACAQQAAAD//////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFgD +AAAAEAAAAAAAAAEAQwBvAG0AcABPAGIAagAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAASAAIA////////////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAG0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////////////8AAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAA/v////////////////// +//////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////wEA/v8DCgAA/////wYJAgAAAAAA +wAAAAAAAAEYbAAAATWljcm9zb2Z0IE9mZmljZSBXb3JkIM7EtbUACgAAAE1TV29yZERvYwAQAAAA +V29yZC5Eb2N1bWVudC44APQ5snEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + +--=====001_Dragon274075040732_=====-- + + + +. diff --git a/lib_acl_cpp/samples/mime/test6.eml b/lib_acl_cpp/samples/mime/test6.eml new file mode 100644 index 000000000..c5f0c8baa --- /dev/null +++ b/lib_acl_cpp/samples/mime/test6.eml @@ -0,0 +1,209 @@ +Received: from ltdmailsystem.com (unknown [60.195.252.107]) + by mx5 (Coremail) with SMTP id I8mowLBLD0m5N7dMbuCYBg--.758S2; + Fri, 15 Oct 2010 01:02:49 +0800 (CST) +Received: from localhost.localdomain (unknown [192.168.2.2]) + by ltdmailsystem.com (Postfix) with ESMTP id A5569143276 + for ; Fri, 15 Oct 2010 01:02:48 +0800 (CST) +Date: Fri, 15 Oct 2010 01:02:48 +0800 +To: "whouseit@126.com" +From: =?UTF-8?B?55uR5o6n5a6d?= +Subject: =?UTF-8?B?56uZ54K555uR5o6n5pel5oqlWzEw5pyIMTTml6Vd?= +Message-ID: <8259409720071c429d0461cb07567c8c@localhost.localdomain> +X-Priority: 3 +X-Mailer: PHPMailer 5.1 (phpmailer.sourceforge.net) +MIME-Version: 1.0 +Content-Transfer-Encoding: 8bit +Content-Type: text/html; charset="UTF-8" +X-Coremail-Antispam: 1Uf129KBjvdXoW7XryDJrWDCr4xWFW7uF1rJFb_yoWkZrXEgw + 43Aa9xJrWDAr1kXF40gr43A390qr1kXw1xGw4qq34fKry3Cr48KrZFkanI9r40qr4Du3Z8 + X34Y93yakw47ujkaLaAFLSUrUUUUjb8apTn2vfkv8UJUUUU8Yxn0WfASr-VFAUDa7-sFnT + 9fnUUvcSsGvfC2KfnxnUUI43ZEXa7IU8ME_tUUUUU== + + + + + + + +

绔欑偣鐩戞帶鏃ユ姤[10鏈14鏃

+

浠ヤ笅鏄洃鎺у疂鑷姩鍙戦佺殑鐩戞帶鏃ユ姤姒傝堪锛屼綘鍙互閫氳繃瀹冨揩閫熶簡瑙f槰鏃ョ殑绔欑偣鎬ц兘鍜屽彲鐢ㄧ巼銆備綘涔熷彲浠ュ湪璇︾粏鎶ュ憡涓簡瑙f洿澶氱殑淇℃伅銆

+ + + + +

鐩戞帶椤圭洰姒傝堪[10鏈14鏃

+

瀵煎嚭浠ヤ笅鎶ヨ〃鍒癊xcel锛

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
 浠诲姟鍚嶇О鎽樿鐩戞帶绫诲瀷鐩戞帶棰戠巼鍙敤鐜骞冲潎鍝嶅簲鏃堕棿鏁呴殰鏃堕棿 
 httphttp://221.194.139.155:8088/http30鍒嗛挓100.00%205.38 ms-[鏌ョ湅璇︾粏鎶ュ憡] 
 ping221.194.139.155ping30鍒嗛挓100.00%81.29 ms-[鏌ョ湅璇︾粏鎶ュ憡] 
+ + +

鍛婅閫氱煡[10鏈14鏃

+

鏄惁闇瑕佹墜鏈虹煭淇″憡璀︼紵閭璇峰ソ鍙嬪嵆鍙幏璧犳洿澶氱煭淇¢厤棰濓紒

+ + + + + + + + + + + + + + + + + + + + + + + + + +
  Email閫氱煡娆℃暟: + 0 +
  鐭俊閫氱煡娆℃暟: + 0 +
  MSN閫氱煡娆℃暟: + 0 +
  Gtalk閫氱煡娆℃暟: + 0 +
+ +

whouseit@126.com鐨勫笎鍙蜂俊鎭

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
 璐︽埛鐗堟湰:鍏嶈垂鐗
 鏈湀濂楅鍓╀綑鐭俊閰嶉:0
 棰濆鍓╀綑鐭俊閰嶉:2
 杩樺彲鍒涘缓绔欑偣鐩戞帶椤圭洰鏁:3
+ + +

鏄惁闇瑕侀璁㈡瘡鏃ユ姤鍛婇偖浠讹紵 +璇疯闂 http://www.jiankongbao.com/user_report_list.php?m=8771

+

鏄惁闇瑕佸府鍔╋紵璇峰彂閫侀偖浠惰嚦 help@jiankongbao.com銆傛垜浠皢灏藉姏甯姪鎮ㄣ

+

鏄惁甯屾湜浜嗚В鐩戞帶瀹濈殑鏂板姛鑳藉拰鏂板姩鎬侊紵璇锋祻瑙堟垜浠殑Blog: http://blog.jiankongbao.com锛屾垨鑰呭叧娉ㄦ垜浠殑寰崥: http://t.sina.com.cn/jiankongbao(鏂版氮寰崥) 鎴 http://t.qq.com/jiankongbao(鑵捐寰崥)銆

+

璋㈣阿鎮ㄧ殑浣跨敤
+鐩戞帶瀹 www.jiankongbao.com +

+ + diff --git a/lib_acl_cpp/samples/mime/test7.eml b/lib_acl_cpp/samples/mime/test7.eml new file mode 100644 index 000000000..cae6c0436 --- /dev/null +++ b/lib_acl_cpp/samples/mime/test7.eml @@ -0,0 +1,14763 @@ +Date: Wed, 01 Dec 2010 07:18:04 GMT +From: +To: "admin" +Subject: =?GB2312?B?08q8/rLiytTW98zi?= +Mime-version: 1.0 +Content-Type: multipart/mixed; charset="GB2312"; boundary="=_0_10109_1291187882" + +This is a multi-part message in MIME format. + +--=_0_10109_1291187882 +Content-Type: text/html; charset="GB2312" +Content-Transfer-Encoding: base64 + +PGRpdiBhbGlnbj0iY2VudGVyIj48c3Ryb25nPtPKvP7W98zisuLK1DxiciAvPtPKvP7W98zisuLK +1DxiciAvPtPKvP7W98zisuLK1DxiciAvPtPKvP7W98zisuLK1DxiciAvPtPKvP7W98zisuLK1Dxi +ciAvPtPKvP7W98zisuLK1DxiciAvPtPKvP7W98zisuLK1Dwvc3Ryb25nPjxiciAvPjwvZGl2Pg== + + +--=_0_10109_1291187882 +Content-Type: application/octet-stream; + name="EA-help.docx" +Content-Disposition: attachment; + filename="EA-help.docx" +Content-Transfer-Encoding: base64 + +UEsDBBQABgAIAAAAIQCi/RKq1gEAAJcIAAATAAgCW0NvbnRlbnRfVHlwZXNdLnhtbCCiBAIooAAC +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC0 +Vk1r4zAQvS/0PxhdS6x0D6UscXpod4/bwqawV0UaJ2r1hTRpm3+/IycxS+raUOOLwTbz3hu9N2Mv +bt+tKV4hJu1dxa7KOSvASa+021TsafVrdsOKhMIpYbyDiu0hsdvlxbfFah8gFVTtUsW2iOEH50lu +wYpU+gCO3tQ+WoF0Gzc8CPkiNsC/z+fXXHqH4HCGGYMtFw8kIGoFxaOI+FtY4uFvPipee4/OI6SS +4Fhxd6jL1BUTIRgtBZJw/urUGenM17WWoLzcWaIqM1yIXkJK1Jo1ZQt9maH5cnEPtdgZLH6+k7bD +cQS3OSPVNjeRn1NFl2y5S+jtX2u4RrCP0Yd0NVp8C5rxIKKG1KP6OUC37OZFd6cRTDprdeB8j4aW +VNl4kLY69KnqN/DoQdeJNkFofeyH+UIOWmQrtDud6qc63M6uIVKCRnv6IZAt9KCIhHszxUgccAfp +wamJZvKE3CeB/GqmilM+R5sAedYVqBmthrPB+jQCCRApABOspBNyX/vtWoQ4fq98yGBeihAH+ZHW +PPDmOl5EAzNIWdPqX4m1gdGedzR9hB4U8QbrP5O5/x/4oJAtCDVJAA7Affzt/Ekfv2DG6bORqzum +jje/Fct/AAAA//8DAFBLAwQUAAYACAAAACEAHpEat/MAAABOAgAACwAIAl9yZWxzLy5yZWxzIKIE +AiigAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAIyS20oDQQyG7wXfYch9N9sKItLZ3kihdyLrA4SZ7AF3Dsyk2r69oyC6UNte5vTny0/Wm4Ob +1DunPAavYVnVoNibYEffa3htt4sHUFnIW5qCZw1HzrBpbm/WLzyRlKE8jDGrouKzhkEkPiJmM7Cj +XIXIvlS6kBxJCVOPkcwb9Yyrur7H9FcDmpmm2lkNaWfvQLXHWDZf1g5dNxp+Cmbv2MuJFcgHYW/Z +LmIqbEnGco1qKfUsGmwwzyWdkWKsCjbgaaLV9UT/X4uOhSwJoQmJz/N8dZwDWl4PdNmiecevOx8h +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 +DAwMDAwMDAwMDAwMDAwBDQsLDQ4NEA4OEBQODg4UFA4ODg4UEQwMDAwMEREMDAwMDAwRDAwMDAwM +DAwMDAwMDAwMDAwMDAwMDAwMDAwMDP/AABEIAG8AoAMBIgACEQEDEQH/3QAEAAr/xAE/AAABBQEB +AQEBAQAAAAAAAAADAAECBAUGBwgJCgsBAAEFAQEBAQEBAAAAAAAAAAEAAgMEBQYHCAkKCxAAAQQB +AwIEAgUHBggFAwwzAQACEQMEIRIxBUFRYRMicYEyBhSRobFCIyQVUsFiMzRygtFDByWSU/Dh8WNz +NRaisoMmRJNUZEXCo3Q2F9JV4mXys4TD03Xj80YnlKSFtJXE1OT0pbXF1eX1VmZ2hpamtsbW5vY3 +R1dnd4eXp7fH1+f3EQACAgECBAQDBAUGBwcGBTUBAAIRAyExEgRBUWFxIhMFMoGRFKGxQiPBUtHw +MyRi4XKCkkNTFWNzNPElBhaisoMHJjXC0kSTVKMXZEVVNnRl4vKzhMPTdePzRpSkhbSVxNTk9KW1 +xdXl9VZmdoaWprbG1ub2JzdHV2d3h5ent8f/2gAMAwEAAhEDEQA/APSMzKvZezHo2NJY6x9lgLgG +tLW7W1tdVu3bvper+jVWrqVtxLac7EtcORWzcRH9TMKj1zp9fU3XYNpLWX4jmFw7EvYWn/Oas/oX +1Yp6Va+/QPcNjK2u3NY0/TcHQ332bf3UbNxAjYPzSXxjiOPJKWQxyRoY8YHz/wCE6/2jqH+no/7Z +d/71JvtOf/p6P+2Xf+9Sot6f1AY7K/U2kMaHgWaucNxtf6pbY/c/9Dsd/wAZ+jUnY3VAxznWb3bo +a2stbO6ysT7mP2sbT63/ABSlqPZgs9279pz/APT0f9su/wDepL7Tn/6ej/tl3/vUqZw+pBrT6zXW +fn6gN5G3aPT9rNv0/wDCJ/sfUH4npPuaLy+XWjs0e5oYKyz6dzf3v5n2fyEqj2VZ7tv7R1D/AE9H +/bLv/epN9pz/APuRR/2y7/3qVF+D1N9j372De5pLQ/QbHepXt/R/zTG+z0vp22e/epnE6mC7bcHN +9m2S0HQD1d7tn+k3/QZ9DZ/xSVR7Ks922crOAJORQABJJpdAA/8AQpI5eaGhxyccNMQ70XQZ+jr9 +r/OVZ2NmfZNr2m+/fLYc0e2R7n7nVVe1u/Y38y30rP8AioOw7/Qq/Qvdax0vG6prTIG72+s5jWuf +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 +AAAAAAtwcmludE91dHB1dAAAAAUAAAAAQ2xyU2VudW0AAAAAQ2xyUwAAAABSR0JDAAAAAEludGVl +bnVtAAAAAEludGUAAAAASW1nIAAAAABNcEJsYm9vbAEAAAAPcHJpbnRTaXh0ZWVuQml0Ym9vbAAA +AAALcHJpbnRlck5hbWVURVhUAAAAAQAAADhCSU0EOwAAAAABsgAAABAAAAABAAAAAAAScHJpbnRP +dXRwdXRPcHRpb25zAAAAEgAAAABDcHRuYm9vbAAAAAAAQ2xicmJvb2wAAAAAAFJnc01ib29sAAAA +AABDcm5DYm9vbAAAAAAAQ250Q2Jvb2wAAAAAAExibHNib29sAAAAAABOZ3R2Ym9vbAAAAAAARW1s +RGJvb2wAAAAAAEludHJib29sAAAAAABCY2tnT2JqYwAAAAEAAAAAAABSR0JDAAAAAwAAAABSZCAg +ZG91YkBv4AAAAAAAAAAAAEdybiBkb3ViQG/gAAAAAAAAAAAAQmwgIGRvdWJAb+AAAAAAAAAAAABC +cmRUVW50RiNSbHQAAAAAAAAAAAAAAABCbGQgVW50RiNSbHQAAAAAAAAAAAAAAABSc2x0VW50RiNQ +eGxAUgAAAAAAAAAAAAp2ZWN0b3JEYXRhYm9vbAEAAAAAUGdQc2VudW0AAAAAUGdQcwAAAABQZ1BD +AAAAAExlZnRVbnRGI1JsdAAAAAAAAAAAAAAAAFRvcCBVbnRGI1JsdAAAAAAAAAAAAAAAAFNjbCBV +bnRGI1ByY0BZAAAAAAAAOEJJTQPtAAAAAAAQAEgAAAABAAIASAAAAAEAAjhCSU0EJgAAAAAADgAA +AAAAAAAAAAA/gAAAOEJJTQQNAAAAAAAEAAAAeDhCSU0EGQAAAAAABAAAAB44QklNA/MAAAAAAAkA +AAAAAAAAAAEAOEJJTScQAAAAAAAKAAEAAAAAAAAAAjhCSU0D9QAAAAAASAAvZmYAAQBsZmYABgAA +AAAAAQAvZmYAAQChmZoABgAAAAAAAQAyAAAAAQBaAAAABgAAAAAAAQA1AAAAAQAtAAAABgAAAAAA +AThCSU0D+AAAAAAAcAAA/////////////////////////////wPoAAAAAP////////////////// +//////////8D6AAAAAD/////////////////////////////A+gAAAAA//////////////////// +/////////wPoAAA4QklNBAAAAAAAAAIAAThCSU0EAgAAAAAABAAAAAA4QklNBDAAAAAAAAIBAThC +SU0ELQAAAAAABgABAAAADThCSU0ECAAAAAAAEAAAAAEAAAJAAAACQAAAAAA4QklNBB4AAAAAAAQA +AAAAOEJJTQQaAAAAAAM/AAAABgAAAAAAAAAAAAAA7AAAAVMAAAAFZypoB5iYAC0AMQAAAAEAAAAA +AAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAABUwAAAOwAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAA +AAAAAAAAAAAAAAAQAAAAAQAAAAAAAG51bGwAAAACAAAABmJvdW5kc09iamMAAAABAAAAAAAAUmN0 +MQAAAAQAAAAAVG9wIGxvbmcAAAAAAAAAAExlZnRsb25nAAAAAAAAAABCdG9tbG9uZwAAAOwAAAAA +UmdodGxvbmcAAAFTAAAABnNsaWNlc1ZsTHMAAAABT2JqYwAAAAEAAAAAAAVzbGljZQAAABIAAAAH +c2xpY2VJRGxvbmcAAAAAAAAAB2dyb3VwSURsb25nAAAAAAAAAAZvcmlnaW5lbnVtAAAADEVTbGlj +ZU9yaWdpbgAAAA1hdXRvR2VuZXJhdGVkAAAAAFR5cGVlbnVtAAAACkVTbGljZVR5cGUAAAAASW1n +IAAAAAZib3VuZHNPYmpjAAAAAQAAAAAAAFJjdDEAAAAEAAAAAFRvcCBsb25nAAAAAAAAAABMZWZ0 +bG9uZwAAAAAAAAAAQnRvbWxvbmcAAADsAAAAAFJnaHRsb25nAAABUwAAAAN1cmxURVhUAAAAAQAA +AAAAAG51bGxURVhUAAAAAQAAAAAAAE1zZ2VURVhUAAAAAQAAAAAABmFsdFRhZ1RFWFQAAAABAAAA +AAAOY2VsbFRleHRJc0hUTUxib29sAQAAAAhjZWxsVGV4dFRFWFQAAAABAAAAAAAJaG9yekFsaWdu +ZW51bQAAAA9FU2xpY2VIb3J6QWxpZ24AAAAHZGVmYXVsdAAAAAl2ZXJ0QWxpZ25lbnVtAAAAD0VT +bGljZVZlcnRBbGlnbgAAAAdkZWZhdWx0AAAAC2JnQ29sb3JUeXBlZW51bQAAABFFU2xpY2VCR0Nv +bG9yVHlwZQAAAABOb25lAAAACXRvcE91dHNldGxvbmcAAAAAAAAACmxlZnRPdXRzZXRsb25nAAAA +AAAAAAxib3R0b21PdXRzZXRsb25nAAAAAAAAAAtyaWdodE91dHNldGxvbmcAAAAAADhCSU0EKAAA +AAAADAAAAAI/8AAAAAAAADhCSU0EFAAAAAAABAAAAA04QklNBAwAAAAAEgAAAAABAAAAoAAAAG8A +AAHgAADQIAAAEeQAGAAB/9j/7QAMQWRvYmVfQ00AAf/uAA5BZG9iZQBkgAAAAAH/2wCEAAwICAgJ +CAwJCQwRCwoLERUPDAwPFRgTExUTExgRDAwMDAwMEQwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwM +DAwBDQsLDQ4NEA4OEBQODg4UFA4ODg4UEQwMDAwMEREMDAwMDAwRDAwMDAwMDAwMDAwMDAwMDAwM +DAwMDAwMDAwMDP/AABEIAG8AoAMBIgACEQEDEQH/3QAEAAr/xAE/AAABBQEBAQEBAQAAAAAAAAAD +AAECBAUGBwgJCgsBAAEFAQEBAQEBAAAAAAAAAAEAAgMEBQYHCAkKCxAAAQQBAwIEAgUHBggFAwwz +AQACEQMEIRIxBUFRYRMicYEyBhSRobFCIyQVUsFiMzRygtFDByWSU/Dh8WNzNRaisoMmRJNUZEXC +o3Q2F9JV4mXys4TD03Xj80YnlKSFtJXE1OT0pbXF1eX1VmZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3 +EQACAgECBAQDBAUGBwcGBTUBAAIRAyExEgRBUWFxIhMFMoGRFKGxQiPBUtHwMyRi4XKCkkNTFWNz +NPElBhaisoMHJjXC0kSTVKMXZEVVNnRl4vKzhMPTdePzRpSkhbSVxNTk9KW1xdXl9VZmdoaWprbG +1ub2JzdHV2d3h5ent8f/2gAMAwEAAhEDEQA/APSMzKvZezHo2NJY6x9lgLgGtLW7W1tdVu3bvper ++jVWrqVtxLac7EtcORWzcRH9TMKj1zp9fU3XYNpLWX4jmFw7EvYWn/Oas/oX1Yp6Va+/QPcNjK2u +3NY0/TcHQ332bf3UbNxAjYPzSXxjiOPJKWQxyRoY8YHz/wCE6/2jqH+no/7Zd/71JvtOf/p6P+2X +f+9Sot6f1AY7K/U2kMaHgWaucNxtf6pbY/c/9Dsd/wAZ+jUnY3VAxznWb3boa2stbO6ysT7mP2sb +T63/ABSlqPZgs9279pz/APT0f9su/wDepL7Tn/6ej/tl3/vUqZw+pBrT6zXWfn6gN5G3aPT9rNv0 +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 +9ky/+5WL/mO/9LpfZMv/ALlYv+Y7/wBLpe9D95Xty7Ifs2N/omf5oS+zY3+hZ/mhG+yZf/crF/zH +f+l0vsmX/wBysX/Md/6XS96H7yvbl2YpVf8AKGF/xj//AD1apfZMv/uVi/5jv/S6lj4lozMey3Jo +cK3OLWVtIc4lj2bW7rn/AEWu3/QTZZYGJAPRMYSBBrq//9k4QklNBCEAAAAAAFUAAAABAQAAAA8A +QQBkAG8AYgBlACAAUABoAG8AdABvAHMAaABvAHAAAAATAEEAZABvAGIAZQAgAFAAaABvAHQAbwBz +AGgAbwBwACAAQwBTADUAAAABADhCSU0EBgAAAAAABwAIAAEAAQEA/+EN0Gh0dHA6Ly9ucy5hZG9i +ZS5jb20veGFwLzEuMC8APD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6 +TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0i +QWRvYmUgWE1QIENvcmUgNS4wLWMwNjAgNjEuMTM0Nzc3LCAyMDEwLzAyLzEyLTE3OjMyOjAwICAg +ICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjIt +cmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9 +Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRv +YmUuY29tL3hhcC8xLjAvbW0vIiB4bWxuczpzdEV2dD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAv +MS4wL3NUeXBlL1Jlc291cmNlRXZlbnQjIiB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2Vs +ZW1lbnRzLzEuMS8iIHhtbG5zOnBob3Rvc2hvcD0iaHR0cDovL25zLmFkb2JlLmNvbS9waG90b3No +b3AvMS4wLyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IFdpbmRvd3MiIHht +cDpDcmVhdGVEYXRlPSIyMDEwLTA4LTMxVDAxOjExOjM5KzA4OjAwIiB4bXA6TWV0YWRhdGFEYXRl +PSIyMDEwLTA4LTMxVDAxOjExOjM5KzA4OjAwIiB4bXA6TW9kaWZ5RGF0ZT0iMjAxMC0wOC0zMVQw +MToxMTozOSswODowMCIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo1MzRFNzBDMDU3QjRERjEx +QkU3RUIyMzcyOTQyRjc0OSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo1MjRFNzBDMDU3QjRE +RjExQkU3RUIyMzcyOTQyRjc0OSIgeG1wTU06T3JpZ2luYWxEb2N1bWVudElEPSJ4bXAuZGlkOjUy +NEU3MEMwNTdCNERGMTFCRTdFQjIzNzI5NDJGNzQ5IiBkYzpmb3JtYXQ9ImltYWdlL2pwZWciIHBo +b3Rvc2hvcDpDb2xvck1vZGU9IjMiIHBob3Rvc2hvcDpJQ0NQcm9maWxlPSJzUkdCIElFQzYxOTY2 +LTIuMSI+IDx4bXBNTTpIaXN0b3J5PiA8cmRmOlNlcT4gPHJkZjpsaSBzdEV2dDphY3Rpb249ImNy +ZWF0ZWQiIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6NTI0RTcwQzA1N0I0REYxMUJFN0VCMjM3 +Mjk0MkY3NDkiIHN0RXZ0OndoZW49IjIwMTAtMDgtMzFUMDE6MTE6MzkrMDg6MDAiIHN0RXZ0OnNv +ZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCBDUzUgV2luZG93cyIvPiA8cmRmOmxpIHN0RXZ0 +OmFjdGlvbj0ic2F2ZWQiIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6NTM0RTcwQzA1N0I0REYx +MUJFN0VCMjM3Mjk0MkY3NDkiIHN0RXZ0OndoZW49IjIwMTAtMDgtMzFUMDE6MTE6MzkrMDg6MDAi +IHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCBDUzUgV2luZG93cyIgc3RFdnQ6 +Y2hhbmdlZD0iLyIvPiA8L3JkZjpTZXE+IDwveG1wTU06SGlzdG9yeT4gPC9yZGY6RGVzY3JpcHRp +b24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgPD94cGFja2V0IGVuZD0idyI/Pv/iDFhJQ0NfUFJPRklM +RQABAQAADEhMaW5vAhAAAG1udHJSR0IgWFlaIAfOAAIACQAGADEAAGFjc3BNU0ZUAAAAAElFQyBz +UkdCAAAAAAAAAAAAAAAAAAD21gABAAAAANMtSFAgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAEWNwcnQAAAFQAAAAM2Rlc2MAAAGEAAAAbHd0cHQAAAHwAAAA +FGJrcHQAAAIEAAAAFHJYWVoAAAIYAAAAFGdYWVoAAAIsAAAAFGJYWVoAAAJAAAAAFGRtbmQAAAJU +AAAAcGRtZGQAAALEAAAAiHZ1ZWQAAANMAAAAhnZpZXcAAAPUAAAAJGx1bWkAAAP4AAAAFG1lYXMA +AAQMAAAAJHRlY2gAAAQwAAAADHJUUkMAAAQ8AAAIDGdUUkMAAAQ8AAAIDGJUUkMAAAQ8AAAIDHRl +eHQAAAAAQ29weXJpZ2h0IChjKSAxOTk4IEhld2xldHQtUGFja2FyZCBDb21wYW55AABkZXNjAAAA +AAAAABJzUkdCIElFQzYxOTY2LTIuMQAAAAAAAAAAAAAAEnNSR0IgSUVDNjE5NjYtMi4xAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABYWVogAAAAAAAA81EA +AQAAAAEWzFhZWiAAAAAAAAAAAAAAAAAAAAAAWFlaIAAAAAAAAG+iAAA49QAAA5BYWVogAAAAAAAA +YpkAALeFAAAY2lhZWiAAAAAAAAAkoAAAD4QAALbPZGVzYwAAAAAAAAAWSUVDIGh0dHA6Ly93d3cu +aWVjLmNoAAAAAAAAAAAAAAAWSUVDIGh0dHA6Ly93d3cuaWVjLmNoAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGRlc2MAAAAAAAAALklFQyA2MTk2Ni0yLjEgRGVm +YXVsdCBSR0IgY29sb3VyIHNwYWNlIC0gc1JHQgAAAAAAAAAAAAAALklFQyA2MTk2Ni0yLjEgRGVm +YXVsdCBSR0IgY29sb3VyIHNwYWNlIC0gc1JHQgAAAAAAAAAAAAAAAAAAAAAAAAAAAABkZXNjAAAA +AAAAACxSZWZlcmVuY2UgVmlld2luZyBDb25kaXRpb24gaW4gSUVDNjE5NjYtMi4xAAAAAAAAAAAA +AAAsUmVmZXJlbmNlIFZpZXdpbmcgQ29uZGl0aW9uIGluIElFQzYxOTY2LTIuMQAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAdmlldwAAAAAAE6T+ABRfLgAQzxQAA+3MAAQTCwADXJ4AAAABWFlaIAAA +AAAATAlWAFAAAABXH+dtZWFzAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAACjwAAAAJzaWcgAAAA +AENSVCBjdXJ2AAAAAAAABAAAAAAFAAoADwAUABkAHgAjACgALQAyADcAOwBAAEUASgBPAFQAWQBe +AGMAaABtAHIAdwB8AIEAhgCLAJAAlQCaAJ8ApACpAK4AsgC3ALwAwQDGAMsA0ADVANsA4ADlAOsA +8AD2APsBAQEHAQ0BEwEZAR8BJQErATIBOAE+AUUBTAFSAVkBYAFnAW4BdQF8AYMBiwGSAZoBoQGp +AbEBuQHBAckB0QHZAeEB6QHyAfoCAwIMAhQCHQImAi8COAJBAksCVAJdAmcCcQJ6AoQCjgKYAqIC +rAK2AsECywLVAuAC6wL1AwADCwMWAyEDLQM4A0MDTwNaA2YDcgN+A4oDlgOiA64DugPHA9MD4APs +A/kEBgQTBCAELQQ7BEgEVQRjBHEEfgSMBJoEqAS2BMQE0wThBPAE/gUNBRwFKwU6BUkFWAVnBXcF +hgWWBaYFtQXFBdUF5QX2BgYGFgYnBjcGSAZZBmoGewaMBp0GrwbABtEG4wb1BwcHGQcrBz0HTwdh +B3QHhgeZB6wHvwfSB+UH+AgLCB8IMghGCFoIbgiCCJYIqgi+CNII5wj7CRAJJQk6CU8JZAl5CY8J +pAm6Cc8J5Qn7ChEKJwo9ClQKagqBCpgKrgrFCtwK8wsLCyILOQtRC2kLgAuYC7ALyAvhC/kMEgwq +DEMMXAx1DI4MpwzADNkM8w0NDSYNQA1aDXQNjg2pDcMN3g34DhMOLg5JDmQOfw6bDrYO0g7uDwkP +JQ9BD14Peg+WD7MPzw/sEAkQJhBDEGEQfhCbELkQ1xD1ERMRMRFPEW0RjBGqEckR6BIHEiYSRRJk +EoQSoxLDEuMTAxMjE0MTYxODE6QTxRPlFAYUJxRJFGoUixStFM4U8BUSFTQVVhV4FZsVvRXgFgMW +JhZJFmwWjxayFtYW+hcdF0EXZReJF64X0hf3GBsYQBhlGIoYrxjVGPoZIBlFGWsZkRm3Gd0aBBoq +GlEadxqeGsUa7BsUGzsbYxuKG7Ib2hwCHCocUhx7HKMczBz1HR4dRx1wHZkdwx3sHhYeQB5qHpQe +vh7pHxMfPh9pH5Qfvx/qIBUgQSBsIJggxCDwIRwhSCF1IaEhziH7IiciVSKCIq8i3SMKIzgjZiOU +I8Ij8CQfJE0kfCSrJNolCSU4JWgllyXHJfcmJyZXJocmtyboJxgnSSd6J6sn3CgNKD8ocSiiKNQp +Bik4KWspnSnQKgIqNSpoKpsqzysCKzYraSudK9EsBSw5LG4soizXLQwtQS12Last4S4WLkwugi63 +Lu4vJC9aL5Evxy/+MDUwbDCkMNsxEjFKMYIxujHyMioyYzKbMtQzDTNGM38zuDPxNCs0ZTSeNNg1 +EzVNNYc1wjX9Njc2cjauNuk3JDdgN5w31zgUOFA4jDjIOQU5Qjl/Obw5+To2OnQ6sjrvOy07azuq +O+g8JzxlPKQ84z0iPWE9oT3gPiA+YD6gPuA/IT9hP6I/4kAjQGRApkDnQSlBakGsQe5CMEJyQrVC +90M6Q31DwEQDREdEikTORRJFVUWaRd5GIkZnRqtG8Ec1R3tHwEgFSEtIkUjXSR1JY0mpSfBKN0p9 +SsRLDEtTS5pL4kwqTHJMuk0CTUpNk03cTiVObk63TwBPSU+TT91QJ1BxULtRBlFQUZtR5lIxUnxS +x1MTU19TqlP2VEJUj1TbVShVdVXCVg9WXFapVvdXRFeSV+BYL1h9WMtZGllpWbhaB1pWWqZa9VtF +W5Vb5Vw1XIZc1l0nXXhdyV4aXmxevV8PX2Ffs2AFYFdgqmD8YU9homH1YklinGLwY0Njl2PrZEBk +lGTpZT1lkmXnZj1mkmboZz1nk2fpaD9olmjsaUNpmmnxakhqn2r3a09rp2v/bFdsr20IbWBtuW4S +bmtuxG8eb3hv0XArcIZw4HE6cZVx8HJLcqZzAXNdc7h0FHRwdMx1KHWFdeF2Pnabdvh3VnezeBF4 +bnjMeSp5iXnnekZ6pXsEe2N7wnwhfIF84X1BfaF+AX5ifsJ/I3+Ef+WAR4CogQqBa4HNgjCCkoL0 +g1eDuoQdhICE44VHhauGDoZyhteHO4efiASIaYjOiTOJmYn+imSKyoswi5aL/IxjjMqNMY2Yjf+O +Zo7OjzaPnpAGkG6Q1pE/kaiSEZJ6kuOTTZO2lCCUipT0lV+VyZY0lp+XCpd1l+CYTJi4mSSZkJn8 +mmia1ZtCm6+cHJyJnPedZJ3SnkCerp8dn4uf+qBpoNihR6G2oiailqMGo3aj5qRWpMelOKWpphqm +i6b9p26n4KhSqMSpN6mpqhyqj6sCq3Wr6axcrNCtRK24ri2uoa8Wr4uwALB1sOqxYLHWskuywrM4 +s660JbSctRO1irYBtnm28Ldot+C4WbjRuUq5wro7urW7LrunvCG8m70VvY++Cr6Evv+/er/1wHDA +7MFnwePCX8Lbw1jD1MRRxM7FS8XIxkbGw8dBx7/IPci8yTrJuco4yrfLNsu2zDXMtc01zbXONs62 +zzfPuNA50LrRPNG+0j/SwdNE08bUSdTL1U7V0dZV1tjXXNfg2GTY6Nls2fHadtr724DcBdyK3RDd +lt4c3qLfKd+v4DbgveFE4cziU+Lb42Pj6+Rz5PzlhOYN5pbnH+ep6DLovOlG6dDqW+rl63Dr++yG +7RHtnO4o7rTvQO/M8Fjw5fFy8f/yjPMZ86f0NPTC9VD13vZt9vv3ivgZ+Kj5OPnH+lf65/t3/Af8 +mP0p/br+S/7c/23////uAA5BZG9iZQBkQAAAAAH/2wCEAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB +AQEBAQEBAQEBAQEBAQEBAQEBAQECAgICAgICAgICAgMDAwMDAwMDAwMBAQEBAQEBAQEBAQICAQIC +AwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA//AABEIAOwB +UwMBEQACEQEDEQH/3QAEACv/xADuAAEAAQUBAQEBAAAAAAAAAAAABwUGCAkKBAMBAgEBAAEFAQEB +AQAAAAAAAAAAAAQCAwUGCAEHCQoQAAAFAwEBCwgHAQsIBwkAAAMEBQYHAAECCBYREhMUFZbWF9dY +mJGUVVd3GDgJIVOVl7e42DFBUXGB4SJSNFa2N2GhsXKyIyQl0TIzVNQ1J0JikuJjc0V2ChEAAQMC +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 +A07Nh+zv8xTr0nTN84Tl8P68n54DTs2H7O/zFOvSdM3zhOXw/ryfngNOzYfs7/MU69J0zfOE5fD+ +vJ+eA07Nh+zv8xTr0nTN84Tl8P68n54DTs2H7O/zFOvSdM3zhOXw/ryfngNOzYfs7/MU69J0zfOE +5fD+vJ+eA07Nh+zv8xTr0nTN84Tl8P68n54DTs2H7O/zFOvSdM3zhOXw/ryfngNOzYfs7/MU69J0 +zfOE5fD+vJ+eA07Nh+zv8xTr0nTN84Tl8P68n54DTs2H7O/zFOvSdM3zhOXw/ryfngNOzYfs7/MU +69J0zfOFBCUTRo31eQW+2IQSEZW1EL7ug+ZCqcIdAIPRHQYZlWbmU8lZKSVNPR1GQWOuxPklpysf +KnRwUNxKhS17cKDmBHzy1EvDl6yVr8NrgkiJGlpdIyN7ASCQx4kxOaCKvYx3gIN3Krgszq1dGW1u +MTJKH8oNY57XEA0LmlmEOINGucPFTaNXyxb8v//R7+KIuWLUmQmXH5OkWnoOdrkZDtLwNpeFVFxo +GDae57M42hsIg5gEhXThAlJHyyJnbCGTIGYYmBIMa18rY5ZVvP8AOfMM1sOEuJrvKLqSKeKWrnR1 +D+b50B+Fw0toDVxBHoh2mi3b/wCnXD/CvEv89P5eZBxblttdWF4JI447gNdCbnq73QB7H1bJie3B +GxwIdK5mgmi57mZpnmKNiqe6ASB4cmNnY2NkKNmaGFEFviNmYHtnbf3EEEvv887bmd733b3vf9v5 +7XF7cytdPJFJhdpxHTWvhPh0r+jTKeG8lsp4sttswtHTxANMbHBuEDQGigDfR8ABNOQLpd+V1Gkh +hsV3Sm+QDSeTeeaQiNEgaHHzEOJDcEUszizcETdwxICqKhkAUv8ARluhD5blsM8csutv/rtk2Y5f +k2bcQXoLLe+dG2Fp0FzIsdZKfFc55ayorRpd+S5pP45//wClvHXC+dcecI/y54flZPmXD8dxJfSM +Ic2Oe86vhtcQGmSKOBsk1CWgzMjNJI5GtyIUpkVcZnkCOzk26dYwAaTsaDfQmlICEYOPx3FnAzWm +4xTScZFm5j4ZiG1NfGJFeBSDGNswsbX4XPfY3+/5VmD74xOfcRPkN9LDzDBSUtjkDGgHG845QaNP +NEYuRruRfmvmFky0t7d7YZGtfY88ZXEc01xluYyKYW+jG2Fj3jnAaP5WihV9kp9RFJczRiUeSTcu +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 +Y3Xy9b2v/9Pv4oi0q6Mn+sGNJum0uCoLJQJLgiH0gMIMVsih3wT43bAOOYfDNDMfAPK1v5uOYgue +Nty2Wed93K/Sk2Q21zcXU74YMTpXnS2av5buWlwBXx0aBXkAGhfDRmMkcVvHzs4DY2DQ9jR+SPBz +X9JJ8ZKyY21XfTK35Wr0Pqju3adBB82f3lO1JenudY3ZJtqu+mVvytXofTu3adBB82f3lO1Jenud +Y3ZJtqu+mVvytXofTu3adBB82f3lO1JenudY3ZJtqu+mVvytXofTu3adBB82f3lO1JenudY3ZJtq +u+mVvytXofTu3adBB82f3lO1JenudY3ZJtqu+mVvytXofTu3adBB82f3lO1JenudY3ZJtqu+mVvy +tXofTu3adBB82f3lO1JenudY3ZJtqu+mVvytXofTu3adBB82f3lO1JenudY3ZJtqu+mVvytXofTu +3adBB82f3lO1JenudY3ZJtqu+mVvytXofTu3adBB82f3lO1JenudY3ZJtqu+mVvytXofTu3adBB8 +2f3lO1JenudY3ZJtqu+mVvytXofTu3adBB82f3lO1JenudY3ZJtqu+mVvytXofTu3adBB82f3lO1 +JenudY3ZJtqu+mVvytXofTu3adBB82f3lO1JenudY3ZJtqu+mVvytXofTu3adBB82f3lO1JenudY +3ZJtqu+mVvytXofTu3adBB82f3lO1JenudY3ZJtqu+mVvytXofTu3adBB82f3lO1JenudY3ZJtqu ++mVvytXofTu3adBB82f3lO1JenudY3ZJtqu+mVvytXofTu3adBB82f3lO1JenudY3ZL921XPTK55 +Wr0Przu1a9Db/Nn95TtSTwzXOtbsk21XPTK55Wp0Pp3ateht/mz+8r3tR/TXOtbsk21XPTK55Wp0 +Pp3ateht/mz+8p2o/prnWt2Sbarnplc8rU6H07tWvQ2/zZ/eU7Uf01zrW7JNtVz0yueVqdD6d2rX +obf5s/vKdqP6a51rdkm2q56ZXPK1Oh9O7Vr0Nv8ANn95TtR/TXOtbsk21XPTK55Wp0Pp3ateht/m +z+8p2o/prnWt2Sbarnplc8rU6H07tWvQ2/zZ/eU7Uf01zrW7JNtVz0yueVqdD6d2rXobf5s/vKdq +P6a51rdkm2q56ZXPK1Oh9O7Vr0Nv82f3lO1H9Nc61uyTbVc9MrnlanQ+ndq16G3+bP7ynaj+muda +3ZJtquemVzytTofTu1a9Db/Nn95TtR/TXOtbsk21XPTK55Wp0Pp3ateht/mz+8p2o/prnWt2Sbar +nplc8rU6H07tWvQ2/wA2f3lO1H9Nc61uyTbVc9MrnlanQ+ndq16G3+bP7ynaj+muda3ZJtquemVz +ytTofTu1a9Db/Nn95TtR/TXOtbsk21XPTK55Wp0Pp3ateht/mz+8p2o/prnWt2Sbarnplc8rU6H0 +7tWvQ2/zZ/eU7Uf01zrW7JNtVz0yueVqdD6d2rXobf5s/vKdqP6a51rdkm2q56ZXPK1Oh9O7Vr0N +v82f3lO1H9Nc61uyUaKLpUFjUloqTDhxSNYF9QDwP48czRLhb8XRxq8L/Rgmt5KMWEwsH9F7jZYb +mV93C99zK2A4pyqHL+Hc5kjjiBdEweiJAf8AOID/AG5pBT/sg8mkCoOb4evX3OcZbG6SUgSPPpua +76mUeCNp/HTl0V0ra5Xw5fVl/9Tv4oi0MaKPhUgL2Qxj+HzZrrJn1v6R/wBNy56f9X8hv0QspauK +lKIlESiJREoiURKIlESiJREoiURKIlESiJREoiURKIlESiJREoiURKIlESiJREoiURKIlESiJREo +iURKIlEUeg/FPoz9uLr/ACgawa1Djn+Gc1+Qz9ogWx8KfvzL/lv/AFMq3CVzwvsi/9Xv4oi0MaKP +hUgL2Qxj+HzZrrJn1v6R/wBNy56f9X8hv0QspauKlKIlESiJREoiURKIlESiJREoiURKIlESiJRE +oiURKIlESiJREoiURKIlESiJREoiURKIlESiJREoiURKIlEUeg/FPoz9uLr/ACgawa1Djn+Gc1+Q +z9ogWx8KfvzL/lv/AFMq3CVzwvsi/9bv4oi0MaKPhUgL2Qxj+HzZrrJn1v6R/wBNy56f9X8hv0Qs +pauKlKIlESiJREoiURKIlESiJREoiURKIlESiJREoiURKIlESiJREoiURKIlESiJREoiURKIlESi +JREoiURKIlEUeg/FPoz9uLr/ACgawa1Djn+Gc1+Qz9ogWx8KfvzL/lv/AFMq3CVzwvsi/9fv4oi0 +MaKPhUgL2Qxj+HzZrrJn1v6R/wBNy56f9X8hv0QspauKlKIlESiJREoiURKIqQuLie3U/lJS49kB +keSEsABLSFZeUzimvKxJCRk5ORkIkpK6keUldSALgglwBBMxBLWtb9t6rYwvLvSa1rWucS5zWNa1 +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 +rrJn1v6R/wBNy56f9X8hv0QspauKlKIlESiJREoiURKIqI4EXJdIlioKspoJwguthypayj4JQiim +LbPcqS7EM6XBXEtaRx+AWEUDLMMyUHCEDtljlje16qHNls0c0LZIJIpI3tcXAOZIx0bwSxzXCrXE +Va4EcoKpOMOjfHIWSsex7XChIcxwe00cHNNHNGggg+EK4drZz7xkl80tP/YnWvd0eDfutb66896W +Y7x8S7+l1dtsE2tnPvGSXzS0/wDYnTujwb91rfXXnvSd4+Jd/S6u22CbWzn3jJL5paf+xOndHg37 +rW+uvPek7x8S7+l1dtsE2tnPvGSXzS0/9idO6PBv3Wt9dee9J3j4l39Lq7bYJtbOfeMkvmlp/wCx +OndHg37rW+uvPek7x8S7+l1dtsE2tnPvGSXzS0/9idO6PBv3Wt9dee9J3j4l39Lq7bYJtbOfeMkv +mlp/7E6d0eDfutb66896TvHxLv6XV22wTa2c+8ZJfNLT/wBidO6PBv3Wt9dee9J3j4l39Lq7bYJt +bOfeMkvmlp/7E6d0eDfutb66896TvHxLv6XV22wTa2c+8ZJfNLT/ANidO6PBv3Wt9dee9J3j4l39 +Lq7bYJtbOfeMkvmlp/7E6d0eDfutb66896TvHxLv6XV22wTa2c+8ZJfNLT/2J07o8G/da311570n +ePiXf0urttgm1s594yS+aWn/ALE6d0eDfutb66896TvHxLv6XV22wTa2c+8ZJfNLT/2J07o8G/da +311570nePiXf0urttgm1s594yS+aWn/sTp3R4N+61vrrz3pO8fEu/pdXbbBNrZz7xkl80tP/AGJ0 +7o8G/da311570nePiXf0urttgm1s594yS+aWn/sTp3R4N+61vrrz3pO8fEu/pdXbbBNrZz7xkl80 +tP8A2J07o8G/da311570nePiXf0urttgm1s594yS+aWn/sTp3R4N+61vrrz3pO8fEu/pdXbbBNrZ +z7xkl80tP/YnTujwb91rfXXnvSd4+Jd/S6u22CbWzn3jJL5paf8AsTp3R4N+61vrrz3pO8fEu/pd +XbbBNrZz7xkl80tP/YnTujwb91rfXXnvSd4+Jd/S6u22CbWzn3jJL5paf+xOndHg37rW+uvPek7x +8S7+l1dtsE2tnPvGSXzS0/8AYnTujwb91rfXXnvSd4+Jd/S6u22CbWzn3jJL5paf+xOndHg37rW+ +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 +KdHiNLFcLBWK8ViJuFAiTcd5uVKRRCHJleIS6X8y8R+W/QmTdw0ArIZPwE62B7XLbMB+7gECiw5Y +0nYAQH7zLYwaC5EAEGc0Mnn3AACTv/mPQCsBAM2XpOMAALzoGFyolBdMxggAAESggSqwQQcMwRSs +wA6cwR28wBcCYQZEQAwkwDwQQgbkgBwKoRiWQRlUwDrYBLWwAxqgEZrhELTBMTgN5+ASXIHrcBcG +YBiewhi8hgkEQcgIE2EhOogRYo7YIs4IF5mOBCJhSDSSgKQg6YgUUSLFyHKkAqlCapFdSCPyLXIU +OY1cQPqQ28ggMor8irxHMZSBslED1AJ1QLmoHxqKxqBz0XQ0D12AlqJr0Rq0Hj2AtqKn0UvodXQA +fYqOY4DRMQ5mjNlhXIyHRWCJWBomxxZj5Vg1Vo81Yx1YN3YVG8CeYe8IJAKLgBPsCF6EEMJsgpCQ +R1hMWEOoJewjtBK6CFcJg4Qxwicik6hPtCV6EvnEeGI6sZBYRqwm7iEeIZ4lXicOE1+TSCQOyZLk +TgohJZAySQtJa0jbSC2kU6Q+0hBpnEwm65Btyd7kCLKArCCXkbeQD5BPkvvJw+S3FDrFiOJMCaIk +UqSUEko1ZT/lBKWfMkKZoKpRzame1AiqiDqfWkltoHZQL1OHqRM0dZolzZsWQ8ukLaPV0JppZ2n3 +aC/pdLoJ3YMeRZfQl9Jr6Afp5+mD9HcMDYYNg8dIYigZaxl7GacYtxkvmUymBdOXmchUMNcyG5ln +mA+Yb1VYKvYqfBWRyhKVOpVWlX6V56pUVXNVP9V5qgtUq1UPq15WfaZGVbNQ46kJ1Bar1akdVbup +Nq7OUndSj1DPUV+jvl/9gvpjDbKGhUaghkijVGO3xhmNIRbGMmXxWELWclYD6yxrmE1iW7L57Ex2 +Bfsbdi97TFNDc6pmrGaRZp3mcc0BDsax4PA52ZxKziHODc57LQMtPy2x1mqtZq1+rTfaetq+2mLt +cu0W7eva73VwnUCdLJ31Om0693UJuja6UbqFutt1z+o+02PreekJ9cr1Dund0Uf1bfSj9Rfq79bv +0R83MDQINpAZbDE4Y/DMkGPoa5hpuNHwhOGoEctoupHEaKPRSaMnuCbuh2fjNXgXPmasbxxirDTe +ZdxrPGFiaTLbpMSkxeS+Kc2Ua5pmutG003TMzMgs3KzYrMnsjjnVnGueYb7ZvNv8jYWlRZzFSos2 +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 +qX7Yxv3bP83/AGpe3P8AdKuOPcN5YHUP5rO+Fv8A1K0f2vjfu2f5v+1ZmY8WY2XY36L22kTz9GNV +JijIE2K0WZJAgUer0KSSSgZVJJJJKf/U9VTHhOkkpyrWnT4BC2laTsZrjrMR2UPszJiHfGVYGYAM +JxktDaUtpWgMZmntd96cYtcfnD5o+8Fe0XPDTIULarsinDom9lFdu/INLranOrFd7WtbdjbHu/WH +4ztjbPzFp/ZW6RPOsmUapgrrawdkyeQSFUuhAg24+b9ur6f9n6Yb2WsdX6djxZa8MFjbLd78re63 +dSHs/SWKli3/AFmFvTnWsvdTXTWzN3bA51hdsvfYz0W/Qb+m/V/53+bq9HfauoSUfEOy6j3aAybd +7SWW7dQ72P77f5K5yn/ntYLftD7a5aTVtawe53r3DVrMr21v+z0+/wDwf5n/AGop7JJEyB/RVwnu +5tGRltx6m3ix1wY0WuDHQXx7zpXX+d/wbET7Tb+5Z/mP/wDIq8klxj91XCe7QdkXFrgGWAkED2P/ +APIqjmtc+jLdBG5thg6HVvgVuoFmM14eD+fM/MJ0cgHSlsoE9bTpJJKJkUkkkkp//9X1VJfKqSSn +6qSXyqkkp+qkl8qpJKfqpJfKqSSn6qSXyqkkp+qkl8qpJKfqpJfKqSSn6qSXyqkkp+qkl8qpJKfq +pJfKqSSn/9n/7RW6UGhvdG9zaG9wIDMuMAA4QklNBCUAAAAAABAAAAAAAAAAAAAAAAAAAAAAOEJJ +TQQ6AAAAAACTAAAAEAAAAAEAAAAAAAtwcmludE91dHB1dAAAAAUAAAAAQ2xyU2VudW0AAAAAQ2xy +UwAAAABSR0JDAAAAAEludGVlbnVtAAAAAEludGUAAAAASW1nIAAAAABNcEJsYm9vbAEAAAAPcHJp +bnRTaXh0ZWVuQml0Ym9vbAAAAAALcHJpbnRlck5hbWVURVhUAAAAAQAAADhCSU0EOwAAAAABsgAA +ABAAAAABAAAAAAAScHJpbnRPdXRwdXRPcHRpb25zAAAAEgAAAABDcHRuYm9vbAAAAAAAQ2xicmJv +b2wAAAAAAFJnc01ib29sAAAAAABDcm5DYm9vbAAAAAAAQ250Q2Jvb2wAAAAAAExibHNib29sAAAA +AABOZ3R2Ym9vbAAAAAAARW1sRGJvb2wAAAAAAEludHJib29sAAAAAABCY2tnT2JqYwAAAAEAAAAA +AABSR0JDAAAAAwAAAABSZCAgZG91YkBv4AAAAAAAAAAAAEdybiBkb3ViQG/gAAAAAAAAAAAAQmwg +IGRvdWJAb+AAAAAAAAAAAABCcmRUVW50RiNSbHQAAAAAAAAAAAAAAABCbGQgVW50RiNSbHQAAAAA +AAAAAAAAAABSc2x0VW50RiNQeGxAUgAAAAAAAAAAAAp2ZWN0b3JEYXRhYm9vbAEAAAAAUGdQc2Vu +dW0AAAAAUGdQcwAAAABQZ1BDAAAAAExlZnRVbnRGI1JsdAAAAAAAAAAAAAAAAFRvcCBVbnRGI1Js +dAAAAAAAAAAAAAAAAFNjbCBVbnRGI1ByY0BZAAAAAAAAOEJJTQPtAAAAAAAQAEgAAAABAAIASAAA +AAEAAjhCSU0EJgAAAAAADgAAAAAAAAAAAAA/gAAAOEJJTQQNAAAAAAAEAAAAeDhCSU0EGQAAAAAA +BAAAAB44QklNA/MAAAAAAAkAAAAAAAAAAAEAOEJJTScQAAAAAAAKAAEAAAAAAAAAAjhCSU0D9QAA +AAAASAAvZmYAAQBsZmYABgAAAAAAAQAvZmYAAQChmZoABgAAAAAAAQAyAAAAAQBaAAAABgAAAAAA +AQA1AAAAAQAtAAAABgAAAAAAAThCSU0D+AAAAAAAcAAA/////////////////////////////wPo +AAAAAP////////////////////////////8D6AAAAAD/////////////////////////////A+gA +AAAA/////////////////////////////wPoAAA4QklNBAAAAAAAAAIAAThCSU0EAgAAAAAACAAA +AAAAAAAAOEJJTQQwAAAAAAAEAQEBAThCSU0ELQAAAAAABgABAAAADjhCSU0ECAAAAAAAEAAAAAEA +AAJAAAACQAAAAAA4QklNBB4AAAAAAAQAAAAAOEJJTQQaAAAAAAM/AAAABgAAAAAAAAAAAAABCwAA +AZ0AAAAFZypoB5iYAC0AMQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAABnQAAAQsA +AAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAQAAAAAAAG51bGwAAAACAAAA +BmJvdW5kc09iamMAAAABAAAAAAAAUmN0MQAAAAQAAAAAVG9wIGxvbmcAAAAAAAAAAExlZnRsb25n +AAAAAAAAAABCdG9tbG9uZwAAAQsAAAAAUmdodGxvbmcAAAGdAAAABnNsaWNlc1ZsTHMAAAABT2Jq +YwAAAAEAAAAAAAVzbGljZQAAABIAAAAHc2xpY2VJRGxvbmcAAAAAAAAAB2dyb3VwSURsb25nAAAA +AAAAAAZvcmlnaW5lbnVtAAAADEVTbGljZU9yaWdpbgAAAA1hdXRvR2VuZXJhdGVkAAAAAFR5cGVl +bnVtAAAACkVTbGljZVR5cGUAAAAASW1nIAAAAAZib3VuZHNPYmpjAAAAAQAAAAAAAFJjdDEAAAAE +AAAAAFRvcCBsb25nAAAAAAAAAABMZWZ0bG9uZwAAAAAAAAAAQnRvbWxvbmcAAAELAAAAAFJnaHRs +b25nAAABnQAAAAN1cmxURVhUAAAAAQAAAAAAAG51bGxURVhUAAAAAQAAAAAAAE1zZ2VURVhUAAAA +AQAAAAAABmFsdFRhZ1RFWFQAAAABAAAAAAAOY2VsbFRleHRJc0hUTUxib29sAQAAAAhjZWxsVGV4 +dFRFWFQAAAABAAAAAAAJaG9yekFsaWduZW51bQAAAA9FU2xpY2VIb3J6QWxpZ24AAAAHZGVmYXVs +dAAAAAl2ZXJ0QWxpZ25lbnVtAAAAD0VTbGljZVZlcnRBbGlnbgAAAAdkZWZhdWx0AAAAC2JnQ29s +b3JUeXBlZW51bQAAABFFU2xpY2VCR0NvbG9yVHlwZQAAAABOb25lAAAACXRvcE91dHNldGxvbmcA +AAAAAAAACmxlZnRPdXRzZXRsb25nAAAAAAAAAAxib3R0b21PdXRzZXRsb25nAAAAAAAAAAtyaWdo +dE91dHNldGxvbmcAAAAAADhCSU0EKAAAAAAADAAAAAI/8AAAAAAAADhCSU0EFAAAAAAABAAAABI4 +QklNBAwAAAAADXgAAAABAAAAoAAAAGcAAAHgAADBIAAADVwAGAAB/9j/7QAMQWRvYmVfQ00AAf/u +AA5BZG9iZQBkgAAAAAH/2wCEAAwICAgJCAwJCQwRCwoLERUPDAwPFRgTExUTExgRDAwMDAwMEQwM +DAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwBDQsLDQ4NEA4OEBQODg4UFA4ODg4UEQwMDAwMEREM +DAwMDAwRDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDP/AABEIAGcAoAMBIgACEQEDEQH/3QAE +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 +vhb/ANStH9r437tn+b/tWZmPFmNl2N+i9tpE8/RjVSYoyBNitFmSQIFHq9CkkkoGVSSSSSn/1PVU +x4TpJKcq1p0+AQtpWk7Ga46zEdlD7MyYh3xlWBmADCcZLQ2lLaVoDGZp7XfenGLXH5w+aPvBXtFz +w0yFC2q7Ipw6JvZRXbvyDS62pzqxXe1rW3Y2x7v1h+M7Y2z8xaf2VukTzrJlGqYK62sHZMnkEhVL +oQINuPm/bq+n/Z+mG9lrHV+nY8WWvDBY2y3e/K3ut3Uh7P0lipYt/wBZhb051rL3U101szd2wOdY +XbL32M9Fv0G/pv1f+d/m6vR32rqElHxDsuo92gMm3e0llu3UO9j++3+Sucp/57WC37Q+2uWk1bWs +Hud69w1azK9tb/s9Pv8A8H+Z/wBqKeySRMgf0VcJ7ubRkZbcept4sdcGNFrgx0F8e86V1/nf8GxE ++02/uWf5j/8AyKvJJcY/dVwnu0HZFxa4BlgJBA9j/wDyKo5rXPoy3QRubYYOh1b4FbqBZjNeHg/n +zPzCdHIB0pbKBPW06SSSiZFJJJJKf//V9VSXyqkkp+qkl8qpJKfqpJfKqSSn6qSXyqkkp+qkl8qp +JKfqpJfKqSSn6qSXyqkkp+qkl8qpJKfqpJfKqSSn6qSXyqkkp//ZOEJJTQQhAAAAAABVAAAAAQEA +AAAPAEEAZABvAGIAZQAgAFAAaABvAHQAbwBzAGgAbwBwAAAAEwBBAGQAbwBiAGUAIABQAGgAbwB0 +AG8AcwBoAG8AcAAgAEMAUwA1AAAAAQA4QklNBAYAAAAAAAcACAABAAEBAP/hDlxodHRwOi8vbnMu +YWRvYmUuY29tL3hhcC8xLjAvADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6 +cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1w +dGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjow +MCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAy +LzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6 +eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25z +LmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20v +eGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMu +YWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2Vs +ZW1lbnRzLzEuMS8iIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBXaW5kb3dz +IiB4bXA6Q3JlYXRlRGF0ZT0iMjAxMC0wOC0zMVQwMTo0MzoyNSswODowMCIgeG1wOk1ldGFkYXRh +RGF0ZT0iMjAxMC0wOC0zMVQwMTo0MzoyNSswODowMCIgeG1wOk1vZGlmeURhdGU9IjIwMTAtMDgt +MzFUMDE6NDM6MjUrMDg6MDAiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6Mjc4QUVGRDc1Q0I0 +REYxMUJFN0VCMjM3Mjk0MkY3NDkiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MjY4QUVGRDc1 +Q0I0REYxMUJFN0VCMjM3Mjk0MkY3NDkiIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRp +ZDoyNjhBRUZENzVDQjRERjExQkU3RUIyMzcyOTQyRjc0OSIgcGhvdG9zaG9wOkNvbG9yTW9kZT0i +MyIgcGhvdG9zaG9wOklDQ1Byb2ZpbGU9InNSR0IgSUVDNjE5NjYtMi4xIiBkYzpmb3JtYXQ9Imlt +YWdlL2pwZWciPiA8eG1wTU06SGlzdG9yeT4gPHJkZjpTZXE+IDxyZGY6bGkgc3RFdnQ6YWN0aW9u +PSJjcmVhdGVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOjI2OEFFRkQ3NUNCNERGMTFCRTdF +QjIzNzI5NDJGNzQ5IiBzdEV2dDp3aGVuPSIyMDEwLTA4LTMxVDAxOjQzOjI1KzA4OjAwIiBzdEV2 +dDpzb2Z0d2FyZUFnZW50PSJBZG9iZSBQaG90b3Nob3AgQ1M1IFdpbmRvd3MiLz4gPHJkZjpsaSBz +dEV2dDphY3Rpb249InNhdmVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOjI3OEFFRkQ3NUNC +NERGMTFCRTdFQjIzNzI5NDJGNzQ5IiBzdEV2dDp3aGVuPSIyMDEwLTA4LTMxVDAxOjQzOjI1KzA4 +OjAwIiBzdEV2dDpzb2Z0d2FyZUFnZW50PSJBZG9iZSBQaG90b3Nob3AgQ1M1IFdpbmRvd3MiIHN0 +RXZ0OmNoYW5nZWQ9Ii8iLz4gPC9yZGY6U2VxPiA8L3htcE1NOkhpc3Rvcnk+IDxwaG90b3Nob3A6 +RG9jdW1lbnRBbmNlc3RvcnM+IDxyZGY6QmFnPiA8cmRmOmxpPnhtcC5kaWQ6NTQ0RTcwQzA1N0I0 +REYxMUJFN0VCMjM3Mjk0MkY3NDk8L3JkZjpsaT4gPC9yZGY6QmFnPiA8L3Bob3Rvc2hvcDpEb2N1 +bWVudEFuY2VzdG9ycz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+ +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPD94 +cGFja2V0IGVuZD0idyI/Pv/iDFhJQ0NfUFJPRklMRQABAQAADEhMaW5vAhAAAG1udHJSR0IgWFla +IAfOAAIACQAGADEAAGFjc3BNU0ZUAAAAAElFQyBzUkdCAAAAAAAAAAAAAAAAAAD21gABAAAAANMt +SFAgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEWNwcnQA +AAFQAAAAM2Rlc2MAAAGEAAAAbHd0cHQAAAHwAAAAFGJrcHQAAAIEAAAAFHJYWVoAAAIYAAAAFGdY +WVoAAAIsAAAAFGJYWVoAAAJAAAAAFGRtbmQAAAJUAAAAcGRtZGQAAALEAAAAiHZ1ZWQAAANMAAAA +hnZpZXcAAAPUAAAAJGx1bWkAAAP4AAAAFG1lYXMAAAQMAAAAJHRlY2gAAAQwAAAADHJUUkMAAAQ8 +AAAIDGdUUkMAAAQ8AAAIDGJUUkMAAAQ8AAAIDHRleHQAAAAAQ29weXJpZ2h0IChjKSAxOTk4IEhl +d2xldHQtUGFja2FyZCBDb21wYW55AABkZXNjAAAAAAAAABJzUkdCIElFQzYxOTY2LTIuMQAAAAAA +AAAAAAAAEnNSR0IgSUVDNjE5NjYtMi4xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAABYWVogAAAAAAAA81EAAQAAAAEWzFhZWiAAAAAAAAAAAAAAAAAAAAAA +WFlaIAAAAAAAAG+iAAA49QAAA5BYWVogAAAAAAAAYpkAALeFAAAY2lhZWiAAAAAAAAAkoAAAD4QA +ALbPZGVzYwAAAAAAAAAWSUVDIGh0dHA6Ly93d3cuaWVjLmNoAAAAAAAAAAAAAAAWSUVDIGh0dHA6 +Ly93d3cuaWVjLmNoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AGRlc2MAAAAAAAAALklFQyA2MTk2Ni0yLjEgRGVmYXVsdCBSR0IgY29sb3VyIHNwYWNlIC0gc1JH +QgAAAAAAAAAAAAAALklFQyA2MTk2Ni0yLjEgRGVmYXVsdCBSR0IgY29sb3VyIHNwYWNlIC0gc1JH +QgAAAAAAAAAAAAAAAAAAAAAAAAAAAABkZXNjAAAAAAAAACxSZWZlcmVuY2UgVmlld2luZyBDb25k +aXRpb24gaW4gSUVDNjE5NjYtMi4xAAAAAAAAAAAAAAAsUmVmZXJlbmNlIFZpZXdpbmcgQ29uZGl0 +aW9uIGluIElFQzYxOTY2LTIuMQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdmlldwAAAAAAE6T+ +ABRfLgAQzxQAA+3MAAQTCwADXJ4AAAABWFlaIAAAAAAATAlWAFAAAABXH+dtZWFzAAAAAAAAAAEA +AAAAAAAAAAAAAAAAAAAAAAACjwAAAAJzaWcgAAAAAENSVCBjdXJ2AAAAAAAABAAAAAAFAAoADwAU +ABkAHgAjACgALQAyADcAOwBAAEUASgBPAFQAWQBeAGMAaABtAHIAdwB8AIEAhgCLAJAAlQCaAJ8A +pACpAK4AsgC3ALwAwQDGAMsA0ADVANsA4ADlAOsA8AD2APsBAQEHAQ0BEwEZAR8BJQErATIBOAE+ +AUUBTAFSAVkBYAFnAW4BdQF8AYMBiwGSAZoBoQGpAbEBuQHBAckB0QHZAeEB6QHyAfoCAwIMAhQC +HQImAi8COAJBAksCVAJdAmcCcQJ6AoQCjgKYAqICrAK2AsECywLVAuAC6wL1AwADCwMWAyEDLQM4 +A0MDTwNaA2YDcgN+A4oDlgOiA64DugPHA9MD4APsA/kEBgQTBCAELQQ7BEgEVQRjBHEEfgSMBJoE +qAS2BMQE0wThBPAE/gUNBRwFKwU6BUkFWAVnBXcFhgWWBaYFtQXFBdUF5QX2BgYGFgYnBjcGSAZZ +BmoGewaMBp0GrwbABtEG4wb1BwcHGQcrBz0HTwdhB3QHhgeZB6wHvwfSB+UH+AgLCB8IMghGCFoI +bgiCCJYIqgi+CNII5wj7CRAJJQk6CU8JZAl5CY8JpAm6Cc8J5Qn7ChEKJwo9ClQKagqBCpgKrgrF +CtwK8wsLCyILOQtRC2kLgAuYC7ALyAvhC/kMEgwqDEMMXAx1DI4MpwzADNkM8w0NDSYNQA1aDXQN +jg2pDcMN3g34DhMOLg5JDmQOfw6bDrYO0g7uDwkPJQ9BD14Peg+WD7MPzw/sEAkQJhBDEGEQfhCb +ELkQ1xD1ERMRMRFPEW0RjBGqEckR6BIHEiYSRRJkEoQSoxLDEuMTAxMjE0MTYxODE6QTxRPlFAYU +JxRJFGoUixStFM4U8BUSFTQVVhV4FZsVvRXgFgMWJhZJFmwWjxayFtYW+hcdF0EXZReJF64X0hf3 +GBsYQBhlGIoYrxjVGPoZIBlFGWsZkRm3Gd0aBBoqGlEadxqeGsUa7BsUGzsbYxuKG7Ib2hwCHCoc +Uhx7HKMczBz1HR4dRx1wHZkdwx3sHhYeQB5qHpQevh7pHxMfPh9pH5Qfvx/qIBUgQSBsIJggxCDw +IRwhSCF1IaEhziH7IiciVSKCIq8i3SMKIzgjZiOUI8Ij8CQfJE0kfCSrJNolCSU4JWgllyXHJfcm +JyZXJocmtyboJxgnSSd6J6sn3CgNKD8ocSiiKNQpBik4KWspnSnQKgIqNSpoKpsqzysCKzYraSud +K9EsBSw5LG4soizXLQwtQS12Last4S4WLkwugi63Lu4vJC9aL5Evxy/+MDUwbDCkMNsxEjFKMYIx +ujHyMioyYzKbMtQzDTNGM38zuDPxNCs0ZTSeNNg1EzVNNYc1wjX9Njc2cjauNuk3JDdgN5w31zgU +OFA4jDjIOQU5Qjl/Obw5+To2OnQ6sjrvOy07azuqO+g8JzxlPKQ84z0iPWE9oT3gPiA+YD6gPuA/ +IT9hP6I/4kAjQGRApkDnQSlBakGsQe5CMEJyQrVC90M6Q31DwEQDREdEikTORRJFVUWaRd5GIkZn +RqtG8Ec1R3tHwEgFSEtIkUjXSR1JY0mpSfBKN0p9SsRLDEtTS5pL4kwqTHJMuk0CTUpNk03cTiVO +bk63TwBPSU+TT91QJ1BxULtRBlFQUZtR5lIxUnxSx1MTU19TqlP2VEJUj1TbVShVdVXCVg9WXFap +VvdXRFeSV+BYL1h9WMtZGllpWbhaB1pWWqZa9VtFW5Vb5Vw1XIZc1l0nXXhdyV4aXmxevV8PX2Ff +s2AFYFdgqmD8YU9homH1YklinGLwY0Njl2PrZEBklGTpZT1lkmXnZj1mkmboZz1nk2fpaD9olmjs +aUNpmmnxakhqn2r3a09rp2v/bFdsr20IbWBtuW4SbmtuxG8eb3hv0XArcIZw4HE6cZVx8HJLcqZz +AXNdc7h0FHRwdMx1KHWFdeF2Pnabdvh3VnezeBF4bnjMeSp5iXnnekZ6pXsEe2N7wnwhfIF84X1B +faF+AX5ifsJ/I3+Ef+WAR4CogQqBa4HNgjCCkoL0g1eDuoQdhICE44VHhauGDoZyhteHO4efiASI +aYjOiTOJmYn+imSKyoswi5aL/IxjjMqNMY2Yjf+OZo7OjzaPnpAGkG6Q1pE/kaiSEZJ6kuOTTZO2 +lCCUipT0lV+VyZY0lp+XCpd1l+CYTJi4mSSZkJn8mmia1ZtCm6+cHJyJnPedZJ3SnkCerp8dn4uf ++qBpoNihR6G2oiailqMGo3aj5qRWpMelOKWpphqmi6b9p26n4KhSqMSpN6mpqhyqj6sCq3Wr6axc +rNCtRK24ri2uoa8Wr4uwALB1sOqxYLHWskuywrM4s660JbSctRO1irYBtnm28Ldot+C4WbjRuUq5 +wro7urW7LrunvCG8m70VvY++Cr6Evv+/er/1wHDA7MFnwePCX8Lbw1jD1MRRxM7FS8XIxkbGw8dB +x7/IPci8yTrJuco4yrfLNsu2zDXMtc01zbXONs62zzfPuNA50LrRPNG+0j/SwdNE08bUSdTL1U7V +0dZV1tjXXNfg2GTY6Nls2fHadtr724DcBdyK3RDdlt4c3qLfKd+v4DbgveFE4cziU+Lb42Pj6+Rz +5PzlhOYN5pbnH+ep6DLovOlG6dDqW+rl63Dr++yG7RHtnO4o7rTvQO/M8Fjw5fFy8f/yjPMZ86f0 +NPTC9VD13vZt9vv3ivgZ+Kj5OPnH+lf65/t3/Af8mP0p/br+S/7c/23////uAA5BZG9iZQBkQAAA +AAH/2wCEAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQECAgICAgIC +AgICAgMDAwMDAwMDAwMBAQEBAQEBAQEBAQICAQICAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMD +AwMDAwMDAwMDAwMDAwMDAwMDAwMDA//AABEIAQsBnQMBEQACEQEDEQH/3QAEADT/xAEKAAEAAQMF +AQAAAAAAAAAAAAAABwUGCAEDBAkKAgEBAAEFAQEBAAAAAAAAAAAAAAUBAwQGBwIICRAAAAUDAQEG +CRIPCQoHEQAAAwQFBgcAAQIIESESFhdXCTETFFQVl9cYmEFRYXGBkaEi0pPUVdVWltZ32MHRMlKS +Y5S0NZW2Nzi4GfCx4SN0dXa3ePFCcoKyU7MktTbDRCVmJ0dnosIzZEVlpcUmRqbGh8dZeQoRAAED +AgIDBwsMDwYFBQEBAAEAAgMRBBIFIRMGMVPTFJQVFkFRYZEiktIjk9QHcdEyUnOzJFR0tFVWgaGx +wWJysqPjNZXVNhcYQoIzYzRk8IOkZQjhosMlRUNE/9oADAMBAAIRAxEAPwD38URKIlESiJREoiUR +KIlESiJREoiURKIlESiJREoiURKIlESiJREoiURKIlESiJREoiURKIlESiJREoiURKIlESiJREoi +URKIlESiJREoiURKIlESiL//0PfxREoiURKIlESiJREoiURKIlESiJREoiURKIlESiJREoiURKIl +ESiJREoiURKIlESiJREoiURKIlESiJREoiURKIlESiJREoiURKIlESiJREoiURKIv//R9/FESiLj +GQsRML2yyGxte190IwOBf7IEQPK1e2bq8lRwvtlPO452GUXcDt2/g1+PhJvu/W3SnCTvj5l9ypO2 +0kdzH9ljD90FYMx0br/sOcPuFQQ4IrbBzLO4zqm8DfXve/Y7UfqHSbW/wbJUnE7YeZsrYrZhIHir +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 +jM+XDzxOLWfOTrV34WxX52dOf/Rz8ZyX9mO/d6c0ba7xmfLh54nFrPnJ1q78LYr87OnP/o5+M5L+ +zHfu9OaNtd4zPlw88Ti1nzk61d+FsV+dnTn/ANHPxnJf2Y793pzRtrvGZ8uHnicWs+cnWrvwtivz +s6c/+jn4zkv7Md+705o213jM+XDzxOLWfOTrV34WxX52dOf/AEc/Gcl/Zjv3enNG2u8Zny4eeJxa +z5ydau/C2K/Ozpz/AOjn4zkv7Md+705o213jM+XDzxOLWfOTrV34WxX52dOf/Rz8ZyX9mO/d6c0b +a7xmfLh54nFrPnJ1q78LYr87OnP/AKOfjOS/sx37vTmjbXeMz5cPPE4tZ85OtXfhbFfnZ05/9HPx +nJf2Y793pzRtrvGZ8uHnicWs+cnWrvwtivzs6c/+jn4zkv7Md+705o213jM+XDzxOLWfOTrV34Wx +X52dOf8A0c/Gcl/Zjv3enNG2u8Zny4eeJxaz5ydau/C2K/Ozpz/6OfjOS/sx37vTmjbXeMz5cPPE +4tZ85OtXfhbFfnZ05/8ARz8ZyX9mO/d6c0ba7xmfLh54nFrPnJ1q78LYr87OnP8A6OfjOS/sx37v +TmjbXeMz5cPPE4tZ85OtXfhbFfnZ05/9HPxnJf2Y793pzRtrvGZ8uHnicWs+cnWrvwtivzs6c/8A +o5+M5L+zHfu9OaNtd4zPlw88VIaJTJNUn6lKKA+G87U13FAHuWkR4cPHMaXTDFZSimnTDos+JCwU +SuTMPJQQNsVLKwOAXSul4Xwva+yxTWdzY5dcZbLA/K3xO1Wpi1MYaJZWuAj1UJadaJCe4FScVTWq +g5IrmC6vYb6OVt+141msk1ryTGwtJfjkr4ssA7o0ApQUVzK34KUv5vOfewlEG6FP/N/fo24/2gNZ +f6489V867cfxNf8A4kHzeJdm2W/Udp+NL79Is061NbClESiJREoiURKIlESiJRF//9H38URKIlES +iJRFiMrY+nXNnvset7+a7lu9deyY/B7L3CL3tq5zmY8dc+6yfluUUKePpsv3blb5aHQFqVwO6KtY +W27f93iVLs6ij3bq42yrqt0KURNlEoUolCmyiUPWWuy9UVaFabKqqUPWTZRKFa7L1SqUKbL+NSqU +KvOAD3Y2UpoH+vYEBBdHZ0XFqMz6P+JWj+kC341abNR9aS9P2rEffW17HTcXuM8f12Wo+3deso45 +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 +REoiURKIlESiJREoi4ly2OQguey20TPHK/k3sGGH43jYVdbIQ1o6ytlgJJotMiuN7Xts6Ntletae +uqasdZfZQDEuD0rG2y3TjImzyRjAo2V/NyEq044nEq40UFFya8qqURKIlESiJREoiURKIlEX/9b3 +8URKIlESiJRFpstRUoE3ttt9zo7PQ2/TqtUomy3jWpU9dVotN7bba+y25a9rbnj3te/71KlKLS+G +N7Xte1r762y99ltt7bu5t82qVRadLttvfZbbe9t3Z6a2zba2y+3c2WvfyN2/j3oi+t7jt27Lbdmy ++50bbdtvOpU9dEthja+21tnn7N3xrdC3RoibzHcvs3bbdl/F3ej59EWt7Wvs22tfZ0PG87yKItaI +lEWmz93oUSi1oiURKIlESiJREoiURKIlESiJREoiURKIlESiJREoiURKIlESiJREoiURKIlESiJR +EoiURKIlEX//1/fxREoiURKIlESiJREoiURKIlESiJREoiURKIlESiJREoiURKIlESiJREoiURKI +lESiJREoiURKIlESiJREoiURKIlESiJREoiURKIlESiJREoiURKIv//Q9/FESiJREoiURKIlESiJ +REoiURKIlESiJREoiURKIlESiJREoiURKIlESiJREoiURKIlESiJREoiURKIlESiJREoiURKIlES +iJREoiURKIlESiJREoi//9lQSwMECgAAAAAAAAAhAO2ESGznUQAA51EAABcAAAB3b3JkL21lZGlh +L2ltYWdlMTAuanBlZ//Y/+AAEEpGSUYAAQIBAEgASAAA/+ELfkV4aWYAAE1NACoAAAAIAAcBEgAD +AAAAAQABAAABGgAFAAAAAQAAAGIBGwAFAAAAAQAAAGoBKAADAAAAAQACAAABMQACAAAAFAAAAHIB +MgACAAAAFAAAAIaHaQAEAAAAAQAAAJwAAADIAAAASAAAAAEAAABIAAAAAUFkb2JlIFBob3Rvc2hv +cCA3LjAAMjAxMDowNjowMSAxODoxMDozNQAAAAADoAEAAwAAAAH//wAAoAIABAAAAAEAAACcoAMA +BAAAAAEAAABGAAAAAAAAAAYBAwADAAAAAQAGAAABGgAFAAAAAQAAARYBGwAFAAAAAQAAAR4BKAAD +AAAAAQACAAACAQAEAAAAAQAAASYCAgAEAAAAAQAAClAAAAAAAAAASAAAAAEAAABIAAAAAf/Y/+AA +EEpGSUYAAQIBAEgASAAA/+0ADEFkb2JlX0NNAAL/7gAOQWRvYmUAZIAAAAAB/9sAhAAMCAgICQgM +CQkMEQsKCxEVDwwMDxUYExMVExMYEQwMDAwMDBEMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwM +AQ0LCw0ODRAODhAUDg4OFBQODg4OFBEMDAwMDBERDAwMDAwMEQwMDAwMDAwMDAwMDAwMDAwMDAwM +DAwMDAwMDAz/wAARCAA5AIADASIAAhEBAxEB/90ABAAI/8QBPwAAAQUBAQEBAQEAAAAAAAAAAwAB +AgQFBgcICQoLAQABBQEBAQEBAQAAAAAAAAABAAIDBAUGBwgJCgsQAAEEAQMCBAIFBwYIBQMMMwEA +AhEDBCESMQVBUWETInGBMgYUkaGxQiMkFVLBYjM0coLRQwclklPw4fFjczUWorKDJkSTVGRFwqN0 +NhfSVeJl8rOEw9N14/NGJ5SkhbSVxNTk9KW1xdXl9VZmdoaWprbG1ub2N0dXZ3eHl6e3x9fn9xEA +AgIBAgQEAwQFBgcHBgU1AQACEQMhMRIEQVFhcSITBTKBkRShsUIjwVLR8DMkYuFygpJDUxVjczTx +JQYWorKDByY1wtJEk1SjF2RFVTZ0ZeLys4TD03Xj80aUpIW0lcTU5PSltcXV5fVWZnaGlqa2xtbm +9ic3R1dnd4eXp7fH/9oADAMBAAIRAxEAPwD1VMeFndZ6/wBO6Lji7Os2l8+lSz3WWEciqv8A7+79 +GuE6p/jF6xlEs6exuBV2cQLbT/af+hZ/23/1xMnkjHc69g2+V5DmOZ1xxqH+cn6Yf+hf4D6TZayp +hsse2tjeXOIAH9p0LIyvrl9WcUkWdQqe4ctqm3/zwLF5PlZWVmv9TMvsyX8h1zi+P6u72tQgABHZ +QnmT0H2upi+AwH87lJ8MY4f+dLi/6L6Xb/jK6AzRlWVd5traB/4LZWhj/Gd0WQDi5gHjtqP/AKPX +nCSb78/D7GyPgvJ1tM/4T630z659A6nY2mnJ9K9+jab2mtxJ4axzv0T3fyWWLcC8IIaRDhIPZer/ +AFH6lkdQ+r9Lsl5sux3ux32OMuds/m3OP5zvScz3KXFlMzR3q9HM+JfDI8tAZcciYE8JjLeJPi9C +kkkpnKUkkkkpSSSSSlJJJJKf/9CP1+fa/wCtOQ10kV10sqHPtLd21n/XXvWZ+wuvf+VmZ/2w/wD8 +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 +QklNBA0AAAAAAAQAAAB4OEJJTQQZAAAAAAAEAAAAHjhCSU0D8wAAAAAACQAAAAAAAAAAAQA4QklN +BAoAAAAAAAEAADhCSU0nEAAAAAAACgABAAAAAAAAAAI4QklNA/UAAAAAAEgAL2ZmAAEAbGZmAAYA +AAAAAAEAL2ZmAAEAoZmaAAYAAAAAAAEAMgAAAAEAWgAAAAYAAAAAAAEANQAAAAEALQAAAAYAAAAA +AAE4QklNA/gAAAAAAHAAAP////////////////////////////8D6AAAAAD///////////////// +////////////A+gAAAAA/////////////////////////////wPoAAAAAP////////////////// +//////////8D6AAAOEJJTQQAAAAAAAACAAI4QklNBAIAAAAAAAYAAAAAAAA4QklNBAgAAAAAABAA +AAABAAACQAAAAkAAAAAAOEJJTQQeAAAAAAAEAAAAADhCSU0EGgAAAAADPQAAAAYAAAAAAAAAAAAA +AEYAAACcAAAABABzAHMAcwBzAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAACcAAAA +RgAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAABAAAAABAAAAAAAAbnVsbAAAAAIA +AAAGYm91bmRzT2JqYwAAAAEAAAAAAABSY3QxAAAABAAAAABUb3AgbG9uZwAAAAAAAAAATGVmdGxv +bmcAAAAAAAAAAEJ0b21sb25nAAAARgAAAABSZ2h0bG9uZwAAAJwAAAAGc2xpY2VzVmxMcwAAAAFP +YmpjAAAAAQAAAAAABXNsaWNlAAAAEgAAAAdzbGljZUlEbG9uZwAAAAAAAAAHZ3JvdXBJRGxvbmcA +AAAAAAAABm9yaWdpbmVudW0AAAAMRVNsaWNlT3JpZ2luAAAADWF1dG9HZW5lcmF0ZWQAAAAAVHlw +ZWVudW0AAAAKRVNsaWNlVHlwZQAAAABJbWcgAAAABmJvdW5kc09iamMAAAABAAAAAAAAUmN0MQAA +AAQAAAAAVG9wIGxvbmcAAAAAAAAAAExlZnRsb25nAAAAAAAAAABCdG9tbG9uZwAAAEYAAAAAUmdo +dGxvbmcAAACcAAAAA3VybFRFWFQAAAABAAAAAAAAbnVsbFRFWFQAAAABAAAAAAAATXNnZVRFWFQA +AAABAAAAAAAGYWx0VGFnVEVYVAAAAAEAAAAAAA5jZWxsVGV4dElzSFRNTGJvb2wBAAAACGNlbGxU +ZXh0VEVYVAAAAAEAAAAAAAlob3J6QWxpZ25lbnVtAAAAD0VTbGljZUhvcnpBbGlnbgAAAAdkZWZh +dWx0AAAACXZlcnRBbGlnbmVudW0AAAAPRVNsaWNlVmVydEFsaWduAAAAB2RlZmF1bHQAAAALYmdD +b2xvclR5cGVlbnVtAAAAEUVTbGljZUJHQ29sb3JUeXBlAAAAAE5vbmUAAAAJdG9wT3V0c2V0bG9u +ZwAAAAAAAAAKbGVmdE91dHNldGxvbmcAAAAAAAAADGJvdHRvbU91dHNldGxvbmcAAAAAAAAAC3Jp +Z2h0T3V0c2V0bG9uZwAAAAAAOEJJTQQRAAAAAAABAQA4QklNBBQAAAAAAAQAAAADOEJJTQQMAAAA +AApsAAAAAQAAAIAAAAA5AAABgAAAVYAAAApQABgAAf/Y/+AAEEpGSUYAAQIBAEgASAAA/+0ADEFk +b2JlX0NNAAL/7gAOQWRvYmUAZIAAAAAB/9sAhAAMCAgICQgMCQkMEQsKCxEVDwwMDxUYExMVExMY +EQwMDAwMDBEMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMAQ0LCw0ODRAODhAUDg4OFBQODg4O +FBEMDAwMDBERDAwMDAwMEQwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCAA5AIADASIA +AhEBAxEB/90ABAAI/8QBPwAAAQUBAQEBAQEAAAAAAAAAAwABAgQFBgcICQoLAQABBQEBAQEBAQAA +AAAAAAABAAIDBAUGBwgJCgsQAAEEAQMCBAIFBwYIBQMMMwEAAhEDBCESMQVBUWETInGBMgYUkaGx +QiMkFVLBYjM0coLRQwclklPw4fFjczUWorKDJkSTVGRFwqN0NhfSVeJl8rOEw9N14/NGJ5SkhbSV +xNTk9KW1xdXl9VZmdoaWprbG1ub2N0dXZ3eHl6e3x9fn9xEAAgIBAgQEAwQFBgcHBgU1AQACEQMh +MRIEQVFhcSITBTKBkRShsUIjwVLR8DMkYuFygpJDUxVjczTxJQYWorKDByY1wtJEk1SjF2RFVTZ0 +ZeLys4TD03Xj80aUpIW0lcTU5PSltcXV5fVWZnaGlqa2xtbm9ic3R1dnd4eXp7fH/9oADAMBAAIR +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 +ng8+PKJV9Xeh0+r6eFU312mu32zuY6C5jp/MdtWikkpzD9Wfq+ZnAo15GwQtGutlVba62hlbAGsY +0QAAIa1rR+6pJJKf/9L1VUesdHwusYL8LMaTW73Mc3RzHj6FtTvzXtV5MeEJVRvbqvxcfHH279yx +wcPzcXR8n6j9R/rDg3FlVH26mfZfRGo7epQ52+p/+fX/AMIi9N+oP1gzHg5LG4FPd9pD3x/IoqJ9 +3/GWUr1HxT9lV/U8X6Vf816U/wClfaH8zx1/1X/1RxOT0H6sdL6GwnFYX5LxFmTZBscP3G/m1V/8 +HWteEgnVqPDQ4arwecz+97kve4vcv1cfzKSSSRYlJJJJKUkkkkpSSSSSlJJJJKf/2ThCSU0EIQAA +AAAAVQAAAAEBAAAADwBBAGQAbwBiAGUAIABQAGgAbwB0AG8AcwBoAG8AcAAAABMAQQBkAG8AYgBl +ACAAUABoAG8AdABvAHMAaABvAHAAIAA3AC4AMAAAAAEAOEJJTQQGAAAAAAAHAAgAAAABAQD/4RJI +aHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49J++7vycgaWQ9J1c1 +TTBNcENlaGlIenJlU3pOVGN6a2M5ZCc/Pgo8P2Fkb2JlLXhhcC1maWx0ZXJzIGVzYz0iQ1IiPz4K +PHg6eGFwbWV0YSB4bWxuczp4PSdhZG9iZTpuczptZXRhLycgeDp4YXB0az0nWE1QIHRvb2xraXQg +Mi44LjItMzMsIGZyYW1ld29yayAxLjUnPgo8cmRmOlJERiB4bWxuczpyZGY9J2h0dHA6Ly93d3cu +dzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMnIHhtbG5zOmlYPSdodHRwOi8vbnMuYWRv +YmUuY29tL2lYLzEuMC8nPgoKIDxyZGY6RGVzY3JpcHRpb24gYWJvdXQ9J3V1aWQ6ZTZiMjYwMTMt +NmQ2NS0xMWRmLTk5NjctZWQzZjFkOTdmNTg5JwogIHhtbG5zOnhhcE1NPSdodHRwOi8vbnMuYWRv +YmUuY29tL3hhcC8xLjAvbW0vJz4KICA8eGFwTU06RG9jdW1lbnRJRD5hZG9iZTpkb2NpZDpwaG90 +b3Nob3A6YmNmODU5NTItNmQ1MC0xMWRmLTk5NjctZWQzZjFkOTdmNTg5PC94YXBNTTpEb2N1bWVu +dElEPgogPC9yZGY6RGVzY3JpcHRpb24+Cgo8L3JkZjpSREY+CjwveDp4YXBtZXRhPgogICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAK +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +IAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAog +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKPD94cGFja2V0IGVuZD0n +dyc/Pv/uAA5BZG9iZQBkQAAAAAH/2wCEAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB +AQEBAQEBAQEBAQECAgICAgICAgICAgMDAwMDAwMDAwMBAQEBAQEBAQEBAQICAQICAwMDAwMDAwMD +AwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA//AABEIAEYAnAMBEQACEQED +EQH/3QAEABT/xAGiAAAABgIDAQAAAAAAAAAAAAAHCAYFBAkDCgIBAAsBAAAGAwEBAQAAAAAAAAAA +AAYFBAMHAggBCQAKCxAAAgEDBAEDAwIDAwMCBgl1AQIDBBEFEgYhBxMiAAgxFEEyIxUJUUIWYSQz +F1JxgRhikSVDobHwJjRyChnB0TUn4VM2gvGSokRUc0VGN0djKFVWVxqywtLi8mSDdJOEZaOzw9Pj +KThm83UqOTpISUpYWVpnaGlqdnd4eXqFhoeIiYqUlZaXmJmapKWmp6ipqrS1tre4ubrExcbHyMnK +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 +Lv33f57lGXT4nk6knX5KUHwSbua4n3AEAe3yLuf85I6bK33Y+7w/L/5FL3eH5f8AyKp/s/O+02Xf +tPKdVZYXtoMbWNIc30K3B/0Gucx3v/cVzHZZSCHXX2y6dzzqPLV7k3il2TUe6g5/5pIB19rnAf8A +QS3WeLv896ekPrZtJeP6vH0Wt/76qNfTMxjKmO6rmvFbHscSRLt5Lm2Oc57netR7fRf/ANueokSb +2SK7t3dYOXOH9t6ebP3nf571EMsGOajZbY6CNz+8k/S9zlMgzwiPFB8Ft1n7zv8APep4s/baJ5Ln +aySfoP5LlGD4KeMD9sx/6zv+oelP5ZeRVH5h5v8A/9b03L+xbWfa/TifZ6kcwfo7v5Kr/wCQ/wDg +P+ivmVJPjt+l9Fp36fV+mv8AIf8AwH/RS/yH/wAB/wBFfMqSP+Mr/Ffpr/If/Af9FL/If/Af9FfM +qSX+Mr/Ffpr/ACH/AMB/0Uv8h/8AAf8ARXzKkl/jK/xX6a/yH/wH/RS/yH/wH/RXzKkl/jK/xX6a +/wAh/wDAf9FL/If/AAH/AEV8ypJf4yv8V+mv8h/8B/0Uv8h/8B/0V8ypJf4yv8V+mv8AIf8AwH/R +S/yH/wAB/wBFfMqSX+Mr/Ffpr/If/Af9FL/If/Af9FfMqSX+Mr/Ffpr/ACH/AMB/0UTH/ZXrN+z+ +j62uzbG7j3bf7K+YUkDt+kofR//Z/+0cJlBob3Rvc2hvcCAzLjAAOEJJTQQlAAAAAAAQAAAAAAAA +AAAAAAAAAAAAADhCSU0EOgAAAAAAkwAAABAAAAABAAAAAAALcHJpbnRPdXRwdXQAAAAFAAAAAENs +clNlbnVtAAAAAENsclMAAAAAUkdCQwAAAABJbnRlZW51bQAAAABJbnRlAAAAAEltZyAAAAAATXBC +bGJvb2wBAAAAD3ByaW50U2l4dGVlbkJpdGJvb2wAAAAAC3ByaW50ZXJOYW1lVEVYVAAAAAEAAAA4 +QklNBDsAAAAAAbIAAAAQAAAAAQAAAAAAEnByaW50T3V0cHV0T3B0aW9ucwAAABIAAAAAQ3B0bmJv +b2wAAAAAAENsYnJib29sAAAAAABSZ3NNYm9vbAAAAAAAQ3JuQ2Jvb2wAAAAAAENudENib29sAAAA +AABMYmxzYm9vbAAAAAAATmd0dmJvb2wAAAAAAEVtbERib29sAAAAAABJbnRyYm9vbAAAAAAAQmNr +Z09iamMAAAABAAAAAAAAUkdCQwAAAAMAAAAAUmQgIGRvdWJAb+AAAAAAAAAAAABHcm4gZG91YkBv +4AAAAAAAAAAAAEJsICBkb3ViQG/gAAAAAAAAAAAAQnJkVFVudEYjUmx0AAAAAAAAAAAAAAAAQmxk +IFVudEYjUmx0AAAAAAAAAAAAAAAAUnNsdFVudEYjUHhsQFIAAAAAAAAAAAAKdmVjdG9yRGF0YWJv +b2wBAAAAAFBnUHNlbnVtAAAAAFBnUHMAAAAAUGdQQwAAAABMZWZ0VW50RiNSbHQAAAAAAAAAAAAA +AABUb3AgVW50RiNSbHQAAAAAAAAAAAAAAABTY2wgVW50RiNQcmNAWQAAAAAAADhCSU0D7QAAAAAA +EABIAAAAAQACAEgAAAABAAI4QklNBCYAAAAAAA4AAAAAAAAAAAAAP4AAADhCSU0EDQAAAAAABAAA +AHg4QklNBBkAAAAAAAQAAAAeOEJJTQPzAAAAAAAJAAAAAAAAAAABADhCSU0nEAAAAAAACgABAAAA +AAAAAAI4QklNA/UAAAAAAEgAL2ZmAAEAbGZmAAYAAAAAAAEAL2ZmAAEAoZmaAAYAAAAAAAEAMgAA +AAEAWgAAAAYAAAAAAAEANQAAAAEALQAAAAYAAAAAAAE4QklNA/gAAAAAAHAAAP////////////// +//////////////8D6AAAAAD/////////////////////////////A+gAAAAA//////////////// +/////////////wPoAAAAAP////////////////////////////8D6AAAOEJJTQQAAAAAAAACAAI4 +QklNBAIAAAAAAAYAAAAAAAA4QklNBDAAAAAAAAMBAQEAOEJJTQQtAAAAAAAGAAEAAAAQOEJJTQQI +AAAAAAAQAAAAAQAAAkAAAAJAAAAAADhCSU0EHgAAAAAABAAAAAA4QklNBBoAAAAAAz8AAAAGAAAA +AAAAAAAAAAHxAAACpQAAAAVnKmgHmJgALQAxAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAA +AAAAAAKlAAAB8QAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAABAAAAABAAAAAAAA +bnVsbAAAAAIAAAAGYm91bmRzT2JqYwAAAAEAAAAAAABSY3QxAAAABAAAAABUb3AgbG9uZwAAAAAA +AAAATGVmdGxvbmcAAAAAAAAAAEJ0b21sb25nAAAB8QAAAABSZ2h0bG9uZwAAAqUAAAAGc2xpY2Vz +VmxMcwAAAAFPYmpjAAAAAQAAAAAABXNsaWNlAAAAEgAAAAdzbGljZUlEbG9uZwAAAAAAAAAHZ3Jv +dXBJRGxvbmcAAAAAAAAABm9yaWdpbmVudW0AAAAMRVNsaWNlT3JpZ2luAAAADWF1dG9HZW5lcmF0 +ZWQAAAAAVHlwZWVudW0AAAAKRVNsaWNlVHlwZQAAAABJbWcgAAAABmJvdW5kc09iamMAAAABAAAA +AAAAUmN0MQAAAAQAAAAAVG9wIGxvbmcAAAAAAAAAAExlZnRsb25nAAAAAAAAAABCdG9tbG9uZwAA +AfEAAAAAUmdodGxvbmcAAAKlAAAAA3VybFRFWFQAAAABAAAAAAAAbnVsbFRFWFQAAAABAAAAAAAA +TXNnZVRFWFQAAAABAAAAAAAGYWx0VGFnVEVYVAAAAAEAAAAAAA5jZWxsVGV4dElzSFRNTGJvb2wB +AAAACGNlbGxUZXh0VEVYVAAAAAEAAAAAAAlob3J6QWxpZ25lbnVtAAAAD0VTbGljZUhvcnpBbGln +bgAAAAdkZWZhdWx0AAAACXZlcnRBbGlnbmVudW0AAAAPRVNsaWNlVmVydEFsaWduAAAAB2RlZmF1 +bHQAAAALYmdDb2xvclR5cGVlbnVtAAAAEUVTbGljZUJHQ29sb3JUeXBlAAAAAE5vbmUAAAAJdG9w +T3V0c2V0bG9uZwAAAAAAAAAKbGVmdE91dHNldGxvbmcAAAAAAAAADGJvdHRvbU91dHNldGxvbmcA +AAAAAAAAC3JpZ2h0T3V0c2V0bG9uZwAAAAAAOEJJTQQoAAAAAAAMAAAAAj/wAAAAAAAAOEJJTQQU +AAAAAAAEAAAAEDhCSU0EDAAAAAAT5gAAAAEAAACgAAAAdQAAAeAAANtgAAATygAYAAH/2P/tAAxB +ZG9iZV9DTQAB/+4ADkFkb2JlAGSAAAAAAf/bAIQADAgICAkIDAkJDBELCgsRFQ8MDA8VGBMTFRMT +GBEMDAwMDAwRDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAENCwsNDg0QDg4QFA4ODhQUDg4O +DhQRDAwMDAwREQwMDAwMDBEMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwM/8AAEQgAdQCgAwEi +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 +IM8IjxQfBbdZ+87/AD3qeLP22ieS52skn6D+S5Rg+CnjA/bMf+s7/qHpT+WXkVR+Yeb/AP/W9Ny/ +sW1n2v04n2epHMH6O7+Sq/8AkP8A4D/or5lST47fpfRad+n1fpr/ACH/AMB/0Uv8h/8AAf8ARXzK +kj/jK/xX6a/yH/wH/RS/yH/wH/RXzKkl/jK/xX6a/wAh/wDAf9FL/If/AAH/AEV8ypJf4yv8V+mv +8h/8B/0Uv8h/8B/0V8ypJf4yv8V+mv8AIf8AwH/RS/yH/wAB/wBFfMqSX+Mr/Ffpr/If/Af9FL/I +f/Af9FfMqSX+Mr/Ffpr/ACH/AMB/0Uv8h/8AAf8ARXzKkl/jK/xX6a/yH/wH/RS/yH/wH/RXzKkl +/jK/xX6a/wAh/wDAf9FEx/2V6zfs/o+trs2xu4923+yvmFJA7fpKH0f/2ThCSU0EIQAAAAAAVQAA +AAEBAAAADwBBAGQAbwBiAGUAIABQAGgAbwB0AG8AcwBoAG8AcAAAABMAQQBkAG8AYgBlACAAUABo +AG8AdABvAHMAaABvAHAAIABDAFMANQAAAAEAOEJJTQQGAAAAAAAHAAgAAQABAQD/4Q5caHR0cDov +L25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENl +aGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4 +OnhtcHRrPSJBZG9iZSBYTVAgQ29yZSA1LjAtYzA2MCA2MS4xMzQ3NzcsIDIwMTAvMDIvMTItMTc6 +MzI6MDAgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5 +OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHht +bG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIgeG1sbnM6eG1wTU09Imh0dHA6 +Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0RXZ0PSJodHRwOi8vbnMuYWRvYmUu +Y29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VFdmVudCMiIHhtbG5zOnBob3Rvc2hvcD0iaHR0cDov +L25zLmFkb2JlLmNvbS9waG90b3Nob3AvMS4wLyIgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9k +Yy9lbGVtZW50cy8xLjEvIiB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIFBob3Rvc2hvcCBDUzUgV2lu +ZG93cyIgeG1wOkNyZWF0ZURhdGU9IjIwMTAtMDgtMzFUMDE6MzQ6MjkrMDg6MDAiIHhtcDpNZXRh +ZGF0YURhdGU9IjIwMTAtMDgtMzFUMDE6MzQ6MjkrMDg6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDEw +LTA4LTMxVDAxOjM0OjI5KzA4OjAwIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjI1OEFFRkQ3 +NUNCNERGMTFCRTdFQjIzNzI5NDJGNzQ5IiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjU4NEU3 +MEMwNTdCNERGMTFCRTdFQjIzNzI5NDJGNzQ5IiB4bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ9Inht +cC5kaWQ6NTg0RTcwQzA1N0I0REYxMUJFN0VCMjM3Mjk0MkY3NDkiIHBob3Rvc2hvcDpDb2xvck1v +ZGU9IjMiIHBob3Rvc2hvcDpJQ0NQcm9maWxlPSJzUkdCIElFQzYxOTY2LTIuMSIgZGM6Zm9ybWF0 +PSJpbWFnZS9qcGVnIj4gPHhtcE1NOkhpc3Rvcnk+IDxyZGY6U2VxPiA8cmRmOmxpIHN0RXZ0OmFj +dGlvbj0iY3JlYXRlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDo1ODRFNzBDMDU3QjRERjEx +QkU3RUIyMzcyOTQyRjc0OSIgc3RFdnQ6d2hlbj0iMjAxMC0wOC0zMVQwMTozNDoyOSswODowMCIg +c3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIENTNSBXaW5kb3dzIi8+IDxyZGY6 +bGkgc3RFdnQ6YWN0aW9uPSJzYXZlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDoyNThBRUZE +NzVDQjRERjExQkU3RUIyMzcyOTQyRjc0OSIgc3RFdnQ6d2hlbj0iMjAxMC0wOC0zMVQwMTozNDoy +OSswODowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIENTNSBXaW5kb3dz +IiBzdEV2dDpjaGFuZ2VkPSIvIi8+IDwvcmRmOlNlcT4gPC94bXBNTTpIaXN0b3J5PiA8cGhvdG9z +aG9wOkRvY3VtZW50QW5jZXN0b3JzPiA8cmRmOkJhZz4gPHJkZjpsaT54bXAuZGlkOjU0NEU3MEMw +NTdCNERGMTFCRTdFQjIzNzI5NDJGNzQ5PC9yZGY6bGk+IDwvcmRmOkJhZz4gPC9waG90b3Nob3A6 +RG9jdW1lbnRBbmNlc3RvcnM+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBt +ZXRhPiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +IDw/eHBhY2tldCBlbmQ9InciPz7/4gxYSUNDX1BST0ZJTEUAAQEAAAxITGlubwIQAABtbnRyUkdC +IFhZWiAHzgACAAkABgAxAABhY3NwTVNGVAAAAABJRUMgc1JHQgAAAAAAAAAAAAAAAAAA9tYAAQAA +AADTLUhQICAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABFj +cHJ0AAABUAAAADNkZXNjAAABhAAAAGx3dHB0AAAB8AAAABRia3B0AAACBAAAABRyWFlaAAACGAAA +ABRnWFlaAAACLAAAABRiWFlaAAACQAAAABRkbW5kAAACVAAAAHBkbWRkAAACxAAAAIh2dWVkAAAD +TAAAAIZ2aWV3AAAD1AAAACRsdW1pAAAD+AAAABRtZWFzAAAEDAAAACR0ZWNoAAAEMAAAAAxyVFJD +AAAEPAAACAxnVFJDAAAEPAAACAxiVFJDAAAEPAAACAx0ZXh0AAAAAENvcHlyaWdodCAoYykgMTk5 +OCBIZXdsZXR0LVBhY2thcmQgQ29tcGFueQAAZGVzYwAAAAAAAAASc1JHQiBJRUM2MTk2Ni0yLjEA +AAAAAAAAAAAAABJzUkdCIElFQzYxOTY2LTIuMQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAWFlaIAAAAAAAAPNRAAEAAAABFsxYWVogAAAAAAAAAAAAAAAA +AAAAAFhZWiAAAAAAAABvogAAOPUAAAOQWFlaIAAAAAAAAGKZAAC3hQAAGNpYWVogAAAAAAAAJKAA +AA+EAAC2z2Rlc2MAAAAAAAAAFklFQyBodHRwOi8vd3d3LmllYy5jaAAAAAAAAAAAAAAAFklFQyBo +dHRwOi8vd3d3LmllYy5jaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAABkZXNjAAAAAAAAAC5JRUMgNjE5NjYtMi4xIERlZmF1bHQgUkdCIGNvbG91ciBzcGFjZSAt +IHNSR0IAAAAAAAAAAAAAAC5JRUMgNjE5NjYtMi4xIERlZmF1bHQgUkdCIGNvbG91ciBzcGFjZSAt +IHNSR0IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZGVzYwAAAAAAAAAsUmVmZXJlbmNlIFZpZXdpbmcg +Q29uZGl0aW9uIGluIElFQzYxOTY2LTIuMQAAAAAAAAAAAAAALFJlZmVyZW5jZSBWaWV3aW5nIENv +bmRpdGlvbiBpbiBJRUM2MTk2Ni0yLjEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHZpZXcAAAAA +ABOk/gAUXy4AEM8UAAPtzAAEEwsAA1yeAAAAAVhZWiAAAAAAAEwJVgBQAAAAVx/nbWVhcwAAAAAA +AAABAAAAAAAAAAAAAAAAAAAAAAAAAo8AAAACc2lnIAAAAABDUlQgY3VydgAAAAAAAAQAAAAABQAK +AA8AFAAZAB4AIwAoAC0AMgA3ADsAQABFAEoATwBUAFkAXgBjAGgAbQByAHcAfACBAIYAiwCQAJUA +mgCfAKQAqQCuALIAtwC8AMEAxgDLANAA1QDbAOAA5QDrAPAA9gD7AQEBBwENARMBGQEfASUBKwEy +ATgBPgFFAUwBUgFZAWABZwFuAXUBfAGDAYsBkgGaAaEBqQGxAbkBwQHJAdEB2QHhAekB8gH6AgMC +DAIUAh0CJgIvAjgCQQJLAlQCXQJnAnECegKEAo4CmAKiAqwCtgLBAssC1QLgAusC9QMAAwsDFgMh +Ay0DOANDA08DWgNmA3IDfgOKA5YDogOuA7oDxwPTA+AD7AP5BAYEEwQgBC0EOwRIBFUEYwRxBH4E +jASaBKgEtgTEBNME4QTwBP4FDQUcBSsFOgVJBVgFZwV3BYYFlgWmBbUFxQXVBeUF9gYGBhYGJwY3 +BkgGWQZqBnsGjAadBq8GwAbRBuMG9QcHBxkHKwc9B08HYQd0B4YHmQesB78H0gflB/gICwgfCDII +RghaCG4IggiWCKoIvgjSCOcI+wkQCSUJOglPCWQJeQmPCaQJugnPCeUJ+woRCicKPQpUCmoKgQqY +Cq4KxQrcCvMLCwsiCzkLUQtpC4ALmAuwC8gL4Qv5DBIMKgxDDFwMdQyODKcMwAzZDPMNDQ0mDUAN +Wg10DY4NqQ3DDd4N+A4TDi4OSQ5kDn8Omw62DtIO7g8JDyUPQQ9eD3oPlg+zD88P7BAJECYQQxBh +EH4QmxC5ENcQ9RETETERTxFtEYwRqhHJEegSBxImEkUSZBKEEqMSwxLjEwMTIxNDE2MTgxOkE8UT +5RQGFCcUSRRqFIsUrRTOFPAVEhU0FVYVeBWbFb0V4BYDFiYWSRZsFo8WshbWFvoXHRdBF2UXiReu +F9IX9xgbGEAYZRiKGK8Y1Rj6GSAZRRlrGZEZtxndGgQaKhpRGncanhrFGuwbFBs7G2MbihuyG9oc +AhwqHFIcexyjHMwc9R0eHUcdcB2ZHcMd7B4WHkAeah6UHr4e6R8THz4faR+UH78f6iAVIEEgbCCY +IMQg8CEcIUghdSGhIc4h+yInIlUigiKvIt0jCiM4I2YjlCPCI/AkHyRNJHwkqyTaJQklOCVoJZcl +xyX3JicmVyaHJrcm6CcYJ0kneierJ9woDSg/KHEooijUKQYpOClrKZ0p0CoCKjUqaCqbKs8rAis2 +K2krnSvRLAUsOSxuLKIs1y0MLUEtdi2rLeEuFi5MLoIuty7uLyQvWi+RL8cv/jA1MGwwpDDbMRIx +SjGCMbox8jIqMmMymzLUMw0zRjN/M7gz8TQrNGU0njTYNRM1TTWHNcI1/TY3NnI2rjbpNyQ3YDec +N9c4FDhQOIw4yDkFOUI5fzm8Ofk6Njp0OrI67zstO2s7qjvoPCc8ZTykPOM9Ij1hPaE94D4gPmA+ +oD7gPyE/YT+iP+JAI0BkQKZA50EpQWpBrEHuQjBCckK1QvdDOkN9Q8BEA0RHRIpEzkUSRVVFmkXe +RiJGZ0arRvBHNUd7R8BIBUhLSJFI10kdSWNJqUnwSjdKfUrESwxLU0uaS+JMKkxyTLpNAk1KTZNN +3E4lTm5Ot08AT0lPk0/dUCdQcVC7UQZRUFGbUeZSMVJ8UsdTE1NfU6pT9lRCVI9U21UoVXVVwlYP +VlxWqVb3V0RXklfgWC9YfVjLWRpZaVm4WgdaVlqmWvVbRVuVW+VcNVyGXNZdJ114XcleGl5sXr1f +D19hX7NgBWBXYKpg/GFPYaJh9WJJYpxi8GNDY5dj62RAZJRk6WU9ZZJl52Y9ZpJm6Gc9Z5Nn6Wg/ +aJZo7GlDaZpp8WpIap9q92tPa6dr/2xXbK9tCG1gbbluEm5rbsRvHm94b9FwK3CGcOBxOnGVcfBy +S3KmcwFzXXO4dBR0cHTMdSh1hXXhdj52m3b4d1Z3s3gReG54zHkqeYl553pGeqV7BHtje8J8IXyB +fOF9QX2hfgF+Yn7CfyN/hH/lgEeAqIEKgWuBzYIwgpKC9INXg7qEHYSAhOOFR4Wrhg6GcobXhzuH +n4gEiGmIzokziZmJ/opkisqLMIuWi/yMY4zKjTGNmI3/jmaOzo82j56QBpBukNaRP5GokhGSepLj +k02TtpQglIqU9JVflcmWNJaflwqXdZfgmEyYuJkkmZCZ/JpomtWbQpuvnByciZz3nWSd0p5Anq6f +HZ+Ln/qgaaDYoUehtqImopajBqN2o+akVqTHpTilqaYapoum/adup+CoUqjEqTepqaocqo+rAqt1 +q+msXKzQrUStuK4trqGvFq+LsACwdbDqsWCx1rJLssKzOLOutCW0nLUTtYq2AbZ5tvC3aLfguFm4 +0blKucK6O7q1uy67p7whvJu9Fb2Pvgq+hL7/v3q/9cBwwOzBZ8Hjwl/C28NYw9TEUcTOxUvFyMZG +xsPHQce/yD3IvMk6ybnKOMq3yzbLtsw1zLXNNc21zjbOts83z7jQOdC60TzRvtI/0sHTRNPG1EnU +y9VO1dHWVdbY11zX4Nhk2OjZbNnx2nba+9uA3AXcit0Q3ZbeHN6i3ynfr+A24L3hROHM4lPi2+Nj +4+vkc+T85YTmDeaW5x/nqegy6LzpRunQ6lvq5etw6/vshu0R7ZzuKO6070DvzPBY8OXxcvH/8ozz +GfOn9DT0wvVQ9d72bfb794r4Gfio+Tj5x/pX+uf7d/wH/Jj9Kf26/kv+3P9t////7gAOQWRvYmUA +ZEAAAAAB/9sAhAABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAgIC +AgICAgICAgIDAwMDAwMDAwMDAQEBAQEBAQEBAQECAgECAgMDAwMDAwMDAwMDAwMDAwMDAwMDAwMD +AwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwP/wAARCAHxAqUDAREAAhEBAxEB/90ABABV/8QBCwAB +AAICAwEBAQAAAAAAAAAAAAcJBggDBAUKAQIBAQABBQEBAQEAAAAAAAAAAAAHAgMEBQYBCAkKEAAA +BQQAAAcICgkLEgMFBAsDBAUGBwABAggREhMUFhcJFdZXd5cYmNghVFWVtje31zhYMaHSY5Ok1Fa4 +QVFh0SJSkjNTtZZxgZGxwTKCI9MkdJS0dTZ2qArwo2bhYsI0GXPDJsZHQnKzRGSEJdXHKREAAQQA +AgQEDQ0LCgYBAwMFAQACAwQRBSESEwYxkxSUQVGRItJT09QVVRYHF2FxMlJysiNzs1S0NlaxwZKj +JDRkdIRF1fCBodFCYjM1daWiwuNElQhjwyVl4UODpIK1JvH/2gAMAwEAAhEDEQA/APv4oiURKIlE +SiJREoiURKIlESiJREoiURKIlESiJREoiURKIlESiJREoiURKIlESiJREoiURKIlESiJREoiURKI +lESiJREoiURKIlESiJREoiURKIlESiJREoiURKIlESiJREoiURKIlESiJREoiURKIlESiJREoiUR +KIlESiJREoiURKIlESiJREoi/9D7+KIlESiJREoiURKIlESiJREoiURKIlESiJREoiURKIlESiJR +EoiURKIlESiJREoiURKIlESiJREoiURKIlESiJREoiURKIlESiJREoiURKIlESiJREoiURKIlESi +JREoiURKIlESiJREoiURKIlESiJREoiURKIlESiJREoiURKIlESiJREoiURKIv/R+/iiJRFpptPJ +UhJzqhqEYpdxyOHXJxh3v50yMVbDYdBxuQ/DpllF3qmtQq7slNBLv54O6SmyllBjyIskSyMZVjPJ +hnACWWXV7r5VVvG/cuxCSvA1rQwuc0Okk1tXWLcHajWse46r2uLwwY6pdhz+fZhPVFStVkLJpS4l +wAJDGYa2rrYjWc5zAMWuAaXHDENxgoDX5igghBCSTtiaEDDwwzMj7t7lYjGMscbWyGFxLTkXL2EE +vbhvYMPDDhv7GNrexXXGA4/m9HmtbuS54TDD/Gtc4n7ouXqCYfhB2r9NzdH5+acnPaKXNavck2ze +22ucT90TqCYfhB2r9NzdH5+acnPaKXNavck2ze22ucT90TqCYfhB2r9NzdH5+acnPaKXNavck2ze +22ucT90TqCYfhB2r9NzdH5+KcnPaKXNavck2ze22ucT90TqCYfhC2s9NzdH5+KcnPzelzWr3JNsO +3WucT90TqCYfhC2s9NzdH5+KcnPzelzWr3JNsO3WucT90TqCYfhC2s9NzdH5+KcnPzelzWr3JNsO +3WucT90TqCYfhC2s9NzdH5+KcnPzelzWr3JNsO3WucT90TqCYfhC2s9NzdH5+KcnPzelzWr3JNsO +3WucT90TqCYfhC2s9NzdH5+KcnPzelzWr3JNsO3WucT90TqCYfhC2s9NzdH5+KcnPzelzWr3JNsO +3WucT90TqCYfhC2s9NzdH5+KcnPzelzWr3JNsO3WucT90TqCYfhC2s9NzdH5+KcnPzelzWr3JNsO +3WucT90TqCYfhC2s9NzdH5+KcnPzelzWr3JNsO3WucT90TqCYfhC2s9NzdH5+KcnPzelzWr3JNsO +3WucT90TqCYfhC2s9NzdH5+KcnPzelzWr3JNsO3WucT90TqCYfhC2s9NzdH5+KcnPzelzWr3JNsO +3WucT90TqCYfhC2s9NzdH5+KcnPzelzWr3JNsO3WucT90TqCYfhC2s9NzdH5+KcnPzelzWr3JNsO +3WucT90TqCYfhC2s9NzdH5+KcnPzelzWr3JNsO3WucT90TqCYfhC2s9NzdH5+KcnPzelzWr3JNsO +3WucT90TqCYfhC2s9NzdH5+KcnPzelzWr3JNsO3WucT90TqCYfhC2s9NzdH5+KcnPzelzWr3JNsO +3WucT90TqCYfhC2s9NzdH5+KcnPzelzWr3JNsO3WucT90TqCYfhC2s9NzdH5+KcnPzelzWr3JNsO +3WucT90TqCYfhC2s9NzdH5+KcnPzelzWr3JNsO3WucT90TqCYfhC2s9NzdH5+KcnPzelzWr3JNsO +3WucT90TqCYfhC2s9NzdH5+KcnPzelzWr3JNsO3WucT90TqCYfhC2s9NzdH5+KcnPzelzWr3JNsO +3WucT90TqCYfhC2s9NzdH5+KcnPzelzWr3JNsO3WucT90TqCYfhC2s9NzdH5+KcnPzelzWr3JNsO +3WucT90TqCYfhC2s9NzdH5+KcnPzelzWr3JNsO3WucT90TqCYfhC2s9NzdH5+KcnPzelzWr3JNsO +3WucT90TqCYfhC2s9NzdH5+KcnPzelzWr3JNsO3WucT90TqCYfhC2s9NzdH5+KcnPzelzWr3JNsO +3WucT90TqCYfhC2s9NzdH5+KcnPzelzWr3JNsO3WucT90TqCYfhC2s9NzdH5+KcnPzelzWr3JNsO +3WucT90TqCYfhC2s9NzdH5+KcnPzelzWr3JNsO3WucT90TqCYfhC2s9NzdH5+KcnPzelzWr3JNsO +3WucT90TqCYfhB2r9NzdH5+acnPaKXNavck2ze22ucT90TqCYfhB2r9NzdH5+acnPaKXNavck2ze +22ucT90TqCYfhB2r9NzdH5+acnPaKXNavck2ze22ucT90TqCYfhB2r9NzdH5+acnPaKXNavck2ze +22ucT90TqCYfhB2r9NzdH5+acnPaKXNavck2ze22ucT90TqCYfhB2r9NzdH5+acnPaKXNavck2ze +22ucT90TqCYfhB2r9NzdH5+acnPaKXNavck2ze22ucT90TqCYfhB2r9NzdH5+acnPaKXNavck2ze +22ucT90TqCYfhB2r9NzdH5+acnPaKXNavck2ze22ucT90TqCYfhB2r9NzdH5+acnPaKXNavck2ze +22ucT90TqCYfhB2r9NzdH5+acnPaKXNavck2ze22ucT90TqCYfhB2r9NzdH5+acnPaKXNavck2ze +22ucT90TqCYfhB2r9NzdH5+acnPaKXNavck2ze22ucT90TqCYfhB2r9NzdH5+acnPaKXNavck2ze +22ucT90TqCYfhB2r9NzdH5+acnPaKXNavck2ze22ucT90TqCYfhB2r9NzdH5+acnPaKXNavck2ze +22ucT90TqCYfhB2r9NzdH5+acnPaKXNavck2ze22ucT90TqCYfhB2r9NzdH5+acnPaKXNavck2ze +22ucT90TqCYfhB2r9NzdH5+acnPaKXNavck2ze22ucT90TqCYfhB2r9NzdH5+acnPaKXNavck2ze +22ucT90TqCYfhB2r9NzdH5+acnPaKXNavck2ze22ucT90TqCYfhB2r9NzdH5+acnPaKXNavck2ze +22ucT90TqCYfhB2r9NzdH5+acnPaKXNavck2ze22ucT90TqCYfhB2r9NzdH5+acnPaKXNavck2ze +22ucT90TqCYfhB2r9NzdH5+acnPaKXNavck2ze22ucT90TqCYfhB2r9NzdH5+acnPaKXNavck2ze +22ucT90TqCYfhB2r9NzdH5+acnPaKXNavck2ze22ucT90TqCYfhB2r9NzdH5+acnPaKXNavck2ze +22ucT90TqCYfhB2r9NzdH5+acnPaKXNavck2ze22ucT90TqCYfhB2r9NzdH5+acnPaKXNavck2ze +22ucT90TqCYfhB2r9NzdH5+acnPaKXNavck2ze22ucT90TqCYfhB2r9NzdH5+acnPaKXNavck2ze +22ucT90TqCYfhB2r9NzdH5+acnPaKXNavck2ze22ucT90TqCYfhB2r9NzdH5+acnPaKXNavck2ze +22ucT90TqCYfhB2r9NzdH5+acnPaKXNavck2ze22ucT90TqCYfhB2r9NzdH5+acnPaKXNavck2ze +22ucT90TqCYfhB2r9NzdH5+acnPaKXNavck2ze22ucT90TqCYfhB2r9NzdH5+acnPaKXNavck2ze +22ucT90TqCYfhB2r9NzdH5+acnPaKXNavck2ze22ucT90XEPr8xRgRQg5J2xKiCB54YGQN29yshi ++WWN7YjBYmZyMF7iB3vw2sIHnhw29nG9vYoIDj+b0ea1u5IZhh/jWucT90U66sSVISi6plhGVncc +kd1xiYaD+a0jGmw2GucccPzEZepdlJrrKtHJMQTD+Z7ujVzJZsYiiIxEyjFkkzyYhwc7ljyO9GVV +aJoXKUQjrztc0sDnODZI9XW1S7F2o5r2OGs9zg8vGOqG49DkOYT2hbrWpC+aItIcQASx+OrrauA1 +mua8HBrQWhpwxLsNy65RdAv/0vv4oiURV5bO2FvtnrTyIogWdtdtvb8YPO+GXF6ytKrXtxsb2vwX +vepF3H1eQ53rtBG1r+9sLi96tblWV6pIOzm+7Cvl73/7RLfJK2jlSBolVcomjuMVQmhBGG6lhKb3 +ewCo3ERYutqrkUwVEZFLD4qPKkMEnBOHCBEtyow2XBe3z951POvvHlO8WZbv5ZLFSrV3BuLWNMj8 +WtdrF7gdUHHFuoGkAjEkr9Uv/Ur/ANO/Nrv15uN3POHvLltjOswzBj36r5ZGVoDHNJHqMjiLDI5p +YWy7Z0jC4HBjRoMawRt9s6qqCOhHJMmNee6kspacjlz72eiycMrJk4GXTygJU0rZYHMjBwXHG5Qw +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 +Wd3KiLzocGS+7n97XUi7icOZ+4i+7MrM6iZSEv/W+/iiJRFVzux9KvUbxQ7VfKDpzUsebH97/GQe +8sqPt+v3d7iX30K5Kl5RyvFPiuY0vsZpM9JQlZxvxynm6nYOVwqDYRCfc1lO97mzh1TS2w7z3/yL +QFBDDwJZ8cUbHjZYY2verNu3Ty3L8wzTMHyipWja52zY17zrSxxABrnxt9lICSXjQDhidCuV69m7 +cp0KbWGxM9zRruLWjVjfISS1jzwMIGDTpI4FJHUbst+bEGeWV/er7XIekjc7p5nzeDvxdH5E7yfo +PHS97J1G7LfmxBnllf3q+09JG53TzPm8HfieRO8n6Dx0veydRuy35sQZ5ZX96vtPSRud08z5vB34 +nkTvJ+g8dL3snUbst+bEGeWV/er7T0kbndPM+bwd+J5E7yfoPHS97J1G7LfmxBnllf3q+09JG53T +zPm8HfieRO8n6Dx0veydRuy35sQZ5ZX96vtPSRud08z5vB34nkTvJ+g8dL3snUbst+bEGeWV/er7 +T0kbndPM+bwd+J5E7yfoPHS97J1G7LfmxBnllf3q+09JG53TzPm8HfieRO8n6Dx0veydRuy35sQZ +5ZX96vtPSRud08z5vB34nkTvJ+g8dL3snUbst+bEGeWV/er7T0kbndPM+bwd+J5E7yfoPHS97J1G +7LfmxBnllf3q+09JG53TzPm8HfieRO8n6Dx0veydRuy35sQZ5ZX96vtPSRud08z5vB34nkTvJ+g8 +dL3snUbst+bEGeWV/er7T0kbndPM+bwd+J5E7yfoPHS97J1G7LfmxBnllf3q+09JG53TzPm8Hfie +RO8n6Dx0veydRuy35sQZ5ZX96vtPSRud08z5vB34nkTvJ+g8dL3snUbst+bEGeWV/er7T0kbndPM ++bwd+J5E7yfoPHS97J1G7LfmxBnllf3q+09JG53TzPm8HfieRO8n6Dx0veydRuy35sQZ5ZX96vtP +SRud08z5vB34nkTvJ+g8dL3snUbst+bEGeWV/er7T0kbndPM+bwd+J5E7yfoPHS97J1G7LfmxBnl +lf3q+09JG53TzPm8HfieRO8n6Dx0veydRuy35sQZ5ZX96vtPSRud08z5vB34nkTvJ+g8dL3snUbs +t+bEGeWV/er7T0kbndPM+bwd+J5E7yfoPHS97J1G7LfmxBnllf3q+09JG53TzPm8HfieRO8n6Dx0 +veydRuy35sQZ5ZX96vtPSRud08z5vB34nkTvJ+g8dL3snUbst+bEGeWV/er7T0kbndPM+bwd+J5E +7yfoPHS97J1G7LfmxBnllf3q+09JG53TzPm8HfieRO8n6Dx0veydRuy35sQZ5ZX96vtPSRud08z5 +vB34nkTvJ+g8dL3snUbst+bEGeWV/er7T0kbndPM+bwd+J5E7yfoPHS97J1G7LfmxBnllf3q+09J +G53TzPm8HfieRO8n6Dx0veydRuy35sQZ5ZX96vtPSRud08z5vB34nkTvJ+g8dL3snUbst+bEGeWV +/er7T0kbndPM+bwd+J5E7yfoPHS97J1G7LfmxBnllf3q+09JG53TzPm8HfieRO8n6Dx0veydRuy3 +5sQZ5ZX96vtPSRud08z5vB34nkTvJ+g8dL3snUbst+bEGeWV/er7T0kbndPM+bwd+J5E7yfoPHS9 +7J1G7LfmxBnllf3q+09JG53TzPm8HfieRO8n6Dx0veydRuy35sQZ5ZX96vtPSRud08z5vB34nkTv +J+g8dL3snUbst+bEGeWV/er7T0kbndPM+bwd+J5E7yfoPHS97J1G7LfmxBnllf3q+09JG53TzPm8 +HfieRO8n6Dx0veydRuy35sQZ5ZX96vtPSRud08z5vB34nkTvJ+g8dL3snUbst+bEGeWV/er7T0kb +ndPM+bwd+J5E7yfoPHS97J1G7LfmxBnllf3q+09JG53TzPm8HfieRO8n6Dx0veydRuy35sQZ5ZX9 +6vtPSRud08z5vB34nkTvJ+g8dL3so9Mlnw2XwtsB/ojUS1lLajReBYyz3cruxMOJjsV3wiggDjLT +HY5omeJmmONlljiCOHmGPhe2dr2yxrqMrzTLM8yxma5U+fk+3kiIljZG4OjZE8kBksoLSJRgcQcQ +dHAVob9C9lV51C+2LbbJkgMb3PbqvdI3A60cZBBjPQIwI0rgVlI8VNN9JSE4JVXXSt9wkUmZP4JZ +HIyEkKzgOjn1C5c6KWKlEVBNC/4ouYEzzwxwth+6vljfsWIKdaxcsucK8TQTgMTpcGgAYgYlzgNJ +A6OKswwy2Joa8IBleSBicBoBccTgegD0Cvb6Jy7+azF8oSv83daLytyPpWuLZ3ZbbyfzTpQfhu7m +nROXfzWYvlCV/m7p5W5H0rXFs7snk/mn/wAH4bu5p0Tl381mL5Qlf5u688rcj/SuLZ3ZPJ/NOlB+ +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 +i7NNhZ+Zz8XJ2KdKyXuM+vJrInevTldHxlV4+Ls02Fn5nPxcnYr+cnYRxtfK6M++C372M5Gyv9ng +9jHFrXyv/Yr0WqJ0eEqvHw9mmws/M5+Lk7FcfTFP9xX/AOS2S+9KveUUvGVTnEPdE2Fn5nPxcnYr +ls7CN7WvZGfXs2tf2Y0kW1/Z/XtdrWva/wDVqnlVHxlV4+Ls02Fn5nPxcnYrspzkS1I8ImBd0iak +GUsf7nraEuN08MRuNzfI4UKL6cmjnSgI98cBRAcc8As88LZ3xvnhbK6x8crDJDNHIwHAlj2vAPDg +S0nA9IHh6Coc17HBskb2OIxwc1zSR6msBj/Mu0rLKciAAmFEYQOxk2AQJgFiptQPnzxjjciTTk1P +ANKCgbzwwzz5MAITOweGed7WwwyytVoAc5zmtY0YkkhoA6ZJIAHqk8OhU6SWtAJcTgAASSfUAxJ/ +mXm9KyXuM+vJrInevVjldHxlV4+Ls1d2Fn5nPxcnYp0rJe4z68msid69OV0fGVXj4uzTYWfmc/Fy +dinSsl7jPryayJ3r05XR8ZVePi7NNhZ+Zz8XJ2KdKyXuM+vJrInevTldHxlV4+Ls02Fn5nPxcnYp +0rJe4z68msid69OV0fGVXj4uzTYWfmc/FydinSsl7jPryayJ3r05XR8ZVePi7NNhZ+Zz8XJ2KdKy +XuM+vJrInevTldHxlV4+Ls02Fn5nPxcnYr+cnYRxtfK6M++C372M5Gyv9ng9jHFrXyv/AGK9Fqid +HhKrx8PZpsLPzOfi5OxXH0xT/cV/+S2S+9KveUUvGVTnEPdE2Fn5nPxcnYrls7CN7WvZGfXs2tf2 +Y0kW1/Z/XtdrWva/9WqeVUfGVXj4uzTYWfmc/FydiuynORLUjwiYF3SJqQZSx/uetoS43TwxG43N +8jhQovpyaOdKAj3xwFEBxzwCzzwtnfG+eFsrrHxysMkM0cjAcCWPa8A8OBLScD0geHoKhzXscGyR +vY4jHBzXNJHqawGP8y96ql4lESiJREoiURKIlESiJREoi7+m30odn/Edq18rO7lRF50ODJfdz+9r +qRdxOHM/cRfdmVmdRMpCX//W+/iiJRFVzux9KvUbxQ7VfKDpzUsebH97/GQe8sqPt+v3d7iX30K5 +Kl5RylESiJREoiURKIlESiJREoiURKIlESiJREoiURKIlESiJREoiURKIlESiJREoiURKIlESiJR +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 +4DpLKr0qdPX5JUii1sMdRrW44Y4Y6oGOGJwx4MSpVrCWSv/U+/iiJREoiURKIlESiJREoiURKIlE +SiJREoiURKIlESiJREoiURKIlESiJREoiURKIlESiJREoiURKIlESiJREoiURKIlESiJREoiURKI +lESiJREoiURKIlESiJREoiURKIlESiJREoiURKIlESiJREoiURKIlESiJREoiURKIlESiJREoiUR +KIlESiL/1fv4oiURKIlESiJREoiURKIlESiJREoiURKIlESiJREoiURKIlESiJREoiURKIlESiJR +EoiURKIlESiJREoiURKIlESiJREoiURKIlESiJREoiURKIlESiJREoiURKIlESiJREoiURKIlESi +JREoiURKIlESiJREoiURKIlESiJREoiURKIlESiJREoi/9lQSwMECgAAAAAAAAAhAAdIekDwbQAA +8G0AABYAAAB3b3JkL21lZGlhL2ltYWdlNS5qcGVn/9j/4Q48RXhpZgAATU0AKgAAAAgABwESAAMA +AAABAAEAAAEaAAUAAAABAAAAYgEbAAUAAAABAAAAagEoAAMAAAABAAIAAAExAAIAAAAcAAAAcgEy +AAIAAAAUAAAAjodpAAQAAAABAAAApAAAANAACvyAAAAnEAAK/IAAACcQQWRvYmUgUGhvdG9zaG9w +IENTNSBXaW5kb3dzADIwMTA6MDg6MzEgMDE6MDI6MTkAAAAAA6ABAAMAAAABAAEAAKACAAQAAAAB +AAAAt6ADAAQAAAABAAAAPAAAAAAAAAAGAQMAAwAAAAEABgAAARoABQAAAAEAAAEeARsABQAAAAEA +AAEmASgAAwAAAAEAAgAAAgEABAAAAAEAAAEuAgIABAAAAAEAAA0GAAAAAAAAAEgAAAABAAAASAAA +AAH/2P/tAAxBZG9iZV9DTQAB/+4ADkFkb2JlAGSAAAAAAf/bAIQADAgICAkIDAkJDBELCgsRFQ8M +DA8VGBMTFRMTGBEMDAwMDAwRDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAENCwsNDg0QDg4Q +FA4ODhQUDg4ODhQRDAwMDAwREQwMDAwMDBEMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwM/8AA +EQgANACgAwEiAAIRAQMRAf/dAAQACv/EAT8AAAEFAQEBAQEBAAAAAAAAAAMAAQIEBQYHCAkKCwEA +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 +/wBJpfsN3/ljnf8Abo/9JpCUhtH8f8FRx4iCPe339EmpjfVrIGE/FzcpuR6uHZiPc2sNA9Rznt9N +m536Ohjtn6TfbZ/OWWKjlfVDquY1gysyt5sb6OUWG+smt7333ONjb3W5b6XW7OmU5Vn2XAZ/grvU +Wz+w3f8Aljnf9uj/ANJpfsN3/ljnf9uj/wBJoWf3fxUceI3+u3/qS/l+iy6L07L6cMim+1mRU5/q +VXkO9d5P03Zz7H2Ntta1tVTH1enX6dfsppr9OpaSy/2G7/yxzv8At0f+k0v2G7/yxzv+3R/6TRuX +7v4o9rD/AJ7/AJkkvRf6HZ/4bzP/AG6yFfQMLErwscY9bnPAc95e8y4use66xziA36VljkdGIqIB +6BbmkJZZyjtKUpDyJf/S9VSXyqkkp+qkl8qpJKfqpJfKqSSn6qSXyqkkp+qkl8qpJKfqpJfKqSSn +6qSXyqkkp+qkl8qpJKfqpJfKqSSn6qSXyqkkp//Z/+0VdFBob3Rvc2hvcCAzLjAAOEJJTQQlAAAA +AAAQAAAAAAAAAAAAAAAAAAAAADhCSU0EOgAAAAAAkwAAABAAAAABAAAAAAALcHJpbnRPdXRwdXQA +AAAFAAAAAENsclNlbnVtAAAAAENsclMAAAAAUkdCQwAAAABJbnRlZW51bQAAAABJbnRlAAAAAElt +ZyAAAAAATXBCbGJvb2wBAAAAD3ByaW50U2l4dGVlbkJpdGJvb2wAAAAAC3ByaW50ZXJOYW1lVEVY +VAAAAAEAAAA4QklNBDsAAAAAAbIAAAAQAAAAAQAAAAAAEnByaW50T3V0cHV0T3B0aW9ucwAAABIA +AAAAQ3B0bmJvb2wAAAAAAENsYnJib29sAAAAAABSZ3NNYm9vbAAAAAAAQ3JuQ2Jvb2wAAAAAAENu +dENib29sAAAAAABMYmxzYm9vbAAAAAAATmd0dmJvb2wAAAAAAEVtbERib29sAAAAAABJbnRyYm9v +bAAAAAAAQmNrZ09iamMAAAABAAAAAAAAUkdCQwAAAAMAAAAAUmQgIGRvdWJAb+AAAAAAAAAAAABH +cm4gZG91YkBv4AAAAAAAAAAAAEJsICBkb3ViQG/gAAAAAAAAAAAAQnJkVFVudEYjUmx0AAAAAAAA +AAAAAAAAQmxkIFVudEYjUmx0AAAAAAAAAAAAAAAAUnNsdFVudEYjUHhsQFIAAAAAAAAAAAAKdmVj +dG9yRGF0YWJvb2wBAAAAAFBnUHNlbnVtAAAAAFBnUHMAAAAAUGdQQwAAAABMZWZ0VW50RiNSbHQA +AAAAAAAAAAAAAABUb3AgVW50RiNSbHQAAAAAAAAAAAAAAABTY2wgVW50RiNQcmNAWQAAAAAAADhC +SU0D7QAAAAAAEABIAAAAAQACAEgAAAABAAI4QklNBCYAAAAAAA4AAAAAAAAAAAAAP4AAADhCSU0E +DQAAAAAABAAAAHg4QklNBBkAAAAAAAQAAAAeOEJJTQPzAAAAAAAJAAAAAAAAAAABADhCSU0nEAAA +AAAACgABAAAAAAAAAAI4QklNA/UAAAAAAEgAL2ZmAAEAbGZmAAYAAAAAAAEAL2ZmAAEAoZmaAAYA +AAAAAAEAMgAAAAEAWgAAAAYAAAAAAAEANQAAAAEALQAAAAYAAAAAAAE4QklNA/gAAAAAAHAAAP// +//////////////////////////8D6AAAAAD/////////////////////////////A+gAAAAA//// +/////////////////////////wPoAAAAAP////////////////////////////8D6AAAOEJJTQQA +AAAAAAACAAc4QklNBAIAAAAAABIAAAAAAAAAAAAAAAAAAAAAAAA4QklNBDAAAAAAAAkBAQEBAQEB +AQEAOEJJTQQtAAAAAAAGAAEAAAALOEJJTQQIAAAAAAAQAAAAAQAAAkAAAAJAAAAAADhCSU0EHgAA +AAAABAAAAAA4QklNBBoAAAAAAz8AAAAGAAAAAAAAAAAAAAA8AAAAtwAAAAVnKmgHmJgALQAxAAAA +AQAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAC3AAAAPAAAAAAAAAAAAAAAAAAAAAABAAAA +AAAAAAAAAAAAAAAAAAAAABAAAAABAAAAAAAAbnVsbAAAAAIAAAAGYm91bmRzT2JqYwAAAAEAAAAA +AABSY3QxAAAABAAAAABUb3AgbG9uZwAAAAAAAAAATGVmdGxvbmcAAAAAAAAAAEJ0b21sb25nAAAA +PAAAAABSZ2h0bG9uZwAAALcAAAAGc2xpY2VzVmxMcwAAAAFPYmpjAAAAAQAAAAAABXNsaWNlAAAA +EgAAAAdzbGljZUlEbG9uZwAAAAAAAAAHZ3JvdXBJRGxvbmcAAAAAAAAABm9yaWdpbmVudW0AAAAM +RVNsaWNlT3JpZ2luAAAADWF1dG9HZW5lcmF0ZWQAAAAAVHlwZWVudW0AAAAKRVNsaWNlVHlwZQAA +AABJbWcgAAAABmJvdW5kc09iamMAAAABAAAAAAAAUmN0MQAAAAQAAAAAVG9wIGxvbmcAAAAAAAAA +AExlZnRsb25nAAAAAAAAAABCdG9tbG9uZwAAADwAAAAAUmdodGxvbmcAAAC3AAAAA3VybFRFWFQA +AAABAAAAAAAAbnVsbFRFWFQAAAABAAAAAAAATXNnZVRFWFQAAAABAAAAAAAGYWx0VGFnVEVYVAAA +AAEAAAAAAA5jZWxsVGV4dElzSFRNTGJvb2wBAAAACGNlbGxUZXh0VEVYVAAAAAEAAAAAAAlob3J6 +QWxpZ25lbnVtAAAAD0VTbGljZUhvcnpBbGlnbgAAAAdkZWZhdWx0AAAACXZlcnRBbGlnbmVudW0A +AAAPRVNsaWNlVmVydEFsaWduAAAAB2RlZmF1bHQAAAALYmdDb2xvclR5cGVlbnVtAAAAEUVTbGlj +ZUJHQ29sb3JUeXBlAAAAAE5vbmUAAAAJdG9wT3V0c2V0bG9uZwAAAAAAAAAKbGVmdE91dHNldGxv +bmcAAAAAAAAADGJvdHRvbU91dHNldGxvbmcAAAAAAAAAC3JpZ2h0T3V0c2V0bG9uZwAAAAAAOEJJ +TQQoAAAAAAAMAAAAAj/wAAAAAAAAOEJJTQQUAAAAAAAEAAAACzhCSU0EDAAAAAANIgAAAAEAAACg +AAAANAAAAeAAAGGAAAANBgAYAAH/2P/tAAxBZG9iZV9DTQAB/+4ADkFkb2JlAGSAAAAAAf/bAIQA +DAgICAkIDAkJDBELCgsRFQ8MDA8VGBMTFRMTGBEMDAwMDAwRDAwMDAwMDAwMDAwMDAwMDAwMDAwM +DAwMDAwMDAENCwsNDg0QDg4QFA4ODhQUDg4ODhQRDAwMDAwREQwMDAwMDBEMDAwMDAwMDAwMDAwM +DAwMDAwMDAwMDAwMDAwM/8AAEQgANACgAwEiAAIRAQMRAf/dAAQACv/EAT8AAAEFAQEBAQEBAAAA +AAAAAAMAAQIEBQYHCAkKCwEAAQUBAQEBAQEAAAAAAAAAAQACAwQFBgcICQoLEAABBAEDAgQCBQcG +CAUDDDMBAAIRAwQhEjEFQVFhEyJxgTIGFJGhsUIjJBVSwWIzNHKC0UMHJZJT8OHxY3M1FqKygyZE +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 +b3W5b6XW7OmU5Vn2XAZ/grvUWz+w3f8Aljnf9uj/ANJpfsN3/ljnf9uj/wBJoWf3fxUceI3+u3/q +S/l+iy6L07L6cMim+1mRU5/qVXkO9d5P03Zz7H2Ntta1tVTH1enX6dfsppr9OpaSy/2G7/yxzv8A +t0f+k0v2G7/yxzv+3R/6TRuX7v4o9rD/AJ7/AJkkvRf6HZ/4bzP/AG6yFfQMLErwscY9bnPAc95e +8y4use66xziA36VljkdGIqIB6BbmkJZZyjtKUpDyJf/S9VSXyqkkp+qkl8qpJKfqpJfKqSSn6qSX +yqkkp+qkl8qpJKfqpJfKqSSn6qSXyqkkp+qkl8qpJKfqpJfKqSSn6qSXyqkkp//ZOEJJTQQhAAAA +AABVAAAAAQEAAAAPAEEAZABvAGIAZQAgAFAAaABvAHQAbwBzAGgAbwBwAAAAEwBBAGQAbwBiAGUA +IABQAGgAbwB0AG8AcwBoAG8AcAAgAEMAUwA1AAAAAQA4QklNBAYAAAAAAAcACAABAAEBAP/hDlxo +dHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVN +ME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0 +YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8x +Mi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9y +Zy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9 +IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0i +aHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5h +ZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1sbnM6cGhvdG9zaG9wPSJo +dHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczpkYz0iaHR0cDovL3B1cmwu +b3JnL2RjL2VsZW1lbnRzLzEuMS8iIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENT +NSBXaW5kb3dzIiB4bXA6Q3JlYXRlRGF0ZT0iMjAxMC0wOC0zMVQwMTowMjoxOSswODowMCIgeG1w +Ok1ldGFkYXRhRGF0ZT0iMjAxMC0wOC0zMVQwMTowMjoxOSswODowMCIgeG1wOk1vZGlmeURhdGU9 +IjIwMTAtMDgtMzFUMDE6MDI6MTkrMDg6MDAiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NTE0 +RTcwQzA1N0I0REYxMUJFN0VCMjM3Mjk0MkY3NDkiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6 +NTA0RTcwQzA1N0I0REYxMUJFN0VCMjM3Mjk0MkY3NDkiIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJ +RD0ieG1wLmRpZDo1MDRFNzBDMDU3QjRERjExQkU3RUIyMzcyOTQyRjc0OSIgcGhvdG9zaG9wOkNv +bG9yTW9kZT0iMyIgcGhvdG9zaG9wOklDQ1Byb2ZpbGU9InNSR0IgSUVDNjE5NjYtMi4xIiBkYzpm +b3JtYXQ9ImltYWdlL2pwZWciPiA8eG1wTU06SGlzdG9yeT4gPHJkZjpTZXE+IDxyZGY6bGkgc3RF +dnQ6YWN0aW9uPSJjcmVhdGVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOjUwNEU3MEMwNTdC +NERGMTFCRTdFQjIzNzI5NDJGNzQ5IiBzdEV2dDp3aGVuPSIyMDEwLTA4LTMxVDAxOjAyOjE5KzA4 +OjAwIiBzdEV2dDpzb2Z0d2FyZUFnZW50PSJBZG9iZSBQaG90b3Nob3AgQ1M1IFdpbmRvd3MiLz4g +PHJkZjpsaSBzdEV2dDphY3Rpb249InNhdmVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOjUx +NEU3MEMwNTdCNERGMTFCRTdFQjIzNzI5NDJGNzQ5IiBzdEV2dDp3aGVuPSIyMDEwLTA4LTMxVDAx +OjAyOjE5KzA4OjAwIiBzdEV2dDpzb2Z0d2FyZUFnZW50PSJBZG9iZSBQaG90b3Nob3AgQ1M1IFdp +bmRvd3MiIHN0RXZ0OmNoYW5nZWQ9Ii8iLz4gPC9yZGY6U2VxPiA8L3htcE1NOkhpc3Rvcnk+IDxw +aG90b3Nob3A6RG9jdW1lbnRBbmNlc3RvcnM+IDxyZGY6QmFnPiA8cmRmOmxpPnhtcC5kaWQ6NENC +MTQ5RjQ1NEI0REYxMUJFN0VCMjM3Mjk0MkY3NDk8L3JkZjpsaT4gPC9yZGY6QmFnPiA8L3Bob3Rv +c2hvcDpEb2N1bWVudEFuY2VzdG9ycz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94 +OnhtcG1ldGE+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgPD94cGFja2V0IGVuZD0idyI/Pv/iDFhJQ0NfUFJPRklMRQABAQAADEhMaW5vAhAAAG1u +dHJSR0IgWFlaIAfOAAIACQAGADEAAGFjc3BNU0ZUAAAAAElFQyBzUkdCAAAAAAAAAAAAAAAAAAD2 +1gABAAAAANMtSFAgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAEWNwcnQAAAFQAAAAM2Rlc2MAAAGEAAAAbHd0cHQAAAHwAAAAFGJrcHQAAAIEAAAAFHJYWVoA +AAIYAAAAFGdYWVoAAAIsAAAAFGJYWVoAAAJAAAAAFGRtbmQAAAJUAAAAcGRtZGQAAALEAAAAiHZ1 +ZWQAAANMAAAAhnZpZXcAAAPUAAAAJGx1bWkAAAP4AAAAFG1lYXMAAAQMAAAAJHRlY2gAAAQwAAAA +DHJUUkMAAAQ8AAAIDGdUUkMAAAQ8AAAIDGJUUkMAAAQ8AAAIDHRleHQAAAAAQ29weXJpZ2h0IChj +KSAxOTk4IEhld2xldHQtUGFja2FyZCBDb21wYW55AABkZXNjAAAAAAAAABJzUkdCIElFQzYxOTY2 +LTIuMQAAAAAAAAAAAAAAEnNSR0IgSUVDNjE5NjYtMi4xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABYWVogAAAAAAAA81EAAQAAAAEWzFhZWiAAAAAAAAAA +AAAAAAAAAAAAWFlaIAAAAAAAAG+iAAA49QAAA5BYWVogAAAAAAAAYpkAALeFAAAY2lhZWiAAAAAA +AAAkoAAAD4QAALbPZGVzYwAAAAAAAAAWSUVDIGh0dHA6Ly93d3cuaWVjLmNoAAAAAAAAAAAAAAAW +SUVDIGh0dHA6Ly93d3cuaWVjLmNoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAGRlc2MAAAAAAAAALklFQyA2MTk2Ni0yLjEgRGVmYXVsdCBSR0IgY29sb3VyIHNw +YWNlIC0gc1JHQgAAAAAAAAAAAAAALklFQyA2MTk2Ni0yLjEgRGVmYXVsdCBSR0IgY29sb3VyIHNw +YWNlIC0gc1JHQgAAAAAAAAAAAAAAAAAAAAAAAAAAAABkZXNjAAAAAAAAACxSZWZlcmVuY2UgVmll +d2luZyBDb25kaXRpb24gaW4gSUVDNjE5NjYtMi4xAAAAAAAAAAAAAAAsUmVmZXJlbmNlIFZpZXdp +bmcgQ29uZGl0aW9uIGluIElFQzYxOTY2LTIuMQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdmll +dwAAAAAAE6T+ABRfLgAQzxQAA+3MAAQTCwADXJ4AAAABWFlaIAAAAAAATAlWAFAAAABXH+dtZWFz +AAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAACjwAAAAJzaWcgAAAAAENSVCBjdXJ2AAAAAAAABAAA +AAAFAAoADwAUABkAHgAjACgALQAyADcAOwBAAEUASgBPAFQAWQBeAGMAaABtAHIAdwB8AIEAhgCL +AJAAlQCaAJ8ApACpAK4AsgC3ALwAwQDGAMsA0ADVANsA4ADlAOsA8AD2APsBAQEHAQ0BEwEZAR8B +JQErATIBOAE+AUUBTAFSAVkBYAFnAW4BdQF8AYMBiwGSAZoBoQGpAbEBuQHBAckB0QHZAeEB6QHy +AfoCAwIMAhQCHQImAi8COAJBAksCVAJdAmcCcQJ6AoQCjgKYAqICrAK2AsECywLVAuAC6wL1AwAD +CwMWAyEDLQM4A0MDTwNaA2YDcgN+A4oDlgOiA64DugPHA9MD4APsA/kEBgQTBCAELQQ7BEgEVQRj +BHEEfgSMBJoEqAS2BMQE0wThBPAE/gUNBRwFKwU6BUkFWAVnBXcFhgWWBaYFtQXFBdUF5QX2BgYG +FgYnBjcGSAZZBmoGewaMBp0GrwbABtEG4wb1BwcHGQcrBz0HTwdhB3QHhgeZB6wHvwfSB+UH+AgL +CB8IMghGCFoIbgiCCJYIqgi+CNII5wj7CRAJJQk6CU8JZAl5CY8JpAm6Cc8J5Qn7ChEKJwo9ClQK +agqBCpgKrgrFCtwK8wsLCyILOQtRC2kLgAuYC7ALyAvhC/kMEgwqDEMMXAx1DI4MpwzADNkM8w0N +DSYNQA1aDXQNjg2pDcMN3g34DhMOLg5JDmQOfw6bDrYO0g7uDwkPJQ9BD14Peg+WD7MPzw/sEAkQ +JhBDEGEQfhCbELkQ1xD1ERMRMRFPEW0RjBGqEckR6BIHEiYSRRJkEoQSoxLDEuMTAxMjE0MTYxOD +E6QTxRPlFAYUJxRJFGoUixStFM4U8BUSFTQVVhV4FZsVvRXgFgMWJhZJFmwWjxayFtYW+hcdF0EX +ZReJF64X0hf3GBsYQBhlGIoYrxjVGPoZIBlFGWsZkRm3Gd0aBBoqGlEadxqeGsUa7BsUGzsbYxuK +G7Ib2hwCHCocUhx7HKMczBz1HR4dRx1wHZkdwx3sHhYeQB5qHpQevh7pHxMfPh9pH5Qfvx/qIBUg +QSBsIJggxCDwIRwhSCF1IaEhziH7IiciVSKCIq8i3SMKIzgjZiOUI8Ij8CQfJE0kfCSrJNolCSU4 +JWgllyXHJfcmJyZXJocmtyboJxgnSSd6J6sn3CgNKD8ocSiiKNQpBik4KWspnSnQKgIqNSpoKpsq +zysCKzYraSudK9EsBSw5LG4soizXLQwtQS12Last4S4WLkwugi63Lu4vJC9aL5Evxy/+MDUwbDCk +MNsxEjFKMYIxujHyMioyYzKbMtQzDTNGM38zuDPxNCs0ZTSeNNg1EzVNNYc1wjX9Njc2cjauNuk3 +JDdgN5w31zgUOFA4jDjIOQU5Qjl/Obw5+To2OnQ6sjrvOy07azuqO+g8JzxlPKQ84z0iPWE9oT3g +PiA+YD6gPuA/IT9hP6I/4kAjQGRApkDnQSlBakGsQe5CMEJyQrVC90M6Q31DwEQDREdEikTORRJF +VUWaRd5GIkZnRqtG8Ec1R3tHwEgFSEtIkUjXSR1JY0mpSfBKN0p9SsRLDEtTS5pL4kwqTHJMuk0C +TUpNk03cTiVObk63TwBPSU+TT91QJ1BxULtRBlFQUZtR5lIxUnxSx1MTU19TqlP2VEJUj1TbVShV +dVXCVg9WXFapVvdXRFeSV+BYL1h9WMtZGllpWbhaB1pWWqZa9VtFW5Vb5Vw1XIZc1l0nXXhdyV4a +XmxevV8PX2Ffs2AFYFdgqmD8YU9homH1YklinGLwY0Njl2PrZEBklGTpZT1lkmXnZj1mkmboZz1n +k2fpaD9olmjsaUNpmmnxakhqn2r3a09rp2v/bFdsr20IbWBtuW4SbmtuxG8eb3hv0XArcIZw4HE6 +cZVx8HJLcqZzAXNdc7h0FHRwdMx1KHWFdeF2Pnabdvh3VnezeBF4bnjMeSp5iXnnekZ6pXsEe2N7 +wnwhfIF84X1BfaF+AX5ifsJ/I3+Ef+WAR4CogQqBa4HNgjCCkoL0g1eDuoQdhICE44VHhauGDoZy +hteHO4efiASIaYjOiTOJmYn+imSKyoswi5aL/IxjjMqNMY2Yjf+OZo7OjzaPnpAGkG6Q1pE/kaiS +EZJ6kuOTTZO2lCCUipT0lV+VyZY0lp+XCpd1l+CYTJi4mSSZkJn8mmia1ZtCm6+cHJyJnPedZJ3S +nkCerp8dn4uf+qBpoNihR6G2oiailqMGo3aj5qRWpMelOKWpphqmi6b9p26n4KhSqMSpN6mpqhyq +j6sCq3Wr6axcrNCtRK24ri2uoa8Wr4uwALB1sOqxYLHWskuywrM4s660JbSctRO1irYBtnm28Ldo +t+C4WbjRuUq5wro7urW7LrunvCG8m70VvY++Cr6Evv+/er/1wHDA7MFnwePCX8Lbw1jD1MRRxM7F +S8XIxkbGw8dBx7/IPci8yTrJuco4yrfLNsu2zDXMtc01zbXONs62zzfPuNA50LrRPNG+0j/SwdNE +08bUSdTL1U7V0dZV1tjXXNfg2GTY6Nls2fHadtr724DcBdyK3RDdlt4c3qLfKd+v4DbgveFE4czi +U+Lb42Pj6+Rz5PzlhOYN5pbnH+ep6DLovOlG6dDqW+rl63Dr++yG7RHtnO4o7rTvQO/M8Fjw5fFy +8f/yjPMZ86f0NPTC9VD13vZt9vv3ivgZ+Kj5OPnH+lf65/t3/Af8mP0p/br+S/7c/23////uAA5B +ZG9iZQBkQAAAAAH/2wCEAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB +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 +W6me3OnvJ3HsHwf7mYn6JX+b0/Nj70/6lvMD8Q5f65r12DSbTOKPrLKIvqPrHG5NG3Ztf47ImChK +qZ31gfWdYS4tD0yu7dFEzg1OzU4Jiz0ykgws4g4sIwCCIOM4uo4Xw6q9NqrxPGLsrOCAxqoEhIZ3 +EhKAiRIZiJiYmJiY3j061+W95v3ks/isngs77wfOLuEu12IsV353KOQ9DglbUuUy0S2qasiBizEg +MCkSiRmY1Zzkm1w/TjTX/9bv4400400400400400400400400400400400400400400400400400 +400400400400400401//2VBLAwQKAAAAAAAAACEA/hCfFvOjAgDzowIAFgAAAHdvcmQvbWVkaWEv +aW1hZ2U0LmpwZWf/2P/hGe9FeGlmAABNTQAqAAAACAAHARIAAwAAAAEAAQAAARoABQAAAAEAAABi +ARsABQAAAAEAAABqASgAAwAAAAEAAgAAATEAAgAAABwAAAByATIAAgAAABQAAACOh2kABAAAAAEA +AACkAAAA0AAK/IAAACcQAAr8gAAAJxBBZG9iZSBQaG90b3Nob3AgQ1M1IFdpbmRvd3MAMjAxMDow +ODozMSAwMDo1ODowMgAAAAADoAEAAwAAAAEAAQAAoAIABAAAAAEAAAIioAMABAAAAAEAAAGpAAAA +AAAAAAYBAwADAAAAAQAGAAABGgAFAAAAAQAAAR4BGwAFAAAAAQAAASYBKAADAAAAAQACAAACAQAE +AAAAAQAAAS4CAgAEAAAAAQAAGLkAAAAAAAAASAAAAAEAAABIAAAAAf/Y/+0ADEFkb2JlX0NNAAH/ +7gAOQWRvYmUAZIAAAAAB/9sAhAAMCAgICQgMCQkMEQsKCxEVDwwMDxUYExMVExMYEQwMDAwMDBEM +DAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMAQ0LCw0ODRAODhAUDg4OFBQODg4OFBEMDAwMDBER +DAwMDAwMEQwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCAB9AKADASIAAhEBAxEB/90A +BAAK/8QBPwAAAQUBAQEBAQEAAAAAAAAAAwABAgQFBgcICQoLAQABBQEBAQEBAQAAAAAAAAABAAID +BAUGBwgJCgsQAAEEAQMCBAIFBwYIBQMMMwEAAhEDBCESMQVBUWETInGBMgYUkaGxQiMkFVLBYjM0 +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 +2eqK7GBu5pcCHT9EtH7rf31nUf8Aipyv/CdP/ny9Hptx2Wix+ZU8BpaBIH0i0/vu/cVXFsrt+s+W +6p7Xt+x0iWkET6l2ntTJkXCiPm/ZJlxRkI5bBHo/7uD/AP/W9VVPI6P0nJtddkYdN1r43PfW1zjA +DRLnD91quJIS4a9VfVdDjv0cV/1N/wDmuf8A83+hf+V+N/20z/yKX/N/oX/lfjf9tM/8itBJM/Vf +1f8Amsv9J/1n/Pc//m/0L/yvxv8Atpn/AJFL/m/0L/yvxv8Atpn/AJFaCSX6r+r/AM1X9J/1n/Pc +/wD5v9C/8r8b/tpn/kUv+b/Qv/K/G/7aZ/5FaCSX6r+r/wA1X9J/1n/Pc/8A5v8AQv8Ayvxv+2mf ++RS/5v8AQv8Ayvxv+2mf+RWgkl+q/q/81X9J/wBZ/wA9z/8Am/0L/wAr8b/tpn/kUv8Am90L/wAr +8b/tpn/kVoJJfqv6v/NV/Sf9Z/z3P/5vdC/8r8b/ALaZ/wCRS/5vdC/8r8b/ALaZ/wCRWgkl+q/q +/wDNV/Sf9Z/z3P8A+b3Qv/K/G/7aZ/5FL/m90L/yvxv+2mf+RWgkl+q/q/8ANV/Sf9Z/z3P/AOb3 +Qv8Ayvxv+2mf+RS/5vdC/wDK/G/7aZ/5FaCSX6r+r/zVf0n/AFn/AD3P/wCb3Qv/ACvxv+2mf+RR +8XpvT8NznYmNVjucIca2BsgawdoVlJEe3enDfhS2Xv0eLj4evFxcL//Z/+0hIlBob3Rvc2hvcCAz +LjAAOEJJTQQlAAAAAAAQAAAAAAAAAAAAAAAAAAAAADhCSU0EOgAAAAAAkwAAABAAAAABAAAAAAAL +cHJpbnRPdXRwdXQAAAAFAAAAAENsclNlbnVtAAAAAENsclMAAAAAUkdCQwAAAABJbnRlZW51bQAA +AABJbnRlAAAAAEltZyAAAAAATXBCbGJvb2wBAAAAD3ByaW50U2l4dGVlbkJpdGJvb2wAAAAAC3By +aW50ZXJOYW1lVEVYVAAAAAEAAAA4QklNBDsAAAAAAbIAAAAQAAAAAQAAAAAAEnByaW50T3V0cHV0 +T3B0aW9ucwAAABIAAAAAQ3B0bmJvb2wAAAAAAENsYnJib29sAAAAAABSZ3NNYm9vbAAAAAAAQ3Ju +Q2Jvb2wAAAAAAENudENib29sAAAAAABMYmxzYm9vbAAAAAAATmd0dmJvb2wAAAAAAEVtbERib29s +AAAAAABJbnRyYm9vbAAAAAAAQmNrZ09iamMAAAABAAAAAAAAUkdCQwAAAAMAAAAAUmQgIGRvdWJA +b+AAAAAAAAAAAABHcm4gZG91YkBv4AAAAAAAAAAAAEJsICBkb3ViQG/gAAAAAAAAAAAAQnJkVFVu +dEYjUmx0AAAAAAAAAAAAAAAAQmxkIFVudEYjUmx0AAAAAAAAAAAAAAAAUnNsdFVudEYjUHhsQFIA +AAAAAAAAAAAKdmVjdG9yRGF0YWJvb2wBAAAAAFBnUHNlbnVtAAAAAFBnUHMAAAAAUGdQQwAAAABM +ZWZ0VW50RiNSbHQAAAAAAAAAAAAAAABUb3AgVW50RiNSbHQAAAAAAAAAAAAAAABTY2wgVW50RiNQ +cmNAWQAAAAAAADhCSU0D7QAAAAAAEABIAAAAAQACAEgAAAABAAI4QklNBCYAAAAAAA4AAAAAAAAA +AAAAP4AAADhCSU0EDQAAAAAABAAAAHg4QklNBBkAAAAAAAQAAAAeOEJJTQPzAAAAAAAJAAAAAAAA +AAABADhCSU0nEAAAAAAACgABAAAAAAAAAAI4QklNA/UAAAAAAEgAL2ZmAAEAbGZmAAYAAAAAAAEA +L2ZmAAEAoZmaAAYAAAAAAAEAMgAAAAEAWgAAAAYAAAAAAAEANQAAAAEALQAAAAYAAAAAAAE4QklN +A/gAAAAAAHAAAP////////////////////////////8D6AAAAAD///////////////////////// +////A+gAAAAA/////////////////////////////wPoAAAAAP////////////////////////// +//8D6AAAOEJJTQQAAAAAAAACAAU4QklNBAIAAAAAAA4AAAAAAAAAAAAAAAAAADhCSU0EMAAAAAAA +BwEBAQEBAQEAOEJJTQQtAAAAAAAGAAEAAAAGOEJJTQQIAAAAAAAQAAAAAQAAAkAAAAJAAAAAADhC +SU0EHgAAAAAABAAAAAA4QklNBBoAAAAAAz8AAAAGAAAAAAAAAAAAAAGpAAACIgAAAAVnKmgHmJgA +LQAxAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAIiAAABqQAAAAAAAAAAAAAAAAAA +AAABAAAAAAAAAAAAAAAAAAAAAAAAABAAAAABAAAAAAAAbnVsbAAAAAIAAAAGYm91bmRzT2JqYwAA +AAEAAAAAAABSY3QxAAAABAAAAABUb3AgbG9uZwAAAAAAAAAATGVmdGxvbmcAAAAAAAAAAEJ0b21s +b25nAAABqQAAAABSZ2h0bG9uZwAAAiIAAAAGc2xpY2VzVmxMcwAAAAFPYmpjAAAAAQAAAAAABXNs +aWNlAAAAEgAAAAdzbGljZUlEbG9uZwAAAAAAAAAHZ3JvdXBJRGxvbmcAAAAAAAAABm9yaWdpbmVu +dW0AAAAMRVNsaWNlT3JpZ2luAAAADWF1dG9HZW5lcmF0ZWQAAAAAVHlwZWVudW0AAAAKRVNsaWNl +VHlwZQAAAABJbWcgAAAABmJvdW5kc09iamMAAAABAAAAAAAAUmN0MQAAAAQAAAAAVG9wIGxvbmcA +AAAAAAAAAExlZnRsb25nAAAAAAAAAABCdG9tbG9uZwAAAakAAAAAUmdodGxvbmcAAAIiAAAAA3Vy +bFRFWFQAAAABAAAAAAAAbnVsbFRFWFQAAAABAAAAAAAATXNnZVRFWFQAAAABAAAAAAAGYWx0VGFn +VEVYVAAAAAEAAAAAAA5jZWxsVGV4dElzSFRNTGJvb2wBAAAACGNlbGxUZXh0VEVYVAAAAAEAAAAA +AAlob3J6QWxpZ25lbnVtAAAAD0VTbGljZUhvcnpBbGlnbgAAAAdkZWZhdWx0AAAACXZlcnRBbGln +bmVudW0AAAAPRVNsaWNlVmVydEFsaWduAAAAB2RlZmF1bHQAAAALYmdDb2xvclR5cGVlbnVtAAAA +EUVTbGljZUJHQ29sb3JUeXBlAAAAAE5vbmUAAAAJdG9wT3V0c2V0bG9uZwAAAAAAAAAKbGVmdE91 +dHNldGxvbmcAAAAAAAAADGJvdHRvbU91dHNldGxvbmcAAAAAAAAAC3JpZ2h0T3V0c2V0bG9uZwAA +AAAAOEJJTQQoAAAAAAAMAAAAAj/wAAAAAAAAOEJJTQQUAAAAAAAEAAAACDhCSU0EDAAAAAAY1QAA +AAEAAACgAAAAfQAAAeAAAOpgAAAYuQAYAAH/2P/tAAxBZG9iZV9DTQAB/+4ADkFkb2JlAGSAAAAA +Af/bAIQADAgICAkIDAkJDBELCgsRFQ8MDA8VGBMTFRMTGBEMDAwMDAwRDAwMDAwMDAwMDAwMDAwM +DAwMDAwMDAwMDAwMDAENCwsNDg0QDg4QFA4ODhQUDg4ODhQRDAwMDAwREQwMDAwMDBEMDAwMDAwM +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 +OWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUg +WE1QIENvcmUgNS4wLWMwNjAgNjEuMTM0Nzc3LCAyMDEwLzAyLzEyLTE3OjMyOjAwICAgICAgICAi +PiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5 +bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6 +Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29t +L3hhcC8xLjAvbW0vIiB4bWxuczpzdEV2dD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NU +eXBlL1Jlc291cmNlRXZlbnQjIiB4bWxuczpwaG90b3Nob3A9Imh0dHA6Ly9ucy5hZG9iZS5jb20v +cGhvdG9zaG9wLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4x +LyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IFdpbmRvd3MiIHhtcDpDcmVh +dGVEYXRlPSIyMDEwLTA4LTMxVDAwOjU4OjAyKzA4OjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDEw +LTA4LTMxVDAwOjU4OjAyKzA4OjAwIiB4bXA6TW9kaWZ5RGF0ZT0iMjAxMC0wOC0zMVQwMDo1ODow +MiswODowMCIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo0RjRFNzBDMDU3QjRERjExQkU3RUIy +MzcyOTQyRjc0OSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo0RTRFNzBDMDU3QjRERjExQkU3 +RUIyMzcyOTQyRjc0OSIgeG1wTU06T3JpZ2luYWxEb2N1bWVudElEPSJ4bXAuZGlkOjRFNEU3MEMw +NTdCNERGMTFCRTdFQjIzNzI5NDJGNzQ5IiBwaG90b3Nob3A6Q29sb3JNb2RlPSIzIiBwaG90b3No +b3A6SUNDUHJvZmlsZT0ic1JHQiBJRUM2MTk2Ni0yLjEiIGRjOmZvcm1hdD0iaW1hZ2UvanBlZyI+ +IDx4bXBNTTpIaXN0b3J5PiA8cmRmOlNlcT4gPHJkZjpsaSBzdEV2dDphY3Rpb249ImNyZWF0ZWQi +IHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6NEU0RTcwQzA1N0I0REYxMUJFN0VCMjM3Mjk0MkY3 +NDkiIHN0RXZ0OndoZW49IjIwMTAtMDgtMzFUMDA6NTg6MDIrMDg6MDAiIHN0RXZ0OnNvZnR3YXJl +QWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCBDUzUgV2luZG93cyIvPiA8cmRmOmxpIHN0RXZ0OmFjdGlv +bj0ic2F2ZWQiIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6NEY0RTcwQzA1N0I0REYxMUJFN0VC +MjM3Mjk0MkY3NDkiIHN0RXZ0OndoZW49IjIwMTAtMDgtMzFUMDA6NTg6MDIrMDg6MDAiIHN0RXZ0 +OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCBDUzUgV2luZG93cyIgc3RFdnQ6Y2hhbmdl +ZD0iLyIvPiA8L3JkZjpTZXE+IDwveG1wTU06SGlzdG9yeT4gPHBob3Rvc2hvcDpEb2N1bWVudEFu +Y2VzdG9ycz4gPHJkZjpCYWc+IDxyZGY6bGk+eG1wLmRpZDo0Q0IxNDlGNDU0QjRERjExQkU3RUIy +MzcyOTQyRjc0OTwvcmRmOmxpPiA8L3JkZjpCYWc+IDwvcGhvdG9zaG9wOkRvY3VtZW50QW5jZXN0 +b3JzPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8P3hwYWNrZXQgZW5k +PSJ3Ij8+/+IMWElDQ19QUk9GSUxFAAEBAAAMSExpbm8CEAAAbW50clJHQiBYWVogB84AAgAJAAYA +MQAAYWNzcE1TRlQAAAAASUVDIHNSR0IAAAAAAAAAAAAAAAAAAPbWAAEAAAAA0y1IUCAgAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARY3BydAAAAVAAAAAzZGVz +YwAAAYQAAABsd3RwdAAAAfAAAAAUYmtwdAAAAgQAAAAUclhZWgAAAhgAAAAUZ1hZWgAAAiwAAAAU +YlhZWgAAAkAAAAAUZG1uZAAAAlQAAABwZG1kZAAAAsQAAACIdnVlZAAAA0wAAACGdmlldwAAA9QA +AAAkbHVtaQAAA/gAAAAUbWVhcwAABAwAAAAkdGVjaAAABDAAAAAMclRSQwAABDwAAAgMZ1RSQwAA +BDwAAAgMYlRSQwAABDwAAAgMdGV4dAAAAABDb3B5cmlnaHQgKGMpIDE5OTggSGV3bGV0dC1QYWNr +YXJkIENvbXBhbnkAAGRlc2MAAAAAAAAAEnNSR0IgSUVDNjE5NjYtMi4xAAAAAAAAAAAAAAASc1JH +QiBJRUM2MTk2Ni0yLjEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAFhZWiAAAAAAAADzUQABAAAAARbMWFlaIAAAAAAAAAAAAAAAAAAAAABYWVogAAAAAAAA +b6IAADj1AAADkFhZWiAAAAAAAABimQAAt4UAABjaWFlaIAAAAAAAACSgAAAPhAAAts9kZXNjAAAA +AAAAABZJRUMgaHR0cDovL3d3dy5pZWMuY2gAAAAAAAAAAAAAABZJRUMgaHR0cDovL3d3dy5pZWMu +Y2gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZGVzYwAAAAAA +AAAuSUVDIDYxOTY2LTIuMSBEZWZhdWx0IFJHQiBjb2xvdXIgc3BhY2UgLSBzUkdCAAAAAAAAAAAA +AAAuSUVDIDYxOTY2LTIuMSBEZWZhdWx0IFJHQiBjb2xvdXIgc3BhY2UgLSBzUkdCAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAGRlc2MAAAAAAAAALFJlZmVyZW5jZSBWaWV3aW5nIENvbmRpdGlvbiBpbiBJ +RUM2MTk2Ni0yLjEAAAAAAAAAAAAAACxSZWZlcmVuY2UgVmlld2luZyBDb25kaXRpb24gaW4gSUVD +NjE5NjYtMi4xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB2aWV3AAAAAAATpP4AFF8uABDPFAAD +7cwABBMLAANcngAAAAFYWVogAAAAAABMCVYAUAAAAFcf521lYXMAAAAAAAAAAQAAAAAAAAAAAAAA +AAAAAAAAAAKPAAAAAnNpZyAAAAAAQ1JUIGN1cnYAAAAAAAAEAAAAAAUACgAPABQAGQAeACMAKAAt +ADIANwA7AEAARQBKAE8AVABZAF4AYwBoAG0AcgB3AHwAgQCGAIsAkACVAJoAnwCkAKkArgCyALcA +vADBAMYAywDQANUA2wDgAOUA6wDwAPYA+wEBAQcBDQETARkBHwElASsBMgE4AT4BRQFMAVIBWQFg +AWcBbgF1AXwBgwGLAZIBmgGhAakBsQG5AcEByQHRAdkB4QHpAfIB+gIDAgwCFAIdAiYCLwI4AkEC +SwJUAl0CZwJxAnoChAKOApgCogKsArYCwQLLAtUC4ALrAvUDAAMLAxYDIQMtAzgDQwNPA1oDZgNy +A34DigOWA6IDrgO6A8cD0wPgA+wD+QQGBBMEIAQtBDsESARVBGMEcQR+BIwEmgSoBLYExATTBOEE +8AT+BQ0FHAUrBToFSQVYBWcFdwWGBZYFpgW1BcUF1QXlBfYGBgYWBicGNwZIBlkGagZ7BowGnQav +BsAG0QbjBvUHBwcZBysHPQdPB2EHdAeGB5kHrAe/B9IH5Qf4CAsIHwgyCEYIWghuCIIIlgiqCL4I +0gjnCPsJEAklCToJTwlkCXkJjwmkCboJzwnlCfsKEQonCj0KVApqCoEKmAquCsUK3ArzCwsLIgs5 +C1ELaQuAC5gLsAvIC+EL+QwSDCoMQwxcDHUMjgynDMAM2QzzDQ0NJg1ADVoNdA2ODakNww3eDfgO +Ew4uDkkOZA5/DpsOtg7SDu4PCQ8lD0EPXg96D5YPsw/PD+wQCRAmEEMQYRB+EJsQuRDXEPURExEx +EU8RbRGMEaoRyRHoEgcSJhJFEmQShBKjEsMS4xMDEyMTQxNjE4MTpBPFE+UUBhQnFEkUahSLFK0U +zhTwFRIVNBVWFXgVmxW9FeAWAxYmFkkWbBaPFrIW1hb6Fx0XQRdlF4kXrhfSF/cYGxhAGGUYihiv +GNUY+hkgGUUZaxmRGbcZ3RoEGioaURp3Gp4axRrsGxQbOxtjG4obshvaHAIcKhxSHHscoxzMHPUd +Hh1HHXAdmR3DHeweFh5AHmoelB6+HukfEx8+H2kflB+/H+ogFSBBIGwgmCDEIPAhHCFIIXUhoSHO +IfsiJyJVIoIiryLdIwojOCNmI5QjwiPwJB8kTSR8JKsk2iUJJTglaCWXJccl9yYnJlcmhya3Jugn +GCdJJ3onqyfcKA0oPyhxKKIo1CkGKTgpaymdKdAqAio1KmgqmyrPKwIrNitpK50r0SwFLDksbiyi +LNctDC1BLXYtqy3hLhYuTC6CLrcu7i8kL1ovkS/HL/4wNTBsMKQw2zESMUoxgjG6MfIyKjJjMpsy +1DMNM0YzfzO4M/E0KzRlNJ402DUTNU01hzXCNf02NzZyNq426TckN2A3nDfXOBQ4UDiMOMg5BTlC +OX85vDn5OjY6dDqyOu87LTtrO6o76DwnPGU8pDzjPSI9YT2hPeA+ID5gPqA+4D8hP2E/oj/iQCNA +ZECmQOdBKUFqQaxB7kIwQnJCtUL3QzpDfUPARANER0SKRM5FEkVVRZpF3kYiRmdGq0bwRzVHe0fA +SAVIS0iRSNdJHUljSalJ8Eo3Sn1KxEsMS1NLmkviTCpMcky6TQJNSk2TTdxOJU5uTrdPAE9JT5NP +3VAnUHFQu1EGUVBRm1HmUjFSfFLHUxNTX1OqU/ZUQlSPVNtVKFV1VcJWD1ZcVqlW91dEV5JX4Fgv +WH1Yy1kaWWlZuFoHWlZaplr1W0VblVvlXDVchlzWXSddeF3JXhpebF69Xw9fYV+zYAVgV2CqYPxh +T2GiYfViSWKcYvBjQ2OXY+tkQGSUZOllPWWSZedmPWaSZuhnPWeTZ+loP2iWaOxpQ2maafFqSGqf +avdrT2una/9sV2yvbQhtYG25bhJua27Ebx5veG/RcCtwhnDgcTpxlXHwcktypnMBc11zuHQUdHB0 +zHUodYV14XY+dpt2+HdWd7N4EXhueMx5KnmJeed6RnqlewR7Y3vCfCF8gXzhfUF9oX4BfmJ+wn8j +f4R/5YBHgKiBCoFrgc2CMIKSgvSDV4O6hB2EgITjhUeFq4YOhnKG14c7h5+IBIhpiM6JM4mZif6K +ZIrKizCLlov8jGOMyo0xjZiN/45mjs6PNo+ekAaQbpDWkT+RqJIRknqS45NNk7aUIJSKlPSVX5XJ +ljSWn5cKl3WX4JhMmLiZJJmQmfyaaJrVm0Kbr5wcnImc951kndKeQJ6unx2fi5/6oGmg2KFHobai +JqKWowajdqPmpFakx6U4pammGqaLpv2nbqfgqFKoxKk3qamqHKqPqwKrdavprFys0K1ErbiuLa6h +rxavi7AAsHWw6rFgsdayS7LCszizrrQltJy1E7WKtgG2ebbwt2i34LhZuNG5SrnCuju6tbsuu6e8 +IbybvRW9j74KvoS+/796v/XAcMDswWfB48JfwtvDWMPUxFHEzsVLxcjGRsbDx0HHv8g9yLzJOsm5 +yjjKt8s2y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DY +ZNjo2WzZ8dp22vvbgNwF3IrdEN2W3hzeot8p36/gNuC94UThzOJT4tvjY+Pr5HPk/OWE5g3mlucf +56noMui86Ubp0Opb6uXrcOv77IbtEe2c7ijutO9A78zwWPDl8XLx//KM8xnzp/Q09ML1UPXe9m32 ++/eK+Bn4qPk4+cf6V/rn+3f8B/yY/Sn9uv5L/tz/bf///+4ADkFkb2JlAGRAAAAAAf/bAIQAAQEB +AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQICAgICAgICAgICAwMDAwMD +AwMDAwEBAQEBAQEBAQEBAgIBAgIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMD +AwMDAwMDAwMDAwMD/8AAEQgBqQIiAwERAAIRAQMRAf/dAAQARf/EAQkAAQABBAMBAQEAAAAAAAAA +AAAKBQYHCAMECQECCwEBAAEEAwEAAAAAAAAAAAAAAAUDBAYJAQIHCBAAAAYCAQAEBwkICQ0MBwcF +AgMEBQYHAQgAERIWCRMU1BWVVhghddaXOFiY2BkxUZGhUhfXuEGx0eEiMjNjtmGBcrLSI1NzJCU1 +dwpxwUJigqJDlDe3eMhEZbU2KEiI8JLCVNUnV8N2lmd6EQACAgIABAIDCQkMBQcHCAsCAwEEAAUR +EhMGFAchMVZRItOU1BUWCBhBkXKSI1OTN1dhcbEy0jNzs8MkVRmBUmLClkJjtCWVF1ihwbJDNNXW +0eGjVHQ1dbU2dziiJieCRKTECf/aAAwDAQACEQMRAD8An8cYxxjHGMcYxxjHGMcYxxjHGMcYxxjH +GMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcY +xxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjH +GM//0J/HGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcY +xxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjH +GMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjP/9GfxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcY +xxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjH +GMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcY +z//Sn8cYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjH +GMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcY +xxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGM//05/HGMcYxxjHGM8oLg212SYbxuyBwN4o9jiN +ZzeNQ5mJltOT2cSNeF0pWo7NXuTm+s2w1dNghCdbGPTEkFNZfgk6YvIjDBiFnHyB5wfWN3/lp3ne +7bqaem+quFyJGDJPgSVMnmmHhEzzGURwCOAxHrnjOfQfYHlDpu7+26W5s3rK7DOfmgTCB961gRwi +UnMegImeJTxmZ9UZYXtgbgeuetn0bbP+t/zyz7Z3c/s1Q/Eb8pzNfs8aD/FLn6RfyfHtgbgeumtn +0bLQ+t/97j7Z3c/s1Q/Eb8px9njQf4rc/SL+T599sDcH1y1s+jbZ/wBb/j7Z/c/s1Q/Eb8pzn7PG +g/xS5+kX8nz57YG4HrprZ9Gy0Oj9b/j7Z/c/s1Q/Eb8px9njQf4rc/SL+T49sDcD101r+jbaH1v+ +jj7Z/c/s1Q/Eb8px9njQf4pc/SL+T49sDcD1z1s+jbaH1v8Aj7Z/c/s1Q/Eb8px9njQf4pc/SL+T +49sDcD1z1s/qf/DZaH1v+Ptn9z8P/wBGqH4jflOPs8aD/FLn6RfyfPvtgbgeuetn9TPs22h0frf8 +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 +qw/RycPrB85+x5Q9vHfFB+UZz/mEbb9l1f48fyXPue42lHztWD6OLh/vbB44+x5Q9vXfFB+UY/zC +Nt+y6v8AHj+S58+w2k/ztWD6OTj9YTj7HlD29d8UH5RnH+YRtv2XV/jx/JcfYbSf52rD9HJw+sHx +9jyh7eO+KD8ox/mEbb9l1f48fyXPv2G0n+dqw/RycPrB8fY8oe3rvig/KM5/zCNt+y6v8eP5Lnz7 +DaUZ/wDm2YPo4uGP/MHx9jyh7eu+KD8ox/mEbb9l1f48fyXH2G0n+dqwdP8A4cnH6wnH2PKHt474 +oPyjH+YRtv2XV/jx/JcfYbSf52rD9HJx+sJzj7HlD29d8UH5Rj/MI237Lq/x4/kuffsNpP8AO1Yf +o5OP1g+c/Y8oe3rvig/KMf5hG2/ZdX+PH8lz59htKPnbMH0cnH6wnH2PKHt474oPyjH+YRtv2XV/ +j5/JcfYbSf52rB9HJx+sJx9jyh7eu+KD8ox/mEbb9l1f48fyXGe42k/ztWHH/wBOTj9YTj7HlD29 +d8UH5Rj/ADCNt+y6v8eP5Ln37DaUfO1YPo4uH1g+PseUPb13xQflGcf5hG2/ZdX+Pn8lx9htKP2d +tWD+tri4Y/8AMHzj7HlD29d8UH5RnP8AmEbb9l1f48fyXPn2G0o+dsw/RycPrCc5+x5Q9vXfFB+U +Y/zCNt+y6v8AHj+S4+w2lHztWD6OTh9YTj7HlD29d8UH5RnH+YRtv2XV/jx/Jc+/YbSj9jbVg/r6 +4r8/+YPj7HlD28d8UH5RnP8AmEbb9l1f48fyXH2G8o+drH/o4uH1g+PseUPb13xQflGcf5hG2/Zd +X+PH8lz59htKPnasP0cnH6wnH2PKHt674oPyjOf8wjbfsur/AB4/kufc9xtKM/8AzasH9bXFwx/5 +g+cfY8oe3rvig/KMf5hG2/ZdX+PH8lx9htKPnbMP0cnH6wnOfseUPb13xQflGcf5hG2/ZdW+PH8l +z59htKPnasH0cnH6wnH2PKHt674oPyjOf8wjbfsur/Hj+S59+w2lH3M7bMPR972cnH6wnH2PKHt4 +74oPyjH+YRtv2XV/jx/Jc+fYbSj52rD9HJw+sHx9jyh7eO+KD8ox/mEbb9l1f48fyXH2G0o+dqwf +RxcPrCcfY8oe3jvig/KMf5hG2/ZdX+Pn8lx9htKPnasH0cnD6wnH2PKHt474oPyjH+YRtv2XV/jx +/JcfYbSj52rD9HJx+sJx9jyh7eO+KD8ox/mEbb9l1f48fyXPv2G0n+dqwfRycPrB8fY8oe3rvig/ +KMf5hG2/ZdX+PH8lz59htKOj5WrB9HFw+sJx9jyh7eu+KD8ox/mEbb9l1f48fyXH2G0o+dswfRxc +frCcfY8oe3rvig/KMf5hG2/ZdX+Pn8lx9htKPnbMH0cXH6wnH2PKHt674oPyjH+YRtv2XV/j5/Jc +fYbSj52zB9HFx+sJx9jyh7eu+KD8ox/mEbb9l1f4+fyXH2G0o+dswfRxcfrCcfY8oe3rvig/KMf5 +hG2/ZdX+Pn8lx9htKPnbMH0cXH6wnH2PKHt674oPyjH+YRtv2XV/j5/JcfYbSj52zB9HFx+sJx9j +yh7eu+KD8ox/mEbb9l1f4+fyXH2G0o+dswfRxcfrCcfY8oe3rvig/KMf5hG2/ZdX+Pn8lx9htKPn +bMH0cXH6wnH2PKHt674oPyjH+YRtv2XV/j5/JcfYbSj52zB9HFx+sJx9jyh7eu+KD8ox/mEbb9l1 +f4+fyXPuO42lGP8A5tWDP+7ri4/WE4+x5Q9vXfFB+UY/zCNt+y6v8eP5Ln37DeT/ADtI/wDRxcPr +Cc4+x5Q9vXfFB+UY/wAwjbfsur/Hj+S4+w3k/wA7SP8A0cXD6wnH2PKHt674oPyjH+YRtv2XV/jx +/JcfYbyf52kf+ji4fWE4+x5Q9vXfFB+UY/zCNt+y6v8AHj+S4+w3k/ztI/8ARxcPrCcfY8oe3rvi +g/KMf5hG2/ZdX+PH8lx9hvJ/naR/6OLh9YTj7HlD29d8UH5Rj/MI237Lq/x4/kuPsN5P87SP/Rxc +PrCcfY8oe3rvig/KMf5hG2/ZdX+PH8lx9hvJ/naR/wCji4fWE4+x5Q9vXfFB+UY/zCNt+y6v8eP5 +Lj7DeT/O0j/0cXD6wnH2PKHt674oPyjH+YRtv2XV/jx/JcfYbyf52kf+ji4fWE4+x5Q9vXfFB+UY +/wAwjbfsur/Hj+S5bku7kizGiNPTpD9jYjNJM3t6hWzRNypt0hCOQrSAeELajJWXb0x8yDWdXICz +xNqoATMh6wcB6RBstj9UDo0bTdZ3oTr4hMgB14WJFHqGThxyPH7k8s+n18I9MSOo/wD+gZv2dJO6 +8uQRqyZENYu2TTAJn0kKyQEFw9fDmj0ceHGfROlvdkrCnHc/WFeTgWCVsumiwrA8dA8FKdYNgzi8 +Cx0+4LAB46eeWfVsUSfNvVJL+MA2In9+K74nPVvrtuCz5L1bC+PIy4go/eIgmP4cmA82YZqAxxjP +/9GfxxjHGMcYxxjIdfeo/K121+/56jf6qtBc1rfWJ/XJc/Cq/wBRXzbp9TP9RO3/AKa1/aZMU5sp +zUXjjGa7WIzv7TMATBsb/PbcsZiWd0RhUhIdG/xBcocEi5kMO/yQeVPjpgFac0ZGFGSkw/DAyn6h +vMTwziY455/Wx3f+vF6r32ZVqoVUJc6lQa6usmgaICVvdndWYYYNVZ1SLTEsekZLir63hl6UDc4K +BdYZa8WenOfKu9/JzsvvhTzs0Iq7Q4mYemIGeaePpMfQJ+meM/xSmfWWRtzV1LnGWL4N/wBaPX/8 ++edklilo0ZOW2rL2YkEeelidcfCZoxKD1da2oiSCxlWvh7urLIPQPSJP1BLWNeElyQ4H1uqcnyBQ +PWj51eTfdPltch1xEv0jCmF2AiZGf3C/1S92J/gmOMOVVtQxWz+J9yfuT/8AJOWOfVc3v6YK4JWq +JOvUNpaY+XyheYYXEYKgWYF4sdIXEgBozXVcWEQkbWmwYuVYDkXVATgRoe3kt5Vd2eYl3l09Pk1y +5jq2GcRUv9+eEyRT9wRgin08I4QUxHvouvs6a/QP3Z+5H/yz+5mfoppNT9RuLYWSyuFyW2IZSxG5 +PSApyPSriRhyBdG4hg0ceiiJKpxjJa5Xkw8kXRnKvGejmy3sfyY7O7KVXsHXi9ug4T13DHASjh/N +K4yIRE+mJKTOPXBR6smtdp6dGPyKuZv3Sn0z/wDN/oz1S1LpSwIjJ3aczk5Gg8bYE7Azx9vPMWDI +SCczXZQpe3LJZJK5cUcLASCyQiKSeEP6ppvhs9X01dZKXWXKGYNsxJfuzEcOPD3Zj1+7wjJ1YcnH +jPpnPQXlbKmOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGO +MY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMZDr +7q75WupXv1JP6/8A8K1+81rfV2/XJT/Ctf1FjNun1zP1E6n+mq/2eTFObKc1F44xn//Sn8cYxxjH +GMcYyHX3qPytdtffqN/qrUD938PNa31if1y3Pwqv9RXzbp9TP9RO3/prX9pkxTmynNReOMZxmFFm +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 +Y1S+9rl6yc29xqKNIaocSr1iTdK9asg6SCSNkhXrCEVV9RYy1jA6QIKp3FQr7JvZ1GgqPm7U7S3c +Kwz0WLInUinVQxUQyIFfO22Rlab0nQIADJYTw9/uWmX2OMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjG +OMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMZDr7q75W2pXv3JP1Vb+/c5rW+r +t+uSn+Fa/qLGbdPrmfqJ1H9NV/s8mKc2U5qLxxjP/9SfxxjHGMcYxxjIdXepfK1219+o3+qtQPNa +31if1yW/wqv9RXzbp9TP9RO3/p7X+/kxXGOjGMfe9z3c5zn+vnPu55spzUXjjGOMY4xjjGOMY4xj +jGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOM +Y4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xkOrurvlba +le/Uk/qf/Ktf3Na31dv1yU/wrX9RYzbp9cz9ROo/pqv9nkxXmynNReOMZ//Vn8cYxxjHGMcYyHV3 +qXytdtffqN/qrUDzWt9Yn9ctv8Kr/UV826fUz/UTt/6e1/v5MV5spzUXlpTcoo+PiJOLLOJOeYsU +aUaAJhRpRkoZgGFmFjxkAyxgznGcZxnGcZ6M87riJYET6uMfw5SdMwlsxPCYGf4MtrsxGvV5j9Eo +PJ+SfTX+bH70Zj/Xf+eP7847MRr1eY/RKDyfjpr/ADY/ejHXf+eP7847MRr1eY/RKDyfjpr/ADY/ +ejHXf+eP7847MRr1eY/RKDyfjpr/ADY/ejHXf+eP7847MRr1eY/RKDyfjpr/ADY/ejHXf+eP7847 +MRr1eY/RKDyfjpr/ADY/ejHXf+eP7847MRr1eY/RKDyfjpr/ADY/ejHXf+eP7847MRr1eY/RKDyf +jpr/ADY/ejHXf+eP7847MRr1eY/RKDyfjpr/ADY/ejHXf+eP7847MRr1eY/RKDyfjpr/ADY/ejHX +f+eP7847MRr1eY/RKDyfjpr/ADY/ejHXf+eP7847MRr1eY/RKDyfjpr/ADY/ejHXf+eP7847MRr1 +eY/RKDyfjpr/ADY/ejHXf+eP7847MRr1eY/RKDyfjpr/ADY/ejHXf+eP7847MRr1eY/RKDyfjpr/ +ADY/ejHXf+eP7847MRr1eY/RKDyfjpr/ADY/ejHXf+eP7847MRr1eY/RKDyfjpr/ADY/ejHXf+eP +7847MRr1eY/RKDyfjpr/ADY/ejHXf+eP7847MRr1eY/RKDyfjpr/ADY/ejHXf+eP7847MRr1eY/R +KDyfjpr/ADY/ejHXf+eP7847MRr1eY/RKDyfjpr/ADY/ejHXf+eP7847MRr1eY/RKDyfjpr/ADY/ +ejHXf+eP7847MRr1eY/RKDyfjpr/ADY/ejHXf+eP7847MRr1eY/RKDyfjpr/ADY/ejHXf+eP7847 +MRr1eY/RKDyfjpr/ADY/ejHXf+eP7847MRr1eY/RKDyfjpr/ADY/ejHXf+eP7847MRr1eY/RKDyf +jpr/ADY/ejHXf+eP7847MRr1eY/RKDyfjpr/ADY/ejHXf+eP7847MRr1eY/RKDyfjpr/ADY/ejHX +f+eP7847MRr1eY/RKDyfjpr/ADY/ejHXf+eP7847MRr1eY/RKDyfjpr/ADY/ejHXf+eP7847MRr1 +eY/RKDyfjpr/ADY/ejHXf+eP7847MRr1eY/RKDyfjpr/ADY/ejHXf+eP7847MRr1eY/RKDyfjpr/ +ADY/ejHXf+eP7847MRr1eY/RKDyfjpr/ADY/ejHXf+eP7847MRr1eY/RKDyfjpr/ADY/ejHXf+eP +7847MRr1eY/RKDyfjpr/ADY/ejHXf+eP7847MRr1eY/RKDyfjpr/ADY/ejHXf+eP7847MRr1eY/R +KDyfjpr/ADY/ejHXf+eP7847MRr1eY/RKDyfjpr/ADY/ejHXf+eP7847MRr1eY/RKDyfjpr/ADY/ +ejHXf+eP7847MRr1eY/RKDyfjpr/ADY/ejHXf+eP7847MRr1eY/RKDyfjpr/ADY/ejHXf+eP7847 +MRr1eY/RKDyfjpr/ADY/ejHXf+eP7847MRr1eY/RKDyfjpr/ADY/ejHXf+eP7847MRr1eY/RKDyf +jpr/ADY/ejHXf+eP7847MRr1eY/RKDyfjpr/ADY/ejHXf+eP7847MRr1eY/RKDyfjpr/ADY/ejHX +f+eP7847MRr1eY/RKDyfjpr/ADY/ejHXf+eP7847MRr1eY/RKDyfjpr/ADY/ejHXf+eP7847MRr1 +eY/RKDyfjpr/ADY/ejHXf+eP7847MRr1eY/RKDyfjpr/ADY/ejHXf+eP7847MRr1eY/RKDyfjpr/ +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 +d2NmnD7N1zmS+yt0oKtXRMVvEsOK7orOYlh1oBpbawOzYzFZPXWtxrY+EyxvqGNvIFGSmYhpIQNb +ZhrymyiOdUkqHgsTUMI1pTSJoIPyBKarLVmFphfUSe9dIfmNuPK6olvzrQ1025ZxR0SSLUJiACHe +KkZmwvlsTVGiZC1C7RWUtQHgXc/Ze53mi7s84gu1i0Lt/YTI8XE0mNZLebnhRVY49SJhJWotmHM8 +EHXEnRsZzM88jxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMc +YxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjMff+jNnvGwf+xEHIXMqzFt3/APYtb3+q+f8A9FHb +jGd/Qb5FGrH+oyuv6OIeMZtzxjIdXdXfK21L9+pJ+qtf3Na31dv1yVPwrX9RYzbp9cz9ROo/pqv9 +nkxXmynNReOMZ//Tn8cYxxjHGMcYyHV3qXytdtffqN/qrUDzWt9Yn9ctv8Kr/UV826fUz/UTt/6e +1/v5MV5spzUXlqzL/QYffyKf0qZed1/zi/wo/hyk/wDmHfgT/BnU5L5jWOMY4xjjGOMY4xjjGOMY +4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjj +GOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGY+/9GbPeNg/9iIOQuZVmLbv/wCx +a3v9V8//AKKO3GM7+g3yKNWP9Rldf0cQ8YzbnjGQ6u6u+VtqX79ST9Va/ua1vq7frkqfhWv6ixm3 +T65n6idR/TVf7PJivNlOai8cYz//1J/HGMcYxxjHGMh1d6l8rXbX36jf6q1A81rfWJ/XLb/Cq/1F +fNun1M/1E7f+ntf7+TFebKc1F5asy/0GH38in9KmXndf84v8KP4cpP8A5h34E/wZ1OS+Y1nTG4t5 +bgnaTFyMDqrRrHFK2DVEBcFLe3nIUy9cnRiHhScjQqHNMWcaEOQFDUFBFnGTA4zQizXmwVSHh4sQ +g5DmjngCmRgpHjxgZkSiC4cJkZiJ4xOXA1LZVG3xqsmitgLJkDPTFjBMgAj4csGYrYQDM8xCs5iJ +gS4ftYsSN6RUvXqk6FChTnrFq1YeUmSI0iYoRylUqUnCASnTpyQZGMY84CAOM5znGMc6XbtPW07e +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 +T9/whnT+UL7uWMurjGQ6u6u+VtqX79ST9Va/ua1vq7frkqfhWv6ixm3T65n6idR/TVf7PJivNlOa +i8cYz//Xn8cYxxjHGMcYyHV3qXytdtffqN/qrUDzWt9Yn9ctv8Kr/UV826fUz/UTt/6e1/v5MV5s +pzUXlqzL/QYffyKf0qZed1/zi/wo/hyk/wDmHfgT/BnU5L5jWOMY4xjjGOMY4xjjGOMY4xjjGOMY +4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjj +GOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGcH8b/jdb/l9fr/9a8J4Txr+e6/hv+m8N/nC +FzKsfxv+N1v+X1+v/wBa8J4Txr+e6/hv+m8N/nBjKlC89ZiyLrdbrPkrz1ut1+t0yp5z1uv4dT1+ +n7/hDOn8oX3csZdXGMh1d1d8rbUv36kn6q1/c1rfV2/XJU/Ctf1FjNun1zP1E6j+mq/2eTFebKc1 +F44xn//Qn8cYxxjHGMcYyHV3qXytdtffqN/qrUDzWt9Yn9ctv8Kr/UV826fUz/UTt/6e1/v5MV5s +pzUXlqzL/QYffyKf0qZed1/zi/wo/hyk/wDmHfgT/BnU5L5jWRm+/a3PuHWR3QqYbsluHrtSP5k7 +fjF1yyqdd3Q2t4nZMgr99Wa1PzHsDJe72u2Nedp/ZitJFHotltaOObKJS3qEhSFWUqVjwTc3LjJ7 +xoqttEy1jRoAfNX622EqbQqqcM1Wyk6E3Xy1DnxNhbAO1T8GSLObaOrTEO1LDaayMd1WZbZEC7pa +k5aqy565N6xJFhaISplQjbNgVsRYRaCxS1i7tTdDYfZjXi5Rud8747GVaTpbBI7T0knLa564Q+dW +/G6vTvm1EhJ7wSK93hU7PTDrVssalcVj8gklvvjksXInBatMWKFKNak9K70KkjT99bZkHWQndnar +2OavTaOiQ2rK9jWCxNPXOYcsfYmi9A1nLrTWtLp0F2bNrBu1+uG17I1XKDNgytKrSpB1xQ7J0W+l +Qf0yu3IQVearG2wlViu1qvAlceakD5aXft3dOdh5DHFG8WzLNGDb+s98RWJPt8MRBW/wil9etI35 +ho9xb6971zu1NFS2Wcvt4vq+RONcuxkgWrygmR4wSHBxgcdc9lUd1aYtU3aC9y40D4kQtWJ7n7q1 +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 +Xqhr/DeH6EIZLOsex3BbHq19k061CrTlLoMptpcjD5qb6kzz2EMIiZNi8BuVfc8nG9TAAZXFHWeB +u7WjUQjWICNhj2wmxNh1dEov2Gp+mLOfawXV/SkIJVJBtkYiS+FVPBbJnKdgaGxG1tq2fSGZOyBu +S9QhWAxQtNUy03LlhRltLR3doQqErTuHXPphyETOlC0sa+YBj3mknsYMn1Il1jrUbAV2P56VNNKl +12O8PXGATDGSczyRPMakhLW9OopgUw5wga/CtTivt7y3znHGMcYxxjHGMcYxxjHGMcYxxjHGM0K3 +b23aNHNcHzZaVUrfF4QOumOOOVis+u8chEum8JhBcbCoerNd45NbDrrx6BxHxYvL0obT1ytrSH5c +FCYDWkcVyKFzKs1T1Q7xuA95tpxfF90/Q2y1T1ClhtgxyHzbYSJVvDm+2XBvjUnRStRV6SF2vYzq +/sMJdUGG9xdVCdE1jdBmoUahWrQOpKBjPR3Qb5FGrH+oyuv6OIeMZtzxjIdXdXfK21L9+pJ+qtf3 +Na31dv1yVPwrX9RYzbp9cz9ROo/pqv8AZ5MV5spzUXjjGf/Sn8cYxxjHGMcYyHV3qXytdtffqN/q +rUDzWt9Yn9ctv8Kr/UV826fUz/UTt/6e1/v5MV5spzUXlqzL/QYffyKf0qZed1/zi/wo/hyk/wDm +HfgT/BnU5L5jWOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjj +GOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY +4xjjGee6vcxnTGhRk62bruBbemRNoXBHqja4Ea/zajIQCWowL2dCvCjViT5MKweQQd4MWPCFgH0g +xEdNn5svvTmS9dH54PvxmJXzYeJJKWeKdrfUPbeDx1LV7hWkCi7Hp/YUahcQZSYodFosws7IwsQU +Mfi8fQhITp0qJLgpIkJCWSV1QhBx02fmy+9OOuj88H34zfDR9md47p/rbH5A1OTE/sVPQhmfGN5Q +qmt3ZndrZUyJyanVtWlELW5yblpAyTyDgANJNAIAw4FjOOdJiYnhPrypExMRMTxic2n4znIdXdXf +K21L9+pJ+qtf3Na31dv1yVPwrX9RYzbp9cz9ROo/pqv9nkxXmynNReOMZ//Tn8cYxxjHGMcYyHV3 +qXytdtffqN/qrUDzWt9Yn9ctv8Kr/UV826fUz/UTt/6e1/v5MV5spzUXnWVo0jgnMSL0qZakN6nh +UqsgpSnN8GMJoPCEnBGWPqGAwLHTjPQLGM/dxxjKL2OiPqtHPQjZ5LxjHY6I+q0c9CNnkvGMdjoj +6rRz0I2eS8Yx2OiPqtHPQjZ5LxjHY6I+q0c9CNnkvGMdjoj6rRz0I2eS8Yx2OiPqtHPQjZ5LxjHY +6I+q0c9CNnkvGMdjoj6rRz0I2eS8Yx2OiPqtHPQjZ5LxjHY6I+q0c9CNnkvGMdjoj6rRz0I2eS8Y +x2OiPqtHPQjZ5LxjHY6I+q0c9CNnkvGMdjoj6rRz0I2eS8Yx2OiPqtHPQjZ5LxjHY6I+q0c9CNnk +vGMdjoj6rRz0I2eS8Yx2OiPqtHPQjZ5LxjHY6I+q0c9CNnkvGMdjoj6rRz0I2eS8Yx2OiPqtHPQj +Z5LxjHY6I+q0c9CNnkvGMdjoj6rRz0I2eS8Yx2OiPqtHPQjZ5LxjHY6I+q0c9CNnkvGMdjoj6rRz +0I2eS8Yx2OiPqtHPQjZ5LxjHY6I+q0c9CNnkvGMdjoj6rRz0I2eS8Yx2OiPqtHPQjZ5LxjHY6I+q +0c9CNnkvGMdjoj6rRz0I2eS8Yx2OiPqtHPQjZ5LxjHY6I+q0c9CNnkvGMdjoj6rRz0I2eS8Yx2Oi +PqtHPQjZ5LxjHY6I+q0c9CNnkvGMdjoj6rRz0I2eS8Yx2OiPqtHPQjZ5LxjHY6I+q0c9CNnkvGMd +joj6rRz0I2eS8Yx2OiPqtHPQjZ5LxjHY6I+q0c9CNnkvGMdjoj6rRz0I2eS8Yx2OiPqtHPQjZ5Lx +jHY6I+q0c9CNnkvGMdjoj6rRz0I2eS8Yx2OiPqtHPQjZ5LxjHY6I+q0c9CNnkvGMdjoj6rRz0I2e +S8Yx2OiPqtHPQjZ5LxjHY6I+q0c9CNnkvGMdjoj6rRz0I2eS8Yx2OiPqtHPQjZ5LxjHY6I+q0c9C +NnkvGMdjoj6rRz0I2eS8YytJEaRvTlpECVMiSFdfwSVIQUmTleEGI0fgySQgLB1zB5FnoxjpFnOf +u54xnZ4xkOrurvlbal+/Uk/VWv7mtb6u365Kn4Vr+osZt0+uZ+onUf01X+zyYrzZTmovHGM//9Sf +xxjHGMcYxxjIdXeo+7trtr79Rv8AVWoHmtb6xP65Lc/7VX+or5t0+pn+onb/ANPa/wB/Jigc4EEI +sfcFjGcdP3ejOOn3ebKc1Fz6J4Z94xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY +4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjj +GOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGfM56MZz97Gc/g4xkOzur8dG22pX9V6kn6q1/fuc1rfV +2/XJT/Ctf1FjNun1zP1E6j+mq/2eTFObKc1F44xn/9WfxxjHGMcYxxjIdfeo/K2209+41+qtQPNa +31if1x3Pwqv9RXzbp9TP9RO3/p7X+/kxAr+SL/xYP7XHNlEeqM1GF65/fzk5znGfM5xjGc5zjGMY +6c5z7mMYx93Oc/e51MwWBsYcCsYmZmZ4RER6ZmZn0RER65xEcfRHryP+/wDfz1W7vlit1Tl6bImq +tryZ6Afn/Z3vHqUp1pbZEug0qsUyzZC/0JC9w4PHKEemlkSMrA+nPI3hfNVKpgcWVnWN5ojLXX2S +2Gp0G6FlYKmxiSXEt4ksRW8pS6RCVeMYaCZVTXbZr26ItvKucq4UchsqPzZsN3q29U7tClDzEQji +fNtauriFrIxeIIl5PvTZTWdTDwsFXYNwWKzNVXe/R+WUnaFuP1YV1aY6+2jZtYWXGiO19Q7NVTYT +o8UVC74OmTBsDeqXSir2phiTFJlqJ/8AOahIW2LWc8ODz856obrbvq6eh2Xesw9Y7iNmXFwqrrrr +1Stras2GNa6Bmr4PUWHi6Igp5gCFzHE8tE12uubGqpyGdCjr7HKomOcTNjtJ1FepKVqIhslZJBCE +zMSl4Mkh9U4lqfv/AClrUn4K5aaMLd5LK582xCpGGue8Z7lezJfPETykZE7WashrT3mLc+N8yWSd +YtSFsTMCSCOTJ05xSow9UNEmkdXr27RtCouZG4yWy3gDGLStbGz1uKgNzFhTALNmRrwSS6ygF4JF +7o3Y3Va4Ltpsj4BYL5CkwWbDIA5lzDCFQT4gpSmZfMNHpsPokcqD30DnOQhzkOQZzjGchF1ciDnO +OnIRdUQg9OPuZ6M5x/V5YzHCZiJ4xl2BSQARBIlMRPCeHGP3J4TMcY9U8JmPcmYzxZ7xG9WPXm14 ++atU3k7GWGzhdDkUS2vtKoo+xmM5KFkLTMkIikek6IRSolJhQrPJAnLwpNyIzrGHdOcr0WiqbOhc +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 +jOIJOomRIqy1T3snqSuXp/bnpjjkwi0pWaw09IXZ0YyVKVzDjCNnNJWgESUf0FgVDwSn2Kej7r1e +yqWtLtNBUtodK7W20NebILIGNS1Q7S4sBZMGr+O6CCYIh9MrjIn9wjsNPbquTfqbFyWBBJp7FkKI +oIQMDmogikeMH/FCYL0RPogp8lKlohRXtASepF9dT93kcomGt8kTvL1Re8L5B62lVSNB7DK74piv +4x3ZdVpoTcyxnbUBBPnFTIO04x4HJnFyITLUj/8ARXcXdobnvGh3GndU10q9bZKkAv6Jb7KrhwxV +C7Yb3Pbl9ITJhF0xr+FiOFBCDNTKfmOs0pUdHY1Z0HlYY2qcEVfYEtRoHlOyhQalMLfIwMRzS3re +uwxkCYvr7fTbkXoRWGryOKSeuJvXd6wqz5wjrrUffdzrfZhhjLkBU5gtdysjS+W+LSd+8MmVmp3m +KzqN4XxptLA2ltok7c0Wju5kF5vb7v1mxRd1V3Uvqomzt9ANnWMaPAfCDW3SeKl8CCCTboWenZfM +vJ8G6zWDUsjsrXduBWZXuIurcyFUtlKrYhPGetLaB8DL0FMMTYVzKXELhcitXsPoYzkxLV+va9KK +s4n823nqGhKtki1xSRMgTPCx3j7age7iobWuTyOMMkYeUKFuOTxFA2oCE2GxOM/xAZovmrzdslse +/dzuSKhPjuR3GpNTpSUhAMIgp39mpbTaBsZBXGNYRdc4DrQMeq9lqir27RoxFiPD8y/y0O54iCkh +iCfWqGYCBCIzCBAYjpjJckzm4nPNMyrHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcY +xxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjPyP8Aii/sc/tZ5xPq +nOY9cZDu7rH5W+pHvzJP1Vb/AOa1/q7frkp/hWv6ixm3T65n6idT/TVf7PJifNlOaiscYz//15/H +GMcYxxjHGMh196j8rbbT37jX6q1A81rfWJ/XHc/Cq/1FfNun1M/1E7f+ntf7+TECv5Iv/Fg/tcc2 +UR6ozUYXrn9/OTnOcY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4x +jjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGOMY4xjjGO +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 +/wCJI+874HIvp3/8Lsffr/D48Tur5utx+ntbfrFcc1H/ABJH3nfA46d//C7H36/w+PE7q+brcfp7 +W36xXHNR/wASR953wOOnf/wux9+v8PjxO6vm63H6e1t+sVxzUf8AEkfed8Djp3/8Lsffr/D48Tur +5utx+ntbfrFcc1H/ABJH3nfA46d//C7H36/w+PE7q+brcfp7W36xXHNR/wASR953wOOnf/wux9+v +8PjxO6vm63H6e1t+sVxzUf8AEkfed8Djp3/8Lsffr/D48Tur5utx+ntbfrFcc1H/ABJH3nfA46d/ +/C7H36/w+PE7q+brcfp7W36xXHNR/wASR953wOOnf/wux9+v8PmVdd4vYaKyLSl8zruSwBseoDUE +WZASl2r1wcHdwiclu15fDiU9fzqdpkiNIlnTeAIlJxIzRiH1AZwDOeWeybWKrUSiyLDFjCnlg4iI +IVRH8cA9PvJ9UTl/qk2htXH2KpqAlKGOaQmZkSdM/wAQz4REGPrmOObfchsnc/I/4ov7HP7WecT6 +pzmPXGQ7u6x+VvqR78yT9VW/+a1/q7frkp/hWv6ixm3T65n6idT/AE1X+zyYnzZTmorHGM//1Z/H +GMcYxxjHGMh196j8rXbXP/rqN/i1WoH+rzWt9Yn9ctv8Kr/UV826fUz/AFE7f+mtf2mTFMYxjGMY +x0Yx7mMY+5jH3sc2U5qLxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcY +xxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjH +GMcYxxjHGMcYxxjHGMcYxxjHGMcYyHX3V/u7balfs/56kn6qt/c1rfV2/XJT/Ctf1FjNun1zP1E6 +j+mq/wBnkxTmynNReOMZ/9afxxjHGMcYxxjIh/eUMat53Q2aIA2rVyJTNIUiU5TpVBpYgG6wa8gO +JyYSAWAjyUb9zp6cYFjP7OOa0vrJhYjzX2z0rKZEa8xMRM+mKyJ/e9Hozbx9Sd9GPJx9a5YWMMuP +iRIoGZEiOJ9cxPCfTHHMtRLvWN6YpGmaNmtVSTQbIgTt2JROKrsFZLXktMDwZa2QLYzakTZFjmMs +OMGHENyXBosdYQcjyIWcg131qPMajRq036KjZasIGWsB/OfD7pcjBHj7swMcfXPGeM5Gbf6kXk3s +tldv1e79hTQ1klCVOqytfGePKHUUZ8sfciSnh6o4RwjLi+143k9Q9efiiuD9O3L37WXmD7Kaz8Sz +8Nkd9hXyi/aFtv0tL4DH2vG8vqHrz8UVwfp14+1l5g+yms/Es/DY+wr5RftC236Wl8Bj7XjeX1D1 +5+KK4P068fay8wfZTWfiWfhsfYV8ov2hbb9LS+Ax9rxvL6h68/FFcH6dePtZeYPsprPxLPw2PsK+ +UX7Qtt+lpfAY+143l9Q9efiiuD9OvH2svMH2U1n4ln4bH2FfKL9oW2/S0vgMfa8by+oevPxRXB+n +Xj7WXmD7Kaz8Sz8Nj7CvlF+0LbfpaXwGPteN5fUPXn4org/Trx9rLzB9lNZ+JZ+Gx9hXyi/aFtv0 +tL4DH2vG8vqHrz8UVwfp14+1l5g+yms/Es/DY+wr5RftC236Wl8Bj7XjeX1D15+KK4P068fay8wf +ZTWfiWfhsfYV8ov2hbb9LS+Ax9rxvL6h68/FFcH6dePtZeYPsprPxLPw2PsK+UX7Qtt+lpfAY+14 +3l9Q9efiiuD9OvH2svMH2U1n4ln4bH2FfKL9oW2/S0vgMfa8by+oevPxRXB+nXj7WXmD7Kaz8Sz8 +Nj7CvlF+0LbfpaXwGPteN5fUPXn4org/Trx9rLzB9lNZ+JZ+Gx9hXyi/aFtv0tL4DH2vG8vqHrz8 +UVwfp14+1l5g+yms/Es/DY+wr5RftC236Wl8Bj7XjeX1D15+KK4P068fay8wfZTWfiWfhsfYV8ov +2hbb9LS+Ax9rxvL6h68/FFcH6dePtZeYPsprPxLPw2PsK+UX7Qtt+lpfAY+143l9Q9efiiuD9OvH +2svMH2U1n4ln4bH2FfKL9oW2/S0vgMfa8by+oevPxRXB+nXj7WXmD7Kaz8Sz8Nj7CvlF+0LbfpaX +wGPteN5fUPXn4org/Trx9rLzB9lNZ+JZ+Gx9hXyi/aFtv0tL4DH2vG8vqHrz8UVwfp14+1l5g+ym +s/Es/DY+wr5RftC236Wl8Bj7XjeX1D15+KK4P068fay8wfZTWfiWfhsfYV8ov2hbb9LS+Ax9rxvL +6h68/FFcH6dePtZeYPsprPxLPw2PsK+UX7Qtt+lpfAY+143l9Q9efiiuD9OvH2svMH2U1n4ln4bH +2FfKL9oW2/S0vgMfa8by+oevPxRXB+nXj7WXmD7Kaz8Sz8Nj7CvlF+0LbfpaXwGPteN5fUPXn4or +g/Trx9rLzB9lNZ+JZ+Gx9hXyi/aFtv0tL4DH2vG8vqHrz8UVwfp14+1l5g+yms/Es/DY+wr5RftC +236Wl8Bj7XjeX1D15+KK4P068fay8wfZTWfiWfhsfYV8ov2hbb9LS+Ax9rxvL6h68/FFcH6dePtZ +eYPsprPxLPw2PsK+UX7Qtt+lpfAY+143l9Q9efiiuD9OvH2svMH2U1n4ln4bH2FfKL9oW2/S0vgM +fa8by+oevPxRXB+nXj7WXmD7Kaz8Sz8Nj7CvlF+0LbfpaXwGPted5MfdgevX9aorf/373xx9rLzB +9lNZ+JZ+Gx9hXyj/AGg7b9LS+Ax9r1vH6h69fFFb36eOPtY+YPsrrPxLPw2PsK+Uf7Qdt+lpfAY+ +163j9Q9eviit79PHH2sfMH2V1n4ln4bH2FfKP9oO2/S0vgMfa9bx+oevXxRW9+njj7WPmD7K6z8S +z8Nj7CvlH+0HbfpaXwGPtet4/UPXr4ore/Txx9rHzB9ldZ+JZ+Gx9hXyj/aDtv0tL4DH2vW8fqHr +18UVvfp44+1j5g+yus/Es/DY+wr5R/tB236Wl8Bj7XreP1D16+KK3v08cfax8wfZXWfiWfhsfYV8 +o/2g7b9LS+Ax9r1vH6h69fFFb36eOPtY+YPsrrPxLPw2PsK+Uf7Qdt+lpfAY+163j9Q9eviit79P +HH2sfMH2V1n4ln4bH2FfKP8AaDtv0tL4DH2vW8fqHr18UVvfp44+1j5g+yus/Es/DY+wr5R/tB23 +6Wl8Bj7XreP1D16+KK3v08cfax8wfZXWfiWfhsfYV8o/2g7b9LS+Ax9r1vH6h69fFFb36eOPtY+Y +PsrrPxLPw2PsK+Uf7Qdt+lpfAY+163j9Q9eviit79PHH2sfMH2V1n4ln4bH2FfKP9oO2/S0vgMfa +9bx+oevXxRW9+njj7WPmD7K6z8Sz8Nj7CvlH+0HbfpaXwGPtet4/UPXr4ore/Txx9rHzB9ldZ+JZ ++Gx9hXyj/aDtv0tL4DH2vW8fqHr18UVvfp44+1j5g+yus/Es/DY+wr5R/tB236Wl8Bj7XreP1D16 ++KK3v08cfax8wfZXWfiWfhsfYV8o/wBoO2/S0vgMfa9bx+oevXxRW9+njj7WPmD7K6z8Sz8Nj7Cv +lH+0HbfpaXwGPtet4/UPXr4ore/Txx9rHzB9ldZ+JZ+Gx9hXyj/aDtv0tL4DH2vW8fqHr18UVvfp +44+1j5g+yus/Es/DY+wr5R/tB236Wl8Bj7XreP1D16+KK3v08cfax8wfZXWfiWfhsfYV8o/2g7b9 +LS+Ax9r1vH6h69fFFb36eOPtY+YPsrrPxLPw2PsK+Uf7Qdt+lpfAY+163j9Q9eviit79PHH2sfMH +2V1n4ln4bH2FfKP9oO2/S0vgMfa9bx+oevXxRW9+njj7WPmD7K6z8Sz8Nj7CvlH+0HbfpaXwGPte +t4/UPXr4ore/Txx9rHzB9ldZ+JZ+Gx9hXyj/AGg7b9LS+Ax9r1vH6h69fFFb36eOPtY+YPsrrPxL +Pw2PsK+Uf7Qdt+lpfAY+163j9Q9eviit79PHH2sfMH2V1n4ln4bH2FfKP9oO2/S0vgMfa9bx+oev +XxRW9+njj7WPmD7K6z8Sz8Nj7CvlH+0HbfpaXwGPtet4/UPXr4ore/Txx9rHzB9ldZ+JZ+Gx9hXy +j/aDtv0tL4DLdlves70yuNPUbIaqlhg3pAe3ZlMHquwUMuZQKQZLMWR9bJrVlrIicwF5zgo49uU4 +KFnrBDgeAixZbH60/mNeo2qaNFRrNYEjDVg/nDj/AMoedhDx9yZGeHrjhPCckdT9SLyb1uypX7Xd ++wuIUyClLW1YWyInjyn01AfLP3Ygo4+qeMcYnEvdrsitn3Q1kIG2LUKJLNJqiTZUJlJRYQE6w7Dh +JJCYcAOBCwSV7mOnpzgOc/f5j/1bAsT5r6l7llHMNjjMxMRxmtYn/wAvpyT+uw+jPk4irTsLKAuI +iIEoKYESCI9UzPCPRHHJeHNluah8cYz/15/HGMcYxxjHGMwPM9WdYrHkrlM7D1yoeeTB58T88SuZ +1DX0okrr5uQJWpv85Pr5Hlzou8Ra0JCYnwpovBJyQFh6AADjEBd7U7X2Vlt3Y9t0LFw+HMxldJmX +CIGOYiCSngMREcZ9ERER6IyXq9w7+igKtLeXE1R48oA5gDHGZmeAiURHGZmZ4R6ZmZ9c5a/sQ6Xf +ND1f+IGqPgny1+g3ZXsfq/iiPg8uPpX3T7S7D4w7+Xn32ItL/mh6wfEFVPwT4+g3ZXsfq/iiPg85 ++lndPtLsPjDv5ePYi0v+aJrB8QVU/BPj6Ddlex+r+KI+Dx9LO6faXYfGHfy8exFpf80TWD4gqp+C +fH0G7K9j9X8UR8Hj6Wd0+0uw+MO/l49iLS/5omsHxBVT8E+PoN2V7H6v4oj4PH0s7p9pdh8Yd/Lx +7EWl/wA0TWD4gqp+CfH0G7K9j9X8UR8Hj6Wd0+0uw+MO/l49iLS/5omsHxBVT8E+PoN2V7H6v4oj +4PH0s7p9pdh8Yd/Lx7EWl/zRNYPiCqn4J8fQbsr2P1fxRHwePpZ3T7S7D4w7+Xj2ItL/AJomsHxB +VT8E+PoN2V7H6v4oj4PH0s7p9pdh8Yd/Lx7EWl/zRNYPiCqn4J8fQbsr2P1fxRHwePpZ3T7S7D4w +7+Xj2ItL/miawfEFVPwT4+g3ZXsfq/iiPg8fSzun2l2Hxh38vHsRaX/NE1g+IKqfgnx9BuyvY/V/ +FEfB4+lndPtLsPjDv5ePYi0v+aJrB8QVU/BPj6Ddlex+r+KI+Dx9LO6faXYfGHfy8exFpf8ANE1g ++IKqfgnx9BuyvY/V/FEfB4+lndPtLsPjDv5ePYi0v+aJrB8QVU/BPj6Ddlex+r+KI+Dx9LO6faXY +fGHfy8exFpf80TWD4gqp+CfH0G7K9j9X8UR8Hj6Wd0+0uw+MO/l49iLS/wCaJrB8QVU/BPj6Ddle +x+r+KI+Dx9LO6faXYfGHfy8exFpf80TWD4gqp+CfH0G7K9j9X8UR8Hj6Wd0+0uw+MO/l49iLS/5o +msHxBVT8E+PoN2V7H6v4oj4PH0s7p9pdh8Yd/Lx7EWl/zRNYPiCqn4J8fQbsr2P1fxRHwePpZ3T7 +S7D4w7+Xj2ItL/miawfEFVPwT4+g3ZXsfq/iiPg8fSzun2l2Hxh38vHsRaX/ADRNYPiCqn4J8fQb +sr2P1fxRHwePpZ3T7S7D4w7+Xj2ItL/miawfEFVPwT4+g3ZXsfq/iiPg8fSzun2l2Hxh38vHsRaX +/NE1g+IKqfgnx9BuyvY/V/FEfB4+lndPtLsPjDv5ePYi0v8AmiawfEFVPwT4+g3ZXsfq/iiPg8fS +zun2l2Hxh38vHsRaX/NE1g+IKqfgnx9BuyvY/V/FEfB4+lndPtLsPjDv5ePYi0v+aJrB8QVU/BPj +6Ddlex+r+KI+Dx9LO6faXYfGHfy8exFpf80TWD4gqp+CfH0G7K9j9X8UR8Hj6Wd0+0uw+MO/l49i +LS/5omsHxBVT8E+PoN2V7H6v4oj4PH0s7p9pdh8Yd/Lx7EWl/wA0TWD4gqp+CfH0G7K9j9X8UR8H +j6Wd0+0uw+MO/l49iLS/5omsHxBVT8E+PoN2V7H6v4oj4PH0s7p9pdh8Yd/Lz57EWl3zQ9X/AIgq +p+CfH0G7K9j9X8UR8HnH0s7p9pdh8Yd/Lx7EOl3zQ9X/AIgap+CfH0G7K9j9X8UR8Hj6V90+0uw+ +MO/l49iHS75oer/xA1T8E+PoN2V7H6v4oj4PH0r7p9pdh8Yd/Lx7EOl3zQ9X/iBqn4J8fQbsr2P1 +fxRHwePpX3T7S7D4w7+Xj2IdLvmh6v8AxA1T8E+PoN2V7H6v4oj4PH0r7p9pdh8Yd/Lx7EOl3zQ9 +X/iBqn4J8fQbsr2P1fxRHwePpX3T7S7D4w7+Xj2IdLvmh6v/ABA1T8E+PoN2V7H6v4oj4PH0r7p9 +pdh8Yd/Lx7EOl3zQ9X/iBqn4J8fQbsr2P1fxRHwePpX3T7S7D4w7+Xj2IdLvmh6v/EDVPwT4+g3Z +Xsfq/iiPg8fSvun2l2Hxh38vHsQ6XfND1f8AiBqn4J8fQbsr2P1fxRHwePpX3T7S7D4w7+Xj2IdL +vmh6v/EDVPwT4+g3ZXsfq/iiPg8fSvun2l2Hxh38vHsQ6XfND1f+IGqfgnx9BuyvY/V/FEfB4+lf +dPtLsPjDv5ePYh0u+aHq/wDEDVPwT4+g3ZXsfq/iiPg8fSvun2l2Hxh38vHsQ6XfND1f+IGqfgnx +9BuyvY/V/FEfB4+lfdPtLsPjDv5ePYh0u+aHq/8AEDVPwT4+g3ZXsfq/iiPg8fSvun2l2Hxh38vH +sQ6XfND1f+IGqfgnx9BuyvY/V/FEfB4+lfdPtLsPjDv5ePYh0u+aHq/8QNU/BPj6Ddlex+r+KI+D +x9K+6faXYfGHfy8exDpd80PV/wCIGqfgnx9BuyvY/V/FEfB4+lfdPtLsPjDv5ePYh0u+aHq/8QNU +/BPj6Ddlex+r+KI+Dx9K+6faXYfGHfy8exDpd80PV/4gap+CfH0G7K9j9X8UR8Hj6V90+0uw+MO/ +l49iHS75oer/AMQNU/BPj6Ddlex+r+KI+Dx9K+6faXYfGHfy8exDpd80PV/4gap+CfH0G7K9j9X8 +UR8Hj6V90+0uw+MO/l49iHS75oer/wAQNU/BPj6Ddlex+r+KI+Dx9K+6faXYfGHfy8exDpd80PV/ +4gap+CfH0G7K9j9X8UR8Hj6V90+0uw+MO/l49iHS75oer/xA1T8E+PoN2V7H6v4oj4PH0r7p9pdh +8Yd/Lx7EOl3zQ9X/AIgap+CfH0G7K9j9X8UR8Hj6V90+0uw+MO/l49iHS75oer/xA1T8E+PoN2V7 +H6v4oj4PH0r7p9pdh8Yd/Lx7EOl3zQ9X/iBqn4J8fQbsr2P1fxRHwePpX3T7S7D4w7+Xj2IdLvmh +6v8AxA1T8E+PoN2V7H6v4oj4PH0r7p9pdh8Yd/Lx7EWl3zQ9X/iCqn4J8fQbsr2P1fxRHwePpX3T +7S7D4w7+Xl0QzVnWKuJK2zOvNcqHgcwZvHPM8shlQ19F5K1ecUCpqcPNr6xx5C6IfHmtcemO8EaH +wqc4ZYukAxYzdUu1e19bZVd13bdCvcDjysXXSBjxiRnlIQgo4jMjPCfTEzE+icoWu4d/eQyrd3lx +1Y+HMBuYYzwmJjiJFMTwmImOMeiYifXmeOT+Q+OMZ//Qn8cYxxjHGMcYxxjHGMcYxxjHGMcYxxjH +GMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcY +xxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjH +GM//0Z/HGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcY +xxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjH +GMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjP/9KfxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcY +xxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjH +GMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcY +z//Tn8cYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjH +GMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcY +xxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGM//1J/HGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjH +GMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcYxxjHGMcY +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 +AAAAAENsclMAAAAAUkdCQwAAAABJbnRlZW51bQAAAABJbnRlAAAAAEltZyAAAAAATXBCbGJvb2wB +AAAAD3ByaW50U2l4dGVlbkJpdGJvb2wAAAAAC3ByaW50ZXJOYW1lVEVYVAAAAAEAAAA4QklNBDsA +AAAAAbIAAAAQAAAAAQAAAAAAEnByaW50T3V0cHV0T3B0aW9ucwAAABIAAAAAQ3B0bmJvb2wAAAAA +AENsYnJib29sAAAAAABSZ3NNYm9vbAAAAAAAQ3JuQ2Jvb2wAAAAAAENudENib29sAAAAAABMYmxz +Ym9vbAAAAAAATmd0dmJvb2wAAAAAAEVtbERib29sAAAAAABJbnRyYm9vbAAAAAAAQmNrZ09iamMA +AAABAAAAAAAAUkdCQwAAAAMAAAAAUmQgIGRvdWJAb+AAAAAAAAAAAABHcm4gZG91YkBv4AAAAAAA +AAAAAEJsICBkb3ViQG/gAAAAAAAAAAAAQnJkVFVudEYjUmx0AAAAAAAAAAAAAAAAQmxkIFVudEYj +Umx0AAAAAAAAAAAAAAAAUnNsdFVudEYjUHhsQFIAAAAAAAAAAAAKdmVjdG9yRGF0YWJvb2wBAAAA +AFBnUHNlbnVtAAAAAFBnUHMAAAAAUGdQQwAAAABMZWZ0VW50RiNSbHQAAAAAAAAAAAAAAABUb3Ag +VW50RiNSbHQAAAAAAAAAAAAAAABTY2wgVW50RiNQcmNAWQAAAAAAADhCSU0D7QAAAAAAEABIAAAA +AQACAEgAAAABAAI4QklNBCYAAAAAAA4AAAAAAAAAAAAAP4AAADhCSU0EDQAAAAAABAAAAHg4QklN +BBkAAAAAAAQAAAAeOEJJTQPzAAAAAAAJAAAAAAAAAAABADhCSU0nEAAAAAAACgABAAAAAAAAAAI4 +QklNA/UAAAAAAEgAL2ZmAAEAbGZmAAYAAAAAAAEAL2ZmAAEAoZmaAAYAAAAAAAEAMgAAAAEAWgAA +AAYAAAAAAAEANQAAAAEALQAAAAYAAAAAAAE4QklNA/gAAAAAAHAAAP////////////////////// +//////8D6AAAAAD/////////////////////////////A+gAAAAA//////////////////////// +/////wPoAAAAAP////////////////////////////8D6AAAOEJJTQQAAAAAAAACAAQ4QklNBAIA +AAAAAAoAAAAAAAAAAAAAOEJJTQQwAAAAAAAFAQEBAQEAOEJJTQQtAAAAAAAGAAEAAAAFOEJJTQQI +AAAAAAAQAAAAAQAAAkAAAAJAAAAAADhCSU0EHgAAAAAABAAAAAA4QklNBBoAAAAAAz8AAAAGAAAA +AAAAAAAAAAGpAAACIgAAAAVnKmgHmJgALQAxAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAA +AAAAAAIiAAABqQAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAABAAAAABAAAAAAAA +bnVsbAAAAAIAAAAGYm91bmRzT2JqYwAAAAEAAAAAAABSY3QxAAAABAAAAABUb3AgbG9uZwAAAAAA +AAAATGVmdGxvbmcAAAAAAAAAAEJ0b21sb25nAAABqQAAAABSZ2h0bG9uZwAAAiIAAAAGc2xpY2Vz +VmxMcwAAAAFPYmpjAAAAAQAAAAAABXNsaWNlAAAAEgAAAAdzbGljZUlEbG9uZwAAAAAAAAAHZ3Jv +dXBJRGxvbmcAAAAAAAAABm9yaWdpbmVudW0AAAAMRVNsaWNlT3JpZ2luAAAADWF1dG9HZW5lcmF0 +ZWQAAAAAVHlwZWVudW0AAAAKRVNsaWNlVHlwZQAAAABJbWcgAAAABmJvdW5kc09iamMAAAABAAAA +AAAAUmN0MQAAAAQAAAAAVG9wIGxvbmcAAAAAAAAAAExlZnRsb25nAAAAAAAAAABCdG9tbG9uZwAA +AakAAAAAUmdodGxvbmcAAAIiAAAAA3VybFRFWFQAAAABAAAAAAAAbnVsbFRFWFQAAAABAAAAAAAA +TXNnZVRFWFQAAAABAAAAAAAGYWx0VGFnVEVYVAAAAAEAAAAAAA5jZWxsVGV4dElzSFRNTGJvb2wB +AAAACGNlbGxUZXh0VEVYVAAAAAEAAAAAAAlob3J6QWxpZ25lbnVtAAAAD0VTbGljZUhvcnpBbGln +bgAAAAdkZWZhdWx0AAAACXZlcnRBbGlnbmVudW0AAAAPRVNsaWNlVmVydEFsaWduAAAAB2RlZmF1 +bHQAAAALYmdDb2xvclR5cGVlbnVtAAAAEUVTbGljZUJHQ29sb3JUeXBlAAAAAE5vbmUAAAAJdG9w +T3V0c2V0bG9uZwAAAAAAAAAKbGVmdE91dHNldGxvbmcAAAAAAAAADGJvdHRvbU91dHNldGxvbmcA +AAAAAAAAC3JpZ2h0T3V0c2V0bG9uZwAAAAAAOEJJTQQoAAAAAAAMAAAAAj/wAAAAAAAAOEJJTQQU +AAAAAAAEAAAABThCSU0EDAAAAAAQ6AAAAAEAAACgAAAAfQAAAeAAAOpgAAAQzAAYAAH/2P/tAAxB +ZG9iZV9DTQAB/+4ADkFkb2JlAGSAAAAAAf/bAIQADAgICAkIDAkJDBELCgsRFQ8MDA8VGBMTFRMT +GBEMDAwMDAwRDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAENCwsNDg0QDg4QFA4ODhQUDg4O +DhQRDAwMDAwREQwMDAwMDBEMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwM/8AAEQgAfQCgAwEi +AAIRAQMRAf/dAAQACv/EAT8AAAEFAQEBAQEBAAAAAAAAAAMAAQIEBQYHCAkKCwEAAQUBAQEBAQEA +AAAAAAAAAQACAwQFBgcICQoLEAABBAEDAgQCBQcGCAUDDDMBAAIRAwQhEjEFQVFhEyJxgTIGFJGh +sUIjJBVSwWIzNHKC0UMHJZJT8OHxY3M1FqKygyZEk1RkRcKjdDYX0lXiZfKzhMPTdePzRieUpIW0 +lcTU5PSltcXV5fVWZnaGlqa2xtbm9jdHV2d3h5ent8fX5/cRAAICAQIEBAMEBQYHBwYFNQEAAhED +ITESBEFRYXEiEwUygZEUobFCI8FS0fAzJGLhcoKSQ1MVY3M08SUGFqKygwcmNcLSRJNUoxdkRVU2 +dGXi8rOEw9N14/NGlKSFtJXE1OT0pbXF1eX1VmZ2hpamtsbW5vYnN0dXZ3eHl6e3x//aAAwDAQAC +EQMRAD8A9B6v1DIotpxsUtbbducbHguDWMG53sa5m97tzGt96yqetZlznNr6hSdha1x9B8BznGmt +s/aPz3t/qen+l+grXWiR1bDLTDvTug+BIqgoX7DxumYjzfbRXitDS9+U8loFQ/R7rbdvtZ7rP6/q +PSUodRz3ajqmGY8Gt8Af+5f8pSbm9Ue4MZn4znFwY1oZqXHhrP1r3/Rd9H9yz/RvUbMLpxda19vT +w9rmUXQQ1zXv99ND3Nc19b7d36Ov/Cb/AOWp4/TcXJtccR+BbbjH03GoNc6o+6v0z6f8z+fXsSUg +HWM0hhHUsUiwNcw+mRIeXMrdrk/nOY9J3VupNY6z7filjAXPc1m6ACAT7Ml35z2Kz/zaIIcyvEYW +kFu2qII10a2GoZ+qztrmAYrWvYantFRALDAdV7XD9G7a1JTWZ17Nss9GrPx7L9peahU8O2iJdtdc +395Met9XH+Hr/wC2j/70K1X9VbKn+pUcet4Z6Yeysh2wcVzu/m/5Kf8A5s5X+nr/AM0/3pKaf7d6 +v/pq/wDto/8ApdQd9YusNMGyv/ts/wDpdXv+bGV/p6/80/3qL/qrkuH9IYP7J/8AJJKaX/OPq/8A +pK/+2z/6XT/84ur/AOlr/wC2z/6XVn/mjk/9yWf5h/8AJJ/+aWV/3JZ/mH/ySSmsPrB1f/TV/wDb +R/8AS6kOu9WP+Hr/AO2j/wC9CsD6p5X/AHJZ/mH/AMknH1Vyh/2pZ/mn/wAkkpEOsdWP/aiv/tk/ ++9CmOqdXP/amv/tk/wDvSij6s5Y/7UM/zT/5JTH1eyx/h6z8j/ekpCOodXP/AGqq/wC2Xf8AvSqe +T9ZsnFvfj5GdUyxgDo9B3Dmh4/7ULVb0PLH+FrPycq+b0ltAORlNoLQADad0/utb7R9L9xNlxUeE +iNa3Lal+IwEhxxM4nThh83EdnPu+td9Ei3Nqa7aHBvouMhw3N4yP879xbvReqX5Vt+LlbTfjP2Oc +yQ10tbax7WulzdzLG+xcT1Hr+L026zGyOigvr1LRaNR++G+l763fvrqOgCOt9THMXN1/61SncGSO +s6qWsK19P0RLJhlpjBBhpk4v3v7svlf/0O263/yth/1Lf/RK0es9Hw+t9Ot6bnBxxrtu8MdtPtIs +Z7h+69rXLP61/wAq4p8Krj9wqWyciDGx2n9X/wAkkp5XNw/qg7IyzlOvNl2VWzIJ9Tb649VlfpS3 +axj33W+p9n/R3P8A5z/hLnS7/q/0/Muf09txf1W4uuO12wWBxA9tmz093q/zdK1nUYL534jXbnF5 +ltZlxDmOfqfp7HvYkKMEO3jDYHA7g7ZXMgRu5SU1a/rV0e1ge2xwa6h2U3c0tmtr3UudD9rvpsRW +fWHpLy9ouO6ttbnjY8wLfT9M+1pa7+kVfQRKcXp1Dmvpwq6nsaa2uYytpDC71nVtLT7a/V/S7P8A +SKXpYQe6wYjd9gAe7bXLg2NjXOn3bNjdqSkf7f6N7v1usenq+TG0fvOn83+UnHXejkOP2uqGPZW/ +3fRfYXMrY/8Acc51b/pIzjQ47nUSZDpIYTuH0XfS+k1LdT7h6H0vpaM1mfpe7+UkprD6x9DLd5zK +2j+US3gMedHhv0W3VqOV9Zek4nretY8DHLRaRW8gbwHM2u27X7t7PoK1+rRt+zjbzG1ka/2v5Kg+ +nBeXF+I15cQ5xc2syW6McZP5jfoJKbqSCLwAAK3ADj6P/kkvtH8h3/R/8mkpMkg/aP5Dv+j/AOTS ++0fyHf8AR/8AJpKTJIP2j+Q7/o/+TS+0fyHf9H/yaSky4X63ZfUMjrBw2gjDxq2uAaCZe4b327R/ +Id6Pu/mv0i7T7R/Id/0f/JrnfrL0nqHUg04dbWvES5z2MJDd0N3/AKRzfpu/89/QS9qGX0TIjAn1 +Xr6VmSeaHDPCSJxN6aXH9KPEPl4ngOt5+VmgMLQ6ut7212OrLXOOnsY5x/m6t3/Xv53+b/nPQug/ +8udU/wCOb/56pXJdT+qP1tzWMJooY2it4aPtW4ku/f8Aayr83/R/9eXXdCIPXeqEcG5pHwNNCknD +HCMMeM3GAOv739b/AAkQnknKeTIOGUyNP3R0j/gv/9Ht+tOY3quMXmAab2tnu4irY3+0tV30j8Ss +T6yGOpYPxd+WpbbvpH4lJStrvApbXeB1XJZOA6rqXUdmNllxsbnV2MebG2WNl1FOOx1VXp++636N +tvpP/nP0f6RLqWI3Jurs+zW0t6vV6mQGOI9AAtta3b6b2/bL7XP9X9D+g/S5Ffqelbakp63a7wKW +13gVyWSXZNbA3DtY+uh1DHN3tbusaRmPf6dG71ttu/8ARv8A51n856atY31dqzcIm+3Jqsupqre5 +87o9mUX1+s9/0fVfj/pK/wBD/ofVrSU9FBOgGoT7HeB+5Z2R0dt+LVj/AGixvoOa+t3IBZWMbZ6c +s/RObue+r9+yxVKfqrh48elfaQL3ZDvV953vDWP2+5mxvsakp3NrvD5JbHeB+5c4z6lYVbA2u97d +tdtTZbugXeoN/wCkse/fU239F7/T/wCDUrfqdh20Gl+RYd1dVTyAB7adu309rw+n1XV77/Ss/SJK +eh2u8Cltd4FYz/q3Q5keu/cbBa5xBPubuG5jPU2sdtf9L/1J6kWfVbFZ6cX2TXW5gMclzRWbHN37 +fzfof9a/mf0aSnb2mYjXwTQSYAkrDf8AVPEdh/Yze+yr0TjkWtDgWuf673O9N9Ltzv5D9n83Z/O1 +1KxlfV/Gy+l1dMvutFNJqLTURXAqY2j0mRu202MD/Zus/nUlOptd4FIAkwBJWa3orG05lQuL3Zj3 +WB9jd3pve19NljNr2e91Nnp7v0aJl9KbmY4ouvtA3Mc8tc6PYZ/Rse9+zd/wj70lN6DMRr4JEEci +Fn9R6JidQw7cK2y6qi5zX7an7dpad36P2/4Zzt1/+kei4PTm4VuTY219n2pzXuD+xaNnM+79H6bP ++tpKbNn81ZH7jv8AqSsboDmP631J9ZDmOsZtcO/6DHW076D/AOq78hXPfVEznZh/lt/89UpKf//S +7D6y/wDKWB8XflqW476R+JWJ9Zf+UsH4u/LUtt30j8SkpaTETon3O8SmSSUrc7xKSSSSlJJJJKUk +kkkpSSSSSlJJJJKUkkkkpSSSSSlnfQd/Vd+Qrnfqf/TMz+s3/wA9VLonfQd/Vd+Qrnfqf/TMz+s3 +/wA9VJKf/9PsfrJ/ylg/F/5altu+kfiVifWP/lLB/t/lqW276R+JSUskkkkpSSSSSlJJJJKUkkkk +pSSSSSlJJJJKUkkkkpSSSSSlnfQd/Vd+Qrnfqf8A0zM/rN/89VLonfQd/Vd+Qrnfqf8A0zM/rN/8 +9VJKf//U7H6x/wDKWD/b/LUtt30j8SsT6x/8pYP9v8tS23fSPxKSlkkkklKSSSSUpJJJJSkkkklK +SSSSUpJJJJSkkkklKSSSSUs76Dv6rvyFc79T/wCmZn9Zv/nqpdE76Dv6rvyFc79T/wCmZf8AWb/5 +6qSU/wD/1ex+sf8Aylg/2/y1LTd1DA3vH2moFheXgvaNux3pWbtx9uy39Gs36x/8p4P9v8tS0rOn +dOc60PxKHC0n1Aa2ndMzv9vuSUoZ+CXNaMmpznwGNa9riZOxu1rC5zvcoHqvTG1mw5dO0NLvpgmB +H5o9+73fQ/nFMYWCLPVGNULAZDwxocD47oUT03ppABw6CBtgGtp+gNtfb/Bt+gkpLVfRezfRay1k +xurcHCR+buYSiaeKHXRj1ViqqpldbZ2sa0BonmGwpbGfuN/zR/ckplp4paeKjsZ+43/NH9yWxn7j +f80f3JKZaeKWnio7GfuN/wA0f3Id766a95awNk7nOGgAa+xzva3d/g0lJtPFLTxVF2fjNdDvSDfT +Zb6hY7ZtsLm1+/Z/Ofo/5tVn9f6bW99btu6uxtRip0FzhubsnbuZ/L/9F+9KlW6+nilp4qoMgveG +VV0GW797iWtLTt2bf0bnfne/cs+36x4dNjq7K62uZeMVxLXAeoTGhcxu5n+v0E7hP8it443WunhJ +29PFLTxVDGzDlNc6mvHhh2neSNflW5WG2Mdi15ArYPUbW4NcBA9Tb9Jwb+ZvQMSNSoTiTQ/IhPp4 +paeKz+o9Txem44ycoV+kXtr/AEbdztz/AKHs9ngli9Uw8vJyMWg0m3FDDcHNLQBYN1cSP8/9xBc3 +3EbHa/mu/IVzn1O/pmX/AFm/+eqlvN2PFrS2s7WzLBI9wf8AvD+QsH6nf0vL/rN/89VJKf/W7H6y +adSwZ/lx5x6b4H9lj1onqmCST6jtT/o7P/SaD9ZP2R9lH7TIFciJAOv5u2fzlykfUz96z/N/8zSU +9h+08H/SO/7bs/8ASaX7Twf9I7/tuz/0muPj6mfvWf5v/maUfUz96z/N/wDM0lPYftPB/wBIf+27 +P/Sab9q9P/0p/wC27P8A0muQj6mfvWf5v/maUfUz96z/ADf/ADNJT1/7W6d/pj/23Z/6TTftbp3+ +mP8A23Z/6TXIx9TP3rP83/zNPH1M/es/zf8AzNJT146pgHi0/wDbdn/pNRsz+nWAB73EA7hDLQQR +/KaweK5GPqZ+9Z/m/wDmaUfUz96z/N/8zSU9OH9DZabgC25wg2hlweR+6bNm/an9XoevPuJc72Xa +uI2ue72e57m+3euXj6mfvWf5v/maUfUz96z/ADf/ADNHVGng9Q67orol7xtkAt+0NMGNC5gbu+ih +f9jvnyTxfyZ3O4+k7c5c5H1M/es/zf8AzNKPqZ+9Z/m/+Zpw9ytOKvDiY5ezZ4uC+t8NvSCzoDQQ +172g8hpyG9o/NVgdQ6U6oUCz9G0Boa1logNjZBazd7dq5OPqZ+9Z/m/+ZpR9TP3rP83/AMzQlx/p +cX+Euh7dng4b68PD/wBy9SbejuEOLnA8hzbiPucxIW9GH0S5ukaNuGnhoxctH1M/es/zf/M0o+pn +71n+b/5mmr3rG53TKWPDHuG8GZZaZMFrfps81lfU4freZ5PAPxFdTXD+y5ZEfUz96z/N/wDM11P1 +a/ZH2b/Jhmv4Af8AUkpKf//ZOEJJTQQhAAAAAABVAAAAAQEAAAAPAEEAZABvAGIAZQAgAFAAaABv +AHQAbwBzAGgAbwBwAAAAEwBBAGQAbwBiAGUAIABQAGgAbwB0AG8AcwBoAG8AcAAgAEMAUwA1AAAA +AQA4QklNBAYAAAAAAAcACAABAAEBAP/hDdBodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvADw/ +eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4Onht +cG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUu +MC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYg +eG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4g +PHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUu +Y29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21t +LyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJj +ZUV2ZW50IyIgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIiB4bWxu +czpwaG90b3Nob3A9Imh0dHA6Ly9ucy5hZG9iZS5jb20vcGhvdG9zaG9wLzEuMC8iIHhtcDpDcmVh +dG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBXaW5kb3dzIiB4bXA6Q3JlYXRlRGF0ZT0iMjAx +MC0wOC0zMVQwMDo1MDo0OSswODowMCIgeG1wOk1ldGFkYXRhRGF0ZT0iMjAxMC0wOC0zMVQwMDo1 +MDo0OSswODowMCIgeG1wOk1vZGlmeURhdGU9IjIwMTAtMDgtMzFUMDA6NTA6NDkrMDg6MDAiIHht +cE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NTNCMTQ5RjQ1NEI0REYxMUJFN0VCMjM3Mjk0MkY3NDki +IHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NTJCMTQ5RjQ1NEI0REYxMUJFN0VCMjM3Mjk0MkY3 +NDkiIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo1MkIxNDlGNDU0QjRERjExQkU3 +RUIyMzcyOTQyRjc0OSIgZGM6Zm9ybWF0PSJpbWFnZS9qcGVnIiBwaG90b3Nob3A6Q29sb3JNb2Rl +PSIzIiBwaG90b3Nob3A6SUNDUHJvZmlsZT0ic1JHQiBJRUM2MTk2Ni0yLjEiPiA8eG1wTU06SGlz +dG9yeT4gPHJkZjpTZXE+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJjcmVhdGVkIiBzdEV2dDppbnN0 +YW5jZUlEPSJ4bXAuaWlkOjUyQjE0OUY0NTRCNERGMTFCRTdFQjIzNzI5NDJGNzQ5IiBzdEV2dDp3 +aGVuPSIyMDEwLTA4LTMxVDAwOjUwOjQ5KzA4OjAwIiBzdEV2dDpzb2Z0d2FyZUFnZW50PSJBZG9i +ZSBQaG90b3Nob3AgQ1M1IFdpbmRvd3MiLz4gPHJkZjpsaSBzdEV2dDphY3Rpb249InNhdmVkIiBz +dEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOjUzQjE0OUY0NTRCNERGMTFCRTdFQjIzNzI5NDJGNzQ5 +IiBzdEV2dDp3aGVuPSIyMDEwLTA4LTMxVDAwOjUwOjQ5KzA4OjAwIiBzdEV2dDpzb2Z0d2FyZUFn +ZW50PSJBZG9iZSBQaG90b3Nob3AgQ1M1IFdpbmRvd3MiIHN0RXZ0OmNoYW5nZWQ9Ii8iLz4gPC9y +ZGY6U2VxPiA8L3htcE1NOkhpc3Rvcnk+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwv +eDp4bXBtZXRhPiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgIDw/eHBhY2tldCBlbmQ9InciPz7/4gxYSUNDX1BST0ZJTEUAAQEAAAxITGlubwIQAABt +bnRyUkdCIFhZWiAHzgACAAkABgAxAABhY3NwTVNGVAAAAABJRUMgc1JHQgAAAAAAAAAAAAAAAAAA +9tYAAQAAAADTLUhQICAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAABFjcHJ0AAABUAAAADNkZXNjAAABhAAAAGx3dHB0AAAB8AAAABRia3B0AAACBAAAABRyWFla +AAACGAAAABRnWFlaAAACLAAAABRiWFlaAAACQAAAABRkbW5kAAACVAAAAHBkbWRkAAACxAAAAIh2 +dWVkAAADTAAAAIZ2aWV3AAAD1AAAACRsdW1pAAAD+AAAABRtZWFzAAAEDAAAACR0ZWNoAAAEMAAA +AAxyVFJDAAAEPAAACAxnVFJDAAAEPAAACAxiVFJDAAAEPAAACAx0ZXh0AAAAAENvcHlyaWdodCAo +YykgMTk5OCBIZXdsZXR0LVBhY2thcmQgQ29tcGFueQAAZGVzYwAAAAAAAAASc1JHQiBJRUM2MTk2 +Ni0yLjEAAAAAAAAAAAAAABJzUkdCIElFQzYxOTY2LTIuMQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWFlaIAAAAAAAAPNRAAEAAAABFsxYWVogAAAAAAAA +AAAAAAAAAAAAAFhZWiAAAAAAAABvogAAOPUAAAOQWFlaIAAAAAAAAGKZAAC3hQAAGNpYWVogAAAA +AAAAJKAAAA+EAAC2z2Rlc2MAAAAAAAAAFklFQyBodHRwOi8vd3d3LmllYy5jaAAAAAAAAAAAAAAA +FklFQyBodHRwOi8vd3d3LmllYy5jaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAABkZXNjAAAAAAAAAC5JRUMgNjE5NjYtMi4xIERlZmF1bHQgUkdCIGNvbG91ciBz +cGFjZSAtIHNSR0IAAAAAAAAAAAAAAC5JRUMgNjE5NjYtMi4xIERlZmF1bHQgUkdCIGNvbG91ciBz +cGFjZSAtIHNSR0IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZGVzYwAAAAAAAAAsUmVmZXJlbmNlIFZp +ZXdpbmcgQ29uZGl0aW9uIGluIElFQzYxOTY2LTIuMQAAAAAAAAAAAAAALFJlZmVyZW5jZSBWaWV3 +aW5nIENvbmRpdGlvbiBpbiBJRUM2MTk2Ni0yLjEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHZp +ZXcAAAAAABOk/gAUXy4AEM8UAAPtzAAEEwsAA1yeAAAAAVhZWiAAAAAAAEwJVgBQAAAAVx/nbWVh +cwAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAo8AAAACc2lnIAAAAABDUlQgY3VydgAAAAAAAAQA +AAAABQAKAA8AFAAZAB4AIwAoAC0AMgA3ADsAQABFAEoATwBUAFkAXgBjAGgAbQByAHcAfACBAIYA +iwCQAJUAmgCfAKQAqQCuALIAtwC8AMEAxgDLANAA1QDbAOAA5QDrAPAA9gD7AQEBBwENARMBGQEf +ASUBKwEyATgBPgFFAUwBUgFZAWABZwFuAXUBfAGDAYsBkgGaAaEBqQGxAbkBwQHJAdEB2QHhAekB +8gH6AgMCDAIUAh0CJgIvAjgCQQJLAlQCXQJnAnECegKEAo4CmAKiAqwCtgLBAssC1QLgAusC9QMA +AwsDFgMhAy0DOANDA08DWgNmA3IDfgOKA5YDogOuA7oDxwPTA+AD7AP5BAYEEwQgBC0EOwRIBFUE +YwRxBH4EjASaBKgEtgTEBNME4QTwBP4FDQUcBSsFOgVJBVgFZwV3BYYFlgWmBbUFxQXVBeUF9gYG +BhYGJwY3BkgGWQZqBnsGjAadBq8GwAbRBuMG9QcHBxkHKwc9B08HYQd0B4YHmQesB78H0gflB/gI +CwgfCDIIRghaCG4IggiWCKoIvgjSCOcI+wkQCSUJOglPCWQJeQmPCaQJugnPCeUJ+woRCicKPQpU +CmoKgQqYCq4KxQrcCvMLCwsiCzkLUQtpC4ALmAuwC8gL4Qv5DBIMKgxDDFwMdQyODKcMwAzZDPMN +DQ0mDUANWg10DY4NqQ3DDd4N+A4TDi4OSQ5kDn8Omw62DtIO7g8JDyUPQQ9eD3oPlg+zD88P7BAJ +ECYQQxBhEH4QmxC5ENcQ9RETETERTxFtEYwRqhHJEegSBxImEkUSZBKEEqMSwxLjEwMTIxNDE2MT +gxOkE8UT5RQGFCcUSRRqFIsUrRTOFPAVEhU0FVYVeBWbFb0V4BYDFiYWSRZsFo8WshbWFvoXHRdB +F2UXiReuF9IX9xgbGEAYZRiKGK8Y1Rj6GSAZRRlrGZEZtxndGgQaKhpRGncanhrFGuwbFBs7G2Mb +ihuyG9ocAhwqHFIcexyjHMwc9R0eHUcdcB2ZHcMd7B4WHkAeah6UHr4e6R8THz4faR+UH78f6iAV +IEEgbCCYIMQg8CEcIUghdSGhIc4h+yInIlUigiKvIt0jCiM4I2YjlCPCI/AkHyRNJHwkqyTaJQkl +OCVoJZclxyX3JicmVyaHJrcm6CcYJ0kneierJ9woDSg/KHEooijUKQYpOClrKZ0p0CoCKjUqaCqb +Ks8rAis2K2krnSvRLAUsOSxuLKIs1y0MLUEtdi2rLeEuFi5MLoIuty7uLyQvWi+RL8cv/jA1MGww +pDDbMRIxSjGCMbox8jIqMmMymzLUMw0zRjN/M7gz8TQrNGU0njTYNRM1TTWHNcI1/TY3NnI2rjbp +NyQ3YDecN9c4FDhQOIw4yDkFOUI5fzm8Ofk6Njp0OrI67zstO2s7qjvoPCc8ZTykPOM9Ij1hPaE9 +4D4gPmA+oD7gPyE/YT+iP+JAI0BkQKZA50EpQWpBrEHuQjBCckK1QvdDOkN9Q8BEA0RHRIpEzkUS +RVVFmkXeRiJGZ0arRvBHNUd7R8BIBUhLSJFI10kdSWNJqUnwSjdKfUrESwxLU0uaS+JMKkxyTLpN +Ak1KTZNN3E4lTm5Ot08AT0lPk0/dUCdQcVC7UQZRUFGbUeZSMVJ8UsdTE1NfU6pT9lRCVI9U21Uo +VXVVwlYPVlxWqVb3V0RXklfgWC9YfVjLWRpZaVm4WgdaVlqmWvVbRVuVW+VcNVyGXNZdJ114Xcle +Gl5sXr1fD19hX7NgBWBXYKpg/GFPYaJh9WJJYpxi8GNDY5dj62RAZJRk6WU9ZZJl52Y9ZpJm6Gc9 +Z5Nn6Wg/aJZo7GlDaZpp8WpIap9q92tPa6dr/2xXbK9tCG1gbbluEm5rbsRvHm94b9FwK3CGcOBx +OnGVcfByS3KmcwFzXXO4dBR0cHTMdSh1hXXhdj52m3b4d1Z3s3gReG54zHkqeYl553pGeqV7BHtj +e8J8IXyBfOF9QX2hfgF+Yn7CfyN/hH/lgEeAqIEKgWuBzYIwgpKC9INXg7qEHYSAhOOFR4Wrhg6G +cobXhzuHn4gEiGmIzokziZmJ/opkisqLMIuWi/yMY4zKjTGNmI3/jmaOzo82j56QBpBukNaRP5Go +khGSepLjk02TtpQglIqU9JVflcmWNJaflwqXdZfgmEyYuJkkmZCZ/JpomtWbQpuvnByciZz3nWSd +0p5Anq6fHZ+Ln/qgaaDYoUehtqImopajBqN2o+akVqTHpTilqaYapoum/adup+CoUqjEqTepqaoc +qo+rAqt1q+msXKzQrUStuK4trqGvFq+LsACwdbDqsWCx1rJLssKzOLOutCW0nLUTtYq2AbZ5tvC3 +aLfguFm40blKucK6O7q1uy67p7whvJu9Fb2Pvgq+hL7/v3q/9cBwwOzBZ8Hjwl/C28NYw9TEUcTO +xUvFyMZGxsPHQce/yD3IvMk6ybnKOMq3yzbLtsw1zLXNNc21zjbOts83z7jQOdC60TzRvtI/0sHT +RNPG1EnUy9VO1dHWVdbY11zX4Nhk2OjZbNnx2nba+9uA3AXcit0Q3ZbeHN6i3ynfr+A24L3hROHM +4lPi2+Nj4+vkc+T85YTmDeaW5x/nqegy6LzpRunQ6lvq5etw6/vshu0R7ZzuKO6070DvzPBY8OXx +cvH/8ozzGfOn9DT0wvVQ9d72bfb794r4Gfio+Tj5x/pX+uf7d/wH/Jj9Kf26/kv+3P9t////7gAO +QWRvYmUAZEAAAAAB/9sAhAABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB +AQEBAgICAgICAgICAgIDAwMDAwMDAwMDAQEBAQEBAQEBAQECAgECAgMDAwMDAwMDAwMDAwMDAwMD +AwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwP/wAARCAGpAiIDAREAAhEBAxEB/90ABABF +/8QBCgABAAEEAwEBAQAAAAAAAAAAAAkFBwgKAwQGAgELAQEAAQQDAQEAAAAAAAAAAAAABQMEBgcB +AggJChAAAAUEAAADDA8RCgYOBwgDAAQFBgcBAgMIERcJITES0hMVFpfXGFjYQVFhscFzkxRUVVY3 +eJi4cYGhcpKyM7M0dJQ1Nle3OBnwkdEiMlLWd7kKI1MlloeIQoPTJISVJkYnZyhIqMjh8UPUx2g5 +YsJjpEV1tUdZmakRAAEEAQIDBAIMCAgLBwUBAAABAgMEBRESIRMGMSIUB0EVUWHRMpLSI9OUFlYI +cZGhUlMkVBeBscFCk1WVGGJygqIzQ3Oz4zQl8OHCY4O1V/GyRGQmCf/aAAwDAQACEQMRAD8A3+Od +zagCnmz2MtbWt11Kc/8Ah5oA8MqPokS6Los1ltacPPrb5Hkc2vD5IA8XmllOx3cFDOPn86t1vk14 +Kf7KnAAOLjcT/ZOP6q3pwA43E/2Tj+qt6cAONxP9k4/qrenADjcT/ZOP6q3pwA43E/2Tj+qt6cAO +NxP9k4/qrenADjcT/ZOP6q3pwA43E/2Tj+qt6cAONxP9k4/qrenADjcT/ZOP6q3pwA43E/2Tj+qt +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 +0f2vS4gFsLGNOtPUDWYmdKHM6LlyqmCUlpzxSNRzH+HfdoVY3rHKzmz5SPEzUmRxSRssOWSHLRyS +osKLVStPHbSCabGx37Wui2p4qUTo1yT1sfJcyJVYyq9zZpZJUeteONGcuZivma6aKZqwte6K0yv6 +k7yqTWR5DT4RcOn+5aBsO4ltpEGRAZ1D1vPPd8tt+sia3wzZERnSgbMLMNI7IWC+vjpIZ71x0pCk +jKJLHYqkyGEzgz5OmNrS5OVa0G1tqKaaOy1XIqU/D+q3TPsSsV8Kxthysc0T4JJ22vC2qtPxF/wt +S10klihqVcnI9UxFqJj606tfts7peTy449vPZNHI6tzobEMMkMVyvZlaysk80HVYvKlMRwywhwER +jSX5WlE4pSGuPTLHzYhlkE4miVubXyRq6nyQ62I/9nzclPtktp0sExiX1thEnfQgVwWKiqnt+xSJ +JttpXnrS4Z2ennSHBVsRj7Vm27c6Jkt7FsyTI3QxNlswLLE9ro+ZE+sx0iwNv2VqXZoal+O1Raj3 +0pHWJ7tyCGs3Y6ZzqMdeWeJJNza89hrJ9zIIpEtWEjf4eq/WHnVfS/lctSN7pacUPQetZDThTWOp +Se1TeSSNbnra/Y4SHAiN1RdeNowrPErylD+UobdaRfchye32G5+hUqY+tvrgmpYCMjVx1yzib2VW +LYlWSuyZmqSctbTZ3RaTwLLTm18NM13h7MysVGuciMlie/jLqzC5lmFsyNdK6xYgR7V0Ys9b/Sxo +2TZMuqJI6OVsS15mQyPimexY3PqSxu880XfxMgM4gs3BrGcqYgwxJeYssWvEtuTZExvZnEyMitVe +tbOFkd72RuzdTqm3HL1q/qfrqylnUL4fG3IZaXVF/KOWGrXq3rdV6J3ZKmIkxsGRkcnefKr7GRnZ +AkTW8lMFlFlSXmRLFUy0M1NMG2jE6aZ0lTxaIiv5UeSffgoro3jErLNCCKZZUc2X13ikjWNVXn48 +Z+VZNGpkj570g/Ztq6vPDWiR33FBRcZ0FGHHuC9nJPWr0Ua9K0HNZElpwy006vAxLXrUiWkItHRe +0u5SxxVxF8JUwYTpGjVu7s7RvY6VOpHzYKKvRVWJYrPvR5yxbdZej0qQtjr0mSW+daV1JKNhJGwv +R7ZeciyCCWkyC9D6tgsZTxV1FV1VWY+FivZH3VnmXnI9td1avI2650bar7CTQI/1WvfKPP5zT7LM +Iyfrfs0RfqzPLwKsSNDyfq1lN6/QhHET6cmXyuzA+2LPqpGl6OmOXYLI5MdU9xuhcOJpnKVK4cx7 +AXSaUa8tFOmquTs3o0jqU7tq/aVsqQxQpl+oa1ZFTlo58sUeJjpOhrxSSySPZaa2apFkL1W3vpYg +yNhsdOTZI2rFWrorHTWLDqbLEnKRHuRrZUc5zX2JIYmOZynLFJLWjnt+3v7wjoA50KVHIkLKwdS4 +6aCM/UC9MlLUJwmZKaLilBjRAirVCTW2gXTeuWEw9ZQbeIzjnOyJ8yVgVq5VCwpanq/W6vXpZC3W +qurUXyZKa/UppXa6JzudcZZkia2y2RcfMvLp2V5de5LM90bIoYpZrNSOxf26T6eXu4iSVrn148g5 +z2o9yK7GxOmsRRwo3xUrlZHKsL4q74JWxSStm5CJKuUCPyl7aV5njvXjvV9qk2bHa0kqRH3Gipi1 +owO+D4zXJnWoMTJPeqHg2XMqEmxzV1oOY4cWYqxyKQSUXKVOqGQpjOk6Z+9Op46zlWV7DFoUXQxT +2FR/LitTQOnZUkj2eKjk0RI0nkrsoyPc5YbcsUFqSCKtWFq4mhl3QK+K26z4drHRP8QyrBWtSSQS +tkWtM51ey2WOtHO689WSxeFSdiROxN5XfcHaTXJOmJBjBwt9JZKxrAiFYuaCfoBynGwMhTbsrKjq +liL27CiVt9p3J8HxTqs4JLdORiNllG8S+ce5ZzOO87XEn2URMijaFyW/hjcjYF2PRsa1y1s04NhW +2iw+4zW1pdD5Evli9C9uLoaOwFPeNuzWxpWazqcTWZcwSZK0RZS6IUQ22z8i+eLLBRlZcLhJJaRn +AxAmnYLlPI0UZTYy5K0wRs9pE3f1Ke8LQutaR7abx7KuHWrXRq8knn2Xmg7KOhkhRNr41IfT8cgn +DUyR6yGXcyF17qT4ZrWc6peq4FLEBs+wCqSEuw1HrhlN0t96PZyN/C5VFxtqCJM1iTjic48+dbbB +YzAEzP8Ak+VopcCS1j5ImrJLgWMqrhVS5i7OXIX3VTyoF4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAABwvAHBnrwW/v+dw+fQVI01cUZveqhbN+XmMjSdGMpkpjNZG+s2F8la8FtmaqeYpjuvrzf4l +t/BWvmDI8QxPH0lXs5rP/uQwzqeZ3qTMsZ/pFqyon4VY5DRAKxP0RQtW0l0HDhxX2WZbKWdBfXFX ++LfTgpWnQ+TTm3Vt4fJpTg8u3HvS1cjlRWvinVPbXXdqntrub29vE+YzmtYmyZq6tVyO4aqq7vY/ +j0PTWw+9czGlFqMQwvNh7ydHRElGSwj5ciQqqjrZMpxtMjcSkI/bcXrlNPNRi3GgluhvuxVOKmPo +7qUrSlNt+U0zMT1M6HN0pIq2QqchvMb3JFd3kb3kVO/ptT0Kq6KbC8tb78D1Njr1t8sKyrsjkRro +lSRXI9uxy8ddWpwbxVODeKlk5km25gRhe6mo0nE8FlWxEieButojjIt10OZSK23lM1qmVNkzjNSl +I9myZFYmRxZclceDJaRvKUMdVKYT1t9wPofN+beN64oTMp9NTqs9um1q6Pl17jY3MVNrF969NURd +VTTifaToD/8A0e6xxXlZlujupcat3zNqNbFTyUj2pFy3o7fNM1U+Unhbry9qK2V2jpuDVa6N2K4v +lh4utWkd/XOB9zI+i9Mt6EhJ5kxYgo5DBdeVbraQUnDkxJSS304vbjxYC2LqJXDjtr0NtLLqV+lH +QvSOI6PxFOrUr+HrxMayKJsbUZHC1u1rURE9nRVXtXRNyqiIfKzzD67ynX+dtz3LtizZmkkle+V3 +Mknkc5Vlkeq6++cu9N3Ztbt0VG6cyxwY78llbb632X5K9BdbSyvVLbqcFb6VyUpgsyW5KcN9a0pS +tf8AZUpdWuYTys3Oka7c1fT2aexw7O3h2GJY+GRu1j2tY5qaIi67l9j8Ps8dTKbQNr5jOz+vryyE +r7iBDZTXdDIHc1aYsdT52XmYaMXFb8lMVxo1gJYuhvx2UrdSwzW/oegspdbp/wA1rqM6cvUWO1c7 +l7v4JWKn4OKG9PKmi+TqGG89ukUbXI1P8JY3Iq+3wVfaJ3+Vhtrbr7r7w+TvTFfyZtyPMHl49MF+ +9LPsKX6SW+12ADYSi/8AFxb0u3z6AC8QA//R33l77gy/S3egAIlNxfyWcn3ga+sqAMMuTJxdFqlr +3fSla1pKm1HkU51N/dm/L8rngCaXQ/8AUd00+Clrv+iFngDK0AAAAEYG0WqWwmzex0au5IMR/ro3 +4D66Yor2ujrYjZhX2OUGdIZqI3DL0ZZ9ZGYQgTXIh1+ecYpCinKMjuOdWJXK0CFqzHayUVzxIgAI +aQynngnZfXSQFDUCdEyYpAQZTTJd2V1ncc68bbiMPFJOrtu6GuihLzRaUyyAymlG7bwN11Nh3Mhq +kf8AJqQgMFnNtkIiQpgRgsf+73M5FYkxqLhhbQA9PSRIE08Qz9u1sgleKy/FjwWFVIanfCNBU1VI +asQdIGOGG7HqYhcXkKqKdHMjsxUe2bs7TH892CsAZ/sbk1HEfxupXVXz3m7gTNv4o2y18TtI1CLH +Qjwd2KclRCXJ0OGISBTYbVVXjJXj9IJJD1Io+PExSPRIV6MexY0o31ZNKAefj7k15CRpzbLaejrc +C1q5HUP7zIxWbEba+TIz3amqZd9NwtW925IdjswaqQTqS1oBb7blaI3OQx42U8DONYQ1AmVzky5b +MfKACz8zcj8/1uOteoka0wbATb1k2AhB6zpPM6cq7yn7HeOCLIL2niSX0g41oIRJJmWJZI2Ad0Ss +o8mnl8ooRYnIb7xl3O2CaD0ZFOQQMn9z9C5am6EHMxY/lZwO4y2nBpkSgWK3zsNsPCbVQoz1w2V1 +ln6Tcsk7IMlRmjYN6bPy1kg02VIy8dwqLhaZbrbiQyqYpGXg4HaBQOSw1H2c05KykyZhYsfkGlIM +gTpK9jyQuUl3T3KWC6xJWx0mzCy2MnxPtBAjDaTI6xtKXjpF0vZGXMS6/l1HwrC6ROn1DKZIARgQ +D/d/dtYfK6tudf3Pj92uCJ/2WSRJMUYFXlDqsQwztBtjkCbVxEaLqfPKBSBGTo6kSU13G3EtchzA +xCRwqUyNlsR6bUlJTxgbDz7hR1SZs/B0mupQb9kOa2N97vmO2qWNKJh1OLZ+SW+vxFjklZqXSkTG +2G/DGvjld6AmEaqi+nu8zKR80eTUo40UI8ogY/o+ochJemcy67HyUPu17SVs/tvMDXU3KvSYTZbC +Tth+UBl3aGMpRLKrCxMSVsEwa8NaRUt0JJdtLLSVaP5uFyyQ8G9f61dpACOB7clJv1njreiPoonr +UBopm2uoEua1uI1JkXTRKbxltxPXaflRZiwSe6Hg0ZFhNpa/yBJ7S3iSlh6H0NnPNqkX2ordjbaC +U20dISVMCaLZXWimxVsTKCbNsxa/vWFZDOySxJDhUtCyi5SiwqR69oxVU5QSp7hucmCooqi1H+oY +77MiL65x5up5MWbHdZzaUUcsGRXJV7T2SOozVHtRGKySGeapYc125jnIqS0oHNcxzFTRzV3NcqFZ +ZY5KFjHT1mSRSTQyoqq9HMkgVysc3a9qL79yOR7XtVF7EVEVLV26FNpbZ2wTalOfZ/mpwbMQah6/ +SZJb6pAreet7IbahLx5DNoKfD0DxZHCS4iGCZ1ErTPVv5cGUuTJ1yYb81pjMZvorDK7MaytUjjSt +nq2XTRXrzLdX1bs37nu+Sf6rr8xjNirum2OZuZsosdM22y4+dz3spz1WNVG7WRWEdvRNrWuVUc97 +2ue5yo52i6tRrUoUgcnUz3jIj2lBtbD7LRE6nRKbRnZtZY3V4WzE4rnBtRSQghXk1hlpIg+RLlAz +IUKkextdb7nvcbNzFst5wojE1XoFCyyqJPRdG6vckRY320i1SNUjrX3yWL1HarNstazfkTJbrCTW +q12KF1OzWhibAnZeU+KGCWsx8DcdXqPauqc1ac7ZqVtytVrmW6yItdskDoo56r317cVmN6oUmXdD +XC6oD21aaNO0hSfPey2q2PXHPK05VilDxZcjapNJthuNYTYOg1htJJOET01HC5zKQbeQvkJEClaE +rzFpnKbrPcv/AEmvTRKlaPqbHZaR8Xela+q/EMsPh5/OjWR8GJZLHHI1YVtyPRdlZzY4q2OlbWvQ +XbznWeTSt12MfojVZZ5z0jfyuU7Y18uzc1ySJEnvnSd5fQR1yerOa0tsrYWR5znvYOfmS4EhTT5W +ljJBqQsZ2s3Y0mGNmxFmVuwhBkMx8Vj5t2z26lnDUkik104tKVMh9SNli5YphvK1xlB2QXH1Y40t +w2I5176rO6xLjnrPJue7SWKPF1IIWRcutHHz3pAtizNO+I8LNYoYyldsOWGoyBIo2rpFC6J75JFi +RU1V1hzo22JZd80kVWpHzGsrsani3NyWcRu9ZYdjjmWeFuLWHNJjYcrAi7i18ckYqEy3TpJk/p7/ +ACSu5df1mZI1cqS65ROJ1hxjuxqmjiAULkT2Q3bccvNxVStBXix0FiPxMFTGMowpIqtcyBuKgxDm +c2FYpnRzV60ck9Z0jqUth0znVuVPNFJK3bE1uLPRxSLXfk5JFtOiVflopXskdA5knMhRjXMVY5mR +tuROc2SO02WtSkrX61m1MPavWYGy2tm9i5ChhvNmjNjCA5U4glthxC2CR0te2khnvZswI0NhHFhZ +6GVtSE+92vZzZqp33VeZM24zNkkt61YrObk5VuZNyQo63LwsP5Uaxq5/K5UMkk/dfYlfC6WWVnM3 +o98yy21qOObIS3asbasD5ZpXQQoiQK+d6yvVrX8x8TGyOe6KKF8cMTX8qONsLIo47LK3JO6VrLkO +yebi9E74o/sEW2Oz7YUaEX5dneysrKBSRbGhilw3HxlZxRbehE7WVehUs9b3Mm64h0XVrqnBFUaV +THVMTj6sCNoV69uGaNFc1LzMhBdgyC3nNVr53XFyFqaRUezlTOj8L4eKvXiir5GV+VkzEt9VkktN +gRiqq61HVGVmUZKa66wSUnU600KorkkljctpLDZ7LJvEk+SRizCnpCUo7K7bL6dHcdY4u13LKzqh +Sy7WFqoUoxBMMb0ig4kQMlKDmWYoesGNy5JPP/M9jSiRKXE129YLZbsQkmXcg2abJPvyP6klnoyy +3nNjWxM6jDfrokkaMSmqWoMnfiu6VWunbZcu5j2ROj4s8m1PcV9SJuLmXJL4RiK2uxco1zbCxo1U +lbyl5clJOaraL4InVUi+USS9sD6BsGD5XcE4HpenKapSeBWS8DzdMwqUW5uykxKyPr0hOc8eQ4yi +eMm2l3YE/WlBsJFUsmQTitDJ220tXHkL2FbeSOnJ0/kul1oR+prddkMrNZFVzUt5i69d6yK5HTT5 +u7v0Xa1iQRwtibGqOoPSeW/UyklyVb0ErZGOTa3arII60bUa1rWtbHDFGiK1Ec96LNK6SaSR76Cy +tBXHGsenYlj3fPdpoxklJDeQIdaJIzqUq978hNJ1obgbCLHztc+pa7IL4SEhAROxmpSRld9FzreN +ZsRywyb6icwrbrGTghbl7Lrl5NqSTzNjc+yxKk1SVlqNGJWn8QybmzyyV1nW1FFajljnR733Lnwe +sLV2GlFDWmdO91ePcyFJZ5OdzI9Hc6HlT6yQwwzR1mtVazoH0v1YtO2uR+glrosGMcpL03GofgqQ +mxMqRBphu6pk4rXZuakpPWYE6Yk9JQ9YUddgZ7Z3e+jVhiyIVGOEjIm47CVCNpa8zjMXtO9LTymO +yrU3z0oFirb3yOdXYtKKi9jJ1f4p8D2RNkdTnnlo71fE2q2o91ZaF7nZCp1HBatPW1mXSJkJu7vu +xSLHrDPHt8MqtZE1qWmQMyDn6W5Lkl6KC1Fcbe/Wuc9sFGNI6Zzbh9pMliOAnLTR2dWdkdwmDMsL +TKXasoR0p5GnBeo6trG6ZJb7jil/KDdyGbtgWZjw43QcMmEtQsSsJFXsjsGXp7MrTUdoG89JIh/a +Ft7Mw+eZh6YNoYdwOqZbVFCat7RZUV7Ax1HyrHWvmw+sGfG+3OcsaDKR4KSkDHcftzkXI4Xw5nhg +AjAYn932j3JJk4uGWIb5OBQx2uBkPrWmSWtpVGZbAnOBLj1AxHIsf+o6I048glL1gbEkuqUSZpHU +ViRJQf7NeLXuOSGgOyM2y58oE3+l8PqMA6wRBDqxF0Pw4rsJvnUZUYsEKDVVIzxqNzgWDx52JZti +64ahsmrgkgybucjgxo8bNFKwOFWPYihOpezHnzAZPgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +ADpnK1txVrT93keiK0CavQt7CokblX2DwKhksy9UwZrLb8WW3JjyWXW0vtvx5La23W1trw0updbX +g4OdUZFWYqNa9q6OTRfxGGX3te98buKPRWr/AJSKn8prpT/r5xdy27ilUoufb6gum15HpfZTERNl +VOtiwfR89cNl1pG0nlOX4qY7beioUuxX2Ur0V1tmneu8G7C5+t1ClXfgbMizL6ER27V8bl7U1dq5 +vp28E9g8C9f9NT9J9VXFdCsmN38xFRdE7ddN3oRexdexNVQj3mCSn7rzJLsPPNzEZ8YU7WOh+xtG +8gOFy+vIsUCrsxmWguLjLOWGiCelpVt51GJ4Eg31ocaTjM2UyY8eHqGH6c9JdP8AQ/nj0L05PHg5 +ce7HyQv70W1z0Y1FTR6aL75EVV19LdF0VFfCZjNW8DdfZuPS7UufKRQyf/jSRuY6NVa7sammjUTT +ma6u3N11tEgTa83Georr2ZpqrgyqplxVcxuNozucWNZO5bTRtcwrFGncaxql+bhyYz11bTWK+tK4 +s1ttmOuPdCeW3R9d0KRVXxxqxrUYrpNq7O9xVX6p7PbxXQgW+ZPVnIakkkTpFfru2xue3gqaormL +x2qqL7KcF1RC7aUptBooElyHiba9mdiskm3M+qsZAwOZxPBIZDfcDgOpTOZBU6iHFJ6PlboUvMJ5 +Y0WJHzxPAYyXl7erX4cTzeGg6US9npGPsY6NNWQ8Vc3cqMXd6VZo7uquq66KZjgMs/qx9bBQTNqZ +WdycywmjWua35RFbw0R6q1Ec1qI3RV4Gv5IOyRGaJHkyW1BgHm+SdCySvZbSWDhe5QqVS0BIRDDw +kU6Rr0B15vg6SyrqqTJZL7aKalltvN57aVvz6go3cjl/FWXU0rVHSasT/AReCcezsNz5DFYvFTVq +taylmaKNEe708zTt7fZ04di+wZW6eOJZO7YaHpqyb6oYN7Gw0u3k8NlhZPTqrklN80UKJybhtxl0 +0tYjlS1epW20rW6vRVrWta1rqrzHWN2Mzr4+Lfkvb486M3F5eQyRWcSj17yukcqezrG8n25W3F1P +X3XnhpwVrvVFvkUpw/8AZm3HHng3oXt0s+wpfpJb7XYANhKL/wAXFvS7fPoALxAD/9LfeXvuDL9L +d6AAiU3F/JZyfeBr6yoAxC5MHF0epmv9fKlTar6G/ezf8IAmV0P/AFHdNPgpa7/ohZ4AytAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAU5Qv4C99fJpw/Q5tPo0FxWTWRPY1LC85Uhf7H/AHoWfcKpQliz5qcFa20u6Hm0pzehr5N3 +lVqMxp1+YxEcnA11k7aRueqO0X3SMrYm8yrUyGyuJPUlO0xbWicsYsphIXL7TFM2MkoWYMmI5gye +uLv8GZwXUzYq33Ur1TFky4suaQYqjeppVyNNk1PVFVjk1aunZw/Jw/iNUdR16GVYte9Ckkfo4Iq/ +iXtT2UXVNNeBqwTqxcqjLzycKlLpc28lhwHLlUrNawhtS5QNFLCZDEWaEsXlm7CrlbybdhoTI4Ls +zVMYipfHgKJFhfF1QewuhvNTpyjh6eGs0UoxxNa1EbqjV29irx/h17VXiqqecusvKvOXr8+SxOUb +dfI7crXq1rk7E0TgiJtamiJ2IiaIiHrWfEMzFPWuTiwfBwpfbZlxKKU3VJeQr8da0/31hX0bAeQz +JW6taV6pYY6G+yvRdH0PBW7Z31z6ZdHzGZqurX6e/dwTjr7PD+D8CmuF6H6rhnVj8DZSRNU7jdyL ++B3YnuHRlHbCD9YU7JfLUgpWB0lK2UIxgxFJOfUwnz+KluTAQLtRuHjONkqFMuGuXEZdJpvF7bLb +7sWTPl6DFlwPqvzW6Vx0VmtWlS5ckYrUa1Ec1dU00VePBNdyehFRNOJsPpDyc6syU9a5cVaNGKRH +q5y7XN0XXVE7NVXRq+0qkHrolJxbByU7JEPx6jxfbITpw5kFlo2Tq9SBPPiJppbOsG8JNOKqbpXs +2Oh9YN4CpAmdVjZnNgIk8N+Ivj01St35aclm9X5OqO2NT81exNOw3VepYxmShgxt1Z3ord7v8JO3 +2jOfVU/hycorp2nlrqVKE9m4VTydtK8PQE098IJMnZwcH8n1uVpwV5/8WnDXm1GoOs0//mMu9e1X +R/76M3Z0kn/XcW381r/9082MuV7xdBr1rpXg4OHeuMKc7n1prLuL5tfLGgjcxdvSz7Cl+klvtdgA +2Eov/Fxb0u3z6AC8QA//0995e+4Mv0t3oACJTcX8lnJ94GvrKgDFTkuMPR6hwFfSnOlXa3+Nwc7g +352Zr6IAkW0lfMqFNMdRiicyosNp5XWKAy5E0oS0901QMk8MVNTGWMHk4pAqwVIHM2C227LhxGzW +PFfWttubLSlL7gMneMGYPcFEHbnf/i6ABxgzB7gog7c7/wDF0ADjBmD3BRB253/4ugAcYMwe4KIO +3O//ABdAA4wZg9wUQdud/wDi6ABxgzB7gog7c7/8XQAOMGYPcFEHbnf/AIugAcYMwe4KIO3O/wDx +dAA4wZg9wUQdud/+LoAHGDMHuCiDtzv/AMXQAOMGYPcFEHbnf/i6ABxgzB7gog7c7/8AF0ADjBmD +3BRB253/AOLoAHGDMHuCiDtzv/xdAA4wZg9wUQdud/8Ai6ABxgzB7gog7c7/APF0ADjBmD3BRB25 +3/4ugAcYMwe4KIO3O/8AxdAA4wZg9wUQdud/+LoAHGDMHuCiDtzv/wAXQAOMGYPcFEHbnf8A4ugA +cYMwe4KIO3O//F0ADjBmD3BRB253/wCLoAHGDMHuCiDtzv8A8XQAOMGYPcFEHbnf/i6ABxgzB7go +g7c7/wDF0ADjBmD3BRB253/4ugAcYMwe4KIO3O//ABdAA4wZg9wUQdud/wDi6ABxgzB7gog7c7/8 +XQAOMGYPcFEHbnf/AIugAcYMwe4KIO3O/wDxdAA4wZg9wUQdud/+LoAHGDMHuCiDtzv/AMXQAOMG +YPcFEHbnf/i6ABxgzB7gog7c7/8AF0ADjBmD3BRB253/AOLoAHGDMHuCiDtzv/xdAA4wZg9wUQdu +d/8Ai6ABxgzB7gog7c7/APF0ADjBmD3BRB253/4ugAcYMwe4KIO3O/8AxdAA4wZg9wUQdud/+LoA +HGDMHuCiDtzv/wAXQAOMGYPcFEHbnf8A4ugAcYMwe4KIO3O//F0ADjBmD3BRB253/wCLoAHGDMHu +CiDtzv8A8XQAOMGYPcFEHbnf/i6ABxgzB7gog7c7/wDF0ADjBmD3BRB253/4ugAcYMwe4KIO3O// +ABdAA4wZg9wUQdud/wDi6ADqGnvMJnHfjoxogx9FTg4eOR/3cHl8zvdreHh+aKsMqRORyt1T8RbW +a/iI1Yj9uvta/wAqFuF0vMq1iuxUb0PFaXcPDXjTkDNzK+RSnELh4K0p5IyKr1E2s1GrR3f5en/h +MPu9GOtuc71nt1/8vX/xoYvyNrZOj5TVAknOCIW0aULKl6qVrtkBSMlSual1pu0nSkSptMJszjrS +3q3DXqdK3dDbS6ttbZ6Lr1sTUZ6n1b/tf+H7PEx+TyvfI9ZPX+j/AGeT/wAUwDfXI8yg+ivW0/J8 +MYUm+nU85G/E+TnVMF3QWZMdl+VjWY7L78VtaUrdjvtpdXh6GvNpWbh81mxR7F6cY/8AxpdU/wBz +r+Uh5PJjmSK/6yqmq68K/wDxiPmQv7rfmf6xkU8svwOiF6XV9bJqW05BxYMWPm8Fc+WxOxXnDHBW +vDkvpw82tLaW216EdF8zcY9Plek1c/0/rSonweTp/GSMXlpm6/dg6zRsSdjfC/xr4nifqR/deFtv +N5QRkKc4PTzhvIUzllnsQf2Y2SzFc9l/R0tvTqX5aZC9cmPgpkx9DdfS6lf4vQ1rUvNSlQnbND0o +3RNeCzovoVO1a6qh1u+VuQyNd8Nrq5yuXTikG1O1F7EnTXs07T7Q/wC7LS8juFHXr9r4fN9aFEqp +WFLWK/S9MuYlkpnLW1y9Sz247LM9tta06nWlaU4PJEhb86XWY5Y06c27k0/5jXT8CchP5Czx/k02 +hNFKnUKORq6qnh9Nf4ecqlSQeQqk3U2b9ftp3FsXG71SI12c1nuNs1BaLwIKyt2az5HMfYKFVRVr +YSwdbzTrxmb+qW16LFgust/jXUqMMzXXXrfE2MZ6q5ayI3vc3dorXtfrt5bdddummvDXX0aGeYnp +H1XkIb3rDmKxXcNm3grVbprvXs11109oyg5Y3B1HXrW+vBwdFvXGfzK8Gsm4fN+iNfmZFx9LPsKX +6SW+12ADYSi/8XFvS7fPoALxAD//1N95e+4Mv0t3oACJTcX8lnJ94GvrKgDHLkqStMumkD5a/wCx +lfbPyOH+TvtsvXygBn5pJ+pjqL8GGA/0UtMAZPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAxf28pwxO1aeXs5 +pLT9/c6A6ACHrlpitC+u+s9aU/l72xvSvMrTnaybf+X80Aep0s+wpfpJb7XYANhKL/xcW9Lt8+gA +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 +ue9yNa1PbVyoiHnof341ulXWi7bFfeRPX+ISC4qNt0qmyS4yolysJZIOOxtkiL6UFJ2nWq3DLjyn +CJlOx5VOuQwWUynDbZmy9RtlMhD6q9XNyE0cU1lXsaxXt3JYhlnr2qi8drrNO1Vt1bDI1kYk1Wfl +vkiakjrOm9MjZysGOa6wyorXLJGiujkgkrw24LUapx8PYqWa9mJ70Y5Ipmc1kb9zG9rXDd2Ddh4h +ckxp8iRQiNtp5ZRX184TlxoOVDR4fYksSzGzZm9YcmDIlkEqNpFTohU1giq5rbUvqBc1jxGzNpPL +nr3dTsx0sDZmryMmuVce50bmqjorV+nUttou1RFWwzxkLEYrWyScyJ6RN5rGneHW3lLOMoJ4h/jJ +oK6x99bXIeyN7oWt137ZJGxvaxX7Hq1qruciHvabe6m1fD6jGm0Gu9ZJi5vqbskyPaTXGvZxHTVR +S5A4sOV9NPsm6/NFvpJRVK5TJ1QLly2DGZxXX3225LK1oVWuvRyTUWrNEyy2u5zO+iWHz+FZAqt1 +RJnWv1ZsS990/wAijVk7p1c9jFpo96ItiJJItV05sboFstkj/PY6ui2Ec3VqwIsqLy03HVJblagq +TAkCV07avW0/FsTruFrynJRKc4wNMCNHMYOkk0u3ZAeOB0ZG6zV3OoqZYvYUUTJYxdmMY7KWVuyW +0rbNtVn0MZlWWY1xd1+yvMjkWKw7Y2XbDJrsldy3sk0Yrl2Pa/3rkVa8cM0163i4YnPycEaySwoi +rLHG1JFc+SNO+xjUhlVXORGokUiqvcdp2EXcDUpyO2OGA3dotdV59zE2Sz1iNlIs2xoqO2U2ccwq +xko7Y4bZFzZ1l8Nk0XQT2TGfTMJorfYSz3W31phyVtvo61maxcqQ13vtV42ySsRqq+KN8TJ2Pkai +asY+GWOZrnIjXRSMkRVY9qravmhjqQX5JWtoSzOiZIqokb5WS8h0bXr3XSNm+RcxFVyS/JqiP4Hg +WlvBBMk7WU1TiWR4llh1IMays9pTzR1LzOeLgiBxRi/YzYdGC/2Q2squpNtaXTz8OXf5RMEM5bKi +5sPrfLddfdgpYpvrfH5vLVV3YqqmP5cze/FOt71gqoyRO5rC2kxy7VfvbYavcRqLJVyf/SrGKpWu +5krMszVhf3JWMiijkSRWL3la/mI1F2tROC7l10KS3t94eouT+RmZOU9VGvr7J90SqsnbLyHrkxY7 +kF1YmThk01dHSshTo8FbKnEY0UU9ezXLpFCz409QtpXF64KqWAjQhnrPwOKz09mOBttZtsMjkSZj +YLrca979u6FG+sXpRarZnq+wsbWorZ6z5q1mvNBlJsXDE6xy4GSuljaqxIksXOjau9GSbnRNkk/0 +ejWwyq9zdE3XUzbgallzUREM+0WuuA9sCWKHIGJ5ptjTGam0moGyyeQNREXvc1uaSSx4+cw4MN6N +Q7blzZbLLa1uutpW55MvjZ8bynesYqrbL4tF5jKz43zMsOZ75sDoYpJWyqiRujje9HK1jlSzdYrs +otyj52JjFnfCkyuRIlmje2OSJJNdnMjkexj2a7mvc1rkRzkRbGsjlSOT9eUfqclndutcY9a6RKT5 +h5QMSZPkKNO8s+GM5nK3703NmzSCaTsOR1pzYyriLhvz2nDzfMFzvUcduSttlKs5l2p01bqvbI3L +U47FZrV3Oej4as0kSImu6et4ytHajjV/JlljY5y8yNXXViGarkM7jJ4XNs46wkM+qKiMc5ZUjVdd +Fa2VYJ0iV6NV6wTIiaxP04UDf1mnNi5chh2ozZYLBiBBlp1OCc3HJqUSaGBrxQx9TnyfcixapoSU +it5BOJuz91cxzOr3lyWBBrnuvyWnK0Kd63LdhchmMjKlRa8kUbmSd3vy5XO4prFc5W7X8zCo9Gq3 +Vz7aQomsKPm6So593D1MY1biXWsdG6Lvbmvpx20cxGb96bX6IrV0Vqb+xdEvqjbiajuJFYLlb+02 +uS63JWV8jei5fRpvjNTRZJX8ToTGPlQ2CqknPnIvFXxPVaJo9xZOyGc1qobwlK29Xy2Y7qvhbXiY +KfhpPGSta5jNq73tfFZnY5rdNzmvgpXJmqiKjoqlmRNWQSqyis8CV7txZmJUrbuc/VNkW1InO5ju +yPak0Ku3KmiSxKvCRmuRooFUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAxD3j94Iv8IDTv5X0FgDWF2+94mMPhwQf8mvd0ASdaWfYUv0k +t9rsAGwlF/4uLel2+fQAXiAH/9PfeXvuDL9Ld6AAiU3F/JZyfeBr6yoAiO0f957V3+szYr+0S2kA +EqDfiB67AclFDEHMJ3l2Cry3qRrnHqy8ctLbjbfjx1sqPEaWT6BjypC6TzPC2LTazaiYzZXKRyLF +xa01WwvXLfbTdTq3Zsey9ZljpxXK07+WyKR0ja1iKwtdWzI6LZZSLw8rpGSsZHK97oLCN5Ml1Uv2 +cY+xcoxtXItrztgVznsSKw+GRkE+6NUk/V5nMnRGOY5yxo1skaqj248fs7dm4ilYzJUWyoz9oiKH +PMW7StltbZrrTiVSXpfT4DlTViSk4+tax6nEo9jlHTYrVWartpXTWSrKGZaRT5Y6XsodsVMV5Qv2 +Kawyy1I5LMT8vDHJvkSVlXMeDuTyI96SKlhMlBdR8bEjinpZe21ZIntVliwlo01qTVq9iSKOTH4+ +B0aRx7N2JvRzVEe5ux88L6b3Qqk2+WrPjcU+KSaBiV6vrm1ye8wmGvEBN6r8SkVlYkOeS+2aY2lB +3rTUfECSrtOt7YJDCaeNba6RlcypgXypZrG7VgsQLYW+63FkxZM2XqGAzzjEqYrI9POje+TG0sFh +InrsSOabK9O1kiw9lqpI/kVq1qzfvOja+R8z21IH6x81ydMm2XL0OpVsRRsydy7eSJu50kLMbmYo +6mYqScI+ZNLVhrcmzy0Vliox7GQQ2LELscti+TL3L2He8gn3Y9WE4Cqko7YFEB9PfcDaRwobjj+c +YVmiJ4tYdul2CKE/VyCccapj5Qk5TVkOrhWnAVTjZ8ybuOGzWE3Y9NwwU1xy5yrHK1kNOG01US0t +1YM/hspYsOksIxa7LMGLlVMZCzwkcs9etzXxVG2ZJTK2lnuxz45yxxQ2o7FZW6wLVVuOs01jY2JV +WeTfcmVL08rpuW6VrYWNsNjrZgzXpjMhnY4jsvCabBq0ox6W1jMsGJZFc7pj1nO49D7a2yj50Jrp +c7SiuSM7BxoTY2PJqTUUySI4b8amjVL5iRbFfYasua129Wv38lIjbNq3lsrPI6R7uYyLJYvE1PEQ +yq16tvc/Guhn3NVs+Mt26/Oa+yqxRbKNR+GxGIkXkpVxVWuixsRzVdTyKXo4HMV0e6ovfcxNzVgu +JBabFJyVjlsvn5P+cnXs045qk+NY+dTemSWIOnl6pTZ5THfCM0WDZGjBmxg0Klm1AzJiFM172ytZ +6lEaYvoS06UhinD2XJYmHylpciXN5LGChE3C3sCt2SN3LyzYLfLSw9iZavZ5jUqTyLFA6Ka9cqc+ +CdqS01jspXhtLNHJe5O3Yvsp2FrxvlbTiqSVnOWOJ0UFueVqpZiY2ZzJo5WzPrviVYbnPWOy9k7V +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 ++k037W6d/pj/ANt2f+k1yMfUz96z/N/8zTx9TP3rP83/AMzSU9eOqYB4tP8A23Z/6TUbM/p1gAfY +4gHcIZaCCP5TWDxXIx9TP3rP83/zNKPqZ+9Z/m/+ZpKenD+hstNwltxEG0MuDyP3TYGb9qf1eh68 ++4lzvZdq4ja57vZ7nub+euXj6mfvWf5v/maUfUz96z/N/wDM0lPTvt6I/buc72cEC8HkO+k0D6Lm +N2f6NRNnQi5rnWWFzJ2OJySWzodhP0P7K5qPqZ+9Z/m/+ZpR9TP3rP8AN/8AM08e7QrirpXFTFL2 +OI8Xt8XXi4eJ6QWdAaIbY9ugHtOSNANrW+391qsDqHSnVCgWfo2gNDWstEBsbI2s3e3auTj6mfvW +f5v/AJmlH1M/es/zf/M0pcf6XF/hWnH7Vn2+C+vBw/8AcvUm3o7hDi5wPIc24j7nMSFvRh9EubpG +jbhp4aMXLR9TP3rP83/zNKPqZ+9Z/m/+ZpjI9Y3O6ZSx4Y9w3gzLLTJgtb9Nnmsr6nD9bzPJ4B+I +rqa4f2XLIj6mfvWf5v8A5mup+rX7I+zf5MM1/AD/AKklJT//2f/tG5BQaG90b3Nob3AgMy4wADhC +SU0EJQAAAAAAEAAAAAAAAAAAAAAAAAAAAAA4QklNBDoAAAAAAJMAAAAQAAAAAQAAAAAAC3ByaW50 +T3V0cHV0AAAABQAAAABDbHJTZW51bQAAAABDbHJTAAAAAFJHQkMAAAAASW50ZWVudW0AAAAASW50 +ZQAAAABJbWcgAAAAAE1wQmxib29sAQAAAA9wcmludFNpeHRlZW5CaXRib29sAAAAAAtwcmludGVy +TmFtZVRFWFQAAAABAAAAOEJJTQQ7AAAAAAGyAAAAEAAAAAEAAAAAABJwcmludE91dHB1dE9wdGlv +bnMAAAASAAAAAENwdG5ib29sAAAAAABDbGJyYm9vbAAAAAAAUmdzTWJvb2wAAAAAAENybkNib29s +AAAAAABDbnRDYm9vbAAAAAAATGJsc2Jvb2wAAAAAAE5ndHZib29sAAAAAABFbWxEYm9vbAAAAAAA +SW50cmJvb2wAAAAAAEJja2dPYmpjAAAAAQAAAAAAAFJHQkMAAAADAAAAAFJkICBkb3ViQG/gAAAA +AAAAAAAAR3JuIGRvdWJAb+AAAAAAAAAAAABCbCAgZG91YkBv4AAAAAAAAAAAAEJyZFRVbnRGI1Js +dAAAAAAAAAAAAAAAAEJsZCBVbnRGI1JsdAAAAAAAAAAAAAAAAFJzbHRVbnRGI1B4bEBSAAAAAAAA +AAAACnZlY3RvckRhdGFib29sAQAAAABQZ1BzZW51bQAAAABQZ1BzAAAAAFBnUEMAAAAATGVmdFVu +dEYjUmx0AAAAAAAAAAAAAAAAVG9wIFVudEYjUmx0AAAAAAAAAAAAAAAAU2NsIFVudEYjUHJjQFkA +AAAAAAA4QklNA+0AAAAAABAASAAAAAEAAgBIAAAAAQACOEJJTQQmAAAAAAAOAAAAAAAAAAAAAD+A +AAA4QklNBA0AAAAAAAQAAAB4OEJJTQQZAAAAAAAEAAAAHjhCSU0D8wAAAAAACQAAAAAAAAAAAQA4 +QklNJxAAAAAAAAoAAQAAAAAAAAACOEJJTQP1AAAAAABIAC9mZgABAGxmZgAGAAAAAAABAC9mZgAB +AKGZmgAGAAAAAAABADIAAAABAFoAAAAGAAAAAAABADUAAAABAC0AAAAGAAAAAAABOEJJTQP4AAAA +AABwAAD/////////////////////////////A+gAAAAA/////////////////////////////wPo +AAAAAP////////////////////////////8D6AAAAAD/////////////////////////////A+gA +ADhCSU0EAAAAAAAAAgADOEJJTQQCAAAAAAAIAAAAAAAAAAA4QklNBDAAAAAAAAQBAQEBOEJJTQQt +AAAAAAAGAAEAAAAEOEJJTQQIAAAAAAAQAAAAAQAAAkAAAAJAAAAAADhCSU0EHgAAAAAABAAAAAA4 +QklNBBoAAAAAAz8AAAAGAAAAAAAAAAAAAAGpAAACIgAAAAVnKmgHmJgALQAxAAAAAQAAAAAAAAAA +AAAAAAAAAAAAAAABAAAAAAAAAAAAAAIiAAABqQAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAA +AAAAAAAAABAAAAABAAAAAAAAbnVsbAAAAAIAAAAGYm91bmRzT2JqYwAAAAEAAAAAAABSY3QxAAAA +BAAAAABUb3AgbG9uZwAAAAAAAAAATGVmdGxvbmcAAAAAAAAAAEJ0b21sb25nAAABqQAAAABSZ2h0 +bG9uZwAAAiIAAAAGc2xpY2VzVmxMcwAAAAFPYmpjAAAAAQAAAAAABXNsaWNlAAAAEgAAAAdzbGlj +ZUlEbG9uZwAAAAAAAAAHZ3JvdXBJRGxvbmcAAAAAAAAABm9yaWdpbmVudW0AAAAMRVNsaWNlT3Jp +Z2luAAAADWF1dG9HZW5lcmF0ZWQAAAAAVHlwZWVudW0AAAAKRVNsaWNlVHlwZQAAAABJbWcgAAAA +BmJvdW5kc09iamMAAAABAAAAAAAAUmN0MQAAAAQAAAAAVG9wIGxvbmcAAAAAAAAAAExlZnRsb25n +AAAAAAAAAABCdG9tbG9uZwAAAakAAAAAUmdodGxvbmcAAAIiAAAAA3VybFRFWFQAAAABAAAAAAAA +bnVsbFRFWFQAAAABAAAAAAAATXNnZVRFWFQAAAABAAAAAAAGYWx0VGFnVEVYVAAAAAEAAAAAAA5j +ZWxsVGV4dElzSFRNTGJvb2wBAAAACGNlbGxUZXh0VEVYVAAAAAEAAAAAAAlob3J6QWxpZ25lbnVt +AAAAD0VTbGljZUhvcnpBbGlnbgAAAAdkZWZhdWx0AAAACXZlcnRBbGlnbmVudW0AAAAPRVNsaWNl +VmVydEFsaWduAAAAB2RlZmF1bHQAAAALYmdDb2xvclR5cGVlbnVtAAAAEUVTbGljZUJHQ29sb3JU +eXBlAAAAAE5vbmUAAAAJdG9wT3V0c2V0bG9uZwAAAAAAAAAKbGVmdE91dHNldGxvbmcAAAAAAAAA +DGJvdHRvbU91dHNldGxvbmcAAAAAAAAAC3JpZ2h0T3V0c2V0bG9uZwAAAAAAOEJJTQQoAAAAAAAM +AAAAAj/wAAAAAAAAOEJJTQQUAAAAAAAEAAAABDhCSU0EDAAAAAATTgAAAAEAAACgAAAAfQAAAeAA +AOpgAAATMgAYAAH/2P/tAAxBZG9iZV9DTQAB/+4ADkFkb2JlAGSAAAAAAf/bAIQADAgICAkIDAkJ +DBELCgsRFQ8MDA8VGBMTFRMTGBEMDAwMDAwRDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAEN +CwsNDg0QDg4QFA4ODhQUDg4ODhQRDAwMDAwREQwMDAwMDBEMDAwMDAwMDAwMDAwMDAwMDAwMDAwM +DAwMDAwM/8AAEQgAfQCgAwEiAAIRAQMRAf/dAAQACv/EAT8AAAEFAQEBAQEBAAAAAAAAAAMAAQIE +BQYHCAkKCwEAAQUBAQEBAQEAAAAAAAAAAQACAwQFBgcICQoLEAABBAEDAgQCBQcGCAUDDDMBAAIR +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 +8zSj6mfvWf5v/maYyPWNzumUseGPcN4Myy0yYLW/TZ5rK+pw/W8zyeAfiK6muH9lyyI+pn71n+b/ +AOZrqfq1+yPs3+TDNfwA/wCpJSU//9k4QklNBCEAAAAAAFUAAAABAQAAAA8AQQBkAG8AYgBlACAA +UABoAG8AdABvAHMAaABvAHAAAAATAEEAZABvAGIAZQAgAFAAaABvAHQAbwBzAGgAbwBwACAAQwBT +ADUAAAABADhCSU0EBgAAAAAABwAIAAEAAQEA/+EN0Gh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEu +MC8APD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4g +PHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENv +cmUgNS4wLWMwNjAgNjEuMTM0Nzc3LCAyMDEwLzAyLzEyLTE3OjMyOjAwICAgICAgICAiPiA8cmRm +OlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1u +cyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5h +ZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8x +LjAvbW0vIiB4bWxuczpzdEV2dD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jl +c291cmNlRXZlbnQjIiB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8i +IHhtbG5zOnBob3Rvc2hvcD0iaHR0cDovL25zLmFkb2JlLmNvbS9waG90b3Nob3AvMS4wLyIgeG1w +OkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IFdpbmRvd3MiIHhtcDpDcmVhdGVEYXRl +PSIyMDEwLTA4LTMxVDAwOjQzOjUyKzA4OjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDEwLTA4LTMx +VDAwOjQzOjUyKzA4OjAwIiB4bXA6TW9kaWZ5RGF0ZT0iMjAxMC0wOC0zMVQwMDo0Mzo1MiswODow +MCIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo1MUIxNDlGNDU0QjRERjExQkU3RUIyMzcyOTQy +Rjc0OSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo1MEIxNDlGNDU0QjRERjExQkU3RUIyMzcy +OTQyRjc0OSIgeG1wTU06T3JpZ2luYWxEb2N1bWVudElEPSJ4bXAuZGlkOjUwQjE0OUY0NTRCNERG +MTFCRTdFQjIzNzI5NDJGNzQ5IiBkYzpmb3JtYXQ9ImltYWdlL2pwZWciIHBob3Rvc2hvcDpDb2xv +ck1vZGU9IjMiIHBob3Rvc2hvcDpJQ0NQcm9maWxlPSJzUkdCIElFQzYxOTY2LTIuMSI+IDx4bXBN +TTpIaXN0b3J5PiA8cmRmOlNlcT4gPHJkZjpsaSBzdEV2dDphY3Rpb249ImNyZWF0ZWQiIHN0RXZ0 +Omluc3RhbmNlSUQ9InhtcC5paWQ6NTBCMTQ5RjQ1NEI0REYxMUJFN0VCMjM3Mjk0MkY3NDkiIHN0 +RXZ0OndoZW49IjIwMTAtMDgtMzFUMDA6NDM6NTIrMDg6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9 +IkFkb2JlIFBob3Rvc2hvcCBDUzUgV2luZG93cyIvPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0ic2F2 +ZWQiIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6NTFCMTQ5RjQ1NEI0REYxMUJFN0VCMjM3Mjk0 +MkY3NDkiIHN0RXZ0OndoZW49IjIwMTAtMDgtMzFUMDA6NDM6NTIrMDg6MDAiIHN0RXZ0OnNvZnR3 +YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCBDUzUgV2luZG93cyIgc3RFdnQ6Y2hhbmdlZD0iLyIv +PiA8L3JkZjpTZXE+IDwveG1wTU06SGlzdG9yeT4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJE +Rj4gPC94OnhtcG1ldGE+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg +ICAgICAgICAgICAgPD94cGFja2V0IGVuZD0idyI/Pv/iDFhJQ0NfUFJPRklMRQABAQAADEhMaW5v +AhAAAG1udHJSR0IgWFlaIAfOAAIACQAGADEAAGFjc3BNU0ZUAAAAAElFQyBzUkdCAAAAAAAAAAAA +AAAAAAD21gABAAAAANMtSFAgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAEWNwcnQAAAFQAAAAM2Rlc2MAAAGEAAAAbHd0cHQAAAHwAAAAFGJrcHQAAAIEAAAA +FHJYWVoAAAIYAAAAFGdYWVoAAAIsAAAAFGJYWVoAAAJAAAAAFGRtbmQAAAJUAAAAcGRtZGQAAALE +AAAAiHZ1ZWQAAANMAAAAhnZpZXcAAAPUAAAAJGx1bWkAAAP4AAAAFG1lYXMAAAQMAAAAJHRlY2gA +AAQwAAAADHJUUkMAAAQ8AAAIDGdUUkMAAAQ8AAAIDGJUUkMAAAQ8AAAIDHRleHQAAAAAQ29weXJp +Z2h0IChjKSAxOTk4IEhld2xldHQtUGFja2FyZCBDb21wYW55AABkZXNjAAAAAAAAABJzUkdCIElF +QzYxOTY2LTIuMQAAAAAAAAAAAAAAEnNSR0IgSUVDNjE5NjYtMi4xAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABYWVogAAAAAAAA81EAAQAAAAEWzFhZWiAA +AAAAAAAAAAAAAAAAAAAAWFlaIAAAAAAAAG+iAAA49QAAA5BYWVogAAAAAAAAYpkAALeFAAAY2lhZ +WiAAAAAAAAAkoAAAD4QAALbPZGVzYwAAAAAAAAAWSUVDIGh0dHA6Ly93d3cuaWVjLmNoAAAAAAAA +AAAAAAAWSUVDIGh0dHA6Ly93d3cuaWVjLmNoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAGRlc2MAAAAAAAAALklFQyA2MTk2Ni0yLjEgRGVmYXVsdCBSR0IgY29s +b3VyIHNwYWNlIC0gc1JHQgAAAAAAAAAAAAAALklFQyA2MTk2Ni0yLjEgRGVmYXVsdCBSR0IgY29s +b3VyIHNwYWNlIC0gc1JHQgAAAAAAAAAAAAAAAAAAAAAAAAAAAABkZXNjAAAAAAAAACxSZWZlcmVu +Y2UgVmlld2luZyBDb25kaXRpb24gaW4gSUVDNjE5NjYtMi4xAAAAAAAAAAAAAAAsUmVmZXJlbmNl +IFZpZXdpbmcgQ29uZGl0aW9uIGluIElFQzYxOTY2LTIuMQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAdmlldwAAAAAAE6T+ABRfLgAQzxQAA+3MAAQTCwADXJ4AAAABWFlaIAAAAAAATAlWAFAAAABX +H+dtZWFzAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAACjwAAAAJzaWcgAAAAAENSVCBjdXJ2AAAA +AAAABAAAAAAFAAoADwAUABkAHgAjACgALQAyADcAOwBAAEUASgBPAFQAWQBeAGMAaABtAHIAdwB8 +AIEAhgCLAJAAlQCaAJ8ApACpAK4AsgC3ALwAwQDGAMsA0ADVANsA4ADlAOsA8AD2APsBAQEHAQ0B +EwEZAR8BJQErATIBOAE+AUUBTAFSAVkBYAFnAW4BdQF8AYMBiwGSAZoBoQGpAbEBuQHBAckB0QHZ +AeEB6QHyAfoCAwIMAhQCHQImAi8COAJBAksCVAJdAmcCcQJ6AoQCjgKYAqICrAK2AsECywLVAuAC +6wL1AwADCwMWAyEDLQM4A0MDTwNaA2YDcgN+A4oDlgOiA64DugPHA9MD4APsA/kEBgQTBCAELQQ7 +BEgEVQRjBHEEfgSMBJoEqAS2BMQE0wThBPAE/gUNBRwFKwU6BUkFWAVnBXcFhgWWBaYFtQXFBdUF +5QX2BgYGFgYnBjcGSAZZBmoGewaMBp0GrwbABtEG4wb1BwcHGQcrBz0HTwdhB3QHhgeZB6wHvwfS +B+UH+AgLCB8IMghGCFoIbgiCCJYIqgi+CNII5wj7CRAJJQk6CU8JZAl5CY8JpAm6Cc8J5Qn7ChEK +Jwo9ClQKagqBCpgKrgrFCtwK8wsLCyILOQtRC2kLgAuYC7ALyAvhC/kMEgwqDEMMXAx1DI4MpwzA +DNkM8w0NDSYNQA1aDXQNjg2pDcMN3g34DhMOLg5JDmQOfw6bDrYO0g7uDwkPJQ9BD14Peg+WD7MP +zw/sEAkQJhBDEGEQfhCbELkQ1xD1ERMRMRFPEW0RjBGqEckR6BIHEiYSRRJkEoQSoxLDEuMTAxMj +E0MTYxODE6QTxRPlFAYUJxRJFGoUixStFM4U8BUSFTQVVhV4FZsVvRXgFgMWJhZJFmwWjxayFtYW ++hcdF0EXZReJF64X0hf3GBsYQBhlGIoYrxjVGPoZIBlFGWsZkRm3Gd0aBBoqGlEadxqeGsUa7BsU +GzsbYxuKG7Ib2hwCHCocUhx7HKMczBz1HR4dRx1wHZkdwx3sHhYeQB5qHpQevh7pHxMfPh9pH5Qf +vx/qIBUgQSBsIJggxCDwIRwhSCF1IaEhziH7IiciVSKCIq8i3SMKIzgjZiOUI8Ij8CQfJE0kfCSr +JNolCSU4JWgllyXHJfcmJyZXJocmtyboJxgnSSd6J6sn3CgNKD8ocSiiKNQpBik4KWspnSnQKgIq +NSpoKpsqzysCKzYraSudK9EsBSw5LG4soizXLQwtQS12Last4S4WLkwugi63Lu4vJC9aL5Evxy/+ +MDUwbDCkMNsxEjFKMYIxujHyMioyYzKbMtQzDTNGM38zuDPxNCs0ZTSeNNg1EzVNNYc1wjX9Njc2 +cjauNuk3JDdgN5w31zgUOFA4jDjIOQU5Qjl/Obw5+To2OnQ6sjrvOy07azuqO+g8JzxlPKQ84z0i +PWE9oT3gPiA+YD6gPuA/IT9hP6I/4kAjQGRApkDnQSlBakGsQe5CMEJyQrVC90M6Q31DwEQDREdE +ikTORRJFVUWaRd5GIkZnRqtG8Ec1R3tHwEgFSEtIkUjXSR1JY0mpSfBKN0p9SsRLDEtTS5pL4kwq +THJMuk0CTUpNk03cTiVObk63TwBPSU+TT91QJ1BxULtRBlFQUZtR5lIxUnxSx1MTU19TqlP2VEJU +j1TbVShVdVXCVg9WXFapVvdXRFeSV+BYL1h9WMtZGllpWbhaB1pWWqZa9VtFW5Vb5Vw1XIZc1l0n +XXhdyV4aXmxevV8PX2Ffs2AFYFdgqmD8YU9homH1YklinGLwY0Njl2PrZEBklGTpZT1lkmXnZj1m +kmboZz1nk2fpaD9olmjsaUNpmmnxakhqn2r3a09rp2v/bFdsr20IbWBtuW4SbmtuxG8eb3hv0XAr +cIZw4HE6cZVx8HJLcqZzAXNdc7h0FHRwdMx1KHWFdeF2Pnabdvh3VnezeBF4bnjMeSp5iXnnekZ6 +pXsEe2N7wnwhfIF84X1BfaF+AX5ifsJ/I3+Ef+WAR4CogQqBa4HNgjCCkoL0g1eDuoQdhICE44VH +hauGDoZyhteHO4efiASIaYjOiTOJmYn+imSKyoswi5aL/IxjjMqNMY2Yjf+OZo7OjzaPnpAGkG6Q +1pE/kaiSEZJ6kuOTTZO2lCCUipT0lV+VyZY0lp+XCpd1l+CYTJi4mSSZkJn8mmia1ZtCm6+cHJyJ +nPedZJ3SnkCerp8dn4uf+qBpoNihR6G2oiailqMGo3aj5qRWpMelOKWpphqmi6b9p26n4KhSqMSp +N6mpqhyqj6sCq3Wr6axcrNCtRK24ri2uoa8Wr4uwALB1sOqxYLHWskuywrM4s660JbSctRO1irYB +tnm28Ldot+C4WbjRuUq5wro7urW7LrunvCG8m70VvY++Cr6Evv+/er/1wHDA7MFnwePCX8Lbw1jD +1MRRxM7FS8XIxkbGw8dBx7/IPci8yTrJuco4yrfLNsu2zDXMtc01zbXONs62zzfPuNA50LrRPNG+ +0j/SwdNE08bUSdTL1U7V0dZV1tjXXNfg2GTY6Nls2fHadtr724DcBdyK3RDdlt4c3qLfKd+v4Dbg +veFE4cziU+Lb42Pj6+Rz5PzlhOYN5pbnH+ep6DLovOlG6dDqW+rl63Dr++yG7RHtnO4o7rTvQO/M +8Fjw5fFy8f/yjPMZ86f0NPTC9VD13vZt9vv3ivgZ+Kj5OPnH+lf65/t3/Af8mP0p/br+S/7c/23/ +///uAA5BZG9iZQBkQAAAAAH/2wCEAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB +AQEBAQEBAQECAgICAgICAgICAgMDAwMDAwMDAwMBAQEBAQEBAQEBAQICAQICAwMDAwMDAwMDAwMD +AwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA//AABEIAakCIgMBEQACEQEDEQH/ +3QAEAEX/xAEKAAEAAQQDAQEBAAAAAAAAAAAACQUHCAoDBAYBAgsBAQABBAMBAQAAAAAAAAAAAAAE +AgMFBgEHCAkKEAAABQQAAAQKDhMJCgsFBgcEBQYHCAABAgMRFhcJITESExQVl9cY2EFRYbHSc5OU +VVY3WHiYcYHBcpKyM7PTNFR0NTZXtzi4GZGhIjJS1JXWufDRI1MkJXeHiApCg4QmlidnKEioyOFD +Rsdo8WKkdTmZwmNFtkdZqREAAgMAAQMCBAEFBw4JCgcBAAIBAwQFERIGIRMxIhQHI0FRMhUIYXHS +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 +7nyTP6tj0hq19xW7rO21Or/I9Vc/pdGSzJDzeUm0I7yXU7c8hqQAmbnDT50nUK3icAUaH7R4TafW +UJc0CoiguY7OIwbq9ZJXLB3KVWDN2/XiPPxA+xYfbAGN9Zhz45dPG5eC4zkI68Vlw8dXdWv4qX34 +OCw8aj1w3tW5LU05JmvTn0LXbmjI2vj73yRTZXzrxyFPkL5lhtuvRyU0S8e22aOTmuNFzWJ3xsS5 +YadPG66LM1rLZK6K7tn1OLkXEJJymZDm1RWatmbsqXO1LFVhSFHzclZEU8W4ORDtnDpoRxHBUEeG +L3ONmbMyBWJ4Rb29Dq3alFb2XrNBZiF3hwgQLrurjtPI+O5uG1rXGqvx2nia2lmuozxiz15K9k5W +Wqrc/I0qlmjLq6V8bOec+e3dG67TnykclXj5rkuU45Giu3laN3T5a77OtE/UZI0xFjY0p1IllGvM +jX6EeItSiM017LAAuZykfdvtKdN3GavYdkbfNxoK+0LmvmjbqFctSU82ePJyQW4aFIUk5rekCoU8 +Iz4LdTkgzYfp3SaFZoFCDBWreC1bty3LLp5rdzWamx5fmm1+3Nr55spu5Ty7RejX09WqujH5HS1c ++3dS+ui2q+p83rdrnE4kwcfj4j3Fqypxd2LuSpbYrR+OXFX2UXMy2UxKxXZQ9qM+RnqW+t2ixM4I +lwUVbSv0lX3VzYN+3hmXJCQpWqAmuZcnZ3rc8WzsiouACNcB3qlY2SIcAH1xEMRvKDAvwvrDBNAc +FbRcRYSJ7HjZNFOLHy9FT+ujHioSEpqq9tKd3MbtlTWJPfdXo0bsuqWeOr6EfvWPp6LLGuu7bbx7 +Wr/yGtres22PDrGT6emYraOyuyqHvqiV6zNL9O/pPtrJ4dpoeci9YoKvl2ldesPhouXpfBuci/dn +js27LjN11e26wMuzNmO22GXUCcNHUa8Op1Y59XnnjiWUfiIcfljd/wBTY7vGUA4iHH5Y3f8AU2O7 +xlAOIhx+WN3/AFNju8ZQDiIcfljd/wBTY7vGUA4iHH5Y3f8AU2O7xlAOIhx+WN3/AFNju8ZQDiIc +fljd/wBTY7vGUA4iHH5Y3f8AU2O7xlAOIhx+WN3/AFNju8ZQDiIcfljd/wBTY7vGUA4iHH5Y3f8A +U2O7xlAOIhx+WN3/AFNju8ZQDiIcfljd/wBTY7vGUA4iHH5Y3f8AU2O7xlAOIhx+WN3/AFNju8ZQ +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 +2A68OC9v/dWt0ujw9CgMt0ghgxNq1YYaccLY2t0LWtbpcHmUBdsPpx1YWxtboWt0KA7FAf/U3+KA +4dvk/O/36A8wY9K/yPmUB5YR5Hz16A6tAKAUAoBQCgFAKAUAoBQCgFAKAUAoBQCgFAKAUAoBQCgF +AKAUAoBQCgFAKAUAoBQCgFAKAUAoBQCgFAKAUAoBQCgFAKAUAoBQCgFAKAUAoBQCgP3r/j4/JoCu +gv49v7vJvQHsA/8AEv8AK86gKhQCgP/ZUEsDBBQABgAIAAAAIQCnCbwE/SoAACfQAAARAAAAd29y +ZC9zZXR0aW5ncy54bWycnV1z3UaSpu83Yv+DgtfrNlAACgDD8gQKH9Oz4Z7tGHXvXkzMxRF5ZHFN +8igOKcnuX78PSLFlu5+cmNgrWyeJQqE+sjLffDPru3/6+e721afj+eHmdP/6ov5DdfHqeH91ur65 +//H1xV//sn0zXLx6eDzcXx9uT/fH1xe/HB8u/un7//7fvvt8+XB8fOTPHl7RxP3D5en1xcfz/eXD +1fvj3eHhm7ubq/Pp4fTu8Zur093l6d27m6vjl/9cfHni/Pri/ePjh8tvv/3y0B9OH473tPbudL47 +PD784XT+8dvnJ5fT1ce74/3jt6mq8rfn4+3hkQ4/vL/58PDS2t3/b2u86v1LI5/+s4/4dHf78nef +6+o/+8svn/v5dL7++xP/le7tD3w4n66ODw+M7N3t8+feHW7uX5p5uP2vtPM8nj/cvD0fzr/8qpHv +mba/nU53rz5ffjierxhQ5ryuLr7dBW95OQthOf3r6fHNx/P59PH++o/HA7+F4u10evwivj6+O3y8 +ffzL4e2bx9MHXvDpQFfb9KXx6/PhM5/0z+eb6z+ezjd/O90/Hm7ffDhc8ePLH9dV99yTX/3x/z6e +H2+u/vFPu/zlT28ePtwefvna5vL1RSvr+peXxl/68fz3L81Gf52eW796fzgfrvjELz2d6fb5dPvS +Jiv7w5m5+vPH+6vHj09L8vm599fnN+8PH47L86A8fP/d6fJh/+HLKD28+nR5/JnBP17fPLLBPtxc +3x1+fn3RD0PHDnzgJT8dr063J7bIPfvu1b/XuU7/cfH9d58un4WvRMo0nS6ffmerfPztK97d3N7+ +6pHfveN8vN47/u3veskvny//8Vs+X75j3u+Z+j+f94Xz8i+G5eb69cWXkf7dr/XTC77+8fOjx/vr +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 + +--=_0_10109_1291187882-- + diff --git a/lib_acl_cpp/samples/mime/test8.eml b/lib_acl_cpp/samples/mime/test8.eml new file mode 100644 index 000000000..5f03495ca --- /dev/null +++ b/lib_acl_cpp/samples/mime/test8.eml @@ -0,0 +1,1109 @@ +Return-Path: +Delivered-To: zhengshuxin@51iker.com +Received: from ikerf954f96714 (unknown [123.122.116.217]) + by 51iker.com (zebra mail for UNIX) with ESMTP id 93EFC27465E + for ; Mon, 6 Dec 2010 16:33:19 +0800 (CST) +Message-ID: <4D7F3C7A329447AEA00F9C725EBCB966@ikerf954f96714> +From: +To: +Subject: mixed mail +Date: Mon, 6 Dec 2010 16:31:22 +0800 +MIME-Version: 1.0 +Content-Type: multipart/mixed; + boundary="----=_NextPart_000_0012_01CB9563.04E44200" +X-Priority: 3 +X-MSMail-Priority: Normal +X-Mailer: Microsoft Outlook Express 6.00.2900.5931 +X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2900.5931 + +This is a multi-part message in MIME format. + +------=_NextPart_000_0012_01CB9563.04E44200 +Content-Type: multipart/related; + type="multipart/alternative"; + boundary="----=_NextPart_001_0013_01CB9563.04E44200" + + +------=_NextPart_001_0013_01CB9563.04E44200 +Content-Type: multipart/alternative; + boundary="----=_NextPart_002_0014_01CB9563.04E44200" + + +------=_NextPart_002_0014_01CB9563.04E44200 +Content-Type: text/plain; + charset="gb2312" +Content-Transfer-Encoding: base64 + +DQoNCtPKvP6y4srU + +------=_NextPart_002_0014_01CB9563.04E44200 +Content-Type: text/html; + charset="gb2312" +Content-Transfer-Encoding: base64 + +PCFET0NUWVBFIEhUTUwgUFVCTElDICItLy9XM0MvL0RURCBIVE1MIDQuMCBUcmFuc2l0aW9uYWwv +L0VOIj4NCjxIVE1MPjxIRUFEPg0KPE1FVEEgaHR0cC1lcXVpdj1Db250ZW50LVR5cGUgY29udGVu +dD0idGV4dC9odG1sOyBjaGFyc2V0PWdiMjMxMiI+DQo8TUVUQSBjb250ZW50PSJNU0hUTUwgNi4w +MC42MDAwLjE3MDgwIiBuYW1lPUdFTkVSQVRPUj4NCjxTVFlMRT48L1NUWUxFPg0KPC9IRUFEPg0K +PEJPRFkgYmdDb2xvcj0jYzBjMGMwPg0KPERJVj48Rk9OVCBjb2xvcj0jZmYwMDAwIHNpemU9NT48 +SU1HIGFsdD0iIiBoc3BhY2U9MCANCnNyYz0iY2lkOjExMUNGMkZEMUE4ODRGRjlCRDBBMkI3MzVF +RDc3M0YzQGlrZXJmOTU0Zjk2NzE0IiBhbGlnbj1iYXNlbGluZSANCmJvcmRlcj0wPjwvRk9OVD48 +L0RJVj4NCjxESVY+PEZPTlQgc2l6ZT0yPjwvRk9OVD4mbmJzcDs8L0RJVj4NCjxESVY+PEZPTlQg +Y29sb3I9IzgwMDA4MCBzaXplPTU+PFNUUk9ORz7Tyrz+suLK1DwvU1RST05HPjwvRk9OVD48L0RJ +Vj48L0JPRFk+PC9IVE1MPg0K + +------=_NextPart_002_0014_01CB9563.04E44200-- + +------=_NextPart_001_0013_01CB9563.04E44200 +Content-Type: image/jpeg; + name="q.JPG" +Content-Transfer-Encoding: base64 +Content-ID: <111CF2FD1A884FF9BD0A2B735ED773F3@ikerf954f96714> + +/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0a +HBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIy +MjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCAAwACQDASIA +AhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQA +AAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3 +ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWm +p6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEA +AwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSEx +BhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElK +U1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3 +uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0iXxr +JqWlSG18O6s8c8TBJBECpyCM9a5PwP8A2p4Yvbqa40LUZhNGEAii5GDnvXaeESx8H6bgE4hHT6mt +ON/tLsLdsxKcPKOhPovr7nt069Ol1lT5qajozmVNz5Zt6mJf+OZP7K1NoNOuLS9tIVlC3aDBBcL0 +B+tcpD4m8Zapb/2naWVvsQEGaNccDkggtz+VXvF/y3muqOB/ZsA/8i07wc6L4FnDSKp/fcFsdq15 +KfsuZxT1X5Ec03U5ea2jKOn/ABE12a3LSG1YhsZMXsPQ0VyelIzWrEKSN56D2FFdLw9JO1jBVqjW +57H4LH/FI6Yf+mI/ma1IJDFqMtoFzGY/OBH8BJwQfqckfRvasjwhcCHwfpagbpXiwif3jz+nqa1Y +92nszTyeZHK2XlIxtc8c/wCz0A9OB9PJrP8AeP1O+HwI4Txpxf69/wBg6H/0aa5zQ/CFvqvh99Sk +upY3Xf8AIqgj5a6Pxp/x/wCvf9g6D/0aak8FoD4CnP8A12/lXoKcoUbxfVfkcrhGdW0uz/M5jwx4 +gk0zS3t1tLeUGUtudeeg/wAKKx9L/wCPZv8AfP8AIUV0VKUHJtowhUkopJnoOk2/i3R4YLSL+xGZ +I9kfnu+7bnOBgj/P0q8+peMGi+f/AIRsxvkcu+G7Efe561NceGLq7a7e4uoHe7gWORvIOY2CsMp8 +3AO7p9fWqM3gdrgyNJcxbnSVQoh+RCyIgKjPUbM/j7VwqVNu7t9x18k0rK/3mVqmnalHoGsahqU9 +o7vAkEaWzMwVVkzgk+mcd6wfDC+I9Rsbmx0m+SK2ix5kbkDO/PTgnsa7u/8ADM0fhrVbC1MbPdze +bGoGxV+5x/46T+NVvAXhq/0V777ciDzvL2bG3dN2f5itY1oxpSta99PwIdKTqR3tbX8Rmh/D+2tt +OC6hI0lwzFj5TYVenHTnp1or0JLcBQMUVySr1G73OhUYJWsf/9k= + +------=_NextPart_001_0013_01CB9563.04E44200-- + +------=_NextPart_000_0012_01CB9563.04E44200 +Content-Type: application/vnd.openxmlformats-officedocument.presentationml.presentation; + name="=?gb2312?B?zOXPtb3hubkucHB0eA==?=" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; + filename="=?gb2312?B?zOXPtb3hubkucHB0eA==?=" + +UEsDBBQABgAIAAAAIQAQ2mU99QEAAEoNAAATAAgCW0NvbnRlbnRfVHlwZXNdLnhtbCCiBAIooAAC +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADM +l99v2jAQx98n9X+I/FoRQ7sxOhH6sHVP3YY0+ge4yQHeHNuyDwr//S4JoIAogUDEXkAm+O7j++Hv +pf+4SFUwB+el0RHrhG0WgI5NIvUkYi+j760eCzwKnQhlNERsCZ49Dm4+9EdLCz6g3dpHbIpov3Du +4ymkwofGgqYnY+NSgbR0E25F/FdMgN+1210eG42gsYWZDTbo/yIAJxMIhsLhT5GSH24tcq/ox2ex +NDP05cXnkKyz4GthJiOJmLBWyVggnYPPdbLD0DLjsYwhMfEsJc+hdeDpO/97qsKSo9vMND+dqXdt +ph/CI+WxiFOx6DTCVNg+Kk4rmvtGOKoIshwPnbH+0t43hqsISmW1Vb8fL01UclSX6dN/yNS9NtMq +a8300VGZWhHcNRKJKgKk6xx4/nl+CHIzVR5LhbzVMc2cv5CWukzN3GrbTN9gLGYKg6cFCWah0X8s +THa0T6aZtOYPSLn27HGg/M6eCr1c6XVIO3OR9FNp/TpSezwcFuQKTS2r8aULfct2KqReH+LUoeP8 +DiijHD900MySqxinjJ0dHMjqKIGkZUkYwaGETVLfiweKVwW/cang4kJaMl07K9dKy6H5tNM+O1H1 +aiWDmkt4a2Ts2Rium6uHK0Vl00GxcXA6w/oqzHbv6RuevwkN/gEAAP//AwBQSwMEFAAGAAgAAAAh +AGj4dKEFAQAA4gIAAAsACAJfcmVscy8ucmVscyCiBAIooAACAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACskttKAzEQhu8F3yHMfTfbKiLSbG9E +6J3I+gBjMrsb3RxIptK+vaHgYWEtgr2c0z9f8s96s3ejeKeUbfAKllUNgrwOxvpewXP7sLgFkRm9 +wTF4UnCgDJvm8mL9RCNyGcqDjVkUFZ8VDMzxTsqsB3KYqxDJl0oXkkMuYeplRP2GPclVXd/I9FMD +momm2BoFaWuuQLSHWDb/R1s6YjTIKHVItIipkCW25S2ixdQTKzBBP5Z0PnZUhRrkPNDqvEA87NyL +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 +Ip9/VCgenaUzcqZUsJh6yhqknN95LmpZ3gfVNuprbvsBAAD//wMAUEsDBBQABgAIAAAAIQDV0ZLx +vgAAADcBAAAsAAAAcHB0L3NsaWRlTGF5b3V0cy9fcmVscy9zbGlkZUxheW91dDUueG1sLnJlbHOE +j8EKwjAQRO+C/xD2btJ6EJGmXkTw4EX0A5Zk2wbbJGSj6N+bYwXB4+wwb3aa/WsaxZMSu+A11LIC +Qd4E63yv4XY9rrYgOKO3OAZPGt7EsG+Xi+ZCI+YS4sFFFoXiWcOQc9wpxWagCVmGSL44XUgT5iJT +ryKaO/ak1lW1UWnOgPaLKU5WQzrZGsT1HUvzf3boOmfoEMxjIp9/VCgenaUzcqZUsJh6yhqknN95 +LmpZ3gfVNuprbvsBAAD//wMAUEsDBBQABgAIAAAAIQDV0ZLxvgAAADcBAAAsAAAAcHB0L3NsaWRl +TGF5b3V0cy9fcmVscy9zbGlkZUxheW91dDQueG1sLnJlbHOEj8EKwjAQRO+C/xD2btJ6EJGmXkTw +4EX0A5Zk2wbbJGSj6N+bYwXB4+wwb3aa/WsaxZMSu+A11LICQd4E63yv4XY9rrYgOKO3OAZPGt7E +sG+Xi+ZCI+YS4sFFFoXiWcOQc9wpxWagCVmGSL44XUgT5iJTryKaO/ak1lW1UWnOgPaLKU5WQzrZ +GsT1HUvzf3boOmfoEMxjIp9/VCgenaUzcqZUsJh6yhqknN95LmpZ3gfVNuprbvsBAAD//wMAUEsD +BBQABgAIAAAAIQDV0ZLxvgAAADcBAAAsAAAAcHB0L3NsaWRlTGF5b3V0cy9fcmVscy9zbGlkZUxh +eW91dDEueG1sLnJlbHOEj8EKwjAQRO+C/xD2btJ6EJGmXkTw4EX0A5Zk2wbbJGSj6N+bYwXB4+ww +b3aa/WsaxZMSu+A11LICQd4E63yv4XY9rrYgOKO3OAZPGt7EsG+Xi+ZCI+YS4sFFFoXiWcOQc9wp +xWagCVmGSL44XUgT5iJTryKaO/ak1lW1UWnOgPaLKU5WQzrZGsT1HUvzf3boOmfoEMxjIp9/VCge +naUzcqZUsJh6yhqknN95LmpZ3gfVNuprbvsBAAD//wMAUEsDBBQABgAIAAAAIQDV0ZLxvgAAADcB +AAAsAAAAcHB0L3NsaWRlTGF5b3V0cy9fcmVscy9zbGlkZUxheW91dDgueG1sLnJlbHOEj8EKwjAQ +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 +3NRxoYN5KqkHtlXqbow7uymm5M/JlHIa/89M0fsJXBmsBDoCPtzpCox0vbY9LlTEoQulEfX7AgYH +0zsgW+BeFl5DUsHNsvkvyIH+b2vO8jBlDSc/tUdDJCjsRyoShOxCWzLZdwKzerZ3WZYsY2QyqqSu +TK3aI3JA2FD3wFW9t3soglQ33SRrAwZ3PP/c56yCRqEecsr15vSQYu+1NfB3Tz62mMEotw+bgSb3 +f6Fixa5q6Q15vveWDdEvZmNWI68KEFbaClpZ2b+hCmfcam3HmrN4uZkrB1GctxgWi4EohYsfpP/A +/keFz4hJY72hDvke9FYEXzpoZpA2kNUX7OCBdIO0iyMYnOyiTSbNyro2G5201/LN+pwn3ULuMWdr +zU4T7zM6uxjOXHFOLZ6nszMPO762awtdDZE9XqKwNM4PMiYw5vut8jdQfHQXAr0Fd/0TpqRJJvh+ +SWAYPQemDqD4rURDuvEXAAAA//8DAFBLAwQKAAAAAAAAACEATJVHlgBUAAAAVAAAFwAAAGRvY1By +b3BzL3RodW1ibmFpbC5qcGVn/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAEBAQEBAQEBAQEBAQEB +AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/2wBDAQEB +AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB +AQEBAQH/wAARCADAAQADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL +/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2Jy +ggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWG +h4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo +6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQD +BAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRom +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 +2QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUEsDBBQABgAIAAAAIQBYm5DCqgAAAB8B +AAARAAAAcHB0L3ByZXNQcm9wcy54bWyMjzsOwjAMQHck7hBlpykMCFX9LIiZAQ4QpW4bKXEiO/xu +T8RHgq2jZb3n57q7eyeuQGwDNnJdlFIAmtBbHBt5Ph1WOyk4aey1CwiNfADLrl0u6lhFAgZMOmX0 +SCKLkCvdyCmlWCnFZgKvuQgRMO+GQF6nPNKoetK3fMA7tSnLrfLaovzwNIcPw2AN7IO5+BzwlhC4 +VwlPNvLXFufYfv/4S1LtEwAA//8DAFBLAwQUAAYACAAAACEA2P2Nj6wAAAC2AAAAEwAAAHBwdC90 +YWJsZVN0eWxlcy54bWwMzEkOgjAYQOG9iXdo/n0tQ1EkFMIgK3fqASqUIelAaKMS491l+fKSL80/ +SqKXWOxkNAP/4AESujXdpAcGj3uDY0DWcd1xabRgsAoLebbfpTxxT3lzqxRX69CmaJtwBqNzc0KI +bUehuD2YWejt9WZR3G25DKRb+HvTlSSB5x2J4pMG1ImewTeqgiCitMCny+WIaUgDXHo0xnFU1tW5 +qf0qLH5Asj8AAAD//wMAUEsDBBQABgAIAAAAIQCXwc7qhAEAAE8DAAARAAAAcHB0L3ZpZXdQcm9w +cy54bWysUk1vwjAMvU/af4hyHy0f61hFy2WaNAlpk2C7R6nbRkqTKAlQ+PVzW6BF48Bhp8R2/Pze +cxbLupJkB9YJrRI6HoWUgOI6E6pI6Pfm/WlOifNMZUxqBQk9gKPL9PFhYeKdgP2XJQigXMwSWnpv +4iBwvISKuZE2oLCWa1sxj6EtgsyyPQJXMpiEYRRUTCh66rf39Os8FxzeNN9WoHwHYkEyj+RdKYw7 +o5l70IwFhzBt9xWlFMWphrb86SS6Uu8/t14KBR8cRyU0pM0jBPDaQraC3BN3RP+eo0lIg2Fto01b +ep1FUVsKrsGbt06KDLpZTcjXMhtE/dVxJiFdsNjVpNlWiNvKuhNnYvpwI43zTn0m1lYUQpE6oVFE +ySGhs/mZE+/HFFuks3K+4dLeCfahU2iqtkdKjEYHJuNOzvlJl5xf8HoQJDBU1PC51qu0B7eB2vcU +Bmz+UTTahZr/KEZGNygUVmRrwzh+WMLRsZfpyxS3ixgcQS4RGo/9u/ajpL8AAAD//wMAUEsDBBQA +BgAIAAAAIQAQRdCYTAEAACcCAAARAAgBZG9jUHJvcHMvY29yZS54bWwgogQBKKAAAQAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAABskcFKAzEQhu+C77DkvpvdrUgNuymo9GRBsKJ4C8m0DW6yIYnd +1psn8Wk8i88jfQ2z27q2KOQyM3+++WemGK1UFS3BOlnrEmVJiiLQvBZSz0t0Ox3HQxQ5z7RgVa2h +RGtwaESPjwpuCK8tXNvagPUSXBRI2hFuSrTw3hCMHV+AYi4JCh2Ks9oq5kNo59gw/sjmgPM0PcUK +PBPMM9wCY9MT0Q4peI80T7bqAIJjqECB9g5nSYZ/tR6scv9+6Cp7SiX92oSZdnb32YJvi7165WQv +bJomaQadjeA/w/eTq5tu1FjqdlccEC0EJ176CujXx+fm5X3z9hplBe6z7f4q5vwkrHomQZyv6bNb +FfhvulVaWMr2QjTLO0kfhzbdVETtOFEwSrZj/ZTuBheX0zGieZqlcftOpumQpAOSnz20jg4BtGtw +eFr6DQAA//8DAFBLAwQUAAYACAAAACEABiQG+goCAABVBAAAEAAIAWRvY1Byb3BzL2FwcC54bWwg +ogQBKKAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACcVE1vEzEQvSPxH1Z7gkPjJE1LFU1c +oVRVDpRGyraczXqSWGzslW2ilhsHVHHi2iNCPfSGuAGV+DWkEf+C2XU+SQHBnt7MexrPvLEX9s9G +WTRG65TRrbhWqcYR6tRIpQet+CQ53NqLI+eFliIzGlvxObp4n9+/B11rcrReoYuohHateOh93mTM +pUMcCVchWhPTN3YkPIV2wEy/r1I8MOnLEWrP6tXqLsMzj1qi3MoXBeNQsTn2/1tUmrToz50m5zk1 +zCExXmSJGiHf2wW2jOCZsdLxWu0RsABpMHTUnfDkyGHZPJ+8uZ58end7+W169fVBo7n9ENgdKugK +KwZW5EPHd3ZIsgyhlymJjm8DmyF4ajwlqsACgI6SEvWMpfRaDEdH7UzlpX4OoZeKDNs0Ju+LzCGV +XiSgg6JYYVco6ziMfXOMqTc2cuoVLbERR8+Fw8KcVjwWVgntyaRCFoISZ7nzln//fPPjwyUwIkOi +hKu6VawavFYKCPxRGGpNvtxMX3+cvr24fX/xb6eQk9TRxilFMoxKx6+bkCifoTvu01r83zwpuwuO +hEaPy5sbbZqxsGUxShQMmJl1B18vW/89H0ab8WsD/TLCE6VfuJM8MQfC4/wSrCehNxQWJT25Ob9M +QIf2b7OiSHso9ADlXLNJwOM8Pw1/CV6rV6r0AVvJFQ9i/j/gPwEAAP//AwBQSwECLQAUAAYACAAA +ACEAENplPfUBAABKDQAAEwAAAAAAAAAAAAAAAAAAAAAAW0NvbnRlbnRfVHlwZXNdLnhtbFBLAQIt +ABQABgAIAAAAIQBo+HShBQEAAOICAAALAAAAAAAAAAAAAAAAAC4EAABfcmVscy8ucmVsc1BLAQIt +ABQABgAIAAAAIQBjXCO0wQAAADcBAAAgAAAAAAAAAAAAAAAAAGQHAABwcHQvc2xpZGVzL19yZWxz +L3NsaWRlMS54bWwucmVsc1BLAQItABQABgAIAAAAIQBL9T3svwAAADcBAAAgAAAAAAAAAAAAAAAA +AGMIAABwcHQvc2xpZGVzL19yZWxzL3NsaWRlMy54bWwucmVsc1BLAQItABQABgAIAAAAIQACRcxG +IgEAANoEAAAfAAAAAAAAAAAAAAAAAGAJAABwcHQvX3JlbHMvcHJlc2VudGF0aW9uLnhtbC5yZWxz +UEsBAi0AFAAGAAgAAAAhAEv1Pey/AAAANwEAACAAAAAAAAAAAAAAAAAAxwsAAHBwdC9zbGlkZXMv +X3JlbHMvc2xpZGUyLnhtbC5yZWxzUEsBAi0AFAAGAAgAAAAhABvl8hRaAgAA2gwAABQAAAAAAAAA +AAAAAAAAxAwAAHBwdC9wcmVzZW50YXRpb24ueG1sUEsBAi0AFAAGAAgAAAAhAJlrbCjPCgAABH4A +ABUAAAAAAAAAAAAAAAAAUA8AAHBwdC9zbGlkZXMvc2xpZGUyLnhtbFBLAQItABQABgAIAAAAIQDT ++KeaZwgAAOl/AAAVAAAAAAAAAAAAAAAAAFIaAABwcHQvc2xpZGVzL3NsaWRlMy54bWxQSwECLQAU +AAYACAAAACEApdNmeUYGAACEKwAAFQAAAAAAAAAAAAAAAADsIgAAcHB0L3NsaWRlcy9zbGlkZTEu +eG1sUEsBAi0AFAAGAAgAAAAhANXRkvG+AAAANwEAACwAAAAAAAAAAAAAAAAAZSkAAHBwdC9zbGlk +ZUxheW91dHMvX3JlbHMvc2xpZGVMYXlvdXQ5LnhtbC5yZWxzUEsBAi0AFAAGAAgAAAAhAGmiXyEe +AQAAxwcAACwAAAAAAAAAAAAAAAAAbSoAAHBwdC9zbGlkZU1hc3RlcnMvX3JlbHMvc2xpZGVNYXN0 +ZXIxLnhtbC5yZWxzUEsBAi0AFAAGAAgAAAAhANXRkvG+AAAANwEAAC0AAAAAAAAAAAAAAAAA1SsA +AHBwdC9zbGlkZUxheW91dHMvX3JlbHMvc2xpZGVMYXlvdXQxMS54bWwucmVsc1BLAQItABQABgAI +AAAAIQDV0ZLxvgAAADcBAAAtAAAAAAAAAAAAAAAAAN4sAABwcHQvc2xpZGVMYXlvdXRzL19yZWxz +L3NsaWRlTGF5b3V0MTAueG1sLnJlbHNQSwECLQAUAAYACAAAACEA1dGS8b4AAAA3AQAALAAAAAAA +AAAAAAAAAADnLQAAcHB0L3NsaWRlTGF5b3V0cy9fcmVscy9zbGlkZUxheW91dDIueG1sLnJlbHNQ +SwECLQAUAAYACAAAACEA1dGS8b4AAAA3AQAALAAAAAAAAAAAAAAAAADvLgAAcHB0L3NsaWRlTGF5 +b3V0cy9fcmVscy9zbGlkZUxheW91dDMueG1sLnJlbHNQSwECLQAUAAYACAAAACEA1dGS8b4AAAA3 +AQAALAAAAAAAAAAAAAAAAAD3LwAAcHB0L3NsaWRlTGF5b3V0cy9fcmVscy9zbGlkZUxheW91dDcu +eG1sLnJlbHNQSwECLQAUAAYACAAAACEA1dGS8b4AAAA3AQAALAAAAAAAAAAAAAAAAAD/MAAAcHB0 +L3NsaWRlTGF5b3V0cy9fcmVscy9zbGlkZUxheW91dDYueG1sLnJlbHNQSwECLQAUAAYACAAAACEA +1dGS8b4AAAA3AQAALAAAAAAAAAAAAAAAAAAHMgAAcHB0L3NsaWRlTGF5b3V0cy9fcmVscy9zbGlk +ZUxheW91dDUueG1sLnJlbHNQSwECLQAUAAYACAAAACEA1dGS8b4AAAA3AQAALAAAAAAAAAAAAAAA +AAAPMwAAcHB0L3NsaWRlTGF5b3V0cy9fcmVscy9zbGlkZUxheW91dDQueG1sLnJlbHNQSwECLQAU +AAYACAAAACEA1dGS8b4AAAA3AQAALAAAAAAAAAAAAAAAAAAXNAAAcHB0L3NsaWRlTGF5b3V0cy9f +cmVscy9zbGlkZUxheW91dDEueG1sLnJlbHNQSwECLQAUAAYACAAAACEA1dGS8b4AAAA3AQAALAAA +AAAAAAAAAAAAAAAfNQAAcHB0L3NsaWRlTGF5b3V0cy9fcmVscy9zbGlkZUxheW91dDgueG1sLnJl +bHNQSwECLQAUAAYACAAAACEAkOXSnLgDAADrCwAAIgAAAAAAAAAAAAAAAAAnNgAAcHB0L3NsaWRl +TGF5b3V0cy9zbGlkZUxheW91dDEwLnhtbFBLAQItABQABgAIAAAAIQBihLvk0gQAADERAAAhAAAA +AAAAAAAAAAAAAB86AABwcHQvc2xpZGVMYXlvdXRzL3NsaWRlTGF5b3V0My54bWxQSwECLQAUAAYA +CAAAACEA/vethpcDAAC0CwAAIQAAAAAAAAAAAAAAAAAwPwAAcHB0L3NsaWRlTGF5b3V0cy9zbGlk +ZUxheW91dDIueG1sUEsBAi0AFAAGAAgAAAAhAOY4QduIBAAA+BAAACEAAAAAAAAAAAAAAAAABkMA +AHBwdC9zbGlkZUxheW91dHMvc2xpZGVMYXlvdXQxLnhtbFBLAQItABQABgAIAAAAIQDuQ14m7AcA +APcvAAAhAAAAAAAAAAAAAAAAAM1HAABwcHQvc2xpZGVNYXN0ZXJzL3NsaWRlTWFzdGVyMS54bWxQ +SwECLQAUAAYACAAAACEAK8Ls5XQEAADfEgAAIQAAAAAAAAAAAAAAAAD4TwAAcHB0L3NsaWRlTGF5 +b3V0cy9zbGlkZUxheW91dDQueG1sUEsBAi0AFAAGAAgAAAAhAOI6ARfEBQAAzxwAACEAAAAAAAAA +AAAAAAAAq1QAAHBwdC9zbGlkZUxheW91dHMvc2xpZGVMYXlvdXQ1LnhtbFBLAQItABQABgAIAAAA +IQA4CWvhIgMAAIIIAAAhAAAAAAAAAAAAAAAAAK5aAABwcHQvc2xpZGVMYXlvdXRzL3NsaWRlTGF5 +b3V0Ni54bWxQSwECLQAUAAYACAAAACEAE8Cnk98CAAANBwAAIQAAAAAAAAAAAAAAAAAPXgAAcHB0 +L3NsaWRlTGF5b3V0cy9zbGlkZUxheW91dDcueG1sUEsBAi0AFAAGAAgAAAAhALDIAcxCBQAA8BIA +ACEAAAAAAAAAAAAAAAAALWEAAHBwdC9zbGlkZUxheW91dHMvc2xpZGVMYXlvdXQ4LnhtbFBLAQIt +ABQABgAIAAAAIQC9nZMC+gQAABUSAAAhAAAAAAAAAAAAAAAAAK5mAABwcHQvc2xpZGVMYXlvdXRz +L3NsaWRlTGF5b3V0OS54bWxQSwECLQAUAAYACAAAACEAZNFfshgEAADODAAAIgAAAAAAAAAAAAAA +AADnawAAcHB0L3NsaWRlTGF5b3V0cy9zbGlkZUxheW91dDExLnhtbFBLAQItABQABgAIAAAAIQBy +/A4ziwYAAF0bAAAUAAAAAAAAAAAAAAAAAD9wAABwcHQvdGhlbWUvdGhlbWUxLnhtbFBLAQItAAoA +AAAAAAAAIQBMlUeWAFQAAABUAAAXAAAAAAAAAAAAAAAAAPx2AABkb2NQcm9wcy90aHVtYm5haWwu +anBlZ1BLAQItABQABgAIAAAAIQBYm5DCqgAAAB8BAAARAAAAAAAAAAAAAAAAADHLAABwcHQvcHJl +c1Byb3BzLnhtbFBLAQItABQABgAIAAAAIQDY/Y2PrAAAALYAAAATAAAAAAAAAAAAAAAAAArMAABw +cHQvdGFibGVTdHlsZXMueG1sUEsBAi0AFAAGAAgAAAAhAJfBzuqEAQAATwMAABEAAAAAAAAAAAAA +AAAA58wAAHBwdC92aWV3UHJvcHMueG1sUEsBAi0AFAAGAAgAAAAhABBF0JhMAQAAJwIAABEAAAAA +AAAAAAAAAAAAms4AAGRvY1Byb3BzL2NvcmUueG1sUEsBAi0AFAAGAAgAAAAhAAYkBvoKAgAAVQQA +ABAAAAAAAAAAAAAAAAAAHdEAAGRvY1Byb3BzL2FwcC54bWxQSwUGAAAAACkAKQBvDAAAXdQAAAAA + +------=_NextPart_000_0012_01CB9563.04E44200-- + diff --git a/lib_acl_cpp/samples/mime/test9.eml b/lib_acl_cpp/samples/mime/test9.eml new file mode 100644 index 000000000..2b9d23d76 --- /dev/null +++ b/lib_acl_cpp/samples/mime/test9.eml @@ -0,0 +1,1668 @@ +X-Uidl: 1291623916.4734_3.localhost&&mail.51iker.com +Return-Path: +Delivered-To: zhengshuxin@51iker.com +Received: from iker-f954f96714 (unknown [123.122.116.217]) + by 51iker.com (zebra mail for UNIX) with ESMTP id 2EFB727465C + for ; Mon, 6 Dec 2010 16:25:12 +0800 (CST) +Date: Mon, 6 Dec 2010 16:23:16 +0800 +From: "zhengshuxin" +To: "zhengshuxin" +Subject: alternative mail +Message-ID: <201012061623147815791@51iker.com> +X-mailer: Foxmail 6, 15, 201, 23 [cn] +Mime-Version: 1.0 +Content-Type: multipart/mixed; + boundary="=====001_Dragon322738684085_=====" + +This is a multi-part message in MIME format. + +--=====001_Dragon322738684085_===== +Content-Type: multipart/alternative; + boundary="=====003_Dragon322738684085_=====" + + +--=====003_Dragon322738684085_===== +Content-Type: text/plain; + charset="gb2312" +Content-Transfer-Encoding: 7bit + +hello world! + +2010-12-06 + + + +zhengshuxin + +--=====003_Dragon322738684085_===== +Content-Type: text/html; + charset="gb2312" +Content-Transfer-Encoding: 7bit + + + + + + +
hello world!
+
 
+
2010-12-06
+
+ +
zhengshuxin +
+ +--=====003_Dragon322738684085_=====-- +--=====001_Dragon322738684085_===== +Content-Type: application/octet-stream; + name="=?gb2312?B?sKy/y8j8wNbQ+7SrsuHOxLC4LmRvYw==?=" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; + filename="=?gb2312?B?sKy/y8j8wNbQ+7SrsuHOxLC4LmRvYw==?=" + +0M8R4KGxGuEAAAAAAAAAAAAAAAAAAAAAPgADAP7/CQAGAAAAAAAAAAAAAAACAAAAqwAAAAAAAAAA +EAAArgAAAAEAAAD+////AAAAAKkAAACqAAAA//////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////s +pcEAA4AJBAAA+FK/AAAAAAAAEAAAAAAACAAAlmkAAA4AYmpialR+VH4AAAAAAAAAAAAAAAAAAAAA +AAAECBYAOKQAADYUAQA2FAEAvB0AAAAAAAANAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//w8AAAAA +AAAAAAD//w8AAAAAAAAAAAD//w8AAAAAAAAAAAAAAAAAAAAAALcAAAAAAA4JAAAAAAAADgkAAFgW +AAAAAAAAWBYAAAAAAABYFgAAAAAAAFgWAAAAAAAAWBYAABQAAAAAAAAAAAAAAP////8AAAAAbBYA +AAAAAABsFgAAAAAAAGwWAAA4AAAApBYAAMQAAABoFwAAxAAAAGwWAAAAAAAAZWkAAKQBAAAsGAAA +egIAAKYaAAAAAAAAphoAAAAAAACmGgAAAAAAAKYaAAAAAAAA2hsAAJIHAABsIwAALAIAAJglAAAY +AQAAfGgAAAIAAAB+aAAAAAAAAH5oAAAAAAAAfmgAAAAAAAB+aAAAAAAAAH5oAAAAAAAAfmgAACQA +AAAJawAAogIAAKttAAA4AAAAomgAAGkAAAAAAAAAAAAAAAAAAAAAAAAAWBYAAAAAAACwJgAAAAAA +AAAAAAAAAAAAAAAAAAAAAADaGwAAAAAAANobAAAAAAAAsCYAAAAAAACwJgAAAAAAAKJoAAAAAAAA +AAAAAAAAAABYFgAAAAAAAFgWAAAAAAAAphoAAAAAAAAAAAAAAAAAAKYaAAA0AQAAC2kAAB4AAABU +NQAAAAAAAFQ1AAAAAAAAVDUAAAAAAACwJgAAAAoAAFgWAAAAAAAAphoAAAAAAABYFgAAAAAAAKYa +AAAAAAAAfGgAAAAAAAAAAAAAAAAAAFQ1AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAsCYAAAAAAAB8aAAAAAAAAAAAAAAAAAAAVDUAAAAAAABUNQAA +3gEAABxlAABYAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAxGYAAAAAAACmGgAAAAAAAP////8AAAAAcKW2AZSP +ywEAAAAAAAAAAGwWAAAAAAAAsDAAABoCAAB0ZgAAKAAAAAAAAAAAAAAAaGgAABQAAAApaQAAPAAA +AGVpAAAAAAAAnGYAACgAAADjbQAAAAAAAMoyAAA+AgAA420AAFAAAADEZgAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAONtAAAAAAAAAAAAAAAAAABYFgAAAAAAAMRmAACkAQAAsCYAAAAAAACwJgAAAAAAAFQ1 +AAAAAAAAsCYAAAAAAACwJgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsCYA +AAAAAACwJgAAAAAAALAmAAAAAAAAomgAAAAAAACiaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAACDUAAEwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALAmAAAA +AAAAsCYAAAAAAACwJgAAAAAAAGVpAAAAAAAAsCYAAAAAAACwJgAAAAAAALAmAAAAAAAAsCYAAAAA +AAAAAAAAAAAAAP////8AAAAA/////wAAAAD/////AAAAAAAAAAAAAAAA/////wAAAAD/////AAAA +AP////8AAAAA/////wAAAAD/////AAAAAP////8AAAAA/////wAAAAD/////AAAAAP////8AAAAA +/////wAAAAD/////AAAAAP////8AAAAA/////wAAAAD/////AAAAAONtAAAAAAAAsCYAAAAAAACw +JgAAAAAAALAmAAAAAAAAsCYAAAAAAACwJgAAAAAAALAmAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACwJgAAAAAAALAmAAAAAAAAsCYA +AAAAAAAOCQAAEAwAAB4VAAA6AQAABQASAQAACQQECAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH6CS1Fb +jVBOo1sgT4xRh2VIaA0Ah2UgAEhoIADudiAAVV8NABMAIABUAE8AQwAgAFwAbwAgACIAMQAtADMA +IgAgAFwAaAAgAFwAegAgAFwAdQAgABQAEwAgAEgAWQBQAEUAUgBMAEkATgBLACAAXABsACAAIgBf +AFQAbwBjADIANwA4ADUANQA1ADIAMQA3ACIAIAABABQAMQAJAGxR+FOAe8tOCQATACAAUABBAEcA +RQBSAEUARgAgAF8AVABvAGMAMgA3ADgANQA1ADUAMgAxADcAIABcAGgAIAABABQAMgAVABUADQAT +ACAASABZAFAARQBSAEwASQBOAEsAIABcAGwAIAAiAF8AVABvAGMAMgA3ADgANQA1ADUAMgAxADgA +IgAgAAEAFAAyAAkAfoJLUVuNUE4JTidZLU7DXwkAEwAgAFAAQQBHAEUAUgBFAEYAIABfAFQAbwBj +ADIANwA4ADUANQA1ADIAMQA4ACAAXABoACAAAQAUADIAFQAVAA0AEwAgAEgAWQBQAEUAUgBMAEkA +TgBLACAAXABsACAAIgBfAFQAbwBjADIANwA4ADUANQA1ADIAMQA5ACIAIAABABQAMgAuADEACQAX +U6xOfoJLUVuNUE5/iTpTcGVuYy1Ow18JABMAIABQAEEARwBFAFIARQBGACAAXwBUAG8AYwAyADcA +OAA1ADUANQAyADEAOQAgAFwAaAAgAAEAFAAyABUAFQANABMAIABIAFkAUABFAFIATABJAE4ASwAg +AFwAbAAgACIAXwBUAG8AYwAyADcAOAA1ADUANQAyADIAMAAiACAAAQAUADIALgAyAAkASQBEAEMA +nlg8UA1noVJTT4yaLU7DXwkAEwAgAFAAQQBHAEUAUgBFAEYAIABfAFQAbwBjADIANwA4ADUANQA1 +ADIAMgAwACAAXABoACAAAQAUADQAFQAVAA0AEwAgAEgAWQBQAEUAUgBMAEkATgBLACAAXABsACAA +IgBfAFQAbwBjADIANwA4ADUANQA1ADIAMgAxACIAIAABABQAMgAuADMACQABTxpO4U9vYBZTFlkF +Uw1noVItTsNfCQATACAAUABBAEcARQBSAEUARgAgAF8AVABvAGMAMgA3ADgANQA1ADUAMgAyADEA +IABcAGgAIAABABQANQAVABUADQATACAASABZAFAARQBSAEwASQBOAEsAIABcAGwAIAAiAF8AVABv +AGMAMgA3ADgANQA1ADUAMgAyADIAIgAgAAEAFAAzAAkASQBEAEMAnlg8UA1noVIJTidZGE+/UgkA +EwAgAFAAQQBHAEUAUgBFAEYAIABfAFQAbwBjADIANwA4ADUANQA1ADIAMgAyACAAXABoACAAAQAU +ADYAFQAVAA0AEwAgAEgAWQBQAEUAUgBMAEkATgBLACAAXABsACAAIgBfAFQAbwBjADIANwA4ADUA +NQA1ADIAMgAzACIAIAABABQAMwAuADEACQBsePZOGE+/UgkAEwAgAFAAQQBHAEUAUgBFAEYAIABf +AFQAbwBjADIANwA4ADUANQA1ADIAMgAzACAAXABoACAAAQAUADYAFQAVAA0AEwAgAEgAWQBQAEUA +UgBMAEkATgBLACAAXABsACAAIgBfAFQAbwBjADIANwA4ADUANQA1ADIAMgA0ACIAIAABABQAMwAu +ADIACQCAYi9nGE+/UgkAEwAgAFAAQQBHAEUAUgBFAEYAIABfAFQAbwBjADIANwA4ADUANQA1ADIA +MgA0ACAAXABoACAAAQAUADYAFQAVAA0AEwAgAEgAWQBQAEUAUgBMAEkATgBLACAAXABsACAAIgBf +AFQAbwBjADIANwA4ADUANQA1ADIAMgA1ACIAIAABABQAMwAuADMACQANZ6FSGE+/UgkAEwAgAFAA +QQBHAEUAUgBFAEYAIABfAFQAbwBjADIANwA4ADUANQA1ADIAMgA1ACAAXABoACAAAQAUADYAFQAV +AA0AEwAgAEgAWQBQAEUAUgBMAEkATgBLACAAXABsACAAIgBfAFQAbwBjADIANwA4ADUANQA1ADIA +MgA2ACIAIAABABQANAAJACdZi1fjibNRuWVIaAkAEwAgAFAAQQBHAEUAUgBFAEYAIABfAFQAbwBj +ADIANwA4ADUANQA1ADIAMgA2ACAAXABoACAAAQAUADcAFQAVAA0AEwAgAEgAWQBQAEUAUgBMAEkA +TgBLACAAXABsACAAIgBfAFQAbwBjADIANwA4ADUANQA1ADIAMgA3ACIAIAABABQANAAuADEACQCJ +W2hRtmeEZ+OJs1G5ZUhoCQATACAAUABBAEcARQBSAEUARgAgAF8AVABvAGMAMgA3ADgANQA1ADUA +MgAyADcAIABcAGgAIAABABQANwAVABUADQATACAASABZAFAARQBSAEwASQBOAEsAIABcAGwAIAAi +AF8AVABvAGMAMgA3ADgANQA1ADUAMgAyADgAIgAgAAEAFAA0AC4AMgAJACdZi1eiWzdi44mzUbll +SGgJABMAIABQAEEARwBFAFIARQBGACAAXwBUAG8AYwAyADcAOAA1ADUANQAyADIAOAAgAFwAaAAg +AAEAFAA3ABUAFQANABMAIABIAFkAUABFAFIATABJAE4ASwAgAFwAbAAgACIAXwBUAG8AYwAyADcA +OAA1ADUANQAyADIAOQAiACAAAQAUADQALgAzAAkAkk5UgJJOGpDjibNRuWVIaAkAEwAgAFAAQQBH +AEUAUgBFAEYAIABfAFQAbwBjADIANwA4ADUANQA1ADIAMgA5ACAAXABoACAAAQAUADcAFQAVAA0A +EwAgAEgAWQBQAEUAUgBMAEkATgBLACAAXABsACAAIgBfAFQAbwBjADIANwA4ADUANQA1ADIAMwAw +ACIAIAABABQANAAuADQACQAnWYtXUX/ZeghUXE8QYp9SSGiLTwkAEwAgAFAAQQBHAEUAUgBFAEYA +IABfAFQAbwBjADIANwA4ADUANQA1ADIAMwAwACAAXABoACAAAQAUADgAFQAVAA0AEwAgAEgAWQBQ +AEUAUgBMAEkATgBLACAAXABsACAAIgBfAFQAbwBjADIANwA4ADUANQA1ADIAMwAxACIAIAABABQA +NQAJAGxR+FMBTxpOh2UWUwkAEwAgAFAAQQBHAEUAUgBFAEYAIABfAFQAbwBjADIANwA4ADUANQA1 +ADIAMwAxACAAXABoACAAAQAUADgAFQAVAA0AEwAgAEgAWQBQAEUAUgBMAEkATgBLACAAXABsACAA +IgBfAFQAbwBjADIANwA4ADUANQA1ADIAMwAyACIAIAABABQANgAJAGxR+FNEjSiNCQATACAAUABB +AEcARQBSAEUARgAgAF8AVABvAGMAMgA3ADgANQA1ADUAMgAzADIAIABcAGgAIAABABQAOQAVABUA +DQATACAASABZAFAARQBSAEwASQBOAEsAIABcAGwAIAAiAF8AVABvAGMAMgA3ADgANQA1ADUAMgAz +ADMAIgAgAAEAFAA3AAkADWehUsFUTHII/8FUTHJMAE8ARwBPAHWYCf8JABMAIABQAEEARwBFAFIA +RQBGACAAXwBUAG8AYwAyADcAOAA1ADUANQAyADMAMwAgAFwAaAAgAAEAFAA5ABUAFQANABUADQAN +AA0ADAANAGxR+FOAe8tODQAXU6xOfoJLUVuNUE7ReYBiCWdQlmxR+FMvZv1WhVEAZydZhHZJAEQA +QwCeWDxQDWehUtBjm09GVQz/6oEyADAAMAA3AHReMQAIZxBiy3rlTmVnDP8ATvR29IGbUo5OGpDh +T8pTkk5UgFF/TIgaToR2gGIvZwBf0VPKU4BiL2cNZ6FSAjAoV3BlbmMtTsNfCP9JAEQAQwAJ/w1n +oVIBMFF/3H6JW2hRDWehUgEwAU8aTlF/2Xr7fN9++l6+iwEwJ1mLV1F/2XrQj/R+FlkFUw1noVIB +MJJOVIBRf5ReKHUAX9FTSXu5ZWKXCWdAdzBOzFuEdtCPJYTPfoyaDP9sUfhT5WIJZ8SWmlOEdoBi +L2eeW5tSDP/lYglnF1OsTgBnJ1mEdkkARABDAHBlbmMNZ6FSLU7DXwz/5WIJZ0FTGll0XuiVN2Ll +XVxPz36MmoR2AE5BbYBiL2fiVh+WjFSMW4RVhHYNZ6FSU0/7fAIwbFH4UxBiy3rlTmVnDP8OTgRU +J1n6V0B40I8lhEZVbnjLeoZOGGJldQhUXE8ZTzRPc1H7fAz/SFEOVA5OLU5OU1F/ATBHWU6GUX8B +MHdtz5HReYBiCP8ATneNUX8J/wEwjFSvi1F/ATC3Xtt2G1LzYAj/RABJAFMAQwBVAFoASQAJ/wEw +Io3PflF/SXsaWbZbJ1mLV1F/2Xr6Xst6hk5JAEQAQwAIVFxPATDolTdi0I/0fhZZBVMIVFxPc1H7 +fAIwDQAOTqJbN2JxUWKNL2YRYuxODU7IYf2PQmyEdu52B2gCMGxR+FMQkGVrYl8QYoZO5U6iWzdi +Ok4tTsNfATDlToBiL2c6TvpXQHgBMOVOAl46VzpO/FsRVAEw5U4NZ6FSOk44aMNfhHaMW3RlU0/7 +fAIwEWLsTgZcAE6CWeJlgF+EdkVRBlIpUih1EWLsToR2gGIvZxhPv1IBMEyIGk5EjZBuGE+/UjpO +KHU3YtBjm0/0ZhNO6GwBMPRmNI3DX4R2p07BVIxUDWehUgIwDQBTAGwAbwBnAGEAbgAa/xwgc1Ex +cqJbN2IM/yhX619QTi1OwlMOTt56iU4M/yhX3nqJTi1OU0+MmutfUE4B/x0goAANAA0ADQB+gktR +W41QTglOJ1ktTsNfDQANABdTrE5+gktRW41QTn+JOlNwZW5jLU7DXw0ALU7DX4B7y04NAH6CS1Fb +jVBOcGVuYydZplMvZhdTrE5+gktRW41QTtF5gGIJZ1CWbFH4Uz5Qm1JTYiCQhHYXU6xOf4k6U3aY +p35wZW5jLU7DXwIwJ1mmU2BTMFdil+95CU5DU1lPc165ZXN8DP9EjdGRlWJlUQpOv05DUQIwcGVu +YydZplPGlgRU0I8lhEZVGE8ojUSNkG4BMP1WRZYATkFtb49sePZO+ldAeL6LvWUBMN9+AE6Edolb +aFGhewZ0c17wUwEwJ2D9gBhPAl+EdtCP9H7dT5yWc17wU+VOylN2mBZc4U9vYBZTDWehUgdoxlGO +TgBOq44M/8aWcGVuYy1Ow18BMNCPJYT0fqRiLU7DXwEwnlg8UA1noVJTT4yaLU7DXwEwRlWhUp5S +bFEtTsNfjk4ATlNPDP8vZhdTrE4AZydZhHZ2mKd+/H4IVHBlbmMNZ6FSLU7DXwIwDQANAL58w18J +kEBXDP/scmBTrE7OVxhPio0wVxh/RI2Qbg0AfoJLUVuNUE5wZW5jJ1mmU01Pjk4XU6xO83dvZnFc +OlN/iZROr3NZiOiV41NlaH+Jp08M/yd9u5B/lYlbV4gM/92Nu3ktTnNRUWfFTjEANAAuADYAbFHM +kQz/3Y27eQpOMFfhT29gp04aTvpXMFfFTjEAOABsUcyRDP8vZhdTrE4CXjpThVHFTglnhHYnWYtX +/H4IVEkARABDAA1noVInWaZTAjANAA0A6oE2ca9zg1gYT4qNM3qaWw0AfoJLUVuNUE5wZW5jJ1mm +U9dru5A4bJpbs2wM/xdTp0/zd29mcVzVllFYbFHtVgEw/VZFltWWUVhsUe1WYl8QYm+CfVmEduqB +NnGUlrt5Jl4M/39Pl19wZW5jJ1mmU2hUuY96ehRsKI3PkRhPio0CMA0ADQBPUGdiMFf9j0JsBnTz +YA5OjFuOfw0AEWLsTuVO+VvBVCiN0Y9OTk9QZ2KEdv2PQmxlZ1NiIJAGdPNgLU6EdnBlbmMtTsNf +AjANAH6CS1FbjVBOcGVuYydZplPHkSh1LU7BlOVdC3q+i6GLYpYBMJaZopS+i6GLYpaEdjtgU0/E +iRJSvouhi7llSGgM/zF1LU79VnaYp36+i6GLbFH4Uy1O4U/9Volb249MiBhPFlO+i6GLDP9oUXxp +U08xdaKUS3v3bd1RH1d0ZVNPR21RewyAEGIM/89rc165ZXN8f2LNkb6PMFIyAC4ANQAoVAz/l2IH +l/2Am1K+jzgAp37lTgpOAjANAA0ANXWbUvt8334NACdZplM1dZtSUX/vjceRKHXMU++NNXWQbgZS +K1KlY2VRTlMXUzV1UX8NTgxU2FM1dUBiDP+eW7Bzl1FZTzV1m1KbT5ReDP+bTzV1NXWLUzEAMABL +AFYADP+bTzV1/YCbUr6PMQAwADAAMAAwAEsAVgBBAOVOCk4CME2RNXWkW8eRKHVOUxxONXUUbPpR +wVSEdtiaATBOT4tT3GcM/zhow19DUfZOx5Eodf1WRZYATkFtwVRMcr1lEIC3X6dOwVQCMHxphVFH +V8eRKHXMUzV1kG6+i6GLDP/Ymk5Pi1PcZ2hR6JCeW7Bz6oGoUgdSYmMM/02RCFRVAFAAUwA1dZBu +nluwc+Bl9JWtZZtPNXUCMA0AfGmFUWdxDmb7fN9+X07HkSh1zFM1dZBum081dQz/Ok6iWzdinlJs +UdBjm0/gZfSVrWVncQ5mr3ODWAIwDQANACdZi1eaWzZSFlM6Zz9iOk6iWzdi0GObT0VRs40BMOqB +MXWEdmliRVF6evSVDQB+gktRW41QTnBlbmMnWaZTz2tCXMeRKHUyADAAMAAwAHNec3wAXz5lD186 +Zz9ivouhiwz/71M5aG5jKHU3YgCXQmzbj0yI6oExdXp69JXEfghUDP/Pa0Jc71O5W7N+OAAwADAA +Kk4NZ6FSaFY6Z9xnDP86TqJbN2LQY5tPRVGzjQEw6oExdYR2aWJFUXp69JUCMA0ADQAaWb9+pWNl +UQz/0GObTxhPKI0mXr1bRI2Qbg0AfoJLUVuNUE5wZW5jJ1mmUzhow19Rf9x+x5EodRpZv35JUaR+ +pWNlUQz/VIAakAEwNXXhT79+7436UeNTJl69W76PMFI0ADAARwAM/1llsoBRfwEw+3moUgEwwZQa +kL9+740mXr1bvo8wUjEAMABHAAIwBFS/fu+NR1cJZ5dRWU8HWf1ODP/gZVVTv37vjUVlnJYCMDho +w1+kTmJjQlzHkSh1SAAzAEMAhHY5ADUAMAAwAPt8F1IBMDcANQAwADAA+3wXUqdOwVQM/0dsWoBC +XKROYmO+iwdZx5EodU5TOk41ADMAMAAwAPt8F1KnTsFUDP84aMNfQlwOTkdsWoBCXPSVx5EodQdO +RlFJUaR+3o+lYwIwDQBRf9x+p2M2Ui1Ow1/vUzlobmModTdiAJdCbAz/+VtRf9x+740xdduPTIh1 +cDttvotufwz/0GObTw5OeXKaW6GLl3s6Z/t8334BMBZZ6JCEdnlymltwZW5jLU7DXwEwUX+5cIR2 +E05Rf96PpWMCMARUols3YktO9JWEdlF/3H5pcgZ0lJa7eQz/bnjdT3BlbmMgT5OPjFRRf9x+GpCv +i4lbaFHvU2CXAjCpiyh1N2KrTih12JofkKVjZVEBMNiaJ2D3TtRrATBpYlVcR1Onfrllv08BMBNm +jk70fqRioXsGdIR2p07BVMpTDWehUoR2DFT2ZQz/9GY+ZcNfATD0Zolbw18CMA0ADQC3Ue1wGpBT +kAZSu3kM/1JgKW5SYH9uDQA6Zz9ix5EodbdR7XAakFOQBlK7eQz/C04BkM6YDP8KTt5WzpgM/wpU +dphwjb9+vouhiwz/Yl8QYst6U0+qX69zFGxBbYR2vouhiwZ09V8M/wlnSGWeW7BzOmc/YoVR5V1c +T69zg1iEdlJgKW5SYH9uAjANABqQx49/Tyh1foLYnh91vnzGW3p6A4yMVHpm/YCwZc6Y+3zffgz/ ++Vs6Zz9iKW6mXspTf26mXp5bTIgyADQAD1z2ZWhRemb9gNF2p2OMVISYZosM/2543U86Zz9ipFuF +USlupl4zeppbKFcyADEAAyF+ADIAMwADIQz/z2sqTjpnP2J6egOMvosHWUdXx5EodRwgCU7EfgBO +B1kdIE2Rbn8M/zpOKHU3Yvt8336+iwdZ0GObTzN6mlsBMIlbaFEBMIKC/YCEdtCPTIivc4NYAjAN +AA0AvVteZQ5mrk6EdgOM1Yuvc4NYDQB+gktRW41QTnBlbmMnWaZTTZEHWdGPfnZzXnN8hHYNZ6FS +aFa+iwdZA4zVizpTDP86TqJbN2LQY5tPDmauTgEwM3qaWwEwiVtZl4R2vosHWQOM1Yuvc4NYAjAN +AA0A/H4IVNF2p2MtTsNfDQB+gktRW41QTnBlbmMnWaZT/H4IVNF2p2MtTsNfMXVRf9x+0XanYwEw +iG0yltF2p2OMVIlbMpbRdqdjCU7okAZSxH4QYgz/5WIJZzBOzFvQj/R+z36MmoR2E04aTrpOWFQl +TohbTIAjjQz/bnjdT3BlbmMtTsNfhHaJW2hR0I9sjwIwDQBRf9x+0XanY/t8334NAHBlbmMnWaZT +x5EodUMAYQBjAHQAaQCMVE4AYQBnAGkAbwBzAFSACFSeW7Bz+VtRf9x+ylMNZ6FSaFaEdtF2p2MM +/zpnP2LPa2FnOmfcZxqQU5BHV02RB1nscst6xomRmNF2p2O+iwdZDP+eW/Zl0XanYyh1N2K+iwdZ +0I9MiMVgtVEM/9F2p2PiVh+WNwDXADIANAAPXPZlOk4odTdivosHWdCPTIikYiqCAjANAA0AiG0y +ltF2p2P7fN9+DQAnWaZTBlJCXANebn8aToVRAGdIUduPhHYDTh9sGU73cBRsU09tcGtw+3zffgz/ +71PFjx+Q0VOwc4xU618fkJpbTU9rcMVgDP9ueN1PbXBrcEhlh3MM/wlnSGXdT5yWKHU3YiKNp06J +W2hRAjANAA0AiVsyltF2p2P7fN9+DQB+gktRW41QTnBlbmMnWaZThVEWWYlbxYhoUbllTU+eW/Zl +0XanY/t8334M/+BlxomRmNF2p2N7a9KJDP83ANcAMgA0AA9c9mVoUQt6sItVX3BlbmMnWaZThVEW +WcVgtVEM/4lbMpZVX89Q3U9YWwlOKk4IZwz/J1mmU6F7BnTokOiV/YDFjx+QaFFil4R2jGPhY3xp +h1uFURZZiVvdT8VgtVEM/zpOKHU3YtBjm0+JW2hRM3qaW4R2vosHWdCPTIivc4NYAjANAA0ASQBE +AEMAnlg8UA1noVJTT4yaLU7DXw0AfoJLUVuNUE6eWDxQDWehUlNPjJotTsNfMXXPfoyaME7MW4R2 +DWehUuJWH5bQjyWEDP+dT1hifoJLUVuNUE5/iTpTcGVuYy1Ow19JexhPKI1sePZORI2QbjpOKHU3 +YtBjm0+BZ3dR9048UIR2nlg8UA1noVICMAxU9mUM/yh1N2LvU01ROY2rTih1nlg8UA1noVItTsNf +0GObT4R2Gll5mE1ROY2eWDxQDWehUqdOwVQCMA0ADQCeWDxQDWehUgZSe3wNAIlbaFENZ6FSATDj +TvR+DWehUgEw0XanYw1noVIBMJReKHW5ZUhoATBwZW5jB1n9TgEw+3zffrZnhGcBMFF/3H62Z4Rn +DQAoANmPm04NZ6FShHb3TjxQoWwJZ1NPsHP6UWVnLAAgAAxU9mX7fN9+tmeEZ4xUUX/cfrZnhGck +TnmYL2ZyXsBOSE6Edj8AKQANAA0Anlg8UA1noVJEjTmNDQAI/8JTA4CHZU5TRI2ZZWiIPGgJ/w0A +DQAcIJFlbJq/fh0goXsGdPt8334I/36CS1FbjVBOcGVuYydZplModTdiTVE5jX9PKHUJ/w0AHCCR +ZWyav34dIKF7BnT7fN9+L2YxdX6CS1FbjVBO6oE7ThR40VOEdgBOPmuIlPlbDWehUmhWATBRf9x+ +vosHWQEwlF4odft8337bj0yIxpYtTtF2p2MOTqF7BnSEdm+P9k4M/zF1foJLUVuNUE7qgTtOFHjR +UwIwDQAcIJFlbJq/fh0gb4/2TqF7BnT7fN9+nlv2ZdF2p2ModTdivosHWYR20I9MiLZyAWAM/1Nf +2Y+bTr6LB1n6UbBz0I9MiEVlnJb2ZSx7AE72ZfSVGpDldyh1N2Lbj0yIBFkGdBv/DFT2ZQz/5Yv7 +fN9+T1OpUih1N2L5W3ZRvosHWduPTIjffgBOoXsGdAz/0GObT4ZOKHU3Yqd+ATDokOiVp34BMGxR ++FOnfoR2oXsGdENnUJYCMA1OxU53UQln+VsodTdiQGIJZ0kAVAC+iwdZxpYtTtF2p2OEdp9S/YAM +/wxU9mXYj3dRCWf5W0BiCWcNZ6FSaFbbj0yIxpYtTqF7BnQAAAAIAAASCAAAFAgAABwIAAAeCAAA +IAgAACIIAAAkCAAAJggAAFQIAABWCAAAWAgAAFoIAACSCAAAlAgAAJYIAACYCAAAmggAAJwIAACk +CAAApggAAKgIAADcCAAA3ggAAOAIAADiCAAA5AgAAOYIAADoCAAA6ggAAPLk29Pb08/Hz8e0pp2m +h7SmnXdsXWxLXWxdtJ20ACMCCIEDan0AAAAGCAERCIEWaGt8wQBVCAFtSAAEbkgABHUIAR0DagAA +AAARCIEWaGt8wQBVCAFtSAAEbkgABHUIARQRCIEWaGt8wQBtSAAEbkgABHUIAQAeFWi3YsEAFmhr +fMEAMEoVAG1IAARuSAAEbygBdQgBACoCCIEDagAAAAAGCAEVaLdiwQAWaGt8wQAwShUAVQgBbUgA +BG5IAAR1CAEAERZoa3zBAG1IAARuSAAEdQgBGxVot2LBABZoa3zBADBKFQBtSAAEbkgABHUIASQD +agAAAAAVaLdiwQAWaGt8wQAwShUAVQgBbUgABG5IAAR1CAEADwNqAAAAABZoa3zBAFUIAQYWaGt8 +wQAADhZoa3zBAG1IBAhzSAQIABEWaGt8wQBtSAQIbygBc0gECBoVaIgV2gAWaMIfwAA1CIFDSiwA +YUosAG8oAQAaFWiIFdoAFmjaRf0ANQiBQ0osAGFKLABvKAEdAAgAABQIAAAkCAAA6AgAAIIJAAAo +CgAAzAoAAHALAAAQDAAApgwAADwNAADSDQAAaA4AAAYPAACkDwAAQhAAAOQQAAB6EQAADBIAALAS +AAC0EgAAthIAALgSAAC8EgAA9wAAAAAAAAAAAAAAAO8AAAAAAAAAAAAAAADoAAAAAAAAAAAAAAAA +6AAAAAAAAAAAAAAAAOEAAAAAAAAAAAAAAADhAAAAAAAAAAAAAAAA4QAAAAAAAAAAAAAAAOgAAAAA +AAAAAAAAAADhAAAAAAAAAAAAAAAA4QAAAAAAAAAAAAAAAOEAAAAAAAAAAAAAAADoAAAAAAAAAAAA +AAAA4QAAAAAAAAAAAAAAAOEAAAAAAAAAAAAAAADhAAAAAAAAAAAAAAAA4QAAAAAAAAAAAAAAAOgA +AAAAAAAAAAAAAADoAAAAAAAAAAAAAAAA6AAAAAAAAAAAAAAAAN8AAAAAAAAAAAAAAADfAAAAAAAA +AAAAAAAA0AAAAAAAAAAAAAAAANAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADg8A +D4SpARGEAABXRAAAXoSpAWCEAABnZPpCAwAAAQAABxQADcYIAAIaBGggAAoHEwANxggAAqQBaCAA +CgAHEQADJAFhJAFnZGt8wQAABwAAAyQBYSQBZ2TaRf0AABfqCAAA7AgAACQJAAAmCQAAKAkAACoJ +AAAsCQAALgkAAD4JAABACQAAQgkAAHYJAAB4CQAAegkAAHwJAAB+CQAAgAkAAIIJAACECQAAhgkA +AL4JAADACQAAwgkAAMQJAADKCQAAzAkAAOQJAADmCQAA6AkAABwKAAAeCgAAIAoAACIKAAAkCgAA +JgoAACgKAADx6PHSv/Hor6SVpIOVpJW/6L/x6PFtv/Hor6SVpFuVpJW/6AAAACMCCIEDanECAAAG +CAERCIEWaGt8wQBVCAFtSAAEbkgABHUIASoCCIEDavQBAAAGCAEVaLdiwQAWaGt8wQAwShUAVQgB +bUgABG5IAAR1CAEAIwIIgQNqdwEAAAYIAREIgRZoa3zBAFUIAW1IAARuSAAEdQgBHQNqAAAAABEI +gRZoa3zBAFUIAW1IAARuSAAEdQgBFBEIgRZoa3zBAG1IAARuSAAEdQgBAB4VaLdiwQAWaGt8wQAw +ShUAbUgABG5IAARvKAF1CAEAJANqAAAAABVot2LBABZoa3zBADBKFQBVCAFtSAAEbkgABHUIAQAq +AgiBA2r6AAAABggBFWi3YsEAFmhrfMEAMEoVAFUIAW1IAARuSAAEdQgBABEWaGt8wQBtSAAEbkgA +BHUIARsVaLdiwQAWaGt8wQAwShUAbUgABG5IAAR1CAEAIygKAAAqCgAALAoAAGQKAABmCgAAaAoA +AGoKAABwCgAAcgoAAHgKAACICgAAigoAAIwKAADACgAAwgoAAMQKAADGCgAAyAoAAMoKAADMCgAA +zgoAANAKAAAICwAACgsAAAwLAAAOCwAAFAsAABYLAAAsCwAALgsAADALAABkCwAAZgsAAGgLAABq +CwAAbAsAAG4LAADt39bfwO3f1t+wpZalhJallu3W7d/W327t39awpZalXJallu0jAgiBA2plBAAA +BggBEQiBFmhrfMEAVQgBbUgABG5IAAR1CAEqAgiBA2roAwAABggBFWi3YsEAFmhrfMEAMEoVAFUI +AW1IAARuSAAEdQgBACMCCIEDamsDAAAGCAERCIEWaGt8wQBVCAFtSAAEbkgABHUIAR0DagAAAAAR +CIEWaGt8wQBVCAFtSAAEbkgABHUIARQRCIEWaGt8wQBtSAAEbkgABHUIAQAeFWi3YsEAFmhrfMEA +MEoVAG1IAARuSAAEbygBdQgBACoCCIEDau4CAAAGCAEVaLdiwQAWaGt8wQAwShUAVQgBbUgABG5I +AAR1CAEAERZoa3zBAG1IAARuSAAEdQgBGxVot2LBABZoa3zBADBKFQBtSAAEbkgABHUIASQDagAA +AAAVaLdiwQAWaGt8wQAwShUAVQgBbUgABG5IAAR1CAEkbgsAAHALAAByCwAAdAsAAKwLAACuCwAA +sAsAALILAAC0CwAAtgsAALwLAADMCwAAzgsAANALAAAEDAAABgwAAAgMAAAKDAAADAwAAA4MAAAQ +DAAAEgwAABQMAABMDAAATgwAAFAMAABSDAAAWAwAAFoMAABiDAAAZAwAAGYMAACaDAAAnAwAAJ4M +AACgDAAA9uPV9tW/49X21a+klaSDlaSV4/bj1fbVbePV9q+klaRblaQAAAAjAgiBA2pZBgAABggB +EQiBFmhrfMEAVQgBbUgABG5IAAR1CAEqAgiBA2rcBQAABggBFWi3YsEAFmhrfMEAMEoVAFUIAW1I +AARuSAAEdQgBACMCCIEDal8FAAAGCAERCIEWaGt8wQBVCAFtSAAEbkgABHUIAR0DagAAAAARCIEW +aGt8wQBVCAFtSAAEbkgABHUIARQRCIEWaGt8wQBtSAAEbkgABHUIAQAeFWi3YsEAFmhrfMEAMEoV +AG1IAARuSAAEbygBdQgBACoCCIEDauIEAAAGCAEVaLdiwQAWaGt8wQAwShUAVQgBbUgABG5IAAR1 +CAEAGxVot2LBABZoa3zBADBKFQBtSAAEbkgABHUIASQDagAAAAAVaLdiwQAWaGt8wQAwShUAVQgB +bUgABG5IAAR1CAEAERZoa3zBAG1IAARuSAAEdQgBACOgDAAAogwAAKQMAACmDAAAqAwAAKoMAADi +DAAA5AwAAOYMAADoDAAA7gwAAPAMAAD4DAAA+gwAAPwMAAAwDQAAMg0AADQNAAA2DQAAOA0AADoN +AAA8DQAAPg0AAEANAAB4DQAAeg0AAHwNAAB+DQAAhA0AAIYNAACODQAAkA0AAJINAADGDQAAyA0A +AMoNAADw3dTdxtTGsN3G1KCV8JWD8JXw3dTdxtTGbd3G1KCV8JVb8AAAACMCCIEDak0IAAAGCAER +CIEWaGt8wQBVCAFtSAAEbkgABHUIASoCCIEDatAHAAAGCAEVaLdiwQAWaGt8wQAwShUAVQgBbUgA +BG5IAAR1CAEAIwIIgQNqUwcAAAYIAREIgRZoa3zBAFUIAW1IAARuSAAEdQgBFBEIgRZoa3zBAG1I +AARuSAAEdQgBAB4VaLdiwQAWaGt8wQAwShUAbUgABG5IAARvKAF1CAEAKgIIgQNq1gYAAAYIARVo +t2LBABZoa3zBADBKFQBVCAFtSAAEbkgABHUIAQAbFWi3YsEAFmhrfMEAMEoVAG1IAARuSAAEdQgB +ERZoa3zBAG1IAARuSAAEdQgBJANqAAAAABVot2LBABZoa3zBADBKFQBVCAFtSAAEbkgABHUIAQAd +A2oAAAAAEQiBFmhrfMEAVQgBbUgABG5IAAR1CAEAI8oNAADMDQAAzg0AANANAADSDQAA1A0AANYN +AAAODgAAEA4AABIOAAAUDgAAFg4AABgOAAAkDgAAJg4AACgOAABcDgAAXg4AAGAOAABiDgAAZA4A +AGYOAABoDgAAag4AAGwOAACkDgAApg4AAKgOAACqDgAAsA4AALIOAADCDgAAxA4AAMYOAAD6DgAA +/A4AAP4OAAD15tPK07zKvKbTvMqW9eb1hOb15tPK07zKvG7TvMqW9eb1XOYjAgiBA2pBCgAABggB +EQiBFmhrfMEAVQgBbUgABG5IAAR1CAEqAgiBA2rECQAABggBFWi3YsEAFmhrfMEAMEoVAFUIAW1I +AARuSAAEdQgBACMCCIEDakcJAAAGCAERCIEWaGt8wQBVCAFtSAAEbkgABHUIAR4VaLdiwQAWaGt8 +wQAwShUAbUgABG5IAARvKAF1CAEAKgIIgQNqyggAAAYIARVot2LBABZoa3zBADBKFQBVCAFtSAAE +bkgABHUIAQAbFWi3YsEAFmhrfMEAMEoVAG1IAARuSAAEdQgBERZoa3zBAG1IAARuSAAEdQgBJANq +AAAAABVot2LBABZoa3zBADBKFQBVCAFtSAAEbkgABHUIAQAdA2oAAAAAEQiBFmhrfMEAVQgBbUgA +BG5IAAR1CAEUEQiBFmhrfMEAbUgABG5IAAR1CAEk/g4AAAAPAAACDwAABA8AAAYPAAAIDwAACg8A +AEIPAABEDwAARg8AAEgPAABODwAAUA8AAGAPAABiDwAAZA8AAJgPAACaDwAAnA8AAJ4PAACgDwAA +og8AAKQPAACmDwAAqA8AAOAPAADiDwAA5A8AAOYPAADsDwAA7g8AAP4PAAAAEAAAAhAAADYQAAA4 +EAAAOhAAAPXm08rTvMq8ptO8ypb15vWE5vXm08rTvMq8btO8ypb15vVc5iMCCIEDajUMAAAGCAER +CIEWaGt8wQBVCAFtSAAEbkgABHUIASoCCIEDargLAAAGCAEVaLdiwQAWaGt8wQAwShUAVQgBbUgA +BG5IAAR1CAEAIwIIgQNqOwsAAAYIAREIgRZoa3zBAFUIAW1IAARuSAAEdQgBHhVot2LBABZoa3zB +ADBKFQBtSAAEbkgABG8oAXUIAQAqAgiBA2q+CgAABggBFWi3YsEAFmhrfMEAMEoVAFUIAW1IAARu +SAAEdQgBABsVaLdiwQAWaGt8wQAwShUAbUgABG5IAAR1CAERFmhrfMEAbUgABG5IAAR1CAEkA2oA +AAAAFWi3YsEAFmhrfMEAMEoVAFUIAW1IAARuSAAEdQgBAB0DagAAAAARCIEWaGt8wQBVCAFtSAAE +bkgABHUIARQRCIEWaGt8wQBtSAAEbkgABHUIASQ6EAAAPBAAAD4QAABAEAAAQhAAAEQQAABGEAAA +fhAAAIAQAACCEAAAhBAAAIoQAACMEAAAoBAAAKIQAACkEAAA2BAAANoQAADcEAAA3hAAAOAQAADi +EAAA5BAAAOYQAADoEAAAIBEAACIRAAAkEQAAJhEAACgRAAAqEQAANhEAADgRAAA6EQAAbhEAAHAR +AAByEQAA9ebTytO8yrym07zKlvXm9YTm9ebTytO8yrxu07zKlvXm9VzmIwIIgQNqKQ4AAAYIAREI +gRZoa3zBAFUIAW1IAARuSAAEdQgBKgIIgQNqrA0AAAYIARVot2LBABZoa3zBADBKFQBVCAFtSAAE +bkgABHUIAQAjAgiBA2ovDQAABggBEQiBFmhrfMEAVQgBbUgABG5IAAR1CAEeFWi3YsEAFmhrfMEA +MEoVAG1IAARuSAAEbygBdQgBACoCCIEDarIMAAAGCAEVaLdiwQAWaGt8wQAwShUAVQgBbUgABG5I +AAR1CAEAGxVot2LBABZoa3zBADBKFQBtSAAEbkgABHUIAREWaGt8wQBtSAAEbkgABHUIASQDagAA +AAAVaLdiwQAWaGt8wQAwShUAVQgBbUgABG5IAAR1CAEAHQNqAAAAABEIgRZoa3zBAFUIAW1IAARu +SAAEdQgBFBEIgRZoa3zBAG1IAARuSAAEdQgBJHIRAAB0EQAAdhEAAHgRAAB6EQAAfBEAAH4RAAC2 +EQAAuBEAALoRAAC8EQAAvhEAAMARAADIEQAAyhEAAMwRAAAAEgAAAhIAAAQSAAAGEgAACBIAAAoS +AAAMEgAADhIAABASAABIEgAAShIAAEwSAABOEgAAUBIAAFISAABgEgAAaBIAAGwSAABuEgAAcBIA +AKQSAAD15tPK07zKvKbTvMqW9eb1hOb15tPK07zKvG7TvMqWvJb15vUAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAqAgiBA2qgDwAABggBFWi3YsEAFmhrfMEAMEoVAFUIAW1IAARu +SAAEdQgBACMCCIEDaiMPAAAGCAERCIEWaGt8wQBVCAFtSAAEbkgABHUIAR4VaLdiwQAWaGt8wQAw +ShUAbUgABG5IAARvKAF1CAEAKgIIgQNqpg4AAAYIARVot2LBABZoa3zBADBKFQBVCAFtSAAEbkgA +BHUIAQAbFWi3YsEAFmhrfMEAMEoVAG1IAARuSAAEdQgBERZoa3zBAG1IAARuSAAEdQgBJANqAAAA +ABVot2LBABZoa3zBADBKFQBVCAFtSAAEbkgABHUIAQAdA2oAAAAAEQiBFmhrfMEAVQgBbUgABG5I +AAR1CAEUEQiBFmhrfMEAbUgABG5IAAR1CAEkpBIAAKYSAACoEgAAqhIAAKwSAACuEgAAsBIAALIS +AAC0EgAAthIAALgSAAC6EgAAvBIAAMYSAAD+EgAAABMAABgTAAAaEwAASBMAAEoTAABUEwAAVhMA +AFwTAABeEwAAYhMAAGQTAACYEwAAmhMAAL4VAADAFQAAwhUAAO3e097At6+rp5uUiIB7dnt2e3Z7 +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 +AAAAAAAAAAAAAACuAAAAAAAAAAAAAAAAuQAAAAAAAAAAAAAAAK4AAAAAAAAAAAAAAAC5AAAAAAAA +AAAAAAAArgAAAAAAAAAAAAAAALkAAAAAAAAAAAAAAACjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAKDwAPhFIDVkSVAV6EUgNnZMFf8gAACg8AD4RSA1ZElQFehFIDZ2TzMYwAAA4PAA+ENwIR +hKYBVkQOAV6ENwJghKYBZ2TBX/IAAAoPAA+E3wNWRNgBXoTfA2dkoGVFAAAIDwAPhOADXoTgA2dk +kHm6AAoPAAomAgtGCQBXRAAAZ2R2PjoAAA4PAA+E4AMRhAAAV0QAAF6E4ANghAAAZ2R6eR0ACg8A +CiYCC0YQAFdEAABnZHY+OgAAEjAlAAA0JQAAXiUAAHQlAACsJQAAsCUAALIlAAC2JQAAuiUAANQl +AADaJQAA3CUAAOIlAADmJQAA9iUAAPolAAD+JQAAAEwAAAZMAAAITAAACkwAAPTo3NDE0K+ar4WA +a4VrVmtUhYA/AAAAAAAAAAAAAAAAAAAAAAAAAAAAACgACIEWaJB5ugAXaAsoIgBjSAEAZGgAAAAA +ZGgAAAAAZGiF6+smbygBAANVCAEoAAiBFmiQeboAF2g5d+sAY0gBAGRoAAAAAGRoAAAAAGRoeevr +Jm8oAQAoAAiBFmiQeboAF2gLKCIAY0gBAGRoAAAAAGRoAAAAAGRoh+vrJm8oAQAJFmiQeboAbygB +KAAIgRZokHm6ABdoOXfrAGNIAQBkaAAAAABkaAAAAABkaHjr6yZvKAEAKAAIgRZokHm6ABdoOXfr +AGNIAQBkaAAAAABkaAAAAABkaHfr6yZvKAEAKAAIgRZokHm6ABdoCygiAGNIAQBkaAAAAABkaAAA +AABkaIbr6yZvKAEAFgEIgQRIAQAFaIzr6yYWaHRk/QBvKAEAFgEIgQRIAQAFaInr6yYWaAsoIgBv +KAEAFgEIgQRIAQAFaIfr6yYWaAsoIgBvKAEAFgEIgQRIAQAFaIbr6yYWaAsoIgBvKAEAFgEIgQRI +AQAFaIjr6yYWaAsoIgBvKAEUhHafUv2AAjAgAOWL+3zffu9TOk4odTdi0GObT55b9mUnYP2ApWJm +iwz/f0+XXyh1N2LvU+VOLHsATvZl9JWGTuOJMFK+iwdZhHbQj0yIRWWclgz/dl5zU/Zl249MiARZ +BnQCMA0AOyDtd+FPpWJmixr/DQAfdxBiWlAwUjMANgA1ACoAMgA0AEVlnJaEmGaLAjAgAA0AOyA7 +TjpnwGhLbRr/DQDqgahSwGhLbQ1noVJoVuaLxn5NkW5/AjAgAA0AOyB6Zv2AhHalYmaLuk6+i25/ +Gv8NADlobmMAl0Js+04PYb6Lbn+lYmaL+06hUgz/H3dja1pQMFIjjftOMFK6TgIwIAANADsgpWJm +i59S/YAa/w0A7XfhT6ViZosBMK6Q9k6lYmaLATBXAEUAQgCeW/ZltnIBYFVcOnkM/6mLKHU3Yix7 +AE72ZfSV5XdTkA1noVJoVoR20I9MiLZyAWACMCAADQA7IFF/3H6+iwdZBFTveuNTIk4FU9F2p2Ma +/w0A0XanY1F/3H6+iwdZhHYiTgVTtnIBYAz/j5b2ZdBjm0+lYmaLDP8JZ0hlMFeeW/Zlhk7jiVF/ +3H4vZiZU11MwUjtl+1EWYi9mE3+yUTpTom76UQIwIAANADsgpWJoiJ9S/YAa/w0AOl8nWYR2pWJo +iJ9S/YABMEUAeABjAGUAbABoiDxo/Fv6UQEwDWehUmhWJ2D9gAZSkGedT25jDP9Rf9x+oXsGdAWA +hHYAZ3NPqVJLYgIwDQANADsgME7MW4R20XanY/tOoVINAJ5b9mXRdqdjO046ZyP/MP81/wEwhVFY +WwEwwXjYdoR20I9MiLZyAWAM/+qBqFLAaOVnO046Z4R2UX/cfv6U743ejxqQJ2AM/5pb9mXAaEtt +O046Z4R2BFSUXih1DWehUgj/glk3/yX/Iv8BMC3/Qf9J/0z/Cf/KU3BlbmOTXoR2ZVDuWCdgAjAN +ADsgnlv2ZYR2pWJmixqQ5XcNAFNfKHU3Yr6LB1kWYpReKHUNZ6FS+lGwc0VlnJb2ZQz/5Yv7fN9+ +BlzLejtS5U7td+FPATCukPZOSXu5ZQ9fGpDldyh1N2Lbj0yIBFkGdAIwDQA7IBpZN2iEdqViZou5 +ZQ9fDQAodTdi71O+i25/7XfhTwEwrpD2Tkl7GlnNeaViZou5ZQ9fZWe3g5dfpWJmi4htb2ACMA0A +OyAwTsxbhHalYmiIn1L9gA0AKHU3Yg1OxU7vU+VOzk43/yX/Iv+hewZ0THVilyhXv363g5dfvosH +WdCPTIi2cgFgDP8MgBRO2I/vU+VO/Fv6USX/WP9D/0X/TP88aA9fhHaGU/JTcGVuYwz/+Vu+iwdZ +hHbQj0yIsItVX9uPTIjffqGLBlKQZwIwDQA7IDpfJ1mEdkSNp06hewZ0DQDQY5tPKHU3Yqd+ATDo +kOiVp34BMGxR+FOnfglOzXmnfitShHZDZ1CWoXsGdAz/CWcpUo5OKHU3Yt9+AE6hewZ06oHxXYR2 +vosHWQIwDQAcIPtOEWKukB0gAU8aTq6QQFz7fN9+CP9+gktRW41QTnBlbmMnWaZTKHU3Yk1ROY1/ +Tyh1Cf8NAPtOEWKukC9mAE4+a/pXjk6RTqGLl3tzXvBTgGIvZ4R2sGUATuNOAU8aTq6QQFz7fN9+ +DP8xdX6CS1FbjVBO6oE7ThR40VMCMAz/5WIJZxpZeZj9VoVRATAWWYaYSFGAYi9nAjAb/59S/YC+ +i6GLR1fOTgFPGk4odTdiAJdCbPpR0VMM/zpOAU8aTih1N2LQY5tPaFGwZYR2RXU4blNPjJoCMA0A +OyD7ThFirpCnTsFUn1L9gGiIDQB3AGUAYgBtAGEAaQBsAAcAVwBlAGIAIABhAGQAbQBpAG4ABwBJ +AE0ABwAHAK6Q9k42ZdFTBwABTxpO4U9vYKF7BnQHACpOuk5zU/ZlGpCviwcABwCukPZOHGQifQcA +ImvOj+FPmls2UgcAGlm6ThpProsHAAcAKk66Ti8AAU8aThqQr4tVXwcA31cvAOiQ6JVsUUpUoXsG +dAcAh2X2Tq1luXDtfiBPBwAHAIdl9k45WaF7BnQHACh1N2JEjZlloXsGdAcArpD2Tutfd2NlUeNT +BwAHACpOJ2AWU357DVQHACaN91OhewZ0BwBKgClZsItVXxxkIn0HAAcA6oGpUuVn4osHAOqBmltJ +Tih1N2LEfqF7BnQHAMR+4U9vYNFTAZAHAAcAMQBHAIWNJ1lElvZOBwBoUd9XLwDokOiVGpCvi1Vf +5WcLd0NnUJahewZ0BwABTxpOcVGrThqQr4tVXw//6JDolRqQr4tVXw//Kk66ThqQr4tVXwcABwDN +U4NXPlcBMDKWMpbSawcArpD2TqR/0VMHANF+mls7TkFtrpD2TqJbN2LvegcABwB3bRZZNmXRUwEw +V1MXUxpZv36lY2VRBwABTxpOLwDokOiVGpCvi1VfoXsGdAcAsGWukPZOnlv2ZdBjkpEHAAcAUABP +AFAA4042ZQcArpD2TgdZ/U4HAAcABwCukPZO6oGoUmyP0VMHAK6Q9k7RdqdjBwAHAAcA6oGaW66Q +9k7Hj+RuxIkZUgcABwAHAAcArpD2Tp5b9mWoYwGQBwAHAAcABwANADsgOGjDXxhPv1INALcAc1P2 +ZRqQr4sM/1NiIJD0Zutfd2PYmkhlhHYBTxpOpE5BbXNe8FMNALcAOl8nWYR2GpCvi1Vfn1L9gA0A +twCukPZOnlv2ZahjAZANALcAhY0nWXp69JUBMIWNJ1lElvZODQC3AIWNOl/NU4NXPlcylsV10msM +//9+coKJW2hRDQC3ANF+mls7TkFtrpD2TqJbN2Lvegj/RgBvAHgAbQBhAGkAbAAsACAATwB1AHQA +bABvAG8AawAsACAATwB1AHQAbABvAG8AawAgAEUAeABwAHIAZQBzAHMACf8M/7llv0/rX3djDQC3 +AGhRA3Rsj9FTATBXUxdTRXU4bg0AtwA1deFPp37QjyWEDP8NZ6FSd23PkSh1N2INALcAy3pTTw9f +DWehUvt8334NAA0AAU8aTuFPb2AWUxZZBVMNZ6FSLU7DXw0AfoJLUVuNUE7Qj/R+FlkFUw1noVLi +Vh+W5WIJZzBOzFuEdp5b9Y3PfoyaATDEiQODhHYNZ6FSQW0LegEwOl8nWYR2gGIvZ5tSz5GMVBdP +GlmEdhpOoVIIVFxPGU80Twz/LGdAdxwgE04aTg1noVIBMHNRMXKiWzdiHSCEdg1noVIGdPVfDP/6 +Xst6xIkDg4R2DWehUlNP+3yMVA1noVJBbQt6AjAsZ0B3HCAATtl6D18dIA1noVKEdtCPJYS5ZYiU +DP8RVCh1N2LQY5tPiVtoUQ1noVIBMCdg/YAYTxZTATD7fN9+tmeEZwEwUX/cfrZnhGcBMHBlbmMH +Wf1OATDRdqdjc17wU+iQcn9JexpZeZgNZ6FSAjAMVPZlnU9YYuJWH5YwTsxbhHaeW/WNz36Mmgz/ +Ok6iWzdi0GObT3RlU0+EdhZZBVPjibNRuWVIaAIwDQDQj/R+FlkFUw1noVKFUblbDQCJW2hRDWeh +UgEwJ2D9gBhPFlMBMPt83362Z4RnATBRf9x+tmeEZwEwcGVuYwdZ/U4BMNF2p2MNZ6FSDQANZ6FS +f2L6iw0AtwA3ANcAMgA0AA9c9mU1dd2Ly3pzU81UlF4NALcA7XfhT6ViZosM/xqQ5XfRdqdjDQC3 +AFF/2XoKTr9+h3PdT8GLOQA5AC4AOQAlAA0AtwAHWf1O4GXnXwz/iVtoUSx7AE4NALcAD28ebe5P +ZYgM/wJjbJoFbmSWDQC3ABNOGk7iVh+WDP8xcqJb4GVQlg0ADQBJAEQAQwCeWDxQDWehUglOJ1kY +T79SDQBsePZOGE+/Ug0AfoJLUVuNUE7scst6+l6+i9CPJYSEdhwgfoJLUVuNUE5wZW5jJ1mmUx0g ++l5Re2KX73kKTgdOc15zfAz/RI3RkZViZVEKTr9OQ1EM/8aWBFTQjyWERlUYTyiNRI2QbgEw/VZF +lgBOQW1vj2x49k76V0B4vou9ZQEw334AToR2iVtoUaF7BnRzXvBTATAnYP2AGE8CX4R20I/0ft1P +nJZzXvBT5U7KU3aYFlzhT29gFlMNZ6FSB2jGUY5OAE6rjgz/L2YXU6xOAGcnWYR2SQBEAEMAcGVu +Yw1noVInWaZTAjANAIBiL2cYT79SDQB+gktRW41QTuViCWcTTrZbp36EdoBiL2cNZ6FS4lYflgz/ +f5UfZxNO6GyOTlF/3H4BMPt8336EdoBiL2enTsFUhHYUeHZ6jFQAX9FTDP/0gZtSjk7QY9iaEWLs +ToR2gGIvZzRsc16MVOVdXE9IZYdzAjARYuxOOk6iWzdi0GObTxhPKI2EdqhU4ot+mO6VDk7jibNR +uWVIaAIwfoJLUVuNUE7lYglnGlkNVIBiL2eki8GLE062Wwz/3U/BizpOols3YtBjm0/YmiiNz5GE +doBiL2cNZ6FSAjB/lR9n9IGbUo5OVwBpAG4AZABvAHcAcwAgAE4AVAABMFcAaQBuAGQAbwB3AHMA +MgAwADAAMwABMFUAbgBpAHgAATAvAEwAaQBuAHUAeABzXvBTCk6EdqdOwVQAX9FTATBLbdWLDP/l +TspT0GObTwRUzXkaTqFSe3yLV4R2UX/cfuOJs1G5ZUhoAjAakMePJ1nPkYR25V1cT5ReKHVIaItP +DP8oV1F/3H6UXih1vouhiwEweZjudp5bvWUBMKJbN2INZ6FSSXu5ZWKX73kvfYZOME7MW4R2E04a +Ts9+jJoCMA5O/VaFURZZ5XcNVEkAVAABTxpO+l7LeoZOf17bbIR2Gk6hUghUXE9zUft8DP8akMeP +GE+/UpJOZYg6TqJbN2LQY5tP9GaMW4RVhHYNZ6FSAjB+gktRW41QTstZyH7ZeihXnlg8UA1noVLR +U1VchHZNUr9sDP/9jyqOATCGmPxbnlg8UA1noVICXjpXhHYAZ7Bli42/Ugz/Ok6nTsFUjFQNZ6FS +hHYCkCh1J2ABME1Su3cnYNBjm0+dT25jAjANAA0ADWehUhhPv1INAH6CS1FbjVBOAE70dlpXAWOi +WzdihHYAl4GJMVwvZhFi7E79j0JshHYNZ6FSl1voZQz/L2YaTkx1TZFuf4ZO/YAfWSdZxIkhagRZ +BnRoUf1Wols3YmVnNXWEdnxU61MtTsNf+3zffoR2E04aTg1noVJGVQz/Ok6iWzdi0GObTzcA1wAy +ADQAD1z2ZQ1O9JWtZQ1noVICMA0AfoJLUVuNUE7Yj4dzSFGeW71lhk6iWzdiUX/ZemhRsHM6Vw1n +oVIM/36CS1FbjVBOhHaAYi9n5V0LegheaFEpWRlQ5V1cTyhXols3YlF/2XpYYqF7cGVuYy1Ow1+M +VJ5SbFE6V0BiDP8AZydZUJamXjBX3U/Bi6JbN2JRf9l6iVtoUdCPTIgCMA0ADQANACdZi1fjibNR +uWVIaA0AiVtoUbZnhGfjibNRuWVIaA0AEWLsTkhkA1+GTiBP336EdjKWa3CZWKBSSQBEAFMAhHbj +ibNRuWVIaAz/MpZrcJlYnluwc4ZOxpYtToR2oXsGdEZPL2YylmtwmVgaTxBiOk5VU7lwDIAUThpP +EGI6TnRlKk5Rf9l6hHb2dIiYAjBAYuVOGpDHjzpOz2vEfg1noVJoVgdjmlvmi8Z+hHaJW2hRVntl +dYWP5U5WAFAATgAM/4xOIWuki8GLDP/lZddfDWehUmhWDP9lUbVPwGhLbft8336EZxBidGVTT4R2 +iVtoUVNP+3wCMA0AJ1mLV6JbN2LjibNRuWVIaA0AJ1mLV6JbN2LjibNRuWVIaC9mfoJLUVuNUE46 +TkVRBlLhbrONJ1miWzdihHZYYqF7AJdCbAEwaFFil9BjR1MNZ6FSNGxzXgyAvotuf4R2E07olWKX +EVQnWaJbN2IBMJ5bvWVoUf1Wglf0dgBOU08WU6F7BnQBMNdTBnQ1deFPp35JAEQAQwAaTqFShHYl +hACVDWehUiBuU5AM/51PWGKOTn6CS1FbjVBO6oH6XoR2aFH9VgBnJ1lJAEQAQwCeWDxQDWehUlNP +jJotTsNfhHZsePZOGpDhT/pXQHi+i71lDP/lTkhR24+EdlF/3H6AYi9nATA6XydZhHZRf9x+0I/0 +fv2Am1KMVDBOzFuEdlF/3H6hewZ0z36MmjpOL2WRZAz/YpcRVCdZols3YtBjm08aTqFSqFTiiwEw +11MGdAEwUX/cfhhPFlMBMFF/3H6hewZ0ylPRU1VcxIkSUkl7aFEaTqFS/H4IVA1noVKMVO96MFLv +ehwgAE7Zeg9fDWehUh0gDP/lTspTz5GrjppbNlKEdipOJ2AWUw1noVIBMGhRYpfjibNRuWVIaA9f +DWehUoxU6I0wV99X4GXuXQJfDWehUgIwDQANAJJOVICSThqQ44mzUbllSGgNADpO44mzUS1O/VaD +WIVRBFQnWdCPJYRGVVF/3H5LTvSV4GXVbOtfH5CSTlSAkk4akIR2QFxilwz/foJLUVuNUE45aG5j +DU4MVKJbN2KEdgCXQmwM/9Bjm0/bVidZkk5UgJJOGpDjibNRuWVIaA0ADQBBALllSGga/8xTDWeh +UmhWzFM6Zz9iuWVIaA0AfoJLUVuNUE5sUfhTKFdRf1SAGpBwZW5jLU7DXw5ONXXhT3BlbmMtTsNf +S070lQz/+pS+i4ZO7HIJZ4R2cGVuYwxUZWtJUaR+DP/jibNRhk6iWzdiWGKheyhXJE4qTjpnP2KF +UQ1noVJoVnBlbmOEdgxUZWvulZiYDQANAEIAuWVIaBr/VVMNZ6FSaFbMU79+740vAMxTSQBQALll +SGgNAH6CS1FbjVBObFH4U9Bjm08kTs15VVPscg1noVJoVsxTv37jibNRuWVIaAz/AE7NeS9mzFO/ +fu+NVVNJAFAAuWVIaAj/QgBHAFAAv37vjQn/G//kTgBOzXkvZsxTv37vjcxTSQBQALllSGgCMA0A +DQBDALllSGga/3pm/YDfVw1UuWVIaAj/zFMNZ6FSaFYJ/w0AKFdBALllSGiEdvpXQHgKTgz/foJL +UVuNUE5sUfhTAF/RU4ZO6oHxXYR2emb9gN9XDVTjiZBn+3zffgIwZGv7fN9+AGf6VyxnhHafUv2A +L2bvU+VOemb9gIR2JFKtZcaLK1K/i+6Vols3YlF/2XqEdih1N2IM/zlobmMNTgxUhHa/i+6VBYCK +YqJbN2KEdt9XDVQGUitS44mQZxBiDU4MVIR2SQBQADBXQFcCMA0ADQBEALllSGga/36CS1GgUh+Q +44mzUbllSGgNAH6CS1GgUh+QaFYvZgBOeZiIlPlbUX/ZeqBSH5CEdg1noVICMBqQx4/jTgZ0E39Y +W4VRuVsBMEgAQQBTAEgASXuAYi9n0GPYmqJbN2JRf9l6v4vulR+Qpl4CMINb/YAfWX9ixWKiWzdi +UX/ZenWYYpc3ADAAJQDmXfNThHaFUblbv4vulc+RDP/QY0dTUX/ZeoR2J2D9gAIwL2aiWzdiz1F7 +jw1noVJoVotTm1IBMNBj2JoodTdiv4vulR+Qpl6EdohffVkJkOliAjANAA0AJ1mLV1F/2XoIVFxP +EGKfUkhoi08NAEdZToZRfy0AdwB3AHcALgBxAGkAaABvAG8ALgBjAG8AbQANAOOJs1G5ZUhoGv9H +WU6GUX8vZv1WhVEnWYtXhHbPfoyaHGQifVF/2XoM/89rKVmTYtZTJ1nPkYR2kk5UgFF/cGVuY9uP +TIgGUnt8BFkGdIxUVVywcwz/J1nPkYR2DWehUmhWxpakf76LoYsM/1F/3H4eVBBUz5FelzheJ1kC +MM9+x4/MU7llGlkha6ROQW0M/5dfMFKGTvlbuWWEdqSL71MM/8xTuWVjaw9ffntyf9CP9H4NZ6FS +CFRcT09TrosM/wBOKk4IZ/Zl9JWFUUdZToZRfwpOQ1PwUw1noVJoVmhR6JAQYp9Sc17RbsGPZVF+ +gktRW41QTnBlbmMnWaZTAjANAC1OTlNRfy0AdwB3AHcALgBjAGgAaQBuAGEALgBjAG8AbQANAOOJ +s1G5ZUhoGv8tTk5TUX9cTzpO/VaFUSdZi1f8fghU6JU3Ygz/5WIJZ4WNJ1mEdih1N2Kkf4xU6F0n +WYR2v4vulc+RDP8oV1F/2XqEdjN6mlsnYAEwv4vulUhlh3PKU4lbaFEnYEl7uWVil4GJQmyIX9ia +AjDmUxZZDP/Qj/R+DWehUs1UlF4BMFF/3H6XUVlPtmeEZ76LoYsBMFF/3H4DXr9+xIkDg0l7uWVi +l4GJQmxelzheJU48aAz/EWK5ZdBjm09oUWKXhHbjibNRuWVIaAz/LU5OU1F/OGjDXw1noVJoVmhR +6JDBj2VRfoJLUVuNUE5wZW5jJ1mmUwIwDQCMVK+LUX8tAHcAdwB3AC4AaABlAHgAdQBuAC4AYwBv +AG0ADQDjibNRuWVIaBr/jFSvi1F/XE86Tv1WhVEAZydZhHYijc9+6JU3Ygz/+VuOTlF/3H6EdsFU +KI2MVDN6mlsnYIGJu1NelzheJU48aAIwDFT2ZVxPOk4nWYtXIo3PfuiVN2JRf9l6DP9Rf9l6tmeE +Z16XOF4NWUJnDP9Bbc+R6F0nWQz/+leOThFibFH4UzBOzFuEdoBiL2eeW5tSjFTPfoyaDP8sZ0B3 +zk4odTdi0ommXvpR0VMM/yhXRVEGUuFus40odTdiAJdCbIR2+ldAeApODP8AZydZUJamXjpOKHU3 +YoKCpn4QYixnDP/PfsePzVMNWXdQ5V0M/wBnyH5+gktRW41QToR2UX/cfr6LoYu5ZUhoepgpUhqQ +x4+iWzdixItLbQz/zFO5ZWNrD19+e3J/CFRcT09TrosM/4xUr4tRfw1noVJoVsGPZVF+gktRW41Q +TnBlbmMnWaZTDP8RYmxR+FNjaw9fEVSMVK+LUX/QY5tPNwDXADIANAAPXPZlE04aTkkARABDAA1n +oVICMA0Ad23PkeFPb2AtAHcAdwB3AC4AaAB5AGwAaQBhAG4AZABhAC4AYwBvAG0ADQDjibNRuWVI +aBr/z37Hjw5OGlm2W0kARABDANCPJYRGVd56iU4M/36CS1FbjVBOcGVuYydZplOEdiZevVtEjZBu +ATAzeppbH5CmXoxUJ2D3TtRrSXsYT79SDmY+Zgz/dl4UTmhRuWVNT4R2nlg8UA1noVLKU4BiL2fj +ibNRuWVIaAz/Yo2XX4ZOAE53jVF/ylN2UYBiL2fiVh+WhHbYmqZepIvvUwz/dl6zUZpbMXV+gktR +W41QTmxR+FM6TnZR0GObT3dtz5HReYBiylMATneNUX9oUeiQDWehUmhWhHZJAEQAQwANZ6FSylNR +f9l60I/0fhZZBVMNZ6FSAjDudk1SdlENZ6FSaFZoUeiQWGKhe45OfoJLUVuNUE5wZW5jJ1mmU1YA +SQBQADpnP2ICMA0ADQBsUfhTAU8aTodlFlMNABwgc1ExcqJbN2IM/yhX619QTi1OwlMOTt56iU4M +/yhX3nqJTi1OU0+MmutfUE4B/x0gDQCgABwgMXKiWx0gL2Z+gktRW41QTrpOc1ExcqJbN2IM/+VO +ols3YjpOLU7DXwz/zk6iWzdihHbSiaZe+lHRUwOAUYYBMOOJs1HulZiYDP9FUQZS4W6zjaJbN2KE +dgCXQmyEduVdXE8BYKZeAjANAKAAoAAcIFuNUE4dIHNTOk7rX1BOhHbCUw5O3nqJTgz/3nqJTi1O +U0+MmutfUE4CMA0ADQCgAH6CS1FbjVBO85fRixBi8YKHZWEAYwBjAGUAbABlAHIAYQB0AGUAHSAM +/6BSH5CEdg9hHWAM/wBOB2MdIHcAZQAgAGEAYwBjAGUAbABlAHIAYQB0AGUAIAB5AG8AdQByACAA +YgB1AHMAaQBuAGUAcwBzAB0gDP8TTuhsjk46TgFPGk6EdkZVGk5MiDpOqVKbUgz/5lMWWV9OB2MT +ThpOOk4odTdihHZRf9l60GObT4xbhFWEdqBSH5ANZ6FSAjANAA0AbFH4U0SNKI0NAAj/AJd1jTtg +dGUGdBdSaIgJ/w0ADWehUsFUTHII/8FUTHJMAE8ARwBPAHWYCf8NAAMADQANAAQADQANAAMADQAN +AAQADQANAA0ADQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAACkwAAGRMAABmTAAAaEwAAJJMAACWTAAAmEwAALxMAADATAAAwkwAAAJNAAAGTQAACE0AAGBN +AABkTQAAZk0AANRNAADYTQAA2k0AADROAAA2TgAAOE4AAEhOAABKTgAAck4AAHROAAB6TgAAfE4A +AIpOAACMTgAA6+bQu6jQu6jQu6jQu6jQu6jQu6OXiJd8cGRYZEwAAAAWAQiBBEgBAAVonuvrJhZo +LGPMAG8oAQAWAQiBBEgBAAVooevrJhZoLGPMAG8oAQAWAQiBBEgBAAVonOvrJhZokwx3AG8oAQAW +AQiBBEgBAAVonevrJhZokwx3AG8oAQAWAQiBBEgBAAVom+vrJhZokwx3AG8oAQAcAQiBBEgBAAVo +muvrJhVokwx3ABZokwx3AG8oAQAWAQiBBEgBAAVomuvrJhZokwx3AG8oAQAJFmjZFewAbygBJQAI +gRZowV/yABdokwx3AGNIAQBkaAAAAABkaAAAAABkaJXr6yYoAAiBFmjBX/IAF2iTDHcAY0gBAGRo +AAAAAGRoAAAAAGRolevrJm8oAQArAAiBFmjBX/IAF2iTDHcANQiBY0gBAGRoAAAAAGRoAAAAAGRo +levrJm8oAQkWaDQFbwBvKAEoAAiBFmiQeboAF2g5d+sAY0gBAGRoAAAAAGRoAAAAAGRoeuvrJm8o +AR02TgAAOE4AAEpOAADUTgAA5k4AADhPAABKTwAAfk8AAJBPAAAKUAAAHFAAAGpQAACiUAAARlEA +AFpRAABqUQAAflEAAIRRAADwAAAAAAAAAAAAAAAA8AAAAAAAAAAAAAAAAPAAAAAAAAAAAAAAAADw +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 +6yYWaF0IbAA1CIFvKAEZAQiBBEgBAAVouOvrJhZoXQhsADUIgW8oAR8BCIEESAEABWi06+smFWg/ +XoYAFmhUTk0ANQiBbygBFgEIgQRIAQAFaLTr6yYWaFROTQBvKAEaslQAAM5UAADgVAAA4lQAAPpU +AABMVgAAXlYAAJpWAACkVgAAwFYAANZWAADyVgAACFcAAB5XAAA0VwAANlcAAE5XAABYVwAA9AAA +AAAAAAAAAAAAAPQAAAAAAAAAAAAAAADtAAAAAAAAAAAAAAAA5QAAAAAAAAAAAAAAANoAAAAAAAAA +AAAAAADQAAAAAAAAAAAAAAAAxQAAAAAAAAAAAAAAALsAAAAAAAAAAAAAAACwAAAAAAAAAAAAAAAA +sAAAAAAAAAAAAAAAALAAAAAAAAAAAAAAAACwAAAAAAAAAAAAAAAAsAAAAAAAAAAAAAAAALAAAAAA +AAAAAAAAAACrAAAAAAAAAAAAAAAAowAAAAAAAAAAAAAAAJsAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAgCAAomAQtGAwBnZHY+OgAIAQAKJgALRgIAZ2R2PjoAAAQAAGdkdj46AAAKAAAPhG4E +VkQcAl6EbgRnZOxKRwAKDwAKJgILRg8AV0QAAGdkdj46AAAKAAAPhFIDVkSVAV6EUgNnZANYpQAK +DwAKJgILRgsAV0QAAGdkdj46AAAKAAARhKQBV0TIAGCEpAFnZOwmogAIAgAKJgELRgQAZ2T6QgMA +AAYPAFdEAABnZKBlRQAACgAAD4SoAVZEygBehKgBZ2SgZUUAABHMVgAA0FYAANZWAADYVgAA8lYA +APRWAAAIVwAAClcAAB5XAAAgVwAAKlcAAC5XAAA0VwAANlcAAFhXAAA6WAAARFgAAFhYAABcWAAA +blgAAHBYAACmWAAAqlgAADRZAABSWQAAXFkAAF5ZAABgWQAAsFkAALRZAAC4WQAAuloAAL5aAADI +WgAA6lsAAOxbAADuWwAA/FsAAAxcAAD69ev16/Xr9ev1+vXk3Nfcz9fP18/Xz7fPt6vPk4fP19zX +fXVtZgAAAAAAAAAAAAAMFWgDWKUAFmgDWKUAAA8VaPpCAwAWaNpF/QBvKAEPFWh6eR0AFmh2PjoA +bygBEhVodj46ABZodj46ADUIgW8oAQAWAQiBBEgBAAVowuvrJhZo+Eu5AG8oAQAuAAiBFWi6UWkA +Fmh2PjoAF2j4S7kAY0gBAGRoAAAAAGRoAAAAAGRowuvrJm8oAQAWAQiBBEgBAAVowevrJhZo+Eu5 +AG8oAQAuAAiBFWi6UWkAFmh2PjoAF2j4S7kAY0gBAGRoAAAAAGRoAAAAAGRowevrJm8oAQAPFWi6 +UWkAFmh2PjoAbygBCRZodj46AG8oAQ8VaPpCAwAWaHY+OgBvKAEMFmh2PjoANQiBbygBABIVaOxK +RwAWaOxKRwA1CIFvKAEACRZo7EpHAG8oAQkWaOx2zwBvKAEAJlhXAAA6WAAARFgAALxaAAC+WgAA +yFoAAGBbAADqWwAA7FsAAO5bAAD8WwAADlwAAOZcAAD4XAAAvF4AAL5eAADQXgAAPl8AAEBfAABc +XwAA1l8AANhfAAD0AAAAAAAAAAAAAAAA7AAAAAAAAAAAAAAAAPQAAAAAAAAAAAAAAADnAAAAAAAA +AAAAAAAA7AAAAAAAAAAAAAAAAPQAAAAAAAAAAAAAAAD0AAAAAAAAAAAAAAAA5wAAAAAAAAAAAAAA +AOcAAAAAAAAAAAAAAADfAAAAAAAAAAAAAAAA1wAAAAAAAAAAAAAAAMwAAAAAAAAAAAAAAADXAAAA +AAAAAAAAAAAAzAAAAAAAAAAAAAAAAMwAAAAAAAAAAAAAAADXAAAAAAAAAAAAAAAAwQAAAAAAAAAA +AAAAAMEAAAAAAAAAAAAAAAC2AAAAAAAAAAAAAAAAwQAAAAAAAAAAAAAAAMEAAAAAAAAAAAAAAAAA +AAAACgAAEYSmAVdEyABghKYBZ2T3BuUAAAoAABGEpAFXRMgAYISkAWdk9wblAAAKAAARhKQBV0TI +AGCEpAFnZANYpQAIAgAKJgELRhEAZ2TCGNAACAEACiYAC0YCAGdk+kIDAAAEAABnZHY+OgAIAgAK +JgELRgMAZ2R2PjoAAAoPAA+EqAFWRMoAXoSoAWdkdj46AAAVDFwAAA5cAADkXAAA5lwAAPZcAAD4 +XAAAvF4AAL5eAADQXgAAPl8AAEBfAABcXwAA1l8AANhfAAD8XwAAamAAAGxgAACOYAAAPGEAAD5h +AABYYQAAJmIAADxiAABgYgAAamIAAK5iAABgYwAAYmMAAIRjAACGYwAAkGMAAMxjAACEZAAAhmQA +AKhkAACqZAAA9/Dr49vW0cnRxbvRxbvRxbvRxbvR46+l1qDWl4uBfHdyZloAFhVoXmxoABZo3hmx +ADUIgWFKFQBvKAEAFhVoXmxoABZoXmxoADUIgWFKFQBvKAEACRZoxxZNAG8oAQkWaNs3swBvKAEJ +FmiyJu4AbygBEhVoXmxoABZoxxZNADUIgW8oAQAWFWjHFk0AFmjeGbEANQiBYUoVAG8oAQAQFmiy +Ju4ANQiBYUoVAG8oAQAJFmjeGbEAbygBEhVo3hmxABZoL0l+ADUIgW8oAQAWFWgvSX4AFmgvSX4A +NQiBYUoVAG8oAQASFWj3BuUAFmj3BuUANQiBbygBAAYWaPcG5QAADxVowhjQABZo9wblAG8oAQkW +aPcG5QBvKAEJFmgvSX4AbygBDxVowhjQABZoA1ilAG8oAQ8VaMIY0AAWaC9JfgBvKAEJFmjaRf0A +bygBDBVoA1ilABZoA1ilAAAPFWgDWKUAFmgDWKUAbygBACPYXwAA/F8AAGpgAABsYAAAjmAAADxh +AAA+YQAAWGEAACRiAAAmYgAAPGIAAGBiAABiYwAAhmMAAIZkAACqZAAAOmYAAGZmAACWZwAAmGcA +APQAAAAAAAAAAAAAAADpAAAAAAAAAAAAAAAA6QAAAAAAAAAAAAAAAPQAAAAAAAAAAAAAAADpAAAA +AAAAAAAAAAAA6QAAAAAAAAAAAAAAAPQAAAAAAAAAAAAAAADpAAAAAAAAAAAAAAAA3gAAAAAAAAAA +AAAAANYAAAAAAAAAAAAAAADMAAAAAAAAAAAAAAAAwQAAAAAAAAAAAAAAALcAAAAAAAAAAAAAAACs +AAAAAAAAAAAAAAAAtwAAAAAAAAAAAAAAAKwAAAAAAAAAAAAAAAC3AAAAAAAAAAAAAAAArAAAAAAA +AAAAAAAAAN4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAARhKYBV0TIAGCEpgFnZF5s +aAAKDwAKJgILRg0AV0QAAGdkjGY8AAAKAAARhKYBV0TIAGCEpgFnZN4ZsQAKDwAKJgILRg0AV0QA +AGdk9wblAAgCAAomAQtGEQBnZMIY0AAACgAAEYSkAVdEyABghKQBZ2QDWKUAAAoAABGEpAFXRMgA +YISkAWdk9wblAAAKAAARhKYBV0TIAGCEpgFnZPcG5QAAE6pkAACyZAAAOGYAADpmAABkZgAAZmYA +AHBmAACWZwAAmGcAAJxnAACgZwAApmcAANpnAADkZwAA8GcAADpoAABEaAAARmgAAEhoAABUaAAA +eGgAAHpoAAB8aAAAkGgAAKRoAAC6aAAA8GgAADxpAAA+aQAAQGkAAEppAAD28end0fbxzMS8xKyi +m5KbkoOiknx1bGBsVGx1T8QAAAAACRZocCy0AG8oARYVaIkEFQAWaIkEFQA1CIFLSAAAXAiBABYV +aE5wiwAWaIkEFQA1CIFLSAAAXAiBABAVaE5wiwAWaIkEFQBLSAAAAA0WaIkEFQBLSAAAbygBDRZo +cCy0AEtIAABvKAEcFmhwLLQANQiBQioGS0gAAFwIgW8oAXBo/0gAAAAQFWhOcIsAFmhwLLQAS0gA +AAANFmjkXUQAS0gAAG8oARMVaHAstAAWaHAstAA1CIFLSAAAHhVoiBXaABZoiBXaADUIgUNKHgBL +SAAAYUoeAG8oAQAPFWiOLdkAFmiOLdkAbygBDxVojGY8ABZo2kX9AG8oAQkWaC9JfgBvKAEWFWhe +bGgAFmjeGbEANQiBYUoVAG8oAQAWFWhebGgAFmhebGgANQiBYUoVAG8oAQAPFWhebGgAFmhebGgA +bygBCRZoXmxoAG8oARIVaF5saAAWaF5saAA1CIFvKAEemGcAAKZnAADaZwAASGgAAHpoAAB8aAAA +PmkAAEBpAABKaQAAXmkAAHppAAB+aQAAgGkAAIRpAACGaQAAimkAAIxpAACQaQAAkmkAAJRpAACW +aQAA9wAAAAAAAAAAAAAAAOsAAAAAAAAAAAAAAADaAAAAAAAAAAAAAAAA2gAAAAAAAAAAAAAAAMkA +AAAAAAAAAAAAAADJAAAAAAAAAAAAAAAAuAAAAAAAAAAAAAAAAPcAAAAAAAAAAAAAAACzAAAAAAAA +AAAAAAAA9wAAAAAAAAAAAAAAAK4AAAAAAAAAAAAAAACsAAAAAAAAAAAAAAAArgAAAAAAAAAAAAAA +AKwAAAAAAAAAAAAAAACuAAAAAAAAAAAAAAAArAAAAAAAAAAAAAAAAK4AAAAAAAAAAAAAAACsAAAA +AAAAAAAAAAAArAAAAAAAAAAAAAAAAPcAAAAAAAAAAAAAAAAAAQAAAAQAAGdkuV44AAAEAABnZNpF +/QAAEAAAD4QUBhGEzf1WRNkBV0T0/l6EFAZghM39Z2RwLLQAABAAAA+EeAIRhKQBVkQtAVdEyABe +hHgCYISkAWdkiQQVAAAQAAAPhBYGEYTL/VZE2QFXRPT+XoQWBmCEy/1nZHAstAAACwAAAyQBD4QC +AF6EAgBhJAFnZIgV2gAIAQAKJgALRgIAZ2SMZjwAABRKaQAAXGkAAF5pAABmaQAAaGkAAHhpAAB6 +aQAAfGkAAIBpAACCaQAAhmkAAIhpAACMaQAAjmkAAJRpAACWaQAA+vXt5fre1tLW0tbS1tLeAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGFmjR +MX0AAA8DagAAAAAWaNExfQBVCAEMFWiMZjwAFmjaRf0AAA8VaIxmPAAWaAh7AwBvKAEPFWiMZjwA +FmjaRf0AbygBCRZo2kX9AG8oAQkWaAh7AwBvKAEADzYAMZA4ATJQAgA6cMIfwAAfsIIuILDGQSGw +CAcisAgHI5CgBSSQoAUlsAAAF7BTAxiw4AMMkKkBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +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 +AAAAAAAAAAAAAAAAAAAAAGoEHAASAAEACwEPAAcAAwAEAAMAAAAEAAgAAACYAAAAngAAAJ4AAACe +AAAAngAAAJ4AAACeAAAAngAAAJ4AAAA2BgAANgYAADYGAAA2BgAANgYAADYGAAA2BgAANgYAADYG +AAB2AgAAdgIAAHYCAAB2AgAAdgIAAHYCAAB2AgAAdgIAAHYCAAA2BgAANgYAADYGAAA2BgAANgYA +ADYGAAA+AgAANgYAADYGAAA2BgAANgYAADYGAAA2BgAANgYAADYGAAA2BgAANgYAADYGAAA2BgAA +NgYAADYGAAA2BgAANgYAADYGAAA2BgAANgYAADYGAAA2BgAANgYAADYGAAA2BgAANgYAADYGAAA2 +BgAAqAAAADYGAAA2BgAAFgAAADYGAAA2BgAANgYAADYGAAA2BgAANgYAADYGAAA2BgAAuAAAADYG +AAA2BgAANgYAADYGAAA2BgAANgYAADYGAAA2BgAANgYAADYGAAA2BgAANgYAAGgBAABIAQAANgYA +ADYGAAA2BgAANgYAADYGAAA2BgAANgYAADYGAAA2BgAANgYAADYGAAA2BgAANgYAADYGAAA2BgAA +NgYAADYGAAA2BgAANgYAADYGAAA2BgAANgYAADYGAAA2BgAANgYAADYGAAA2BgAANgYAADYGAAA2 +BgAANgYAADYGAAA2BgAANgYAADYGAAA2BgAANgYAADYGAAA2BgAANgYAADYGAAA2BgAANgYAADYG +AAA2BgAANgYAADYGAAA2BgAANgYAADYGAAA2BgAANgYAADYGAAA2BgAANgYAADYGAAA2BgAANgYA +ADYGAAA2BgAANgYAADYGAAA2BgAANgYAADYGAACwAwAANgYAADIGAAAYAAAAwAMAANADAADgAwAA +8AMAAAAEAAAQBAAAIAQAADAEAABABAAAUAQAAGAEAABwBAAAgAQAAJAEAADAAwAA0AMAAOADAADw +AwAAAAQAABAEAAAyBgAAKAIAANgBAADoAQAAIAQAADAEAABABAAAUAQAAGAEAABwBAAAgAQAAJAE +AADAAwAA0AMAAOADAADwAwAAAAQAABAEAAAgBAAAMAQAAEAEAABQBAAAYAQAAHAEAACABAAAkAQA +AMADAADQAwAA4AMAAPADAAAABAAAEAQAACAEAAAwBAAAQAQAAFAEAABgBAAAcAQAAIAEAACQBAAA +wAMAANADAADgAwAA8AMAAAAEAAAQBAAAIAQAADAEAABABAAAUAQAAGAEAABwBAAAgAQAAJAEAADA +AwAA0AMAAOADAADwAwAAAAQAABAEAAAgBAAAMAQAAEAEAABQBAAAYAQAAHAEAACABAAAkAQAAMAD +AADQAwAA4AMAAPADAAAABAAAEAQAACAEAAAwBAAAQAQAAFAEAABgBAAAcAQAAIAEAACQBAAAOAEA +AFgBAAD4AQAACAIAABgCAABWAgAAfgIAACAAAABPSgMAUEoEAFFKAwBfSAEEbUgJBG5IBAhzSAkE +dEgECAAAAABKAABg8f8CAEoADBAAAMIfwAAAAAIAY2uHZQAACwAAAAMkAzEkAGEkAwAgAENKFQBL +SAIAX0gBBGFKFgBtSAkEbkgECHNICQR0SAQITgABQAEAAgBOAAwUEAD6QgMAkAAEAAdomJggADEA +AAAZAAEABSQBBiQBEmRCAgEAE6RUARSkSgFAJgAAEgA1CIFDSiwAS0gsAFwIgWFKLABaAAJAAQAC +AFoADBwSAPpCAwCQAAQAB2iYmCAAMgAAABkAAgAFJAEGJAESZKABAQATpAQBFKQEAUAmAQAeADUI +gUNKIABPSgUAUEoEAFFKBQBcCIFeSgAAYUogAAAAAAAAAAAAAAAAAAAAJABBYPL/oQAkAAwNAAAA +AAAAEAAGANiepIu1az2EV1tTTwAAAABCAGlA8/+zAEIADB0AAAAAAAAwBgQAbmYakGiIPGgAABwA +F/YDAAA01gYAAQoDbAA01gYAAQUDAABh9gMAAAIACwAAACAAayD0/8EAIAAADQAAAAAAADAGAwDg +ZRdSaIgAAAIADAAAAAAAMACzQAEA8gAwAAwUAADaRf0AIAIEABdS+lG1az2EAAAOAA8AEYSkAVdE +yABghKQBAAA8AP4PogABATwADAABAPpCAwCQAAkAB2iYmCAAMQAgAEMAaABhAHIAAAASADUIAUNK +LABLSCwAXAgBYUosAGgACkERAAIAaAAMGQAA+kIDAHACBgBUAE8AQwAgAAdomJgAABwAEQADJAAS +ZBQBAQATpOABFKQAADEkAUAmCWEkACUAQioHQ0ocAEtIAABPSgUAUEoEAFFKBQBeSgAAYUocAHBo +Nl+RAABMAP4PogAhAUwADAACAPpCAwCQAAkAB2iYmCAAMgAgAEMAaABhAHIAAAAiADUIAUNKIABL +SAIAT0oFAFBKBABRSgUAXAgBXkoAAGFKIAAkABNAAQACACQADQwAAI4t2QBwAgQA7nZVXyAAMQAA +AAIAEwAAADAAFEABAAIAMAANDAAAji3ZAHACBADudlVfIAAyAAAADgAUAA+EpAFWRMgAXoSkAQAA +KgBVQKIAUQEqAAwMAACOLdkAMAYDAIWN/pSlYwAADAA+KgFCKgdwaAAA/wBOAB8AAQBiAU4ADA0X +ALleOAAwBgIAdZgJdwAAJwAWAAMkAQ3GCAACORByIAECJmQGAQABRyQAUMYIAAAA/wYBAQBhJAEA +CABDShIAYUoSADIA/g+iAHEBMgAMARYAuV44ADAGBwB1mAl3IABDAGgAYQByAAAADABDShIAS0gC +AGFKEgA8ACAAAQCCATwADA0ZALleOAAwBgIAdZgagQAAFgAYAAMkAA3GCAACORByIAECRyQAYSQA +CABDShIAYUoSADIA/g+iAJEBMgAMARgAuV44ADAGBwB1mBqBIABDAGgAYQByAAAADABDShIAS0gC +AGFKEgAuAJkAAQCiAS4ADA0bAJMMdwAwBgUAeWLobEZoh2UsZwAAAgAaAAgAQ0oSAGFKEgA4AP4v +ogCxATgADAEaAJMMdwAwBgoAeWLobEZoh2UsZyAAQwBoAGEAcgAAAAwAQ0oSAEtIAgBhShIAUEsD +BBQABgAIAAAAIQCCirwT+gAAABwCAAATAAAAW0NvbnRlbnRfVHlwZXNdLnhtbKyRy2rDMBBF94X+ +g9C22HK6KKXYzqJJd30s0g8Y5LEtao+ENAnJ33fsuFC6CC10IxBizpl7Va6P46AOGJPzVOlVXmiF +ZH3jqKv0++4pu9cqMVADgyes9AmTXtfXV+XuFDApmaZU6Z45PBiTbI8jpNwHJHlpfRyB5Ro7E8B+ +QIfmtijujPXESJzxxNB1+SoLRNegeoPILzCKx7Cg8Pv5DCSAmAtYq8czYVqi0hDC4CywRDAHan7o +M9+2zmLj7X4UaT6DF9jNBDO/XGD1P+ov5wZb2A+stkfp4lx/xCH9LdtSay6Tc/7Uu5AuGC6Xt7Rh +5r+tPwEAAP//AwBQSwMEFAAGAAgAAAAhAKXWp+fAAAAANgEAAAsAAABfcmVscy8ucmVsc4SPz2rD +MAyH74W9g9F9UdLDGCV2L6WQQy+jfQDhKH9oIhvbG+vbT8cGCrsIhKTv96k9/q6L+eGU5yAWmqoG +w+JDP8to4XY9v3+CyYWkpyUIW3hwhqN727VfvFDRozzNMRulSLYwlRIPiNlPvFKuQmTRyRDSSkXb +NGIkf6eRcV/XH5ieGeA2TNP1FlLXN2Cuj6jJ/7PDMMyeT8F/ryzlRQRuN5RMaeRioagv41O9kKhl +qtQe0LW4+db9AQAA//8DAFBLAwQUAAYACAAAACEAa3mWFoMAAACKAAAAHAAAAHRoZW1lL3RoZW1l +L3RoZW1lTWFuYWdlci54bWwMzE0KwyAQQOF9oXeQ2TdjuyhFYrLLrrv2AEOcGkHHoNKf29fl44M3 +zt8U1ZtLDVksnAcNimXNLoi38Hwspxuo2kgcxSxs4ccV5ul4GMm0jRPfSchzUX0j1ZCFrbXdINa1 +K9Uh7yzdXrkkaj2LR1fo0/cp4kXrKyYKAjj9AQAA//8DAFBLAwQUAAYACAAAACEA6djl/p0GAABR +GwAAFgAAAHRoZW1lL3RoZW1lL3RoZW1lMS54bWzsWU1vG0UYviPxH0Z7b2MndhpHdarYsRto00ax +W9TjeD3enXp2ZzUzTuobao9ISIiCeqAS4sIBAZVaCSTKr0kpKkXqX+Cdmd31TrwmSRtBBU2kxDv7 +vN8f88744qU7EUP7REjK46ZXPV/xEIl9PqRx0PRu9Lvn1jwkFY6HmPGYNL0pkd6ljfffu4jXVUgi +goA+luu46YVKJetLS9KHZSzP84TE8G7ERYQVPIpgaSjwAfCN2NJypbK6FGEaeyjGEbC9PhpRn6Bn +P//y4psH3kbGvcNARKykXvCZ6GnexCEx2OG4qhFyKttMoH3Mmh4IGvKDPrmjPMSwVPCi6VXMj7e0 +cXEJr6dETC2gLdC1K/o3pUsJhuNlI1MEg1xotVtrXNjK+RsAU/O4TqfT7lRzfgaAfR8stboUeda6 +a9VWxrMAsh/nebcr9UrNxRf4r8zp3Gi1WvVGqotlakD2Y20Ov1ZZrW0uO3gDsvj6HL7W2my3Vx28 +AVn86hy+e6GxWnPxBhQyGo/n0Dqg3W7KPYeMONsuha8BfC0L5AwF2ZBnlxYx4rFalGsRvs1FFwAa +yLCiMVLThIywD2ncxtFAUKz1wesEF97YJV/OLWlZSPqCJqrpfZhgKIkZv1dPv3/19DE6vPvk8O5P +h/fuHd790TJyqLZxHBSpXn772Z8PP0Z/PP765f0vyvGyiP/th0+e/fp5ORDKZ6bO8y8f/f7k0fMH +n7747n4JfFPgQRHepxGR6Bo5QHs8AsOMV1zNyUCcjqIfYlqk2IwDiWOspZTw76jQQV+bYpZGx9Gj +RVwP3hTQPsqAlye3HYV7oZgoWiL5Shg5wB3OWYuLUi9c0bIKbu5P4qBcuJgUcXsY75fJbuPYiW9n +kkDfzNLSMbwdEkfNXYZjhQMSE4X0Oz4mpMS6W5Q6ft2hvuCSjxS6RVEL01KX9OnAyaYZ0TaNIC7T +Mpsh3o5vdm6iFmdlVm+RfRcJVYFZifJ9whw3XsYThaMyln0csaLDr2IVlinZmwq/iOtIBZEOCOOo +MyRSltFcF2BvIehXMHSs0rDvsGnkIoWi4zKeVzHnReQWH7dDHCVl2B6NwyL2AzmGFMVol6sy+A53 +K0Q/QxxwvDDcNylxwn18N7hBA0elWYLoNxOhYwmt2unAEY3/rh0zCv3Y5sDZtWNogM+/eliSWW9r +I96EPamsEraPtN9FuKNNt83FkL79PXcLT+JdAmk+v/G8a7nvWq73n2+5i+r5pI121luh7eq5wQ7F +ZkSOFk7II8pYT00ZuSrNkCxhnxh2YVHTmeMhyU9MSQgf077u4AKBDQ0SXH1EVdgLcQIDdtXTTAKZ +sg4kSriEg51ZLuWt8TCkK3ssrOsDg+0HEqsdPrTLK3o5OxfkbMxuE5jDZyZoRTM4qbCVCylTMPt1 +hFW1UieWVjWqmVbnSMtNhhjOmwaLuTdhAEEwtoCXV+GArkXDwQQzMtR+t3tvFhYThbMMkQzxkKQx +0nbPx6hqgpTlirkJgNwpiZE+5B3jtYK0hmb7BtJOEqSiuNoCcVn03iRKWQbPoqTr9kg5srhYnCxG +B02vUV+ue8jHSdMbwZkWPkYJRF3qmQ+zAG6GfCVs2h9bzKbKZ9FsZIa5RVCFawrr9zmDnT6QCKm2 +sAxtaphXaQqwWEuy+i/Xwa1nZYDN9NfQYmUNkuFf0wL86IaWjEbEV8VgF1a07+xj2kr5RBHRC4cH +aMAmYg9D+HWqgj1DKuFqwnQE/QD3aNrb5pXbnNOiK95eGZxdxywJcdpudYlmlWzhpo5zHcxTQT2w +rVR3Y9zpTTElf0amFNP4f2aK3k/gpmBlqCPgwz2uwEjXa9PjQoUculASUr8rYHAwvQOyBe5i4TUk +Fdwmm/+C7Ov/tuYsD1PWcOBTezRAgsJ+pEJByC60JZN9xzCrpnuXZclSRiajCurKxKo9IPuE9XUP +XNV7u4dCSHXTTdI2YHBH8899TitoEOghp1hvTg/J915bA//05GOLGYxy+7AZaDL/5yqW7KqW3pBn +e2/REP1iNmbVsqoAYYWtoJGW/WuqcMqt1nasOYuX65lyEMV5i2ExH4gSuO9B+g/sf1T4jJg01htq +n+9Bb0XwRYNmBmkDWX3ODh5IN0i7OIDByS7aZNKsrGvT0Ul7Ldusz3jSzeUecbbW7CTxPqWz8+HM +FefU4lk6O/Ww42u7ttDVENmjJQpLo+wgYwJjvtMqfuvEB7ch0Ftwvz9hSppkgu+UBIbRs2fqAIrf +SjSkG38BAAD//wMAUEsDBBQABgAIAAAAIQAN0ZCftgAAABsBAAAnAAAAdGhlbWUvdGhlbWUvX3Jl +bHMvdGhlbWVNYW5hZ2VyLnhtbC5yZWxzhI9NCsIwFIT3gncIb2/TuhCRJt2I0K3UA4TkNQ02PyRR +7O0NriwILodhvplpu5edyRNjMt4xaKoaCDrplXGawW247I5AUhZOidk7ZLBggo5vN+0VZ5FLKE0m +JFIoLjGYcg4nSpOc0IpU+YCuOKOPVuQio6ZByLvQSPd1faDxmwF8xSS9YhB71QAZllCa/7P9OBqJ +Zy8fFl3+UUFz2YUFKKLGzOAjm6pMBMpburrE3wAAAP//AwBQSwECLQAUAAYACAAAACEAgoq8E/oA +AAAcAgAAEwAAAAAAAAAAAAAAAAAAAAAAW0NvbnRlbnRfVHlwZXNdLnhtbFBLAQItABQABgAIAAAA +IQCl1qfnwAAAADYBAAALAAAAAAAAAAAAAAAAACsBAABfcmVscy8ucmVsc1BLAQItABQABgAIAAAA +IQBreZYWgwAAAIoAAAAcAAAAAAAAAAAAAAAAABQCAAB0aGVtZS90aGVtZS90aGVtZU1hbmFnZXIu +eG1sUEsBAi0AFAAGAAgAAAAhAOnY5f6dBgAAURsAABYAAAAAAAAAAAAAAAAA0QIAAHRoZW1lL3Ro +ZW1lL3RoZW1lMS54bWxQSwECLQAUAAYACAAAACEADdGQn7YAAAAbAQAAJwAAAAAAAAAAAAAAAACi +CQAAdGhlbWUvdGhlbWUvX3JlbHMvdGhlbWVNYW5hZ2VyLnhtbC5yZWxzUEsFBgAAAAAFAAUAXQEA +AJ0KAAAAADw/eG1sIHZlcnNpb249IjEuMCIgZW5jb2Rpbmc9IlVURi04IiBzdGFuZGFsb25lPSJ5 +ZXMiPz4NCjxhOmNsck1hcCB4bWxuczphPSJodHRwOi8vc2NoZW1hcy5vcGVueG1sZm9ybWF0cy5v +cmcvZHJhd2luZ21sLzIwMDYvbWFpbiIgYmcxPSJsdDEiIHR4MT0iZGsxIiBiZzI9Imx0MiIgdHgy +PSJkazIiIGFjY2VudDE9ImFjY2VudDEiIGFjY2VudDI9ImFjY2VudDIiIGFjY2VudDM9ImFjY2Vu +dDMiIGFjY2VudDQ9ImFjY2VudDQiIGFjY2VudDU9ImFjY2VudDUiIGFjY2VudDY9ImFjY2VudDYi +IGhsaW5rPSJobGluayIgZm9sSGxpbms9ImZvbEhsaW5rIi8+AAAAAModAAAOAACkAAAAAP////8A +AAAAAwAAAAYAAAAGAAAACQAAAAwAAAAMAAAADAAAAAwAAAAMAAAADAAAAAwAAAAMAAAADwAAAAAI +AADqCAAAKAoAAG4LAACgDAAAyg0AAP4OAAA6EAAAchEAAKQSAADCFQAAECAAACYkAAAwJQAACkwA +AIxOAACQTwAABFEAANRSAAA0VAAAzFYAAAxcAACqZAAASmkAAJZpAAATAAAAFQAAABYAAAAXAAAA +GAAAABkAAAAaAAAAGwAAABwAAAAdAAAAHwAAACEAAAAjAAAAJQAAADUAAAA3AAAAOAAAADkAAABC +AAAASQAAAEsAAABNAAAATwAAAFEAAAAACAAAvBIAAOoZAACmIAAAKCQAADZOAACEUQAArFEAAM5R +AAACUgAALFIAAFJSAAB8UgAA0lIAAAJTAABCUwAAXFMAAHhTAACQUwAApFMAALJUAABYVwAA2F8A +AJhnAACWaQAAFAAAAB4AAAAgAAAAIgAAACQAAAA2AAAAOgAAADsAAAA8AAAAPQAAAD4AAAA/AAAA +QAAAAEEAAABDAAAARAAAAEUAAABGAAAARwAAAEgAAABKAAAATAAAAE4AAABQAAAAEgAAACoAAAAr +AAAASwAAAFMAAABvAAAAcQAAAHIAAAB0AAAAlAAAAKAAAAC8AAAAvgAAAL8AAADBAAAA4QAAAPMA +AAAPAQAAEQEAABIBAAAUAQAANAEAAEUBAABhAQAAYwEAAGQBAABmAQAAhgEAAJcBAACzAQAAtQEA +ALYBAAC4AQAA2AEAAOcBAAADAgAABQIAAAYCAAAIAgAAKAIAADICAABOAgAAUAIAAFECAABTAgAA +cwIAAH0CAACZAgAAmwIAAJwCAACeAgAAvgIAAMgCAADkAgAA5gIAAOcCAADpAgAACQMAABMDAAAv +AwAAMQMAADIDAAA0AwAAVAMAAGIDAAB+AwAAgAMAAIEDAACDAwAAowMAALEDAADNAwAAzwMAANAD +AADSAwAA8gMAAAAEAAAcBAAAHgQAAB8EAAAhBAAAQQQAAFEEAABtBAAAbwQAAHAEAAByBAAAkgQA +AJwEAAC4BAAAugQAALsEAAC9BAAA3QQAAOUEAAABBQAAAwUAAAQFAAAGBQAAJgUAADcFAABTBQAA +VQUAAFYFAABYBQAAyh0AABMNlP8TWJT/EyXU/5XAlcwTWJT/EyXU/5XAlcwTWJT/EyXU/5XAlcwT +WJT/EyXU/5XAlcwTWJT/EyXU/5XAlcwTWJT/EyXU/5XAlcwTWJT/EyXU/5XAlcwTWJT/EyXU/5XA +lcwTWJT/EyXU/5XAlcwTWJT/EyXU/5XAlcwTWJT/EyXU/5XAlcwTWJT/EyXU/5XAlcwTWJT/EyXU +/5XAlcwTWJT/EyXU/5XAlcwTWJT/EyXU/5XAlcwTWJT/EyXU/5XAlcwTWJT/EyXU/5XAlcyVjA8A +APBAAAAAAAAG8CAAAAACDAAAAwAAAAIAAAACAAAAAgAAAAIAAAABAAAAAQAAAEAAHvEQAAAA//8A +AAAA/wCAgIAA9wAAEAAPAALwkgAAACAACPAIAAAAAQAAAAEEAAAPAAPwMAAAAA8ABPAoAAAAAQAJ +8BAAAAAAAAAAAAAAAAAAAAAAAAAAAgAK8AgAAAAABAAABQAAAA8ABPBCAAAAEgAK8AgAAAABBAAA +AA4AAFMAC/AeAAAAvwEAABAAywEAAAAA/wEAAAgABAMJAAAAPwMBAAEAAAAR8AQAAAABAAAAAQ8A +AvBIAAAAEAAI8AgAAAABAAAAAAgAAA8AA/AwAAAADwAE8CgAAAABAAnwEAAAAAAAAAAAAAAAAAAA +AAAAAAACAArwCAAAAAAIAAAFAAAA//9FAAAADQBfAFQAbwBjADIANwA4ADUANAAwADQAMAAzAA0A +XwBUAG8AYwAyADcAOAA1ADQAMAA0ADcAMwANAF8AVABvAGMAMgA3ADgANQA1ADUAMAAwADYADQBf +AFQAbwBjADIANwA4ADUANQA1ADEAMQA4AA0AXwBUAG8AYwAyADcAOAA1ADUANQAyADEANwANAF8A +VABvAGMAMgA3ADgANQA0ADAANAAwADgADQBfAFQAbwBjADIANwA4ADUANAAwADQANwA4AA0AXwBU +AG8AYwAyADcAOAA1ADUANQAwADAANwANAF8AVABvAGMAMgA3ADgANQA1ADUAMQAxADkADQBfAFQA +bwBjADIANwA4ADUANQA1ADIAMQA4AA0AXwBUAG8AYwAyADcAOAA1ADQAMAA0ADAAOQANAF8AVABv +AGMAMgA3ADgANQA0ADAANAA3ADkADQBfAFQAbwBjADIANwA4ADUANQA1ADAAMAA4AA0AXwBUAG8A +YwAyADcAOAA1ADUANQAxADIAMAANAF8AVABvAGMAMgA3ADgANQA1ADUAMgAxADkADQBfAFQAbwBj +ADIANwA4ADUANAAwADQAMQAwAA0AXwBUAG8AYwAyADcAOAA1ADQAMAA0ADgAMAANAF8AVABvAGMA +MgA3ADgANQA1ADUAMAAwADkADQBfAFQAbwBjADIANwA4ADUANQA1ADEAMgAxAA0AXwBUAG8AYwAy +ADcAOAA1ADUANQAyADIAMAANAF8AVABvAGMAMgA3ADgANQA0ADAANAAxADEADQBfAFQAbwBjADIA +NwA4ADUANAAwADQAOAAxAA0AXwBUAG8AYwAyADcAOAA1ADUANQAwADEAMAANAF8AVABvAGMAMgA3 +ADgANQA1ADUAMQAyADIADQBfAFQAbwBjADIANwA4ADUANQA1ADIAMgAxAA0AXwBUAG8AYwAyADcA +OAA1ADQAMAA0ADAANAANAF8AVABvAGMAMgA3ADgANQA0ADAANAA3ADQADQBfAFQAbwBjADIANwA4 +ADUANQA1ADAAMQAxAA0AXwBUAG8AYwAyADcAOAA1ADUANQAxADIAMwANAF8AVABvAGMAMgA3ADgA +NQA1ADUAMgAyADIADQBfAFQAbwBjADIANwA4ADUANAAwADQAMAA1AA0AXwBUAG8AYwAyADcAOAA1 +ADQAMAA0ADcANQANAF8AVABvAGMAMgA3ADgANQA1ADUAMAAxADIADQBfAFQAbwBjADIANwA4ADUA +NQA1ADEAMgA0AA0AXwBUAG8AYwAyADcAOAA1ADUANQAyADIAMwANAF8AVABvAGMAMgA3ADgANQA0 +ADAANAAwADYADQBfAFQAbwBjADIANwA4ADUANAAwADQANwA2AA0AXwBUAG8AYwAyADcAOAA1ADUA +NQAwADEAMwANAF8AVABvAGMAMgA3ADgANQA1ADUAMQAyADUADQBfAFQAbwBjADIANwA4ADUANQA1 +ADIAMgA0AA0AXwBUAG8AYwAyADcAOAA1ADQAMAA0ADAANwANAF8AVABvAGMAMgA3ADgANQA0ADAA +NAA3ADcADQBfAFQAbwBjADIANwA4ADUANQA1ADAAMQA0AA0AXwBUAG8AYwAyADcAOAA1ADUANQAx +ADIANgANAF8AVABvAGMAMgA3ADgANQA1ADUAMgAyADUADQBfAFQAbwBjADIANwA4ADUANAAwADQA +MQAyAA0AXwBUAG8AYwAyADcAOAA1ADQAMAA0ADgAMgANAF8AVABvAGMAMgA3ADgANQA1ADUAMAAx +ADUADQBfAFQAbwBjADIANwA4ADUANQA1ADEAMgA3AA0AXwBUAG8AYwAyADcAOAA1ADUANQAyADIA +NgANAF8AVABvAGMAMgA3ADgANQA1ADUAMgAyADcADQBfAFQAbwBjADIANwA4ADUANQA1ADIAMgA4 +AA0AXwBUAG8AYwAyADcAOAA1ADUANQAyADIAOQANAF8AVABvAGMAMgA3ADgANQA1ADUAMgAzADAA +DQBfAFQAbwBjADIANwA4ADUANAAwADQAMQAzAA0AXwBUAG8AYwAyADcAOAA1ADQAMAA0ADgAMwAN +AF8AVABvAGMAMgA3ADgANQA1ADUAMAAxADYADQBfAFQAbwBjADIANwA4ADUANQA1ADEAMgA4AA0A +XwBUAG8AYwAyADcAOAA1ADUANQAyADMAMQANAF8AVABvAGMAMgA3ADgANQA0ADAANAAxADYADQBf +AFQAbwBjADIANwA4ADUANAAwADQAOAA1AA0AXwBUAG8AYwAyADcAOAA1ADUANQAwADEAOAANAF8A +VABvAGMAMgA3ADgANQA1ADUAMQAyADkADQBfAFQAbwBjADIANwA4ADUANQA1ADIAMwAyAA0AXwBU +AG8AYwAyADcAOAA1ADQAMAA0ADEANwANAF8AVABvAGMAMgA3ADgANQA0ADAANAA4ADYADQBfAFQA +bwBjADIANwA4ADUANQA1ADAAMQA5AA0AXwBUAG8AYwAyADcAOAA1ADUANQAxADMAMAANAF8AVABv +AGMAMgA3ADgANQA1ADUAMgAzADMAXgUAAF4FAABeBQAAXgUAAF4FAAAEBwAABAcAAAQHAAAEBwAA +BAcAAA4HAAAOBwAADgcAAA4HAAAOBwAAXQ0AAF0NAABdDQAAXQ0AAF0NAABwEwAAcBMAAHATAABw +EwAAcBMAAJoUAACaFAAAmhQAAJoUAACaFAAAphQAAKYUAACmFAAAphQAAKYUAAAcFQAAHBUAABwV +AAAcFQAAHBUAAF4WAABeFgAAXhYAAF4WAABeFgAA9hYAAPYWAAD2FgAA9hYAAPYWAAD9FgAAchcA +AF4YAAASGgAAyxwAAMscAADLHAAAyxwAAMscAACfHQAAnx0AAJ8dAACfHQAAnx0AAK4dAACuHQAA +rh0AAK4dAACuHQAAyx0AAAAAAAABAAAAAgAAAAMAAAAEAAAABQAAAAYAAAAHAAAACAAAAAkAAAAK +AAAACwAAAAwAAAANAAAADgAAAA8AAAAQAAAAEQAAABIAAAATAAAAFAAAABUAAAAWAAAAFwAAABgA +AAAZAAAAGgAAABsAAAAcAAAAHQAAAB4AAAAfAAAAIAAAACEAAAAiAAAAIwAAACQAAAAlAAAAJgAA +ACcAAAAoAAAAKQAAACoAAAArAAAALAAAAC0AAAAuAAAALwAAADAAAAAxAAAAMgAAADMAAAA0AAAA +NQAAADYAAAA3AAAAOAAAADkAAAA6AAAAOwAAADwAAAA9AAAAPgAAAD8AAABAAAAAQQAAAEIAAABD +AAAARAAAAGIFAABiBQAAYgUAAGIFAABiBQAADAcAAAwHAAAMBwAADAcAAAwHAAAaBwAAGgcAABoH +AAAaBwAAGgcAAGgNAABoDQAAaA0AAGgNAABoDQAAexMAAHsTAAB7EwAAexMAAHsTAAClFAAApRQA +AKUUAAClFAAApRQAAKoUAACqFAAAqhQAAKoUAACqFAAAIBUAACAVAAAgFQAAIBUAACAVAABiFgAA +YhYAAGIWAABiFgAAYhYAAPwWAAD8FgAA/BYAAPwWAAD8FgAABRcAAHoXAABmGAAAHBoAANEcAADR +HAAA0RwAANEcAADRHAAAox0AAKMdAACjHQAAox0AAKMdAAC7HQAAux0AALsdAAC7HQAAux0AAMsd +AAAAAAAACQAAAAoAAAALAAAADgAAAA8AAABeBQAAYgUAAGMFAAB1BQAAeAUAAH8FAACFBQAAhgUA +AIcFAACMBQAArwUAALEFAAD3BQAAUgYAAFoGAABoBgAAawYAAHkGAADmBgAA5wYAAOgGAAD/BgAA +BAcAAAwHAAAOBwAAGgcAABsHAAAfBwAAIAcAAI8HAADLBwAA2gcAANsHAAABCAAABQgAABMIAAAV +CAAAJQgAACgIAAAtCAAALwgAADcIAAA4CAAAcAgAAHIIAAB8CAAAfQgAAJYIAACXCAAA5AgAAOcI +AADuCAAA7wgAAPMIAAD1CAAA+QgAAPoIAAAhCQAAJQkAACsJAAAzCQAAdAkAAHcJAACBCQAAggkA +AJIJAACiCQAApAkAALkJAADFCQAAyQkAAOgJAADrCQAAAgoAAAQKAAARCgAAEgoAADQKAAA3CgAA +RwoAAEoKAABjCgAAZgoAAGcKAABrCgAAbgoAAHIKAACCCgAAhgoAAJwKAACdCgAA2AoAACELAAAs +CwAALQsAAGYLAABnCwAAhAsAAIYLAACcCwAAngsAAJ8LAACiCwAAzwsAANELAADaCwAA2wsAAOUL +AAAKDAAAEAwAABEMAAATDAAAUwwAAFkMAABaDAAAYAwAAGUMAABmDAAAbAwAAKAMAAChDAAAogwA +AKQMAACwDAAAsgwAALQMAAC5DAAA7wwAAPEMAADzDAAA+AwAAAANAAAXDQAAGA0AABoNAAAqDQAA +YA0AAGgNAABpDQAAuQ0AAMQNAADKDQAAyw0AAO0NAADvDQAA8w0AAP4NAAAADgAAFA4AABoOAAAc +DgAAHw4AACcOAAAwDgAAQQ4AAEoOAAB+DgAAgw4AABsQAAAjEAAAJBAAAC0QAABVEAAAVhAAAF8Q +AABiEAAAaRAAAHEQAAByEAAAhRAAAJsQAACjEAAApBAAAKgQAAC+EAAAvxAAAMcQAADVEAAABBEA +AAwRAAANEQAAJhEAADQRAAA/EQAAQBEAAE8RAABQEQAAYxEAAKIRAACjEQAAwhEAAMYRAADOEQAA +1BEAANsRAADgEQAA5xEAAOkRAADqEQAA7xEAAPIRAAD4EQAAARIAAAYSAAAOEgAAFBIAABwSAAAg +EgAAKRIAAC0SAAA3EgAAPBIAAEASAABEEgAASBIAAFMSAABUEgAAVhIAAGkSAABsEgAAdhIAAH8S +AACNEgAAjxIAAJASAACXEgAApBIAAKYSAACuEgAAtBIAALwSAADEEgAA0xIAANQSAADZEgAA2hIA +AO4SAADvEgAA+BIAAPkSAAAAEwAAARMAAAsTAAAMEwAAGhMAABsTAAAlEwAALBMAAEcTAABMEwAA +TRMAAE4TAABYEwAAWRMAAGYTAABnEwAAcBMAAHsTAAB8EwAA2xMAACUUAAAtFAAALhQAADIUAABM +FAAAUBQAAFEUAABSFAAAUxQAAFQUAABWFAAAXhQAAF8UAABgFAAAahQAAGsUAAB4FAAAeRQAAIMU +AACEFAAAjhQAAI8UAACdFAAApRQAAKsUAACvFAAAFBUAABsVAAAhFQAAKxUAAKgVAACpFQAAtBUA +ANcVAAAFFgAAXBYAAGMWAACiFgAAoxYAAKQWAACmFgAArhYAAPYWAAD8FgAA/RYAAAUXAAAGFwAA +EhcAABUXAABSFwAAVRcAAHEXAAByFwAAehcAAHsXAACOFwAAvhcAAM8XAADZFwAAXBgAAF4YAABh +GAAAZxgAAJ0YAACgGAAArBgAAOwYAAD2GAAA9xgAAPgYAAD6GAAA/BgAABwZAAAfGQAAIhkAAC4Z +AAAwGQAAMxkAADYZAABFGQAASBkAAGEZAACZGQAAnBkAAJ8ZAACqGQAAqxkAAMYZAADKGQAA4xkA +AOYZAAAQGgAAEhoAABwaAAAdGgAAIBoAAC8aAAA0GgAAsBoAALMaAADCGgAAxxoAAEIbAABFGwAA +VBsAAFobAAAOHAAADxwAABEcAAAVHAAAGBwAABscAAAcHAAAIBwAADIcAAA8HAAAPxwAAEIcAACk +HAAAwxwAAMYcAADJHAAAyxwAAM0cAADSHAAA6xwAAO4cAADwHAAA8RwAAPccAAAmHQAAKB0AACkd +AAA7HQAAPh0AAEcdAABSHQAAWx0AAHgdAACNHQAAnx0AAKMdAAClHQAArB0AAK4dAACyHQAAuR0A +ALodAAC8HQAAvB0AAL4dAAC+HQAAvx0AAL8dAADBHQAAwh0AAMQdAADFHQAAxx0AAMgdAADLHQAA +BQAHAAUABwAFAAcABQAHAAUABwAFAAcABQAHAAUABwAFAAcABQAHAAUABwAFAAcABQAHAAUABwAF +AAcABQAHAAUABwAFAAcABQAHAAUABwAFAAcABQAHAAUABwAFAAcABQAHAAUABwAFAAcABQAHAAUA +BwAFAAcABQAHAAUABwAFAAcABQAHAAUABwAFAAcABQAHAAUABwAFAAcABQAHAAUABwAFAAcABQAH +AAUABwAFAAcABQAHAAUABwAFAAcABQAHAAUABwAFAAcABQAHAAUABwAFAAcABQAHAAUABwAFAAcA +BQAHAAUABwAFAAcABQAHAAUAHAAFAAcABQAHAAUABwAFAAcABQAHAAUABwAFAAcABQAHAAUABwAF +AAcABQAHAAUABwAFAAcABQAHAAUABwAFAAcABQAHAAUABwAFAAcABQAHAAUABwAFAAcABQAHAAUA +BwAFAAcABQAHAAUABwAFAAcABQAHAAUABwAFAAcABQAHAAUABwAFAAcABQAHAAUABwAFAAcABQAH +AAUABwAFAAcABQAHAAUABwAFAAcABQAHAAUABwAFAAcABQAHAAUABwAFAAcABQAHAAUABwAFAAcA +BQAHAAUABwAFAAcABQAHAAUABwAFAAcABQAHAAUABwAFAAcABQAHAAUABwAFAAcAHAAHAAUABwAF +AAcABQAHAAUABwAFAAcABQAHAAUABwAFAAcABQAHAAUABwAFAAcABQAHAAUABwAFAAcABQAHAAUA +BwAFAAcABQAHAAUABwAFAAcABQAHAAUABwAFAAcABQAHAAUABwAFAAcABQAHAAUABwAFAAcABQAH +AAUABwAFAAcABQAHAAUABwAFAAcABQAHAAUABwAFAAcABQAHAAUABwAFAAcABQAHAAUABwAFAAcA +BQAHAAUABwAFAAcABQAHAAUABwAFAAcABQAHAAUABwAFAAcABQAHAAUABwAFAAcABQAHAAUABwAF +AAcABQAHAAUABwAFAAcABQAHAAUABwAFAAcABQAHAAUABwAFAAcABQAHAAUABwAFAAcABQAHAAUA +BwAFAAcABQAHAAUABwAFAAcABQAHAAUABwAFAAcABAAHAAQAAgAEAAcABAAHAAQABwAEAAIAAAAA +ADsGAAA+BgAARAYAAEUGAABbBgAAXgYAAIQHAACHBwAA7gcAAPQHAABoCQAAawkAALILAACzCwAA +NgwAADwMAADEDAAAyQwAAB8OAAAiDgAAUBEAAFQRAABYEQAAWxEAAKQRAACoEQAANxIAADoSAABZ +EwAAXBMAAG8UAAByFAAAiRQAAI0UAAD3FAAA+hQAADsWAAA/FgAAuxYAAMAWAAC4FwAAuxcAAPoX +AAD9FwAAKRgAACwYAAArGQAALhkAAB0aAAAgGgAANBoAADcaAACUGgAAmRoAAC4bAAAxGwAAQhsA +AEUbAABZGwAAXhsAAPEbAAD3GwAACBwAAA0cAAB2HAAAdxwAAJgcAACZHAAAUR0AAFIdAABbHQAA +XB0AAHcdAAB4HQAApR0AAKgdAAC8HQAAvB0AAL4dAAC+HQAAvx0AAL8dAADBHQAAwh0AAMQdAADF +HQAAxx0AAMgdAADLHQAABwAzAAcAcwAHADMABwAzAAcAMwAHADMABwBzAAcAMwAHADMABwAzAAcA +MwAHADMABwAzAAcAMwAHADMABwAzAAcAMwAHADMABwAzAAcAMwAHADMABwAzAAcAMwAHADMABwAz +AAcAMwAHADMABwAzAAcAMwAHADMABwAzAAcAMwAHAHMABwBzAAcAcwAHAHMABwBzAAcAMwAHAAQA +BwAEAAIABAAHAAQABwAEAAcABAACAAAAAAAKAAAAEgAAAF4FAABjBQAABAcAAA4HAAAvCAAAOAgA +AHIIAAB9CAAA9QgAAPoIAADRCwAA2wsAAAoMAAARDAAAUwwAAFoMAACyDAAAuQwAAPEMAAD4DAAA +xA0AAMsNAAAUDgAAJQ4AADkPAABKDwAAXw8AAGoPAACCDwAAiQ8AAOsPAADyDwAAGxAAACMQAABp +EAAAcRAAAJsQAACjEAAAvhAAAMcQAAAEEQAADBEAAKIRAABFEgAAaRIAAIESAACNEgAA0hIAAO4S +AAD4EgAAGhMAAE0TAABmEwAAcBMAACUUAAAuFAAATBQAAFEUAABfFAAAahQAAKYUAACrFAAAHBUA +ACEVAABeFgAAYxYAAPYWAAD9FgAAQRcAAIYXAABeGAAAZxgAABIaAAAdGgAAsBoAAMIaAADLHAAA +0hwAAJ8dAACuHQAAvB0AALwdAAC+HQAAvh0AAL8dAAC/HQAAwR0AAMIdAADEHQAAxR0AAMcdAADI +HQAAyx0AAAcABQAHAAUABwAFAAcABQAHAAUABwAFAAcABQAHAAUABwAFAAcABQAHAAUABwAFAAcA +BQAHAAUABwAFAAcABQAHAAUABwAFAAcABQAHAAUABwAFAAcABQAHAAUABwAFAAcABQAHAAUABwAF +AAcABQAHAAUABwAFAAcABQAHAAUABwAFAAcABQAHAAUABwAFAAcABQAHAAUABwAFAAcABQAHAAUA +BwAEAAcABAACAAQABwAEAAcABAAHAAQAAgAAAAAA7xIAAO8SAAAbEwAATBMAAJkVAACoFQAArRUA +AK8VAADXFQAA2xUAALsdAADLHQAAAwAEAAMABAADAAQAAwAEAAMABAADAAcAEQBBJg4Q5K3Wkv8P +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 +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAD+/wAABQECAAAAAAAAAAAAAAAAAAAAAAABAAAA4IWf8vlPaBCrkQgA +Kyez2TAAAABUAQAAEAAAAAEAAACIAAAAAgAAAJAAAAADAAAAnAAAAAQAAACoAAAABQAAALgAAAAH +AAAAxAAAAAgAAADYAAAACQAAAOQAAAASAAAA8AAAAAoAAAAQAQAADAAAABwBAAANAAAAKAEAAA4A +AAA0AQAADwAAADwBAAAQAAAARAEAABMAAABMAQAAAgAAAKgDAAAeAAAABAAAAAAAAAAeAAAABAAA +AAAAAAAeAAAACAAAAExvbmcAAAAAHgAAAAQAAAAAAAAAHgAAAAwAAABOb3JtYWwuZG90bQAeAAAA +BAAAAHpzeAAeAAAABAAAADc3AAAeAAAAGAAAAE1pY3Jvc29mdCBPZmZpY2UgV29yZAAAAEAAAAAA +miuuQAAAAEAAAAAAXmD6Co3LAUAAAAAAfIXgk4/LAQMAAAAJAAAAAwAAAHAEAAADAAAATBkAAAMA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAA/v8AAAUBAgAAAAAAAAAAAAAAAAAAAAAAAgAAAALVzdWcLhsQk5cIACss+a5EAAAA +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 +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAEAAAACAAAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAACQAAAAoAAAALAAAADAAAAA0AAAAOAAAA +DwAAABAAAAARAAAAEgAAABMAAAAUAAAAFQAAABYAAAAXAAAAGAAAABkAAAAaAAAAGwAAABwAAAAd +AAAAHgAAAB8AAAAgAAAAIQAAACIAAAAjAAAAJAAAACUAAAAmAAAAJwAAACgAAAApAAAAKgAAACsA +AAAsAAAALQAAAC4AAAAvAAAAMAAAADEAAAAyAAAAMwAAADQAAAA1AAAANgAAADcAAAA4AAAAOQAA +ADoAAAA7AAAAPAAAAD0AAAA+AAAAPwAAAEAAAABBAAAAQgAAAEMAAABEAAAARQAAAEYAAABHAAAA +SAAAAEkAAABKAAAASwAAAEwAAABNAAAATgAAAE8AAABQAAAAUQAAAFIAAAD+////VAAAAFUAAABW +AAAAVwAAAFgAAABZAAAAWgAAAFsAAABcAAAAXQAAAF4AAABfAAAAYAAAAP7///9iAAAAYwAAAGQA +AABlAAAAZgAAAGcAAABoAAAAaQAAAGoAAABrAAAAbAAAAG0AAABuAAAAbwAAAHAAAABxAAAAcgAA +AHMAAAB0AAAAdQAAAHYAAAB3AAAAeAAAAHkAAAB6AAAAewAAAHwAAAB9AAAAfgAAAH8AAACAAAAA +gQAAAIIAAACDAAAAhAAAAIUAAACGAAAAhwAAAIgAAACJAAAAigAAAIsAAACMAAAAjQAAAI4AAACP +AAAAkAAAAJEAAACSAAAAkwAAAJQAAACVAAAAlgAAAJcAAACYAAAA/v///5oAAACbAAAAnAAAAJ0A +AACeAAAAnwAAAKAAAAD+////ogAAAKMAAACkAAAApQAAAKYAAACnAAAAqAAAAP7////9/////f// +/6wAAACtAAAA/v////7///+wAAAA/v////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////9S +AG8AbwB0ACAARQBuAHQAcgB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAFgAFAf//////////AwAAAAYJAgAAAAAAwAAAAAAAAEYAAAAAAAAAAAAAAABgQsABlI/L +Aa8AAAAAAwAAAAAAAEQAYQB0AGEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAKAAIB////////////////AAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAUwAAAMYaAAAAAAAAMQBUAGEAYgBsAGUAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4AAgABAAAA//////////8AAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABhAAAAM24AAAAAAABXAG8AcgBkAEQAbwBjAHUA +bQBlAG4AdAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGgACAQoAAAAF +AAAA/////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4pAAAAAAAAAUA +UwB1AG0AbQBhAHIAeQBJAG4AZgBvAHIAbQBhAHQAaQBvAG4AAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAoAAIB////////////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +mQAAAAAQAAAAAAAABQBEAG8AYwB1AG0AZQBuAHQAUwB1AG0AbQBhAHIAeQBJAG4AZgBvAHIAbQBh +AHQAaQBvAG4AAAAAAAAAAAAAADgAAgEEAAAA//////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAChAAAAABAAAAAAAABNAHMAbwBEAGEAdABhAFMAdABvAHIAZQAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGgABAP//////////BwAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAA0H+QAZSPywFwpbYBlI/LAQAAAAAAAAAAAAAAANcA3wBBAEEAWQBLAE0AzwDJ +AMQAwgDJAM8AUwDPAMMA0ADdAN0AWQDGAEEAPQA9AAAAAAAAAAAAAAAAAAAAAAAyAAEB//////// +//8IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADQf5ABlI/LAXCltgGUj8sBAAAAAAAAAAAAAAAASQB0 +AGUAbQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAoAAgH/////CQAAAP////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAA2gAAAAAAAABQAHIAbwBwAGUAcgB0AGkAZQBzAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAFgACAP///////////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAQAAABVAQAAAAAAAAEAQwBvAG0AcABPAGIAagAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASAAIBAgAAAAYAAAD/////AAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAHUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////// +//////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAA +AgAAAAMAAAD+////BQAAAAYAAAAHAAAACAAAAAkAAAD+////CwAAAP7///////////////////// +//////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////zxiOlNv +dXJjZXMgU2VsZWN0ZWRTdHlsZT0iXEFQQS5YU0wiIFN0eWxlTmFtZT0iQVBBIiB4bWxuczpiPSJo +dHRwOi8vc2NoZW1hcy5vcGVueG1sZm9ybWF0cy5vcmcvb2ZmaWNlRG9jdW1lbnQvMjAwNi9iaWJs +aW9ncmFwaHkiIHhtbG5zPSJodHRwOi8vc2NoZW1hcy5vcGVueG1sZm9ybWF0cy5vcmcvb2ZmaWNl +RG9jdW1lbnQvMjAwNi9iaWJsaW9ncmFwaHkiPjwvYjpTb3VyY2VzPg0KAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8P3htbCB2ZXJzaW9uPSIxLjAiIGVuY29kaW5nPSJVVEYt +OCIgc3RhbmRhbG9uZT0ibm8iPz4NCjxkczpkYXRhc3RvcmVJdGVtIGRzOml0ZW1JRD0iezYwMDBG +MERGLTJGQTMtNDhBNi1BOUJELTJCRTNDM0RGNTg5OH0iIHhtbG5zOmRzPSJodHRwOi8vc2NoZW1h +cy5vcGVueG1sZm9ybWF0cy5vcmcvb2ZmaWNlRG9jdW1lbnQvMjAwNi9jdXN0b21YbWwiPjxkczpz +Y2hlbWFSZWZzPjxkczpzY2hlbWFSZWYgZHM6dXJpPSJodHRwOi8vc2NoZW1hcy5vcGVueG1sZm9y +bWF0cy5vcmcvb2ZmaWNlRG9jdW1lbnQvMjAwNi9iaWJsaW9ncmFwaHkiLz48L2RzOnNjaGVtYVJl +ZnM+PC9kczpkYXRhc3RvcmVJdGVtPgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAABAP7/AwoAAP////8GCQIAAAAAAMAAAAAAAABGIwAAAE1pY3Jvc29mdCBPZmZpY2Ug +V29yZCA5Ny0yMDAzIM7EtbUACgAAAE1TV29yZERvYwAQAAAAV29yZC5Eb2N1bWVudC44APQ5snEA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= + +--=====001_Dragon322738684085_=====-- + + diff --git a/lib_acl_cpp/samples/mime/utf.eml b/lib_acl_cpp/samples/mime/utf.eml new file mode 100644 index 000000000..d69c995f1 --- /dev/null +++ b/lib_acl_cpp/samples/mime/utf.eml @@ -0,0 +1,77 @@ +Return-Path: +Delivered-To: zhengshuxin@51iker.com +Received: from mail.banmau.com (localhost.localdomain [127.0.0.1]) + by mail.banmau.com (banmau mail for UNIX) with ESMTP id 3FD1FBE0002 + for ; Fri, 25 May 2012 10:37:45 +0800 (CST) +Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) + by mail.banmau.com (banmau mail for UNIX) with SMTP id EB7DEBE0001 + for ; Fri, 25 May 2012 10:37:44 +0800 (CST) +BANMAU-SPAM-Result: Innocent +BANMAU-SPAM-Processed: Fri May 25 10:37:44 2012 +BANMAU-SPAM-SIGNATURE: 1,4fbef078242001863519165,0 +BANMAU-SPAM-Confidence: 0.7625 +BANMAU-SPAM-Possibility: 0.0000 +BANMAU_FRONT_USER_AUTHED: 0 +BANMAU_FRONT_RESULT: 00 +BANMAU_FRONT_SUSPICION_REASON: 0 +X-Forward-For: 123.125.66.207 +Received: from mail-out.sys.baidu.com (m1-passport-ppui02.m1.baidu.com [10.42.205.13]) + by db-sysnoc-mailrelay3.db01.baidu.com (Postfix) with SMTP id DB58AA560C + for ; Fri, 25 May 2012 10:37:44 +0800 (CST) +From: =?utf8?B?YmFpZHU=?= +To: =?utf8?B?emhlbmdzaHV4aW5ANTFpa2VyLmNvbQ==?= +Subject: =?utf8?B?55m+5bqm5Liq5Lq65Lit5b+D5om+5Zue5a+G56CB?= +MIME-Version: 1.0 +Content-Type: text/html; + charset="utf8" +Content-Transfer-Encoding: base64 +Message-Id: <20120525023744.EB7DEBE0001@mail.banmau.com> +Date: Fri, 25 May 2012 10:37:44 +0800 (CST) + +PCFET0NUWVBFIEhUTUw+DQo8aHRtbD4NCjxoZWFkPg0KPG1ldGEgaHR0cC1lcXVpdj0iQ29udGVu +dC1UeXBlIiBjb250ZW50PSJ0ZXh0L2h0bWw7IGNoYXJzZXQ9dXRmLTgiPg0KPHRpdGxlPuaJvuWb +nuWvhueggTwvdGl0bGU+DQo8c3R5bGU+DQoqew0KCW1hcmdpbjowOw0KCXBhZGRpbmc6MDsNCglm +b250LWZhbWlseTpBcmlhbCwgSGVsdmV0aWNhLCBzYW5zLXNlcmlmOw0KCWZvbnQtc2l6ZToxMnB4 +Ow0KfQ0KaW1new0KCWRpc3BsYXk6YmxvY2s7DQoJYm9yZGVyOjA7DQp9DQouc3Ryb25new0KCWZv +bnQtd2VpZ2h0OmJvbGQ7DQp9DQphew0KCWNvbG9yOiMwMTAwZmU7DQoJdGV4dC1kZWNvcmF0aW9u +OnVuZGVybGluZTsNCn0NCiNoZWFkZXJ7DQoJd2lkdGg6MTAwJTsNCgloZWlnaHQ6NjJweDsNCgli +YWNrZ3JvdW5kOnVybChodHRwczovL3Bhc3Nwb3J0LmJhaWR1LmNvbS9nZXRwYXNzL2ltZy9pbWcv +YmdfcmVwX3guZ2lmKSAwIDAgcmVwZWF0LXg7DQp9DQojZm9vdGVyew0KCW1hcmdpbi10b3A6NTBw +eDsNCgl3aWR0aDoxMDAlOw0KCXRleHQtYWxpZ246Y2VudGVyOw0KfQ0KI2Zvb3RlciBzcGFuew0K +CWNvbG9yOiM3YTc2Y2E7DQp9DQojd3JhcHBlcnsNCgl3aWR0aDo5ODBweDsNCgltYXJnaW46LTYy +cHggYXV0byAwOw0KfQ0KI2xvZ28sI2xvZ28gaW1new0KCXdpZHRoOjEzN3B4Ow0KCWhlaWdodDo0 +NnB4Ow0KfQ0KI2xvZ297DQoJZGlzcGxheTpibG9jazsNCgltYXJnaW46N3B4IDAgMCA1cHg7DQoJ +Y2xlYXI6Ym90aDsNCn0NCiNhcnRpY2xlew0KCW1hcmdpbi10b3A6NzBweDsNCn0NCmgxew0KCWZv +bnQtc2l6ZToxNHB4Ow0KfQ0KaDEsaDJ7DQoJZm9udC13ZWlnaHQ6Ym9sZDsNCn0NCnAsaDEsaDJ7 +DQoJcGFkZGluZzoxMnB4IDA7DQp9DQo8L3N0eWxlPg0KPC9oZWFkPg0KPGJvZHk+DQoJPGRpdiBp +ZD0iaGVhZGVyIj48L2Rpdj4NCgk8ZGl2IGlkPSJ3cmFwcGVyIj4NCgkJPGEgaWQ9ImxvZ28iIHRh +cmdldD0iX2JsYW5rIiBocmVmPSJodHRwOi8vd3d3LmJhaWR1LmNvbSI+DQoJCQk8aW1nIGFsdD0i +YmFpZHUiIHRpdGxlPSJiYWlkdSIgc3JjPSJodHRwczovL3Bhc3Nwb3J0LmJhaWR1LmNvbS9nZXRw +YXNzL2ltZy9sb2dvLmdpZiIgLz4NCgkJPC9hPg0KCQk8ZGl2IGlkPSJhcnRpY2xlIj4NCgkJCTxo +MT7nmb7luqbkuKrkurrkuK3lv4PluJDlj7fmnI3liqE8L2gxPg0KCQkJPGgyPuS6sueIseeahOeU +qOaIt++8mjwvaDI+DQoJCQk8aDI+5oKo5aW977yBPC9oMj4NCgkJCQ0KPHA+5oKo5ZyoMjAxMuW5 +tDA15pyIMjXml6UgMTA6Mzc6NDTmj5DkuqTmib7lm57lr4bnoIHor7fmsYLvvIzor7fngrnlh7vk +uIvpnaLnmoTpk77mjqXkv67mlLnlr4bnoIHjgII8L3A+DQo8cD48YSBocmVmPSJodHRwOi8vcGFz +c3BvcnQuYmFpZHUuY29tLz9nZXRwYXNzcmVzZXRwd2QmdnN0cj0yYWY3OTQwMzBiNjA5ZTMwMGJl +YzM4NDFmMTc5YTg4OSZ0eXBlPW1haWwiIHRhcmdldD0iX2JsYW5rIj5odHRwOi8vcGFzc3BvcnQu +YmFpZHUuY29tLz9nZXRwYXNzcmVzZXRwd2QmdnN0cj0yYWY3OTQwMzBiNjA5ZTMwMGJlYzM4NDFm +MTc5YTg4OSZ0eXBlPW1haWw8L2E+PGJyLz4o5aaC5p6c5oKo5peg5rOV54K55Ye76L+Z5Liq6ZO+ +5o6l77yM6K+35bCG5q2k6ZO+5o6l5aSN5Yi25Yiw5rWP6KeI5Zmo5Zyw5Z2A5qCP5ZCO6K6/6Zeu +KTwvcD4NCjxwPuS4uuS6huS/neivgeaCqOW4kOWPt+eahOWuieWFqOaAp++8jOivpemTvuaOpeac +ieaViOacn+S4ujI05bCP5pe277yM5bm25LiUPHNwYW4gY2xhc3M9InN0cm9uZyI+54K55Ye75LiA +5qyh5ZCO5bCG5aSx5pWIITwvc3Bhbj48L3A+DQo8cD7nu5HlrprmiYvmnLrlj7fnoIHjgIHorr7n +va7pqozor4Hpgq7nrrHjgIHorr7nva7lr4bnoIHkv53miqTpl67popjlsIbmm7Tlpb3lnLDkv53p +mpzmgqjnmoTluJDlj7flronlhajvvIzlu7rorq7lnKjnmb7luqbkuKrkurrotYTmlpnorr7nva7l +ronlhajpqozor4HjgII8L3A+DQoNCgkJCTxwPuWmguaenOaCqOivr+aUtuWIsOatpOeUteWtkOmC +ruS7tu+8jOWImeWPr+iDveaYr+WFtuS7lueUqOaIt+WcqOWwneivleW4kOWPt+iuvue9ruaXtuea +hOivr+aTjeS9nO+8jOWmguaenOaCqOW5tuacquWPkei1t+ivpeivt+axgu+8jOWImeaXoOmcgOWG +jei/m+ihjOS7u+S9leaTjeS9nO+8jOW5tuWPr+S7peaUvuW/g+WcsOW/veeVpeatpOeUteWtkOmC +ruS7tuOAgjwvcD4NCgkJCTxwPuiLpeaCqOaLheW/g+W4kOWPt+WuieWFqO+8jOW7uuiuruaCqDxh +IGhyZWY9Imh0dHBzOi8vcGFzc3BvcnQuYmFpZHUuY29tL3YyLz9sb2dpbiIgdGFyZ2V0PSJfYmxh +bmsiPueri+WNs+eZu+W9lTwvYT7vvIzov5vlhaXkuKrkurrotYTmlpnpobXpnaLkuK3nmoTluJDl +j7flronlhajvvIznu5HlrprmiYvmnLrmiJbpgq7nrrHjgII8L3A+DQoJCQk8cD7mhJ/osKLmgqjk +vb/nlKjnmb7luqbvvIE8L3A+DQoJCQk8aDI+55m+5bqm5Liq5Lq66LWE5paZPC9oMj4NCgkJCTxo +Mj4yMDEy5bm0MDXmnIgyNeaXpTwvaDI+DQoJCTwvZGl2Pg0KCTwvZGl2Pg0KCTxkaXYgaWQ9ImZv +b3RlciI+DQoJCTxzcGFuPiZjb3B5OzIwMTImbmJzcDtCYWlkdTwvc3Bhbj4NCgk8L2Rpdj4NCjwv +Ym9keT4NCjwvaHRtbD4= + diff --git a/lib_acl_cpp/samples/mime/valgrind.sh b/lib_acl_cpp/samples/mime/valgrind.sh new file mode 100644 index 000000000..f5c8915c0 --- /dev/null +++ b/lib_acl_cpp/samples/mime/valgrind.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +valgrind --tool=memcheck --leak-check=yes --show-reachable=yes -v ./mime -s -f test2.eml diff --git a/lib_acl_cpp/samples/mime/vld.dll b/lib_acl_cpp/samples/mime/vld.dll new file mode 100644 index 000000000..381ac17d0 Binary files /dev/null and b/lib_acl_cpp/samples/mime/vld.dll differ diff --git a/lib_acl_cpp/samples/mime_base64/Makefile b/lib_acl_cpp/samples/mime_base64/Makefile new file mode 100644 index 000000000..3944be749 --- /dev/null +++ b/lib_acl_cpp/samples/mime_base64/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = mime_base64 diff --git a/lib_acl_cpp/samples/mime_base64/base64_decode.txt b/lib_acl_cpp/samples/mime_base64/base64_decode.txt new file mode 100644 index 000000000..43c06bb93 --- /dev/null +++ b/lib_acl_cpp/samples/mime_base64/base64_decode.txt @@ -0,0 +1,10 @@ +市场份额和利润证明了微软的错误。但在这之前, +Google有足够时间成长为可与微软比肩的巨人。到2007年,微 +软不得不通过并购来对抗Google。它的目标甚至指向了雅虎,这 +让Google惊出一身冷汗,并花大力气来说服雅虎拒绝微软。微软 +还试图通过削弱软件基因给其互联网业务带来的影响,并在2009年 +6月推出了自己的独立搜索引擎Bing。这款产品完全抛弃Windows + 基因,在界面和功能上小心翼翼和竞争对手针锋相对并避免雷同。 +到这时,微软才意识到搜索业务不能是Windows业务的附庸,以搜 +索为核心的互联网业务有其生长逻辑。:) + diff --git a/lib_acl_cpp/samples/mime_base64/base64_encode.txt b/lib_acl_cpp/samples/mime_base64/base64_encode.txt new file mode 100644 index 000000000..ec5e04cf5 --- /dev/null +++ b/lib_acl_cpp/samples/mime_base64/base64_encode.txt @@ -0,0 +1,9 @@ +ytCzobfdtu66zcD7yPPWpMP3wcvOosjttcS07c7zoaO1q9Ta1eLWrsewo6wNCkdvb2dsZdPQ1+O5 +u8qxvOSzybOkzqq/ydPrzqLI7bHIvOe1xL7eyMuho7W9MjAwN8Tqo6zOog0KyO2yu7XDsrvNqLn9 +sqK5usC0ttS/uUdvb2dsZaGjy/y1xMS/serJ9dbB1rjP8sHL0cW7oqOs1eINCsjDR29vZ2xlvqqz +9tK7ye3A5Lq5o6yyoruotPPBpsb4wLTLtbf+0cW7or7cvvjOosjtoaPOosjtDQq7ucrUzbzNqLn9 +z/fI9cjtvP67+dLyuPjG5LulwarN+NK1zvG0+MC0tcTTsM/so6yyotTaMjAwOcTqDQo21MLNxrP2 +wcvX1Ly6tcS2wMGiy9HL99L9x+ZCaW5noaPV4r/usvrGt83qyKvF18b6V2luZG93cw0KILv50vKj +rNTavefD5rrNuabE3MnP0KHQxNLt0u26zb661fm21MrW1eu35s/gttSyorHcw+LA182soaMNCrW9 +1eLKsaOszqLI7bLF0uLKtrW9y9HL99K1zvGyu8TcysdXaW5kb3dz0rXO8bXEuL3TuaOs0tTL0Q0K +y/fOqrrL0MS1xLulwarN+NK1zvHT0MbkyfqzpMLfvK2hozopDQo= diff --git a/lib_acl_cpp/samples/mime_base64/main.cpp b/lib_acl_cpp/samples/mime_base64/main.cpp new file mode 100644 index 000000000..103ac8239 --- /dev/null +++ b/lib_acl_cpp/samples/mime_base64/main.cpp @@ -0,0 +1,144 @@ +#include +#include "acl_cpp/mime/mime_base64.hpp" +#include "acl_cpp/mime/mime_uucode.hpp" +#include "acl_cpp/mime/mime_xxcode.hpp" +#include "acl_cpp/stream/fstream.hpp" +#include "acl_cpp/stream/ifstream.hpp" + +static void test1(void) +{ + acl::mime_base64 mime; + acl::string out; + const char *x = "sg==y8bX"; + const char* ptr = x; + + while (*ptr) + { + mime.decode_update(ptr, 1, &out); + ptr++; + } + mime.decode_finish(&out); + printf(">>>result:|%s|\n", out.c_str()); + + out.clear(); + const char *s1 = "sg==", *s2 = "y8bX"; + mime.reset(); + mime.decode_update(s1, (int) strlen(s1), &out); + mime.decode_update(s2, (int) strlen(s2), &out); + mime.decode_finish(&out); + printf(">>>2result:|%s|\n", out.c_str()); +} + +int main(void) +{ + test1(); + + const char *text = "市场份额和利润证明了微软的错误。但在这之前,\r\n" + "Google有足够时间成长为可与微软比肩的巨人。到2007年,微\r\n" + "软不得不通过并购来对抗Google。它的目标甚至指向了雅虎,这\r\n" + "让Google惊出一身冷汗,并花大力气来说服雅虎拒绝微软。微软\r\n" + "还试图通过削弱软件基因给其互联网业务带来的影响,并在2009年\r\n" + "6月推出了自己的独立搜索引擎Bing。这款产品完全抛弃Windows\r\n" + " 基因,在界面和功能上小心翼翼和竞争对手针锋相对并避免雷同。\r\n" + "到这时,微软才意识到搜索业务不能是Windows业务的附庸,以搜\r\n" + "索为核心的互联网业务有其生长逻辑。:)\r\n"; + //acl::mime_xxcode mime; + //acl::mime_uucode mime; + acl::mime_base64 mime; + acl::string out; + acl::string path_encode("base64_encode.txt"); + acl::string path_decode("base64_decode.txt"); + acl::fstream fp_out; + const char *ptr, *end; + + /*----------------------- 编码过程 --------------------------*/ + +#if 1 + if (fp_out.open_trunc(path_encode.c_str()) == false) { + printf("open %s error\r\n", path_encode.c_str()); + getchar(); + return (1); + } + + ptr = text; + end = text + strlen(text); + + while (ptr < end) { + mime.encode_update(ptr, 1, &out); + fp_out << out.c_str(); + out.clear(); + ptr++; + } + mime.encode_finish(&out); + if (out.length() > 0) { + fp_out << out.c_str(); + out.clear(); + } + fp_out.close(); + + printf("base64 encode over\r\n"); +#endif + /*----------------------- 解码过程 --------------------------*/ + + acl::string buf; + if (acl::ifstream::load(path_encode.c_str(), &buf) == false) { + printf("load %s error\r\n", path_encode.c_str()); + return (1); + } + + if (fp_out.open_trunc(path_decode.c_str()) == false) { + printf("open %s error\r\n", path_decode.c_str()); + getchar(); + return (1); + } + + ptr = buf.c_str(); + end = ptr + buf.length(); + + mime.reset(); + mime.add_invalid(true); + while (ptr < end) { + mime.decode_update(ptr, 1, &out); + if (out.length() > 0) { + fp_out << out.c_str(); + out.clear(); + } + ptr++; + } + mime.decode_finish(&out); + if (out.length() > 0) { + fp_out << out.c_str(); + out.clear(); + } + + fp_out.close(); + + printf("base64 decode over\r\n"); + + /*----------------------- 解码过程 --------------------------*/ + + const char* s2 = "PCFET0NUWVBFIEhUTUwgUFVCTElDICItLy9XM0MvL0RURCBIVE1MIDQuMCBUcmFuc2l0aW9uYWwv\r\n" + "L0VOIj4NCjxIVE1MPjxIRUFEPg0KPE1FVEEgY29udGVudD0idGV4dC9odG1sOyBjaGFyc2V0PWdi\r\n" + "MjMxMiIgaHR0cC1lcXVpdj1Db250ZW50LVR5cGU+DQo8TUVUQSBuYW1lPUdFTkVSQVRPUiBjb250\r\n" + "ZW50PSJNU0hUTUwgOC4wMC43NjAwLjE2NjI1Ij48TElOSyByZWw9c3R5bGVzaGVldCANCmhyZWY9\r\n" + "IkJMT0NLUVVPVEV7bWFyZ2luLVRvcDogMHB4OyBtYXJnaW4tQm90dG9tOiAwcHg7IG1hcmdpbi1M\r\n" + "ZWZ0OiAyZW19Ij48L0hFQUQ+DQo8Qk9EWSBzdHlsZT0iTUFSR0lOOiAxMHB4OyBGT05ULUZBTUlM\r\n" + "WTogdmVyZGFuYTsgRk9OVC1TSVpFOiAxMHB0Ij4NCjxESVY+PEZPTlQgc2l6ZT0yIGZhY2U9VmVy\r\n" + "ZGFuYT48L0ZPTlQ+Jm5ic3A7PC9ESVY+DQo8RElWPjxGT05UIHNpemU9MiBmYWNlPVZlcmRhbmE+\r\n" + "PC9GT05UPiZuYnNwOzwvRElWPg0KPERJViBhbGlnbj1sZWZ0PjxGT05UIGNvbG9yPSNjMGMwYzAg\r\n" + "c2l6ZT0yIGZhY2U9VmVyZGFuYT4yMDEwLTA5LTIxIA0KPC9GT05UPjwvRElWPjxGT05UIHNpemU9\r\n" + "MiBmYWNlPVZlcmRhbmE+DQo8SFIgc3R5bGU9IldJRFRIOiAxMjJweDsgSEVJR0hUOiAycHgiIGFs\r\n" + "aWduPWxlZnQgU0laRT0yPg0KDQo8RElWPjxGT05UIGNvbG9yPSNjMGMwYzAgc2l6ZT0yIGZhY2U9\r\n" + "VmVyZGFuYT48U1BBTj7C7crAw/Q8L1NQQU4+IA0KPC9GT05UPjwvRElWPjwvRk9OVD48L0JPRFk+\r\n" + "PC9IVE1MPg0K\r\n" + "\r\n" + "\r\n"; + mime.reset(); + out.clear(); + + mime.decode_update(s2, (int) strlen(s2), &out); + mime.decode_finish(&out); + printf("result:\n%s\n", out.c_str()); + getchar(); + return (0); +} diff --git a/lib_acl_cpp/samples/mime_base64/mime_base64.vcproj b/lib_acl_cpp/samples/mime_base64/mime_base64.vcproj new file mode 100644 index 000000000..3a1f58956 --- /dev/null +++ b/lib_acl_cpp/samples/mime_base64/mime_base64.vcproj @@ -0,0 +1,240 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_acl_cpp/samples/mime_base64/mime_base64.vcxproj b/lib_acl_cpp/samples/mime_base64/mime_base64.vcxproj new file mode 100644 index 000000000..c42c181a6 --- /dev/null +++ b/lib_acl_cpp/samples/mime_base64/mime_base64.vcxproj @@ -0,0 +1,189 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + Releasedll + Win32 + + + Release + Win32 + + + + {19CB30E5-2672-4A8B-96FB-9C42970CCF69} + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + true + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + ws2_32.lib;lib_acl_vc2010d.lib;lib_acl_cpp_vc2010d.lib;%(AdditionalDependencies) + $(OutDir)mime_base64.exe + ..\..\..\lib\win32;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)mime_base64.pdb + Console + MachineX86 + + + + + + + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;lib_acl_vc2010.lib;lib_acl_cpp_vc2010.lib;%(AdditionalDependencies) + $(OutDir)mime_base64.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + lib_acl_d.lib;lib_acl_cpp_d.lib;ws2_32.lib;%(AdditionalDependencies) + $(OutDir)mime_base64.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)mime_base64.pdb + Console + MachineX86 + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + lib_acl.lib;lib_acl_cpp.lib;ws2_32.lib;%(AdditionalDependencies) + $(OutDir)mime_base64.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)mime_base64.pdb + Console + MachineX86 + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib_acl_cpp/samples/mime_base64/mime_base64_vc2012.vcxproj b/lib_acl_cpp/samples/mime_base64/mime_base64_vc2012.vcxproj new file mode 100644 index 000000000..5b093975f --- /dev/null +++ b/lib_acl_cpp/samples/mime_base64/mime_base64_vc2012.vcxproj @@ -0,0 +1,194 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + Releasedll + Win32 + + + Release + Win32 + + + + {19CB30E5-2672-4A8B-96FB-9C42970CCF69} + Win32Proj + mime_base64 + + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + true + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + ws2_32.lib;lib_acl_vc2012d.lib;lib_acl_cpp_vc2012d.lib;%(AdditionalDependencies) + $(OutDir)mime_base64.exe + ..\..\..\lib\win32;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)mime_base64.pdb + Console + MachineX86 + + + + + + + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;lib_acl_vc2012.lib;lib_acl_cpp_vc2012.lib;%(AdditionalDependencies) + $(OutDir)mime_base64.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + lib_acl_d.lib;lib_acl_cpp_d.lib;ws2_32.lib;%(AdditionalDependencies) + $(OutDir)mime_base64.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)mime_base64.pdb + Console + MachineX86 + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + lib_acl.lib;lib_acl_cpp.lib;ws2_32.lib;%(AdditionalDependencies) + $(OutDir)mime_base64.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)mime_base64.pdb + Console + MachineX86 + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib_acl_cpp/samples/mime_qp/Makefile b/lib_acl_cpp/samples/mime_qp/Makefile new file mode 100644 index 000000000..b14706da8 --- /dev/null +++ b/lib_acl_cpp/samples/mime_qp/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = mime_qp diff --git a/lib_acl_cpp/samples/mime_qp/main.cpp b/lib_acl_cpp/samples/mime_qp/main.cpp new file mode 100644 index 000000000..53f45cbcf --- /dev/null +++ b/lib_acl_cpp/samples/mime_qp/main.cpp @@ -0,0 +1,77 @@ +#include +#include "acl_cpp/mime/mime_code.hpp" +#include "acl_cpp/stream/fstream.hpp" +#include "acl_cpp/mime/mime_quoted_printable.hpp" + +int main(void) +{ + acl::mime_quoted_printable mime; + acl::string out; + const char *ptr, *end; + +#if 1 + const char *text = + "徐刚辉 changed: \r\n" + "What |Removed |Added\r\n" + "-------------------------------------\r\n" + "Status|NEW |ASSIGNED\r\n" + "AssignedTo|xuganghui |zhengshuxin\r\n"; +#else + const char *text = "缺陷 410"; +#endif + + ptr = text; + end = text + strlen(text); + + while (ptr < end) { + mime.encode_update(ptr, 1, &out); + ptr++; + } + mime.encode_finish(&out); + + printf("encode result length: %d\r\n", (int) out.length()); + printf("(%s)\r\n", out.c_str()); + +#if 1 + const char *qp = "=D0=EC=B8=D5=BB=D4 changed:=20\r\n" + "What |Removed |Added\r\n" + "-------------------------------------\r\n" + "Status|NEW |ASSIGNED\r\n" + "AssignedTo|xuganghui |zhengshuxin\r\n"; +#else + const char *qp = "=C8=B1=CF=DD 410"; +#endif + + out.clear(); + + ptr = qp; + end = qp + strlen(qp); + + mime.reset(); + mime.add_invalid(true); + while (ptr < end) { + mime.decode_update(ptr, 1, &out); + ptr++; + } + mime.decode_finish(&out); + if (out.length() > 0) { + printf("decode result length: %d\r\n", (int) out.length()); + printf("(%s)\r\n", out.c_str()); + } + + acl::fstream fp; + fp.open_trunc("out.txt"); + fp << out.c_str(); + fp.close(); + + out.clear(); + //static const unsigned char to_tab[] = + // "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + //static const unsigned char to_tab[] = + // "+-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + //acl::mime_code::create_decode_tab(to_tab, &out); + //printf("%s", out.c_str()); + getchar(); + + return (0); +} diff --git a/lib_acl_cpp/samples/mime_qp/mime_qp.vcproj b/lib_acl_cpp/samples/mime_qp/mime_qp.vcproj new file mode 100644 index 000000000..fa8694959 --- /dev/null +++ b/lib_acl_cpp/samples/mime_qp/mime_qp.vcproj @@ -0,0 +1,240 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_acl_cpp/samples/mime_qp/mime_qp.vcxproj b/lib_acl_cpp/samples/mime_qp/mime_qp.vcxproj new file mode 100644 index 000000000..d8e91e9f6 --- /dev/null +++ b/lib_acl_cpp/samples/mime_qp/mime_qp.vcxproj @@ -0,0 +1,189 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + Releasedll + Win32 + + + Release + Win32 + + + + {5DC79C83-9DE8-46B3-A172-8A4E3371878B} + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + true + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + ws2_32.lib;lib_acl_vc2010d.lib;lib_acl_cpp_vc2010d.lib;%(AdditionalDependencies) + $(OutDir)mime_qp.exe + ..\..\..\lib\win32;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)mime_qp.pdb + Console + MachineX86 + + + + + + + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;lib_acl_vc2010.lib;lib_acl_cpp_vc2010.lib;%(AdditionalDependencies) + $(OutDir)mime_qp.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + lib_acl_d.lib;lib_acl_cpp_d.lib;ws2_32.lib;%(AdditionalDependencies) + $(OutDir)mime_qp.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)mime_qp.pdb + Console + MachineX86 + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + lib_acl.lib;lib_acl_cpp.lib;ws2_32.lib;%(AdditionalDependencies) + $(OutDir)mime_qp.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)mime_qp.pdb + Console + MachineX86 + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib_acl_cpp/samples/mime_qp/mime_qp_vc2012.vcxproj b/lib_acl_cpp/samples/mime_qp/mime_qp_vc2012.vcxproj new file mode 100644 index 000000000..53c25630c --- /dev/null +++ b/lib_acl_cpp/samples/mime_qp/mime_qp_vc2012.vcxproj @@ -0,0 +1,194 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + Releasedll + Win32 + + + Release + Win32 + + + + {5DC79C83-9DE8-46B3-A172-8A4E3371878B} + Win32Proj + mime_qp + + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + true + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + ws2_32.lib;lib_acl_vc2012d.lib;lib_acl_cpp_vc2012d.lib;%(AdditionalDependencies) + $(OutDir)mime_qp.exe + ..\..\..\lib\win32;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)mime_qp.pdb + Console + MachineX86 + + + + + + + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;lib_acl_vc2012.lib;lib_acl_cpp_vc2012.lib;%(AdditionalDependencies) + $(OutDir)mime_qp.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + lib_acl_d.lib;lib_acl_cpp_d.lib;ws2_32.lib;%(AdditionalDependencies) + $(OutDir)mime_qp.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)mime_qp.pdb + Console + MachineX86 + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + lib_acl.lib;lib_acl_cpp.lib;ws2_32.lib;%(AdditionalDependencies) + $(OutDir)mime_qp.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)mime_qp.pdb + Console + MachineX86 + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib_acl_cpp/samples/mime_qp/out.txt b/lib_acl_cpp/samples/mime_qp/out.txt new file mode 100644 index 000000000..c3f91e996 --- /dev/null +++ b/lib_acl_cpp/samples/mime_qp/out.txt @@ -0,0 +1,5 @@ +徐刚辉 changed: +What |Removed |Added +------------------------------------- +Status|NEW |ASSIGNED +AssignedTo|xuganghui |zhengshuxin diff --git a/lib_acl_cpp/samples/mime_xxcode/Makefile b/lib_acl_cpp/samples/mime_xxcode/Makefile new file mode 100644 index 000000000..67864cbf6 --- /dev/null +++ b/lib_acl_cpp/samples/mime_xxcode/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = mime_xxcode diff --git a/lib_acl_cpp/samples/mime_xxcode/main.cpp b/lib_acl_cpp/samples/mime_xxcode/main.cpp new file mode 100644 index 000000000..69c6196ec --- /dev/null +++ b/lib_acl_cpp/samples/mime_xxcode/main.cpp @@ -0,0 +1,62 @@ +#include "acl_cpp/mime/mime_xxcode.hpp" +#include +#include + +static void encoding(const char* s) +{ + acl::mime_xxcode coder(false, false); + acl::string out; + + coder.encode_update(s, strlen(s), &out); + coder.encode_finish(&out); + printf(">>>%s\n", out.c_str()); +} + +static void decoding(const char* s) +{ + acl::mime_xxcode coder(false, false); + acl::string out; + + coder.decode_update(s, strlen(s), &out); + coder.decode_finish(&out); + printf(">>>%s\n", out.c_str()); +} + +static void usage(const char* procname) +{ + printf("usage: %s -h[help] -e plain -d txt\n", procname); +} + +int main(int argc, char* argv[]) +{ + int ch; + void (*action)(const char*) = NULL; + acl::string s; + + while ((ch = getopt(argc, argv, "he:d:")) > 0) + { + switch (ch) + { + case 'h': + usage(argv[0]); + return (0); + case 'e': + action = encoding; + s = optarg; + break; + case 'd': + action = decoding; + s = optarg; + break; + default: + break; + } + } + + if (action && !s.empty()) + action(s); + else + usage(argv[0]); + + return (0); +} diff --git a/lib_acl_cpp/samples/mysql/Makefile b/lib_acl_cpp/samples/mysql/Makefile new file mode 100644 index 000000000..d73710e4b --- /dev/null +++ b/lib_acl_cpp/samples/mysql/Makefile @@ -0,0 +1,103 @@ +SHELL = /bin/sh +CC = gcc +CC = g++ +AR = ar +ARFL = rv +#ARFL = cru +RANLIB = ranlib + +CFLAGS = -c -g -W -Wall -Wcast-qual -Wcast-align \ +-Wno-long-long \ +-Wpointer-arith -Werror -Wshadow -O2 \ +-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO +#-Waggregate-return +########################################################### +#Check system: +# Linux, SunOS, Solaris, BSD variants, AIX, HP-UX +SYSLIB = -lpthread -lcrypt -lz +CHECKSYSRES = @echo "Unknow system type!";exit 1 +UNIXNAME = $(shell uname -sm) + +ifeq ($(CC),) + CC = gcc +endif + +# For FreeBSD +ifeq ($(findstring FreeBSD, $(UNIXNAME)), FreeBSD) + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DFREEBSD -D_REENTRANT + SYSLIB = -lcrypt -lpthread +endif + +#Path for Linux +ifeq ($(findstring Linux, $(UNIXNAME)), Linux) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DLINUX2 -D_REENTRANT +endif + +#Path for SunOS +ifeq ($(findstring SunOS, $(UNIXNAME)), SunOS) + ifeq ($(findstring 86, $(UNIXNAME)), 86) + SYSLIB += -lsocket -lnsl -lrt + endif + ifeq ($(findstring sun4u, $(UNIXNAME)), sun4u) + SYSLIB += -lsocket -lnsl -lrt + endif + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DSUNOS5 -D_REENTRANT +endif + +#Path for HP-UX +ifeq ($(findstring HP-UX, $(UNIXNAME)), HP-UX) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DHP_UX -DHPUX11 + PLAT_NAME=hp-ux +endif + +#Find system type. +ifneq ($(SYSPATH),) + CHECKSYSRES = @echo "System is $(shell uname -sm)" +endif +########################################################### + +CFLAGS += $(INC_COMPILE) + +INC_COMPILE = -I../../include -I../../../lib_acl/include -I../../../include/mysql +LIB_COMPILE = -L../../lib -l_acl_cpp -L/opt/import_lib/lib -l_acl \ + -lmysqlclient_r -ldl + +########################################################### +OUT_PATH = . +OBJ_PATH_DST = $(OUT_PATH) + +#Project's objs +SRC = $(wildcard *.cpp) +OBJ = $(patsubst %.cpp, $(OBJ_PATH_DST)/%.o, $(notdir $(SRC))) +########################################################### + +PROG = mysql_test + +.PHONY = all clean +COMPILE = $(CC) $(CFLAGS) + +$(PROG): $(OBJ) + $(CC) $(OBJ) $(LIB_COMPILE) $(SYSLIB) -o $(OBJ_PATH_DST)/$(PROG) + @echo "" + @echo "All ok! Output:$(PROG)" + @echo "" +# fifo +$(OBJ_PATH_DST)/%.o: %.cpp + $(COMPILE) $< -o $@ + +clean: + rm -f $(PROG) + rm -f $(OBJ) + diff --git a/lib_acl_cpp/samples/mysql/ReadMe.txt b/lib_acl_cpp/samples/mysql/ReadMe.txt new file mode 100644 index 000000000..e740d9c00 --- /dev/null +++ b/lib_acl_cpp/samples/mysql/ReadMe.txt @@ -0,0 +1,39 @@ +======================================================================== + 控制台应用程序 : mysql 项目概况 +======================================================================== + +应用程序向导已为您创建了这个 mysql 应用程序。 +此文件包含组成 mysql 应用程序 +的每个文件的内容摘要。 + + +mysql.vcproj + 这是用应用程序向导生成的 VC++ 项目的主项目文件。 + 它包含有关生成此文件的 Visual C++ 版本的信息,以及 + 有关用应用程序向导选择的 + 平台、配置和项目功能的信息。 + +mysql.cpp + 这是主应用程序源文件。 + +///////////////////////////////////////////////////////////////////////////// +其他标准文件: + +StdAfx.h、StdAfx.cpp + 这些文件用于生成名为 mysql.pch + 的预编译头(PCH)文件以及名为 StdAfx.obj 的预编译类型文件。 + +///////////////////////////////////////////////////////////////////////////// +其他注释: + +应用程序向导使用 "TODO:" 注释指示应添加或自定义的源代码部分。 + +///////////////////////////////////////////////////////////////////////////// + +use mysql; +create database acl_test_db; +insert into user (User, Host, Password) values ('acl_user', 'localhost', PASSWORD('111111')); +insert into user (User, Host, Password) values ('acl_user', '192.168.1.%', PASSWORD('111111')); +grant CREATE,DROP,INSERT,DELETE,UPDATE,SELECT on acl_test_db.* to 'acl_user'; +flush privileges; + diff --git a/lib_acl_cpp/samples/mysql/mysql.cpp b/lib_acl_cpp/samples/mysql/mysql.cpp new file mode 100644 index 000000000..bbb9adacd --- /dev/null +++ b/lib_acl_cpp/samples/mysql/mysql.cpp @@ -0,0 +1,262 @@ +// mysql.cpp : 定义控制台应用程序的入口点。 +// + +#include "stdafx.h" +#include "lib_acl.h" +#include "acl_cpp/stdlib/string.hpp" +#include "acl_cpp/db/db_mysql.hpp" + +const char* CREATE_TBL = + "create table group_tbl\r\n" + "(\r\n" + "group_name varchar(128) not null,\r\n" + "uvip_tbl varchar(32) not null default 'uvip_tbl',\r\n" + "access_tbl varchar(32) not null default 'access_tbl',\r\n" + "access_week_tbl varchar(32) not null default 'access_week_tbl',\r\n" + "access_month_tbl varchar(32) not null default 'access_month_tbl',\r\n" + "update_date date not null default '1970-1-1',\r\n" + "disable integer not null default 0,\r\n" + "add_by_hand integer not null default 0,\r\n" + "class_level integer not null default 0,\r\n" + "primary key(group_name, class_level)\r\n" + ")"; + +static bool tbl_create(acl::db_handle& db) +{ + if (db.tbl_exists("group_tbl")) + { + printf("table exist\r\n"); + return (true); + } + else if (db.sql_update(CREATE_TBL) == false) + { + printf("sql error\r\n"); + return (false); + } + else + { + printf("create table ok\r\n"); + return (true); + } +} + +// 添加表数据 +static bool tbl_insert(acl::db_handle& db, int n) +{ + const char* sql_fmt = "insert into group_tbl(group_name, uvip_tbl)" + " values('中国人-%d', 'test')"; + + acl::string sql; + sql.format(sql_fmt, n); + if (db.sql_update(sql.c_str()) == false) + return (false); + + const acl::db_rows* result = db.get_result(); + if (result) + { + const std::vector& rows = result->get_rows(); + for (size_t i = 0; i < rows.size(); i++) + { + const acl::db_row* row = rows[i]; + for (size_t j = 0; j < row->length(); j++) + printf("%s, ", (*row)[j]); + printf("\r\n"); + } + } + + db.free_result(); + return (true); +} + +// 查询表数据 +static int tbl_select(acl::db_handle& db, int n) +{ + const char* sql_fmt = "select * from group_tbl where" + " group_name='中国人-%d' and uvip_tbl='test'"; + + acl::string sql; + sql.format(sql_fmt, n); + + if (db.sql_select(sql.c_str()) == false) + { + printf("select sql error\r\n"); + return (-1); + } + + printf("\r\n---------------------------------------------------\r\n"); + + // 列出查询结果方法一 + const acl::db_rows* result = db.get_result(); + if (result) + { + const std::vector& rows = result->get_rows(); + for (size_t i = 0; i < rows.size(); i++) + { + if (n > 100) + continue; + const acl::db_row* row = rows[i]; + for (size_t j = 0; j < row->length(); j++) + printf("%s, ", (*row)[j]); + printf("\r\n"); + } + } + + // 列出查询结果方法二 + for (size_t i = 0; i < db.length(); i++) + { + if (n > 100) + continue; + const acl::db_row* row = db[i]; + + // 取出该行记录中某个字段的值 + const char* ptr = (*row)["group_name"]; + if (ptr == NULL) + { + printf("error, no group name\r\n"); + continue; + } + printf("group_name=%s: ", ptr); + for (size_t j = 0; j < row->length(); j++) + printf("%s, ", (*row)[j]); + printf("\r\n"); + } + + // 列出查询结果方法三 + const std::vector* rows = db.get_rows(); + if (rows) + { + std::vector::const_iterator cit = rows->begin(); + for (; cit != rows->end(); cit++) + { + if (n > 100) + continue; + const acl::db_row* row = *cit; + for (size_t j = 0; j < row->length(); j++) + printf("%s, ", (*row)[j]); + printf("\r\n"); + } + + } + int ret = (int) db.length(); + + // 释放查询结果 + db.free_result(); + return (ret); +} + +// 删除表数据 +static bool tbl_delete(acl::db_handle& db, int n) +{ + const char* sql_fmt = "delete from group_tbl where group_name='中国人-%d'"; + + acl::string sql; + sql.format(sql_fmt, n); + + if (db.sql_update(sql.c_str()) == false) + { + printf("delete sql error\r\n"); + return (false); + } + + for (size_t i = 0; i < db.length(); i++) + { + const acl::db_row* row = db[i]; + for (size_t j = 0; j < row->length(); j++) + printf("%s, ", (*row)[j]); + printf("\r\n"); + } + // 释放查询结果 + db.free_result(); + + return (true); +} + +int main(void) +{ + +#ifdef WIN32 + const char* dbaddr = "192.168.1.251:3306"; +#else + const char* dbaddr = "127.0.0.1:3306"; +#endif + const char* dbname = "acl_test_db"; + const char* dbuser = "acl_user", *dbpass = "111111"; + acl::db_mysql db(dbaddr, dbname, dbuser, dbpass); + int max = 100; + + // 允许将错误日志输出至屏幕 + acl_msg_stdout_enable(1); + + if (db.open() == false) + { + printf("open db(%s) error\r\n", dbname); + getchar(); + return 1; + } + + printf("open db %s ok\r\n", dbname); + + if (tbl_create(db) == false) + { + printf("create table error\r\n"); + getchar(); + return 1; + } + + ACL_METER_TIME("---begin insert---"); + for (int i = 0; i < max; i++) + { + bool ret = tbl_insert(db, i); + if (ret) + printf(">>insert ok: i=%d, affected: %d\r", + i, db.affect_count()); + else + printf(">>insert error: i = %d\r\n", i); + } + printf("\r\n"); + ACL_METER_TIME("---end insert---"); + + ACL_METER_TIME("---begin select---"); + int n = 0; + for (int i = 0; i < max; i++) + { + int ret = tbl_select(db, i); + if (ret >= 0) + { + n += ret; + printf(">>select ok: i=%d, ret=%d\r", i, ret); + } + else + printf(">>select error: i = %d\r\n", i); + } + printf("\r\n"); + printf(">>select total: %d\r\n", n); + ACL_METER_TIME("---end select---"); + + ACL_METER_TIME("---begin delete---"); + for (int i = 0; i < max; i++) + { + bool ret = tbl_delete(db, i); + if (ret) + printf(">>delete ok: %d, affected: %d\r", + i, (int) db.affect_count()); + else + printf(">>delete error: i = %d\r\n", i); + } + printf("\r\n"); + +#ifndef WIN32 +// mysql_server_end(); +// mysql_thread_end(); +#endif + + printf("mysqlclient lib's version: %ld, info: %s\r\n", + db.mysql_libversion(), db.mysql_client_info()); + + ACL_METER_TIME("---end delete---"); + + printf("Enter any key to exit.\r\n"); + getchar(); + return 0; +} + diff --git a/lib_acl_cpp/samples/mysql/mysql.vcproj b/lib_acl_cpp/samples/mysql/mysql.vcproj new file mode 100644 index 000000000..4329abb3a --- /dev/null +++ b/lib_acl_cpp/samples/mysql/mysql.vcproj @@ -0,0 +1,274 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_acl_cpp/samples/mysql/stdafx.cpp b/lib_acl_cpp/samples/mysql/stdafx.cpp new file mode 100644 index 000000000..3f9a6a49e --- /dev/null +++ b/lib_acl_cpp/samples/mysql/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// mysql.pch 将成为预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + +// TODO: 在 STDAFX.H 中 +//引用任何所需的附加头文件,而不是在此文件中引用 diff --git a/lib_acl_cpp/samples/mysql/stdafx.h b/lib_acl_cpp/samples/mysql/stdafx.h new file mode 100644 index 000000000..b98553f2c --- /dev/null +++ b/lib_acl_cpp/samples/mysql/stdafx.h @@ -0,0 +1,11 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是常用但不常更改的项目特定的包含文件 +// + +#pragma once + + +#include +//#include + +// TODO: 在此处引用程序要求的附加头文件 diff --git a/lib_acl_cpp/samples/mysql/valgrind.sh b/lib_acl_cpp/samples/mysql/valgrind.sh new file mode 100644 index 000000000..6241fb150 --- /dev/null +++ b/lib_acl_cpp/samples/mysql/valgrind.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +valgrind --tool=memcheck --leak-check=full --show-reachable=yes -v ./mysql_test diff --git a/lib_acl_cpp/samples/mysql2/Makefile b/lib_acl_cpp/samples/mysql2/Makefile new file mode 100644 index 000000000..d73710e4b --- /dev/null +++ b/lib_acl_cpp/samples/mysql2/Makefile @@ -0,0 +1,103 @@ +SHELL = /bin/sh +CC = gcc +CC = g++ +AR = ar +ARFL = rv +#ARFL = cru +RANLIB = ranlib + +CFLAGS = -c -g -W -Wall -Wcast-qual -Wcast-align \ +-Wno-long-long \ +-Wpointer-arith -Werror -Wshadow -O2 \ +-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO +#-Waggregate-return +########################################################### +#Check system: +# Linux, SunOS, Solaris, BSD variants, AIX, HP-UX +SYSLIB = -lpthread -lcrypt -lz +CHECKSYSRES = @echo "Unknow system type!";exit 1 +UNIXNAME = $(shell uname -sm) + +ifeq ($(CC),) + CC = gcc +endif + +# For FreeBSD +ifeq ($(findstring FreeBSD, $(UNIXNAME)), FreeBSD) + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DFREEBSD -D_REENTRANT + SYSLIB = -lcrypt -lpthread +endif + +#Path for Linux +ifeq ($(findstring Linux, $(UNIXNAME)), Linux) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DLINUX2 -D_REENTRANT +endif + +#Path for SunOS +ifeq ($(findstring SunOS, $(UNIXNAME)), SunOS) + ifeq ($(findstring 86, $(UNIXNAME)), 86) + SYSLIB += -lsocket -lnsl -lrt + endif + ifeq ($(findstring sun4u, $(UNIXNAME)), sun4u) + SYSLIB += -lsocket -lnsl -lrt + endif + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DSUNOS5 -D_REENTRANT +endif + +#Path for HP-UX +ifeq ($(findstring HP-UX, $(UNIXNAME)), HP-UX) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DHP_UX -DHPUX11 + PLAT_NAME=hp-ux +endif + +#Find system type. +ifneq ($(SYSPATH),) + CHECKSYSRES = @echo "System is $(shell uname -sm)" +endif +########################################################### + +CFLAGS += $(INC_COMPILE) + +INC_COMPILE = -I../../include -I../../../lib_acl/include -I../../../include/mysql +LIB_COMPILE = -L../../lib -l_acl_cpp -L/opt/import_lib/lib -l_acl \ + -lmysqlclient_r -ldl + +########################################################### +OUT_PATH = . +OBJ_PATH_DST = $(OUT_PATH) + +#Project's objs +SRC = $(wildcard *.cpp) +OBJ = $(patsubst %.cpp, $(OBJ_PATH_DST)/%.o, $(notdir $(SRC))) +########################################################### + +PROG = mysql_test + +.PHONY = all clean +COMPILE = $(CC) $(CFLAGS) + +$(PROG): $(OBJ) + $(CC) $(OBJ) $(LIB_COMPILE) $(SYSLIB) -o $(OBJ_PATH_DST)/$(PROG) + @echo "" + @echo "All ok! Output:$(PROG)" + @echo "" +# fifo +$(OBJ_PATH_DST)/%.o: %.cpp + $(COMPILE) $< -o $@ + +clean: + rm -f $(PROG) + rm -f $(OBJ) + diff --git a/lib_acl_cpp/samples/mysql2/ReadMe.txt b/lib_acl_cpp/samples/mysql2/ReadMe.txt new file mode 100644 index 000000000..e740d9c00 --- /dev/null +++ b/lib_acl_cpp/samples/mysql2/ReadMe.txt @@ -0,0 +1,39 @@ +======================================================================== + 控制台应用程序 : mysql 项目概况 +======================================================================== + +应用程序向导已为您创建了这个 mysql 应用程序。 +此文件包含组成 mysql 应用程序 +的每个文件的内容摘要。 + + +mysql.vcproj + 这是用应用程序向导生成的 VC++ 项目的主项目文件。 + 它包含有关生成此文件的 Visual C++ 版本的信息,以及 + 有关用应用程序向导选择的 + 平台、配置和项目功能的信息。 + +mysql.cpp + 这是主应用程序源文件。 + +///////////////////////////////////////////////////////////////////////////// +其他标准文件: + +StdAfx.h、StdAfx.cpp + 这些文件用于生成名为 mysql.pch + 的预编译头(PCH)文件以及名为 StdAfx.obj 的预编译类型文件。 + +///////////////////////////////////////////////////////////////////////////// +其他注释: + +应用程序向导使用 "TODO:" 注释指示应添加或自定义的源代码部分。 + +///////////////////////////////////////////////////////////////////////////// + +use mysql; +create database acl_test_db; +insert into user (User, Host, Password) values ('acl_user', 'localhost', PASSWORD('111111')); +insert into user (User, Host, Password) values ('acl_user', '192.168.1.%', PASSWORD('111111')); +grant CREATE,DROP,INSERT,DELETE,UPDATE,SELECT on acl_test_db.* to 'acl_user'; +flush privileges; + diff --git a/lib_acl_cpp/samples/mysql2/mysql.cpp b/lib_acl_cpp/samples/mysql2/mysql.cpp new file mode 100644 index 000000000..1dc6ad6cb --- /dev/null +++ b/lib_acl_cpp/samples/mysql2/mysql.cpp @@ -0,0 +1,73 @@ +// mysql.cpp : 定义控制台应用程序的入口点。 +// + +#include "stdafx.h" +#include "lib_acl.h" +#include "string.hpp" +#include "db_mysql.hpp" + +// 查询表数据 +static int tbl_select(acl::db_handle& db) +{ + const char* sql = "select value, category, type from black_white_list"; + + if (db.sql_select(sql) == false) + { + printf("select sql error\r\n"); + return (-1); + } + + printf("\r\n---------------------------------------------------\r\n"); + + const acl::db_rows* result = db.get_result(); + if (result) + { + const std::vector& rows = result->get_rows(); + for (size_t i = 0; i < rows.size(); i++) + { + const acl::db_row* row = rows[i]; + for (size_t j = 0; j < row->length(); j++) + printf("%s, ", (*row)[j]); + printf("\r\n"); + } + } + + int ret = (int) db.length(); + + // 释放查询结果 + db.free_result(); + return (ret); +} + +int main(void) +{ + + const char* dbaddr = "127.0.0.1:16811"; + const char* dbname = "inc365_antispam_db"; + const char* dbuser = "root", *dbpass = ""; + acl::db_mysql db(dbaddr, dbname, dbuser, dbpass); + + // 允许将错误日志输出至屏幕 + acl_msg_stdout_enable(1); + + if (db.open(NULL) == false) + { + printf("open db(%s) error\r\n", dbname); + getchar(); + return 1; + } + + printf("open db %s ok\r\n", dbname); + + int ret = tbl_select(db); + if (ret >= 0) + { + printf(">>select ok\r\n"); + } + else + printf(">>select error\r\n"); + + printf("mysqlclient lib's version: %ld, info: %s\r\n", + db.mysql_libversion(), db.mysql_client_info()); + return 0; +} diff --git a/lib_acl_cpp/samples/mysql2/mysql.vcproj b/lib_acl_cpp/samples/mysql2/mysql.vcproj new file mode 100644 index 000000000..aa6e61482 --- /dev/null +++ b/lib_acl_cpp/samples/mysql2/mysql.vcproj @@ -0,0 +1,275 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_acl_cpp/samples/mysql2/stdafx.cpp b/lib_acl_cpp/samples/mysql2/stdafx.cpp new file mode 100644 index 000000000..3f9a6a49e --- /dev/null +++ b/lib_acl_cpp/samples/mysql2/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// mysql.pch 将成为预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + +// TODO: 在 STDAFX.H 中 +//引用任何所需的附加头文件,而不是在此文件中引用 diff --git a/lib_acl_cpp/samples/mysql2/stdafx.h b/lib_acl_cpp/samples/mysql2/stdafx.h new file mode 100644 index 000000000..b98553f2c --- /dev/null +++ b/lib_acl_cpp/samples/mysql2/stdafx.h @@ -0,0 +1,11 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是常用但不常更改的项目特定的包含文件 +// + +#pragma once + + +#include +//#include + +// TODO: 在此处引用程序要求的附加头文件 diff --git a/lib_acl_cpp/samples/mysql2/valgrind.sh b/lib_acl_cpp/samples/mysql2/valgrind.sh new file mode 100644 index 000000000..6241fb150 --- /dev/null +++ b/lib_acl_cpp/samples/mysql2/valgrind.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +valgrind --tool=memcheck --leak-check=full --show-reachable=yes -v ./mysql_test diff --git a/lib_acl_cpp/samples/rfc2047/Makefile b/lib_acl_cpp/samples/rfc2047/Makefile new file mode 100644 index 000000000..7de4a1570 --- /dev/null +++ b/lib_acl_cpp/samples/rfc2047/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = rfc2047 diff --git a/lib_acl_cpp/samples/rfc2047/main.cpp b/lib_acl_cpp/samples/rfc2047/main.cpp new file mode 100644 index 000000000..9d59c1146 --- /dev/null +++ b/lib_acl_cpp/samples/rfc2047/main.cpp @@ -0,0 +1,360 @@ +#include +#include +#include + +#ifdef WIN32 +#include "vld.h" // win32 下进行内存泄露检测 +#include "lib_acl.h" +#else +#include +#endif +#include "acl_cpp/stdlib/string.hpp" +#include "acl_cpp/stream/fstream.hpp" +#include "acl_cpp/stream/ifstream.hpp" +#include "acl_cpp/stream/ofstream.hpp" +#include "acl_cpp/mime/rfc2047.hpp" + +static int isvalidChinese(char c1, char c2) +{ + if ((c1 & 0x80) == 0 || (c2 & 0x80) == 0) + return (0); + else + return (1); + if (!((c2)&0xc0) ) + return (0); +} + +// 获得有效的汉字字符 +static int get_valid_string(char *src, unsigned dlen, char *buffer, unsigned bsize) +{ + int n = 0; + unsigned char *src_ptr = NULL; + unsigned char *obj_ptr = NULL; + unsigned char *ch = NULL; + int firstChineseChar = 0; + char lastChar = 0; + + if (src == NULL || dlen == 0 || buffer == NULL || bsize == 0) + return -1; + + obj_ptr = (unsigned char *)buffer; + + src_ptr = (unsigned char *)src; + + /* 为最后一个 '\0' 留出一个字节空间 */ + n = bsize - 1; + + for (ch = src_ptr; *ch; ch++) { + if (ch - src_ptr >= n) + break; + + /* 先判断前一个字节最高位是否为 1 */ + if (firstChineseChar) { + if (!isvalidChinese(lastChar,*ch)) + break; + + //if (ch - src_ptr >= n + 1) + // break; + + firstChineseChar = 0; + /* 先拷贝前一个字节 */ + *obj_ptr++ = lastChar; + *obj_ptr++ = *ch; + } + else if ((*ch) & 0x80) { + /* 说明当前字节的最高位为 1, 且有可能是汉字的第一个字节 */ + firstChineseChar = 1; + lastChar = *ch; + } + else + *obj_ptr++ = *ch; + } + *obj_ptr = 0; + return 0; +} + +static void rfc2047_test(acl::rfc2047& rfc2047, const char* s) +{ + acl::string out; + + printf("\n"); + printf("------------------ charset to gb2312 begin -------------\n"); + rfc2047.reset(true); + rfc2047.decode_update(s, (int) strlen(s)); + if (rfc2047.decode_finish("gb18030", &out)) + { + char buf[50]; + + get_valid_string(out.c_str(), (unsigned) out.length(), + buf, (unsigned) sizeof(buf) - 3); + printf(">>> |%s|, len(%d)\n", buf, (int) strlen(buf)); + + rfc2047.debug_rfc2047(); + } + else + printf(">>error: %s\n", out.c_str()); + printf("------------------ charset to gb2312 end ---------------\n"); +} + +static void rfc2047_test2(acl::rfc2047& rfc2047, const char* s) +{ + acl::string out; + + printf("\n"); + printf("------------------ charset to utf-8 begin --------------\n"); + rfc2047.reset(true); + rfc2047.decode_update(s, (int) strlen(s)); + if (rfc2047.decode_finish("utf-8", &out)) + { + printf(">>> {%s}\n", out.c_str()); + rfc2047.debug_rfc2047(); + + acl::fstream fp; + if (fp.open_trunc("test.html")) + { + fp << "\r\n" + << "\r\n" + << "\r\n" + << "\r\n" + << "\r\n"; + fp.write(out.c_str(), out.length()); + fp << "\r\n\r\n"; + } + } + else + printf(">>error: %s\n", out.c_str()); + printf("------------------ charset to utf-8 end ----------------\n"); +} + +static void rfc2047_test_encode(const char* s) +{ + acl::string out; + acl::rfc2047 rfc2047(false, false); + + rfc2047.encode_update(s, (int) strlen(s), &out); + rfc2047.encode_update(s, (int) strlen(s), &out, "gb2312", 'Q'); + rfc2047.encode_finish(&out); + printf("rfc2047 encoding result: %s\n", out.c_str()); +} + +static void rfc2047_test_file(acl::rfc2047& rfc2047, const char* filepath) +{ + acl::string buf; + + if (acl::ifstream::load(filepath, &buf) == false) + { + printf("load file %s error(%s)\r\n", filepath, strerror(errno)); + return; + } + printf(">>src: \r\n|%s|\r\n", buf.c_str()); + + rfc2047.decode_update(buf.c_str(), (int) buf.length()); + + buf.clear(); + rfc2047.decode_finish("gb18030", &buf); + printf(">>result:\r\n|%s|\r\n", buf.c_str()); + + acl::ofstream out; + if (out.open_write("out.txt") == false) + { + printf("open out.txt error\r\n"); + return; + } + + out.write(buf); + + const std::list& entries = rfc2047.get_list(); + std::list::const_iterator cit = entries.begin(); + for (; cit != entries.end(); cit++) + { + if ((*cit)->pCharset && !(*cit)->pCharset->empty()) + { + if ((*cit)->pData) + printf("data: %s, ", (*cit)->pData->c_str()); + if ((*cit)->pCharset) + printf("charset: %s, ", (*cit)->pCharset->c_str()); + printf("code: %c\r\n", (*cit)->coding); + } + } +} + +static void usage(const char* procname) +{ + printf("usage: %s -h[help] -d src -e src -f file\n", procname); +} + +int main(int argc, char* argv[]) +{ + acl::rfc2047 rfc2047(false); + + int ch; + + while ((ch = getopt(argc, argv, "hd:e:f:")) > 0) + { + switch (ch) + { + case 'h': + usage(argv[0]); + return (0); + case 'd': + rfc2047_test(rfc2047, optarg); + return (0); + case 'e': + rfc2047_test_encode(optarg); + return (0); + case 'f': + rfc2047_test_file(rfc2047, optarg); + return (0); + default: + break; + } + } + + ///////////////////////////////////////////////////////////////////// + + const char* s = "[=?UTF-8?Q?=E7=BC=BA=E9=99=B7=20602?=]=?UTF-8?Q?=20=E6=89=80=E5=B1=9E=E9=83=A8=E9=97=A8=E5=BA=94=E4=B8=BA=E4=B8=AD=E6=96=87?="; + acl::string out; + const char* ptr = s, *end = s + strlen(s); + + while (ptr < end) + { + rfc2047.decode_update(ptr, 1); + ptr++; + } + + if (rfc2047.decode_finish("gb2312", &out)) + { + printf(">>ok\n"); + printf("%s\n", out.c_str()); + } + else + printf(">>error: %s\n", out.c_str()); + + ///////////////////////////////////////////////////////////////////// + + s = "=?GB2312?B?yO28/r+qt6IyLjC087vh\r\n" + " IM3FubrT\r\n" + " xbvd1tA=?="; + rfc2047_test(rfc2047, s); + + ///////////////////////////////////////////////////////////////////// + + s = "Re: [hiphop-php-dev] Why does hiphop delete my output directory?"; + rfc2047_test(rfc2047, s); + + ///////////////////////////////////////////////////////////////////// + + s = " =?UTF-8?\r\n" + " Q?<=E5=B9=BF=E5=91=8A>_iPho?=\r\n" + " =?UTF\r\n" + " -8?Q?ne_4_=E7=8E=B0=E5=B7\r\n" + " =B2=E5=8F=91=E5=94=AE?="; + rfc2047_test(rfc2047, s); + + ///////////////////////////////////////////////////////////////////// + + s = " =\r\n" + " ?\r\n" + " U\r\n" + " T\r\n" + " F\r\n" + " -8?\r\n" + " Q?\r\n" + " <=E5=B9=BF=E5=91=8A>\r\n" + " _iPho?\r\n" + " =\r\n" + " =?UTF\r\n" + " -8?\r\n" + " Q?ne_4_=E7\r\n" + " =8E=B0=E5=B7\r\n" + " =B2=E5=8F=91=E5=94=AE?\r\n" + " ="; + rfc2047_test(rfc2047, s); + + ///////////////////////////////////////////////////////////////////// + + s = "\"=?gb2\r\n312?B?yMvBpt\r\nfK1\r\nLSyvw=\r\n=\r\n?=\" "; + rfc2047_test(rfc2047, s); + + ///////////////////////////////////////////////////////////////////// + +#if 1 + const char* s1 = "=?gb2312?B?ILL9wfrN+KOsyei8xqOsxr3D5snovMajrLmk0rXJ6LzGo6zN+NKzyei8xqOssg==?=" + "=?GB2312?B?y8bXyei8xqOssvrGt8novMajrNPK1rfTys/kt/7O8aOs08q8/s3GueOjrMr9?=" + "=?GB2312?B?vt271ri0o6y158TUzqy7pKOstefE1New0N6jrMnPw8W3/s7xo6w=?="; +#else + const char* s1 = "=?gb2312?B?sg==?=" + "=?gb2312?B?y8bX?="; +#endif + rfc2047_test(rfc2047, s1); + ///////////////////////////////////////////////////////////////////// + +#if 1 + const char* s2 = "=?gb2312?Q?=D0=EC=B8=D5=BB=D4 ?=" + "=?gb2312?B?LCDl0NKjz8ksIA==?==?utf-8?B?5Lit5Zu95Lq65rCR5YWx5ZKM5Zu9?=" + "=?BIG5?B?pKSw6qRIpcGmQKlNsOo=?=" + "=?gb2312?Q?=D0=EC=B8=D5=BB=D4 ?="; +#elif 1 + const char* s2 = "=?utf-8?B?5Lit5Zu95Lq65rCR5YWx5ZKM5Zu9?="; +#else + const char* s2 = "=?BIG5?B?pKSw6qRIpcGmQKlNsOo=?=" + "=?gb2312?Q?=D0=EC=B8=D5=BB=D4 ?="; +#endif + rfc2047_test(rfc2047, s2); + rfc2047_test2(rfc2047, s2); + + ///////////////////////////////////////////////////////////////////// + + const char* s3 = "=?UTF-8?B?55uR5o6n5a6d?= "; + rfc2047_test(rfc2047, s3); + + ///////////////////////////////////////////////////////////////////// + + const char* s4 = "=?gb2312?B?ILG+uavLvs6qwKm088rQs6G+rdOq0qrV0tPQvq28w8q1waa1" + "xL/Nu6fAtLmy0w==?==?GB2312?B?w7+qt6LK0LOhu/LWsb3TwvLC9Lj4v827pw==?="; + rfc2047_test(rfc2047, s4); + + ///////////////////////////////////////////////////////////////////// + + const char* s5 = "=?GB2312?B?zOzT7sb7w7M=?= "; + rfc2047_test(rfc2047, s5); + + ///////////////////////////////////////////////////////////////////// + + const char* s6 = "=?utf-8?B?6LaF57qn5L2O5Lu377yB57ud5a+55aSn54mM77yB5LuFNDblhYPmiqLotK0=?= =?utf-8?B?5paw54mI5YWw6JS75rC05Lu957yY6IiS57yT5p+U6IKk5ZWr5Zax5Lit5qC3?= =?utf-8?B?77yBM+aKmOaKoui0rei2hee7j+WFuOmbhemhv+aZmuWuieWlveecoOa7iw==?= =?utf-8?B?5YW76Zyc5ZCM5pyf6L+b6KGM77yB?="; + rfc2047_test(rfc2047, s6); + + ///////////////////////////////////////////////////////////////////// + + const char* s7 = "=?UTF-8?B?MjAxMeW5tOaYpeiKguelneemjw==?="; + rfc2047_test(rfc2047, s7); + + ///////////////////////////////////////////////////////////////////// + + const char* s8 = "=?GB18030?Q?=BE=B4=F6=A9_=D3=A6=C6=B8=D6=B0=CE=BB:_?==?GB18030?Q?=CF=FA=CA=DB=B4=FA=B1=ED_(201?==?GB18030?Q?1-05-31=C0=B4=D7=D401HR.COM)?="; + rfc2047_test(rfc2047, s8); + + ///////////////////////////////////////////////////////////////////// + + const char* s9 = "=?GB18030?Q?=B3=C2=B3=AC_=D3=A6=C6=B8=D6=B0=CE=BB:_J?=\r\n" + " =?GB18030?Q?AVA=B8=DF=BC=B6=B9=A4=B3=CC=CA=A6_(?=\r\n" + " =?GB18030?Q?2011-05-31=C0=B4=D7=D401HR.COM)?=\r\n"; + rfc2047_test(rfc2047, s9); + + ///////////////////////////////////////////////////////////////////// + + const char* s10 = "Subject: =?utf-8?B?54ix576O5bCx5p2l77yB5LuFNTjlhYPvvIHkuqvljp/ku7cx?=\r\n" + " =?utf-8?B?MTgw5YWD44CO5Lid55Ge57yHU1BB55Sf5rS76aaG44CP55qE576O5a65?=\r\n" + " =?utf-8?B?576O5L2T5aWX6aSQ77yI5piO55y454m55pWI5oqk55CGLzUw5YiG6ZKf?=\r\n" + " =?utf-8?B?K+iDjOmDqOS4ieeEpuiIkueptC81MOWIhumSnyvnvo7og7jkv53lgaXo?=\r\n" + " =?utf-8?B?r77nqIsvNTDliIbpkp8r5paw5pWI5rC05ram5Lqu55m95oqk55CGLzgw?=\r\n" + " =?utf-8?B?5YiG6ZKf77yJ77yM6K6p576O5Li95p2l55qE6LGq5peg5Y6L5Yqb77yB?=\r\n" + " =?utf-8?B?\?=\r\n"; + + rfc2047_test(rfc2047, s10); + + ///////////////////////////////////////////////////////////////////// + + getchar(); + return (0); +} diff --git a/lib_acl_cpp/samples/rfc2047/rfc2047.vcproj b/lib_acl_cpp/samples/rfc2047/rfc2047.vcproj new file mode 100644 index 000000000..bd41d9e63 --- /dev/null +++ b/lib_acl_cpp/samples/rfc2047/rfc2047.vcproj @@ -0,0 +1,240 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_acl_cpp/samples/rfc2047/rfc2047.vcxproj b/lib_acl_cpp/samples/rfc2047/rfc2047.vcxproj new file mode 100644 index 000000000..5cb8c7ba0 --- /dev/null +++ b/lib_acl_cpp/samples/rfc2047/rfc2047.vcxproj @@ -0,0 +1,189 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + Releasedll + Win32 + + + Release + Win32 + + + + {503AFD46-DF2F-4D2B-8584-60AD2007D2BE} + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + true + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + ws2_32.lib;vld.lib;lib_acl_vc2010d.lib;lib_acl_cpp_vc2010d.lib;%(AdditionalDependencies) + $(OutDir)rfc2047.exe + ..\..\..\lib\win32;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)rfc2047.pdb + Console + MachineX86 + + + + + + + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;lib_acl_vc2010.lib;lib_acl_cpp_vc2010.lib;%(AdditionalDependencies) + $(OutDir)rfc2047.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + + + + + + + Disabled + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + lib_acl_d.lib;lib_acl_cpp_d.lib;ws2_32.lib;vld.lib;%(AdditionalDependencies) + $(OutDir)rfc2047.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)rfc2047.pdb + Console + MachineX86 + + + + + Disabled + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + lib_acl.lib;lib_acl_cpp.lib;ws2_32.lib;vld.lib;%(AdditionalDependencies) + $(OutDir)rfc2047.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)rfc2047.pdb + Console + MachineX86 + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib_acl_cpp/samples/rfc2047/rfc2047_vc2012.vcxproj b/lib_acl_cpp/samples/rfc2047/rfc2047_vc2012.vcxproj new file mode 100644 index 000000000..c39e30e5c --- /dev/null +++ b/lib_acl_cpp/samples/rfc2047/rfc2047_vc2012.vcxproj @@ -0,0 +1,194 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + Releasedll + Win32 + + + Release + Win32 + + + + {503AFD46-DF2F-4D2B-8584-60AD2007D2BE} + Win32Proj + rfc2047 + + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + true + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + ws2_32.lib;vld.lib;lib_acl_vc2012d.lib;lib_acl_cpp_vc2012d.lib;%(AdditionalDependencies) + $(OutDir)rfc2047.exe + ..\..\..\lib\win32;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)rfc2047.pdb + Console + MachineX86 + + + + + + + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;lib_acl_vc2012.lib;lib_acl_cpp_vc2012.lib;%(AdditionalDependencies) + $(OutDir)rfc2047.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + + + + + + + Disabled + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + lib_acl_d.lib;lib_acl_cpp_d.lib;ws2_32.lib;vld.lib;%(AdditionalDependencies) + $(OutDir)rfc2047.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)rfc2047.pdb + Console + MachineX86 + + + + + Disabled + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + lib_acl.lib;lib_acl_cpp.lib;ws2_32.lib;vld.lib;%(AdditionalDependencies) + $(OutDir)rfc2047.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)rfc2047.pdb + Console + MachineX86 + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib_acl_cpp/samples/rfc2047/test1.txt b/lib_acl_cpp/samples/rfc2047/test1.txt new file mode 100644 index 000000000..20c69f71f --- /dev/null +++ b/lib_acl_cpp/samples/rfc2047/test1.txt @@ -0,0 +1,2 @@ +=?utf-8?B?r77nqIsvNTDliIbpkp8r5paw5pWI5rC05ram5Lqu55m95oqk55CGLzgw?= +=?utf-8?B?5YiG6ZKf77yJ77yM6K6p576O5Li95p2l55qE6LGq5peg5Y6L5Yqb77yB?= diff --git a/lib_acl_cpp/samples/rfc2047/test2.txt b/lib_acl_cpp/samples/rfc2047/test2.txt new file mode 100644 index 000000000..8add50054 --- /dev/null +++ b/lib_acl_cpp/samples/rfc2047/test2.txt @@ -0,0 +1,7 @@ +=?utf-8?B?54ix576O5bCx5p2l77yB5LuFNTjlhYPvvIHkuqvljp/ku7cx?= +=?utf-8?B?MTgw5YWD44CO5Lid55Ge57yHU1BB55Sf5rS76aaG44CP55qE576O5a65?= +=?utf-8?B?576O5L2T5aWX6aSQ77yI5piO55y454m55pWI5oqk55CGLzUw5YiG6ZKf?= +=?utf-8?B?K+iDjOmDqOS4ieeEpuiIkueptC81MOWIhumSnyvnvo7og7jkv53lgaXo?= +=?utf-8?B?r77nqIsvNTDliIbpkp8r5paw5pWI5rC05ram5Lqu55m95oqk55CGLzgw?= +=?utf-8?B?5YiG6ZKf77yJ77yM6K6p576O5Li95p2l55qE6LGq5peg5Y6L5Yqb77yB?= +=?utf-8?B??= diff --git a/lib_acl_cpp/samples/rfc2047/test3.txt b/lib_acl_cpp/samples/rfc2047/test3.txt new file mode 100644 index 000000000..a522983c4 --- /dev/null +++ b/lib_acl_cpp/samples/rfc2047/test3.txt @@ -0,0 +1 @@ +=?utf-8?B?54ix576O5bCx5p2l77yB5LuFNTjlhYPvvIHkuqvljp/ku7cx?= =?utf-8?B?MTgw5YWD44CO5Lid55Ge57yHU1BB55Sf5rS76aaG44CP55qE576O5a65?= =?utf-8?B?576O5L2T5aWX6aSQ77yI5piO55y454m55pWI5oqk55CGLzUw5YiG6ZKf?= =?utf-8?B?K+iDjOmDqOS4ieeEpuiIkueptC81MOWIhumSnyvnvo7og7jkv53lgaXo?= =?utf-8?B?r77nqIsvNTDliIbpkp8r5paw5pWI5rC05ram5Lqu55m95oqk55CGLzgw?= =?utf-8?B?5YiG6ZKf77yJ77yM6K6p576O5Li95p2l55qE6LGq5peg5Y6L5Yqb77yB?= =?utf-8?B??= diff --git a/lib_acl_cpp/samples/rfc2047/valgrind.sh b/lib_acl_cpp/samples/rfc2047/valgrind.sh new file mode 100644 index 000000000..775be7971 --- /dev/null +++ b/lib_acl_cpp/samples/rfc2047/valgrind.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +#valgrind --tool=memcheck --leak-check=yes -v ./rfc2047 -e "中国人民" +valgrind --tool=memcheck --leak-check=yes -v ./rfc2047 diff --git a/lib_acl_cpp/samples/rfc822/Makefile b/lib_acl_cpp/samples/rfc822/Makefile new file mode 100644 index 000000000..80b8687a8 --- /dev/null +++ b/lib_acl_cpp/samples/rfc822/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = rfc822 diff --git a/lib_acl_cpp/samples/rfc822/main.cpp b/lib_acl_cpp/samples/rfc822/main.cpp new file mode 100644 index 000000000..e81c42f37 --- /dev/null +++ b/lib_acl_cpp/samples/rfc822/main.cpp @@ -0,0 +1,124 @@ +#include "acl_cpp/mime/rfc822.hpp" + +int main(void) +{ + acl::rfc822 rfc; + + const char* addrs = "=?gb2312?B?1dSx+A==?= ;\r\n" + "\t\"=?GB2312?B?t+vBosn6?=\" ;\r\n" + " \"zhengshuxin1\" \"zhengshuxin2\" ;\r\n" + "\"zhengshuxin3\";\"zhengshuxin4\" ;" + ";"; + const std::list& addr_list = rfc.parse_addrs(addrs); + std::list::const_iterator cit = addr_list.begin(); + for (; cit != addr_list.end(); cit++) + { + const acl::rfc822_addr* addr = *cit; + printf("addr: %s, comment: %s\n", addr->addr, + addr->comment ? addr->comment : "null"); + } + + printf("===================================================\r\n"); + const std::list& addr_list2 = rfc.parse_addrs("helloworld"); + if (addr_list2.empty()) + printf("Failed\n"); + else + printf("Ok\n"); + printf("===================================================\r\n"); + + const char* addrs2[] = { + "=?gb2312?B?1dSx+A==?= ;", + "\"=?GB2312?B?t+vBosn6?=\" ;", + "\"zhengshuxin1\" \"zhengshuxin2\" ;", + "\"zhengshuxin3\";\"zhengshuxin4\" ;", + ";", + "", + "\"SYD - Rywak, Ray\" ;", + NULL + }; + + for (int i = 0; addrs2[i] != NULL; i++) + { + const acl::rfc822_addr* addr = rfc.parse_addr(addrs2[i]); + printf("addr: %s, comment: %s\n", addr->addr, + addr->comment ? addr->comment : "null"); + } + + printf("===================================================\r\n"); + + time_t now = time(NULL); + char buf[64]; + rfc.mkdate(now, buf, sizeof(buf), acl::tzone_gmt); + printf(">>date: %s, %ld\n", buf, now); + + time_t t = rfc.parse_date(buf); + printf(">> now: %ld\n", t); + + printf("===================================================\r\n"); + struct ADDR_CHECK + { + const char* addr; + bool ret; + }; + const ADDR_CHECK addr3[] = { + { "=?gb2312?B?1dSx+A==?= ", true }, + { "\"=?GB2312?B?t+vBosn6?=\" ;", true }, + { "\"=?GB2312?B?t+vBosn6?=\" ,", true }, + { "\"=?GB2312?B?t+vBosn6?=\" ;", true }, + { "\"zhengshuxin1\" \"zhengshuxin2\" ;", true }, + { "\"zhengshuxin1, ;zhengshuxin2\" ;", true }, + { ";", true }, + { "", true }, + { "xxx@xxx.xxx", true }, + { "xxx.xxx@xxx.xxx.xxx", true }, + { "x_x-x@xxx.xxx", true }, + { "x._x@xxx.xxx", true }, + { "x@x.x", true }, + { "@xxx.xxx", false }, + { "_xxx@xxx.xxx", false }, + { "xx_@xx.xx", false }, + { "xx@", false }, + { "xx@x", false }, + { "xx@_x.xx", false }, + { "xx@.x.xx", false }, + { "xx@xx.xx.", false }, + { "xx@xx_xx", false }, + { "xx@_", false }, + { "@@xx.xx@xx.xx", false }, + { "中@xx.xx", false }, + { "~@xx.xx", false }, + { "#@xx.xx", false }, + { "*@xx.xx", false }, + { ";xxx@xxx.xxx", false }, + { ",xxx@xxx.xxx", false }, + { " ;xxx@xxx.xxx", false }, + { "x;xxx@xxx.xxx", false }, + { "\";\" ", true }, + { "&xxx@xxx.xxx", false }, + { "xxx_@xxx.xxx", false }, + { "xxx.@xxx.xxx", false }, + + { NULL, false } + }; + + int nerror = 0; + for (int i = 0; addr3[i].addr != NULL; i++) + { + if (rfc.check_addr(addr3[i].addr) != addr3[i].ret) + { + nerror++; + printf("addr3[%d]: %s, check failed ...\r\n", + i, addr3[i].addr); + } + } + if (nerror == 0) + printf("check mail addr ok...\r\n"); + else + printf("check mail addr failed...\r\n"); + +#ifdef WIN32 + printf("enter any key to exit ...\r\n"); + getchar(); +#endif + return (0); +} diff --git a/lib_acl_cpp/samples/rfc822/rfc822.vcproj b/lib_acl_cpp/samples/rfc822/rfc822.vcproj new file mode 100644 index 000000000..3e8ccb45e --- /dev/null +++ b/lib_acl_cpp/samples/rfc822/rfc822.vcproj @@ -0,0 +1,236 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_acl_cpp/samples/rfc822/valgrind.sh b/lib_acl_cpp/samples/rfc822/valgrind.sh new file mode 100644 index 000000000..af4d5f352 --- /dev/null +++ b/lib_acl_cpp/samples/rfc822/valgrind.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +valgrind --tool=memcheck --leak-check=yes -v ./rfc822 diff --git a/lib_acl_cpp/samples/rpc_download/Makefile b/lib_acl_cpp/samples/rpc_download/Makefile new file mode 100644 index 000000000..7dd32fa2b --- /dev/null +++ b/lib_acl_cpp/samples/rpc_download/Makefile @@ -0,0 +1,3 @@ +include ../Makefile.in +EXTLIBS = -lz +PROG = rpc_download diff --git a/lib_acl_cpp/samples/rpc_download/ReadMe.txt b/lib_acl_cpp/samples/rpc_download/ReadMe.txt new file mode 100644 index 000000000..02186bb8a --- /dev/null +++ b/lib_acl_cpp/samples/rpc_download/ReadMe.txt @@ -0,0 +1,31 @@ +======================================================================== + 控制台应用程序 : rpc_download 项目概况 +======================================================================== + +应用程序向导已为您创建了这个 rpc_download 应用程序。 +此文件包含组成 rpc_download 应用程序 +的每个文件的内容摘要。 + + +rpc_download.vcproj + 这是用应用程序向导生成的 VC++ 项目的主项目文件。 + 它包含有关生成此文件的 Visual C++ 版本的信息,以及 + 有关用应用程序向导选择的 + 平台、配置和项目功能的信息。 + +rpc_download.cpp + 这是主应用程序源文件。 + +///////////////////////////////////////////////////////////////////////////// +其他标准文件: + +StdAfx.h、StdAfx.cpp + 这些文件用于生成名为 rpc_download.pch + 的预编译头(PCH)文件以及名为 StdAfx.obj 的预编译类型文件。 + +///////////////////////////////////////////////////////////////////////////// +其他注释: + +应用程序向导使用 "TODO:" 注释指示应添加或自定义的源代码部分。 + +///////////////////////////////////////////////////////////////////////////// diff --git a/lib_acl_cpp/samples/rpc_download/rpc_download.cpp b/lib_acl_cpp/samples/rpc_download/rpc_download.cpp new file mode 100644 index 000000000..5517d64c4 --- /dev/null +++ b/lib_acl_cpp/samples/rpc_download/rpc_download.cpp @@ -0,0 +1,186 @@ +// rpc_download.cpp : 定义控制台应用程序的入口点。 +// + +#include "stdafx.h" +#include +#include "acl_cpp/lib_acl.hpp" + +using namespace acl; + +typedef enum +{ + CTX_T_CONTENT_LENGTH, + CTX_T_PARTIAL_LENGTH, + CTX_T_END +} ctx_t; + +struct DOWN_CTX +{ + ctx_t type; + int length; +}; + +static int __download_count = 0; + +class http_down : public rpc_request +{ +public: + http_down(aio_handle& handle, const char* addr, const char* url) + : handle_(handle) + , addr_(addr) + , url_(url) + , error_(false) + , total_read_(0) + , content_length_(0) + {} + ~http_down() {} +protected: + + // 子线程处理函数 + void rpc_run() + { + http_request req(addr_); // HTTP 请求对象 + + // 设置 HTTP 请求头信息 + req.request_header().set_url(url_.c_str()) + .set_content_type("text/html") + .set_host(addr_.c_str()) + .set_method(HTTP_METHOD_GET); + + // 测试用,显示 HTTP 请求头信息内容 + string header; + req.request_header().build_request(header); + printf("request: %s\r\n", header.c_str()); + + // 发送 HTTP 请求数据 + if (req.request(NULL, 0) == false) + { + printf("send request error\r\n"); + error_ = false; + return; + } + + // 获得 HTTP 请求的连接对象 + http_client* conn = req.get_client(); + assert(conn); + DOWN_CTX* ctx = new DOWN_CTX; + ctx->type = CTX_T_CONTENT_LENGTH; + + // 获得 HTTP 响应数据的数据体长度 + ctx->length = (int) conn->body_length(); + content_length_ = ctx->length; + + // 通知主线程 + rpc_signal(ctx); + + char buf[8192]; + while (true) + { + // 读 HTTP 响应数据体 + int ret = req.get_body(buf, sizeof(buf)); + if (ret <= 0) + { + ctx = new DOWN_CTX; + ctx->type = CTX_T_END; + ctx->length = ret; + // 通知主线程 + rpc_signal(ctx); + break; + } + ctx = new DOWN_CTX; + ctx->type = CTX_T_PARTIAL_LENGTH; + ctx->length = ret; + // 通知主线程 + rpc_signal(ctx); + } + } + + // 主线程处理过程,收到子线程任务完成的消息 + void rpc_onover() + { + printf("%s: read over now, total read: %d, content-length: %d\r\n", + addr_.c_str(), total_read_, content_length_); + + // 当 HTTP 响应都完成时,通知主线程停止事件循环过程 + __download_count--; + if (__download_count == 0) + handle_.stop(); + } + + // 主线程处理过程,收到子线程的通知消息 + void rpc_wakeup(void* ctx) + { + DOWN_CTX* down_ctx = (DOWN_CTX*) ctx; + switch (down_ctx->type) + { + case CTX_T_CONTENT_LENGTH: + printf("%s: content-length: %d\r\n", + addr_.c_str(), down_ctx->length); + break; + case CTX_T_PARTIAL_LENGTH: + total_read_ += down_ctx->length; + printf("%s: partial-length: %d, total read: %d\r\n", + addr_.c_str(), down_ctx->length, total_read_); + break; + case CTX_T_END: + printf("%s: read over\r\n", addr_.c_str()); + break; + default: + printf("%s: ERROR\r\n", addr_.c_str()); + break; + } + delete down_ctx; + } +private: + aio_handle& handle_; + string addr_; + string url_; + bool error_; + int total_read_; + int content_length_; +}; + +static void run(void) +{ + aio_handle handle; + rpc_service* service = new rpc_service(10); // 创建 rpc 服务对象 + + // 打开消息服务器 + if (service->open(&handle) == false) + { + printf("open service error: %s\r\n", last_serror()); + return; + } + + // 下载页面内容 + + http_down down1(handle, "www.sina.com.cn:80", "http://www.sina.com.cn/"); + service->rpc_fork(&down1); // 发起一个阻塞会话过程 + __download_count++; + + http_down down2(handle, "www.hexun.com:80", "/"); + service->rpc_fork(&down2); // 发起第二个阻塞会话过程 + __download_count++; + + // 异步事件循环过程 + while (true) + { + if (handle.check() == false) + break; + } + + delete service; + handle.check(); // 保证释放所有延迟关闭的异步对象 +} + +int main(void) +{ +#ifdef WIN32 + acl_cpp_init(); +#endif + + run(); + printf("Enter any key to continue\r\n"); + getchar(); + return 0; +} diff --git a/lib_acl_cpp/samples/rpc_download/rpc_download.vcproj b/lib_acl_cpp/samples/rpc_download/rpc_download.vcproj new file mode 100644 index 000000000..b8e112178 --- /dev/null +++ b/lib_acl_cpp/samples/rpc_download/rpc_download.vcproj @@ -0,0 +1,277 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_acl_cpp/samples/rpc_download/stdafx.cpp b/lib_acl_cpp/samples/rpc_download/stdafx.cpp new file mode 100644 index 000000000..08ee7e9b1 --- /dev/null +++ b/lib_acl_cpp/samples/rpc_download/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// rpc_download.pch 将成为预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + +// TODO: 在 STDAFX.H 中 +//引用任何所需的附加头文件,而不是在此文件中引用 diff --git a/lib_acl_cpp/samples/rpc_download/stdafx.h b/lib_acl_cpp/samples/rpc_download/stdafx.h new file mode 100644 index 000000000..9024458d0 --- /dev/null +++ b/lib_acl_cpp/samples/rpc_download/stdafx.h @@ -0,0 +1,11 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是常用但不常更改的项目特定的包含文件 +// + +#pragma once + + +//#include +//#include + +// TODO: 在此处引用程序要求的附加头文件 diff --git a/lib_acl_cpp/samples/rpc_download/valgrind.sh b/lib_acl_cpp/samples/rpc_download/valgrind.sh new file mode 100644 index 000000000..df65b6049 --- /dev/null +++ b/lib_acl_cpp/samples/rpc_download/valgrind.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +valgrind --tool=memcheck --leak-check=yes -v ./rpc_download diff --git a/lib_acl_cpp/samples/session/Makefile b/lib_acl_cpp/samples/session/Makefile new file mode 100644 index 000000000..2c685ca61 --- /dev/null +++ b/lib_acl_cpp/samples/session/Makefile @@ -0,0 +1,3 @@ +include ../Makefile.in +#EXTLIBS = -lpolarssl +PROG = session diff --git a/lib_acl_cpp/samples/session/session.cpp b/lib_acl_cpp/samples/session/session.cpp new file mode 100644 index 000000000..71dcab670 --- /dev/null +++ b/lib_acl_cpp/samples/session/session.cpp @@ -0,0 +1,148 @@ +// session.cpp : 定义控制台应用程序的入口点。 +// + +#include "stdafx.h" +#include "acl_cpp/acl_cpp_init.hpp" +#include "acl_cpp/session/memcache_session.hpp" + +using namespace acl; + +#ifdef WIN32 +#define snprintf _snprintf +#endif + +static int session_test1(const char* addr, int n) +{ + memcache_session s(addr); + + char name[32], value[32]; + + printf(">>>>>>>>>>>>> set session <<<<<<<<<<<<<<<<<<<\r\n"); + for (int i = 0; i < n; i++) + { + snprintf(name, sizeof(name), "name-%d", i); + snprintf(value, sizeof(value), "value-%d", i); + if (s.set(name, value) == 0) + { + printf("set error, name: %s, value: %s\r\n", name, value); + return 1; + } + printf("set ok, name: %s, value: %s\r\n", name, value); + } + + printf("\r\n>>>>>>>>>>>>> get session <<<<<<<<<<<<<<<<<<<\r\n"); + for (int i = 0; i < n; i++) + { + snprintf(name, sizeof(name), "name-%d", i); + snprintf(value, sizeof(value), "value-%d", i); + const char* ptr = s.get(name); + if (ptr == NULL || *ptr == 0 || strcmp(ptr, value) != 0) + { + printf("get error, name: %s\r\n", name); + return 1; + } + printf("get ok, name: %s, value: %s\r\n", name, ptr); + } + + printf("\r\n>>>>>>>>>>>>> del session <<<<<<<<<<<<<<<<<<<\r\n"); + for (int i = 0; i < n; i++) + { + snprintf(name, sizeof(name), "name-%d", i); + if (s.del(name) == false) + { + printf("del error, name: %s\r\n", name); + return 1; + } + printf("del ok, name: %s\r\n", name); + } + + printf("\r\n>>>>>>>>>>>>> get session <<<<<<<<<<<<<<<<<<<\r\n"); + for (int i = 0; i < n; i++) + { + snprintf(name, sizeof(name), "name-%d", i); + const char* ptr = s.get(name); + if (ptr == NULL || *ptr == 0) + printf("get ok, name: %s no exist\r\n", name); + else + { + printf("get error, name: %s exist, value: %s\r\n", + name, value); + return 1; + } + } + + printf("\r\n------------ test session ok now -------------\r\n"); + return 0; +} + +static void session_delay_test(const char* addr) +{ + const char* sid = "XXXXXXXXXXXXXX"; + memcache_session sess(addr, 120, 300, NULL, 0, sid); + sess.set_ttl(128, true); + + char name[128], value[128]; + for (int i = 0; i < 10; i++) + { + snprintf(name, sizeof(name), "name%d", i); + snprintf(value, sizeof(value), "value%d", i); + sess.set(name, value, true); + printf(">>>set %s: %s\r\n", name, value); + } + + snprintf(name, sizeof(name), "name5"); + sess.del(name, true); + + if (sess.flush() == false) + printf("set session error\r\n"); + else + { + printf("set session ok\r\n"); + printf("begin get session:\r\n"); + + for (int i = 0; i < 11; i++) + { + snprintf(name, sizeof(name), "name%d", i); + snprintf(value, sizeof(value), "value%d", i); + const char* ptr = sess.get(name); + if (ptr == NULL) + printf(">>> %s not found\r\n", name); + else + printf(">>>get %s: %s, %s\r\n", name, ptr, + strcmp(ptr, value) == 0 ? "ok" : "failed"); + } + } +} + + +int main(int argc, char* argv[]) +{ + char addr[256]; + int n = 10; + + if (argc >= 2) + { + snprintf(addr, sizeof(addr), "%s", argv[1]); + if (argc >= 3) + n = atoi(argv[2]); + if (n <= 0) + n = 10; + } + else + { + snprintf(addr, sizeof(addr), "192.168.0.250:11211"); + n = 10; + } + + acl_cpp_init(); + + session_test1(addr, n); + session_delay_test(addr); + +#ifdef WIN32 + printf("enter any key to exit\r\n"); + getchar(); +#endif + return 0; +} + diff --git a/lib_acl_cpp/samples/session/session.vcproj b/lib_acl_cpp/samples/session/session.vcproj new file mode 100644 index 000000000..b77859c60 --- /dev/null +++ b/lib_acl_cpp/samples/session/session.vcproj @@ -0,0 +1,269 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_acl_cpp/samples/session/stdafx.cpp b/lib_acl_cpp/samples/session/stdafx.cpp new file mode 100644 index 000000000..4bfbf8227 --- /dev/null +++ b/lib_acl_cpp/samples/session/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// session.pch 将成为预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + +// TODO: 在 STDAFX.H 中 +//引用任何所需的附加头文件,而不是在此文件中引用 diff --git a/lib_acl_cpp/samples/session/stdafx.h b/lib_acl_cpp/samples/session/stdafx.h new file mode 100644 index 000000000..12dfecdeb --- /dev/null +++ b/lib_acl_cpp/samples/session/stdafx.h @@ -0,0 +1,7 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是常用但不常更改的项目特定的包含文件 +// + +#pragma once + +// TODO: 在此处引用程序要求的附加头文件 diff --git a/lib_acl_cpp/samples/session/valgrind.sh b/lib_acl_cpp/samples/session/valgrind.sh new file mode 100644 index 000000000..d2610aa17 --- /dev/null +++ b/lib_acl_cpp/samples/session/valgrind.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +#valgrind --tool=memcheck --leak-check=yes --track-origins=yes -v ./http_servlet alone +valgrind --tool=memcheck --leak-check=yes -v ./session 127.0.0.1:11211 1 diff --git a/lib_acl_cpp/samples/singleton/singleton.cpp b/lib_acl_cpp/samples/singleton/singleton.cpp new file mode 100644 index 000000000..733c0f0ae --- /dev/null +++ b/lib_acl_cpp/samples/singleton/singleton.cpp @@ -0,0 +1,96 @@ +// singleton.cpp : 定义控制台应用程序的入口点。 +// + +#include "stdafx.h" +#include "acl_cpp/stdlib/singleton.hpp" + +// 跟踪调用过程的计数器 +static int __nstep = 0; + +class singleton_test : public acl::singleton +{ +public: + singleton_test() + { + // 如果该句话打印先于 main 函数中的打印结果,则 + // 说明该单例是在 main 函数执行先被初始化的 + printf("step %d: singleton_test construct called\r\n", ++__nstep); + fflush(stdout); + } + + virtual ~singleton_test() + { + printf("step %d: singleton_test destruct called\r\n", ++__nstep); + fflush(stdout); + getchar(); + } + + const singleton_test& init() const + { + printf("step %d: singleton_test init called\r\n", ++__nstep); + fflush(stdout); + return *this; + } + + const singleton_test& set(const char* name) const + { + printf("step %d: singleton_test set(%s) called\r\n", ++__nstep, name); + fflush(stdout); + return *this; + } +}; + +////////////////////////////////////////////////////////////////////////// + +class singleton_test2 +{ +public: + singleton_test2() + { + // 如果该句话打印先于 main 函数中的打印结果,则 + // 说明该单例是在 main 函数执行先被初始化的 + printf("step %d: singleton_test2 construct called\r\n", ++__nstep); + fflush(stdout); + } + + virtual ~singleton_test2() + { + printf("step %d: singleton_test2 destruct called\r\n", ++__nstep); + fflush(stdout); + getchar(); + } + + const singleton_test2& init() const + { + printf("step %d: singleton_test2 init called\r\n", ++__nstep); + fflush(stdout); + return *this; + } + + const singleton_test2& set(const char* name) const + { + printf("step %d: singleton_test2 set(%s) called\r\n", ++__nstep, name); + fflush(stdout); + return *this; + } +}; + +//singleton_test::get_const_instance(); +int main() +{ + printf("step %d: first line in main\r\n", ++__nstep); + fflush(stdout); + + // 方法一 + const singleton_test& test1 = singleton_test::get_instance().init(); + const singleton_test& test2 = singleton_test::get_instance(); + test1.set("test1"); + test2.set("test2"); + + // 方法二,用 VC2003 编译成 release 版本时, + // 该方式可以保证单体实例在 main 之前被构造 + acl::singleton2::get_instance().init(); + acl::singleton2::get_instance().set("test1"); + acl::singleton2::get_instance().set("test2"); + return 0; +} diff --git a/lib_acl_cpp/samples/singleton/singleton.vcproj b/lib_acl_cpp/samples/singleton/singleton.vcproj new file mode 100644 index 000000000..c08574463 --- /dev/null +++ b/lib_acl_cpp/samples/singleton/singleton.vcproj @@ -0,0 +1,264 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_acl_cpp/samples/singleton/singleton.vcxproj b/lib_acl_cpp/samples/singleton/singleton.vcxproj new file mode 100644 index 000000000..a943b6b00 --- /dev/null +++ b/lib_acl_cpp/samples/singleton/singleton.vcxproj @@ -0,0 +1,180 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + ReleaseDll + Win32 + + + Release + Win32 + + + + {128791D9-6787-471C-9A0C-0DCAE53F4911} + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Use + Level3 + EditAndContinue + + + $(OutDir)singleton.exe + true + $(OutDir)singleton.pdb + Console + MachineX86 + + + + + Full + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + Use + Level3 + ProgramDatabase + + + $(OutDir)singleton.exe + true + Console + true + true + MachineX86 + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Use + Level3 + EditAndContinue + + + $(OutDir)singleton.exe + true + $(OutDir)singleton.pdb + Console + MachineX86 + + + + + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDLL + Use + Level3 + ProgramDatabase + + + $(OutDir)singleton.exe + true + Console + true + true + MachineX86 + + + + + + Create + Create + Create + Create + + + + + + + + + + + + \ No newline at end of file diff --git a/lib_acl_cpp/samples/singleton/singleton.vcxproj.filters b/lib_acl_cpp/samples/singleton/singleton.vcxproj.filters new file mode 100644 index 000000000..b515e7a5b --- /dev/null +++ b/lib_acl_cpp/samples/singleton/singleton.vcxproj.filters @@ -0,0 +1,33 @@ +锘 + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx + + + + + 婧愭枃浠 + + + 婧愭枃浠 + + + + + 澶存枃浠 + + + + + + \ No newline at end of file diff --git a/lib_acl_cpp/samples/singleton/singleton_vc2012.vcxproj b/lib_acl_cpp/samples/singleton/singleton_vc2012.vcxproj new file mode 100644 index 000000000..58759b6f2 --- /dev/null +++ b/lib_acl_cpp/samples/singleton/singleton_vc2012.vcxproj @@ -0,0 +1,185 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + ReleaseDll + Win32 + + + Release + Win32 + + + + {128791D9-6787-471C-9A0C-0DCAE53F4911} + Win32Proj + singleton + + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + false + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Use + Level3 + ProgramDatabase + + + $(OutDir)singleton.exe + true + $(OutDir)singleton.pdb + Console + MachineX86 + + + + + Full + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + Use + Level3 + ProgramDatabase + + + $(OutDir)singleton.exe + true + Console + true + true + MachineX86 + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Use + Level3 + EditAndContinue + + + $(OutDir)singleton.exe + true + $(OutDir)singleton.pdb + Console + MachineX86 + + + + + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDLL + Use + Level3 + ProgramDatabase + + + $(OutDir)singleton.exe + true + Console + true + true + MachineX86 + + + + + + Create + Create + Create + Create + + + + + + + + + + + + \ No newline at end of file diff --git a/lib_acl_cpp/samples/singleton/stdafx.cpp b/lib_acl_cpp/samples/singleton/stdafx.cpp new file mode 100644 index 000000000..a80807224 --- /dev/null +++ b/lib_acl_cpp/samples/singleton/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// singleton.pch 将成为预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + +// TODO: 在 STDAFX.H 中 +//引用任何所需的附加头文件,而不是在此文件中引用 diff --git a/lib_acl_cpp/samples/singleton/stdafx.h b/lib_acl_cpp/samples/singleton/stdafx.h new file mode 100644 index 000000000..12dfecdeb --- /dev/null +++ b/lib_acl_cpp/samples/singleton/stdafx.h @@ -0,0 +1,7 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是常用但不常更改的项目特定的包含文件 +// + +#pragma once + +// TODO: 在此处引用程序要求的附加头文件 diff --git a/lib_acl_cpp/samples/socket_client/Makefile b/lib_acl_cpp/samples/socket_client/Makefile new file mode 100644 index 000000000..c5a445bcf --- /dev/null +++ b/lib_acl_cpp/samples/socket_client/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = socket_client diff --git a/lib_acl_cpp/samples/socket_client/main.cpp b/lib_acl_cpp/samples/socket_client/main.cpp new file mode 100644 index 000000000..17aec6998 --- /dev/null +++ b/lib_acl_cpp/samples/socket_client/main.cpp @@ -0,0 +1,49 @@ +#include "lib_acl.h" +#include "acl_cpp/stream/socket_stream.hpp" +#include "acl_cpp/stdlib/string.hpp" +#include +#include + +int main(void) +{ + acl::socket_stream client; + acl::string addr = "127.0.0.1:9001"; + + acl_init(); + if (client.open(addr, 0, 0) == false) + { + printf("open %s error\n", addr.c_str()); + getchar(); + return (0); + } + + acl::string req = "echo1\r\n" + "echo2\r\n" + "echo3\r\n" + "read_delay1\r\n" + "read_delay2\r\n" + "read_delay3\r\n" + "read_delay4\r\n" + "read_delay5\r\n" + "quit\r\n"; + + if (client.write(req.c_str(), req.length()) == false) + { + printf("write error\n"); + getchar(); + return (0); + } + + acl::string res; + while (true) + { + if (client.gets(res) == false) + break; + printf(">>%s\r\n", res.c_str()); + } + + printf(">>stream closed, enter any key to exit ...\r\n"); + + getchar(); + return (0); +} diff --git a/lib_acl_cpp/samples/socket_client/socket_client.vcproj b/lib_acl_cpp/samples/socket_client/socket_client.vcproj new file mode 100644 index 000000000..b12ede949 --- /dev/null +++ b/lib_acl_cpp/samples/socket_client/socket_client.vcproj @@ -0,0 +1,240 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_acl_cpp/samples/socket_stream/Makefile b/lib_acl_cpp/samples/socket_stream/Makefile new file mode 100644 index 000000000..d2fbacfc1 --- /dev/null +++ b/lib_acl_cpp/samples/socket_stream/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = stream diff --git a/lib_acl_cpp/samples/socket_stream/ReadMe.txt b/lib_acl_cpp/samples/socket_stream/ReadMe.txt new file mode 100644 index 000000000..ab2fec5ae --- /dev/null +++ b/lib_acl_cpp/samples/socket_stream/ReadMe.txt @@ -0,0 +1,31 @@ +======================================================================== + 控制台应用程序 : socket_stream 项目概况 +======================================================================== + +应用程序向导已为您创建了这个 socket_stream 应用程序。 +此文件包含组成 socket_stream 应用程序 +的每个文件的内容摘要。 + + +socket_stream.vcproj + 这是用应用程序向导生成的 VC++ 项目的主项目文件。 + 它包含有关生成此文件的 Visual C++ 版本的信息,以及 + 有关用应用程序向导选择的 + 平台、配置和项目功能的信息。 + +socket_stream.cpp + 这是主应用程序源文件。 + +///////////////////////////////////////////////////////////////////////////// +其他标准文件: + +StdAfx.h、StdAfx.cpp + 这些文件用于生成名为 socket_stream.pch + 的预编译头(PCH)文件以及名为 StdAfx.obj 的预编译类型文件。 + +///////////////////////////////////////////////////////////////////////////// +其他注释: + +应用程序向导使用 "TODO:" 注释指示应添加或自定义的源代码部分。 + +///////////////////////////////////////////////////////////////////////////// diff --git a/lib_acl_cpp/samples/socket_stream/socket_stream.cpp b/lib_acl_cpp/samples/socket_stream/socket_stream.cpp new file mode 100644 index 000000000..69565a709 --- /dev/null +++ b/lib_acl_cpp/samples/socket_stream/socket_stream.cpp @@ -0,0 +1,49 @@ +// socket_stream.cpp : 定义控制台应用程序的入口点。 +// + +#include "stdafx.h" +#include "lib_acl.h" +#include "acl_cpp/stdlib/string.hpp" +#include "acl_cpp/stream/socket_stream.hpp" + +//using acl; + +int main(int argc, char* argv[]) +{ + (void) argc; + (void) argv; + + acl::socket_stream client; + acl::string addr = "mail.51iker.com:80"; + acl::string request = "GET / HTTP/1.1\r\n" + "HOST: mail.51iker.com\r\n" + "Connection: close\r\n\r\n"; + acl::string respond; + + acl_init(); + if (client.open(addr, 0, 0) == false) { + printf("connect %s error(%s)\n", addr.c_str(), acl_last_serror()); + printf("input any key to exit\n"); + getchar(); + return (0); + } + + if (client.write(request) == -1) { + printf("write %s to %s error(%s)\n", request.c_str(), addr.c_str(), + acl_last_serror()); + printf("input any key to exit\n"); + getchar(); + } + printf("%s", request.c_str()); + + while (1) { + if (client.read(respond, false) == false) + break; + printf("%s", respond.c_str()); + } + + printf("ok, enter any key to exit\n"); + getchar(); + return 0; +} + diff --git a/lib_acl_cpp/samples/socket_stream/socket_stream.vcproj b/lib_acl_cpp/samples/socket_stream/socket_stream.vcproj new file mode 100644 index 000000000..e48e23813 --- /dev/null +++ b/lib_acl_cpp/samples/socket_stream/socket_stream.vcproj @@ -0,0 +1,273 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_acl_cpp/samples/socket_stream/socket_stream.vcxproj b/lib_acl_cpp/samples/socket_stream/socket_stream.vcxproj new file mode 100644 index 000000000..3065ef038 --- /dev/null +++ b/lib_acl_cpp/samples/socket_stream/socket_stream.vcxproj @@ -0,0 +1,197 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + Releasedll + Win32 + + + Release + Win32 + + + + {41FA5224-3315-4CDA-9C44-19085049F179} + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + true + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Use + Level3 + ProgramDatabase + + + ws2_32.lib;lib_acl_vc2010d.lib;lib_acl_cpp_vc2010d.lib;%(AdditionalDependencies) + $(OutDir)socket_stream.exe + ..\..\..\lib\win32;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)socket_stream.pdb + Console + MachineX86 + + + + + + + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + Use + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;lib_acl_vc2010.lib;lib_acl_cpp_vc2010.lib;%(AdditionalDependencies) + $(OutDir)socket_stream.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + + + + + + + Disabled + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Use + Level3 + ProgramDatabase + + + lib_acl_d.lib;lib_acl_cpp_d.lib;ws2_32.lib;%(AdditionalDependencies) + $(OutDir)socket_stream.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)socket_stream.pdb + Console + MachineX86 + + + + + Disabled + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDLL + Use + Level3 + ProgramDatabase + + + ws2_32.lib;lib_acl_cpp.lib;lib_acl.lib;%(AdditionalDependencies) + $(OutDir)socket_stream.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)socket_stream.pdb + Console + MachineX86 + + + + + + + + + + Create + Create + Create + Create + + + + + + + + + + + + \ No newline at end of file diff --git a/lib_acl_cpp/samples/socket_stream/socket_stream_vc2012.vcxproj b/lib_acl_cpp/samples/socket_stream/socket_stream_vc2012.vcxproj new file mode 100644 index 000000000..559b07b0c --- /dev/null +++ b/lib_acl_cpp/samples/socket_stream/socket_stream_vc2012.vcxproj @@ -0,0 +1,202 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + Releasedll + Win32 + + + Release + Win32 + + + + {41FA5224-3315-4CDA-9C44-19085049F179} + Win32Proj + socket_stream + + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + true + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Use + Level3 + ProgramDatabase + + + ws2_32.lib;lib_acl_vc2012d.lib;lib_acl_cpp_vc2012d.lib;%(AdditionalDependencies) + $(OutDir)socket_stream.exe + ..\..\..\lib\win32;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)socket_stream.pdb + Console + MachineX86 + + + + + + + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + Use + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;lib_acl_vc2012.lib;lib_acl_cpp_vc2012.lib;%(AdditionalDependencies) + $(OutDir)socket_stream.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + + + + + + + Disabled + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Use + Level3 + ProgramDatabase + + + lib_acl_d.lib;lib_acl_cpp_d.lib;ws2_32.lib;%(AdditionalDependencies) + $(OutDir)socket_stream.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)socket_stream.pdb + Console + MachineX86 + + + + + Disabled + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDLL + Use + Level3 + ProgramDatabase + + + ws2_32.lib;lib_acl_cpp.lib;lib_acl.lib;%(AdditionalDependencies) + $(OutDir)socket_stream.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)socket_stream.pdb + Console + MachineX86 + + + + + + + + + + Create + Create + Create + Create + + + + + + + + + + + + \ No newline at end of file diff --git a/lib_acl_cpp/samples/socket_stream/stdafx.cpp b/lib_acl_cpp/samples/socket_stream/stdafx.cpp new file mode 100644 index 000000000..eb2fa98a2 --- /dev/null +++ b/lib_acl_cpp/samples/socket_stream/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// socket_stream.pch 将成为预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + +// TODO: 在 STDAFX.H 中 +//引用任何所需的附加头文件,而不是在此文件中引用 diff --git a/lib_acl_cpp/samples/socket_stream/stdafx.h b/lib_acl_cpp/samples/socket_stream/stdafx.h new file mode 100644 index 000000000..9024458d0 --- /dev/null +++ b/lib_acl_cpp/samples/socket_stream/stdafx.h @@ -0,0 +1,11 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是常用但不常更改的项目特定的包含文件 +// + +#pragma once + + +//#include +//#include + +// TODO: 在此处引用程序要求的附加头文件 diff --git a/lib_acl_cpp/samples/socket_stream/valgrind.sh b/lib_acl_cpp/samples/socket_stream/valgrind.sh new file mode 100644 index 000000000..9cb33e551 --- /dev/null +++ b/lib_acl_cpp/samples/socket_stream/valgrind.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +valgrind --tool=memcheck --leak-check=yes -v ./stream diff --git a/lib_acl_cpp/samples/sqlite/Makefile b/lib_acl_cpp/samples/sqlite/Makefile new file mode 100644 index 000000000..f0fbe0a98 --- /dev/null +++ b/lib_acl_cpp/samples/sqlite/Makefile @@ -0,0 +1,3 @@ +include ../Makefile.in +PROG = sqlite +EXTLIBS += -lsqlite3 -lmysqlclient diff --git a/lib_acl_cpp/samples/sqlite/ReadMe.txt b/lib_acl_cpp/samples/sqlite/ReadMe.txt new file mode 100644 index 000000000..fba92446c --- /dev/null +++ b/lib_acl_cpp/samples/sqlite/ReadMe.txt @@ -0,0 +1,31 @@ +======================================================================== + 控制台应用程序 : sqlite 项目概况 +======================================================================== + +应用程序向导已为您创建了这个 sqlite 应用程序。 +此文件包含组成 sqlite 应用程序 +的每个文件的内容摘要。 + + +sqlite.vcproj + 这是用应用程序向导生成的 VC++ 项目的主项目文件。 + 它包含有关生成此文件的 Visual C++ 版本的信息,以及 + 有关用应用程序向导选择的 + 平台、配置和项目功能的信息。 + +sqlite.cpp + 这是主应用程序源文件。 + +///////////////////////////////////////////////////////////////////////////// +其他标准文件: + +StdAfx.h、StdAfx.cpp + 这些文件用于生成名为 sqlite.pch + 的预编译头(PCH)文件以及名为 StdAfx.obj 的预编译类型文件。 + +///////////////////////////////////////////////////////////////////////////// +其他注释: + +应用程序向导使用 "TODO:" 注释指示应添加或自定义的源代码部分。 + +///////////////////////////////////////////////////////////////////////////// diff --git a/lib_acl_cpp/samples/sqlite/sqlite.cpp b/lib_acl_cpp/samples/sqlite/sqlite.cpp new file mode 100644 index 000000000..02c4c82e5 --- /dev/null +++ b/lib_acl_cpp/samples/sqlite/sqlite.cpp @@ -0,0 +1,235 @@ +// sqlite.cpp : 定义控制台应用程序的入口点。 +// + +#include "stdafx.h" +#include "acl_cpp/stdlib/string.hpp" +#include "acl_cpp/stdlib/util.hpp" +#include "acl_cpp/db/db_sqlite.hpp" + +const char* CREATE_TBL = + "create table group_tbl\r\n" + "(\r\n" + "group_name varchar(128) not null,\r\n" + "uvip_tbl varchar(32) not null default 'uvip_tbl',\r\n" + "access_tbl varchar(32) not null default 'access_tbl',\r\n" + "access_week_tbl varchar(32) not null default 'access_week_tbl',\r\n" + "access_month_tbl varchar(32) not null default 'access_month_tbl',\r\n" + "update_date date not null default '1970-1-1',\r\n" + "disable integer not null default 0,\r\n" + "add_by_hand integer not null default 0,\r\n" + "class_level integer not null default 0,\r\n" + "primary key(group_name, class_level)\r\n" + ")"; + +static bool tbl_create(acl::db_handle& db) +{ + if (db.tbl_exists("group_tbl")) + { + printf("table exist\r\n"); + return (true); + } + else if (db.sql_update(CREATE_TBL) == false) + { + printf("sql error\r\n"); + return (false); + } + else + { + printf("create table ok\r\n"); + return (true); + } +} + +// 添加表数据 +static bool tbl_insert(acl::db_handle& db, int n) +{ + const char* sql_fmt = "insert into group_tbl('group_name', 'uvip_tbl')" + " values('中国人-%d', 'test')"; + + acl::string sql; + sql.format(sql_fmt, n); + if (db.sql_update(sql.c_str()) == false) + return (false); + + const acl::db_rows* result = db.get_result(); + if (result) + { + const std::vector& rows = result->get_rows(); + for (size_t i = 0; i < rows.size(); i++) + { + const acl::db_row* row = rows[i]; + for (size_t j = 0; j < row->length(); j++) + printf("%s, ", (*row)[j]); + printf("\r\n"); + } + } + + db.free_result(); + return (true); +} + +// 查询表数据 +static int tbl_select(acl::db_handle& db, int n) +{ + const char* sql_fmt = "select * from group_tbl where" + " group_name='中国人-%d' and uvip_tbl='test'"; + + acl::string sql; + sql.format(sql_fmt, n); + + if (db.sql_select(sql.c_str()) == false) + { + printf("select sql error\r\n"); + return (-1); + } + + // 列出查询结果方法一 + const acl::db_rows* result = db.get_result(); + if (result) + { + const std::vector& rows = result->get_rows(); + for (size_t i = 0; i < rows.size(); i++) + { + if (n >= 5) + continue; + const acl::db_row* row = rows[i]; + for (size_t j = 0; j < row->length(); j++) + printf("%s, ", (*row)[j]); + printf("\r\n"); + } + } + + // 列出查询结果方法二 + for (size_t i = 0; i < db.length(); i++) + { + if (n >= 5) + continue; + const acl::db_row* row = db[i]; + + // 取出该行记录中某个字段的值 + const char* ptr = (*row)["group_name"]; + if (ptr == NULL) + { + printf(("error, no group name\r\n")); + continue; + } + printf("group_name=%s: ", ptr); + for (size_t j = 0; j < row->length(); j++) + printf("%s, ", (*row)[j]); + printf("\r\n"); + } + + int ret = (int) db.length(); + + // 释放查询结果 + db.free_result(); + return (ret); +} + +// 删除表数据 +static bool tbl_delete(acl::db_handle& db, int n) +{ + const char* sql_fmt = "delete from group_tbl where group_name='中国人-%d'"; + + acl::string sql; + sql.format(sql_fmt, n); + + if (db.sql_update(sql.c_str()) == false) + { + printf("delete sql error\r\n"); + return (false); + } + + for (size_t i = 0; i < db.length(); i++) + { + const acl::db_row* row = db[i]; + for (size_t j = 0; j < row->length(); j++) + printf("%s, ", (*row)[j]); + printf("\r\n"); + } + // 释放查询结果 + db.free_result(); + + return (true); +} + +int main(void) +{ + acl::string dbfile("测试.db"); + acl::db_sqlite db(dbfile); + int max = 100; + + if (db.open() == false) + { + printf("open dbfile: %s error\r\n", dbfile.c_str()); + getchar(); + return 1; + } + + printf("open dbfile %s ok\r\n", dbfile.c_str()); + + if (tbl_create(db) == false) + { + printf("create table error\r\n"); + getchar(); + return 1; + } + + // 配置数据库引擎 + db.set_conf("PRAGMA synchronous = off"); + db.set_conf("PRAGMA encoding = \"UTF-8\""); + acl::string buf; + if ((db.get_conf("PRAGMA encoding", buf))) + printf(">>PRAGMA encoding: %s\r\n", buf.c_str()); + db.show_conf(); + + acl::meter_time(__FILE__, __LINE__, "---begin insert---"); + for (int i = 0; i < max; i++) + { + bool ret = tbl_insert(db, i); + if (ret) + printf(">>insert ok: i=%d, affected: %d\r", + i, db.affect_count()); + else + printf(">>insert error: i = %d\r\n", i); + } + printf("\r\n"); + printf(">>insert total affect: %d\n", db.affect_total_count()); + + acl::meter_time(__FILE__, __LINE__, "---end insert---"); + acl::meter_time(__FILE__, __LINE__, "---begin select---"); + + int n = 0; + for (int i = 0; i < max; i++) + { + int ret = tbl_select(db, i); + if (ret >= 0) + { + n += ret; + printf(">>select ok: i=%d, ret=%d\r", i, ret); + } + else + printf(">>select error: i = %d\r\n", i); + } + printf("\r\n"); + printf(">>select total: %d\r\n", n); + acl::meter_time(__FILE__, __LINE__, "---end select---"); + + acl::meter_time(__FILE__, __LINE__, "---begin delete---"); + for (int i = 0; i < max; i++) + { + bool ret = tbl_delete(db, i); + if (ret) + printf(">>delete ok: %d, affected: %d\r", + i, (int) db.affect_count()); + else + printf(">>delete error: i = %d\r\n", i); + } + printf("\r\n"); + printf(">>delete total affected: %d\n", db.affect_total_count()); + acl::meter_time(__FILE__, __LINE__, "---end delete---"); + + printf("Enter any key to exit.\r\n"); + getchar(); + return 0; +} diff --git a/lib_acl_cpp/samples/sqlite/sqlite.vcproj b/lib_acl_cpp/samples/sqlite/sqlite.vcproj new file mode 100644 index 000000000..7ff09f72a --- /dev/null +++ b/lib_acl_cpp/samples/sqlite/sqlite.vcproj @@ -0,0 +1,281 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_acl_cpp/samples/sqlite/stdafx.cpp b/lib_acl_cpp/samples/sqlite/stdafx.cpp new file mode 100644 index 000000000..bd4da0620 --- /dev/null +++ b/lib_acl_cpp/samples/sqlite/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// sqlite.pch 将成为预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + +// TODO: 在 STDAFX.H 中 +//引用任何所需的附加头文件,而不是在此文件中引用 diff --git a/lib_acl_cpp/samples/sqlite/stdafx.h b/lib_acl_cpp/samples/sqlite/stdafx.h new file mode 100644 index 000000000..12dfecdeb --- /dev/null +++ b/lib_acl_cpp/samples/sqlite/stdafx.h @@ -0,0 +1,7 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是常用但不常更改的项目特定的包含文件 +// + +#pragma once + +// TODO: 在此处引用程序要求的附加头文件 diff --git a/lib_acl_cpp/samples/sqlite/valgrind.sh b/lib_acl_cpp/samples/sqlite/valgrind.sh new file mode 100644 index 000000000..6210f2759 --- /dev/null +++ b/lib_acl_cpp/samples/sqlite/valgrind.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +valgrind --tool=memcheck --leak-check=yes -v ./sqlite diff --git a/lib_acl_cpp/samples/ssl_aio_client/Makefile b/lib_acl_cpp/samples/ssl_aio_client/Makefile new file mode 100644 index 000000000..11caecd2b --- /dev/null +++ b/lib_acl_cpp/samples/ssl_aio_client/Makefile @@ -0,0 +1,3 @@ +include ../Makefile.in +PROG = ssl_aio_client +EXTLIBS += -lpolarssl diff --git a/lib_acl_cpp/samples/ssl_aio_client/main.cpp b/lib_acl_cpp/samples/ssl_aio_client/main.cpp new file mode 100644 index 000000000..c0ef3f202 --- /dev/null +++ b/lib_acl_cpp/samples/ssl_aio_client/main.cpp @@ -0,0 +1,293 @@ +#include +#include +#include "lib_acl.h" +#include "acl_cpp/stdlib/string.hpp" +#include "acl_cpp/http/http_header.hpp" +#include "acl_cpp/stream/aio_handle.hpp" +#include "acl_cpp/stream/ssl_aio_stream.hpp" + +#ifdef WIN32 +# ifndef snprintf +# define snprintf _snprintf +# endif +#endif + +using namespace acl; + +typedef struct +{ + char addr[64]; + aio_handle* handle; + int connect_timeout; + int read_timeout; + int nopen_limit; + int nopen_total; + int nwrite_limit; + int nwrite_total; + int nread_total; + int id_begin; + bool debug; +} IO_CTX; + +static bool connect_ssl_server(IO_CTX* ctx, int id); + +/** +* 客户端异步连接流回调函数类 +*/ +class ssl_io_callback : public aio_open_callback +{ +public: + /** + * 构造函数 + * @param ctx {IO_CTX*} + * @param client {ssl_aio_stream*} 异步连接流 + * @param id {int} 本流的ID号 + */ + ssl_io_callback(IO_CTX* ctx, ssl_aio_stream* client, int id) + : client_(client) + , ctx_(ctx) + , nwrite_(0) + , id_(id) + { + } + + ~ssl_io_callback() + { + std::cout << ">>>ID: " << id_ << ", ssl_io_callback deleted now!" << std::endl; + } + + /** + * 基类虚函数, 当异步流读到所要求的数据时调用此回调函数 + * @param data {char*} 读到的数据地址 + * @param len {int} 读到的数据长度 + * @return {bool} 返回给调用者 true 表示继续,否则表示需要关闭异步流 + */ + bool read_callback(char* data, int len) + { + string buf(data, len); + ctx_->nread_total++; + //std::cout << buf.c_str(); + return (true); + } + + /** + * 基类虚函数, 当异步流写成功时调用此回调函数 + * @return {bool} 返回给调用者 true 表示继续,否则表示需要关闭异步流 + */ + bool write_callback() + { + ctx_->nwrite_total++; + nwrite_++; + return (true); + } + + /** + * 基类虚函数, 当该异步流关闭时调用此回调函数 + */ + void close_callback() + { + if (client_->is_opened() == false) + { + std::cout << "Id: " << id_ << " connect " + << ctx_->addr << " error" << std::endl; + + // 如果是第一次连接就失败,则退出 + if (ctx_->nopen_total == 0) + { + std::cout << ", first connect error, quit"; + /* 获得异步引擎句柄,并设置为退出状态 */ + client_->get_handle().stop(); + } + std::cout << std::endl; + delete this; + return; + } + + /* 获得异步引擎中受监控的异步流个数 */ + int nleft = client_->get_handle().length(); + if (ctx_->nopen_total == ctx_->nopen_limit && nleft == 1) + { + std::cout << "Id: " << id_ << " stop now! nstream: " + << nleft << std::endl; + /* 获得异步引擎句柄,并设置为退出状态 */ + client_->get_handle().stop(); + } + + // 必须在此处删除该动态分配的回调类对象以防止内存泄露 + delete this; + } + + /** + * 基类虚函数,当异步流超时时调用此函数 + * @return {bool} 返回给调用者 true 表示继续,否则表示需要关闭异步流 + */ + bool timeout_callback() + { + std::cout << "Connect " << ctx_->addr << " Timeout ..." << std::endl; + client_->close(); + return (false); + } + + /** + * 基类虚函数, 当异步连接成功后调用此函数 + * @return {bool} 返回给调用者 true 表示继续,否则表示需要关闭异步流 + */ + bool open_callback() + { + // 连接成功,设置IO读写回调函数 + client_->add_read_callback(this); + client_->add_write_callback(this); + ctx_->nopen_total++; + + assert(id_ > 0); + if (ctx_->nopen_total < ctx_->nopen_limit) + { + // 开始进行下一个连接过程 + if (connect_ssl_server(ctx_, id_ + 1) == false) + std::cout << "connect error!" << std::endl; + } + + http_header header; + header.set_url("/cgi-bin/mail/index_login"); + header.set_host("mail.banmau.com"); + header.set_keep_alive(false); + string buf; + (void) header.build_request(buf); + + // 异步向服务器发送数据 + client_->write(buf.c_str(), (int) buf.length()); + + // 异步从服务器读取一行数据 + client_->gets(ctx_->read_timeout, false); + + // 表示继续异步过程 + return (true); + } + +protected: +private: + ssl_aio_stream* client_; + IO_CTX* ctx_; + int nwrite_; + int id_; +}; + +static bool connect_ssl_server(IO_CTX* ctx, int id) +{ + // 开始异步连接远程服务器 + ssl_aio_stream* stream = ssl_aio_stream::open(ctx->handle, + ctx->addr, ctx->connect_timeout, true); + if (stream == NULL) + { + std::cout << "connect " << ctx->addr << " error!" << std::endl; + std::cout << "stoping ..." << std::endl; + if (id == 0) + ctx->handle->stop(); + return (false); + } + + // 创建连接后的回调函数类 + ssl_io_callback* callback = new ssl_io_callback(ctx, stream, id); + + // 添加连接成功的回调函数类 + stream->add_open_callback(callback); + + // 添加连接失败后回调函数类 + stream->add_close_callback(callback); + + // 添加连接超时的回调函数类 + stream->add_timeout_callback(callback); + return (true); +} + +static void usage(const char* procname) +{ + printf("usage: %s -h[help] -l server_addr -c nconnect" + " -n io_max -k[use kernel event: epoll/kqueue/devpoll" + " -t connect_timeout -d[debug]\n", procname); +} + +int main(int argc, char* argv[]) +{ + bool use_kernel = false; + int ch; + IO_CTX ctx; + + memset(&ctx, 0, sizeof(ctx)); + ctx.connect_timeout = 500; + ctx.nopen_limit = 30; + ctx.id_begin = 1; + ctx.nwrite_limit = 10; + ctx.debug = false; + //snprintf(ctx.addr, sizeof(ctx.addr), "74.125.71.19:443"); + snprintf(ctx.addr, sizeof(ctx.addr), "122.49.0.202:443"); + + while ((ch = getopt(argc, argv, "hc:n:kl:dt:")) > 0) + { + switch (ch) + { + case 'c': + ctx.nopen_limit = atoi(optarg); + if (ctx.nopen_limit <= 0) + ctx.nopen_limit = 10; + break; + case 'n': + ctx.nwrite_limit = atoi(optarg); + if (ctx.nwrite_limit <= 0) + ctx.nwrite_limit = 10; + break; + case 'h': + usage(argv[0]); + return (0); + case 'k': + use_kernel = true; + break; + case 'l': + snprintf(ctx.addr, sizeof(ctx.addr), "%s", optarg); + break; + case 'd': + ctx.debug = true; + break; + case 't': + ctx.connect_timeout = atoi(optarg); + break; + default: + break; + } + } + + ACL_METER_TIME("-----BEGIN-----"); + acl_init(); + + aio_handle handle(use_kernel ? ENGINE_KERNEL : ENGINE_SELECT); + ctx.handle = &handle; + + if (connect_ssl_server(&ctx, ctx.id_begin) == false) + { + std::cout << "enter any key to exit." << std::endl; + getchar(); + return (1); + } + + std::cout << "Connect " << ctx.addr << " ..." << std::endl; + + while (true) + { + // 如果返回 false 则表示不再继续,需要退出 + if (handle.check() == false) + break; + //std::cout << ">>> Loop Check ..." << std::endl; + } + + acl::string buf; + + buf << "total open: " << ctx.nopen_total + << ", total write: " << ctx.nwrite_total + << ", total read: " << ctx.nread_total; + + ACL_METER_TIME(buf.c_str()); + + std::cout << "enter any key to exit." << std::endl; + getchar(); + return (0); +} diff --git a/lib_acl_cpp/samples/ssl_aio_client/ssl_aio_client.vcproj b/lib_acl_cpp/samples/ssl_aio_client/ssl_aio_client.vcproj new file mode 100644 index 000000000..91ec39b6e --- /dev/null +++ b/lib_acl_cpp/samples/ssl_aio_client/ssl_aio_client.vcproj @@ -0,0 +1,239 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_acl_cpp/samples/ssl_aio_client/valgrind.sh b/lib_acl_cpp/samples/ssl_aio_client/valgrind.sh new file mode 100644 index 000000000..ba5010f86 --- /dev/null +++ b/lib_acl_cpp/samples/ssl_aio_client/valgrind.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +valgrind --tool=memcheck --leak-check=yes --show-reachable=yes -v ./ssl_aio_client diff --git a/lib_acl_cpp/samples/ssl_client/Makefile b/lib_acl_cpp/samples/ssl_client/Makefile new file mode 100644 index 000000000..0578de5a0 --- /dev/null +++ b/lib_acl_cpp/samples/ssl_client/Makefile @@ -0,0 +1,3 @@ +include ../Makefile.in +PROG = ssl_client +EXTLIBS += -lpolarssl diff --git a/lib_acl_cpp/samples/ssl_client/ReadMe.txt b/lib_acl_cpp/samples/ssl_client/ReadMe.txt new file mode 100644 index 000000000..6a916ba16 --- /dev/null +++ b/lib_acl_cpp/samples/ssl_client/ReadMe.txt @@ -0,0 +1,31 @@ +======================================================================== + 控制台应用程序 : ssl_client 项目概况 +======================================================================== + +应用程序向导已为您创建了这个 ssl_client 应用程序。 +此文件包含组成 ssl_client 应用程序 +的每个文件的内容摘要。 + + +ssl_client.vcproj + 这是用应用程序向导生成的 VC++ 项目的主项目文件。 + 它包含有关生成此文件的 Visual C++ 版本的信息,以及 + 有关用应用程序向导选择的 + 平台、配置和项目功能的信息。 + +ssl_client.cpp + 这是主应用程序源文件。 + +///////////////////////////////////////////////////////////////////////////// +其他标准文件: + +StdAfx.h、StdAfx.cpp + 这些文件用于生成名为 ssl_client.pch + 的预编译头(PCH)文件以及名为 StdAfx.obj 的预编译类型文件。 + +///////////////////////////////////////////////////////////////////////////// +其他注释: + +应用程序向导使用 "TODO:" 注释指示应添加或自定义的源代码部分。 + +///////////////////////////////////////////////////////////////////////////// diff --git a/lib_acl_cpp/samples/ssl_client/ssl_client.cpp b/lib_acl_cpp/samples/ssl_client/ssl_client.cpp new file mode 100644 index 000000000..701754429 --- /dev/null +++ b/lib_acl_cpp/samples/ssl_client/ssl_client.cpp @@ -0,0 +1,177 @@ +// ssl_client.cpp : 定义控制台应用程序的入口点。 +// + +#include "stdafx.h" +#include "lib_acl.h" +#include +#include "acl_cpp/acl_cpp_init.hpp" +#include "acl_cpp/http/http_header.hpp" +#include "acl_cpp/stdlib/string.hpp" +#include "acl_cpp/stream/ssl_stream.hpp" +#include "acl_cpp/http/http_client.hpp" + +static void test0(int i) +{ + acl::ssl_stream client; + acl::string addr("127.0.0.1:441"); + if (client.open_ssl(addr.c_str(), 60, 60) == false) + { + std::cout << "connect " << addr.c_str() << " error!" << std::endl; + return; + } + + char line[1024]; + memset(line, 'x', sizeof(line)); + line[1023] = 0; + line[1022] = '\n'; + if (client.write(line, strlen(line)) == -1) + { + std::cout << "write to " << addr.c_str() << " error!" << std::endl; + return; + } + + size_t n = sizeof(line); + if (client.gets(line, &n) == false) + { + std::cout << "gets from " << addr.c_str() << " error!" << std::endl; + return; + } + if (i < 10) + std::cout << ">>gets: " << line << std::endl; +} + +static void test1(void) +{ + acl::string url("https://mail.51iker.com/"); + acl::http_header header; + header.set_url(url.c_str()); + header.set_host("mail.51iker.com"); + acl::string request; + + header.build_request(request); + + acl::string addr("mail.51iker.com:443"); + acl::ssl_stream client; + + if (client.open_ssl(addr.c_str(), 60, 60) == false) + { + std::cout << "connect " << addr.c_str() << " error!" << std::endl; + return; + } + + std::cout << "request:" << std::endl; + std::cout << "----------------------------------------------" << std::endl; + std::cout << request.c_str(); + std::cout << "----------------------------------------------" << std::endl; + + if (client.write(request) == false) + { + std::cout << "write to " << addr.c_str() << " error!" << std::endl; + return; + } + + char buf[8192]; + size_t size; + int ret; + + while (true) + { + size = sizeof(buf) - 1; + if ((ret = client.read(buf, size, false)) == -1) + { + std::cout << "read over!" << std::endl; + break; + } + buf[ret] = 0; + std::cout << buf; + } +} + +static void test2(void) +{ + acl::http_client client; + acl::string url("https://mail.51iker.com/"); + acl::http_header header; + + header.set_url(url.c_str()); + header.set_host("mail.51iker.com"); + acl::string request; + + header.build_request(request); + + // acl::string addr("mail.51iker.com:443"); + acl::string addr("122.49.0.202:443"); + + if (client.open(addr.c_str(), true) == false) + { + std::cout << "connect " << addr.c_str() << " error!" << std::endl; + return; + } + + std::cout << "request:" << std::endl; + std::cout << "----------------------------------------------" << std::endl; + std::cout << request.c_str(); + std::cout << "----------------------------------------------" << std::endl; + + if (client.get_ostream().write(request) == false) + { + std::cout << "write to " << addr.c_str() << " error!" << std::endl; + return; + } + + if (client.read_head() == false) + { + std::cout << "read http respond header error!" << std::endl; + return; + } + + client.get_respond_head(&request); + std::cout << "respond header:" << std::endl; + std::cout << request.c_str(); + + char buf[8192]; + size_t size; + int ret; + + while (true) + { + size = sizeof(buf) - 1; + if ((ret = client.read_body(buf, size)) <= 0) + { + std::cout << "read over!" << std::endl; + break; + } + buf[ret] = 0; + std::cout << buf; + } +} + +int main(int argc, char* argv[]) +{ + (void) argc; (void) argv; + acl::acl_cpp_init(); + + int n = 100; + if (argc >= 2) + n = atoi(argv[1]); + if (n <= 0) + n = 100; + ACL_METER_TIME("---------- begin ----------"); + for (int i = 0; i < 0; i++) + test0(i); + ACL_METER_TIME("---------- end ----------"); + + test1(); + + ACL_METER_TIME("---------- begin ----------"); + for (int i = 0; i < 1; i++) + { + printf(">>>i: %d\n", i); + test2(); + } + ACL_METER_TIME("---------- end ----------"); + + printf("Over, enter any key to exit!\n"); + getchar(); + return (0); +} diff --git a/lib_acl_cpp/samples/ssl_client/ssl_client.vcproj b/lib_acl_cpp/samples/ssl_client/ssl_client.vcproj new file mode 100644 index 000000000..06ec61731 --- /dev/null +++ b/lib_acl_cpp/samples/ssl_client/ssl_client.vcproj @@ -0,0 +1,272 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_acl_cpp/samples/ssl_client/stdafx.cpp b/lib_acl_cpp/samples/ssl_client/stdafx.cpp new file mode 100644 index 000000000..b4920a91b --- /dev/null +++ b/lib_acl_cpp/samples/ssl_client/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// ssl_client.pch 将成为预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + +// TODO: 在 STDAFX.H 中 +//引用任何所需的附加头文件,而不是在此文件中引用 diff --git a/lib_acl_cpp/samples/ssl_client/stdafx.h b/lib_acl_cpp/samples/ssl_client/stdafx.h new file mode 100644 index 000000000..5d66dc1cf --- /dev/null +++ b/lib_acl_cpp/samples/ssl_client/stdafx.h @@ -0,0 +1,10 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是常用但不常更改的项目特定的包含文件 +// + +#pragma once + + +#include + +// TODO: 在此处引用程序要求的附加头文件 diff --git a/lib_acl_cpp/samples/ssl_client/valgrind.sh b/lib_acl_cpp/samples/ssl_client/valgrind.sh new file mode 100644 index 000000000..9764d32c9 --- /dev/null +++ b/lib_acl_cpp/samples/ssl_client/valgrind.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +valgrind --tool=memcheck --leak-check=yes --show-reachable=yes -v ./ssl_client diff --git a/lib_acl_cpp/samples/string/Makefile b/lib_acl_cpp/samples/string/Makefile new file mode 100644 index 000000000..3589772ff --- /dev/null +++ b/lib_acl_cpp/samples/string/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = string diff --git a/lib_acl_cpp/samples/string/main.cpp b/lib_acl_cpp/samples/string/main.cpp new file mode 100644 index 000000000..5a263eaf6 --- /dev/null +++ b/lib_acl_cpp/samples/string/main.cpp @@ -0,0 +1,404 @@ +#include "lib_acl.h" +#include "acl_cpp/stream/ofstream.hpp" +#include "acl_cpp/stdlib/string.hpp" +#include +#include + +// std::string 测试 + +static void test(void) +{ + std::string s; + + printf("--------------------- in test -----------------\r\n"); + + s = "XXX"; + printf(">>s: %s, len: %d\n", s.c_str(), (int) s.length()); + + acl::string s1("hello world, You're welcome!"); + printf("strip: '\t !', before strip: %s, ", s1.c_str()); + s1.strip("\t !", true); + printf("after strip: %s\r\n", s1.c_str()); + + s1 = ("hello world, You're welcome!"); + s1.strip(":", true); + printf(">>s1: %s\n", s1.c_str()); + + s1 = ("hello world, You're welcome!"); + s1.strip("he"); + printf(">>s1: %s\n", s1.c_str()); + + s1 = ("hello world, You're welcome!"); + s1.strip("he "); + printf(">>s1: %s\n", s1.c_str()); +} + +static void test2(void) +{ + acl::string s, s1("hello1;"), s2("hello2;"); + + printf("------------------- in test2 ----------------------\r\n"); + s.append("<"); + s << s1; + s << s2; + s.append(">"); + printf(">>>%s\n", s.c_str()); +} + +static void test3(void) +{ + printf("------------------- in test3 ------------------\r\n"); + printf("parse_int: %s\n", acl::string::parse_int(100).c_str()); + printf("parse_int(-1): %s, %s\n", + acl::string::parse_int(-1).c_str(), + acl::string::parse_int((unsigned int) -1).c_str()); + printf("parse_int64(-1): %s, %s\n", + acl::string::parse_int(-1).c_str(), + acl::string::parse_int64((unsigned long long int) -1).c_str()); + + unsigned char n1 = 255; + char n2 = (char) 255; + + printf("parse_int: unsigned char %s, char %s\n", + acl::string::parse_int(n1).c_str(), + acl::string::parse_int(n2).c_str()); +} + +////////////////////////////////////////////////////////////////////////// + +static void test41(void) +{ + acl::string buf; + buf = "hello world!"; + + buf += "hello world!"; + buf += "hello world!"; + buf += "hello world!"; + buf += "hello world!"; + buf += "hello world!"; + buf += "hello world!"; + buf += "hello world!"; + buf += "hello world!"; + buf += "hello world!"; + + buf += "hello world!"; + buf += "hello world!"; + buf += "hello world!"; + buf += "hello world!"; + buf += "hello world!"; + buf += "hello world!"; + buf += "hello world!"; + buf += "hello world!"; + + buf += "hello world!"; + buf += "hello world!"; + buf += "hello world!"; + buf += "hello world!"; + buf += "hello world!"; + buf += "hello world!"; + buf += "hello world!"; + buf += "hello world!"; + buf += "hello world!"; + + buf += "hello world!"; + buf += "hello world!"; + buf += "hello world!"; + buf += "hello world!"; + buf += "hello world!"; + buf += "hello world!"; + buf += "hello world!"; + buf += "hello world!"; +} + +// 压力测试 acl::string + +static void test4(void) +{ + ACL_METER_TIME(">> begin acl::string"); + for (int i = 0; i < 100000; i++) + { + test41(); + } + ACL_METER_TIME(">> end acl::string"); +} + +////////////////////////////////////////////////////////////////////////// + +static void test51(void) +{ + std::string buf; + buf = "hello world!"; + + buf += "hello world!"; + buf += "hello world!"; + buf += "hello world!"; + buf += "hello world!"; + buf += "hello world!"; + buf += "hello world!"; + buf += "hello world!"; + buf += "hello world!"; + buf += "hello world!"; + + buf += "hello world!"; + buf += "hello world!"; + buf += "hello world!"; + buf += "hello world!"; + buf += "hello world!"; + buf += "hello world!"; + buf += "hello world!"; + buf += "hello world!"; + + buf += "hello world!"; + buf += "hello world!"; + buf += "hello world!"; + buf += "hello world!"; + buf += "hello world!"; + buf += "hello world!"; + buf += "hello world!"; + buf += "hello world!"; + buf += "hello world!"; + + buf += "hello world!"; + buf += "hello world!"; + buf += "hello world!"; + buf += "hello world!"; + buf += "hello world!"; + buf += "hello world!"; + buf += "hello world!"; + buf += "hello world!"; +} + +// 压力测试 std::string + +static void test5(void) +{ + ACL_METER_TIME(">> begin std::string"); + for (int i = 0; i < 100000; i++) + { + test51(); + } + ACL_METER_TIME(">> end std::string"); +} + +////////////////////////////////////////////////////////////////////////// + +static void test61(void) +{ + ACL_VSTRING* buf; + buf = acl_vstring_alloc(256); + + acl_vstring_strcpy(buf, "hello world!"); + acl_vstring_strcat(buf, "hello world!"); + acl_vstring_strcat(buf, "hello world!"); + + acl_vstring_strcat(buf, "hello world!"); + acl_vstring_strcat(buf, "hello world!"); + acl_vstring_strcat(buf, "hello world!"); + acl_vstring_strcat(buf, "hello world!"); + acl_vstring_strcat(buf, "hello world!"); + acl_vstring_strcat(buf, "hello world!"); + acl_vstring_strcat(buf, "hello world!"); + acl_vstring_strcat(buf, "hello world!"); + + acl_vstring_strcat(buf, "hello world!"); + acl_vstring_strcat(buf, "hello world!"); + acl_vstring_strcat(buf, "hello world!"); + acl_vstring_strcat(buf, "hello world!"); + acl_vstring_strcat(buf, "hello world!"); + acl_vstring_strcat(buf, "hello world!"); + acl_vstring_strcat(buf, "hello world!"); + acl_vstring_strcat(buf, "hello world!"); + + acl_vstring_strcat(buf, "hello world!"); + acl_vstring_strcat(buf, "hello world!"); + acl_vstring_strcat(buf, "hello world!"); + acl_vstring_strcat(buf, "hello world!"); + acl_vstring_strcat(buf, "hello world!"); + acl_vstring_strcat(buf, "hello world!"); + acl_vstring_strcat(buf, "hello world!"); + acl_vstring_strcat(buf, "hello world!"); + + acl_vstring_strcat(buf, "hello world!"); + acl_vstring_strcat(buf, "hello world!"); + acl_vstring_strcat(buf, "hello world!"); + acl_vstring_strcat(buf, "hello world!"); + acl_vstring_strcat(buf, "hello world!"); + acl_vstring_strcat(buf, "hello world!"); + acl_vstring_strcat(buf, "hello world!"); + acl_vstring_strcat(buf, "hello world!"); + + acl_vstring_free(buf); +} + +static void test6(void) +{ + ACL_METER_TIME(">> begin ACL_VSTRING"); + for (int i = 0; i < 100000; i++) + { + test61(); + } + ACL_METER_TIME(">> end ACL_VSTRING"); +} + +////////////////////////////////////////////////////////////////////////// + +static void test71(void) +{ + ACL_VSTRING* buf = acl_vstring_alloc(256); + + acl_vstring_sprintf(buf, "max unsigned int: %u; max unsigned long long int: %llu", + (unsigned int) -1, (unsigned long long) -1); + acl_vstring_free(buf); +} + +static void test7(void) +{ + ACL_METER_TIME(">> begin ACL_VSTRING: acl_vstring_sprintf"); + for (int i = 0; i < 100000; i++) + { + test71(); + } + ACL_METER_TIME(">> end ACL_VSTRING: acl_vstring_sprintf"); +} + +////////////////////////////////////////////////////////////////////////// + +static void test_main(void) +{ + acl::string s; + int n = 200; + unsigned char ch; + + printf("-------------------- in test_main ---------------\r\n"); + + ////////////////////////////////////////////////////////////////////// + + s += (char) n; + ch = s[0]; + n = (unsigned char) s[0]; + printf("n: %d, ch: %d\n", n, ch); + + ////////////////////////////////////////////////////////////////////// + + s.clear(); + s.format("\tunsigned long long -1: %llu\r\n" + "\tunsigned int -1: %u\r\n" + "\tunsigned short -1: %u\r\n" + "\tunsigned char -1: %u\r\n", + (unsigned long long) -1, (unsigned int) -1, + (unsigned short) -1, (unsigned char) -1); + printf(">>> 0 result:\r\n"); + printf("%s", s.c_str()); + + s.clear(); + s<<"append char: " << 'X'; + printf(">>> 1 result: %s\r\n", s.c_str()); + + s = 'X'; + printf(">>> 2 result: %s\r\n", s.c_str()); + + ////////////////////////////////////////////////////////////////////// + s.clear(); + printf(">>> set bin status\r\n"); + s.set_bin(true); +#ifdef WIN32 + s << (unsigned __int64) -1 << (unsigned int) -1 << (unsigned short) -1 << (unsigned char) 'Z'; +#else + s << (unsigned long long int) -1 << (unsigned int) -1 << (unsigned short) -1 << (unsigned char) 'Z'; +#endif + printf(">>> 3 result: %s\r\n", s.c_str()); + +#ifdef WIN32 + unsigned __int64 n1; +#else + unsigned long long int n1; +#endif + unsigned int n2; + unsigned short n3; + unsigned char n4; + s >> n1 >> n2 >> n3 >> n4; + + s.format("\tunsigned int64 -1: %llu\r\n" + "\tunsigned int -1: %lu\r\n" + "\tunsigned short -1: %u\r\n" + "\tunsigned char -1: %u, %c\r\n", + n1, n2, n3, n4, n4); + printf(">>> 4 result: \r\n%s\r\n", s.c_str()); + + ////////////////////////////////////////////////////////////////////// + s.clear(); + s.set_bin(false); + printf(">>> set asc status\r\n"); +#ifdef WIN32 + s << (unsigned __int64) -1 << ", " + << (unsigned int) -1 << ", " + << (unsigned short) -1 << ", " + << (unsigned char) 'Z'; +#else + s << (unsigned long long int) -1 << ", " + << (unsigned int) -1 << ", " + << (unsigned short) -1 << ", " + << (unsigned char) 'Z'; +#endif + printf(">>> 5 result: %s\r\n", s.c_str()); + + ////////////////////////////////////////////////////////////////////// + + printf("\r\n"); + + test(); + test2(); + test3(); +} + +int main(void) +{ + //acl_mem_slice_init(8, 1024, 1000000, ACL_SLICE_FLAG_GC2 | ACL_SLICE_FLAG_RTGC_OFF); + + acl::string buf; + const char* sss = "hello world!"; + buf.format("max unsigned short: %30u\r\n", (unsigned short) -1); + buf.format_append("max unsigned int: %30u\r\n", (unsigned int) -1); + buf.format_append("max unsigned long long int: %30llu\r\n", + (unsigned long long int) -1); + buf.format_append("sss: %s, max unsigned int: %u", sss, + (unsigned int) -1); + printf(">>buf: %s\r\n", buf.c_str()); + printf("enter any key to continue\r\n"); + getchar(); + + const char* s[] = { "a.b", "a.", ".b", ".", "ab", "abcd.txt", NULL }; + acl::string s1, s2, ss; + for (size_t i = 0; s[i] != NULL; i++) + { + ss = s[i]; + const char* p = strchr(ss.c_str(), '.'); + if (p) + { + printf("----------------------------------------------------\r\n"); + int n = (int) (p - ss.c_str()); + printf("string: |%s|, pos: %d\r\n", ss.c_str(), n); + + s1 = ss.left(n); + printf("left: |%s|, len: %d\r\n", s1.c_str(), (int) s1.length()); + + s2 = ss.right(n); + printf("right: |%s|, len: %d\r\n", s2.c_str(), (int) s2.length()); + } + } + printf("enter any key to continue ...\r\n"); + getchar(); + + test_main(); + + test4(); + test5(); + test6(); + test7(); + +#ifdef WIN32 + printf("enter any key to exit\r\n"); + getchar(); +#endif + return (0); +} diff --git a/lib_acl_cpp/samples/string/string.vcproj b/lib_acl_cpp/samples/string/string.vcproj new file mode 100644 index 000000000..b5284cfe7 --- /dev/null +++ b/lib_acl_cpp/samples/string/string.vcproj @@ -0,0 +1,240 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_acl_cpp/samples/string/string.vcxproj b/lib_acl_cpp/samples/string/string.vcxproj new file mode 100644 index 000000000..8d7b32357 --- /dev/null +++ b/lib_acl_cpp/samples/string/string.vcxproj @@ -0,0 +1,189 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + Releasedll + Win32 + + + Release + Win32 + + + + {C94BEF01-706C-49A7-9FF1-9D87FA5BB8E7} + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + true + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + lib_acl_vc2010d.lib;lib_acl_cpp_vc2010d.lib;%(AdditionalDependencies) + $(OutDir)string.exe + ..\..\..\lib\win32;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)string.pdb + Console + MachineX86 + + + + + + + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;lib_acl_vc2010.lib;lib_acl_cpp_vc2010.lib;%(AdditionalDependencies) + $(OutDir)string.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + + + + + + + Disabled + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + lib_acl_d.lib;lib_acl_cpp_d.lib;ws2_32.lib;%(AdditionalDependencies) + $(OutDir)string.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)string.pdb + Console + MachineX86 + + + + + Disabled + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + ProgramDatabase + + + lib_acl.lib;lib_acl_cpp.lib;ws2_32.lib;%(AdditionalDependencies) + $(OutDir)string.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)string.pdb + Console + MachineX86 + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib_acl_cpp/samples/string/string_vc2012.vcxproj b/lib_acl_cpp/samples/string/string_vc2012.vcxproj new file mode 100644 index 000000000..d0a1787a3 --- /dev/null +++ b/lib_acl_cpp/samples/string/string_vc2012.vcxproj @@ -0,0 +1,194 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + Releasedll + Win32 + + + Release + Win32 + + + + {C94BEF01-706C-49A7-9FF1-9D87FA5BB8E7} + Win32Proj + string + + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + true + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + lib_acl_vc2012d.lib;lib_acl_cpp_vc2012d.lib;%(AdditionalDependencies) + $(OutDir)string.exe + ..\..\..\lib\win32;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)string.pdb + Console + MachineX86 + + + + + + + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;lib_acl_vc2012.lib;lib_acl_cpp_vc2012.lib;%(AdditionalDependencies) + $(OutDir)string.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + + + + + + + Disabled + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + lib_acl_d.lib;lib_acl_cpp_d.lib;ws2_32.lib;%(AdditionalDependencies) + $(OutDir)string.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)string.pdb + Console + MachineX86 + + + + + Disabled + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + ProgramDatabase + + + lib_acl.lib;lib_acl_cpp.lib;ws2_32.lib;%(AdditionalDependencies) + $(OutDir)string.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)string.pdb + Console + MachineX86 + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib_acl_cpp/samples/string/valgrind.sh b/lib_acl_cpp/samples/string/valgrind.sh new file mode 100644 index 000000000..f3893e758 --- /dev/null +++ b/lib_acl_cpp/samples/string/valgrind.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +valgrind --tool=memcheck --leak-check=yes --show-reachable=yes -v ./string diff --git a/lib_acl_cpp/samples/url_coder/Makefile b/lib_acl_cpp/samples/url_coder/Makefile new file mode 100644 index 000000000..e8af898f9 --- /dev/null +++ b/lib_acl_cpp/samples/url_coder/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = url_coder diff --git a/lib_acl_cpp/samples/url_coder/ReadMe.txt b/lib_acl_cpp/samples/url_coder/ReadMe.txt new file mode 100644 index 000000000..efc26e0f8 --- /dev/null +++ b/lib_acl_cpp/samples/url_coder/ReadMe.txt @@ -0,0 +1,31 @@ +======================================================================== + 控制台应用程序 : url_coder 项目概况 +======================================================================== + +应用程序向导已为您创建了这个 url_coder 应用程序。 +此文件包含组成 url_coder 应用程序 +的每个文件的内容摘要。 + + +url_coder.vcproj + 这是用应用程序向导生成的 VC++ 项目的主项目文件。 + 它包含有关生成此文件的 Visual C++ 版本的信息,以及 + 有关用应用程序向导选择的 + 平台、配置和项目功能的信息。 + +url_coder.cpp + 这是主应用程序源文件。 + +///////////////////////////////////////////////////////////////////////////// +其他标准文件: + +StdAfx.h、StdAfx.cpp + 这些文件用于生成名为 url_coder.pch + 的预编译头(PCH)文件以及名为 StdAfx.obj 的预编译类型文件。 + +///////////////////////////////////////////////////////////////////////////// +其他注释: + +应用程序向导使用 "TODO:" 注释指示应添加或自定义的源代码部分。 + +///////////////////////////////////////////////////////////////////////////// diff --git a/lib_acl_cpp/samples/url_coder/stdafx.cpp b/lib_acl_cpp/samples/url_coder/stdafx.cpp new file mode 100644 index 000000000..49f0083b1 --- /dev/null +++ b/lib_acl_cpp/samples/url_coder/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// url_coder.pch 将成为预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + +// TODO: 在 STDAFX.H 中 +//引用任何所需的附加头文件,而不是在此文件中引用 diff --git a/lib_acl_cpp/samples/url_coder/stdafx.h b/lib_acl_cpp/samples/url_coder/stdafx.h new file mode 100644 index 000000000..12dfecdeb --- /dev/null +++ b/lib_acl_cpp/samples/url_coder/stdafx.h @@ -0,0 +1,7 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是常用但不常更改的项目特定的包含文件 +// + +#pragma once + +// TODO: 在此处引用程序要求的附加头文件 diff --git a/lib_acl_cpp/samples/url_coder/url_coder.cpp b/lib_acl_cpp/samples/url_coder/url_coder.cpp new file mode 100644 index 000000000..5310903ef --- /dev/null +++ b/lib_acl_cpp/samples/url_coder/url_coder.cpp @@ -0,0 +1,69 @@ +// url_coder.cpp : 定义控制台应用程序的入口点。 +// + +#include "stdafx.h" +#include "acl_cpp/stdlib/string.hpp" +#include "acl_cpp/stdlib/url_coder.hpp" + +using namespace acl; + +int main(void) +{ + url_coder coder1; + + coder1.set("name1", "value1"); + coder1.set("name2", 2); + coder1.set("name3", true, "value%d", 3); + coder1.set("name4", "中国人"); + printf("coder1 >> %s, name1: %s, name2: %s, name3: %s, name4: %s\r\n", + coder1.to_string().c_str(), + coder1["name1"], coder1["name2"], coder1["name3"], coder1["name4"]); + coder1.del("name1"); + const char* ptr = coder1["name1"]; + printf("coder1 >> %s, name1: %s, name2: %s, name3: %s, name4: %s\r\n", + coder1.to_string().c_str(), ptr ? ptr : "null", + coder1["name2"], coder1["name3"], coder1["name4"]); + + ////////////////////////////////////////////////////////////////////////// + + url_coder coder2; + + coder2 = coder1; + coder2.set("name5", "&=value5=&"); + ptr = coder2["name1"]; + printf("--------------------------------------------------------\r\n"); + printf("coder2 >> %s, name1: %s, name2: %s, name3: %s, name4: %s, name5: %s\r\n", + coder2.to_string().c_str(), ptr ? ptr : "null", + coder2["name2"], coder2["name3"], coder2["name4"], coder2["name5"]); + + ////////////////////////////////////////////////////////////////////////// + + url_coder coder3(coder2); + + coder3.set("name5", 5); + coder3.set("name6", "=&外国人&="); + ptr = coder3["name1"]; + printf("--------------------------------------------------------\r\n"); + printf("coder3 >> %s, name1: %s, name2: %s, name3: %s, name4: %s, name5: %s, name6: %s\r\n", + coder3.to_string().c_str(), ptr ? ptr : "null", + coder3["name2"], coder3["name3"], coder3["name4"], + coder3["name5"], coder3["name6"]); + + ////////////////////////////////////////////////////////////////////////// + + url_coder coder4; + const char* s = "name1=value1&name2=2&name3=value3&name4=%D6%D0%B9%FA%C8%CB"; + coder4.decode(s); + printf("--------------------------------------------------------\r\n"); + printf("coder4 >> %s, name1: %s, name2: %s, name3: %s, name4: %s\r\n", + coder4.to_string().c_str(), + coder4["name1"], coder4["name2"], coder4["name3"], coder4["name4"]); + +#ifdef WIN32 + printf("enter any key to exit ...\r\n"); + getchar(); +#endif + + return 0; +} + diff --git a/lib_acl_cpp/samples/url_coder/url_coder.vcproj b/lib_acl_cpp/samples/url_coder/url_coder.vcproj new file mode 100644 index 000000000..187ea2b0b --- /dev/null +++ b/lib_acl_cpp/samples/url_coder/url_coder.vcproj @@ -0,0 +1,263 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_acl_cpp/samples/url_coder/valgrind.sh b/lib_acl_cpp/samples/url_coder/valgrind.sh new file mode 100644 index 000000000..6b340d717 --- /dev/null +++ b/lib_acl_cpp/samples/url_coder/valgrind.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +valgrind --tool=memcheck --leak-check=yes --show-reachable=yes -v ./url_coder diff --git a/lib_acl_cpp/samples/util.cpp b/lib_acl_cpp/samples/util.cpp new file mode 100644 index 000000000..95a33ea94 --- /dev/null +++ b/lib_acl_cpp/samples/util.cpp @@ -0,0 +1,18 @@ +#include "stdafx.h" +#include "util.h" + +double util::stamp_sub(const struct timeval *from, const struct timeval *sub_by) +{ + struct timeval res; + + memcpy(&res, from, sizeof(struct timeval)); + + res.tv_usec -= sub_by->tv_usec; + if (res.tv_usec < 0) { + --res.tv_sec; + res.tv_usec += 1000000; + } + res.tv_sec -= sub_by->tv_sec; + + return (res.tv_sec * 1000.0 + res.tv_usec/1000.0); +} diff --git a/lib_acl_cpp/samples/util.h b/lib_acl_cpp/samples/util.h new file mode 100644 index 000000000..e686072f1 --- /dev/null +++ b/lib_acl_cpp/samples/util.h @@ -0,0 +1,10 @@ +#pragma once + +class util +{ +public: + util() {} + ~util() {} + + static double stamp_sub(const struct timeval *from, const struct timeval *sub_by); +}; diff --git a/lib_acl_cpp/samples/win_dbservice/ReadMe.txt b/lib_acl_cpp/samples/win_dbservice/ReadMe.txt new file mode 100644 index 000000000..75f30031e --- /dev/null +++ b/lib_acl_cpp/samples/win_dbservice/ReadMe.txt @@ -0,0 +1,82 @@ +================================================================================ + MICROSOFT 基础类库: win_dbservice 项目概述 +=============================================================================== + +应用程序向导已为您创建了此 win_dbservice 应用程序。此应用程序 +不仅介绍了使用 Microsoft 基础类的基本知识, +而且是编写应用程序的起点。 + +此文件包含组成 win_dbservice 应用程序的每个文件的内容摘要。 + +win_dbservice.vcproj + 这是使用“应用程序向导”生成的 VC++ 项目的主项目文件。 + 它包含有关生成文件的 Visual C++ 版本的信息,以及 + 有关用“应用程序向导”所选择的平台、配置和 + 项目功能的信息。 + +win_dbservice.h + 这是应用程序的主头文件。 它包含其他 + 项目特定的头文件(包括 Resource.h),并声明 + Cwin_dbserviceApp 应用程序类。 + +win_dbservice.cpp + 这是包含应用程序 + 类 Cwin_dbserviceApp 的主应用程序源文件。 + +win_dbservice.rc + 这是程序使用的所有 Microsoft Windows 资源 + 的列表。 它包含存储在 RES 子目录中 + 的图标、位图和光标。 可直接在 Microsoft + Visual C++ 中编辑此文件。 项目资源包含在 2052 中。 + +res\win_dbservice.ico + 这是一个图标文件,用作应用程序的图标。 此 + 图标包含在主资源文件 win_dbservice.rc 中。 + +res\win_dbservice.rc2 + 此文件包含不由 Microsoft + Visual C++ 编辑的资源。 应将所有不能由 + 资源编辑器编辑的资源放在此文件中。 + +///////////////////////////////////////////////////////////////////////////// + +应用程序向导将创建一个对话框类: +win_dbserviceDlg.h、win_dbserviceDlg.cpp - 对话框 + 这些文件包含 Cwin_dbserviceDlg 类。 此类定义 + 应用程序主对话框的行为。 此对话框的模板包含在 + win_dbservice.rc 中,而此文件可以在 Microsoft Visual C++ 中进行编辑。 +///////////////////////////////////////////////////////////////////////////// + +其他功能: + +ActiveX 控件 + 应用程序支持使用 ActiveX 控件。 +///////////////////////////////////////////////////////////////////////////// + +其他标准文件: + +StdAfx.h、StdAfx.cpp + 这些文件用于生成名为 win_dbservice.pch 的预编译头文件 (PCH) + 和名为 StdAfx.obj 的预编译类型文件。 + +Resource.h + 这是标准头文件,它定义新资源 ID。 + Microsoft Visual C++ 将读取并更新此文件。 + +///////////////////////////////////////////////////////////////////////////// + +其他说明: + +应用程序向导使用“TODO:” 来指示 +应添加或自定义的源代码部分。 + +如果应用程序在共享 DLL 中使用 MFC,且应用程序使用的语言不是 +操作系统的当前语言,则需要从 Microsoft Visual C++ 光盘上 +Win\System 目录下将相应的本地化资源 MFC70XXX.DLL +复制到计算机的 system 或 system32 目录下, +并将其重命名为 MFCLOC.DLL。 (“XXX”代表 +语言缩写。 例如,MFC70DEU.DLL 包含翻译成 +德语的资源。) 如果不这样做,应用程序的某些 UI 元素 +将保留为操作系统的语言。 + +///////////////////////////////////////////////////////////////////////////// diff --git a/lib_acl_cpp/samples/win_dbservice/res/win_dbservice.ico b/lib_acl_cpp/samples/win_dbservice/res/win_dbservice.ico new file mode 100644 index 000000000..8a84ca3d3 Binary files /dev/null and b/lib_acl_cpp/samples/win_dbservice/res/win_dbservice.ico differ diff --git a/lib_acl_cpp/samples/win_dbservice/res/win_dbservice.manifest b/lib_acl_cpp/samples/win_dbservice/res/win_dbservice.manifest new file mode 100644 index 000000000..64bf0c907 --- /dev/null +++ b/lib_acl_cpp/samples/win_dbservice/res/win_dbservice.manifest @@ -0,0 +1,22 @@ + + + +鍦ㄦ璇存槑搴旂敤绋嬪簭 + + + + + + diff --git a/lib_acl_cpp/samples/win_dbservice/res/win_dbservice.rc2 b/lib_acl_cpp/samples/win_dbservice/res/win_dbservice.rc2 new file mode 100644 index 000000000..e756822b6 --- /dev/null +++ b/lib_acl_cpp/samples/win_dbservice/res/win_dbservice.rc2 @@ -0,0 +1,13 @@ +// +// win_dbservice.RC2 - Microsoft Visual C++ 不会直接编辑的资源 +// + +#ifdef APSTUDIO_INVOKED +#error 此文件不能由 Microsoft Visual C++ 编辑 +#endif //APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// 在此处添加手动编辑的资源... + +///////////////////////////////////////////////////////////////////////////// diff --git a/lib_acl_cpp/samples/win_dbservice/resource.h b/lib_acl_cpp/samples/win_dbservice/resource.h new file mode 100644 index 000000000..99564b631 --- /dev/null +++ b/lib_acl_cpp/samples/win_dbservice/resource.h @@ -0,0 +1,25 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by win_dbservice.rc +// +#define IDM_ABOUTBOX 0x0010 +#define IDD_ABOUTBOX 100 +#define IDS_ABOUTBOX 101 +#define IDD_WIN_DBSERVICE_DIALOG 102 +#define IDR_MAINFRAME 128 +#define IDC_BUTTON1 1000 +#define IDC_ADD_DATA 1000 +#define IDC_GET_DATA 1001 +#define IDC_BUTTON3 1002 +#define IDC_DELETE_DATA 1002 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 129 +#define _APS_NEXT_COMMAND_VALUE 32771 +#define _APS_NEXT_CONTROL_VALUE 1003 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/lib_acl_cpp/samples/win_dbservice/stdafx.cpp b/lib_acl_cpp/samples/win_dbservice/stdafx.cpp new file mode 100644 index 000000000..360407ef5 --- /dev/null +++ b/lib_acl_cpp/samples/win_dbservice/stdafx.cpp @@ -0,0 +1,7 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// win_dbservice.pch 将是预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + + diff --git a/lib_acl_cpp/samples/win_dbservice/stdafx.h b/lib_acl_cpp/samples/win_dbservice/stdafx.h new file mode 100644 index 000000000..1c53d4132 --- /dev/null +++ b/lib_acl_cpp/samples/win_dbservice/stdafx.h @@ -0,0 +1,113 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是经常使用但不常更改的 +// 项目特定的包含文件 + +#pragma once + +#ifdef VC2003 + +#ifndef VC_EXTRALEAN +#define VC_EXTRALEAN // 从 Windows 标头中排除不常使用的资料 +#endif + +// 如果您必须使用下列所指定的平台之前的平台,则修改下面的定义。 +// 有关不同平台的相应值的最新信息,请参考 MSDN。 +#ifndef WINVER // 允许使用 Windows 95 和 Windows NT 4 或更高版本的特定功能。 +#define WINVER 0x0400 //为 Windows98 和 Windows 2000 及更新版本改变为适当的值。 +#endif + +#ifndef _WIN32_WINNT // 允许使用 Windows NT 4 或更高版本的特定功能。 +#define _WIN32_WINNT 0x0400 //为 Windows98 和 Windows 2000 及更新版本改变为适当的值。 +#endif + +#ifndef _WIN32_WINDOWS // 允许使用 Windows 98 或更高版本的特定功能。 +#define _WIN32_WINDOWS 0x0410 //为 Windows Me 及更新版本改变为适当的值。 +#endif + +#ifndef _WIN32_IE // 允许使用 IE 4.0 或更高版本的特定功能。 +#define _WIN32_IE 0x0400 //为 IE 5.0 及更新版本改变为适当的值。 +#endif + +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // 某些 CString 构造函数将是显式的 + +// 关闭 MFC 对某些常见但经常被安全忽略的警告消息的隐藏 +#define _AFX_ALL_WARNINGS + +#include // MFC 核心和标准组件 +#include // MFC 扩展 +#include // MFC 自动化类 + +#include // Internet Explorer 4 公共控件的 MFC 支持 +#ifndef _AFX_NO_AFXCMN_SUPPORT +#include // Windows 公共控件的 MFC 支持 +#endif // _AFX_NO_AFXCMN_SUPPORT + +////////////////////////////////////////////////////////////////////////////////////// +#else +// stdafx.h : 标准系统包含文件的包含文件, +// 或是经常使用但不常更改的 +// 特定于项目的包含文件 + +#pragma once + +#ifndef _SECURE_ATL +#define _SECURE_ATL 1 +#endif + +#ifndef VC_EXTRALEAN +#define VC_EXTRALEAN // 从 Windows 头中排除极少使用的资料 +#endif + +// 包括 SDKDDKVer.h 将定义最高版本的可用 Windows 平台。 + +// 如果要为以前的 Windows 平台生成应用程序,请包括 WinSDKVer.h,并将 +// WIN32_WINNT 宏设置为要支持的平台,然后再包括 SDKDDKVer.h。 + +#include + +//#ifndef _CRTDBG_MAP_ALLOC +//#define _CRTDBG_MAP_ALLOC +//#include +//#include +//#endif + +//#ifdef _DEBUG +//#define NEW new(_NORMAL_BLOCK, __FILE__, __LINE__) +//// Replace _NORMAL_BLOCK with _CLIENT_BLOCK if you want the +////allocations to be of _CLIENT_BLOCK type +//#else +//#define NEW new +//#endif // _DEBUG + +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // 某些 CString 构造函数将是显式的 + +// 关闭 MFC 对某些常见但经常可放心忽略的警告消息的隐藏 +#define _AFX_ALL_WARNINGS + +#include // MFC 核心组件和标准组件 +#include // MFC 扩展 + + +#include // MFC 自动化类 + + +#ifndef _AFX_NO_OLE_SUPPORT +#include // MFC 对 Internet Explorer 4 公共控件的支持 +#endif +#ifndef _AFX_NO_AFXCMN_SUPPORT +#include // MFC 对 Windows 公共控件的支持 +#endif // _AFX_NO_AFXCMN_SUPPORT + +#include // 功能区和控件条的 MFC 支持 +#include + +#include +//#ifndef _CRTDBG_MAP_ALLOC +//# define _CRTDBG_MAP_ALLOC +//# include +//# include +//#endif + +#endif // VC2003 + +#include "acl_cpp/lib_acl.hpp" \ No newline at end of file diff --git a/lib_acl_cpp/samples/win_dbservice/win_dbservice.cpp b/lib_acl_cpp/samples/win_dbservice/win_dbservice.cpp new file mode 100644 index 000000000..f9f5c0f75 --- /dev/null +++ b/lib_acl_cpp/samples/win_dbservice/win_dbservice.cpp @@ -0,0 +1,73 @@ +// win_dbservice.cpp : 定义应用程序的类行为。 +// + +#include "stdafx.h" +#include "win_dbservice.h" +#include "win_dbserviceDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#endif + + +// Cwin_dbserviceApp + +BEGIN_MESSAGE_MAP(Cwin_dbserviceApp, CWinApp) + ON_COMMAND(ID_HELP, CWinApp::OnHelp) +END_MESSAGE_MAP() + + +// Cwin_dbserviceApp 构造 + +Cwin_dbserviceApp::Cwin_dbserviceApp() +{ + // TODO: 在此处添加构造代码, + // 将所有重要的初始化放置在 InitInstance 中 +} + + +// 唯一的一个 Cwin_dbserviceApp 对象 + +Cwin_dbserviceApp theApp; + + +// Cwin_dbserviceApp 初始化 + +BOOL Cwin_dbserviceApp::InitInstance() +{ + // 如果一个运行在 Windows XP 上的应用程序清单指定要 + // 使用 ComCtl32.dll 版本 6 或更高版本来启用可视化方式, + //则需要 InitCommonControls()。否则,将无法创建窗口。 + InitCommonControls(); + + CWinApp::InitInstance(); + + AfxEnableControlContainer(); + + // 标准初始化 + // 如果未使用这些功能并希望减小 + // 最终可执行文件的大小,则应移除下列 + // 不需要的特定初始化例程 + // 更改用于存储设置的注册表项 + // TODO: 应适当修改该字符串, + // 例如修改为公司或组织名 + SetRegistryKey(_T("应用程序向导生成的本地应用程序")); + + Cwin_dbserviceDlg dlg; + m_pMainWnd = &dlg; + INT_PTR nResponse = dlg.DoModal(); + if (nResponse == IDOK) + { + // TODO: 在此放置处理何时用“确定”来关闭 + //对话框的代码 + } + else if (nResponse == IDCANCEL) + { + // TODO: 在此放置处理何时用“取消”来关闭 + //对话框的代码 + } + + // 由于对话框已关闭,所以将返回 FALSE 以便退出应用程序, + // 而不是启动应用程序的消息泵。 + return FALSE; +} diff --git a/lib_acl_cpp/samples/win_dbservice/win_dbservice.h b/lib_acl_cpp/samples/win_dbservice/win_dbservice.h new file mode 100644 index 000000000..53a7b9f05 --- /dev/null +++ b/lib_acl_cpp/samples/win_dbservice/win_dbservice.h @@ -0,0 +1,31 @@ +// win_dbservice.h : PROJECT_NAME 应用程序的主头文件 +// + +#pragma once + +#ifndef __AFXWIN_H__ + #error 在包含用于 PCH 的此文件之前包含“stdafx.h” +#endif + +#include "resource.h" // 主符号 + + +// Cwin_dbserviceApp: +// 有关此类的实现,请参阅 win_dbservice.cpp +// + +class Cwin_dbserviceApp : public CWinApp +{ +public: + Cwin_dbserviceApp(); + +// 重写 + public: + virtual BOOL InitInstance(); + +// 实现 + + DECLARE_MESSAGE_MAP() +}; + +extern Cwin_dbserviceApp theApp; diff --git a/lib_acl_cpp/samples/win_dbservice/win_dbservice.rc b/lib_acl_cpp/samples/win_dbservice/win_dbservice.rc new file mode 100644 index 000000000..11fa5c864 --- /dev/null +++ b/lib_acl_cpp/samples/win_dbservice/win_dbservice.rc @@ -0,0 +1,202 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// 中文(中华人民共和国) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) +#ifdef _WIN32 +LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED +#pragma code_page(936) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "#define _AFX_NO_SPLITTER_RESOURCES\r\n" + "#define _AFX_NO_OLE_RESOURCES\r\n" + "#define _AFX_NO_TRACKER_RESOURCES\r\n" + "#define _AFX_NO_PROPERTY_RESOURCES\r\n" + "\r\n" + "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)\r\n" + "LANGUAGE 4, 2\r\n" + "#pragma code_page(936)\r\n" + "#include ""res\\win_dbservice.rc2"" // 非 Microsoft Visual C++ 编辑过的资源\r\n" + "#include ""afxres.rc"" // 标准组件\r\n" + "#endif\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDR_MAINFRAME ICON "res\\win_dbservice.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_ABOUTBOX DIALOGEX 0, 0, 235, 55 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | + WS_SYSMENU +CAPTION "关于 win_dbservice" +FONT 9, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + ICON IDR_MAINFRAME,IDC_STATIC,11,17,20,20 + LTEXT "win_dbservice Version 1.0",IDC_STATIC,40,10,119,8, + SS_NOPREFIX + LTEXT "Copyright (C) 2011",IDC_STATIC,40,25,119,8 + DEFPUSHBUTTON "确定",IDOK,178,7,50,16,WS_GROUP +END + +IDD_WIN_DBSERVICE_DIALOG DIALOGEX 0, 0, 320, 200 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | + WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_APPWINDOW +CAPTION "win_dbservice" +FONT 9, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + DEFPUSHBUTTON "确定",IDOK,263,7,50,16 + PUSHBUTTON "取消",IDCANCEL,263,25,50,16 + PUSHBUTTON "添加数据",IDC_ADD_DATA,90,49,50,14 + PUSHBUTTON "查询数据",IDC_GET_DATA,90,78,50,14 + PUSHBUTTON "删除数据",IDC_DELETE_DATA,90,109,50,14 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "080403a8" + BEGIN + VALUE "CompanyName", "TODO: <公司名>" + VALUE "FileDescription", "TODO: <文件说明>" + VALUE "FileVersion", "1.0.0.1" + VALUE "InternalName", "win_dbservice.exe" + VALUE "LegalCopyright", "TODO: (C) <公司名>。保留所有权利。" + VALUE "OriginalFilename", "win_dbservice.exe" + VALUE "ProductName", "TODO: <产品名>" + VALUE "ProductVersion", "1.0.0.1" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "翻译", 0x804, 936 + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_ABOUTBOX, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 228 + TOPMARGIN, 7 + BOTTOMMARGIN, 48 + END + + IDD_WIN_DBSERVICE_DIALOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 313 + TOPMARGIN, 7 + BOTTOMMARGIN, 193 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + IDS_ABOUTBOX "关于 win_dbservice(&A)..." +END + +#endif // 中文(中华人民共和国) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +#define _AFX_NO_SPLITTER_RESOURCES +#define _AFX_NO_OLE_RESOURCES +#define _AFX_NO_TRACKER_RESOURCES +#define _AFX_NO_PROPERTY_RESOURCES + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) +LANGUAGE 4, 2 +#pragma code_page(936) +#include "res\win_dbservice.rc2" // 非 Microsoft Visual C++ 编辑过的资源 +#include "afxres.rc" // 标准组件 +#endif + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/lib_acl_cpp/samples/win_dbservice/win_dbservice.vcproj b/lib_acl_cpp/samples/win_dbservice/win_dbservice.vcproj new file mode 100644 index 000000000..906ff481c --- /dev/null +++ b/lib_acl_cpp/samples/win_dbservice/win_dbservice.vcproj @@ -0,0 +1,346 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_acl_cpp/samples/win_dbservice/win_dbservice.vcxproj b/lib_acl_cpp/samples/win_dbservice/win_dbservice.vcxproj new file mode 100644 index 000000000..9274f4197 --- /dev/null +++ b/lib_acl_cpp/samples/win_dbservice/win_dbservice.vcxproj @@ -0,0 +1,286 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + ReleaseDll + Win32 + + + Release + Win32 + + + Template + Win32 + + + + {DC7E75E5-FE42-4529-9D9A-19D240B8727B} + MFCProj + + + + Application + Dynamic + MultiByte + + + Application + Dynamic + MultiByte + + + Application + Dynamic + MultiByte + + + Application + Static + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_WINDOWS;_DEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + true + Use + Level3 + ProgramDatabase + + + lib_acl_cpp_d.lib;%(AdditionalDependencies) + ..\..\..\lib\win32;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + %(IgnoreSpecificDefaultLibraries) + %(DelayLoadDLLs) + true + Windows + MachineX86 + + + _DEBUG;%(PreprocessorDefinitions) + false + + + copy ..\..\..\dist\lib\win32\lib_acl_d.dll $(OutDir) /Y +copy ..\..\bin\sqlite3.dll $(OutDir) /Y +copy ..\..\bin\iconv.dll $(OutDir) /Y +copy ..\..\lib\lib_acl_cpp_vc2010d_dll.dll $(OutDir) /Y +copy ..\..\..\dist\lib\win32\lib_protocol_d.dll $(OutDir) /Y + + + + _DEBUG;%(PreprocessorDefinitions) + 0x0804 + $(IntDir);%(AdditionalIncludeDirectories) + + + + + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_WINDOWS;NDEBUG;ACL_CPP_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + false + MultiThreadedDLL + true + Use + Level3 + ProgramDatabase + + + lib_acl_cpp.lib;%(AdditionalDependencies) + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + Windows + true + true + MachineX86 + + + NDEBUG;%(PreprocessorDefinitions) + false + + + copy ..\..\..\dist\lib\win32\lib_acl.dll $(OutDir) /Y +copy ..\..\bin\sqlite3.dll $(OutDir) /Y +copy ..\..\bin\iconv.dll $(OutDir) /Y +copy ..\..\lib\lib_acl_cpp_vc2010_dll.dll $(OutDir) /Y +copy ..\..\..\dist\lib\win32\lib_protocol.dll $(OutDir) /Y + + + + NDEBUG;%(PreprocessorDefinitions) + 0x0804 + $(IntDir);%(AdditionalIncludeDirectories) + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_WINDOWS;_DEBUG;ACL_CPP_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + true + Use + Level3 + ProgramDatabase + + + lib_acl_cpp_d.lib;%(AdditionalDependencies) + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + %(IgnoreSpecificDefaultLibraries) + true + Windows + MachineX86 + + + _DEBUG;%(PreprocessorDefinitions) + false + + + copy ..\..\..\dist\lib\win32\lib_acl_d.dll $(OutDir) /Y +copy ..\..\..\lib\win32\sqlite3.dll $(OutDir) /Y +copy ..\..\..\dist\lib\win32\lib_acl_cpp_vc2010d_dll.dll $(OutDir) /Y +copy ..\..\..\dist\lib\win32\lib_acl_cpp_vc2010d_dll.pdb $(OutDir) /Y +copy ..\..\..\dist\lib\win32\lib_protocol_d.dll $(OutDir) /Y + + + + _DEBUG;%(PreprocessorDefinitions) + 0x0804 + $(IntDir);%(AdditionalIncludeDirectories) + + + + + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_WINDOWS;NDEBUG;ACL_CPP_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + false + MultiThreadedDLL + true + Use + Level3 + ProgramDatabase + + + lib_acl_cpp.lib;%(AdditionalDependencies) + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + Windows + true + true + MachineX86 + + + NDEBUG;%(PreprocessorDefinitions) + false + + + copy ..\..\..\dist\lib\win32\lib_acl.dll $(OutDir) /Y +copy ..\..\..\lib\win32\sqlite3.dll $(OutDir) /Y +copy ..\..\..\lib\win32\iconv.dll $(OutDir) /Y +copy ..\..\..\dist\lib\win32\lib_acl_cpp_vc2010_dll.dll $(OutDir) /Y +copy ..\..\..\dist\lib\win32\lib_protocol.dll $(OutDir) /Y + + + + NDEBUG;%(PreprocessorDefinitions) + 0x0804 + $(IntDir);%(AdditionalIncludeDirectories) + + + + + Create + Create + Create + Create + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib_acl_cpp/samples/win_dbservice/win_dbserviceDlg.cpp b/lib_acl_cpp/samples/win_dbservice/win_dbserviceDlg.cpp new file mode 100644 index 000000000..e55b52192 --- /dev/null +++ b/lib_acl_cpp/samples/win_dbservice/win_dbserviceDlg.cpp @@ -0,0 +1,321 @@ +// win_dbserviceDlg.cpp : 实现文件 +// + +#include "stdafx.h" +#include "acl_cpp/db/db_service_sqlite.hpp" +#include "acl_cpp/db/db_handle.hpp" +#include "acl_cpp/db/db_sqlite.hpp" +#include "win_dbservice.h" +#include "win_dbserviceDlg.h" +#include ".\win_dbservicedlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#endif + +////////////////////////////////////////////////////////////////////////// + + +class myquery : public acl::db_query +{ +public: + myquery(int id) : id_(id) + { + + } + + ~myquery() + { + + } + + // 基类虚接口:当 SQL 语句出错时的回调函数 + virtual void on_error(acl::db_status status) + { + (void) status; + printf(">>on error, id: %d\r\n", id_); + } + + // 基类虚接口:当 SQL 语句成功时的回调函数 + virtual void on_ok(const acl::db_rows* rows, int affected) + { + if (rows) + printf(">>on ok, id: %d, rows->legnth: %u, group_name: %s\r\n", + id_, rows->length(), (*(*rows)[0])["group_name"]); + else + printf(">>on ok, id: %d, affected: %d\r\n", + id_, affected); + } + + // 基类虚接口:当该类实例对象被释放时的回调函数 + virtual void destroy() + { + printf(">> myquery destroy now\r\n"); + delete this; + } +protected: +private: + int id_; +}; + +static acl::string __dbfile("测试.db"); + +const char* CREATE_TBL = +"create table group_tbl\r\n" +"(\r\n" +"group_name varchar(128) not null,\r\n" +"uvip_tbl varchar(32) not null default 'uvip_tbl',\r\n" +"access_tbl varchar(32) not null default 'access_tbl',\r\n" +"access_week_tbl varchar(32) not null default 'access_week_tbl',\r\n" +"access_month_tbl varchar(32) not null default 'access_month_tbl',\r\n" +"update_date date not null default '1970-1-1',\r\n" +"disable integer not null default 0,\r\n" +"add_by_hand integer not null default 0,\r\n" +"class_level integer not null default 0,\r\n" +"primary key(group_name, class_level)\r\n" +")"; + +static bool tbl_create(acl::db_handle& db) +{ + if (db.tbl_exists("group_tbl")) + return (true); + if (db.sql_update(CREATE_TBL) == false) + { + printf("sql error\r\n"); + return (false); + } + else + { + printf("create table ok\r\n"); + return (true); + } +} + +static bool create_db(void) +{ + acl::db_sqlite db(__dbfile); + + if (db.open() == false) + { + printf("open dbfile: %s error\r\n", __dbfile.c_str()); + return (false); + } + db.show_conf(); + return (tbl_create(db)); +} + +////////////////////////////////////////////////////////////////////////// + +// 用于应用程序“关于”菜单项的 CAboutDlg 对话框 + +class CAboutDlg : public CDialog +{ +public: + CAboutDlg(); + +// 对话框数据 + enum { IDD = IDD_ABOUTBOX }; + + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 + +// 实现 +protected: + DECLARE_MESSAGE_MAP() +}; + +CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) +{ +} + +void CAboutDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); +} + +BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) +END_MESSAGE_MAP() + + +// Cwin_dbserviceDlg 对话框 + + + +Cwin_dbserviceDlg::Cwin_dbserviceDlg(CWnd* pParent /*=NULL*/) + : CDialog(Cwin_dbserviceDlg::IDD, pParent) +{ + m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); + server_ = NULL; +} + +Cwin_dbserviceDlg::~Cwin_dbserviceDlg() +{ + if (server_) + delete server_; +} + +void Cwin_dbserviceDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); +} + +BEGIN_MESSAGE_MAP(Cwin_dbserviceDlg, CDialog) + ON_WM_SYSCOMMAND() + ON_WM_PAINT() + ON_WM_QUERYDRAGICON() + //}}AFX_MSG_MAP + ON_BN_CLICKED(IDC_ADD_DATA, OnBnClickedAddData) + ON_BN_CLICKED(IDC_GET_DATA, OnBnClickedGetData) + ON_BN_CLICKED(IDC_DELETE_DATA, OnBnClickedDeleteData) +END_MESSAGE_MAP() + + +// Cwin_dbserviceDlg 消息处理程序 + +BOOL Cwin_dbserviceDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + // 将\“关于...\”菜单项添加到系统菜单中。 + + // IDM_ABOUTBOX 必须在系统命令范围内。 + ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); + ASSERT(IDM_ABOUTBOX < 0xF000); + + CMenu* pSysMenu = GetSystemMenu(FALSE); + if (pSysMenu != NULL) + { + CString strAboutMenu; + strAboutMenu.LoadString(IDS_ABOUTBOX); + if (!strAboutMenu.IsEmpty()) + { + pSysMenu->AppendMenu(MF_SEPARATOR); + pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); + } + } + + // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动 + // 执行此操作 + SetIcon(m_hIcon, TRUE); // 设置大图标 + SetIcon(m_hIcon, FALSE); // 设置小图标 + + ShowWindow(SW_MINIMIZE); + + // TODO: 在此添加额外的初始化代码 + + // 打开 DOS 窗口 + AllocConsole(); + FILE* fp = freopen("CONOUT$","w+t",stdout); + // 打开库的 DOS 窗口 + acl::open_dos(); + + logger_open("dbservice.log", "dbservice", "all:1"); + if (create_db() == false) + printf(">>create table error\r\n"); + + // 采用基于 WIN32 消息模式的IPC方式 + server_ = new acl::db_service_sqlite("DB_TEST", __dbfile, 2, 2, true); + + return TRUE; // 除非设置了控件的焦点,否则返回 TRUE +} + +void Cwin_dbserviceDlg::OnSysCommand(UINT nID, LPARAM lParam) +{ + if ((nID & 0xFFF0) == IDM_ABOUTBOX) + { + CAboutDlg dlgAbout; + dlgAbout.DoModal(); + } + else + { + CDialog::OnSysCommand(nID, lParam); + } +} + +// 如果向对话框添加最小化按钮,则需要下面的代码 +// 来绘制该图标。对于使用文档/视图模型的 MFC 应用程序, +// 这将由框架自动完成。 + +void Cwin_dbserviceDlg::OnPaint() +{ + if (IsIconic()) + { + CPaintDC dc(this); // 用于绘制的设备上下文 + + SendMessage(WM_ICONERASEBKGND, reinterpret_cast(dc.GetSafeHdc()), 0); + + // 使图标在工作矩形中居中 + int cxIcon = GetSystemMetrics(SM_CXICON); + int cyIcon = GetSystemMetrics(SM_CYICON); + CRect rect; + GetClientRect(&rect); + int x = (rect.Width() - cxIcon + 1) / 2; + int y = (rect.Height() - cyIcon + 1) / 2; + + // 绘制图标 + dc.DrawIcon(x, y, m_hIcon); + } + else + { + CDialog::OnPaint(); + } +} + +//当用户拖动最小化窗口时系统调用此函数取得光标显示。 +HCURSOR Cwin_dbserviceDlg::OnQueryDragIcon() +{ + return static_cast(m_hIcon); +} + +// 添加数据过程 +void Cwin_dbserviceDlg::OnBnClickedAddData() +{ + // TODO: 在此添加控件通知处理程序代码 + + acl::string sql; + myquery* query; + + for (int i = 0; i < 1000; i++) + { + query = new myquery(i); + sql.format("insert into group_tbl('group_name', 'uvip_tbl')" + " values('中国人-%d', 'test')", i); + server_->sql_update(sql.c_str(), query); + } +} + +// 查询数据过程 +void Cwin_dbserviceDlg::OnBnClickedGetData() +{ + // TODO: 在此添加控件通知处理程序代码 + + acl::string sql; + myquery* query; + + for (int i = 0; i < 1000; i++) + { + query = new myquery(i); + sql.format("select * from group_tbl" + " where group_name='中国人-%d'" + " and uvip_tbl='test'", i); + server_->sql_select(sql.c_str(), query); + } +} + +// 删除数据过程 +void Cwin_dbserviceDlg::OnBnClickedDeleteData() +{ + // TODO: 在此添加控件通知处理程序代码 + + acl::string sql; + myquery* query; + + for (int i = 0; i < 1000; i++) + { + query = new myquery(i); + sql.format("delete from group_tbl" + " where group_name='中国人-%d'" + " and uvip_tbl='test'", i); + server_->sql_update(sql.c_str(), query); + } +} diff --git a/lib_acl_cpp/samples/win_dbservice/win_dbserviceDlg.h b/lib_acl_cpp/samples/win_dbservice/win_dbserviceDlg.h new file mode 100644 index 000000000..5a3928773 --- /dev/null +++ b/lib_acl_cpp/samples/win_dbservice/win_dbserviceDlg.h @@ -0,0 +1,42 @@ +// win_dbserviceDlg.h : 头文件 +// + +#pragma once + +#include "acl_cpp/db/db_service.hpp" + +// Cwin_dbserviceDlg 对话框 +class Cwin_dbserviceDlg : public CDialog +{ +// 构造 +public: + Cwin_dbserviceDlg(CWnd* pParent = NULL); // 标准构造函数 + + // 析构 + ~Cwin_dbserviceDlg(); + +// 对话框数据 + enum { IDD = IDD_WIN_DBSERVICE_DIALOG }; + + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 + +// 实现 +protected: + HICON m_hIcon; + + // 生成的消息映射函数 + virtual BOOL OnInitDialog(); + afx_msg void OnSysCommand(UINT nID, LPARAM lParam); + afx_msg void OnPaint(); + afx_msg HCURSOR OnQueryDragIcon(); + DECLARE_MESSAGE_MAP() +public: + afx_msg void OnBnClickedAddData(); + +private: + acl::db_service* server_; +public: + afx_msg void OnBnClickedGetData(); + afx_msg void OnBnClickedDeleteData(); +}; diff --git a/lib_acl_cpp/samples/win_dbservice/win_dbservice_vc2012.vcxproj b/lib_acl_cpp/samples/win_dbservice/win_dbservice_vc2012.vcxproj new file mode 100644 index 000000000..740be0459 --- /dev/null +++ b/lib_acl_cpp/samples/win_dbservice/win_dbservice_vc2012.vcxproj @@ -0,0 +1,291 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + ReleaseDll + Win32 + + + Release + Win32 + + + Template + Win32 + + + + {DC7E75E5-FE42-4529-9D9A-19D240B8727B} + MFCProj + win_dbservice + + + + Application + Dynamic + MultiByte + v110 + + + Application + Dynamic + MultiByte + v110 + + + Application + Dynamic + MultiByte + v110 + + + Application + Static + MultiByte + v110 + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_WINDOWS;_DEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + true + Use + Level3 + ProgramDatabase + + + lib_acl_cpp_d.lib;%(AdditionalDependencies) + ..\..\..\lib\win32;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + %(IgnoreSpecificDefaultLibraries) + %(DelayLoadDLLs) + true + Windows + MachineX86 + + + _DEBUG;%(PreprocessorDefinitions) + false + + + copy ..\..\..\dist\lib\win32\lib_acl_d.dll $(OutDir) /Y +copy ..\..\bin\sqlite3.dll $(OutDir) /Y +copy ..\..\bin\iconv.dll $(OutDir) /Y +copy ..\..\lib\lib_acl_cpp_vc2012d_dll.dll $(OutDir) /Y +copy ..\..\..\dist\lib\win32\lib_protocol_d.dll $(OutDir) /Y + + + + _DEBUG;%(PreprocessorDefinitions) + 0x0804 + $(IntDir);%(AdditionalIncludeDirectories) + + + + + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_WINDOWS;NDEBUG;ACL_CPP_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + false + MultiThreadedDLL + true + Use + Level3 + ProgramDatabase + + + lib_acl_cpp.lib;%(AdditionalDependencies) + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + Windows + true + true + MachineX86 + + + NDEBUG;%(PreprocessorDefinitions) + false + + + copy ..\..\..\dist\lib\win32\lib_acl.dll $(OutDir) /Y +copy ..\..\bin\sqlite3.dll $(OutDir) /Y +copy ..\..\bin\iconv.dll $(OutDir) /Y +copy ..\..\lib\lib_acl_cpp_vc2012_dll.dll $(OutDir) /Y +copy ..\..\..\dist\lib\win32\lib_protocol.dll $(OutDir) /Y + + + + NDEBUG;%(PreprocessorDefinitions) + 0x0804 + $(IntDir);%(AdditionalIncludeDirectories) + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_WINDOWS;_DEBUG;ACL_CPP_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + true + Use + Level3 + ProgramDatabase + + + lib_acl_cpp_d.lib;%(AdditionalDependencies) + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + %(IgnoreSpecificDefaultLibraries) + true + Windows + MachineX86 + + + _DEBUG;%(PreprocessorDefinitions) + false + + + copy ..\..\..\dist\lib\win32\lib_acl_d.dll $(OutDir) /Y +copy ..\..\..\lib\win32\sqlite3.dll $(OutDir) /Y +copy ..\..\..\dist\lib\win32\lib_acl_cpp_vc2012d_dll.dll $(OutDir) /Y +copy ..\..\..\dist\lib\win32\lib_acl_cpp_vc2012d_dll.pdb $(OutDir) /Y +copy ..\..\..\dist\lib\win32\lib_protocol_d.dll $(OutDir) /Y + + + + _DEBUG;%(PreprocessorDefinitions) + 0x0804 + $(IntDir);%(AdditionalIncludeDirectories) + + + + + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_WINDOWS;NDEBUG;ACL_CPP_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + false + MultiThreadedDLL + true + Use + Level3 + ProgramDatabase + + + lib_acl_cpp.lib;%(AdditionalDependencies) + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + Windows + true + true + MachineX86 + + + NDEBUG;%(PreprocessorDefinitions) + false + + + copy ..\..\..\dist\lib\win32\lib_acl.dll $(OutDir) /Y +copy ..\..\..\lib\win32\sqlite3.dll $(OutDir) /Y +copy ..\..\..\lib\win32\iconv.dll $(OutDir) /Y +copy ..\..\..\dist\lib\win32\lib_acl_cpp_vc2012_dll.dll $(OutDir) /Y +copy ..\..\..\dist\lib\win32\lib_protocol.dll $(OutDir) /Y + + + + NDEBUG;%(PreprocessorDefinitions) + 0x0804 + $(IntDir);%(AdditionalIncludeDirectories) + + + + + Create + Create + Create + Create + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib_acl_cpp/samples/winaio/AioClient.cpp b/lib_acl_cpp/samples/winaio/AioClient.cpp new file mode 100644 index 000000000..2d1b34271 --- /dev/null +++ b/lib_acl_cpp/samples/winaio/AioClient.cpp @@ -0,0 +1,179 @@ +#include "StdAfx.h" +#include "lib_acl.h" +#include +#include +#include "acl_cpp/stream/aio_handle.hpp" +#include "AioClient.h" + +#ifdef WIN32 +# ifndef snprintf +# define snprintf _snprintf +# endif +#endif + +using namespace acl; + +CConnectClientCallback::CConnectClientCallback(IO_CTX* ctx, + aio_socket_stream* client, int id) +: client_(client) +, ctx_(ctx) +, nwrite_(0) +, id_(id) +{ +} + +CConnectClientCallback::~CConnectClientCallback() +{ + std::cout << ">>>ID: " << id_ << ", CConnectClientCallback deleted now!" + << std::endl; +} + +bool CConnectClientCallback::read_callback(char* data, int len) +{ + (void) data; + (void) len; + + ctx_->nread_total++; + + if (ctx_->debug) + { + if (nwrite_ < 10) + std::cout << "gets(" << nwrite_ << "): " << data; + else if (nwrite_ % 2000 == 0) + std::cout << ">>ID: " << id_ << ", I: " + << nwrite_ << "; "<< data; + } + + // 如果收到服务器的退出消息,则也应退出 + if (strncasecmp(data, "quit", 4) == 0) + { + // 向服务器发送数据 + client_->format("Bye!\r\n"); + // 关闭异步流连接 + client_->close(); + return (true); + } + + if (nwrite_ >= ctx_->nwrite_limit) + { + if (ctx_->debug) + std::cout << "ID: " << id_ + << ", nwrite: " << nwrite_ + << ", nwrite_limit: " << ctx_->nwrite_limit + << ", quiting ..." << std::endl; + + // 向服务器发送退出消息 + client_->format("quit\r\n"); + client_->close(); + } + else + { + char buf[256]; + snprintf(buf, sizeof(buf), "hello world: %d\n", nwrite_); + client_->write(buf, (int) strlen(buf)); + + // 向服务器发送数据 + //client_->format("hello world: %d\n", nwrite_); + } + + return (true); +} + +bool CConnectClientCallback::write_callback() +{ + ctx_->nwrite_total++; + nwrite_++; + + // 从服务器读一行数据 + client_->gets(ctx_->read_timeout, false); + return (true); +} + +void CConnectClientCallback::close_callback() +{ + if (client_->is_opened() == false) + { + std::cout << "Id: " << id_ << " connect " + << ctx_->addr << " error: " + << acl_last_serror(); + + // 如果是第一次连接就失败,则退出 + if (ctx_->nopen_total == 0) + { + std::cout << ", first connect error, quit"; + /* 获得异步引擎句柄,并设置为退出状态 */ + client_->get_handle().stop(); + } + std::cout << std::endl; + delete this; + return; + } + + // 必须在此处删除该动态分配的回调类对象以防止内存泄露 + delete this; +} + +bool CConnectClientCallback::timeout_callback() +{ + std::cout << "Connect " << ctx_->addr << " Timeout ..." << std::endl; + client_->close(); + return (false); +} + +bool CConnectClientCallback::open_callback() +{ + // 连接成功,设置IO读写回调函数 + client_->add_read_callback(this); + client_->add_write_callback(this); + ctx_->nopen_total++; + + acl_assert(id_ > 0); + if (ctx_->nopen_total < ctx_->nopen_limit) + { + // 开始进行下一个连接过程 + if (connect_server(ctx_, id_ + 1) == false) + std::cout << "connect error!" << std::endl; + } + + // 异步向服务器发送数据 + //client_->format("hello world: %d\n", nwrite_); + char buf[256]; + snprintf(buf, sizeof(buf), "hello world: %d\n", nwrite_); + client_->write(buf, (int) strlen(buf)); + + // 异步从服务器读取一行数据 + client_->gets(ctx_->read_timeout, false); + + // 表示继续异步过程 + return (true); +} + +bool CConnectClientCallback::connect_server(IO_CTX* ctx, int id) +{ + // 开始异步连接远程服务器 + // const char* addr = "221.194.139.155:18887"; + // ctx->connect_timeout = 1; + aio_socket_stream* stream = aio_socket_stream::open(ctx->handle, + ctx->addr, ctx->connect_timeout); + if (stream == NULL) + { + std::cout << "connect " << ctx->addr << " error!" << std::endl; + std::cout << "stoping ..." << std::endl; + if (id == 0) + ctx->handle->stop(); + return (false); + } + + // 创建连接后的回调函数类 + CConnectClientCallback* callback = new CConnectClientCallback(ctx, stream, id); + + // 添加连接成功的回调函数类 + stream->add_open_callback(callback); + + // 添加连接失败后回调函数类 + stream->add_close_callback(callback); + + // 添加连接超时的回调函数类 + stream->add_timeout_callback(callback); + return (true); +} diff --git a/lib_acl_cpp/samples/winaio/AioClient.h b/lib_acl_cpp/samples/winaio/AioClient.h new file mode 100644 index 000000000..3661a3ea9 --- /dev/null +++ b/lib_acl_cpp/samples/winaio/AioClient.h @@ -0,0 +1,63 @@ +#pragma once + +#include "acl_cpp/stream/aio_socket_stream.hpp" + +typedef struct +{ + char addr[64]; + acl::aio_handle* handle; + int connect_timeout; + int read_timeout; + int nopen_limit; + int nopen_total; + int nwrite_limit; + int nwrite_total; + int nread_total; + int id_begin; + bool debug; +} IO_CTX; + +class CConnectClientCallback : public acl::aio_open_callback +{ +public: + CConnectClientCallback(IO_CTX* ctx, acl::aio_socket_stream* client, int id); + ~CConnectClientCallback(); + + /** + * 基类虚函数, 当异步流读到所要求的数据时调用此回调函数 + * @param data {char*} 读到的数据地址 + * @param len {int} 读到的数据长度 + * @return {bool} 返回给调用者 true 表示继续,否则表示需要关闭异步流 + */ + bool read_callback(char* data, int len); + + /** + * 基类虚函数, 当异步流写成功时调用此回调函数 + * @return {bool} 返回给调用者 true 表示继续,否则表示需要关闭异步流 + */ + bool write_callback(); + + /** + * 基类虚函数, 当该异步流关闭时调用此回调函数 + */ + void close_callback(); + + /** + * 基类虚函数,当异步流超时时调用此函数 + * @return {bool} 返回给调用者 true 表示继续,否则表示需要关闭异步流 + */ + bool timeout_callback(); + + /** + * 基类虚函数, 当异步连接成功后调用此函数 + * @return {bool} 返回给调用者 true 表示继续,否则表示需要关闭异步流 + */ + bool open_callback(); + + static bool CConnectClientCallback::connect_server(IO_CTX* ctx, int id); +private: + acl::aio_socket_stream* client_; + IO_CTX* ctx_; + int nwrite_; + int id_; +}; \ No newline at end of file diff --git a/lib_acl_cpp/samples/winaio/AioServer.cpp b/lib_acl_cpp/samples/winaio/AioServer.cpp new file mode 100644 index 000000000..9819a745b --- /dev/null +++ b/lib_acl_cpp/samples/winaio/AioServer.cpp @@ -0,0 +1,204 @@ +#include "StdAfx.h" +#include +#include "lib_acl.h" +#include "acl_cpp/stream/aio_handle.hpp" +#include "acl_cpp/stream/aio_listen_stream.hpp" +#include "acl_cpp/stream/aio_socket_stream.hpp" +#include "AioServer.h" + +using namespace acl; + +/** +* 延迟读回调处理类 +*/ +class timer_reader: public aio_timer_reader +{ +public: + timer_reader() + { + std::cout << "timer_reader init now" << std::endl; + } + + ~timer_reader() + { + } + + // aio_timer_reader 的子类必须重载 destroy 方法 + void destroy() + { + std::cout << "timer_reader delete now" << std::endl; + delete this; + } + + // 重载基类回调方法 + virtual void timer_callback(unsigned int id) + { + std::cout << "timer_reader: timer_callback now" << std::endl; + + // 调用基类的处理过程 + aio_timer_reader::timer_callback(id); + } +}; + +/** +* 延迟写回调处理类 +*/ +class timer_writer: public aio_timer_writer +{ +public: + timer_writer() + { + std::cout << "timer_writer init now" << std::endl; + } + + ~timer_writer() + { + } + + // aio_timer_reader 的子类必须重载 destroy 方法 + void destroy() + { + std::cout << "timer_writer delete now" << std::endl; + delete this; + } + + // 重载基类回调方法 + virtual void timer_callback(unsigned int id) + { + std::cout << "timer_writer: timer_callback now" << std::endl; + + // 调用基类的处理过程 + aio_timer_writer::timer_callback(0); + } +}; + +CAcceptedClientCallback::CAcceptedClientCallback(aio_socket_stream* client) +: client_(client) +, i_(0) +{ + +} + +CAcceptedClientCallback::~CAcceptedClientCallback() +{ + std::cout << "delete io_callback now ..." << std::endl; +} + +bool CAcceptedClientCallback::read_callback(char* data, int len) +{ + i_++; + if (i_ < 10) + std::cout << ">>gets(i:" << i_ << "): " << data; + + // 如果远程客户端希望退出,则关闭之 + if (strncasecmp(data, "quit", 4) == 0) + { + client_->format("Bye!\r\n"); + client_->close(); + return (true); + } + + // 如果远程客户端希望服务端也关闭,则中止异步事件过程 + else if (strncasecmp(data, "stop", 4) == 0) + { + client_->format("Stop now!\r\n"); + client_->close(); // 关闭远程异步流 + + // 通知异步引擎关闭循环过程 + client_->get_handle().stop(); + return (true); + } + + int delay = 0; + + if (strncasecmp(data, "write_delay", strlen("write_delay")) == 0) + { + // 延迟写过程 + + const char* ptr = data + strlen("write_delay"); + delay = atoi(ptr); + if (delay > 0) + { + std::cout << ">> write delay " << delay + << " second ..." << std::endl; + timer_writer* timer = new timer_writer(); + client_->write(data, len, delay, timer); + client_->gets(10, false); + return (true); + } + } + else if (strncasecmp(data, "read_delay", strlen("read_delay")) == 0) + { + // 延迟读过程 + + const char* ptr = data + strlen("read_delay"); + delay = atoi(ptr); + if (delay > 0) + { + client_->write(data, len); + std::cout << ">> read delay " << delay + << " second ..." << std::endl; + timer_reader* timer = new timer_reader(); + client_->gets(10, false, delay, timer); + return (true); + } + } + + // 向远程客户端回写收到的数据 + client_->write(data, len); + + // 继续读下一行数据 + client_->gets(10, false); + return (true); +} + +bool CAcceptedClientCallback::write_callback() +{ + return (true); +} + +void CAcceptedClientCallback::close_callback() +{ + // 必须在此处删除该动态分配的回调类对象以防止内存泄露 + delete this; +} + +bool CAcceptedClientCallback::timeout_callback() +{ + std::cout << "Timeout ..." << std::endl; + return (true); +} + +/////////////////////////////////////////////////////////////////////////////// + +CServerCallback::CServerCallback() +{ + +} + +CServerCallback::~CServerCallback() +{ + +} + +bool CServerCallback::accept_callback(aio_socket_stream* client) +{ + // 创建异步客户端流的回调对象并与该异步流进行绑定 + CAcceptedClientCallback* callback = new CAcceptedClientCallback(client); + + // 注册异步流的读回调过程 + client->add_read_callback(callback); + + // 注册异步流的写回调过程 + client->add_write_callback(callback); + + // 注册异步流的关闭回调过程 + client->add_close_callback(callback); + + // 注册异步流的超时回调过程 + client->add_timeout_callback(callback); + + // 从异步流读一行数据 + client->gets(10, false); + return (true); +} diff --git a/lib_acl_cpp/samples/winaio/AioServer.h b/lib_acl_cpp/samples/winaio/AioServer.h new file mode 100644 index 000000000..771571eff --- /dev/null +++ b/lib_acl_cpp/samples/winaio/AioServer.h @@ -0,0 +1,60 @@ +#pragma once +#include "acl_cpp/stream/aio_listen_stream.hpp" +#include "acl_cpp/stream/aio_socket_stream.hpp" + +/** +* 异步客户端流的回调类的子类 +*/ +class CAcceptedClientCallback : public acl::aio_callback +{ +public: + CAcceptedClientCallback(acl::aio_socket_stream* client); + + ~CAcceptedClientCallback(); + + /** + * 实现父类中的虚函数,客户端流的读成功回调过程 + * @param data {char*} 读到的数据地址 + * @param len {int} 读到的数据长度 + * @return {bool} 返回 true 表示继续,否则希望关闭该异步流 + */ + bool read_callback(char* data, int len); + + /** + * 实现父类中的虚函数,客户端流的写成功回调过程 + * @return {bool} 返回 true 表示继续,否则希望关闭该异步流 + */ + bool write_callback(); + + /** + * 实现父类中的虚函数,客户端流的超时回调过程 + */ + void close_callback(); + + /** + * 实现父类中的虚函数,客户端流的超时回调过程 + * @return {bool} 返回 true 表示继续,否则希望关闭该异步流 + */ + bool timeout_callback(); + +private: + acl::aio_socket_stream* client_; + int i_; +}; + +/** +* 异步监听流的回调类的子类 +*/ +class CServerCallback : public acl::aio_accept_callback +{ +public: + CServerCallback(); + ~CServerCallback(); + + /** + * 基类虚函数,当有新连接到达后调用此回调过程 + * @param client {aio_socket_stream*} 异步客户端流 + * @return {bool} 返回 true 以通知监听流继续监听 + */ + bool accept_callback(acl::aio_socket_stream* client); +}; diff --git a/lib_acl_cpp/samples/winaio/AioTimer.cpp b/lib_acl_cpp/samples/winaio/AioTimer.cpp new file mode 100644 index 000000000..b313c2ae6 --- /dev/null +++ b/lib_acl_cpp/samples/winaio/AioTimer.cpp @@ -0,0 +1,46 @@ +#include "StdAfx.h" +#include +#include "acl_cpp/stream/aio_handle.hpp" +#include "winaioDlg.h" +#include "AioTimer.hpp" +//#include + +//using namespace acl; + +CAioTimer::CAioTimer(acl::aio_handle* handle, int id, bool keep) +: acl::aio_timer_callback(keep) +, handle_(handle) +, id_(id) +, inited_(false) +{ + +} + +CAioTimer::~CAioTimer() +{ + std::cout << "timer deleted" << std::endl; +} + +void CAioTimer::timer_callback(unsigned int id) +{ + const char* s = keep_timer() ? "keep timer" : "cancel timer"; + std::cout << "timer " << id_ << ':' << id << " callback! " << s << std::endl; + if (inited_) + return; + inited_ = true; +#if 0 + handle_->del_timer(this); + handle_->delay_free(this); +#elif 1 + set_task(1, 5000000); + set_task(2, 4000000); + set_task(3, 3000000); + set_task(4, 2000000); + set_task(5, 1000000); +#endif +} + +void CAioTimer::destroy(void) +{ + delete this; +} \ No newline at end of file diff --git a/lib_acl_cpp/samples/winaio/AioTimer.hpp b/lib_acl_cpp/samples/winaio/AioTimer.hpp new file mode 100644 index 000000000..368e8dcf7 --- /dev/null +++ b/lib_acl_cpp/samples/winaio/AioTimer.hpp @@ -0,0 +1,36 @@ +#pragma once +#include "acl_cpp/stream/aio_handle.hpp" + +class CAioTimer : public acl::aio_timer_callback +{ +public: + CAioTimer(acl::aio_handle* handle, int id, bool keep); + ~CAioTimer(); + +protected: + // 基类纯虚函数 + virtual void timer_callback(unsigned int id); + virtual void destroy(void); +private: + acl::aio_handle* handle_; + int id_; + bool inited_; + std::set tt_; +}; + +class CMemory +{ +public: + CMemory(void) + { + printf(">>in CMemory\n"); + } + + ~CMemory(void) + { + printf(">> in ~CMemory\n"); + } + +protected: +private: +}; \ No newline at end of file diff --git a/lib_acl_cpp/samples/winaio/ReadMe.txt b/lib_acl_cpp/samples/winaio/ReadMe.txt new file mode 100644 index 000000000..997317c2a --- /dev/null +++ b/lib_acl_cpp/samples/winaio/ReadMe.txt @@ -0,0 +1,87 @@ +================================================================================ + MICROSOFT 基础类库: winaio 项目概述 +=============================================================================== + +应用程序向导已为您创建了此 winaio 应用程序。此应用程序 +不仅介绍了使用 Microsoft 基础类的基本知识, +而且是编写应用程序的起点。 + +此文件包含组成 winaio 应用程序的每个文件的内容摘要。 + +winaio.vcproj + 这是使用“应用程序向导”生成的 VC++ 项目的主项目文件。 + 它包含有关生成文件的 Visual C++ 版本的信息,以及 + 有关用“应用程序向导”所选择的平台、配置和 + 项目功能的信息。 + +winaio.h + 这是应用程序的主头文件。 它包含其他 + 项目特定的头文件(包括 Resource.h),并声明 + CwinaioApp 应用程序类。 + +winaio.cpp + 这是包含应用程序 + 类 CwinaioApp 的主应用程序源文件。 + +winaio.rc + 这是程序使用的所有 Microsoft Windows 资源 + 的列表。 它包含存储在 RES 子目录中 + 的图标、位图和光标。 可直接在 Microsoft + Visual C++ 中编辑此文件。 项目资源包含在 2052 中。 + +res\winaio.ico + 这是一个图标文件,用作应用程序的图标。 此 + 图标包含在主资源文件 winaio.rc 中。 + +res\winaio.rc2 + 此文件包含不由 Microsoft + Visual C++ 编辑的资源。 应将所有不能由 + 资源编辑器编辑的资源放在此文件中。 + +///////////////////////////////////////////////////////////////////////////// + +应用程序向导将创建一个对话框类: +winaioDlg.h、winaioDlg.cpp - 对话框 + 这些文件包含 CwinaioDlg 类。 此类定义 + 应用程序主对话框的行为。 此对话框的模板包含在 + winaio.rc 中,而此文件可以在 Microsoft Visual C++ 中进行编辑。 +///////////////////////////////////////////////////////////////////////////// + +其他功能: + +ActiveX 控件 + 应用程序支持使用 ActiveX 控件。 + +Windows 套接字 + 应用程序支持在 TCP/IP 网络上建立通讯。 +///////////////////////////////////////////////////////////////////////////// + +其他标准文件: + +StdAfx.h、StdAfx.cpp + 这些文件用于生成名为 winaio.pch 的预编译头文件 (PCH) + 和名为 StdAfx.obj 的预编译类型文件。 + +Resource.h + 这是标准头文件,它定义新资源 ID。 + Microsoft Visual C++ 将读取并更新此文件。 + +///////////////////////////////////////////////////////////////////////////// + +其他说明: + +应用程序向导使用“TODO:” 来指示 +应添加或自定义的源代码部分。 + +如果应用程序在共享 DLL 中使用 MFC,且应用程序使用的语言不是 +操作系统的当前语言,则需要从 Microsoft Visual C++ 光盘上 +Win\System 目录下将相应的本地化资源 MFC70XXX.DLL +复制到计算机的 system 或 system32 目录下, +并将其重命名为 MFCLOC.DLL。 (“XXX”代表 +语言缩写。 例如,MFC70DEU.DLL 包含翻译成 +德语的资源。) 如果不这样做,应用程序的某些 UI 元素 +将保留为操作系统的语言。 + +///////////////////////////////////////////////////////////////////////////// + +注意:该工程只能在 DebugDll 或 ReleaseDll 下编译 \ No newline at end of file diff --git a/lib_acl_cpp/samples/winaio/detours.h b/lib_acl_cpp/samples/winaio/detours.h new file mode 100644 index 000000000..e9acca592 --- /dev/null +++ b/lib_acl_cpp/samples/winaio/detours.h @@ -0,0 +1,616 @@ +////////////////////////////////////////////////////////////////////////////// +// +// File: detours.h +// Module: detours.lib +// +// Detours for binary functions. Version 1.5 (Build 46) +// +// Copyright 1995-2001, Microsoft Corporation +// + +#pragma once +#ifndef _DETOURS_H_ +#define _DETOURS_H_ + +#pragma comment(lib, "detours") + +////////////////////////////////////////////////////////////////////////////// +// +#ifndef GUID_DEFINED +#define GUID_DEFINED +typedef struct _GUID +{ + DWORD Data1; + WORD Data2; + WORD Data3; + BYTE Data4[ 8 ]; +} GUID; +#endif // !GUID_DEFINED + +#if defined(__cplusplus) +#ifndef _REFGUID_DEFINED +#define _REFGUID_DEFINED +#define REFGUID const GUID & +#endif // !_REFGUID_DEFINED +#else // !__cplusplus +#ifndef _REFGUID_DEFINED +#define _REFGUID_DEFINED +#define REFGUID const GUID * const +#endif // !_REFGUID_DEFINED +#endif // !__cplusplus +// +////////////////////////////////////////////////////////////////////////////// + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +/////////////////////////////////////////////////// Instruction Target Macros. +// +#define DETOUR_INSTRUCTION_TARGET_NONE ((PBYTE)0) +#define DETOUR_INSTRUCTION_TARGET_DYNAMIC ((PBYTE)~0ul) + +/////////////////////////////////////////////////////////// Trampoline Macros. +// +// DETOUR_TRAMPOLINE(trampoline_prototype, target_name) +// +// The naked trampoline must be at least DETOUR_TRAMPOLINE_SIZE bytes. +// +#define DETOUR_TRAMPOLINE_SIZE 32 +#define DETOUR_SECTION_HEADER_SIGNATURE 0x00727444 // "Dtr\0" + +#define DETOUR_TRAMPOLINE(trampoline,target) \ +static PVOID __fastcall _Detours_GetVA_##target(VOID) \ +{ \ + return ⌖ \ +} \ +\ +__declspec(naked) trampoline \ +{ \ + __asm { nop };\ + __asm { nop };\ + __asm { call _Detours_GetVA_##target };\ + __asm { jmp eax };\ + __asm { ret };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ +} + +#define DETOUR_TRAMPOLINE_EMPTY(trampoline) \ +__declspec(naked) trampoline \ +{ \ + __asm { nop };\ + __asm { nop };\ + __asm { xor eax, eax };\ + __asm { mov eax, [eax] };\ + __asm { ret };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ + __asm { nop };\ +} + +/////////////////////////////////////////////////////////// Binary Structures. +// +#pragma pack(push, 8) +typedef struct _DETOUR_SECTION_HEADER +{ + DWORD cbHeaderSize; + DWORD nSignature; + DWORD nDataOffset; + DWORD cbDataSize; + + DWORD nOriginalImportVirtualAddress; + DWORD nOriginalImportSize; + DWORD nOriginalBoundImportVirtualAddress; + DWORD nOriginalBoundImportSize; + + DWORD nOriginalIatVirtualAddress; + DWORD nOriginalIatSize; + DWORD nOriginalSizeOfImage; + DWORD nReserve; +} DETOUR_SECTION_HEADER, *PDETOUR_SECTION_HEADER; + +typedef struct _DETOUR_SECTION_RECORD +{ + DWORD cbBytes; + DWORD nReserved; + GUID guid; +} DETOUR_SECTION_RECORD, *PDETOUR_SECTION_RECORD; +#pragma pack(pop) + +#define DETOUR_SECTION_HEADER_DECLARE(cbSectionSize) \ +{ \ + sizeof(DETOUR_SECTION_HEADER),\ + DETOUR_SECTION_HEADER_SIGNATURE,\ + sizeof(DETOUR_SECTION_HEADER),\ + (cbSectionSize),\ + \ + 0,\ + 0,\ + 0,\ + 0,\ + \ + 0,\ + 0,\ + 0,\ + 0,\ +} + +///////////////////////////////////////////////////////////// Binary Typedefs. +// +typedef BOOL (CALLBACK *PF_DETOUR_BINARY_BYWAY_CALLBACK)(PVOID pContext, + PCHAR pszFile, + PCHAR *ppszOutFile); +typedef BOOL (CALLBACK *PF_DETOUR_BINARY_FILE_CALLBACK)(PVOID pContext, + PCHAR pszOrigFile, + PCHAR pszFile, + PCHAR *ppszOutFile); +typedef BOOL (CALLBACK *PF_DETOUR_BINARY_SYMBOL_CALLBACK)(PVOID pContext, + DWORD nOrdinal, + PCHAR pszOrigSymbol, + PCHAR pszSymbol, + PCHAR *ppszOutSymbol); +typedef BOOL (CALLBACK *PF_DETOUR_BINARY_FINAL_CALLBACK)(PVOID pContext); +typedef BOOL (CALLBACK *PF_DETOUR_BINARY_EXPORT_CALLBACK)(PVOID pContext, + DWORD nOrdinal, + PCHAR pszName, + PBYTE pbCode); + +typedef VOID * PDETOUR_BINARY; +typedef VOID * PDETOUR_LOADED_BINARY; + +//////////////////////////////////////////////////////// Trampoline Functions. +// +PBYTE WINAPI DetourFunction(PBYTE pbTargetFunction, + PBYTE pbDetourFunction); + +BOOL WINAPI DetourFunctionWithEmptyTrampoline(PBYTE pbTrampoline, + PBYTE pbTarget, + PBYTE pbDetour); + +BOOL WINAPI DetourFunctionWithEmptyTrampolineEx(PBYTE pbTrampoline, + PBYTE pbTarget, + PBYTE pbDetour, + PBYTE *ppbRealTrampoline, + PBYTE *ppbRealTarget, + PBYTE *ppbRealDetour); + +BOOL WINAPI DetourFunctionWithTrampoline(PBYTE pbTrampoline, + PBYTE pbDetour); + +BOOL WINAPI DetourFunctionWithTrampolineEx(PBYTE pbTrampoline, + PBYTE pbDetour, + PBYTE *ppbRealTrampoline, + PBYTE *ppbRealTarget); + +BOOL WINAPI DetourRemove(PBYTE pbTrampoline, PBYTE pbDetour); + +////////////////////////////////////////////////////////////// Code Functions. +// +PBYTE WINAPI DetourFindFunction(PCHAR pszModule, PCHAR pszFunction); +PBYTE WINAPI DetourGetFinalCode(PBYTE pbCode, BOOL fSkipJmp); + +PBYTE WINAPI DetourCopyInstruction(PBYTE pbDst, PBYTE pbSrc, PBYTE *ppbTarget); +PBYTE WINAPI DetourCopyInstructionEx(PBYTE pbDst, + PBYTE pbSrc, + PBYTE *ppbTarget, + LONG *plExtra); + +///////////////////////////////////////////////////// Loaded Binary Functions. +// +HMODULE WINAPI DetourEnumerateModules(HMODULE hModuleLast); +PBYTE WINAPI DetourGetEntryPoint(HMODULE hModule); +BOOL WINAPI DetourEnumerateExports(HMODULE hModule, + PVOID pContext, + PF_DETOUR_BINARY_EXPORT_CALLBACK pfExport); + +PBYTE WINAPI DetourFindPayload(HMODULE hModule, REFGUID rguid, DWORD *pcbData); +DWORD WINAPI DetourGetSizeOfPayloads(HMODULE hModule); + +///////////////////////////////////////////////// Persistent Binary Functions. +// +BOOL WINAPI DetourBinaryBindA(PCHAR pszFile, PCHAR pszDll, PCHAR pszPath); +BOOL WINAPI DetourBinaryBindW(PWCHAR pwzFile, PWCHAR pwzDll, PWCHAR pwzPath); +#ifdef UNICODE +#define DetourBinaryBind DetourBinaryBindW +#else +#define DetourBinaryBind DetourBinaryBindA +#endif // !UNICODE + +PDETOUR_BINARY WINAPI DetourBinaryOpen(HANDLE hFile); +PBYTE WINAPI DetourBinaryEnumeratePayloads(PDETOUR_BINARY pBinary, + GUID *pGuid, + DWORD *pcbData, + DWORD *pnIterator); +PBYTE WINAPI DetourBinaryFindPayload(PDETOUR_BINARY pBinary, + REFGUID rguid, + DWORD *pcbData); +PBYTE WINAPI DetourBinarySetPayload(PDETOUR_BINARY pBinary, + REFGUID rguid, + PBYTE pbData, + DWORD cbData); +BOOL WINAPI DetourBinaryDeletePayload(PDETOUR_BINARY pBinary, REFGUID rguid); +BOOL WINAPI DetourBinaryPurgePayloads(PDETOUR_BINARY pBinary); +BOOL WINAPI DetourBinaryResetImports(PDETOUR_BINARY pBinary); +BOOL WINAPI DetourBinaryEditImports(PDETOUR_BINARY pBinary, + PVOID pContext, + PF_DETOUR_BINARY_BYWAY_CALLBACK pfByway, + PF_DETOUR_BINARY_FILE_CALLBACK pfFile, + PF_DETOUR_BINARY_SYMBOL_CALLBACK pfSymbol, + PF_DETOUR_BINARY_FINAL_CALLBACK pfFinal); +BOOL WINAPI DetourBinaryWrite(PDETOUR_BINARY pBinary, HANDLE hFile); +BOOL WINAPI DetourBinaryClose(PDETOUR_BINARY pBinary); + +/////////////////////////////////////////////// First Chance Exception Filter. +// +LPTOP_LEVEL_EXCEPTION_FILTER WINAPI +DetourFirstChanceExceptionFilter(LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelFilter); + +///////////////////////////////////////////////// Create Process & Inject Dll. +// +typedef BOOL (WINAPI *PDETOUR_CREATE_PROCESS_ROUTINEA) + (LPCSTR lpApplicationName, + LPSTR lpCommandLine, + LPSECURITY_ATTRIBUTES lpProcessAttributes, + LPSECURITY_ATTRIBUTES lpThreadAttributes, + BOOL bInheritHandles, + DWORD dwCreationFlags, + LPVOID lpEnvironment, + LPCSTR lpCurrentDirectory, + LPSTARTUPINFOA lpStartupInfo, + LPPROCESS_INFORMATION lpProcessInformation); + +typedef BOOL (WINAPI *PDETOUR_CREATE_PROCESS_ROUTINEW) + (LPCWSTR lpApplicationName, + LPWSTR lpCommandLine, + LPSECURITY_ATTRIBUTES lpProcessAttributes, + LPSECURITY_ATTRIBUTES lpThreadAttributes, + BOOL bInheritHandles, + DWORD dwCreationFlags, + LPVOID lpEnvironment, + LPCWSTR lpCurrentDirectory, + LPSTARTUPINFOW lpStartupInfo, + LPPROCESS_INFORMATION lpProcessInformation); + +BOOL WINAPI DetourCreateProcessWithDllA(LPCSTR lpApplicationName, + LPSTR lpCommandLine, + LPSECURITY_ATTRIBUTES lpProcessAttributes, + LPSECURITY_ATTRIBUTES lpThreadAttributes, + BOOL bInheritHandles, + DWORD dwCreationFlags, + LPVOID lpEnvironment, + LPCSTR lpCurrentDirectory, + LPSTARTUPINFOA lpStartupInfo, + LPPROCESS_INFORMATION lpProcessInformation, + LPCSTR lpDllName, + PDETOUR_CREATE_PROCESS_ROUTINEA + pfCreateProcessA); + +BOOL WINAPI DetourCreateProcessWithDllW(LPCWSTR lpApplicationName, + LPWSTR lpCommandLine, + LPSECURITY_ATTRIBUTES lpProcessAttributes, + LPSECURITY_ATTRIBUTES lpThreadAttributes, + BOOL bInheritHandles, + DWORD dwCreationFlags, + LPVOID lpEnvironment, + LPCWSTR lpCurrentDirectory, + LPSTARTUPINFOW lpStartupInfo, + LPPROCESS_INFORMATION lpProcessInformation, + LPCWSTR lpDllName, + PDETOUR_CREATE_PROCESS_ROUTINEW + pfCreateProcessW); + +#ifdef UNICODE +#define DetourCreateProcessWithDll DetourCreateProcessWithDllW +#define PDETOUR_CREATE_PROCESS_ROUTINE PDETOUR_CREATE_PROCESS_ROUTINEW +#else +#define DetourCreateProcessWithDll DetourCreateProcessWithDllA +#define PDETOUR_CREATE_PROCESS_ROUTINE PDETOUR_CREATE_PROCESS_ROUTINEA +#endif // !UNICODE + +BOOL WINAPI DetourContinueProcessWithDllA(HANDLE hProcess, LPCSTR lpDllName); +BOOL WINAPI DetourContinueProcessWithDllW(HANDLE hProcess, LPCWSTR lpDllName); + +#ifdef UNICODE +#define DetourContinueProcessWithDll DetourContinueProcessWithDllW +#else +#define DetourContinueProcessWithDll DetourContinueProcessWithDllA +#endif // !UNICODE +// +////////////////////////////////////////////////////////////////////////////// +#ifdef __cplusplus +} +#endif // __cplusplus + +/////////////////////////////////////////////////////////////////// Old Names. +// +#define ContinueProcessWithDll DetourContinueProcessWithDll +#define ContinueProcessWithDllA DetourContinueProcessWithDllA +#define ContinueProcessWithDllW DetourContinueProcessWithDllW +#define CreateProcessWithDll DetourCreateProcessWithDll +#define CreateProcessWithDllA DetourCreateProcessWithDllA +#define CreateProcessWithDllW DetourCreateProcessWithDllW +#define DETOUR_TRAMPOLINE_WO_TARGET DETOUR_TRAMPOLINE_EMPTY +#define DetourBinaryPurgePayload DetourBinaryPurgePayloads +#define DetourEnumerateExportsForInstance DetourEnumerateExports +#define DetourEnumerateInstances DetourEnumerateModules +#define DetourFindEntryPointForInstance DetourGetEntryPoint +#define DetourFindFinalCode DetourGetFinalCode +#define DetourFindPayloadInBinary DetourFindPayload +#define DetourGetSizeOfBinary DetourGetSizeOfPayloads +#define DetourRemoveWithTrampoline DetourRemove +#define PCREATE_PROCESS_ROUTINE PDETOUR_CREATE_PROCESS_ROUTINE +#define PCREATE_PROCESS_ROUTINEA PDETOUR_CREATE_PROCESS_ROUTINEA +#define PCREATE_PROCESS_ROUTINEW PDETOUR_CREATE_PROCESS_ROUTINEW +// + +//////////////////////////////////////////////// Detours Internal Definitions. +// +#ifdef __cplusplus +#ifdef DETOURS_INTERNAL + +////////////////////////////////////////////////////////////////////////////// +// +#ifdef IMAGEAPI // defined by IMAGEHLP.H +typedef LPAPI_VERSION (NTAPI *PF_ImagehlpApiVersionEx)(LPAPI_VERSION AppVersion); + +typedef BOOL (NTAPI *PF_SymInitialize)(IN HANDLE hProcess, + IN LPSTR UserSearchPath, + IN BOOL fInvadeProcess); +typedef DWORD (NTAPI *PF_SymSetOptions)(IN DWORD SymOptions); +typedef DWORD (NTAPI *PF_SymGetOptions)(VOID); +typedef BOOL (NTAPI *PF_SymLoadModule)(IN HANDLE hProcess, + IN HANDLE hFile, + IN PSTR ImageName, + IN PSTR ModuleName, + IN DWORD BaseOfDll, + IN DWORD SizeOfDll); +typedef BOOL (NTAPI *PF_SymGetModuleInfo)(IN HANDLE hProcess, + IN DWORD dwAddr, + OUT PIMAGEHLP_MODULE ModuleInfo); +typedef BOOL (NTAPI *PF_SymGetSymFromName)(IN HANDLE hProcess, + IN LPSTR Name, + OUT PIMAGEHLP_SYMBOL Symbol); +typedef BOOL (NTAPI *PF_BindImage)(IN LPSTR pszImageName, + IN LPSTR pszDllPath, + IN LPSTR pszSymbolPath); + +typedef struct _DETOUR_SYM_INFO +{ + HANDLE hProcess; + HMODULE hImageHlp; + PF_ImagehlpApiVersionEx pfImagehlpApiVersionEx; + PF_SymInitialize pfSymInitialize; + PF_SymSetOptions pfSymSetOptions; + PF_SymGetOptions pfSymGetOptions; + PF_SymLoadModule pfSymLoadModule; + PF_SymGetModuleInfo pfSymGetModuleInfo; + PF_SymGetSymFromName pfSymGetSymFromName; + PF_BindImage pfBindImage; +} DETOUR_SYM_INFO, *PDETOUR_SYM_INFO; + +PDETOUR_SYM_INFO DetourLoadImageHlp(VOID); + +#endif // IMAGEAPI + +////////////////////////////////////////////////////////////////////////////// +// +class CDetourEnableWriteOnCodePage +{ +public: + CDetourEnableWriteOnCodePage(PBYTE pbCode, LONG cbCode = DETOUR_TRAMPOLINE_SIZE) + { + m_pbCode = pbCode; + m_cbCode = cbCode; + m_dwOldPerm = 0; + m_hProcess = GetCurrentProcess(); + + if (m_pbCode && m_cbCode) { + if (!FlushInstructionCache(m_hProcess, pbCode, cbCode)) { + return; + } + if (!VirtualProtect(pbCode, + cbCode, + PAGE_EXECUTE_READWRITE, + &m_dwOldPerm)) { + return; + } + } + } + + ~CDetourEnableWriteOnCodePage() + { + if (m_dwOldPerm && m_pbCode && m_cbCode) { + DWORD dwTemp = 0; + if (!FlushInstructionCache(m_hProcess, m_pbCode, m_cbCode)) { + return; + } + if (!VirtualProtect(m_pbCode, m_cbCode, m_dwOldPerm, &dwTemp)) { + return; + } + } + } + + BOOL SetPermission(DWORD dwPerms) + { + if (m_dwOldPerm && m_pbCode && m_cbCode) { + m_dwOldPerm = dwPerms; + return TRUE; + } + return FALSE; + } + + BOOL IsValid(VOID) + { + return m_pbCode && m_cbCode && m_dwOldPerm; + } + +private: + HANDLE m_hProcess; + PBYTE m_pbCode; + LONG m_cbCode; + DWORD m_dwOldPerm; +}; + +////////////////////////////////////////////////////////////////////////////// +// +inline PBYTE DetourGenMovEax(PBYTE pbCode, UINT32 nValue) +{ + *pbCode++ = 0xB8; + *((UINT32*&)pbCode)++ = nValue; + return pbCode; +} + +inline PBYTE DetourGenMovEbx(PBYTE pbCode, UINT32 nValue) +{ + *pbCode++ = 0xBB; + *((UINT32*&)pbCode)++ = nValue; + return pbCode; +} + +inline PBYTE DetourGenMovEcx(PBYTE pbCode, UINT32 nValue) +{ + *pbCode++ = 0xB9; + *((UINT32*&)pbCode)++ = nValue; + return pbCode; +} + +inline PBYTE DetourGenMovEdx(PBYTE pbCode, UINT32 nValue) +{ + *pbCode++ = 0xBA; + *((UINT32*&)pbCode)++ = nValue; + return pbCode; +} + +inline PBYTE DetourGenMovEsi(PBYTE pbCode, UINT32 nValue) +{ + *pbCode++ = 0xBE; + *((UINT32*&)pbCode)++ = nValue; + return pbCode; +} + +inline PBYTE DetourGenMovEdi(PBYTE pbCode, UINT32 nValue) +{ + *pbCode++ = 0xBF; + *((UINT32*&)pbCode)++ = nValue; + return pbCode; +} + +inline PBYTE DetourGenMovEbp(PBYTE pbCode, UINT32 nValue) +{ + *pbCode++ = 0xBD; + *((UINT32*&)pbCode)++ = nValue; + return pbCode; +} + +inline PBYTE DetourGenMovEsp(PBYTE pbCode, UINT32 nValue) +{ + *pbCode++ = 0xBC; + *((UINT32*&)pbCode)++ = nValue; + return pbCode; +} + +inline PBYTE DetourGenPush(PBYTE pbCode, UINT32 nValue) +{ + *pbCode++ = 0x68; + *((UINT32*&)pbCode)++ = nValue; + return pbCode; +} + +inline PBYTE DetourGenPushad(PBYTE pbCode) +{ + *pbCode++ = 0x60; + return pbCode; +} + +inline PBYTE DetourGenPopad(PBYTE pbCode) +{ + *pbCode++ = 0x61; + return pbCode; +} + +inline PBYTE DetourGenJmp(PBYTE pbCode, PBYTE pbJmpDst, PBYTE pbJmpSrc = 0) +{ + if (pbJmpSrc == 0) { + pbJmpSrc = pbCode; + } + *pbCode++ = 0xE9; + *((INT32*&)pbCode)++ = pbJmpDst - (pbJmpSrc + 5); + return pbCode; +} + +inline PBYTE DetourGenCall(PBYTE pbCode, PBYTE pbJmpDst, PBYTE pbJmpSrc = 0) +{ + if (pbJmpSrc == 0) { + pbJmpSrc = pbCode; + } + *pbCode++ = 0xE8; + *((INT32*&)pbCode)++ = pbJmpDst - (pbJmpSrc + 5); + return pbCode; +} + +inline PBYTE DetourGenBreak(PBYTE pbCode) +{ + *pbCode++ = 0xcc; + return pbCode; +} + +inline PBYTE DetourGenRet(PBYTE pbCode) +{ + *pbCode++ = 0xc3; + return pbCode; +} + +inline PBYTE DetourGenNop(PBYTE pbCode) +{ + *pbCode++ = 0x90; + return pbCode; +} +#endif DETOURS_INTERAL +#endif // __cplusplus + +#endif // _DETOURS_H_ +// +//////////////////////////////////////////////////////////////// End of File. diff --git a/lib_acl_cpp/samples/winaio/heap_hook.cpp b/lib_acl_cpp/samples/winaio/heap_hook.cpp new file mode 100644 index 000000000..e3885a75a --- /dev/null +++ b/lib_acl_cpp/samples/winaio/heap_hook.cpp @@ -0,0 +1,563 @@ +#include "stdafx.h" +#include +#include "dbghelpapi.h" + +#define BLOCKMAPRESERVE 64 // This should strike a balance between memory use and a desire to minimize heap hits. +#define HEAPMAPRESERVE 2 // Usually there won't be more than a few heaps in the process, so this should be small. +#define MAXSYMBOLNAMELENGTH 256 // Maximum symbol name length that we will allow. Longer names will be truncated. +#define MODULESETRESERVE 16 // There are likely to be several modules loaded in the process. + +typedef struct patchentry_s +{ + LPCSTR exportmodulename; // The name of the module exporting the patched API. + LPCSTR importname; // The name (or ordinal) of the imported API being patched. + LPSTR modulepath; // (Optional) module path. If the module is loaded, then VLD will fill this in at startup. + LPCVOID replacement; // Pointer to the function to which the imported API should be patched through to. +} patchentry_t; + +static HMODULE __dbghelp; +////////////////////////////////////////////////////////////////////////// + +static BOOL linkdebughelplibrary (void) +{ + TCHAR dbghelppath [MAX_PATH] = { 0 }; + LPCSTR functionname; + DWORD length = MAX_PATH; + + strncpy(dbghelppath, "dbghelp.dll", MAX_PATH); + + // Load the copy of dbghelp.dll installed by Visual Leak Detector. + __dbghelp = LoadLibrary(dbghelppath); + if (__dbghelp == NULL) + abort(); + + // Obtain pointers to the exported functions that we will be using. + functionname = "EnumerateLoadedModules"; + if ((pEnumerateLoadedModules = (EnumerateLoadedModules_t) + GetProcAddress(__dbghelp, functionname)) == NULL) + { + goto getprocaddressfailure; + } + functionname = "ImageDirectoryEntryToDataEx"; + if ((pImageDirectoryEntryToDataEx = (ImageDirectoryEntryToDataEx_t) + GetProcAddress(__dbghelp, functionname)) == NULL) + { + goto getprocaddressfailure; + } + functionname = "StackWalk"; + if ((pStackWalk = (StackWalk_t) + GetProcAddress(__dbghelp, functionname)) == NULL) + { + goto getprocaddressfailure; + } + functionname = "SymCleanup"; + if ((pSymCleanup = (SymCleanup_t) + GetProcAddress(__dbghelp, functionname)) == NULL) + { + goto getprocaddressfailure; + } + functionname = "SymFromAddr"; + if ((pSymFromAddr = (SymFromAddr_t) + GetProcAddress(__dbghelp, functionname)) == NULL) + { + goto getprocaddressfailure; + } + functionname = "SymFunctionTableAccess"; + if ((pSymFunctionTableAccess = (SymFunctionTableAccess_t) + GetProcAddress(__dbghelp, functionname)) == NULL) + { + goto getprocaddressfailure; + } + functionname = "SymGetLineFromAddr"; + if ((pSymGetLineFromAddr = (SymGetLineFromAddr_t) + GetProcAddress(__dbghelp, functionname)) == NULL) + { + goto getprocaddressfailure; + } + functionname = "SymGetModuleBase"; + if ((pSymGetModuleBase = (SymGetModuleBase_t) + GetProcAddress(__dbghelp, functionname)) == NULL) + { + goto getprocaddressfailure; + } + functionname = "SymInitialize"; + if ((pSymInitialize = (SymInitialize_t) + GetProcAddress(__dbghelp, functionname)) == NULL) + { + goto getprocaddressfailure; + } + functionname = "SymLoadModule"; + if ((pSymLoadModule = (SymLoadModule_t) + GetProcAddress(__dbghelp, functionname)) == NULL) + { + goto getprocaddressfailure; + } + functionname = "SymGetModuleInfo"; + if ((pSymGetModuleInfo = (SymGetModuleInfo_t) + GetProcAddress(__dbghelp, functionname)) == NULL) + { + goto getprocaddressfailure; + } + functionname = "SymSetOptions"; + if ((pSymSetOptions = (SymSetOptions_t) + GetProcAddress(__dbghelp, functionname)) == NULL) + { + goto getprocaddressfailure; + } + functionname = "SymUnloadModule"; + if ((pSymUnloadModule = (SymUnloadModule_t) + GetProcAddress(__dbghelp, functionname)) == NULL) + { + goto getprocaddressfailure; + } + return TRUE; + +getprocaddressfailure: + // One of the required exports was not found. + abort(); + return FALSE; +} + +////////////////////////////////////////////////////////////////////////// + +typedef LONG (__stdcall *LdrLoadDll_t) (LPSTR, PDWORD, LPSTR, PHANDLE); +typedef LPVOID (__stdcall *RtlAllocateHeap_t) (HANDLE, DWORD, SIZE_T); +typedef BOOL (__stdcall *RtlFreeHeap_t) (HANDLE, DWORD, LPVOID); +typedef LPVOID (__stdcall *RtlReAllocateHeap_t) (HANDLE, DWORD, LPVOID, SIZE_T); + +static HANDLE currentprocess; // Pseudo-handle for the current process. +static HANDLE currentthread; // Pseudo-handle for the current thread. +static HANDLE processheap; // Handle to the process's heap (COM allocations come from here). + +static LdrLoadDll_t LdrLoadDll; +static RtlAllocateHeap_t RtlAllocateHeap; +static RtlFreeHeap_t RtlFreeHeap; +static RtlReAllocateHeap_t RtlReAllocateHeap; + +typedef void* (__cdecl *_calloc_dbg_t) (size_t, size_t, int, const char*, int); +typedef void* (__cdecl *_malloc_dbg_t) (size_t, int, const char *, int); +typedef void* (__cdecl *_realloc_dbg_t) (void *, size_t, int, const char *, int); +typedef void* (__cdecl *calloc_t) (size_t, size_t); +typedef void* (__cdecl *malloc_t) (size_t); +typedef void* (__cdecl *realloc_t) (void *, size_t); + +static _calloc_dbg_t pcrtd__calloc_dbg = NULL; +static _malloc_dbg_t pcrtd__malloc_dbg = NULL; +static _realloc_dbg_t pcrtd__realloc_dbg = NULL; + +static CRITICAL_SECTION loadLock; +////////////////////////////////////////////////////////////////////////// + +#define R2VA(modulebase, rva) (((PBYTE)modulebase) + rva) // Relative Virtual Address to Virtual Address conversion. + +static BOOL patchimport (HMODULE importmodule, LPCSTR exportmodulename, + LPCSTR exportmodulepath, LPCSTR importname, LPCVOID replacement) +{ + HMODULE exportmodule; + IMAGE_THUNK_DATA *iate; + IMAGE_IMPORT_DESCRIPTOR *idte; + FARPROC import; + DWORD protect; + IMAGE_SECTION_HEADER *section; + ULONG size; + + assert(exportmodulename != NULL); + + // Locate the importing module's Import Directory Table (IDT) entry for the + // exporting module. The importing module actually can have several IATs -- + // one for each export module that it imports something from. The IDT entry + // gives us the offset of the IAT for the module we are interested in. + idte = (IMAGE_IMPORT_DESCRIPTOR*)pImageDirectoryEntryToDataEx( + (PVOID)importmodule, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, + &size, §ion); + if (idte == NULL) + { + // This module has no IDT (i.e. it imports nothing). + return FALSE; + } + while (idte->OriginalFirstThunk != 0x0) + { + if (_stricmp((PCHAR)R2VA(importmodule, idte->Name), + exportmodulename) == 0) + { + // Found the IDT entry for the exporting module. + break; + } + idte++; + } + if (idte->OriginalFirstThunk == 0x0) + { + // The importing module does not import anything from the exporting + // module. + return FALSE; + } + + // Get the *real* address of the import. If we find this address in the IAT, + // then we've found the entry that needs to be patched. + if (exportmodulepath != NULL) + { + // Always try to use the full path if available. There seems to be a bug + // (or is this a new feature of the "side-by-side" kruft?) where + // GetModuleHandle sometimes fails if the full path is not supplied for + // DLLs in the side-by-side cache. + exportmodule = GetModuleHandle(exportmodulepath); + } + else { + // No full path available. Try using just the module name by itself. + exportmodule = GetModuleHandle(exportmodulename); + } + assert(exportmodule != NULL); + import = GetProcAddress(exportmodule, importname); + assert(import != NULL); // Perhaps the named export module does not actually export the named import? + + // Locate the import's IAT entry. + iate = (IMAGE_THUNK_DATA*)R2VA(importmodule, idte->FirstThunk); + while (iate->u1.Function != 0x0) + { + if (iate->u1.Function == (DWORD_PTR)import) + { + // Found the IAT entry. Overwrite the address stored in the IAT + // entry with the address of the replacement. Note that the IAT + // entry may be write-protected, so we must first ensure that it is + // writable. + VirtualProtect(&iate->u1.Function, sizeof(iate->u1.Function), + PAGE_READWRITE, &protect); + iate->u1.Function = (DWORD_PTR) replacement; + VirtualProtect(&iate->u1.Function, sizeof(iate->u1.Function), + protect, &protect); + + // The patch has been installed in the import module. + return TRUE; + } + iate++; + } + + // The import's IAT entry was not found. The importing module does not + // import the specified import. + return FALSE; +} + +static BOOL patchmodule (HMODULE importmodule, patchentry_t patchtable [], UINT tablesize) +{ + patchentry_t *entry; + UINT index; + BOOL patched = FALSE; + + // Loop through the import patch table, individually patching each import + // listed in the table. + for (index = 0; index < tablesize; index++) + { + entry = &patchtable[index]; + if (patchimport(importmodule, entry->exportmodulename, + entry->modulepath, entry->importname, + entry->replacement) == TRUE) + { + patched = TRUE; + } + } + + return patched; +} + +////////////////////////////////////////////////////////////////////////// + +static HANDLE _HeapCreate (DWORD options, SIZE_T initsize, SIZE_T maxsize) +{ + HANDLE heap; + // Create the heap. + heap = HeapCreate(options, initsize, maxsize); + return heap; +} + +static BOOL _HeapDestroy (HANDLE heap) +{ + return HeapDestroy(heap); +} + +static LPVOID _RtlAllocateHeap (HANDLE heap, DWORD flags, SIZE_T size) +{ + LPVOID block; + // Allocate the block. + //heap = processheap; + if (heap == 0) + return 0; + block = RtlAllocateHeap(heap, flags, size); + return block; +} + +static BOOL _RtlFreeHeap (HANDLE heap, DWORD flags, LPVOID mem) +{ + BOOL status; + status = RtlFreeHeap(heap, flags, mem); + return status; +} + +static LPVOID _RtlReAllocateHeap (HANDLE heap, DWORD flags, LPVOID mem, SIZE_T size) +{ + LPVOID newmem; + // Reallocate the block. + newmem = RtlReAllocateHeap(heap, flags, mem, size); + return newmem; +} + +static patchentry_t __hook_table[] = +{ + // Win32 heap APIs. + //"kernel32.dll", "GetProcAddress", NULL, _GetProcAddress, // Not heap related, but can be used to obtain pointers to heap functions. + { "kernel32.dll", "HeapAlloc", NULL, _RtlAllocateHeap }, + { "kernel32.dll", "HeapCreate", NULL, _HeapCreate }, + { "kernel32.dll", "HeapDestroy", NULL, _HeapDestroy }, + { "kernel32.dll", "HeapFree", NULL, _RtlFreeHeap }, + { "kernel32.dll", "HeapReAlloc", NULL, _RtlReAllocateHeap }, + +}; + +static BOOL CALLBACK attachtomodule(PSTR modulepath, ULONG modulebase, + ULONG modulesize, PVOID userContext) +{ + UINT tablesize = sizeof(__hook_table) / sizeof(patchentry_t); + + // Attach to the module. + patchmodule((HMODULE)modulebase, __hook_table, tablesize); + + return (TRUE); +} + +static LONG _LdrLoadDll (LPSTR searchpath, PDWORD flags, + LPSTR modulename, PHANDLE modulehandle) +{ + LONG status; + + EnterCriticalSection(&loadLock); + // Load the DLL. + status = LdrLoadDll(searchpath, flags, modulename, modulehandle); + + if (0 == status) + { + // Attach to any newly loaded modules. + pEnumerateLoadedModules(currentprocess, attachtomodule, NULL); + } + + LeaveCriticalSection(&loadLock); + return status; +} + +class CHeapHook +{ +public: + CHeapHook() + { + HMODULE kernel32 = GetModuleHandle("kernel32.dll"); + HMODULE ntdll = GetModuleHandle("ntdll.dll"); + + // Initialize global variables. + currentprocess = GetCurrentProcess(); + currentthread = GetCurrentThread(); + LdrLoadDll = (LdrLoadDll_t)GetProcAddress(ntdll, "LdrLoadDll"); + processheap = GetProcessHeap(); + RtlAllocateHeap = (RtlAllocateHeap_t)GetProcAddress(ntdll, "RtlAllocateHeap"); + RtlFreeHeap = (RtlFreeHeap_t)GetProcAddress(ntdll, "RtlFreeHeap"); + RtlReAllocateHeap = (RtlReAllocateHeap_t)GetProcAddress(ntdll, "RtlReAllocateHeap"); + + InitializeCriticalSection(&loadLock); + linkdebughelplibrary(); + + // Patch into kernel32.dll's calls to LdrLoadDll so that VLD can + // dynamically attach to new modules loaded during runtime. + //patchimport(kernel32, "ntdll.dll", NULL, "LdrLoadDll", _LdrLoadDll); + + pEnumerateLoadedModules(currentprocess, &attachtomodule, NULL); + } + + ~CHeapHook() + { + + } +}; + +// The one and only VisualLeakDetector object instance. +//__declspec(dllexport) CHeapHook vld; + +////////////////////////////////////////////////////////////////////////// +#include +#include "lib_acl.h" +#include "detours.h" +#include "heap_hook.h" + +LPVOID WINAPI Real_HeapAlloc( HANDLE hHeap, DWORD dwFlags, SIZE_T dwBytes); +BOOL WINAPI Real_HeapFree( HANDLE hHeap, DWORD dwFlags, LPVOID lpMem); +LPVOID WINAPI Real_HeapReAlloc(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem, SIZE_T dwBytes); + +DETOUR_TRAMPOLINE(LPVOID WINAPI + Real_HeapAlloc(HANDLE hHeap, DWORD dwFlags, SIZE_T dwBytes), + HeapAlloc); + +DETOUR_TRAMPOLINE(BOOL WINAPI + Real_HeapFree(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem), + HeapFree); + +DETOUR_TRAMPOLINE(LPVOID WINAPI + Real_HeapReAlloc(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem, SIZE_T dwBytes), + HeapReAlloc); + +BOOL WINAPI DetourFunctionWithTrampoline(PBYTE pbTrampoline, + PBYTE pbDetour); +LPVOID WINAPI HookHeapAlloc( HANDLE hHeap, DWORD dwFlags, SIZE_T dwBytes ); +BOOL WINAPI HookHeapFree( HANDLE hHeap, DWORD dwFlags, LPVOID lpMem ); +LPVOID WINAPI HookHeapReAlloc( HANDLE hHeap, DWORD dwFlags, LPVOID lpMem, SIZE_T dwBytes ); + +LPVOID WINAPI HookHeapAlloc( + HANDLE hHeap, // handle to private heap block + DWORD dwFlags, // heap allocation control + SIZE_T dwBytes // number of bytes to allocate + ) +{ + const char* myname = "HookHeapAlloc\r\n"; + LPVOID p = Real_HeapAlloc(hHeap, dwFlags, dwBytes); + + //TraceMemoryAllocation( p, dwBytes, fnHeapAlloc ); + + //write(1, myname, strlen(myname)); + return p; +} + + +BOOL WINAPI HookHeapFree( + HANDLE hHeap, // handle to heap + DWORD dwFlags, // heap free options + LPVOID lpMem // pointer to memory + ) +{ + BOOL res = Real_HeapFree(hHeap, dwFlags, lpMem); + const char* myname = "HookHeapFree\r\n"; + //TraceMemoryRelease( lpMem ); + + //write(1, myname, strlen(myname)); + return res; +} + + +LPVOID WINAPI HookHeapReAlloc( + HANDLE hHeap, // handle to heap block + DWORD dwFlags, // heap reallocation options + LPVOID lpMem, // pointer to memory to reallocate + SIZE_T dwBytes // number of bytes to reallocate + ) +{ + const char* myname = "HookHeapReAlloc\r\n"; + LPVOID p = Real_HeapReAlloc(hHeap, dwFlags, lpMem, dwBytes); + + // the previous block was freed + //if( !!lpMem ) + // TraceMemoryRelease( lpMem ); + + // new block allocated (may be in same address) + //TraceMemoryAllocation( p, dwBytes, fnHeapAlloc ); + + //write(1, myname, strlen(myname)); + return p; +} + +static void* malloc_hook(const char* fname, int lineno, size_t len) +{ + printf(">>>%s\n", __FUNCTION__); + + void* ptr = Real_HeapAlloc(processheap, 0, len); + if (ptr == NULL) + { + char buf[1024]; + int n = WSAGetLastError(); + printf("error: %d, %s\n", n, acl_strerror(n, buf, sizeof(buf))); + } + + return ptr; +} + +static void *calloc_hook(const char* fname, int lineno, size_t n, size_t len) +{ + printf(">>>%s\n", __FUNCTION__); + + void* ptr = Real_HeapAlloc(processheap, 0, n * len); + if (ptr == NULL) + return NULL; + memset(ptr, 0, n * 140); + return ptr; +} + +static void *realloc_hook(const char* fname, int lineno, void* ptr, size_t len) +{ + printf(">>>%s\n", __FUNCTION__); + + void* newptr = Real_HeapReAlloc(processheap, 0, ptr, len); + return newptr; +} + +static char *strdup_hook(const char* fname, int lineno, const char* ptr) +{ + printf(">>>%s\n", __FUNCTION__); + + size_t len = strlen(ptr); + char* s = (char*) malloc_hook(fname, lineno, len + 1); + + memcpy(s, (const char*) ptr, len); + s[len] = 0; + return s; +} + +static char *strndup_hook(const char* fname, int lineno, const char* ptr, size_t n) +{ + printf(">>>%s\n", __FUNCTION__); + + size_t len = strlen(ptr); + if (len > n) + len = n; + char* s = (char*) malloc_hook(fname, lineno, len + 1); + memcpy(s, (const char*) ptr, len); + s[len] = 0; + return s; +} + +static void *memdup_hook(const char* fname, int lineno, const void* ptr, size_t n) +{ + printf(">>>%s\n", __FUNCTION__); + + char* p = (char*) malloc_hook(fname, lineno, n); + memcpy(p, (const char*) ptr, n); + return p; +} + +static void free_hook(const char* fname, int lineno, void* ptr) +{ + printf(">>>%s\n", __FUNCTION__); + + Real_HeapFree(processheap, 0, ptr); +} + +CHeapHook2::CHeapHook2() +{ + processheap = GetProcessHeap(); + DetourFunctionWithTrampoline((PBYTE)Real_HeapAlloc, (PBYTE)HookHeapAlloc); + DetourFunctionWithTrampoline((PBYTE)Real_HeapFree, (PBYTE)HookHeapFree); + DetourFunctionWithTrampoline((PBYTE)Real_HeapReAlloc, (PBYTE)HookHeapReAlloc); + + FILE *fp; + AllocConsole(); + fp = freopen("CONOUT$","w+t",stdout); + + acl_mem_hook(malloc_hook, calloc_hook, realloc_hook, + strdup_hook, strndup_hook, memdup_hook, free_hook); + char* p = acl_mystrdup("hello world!\n"); + printf(">>%s\n", p); + acl_myfree(p); + + acl_msg_open("heap.log", "test"); +} + +CHeapHook2::~CHeapHook2() +{ + DetourRemove((PBYTE)Real_HeapAlloc, (PBYTE)HookHeapAlloc); + DetourRemove((PBYTE)Real_HeapFree, (PBYTE)HookHeapFree); + DetourRemove((PBYTE)Real_HeapReAlloc, (PBYTE)HookHeapReAlloc); +} + +//__declspec(dllexport) CHeapHook2 vld2; diff --git a/lib_acl_cpp/samples/winaio/heap_hook.h b/lib_acl_cpp/samples/winaio/heap_hook.h new file mode 100644 index 000000000..ae34e580c --- /dev/null +++ b/lib_acl_cpp/samples/winaio/heap_hook.h @@ -0,0 +1,10 @@ +#pragma once + +class CHeapHook2 +{ +public: + CHeapHook2(); + ~CHeapHook2(); +}; + +extern CHeapHook2 vld2; diff --git a/lib_acl_cpp/samples/winaio/memory.cpp b/lib_acl_cpp/samples/winaio/memory.cpp new file mode 100644 index 000000000..bb4e204d5 --- /dev/null +++ b/lib_acl_cpp/samples/winaio/memory.cpp @@ -0,0 +1,35 @@ +#include "stdafx.h" +#include +#include +#include "malloc.hpp" +#include "memory.h" + +void* __new(size_t n, const char* filename, + const char* funcname, int lineno) +{ + printf(">>>%s(%d), %s: new size: %d\n", + filename, lineno, funcname, (int) n); + + return (acl::acl_new(n, filename, funcname, lineno)); +} + +//void* __new[](size_t n, const char* filename, +// const char* funcname, int lineno) +//{ +// +//} + +void __delete(void* p, const char* filename, + const char* funcname, int lineno) +{ + printf(">>>%s(%d), %s: delete\n", + filename, lineno, funcname); + if (p) + acl::acl_delete(p, filename, funcname, lineno); +} + +//void __delete[](void* p, const char* filename, +// const char* funcname, int lineno) +//{ +// +//} diff --git a/lib_acl_cpp/samples/winaio/memory.h b/lib_acl_cpp/samples/winaio/memory.h new file mode 100644 index 000000000..572628cbe --- /dev/null +++ b/lib_acl_cpp/samples/winaio/memory.h @@ -0,0 +1,36 @@ +#pragma once + +void* __new(size_t n, const char* filename, + const char* funcname, int lineno); + +//void* __new[](size_t n, const char* filename, +// const char* funcname, int lineno); + +void __delete(void* p, const char* filename, + const char* funcname, int lineno); + +//void __delete[](void* p, const char* filename, +// const char* funcname, int lineno); + +inline void* __cdecl operator new(size_t n) +{ + return ::__new(n, __FILE__, __FUNCTION__, __LINE__); +} + +inline void __cdecl operator delete(void *p) +{ + ::__delete(p, __FILE__, __FUNCTION__, __LINE__); +} + +inline void* __cdecl operator new(size_t n, const char* filename, int lineno) +{ + return ::__new(n, filename, __FUNCTION__, lineno); +} + +inline void __cdecl operator delete(void *p, const char* filename, int lineno) +{ + ::__delete(p, filename, __FUNCTION__, lineno); +} + +//#define NEW(n) (::__new((n), __FILE__, __FUNCTION__, __LINE__)) +//#define DELETE(p) (::__delete((p), __FILE__, __FUNCTION__, __LINE__)) diff --git a/lib_acl_cpp/samples/winaio/res/winaio.ico b/lib_acl_cpp/samples/winaio/res/winaio.ico new file mode 100644 index 000000000..8a84ca3d3 Binary files /dev/null and b/lib_acl_cpp/samples/winaio/res/winaio.ico differ diff --git a/lib_acl_cpp/samples/winaio/res/winaio.manifest b/lib_acl_cpp/samples/winaio/res/winaio.manifest new file mode 100644 index 000000000..e6e8e243b --- /dev/null +++ b/lib_acl_cpp/samples/winaio/res/winaio.manifest @@ -0,0 +1,22 @@ + + + +鍦ㄦ璇存槑搴旂敤绋嬪簭 + + + + + + diff --git a/lib_acl_cpp/samples/winaio/res/winaio.rc2 b/lib_acl_cpp/samples/winaio/res/winaio.rc2 new file mode 100644 index 000000000..361f6e40e --- /dev/null +++ b/lib_acl_cpp/samples/winaio/res/winaio.rc2 @@ -0,0 +1,13 @@ +// +// winaio.RC2 - Microsoft Visual C++ 不会直接编辑的资源 +// + +#ifdef APSTUDIO_INVOKED +#error 此文件不能由 Microsoft Visual C++ 编辑 +#endif //APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// 在此处添加手动编辑的资源... + +///////////////////////////////////////////////////////////////////////////// diff --git a/lib_acl_cpp/samples/winaio/resource.h b/lib_acl_cpp/samples/winaio/resource.h new file mode 100644 index 000000000..941ba3e9e --- /dev/null +++ b/lib_acl_cpp/samples/winaio/resource.h @@ -0,0 +1,30 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by winaio.rc +// +#define IDM_ABOUTBOX 0x0010 +#define IDD_ABOUTBOX 100 +#define IDS_ABOUTBOX 101 +#define IDD_WINAIO_DIALOG 102 +#define IDP_SOCKETS_INIT_FAILED 103 +#define IDR_MAINFRAME 128 +#define IDC_LISTEN 1000 +#define IDC_CONNECT 1001 +#define IDC_SET_TIMER 1002 +#define IDC_BUTTON4 1003 +#define IDC_DEL_TIMER 1003 +#define IDC_BUTTON_KEEP_TIMER 1004 +#define IDC_BUTTON_NO_KEEP_TIMER 1005 +#define IDC_BUTTON1 1006 +#define IDC_BUTTON_MEMTEST 1006 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 129 +#define _APS_NEXT_COMMAND_VALUE 32771 +#define _APS_NEXT_CONTROL_VALUE 1007 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/lib_acl_cpp/samples/winaio/stdafx.cpp b/lib_acl_cpp/samples/winaio/stdafx.cpp new file mode 100644 index 000000000..69b70e83e --- /dev/null +++ b/lib_acl_cpp/samples/winaio/stdafx.cpp @@ -0,0 +1,7 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// winaio.pch 将是预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + + diff --git a/lib_acl_cpp/samples/winaio/stdafx.h b/lib_acl_cpp/samples/winaio/stdafx.h new file mode 100644 index 000000000..829606b65 --- /dev/null +++ b/lib_acl_cpp/samples/winaio/stdafx.h @@ -0,0 +1,113 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是经常使用但不常更改的 +// 项目特定的包含文件 + +#pragma once + +#ifdef VC2003 + +#ifndef VC_EXTRALEAN +#define VC_EXTRALEAN // 从 Windows 标头中排除不常使用的资料 +#endif + +// 如果您必须使用下列所指定的平台之前的平台,则修改下面的定义。 +// 有关不同平台的相应值的最新信息,请参考 MSDN。 +#ifndef WINVER // 允许使用 Windows 95 和 Windows NT 4 或更高版本的特定功能。 +#define WINVER 0x0400 //为 Windows98 和 Windows 2000 及更新版本改变为适当的值。 +#endif + +#ifndef _WIN32_WINNT // 允许使用 Windows NT 4 或更高版本的特定功能。 +#define _WIN32_WINNT 0x0400 //为 Windows98 和 Windows 2000 及更新版本改变为适当的值。 +#endif + +#ifndef _WIN32_WINDOWS // 允许使用 Windows 98 或更高版本的特定功能。 +#define _WIN32_WINDOWS 0x0410 //为 Windows Me 及更新版本改变为适当的值。 +#endif + +#ifndef _WIN32_IE // 允许使用 IE 4.0 或更高版本的特定功能。 +#define _WIN32_IE 0x0400 //为 IE 5.0 及更新版本改变为适当的值。 +#endif + +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // 某些 CString 构造函数将是显式的 + +// 关闭 MFC 对某些常见但经常被安全忽略的警告消息的隐藏 +#define _AFX_ALL_WARNINGS + +#include // MFC 核心和标准组件 +#include // MFC 扩展 +#include // MFC 自动化类 + +#include // Internet Explorer 4 公共控件的 MFC 支持 +#ifndef _AFX_NO_AFXCMN_SUPPORT +#include // Windows 公共控件的 MFC 支持 +#endif // _AFX_NO_AFXCMN_SUPPORT + +#include // MFC 套接字扩展 + +////////////////////////////////////////////////////////////////////////////////////// +#else +// stdafx.h : 标准系统包含文件的包含文件, +// 或是经常使用但不常更改的 +// 特定于项目的包含文件 + +#pragma once + +#ifndef _SECURE_ATL +#define _SECURE_ATL 1 +#endif + +#ifndef VC_EXTRALEAN +#define VC_EXTRALEAN // 从 Windows 头中排除极少使用的资料 +#endif + +// 包括 SDKDDKVer.h 将定义最高版本的可用 Windows 平台。 + +// 如果要为以前的 Windows 平台生成应用程序,请包括 WinSDKVer.h,并将 +// WIN32_WINNT 宏设置为要支持的平台,然后再包括 SDKDDKVer.h。 + +#include + +//#ifndef _CRTDBG_MAP_ALLOC +//#define _CRTDBG_MAP_ALLOC +//#include +//#include +//#endif + +//#ifdef _DEBUG +//#define NEW new(_NORMAL_BLOCK, __FILE__, __LINE__) +//// Replace _NORMAL_BLOCK with _CLIENT_BLOCK if you want the +////allocations to be of _CLIENT_BLOCK type +//#else +//#define NEW new +//#endif // _DEBUG + +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // 某些 CString 构造函数将是显式的 + +// 关闭 MFC 对某些常见但经常可放心忽略的警告消息的隐藏 +#define _AFX_ALL_WARNINGS + +#include // MFC 核心组件和标准组件 +#include // MFC 扩展 + + +#include // MFC 自动化类 + + +#ifndef _AFX_NO_OLE_SUPPORT +#include // MFC 对 Internet Explorer 4 公共控件的支持 +#endif +#ifndef _AFX_NO_AFXCMN_SUPPORT +#include // MFC 对 Windows 公共控件的支持 +#endif // _AFX_NO_AFXCMN_SUPPORT + +#include // 功能区和控件条的 MFC 支持 +#include + +#include +//#ifndef _CRTDBG_MAP_ALLOC +//# define _CRTDBG_MAP_ALLOC +//# include +//# include +//#endif + +#endif \ No newline at end of file diff --git a/lib_acl_cpp/samples/winaio/winaio.cpp b/lib_acl_cpp/samples/winaio/winaio.cpp new file mode 100644 index 000000000..a2013b97e --- /dev/null +++ b/lib_acl_cpp/samples/winaio/winaio.cpp @@ -0,0 +1,79 @@ +// winaio.cpp : 定义应用程序的类行为。 +// + +#include "stdafx.h" +#include "winaio.h" +#include "winaioDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#endif + + +// CwinaioApp + +BEGIN_MESSAGE_MAP(CwinaioApp, CWinApp) + ON_COMMAND(ID_HELP, CWinApp::OnHelp) +END_MESSAGE_MAP() + + +// CwinaioApp 构造 + +CwinaioApp::CwinaioApp() +{ + // TODO: 在此处添加构造代码, + // 将所有重要的初始化放置在 InitInstance 中 +} + + +// 唯一的一个 CwinaioApp 对象 + +CwinaioApp theApp; + + +// CwinaioApp 初始化 + +BOOL CwinaioApp::InitInstance() +{ + // 如果一个运行在 Windows XP 上的应用程序清单指定要 + // 使用 ComCtl32.dll 版本 6 或更高版本来启用可视化方式, + //则需要 InitCommonControls()。否则,将无法创建窗口。 + InitCommonControls(); + + CWinApp::InitInstance(); + + if (!AfxSocketInit()) + { + AfxMessageBox(IDP_SOCKETS_INIT_FAILED); + return FALSE; + } + + AfxEnableControlContainer(); + + // 标准初始化 + // 如果未使用这些功能并希望减小 + // 最终可执行文件的大小,则应移除下列 + // 不需要的特定初始化例程 + // 更改用于存储设置的注册表项 + // TODO: 应适当修改该字符串, + // 例如修改为公司或组织名 + SetRegistryKey(_T("应用程序向导生成的本地应用程序")); + + CwinaioDlg dlg; + m_pMainWnd = &dlg; + INT_PTR nResponse = dlg.DoModal(); + if (nResponse == IDOK) + { + // TODO: 在此放置处理何时用“确定”来关闭 + //对话框的代码 + } + else if (nResponse == IDCANCEL) + { + // TODO: 在此放置处理何时用“取消”来关闭 + //对话框的代码 + } + + // 由于对话框已关闭,所以将返回 FALSE 以便退出应用程序, + // 而不是启动应用程序的消息泵。 + return FALSE; +} diff --git a/lib_acl_cpp/samples/winaio/winaio.h b/lib_acl_cpp/samples/winaio/winaio.h new file mode 100644 index 000000000..d5592d4e4 --- /dev/null +++ b/lib_acl_cpp/samples/winaio/winaio.h @@ -0,0 +1,31 @@ +// winaio.h : PROJECT_NAME 应用程序的主头文件 +// + +#pragma once + +#ifndef __AFXWIN_H__ + #error 在包含用于 PCH 的此文件之前包含“stdafx.h” +#endif + +#include "resource.h" // 主符号 + + +// CwinaioApp: +// 有关此类的实现,请参阅 winaio.cpp +// + +class CwinaioApp : public CWinApp +{ +public: + CwinaioApp(); + +// 重写 + public: + virtual BOOL InitInstance(); + +// 实现 + + DECLARE_MESSAGE_MAP() +}; + +extern CwinaioApp theApp; diff --git a/lib_acl_cpp/samples/winaio/winaio.rc b/lib_acl_cpp/samples/winaio/winaio.rc new file mode 100644 index 000000000..a72a9faa8 --- /dev/null +++ b/lib_acl_cpp/samples/winaio/winaio.rc @@ -0,0 +1,205 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// 中文(中华人民共和国) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) +#ifdef _WIN32 +LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED +#pragma code_page(936) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "#define _AFX_NO_SPLITTER_RESOURCES\r\n" + "#define _AFX_NO_OLE_RESOURCES\r\n" + "#define _AFX_NO_TRACKER_RESOURCES\r\n" + "#define _AFX_NO_PROPERTY_RESOURCES\r\n" + "\r\n" + "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)\r\n" + "LANGUAGE 4, 2\r\n" + "#pragma code_page(936)\r\n" + "#include ""res\\winaio.rc2"" // 非 Microsoft Visual C++ 编辑过的资源\r\n" + "#include ""afxres.rc"" // 标准组件\r\n" + "#endif\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDR_MAINFRAME ICON "res\\winaio.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_ABOUTBOX DIALOGEX 0, 0, 235, 55 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | + WS_SYSMENU +CAPTION "关于 winaio" +FONT 9, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + ICON IDR_MAINFRAME,IDC_STATIC,11,17,20,20 + LTEXT "winaio Version 1.0",IDC_STATIC,40,10,119,8,SS_NOPREFIX + LTEXT "Copyright (C) 2011",IDC_STATIC,40,25,119,8 + DEFPUSHBUTTON "确定",IDOK,178,7,50,16,WS_GROUP +END + +IDD_WINAIO_DIALOG DIALOGEX 0, 0, 320, 200 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | + WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_APPWINDOW +CAPTION "winaio" +FONT 9, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + DEFPUSHBUTTON "退出",IDOK,263,7,50,16 + PUSHBUTTON "监听",IDC_LISTEN,53,30,50,14 + PUSHBUTTON "连接",IDC_CONNECT,53,52,50,14 + PUSHBUTTON "设置定时器",IDC_SET_TIMER,53,80,50,14 + PUSHBUTTON "取消定时器",IDC_DEL_TIMER,53,104,50,14 + PUSHBUTTON "定时器保持",IDC_BUTTON_KEEP_TIMER,53,127,50,14 + PUSHBUTTON "取消定时器保持",IDC_BUTTON_NO_KEEP_TIMER,53,150,50,14 + PUSHBUTTON "内存测试",IDC_BUTTON_MEMTEST,126,30,50,14 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "080403a8" + BEGIN + VALUE "CompanyName", "TODO: <公司名>" + VALUE "FileDescription", "TODO: <文件说明>" + VALUE "FileVersion", "1.0.0.1" + VALUE "InternalName", "winaio.exe" + VALUE "LegalCopyright", "TODO: (C) <公司名>。保留所有权利。" + VALUE "OriginalFilename", "winaio.exe" + VALUE "ProductName", "TODO: <产品名>" + VALUE "ProductVersion", "1.0.0.1" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "翻译", 0x804, 936 + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_ABOUTBOX, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 228 + TOPMARGIN, 7 + BOTTOMMARGIN, 48 + END + + IDD_WINAIO_DIALOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 313 + TOPMARGIN, 7 + BOTTOMMARGIN, 193 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + IDS_ABOUTBOX "关于 winaio(&A)..." + IDP_SOCKETS_INIT_FAILED "Windows 套接字初始化失败。" +END + +#endif // 中文(中华人民共和国) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +#define _AFX_NO_SPLITTER_RESOURCES +#define _AFX_NO_OLE_RESOURCES +#define _AFX_NO_TRACKER_RESOURCES +#define _AFX_NO_PROPERTY_RESOURCES + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) +LANGUAGE 4, 2 +#pragma code_page(936) +#include "res\winaio.rc2" // 非 Microsoft Visual C++ 编辑过的资源 +#include "afxres.rc" // 标准组件 +#endif + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/lib_acl_cpp/samples/winaio/winaio.vcproj b/lib_acl_cpp/samples/winaio/winaio.vcproj new file mode 100644 index 000000000..edfebda94 --- /dev/null +++ b/lib_acl_cpp/samples/winaio/winaio.vcproj @@ -0,0 +1,378 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_acl_cpp/samples/winaio/winaio.vcxproj b/lib_acl_cpp/samples/winaio/winaio.vcxproj new file mode 100644 index 000000000..72fb586a2 --- /dev/null +++ b/lib_acl_cpp/samples/winaio/winaio.vcxproj @@ -0,0 +1,269 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + Releasedll + Win32 + + + Release + Win32 + + + Template + Win32 + + + + {ADE6F714-BD52-432D-AB86-62FA59AB6746} + MFCProj + + + + Application + Dynamic + MultiByte + + + Application + Dynamic + MultiByte + + + Application + Dynamic + MultiByte + + + Application + Static + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + true + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_WINDOWS;_DEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + true + Use + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;lib_acl_d.lib;lib_acl_cpp_d.lib;%(AdditionalDependencies) + ..\..\..\lib\win32;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + %(IgnoreSpecificDefaultLibraries) + true + Windows + MachineX86 + + + _DEBUG;%(PreprocessorDefinitions) + false + + + _DEBUG;%(PreprocessorDefinitions) + 0x0804 + $(IntDir);%(AdditionalIncludeDirectories) + + + + + + + + + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_WINDOWS;NDEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + false + MultiThreadedDLL + true + Use + Level3 + ProgramDatabase + + + ws2_32.lib;lib_acl_cpp.lib;lib_acl.lib;%(AdditionalDependencies) + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + libcmt;%(IgnoreSpecificDefaultLibraries) + true + Windows + true + true + MachineX86 + + + NDEBUG;%(PreprocessorDefinitions) + false + + + NDEBUG;%(PreprocessorDefinitions) + 0x0804 + $(IntDir);%(AdditionalIncludeDirectories) + + + + + Disabled + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_WINDOWS;_DEBUG;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + true + Use + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;lib_acl_d.lib;lib_acl_cpp_d.lib;%(AdditionalDependencies) + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + libcmtd;%(IgnoreSpecificDefaultLibraries) + true + Windows + MachineX86 + + + _DEBUG;%(PreprocessorDefinitions) + false + + + _DEBUG;%(PreprocessorDefinitions) + 0x0804 + $(IntDir);%(AdditionalIncludeDirectories) + + + + + Disabled + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDLL + true + Use + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;lib_acl.lib;lib_acl_cpp.lib;%(AdditionalDependencies) + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + libcmtd;%(IgnoreSpecificDefaultLibraries) + true + Windows + MachineX86 + + + _DEBUG;%(PreprocessorDefinitions) + false + + + _DEBUG;%(PreprocessorDefinitions) + 0x0804 + $(IntDir);%(AdditionalIncludeDirectories) + + + + + + + + + + + + Create + Create + Create + Create + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib_acl_cpp/samples/winaio/winaioDlg.cpp b/lib_acl_cpp/samples/winaio/winaioDlg.cpp new file mode 100644 index 000000000..4c7957cec --- /dev/null +++ b/lib_acl_cpp/samples/winaio/winaioDlg.cpp @@ -0,0 +1,332 @@ +// winaioDlg.cpp : 实现文件 +// + +#include "stdafx.h" +#include "lib_acl.h" +#include +#include "acl_cpp/stream/aio_handle.hpp" +#include "acl_cpp/stream/aio_stream.hpp" +#include "AioServer.h" +#include "AioClient.h" +#include "AioTimer.hpp" +#include "winaio.h" +//#include "vld.h" +//#include "heap_hook.h" +#include "winaioDlg.h" +#include ".\winaiodlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#endif + +#ifdef WIN32 +# ifndef snprintf +# define snprintf _snprintf +# endif +#endif + +//CHeapHook2 vld2; + +using namespace acl; + +// 用于应用程序“关于”菜单项的 CAboutDlg 对话框 + +class CAboutDlg : public CDialog +{ +public: + CAboutDlg(); + +// 对话框数据 + enum { IDD = IDD_ABOUTBOX }; + + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 + +// 实现 +protected: + DECLARE_MESSAGE_MAP() +}; + +CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) +{ +} + +void CAboutDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); +} + +BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) +END_MESSAGE_MAP() + + +// CwinaioDlg 对话框 + + + +CwinaioDlg::CwinaioDlg(CWnd* pParent /*=NULL*/) + : CDialog(CwinaioDlg::IDD, pParent) + , sstream_(NULL) + , handle_(NULL) + , keep_timer_(false) +{ + m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); +} + +CwinaioDlg::~CwinaioDlg() +{ + std::list::iterator it = timers_.begin(), it_next; + for (it_next = it; it != timers_.end(); it = it_next) + { + it_next++; + handle_->del_timer(*it); + timers_.erase(it); + } + if (handle_) + delete handle_; +} + +void CwinaioDlg::InitCtx() +{ + memset(&client_ctx_, 0, sizeof(client_ctx_)); + client_ctx_.connect_timeout = 5; + client_ctx_.nopen_limit = 10; + client_ctx_.id_begin = 1; + client_ctx_.nwrite_limit = 10; + client_ctx_.debug = false; + snprintf(client_ctx_.addr, sizeof(client_ctx_.addr), "127.0.0.1:9001"); + client_ctx_.handle = handle_; +} + +void CwinaioDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); +} + +BEGIN_MESSAGE_MAP(CwinaioDlg, CDialog) + ON_WM_SYSCOMMAND() + ON_WM_PAINT() + ON_WM_QUERYDRAGICON() + //}}AFX_MSG_MAP + ON_BN_CLICKED(IDC_LISTEN, OnBnClickedListen) + ON_BN_CLICKED(IDC_CONNECT, OnBnClickedConnect) + ON_BN_CLICKED(IDC_SET_TIMER, OnBnClickedSetTimer) + ON_BN_CLICKED(IDC_DEL_TIMER, OnBnClickedDelTimer) + ON_BN_CLICKED(IDOK, OnBnClickedOk) + ON_BN_CLICKED(IDC_BUTTON_KEEP_TIMER, OnBnClickedButtonKeepTimer) + ON_BN_CLICKED(IDC_BUTTON_NO_KEEP_TIMER, OnBnClickedButtonNoKeepTimer) + ON_BN_CLICKED(IDC_BUTTON_MEMTEST, OnBnClickedButtonMemtest) +END_MESSAGE_MAP() + + +// CwinaioDlg 消息处理程序 + +BOOL CwinaioDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + // 将\“关于...\”菜单项添加到系统菜单中。 + + // IDM_ABOUTBOX 必须在系统命令范围内。 + ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); + ASSERT(IDM_ABOUTBOX < 0xF000); + + CMenu* pSysMenu = GetSystemMenu(FALSE); + if (pSysMenu != NULL) + { + CString strAboutMenu; + strAboutMenu.LoadString(IDS_ABOUTBOX); + if (!strAboutMenu.IsEmpty()) + { + pSysMenu->AppendMenu(MF_SEPARATOR); + pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); + } + } + + // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动 + // 执行此操作 + SetIcon(m_hIcon, TRUE); // 设置大图标 + SetIcon(m_hIcon, FALSE); // 设置小图标 + + // TODO: 在此添加额外的初始化代码 + GetDlgItem(IDC_SET_TIMER)->EnableWindow(TRUE); + GetDlgItem(IDC_DEL_TIMER)->EnableWindow(FALSE); + + GetDlgItem(IDC_BUTTON_KEEP_TIMER)->EnableWindow(TRUE); + GetDlgItem(IDC_BUTTON_NO_KEEP_TIMER)->EnableWindow(FALSE); + + FILE *fp; + AllocConsole(); + fp = freopen("CONOUT$","w+t",stdout); + + handle_ = new acl::aio_handle(ENGINE_WINMSG); + InitCtx(); + + return TRUE; // 除非设置了控件的焦点,否则返回 TRUE +} + +void CwinaioDlg::OnSysCommand(UINT nID, LPARAM lParam) +{ + if ((nID & 0xFFF0) == IDM_ABOUTBOX) + { + CAboutDlg dlgAbout; + dlgAbout.DoModal(); + } + else + { + CDialog::OnSysCommand(nID, lParam); + } +} + +// 如果向对话框添加最小化按钮,则需要下面的代码 +// 来绘制该图标。对于使用文档/视图模型的 MFC 应用程序, +// 这将由框架自动完成。 + +void CwinaioDlg::OnPaint() +{ + if (IsIconic()) + { + CPaintDC dc(this); // 用于绘制的设备上下文 + + SendMessage(WM_ICONERASEBKGND, reinterpret_cast(dc.GetSafeHdc()), 0); + + // 使图标在工作矩形中居中 + int cxIcon = GetSystemMetrics(SM_CXICON); + int cyIcon = GetSystemMetrics(SM_CYICON); + CRect rect; + GetClientRect(&rect); + int x = (rect.Width() - cxIcon + 1) / 2; + int y = (rect.Height() - cyIcon + 1) / 2; + + // 绘制图标 + dc.DrawIcon(x, y, m_hIcon); + } + else + { + CDialog::OnPaint(); + } +} + +//当用户拖动最小化窗口时系统调用此函数取得光标显示。 +HCURSOR CwinaioDlg::OnQueryDragIcon() +{ + return static_cast(m_hIcon); +} + +void CwinaioDlg::OnBnClickedListen() +{ + // TODO: 在此添加控件通知处理程序代码 + + sstream_ = new aio_listen_stream(handle_); + const char* addr = "127.0.0.1:9001"; + // 监听指定的地址 + if (sstream_->open(addr) == false) + { + std::cout << "open " << addr << " error!" << std::endl; + sstream_->close(); // 释放监听流所占资源 + handle_->check(); // 清空所有异步流所占资源 + acl_pthread_end(); // 清除所有线程所占资源 + return; + } + GetDlgItem(IDC_LISTEN)->EnableWindow(FALSE); + // 创建回调类对象,当有新连接到达时自动调用此类对象的回调过程 + sstream_->add_accept_callback(&callback_); + std::cout << "Listen: " << addr << " ok!" << std::endl; +} + +void CwinaioDlg::OnBnClickedConnect() +{ + // TODO: 在此添加控件通知处理程序代码 + if (CConnectClientCallback::connect_server(&client_ctx_, + client_ctx_.id_begin) == false) + { + std::cout << "connect " << client_ctx_.addr << " error!" << std::endl; + } + else + GetDlgItem(IDC_CONNECT)->EnableWindow(FALSE); +} + +void CwinaioDlg::OnBnClickedSetTimer() +{ + // TODO: 在此添加控件通知处理程序代码 + + GetDlgItem(IDC_SET_TIMER)->EnableWindow(FALSE); + GetDlgItem(IDC_DEL_TIMER)->EnableWindow(TRUE); + __int64 inter = 1000000; + for (int i = 0; i < 10; i++) + { + CAioTimer* timer = new CAioTimer(handle_, i, keep_timer_); + handle_->set_timer(timer, (i + 1) * inter, 1); + if (timer->keep_timer()) + timers_.push_back(timer); + } +} + +void CwinaioDlg::OnBnClickedDelTimer() +{ + // TODO: 在此添加控件通知处理程序代码 + GetDlgItem(IDC_SET_TIMER)->EnableWindow(TRUE); + GetDlgItem(IDC_DEL_TIMER)->EnableWindow(FALSE); + + std::list::iterator it = timers_.begin(), it_next; + for (it_next = it; it != timers_.end(); it = it_next) + { + it_next++; + handle_->del_timer(*it); + timers_.erase(it); + } +} + +void CwinaioDlg::OnBnClickedOk() +{ + // TODO: 在此添加控件通知处理程序代码 + if (sstream_) + { + sstream_->close(); // 释放监听流资源 + handle_->check(); // 最后清空一下所有异步流所占的资源 + } + acl_pthread_end(); // 清除所有线程所占资源 + + OnOK(); +} + +void CwinaioDlg::on_increase() +{ + +} + +void CwinaioDlg::on_decrease() +{ + /* 获得异步引擎中受监控的异步流个数 */ + int nleft = handle_->length(); + if (client_ctx_.nopen_total == client_ctx_.nopen_limit && nleft == 1) + { + std::cout << "All client streams over! just one listen stream: " + << std::endl; + + InitCtx(); + GetDlgItem(IDC_CONNECT)->EnableWindow(TRUE); + } +} +void CwinaioDlg::OnBnClickedButtonKeepTimer() +{ + // TODO: 在此添加控件通知处理程序代码 + keep_timer_ = true; + GetDlgItem(IDC_BUTTON_KEEP_TIMER)->EnableWindow(FALSE); + GetDlgItem(IDC_BUTTON_NO_KEEP_TIMER)->EnableWindow(TRUE); +} + +void CwinaioDlg::OnBnClickedButtonNoKeepTimer() +{ + // TODO: 在此添加控件通知处理程序代码 + keep_timer_ = false; + GetDlgItem(IDC_BUTTON_KEEP_TIMER)->EnableWindow(TRUE); + GetDlgItem(IDC_BUTTON_NO_KEEP_TIMER)->EnableWindow(FALSE); +} + +void CwinaioDlg::OnBnClickedButtonMemtest() +{ + // TODO: 在此添加控件通知处理程序代码 + CMemory* m = new CMemory; + delete m; +} diff --git a/lib_acl_cpp/samples/winaio/winaioDlg.h b/lib_acl_cpp/samples/winaio/winaioDlg.h new file mode 100644 index 000000000..e093939b6 --- /dev/null +++ b/lib_acl_cpp/samples/winaio/winaioDlg.h @@ -0,0 +1,63 @@ +// winaioDlg.h : 头文件 +// + +#pragma once +#include +#include "resource.h" +#include "AioServer.h" +#include "AioClient.h" + +class CAioTimer; +class acl::aio_handle; +class acl::aio_listen_stream; + +// CwinaioDlg 对话框 +class CwinaioDlg : public CDialog +{ +// 构造 +public: + CwinaioDlg(CWnd* pParent = NULL); // 标准构造函数 + ~CwinaioDlg(); + +// 对话框数据 + enum { IDD = IDD_WINAIO_DIALOG }; + + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 + + +// 实现 +protected: + HICON m_hIcon; + + // 生成的消息映射函数 + virtual BOOL OnInitDialog(); + afx_msg void OnSysCommand(UINT nID, LPARAM lParam); + afx_msg void OnPaint(); + afx_msg HCURSOR OnQueryDragIcon(); + DECLARE_MESSAGE_MAP() +public: + afx_msg void OnBnClickedListen(); + afx_msg void OnBnClickedConnect(); + afx_msg void OnBnClickedSetTimer(); + afx_msg void OnBnClickedDelTimer(); +protected: + // acl::aio_handle 类虚函数 + void on_increase(); + void on_decrease(); +private: + CServerCallback callback_; + acl::aio_handle* handle_; + acl::aio_listen_stream* sstream_; + bool keep_timer_; + IO_CTX client_ctx_; + void InitCtx(); +public: + afx_msg void OnBnClickedOk(); + afx_msg void OnBnClickedButtonKeepTimer(); + afx_msg void OnBnClickedButtonNoKeepTimer(); + afx_msg void OnBnClickedButtonMemtest(); +private: + std::list timers_; +public: +}; diff --git a/lib_acl_cpp/samples/winaio/winaio_vc2012.vcxproj b/lib_acl_cpp/samples/winaio/winaio_vc2012.vcxproj new file mode 100644 index 000000000..89f26452a --- /dev/null +++ b/lib_acl_cpp/samples/winaio/winaio_vc2012.vcxproj @@ -0,0 +1,274 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + Releasedll + Win32 + + + Release + Win32 + + + Template + Win32 + + + + {ADE6F714-BD52-432D-AB86-62FA59AB6746} + MFCProj + winaio + + + + Application + Dynamic + MultiByte + v110 + + + Application + Dynamic + MultiByte + v110 + + + Application + Dynamic + MultiByte + v110 + + + Application + Static + MultiByte + v110 + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + true + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_WINDOWS;_DEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + true + Use + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;lib_acl_d.lib;lib_acl_cpp_d.lib;%(AdditionalDependencies) + ..\..\..\lib\win32;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + %(IgnoreSpecificDefaultLibraries) + true + Windows + MachineX86 + + + _DEBUG;%(PreprocessorDefinitions) + false + + + _DEBUG;%(PreprocessorDefinitions) + 0x0804 + $(IntDir);%(AdditionalIncludeDirectories) + + + + + + + + + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_WINDOWS;NDEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + false + MultiThreadedDLL + true + Use + Level3 + ProgramDatabase + + + ws2_32.lib;lib_acl_cpp.lib;lib_acl.lib;%(AdditionalDependencies) + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + libcmt;%(IgnoreSpecificDefaultLibraries) + true + Windows + true + true + MachineX86 + + + NDEBUG;%(PreprocessorDefinitions) + false + + + NDEBUG;%(PreprocessorDefinitions) + 0x0804 + $(IntDir);%(AdditionalIncludeDirectories) + + + + + Disabled + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_WINDOWS;_DEBUG;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + true + Use + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;lib_acl_d.lib;lib_acl_cpp_d.lib;%(AdditionalDependencies) + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + libcmtd;%(IgnoreSpecificDefaultLibraries) + true + Windows + MachineX86 + + + _DEBUG;%(PreprocessorDefinitions) + false + + + _DEBUG;%(PreprocessorDefinitions) + 0x0804 + $(IntDir);%(AdditionalIncludeDirectories) + + + + + Disabled + ..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDLL + true + Use + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;lib_acl.lib;lib_acl_cpp.lib;%(AdditionalDependencies) + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + libcmtd;%(IgnoreSpecificDefaultLibraries) + true + Windows + MachineX86 + + + _DEBUG;%(PreprocessorDefinitions) + false + + + _DEBUG;%(PreprocessorDefinitions) + 0x0804 + $(IntDir);%(AdditionalIncludeDirectories) + + + + + + + + + + + + Create + Create + Create + Create + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib_acl_cpp/samples/xml/Makefile b/lib_acl_cpp/samples/xml/Makefile new file mode 100644 index 000000000..718a8fcd2 --- /dev/null +++ b/lib_acl_cpp/samples/xml/Makefile @@ -0,0 +1,2 @@ +PROG = xml +include ../Makefile.in diff --git a/lib_acl_cpp/samples/xml/ReadMe.txt b/lib_acl_cpp/samples/xml/ReadMe.txt new file mode 100644 index 000000000..014dcb093 --- /dev/null +++ b/lib_acl_cpp/samples/xml/ReadMe.txt @@ -0,0 +1,31 @@ +======================================================================== + 控制台应用程序 : xml 项目概况 +======================================================================== + +应用程序向导已为您创建了这个 xml 应用程序。 +此文件包含组成 xml 应用程序 +的每个文件的内容摘要。 + + +xml.vcproj + 这是用应用程序向导生成的 VC++ 项目的主项目文件。 + 它包含有关生成此文件的 Visual C++ 版本的信息,以及 + 有关用应用程序向导选择的 + 平台、配置和项目功能的信息。 + +xml.cpp + 这是主应用程序源文件。 + +///////////////////////////////////////////////////////////////////////////// +其他标准文件: + +StdAfx.h、StdAfx.cpp + 这些文件用于生成名为 xml.pch + 的预编译头(PCH)文件以及名为 StdAfx.obj 的预编译类型文件。 + +///////////////////////////////////////////////////////////////////////////// +其他注释: + +应用程序向导使用 "TODO:" 注释指示应添加或自定义的源代码部分。 + +///////////////////////////////////////////////////////////////////////////// diff --git a/lib_acl_cpp/samples/xml/stdafx.cpp b/lib_acl_cpp/samples/xml/stdafx.cpp new file mode 100644 index 000000000..b3b687825 --- /dev/null +++ b/lib_acl_cpp/samples/xml/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// xml.pch 将成为预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + +// TODO: 在 STDAFX.H 中 +//引用任何所需的附加头文件,而不是在此文件中引用 diff --git a/lib_acl_cpp/samples/xml/stdafx.h b/lib_acl_cpp/samples/xml/stdafx.h new file mode 100644 index 000000000..4bf167925 --- /dev/null +++ b/lib_acl_cpp/samples/xml/stdafx.h @@ -0,0 +1,12 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是常用但不常更改的项目特定的包含文件 +// + +#pragma once + +// +//#include +//#include + +// TODO: 在此处引用程序要求的附加头文件 +#include "acl_cpp/lib_acl.hpp" diff --git a/lib_acl_cpp/samples/xml/valgrind.sh b/lib_acl_cpp/samples/xml/valgrind.sh new file mode 100644 index 000000000..3a9d3bb09 --- /dev/null +++ b/lib_acl_cpp/samples/xml/valgrind.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +valgrind --tool=memcheck --leak-check=yes -v ./xml diff --git a/lib_acl_cpp/samples/xml/xml.cpp b/lib_acl_cpp/samples/xml/xml.cpp new file mode 100644 index 000000000..5a97decac --- /dev/null +++ b/lib_acl_cpp/samples/xml/xml.cpp @@ -0,0 +1,240 @@ +// xml.cpp : 定义控制台应用程序的入口点。 +// +#include "stdafx.h" +#include + +using namespace std; + +static void test(void) +{ + const char *data = + "\r\n" + "\r\n" + "xmllint
\">\r\n" + "]>\r\n" + "test\r\n" + " - -->\r\n" + " zsx\r\n" + " 38\r\n" + " \r\n" + "\r\n" + " -->\r\n" + "\r\n" + "\r\n" + "test\r\n"; + acl::xml xml; + +#if 1 + const char* p = data; + char tmp[2]; + while (*p) + { + tmp[0] = *p++; + tmp[1] = 0; + xml.update(tmp); + } +#else + xml.update(data); +#endif + + const vector& elements = xml.getElementsByTagName("user"); + + if (!elements.empty()) { + vector::const_iterator cit = elements.begin(); + for (; cit != elements.end(); cit++) { + acl::xml_node *node = *cit; + printf("tagname: %s, text: %s\n", node->tag_name() ? node->tag_name() : "", + node->text() ? node->text() : ""); + + const acl::xml_attr* attr = (*cit)->first_attr(); + while (attr) + { + printf("test1: %s=%s\r\n", attr->get_name(), attr->get_value()); + attr = (*cit)->next_attr(); + } + } + } + + xml.reset(); + + ////////////////////////////////////////////////////////////////////// + + const char* s2 = "Title\r\n各位同学:\r\n" + "本月考勤统计日为20日,烦请各位同学在19日下班之前尽快将个人需要申诉的事由找部门领导审批通\r\n" + "过。逾期不再修改考勤。\r\n" + "另烦请本月有请年假、事假、病假的同学补发邮件给部门领导审批并转发给行政部。谢谢各位同学配合。\r\n" + "如在考勤日未收到以上邮件,我部门将按照考勤严格执行不再做任何修改。\r\n"; + xml.update(""); + xml.update(s2); + xml.update(""); + const acl::string& r2 = xml.getText(); + printf("\r\n|%s|\r\n", r2.c_str()); + + printf("------------ the result is: ------------------\r\n"); + acl::string buf; + xml.build_xml(buf); + printf("%s\r\n", buf.c_str()); + + ////////////////////////////////////////////////////////////////////////// + acl::xml xml2; + acl::xml_node& root = xml2.get_root(); + acl::xml_node* node1, *node2, *node3, *node4; + + node1 = &xml2.create_node("test1"); + (*node1).add_attr("name1_1", "value1_1") + .add_attr("name1_2", "value1_2") + .add_attr("name1_3", "value1_3"); + root.add_child(node1); + + printf("----------------------node1's attr valuse list----------------\r\n"); + const acl::xml_attr* attr1 = node1->first_attr(); + while (attr1) + { + printf("node1: %s=%s\r\n", attr1->get_name(), attr1->get_value()); + attr1 = node1->next_attr(); + } + printf("----------------------node1's attr end list------------------\r\n"); + + node2 = &xml2.create_node("test2"); + (*node2).add_attr("name2_1", "value2_1") + .add_attr("name2_2", "value2_2"); + root.add_child(node2); + + node2 = &xml2.create_node("test11"); + (*node2).add_attr("name11_1", "value11_1") + .add_attr("name11_2", "value11_2") + .add_attr("name11_3", "value11_3"); + node1->add_child(node2); + node2->set_text("hello world!"); + + node1 = &xml2.create_node("test3"); + (*node1).add_attr("name3_1", "value3_1") + .add_attr("name3_2", "value3_2"); + node2 = &xml2.create_node("test4"); + (*node2).add_attr("name4_1", "value4_1") + .add_attr("name4_2", "value4_2") + .add_attr("name4_3", "value4_3"); + root.add_child(node1).add_child(node2); + + node1 = &xml2.create_node("test5"); + root.add_child(node1); + node2 = &xml2.create_node("test51"); + (*node2).add_attr("name51_1", "value51_1") + .add_attr("name51_2", "value51_2"); + (*node1).add_child(node2); + + node3 = &xml2.create_node("test52"); + (*node3).add_attr("name52_1", "value52_1") + .add_attr("name52_2", "value52_2"); + node4 = &xml2.create_node("test53"); + (*node4).add_attr("name53_1", "value53\"_1") + .add_attr("name53_2", "value53_2"); + (*node1).add_child(node3).add_child(node4); + + root.add_child("test6", true, "text6") + .add_child("test61", true, "text61") + .add_attr("name61_1", "value61_1") + .add_attr("name61_2", "value61_2") + .add_attr("name61_3", "value61_3") + .add_child("test611", true, "text611") + .add_attr("name611_1", "value611_1") + .add_attr("name611_2", "value611_2") + .add_attr("name611_3", "value611_3") + .get_parent() + .get_parent() + .add_child("test62", true, "text62") + .add_attr("name62_1", "value62_1") + .add_attr("name62_2", "value62_2") + .add_attr("name62_3", "value62_3") + .get_parent() + .add_attr("name6_1", "value6_1") + .add_attr("name6_2", "value6_2") + .add_attr("name6_3", "value6_3"); + + buf.clear(); + xml2.build_xml(buf); + + printf("-----------------xml2------------------------\r\n"); + printf("%s\r\n", buf.c_str()); + + printf("-----------------xml2 iterator --------------\r\n"); + acl::xml_node* iter = xml2.first_node(); + while (iter) + { + if (iter->tag_name()) + { + printf("tag: %s", iter->tag_name()); + if (iter->text()) + printf(", text: %s\r\n", iter->text()); + else + printf("\r\n"); + } + iter = xml2.next_node(); + } + + printf("------------------root first level child---------\r\n"); + iter = xml2.get_root().first_child(); + int n = 0; + while (iter) + { + n++; + if (iter->tag_name()) + printf("tag: %s", iter->tag_name()); + if (iter->text()) + printf(", text: %s\r\n", iter->text()); + else + printf("\r\n"); + iter = xml2.get_root().next_child(); + } + if (n == xml2.get_root().children_count()) + printf("ok, children_count: %d\n", n); + else + { + printf("error, n: %d, children_count: %d, enter any key to continue\r\n", + n, xml2.get_root().children_count()); + getchar(); + } +} + +static void test2(void) +{ + acl::xml body; + body.get_root().add_child("test", true) + .add_attr("mail", "\"zsxxsz1\" zsxxsz1@test.com") + .add_attr("title", "中<国>人\',
中国人\",中国人\\\"") + .add_attr("from", "\"zsxxsz2\" zsxxsz2@test.com"); + acl::string buf; + body.build_xml(buf); + printf("data: %s\r\n", buf.c_str()); + + printf("------------------------------------------\r\n"); + + acl::xml xml(buf.c_str()); + const acl::xml_node* node = xml.getFirstElementByTag("test"); + if (node == NULL) + printf("test tag null\r\n"); + else + { + const char* mail = (*node)["mail"]; + const char* title = (*node)["title"]; + const char* from = (*node)["from"]; + printf("mail: %s\r\n", mail ? mail : "null"); + printf("title: %s\r\n", title ? title : "null"); + printf("from: %s\r\n", from ? from : "null"); + } +} + +int main(int argc, char* argv[]) +{ + (void) argc; + (void) argv; + test2(); getchar(); return 0; + + test(); + printf("enter any key to exit\r\n"); + getchar(); + return 0; +} diff --git a/lib_acl_cpp/samples/xml/xml.vcproj b/lib_acl_cpp/samples/xml/xml.vcproj new file mode 100644 index 000000000..128020572 --- /dev/null +++ b/lib_acl_cpp/samples/xml/xml.vcproj @@ -0,0 +1,273 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_acl_cpp/samples/xml/xml.vcxproj b/lib_acl_cpp/samples/xml/xml.vcxproj new file mode 100644 index 000000000..306ed7f8c --- /dev/null +++ b/lib_acl_cpp/samples/xml/xml.vcxproj @@ -0,0 +1,197 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + Releasedll + Win32 + + + Release + Win32 + + + + {2DABFAD1-114B-4F96-9185-DC0C56A3662D} + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + true + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Use + Level3 + ProgramDatabase + + + lib_acl_vc2010d.lib;lib_acl_cpp_vc2010d.lib;%(AdditionalDependencies) + $(OutDir)xml.exe + ..\..\..\lib\win32;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)xml.pdb + Console + MachineX86 + + + + + + + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + Use + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;lib_acl_vc2010.lib;lib_acl_cpp_vc2010.lib;%(AdditionalDependencies) + $(OutDir)xml.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Use + Level3 + ProgramDatabase + + + lib_acl_d.lib;lib_acl_cpp_d.lib;ws2_32.lib;%(AdditionalDependencies) + $(OutDir)xml.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)xml.pdb + Console + MachineX86 + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDLL + Use + Level3 + ProgramDatabase + + + lib_acl.lib;lib_acl_cpp.lib;ws2_32.lib;%(AdditionalDependencies) + $(OutDir)xml.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)xml.pdb + Console + MachineX86 + + + + + + + + + Create + Create + Create + Create + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib_acl_cpp/samples/xml/xml_vc2012.vcxproj b/lib_acl_cpp/samples/xml/xml_vc2012.vcxproj new file mode 100644 index 000000000..5df64209a --- /dev/null +++ b/lib_acl_cpp/samples/xml/xml_vc2012.vcxproj @@ -0,0 +1,202 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + Releasedll + Win32 + + + Release + Win32 + + + + {2DABFAD1-114B-4F96-9185-DC0C56A3662D} + Win32Proj + xml + + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + true + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Use + Level3 + ProgramDatabase + + + lib_acl_vc2012d.lib;lib_acl_cpp_vc2012d.lib;%(AdditionalDependencies) + $(OutDir)xml.exe + ..\..\..\lib\win32;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)xml.pdb + Console + MachineX86 + + + + + + + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + Use + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;lib_acl_vc2012.lib;lib_acl_cpp_vc2012.lib;%(AdditionalDependencies) + $(OutDir)xml.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + + + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Use + Level3 + ProgramDatabase + + + lib_acl_d.lib;lib_acl_cpp_d.lib;ws2_32.lib;%(AdditionalDependencies) + $(OutDir)xml.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)xml.pdb + Console + MachineX86 + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_CPP_DLL;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDLL + Use + Level3 + ProgramDatabase + + + lib_acl.lib;lib_acl_cpp.lib;ws2_32.lib;%(AdditionalDependencies) + $(OutDir)xml.exe + ..\..\lib;..\..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + true + $(OutDir)xml.pdb + Console + MachineX86 + + + + + + + + + Create + Create + Create + Create + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib_acl_cpp/samples/zlib/Makefile b/lib_acl_cpp/samples/zlib/Makefile new file mode 100644 index 000000000..6a9fdfec9 --- /dev/null +++ b/lib_acl_cpp/samples/zlib/Makefile @@ -0,0 +1,3 @@ +include ../Makefile.in +PROG = zlib +EXTLIBS += -lz diff --git a/lib_acl_cpp/samples/zlib/in.txt b/lib_acl_cpp/samples/zlib/in.txt new file mode 100644 index 000000000..9641ddb65 --- /dev/null +++ b/lib_acl_cpp/samples/zlib/in.txt @@ -0,0 +1,6 @@ +未来的选择 + +  传统电视存在着时间和频道的限制,而互联网则有无限的选择。而且,越来越多的观众选择用互联网进行点播来替代过去用录像机来预先录制节目的方式,这让用户在选择节目方面有着更多的自由。 + +  许多年来,电视台通过编辑选择等方式来控制用户观看的节目,这是一种类似营销中“推”的方式,但是在互联网时代,我们有大量的内容选择,需要用“拉”的方式通过结合算法和编辑控制量身定制适合您的节目,这正是Google的强项。你观看和分享越多,系统会有更多机会了解你,并将更好的节目推荐给你。对你来说,这就是完美的电视频道。 + diff --git a/lib_acl_cpp/samples/zlib/stdafx.cpp b/lib_acl_cpp/samples/zlib/stdafx.cpp new file mode 100644 index 000000000..c11b1d006 --- /dev/null +++ b/lib_acl_cpp/samples/zlib/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// zlib.pch 将成为预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + +// TODO: 在 STDAFX.H 中 +//引用任何所需的附加头文件,而不是在此文件中引用 diff --git a/lib_acl_cpp/samples/zlib/stdafx.h b/lib_acl_cpp/samples/zlib/stdafx.h new file mode 100644 index 000000000..b98553f2c --- /dev/null +++ b/lib_acl_cpp/samples/zlib/stdafx.h @@ -0,0 +1,11 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是常用但不常更改的项目特定的包含文件 +// + +#pragma once + + +#include +//#include + +// TODO: 在此处引用程序要求的附加头文件 diff --git a/lib_acl_cpp/samples/zlib/utf8_in.txt b/lib_acl_cpp/samples/zlib/utf8_in.txt new file mode 100644 index 000000000..9f0f9027c --- /dev/null +++ b/lib_acl_cpp/samples/zlib/utf8_in.txt @@ -0,0 +1,6 @@ +鏈潵鐨勯夋嫨 + +銆銆浼犵粺鐢佃瀛樺湪鐫鏃堕棿鍜岄閬撶殑闄愬埗锛岃屼簰鑱旂綉鍒欐湁鏃犻檺鐨勯夋嫨銆傝屼笖锛岃秺鏉ヨ秺澶氱殑瑙備紬閫夋嫨鐢ㄤ簰鑱旂綉杩涜鐐规挱鏉ユ浛浠h繃鍘荤敤褰曞儚鏈烘潵棰勫厛褰曞埗鑺傜洰鐨勬柟寮忥紝杩欒鐢ㄦ埛鍦ㄩ夋嫨鑺傜洰鏂归潰鏈夌潃鏇村鐨勮嚜鐢便 + +銆銆璁稿骞存潵锛岀數瑙嗗彴閫氳繃缂栬緫閫夋嫨绛夋柟寮忔潵鎺у埗鐢ㄦ埛瑙傜湅鐨勮妭鐩紝杩欐槸涓绉嶇被浼艰惀閿涓滄帹鈥濈殑鏂瑰紡锛屼絾鏄湪浜掕仈缃戞椂浠o紝鎴戜滑鏈夊ぇ閲忕殑鍐呭閫夋嫨锛岄渶瑕佺敤鈥滄媺鈥濈殑鏂瑰紡閫氳繃缁撳悎绠楁硶鍜岀紪杈戞帶鍒堕噺韬畾鍒堕傚悎鎮ㄧ殑鑺傜洰锛岃繖姝f槸Google鐨勫己椤广備綘瑙傜湅鍜屽垎浜秺澶氾紝绯荤粺浼氭湁鏇村鏈轰細浜嗚В浣狅紝骞跺皢鏇村ソ鐨勮妭鐩帹鑽愮粰浣犮傚浣犳潵璇达紝杩欏氨鏄畬缇庣殑鐢佃棰戦亾銆 + diff --git a/lib_acl_cpp/samples/zlib/valgrind.sh b/lib_acl_cpp/samples/zlib/valgrind.sh new file mode 100644 index 000000000..22ad82ef7 --- /dev/null +++ b/lib_acl_cpp/samples/zlib/valgrind.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +#valgrind --show-reachable=yes --tool=memcheck --leak-check=yes -v ./zlib +valgrind --tool=memcheck --leak-check=yes -v ./zlib diff --git a/lib_acl_cpp/samples/zlib/zlib.cpp b/lib_acl_cpp/samples/zlib/zlib.cpp new file mode 100644 index 000000000..9658921d2 --- /dev/null +++ b/lib_acl_cpp/samples/zlib/zlib.cpp @@ -0,0 +1,283 @@ +// zlib.cpp : 定义控制台应用程序的入口点。 +// + +#include "stdafx.h" +#include "acl_cpp/stdlib/string.hpp" +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/stdlib/pipe_stream.hpp" +#include "acl_cpp/stream/ofstream.hpp" +#include "acl_cpp/stream/ifstream.hpp" +#include "acl_cpp/stdlib/charset_conv.hpp" +#include "acl_cpp/stdlib/malloc.hpp" +#include "acl_cpp/stdlib/zlib_stream.hpp" + +static int test_zip_stream(void) +{ + const char* dummy = "中国人民中国人民中国人民中国人民中国人民\r\n"; + acl::zlib_stream zstream; + acl::string out, out2; + + const char* ptr = dummy; + int n = (int) strlen(ptr); + + bool ret = zstream.zip_begin(acl::zlib_level9); + if (ret == false) + { + printf("zip_begin error\r\n"); + zstream.zip_reset(); + return 1; + } + while (n > 0) + { + ret = zstream.zip_update(ptr, n, &out, acl::zlib_flush_off); + if (ret == false) + { + printf("zip_update error\r\n"); + return 1; + } + ptr++; + n--; + n = 0; + } + ret = zstream.zip_finish(&out); + if (ret == false) + { + printf("zip_finish error\r\n"); + return 1; + } + + printf(">>after zip, src's len: %d, dst's len: %d\r\n", + (int) strlen(dummy), (int) out.length()); + + ptr = out.c_str(); + n = (int) out.length(); + + ret = zstream.unzip_begin(); + if (ret == false) + { + printf("unzip_begin error\r\n"); + return 1; + } + + while (n > 0) + { + ret = zstream.unzip_update(ptr, 1, &out2, acl::zlib_flush_full); + if (ret == false) + { + printf("unzip_update error\r\n"); + return 1; + } + ptr++; + n--; + } + ret = zstream.unzip_finish(&out2); + if (ret == false) + { + printf("unzip_finish error\r\n"); + return 1; + } + + printf("len: %d, out2: %s", (int) out2.length(), out2.c_str()); + return 0; +} + +static int test_compress(void) +{ + printf("-----------------------------------------------\r\n"); + + const char* dummy = "中国人民中国人民中国人民中国人民中国人民\r\n"; + acl::zlib_stream zstream; + acl::string out, out2; + + if (zstream.zlib_compress(dummy, (int) strlen(dummy), + &out, acl::zlib_best_compress) == false) + { + printf("zlib_compress error\r\n"); + return 1; + } + + printf(">>after compress, len: %d\r\n", (int) out.length()); + + if (zstream.zlib_uncompress(out.c_str(), (int) out.length(), &out2) == false) + { + printf("zlib_uncompress error\r\n"); + return 1; + } + + printf(">>len: %d, result: %s\r\n", (int) out2.length(), out2.c_str()); + return 0; +} + +static void test_zlib_pipe(void) +{ + acl::ifstream in; + + if (in.open_read("./in.txt") == false) + { + logger_error("open in.txt error"); + return; + } + + acl::pipe_manager manager; + acl::charset_conv gbToUtf; + acl::zlib_stream zip; + acl::zlib_stream unzip; + acl::charset_conv utfToGb; + acl::ofstream out; + acl::pipe_string ps; + + zip.pipe_zip_begin(); + unzip.pipe_unzip_begin(); + if (1) + { + gbToUtf.update_begin("gb2312", "utf-8"); + utfToGb.update_begin("utf-8", "gb2312"); + } + else + { + gbToUtf.update_begin("gb2312", "big5"); + utfToGb.update_begin("big5", "gb2312"); + } + + if (out.open_write("./out.txt") == false) + { + logger_error("open out.txt file error"); + return; + } + + if (0) + { + // 倒序方式添加,即执行的顺序与添加的顺序相反 + + manager.push_front(&ps); + manager.push_front(&out); + manager.push_front(&utfToGb); + manager.push_front(&unzip); + manager.push_front(&zip); + manager.push_front(&gbToUtf); + } + else + { + // 正序方式添加,即执行的顺序与添加的顺序相同 + + manager.push_back(&gbToUtf); + manager.push_back(&zip); + manager.push_back(&unzip); + manager.push_back(&utfToGb); + manager.push_back(&ps); + manager.push_back(&out); + } + + while (true) + { + char buf[1]; + int ret; + if ((ret = in.read(buf, sizeof(buf), false)) == -1) + break; + + if (manager.update(buf, ret) == false) + { + logger_error("manager update error"); + return; + } + } + + if (manager.update_end() == false) + logger_error("manager update_end error"); + + printf("result >>> %s\r\n", ps.c_str()); + + //while (true) + //{ + // char buf[1]; + // acl::string out_buf; + // int ret; + + // if ((ret = in.read(buf, sizeof(buf), false)) == -1) + // break; + // if (utfToGb.update(buf, ret, &out_buf) == false) + // { + // logger_error("charset update error"); + // break; + // } + + // out.write(out_buf.c_str(), out_buf.length()); + // out_buf.clear(); + //} +} + +static void check(void) +{ + printf("enter any key to exit now\r\n"); + getchar(); +} + +static void test_unzip_file(void) +{ + const char* file = "test.gz"; + acl::string buf; + if (acl::ifstream::load(file, &buf) == false) + return; + const char* ptr = buf.c_str() + 10; + acl::zlib_stream zstream; + if (zstream.unzip_begin(false) == false) + return; + acl::string out; + if (zstream.unzip_update(ptr, (int) buf.length() - 10, &out) == false) + printf("unzip_update error\r\n"); + else if (zstream.unzip_finish(&out) == false) + { + printf(">>%s\r\n", out.c_str()); + acl::ofstream fp; + fp.open_write("result.txt"); + fp.write(out); + printf("unzip_finish error\r\n"); + } + else + printf("unzip_finish ok\r\n"); +} + +static void test_pipe() +{ + acl::pipe_manager manager; + acl::pipe_string ps1, ps2, ps3; + + manager.push_back(&ps1); + manager.push_back(&ps2); + manager.push_back(&ps3); + + for (int i = 0; i < 4096; i++) + manager.update("x", 1); + manager.update("", 1); + manager.update_end(); + printf("result >>%s\r\n", ps3.c_str()); +} + +int main(int argc, char* argv[]) +{ + test_pipe(); + + (void) argc; + (void) argv; + + atexit(check); + + // win32 下,在 DLL 中不得使用内存池功能 +#ifdef USE_SLICE +# ifndef ACL_DLL + acl::acl_slice_init(); +# endif +#endif + + test_unzip_file(); + + int ret1 = 0, ret2 = 0; + + ret1 = test_zip_stream(); + ret2 = test_compress(); + test_zlib_pipe(); + + printf("enter any key to call functions registered by atexit\r\n"); + getchar(); + return (ret1 == 0 && ret2 == 0 ? 0 : 1); +} diff --git a/lib_acl_cpp/samples/zlib/zlib.vcproj b/lib_acl_cpp/samples/zlib/zlib.vcproj new file mode 100644 index 000000000..d567fef4b --- /dev/null +++ b/lib_acl_cpp/samples/zlib/zlib.vcproj @@ -0,0 +1,274 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_acl_cpp/src/acl_cpp_init.cpp b/lib_acl_cpp/src/acl_cpp_init.cpp new file mode 100644 index 000000000..2e101ecbf --- /dev/null +++ b/lib_acl_cpp/src/acl_cpp_init.cpp @@ -0,0 +1,21 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/acl_cpp_init.hpp" + +namespace acl +{ + +void acl_cpp_init(void) +{ + acl_init(); +} + +#ifdef WIN32 +void open_dos(void) +{ + // 打开 DOS 窗口 + AllocConsole(); + FILE* fp = freopen("CONOUT$","w+t",stdout); +} +#endif + +} diff --git a/lib_acl_cpp/src/acl_cpp_test.cpp b/lib_acl_cpp/src/acl_cpp_test.cpp new file mode 100644 index 000000000..1ec3b4caf --- /dev/null +++ b/lib_acl_cpp/src/acl_cpp_test.cpp @@ -0,0 +1,41 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/stdlib/snprintf.hpp" +#include "acl_cpp/acl_cpp_test.hpp" + +namespace acl +{ + +void test_logger(void) +{ + logger("logger ok!"); + logger_warn("logger_warn ok!"); + logger_error("logger_error ok!"); + logger_fatal("logger_fatal ok!"); +} + +void test_snprintf(void) +{ + char buf[10]; + const char* s9 = "xxxxxxxxx"; + const char* s10 = "xxxxxxxxxx"; + const char* s11 = "xxxxxxxxxxx"; + int ret; + + memset(buf, 0, sizeof(buf)); + ret = snprintf(buf, sizeof(buf), "%s", s9); + printf("buf size: %d, string len: %d, ret: %d, buf: %s\r\n", + (int) sizeof(buf), (int) strlen(s9), ret, buf); + + memset(buf, 0, sizeof(buf)); + ret = snprintf(buf, sizeof(buf), "%s", s10); + printf("buf size: %d, string len: %d, ret: %d, buf: %s\r\n", + (int) sizeof(buf), (int) strlen(s10), ret, buf); + + memset(buf, 0, sizeof(buf)); + ret = snprintf(buf, sizeof(buf), "%s", s11); + printf("buf size: %d, string len: %d, ret: %d, buf: %s\r\n", + (int) sizeof(buf), (int) strlen(s11), ret, buf); +} + +} diff --git a/lib_acl_cpp/src/acl_stdafx.cpp b/lib_acl_cpp/src/acl_stdafx.cpp new file mode 100644 index 000000000..8eea316ff --- /dev/null +++ b/lib_acl_cpp/src/acl_stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// lib_acl_wrap_vc2003.pch 将成为预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "acl_stdafx.hpp" + +// TODO: 在 STDAFX.H 中 +//引用任何所需的附加头文件,而不是在此文件中引用 diff --git a/lib_acl_cpp/src/acl_stdafx.hpp b/lib_acl_cpp/src/acl_stdafx.hpp new file mode 100644 index 000000000..e74f6e0e4 --- /dev/null +++ b/lib_acl_cpp/src/acl_stdafx.hpp @@ -0,0 +1,39 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是常用但不常更改的项目特定的包含文件 +// + +#pragma once + +//#define WIN32_LEAN_AND_MEAN // 从 Windows 头中排除极少使用的资料 + +// TODO: 在此处引用程序要求的附加头文件 + +#include "acl_cpp/acl_cpp_define.hpp" + +#include "lib_acl.h" +#include "lib_protocol.h" + +#include "acl_cpp/stdlib/malloc.hpp" + +#ifdef WIN32 +# include "acl_cpp/stdlib/snprintf.hpp" +# ifdef _DEBUG +# ifndef _CRTDBG_MAP_ALLOC +# define _CRTDBG_MAP_ALLOC +# include +# include +# endif +# undef NEW +# define NEW new(_NORMAL_BLOCK, __FILE__, __LINE__) +# else +# undef NEW +# define NEW new +# endif // _DEBUG +#else +# define NEW new +#endif + +// 加入下面一行可以加快在 VC 下的编译速度 +#ifdef WIN32 +#include "acl_cpp/lib_acl.hpp" +#endif diff --git a/lib_acl_cpp/src/beanstalk/beanstalk.cpp b/lib_acl_cpp/src/beanstalk/beanstalk.cpp new file mode 100644 index 000000000..acdbedd78 --- /dev/null +++ b/lib_acl_cpp/src/beanstalk/beanstalk.cpp @@ -0,0 +1,812 @@ +#include "acl_stdafx.hpp" +#include +#include "acl_cpp/stream/socket_stream.hpp" +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/stdlib/util.hpp" +#include "acl_cpp/beanstalk/beanstalk.hpp" + +namespace acl +{ + +#ifdef WIN32 +#define atoll _atoi64 +#endif + + +beanstalk::beanstalk(const char* addr, int conn_timeout, + bool retry /* = true */) +: timeout_(conn_timeout) +, retry_(retry) +{ + addr_ = acl_mystrdup(addr); + acl_lowercase(addr_); + errbuf_[0] = 0; + tube_used_ = NULL; + // 放置缺省队列 + tubes_watched_.push_back(acl_mystrdup("default")); +} + +beanstalk::~beanstalk() +{ + acl_myfree(addr_); + if (tube_used_) + acl_myfree(tube_used_); + std::vector::iterator it = tubes_watched_.begin(); + for (; it != tubes_watched_.end(); ++it) + acl_myfree(*it); + tubes_watched_.clear(); +} + +bool beanstalk::beanstalk_open() +{ + if (conn_.opened()) + return true; + if (conn_.open(addr_, timeout_, 0) == false) + { + logger_error("connect server: %s error: %s", + addr_, last_serror()); + return false; + } + if (tube_used_ && beanstalk_use() == false) + { + logger_error("use %s error: %s", tube_used_, last_serror()); + conn_.close(); + return false; + } + + if (tubes_watched_.empty()) + return true; + + std::vector::iterator it = tubes_watched_.begin(); + for (; it != tubes_watched_.end(); ++it) + { + if (beanstalk_watch(*it) == false) + { + logger_error("watch %s failed", *it); + conn_.close(); + return false; + } + } + + return true; +} + +bool beanstalk::beanstalk_use() +{ + if (tube_used_ == NULL) + return true; + + if (conn_.format("use %s\r\n", tube_used_) == -1) + { + logger_error("use %s error: %s", tube_used_, last_serror()); + conn_.close(); + return false; + } + string line(128); + if (conn_.gets(line) == false || line.empty()) + { + conn_.close(); + logger_error("gets from beanstalkd(%s) error: %s", + addr_, last_serror()); + return false; + } + + ACL_ARGV* tokens = acl_argv_split(line.c_str(), "\t "); + if (tokens->argc < 2 || strcasecmp(tokens->argv[0], "USING") + || strcasecmp(tokens->argv[1], tube_used_)) + { + logger_error("'use %s' error %s", tube_used_, tokens->argv[0]); + ACL_SAFE_STRNCPY(errbuf_, tokens->argv[0], sizeof(errbuf_)); + acl_argv_free(tokens); + close(); + return false; + } + + acl_argv_free(tokens); + return true; +} + +unsigned beanstalk::beanstalk_watch(const char* tube) +{ + if (conn_.format("watch %s\r\n", tube) == -1) + { + logger_error("'watch %s' failed: %s", tube, last_serror()); + return 0; + } + string line(128); + if (conn_.gets(line) == false) + { + logger_error("'watch %s' error(%s): reply ailed", + last_serror(), tube); + return 0; + } + + ACL_ARGV* tokens = acl_argv_split(line.c_str(), "\t "); + if (tokens->argc < 2 || strcasecmp(tokens->argv[0], "WATCHING")) + { + logger_error("'watch %s' error: %s", tube, line.c_str()); + ACL_SAFE_STRNCPY(errbuf_, tokens->argv[0], sizeof(errbuf_)); + acl_argv_free(tokens); + close(); + return 0; + } + + unsigned n = (unsigned) atoi(tokens->argv[1]); + acl_argv_free(tokens); + + // 如果服务器返回所关注的队列数为 0,肯定是出错了,因为至少还有一个 + // 缺省队列:default,所以此时需要关闭连接,以尽量消除与本连接相关 + // 的错误,下一个命令会自动进行重连操作以恢复操作过程 + if (n == 0) + { + logger_error("'watch %s' error(%s), tube watched is 0", + line.c_str(), tube); + close(); + } + return n; +} + +ACL_ARGV* beanstalk::beanstalk_request(const string& cmdline, + const void* data /*= NULL */, size_t len /* = 0 */) +{ + string line(128); + bool retried = false; + + while (true) + { + if (beanstalk_open() == false) + return NULL; + + // 先写入数据头 + if (conn_.write(cmdline) == -1) + { + conn_.close(); + if (retry_ && !retried) + { + retried = true; + continue; + } + logger_error("write to beanstalkd(%s) error: %s", + addr_, last_serror()); + return NULL; + } + + // 如果有数据体,则写入数据体 + if (data && len > 0 && (conn_.write(data, len) == -1 + || conn_.write("\r\n", 2) == -1)) + { + conn_.close(); + if (retry_ && !retried) + { + retried = true; + continue; + } + logger_error("write to beanstalkd(%s) error: %s", + addr_, last_serror()); + return NULL; + } + + line.clear(); + if (conn_.gets(line) == false || line.empty()) + { + conn_.close(); + if (retry_ && !retried) + { + retried = true; + continue; + } + logger_error("gets from beanstalkd(%s) error: %s", + addr_, last_serror()); + return NULL; + } + break; + } + + ACL_ARGV* tokens = acl_argv_split(line.c_str(), "\t "); + return tokens; +} + +bool beanstalk::open() +{ + if (conn_.opened()) + return true; + + if (conn_.open(addr_, timeout_, 0) == false) + { + logger_error("connect beanstalkd %s error: %s", + addr_, last_serror()); + return false; + } + return true; +} + +void beanstalk::close() +{ + if (conn_.opened()) + conn_.close(); + if (tube_used_) + { + acl_myfree(tube_used_); + tube_used_ = NULL; + } + std::vector::iterator it = tubes_watched_.begin(); + for (; it != tubes_watched_.end(); ++it) + acl_myfree(*it); + tubes_watched_.clear(); +} + +bool beanstalk::use(const char* tube) +{ + if (tube_used_) + { + // 在 beanstalk_request 前释放掉该值,可以避免在 + // beanstalk_request 触发 beanstalk_use 过程,虽然 + // 触发该过程并没有害处,但却多了一次通讯过程 + acl_myfree(tube_used_); + tube_used_ = NULL; + } + + string cmdline(128); + cmdline.format("use %s\r\n", tube); + ACL_ARGV* tokens = beanstalk_request(cmdline); + if (tokens == NULL) + { + logger_error("'%s' error", cmdline.c_str()); + return false; + } + if (tokens->argc < 2 || strcasecmp(tokens->argv[0], "USING") + || strcasecmp(tokens->argv[1], tube)) + { + logger_error("'%s' error %s", cmdline.c_str(), tokens->argv[0]); + ACL_SAFE_STRNCPY(errbuf_, tokens->argv[0], sizeof(errbuf_)); + acl_argv_free(tokens); + close(); + return false; + } + + acl_argv_free(tokens); + + // 放在后面,在第一次使用时可以避免多一次通讯交互 + tube_used_ = acl_mystrdup(tube); + + return true; +} + +unsigned long long beanstalk::put(const void* data, size_t n, + unsigned pri /* = 1024 */, unsigned delay /* = 0 */, + unsigned int ttr /* = 60 */) +{ + string cmdline(128); + cmdline.format("put %u %u %u %u\r\n", pri, delay, ttr, (unsigned int) n); + ACL_ARGV* tokens = beanstalk_request(cmdline, data, n); + if (tokens == NULL) + { + logger_error("'%s' error", cmdline.c_str()); + return 0; + } + + if (tokens->argc < 2 || strcasecmp(tokens->argv[0], "INSERTED")) + { + logger_error("'%s' error", cmdline.c_str()); + ACL_SAFE_STRNCPY(errbuf_, tokens->argv[0], sizeof(errbuf_)); + acl_argv_free(tokens); + close(); + return 0; + } + + unsigned long long id = (unsigned long long) atoll(tokens->argv[1]); + acl_argv_free(tokens); + return id; +} + +unsigned long long beanstalk::format_put(unsigned pri, unsigned delay, + unsigned int ttr, const char* fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + unsigned long long ret = vformat_put(fmt, ap, pri, delay, ttr); + va_end(ap); + return ret; +} + +unsigned long long beanstalk::vformat_put(const char* fmt, va_list ap, + unsigned pri /* = 1024 */, unsigned delay /* = 0 */, + unsigned ttr /* = 60 */) +{ + string buf; + buf.vformat(fmt, ap); + return put(buf.c_str(), buf.length(), pri, delay, ttr); +} + +unsigned long long beanstalk::format_put(const char* fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + unsigned long long ret = vformat_put(fmt, ap); + va_end(ap); + return ret; +} + +unsigned beanstalk::watch(const char* tube) +{ + // 先检查是否已经监控相同队列 + std::vector::iterator it = tubes_watched_.begin(); + for (; it != tubes_watched_.end(); ++it) + { + if (strcmp(*it, tube) == 0) + break; + } + + string cmdline(128); + cmdline.format("watch %s\r\n", tube); + ACL_ARGV* tokens = beanstalk_request(cmdline); + if (tokens == NULL) + { + logger_error("'%s' error", cmdline.c_str()); + return 0; + } + if (tokens->argc < 2 || strcasecmp(tokens->argv[0], "WATCHING")) + { + logger_error("'%s' error %s", cmdline.c_str(), tokens->argv[0]); + ACL_SAFE_STRNCPY(errbuf_, tokens->argv[0], sizeof(errbuf_)); + acl_argv_free(tokens); + close(); + return 0; + } + + unsigned n = (unsigned) atoi(tokens->argv[1]); + acl_argv_free(tokens); + + // 如果服务器返回所关注的队列数为 0,肯定是出错了,因为至少还有一个 + // 缺省队列:default,所以此时需要关闭连接,以尽量消除与本连接相关 + // 的错误,下一个命令会自动进行重连操作以恢复操作过程 + if (n == 0) + { + logger_error("'%s' error, tube watched is 0", cmdline.c_str()); + close(); + } + + // 添加进监控集合中 + else if (it == tubes_watched_.end()) + tubes_watched_.push_back(acl_mystrdup(tube)); + + return n; +} + +unsigned beanstalk::ignore(const char* tube) +{ + if (strcasecmp(tube, "default") == 0) + { + logger_error("tube(%s) is default, can't be ignore", tube); + return 0; + } + + bool found = false; + std::vector::iterator it = tubes_watched_.begin(); + for (; it != tubes_watched_.end(); ++it) + { + if (strcmp(tube, *it) == 0) + { + acl_myfree(*it); + tubes_watched_.erase(it); + found = true; + break; + } + } + + if (!found) + { + logger_error("tube(%s) not found", tube); + return 0; + } + return ignore_one(tube); +} + +unsigned beanstalk::ignore_all() +{ + if (tubes_watched_.size() <= 1) + { + // first tube watched must be "default" + if (strcmp(tubes_watched_[0], "default") != 0) + logger_fatal("first tube(%s) is not default", + tubes_watched_[0]); + return 1; + } + + unsigned ret = 1; // at least one default tube is watched + std::vector::iterator it_next = tubes_watched_.begin(), it; + ++it_next; // skip first default tube + for (it = it_next; it != tubes_watched_.end(); it = it_next) + { + ++it_next; + ret = ignore_one(*it); + if (ret == 0) + { + logger_error("ignore tube %s failed", *it); + return 0; + } + tubes_watched_.erase(it); + } + + return ret; +} + +unsigned beanstalk::ignore_one(const char* tube) +{ + string cmdline(128); + cmdline.format("ignore %s\r\n", tube); + ACL_ARGV* tokens = beanstalk_request(cmdline); + if (tokens == NULL) + { + logger_error("'%s' error", cmdline.c_str()); + return 0; + } + if (tokens->argc < 2 || strcasecmp(tokens->argv[0], "WATCHING")) + { + logger_error("'%s' error %s", cmdline.c_str(), tokens->argv[0]); + ACL_SAFE_STRNCPY(errbuf_, tokens->argv[0], sizeof(errbuf_)); + acl_argv_free(tokens); + close(); + return 0; + } + + unsigned n = (unsigned) atoi(tokens->argv[1]); + acl_argv_free(tokens); + + // 如果服务器返回所关注的队列数为 0,肯定是出错了,因为至少还有一个 + // 缺省队列:default,所以此时需要关闭连接,以尽量消除与本连接相关 + // 的错误,下一个命令会自动进行重连操作以恢复操作过程 + if (n == 0) + { + logger_error("'%s' error, tube watched is 0", cmdline.c_str()); + close(); + } + return n; +} + +unsigned long long beanstalk::reserve(string& buf, int timeout /* = -1 */) +{ + buf.clear(); // 虽然读操作过程也会清空缓存 + string cmdline(128); + if (timeout >= 0) + cmdline.format("reserve-with-timeout %d\r\n", timeout); + else + cmdline.format("reserve\r\n"); + ACL_ARGV* tokens = beanstalk_request(cmdline); + if (tokens == NULL) + { + logger_error("'%s' error", cmdline.c_str()); + return 0; + } + if (tokens->argc < 3 || strcasecmp(tokens->argv[0], "RESERVED")) + { + logger_error("reserve failed: %s", tokens->argv[0]); + ACL_SAFE_STRNCPY(errbuf_, tokens->argv[0], sizeof(errbuf_)); + acl_argv_free(tokens); + close(); + return 0; + } + + unsigned long long id = (unsigned long long) atoll(tokens->argv[1]); + unsigned short n = (unsigned short) atoi(tokens->argv[2]); + acl_argv_free(tokens); + + if (n == 0) + { + logger_error("reserve data's length 0"); + close(); + return 0; + } + + // 读取规定的字节数 + if (conn_.read(buf, n, true) == false) + { + logger_error("reserve read body failed"); + close(); + return 0; + } + else if (conn_.gets(cmdline) == false) + { + logger_error("reserve: gets last line failed"); + close(); + return 0; + } + return id; +} + +bool beanstalk::delete_id(unsigned long long id) +{ + string cmdline(128); + cmdline.format("delete %llu\r\n", id); + ACL_ARGV* tokens = beanstalk_request(cmdline); + if (tokens == NULL) + { + logger_error("'%s' error", cmdline.c_str()); + return false; + } + if (strcasecmp(tokens->argv[0], "DELETED")) + { + logger_error("'%s' error %s", cmdline.c_str(), tokens->argv[0]); + ACL_SAFE_STRNCPY(errbuf_, tokens->argv[0], sizeof(errbuf_)); + acl_argv_free(tokens); + return false; + } + + acl_argv_free(tokens); + return true; +} + +bool beanstalk::release(unsigned long long id, unsigned pri /* = 1024 */, + unsigned delay /* = 0*/) +{ + string cmdline(128); + cmdline.format("release %llu %u %u\r\n", id, pri, delay); + ACL_ARGV* tokens = beanstalk_request(cmdline); + if (tokens == NULL) + { + logger_error("'%s' error", cmdline.c_str()); + return false; + } + if (strcasecmp(tokens->argv[0], "RELEASED")) + { + logger_error("'%s' error %s", cmdline.c_str(), tokens->argv[0]); + ACL_SAFE_STRNCPY(errbuf_, tokens->argv[0], sizeof(errbuf_)); + acl_argv_free(tokens); + return false; + } + + acl_argv_free(tokens); + return true; +} + +bool beanstalk::bury(unsigned long long id, unsigned int pri /* = 1024 */) +{ + string cmdline(128); + cmdline.format("bury %llu %u %u\r\n", id, pri); + ACL_ARGV* tokens = beanstalk_request(cmdline); + if (tokens == NULL) + { + logger_error("'%s' error", cmdline.c_str()); + return false; + } + if (strcasecmp(tokens->argv[0], "BURIED")) + { + logger_error("'%s' error %s", cmdline.c_str(), tokens->argv[0]); + ACL_SAFE_STRNCPY(errbuf_, tokens->argv[0], sizeof(errbuf_)); + acl_argv_free(tokens); + return false; + } + + acl_argv_free(tokens); + return true; +} + +bool beanstalk::touch(unsigned long long id) +{ + string cmdline(128); + cmdline.format("touch %llu\r\n", id); + ACL_ARGV* tokens = beanstalk_request(cmdline); + if (tokens == NULL) + { + logger_error("'%s' error", cmdline.c_str()); + return false; + } + if (strcasecmp(tokens->argv[0], "TOUCHED")) + { + logger_error("'%s' error %s", cmdline.c_str(), tokens->argv[0]); + ACL_SAFE_STRNCPY(errbuf_, tokens->argv[0], sizeof(errbuf_)); + acl_argv_free(tokens); + return false; + } + + acl_argv_free(tokens); + return true; +} + +unsigned long long beanstalk::peek_fmt(string& buf, const char* fmt, ...) +{ + buf.clear(); // 虽然读操作过程也会清空缓存 + + string cmdline(128); + va_list ap; + va_start(ap, fmt); + cmdline.vformat(fmt, ap); + va_end(ap); + + ACL_ARGV* tokens = beanstalk_request(cmdline); + if (tokens == NULL) + { + logger_error("'%s' error", cmdline.c_str()); + return 0; + } + if (tokens->argc < 3 || strcasecmp(tokens->argv[0], "FOUND")) + { + ACL_SAFE_STRNCPY(errbuf_, tokens->argv[0], sizeof(errbuf_)); + acl_argv_free(tokens); + return 0; + } + unsigned long long id = (unsigned long long) atoll(tokens->argv[1]); + unsigned short n = (unsigned short) atoi(tokens->argv[2]); + acl_argv_free(tokens); + + if (n == 0) + { + logger_error("peek data's length 0"); + close(); + return 0; + } + + // 读取规定的字节数 + if (conn_.read(buf, n, true) == false) + { + logger_error("peek read body failed"); + close(); + return 0; + } + else if (conn_.gets(cmdline) == false) + { + logger_error("peek: gets last line falied"); + close(); + return 0; + } + return id; +} + +unsigned long long beanstalk::peek(string& buf, unsigned long long id) +{ + return peek_fmt(buf, "peek %llu\r\n", id); +} + +unsigned long long beanstalk::peek_ready(string& buf) +{ + return peek_fmt(buf, "peek-ready\r\n"); +} + +unsigned long long beanstalk::peek_delayed(string& buf) +{ + return peek_fmt(buf, "peek-delayed\r\n"); +} + +unsigned long long beanstalk::peek_buried(string& buf) +{ + return peek_fmt(buf, "peek-buried\r\n"); +} + +int beanstalk::kick(unsigned n) +{ + string cmdline(128); + cmdline.format("kick %u\r\n", n); + ACL_ARGV* tokens = beanstalk_request(cmdline); + if (tokens == NULL) + { + logger_error("'%s' error", cmdline.c_str()); + return -1; + } + if (strcasecmp(tokens->argv[0], "KICKED")) + { + logger_error("'%s' error %s", cmdline.c_str(), tokens->argv[0]); + ACL_SAFE_STRNCPY(errbuf_, tokens->argv[0], sizeof(errbuf_)); + acl_argv_free(tokens); + return -1; + } + + int ret; + if (tokens->argc >= 2) + ret = atoi(tokens->argv[1]); + else + ret = 0; + acl_argv_free(tokens); + return ret; +} + +bool beanstalk::list_tube_used(string& buf) +{ + buf.clear(); // 虽然读操作过程也会清空缓存 + + string cmdline(128); + cmdline.format("list-tube-used\r\n"); + ACL_ARGV* tokens = beanstalk_request(cmdline); + if (tokens == NULL) + { + logger_error("'%s' error", cmdline.c_str()); + return false; + } + if (tokens->argc < 2 || strcasecmp(tokens->argv[0], "USING")) + { + logger_error("'%s' error %s", cmdline.c_str(), tokens->argv[0]); + ACL_SAFE_STRNCPY(errbuf_, tokens->argv[0], sizeof(errbuf_)); + acl_argv_free(tokens); + close(); + return false; + } + + buf = tokens->argv[1]; + acl_argv_free(tokens); + return true; +} + +bool beanstalk::list_tubes_fmt(string& buf, const char* fmt, ...) +{ + buf.clear(); // 虽然读操作过程也会清空缓存 + + string cmdline(128); + va_list ap; + va_start(ap, fmt); + cmdline.vformat(fmt, ap); + va_end(ap); + + ACL_ARGV* tokens = beanstalk_request(cmdline); + if (tokens == NULL) + { + logger_error("'%s' error", cmdline.c_str()); + return false; + } + if (tokens->argc < 2 || strcasecmp(tokens->argv[0], "OK")) + { + ACL_SAFE_STRNCPY(errbuf_, tokens->argv[0], sizeof(errbuf_)); + acl_argv_free(tokens); + close(); + return false; + } + unsigned short n = (unsigned short) atoi(tokens->argv[1]); + acl_argv_free(tokens); + + if (n == 0) + { + logger_error("list data's length 0"); + close(); + return false; + } + + // 读取规定的字节数 + if (conn_.read(buf, n, true) == false) + { + logger_error("peek read body failed"); + close(); + return false; + } + return true; +} + +bool beanstalk::list_tubes(string& buf) +{ + return list_tubes_fmt(buf, "list-tubes\r\n"); +} + +bool beanstalk::list_tubes_watched(string& buf) +{ + return list_tubes_fmt(buf, "list-tubes-watched\r\n"); +} + +bool beanstalk::pause_tube(const char* tube, unsigned delay) +{ + string cmdline(128); + cmdline.format("pause-tube %s %u\r\n", tube, delay); + ACL_ARGV* tokens = beanstalk_request(cmdline); + if (tokens == NULL) + { + logger_error("'%s' error", cmdline.c_str()); + return false; + } + if (strcasecmp(tokens->argv[0], "PAUSED")) + { + logger_error("'%s' error %s", cmdline.c_str(), tokens->argv[0]); + ACL_SAFE_STRNCPY(errbuf_, tokens->argv[0], sizeof(errbuf_)); + acl_argv_free(tokens); + return false; + } + + acl_argv_free(tokens); + return true; +} + +void beanstalk::quit() +{ + if (conn_.opened()) + { + conn_.format("quit\r\n"); + conn_.close(); + } +} + +} // namespace acl diff --git a/lib_acl_cpp/src/beanstalk/beanstalk_pool.cpp b/lib_acl_cpp/src/beanstalk/beanstalk_pool.cpp new file mode 100644 index 000000000..1c0cb364c --- /dev/null +++ b/lib_acl_cpp/src/beanstalk/beanstalk_pool.cpp @@ -0,0 +1,62 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/stdlib/locker.hpp" +#include "acl_cpp/beanstalk/beanstalk.hpp" +#include "acl_cpp/beanstalk/beanstalk_pool.hpp" + +namespace acl { + +beanstalk_pool::beanstalk_pool() +{ + lock_ = NEW locker(); +} + +beanstalk_pool::~beanstalk_pool() +{ + pool_it it = pool_.begin(); + for (; it != pool_.end(); ++it) + delete it->second; + delete lock_; +} + +beanstalk* beanstalk_pool::peek(const char* addr, bool clean_watch /* = true */, + int conn_timeout /* = 60 */) +{ + char* key = acl_mystrdup(addr); + acl_lowercase(key); + + lock_->lock(); + pool_range r = pool_.equal_range(key); + for (pool_it it = r.first; it != r.second; ++it) + { + beanstalk* client = it->second; + pool_.erase(it); + lock_->unlock(); + + acl_myfree(key); + if (clean_watch) + client->ignore_all(); + return client; + } + + lock_->unlock(); + acl_myfree(key); + return NEW beanstalk(addr, conn_timeout); +} + +void beanstalk_pool::put(beanstalk* client, bool clean_watch /* = true */, + bool keep /* = true */) +{ + if (keep == false) + { + delete client; + return; + } + if (clean_watch) + client->ignore_all(); + + lock_->lock(); + pool_.insert(std::make_pair(client->get_addr(), client)); + lock_->unlock(); +} + +} // namespace acl diff --git a/lib_acl_cpp/src/connpool/connect_manager.cpp b/lib_acl_cpp/src/connpool/connect_manager.cpp new file mode 100644 index 000000000..fbb1e18c9 --- /dev/null +++ b/lib_acl_cpp/src/connpool/connect_manager.cpp @@ -0,0 +1,204 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/stdlib/string.hpp" +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/stdlib/locker.hpp" +#include "acl_cpp/connpool/connect_pool.hpp" +#include "acl_cpp/connpool/connect_manager.hpp" + +namespace acl +{ + +connect_manager::connect_manager() +: default_pool_(NULL) +, service_idx_(0) +, stat_inter_(1) +{ +} + +connect_manager::~connect_manager() +{ + std::vector::iterator it = pools_.begin(); + + // default_pool_ 已经包含在 pools_ 里了 + for (; it != pools_.end(); ++it) + delete *it; +} + +// 分析一个服务器地址,格式:IP:PORT[:MAX_CONN] +// 返回值 < 0 表示非法的地址 +static int check_addr(const char* addr, string& buf, int default_count) +{ + // 数据格式:IP:PORT[:CONNECT_COUNT] + ACL_ARGV* tokens = acl_argv_split(addr, ":|"); + if (tokens->argc < 2) + { + logger_error("invalid addr: %s", addr); + acl_argv_free(tokens); + return -1; + } + + int port = atoi(tokens->argv[1]); + if (port <= 0 || port >= 65535) + { + logger_error("invalid addr: %s, port: %d", addr, port); + acl_argv_free(tokens); + return -1; + } + buf.format("%s:%d", tokens->argv[0], port); + int conn_max; + if (tokens->argc >= 3) + conn_max = atoi(tokens->argv[2]); + else + conn_max = default_count; + if (conn_max <= 0) + conn_max = default_count; + acl_argv_free(tokens); + return conn_max; +} + +void connect_manager::init(const char* default_addr, + const char* addr_list, int count) +{ + if (addr_list != NULL && *addr_list != 0) + set_service_list(addr_list, count); + + // 创建缺省 redis 服务连接池对象,该对象一同放入总的连接池集群中 + if (default_addr != NULL && *default_addr != 0) + { + logger("default_pool: %s", default_addr); + int max = check_addr(default_addr, default_addr_, count); + default_pool_ = &set(default_addr_.c_str(), max); + } + else + logger("no default redis set"); + + // 必须保证至少有一个 redis 服务可用 + if (pools_.empty()) + logger_fatal("no redis service available!"); +} + +void connect_manager::set_service_list(const char* addr_list, int count) +{ + if (addr_list == NULL || *addr_list == 0) + { + logger("addr_list null"); + return; + } + + // 创建 redis 连接池服务集群 + + ACL_ARGV* tokens = acl_argv_split(addr_list, ";, \t"); + ACL_ITER iter; + acl::string addr; + acl_foreach(iter, tokens) + { + const char* ptr = (const char*) iter.data; + int max = check_addr(ptr, addr, count); + if (max <= 0) + { + logger_error("invalid redis addr: %s", addr.c_str()); + continue; + } + set(addr.c_str(), max); + logger("add one service: %s, max connect: %d", + addr.c_str(), max); + } + acl_argv_free(tokens); +} + +connect_pool& connect_manager::set(const char* addr, int count) +{ + char key[64]; + ACL_SAFE_STRNCPY(key, addr, sizeof(key)); + acl_lowercase(key); + + std::vector::iterator it = pools_.begin(); + for (; it != pools_.end(); ++it) + { + if (strcasecmp(key, (*it)->get_addr()) == 0) + return **it; + } + + connect_pool* pool = create_pool(key, count); + pools_.push_back(pool); + service_size_ = pools_.size(); + + logger("Add one service, addr: %s, count: %d", addr, count); + + return *pool; +} + +connect_pool* connect_manager::get(const char* addr) +{ + char key[64]; + ACL_SAFE_STRNCPY(key, addr, sizeof(key)); + acl_lowercase(key); + + std::vector::iterator it = pools_.begin(); + for (; it != pools_.end(); ++it) + { + if (strcasecmp(key, (*it)->get_addr()) == 0) + return *it; + } + + logger_error("no connect pool for addr %s", addr); + return NULL; +} + +////////////////////////////////////////////////////////////////////////// + +connect_pool* connect_manager::peek() +{ + connect_pool* pool; + lock_.lock(); + size_t n = service_idx_ % service_size_; + service_idx_++; + lock_.unlock(); + pool = pools_[n]; + return pool; +} + +void connect_manager::statistics_record(int, void* ctx) +{ + connect_manager* manager = (connect_manager*) ctx; + + // 记录当前 redis 访问情况 + manager->statistics(); + + // 重新设置定时器 + manager->statistics_timer(); +} + +void connect_manager::statistics_settimer(int inter /* = 1 */) +{ + if (inter <= 0 || inter >= 3600 * 24 * 32) + { + logger_error("invalid inter: %d", inter); + return; + } + + stat_inter_ = inter; +#ifndef WIN32 + acl_ioctl_server_request_timer(statistics_record, this, inter); +#endif + logger("set statistics_timer ok! inter: %d", inter); +} + +void connect_manager::statistics_timer() +{ + statistics_settimer(stat_inter_); +} + +void connect_manager::statistics() +{ + std::vector::const_iterator cit = pools_.begin(); + for (; cit != pools_.end(); ++cit) + { + logger("redis: %s, total: %llu, curr: %llu", + (*cit)->get_addr(), (*cit)->get_total_used(), + (*cit)->get_current_used()); + (*cit)->reset_statistics(stat_inter_); + } +} + +} // namespace acl diff --git a/lib_acl_cpp/src/connpool/connect_pool.cpp b/lib_acl_cpp/src/connpool/connect_pool.cpp new file mode 100644 index 000000000..b724ae28a --- /dev/null +++ b/lib_acl_cpp/src/connpool/connect_pool.cpp @@ -0,0 +1,192 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/stdlib/locker.hpp" +#include "acl_cpp/connpool/connect_client.hpp" +#include "acl_cpp/connpool/connect_pool.hpp" + +namespace acl +{ + +connect_pool::connect_pool(const char* addr, int max, int retry_inter /* = 1 */) +: alive_(true) +, last_dead_(0) +, max_(max) +, count_(0) +, idle_ttl_(-1) +, last_check_(0) +, check_inter_(30) +, total_used_(0) +, current_used_(0) +, last_(0) +{ + if (retry_inter < 1 || retry_inter >= 60) + retry_inter_ = 1; + else + retry_inter_ = retry_inter; + + if (max_ < 1) + max_ = 10; + + ACL_SAFE_STRNCPY(addr_, addr, sizeof(addr_)); +} + +connect_pool::~connect_pool() +{ + std::list::iterator it = pool_.begin(); + for (; it != pool_.end(); ++it) + delete *it; +} + +connect_pool& connect_pool::set_idle_ttl(time_t ttl) +{ + idle_ttl_ = ttl; + return *this; +} + +connect_client* connect_pool::peek() +{ + lock_.lock(); + if (alive_ == false) + { + time_t now = time(NULL); + if (now - last_dead_ < retry_inter_) + { + lock_.unlock(); + return NULL; + } + alive_ = true; + } + + connect_client* conn; + + std::list::iterator it = pool_.begin(); + if (it != pool_.end()) + { + conn = *it; + pool_.erase(it); + total_used_++; + current_used_++; + lock_.unlock(); + return conn; + } + else if (count_ >= max_) + { + logger_error("too many connect(%d > %d) to redis: %s", + count_, max_, addr_); + lock_.unlock(); + return NULL; + } + + conn = create_connect(); + if (conn->open() == false) + { + delete conn; + alive_ = false; + time(&last_dead_); + (void) time(&last_dead_); + lock_.unlock(); + return NULL; + } + + count_++; + + total_used_++; + current_used_++; + + lock_.unlock(); + return conn; +} + +void connect_pool::put(connect_client* conn, bool keep /* = true */) +{ + time_t now = time(NULL); + + lock_.lock(); + if (keep && alive_) + { + conn->set_when(now); + pool_.push_back(conn); + } + else + { + delete conn; + count_--; + acl_assert(count_ >= 0); + } + + if (idle_ttl_ >= 0 && now - last_check_ >= check_inter_) + { + (void) check_idle(idle_ttl_, false); + (void) time(&last_check_); + } + lock_.unlock(); +} + +void connect_pool::set_alive(bool ok /* true | false */) +{ + lock_.lock(); + alive_ = ok; + if (ok == false) + time(&last_dead_); + lock_.unlock(); +} + +int connect_pool::check_idle(time_t ttl, bool exclusive /* = true */) +{ + if (ttl < 0) + return 0; + if (exclusive) + lock_.lock(); + if (pool_.empty()) + { + lock_.unlock(); + return 0; + } + + if (ttl == 0) + { + int n = 0; + std::list::iterator it = pool_.begin(); + for (; it != pool_.end(); ++it) + { + delete *it; + n++; + }; + pool_.clear(); + count_ = 0; + lock_.unlock(); + return n; + } + + int n = 0; + time_t now = time(NULL), when; + + std::list::iterator it, next; + std::list::reverse_iterator rit = pool_.rbegin(); + + for (; rit != pool_.rend();) + { + it = --rit.base(); + when = (*it)->get_when(); + if (when <= 0) + { + ++rit; + continue; + } + + if (now - when < ttl) + break; + + delete *it; + next = pool_.erase(it); + rit = std::list::reverse_iterator(next); + + n++; + count_--; + } + + lock_.unlock(); + return n; +} + +} // namespace acl diff --git a/lib_acl_cpp/src/db/db_handle.cpp b/lib_acl_cpp/src/db/db_handle.cpp new file mode 100644 index 000000000..3259d1e0b --- /dev/null +++ b/lib_acl_cpp/src/db/db_handle.cpp @@ -0,0 +1,374 @@ +#include "acl_stdafx.hpp" +#include +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/db/db_pool.hpp" +#include "acl_cpp/db/db_handle.hpp" + +namespace acl +{ + +////////////////////////////////////////////////////////////////////////// + +db_row::db_row(const std::vector& names) +: names_(names) +{ + +} + +db_row::~db_row() +{ + +} + +const char* db_row::field_name(size_t ifield) const +{ + if (ifield >= names_.size()) + { + logger_error("ifield: %d > names_.size: %d", + (int) ifield, (int) names_.size()); + return (NULL); + } + return (names_[ifield]); +} + +const char* db_row::field_value(const char* name) const +{ + size_t i, n = names_.size(); + + // 必须保证表中字段名的个数与行记录的值的个数相等 + acl_assert(names_.size() == values_.size()); + + // 通过扫描字段名找出字段值的下标位置 + for (i = 0; i < n; i++) + { + if (strcasecmp(name, names_[i]) == 0) + break; + } + if (i == n) + { + logger_error("cloumn not exist, name: %s", name); + return (NULL); + } + + // 直接返回相应下标的字段值 + return (values_[i]); +} + +const char* db_row::operator [](const char* name) const +{ + return (field_value(name)); +} + +const char* db_row::field_value(size_t ifield) const +{ + if (ifield >= values_.size()) + { + logger_error("ifield(%d) invalid, values_.size: %d", + ifield, (int) values_.size()); + return (NULL); + } + + return (values_[ifield]); +} + +const char* db_row::operator [](size_t ifield) const +{ + return (field_value(ifield)); +} + +int db_row::field_int(size_t ifield, int null_value /* = 0 */) const +{ + const char* ptr = field_value(ifield); + if (ptr == NULL) + return (null_value); + else + return (atoi(ptr)); +} + +int db_row::field_int(const char* name, int null_value /* = 0 */) const +{ + const char* ptr = field_value(name); + if (ptr == NULL) + return (null_value); + else + return (atoi(ptr)); +} + +acl_int64 db_row::field_int64(size_t ifield, acl_int64 null_value /* = 0 */) const +{ + const char* ptr = field_value(ifield); + if (ptr == NULL) + return (null_value); + else + return (ACL_DB_ATOU(ptr)); +} + +acl_int64 db_row::field_int64(const char* name, acl_int64 null_value /* = 0 */) const +{ + const char* ptr = field_value(name); + if (ptr == NULL) + return (null_value); + else + return (ACL_DB_ATOU(ptr)); +} + +const char* db_row::field_string(size_t ifield) const +{ + const char* ptr = field_value(ifield); + if (ptr == NULL) + return (NULL); + else + return (ptr); +} + +const char* db_row::field_string(const char* name) const +{ + const char* ptr = field_value(name); + if (ptr == NULL) + return (NULL); + else + return (ptr); +} + +void db_row::push_back(const char* value) +{ + values_.push_back(value); +} + +size_t db_row::length() const +{ + return (values_.size()); +} + +////////////////////////////////////////////////////////////////////////// + +db_rows::db_rows() +{ + +} + +db_rows::~db_rows() +{ + std::vector::iterator it = rows_.begin(); + for (; it != rows_.end(); ++it) + delete (*it); +} + +const std::vector& db_rows::get_rows( + const char* name, const char* value) +{ + // 先清空上一次的临时结果集 + rows_tmp_.clear(); + + if (empty()) + return (rows_tmp_); + + size_t icolumn, ncolumn = names_.size(); + + // 通过扫描字段名找出字段值的下标位置 + for (icolumn = 0; icolumn < ncolumn; icolumn++) + { + if (strcasecmp(name, names_[icolumn]) == 0) + break; + } + + const db_row* row; + const char* ptr = 0; + + // 比较对应下标相同的字段值的行记录 + size_t nrow = rows_.size(); + for (size_t irow = 0; irow < nrow; irow++) + { + row = rows_[irow]; + acl_assert(row->length() == ncolumn); + ptr = (*row)[icolumn]; + if (ptr && strcmp(ptr, value) == 0) + rows_tmp_.push_back(row); + } + + return (rows_tmp_); +} + +const std::vector& db_rows::get_rows() const +{ + return (rows_); +} + +const db_row* db_rows::operator [](size_t idx) const +{ + if (idx >= rows_.size()) + { + logger_error("idx(%d) >= rows_.size %d", (int) idx, rows_.size()); + return (NULL); + } + + db_row* row = rows_[idx]; + return (row); +} + +bool db_rows::empty() const +{ + return (rows_.empty()); +} + +size_t db_rows::length() const +{ + return (rows_.size()); +} + +////////////////////////////////////////////////////////////////////////// + +db_handle::db_handle() +: result_(NULL) +, id_(NULL) +{ + time(&when_); +} + +db_handle::~db_handle() +{ + if (id_) + acl_myfree(id_); +} + +string& db_handle::escape_string(const char* in, size_t len, string& out) +{ + for (size_t i = 0; i < len; i++, in++) + { + switch (*in) { + case 0: /* Must be escaped for 'mysql' */ + out += '\\'; + out += '0'; + break; + case '\n': /* Must be escaped for logs */ + out += '\\'; + out += 'n'; + break; + case '\r': + out += '\\'; + out += 'r'; + break; + case '\\': + out += '\\'; + out += '\\'; + break; + case '\'': + out += '\\'; + out += '\''; + break; + case '"': /* Better safe than sorry */ + out += '\\'; + out += '"'; + break; + case '\032': /* This gives problems on Win32 */ + out += '\\'; + out += 'Z'; + break; + default: + out += *in; + break; + } + } + + return out; +} + +void db_handle::print_out(size_t max /* = 0 */) const +{ + // 列出查询结果方法二 + for (size_t i = 0; i < length(); i++) + { + if (max > 0 && i >= max) + continue; + + const acl::db_row* row = (*this)[i]; + + for (size_t j = 0; j < row->length(); j++) + printf("%s, ", (*row)[j]); + printf("\r\n"); + } + + printf("total result: %d\n", (int) length()); +} + + +const db_rows* db_handle::get_result() const +{ + return (result_); +} + +const std::vector* db_handle::get_rows( + const char* name, const char* value) +{ + if (result_ == NULL) + return NULL; + const std::vector& rows = result_->get_rows(name, value); + return &rows; +} + +const std::vector* db_handle::get_rows() const +{ + if (result_ == NULL) + return NULL; + const std::vector& rows = result_->get_rows(); + return &rows; +} + +const db_row* db_handle::get_first_row() const +{ + if (result_ == NULL) + return NULL; + + const std::vector& rows = result_->get_rows(); + const acl::db_row* first_row = rows[0]; + acl_assert(first_row); + return first_row; +} + +void db_handle::free_result() +{ + if (result_) + { + delete result_; + result_ = NULL; + } +} + +const db_row* db_handle::operator [](size_t idx) const +{ + if (result_ == NULL) + return (NULL); + if (idx >= result_->length()) + return (NULL); + return (*result_)[idx]; +} + +size_t db_handle::length() const +{ + if (result_ == NULL) + return 0; + else + return result_->length(); +} + +bool db_handle::empty() const +{ + return (length() == 0 ? true : false); +} + +db_handle& db_handle::set_id(const char* id) +{ + if (id == NULL || *id == 0) + return *this; + if (id_) + acl_myfree(id_); + id_ = acl_mystrdup(id); + return *this; +} + +db_handle& db_handle::set_when(time_t now) +{ + when_ = now; + return *this; +} +} // namespace acl diff --git a/lib_acl_cpp/src/db/db_mysql.cpp b/lib_acl_cpp/src/db/db_mysql.cpp new file mode 100644 index 000000000..31e01e156 --- /dev/null +++ b/lib_acl_cpp/src/db/db_mysql.cpp @@ -0,0 +1,625 @@ +#include "acl_stdafx.hpp" +#include +#include "mysql.h" +#include "errmsg.h" +#include "mysqld_error.h" +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/db/db_mysql.hpp" + +////////////////////////////////////////////////////////////////////////// + +#ifdef HAS_MYSQL + +#if defined(ACL_CPP_DLL) || defined(USE_DYNAMIC) +typedef unsigned long (*mysql_libversion_fn)(void); +typedef const char* (*mysql_client_info_fn)(void); +typedef MYSQL* (*mysql_init_fn)(MYSQL*); +typedef MYSQL* (*mysql_open_fn)(MYSQL*, const char*, const char*, + const char*, const char*, unsigned int, + const char*, unsigned long); +typedef void (*mysql_close_fn)(MYSQL*); +typedef int (*mysql_options_fn)(MYSQL*,enum mysql_option option, const void*); +typedef my_bool (*mysql_autocommit_fn)(MYSQL*, my_bool); +typedef unsigned int (*mysql_errno_fn)(MYSQL*); +typedef const char* (*mysql_error_fn)(MYSQL*); +typedef int (*mysql_query_fn)(MYSQL*, const char*); +typedef unsigned int (*mysql_num_fields_fn)(MYSQL_RES*); +typedef MYSQL_FIELD* (*mysql_fetch_fields_fn)(MYSQL_RES*); +typedef MYSQL_ROW (*mysql_fetch_row_fn)(MYSQL_RES*); +typedef MYSQL_RES* (*mysql_store_result_fn)(MYSQL*); +typedef my_ulonglong (*mysql_num_rows_fn)(MYSQL_RES*); +typedef void (*mysql_free_result_fn)(MYSQL_RES*); +typedef my_ulonglong (*mysql_affected_rows_fn)(MYSQL*); +typedef int (*mysql_set_character_set_fn)(MYSQL*, const char*); +typedef const char* (*mysql_character_set_name_fn)(MYSQL*); + +static mysql_libversion_fn __mysql_libversion = NULL; +static mysql_client_info_fn __mysql_client_info = NULL; +static mysql_init_fn __mysql_init = NULL; +static mysql_open_fn __mysql_open = NULL; +static mysql_close_fn __mysql_close = NULL; +static mysql_options_fn __mysql_options = NULL; +static mysql_autocommit_fn __mysql_autocommit = NULL; +static mysql_errno_fn __mysql_errno = NULL; +static mysql_error_fn __mysql_error = NULL; +static mysql_query_fn __mysql_query = NULL; +static mysql_num_fields_fn __mysql_num_fields = NULL; +static mysql_fetch_fields_fn __mysql_fetch_fields = NULL; +static mysql_fetch_row_fn __mysql_fetch_row = NULL; +static mysql_store_result_fn __mysql_store_result = NULL; +static mysql_num_rows_fn __mysql_num_rows = NULL; +static mysql_free_result_fn __mysql_free_result = NULL; +static mysql_affected_rows_fn __mysql_affected_rows = NULL; +static mysql_set_character_set_fn __mysql_set_character_set = NULL; +static mysql_character_set_name_fn __mysql_character_set_name = NULL; + +static acl_pthread_once_t __mysql_once = ACL_PTHREAD_ONCE_INIT; +static ACL_DLL_HANDLE __mysql_dll = NULL; + +// 程序退出释放动态加载的库 +static void __mysql_dll_unload(void) +{ + if (__mysql_dll != NULL) + { + acl_dlclose(__mysql_dll); + __mysql_dll = NULL; + logger("libmysql.dll unload ok"); + } +} + +// 动态加载 libmysql.dll 库 +static void __mysql_dll_load(void) +{ + if (__mysql_dll != NULL) + logger_fatal("__mysql_dll not null"); + + __mysql_dll = acl_dlopen("libmysql.dll"); + if (__mysql_dll == NULL) + logger_fatal("load libmysql.dll error: %s", acl_last_serror()); + + __mysql_libversion = (mysql_libversion_fn) acl_dlsym(__mysql_dll, "mysql_get_client_version"); + if (__mysql_libversion == NULL) + logger_fatal("load mysql_get_client_version from libmysql.dll error: %s", acl_last_serror()); + + __mysql_client_info = (mysql_client_info_fn) acl_dlsym(__mysql_dll, "mysql_get_client_info"); + if (__mysql_client_info == NULL) + logger_fatal("load mysql_get_client_info from libmysql.dll error: %s", acl_last_serror()); + + __mysql_init = (mysql_init_fn) acl_dlsym(__mysql_dll, "mysql_init"); + if (__mysql_init == NULL) + logger_fatal("load mysql_init from libmysql.dll error: %s", acl_last_serror()); + + __mysql_open = (mysql_open_fn) acl_dlsym(__mysql_dll, "mysql_real_connect"); + if (__mysql_open == NULL) + logger_fatal("load mysql_real_connect from libmysql.dll error: %s", acl_last_serror()); + + __mysql_close = (mysql_close_fn) acl_dlsym(__mysql_dll, "mysql_close"); + if (__mysql_close == NULL) + logger_fatal("load mysql_close from libmysql.dll error: %s", acl_last_serror()); + + __mysql_options = (mysql_options_fn) acl_dlsym(__mysql_dll, "mysql_options"); + if (__mysql_options == NULL) + logger_fatal("load mysql_options from libmysql.dll error: %s", acl_last_serror()); + + __mysql_autocommit = (mysql_autocommit_fn) acl_dlsym(__mysql_dll, "mysql_autocommit"); + if (__mysql_autocommit == NULL) + logger_fatal("load mysql_autocommit from libmysql.dll error: %s", acl_last_serror()); + + __mysql_errno = (mysql_errno_fn) acl_dlsym(__mysql_dll, "mysql_errno"); + if (__mysql_errno == NULL) + logger_fatal("load mysql_errno from libmysql.dll error: %s", acl_last_serror()); + + __mysql_error = (mysql_error_fn) acl_dlsym(__mysql_dll, "mysql_error"); + if (__mysql_error == NULL) + logger_fatal("load mysql_error from libmysql.dll error: %s", acl_last_serror()); + + __mysql_query = (mysql_query_fn) acl_dlsym(__mysql_dll, "mysql_query"); + if (__mysql_query == NULL) + logger_fatal("load mysql_query from libmysql.dll error: %s", acl_last_serror()); + + __mysql_num_fields = (mysql_num_fields_fn) acl_dlsym(__mysql_dll, "mysql_num_fields"); + if (__mysql_num_fields == NULL) + logger_fatal("load mysql_num_fields from libmysql.dll error: %s", acl_last_serror()); + + __mysql_fetch_fields = (mysql_fetch_fields_fn) acl_dlsym(__mysql_dll, "mysql_fetch_fields"); + if (__mysql_fetch_fields == NULL) + logger_fatal("load mysql_fetch_fields from libmysql.dll error: %s", acl_last_serror()); + + __mysql_fetch_row = (mysql_fetch_row_fn) acl_dlsym(__mysql_dll, "mysql_fetch_row"); + if (__mysql_fetch_row == NULL) + logger_fatal("load mysql_fetch_row from libmysql.dll error: %s", acl_last_serror()); + + __mysql_store_result = (mysql_store_result_fn) acl_dlsym(__mysql_dll, "mysql_store_result"); + if (__mysql_store_result == NULL) + logger_fatal("load mysql_store_result from libmysql.dll error: %s", acl_last_serror()); + + __mysql_num_rows = (mysql_num_rows_fn) acl_dlsym(__mysql_dll, "mysql_num_rows"); + if (__mysql_num_rows == NULL) + logger_fatal("load mysql_num_rows from libmysql.dll error: %s", acl_last_serror()); + + __mysql_free_result = (mysql_free_result_fn) acl_dlsym(__mysql_dll, "mysql_free_result"); + if (__mysql_free_result == NULL) + logger_fatal("load mysql_free_result from libmysql.dll error: %s", acl_last_serror()); + + __mysql_affected_rows = (mysql_affected_rows_fn) acl_dlsym(__mysql_dll, "mysql_affected_rows"); + if (__mysql_affected_rows == NULL) + logger_fatal("load mysql_affected_rows from libmysql.dll error: %s", acl_last_serror()); + + __mysql_set_character_set = (mysql_set_character_set_fn) acl_dlsym(__mysql_dll, "mysql_set_character_set"); + if (__mysql_affected_rows == NULL) + logger_fatal("load mysql_set_character_set_fn from libmysql.dll error: %s", acl_last_serror()); + + __mysql_character_set_name = (mysql_character_set_name_fn) acl_dlsym(__mysql_dll, "mysql_character_set_name"); + if (__mysql_affected_rows == NULL) + logger_fatal("load mysql_character_set_name from libmysql.dll error: %s", acl_last_serror()); + + logger("libmysql.dll loaded"); + atexit(__mysql_dll_unload); +} +#else + +# define __mysql_libversion mysql_get_client_version +# define __mysql_client_info mysql_get_client_info +# define __mysql_init mysql_init +# define __mysql_open mysql_real_connect +# define __mysql_close mysql_close +# define __mysql_options mysql_options +# define __mysql_autocommit mysql_autocommit +# define __mysql_errno mysql_errno +# define __mysql_error mysql_error +# define __mysql_query mysql_query +# define __mysql_num_fields mysql_num_fields +# define __mysql_fetch_fields mysql_fetch_fields +# define __mysql_fetch_row mysql_fetch_row +# define __mysql_store_result mysql_store_result +# define __mysql_num_rows mysql_num_rows +# define __mysql_free_result mysql_free_result +# define __mysql_affected_rows mysql_affected_rows +# define __mysql_set_character_set mysql_set_character_set +# define __mysql_character_set_name mysql_character_set_name + +#endif + +////////////////////////////////////////////////////////////////////////// + +namespace acl +{ + +////////////////////////////////////////////////////////////////////////// +// mysql 的记录行类型定义 + +class db_mysql_rows : public db_rows +{ +public: + db_mysql_rows(MYSQL_RES *my_res) + { + int ncolumn = __mysql_num_fields(my_res); + MYSQL_FIELD *fields = __mysql_fetch_fields(my_res); + + // 取出变量名 + for (int j = 0; j < ncolumn; j++) + names_.push_back(fields[j].name); + + // 开始取出所有行数据结果,加入动态数组中 + while (true) + { + MYSQL_ROW my_row = __mysql_fetch_row(my_res); + if (my_row == NULL) + break; + db_row* row = NEW db_row(names_); + for (int j = 0; j < ncolumn; j++) + row->push_back(my_row[j]); + rows_.push_back(row); + } + + my_res_ = my_res; + } + + ~db_mysql_rows() + { + __mysql_free_result(my_res_); + } + +private: + MYSQL_RES *my_res_; +}; + +////////////////////////////////////////////////////////////////////////// + +db_mysql::db_mysql(const char* dbaddr, const char* dbname, + const char* dbuser, const char* dbpass, + unsigned long dbflags /* = 0 */, bool auto_commit /* = true */, + int conn_timeout /* = 60 */, int rw_timeout /* = 60 */) +{ + acl_assert(dbaddr && *dbaddr); + acl_assert(dbname && *dbname); + dbaddr_ = acl_mystrdup(dbaddr); + dbname_ = acl_mystrdup(dbname); + + if (dbuser) + dbuser_ = acl_mystrdup(dbuser); + else + dbuser_ = NULL; + + if (dbpass) + dbpass_ = acl_mystrdup(dbpass); + else + dbpass_ = NULL; + + dbflags_ = dbflags; + auto_commit_ = auto_commit; + conn_timeout_ = conn_timeout; + rw_timeout_ = rw_timeout; + +#if defined(ACL_CPP_DLL) || defined(USE_DYNAMIC) + acl_pthread_once(&__mysql_once, __mysql_dll_load); +#endif + conn_ = NULL; +} + +db_mysql::~db_mysql() +{ + acl_myfree(dbaddr_); + acl_myfree(dbname_); + if (dbuser_) + acl_myfree(dbuser_); + if (dbpass_) + acl_myfree(dbpass_); + if (conn_) + __mysql_close(conn_); +} + +unsigned long db_mysql::mysql_libversion() const +{ + return __mysql_libversion(); +} + +const char* db_mysql::mysql_client_info() const +{ + return __mysql_client_info(); +} + +const char* db_mysql::dbtype() const +{ + static const char* type = "mysql"; + return type; +} + +int db_mysql::get_errno() const +{ + if (conn_) + return __mysql_errno(conn_); + else + return -1; +} + +const char* db_mysql::get_error() const +{ + if (conn_) + return __mysql_error(conn_); + else + return "mysql not opened yet!"; +} + +bool db_mysql::open(const char* local_charset /* = GBK */) +{ + if (conn_) + return true; + + char tmpbuf[256]; + char *db_host, *db_unix; + int db_port; + + char* ptr = strchr(dbaddr_, '/'); + if (ptr == NULL) { + ACL_SAFE_STRNCPY(tmpbuf, dbaddr_, sizeof(tmpbuf)); + ptr = strchr(tmpbuf, ':'); + if (ptr == NULL || *(ptr + 1) == 0) + { + logger_error("invalid db_addr=%s", dbaddr_); + return false; + } + else + *ptr++ = 0; + db_host = tmpbuf; + + db_port = atoi(ptr); + if (db_port <= 0) + { + logger_error("invalid port=%d", db_port); + return false; + } + db_unix = NULL; + } else { + db_unix = dbaddr_; + db_host = NULL; + db_port = 0; + } + + conn_ = __mysql_init(NULL); + if (conn_ == NULL) + { + logger_error("mysql init error"); + return false; + } + + if (conn_timeout_ > 0) +#if MYSQL_VERSION_ID >= 50500 + __mysql_options(conn_, MYSQL_OPT_CONNECT_TIMEOUT, + (const void*) &conn_timeout_); +#else + __mysql_options(conn_, MYSQL_OPT_CONNECT_TIMEOUT, + (const char*) &conn_timeout_); +#endif + + if (rw_timeout_ > 0) + { +#if MYSQL_VERSION_ID >= 50500 + __mysql_options(conn_, MYSQL_OPT_READ_TIMEOUT, + (const void*) &rw_timeout_); + __mysql_options(conn_, MYSQL_OPT_WRITE_TIMEOUT, + (const void*) &rw_timeout_); +#else + __mysql_options(conn_, MYSQL_OPT_READ_TIMEOUT, + (const char*) &rw_timeout_); + __mysql_options(conn_, MYSQL_OPT_WRITE_TIMEOUT, + (const char*) &rw_timeout_); +#endif + } + + my_bool reconnect = 1; + +#if MYSQL_VERSION_ID >= 50500 + __mysql_options(conn_, MYSQL_OPT_RECONNECT, (const void*) &reconnect); +#else + __mysql_options(conn_, MYSQL_OPT_RECONNECT, (const char*) &reconnect); +#endif + + if (__mysql_open(conn_, db_host, dbuser_ ? dbuser_ : "", + dbpass_ ? dbpass_ : "", dbname_, db_port, + db_unix, dbflags_) == NULL) + { + logger_error("connect mysql error(%s), db_host=%s, db_port=%d," + " db_unix=%s, db_name=%s, db_user=%s, db_pass=%s", + __mysql_error(conn_), db_host ? db_host : "null", db_port, + db_unix ? db_unix : "null", dbname_, dbuser_, dbpass_); + + __mysql_close(conn_); + conn_ = NULL; + return false; + } + + if (local_charset) + { + if (!__mysql_set_character_set(conn_, local_charset)) + logger_warn("set mysql charset(%s) error(%s)", + local_charset, __mysql_character_set_name(conn_)); + } + +#if MYSQL_VERSION_ID >= 50000 + if (__mysql_autocommit(conn_, auto_commit_ ? 1 : 0) != 0) + { + logger_error("mysql_autocommit error"); + __mysql_close(conn_); + conn_ = NULL; + return (false); + } +#else + auto_commit_ = false; +#endif + + return true; +} + +bool db_mysql::is_opened() const +{ + return conn_ ? true : false; +} + +bool db_mysql::close() +{ + if (conn_ != NULL) + { + __mysql_close(conn_); + conn_ = NULL; + } + return true; +} + +bool db_mysql::sane_mysql_query(const char* sql) +{ + if (conn_ == NULL) + { + logger_error("db(%s) not opened yet!", dbname_); + return false; + } + if (__mysql_query(conn_, sql) == 0) + return true; + + int errnum = __mysql_errno(conn_); + if (errnum != CR_SERVER_LOST && errnum != CR_SERVER_GONE_ERROR) + { + logger_error("db(%s): sql(%s) error(%s)", + dbname_, sql, __mysql_error(conn_)); + return false; + } + + /* 重新打开MYSQL连接进行重试 */ + close(); + if (open("GBK") == false) + { + logger_error("reopen db(%s) error", dbname_); + return false; + } + if (__mysql_query(conn_, sql) == 0) + return true; + logger_error("db(%s), sql(%s) error(%s)", + dbname_, sql, __mysql_error(conn_)); + close(); + return false; +} + +bool db_mysql::tbl_exists(const char* tbl_name) +{ + if (conn_ == NULL) + { + logger_error("db(%s) not opened yet", dbname_); + return false; + } + + char sql[256]; + + snprintf(sql, sizeof(sql), "show tables like '%s'", tbl_name); + if (sane_mysql_query(sql) == false) + return false; + MYSQL_RES *my_res = __mysql_store_result(conn_); + if (my_res == NULL) + { + if (__mysql_errno(conn_) != 0) + { + logger_error("db(%s), sql(%s) error(%s)", + dbname_, sql, __mysql_error(conn_)); + close(); + } + return false; + } + + bool ret; + if (__mysql_num_rows(my_res) > 0) + ret = true; + else + ret = false; + __mysql_free_result(my_res); + return ret; +} + +bool db_mysql::sql_select(const char* sql) +{ + if (sane_mysql_query(sql) == false) + return false; + MYSQL_RES *my_res = __mysql_store_result(conn_); + if (my_res == NULL) + { + if (__mysql_errno(conn_) != 0) + { + logger_error("db(%s), sql(%s) error(%s)", + dbname_, sql, __mysql_error(conn_)); + close(); + } + return false; + } + + my_ulonglong nrow = __mysql_num_rows(my_res); + if (nrow <= 0) + { + __mysql_free_result(my_res); + result_ = NULL; + return true; + } + + result_ = NEW db_mysql_rows(my_res); + return true; +} + +bool db_mysql::sql_update(const char* sql) +{ + if (sane_mysql_query(sql) == false) + return false; + int ret = (int) __mysql_affected_rows(conn_); + if (ret == -1) + return false; + return true; +} + +int db_mysql::affect_count() const +{ + if (!is_opened()) + { + logger_error("mysql not opened yet"); + return -1; + } + + return (int) __mysql_affected_rows(conn_); +} + +} // namespace acl + +#else + +namespace acl +{ + +db_mysql::db_mysql(const char*, const char*, + const char*, const char*, + unsigned long, bool, int, int) +{ + logger_fatal("Please #define HAS_MYSQL first"); +} + +db_mysql::~db_mysql(void) +{ +} + +const char* db_mysql::dbtype() const +{ + return NULL; +} + +bool db_mysql::open(const char*) +{ + return false; +} + +bool db_mysql::is_opened() const +{ + return false; +} + +bool db_mysql::close(void) +{ + return false; +} + +bool db_mysql::tbl_exists(const char*) +{ + return false; +} + +bool db_mysql::sql_select(const char*) +{ + return false; +} + +bool db_mysql::sql_update(const char*) +{ + return false; +} + +int db_mysql::affect_count() const +{ + return 0; +} + +unsigned long db_mysql::mysql_libversion() const +{ + return 0; +} + +const char* db_mysql::mysql_client_info() const +{ + return NULL; +} + +int db_mysql::get_errno() const +{ + return -1; +} + +const char* db_mysql::get_error() const +{ + return "mysql not opened yet!"; +} + +} // namespace acl + +#endif // HAS_MYSQL diff --git a/lib_acl_cpp/src/db/db_pool.cpp b/lib_acl_cpp/src/db/db_pool.cpp new file mode 100644 index 000000000..5d97b5094 --- /dev/null +++ b/lib_acl_cpp/src/db/db_pool.cpp @@ -0,0 +1,190 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/stdlib/locker.hpp" +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/db/db_handle.hpp" +#include "acl_cpp/db/db_sqlite.hpp" +#include "acl_cpp/db/db_pool.hpp" + +namespace acl +{ + +db_pool::db_pool(int dblimit /* = 64 */) +{ + if (dblimit > 0) + dblimit_ = dblimit; + else + dblimit_ = 64; + + ttl_ = -1; + dbcount_ = 0; + id_[0] = 0; + locker_ = NEW locker(true); + last_check_ = 0; + check_inter_ = 30; + set_id(); +} + +db_pool::~db_pool() +{ + std::list::iterator it = pool_.begin(); + for (; it != pool_.end(); ++it) + delete (*it); + pool_.clear(); + delete locker_; +} + +void db_pool::set_id() +{ + struct timeval tv; + + (void) gettimeofday(&tv, NULL); + snprintf(id_, sizeof(id_), "%d.%d.%d", + (int) tv.tv_sec, (int) tv.tv_usec, rand()); +} + +db_pool& db_pool::set_idle(int idle) +{ + ttl_ = idle; + return *this; +} + +db_handle* db_pool::peek() +{ + db_handle* conn; + + locker_->lock(); + + std::list::iterator it = pool_.begin(); + if (it != pool_.end()) + { + conn = *it; + pool_.erase(it); + locker_->unlock(); + conn->set_when(time(NULL)); + return conn; + } + else if (dbcount_ >= dblimit_) + { + logger_error("dbcount(%d) > dblimit(%d)", + dbcount_, dblimit_); + locker_->unlock(); + return NULL; + } + + // 记数器加 1 + dbcount_++; + locker_->unlock(); // 尽量减少锁的锁定时间 + + // 创建 mysql 或 sqlite 连接句柄 + conn = create(); + + static int __id = 0; + snprintf(id_, sizeof(id_), "id: %d", __id++); + conn->set_id(id_); + conn->set_when(time(NULL)); + return conn; +} + +void db_pool::put(db_handle* conn, bool keep /* = true */) +{ + acl_assert(conn); + + const char* id = conn->get_id(); + bool eq; + if (id && strcmp(id, id_) == 0) + eq = true; + else + eq = false; + + time_t now = time(NULL); + + locker_->lock(); + + if (keep) + { + conn->set_when(now); + // 将归还的连接放在链表首部,这样在调用释放过期连接 + // 时比较方便,有利于尽快将不忙的数据库连接关闭 + pool_.push_front(conn); + // 如果该连接句柄不是由本连接池产生的,则需要 + // 重新设置连接句柄的 ID 标识 + if (!eq) + conn->set_id(id_); + } + else + { + // 只有当该连接句柄由本连接池产生时,才需要 + // 减少记数器 + if (eq) + dbcount_--; + delete conn; + } + + if (ttl_ >= 0 && now - last_check_ >= check_inter_) + { + (void) check_idle(ttl_, false); + (void) time(&last_check_); + } + + locker_->unlock(); +} + +int db_pool::check_idle(time_t ttl, bool exclusive /* = true */) +{ + if (ttl < 0) + return 0; + if (exclusive) + locker_->lock(); + if (pool_.empty()) + { + locker_->unlock(); + return 0; + } + + if (ttl == 0) + { + int n = 0; + std::list::iterator it = pool_.begin(); + for (; it != pool_.end(); ++it) + { + delete *it; + n++; + }; + pool_.clear(); + dbcount_ = 0; + locker_->unlock(); + return n; + } + + int n = 0; + time_t now = time(NULL), when; + + std::list::iterator it, next; + std::list::reverse_iterator rit = pool_.rbegin(); + + for (; rit != pool_.rend();) + { + it = --rit.base(); + when = (*it)->get_when(); + if (when <= 0) + { + ++rit; + continue; + } + + if (now - when < ttl) + break; + + delete *it; + next = pool_.erase(it); + rit = std::list::reverse_iterator(next); + + n++; + dbcount_--; + } + + locker_->unlock(); + return n; +} + +} // namespace acl diff --git a/lib_acl_cpp/src/db/db_service.cpp b/lib_acl_cpp/src/db/db_service.cpp new file mode 100644 index 000000000..62708e6cc --- /dev/null +++ b/lib_acl_cpp/src/db/db_service.cpp @@ -0,0 +1,315 @@ +#include "acl_stdafx.hpp" +#include +#include "acl_cpp/stdlib/string.hpp" +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/ipc/ipc_client.hpp" +#include "acl_cpp/db/db_handle.hpp" +#include "acl_cpp/db/db_sqlite.hpp" +#include "acl_cpp/db/db_service.hpp" + +namespace acl +{ + +struct DB_IPC_DAT +{ + db_handle* db; + const db_rows* rows; + int affected_rows; + db_query* query; +}; + +////////////////////////////////////////////////////////////////////////// +// 工作子线程的处理类 + +class db_ipc_request : public ipc_request +{ +public: + db_ipc_request(db_handle* db, const char* sql, db_query* query, bool has_res) + : db_(db) + , sql_(sql) + , query_(query) + , has_res_(has_res) + { + + } + + ~db_ipc_request(void) + { + + } + +protected: + // 基类 ipc_request 会自动调用此回调处理请求过程 + virtual void run(ipc_client* ipc) + { + DB_IPC_DAT data; + + data.db = db_; + data.query = query_; + data.rows = NULL; + data.affected_rows = 0; + + if (db_->open() == false) + ipc->send_message(DB_ERR_OPEN, &data, sizeof(data)); + else if (has_res_) + { + if (db_->sql_select(sql_.c_str()) == false) + ipc->send_message(DB_ERR_EXEC_SQL, &data, sizeof(data)); + else + { + data.rows = db_->get_result(); + ipc->send_message(DB_OK, &data, sizeof(data)); + } + } + else if (db_->sql_update(sql_.c_str()) == false) + ipc->send_message(DB_ERR_EXEC_SQL, &data, sizeof(data)); + else + { + data.rows = db_->get_result(); + // 修改操作,需要取一下 SQL 操作影响的行数 + data.affected_rows = db_->affect_count(); + ipc->send_message(DB_OK, &data, sizeof(data)); + } + // 因为本请求对象是动态创建的,所以需要释放 + delete this; + } + +#ifdef WIN32 + + // 基类虚接口,使子线程可以在执行完任务后向主线程发送 WIN32 窗口消息 + + virtual void run(HWND hWnd) + { + DB_IPC_DAT* data = (DB_IPC_DAT*) acl_mymalloc(sizeof(DB_IPC_DAT)); + + data->db = db_; + data->query = query_; + data->rows = NULL; + data->affected_rows = 0; + + if (db_->open() == false) + ::PostMessage(hWnd, DB_ERR_OPEN + WM_USER, 0, (LPARAM) data); + else if (has_res_) + { + if (db_->sql_select(sql_.c_str()) == false) + ::PostMessage(hWnd, DB_ERR_EXEC_SQL + WM_USER, 0, (LPARAM) data); + { + data->rows = db_->get_result(); + ::PostMessage(hWnd, DB_OK + WM_USER, 0, (LPARAM) data); + } + } else if (db_->sql_update(sql_.c_str()) == false) + ::PostMessage(hWnd, DB_ERR_EXEC_SQL + WM_USER, 0, (LPARAM) data); + else + { + data->rows = db_->get_result(); + // 修改操作,需要取一下 SQL 操作影响的行数 + data->affected_rows = db_->affect_count(); + ::PostMessage(hWnd, DB_OK + WM_USER, 0, (LPARAM) data); + //::SendMessage(hWnd, DB_OK + WM_USER, 0, (LPARAM) data); + } + // 因为本请求对象是动态创建的,所以需要释放 + delete this; + } +#endif +private: + db_handle* db_; + acl::string sql_; + db_query* query_; + bool has_res_; +}; + +////////////////////////////////////////////////////////////////////////// +// 服务线程与子线程池之间的 IPC 通道类定义 + +class db_ipc : public ipc_client +{ +public: + db_ipc(db_service* dbs) : dbservice_(dbs) + { + + } + + ~db_ipc(void) + { + + } + + virtual void on_message(int nMsg, void* data, int dlen acl_unused) + { + DB_IPC_DAT* dat = (DB_IPC_DAT*) data; + db_query* query = dat->query; + + switch (nMsg) + { + case DB_OK: + query->on_ok(dat->rows, dat->affected_rows); + break; + case DB_ERR_OPEN: + query->on_error(DB_ERR_OPEN); + break; + case DB_ERR_EXEC_SQL: + query->on_error(DB_ERR_EXEC_SQL); + break; + default: + break; + } + + dat->db->free_result(); + dbservice_->push_back(dat->db); + query->destroy(); + } +protected: + virtual void on_close(void) + { + delete this; + } +private: + db_service* dbservice_; +}; + +////////////////////////////////////////////////////////////////////////// + +db_service::db_service(size_t dblimit /* = 100 */, int nthread /* = 2 */, + bool win32_gui /* = false */) +: ipc_service(nthread, win32_gui) +, dbsize_(0) +{ + // 当采用线程池方式,则数据库连接池的最大值不应超过线程数 + if (nthread > 1) + dblimit_ = (int) dblimit > nthread ? nthread : dblimit; + else + dblimit_ = dblimit; +} + +db_service::~db_service(void) +{ + std::list::iterator it = dbpool_.begin(); + for (; it != dbpool_.end(); ++it) + { + delete (*it); + } +} + +void db_service::on_accept(acl::aio_socket_stream* client) +{ + ACL_SOCKET fd = client->get_socket(); + // 在此处设置服务端接收到的套接口的 SO_LINGER 选项, + // 以保证在套接口关闭后其资源能得到立刻释放,虽然一般 + // 而言设置此选项会有危害,但考虑到服务端只有接收到 + // 完整的客户端数据后才会调用关闭操作,所以应该不会 + // 造成数据发送不全的问题,切记,不应在客户端的关闭 + // 操作中设置 SO_LINGER 选项,以防数据未完整发送 + // 在服务端设置接收连接的 SO_LINGER 选项,有助于操作 + // 系统快速回收套接口资源 + acl_tcp_so_linger(fd, 1, 0); + + ipc_client* ipc = NEW db_ipc(this); + ipc->open(client); + + // 添加服务线程的消息处理 + + ipc->append_message(DB_OK); + ipc->append_message(DB_ERR_OPEN); + ipc->append_message(DB_ERR_EXEC_SQL); + + // 异步等待消息 + ipc->wait(); +} + +#ifdef WIN32 + +void db_service::win32_proc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + DB_IPC_DAT* dat = NULL; + db_query* query = NULL; + + switch (msg - WM_USER) + { + case DB_OK: + dat = (DB_IPC_DAT*) lParam; + query = dat->query; + query->on_ok(dat->rows, dat->affected_rows); + break; + case DB_ERR_OPEN: + dat = (DB_IPC_DAT*) lParam; + query = dat->query; + query->on_error(DB_ERR_OPEN); + break; + case DB_ERR_EXEC_SQL: + dat = (DB_IPC_DAT*) lParam; + query = dat->query; + query->on_error(DB_ERR_EXEC_SQL); + break; + default: + break; + } + + if (dat) + { + dat->db->free_result(); + push_back(dat->db); + query->destroy(); + + // 在采用 WIN32 消息时该对象空间是动态分配的,所以需要释放 + acl_myfree(dat); + } +} + +#endif + +void db_service::sql_select(const char* sql, db_query* query) +{ + assert(sql && *sql); + + db_handle* db; + + std::list::iterator it = dbpool_.begin(); + if (it == dbpool_.end()) + db = db_create(); + else + { + db = *it; + dbpool_.erase(it); + } + + // 创建子线程的请求对象 + db_ipc_request* ipc_req = NEW db_ipc_request(db, sql, query, true); + + // 调用基类 ipc_service 请求过程 + request(ipc_req); +} + +void db_service::sql_update(const char* sql, db_query* query) +{ + assert(sql && *sql); + + db_handle* db; + + std::list::iterator it = dbpool_.begin(); + if (it == dbpool_.end()) + db = db_create(); + else + { + db = *it; + dbpool_.erase(it); + } + + // 创建子线程的请求对象 + db_ipc_request* ipc_req = NEW db_ipc_request(db, sql, query, false); + + // 调用基类 ipc_service 请求过程 + request(ipc_req); +} + +void db_service::push_back(db_handle* db) +{ + if (dbsize_ >= dblimit_) + delete db; + else + { + dbsize_++; + dbpool_.push_back(db); + } +} + +} // namespace acl diff --git a/lib_acl_cpp/src/db/db_service_mysql.cpp b/lib_acl_cpp/src/db/db_service_mysql.cpp new file mode 100644 index 000000000..a77ee86a7 --- /dev/null +++ b/lib_acl_cpp/src/db/db_service_mysql.cpp @@ -0,0 +1,38 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/db/db_mysql.hpp" +#include "acl_cpp/db/db_service_mysql.hpp" + +namespace acl +{ + +db_service_mysql::db_service_mysql(const char* dbaddr, const char* dbname, + const char* dbuser, const char* dbpass, unsigned long dbflags /* = 0 */, + bool auto_commit /* = true */, int conn_timeout /* = 60 */, + int rw_timeout /* = 60 */, size_t dblimit /* = 100 */, + int nthread /* = 2 */, bool win32_gui /* = false */) +: db_service(dblimit, nthread, win32_gui) +, dbaddr_(dbaddr) +, dbname_(dbname) +, dbuser_(dbuser) +, dbpass_(dbpass) +, dbflags_(dbflags) +, auto_commit_(auto_commit) +, conn_timeout_(conn_timeout) +, rw_timeout_(rw_timeout) +{ + +} + +db_service_mysql::~db_service_mysql(void) +{ + +} + +db_handle* db_service_mysql::db_create(void) +{ + db_handle* db = NEW db_mysql(dbaddr_, dbname_, dbuser_, dbpass_, + dbflags_, auto_commit_, conn_timeout_, rw_timeout_); + return db; +} + +} diff --git a/lib_acl_cpp/src/db/db_service_sqlite.cpp b/lib_acl_cpp/src/db/db_service_sqlite.cpp new file mode 100644 index 000000000..342d9bc0e --- /dev/null +++ b/lib_acl_cpp/src/db/db_service_sqlite.cpp @@ -0,0 +1,30 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/db/db_sqlite.hpp" +#include "acl_cpp/db/db_service_sqlite.hpp" + +namespace acl +{ + +db_service_sqlite::db_service_sqlite(const char* dbname, const char* dbfile, + size_t dblimit /* = 100 */, int nthread /* = 2 */, + bool win32_gui /* = false */) +: db_service(dblimit, nthread, win32_gui) +, dbname_(dbname) +, dbfile_(dbfile) +{ + +} + +db_service_sqlite::~db_service_sqlite(void) +{ + +} + +db_handle* db_service_sqlite::db_create(void) +{ + db_handle* db = NEW db_sqlite(dbfile_.c_str()); + + return db; +} + +} // namespace acl diff --git a/lib_acl_cpp/src/db/db_sqlite.cpp b/lib_acl_cpp/src/db/db_sqlite.cpp new file mode 100644 index 000000000..9d6e67aa7 --- /dev/null +++ b/lib_acl_cpp/src/db/db_sqlite.cpp @@ -0,0 +1,516 @@ +#include "acl_stdafx.hpp" +#include "sqlite3.h" +#include "acl_cpp/stdlib/charset_conv.hpp" +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/db/db_sqlite.hpp" + +#ifdef HAS_SQLITE + +#if defined(WIN32) || defined(USE_DYNAMIC) + typedef char* (*sqlite3_libversion_fn)(void); + typedef int (*sqlite3_open_fn)(const char*, sqlite3**); + typedef int (*sqlite3_close_fn)(sqlite3*); + typedef int (*sqlite3_get_table_fn)(sqlite3*, const char*, char***, int*, int*, char**); + typedef void (*sqlite3_free_table_fn)(char**); + typedef int (*sqlite3_busy_handler_fn)(sqlite3*, int(*)(void*,int), void*); + typedef const char* (*sqlite3_errmsg_fn)(sqlite3*); + typedef int (*sqlite3_errcode_fn)(sqlite3*); + typedef int (*sqlite3_changes_fn)(sqlite3*); + typedef int (*sqlite3_total_changes_fn)(sqlite3*); + + static sqlite3_libversion_fn __sqlite3_libversion = NULL; + static sqlite3_open_fn __sqlite3_open = NULL; + static sqlite3_close_fn __sqlite3_close = NULL; + static sqlite3_get_table_fn __sqlite3_get_table = NULL; + static sqlite3_free_table_fn __sqlite3_free_table = NULL; + static sqlite3_busy_handler_fn __sqlite3_busy_handler = NULL; + static sqlite3_errmsg_fn __sqlite3_errmsg = NULL; + static sqlite3_errcode_fn __sqlite3_errcode = NULL; + static sqlite3_changes_fn __sqlite3_changes = NULL; + static sqlite3_total_changes_fn __sqlite3_total_changes = NULL; + + static acl_pthread_once_t __sqlite_once = ACL_PTHREAD_ONCE_INIT; + static ACL_DLL_HANDLE __sqlite_dll = NULL; + + // 程序退出释放动态加载的库 + static void __sqlite_dll_unload(void) + { + if (__sqlite_dll != NULL) + { + acl_dlclose(__sqlite_dll); + __sqlite_dll = NULL; + logger("sqlite3.dll unload ok"); + } + } + + // 动态加载 sqlite3.dll 库 + static void __sqlite_dll_load(void) + { + if (__sqlite_dll != NULL) + logger_fatal("__sqlite_dll not null"); + + __sqlite_dll = acl_dlopen("sqlite3.dll"); + if (__sqlite_dll == NULL) + logger_fatal("load sqlite3.dll error: %s", acl_last_serror()); + + __sqlite3_libversion = (sqlite3_libversion_fn) + acl_dlsym(__sqlite_dll, "sqlite3_libversion"); + if (__sqlite3_libversion == NULL) + logger_fatal("load sqlite3_libversion from sqlite3.dll error: %s", + acl_last_serror()); + + __sqlite3_open = (sqlite3_open_fn) + acl_dlsym(__sqlite_dll, "sqlite3_open"); + if (__sqlite3_open == NULL) + logger_fatal("load sqlite3_open from sqlite3.dll error: %s", + acl_last_serror()); + + __sqlite3_close = (sqlite3_close_fn) + acl_dlsym(__sqlite_dll, "sqlite3_close"); + if (__sqlite3_close == NULL) + logger_fatal("load sqlite3_close from sqlite3.dll error: %s", + acl_last_serror()); + + __sqlite3_get_table = (sqlite3_get_table_fn) + acl_dlsym(__sqlite_dll, "sqlite3_get_table"); + if (__sqlite3_get_table == NULL) + logger_fatal("load sqlite3_get_table from sqlite3.dll error: %s", + acl_last_serror()); + + __sqlite3_free_table = (sqlite3_free_table_fn) + acl_dlsym(__sqlite_dll, "sqlite3_free_table"); + if (__sqlite3_free_table == NULL) + logger_fatal("load sqlite3_free_table from sqlite3.dll error: %s", + acl_last_serror()); + + __sqlite3_busy_handler = (sqlite3_busy_handler_fn) + acl_dlsym(__sqlite_dll, "sqlite3_busy_handler"); + if (__sqlite3_busy_handler == NULL) + logger_fatal("load sqlite3_busy_handler from sqlite3.dll error: %s", + acl_last_serror()); + + __sqlite3_errmsg = (sqlite3_errmsg_fn) + acl_dlsym(__sqlite_dll, "sqlite3_errmsg"); + if (__sqlite3_errmsg == NULL) + logger_fatal("load sqlite3_errmsg from sqlite3.dll error: %s", + acl_last_serror()); + + __sqlite3_errcode = (sqlite3_errcode_fn) + acl_dlsym(__sqlite_dll, "sqlite3_errcode"); + if (__sqlite3_errcode == NULL) + logger_fatal("load sqlite3_errcode from sqlite3.dll error: %s", + acl_last_serror()); + + __sqlite3_changes = (sqlite3_changes_fn) + acl_dlsym(__sqlite_dll, "sqlite3_changes"); + if (__sqlite3_changes == NULL) + logger_fatal("load sqlite3_changes from sqlite3.dll error: %s", + acl_last_serror()); + + __sqlite3_total_changes = (sqlite3_total_changes_fn) + acl_dlsym(__sqlite_dll, "sqlite3_total_changes"); + if (__sqlite3_total_changes == NULL) + logger_fatal("load sqlite3_total_changes from sqlite3.dll error: %s", + acl_last_serror()); + + logger("sqlite3.dll loaded"); + atexit(__sqlite_dll_unload); + } +#else +# define __sqlite3_libversion sqlite3_libversion +# define __sqlite3_open sqlite3_open +# define __sqlite3_close sqlite3_close +# define __sqlite3_get_table sqlite3_get_table +# define __sqlite3_free_table sqlite3_free_table +# define __sqlite3_busy_handler sqlite3_busy_handler +# define __sqlite3_errmsg sqlite3_errmsg +# define __sqlite3_errcode sqlite3_errcode +# define __sqlite3_changes sqlite3_changes +# define __sqlite3_total_changes sqlite3_total_changes +#endif + +namespace acl +{ + +////////////////////////////////////////////////////////////////////////// +// sqlite 的记录行类型定义 + +class db_sqlite_rows : public db_rows +{ +public: + db_sqlite_rows(char** results, int nrow, int ncolumn) + { + results_ = results; + + int n = 0; + + // 取出变量名 + for (int j = 0; j < ncolumn; j++) + { + names_.push_back(results[j]); + n++; + } + + // 开始取出所有行数据结果,加入动态数组中 + for (int i = 0; i < nrow; i++) + { + db_row* row = NEW db_row(names_); + for (int j = 0; j < ncolumn; j++) + { + row->push_back(results[n]); + n++; + } + rows_.push_back(row); + } + } + + ~db_sqlite_rows() + { + if (results_) + __sqlite3_free_table(results_); + } + +private: + char** results_; +}; + +////////////////////////////////////////////////////////////////////////// + +db_sqlite::db_sqlite(const char* dbfile) +: db_(NULL) +, dbfile_(dbfile) +, conv_(NULL) +{ + acl_assert(dbfile && *dbfile); +#if defined(WIN32) || defined(USE_DYNAMIC) + acl_pthread_once(&__sqlite_once, __sqlite_dll_load); +#endif +} + +db_sqlite::~db_sqlite(void) +{ + close(); + if (conv_) + delete conv_; +} + +const char* db_sqlite::version() const +{ + return (__sqlite3_libversion()); +} + +static int sqlite_busy_callback(void *ctx acl_unused, int nretry acl_unused) +{ + acl_doze(10); + return (1); +} + +const char* db_sqlite::dbtype() const +{ + static const char* type = "sqlite"; + return type; +} + +int db_sqlite::get_errno() const +{ + if (db_) + return __sqlite3_errcode(db_); + else + return -1; +} + +const char* db_sqlite::get_error() const +{ + if (db_) + return __sqlite3_errmsg(db_); + else + return "mysql not opened yet!"; +} +bool db_sqlite::open(const char* local_charset /* = "GBK" */) +{ + // 如果数据库已经打开,则直接返回 true + if (db_ != NULL) + return (true); + + string buf; + + if (local_charset && strcasecmp(local_charset, "UTF-8")) + { + local_charset_ = local_charset; + conv_ = NEW charset_conv(); + } + + const char* ptr; + + // 转换成 [UTF-8] 编码格式 + + if (conv_ == NULL) + ptr = dbfile_.c_str(); + else if (conv_->convert(local_charset_.c_str(), "UTF-8", + dbfile_.c_str(), dbfile_.length(), &buf) == false) + { + logger_error("charset convert(%s) from %s to UTF-8 error", + dbfile_.c_str(), local_charset_.c_str()); + return (false); + } + else + ptr = buf.c_str(); + + // 打开 sqlite 数据库 + int ret = __sqlite3_open(ptr, &db_); + if (ret != SQLITE_OK) + { + logger_error("open %s error(%s, %d)", dbfile_.c_str(), + __sqlite3_errmsg(db_), __sqlite3_errcode(db_)); + __sqlite3_close(db_); + db_ = NULL; + + return (false); + } + + // 当 SQLITE 忙时的回调函数 + __sqlite3_busy_handler(db_, sqlite_busy_callback, NULL); + + // 关闭 SQLITE 实时刷新磁盘的特性,从而提高性能 + set_conf("PRAGMA synchronous = off"); + return (true); +} + +bool db_sqlite::is_opened() const +{ + return (db_ != NULL ? true : false); +} + +bool db_sqlite::close() +{ + if (db_ == NULL) + return (false); + + // 关闭 sqlite 数据库 + int ret = __sqlite3_close(db_); + if (ret == SQLITE_BUSY) + { + logger_error("close %s error SQLITE_BUSY", dbfile_.c_str()); + return (false); + } + + db_ = NULL; + return (true); +} + +bool db_sqlite::set_conf(const char* pragma) +{ + bool ret = exec_sql(pragma); + if (result_) + free_result(); + return (ret); +} + +const char* db_sqlite::get_conf(const char* pragma, string& out) +{ + bool ret = exec_sql(pragma); + if (ret == false) + return (NULL); + else if (length() == 0) + { + free_result(); + return (NULL); + } + else + { + const db_row* row = (*this)[(size_t) 0]; + acl_assert(row != NULL); + const char* ptr = (*row)[(size_t) 0]; + if (ptr == NULL) + { + free_result(); + return (NULL); + } + out = ptr; + free_result(); + return (out.c_str()); + } +} + +// sqlite 的一些配置选项 +const char* __pragmas[] = +{ + "PRAGMA auto_vacuum", + "PRAGMA cache_size", + "PRAGMA case_sensitive_like", + "PRAGMA count_changes", + "PRAGMA default_cache_size", + "PRAGMA default_synchronous", + "PRAGMA empty_result_callbacks", + "PRAGMA encoding", + "PRAGMA full_column_names", + "PRAGMA fullfsync", + "PRAGMA legacy_file_format", + "PRAGMA locking_mode", + "PRAGMA page_size", + "PRAGMA max_page_count", + "PRAGMA read_uncommitted", + "PRAGMA short_column_names", + "PRAGMA synchronous", + "PRAGMA temp_store", + "PRAGMA temp_store_directory", + NULL +}; + +void db_sqlite::show_conf(const char* pragma /* = NULL */) +{ + if (db_ == NULL) + { + logger_error("db not open yet!"); + return; + } + + string buf; + + if (pragma != NULL) + { + if (get_conf(pragma, buf) != NULL) + printf("%s: %s\r\n", pragma, buf.c_str()); + else + printf("%s: UNKNOWN\r\n", pragma); + return; + } + + int i; + for (i = 0; __pragmas[i] != NULL; i++) + { + if (get_conf(__pragmas[i], buf) != NULL) + printf("%s: %s\r\n", __pragmas[i], buf.c_str()); + else + printf("%s: UNKNOWN\r\n", __pragmas[i]); + } +} + +bool db_sqlite::tbl_exists(const char* tbl_name) +{ + if (tbl_name == NULL || *tbl_name == 0) + { + logger_error("tbl_name null"); + return (false); + } + + acl::string sql; + sql.format("select count(*) from sqlite_master" + " where type='table' and name='%s'", tbl_name); + + if (exec_sql(sql.c_str()) == false) + { + free_result(); + return (false); + } + + if (length() == 0) + { + free_result(); + return (false); + } + else + { + const db_row* row = (*this)[0]; + acl_assert(row != NULL); + + int n = row->field_int((size_t) 0, (int) 0); + free_result(); + + if (n == 0) + return (false); + return (true); + } +} + +bool db_sqlite::sql_select(const char* sql) +{ + return (exec_sql(sql)); +} + +bool db_sqlite::sql_update(const char* sql) +{ + return (exec_sql(sql)); +} + +bool db_sqlite::exec_sql(const char* sql) +{ + // 必须将上次的查询结果删除 + if (result_) + { + logger_warn("You forgot free result of last query"); + free_result(); + } + + if (sql == NULL || *sql == 0) + { + logger_error("invalid params"); + return (false); + } + else if (db_ == NULL) + { + logger_error("db not open yet!"); + return (false); + } + + char** results = NULL, *err; + int nrow, ncolumn; + + // 执行 sqlite 的查询过程 + int ret = __sqlite3_get_table(db_, sql, &results, + &nrow, &ncolumn, &err); + if (ret != SQLITE_OK) + { + logger_error("sqlites_get_table(%s) error(%s)", + sql, __sqlite3_errmsg(db_)); + __sqlite3_free_table(results); + return (false); + } + + if (nrow > 0) + result_ = NEW db_sqlite_rows(results, nrow, ncolumn); + else if (results) + { + result_ = NULL; + __sqlite3_free_table(results); + } + return (true); +} + +int db_sqlite::affect_count() const +{ + if (db_ == NULL) + { + logger_error("db not opened yet!"); + return (-1); + } + + return (__sqlite3_changes(db_)); +} + +int db_sqlite::affect_total_count() const +{ + return (__sqlite3_total_changes(db_)); +} + +} // namespace acl + +#else + +namespace acl +{ + +db_sqlite::db_sqlite(const char*) {} +db_sqlite::~db_sqlite(void) {} +const char* db_sqlite::dbtype() const { return NULL; } +bool db_sqlite::open(const char*) { return false; } +bool db_sqlite::is_opened() const { return false; } +bool db_sqlite::close(void) { return false; } +bool db_sqlite::tbl_exists(const char*) { return false; } +bool db_sqlite::sql_select(const char*) { return false; } +bool db_sqlite::sql_update(const char*) { return false; } +int db_sqlite::affect_count() const { return 0; } + +} // namespace acl + +#endif // HAS_SQLITE diff --git a/lib_acl_cpp/src/db/mysql_pool.cpp b/lib_acl_cpp/src/db/mysql_pool.cpp new file mode 100644 index 000000000..7137275ba --- /dev/null +++ b/lib_acl_cpp/src/db/mysql_pool.cpp @@ -0,0 +1,54 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/db/db_handle.hpp" +#include "acl_cpp/db/db_mysql.hpp" +#include "acl_cpp/db/mysql_pool.hpp" + +namespace acl +{ + +mysql_pool::mysql_pool(const char* dbaddr, const char* dbname, + const char* dbuser, const char* dbpass, int dblimit /* = 64 */, + unsigned long dbflags /* = 0 */, bool auto_commit /* = true */, + int conn_timeout /* = 60 */, int rw_timeout /* = 60 */) +: db_pool(dblimit) +{ + acl_assert(dbaddr && *dbaddr); + acl_assert(dbname && *dbname); + dbaddr_ = acl_mystrdup(dbaddr); + dbname_ = acl_mystrdup(dbname); + if (dbuser) + dbuser_ = acl_mystrdup(dbuser); + else + dbuser_ = NULL; + + if (dbpass) + dbpass_ = acl_mystrdup(dbpass); + else + dbpass_ = NULL; + + dbflags_ = dbflags; + auto_commit_ = auto_commit; + conn_timeout_ = conn_timeout; + rw_timeout_ = rw_timeout; +} + +mysql_pool::~mysql_pool() +{ + if (dbaddr_) + acl_myfree(dbaddr_); + if (dbname_) + acl_myfree(dbname_); + if (dbuser_) + acl_myfree(dbuser_); + if (dbpass_) + acl_myfree(dbpass_); +} + +db_handle* mysql_pool::create() +{ + return NEW db_mysql(dbaddr_, dbname_, dbuser_, + dbpass_, dbflags_, auto_commit_, + conn_timeout_, rw_timeout_); +} + +} // namespace acl diff --git a/lib_acl_cpp/src/db/sqlite_pool.cpp b/lib_acl_cpp/src/db/sqlite_pool.cpp new file mode 100644 index 000000000..9578ea2cb --- /dev/null +++ b/lib_acl_cpp/src/db/sqlite_pool.cpp @@ -0,0 +1,27 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/db/db_handle.hpp" +#include "acl_cpp/db/db_sqlite.hpp" +#include "acl_cpp/db/sqlite_pool.hpp" + +namespace acl +{ + +sqlite_pool::sqlite_pool(const char* dbfile, int dblimit /* = 64 */) +: db_pool(dblimit) +{ + acl_assert(dbfile && *dbfile); + dbfile_ = acl_mystrdup(dbfile); +} + +sqlite_pool::~sqlite_pool() +{ + if (dbfile_) + acl_myfree(dbfile_); +} + +db_handle* sqlite_pool::create() +{ + return NEW db_sqlite(dbfile_); +} + +} // namespace acl diff --git a/lib_acl_cpp/src/hsocket/hsclient.cpp b/lib_acl_cpp/src/hsocket/hsclient.cpp new file mode 100644 index 000000000..0f169fea7 --- /dev/null +++ b/lib_acl_cpp/src/hsocket/hsclient.cpp @@ -0,0 +1,508 @@ +#include "acl_stdafx.hpp" +#include +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/stdlib/string.hpp" +#include "acl_cpp/stdlib/escape.hpp" +#include "acl_cpp/hsocket/hsrow.hpp" +#include "acl_cpp/hsocket/hstable.hpp" +#include "acl_cpp/hsocket/hsproto.hpp" +#include "acl_cpp/hsocket/hserror.hpp" +#include "acl_cpp/hsocket/hsclient.hpp" + +namespace acl +{ + +#define MAX_INT 2147483647 + +static const char* dummy_ok = "ok"; +static const char* dummy_unknown = "uknown error"; + +hsclient::hsclient(const char* addr, bool cache_enable /* = true */, + bool retry_enable /* = true */) +: debugOn_(false) +, proto_(cache_enable) +, retry_enable_(retry_enable) +, id_max_(0) +, tbl_curr_(NULL) +, error_(HS_ERR_OK) +{ + addr_ = acl_mystrdup(addr); + serror_ = dummy_ok; +} + +hsclient::~hsclient() +{ + acl_myfree(addr_); + clear_tables(); +} + +bool hsclient::open_tbl(const char* dbn, const char* tbl, + const char* idx, const char* flds, bool auto_open /* = true */) +{ + string key(dbn); + + key << '|' << tbl << '|' << idx << '|' << flds; + key.lower(); + + if (stream_.opened()) + { + std::map::iterator it = tables_.find(key); + if (it != tables_.end()) + { + tbl_curr_ = it->second; + return (true); + } + } + + if (!auto_open) + { + error_ = HS_ERR_NOT_OPEN; + tbl_curr_ = NULL; + return (false); + } + return (open_tbl(dbn, tbl, idx, flds, key.c_str())); +} + + +bool hsclient::open_tbl(const char* dbn, const char* tbl, + const char* idx, const char* flds, const char* key) +{ + if (!stream_.opened()) + { + clear_tables(); + + if (stream_.open(addr_, 60, 60) == false) + { + error_ = HS_ERR_CONN; + tbl_curr_ = NULL; + logger_error("open %s error(%s)", + addr_, acl_last_serror()); + return (false); + } + } + + tbl_curr_ = NEW hstable(id_max_++, dbn, tbl, idx, flds); + + cond_def_[0] = '='; + cond_def_[1] = 0; + + buf_.clear(); + buf_ << "P\t" << tbl_curr_->id_ << '\t' << dbn << '\t' << tbl + << '\t' << idx << '\t' << flds << '\n'; + + if (stream_.write(buf_) == false) + { + error_ = HS_ERR_WRITE; + close_stream(); + delete tbl_curr_; + tbl_curr_ = NULL; + logger_error("send(%s) to %s error", buf_.c_str(), addr_); + return (false); + } + + buf_.clear(); + if (stream_.gets(buf_) == false) + { + error_ = HS_ERR_READ; + close_stream(); + delete tbl_curr_; + tbl_curr_ = NULL; + logger_error("open error for read from %s", addr_); + return (false); + } + + bool ret = proto_.parse_respond(tbl_curr_->nfld_, buf_, error_, serror_); + if (ret) + tables_[key] = tbl_curr_; + else + { + delete tbl_curr_; + tbl_curr_ = NULL; + } + return (ret); +} + +void hsclient::clear_tables() +{ + std::map::iterator it = tables_.begin(); + for (; it != tables_.end(); ++it) + delete it->second; + tables_.clear(); +} + +void hsclient::close_stream() +{ + // 关闭流连接,但并不释放流对象 + stream_.close(); + + // 必须清除与该流对象相关的已经打开的表对象 + clear_tables(); +} + +const std::vector& hsclient::get(const char* values[], int num, + const char* cond /* = "=" */, int nlimit /* = 0 */, + int noffset /* = 0 */) +{ + proto_.reset(); + + if (tbl_curr_ == NULL) + { + error_ = HS_ERR_NOT_OPEN; + logger_error("tbl not opened yet!"); + return (proto_.get()); + } + else if (values == NULL || values[0] == NULL) + { + error_ = HS_ERR_PARAMS; + logger_error("values null"); + return (proto_.get()); + } + else if (num <= 0 || num > tbl_curr_->nfld_) + { + error_ = HS_ERR_PARAMS; + logger_error("num(%d) invalid, nfld(%d)", + num, tbl_curr_->nfld_); + return (proto_.get()); + } + else if (cond == NULL || *cond == 0) + { + error_ = HS_ERR_PARAMS; + logger_error("cond null"); + return (proto_.get()); + } + + if (nlimit <= 0) + nlimit = MAX_INT; + if (noffset < 0) + noffset = 0; + char buf[32], *limit_offset = NULL; + if (nlimit > 1) + { + snprintf(buf, sizeof(buf), "%d\t%d", nlimit, noffset); + limit_offset = buf; + } + + (void) query(cond, values, num, limit_offset, (char) 0, 0, 0); + return (proto_.get()); +} + +const std::vector& hsclient::get(const char* first_value, ...) +{ + if (tbl_curr_ == NULL) + { + error_ = HS_ERR_NOT_OPEN; + logger_error("tbl not opened yet!"); + proto_.reset(); + return (proto_.get()); + } + + va_list ap; + char *ptr; + + va_start(ap, first_value); + + tbl_curr_->values_[0] = (char*) first_value; + int i = 1; + while ((ptr = va_arg(ap, char*)) != NULL) + { + if (i >= tbl_curr_->nfld_) + break; + tbl_curr_->values_[i] = ptr; + i++; + } + va_end(ap); + + return (get((const char**) tbl_curr_->values_, i, cond_def_, 0, 0)); +} + +bool hsclient::mod(const char* values[], int num, + const char* to_values[], int to_num, const char* cond /* = "=" */, + int nlimit /* = 0 */, int noffset /* = 0 */) +{ + if (tbl_curr_ == NULL) + { + error_ = HS_ERR_NOT_OPEN; + logger_error("tbl not opened yet!"); + return (false); + } + else if (values == NULL || values[0] == NULL) + { + error_ = HS_ERR_PARAMS; + logger_error("values null"); + return (false); + } + else if (num <= 0 || num > tbl_curr_->nfld_) + { + error_ = HS_ERR_PARAMS; + logger_error("num(%d) invalid, nfld(%d)", + num, tbl_curr_->nfld_); + return (false); + } + else if (cond == NULL || *cond == 0) + { + error_ = HS_ERR_PARAMS; + logger_error("cond null"); + return (false); + } + else if (to_values == NULL || to_values[0] == NULL) + { + error_ = HS_ERR_PARAMS; + logger_error("to_values null"); + return (false); + } + else if (to_num <= 0 || to_num > tbl_curr_->nfld_) + { + error_ = HS_ERR_PARAMS; + logger_error("to_num(%d) invalid, nfld(%d)", + to_num, tbl_curr_->nfld_); + return (false); + } + + if (nlimit <= 0) + nlimit = MAX_INT; + if (noffset < 0) + noffset = 0; + char buf[32]; + snprintf(buf, sizeof(buf), "%d\t%d", nlimit, noffset); + return (query(cond, values, num, buf, 'U', to_values, to_num)); +} + +bool hsclient::del(const char* values[], int num, + const char* cond /* = "=" */, int nlimit /* = 1 */, int noffset /* = 0 */) +{ + if (tbl_curr_ == NULL) + { + error_ = HS_ERR_NOT_OPEN; + logger_error("tbl not opened yet!"); + return (false); + } + else if (values == NULL || values[0] == NULL) + { + error_ = HS_ERR_PARAMS; + logger_error("values null"); + return (false); + } + else if (num <= 0 || num > tbl_curr_->nfld_) + { + error_ = HS_ERR_PARAMS; + logger_error("num(%d) invalid, nfld(%d)", + num, tbl_curr_->nfld_); + return (false); + } + else if (cond == NULL || *cond == 0) + { + error_ = HS_ERR_PARAMS; + logger_error("cond null"); + return (false); + } + + if (nlimit <= 0) + nlimit = 1; + if (noffset < 0) + noffset = 0; + char buf[32], *limit_offset = NULL; + if (nlimit > 1) + { + snprintf(buf, sizeof(buf), "%d\t%d", nlimit, noffset); + limit_offset = buf; + } + + return (query(cond, values, num, limit_offset, 'D', 0, 0)); +} + +bool hsclient::fmt_del(const char* first_value, ...) +{ + if (tbl_curr_ == NULL) + { + error_ = HS_ERR_NOT_OPEN; + logger_error("tbl not opened yet!"); + return (false); + } + + va_list ap; + char *ptr; + + va_start(ap, first_value); + + tbl_curr_->values_[0] = NULL; + int i = 0; + while ((ptr = va_arg(ap, char*)) != NULL) + { + if (i >= tbl_curr_->nfld_) + break; + tbl_curr_->values_[i] = ptr; + i++; + } + va_end(ap); + + return (del((const char**) tbl_curr_->values_, i, cond_def_, 0, 0)); +} + +bool hsclient::add(const char* values[], int num) +{ + if (tbl_curr_ == NULL) + { + error_ = HS_ERR_NOT_OPEN; + logger_error("tbl not opened yet!"); + return (false); + } + else if (values == NULL || values[0] == NULL) + { + error_ = HS_ERR_PARAMS; + logger_error("input invalid"); + return (false); + } + else if (num <= 0 || num > tbl_curr_->nfld_) + { + error_ = HS_ERR_PARAMS; + logger_error("num(%d) invalid, nfld(%d)", + num, tbl_curr_->nfld_); + return (false); + } + + return (query("+", values, num, NULL, 0, NULL, 0)); +} + +bool hsclient::fmt_add(const char* first_value, ...) +{ + if (tbl_curr_ == NULL) + { + error_ = HS_ERR_NOT_OPEN; + logger_error("tbl not opened yet!"); + return (false); + } + + va_list ap; + char *ptr; + + va_start(ap, first_value); + + tbl_curr_->values_[0] = NULL; + int i = 0; + while ((ptr = va_arg(ap, char*)) != NULL) + { + if (i >= tbl_curr_->nfld_) + break; + tbl_curr_->values_[i] = ptr; + i++; + } + va_end(ap); + + return (add((const char**) tbl_curr_->values_, i)); +} + +bool hsclient::query(const char* oper, const char* values[], int num, + const char* limit_offset, char mop, + const char* to_values[], int to_num) +{ + acl_assert(tbl_curr_); + + bool retried = false; + + while (true) + { + // 创建请求数据 + hsproto::build_request(buf_, tbl_curr_->id_, oper, values, + num, limit_offset, mop, to_values, to_num); + + if (debugOn_) + printf("%s(%d)>>>send: (%s)\n", + __FUNCTION__, __LINE__, buf_.c_str()); + + // 与数据库通信并从数据库获得结果 + if (chat() == true) + break; + + // 如果与数据库通信失败当允许重试时若重试也失败则返回错误 + if (retry_enable_ == false || retried) + { + close_stream(); + return (false); + } + + retried = true; + + // 先缓冲当前表结构中的信息 + string dbn(tbl_curr_->dbn_), tbl(tbl_curr_->tbl_); + string idx(tbl_curr_->idx_), flds(tbl_curr_->flds_); + + // 先关闭旧的连接对象及所有的表对象 + close_stream(); + + // 再重新打开连接对象并打开表对象 + if (open_tbl(dbn.c_str(), tbl.c_str(), idx.c_str(), + flds.c_str(), true) == false) + { + logger_error("reopen error"); + return (false); + } + } + + if (debugOn_) + printf("%s(%d): gets: (%s)\n", + __FUNCTION__, __LINE__, buf_.c_str()); + return (proto_.parse_respond(tbl_curr_->nfld_, buf_, error_, serror_)); +} + +bool hsclient::chat() +{ + if (stream_.write(buf_) == false) + { + error_ = HS_ERR_WRITE; + logger_error("send(%s) error(%s)", + buf_.c_str(), acl_last_serror()); + return (false); + } + + if (stream_.gets(buf_) == false) + { + error_ = HS_ERR_READ; + logger_error("gets error(%s)", acl_last_serror()); + return (false); + } + + error_ = HS_ERR_OK; + return (true); +} + +int hsclient::get_error() const +{ + return (error_); +} + +const char* hsclient::get_serror(int errnum) const +{ + return (hserror::get_serror(errnum)); +} + +const char* hsclient::get_last_serror() const +{ + if (error_ == 0) + return (dummy_ok); + const char* ptr = hserror::get_serror(error_); + if (ptr != dummy_unknown) + return (ptr); + return (serror_); +} + +const char* hsclient::get_addr() const +{ + return (addr_); +} + +int hsclient::get_id() const +{ + if (tbl_curr_ == NULL) + { + logger_warn("tbl not open!"); + return (-1); + } + return (tbl_curr_->id_); +} + +void hsclient::debug_enable(bool on) +{ + debugOn_ = on; +} + +} // namespace acl diff --git a/lib_acl_cpp/src/hsocket/hserror.cpp b/lib_acl_cpp/src/hsocket/hserror.cpp new file mode 100644 index 000000000..2b86d7a81 --- /dev/null +++ b/lib_acl_cpp/src/hsocket/hserror.cpp @@ -0,0 +1,45 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/hsocket/hserror.hpp" + +namespace acl +{ + +static const char* dummy_unknown = "uknown error"; + +hserror::hserror() +{ +} + +hserror::~hserror() +{ +} + +const char* hserror::get_serror(int errnum) +{ + static struct + { + int err; + const char* msg; + } err_list[] = + { + { HS_ERR_INVALID_REPLY, "server reply invalid" }, + { HS_ERR_EMPTY, "server reply empty" }, + { HS_ERR_PARAMS, "params invalid" }, + { HS_ERR_NOT_OPEN, "server's table not open" }, + { HS_ERR_READ, "read from server error" }, + { HS_ERR_WRITE, "write to server error" }, + { HS_ERR_CONN, "connect server error" }, + { HS_ERR_OK, "ok" }, + + { -1000, NULL} + }; + + for (int i = 0; err_list[i].msg != NULL; i++) + { + if (err_list[i].err == errnum) + return (err_list[i].msg); + } + return (dummy_unknown); +} + +} diff --git a/lib_acl_cpp/src/hsocket/hspool.cpp b/lib_acl_cpp/src/hsocket/hspool.cpp new file mode 100644 index 000000000..bd5392726 --- /dev/null +++ b/lib_acl_cpp/src/hsocket/hspool.cpp @@ -0,0 +1,114 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/stdlib/locker.hpp" +#include "acl_cpp/hsocket/hsclient.hpp" +#include "acl_cpp/hsocket/hspool.hpp" + +namespace acl +{ + +hspool::hspool(const char* addr_rw, const char* addr_rd, + bool cache_enable /* = true */, bool retry_enable /* = true */) +: cache_enable_(cache_enable) +, retry_enable_(retry_enable) +{ + acl_assert(addr_rw); + addr_rw_ = acl_mystrdup(addr_rw); + if (addr_rd != NULL) + addr_rd_ = acl_mystrdup(addr_rd); + else + addr_rd_ = addr_rw_; + locker_ = NEW locker(true); +} + +hspool::~hspool() +{ + if (addr_rd_ != addr_rw_) + acl_myfree(addr_rd_); + acl_myfree(addr_rw_); + + std::list::iterator it = pool_.begin(); + for (; it != pool_.end(); ++it) + delete (*it); + pool_.clear(); + delete locker_; +} + +hsclient* hspool::peek(const char* dbn, const char* tbl, + const char* idx, const char* flds, bool readonly /* = false */) +{ + hsclient* client; + const char* addr; + + if (readonly) + addr = addr_rd_; + else + addr = addr_rw_; + + locker_->lock(); + + // 先顺序查询符合表字段条件的连接对象 + std::list::iterator it = pool_.begin(); + for (; it != pool_.end(); ++it) + { + // 如果地址不匹配查跳过,地址必须匹配 + if (strcmp((*it)->get_addr(), addr) != 0) + continue; + + // 打开已经打开的表,查询表字段是否符合 + if ((*it)->open_tbl(dbn, tbl, idx, flds, false)) + { + client = *it; + pool_.erase(it); + locker_->unlock(); + return (client); + } + } + + // 查询地址匹配的连接对象,如果存在一个匹配的连接对象,则 + // 打开新的表 + it = pool_.begin(); + std::list::iterator it_next = it; + + for (; it != pool_.end(); it = it_next) + { + ++it_next; + // 如果地址不匹配查跳过,地址必须匹配 + if (strcmp((*it)->get_addr(), addr) != 0) + continue; + + client = *it; + pool_.erase(it); // 从连接池中删除 + + // 打开新的表 + if (client->open_tbl(dbn, tbl, idx, flds, true)) + { + locker_->unlock(); + return (client); + } + + // 打开失败,则需要删除该连接对象 + delete client; + } + + locker_->unlock(); + + client = NEW hsclient(addr, cache_enable_, retry_enable_); + + if (client->open_tbl(dbn, tbl, idx, flds) == false) + { + delete client; + return (false); + } + + return (client); +} + +void hspool::put(hsclient* client) +{ + acl_assert(client); + locker_->lock(); + pool_.push_back(client); + locker_->unlock(); +} + +} // namespace acl diff --git a/lib_acl_cpp/src/hsocket/hsproto.cpp b/lib_acl_cpp/src/hsocket/hsproto.cpp new file mode 100644 index 000000000..dfe0a2733 --- /dev/null +++ b/lib_acl_cpp/src/hsocket/hsproto.cpp @@ -0,0 +1,377 @@ +#include "acl_stdafx.hpp" +#include +#include +#include "acl_cpp/stdlib/string.hpp" +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/stdlib/escape.hpp" +#include "acl_cpp/hsocket/hsrow.hpp" +#include "acl_cpp/hsocket/hserror.hpp" +#include "acl_cpp/hsocket/hsproto.hpp" + +namespace acl +{ + +#define MAX_INT 2147483647 + +hsproto::hsproto(bool cache_enable) +: debugOn_(false) +, cache_enable_(cache_enable) +, buf_ptr_(NULL) +{ +} + +hsproto::~hsproto() +{ + reset(); + clear_cache(); +} + +bool hsproto::build_open(string& out, int id, + const char* dbn, const char* tbl, + const char* idx, const char* flds) +{ + out.clear(); + out << "P\t" << id << '\t' << dbn << '\t' << tbl + << '\t' << idx << '\t' << flds << '\n'; + return (true); +} + +bool hsproto::build_get(string& out, int id, const char* values[], int num, + const char* cond /* = "=" */, int nlimit /* = 0 */, int noffset /* = 0 */) +{ + if (nlimit <= 0) + nlimit = MAX_INT; + if (noffset < 0) + noffset = 0; + char buf[32], *limit_offset = NULL; + if (nlimit > 1) + { + snprintf(buf, sizeof(buf), "%d\t%d", nlimit, noffset); + limit_offset = buf; + } + + build_request(out, id, cond, values, num, limit_offset, 0, 0, 0); + return (true); +} + +bool hsproto::build_get(string& out, int id, int nfld, + const char* first_value, ...) +{ + va_list ap; + char* ptr; + char** pptr; + + pptr = (char**) acl_mycalloc((size_t) nfld, sizeof(char*)); + va_start(ap, first_value); + + pptr[0] = (char*) first_value; + int i = 1; + while ((ptr = va_arg(ap, char*)) != NULL) + { + if (i >= nfld) + break; + pptr[i] = ptr; + i++; + } + va_end(ap); + + bool ret = build_get(out, id, (const char**) pptr, i, "=", 0, 0); + acl_myfree(pptr); + return (ret); +} + +bool hsproto::build_mod(string& out, int id, const char* values[], int num, + const char* to_values[], int to_num, const char* cond /* = "=" */, + int nlimit /* = 0 */, int noffset /* = 0 */) +{ + if (nlimit <= 0) + nlimit = MAX_INT; + if (noffset < 0) + noffset = 0; + char buf[32], *limit_offset = NULL; + + snprintf(buf, sizeof(buf), "%d\t%d", nlimit, noffset); + build_request(out, id, cond, values, + num, limit_offset, 'U', to_values, to_num); + return (true); +} + +bool hsproto::build_del(string& out, int id, const char* values[], + int num, const char* cond /* = "=" */, + int nlimit /* = 0 */, int noffset /* = 0 */) +{ + if (nlimit <= 0) + nlimit = 1; + if (noffset < 0) + noffset = 0; + char buf[32], *limit_offset = NULL; + if (nlimit > 1) + { + snprintf(buf, sizeof(buf), "%d\t%d", nlimit, noffset); + limit_offset = buf; + } + + build_request(out, id, cond, values, num, limit_offset, 'D', 0, 0); + return (true); +} + +bool hsproto::build_del(string& out, int id, int nfld, const char* first_value, ...) +{ + va_list ap; + char* ptr; + char** pptr; + + pptr = (char**) acl_mycalloc((size_t) nfld, sizeof(char*)); + va_start(ap, first_value); + + pptr[0] = (char*) first_value; + int i = 1; + while ((ptr = va_arg(ap, char*)) != NULL) + { + if (i >= nfld) + break; + pptr[i] = ptr; + i++; + } + va_end(ap); + + bool ret = build_del(out, id, (const char**) pptr, i, "=", 0, 0); + acl_myfree(pptr); + return (ret); + +} + +bool hsproto::build_add(string& out, int id, const char* values[], int num) +{ + build_request(out, id, "+", values, num, 0, 0, 0, 0); + return (true); +} + +bool hsproto::build_add(string& out, int id, int nfld, const char* first_value, ...) +{ + va_list ap; + char* ptr; + char** pptr; + + pptr = (char**) acl_mycalloc((size_t) nfld, sizeof(char*)); + va_start(ap, first_value); + + pptr[0] = (char*) first_value; + int i = 1; + while ((ptr = va_arg(ap, char*)) != NULL) + { + if (i >= nfld) + break; + pptr[i] = ptr; + i++; + } + va_end(ap); + + bool ret = build_add(out, id, (const char**) pptr, i); + acl_myfree(pptr); + return (ret); +} + +void hsproto::build_request(string& buf, int id, const char* oper, + const char* values[], int num, + const char* limit_offset, char mop, + const char* to_values[], int to_num) +{ + char idbuf[32], numbuf[32]; + + buf.clear(); + + snprintf(idbuf, sizeof(idbuf), "%d", id); + snprintf(numbuf, sizeof(numbuf), "%d", num); + buf << idbuf << "\t" << oper << "\t" << numbuf; + + int i; + for (i = 0; i < num; i++) + { + buf << "\t"; + escape(values[i], strlen(values[i]), buf); + } + + if (limit_offset) + buf << "\t" << limit_offset; + + if (mop) + buf << "\t" << mop; + + if (to_values && to_num > 0) + { + for (i = 0; i < to_num; i++) + { + buf << "\t"; + escape(to_values[i], strlen(to_values[i]), buf); + } + } + + buf << "\n"; +} + +static const char* dummy_ok = "ok"; + +bool hsproto::parse_respond(int nfld, string& buf, + int& errnum, const char*& serror) +{ + serror = dummy_ok; + + if (buf.empty()) + { + errnum = HS_ERR_EMPTY; + logger_error("respond empty"); + return (false); + } + + buf_ptr_ = buf.c_str(); + char *last = buf_ptr_, *save = NULL; + while (*buf_ptr_) + { + if (*buf_ptr_ == '\t') + { + save = buf_ptr_; + *buf_ptr_++ = 0; + break; + } + buf_ptr_++; + } + errnum = atoi(last); + if (*buf_ptr_ == 0) + { + if (save) + *save = '\t'; + errnum = HS_ERR_INVALID_REPLY; + logger_error("respond(%s) invalid", buf.c_str()); + return (false); + } + + last = buf_ptr_; + save = NULL; + while (*buf_ptr_) + { + if (*buf_ptr_ == '\t') + { + save = buf_ptr_; + *buf_ptr_++ = 0; + break; + } + buf_ptr_++; + } + + ntoken_ = atoi(last); + if (ntoken_ <= 0) + { + if (errnum != 0) + { + errnum = HS_ERR_INVALID_REPLY; + logger_error("ntoken(%d) invalid", ntoken_); + return (false); + } + return (false); + } + + if (ntoken_ > nfld) + ntoken_ = nfld; + + if (errnum == 0) + return (true); + + serror = buf_ptr_; + return (false); +} + +hsrow* hsproto::get_next_row() +{ + static const char *dummy_nil = ""; + + if (ntoken_ <= 0 || buf_ptr_ == NULL || *buf_ptr_ == 0) + return (NULL); + + hsrow* row; + + if (!rows_cache_.empty()) + { + row = rows_cache_[rows_cache_.size() - 1]; + rows_cache_.pop_back(); + row->reset(ntoken_); + } + else + row = NEW hsrow(ntoken_); + + char* last; + int i; + for (i = 0; i < ntoken_; i++) + { + if (*buf_ptr_ == '\0') + { + row->push_back(dummy_nil, 1); + break; + } + if (*buf_ptr_ == '\t') + { + row->push_back(dummy_nil, 1); + buf_ptr_++; + continue; + } + + last = buf_ptr_; + buf_ptr_ = strchr(buf_ptr_, '\t'); + if (buf_ptr_ == NULL) + { + row->push_back(last, strlen(last)); + break; + } + + *buf_ptr_++ = 0; + + row->push_back(last, strlen(last)); + } + + if (debugOn_) + { + std::vector::const_iterator cit = + row->get_row().begin(); + for (; cit != row->get_row().end(); ++cit) + { + printf(">>>%s\n", *cit); + } + } + + return (row); +} + +const std::vector& hsproto::get() +{ + while (true) + { + hsrow* row = get_next_row(); + if (row == NULL) + break; + rows_.push_back(row); + } + return (rows_); +} + +void hsproto::reset() +{ + std::vector::iterator it = rows_.begin(); + for (; it != rows_.end(); ++it) + { + if (cache_enable_) + rows_cache_.push_back(*it); + else + delete (*it); + } + rows_.clear(); +} + +void hsproto::clear_cache() +{ + std::vector::iterator it = rows_cache_.begin(); + for (; it != rows_cache_.end(); ++it) + delete (*it); + rows_cache_.clear(); +} + +} // namespace acl diff --git a/lib_acl_cpp/src/hsocket/hsrow.cpp b/lib_acl_cpp/src/hsocket/hsrow.cpp new file mode 100644 index 000000000..fd75a6a61 --- /dev/null +++ b/lib_acl_cpp/src/hsocket/hsrow.cpp @@ -0,0 +1,64 @@ +#include "acl_stdafx.hpp" +#include +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/stdlib/string.hpp" +#include "acl_cpp/stdlib/escape.hpp" +#include "acl_cpp/hsocket/hsrow.hpp" + +namespace acl +{ + +hsrow::hsrow(int ncolum) +: ncolum_(ncolum) +, icolum_(0) +{ + colums_ = NEW string[ncolum_]; +} + +hsrow::~hsrow() +{ + row_.clear(); + delete[] colums_; +} + +void hsrow::reset(int ncolum) +{ + icolum_ = 0; + row_.clear(); + if (ncolum <= ncolum_) + return; + delete[] colums_; + ncolum_ = ncolum; + colums_ = NEW string[ncolum_]; +} + +void hsrow::push_back(const char* value, size_t dlen) +{ + if (icolum_ >= ncolum_) + { + logger_error("icolum_(%d) >= ncolum_(%d)", + icolum_, ncolum_); + return; + } + + static const char* dummy_ = ""; + if (*value == 0) + { + row_.push_back(dummy_); + icolum_++; + return; + } + + string* buf = &colums_[icolum_]; + buf->clear(); + unescape(value, dlen, *buf); + row_.push_back(buf->c_str()); + icolum_++; +} + +const std::vector& hsrow::get_row() const +{ + return (row_); +} + +} // namespace acl diff --git a/lib_acl_cpp/src/hsocket/hstable.cpp b/lib_acl_cpp/src/hsocket/hstable.cpp new file mode 100644 index 000000000..9ede80c45 --- /dev/null +++ b/lib_acl_cpp/src/hsocket/hstable.cpp @@ -0,0 +1,31 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/hsocket/hstable.hpp" + +namespace acl +{ + +hstable::hstable(int id, const char* dbn, const char* tbl, + const char* idx, const char* flds) +{ + id_ = id; + dbn_ = acl_mystrdup(dbn); + tbl_ = acl_mystrdup(tbl); + idx_ = acl_mystrdup(idx); + flds_ = acl_mystrdup(flds); + + ACL_ARGV *tokens = acl_argv_split(flds, ",; \t"); + nfld_ = tokens->argc; + acl_argv_free(tokens); + values_ = (char**) acl_mycalloc(nfld_, sizeof(char*)); +} + +hstable::~hstable() +{ + acl_myfree(dbn_); + acl_myfree(tbl_); + acl_myfree(idx_); + acl_myfree(flds_); + acl_myfree(values_); +} + +} // namespace acl diff --git a/lib_acl_cpp/src/http/HttpCookie.cpp b/lib_acl_cpp/src/http/HttpCookie.cpp new file mode 100644 index 000000000..f7dbf3b02 --- /dev/null +++ b/lib_acl_cpp/src/http/HttpCookie.cpp @@ -0,0 +1,233 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/http/http_header.hpp" +#include "acl_cpp/http/HttpCookie.hpp" + +namespace acl +{ + +HttpCookie::HttpCookie(const char* name, const char* value) +{ + acl_assert(name && *name && value); + name_ = acl_mystrdup(name); + value_ = acl_mystrdup(value); + dummy_[0] = 0; +} + +HttpCookie::HttpCookie(void) +{ + name_ = NULL; + value_ = NULL; + dummy_[0] = 0; +} + +HttpCookie::~HttpCookie(void) +{ + if (name_) + acl_myfree(name_); + if (value_) + acl_myfree(value_); + + std::list::iterator it = params_.begin(); + for (; it != params_.end(); ++it) + { + acl_myfree((*it)->name); + acl_myfree((*it)->value); + acl_myfree(*it); + } +} + +void HttpCookie::destroy(void) +{ + delete this; +} + +bool HttpCookie::splitNameValue(char* data, HTTP_PARAM* param) +{ +#define SKIP_SPECIAL(x) { while (*(x) == ' ' || *(x) == '\t' || *(x) == '=') (x)++; } +#define SKIP_WHILE(cond, x) { while(*(x) && (cond)) (x)++; } + + // 开始解析过程 + param->name = data; + + // 去掉开头无用的特殊字符 + SKIP_SPECIAL(param->name); + if (*(param->name) == 0) + return false; + + // 找到 '=' + param->value = param->name; + SKIP_WHILE(*(param->value) != '=', param->value); + if (*(param->value) != '=') + return false; + + // 去掉 '=' 前面的空格 + char* ptr = param->value - 1; + *param->value++ = 0; + while (ptr > param->name && (*ptr == ' ' || *ptr == '\t')) + *ptr-- = 0; + + // 去掉 value 开始的无效字符 + SKIP_SPECIAL(param->value); + + // 找到 value 值的结束位置 + // 允许 value = "\0" + ptr = param->value + strlen(param->value) - 1; + while (ptr >= param->value && (*ptr == ' ' || *ptr == '\t')) + *ptr-- = 0; + + return true; +} + +// value 格式:xxx=xxx; domain=xxx; expires=xxx; path=xxx +bool HttpCookie::setCookie(const char* value) +{ + if (value == NULL || *value == 0) + return false; + + HTTP_PARAM param; + ACL_ARGV* tokens = acl_argv_split(value, ";"); + acl_assert(tokens->argc > 0); + + // 从第一个 name=value 字段中取得 cookie 名及 cookie 值 + if (splitNameValue(tokens->argv[0], ¶m) == false) + { + acl_argv_free(tokens); + return false; + } + // name 肯定非 "\0",而 value 可以为 "\0" + name_ = acl_mystrdup(param.name); + value_ = acl_mystrdup(param.value); + + for (int i = 1; i < tokens->argc; i++) + { + if (splitNameValue(tokens->argv[i], ¶m) == false) + continue; + if (*(param.value) == 0) + continue; + if (strcasecmp(param.name, "domain") == 0) + setDomain(param.value); + else if (strcasecmp(param.name, "expires") == 0) + setExpires(param.value); + else if (strcasecmp(param.name, "path") == 0) + setPath(param.value); + else + add(param.name, param.value); + } + + acl_argv_free(tokens); + return true; +} + +HttpCookie& HttpCookie::setDomain(const char* domain) +{ + add("Domain", domain); + return *this; +} + +HttpCookie& HttpCookie::setPath(const char* path) +{ + add("Path", path); + return *this; +} + +HttpCookie& HttpCookie::setExpires(time_t timeout) +{ + if (timeout > 0) + { + time_t n = time(NULL); + n += timeout; + + char buf[64]; + http_header::date_format(buf, sizeof(buf), n); + add("Expires", buf); + } + return *this; +} + +HttpCookie& HttpCookie::setExpires(const char* expires) +{ + if (expires && *expires) + add("Expires", expires); + return *this; +} + +HttpCookie& HttpCookie::setMaxAge(int max_age) +{ + char tmp[20]; + snprintf(tmp, sizeof(tmp), "%d", max_age); + add("Max-Age", tmp); + return *this; +} + +HttpCookie& HttpCookie::add(const char* name, const char* value) +{ + if (name == NULL || *name == 0 || value == NULL) + return *this; + + HTTP_PARAM* param = (HTTP_PARAM*) acl_mymalloc(sizeof(HTTP_PARAM)); + param->name = acl_mystrdup(name); + param->value = acl_mystrdup(value); + params_.push_back(param); + return *this; +} + +const char* HttpCookie::getName(void) const +{ + if (name_ == NULL) + return dummy_; + return name_; +} + +const char* HttpCookie::getValue(void) const +{ + if (value_ == NULL) + return dummy_; + return value_; +} + +const char* HttpCookie::getExpires(void) const +{ + return getParam("Expires"); +} + +const char* HttpCookie::getDomain(void) const +{ + return getParam("Domain"); +} + +const char* HttpCookie::getPath(void) const +{ + return getParam("Path"); +} + +int HttpCookie::getMaxAge(void) const +{ + const char* ptr = getParam("Max-Age"); + if (ptr == NULL || *ptr == 0) + return -1; + return atoi(ptr); +} + +const char* HttpCookie::getParam(const char* name, + bool case_insensitive /* = true */) const +{ + std::list::const_iterator cit = params_.begin(); + for (; cit != params_.end(); ++cit) + { + if (case_insensitive) + { + if (strcasecmp((*cit)->name, name) == 0) + return (*cit)->value; + } + else if (strcasecmp((*cit)->name, name) == 0) + return (*cit)->value; + } + return dummy_; +} + +const std::list& HttpCookie::getParams(void) const +{ + return params_; +} + +} // namespace acl end diff --git a/lib_acl_cpp/src/http/HttpServlet.cpp b/lib_acl_cpp/src/http/HttpServlet.cpp new file mode 100644 index 000000000..5853cfb3e --- /dev/null +++ b/lib_acl_cpp/src/http/HttpServlet.cpp @@ -0,0 +1,119 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/stream/socket_stream.hpp" +#include "acl_cpp/session/memcache_session.hpp" +#include "acl_cpp/http/http_header.hpp" +#include "acl_cpp/http/HttpSession.hpp" +#include "acl_cpp/http/HttpServletRequest.hpp" +#include "acl_cpp/http/HttpServletResponse.hpp" +#include "acl_cpp/http/HttpServlet.hpp" + +namespace acl +{ + +HttpServlet::HttpServlet(void) +{ + local_charset_[0] = 0; + rw_timeout_ = 60; +} + +HttpServlet::~HttpServlet(void) +{ +} + +void HttpServlet::setLocalCharset(const char* charset) +{ + if (charset && *charset) + snprintf(local_charset_, sizeof(local_charset_), "%s", charset); + else + local_charset_[0] =0; +} + +void HttpServlet::setRwTimeout(int rw_timeout) +{ + rw_timeout_ = rw_timeout; +} + +bool HttpServlet::doRun(session& session, socket_stream* stream /* = NULL */, + bool body_parse /* = true */, int body_limit /* = 102400 */) +{ + socket_stream* in; + socket_stream* out; + bool cgi_mode; + + if (stream == NULL) + { + // 数据流为空,则当 CGI 模式处理,将标准输入输出 + // 作为数据流 + stream = NEW socket_stream(); + (void) stream->open(ACL_VSTREAM_IN); + in = stream; + + stream = NEW socket_stream(); + (void) stream->open(ACL_VSTREAM_OUT); + out = stream; + cgi_mode = true; + } + else + { + in = out = stream; + cgi_mode = false; + } + + // req/res 采用栈变量,减少内存分配次数 + + HttpServletResponse res(*out); + HttpServletRequest req(res, session, *in, local_charset_, + body_parse, body_limit); + + if (rw_timeout_ >= 0) + req.setRwTimeout(rw_timeout_); + + res.setCgiMode(cgi_mode); + + bool ret; + + http_method_t method = req.getMethod(); + if (method == HTTP_METHOD_GET) + ret = doGet(req, res); + else if (method == HTTP_METHOD_POST) + ret = doPost(req, res); + else if (method == HTTP_METHOD_PUT) + ret = doPut(req, res); + else if (method == HTTP_METHOD_CONNECT) + ret = doConnect(req, res); + else if (method == HTTP_METHOD_PURGE) + ret = doPurge(req, res); + else + { + ret = false; // 有可能是IO失败或未知方法 + http_request_error_t n = req.getLastError(); + if (n == HTTP_REQ_ERR_METHOD) + doUnknown(req, res); + else + doError(req, res); + } + + if (in != out) + { + // 如果是标准输入输出流,则需要先将数据流与标准输入输出解绑, + // 然后才能释放数据流对象,数据流内部会自动判断流句柄合法性 + // 这样可以保证与客户端保持长连接 + in->unbind(); + out->unbind(); + delete in; + delete out; + } + + return ret; +} + +bool HttpServlet::doRun(const char* memcached_addr /* = "127.0.0.1:11211" */, + socket_stream* stream /* = NULL */, + bool body_parse /* = true */, int body_limit /* = 102400 */) +{ + memcache_session session(memcached_addr); + return doRun(session, stream, body_parse, body_limit); +} + +} // namespace acl diff --git a/lib_acl_cpp/src/http/HttpServletRequest.cpp b/lib_acl_cpp/src/http/HttpServletRequest.cpp new file mode 100644 index 000000000..2fd08c6ac --- /dev/null +++ b/lib_acl_cpp/src/http/HttpServletRequest.cpp @@ -0,0 +1,624 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/stdlib/string.hpp" +#include "acl_cpp/stream/istream.hpp" +#include "acl_cpp/session/session.hpp" +#include "acl_cpp/stream/socket_stream.hpp" +#include "acl_cpp/stdlib/charset_conv.hpp" +#include "acl_cpp/http/http_header.hpp" +#include "acl_cpp/http/HttpCookie.hpp" +#include "acl_cpp/http/http_client.hpp" +#include "acl_cpp/http/http_mime.hpp" +#include "acl_cpp/http/HttpSession.hpp" +#include "acl_cpp/http/HttpServletResponse.hpp" +#include "acl_cpp/http/HttpServletRequest.hpp" + +#define SKIP_SPACE(x) { while (*x == ' ' || *x == '\t') x++; } + +namespace acl +{ + +HttpServletRequest::HttpServletRequest(HttpServletResponse& res, session& store, + socket_stream& stream, const char* local_charset /* = NULL */, + bool body_parse /* = true */, int body_limit /* = 102400 */) +: req_error_(HTTP_REQ_OK) +, res_(res) +, store_(store) +, http_session_(NULL) +, stream_(stream) +, body_parse_(body_parse) +, body_limit_(body_limit) +, cookies_inited_(false) +, client_(NULL) +, method_(HTTP_METHOD_UNKNOWN) +, request_type_(HTTP_REQUEST_NORMAL) +, mime_(NULL) +, readHeaderCalled_(false) +{ + ACL_SAFE_STRNCPY(cookie_name_, "ACL_SESSION_ID", sizeof(cookie_name_)); + ACL_VSTREAM* in = stream.get_vstream(); + if (in == ACL_VSTREAM_IN) + cgi_mode_ = true; + else + cgi_mode_ = false; + if (local_charset && *local_charset) + snprintf(localCharset_, sizeof(localCharset_), + "%s", local_charset); + else + localCharset_[0] = 0; + rw_timeout_ = 60; +} + +HttpServletRequest::~HttpServletRequest(void) +{ + if (client_) + delete client_; + std::vector::iterator it = cookies_.begin(); + for (; it != cookies_.end(); ++it) + (*it)->destroy(); + std::vector::iterator it1 = params_.begin(); + for (; it1 != params_.end(); ++it1) + { + acl_myfree((*it1)->name); + acl_myfree((*it1)->value); + acl_myfree(*it1); + } + if (mime_) + delete mime_; + if (http_session_) + delete http_session_; +} + +http_method_t HttpServletRequest::getMethod(void) const +{ + // HttpServlet 类对象的 doRun 运行时 readHeader 必须先被调用, + // 而 HttpSevlet 类在初始化请求时肯定会调用 getMethod 方法, + // 所以在此函数中触发 readHeader 方法比较好,这样一方面可以 + // 将 readHeader 方法隐藏起来,免得用户误调用;另一方面,又 + // 能保证 readHeader 肯定会被调用;同时又不必把 HttpServlet + // 类声明本类的友元类 + + if (readHeaderCalled_ == false) + const_cast(this)->readHeader(); + return method_; +} + +static void add_cookie(std::vector& cookies, char* data) +{ + SKIP_SPACE(data); + if (*data == 0 || *data == '=') + return; + char* ptr = strchr(data, '='); + if (ptr == NULL) + return; + *ptr++ = 0; + SKIP_SPACE(ptr) + if (*ptr == 0) + return; + char* end = ptr + strlen(ptr) - 1; + while (end > ptr && (*end == ' ' || *end == '\t')) + *end-- = 0; + HttpCookie* cookie = NEW HttpCookie(data, ptr); + cookies.push_back(cookie); +} + +void HttpServletRequest::setCookie(const char* name, const char* value) +{ + if (name == NULL || *name == 0 || value == NULL) + return; + HttpCookie* cookie = NEW HttpCookie(name, value); + cookies_.push_back(cookie); +} + +const std::vector& HttpServletRequest::getCookies(void) const +{ + if (cookies_inited_) + return cookies_; + + // 设置标记表明已经分析过cookie了,以便于下次重复调用时节省时间 + const_cast(this)->cookies_inited_ = true; + + if (cgi_mode_) + { + const char* ptr = acl_getenv("HTTP_COOKIE"); + if (ptr == NULL || *ptr == 0) + return cookies_; + ACL_ARGV* argv = acl_argv_split(ptr, ";"); + ACL_ITER iter; + acl_foreach(iter, argv) + { + add_cookie(const_cast + (this)->cookies_, (char*) iter.data); + } + acl_argv_free(argv); + return cookies_; + } + + if (client_ == NULL) + return cookies_; + const HTTP_HDR_REQ* req = client_->get_request_head(NULL); + if (req == NULL) + return cookies_; + if (req->cookies_table == NULL) + return cookies_; + + const char* name, *value; + HttpCookie* cookie; + ACL_HTABLE_ITER iter; + + // 遍历 HTTP 请求头中的 cookie 项 + acl_htable_foreach(iter, req->cookies_table) + { + name = acl_htable_iter_key(iter); + value = (char*) acl_htable_iter_value(iter); + if (name == NULL || *name == 0 + || value == NULL || *value == 0) + { + continue; + } + // 创建 cookie 对象并将之加入数组中 + cookie = NEW HttpCookie(name, value); + const_cast + (this)->cookies_.push_back(cookie); + } + + return cookies_; +} + +const char* HttpServletRequest::getCookieValue(const char* name) const +{ + (void) getCookies(); + + std::vector::const_iterator cit = cookies_.begin(); + for (; cit != cookies_.end(); ++cit) + { + const char* ptr = (*cit)->getName(); + if (ptr && strcmp(name, ptr) == 0) + return (*cit)->getValue(); + } + return NULL; +} + +const char* HttpServletRequest::getHeader(const char* name) const +{ + if (cgi_mode_) + return acl_getenv(name); + + if (client_ == NULL) + return NULL; + return client_->header_value(name); +} + +const char* HttpServletRequest::getQueryString(void) const +{ + if (cgi_mode_) + return acl_getenv("QUERY_STRING"); + if (client_ == NULL) + return NULL; + return client_->request_params(); +} + +const char* HttpServletRequest::getPathInfo(void) const +{ + if (cgi_mode_) + { + const char* ptr = acl_getenv("SCRIPT_NAME"); + if (ptr != NULL) + return ptr; + ptr = acl_getenv("PATH_INFO"); + return ptr; + } + if (client_ == NULL) + return NULL; + return client_->request_path(); +} + +const char* HttpServletRequest::getRequestUri(void) const +{ + if (cgi_mode_) + return acl_getenv("REQUEST_URI"); + if (client_ == NULL) + return NULL; + else + return client_->request_url(); +} + +HttpSession& HttpServletRequest::getSession(bool create /* = true */, + const char* sid_in /* = NULL */) +{ + if (http_session_ == NULL) + { + http_session_ = NEW HttpSession(store_); + const char* sid; + + if ((sid = getCookieValue(cookie_name_)) != NULL) + store_.set_sid(sid); + else if (create) + { + // 获得唯一 ID 标识符 + sid = store_.get_sid(); + // 生成 cookie 对象,并分别向请求对象和响应对象添加 cookie + HttpCookie* cookie = NEW HttpCookie(cookie_name_, sid); + res_.addCookie(cookie); + setCookie(cookie_name_, sid); + } + else if (sid_in != NULL && *sid_in != 0) + { + store_.set_sid(sid_in); + // 生成 cookie 对象,并分别向请求对象和响应对象添加 cookie + HttpCookie* cookie = NEW HttpCookie(cookie_name_, sid_in); + res_.addCookie(cookie); + setCookie(cookie_name_, sid_in); + } + } + return *http_session_; +} + +acl_int64 HttpServletRequest::getContentLength(void) const +{ + if (cgi_mode_) + { + const char* ptr = acl_getenv("CONTENT_LENGTH"); + if (ptr == NULL) + return -1; + return acl_atoui64(ptr); + } + if (client_ == NULL) + return -1; + return client_->body_length(); +} + +const char* HttpServletRequest::getContentType(bool part /* = true */) const +{ + if (part) + return content_type_.get_ctype(); + if (cgi_mode_) + return acl_getenv("CONTENT_TYPE"); + return client_->header_value("Content-Type"); +} + +const char* HttpServletRequest::getCharacterEncoding(void) const +{ + return content_type_.get_charset(); +} + +const char* HttpServletRequest::getLocalCharset(void) const +{ + return localCharset_[0] ? localCharset_ : NULL; +} + +const char* HttpServletRequest::getLocalAddr(void) const +{ + if (cgi_mode_) + return NULL; + + if (client_ == NULL) + return NULL; + const char* ptr = client_->get_stream().get_local(); + if (*ptr == 0) + return NULL; + snprintf(const_cast(this)->localAddr_, + sizeof(localAddr_), "%s", ptr); + char* p = (char*) strchr(localAddr_, ':'); + if (p) + *p = 0; + return localAddr_; +} + +unsigned short HttpServletRequest::getLocalPort(void) const +{ + if (cgi_mode_) + return 0; + + if (client_ == NULL) + return 0; + const char* ptr = client_->get_stream().get_local(); + if (*ptr == 0) + return 0; + char* p = (char*) strchr(ptr, ':'); + if (p == NULL || *(++p) == 0) + return 0; + + return atoi(p); +} + +const char* HttpServletRequest::getRemoteAddr(void) const +{ + if (cgi_mode_) + { + const char* ptr = acl_getenv("REMOTE_ADDR"); + if (ptr && *ptr) + return ptr; + logger_warn("no REMOTE_ADDR from acl_getenv"); + return NULL; + } + if (client_ == NULL) + return NULL; + const char* ptr = client_->get_stream().get_peer(); + if (*ptr == 0) + { + logger_warn("get_peer return empty string"); + return NULL; + } + snprintf(const_cast(this)->remoteAddr_, + sizeof(remoteAddr_), "%s", ptr); + char* p = (char*) strchr(remoteAddr_, ':'); + if (p) + *p = 0; + return remoteAddr_; +} + +unsigned short HttpServletRequest::getRemotePort(void) const +{ + if (cgi_mode_) + { + const char* ptr = acl_getenv("REMOTE_PORT"); + if (ptr && *ptr) + return atoi(ptr); + logger_warn("no REMOTE_PORT from acl_getenv"); + return 0; + } + if (client_ == NULL) + return 0; + const char* ptr = client_->get_stream().get_peer(true); + if (*ptr == 0) + { + logger_warn("get_peer return empty string"); + return 0; + } + char* port = (char*) strchr(ptr, ':'); + if (port == NULL || *(++port) == 0) + { + logger_warn("no port in addr: %s", ptr); + return 0; + } + + return atoi(port); +} + +const char* HttpServletRequest::getParameter(const char* name) const +{ + std::vector::const_iterator cit = params_.begin(); + for (; cit != params_.end(); ++cit) + { + if (strcmp((*cit)->name, name) == 0) + return (*cit)->value; + } + + // 如果是 MIME 格式,则尝试从 mime_ 对象中查询参数 + if (mime_ == NULL) + return NULL; + const http_mime_node* node = mime_->get_node(name); + if (node == NULL) + return NULL; + return node->get_value(); +} + +http_mime* HttpServletRequest::getHttpMime(void) const +{ + return mime_; +} + +http_request_t HttpServletRequest::getRequestType(void) const +{ + return request_type_; +} + +istream& HttpServletRequest::getInputStream(void) const +{ + return stream_; +} + +void HttpServletRequest::parseParameters(const char* str) +{ + const char* requestCharset = getCharacterEncoding(); + charset_conv conv; + string buf; + ACL_ARGV* tokens = acl_argv_split(str, "&"); + ACL_ITER iter; + acl_foreach(iter, tokens) + { + char* name = (char*) iter.data; + char* value = strchr(name, '='); + if (value == NULL || *(value + 1) == 0) + continue; + *value++ = 0; + name = acl_url_decode(name); + value = acl_url_decode(value); + HTTP_PARAM* param = (HTTP_PARAM*) acl_mycalloc(1, + sizeof(HTTP_PARAM)); + if (localCharset_[0] != 0 && requestCharset + && strcasecmp(requestCharset, localCharset_)) + { + buf.clear(); + if (conv.convert(requestCharset, localCharset_, + name, strlen(name), &buf) == true) + { + param->name = acl_mystrdup(buf.c_str()); + acl_myfree(name); + } + else + param->name = name; + + buf.clear(); + if (conv.convert(requestCharset, localCharset_, + value, strlen(value), &buf) == true) + { + param->value = acl_mystrdup(buf.c_str()); + acl_myfree(value); + } + else + param->value = value; + } + else + { + param->name = name; + param->value = value; + } + params_.push_back(param); + } + + acl_argv_free(tokens); +} + +// Content-Type: application/x-www-form-urlencoded; charset=utf-8 +// Content-Type: multipart/form-data; boundary=---------------------------41184676334 +// Content-Type: application/octet-stream + +bool HttpServletRequest::readHeader(void) +{ + acl_assert(readHeaderCalled_ == false); + readHeaderCalled_ = true; + + const char* method; + + if (cgi_mode_) + { + const char* ptr = acl_getenv("CONTENT_TYPE"); + if (ptr && *ptr) + content_type_.parse(ptr); + + // 必须是后获得 method,因为 acl_getenv 内部的内存区用的 + // 是线程局部变量,该内存区在同一线程中会被重复使用,这样 + // 后获得 method 可以保证 method 可以由下面的过程确定具体 + // 的请求方法 + method = acl_getenv("REQUEST_METHOD"); + } + else + { + client_ = NEW http_client(&stream_, rw_timeout_); + if (client_->read_head() == false) + { + req_error_ = HTTP_REQ_ERR_IO; + return false; + } + method = client_->request_method(); + const char* ptr = client_->header_value("Content-Type"); + if (ptr && *ptr) + content_type_.parse(ptr); + } + + if (method == NULL || *method == 0) + { + req_error_ = HTTP_REQ_ERR_METHOD; + logger_error("method null"); + return false; + } + if (strcmp(method, "GET") == 0) + method_ = HTTP_METHOD_GET; + else if (strcmp(method, "POST") == 0) + method_ = HTTP_METHOD_POST; + else if (strcmp(method, "PUT") == 0) + method_ = HTTP_METHOD_PUT; + else if (strcmp(method, "CONNECT") == 0) + method_ = HTTP_METHOD_CONNECT; + else if (strcmp(method, "PURGE") == 0) + method_ = HTTP_METHOD_PURGE; + else + { + logger_error("unkown method: %s", method); + method_ = HTTP_METHOD_UNKNOWN; + req_error_ = HTTP_REQ_ERR_METHOD; + return false; + } + + const char* ptr = getQueryString(); + if (ptr && ptr) + parseParameters(ptr); + + if (method_ == HTTP_METHOD_GET) + request_type_ = HTTP_REQUEST_NORMAL; + else if (method_ == HTTP_METHOD_POST) + { + acl_int64 len = getContentLength(); + if (len == -1) + return false; + const char* ctype = getContentType(); + const char* stype = content_type_.get_stype(); + + // 数据体为文件上传的 MIME 类型 + if (ctype == NULL) + request_type_ = HTTP_REQUEST_OTHER; + else if (strcasecmp(ctype, "multipart") == 0 + && strcasecmp(stype, "form-data") == 0) + { + const char* bound = content_type_.get_bound(); + if (bound == NULL) + request_type_ = HTTP_REQUEST_NORMAL; + else + { + request_type_ = HTTP_REQUEST_MULTIPART_FORM; + mime_ = NEW http_mime(bound, localCharset_); + } + } + + // 数据体为数据流类型 + else if (strcasecmp(ctype, "application") == 0 + && strcasecmp(stype, "octet-stream") == 0) + { + request_type_ = HTTP_REQUEST_OCTET_STREAM; + } + + // 数据体为普通的 name=value 类型 + else if (body_parse_) + { + if (len >= body_limit_) + return false; + + request_type_ = HTTP_REQUEST_NORMAL; + char* query = (char*) acl_mymalloc((size_t) len + 1); + int ret = getInputStream().read(query, (size_t) len); + if (ret > 0) + { + query[ret] = 0; + parseParameters(query); + } + acl_myfree(query); + return ret == -1 ? false : true; + } + else + request_type_ = HTTP_REQUEST_OTHER; + } + + return true; +} + +const char* HttpServletRequest::getRequestReferer(void) const +{ + if (cgi_mode_) + return acl_getenv("HTTP_REFERER"); + if (client_ == NULL) + return NULL; + return client_->header_value("Referer"); +} + +const http_ctype& HttpServletRequest::getHttpCtype(void) const +{ + return content_type_; +} + +void HttpServletRequest::setRwTimeout(int rw_timeout) +{ + rw_timeout_ = rw_timeout; +} + +http_request_error_t HttpServletRequest::getLastError(void) const +{ + return req_error_; +} + +void HttpServletRequest::fprint_header(ostream& out, const char* prompt) +{ + if (client_) + { + client_->fprint_header(out, prompt); + } + else + { + const char* ptr = acl_getenv_list(); + if (ptr) + out.format("%s", ptr); + } +} + +} // namespace acl diff --git a/lib_acl_cpp/src/http/HttpServletResponse.cpp b/lib_acl_cpp/src/http/HttpServletResponse.cpp new file mode 100644 index 000000000..0cfffbaaa --- /dev/null +++ b/lib_acl_cpp/src/http/HttpServletResponse.cpp @@ -0,0 +1,137 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/stdlib/string.hpp" +#include "acl_cpp/stream/ostream.hpp" +#include "acl_cpp/stream/socket_stream.hpp" +#include "acl_cpp/http/http_header.hpp" +#include "acl_cpp/http/HttpServlet.hpp" +#include "acl_cpp/http/HttpServletResponse.hpp" + +namespace acl +{ + +HttpServletResponse::HttpServletResponse(socket_stream& stream) +: stream_(stream) +{ + header_ = NEW http_header(); + header_->set_request_mode(false); + charset_[0] = 0; + snprintf(content_type_, sizeof(content_type_), "text/html"); +} + +HttpServletResponse::~HttpServletResponse(void) +{ + delete header_; +} + +HttpServletResponse& HttpServletResponse::setRedirect(const char* location, int status /* = 302 */) +{ + header_->add_entry("Location", location); + header_->set_status(status); + return *this; +} + +HttpServletResponse& HttpServletResponse::setCharacterEncoding(const char* charset) +{ + snprintf(charset_, sizeof(charset_), "%s", charset); + return *this; +} + +HttpServletResponse& HttpServletResponse::setKeepAlive(bool on) +{ + header_->set_keep_alive(on); + return *this; +} + +HttpServletResponse& HttpServletResponse::setContentLength(acl_int64 n) +{ + header_->set_content_length(n); + return *this; +} + +HttpServletResponse& HttpServletResponse::setContentType(const char* value) +{ + snprintf(content_type_, sizeof(content_type_), "%s", value); + return *this; +} + +HttpServletResponse& HttpServletResponse::setDateHeader(const char* name, time_t value) +{ + char buf[256]; + header_->date_format(buf, sizeof(buf), value); + header_->add_entry(name, buf); + return *this; +} + +HttpServletResponse& HttpServletResponse::setHeader(const char* name, int value) +{ + char buf[32]; + snprintf(buf, sizeof(buf), "%d", value); + header_->add_entry(name, buf); + return *this; +} + +HttpServletResponse& HttpServletResponse::setHeader(const char* name, const char* value) +{ + header_->add_entry(name, value); + return *this; +} + +HttpServletResponse& HttpServletResponse::setStatus(int status) +{ + header_->set_status(status); + return *this; +} + +HttpServletResponse& HttpServletResponse::setCgiMode(bool on) +{ + header_->set_cgi_mode(on); + return *this; +} + +HttpServletResponse& HttpServletResponse::addCookie(HttpCookie* cookie) +{ + header_->add_cookie(cookie); + return *this; +} + +HttpServletResponse& HttpServletResponse::addCookie(const char* name, const char* value, + const char* domain /* = NULL */, const char* path /* = NULL */, + time_t expires /* = 0 */) +{ + acl_assert(name && *name && value); + header_->add_cookie(name, value, domain, path, expires); + return *this; +} + +http_header& HttpServletResponse::getHttpHeader(void) const +{ + return *header_; +} + +bool HttpServletResponse::sendHeader(void) +{ + acl_assert(header_->is_request() == false); + string buf; + if (charset_[0] != 0) + buf.format("%s; charset=%s", content_type_, charset_); + else + buf.format("%s", content_type_); + header_->set_content_type(buf.c_str()); + + buf.clear(); + header_->build_response(buf); + return getOutputStream().write(buf) == -1 ? false : true; +} + +void HttpServletResponse::encodeUrl(string& out, const char* url) +{ + out.clear(); + out.url_encode(url); +} + +ostream& HttpServletResponse::getOutputStream(void) const +{ + return stream_; +} + +} // namespace acl diff --git a/lib_acl_cpp/src/http/HttpSession.cpp b/lib_acl_cpp/src/http/HttpSession.cpp new file mode 100644 index 000000000..e7fafe2b7 --- /dev/null +++ b/lib_acl_cpp/src/http/HttpSession.cpp @@ -0,0 +1,62 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/session/session.hpp" +#include "acl_cpp/http/HttpSession.hpp" + +namespace acl +{ + +HttpSession::HttpSession(session& session) +: session_(session) +{ +} + +HttpSession::~HttpSession(void) +{ +} + +const char* HttpSession::getSid(void) const +{ + return session_.get_sid(); +} + +const char* HttpSession::getAttribute(const char* name) const +{ + return const_cast (this)->session_.get(name); +} + +const void* HttpSession::getAttribute(const char* name, size_t* size) const +{ + const VBUF* bf = const_cast (this)->session_.get_vbuf(name); + if (bf == NULL) + return NULL; + if (size) + *size = bf->len; + return bf->buf; +} + +bool HttpSession::setAttribute(const char* name, const char* value) +{ + return setAttribute(name, value, strlen(value)); +} + +bool HttpSession::setAttribute(const char* name, const void* value, size_t len) +{ + return session_.set(name, value, len); +} + +bool HttpSession::removeAttribute(const char* name) +{ + return session_.del(name); +} + +bool HttpSession::setMaxAge(time_t ttl) +{ + return session_.set_ttl(ttl); +} + +bool HttpSession::invalidate() +{ + return session_.remove(); +} + +} // namespace acl diff --git a/lib_acl_cpp/src/http/http_client.cpp b/lib_acl_cpp/src/http/http_client.cpp new file mode 100644 index 000000000..30dfbeab2 --- /dev/null +++ b/lib_acl_cpp/src/http/http_client.cpp @@ -0,0 +1,649 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/stdlib/zlib_stream.hpp" +#include "acl_cpp/stream/ssl_stream.hpp" +#include "acl_cpp/stream/ostream.hpp" +#include "acl_cpp/http/http_header.hpp" +#include "acl_cpp/http/http_client.hpp" + +namespace acl +{ + +http_client::http_client(void) + : stream_(NULL) + , stream_fixed_(false) + , hdr_res_(NULL) + , res_(NULL) + , hdr_req_(NULL) + , req_(NULL) + , rw_timeout_(120) + , unzip_(true) + , zstream_(NULL) + , is_request_(true) +{ + +} + +http_client::http_client(socket_stream* client, int rw_timeout /* = 120 */, + bool is_request /* = false */, bool unzip /* = true */) + : stream_(client) + , stream_fixed_(true) + , hdr_res_(NULL) + , res_(NULL) + , hdr_req_(NULL) + , req_(NULL) + , rw_timeout_(rw_timeout) + , unzip_(unzip) + , zstream_(NULL) + , is_request_(is_request) +{ + +} + +http_client::~http_client(void) +{ + reset(); + if (stream_ && !stream_fixed_) + delete stream_; +} + +void http_client::reset(void) +{ + if (res_) + { + // 说明是长连接的第二次请求,所以需要把上次请求的 + // 响应头对象及响应体对象释放 + + acl_assert(hdr_res_); + http_res_free(res_); + hdr_res_ = NULL; + res_ = NULL; + } + else if (hdr_res_) + { + // 说明是长连接的第二次请求,因为有可能第一次请求 + // 只有响应头,所以仅需要释放上次的响应头对象 + + http_hdr_res_free(hdr_res_); + hdr_res_ = NULL; + } + + if (req_) + { + acl_assert(hdr_req_); + http_req_free(req_); + hdr_req_ = NULL; + req_ = NULL; + } + else if (hdr_req_) + { + http_hdr_req_free(hdr_req_); + hdr_req_ = NULL; + } + + if (zstream_) + { + delete zstream_; + zstream_ = NULL; + } + + last_ret_ = -1; + body_finish_ = false; +} + +bool http_client::open(const char* addr, int conn_timeout /* = 60 */, + int rw_timeout /* = 60 */, bool unzip /* = true */, + bool use_ssl /* = false */) +{ + is_request_ = true; + + if (stream_ && !stream_fixed_) + { + delete stream_; + stream_ = NULL; + } + + ssl_stream* stream = NEW ssl_stream(); + rw_timeout_ = rw_timeout; + unzip_ = unzip; + + if (stream->open_ssl(addr, conn_timeout, + rw_timeout, use_ssl) == false) + { + delete stream; + return (false); + } + stream_ = stream; + return (true); +} + +int http_client::write(const http_header& header) +{ + string buf; + if (header.is_request()) + header.build_request(buf); + else + header.build_response(buf); + return get_ostream().write(buf.c_str(), buf.length()); +} + +ostream& http_client::get_ostream(void) const +{ + acl_assert(stream_); + return *stream_; +} + +istream& http_client::get_istream(void) const +{ + acl_assert(stream_); + return *stream_; +} + +socket_stream& http_client::get_stream(void) const +{ + acl_assert(stream_); + return *stream_; +} + +bool http_client::read_head(void) +{ + if (is_request_) + return read_response_head(); + else + return read_request_head(); +} + +bool http_client::read_response_head(void) +{ + // 以防万一,先清除可能的上次请求的残留的中间数据对象 + reset(); + + if (stream_ == NULL) + { + logger_error("connect stream not open yet"); + return (false); + } + ACL_VSTREAM* vstream = stream_->get_vstream(); + if (vstream == NULL) + { + logger_error("connect stream null"); + return (false); + } + + hdr_res_ = http_hdr_res_new(); + int ret = http_hdr_res_get_sync(hdr_res_, vstream, rw_timeout_); + if (ret == -1) + { + http_hdr_res_free(hdr_res_); + hdr_res_ = NULL; + return (false); + } + + if (http_hdr_res_parse(hdr_res_) < 0) + { + logger_error("parse response header error"); + http_hdr_res_free(hdr_res_); + hdr_res_ = NULL; + return (false); + } + + // 块传输的优先级最高 + if (!hdr_res_->hdr.chunked) + { + // 如果服务器响应时明确指明了长度为 0 则表示不没有数据体 + if (hdr_res_->hdr.content_length == 0) + { + body_finish_ = true; + return (true); + } + } + + const char* ptr = http_hdr_entry_value(&hdr_res_->hdr, "Content-Encoding"); + if (ptr && unzip_) + { + // 目前仅支持 gzip 数据的解压 + if (strcasecmp(ptr, "gzip") == 0) + { + zstream_ = NEW zlib_stream(); + if (zstream_->unzip_begin(false) == false) + { + logger_error("unzip_begin error"); + delete zstream_; + zstream_ = NULL; + } + gzip_header_left_ = 10; + } + else + logger_warn("unknown compress format: %s", ptr); + } + + return (true); +} + +bool http_client::read_request_head(void) +{ + // 以防万一,先清除可能的上次请求的残留的中间数据对象 + reset(); + + if (stream_ == NULL) + { + logger_error("client stream not open yet"); + return (false); + } + ACL_VSTREAM* vstream = stream_->get_vstream(); + if (vstream == NULL) + { + logger_error("client stream null"); + return (false); + } + + hdr_req_ = http_hdr_req_new(); + int ret = http_hdr_req_get_sync(hdr_req_, vstream, rw_timeout_); + if (ret == -1) + { + http_hdr_req_free(hdr_req_); + hdr_req_ = NULL; + return (false); + } + + if (http_hdr_req_parse(hdr_req_) < 0) + { + logger_error("parse request header error"); + http_hdr_req_free(hdr_req_); + hdr_req_ = NULL; + return (false); + } + + if (hdr_req_->hdr.content_length <= 0) + body_finish_ = true; + return (true); +} + +acl_int64 http_client::body_length() const +{ + if (is_request_) + { + if (hdr_res_) + return hdr_res_->hdr.content_length; + } + else if (hdr_req_) + return hdr_req_->hdr.content_length; + return -1; +} + +bool http_client::keep_alive() const +{ + if (is_request_) + { + if (hdr_res_) + return hdr_res_->hdr.keep_alive ? true : false; + } + else if (hdr_req_) + return hdr_req_->hdr.keep_alive ? true : false; + return false; +} + +const char* http_client::header_value(const char* name) const +{ + if (is_request_) + { + if (hdr_res_) + return http_hdr_entry_value(&hdr_res_->hdr, name); + } + else if (hdr_req_) + return http_hdr_entry_value(&hdr_req_->hdr, name); + return NULL; +} + +int http_client::response_status(void) const +{ + if (is_request_ && hdr_res_) + return hdr_res_->reply_status; + return -1; +} + +const char* http_client::request_host(void) const +{ + if (!is_request_ && hdr_req_) + return hdr_req_->host; + return NULL; +} + +int http_client::request_port(void) const +{ + if (!is_request_ && hdr_req_) + return hdr_req_->port; + return -1; +} + +const char* http_client::request_method(void) const +{ + if (!is_request_ && hdr_req_) + return hdr_req_->method; + return NULL; +} + +const char* http_client::request_url(void) const +{ + if (!is_request_ && hdr_req_ && hdr_req_->url_part) + return acl_vstring_str(hdr_req_->url_part); + return NULL; +} + +const char* http_client::request_path(void) const +{ + if (!is_request_ && hdr_req_ && hdr_req_->url_path) + return acl_vstring_str(hdr_req_->url_path); + return NULL; +} + +const char* http_client::request_params(void) const +{ + if (!is_request_ && hdr_req_ && hdr_req_->url_params) + return acl_vstring_str(hdr_req_->url_params); + return NULL; +} + +const char* http_client::request_param(const char* name) const +{ + if (!is_request_ && hdr_req_) + return http_hdr_req_param(hdr_req_, name); + return NULL; +} + +const char* http_client::request_cookie(const char* name) const +{ + if (!is_request_ && hdr_req_) + return http_hdr_req_cookie_get(hdr_req_, name); + return NULL; +} + +int http_client::read_body(char* buf, size_t size) +{ + if (is_request_) + return read_response_body(buf, size); + else + return read_request_body(buf, size); +} + +int http_client::read_response_body(char* buf, size_t size) +{ + if (hdr_res_ == NULL) + { + logger_error("response header not get yet"); + return (-1); + } + + if (stream_ == NULL) + { + logger_error("not connected yet"); + return (-1); + } + ACL_VSTREAM* vstream = stream_->get_vstream(); + if (vstream == NULL) + { + logger_error("connect stream null"); + return (-1); + } + + if (res_ == NULL) + res_ = http_res_new(hdr_res_); + + // 缓冲区太大了没有任何意义 + if (size >= 1024000) + size = 1024000; + http_off_t ret = http_res_body_get_sync(res_, vstream, buf, size); + + if (ret <= 0) + { + // 如果在读响应头时调用了 unzip_begin,则必须保证读完数据 + // 后再调用 unzip_finish,否则会因为 zlib 本身的设计而导致 + // 内存泄露 + if (zstream_ != NULL) + { + string dummy(64); + zstream_->unzip_finish(&dummy); + } + body_finish_ = true; + } + + return ((int) ret); +} + +int http_client::read_request_body(char* buf, size_t size) +{ + if (hdr_req_ == NULL) + { + logger_error("request header not get yet"); + return (-1); + } + + if (stream_ == NULL) + { + logger_error("not connected yet"); + return (-1); + } + ACL_VSTREAM* vstream = stream_->get_vstream(); + if (vstream == NULL) + { + logger_error("client stream null"); + return (-1); + } + + if (req_ == NULL) + req_ = http_req_new(hdr_req_); + + // 缓冲区太大了没有任何意义 + if (size >= 1024000) + size = 1024000; + http_off_t ret = http_req_body_get_sync(req_, vstream, buf, (int) size); + + if (ret <= 0) + body_finish_ = true; + + return ((int) ret); +} + +bool http_client::body_finish(void) const +{ + return (body_finish_); +} + +int http_client::read_body(string& out, bool clean /* = true */, + int* real_size /* = NULL */) +{ + if (is_request_) + return read_response_body(out, clean, real_size); + else + return read_request_body(out, clean, real_size); +} + +int http_client::read_response_body(string& out, bool clean, + int* real_size) +{ + if (real_size) + *real_size = 0; + if (body_finish_) + return (last_ret_); + + if (stream_ == NULL) + { + logger_error("connect null"); + return (-1); + } + ACL_VSTREAM* vstream = stream_->get_vstream(); + if (vstream == NULL) + { + logger_error("connect stream null"); + return (-1); + } + + if (hdr_res_ == NULL) + { + logger_error("response header not get yet"); + return (-1); + } + if (res_ == NULL) + res_ = http_res_new(hdr_res_); + + if (clean) + out.clear(); + + int saved_count = (int) out.length(); + char buf[8192]; + +SKIP_GZIP_HEAD_AGAIN: // 对于有 GZIP 头数据,可能需要重复读 + int ret = (int) http_res_body_get_sync(res_, vstream, buf, sizeof(buf)); + + if (zstream_ == NULL) + { + if (ret > 0) + { + out.append(buf, ret); + if (real_size) + *real_size = ret; + } + else + { + body_finish_ = true; // 表示数据已经读完 + last_ret_ = ret; + } + return (ret); + } + + if (ret <= 0) + { + if (zstream_->unzip_finish(&out) == false) + { + logger_error("unzip_finish error"); + return (-1); + } + + last_ret_ = ret; // 记录返回值 + body_finish_ = true; // 表示数据已经读完且解压缩完毕 + return ((int) out.length() - saved_count); + } + + if (real_size) + (*real_size) += ret; + + // 需要先跳过 gzip 头 + + if (gzip_header_left_ >= ret) + { + gzip_header_left_ -= ret; + goto SKIP_GZIP_HEAD_AGAIN; + } + + int n; + if (gzip_header_left_ > 0) + { + n = gzip_header_left_; + gzip_header_left_ = 0; + } + else + n = 0; + if (zstream_->unzip_update(buf + n, ret - n, &out) == false) + { + logger_error("unzip_update error"); + return (-1); + } + return ((int) out.length() - saved_count); +} + +int http_client::read_request_body(string& out, bool clean, + int* real_size) +{ + if (real_size) + *real_size = 0; + if (body_finish_) + return (last_ret_); + + if (stream_ == NULL) + { + logger_error("client null"); + return (-1); + } + ACL_VSTREAM* vstream = stream_->get_vstream(); + if (vstream == NULL) + { + logger_error("client stream null"); + return (-1); + } + + if (hdr_req_ == NULL) + { + logger_error("request header not get yet"); + return (-1); + } + if (req_ == NULL) + req_ = http_req_new(hdr_req_); + + if (clean) + out.clear(); + + char buf[8192]; + + int ret = (int) http_req_body_get_sync(req_, vstream, buf, sizeof(buf)); + + if (ret > 0) + { + out.append(buf, ret); + if (real_size) + *real_size = ret; + } + else + { + body_finish_ = true; // 表示数据已经读完 + last_ret_ = ret; + } + return (ret); +} + +const HTTP_HDR_RES* http_client::get_respond_head(string* buf) +{ + if (hdr_res_ == NULL) + return (NULL); + if (buf) + { + ACL_VSTRING* vbf = buf->vstring(); + http_hdr_build(&hdr_res_->hdr, vbf); + } + return (hdr_res_); +} + +const HTTP_HDR_REQ* http_client::get_request_head(string* buf) +{ + if (hdr_req_ == NULL) + return (NULL); + if (buf) + { + ACL_VSTRING* vbf = buf->vstring(); + http_hdr_build(&hdr_req_->hdr, vbf); + } + return (hdr_req_); +} + +void http_client::print_header(const char* prompt) +{ + if (hdr_res_) + http_hdr_print(&hdr_res_->hdr, prompt ? prompt : "dummy"); + else if (hdr_req_) + http_hdr_print(&hdr_req_->hdr, prompt ? prompt : "dummy"); +} + +void http_client::fprint_header(ostream& out, const char* prompt) +{ + ACL_VSTREAM* fp = out.get_vstream(); + if (fp == NULL) + { + logger_error("fp stream null"); + return; + } + if (hdr_res_) + http_hdr_fprint(fp, &hdr_res_->hdr, prompt ? prompt : "dummy"); + else if (hdr_req_) + http_hdr_fprint(fp, &hdr_req_->hdr, prompt ? prompt : "dummy"); +} + +} // namespace acl diff --git a/lib_acl_cpp/src/http/http_ctype.cpp b/lib_acl_cpp/src/http/http_ctype.cpp new file mode 100644 index 000000000..164da9d94 --- /dev/null +++ b/lib_acl_cpp/src/http/http_ctype.cpp @@ -0,0 +1,175 @@ +#include "acl_stdafx.hpp" +#include "../mime/internal/header_token.hpp" +#include "../mime/internal/mime_state.hpp" +#include "acl_cpp/http/http_ctype.hpp" + +namespace acl +{ + +http_ctype::http_ctype() +{ + ctype_ = NULL; + stype_ = NULL; + name_ = NULL; + charset_ = NULL; + bound_ = NULL; +} + +http_ctype::~http_ctype() +{ + reset(); +} + +void http_ctype::reset() +{ + if (ctype_) + { + acl_myfree(ctype_); + ctype_ = NULL; + } + if (stype_) + { + acl_myfree(stype_); + stype_ = NULL; + } + if (charset_) + { + acl_myfree(charset_); + charset_ = NULL; + } + if (name_) + { + acl_myfree(name_); + name_ = NULL; + } + if (bound_) + { + delete bound_; + bound_ = NULL; + } +} + +#define RFC2045_TSPECIALS "()<>@,;:\\\"/[]?=" +#define EQUAL(x, y) !strcasecmp((x), (y)) +#define TOKEN_MATCH(tok, text) \ + ((tok).type == HEADER_TOK_TOKEN && EQUAL((tok).u.value, (text))) + +bool http_ctype::parse(const char* cp) +{ + reset(); + +#define PARSE_CONTENT_TYPE_HEADER(t, ptr) \ + header_token(t, MIME_MAX_TOKEN, \ + buffer, ptr, RFC2045_TSPECIALS, ';') + + HEADER_TOKEN token[MIME_MAX_TOKEN]; + ssize_t tok_count; + ACL_VSTRING* buffer = acl_vstring_alloc(64); + + tok_count = PARSE_CONTENT_TYPE_HEADER(token, &cp); + if (tok_count < 0) + { + acl_vstring_free(buffer); + return false; + } + + ctype_ = acl_mystrdup(token[0].u.value); + + if (TOKEN_MATCH(token[0], "multipart")) + { + if (tok_count >= 3 && token[1].type == '/') + stype_ = acl_mystrdup(token[2].u.value); + while ((tok_count = PARSE_CONTENT_TYPE_HEADER(token, &cp)) >= 0) + { + if (tok_count < 3 || token[1].type != '=') + continue; + if (TOKEN_MATCH(token[0], "boundary")) + { + if (bound_ == NULL) + bound_ = NEW string(64); + /* 需要添加 "--" 做为分隔符的前导符 */ + *bound_ = "--"; + *bound_ += token[2].u.value; + break; + } + } + } + else if (TOKEN_MATCH(token[0], "text")) + { + if (tok_count >= 3 && token[1].type == '/') + stype_ = acl_mystrdup(token[2].u.value); + while ((tok_count = PARSE_CONTENT_TYPE_HEADER(token, &cp)) >= 0) + { + if (tok_count < 3 || token[1].type != '=') + continue; + if (TOKEN_MATCH(token[0], "charset")) + { + charset_ = acl_mystrdup(token[2].u.value); + break; + } + } + } + else if (TOKEN_MATCH(token[0], "image")) + { + if (tok_count >= 3 && token[1].type == '/') + stype_ = acl_mystrdup(token[2].u.value); + while ((tok_count = PARSE_CONTENT_TYPE_HEADER(token, &cp)) >= 0) + { + if (tok_count < 3 || token[1].type != '=') + continue; + if (TOKEN_MATCH(token[0], "name")) + { + name_ = acl_mystrdup(token[2].u.value); + break; + } + } + } + else if (TOKEN_MATCH(token[0], "application")) + { + if (tok_count >= 3 && token[1].type == '/') + stype_ = acl_mystrdup(token[2].u.value); + while ((tok_count = PARSE_CONTENT_TYPE_HEADER(token, &cp)) >= 0) + { + if (tok_count < 3 || token[1].type != '=') + continue; + if (TOKEN_MATCH(token[0], "name")) { + name_ = acl_mystrdup(token[2].u.value); + break; + } + } + } + else if (tok_count >= 3 && token[1].type == '/') + stype_ = acl_mystrdup(token[1].u.value); + + acl_vstring_free(buffer); + return true; +} + +const char* http_ctype::get_ctype() const +{ + return ctype_; +} + +const char* http_ctype::get_stype() const +{ + return stype_; +} + +const char* http_ctype::get_bound() const +{ + if (bound_ == NULL || bound_->empty()) + return NULL; + return bound_->c_str(); +} + +const char* http_ctype::get_name() const +{ + return name_; +} + +const char* http_ctype::get_charset() const +{ + return charset_; +} + +} // namespace acl diff --git a/lib_acl_cpp/src/http/http_download.cpp b/lib_acl_cpp/src/http/http_download.cpp new file mode 100644 index 000000000..4438d1851 --- /dev/null +++ b/lib_acl_cpp/src/http/http_download.cpp @@ -0,0 +1,245 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/http/http_utils.hpp" +#include "acl_cpp/http/http_request.hpp" +#include "acl_cpp/http/http_client.hpp" +#include "acl_cpp/http/http_download.hpp" + +namespace acl +{ + +http_download::http_download(const char* url, const char* addr /* = NULL */) +{ + if (addr) + ACL_SAFE_STRNCPY(addr_, addr, sizeof(addr)); + else if (http_utils::get_addr(url, addr_, sizeof(addr_)) == false) + { + logger_error("url(%s) invalid", url); + addr_[0] = 0; + url_ = NULL; + req_ = NULL; + return; + } + + url_ = acl_mystrdup(url); + req_ = NEW http_request(addr_); // HTTP 请求对象 + req_->request_header().set_url(url_) + .set_content_type("text/html") + .set_host(addr_); +} + +http_download::~http_download() +{ + if (url_) + acl_myfree(url_); + if (req_) + delete req_; +} + +const char* http_download::get_url() const +{ + return url_; +} + +const char* http_download::get_addr() const +{ + return addr_[0] == 0 ? NULL : addr_; +} + +bool http_download::reset(const char* url /* = NULL */, + const char* addr /* = NULL */) +{ + if (url) + { + if (url_) + { + acl_myfree(url_); + url_ = NULL; + } + if (addr) + ACL_SAFE_STRNCPY(addr_, addr, sizeof(addr_)); + else if (http_utils::get_addr(url, addr_, + sizeof(addr_)) == false) + { + logger_error("url(%s) invalid", url); + addr_[0] = 0; + if (req_) + { + delete req_; + req_ = NULL; + } + return false; + } + url_ = acl_mystrdup(url); + } + else if (url_ == NULL) + return false; + else if (addr) + ACL_SAFE_STRNCPY(addr_, addr, sizeof(addr_)); + + if (req_) + delete req_; + req_ = NEW http_request(addr_); // HTTP 请求对象 + req_->request_header().set_url(url_) + .set_content_type("text/html") + .set_host(addr_); + return true; +} + +http_header* http_download::request_header() const +{ + return req_ ? &req_->request_header() : NULL; +} + +http_request* http_download::request() const +{ + return req_ ? req_ : NULL; +} + +bool http_download::on_response(http_client*) +{ + return true; +} + +bool http_download::on_length(long long int) +{ + return true; +} + +bool http_download::get(acl_int64 range_from /* = -1 */, acl_int64 range_to /* = -1 */, + const char* body /* = NULL */, size_t len /* = 0 */) +{ + if (req_ == NULL) + { + logger_error("no valid url"); + return false; + } + else if (range_from >= 0) + return save_range(body, len, range_from, range_to); + else + return save_total(body, len); +} + +bool http_download::save_total(const char* body, size_t len) +{ + // 发送不带 range 字段的下载请求 + + http_method_t method = body && len > 0 + ? HTTP_METHOD_POST : HTTP_METHOD_GET; + + // 设置 HTTP 请求头信息 + req_->request_header().set_method(method); + + // 发送 HTTP 请求数据 + if (req_->request(body, len) == false) + { + logger_error("send request error, url: %s", url_); + return false; + } + + http_client* conn = req_->get_client(); + if (conn == NULL) + logger_fatal("no connect to server"); + + // 回调子类虚接口实现 + if (on_response(conn) == false) + { + logger_error("deny url(%s)'s download", url_); + return false; + } + + // 获得文件长度 + acl_int64 length = conn->body_length(); + + // 回调子类虚接口实现 + if (on_length(length) == false) + { + logger_error("deny url(%s)'s download", url_); + return false; + } + + // 开始下载数据体过程 + return save(req_); +} + +bool http_download::save_range(const char* body, size_t len, + acl_int64 range_from, acl_int64 range_to) +{ + if (range_from < 0) + { + logger_error("invalid range_from: %lld", range_from); + return false; + } + else if (range_to >= 0 && range_to < range_from) + { + logger_error("invalid, 0 <= range_to: %lld < range_from: %lld", + range_to, range_from); + return false; + } + + http_method_t method = body && len > 0 + ? HTTP_METHOD_POST : HTTP_METHOD_GET; + + // 发送带 range 字段的下载请求 + + // 设置 HTTP 请求头信息 + req_->request_header().set_method(method) + .set_range(range_from, range_to); + + // 发送 HTTP 请求数据 + if (req_->request(NULL, 0) == false) + { + logger_error("send request error, url: %s", url_); + return false; + } + + // 获得文件长度 + acl_int64 length = req_->get_range_max(); + if (length <= 0) + { + // 可能是服务器不支持 range 功能,所以还得从头下载 + return false; + } + + http_client* conn = req_->get_client(); + if (conn == NULL) + logger_fatal("no connect to server"); + + // 回调子类虚接口实现 + if (on_response(conn) == false) + { + logger_error("deny url(%s)'s download", url_); + return false; + } + + // 回调子类虚接口实现 + if (on_length(length) == false) + { + logger_error("deny url(%s)'s download", url_); + return false; + } + + return save(req_); +} + +bool http_download::save(http_request* req) +{ + // 开始接收服务端的 HTTP 数据体 + + char buf[8192]; + int ret; + while (true) + { + ret = req->get_body(buf, sizeof(buf)); + if (ret <= 0) + break; + if (on_save(buf, ret) == false) + { + logger_error("on_save error, url: %s", url_); + return false; + } + } + return true; +} + +} // namespace acl diff --git a/lib_acl_cpp/src/http/http_header.cpp b/lib_acl_cpp/src/http/http_header.cpp new file mode 100644 index 000000000..7923a4870 --- /dev/null +++ b/lib_acl_cpp/src/http/http_header.cpp @@ -0,0 +1,594 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/stdlib/string.hpp" +#include "acl_cpp/http/HttpCookie.hpp" +#include "acl_cpp/http/http_header.hpp" + +namespace acl +{ + +http_header::http_header(void) +{ + init(); +} + +http_header::http_header(const char* url) +{ + init(); + if (url && *url) + set_url(url); +} + +http_header::http_header(int status) +{ + init(); + set_status(status); +} + +http_header::~http_header(void) +{ + clear(); +} + +void http_header::init() +{ + is_request_ = true; + url_ = NULL; + method_ = HTTP_METHOD_GET; + keep_alive_ = false; + nredirect_ = 0; // 默认条件下不主动进行重定向 + accept_compress_ = true; + status_ = 200; + cgi_mode_ = false; + range_from_ = -1; + range_to_ = -1; +} + +void http_header::clear() +{ + if (url_) + acl_myfree(url_); + + std::list::iterator cookies_it = cookies_.begin(); + for (; cookies_it != cookies_.end(); ++cookies_it) + (*cookies_it)->destroy(); + cookies_.clear(); + + std::list::iterator entries_it = entries_.begin(); + for (; entries_it != entries_.end(); ++entries_it) + { + acl_myfree((*entries_it)->name); + acl_myfree((*entries_it)->value); + acl_myfree(*entries_it); + } + entries_.clear(); + + std::list::iterator params_it = params_.begin(); + for (; params_it != params_.end(); ++params_it) + { + acl_myfree((*params_it)->name); + acl_myfree((*params_it)->value); + acl_myfree(*params_it); + } + params_.clear(); +} + +void http_header::reset() +{ + clear(); + init(); +} + +////////////////////////////////////////////////////////////////////////// +// 通用的函数 + +http_header& http_header::set_request_mode(bool onoff) +{ + is_request_ = onoff; + return *this; +} + +http_header& http_header::add_entry(const char* name, const char* value) +{ + if (name == NULL || *name == 0 || value == NULL || *value == 0) + return *this; + + std::list::iterator it = entries_.begin(); + for (; it != entries_.end(); ++it) + { + if (strcasecmp((*it)->name, name) == 0) + { + acl_myfree((*it)->value); + (*it)->value = acl_mystrdup(value); + return *this; + } + } + + HTTP_HDR_ENTRY* entry = (HTTP_HDR_ENTRY*) + acl_mycalloc(1, sizeof(HTTP_HDR_ENTRY)); + entry->name = acl_mystrdup(name); + entry->value = acl_mystrdup(value); + entries_.push_back(entry); + return *this; +} + +http_header& http_header::set_content_length(acl_int64 n) +{ + char buf[64]; +#ifdef WIN32 + _snprintf(buf, sizeof(buf), "%I64d", n); +#else + snprintf(buf, sizeof(buf), "%lld", n); +#endif + add_entry("Content-Length", buf); + return *this; +} + +http_header& http_header::set_content_type(const char* value) +{ + add_entry("Content-Type", value); + return *this; +} + +http_header& http_header::set_keep_alive(bool on) +{ + keep_alive_ = on; + return *this; +} + +http_header& http_header::add_cookie(const char* name, const char* value, + const char* domain /* = NULL */, const char* path /* = NULL */, + time_t expires /* = 0 */) +{ + if (name == NULL || *name == 0 || value == NULL) + return *this; + + HttpCookie* cookie = NEW HttpCookie(name, value); + if (domain && *domain) + cookie->setDomain(domain); + if (path && *path) + cookie->setPath(path); + if (expires > 0) + cookie->setExpires(expires); + cookies_.push_back(cookie); + return *this; +} + +http_header& http_header::add_cookie(HttpCookie* cookie) +{ + if (cookie) + cookies_.push_back(cookie); + return *this; +} + +#define RFC1123_STRFTIME "%a, %d %b %Y %H:%M:%S GMT" + +void http_header::date_format(char* out, size_t size, time_t t) +{ + struct tm *gmt = gmtime(&t); + strftime(out, size - 1, RFC1123_STRFTIME, gmt); +} + +bool http_header::is_request() const +{ + return is_request_; +} + +void http_header::build_common(string& buf) const +{ + if (!entries_.empty()) + { + std::list::const_iterator it = entries_.begin(); + for (; it != entries_.end(); ++it) + buf << (*it)->name << ": " << (*it)->value << "\r\n"; + } + + if (is_request_ == false && cgi_mode_) + return; + if (keep_alive_) + buf << "Connection: " << "Keep-Alive\r\n"; + else + buf << "Connection: " << "Close\r\n"; +} + +////////////////////////////////////////////////////////////////////////// +// 与 HTTP 请求头相关的函数 + +http_header& http_header::set_url(const char* url) +{ + acl_assert(url && *url); + if (url_) + acl_myfree(url_); + url_ = acl_mystrdup(url); + is_request_ = true; + return *this; +} + +http_header& http_header::set_host(const char* value) +{ + add_entry("Host", value); + return *this; +} + +http_header& http_header::set_method(http_method_t method) +{ + method_ = method; + return *this; +} + +http_header& http_header::set_range(http_off_t from, http_off_t to) +{ + range_from_ = from; + if (to >= from) + range_to_ = to; + else + range_to_ = -1; + return *this; +} + +void http_header::get_range(http_off_t* from, http_off_t* to) +{ + if (from) + *from = range_from_; + if (to) + *to = range_to_; +} + +http_header& http_header::accept_gzip(bool on) +{ + accept_compress_ = on; + return *this; +} + +http_header& http_header::add_param(const char* name, const char* value) +{ + if (name == NULL || *name == 0 || value == NULL || *value == 0) + return *this; + + std::list::iterator it = params_.begin(); + for (; it != params_.end(); ++it) + { + if (strcasecmp((*it)->name, name) == 0) + { + acl_myfree((*it)->value); + (*it)->value = acl_mystrdup(value); + return *this; + } + } + + HTTP_PARAM* param = (HTTP_PARAM*) acl_mycalloc(1, sizeof(HTTP_PARAM)); + param->name = acl_mystrdup(name); + param->value = acl_mystrdup(value); + params_.push_back(param); + return *this; +} + +bool http_header::build_request(string& buf) const +{ + if (url_ == NULL || *url_ == 0) + { + logger_error("url empty"); + return (false); + } + + buf.clear(); + switch(method_) + { + case HTTP_METHOD_GET: + buf = "GET "; + break; + case HTTP_METHOD_POST: + buf = "POST "; + break; + case HTTP_METHOD_PUT: + buf = "PUT "; + break; + case HTTP_METHOD_CONNECT: + buf = "CONNECT"; + break; + case HTTP_METHOD_PURGE: + buf = "PURGE"; + break; + default: + logger_error("unknown method(%d)", (int) method_); + return (false); + } + + buf << url_; + if (!params_.empty()) + { + buf << '?'; + acl::string tmp; + int i = 0; + std::list::const_iterator it = params_.begin(); + for (; it != params_.end(); ++it) + { + if (!(*it)->name || !(*it)->value) + continue; + + if (i > 0) + buf << '&'; + + // 需要对参数进行 URL 编码 + + tmp.url_encode((*it)->name); + buf << tmp.c_str() << '='; + tmp.url_encode((*it)->value); + buf << tmp.c_str(); + i++; + } + } + buf << " HTTP/1.1\r\n"; + if (accept_compress_) + // 因为目前的 zlib_stream 仅支持于此 + buf << "Accept-Encoding: gzip\r\n"; + + + if (!cookies_.empty()) + { + buf << "Cookie: "; + std::list::const_iterator it = cookies_.begin(); + for (; it != cookies_.end(); ++it) + { + if (it != cookies_.begin()) + buf << "; "; + buf << (*it)->getName() << "=" << (*it)->getValue(); + } + buf << "\r\n"; + } + + // 添加分段请求字段 + if (range_from_ >= 0) + { + buf << "Range: bytes=" << range_from_ << '-'; + if (range_to_ >= range_from_) + buf << range_to_; + buf << "\r\n"; + } + + build_common(buf); + buf << "\r\n"; + + return (true); +} + +bool http_header::redirect(const char* url) +{ + if (url == NULL || *url == 0) + { + logger_error("url null"); + return (false); + } + + size_t n = 0; + + // url: http[s]://xxx.xxx.xxx/xxx or /xxx + if (strncasecmp(url, "http://", sizeof("http://") - 1) == 0) + n = sizeof("http://") - 1; + else if (strncasecmp(url, "https://", sizeof("https://") - 1) == 0) + n = sizeof("https://") - 1; + if (url_) + { + acl_myfree(url_); + url_ = NULL; + } + + if (n > 0) + { + url += n; + char* ptr = acl_mystrdup(url); + char* p = strchr(ptr, '/'); + if (p) + *p = 0; + if (*ptr == 0) + { + logger_error("invalid url(%s)", url); + acl_myfree(ptr); + return (false); + } + set_host(ptr); + if (*(p + 1)) + { + *p = '/'; + url_ = acl_mystrdup(p); + } + else + url_ = acl_mystrdup("/"); + acl_myfree(ptr); + } + else + url_ = acl_mystrdup(url); + + return (true); +} + +http_header& http_header::set_redirect(unsigned int n /* = 5 */) +{ + nredirect_ = n; + return *this; +} + +unsigned int http_header::get_redirect() const +{ + return (nredirect_); +} + +////////////////////////////////////////////////////////////////////////// +// 与 HTTP 响应头相关的函数 + +typedef struct HTTP_STATUS { + int status; + const char *title; +} HTTP_STATUS; + +static HTTP_STATUS __1xx_tab[] = { + /* 1xx */ + { 100, "Continue" }, + { 101, "Switching Protocols" }, + { 102, "Processing" }, /* RFC2518 section 10.1 */ +}; + +static HTTP_STATUS __2xx_tab[] = { + /* 2xx */ + { 200, "OK" }, + { 201, "Created" }, + { 202, "Accepted" }, + { 203, "Non Authoritative Information" }, + { 204, "No Content" }, + { 205, "Reset Content" }, + { 206, "Partial Content" }, + { 207, "Multi Status" }, /* RFC2518 section 10.2 */ +}; + +static HTTP_STATUS __3xx_tab[] = { + /* 3xx */ + { 300, "Multiple Choices" }, + { 301, "Moved Permanently" }, + { 302, "Moved Temporarily" }, + { 303, "See Other" }, + { 304, "Not Modified" }, + { 305, "Use Proxy" }, + { 307, "Temporary Redirect" }, +}; + +static HTTP_STATUS __4xx_tab[] = { + /* 4xx */ + { 400, "Bad Request" }, + { 401, "Authorization Required" }, + { 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" }, + { 418, NULL }, + { 419, NULL }, + { 420, NULL }, + { 421, NULL }, + { 422, "Unprocessable Entity" }, + { 423, "Locked" }, + { 424, "Failed Dependency" }, + { 425, "No code" }, + { 426, "Upgrade Required" }, +}; + +static HTTP_STATUS __5xx_tab[] = { + /* 5xx */ + { 500, "Internal Server Error" }, + { 501, "Method Not Implemented" }, + { 502, "Bad Gateway" }, + { 503, "Service Temporarily Unavailable" }, + { 504, "Gateway Time-out" }, + { 505, "HTTP Version Not Supported" }, + { 506, "Variant Also Negotiates" }, + { 507, "Insufficient Storage" }, + { 508, NULL }, + { 509, NULL }, + { 510, "Not Extended" }, +}; + +typedef struct STATUS_MAP { + int level; + size_t size; + HTTP_STATUS *hs; +} STATUS_MAP; + +static STATUS_MAP __maps[] = { + { 100, sizeof(__1xx_tab) / sizeof(HTTP_STATUS), __1xx_tab }, + { 200, sizeof(__2xx_tab) / sizeof(HTTP_STATUS), __2xx_tab }, + { 300, sizeof(__3xx_tab) / sizeof(HTTP_STATUS), __3xx_tab }, + { 400, sizeof(__4xx_tab) / sizeof(HTTP_STATUS), __4xx_tab }, + { 500, sizeof(__5xx_tab) / sizeof(HTTP_STATUS), __5xx_tab } +}; + +static const char *__unknown_status = "unknow status"; + +static const char *http_status(int status) +{ + size_t i, pos; + + i = status / 100; + if (i < 1 || i > 5) + return (__unknown_status); + + i--; + pos = status - __maps[i].level; + + if (pos >= __maps[i].size) + return (__unknown_status); + + if (__maps[i].hs[pos].title == NULL) + return (__unknown_status); + + return (__maps[i].hs[pos].title); +} + +bool http_header::build_response(string& out) const +{ + out.clear(); + + if (status_ > 0) + { + if (cgi_mode_) + out.format("STATUS: %d\r\n", status_); + else + { + out = "HTTP/1.1 "; + out << status_ << " " << http_status(status_) << "\r\n"; + + time_t now = time(NULL); + char buf[64]; + date_format(buf, sizeof(buf), now); + out << "Date: " << buf << "\r\n"; + } + } + + if (!cookies_.empty()) + { + std::list::const_iterator it = cookies_.begin(); + for (; it != cookies_.end(); ++it) + { + out.format_append("Set-Cookie: %s=%s", + (*it)->getName(), (*it)->getValue()); + const std::list& params = (*it)->getParams(); + std::list::const_iterator cit = params.begin(); + for (; cit != params.end(); ++ cit) + { + out.format_append("; %s=%s", + (*cit)->name, (*cit)->value); + } + out << "\r\n"; + } + } + + build_common(out); + out << "\r\n"; + return true; +} + +http_header& http_header::set_status(int status) +{ + status_ = status; + is_request_ = false; + return *this; +} + +http_header& http_header::set_cgi_mode(bool on) +{ + cgi_mode_ = on; + if (cgi_mode_) + is_request_ = false; + return *this; +} + +} // namespace acl end diff --git a/lib_acl_cpp/src/http/http_mime.cpp b/lib_acl_cpp/src/http/http_mime.cpp new file mode 100644 index 000000000..7b5b91908 --- /dev/null +++ b/lib_acl_cpp/src/http/http_mime.cpp @@ -0,0 +1,240 @@ +#include "acl_stdafx.hpp" +#include "../mime/internal/mime_state.hpp" +#include "../mime/internal/header_opts.hpp" +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/stdlib/util.hpp" +#include "acl_cpp/stdlib/charset_conv.hpp" +#include "acl_cpp/stream/ifstream.hpp" +#include "acl_cpp/http/http_header.hpp" +#include "acl_cpp/http/http_mime.hpp" + +namespace acl +{ + +////////////////////////////////////////////////////////////////////////// + +http_mime_node::http_mime_node(const char* path, const MIME_NODE* node, + bool decodeIt /* = true */, const char* toCharset /* = */, + off_t off /* = 0 */) + : mime_attach(path, node, decodeIt, toCharset, off) +{ + param_value_ = NULL; + + if (get_filename() == NULL) + { + mime_type_ = HTTP_MIME_PARAM; + const char* name = get_name(); + if (path && name) + load_param(path); + } + else + mime_type_ = HTTP_MIME_FILE; +} + +http_mime_node::~http_mime_node() +{ + if (param_value_) + acl_myfree(param_value_); +} + +http_mime_t http_mime_node::get_mime_type() const +{ + return mime_type_; +} + +void http_mime_node::load_param(const char* path) +{ + ifstream in; + if (in.open_read(path) == false) + { + logger_error("open file %s error(%s)", path, last_serror()); + return; + } + off_t begin = get_bodyBegin(); + off_t end = get_bodyEnd(); + if (begin < 0 || end < 0 || begin >= end) + { + logger_error("invalid file offset, begin: %d, end: %d", + (int) begin, (int) end); + return; + } + + if (in.fseek(begin, SEEK_SET) == -1) + { + logger_error("fseek file %s error(%s), begin: %d", + path, last_serror(), (int) begin); + return; + } + + size_t len = end - begin; + char* buf = (char*) acl_mymalloc(len + 1); + if (in.read(buf, len) == -1) + { + acl_myfree(buf); + logger_error("read file %s error(%s)", path, last_serror()); + return; + } + buf[len] = 0; + char* ptr = buf + len - 1; + while (ptr >= buf) + { + if (*ptr == '\r' || *ptr == '\n' + || *ptr == ' ' || *ptr == '\t') + { + *ptr-- = 0; + continue; + } + break; + } + if (*buf == 0) + { + acl_myfree(buf); + return; + } + + char* value = acl_url_decode(buf); + if (value == NULL) + value = buf; + else + acl_myfree(buf); + + const char* fromCharset = get_charset(); + const char* toCharset = get_toCharset(); + if (fromCharset && *fromCharset && toCharset && *toCharset + && strcasecmp(fromCharset, toCharset)) + { + charset_conv conv; + string tmp; + if (conv.convert(fromCharset, toCharset, + value, strlen(value), &tmp) == true) + { + param_value_ = acl_mystrdup(tmp.c_str()); + acl_myfree(value); + } + else + param_value_ = value; + } + else + param_value_ = value; +} + +const char* http_mime_node::get_value() const +{ + return param_value_; +} + +////////////////////////////////////////////////////////////////////////// + +http_mime::http_mime(const char* boundary, + const char* local_charset /* = "gb2312" */) +{ + static const char ctype_pre[] = + "Content-Type: multipart/form-data; boundary="; + + if (boundary == NULL || strlen(boundary) < 2) + { + logger_error("boundary invalid"); + boundary = NULL; + mime_state_ = NULL; + save_path_ = NULL; + return; + } + // HTTP 的 MIME 格式与 邮件的 MIME 的分隔符有所不同, + // HTTP 的分隔符要比邮件分隔符多两个 '-',而目前 HTTP + // 的 MIME 解析器用的是邮件的 MIME 解析器,目前邮件的 + // MIME 解析器会自动加上两个 '-' 前缀,所以需要去掉 + // 开头的两个 '-' + if (*boundary == '-') + boundary++; + if (*boundary == '-') + boundary++; + boundary_ = acl_mystrdup(boundary); + + if (local_charset && *local_charset) + snprintf(local_charset_, sizeof(local_charset_), + "%s", local_charset); + else + local_charset_[0] = 0; + + decode_on_ = true; + + save_path_ = NULL; + mime_state_ = mime_state_alloc(); + + // 为了使用邮件的 mime 解析器,需要模拟出一个头部字段 + mime_state_update(mime_state_, ctype_pre, sizeof(ctype_pre) - 1); + size_t len = strlen(boundary); + mime_state_update(mime_state_, boundary, len); + mime_state_update(mime_state_, "\r\n\r\n", 4); + + // 因为该头作为解析器的主头是额外加进去的,所以会造成实际的偏移量, + // 通过 off_ 来进行偏移量补偿 + off_ = 0 - (sizeof(ctype_pre) - 1 + len + 4); + + parsed_ = false; +} + +http_mime::~http_mime() +{ + if (boundary_) + acl_myfree(boundary_); + if (save_path_) + acl_myfree(save_path_); + if (mime_state_) + mime_state_free(mime_state_); + std::list::iterator it = mime_nodes_.begin(); + for (; it != mime_nodes_.end(); ++it) + delete *it; +} + +void http_mime::set_saved_path(const char* path) +{ + if (path && *path) + save_path_ = acl_mystrdup(path); +} + +bool http_mime::update(const char* data, size_t len) +{ + return (mime_state_update(mime_state_, data, len) == 1 ? true : false); +} + +const std::list& http_mime::get_nodes(void) const +{ + if (parsed_) + return mime_nodes_; + const_cast(this)->parsed_ = true; + + ACL_ITER iter; + MIME_NODE* node; + int i = 0; + acl_foreach(iter, mime_state_) + { + // 每一个节点是主头结点,所以跳过 + if (i++ == 0) + continue; + node = (MIME_NODE*) iter.data; + const_cast(this)->mime_nodes_.push_back( + NEW http_mime_node(save_path_, node, + decode_on_, local_charset_, off_)); + } + + return mime_nodes_; +} + +const http_mime_node* http_mime::get_node(const char* name) const +{ + get_nodes(); + + const char* ptr; + std::list::const_iterator cit = mime_nodes_.begin(); + for (; cit != mime_nodes_.end(); ++cit) + { + ptr = (*cit)->get_name(); + if (ptr && strcmp(ptr, name) == 0) + return *cit; + } + + return NULL; +} + +} // namespace acl diff --git a/lib_acl_cpp/src/http/http_pipe.cpp b/lib_acl_cpp/src/http/http_pipe.cpp new file mode 100644 index 000000000..9bbee6dd1 --- /dev/null +++ b/lib_acl_cpp/src/http/http_pipe.cpp @@ -0,0 +1,67 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/stdlib/charset_conv.hpp" +#include "acl_cpp/stdlib/pipe_stream.hpp" +#include "acl_cpp/http/http_pipe.hpp" + +namespace acl +{ + +http_pipe::http_pipe() +: conv_(NULL) +{ + +} + +http_pipe::~http_pipe() +{ + if (conv_) + delete conv_; +} + +void http_pipe::set_charset(charset_conv* conv) +{ + manager_.push_back(conv); +} + +bool http_pipe::set_charset(const char* from, const char* to) +{ + if (from == NULL || to == NULL || strcasecmp(from, to) == 0) + return false; + if (conv_ == NULL) + conv_ = NEW charset_conv(); + if (conv_->update_begin(from, to) == false) + { + delete conv_; + conv_ = NULL; + return false; + } + set_charset(conv_); + return true; +} + +void http_pipe::append(pipe_stream* ps) +{ + manager_.push_back(ps); +} + +void http_pipe::reset() +{ + manager_.clear(); +} + +bool http_pipe::update(const char* in, size_t len) +{ + return manager_.update(in, len); +} + +bool http_pipe::update_end() +{ + return manager_.update_end(); +} + +pipe_manager& http_pipe::get_manager() +{ + return manager_; +} + +} // namespace acl diff --git a/lib_acl_cpp/src/http/http_request.cpp b/lib_acl_cpp/src/http/http_request.cpp new file mode 100644 index 000000000..068442b68 --- /dev/null +++ b/lib_acl_cpp/src/http/http_request.cpp @@ -0,0 +1,597 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/stdlib/util.hpp" +#include "acl_cpp/stdlib/xml.hpp" +#include "acl_cpp/stdlib/json.hpp" +#include "acl_cpp/stdlib/string.hpp" +#include "acl_cpp/stream/socket_stream.hpp" +#include "acl_cpp/stdlib/charset_conv.hpp" +#include "acl_cpp/stdlib/pipe_stream.hpp" +#include "acl_cpp/http/http_client.hpp" +#include "acl_cpp/http/http_header.hpp" +#include "acl_cpp/http/HttpCookie.hpp" +#include "acl_cpp/http/http_ctype.hpp" +#include "acl_cpp/http/http_pipe.hpp" +#include "acl_cpp/http/http_request.hpp" + +namespace acl +{ + +#define RESET_RANGE() do \ +{ \ + range_from_ = -1; \ + range_to_ = -1; \ + range_max_ = -1; \ +} while(0) + +http_request::http_request(socket_stream* client, + int conn_timeout /* = 60 */, bool unzip /* = true */) +{ + // 设置解压参数 + client_ = NEW http_client(client, client->get_vstream()->rw_timeout, + true, unzip); + unzip_ = unzip; + conv_ = NULL; + + const char* ptr = client->get_peer(); + acl_assert(ptr); + ACL_SAFE_STRNCPY(addr_, ptr, sizeof(addr_)); + rw_timeout_ = client->get_vstream()->rw_timeout; + conn_timeout_ = conn_timeout; + header_.set_url("/"); + header_.set_keep_alive(true); + header_.set_host(addr_); + cookie_inited_ = false; + cookies_ = NULL; + RESET_RANGE(); +} + +http_request::http_request(const char* addr, + int conn_timeout /* = 60 */, int rw_timeout /* = 60 */, + bool unzip /* = true */) +{ + acl_assert(addr && *addr); + ACL_SAFE_STRNCPY(addr_, addr, sizeof(addr_)); + conn_timeout_ = conn_timeout; + rw_timeout_ = rw_timeout; + unzip_ = unzip; + conv_ = NULL; + + header_.set_url("/"); + header_.set_keep_alive(true); + header_.set_host(addr_); + cookie_inited_ = false; + cookies_ = NULL; + client_ = NULL; + RESET_RANGE(); +} + +http_request::~http_request(void) +{ + close(); + if (cookies_) + { + reset(); + delete cookies_; + } + else if (conv_) + delete conv_; +} + +void http_request::close(void) +{ + if (client_) + { + delete client_; + client_ = NULL; + } +} + +void http_request::reset(void) +{ + if (cookies_) + { + std::vector::iterator it = cookies_->begin(); + for (; it != cookies_->end(); ++it) + (*it)->destroy(); + cookies_->clear(); + cookie_inited_ = false; + } + if (conv_) + { + delete conv_; + conv_ = NULL; + } + RESET_RANGE(); +} + +http_request& http_request::set_unzip(bool on) +{ + unzip_ = on; + return *this; +} + +bool http_request::open() +{ + bool reuse; + return try_open(&reuse); +} + +bool http_request::try_open(bool* reuse_conn) +{ + if (client_) + { + client_->reset(); + *reuse_conn = true; + return true; + } + + *reuse_conn = false; + + client_ = new http_client(); + + if (client_->open(addr_, conn_timeout_, + rw_timeout_, unzip_) == false) + { + logger_error("connect server(%s) error(%s)", + addr_, last_serror()); + close(); + return false; + } + + return true; +} + +http_header& http_request::request_header() +{ + return header_; +} + +http_client* http_request::get_client(void) const +{ + return client_; +} + +bool http_request::send_request(const char* data, size_t len) +{ + acl_assert(client_); // 必须保证该连接已经打开 + client_->reset(); // 重置状态 + + // 构建 HTTP 请求头 + if (data && len > 0) + { + header_.set_method(HTTP_METHOD_POST); + header_.set_content_length(len); + } + else + header_.set_method(HTTP_METHOD_GET); + + // 写 HTTP 请求头 + if (client_->write(header_) == false) + { + close(); + return false; + } + + if (data == NULL || len == 0) + return true; + + // 写 HTTP 请求体 + if (client_->get_ostream().write(data, len) == -1) + { + close(); + return false; + } + + return true; +} + +bool http_request::request(const char* data, size_t len) +{ + bool have_retried = false; + bool reuse_conn; + + while (true) + { + // 尝试打开远程连接 + if (try_open(&reuse_conn) == false) + { + logger_error("connect server error"); + return false; + + } + + // 发送 HTTP 请求至服务器 + if (send_request(data, len) == false) + { + if (have_retried || !reuse_conn) + { + logger_error("send request error"); + return false; + } + + // 对于长连接,如果是第一次IO失败,则可以再重试一次 + have_retried = true; + continue; + } + + client_->reset(); // 重置状态 + + // 读 HTTP 响应头 + if (client_->read_head() == true) + break; + + if (have_retried || !reuse_conn) + { + logger_error("read response header error"); + close(); + return false; + } + + // 先关闭之前的连接流 + close(); + + // 对于长连接,如果是第一次IO失败,则可以再重试一次 + have_retried = true; + } + + // 检查返回头中是否有 Content-Range 字段 + check_range(); + return true; +} + +void http_request::check_range() +{ + http_off_t range_from, range_to; + acl_int64 length; + + // 先取出用户在请求时设置的 range 字段,如果没设置则直接返回 + header_.get_range(&range_from, &range_to); + if (range_from < 0) + return; + + const HTTP_HDR_RES* hdr_res = client_->get_respond_head(NULL); + + // 从 HTTP 服务器响应中获得 range 回应字段,如果没有则说明 + // 服务器不支持 range 请求 + if (http_hdr_res_range((HTTP_HDR_RES*) hdr_res, &range_from_, + &range_to_, &range_max_) < 0) + { + RESET_RANGE(); + } + + // 如果服务器返回的 range 内容与请求的不一致,则说明有错 + else if (range_from_ != range_from) + { + logger_error("range_from(%lld) != %lld", range_from_, range_from); + RESET_RANGE(); + } + else if (range_to >= range_from && range_to_ != range_to) + { + logger_error("range_to(%lld) != %lld", range_to_, range_to); + RESET_RANGE(); + } + + // 虽然用户发送了 range 请求,但发送的请求内容是整个数据体, + // 则需要检查数据体长度的一致性 + else if (range_from == 0 && range_to < 0 + && (length = client_->body_length()) > 0 + && range_max_ != length) + { + logger_error("range_total_length: %lld != content_length: %lld", + range_max_, length); + RESET_RANGE(); + } +} + +bool http_request::support_range() const +{ + return range_from_ >= 0 ? true : false; +} + +acl_int64 http_request::get_range_from() const +{ + return range_from_; +} + +acl_int64 http_request::get_range_to() const +{ + return range_to_; +} + +acl_int64 http_request::get_range_max() const +{ + return range_max_; +} + +http_pipe* http_request::get_pipe(const char* to_charset) +{ + if (to_charset == NULL || *to_charset == 0) + return NULL; + + // 需要获得响应头字符集信息 + const char* ptr = client_->header_value("Content-Type"); + if (ptr == NULL || *ptr == 0) + return NULL; + + http_ctype ctype; + ctype.parse(ptr); + + const char* from_charset = ctype.get_charset(); + + if (from_charset && strcasecmp(from_charset, to_charset) != 0) + { + http_pipe* hp = NEW http_pipe(); + hp->set_charset(from_charset, to_charset); + return hp; + } + else + return NULL; +} + +bool http_request::get_body(xml& out, const char* to_charset /* = NULL */) +{ + if (client_ == NULL) + return false; + + http_pipe* hp = get_pipe(to_charset); + if (hp) + hp->append(&out); + + string buf(4096); + int ret; + // 读 HTTP 响应体,并按 xml 格式进行分析 + while (true) + { + // 调用可以自动解压缩的读函数 + ret = client_->read_body(buf); + if (ret < 0) + { + close(); + break; + } + else if (ret == 0) + break; + if (hp) + hp->update(buf.c_str(), ret); + else + out.update(buf.c_str()); + } + + if (hp) + { + hp->update_end(); + delete hp; + } + return true; +} + +bool http_request::get_body(json& out, const char* to_charset /* = NULL */) +{ + if (client_ == NULL) + return false; + + http_pipe* hp = get_pipe(to_charset); + if (hp) + hp->append(&out); + + string buf(4096); + int ret; + // 读 HTTP 响应体,并按 json 格式进行分析员 + while (true) + { + ret = client_->read_body(buf); + if (ret < 0) + { + close(); + break; + } + else if (ret == 0) + break; + if (hp) + hp->update(buf.c_str(), ret); + else + out.update(buf.c_str()); + } + + if (hp) + { + hp->update_end(); + delete hp; + } + return true; +} + +bool http_request::get_body(string& out, const char* to_charset /* = NULL */) +{ + if (client_ == NULL) + return false; + + http_pipe* hp = get_pipe(to_charset); + if (hp) + { + pipe_string ps(out); + hp->append(&ps); + } + + string buf(4096); + int ret; + // 读 HTTP 响应体 + while (true) + { + ret = client_->read_body(buf); + if (ret < 0) + { + close(); + break; + } + else if (ret == 0) + break; + if (hp) + hp->update(buf.c_str(), ret); + else + out.append(buf); + } + + if (hp) + { + hp->update_end(); + delete hp; + } + return true; +} + +void http_request::set_charset(const char* to_charset) +{ + if (client_ == NULL || to_charset == NULL || *to_charset == 0) + { + if (conv_) + { + delete conv_; + conv_ = NULL; + } + return; + } + + // 需要获得响应头字符集信息 + const char* ptr = client_->header_value("Content-Type"); + if (ptr == NULL || *ptr == 0) + { + if (conv_) + { + delete conv_; + conv_ = NULL; + } + return; + } + + http_ctype ctype; + ctype.parse(ptr); + + const char* from_charset = ctype.get_charset(); + if (from_charset && strcasecmp(from_charset, to_charset) != 0) + { + if (conv_ == NULL) + conv_ = charset_conv::create(from_charset, to_charset); + else if (conv_->update_begin(from_charset, to_charset) == false) + { + logger_error("invalid charset conv, from %s, to %s", + from_charset, to_charset); + delete conv_; + conv_ = NULL; + } + } + else if (conv_) + { + delete conv_; + conv_ = NULL; + } +} + +int http_request::read_body(string& out, bool clean /* = NULL */, + int* real_size /* = NULL */) +{ + if (clean) + out.clear(); + if (client_ == NULL) + return -1; + + int ret; + if (conv_ == NULL) + { + ret = client_->read_body(out, clean, real_size); + if (ret < 0) + close(); + return ret; + } + + string buf(4096); + ret = client_->read_body(buf, true, real_size); + if (ret < 0) + { + conv_->update_finish(&out); + close(); + } + else if (ret == 0) + conv_->update_finish(&out); + else if (ret > 0) + conv_->update(buf.c_str(), ret, &out); + + return ret; +} + +int http_request::get_body(char* buf, size_t size) +{ + if (client_ == NULL) + return -1; + return client_->read_body(buf, size); +} + +const std::vector* http_request::get_cookies() const +{ + if (cookies_ && cookie_inited_) + return cookies_; + const_cast(this)->create_cookies(); + if (cookie_inited_ == false) + return NULL; + return cookies_; +} + +const HttpCookie* http_request::get_cookie(const char* name, + bool case_insensitive /* = true */) const +{ + if (!cookie_inited_) + const_cast(this)->create_cookies(); + if (cookies_ == NULL) + return NULL; + std::vector::const_iterator cit = cookies_->begin(); + for (; cit != cookies_->end(); ++cit) + { + if (case_insensitive) + { + if (strcasecmp((*cit)->getName(), name) == 0) + { + return *cit; + } + } + else if (strcmp((*cit)->getName(), name) == 0) + { + return *cit; + } + } + return NULL; +} + +void http_request::create_cookies() +{ + acl_assert(cookie_inited_ == false); + if (client_ == NULL) + return; + const HTTP_HDR_RES* res = client_->get_respond_head(NULL); + if (res == NULL) + return; + + if (cookies_ == NULL) + cookies_ = NEW std::vector; + + int n = acl_array_size(res->hdr.entry_lnk); + for (int i = 0; i < n; i++) + { + const HTTP_HDR_ENTRY* hdr = (const HTTP_HDR_ENTRY*) + acl_array_index(res->hdr.entry_lnk, i); + if (strcasecmp(hdr->name, "Set-Cookie") != 0) + continue; + if (hdr->value == NULL || *(hdr->value) == 0) + continue; + HttpCookie* cookie = NEW HttpCookie(); + if (cookie->setCookie(hdr->value) == false) + { + cookie->destroy(); + continue; + } + cookies_->push_back(cookie); + } + cookie_inited_ = true; +} + +} // namespace acl diff --git a/lib_acl_cpp/src/http/http_request_pool.cpp b/lib_acl_cpp/src/http/http_request_pool.cpp new file mode 100644 index 000000000..48ea6256f --- /dev/null +++ b/lib_acl_cpp/src/http/http_request_pool.cpp @@ -0,0 +1,36 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/http/http_request.hpp" +#include "acl_cpp/http/http_request_pool.hpp" + +namespace acl +{ + +http_reuqest_pool::http_reuqest_pool(const char* addr, + int count, int retry_inter /* = 0 */) +: connect_pool(addr, count, retry_inter) +{ + conn_timeout_ = 30; + rw_timeout_ = 30; +} + +http_reuqest_pool::~http_reuqest_pool() +{ + +} + +http_reuqest_pool& http_reuqest_pool::set_timeout(int conn_timeout /* = 30 */, + int rw_timeout /* = 60 */) +{ + conn_timeout_ = conn_timeout; + rw_timeout_ = rw_timeout; + return *this; +} + +connect_client* http_reuqest_pool::create_connect() +{ + http_request* request = NEW http_request(addr_, + conn_timeout_, rw_timeout_); + return request; +} + +} // namespace acl diff --git a/lib_acl_cpp/src/http/http_response.cpp b/lib_acl_cpp/src/http/http_response.cpp new file mode 100644 index 000000000..44eb91f31 --- /dev/null +++ b/lib_acl_cpp/src/http/http_response.cpp @@ -0,0 +1,324 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/stdlib/xml.hpp" +#include "acl_cpp/stdlib/json.hpp" +#include "acl_cpp/stdlib/string.hpp" +#include "acl_cpp/stream/ostream.hpp" +#include "acl_cpp/http/http_header.hpp" +#include "acl_cpp/http/http_ctype.hpp" +#include "acl_cpp/http/http_pipe.hpp" +#include "acl_cpp/http/http_client.hpp" +#include "acl_cpp/http/http_response.hpp" + +namespace acl +{ + +http_response::http_response(socket_stream* client) +{ + debug_ = false; + header_ok_ = false; + client_ = NEW http_client(client); +} + +http_response::~http_response(void) +{ + close(); +} + +void http_response::close() +{ + if (client_) + { + delete client_; + client_ = NULL; + } +} + +http_header& http_response::response_header() +{ + return header_; +} + +http_client* http_response::get_client() const +{ + return client_; +} + +bool http_response::read_header() +{ + if (client_) + { + client_->reset(); + header_.reset(); + } + else + { + logger_error("client_ not opened"); + header_ok_ = false; + return false; + } + + // 读取客户端的请求头并进行分析 + + if (client_->read_head() == false) + { + close(); + header_ok_ = false; + return false; + } + header_ok_ = true; + return true; +} + +http_pipe* http_response::get_pipe(const char* to_charset) +{ + if (to_charset == NULL || *to_charset == 0) + return NULL; + + // 需要获得响应头字符集信息 + const char* ptr = client_->header_value("Content-Type"); + if (ptr == NULL || *ptr == 0) + return NULL; + + http_ctype ctype; + ctype.parse(ptr); + + const char* from_charset = ctype.get_charset(); + + if (from_charset && strcasecmp(from_charset, to_charset) != 0) + { + http_pipe* hp = NEW http_pipe(); + hp->set_charset(from_charset, to_charset); + return hp; + } + else + return NULL; +} + +bool http_response::get_body(xml& out, const char* to_charset /* = NULL */) +{ + if (header_ok_ == false) + { + logger_error("header not read yet"); + return false; + } else if (client_->body_length() == 0) + return true; + else if (client_->body_length() < 0) + { + const char* method = client_->request_method(); + if (method && (strcmp(method, "GET") == 0 + || strcmp(method, "CONNECT") == 0)) + { + return true; + } + + logger_error("client request body length(%d) invalid", + (int) client_->body_length()); + return false; + } + + if (debug_) + client_->print_header("----request---"); + + http_pipe* hp = get_pipe(to_charset); + if (hp) + hp->append(&out); + + string buf; + int ret; + + while (true) + { + // 循环读取客户端请求数据体 + ret = client_->read_body(buf); + if (ret == 0) + break; + if (ret < 0) + { + logger_error("read client body error"); + close(); + return false; + } + + // 流式分析 xml 格式的数据体 + if (hp) + hp->update(buf.c_str(), ret); + else + out.update(buf.c_str()); + if (debug_) + printf("%s", buf.c_str()); + } + + if (hp) + { + hp->update_end(); + delete hp; + } + return true; +} + +bool http_response::get_body(json& out, const char* to_charset /* = NULL */) +{ + if (header_ok_ == false) + { + logger_error("header not read yet"); + return false; + } else if (client_->body_length() == 0) + return true; + else if (client_->body_length() < 0) + { + const char* method = client_->request_method(); + if (method && (strcmp(method, "GET") == 0 + || strcmp(method, "CONNECT") == 0)) + { + return true; + } + + logger_error("client request body length(%d) invalid", + (int) client_->body_length()); + return false; + } + + if (debug_) + client_->print_header("----request---"); + + http_pipe* hp = get_pipe(to_charset); + if (hp) + hp->append(&out); + + string buf; + int ret; + + while (true) + { + // 循环读取客户端请求数据体 + ret = client_->read_body(buf); + if (ret == 0) + break; + if (ret < 0) + { + logger_error("read client body error"); + close(); + return false; + } + + // 流式分析 json 格式的数据体 + if (hp) + hp->update(buf.c_str(), ret); + else + out.update(buf.c_str()); + if (debug_) + printf("%s", buf.c_str()); + } + + if (hp) + { + hp->update_end(); + delete hp; + } + return true; +} + +bool http_response::get_body(string& out, const char* to_charset /* = NULL */) +{ + if (header_ok_ == false) + { + logger_error("header not read yet"); + return false; + } + else if (client_->body_length() == 0) + return true; + else if (client_->body_length() < 0) + { + const char* method = client_->request_method(); + if (method && (strcmp(method, "GET") == 0 + || strcmp(method, "CONNECT") == 0)) + { + return true; + } + + logger_error("client request body length(%d) invalid", + (int) client_->body_length()); + return false; + } + + http_pipe* hp = get_pipe(to_charset); + if (hp) + { + pipe_string ps(out); + hp->append(&ps); + } + + string buf; + int ret; + // 读 HTTP 请求体 + while (true) + { + ret = client_->read_body(buf); + if (ret < 0) + { + close(); + break; + } + else if (ret == 0) + break; + if (hp) + hp->update(buf.c_str(), ret); + else + out.append(buf); + } + + if (hp) + { + hp->update_end(); + delete hp; + } + return true; +} + +int http_response::get_body(char* buf, size_t size) +{ + if (header_ok_ == false) + { + logger_error("header not read yet"); + return -1; + } + return client_->read_body(buf, size); +} + +bool http_response::response(const char* body, size_t len, + int status /* = 200 */, bool keep_alive /* = true */) +{ + if (client_ == NULL) + { + logger_error("conn not opened"); + return false; + } + + // 构建 HTTP 响应头 + header_.set_status(status); + header_.set_keep_alive(keep_alive); + if (body && len > 0) + header_.set_content_length(len); + + // 写 HTTP 响应头 + if (client_->write(header_) == false) + { + close(); + return false; + } + + if (body == NULL || len == 0) + return true; + + // 一次性将 HTTP 响应头及响应体写入流中 + // 写 HTTP 请求体 + if (client_->get_ostream().write(body, len) == -1) + { + close(); + return false; + } + return true; +} + +} // namespace acl diff --git a/lib_acl_cpp/src/http/http_service.cpp b/lib_acl_cpp/src/http/http_service.cpp new file mode 100644 index 000000000..a3c9cc0f6 --- /dev/null +++ b/lib_acl_cpp/src/http/http_service.cpp @@ -0,0 +1,660 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/stdlib/string.hpp" +#include "acl_cpp/stream/aio_socket_stream.hpp" +#include "acl_cpp/stream/socket_stream.hpp" +#include "acl_cpp/ipc/ipc_client.hpp" +#include "acl_cpp/http/http_service.hpp" + +namespace acl +{ + +////////////////////////////////////////////////////////////////////////// + +http_service_request::http_service_request(const char* domain, + unsigned short port) +{ + acl_assert(domain && *domain); + domain_ = acl_mystrdup(domain); + port_ = port; +} + +http_service_request::~http_service_request(void) +{ + acl_myfree(domain_); +} + +const string* http_service_request::get_body() +{ + return (NULL); +} + +const char* http_service_request::get_domain(void) const +{ + return (domain_); +} + +unsigned short http_service_request::get_port(void) const +{ + return (port_); +} + +////////////////////////////////////////////////////////////////////////// + +enum +{ + HTTP_MSG_HDR, + HTTP_MSG_DAT, + HTTP_MSG_ERR, +}; + +struct HTTP_IPC_DAT +{ + http_service_request* callback; + struct + { + HTTP_HDR_RES* hdr_res; + char addr[64]; + } http_hdr; + struct + { + char* ptr; + size_t dlen; + } http_dat; + http_status_t error; +#define i_hdr_res http_hdr.hdr_res +#define i_addr http_hdr.addr +#define i_ptr http_dat.ptr +#define i_dlen http_dat.dlen +#define i_error error +}; + +////////////////////////////////////////////////////////////////////////// + +class http_ipc_request : public ipc_request +{ +public: + http_ipc_request(http_service_request* callback, int nwait) + { + nwait_ = nwait; + memset(&data_, 0, sizeof(data_)); + data_.callback = callback; + hdr_res_ = NULL; + res_ = NULL; + vstream_ = NULL; + respond_over_ = false; + } + + ~http_ipc_request(void) + { + if (res_) + { + res_->hdr_res = NULL; + http_res_free(res_); + } + } + + // 基类 ipc_request 会自动调用此回调处理请求过程 + virtual void run(ipc_client* ipc) + { + unsigned int nredirect_limit = data_.callback->get_redirect(); + unsigned int nredirect = 0; + http_status_t ret; + + while (true) + { + if ((ret = connect_server()) != HTTP_OK) + { + report_error(ipc, ret); + break; + } + if ((ret = send_request()) != HTTP_OK) + { + report_error(ipc, ret); + break; + } + if ((ret = read_respond_hdr()) != HTTP_OK) + { + report_error(ipc, ret); + break; + } + + acl_assert(hdr_res_); + + // 如果服务器返回的是重定向信息,则进行重定向访问 + + if ((hdr_res_->reply_status != 301 + && hdr_res_->reply_status != 302) + || nredirect_limit == 0) + { + // 发送响应头收到消息给主线程 + report(ipc, HTTP_MSG_HDR); + + // 连续接收响应体并发响应体收到消息给主线程 + read_respond_body(ipc); + break; + } + + // 开始重定向过程 + + nredirect++; + // 防止重定向次数太多而造成了循环 + if (nredirect > nredirect_limit) + { + report_error(ipc, HTTP_ERR_REDIRECT_MAX); + break; + } + + const char* url = http_hdr_entry_value( + &hdr_res_->hdr, "Location"); + + if (url == NULL) + { + logger_error("redirect Location null"); + report_error(ipc, HTTP_ERR_INVALID_HDR); + break; + } + if (data_.callback->redirect(url) == false) + { + http_hdr_res_free(hdr_res_); + hdr_res_ = NULL; + report_error(ipc, HTTP_ERR_INVALID_HDR); + break; + } + http_hdr_res_free(hdr_res_); + hdr_res_ = NULL; + data_.callback->redicrect_reset(); + } + + delete this; + } + +#ifdef WIN32 + // 基类会自动调用此回调处理请求过程 + // 基类虚接口,使子线程可以在执行完任务后向主线程发送 WIN32 窗口消息 + virtual void run(HWND hWnd) + { + unsigned int nredirect_limit = data_.callback->get_redirect(); + unsigned int nredirect = 0; + http_status_t ret; + + while (true) + { + if ((ret = connect_server()) != HTTP_OK) + { + report_error(hWnd, ret); + break; + } + if ((ret = send_request()) != HTTP_OK) + { + report_error(hWnd, ret); + break; + } + if ((ret = read_respond_hdr()) != HTTP_OK) + { + report_error(hWnd, ret); + break; + } + + acl_assert(hdr_res_); + + // 如果服务器返回的是重定向信息,则进行重定向访问 + + if ((hdr_res_->reply_status != 301 + && hdr_res_->reply_status != 302) + || nredirect_limit == 0) + { + // 发送响应头收到消息给主线程 + report(hWnd, HTTP_MSG_HDR); + + // 连续接收响应体并发响应体收到消息给主线程 + read_respond_body(hWnd); + break; + } + + // 开始重定向过程 + + nredirect++; + // 防止重定向次数太多而造成了循环 + if (nredirect > nredirect_limit) + { + report_error(hWnd, HTTP_ERR_REDIRECT_MAX); + break; + } + + const char* url = http_hdr_entry_value( + &hdr_res_->hdr, "Location"); + + if (url == NULL) + { + logger_error("redirect Location null"); + report_error(hWnd, HTTP_ERR_INVALID_HDR); + break; + } + if (data_.callback->redirect(url) == false) + { + http_hdr_res_free(hdr_res_); + hdr_res_ = NULL; + report_error(hWnd, HTTP_ERR_INVALID_HDR); + break; + } + http_hdr_res_free(hdr_res_); + hdr_res_ = NULL; + data_.callback->redicrect_reset(); + } + + delete this; + } +#endif +protected: +private: + int nwait_; + HTTP_IPC_DAT data_; + socket_stream client_; + ACL_VSTREAM* vstream_; + char addr_[64]; + HTTP_HDR_RES* hdr_res_; + HTTP_RES* res_; + bool respond_over_; + + void report_error(ipc_client* ipc, http_status_t errnum) + { + data_.i_hdr_res = hdr_res_; + data_.i_error = errnum; + ipc->send_message(HTTP_MSG_ERR, &data_, sizeof(data_)); + } + + void report(ipc_client* ipc, unsigned int nMsg) + { + data_.i_hdr_res = hdr_res_; + data_.i_error = HTTP_OK; + ipc->send_message(nMsg, &data_, sizeof(data_)); + } + +#ifdef WIN32 + void report_error(HWND hWnd, http_status_t errnum) + { + HTTP_IPC_DAT* data = (HTTP_IPC_DAT*) + acl_mymalloc(sizeof(HTTP_IPC_DAT)); + memcpy(data, &data_, sizeof(HTTP_IPC_DAT)); + data->i_hdr_res = hdr_res_; + data->i_error = errnum; + // 向主线程发送结果 + ::PostMessage(hWnd, HTTP_MSG_ERR + WM_USER, 0, (LPARAM) data); + } + + void report(HWND hWnd, UINT nMsg) + { + HTTP_IPC_DAT* data = (HTTP_IPC_DAT*) + acl_mymalloc(sizeof(HTTP_IPC_DAT)); + memcpy(data, &data_, sizeof(HTTP_IPC_DAT)); + data->i_hdr_res = hdr_res_; + data->i_error = HTTP_OK; + ::PostMessage(hWnd, nMsg + WM_USER, 0, (LPARAM) data); + } +#endif + + http_status_t connect_server(void) + { + string addr(data_.callback->get_domain()); + addr << ':' << data_.callback->get_port(); + + if (client_.opened()) + client_.close(); + + if (client_.open(addr.c_str(), 60, 60) == false) + { + logger_error("connect %s error(%s)", + addr.c_str(), acl_last_serror()); + return (HTTP_ERR_CONN); + } + + vstream_ = client_.get_vstream(); + return (HTTP_OK); + } + + http_status_t send_request(void) + { + string hdr_req; + if (data_.callback->build_request(hdr_req) == false) + return (HTTP_ERR_REQ); + + // 写 HTTP 请求头 + if (client_.write(hdr_req.c_str(), hdr_req.length()) == false) + return (HTTP_ERR_SEND); + + // 循环从请求对象中获得请求体数据,并写 HTTP 请求体数据 + while (true) + { + const string* data = data_.callback->get_body(); + if (data == NULL || data->empty()) + break; + if (client_.write(data->c_str(), data->length()) == false) + return (HTTP_ERR_SEND); + } + return (HTTP_OK); + } + + http_status_t read_respond_hdr(void) + { + acl_assert(vstream_); + snprintf(data_.i_addr, sizeof(data_.i_addr), + "%s", ACL_VSTREAM_PEER(vstream_)); + hdr_res_ = http_hdr_res_new(); + int ret = http_hdr_res_get_sync(hdr_res_, vstream_, 60); + if (ret < 0) + { + logger_error("get http respond hdr from %s error %s", + data_.i_addr, acl_last_serror()); + http_hdr_res_free(hdr_res_); + hdr_res_ = NULL; + return (HTTP_ERR_READ_HDR); + } + + if (http_hdr_res_parse(hdr_res_) < 0) + { + logger_error("parse http respond hdr error from %s", + data_.i_addr); + + http_hdr_res_free(hdr_res_); + hdr_res_ = NULL; + return (HTTP_ERR_INVALID_HDR); + } + + return (HTTP_OK); + } + + void read_respond_body(ipc_client* ipc) + { + acl_assert(hdr_res_); + + /* 如果 HTTP 响应没有数据体则仅输出 HTTP 响应头即可 */ + + if (hdr_res_->hdr.content_length == 0 + || (hdr_res_->hdr.content_length == -1 + && hdr_res_->reply_status > 300 + && hdr_res_->reply_status < 400)) + { + data_.i_ptr = NULL; + data_.i_dlen = 0; + // 如果没有数据体,也发送消息通知调用者数据结束 + report(ipc, HTTP_MSG_DAT); + return; + } + + res_ = http_res_new(hdr_res_); + +#define BUF_LEN 8192 + + char* buf; + int ret; + + while (true) + { + buf = (char*) acl_mymalloc(BUF_LEN); + ret = read_respond_body(buf, BUF_LEN - 1); + if (ret <= 0) + { + acl_myfree(buf); + break; + } + buf[ret] = 0; + + data_.i_ptr = buf; + data_.i_dlen = ret; + report(ipc, HTTP_MSG_DAT); + + if (respond_over_) + break; + if (nwait_ > 0) + acl_doze(nwait_); + } + + data_.i_ptr = NULL; + data_.i_dlen = 0; + report(ipc, HTTP_MSG_DAT); + } + +#ifdef WIN32 + void read_respond_body(HWND hWnd) + { + acl_assert(hdr_res_); + + /* 如果 HTTP 响应没有数据体则仅输出 HTTP 响应头即可 */ + + if (hdr_res_->hdr.content_length == 0 + || (hdr_res_->hdr.content_length == -1 + && hdr_res_->reply_status > 300 + && hdr_res_->reply_status < 400)) + { + data_.i_ptr = NULL; + data_.i_dlen = 0; + // 如果没有数据体,也发送消息通知调用者数据结束 + report(hWnd, HTTP_MSG_DAT); + return; + } + + res_ = http_res_new(hdr_res_); + +#define BUF_LEN 8192 + + char* buf; + int ret; + + while (true) + { + buf = (char*) acl_mymalloc(BUF_LEN); + ret = read_respond_body(buf, BUF_LEN - 1); + if (ret <= 0) + { + acl_myfree(buf); + break; + } + buf[ret] = 0; + + data_.i_ptr = buf; + data_.i_dlen = (size_t) ret; + report(hWnd, HTTP_MSG_DAT); + + if (respond_over_) + break; + if (nwait_ > 0) + acl_doze(nwait_); + } + + data_.i_ptr = NULL; + data_.i_dlen = 0; + report(hWnd, HTTP_MSG_DAT); + } +#endif + + int read_respond_body(char* buf, int dlen) + { + acl_assert(vstream_); + acl_assert(res_); + + char* ptr = buf; + int dlen_saved = dlen; + int ret; + + // 因为 buf 是动态分配的,所以应尽量让 buf 填满, + // 这样可以节省内存分配的消耗 + + while (true) + { + ret = (int) http_res_body_get_sync(res_, vstream_, + ptr, dlen); + if (ret <= 0) + { + respond_over_ = true; + break; + } + dlen -= ret; + if (dlen <= 0) + break; + ptr += ret; + } + + return (dlen_saved - dlen); + } +}; + +////////////////////////////////////////////////////////////////////////// + +class http_ipc : public ipc_client +{ +public: + http_ipc(void) + { + + } + + ~http_ipc(void) + { + + } + + virtual void on_message(int nMsg, void* data, int dlen) + { + acl_assert(dlen == sizeof(HTTP_IPC_DAT)); + HTTP_IPC_DAT* dat = (HTTP_IPC_DAT*) data; + + switch (nMsg) + { + case HTTP_MSG_HDR: + dat->callback->on_hdr(dat->i_addr, dat->i_hdr_res); + break; + case HTTP_MSG_DAT: + dat->callback->on_body(dat->i_ptr, dat->i_dlen); + if (dat->i_ptr && dat->i_dlen > 0) + acl_myfree(dat->i_ptr); + else + { + // 调用请求对象的销毁过程 + dat->callback->destroy(); + if (dat->i_hdr_res) + http_hdr_res_free(dat->i_hdr_res); + this->close(); // 自动触发析构过程 + } + break; + case HTTP_MSG_ERR: + dat->callback->on_error(dat->i_error); + // 调用请求对象的销毁过程 + dat->callback->destroy(); + if (dat->i_hdr_res) + http_hdr_res_free(dat->i_hdr_res); + this->close(); // 自动触发析构过程 + break; + default: + // 出现了异常消息 + logger_error("unknown ipc msg: %d", nMsg); + break; + } + } +protected: + virtual void on_close(void) + { + delete this; + } +private: + HTTP_HDR_RES* hdr_res_; +}; + +////////////////////////////////////////////////////////////////////////// + +http_service::http_service(int nthread /* = 1 */, int nwait, + bool win32_gui /* = false */) +: ipc_service(nthread, win32_gui) +, addr_(NULL) +, nwait_(nwait) +, handle_type_(ENGINE_SELECT) +{ + +} + +http_service::~http_service() +{ + if (addr_) + acl_myfree(addr_); +} + +#ifdef WIN32 + +void http_service::win32_proc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam) +{ + if (lParam == 0) + return; + + HTTP_IPC_DAT* dat = (HTTP_IPC_DAT*) lParam; + + switch (nMsg - WM_USER) + { + case HTTP_MSG_HDR: + dat->callback->on_hdr(dat->i_addr, dat->i_hdr_res); + acl_myfree(dat); + break; + case HTTP_MSG_DAT: + dat->callback->on_body(dat->i_ptr, dat->i_dlen); + if (dat->i_ptr && dat->i_dlen > 0) + acl_myfree(dat->i_ptr); + else + { + // 调用请求对象的销毁过程 + dat->callback->destroy(); + if (dat->i_hdr_res) + http_hdr_res_free(dat->i_hdr_res); + } + acl_myfree(dat); + break; + case HTTP_MSG_ERR: + dat->callback->on_error(dat->i_error); + // 调用请求对象的销毁过程 + dat->callback->destroy(); + if (dat->i_hdr_res) + http_hdr_res_free(dat->i_hdr_res); + acl_myfree(dat); + break; + default: + // 出现了异常消息 + logger_error("unknown ipc msg: %d", nMsg); + break; + } +} + +#endif + +void http_service::on_accept(aio_socket_stream* client) +{ + ipc_client* ipc = NEW http_ipc(); + ipc->open(client); + + // 添加消息处理 + + ipc->append_message(HTTP_MSG_HDR); + ipc->append_message(HTTP_MSG_DAT); + ipc->append_message(HTTP_MSG_ERR); + + // 异步等待消息 + ipc->wait(); +} + +void http_service::on_open(const char*addr) +{ + aio_handle& handle = get_handle(); + handle_type_ = handle.get_engine_type(); + addr_ = acl_mystrdup(addr); +} + +void http_service::on_close(void) +{ + +} + +void http_service::do_request(http_service_request* req) +{ + http_ipc_request* ipc_req = NEW http_ipc_request(req, nwait_); + // 调用基类 ipc_service 请求过程 + request(ipc_req); +} + +} diff --git a/lib_acl_cpp/src/http/http_utils.cpp b/lib_acl_cpp/src/http/http_utils.cpp new file mode 100644 index 000000000..219cf29b6 --- /dev/null +++ b/lib_acl_cpp/src/http/http_utils.cpp @@ -0,0 +1,45 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/http/http_utils.hpp" + +namespace acl +{ + +bool http_utils::get_addr(const char* url, char* out, size_t size) +{ + if (strncasecmp(url, "http://", sizeof("http://") - 1) != 0) + { + logger_error("invalid url: %s", url); + return false; + } + + const char* ptr = url + sizeof("http://") - 1; + if (*ptr == 0) + { + logger_error("invalid url: %s", url); + return false; + } + + char buf[256]; + ACL_SAFE_STRNCPY(buf, ptr, sizeof(buf)); + + char* slash = strchr(buf, '/'); + if (slash) + *slash = 0; + unsigned short port; + char* col = strchr(buf, ':'); + if (col == NULL) + port = 80; + else + { + *col++ = 0; + port = (unsigned short) atoi(col); + if (port < 80) + port = 80; + } + + snprintf(out, size, "%s:%d", buf, port); + return true; +} + +} // namespace acl diff --git a/lib_acl_cpp/src/ipc/ipc_client.cpp b/lib_acl_cpp/src/ipc/ipc_client.cpp new file mode 100644 index 000000000..1b775ff2c --- /dev/null +++ b/lib_acl_cpp/src/ipc/ipc_client.cpp @@ -0,0 +1,331 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/stream/socket_stream.hpp" +#include "acl_cpp/stream/aio_socket_stream.hpp" +#include "acl_cpp/stream/aio_handle.hpp" +#include "acl_cpp/stdlib/string.hpp" +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/ipc/ipc_client.hpp" + +namespace acl +{ + +ipc_client::ipc_client() + : addr_(NULL) + , async_stream_(NULL) + , sync_stream_(NULL) + , sync_stream_inner_(NULL) + , closing_(false) + , status_(IO_WAIT_HDR) +{ + +} + +ipc_client::~ipc_client() +{ + messages_.clear(); + + if (addr_) + acl_myfree(addr_); + if (async_stream_ && !closing_) + async_stream_->close(); + if (sync_stream_inner_) + delete sync_stream_inner_; +} + +void ipc_client::on_message(int nMsg, void* data, int dlen) +{ + (void) nMsg; + (void) data; + (void) dlen; + + // 子类必须实现该接口 + logger_fatal("ipc_client be called here"); +} + +bool ipc_client::open(aio_handle* handle, const char* addr, int timeout) +{ + acl_assert(sync_stream_ == NULL && async_stream_ == NULL); + + async_stream_ = aio_socket_stream::open(handle, addr, timeout); + if (async_stream_ == NULL) + return (false); + addr_ = acl_mystrdup(addr); + + // 添加连接成功的回调函数类 + async_stream_->add_open_callback(this); + + // 添加连接失败后回调函数类 + async_stream_->add_close_callback(this); + + // 添加连接超时的回调函数类 + async_stream_->add_timeout_callback(this); + return (true); +} + +void ipc_client::open(aio_socket_stream* client) +{ + acl_assert(client); + acl_assert(sync_stream_ == NULL && async_stream_ == NULL); + + async_stream_ = client; + + // 注册异步流的读回调过程 + client->add_read_callback(this); + + // 注册异步流的写回调过程 + client->add_write_callback(this); + + // 添加连接失败后回调函数类 + client->add_close_callback(this); + + // 添加连接超时的回调函数类 + client->add_timeout_callback(this); +} + +bool ipc_client::open(const char* addr, int timeout) +{ + acl_assert(sync_stream_ == NULL && async_stream_ == NULL); + sync_stream_ = NEW socket_stream(); + if (sync_stream_->open(addr, timeout, 0) == false) + { + delete sync_stream_; + sync_stream_ = NULL; + return (false); + } + sync_stream_inner_ = sync_stream_; + return (true); +} + +void ipc_client::open(socket_stream* client) +{ + acl_assert(sync_stream_ == NULL && async_stream_ == NULL); + acl_assert(client); + sync_stream_ = client; +} + +void ipc_client::wait() +{ + if (closing_) + return; + + // 同步接收消息 + if (sync_stream_) + { + MSG_HDR hdr; + int n; + n = sync_stream_->read(&hdr, sizeof(hdr)); + if (n < 0) + { + close(); + return; + } + if ((n = hdr.dlen) <= 0) + { + trigger(hdr.nMsg, NULL, 0); + return; + } + string buf(n); + + if (sync_stream_->read(buf.c_str(), n) < 0) + { + close(); + return; + } + trigger(hdr.nMsg, buf.c_str(), n); + } + + // 异步接收消息 + else if (async_stream_) + { + // 进入异步读消息过程 + status_ = IO_WAIT_HDR; + async_stream_->read(sizeof(MSG_HDR)); + } + + // 未知情况 + else + acl_assert(0); +} + +void ipc_client::close() +{ + if (closing_) + return; + + closing_ = true; + + if (async_stream_) + async_stream_->close(); + else if (sync_stream_inner_) + { + delete sync_stream_inner_; + sync_stream_inner_ = sync_stream_ = NULL; + } +} + +bool ipc_client::active() const +{ + if (closing_) + return false; + else if (async_stream_ != NULL || sync_stream_ != NULL) + return true; + else + return false; +} + +aio_socket_stream* ipc_client::get_async_stream() const +{ + acl_assert(async_stream_); + return (async_stream_); +} + +aio_handle& ipc_client::get_handle() const +{ + return (get_async_stream()->get_handle()); +} + +socket_stream* ipc_client::get_sync_stream() const +{ + acl_assert(sync_stream_); + return (sync_stream_); +} + +void ipc_client::append_message(int nMsg) +{ + std::list::iterator it = messages_.begin(); + + // 该消息是否已经存在于已经注册的消息集合中 + for (; it != messages_.end(); ++it) + { + if (*it == nMsg) + return; + } + + messages_.push_back(nMsg); +} + +void ipc_client::delete_message(int nMsg) +{ + std::list::iterator it = messages_.begin(); + + // 该消息是否已经存在于已经注册的消息集合中 + for (; it != messages_.end(); ++it) + { + if (*it == nMsg) + { + messages_.erase(it); + break; + } + } +} + +void ipc_client::send_message(int nMsg, const void* data, int dlen) +{ + struct MSG_HDR hdr; + + hdr.nMsg = nMsg; + hdr.dlen = dlen > 0 ? dlen : 0; + + // 发送消息头 + if (sync_stream_ != NULL) + sync_stream_->write(&hdr, sizeof(hdr)); + else if (async_stream_ != NULL) + async_stream_->write(&hdr, sizeof(hdr)); + else + acl_assert(0); + + // 发关消息体 + if (data && dlen > 0) + { + if (sync_stream_ == NULL) + async_stream_->write(data, dlen); + else if (sync_stream_->write(data, dlen) < 0) + close(); + } +} + +void ipc_client::trigger(int nMsg, void* data, int dlen) +{ + std::list::iterator it = messages_.begin(); + + // 该消息是否已经存在于已经注册的消息集合中 + for (; it != messages_.end(); ++it) + { + if (*it == nMsg) + { + on_message(nMsg, data, dlen); + return; + } + } + + logger_warn("unknown msg: %d", nMsg); +} + +bool ipc_client::read_callback(char* data, int len) +{ + if (status_ == IO_WAIT_HDR) + { + acl_assert(len == sizeof(MSG_HDR)); + MSG_HDR* hdr = (MSG_HDR*) data; + if (hdr->dlen > 0) + { + hdr_.nMsg = hdr->nMsg; + hdr_.dlen = hdr->dlen; + // 如果有消息体则继续读消息体 + status_ = IO_WAIT_DAT; + async_stream_->read(hdr->dlen); + return (true); + } + + // 消息处理过程 + trigger(hdr->nMsg, NULL, 0); + + // 异步等待下一条消息 + wait(); + return (true); + } + else if (status_ == IO_WAIT_DAT) + { + acl_assert(len == hdr_.dlen); + trigger(hdr_.nMsg, data, len); + + // 异步等待下一条消息 + wait(); + return (true); + } + else + acl_assert(0); + + return (true); +} + +bool ipc_client::write_callback() +{ + return (true); +} + +void ipc_client::close_callback() +{ + // 通知子类关闭IPC异步流 + on_close(); +} + +bool ipc_client::timeout_callback() +{ + return (true); +} + +bool ipc_client::open_callback() +{ + // 连接成功,设置IO读写回调函数 + async_stream_->add_read_callback(this); + async_stream_->add_write_callback(this); + + // 通知子类连接消息服务器成功 + on_open(); + + // 返回 true 表示继续异步过程 + return (true); +} + +} // namespace acl diff --git a/lib_acl_cpp/src/ipc/ipc_server.cpp b/lib_acl_cpp/src/ipc/ipc_server.cpp new file mode 100644 index 000000000..fb2e3f32a --- /dev/null +++ b/lib_acl_cpp/src/ipc/ipc_server.cpp @@ -0,0 +1,90 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/stream/aio_socket_stream.hpp" +#include "acl_cpp/stream/aio_listen_stream.hpp" +#include "acl_cpp/stream/aio_handle.hpp" +#include "acl_cpp/ipc/ipc_server.hpp" + +namespace acl +{ + +ipc_server::ipc_server() + : handle_(NULL) + , sstream_(NULL) +{ + +} + +ipc_server::~ipc_server() +{ + if (sstream_) + sstream_->close(); +} + +bool ipc_server::open(aio_handle* handle, const char* addr /* = "127.0.0.1:0" */) +{ + if (handle == NULL) + logger_fatal("handle null"); + else + handle_ = handle; + +#ifdef WIN32 + // 如果事件引擎是基于 WIN32 窗口消息,则直接返回 + if (handle->get_engine_type() == ENGINE_WINMSG) + return create_window(); +#endif + + if (addr == NULL) + addr = "127.0.0.1:0"; + sstream_ = NEW aio_listen_stream(handle); + if (sstream_->open(addr) == false) + { + logger_error("listen %s error(%s)", + addr, acl_last_serror()); + sstream_->destroy(); + sstream_ = NULL; + return (false); + } + sstream_->add_accept_callback(this); + + // 调用子类处理过程 + on_open(get_addr()); + + return (true); +} + +bool ipc_server::accept_callback(aio_socket_stream* client) +{ + on_accept(client); + return (true); +} + +void ipc_server::close_callback() +{ + // 调用子类处理过程 + on_close(); +} + +bool ipc_server::timeout_callback() +{ + return true; +} + +const char* ipc_server::get_addr() const +{ + acl_assert(sstream_); + return (sstream_->get_addr()); +} + +aio_listen_stream* ipc_server::get_stream() const +{ + acl_assert(sstream_); + return (sstream_); +} + +aio_handle& ipc_server::get_handle() const +{ + return (*handle_); +} + +} // namespace acl diff --git a/lib_acl_cpp/src/ipc/ipc_service.cpp b/lib_acl_cpp/src/ipc/ipc_service.cpp new file mode 100644 index 000000000..55a5cec76 --- /dev/null +++ b/lib_acl_cpp/src/ipc/ipc_service.cpp @@ -0,0 +1,389 @@ +#include "acl_stdafx.hpp" +#include +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/stdlib/util.hpp" +#include "acl_cpp/stream/socket_stream.hpp" +#include "acl_cpp/ipc/ipc_client.hpp" +#include "acl_cpp/ipc/ipc_server.hpp" +#include "acl_cpp/ipc/ipc_service.hpp" + +namespace acl +{ + +////////////////////////////////////////////////////////////////////////// + +ipc_request::ipc_request() +{ +#ifdef WIN32 + hWnd_ = NULL; +#endif +} + +ipc_request::~ipc_request() +{ + +} + +void ipc_request::run(ipc_client* ipc acl_unused) +{ + logger_fatal("ipc_request::run(ipc_client*) be called now"); +} + +#ifdef WIN32 +void ipc_request::run(HWND hWnd acl_unused) +{ + logger_fatal("ipc_request::run(HWND) be called now"); +} +#endif +////////////////////////////////////////////////////////////////////////// + +struct REQ_CTX +{ + char addr[256]; + ipc_request* req; + ipc_service* service; +}; + +static void thread_pool_main(REQ_CTX* ctx) +{ + +#ifdef WIN32 + HWND hWnd = ctx->req->get_hwnd(); + if (hWnd != NULL) + ctx->req->run(hWnd); + else +#endif + if (ctx->service) + { + ipc_client* ipc = ctx->service->peek_conn(); + if (ipc == NULL) + { + logger_error("peek connect to %s error: %s", + ctx->addr, last_serror()); + } + else + { + ctx->req->run(ipc); + + // 如果该连接流依然正常,则放入连接池中 + if (ipc->active()) + ctx->service->push_conn(ipc); + + // 否则则释放动态对象 + else + delete ipc; + } + } + else + { + // IO 消息模式 + + ipc_client* ipc = NEW ipc_client(); + + // 连接消息服务器, 采用同步IPC通道方式 + if (ipc->open(ctx->addr, 0) == false) + logger_error("open %s error(%s)", + ctx->addr, last_serror()); + + // 调用子类的阻塞处理过程 + else + ctx->req->run(ipc); + + // 销毁 IPC 流 + delete ipc; + } + + // 释放在主线程中分配的对象 + acl_myfree(ctx); +} + +static void* thread_once_main(REQ_CTX* ctx) +{ +#ifdef WIN32 + HWND hWnd = ctx->req->get_hwnd(); + if (hWnd != NULL) + ctx->req->run(hWnd); + else +#endif + if (ctx->service) + { + ipc_client* ipc = ctx->service->peek_conn(); + if (ipc == NULL) + { + logger_error("peek connect to %s error: %s", + ctx->addr, last_error()); + } + else + { + ctx->req->run(ipc); + + // 如果该连接流依然正常,则放入连接池中 + if (ipc->active()) + ctx->service->push_conn(ipc); + + // 否则则释放动态对象 + else + delete ipc; + } + } + else + { + // IO 消息模式 + + ipc_client* ipc = NEW ipc_client(); + + // 连接消息服务器 + if (ipc->open(ctx->addr, 0) == false) + logger_error("open %s error(%s)", + ctx->addr, acl_last_serror()); + + // 调用子类的阻塞处理过程 + else + ctx->req->run(ipc); + // 销毁 IPC 流 + delete ipc; + } + + // 释放在主线程中分配的对象 + acl_myfree(ctx); + return (NULL); +} + +/////////////////////////////////////////////////////////////////////////// + +#ifdef WIN32 + +static LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, + WPARAM wParam, LPARAM lParam) +{ + ipc_service* service = (ipc_service*) + GetWindowLongPtr(hWnd, GWL_USERDATA); + if (service == NULL) + return (DefWindowProc(hWnd, msg, wParam, lParam)); + + // 调用子类的消息处理过程,消息号必须是 >= WM_USER + if (msg >= WM_USER) + service->win32_proc(hWnd, msg, wParam, lParam); + return (DefWindowProc(hWnd, msg, wParam, lParam)); +} + +static BOOL InitApplication(const char *class_name, HINSTANCE hInstance) +{ + const char *myname = "InitApplication"; + WNDCLASSEX wcx; + + if (GetClassInfoEx(hInstance, class_name, &wcx)) + { + // class already registered + logger_warn("class(%s) already registered", class_name); + return TRUE; + } + + // Fill in the window class structure with parameters + // that describe the main window. + + memset(&wcx, 0, sizeof(wcx)); + + wcx.cbSize = sizeof(wcx); // size of structure + wcx.style = CS_HREDRAW | CS_VREDRAW; + wcx.lpfnWndProc = WndProc; // points to window procedure + wcx.cbClsExtra = 0; // no extra class memory + wcx.cbWndExtra = 0; // no extra window memory + wcx.hInstance = hInstance; // handle to instance + + wcx.hIcon = LoadIcon(NULL, IDI_APPLICATION); // predefined app. icon + wcx.hCursor = (HCURSOR) LoadCursor(NULL, IDC_ARROW); // predefined arrow + wcx.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); // white background brush + wcx.lpszMenuName = NULL; // name of menu resource + wcx.lpszClassName = class_name; // name of window class + wcx.hIconSm = (HICON) LoadImage(hInstance, // small class icon + MAKEINTRESOURCE(5), + IMAGE_ICON, + GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON), + (UINT) LR_DEFAULTCOLOR); + // Register the window class. + if (RegisterClassEx(&wcx) == 0) { + logger_error("RegisterClassEx error(%d, %s)", + acl_last_error(), acl_last_serror()); + return (FALSE); + } else + return (TRUE); +} + +static HWND InitInstance(const char *class_name, HINSTANCE hInstance) +{ + const char *myname = "InitInstance"; + HWND hWnd; + CREATESTRUCT cs; + + cs.dwExStyle = 0; + cs.lpszClass = class_name; + cs.lpszName = "WIN32 IPC Notification"; + cs.style = WS_OVERLAPPED; + cs.x = 0; + cs.y = 0; + cs.cx = 0; + cs.cy = 0; + cs.hwndParent = NULL; + cs.hMenu = NULL; + cs.hInstance = hInstance; + cs.lpCreateParams = NULL; + hWnd = CreateWindowEx(cs.dwExStyle, cs.lpszClass, + cs.lpszName, cs.style, cs.x, cs.y, cs.cx, cs.cy, + cs.hwndParent, cs.hMenu, cs.hInstance, cs.lpCreateParams); + if (hWnd == NULL) + logger_fatal("create window error: %s", acl_last_serror()); + return (hWnd); +} + +static const char *__class_name = "__IpcEventsMainWClass"; + +bool ipc_service::create_window(void) +{ + hInstance_ = GetModuleHandle(NULL); + if (InitApplication(__class_name, hInstance_) == FALSE) + logger_fatal("InitApplication %s error(%s)", + __class_name, acl_last_serror()); + hWnd_ = InitInstance(__class_name, hInstance_); + if (hWnd_ == NULL) + logger_fatal("create %s window error(%s)", + __class_name, acl_last_serror()); + + // 添加窗口句柄的关联对象 + SetWindowLongPtr(hWnd_, GWL_USERDATA, (LONG) this); + + // 调用子类处理过程 + on_open("win32 gui message"); + return true; +} + +void ipc_service::close_window(void) +{ + if (hWnd_ == NULL) + return; + WNDCLASSEX wcx; + DestroyWindow(hWnd_); + if (__class_name && GetClassInfoEx(hInstance_, __class_name, &wcx)) + { + logger("unregister ipc_service class: %s", __class_name); + UnregisterClass(__class_name, hInstance_); + } +} + +#endif + +ipc_service::ipc_service(int nthread, bool ipc_keep /* true */) +{ +#ifdef WIN32 + hWnd_ = NULL; +#endif + ipc_keep_ = ipc_keep; + if (nthread > 1) + thread_pool_ = acl_thread_pool_create(nthread, 30); + else + thread_pool_ = NULL; +} + +ipc_service::~ipc_service() +{ +#ifdef WIN32 + if (hWnd_ != NULL) + close_window(); +#endif + if (thread_pool_) + acl_pthread_pool_destroy(thread_pool_); + std::list::iterator it = conn_pool_.begin(); + for (; it != conn_pool_.end(); ++it) + delete (*it); + logger("delete service ipc_service"); +} + +#ifdef WIN32 +void ipc_service::win32_proc(HWND hWnd, UINT msg, + WPARAM wParam, LPARAM lParam) +{ + // 子类必须实现该接口 + logger_fatal("ipc_service::win32_proc be called"); +} +#endif + +void ipc_service::request(ipc_request* req) +{ + REQ_CTX* req_ctx = (REQ_CTX*) acl_mycalloc(1, sizeof(REQ_CTX)); +#ifdef WIN32 + if (hWnd_ != NULL) + req->set_hwnd(hWnd_); + else + ACL_SAFE_STRNCPY(req_ctx->addr, + get_addr(), sizeof(req_ctx->addr)); +#else + ACL_SAFE_STRNCPY(req_ctx->addr, get_addr(), sizeof(req_ctx->addr)); +#endif + req_ctx->req = req; + if (ipc_keep_) + req_ctx->service = this; + else + req_ctx->service = NULL; + + if (thread_pool_) + acl_pthread_pool_add(thread_pool_, (void (*)(void*)) + thread_pool_main, req_ctx); + else + { + acl_pthread_t tid; + acl_pthread_attr_t attr; + + acl_pthread_attr_init(&attr); + acl_pthread_attr_setdetachstate(&attr, 1); + acl_pthread_create(&tid, &attr, (void* (*)(void*)) + thread_once_main, req_ctx); + } +} + +ipc_client* ipc_service::peek_conn() +{ + ipc_client* ipc; + + // 先从连接池中查找是否有可用的连接 + + lock_.lock(); + + std::list::iterator it = conn_pool_.begin(); + if (it != conn_pool_.end()) + { + ipc = *it; + conn_pool_.pop_front(); + } + else + ipc = NULL; + + lock_.unlock(); + + if (ipc) + return ipc; + + // 创建新的 IO 消息流 + + ipc = NEW ipc_client(); + + const char* addr = get_addr(); + // 连接消息服务器, 采用同步IPC通道方式 + if (ipc->open(addr, 0) == false) + { + logger_error("open %s error(%s)", addr, acl_last_serror()); + delete ipc; + return NULL; + } + else + return ipc; +} + +void ipc_service::push_conn(ipc_client* conn) +{ + lock_.lock(); + conn_pool_.push_back(conn); + lock_.unlock(); +} + +} diff --git a/lib_acl_cpp/src/ipc/rpc.cpp b/lib_acl_cpp/src/ipc/rpc.cpp new file mode 100644 index 000000000..29a9ce09f --- /dev/null +++ b/lib_acl_cpp/src/ipc/rpc.cpp @@ -0,0 +1,286 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/ipc/ipc_client.hpp" +#include "acl_cpp/ipc/rpc.hpp" + +namespace acl +{ + +// 所有消息类型定义 +enum +{ + RPC_MSG, + RPC_SIG +}; + +#ifdef WIN32 +#define RPC_WIN32_MSG (WM_USER + 100) +#define RPC_WIN32_SIG (WM_USER + 101) +#endif + +// IPC 通信时,子线程通过发送此数据通知主线程任务处理结果 +/* +struct IPC_DAT +{ + rpc_request* req; + void* ctx; +}; +*/ + +rpc_request::rpc_request() +: ipc_(NULL) +, wait_timedout_(false) +{ + dat_.req = this; + dat_.ctx = NULL; + + cond_count_ = 0; + cond_ = (acl_pthread_cond_t*) acl_mycalloc( + 1, sizeof(acl_pthread_cond_t)); + acl_pthread_cond_init(cond_, NULL); + + lock_ = (acl_pthread_mutex_t*) acl_mycalloc( + 1, sizeof(acl_pthread_mutex_t)); + acl_pthread_mutex_init(lock_, NULL); +} + +rpc_request::~rpc_request() +{ + acl_pthread_mutex_destroy(lock_); + acl_myfree(lock_); + + acl_pthread_cond_destroy(cond_); + acl_myfree(cond_); +} + +// 该函数在子线程中被调用 +void rpc_request::run(ipc_client* ipc) +{ + ipc_ = ipc; + rpc_run(); + /* + IPC_DAT data; + data.req = this; + data.ctx = NULL; + // 向主线程发送结果 + ipc->send_message(RPC_MSG, &data, sizeof(data)); + */ + dat_.ctx = NULL; + + // 向主线程发送结果 + ipc->send_message(RPC_MSG, &dat_, sizeof(RPC_DAT)); +} + +// 该函数在子线程中被调用 +#ifdef WIN32 +void rpc_request::run(HWND hWnd) +{ + rpc_run(); + // 向窗口句柄发消息,将当前对象的地址发给主线程 + ::PostMessage(hWnd, RPC_WIN32_MSG, 0, (LPARAM) this); +} +#endif + +// 该函数在子线程中被调用 +void rpc_request::rpc_signal(void* ctx) +{ +#ifdef WIN32 + HWND hWnd = get_hwnd(); + if (hWnd != NULL) + { + // 向窗口句柄发消息,将当前对象的地址发给主线程 + ::PostMessage(hWnd, RPC_WIN32_SIG, (WPARAM) ctx, (LPARAM) this); + return; + } +#endif + acl_assert(ipc_ != NULL); + /* + IPC_DAT data; + data.req = this; + data.ctx = ctx; + // 向主线程发送结果 + ipc_->send_message(RPC_SIG, &data, sizeof(data)); + */ + dat_.ctx = ctx; + // 向主线程发送结果 + ipc_->send_message(RPC_SIG, &dat_, sizeof(RPC_DAT)); +} + +bool rpc_request::cond_wait(int timeout /* = -1 */) +{ + int status; + + status = acl_pthread_mutex_lock(lock_); + if (status != 0) + { + logger_error("pthread_mutex_lock error: %d", status); + return false; + } + + if (--cond_count_ >= 0) + { + status = acl_pthread_mutex_unlock(lock_); + if (status != 0) + { + logger_error("pthread_mutex_unlock error: %d", status); + return false; + } + return true; + } + + if (timeout < 0) + { + status = acl_pthread_cond_wait(cond_, lock_); + if (status != 0) + { + logger_error("pthread_cond_wait error: %d", status); + status = acl_pthread_mutex_unlock(lock_); + if (status != 0) + logger_error("pthread_mutex_unlock error: %d", status); + return false; + } + status = acl_pthread_mutex_unlock(lock_); + if (status != 0) + { + logger_error("pthread_mutex_unlock error: %d", status); + return false; + } + return true; + } + + struct timeval tv; + struct timespec when_ttl; + gettimeofday(&tv, NULL); + when_ttl.tv_sec = tv.tv_sec + timeout / 1000; + when_ttl.tv_nsec = tv.tv_usec * 1000 + (timeout % 1000) * 1000; + wait_timedout_ = false; + + status = acl_pthread_cond_timedwait(cond_, lock_, &when_ttl); + if (status != 0) + { + if (status == ACL_ETIMEDOUT) + wait_timedout_ = true; + else + logger_error("pthread_cond_timedwait error: %d", status); + status = acl_pthread_mutex_unlock(lock_); + if (status != 0) + logger_error("pthread_mutex_unlock error: %d", status); + return false; + } + else + { + status = acl_pthread_mutex_unlock(lock_); + if (status != 0) + { + logger_error("pthread_mutex_unlock error: %d", status); + return false; + } + return true; + } +} + +bool rpc_request::cond_signal() +{ + int status; + + status = acl_pthread_mutex_lock(lock_); + if (status != 0) + { + logger_error("pthread_mutex_lock error: %d", status); + return false; + } + + cond_count_++; + + status = acl_pthread_cond_signal(cond_); + if (status != 0) + { + (void) acl_pthread_mutex_unlock(lock_); + logger_error("pthread_cond_signal error: %d", status); + return false; + } + + status = acl_pthread_mutex_unlock(lock_); + if (status != 0) + { + logger_error("pthread_mutex_unlock error: %d", status); + return false; + } + + return true; +} + +////////////////////////////////////////////////////////////////////////// + +// 该类实例在主线程中运行 + +class rpc_client : public ipc_client +{ +public: + rpc_client(void) {} + ~rpc_client(void) {} + +protected: + /** + * 基类虚接口:当收到消息时的回调函数 + * @param nMsg {int} 用户添加的自定义消息值 + * @param data {void*} 消息数据 + * @param dlen {int} 消息数据的长度 + */ + virtual void on_message(int nMsg, void* data, int dlen) + { + acl_assert(data && dlen == sizeof(RPC_DAT)); + RPC_DAT* dat = (RPC_DAT*) data; + acl_assert(dat->req); + + if (nMsg == RPC_MSG) + dat->req->rpc_onover(); + else if (nMsg == RPC_SIG) + dat->req->rpc_wakeup(dat->ctx); + } + + // 基类虚接口 + virtual void on_close(void) + { + delete this; + } +private: +}; + +void rpc_service::on_accept(aio_socket_stream* client) +{ + // 创建接收来自于子线程消息的 IPC 连接对象 + ipc_client* ipc = new rpc_client(); + ipc->open(client); + + // 添加消息回调对象 + ipc->append_message(RPC_MSG); + ipc->append_message(RPC_SIG); + ipc->wait(); +} + +#ifdef WIN32 +void rpc_service::win32_proc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + if (msg == RPC_WIN32_MSG) + { + rpc_request* req = (rpc_request*) lParam; + acl_assert(req); + req->rpc_onover(); + } + else if (msg == RPC_WIN32_SIG) + { + rpc_request* req = (rpc_request*) lParam; + acl_assert(req); + void* ctx = (void*) wParam; + req->rpc_wakeup(ctx); + } +} +#endif + +void rpc_service::rpc_fork(rpc_request* req) +{ + request(req); +} + +} // namespace acl diff --git a/lib_acl_cpp/src/master/master_aio.cpp b/lib_acl_cpp/src/master/master_aio.cpp new file mode 100644 index 000000000..742d0d234 --- /dev/null +++ b/lib_acl_cpp/src/master/master_aio.cpp @@ -0,0 +1,165 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/stream/aio_handle.hpp" +#include "acl_cpp/stream/aio_socket_stream.hpp" +#include "acl_cpp/master/master_aio.hpp" + +namespace acl +{ + +static master_aio* __ma = NULL; +static aio_handle* __handle = NULL; +static aio_listen_stream* __sstream = NULL; + +master_aio::master_aio() +{ + // 全局静态变量 + acl_assert(__ma == NULL); + __ma = this; +} + +master_aio::~master_aio() +{ + if (__sstream) + { + __sstream->close(); + __sstream = NULL; + } + + if (__handle) + { + __handle->check(); + if (daemon_mode_ == false) + delete __handle; + __handle = NULL; + } +} + +aio_handle* master_aio::get_handle() const +{ + acl_assert(__handle); + return __handle; +} + +static bool has_called = false; + +void master_aio::run_daemon(int argc, char** argv) +{ +#ifndef WIN32 + // 每个进程只能有一个实例在运行 + acl_assert(has_called == false); + has_called = true; + daemon_mode_ = true; + + // 调用 acl 服务器框架的单线程非阻塞模板 + acl_aio_app2_main(argc, argv, service_main, NULL, + ACL_APP_CTL_PRE_JAIL, service_pre_jail, + ACL_APP_CTL_INIT_FN, service_init, + ACL_APP_CTL_EXIT_FN, service_exit, + ACL_APP_CTL_CFG_BOOL, conf_.get_bool_cfg(), + ACL_APP_CTL_CFG_INT64, conf_.get_int64_cfg(), + ACL_APP_CTL_CFG_INT, conf_.get_int_cfg(), + ACL_APP_CTL_CFG_STR, conf_.get_str_cfg(), + ACL_APP_CTL_END); +#else + logger_fatal("no support win32 yet!"); +#endif + } + +bool master_aio::run_alone(const char* addr, const char* path /* = NULL */, + aio_handle_type ht /* = ENGINE_SELECT */) +{ + acl_assert(__handle == NULL); + daemon_mode_ = false; +#ifdef WIN32 + acl_init(); +#endif + + // 初始化配置参数 + conf_.load(path); + + __handle = NEW aio_handle(ht); + __sstream = NEW aio_listen_stream(__handle); + // 监听指定的地址 + if (__sstream->open(addr) == false) + { + logger_error("listen %s error: %s", addr, acl_last_serror()); + __sstream->close(); + // XXX: 为了保证能关闭监听流,应在此处再 check 一下 + __handle->check(); + __sstream = NULL; + return (false); + } + __sstream->add_accept_callback(this); + + service_pre_jail(NULL); + service_init(NULL); + while (true) + { + // 如果返回 false 则表示不再继续,需要退出 + if (__handle->check() == false) + { + logger("aio_server stop now ..."); + break; + } + } + __sstream->close(); + __sstream = NULL; + __handle->check(); + service_exit(NULL); + return true; +} + +void master_aio::stop() +{ + acl_assert(__handle); + __handle->stop(); +} + +bool master_aio::accept_callback(aio_socket_stream* client) +{ + return on_accept(client); +} + +////////////////////////////////////////////////////////////////////////// + +void master_aio::service_pre_jail(void*) +{ + acl_assert(__ma != NULL); +#ifndef WIN32 + if (__ma->daemon_mode_) + { + acl_assert(__handle == NULL); + + ACL_AIO *aio = acl_aio_server_handle(); + acl_assert(aio); + __handle = NEW aio_handle(aio); + } +#endif + __ma->proc_pre_jail(); +} + +void master_aio::service_init(void* ctx acl_unused) +{ + acl_assert(__ma != NULL); + __ma->proc_inited_ = true; + __ma->proc_on_init(); +} + +void master_aio::service_exit(void* ctx acl_unused) +{ + acl_assert(__ma != NULL); + __ma->proc_on_exit(); +} + +int master_aio::service_main(ACL_SOCKET fd, void*) +{ + acl_assert(__handle); + acl_assert(__ma); + + aio_socket_stream* stream = NEW aio_socket_stream(__handle, fd); + __ma->on_accept(stream); + return 0; +} + +} // namespace acl diff --git a/lib_acl_cpp/src/master/master_base.cpp b/lib_acl_cpp/src/master/master_base.cpp new file mode 100644 index 000000000..b9f4b9c57 --- /dev/null +++ b/lib_acl_cpp/src/master/master_base.cpp @@ -0,0 +1,50 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/master/master_base.hpp" + +namespace acl +{ +master_base::master_base() +{ + daemon_mode_ = false; + proc_inited_ = false; +} + +master_base::~master_base() +{ + +} + +void master_base::set_cfg_bool(master_bool_tbl* table) +{ + if (table == NULL) + return; + conf_.set_cfg_bool(table); +} + +void master_base::set_cfg_int(master_int_tbl* table) +{ + if (table == NULL) + return; + conf_.set_cfg_int(table); +} + +void master_base::set_cfg_int64(master_int64_tbl* table) +{ + if (table == NULL) + return; + conf_.set_cfg_int64(table); +} + +void master_base::set_cfg_str(master_str_tbl* table) +{ + if (table == NULL) + return; + conf_.set_cfg_str(table); +} + +bool master_base::daemon_mode() const +{ + return daemon_mode_; +} + +} // namespace acl diff --git a/lib_acl_cpp/src/master/master_conf.cpp b/lib_acl_cpp/src/master/master_conf.cpp new file mode 100644 index 000000000..9b319dfa9 --- /dev/null +++ b/lib_acl_cpp/src/master/master_conf.cpp @@ -0,0 +1,216 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/master/master_conf.hpp" + +namespace acl +{ + +master_conf::master_conf() +{ + cfg_loaded_ = false; + + bool_tbl_ = NULL; + int_tbl_ = NULL; + int64_tbl_ = NULL; + str_tbl_ = NULL; + + cfg_ = NULL; + bool_cfg_ = NULL; + int_cfg_ = NULL; + int64_cfg_ = NULL; + str_cfg_ = NULL; +} + +master_conf::~master_conf() +{ + reset(); +} + +void master_conf::reset() +{ + if (cfg_) + { + acl_xinetd_cfg_free(cfg_); + cfg_ = NULL; + } + if (int_cfg_) + { + acl_myfree(int_cfg_); + int_cfg_ = NULL; + } + if (int64_cfg_) + { + acl_myfree(int64_cfg_); + int64_cfg_ = NULL; + } + if (str_cfg_) + { + for (int i = 0; str_cfg_[i].name != NULL; i++) + { + if (*str_cfg_[i].target) + acl_myfree(*str_cfg_[i].target); + } + acl_myfree(str_cfg_); + str_cfg_ = NULL; + } + if (bool_cfg_) + { + acl_myfree(bool_cfg_); + bool_cfg_ = NULL; + } + + cfg_loaded_ = false; + + bool_tbl_ = NULL; + int_tbl_ = NULL; + int64_tbl_ = NULL; + str_tbl_ = NULL; +} + +void master_conf::load(const char* path) +{ + if (cfg_loaded_) + return; + if (path) + cfg_ = acl_xinetd_cfg_load(path); + cfg_loaded_ = true; + + load_bool(); + load_int(); + load_int64(); + load_str(); +} + +void master_conf::load_bool() +{ + if (!cfg_loaded_ || bool_cfg_ == NULL) + return; + acl_xinetd_params_bool_table(cfg_, bool_cfg_); +} + +void master_conf::load_int() +{ + if (!cfg_loaded_ || int_cfg_ == NULL) + return; + acl_xinetd_params_int_table(cfg_, int_cfg_); +} + +void master_conf::load_int64() +{ + if (!cfg_loaded_ || int64_cfg_ == NULL) + return; + acl_xinetd_params_int64_table(cfg_, int64_cfg_); +} + +void master_conf::load_str() +{ + if (!cfg_loaded_ || str_cfg_ == NULL) + return; + acl_xinetd_params_str_table(cfg_, str_cfg_); +} + +void master_conf::set_cfg_bool(master_bool_tbl* table) +{ + if (table == NULL || bool_cfg_) + return; + + int i = 0; + for (; table[i].name != NULL; i++); + bool_cfg_ = (ACL_CFG_BOOL_TABLE*) acl_mycalloc(i + 1, + sizeof(ACL_CFG_BOOL_TABLE)); + + for (i = 0; table[i].name != NULL; i++) + { + bool_cfg_[i].name = table[i].name; + bool_cfg_[i].defval = table[i].defval; + bool_cfg_[i].target = table[i].target; + } + bool_cfg_[i].name = NULL; + load_bool(); +} + +void master_conf::set_cfg_int(master_int_tbl* table) +{ + if (table == NULL || int_cfg_) + return; + + int i = 0; + for (; table[i].name != NULL; i++); + int_cfg_ = (ACL_CFG_INT_TABLE*) acl_mycalloc(i + 1, + sizeof(ACL_CFG_INT_TABLE)); + + for (i = 0; table[i].name != NULL; i++) + { + int_cfg_[i].name = table[i].name; + int_cfg_[i].defval = table[i].defval; + int_cfg_[i].target = table[i].target; + int_cfg_[i].min = table[i].min; + int_cfg_[i].max = table[i].max; + } + int_cfg_[i].name = NULL; + load_int(); +} + +void master_conf::set_cfg_int64(master_int64_tbl* table) +{ + if (table == NULL || int64_cfg_) + return; + + int i = 0; + for (i = 0; table[i].name != NULL; i++); + int64_cfg_ = (ACL_CFG_INT64_TABLE*) acl_mycalloc(i + 1, + sizeof(ACL_CFG_INT64_TABLE)); + + for (i = 0; table[i].name != NULL; i++) + { + int64_cfg_[i].name = table[i].name; + int64_cfg_[i].defval = table[i].defval; + int64_cfg_[i].target = table[i].target; + int64_cfg_[i].min = table[i].min; + int64_cfg_[i].max = table[i].max; + } + + int64_cfg_[i].name = NULL; + load_int64(); +} + +void master_conf::set_cfg_str(master_str_tbl* table) +{ + if (table == NULL || str_cfg_) + return; + + int i = 0; + for (; table[i].name != NULL; i++); + str_cfg_ = (ACL_CFG_STR_TABLE*) acl_mycalloc(i + 1, + sizeof(ACL_CFG_STR_TABLE)); + + for (i = 0; table[i].name != NULL; i++) + { + str_cfg_[i].name = table[i].name; + str_cfg_[i].defval = table[i].defval; + str_cfg_[i].target = table[i].target; + } + str_cfg_[i].name = NULL; + load_str(); +} + +ACL_CFG_INT_TABLE* master_conf::get_int_cfg() const +{ + return int_cfg_; +} + +ACL_CFG_INT64_TABLE* master_conf::get_int64_cfg() const +{ + return int64_cfg_; +} + +ACL_CFG_STR_TABLE* master_conf::get_str_cfg() const +{ + return str_cfg_; +} + +ACL_CFG_BOOL_TABLE* master_conf::get_bool_cfg() const +{ + return bool_cfg_; +} + +} // namespace acl diff --git a/lib_acl_cpp/src/master/master_proc.cpp b/lib_acl_cpp/src/master/master_proc.cpp new file mode 100644 index 000000000..90155b034 --- /dev/null +++ b/lib_acl_cpp/src/master/master_proc.cpp @@ -0,0 +1,128 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/stream/socket_stream.hpp" +#include "acl_cpp/master/master_proc.hpp" + +namespace acl +{ +static master_proc* __mp = NULL; + +master_proc::master_proc() +{ + acl_assert(__mp == NULL); + __mp = this; +} + +master_proc::~master_proc() +{ + +} + +static bool has_called = false; + +void master_proc::run_daemon(int argc, char** argv) +{ +#ifdef WIN32 + logger_fatal("not support WIN32!"); +#else + // 每个进程只能有一个实例在运行 + acl_assert(has_called == false); + has_called = true; + daemon_mode_ = true; + + acl_single_server_main(argc, argv, service_main, + ACL_MASTER_SERVER_PRE_INIT, service_pre_jail, + ACL_MASTER_SERVER_POST_INIT, service_init, + ACL_MASTER_SERVER_EXIT, service_exit, + ACL_MASTER_SERVER_INT_TABLE, conf_.get_int_cfg(), + ACL_MASTER_SERVER_STR_TABLE, conf_.get_str_cfg(), + ACL_MASTER_SERVER_BOOL_TABLE, conf_.get_bool_cfg(), + ACL_MASTER_SERVER_INT64_TABLE, conf_.get_int64_cfg(), + 0); +#endif +} + +bool master_proc::run_alone(const char* addr, const char* path /* = NULL */, + int count /* = 1 */) +{ + // 每个进程只能有一个实例在运行 + acl_assert(has_called == false); + has_called = true; + daemon_mode_ = false; + acl_assert(addr && *addr); + +#ifdef WIN32 + acl_init(); +#endif + + ACL_VSTREAM* sstream = acl_vstream_listen(addr, 128); + if (sstream == NULL) + { + logger_error("listen %s error(%s)", + addr, acl_last_serror()); + return false; + } + + // 初始化配置参数 + conf_.load(path); + + service_pre_jail(NULL, NULL); + service_init(NULL, NULL); + + int i = 0; + while (true) + { + ACL_VSTREAM* client = acl_vstream_accept(sstream, NULL, 0); + if (client == NULL) + break; + + service_main(client, NULL, NULL); + acl_vstream_close(client); // 因为在 service_main 里不会关闭连接 + + if (count > 0 && ++i >= count) + break; + } + + acl_vstream_close(sstream); + service_exit(NULL, NULL); + return true; +} + +////////////////////////////////////////////////////////////////////////// + +void master_proc::service_main(ACL_VSTREAM *stream, char*, char**) +{ + socket_stream* client = NEW socket_stream(); + if (client->open(stream) == false) + logger_fatal("open stream error!"); + + acl_assert(__mp != NULL); +#ifndef WIN32 + if (__mp->daemon_mode_) + acl_watchdog_pat(); // 必须通知 acl_master 框架一下 +#endif + __mp->on_accept(client); + client->unbind(); + delete client; +} + +void master_proc::service_pre_jail(char*, char**) +{ + acl_assert(__mp != NULL); + __mp->proc_pre_jail(); +} + +void master_proc::service_init(char*, char**) +{ + acl_assert(__mp != NULL); + __mp->proc_inited_ = true; + __mp->proc_on_init(); +} + +void master_proc::service_exit(char*, char**) +{ + acl_assert(__mp != NULL); + __mp->proc_on_exit(); +} + +} // namespace acl diff --git a/lib_acl_cpp/src/master/master_threads.cpp b/lib_acl_cpp/src/master/master_threads.cpp new file mode 100644 index 000000000..bfc848c6b --- /dev/null +++ b/lib_acl_cpp/src/master/master_threads.cpp @@ -0,0 +1,326 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/stream/socket_stream.hpp" +#include "acl_cpp/master/master_threads.hpp" + +namespace acl +{ + +static master_threads* __mt = NULL; + +master_threads::master_threads(void) +{ + // 全局静态变量 + acl_assert(__mt == NULL); + __mt = this; +} + +static bool has_called = false; + +void master_threads::run_daemon(int argc, char** argv) +{ +#ifndef WIN32 + // 每个进程只能有一个实例在运行 + acl_assert(has_called == false); + has_called = true; + daemon_mode_ = true; + + // 调用 acl 服务器框架的多线程模板 + acl_ioctl_app_main(argc, argv, service_main, NULL, + ACL_APP_CTL_ON_ACCEPT, service_on_accept, + ACL_APP_CTL_ON_TIMEOUT, service_on_timeout, + ACL_APP_CTL_ON_CLOSE, service_on_close, + ACL_APP_CTL_PRE_JAIL, service_pre_jail, + ACL_APP_CTL_INIT_FN, service_init, + ACL_APP_CTL_EXIT_FN, service_exit, + ACL_APP_CTL_THREAD_INIT, thread_init, + ACL_APP_CTL_THREAD_EXIT, thread_exit, + ACL_APP_CTL_CFG_BOOL, conf_.get_bool_cfg(), + ACL_APP_CTL_CFG_INT64, conf_.get_int64_cfg(), + ACL_APP_CTL_CFG_INT, conf_.get_int_cfg(), + ACL_APP_CTL_CFG_STR, conf_.get_str_cfg(), + ACL_APP_CTL_END); +#else + logger_fatal("no support win32 yet!"); +#endif +} + +bool master_threads::run_alone(const char* addr, const char* path /* = NULL */, + unsigned int count /* = 1 */, int threads_count /* = 1 */) +{ + // 每个进程只能有一个实例在运行 + acl_assert(has_called == false); + has_called = true; + daemon_mode_ = false; + acl_assert(addr && *addr); + +#ifdef WIN32 + acl_init(); +#endif + + ACL_VSTREAM* sstream = acl_vstream_listen(addr, 128); + if (sstream == NULL) + { + logger_error("listen %s error(%s)", + addr, acl_last_serror()); + return false; + } + + // 初始化配置参数 + conf_.load(path); + + service_pre_jail(NULL); + service_init(NULL); + + if (count == 1) + { + thread_init(NULL); + run_once(sstream); + } + else if (threads_count > 1) + run_parallel(sstream, count, threads_count); + else + { + thread_init(NULL); + run_serial(sstream, count); + thread_exit(NULL); + } + + acl_vstream_close(sstream); + service_exit(NULL); + return true; +} + +void master_threads::do_serivce(ACL_VSTREAM* client) +{ + if (service_on_accept(client) == 0) + { + while (true) + { + // 当函数返回 1 时表示 client 已经被关闭了 + if (service_main(client, NULL) == 1) + break; + } + } +} + +void master_threads::run_once(ACL_VSTREAM* sstream) +{ + ACL_VSTREAM* client = acl_vstream_accept(sstream, NULL, 0); + if (client == NULL) + logger_error("accept error(%s)", acl_last_serror()); + else + do_serivce(client); // 该函数内部自动关闭连接 +} + +void master_threads::thread_run(void* arg) +{ + ACL_VSTREAM* client = (ACL_VSTREAM*) arg; + if (service_on_accept(client) != 0) + return; + while (true) + { + if (ACL_VSTREAM_BFRD_CNT(client) > 0) + { + // 当函数返回 1 时表示 client 已经被关闭了 + if (service_main(client, NULL) == 1) + break; + continue; + } + + // acl_read_wait 当 timeout 为 -1 时才是完全阻塞 + // 等待连接有数据可读,当为 0 时则会立即返回,当 + // > 0 时则等待最多指定超时时间 + if(acl_read_wait(ACL_VSTREAM_SOCK(client), + client->rw_timeout > 0 ? + client->rw_timeout : -1) == 0) + { + client->sys_read_ready = 1; + } + + // 当函数返回 1 时表示 client 已经被关闭了 + if (service_main(client, NULL) == 1) + break; + } +} + +int master_threads::thread_begin(void* arg) +{ + thread_init(arg); + return 0; +} + +void master_threads::thread_finish(void* arg) +{ + thread_exit(arg); +} + +void master_threads::run_parallel(ACL_VSTREAM* sstream, + unsigned int count, int threads_count) +{ + acl_assert(threads_count > 1); + acl_pthread_pool_t* thrpool = acl_thread_pool_create(threads_count, 120); + acl_pthread_pool_atinit(thrpool, thread_begin, NULL); + acl_pthread_pool_atfree(thrpool, thread_finish, NULL); + + unsigned int i = 0; + + while (true) + { + ACL_VSTREAM* client = acl_vstream_accept(sstream, NULL, 0); + if (client == NULL) + { + logger_error("accept error(%s)", acl_last_serror()); + break; + } + acl_pthread_pool_add(thrpool, thread_run, client); + i++; + if (count > 0 && i >= count) + break; + } + acl_pthread_pool_destroy(thrpool); +} + +void master_threads::run_serial(ACL_VSTREAM* sstream, unsigned int count) +{ + unsigned int i = 0; + while (true) + { + run_once(sstream); + i++; + if (count > 0 && i >= count) + break; + } +} + +void master_threads::proc_set_timer(void (*callback)(int, void*), + void* ctx, int delay) +{ +#ifdef WIN32 + logger_error("can't support on win32"); +#else + if (__mt->proc_inited_) + acl_ioctl_server_request_timer(callback, ctx, delay); + else + logger_error("please call me in proc_on_init"); +#endif +} + +void master_threads::proc_del_timer(void (*callback)(int, void*), void* ctx) +{ +#ifdef WIN32 + logger_error("can't support on win32"); +#else + if (__mt->proc_inited_) + acl_ioctl_server_cancel_timer(callback, ctx); +#endif +} + +////////////////////////////////////////////////////////////////////////// + +void master_threads::service_pre_jail(void*) +{ + acl_assert(__mt != NULL); + __mt->proc_pre_jail(); +} + +void master_threads::service_init(void*) +{ + acl_assert(__mt != NULL); + __mt->proc_inited_ = true; + __mt->proc_on_init(); +} + +void master_threads::service_exit(void*) +{ + acl_assert(__mt != NULL); + __mt->proc_on_exit(); +} + +void master_threads::thread_init(void*) +{ + acl_assert(__mt != NULL); + __mt->thread_on_init(); +} + +void master_threads::thread_exit(void*) +{ + acl_assert(__mt != NULL); + __mt->thread_on_exit(); +} + +int master_threads::service_main(ACL_VSTREAM *client, void*) +{ + acl_assert(__mt != NULL); + + // client->context 在 service_on_accept 中被设置 + socket_stream* stream = (socket_stream*) client->context; + if (stream == NULL) + logger_fatal("client->context is null!"); + + // 调用子类的虚函数实现,如果返回 true 表示让框架继续监控该连接流 + // 否则需要关闭该流 + if (__mt->thread_on_read(stream) == true) + return 0; // 与该连接保持长连接 + else + { + __mt->thread_on_close(stream); + delete stream; + return 1; // 此连接已经关闭 + } +} + +int master_threads::service_on_accept(ACL_VSTREAM* client) +{ + // client->context 不应被占用 + if (client->context != NULL) + logger_fatal("client->context not null!"); + + socket_stream* stream = NEW socket_stream(); + if (stream->open(client) == false) + { + logger_error("open stream error(%s)", acl_last_serror()); + delete stream; + return -1; + } + // 设置 client->context 为流对象 + client->context = stream; + + acl_assert(__mt != NULL); + + if (__mt->thread_on_accept(stream) == false) + { + client->context = NULL; + // 解释与连接流的绑定关系,这样可以防止在删除流对象时 + // 真正关闭了连接流,因为该流连接需要在本函数返回后由 + // 框架自动关闭 + (void) stream->unbind(); + // 删除流对象 + delete stream; + // 让框架关闭连接流 + return -1; + } + return 0; +} + +int master_threads::service_on_timeout(ACL_VSTREAM* client, void*) +{ + socket_stream* stream = (socket_stream*) client->context; + if (stream == NULL) + logger_fatal("client->context is null!"); + + acl_assert(__mt != NULL); + return __mt->thread_on_timeout(stream) == true ? 0 : -1; +} + +void master_threads::service_on_close(ACL_VSTREAM* client, void*) +{ + socket_stream* stream = (socket_stream*) client->context; + if (stream == NULL) + logger_fatal("client->context is null!"); + + acl_assert(__mt != NULL); + __mt->thread_on_close(stream); +} + +} // namespace acl diff --git a/lib_acl_cpp/src/master/master_trigger.cpp b/lib_acl_cpp/src/master/master_trigger.cpp new file mode 100644 index 000000000..95c09f99a --- /dev/null +++ b/lib_acl_cpp/src/master/master_trigger.cpp @@ -0,0 +1,107 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/master/master_trigger.hpp" + +namespace acl +{ + +static master_trigger* __mt = NULL; + +master_trigger::master_trigger() +{ + acl_assert(__mt == NULL); + __mt = this; +} + +master_trigger::~master_trigger() +{ + +} + +static bool has_called = false; + +void master_trigger::run_daemon(int argc, char** argv) +{ +#ifdef WIN32 + logger_fatal("not support WIN32!"); +#else + // 每个进程只能有一个实例在运行 + acl_assert(has_called == false); + has_called = true; + daemon_mode_ = true; + + acl_trigger_server_main(argc, argv, service_main, + ACL_MASTER_SERVER_PRE_INIT, service_pre_jail, + ACL_MASTER_SERVER_POST_INIT, service_init, + ACL_MASTER_SERVER_EXIT, service_exit, + ACL_MASTER_SERVER_INT_TABLE, conf_.get_int_cfg(), + ACL_MASTER_SERVER_STR_TABLE, conf_.get_str_cfg(), + ACL_MASTER_SERVER_BOOL_TABLE, conf_.get_bool_cfg(), + ACL_MASTER_SERVER_INT64_TABLE, conf_.get_int64_cfg(), + 0); +#endif +} + +void master_trigger::run_alone(const char* path /* = NULL */, + int count /* = 1 */, int interval /* = 1 */) +{ + // 每个进程只能有一个实例在运行 + acl_assert(has_called == false); + has_called = true; + daemon_mode_ = false; +#ifdef WIN32 + acl_init(); +#endif + if (interval <= 0) + interval = 1; + + // 初始化配置参数 + conf_.load(path); + + service_pre_jail(NULL, NULL); + service_init(NULL, NULL); + + int i = 0; + while (true) + { + sleep(interval); + service_main(NULL, 0, NULL, NULL); + if (count > 0 && ++i >= count) + break; + } + + service_exit(NULL, NULL); +} + +////////////////////////////////////////////////////////////////////////// + +void master_trigger::service_main(char*, int, char*, char**) +{ + acl_assert(__mt != NULL); +#ifndef WIN32 + if (__mt->daemon_mode_) + acl_watchdog_pat(); +#endif + __mt->on_trigger(); +} + +void master_trigger::service_pre_jail(char*, char**) +{ + acl_assert(__mt != NULL); + __mt->proc_pre_jail(); +} + +void master_trigger::service_init(char*, char**) +{ + acl_assert(__mt != NULL); + __mt->proc_inited_ = true; + __mt->proc_on_init(); +} + +void master_trigger::service_exit(char*, char**) +{ + acl_assert(__mt != NULL); + __mt->proc_on_exit(); +} + +} // namespace acl diff --git a/lib_acl_cpp/src/memcache/memcache.cpp b/lib_acl_cpp/src/memcache/memcache.cpp new file mode 100644 index 000000000..a2c9e8d08 --- /dev/null +++ b/lib_acl_cpp/src/memcache/memcache.cpp @@ -0,0 +1,480 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/mime/rfc2047.hpp" +#include "acl_cpp/memcache/memcache.hpp" +#include "acl_cpp/stdlib/util.hpp" +#include "acl_cpp/stream/socket_stream.hpp" + +#define SPECIAL_CHAR(x) ((x) == ' ' || (x) == '\t' || (x) == '\r' || (x) == '\n') + +namespace acl +{ + +memcache::memcache(const char* addr /* = "127.0.0.1:11211" */, + int conn_timeout /* = 180 */, int rw_timeout /* = 300 */) +: keypre_(NULL) +, coder_(false, false) +, conn_timeout_(conn_timeout) +, rw_timeout_(rw_timeout) +, encode_key_(false) +, opened_(false) +, retry_(true) +, conn_(NULL) +{ + acl_assert(addr && *addr); + addr_ = acl_mystrdup(addr); + char* ptr = strchr(addr_, ':'); + if (ptr == NULL) + logger_fatal("addr(%s) invalid", addr); + *ptr++ = 0; + if (*ptr == 0) + logger_fatal("addr(%s) invalid", addr); + ip_ = addr_; + port_ = atoi(ptr); + if (port_ <= 0) + logger_fatal("addr(%s) invalid", addr); +} + +memcache::~memcache() +{ + close(); + if (keypre_) + delete keypre_; + acl_myfree(addr_); +} + +memcache& memcache::set_prefix(const char* keypre) +{ + if (keypre == NULL || *keypre == 0) + { + if (keypre_) + { + delete keypre_; + keypre_ = NULL; + } + return *this; + } + + bool beCoding = false; + + if (keypre_ == NULL) + keypre_ = NEW acl::string(strlen(keypre)); + else + keypre_->clear(); + + while (*keypre) + { + if (SPECIAL_CHAR(*keypre) || !ACL_ISPRINT(*keypre)) + { + coder_.encode_update(keypre, 1, keypre_); + beCoding = true; + } + else if (beCoding) + { + coder_.encode_finish(keypre_); + coder_.reset(); + beCoding = false; + *keypre_ << (char) *keypre; + } + else + *keypre_ << (char) *keypre; + keypre++; + } + + if (beCoding) + coder_.encode_finish(keypre_); + return *this; +} + +memcache& memcache::auto_retry(bool onoff) +{ + retry_ = onoff; + return *this; +} + +memcache& memcache::encode_key(bool onoff) +{ + encode_key_ = onoff; + return *this; +} + +void memcache::close() +{ + if (opened_ == false) + return; + + if (conn_) + { + delete conn_; + conn_ = NULL; + } + opened_ = false; +} + +bool memcache::open() +{ + if (opened_) + return (true); + + conn_ = NEW socket_stream(); + char addr[64]; + + snprintf(addr, sizeof(addr), "%s:%d", ip_, port_); + if (conn_->open(addr, conn_timeout_, rw_timeout_) == false) + { + logger_error("connect %s error(%s)", + addr, acl::last_serror()); + delete conn_; + conn_ = NULL; + opened_ = false; + ebuf_.format("connect server(%s) error(%s)", + addr, acl_last_serror()); + return (false); + } + opened_ = true; + return (true); +} + +bool memcache::set(const acl::string& key, const void* dat, size_t dlen, + time_t timeout, unsigned short flags) +{ + bool has_tried = false; + struct iovec v[4]; + line_.format("set %s %u %d %d\r\n", key.c_str(), + flags, (int) timeout, (int) dlen); +AGAIN: + if (open() == false) + return (false); + + v[0].iov_base = (void*) line_.c_str(); + v[0].iov_len = line_.length(); + v[1].iov_base = (void*) dat; + v[1].iov_len = dlen; + v[2].iov_base = (void*) "\r\n"; + v[2].iov_len = 2; + + if (conn_->writev(v, 3) < 0) + { + close(); + if (retry_ && !has_tried) + { + has_tried = true; + goto AGAIN; + } + ebuf_.format("write set(%s) error", key.c_str()); + return (false); + } + + if (conn_->gets(line_) == false) + { + close(); + if (retry_ && !has_tried) + { + has_tried = true; + goto AGAIN; + } + ebuf_.format("reply for set(%s) error", key.c_str()); + return (false); + } + + if (line_ != "STORED") + { + close(); + if (retry_ && !has_tried) + { + has_tried = true; + goto AGAIN; + } + ebuf_.format("reply(%s) for set(%s) error", + line_.c_str(), key.c_str()); + return (false); + } + return (true); +} + +bool memcache::set(const char* key, size_t klen, const void* dat, + size_t dlen, time_t timeout /* = 0 */, unsigned short flags /* = 0 */) +{ + const acl::string& keybuf = get_key(key, klen); + return (set(keybuf, dat, dlen, timeout, flags)); +} + +bool memcache::set(const char* key, const void* dat, size_t dlen, + time_t timeout /* = 0 */, unsigned short flags /* = 0 */) +{ + return (set(key, strlen(key), dat, dlen, timeout, flags)); +} + +bool memcache::set(const char* key, size_t klen, time_t timeout /* = 0 */) +{ + const acl::string& keybuf = get_key(key, klen); + acl::string buf; + unsigned short flags; + + if (get(keybuf, buf, &flags) == false) + return (false); + return (set(keybuf, buf.c_str(), buf.length(), timeout, flags)); +} + +bool memcache::set(const char* key, time_t timeout /* = 0 */) +{ + return (set(key, strlen(key), timeout)); +} + +bool memcache::get(const acl::string& key, acl::string& buf, + unsigned short* flags) +{ + bool has_tried = false; + buf.clear(); + + line_.format("get %s\r\n", key.c_str()); + +AGAIN: + if (open() == false) + return (false); + if (conn_->write(line_) < 0) + { + close(); + if (retry_ && !has_tried) + { + has_tried = true; + goto AGAIN; + } + ebuf_.format("write get(%s) error", key.c_str()); + return (false); + } + + // 读取服务器响应行 + if (conn_->gets(line_) == false) + { + close(); + if (retry_ && !has_tried) + { + has_tried = true; + goto AGAIN; + } + ebuf_.format("reply for get(%s) error", key.c_str()); + return (false); + } + else if (line_ == "END") + { + ebuf_.format("not found"); + return (false); + } + else if (error_happen(line_.c_str())) + { + close(); + return (false); + } + + // VALUE {key} {flags} {bytes}\r\n + ACL_ARGV* tokens = acl_argv_split(line_.c_str(), " \t"); + if (tokens->argc < 4 || strcasecmp(tokens->argv[0], "VALUE") != 0) + { + close(); + ebuf_.format("server error for get(%s)", key.c_str()); + acl_argv_free(tokens); + return (false); + } + if (flags) + *flags = (unsigned short) atoi(tokens->argv[2]); + + int len = atoi(tokens->argv[3]); + if (len < 0) + { + close(); + ebuf_.format("value's len < 0"); + acl_argv_free(tokens); + return (false); + } + else if (len == 0) + { + acl_argv_free(tokens); + return (true); + } + acl_argv_free(tokens); + + // 得需要保证足够的空间能容纳读取的数据,该种方式 + // 可能会造成数据量非常大时的缓冲区溢出! + + char tmp[4096]; + int n; + while (true) + { + n = sizeof(tmp); + if (n > len) + n = len; + if ((n = conn_->read(tmp, n, false)) < 0) + { + close(); + ebuf_.format("read data for get cmd error"); + return (false); + } + buf.append(tmp, n); + len -= n; + if (len <= 0) + break; + } + + // 读取数据尾部的 "\r\n" + if (conn_->gets(line_) == false) + { + close(); + ebuf_.format("read data's delimiter error"); + return (false); + } + + // 读取 "END\r\n" + if (conn_->gets(line_) == false || line_ != "END") + { + close(); + ebuf_.format("END flag not found"); + return (false); + } + return (true); +} + +bool memcache::get(const char* key, size_t klen, acl::string& buf, + unsigned short* flags /* = NULL */) +{ + const acl::string& keybuf = get_key(key, klen); + return (get(keybuf, buf, flags)); +} + +bool memcache::get(const char* key, acl::string& buf, + unsigned short* flags /* = NULL */) +{ + return (get(key, strlen(key), buf, flags)); +} + +bool memcache::del(const char* key, size_t klen) +{ + bool has_tried = false; + const acl::string& keybuf = get_key(key, klen); + +AGAIN: + if (open() == false) + return (false); + + line_.format("delete %s\r\n", keybuf.c_str()); + if (conn_->write(line_) < 0) + { + if (retry_ && !has_tried) + { + has_tried = true; + goto AGAIN; + } + ebuf_.format("write (%s) error", line_.c_str()); + return (false); + } + // DELETED|NOT_FOUND\r\n + if (conn_->gets(line_) == false) + { + if (retry_ && !has_tried) + { + has_tried = true; + goto AGAIN; + } + ebuf_.format("reply for(%s) error", line_.c_str()); + return (false); + } + if (line_ != "DELETED" && line_ != "NOT_FOUND") + { + ebuf_.format("reply for (%s) error", line_.c_str()); + return (false); + } + return (true); +} + +bool memcache::del(const char* key) +{ + return (del(key, strlen(key))); +} + +const char* memcache::last_serror() const +{ + static const char* dummy = "ok"; + + if (ebuf_.empty()) + return (dummy); + return (ebuf_.c_str()); +} + +int memcache::last_error() const +{ + return (enum_); +} + +const acl::string& memcache::get_key(const char* key, size_t klen) +{ + kbuf_.clear(); + if (keypre_) + kbuf_.format("%s:", keypre_->c_str()); + + coder_.reset(); + + if (encode_key_) + { + coder_.encode_update(key, klen, &kbuf_); + coder_.encode_finish(&kbuf_); + return (kbuf_); + } + + bool beCoding = false; + + while (klen > 0) + { + if (SPECIAL_CHAR(*key) || !ACL_ISPRINT(*key)) + { + coder_.encode_update(key, 1, &kbuf_); + beCoding = true; + } + else if (beCoding) + { + coder_.encode_finish(&kbuf_); + coder_.reset(); + beCoding = false; + kbuf_ << (char) *key; + } + else + kbuf_ << (char) *key; + key++; + klen--; + } + + if (beCoding) + coder_.encode_finish(&kbuf_); + + return (kbuf_); +} + +bool memcache::error_happen(const char* line) +{ + if (strcasecmp(line, "ERROR") == 0) + return (true); + if (strncasecmp(line, "CLIENT_ERROR", sizeof("CLIENT_ERROR") - 1) == 0) + { + ebuf_.format("%s", line); + const char* ptr = line + sizeof("CLIENT_ERROR") - 1; + if (*ptr == ' ' || *ptr == '\t') + ptr++; + enum_ = atoi(ptr); + return (true); + } + if (strncasecmp(line, "SERVER_ERROR", sizeof("SERVER_ERROR") - 1) == 0) + { + ebuf_.format("%s", line); + const char* ptr = line + sizeof("SERVER_ERROR") - 1; + if (*ptr == ' ' || *ptr == '\t') + ptr++; + enum_ = atoi(ptr); + return (true); + } + return (false); +} + +void memcache::property_list() +{ +} + +} // namespace acl diff --git a/lib_acl_cpp/src/memcache/memcache_pool.cpp b/lib_acl_cpp/src/memcache/memcache_pool.cpp new file mode 100644 index 000000000..66175c6a8 --- /dev/null +++ b/lib_acl_cpp/src/memcache/memcache_pool.cpp @@ -0,0 +1,36 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/memcache/memcache.hpp" +#include "acl_cpp/memcache/memcache_pool.hpp" + +namespace acl +{ + +memcache_pool::memcache_pool(const char* addr, int count, + int retry_inter /* = 0 */) +: connect_pool(addr, count, retry_inter) +{ + conn_timeout_ = 30; + rw_timeout_ = 60; +} + +memcache_pool::~memcache_pool() +{ + +} + +memcache_pool& memcache_pool::set_timeout(int conn_timeout /* = 30 */, + int rw_timeout /* = 60 */) +{ + conn_timeout_ = conn_timeout; + rw_timeout_ = rw_timeout; + return *this; +} + +connect_client* memcache_pool::create_connect() +{ + memcache* conn = NEW memcache(addr_, conn_timeout_, + rw_timeout_); + return conn; +} + +} // namespace acl diff --git a/lib_acl_cpp/src/mime/internal/header_opts.cpp b/lib_acl_cpp/src/mime/internal/header_opts.cpp new file mode 100644 index 000000000..b38229aa8 --- /dev/null +++ b/lib_acl_cpp/src/mime/internal/header_opts.cpp @@ -0,0 +1,224 @@ +/*++ +* NAME +* header_opts 3 +* SUMMARY +* message header classification +* SYNOPSIS +* #include +* +* const HEADER_OPTS *header_opts_find(string) +* const char *string; +* DESCRIPTION +* header_opts_find() takes a message header line and looks up control +* information for the corresponding header type. +* DIAGNOSTICS +* Panic: input is not a valid header line. The result is a pointer +* to HEADER_OPTS in case of success, a null pointer when the header +* label was not recognized. +* SEE ALSO +* header_opts(3h) the gory details +* LICENSE +* .ad +* .fi +* The Secure Mailer license must be distributed with this software. +* AUTHOR(S) +* Wietse Venema +* IBM T.J. Watson Research +* P.O. Box 704 +* Yorktown Heights, NY 10598, USA +*--*/ + +/* System library. */ + +#include "acl_stdafx.hpp" +#include + +/* Utility library. */ + +#include "stdlib/acl_msg.h" +#include "stdlib/acl_htable.h" +#include "stdlib/acl_vstring.h" +#include "stdlib/acl_stringops.h" +#include "thread/acl_pthread.h" +/* Global library. */ + +#include "trimblanks.hpp" +#include "header_opts.hpp" + +/* +* Header names are given in the preferred capitalization. The lookups are +* case-insensitive. +* +* XXX Removing Return-Path: headers should probably be done only with mail +* that enters via a non-SMTP channel. Changing this now could break other +* software. See also comments in bounce_notify_util.c. +*/ +static const HEADER_OPTS header_opts[] = { + { "Apparently-To", HDR_APPARENTLY_TO, HDR_OPT_RECIP }, + { "Bcc", HDR_BCC, HDR_OPT_DROP | HDR_OPT_XRECIP }, + { "Cc", HDR_CC, HDR_OPT_XRECIP }, + { "Content-Description", HDR_CONTENT_DESCRIPTION, HDR_OPT_MIME }, + { "Content-Disposition", HDR_CONTENT_DISPOSITION, HDR_OPT_MIME }, + { "Content-ID", HDR_CONTENT_ID, HDR_OPT_MIME }, + { "Content-Length", HDR_CONTENT_LENGTH, HDR_OPT_DROP }, + { "Content-Transfer-Encoding", HDR_CONTENT_TRANSFER_ENCODING, HDR_OPT_MIME }, + { "Content-Type", HDR_CONTENT_TYPE, HDR_OPT_MIME }, + { "Delivered-To", HDR_DELIVERED_TO, 0 }, + { "Disposition-Notification-To", HDR_DISP_NOTIFICATION, HDR_OPT_SENDER }, + { "Date", HDR_DATE, 0 }, + { "Errors-To", HDR_ERRORS_TO, HDR_OPT_SENDER }, + { "From", HDR_FROM, HDR_OPT_SENDER }, + { "Mail-Followup-To", HDR_MAIL_FOLLOWUP_TO, HDR_OPT_SENDER }, + { "Message-Id", HDR_MESSAGE_ID, 0 }, + { "MIME-Version", HDR_MIME_VERSION, HDR_OPT_MIME }, + { "Received", HDR_RECEIVED, 0 }, + { "Reply-To", HDR_REPLY_TO, HDR_OPT_SENDER }, + { "Resent-Bcc", HDR_RESENT_BCC, HDR_OPT_DROP | HDR_OPT_XRECIP | HDR_OPT_RR }, + { "Resent-Cc", HDR_RESENT_CC, HDR_OPT_XRECIP | HDR_OPT_RR }, + { "Resent-Date", HDR_RESENT_DATE, HDR_OPT_RR }, + { "Resent-From", HDR_RESENT_FROM, HDR_OPT_SENDER | HDR_OPT_RR }, + { "Resent-Message-Id", HDR_RESENT_MESSAGE_ID, HDR_OPT_RR }, + { "Resent-Reply-To", HDR_RESENT_REPLY_TO, HDR_OPT_RECIP | HDR_OPT_RR }, + { "Resent-Sender", HDR_RESENT_SENDER, HDR_OPT_SENDER | HDR_OPT_RR }, + { "Resent-To", HDR_RESENT_TO, HDR_OPT_XRECIP | HDR_OPT_RR }, + { "Return-Path", HDR_RETURN_PATH, HDR_OPT_DROP | HDR_OPT_SENDER }, + { "Return-Receipt-To", HDR_RETURN_RECEIPT_TO, HDR_OPT_SENDER }, + { "Sender", HDR_SENDER, HDR_OPT_SENDER }, + { "To", HDR_TO, HDR_OPT_XRECIP }, + { "Subject", HDR_SUBJECT, HDR_OPT_SUBJECT }, +}; + +#define HEADER_OPTS_SIZE (sizeof(header_opts) / sizeof(header_opts[0])) + +typedef struct { + ACL_HTABLE *header_hash; +} HEADER_CTX; + +#define STR acl_vstring_str + +/* header_opts_init - initialize */ + +static void header_opts_init(ACL_HTABLE *header_hash) +{ + const HEADER_OPTS *hp; + const char *cp; + ACL_VSTRING *header_key = acl_vstring_alloc(128); + + /* + * Build a hash table for quick lookup, and allocate memory for + * lower-casing the lookup key. + */ + for (hp = header_opts; hp < header_opts + HEADER_OPTS_SIZE; hp++) { + ACL_VSTRING_RESET(header_key); + for (cp = hp->name; *cp; cp++) + ACL_VSTRING_ADDCH(header_key, ACL_TOLOWER(*cp)); + ACL_VSTRING_TERMINATE(header_key); + acl_htable_enter(header_hash, STR(header_key), (void*) hp); + } + + acl_vstring_free(header_key); +} + +static HEADER_CTX *header_ctx = NULL; + +static void header_ctx_free(void) +{ + if (header_ctx == NULL) + return; + acl_htable_free(header_ctx->header_hash, NULL); + acl_myfree(header_ctx); + header_ctx = NULL; +} + +static void header_opts_once(void) +{ + header_ctx = (HEADER_CTX*) acl_mymalloc(sizeof(HEADER_CTX)); + header_ctx->header_hash = acl_htable_create(HEADER_OPTS_SIZE, 0); + header_opts_init(header_ctx->header_hash); + + atexit(header_ctx_free); +} + +static acl_pthread_once_t __header_once = ACL_PTHREAD_ONCE_INIT; + +/* header_opts_find - look up header options */ + +const HEADER_OPTS *header_opts_find(const char *string, ACL_VSTRING *key_buffer) +{ + const char *myname = "header_opts_find"; + const char *cp; + HEADER_OPTS *header_info; + ACL_VSTRING *header_key; + + acl_pthread_once(&__header_once, header_opts_once); + + if (header_ctx == NULL) + acl_msg_fatal("%s(%d): header_ctx!", myname, __LINE__); + + if (key_buffer == NULL) + header_key = acl_vstring_alloc(128); + else + header_key = key_buffer; + + /* + * Look up the lower-cased version of the header name. + */ + ACL_VSTRING_RESET(header_key); + for (cp = string; *cp != ':'; cp++) { + if (*cp == 0) { + acl_msg_error("%s: no colon in header: %.30s", + myname, string); + if (key_buffer == NULL) + acl_vstring_free(header_key); + return (NULL); + } + ACL_VSTRING_ADDCH(header_key, ACL_TOLOWER(*cp)); + } + acl_vstring_truncate(header_key, trimblanks(STR(header_key), cp - string) + - STR(header_key)); + ACL_VSTRING_TERMINATE(header_key); + + header_info = (HEADER_OPTS*) acl_htable_find(header_ctx->header_hash, + STR(header_key)); + if (key_buffer == NULL) + acl_vstring_free(header_key); + + return (header_info); +} + +HEADER_NV *header_split(const char *s) +{ + HEADER_NV *header; + +#define SKIP_SPACE(x) { \ + while (*(x) == ' ' || *(x) == '\t') \ + (x)++; \ +} + SKIP_SPACE(s); + if (*s == 0) + return (NULL); + + header = (HEADER_NV*) acl_mycalloc(1, sizeof(HEADER_NV)); + header->name = acl_mystrdup(s); + char *ptr = strchr(header->name, ':'); + if (ptr == NULL) { + header_nv_free(header); + return (NULL); + } + *ptr++ = 0; + SKIP_SPACE(ptr); + if (*ptr == 0) { + header_nv_free(header); + return (NULL); + } + header->value = ptr; + return (header); +} + +void header_nv_free(HEADER_NV *header) +{ + if (header) { + acl_myfree(header->name); + acl_myfree(header); + } +} diff --git a/lib_acl_cpp/src/mime/internal/header_opts.hpp b/lib_acl_cpp/src/mime/internal/header_opts.hpp new file mode 100644 index 000000000..a3aadffe6 --- /dev/null +++ b/lib_acl_cpp/src/mime/internal/header_opts.hpp @@ -0,0 +1,96 @@ +#ifndef _HEADER_OPTS_H_INCLUDED_ +#define _HEADER_OPTS_H_INCLUDED_ + +/*++ + * NAME + * header_opts 3h + * SUMMARY + * message header classification + * SYNOPSIS + * #include + * DESCRIPTION + * .nf + */ + + /* External interface. */ +typedef struct MIME_STATE MIME_STATE; + +struct HEADER_OPTS { + const char *name; /* name, preferred capitalization */ + int type; /* type, see below */ + int flags; /* flags, see below */ +}; + +typedef struct HEADER_NV HEADER_NV; + +struct HEADER_NV { + char *name; + char *value; +}; + + /* + * Header types. If we reach 31, we must group the headers we need to + * remember at the beginning, or we should use fd_set bit sets. + */ +#define HDR_APPARENTLY_TO 1 +#define HDR_BCC 2 +#define HDR_CC 3 +#define HDR_CONTENT_LENGTH 4 +#define HDR_CONTENT_TRANSFER_ENCODING 5 +#define HDR_CONTENT_TYPE 6 +#define HDR_DATE 7 +#define HDR_DELIVERED_TO 8 +#define HDR_ERRORS_TO 9 +#define HDR_FROM 10 +#define HDR_MESSAGE_ID 11 +#define HDR_RECEIVED 12 +#define HDR_REPLY_TO 13 +#define HDR_RESENT_BCC 14 +#define HDR_RESENT_CC 15 +#define HDR_RESENT_DATE 16 +#define HDR_RESENT_FROM 17 +#define HDR_RESENT_MESSAGE_ID 18 +#define HDR_RESENT_REPLY_TO 19 +#define HDR_RESENT_SENDER 20 +#define HDR_RESENT_TO 21 +#define HDR_RETURN_PATH 22 +#define HDR_RETURN_RECEIPT_TO 23 +#define HDR_SENDER 24 +#define HDR_TO 25 +#define HDR_MAIL_FOLLOWUP_TO 26 +#define HDR_CONTENT_DESCRIPTION 27 +#define HDR_CONTENT_DISPOSITION 28 +#define HDR_CONTENT_ID 29 +#define HDR_MIME_VERSION 30 +#define HDR_DISP_NOTIFICATION 31 +#define HDR_SUBJECT 32 + + /* + * Header flags. + */ +#define HDR_OPT_DROP (1<<0) /* delete from input */ +#define HDR_OPT_SENDER (1<<1) /* sender address */ +#define HDR_OPT_RECIP (1<<2) /* recipient address */ +#define HDR_OPT_RR (1<<3) /* Resent- header */ +#define HDR_OPT_EXTRACT (1<<4) /* extract flag */ +#define HDR_OPT_MIME (1<<5) /* MIME header */ +#define HDR_OPT_SUBJECT (1<<6) /* subject */ + +#define HDR_OPT_XRECIP (HDR_OPT_RECIP | HDR_OPT_EXTRACT) + +extern const HEADER_OPTS *header_opts_find(const char *, ACL_VSTRING*); +extern HEADER_NV *header_split(const char *s); +extern void header_nv_free(HEADER_NV *header); + +/* LICENSE + * .ad + * .fi + * The Secure Mailer license must be distributed with this software. + * AUTHOR(S) + * Wietse Venema + * IBM T.J. Watson Research + * P.O. Box 704 + * Yorktown Heights, NY 10598, USA + *--*/ + +#endif diff --git a/lib_acl_cpp/src/mime/internal/header_token.cpp b/lib_acl_cpp/src/mime/internal/header_token.cpp new file mode 100644 index 000000000..47b3eebe1 --- /dev/null +++ b/lib_acl_cpp/src/mime/internal/header_token.cpp @@ -0,0 +1,266 @@ +/*++ + * NAME + * header_token 3 + * SUMMARY + * mail header parser + * SYNOPSIS + * #include + * + * typedef struct { + * .in +4 + * int type; + * const char *u.value; + * ... + * .in + * } HEADER_TOKEN; + * + * ssize_t header_token(token, token_len, token_buffer, ptr, + * specials, terminator) + * HEADER_TOKEN *token; + * ssize_t token_len; + * VSTRING *token_buffer; + * const char **ptr; + * const char *specials; + * int terminator; + * DESCRIPTION + * This module parses a mail header value (text after field-name:) + * into tokens. The parser understands RFC 822 linear white space, + * quoted-string, comment, control characters, and a set of + * user-specified special characters. + * + * A result token type is one of the following: + * .IP HEADER_TOK_QSTRING + * Quoted string as per RFC 822. + * .IP HEADER_TOK_TOKEN + * Token as per RFC 822, and the special characters supplied by the + * caller. + * .IP other + * The value of a control character or special character. + * .PP + * header_token() tokenizes the input and stops after a user-specified + * terminator (ignoring all tokens that exceed the capacity of + * the result storage), or when it runs out of space for the result. + * The terminator is not stored. The result value is the number of + * tokens stored, or -1 when the input was exhausted before any tokens + * were found. + * + * Arguments: + * .IP token + * Result array of HEADER_TOKEN structures. Token string values + * are pointers to null-terminated substrings in the token_buffer. + * .IP token_len + * Length of the array of HEADER_TOKEN structures. + * .IP token_buffer + * Storage for result token string values. + * .IP ptr + * Input/output read position. The input is a null-terminated string. + * .IP specials + * Special characters according to the relevant RFC, or a + * null pointer (default to the RFC 822 special characters). + * This must include the optional terminator if one is specified. + * .IP terminator + * The special character to stop after, or zero. + * BUGS + * Eight-bit characters are not given special treatment. + * SEE ALSO + * RFC 822 (ARPA Internet Text Messages) + * DIAGNOSTICS + * Fatal errors: memory allocation problem. + * LICENSE + * .ad + * .fi + * The Secure Mailer license must be distributed with this software. + * AUTHOR(S) + * Wietse Venema + * IBM T.J. Watson Research + * P.O. Box 704 + * Yorktown Heights, NY 10598, USA + *--*/ + +/* System library. */ + +#include "acl_stdafx.hpp" +#include +#include + +/* Utility library. */ + +#include "stdlib/acl_msg.h" +#include "stdlib/acl_vstring.h" + +/* Global library. */ + +#include "lex_822.hpp" +#include "header_token.hpp" + +/* Application-specific. */ + + /* + * Silly little macros. + */ +#define STR(x) acl_vstring_str(x) +#define LEN(x) ACL_VSTRING_LEN(x) +#define CU_CHAR_PTR(x) ((const unsigned char *) (x)) + +/* header_token - parse out the next item in a message header */ + +ssize_t header_token(HEADER_TOKEN *token, ssize_t token_len, + ACL_VSTRING *token_buffer, const char **ptr, + const char *user_specials, int user_terminator) +{ + ssize_t comment_level; + const unsigned char *cp; + ssize_t len; + int ch; + ssize_t tok_count; + ssize_t n; + + /* + * Initialize. + */ + ACL_VSTRING_RESET(token_buffer); + cp = CU_CHAR_PTR(*ptr); + tok_count = 0; + if (user_specials == 0) + user_specials = LEX_822_SPECIALS; + + /* + * Main parsing loop. + * + * XXX What was the reason to continue parsing when user_terminator is + * specified? Perhaps this was needed at some intermediate stage of + * development? + */ + while ((ch = *cp) != 0 && (user_terminator != 0 || tok_count < token_len)) { + cp++; + + /* + * Skip RFC 822 linear white space. + */ + if (IS_SPACE_TAB_CR_LF(ch)) + continue; + + /* + * Terminator. + */ + if (ch == user_terminator) + break; + + /* + * Skip RFC 822 comment. + */ + if (ch == '(') { + comment_level = 1; + while ((ch = *cp) != 0) { + cp++; + if (ch == '(') { /* comments can nest! */ + comment_level++; + } else if (ch == ')') { + if (--comment_level == 0) + break; + } else if (ch == '\\') { + if ((ch = *cp) == 0) + break; + cp++; + } + } + continue; + } + + /* + * Copy quoted text according to RFC 822. + */ + if (ch == '"') { + if (tok_count < token_len) { + token[tok_count].u.offset = LEN(token_buffer); + token[tok_count].type = HEADER_TOK_QSTRING; + } + while ((ch = *cp) != 0) { + cp++; + if (ch == '"') + break; + if (ch == '\n') { /* unfold */ + if (tok_count < token_len) { + len = LEN(token_buffer); + while (len > 0 + && IS_SPACE_TAB_CR_LF(STR(token_buffer)[len - 1])) + len--; + if (len < (ssize_t) LEN(token_buffer)) + acl_vstring_truncate(token_buffer, len); + } + continue; + } + if (ch == '\\') { + if ((ch = *cp) == 0) + break; + cp++; + } + if (tok_count < token_len) + ACL_VSTRING_ADDCH(token_buffer, ch); + } + if (tok_count < token_len) { + ACL_VSTRING_ADDCH(token_buffer, 0); + tok_count++; + } + continue; + } + + /* + * Control, or special. + */ + if (strchr(user_specials, ch) || ACL_ISCNTRL(ch)) { + if (tok_count < token_len) { + token[tok_count].u.offset = LEN(token_buffer); + token[tok_count].type = ch; + ACL_VSTRING_ADDCH(token_buffer, ch); + ACL_VSTRING_ADDCH(token_buffer, 0); + tok_count++; + } + continue; + } + + /* + * Token. + */ + else { + if (tok_count < token_len) { + token[tok_count].u.offset = LEN(token_buffer); + token[tok_count].type = HEADER_TOK_TOKEN; + ACL_VSTRING_ADDCH(token_buffer, ch); + } + while ((ch = *cp) != 0 && !IS_SPACE_TAB_CR_LF(ch) + && !ACL_ISCNTRL(ch) && !strchr(user_specials, ch)) { + cp++; + if (tok_count < token_len) + ACL_VSTRING_ADDCH(token_buffer, ch); + } + if (tok_count < token_len) { + ACL_VSTRING_ADDCH(token_buffer, 0); + tok_count++; + } + continue; + } + } + + /* + * Ignore a zero-length item after the last terminator. + */ + if (tok_count == 0 && ch == 0) + return (-1); + + /* + * Finalize. Fill in the string pointer array, now that the token buffer + * is no longer dynamically reallocated as it grows. + */ + *ptr = (const char *) cp; + for (n = 0; n < tok_count; n++) + token[n].u.value = STR(token_buffer) + token[n].u.offset; + + //if (acl_msg_verbose) + // acl_msg_info("header_token: %s %s %s", + // tok_count > 0 ? token[0].u.value : "", + // tok_count > 1 ? token[1].u.value : "", + // tok_count > 2 ? token[2].u.value : ""); + + return (tok_count); +} diff --git a/lib_acl_cpp/src/mime/internal/header_token.hpp b/lib_acl_cpp/src/mime/internal/header_token.hpp new file mode 100644 index 000000000..d1cc461ee --- /dev/null +++ b/lib_acl_cpp/src/mime/internal/header_token.hpp @@ -0,0 +1,49 @@ +#ifndef _HEADER_TOKEN_H_INCLUDED_ +#define _HEADER_TOKEN_H_INCLUDED_ + +/*++ + * NAME + * header_token 3h + * SUMMARY + * mail header parser + * SYNOPSIS + * #include "header_token.h" + * DESCRIPTION + * .nf + */ + + /* + * Utility library. + */ +#include +#include "stdlib/acl_vstring.h" + + /* + * HEADER header parser tokens. Specials and controls are represented by + * themselves. Character pointers point to substrings in a token buffer. + */ +typedef struct HEADER_TOKEN { + int type; /* see below */ + union { + const char *value; /* just a pointer, not a copy */ + ssize_t offset; /* index into token buffer */ + } u; /* indent beats any alternative */ +} HEADER_TOKEN; + +#define HEADER_TOK_TOKEN 256 +#define HEADER_TOK_QSTRING 257 + +extern ssize_t header_token(HEADER_TOKEN *, ssize_t, ACL_VSTRING *, const char **, const char *, int); + +/* LICENSE + * .ad + * .fi + * The Secure Mailer license must be distributed with this software. + * AUTHOR(S) + * Wietse Venema + * IBM T.J. Watson Research + * P.O. Box 704 + * Yorktown Heights, NY 10598, USA + *--*/ + +#endif diff --git a/lib_acl_cpp/src/mime/internal/is_header.cpp b/lib_acl_cpp/src/mime/internal/is_header.cpp new file mode 100644 index 000000000..8f6cbc256 --- /dev/null +++ b/lib_acl_cpp/src/mime/internal/is_header.cpp @@ -0,0 +1,92 @@ +/*++ + * NAME + * is_header 3 + * SUMMARY + * message header classification + * SYNOPSIS + * #include + * + * ssize_t is_header(string) + * const char *string; + * + * ssize_t is_header_buf(string, len) + * const char *string; + * ssize_t len; + * DESCRIPTION + * is_header() examines the given string and returns non-zero (true) + * when it begins with a mail header name + optional space + colon. + * The result is the length of the mail header name. + * + * is_header_buf() is a more elaborate interface for use with strings + * that may not be null terminated. + * STANDARDS + * RFC 822 (ARPA Internet Text Messages) + * LICENSE + * .ad + * .fi + * The Secure Mailer license must be distributed with this software. + * AUTHOR(S) + * Wietse Venema + * IBM T.J. Watson Research + * P.O. Box 704 + * Yorktown Heights, NY 10598, USA + *--*/ + +/* System library. */ + +#include "acl_stdafx.hpp" +#include + +/* Global library. */ + +#include "is_header.hpp" + +/* is_header_buf - determine if this can be a header line */ + +ssize_t is_header_buf(const char *str, ssize_t str_len) +{ + const unsigned char *cp; + int state; + int c; + ssize_t len; + +#define INIT 0 +#define IN_CHAR 1 +#define IN_CHAR_SPACE 2 +#define CU_CHAR_PTR(x) ((const unsigned char *) (x)) + + /* + * XXX RFC 2822 Section 4.5, Obsolete header fields: whitespace may + * appear between header label and ":" (see: RFC 822, Section 3.4.2.). + * + * XXX Don't run off the end in case some non-standard iscntrl() + * implementation considers null a non-control character... + */ + for (len = 0, state = INIT, cp = CU_CHAR_PTR(str); /* see below */; cp++) { + if (str_len != IS_HEADER_NULL_TERMINATED && str_len-- <= 0) + return (0); + switch (c = *cp) { + default: + if (c == 0 || !ACL_ISASCII(c) || ACL_ISCNTRL(c)) + return (0); + if (state == INIT) + state = IN_CHAR; + if (state == IN_CHAR) { + len++; + continue; + } + return (0); + case ' ': + case '\t': + if (state == IN_CHAR) + state = IN_CHAR_SPACE; + if (state == IN_CHAR_SPACE) + continue; + return (0); + case ':': + return ((state == IN_CHAR || state == IN_CHAR_SPACE) ? len : 0); + } + } + /* Redundant return for future proofing. */ + return (0); +} diff --git a/lib_acl_cpp/src/mime/internal/is_header.hpp b/lib_acl_cpp/src/mime/internal/is_header.hpp new file mode 100644 index 000000000..5d2764860 --- /dev/null +++ b/lib_acl_cpp/src/mime/internal/is_header.hpp @@ -0,0 +1,33 @@ +#ifndef _IS_HEADER_H_INCLUDED_ +#define _IS_HEADER_H_INCLUDED_ + +/*++ + * NAME + * is_header 3h + * SUMMARY + * message header classification + * SYNOPSIS + * #include + * DESCRIPTION + * .nf + */ + + /* External interface. */ + +#define IS_HEADER_NULL_TERMINATED (-1) +#define is_header(str) is_header_buf(str, IS_HEADER_NULL_TERMINATED) + +extern ssize_t is_header_buf(const char *, ssize_t); + +/* LICENSE + * .ad + * .fi + * The Secure Mailer license must be distributed with this software. + * AUTHOR(S) + * Wietse Venema + * IBM T.J. Watson Research + * P.O. Box 704 + * Yorktown Heights, NY 10598, USA + *--*/ + +#endif diff --git a/lib_acl_cpp/src/mime/internal/lex_822.hpp b/lib_acl_cpp/src/mime/internal/lex_822.hpp new file mode 100644 index 000000000..ec1680d9e --- /dev/null +++ b/lib_acl_cpp/src/mime/internal/lex_822.hpp @@ -0,0 +1,37 @@ +#ifndef _LEX_822_H_INCLUDED_ +#define _LEX_822_H_INCLUDED_ + +/*++ + * NAME + * lex_822 3h + * SUMMARY + * RFC822 lexicals + * SYNOPSIS + * #include + * DESCRIPTION + * .nf + */ + +/* + * The predicate macros. + */ +#define IS_SPACE_TAB(ch) (ch == ' ' || ch == '\t') +#define IS_SPACE_TAB_CR_LF(ch) (IS_SPACE_TAB(ch) || ch == '\r' || ch == '\n') + +/* + * Special characters as per RFC 822. + */ +#define LEX_822_SPECIALS "()<>@,;:\\\".[]" + +/* LICENSE + * .ad + * .fi + * The Secure Mailer license must be distributed with this software. + * AUTHOR(S) + * Wietse Venema + * IBM T.J. Watson Research + * P.O. Box 704 + * Yorktown Heights, NY 10598, USA + *--*/ + +#endif diff --git a/lib_acl_cpp/src/mime/internal/mime_state.cpp b/lib_acl_cpp/src/mime/internal/mime_state.cpp new file mode 100644 index 000000000..45c1df378 --- /dev/null +++ b/lib_acl_cpp/src/mime/internal/mime_state.cpp @@ -0,0 +1,495 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/stdlib/string.hpp" +#include "header_opts.hpp" +#include "mime_state.hpp" + +static MIME_NODE *node_iter_head(ACL_ITER *it, MIME_NODE *node) +{ + ACL_RING *ring_ptr; + + it->dlen = -1; + it->key = NULL; + it->klen = -1; + + it->i = 0; + it->size = node->children.len; + + if ((ring_ptr = acl_ring_succ(&node->children)) == &node->children) { + it->ptr = it->data = NULL; + return (NULL); + } + it->ptr = acl_ring_to_appl(ring_ptr, MIME_NODE, node); + it->data = it->ptr; + return ((MIME_NODE*) it->ptr); +} + +static MIME_NODE *node_iter_next(ACL_ITER *it, MIME_NODE *node) +{ + ACL_RING *ring_ptr; + MIME_NODE *child; + + child = (MIME_NODE*) it->data; + if ((ring_ptr = acl_ring_succ(&child->node)) == &node->children) { + it->ptr = it->data = NULL; + return (NULL); + } + it->i++; + it->ptr = acl_ring_to_appl(ring_ptr, MIME_NODE, node); + it->data = it->ptr; + return ((MIME_NODE*) it->ptr); +} + +static MIME_NODE *node_iter_tail(ACL_ITER *it, MIME_NODE *node) +{ + ACL_RING *ring_ptr; + + it->dlen = -1; + it->key = NULL; + it->klen = -1; + + it->i = 0; + it->size = node->children.len; + + if ((ring_ptr = acl_ring_pred(&node->children)) == &node->children) { + it->ptr = it->data = NULL; + return (NULL); + } + + it->ptr = acl_ring_to_appl(ring_ptr, MIME_NODE, node); + it->data = it->ptr; + return ((MIME_NODE*) it->ptr); +} + +static MIME_NODE *node_iter_prev(ACL_ITER *it, MIME_NODE *node) +{ + ACL_RING *ring_ptr; + MIME_NODE *child; + + child = (MIME_NODE*) it->data; + if ((ring_ptr = acl_ring_pred(&child->node)) == &node->children) { + it->ptr = it->data = NULL; + return (NULL); + } + it->i++; + it->ptr = acl_ring_to_appl(ring_ptr, MIME_NODE, node); + it->data = it->ptr; + return ((MIME_NODE*) it->ptr); +} + +MIME_NODE *mime_node_new(MIME_STATE *state) +{ + MIME_NODE *node = (MIME_NODE*) acl_mycalloc(1, sizeof(MIME_NODE)); + + node->buffer = acl_vstring_alloc(256); + node->state = state; + acl_ring_init(&node->children); + acl_ring_init(&node->node); + node->header_list = acl_fifo_new(); + + state->node_cnt++; + + node->iter_head = node_iter_head; + node->iter_next = node_iter_next; + node->iter_tail = node_iter_tail; + node->iter_prev = node_iter_prev; + + node->last_cr_pos = -1; + node->last_lf_pos = -1; + return (node); +} + +static void mail_addr_list_free(ACL_FIFO *mail_addr_list) +{ + MAIL_ADDR *mail_addr; + + while(1) { + mail_addr = (MAIL_ADDR*) acl_fifo_pop(mail_addr_list); + if (mail_addr == NULL) + break; + if (mail_addr->addr) + acl_myfree(mail_addr->addr); + if (mail_addr->comment) + acl_myfree(mail_addr->comment); + acl_myfree(mail_addr); + } + acl_fifo_free(mail_addr_list, NULL); +} + +static void mime_node_free(MIME_NODE *node) +{ + if (node->header_list) { + HEADER_NV *header; + while (1) { + header = (HEADER_NV*) acl_fifo_pop(node->header_list); + if (header == NULL) + break; + header_nv_free(header); + } + acl_fifo_free(node->header_list, NULL); + } + if (node->header_to_list) + mail_addr_list_free(node->header_to_list); + if (node->header_cc_list) + mail_addr_list_free(node->header_cc_list); + if (node->header_bcc_list) + mail_addr_list_free(node->header_bcc_list); + if (node->header_sender) + acl_myfree(node->header_sender); + if (node->header_from) + acl_myfree(node->header_from); + if (node->header_replyto) + acl_myfree(node->header_replyto); + if (node->header_returnpath) + acl_myfree(node->header_returnpath); + if (node->header_subject) + acl_myfree(node->header_subject); + + if (node->header_filename) + acl_myfree(node->header_filename); + if (node->header_name) + acl_myfree(node->header_name); + if (node->charset) + acl_myfree(node->charset); + + acl_vstring_free(node->buffer); + if (node->boundary) + acl_vstring_free(node->boundary); + if (node->body) + acl_vstring_free(node->body); + acl_myfree(node); +} + +int mime_node_delete(MIME_NODE *node) +{ + ACL_RING *next; + MIME_NODE *node_next; + int n = 1; + + while ((next = acl_ring_pop_head(&node->children)) != NULL) { + node_next = acl_ring_to_appl(next, MIME_NODE, node); + n += mime_node_delete(node_next); + } + + node->state->node_cnt--; + mime_node_free(node); + return (n); +} + +void mime_node_add_child(MIME_NODE *parent, MIME_NODE *child) +{ + acl_ring_prepend(&parent->children, &child->node); + child->parent = parent; +} + +/*-------------------------------------------------------------------------*/ + +static MIME_NODE *mime_iter_head(ACL_ITER *it, MIME_STATE *state) +{ +#if 0 + ACL_RING *ring_ptr; + + it->dlen = -1; + it->key = NULL; + it->klen = -1; + + it->i = 0; + it->size = state->node_cnt; + + ring_ptr = acl_ring_succ(&state->root->children); + if (ring_ptr== &state->root->children) { + it->ptr = it->data = NULL; + return (NULL); + } + it->ptr = acl_ring_to_appl(ring_ptr, MIME_NODE, node); + it->data = it->ptr; + return ((MIME_NODE*) it->ptr); +#else + it->dlen = -1; + it->key = NULL; + it->klen = -1; + + it->i = 0; + it->size = state->node_cnt; + + it->data = it->ptr = state->root; + return ((MIME_NODE*) it->data); +#endif +} + +static MIME_NODE *mime_iter_next(ACL_ITER *it, MIME_STATE *state) +{ + ACL_RING *ring_ptr; + MIME_NODE *node, *parent; + + node = (MIME_NODE*) it->data; + + /* 先遍历当前结点的子结点 */ + + ring_ptr = acl_ring_succ(&node->children); + if (ring_ptr != &node->children) { + it->i++; + it->ptr = acl_ring_to_appl(ring_ptr, MIME_NODE, node); + it->data = it->ptr; + return ((MIME_NODE*) it->ptr); + } + + /* 如果当前结点是根结点则直接返回空 */ + + if (node == state->root) { + it->ptr = it->data = NULL; + return (NULL); + } + + /* 当前结点的子结点遍历完毕,再遍历当前结点的兄弟结点 */ + + parent = node->parent; + ring_ptr = acl_ring_succ(&node->node); + if (ring_ptr != &parent->children) { + it->i++; + it->ptr = acl_ring_to_appl(ring_ptr, MIME_NODE, node); + it->data = it->ptr; + return ((MIME_NODE*) it->ptr); + } + + /* 当前结点的兄弟结点遍历完毕,最后遍历当前结点的父结点的兄弟结点 */ + + do { + ring_ptr = acl_ring_succ(&parent->node); + parent = parent->parent; + if (parent == NULL) + break; + + if (ring_ptr != &parent->children) { + it->i++; + it->ptr = acl_ring_to_appl(ring_ptr, MIME_NODE, node); + it->data = it->ptr; + return ((MIME_NODE*) it->ptr); + } + } while (ring_ptr != &state->root->children); + + /* 遍历完所有结点 */ + + it->ptr = it->data = NULL; + return (NULL); +} + +static MIME_NODE *mime_iter_tail(ACL_ITER *it, MIME_STATE *state) +{ +#if 0 + ACL_RING *ring_ptr; + + it->dlen = -1; + it->key = NULL; + it->klen = -1; + + it->i = 0; + it->size = state->node_cnt; + + ring_ptr = acl_ring_pred(&state->root->children); + if (ring_ptr== &state->root->children) { + it->ptr = it->data = NULL; + return (NULL); + } + it->ptr = acl_ring_to_appl(ring_ptr, MIME_NODE, node); + it->data = it->ptr; + return ((MIME_NODE*) it->ptr); +#else + it->dlen = -1; + it->key = NULL; + it->klen = -1; + + it->i = 0; + it->size = state->node_cnt; + + it->data = it->ptr = state->root; + return ((MIME_NODE*) it->ptr); +#endif +} + +static MIME_NODE *mime_iter_prev(ACL_ITER *it, MIME_STATE *state) +{ + ACL_RING *ring_ptr; + MIME_NODE *node, *parent; + + node = (MIME_NODE*) it->data; + + /* 先遍历当前结点的子结点 */ + + ring_ptr = acl_ring_pred(&node->children); + if (ring_ptr != &node->children) { + it->i++; + it->ptr = acl_ring_to_appl(ring_ptr, MIME_NODE, node); + it->data = it->ptr; + return ((MIME_NODE*) it->ptr); + } + + /* 如果当前结点是根结点则直接返回空 */ + + if (node == state->root) { + it->ptr = it->data = NULL; + return (NULL); + } + + /* 当前结点的子结点遍历完毕,再遍历当前结点的兄弟结点 */ + + parent = node->parent; + ring_ptr = acl_ring_pred(&node->node); + if (ring_ptr != &parent->children) { + it->i++; + it->ptr = acl_ring_to_appl(ring_ptr, MIME_NODE, node); + it->data = it->ptr; + return ((MIME_NODE*) it->ptr); + } + + /* 当前结点的兄弟结点遍历完毕,最后遍历当前结点的父结点的兄弟结点 */ + + do { + ring_ptr = acl_ring_pred(&parent->node); + parent = parent->parent; + if (parent == NULL) + break; + + if (ring_ptr != &parent->children) { + it->i++; + it->ptr = acl_ring_to_appl(ring_ptr, MIME_NODE, node); + it->data = it->ptr; + return ((MIME_NODE*) it->ptr); + } + } while (ring_ptr != &state->root->children); + + /* 遍历完所有结点 */ + + it->ptr = it->data = NULL; + return (NULL); +} + +void mime_state_foreach_init(MIME_STATE *state) +{ + state->iter_head = mime_iter_head; + state->iter_next = mime_iter_next; + state->iter_tail = mime_iter_tail; + state->iter_prev = mime_iter_prev; +} + +MIME_STATE *mime_state_alloc() +{ + MIME_STATE *state; + + state = (MIME_STATE*) acl_mycalloc(1, sizeof(MIME_STATE)); + state->root = mime_node_new(state); + state->curr_node = state->root; + state->curr_status = MIME_S_HEAD; + state->token_buffer = acl_vstring_alloc(256); + state->key_buffer = acl_vstring_alloc(128); + + state->iter_head = mime_iter_head; + state->iter_next = mime_iter_next; + state->iter_tail = mime_iter_tail; + state->iter_prev = mime_iter_prev; + + return (state); +} + +int mime_state_free(MIME_STATE *state) +{ + ACL_RING *next; + MIME_NODE *node; + int n = 1; + + while ((next = acl_ring_pop_head(&state->root->children)) != NULL) { + node = acl_ring_to_appl(next, MIME_NODE, node); + n += mime_node_delete(node); + } + + mime_node_free(state->root); + state->node_cnt--; + n = state->node_cnt; + acl_vstring_free(state->token_buffer); + acl_vstring_free(state->key_buffer); + acl_myfree(state); + + return (n); +} + +int mime_state_reset(MIME_STATE *state) +{ + ACL_RING *next; + MIME_NODE *node; + int n; + + while ((next = acl_ring_pop_head(&state->root->children)) != NULL) { + node = acl_ring_to_appl(next, MIME_NODE, node); + (void) mime_node_delete(node); + } + + mime_node_free(state->root); + state->node_cnt--; + n = state->node_cnt; + + state->root = mime_node_new(state); + state->curr_node = state->root; + state->curr_status = MIME_S_HEAD; + ACL_VSTRING_RESET(state->token_buffer); + + state->depth = 0; + state->curr_bound = NULL; + state->curr_off = 0; + return (n); +} + +int mime_state_head_finish(MIME_STATE *state) +{ + if (state->curr_node != state->root) + return (1); + if (state->curr_status > MIME_S_HEAD) + return (1); + return (0); +} +/*-------------------------------------------------------------------------*/ + +typedef struct { + int type; + const char *name; +} MIME_TYPE; + +static MIME_TYPE mime_ctype_map[] = { + { MIME_CTYPE_OTHER, "other" }, + { MIME_CTYPE_TEXT, "text" }, + { MIME_CTYPE_MESSAGE, "message" }, + { MIME_CTYPE_MULTIPART, "multipart" }, + { MIME_CTYPE_IMAGE, "image" }, + { MIME_CTYPE_APPLICATION, "application" }, +}; + +static MIME_TYPE mime_stype_map[] = { + { MIME_STYPE_OTHER, "other" }, + { MIME_STYPE_PLAIN, "plain" }, + { MIME_STYPE_HTML, "html" }, + { MIME_STYPE_RFC822, "rfc822" }, + { MIME_STYPE_PARTIAL, "partial" }, + { MIME_STYPE_EXTERN_BODY, "extern body" }, + { MIME_STYPE_JPEG, "jpeg" }, + { MIME_STYPE_GIF, "gif" }, + { MIME_STYPE_BMP, "bmp" }, + { MIME_STYPE_PNG, "png" }, + { MIME_STYPE_OCTET_STREAM, "octet-stream" }, + { MIME_STYPE_MIXED, "mixed" }, + { MIME_STYPE_ALTERNATIVE, "alternative" }, + { MIME_STYPE_RELATED, "related" }, +}; + +#define OTHER_NAME "other" + +const char *mime_ctype_name(size_t ctype) +{ + if (ctype > MIME_CTYPE_MAX) + return (OTHER_NAME); + return (mime_ctype_map[ctype].name); +} + +const char *mime_stype_name(size_t stype) +{ + if (stype > MIME_STYPE_MAX) + return (OTHER_NAME); + return (mime_stype_map[stype].name); +} diff --git a/lib_acl_cpp/src/mime/internal/mime_state.hpp b/lib_acl_cpp/src/mime/internal/mime_state.hpp new file mode 100644 index 000000000..7659353fa --- /dev/null +++ b/lib_acl_cpp/src/mime/internal/mime_state.hpp @@ -0,0 +1,133 @@ +#ifndef __MIME_STATE_INCLUDE__ +#define __MIME_STATE_INCLUDE__ + +#include "lib_acl.h" +#include "acl_cpp/mime/mime_define.hpp" +#include "header_token.hpp" + +typedef struct MIME_NODE MIME_NODE; +typedef struct MIME_STATE MIME_STATE; +typedef struct MAIL_ADDR MAIL_ADDR; + +struct MAIL_ADDR +{ + char *addr; + char *comment; +}; + +struct MIME_NODE +{ + ACL_RING children; /**< 子结点集合 */ + int depth; /**< 当前结点的深度 */ + MIME_NODE *parent; /**< 父结点 */ + MIME_STATE *state; /**< MIME_STATE 对象 */ + + /* 邮件头 */ + ACL_FIFO *header_list; /**< HEADER_NV 集合 */ + ACL_FIFO *header_to_list; /**< MAIL_ADDR 集合 */ + ACL_FIFO *header_cc_list; /**< MAIL_ADDR 集合 */ + ACL_FIFO *header_bcc_list; /**< MAIL_ADDR 集合 */ + char *header_sender; + char *header_from; + char *header_replyto; + char *header_returnpath; + char *header_subject; + + /* multipart 头 */ + char *header_filename; + + /* 通用头 */ + int ctype; /**< MIME_CTYPE_XXX */ + int stype; /**< MIME_STYPE_XXX */ + char *charset; + char *header_name; + + int domain; + int encoding; /**< MIME_ENC_XXX */ + int valid_line; + char last_ch; /**< 分析过程中记录的前一个字节 */ + char last_lf; /**< 分析头部每行数据时前一个 \n */ + off_t last_cr_pos; /**< 上一个 \r 的偏移位置 */ + off_t last_lf_pos; /**< 上一个 \n 的偏移位置 */ + ACL_VSTRING *boundary; /**< 当是 multipart 邮件时存储分隔符 */ + + /**< 当是 multipart 邮件时记录分隔符的下一个匹配位置, + 当该值指向分隔符尾部时说明完全匹配完毕 */ + const char *bound_ptr; + + char bound_term[3]; + ACL_VSTRING *buffer; /**< headers, quoted-printable body */ + ACL_VSTRING *body; + ACL_RING node; /**< 当前结点 */ + + off_t header_begin; /**< 结点头开始位置 */ + off_t header_end; /**< 结点头结束位置 */ + off_t body_begin; /**< 结点体开始位置 */ + off_t body_end; /**< 结点体结束位置 */ + off_t body_data_end; /**< 结点数据体结束位置 */ + off_t bound_end; /**< 分隔体结束位置 */ + + /* for acl_iterator, 通过 acl_foreach 列出该结点的一级子结点 */ + + /* 取迭代器头函数 */ + MIME_NODE *(*iter_head)(ACL_ITER*, MIME_NODE*); + /* 取迭代器下一个函数 */ + MIME_NODE *(*iter_next)(ACL_ITER*, MIME_NODE*); + /* 取迭代器尾函数 */ + MIME_NODE *(*iter_tail)(ACL_ITER*, MIME_NODE*); + /* 取迭代器上一个函数 */ + MIME_NODE *(*iter_prev)(ACL_ITER*, MIME_NODE*); +}; + +#define MIME_MAX_TOKEN 3 /* tokens per attribute */ + +struct MIME_STATE +{ + int depth; /**< 最大深度 */ + int node_cnt; /**< 结点总数, 包括 root 结点 */ + MIME_NODE *root; /**< MIME_NODE 根结点 */ + int use_crlf; /**< 是用 \r\n 还是用 \n 做为换行符 */ + + /* private */ + + MIME_NODE *curr_node; /**< 当前正在处理的 MIME_NODE 结点 */ + const char *curr_bound; /**< 针对 multipart 邮件, 当前的分隔符 */ + off_t curr_off; /**< 针对邮件的当前偏移, 它总是会指向下一个位置 */ + int curr_status; /**< 状态机当前解析状态 */ +#define MIME_S_HEAD 0 +#define MIME_S_BODY 1 +#define MIME_S_BODY_BOUND_CRLF 2 +#define MIME_S_MULTI_BOUND 3 +#define MIME_S_MULTI_BOUND_CRLF 4 +#define MIME_S_TERM 5 + + HEADER_TOKEN token[MIME_MAX_TOKEN]; /* header token array */ + ACL_VSTRING *token_buffer; /* header parser scratch buffer */ + ACL_VSTRING *key_buffer; + + /* for acl_iterator, 通过 acl_foreach 可以列出所有子结点 */ + + /* 取迭代器头函数 */ + MIME_NODE *(*iter_head)(ACL_ITER*, MIME_STATE*); + /* 取迭代器下一个函数 */ + MIME_NODE *(*iter_next)(ACL_ITER*, MIME_STATE*); + /* 取迭代器尾函数 */ + MIME_NODE *(*iter_tail)(ACL_ITER*, MIME_STATE*); + /* 取迭代器上一个函数 */ + MIME_NODE *(*iter_prev)(ACL_ITER*, MIME_STATE*); +}; + +MIME_STATE *mime_state_alloc(void); +void mime_state_foreach_init(MIME_STATE *state); +int mime_state_free(MIME_STATE *state); +int mime_state_reset(MIME_STATE *state); +int mime_state_update(MIME_STATE *state, const char *data, int len); +int mime_state_head_finish(MIME_STATE *state); + +MIME_NODE *mime_node_new(MIME_STATE *state); +int mime_node_delete(MIME_NODE *node); +void mime_node_add_child(MIME_NODE *parent, MIME_NODE *child); +const char *mime_ctype_name(size_t ctype); +const char *mime_stype_name(size_t stype); + +#endif diff --git a/lib_acl_cpp/src/mime/internal/mime_state_parse.cpp b/lib_acl_cpp/src/mime/internal/mime_state_parse.cpp new file mode 100644 index 000000000..a74b79c19 --- /dev/null +++ b/lib_acl_cpp/src/mime/internal/mime_state_parse.cpp @@ -0,0 +1,958 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/stdlib/string.hpp" +#include "header_opts.hpp" +#include "tok822.hpp" +#include "rec_type.hpp" +#include "lex_822.hpp" +#include "rec_type.hpp" +#include "mime_state.hpp" + +#define SCP(x, s) acl_vstring_strcpy((x), (s)) +#define SCAT(x, s) acl_vstring_strcat((x), (s)) +#define STR(x) acl_vstring_str((x)) +#define LEN(x) ACL_VSTRING_LEN((x)) +#define END(x) acl_vstring_end((x)) +#define TERM(x) ACL_VSTRING_TERMINATE((x)) +#define ADDCH(x, ch) { ACL_VSTRING_ADDCH((x), (ch)); TERM((x)); } +#define APPEND(x, s, n) { acl_vstring_memcat((x), (s), (n)); TERM((x)); } +#define EQUAL(x, y) !strcasecmp((x), (y)) + +/* +* MIME encodings and domains. We intentionally use the same codes for +* encodings and domains, so that we can easily find out whether a content +* transfer encoding header specifies a domain or whether it specifies +* domain+encoding, which is illegal for multipart/any and message/any. +*/ +typedef struct MIME_ENCODING { + const char *name; /* external representation */ + int encoding; /* internal representation */ + int domain; /* subset of encoding */ +} MIME_ENCODING; + +static const MIME_ENCODING mime_encoding_map[] = { /* RFC 2045 */ + { "7bit", MIME_ENC_7BIT, MIME_ENC_7BIT }, /* domain */ + { "8bit", MIME_ENC_8BIT, MIME_ENC_8BIT }, /* domain */ + { "binary", MIME_ENC_BINARY, MIME_ENC_BINARY }, /* domain */ + { "base64", MIME_ENC_BASE64, MIME_ENC_7BIT }, /* encoding */ + { "uucode", MIME_ENC_UUCODE, MIME_ENC_7BIT }, /* encoding */ + { "xxcode", MIME_ENC_XXCODE, MIME_ENC_7BIT }, /* encoding */ + { "quoted-printable", MIME_ENC_QP, MIME_ENC_7BIT }, /* encoding */ + { 0, 0, 0 }, +}; + +/*-------------------------------------------------------------------------*/ + +#define RFC2045_TSPECIALS "()<>@,;:\\\"/[]?=" +#define TOKEN_MATCH(tok, text) \ + ((tok).type == HEADER_TOK_TOKEN && EQUAL((tok).u.value, (text))) + +static void mime_content_type(MIME_NODE *node, const HEADER_OPTS *header_info) +{ + const char *cp; + ssize_t tok_count; + MIME_STATE *state = node->state; + +#define PARSE_CONTENT_TYPE_HEADER(state, ptr) \ + header_token(state->token, MIME_MAX_TOKEN, \ + state->token_buffer, ptr, RFC2045_TSPECIALS, ';') + + cp = STR(node->buffer) + strlen(header_info->name) + 1; + if ((tok_count = PARSE_CONTENT_TYPE_HEADER(state, &cp)) <= 0) { + + /* + * other/whatever. + */ + node->ctype = MIME_CTYPE_OTHER; + return; + } + + /* tok_count > 0 */ + + /* + * message/whatever body parts start with another block of message + * headers that we may want to look at. The partial and external-body + * subtypes cannot be subjected to 8-bit -> 7-bit conversion, so we + * must properly recognize them. + */ + if (TOKEN_MATCH(state->token[0], "message")) { + node->ctype = MIME_CTYPE_MESSAGE; + node->stype = MIME_STYPE_OTHER; + if (tok_count >= 3 && state->token[1].type == '/') { + if (TOKEN_MATCH(state->token[2], "rfc822")) + node->stype = MIME_STYPE_RFC822; + else if (TOKEN_MATCH(state->token[2], "partial")) + node->stype = MIME_STYPE_PARTIAL; + else if (TOKEN_MATCH(state->token[2], "external-body")) + node->stype = MIME_STYPE_EXTERN_BODY; + } + } + + /* + * multipart/digest has default content type message/rfc822, + * multipart/whatever has default content type text/plain. + */ + else if (TOKEN_MATCH(state->token[0], "multipart")) { + node->ctype = MIME_CTYPE_MULTIPART; + if (tok_count >= 3 && state->token[1].type == '/') { + if (TOKEN_MATCH(state->token[2], "digest")) { + node->ctype = MIME_CTYPE_MESSAGE; + node->stype = MIME_STYPE_RFC822; + } else if (TOKEN_MATCH(state->token[2], "alternative")) { + node->stype = MIME_STYPE_ALTERNATIVE; + } else if (TOKEN_MATCH(state->token[2], "related")) { + node->stype = MIME_STYPE_RELATED; + } else if (TOKEN_MATCH(state->token[2], "mixed")) { + node->stype = MIME_STYPE_MIXED; + } else { + node->stype = MIME_STYPE_OTHER; + } + } else { + node->ctype = MIME_CTYPE_TEXT; + node->stype = MIME_STYPE_PLAIN; + } + + /* + * Yes, this is supposed to capture multiple boundary strings, + * which are illegal and which could be used to hide content in + * an implementation dependent manner. The code below allows us + * to find embedded message headers as long as the sender uses + * only one of these same-level boundary strings. + * + * Yes, this is supposed to ignore the boundary value type. + */ + while ((tok_count = PARSE_CONTENT_TYPE_HEADER(state, &cp)) >= 0) { + if (tok_count < 3 || state->token[1].type != '=') + continue; + if (TOKEN_MATCH(state->token[0], "boundary")) { + if (node->boundary == NULL) + node->boundary = acl_vstring_alloc(256); + /* 需要添加 "--" 做为分隔符的前导符 */ + SCP(node->boundary, "--"); + SCAT(node->boundary, state->token[2].u.value); + break; + } + } + } + + /* + * text/whatever. Right now we don't really care if it is plain or + * not, but we may want to recognize subtypes later, and then this + * code can serve as an example. + */ + else if (TOKEN_MATCH(state->token[0], "text")) { + node->ctype = MIME_CTYPE_TEXT; + if (tok_count >= 3 && state->token[1].type == '/') { + if (TOKEN_MATCH(state->token[2], "plain")) + node->stype = MIME_STYPE_PLAIN; + else if (TOKEN_MATCH(state->token[2], "html")) + node->stype = MIME_STYPE_HTML; + else + node->stype = MIME_STYPE_OTHER; + } else + node->stype = MIME_STYPE_OTHER; + + while ((tok_count = PARSE_CONTENT_TYPE_HEADER(state, &cp)) >= 0) { + if (tok_count < 3 || state->token[1].type != '=') + continue; + if (TOKEN_MATCH(state->token[0], "charset") + && node->charset == NULL) + { + node->charset = acl_mystrdup(state->token[2].u.value); + break; + } + } + + /* 如果没有字符集, 则缺省采用 gb2312 */ + if (node->charset == NULL) + node->charset = acl_mystrdup("gb2312"); + } + else if (TOKEN_MATCH(state->token[0], "image")) { + node->ctype = MIME_CTYPE_IMAGE; + if (tok_count >= 3 && state->token[1].type == '/') { + if (TOKEN_MATCH(state->token[2], "jpeg")) + node->stype = MIME_STYPE_JPEG; + else if (TOKEN_MATCH(state->token[2], "gif")) + node->stype = MIME_STYPE_GIF; + else if (TOKEN_MATCH(state->token[2], "bmp")) + node->stype = MIME_STYPE_BMP; + else if (TOKEN_MATCH(state->token[2], "png")) + node->stype = MIME_STYPE_PNG; + else + node->stype = MIME_STYPE_OTHER; + } else + node->stype = MIME_STYPE_OTHER; + + while ((tok_count = PARSE_CONTENT_TYPE_HEADER(state, &cp)) >= 0) { + if (tok_count < 3 || state->token[1].type != '=') + continue; + if (TOKEN_MATCH(state->token[0], "name") + && node->header_name == NULL) + { + node->header_name = acl_mystrdup(state->token[2].u.value); + break; + } + } + } + else if (TOKEN_MATCH(state->token[0], "application")) { + node->ctype = MIME_CTYPE_APPLICATION; + if (tok_count >= 3 && state->token[1].type == '/') { + if (TOKEN_MATCH(state->token[2], "octet-stream")) + node->stype = MIME_STYPE_OCTET_STREAM; + else + node->stype = MIME_STYPE_OTHER; + } + while ((tok_count = PARSE_CONTENT_TYPE_HEADER(state, &cp)) >= 0) { + if (tok_count < 3 || state->token[1].type != '=') + continue; + if (TOKEN_MATCH(state->token[0], "name") + && node->header_name == NULL) + { + node->header_name = acl_mystrdup(state->token[2].u.value); + break; + } + } + } +} + +/* mime_state_content_encoding - process content-transfer-encoding header */ + +static void mime_content_encoding(MIME_NODE *node, + const HEADER_OPTS *header_info) +{ + MIME_STATE *state = node->state; + const char *cp; + const MIME_ENCODING *cmp; + +#define PARSE_CONTENT_ENCODING_HEADER(state, ptr) \ + header_token(state->token, 1, state->token_buffer, ptr, (char *) 0, 0) + + /* + * Do content-transfer-encoding header. Never set the encoding domain to + * something other than 7bit, 8bit or binary, even if we don't recognize + * the input. + */ + cp = STR(node->buffer) + strlen(header_info->name) + 1; + if (PARSE_CONTENT_ENCODING_HEADER(state, &cp) > 0 + && state->token[0].type == HEADER_TOK_TOKEN) + { + for (cmp = mime_encoding_map; cmp->name != 0; cmp++) { + if (EQUAL(state->token[0].u.value, cmp->name)) { + node->encoding = cmp->encoding; + node->domain = cmp->domain; + break; + } + } + } +} + +static void mime_content_disposition(MIME_NODE *node, + const HEADER_OPTS *header_info) +{ + const char *cp = STR(node->buffer) + strlen(header_info->name) + 1; + ssize_t tok_count; + +#define PARSE_CONTENT_DISPOSITION(state, ptr) \ + header_token(state->token, MIME_MAX_TOKEN, \ + state->token_buffer, ptr, RFC2045_TSPECIALS, ';') + + while ((tok_count = PARSE_CONTENT_DISPOSITION(node->state, &cp)) > 0) { + if (tok_count < 3 || node->state->token[1].type != '=') + continue; + if (TOKEN_MATCH(node->state->token[0], "filename") + && node->header_filename == NULL) + { + node->header_filename = + acl_mystrdup(node->state->token[2].u.value); + } else if (TOKEN_MATCH(node->state->token[0], "name") + && node->header_name == NULL) + { + node->header_name = + acl_mystrdup(node->state->token[2].u.value); + } + } +} + +/* mime_state_downgrade - convert 8-bit data to quoted-printable */ + +void mime_state_downgrade(MIME_STATE *state, int rec_type, + const char *text, ssize_t len) +{ + static char hexchars[] = "0123456789ABCDEF"; + const unsigned char *cp; + MIME_NODE *node = state->curr_node; + int ch; + +#define CU_CHAR_PTR(x) ((const unsigned char *) (x)) +#define QP_ENCODE(buffer, ch) { \ + buffer += '='; \ + buffer += (char) hexchars[(ch >> 4) & 0xff]; \ + buffer += (char) hexchars[ch & 0xf]; \ +} + + /* + * Insert a soft line break when the output reaches a critical length + * before we reach a hard line break. + */ + for (cp = CU_CHAR_PTR(text); cp < CU_CHAR_PTR(text + len); cp++) { + /* Critical length before hard line break. */ + if (LEN(node->buffer) > 72) { + node->buffer += '='; + } + /* Append the next character. */ + ch = *cp; + if ((ch < 32 && ch != '\t') || ch == '=' || ch > 126) { + QP_ENCODE(node->buffer, ch); + } else { + ADDCH(node->buffer, ch); + } + } + + /* + * Flush output after a hard line break (i.e. the end of a REC_TYPE_NORM + * record). Fix trailing whitespace as per the RFC: in the worst case, + * the output length will grow from 73 characters to 75 characters. + */ + if (rec_type == REC_TYPE_NORM) { + if (LEN(node->buffer) > 0 + && ((ch = END(node->buffer)[-1]) == ' ' || ch == '\t')) + { + acl_vstring_truncate(node->buffer, LEN(node->buffer) - 1); + QP_ENCODE(node->buffer, ch); + } + ACL_VSTRING_TERMINATE(node->buffer); + } +} + +static ACL_FIFO *mail_addr_add(ACL_FIFO *addr_list, const char *addr) +{ + MAIL_ADDR *mail_addr; + + if (addr_list == NULL) + addr_list = acl_fifo_new(); + mail_addr = (MAIL_ADDR*) acl_mycalloc(1, sizeof(MAIL_ADDR)); + mail_addr->addr = acl_mystrdup(addr); + acl_fifo_push(addr_list, mail_addr); + return (addr_list); +} + +static void mail_rcpt(MIME_NODE *node, const HEADER_OPTS *header_info) +{ + TOK822 *tree; + TOK822 **addr_list; + TOK822 **tpp; + ACL_VSTRING *temp; + const char *cp; + + temp = acl_vstring_alloc(10); + cp = STR(node->buffer) + strlen(header_info->name) + 1; + tree = tok822_parse(cp); + addr_list = tok822_grep(tree, TOK822_ADDR); + for (tpp = addr_list; *tpp; tpp++) { + tok822_internalize(temp, tpp[0]->head, TOK822_STR_DEFL); + if (header_info->type == HDR_TO) { + node->header_to_list = + mail_addr_add(node->header_to_list, STR(temp)); + } else if (header_info->type == HDR_CC) { + node->header_cc_list = + mail_addr_add(node->header_cc_list, STR(temp)); + } else if (header_info->type == HDR_BCC) { + node->header_bcc_list = + mail_addr_add(node->header_bcc_list, STR(temp)); + } + } + + acl_myfree(addr_list); + tok822_free_tree(tree); + acl_vstring_free(temp); +} + +static void mail_from(MIME_NODE *node, const HEADER_OPTS *header_info) +{ + //MIME_STATE *state = node->state; + TOK822 *tree; + TOK822 **addr_list; + TOK822 **tpp; + ACL_VSTRING *temp; + const char *cp; + + temp = acl_vstring_alloc(10); + cp = STR(node->buffer) + strlen(header_info->name) + 1; + tree = tok822_parse(cp); + addr_list = tok822_grep(tree, TOK822_ADDR); + for (tpp = addr_list; *tpp; tpp++) { + tok822_internalize(temp, tpp[0]->head, TOK822_STR_DEFL); + if (header_info->type == HDR_SENDER) { + if (node->header_sender) + acl_myfree(node->header_sender); + node->header_sender = acl_mystrdup(STR(temp)); + break; + } else if (header_info->type == HDR_FROM) { + if (node->header_from) + acl_myfree(node->header_from); + node->header_from = acl_mystrdup(STR(temp)); + break; + } else if (header_info->type == HDR_REPLY_TO) { + if (node->header_replyto) + acl_myfree(node->header_replyto); + node->header_replyto = acl_mystrdup(STR(temp)); + break; + } else if (header_info->type == HDR_RETURN_PATH) { + if (node->header_returnpath) + acl_myfree(node->header_returnpath); + node->header_returnpath = acl_mystrdup(STR(temp)); + } + } + + acl_myfree(addr_list); + + tok822_free_tree(tree); + acl_vstring_free(temp); +} + +static void mail_subject(MIME_NODE *node, const HEADER_OPTS *header_info) +{ + const char *cp; + + if (header_info->type != HDR_SUBJECT) + return; + + cp = STR(node->buffer) + strlen(header_info->name) + 1; + if (strlen(cp) == 0) + return; + if (node->header_subject) + acl_myfree(node->header_subject); + node->header_subject = acl_mystrdup(cp); +} + +static void mime_header_line(MIME_NODE *node) +{ + const HEADER_OPTS *header_info; + size_t len = LEN(node->buffer); + char *ptr = strrchr(STR(node->buffer), '\n'); + + if (ptr) { + *ptr-- = 0; + len--; + if (ptr > STR(node->buffer)) { + if (*ptr == '\r') { + *ptr = 0; + len--; + } + } + if (len == 0) + return; + + acl_vstring_truncate(node->buffer, len); + } + + header_info = header_opts_find(STR(node->buffer), node->state->key_buffer); + if (header_info) { + if (header_info->type == HDR_CONTENT_TYPE) + mime_content_type(node, header_info); + else if (header_info->type == HDR_CONTENT_TRANSFER_ENCODING) + mime_content_encoding(node, header_info); + else if (node == node->state->root) { + /* 说明邮件头 */ + + if ((header_info->flags & HDR_OPT_RECIP) + && (header_info->flags & HDR_OPT_EXTRACT)) + { + /* 分析收件人地址: To, Cc, Bcc */ + mail_rcpt(node, header_info); + } else if ((header_info->flags & HDR_OPT_SENDER)) { + /* 分析发件人地址: From, Sender, + * Replyto, Returnpath + */ + mail_from(node, header_info); + } else if ((header_info->flags & HDR_OPT_SUBJECT)) { + mail_subject(node, header_info); + } + } else if (header_info->type == HDR_CONTENT_DISPOSITION) { + mime_content_disposition(node, header_info); + } + } + + if (node->header_list) { + HEADER_NV *header = header_split(STR(node->buffer)); + if (header) + node->header_list->push_back(node->header_list, header); + } + + ACL_VSTRING_RESET(node->buffer); /* 清空缓冲区 */ + node->last_ch = 0; + node->last_lf = 0; +} + +/* 状态机数据结构类型 */ + +struct MIME_STATUS_MACHINE { + /**< 状态码 */ + int status; + + /**< 状态机处理函数 */ + int (*callback) (MIME_STATE*, const char*, int); +}; + +// 分析邮件头及 multipart 各部分的头 +static int mime_state_head(MIME_STATE *state, const char *s, int n) +{ + MIME_NODE *node = state->curr_node; + + if (n <= 0) + return (n); + + /* 如果还未找到换行符,则继续 */ + + if (node->last_lf != '\n') { + while (n > 0) { + node->last_ch = *s; + ADDCH(node->buffer, node->last_ch); + n--; + state->curr_off++; + + if (node->last_ch == '\n') { + node->last_lf = '\n'; + break; + } + s++; + } + + return (n); + } + + /* 如果数据以换行开始, 说明当前的邮件头结束 */ + + if (*s == '\n') { + /* 上次数据为: \n\r 或 \n */ + + state->curr_off++; + node->header_end = state->curr_off; + + if (LEN(node->buffer) > 0) { + /* 处理头部的最后一行数据 */ + mime_header_line(node); + node->valid_line++; + } + + /* 略过开头无用的空行 */ + if (node->valid_line == 0) + return (0); + + /* 如果当前结点为 multipart 格式, 则重置 state->curr_bound */ + if (node->boundary != NULL) + state->curr_bound = STR(node->boundary); + state->curr_status = MIME_S_BODY; + node->body_begin = state->curr_off; + return (n - 1); + } + if (*s == '\r') { + state->curr_off++; + if (node->last_ch == '\r') { + /* XXX: 出现了 \n\r\r 现象 */ + node->last_ch = '\r'; + node->last_lf = 0; + return (n - 1); + } + + node->last_ch = '\r'; + /* 返回, 以期待下一个字符为 '\n' */ + return (n - 1); + } + + /* 清除 '\n' */ + node->last_lf = 0; + + /* 如果数据以空格或TAB开始, 说明数据附属于上一行 */ + + if (IS_SPACE_TAB(*s)) { + /* 说明本行数据附属于上一行数据 */ + while (n > 0) { + node->last_ch = *s; + ADDCH(node->buffer, node->last_ch); + n--; + state->curr_off++; + + if (node->last_ch == '\n') { + /* 处理完本完整行数据 */ + node->last_lf = '\n'; + break; + } + s++; + } + return (n); + } + + /* 处理头部的上一行数据 */ + + if (LEN(node->buffer) > 0) { + mime_header_line(node); + node->valid_line++; + } + return (n); +} + +// 分析 multipart 部分体, 当匹配到一个完整的分隔符后则表明该部分数据体分析完毕 +static int mime_bound_body(const char *boundary, MIME_NODE *node, + const char *s, int n, int *finish) +{ + const unsigned char *cp; + const unsigned char *startn = NULL; + + for (cp = (const unsigned char *) s; + cp < (const unsigned char *) s + n; cp++) + { + // 记录下 \r\n 的位置 + if (*cp == '\r') + node->last_cr_pos = node->state->curr_off; + else if (*cp == '\n') + node->last_lf_pos = node->state->curr_off; + + node->state->curr_off++; + if (node->bound_ptr) { + if (*cp == *node->bound_ptr) { + node->bound_ptr++; + if (*node->bound_ptr == 0) { + + /* 说明完全匹配 */ + *finish = 1; + + node->body_end = node->state->curr_off + - strlen(node->state->curr_bound); + node->body_data_end = node->body_end; + + // 因为 body_end 记录的是某个结点最后的位置,其中会包含 + // 根据协议附加的 \r\n,所以真实数据的结束位置 body_data_end + // 得是去掉这些数据后的位置 + if (node->last_lf_pos + (off_t) strlen(boundary) + == node->state->curr_off - 1) + { + node->body_data_end--; + if (node->last_cr_pos + 1 == node->last_lf_pos) + node->body_data_end--; + } + + if (startn > (const unsigned char *) s) { + + /* 将匹配之前的数据拷贝 */ + APPEND(node->body, (const char*) s, + (const char*) startn - s); + } + node->bound_ptr = NULL; + cp++; + break; + } + } else { + /* 说明之前的匹配失效,需要重新匹配, + * 但必须将之前匹配的字符拷贝 + */ + + if (node->bound_ptr > boundary) { + APPEND(node->body, boundary, + node->bound_ptr - boundary); + } + node->bound_ptr = NULL; + } + } + if (!node->bound_ptr) { + if (*cp == *boundary) { + node->bound_ptr = boundary + 1; + + /* 说明完全匹配 */ + if (*node->bound_ptr == 0) { + node->body_end = node->state->curr_off + - strlen(node->state->curr_bound); + node->body_data_end = node->body_end; + + // 因为 body_end 记录的是某个结点最后的位置,其中会包含 + // 根据协议附加的 \r\n,所以真实数据的结束位置 body_data_end + // 得是去掉这些数据后的位置 + if (node->last_lf_pos + (off_t) strlen(boundary) + == node->state->curr_off - 1) + { + node->body_data_end--; + if (node->last_cr_pos + 1 == node->last_lf_pos) + node->body_data_end--; + } + *finish = 1; + node->bound_ptr = NULL; + cp++; + break; + } + startn = cp; + } else { + ADDCH(node->body, *cp); + } + } + } + + return (n - ((const char*) cp - s)); +} + +// 分析邮件体或 multipart 部分体 +static int mime_state_body(MIME_STATE *state, const char *s, int n) +{ + int finish = 0; + + if (state->curr_node->body == NULL) + state->curr_node->body = acl_vstring_alloc(1024); + + if (state->curr_bound == NULL) { + + /* 如果没有分隔符,则说明是文本类型,即只有正文内容 */ + + APPEND(state->curr_node->body, s, n); + state->curr_off += n; + + /* 因为 curr_off 指向的是下一个偏移位置,所以 body_end = curr_off - 1 */ + state->curr_node->body_end = state->curr_off - 1; + state->curr_node->body_data_end = state->curr_node->body_end; // add by zsx, 2012.5.28 + return (0); + } + + n = mime_bound_body(state->curr_bound, state->curr_node, s, n, &finish); + if (finish) + state->curr_status = MIME_S_BODY_BOUND_CRLF; + + return (n); +} + +// 查找分隔符后的 "\r\n" +static int mime_state_body_bound_crlf(MIME_STATE *state, const char *s, int n) +{ + if (n <= 0) + return (n); + + /* 如果不是分隔符的最后两个 "--" 则说明还由其它结点由本分隔符分隔 */ + + if (*s == '\n') { + state->curr_node->last_lf_pos = state->curr_off; + state->curr_node->last_ch = '\n'; + + state->curr_off++; + state->curr_node->bound_end = state->curr_node->state->curr_off; + + /* + state->curr_node->body_end = state->curr_node->bound_end + - strlen(state->curr_bound) - 1; + if (state->curr_node->last_ch == '\r') + state->curr_node->body_end--; + */ + + /* 如果结束符为 "--\r\n", 说明不仅结点结束, + * 同时本结点的父结点也结束 + */ + if (state->curr_node->bound_term[0] == '-' + && state->curr_node->bound_term[1] == '-') + { + /* 说明本分隔符所约束的结点完毕 */ + + if (state->curr_node == state->root) { + /* xxx: 本结点不应为根结点 */ + state->curr_status = MIME_S_TERM; + } else if (state->curr_node->parent == state->root) { + /* 说明根结点的一级子结点都结束, 则整封邮件分析完毕 */ + state->curr_status = MIME_S_TERM; + } else { + /* 说明本结点为根结点的二级或以上结点, 同时说明 + * 本结点的父结点已经结束, 下一步需要找出本结点的 + * 爷爷结点的分隔符 + */ + + /* 只有根结点 root 的父结点为 NULL */ + acl_assert(state->curr_node->parent); + acl_assert(state->curr_node->parent->boundary); + + state->curr_node = state->curr_node->parent; + state->curr_bound = STR(state->curr_node->parent->boundary); + + state->curr_status = MIME_S_MULTI_BOUND; + state->curr_node->bound_ptr = NULL; + } + } else { + acl_assert(state->curr_node != NULL); + + MIME_NODE *node = mime_node_new(state); + + node->header_begin = state->curr_off; + if (state->curr_node->boundary != NULL) { + acl_assert(state->curr_bound == STR(state->curr_node->boundary)); + mime_node_add_child(state->curr_node, node); + } else { + acl_assert(state->curr_node->parent->boundary != NULL); + acl_assert(state->curr_bound == STR(state->curr_node->parent->boundary)); + mime_node_add_child(state->curr_node->parent, node); + } + state->curr_node = node; + state->curr_status = MIME_S_HEAD; + state->curr_node->last_ch = 0; + state->curr_node->last_lf = 0; + } + return (n - 1); + } else if (*s == '\r') { + state->curr_node->last_cr_pos = state->curr_off; + state->curr_node->last_ch = '\r'; + state->curr_off++; + state->use_crlf = 1; + /* 期待下一个字符为 '\n' */ + return (n - 1); + } else if (*s == '-') { + state->curr_off++; + if (state->curr_node->bound_term[0] == '-') { + state->curr_node->bound_term[1] = '-'; + /* 期待下一个字符为 '\r' 或 '\n' */ + return (n - 1); + } else { + /* 期待下一个字符为 '-' */ + state->curr_node->bound_term[0] = '-'; + return (n - 1); + } + } else { + /* XXX: 分隔符后非法字符 ? */ + + /* 弹出父结点, 并开始分析属于该父结点的下一个结点 */ + + state->curr_node = state->curr_node->parent; + state->curr_off++; + + /* xxx */ + if (state->curr_node == NULL) + state->curr_node = state->root; + state->curr_status = MIME_S_HEAD; + state->curr_node->last_ch = 0; + state->curr_node->last_lf = 0; + return (n - 1); + } +} + +static int mime_state_multi_bound(MIME_STATE *state, const char *s, int n) +{ + MIME_NODE *node = state->curr_node; + const unsigned char *cp; + //const unsigned char *startn = NULL; + + acl_assert(state->curr_bound != NULL); + acl_assert(node->parent != NULL); + acl_assert(node->parent->boundary != NULL); + + const char *boundary = state->curr_bound; + + for (cp = (const unsigned char *) s; + cp < (const unsigned char *) s + n; cp++) + { + // 记录下 \r\n 的位置 + if (*cp == '\r') + node->last_cr_pos = state->curr_off; + else if (*cp == '\n') + node->last_lf_pos = state->curr_off; + + state->curr_off++; + if (node->bound_ptr) { + if (*cp == *node->bound_ptr) { + node->bound_ptr++; + if (*node->bound_ptr == 0) { + + /* 说明完全匹配 */ + + state->curr_status = MIME_S_MULTI_BOUND_CRLF; + node->bound_ptr = NULL; + cp++; + break; + } + } else { + + /* 说明之前的匹配失效,需要重新匹配, + * 但必须将之前匹配的字符拷贝 + */ + + node->bound_ptr = NULL; + } + } + if (!node->bound_ptr && *cp == *boundary) { + node->bound_ptr = boundary + 1; + + /* 说明完全匹配 */ + if (*node->bound_ptr == 0) { + state->curr_status = MIME_S_MULTI_BOUND_CRLF; + node->bound_ptr = NULL; + cp++; + break; + } + //startn = cp; + } + } + + return (n - ((const char*) cp - s)); +} + +static int mime_state_multi_bound_crlf(MIME_STATE *state, const char *s, int n) +{ + if (*s == '\n') { + MIME_NODE *node = mime_node_new(state); + + node->last_lf_pos = state->curr_off; + state->curr_off++; + + /* 设置 multipart 体结束位置,该位置包含了其所有子结点数据 */ + state->curr_node->bound_end = state->curr_off; + + /* + state->curr_node->body_end = state->curr_node->bound_end + - strlen(state->curr_bound) - 1; + if (state->curr_node->last_ch == '\r') + state->curr_node->body_end--; + */ + + node->header_begin = state->curr_off; + mime_node_add_child(state->curr_node->parent, node); + state->curr_node = node; + state->curr_status = MIME_S_HEAD; + node->bound_ptr = NULL; + node->last_ch = 0; + node->last_lf = 0; + return (n - 1); + } else if (*s == '\r') { + state->curr_node->last_cr_pos = state->curr_off; + state->curr_node->last_ch = '\r'; + state->curr_off++; + state->use_crlf = 1; + /* 期待下一个字符为 '\n' */ + return (n - 1); + } else { + /* xxx */ + state->curr_off += n; + return (0); + } +} + +static int mime_state_term(MIME_STATE *state, const char *s, int n) +{ + (void) s; + state->curr_off += n; + return (0); +} + +static struct MIME_STATUS_MACHINE status_tab[] = { + { MIME_S_HEAD, mime_state_head }, + { MIME_S_BODY, mime_state_body }, + { MIME_S_BODY_BOUND_CRLF, mime_state_body_bound_crlf }, + { MIME_S_MULTI_BOUND, mime_state_multi_bound }, + { MIME_S_MULTI_BOUND_CRLF, mime_state_multi_bound_crlf }, + { MIME_S_TERM, mime_state_term }, +}; + +int mime_state_update(MIME_STATE *state, const char *ptr, int n) +{ + const char *s = ptr; + while (n > 0) { + int ret = status_tab[state->curr_status].callback(state, s, n); + if (state->curr_status == MIME_S_TERM) + return (1); + acl_assert(ret >= 0); + if (ret == 0) + break; + s += n - ret; + n = ret; + } + + return (0); +} diff --git a/lib_acl_cpp/src/mime/internal/quote_821_local.cpp b/lib_acl_cpp/src/mime/internal/quote_821_local.cpp new file mode 100644 index 000000000..1fb344016 --- /dev/null +++ b/lib_acl_cpp/src/mime/internal/quote_821_local.cpp @@ -0,0 +1,183 @@ +/*++ + * NAME + * quote_821_local 3 + * SUMMARY + * quote local part of address + * SYNOPSIS + * #include "quote_821_local.h" + * + * VSTRING *quote_821_local(dst, src) + * VSTRING *dst; + * char *src; + * + * VSTRING *quote_821_local_flags(dst, src, flags) + * VSTRING *dst; + * const char *src; + * int flags; + * DESCRIPTION + * quote_821_local() quotes the local part of a mailbox address and + * returns a result that can be used in SMTP commands as specified + * by RFC 821. It implements an 8-bit clean version of RFC 821. + * + * quote_821_local_flags() provides finer control. + * + * Arguments: + * .IP dst + * The result. + * .IP src + * The input address. + * .IP flags + * Bit-wise OR of zero or more of the following. + * .RS + * .IP QUOTE_FLAG_8BITCLEAN + * In violation with RFCs, treat 8-bit text as ordinary text. + * .IP QUOTE_FLAG_EXPOSE_AT + * In violation with RFCs, treat `@' as an ordinary character. + * .IP QUOTE_FLAG_APPEND + * Append to the result buffer, instead of overwriting it. + * .RE + * STANDARDS + * RFC 821 (SMTP protocol) + * BUGS + * The code assumes that the domain is RFC 821 clean. + * LICENSE + * .ad + * .fi + * The Secure Mailer license must be distributed with this software. + * AUTHOR(S) + * Wietse Venema + * IBM T.J. Watson Research + * P.O. Box 704 + * Yorktown Heights, NY 10598, USA + *--*/ + +/* System library. */ + +#include "acl_stdafx.hpp" +#include +#include + +/* Utility library. */ + +#include "stdlib/acl_vstring.h" + +/* Global library. */ + +#include "quote_821_local.hpp" + +/* Application-specific. */ + +#define YES 1 +#define NO 0 + +/* is_821_dot_string - is this local-part an rfc 821 dot-string? */ + +static int is_821_dot_string(const char *local_part, const char *end, int flags) +{ + const char *cp; + int ch; + + /* + * Detect any deviations from the definition of dot-string. We could use + * lookup tables to speed up some of the work, but hey, how large can a + * local-part be anyway? + */ + if (local_part == end || local_part[0] == 0 || local_part[0] == '.') + return (NO); + for (cp = local_part; cp < end && (ch = *(const unsigned char *) cp) != 0; cp++) { + if (ch == '.' && cp[1] == '.') + return (NO); + if (ch > 127 && !(flags & QUOTE_FLAG_8BITCLEAN)) + return (NO); + if (ch == ' ') + return (NO); + if (ACL_ISCNTRL(ch)) + return (NO); + if (ch == '<' || ch == '>' + || ch == '(' || ch == ')' + || ch == '[' || ch == ']' + || ch == '\\' || ch == ',' + || ch == ';' || ch == ':' + || (ch == '@' && !(flags & QUOTE_FLAG_EXPOSE_AT)) || ch == '"') + { + return (NO); + } + } + if (cp[-1] == '.') + return (NO); + return (YES); +} + +/* make_821_quoted_string - make quoted-string from local-part */ + +static ACL_VSTRING *make_821_quoted_string(ACL_VSTRING *dst, const char *local_part, + const char *end, int flags) +{ + const char *cp; + int ch; + + /* + * Put quotes around the result, and prepend a backslash to characters + * that need quoting when they occur in a quoted-string. + */ + ACL_VSTRING_ADDCH(dst, '"'); + for (cp = local_part; cp < end && (ch = *(const unsigned char *) cp) != 0; cp++) { + if ((ch > 127 && !(flags & QUOTE_FLAG_8BITCLEAN)) + || ch == '\r' || ch == '\n' || ch == '"' || ch == '\\') + { + ACL_VSTRING_ADDCH(dst, '\\'); + } + ACL_VSTRING_ADDCH(dst, ch); + } + ACL_VSTRING_ADDCH(dst, '"'); + ACL_VSTRING_TERMINATE(dst); + return (dst); +} + +/* quote_821_local_flags - quote local part of address according to rfc 821 */ + +ACL_VSTRING *quote_821_local_flags(ACL_VSTRING *dst, const char *addr, int flags) +{ + const char *at; + + /* + * According to RFC 821, a local-part is a dot-string or a quoted-string. + * We first see if the local-part is a dot-string. If it is not, we turn + * it into a quoted-string. Anything else would be too painful. + */ + if ((at = strrchr(addr, '@')) == 0) /* just in case */ + at = addr + strlen(addr); /* should not happen */ + if ((flags & QUOTE_FLAG_APPEND) == 0) + ACL_VSTRING_RESET(dst); + if (is_821_dot_string(addr, at, flags)) { + return (acl_vstring_strcat(dst, addr)); + } else { + make_821_quoted_string(dst, addr, at, flags & QUOTE_FLAG_8BITCLEAN); + return (acl_vstring_strcat(dst, at)); + } +} + +#ifdef TEST + +/* + * Test program for local-part quoting as per rfc 821 + */ +#include +#include +#include +#include "quote_821_local.h" + +int main(void) +{ + VSTRING *src = vstring_alloc(100); + VSTRING *dst = vstring_alloc(100); + + while (vstring_fgets_nonl(src, VSTREAM_IN)) { + vstream_fprintf(VSTREAM_OUT, "%s\n", + vstring_str(quote_821_local(dst, vstring_str(src)))); + vstream_fflush(VSTREAM_OUT); + } + exit(0); +} + +#endif diff --git a/lib_acl_cpp/src/mime/internal/quote_821_local.hpp b/lib_acl_cpp/src/mime/internal/quote_821_local.hpp new file mode 100644 index 000000000..346d93003 --- /dev/null +++ b/lib_acl_cpp/src/mime/internal/quote_821_local.hpp @@ -0,0 +1,38 @@ +/*++ + * NAME + * quote_821_local 3h + * SUMMARY + * quote rfc 821 local part + * SYNOPSIS + * #include "quote_821_local.h" + * DESCRIPTION + * .nf + */ + +/* + * Utility library. + */ +#include "stdlib/acl_vstring.h" + +/* + * Global library. + */ +#include "quote_flags.hpp" + +/* + * External interface. + */ +extern ACL_VSTRING *quote_821_local_flags(ACL_VSTRING *, const char *, int); +#define quote_821_local(dst, src) \ + quote_821_local_flags((dst), (src), QUOTE_FLAG_8BITCLEAN) + +/* LICENSE + * .ad + * .fi + * The Secure Mailer license must be distributed with this software. + * AUTHOR(S) + * Wietse Venema + * IBM T.J. Watson Research + * P.O. Box 704 + * Yorktown Heights, NY 10598, USA + *--*/ diff --git a/lib_acl_cpp/src/mime/internal/quote_822_local.cpp b/lib_acl_cpp/src/mime/internal/quote_822_local.cpp new file mode 100644 index 000000000..225479f6e --- /dev/null +++ b/lib_acl_cpp/src/mime/internal/quote_822_local.cpp @@ -0,0 +1,245 @@ +/*++ + * NAME + * quote_822_local 3 + * SUMMARY + * quote local part of mailbox + * SYNOPSIS + * #include + * + * VSTRING *quote_822_local(dst, src) + * VSTRING *dst; + * const char *src; + * + * VSTRING *quote_822_local_flags(dst, src, flags) + * VSTRING *dst; + * const char *src; + * int flags; + * + * VSTRING *unquote_822_local(dst, src) + * VSTRING *dst; + * const char *src; + * DESCRIPTION + * quote_822_local() quotes the local part of a mailbox and + * returns a result that can be used in message headers as + * specified by RFC 822 (actually, an 8-bit clean version of + * RFC 822). It implements an 8-bit clean version of RFC 822. + * + * quote_822_local_flags() provides finer control. + * + * unquote_822_local() transforms the local part of a mailbox + * address to unquoted (internal) form. + * + * Arguments: + * .IP dst + * The result. + * .IP src + * The input address. + * .IP flags + * Bit-wise OR of zero or more of the following. + * .RS + * .IP QUOTE_FLAG_8BITCLEAN + * In violation with RFCs, treat 8-bit text as ordinary text. + * .IP QUOTE_FLAG_EXPOSE_AT + * In violation with RFCs, treat `@' as an ordinary character. + * .IP QUOTE_FLAG_APPEND + * Append to the result buffer, instead of overwriting it. + * .RE + * STANDARDS + * RFC 822 (ARPA Internet Text Messages) + * BUGS + * The code assumes that the domain is RFC 822 clean. + * LICENSE + * .ad + * .fi + * The Secure Mailer license must be distributed with this software. + * AUTHOR(S) + * Wietse Venema + * IBM T.J. Watson Research + * P.O. Box 704 + * Yorktown Heights, NY 10598, USA + *--*/ + +/* System library. */ + +#include "acl_stdafx.hpp" +#include +#include + +/* Utility library. */ + +#include "stdlib/acl_vstring.h" + +/* Global library. */ + +/* Application-specific. */ + +#include "quote_822_local.hpp" + +/* Local stuff. */ + +#define YES 1 +#define NO 0 + +/* is_822_dot_string - is this local-part an rfc 822 dot-string? */ + +static int is_822_dot_string(const char *local_part, const char *end, int flags) +{ + const char *cp; + int ch; + + /* + * Detect any deviations from a sequence of atoms separated by dots. We + * could use lookup tables to speed up some of the work, but hey, how + * large can a local-part be anyway? + * + * RFC 822 expects 7-bit data. Rather than quoting every 8-bit character + * (and still passing it on as 8-bit data) we leave 8-bit data alone. + */ + if (local_part == end || local_part[0] == 0 || local_part[0] == '.') + return (NO); + for (cp = local_part; cp < end && (ch = *(unsigned char *) cp) != 0; cp++) { + if (ch == '.' && (cp + 1) < end && cp[1] == '.') + return (NO); + if (ch > 127 && !(flags & QUOTE_FLAG_8BITCLEAN)) + return (NO); + if (ch == ' ') + return (NO); + if (ACL_ISCNTRL(ch)) + return (NO); + if (ch == '(' || ch == ')' + || ch == '<' || ch == '>' + || (ch == '@' && !(flags & QUOTE_FLAG_EXPOSE_AT)) || ch == ',' + || ch == ';' || ch == ':' + || ch == '\\' || ch == '"' + || ch == '[' || ch == ']') + { + return (NO); + } + } + if (cp[-1] == '.') + return (NO); + return (YES); +} + +/* make_822_quoted_string - make quoted-string from local-part */ + +static ACL_VSTRING *make_822_quoted_string(ACL_VSTRING *dst, const char *local_part, + const char *end, int flags) +{ + const char *cp; + int ch; + + /* + * Put quotes around the result, and prepend a backslash to characters + * that need quoting when they occur in a quoted-string. + */ + ACL_VSTRING_ADDCH(dst, '"'); + for (cp = local_part; cp < end && (ch = *(const unsigned char *) cp) != 0; cp++) { + if ((ch > 127 && !(flags & QUOTE_FLAG_8BITCLEAN)) + || ch == '"' || ch == '\\' || ch == '\r') + { + ACL_VSTRING_ADDCH(dst, '\\'); + } + ACL_VSTRING_ADDCH(dst, ch); + } + ACL_VSTRING_ADDCH(dst, '"'); + return (dst); +} + +/* quote_822_local_flags - quote local part of mailbox according to rfc 822 */ + +ACL_VSTRING *quote_822_local_flags(ACL_VSTRING *dst, const char *mbox, int flags) +{ + const char *start; /* first byte of localpart */ + const char *end; /* first byte after localpart */ + const char *colon; + + /* + * According to RFC 822, a local-part is a dot-string or a quoted-string. + * We first see if the local-part is a dot-string. If it is not, we turn + * it into a quoted-string. Anything else would be too painful. But + * first, skip over any source route that precedes the local-part. + */ + if (mbox[0] == '@' && (colon = strchr(mbox, ':')) != 0) + start = colon + 1; + else + start = mbox; + if ((end = strrchr(start, '@')) == 0) + end = start + strlen(start); + if ((flags & QUOTE_FLAG_APPEND) == 0) + ACL_VSTRING_RESET(dst); + if (is_822_dot_string(start, end, flags)) { + return (acl_vstring_strcat(dst, mbox)); + } else { + acl_vstring_strncat(dst, mbox, start - mbox); + make_822_quoted_string(dst, start, end, flags & QUOTE_FLAG_8BITCLEAN); + return (acl_vstring_strcat(dst, end)); + } +} + +/* unquote_822_local - unquote local part of mailbox according to rfc 822 */ + +ACL_VSTRING *unquote_822_local(ACL_VSTRING *dst, const char *mbox) +{ + const char *start; /* first byte of localpart */ + const char *end; /* first byte after localpart */ + const char *colon; + const char *cp; + + if (mbox[0] == '@' && (colon = strchr(mbox, ':')) != 0) { + start = colon + 1; + acl_vstring_strncpy(dst, mbox, start - mbox); + } else { + start = mbox; + ACL_VSTRING_RESET(dst); + } + if ((end = strrchr(start, '@')) == 0) + end = start + strlen(start); + for (cp = start; cp < end; cp++) { + if (*cp == '"') + continue; + if (*cp == '\\') { + if (cp[1] == 0) + continue; + cp++; + } + ACL_VSTRING_ADDCH(dst, *cp); + } + if (*end) + acl_vstring_strcat(dst, end); + else + ACL_VSTRING_TERMINATE(dst); + return (dst); +} + +#ifdef TEST + +/* + * Proof-of-concept test program. Read an unquoted address from stdin, and + * show the quoted and unquoted results. + */ +#include +#include + +#define STR vstring_str + +int main(int unused_argc, char **unused_argv) +{ + VSTRING *raw = vstring_alloc(100); + VSTRING *quoted = vstring_alloc(100); + VSTRING *unquoted = vstring_alloc(100); + + while (vstring_fgets_nonl(raw, VSTREAM_IN)) { + quote_822_local(quoted, STR(raw)); + vstream_printf("quoted: %s\n", STR(quoted)); + unquote_822_local(unquoted, STR(quoted)); + vstream_printf("unquoted: %s\n", STR(unquoted)); + vstream_fflush(VSTREAM_OUT); + } + vstring_free(unquoted); + vstring_free(quoted); + vstring_free(raw); + return (0); +} + +#endif diff --git a/lib_acl_cpp/src/mime/internal/quote_822_local.hpp b/lib_acl_cpp/src/mime/internal/quote_822_local.hpp new file mode 100644 index 000000000..2c9fb1f0e --- /dev/null +++ b/lib_acl_cpp/src/mime/internal/quote_822_local.hpp @@ -0,0 +1,44 @@ +#ifndef _QUOTE_822_H_INCLUDED_ +#define _QUOTE_822_H_INCLUDED_ + +/*++ + * NAME + * quote_822_local 3h + * SUMMARY + * quote local part of mailbox + * SYNOPSIS + * #include "quote_822_local.h" + * DESCRIPTION + * .nf + */ + +/* + * Utility library. + */ +#include "stdlib/acl_vstring.h" + +/* + * Global library. + */ +#include "quote_flags.hpp" + +/* + * External interface. + */ +extern ACL_VSTRING *quote_822_local_flags(ACL_VSTRING *, const char *, int); +extern ACL_VSTRING *unquote_822_local(ACL_VSTRING *, const char *); +#define quote_822_local(dst, src) \ + quote_822_local_flags((dst), (src), QUOTE_FLAG_8BITCLEAN) + +/* LICENSE + * .ad + * .fi + * The Secure Mailer license must be distributed with this software. + * AUTHOR(S) + * Wietse Venema + * IBM T.J. Watson Research + * P.O. Box 704 + * Yorktown Heights, NY 10598, USA + *--*/ + +#endif diff --git a/lib_acl_cpp/src/mime/internal/quote_flags.hpp b/lib_acl_cpp/src/mime/internal/quote_flags.hpp new file mode 100644 index 000000000..a6d7225c5 --- /dev/null +++ b/lib_acl_cpp/src/mime/internal/quote_flags.hpp @@ -0,0 +1,28 @@ +/*++ + * NAME + * quote_flags 3h + * SUMMARY + * quote rfc 821/822 local part + * SYNOPSIS + * #include "quote_flags.h" + * DESCRIPTION + * .nf + */ + +/* + * External interface. + */ +#define QUOTE_FLAG_8BITCLEAN (1<<0) /* be 8-bit clean */ +#define QUOTE_FLAG_EXPOSE_AT (1<<1) /* @ is ordinary text */ +#define QUOTE_FLAG_APPEND (1<<2) /* append, not overwrite */ + +/* LICENSE + * .ad + * .fi + * The Secure Mailer license must be distributed with this software. + * AUTHOR(S) + * Wietse Venema + * IBM T.J. Watson Research + * P.O. Box 704 + * Yorktown Heights, NY 10598, USA + *--*/ diff --git a/lib_acl_cpp/src/mime/internal/rec_type.cpp b/lib_acl_cpp/src/mime/internal/rec_type.cpp new file mode 100644 index 000000000..c6da44a9a --- /dev/null +++ b/lib_acl_cpp/src/mime/internal/rec_type.cpp @@ -0,0 +1,88 @@ +/*++ + * NAME + * rec_type 3 + * SUMMARY + * Postfix record types + * SYNOPSIS + * #include + * + * const char *rec_type_name(type) + * int type; + * DESCRIPTION + * This module and its associated include file implement the + * Postfix-specific record types. + * + * rec_type_name() returns a printable name for the given record + * type. + * LICENSE + * .ad + * .fi + * The Secure Mailer license must be distributed with this software. + * AUTHOR(S) + * Wietse Venema + * IBM T.J. Watson Research + * P.O. Box 704 + * Yorktown Heights, NY 10598, USA + *--*/ + +#include "acl_stdafx.hpp" +/* Global library. */ + +#include "rec_type.hpp" + + /* + * Lookup table with internal record type codes and printable names. + */ +typedef struct { + int type; + const char *name; +} REC_TYPE_NAME; + +REC_TYPE_NAME rec_type_names[] = { + { REC_TYPE_EOF, "end-of-file" }, /* not Postfix-specific. */ + { REC_TYPE_ERROR, "error" }, /* not Postfix-specific. */ + { REC_TYPE_SIZE, "message_size" }, + { REC_TYPE_TIME, "message_arrival_time" }, + { REC_TYPE_CTIME, "queue_file_create_time" }, + { REC_TYPE_FULL, "sender_fullname" }, + { REC_TYPE_INSP, "content_inspector" }, + { REC_TYPE_FILT, "content_filter" }, + { REC_TYPE_FROM, "sender" }, + { REC_TYPE_DONE, "done_recipient" }, + { REC_TYPE_DRCP, "canceled_recipient" }, + { REC_TYPE_RCPT, "recipient" }, + { REC_TYPE_ORCP, "original_recipient" }, + { REC_TYPE_WARN, "warning_message_time" }, + { REC_TYPE_ATTR, "named_attribute" }, + { REC_TYPE_PTR, "pointer_record" }, + { REC_TYPE_KILL, "killed_record" }, + { REC_TYPE_MESG, "message_content" }, + { REC_TYPE_CONT, "unterminated_text" }, + { REC_TYPE_NORM, "regular_text" }, + { REC_TYPE_DTXT, "padding" }, + { REC_TYPE_XTRA, "extracted_info" }, + { REC_TYPE_RRTO, "return_receipt" }, + { REC_TYPE_ERTO, "errors_to" }, + { REC_TYPE_PRIO, "priority" }, + { REC_TYPE_VERP, "verp_delimiters" }, + { REC_TYPE_END, "message_end" }, + { REC_TYPE_RDR, "redirect_to" }, + { REC_TYPE_FLGS, "flags" }, + { REC_TYPE_DSN_RET, "dsn_return_flags" }, + { REC_TYPE_DSN_ENVID, "dsn_envelope_id" }, + { REC_TYPE_DSN_ORCPT, "dsn_original_recipient" }, + { REC_TYPE_DSN_NOTIFY, "dsn_notify_flags" }, + { 0, 0 }, +}; + +/* rec_type_name - map record type to printable name */ + +const char *rec_type_name(int type) +{ + REC_TYPE_NAME *p; + + for (p = rec_type_names; p->name != 0; p++) + if (p->type == type) + return (p->name); + return ("unknown_record_type"); +} diff --git a/lib_acl_cpp/src/mime/internal/rec_type.hpp b/lib_acl_cpp/src/mime/internal/rec_type.hpp new file mode 100644 index 000000000..13161b0ae --- /dev/null +++ b/lib_acl_cpp/src/mime/internal/rec_type.hpp @@ -0,0 +1,198 @@ +#ifndef _REC_TYPE_H_INCLUDED_ +#define _REC_TYPE_H_INCLUDED_ + +/*++ + * NAME + * rec_type 3h + * SUMMARY + * Postfix record types + * SYNOPSIS + * #include + * DESCRIPTION + * .nf + */ + + /* + * System library. + */ +#include +#include + + /* + * Diagnostic codes, not real record lookup results. + */ +#define REC_TYPE_EOF -1 /* no record */ +#define REC_TYPE_ERROR -2 /* bad record */ + + /* + * A queue file or IPC mail message consists of a sequence of typed records. + * The first record group contains time stamp, full name, sender envelope + * information, and optionally contains recipient information. The second + * record group contains data records with the message content. The last + * record group is optional; it contains information extracted from message + * headers, such as recipients, errors-to and return-receipt. + * + * Note: REC_TYPE_FILT and REC_TYPE_CONT are encoded with the same 'L' + * constant, and it is too late to change that now. + */ +#define REC_TYPE_SIZE 'C' /* first record, created by cleanup */ +#define REC_TYPE_TIME 'T' /* arrival time, required */ +#define REC_TYPE_CTIME 'c' /* create time, optional */ +#define REC_TYPE_FULL 'F' /* full name, optional */ +#define REC_TYPE_INSP 'I' /* inspector transport */ +#define REC_TYPE_FILT 'L' /* loop filter transport */ +#define REC_TYPE_FROM 'S' /* sender, required */ +#define REC_TYPE_DONE 'D' /* delivered recipient, optional */ +#define REC_TYPE_RCPT 'R' /* todo recipient, optional */ +#define REC_TYPE_ORCP 'O' /* original recipient, optional */ +#define REC_TYPE_DRCP '/' /* canceled recipient, optional */ +#define REC_TYPE_WARN 'W' /* warning message time */ +#define REC_TYPE_ATTR 'A' /* named attribute for extensions */ +#define REC_TYPE_KILL 'K' /* killed record */ + +#define REC_TYPE_RDR '>' /* redirect target */ +#define REC_TYPE_FLGS 'f' /* cleanup processing flags */ +#define REC_TYPE_DELAY 'd' /* cleanup delay upon arrival */ + +#define REC_TYPE_MESG 'M' /* start message records */ + +#define REC_TYPE_CONT 'L' /* long data record */ +#define REC_TYPE_NORM 'N' /* normal data record */ +#define REC_TYPE_DTXT 'w' /* padding (was: deleted data) */ + +#define REC_TYPE_XTRA 'X' /* start extracted records */ + +#define REC_TYPE_RRTO 'r' /* return-receipt, from headers */ +#define REC_TYPE_ERTO 'e' /* errors-to, from headers */ +#define REC_TYPE_PRIO 'P' /* priority */ +#define REC_TYPE_PTR 'p' /* pointer indirection */ +#define REC_TYPE_VERP 'V' /* VERP delimiters */ + +#define REC_TYPE_DSN_RET '<' /* DSN full/hdrs */ +#define REC_TYPE_DSN_ENVID 'i' /* DSN full/hdrs */ +#define REC_TYPE_DSN_ORCPT 'o' /* DSN orig rcpt address */ +#define REC_TYPE_DSN_NOTIFY 'n' /* DSN notify flags */ + +#define REC_TYPE_MILT_COUNT 'm' + +#define REC_TYPE_END 'E' /* terminator, required */ + + /* + * What I expect to see in a "pure recipient" sequence at the end of the + * initial or extracted envelope segments, respectively. When a queue file + * contains pure recipient sequences only, then the queue manager will not + * have to read all the queue file records before starting delivery. This is + * often the case with list mail, where such optimization is desirable. + * + * XXX These definitions include the respective segment terminators to avoid + * special cases in the cleanup(8) envelope and extracted record processors. + */ +#define REC_TYPE_ENV_RECIPIENT "MDRO/Kon" +#define REC_TYPE_EXT_RECIPIENT "EDRO/Kon" + + /* + * The types of records that I expect to see while processing different + * record groups. The first member in each set is the record type that + * indicates the end of that record group. + * + * XXX A records in the extracted segment are generated only by the cleanup + * server, and are not supposed to be present in locally submitted mail, as + * this is "postfix internal" information. However, the pickup server has to + * allow for the presence of A records in the extracted segment, because it + * can be requested to re-process already queued mail with `postsuper -r'. + * + * Note: REC_TYPE_FILT and REC_TYPE_CONT are encoded with the same 'L' + * constant, and it is too late to change that now. + */ +#define REC_TYPE_ENVELOPE "MCTcFILSDRO/WVA>KKon" + + /* + * The subset of inputs that the postdrop command allows. + */ +#define REC_TYPE_POST_ENVELOPE "MFSRVAin" +#define REC_TYPE_POST_CONTENT "XLN" +#define REC_TYPE_POST_EXTRACT "EAR" + + /* + * The record at the start of the queue file specifies the message content + * size (number of bytes between the REC_TYPE_MESG and REC_TYPE_XTRA meta + * records), data offset (offset of the first REC_TYPE_NORM or REC_TYPE_CONT + * text record), recipient count, and queue manager hints. These are all + * fixed-width fields so they can be updated in place. Queue manager hints + * are defined in qmgr_user.h + * + * See also: REC_TYPE_PTR_FORMAT below. + */ +#define REC_TYPE_SIZE_FORMAT "%15ld %15ld %15ld %15ld %15ld" +#define REC_TYPE_SIZE_CAST1 long /* Vmailer extra offs - data offs */ +#define REC_TYPE_SIZE_CAST2 long /* Postfix 1.0 data offset */ +#define REC_TYPE_SIZE_CAST3 long /* Postfix 1.0 recipient count */ +#define REC_TYPE_SIZE_CAST4 long /* Postfix 2.1 qmgr flags */ +#define REC_TYPE_SIZE_CAST5 long /* Postfix 2.4 content length */ + + /* + * The warn record specifies when the next warning that the message was + * deferred should be sent. It is updated in place by qmgr, so changing + * this value when there are deferred mesages in the queue is dangerous! + */ +#define REC_TYPE_WARN_FORMAT "%15ld" /* warning time format */ +#define REC_TYPE_WARN_ARG(tv) ((long) (tv)) +#define REC_TYPE_WARN_SCAN(cp, tv) ((tv) = atol(cp)) + + /* + * Time information is not updated in place, but it does have complex + * formatting requirements, so we centralize things here. + */ +#define REC_TYPE_TIME_FORMAT "%ld %ld" +#define REC_TYPE_TIME_ARG(tv) (long) (tv).tv_sec, (long) (tv).tv_usec +#define REC_TYPE_TIME_SCAN(cp, tv) \ + do { \ + const char *_p = cp; \ + (tv).tv_sec = atol(_p); \ + while (ISDIGIT(*_p)) \ + _p++; \ + (tv).tv_usec = atol(_p); \ + } while (0) + + /* + * Pointer records are used to edit a queue file in place before it is + * committed. When a record is appended or modified, we patch it into the + * existing record stream with a pointer to storage in a heap after the + * end-of-message marker; the new content is followed by a pointer record + * back to the existing record stream. + * + * We need to have a few dummy pointer records in place at strategic places + * (after the last recipient, after the last header) so that we can always + * append recipients or append/modify headers without having to move message + * segment terminators. + * + * We also need to have a dummy PTR record at the end of the content, so that + * we can always replace the message content without having to move the + * end-of-message marker. + * + * A dummy PTR record has a null argument. + * + * See also: REC_TYPE_SIZE_FORMAT above. + */ +#define REC_TYPE_PTR_FORMAT "%15ld" +#define REC_TYPE_PTR_PAYL_SIZE 15 /* Payload only, excludes record header. */ + + /* + * Programmatic interface. + */ +extern const char *rec_type_name(int); + +/* LICENSE + * .ad + * .fi + * The Secure Mailer license must be distributed with this software. + * AUTHOR(S) + * Wietse Venema + * IBM T.J. Watson Research + * P.O. Box 704 + * Yorktown Heights, NY 10598, USA + *--*/ + +#endif diff --git a/lib_acl_cpp/src/mime/internal/tok822.hpp b/lib_acl_cpp/src/mime/internal/tok822.hpp new file mode 100644 index 000000000..5e143ea90 --- /dev/null +++ b/lib_acl_cpp/src/mime/internal/tok822.hpp @@ -0,0 +1,124 @@ +#ifndef _TOK822_H_INCLUDED_ +#define _TOK822_H_INCLUDED_ + +/*++ + * NAME + * tok822 3h + * SUMMARY + * RFC822 token structures + * SYNOPSIS + * #include + * DESCRIPTION + * .nf + */ +/* + * + * Utility library. + */ +#include "stdlib/acl_vstring.h" + +/* + * Global library. + */ +//#include + +/* + * Internal address representation: a token tree. + */ +typedef struct TOK822 { + int type; /* token value, see below */ + ACL_VSTRING *vstr; /* token contents */ + struct TOK822 *prev; /* peer */ + struct TOK822 *next; /* peer */ + struct TOK822 *head; /* group members */ + struct TOK822 *tail; /* group members */ + struct TOK822 *owner; /* group owner */ +} TOK822; + +/* + * Token values for multi-character objects. Single-character operators are + * represented by their own character value. + */ +#define TOK822_MINTOK 256 +#define TOK822_ATOM 256 /* non-special character sequence */ +#define TOK822_QSTRING 257 /* stuff between "", not nesting */ +#define TOK822_COMMENT 258 /* comment including (), may nest */ +#define TOK822_DOMLIT 259 /* stuff between [] not nesting */ +#define TOK822_ADDR 260 /* actually a token group */ +#define TOK822_STARTGRP 261 /* start of named group */ +#define TOK822_MAXTOK 261 + +/* + * tok822_node.c + */ +extern TOK822 *tok822_alloc(int, const char *); +extern TOK822 *tok822_free(TOK822 *); + +/* + * tok822_tree.c + */ +extern TOK822 *tok822_append(TOK822 *, TOK822 *); +extern TOK822 *tok822_prepend(TOK822 *, TOK822 *); +extern TOK822 *tok822_cut_before(TOK822 *); +extern TOK822 *tok822_cut_after(TOK822 *); +extern TOK822 *tok822_unlink(TOK822 *); +extern TOK822 *tok822_sub_append(TOK822 *, TOK822 *); +extern TOK822 *tok822_sub_prepend(TOK822 *, TOK822 *); +extern TOK822 *tok822_sub_keep_before(TOK822 *, TOK822 *); +extern TOK822 *tok822_sub_keep_after(TOK822 *, TOK822 *); +extern TOK822 *tok822_free_tree(TOK822 *); + +typedef int (*TOK822_ACTION) (TOK822 *); +extern int tok822_apply(TOK822 *, int, TOK822_ACTION); +extern TOK822 **tok822_grep(TOK822 *, int); + +/* + * tok822_parse.c + */ +extern TOK822 *tok822_scan_limit(const char *, TOK822 **, int); +extern TOK822 *tok822_scan_addr(const char *); +extern TOK822 *tok822_parse_limit(const char *, int); +extern ACL_VSTRING *tok822_externalize(ACL_VSTRING *, TOK822 *, int); +extern ACL_VSTRING *tok822_internalize(ACL_VSTRING *, TOK822 *, int); + +#define tok822_scan(cp, ptr) tok822_scan_limit((cp), (ptr), 0) +#define tok822_parse(cp) tok822_parse_limit((cp), 0) + +#define TOK822_STR_NONE (0) +#define TOK822_STR_WIPE (1<<0) +#define TOK822_STR_TERM (1<<1) +#define TOK822_STR_LINE (1<<2) +#define TOK822_STR_TRNC (1<<3) +#define TOK822_STR_DEFL (TOK822_STR_WIPE | TOK822_STR_TERM) +#define TOK822_STR_HEAD (TOK822_STR_TERM | TOK822_STR_LINE | TOK822_STR_TRNC) + +/* + * tok822_find.c + */ +extern TOK822 *tok822_find_type(TOK822 *, int); +extern TOK822 *tok822_rfind_type(TOK822 *, int); + +/* + * tok822_rewrite.c + */ +extern TOK822 *tok822_rewrite(TOK822 *, const char *); + +/* + * tok822_resolve.c + */ +//#define tok822_resolve(t, r) tok822_resolve_from(RESOLVE_NULL_FROM, (t), (r)) +// +//extern void tok822_resolve_from(const char *, TOK822 *, RESOLVE_REPLY *); + +/* LICENSE + * .ad + * .fi + * The Secure Mailer license must be distributed with this software. + * AUTHOR(S) + * Wietse Venema + * IBM T.J. Watson Research + * P.O. Box 704 + * Yorktown Heights, NY 10598, USA + *--*/ + +#endif diff --git a/lib_acl_cpp/src/mime/internal/tok822_find.cpp b/lib_acl_cpp/src/mime/internal/tok822_find.cpp new file mode 100644 index 000000000..c62af7f82 --- /dev/null +++ b/lib_acl_cpp/src/mime/internal/tok822_find.cpp @@ -0,0 +1,67 @@ +/*++ + * NAME + * tok822_find 3 + * SUMMARY + * token list search operators + * SYNOPSIS + * #include + * + * TOK822 *tok822_find_type(head, type) + * TOK822 *head; + * int type; + * + * TOK822 *tok822_rfind_type(tail, type) + * TOK822 *tail; + * int type; + * DESCRIPTION + * This module implements token list search operations. + * + * tok822_find_type() searches a list of tokens for the first + * instance of the specified token type. The result is the + * found token or a null pointer when the search failed. + * + * tok822_rfind_type() searches a list of tokens in reverse direction + * for the first instance of the specified token type. The result + * is the found token or a null pointer when the search failed. + * LICENSE + * .ad + * .fi + * The Secure Mailer license must be distributed with this software. + * AUTHOR(S) + * Wietse Venema + * IBM T.J. Watson Research + * P.O. Box 704 + * Yorktown Heights, NY 10598, USA + *--*/ + +/* System library. */ + +#include "acl_stdafx.hpp" + +/* Utility library. */ + +/* Global library. */ + +#include "tok822.hpp" + +/* tok822_find_type - find specific token type, forward search */ + +TOK822 *tok822_find_type(TOK822 *head, int op) +{ + TOK822 *tp; + + for (tp = head; tp != 0 && tp->type != op; tp = tp->next) + /* void */ ; + return (tp); +} + +/* tok822_rfind_type - find specific token type, backward search */ + +TOK822 *tok822_rfind_type(TOK822 *tail, int op) +{ + TOK822 *tp; + + for (tp = tail; tp != 0 && tp->type != op; tp = tp->prev) + /* void */ ; + return (tp); +} diff --git a/lib_acl_cpp/src/mime/internal/tok822_node.cpp b/lib_acl_cpp/src/mime/internal/tok822_node.cpp new file mode 100644 index 000000000..5a5a72e2d --- /dev/null +++ b/lib_acl_cpp/src/mime/internal/tok822_node.cpp @@ -0,0 +1,79 @@ +/*++ + * NAME + * tok822_node 3 + * SUMMARY + * token memory management + * SYNOPSIS + * #include + * + * TOK822 *tok822_alloc(type, strval) + * int type; + * const char *strval; + * + * TOK822 *tok822_free(tp) + * TOK822 *tp; + * DESCRIPTION + * This module implements memory management for token + * structures. A distinction is made between single-character + * tokens that have no string value, and string-valued tokens. + * + * tok822_alloc() allocates memory for a token structure of + * the named type, and initializes it properly. In case of + * a single-character token, no string memory is allocated. + * Otherwise, \fIstrval\fR is a null pointer or provides + * string data to initialize the token with. + * + * tok822_free() releases the memory used for the specified token + * and conveniently returns a null pointer value. + * LICENSE + * .ad + * .fi + * The Secure Mailer license must be distributed with this software. + * AUTHOR(S) + * Wietse Venema + * IBM T.J. Watson Research + * P.O. Box 704 + * Yorktown Heights, NY 10598, USA + *--*/ + +/* System library. */ + +#include "acl_stdafx.hpp" +#include + +/* Utility library. */ + +#include "stdlib/acl_mymalloc.h" +#include "stdlib/acl_vstring.h" + +/* Global library. */ + +#include "tok822.hpp" + +/* tok822_alloc - allocate and initialize token */ + +TOK822 *tok822_alloc(int type, const char *strval) +{ + TOK822 *tp; + +#define CONTAINER_TOKEN(x) \ + ((x) == TOK822_ADDR || (x) == TOK822_STARTGRP) + + tp = (TOK822 *) acl_mymalloc(sizeof(*tp)); + tp->type = type; + tp->next = tp->prev = tp->head = tp->tail = tp->owner = 0; + tp->vstr = (type < TOK822_MINTOK || CONTAINER_TOKEN(type) ? 0 : + strval == 0 ? acl_vstring_alloc(10) : + acl_vstring_strcpy(acl_vstring_alloc(strlen(strval) + 1), strval)); + return (tp); +} + +/* tok822_free - destroy token */ + +TOK822 *tok822_free(TOK822 *tp) +{ + if (tp->vstr) + acl_vstring_free(tp->vstr); + acl_myfree(tp); + return (0); +} diff --git a/lib_acl_cpp/src/mime/internal/tok822_parse.cpp b/lib_acl_cpp/src/mime/internal/tok822_parse.cpp new file mode 100644 index 000000000..953279dc3 --- /dev/null +++ b/lib_acl_cpp/src/mime/internal/tok822_parse.cpp @@ -0,0 +1,728 @@ +/*++ + * NAME + * tok822_parse 3 + * SUMMARY + * RFC 822 address parser + * SYNOPSIS + * #include + * + * TOK822 *tok822_scan_limit(str, tailp, limit) + * const char *str; + * TOK822 **tailp; + * int limit; + * + * TOK822 *tok822_scan(str, tailp) + * const char *str; + * TOK822 **tailp; + * + * TOK822 *tok822_parse_limit(str, limit) + * const char *str; + * int limit; + * + * TOK822 *tok822_parse(str) + * const char *str; + * + * TOK822 *tok822_scan_addr(str) + * const char *str; + * + * VSTRING *tok822_externalize(buffer, tree, flags) + * VSTRING *buffer; + * TOK822 *tree; + * int flags; + * + * VSTRING *tok822_internalize(buffer, tree, flags) + * VSTRING *buffer; + * TOK822 *tree; + * int flags; + * DESCRIPTION + * This module converts address lists between string form and parse + * tree formats. The string form can appear in two different ways: + * external (or quoted) form, as used in message headers, and internal + * (unquoted) form, as used internally by the mail software. + * Although RFC 822 expects 7-bit data, these routines pay no + * special attention to 8-bit characters. + * + * tok822_scan() converts the external-form string in \fIstr\fR + * to a linear token list. The \fItailp\fR argument is a null pointer + * or receives the pointer value of the last result list element. + * + * tok822_scan_limit() implements tok822_scan(), which is a macro. + * The \fIlimit\fR argument is either zero or an upper bound on the + * number of tokens produced. + * + * tok822_parse() converts the external-form address list in + * \fIstr\fR to the corresponding token tree. The parser is permissive + * and will not throw away information that it does not understand. + * The parser adds missing commas between addresses. + * + * tok822_parse_limit() implements tok822_parse(), which is a macro. + * The \fIlimit\fR argument is either zero or an upper bound on the + * number of tokens produced. + * + * tok822_scan_addr() converts the external-form string in + * \fIstr\fR to an address token tree. This is just string to + * token list conversion; no parsing is done. This routine is + * suitable for data that should contain just one address and no + * other information. + * + * tok822_externalize() converts a token list to external form. + * Where appropriate, characters and strings are quoted and white + * space is inserted. The \fIflags\fR argument is the binary OR of + * zero or more of the following: +* .IP TOK822_STR_WIPE +* Initially, truncate the result to zero length. +* .IP TOK822_STR_TERM +* Append a null terminator to the result when done. +* .IP TOK822_STR_LINE +* Append a line break after each comma token, instead of appending +* whitespace. It is up to the caller to concatenate short lines to +* produce longer ones. +* .IP TOK822_STR_TRNC +* Truncate non-address information to 250 characters per address, to +* protect Sendmail systems that are vulnerable to the problem in CERT +* advisory CA-2003-07. +* This flag has effect with tok822_externalize() only. +* .PP +* The macro TOK_822_NONE expresses that none of the above features +* should be activated. +* +* The macro TOK822_STR_DEFL combines the TOK822_STR_WIPE and +* TOK822_STR_TERM flags. This is useful for most token to string +* conversions. +* +* The macro TOK822_STR_HEAD combines the TOK822_STR_TERM, + * TOK822_STR_LINE and TOK822_STR_TRNC flags. This is useful for + * the special case of token to mail header conversion. + * + * tok822_internalize() converts a token list to string form, + * without quoting. White space is inserted where appropriate. + * The \fIflags\fR argument is as with tok822_externalize(). + * STANDARDS + * .ad + * .fi + * RFC 822 (ARPA Internet Text Messages). In addition to this standard + * this module implements additional operators such as % and !. These + * are needed because the real world is not all RFC 822. Also, the ':' + * operator is allowed to appear inside addresses, to accommodate DECnet. + * In addition, 8-bit data is not given special treatment. + * LICENSE + * .ad + * .fi + * The Secure Mailer license must be distributed with this software. +* AUTHOR(S) + * Wietse Venema + * IBM T.J. Watson Research + * P.O. Box 704 + * Yorktown Heights, NY 10598, USA + *--*/ + + /* System library. */ + +#include "acl_stdafx.hpp" +#include +#include + + /* Utility library. */ + +#include "stdlib/acl_vstring.h" +#include "stdlib/acl_msg.h" +#include "stdlib/acl_stringops.h" + + /* Global library. */ + +#include "lex_822.hpp" +#include "quote_822_local.hpp" +#include "tok822.hpp" + + /* + * I suppose this is my favorite macro. Used heavily for tokenizing. + */ +#define COLLECT(t,s,c,cond) { \ + while ((c = *(unsigned char *) s) != 0) { \ + if (c == '\\') { \ + if ((c = *(unsigned char *)++s) == 0) \ + break; \ + } else if (!(cond)) { \ + break; \ + } \ + ACL_VSTRING_ADDCH(t->vstr, IS_SPACE_TAB_CR_LF(c) ? ' ' : c); \ + s++; \ + } \ + ACL_VSTRING_TERMINATE(t->vstr); \ +} + +#define COLLECT_SKIP_LAST(t,s,c,cond) { COLLECT(t,s,c,cond); if (*s) s++; } + + /* + * Not quite as complex. The parser depends heavily on it. + */ +#define SKIP(tp, cond) { \ + while (tp->type && (cond)) \ + tp = tp->prev; \ +} + +#define MOVE_COMMENT_AND_CONTINUE(tp, right) { \ + TOK822 *prev = tok822_unlink(tp); \ + right = tok822_prepend(right, tp); \ + tp = prev; \ + continue; \ +} + +#define SKIP_MOVE_COMMENT(tp, cond, right) { \ + while (tp->type && (cond)) { \ + if (tp->type == TOK822_COMMENT) \ + MOVE_COMMENT_AND_CONTINUE(tp, right); \ + tp = tp->prev; \ + } \ +} + +/* + * Single-character operators. We include the % and ! operators because not + * all the world is RFC822. XXX Make this operator list configurable when we + * have a real rewriting language. Include | for aliases file parsing. + */ +static char tok822_opchar[] = "|%!" LEX_822_SPECIALS; +static void tok822_quote_atom(TOK822 *); +static const char *tok822_comment(TOK822 *, const char *); +static TOK822 *tok822_group(int, TOK822 *, TOK822 *, int); +static void tok822_copy_quoted(ACL_VSTRING *, char *, const char *); +static int tok822_append_space(TOK822 *); + +#define DO_WORD (1<<0) /* finding a word is ok here */ +#define DO_GROUP (1<<1) /* doing an address group */ + +#define ADD_COMMA ',' /* resynchronize */ +#define NO_MISSING_COMMA 0 + +/* tok822_internalize - token tree to string, internal form */ + +ACL_VSTRING *tok822_internalize(ACL_VSTRING *vp, TOK822 *tree, int flags) +{ + TOK822 *tp; + + if (flags & TOK822_STR_WIPE) + ACL_VSTRING_RESET(vp); + + for (tp = tree; tp; tp = tp->next) { + switch (tp->type) { + case ',': + ACL_VSTRING_ADDCH(vp, tp->type); + if (flags & TOK822_STR_LINE) { + ACL_VSTRING_ADDCH(vp, '\n'); + continue; + } + break; + case TOK822_ADDR: + tok822_internalize(vp, tp->head, TOK822_STR_NONE); + break; + case TOK822_COMMENT: + case TOK822_ATOM: + case TOK822_QSTRING: + acl_vstring_strcat(vp, acl_vstring_str(tp->vstr)); + break; + case TOK822_DOMLIT: + ACL_VSTRING_ADDCH(vp, '['); + acl_vstring_strcat(vp, acl_vstring_str(tp->vstr)); + ACL_VSTRING_ADDCH(vp, ']'); + break; + case TOK822_STARTGRP: + ACL_VSTRING_ADDCH(vp, ':'); + break; + default: + if (tp->type >= TOK822_MINTOK) + acl_msg_panic("tok822_internalize: unknown operator %d", tp->type); + ACL_VSTRING_ADDCH(vp, tp->type); + } + if (tok822_append_space(tp)) + ACL_VSTRING_ADDCH(vp, ' '); + } + if (flags & TOK822_STR_TERM) + ACL_VSTRING_TERMINATE(vp); + return (vp); +} + +/* strip_address - strip non-address text from address expression */ + +static void strip_address(ACL_VSTRING *vp, ssize_t start, TOK822 *addr) +{ + ACL_VSTRING *tmp; + + /* + * Emit plain
. Discard any comments or phrases. + */ + ACL_VSTRING_TERMINATE(vp); + acl_msg_warn("stripping too many comments from address: %.100s...", + acl_vstring_str(vp) + start); + //acl_printable(vstring_str(vp) + start, '?')); //zsx + acl_vstring_truncate(vp, start); + ACL_VSTRING_ADDCH(vp, '<'); + if (addr) { + tmp = acl_vstring_alloc(100); + tok822_internalize(tmp, addr, TOK822_STR_TERM); + quote_822_local_flags(vp, acl_vstring_str(tmp), + QUOTE_FLAG_8BITCLEAN | QUOTE_FLAG_APPEND); + acl_vstring_free(tmp); + } + ACL_VSTRING_ADDCH(vp, '>'); +} + +/* tok822_externalize - token tree to string, external form */ + +ACL_VSTRING *tok822_externalize(ACL_VSTRING *vp, TOK822 *tree, int flags) +{ + ACL_VSTRING *tmp; + TOK822 *tp; + ssize_t start = 0; + TOK822 *addr = 0; + ssize_t addr_len = 0; + + /* + * Guard against a Sendmail buffer overflow (CERT advisory CA-2003-07). + * The problem was that Sendmail could store too much non-address text + * (comments, phrases, etc.) into a static 256-byte buffer. + * + * When the buffer fills up, fixed Sendmail versions remove comments etc. + * and reduce the information to just <$g>, which expands to
. + * No change is made when an address expression (text separated by + * commas) contains no address. This fix reportedly also protects + * Sendmail systems that are still vulnerable to this problem. + * + * Postfix takes the same approach, grudgingly. To avoid unnecessary damage, + * Postfix removes comments etc. only when the amount of non-address text + * in an address expression (text separated by commas) exceeds 250 bytes. + * + * With Sendmail, the address part of an address expression is the + * right-most <> instance in that expression. If an address expression + * contains no <>, then Postfix guarantees that it contains at most one + * non-comment string; that string is the address part of the address + * expression, so there is no ambiguity. + * + * Finally, we note that stress testing shows that other code in Sendmail + * 8.12.8 bluntly truncates ``text
'' to 256 bytes even when + * this means chopping the
somewhere in the middle. This is a + * loss of control that we're not entirely comfortable with. However, + * unbalanced quotes and dangling backslash do not seem to influence the + * way that Sendmail parses headers, so this is not an urgent problem. + */ +#define MAX_NONADDR_LENGTH 250 + +#define RESET_NONADDR_LENGTH { \ + start = ACL_VSTRING_LEN(vp); \ + addr = 0; \ + addr_len = 0; \ +} + +#define ENFORCE_NONADDR_LENGTH do { \ + if (addr && (ssize_t) ACL_VSTRING_LEN(vp) - addr_len > start + MAX_NONADDR_LENGTH) \ + strip_address(vp, start, addr->head); \ +} while(0) + + if (flags & TOK822_STR_WIPE) + ACL_VSTRING_RESET(vp); + + if (flags & TOK822_STR_TRNC) + RESET_NONADDR_LENGTH; + + for (tp = tree; tp; tp = tp->next) { + switch (tp->type) { + case ',': + if (flags & TOK822_STR_TRNC) + ENFORCE_NONADDR_LENGTH; + ACL_VSTRING_ADDCH(vp, tp->type); + ACL_VSTRING_ADDCH(vp, (flags & TOK822_STR_LINE) ? '\n' : ' '); + if (flags & TOK822_STR_TRNC) + RESET_NONADDR_LENGTH; + continue; + + /* + * XXX In order to correctly externalize an address, it is not + * sufficient to quote individual atoms. There are higher-level + * rules that say when an address localpart needs to be quoted. + * We wing it with the quote_822_local() routine, which ignores + * the issue of atoms in the domain part that would need quoting. + */ + case TOK822_ADDR: + addr = tp; + tmp = acl_vstring_alloc(100); + tok822_internalize(tmp, tp->head, TOK822_STR_TERM); + addr_len = ACL_VSTRING_LEN(vp); + quote_822_local_flags(vp, acl_vstring_str(tmp), + QUOTE_FLAG_8BITCLEAN | QUOTE_FLAG_APPEND); + addr_len = ACL_VSTRING_LEN(vp) - addr_len; + acl_vstring_free(tmp); + break; + case TOK822_ATOM: + case TOK822_COMMENT: + acl_vstring_strcat(vp, acl_vstring_str(tp->vstr)); + break; + case TOK822_QSTRING: + ACL_VSTRING_ADDCH(vp, '"'); + tok822_copy_quoted(vp, acl_vstring_str(tp->vstr), "\"\\\r\n"); + ACL_VSTRING_ADDCH(vp, '"'); + break; + case TOK822_DOMLIT: + ACL_VSTRING_ADDCH(vp, '['); + tok822_copy_quoted(vp, acl_vstring_str(tp->vstr), "\\\r\n"); + ACL_VSTRING_ADDCH(vp, ']'); + break; + case TOK822_STARTGRP: + ACL_VSTRING_ADDCH(vp, ':'); + break; + case '<': + if (tp->next && tp->next->type == '>') { + addr = tp; + addr_len = 0; + } + ACL_VSTRING_ADDCH(vp, '<'); + break; + default: + if (tp->type >= TOK822_MINTOK) + acl_msg_panic("tok822_externalize: unknown operator %d", tp->type); + ACL_VSTRING_ADDCH(vp, tp->type); + } + if (tok822_append_space(tp)) + ACL_VSTRING_ADDCH(vp, ' '); + } + if (flags & TOK822_STR_TRNC) + ENFORCE_NONADDR_LENGTH; + + if (flags & TOK822_STR_TERM) + ACL_VSTRING_TERMINATE(vp); + return (vp); +} + +/* tok822_copy_quoted - copy a string while quoting */ + +static void tok822_copy_quoted(ACL_VSTRING *vp, char *str, const char *quote_set) +{ + int ch; + + while ((ch = *(unsigned char *) str++) != 0) { + if (strchr(quote_set, ch)) + ACL_VSTRING_ADDCH(vp, '\\'); + ACL_VSTRING_ADDCH(vp, ch); + } +} + +/* tok822_append_space - see if space is needed after this token */ + +static int tok822_append_space(TOK822 *tp) +{ + TOK822 *next; + + if (tp == 0 || (next = tp->next) == 0 || tp->owner != 0) + return (0); + if (tp->type == ',' || tp->type == TOK822_STARTGRP || next->type == '<') + return (1); + +#define NON_OPERATOR(x) \ + (x->type == TOK822_ATOM || x->type == TOK822_QSTRING \ + || x->type == TOK822_COMMENT || x->type == TOK822_DOMLIT \ + || x->type == TOK822_ADDR) + + return (NON_OPERATOR(tp) && NON_OPERATOR(next)); +} + +/* tok822_scan_limit - tokenize string */ + +TOK822 *tok822_scan_limit(const char *str, TOK822 **tailp, int tok_count_limit) +{ + TOK822 *head = 0; + TOK822 *tail = 0; + TOK822 *tp; + int ch; + int tok_count = 0; + + /* + * XXX 2822 new feature: Section 4.1 allows "." to appear in a phrase (to + * allow for forms such as: Johnny B. Goode . I cannot + * handle that at the tokenizer level - it is not context sensitive. And + * to fix this at the parser level requires radical changes to preserve + * white space as part of the token stream. Thanks a lot, people. + */ + while ((ch = *(const unsigned char *) str++) != 0) { + if (IS_SPACE_TAB_CR_LF(ch)) + continue; + if (ch == '(') { + tp = tok822_alloc(TOK822_COMMENT, (char *) 0); + str = tok822_comment(tp, str); + } else if (ch == '[') { + tp = tok822_alloc(TOK822_DOMLIT, (char *) 0); + COLLECT_SKIP_LAST(tp, str, ch, ch != ']'); + } else if (ch == '"') { + tp = tok822_alloc(TOK822_QSTRING, (char *) 0); + COLLECT_SKIP_LAST(tp, str, ch, ch != '"'); + } else if (ch != '\\' && strchr(tok822_opchar, ch)) { + tp = tok822_alloc(ch, (char *) 0); + } else { + tp = tok822_alloc(TOK822_ATOM, (char *) 0); + str -= 1; /* \ may be first */ + COLLECT(tp, str, ch, !IS_SPACE_TAB_CR_LF(ch) && !strchr(tok822_opchar, ch)); + tok822_quote_atom(tp); + } + if (head == 0) { + head = tail = tp; + while (tail->next) + tail = tail->next; + } else { + tail = tok822_append(tail, tp); + } + if (tok_count_limit > 0 && ++tok_count >= tok_count_limit) + break; + } + if (tailp) + *tailp = tail; + return (head); +} + +/* tok822_parse_limit - translate external string to token tree */ + +TOK822 *tok822_parse_limit(const char *str, int tok_count_limit) +{ + TOK822 *head; + TOK822 *tail; + TOK822 *right; + TOK822 *first_token; + TOK822 *last_token; + TOK822 *tp; + int state; + + /* + * First, tokenize the string, from left to right. We are not allowed to + * throw away any information that we do not understand. With a flat + * token list that contains all tokens, we can always convert back to + * string form. + */ + if ((first_token = tok822_scan_limit(str, &last_token, tok_count_limit)) == 0) + return (0); + + /* + * For convenience, sandwich the token list between two sentinel tokens. + */ +#define GLUE(left,rite) { left->next = rite; rite->prev = left; } + + head = tok822_alloc(0, (char *) 0); + GLUE(head, first_token); + tail = tok822_alloc(0, (char *) 0); + GLUE(last_token, tail); + + /* + * Next step is to transform the token list into a parse tree. This is + * done most conveniently from right to left. If there is something that + * we do not understand, just leave it alone, don't throw it away. The + * address information that we're looking for sits in-between the current + * node (tp) and the one called right. Add missing commas on the fly. + */ + state = DO_WORD; + right = tail; + tp = tail->prev; + while (tp->type) { + if (tp->type == TOK822_COMMENT) { /* move comment to the side */ + MOVE_COMMENT_AND_CONTINUE(tp, right); + } else if (tp->type == ';') { /* rh side of named group */ + right = tok822_group(TOK822_ADDR, tp, right, ADD_COMMA); + state = DO_GROUP | DO_WORD; + } else if (tp->type == ':' && (state & DO_GROUP) != 0) { + tp->type = TOK822_STARTGRP; + (void) tok822_group(TOK822_ADDR, tp, right, NO_MISSING_COMMA); + SKIP(tp, tp->type != ','); + right = tp; + continue; + } else if (tp->type == '>') { /* rh side of */ + right = tok822_group(TOK822_ADDR, tp, right, ADD_COMMA); + SKIP_MOVE_COMMENT(tp, tp->type != '<', right); + (void) tok822_group(TOK822_ADDR, tp, right, NO_MISSING_COMMA); + SKIP(tp, tp->type > 0xff || strchr(">;,:", tp->type) == 0); + right = tp; + state |= DO_WORD; + continue; + } else if (tp->type == TOK822_ATOM || tp->type == TOK822_QSTRING + || tp->type == TOK822_DOMLIT) { + if ((state & DO_WORD) == 0) + right = tok822_group(TOK822_ADDR, tp, right, ADD_COMMA)->next; + state &= ~DO_WORD; + } else if (tp->type == ',') { + right = tok822_group(TOK822_ADDR, tp, right, NO_MISSING_COMMA); + state |= DO_WORD; + } else { + state |= DO_WORD; + } + tp = tp->prev; + } + (void) tok822_group(TOK822_ADDR, tp, right, NO_MISSING_COMMA); + + /* + * Discard the sentinel tokens on the left and right extremes. Properly + * terminate the resulting list. + */ + tp = (head->next != tail ? head->next : 0); + tok822_cut_before(head->next); + tok822_free(head); + tok822_cut_before(tail); + tok822_free(tail); + return (tp); +} + +/* tok822_quote_atom - see if an atom needs quoting when externalized */ + +static void tok822_quote_atom(TOK822 *tp) +{ + char *cp; + int ch; + + /* + * RFC 822 expects 7-bit data. Rather than quoting every 8-bit character + * (and still passing it on as 8-bit data) we leave 8-bit data alone. + */ + for (cp = acl_vstring_str(tp->vstr); (ch = *(unsigned char *) cp) != 0; cp++) { + if ( /* !ISASCII(ch) || */ ch == ' ' + || ACL_ISCNTRL(ch) || strchr(tok822_opchar, ch)) + { + tp->type = TOK822_QSTRING; + break; + } + } +} + +/* tok822_comment - tokenize comment */ + +static const char *tok822_comment(TOK822 *tp, const char *str) +{ + int level = 1; + int ch; + + /* + * XXX We cheat by storing comments in their external form. Otherwise it + * would be a royal pain to preserve \ before (. That would require a + * recursive parser; the easy to implement stack-based recursion would be + * too expensive. + */ + ACL_VSTRING_ADDCH(tp->vstr, '('); + + while ((ch = *(const unsigned char *) str) != 0) { + ACL_VSTRING_ADDCH(tp->vstr, ch); + str++; + if (ch == '(') { /* comments can nest! */ + level++; + } else if (ch == ')') { + if (--level == 0) + break; + } else if (ch == '\\') { + if ((ch = *(unsigned char *) str) == 0) + break; + ACL_VSTRING_ADDCH(tp->vstr, ch); + str++; + } + } + ACL_VSTRING_TERMINATE(tp->vstr); + return (str); +} + +/* tok822_group - cluster a group of tokens */ + +static TOK822 *tok822_group(int group_type, TOK822 *left, TOK822 *right, int sync_type) +{ + TOK822 *group; + TOK822 *sync; + TOK822 *first; + + /* + * Cluster the tokens between left and right under their own parse tree + * node. Optionally insert a resync token. + */ + if (left != right && (first = left->next) != right) { + tok822_cut_before(right); + tok822_cut_before(first); + group = tok822_alloc(group_type, (char *) 0); + tok822_sub_append(group, first); + tok822_append(left, group); + tok822_append(group, right); + if (sync_type) { + sync = tok822_alloc(sync_type, (char *) 0); + tok822_append(left, sync); + } + } + return (left); +} + +/* tok822_scan_addr - convert external address string to address token */ + +TOK822 *tok822_scan_addr(const char *addr) +{ + TOK822 *tree = tok822_alloc(TOK822_ADDR, (char *) 0); + + tree->head = tok822_scan(addr, &tree->tail); + return (tree); +} + +#ifdef TEST + +#include +#include +#include + +/* tok822_print - display token */ + +static void tok822_print(TOK822 *list, int indent) +{ + TOK822 *tp; + + for (tp = list; tp; tp = tp->next) { + if (tp->type < TOK822_MINTOK) { + vstream_printf("%*s %s \"%c\"\n", indent, "", "OP", tp->type); + } else if (tp->type == TOK822_ADDR) { + vstream_printf("%*s %s\n", indent, "", "address"); + tok822_print(tp->head, indent + 2); + } else if (tp->type == TOK822_STARTGRP) { + vstream_printf("%*s %s\n", indent, "", "group \":\""); + } else { + vstream_printf("%*s %s \"%s\"\n", indent, "", + tp->type == TOK822_COMMENT ? "comment" : + tp->type == TOK822_ATOM ? "atom" : + tp->type == TOK822_QSTRING ? "quoted string" : + tp->type == TOK822_DOMLIT ? "domain literal" : + tp->type == TOK822_ADDR ? "address" : + "unknown\n", vstring_str(tp->vstr)); + } + } +} + +int main(int unused_argc, char **unused_argv) +{ + VSTRING *vp = vstring_alloc(100); + TOK822 *list; + VSTRING *buf = vstring_alloc(100); + +#define TEST_TOKEN_LIMIT 20 + + while (readlline(buf, VSTREAM_IN, (int *) 0)) { + while (VSTRING_LEN(buf) > 0 && vstring_end(buf)[-1] == '\n') { + vstring_end(buf)[-1] = 0; + vstring_truncate(buf, VSTRING_LEN(buf) - 1); + } + if (!isatty(vstream_fileno(VSTREAM_IN))) + vstream_printf(">>>%s<<<\n\n", vstring_str(buf)); + list = tok822_parse_limit(vstring_str(buf), TEST_TOKEN_LIMIT); + vstream_printf("Parse tree:\n"); + tok822_print(list, 0); + vstream_printf("\n"); + + vstream_printf("Internalized:\n%s\n\n", + vstring_str(tok822_internalize(vp, list, TOK822_STR_DEFL))); + vstream_fflush(VSTREAM_OUT); + vstream_printf("Externalized, no newlines inserted:\n%s\n\n", + vstring_str(tok822_externalize(vp, list, + TOK822_STR_DEFL | TOK822_STR_TRNC))); + vstream_fflush(VSTREAM_OUT); + vstream_printf("Externalized, newlines inserted:\n%s\n\n", + vstring_str(tok822_externalize(vp, list, + TOK822_STR_DEFL | TOK822_STR_LINE | TOK822_STR_TRNC))); + vstream_fflush(VSTREAM_OUT); + tok822_free_tree(list); + } + vstring_free(vp); + vstring_free(buf); + return (0); +} + +#endif diff --git a/lib_acl_cpp/src/mime/internal/tok822_resolve.c b/lib_acl_cpp/src/mime/internal/tok822_resolve.c new file mode 100644 index 000000000..6ef84edeb --- /dev/null +++ b/lib_acl_cpp/src/mime/internal/tok822_resolve.c @@ -0,0 +1,73 @@ +/*++ + * NAME + * tok822_resolve 3 + * SUMMARY + * address resolving, client interface + * SYNOPSIS + * #include + * + * void tok822_resolve(addr, reply) + * TOK822 *addr; + * RESOLVE_REPLY *reply; + * + * void tok822_resolve_from(sender, addr, reply) + * const char *sender; + * TOK822 *addr; + * RESOLVE_REPLY *reply; + * DESCRIPTION + * tok822_resolve() takes an address token tree and finds out the + * transport to deliver via, the next-hop host on that transport, + * and the recipient relative to that host. + * + * tok822_resolve_from() allows the caller to specify sender context + * that will be used to look up sender-dependent relayhost information. + * SEE ALSO + * resolve_clnt(3) basic resolver client interface + * LICENSE + * .ad + * .fi + * The Secure Mailer license must be distributed with this software. + * AUTHOR(S) + * Wietse Venema + * IBM T.J. Watson Research + * P.O. Box 704 + * Yorktown Heights, NY 10598, USA + *--*/ + +/* System library. */ +#include "acl_stdafx.hpp" + +/* Utility library. */ + +#include "acl/stdlib/acl_vstring.h" +#include "acl/stdlib/acl_msg.h" + +/* Global library. */ + +#include "resolve_clnt.h" +#include "tok822.h" + +/* tok822_resolve - address rewriting interface */ + +void tok822_resolve_from(const char *sender, TOK822 *addr, + RESOLVE_REPLY *reply) +{ + ACL_VSTRING *intern_form = acl_vstring_alloc(100); + + if (addr->type != TOK822_ADDR) + acl_msg_panic("tok822_resolve: non-address token type: %d", addr->type); + + /* + * Internalize the token tree and ship it to the resolve service. + * Shipping string forms is much simpler than shipping parse trees. + */ + tok822_internalize(intern_form, addr->head, TOK822_STR_DEFL); + resolve_clnt_query_from(sender, acl_vstring_str(intern_form), reply); + if (acl_msg_verbose) + acl_msg_info("tok822_resolve: from=%s addr=%s -> chan=%s, host=%s, rcpt=%s", + sender, + acl_vstring_str(intern_form), acl_vstring_str(reply->transport), + acl_vstring_str(reply->nexthop), acl_vstring_str(reply->recipient)); + + acl_vstring_free(intern_form); +} diff --git a/lib_acl_cpp/src/mime/internal/tok822_rewrite.c b/lib_acl_cpp/src/mime/internal/tok822_rewrite.c new file mode 100644 index 000000000..d3df82710 --- /dev/null +++ b/lib_acl_cpp/src/mime/internal/tok822_rewrite.c @@ -0,0 +1,69 @@ +/*++ + * NAME + * tok822_rewrite 3 + * SUMMARY + * address rewriting, client interface + * SYNOPSIS + * #include + * + * TOK822 *tok822_rewrite(addr, how) + * TOK822 *addr; + * char *how; + * DESCRIPTION + * tok822_rewrite() takes an address token tree and transforms + * it according to the rule set specified via \fIhow\fR. The + * result is the \fIaddr\fR argument. + * LICENSE + * .ad + * .fi + * The Secure Mailer license must be distributed with this software. + * AUTHOR(S) + * Wietse Venema + * IBM T.J. Watson Research + * P.O. Box 704 + * Yorktown Heights, NY 10598, USA + *--*/ + +/* System library. */ + +/* Utility library. */ +#include "acl_stdafx.hpp" +#include "acl/stdlib/acl_vstring.h" +#include "acl/stdlib/acl_msg.h" + +/* Global library. */ + +#include "rewrite_clnt.h" +#include "tok822.h" + +/* tok822_rewrite - address rewriting interface */ + +#define STR acl_vstring_str + +TOK822 *tok822_rewrite(TOK822 *addr, const char *how) +{ + const char *myname = "tok822_rewrite"; + ACL_VSTRING *input_ext_form = acl_vstring_alloc(100); + ACL_VSTRING *canon_ext_form = acl_vstring_alloc(100); + + if (addr->type != TOK822_ADDR) + acl_msg_panic("%s: non-address token type: %d", myname, addr->type); + + /* + * Externalize the token tree, ship it to the rewrite service, and parse + * the result. Shipping external form is much simpler than shipping parse + * trees. + */ + tok822_externalize(input_ext_form, addr->head, TOK822_STR_DEFL); + if (acl_msg_verbose) + acl_msg_info("%s: input: %s", myname, STR(input_ext_form)); + rewrite_clnt(how, STR(input_ext_form), canon_ext_form); + if (msg_verbose) + acl_msg_info("tok822_rewrite: result: %s", STR(canon_ext_form)); + tok822_free_tree(addr->head); + addr->head = tok822_scan(STR(canon_ext_form), &addr->tail); + + acl_vstring_free(input_ext_form); + acl_vstring_free(canon_ext_form); + return (addr); +} diff --git a/lib_acl_cpp/src/mime/internal/tok822_tree.cpp b/lib_acl_cpp/src/mime/internal/tok822_tree.cpp new file mode 100644 index 000000000..d9b7e79ca --- /dev/null +++ b/lib_acl_cpp/src/mime/internal/tok822_tree.cpp @@ -0,0 +1,304 @@ +/*++ + * NAME + * tok822_tree 3 + * SUMMARY + * assorted token tree operators + * SYNOPSIS + * #include + * + * TOK822 *tok822_append(t1, t2) + * TOK822 *t1; + * TOK822 *t2; + * + * TOK822 *tok822_prepend(t1, t2) + * TOK822 *t1; + * TOK822 *t2; + * + * TOK822 *tok822_cut_before(tp) + * TOK822 *tp; + * + * TOK822 *tok822_cut_after(tp) + * TOK822 *tp; + * + * TOK822 *tok822_unlink(tp) + * TOK822 *tp; + * + * TOK822 *tok822_sub_append(t1, t2) + * TOK822 *t1; + * + * TOK822 *tok822_sub_prepend(t1, t2) + * TOK822 *t1; + * TOK822 *t2; + * + * TOK822 *tok822_sub_keep_before(t1, t2) + * TOK822 *tp; + * + * TOK822 *tok822_sub_keep_after(t1, t2) + * TOK822 *tp; + * + * int tok822_apply(list, type, action) + * TOK822 *list; + * int type; + * int (*action)(TOK822 *token); + * + * int tok822_grep(list, type) + * TOK822 *list; + * int type; + * + * TOK822 *tok822_free_tree(tp) + * TOK822 *tp; + * DESCRIPTION + * This module manipulates trees of token structures. Trees grow + * to the right or downwards. Operators are provided to cut and + * combine trees in various manners. + * + * tok822_append() appends the token list \fIt2\fR to the right + * of token list \fIt1\fR. The result is the last token in \fIt2\fR. + * The appended list inherits the \fIowner\fR attribute from \fIt1\fR. + * The parent node, if any, is not updated. + * + * tok822_prepend() inserts the token list \fIt2\fR to the left + * of token \fIt1\fR. The result is the last token in \fIt2\fR. + * The appended list inherits the \fIowner\fR attribute from \fIt1\fR. + * The parent node, if any, is not updated. + * + * tok822_cut_before() breaks a token list on the left side of \fItp\fR + * and returns the left neighbor of \tItp\fR. + * + * tok822_cut_after() breaks a token list on the right side of \fItp\fR + * and returns the right neighbor of \tItp\fR. + * + * tok822_unlink() disconnects a token from its left and right neighbors + * and returns the left neighbor of \tItp\fR. + * + * tok822_sub_append() appends the token list \fIt2\fR to the right + * of the token list below \fIt1\fR. The result is the last token + * in \fIt2\fR. + * + * tok822_sub_prepend() prepends the token list \fIt2\fR to the left + * of the token list below \fIt1\fR. The result is the last token + * in \fIt2\fR. + * + * tok822_sub_keep_before() keeps the token list below \fIt1\fR on the + * left side of \fIt2\fR and returns the tail of the disconnected list. + * + * tok822_sub_keep_after() keeps the token list below \fIt1\fR on the + * right side of \fIt2\fR and returns the head of the disconnected list. + * + * tok822_apply() applies the specified action routine to all tokens + * matching the given type (to all tokens when a null type is given). + * Processing terminates when the action routine returns a non-zero + * value. The result is the last result returned by the action routine. + * tok822_apply() does not traverse vertical links. + * + * tok822_grep() returns a null-terminated array of pointers to tokens + * matching the specified type (all tokens when a null type is given). + * tok822_grep() does not traverse vertical links. The result must be + * given to myfree(). + * + * tok822_free_tree() destroys a tree of token structures and + * conveniently returns a null pointer. + * LICENSE + * .ad + * .fi + * The Secure Mailer license must be distributed with this software. + * AUTHOR(S) + * Wietse Venema + * IBM T.J. Watson Research + * P.O. Box 704 + * Yorktown Heights, NY 10598, USA +*--*/ + +/* System library. */ + +/* Utility library. */ +#include "acl_stdafx.hpp" +#include "stdlib/acl_mymalloc.h" + +/* Global library. */ + +#include "tok822.hpp" + +/* tok822_append - insert token list, return end of inserted list */ + +TOK822 *tok822_append(TOK822 *t1, TOK822 *t2) +{ + TOK822 *next = t1->next; + + t1->next = t2; + t2->prev = t1; + + t2->owner = t1->owner; + while (t2->next) + (t2 = t2->next)->owner = t1->owner; + + t2->next = next; + if (next) + next->prev = t2; + return (t2); +} + +/* tok822_prepend - insert token list, return end of inserted list */ + +TOK822 *tok822_prepend(TOK822 *t1, TOK822 *t2) +{ + TOK822 *prev = t1->prev; + + if (prev) + prev->next = t2; + t2->prev = prev; + + t2->owner = t1->owner; + while (t2->next) + (t2 = t2->next)->owner = t1->owner; + + t2->next = t1; + t1->prev = t2; + return (t2); +} + +/* tok822_cut_before - split list before token, return predecessor token */ + +TOK822 *tok822_cut_before(TOK822 *tp) +{ + TOK822 *prev = tp->prev; + + if (prev) { + prev->next = 0; + tp->prev = 0; + } + return (prev); +} + +/* tok822_cut_after - split list after token, return successor token */ + +TOK822 *tok822_cut_after(TOK822 *tp) +{ + TOK822 *next = tp->next; + + if (next) { + next->prev = 0; + tp->next = 0; + } + return (next); +} + +/* tok822_unlink - take token away from list, return predecessor token */ + +TOK822 *tok822_unlink(TOK822 *tp) +{ + TOK822 *prev = tp->prev; + TOK822 *next = tp->next; + + if (prev) + prev->next = next; + if (next) + next->prev = prev; + tp->prev = tp->next = 0; + return (prev); +} + +/* tok822_sub_append - append sublist, return end of appended list */ + +TOK822 *tok822_sub_append(TOK822 *t1, TOK822 *t2) +{ + if (t1->head) { + return (t1->tail = tok822_append(t1->tail, t2)); + } else { + t1->head = t2; + while (t2->next) + (t2 = t2->next)->owner = t1; + return (t1->tail = t2); + } +} + +/* tok822_sub_prepend - prepend sublist, return end of prepended list */ + +TOK822 *tok822_sub_prepend(TOK822 *t1, TOK822 *t2) +{ + TOK822 *tp; + + if (t1->head) { + tp = tok822_prepend(t1->head, t2); + t1->head = t2; + return (tp); + } else { + t1->head = t2; + while (t2->next) + (t2 = t2->next)->owner = t1; + return (t1->tail = t2); + } +} + +/* tok822_sub_keep_before - cut sublist, return tail of disconnected list */ + +TOK822 *tok822_sub_keep_before(TOK822 *t1, TOK822 *t2) +{ + TOK822 *tail = t1->tail; + + if ((t1->tail = tok822_cut_before(t2)) == 0) + t1->head = 0; + return (tail); +} + +/* tok822_sub_keep_after - cut sublist, return head of disconnected list */ + +TOK822 *tok822_sub_keep_after(TOK822 *t1, TOK822 *t2) +{ + TOK822 *head = t1->head; + + if ((t1->head = tok822_cut_after(t2)) == 0) + t1->tail = 0; + return (head); +} + +/* tok822_free_tree - destroy token tree */ + +TOK822 *tok822_free_tree(TOK822 *tp) +{ + if (tp) { + if (tp->next) + tok822_free_tree(tp->next); + if (tp->head) + tok822_free_tree(tp->head); + tok822_free(tp); + } + return (0); +} + +/* tok822_apply - apply action to specified tokens */ + +int tok822_apply(TOK822 *tree, int type, TOK822_ACTION action) +{ + TOK822 *tp; + int result = 0; + + for (tp = tree; tp; tp = tp->next) { + if (type == 0 || tp->type == type) + if ((result = action(tp)) != 0) + break; + } + return (result); +} + +/* tok822_grep - list matching tokens */ + +TOK822 **tok822_grep(TOK822 *tree, int type) +{ + TOK822 **list; + TOK822 *tp; + int count; + + for (count = 0, tp = tree; tp; tp = tp->next) + if (type == 0 || tp->type == type) + count++; + + list = (TOK822 **) acl_mymalloc(sizeof(*list) * (count + 1)); + + for (count = 0, tp = tree; tp; tp = tp->next) + if (type == 0 || tp->type == type) + list[count++] = tp; + + list[count] = 0; + return (list); +} diff --git a/lib_acl_cpp/src/mime/internal/trimblanks.cpp b/lib_acl_cpp/src/mime/internal/trimblanks.cpp new file mode 100644 index 000000000..163802098 --- /dev/null +++ b/lib_acl_cpp/src/mime/internal/trimblanks.cpp @@ -0,0 +1,50 @@ +/*++ + * NAME + * trimblanks 3 + * SUMMARY + * skip leading whitespace + * SYNOPSIS + * #include + * + * char *trimblanks(string, len) + * char *string; + * int len; + * DESCRIPTION + * trimblanks() returns a pointer to the beginning of the trailing + * whitespace in \fIstring\fR, or a pointer to the string terminator + * when the string contains no trailing whitespace. + * The \fIlen\fR argument is either zero or the string length. + * LICENSE + * .ad + * .fi + * The Secure Mailer license must be distributed with this software. + * AUTHOR(S) + * Wietse Venema + * IBM T.J. Watson Research + * P.O. Box 704 + * Yorktown Heights, NY 10598, USA + *--*/ + +/* System library. */ + +#include "acl_stdafx.hpp" +#include + +/* Utility library. */ + +#include "trimblanks.hpp" + +char *trimblanks(char *string, int len) +{ + char *curr; + + if (len) { + curr = string + len; + } else { + for (curr = string; *curr != 0; curr++) + /* void */ ; + } + while (curr > string && ACL_ISSPACE(curr[-1])) + curr -= 1; + return (curr); +} diff --git a/lib_acl_cpp/src/mime/internal/trimblanks.hpp b/lib_acl_cpp/src/mime/internal/trimblanks.hpp new file mode 100644 index 000000000..b780116af --- /dev/null +++ b/lib_acl_cpp/src/mime/internal/trimblanks.hpp @@ -0,0 +1,6 @@ +#ifndef _S_OPTS_H_INCLUDED_ +#define _S_OPTS_H_INCLUDED_ + +extern char *trimblanks(char *string, int len); + +#endif diff --git a/lib_acl_cpp/src/mime/mime.cpp b/lib_acl_cpp/src/mime/mime.cpp new file mode 100644 index 000000000..550ef8778 --- /dev/null +++ b/lib_acl_cpp/src/mime/mime.cpp @@ -0,0 +1,848 @@ +#include "acl_stdafx.hpp" +#include "internal/mime_state.hpp" +#include "internal/header_opts.hpp" +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/stdlib/xml.hpp" +#include "acl_cpp/stream/ifstream.hpp" +#include "acl_cpp/stream/ofstream.hpp" +#include "acl_cpp/stdlib/pipe_stream.hpp" +#include "acl_cpp/stdlib/charset_conv.hpp" +#include "acl_cpp/mime/mime_attach.hpp" +#include "acl_cpp/mime/mime_image.hpp" +#include "acl_cpp/mime/mime_body.hpp" +#include "acl_cpp/mime/mime_base64.hpp" +#include "acl_cpp/mime/mime_uucode.hpp" +#include "acl_cpp/mime/mime_xxcode.hpp" +#include "acl_cpp/mime/mime_quoted_printable.hpp" +#include "acl_cpp/mime/rfc2047.hpp" + +#include "acl_cpp/mime/mime.hpp" + +namespace acl { + +mime::mime() +{ + m_pMimeState = mime_state_alloc(); + m_bPrimaryHeadFinish = false; + m_pFilePath = NULL; + m_pBody = NULL; + m_pNodes = NULL; + m_pAttaches = NULL; + m_pImages = NULL; +} + +mime::~mime() +{ + reset(); + mime_state_free(m_pMimeState); + if (m_pNodes) + delete m_pNodes; + if (m_pAttaches) + delete m_pAttaches; + if (m_pImages) + delete m_pImages; +} + +mime& mime::reset(void) +{ + m_primaryHeader.reset(); + mime_state_reset(m_pMimeState); + m_bPrimaryHeadFinish = false; + + if (m_pFilePath) + { + acl_myfree(m_pFilePath); + m_pFilePath = NULL; + } + + if (m_pBody) + { + delete m_pBody; + m_pBody = NULL; + } + + if (m_pNodes) + { + std::list::iterator it = m_pNodes->begin(); + for (; it != m_pNodes->end(); ++it) + delete (*it); + m_pNodes->clear(); + } + + if (m_pAttaches) + { + std::list::iterator it = m_pAttaches->begin(); + for (; it != m_pAttaches->end(); ++it) + delete (*it); + m_pAttaches->clear(); + } + + if (m_pImages) + { + std::list::iterator it = m_pImages->begin(); + for (; it != m_pImages->end(); ++it) + delete (*it); + m_pImages->clear(); + } + + return (*this); +} + +bool mime::primary_head_ok() const +{ + if (mime_state_head_finish(m_pMimeState)) + return (true); + else + return (false); +} + +void mime::update_begin(const char* path) +{ + reset(); + if (m_pFilePath) + acl_myfree(m_pFilePath); + if (path && *path) + m_pFilePath = acl_mystrdup(path); +} + +bool mime::update(const char* data, size_t len) +{ + return (mime_state_update(m_pMimeState, data, len) == 1 ? true : false); +} + +void mime::update_end() +{ + primary_head_finish(); +} + +void mime::primary_head_finish() +{ + if (m_bPrimaryHeadFinish == true) + return; + + MIME_NODE* node = m_pMimeState->root; + + m_primaryHeader.set_type(node->ctype, node->stype); + + // 针对邮件主头部 + ACL_ITER iter; + + if (node->header_to_list) { + acl_foreach(iter, node->header_to_list) { + MAIL_ADDR* mail_addr = (MAIL_ADDR*) iter.data; + add_to(mail_addr->addr); + } + } + if (node->header_cc_list) { + acl_foreach(iter, node->header_cc_list) { + MAIL_ADDR* mail_addr = (MAIL_ADDR*) iter.data; + add_cc(mail_addr->addr); + } + } + if (node->header_bcc_list) { + acl_foreach(iter, node->header_bcc_list) { + MAIL_ADDR* mail_addr = (MAIL_ADDR*) iter.data; + add_bcc(mail_addr->addr); + } + } + if (node->header_list) { + acl_foreach(iter, node->header_list) { + HEADER_NV* header = (HEADER_NV*) iter.data; + add_header(header->name, header->value); + } + } + + if (node->header_sender) + set_sender(node->header_sender); + if (node->header_from) + set_from(node->header_from); + if (node->header_replyto) + set_replyto(node->header_replyto); + if (node->header_returnpath) + set_returnpath(node->header_returnpath); + if (node->header_subject) + set_subject(node->header_subject); + + m_bPrimaryHeadFinish = true; +} + +bool mime::parse(const char* path) +{ + acl::ifstream fp; + + if (fp.open_read(path) == false) { + logger_error("open %s error %s", path, acl_last_serror()); + return (false); + } + + acl::string buf(1024); + const char* ptr; + int ret; + + while (1) { +#if 0 + if (fp.gets(buf, false) == false) + break; + ptr = buf.c_str(); + ret = (int) buf.length(); +#elif 1 + ret = fp.read(buf.c_str(), buf.capacity() - 1, false); + if (ret <= 0) + break; + ptr = buf.c_str(); +#else + char ch; + if (fp.read(ch) == false) + break; + buf = (char) ch; + ptr = buf.c_str(); + ret = (int) buf.length(); +#endif + + if (mime_state_update(m_pMimeState, ptr, ret) == 1) + break; + buf.clear(); + } + + fp.close(); + primary_head_finish(); + if (m_pFilePath) + acl_myfree(m_pFilePath); + m_pFilePath = acl_mystrdup(path); + return (true); +} + +static bool save_as(ifstream& in, fstream& out, off_t pos, ssize_t len) +{ + if (pos < 0 || len <= 0) + return (true); + + char buf[8192]; + + if (in.fseek(pos, SEEK_SET) < 0) + { + logger_error("fseek error(%s)", acl_last_serror()); + return (false); + } + + size_t size; + int ret; + + while (len > 0) + { + size = sizeof(buf) > (size_t) len ? (size_t) len : sizeof(buf); + ret = in.read(buf, size); + if (ret < 0) + { + logger_error("read error(%s)", acl_last_serror()); + return (false); + } + if (out.write(buf, ret) == false) + { + logger_error("write error(%s), n: %d", + acl_last_serror(), ret); + return (false); + } + len -= ret; + } + + return (true); +} + +static bool save_as(ifstream& in, fstream& out, MIME_NODE* node) +{ + if (node->header_begin < 0 || node->header_end <= node->header_begin) + { + logger_warn("node invalid, header_begin(%d), " + "header_end(%d), body_begin(%d), body_end(%d)", + (int) node->header_begin); + return (true); + } + + ssize_t len = node->header_end - node->header_begin; + if (len <= 0) + { + logger_warn("header_begin(%d) >= header_end(%d)", + (int) node->header_begin, (int) node->header_end); + return (true); + } + if (save_as(in, out, node->header_begin, len) == false) + return (false); + + // 对于 multipart 邮件其 bound_end 应大于 body_begin, + // 而对于非 multipart 邮件其 bound_end 应为 0,此时应 + // 采用 body_end + if (node->bound_end > node->body_begin) + len = node->bound_end - node->body_begin; + else + len = node->body_end - node->body_begin; + if (len <= 0) + return (true); + return (save_as(in, out, node->body_begin, len)); +} + +bool mime::save_as(fstream& out) +{ + if (m_pFilePath == NULL) + { + logger_error("no input filePath"); + return (false); + } + + ACL_ITER iter; + ifstream in; + + if (in.open_read(m_pFilePath) == false) + { + logger_error("open input file %s error(%s)", + m_pFilePath, acl_last_serror()); + return (false); + } + + //if (acl_ring_size(&m_pMimeState->root->children) == 0) + //{ + // // 如果没有 MIME 结点则说明不是 multipart 格式 + // return (copy_file(in, out)); + //} + + // 说明是 multipart 格式 + + // 输出邮件头 + if (acl::save_as(in, out, m_pMimeState->root) == false) + return (false); + + // 输出邮件体的各个一级 MIME 结点及所属内容 + acl_foreach(iter, m_pMimeState->root) + { + MIME_NODE* node = (MIME_NODE*) iter.data; + if (acl::save_as(in, out, node) == false) + return (false); + } + + // 输出最后一个空行 + if (m_pMimeState->use_crlf) + out << "\r\n"; + else + out << "\n"; + + return (true); +} + +bool mime::save_as(const char* file_path) +{ + if (m_pFilePath == NULL) + { + logger_error("no input filePath"); + return (false); + } + + acl::fstream out; + if (out.open_trunc(file_path) == false) + { + logger_error("open file %s error(%s)", + file_path, acl_last_serror()); + return (false); + } + + bool ret = save_as(out); + if (ret == false) + { +#ifdef WIN32 + _unlink(file_path); +#else + unlink(file_path); +#endif + return (false); + } + return (true); +} + +bool mime::save_mail(const char* path, const char* filename, + bool enableDecode /* = true */, const char* toCharset /* = "gb2312" */, + off_t off /* = 0 */) +{ + mime_body* pBody = get_body_node(true, true, NULL); + if (pBody == NULL) + return (false); + + string filepath; + acl_make_dirs(path, 0700); + + if (!pBody->html_stype() + || pBody->parent_ctype() != MIME_CTYPE_MULTIPART) + //|| pBody->parent_stype() != MIME_STYPE_RELATED) + { + filepath << path << "/" << filename; + return (pBody->save_body(filepath.c_str())); + } + + + const std::list& images = get_images(enableDecode, toCharset, off); + if (images.empty()) + { + filepath.clear(); + filepath << path << "/" << filename; + return (pBody->save_body(filepath.c_str())); + } + + string buf; + if (pBody->save_body(buf) == false) + return (false); + + string subPath(path); + subPath << "/img"; + acl_make_dirs(subPath.c_str(), 0700); + + const char* name; + std::list::const_iterator cit = images.begin(); + for (; cit != images.end(); ++cit) + { + name = (*cit)->get_name(); + if (name == NULL) + continue; + filepath.clear(); + filepath << subPath.c_str() << "/" << name; + (*cit)->save(filepath.c_str()); + } + + filepath.clear(); + filepath << path << "/" << filename; + ofstream fpOut; + if (fpOut.open_write(filepath.c_str()) == false) + { + logger_error("create %s error(%s)", + filepath.c_str(), acl_last_serror()); + return (false); + } + +#define SKIP_SP(p) { while (*(p) == ' ' || *(p) == '\t') (p)++; } + + char* s = buf.c_str(), *ptr; + const mime_image* pImg; + string cid(64), cidkey(64); + char last_ch = 0; + + while (true) + { + ptr = strcasestr(s, "cid:"); + if (ptr == NULL) + break; + fpOut.write(s, ptr - s); + ptr += 4; + SKIP_SP(ptr); + if (*ptr == 0) + { + s = NULL; + break; + } + s = ptr; + cidkey.clear(); + + while (*ptr) + { + if (*ptr == ' ' || *ptr == '\t' + || *ptr == '"' || *ptr == '\'' || *ptr == '>') + { + cid.copy(s, ptr - s); + cidkey = '<'; + cidkey += cid.c_str(); + cidkey += '>'; + + last_ch = *ptr; + ptr++; + break; + } + ptr++; + } + + if (*ptr == 0 || cidkey.empty()) + { + fpOut << cid.c_str(); + s = NULL; + break; + } + + pImg = get_image(cidkey.c_str(), enableDecode, toCharset, off); + if (pImg == NULL || (name = pImg->get_name()) == NULL) + { + fpOut << cid.c_str(); + if (last_ch) + { + fpOut << last_ch; + last_ch = 0; + } + s = ptr; + continue; + } + + filepath.clear(); + filepath << "img/" << name; + fpOut << filepath.c_str(); + if (last_ch) + { + fpOut << last_ch; + last_ch = 0; + } + + s = ptr; + } + + if (s) + fpOut << s; + + return (true); +} + +// 找到邮件正文结点 +static MIME_NODE* body_node(MIME_STATE* pMime, bool htmlFirst) +{ + // 如果不是 multipart 格式则返回根结点为邮件正文结点 + if (pMime->root->ctype != MIME_CTYPE_MULTIPART) + { + return (pMime->root); + } + else if (pMime->root->boundary == NULL) + { + logger_warn("no boundary for multipart"); + return (pMime->root); + } + + ACL_ITER iter; + + if (htmlFirst) + { + MIME_NODE* pHtml = NULL, *pText = NULL; + acl_foreach(iter, pMime) + { + MIME_NODE* pNode = (MIME_NODE*) iter.data; + if (pNode->ctype != MIME_CTYPE_TEXT) + continue; + + if (pNode->stype == MIME_STYPE_HTML) + { + pHtml = pNode; + break; + } + else if (pNode->stype == MIME_STYPE_PLAIN) + { + // 仅保留第一个纯文本的结点 + if (pText == NULL) + pText = pNode; + } + } + + return (pHtml != NULL ? pHtml : pText); + } + + // 从根结点开始遍历整个 multipart 邮件中所有的子结点, + // 直至找到第一个不包含子结点的结点,因为遍历过程本身 + // 保证了遍历是自上而下遍历的,即先遍历根结点的子结点, + // 然后层层遍历子结点的子结点直至满足条件为止 + // + + MIME_NODE* pAlterNativeNode = NULL; + + acl_foreach(iter, pMime) + { + MIME_NODE* pNode = (MIME_NODE*) iter.data; + if (pNode->ctype != MIME_CTYPE_MULTIPART + && pNode->stype != MIME_STYPE_ALTERNATIVE) + { + continue; + } + // 如果该结点的子结点数小于 2 则说明邮件格式有误 + if (acl_ring_size(&pNode->children) < 2) + continue; + pAlterNativeNode = pNode; + } + + if (pAlterNativeNode == NULL) + { + logger_warn("no alternative node"); + return (pMime->root); + } + + return (acl_ring_first_appl(&pAlterNativeNode->children, + MIME_NODE, node)); +} + +mime_body* mime::get_body_node(bool htmlFirst, + bool enableDecode /* = true */, + const char* toCharset /* = "gb2312" */, + off_t off /* = 0 */) +{ +#define EQ2(x, y) (((x) == NULL && (y) == NULL) \ + || ((x) != NULL && (y) != NULL && !strcasecmp((x), (y)))) + + if (m_pBody != NULL) + { + const char* ptr = m_pBody->get_toCharset(); + if (EQ2(toCharset, ptr)) + return (m_pBody); + delete m_pBody; + } + + MIME_NODE* node = body_node(m_pMimeState, htmlFirst); + if (node == NULL) + return (NULL); + m_pBody = NEW mime_body(m_pFilePath, node, htmlFirst, + enableDecode, toCharset, off); + return (m_pBody); +} + +const std::list& mime::get_mime_nodes( + bool enableDecode /* = true */, off_t off /* = 0 */) +{ + if (m_pNodes == NULL) + m_pNodes = NEW std::list; + else if (!m_pNodes->empty()) + return (*m_pNodes); + + if (m_pMimeState == NULL) + return (*m_pNodes); + + ACL_ITER iter; + MIME_NODE* node; + acl_foreach(iter, m_pMimeState) + { + node = (MIME_NODE*) iter.data; + m_pNodes->push_back(NEW mime_node(m_pFilePath, node, + enableDecode, "gb2312", off)); + } + return (*m_pNodes); +} + +const std::list& mime::get_attachments( + bool enableDecode /* = true */, off_t off /* = 0 */) +{ + if (m_pAttaches == NULL) + m_pAttaches = NEW std::list; + else if (!m_pAttaches->empty()) + return (*m_pAttaches); + + if (m_pMimeState == NULL) + return (*m_pAttaches); + + ACL_ITER iter; + mime_attach* attach; + MIME_NODE* node; + acl_foreach(iter, m_pMimeState) + { + node = (MIME_NODE*) iter.data; + if (node->header_filename == NULL) + continue; + attach = NEW mime_attach(m_pFilePath, node, + enableDecode, NULL, off); + m_pAttaches->push_back(attach); + } + return (*m_pAttaches); +} + +const std::list& mime::get_images(bool enableDecode /* = true */, + const char* toCharset /* = "gb2312" */, off_t off /* = 0 */) +{ + if (m_pImages == NULL) + m_pImages = NEW std::list; + else if (!m_pImages->empty()) + return (*m_pImages); + + if (m_pMimeState == NULL) + return (*m_pImages); + + ACL_ITER iter; + MIME_NODE* node; + acl_foreach(iter, m_pMimeState) + { + node = (MIME_NODE*) iter.data; + if (node->ctype != MIME_CTYPE_IMAGE) + continue; + m_pImages->push_back(NEW mime_image(m_pFilePath, + node, enableDecode, toCharset, off)); + } + return (*m_pImages); +} + +mime_image* mime::get_image(const char* cid, bool enableDecode /* = true */, + const char* toCharset /* = "gb2312" */, off_t off /* = 0 */) +{ + const char* ptr; + const std::list& images = + get_images(enableDecode, toCharset, off); + std::list::const_iterator cit = images.begin(); + for (; cit != images.end(); ++cit) + { + ptr = (*cit)->header_value("Content-ID"); + if (ptr != NULL && strcmp(ptr, cid) == 0) + return (*cit); + } + + return (NULL); +} + +static void mime_node_dump(const char* from_path, const char* dump_path, + MIME_NODE *node, bool decode) +{ + ifstream in; + fstream out; + string path; + char *pbuf; + static int i = 0; + + if (dump_path == NULL) + return; + + if (in.open_read(from_path) == false) + return; + + path.format("%s/node_%d.txt", dump_path, i++); + if (out.open_trunc(path.c_str()) == false) { + logger_error("open %s error(%s)", path.c_str(), + acl_last_serror()); + return; + } + + ssize_t dlen = node->header_end - node->header_begin; + + out.puts(">---------header begin--------<"); + off_t pos = (off_t) in.fseek(node->header_begin, SEEK_SET); + pbuf = (char*) acl_mymalloc(dlen); + printf(">>>%s: header begin: %ld, end: %ld, len: %ld\n", + __FUNCTION__, node->header_begin, node->header_end, (long int) dlen); + + int ret; + if ((ret = in.read(pbuf, dlen, true)) < 0) { + acl_myfree(pbuf); + return; + } + printf(">>>%s: ret: %d\n", __FUNCTION__, ret); + + out.write(pbuf, ret); + + out.puts(">---------header end----------<"); + acl_myfree(pbuf); + + dlen = node->body_end - node->body_begin; + printf(">>>%s: body begin: %ld, end: %ld, len: %ld\r\n", + __FUNCTION__, node->body_begin, node->body_end, (long int) dlen); + + out.format(">---------body begin(length: %d)----------<\r\n", (int) dlen); + + if (dlen <= 0) { + printf(">>>%s: body_begin(%d) >= body_end(%d), len: %d\r\n", + __FUNCTION__, (int) node->body_begin, + (int) node->body_end, (int) dlen); + out.close(); + in.close(); + return; + } + pos = (off_t) in.fseek(node->body_begin, SEEK_SET); + if (pos == -1) + { + printf(">>>%s: fseek error(%s)\r\n", __FUNCTION__, acl_last_serror()); + return; + } + + pbuf = (char*) acl_mymalloc(dlen); + if ((ret = in.read(pbuf, dlen, true)) == -1) { + acl_myfree(pbuf); + return; + } + + mime_code* decoder; + if (decode) + decoder = mime_code::create(node->encoding); + else + decoder = NULL; + + if (decoder == NULL) + out.write(pbuf, dlen); + else + { + acl::string result(8192); + const char* ptr = pbuf; + ssize_t n; + + while (dlen > 0) + { + n = dlen > 8192 ? 8192 : dlen; + //n = dlen; + decoder->decode_update(ptr, n, &result); + if (result.length() > 0) + { + out.write(result.c_str(), result.length()); + result.clear(); + } + dlen -= n; + ptr += n; + } + + decoder->decode_finish(&result); + if (result.length() > 0) + out.write(result.c_str(), result.length()); + delete decoder; + } + + acl_myfree(pbuf); + out.puts(">---------body end------------<"); + out.close(); + in.close(); +} + +void mime::mime_debug(const char* save_path, bool decode /* = true */) +{ + MIME_STATE* state = m_pMimeState; + // 如果 multipart 格式, 则分析各个部分数据 + MIME_STATE state_dummy; + ACL_ITER iter; + + if (m_pFilePath == NULL) + { + logger_error("m_pFilePath null"); + return; + } + + if (save_path == NULL) + return; + + logger("ctype: %s, stype: %s\r\n", + mime_ctype_name(state->root->ctype), + mime_stype_name(state->root->stype)); + + state_dummy.root = state->root; + mime_state_foreach_init(&state_dummy); + string header_name, header_filename; + + acl_foreach(iter, &state_dummy) + { + MIME_NODE *node = (MIME_NODE*) iter.data; + printf("ctype: %s, stype: %s\r\n", + mime_ctype_name(node->ctype), + mime_stype_name(node->stype)); + if (node->boundary) + printf(">>boundary: %s\r\n", acl_vstring_str(node->boundary)); + if (node->header_filename) + { + header_filename.clear(); + if (rfc2047::decode(node->header_filename, strlen(node->header_filename), + &header_filename, "gbk", true, false) == false) + printf(">>filename: %s\r\n", node->header_filename); + else + printf(">>filename: %s\r\n", header_filename.c_str()); + } + if (node->charset) + printf(">>charset: %s\r\n", node->charset); + if (node->header_name) + { + header_name.clear(); + if (rfc2047::decode(node->header_name, strlen(node->header_name), + &header_name, "gbk", true, false) == false) + printf(">>name: %s\r\n", node->header_name); + else + printf(">>name: %s\r\n", header_name.c_str()); + } + + mime_node_dump(m_pFilePath, save_path, node, decode); + } +} + +} // namespace acl diff --git a/lib_acl_cpp/src/mime/mime_attach.cpp b/lib_acl_cpp/src/mime/mime_attach.cpp new file mode 100644 index 000000000..d2b300a59 --- /dev/null +++ b/lib_acl_cpp/src/mime/mime_attach.cpp @@ -0,0 +1,40 @@ +#include "acl_stdafx.hpp" +#include "internal/mime_state.hpp" +#include "acl_cpp/mime/rfc2047.hpp" +#include "acl_cpp/mime/mime_attach.hpp" + +namespace acl { + +mime_attach::mime_attach(const char* emailFile, const MIME_NODE* node, + bool enableDecode /* = true */, + const char* toCharset /* = "gdb2312" */, + off_t off /* = 0 */) +: mime_node(emailFile, node, enableDecode, toCharset, off) +, m_filename(128) +{ + if (node->header_filename) + { + if (toCharset) + { + rfc2047 rfc; + rfc.decode_update(node->header_filename, + strlen(node->header_filename)); + rfc.decode_finish(toCharset, &m_filename); + } + else + m_filename = node->header_filename; + } +} + +mime_attach::~mime_attach() +{ +} + +const char* mime_attach::get_filename() const +{ + if (m_filename.empty()) + return NULL; + return (m_filename.c_str()); +} + +} // namespace acl diff --git a/lib_acl_cpp/src/mime/mime_base64.cpp b/lib_acl_cpp/src/mime/mime_base64.cpp new file mode 100644 index 000000000..66946deb5 --- /dev/null +++ b/lib_acl_cpp/src/mime/mime_base64.cpp @@ -0,0 +1,58 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/mime/mime_base64.hpp" + +namespace acl { + +static const unsigned char to_b64_tab[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +static const unsigned char un_b64_tab[] = { + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 255, 255, 255, + 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255, + 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 +}; + +mime_base64::mime_base64() +{ + init(to_b64_tab, un_b64_tab, '='); +} + +mime_base64::mime_base64(bool addCrlf, bool addInvalid) + : mime_code(addCrlf, addInvalid) +{ + init(to_b64_tab, un_b64_tab, '='); +} + +mime_base64::~mime_base64() +{ + +} + +void mime_base64::encode(const char* in, int n, acl::string* out) +{ + mime_base64 coder(false, false); + coder.encode_update(in, n, out); + coder.encode_finish(out); +} + +void mime_base64::decode(const char* in, int n, acl::string* out) +{ + mime_base64 decoder(false, false); + decoder.decode_update(in, n, out); + decoder.decode_finish(out); +} + +} // namespace acl diff --git a/lib_acl_cpp/src/mime/mime_body.cpp b/lib_acl_cpp/src/mime/mime_body.cpp new file mode 100644 index 000000000..c91c62c6e --- /dev/null +++ b/lib_acl_cpp/src/mime/mime_body.cpp @@ -0,0 +1,105 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/stdlib/charset_conv.hpp" +#include "acl_cpp/stream/ofstream.hpp" +#include "acl_cpp/stdlib/xml.hpp" +#include "acl_cpp/mime/mime_define.hpp" +#include "acl_cpp/mime/mime_body.hpp" + +namespace acl { + +bool mime_body::save_body(pipe_manager& out, const char* src /* = NULL */, + int len /* = 0 */) +{ + // 是否需要从 HTML 数据中提取出纯文本数据 + + xml* pXml; + if (m_htmlFirst == false && m_ctype == MIME_CTYPE_TEXT + && m_stype == MIME_STYPE_HTML) + { + pXml = NEW xml(); + out.push_front(pXml); + } + else + pXml = NULL; + + // 当需要进行字符集转换时查找字符集转换器 + + charset_conv* conv; + if (m_toCharset[0] != 0) + { + conv = charset_conv::create(m_charset, m_toCharset); + if (conv) + out.push_front(conv); + } + else + conv = NULL; + + bool ret = save(out, src, len); // 调用 mime_node::save + + if (pXml) + delete pXml; + if (conv) + delete conv; + + return (ret); +} + +bool mime_body::save_body(ostream& out, const char* src /* = NULL */, + int len /* = 0 */) +{ + pipe_manager manager; + manager.push_front(&out); + + return (save_body(manager, src, len)); +} + +bool mime_body::save_body(const char* file_path, const char* src /* = NULL */, + int len /* = 0 */) +{ + ofstream out; + + if (out.open_trunc(file_path) == false) + { + logger_error("open file %s error(%s)", + file_path, acl_last_serror()); + return (false); + } + + bool ret = save_body(out, src, len); + if (ret == false) + { +#ifdef WIN32 + _unlink(file_path); +#else + unlink(file_path); +#endif + return (false); + } + return (true); +} + +bool mime_body::save_body(pipe_string& out, const char* src /* = NULL */, + int len /* = 0 */) +{ + pipe_manager manager; + manager.push_front(&out); + return (save_body(manager, src, len)); +} + +bool mime_body::save_body(string& out, const char* src /* = NULL */, + int len /* = 0 */) +{ + pipe_string ps(out); + return (save_body(ps, src, len)); +} + +bool mime_body::html_stype() const +{ + if (m_stype == MIME_STYPE_HTML) + return (true); + else + return (false); +} + +} // namespace acl diff --git a/lib_acl_cpp/src/mime/mime_code.cpp b/lib_acl_cpp/src/mime/mime_code.cpp new file mode 100644 index 000000000..1af244b16 --- /dev/null +++ b/lib_acl_cpp/src/mime/mime_code.cpp @@ -0,0 +1,397 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/mime/mime_define.hpp" +#include "acl_cpp/mime/mime_base64.hpp" +#include "acl_cpp/mime/mime_uucode.hpp" +#include "acl_cpp/mime/mime_xxcode.hpp" +#include "acl_cpp/mime/mime_quoted_printable.hpp" +#include "acl_cpp/mime/mime_code.hpp" + +namespace acl { + +#define INVALID 0xff +#ifndef UCHAR_MAX +#define UCHAR_MAX 0xff +#endif + +mime_code::mime_code() +: m_addCrLf(true) +, m_addInvalid(false) +, m_encoding(false) +, m_toTab(NULL) +, m_unTab(NULL) +, m_fillChar('=') +, m_pBuf(NULL) +{ + reset(); +} + +mime_code::mime_code(bool addCrlf, bool addInvalid) +: m_addCrLf(addCrlf) +, m_addInvalid(addInvalid) +, m_encoding(false) +, m_toTab(NULL) +, m_unTab(NULL) +, m_fillChar('=') +, m_pBuf(NULL) +{ + reset(); +} + +mime_code::~mime_code() +{ + if (m_pBuf) + delete m_pBuf; +} + +void mime_code::init(const unsigned char* toTab, + const unsigned char* unTab, unsigned char fillChar) +{ + m_toTab = toTab; + m_unTab = unTab; + m_fillChar = fillChar; +} + +void mime_code::reset() +{ + m_encodeCnt = 0; + m_decodeCnt = 0; +} + +void mime_code::add_crlf(bool on) +{ + m_addCrLf = on; +} + +void mime_code::add_invalid(bool on) +{ + m_addInvalid = on; +} + +void mime_code::encode_update(const char *src, int n, acl::string* out) +{ + int i = 0; + + while (n > 0) { + if (m_encodeCnt == (int) sizeof(m_encodeBuf)) { + encode(out); + m_encodeCnt = 0; + } + i = n; + if (i > (int) sizeof(m_encodeBuf) - m_encodeCnt) + i = (int) sizeof(m_encodeBuf) - m_encodeCnt; + memcpy(m_encodeBuf + m_encodeCnt, src, i); + m_encodeCnt += i; + src += i; + n -= i; + } +} + +void mime_code::encode_finish(acl::string* out) +{ + encode(out); + m_encodeCnt = 0; +} + +void mime_code::encode(acl::string *out) +{ + const unsigned char *cp; + int count; + + /* + * Encode 3 -> 4. + */ + for (cp = (const unsigned char *) m_encodeBuf, count = m_encodeCnt; + count > 0; count -= 3, cp += 3) + { + out->push_back((char) m_toTab[cp[0] >> 2]); + if (count > 1) { + out->push_back((char) m_toTab[(cp[0] & 0x3) << 4 | cp[1] >> 4]); + if (count > 2) { + out->push_back((char) m_toTab[(cp[1] & 0xf) << 2 | cp[2] >> 6]); + out->push_back((char) m_toTab[cp[2] & 0x3f]); + } else { + out->push_back((char) m_toTab[(cp[1] & 0xf) << 2]); + out->push_back(m_fillChar); + break; + } + } else { + out->push_back((char) m_toTab[(cp[0] & 0x3) << 4]); + out->push_back(m_fillChar); + out->push_back(m_fillChar); + break; + } + } + + if (m_addCrLf) { + out->push_back('\r'); + out->push_back('\n'); + } +} + +void mime_code::decode_update(const char *src, int n, acl::string* out) +{ + int i = 0; + + while (n > 0) { + if (m_decodeCnt == (int) sizeof(m_decodeBuf)) { + decode(out); + } + i = n; + if (i > (int) sizeof(m_decodeBuf) - m_decodeCnt) + i = (int) sizeof(m_decodeBuf) - m_decodeCnt; + memcpy(m_decodeBuf + m_decodeCnt, src, i); + src += i; + n -= i; + m_decodeCnt += i; + } +} + +void mime_code::decode_finish(acl::string* out) +{ + decode(out); + + /* 如果缓冲区内还有数据, 则因其不够4个字节而照原样拷贝 */ + + if (m_addInvalid) + { + if (m_decodeCnt == 1) { + out->push_back(m_decodeBuf[0]); + } else if (m_decodeCnt == 2) { + out->push_back(m_decodeBuf[0]); + out->push_back(m_decodeBuf[1]); + } else if (m_decodeCnt == 3) { + out->push_back(m_decodeBuf[0]); + out->push_back(m_decodeBuf[1]); + out->push_back(m_decodeBuf[2]); + } + } + m_decodeCnt = 0; +} + +void mime_code::decode(acl::string* out) +{ + const unsigned char *cp; + int ch0, ch1, ch2, ch3; + + if (m_decodeCnt <= 0) + return; + + /* 必须缓冲到 4 个字节才开始解析 */ + + for (cp = (const unsigned char *) m_decodeBuf; m_decodeCnt >= 4;) { + + /* 跳过所有的回车换行符及补齐字节 '=' */ + + if (*cp == '\r' || *cp == '\n' || *cp == m_fillChar) { + cp++; + m_decodeCnt--; + continue; + } + + /* 第一个字节 */ + + if ((ch0 = m_unTab[*cp])== INVALID) { + /* 如果非法, 则拷贝原字符 */ + if(m_addInvalid) + out->push_back(*cp); + cp++; + m_decodeCnt--; + continue; + } + cp++; + m_decodeCnt--; + + /* 第二个字节 */ + + if ((ch1 = m_unTab[*cp])== INVALID) { + /* 如果非法, 则拷贝原字符 */ + if (m_addInvalid) + out->push_back((char) (*cp)); + cp++; + m_decodeCnt--; + continue; + } + cp++; + m_decodeCnt--; + + out->push_back((char) (ch0 << 2 | ch1 >> 4)); + + /* 第三个字节 */ + + ch2 = *cp; + if (ch2 == m_fillChar) { + cp++; + m_decodeCnt--; + continue; + } + + if ((ch2 = m_unTab[ch2]) == INVALID) { + /* 如果非法, 则拷贝原字符 */ + if (m_addInvalid) + out->push_back((char) (*cp)); + cp++; + m_decodeCnt--; + continue; + } + cp++; + m_decodeCnt--; + + out->push_back((char) (ch1 << 4 | ch2 >> 2)); + + /* 第四个字节 */ + + ch3 = *cp; + if (ch3 == m_fillChar) { + /* 第三个字节非 '=' 而第四个字节为 '=', + * 则说明第四个字节为补齐用的 + */ + cp++; + m_decodeCnt--; + continue; + } + if ((ch3 = m_unTab[ch3]) == INVALID) { + /* 如果非法, 则拷贝原字符 */ + if (m_addInvalid) + out->push_back((char) (*cp)); + cp++; + m_decodeCnt--; + continue; + } + cp++; + m_decodeCnt--; + + out->push_back((char) (ch2 << 6 | ch3)); + } + + if (m_decodeCnt == 1) { + m_decodeBuf[0] = *cp; + } else if (m_decodeCnt == 2) { + m_decodeBuf[0] = *cp; + m_decodeBuf[1] = *(cp + 1); + } else if (m_decodeCnt == 3) { + m_decodeBuf[0] = *cp; + m_decodeBuf[1] = *(cp + 1); + m_decodeBuf[2] = *(cp + 2); + } +} + +void mime_code::create_decode_tab(const unsigned char *toTab, + acl::string *out) +{ + unsigned char tab[255]; + char buf[32]; + unsigned char *cp; + int i, n = (int) strlen((const char*) toTab); + + memset(tab, 0xff, sizeof(tab)); + + for (i = 0; i < n; i++) { + tab[toTab[i]] = (unsigned char) i; + } + + out->clear(); + for (i = 0, cp = tab; cp < tab + sizeof(tab); cp++) { + if (i++ % 16 == 0) { + out->append("\r\n"); + } + snprintf(buf, sizeof(buf), "%d, ", *cp); + out->append((char*) buf); + } +} + +void mime_code::set_status(bool encoding) +{ + m_encoding = encoding; +} + +int mime_code::push_pop(const char* in, size_t len, + string* out, size_t max /* = 0 */) +{ + if (m_pBuf == NULL) + m_pBuf = NEW acl::string(1024); + + if (in && len > 0) + { + if (m_encoding) + encode_update(in, len, m_pBuf); + else + decode_update(in, len, m_pBuf); + } + + if (out == NULL) + return (0); + + len = m_pBuf->length(); + if (len == 0) + return (0); + + size_t n; + if (max > 0) + n = max > len ? len : max; + else + n = len; + + out->append(m_pBuf->c_str(), n); + + if (len > n) + m_pBuf->memmove(m_pBuf->c_str() + n, len - n); + else + m_pBuf->clear(); + + return (n); +} + +int mime_code::pop_end(acl::string* out, size_t max /* = 0 */) +{ + if (m_pBuf == NULL) + { + logger_error("call push_pop first"); + return (-1); + } + if (m_encoding) + encode_finish(m_pBuf); + else + decode_finish(m_pBuf); + + if (out == NULL) + { + m_pBuf->clear(); + return (0); + } + + size_t n = m_pBuf->length(); + if (n == 0) + return (0); + if (max > 0 && n > max) + n = max; + out->append(m_pBuf->c_str(), n); + m_pBuf->clear(); + return (n); +} + +void mime_code::clear() +{ + if (m_pBuf) + m_pBuf->clear(); +} + +mime_code* mime_code::create(int encoding, bool warn_unsupport /* = true */) +{ + if(encoding == MIME_ENC_BASE64) + return (NEW acl::mime_base64()); + else if (encoding == MIME_ENC_UUCODE) + return (NEW acl::mime_uucode()); + else if (encoding == MIME_ENC_XXCODE) + return (NEW acl::mime_xxcode()); + else if (encoding == MIME_ENC_QP) + return (NEW acl::mime_quoted_printable()); + else + { + if (warn_unsupport) + logger_warn("unknown encoding(%d)", encoding); + return (NULL); + } +} + +} // namespace acl diff --git a/lib_acl_cpp/src/mime/mime_head.cpp b/lib_acl_cpp/src/mime/mime_head.cpp new file mode 100644 index 000000000..6d60268cf --- /dev/null +++ b/lib_acl_cpp/src/mime/mime_head.cpp @@ -0,0 +1,381 @@ +#include "acl_stdafx.hpp" +#include "internal/mime_state.hpp" +#include "acl_cpp/stdlib/string.hpp" +#include "acl_cpp/mime/rfc822.hpp" +#include "acl_cpp/mime/mime_head.hpp" + +namespace acl { + +const static acl::string __dummy; +const static std::list __dummyList; +const static std::list __dummyHeaderList; + +mime_head::mime_head() +{ + m_rcpts = NULL; + m_tos = NULL; + m_ccs = NULL; + m_bccs = NULL; + m_headers = NULL; + m_sender = NULL; + m_from = NULL; + m_replyto = NULL; + m_returnpath = NULL; + m_subject = NULL; + m_boundary = NULL; + m_ctype = MIME_CTYPE_OTHER; + m_stype = MIME_STYPE_OTHER; +} + +mime_head::~mime_head() +{ + reset(); +} + +mime_head& mime_head::reset() +{ + if (m_sender) { + delete m_sender; + m_sender = NULL; + } + if (m_from) { + delete m_from; + m_from = NULL; + } + if (m_replyto) { + delete m_replyto; + m_replyto = NULL; + } + if (m_returnpath) { + delete m_returnpath; + m_returnpath = NULL; + } + if (m_subject) { + delete m_subject; + m_subject = NULL; + } + + std::list::iterator it; + + if (m_rcpts) { + for (it = m_rcpts->begin(); it != m_rcpts->end(); ++it) { + acl_myfree(*it); + } + delete m_rcpts; + m_rcpts = NULL; + } + + if (m_tos) { + for (it = m_tos->begin(); it != m_tos->end(); ++it) { + acl_myfree(*it); + } + delete m_tos; + m_tos = NULL; + } + + if (m_ccs) { + for (it = m_ccs->begin(); it != m_ccs->end(); ++it) { + acl_myfree(*it); + } + delete m_ccs; + m_ccs = NULL; + } + + if (m_bccs) { + for (it = m_bccs->begin(); it != m_bccs->end(); ++it) { + acl_myfree(*it); + } + delete m_bccs; + m_bccs = NULL; + } + + if (m_headers) { + std::list::iterator it1 = m_headers->begin(); + for (; it1 != m_headers->end(); ++it1) { + acl_myfree((*it1)->name); + acl_myfree((*it1)->value); + acl_myfree((*it1)); + } + delete m_headers; + m_headers = NULL; + } + + if (m_boundary) { + delete m_boundary; + m_boundary = NULL; + } + + return (*this); +} + +const char* mime_head::get_ctype() const +{ + return mime_ctype_name(m_ctype); +} + +const char* mime_head::get_stype() const +{ + return mime_stype_name(m_stype); +} + +const acl::string& mime_head::sender() const +{ + return (m_sender ? *m_sender : __dummy); +} + +const acl::string& mime_head::from() const +{ + return (m_from ? *m_from : __dummy); +} + +const acl::string& mime_head::replyto() const +{ + return (m_replyto ? *m_replyto : __dummy); +} + +const acl::string& mime_head::returnpath() const +{ + return (m_returnpath ? *m_returnpath : __dummy); +} + +const acl::string& mime_head::subject() const +{ + return (m_subject ? *m_subject : __dummy); +} + +const std::list& mime_head::to_list() const +{ + return (m_tos ? (*m_tos) : __dummyList); +} + +const std::list& mime_head::cc_list() const +{ + return (m_ccs ? (*m_ccs) : __dummyList); +} + +const std::list& mime_head::bcc_list() const +{ + return (m_bccs ? (*m_bccs) : __dummyList); +} + +const std::list& mime_head::rcpt_list() const +{ + return (m_rcpts ? (*m_rcpts) : __dummyList); +} + +const std::list& mime_head::header_list() const +{ + if (m_headers) + return (*m_headers); + return (__dummyHeaderList); +} + +const char* mime_head::header_value(const char* name) const +{ + if (m_headers == NULL) + return (NULL); + std::list::const_iterator cit = m_headers->begin(); + for (; cit != m_headers->end(); ++cit) + { + if (strcasecmp((*cit)->name, name) == 0) + return ((*cit)->value); + } + + return (NULL); +} + +int mime_head::header_values(const char* name, std::list* values) const +{ + if (m_headers == NULL) + return (0); + + int n = 0; + std::list::const_iterator cit = m_headers->begin(); + for (; cit != m_headers->end(); ++cit) + { + if (strcasecmp((*cit)->name, name) == 0) + { + values->push_back((*cit)->value); + n++; + } + } + return (n); +} + +mime_head& mime_head::set_sender(const char* addr) +{ + if (m_sender) + *m_sender = addr; + else + m_sender = NEW acl::string(addr); + return (*this); +} + +mime_head& mime_head::set_from(const char* addr) +{ + if (m_from) + *m_from = addr; + else + m_from = NEW acl::string(addr); + return (*this); +} + +mime_head& mime_head::set_replyto(const char* addr) +{ + if (m_replyto) + *m_replyto = addr; + else + m_replyto = NEW acl::string(addr); + return (*this); +} + +mime_head& mime_head::set_returnpath(const char* addr) +{ + if (m_returnpath) + *m_returnpath = addr; + else + m_returnpath = NEW acl::string(addr); + return (*this); +} + +mime_head& mime_head::set_subject(const char* s) +{ + if (m_subject) + *m_subject = s; + else + m_subject = NEW acl::string(s); + return (*this); +} + +mime_head& mime_head::add_to(const char* addr) +{ + if (m_tos == NULL) + m_tos = NEW std::list; + m_tos->push_back(acl_mystrdup(addr)); + add_rcpt(addr); + return (*this); +} + +mime_head& mime_head::add_cc(const char* addr) +{ + if (m_ccs == NULL) + m_ccs = NEW std::list; + m_ccs->push_back(acl_mystrdup(addr)); + add_rcpt(addr); + return (*this); +} + +mime_head& mime_head::add_bcc(const char* addr) +{ + if (m_bccs == NULL) + m_bccs = NEW std::list; + m_bccs->push_back(acl_mystrdup(addr)); + add_rcpt(addr); + return (*this); +} + +mime_head& mime_head::add_rcpt(const char* addr) +{ + if (m_rcpts == NULL) + m_rcpts = NEW std::list; + m_rcpts->push_back(acl_mystrdup(addr)); + return (*this); +} + +mime_head& mime_head::add_header(const char* name, const char* value) +{ + if (m_headers == NULL) + m_headers = NEW std::list; + HEADER *header = (HEADER*) acl_mycalloc(1, sizeof(HEADER)); + header->name = acl_mystrdup(name); + header->value = acl_mystrdup(value); + m_headers->push_back(header); + return (*this); +} + +mime_head& mime_head::set_type(size_t ctype, size_t stype) +{ + m_ctype = ctype; + m_stype = stype; + return (*this); +} + +mime_head& mime_head::set_boundary(const char* s) +{ + if (m_boundary == NULL) + m_boundary = NEW acl::string(s); + else + *m_boundary = s; + return (*this); +} + +const acl::string& mime_head::get_boundary() const +{ + if (m_boundary) + return (*m_boundary); + else + return (__dummy); +} + +static void append_recipients(string& out, const char* tagname, + const std::list& recipients) +{ + if (recipients.empty()) + return; + std::list::const_iterator cit = recipients.begin(); + out.format_append("%s: %s", tagname, *cit); + ++cit; + if (cit == recipients.end()) + { + out.append("\r\n"); + return; + } + for (; cit != recipients.end(); ++cit) + out.format_append(",\r\n %s", *cit); + out.append("\r\n"); +} + +void mime_head::build_head(string& out, bool clean) +{ + if (clean) + out.clear(); + if (m_headers) + { + std::list::const_iterator cit = m_headers->begin(); + for (; cit != m_headers->end(); ++cit) + { + out.format_append("%s: %s\r\n", + (*cit)->name, (*cit)->value); + } + } + char buf[64]; + rfc822 rfc; + rfc.mkdate_cst(time(NULL), buf, sizeof(buf)); + out.format_append("Date: %s\r\n", buf); + + if (m_from) + out.format_append("From: %s\r\n", m_from->c_str()); + if (m_replyto) + out.format_append("Reply-To: %s\r\n", m_replyto->c_str()); + if (m_returnpath) + out.format_append("Return-Path: %s\r\n", m_returnpath->c_str()); + if (m_tos) + append_recipients(out, "To", *m_tos); + if (m_ccs) + append_recipients(out, "Cc", *m_ccs); + if (m_bccs) + append_recipients(out, "Bcc", *m_bccs); + if (m_subject) + out.format_append("Subject: %s\r\n", m_subject->c_str()); + out.append("MIME-Version: 1.0\r\n"); + out.format_append("Content-Type: %s/%s", get_ctype(), get_stype()); + if (m_boundary) + out.format_append(";\r\n\tboundary=\"%s\"\r\n", + m_boundary->c_str()); + else + out.append("\r\n"); + + out.append("\r\n"); +} + +} // namespace acl diff --git a/lib_acl_cpp/src/mime/mime_image.cpp b/lib_acl_cpp/src/mime/mime_image.cpp new file mode 100644 index 000000000..606be9691 --- /dev/null +++ b/lib_acl_cpp/src/mime/mime_image.cpp @@ -0,0 +1,11 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/mime/mime_image.hpp" + +namespace acl { + +const char* mime_image::get_location() const +{ + return (header_value("Content-Location")); +} + +} // namespace acl diff --git a/lib_acl_cpp/src/mime/mime_node.cpp b/lib_acl_cpp/src/mime/mime_node.cpp new file mode 100644 index 000000000..7ec460755 --- /dev/null +++ b/lib_acl_cpp/src/mime/mime_node.cpp @@ -0,0 +1,302 @@ +#include "acl_stdafx.hpp" +#include "internal/header_opts.hpp" +#include "internal/mime_state.hpp" +#include "acl_cpp/stdlib/pipe_stream.hpp" +#include "acl_cpp/mime/mime_define.hpp" +#include "acl_cpp/mime/rfc2047.hpp" +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/stream/ifstream.hpp" +#include "acl_cpp/stream/ofstream.hpp" +#include "acl_cpp/mime/mime_code.hpp" +#include "acl_cpp/mime/mime_node.hpp" + +#define SCOPY(x, y) ACL_SAFE_STRNCPY((x), (y), sizeof((x))) + +namespace acl { + +mime_node::mime_node(const char* emailFile, const MIME_NODE* node, + bool enableDecode /* = true */, + const char* toCharset /* = "gb2312" */, + off_t off /* = 0 */) + : m_name(128) + , m_pParent(NULL) +{ + m_pMimeNode = node; + + if (emailFile) + m_emailFile = emailFile; + m_enableDecode = enableDecode; + if (toCharset) + SCOPY(m_toCharset, toCharset); + else + m_toCharset[0] = 0; + + if (node->header_name) + { + if (toCharset) + { + rfc2047 rfc; + rfc.decode_update(node->header_name, + strlen(node->header_name)); + rfc.decode_finish(toCharset, &m_name); + } + else + m_name = node->header_name; + } + + m_ctype = node->ctype; + m_stype = node->stype; + m_encoding = node->encoding; + if (node->charset) + SCOPY(m_charset, node->charset); + else + m_charset[0] = 0; + m_bodyBegin = node->body_begin + off; + m_bodyEnd = node->body_data_end + off; +} + +mime_node::~mime_node() +{ + if (m_pParent) + delete m_pParent; +} + +const char* mime_node::header_value(const char* name) const +{ + ACL_ITER iter; + + acl_foreach(iter, m_pMimeNode->header_list) + { + HEADER_NV* hdr = (HEADER_NV*) iter.data; + if (strcasecmp(hdr->name, name) == 0 && *hdr->value) + return (hdr->value); + } + + return (NULL); +} + +bool mime_node::save(pipe_manager& out) const +{ + if (m_emailFile.empty()) + { + logger_error("m_emailFile empty!"); + return (false); + } + + ifstream in ; + if (in.open_read(m_emailFile) == false) + { + logger_error("open input file %s error(%s)", + m_emailFile.c_str(), acl_last_serror()); + return (false); + } + + if (m_bodyBegin < 0 || m_bodyEnd <= m_bodyBegin) + return (true); + + if (in.fseek(m_bodyBegin, SEEK_SET) < 0) + { + logger_error("fseek error(%s)", acl_last_serror()); + return (false); + } + + // 当需要解码时查找匹配的解码器 + + mime_code* mime_decoder; + if (m_enableDecode) + { + mime_decoder = mime_code::create(m_encoding, false); + if (mime_decoder) + { + mime_decoder->set_status(false); + out.push_front(mime_decoder); + } + } + else + mime_decoder = NULL; + + char buf[8192]; + size_t size; + int len = m_bodyEnd - m_bodyBegin; + + int ret; + while (len > 0) + { + size = sizeof(buf) > (size_t) len + ? (size_t) len : sizeof(buf); + ret = in.read(buf, size, true); + if (ret < 0) + { + logger_error("read error(%s), ret: %d", + acl_last_serror(), ret); + if (mime_decoder) + delete mime_decoder; + return (false); + } + + if (out.update(buf, ret) == false) + { + if (mime_decoder) + delete mime_decoder; + return (false); + } + len -= ret; + } + + bool result = out.update_end(); + + if (mime_decoder) + delete mime_decoder; + return (result); +} + +bool mime_node::save(pipe_manager& out, const char* src, int len) const +{ + if (src == NULL || len <= 0) + return (save(out)); + + if (m_bodyBegin < 0 || m_bodyEnd <= m_bodyBegin) + return (true); + else if (len < m_bodyEnd) + return (true); + + // 当需要解码时查找匹配的解码器 + + mime_code* mime_decoder; + if (m_enableDecode) + { + mime_decoder = mime_code::create(m_encoding, false); + if (mime_decoder) + { + mime_decoder->set_status(false); + out.push_front(mime_decoder); + } + } + else + mime_decoder = NULL; + + size_t n = m_bodyEnd - m_bodyBegin; + if (out.update(src + m_bodyBegin, n) == false) + { + if (mime_decoder) + delete mime_decoder; + return (false); + } + + bool result = out.update_end(); + + if (mime_decoder) + delete mime_decoder; + return (result); +} + +bool mime_node::save(ostream& out, const char* src /* = NULL */, + int len /* = 0 */) const +{ + pipe_manager manager; + manager.push_front(&out); + return (save(manager, src, len)); +} + +bool mime_node::save(const char* outFile, const char* src /* = NULL */, + int len /* = 0 */) const +{ + ofstream out; + + if (out.open_trunc(outFile) == false) + { + logger_error("open %s error(%s)", + outFile, acl_last_serror()); + return (false); + } + return (save(out, src, len)); +} + +bool mime_node::save(string& out, const char* src /* = NULL */, + int len /* = 0 */) const +{ + pipe_manager manager; + pipe_string ps(out); + manager.push_front(&ps); + return (save(manager, src, len)); +} + +mime_node* mime_node::get_parent() const +{ + if (m_pParent) + return (m_pParent); + + const MIME_NODE* node = m_pMimeNode->parent; + if (node == NULL) + return (NULL); + const_cast(this)->m_pParent = + NEW mime_node(m_emailFile.c_str(), + node, m_enableDecode, m_toCharset); + return (m_pParent); +} + +bool mime_node::has_parent() const +{ + return (m_pMimeNode->parent == NULL ? false : true); +} + +int mime_node::parent_ctype() const +{ + if (m_pMimeNode->parent == NULL) + return (MIME_CTYPE_OTHER); + return (m_pMimeNode->parent->ctype); +} + +int mime_node::parent_stype() const +{ + if (m_pMimeNode->parent == NULL) + return (MIME_STYPE_OTHER); + return (m_pMimeNode->parent->stype); +} + +int mime_node::parent_encoding() const +{ + if (m_pMimeNode->parent == NULL) + return (MIME_ENC_OTHER); + return (m_pMimeNode->parent->encoding); +} + +char* mime_node::parent_charset() const +{ + if (m_pMimeNode->parent == NULL) + return (NULL); + return (m_pMimeNode->parent->charset); +} + +off_t mime_node::parent_bodyBegin() const +{ + if (m_pMimeNode->parent == NULL) + return (-1); + return (m_pMimeNode->parent->body_begin); +} + +off_t mime_node::parent_bodyEnd() const +{ + if (m_pMimeNode->parent == NULL) + return (-1); + return (m_pMimeNode->parent->body_end); +} + +const char* mime_node::parent_header_value(const char* name) const +{ + if (m_pMimeNode->parent == NULL) + return (NULL); + + ACL_ITER iter; + + acl_foreach(iter, m_pMimeNode->parent->header_list) + { + HEADER_NV* hdr = (HEADER_NV*) iter.data; + if (strcasecmp(hdr->name, name) == 0 && *hdr->value) + return (hdr->value); + } + + return (NULL); +} + +} // namespace acl diff --git a/lib_acl_cpp/src/mime/mime_quoted_printable.cpp b/lib_acl_cpp/src/mime/mime_quoted_printable.cpp new file mode 100644 index 000000000..2e41717a9 --- /dev/null +++ b/lib_acl_cpp/src/mime/mime_quoted_printable.cpp @@ -0,0 +1,286 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/mime/mime_quoted_printable.hpp" + +namespace acl { + +#define CU_CHAR_PTR(x) ((const unsigned char *) (x)) + +mime_quoted_printable::mime_quoted_printable() +{ + m_addCrLf = true; + m_addInvalid = false; + reset(); +} + +mime_quoted_printable::mime_quoted_printable(bool addCrlf, bool addInvalid) +{ + m_addCrLf = addCrlf; + m_addInvalid = addInvalid; + reset(); +} + +mime_quoted_printable::~mime_quoted_printable() +{ + +} + +void mime_quoted_printable::reset() +{ + m_encodeCnt = 0; + m_decodeCnt = 0; +} + +void mime_quoted_printable::add_crlf(bool on) +{ + m_addCrLf = on; +} + +void mime_quoted_printable::add_invalid(bool on) +{ + m_addInvalid = on; +} + +void mime_quoted_printable::encode_update(const char *src, int n, acl::string* out) +{ + int i = 0; + + while (n > 0) { + if (m_encodeCnt == (int) sizeof(m_encodeBuf)) + encode(out); + i = n; + if (i > (int) sizeof(m_encodeBuf) - m_encodeCnt) + i = (int) sizeof(m_encodeBuf) - m_encodeCnt; + memcpy(m_encodeBuf + m_encodeCnt, src, i); + m_encodeCnt += i; + src += i; + n -= i; + } +} + +static char hexchars[] = "0123456789ABCDEF"; + +#define QP_ENCODE(buffer, ch) { \ + (buffer)->push_back('='); \ + (buffer)->push_back((char) hexchars[((ch) >> 4) & 0xff]); \ + (buffer)->push_back((char) hexchars[(ch) & 0xf]); \ +} +#define QP_SOFT_LINE(buffer) { \ + (buffer)->push_back('='); \ + (buffer)->push_back('\r'); \ + (buffer)->push_back('\n'); \ +} + +void mime_quoted_printable::encode_finish(acl::string* out) +{ + encode(out); + if (m_encodeCnt == 1) + QP_ENCODE(out, m_encodeBuf[0]); + m_encodeCnt = 0; +} + +void mime_quoted_printable::encode(const char* in, int n, acl::string* out) +{ + mime_quoted_printable coder(false, false); + coder.encode_update(in, n, out); + coder.encode_finish(out); +} + +void mime_quoted_printable::decode(const char* in, int n, acl::string* out) +{ + mime_quoted_printable decoder(false, false); + decoder.decode_update(in, n, out); + decoder.decode_finish(out); +} + +void mime_quoted_printable::encode(acl::string* out) +{ + const unsigned char *cp; + const unsigned char *end = CU_CHAR_PTR(m_encodeBuf + m_encodeCnt); + int n; + + /* + * Insert a soft line break when the output reaches + * a critical length before we reach a hard line break. + */ + for (cp = CU_CHAR_PTR(m_encodeBuf), n = 0; cp < end; cp++) { + if (*cp == ' ' || *cp == '\t') { + if (cp + 1 == end) { + /* 无法确定后面字节是否是回车换行, + * 所以暂时缓存该数据 + */ + m_encodeBuf[0] = *cp; + m_encodeCnt = 1; + break; + } + if (*(cp + 1) == '\r' || *(cp + 1) == '\n') { + QP_ENCODE(out, *cp); + n += 3; + } else { + out->push_back((char) (*cp)); + n++; + } + } else if (*cp == '\r' || *cp == '\n') { + out->push_back((char) (*cp)); + n = 0; + } else if (*cp < 32 || *cp == '=' || *cp > 126) { + QP_ENCODE(out, *cp); + n += 3; + } else { + out->push_back((char) (*cp)); + n++; + } + + m_encodeCnt--; + + /* Critical length before hard line break. */ + if (n >= 72 && m_addCrLf) { + QP_SOFT_LINE(out); + n = 0; + } + } +} + +#if 0 +static int Index_hex[128] = { + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1, -1,-1,-1,-1, + -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1 +}; + +#define hexval(c) Index_hex[(unsigned char)(c)] +#define INVALID -1 +#endif + +void mime_quoted_printable::decode_update(const char *src, + int n, acl::string* out) +{ + int i = 0; + + while (n > 0) { + if (m_decodeCnt == (int) sizeof(m_decodeBuf)) { + decode(out); + } + i = n; + if (i > (int) sizeof(m_decodeBuf) - m_decodeCnt) + i = (int) sizeof(m_decodeBuf) - m_decodeCnt; + memcpy(m_decodeBuf + m_decodeCnt, src, i); + src += i; + n -= i; + m_decodeCnt += i; + } +} + +void mime_quoted_printable::decode_finish(acl::string* out) +{ + decode(out); + if (m_addInvalid) + { + if (m_decodeCnt == 1) + out->push_back(m_decodeBuf[0]); + else if (m_decodeCnt == 2) { + out->push_back(m_decodeBuf[0]); + out->push_back(m_decodeBuf[1]); + } + } + m_decodeCnt = 0; +} + +bool mime_quoted_printable::hex_decode(unsigned char first, + unsigned char second, unsigned int *result) +{ + unsigned int hex; + unsigned int bin; + + hex = first; + if (hex >= '0' && hex <= '9') + bin = (hex - '0') << 4; + else if (hex >= 'A' && hex <= 'F') + bin = (hex - 'A' + 10) << 4; + else if (hex >= 'a' && hex <= 'f') + bin = (hex - 'a' + 10) << 4; + else + return (false); + hex = second; + if (hex >= '0' && hex <= '9') + bin |= (hex - '0') ; + else if (hex >= 'A' && hex <= 'F') + bin |= (hex - 'A' + 10) ; + else if (hex >= 'a' && hex <= 'f') + bin |= (hex - 'a' + 10) ; + else + return (false); + *result = bin; + return (true); +} + +void mime_quoted_printable::decode(acl::string* out) +{ + const unsigned char *cp; + const unsigned char *end = CU_CHAR_PTR(m_decodeBuf + m_decodeCnt); + unsigned char first, second; + unsigned int result; + +//#define IS_CRLF(x) ((x) == '\r' || (x) == '\n') + + for (cp = CU_CHAR_PTR(m_decodeBuf); cp < end;) { + if (*cp != '=') { + out->push_back((char) (*cp)); + m_decodeCnt--; + cp++; + continue; + } + + /* '=' 后面需要有两个字节才可操作 */ + if (m_decodeCnt == 1) { + m_decodeBuf[0] = *cp; + m_decodeCnt = 1; + break; + } else if (m_decodeCnt == 2) { + m_decodeBuf[0] = *cp; + m_decodeBuf[1] = *(cp + 1); + m_decodeCnt = 2; + break; + } + + if (*(cp + 1) == '\r') { + if (*(cp + 2) == '\n') { + /* 去掉软回车换行 */ + cp += 3; + m_decodeCnt -= 3; + } else { + if (m_addInvalid) { + /* xxx: 将非法数据原样照搬 */ + out->push_back((char) (*(cp + 1))); + out->push_back((char) (*(cp + 2))); + } + cp += 3; + m_decodeCnt -= 3; + } + } else if (*(cp + 1) == '\n') { + /* xxx: unix 格式的软换行 ? */ + cp += 2; + m_decodeCnt -= 2; + } else { + first = *(cp + 1); + second = *(cp + 2); + m_decodeCnt -= 3; + cp += 3; + if (hex_decode(first, second, &result)) { + out->push_back((char) result); + } else { + if (m_addInvalid) { + /* 将非法数据原样照搬 */ + out->push_back((char) first); + out->push_back((char) second); + } + } + } + } +} + +} // namespace acl diff --git a/lib_acl_cpp/src/mime/mime_uucode.cpp b/lib_acl_cpp/src/mime/mime_uucode.cpp new file mode 100644 index 000000000..547c32e5d --- /dev/null +++ b/lib_acl_cpp/src/mime/mime_uucode.cpp @@ -0,0 +1,58 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/mime/mime_uucode.hpp" + +namespace acl { + +static const unsigned char to_uucode_tab[] = + "`!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"; + +static const unsigned char un_uucode_tab[] = { + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 +}; + +mime_uucode::mime_uucode() +{ + init(to_uucode_tab, un_uucode_tab, '~'); +} + +mime_uucode::mime_uucode(bool addCrlf, bool addInvalid) + : mime_code(addCrlf, addInvalid) +{ + init(to_uucode_tab, un_uucode_tab, '~'); +} + +mime_uucode::~mime_uucode() +{ + +} + +void mime_uucode::encode(const char* in, int n, acl::string* out) +{ + mime_uucode coder(false, false); + coder.encode_update(in, n, out); + coder.encode_finish(out); +} + +void mime_uucode::decode(const char* in, int n, acl::string* out) +{ + mime_uucode decoder(false, false); + decoder.decode_update(in, n, out); + decoder.decode_finish(out); +} + +} // namespace acl diff --git a/lib_acl_cpp/src/mime/mime_xxcode.cpp b/lib_acl_cpp/src/mime/mime_xxcode.cpp new file mode 100644 index 000000000..bde5913d8 --- /dev/null +++ b/lib_acl_cpp/src/mime/mime_xxcode.cpp @@ -0,0 +1,58 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/mime/mime_xxcode.hpp" + +namespace acl { + +static const unsigned char to_xx_tab[] = + "+-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +static const unsigned char un_xx_tab[] = { + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 255, 1, 255, 255, + 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 255, 255, 255, 255, 255, 255, + 255, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 255, 255, 255, 255, 255, + 255, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 +}; + +mime_xxcode::mime_xxcode() +{ + init(to_xx_tab, un_xx_tab, '~'); +} + +mime_xxcode::mime_xxcode(bool addCrlf, bool addInvalid) + : mime_code(addCrlf, addInvalid) +{ + init(to_xx_tab, un_xx_tab, '~'); +} + +mime_xxcode::~mime_xxcode() +{ + +} + +void mime_xxcode::encode(const char* in, int n, acl::string* out) +{ + mime_xxcode coder(false, false); + coder.encode_update(in, n, out); + coder.encode_finish(out); +} + +void mime_xxcode::decode(const char* in, int n, acl::string* out) +{ + mime_xxcode decoder(false, false); + decoder.decode_update(in, n, out); + decoder.decode_finish(out); +} + +} // namespace acl diff --git a/lib_acl_cpp/src/mime/rfc2047.cpp b/lib_acl_cpp/src/mime/rfc2047.cpp new file mode 100644 index 000000000..3083f1037 --- /dev/null +++ b/lib_acl_cpp/src/mime/rfc2047.cpp @@ -0,0 +1,571 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/mime/mime_base64.hpp" +#include "acl_cpp/mime/mime_quoted_printable.hpp" +#include "acl_cpp/stdlib/charset_conv.hpp" +#include "acl_cpp/mime/rfc2047.hpp" + +#define SCOPY(x, y) ACL_SAFE_STRNCPY((x), (y), sizeof(x)) + +namespace acl { + +enum +{ + rfc2047_status_next, + rfc2047_status_data, + rfc2047_status_equal_question, + rfc2047_status_charset, + rfc2047_status_question_first, + rfc2047_status_coding, + rfc2047_status_question_second, + rfc2047_status_question_equal +}; + +rfc2047::rfc2047(bool strip_sp /* false */, bool addCrlf /* true */) + : m_pCurrentEntry(NULL) + , m_coder(NULL) + , m_status(rfc2047_status_next) + , m_stripSp(strip_sp) + , m_addCrlf(addCrlf) + , m_lastCh(0) +{ + +} + +rfc2047::~rfc2047() +{ + reset(); + if (m_coder) + delete m_coder; +} + +void rfc2047::reset(bool strip_sp /* false */) +{ + std::list::iterator it, lt; + + it = lt = m_List.begin(); + for (; it != m_List.end(); it = lt) + { + lt++; + delete (*it)->pData; + delete (*it)->pCharset; + delete (*it); + m_List.pop_front(); + } + m_pCurrentEntry = NULL; + m_status = rfc2047_status_next; + m_lastCh = 0; + m_stripSp = strip_sp; + if (m_coder) + { + delete m_coder; + m_coder = NULL; + } +} + +const std::list& rfc2047::get_list() const +{ + return (m_List); +} + +void rfc2047::debug_rfc2047() const +{ + std::list::const_iterator cit = m_List.begin(); + for (; cit != m_List.end(); ++cit) + { + printf(">>> debug_rfc2047: charset: %s, code: %c, data: %s\n", + (*cit)->pCharset->c_str(), + (*cit)->coding, + (*cit)->pData->c_str()); + } +} + +#define SKIP(s, n) \ +{ \ + if (n > 0 && *s == '\r') \ + { \ + m_lastCh = *s++; \ + n--; \ + } \ + if (n > 0 && *s == '\n') \ + { \ + m_lastCh = *s++; \ + n--; \ + } \ + if (m_lastCh == 0 || m_lastCh == '\n') \ + { \ + while (n > 0 && ((m_lastCh = *s) == ' ' || m_lastCh == '\t')) \ + { \ + s++; \ + n--; \ + } \ + } \ +} + +int rfc2047::status_next(const char* s, int n) +{ + if (m_stripSp) + SKIP(s, n); + if (n <= 0) + return (n); + + rfc2047_entry* entry = NEW rfc2047_entry; + m_pCurrentEntry = entry; + + entry->pData = NEW acl::string(128); + entry->pCharset = NEW acl::string(32); + entry->coding = 0; + + m_List.push_back(entry); + if (*s == '=') + { + m_status = rfc2047_status_equal_question; + return (n - 1); + } + m_status = rfc2047_status_data; + *m_pCurrentEntry->pData << *s; + return (n - 1); +} + +int rfc2047::status_data(const char* s, int n) +{ + if (m_stripSp) + SKIP(s, n); + if (n <= 0) + return (n); + while (n > 0) + { + if (m_stripSp) + SKIP(s, n); + if (n <= 0) + break; + + if (m_pCurrentEntry->coding > 0) + { + if (*s == '?') + { + m_status = rfc2047_status_question_equal; + n--; + break; + } + *m_pCurrentEntry->pData << *s; + s++; + n--; + continue; + } + + if (*s == '=') + { + m_status = rfc2047_status_next; + break; + } + else + { + *m_pCurrentEntry->pData << *s; + s++; + n--; + } + } + return (n); +} + +int rfc2047::status_equal_question(const char* s, int n) +{ + if (m_stripSp) + SKIP(s, n); + if (n <= 0) + return (n); + if (*s == '?') + { + m_status = rfc2047_status_charset; + return (n - 1); + } + m_status = rfc2047_status_data; + *m_pCurrentEntry->pData << '='; + *m_pCurrentEntry->pData << *s; + return (n - 1); +} + +int rfc2047::status_charset(const char* s, int n) +{ + if (m_stripSp) + SKIP(s, n); + if (n <= 0) + return (n); + if (*s == '?') + { + if (m_pCurrentEntry->pCharset->length() == 0) + { + *m_pCurrentEntry->pData = "=??"; + m_status = rfc2047_status_data; + return (n - 1); + } + m_status = rfc2047_status_question_first; + return (n - 1); + } + *m_pCurrentEntry->pCharset << *s; + return (n - 1); +} + +int rfc2047::status_question_first(const char* s, int n) +{ + if (m_stripSp) + SKIP(s, n); + if (n <= 0) + return (n); + m_status = rfc2047_status_coding; + return (n); +} + +int rfc2047::status_coding(const char* s, int n) +{ + if (m_stripSp) + SKIP(s, n); + if (n <= 0) + return (n); + if (*s == 'B' || *s == 'b') + { + m_pCurrentEntry->coding = 'B'; + m_status = rfc2047_status_question_second; + return (n - 1); + } + else if (*s == 'Q' || *s == 'q') + { + m_pCurrentEntry->coding = 'Q'; + m_status = rfc2047_status_question_second; + return (n - 1); + } + + *m_pCurrentEntry->pData << "=?" + << m_pCurrentEntry->pCharset->c_str() + << "?"; + m_pCurrentEntry->pCharset->clear(); + m_pCurrentEntry->coding = 0; + return (n - 1); +} + +int rfc2047::status_question_second(const char* s, int n) +{ + if (m_stripSp) + SKIP(s, n); + if (n <= 0) + return (n); + if (*s == '?') + { + m_status = rfc2047_status_data; + return (n - 1); + } + + *m_pCurrentEntry->pData << "=?" + << m_pCurrentEntry->pCharset->c_str(); + m_pCurrentEntry->pCharset->clear(); + *m_pCurrentEntry->pData << *s; + m_pCurrentEntry->coding = 0; + m_status = rfc2047_status_data; + return (n - 1); +} + +int rfc2047::status_question_equal(const char* s, int n) +{ + if (m_stripSp) + SKIP(s, n); + if (n <= 0) + return (n); + if (*s == '=') + { + m_status = rfc2047_status_next; + m_pCurrentEntry = NULL; + return (n - 1); + } + + size_t size = m_pCurrentEntry->pCharset->length() + + m_pCurrentEntry->pData->length() + + strlen("=???") + 1; + acl::string* pBuf = NEW acl::string(size); + + *pBuf << "=?" << m_pCurrentEntry->pCharset->c_str() + << "?" << m_pCurrentEntry->coding << "?" + << m_pCurrentEntry->pData->c_str() << "?" + << *s; + delete m_pCurrentEntry->pData; + m_pCurrentEntry->pData = pBuf; + m_status = rfc2047_status_data; + return (n - 1); +} + +struct rfc2047_status_matchine +{ + int status; + int (rfc2047::*func)(const char*, int); +}; + +static rfc2047_status_matchine statusTab[] = +{ + { rfc2047_status_next, &rfc2047::status_next }, + { rfc2047_status_data, &rfc2047::status_data }, + { rfc2047_status_equal_question, &rfc2047::status_equal_question }, + { rfc2047_status_charset, &rfc2047::status_charset }, + { rfc2047_status_question_first, &rfc2047::status_question_first }, + { rfc2047_status_coding, &rfc2047::status_coding }, + { rfc2047_status_question_second, &rfc2047::status_question_second }, + { rfc2047_status_question_equal, &rfc2047::status_question_equal } +}; + +void rfc2047::decode_update(const char* in, int n) +{ + while (n > 0) + { + int ret = (this->*(statusTab[m_status].func))(in, n); + in += n - ret; + n = ret; + } +} + +#define EQ(x, y) (((x) == NULL && (y) == NULL) \ + || ((x) != NULL && (y) != NULL && !strcasecmp((x), (y)))) + +static bool decoder_update(rfc2047_entry* entry, + const char* fromCharset, const char* toCharset, + acl::mime_code* pDecoder, acl::charset_conv* pConv, + acl::string* out, acl::string* buf1, acl::string* buf2) +{ + buf1->clear(); + pDecoder->decode_update(entry->pData->c_str(), + entry->pData->length(), buf1); + if (buf1->empty()) + return (true); + + // 如果源字符集与目标字符集相同则不进行字符集转码 + + if (EQ(fromCharset, toCharset) || pConv == NULL) + { + out->append(buf1->c_str(), buf1->length()); + return (true); + } + + // 进行字符集转码 + + buf2->clear(); + + if (!pConv->update_begin(fromCharset, toCharset)) + out->append(buf1->c_str(), buf1->length()); + else if (!pConv->update(buf1->c_str(), buf1->length(), buf2)) + out->append(buf1->c_str(), buf1->length()); + else if (buf2->length() > 0) + out->append(buf2->c_str(), buf2->length()); + + return (true); +} + +static bool decoder_finish(acl::mime_code* pDecoder, acl::charset_conv* pConv, + acl::string* out, acl::string* buf1, acl::string* buf2) +{ + buf1->clear(); + pDecoder->decode_finish(buf1); + if (buf1->empty()) + { + if (pConv) + { + buf2->clear(); + pConv->update_finish(buf2); + if (buf2->length() > 0) + out->append(buf2->c_str(), buf2->length()); + } + return (true); + } + + if (pConv == NULL) + { + out->append(buf1->c_str(), buf1->length()); + return (true); + } + + buf2->clear(); + + if (!pConv->update(buf1->c_str(), buf1->length(), buf2)) + { + out->append(buf1->c_str(), buf1->length()); + } + else + { + pConv->update_finish(buf2); + if (buf2->length() > 0) + out->append(buf2->c_str(), buf2->length()); + } + + return (true); +} + +bool rfc2047::decode_finish(const char* toCharset, acl::string* out, + bool addInvalid /* = true */) +{ + std::list::const_iterator cit = m_List.begin(); + acl::string buf1; + acl::string buf2; + acl::mime_base64 base64; + acl::mime_quoted_printable qp; + acl::mime_code* pDecoder = &base64; // 选择一个默认的解码器,然后根据需要变化 + const char *fromCharset = NULL; + acl::charset_conv conv; + conv.set_add_invalid(addInvalid); + + for (; cit != m_List.end(); ++cit) + { + if ((*cit)->coding == 'Q') + { + if (pDecoder != &qp || !EQ((*cit)->pCharset->c_str(), fromCharset)) + { + if (fromCharset == NULL) + fromCharset = (*cit)->pCharset->c_str(); + if (*fromCharset == 0) + fromCharset = NULL; + if (fromCharset == NULL || toCharset == NULL) + decoder_finish(pDecoder, NULL, out, &buf1, &buf2); + else + { + conv.update_begin(fromCharset, toCharset); + decoder_finish(pDecoder, &conv, out, &buf1, &buf2); + } + pDecoder->reset(); + } + pDecoder = &qp; // qp 解码 + fromCharset = (*cit)->pCharset->c_str(); + if (*fromCharset == 0) + fromCharset = NULL; + decoder_update(*cit, fromCharset, toCharset, + pDecoder, &conv, out, &buf1, &buf2); + } + else if ((*cit)->coding == 'B') + { + if (pDecoder != &base64 || !EQ((*cit)->pCharset->c_str(), fromCharset)) + { + if (fromCharset == NULL) + fromCharset = (*cit)->pCharset->c_str(); + if (*fromCharset == 0) + fromCharset = NULL; + if (fromCharset == NULL && toCharset == NULL) + decoder_finish(pDecoder, NULL, out, &buf1, &buf2); + else + { + conv.update_begin(fromCharset, toCharset); + decoder_finish(pDecoder, &conv, out, &buf1, &buf2); + } + pDecoder->reset(); + } + pDecoder = &base64; // base64 解码 + fromCharset = (*cit)->pCharset->c_str(); + if (*fromCharset == 0) + fromCharset = NULL; + decoder_update(*cit, fromCharset, toCharset, + pDecoder, &conv, out, &buf1, &buf2); + } + else + { + if (fromCharset == NULL || toCharset == NULL) + decoder_finish(pDecoder, NULL, out, &buf1, &buf2); + else + { + conv.update_begin(fromCharset, toCharset); + decoder_finish(pDecoder, &conv, out, &buf1, &buf2); + } + pDecoder->reset(); + out->append((*cit)->pData->c_str(), (*cit)->pData->length()); + } + } + + if (fromCharset != NULL && toCharset != NULL) + { + conv.update_begin(fromCharset, toCharset); + return (decoder_finish(pDecoder, &conv, out, &buf1, &buf2)); + } + else + { + return (decoder_finish(pDecoder, NULL, out, &buf1, &buf2)); + } +} + +bool rfc2047::encode_update(const char* in, int n, acl::string* out, + const char* charset /* = "gb2312" */, char coding /* = 'B' */) +{ + if (charset == NULL || *charset == 0) + return (false); + char ch = toupper(coding); + if (ch != 'B' && ch != 'Q') + return (false); + + acl_assert(in); + acl_assert(n > 0); + acl_assert(out); + + if (m_pCurrentEntry == NULL || + strcasecmp(m_pCurrentEntry->pCharset->c_str(), charset) != 0 || + m_pCurrentEntry->coding != ch) + { + if (m_coder) + { + acl_assert(m_pCurrentEntry); + m_coder->encode_finish(out); + *out << "?="; + delete m_coder; + m_coder = NULL; + } + + m_pCurrentEntry = NEW rfc2047_entry; + m_pCurrentEntry->pData = NEW acl::string(n * 4/3); + m_pCurrentEntry->pCharset = NEW acl::string(charset); + m_pCurrentEntry->pCharset->upper(); + m_pCurrentEntry->coding = ch; + + m_List.push_back(m_pCurrentEntry); + + if (ch == 'B') + { + m_coder = NEW mime_base64(m_addCrlf, false); + *out << "=?" << m_pCurrentEntry->pCharset->c_str() + << "?B?"; + } + else if (ch == 'Q') + { + m_coder = NEW mime_quoted_printable(m_addCrlf, false); + *out << "=?" << m_pCurrentEntry->pCharset->c_str() + << "?Q?"; + } + } + + acl_assert(m_pCurrentEntry); + acl_assert(m_coder); + + m_coder->encode_update(in, n, out); + return (true); +} + +bool rfc2047::encode_finish(string* out) +{ + acl_assert(m_pCurrentEntry); + acl_assert(m_coder); + acl_assert(out); + + m_coder->encode_finish(out); + *out << "?="; + return (true); +} + +bool rfc2047::encode(const char* in, int n, acl::string* out, + const char* charset /* = "gb2312" */, char coding /* = 'B' */, + bool addCrlf /* = true */) +{ + rfc2047 rfc(false, addCrlf); + if (rfc.encode_update(in, n, out, charset, coding) == false) + return (false); + return (rfc.encode_finish(out)); +} + +bool rfc2047::decode(const char* in, int n, acl::string* out, + const char* to_charset /* = "gb2312" */, + bool strip_sp /* = false */, bool addInvalid /* = true */) +{ + rfc2047 rfc(strip_sp, false); + rfc.decode_update(in, n); + return (rfc.decode_finish(to_charset, out, addInvalid)); +} + +} // namespace acl diff --git a/lib_acl_cpp/src/mime/rfc822.cpp b/lib_acl_cpp/src/mime/rfc822.cpp new file mode 100644 index 000000000..8f1290b08 --- /dev/null +++ b/lib_acl_cpp/src/mime/rfc822.cpp @@ -0,0 +1,524 @@ +#include "acl_stdafx.hpp" +#include +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/stdlib/string.hpp" +#include "acl_cpp/mime/rfc2047.hpp" +#include "internal/tok822.hpp" +#include "acl_cpp/mime/rfc822.hpp" + +namespace acl { + +#define STR acl_vstring_str +#define LEN ACL_VSTRING_LEN + +static const char * const months[] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", + NULL +}; + +static const char * const wdays[] = { + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" +}; + +static unsigned parsedig(const char **p) +{ + unsigned i = 0; + + while (isdigit((int) (unsigned char) **p)) + { + i = i * 10 + **p - '0'; + ++*p; + } + return (i); +} + +#define leap(y) (((y) % 400) == 0 || (((y) % 4) == 0 && (y) % 100) ) + +static const unsigned mlength[] = +{ + 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +}; + +#define mdays(m,y) ( (m) != 2 ? mlength[(m) - 1] : leap(y) ? 29 : 28) + +static const char *const zonenames[] = +{ + "UT", "GMT", + "EST", "EDT", + "CST", "CDT", + "MST", "MDT", + "PST", "PDT", + "Z", + "A", "B", "C", "D", "E", "F", "G", "H", "I", "K", "L", "M", + "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", + NULL +}; + +#define ZH(n) ( (n) * 60 * 60 ) + +static const int zoneoffset[] = +{ + 0, 0, + ZH(-5), ZH(-4), + ZH(+8), ZH(-5), + ZH(-7), ZH(-6), + ZH(-8), ZH(-7), + 0, + + ZH(-1), ZH(-2), ZH(-3), ZH(-4), ZH(-5), ZH(-6), + ZH(-7), ZH(-8), ZH(-9), ZH(-10), ZH(-11), ZH(-12), + ZH(1), ZH(2), ZH(3), ZH(4), ZH(5), ZH(6), ZH(7), + ZH(8), ZH(9), ZH(10), ZH(11), ZH(12) +}; + +static unsigned parsekey(const char **mon, const char * const *ary) +{ + unsigned m = 0, j = 0; + + for (m = 0; ary[m]; m++) + { + for (j = 0; ary[m][j]; j++) + { + if (tolower(ary[m][j]) != tolower((*mon)[j])) + break; + } + if (!ary[m][j]) + { + *mon += j; + return (m + 1); + } + } + + return (0); +} + +static int parsetime(const char **t) +{ + unsigned h = 0, m = 0, s = 0; + + if (!isdigit((int)(unsigned char) **t)) + return (-1); + h = parsedig(t); + if (h > 23) + return (-1); + if (**t != ':') + return (-1); + ++*t; + if (!isdigit((int) (unsigned char) **t)) + return (-1); + m = parsedig(t); + if (**t == ':') + { + ++*t; + if (!isdigit((int) (unsigned char) **t)) + return (-1); + s = parsedig(t); + } + if (m > 59 || s > 59) + return (-1); + return (h * 60 * 60 + m * 60 + s); +} + +rfc822::rfc822() +{ +} + +rfc822::~rfc822() +{ + reset(); +} + +time_t rfc822::parse_date(const char *rfcdt) +{ + unsigned day = 0, mon = 0, year = 0; + int secs = 0; + int offset = 0; + time_t t = 0; + unsigned y = 0; + int sign = 1; + unsigned n = 0; + + /* Ignore day of the week. Tolerate "Tue, 25 Feb 1997 ... " + ** without the comma. Tolerate "Feb 25 1997 ...". + */ + + while (!day || !mon) + { + if (!*rfcdt) + return (0); + if (isalpha((int)(unsigned char)*rfcdt)) + { + if (mon) + return (0); + mon = parsekey(&rfcdt, months); + if (!mon) + while (*rfcdt && isalpha((int)(unsigned char)*rfcdt)) + ++rfcdt; + continue; + } + + if (isdigit((int)(unsigned char)*rfcdt)) + { + if (day) + return (0); + day = parsedig(&rfcdt); + if (!day) + return (0); + continue; + } + ++rfcdt; + } + + while (*rfcdt && isspace((int)(unsigned char)*rfcdt)) + ++rfcdt; + if (!isdigit((int)(unsigned char)*rfcdt)) + return (0); + year = parsedig(&rfcdt); + if (year < 70) + year += 2000; + if (year < 100) + year += 1900; + + while (*rfcdt && isspace((int)(unsigned char)*rfcdt)) + ++rfcdt; + + if (day == 0 || mon == 0 || mon > 12 || day > mdays(mon, year)) + return (0); + + secs = parsetime(&rfcdt); + if (secs < 0) + return (0); + + offset = 0; + + /* RFC822 sez no parenthesis, but I've seen (EST) */ + + while ( *rfcdt ) + { + if (isalnum((int)(unsigned char)*rfcdt) || *rfcdt == '+' || + *rfcdt == '-') + { + break; + } + ++rfcdt; + } + + if (isalpha((int)(unsigned char)*rfcdt)) + { + n = parsekey(&rfcdt, zonenames); + if (n > 0) + offset = zoneoffset[n - 1]; + } + else + { + switch (*rfcdt) + { + case '-': + sign = -1; + case '+': + ++rfcdt; + } + + if (isdigit((int)(unsigned char)*rfcdt)) + { + n = parsedig(&rfcdt); + if (n > 2359 || (n % 100) > 59) + n = 0; + offset = sign * ( (n % 100) * 60 + n / 100 * 60 * 60); + } + } + + if (year < 1970) + { + printf("%s(%d)\n", __FUNCTION__, __LINE__); + return (0); + } + + t = 0; + for (y = 1970; y < year; y++) + { + if ( leap(y) ) + { + if (year - y >= 4) + { + y += 3; + t += ( 365 * 3 + 366 ) * 24 * 60 * 60; + continue; + } + t += 24 * 60 * 60; + } + t += 365 * 24 * 60 * 60; + } + + for (y = 1; y < mon; y++) + t += mdays(y, year) * 24 * 60 * 60; + + return (t + (day - 1) * 24 * 60 * 60 + secs - offset); +} + +void rfc822::mkdate(time_t t, char* buf, size_t size, tzone_t zone) +{ + if (zone == tzone_cst) + mkdate_cst(t, buf, size); + else + mkdate_gmt(t, buf, size); +} + +void rfc822::mkdate_gmt(time_t t, char *buf, size_t size) +{ + struct tm *p; + +#ifdef WIN32 + p = gmtime(&t); +#else + struct tm tm_buf; + p = gmtime_r(&t, &tm_buf); +#endif + + snprintf(buf, size, "%s, %02d %s %04d %02d:%02d:%02d (GMT)", + wdays[p->tm_wday], + p->tm_mday, + months[p->tm_mon], + p->tm_year + 1900, + p->tm_hour, + p->tm_min, + p->tm_sec); +} + +#define USE_TIME_DAYLIGHT 1 + +void rfc822::mkdate_cst(time_t t, char *buf, size_t size) +{ + struct tm *p; + int offset = 0; + +#ifdef WIN32 + p = localtime(&t); +#else + struct tm tm_buf; + p = localtime_r(&t, &tm_buf); +#endif + +#if USE_TIME_ALTZONE + + offset = -_timezone; + + if (p->tm_isdst > 0) + offset = -altzone; + + if (offset % 60) + { + offset = 0; +#ifdef WIN32 + p = gmtime(&t); +#else + p = gmtime_r(&t, &tm_buf); +#endif + } + offset /= 60; +#else +#if USE_TIME_DAYLIGHT + +#ifdef WIN32 + offset = - _timezone; +#else + offset = - timezone; +#endif + + if (p->tm_isdst > 0) + offset += 60 * 60; + if (offset % 60) { + offset = 0; +#ifdef WIN32 + p = gmtime(&t); +#else + p = gmtime_r(&t, &tm_buf); +#endif + } + offset /= 60; +#else +#if USE_TIME_GMTOFF + offset = p->tm_gmtoff; + + if (offset % 60) { + offset = 0; +#ifdef WIN32 + p = gmtime(&t); +#else + p = gmtime_r(&t, &tm_buf); +#endif + } + offset /= 60; +#else +#ifdef WIN32 + p = gmtime(&t); +#else + p = gmtime_r(&t, &tm_buf); +#endif + offset = 0; +#endif +#endif +#endif + + offset = (offset % 60) + offset / 60 * 100; + + snprintf(buf, size, "%s, %02d %s %04d %02d:%02d:%02d %+05d (CST)", + wdays[p->tm_wday], + p->tm_mday, + months[p->tm_mon], + p->tm_year + 1900, + p->tm_hour, + p->tm_min, + p->tm_sec, + offset); +} + +const std::list& rfc822::parse_addrs(const char* in) +{ + reset(); + + if (in == NULL || *in == 0) + { + logger_error("input invalid"); + return (addrs_); + } + TOK822 *tree = tok822_parse(in); + if (tree == NULL) + { + logger_error("tok822_parse(%s) error", in); + return (addrs_); + } + + const ACL_VSTRING* comment_prev = NULL; + string buf; + + for (TOK822 *tp = tree; tp; tp = tp->next) + { + if (tp->type == TOK822_ATOM + || tp->type == TOK822_COMMENT + || tp->type == TOK822_QSTRING + || tp->vstr != NULL) + { + comment_prev = tp->vstr; + } + + if (tp->type != TOK822_ADDR || tp->head == NULL) + continue; + + ACL_VSTRING* addrp = acl_vstring_alloc(32); + (void) tok822_internalize(addrp, tp->head, TOK822_STR_DEFL); + rfc822_addr* addr = (rfc822_addr*) + acl_mymalloc(sizeof(rfc822_addr)); + addr->addr = acl_vstring_export(addrp); + if (comment_prev) + { + buf.clear(); + rfc2047::decode(STR(comment_prev), LEN(comment_prev), + &buf, "gb18030"); + addr->comment = acl_mystrdup(buf.c_str()); + comment_prev = NULL; + } + else + addr->comment = NULL; + addrs_.push_back(addr); + } + + tok822_free_tree(tree); + return (addrs_); +} + +const rfc822_addr* rfc822::parse_addr(const char* in) +{ + const std::list addr_list = parse_addrs(in); + if (addr_list.empty()) + return (NULL); + std::list::const_iterator cit = addr_list.begin(); + acl_assert(cit != addr_list.end()); + return (*cit); +} + +bool rfc822::check_addr(const char* in) +{ +#define VALID1(x) (((x) >= '0' && (x) <= '9') \ + || ((x) >= 'a' && (x) <= 'z') \ + || ((x) >= 'A' && (x) <= 'Z')) + +#define VALID2(x) (((x) >= '0' && (x) <= '9') \ + || ((x) >= 'a' && (x) <= 'z') \ + || ((x) >= 'A' && (x) <= 'Z') \ + || (x) == '-' \ + || (x) == '_' \ + || (x) == '.') + + while (*in == ' ' || *in == '\t') + in++; + if (*in == ';' || *in == ',') + return false; + + const rfc822_addr* addr = parse_addr(in); + if (addr == NULL || addr->addr == NULL) + return false; + const char* at = addr->addr; + //printf(">>%s, %s\r\n", addr->comment ? addr->comment : "null", addr->addr); + if (!VALID1(*at)) + return false; + at++; + + while (*at) + { + if (*at == '@') + { + // 必须保证 @ 前一个字符的有效性遵守 VALID1 + if (!VALID1(*(at - 1))) + return false; + break; + } + if (!VALID2(*at)) + return false; + at++; + } + if (*at != '@') + return false; + at++; + + int dot = 0; + bool first = true; + while (*at) + { + if (first) + { + // at: [a-z]|[A-Z]|[0-9] + if (!VALID1(*at)) + return false; + first = false; + } + else if (*at == '.') + { + dot++; + first = true; + } else if (!VALID2(*at)) + return false; + at++; + } + + if (!VALID1(*(at - 1)) || dot == 0) + return false; + return true; +} + +void rfc822::reset() +{ + std::list::iterator it = addrs_.begin(); + for (; it != addrs_.end(); ++it) + { + acl_myfree((*it)->addr); + if ((*it)->comment) + acl_myfree((*it)->comment); + acl_myfree(*it); + } + + addrs_.clear(); +} + +} // namespace acl diff --git a/lib_acl_cpp/src/queue/queue_file.cpp b/lib_acl_cpp/src/queue/queue_file.cpp new file mode 100644 index 000000000..53637ed57 --- /dev/null +++ b/lib_acl_cpp/src/queue/queue_file.cpp @@ -0,0 +1,407 @@ +#include "acl_stdafx.hpp" +#include +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/stdlib/util.hpp" +#include "acl_cpp/stream/fstream.hpp" +#include "acl_cpp/queue/queue_manager.hpp" +#include "acl_cpp/queue/queue_file.hpp" + +#ifdef WIN32 +#include +#define getpid _getpid +#endif + +#ifdef WIN32 +#define PATH_SEP '\\' +#else +#define PATH_SEP '/' +#endif + +static __thread unsigned int __counter = 0; + +namespace acl +{ + +queue_file::queue_file() +: m_fp(NULL) +, m_locker(true, true) +, m_bLocked(false) +, m_bLockerOpened(false) +, nwriten_(0) +{ + +} + +queue_file::~queue_file() +{ + this->close(); +} + +bool queue_file::create(const char* home, const char* queueName, + const char* extName, unsigned width) +{ + acl_assert(width > 0); + + struct timeval tv; + acl::string buf; + acl::fstream* fp = NULL; + int i = 0; + + ACL_SAFE_STRNCPY(m_home, home, sizeof(m_home)); + ACL_SAFE_STRNCPY(m_queueName, queueName, sizeof(m_queueName)); + ACL_SAFE_STRNCPY(m_extName, extName, sizeof(m_extName)); + + unsigned int n; + + while (1) + { + // 产生部分文件名 + memset(&tv, 0, sizeof(tv)); + gettimeofday(&tv, NULL); + snprintf(m_partName, sizeof(m_partName), + "%08x%08x%08x%08x%08x", + (unsigned int) getpid(), + (unsigned int) acl_pthread_self(), + (unsigned int) tv.tv_sec, + (unsigned int) tv.tv_usec, + (unsigned int) __counter); + if (__counter++ >= 1024000) + __counter = 0; + + // 计算队列子目录 + n = queue_manager::hash_queueSub(m_partName, width); + snprintf(m_queueSub, sizeof(m_queueSub), "%u", n); + + buf.clear(); + buf << m_home << PATH_SEP << m_queueName << PATH_SEP << m_queueSub + << PATH_SEP << m_partName << "." << extName; + + fp = NEW fstream; + + while (true) + { + // 排它性创建唯一文件 + if (fp->open(buf.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600) == true) + goto END; + + logger_warn("open file %s error(%s)", buf.c_str(), acl_last_serror()); + + if (acl_last_error() != ENOENT) + break; + + // 尝试性创建目录 + buf.clear(); + buf << m_home << PATH_SEP << m_queueName << PATH_SEP << m_queueSub; + if (acl_make_dirs(buf.c_str(), 0700) == -1) + { + logger_error("mkdir: %s error(%s)", + buf.c_str(), acl_last_serror()); + delete fp; + return false; + } + else + logger("create path: %s ok", buf.c_str()); + + buf.clear(); + buf << m_home << PATH_SEP << m_queueName << PATH_SEP << m_queueSub + << PATH_SEP << m_partName << "." << extName; + + } + delete fp; + sleep(1); + if (i++ >= 10) { + logger_error("can't create file, loop 10 times for (%s)", + buf.c_str()); + return false; + } + } + +END: + m_fp = fp; + m_filePath = buf.c_str(); + + // 打开队列文件对象锁 + if (m_locker.open(m_fp->file_handle()) == false) + { + logger_error("open lock for %s error(%s)", + m_filePath.c_str(), acl_last_serror()); + m_bLockerOpened = false; + } + else + m_bLockerOpened = true; + + return (true); +} + +bool queue_file::open(const char* filePath) +{ + string home, queueName, queueSub, partName, extName; + if (queue_manager::parse_filePath(filePath, &home, &queueName, &queueSub, + &partName, &extName) == false) + { + logger_error("filePath(%s) invalid", filePath); + return (false); + } + + return (open(home.c_str(), queueName.c_str(), queueSub.c_str(), + partName.c_str(), extName.c_str())); +} + +bool queue_file::open(const char* home, const char* queueName, + const char* queueSub, const char* partName, const char* extName) +{ + if (m_fp) + logger_fatal("old file(%s) exist", m_filePath.c_str()); + + m_filePath.clear(); + m_filePath << home << PATH_SEP << queueName << PATH_SEP << queueSub + << PATH_SEP << partName << "." << extName; + + m_fp = NEW fstream; + + if (m_fp->open(m_filePath.c_str(), O_RDWR, 0600) == false) + { + logger_error("open %s error(%s)", m_filePath.c_str(), + acl_last_serror()); + delete m_fp; + m_fp = NULL; + return (false); + } + + if (m_home != home) + ACL_SAFE_STRNCPY(m_home, home, sizeof(m_home)); + if (m_queueName != queueName) + ACL_SAFE_STRNCPY(m_queueName, queueName, sizeof(m_queueName)); + if (m_queueSub != queueSub) + ACL_SAFE_STRNCPY(m_queueSub, queueSub, sizeof(m_queueSub)); + if (m_partName != partName) + ACL_SAFE_STRNCPY(m_partName, partName, sizeof(m_partName)); + if (m_extName != extName) + ACL_SAFE_STRNCPY(m_extName, extName, sizeof(m_extName)); + + // 打开队列文件对象锁 + if (m_locker.open(m_fp->file_handle()) == false) + { + logger_error("open lock for %s error(%s)", + m_filePath.c_str(), acl_last_serror()); + m_bLockerOpened = false; + } + else + { + m_bLockerOpened = true; + } + + // XXX, 需要分析该全路径, 以提取需要的字段 + return (true); +} + +void queue_file::close() +{ + if (m_fp) + { + delete m_fp; + m_fp = NULL; + nwriten_ = 0; + } +} + +acl::fstream* queue_file::get_fstream() const +{ + return (m_fp); +} + +time_t queue_file::get_ctime() const +{ + if (m_fp == NULL) + { + logger_error("m_fp null"); + return ((time_t) -1); + } + else if (m_filePath.empty()) + { + logger_error("m_filePath empty"); + return ((time_t) -1); + } + + struct acl_stat buf; + if (acl_stat(m_filePath.c_str(), &buf) == -1) + { + logger_error("stat file(%s) error(%s)", + m_filePath.c_str(), acl_last_serror()); + return ((time_t) -1); + } + return (buf.st_ctime); +} + +bool queue_file::write(const void* data, size_t len) +{ + if (data == NULL || len == 0 || len >= (unsigned int) -1) + { + logger_error("input invalid"); + return (false); + } + if (m_fp == NULL) + { + logger_error("m_fp null"); + return (false); + } + if (m_fp->write(data, len) != (int) len) + { + logger_error("write error"); + return (false); + } + + nwriten_ += len; + return (true); +} + +int queue_file::format(const char* fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + int ret = vformat(fmt, ap); + va_end(ap); + return ret; +} + +int queue_file::vformat(const char* fmt, va_list ap) +{ + int ret = m_fp->vformat(fmt, ap); + if (ret == -1) + { + logger_error("write to file error(%s)", last_serror()); + return -1; + } + + nwriten_ += ret; + return ret; +} +int queue_file::read(void* buf, size_t len) +{ + if (buf == NULL || len == 0 || len >= (unsigned int) -1) + { + logger_error("input invalid"); + return (-1); + } + if (m_fp == NULL) + { + logger_error("m_fp null"); + return (-1); + } + int ret; + if ((ret = m_fp->read(buf, len, false)) < 0) + return (-1); + return (ret); +} + +bool queue_file::remove() +{ + this->close(); +#ifdef WIN32 + if (_unlink(m_filePath.c_str()) != 0) +#else + if (unlink(m_filePath.c_str()) != 0) +#endif + { + logger_error("unlink %s error(%s)", + m_filePath.c_str(), acl_last_serror()); + return (false); + } + return (true); +} + +bool queue_file::move_file(const char* queueName, const char* extName) +{ + acl::string buf(256); + bool once_again = false; + + while (true) + { + buf.clear(); + buf << m_home << PATH_SEP << queueName << PATH_SEP << m_queueSub + << PATH_SEP << m_partName << "." << extName; + +#ifdef WIN32 + // 在win32下必须先关闭文件句柄 + this->close(); +#endif + + if (rename(m_filePath.c_str(), buf.c_str()) == 0) + break; + + // 如果返回错误原因是目标路径不存在,则尝试创建目录结构 + + if (once_again || acl_last_error() != ENOENT) + { + logger_error("move from %s to %s error(%s), errno: %d, %d", + m_filePath.c_str(), buf.c_str(), acl_last_serror(), + acl_last_error(), ENOENT); + return (false); + } + + // 设置重试标志位 + once_again = true; + + buf.clear(); + buf << m_home << PATH_SEP << queueName + << PATH_SEP << m_queueSub; + + // 创建队列目录 + if (acl_make_dirs(buf.c_str(), 0700) == -1) + { + logger_error("mkdir: %s error(%s)", + buf.c_str(), acl_last_serror()); + return false; + } + } + +#ifdef WIN32 + // win32 下需要重新再打开 + return (open(m_home, queueName, m_queueSub, m_partName, extName)); +#else + if (m_queueName != queueName) + ACL_SAFE_STRNCPY(m_queueName, queueName, sizeof(m_queueName)); + if (m_extName != extName) + ACL_SAFE_STRNCPY(m_extName, extName, sizeof(m_extName)); + m_filePath.clear(); + m_filePath << m_home << PATH_SEP << m_queueName << PATH_SEP + << m_queueSub << PATH_SEP << m_partName << "." << m_extName; +#endif + return (true); +} + +void queue_file::set_queueName(const char* queueName) +{ + ACL_SAFE_STRNCPY(m_queueName, queueName, sizeof(m_queueName)); + m_filePath.clear(); + m_filePath << m_home << PATH_SEP << m_queueName << PATH_SEP + << m_queueSub << PATH_SEP << m_partName << "." << m_extName; +} + +void queue_file::set_extName(const char* extName) +{ + ACL_SAFE_STRNCPY(m_extName, extName, sizeof(m_extName)); + m_filePath.clear(); + m_filePath << m_home << PATH_SEP << m_queueName << PATH_SEP + << m_queueSub << PATH_SEP << m_partName << "." << m_extName; +} + +bool queue_file::lock() +{ + if (m_bLockerOpened == false) + return (false); + if (m_locker.lock() == false) + return (false); + return (true); +} + +bool queue_file::unlock() +{ + if (m_bLockerOpened == false) + return (false); + if (m_locker.unlock() == false) + return (false); + return (true); +} + +} // namespace acl diff --git a/lib_acl_cpp/src/queue/queue_manager.cpp b/lib_acl_cpp/src/queue/queue_manager.cpp new file mode 100644 index 000000000..e88c6ea0b --- /dev/null +++ b/lib_acl_cpp/src/queue/queue_manager.cpp @@ -0,0 +1,443 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/stdlib/util.hpp" +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/queue/queue_manager.hpp" + +#ifdef WIN32 +#define PATH_SEP '\\' +#else +#define PATH_SEP '/' +#endif + +namespace acl +{ + +queue_manager::queue_manager(const char* home, const char* queueName, + unsigned sub_width) +: m_scanDir(NULL) +, m_home(home) +, m_queueName(queueName) +{ + if (sub_width == 0) + sub_width_ = 2; + else + sub_width_ = sub_width; + + string buf = home; + buf << PATH_SEP << queueName; + + // 先创建根目录 + if (acl_make_dirs(buf.c_str(), 0700) == -1) + logger_error("create dir: %s error %s", buf.c_str(), + last_serror()); + else + logger("create dir: %s ok", buf.c_str()); + + char node[32]; + for (unsigned i = 0; i < sub_width_; i++) + { + buf.clear(); + snprintf(node, sizeof(node), "%d", i); + buf << home << PATH_SEP << queueName + << PATH_SEP << node; + // 创建队列下子目录 + if (acl_make_dirs(buf.c_str(), 0700) == -1) + logger_error("create dir: %s error %s", + buf.c_str(), last_serror()); + else + logger("create dir: %s ok", buf.c_str()); + } +} + +queue_manager::~queue_manager() +{ + if (m_scanDir) + acl_scan_dir_close(m_scanDir); +} + +const char* queue_manager::get_home() const +{ + return (m_home.c_str()); +} + +const char* queue_manager::get_queueName() const +{ + return (m_queueName.c_str()); +} + +queue_file* queue_manager::create_file(const char* extName) +{ + queue_file* fp = NEW queue_file; + + if (fp->create(m_home.c_str(), m_queueName.c_str(), + extName, sub_width_) == false) + { + delete fp; + return (NULL); + } + + if (cache_add(fp) == false) + logger_fatal("%s already exist in table", fp->key()); + return (fp); +} + +queue_file* queue_manager::open_file(const char* filePath, bool no_cache /* = true */) +{ + string home, queueName, queueSub, partName, extName; + if (queue_manager::parse_filePath(filePath, &home, &queueName, &queueSub, + &partName, &extName) == false) + { + logger_error("filePath(%s) invalid", filePath); + return (NULL); + } + + queue_file* fp; + + // 如果该文件存在于内存中则直接返回之 + fp = cache_find(partName); + if (fp != NULL) + { + if (no_cache) + { + logger_warn("file: %s locked", filePath); + return NULL; + } + return (fp); + } + + // 从磁盘打开已经存在的队列文件 + fp = NEW queue_file; + if (fp->open(home.c_str(), queueName.c_str(), queueSub.c_str(), + partName.c_str(), extName.c_str()) == false) + { + delete fp; + return (NULL); + } + cache_add(fp); + return (fp); +} + +bool queue_manager::close_file(queue_file* fp) +{ + string key(fp->key()); + delete fp; + cache_del(key.c_str()); + return (true); +} + +bool queue_manager::delete_file(queue_file* fp) +{ + string key(fp->key()); + fp->remove(); + delete fp; + cache_del(key.c_str()); + return (true); +} + +bool queue_manager::rename_extname(queue_file* fp, const char* extName) +{ + if (cache_check(fp) == false) + { + logger_warn("file(%s)'s key(%s) not exist", + fp->get_filePath(), fp->key()); + return (false); + } + return fp->move_file(fp->get_queueName(), extName); +} + +bool queue_manager::move_file(queue_file* fp, const char* queueName, const char* extName) +{ + string key(fp->key()); + bool ret = fp->move_file(queueName, extName); + cache_del(key.c_str()); + return ret; +} + +bool queue_manager::move_file(queue_file* fp, queue_manager* toQueue, const char* extName) +{ + bool ret = move_file(fp, toQueue->get_queueName(), extName); + if (ret == false) + return (false); + return (toQueue->cache_add(fp)); +} + +bool queue_manager::parse_filePath(const char* filePath, string* home, + string* queueName, string* queueSub, + string* partName, string* extName) +{ + if (filePath == NULL || *filePath == 0) + { + logger_error("filePath invalid!"); + return (false); + } + + // 格式为: /home/queue_name/queue_sub_node/file_name.file_ext + + ACL_ARGV *argv = acl_argv_split(filePath, "/\\"); + if (argv->argc < 4) + { + logger_error("filePath(%s) invalid", filePath); + acl_argv_free(argv); + return (false); + } + + home->clear(); + + // 如果第一个字符为 PATH_SEP 则需要补齐 + if (*filePath == PATH_SEP) + home->push_back(PATH_SEP); + + // 仅存储根路径部分 + for (int i = 0; i < argv->argc - 3; i++) + { + if (i > 0 && home->length() > 0) + (*home) += PATH_SEP; + (*home) += argv->argv[i]; + } + + // 取得队列名 + *queueName = argv->argv[argv->argc - 3]; + *queueSub = argv->argv[argv->argc - 2]; + + // 继续分析文件名部分 + bool ret = parse_fileName(argv->argv[argv->argc - 1], partName, extName); + + acl_argv_free(argv); + return (ret); +} + +bool queue_manager::parse_fileName(const char* fileName, string* partName, string* extName) +{ + const char* extSep = strrchr(fileName, '.'); + if (extSep == NULL || extSep == fileName) + { + logger_error("fileName(%s) invalid", fileName); + return (false); + } + + // 拷贝文件名 + partName->copy(fileName, extSep - fileName); + extSep++; + if (*extSep == 0) + { + logger("fileName(%s) invalid", fileName); + return (false); + } + + // 拷贝扩展名 + *extName = extSep; + return (true); +} + +bool queue_manager::parse_path(const char* path, string* home, + string* queueName, string* queueSub) +{ + if (path == NULL || *path == 0) + { + logger_error("path invalid!"); + return (false); + } + + /* WINDOWS 支持 '/' 和 '\\' 两种分隔符 */ + // 数据格式: /home/queueName/queueSub + ACL_ARGV *argv = acl_argv_split(path, "/\\"); + if (argv->argc < 3) + { + logger_error("path(%s) invalid", path); + acl_argv_free(argv); + return (false); + } + + // 取得home + home->clear(); + // 如果第一个字符为 PATH_SEP 则需要补齐 + if (*path == PATH_SEP) + home->push_back(PATH_SEP); + *home += argv->argv[argv->argc - 3]; + + // 取得队列名 + *queueName = argv->argv[argv->argc - 2]; + // 取得队列子目录名 + *queueSub = argv->argv[argv->argc - 1]; + acl_argv_free(argv); + return (true); +} + +unsigned int queue_manager::hash_queueSub(const char* partName, unsigned width) +{ + acl_assert(width > 0); + unsigned int n = acl_hash_crc32(partName, strlen(partName)); + return (n % width); +} + +bool queue_manager::busy(const char* partName) +{ + if (cache_find(partName)) + return (true); + else + return (false); +} + +queue_file* queue_manager::cache_find(const char* key) +{ + queue_file* fp = NULL; + std::map::iterator it; + m_queueLocker.lock(); + it = m_queueList.find(key); + if (it != m_queueList.end()) + { + fp = it->second; + } + m_queueLocker.unlock(); + return (fp); +} + +bool queue_manager::cache_check(queue_file* fp) +{ + std::map::iterator it; + m_queueLocker.lock(); + it = m_queueList.find(fp->key()); + if (it == m_queueList.end()) + { + m_queueLocker.unlock(); + logger_error("%s not exist in table", fp->key()); + return (false); + } + else if (it->second != fp) + { + m_queueLocker.unlock(); + logger_error("%s not match, %lx, %lx", fp->key(), + (size_t) fp, (size_t)it->second); + return (false); + } + m_queueLocker.unlock(); + return (true); +} + +bool queue_manager::cache_add(queue_file* fp) +{ + bool ret; + + std::map::iterator it; + m_queueLocker.lock(); + it = m_queueList.find(fp->key()); + if (it == m_queueList.end()) + { + m_queueList[fp->key()] = fp; + ret = true; + } else { + ret = false; + } + m_queueLocker.unlock(); + return (ret); +} + +bool queue_manager::cache_del(const char* key) +{ + bool ret; + + std::map::iterator it; + m_queueLocker.lock(); + it = m_queueList.find(key); + if (it != m_queueList.end()) + { + m_queueList.erase(it); + ret = true; + } + else + { + ret = false; + } + + m_queueLocker.unlock(); + return (ret); +} + +bool queue_manager::remove(queue_file* fp) +{ + string key(fp->key()); + bool ret = fp->remove(); + delete fp; + cache_del(key.c_str()); + return (ret); +} + +bool queue_manager::scan_open(bool scanSub /* = true */) +{ + string path = m_home.c_str(); + path << PATH_SEP << m_queueName.c_str(); + m_scanDir = acl_scan_dir_open(path.c_str(), scanSub ? 1 : 0); + if (m_scanDir == NULL) + { + logger_error("open %s error(%s)", path.c_str(), acl_last_serror()); + return (false); + } else + return (true); +} + +void queue_manager::scan_close() +{ + if (m_scanDir) + { + acl_scan_dir_close(m_scanDir); + m_scanDir = NULL; + } +} + +queue_file* queue_manager::scan_next() +{ + if (m_scanDir == NULL) + logger_fatal("call scan_open first!"); + + queue_file* fp = NULL; + string filePath; + + while (1) + { + // 扫描下一个磁盘文件 + const char* fileName = acl_scan_dir_next_file(m_scanDir); + if (fileName == NULL) + return (NULL); + + string partName, extName; + + if (parse_fileName(fileName, &partName, &extName) == false) + continue; + // 如果该队列文件已经存在于内存队列中则跳过 + if (busy(partName.c_str())) + continue; + + const char* path = acl_scan_dir_path(m_scanDir); + if (path == NULL) + { + logger_error("acl_scan_dir_path error for %s", fileName); + continue; + } + + filePath.clear(); + filePath << path << PATH_SEP << fileName; + fp = NEW queue_file; + // 从磁盘打开已经存在的队列文件 + if (fp->open(filePath.c_str()) == false) + { + logger_error("open %s error(%s)", filePath.c_str(), + acl_last_serror()); + delete fp; + fp = NULL; + continue; + } + if (cache_add(fp) == false) + { + logger_error("file(%s) locked", filePath.c_str()); + delete fp; + fp = NULL; + continue; + } + else + break; + } + + return (fp); +} + +} // namespace acl diff --git a/lib_acl_cpp/src/redis/redis_client.cpp b/lib_acl_cpp/src/redis/redis_client.cpp new file mode 100644 index 000000000..25c251382 --- /dev/null +++ b/lib_acl_cpp/src/redis/redis_client.cpp @@ -0,0 +1,118 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/stdlib/util.hpp" +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/stream/socket_stream.hpp" +#include "acl_cpp/redis/redis_client.hpp" + +namespace acl +{ + +redis_client::redis_client(const char* addr, int conn_timeout /* = 60 */, + int rw_timeout /* = 30 */, bool retry /* = true */) +: conn_timeout_(conn_timeout) +, rw_timeout_(rw_timeout) +, retry_(retry) +{ + addr_ = acl_mystrdup(addr); +} + +redis_client::~redis_client() +{ + acl_myfree(addr_); +} + +bool redis_client::open() +{ + if (conn_.opened()) + return true; + if (conn_.open(addr_, conn_timeout_, rw_timeout_) == false) + { + logger_error("connect redis %s error: %s", + addr_, last_serror()); + return false; + } + return true; +} + +void redis_client::close() +{ + conn_.close(); +} + +void redis_client::clear() +{ + std::vector::iterator it = res_.begin(); + for (; it != res_.end(); ++it) + delete *it; + res_.clear(); +} + +const std::vector& redis_client::request(const char* cmd, + const void* data, size_t len) +{ + string line(128); + bool retried = false; + + clear(); + + while (true) + { + if (!conn_.opened() && conn_.open(addr_, conn_timeout_, + rw_timeout_) == false) + { + logger_error("connect server: %s error: %s", + addr_, last_serror()); + return res_; + } + + // 先写入数据头 + if (conn_.write(cmd) == -1) + { + conn_.close(); + if (retry_ && !retried) + { + retried = true; + continue; + } + logger_error("write to redis(%s) error: %s", + addr_, last_serror()); + return res_; + } + + // 如果有数据体,则写入数据体 + if (data && len > 0 && (conn_.write(data, len) == -1 + || conn_.write("\r\n", 2) == -1)) + { + conn_.close(); + if (retry_ && !retried) + { + retried = true; + continue; + } + logger_error("write to redis(%s) error: %s", + addr_, last_serror()); + return res_; + } + + line.clear(); + if (conn_.gets(line) == false || line.empty()) + { + conn_.close(); + if (retry_ && !retried) + { + retried = true; + continue; + } + logger_error("gets from redis(%s) error: %s", + addr_, last_serror()); + return res_; + } + break; + } + + return res_; + //ACL_ARGV* tokens = acl_argv_split(line.c_str(), "\t "); + //return tokens; +} + +} // end namespace acl diff --git a/lib_acl_cpp/src/session/memcache_session.cpp b/lib_acl_cpp/src/session/memcache_session.cpp new file mode 100644 index 000000000..c4da17eb1 --- /dev/null +++ b/lib_acl_cpp/src/session/memcache_session.cpp @@ -0,0 +1,59 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/memcache/memcache.hpp" +#include "acl_cpp/session/memcache_session.hpp" + +namespace acl +{ + +memcache_session::memcache_session(const char* cache_addr, + int conn_timeout /* = 180 */, int rw_timeout /* = 300 */, + const char* prefix /* = NULL */, time_t ttl /* = 0 */, + const char* sid /* = NULL */, bool encode_key /* = true */) +: session(ttl, sid) +, auth_free_(true) +{ + acl_assert(cache_addr && *cache_addr); + cache_ = NEW memcache(cache_addr, conn_timeout, rw_timeout); + (*cache_).set_prefix(prefix && *prefix ? prefix : "_") + .encode_key(encode_key) + .auto_retry(true); +} + +memcache_session::memcache_session(memcache* cache, bool auto_free /* = false */, + time_t ttl /* = 0 */, const char* sid /* = NULL */) +: session(ttl, sid) +, cache_(cache) +, auth_free_(auto_free) +{ + +} + +memcache_session::~memcache_session() +{ + if (auth_free_) + delete cache_; +} + +bool memcache_session::get_data(const char* sid, string& buf) +{ + return cache_->get(sid, buf); +} + +bool memcache_session::set_data(const char* sid, const char* buf, + size_t len, time_t ttl) +{ + return cache_->set(sid, buf, len, ttl); +} + +bool memcache_session::del_data(const char* sid) +{ + return cache_->del(sid); +} + +bool memcache_session::set_timeout(const char* sid, time_t ttl) +{ + return cache_->set(sid, ttl); +} + +} // namespace acl diff --git a/lib_acl_cpp/src/session/session.cpp b/lib_acl_cpp/src/session/session.cpp new file mode 100644 index 000000000..c06b9e912 --- /dev/null +++ b/lib_acl_cpp/src/session/session.cpp @@ -0,0 +1,439 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/stdlib/string.hpp" +#include "acl_cpp/stdlib/escape.hpp" +#include "acl_cpp/session/session.hpp" + +namespace acl +{ + +VBUF* session::vbuf_new(const void* str, size_t len, todo_t todo) +{ + // 这样可以减少分配内存的次数 + VBUF* buf = (VBUF*) acl_mymalloc(sizeof(VBUF) + len + 1); + buf->size = len + 1; + buf->todo = todo; + + memcpy(buf->buf, str, len); + // 必须保证尾部以 \0 结束以允许返回字符串属性值 + buf->buf[len] = 0; + buf->len = len; + return buf; +} + +VBUF* session::vbuf_set(VBUF* buf, const void* str, size_t len, todo_t todo) +{ + if (buf == NULL) + { + buf = (VBUF*) acl_mymalloc(sizeof(VBUF) + len + 1); + buf->size = len + 1; + } + else if (buf->size <= len) + { + buf = (VBUF*) acl_myrealloc(buf, sizeof(VBUF) + len + 1); + buf->size = len + 1; + } + + buf->todo = todo; + memcpy(buf->buf, str, len); + buf->buf[len] = 0; + buf->len = len; + return buf; +} + +void session::vbuf_free(VBUF* buf) +{ + acl_myfree(buf); +} + +session::session(time_t ttl /* = 0 */, const char* sid /* = NULL */) +: ttl_(ttl) +, dirty_(false) +{ + struct timeval tv; + + (void) gettimeofday(&tv, NULL); + if (sid == NULL || *sid == 0) + { + char buf[128]; + snprintf(buf, sizeof(buf), "acl.%d.%d.%d", (int) tv.tv_sec, + (int) tv.tv_usec, rand()); + sid_ = vbuf_new(buf, strlen(buf), TODO_NUL); + sid_saved_ = false; + } + else + { + sid_ = vbuf_new(sid, strlen(sid), TODO_NUL); + sid_saved_ = true; + } +} + +session::~session() +{ + reset(); + vbuf_free(sid_); +} + +const char* session::get_sid() const +{ + return sid_->buf; +} + +void session::set_sid(const char* sid) +{ + sid_ = vbuf_set(sid_, sid, strlen(sid), TODO_NUL); + + // 有可能已经存储在后端 cache 服务端了 + if (!sid_saved_) + sid_saved_ = true; + + // 必须清除上次的中间结果 + reset(); +} + +void session::reset() +{ + attrs_clear(attrs_); + attrs_clear(attrs_cache_); +} + +void session::attrs_clear(std::map& attrs) +{ + if (attrs.empty()) + return; + + std::map::iterator it = attrs.begin(); + for (; it != attrs.end(); ++it) + vbuf_free(it->second); + attrs.clear(); +} + +bool session::flush() +{ + if (!dirty_) + return true; + dirty_ = false; + + string buf(256); + + // 调用纯虚接口,获得原来的 sid 数据 + if (get_data(sid_->buf, buf) == true) + { + if (!sid_saved_) + sid_saved_ = true; + deserialize(buf, attrs_); // 反序列化 + } + + std::map::iterator it_cache = attrs_cache_.begin(); + for (; it_cache != attrs_cache_.end(); ++it_cache) + { + // 如果该属性已存在,则需要先释放原来的属性值后再添加新值 + + std::map::iterator it_attr = + attrs_.find(it_cache->first); + if (it_attr == attrs_.end()) + { + if (it_cache->second->todo == TODO_SET) + attrs_[it_cache->first] = it_cache->second; + else + vbuf_free(it_cache->second); + } + else if (it_cache->second->todo == TODO_SET) + { + // 清除旧的数据 + vbuf_free(it_attr->second); + // 设置新的数据 + attrs_[it_cache->first] = it_cache->second; + } + else if (it_cache->second->todo == TODO_DEL) + { + vbuf_free(it_attr->second); + attrs_.erase(it_attr); + vbuf_free(it_cache->second); + } + else + { + logger_warn("unknown todo(%d)", (int) it_cache->second->todo); + vbuf_free(it_cache->second); + } + } + + // 清除缓存的数据:因为内部的数据已经被添加至 attrs_ 中, + // 所以只需要将 attrs_cache_ 空间清除即可 + attrs_cache_.clear(); + + serialize(attrs_, buf); // 序列化数据 + attrs_clear(attrs_); // 清除属性集合数据 + + // 调用纯虚接口,向 memcached 或类似缓存中添加数据 + if (set_data(sid_->buf, buf.c_str(), buf.length(), ttl_) == false) + { + logger_error("set cache error, sid(%s)", sid_->buf); + return false; + } + + if (!sid_saved_) + sid_saved_ = true; + return true; +} + +bool session::set(const char* name, const char* value, + bool delay /* = false */) +{ + return set(name, value, strlen(value), delay); +} + +bool session::set(const char* name, const void* value, size_t len, + bool delay /* = false */) +{ + if (delay) + { + std::map::iterator it = attrs_cache_.find(name); + if (it == attrs_cache_.end()) + attrs_cache_[name] = vbuf_new(value, len, TODO_SET); + else + attrs_cache_[name] = vbuf_set(it->second, value, len, TODO_SET); + dirty_ = true; + return true; + } + + // 直接操作后端 cache 服务器,设置(添加/修改) 属性字段 + + string buf(256); + + // 调用纯虚接口,获得原来的 sid 数据 + if (get_data(sid_->buf, buf) == false) + { + // 如果没有则创建新的 sid 数据 + serialize(name, value, len, buf); + } + + // 如果存在对应 sid 的数据,则将新数据添加在原来数据中 + else + { + if (!sid_saved_) + sid_saved_ = true; + + // 反序列化 + deserialize(buf, attrs_); + + // 如果该属性已存在,则需要先释放原来的属性值后再添加新值 + + std::map::iterator it = attrs_.find(name); + if (it == attrs_.end()) + attrs_[name] = vbuf_new(value, len, TODO_SET); + else + attrs_[name] = vbuf_set(it->second, value, len, TODO_SET); + serialize(attrs_, buf); // 序列化数据 + attrs_clear(attrs_); + } + + // 调用纯虚接口,向 memcached 或类似缓存中添加数据 + if (set_data(sid_->buf, buf.c_str(), buf.length(), ttl_) == false) + { + logger_error("set cache error, sid(%s)", sid_->buf); + return false; + } + if (!sid_saved_) + sid_saved_ = true; + return true; +} + +const char* session::get(const char* name, bool local_cached /* = false */) +{ + const VBUF* bf = get_vbuf(name, local_cached); + if (bf == NULL) + return ""; + return bf->buf; +} + +const VBUF* session::get_vbuf(const char* name, bool local_cached /* = false */) +{ + string buf(256); + if (local_cached == false || attrs_.empty()) + { + if (get_data(sid_->buf, buf) == false) + return NULL; + deserialize(buf, attrs_); + } + std::map::const_iterator cit = attrs_.find(name); + if (cit == attrs_.end()) + return NULL; + return cit->second; +} + +bool session::set_ttl(time_t ttl, bool delay /* = true */) +{ + if (ttl == ttl_) + return true; + + // 如果是延迟修改,则仅设置相关成员变量,最后统一 flush + else if (delay) + { + ttl_ = ttl; + dirty_ = true; + return true; + } + + // 如果该 sid 还没有在后端 cache 上存储过,则仅在对象中本地设置一下 + else if (!sid_saved_) + { + ttl_ = ttl; + return true; + } + + // 修改后端 cache 上针对该 sid 的 ttl + else if (set_timeout(sid_->buf, ttl) == true) + { + ttl_ = ttl; + return true; + } + else + return false; +} + +time_t session::get_ttl() const +{ + return ttl_; +} + +bool session::del(const char* name, bool delay /* = false */) +{ + if (delay) + { + std::map::iterator it = attrs_cache_.find(name); + if (it == attrs_cache_.end()) + attrs_cache_[name] = vbuf_new("", 0, TODO_DEL); + else + it->second->todo = TODO_DEL; + dirty_ = true; + return true; + } + + // 直接操作后端 cache 服务器,删除属性字段 + + string buf(256); + if (get_data(sid_->buf, buf) == false) + return true; + + deserialize(buf, attrs_); + std::map::iterator it = attrs_.find(name); + if (it == attrs_.end()) + return false; + + // 先删除并释放对应的对象 + vbuf_free(it->second); + attrs_.erase(it); + + // 如果 sid 中已经没有了数据,则应该将 sid 对象从 memcached 中删除 + if (attrs_.empty()) + { + // 调用虚函数,删除该 sid 对应的缓存内容 + if (del_data(sid_->buf) == false) + { + logger_error("del sid(%s) error", sid_->buf); + return false; + } + return true; + } + + // 向 memcached 中重新添加剩余的数据 + + serialize(attrs_, buf); + attrs_clear(attrs_); + + if (set_data(sid_->buf, buf.c_str(), buf.length(), ttl_) == false) + { + logger_error("set cache error, sid(%s)", sid_->buf); + return false; + } + return true; +} + +bool session::remove() +{ + // 调用虚函数,删除缓存对象 + if (del_data(sid_->buf) == false) + { + logger_error("invalid sid(%s) error", sid_->buf); + return false; + } + return true; +} + +// 采用 handlersocket 的编码方式 + +void session::serialize(const std::map& attrs, string& out) +{ + out.clear(); // 先清除缓冲区 + + std::map::const_iterator it = attrs.begin(); + if (it == attrs.end()) + return; + + // 添加第一个属性 + const char ch = 1; + escape(it->first.c_str(), it->first.length(), out); + escape(&ch, 1, out); + escape(it->second->buf, it->second->len, out); + ++it; + + // 添加后续的属性 + for (; it != attrs.end(); ++it) + { + // 除第一个属性外后续的都需要添加分隔符 + out << '\t'; + escape(it->first.c_str(), it->first.length(), out); + escape(&ch, 1, out); + escape(it->second->buf, it->second->len, out); + } +} + +void session::serialize(const char* name, const void* value, + size_t len, string& out) +{ + escape(name, strlen(name), out); + const char ch = 1; + escape(&ch, 1, out); + escape((const char*) value, len, out); +} + +// 采用 handlersocket 的解码方式 + +void session::deserialize(string& buf, std::map& attrs) +{ + attrs_clear(attrs); // 先重置 session 前一次查询状态 + + ACL_ARGV* tokens = acl_argv_split(buf.c_str(), "\t"); + ACL_ITER iter; + acl_foreach(iter, tokens) + { + char* ptr = (char*) iter.data; + + // 重复使用原来的内存区,因为 tokens 中已经存储了中间结果数据 + buf.clear(); + if (unescape(ptr, strlen(ptr), buf) == false) + { + logger_error("unescape error"); + continue; + } + ptr = buf.c_str(); + // 因为 acl::string 肯定能保证缓冲区数据的尾部有 \0,所以在用 + // strchr 时不必须担心越界问题,但 std::string 并不保证这样 + char* p1 = strchr(ptr, 1); + if (p1 == NULL || *(p1 + 1) == 0) + continue; + *p1++ = 0; + std::map::iterator it = attrs.find(ptr); + + // xxx: 以防有重复的属性 + if (it != attrs.end()) + vbuf_free(it->second); + // 将从后端取得数据属性都设为 TODO_SET + attrs[ptr] = vbuf_new(p1, buf.length() - (p1 - buf.c_str()), TODO_SET); + } + + acl_argv_free(tokens); +} + +} // namespace acl diff --git a/lib_acl_cpp/src/stdlib/charset_conv.cpp b/lib_acl_cpp/src/stdlib/charset_conv.cpp new file mode 100644 index 000000000..ec3018c09 --- /dev/null +++ b/lib_acl_cpp/src/stdlib/charset_conv.cpp @@ -0,0 +1,556 @@ +#include "acl_stdafx.hpp" +#include + +#ifndef HAVE_H_ICONV +# define HAVE_H_ICONV +#endif + +#ifdef HAVE_H_ICONV +# ifndef USE_WIN_ICONV +# include +# endif +#endif + +#include "acl_cpp/stdlib/string.hpp" +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/stdlib/charset_conv.hpp" + +#define SCOPY ACL_SAFE_STRNCPY + +static const char UTF8_HEADER[] = { (char) 0xEF, (char) 0xBB, (char) 0xBF, (char) 0x00 }; + +#ifdef HAVE_H_ICONV +# ifdef USE_WIN_ICONV +# include "internal/win_iconv.hpp" +# define __iconv_open iconv_open +# define __iconv_close iconv_close +# define __iconv iconv +# elif defined(WIN32) + typedef iconv_t (*iconv_open_fn)(const char*, const char*); + typedef int (*iconv_close_fn)(iconv_t); + typedef size_t (*iconv_fn)(iconv_t, const char**, size_t*, char**, size_t*, int*); + typedef int (*iconvctl_fn)(iconv_t, int, void*); + + static iconv_open_fn __iconv_open = NULL; + static iconv_close_fn __iconv_close = NULL; + static iconv_fn __iconv = NULL; + static iconvctl_fn __iconvctl = NULL; + + static acl_pthread_once_t __iconv_once = ACL_PTHREAD_ONCE_INIT; + static ACL_DLL_HANDLE __iconv_dll = NULL; + + // 程序退出时释放动态加载的 iconv.dll 库 + static void __iconv_dll_unload(void) + { + if (__iconv_dll != NULL) + { + acl_dlclose(__iconv_dll); + __iconv_dll = NULL; + logger("iconv.dll unload ok"); + } + } + + // 动态加载 iconv.dll 库 + static void __iconv_dll_load(void) + { + if (__iconv_dll != NULL) + logger_fatal("__iconv_dll not null"); + + __iconv_dll = acl_dlopen("iconv.dll"); + if (__iconv_dll == NULL) + logger_fatal("load iconv.dll error: %s", acl_last_serror()); + + __iconv_open = (iconv_open_fn) acl_dlsym(__iconv_dll, "libiconv_open"); + if (__iconv_open == NULL) + logger_fatal("load iconv_open from iconv.dll error: %s", + acl_last_serror()); + + __iconv_close = (iconv_close_fn) acl_dlsym(__iconv_dll, "libiconv_close"); + if (__iconv_close == NULL) + logger_fatal("load iconv_close from iconv.dll error: %s", + acl_last_serror()); + + __iconv = (iconv_fn) acl_dlsym(__iconv_dll, "libiconv"); + if (__iconv == NULL) + logger_fatal("load iconv from iconv.dll error: %s", + acl_last_serror()); + + __iconvctl = (iconvctl_fn) acl_dlsym(__iconv_dll, "libiconvctl"); + if (__iconvctl == NULL) + logger_fatal("load iconvctl from iconv.dll error: %s", + acl_last_serror()); + + logger("iconv.dll loaded"); + atexit(__iconv_dll_unload); + } +# else +# define __iconv_open iconv_open +# define __iconv_close iconv_close +# define __iconv iconv +# define __iconvctl iconvctl +# endif +#endif + +namespace acl { + +#define EQ(x, y) !strcasecmp((x), (y)) + +charset_conv::charset_conv() + : m_addInvalid(true) + , m_errmsg("ok") + , m_pBuf(NULL) +{ + m_fromCharset[0] = 0; + m_toCharset[0] = 0; +#ifdef HAVE_H_ICONV + m_iconv = (iconv_t) -1; + m_pInBuf = NULL; + m_pOutBuf = NULL; +# ifdef WIN32 +# ifndef USE_WIN_ICONV + acl_pthread_once(&__iconv_once, __iconv_dll_load); +# endif +# endif +#endif +} + +charset_conv::~charset_conv() +{ +#ifdef HAVE_H_ICONV + if (m_iconv != (iconv_t) -1) + __iconv_close(m_iconv); + if (m_pInBuf) + acl_vstring_free(m_pInBuf); + if (m_pOutBuf) + acl_vstring_free(m_pOutBuf); +#endif + if (m_pBuf) + delete m_pBuf; +} + +void charset_conv::set_add_invalid(bool onoff) +{ + m_addInvalid = onoff; +} + +const char* charset_conv::serror() const +{ + return (m_errmsg.c_str()); +} + +void charset_conv::reset() +{ + m_errmsg = "ok"; + +#ifdef HAVE_H_ICONV + if (m_iconv != (iconv_t) -1) + { + __iconv_close(m_iconv); + m_iconv = (iconv_t) - 1; + } + m_fromCharset[0] = 0; + m_toCharset[0] = 0; +#endif +} + +bool charset_conv::convert(const char* fromCharset, const char* toCharset, + const char* in, size_t n, acl::string* out) +{ + if (fromCharset == NULL || toCharset == NULL + || in == NULL || n == 0 || out == NULL) + { + m_errmsg = "params invalid"; + return (false); + } + + if (update_begin(fromCharset, toCharset) == false) + { + reset(); + return (false); + } + if (update(in, n, out) == false) + { + reset(); + return (false); + } + update_finish(out); + return (true); +} + +#define STR acl_vstring_str +#define LEN ACL_VSTRING_LEN +#define SIZE ACL_VSTRING_SIZE +#define EQ2(x, y) (((x) == NULL && (y) == NULL) \ + || ((x) != NULL && (y) != NULL && !strcasecmp((x), (y)))) + +bool charset_conv::update_begin(const char* fromCharset, + const char* toCharset) +{ +#ifdef HAVE_H_ICONV + if (EQ2(fromCharset, toCharset)) + return (true); + + if (fromCharset == NULL || toCharset == NULL) + { + if (m_iconv != (iconv_t) -1) + return (true); + + logger_error("input invalid, from: %s, to: %s, m_conv: %s", + fromCharset ? fromCharset : "null", + toCharset ? toCharset : "null", + m_iconv == (iconv_t) -1 ? "invalid" : "valud"); + m_errmsg = "input invalid"; + return (false); + } + + // 如果源是 UTF-8 编码,则 m_pTuf8Pre 从 UTF8_HEADER 头部第 + // 一个字节开始进行匹配,否则从最后一个字节 '\0' 开始匹配, + // 即跳过 UTF-8 头部匹配过程 + if (EQ(fromCharset, "utf-8") || EQ(fromCharset, "utf8")) + m_pUtf8Pre = UTF8_HEADER; + else + m_pUtf8Pre = &UTF8_HEADER[3]; + + if (m_iconv != (iconv_t) -1 + && EQ(m_fromCharset, fromCharset) + && EQ(m_toCharset, toCharset)) + { + return (true); + } + + SCOPY(m_fromCharset, fromCharset, sizeof(m_fromCharset)); + SCOPY(m_toCharset, toCharset, sizeof(m_toCharset)); + + if (m_iconv != (iconv_t) -1) + __iconv_close(m_iconv); + m_iconv = __iconv_open(toCharset, fromCharset); + if (m_iconv == (iconv_t) -1) + { + logger_error("iconv_open(%s, %s) error(%s)", + toCharset, fromCharset, acl_last_serror()); + m_errmsg.format("iconv_open(%s, %s) error(%s)", + toCharset, fromCharset, acl_last_serror()); + return (false); + } + else + { +#ifdef WIN32 +# ifndef USE_WIN_ICONV + int n = 1; + __iconvctl(m_iconv, ICONV_TRIVIALP, &n); + + n = 1; + __iconvctl(m_iconv, ICONV_SET_DISCARD_ILSEQ, &n); + + n = 1; + __iconvctl(m_iconv, ICONV_SET_TRANSLITERATE, &n); +# endif // USE_WIN_ICONV +#endif + + char *pNil = NULL; + size_t zero = 0; +#ifdef WIN32 +# ifdef USE_WIN_ICONV + __iconv(m_iconv, (const char**) &pNil, &zero, &pNil, &zero); +# else + __iconv(m_iconv, (const char**) &pNil, &zero, &pNil, &zero, NULL); +# endif // USE_WIN_ICONV +#else // WIN32 + __iconv(m_iconv, &pNil, &zero, &pNil, &zero); +#endif + return (true); + } +#else + logger_error("no iconv lib"); + m_errmsg = "no iconv lib"; + return (false); +#endif +} + +bool charset_conv::update(const char* in, size_t len, acl::string* out) +{ +#ifdef HAVE_H_ICONV + if (in == NULL) + logger_fatal("in null"); + if (out == NULL) + logger_fatal("out null"); + + if (EQ(m_fromCharset, m_toCharset)) + { + out->append(in, len); + return (true); + } + + if (m_iconv == (iconv_t) -1) + { + logger_error("m_iconv invalid"); + m_errmsg = "m_iconv invalid"; + return (false); + } + + // 去掉有些 UTF-8 文档中开始的 UTF-8 引导符 + if (*m_pUtf8Pre) + { + while (len > 0) + { + if (*m_pUtf8Pre == 0x00) + break; + else if (*m_pUtf8Pre != *in) + { + // 必须使 UTF-8 前缀失效 + m_pUtf8Pre = &UTF8_HEADER[3]; + break; + } + m_pUtf8Pre++; + in++; + len--; + } + } + + if (len == 0) + return (true); + + if (m_pInBuf == NULL) + m_pInBuf = acl_vstring_alloc(len); + + if (m_pOutBuf == NULL) + m_pOutBuf = acl_vstring_alloc(len); + else + ACL_VSTRING_SPACE(m_pOutBuf, len); + + // 先将输入数据进行缓冲 + if (*m_pUtf8Pre && m_pUtf8Pre - UTF8_HEADER > 0) + acl_vstring_memcpy(m_pInBuf, UTF8_HEADER, + m_pUtf8Pre - UTF8_HEADER); + acl_vstring_memcat(m_pInBuf, in, len); + ACL_VSTRING_TERMINATE(m_pInBuf); + + char *pIn, *pOut; + size_t ret, nIn, nOut; + + while (true) + { + nIn = LEN(m_pInBuf); + if (nIn == 0) + break; + pIn = STR(m_pInBuf); + pOut = STR(m_pOutBuf); + nOut = SIZE(m_pOutBuf); + +#ifdef WIN32 +# ifdef USE_WIN_ICONV + ret = __iconv(m_iconv, (const char**) &pIn, &nIn, &pOut, &nOut); +# else + int err; + ret = __iconv(m_iconv, (const char**) &pIn, &nIn, &pOut, &nOut, &err); + errno = err; +# endif // USE_WIN_ICONV +#else + ret = __iconv(m_iconv, &pIn, &nIn, &pOut, &nOut); +#endif + + + if (ret != (size_t) -1) + { + if ((ret = SIZE(m_pOutBuf) - nOut) > 0) + out->append(STR(m_pOutBuf), ret); + else // xxx + out->append(in, len); + ACL_VSTRING_RESET(m_pInBuf); + break; + } + else if (errno == E2BIG) + { + if ((ret = SIZE(m_pOutBuf) - nOut) > 0) + out->append(STR(m_pOutBuf), ret); + if (pIn > STR(m_pInBuf) && nIn < LEN(m_pInBuf)) + acl_vstring_memmove(m_pInBuf, pIn, nIn); + // 扩大内存空间 + ACL_VSTRING_SPACE(m_pOutBuf, SIZE(m_pOutBuf) * 2); + continue; + } + else if (errno == EILSEQ) + { + char *pNil = NULL; + size_t zero = 0; + + // 重置状态, 似乎也没啥用处 +#ifdef WIN32 +# ifdef USE_WIN_ICONV + __iconv(m_iconv, (const char**) &pNil, &zero, &pNil, &zero); +# else + __iconv(m_iconv, (const char**) &pNil, &zero, &pNil, &zero, NULL); +# endif +#else + __iconv(m_iconv, &pNil, &zero, &pNil, &zero); +#endif + + // 遇到无效的多字节序列,pIn 指向第一个无效的位置 + + // 先拷贝已经转换的数据 + if ((ret = SIZE(m_pOutBuf) - nOut) > 0) + out->append(STR(m_pOutBuf), ret); + + if (nIn == 0) + { + ACL_VSTRING_RESET(m_pInBuf); + break; + } + + acl_assert(pIn >= STR(m_pInBuf)); + + // 跳过无效字节 + (*out) += (char)(*pIn); // 直接拷贝无效字节 + nIn--; + pIn++; + if (nIn > 0) + acl_vstring_memmove(m_pInBuf, pIn, nIn); + else + ACL_VSTRING_RESET(m_pInBuf); + } + else if (errno == EINVAL) + { + char *pNil = NULL; + size_t zero = 0; + + // 重置状态, 似乎也没啥用处 +#ifdef WIN32 +# ifdef USE_WIN_ICONV + __iconv(m_iconv, (const char**) &pNil, &zero, &pNil, &zero); +# else + __iconv(m_iconv, (const char**) &pNil, &zero, &pNil, &zero, NULL); +# endif // USE_WIN_ICONV +#else + __iconv(m_iconv, &pNil, &zero, &pNil, &zero); +#endif + + // 输入的多字节序列不完整,pIn 指向该不完整的位置 + + // 先拷贝已经转换的数据 + if ((ret = SIZE(m_pOutBuf) - nOut) > 0) + out->append(STR(m_pOutBuf), ret); + + // 移动数据,将未转换的数据移至缓冲区起始位置 + if (nIn > 0) + acl_vstring_memmove(m_pInBuf, pIn, nIn); + else + ACL_VSTRING_RESET(m_pInBuf); + break; + } + else if (LEN(m_pInBuf) > 0) + { + // 如果遇到了无效的字符集,根据设置的标志位 + // 决定是否直接拷贝 + if (m_addInvalid) + { + out->append(STR(m_pInBuf), LEN(m_pInBuf)); + ACL_VSTRING_RESET(m_pInBuf); + } + break; + } + else + break; + } + + return (true); +#else + (void) in; + (void) len; + (void) out; + logger_error("no iconv lib"); + m_errmsg = "no iconv lib"; + return (false); +#endif +} + +void charset_conv::update_finish(acl::string* out) +{ +#ifdef HAVE_H_ICONV + if (m_pInBuf && LEN(m_pInBuf) > 0 && m_addInvalid) + { + out->append(STR(m_pInBuf), LEN(m_pInBuf)); + ACL_VSTRING_RESET(m_pInBuf); + } +#endif +} + +int charset_conv::push_pop(const char* in, size_t len, + acl::string* out, size_t max /* = 0 */) +{ + if (m_pBuf == NULL) + m_pBuf = NEW acl::string(1024); + + if (in && len > 0 && update(in, len, m_pBuf) == false) + return (-1); + + len = m_pBuf->length(); + if (len == 0) + return (0); + + size_t n; + if (max > 0) + n = max > len ? len : max; + else + n = len; + + out->append(m_pBuf->c_str(), n); + + if (len > n) + m_pBuf->memmove(m_pBuf->c_str() + n, len - n); + else + m_pBuf->clear(); + + return (n); +} + +int charset_conv::pop_end(acl::string* out, size_t max /* = 0 */) +{ + if (m_pBuf == NULL) + { + logger_error("call push_pop first"); + return (-1); + } + + update_finish(m_pBuf); + + if (out == NULL) + { + m_pBuf->clear(); + return (0); + } + + size_t n = m_pBuf->length(); + if (n == 0) + return (0); + if (max > 0 && n > max) + n = max; + out->append(m_pBuf->c_str(), m_pBuf->length()); + m_pBuf->clear(); + return (n); +} + +void charset_conv::clear() +{ + if (m_pBuf) + m_pBuf->clear(); +} + +// 获得字符集转换器 +charset_conv* charset_conv::create(const char* fromCharset, + const char* toCharset) +{ + if (fromCharset == NULL || toCharset == NULL) + return (NULL); + if (strcasecmp(fromCharset, toCharset) == 0) + return (NULL); + + charset_conv* conv = NEW charset_conv(); + if (conv->update_begin(fromCharset, toCharset) == false) + { + delete conv; + return (NULL); + } + return (conv); +} + +} // namespace acl diff --git a/lib_acl_cpp/src/stdlib/dns_service.cpp b/lib_acl_cpp/src/stdlib/dns_service.cpp new file mode 100644 index 000000000..dd03384b9 --- /dev/null +++ b/lib_acl_cpp/src/stdlib/dns_service.cpp @@ -0,0 +1,235 @@ +#include "acl_stdafx.hpp" +#include "lib_acl.h" +#include +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/stdlib/string.hpp" +#include "acl_cpp/ipc/ipc_client.hpp" +#include "acl_cpp/ipc/ipc_service.hpp" +#include "acl_cpp/stdlib/dns_service.hpp" + +namespace acl +{ + +struct DNS_IPC_DATA +{ + dns_res* res; +}; + + +enum +{ + IPC_REQ, + IPC_RES +}; + +/////////////////////////////////////////////////////////////////////// + +class dns_request : public ipc_request +{ +public: + dns_request(const char* domain) + : domain_(domain) + { + + } + + ~dns_request() + { + + } + + virtual void run(ipc_client* ipc) + { + ACL_DNS_DB* db = acl_gethostbyname(domain_.c_str(), NULL); + data_.res = NEW dns_res(domain_.c_str()); + + if (db != NULL) + { + ACL_ITER iter; + acl_foreach(iter, db) + { + ACL_HOSTNAME* hn = (ACL_HOSTNAME*) iter.data; + data_.res->ips_.push_back(hn->ip); + } + + acl_netdb_free(db); + } + + // 向主线程发送结果 + ipc->send_message(IPC_RES, &data_, sizeof(data_)); + + // 销毁本类对象,因为其是动态分配的 + delete this; + } + +#ifdef WIN32 + + // 基类虚接口,使子线程可以在执行完任务后向主线程发送 WIN32 窗口消息 + + virtual void run(HWND hWnd) + { + ACL_DNS_DB* db = acl_gethostbyname(domain_.c_str(), NULL); + DNS_IPC_DATA* data = (DNS_IPC_DATA*) + acl_mymalloc(sizeof(DNS_IPC_DATA)); + data->res = NEW dns_res(domain_.c_str()); + + if (db != NULL) + { + ACL_ITER iter; + acl_foreach(iter, db) + { + ACL_HOSTNAME* hn = (ACL_HOSTNAME*) iter.data; + data->res->ips_.push_back(hn->ip); + } + + acl_netdb_free(db); + } + + // 向主线程发送结果 + ::PostMessage(hWnd, IPC_RES + WM_USER, 0, (LPARAM) data); + + // 销毁本类对象,因为其是动态分配的 + delete this; + } +#endif +private: + string domain_; + DNS_IPC_DATA data_; +}; + +/////////////////////////////////////////////////////////////////////// + +class dns_ipc : public ipc_client +{ +public: + dns_ipc(dns_service* server) + : server_(server) + { + + } + + ~dns_ipc() + { + + } + + virtual void on_message(int nMsg acl_unused, + void* data, int dlen acl_unused) + { + if (nMsg != IPC_RES) + { + logger_error("invalid nMsg(%d)", nMsg); + this->close(); + return; + } + + DNS_IPC_DATA* dat = (DNS_IPC_DATA*) data; + dns_res* res = dat->res; + + server_->on_result(*res); + delete res; + } +protected: + virtual void on_close() + { + delete this; + } +private: + dns_service* server_; +}; + +/////////////////////////////////////////////////////////////////////// + +dns_service::dns_service(int nthread /* = 1 */, bool win32_gui /* = false */) + : ipc_service(nthread, win32_gui) +{ + +} + +dns_service::~dns_service() +{ + +} + +void dns_service::on_accept(aio_socket_stream* client) +{ + ipc_client* ipc = NEW dns_ipc(this); + ipc->open(client); + + // 添加消息回调对象 + ipc->append_message(IPC_RES); + ipc->wait(); +} + +#ifdef WIN32 + +void dns_service::win32_proc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam) +{ + if (nMsg != IPC_RES + WM_USER) + { + logger_error("invalid nMsg(%d)", nMsg); + return; + } + else if (lParam == 0) + { + logger_error("lParam invalid"); + return; + } + + DNS_IPC_DATA* dat = (DNS_IPC_DATA*) lParam; + dns_res* res = dat->res; + + on_result(*res); + delete res; + + // 在采用 WIN32 消息时该对象空间是动态分配的,所以需要释放 + acl_myfree(dat); +} + +#endif + +void dns_service::lookup(dns_result_callback* callback) +{ + std::list::iterator it; + const char* domain = callback->get_domain().c_str(); + + for (it= callbacks_.begin(); it != callbacks_.end(); ++it) + { + if ((*it)->get_domain() == domain) + { + callbacks_.push_back(callback); + return; + } + } + + callbacks_.push_back(callback); + + ipc_request* req = NEW dns_request(domain); + + // 调用基类 ipc_service 请求过程 + request(req); +} + +void dns_service::on_result(const dns_res& res) +{ + std::list::iterator it, next; + + it= callbacks_.begin(); + for (; it != callbacks_.end();) + { + next = it; + ++next; + if ((*it)->get_domain() == res.domain_.c_str()) + { + // 通知请求对象的解析结果 + (*it)->on_result((*it)->get_domain(), res); + (*it)->destroy(); // 调用请求对象的销毁过程 + callbacks_.erase(it); + it = next; + } + else + ++it; + } +} + +} // namespace acl diff --git a/lib_acl_cpp/src/stdlib/escape.cpp b/lib_acl_cpp/src/stdlib/escape.cpp new file mode 100644 index 000000000..61a3d781a --- /dev/null +++ b/lib_acl_cpp/src/stdlib/escape.cpp @@ -0,0 +1,59 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/stdlib/string.hpp" +#include "acl_cpp/stdlib/escape.hpp" + +namespace acl +{ + +enum { + escape_prefix = 0x01, + noescape_min = 0x10, + escape_shift = 0x40, +}; + +void escape(const char* in, size_t len, acl::string& out) +{ + char ch; + + while (len > 0) + { + ch = *in; + if (ch >= noescape_min) + out << ch; + else + { + out << (char) escape_prefix; + out << (char) (ch + escape_shift); + } + in++; + len--; + } +} + +bool unescape(const char* in, size_t len, acl::string& out) +{ + char ch; + + while (len > 0) + { + ch = *in; + if (ch != escape_prefix) + out << ch; + else if (*++in == 0) + return (false); + else + { + ch = *in; + if (ch < escape_shift) + return (false); + ch -= escape_shift; + out << ch; + } + in++; + len--; + } + + return (true); +} + +} // namespace acl diff --git a/lib_acl_cpp/src/stdlib/internal/win_iconv.cpp b/lib_acl_cpp/src/stdlib/internal/win_iconv.cpp new file mode 100644 index 000000000..a93eb5dd6 --- /dev/null +++ b/lib_acl_cpp/src/stdlib/internal/win_iconv.cpp @@ -0,0 +1,1956 @@ +/* + * iconv library implemented with Win32 API. + * + * This file is placed in the public domain. + * + * Maintainer: Yukihiro Nakadaira + * + * If $WINICONV_LIBICONV_DLL environment variable was defined, win_iconv + * loads the specified DLL dynamically and uses it. If loading the DLL + * or iconv_open() failed, falls back to internal conversion. + * $WINICONV_LIBICONV_DLL is a comma separated list. The first loadable + * DLL is used. The specified DLL should have iconv_open(), + * iconv_close() and iconv() functions. Or these functions can be + * libiconv_open(), libiconv_close() and libiconv(). + * + * Win32 API does not support strict encoding conversion for some + * codepage. And MLang function drop or replace invalid bytes and does + * not return useful error status as iconv. This implementation cannot + * be used for encoding validation purpose. + */ +#include "acl_stdafx.hpp" + +#ifdef WIN32 +#ifdef USE_WIN_ICONV +#include "win_iconv.hpp" + +/* for WC_NO_BEST_FIT_CHARS */ +#ifndef WINVER +# define WINVER 0x0500 +#endif + +//#define STRICT +#include +#include +#include +#include + +#if 0 +# define MAKE_EXE +# define MAKE_DLL +# define USE_LIBICONV_DLL +#endif + +#if !defined(DEFAULT_LIBICONV_DLL) +# define DEFAULT_LIBICONV_DLL "" +#endif + +#define MB_CHAR_MAX 16 + +#define UNICODE_MODE_BOM_DONE 1 +#define UNICODE_MODE_SWAPPED 2 + +#define FLAG_USE_BOM_ENDIAN 1 +#define FLAG_TRANSLIT 2 /* //TRANSLIT */ +#define FLAG_IGNORE 4 /* //IGNORE (not implemented) */ + +#define return_error(code) \ + do { \ + errno = code; \ + return -1; \ + } while (0) + +#define xstrlcpy(dst, src, size) \ + do { \ + strncpy(dst, src, size); \ + dst[size - 1] = 0; \ + } while (0) + +#define xstrlcpyn(dst, src, srclen, size) \ + xstrlcpy(dst, src, xmin((srclen) + 1, size)) + +#define xmin(a, b) ((a) < (b) ? (a) : (b)) +#define xmax(a, b) ((a) > (b) ? (a) : (b)) + +#define STATIC_STRLEN(arr) (sizeof(arr) - 1) + +typedef unsigned char uchar; +typedef unsigned short ushort; +typedef unsigned int uint; + +/* libiconv interface for vim */ +#if defined(MAKE_DLL) +int +iconvctl (iconv_t cd, int request, void* argument) +{ + /* not supported */ + return 0; +} +#endif + +typedef struct compat_t compat_t; +typedef struct csconv_t csconv_t; +typedef struct rec_iconv_t rec_iconv_t; + +typedef iconv_t (*f_iconv_open)(const char *tocode, const char *fromcode); +typedef int (*f_iconv_close)(iconv_t cd); +typedef size_t (*f_iconv)(iconv_t cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft); +typedef int* (*f_errno)(void); +typedef int (*f_mbtowc)(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize); +typedef int (*f_wctomb)(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize); +typedef int (*f_mblen)(csconv_t *cv, const uchar *buf, int bufsize); +typedef int (*f_flush)(csconv_t *cv, uchar *buf, int bufsize); + +#define COMPAT_IN 1 +#define COMPAT_OUT 2 + +/* unicode mapping for compatibility with other conversion table. */ +struct compat_t { + uint in; + uint out; + uint flag; +}; + +struct csconv_t { + int codepage; + int flags; + f_mbtowc mbtowc; + f_wctomb wctomb; + f_mblen mblen; + f_flush flush; + DWORD mode; + compat_t *compat; +}; + +struct rec_iconv_t { + iconv_t cd; + f_iconv_close iconv_close; + f_iconv iconv; + f_errno _errno; + csconv_t from; + csconv_t to; +#if defined(USE_LIBICONV_DLL) + HMODULE hlibiconv; +#endif +}; + +static int win_iconv_open(rec_iconv_t *cd, const char *tocode, const char *fromcode); +static int win_iconv_close(iconv_t cd); +static size_t win_iconv(iconv_t cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft); + +static int load_mlang(); +static csconv_t make_csconv(const char *name); +static int name_to_codepage(const char *name); +static uint utf16_to_ucs4(const ushort *wbuf); +static void ucs4_to_utf16(uint wc, ushort *wbuf, int *wbufsize); +static int is_unicode(int codepage); +static int mbtowc_flags(int codepage); +static int must_use_null_useddefaultchar(int codepage); +static void check_utf_bom(rec_iconv_t *cd, ushort *wbuf, int *wbufsize); +static char *strrstr(const char *str, const char *token); + +#if defined(USE_LIBICONV_DLL) +static int libiconv_iconv_open(rec_iconv_t *cd, const char *tocode, const char *fromcode); +static PVOID MyImageDirectoryEntryToData(LPVOID Base, BOOLEAN MappedAsImage, USHORT DirectoryEntry, PULONG Size); +static HMODULE find_imported_module_by_funcname(HMODULE hModule, const char *funcname); + +static HMODULE hwiniconv; +static HMODULE hlastdll; /* keep dll loaded for efficiency (unnecessary?) */ +#endif + +static int sbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize); +static int dbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize); +static int mbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize); +static int utf8_mblen(csconv_t *cv, const uchar *buf, int bufsize); +static int eucjp_mblen(csconv_t *cv, const uchar *buf, int bufsize); + +static int kernel_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize); +static int kernel_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize); +static int mlang_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize); +static int mlang_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize); +static int utf16_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize); +static int utf16_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize); +static int utf32_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize); +static int utf32_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize); +static int iso2022jp_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize); +static int iso2022jp_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize); +static int iso2022jp_flush(csconv_t *cv, uchar *buf, int bufsize); + +static struct { + int codepage; + const char *name; +} codepage_alias[] = { + {65001, "CP65001"}, + {65001, "UTF8"}, + {65001, "UTF-8"}, + + {1200, "CP1200"}, + {1200, "UTF16LE"}, + {1200, "UTF-16LE"}, + {1200, "UCS2LE"}, + {1200, "UCS-2LE"}, + + {1201, "CP1201"}, + {1201, "UTF16BE"}, + {1201, "UTF-16BE"}, + {1201, "UCS2BE"}, + {1201, "UCS-2BE"}, + {1201, "unicodeFFFE"}, + + {12000, "CP12000"}, + {12000, "UTF32LE"}, + {12000, "UTF-32LE"}, + {12000, "UCS4LE"}, + {12000, "UCS-4LE"}, + + {12001, "CP12001"}, + {12001, "UTF32BE"}, + {12001, "UTF-32BE"}, + {12001, "UCS4BE"}, + {12001, "UCS-4BE"}, + +#ifndef GLIB_COMPILATION + /* + * Default is big endian. + * See rfc2781 4.3 Interpreting text labelled as UTF-16. + */ + {1201, "UTF16"}, + {1201, "UTF-16"}, + {12001, "UTF32"}, + {12001, "UTF-32"}, + {12001, "UCS-4"}, + {12001, "UCS4"}, +#else + /* Default is little endian, because the platform is */ + {1200, "UTF16"}, + {1200, "UTF-16"}, + {1200, "UCS2"}, + {1200, "UCS-2"}, + {12000, "UTF32"}, + {12000, "UTF-32"}, + {12000, "UCS4"}, + {12000, "UCS-4"}, +#endif + + /* copy from libiconv `iconv -l` */ + /* !IsValidCodePage(367) */ + {20127, "ANSI_X3.4-1968"}, + {20127, "ANSI_X3.4-1986"}, + {20127, "ASCII"}, + {20127, "CP367"}, + {20127, "IBM367"}, + {20127, "ISO-IR-6"}, + {20127, "ISO646-US"}, + {20127, "ISO_646.IRV:1991"}, + {20127, "US"}, + {20127, "US-ASCII"}, + {20127, "CSASCII"}, + + /* !IsValidCodePage(819) */ + {1252, "CP819"}, + {1252, "IBM819"}, + {28591, "ISO-8859-1"}, + {28591, "ISO-IR-100"}, + {28591, "ISO8859-1"}, + {28591, "ISO_8859-1"}, + {28591, "ISO_8859-1:1987"}, + {28591, "L1"}, + {28591, "LATIN1"}, + {28591, "CSISOLATIN1"}, + + {1250, "CP1250"}, + {1250, "MS-EE"}, + {1250, "WINDOWS-1250"}, + + {1251, "CP1251"}, + {1251, "MS-CYRL"}, + {1251, "WINDOWS-1251"}, + + {1252, "CP1252"}, + {1252, "MS-ANSI"}, + {1252, "WINDOWS-1252"}, + + {1253, "CP1253"}, + {1253, "MS-GREEK"}, + {1253, "WINDOWS-1253"}, + + {1254, "CP1254"}, + {1254, "MS-TURK"}, + {1254, "WINDOWS-1254"}, + + {1255, "CP1255"}, + {1255, "MS-HEBR"}, + {1255, "WINDOWS-1255"}, + + {1256, "CP1256"}, + {1256, "MS-ARAB"}, + {1256, "WINDOWS-1256"}, + + {1257, "CP1257"}, + {1257, "WINBALTRIM"}, + {1257, "WINDOWS-1257"}, + + {1258, "CP1258"}, + {1258, "WINDOWS-1258"}, + + {850, "850"}, + {850, "CP850"}, + {850, "IBM850"}, + {850, "CSPC850MULTILINGUAL"}, + + /* !IsValidCodePage(862) */ + {862, "862"}, + {862, "CP862"}, + {862, "IBM862"}, + {862, "CSPC862LATINHEBREW"}, + + {866, "866"}, + {866, "CP866"}, + {866, "IBM866"}, + {866, "CSIBM866"}, + + /* !IsValidCodePage(154) */ + {154, "CP154"}, + {154, "CYRILLIC-ASIAN"}, + {154, "PT154"}, + {154, "PTCP154"}, + {154, "CSPTCP154"}, + + /* !IsValidCodePage(1133) */ + {1133, "CP1133"}, + {1133, "IBM-CP1133"}, + + {874, "CP874"}, + {874, "WINDOWS-874"}, + + /* !IsValidCodePage(51932) */ + {51932, "CP51932"}, + {51932, "MS51932"}, + {51932, "WINDOWS-51932"}, + {51932, "EUC-JP"}, + + {932, "CP932"}, + {932, "MS932"}, + {932, "SHIFFT_JIS"}, + {932, "SHIFFT_JIS-MS"}, + {932, "SJIS"}, + {932, "SJIS-MS"}, + {932, "SJIS-OPEN"}, + {932, "SJIS-WIN"}, + {932, "WINDOWS-31J"}, + {932, "WINDOWS-932"}, + {932, "CSWINDOWS31J"}, + + {50221, "CP50221"}, + {50221, "ISO-2022-JP"}, + {50221, "ISO-2022-JP-MS"}, + {50221, "ISO2022-JP"}, + {50221, "ISO2022-JP-MS"}, + {50221, "MS50221"}, + {50221, "WINDOWS-50221"}, + + {936, "CP936"}, + {936, "GBK"}, + {936, "MS936"}, + {936, "WINDOWS-936"}, + + {950, "CP950"}, + {950, "BIG5"}, + + {949, "CP949"}, + {949, "UHC"}, + {949, "EUC-KR"}, + + {1361, "CP1361"}, + {1361, "JOHAB"}, + + {437, "437"}, + {437, "CP437"}, + {437, "IBM437"}, + {437, "CSPC8CODEPAGE437"}, + + {737, "CP737"}, + + {775, "CP775"}, + {775, "IBM775"}, + {775, "CSPC775BALTIC"}, + + {852, "852"}, + {852, "CP852"}, + {852, "IBM852"}, + {852, "CSPCP852"}, + + /* !IsValidCodePage(853) */ + {853, "CP853"}, + + {855, "855"}, + {855, "CP855"}, + {855, "IBM855"}, + {855, "CSIBM855"}, + + {857, "857"}, + {857, "CP857"}, + {857, "IBM857"}, + {857, "CSIBM857"}, + + /* !IsValidCodePage(858) */ + {858, "CP858"}, + + {860, "860"}, + {860, "CP860"}, + {860, "IBM860"}, + {860, "CSIBM860"}, + + {861, "861"}, + {861, "CP-IS"}, + {861, "CP861"}, + {861, "IBM861"}, + {861, "CSIBM861"}, + + {863, "863"}, + {863, "CP863"}, + {863, "IBM863"}, + {863, "CSIBM863"}, + + {864, "CP864"}, + {864, "IBM864"}, + {864, "CSIBM864"}, + + {865, "865"}, + {865, "CP865"}, + {865, "IBM865"}, + {865, "CSIBM865"}, + + {869, "869"}, + {869, "CP-GR"}, + {869, "CP869"}, + {869, "IBM869"}, + {869, "CSIBM869"}, + + /* !IsValidCodePage(1152) */ + {1125, "CP1125"}, + + /* + * Code Page Identifiers + * http://msdn2.microsoft.com/en-us/library/ms776446.aspx + */ + {37, "IBM037"}, /* IBM EBCDIC US-Canada */ + {437, "IBM437"}, /* OEM United States */ + {500, "IBM500"}, /* IBM EBCDIC International */ + {708, "ASMO-708"}, /* Arabic (ASMO 708) */ + /* 709 Arabic (ASMO-449+, BCON V4) */ + /* 710 Arabic - Transparent Arabic */ + {720, "DOS-720"}, /* Arabic (Transparent ASMO); Arabic (DOS) */ + {737, "ibm737"}, /* OEM Greek (formerly 437G); Greek (DOS) */ + {775, "ibm775"}, /* OEM Baltic; Baltic (DOS) */ + {850, "ibm850"}, /* OEM Multilingual Latin 1; Western European (DOS) */ + {852, "ibm852"}, /* OEM Latin 2; Central European (DOS) */ + {855, "IBM855"}, /* OEM Cyrillic (primarily Russian) */ + {857, "ibm857"}, /* OEM Turkish; Turkish (DOS) */ + {858, "IBM00858"}, /* OEM Multilingual Latin 1 + Euro symbol */ + {860, "IBM860"}, /* OEM Portuguese; Portuguese (DOS) */ + {861, "ibm861"}, /* OEM Icelandic; Icelandic (DOS) */ + {862, "DOS-862"}, /* OEM Hebrew; Hebrew (DOS) */ + {863, "IBM863"}, /* OEM French Canadian; French Canadian (DOS) */ + {864, "IBM864"}, /* OEM Arabic; Arabic (864) */ + {865, "IBM865"}, /* OEM Nordic; Nordic (DOS) */ + {866, "cp866"}, /* OEM Russian; Cyrillic (DOS) */ + {869, "ibm869"}, /* OEM Modern Greek; Greek, Modern (DOS) */ + {870, "IBM870"}, /* IBM EBCDIC Multilingual/ROECE (Latin 2); IBM EBCDIC Multilingual Latin 2 */ + {874, "windows-874"}, /* ANSI/OEM Thai (same as 28605, ISO 8859-15); Thai (Windows) */ + {875, "cp875"}, /* IBM EBCDIC Greek Modern */ + {932, "shift_jis"}, /* ANSI/OEM Japanese; Japanese (Shift-JIS) */ + {932, "shift-jis"}, /* alternative name for it */ + {936, "gb2312"}, /* ANSI/OEM Simplified Chinese (PRC, Singapore); Chinese Simplified (GB2312) */ + {949, "ks_c_5601-1987"}, /* ANSI/OEM Korean (Unified Hangul Code) */ + {950, "big5"}, /* ANSI/OEM Traditional Chinese (Taiwan; Hong Kong SAR, PRC); Chinese Traditional (Big5) */ + {1026, "IBM1026"}, /* IBM EBCDIC Turkish (Latin 5) */ + {1047, "IBM01047"}, /* IBM EBCDIC Latin 1/Open System */ + {1140, "IBM01140"}, /* IBM EBCDIC US-Canada (037 + Euro symbol); IBM EBCDIC (US-Canada-Euro) */ + {1141, "IBM01141"}, /* IBM EBCDIC Germany (20273 + Euro symbol); IBM EBCDIC (Germany-Euro) */ + {1142, "IBM01142"}, /* IBM EBCDIC Denmark-Norway (20277 + Euro symbol); IBM EBCDIC (Denmark-Norway-Euro) */ + {1143, "IBM01143"}, /* IBM EBCDIC Finland-Sweden (20278 + Euro symbol); IBM EBCDIC (Finland-Sweden-Euro) */ + {1144, "IBM01144"}, /* IBM EBCDIC Italy (20280 + Euro symbol); IBM EBCDIC (Italy-Euro) */ + {1145, "IBM01145"}, /* IBM EBCDIC Latin America-Spain (20284 + Euro symbol); IBM EBCDIC (Spain-Euro) */ + {1146, "IBM01146"}, /* IBM EBCDIC United Kingdom (20285 + Euro symbol); IBM EBCDIC (UK-Euro) */ + {1147, "IBM01147"}, /* IBM EBCDIC France (20297 + Euro symbol); IBM EBCDIC (France-Euro) */ + {1148, "IBM01148"}, /* IBM EBCDIC International (500 + Euro symbol); IBM EBCDIC (International-Euro) */ + {1149, "IBM01149"}, /* IBM EBCDIC Icelandic (20871 + Euro symbol); IBM EBCDIC (Icelandic-Euro) */ + {1250, "windows-1250"}, /* ANSI Central European; Central European (Windows) */ + {1251, "windows-1251"}, /* ANSI Cyrillic; Cyrillic (Windows) */ + {1252, "windows-1252"}, /* ANSI Latin 1; Western European (Windows) */ + {1253, "windows-1253"}, /* ANSI Greek; Greek (Windows) */ + {1254, "windows-1254"}, /* ANSI Turkish; Turkish (Windows) */ + {1255, "windows-1255"}, /* ANSI Hebrew; Hebrew (Windows) */ + {1256, "windows-1256"}, /* ANSI Arabic; Arabic (Windows) */ + {1257, "windows-1257"}, /* ANSI Baltic; Baltic (Windows) */ + {1258, "windows-1258"}, /* ANSI/OEM Vietnamese; Vietnamese (Windows) */ + {1361, "Johab"}, /* Korean (Johab) */ + {10000, "macintosh"}, /* MAC Roman; Western European (Mac) */ + {10001, "x-mac-japanese"}, /* Japanese (Mac) */ + {10002, "x-mac-chinesetrad"}, /* MAC Traditional Chinese (Big5); Chinese Traditional (Mac) */ + {10003, "x-mac-korean"}, /* Korean (Mac) */ + {10004, "x-mac-arabic"}, /* Arabic (Mac) */ + {10005, "x-mac-hebrew"}, /* Hebrew (Mac) */ + {10006, "x-mac-greek"}, /* Greek (Mac) */ + {10007, "x-mac-cyrillic"}, /* Cyrillic (Mac) */ + {10008, "x-mac-chinesesimp"}, /* MAC Simplified Chinese (GB 2312); Chinese Simplified (Mac) */ + {10010, "x-mac-romanian"}, /* Romanian (Mac) */ + {10017, "x-mac-ukrainian"}, /* Ukrainian (Mac) */ + {10021, "x-mac-thai"}, /* Thai (Mac) */ + {10029, "x-mac-ce"}, /* MAC Latin 2; Central European (Mac) */ + {10079, "x-mac-icelandic"}, /* Icelandic (Mac) */ + {10081, "x-mac-turkish"}, /* Turkish (Mac) */ + {10082, "x-mac-croatian"}, /* Croatian (Mac) */ + {20000, "x-Chinese_CNS"}, /* CNS Taiwan; Chinese Traditional (CNS) */ + {20001, "x-cp20001"}, /* TCA Taiwan */ + {20002, "x_Chinese-Eten"}, /* Eten Taiwan; Chinese Traditional (Eten) */ + {20003, "x-cp20003"}, /* IBM5550 Taiwan */ + {20004, "x-cp20004"}, /* TeleText Taiwan */ + {20005, "x-cp20005"}, /* Wang Taiwan */ + {20105, "x-IA5"}, /* IA5 (IRV International Alphabet No. 5, 7-bit); Western European (IA5) */ + {20106, "x-IA5-German"}, /* IA5 German (7-bit) */ + {20107, "x-IA5-Swedish"}, /* IA5 Swedish (7-bit) */ + {20108, "x-IA5-Norwegian"}, /* IA5 Norwegian (7-bit) */ + {20127, "us-ascii"}, /* US-ASCII (7-bit) */ + {20261, "x-cp20261"}, /* T.61 */ + {20269, "x-cp20269"}, /* ISO 6937 Non-Spacing Accent */ + {20273, "IBM273"}, /* IBM EBCDIC Germany */ + {20277, "IBM277"}, /* IBM EBCDIC Denmark-Norway */ + {20278, "IBM278"}, /* IBM EBCDIC Finland-Sweden */ + {20280, "IBM280"}, /* IBM EBCDIC Italy */ + {20284, "IBM284"}, /* IBM EBCDIC Latin America-Spain */ + {20285, "IBM285"}, /* IBM EBCDIC United Kingdom */ + {20290, "IBM290"}, /* IBM EBCDIC Japanese Katakana Extended */ + {20297, "IBM297"}, /* IBM EBCDIC France */ + {20420, "IBM420"}, /* IBM EBCDIC Arabic */ + {20423, "IBM423"}, /* IBM EBCDIC Greek */ + {20424, "IBM424"}, /* IBM EBCDIC Hebrew */ + {20833, "x-EBCDIC-KoreanExtended"}, /* IBM EBCDIC Korean Extended */ + {20838, "IBM-Thai"}, /* IBM EBCDIC Thai */ + {20866, "koi8-r"}, /* Russian (KOI8-R); Cyrillic (KOI8-R) */ + {20871, "IBM871"}, /* IBM EBCDIC Icelandic */ + {20880, "IBM880"}, /* IBM EBCDIC Cyrillic Russian */ + {20905, "IBM905"}, /* IBM EBCDIC Turkish */ + {20924, "IBM00924"}, /* IBM EBCDIC Latin 1/Open System (1047 + Euro symbol) */ + {20932, "EUC-JP"}, /* Japanese (JIS 0208-1990 and 0121-1990) */ + {20936, "x-cp20936"}, /* Simplified Chinese (GB2312); Chinese Simplified (GB2312-80) */ + {20949, "x-cp20949"}, /* Korean Wansung */ + {21025, "cp1025"}, /* IBM EBCDIC Cyrillic Serbian-Bulgarian */ + /* 21027 (deprecated) */ + {21866, "koi8-u"}, /* Ukrainian (KOI8-U); Cyrillic (KOI8-U) */ + {28591, "iso-8859-1"}, /* ISO 8859-1 Latin 1; Western European (ISO) */ + {28591, "iso8859-1"}, /* ISO 8859-1 Latin 1; Western European (ISO) */ + {28592, "iso-8859-2"}, /* ISO 8859-2 Central European; Central European (ISO) */ + {28592, "iso8859-2"}, /* ISO 8859-2 Central European; Central European (ISO) */ + {28593, "iso-8859-3"}, /* ISO 8859-3 Latin 3 */ + {28593, "iso8859-3"}, /* ISO 8859-3 Latin 3 */ + {28594, "iso-8859-4"}, /* ISO 8859-4 Baltic */ + {28594, "iso8859-4"}, /* ISO 8859-4 Baltic */ + {28595, "iso-8859-5"}, /* ISO 8859-5 Cyrillic */ + {28595, "iso8859-5"}, /* ISO 8859-5 Cyrillic */ + {28596, "iso-8859-6"}, /* ISO 8859-6 Arabic */ + {28596, "iso8859-6"}, /* ISO 8859-6 Arabic */ + {28597, "iso-8859-7"}, /* ISO 8859-7 Greek */ + {28597, "iso8859-7"}, /* ISO 8859-7 Greek */ + {28598, "iso-8859-8"}, /* ISO 8859-8 Hebrew; Hebrew (ISO-Visual) */ + {28598, "iso8859-8"}, /* ISO 8859-8 Hebrew; Hebrew (ISO-Visual) */ + {28599, "iso-8859-9"}, /* ISO 8859-9 Turkish */ + {28599, "iso8859-9"}, /* ISO 8859-9 Turkish */ + {28603, "iso-8859-13"}, /* ISO 8859-13 Estonian */ + {28603, "iso8859-13"}, /* ISO 8859-13 Estonian */ + {28605, "iso-8859-15"}, /* ISO 8859-15 Latin 9 */ + {28605, "iso8859-15"}, /* ISO 8859-15 Latin 9 */ + {29001, "x-Europa"}, /* Europa 3 */ + {38598, "iso-8859-8-i"}, /* ISO 8859-8 Hebrew; Hebrew (ISO-Logical) */ + {38598, "iso8859-8-i"}, /* ISO 8859-8 Hebrew; Hebrew (ISO-Logical) */ + {50220, "iso-2022-jp"}, /* ISO 2022 Japanese with no halfwidth Katakana; Japanese (JIS) */ + {50221, "csISO2022JP"}, /* ISO 2022 Japanese with halfwidth Katakana; Japanese (JIS-Allow 1 byte Kana) */ + {50222, "iso-2022-jp"}, /* ISO 2022 Japanese JIS X 0201-1989; Japanese (JIS-Allow 1 byte Kana - SO/SI) */ + {50225, "iso-2022-kr"}, /* ISO 2022 Korean */ + {50225, "iso2022-kr"}, /* ISO 2022 Korean */ + {50227, "x-cp50227"}, /* ISO 2022 Simplified Chinese; Chinese Simplified (ISO 2022) */ + /* 50229 ISO 2022 Traditional Chinese */ + /* 50930 EBCDIC Japanese (Katakana) Extended */ + /* 50931 EBCDIC US-Canada and Japanese */ + /* 50933 EBCDIC Korean Extended and Korean */ + /* 50935 EBCDIC Simplified Chinese Extended and Simplified Chinese */ + /* 50936 EBCDIC Simplified Chinese */ + /* 50937 EBCDIC US-Canada and Traditional Chinese */ + /* 50939 EBCDIC Japanese (Latin) Extended and Japanese */ + {51932, "euc-jp"}, /* EUC Japanese */ + {51936, "EUC-CN"}, /* EUC Simplified Chinese; Chinese Simplified (EUC) */ + {51949, "euc-kr"}, /* EUC Korean */ + /* 51950 EUC Traditional Chinese */ + {52936, "hz-gb-2312"}, /* HZ-GB2312 Simplified Chinese; Chinese Simplified (HZ) */ + {54936, "GB18030"}, /* Windows XP and later: GB18030 Simplified Chinese (4 byte); Chinese Simplified (GB18030) */ + {57002, "x-iscii-de"}, /* ISCII Devanagari */ + {57003, "x-iscii-be"}, /* ISCII Bengali */ + {57004, "x-iscii-ta"}, /* ISCII Tamil */ + {57005, "x-iscii-te"}, /* ISCII Telugu */ + {57006, "x-iscii-as"}, /* ISCII Assamese */ + {57007, "x-iscii-or"}, /* ISCII Oriya */ + {57008, "x-iscii-ka"}, /* ISCII Kannada */ + {57009, "x-iscii-ma"}, /* ISCII Malayalam */ + {57010, "x-iscii-gu"}, /* ISCII Gujarati */ + {57011, "x-iscii-pa"}, /* ISCII Punjabi */ + + {0, NULL} +}; + +/* + * SJIS SHIFTJIS table CP932 table + * ---- --------------------------- -------------------------------- + * 5C U+00A5 YEN SIGN U+005C REVERSE SOLIDUS + * 7E U+203E OVERLINE U+007E TILDE + * 815C U+2014 EM DASH U+2015 HORIZONTAL BAR + * 815F U+005C REVERSE SOLIDUS U+FF3C FULLWIDTH REVERSE SOLIDUS + * 8160 U+301C WAVE DASH U+FF5E FULLWIDTH TILDE + * 8161 U+2016 DOUBLE VERTICAL LINE U+2225 PARALLEL TO + * 817C U+2212 MINUS SIGN U+FF0D FULLWIDTH HYPHEN-MINUS + * 8191 U+00A2 CENT SIGN U+FFE0 FULLWIDTH CENT SIGN + * 8192 U+00A3 POUND SIGN U+FFE1 FULLWIDTH POUND SIGN + * 81CA U+00AC NOT SIGN U+FFE2 FULLWIDTH NOT SIGN + * + * EUC-JP and ISO-2022-JP should be compatible with CP932. + * + * Kernel and MLang have different Unicode mapping table. Make sure + * which API is used. + */ +static compat_t cp932_compat[] = { + {0x00A5, 0x005C, COMPAT_OUT}, + {0x203E, 0x007E, COMPAT_OUT}, + {0x2014, 0x2015, COMPAT_OUT}, + {0x301C, 0xFF5E, COMPAT_OUT}, + {0x2016, 0x2225, COMPAT_OUT}, + {0x2212, 0xFF0D, COMPAT_OUT}, + {0x00A2, 0xFFE0, COMPAT_OUT}, + {0x00A3, 0xFFE1, COMPAT_OUT}, + {0x00AC, 0xFFE2, COMPAT_OUT}, + {0, 0, 0} +}; + +static compat_t cp20932_compat[] = { + {0x00A5, 0x005C, COMPAT_OUT}, + {0x203E, 0x007E, COMPAT_OUT}, + {0x2014, 0x2015, COMPAT_OUT}, + {0xFF5E, 0x301C, COMPAT_OUT|COMPAT_IN}, + {0x2225, 0x2016, COMPAT_OUT|COMPAT_IN}, + {0xFF0D, 0x2212, COMPAT_OUT|COMPAT_IN}, + {0xFFE0, 0x00A2, COMPAT_OUT|COMPAT_IN}, + {0xFFE1, 0x00A3, COMPAT_OUT|COMPAT_IN}, + {0xFFE2, 0x00AC, COMPAT_OUT|COMPAT_IN}, + {0, 0, 0} +}; + +static compat_t *cp51932_compat = cp932_compat; + +/* cp20932_compat for kernel. cp932_compat for mlang. */ +static compat_t *cp5022x_compat = cp932_compat; + +typedef HRESULT (WINAPI *CONVERTINETSTRING)( + LPDWORD lpdwMode, + DWORD dwSrcEncoding, + DWORD dwDstEncoding, + LPCSTR lpSrcStr, + LPINT lpnSrcSize, + LPBYTE lpDstStr, + LPINT lpnDstSize +); +typedef HRESULT (WINAPI *CONVERTINETMULTIBYTETOUNICODE)( + LPDWORD lpdwMode, + DWORD dwSrcEncoding, + LPCSTR lpSrcStr, + LPINT lpnMultiCharCount, + LPWSTR lpDstStr, + LPINT lpnWideCharCount +); +typedef HRESULT (WINAPI *CONVERTINETUNICODETOMULTIBYTE)( + LPDWORD lpdwMode, + DWORD dwEncoding, + LPCWSTR lpSrcStr, + LPINT lpnWideCharCount, + LPSTR lpDstStr, + LPINT lpnMultiCharCount +); +typedef HRESULT (WINAPI *ISCONVERTINETSTRINGAVAILABLE)( + DWORD dwSrcEncoding, + DWORD dwDstEncoding +); +typedef HRESULT (WINAPI *LCIDTORFC1766A)( + LCID Locale, + LPSTR pszRfc1766, + int nChar +); +typedef HRESULT (WINAPI *LCIDTORFC1766W)( + LCID Locale, + LPWSTR pszRfc1766, + int nChar +); +typedef HRESULT (WINAPI *RFC1766TOLCIDA)( + LCID *pLocale, + LPSTR pszRfc1766 +); +typedef HRESULT (WINAPI *RFC1766TOLCIDW)( + LCID *pLocale, + LPWSTR pszRfc1766 +); +static CONVERTINETSTRING ConvertINetString; +static CONVERTINETMULTIBYTETOUNICODE ConvertINetMultiByteToUnicode; +static CONVERTINETUNICODETOMULTIBYTE ConvertINetUnicodeToMultiByte; +static ISCONVERTINETSTRINGAVAILABLE IsConvertINetStringAvailable; +static LCIDTORFC1766A LcidToRfc1766A; +static RFC1766TOLCIDA Rfc1766ToLcidA; + +static int +load_mlang() +{ + HMODULE h; + if (ConvertINetString != NULL) + return TRUE; + h = LoadLibrary("mlang.dll"); + if (!h) + return FALSE; + ConvertINetString = (CONVERTINETSTRING)GetProcAddress(h, "ConvertINetString"); + ConvertINetMultiByteToUnicode = (CONVERTINETMULTIBYTETOUNICODE)GetProcAddress(h, "ConvertINetMultiByteToUnicode"); + ConvertINetUnicodeToMultiByte = (CONVERTINETUNICODETOMULTIBYTE)GetProcAddress(h, "ConvertINetUnicodeToMultiByte"); + IsConvertINetStringAvailable = (ISCONVERTINETSTRINGAVAILABLE)GetProcAddress(h, "IsConvertINetStringAvailable"); + LcidToRfc1766A = (LCIDTORFC1766A)GetProcAddress(h, "LcidToRfc1766A"); + Rfc1766ToLcidA = (RFC1766TOLCIDA)GetProcAddress(h, "Rfc1766ToLcidA"); + return TRUE; +} + +iconv_t +iconv_open(const char *tocode, const char *fromcode) +{ + rec_iconv_t *cd; + + cd = (rec_iconv_t *)calloc(1, sizeof(rec_iconv_t)); + if (cd == NULL) + { + errno = ENOMEM; + return (iconv_t)(-1); + } + +#if defined(USE_LIBICONV_DLL) + if (libiconv_iconv_open(cd, tocode, fromcode)) + return (iconv_t)cd; +#endif + + if (win_iconv_open(cd, tocode, fromcode)) + return (iconv_t)cd; + + free(cd); + errno = EINVAL; + return (iconv_t)(-1); +} + +int +iconv_close(iconv_t _cd) +{ + rec_iconv_t *cd = (rec_iconv_t *)_cd; + int r = cd->iconv_close(cd->cd); + int e = *(cd->_errno()); +#if defined(USE_LIBICONV_DLL) + if (cd->hlibiconv != NULL) + FreeLibrary(cd->hlibiconv); +#endif + free(cd); + errno = e; + return r; +} + +size_t +iconv(iconv_t _cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft) +{ + rec_iconv_t *cd = (rec_iconv_t *)_cd; + size_t r = cd->iconv(cd->cd, inbuf, inbytesleft, outbuf, outbytesleft); + errno = *(cd->_errno()); + return r; +} + +static int +win_iconv_open(rec_iconv_t *cd, const char *tocode, const char *fromcode) +{ + cd->from = make_csconv(fromcode); + cd->to = make_csconv(tocode); + if (cd->from.codepage == -1 || cd->to.codepage == -1) + return FALSE; + cd->iconv_close = win_iconv_close; + cd->iconv = win_iconv; + cd->_errno = _errno; + cd->cd = (iconv_t)cd; + return TRUE; +} + +static int +win_iconv_close(iconv_t cd) +{ + return 0; +} + +static size_t +win_iconv(iconv_t _cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft) +{ + rec_iconv_t *cd = (rec_iconv_t *)_cd; + ushort wbuf[MB_CHAR_MAX]; /* enough room for one character */ + int insize; + int outsize; + int wsize; + DWORD mode; + uint wc; + compat_t *cp; + int i; + + if (inbuf == NULL || *inbuf == NULL) + { + if (outbuf != NULL && *outbuf != NULL && cd->to.flush != NULL) + { + outsize = cd->to.flush(&cd->to, (uchar *)*outbuf, *outbytesleft); + if (outsize == -1) + return (size_t)(-1); + *outbuf += outsize; + *outbytesleft -= outsize; + } + if (is_unicode(cd->from.codepage) && (cd->from.mode & UNICODE_MODE_SWAPPED)) + cd->from.codepage ^= 1; + cd->from.mode = 0; + cd->to.mode = 0; + return 0; + } + + while (*inbytesleft != 0) + { + mode = cd->from.mode; + wsize = MB_CHAR_MAX; + + insize = cd->from.mbtowc(&cd->from, (const uchar *)*inbuf, *inbytesleft, wbuf, &wsize); + if (insize == -1) + return (size_t)(-1); + + if (is_unicode(cd->from.codepage) && !(cd->from.mode & UNICODE_MODE_BOM_DONE)) + { + check_utf_bom(cd, wbuf, &wsize); + cd->from.mode |= UNICODE_MODE_BOM_DONE; + } + + if (wsize == 0) + { + *inbuf += insize; + *inbytesleft -= insize; + continue; + } + + if (cd->from.compat != NULL) + { + wc = utf16_to_ucs4(wbuf); + cp = cd->from.compat; + for (i = 0; cp[i].in != 0; ++i) + { + if ((cp[i].flag & COMPAT_IN) && cp[i].out == wc) + { + ucs4_to_utf16(cp[i].in, wbuf, &wsize); + break; + } + } + } + + if (cd->to.compat != NULL) + { + wc = utf16_to_ucs4(wbuf); + cp = cd->to.compat; + for (i = 0; cp[i].in != 0; ++i) + { + if ((cp[i].flag & COMPAT_OUT) && cp[i].in == wc) + { + ucs4_to_utf16(cp[i].out, wbuf, &wsize); + break; + } + } + } + + outsize = cd->to.wctomb(&cd->to, wbuf, wsize, (uchar *)*outbuf, *outbytesleft); + if (outsize == -1) + { + cd->from.mode = mode; + return (size_t)(-1); + } + + *inbuf += insize; + *outbuf += outsize; + *inbytesleft -= insize; + *outbytesleft -= outsize; + } + + return 0; +} + +static csconv_t +make_csconv(const char *_name) +{ + CPINFOEX cpinfoex; + csconv_t cv; + int use_compat = TRUE; + int flag = 0; + char name[128]; + char *p; + + xstrlcpy(name, _name, sizeof(name)); + + /* check for option "enc_name//opt1//opt2" */ + while ((p = strrstr(name, "//")) != NULL) + { + if (_stricmp(p + 2, "nocompat") == 0) + use_compat = FALSE; + else if (_stricmp(p + 2, "translit") == 0) + flag |= FLAG_TRANSLIT; + else if (_stricmp(p + 2, "ignore") == 0) + flag |= FLAG_IGNORE; + *p = 0; + } + + cv.mode = 0; + cv.flags = flag; + cv.mblen = NULL; + cv.flush = NULL; + cv.compat = NULL; + cv.codepage = name_to_codepage(name); + if (cv.codepage == 1200 || cv.codepage == 1201) + { + cv.mbtowc = utf16_mbtowc; + cv.wctomb = utf16_wctomb; + if (_stricmp(name, "UTF-16") == 0 || + _stricmp(name, "UTF16") == 0 || + _stricmp(name, "UCS-2") == 0 || + _stricmp(name, "UCS2") == 0) + cv.flags |= FLAG_USE_BOM_ENDIAN; + } + else if (cv.codepage == 12000 || cv.codepage == 12001) + { + cv.mbtowc = utf32_mbtowc; + cv.wctomb = utf32_wctomb; + if (_stricmp(name, "UTF-32") == 0 || + _stricmp(name, "UTF32") == 0 || + _stricmp(name, "UCS-4") == 0 || + _stricmp(name, "UCS4") == 0) + cv.flags |= FLAG_USE_BOM_ENDIAN; + } + else if (cv.codepage == 65001) + { + cv.mbtowc = kernel_mbtowc; + cv.wctomb = kernel_wctomb; + cv.mblen = utf8_mblen; + } + else if ((cv.codepage == 50220 || cv.codepage == 50221 || cv.codepage == 50222) && load_mlang()) + { + cv.mbtowc = iso2022jp_mbtowc; + cv.wctomb = iso2022jp_wctomb; + cv.flush = iso2022jp_flush; + } + else if (cv.codepage == 51932 && load_mlang()) + { + cv.mbtowc = mlang_mbtowc; + cv.wctomb = mlang_wctomb; + cv.mblen = eucjp_mblen; + } + else if (IsValidCodePage(cv.codepage) + && GetCPInfoEx(cv.codepage, 0, &cpinfoex) != 0) + { + cv.mbtowc = kernel_mbtowc; + cv.wctomb = kernel_wctomb; + if (cpinfoex.MaxCharSize == 1) + cv.mblen = sbcs_mblen; + else if (cpinfoex.MaxCharSize == 2) + cv.mblen = dbcs_mblen; + else + cv.mblen = mbcs_mblen; + } + else + { + /* not supported */ + cv.codepage = -1; + } + if (use_compat) + { + switch (cv.codepage) + { + case 932: cv.compat = cp932_compat; break; + case 20932: cv.compat = cp20932_compat; break; + case 51932: cv.compat = cp51932_compat; break; + case 50220: case 50221: case 50222: cv.compat = cp5022x_compat; break; + } + } + return cv; +} + +static int +name_to_codepage(const char *name) +{ + int i; + + if (*name == '\0' || + strcmp(name, "char") == 0) + return GetACP(); + else if (strcmp(name, "wchar_t") == 0) + return 1200; + else if (_strnicmp(name, "cp", 2) == 0) + return atoi(name + 2); /* CP123 */ + else if ('0' <= name[0] && name[0] <= '9') + return atoi(name); /* 123 */ + else if (_strnicmp(name, "xx", 2) == 0) + return atoi(name + 2); /* XX123 for debug */ + + for (i = 0; codepage_alias[i].name != NULL; ++i) + if (_stricmp(name, codepage_alias[i].name) == 0) + return codepage_alias[i].codepage; + return -1; +} + +/* + * http://www.faqs.org/rfcs/rfc2781.html + */ +static uint +utf16_to_ucs4(const ushort *wbuf) +{ + uint wc = wbuf[0]; + if (0xD800 <= wbuf[0] && wbuf[0] <= 0xDBFF) + wc = ((wbuf[0] & 0x3FF) << 10) + (wbuf[1] & 0x3FF) + 0x10000; + return wc; +} + +static void +ucs4_to_utf16(uint wc, ushort *wbuf, int *wbufsize) +{ + if (wc < 0x10000) + { + wbuf[0] = wc; + *wbufsize = 1; + } + else + { + wc -= 0x10000; + wbuf[0] = 0xD800 | ((wc >> 10) & 0x3FF); + wbuf[1] = 0xDC00 | (wc & 0x3FF); + *wbufsize = 2; + } +} + +static int +is_unicode(int codepage) +{ + return (codepage == 1200 || codepage == 1201 || + codepage == 12000 || codepage == 12001 || + codepage == 65000 || codepage == 65001); +} + +/* + * Check if codepage is one of those for which the dwFlags parameter + * to MultiByteToWideChar() must be zero. Return zero or + * MB_ERR_INVALID_CHARS. The docs in Platform SDK for for Windows + * Server 2003 R2 claims that also codepage 65001 is one of these, but + * that doesn't seem to be the case. The MSDN docs for MSVS2008 leave + * out 65001 (UTF-8), and that indeed seems to be the case on XP, it + * works fine to pass MB_ERR_INVALID_CHARS in dwFlags when converting + * from UTF-8. + */ +static int +mbtowc_flags(int codepage) +{ + return (codepage == 50220 || codepage == 50221 || + codepage == 50222 || codepage == 50225 || + codepage == 50227 || codepage == 50229 || + codepage == 52936 || codepage == 54936 || + (codepage >= 57002 && codepage <= 57011) || + codepage == 65000 || codepage == 42) ? 0 : MB_ERR_INVALID_CHARS; +} + +/* + * Check if codepage is one those for which the lpUsedDefaultChar + * parameter to WideCharToMultiByte() must be NULL. The docs in + * Platform SDK for for Windows Server 2003 R2 claims that this is the + * list below, while the MSDN docs for MSVS2008 claim that it is only + * for 65000 (UTF-7) and 65001 (UTF-8). This time the earlier Platform + * SDK seems to be correct, at least for XP. + */ +static int +must_use_null_useddefaultchar(int codepage) +{ + return (codepage == 65000 || codepage == 65001 || + codepage == 50220 || codepage == 50221 || + codepage == 50222 || codepage == 50225 || + codepage == 50227 || codepage == 50229 || + codepage == 52936 || codepage == 54936 || + (codepage >= 57002 && codepage <= 57011) || + codepage == 42); +} + +static void +check_utf_bom(rec_iconv_t *cd, ushort *wbuf, int *wbufsize) +{ + /* If we have a BOM, trust it, despite what the caller said */ + if (wbuf[0] == 0xFFFE && (cd->from.flags & FLAG_USE_BOM_ENDIAN)) + { + /* swap endian: 1200 <-> 1201 or 12000 <-> 12001 */ + cd->from.codepage ^= 1; + cd->from.mode |= UNICODE_MODE_SWAPPED; + wbuf[0] = 0xFEFF; + } + + /* + * Remove BOM. + * Don't do this if "to" is Unicode, + * except if "to" is UTF-8. + */ + if (wbuf[0] == 0xFEFF && (!is_unicode(cd->to.codepage) || cd->to.codepage == 65001)) + *wbufsize = 0; +} + +static char * +strrstr(const char *str, const char *token) +{ + int len = strlen(token); + const char *p = str + strlen(str); + + while (str <= --p) + if (p[0] == token[0] && strncmp(p, token, len) == 0) + return (char *)p; + return NULL; +} + +#if defined(USE_LIBICONV_DLL) +static int +libiconv_iconv_open(rec_iconv_t *cd, const char *fromcode, const char *tocode) +{ + HMODULE hlibiconv = NULL; + HMODULE hmsvcrt = NULL; + char dllname[_MAX_PATH]; + const char *p; + const char *e; + f_iconv_open _iconv_open; + + /* + * always try to load dll, so that we can switch dll in runtime. + */ + + /* XXX: getenv() can't get variable set by SetEnvironmentVariable() */ + p = getenv("WINICONV_LIBICONV_DLL"); + if (p == NULL) + p = DEFAULT_LIBICONV_DLL; + /* parse comma separated value */ + for ( ; *p != 0; p = (*e == ',') ? e + 1 : e) + { + e = strchr(p, ','); + if (p == e) + continue; + else if (e == NULL) + e = p + strlen(p); + xstrlcpyn(dllname, p, e - p, sizeof(dllname)); + hlibiconv = LoadLibrary(dllname); + if (hlibiconv != NULL) + { + if (hlibiconv == hwiniconv) + { + FreeLibrary(hlibiconv); + hlibiconv = NULL; + continue; + } + break; + } + } + + if (hlastdll != NULL) + { + /* decrement reference count */ + FreeLibrary(hlastdll); + hlastdll = NULL; + } + + if (hlibiconv == NULL) + goto failed; + + hmsvcrt = find_imported_module_by_funcname(hlibiconv, "_errno"); + if (hmsvcrt == NULL) + goto failed; + + _iconv_open = (f_iconv_open)GetProcAddress(hlibiconv, "libiconv_open"); + if (_iconv_open == NULL) + _iconv_open = (f_iconv_open)GetProcAddress(hlibiconv, "iconv_open"); + cd->iconv_close = (f_iconv_close)GetProcAddress(hlibiconv, "libiconv_close"); + if (cd->iconv_close == NULL) + cd->iconv_close = (f_iconv_close)GetProcAddress(hlibiconv, "iconv_close"); + cd->iconv = (f_iconv)GetProcAddress(hlibiconv, "libiconv"); + if (cd->iconv == NULL) + cd->iconv = (f_iconv)GetProcAddress(hlibiconv, "iconv"); + cd->_errno = (f_errno)GetProcAddress(hmsvcrt, "_errno"); + if (_iconv_open == NULL || cd->iconv_close == NULL + || cd->iconv == NULL || cd->_errno == NULL) + goto failed; + + /* increment reference count */ + hlastdll = LoadLibrary(dllname); + + cd->cd = _iconv_open(tocode, fromcode); + if (cd->cd == (iconv_t)(-1)) + goto failed; + + cd->hlibiconv = hlibiconv; + return TRUE; + +failed: + if (hlibiconv != NULL) + FreeLibrary(hlibiconv); + /* do not free hmsvcrt which is obtained by GetModuleHandle() */ + return FALSE; +} + +/* + * Reference: + * http://forums.belution.com/ja/vc/000/234/78s.shtml + * http://nienie.com/~masapico/api_ImageDirectoryEntryToData.html + * + * The formal way is + * imagehlp.h or dbghelp.h + * imagehlp.lib or dbghelp.lib + * ImageDirectoryEntryToData() + */ +#define TO_DOS_HEADER(base) ((PIMAGE_DOS_HEADER)(base)) +#define TO_NT_HEADERS(base) ((PIMAGE_NT_HEADERS)((LPBYTE)(base) + TO_DOS_HEADER(base)->e_lfanew)) +static PVOID +MyImageDirectoryEntryToData(LPVOID Base, BOOLEAN MappedAsImage, USHORT DirectoryEntry, PULONG Size) +{ + /* TODO: MappedAsImage? */ + PIMAGE_DATA_DIRECTORY p; + p = TO_NT_HEADERS(Base)->OptionalHeader.DataDirectory + DirectoryEntry; + if (p->VirtualAddress == 0) { + *Size = 0; + return NULL; + } + *Size = p->Size; + return (PVOID)((LPBYTE)Base + p->VirtualAddress); +} + +static HMODULE +find_imported_module_by_funcname(HMODULE hModule, const char *funcname) +{ + DWORD Base; + ULONG Size; + PIMAGE_IMPORT_DESCRIPTOR Imp; + PIMAGE_THUNK_DATA Name; /* Import Name Table */ + PIMAGE_IMPORT_BY_NAME ImpName; + + Base = (DWORD)hModule; + Imp = MyImageDirectoryEntryToData( + (LPVOID)Base, + TRUE, + IMAGE_DIRECTORY_ENTRY_IMPORT, + &Size); + if (Imp == NULL) + return NULL; + for ( ; Imp->OriginalFirstThunk != 0; ++Imp) + { + Name = (PIMAGE_THUNK_DATA)(Base + Imp->OriginalFirstThunk); + for ( ; Name->u1.Ordinal != 0; ++Name) + { + if (!IMAGE_SNAP_BY_ORDINAL(Name->u1.Ordinal)) + { + ImpName = (PIMAGE_IMPORT_BY_NAME) + (Base + (DWORD)Name->u1.AddressOfData); + if (strcmp((char *)ImpName->Name, funcname) == 0) + return GetModuleHandle((char *)(Base + Imp->Name)); + } + } + } + return NULL; +} +#endif + +static int +sbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize) +{ + return 1; +} + +static int +dbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize) +{ + int len = IsDBCSLeadByteEx(cv->codepage, buf[0]) ? 2 : 1; + if (bufsize < len) + return_error(EINVAL); + return len; +} + +static int +mbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize) +{ + int len = 0; + + if (cv->codepage == 54936) { + if (buf[0] <= 0x7F) len = 1; + else if (buf[0] >= 0x81 && buf[0] <= 0xFE && + bufsize >= 2 && + ((buf[1] >= 0x40 && buf[1] <= 0x7E) || + (buf[1] >= 0x80 && buf[1] <= 0xFE))) len = 2; + else if (buf[0] >= 0x81 && buf[0] <= 0xFE && + bufsize >= 4 && + buf[1] >= 0x30 && buf[1] <= 0x39) len = 4; + else + return_error(EINVAL); + return len; + } + else + return_error(EINVAL); +} + +static int +utf8_mblen(csconv_t *cv, const uchar *buf, int bufsize) +{ + int len = 0; + + if (buf[0] < 0x80) len = 1; + else if ((buf[0] & 0xE0) == 0xC0) len = 2; + else if ((buf[0] & 0xF0) == 0xE0) len = 3; + else if ((buf[0] & 0xF8) == 0xF0) len = 4; + else if ((buf[0] & 0xFC) == 0xF8) len = 5; + else if ((buf[0] & 0xFE) == 0xFC) len = 6; + + if (len == 0) + return_error(EILSEQ); + else if (bufsize < len) + return_error(EINVAL); + return len; +} + +static int +eucjp_mblen(csconv_t *cv, const uchar *buf, int bufsize) +{ + if (buf[0] < 0x80) /* ASCII */ + return 1; + else if (buf[0] == 0x8E) /* JIS X 0201 */ + { + if (bufsize < 2) + return_error(EINVAL); + else if (!(0xA1 <= buf[1] && buf[1] <= 0xDF)) + return_error(EILSEQ); + return 2; + } + else if (buf[0] == 0x8F) /* JIS X 0212 */ + { + if (bufsize < 3) + return_error(EINVAL); + else if (!(0xA1 <= buf[1] && buf[1] <= 0xFE) + || !(0xA1 <= buf[2] && buf[2] <= 0xFE)) + return_error(EILSEQ); + return 3; + } + else /* JIS X 0208 */ + { + if (bufsize < 2) + return_error(EINVAL); + else if (!(0xA1 <= buf[0] && buf[0] <= 0xFE) + || !(0xA1 <= buf[1] && buf[1] <= 0xFE)) + return_error(EILSEQ); + return 2; + } +} + +static int +kernel_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize) +{ + int len; + + len = cv->mblen(cv, buf, bufsize); + if (len == -1) + return -1; + /* If converting from ASCII, reject 8bit + * chars. MultiByteToWideChar() doesn't. Note that for ASCII we + * know that the mblen function is sbcs_mblen() so len is 1. + */ + if (cv->codepage == 20127 && buf[0] >= 0x80) + return_error(EILSEQ); + *wbufsize = MultiByteToWideChar(cv->codepage, mbtowc_flags (cv->codepage), + (const char *)buf, len, (wchar_t *)wbuf, *wbufsize); + if (*wbufsize == 0) + return_error(EILSEQ); + return len; +} + +static int +kernel_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize) +{ + BOOL usedDefaultChar = 0; + BOOL *p = NULL; + int flags = 0; + int len; + + if (bufsize == 0) + return_error(E2BIG); + if (!must_use_null_useddefaultchar(cv->codepage)) + { + p = &usedDefaultChar; +#ifdef WC_NO_BEST_FIT_CHARS + if (!(cv->flags & FLAG_TRANSLIT)) + flags |= WC_NO_BEST_FIT_CHARS; +#endif + } + len = WideCharToMultiByte(cv->codepage, flags, + (const wchar_t *)wbuf, wbufsize, (char *)buf, bufsize, NULL, p); + if (len == 0) + { + if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) + return_error(E2BIG); + return_error(EILSEQ); + } + else if (usedDefaultChar) + return_error(EILSEQ); + else if (cv->mblen(cv, buf, len) != len) /* validate result */ + return_error(EILSEQ); + return len; +} + +/* + * It seems that the mode (cv->mode) is fixnum. + * For example, when converting iso-2022-jp(cp50221) to unicode: + * in ascii sequence: mode=0xC42C0000 + * in jisx0208 sequence: mode=0xC42C0001 + * "C42C" is same for each convert session. + * It should be: ((codepage-1)<<16)|state + */ +static int +mlang_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize) +{ + int len; + int insize; + HRESULT hr; + + len = cv->mblen(cv, buf, bufsize); + if (len == -1) + return -1; + insize = len; + hr = ConvertINetMultiByteToUnicode(&cv->mode, cv->codepage, + (const char *)buf, &insize, (wchar_t *)wbuf, wbufsize); + if (hr != S_OK || insize != len) + return_error(EILSEQ); + return len; +} + +static int +mlang_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize) +{ + char tmpbuf[MB_CHAR_MAX]; /* enough room for one character */ + int tmpsize = MB_CHAR_MAX; + int insize = wbufsize; + HRESULT hr; + + hr = ConvertINetUnicodeToMultiByte(&cv->mode, cv->codepage, + (const wchar_t *)wbuf, &wbufsize, tmpbuf, &tmpsize); + if (hr != S_OK || insize != wbufsize) + return_error(EILSEQ); + else if (bufsize < tmpsize) + return_error(E2BIG); + else if (cv->mblen(cv, (uchar *)tmpbuf, tmpsize) != tmpsize) + return_error(EILSEQ); + memcpy(buf, tmpbuf, tmpsize); + return tmpsize; +} + +static int +utf16_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize) +{ + if (bufsize < 2) + return_error(EINVAL); + if (cv->codepage == 1200) /* little endian */ + wbuf[0] = (buf[1] << 8) | buf[0]; + else if (cv->codepage == 1201) /* big endian */ + wbuf[0] = (buf[0] << 8) | buf[1]; + if (0xDC00 <= wbuf[0] && wbuf[0] <= 0xDFFF) + return_error(EILSEQ); + if (0xD800 <= wbuf[0] && wbuf[0] <= 0xDBFF) + { + if (bufsize < 4) + return_error(EINVAL); + if (cv->codepage == 1200) /* little endian */ + wbuf[1] = (buf[3] << 8) | buf[2]; + else if (cv->codepage == 1201) /* big endian */ + wbuf[1] = (buf[2] << 8) | buf[3]; + if (!(0xDC00 <= wbuf[1] && wbuf[1] <= 0xDFFF)) + return_error(EILSEQ); + *wbufsize = 2; + return 4; + } + *wbufsize = 1; + return 2; +} + +static int +utf16_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize) +{ + if (bufsize < 2) + return_error(E2BIG); + if (cv->codepage == 1200) /* little endian */ + { + buf[0] = (wbuf[0] & 0x00FF); + buf[1] = (wbuf[0] & 0xFF00) >> 8; + } + else if (cv->codepage == 1201) /* big endian */ + { + buf[0] = (wbuf[0] & 0xFF00) >> 8; + buf[1] = (wbuf[0] & 0x00FF); + } + if (0xD800 <= wbuf[0] && wbuf[0] <= 0xDBFF) + { + if (bufsize < 4) + return_error(E2BIG); + if (cv->codepage == 1200) /* little endian */ + { + buf[2] = (wbuf[1] & 0x00FF); + buf[3] = (wbuf[1] & 0xFF00) >> 8; + } + else if (cv->codepage == 1201) /* big endian */ + { + buf[2] = (wbuf[1] & 0xFF00) >> 8; + buf[3] = (wbuf[1] & 0x00FF); + } + return 4; + } + return 2; +} + +static int +utf32_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize) +{ + uint wc; + + if (bufsize < 4) + return_error(EINVAL); + if (cv->codepage == 12000) /* little endian */ + wc = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; + else if (cv->codepage == 12001) /* big endian */ + wc = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; + if ((0xD800 <= wc && wc <= 0xDFFF) || 0x10FFFF < wc) + return_error(EILSEQ); + ucs4_to_utf16(wc, wbuf, wbufsize); + return 4; +} + +static int +utf32_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize) +{ + uint wc; + + if (bufsize < 4) + return_error(E2BIG); + wc = utf16_to_ucs4(wbuf); + if (cv->codepage == 12000) /* little endian */ + { + buf[0] = wc & 0x000000FF; + buf[1] = (wc & 0x0000FF00) >> 8; + buf[2] = (wc & 0x00FF0000) >> 16; + buf[3] = (wc & 0xFF000000) >> 24; + } + else if (cv->codepage == 12001) /* big endian */ + { + buf[0] = (wc & 0xFF000000) >> 24; + buf[1] = (wc & 0x00FF0000) >> 16; + buf[2] = (wc & 0x0000FF00) >> 8; + buf[3] = wc & 0x000000FF; + } + return 4; +} + +/* + * 50220: ISO 2022 Japanese with no halfwidth Katakana; Japanese (JIS) + * 50221: ISO 2022 Japanese with halfwidth Katakana; Japanese (JIS-Allow + * 1 byte Kana) + * 50222: ISO 2022 Japanese JIS X 0201-1989; Japanese (JIS-Allow 1 byte + * Kana - SO/SI) + * + * MultiByteToWideChar() and WideCharToMultiByte() behave differently + * depending on Windows version. On XP, WideCharToMultiByte() doesn't + * terminate result sequence with ascii escape. But Vista does. + * Use MLang instead. + */ + +#define ISO2022_MODE(cs, shift) (((cs) << 8) | (shift)) +#define ISO2022_MODE_CS(mode) (((mode) >> 8) & 0xFF) +#define ISO2022_MODE_SHIFT(mode) ((mode) & 0xFF) + +#define ISO2022_SI 0 +#define ISO2022_SO 1 + +/* shift in */ +static const char iso2022_SI_seq[] = "\x0F"; +/* shift out */ +static const char iso2022_SO_seq[] = "\x0E"; + +typedef struct iso2022_esc_t iso2022_esc_t; +struct iso2022_esc_t { + const char *esc; + int esc_len; + int len; + int cs; +}; + +#define ISO2022JP_CS_ASCII 0 +#define ISO2022JP_CS_JISX0201_ROMAN 1 +#define ISO2022JP_CS_JISX0201_KANA 2 +#define ISO2022JP_CS_JISX0208_1978 3 +#define ISO2022JP_CS_JISX0208_1983 4 +#define ISO2022JP_CS_JISX0212 5 + +static iso2022_esc_t iso2022jp_esc[] = { + {"\x1B\x28\x42", 3, 1, ISO2022JP_CS_ASCII}, + {"\x1B\x28\x4A", 3, 1, ISO2022JP_CS_JISX0201_ROMAN}, + {"\x1B\x28\x49", 3, 1, ISO2022JP_CS_JISX0201_KANA}, + {"\x1B\x24\x40", 3, 2, ISO2022JP_CS_JISX0208_1983}, /* unify 1978 with 1983 */ + {"\x1B\x24\x42", 3, 2, ISO2022JP_CS_JISX0208_1983}, + {"\x1B\x24\x28\x44", 4, 2, ISO2022JP_CS_JISX0212}, + {NULL, 0, 0, 0} +}; + +static int +iso2022jp_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize) +{ + iso2022_esc_t *iesc = iso2022jp_esc; + char tmp[MB_CHAR_MAX]; + int insize; + HRESULT hr; + DWORD dummy = 0; + int len; + int esc_len; + int cs; + int shift; + int i; + + if (buf[0] == 0x1B) + { + for (i = 0; iesc[i].esc != NULL; ++i) + { + esc_len = iesc[i].esc_len; + if (bufsize < esc_len) + { + if (strncmp((char *)buf, iesc[i].esc, bufsize) == 0) + return_error(EINVAL); + } + else + { + if (strncmp((char *)buf, iesc[i].esc, esc_len) == 0) + { + cv->mode = ISO2022_MODE(iesc[i].cs, ISO2022_SI); + *wbufsize = 0; + return esc_len; + } + } + } + /* not supported escape sequence */ + return_error(EILSEQ); + } + else if (buf[0] == iso2022_SO_seq[0]) + { + cv->mode = ISO2022_MODE(ISO2022_MODE_CS(cv->mode), ISO2022_SO); + *wbufsize = 0; + return 1; + } + else if (buf[0] == iso2022_SI_seq[0]) + { + cv->mode = ISO2022_MODE(ISO2022_MODE_CS(cv->mode), ISO2022_SI); + *wbufsize = 0; + return 1; + } + + cs = ISO2022_MODE_CS(cv->mode); + shift = ISO2022_MODE_SHIFT(cv->mode); + + /* reset the mode for informal sequence */ + if (buf[0] < 0x20) + { + cs = ISO2022JP_CS_ASCII; + shift = ISO2022_SI; + } + + len = iesc[cs].len; + if (bufsize < len) + return_error(EINVAL); + for (i = 0; i < len; ++i) + if (!(buf[i] < 0x80)) + return_error(EILSEQ); + esc_len = iesc[cs].esc_len; + memcpy(tmp, iesc[cs].esc, esc_len); + if (shift == ISO2022_SO) + { + memcpy(tmp + esc_len, iso2022_SO_seq, 1); + esc_len += 1; + } + memcpy(tmp + esc_len, buf, len); + + if ((cv->codepage == 50220 || cv->codepage == 50221 + || cv->codepage == 50222) && shift == ISO2022_SO) + { + /* XXX: shift-out cannot be used for mbtowc (both kernel and + * mlang) */ + esc_len = iesc[ISO2022JP_CS_JISX0201_KANA].esc_len; + memcpy(tmp, iesc[ISO2022JP_CS_JISX0201_KANA].esc, esc_len); + memcpy(tmp + esc_len, buf, len); + } + + insize = len + esc_len; + hr = ConvertINetMultiByteToUnicode(&dummy, cv->codepage, + (const char *)tmp, &insize, (wchar_t *)wbuf, wbufsize); + if (hr != S_OK || insize != len + esc_len) + return_error(EILSEQ); + + /* Check for conversion error. Assuming defaultChar is 0x3F. */ + /* ascii should be converted from ascii */ + if (wbuf[0] == buf[0] + && cv->mode != ISO2022_MODE(ISO2022JP_CS_ASCII, ISO2022_SI)) + return_error(EILSEQ); + + /* reset the mode for informal sequence */ + if (cv->mode != ISO2022_MODE(cs, shift)) + cv->mode = ISO2022_MODE(cs, shift); + + return len; +} + +static int +iso2022jp_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize) +{ + iso2022_esc_t *iesc = iso2022jp_esc; + char tmp[MB_CHAR_MAX]; + int tmpsize = MB_CHAR_MAX; + int insize = wbufsize; + HRESULT hr; + DWORD dummy = 0; + int len; + int esc_len; + int cs; + int shift; + int i; + + /* + * MultiByte = [escape sequence] + character + [escape sequence] + * + * Whether trailing escape sequence is added depends on which API is + * used (kernel or MLang, and its version). + */ + hr = ConvertINetUnicodeToMultiByte(&dummy, cv->codepage, + (const wchar_t *)wbuf, &wbufsize, tmp, &tmpsize); + if (hr != S_OK || insize != wbufsize) + return_error(EILSEQ); + else if (bufsize < tmpsize) + return_error(E2BIG); + + if (tmpsize == 1) + { + cs = ISO2022JP_CS_ASCII; + esc_len = 0; + } + else + { + for (i = 1; iesc[i].esc != NULL; ++i) + { + esc_len = iesc[i].esc_len; + if (strncmp(tmp, iesc[i].esc, esc_len) == 0) + { + cs = iesc[i].cs; + break; + } + } + if (iesc[i].esc == NULL) + /* not supported escape sequence */ + return_error(EILSEQ); + } + + shift = ISO2022_SI; + if (tmp[esc_len] == iso2022_SO_seq[0]) + { + shift = ISO2022_SO; + esc_len += 1; + } + + len = iesc[cs].len; + + /* Check for converting error. Assuming defaultChar is 0x3F. */ + /* ascii should be converted from ascii */ + if (cs == ISO2022JP_CS_ASCII && !(wbuf[0] < 0x80)) + return_error(EILSEQ); + else if (tmpsize < esc_len + len) + return_error(EILSEQ); + + if (cv->mode == ISO2022_MODE(cs, shift)) + { + /* remove escape sequence */ + if (esc_len != 0) + memmove(tmp, tmp + esc_len, len); + esc_len = 0; + } + else + { + if (cs == ISO2022JP_CS_ASCII) + { + esc_len = iesc[ISO2022JP_CS_ASCII].esc_len; + memmove(tmp + esc_len, tmp, len); + memcpy(tmp, iesc[ISO2022JP_CS_ASCII].esc, esc_len); + } + if (ISO2022_MODE_SHIFT(cv->mode) == ISO2022_SO) + { + /* shift-in before changing to other mode */ + memmove(tmp + 1, tmp, len + esc_len); + memcpy(tmp, iso2022_SI_seq, 1); + esc_len += 1; + } + } + + if (bufsize < len + esc_len) + return_error(E2BIG); + memcpy(buf, tmp, len + esc_len); + cv->mode = ISO2022_MODE(cs, shift); + return len + esc_len; +} + +static int +iso2022jp_flush(csconv_t *cv, uchar *buf, int bufsize) +{ + iso2022_esc_t *iesc = iso2022jp_esc; + int esc_len; + + if (cv->mode != ISO2022_MODE(ISO2022JP_CS_ASCII, ISO2022_SI)) + { + esc_len = 0; + if (ISO2022_MODE_SHIFT(cv->mode) != ISO2022_SI) + esc_len += 1; + if (ISO2022_MODE_CS(cv->mode) != ISO2022JP_CS_ASCII) + esc_len += iesc[ISO2022JP_CS_ASCII].esc_len; + if (bufsize < esc_len) + return_error(E2BIG); + + esc_len = 0; + if (ISO2022_MODE_SHIFT(cv->mode) != ISO2022_SI) + { + memcpy(buf, iso2022_SI_seq, 1); + esc_len += 1; + } + if (ISO2022_MODE_CS(cv->mode) != ISO2022JP_CS_ASCII) + { + memcpy(buf + esc_len, iesc[ISO2022JP_CS_ASCII].esc, + iesc[ISO2022JP_CS_ASCII].esc_len); + esc_len += iesc[ISO2022JP_CS_ASCII].esc_len; + } + return esc_len; + } + return 0; +} + +#if defined(MAKE_DLL) && defined(USE_LIBICONV_DLL) +BOOL WINAPI +DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved) +{ + switch( fdwReason ) + { + case DLL_PROCESS_ATTACH: + hwiniconv = (HMODULE)hinstDLL; + break; + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + case DLL_PROCESS_DETACH: + break; + } + return TRUE; +} +#endif + +#if defined(MAKE_EXE) +#include +#include +#include +int +main(int argc, char **argv) +{ + char *fromcode = NULL; + char *tocode = NULL; + int i; + char inbuf[BUFSIZ]; + char outbuf[BUFSIZ]; + const char *pin; + char *pout; + size_t inbytesleft; + size_t outbytesleft; + size_t rest = 0; + iconv_t cd; + size_t r; + FILE *in = stdin; + + _setmode(_fileno(stdin), _O_BINARY); + _setmode(_fileno(stdout), _O_BINARY); + + for (i = 1; i < argc; ++i) + { + if (strcmp(argv[i], "-l") == 0) + { + for (i = 0; codepage_alias[i].name != NULL; ++i) + printf("%s\n", codepage_alias[i].name); + return 0; + } + + if (strcmp(argv[i], "-f") == 0) + fromcode = argv[++i]; + else if (strcmp(argv[i], "-t") == 0) + tocode = argv[++i]; + else + { + in = fopen(argv[i], "rb"); + if (in == NULL) + { + fprintf(stderr, "cannot open %s\n", argv[i]); + return 1; + } + break; + } + } + + if (fromcode == NULL || tocode == NULL) + { + printf("usage: %s -f from-enc -t to-enc [file]\n", argv[0]); + return 0; + } + + cd = iconv_open(tocode, fromcode); + if (cd == (iconv_t)(-1)) + { + perror("iconv_open error"); + return 1; + } + + while ((inbytesleft = fread(inbuf + rest, 1, sizeof(inbuf) - rest, in)) != 0 + || rest != 0) + { + inbytesleft += rest; + pin = inbuf; + pout = outbuf; + outbytesleft = sizeof(outbuf); + r = iconv(cd, &pin, &inbytesleft, &pout, &outbytesleft); + fwrite(outbuf, 1, sizeof(outbuf) - outbytesleft, stdout); + if (r == (size_t)(-1) && errno != EINVAL && errno != E2BIG) + { + perror("conversion error"); + return 1; + } + memmove(inbuf, pin, inbytesleft); + rest = inbytesleft; + } + pout = outbuf; + outbytesleft = sizeof(outbuf); + r = iconv(cd, NULL, NULL, &pout, &outbytesleft); + fwrite(outbuf, 1, sizeof(outbuf) - outbytesleft, stdout); + if (r == (size_t)(-1)) + { + perror("conversion error"); + return 1; + } + + iconv_close(cd); + + return 0; +} +#endif +#endif // USE_WIN_ICONV +#endif // WIN32 diff --git a/lib_acl_cpp/src/stdlib/internal/win_iconv.hpp b/lib_acl_cpp/src/stdlib/internal/win_iconv.hpp new file mode 100644 index 000000000..687121072 --- /dev/null +++ b/lib_acl_cpp/src/stdlib/internal/win_iconv.hpp @@ -0,0 +1,14 @@ +#pragma once + +#ifdef WIN32 +#ifdef USE_WIN_ICONV + +typedef void* iconv_t; + +iconv_t iconv_open(const char *tocode, const char *fromcode); +int iconv_close(iconv_t cd); +size_t iconv(iconv_t cd, const char **inbuf, size_t *inbytesleft, + char **outbuf, size_t *outbytesleft); + +#endif +#endif diff --git a/lib_acl_cpp/src/stdlib/json.cpp b/lib_acl_cpp/src/stdlib/json.cpp new file mode 100644 index 000000000..8d57e8c5f --- /dev/null +++ b/lib_acl_cpp/src/stdlib/json.cpp @@ -0,0 +1,355 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/stdlib/json.hpp" + +namespace acl +{ + +json_node::json_node(ACL_JSON_NODE* node, json* json_ptr) + : node_me_(node) + , json_(json_ptr) + , parent_(NULL) + , parent_saved_(NULL) + , child_(NULL) + , iter_(NULL) +{ + acl_assert(json_ptr); +} + +json_node::~json_node(void) +{ + if (parent_saved_) + delete parent_saved_; + if (child_) + delete child_; + if (iter_) + acl_myfree(iter_); +} + +const char* json_node::tag_name(void) const +{ + if (node_me_->ltag && ACL_VSTRING_LEN(node_me_->ltag) > 0) + return (acl_vstring_str(node_me_->ltag)); + else + return (NULL); +} + +const char* json_node::get_text(void) const +{ + if (node_me_->text && ACL_VSTRING_LEN(node_me_->text) > 0) + return acl_vstring_str(node_me_->text); + else + return NULL; +} + +json_node& json_node::add_child(json_node* child, + bool return_child /* = false */) +{ + ACL_JSON_NODE* node = child->get_json_node(); + // 先添加 child 至父结点中 + acl_json_node_add_child(node_me_, node); + child->parent_ = this; + if (return_child) + return *child; + return *this; +} + +json_node& json_node::add_child(json_node& child, + bool return_child /* = false */) +{ + return add_child(&child, return_child); +} + +json_node& json_node::add_child(bool as_array /* = false */, + bool return_child /* = false */) +{ + return add_child(json_->create_node(as_array), return_child); +} + +json_node& json_node::add_child(const char* tag, const char* value, + bool return_child /* = false */) +{ + return add_child(json_->create_node(tag, value), return_child); +} + +json_node& json_node::add_child(const char* tag, json_node* node, + bool return_child /* = false */) +{ + return add_child(json_->create_node(tag, node), return_child); +} + +json_node& json_node::add_child(const char* tag, json_node& node, + bool return_child /* = false */) +{ + return add_child(tag, &node, return_child); +} + +json_node& json_node::get_parent() const +{ + if (parent_) + return *parent_; + else if (node_me_->parent == node_me_->json->root) + return json_->get_root(); + else if (node_me_->parent == NULL) // xxx: can this happen? + return json_->get_root(); + + const_cast(this)->parent_saved_ = + NEW json_node(node_me_->parent, json_); + const_cast(this)->parent_ = parent_saved_; + return *parent_saved_; +} + +json_node* json_node::first_child(void) +{ + if (iter_ == NULL) + iter_ = (ACL_ITER*) acl_mymalloc(sizeof(ACL_ITER)); + + ACL_JSON_NODE* node = node_me_->iter_head(iter_, node_me_); + if (node == NULL) + return NULL; + + if (child_ == NULL) + child_ = NEW json_node(node, json_); + else + child_->node_me_ = node; + return child_; +} + +json_node* json_node::next_child(void) +{ + acl_assert(iter_); + acl_assert(child_); + + ACL_JSON_NODE* node = node_me_->iter_next(iter_, node_me_); + if (node == NULL) + return NULL; + child_->node_me_ = node; + return child_; +} + +int json_node::depth(void) const +{ + return node_me_->depth; +} + +int json_node::children_count(void) const +{ + return acl_ring_size(&node_me_->children); +} + +json& json_node::get_json(void) const +{ + return *json_; +} + +ACL_JSON_NODE* json_node::get_json_node() const +{ + return node_me_; +} + +void json_node::set_json_node(ACL_JSON_NODE* node) +{ + node_me_ = node; +} + +////////////////////////////////////////////////////////////////////////// + +json::json(const char* data /* = NULL */) +{ + json_ = acl_json_alloc(); + root_ = NULL; + node_tmp_ = NULL; + buf_ = NULL; + iter_ = NULL; + if (data && *data) + update(data); +} + +json::~json(void) +{ + clear(); + if (json_) + acl_json_free(json_); + if (root_) + delete root_; + if (node_tmp_) + delete node_tmp_; + if (buf_) + delete buf_; + if (iter_) + acl_myfree(iter_); +} + +json& json::part_word(bool on) +{ + if (on) + json_->flag |= ACL_JSON_FLAG_PART_WORD; + else + json_->flag &= ~ACL_JSON_FLAG_PART_WORD; + return *this; +} + +void json::update(const char* data) +{ + acl_json_update(json_, data); +} + +const std::vector& json::getElementsByTagName(const char* tag) const +{ + const_cast(this)->clear(); + ACL_ARRAY* a = acl_json_getElementsByTagName(json_, tag); + if (a != NULL) { + ACL_ITER iter; + acl_foreach(iter, a) + { + ACL_JSON_NODE *tmp = (ACL_JSON_NODE*) iter.data; + json_node* node = NEW json_node(tmp, const_cast(this)); + const_cast(this)->nodes_tmp_.push_back(node); + } + } + acl_json_free_array(a); + return nodes_tmp_; +} + +const std::vector& json::getElementsByTags(const char* tags) const +{ + const_cast(this)->clear(); + ACL_ARRAY* a = acl_json_getElementsByTags(json_, tags); + if (a != NULL) { + ACL_ITER iter; + acl_foreach(iter, a) + { + ACL_JSON_NODE *tmp = (ACL_JSON_NODE*) iter.data; + json_node* node = NEW json_node(tmp, const_cast(this)); + const_cast(this)->nodes_tmp_.push_back(node); + } + } + acl_json_free_array(a); + return nodes_tmp_; +} + +ACL_JSON* json::get_json(void) const +{ + return json_; +} + +json_node& json::create_node(const char* tag, const char* value) +{ + ACL_JSON_NODE* node = acl_json_create_leaf(json_, tag, value); + json_node* n = NEW json_node(node, this); + nodes_.push_back(n); + return *n; +} + +json_node& json::create_node(bool as_array /* = false */) +{ + ACL_JSON_NODE* node; + + if (as_array) + node = acl_json_create_array(json_); + else + node = acl_json_create_obj(json_); + json_node* n = NEW json_node(node, this); + nodes_.push_back(n); + return *n; +} + +json_node& json::create_node(const char* tag, json_node* node) +{ + ACL_JSON_NODE* tmp = acl_json_create_node(json_, + tag, node->get_json_node()); + json_node* n = NEW json_node(tmp, this); + nodes_.push_back(n); + return *n; +} + +json_node& json::create_node(const char* tag, json_node& node) +{ + ACL_JSON_NODE* tmp = acl_json_create_node(json_, + tag, node.get_json_node()); + json_node* n = NEW json_node(tmp, this); + nodes_.push_back(n); + return *n; +} + +json_node& json::get_root(void) +{ + if (root_) + return *root_; + root_ = NEW json_node(json_->root, this); + return *root_; +} + +json_node* json::first_node(void) +{ + if (iter_ == NULL) + iter_ = (ACL_ITER*) acl_mymalloc(sizeof(ACL_ITER)); + ACL_JSON_NODE* node = json_->iter_head(iter_, json_); + if (node == NULL) + return NULL; + if (node_tmp_ == NULL) + node_tmp_ = NEW json_node(node, this); + else + node_tmp_->set_json_node(node); + return node_tmp_; +} + +json_node* json::next_node(void) +{ + acl_assert(iter_); + acl_assert(node_tmp_); + ACL_JSON_NODE* node = json_->iter_next(iter_, json_); + if (node == NULL) + return NULL; + node_tmp_->set_json_node(node); + return node_tmp_; +} + +void json::build_json(string& out) +{ + ACL_VSTRING* buf = out.vstring(); + (void) acl_json_build(json_, buf); +} + +void json::reset(void) +{ + clear(); + if (json_) + acl_json_reset(json_); + else + json_ = acl_json_alloc(); +} + +int json::push_pop(const char* in, size_t len acl_unused, + string* out, size_t max /* = 0 */) +{ + if (in) + update(in); + if (out == NULL) + return (0); + if (max > 0 && len > max) + len = max; + out->append(in, len); + return len; +} + +int json::pop_end(string* out acl_unused, size_t max /* = 0 */ acl_unused) +{ + return 0; +} + +void json::clear(void) +{ + if (buf_) + buf_->clear(); + + std::vector::iterator it = nodes_tmp_.begin(); + for (; it != nodes_tmp_.end(); ++it) + delete (*it); + nodes_tmp_.clear(); + + std::list::iterator it1 = nodes_.begin(); + for (; it1 != nodes_.end(); ++it1) + delete (*it1); +} + +} // namespace acl diff --git a/lib_acl_cpp/src/stdlib/locker.cpp b/lib_acl_cpp/src/stdlib/locker.cpp new file mode 100644 index 000000000..4bf3c2614 --- /dev/null +++ b/lib_acl_cpp/src/stdlib/locker.cpp @@ -0,0 +1,124 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/stdlib/locker.hpp" + +namespace acl { + +locker::locker(bool use_mutex /* = true */, bool nowait /* = false */) + : pFile_(NULL) + , myFHandle_(false) + , nowait_(nowait) +{ + fHandle_ = ACL_FILE_INVALID; + if (use_mutex) + init_mutex(); + else + pMutex_ = NULL; +} + +locker::~locker() +{ + if (pFile_) + acl_myfree(pFile_); + if (myFHandle_ && fHandle_ != ACL_FILE_INVALID) + acl_file_close(fHandle_); + if (pMutex_) + { +#ifndef WIN32 + pthread_mutexattr_destroy(&mutexAttr_); +#endif + acl_pthread_mutex_destroy(pMutex_); + acl_myfree(pMutex_); + } +} + +void locker::init_mutex() +{ + pMutex_ = (acl_pthread_mutex_t*) + acl_mycalloc(1, sizeof(acl_pthread_mutex_t)); +#ifndef WIN32 + pthread_mutexattr_init(&mutexAttr_); + pthread_mutexattr_settype(&mutexAttr_, PTHREAD_MUTEX_RECURSIVE); + acl_pthread_mutex_init(pMutex_, &mutexAttr_); +#else + acl_pthread_mutex_init(pMutex_, NULL); +#endif +} + +bool locker::open(const char* file_path) +{ + acl_assert(file_path && *file_path); + acl_assert(pFile_ == NULL); + acl_assert(fHandle_ == ACL_FILE_INVALID); + + fHandle_ = acl_file_open(file_path, O_RDWR | O_CREAT, 0600); + if (fHandle_ == ACL_FILE_INVALID) + return false; + myFHandle_ = true; + pFile_ = acl_mystrdup(file_path); + return true; +} + +bool locker::open(ACL_FILE_HANDLE fh) +{ + acl_assert(myFHandle_ == false); + fHandle_ = fh; + return true; +} + +bool locker::lock() +{ + if (pMutex_) + { + if (nowait_) + { + if (acl_pthread_mutex_trylock(pMutex_) == -1) + return false; + } + else if (acl_pthread_mutex_lock(pMutex_) == -1) + return false; + } + + if (fHandle_ != ACL_FILE_INVALID) + { + int operation = ACL_MYFLOCK_OP_EXCLUSIVE; + if (nowait_) + operation |= ACL_MYFLOCK_OP_NOWAIT; + if (acl_myflock(fHandle_, ACL_MYFLOCK_STYLE_FCNTL, + operation) == -1) + { + return false; + } + } else if (pFile_ != NULL) + return false; + return true; +} + +bool locker::unlock() +{ + bool ret; + + if (pMutex_) + { + if (acl_pthread_mutex_unlock(pMutex_) == -1) + ret = false; + else + ret = true; + } + + if (fHandle_ != ACL_FILE_INVALID) + { + if (acl_myflock(fHandle_, ACL_MYFLOCK_STYLE_FCNTL, + ACL_MYFLOCK_OP_NONE) == -1) + { + ret = false; + } + else + ret = true; + } else if (pFile_ != NULL) + ret = false; + else + ret = true; + return (ret); +} + +} // namespace acl diff --git a/lib_acl_cpp/src/stdlib/log.cpp b/lib_acl_cpp/src/stdlib/log.cpp new file mode 100644 index 000000000..db9f58b79 --- /dev/null +++ b/lib_acl_cpp/src/stdlib/log.cpp @@ -0,0 +1,278 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/stdlib/string.hpp" +#include "acl_cpp/stdlib/log.hpp" + +namespace acl { + +static bool m_bOpened = false; + +void log::open(const char* recipients, const char* procname /* = unknown */, + const char* cfg /* = NULL */) +{ + if (m_bOpened) + return; + + acl_assert(recipients); + acl_assert(procname); + + const char* ptr = strrchr(procname, '/'); + if (ptr) + procname = ptr + 1; +#ifdef WIN32 + if (ptr == NULL) + { + ptr = strrchr(procname, '\\'); + if (ptr) + procname = ptr + 1; + } +#endif + + acl_msg_open(recipients, procname); + m_bOpened = true; + if (cfg) + acl_debug_init(cfg); +} + +void log::close(void) +{ + if (m_bOpened) { + acl_msg_close(); + acl_debug_end(); + m_bOpened = false; + } +} + +void log::stdout_open(bool onoff) +{ + acl_msg_stdout_enable(onoff ? 1 : 0); +} + +void log::msg1(const char* fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vmsg2(fmt, ap); + va_end(ap); +} + +void log::vmsg2(const char* fmt, va_list ap) +{ + acl_msg_info2(fmt, ap); +} + +void log::msg4(const char* fname, int line, const char* func, + const char* fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vmsg5(fname, line, func, fmt, ap); + va_end(ap); +} + +void log::vmsg5(const char* fname, int line, const char* func, + const char* fmt, va_list ap) +{ + const char* ptr = strrchr(fname, '/'); + if (ptr) + fname = ptr + 1; +#ifdef WIN32 + if (ptr == NULL) + { + ptr = strrchr(fname, '\\'); + if (ptr) + fname = ptr + 1; + } +#endif + acl::string s; + s.format("%s(%d), %s: ", fname, line, func); + s.vformat_append(fmt, ap); + acl_msg_info("%s", s.c_str()); +} + +void log::msg3(size_t section, size_t level, const char* fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vmsg4(section, level, fmt, ap); + va_end(ap); +} + +void log::vmsg4(size_t section, size_t level, const char* fmt, va_list ap) +{ + if (acl_do_debug((int) section, (int) level)) + vmsg2(fmt, ap); +} + +void log::msg6(size_t section, size_t level, const char* fname, + int line, const char* func, const char* fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vmsg7(section, level, fname, line, func, fmt, ap); + va_end(ap); +} + +void log::vmsg7(size_t section, size_t level, const char* fname, + int line, const char* func, const char* fmt, va_list ap) +{ + if (!acl_do_debug((int) section, (int) level)) + return; + + const char* ptr = strrchr(fname, '/'); + if (ptr) + fname = ptr + 1; +#ifdef WIN32 + if (ptr == NULL) + { + ptr = strrchr(fname, '\\'); + if (ptr) + fname = ptr + 1; + } +#endif + + acl::string s; + s.format("%s(%d), %s: ", fname, line, func); + s.vformat_append(fmt, ap); + acl_msg_info("%s", s.c_str()); +} + +void log::warn1(const char* fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vwarn2(fmt, ap); + va_end(ap); +} + +void log::vwarn2(const char* fmt, va_list ap) +{ + acl_msg_warn2(fmt, ap); +} + +void log::warn4(const char* fname, int line, const char* func, + const char* fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vwarn5(fname, line, func, fmt, ap); + va_end(ap); +} + +void log::vwarn5(const char* fname, int line, const char* func, + const char* fmt, va_list ap) +{ + const char* ptr = strrchr(fname, '/'); + if (ptr) + fname = ptr + 1; +#ifdef WIN32 + if (ptr == NULL) + { + ptr = strrchr(fname, '\\'); + if (ptr) + fname = ptr + 1; + } +#endif + + acl::string s; + s.format("%s(%d), %s: ", fname, line, func); + s.vformat_append(fmt, ap); + acl_msg_warn("%s", s.c_str()); +} + +void log::error1(const char* fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + verror2(fmt, ap); + va_end(ap); +} + +void log::verror2(const char* fmt, va_list ap) +{ + acl_msg_error2(fmt, ap); +} + +void log::error4(const char* fname, int line, const char* func, + const char* fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + verror5(fname, line, func, fmt, ap); + va_end(ap); +} + +void log::verror5(const char* fname, int line, const char* func, + const char* fmt, va_list ap) +{ + const char* ptr = strrchr(fname, '/'); + if (ptr) + fname = ptr + 1; +#ifdef WIN32 + if (ptr == NULL) + { + ptr = strrchr(fname, '\\'); + if (ptr) + fname = ptr + 1; + } +#endif + + acl::string s; + s.format("%s(%d), %s: ", fname, line, func); + s.vformat_append(fmt, ap); + acl_msg_error("%s", s.c_str()); +} + +void log::fatal1(const char* fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vfatal2(fmt, ap); + va_end(ap); +} + +void log::vfatal2(const char* fmt, va_list ap) +{ + acl_msg_fatal2(fmt, ap); +} + +void log::fatal4(const char* fname, int line, const char* func, + const char* fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vfatal5(fname, line, func, fmt, ap); + va_end(ap); +} + +void log::vfatal5(const char* fname, int line, const char* func, + const char* fmt, va_list ap) +{ + const char* ptr = strrchr(fname, '/'); + if (ptr) + fname = ptr + 1; +#ifdef WIN32 + if (ptr == NULL) + { + ptr = strrchr(fname, '\\'); + if (ptr) + fname = ptr + 1; + } +#endif + + acl::string s; + s.format("%s(%d), %s: ", fname, line, func); + s.vformat_append(fmt, ap); + acl_msg_fatal("%s", s.c_str()); +} + +} // namespace acl diff --git a/lib_acl_cpp/src/stdlib/malloc.cpp b/lib_acl_cpp/src/stdlib/malloc.cpp new file mode 100644 index 000000000..ef7435fa5 --- /dev/null +++ b/lib_acl_cpp/src/stdlib/malloc.cpp @@ -0,0 +1,62 @@ +#include "acl_stdafx.hpp" +#include +#include "acl_cpp/stdlib/malloc.hpp" + +#ifdef HOOK_NEW + +#ifdef WIN32 + +# ifdef NDEBUG +void* operator new(size_t n) +{ + return acl::acl_new(n, __FILE__, __FUNCTION__, __LINE__); +} + +void operator delete(void *p) +{ + acl::acl_delete(p, __FILE__, __FUNCTION__, __LINE__); +} +# endif + +#else // WIN32 + +void* operator new(size_t n) throw (std::bad_alloc) +{ + return acl::acl_new(n, __FILE__, __FUNCTION__, __LINE__); +} +void operator delete(void *p) throw() +{ + acl::acl_delete(p, __FILE__, __FUNCTION__, __LINE__); +} + +#endif // !WIN32 + +#endif // HOOK_NEW + +namespace acl +{ + +static ACL_MEM_SLICE* __mem_slice = NULL; + +void acl_slice_init(void) +{ + __mem_slice = acl_mem_slice_init(8, 10240, 100000, + ACL_SLICE_FLAG_GC2 | ACL_SLICE_FLAG_RTGC_OFF | ACL_SLICE_FLAG_LP64_ALIGN); +} + +void* acl_new(size_t size, const char* filename, + const char* funcname acl_unused, int lineno) +{ + void* ptr = acl_malloc_glue(filename, lineno, size); + return (ptr); +} + +void acl_delete(void *ptr, const char* filename, + const char* funcname acl_unused, int lineno) +{ + if (ptr == NULL) + return; + acl_free_glue(filename, lineno, ptr); +} + +} // namespace acl diff --git a/lib_acl_cpp/src/stdlib/md5.cpp b/lib_acl_cpp/src/stdlib/md5.cpp new file mode 100644 index 000000000..73c629ec4 --- /dev/null +++ b/lib_acl_cpp/src/stdlib/md5.cpp @@ -0,0 +1,363 @@ +/* MS VisualStudio Projects are monolithic, so we need the following + * #if to exclude the MD5 code from compile process when we are + * building the SSL support. + */ +#include "acl_stdafx.hpp" +#include +#include "acl_cpp/stream/istream.hpp" +#include "acl_cpp/stream/ifstream.hpp" +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/stdlib/util.hpp" +#include "acl_cpp/stdlib/md5.hpp" + +#ifdef WORDS_BIGENDIAN +static void byteSwap(uint32_t * buf, unsigned words) +{ + uint8_t *p = (uint8_t *) buf; + + do { + *buf++ = (uint32_t) ((unsigned) p[3] << 8 | p[2]) << 16 | + ((unsigned) p[1] << 8 | p[0]); + p += 4; + } while (--words); +} +#else +#define byteSwap(buf,words) +#endif + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f,w,x,y,z,in,s) \ + (w += f(x,y,z) + in, w = (w<>(32-s)) + x) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +static void transform(unsigned int buf[4], unsigned int const in[16]) +{ + register unsigned int a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +namespace acl +{ + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +md5::md5() +{ + reset(); +} + +md5::~md5() +{ + +} + +md5& md5::reset() +{ + buf_[0] = 0x67452301; + buf_[1] = 0xefcdab89; + buf_[2] = 0x98badcfe; + buf_[3] = 0x10325476; + bytes_[0] = 0; + bytes_[1] = 0; + memset(in_, 0, sizeof(in_)); + + digest_[0] = 0; + digest_s_[0] = 0; + return *this; +} + +/* + * update context to reflect the concatenation of another buffer full + * of bytes. + */ +md5& md5::update(const void *in, size_t len) +{ + const unsigned char *buf = (const unsigned char *) in; + unsigned int t; + + /* Update byte count */ + + t = bytes_[0]; + if ((bytes_[0] = t + len) < t) + bytes_[1]++; /* Carry from low to high */ + + t = 64 - (t & 0x3f); /* Space available in in_ (at least 1) */ + if ((size_t) t > len) + { + memcpy((unsigned char *) in_ + 64 - t, buf, len); + return *this; + } + /* First chunk is an odd size */ + memcpy((unsigned char *) in_ + 64 - t, buf, t); + byteSwap(in_, 16); + transform(buf_, in_); + buf += t; + len -= t; + + /* Process data in 64-byte chunks */ + while (len >= 64) + { + memcpy(in_, buf, 64); + byteSwap(in_, 16); + transform(buf_, in_); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + memcpy(in_, buf, len); + + return *this; +} + +/* + * finish wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +md5& md5::finish() +{ + int count = bytes_[0] & 0x3f; /* Number of bytes in ctx->in */ + unsigned char *p = (unsigned char *) in_ + count; + + /* Set the first char of padding to 0x80. There is always room. */ + *p++ = 0x80; + + /* Bytes of padding needed to make 56 bytes (-8..55) */ + count = 56 - 1 - count; + + if (count < 0) + { + /* Padding forces an extra block */ + memset(p, 0, count + 8); + byteSwap(in_, 16); + transform(buf_, in_); + p = (unsigned char *) in_; + count = 56; + } + memset(p, 0, count); + byteSwap(ctx->in, 14); + + /* Append length in bits and transform */ + in_[14] = bytes_[0] << 3; + in_[15] = bytes_[1] << 3 | bytes_[0] >> 29; + transform(buf_, in_); + + byteSwap(buf_, 4); + memcpy(digest_, buf_, 16); + + /* In case it's sensitive */ + memset(buf_, 0, sizeof(buf_)); + memset(bytes_, 0, sizeof(bytes_)); + memset(in_, 0, sizeof(in_)); + + return *this; +} + +const char* md5::get_digest() const +{ + return (const char*) digest_; +} + +const char* md5::get_string() const +{ + const_cast(this)->hex_encode(digest_, + (char*) digest_s_, sizeof(digest_s_)); + return (const char*) digest_s_; +} + +const char* md5::md5_digest(const void *dat, size_t dlen, + const void *key, size_t klen, void* out, size_t size) +{ + md5 md5; + + size = size > 16 ? 16 : size; + + if (key != NULL && klen > 0) + md5.update(key, klen); + md5.update(dat, dlen); + md5.finish(); + memcpy(out, md5.get_digest(), size); + return ((const char*) out); +} + +const char* md5::md5_string(const void *dat, size_t dlen, + const void *key, size_t klen, char* out, size_t size) +{ + md5 md5; + + if (key != NULL && klen > 0) + md5.update(key, klen); + md5.update(dat, dlen); + md5.finish(); + + const unsigned char* d = (const unsigned char*) md5.get_digest(); + hex_encode(d, out, size); + return (out); +} + +acl_int64 md5::md5_file(const char* path, const void *key, size_t klen, + char* out, size_t size) +{ + ifstream in; + + if (in.open_read(path) == false) + { + logger_error("open file: %s error: %s", path, last_serror()); + return -1; + } + return md5_file(in, key, klen, out, size); +} + +acl_int64 md5::md5_file(istream& in, const void *key, size_t klen, + char* out, size_t size) +{ + acl_int64 n = 0; + char buf[8192]; + int ret; + md5 md5; + + if (size < 33) + { + logger_error("size(%d) < 33", (int) size); + return -1; + } + + if (key && klen > 0) + md5.update(key, klen); + while (true) + { + ret = in.read(buf, sizeof(buf), false); + if (ret < 0) + break; + n += ret; + md5.update(buf, ret); + } + + if (n == 0) + return -1; + md5.finish(); + + const char* ptr = md5.get_digest(); + hex_encode(ptr, out, size); + return n; +} + +const char* md5::hex_encode(const void *in, char* out, size_t size) +{ + size_t i; + char buf[34]; // xxx: 必须是 34 个字节 + char *ptr; + unsigned char digest[16]; + + acl_assert(size >= 33); + + memcpy(digest, in, 16); + + for (i = 0; i < 16; i++) + { + sprintf(&(buf[2 * i]), "%02x", (unsigned char) digest[i]); + sprintf(&(buf[2 * i + 1]), "%02x", + (unsigned char) (digest[i] << 4)); + } + + ptr = out; + + for (i = 0; i < 32; i++) + *ptr++ = buf[i]; + *ptr = '\0'; + + return (out); +} + +} // namespace acl diff --git a/lib_acl_cpp/src/stdlib/pipe_stream.cpp b/lib_acl_cpp/src/stdlib/pipe_stream.cpp new file mode 100644 index 000000000..31f55f9b0 --- /dev/null +++ b/lib_acl_cpp/src/stdlib/pipe_stream.cpp @@ -0,0 +1,318 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/stdlib/pipe_stream.hpp" +#include "acl_cpp/stdlib/string.hpp" + +namespace acl { + +pipe_string::pipe_string() +{ + m_pBuf = NEW string(128); + m_pSavedBufPtr = m_pBuf; + m_pos = 0; +} + +pipe_string::pipe_string(string& s) +{ + m_pBuf = &s; + m_pSavedBufPtr = NULL; + m_pos = 0; +} + +pipe_string::~pipe_string() +{ + if (m_pSavedBufPtr) + delete m_pSavedBufPtr; +} + +int pipe_string::push_pop(const char* in, size_t len, + string* out, size_t max /* = 0 */) +{ + if (in && len > 0) + m_pBuf->append(in, len); + + if (out == NULL) + return (0); + + len = m_pBuf->length(); + acl_assert(len >= m_pos); + len -= m_pos; + + if (len == 0) + return (0); + + size_t n; + if (max > 0) + n = max > len ? len : max; + else + n = len; + + out->append(m_pBuf->c_str() + m_pos, n); + m_pos += n; + return (n); +} + +int pipe_string::pop_end(string* out, size_t max /* = 0 */) +{ + if (out == NULL) + return (0); + size_t n = m_pBuf->length(); + acl_assert(n >= m_pos); + n -= m_pos; + if (n == 0) + return (0); + if (max > 0 && n > max) + n = max; + out->append(m_pBuf->c_str() + m_pos, n); + m_pos += n; + return (n); +} + +//////////////////////////////////////////////////////////////////////// + +pipe_manager::pipe_manager() +{ + m_pBuf1 = NEW string(128); + m_pBuf2 = NEW string(128); + m_pPipeStream = NULL; +} + +pipe_manager::~pipe_manager() +{ + delete m_pBuf1; + delete m_pBuf2; + if (m_pPipeStream) + delete m_pPipeStream; +} + +bool pipe_manager::push_back(pipe_stream* stream) +{ + std::list::const_iterator cit = m_streams.begin(); + + for (; cit != m_streams.end(); ++cit) + { + if (stream == *cit) + return (false); + } + + m_streams.push_back(stream); + return (true); +} + +bool pipe_manager::push_front(pipe_stream* stream) +{ + std::list::const_iterator cit = m_streams.begin(); + + for (; cit != m_streams.end(); ++cit) + { + if (stream == *cit) + return (false); + } + + m_streams.push_front(stream); + return (true); +} + +bool pipe_manager::update(const char* src, size_t len, + pipe_stream* out /* = NULL */) +{ + std::list::iterator it = m_streams.begin(); + + string* pBuf = m_pBuf1; + string* pLast = pBuf; + pBuf->clear(); + + for (; it != m_streams.end(); ++it) + { + if (len > 0 && (*it)->push_pop(src, len, pBuf) == -1) + return (false); + src = pBuf->c_str(); + len = pBuf->length(); + pLast = pBuf; + if (pBuf == m_pBuf1) + pBuf = m_pBuf2; + else + pBuf = m_pBuf1; + pBuf->clear(); + } + + if (!pLast->empty() && out != NULL) + return (out->push_pop(pLast->c_str(), + pLast->length(), NULL) == -1 ? false : true); + return (true); +} + +bool pipe_manager::update_end(pipe_stream* out /* = NULL */) +{ + if (m_streams.empty()) + return (true); + + std::list::iterator it = m_streams.begin(); + + string* pBuf = m_pBuf2; + pBuf->clear(); + + if ((*it)->pop_end(pBuf) == -1) + return (false); + + string* pLast = pBuf; + const char* ptr = pLast->c_str(); + size_t len = pLast->length(); + + pBuf = m_pBuf1; + pBuf->clear(); + + ++it; + for (; it != m_streams.end(); ++it) + { + if (len > 0 && (*it)->push_pop(ptr, len, pBuf) == -1) + return (false); + if ((*it)->pop_end(pBuf) == -1) + return (false); + + pLast = pBuf; + ptr = pLast->c_str(); + len = pLast->length(); + + if (pBuf == m_pBuf1) + pBuf = m_pBuf2; + else + pBuf = m_pBuf1; + pBuf->clear(); + } + + if (!pLast->empty() && out != NULL) + return (out->push_pop(pLast->c_str(), + pLast->length(), NULL) == -1 ? false : true); + return (true); +} + +pipe_manager& pipe_manager::operator<<(const acl::string& s) +{ + if (m_pPipeStream == NULL) + m_pPipeStream = NEW pipe_string(); + update(s.c_str(), s.length(), m_pPipeStream); + return (*this); +} + +pipe_manager& pipe_manager::operator<<(const acl::string* s) +{ + if (m_pPipeStream == NULL) + m_pPipeStream = NEW pipe_string(); + update(s->c_str(), s->length(), m_pPipeStream); + return (*this); +} + +pipe_manager& pipe_manager::operator<<(const char* s) +{ + if (m_pPipeStream == NULL) + m_pPipeStream = NEW pipe_string(); + update(s, strlen(s), m_pPipeStream); + return (*this); +} + +pipe_manager& pipe_manager::operator<<(acl_int64 n) +{ + if (m_pPipeStream == NULL) + m_pPipeStream = NEW pipe_string(); + update((const char*) &n, sizeof(n), m_pPipeStream); + return (*this); +} + +pipe_manager& pipe_manager::operator<<(acl_uint64 n) +{ + if (m_pPipeStream == NULL) + m_pPipeStream = NEW pipe_string(); + update((const char*) &n, sizeof(n), m_pPipeStream); + return (*this); +} + +pipe_manager& pipe_manager::operator<<(long n) +{ + if (m_pPipeStream == NULL) + m_pPipeStream = NEW pipe_string(); + update((const char*) &n, sizeof(n), m_pPipeStream); + return (*this); +} + +pipe_manager& pipe_manager::operator<<(unsigned long n) +{ + if (m_pPipeStream == NULL) + m_pPipeStream = NEW pipe_string(); + update((const char*) &n, sizeof(n), m_pPipeStream); + return (*this); +} + +pipe_manager& pipe_manager::operator<<(int n) +{ + if (m_pPipeStream == NULL) + m_pPipeStream = NEW pipe_string(); + update((const char*) &n, sizeof(n), m_pPipeStream); + return (*this); +} + +pipe_manager& pipe_manager::operator<<(unsigned int n) +{ + if (m_pPipeStream == NULL) + m_pPipeStream = NEW pipe_string(); + update((const char*) &n, sizeof(n), m_pPipeStream); + return (*this); +} + +pipe_manager& pipe_manager::operator<<(short n) +{ + if (m_pPipeStream == NULL) + m_pPipeStream = NEW pipe_string(); + update((const char*) &n, sizeof(n), m_pPipeStream); + return (*this); +} + +pipe_manager& pipe_manager::operator<<(unsigned short n) +{ + if (m_pPipeStream == NULL) + m_pPipeStream = NEW pipe_string(); + update((const char*) &n, sizeof(n), m_pPipeStream); + return (*this); +} + +pipe_manager& pipe_manager::operator<<(char n) +{ + if (m_pPipeStream == NULL) + m_pPipeStream = NEW pipe_string(); + update((const char*) &n, sizeof(n), m_pPipeStream); + return (*this); +} + +pipe_manager& pipe_manager::operator<<(unsigned char n) +{ + if (m_pPipeStream == NULL) + m_pPipeStream = NEW pipe_string(); + update((const char*) &n, sizeof(n), m_pPipeStream); + return (*this); +} + +char* pipe_manager::c_str() const +{ + if (m_pPipeStream) + return (m_pPipeStream->c_str()); + else + { + static const char* dummy = ""; + return ((char*) dummy); + } +} + +size_t pipe_manager::length() const +{ + if (m_pPipeStream) + return (m_pPipeStream->length()); + else + return (0); +} + +void pipe_manager::clear() +{ + if (m_pPipeStream) + m_pPipeStream->clear(); +} + +} // namespace acl diff --git a/lib_acl_cpp/src/stdlib/snprintf.cpp b/lib_acl_cpp/src/stdlib/snprintf.cpp new file mode 100644 index 000000000..9bf6372e6 --- /dev/null +++ b/lib_acl_cpp/src/stdlib/snprintf.cpp @@ -0,0 +1,57 @@ +#include "acl_stdafx.hpp" +#ifdef WIN32 +#include + +namespace acl +{ + +#ifdef __STDC_WANT_SECURE_LIB__ + +int snprintf(char *buf, size_t size, const char *fmt, ...) +{ + va_list ap; + int ret; + + va_start(ap, fmt); + ret = _vsnprintf_s(buf, size, size, fmt, ap); + va_end(ap); + return (ret); +} + +int vsnprintf(char *buf, size_t size, const char *fmt, va_list ap) +{ + int ret; + + ret = _vsnprintf_s(buf, size, size, fmt, ap); + return (ret); +} + +#else + +int snprintf(char *buf, size_t size, const char *fmt, ...) +{ + va_list ap; + int ret; + + va_start(ap, fmt); + ret = vsnprintf(buf, size, fmt, ap); + va_end(ap); + return ret; +} + +int vsnprintf(char *buf, size_t size, const char *fmt, va_list ap) +{ + int ret = _vsnprintf(buf, size, fmt, ap); + if (ret <= (int) size) + { + buf[size - 1] = 0; + ret = (int) size - 1; + } + return ret; +} + +#endif // __STDC_WANT_SECURE_LIB__ + +} + +#endif // WIN32 diff --git a/lib_acl_cpp/src/stdlib/string.cpp b/lib_acl_cpp/src/stdlib/string.cpp new file mode 100644 index 000000000..8c9daf12c --- /dev/null +++ b/lib_acl_cpp/src/stdlib/string.cpp @@ -0,0 +1,1138 @@ +#include "acl_stdafx.hpp" +#include +#include +#include "acl_cpp/stdlib/string.hpp" + +#define ALLOC(n) acl_vstring_alloc((n)) +#define FREE(x) acl_vstring_free((x)) +#define STR(x) acl_vstring_str((x)) +#define LEN(x) ACL_VSTRING_LEN((x)) +#define ADDCH(x, ch) ACL_VSTRING_ADDCH((x), (ch)) +#define MCP(x, from, n) acl_vstring_memcpy((x), (from), (n)) +#define MCAT(x, from, n) acl_vstring_memcat((x), (from), (n)) +#define SCP(x, from) acl_vstring_strcpy((x), (from)) +#define SCAT(x, from) acl_vstring_strcat((x), (from)) +#define RSET(x) ACL_VSTRING_RESET((x)) +#define TERM(x) ACL_VSTRING_TERMINATE((x)) +#define AT(x, n) acl_vstring_charat((x), (n)) + +namespace acl { + +void string::init(size_t len) +{ + if (len < 1) + len = 1; + m_pVbf = ALLOC(len); + m_psList = NULL; + m_psList2 = NULL; + m_psPair = NULL; + m_ptr = NULL; +} + +string::string(size_t len /* = 64 */, bool bin /* = false */) +: m_bin(bin) +{ + init(len); +} + +string::string(const string& s) : m_bin(false) +{ + init(s.length() + 1); + MCP(m_pVbf, STR(s.m_pVbf), LEN(s.m_pVbf)); + TERM(m_pVbf); +} + +string::string(const char* s) : m_bin(false) +{ + size_t len = strlen(s); + init(len + 1); + MCP(m_pVbf, s, len); + TERM(m_pVbf); +} + +string::string(const void* s, size_t n) : m_bin(false) +{ + init(n + 1); + if (n > 0) + MCP(m_pVbf, (const char*) s, n); + TERM(m_pVbf); +} + +string::~string() +{ + FREE(m_pVbf); + if (m_psList) + delete m_psList; + if (m_psList2) + delete m_psList2; + if (m_psPair) + delete m_psPair; +} + +void string::set_bin(bool bin) +{ + m_bin = bin; +} + +bool string::get_bin() const +{ + return (m_bin); +} + +char string::operator [](size_t n) +{ + acl_assert(n < LEN(m_pVbf)); + return (AT(m_pVbf, n)); +} + +char string::operator [](int n) +{ + acl_assert(n < (int) LEN(m_pVbf) && n >= 0); + return (AT(m_pVbf, n)); +} + +string& string::operator =(const char* s) +{ + SCP(m_pVbf, s); + return (*this); +} + +string& string::operator =(const string& s) +{ + MCP(m_pVbf, STR(s.m_pVbf), LEN(s.m_pVbf)); + TERM(m_pVbf); + return (*this); +} + +string& string::operator =(const string* s) +{ + MCP(m_pVbf, STR(s->m_pVbf), LEN(s->m_pVbf)); + TERM(m_pVbf); + return (*this); +} + +string& string::operator =(acl_int64 n) +{ + if (m_bin) + { + copy(&n, sizeof(n)); + return (*this); + } + else + return (format("%lld", n)); +} + +string& string::operator =(acl_uint64 n) +{ + if (m_bin) + { + copy(&n, sizeof(n)); + return (*this); + } + else + return (format("%llu", n)); +} + +string& string::operator =(long n) +{ + if (m_bin) + { + copy(&n, sizeof(n)); + return (*this); + } + else + return (format("ld", n)); +} + +string& string::operator =(unsigned long n) +{ + if (m_bin) + { + copy(&n, sizeof(n)); + return (*this); + } + else + return (format("%lu", n)); +} + +string& string::operator =(int n) +{ + if (m_bin) + { + copy(&n, sizeof(n)); + return (*this); + } + else + return (format("%d", n)); +} + +string& string::operator =(unsigned int n) +{ + if (m_bin) + { + copy(&n, sizeof(n)); + return (*this); + } + else + return (format("%u", n)); +} + +string& string::operator =(short n) +{ + if (m_bin) + { + copy(&n, sizeof(n)); + return (*this); + } + else + return (format("%d", n)); +} + +string& string::operator =(unsigned short n) +{ + if (m_bin) + { + copy(&n, sizeof(n)); + return (*this); + } + else + return (format("%d", n)); +} + +string& string::operator =(char n) +{ + if (m_bin) + { + copy(&n, sizeof(n)); + return (*this); + } + else + return (format("%c", n)); +} + +string& string::operator =(unsigned char n) +{ + if (m_bin) + { + copy(&n, sizeof(n)); + return (*this); + } + else + return (format("%c", n)); +} + +string& string::operator +=(const char* s) +{ + SCAT(m_pVbf, s); + return (*this); +} + +string& string::operator +=(const string& s) +{ + MCAT(m_pVbf, STR(s.m_pVbf), LEN(s.m_pVbf)); + TERM(m_pVbf); + return (*this); +} + +string& string::operator +=(const string* s) +{ + MCAT(m_pVbf, STR(s->m_pVbf), LEN(s->m_pVbf)); + TERM(m_pVbf); + return (*this); +} + +string& string::operator +=(acl_int64 n) +{ + if (m_bin) + { + append(&n, sizeof(n)); + return (*this); + } + else + return (format_append("%lld", n)); +} + +string& string::operator +=(acl_uint64 n) +{ + if (m_bin) + { + append(&n, sizeof(n)); + return (*this); + } + else + return (format_append("%llu", n)); +} + +string& string::operator +=(long n) +{ + if (m_bin) + { + append(&n, sizeof(n)); + return (*this); + } + else + return (format_append("%l", n)); +} + +string& string::operator +=(unsigned long n) +{ + if (m_bin) + { + append(&n, sizeof(n)); + return (*this); + } + else + return (format_append("%lu", n)); +} + +string& string::operator +=(int n) +{ + if (m_bin) + { + append(&n, sizeof(n)); + return (*this); + } + else + return (format_append("%d", n)); +} + +string& string::operator +=(unsigned int n) +{ + if (m_bin) + { + append(&n, sizeof(n)); + return (*this); + } + else + return (format_append("%u", n)); +} + +string& string::operator +=(short n) +{ + if (m_bin) + { + append(&n, sizeof(n)); + return (*this); + } + else + return (format_append("%d", n)); +} + +string& string::operator +=(unsigned short n) +{ + if (m_bin) + { + append(&n, sizeof(n)); + return (*this); + } + else + return (format_append("%u", n)); +} + +string& string::operator +=(unsigned char n) +{ + if (m_bin) + { + append(&n, sizeof(n)); + return (*this); + } + else + return (format_append("%c", n)); +} + +string& string::operator +=(char ch) +{ + *this += (unsigned char) ch; + return (*this); +} + +string& string::operator <<(const string& s) +{ + *this += s; + return (*this); +} + +string& string::operator <<(const string* s) +{ + *this += s; + return (*this); +} + +string& string::operator <<(const char* s) +{ + *this += s; + return (*this); +} + +string& string::operator <<(acl_int64 n) +{ + *this += n; + return (*this); +} + +string& string::operator <<(acl_uint64 n) +{ + *this += n; + return (*this); +} + +string& string::operator <<(int n) +{ + *this += n; + return (*this); +} + +string& string::operator <<(unsigned int n) +{ + *this += n; + return (*this); +} + +string& string::operator <<(long n) +{ + *this += n; + return (*this); +} + +string& string::operator <<(unsigned long n) +{ + *this += n; + return (*this); +} + +string& string::operator <<(short n) +{ + *this += n; + return (*this); +} + +string& string::operator <<(unsigned short n) +{ + *this += n; + return (*this); +} + +string& string::operator <<(char n) +{ + *this += n; + return (*this); +} + +string& string::operator <<(unsigned char n) +{ + *this += n; + return (*this); +} + +string& string::operator >>(string* s) +{ + *s = this; + clear(); + return (*this); +} + +string& string::push_back(char ch) +{ + return (append(&ch, sizeof(ch))); +} + +char* string::buf_end() +{ + if (m_ptr == NULL) + m_ptr = STR(m_pVbf); + char *pEnd = acl_vstring_end(m_pVbf); + if (m_ptr >= pEnd) { + if (!empty()) + clear(); + return (NULL); + } + return (pEnd); +} + +string& string::scan_buf(void* pbuf, size_t n) +{ + if (pbuf == NULL || n == 0) + return (*this); + + const char *pEnd = buf_end(); + if (pEnd == NULL) + return (*this); + + size_t len = pEnd - m_ptr; + if (len > n) + len = n; + memcpy(pbuf, m_ptr, len); + m_ptr += len; + return (*this); +} + +string& string::operator >>(acl_int64& n) +{ + return (scan_buf(&n, sizeof(n))); +} + +string& string::operator >>(acl_uint64& n) +{ + return (scan_buf(&n, sizeof(n))); +} + +string& string::operator >>(int& n) +{ + return (scan_buf(&n, sizeof(n))); +} + +string& string::operator >>(unsigned int& n) +{ + return (scan_buf(&n, sizeof(n))); +} + +string& string::operator >>(short& n) +{ + return (scan_buf(&n, sizeof(n))); +} + +string& string::operator >>(unsigned short& n) +{ + return (scan_buf(&n, sizeof(n))); +} + +string& string::operator >>(char& n) +{ + return (scan_buf(&n, sizeof(n))); +} + +string& string::operator >>(unsigned char& n) +{ + return (scan_buf(&n, sizeof(n))); +} + +bool string::operator ==(const string& s) const +{ + return (compare(s) == 0 ? true : false); +} + +bool string::operator==(const string* s) const +{ + return (compare(s) == 0 ? true : false); +} + +bool string::operator ==(const char* s) const +{ + return (compare(s) == 0 ? true : false); +} + +bool string::operator !=(const string& s) const +{ + return (compare(s) != 0 ? true : false); +} + +bool string::operator !=(const string* s) const +{ + return (compare(s) != 0 ? true : false); +} + +bool string::operator !=(const char* s) const +{ + return (compare(s) != 0 ? true : false); +} + +bool string::operator <(const string& s) const +{ + size_t nLeft = LEN(m_pVbf); + size_t nRight = LEN(s.m_pVbf); + size_t n = nLeft > nRight ? nLeft : nRight; + int ret = memcmp(STR(m_pVbf), STR(s.m_pVbf), n); + if (ret < 0) + return (true); + else if (ret > 0) + return (false); + if (nLeft < nRight) + return (true); + return (false); +} + +bool string::operator >(const string& s) const +{ + size_t nLeft = LEN(m_pVbf); + size_t nRight = LEN(s.m_pVbf); + size_t n = nLeft > nRight ? nLeft : nRight; + int ret = memcmp(STR(m_pVbf), STR(s.m_pVbf), n); + if (ret > 0) + return (true); + else if (ret < 0) + return (false); + if (nLeft > nRight) + return (true); + return (false); +} + +string::operator const char *() const +{ + return (STR(m_pVbf)); +} + +string::operator const void *() const +{ + return ((void*) STR(m_pVbf)); +} + +int string::compare(const string& s) const +{ + size_t n = LEN(m_pVbf) > LEN(s.m_pVbf) ? LEN(s.m_pVbf) : LEN(m_pVbf); + int ret; + + ret = memcmp(STR(m_pVbf), STR(s.m_pVbf), n); + if (ret != 0) + return (ret); + return ((int) (LEN(m_pVbf) - LEN(s.m_pVbf))); +} + +int string::compare(const string* s) const +{ + size_t n = LEN(m_pVbf) > LEN(s->m_pVbf) ? LEN(s->m_pVbf) : LEN(m_pVbf); + int ret; + + ret = memcmp(STR(m_pVbf), STR(s->m_pVbf), n); + if (ret != 0) + return (ret); + return ((int) (LEN(m_pVbf) - LEN(s->m_pVbf))); +} + +int string::compare(const char* s, bool case_sensitive) const +{ + if (case_sensitive) + return (compare((const void*) s, (size_t) strlen(s))); + else + return (acl_strcasecmp(STR(m_pVbf), s)); +} + +int string::compare(const void* ptr, size_t len) const +{ + size_t n = LEN(m_pVbf) > len ? len : LEN(m_pVbf); + int ret; + + ret = memcmp(STR(m_pVbf), ptr, n); + if (ret != 0) + return (ret); + return ((int) (LEN(m_pVbf) - len)); +} + +int string::ncompare(const char* s, size_t len, bool case_sensitive/* =true */) const +{ + if (case_sensitive) + return (strncmp(STR(m_pVbf), s, len)); + else + return (acl_strncasecmp(STR(m_pVbf), s, len)); +} + +int string::rncompare(const char* s, size_t len, bool case_sensitive/* =true */) const +{ + if (case_sensitive) + return (acl_strrncmp(STR(m_pVbf), s, len)); + else + return (acl_strrncasecmp(STR(m_pVbf), s, len)); +} + +char* string::c_str() const +{ + return (STR(m_pVbf)); +} + +void* string::buf() const +{ + return (STR(m_pVbf)); +} + +size_t string::length() const +{ + return (LEN(m_pVbf)); +} + +size_t string::size() const +{ + return (LEN(m_pVbf)); +} + +size_t string::capacity() const +{ + return (ACL_VSTRING_SIZE(m_pVbf)); +} + +string& string::set_offset(size_t n) +{ + RSET(m_pVbf); + ACL_VSTRING_SPACE(m_pVbf, (int) n); + ACL_VSTRING_AT_OFFSET(m_pVbf, (int) n); + TERM(m_pVbf); + return (*this); +} + +string& string::space(size_t n) +{ + ACL_VSTRING_SPACE(m_pVbf, (int) n); + return (*this); +} + +bool string::empty() const +{ + return (LEN(m_pVbf) > 0 ? false : true); +} + +ACL_VSTRING* string::vstring() const +{ + return (m_pVbf); +} + +int string::find(char ch) const +{ + char *ptr = acl_vstring_memchr(m_pVbf, ch); + if (ptr == NULL) + return (-1); + return ((int)(ptr - STR(m_pVbf))); +} + +const char* string::find(const char* needle, bool case_sensitive) const +{ + if (case_sensitive) + return (acl_vstring_strstr(m_pVbf, needle)); + else + return (acl_vstring_strcasestr(m_pVbf, needle)); +} + +const char* string::rfind(const char* needle, bool case_sensitive) const +{ + if (case_sensitive) + return (acl_vstring_rstrstr(m_pVbf, needle)); + else + return (acl_vstring_rstrcasestr(m_pVbf, needle)); +} + +const string string::left(size_t npos) +{ + if (npos >= LEN(m_pVbf)) + return (*this); + return (string(STR(m_pVbf), npos)); +} + +const string string::right(size_t npos) +{ + npos++; + if (npos >= LEN(m_pVbf)) + return string(1); + size_t nLeft = LEN(m_pVbf) - npos; + return (string(STR(m_pVbf) + npos, nLeft)); +} + +const std::list& string::split(const char* sep) +{ + ACL_ARGV *argv = acl_argv_split(STR(m_pVbf), sep); + ACL_ITER it; + + if (m_psList == NULL) + m_psList = NEW std::list; + else + m_psList->clear(); + acl_foreach(it, argv) + { + char* ptr = (char*) it.data; + m_psList->push_back(ptr); + } + acl_argv_free(argv); + return (*m_psList); +} + +const std::vector& string::split2(const char* sep) +{ + ACL_ARGV *argv = acl_argv_split(STR(m_pVbf), sep); + ACL_ITER it; + + if (m_psList2 == NULL) + m_psList2 = NEW std::vector; + else + m_psList2->clear(); + acl_foreach(it, argv) + { + char* ptr = (char*) it.data; + m_psList2->push_back(ptr); + } + acl_argv_free(argv); + return (*m_psList2); +} + +const std::pair& string::split_nameval() +{ + char *name, *value; + + if (m_psPair == NULL) + m_psPair = NEW std::pair; + + if (acl_split_nameval(STR(m_pVbf), &name, &value) != NULL) { + m_psPair->first = ""; + m_psPair->second = ""; + return (*m_psPair); + } + m_psPair->first = name; + m_psPair->second = value; + return (*m_psPair); +} + +string& string::copy(const char* ptr) +{ + SCP(m_pVbf, ptr); + return (*this); +} + +string& string::copy(const void* ptr, size_t len) +{ + MCP(m_pVbf, (const char*) ptr, len); + TERM(m_pVbf); + return (*this); +} + +string& string::memmove(const char* ptr) +{ + return (memmove(ptr, strlen(ptr))); +} + +string& string::memmove(const char* ptr, size_t len) +{ + acl_vstring_memmove(m_pVbf, ptr, len); + return (*this); +} + +string& string::append(const string& s) +{ + return (append(s.c_str(), s.length())); +} + +string& string::append(const string* s) +{ + return (append(s->c_str(), s->length())); +} + +string& string::append(const char* ptr) +{ + SCAT(m_pVbf, ptr); + return (*this); +} + +string& string::append(const void* ptr, size_t len) +{ + MCAT(m_pVbf, (const char*) ptr, len); + TERM(m_pVbf); + return (*this); +} + +string& string::prepend(const char* s) +{ + acl_vstring_prepend(m_pVbf, s, strlen(s)); + return (*this); +} + +string& string::prepend(const void* ptr, size_t len) +{ + acl_vstring_prepend(m_pVbf, (const char*) ptr, len); + return (*this); +} + + +string& string::insert(size_t start, const void* ptr, size_t len) +{ + acl_vstring_insert(m_pVbf, start, (const char*) ptr, len); + return (*this); +} + +string& string::format(const char* fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vformat(fmt, ap); + va_end(ap); + return (*this); +} + +string& string::vformat(const char* fmt, va_list ap) +{ + acl_vstring_vsprintf(m_pVbf, fmt, ap); + return (*this); +} + +string& string::format_append(const char* fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vformat_append(fmt, ap); + va_end(ap); + return (*this); +} + +string& string::vformat_append(const char* fmt, va_list ap) +{ + acl_vstring_vsprintf_append(m_pVbf, fmt, ap); + return (*this); +} + +string& string::replace(char from, char to) +{ + char* ptr = STR(m_pVbf); + size_t i, n = LEN(m_pVbf); + + for (i = 0; i < n; i++) { + if (*ptr == from) + *ptr = to; + ptr++; + } + + return (*this); +} + +string& string::truncate(size_t n) +{ + acl_vstring_truncate(m_pVbf, n); + return (*this); +} + +string& string::strip(const char* needle, bool each /* false */) +{ + char* src = STR(m_pVbf); + char* ptr; + ACL_VSTRING* pVbf = NULL; + + if (each) + { + const char* last; + + while (true) + { + last = src; + if ((ptr = acl_mystrtok(&src, needle)) == NULL) + { + if (*last == 0) + break; + if (pVbf != NULL) + SCAT(pVbf, last); + break; + } + // 写时分配 + if (pVbf == NULL) + pVbf = acl_vstring_alloc(LEN(m_pVbf)); + SCAT(pVbf, ptr); + } + + if (pVbf != NULL) + { + FREE(m_pVbf); + m_pVbf = pVbf; + } + return (*this); + } + + size_t len = strlen(needle), n; + + while (true) + { + ptr = strstr(src, needle); + if (ptr == NULL) + { + if (pVbf != NULL) + SCAT(pVbf, src); + break; + } + + // 采用写时延迟分配策略 + if (pVbf == NULL) + pVbf = acl_vstring_alloc(LEN(m_pVbf)); + n = ptr - src; + MCP(pVbf, src, n); + TERM(pVbf); + src += n + len; + } + + if (pVbf != NULL) + { + FREE(m_pVbf); + m_pVbf = pVbf; + } + return (*this); +} + +string& string::clear(void) +{ + RSET(m_pVbf); + TERM(m_pVbf); + m_ptr = NULL; + return (*this); +} + +string& string::lower() +{ + acl_lowercase(STR(m_pVbf)); + return (*this); +} + +string& string::upper() +{ + acl_uppercase(STR(m_pVbf)); + return (*this); +} + +string& string::base64_encode(void) +{ + size_t dlen = length(); + if (dlen == 0) + return (*this); + size_t n = (dlen * 4) / 3; + ACL_VSTRING *s = ALLOC(n) ; + acl_vstring_base64_encode(s, c_str(), (int) dlen); + FREE(m_pVbf); + m_pVbf = s; + return (*this); +} + +string& string::base64_encode(const void* ptr, size_t len) +{ + acl_vstring_base64_encode(m_pVbf, + (const char*) ptr, (int) len); + return (*this); +} + +string& string::base64_decode(void) +{ + size_t dlen = length(); + if (dlen == 0) + return (*this); + size_t n = (dlen * 3) / 4; + ACL_VSTRING *s = ALLOC(n) ; + if (acl_vstring_base64_decode(s, c_str(), (int) dlen) == NULL) + RSET(s); + FREE(m_pVbf); + m_pVbf = s; + return (*this); +} + +string& string::base64_decode(const char* s) +{ + if (acl_vstring_base64_decode(m_pVbf, + s, (int) strlen(s)) == NULL) + { + RSET(m_pVbf); + } + return (*this); +} + +string& string::base64_decode(const void* ptr, size_t len) +{ + if (acl_vstring_base64_decode(m_pVbf, + (const char*) ptr, (int) len) == NULL) + { + RSET(m_pVbf); + } + return (*this); +} + +string& string::url_encode(const char* s) +{ + char *ptr = acl_url_encode(s); + (*this) = ptr; + acl_myfree(ptr); + return (*this); +} + +string& string::url_decode(const char* s) +{ + char *ptr = acl_url_decode(s); + + (*this) = ptr; + acl_myfree(ptr); + return (*this); +} + +string& string::hex_encode(const void* s, size_t len) +{ + (void) acl_hex_encode(m_pVbf, (const char*) s, (int) len); + return (*this); +} + +string& string::hex_decode(const char* s, size_t len) +{ + (void) acl_hex_decode(m_pVbf, s, (int) len); + return (*this); +} + +static void dummy_free(void*) +{ +} + +static void buf_free(void* arg) +{ + string* s = (string*) arg; + delete s; +} + +static string* __main_buf = NULL; + +static void main_buf_free(void) +{ + if (__main_buf) + delete __main_buf; +} + +static acl_pthread_key_t __buf_key; + +static void prepare_once(void) +{ + if ((unsigned long) acl_pthread_self() == acl_main_thread_self()) + { + acl_pthread_key_create(&__buf_key, dummy_free); + atexit(main_buf_free); + } else + acl_pthread_key_create(&__buf_key, buf_free); +} + +static acl_pthread_once_t __buf_once = ACL_PTHREAD_ONCE_INIT; + +static string& get_buf(void) +{ + acl_pthread_once(&__buf_once, prepare_once); + string* s = (string*) acl_pthread_getspecific(__buf_key); + if (s == NULL) + { + s = NEW string(21); + acl_pthread_setspecific(__buf_key, s); + if ((unsigned long) acl_pthread_self() == acl_main_thread_self()) + __main_buf = s; + } + return *s; +} + +const string& string::parse_int(int n) +{ + string& s = get_buf(); + s.format("%d", n); + return (s); +} + +const string& string::parse_int(unsigned int n) +{ + string& s = get_buf(); + s.format("%u", n); + return (s); +} + +const string& string::parse_int64(acl_int64 n) +{ + string& s = get_buf(); + s.format("%lld", n); + return (s); +} + +const string& string::parse_int64(acl_uint64 n) +{ + string& s = get_buf(); + s.format("%llu", n); + return (s); +} + +} // namespace acl diff --git a/lib_acl_cpp/src/stdlib/url_coder.cpp b/lib_acl_cpp/src/stdlib/url_coder.cpp new file mode 100644 index 000000000..53bd303c2 --- /dev/null +++ b/lib_acl_cpp/src/stdlib/url_coder.cpp @@ -0,0 +1,204 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/stdlib/string.hpp" +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/stdlib/url_coder.hpp" + +namespace acl +{ + +url_coder::url_coder(bool nocase /* = true */) +: nocase_(nocase) +{ + buf_ = NEW string(128); +} + +url_coder::url_coder(const url_coder& coder) +{ + buf_ = NEW string(coder.buf_->c_str()); + nocase_ = coder.nocase_; + + std::vector::const_iterator cit = coder.params_.begin(); + for (; cit != coder.params_.end(); ++cit) + set((*cit)->name, (*cit)->value); +} + +url_coder::~url_coder() +{ + reset(); + delete buf_; +} + +const url_coder& url_coder::operator =(const url_coder& coder) +{ + nocase_ = coder.nocase_; + *buf_ = coder.buf_->c_str(); + + std::vector::const_iterator cit = coder.params_.begin(); + for (; cit != coder.params_.end(); ++cit) + set((*cit)->name, (*cit)->value); + + return *this; +} + +void url_coder::free_param(URL_NV* param) +{ + acl_myfree(param->name); + acl_myfree(param->value); + acl_myfree(param); +} + +void url_coder::reset() +{ + std::vector::iterator it = params_.begin(); + for (; it != params_.end(); ++it) + free_param(*it); + params_.clear(); + buf_->clear(); +} + +void url_coder::encode(string& buf, bool clean /* = true */) const +{ + if (clean) + buf.clear(); + std::vector::const_iterator cit = params_.begin(); + char* name, *value; + for (; cit != params_.end(); ++cit) + { + if (cit != params_.begin()) + buf << '&'; + name = acl_url_encode((*cit)->name); + value = acl_url_encode((*cit)->value); + buf << name << '=' << value; + acl_myfree(name); + acl_myfree(value); + } +} + +const string& url_coder::to_string() const +{ + encode(*buf_); + return *buf_; +} + +void url_coder::decode(const char* str) +{ + ACL_ARGV* tokens = acl_argv_split(str, "&"); + ACL_ITER iter; + acl_foreach(iter, tokens) + { + char* name = (char*) iter.data; + char* value = strchr(name, '='); + if (value == NULL || *(value + 1) == 0) + continue; + *value++ = 0; + name = acl_url_decode(name); + value = acl_url_decode(value); + URL_NV* param = (URL_NV*) acl_mymalloc(sizeof(URL_NV)); + param->name = name; + param->value = value; + params_.push_back(param); + } + + acl_argv_free(tokens); +} + +url_coder& url_coder::set(const char* name, const char* value, + bool override /* = true */) +{ + if (name == NULL || *name == 0 || value == NULL || *value == 0) + { + logger_error("invalid input"); + return *this; + } + + if (override) + { + int (*cmp)(const char*, const char*) = nocase_ + ? strcasecmp : strcmp; + + std::vector::iterator it = params_.begin(); + for (; it != params_.end(); ++it) + { + if (cmp((*it)->name, name) == 0) + { + free_param(*it); + params_.erase(it); + break; + } + } + } + + URL_NV* param = (URL_NV*) acl_mymalloc(sizeof(URL_NV)); + param->name = acl_mystrdup(name); + param->value = acl_mystrdup(value); + params_.push_back(param); + return *this; +} + +url_coder& url_coder::set(const char* name, int value, bool override /* = true */) +{ + char buf[24]; + +#ifdef WIN32 +#define snprintf _snprintf +#endif + + snprintf(buf, sizeof(buf), "%d", value); + return set(name, buf, override); +} + +url_coder& url_coder::set(const char* name, bool override, const char* fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + set(name, fmt, ap, override); + va_end(ap); + return *this; +} + +url_coder& url_coder::set(const char* name, const char* fmt, va_list ap, + bool override /* = true */) +{ + string buf; + buf.vformat(fmt, ap); + return set(name, buf.c_str(), override); +} + +const char* url_coder::get(const char* name) const +{ + int (*cmp)(const char*, const char*) = nocase_ ? strcasecmp : strcmp; + std::vector::const_iterator cit = params_.begin(); + + for (; cit != params_.end(); ++cit) + { + if (cmp((*cit)->name, name) == 0) + return (*cit)->value; + } + + return NULL; +} + +const char* url_coder::operator [](const char* name) const +{ + return get(name); +} + +bool url_coder::del(const char* name) +{ + int (*cmp)(const char*, const char*) = nocase_ ? strcasecmp : strcmp; + std::vector::iterator it = params_.begin(); + + for (; it != params_.end(); ++it) + { + if (cmp((*it)->name, name) == 0) + { + free_param(*it); + params_.erase(it); + return true; + } + } + + return false; +} + +} // namespace acl end diff --git a/lib_acl_cpp/src/stdlib/util.cpp b/lib_acl_cpp/src/stdlib/util.cpp new file mode 100644 index 000000000..a36c5b694 --- /dev/null +++ b/lib_acl_cpp/src/stdlib/util.cpp @@ -0,0 +1,48 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/stdlib/util.hpp" + +namespace acl +{ + +int last_error(void) +{ + return acl_last_error(); +} + +void set_error(int errnum) +{ + acl_set_error(errnum); +} + +const char* last_serror(void) +{ + return acl_last_serror(); +} + +const char* last_serror(char* buf, size_t size) +{ + return acl_last_strerror(buf, (int) size); +} + +const char* string_error(int errnum, char* buf, size_t size) +{ + return acl_strerror((unsigned int) errnum, buf, (int) size); +} + +int strncasecmp_(const char *s1, const char *s2, size_t n) +{ + return ::strncasecmp(s1, s2, n); +} + +void assert_(bool n) +{ + if (n == false) + abort(); +} + +void meter_time(const char *filename, int line, const char *info) +{ + acl_meter_time(filename, line, info); +} + +} // namespace acl diff --git a/lib_acl_cpp/src/stdlib/xml.cpp b/lib_acl_cpp/src/stdlib/xml.cpp new file mode 100644 index 000000000..28468cddc --- /dev/null +++ b/lib_acl_cpp/src/stdlib/xml.cpp @@ -0,0 +1,642 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/stdlib/string.hpp" +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/stdlib/xml.hpp" + +namespace acl { + +xml_attr::xml_attr(void) +{ +} + +xml_attr::~xml_attr(void) +{ +} + +const char* xml_attr::get_name(void) const +{ + acl_assert(attr_); + if (attr_->name) + return acl_vstring_str(attr_->name); + else + return ""; +} + +const char* xml_attr::get_value(void) const +{ + acl_assert(attr_); + if (attr_->value) + return acl_vstring_str(attr_->value); + else + return ""; +} + +////////////////////////////////////////////////////////////////////////// + +xml_node::xml_node(ACL_XML_NODE* node, xml* xml_ptr) + : node_(node) + , xml_(xml_ptr) + , parent_(NULL) + , parent_saved_(NULL) + , child_(NULL) + , child_iter_(NULL) + , attr_(NULL) + , attr_iter_(NULL) +{ + acl_assert(xml_ptr); +} + +xml_node::~xml_node(void) +{ + if (parent_saved_) + delete parent_saved_; + if (child_) + delete child_; + if (child_iter_) + acl_myfree(child_iter_); + if (attr_) + delete attr_; + if (attr_iter_) + acl_myfree(attr_iter_); +} + +const char* xml_node::tag_name(void) const +{ + if (node_->ltag && ACL_VSTRING_LEN(node_->ltag) > 0) + return (acl_vstring_str(node_->ltag)); + else + return (NULL); +} + +const char* xml_node::text(void) const +{ + if (node_->text && ACL_VSTRING_LEN(node_->text) > 0) + return acl_vstring_str(node_->text); + else + return NULL; +} + +const char* xml_node::id(void) const +{ + if (node_->id && ACL_VSTRING_LEN(node_->id) > 0) + return acl_vstring_str(node_->id); + else + return NULL; +} + +const char* xml_node::attr_value(const char* name) const +{ + return acl_xml_getElementAttrVal(node_, name); +} + +const char* xml_node::operator[](const char* name) const +{ + return attr_value(name); +} + +const xml_attr* xml_node::first_attr(void) const +{ + ACL_ARRAY* a = node_->attr_list; + if (a == NULL) + return NULL; + + if (attr_iter_ == NULL) + const_cast(this)->attr_iter_ = + (ACL_ITER*) acl_mymalloc(sizeof(ACL_ITER)); + + ACL_XML_ATTR* attr = (ACL_XML_ATTR*) a->iter_head(attr_iter_, a); + if (attr == NULL) + return NULL; + if (attr_ == NULL) + const_cast(this)->attr_ = NEW xml_attr(); + const_cast(this)->attr_->node_ = const_cast(this); + const_cast(this)->attr_->attr_ = attr; + return attr_; +} + +const xml_attr* xml_node::next_attr(void) const +{ + ACL_ARRAY* a = node_->attr_list; + if (a == NULL) + return NULL; + + acl_assert(attr_iter_); + acl_assert(attr_); + + ACL_XML_ATTR* attr = (ACL_XML_ATTR*) a->iter_next(attr_iter_, a); + if (attr == NULL) + return NULL; + const_cast(this)->attr_->node_ = const_cast(this); + const_cast(this)->attr_->attr_ = attr; + return attr_; +} + +xml_node& xml_node::add_attr(const char* name, const char* value) +{ + acl_xml_node_add_attr(node_, name, value); + return *this; +} + +xml_node& xml_node::add_attr(const char* name, char n) +{ + char buf[2]; + snprintf(buf, sizeof(buf), "%c", n); + return add_attr(name, buf); +} + +xml_node& xml_node::add_attr(const char* name, int n) +{ + char buf[32]; + snprintf(buf, sizeof(buf), "%d", n); + return add_attr(name, buf); +} + +xml_node& xml_node::add_attr(const char* name, size_t n) +{ + char buf[32]; + + snprintf(buf, sizeof(buf), "%lu", (unsigned long) n); + return add_attr(name, buf); +} + +xml_node& xml_node::add_attr(const char* name, acl_int64 n) +{ + char buf[32]; +#ifdef WIN32 + snprintf(buf, sizeof(buf), "%I64d", n); +#else + snprintf(buf, sizeof(buf), "%lld", n); +#endif + return add_attr(name, buf); +} + +xml_node& xml_node::set_text(const char* str) +{ + acl_xml_node_set_text(node_, str); + return *this; +} + +xml_node& xml_node::add_child(xml_node* child, + bool return_child /* = false */) +{ + ACL_XML_NODE* node = child->get_xml_node(); + acl_xml_node_add_child(node_, node); + child->parent_ = this; + if (return_child) + return *child; + return *this; +} + +xml_node& xml_node::add_child(xml_node& child, + bool return_child /* = false */) +{ + return add_child(&child, return_child); +} + +xml_node& xml_node::add_child(const char* tag, + bool return_child /* = false */, + const char* str /* = NULL */) +{ + return add_child(xml_->create_node(tag, str), return_child); +} + +xml_node& xml_node::get_parent() const +{ + if (parent_) + return *parent_; + else if (node_->parent == node_->xml->root) + return xml_->get_root(); + else if (node_->parent == NULL) // xxx: can this happen? + return xml_->get_root(); + + const_cast(this)->parent_saved_ = + NEW xml_node(node_->parent, xml_); + const_cast(this)->parent_ = parent_saved_; + return *parent_saved_; +} + +xml_node* xml_node::first_child(void) +{ + if (child_iter_ == NULL) + child_iter_ = (ACL_ITER*) acl_mymalloc(sizeof(ACL_ITER)); + + ACL_XML_NODE* node = node_->iter_head(child_iter_, node_); + if (node == NULL) + return NULL; + + if (child_ == NULL) + child_ = NEW xml_node(node, xml_); + else + child_->node_ = node; + return child_; +} + +xml_node* xml_node::next_child(void) +{ + acl_assert(child_iter_); + acl_assert(child_); + + ACL_XML_NODE* node = node_->iter_next(child_iter_, node_); + if (node == NULL) + return NULL; + child_->node_ = node; + return child_; +} + +int xml_node::depth(void) const +{ + return node_->depth; +} + +int xml_node::children_count(void) const +{ + return acl_ring_size(&node_->children); +} + +xml& xml_node::get_xml() const +{ + return *xml_; +} + +ACL_XML_NODE* xml_node::get_xml_node() const +{ + return node_; +} + +void xml_node::set_xml_node(ACL_XML_NODE* node) +{ + node_ = node; +} + +////////////////////////////////////////////////////////////////////// + +xml::xml(const char* data /* = NULL */) +{ + node_ = NULL; + root_ = NULL; + xml_ = acl_xml_alloc(); + buf_ = NULL; + //dummyRootAdded_ = false; + m_pTokenTree = NULL; + iter_ = NULL; + if (data && *data) + update(data); +} + +xml::~xml(void) +{ + clear(); + if (node_) + delete node_; + if (root_) + delete root_; + if (xml_) + acl_xml_free(xml_); + if (buf_) + delete buf_; + if (m_pTokenTree) + acl_token_tree_destroy(m_pTokenTree); + if (iter_) + acl_myfree(iter_); +} + +xml& xml::part_word(bool on) +{ + if (on) + xml_->flag |= ACL_XML_FLAG_PART_WORD; + else + xml_->flag &= ~ACL_XML_FLAG_PART_WORD; + return *this; +} + +xml& xml::ignore_slash(bool on) +{ + if (on) + xml_->flag |= ACL_XML_FLAG_IGNORE_SLASH; + else + xml_->flag &= ~ACL_XML_FLAG_IGNORE_SLASH; + return *this; +} + +void xml::update(const char* data) +{ + acl_xml_update(xml_, data); +} + +const std::vector& xml::getElementsByTagName(const char* tag) const +{ + const_cast(this)->clear(); + + ACL_ARRAY* a = acl_xml_getElementsByTagName(xml_, tag); + if (a != NULL) { + ACL_ITER iter; + acl_foreach(iter, a) + { + ACL_XML_NODE *tmp = (ACL_XML_NODE*) iter.data; + xml_node* node = NEW xml_node(tmp, const_cast(this)); + const_cast(this)->elements_.push_back(node); + } + acl_xml_free_array(a); + } + return elements_; +} + +const xml_node* xml::getFirstElementByTag(const char* tag) const +{ + ACL_ARRAY* a = acl_xml_getElementsByTagName(xml_, tag); + if (a == NULL) + return NULL; + + ACL_XML_NODE* node = (ACL_XML_NODE*) acl_array_index(a, 0); + acl_assert(node); + if (node_ == NULL) + const_cast(this)->node_ = + NEW xml_node(node, const_cast(this)); + else + const_cast(this)->node_->set_xml_node(node); + acl_xml_free_array(a); + return node_; +} + +const std::vector& xml::getElementsByTags(const char* tags) const +{ + const_cast(this)->clear(); + ACL_ARRAY* a = acl_xml_getElementsByTags(xml_, tags); + if (a != NULL) { + ACL_ITER iter; + acl_foreach(iter, a) + { + ACL_XML_NODE *tmp = (ACL_XML_NODE*) iter.data; + xml_node* node = NEW xml_node(tmp, const_cast(this)); + const_cast(this)->elements_.push_back(node); + } + acl_xml_free_array(a); + } + return elements_; +} + +const xml_node* xml::getFirstElementByTags(const char* tags) const +{ + ACL_ARRAY* a = acl_xml_getElementsByTags(xml_, tags); + if (a == NULL) + return NULL; + + ACL_XML_NODE* node = (ACL_XML_NODE*) acl_array_index(a, 0); + acl_assert(node); + if (node_ == NULL) + const_cast(this)->node_ = + NEW xml_node(node, const_cast(this)); + else + const_cast(this)->node_->set_xml_node(node); + acl_xml_free_array(a); + return node_; +} + +const std::vector& xml::getElementsByName(const char* value) const +{ + const_cast(this)->clear(); + ACL_ARRAY* a = acl_xml_getElementsByName(xml_, value); + if (a != NULL) { + ACL_ITER iter; + acl_foreach(iter, a) + { + ACL_XML_NODE *tmp = (ACL_XML_NODE*) iter.data; + xml_node* node = NEW xml_node(tmp, const_cast(this)); + const_cast(this)->elements_.push_back(node); + } + acl_xml_free_array(a); + } + return elements_; +} + +const std::vector& xml::getElementsByAttr( + const char *name, const char *value) const +{ + const_cast(this)->clear(); + ACL_ARRAY *a = acl_xml_getElementsByAttr(xml_, name, value); + if (a != NULL) { + ACL_ITER iter; + acl_foreach(iter, a) + { + ACL_XML_NODE *tmp = (ACL_XML_NODE*) iter.data; + xml_node* node = NEW xml_node(tmp, const_cast(this)); + const_cast(this)->elements_.push_back(node); + } + acl_xml_free_array(a); + } + return elements_; +} + +const xml_node* xml::getElementById(const char* id) const +{ + ACL_XML_NODE* node = acl_xml_getElementById(xml_, id); + if (node == NULL) + return (NULL); + + if (node_ == NULL) + const_cast(this)->node_ = + NEW xml_node(node, const_cast(this)); + else + const_cast(this)->node_->set_xml_node(node); + return node_; +} + +ACL_XML* xml::get_xml(void) const +{ + return xml_; +} + +const acl::string& xml::getText() +{ +#define STR(x) acl_vstring_str((x)) +#define EQ(x, y) !strcasecmp((x), (y)) + + if (m_pTokenTree == NULL) + { + static const char* s = "  < > & "" + " &NBSP; < > & ""; + m_pTokenTree = acl_token_tree_create2(s, " "); + } + + string* pBuf = NEW string(1024); + ACL_ITER iter; + acl_foreach(iter, xml_) + { + ACL_XML_NODE *node = (ACL_XML_NODE*) iter.data; + + if ((node->flag & ACL_XML_F_META)) + continue; + if (EQ(STR(node->ltag), "style") + || EQ(STR(node->ltag), "meta") + || EQ(STR(node->ltag), "head") + || EQ(STR(node->ltag), "title") + || EQ(STR(node->ltag), "script")) + { + continue; + } + + pBuf->append(STR(node->text)); + } + + if (buf_ == NULL) + buf_ = NEW string(pBuf->length()); + else + buf_->clear(); + + const ACL_TOKEN *token; + const char* ptr = pBuf->c_str(), *pLast; + ACL_VSTRING* name = acl_vstring_alloc(8); + while (*ptr) + { + pLast = ptr; + ACL_TOKEN_TREE_MATCH(m_pTokenTree, ptr, NULL, NULL, token); + if (token == NULL) + { + buf_->append(pLast, ptr - pLast); + continue; + } + + acl_token_name(token, name); + + if (EQ(STR(name), " ")) + { + if (ptr - pLast - 6 > 0) + buf_->append(pLast, ptr - pLast - 6); + *buf_ += ' '; + } + else if (EQ(STR(name), "&")) + { + if (ptr - pLast - 5 > 0) + buf_->append(pLast, ptr - pLast - 5); + *buf_ += '&'; + } + else if (EQ(STR(name), "<")) + { + if (ptr - pLast - 4 > 0) + buf_->append(pLast, ptr - pLast - 4); + *buf_ += '<'; + } + else if (EQ(STR(name), ">")) + { + if (ptr - pLast - 4 > 0) + buf_->append(pLast, ptr - pLast - 4); + *buf_ += '>'; + } + else if (EQ(STR(name), """)) + { + if (ptr - pLast - 6 > 0) + buf_->append(pLast, ptr - pLast - 6); + *buf_ += '"'; + } + } + + acl_vstring_free(name); + delete pBuf; + + return *buf_; +} + +xml_node& xml::create_node(const char* tag, const char* text /* = NULL */) +{ + ACL_XML_NODE* node = acl_xml_create_node(xml_, tag, text); + xml_node* n = NEW xml_node(node, this); + nodes_.push_back(n); + return *n; +} + +xml_node& xml::get_root(void) +{ + if (root_) + return *root_; + root_ = NEW xml_node(xml_->root, this); + return *root_; +} + +xml_node* xml::first_node(void) +{ + if (iter_ == NULL) + iter_ = (ACL_ITER*) acl_mymalloc(sizeof(ACL_ITER)); + + ACL_XML_NODE* node = xml_->iter_head(iter_, xml_); + if (node == NULL) + return NULL; + + if (node_ == NULL) + node_ = NEW xml_node(node, this); + else + node_->set_xml_node(node); + return node_; +} + +xml_node* xml::next_node(void) +{ + acl_assert(iter_); + acl_assert(node_); + + ACL_XML_NODE* node = xml_->iter_next(iter_, xml_); + if (node == NULL) + return NULL; + node_->set_xml_node(node); + return node_; +} + +void xml::build_xml(string& out) +{ + ACL_VSTRING* buf = out.vstring(); + (void) acl_xml_build(xml_, buf); +} + +void xml::reset(void) +{ + clear(); + if (xml_) + acl_xml_reset(xml_); + else + xml_ = acl_xml_alloc(); + //dummyRootAdded_ = false; +} + +int xml::push_pop(const char* in, size_t len acl_unused, + string* out, size_t max /* = 0 */) +{ + //if (!dummyRootAdded_) + //{ + // update(""); + // dummyRootAdded_ = true; + //} + if (in) + update(in); + if (out == NULL) + return (0); + if (max > 0 && len > max) + len = max; + out->append(in, len); + return len; +} + +int xml::pop_end(string* out acl_unused, size_t max /* = 0 */ acl_unused) +{ + //if (dummyRootAdded_) + //{ + // update(""); + // dummyRootAdded_ = false; + //} + return 0; +} + +void xml::clear(void) +{ + if (buf_) + buf_->clear(); + + std::vector::iterator it = elements_.begin(); + for (; it != elements_.end(); ++it) + delete (*it); + elements_.clear(); + + std::list::iterator it1 = nodes_.begin(); + for (; it1 != nodes_.end(); ++it1) + delete (*it1); +} + +} // namespace acl diff --git a/lib_acl_cpp/src/stdlib/zlib_stream.cpp b/lib_acl_cpp/src/stdlib/zlib_stream.cpp new file mode 100644 index 000000000..2ed232189 --- /dev/null +++ b/lib_acl_cpp/src/stdlib/zlib_stream.cpp @@ -0,0 +1,485 @@ +#include "acl_stdafx.hpp" +#include "zlib.h" +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/stdlib/string.hpp" +#include "acl_cpp/stdlib/zlib_stream.hpp" + +#define HAVE_H_ZLIB + +#ifdef HAVE_H_ZLIB +# if defined(WIN32) || defined(USE_DYNAMIC) + +typedef int (*deflateInit_fn)(z_stream*, int, const char*, int); +typedef int (*deflate_fn)(z_stream*, int); +typedef int (*deflateReset_fn)(z_stream*); +typedef int (*deflateEnd_fn)(z_stream*); + +typedef int (*inflateInit_fn)(z_stream*, int, const char*, int); +typedef int (*inflate_fn)(z_stream*, int); +typedef int (*inflateReset_fn)(z_stream*); +typedef int (*inflateEnd_fn)(z_stream*); + +static deflateInit_fn __deflateInit = NULL; +static deflate_fn __deflate = NULL; +static deflateReset_fn __deflateReset = NULL; +static deflateEnd_fn __deflateEnd = NULL; +static inflateInit_fn __inflateInit = NULL; +static inflate_fn __inflate = NULL; +static inflateReset_fn __inflateReset = NULL; +static inflateEnd_fn __inflateEnd = NULL; + +static acl_pthread_once_t __zlib_once = ACL_PTHREAD_ONCE_INIT; +static ACL_DLL_HANDLE __zlib_dll = NULL; + +// 程序退出时释放动态加载的 zlib.dll 库 +static void __zlib_dll_unload(void) +{ + if (__zlib_dll != NULL) + { + acl_dlclose(__zlib_dll); + __zlib_dll = NULL; + logger("zlib.dll unload ok"); + } +} + +// 动态加载 zlib.dll 库 +static void __zlib_dll_load(void) +{ + if (__zlib_dll != NULL) + logger_fatal("__zlib_dll not null"); + +#ifdef WIN32 + __zlib_dll = acl_dlopen("zlib.dll"); +#else + __zlib_dll = acl_dlopen("libz.so"); +#endif + if (__zlib_dll == NULL) + logger_fatal("load zlib.dll error: %s", acl_last_serror()); + + __deflateInit = (deflateInit_fn) acl_dlsym(__zlib_dll, "deflateInit_"); + if (__deflateInit == NULL) + logger_fatal("load deflateInit from zlib.dll error: %s", + acl_last_serror()); + + __deflate = (deflate_fn) acl_dlsym(__zlib_dll, "deflate"); + if (__deflate == NULL) + logger_fatal("load deflate from zlib.dll error: %s", + acl_last_serror()); + + __deflateReset = (deflateReset_fn) acl_dlsym(__zlib_dll, "deflateReset"); + if (__deflateReset == NULL) + logger_fatal("load deflateReset from zlib.dll error: %s", + acl_last_serror()); + + __deflateEnd = (deflateEnd_fn) acl_dlsym(__zlib_dll, "deflateEnd"); + if (__deflateEnd == NULL) + logger_fatal("load deflateEnd from zlib.dll error: %s", + acl_last_serror()); + + __inflateInit = (inflateInit_fn) acl_dlsym(__zlib_dll, "inflateInit2_"); + if (__inflateInit == NULL) + logger_fatal("load inflateInit from zlib.dll error: %s", + acl_last_serror()); + + __inflate = (inflate_fn) acl_dlsym(__zlib_dll, "inflate"); + if (__inflate == NULL) + logger_fatal("load inflate from zlib.dll error: %s", + acl_last_serror()); + + __inflateReset = (inflateReset_fn) acl_dlsym(__zlib_dll, "inflateReset"); + if (__inflateReset == NULL) + logger_fatal("load inflateReset from zlib.dll error: %s", + acl_last_serror()); + + __inflateEnd = (inflateEnd_fn) acl_dlsym(__zlib_dll, "inflateEnd"); + if (__inflateEnd == NULL) + logger_fatal("load inflateEnd from zlib.dll error: %s", + acl_last_serror()); + + logger("zlib.dll loaded"); + atexit(__zlib_dll_unload); +} +# else +# define __deflateInit deflateInit_ +# define __deflate deflate +# define __deflateReset deflateReset +# define __deflateEnd deflateEnd +# define __inflateInit inflateInit2_ +# define __inflate inflate +# define __inflateReset inflateReset +# define __inflateEnd inflateEnd +# endif +#endif + +namespace acl +{ + +static void* __zlib_calloc(void* ctx acl_unused, + unsigned int nitem, unsigned int size) +{ + return (acl_mymalloc(nitem * size)); +} + +static void __zlib_free(void* ctx acl_unused, void* ptr) +{ + acl_myfree(ptr); +} + +zlib_stream::zlib_stream() +{ + finished_ = false; + zstream_ = (z_stream*) acl_mycalloc(1, sizeof(z_stream)); + zstream_->zalloc = __zlib_calloc; + zstream_->zfree = __zlib_free; + zstream_->opaque = (void*) this; + + is_compress_ = true; // 默认为压缩状态 + flush_ = zlib_flush_off; + +#ifdef HAVE_H_ZLIB +#if defined(WIN32) || defined(USE_DYNAMIC) + acl_pthread_once(&__zlib_once, __zlib_dll_load); +# endif +#endif +} + +zlib_stream::~zlib_stream() +{ + acl_myfree(zstream_); +} + +bool zlib_stream::zlib_compress(const char* in, int len, string* out, + zlib_level_t level /* = zlib_default */) +{ + bool ret = zip_begin(level); + if (ret == false) + { + zip_reset(); + return (false); + } + + ret = zip_update(in, len, out, zlib_flush_sync); + if (ret == false) + { + zip_reset(); + return (false); + } + + return (zip_finish(out)); +} + +bool zlib_stream::zlib_uncompress(const char* in, int len, string* out, + bool have_zlib_header /* = true */, int wsize /* = 15 */) +{ + bool ret = unzip_begin(have_zlib_header, wsize); + if (ret == false) + { + unzip_reset(); + return (false); + } + + ret = unzip_update(in, len, out, zlib_flush_sync); + if (ret == false) + { + unzip_reset(); + return (false); + } + + return (unzip_finish(out)); +} + +#define BUF_MIN 4000 + +bool zlib_stream::update(int (*func)(z_stream*, int), + zlib_flush_t flag, const char* in, int len, string* out) +{ + if (finished_) + return (true); + + acl_assert(in); + acl_assert(len >= 0); + acl_assert(out); + + int pos = 0; + int dlen, nbuf, ret; + + zstream_->avail_out = 0; + + while (true) + { + acl_assert(len >= 0); + + nbuf = (int) (out->capacity() - out->length()); + + // 需要保证输出缓冲区的可用空间 + if (nbuf < BUF_MIN) + { + nbuf = (int) out->length() + BUF_MIN; + out->space(nbuf); + } + + dlen = (int) out->length(); + nbuf = (int) out->capacity() - dlen; + acl_assert(nbuf >= BUF_MIN); + + zstream_->next_in = (unsigned char*) in + pos; + zstream_->avail_in = (unsigned int) len; + zstream_->next_out = (unsigned char*) out->c_str() + dlen; + zstream_->avail_out = (unsigned int) nbuf; + + ret = func(zstream_, flag); + if (ret == Z_STREAM_END) + { + acl_assert(flag == Z_FINISH || func == __inflate); + finished_ = true; + + // 修改输出缓冲区的指针位置 + acl_assert(nbuf >= (int) zstream_->avail_out); + dlen += nbuf - zstream_->avail_out; + out->set_offset((ssize_t) dlen); + + if (zstream_->avail_in == 0) + zstream_->next_in = NULL; + + return (true); + } + else if (ret != Z_OK) + { + logger_error("update(%s) error", + func == __deflate ? "deflate" : "inflate"); + return (false); + } + + // 修改输出缓冲区的指针位置 + acl_assert(nbuf >= (int) zstream_->avail_out); + dlen += nbuf - zstream_->avail_out; + out->set_offset((ssize_t) dlen); + + // 如输入数据完成则退出循环 + if (zstream_->avail_in == 0) + { + zstream_->next_in = NULL; + break; + } + + // 更新输入数据的下一个位置 + acl_assert(len >= (int) zstream_->avail_in); + pos += len - zstream_->avail_in; + + // 更新剩余数据长度 + len = zstream_->avail_in; + } + + return (true); +} + +bool zlib_stream::flush_out(int (*func)(z_stream*, int), + zlib_flush_t flag, string* out) +{ + if (finished_) + return (true); + + acl_assert(zstream_->avail_in == 0); + acl_assert(zstream_->next_in == NULL); + + int dlen, nbuf, ret; + + nbuf = 0; + while (true) + { + nbuf = (int) (out->capacity() - out->length()); + + // 需要保证输出缓冲区的可用空间 + if (nbuf < BUF_MIN) + { + nbuf = (int) out->length() + BUF_MIN; + out->space(nbuf); + } + + dlen = (int) out->length(); + nbuf = (int) out->capacity() - dlen; + acl_assert(nbuf >= BUF_MIN); + + zstream_->next_out = (unsigned char*) out->c_str() + dlen; + zstream_->avail_out = (unsigned int) nbuf; + + ret = func(zstream_, flag); + if (ret == Z_STREAM_END) + { + acl_assert(flag == Z_FINISH || func == __inflate); + finished_ = true; + + // 修改输出缓冲区的指针位置 + acl_assert(nbuf >= (int) zstream_->avail_out); + dlen += nbuf - zstream_->avail_out; + out->set_offset((ssize_t) dlen); + + if (zstream_->avail_in == 0) + zstream_->next_in = NULL; + break; + } + else if (ret == Z_BUF_ERROR) + { + if (zstream_->avail_out > 0) + { + logger_error("flush_out(%s) error", + func == __deflate ? "deflate" : "inflate"); + return (false); + } + + // 修改输出缓冲区的指针位置 + acl_assert(nbuf >= (int) zstream_->avail_out); + dlen += nbuf - zstream_->avail_out; + out->set_offset((ssize_t) dlen); + } + else if (ret != Z_OK) + { + logger_error("update(%s) error", func == __deflate ? + "deflate" : "inflate"); + return (false); + } + else if (zstream_->avail_out == 0) + { + // 修改输出缓冲区的指针位置 + acl_assert(nbuf >= (int) zstream_->avail_out); + dlen += nbuf - zstream_->avail_out; + out->set_offset((size_t) dlen); + } + else + break; + } + + return (true); +} + +bool zlib_stream::zip_begin(zlib_level_t level /* = zlib_default */) +{ + is_compress_ = true; + int ret = __deflateInit(zstream_, level, + ZLIB_VERSION, sizeof(z_stream)); + if (ret != Z_OK) + { + logger_error("deflateInit error"); + return (false); + } + return (true); +} + +bool zlib_stream::zip_update(const char* in, int len, string* out, + zlib_flush_t flag /* = zlib_flush_off */) +{ + return (update(__deflate, flag, in, len, out)); +} + +bool zlib_stream::zip_finish(string* out) +{ + bool ret = flush_out(__deflate, zlib_flush_finish, out); + //(void) __deflateReset(zstream_); + __deflateEnd(zstream_); + finished_ = false; + return (ret); +} + +bool zlib_stream::zip_reset() +{ + return (__deflateEnd(zstream_) == Z_OK ? true : false); +} + +bool zlib_stream::unzip_begin(bool have_zlib_header /* = true */, + int wsize /* = 15 */) +{ + is_compress_ = false; + int ret = __inflateInit(zstream_, have_zlib_header ? + wsize : -wsize, ZLIB_VERSION, sizeof(z_stream)); + if (ret != Z_OK) + { + logger_error("inflateInit error"); + return (false); + } + return (true); +} + +bool zlib_stream::unzip_update(const char* in, int len, string* out, + zlib_flush_t flag /* = zlib_flush_off */) +{ + return (update(__inflate, flag, in, len, out)); +} + +bool zlib_stream::unzip_finish(string* out) +{ + bool ret = flush_out(__inflate, zlib_flush_finish, out); + //(void) __inflateReset(zstream_); + __inflateEnd(zstream_); + finished_ = false; + return (ret); +} + +bool zlib_stream::unzip_reset() +{ + return (__inflateEnd(zstream_) == Z_OK ? true : false); +} + +bool zlib_stream::pipe_zip_begin(zlib_level_t level /* = zlib_default */, + zlib_flush_t flag /* = zlib_flush_off */) +{ + flush_ = flag; + return (zip_begin(level)); +} + +bool zlib_stream::pipe_unzip_begin(zlib_flush_t flag /* = zlib_flush_off */) +{ + flush_ = flag; + return (unzip_begin()); +} + +int zlib_stream::push_pop(const char* in, size_t len, + string* out, size_t max /* = 0 */ acl_unused) +{ + if (out == NULL) + return (0); + + size_t n = out->length(); + + if (is_compress_) + { + if (zip_update(in, len, out, flush_) == false) + return (-1); + } + else + { + if (unzip_update(in, len, out, flush_) == false) + return (-1); + } + + return ((int) (out->length() - n)); +} + +int zlib_stream::pop_end(string* out, size_t max /* = 0 */ acl_unused) +{ + if (out == NULL) + return (0); + + size_t n = out->length(); + if (is_compress_) + { + if (zip_finish(out) == false) + return (-1); + } + else + { + if (unzip_finish(out) == false) + return (-1); + } + + return ((int) (out->length() - n)); +} + +void zlib_stream::clear() +{ + if (is_compress_) + zip_reset(); + else + unzip_reset(); +} + +} // namespace acl diff --git a/lib_acl_cpp/src/stream/aio_fstream.cpp b/lib_acl_cpp/src/stream/aio_fstream.cpp new file mode 100644 index 000000000..fb279854d --- /dev/null +++ b/lib_acl_cpp/src/stream/aio_fstream.cpp @@ -0,0 +1,94 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/stream/fstream.hpp" +#include "acl_cpp/stream/aio_handle.hpp" +#include "acl_cpp/stream/aio_fstream.hpp" + +namespace acl { + +aio_fstream::aio_fstream(aio_handle* handle) +: aio_stream(handle), aio_istream(handle), aio_ostream(handle) +{ + acl_assert(handle); +} + +aio_fstream::aio_fstream(aio_handle* handle, ACL_FILE_HANDLE fd, + unsigned int oflags /* = 600 */) +: aio_stream(handle), aio_istream(handle), aio_ostream(handle) +{ + acl_assert(handle); + acl_assert(fd != ACL_FILE_INVALID); + + ACL_VSTREAM* vstream = acl_vstream_fhopen(fd, oflags); + stream_ = acl_aio_open(handle->get_handle(), vstream); + + // 调用基类的 hook_error 以向 handle 中增加异步流计数, + // 同时 hook 关闭及超时回调过程 + hook_error(); + + // 只有当流连接成功后才可 hook IO 读写状态 + // hook 读回调过程 + hook_read(); + + // hook 写回调过程 + hook_write(); +} + +aio_fstream::~aio_fstream() +{ + +} + +void aio_fstream::destroy() +{ + delete this; +} + +bool aio_fstream::open(const char* path, unsigned int oflags, unsigned int mode) +{ + ACL_VSTREAM* fp = acl_vstream_fopen(path, oflags, mode, 8192); + if (fp == NULL) + return false; + stream_ = acl_aio_open(handle_->get_handle(), fp); + + // 调用基类的 hook_error 以向 handle 中增加异步流计数, + // 同时 hook 关闭及超时回调过程 + hook_error(); + + // 只有当流连接成功后才可 hook IO 读写状态 + // hook 读回调过程 + if ((oflags & (O_RDONLY | O_RDWR | O_APPEND | O_CREAT | O_TRUNC))) + hook_read(); + + // hook 写回调过程 + if ((oflags & (O_WRONLY | O_RDWR | O_APPEND | O_CREAT | O_TRUNC))) + hook_write(); + + return true; +} + +bool aio_fstream::open_trunc(const char* path, unsigned int mode /* = 0600 */) +{ + return open(path, O_RDWR | O_CREAT | O_TRUNC, mode); +} + +bool aio_fstream::create(const char* path, unsigned int mode /* = 0600 */) +{ + return open(path, O_RDWR | O_CREAT, mode); +} + +bool aio_fstream::open_read(const char* path) +{ + return open(path, O_RDONLY, 0200); +} + +bool aio_fstream::open_write(const char* path) +{ + return (open(path, O_WRONLY | O_TRUNC | O_CREAT, 0600)); +} + +bool aio_fstream::open_append(const char* path) +{ + return (open(path, O_WRONLY | O_APPEND | O_CREAT, 0600)); +} + +} // namespace diff --git a/lib_acl_cpp/src/stream/aio_handle.cpp b/lib_acl_cpp/src/stream/aio_handle.cpp new file mode 100644 index 000000000..b79614e90 --- /dev/null +++ b/lib_acl_cpp/src/stream/aio_handle.cpp @@ -0,0 +1,563 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/stream/aio_handle.hpp" + +namespace acl +{ + +aio_delay_free::aio_delay_free() +{ + locked_ = false; + locked_fixed_ = false; +} + +aio_delay_free::~aio_delay_free() +{ + +} + +bool aio_delay_free::locked() const +{ + return (locked_ || locked_fixed_); +} + +void aio_delay_free::set_locked() +{ + locked_fixed_ = true; +} + +void aio_delay_free::unset_locked() +{ + locked_fixed_ = false; +} + +////////////////////////////////////////////////////////////////////////// + +#define DELAY_TIMER_ID 0 + +class aio_timer_delay_free : public aio_timer_callback +{ +public: + aio_timer_delay_free() + { + handle_ = NULL; + } + + ~aio_timer_delay_free() + { + std::set::iterator it; + it = gc_set_.begin(); + for (; it != gc_set_.end(); ++it) + { + if (!(*it)->locked()) + (*it)->destroy(); + else + logger_error("one timer locked yet!"); + } + + gc_set_.clear(); + } + + virtual void timer_callback(unsigned int id acl_unused) + { + std::set::iterator it, next; + for (it = gc_set_.begin(); it != gc_set_.end(); it = next) + { + next = it; + ++next; + if (!(*it)->locked()) + { + (*it)->destroy(); + gc_set_.erase(it); + } + } + + acl_assert(handle_); + + // 不管事件引擎是否设置了重复定时器过程,重置本定时器任务 + if (!gc_set_.empty()) + handle_->set_timer(this, 100000, DELAY_TIMER_ID); + else + handle_->del_timer(this, DELAY_TIMER_ID); + } + + bool add(aio_delay_free* callback) + { + std::set::iterator it = + gc_set_.find(callback); + if (it != gc_set_.end()) + return (false); + gc_set_.insert(callback); + return (true); + } + + bool del(aio_delay_free* callback) + { + std::set::iterator it = + gc_set_.find(callback); + if (it != gc_set_.end()) + { + gc_set_.erase(it); + return (true); + } + else + return (false); + } + + aio_handle* handle_; +protected: +private: + std::set gc_set_; +}; + +////////////////////////////////////////////////////////////////////////// + +class aio_timer_task +{ +public: + aio_timer_task() {} + ~aio_timer_task() {} +protected: +private: + friend class aio_timer_callback; + + unsigned int id; + acl_int64 delay; + acl_int64 when; +}; + +////////////////////////////////////////////////////////////////////////// + +aio_timer_callback::aio_timer_callback(bool keep /* = false */) +{ + keep_ = keep; + length_ = 0; +} + +aio_timer_callback::~aio_timer_callback(void) +{ + // 如果正在触发定时器的回调过程中析构过程被调用则会发生严重问题 + if (locked()) + { + logger_error("In trigger proccess, you delete me now!"); + acl_assert(0); + } + + clear(); +} + +int aio_timer_callback::clear() +{ + int n = 0; + std::list::iterator it = tasks_.begin(); + for (; it != tasks_.end(); ++it) + { + delete (*it); + n++; + } + tasks_.clear(); + length_ = 0; + return (n); +} + +bool aio_timer_callback::empty() const +{ + return (tasks_.empty()); +} + +size_t aio_timer_callback::length() const +{ + return (length_); +} + +void aio_timer_callback::keep_timer(bool on) +{ + keep_ = on; +} + +bool aio_timer_callback::keep_timer(void) const +{ + return keep_; +} + +void aio_timer_callback::set_time(void) +{ + struct timeval now; + gettimeofday(&now, NULL); + present_ = ((unsigned long) now.tv_sec) * 1000000 + + ((unsigned long) now.tv_usec); +} + +#define TIMER_EMPTY -1 + +acl_int64 aio_timer_callback::del_task(unsigned int id) +{ + bool ok = false; + std::list::iterator it = tasks_.begin(); + for (; it != tasks_.end(); ++it) + { + if ((*it)->id == id) + { + delete (*it); + tasks_.erase(it); + length_--; + ok = true; + break; + } + } + + if (!ok) + logger_warn("timer id: %u not found", id); + + if (tasks_.empty()) + return (TIMER_EMPTY); + + set_time(); + + acl_int64 delay = tasks_.front()->when - present_; + return (delay < 0 ? 0 : delay); +} + +acl_int64 aio_timer_callback::set_task(unsigned int id, acl_int64 delay) +{ + aio_timer_task* task = NULL; + std::list::iterator it = tasks_.begin(); + for (; it != tasks_.end(); ++it) + { + if ((*it)->id == id) + { + task = (*it); + tasks_.erase(it); + length_--; + break; + } + } + + if (task == NULL) + { + task = NEW aio_timer_task(); + task->delay = delay; + task->id = id; + } + else + task->delay = delay; + + return (set_task(task)); +} + +acl_int64 aio_timer_callback::set_task(aio_timer_task* task) +{ + set_time(); + task->when = present_ + task->delay; + + std::list::iterator it = tasks_.begin(); + for (; it != tasks_.end(); ++it) + { + if (task->when < (*it)->when) + { + tasks_.insert(it, task); + break; + } + } + + if (it == tasks_.end()) + tasks_.push_back(task); + + length_++; + + aio_timer_task* first = tasks_.front(); + acl_int64 delay = first->when - present_; + return (delay < 0 ? 0 : delay); +} + +acl_int64 aio_timer_callback::trigger(void) +{ + // sanity check + if (tasks_.empty()) + return (TIMER_EMPTY); + + acl_assert(length_ > 0); + + set_time(); + + std::list::iterator it, next; + std::list tasks; + aio_timer_task* task; + + // 从定时器中取出到达的定时任务 + for (it = tasks_.begin(); it != tasks_.end(); it = next) + { + if ((*it)->when > present_) + break; + next = it; + ++next; + task = *it; + tasks_.erase(it); + length_--; + tasks.push_back(task); + } + + // 有可能这些到达的定时任务已经被用户提前删除了 + if (tasks.empty()) + { + acl_assert(!tasks_.empty()); + + aio_timer_task* first = tasks_.front(); + acl_int64 delay = first->when - present_; + return (delay < 0 ? 0 : delay); + } + + // 将到达的定时任务重新放回至定时器的任务列表中, + // 并开始触发所有的到达的定时任务 + + // 必须先设置触发器的忙状态,以防止子类在回调过程 + // 中调用了该类对象的析构过程 + set_locked(); + + // 设置解锁后销毁标志为 false,因为当前该定时器处于 + // 锁定状态,所以其它类对象不能直接在锁定时销毁本类 + // 对象,当解锁后,如果该标识被置为 true,则本类对象 + // 应该自动销毁 + destroy_on_unlock_ = false; + + for (it = tasks.begin(); it != tasks.end(); ++it) + { + set_task(*it); + timer_callback((*it)->id); + } + + tasks.clear(); + + // 允许之后的操作中被子类调用析构过程 + unset_locked(); + + // 子类有可能会在 timer_callback 中删除了所有的定时任务 + if (tasks_.empty()) + return (TIMER_EMPTY); + + aio_timer_task* first = tasks_.front(); + acl_int64 delay = first->when - present_; + + // 如果在加锁期间外部程序要求释放该对象,则在此处释放 + if (destroy_on_unlock_) + destroy(); + return (delay < 0 ? 0 : delay); +} + +////////////////////////////////////////////////////////////////////////// + +aio_handle::aio_handle(aio_handle_type engine_type /* = ENGINE_SELECT */ + , unsigned int nMsg /* = 0 */) + : stop_(false) + , nstream_(0) + , engine_type_(engine_type) +{ + int event_type; + + if (engine_type == ENGINE_SELECT) + event_type = ACL_EVENT_SELECT; + else if (engine_type == ENGINE_POLL) + event_type = ACL_EVENT_POLL; + else if (engine_type == ENGINE_KERNEL) + event_type = ACL_EVENT_KERNEL; +#ifdef WIN32 + else if (engine_type == ENGINE_WINMSG) + event_type = ACL_EVENT_WMSG; +#endif + else + acl_assert(0); + + aio_ = acl_aio_create2(event_type, nMsg); + inner_alloc_ = true; + + // 创建延迟关闭的定时器对象 + delay_free_timer_ = NEW aio_timer_delay_free(); + + // 在异步引擎对象的生命周期内锁定该延迟释放定时 + // 器,以防止异步引擎自动销毁该定时器 + delay_free_timer_->set_locked(); +} + +aio_handle::aio_handle(ACL_AIO* aio) + : aio_(aio) + , stop_(false) + , nstream_(0) +{ + acl_assert(aio_); + int event_type = acl_aio_event_mode(aio); + + if (event_type == ACL_EVENT_SELECT) + engine_type_ = ENGINE_SELECT; + else if (event_type == ACL_EVENT_POLL) + engine_type_ = ENGINE_POLL; + else if (event_type == ACL_EVENT_KERNEL) + engine_type_ = ENGINE_KERNEL; + else if (event_type == ACL_EVENT_WMSG) + engine_type_ = ENGINE_WINMSG; + else + acl_assert(0); + + inner_alloc_ = false; + + // 创建延迟关闭的定时器对象 + delay_free_timer_ = NEW aio_timer_delay_free(); + // 在异步引擎对象的生命周期内锁定该延迟释放定时 + // 器,以防止异步引擎自动销毁该定时器 + delay_free_timer_->set_locked(); +} + +aio_handle::~aio_handle() +{ + if (inner_alloc_) + acl_aio_free(aio_); + + delay_free_timer_->unset_locked(); + delete delay_free_timer_; +} + +void aio_handle::keep_read(bool onoff) +{ + acl_aio_set_keep_read(aio_, onoff ? 1 : 0); +} + +bool aio_handle::keep_read() const +{ + return (acl_aio_get_keep_read(aio_) == 0 ? false : true); +} + +acl_int64 aio_handle::set_timer(aio_timer_callback* callback, + acl_int64 delay, unsigned int id /* = 0 */) +{ + acl_assert(aio_); + callback->handle_ = this; + delay = callback->set_task(id, delay); + return (acl_aio_request_timer(aio_, + (void (*)(int, void*)) on_timer_callback, + callback, delay < 0 ? 0 : delay, + callback->keep_ ? 1 : 0)); +} + +void aio_handle::on_timer_callback(int event_type acl_unused, + aio_timer_callback *callback) +{ + acl_assert(callback); + acl_assert(callback->handle_); + aio_handle* handle = callback->handle_; + + // 触发定时器中的所有定时任务 + acl_int64 next_delay = callback->trigger(); + + // 如果定时器中的任务为空或未设置定时器的重复使用,则删除定时器 + if (callback->empty() || !callback->keep_timer()) + { + handle->del_timer(callback); + return; + } + + // 如果允许重复使用定时器且定时器中的任务非空,则再次设置该定时器 + + // 需要重置定时器的到达时间截 + acl_aio_request_timer(handle->aio_, + (void (*)(int, void*)) on_timer_callback, + callback, next_delay < 0 ? 0 : next_delay, + callback->keep_timer() ? 1 : 0); +} + +acl_int64 aio_handle::del_timer(aio_timer_callback* callback, unsigned int id) +{ + acl_assert(aio_); + acl_int64 next_delay = callback->del_task(id); + + // 如果定时器中的任务为空,则删除该定时器 + if (callback->empty()) + return del_timer(callback); + + return (acl_aio_request_timer(callback->handle_->aio_, + (void (*)(int, void*)) on_timer_callback, + callback, next_delay < 0 ? 0 : next_delay, + callback->keep_timer() ? 1 : 0)); +} + +acl_int64 aio_handle::del_timer(aio_timer_callback* callback) +{ + acl_assert(aio_); + acl_int64 next_delay = acl_aio_cancel_timer(aio_, + (void (*)(int, void*)) on_timer_callback, callback); + callback->clear(); + destroy_timer(callback); + + return (next_delay); +} + +void aio_handle::delay_free(aio_delay_free* callback) +{ + // 添加延迟释放定时器的定时任务 + if (delay_free_timer_->add(callback)) + { + delay_free_timer_->handle_ = this; + set_timer(delay_free_timer_, 100000, 0); + } +} + +void aio_handle::destroy_timer(aio_timer_callback* callback) +{ + delay_free_timer_->del(callback); + + // 如果该定时器已经在 trigger 中被锁定,则只需要 + // 设置在解锁后需要将其销毁的标识即可,由其本身 + // 自行销毁 + if (callback->locked()) + callback->destroy_on_unlock_ = true; + + // 直接销毁未锁定的定时器 + else + callback->destroy(); +} + +ACL_AIO* aio_handle::get_handle() const +{ + return (aio_); +} + +aio_handle_type aio_handle::get_engine_type() const +{ + return (engine_type_); +} + +bool aio_handle::check() +{ + acl_aio_loop(aio_); + if (stop_) + return (false); + return (true); +} + +void aio_handle::stop() +{ + stop_ = true; +} + +void aio_handle::reset() +{ + stop_ = false; +} + +void aio_handle::increase() +{ + nstream_++; + on_increase(); +} + +void aio_handle::decrease() +{ + nstream_--; + acl_assert(nstream_ >= 0); + on_decrease(); +} + +int aio_handle::length() const +{ + return (nstream_); +} + +} // namespace acl diff --git a/lib_acl_cpp/src/stream/aio_istream.cpp b/lib_acl_cpp/src/stream/aio_istream.cpp new file mode 100644 index 000000000..c032e6ee2 --- /dev/null +++ b/lib_acl_cpp/src/stream/aio_istream.cpp @@ -0,0 +1,354 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/stream/aio_istream.hpp" + +namespace acl +{ + +void aio_timer_reader::timer_callback(unsigned int id acl_unused) +{ + in_->timer_reader_ = NULL; + if (delay_gets_) + { + int timeout = delay_timeout_; + bool nonl = delay_nonl_; + + in_->gets(timeout, nonl, 0); + } + else + { + int timeout = delay_timeout_; + int count = delay_count_; + + in_->read(count, timeout, 0); + } +} + +////////////////////////////////////////////////////////////////////// + +aio_istream::aio_istream(aio_handle* handle) + : aio_stream(handle) + , timer_reader_(NULL) + , read_hooked_(false) +{ + +} + +aio_istream::~aio_istream() +{ + if (timer_reader_ != NULL) + { + handle_->del_timer(timer_reader_); + timer_reader_->destroy(); + } + + std::list::iterator it = read_callbacks_.begin(); + for (; it != read_callbacks_.end(); ++it) + acl_myfree((*it)); + read_callbacks_.clear(); +} + +void aio_istream::destroy() +{ + delete this; +} + +void aio_istream::add_read_callback(aio_callback* callback) +{ + acl_assert(callback); + + // 先查询该回调对象已经存在 + std::list::iterator it = read_callbacks_.begin(); + for (; it != read_callbacks_.end(); ++it) + { + if ((*it)->callback == callback) + { + if ((*it)->enable == false) + (*it)->enable = true; + return; + } + } + + // 找一个空位 + it = read_callbacks_.begin(); + for (; it != read_callbacks_.end(); ++it) + { + if ((*it)->callback == NULL) + { + (*it)->enable = true; + (*it)->callback = callback; + return; + } + } + + // 分配一个新的位置 + AIO_CALLBACK* ac = (AIO_CALLBACK*) + acl_mycalloc(1, sizeof(AIO_CALLBACK)); + ac->enable = true; + ac->callback = callback; + + // 添加进回调对象队列中 + read_callbacks_.push_back(ac); +} + +int aio_istream::del_read_callback(aio_callback* callback /* = NULL */) +{ + std::list::iterator it = read_callbacks_.begin(); + int n = 0; + + if (callback == NULL) + { + for (; it != read_callbacks_.end(); ++it) + { + if ((*it)->callback == NULL) + continue; + (*it)->enable = false; + (*it)->callback = NULL; + n++; + } + } + else + { + for (; it != read_callbacks_.end(); ++it) + { + if ((*it)->callback != callback) + continue; + (*it)->enable = false; + (*it)->callback = NULL; + n++; + break; + } + } + + return (n); +} + +int aio_istream::disable_read_callback(aio_callback* callback) +{ + std::list::iterator it = read_callbacks_.begin(); + int n = 0; + + if (callback == NULL) + { + for (; it != read_callbacks_.end(); ++it) + { + if ((*it)->callback == NULL || (*it)->enable == false) + continue; + (*it)->enable = false; + n++; + } + } + else + { + for (; it != read_callbacks_.end(); ++it) + { + if ((*it)->callback != callback || (*it)->enable == false) + continue; + (*it)->enable = false; + n++; + break; + } + } + + return (n); +} + +int aio_istream::enable_read_callback(aio_callback* callback /* = NULL */) +{ + std::list::iterator it = read_callbacks_.begin(); + int n = 0; + + if (callback == NULL) + { + for (; it != read_callbacks_.end(); ++it) + { + if ((*it)->enable == false && (*it)->callback != NULL) + { + (*it)->enable = true; + n++; + } + } + } + else + { + for (; it != read_callbacks_.end(); ++it) + { + if ((*it)->enable == false && (*it)->callback == callback) + { + (*it)->enable = true; + n++; + } + } + } + + return (n); +} + +void aio_istream::hook_read() +{ + acl_assert(stream_); + if (read_hooked_) + return; + read_hooked_ = true; + + /* + acl_aio_ctl(stream_, + ACL_AIO_CTL_READ_HOOK_ADD, read_callback, this, + ACL_AIO_CTL_CTX, this, + ACL_AIO_CTL_END); + */ + acl_aio_add_read_hook(stream_, read_callback, this); +} + +void aio_istream::disable_read() +{ + acl_assert(stream_); + acl_aio_disable_read(stream_); +} + +void aio_istream::keep_read(bool onoff) +{ + acl_aio_stream_set_keep_read(stream_, onoff ? 1 : 0); +} + +bool aio_istream::keep_read() const +{ + return (acl_aio_stream_get_keep_read(stream_) == 0 ? false : true); +} + +void aio_istream::gets(int timeout /* = 0 */, bool nonl /* = true */, + acl_int64 delay /* = 0 */, aio_timer_reader* callback /* = NULL */) +{ + if (delay > 0) + { + // 设置新的或重置读延迟定时器 + + disable_read(); + + if (callback != NULL) + { + if (timer_reader_ != NULL) + { + handle_->del_timer(timer_reader_); + timer_reader_->destroy(); + } + timer_reader_= callback; + } + + if (timer_reader_ == NULL) + timer_reader_ = NEW aio_timer_reader(); + // 设置 timer_reader_ 对象的成员变量 + timer_reader_->in_ = this; + timer_reader_->delay_gets_ = true; + timer_reader_->delay_timeout_ = timeout; + timer_reader_->delay_nonl_ = nonl; + + // 设置异步读定时器 + handle_->set_timer(timer_reader_, delay); + return; + } + else if (timer_reader_ != NULL) + { + // 立即取消之前设置的异步读定时器 + handle_->del_timer(timer_reader_); + timer_reader_->destroy(); + timer_reader_ = NULL; + } + + // 设置流的异步读超时时间 + if (timeout >= 0) + if (timeout >= 0) + ACL_AIO_SET_TIMEOUT(stream_, timeout); + if (nonl) + acl_aio_gets_nonl(stream_); + else + acl_aio_gets(stream_); +} + +void aio_istream::read(int count /* = 0 */, int timeout /* = 0 */, + acl_int64 delay /* = 0 */, aio_timer_reader* callback /* = NULL */) +{ + if (delay > 0) + { + // 设置新的或重置读延迟定时器 + + disable_read(); + + if (callback != NULL) + { + if (timer_reader_ != NULL) + { + handle_->del_timer(timer_reader_); + timer_reader_->destroy(); + } + timer_reader_= callback; + } + + if (timer_reader_ == NULL) + timer_reader_ = NEW aio_timer_reader(); + // 设置 timer_reader_ 对象的成员变量 + timer_reader_->in_ = this; + timer_reader_->delay_gets_ = false; + timer_reader_->delay_timeout_ = timeout; + timer_reader_->delay_count_ = count; + + // 设置异步读定时器 + handle_->set_timer(timer_reader_, delay); + return; + } + else if (timer_reader_ != NULL) + { + // 立即取消之前设置的异步读定时器 + handle_->del_timer(timer_reader_); + timer_reader_->destroy(); + timer_reader_ = NULL; + } + + // 设置流的异步读超时时间 + if (timeout >= 0) + ACL_AIO_SET_TIMEOUT(stream_, timeout); + if (count > 0) + acl_aio_readn(stream_, count); + else + acl_aio_read(stream_); +} + +void aio_istream::read_wait(int timeout /* = 0 */) +{ + // 设置流的异步读超时时间 + if (timeout >= 0) + ACL_AIO_SET_TIMEOUT(stream_, timeout); + acl_aio_enable_read(stream_, read_wakeup, this); +} + +int aio_istream::read_callback(ACL_ASTREAM* stream acl_unused, void* ctx, + char* data, int len) +{ + aio_istream* in = (aio_istream*) ctx; + std::list::iterator it = in->read_callbacks_.begin(); + for (; it != in->read_callbacks_.end(); ++it) + { + if ((*it)->enable == false || (*it)->callback == NULL) + continue; + + if ((*it)->callback->read_callback(data, len) == false) + return (-1); + } + return (0); +} + +int aio_istream::read_wakeup(ACL_ASTREAM* stream acl_unused, void* ctx) +{ + aio_istream* in = (aio_istream*) ctx; + std::list::iterator it = in->read_callbacks_.begin(); + for (; it != in->read_callbacks_.end(); ++it) + { + if ((*it)->enable == false || (*it)->callback == NULL) + continue; + + if ((*it)->callback->read_wakeup() == false) + return (-1); + } + return (0); +} + +} // namespace acl diff --git a/lib_acl_cpp/src/stream/aio_listen_stream.cpp b/lib_acl_cpp/src/stream/aio_listen_stream.cpp new file mode 100644 index 000000000..010e2fae9 --- /dev/null +++ b/lib_acl_cpp/src/stream/aio_listen_stream.cpp @@ -0,0 +1,91 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/stream/aio_handle.hpp" +#include "acl_cpp/stream/aio_socket_stream.hpp" +#include "acl_cpp/stream/aio_listen_stream.hpp" + +namespace acl +{ + +aio_listen_stream::aio_listen_stream(aio_handle *handle) + : aio_stream(handle) + , accept_hooked_(false) +{ + addr_[0] = 0; +} + +aio_listen_stream::~aio_listen_stream() +{ + accept_callbacks_.clear(); +} + +void aio_listen_stream::destroy() +{ + delete this; +} + +void aio_listen_stream::add_accept_callback(aio_accept_callback* callback) +{ + std::list::iterator it = + accept_callbacks_.begin(); + for (; it != accept_callbacks_.end(); ++it) + { + if (*it == callback) + return; + } + accept_callbacks_.push_back(callback); +} + +bool aio_listen_stream::open(const char* addr) +{ + ACL_VSTREAM *sstream = acl_vstream_listen(addr, 128); + if (sstream == NULL) + return (false); + + snprintf(addr_, sizeof(addr_), "%s", ACL_VSTREAM_LOCAL(sstream)); + + stream_ = acl_aio_open(handle_->get_handle(), sstream); + + // 调用基类的 hook_error 以向 handle 中增加异步流计数, + // 同时 hook 关闭及超时回调过程 + hook_error(); + + // hook 监听的回调过程 + hook_accept(); + return (true); +} + +const char* aio_listen_stream::get_addr() const +{ + return (addr_); +} + +void aio_listen_stream::hook_accept() +{ + acl_assert(stream_); + if (accept_hooked_) + return; + accept_hooked_ = true; + + acl_aio_ctl(stream_, + ACL_AIO_CTL_ACCEPT_FN, accept_callback, + ACL_AIO_CTL_CTX, this, + ACL_AIO_CTL_END); + acl_aio_accept(stream_); +} + +int aio_listen_stream::accept_callback(ACL_ASTREAM* stream, void* ctx) +{ + aio_listen_stream* as = (aio_listen_stream*) ctx; + std::list::iterator it = + as->accept_callbacks_.begin(); + aio_socket_stream* ss = NEW aio_socket_stream(as->handle_, stream, true); + + for (; it != as->accept_callbacks_.end(); ++it) + { + if ((*it)->accept_callback(ss) == false) + return (-1); + } + return (0); +} + +} // namespace acl diff --git a/lib_acl_cpp/src/stream/aio_ostream.cpp b/lib_acl_cpp/src/stream/aio_ostream.cpp new file mode 100644 index 000000000..474837e5c --- /dev/null +++ b/lib_acl_cpp/src/stream/aio_ostream.cpp @@ -0,0 +1,307 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/stream/aio_ostream.hpp" + +namespace acl +{ + +aio_timer_writer::aio_timer_writer() + : out_(NULL) +{ + +} + +aio_timer_writer::~aio_timer_writer() +{ + +} + +void aio_timer_writer::timer_callback(unsigned int id acl_unused) +{ + if (out_ == NULL) + return; + + bool findit = false; + std::list::iterator it = + out_->timer_writers_.begin(); + for (; it != out_->timer_writers_.end(); ++it) + { + if ((*it) == this) + { + out_->timer_writers_.erase(it); + findit = true; + break; + } + } + + if (findit == false) + logger_warn("Warning: timer_writer is the end!"); + + out_->write(buf_.c_str(), (int) buf_.length(), 0, NULL); +} + +////////////////////////////////////////////////////////////////////// + +aio_ostream::aio_ostream(aio_handle* handle) + : aio_stream(handle) + , write_hooked_(false) +{ + +} + +aio_ostream::~aio_ostream() +{ + std::list::iterator it = timer_writers_.begin(); + + for (; it != timer_writers_.end(); ++it) + { + handle_->del_timer(*it); + (*it)->destroy(); + } + timer_writers_.clear(); + + std::list::iterator it2 = write_callbacks_.begin(); + for (; it2 != write_callbacks_.end(); ++it2) + acl_myfree((*it2)); + write_callbacks_.clear(); +} + +void aio_ostream::destroy() +{ + delete this; +} + +void aio_ostream::add_write_callback(aio_callback* callback) +{ + acl_assert(callback); + + // 先查询该回调对象已经存在 + std::list::iterator it = write_callbacks_.begin(); + for (; it != write_callbacks_.end(); ++it) + { + if ((*it)->callback == callback) + { + if ((*it)->enable == false) + (*it)->enable = true; + return; + } + } + + // 找一个空位 + it = write_callbacks_.begin(); + for (; it != write_callbacks_.end(); ++it) + { + if ((*it)->callback == NULL) + { + (*it)->enable = true; + (*it)->callback = callback; + return; + } + } + + // 分配一个新的位置 + AIO_CALLBACK* ac = (AIO_CALLBACK*) + acl_mycalloc(1, sizeof(AIO_CALLBACK)); + ac->enable = true; + ac->callback = callback; + + // 添加进回调对象队列中 + write_callbacks_.push_back(ac); +} + +int aio_ostream::del_write_callback(aio_callback* callback) +{ + std::list::iterator it = write_callbacks_.begin(); + int n = 0; + + if (callback == NULL) + { + for (; it != write_callbacks_.end(); ++it) + { + if ((*it)->callback == NULL) + continue; + (*it)->enable = false; + (*it)->callback = NULL; + n++; + } + } + else + { + for (; it != write_callbacks_.end(); ++it) + { + if ((*it)->callback != callback) + continue; + (*it)->enable = false; + (*it)->callback = NULL; + n++; + break; + } + } + + return (n); +} + +int aio_ostream::disable_write_callback(aio_callback* callback) +{ + std::list::iterator it = write_callbacks_.begin(); + int n = 0; + + if (callback == NULL) + { + for (; it != write_callbacks_.end(); ++it) + { + if ((*it)->callback == NULL || (*it)->enable == false) + continue; + (*it)->enable = false; + n++; + } + } + else + { + for (; it != write_callbacks_.end(); ++it) + { + if ((*it)->callback != callback || (*it)->enable == false) + continue; + (*it)->enable = false; + n++; + break; + } + } + + return (n); +} + +int aio_ostream::enable_write_callback(aio_callback* callback /* = NULL */) +{ + std::list::iterator it = write_callbacks_.begin(); + int n = 0; + + if (callback == NULL) + { + for (; it != write_callbacks_.end(); ++it) + { + if ((*it)->enable == false && (*it)->callback != NULL) + { + (*it)->enable = true; + n++; + } + } + } + else + { + for (; it != write_callbacks_.end(); ++it) + { + if ((*it)->enable == false && (*it)->callback == callback) + { + (*it)->enable = true; + n++; + } + } + } + + return (n); +} + +void aio_ostream::hook_write() +{ + acl_assert(stream_); + if (write_hooked_) + return; + write_hooked_ = true; + + /* + acl_aio_ctl(stream_, + ACL_AIO_CTL_WRITE_HOOK_ADD, write_callback, this, + ACL_AIO_CTL_END); + */ + acl_aio_add_write_hook(stream_, write_callback, this); +} + +void aio_ostream::disable_write() +{ + acl_assert(stream_); + acl_aio_disable_write(stream_); +} + +void aio_ostream::write(const void* data, int len, + acl_int64 delay /* = 0 */, + aio_timer_writer* callback /* = NULL */) +{ + if (delay > 0) + { + disable_write(); + + aio_timer_writer* timer_writer; + + if (callback != NULL) + timer_writer= callback; + else + timer_writer = NEW aio_timer_writer(); + + // 设置 timer_writer_ 对象的成员变量 + timer_writer->out_ = this; + timer_writer->buf_.copy(data, len); + + // 将该写操作放入延迟异步写的队列中 + timer_writers_.push_back(timer_writer); + // 设置定时器 + handle_->set_timer(timer_writer, delay); + return; + } + + acl_assert(stream_); + acl_aio_writen(stream_, (const char*) data, len); +} + +void aio_ostream::format(const char* fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + acl_aio_vfprintf(stream_, fmt, ap); + va_end(ap); +} + +void aio_ostream::vformat(const char* fmt, va_list ap) +{ + acl_aio_vfprintf(stream_, fmt, ap); +} + +void aio_ostream::write_wait(int timeout /* = 0 */) +{ + // 设置流的异步读超时时间 + if (timeout >= 0) + ACL_AIO_SET_TIMEOUT(stream_, timeout); + acl_aio_enable_write(stream_, write_wakup, this); +} + +int aio_ostream::write_callback(ACL_ASTREAM* stream acl_unused, void* ctx) +{ + aio_ostream* aos = (aio_ostream*) ctx; + std::list::iterator it = aos->write_callbacks_.begin(); + for (; it != aos->write_callbacks_.end(); ++it) + { + if ((*it)->enable == false || (*it)->callback == NULL) + continue; + + if ((*it)->callback->write_callback() == false) + return (-1); + } + return (0); +} + +int aio_ostream::write_wakup(ACL_ASTREAM* stream acl_unused, void* ctx) +{ + aio_ostream* out = (aio_ostream*) ctx; + std::list::iterator it = out->write_callbacks_.begin(); + for (; it != out->write_callbacks_.end(); ++it) + { + if ((*it)->enable == false || (*it)->callback == NULL) + continue; + + if ((*it)->callback->write_wakeup() == false) + return (-1); + } + return (0); +} + +} // namespace acl diff --git a/lib_acl_cpp/src/stream/aio_socket_stream.cpp b/lib_acl_cpp/src/stream/aio_socket_stream.cpp new file mode 100644 index 000000000..266542d68 --- /dev/null +++ b/lib_acl_cpp/src/stream/aio_socket_stream.cpp @@ -0,0 +1,264 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/stream/aio_handle.hpp" +#include "acl_cpp/stream/aio_socket_stream.hpp" + +namespace acl +{ + +aio_socket_stream::aio_socket_stream(aio_handle* handle, + ACL_ASTREAM* stream, bool opened /* = false */) + : aio_stream(handle), aio_istream(handle), aio_ostream(handle) + , opened_(opened) + , open_hooked_(false) +{ + acl_assert(handle); + acl_assert(stream); + + stream_ = stream; + + // 调用基类的 hook_error 以向 handle 中增加异步流计数, + // 同时 hook 关闭及超时回调过程 + hook_error(); + + // 只有当流连接成功后才可 hook IO 读写状态 + if (opened) + { + // hook 读回调过程 + hook_read(); + + // hook 写回调过程 + hook_write(); + } +} + +aio_socket_stream::aio_socket_stream(aio_handle* handle, ACL_SOCKET fd) + : aio_stream(handle), aio_istream(handle), aio_ostream(handle) + , opened_(true) + , open_hooked_(false) +{ + acl_assert(handle); + + ACL_VSTREAM* vstream = acl_vstream_fdopen(fd, O_RDWR, 8192, 0, + ACL_VSTREAM_TYPE_SOCK); + stream_ = acl_aio_open(handle->get_handle(), vstream); + + // 调用基类的 hook_error 以向 handle 中增加异步流计数, + // 同时 hook 关闭及超时回调过程 + hook_error(); + + // 只有当流连接成功后才可 hook IO 读写状态 + // hook 读回调过程 + hook_read(); + + // hook 写回调过程 + hook_write(); +} + +aio_socket_stream::~aio_socket_stream() +{ + std::list::iterator it = open_callbacks_.begin(); + for (; it != open_callbacks_.end(); ++it) + acl_myfree((*it)); + open_callbacks_.clear(); +} + +void aio_socket_stream::destroy() +{ + delete this; +} + +void aio_socket_stream::add_open_callback(aio_open_callback* callback) +{ + // 先查询该回调对象已经存在 + std::list::iterator it = open_callbacks_.begin(); + for (; it != open_callbacks_.end(); ++it) + { + if ((*it)->callback == callback) + { + if ((*it)->enable == false) + (*it)->enable = true; + return; + } + } + + // 找一个空位 + it = open_callbacks_.begin(); + for (; it != open_callbacks_.end(); ++it) + { + if ((*it)->callback == NULL) + { + (*it)->enable = true; + (*it)->callback = callback; + return; + } + } + + // 分配一个新的位置 + AIO_OPEN_CALLBACK* ac = (AIO_OPEN_CALLBACK*) + acl_mycalloc(1, sizeof(AIO_OPEN_CALLBACK)); + ac->enable = true; + ac->callback = callback; + + // 添加进回调对象队列中 + open_callbacks_.push_back(ac); +} + +int aio_socket_stream::del_open_callback(aio_open_callback* callback /* = NULL */) +{ + std::list::iterator it = open_callbacks_.begin(); + int n = 0; + + if (callback == NULL) + { + for (; it != open_callbacks_.end(); ++it) + { + if ((*it)->callback == NULL) + continue; + (*it)->enable = false; + (*it)->callback = NULL; + n++; + } + } + else + { + for (; it != open_callbacks_.end(); ++it) + { + if ((*it)->callback != callback) + continue; + (*it)->enable = false; + (*it)->callback = NULL; + n++; + break; + } + } + + return (n); +} + +int aio_socket_stream::disable_open_callback(aio_open_callback* callback /* = NULL */) +{ + std::list::iterator it = open_callbacks_.begin(); + int n = 0; + + if (callback == NULL) + { + for (; it != open_callbacks_.end(); ++it) + { + if ((*it)->callback == NULL || (*it)->enable == false) + continue; + (*it)->enable = false; + n++; + } + } + else + { + for (; it != open_callbacks_.end(); ++it) + { + if ((*it)->callback != callback || (*it)->enable == false) + continue; + (*it)->enable = false; + n++; + break; + } + } + + return (n); +} + +int aio_socket_stream::enable_open_callback(aio_open_callback* callback /* = NULL */) +{ + std::list::iterator it = open_callbacks_.begin(); + int n = 0; + + if (callback == NULL) + { + for (; it != open_callbacks_.end(); ++it) + { + if ((*it)->enable == false && (*it)->callback != NULL) + { + (*it)->enable = true; + n++; + } + } + } + else + { + for (; it != open_callbacks_.end(); ++it) + { + if ((*it)->enable == false && (*it)->callback == callback) + { + (*it)->enable = true; + n++; + } + } + } + + return (n); +} + +aio_socket_stream* aio_socket_stream::open(aio_handle* handle, + const char* addr, int timeout) +{ + acl_assert(handle); + + ACL_ASTREAM* astream = + acl_aio_connect(handle->get_handle(), addr, timeout); + if (astream == NULL) + return (NULL); + + aio_socket_stream* stream = + NEW aio_socket_stream(handle, astream, false); + + // 调用基类的 hook_error 以向 handle 中增加异步流计数, + // 同时 hook 关闭及超时回调过程 + stream->hook_error(); + // hook 连接成功的回调过程 + stream->hook_open(); + + return (stream); +} + +bool aio_socket_stream::is_opened() const +{ + return (opened_); +} + +void aio_socket_stream::hook_open() +{ + acl_assert(stream_); + if (open_hooked_) + return; + open_hooked_ = true; + + acl_aio_ctl(stream_, + ACL_AIO_CTL_CONNECT_HOOK_ADD, open_callback, this, + ACL_AIO_CTL_END); +} + +int aio_socket_stream::open_callback(ACL_ASTREAM* stream acl_unused, void* ctx) +{ + aio_socket_stream* ss = (aio_socket_stream*) ctx; + + // 设置状态,表明已经连接成功 + ss->opened_ = true; + + // hook 读回调过程 + ss->hook_read(); + + // hook 写回调过程 + ss->hook_write(); + + // 遍历所有的打开回调对象,并调用之 + std::list::iterator it = ss->open_callbacks_.begin(); + for (; it != ss->open_callbacks_.end(); ++it) + { + if ((*it)->enable == false || (*it)->callback == NULL) + continue; + + if ((*it)->callback->open_callback() == false) + return (-1); + } + return (0); +} + +} // namespace acl diff --git a/lib_acl_cpp/src/stream/aio_stream.cpp b/lib_acl_cpp/src/stream/aio_stream.cpp new file mode 100644 index 000000000..4d43004eb --- /dev/null +++ b/lib_acl_cpp/src/stream/aio_stream.cpp @@ -0,0 +1,392 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/stream/aio_handle.hpp" +#include "acl_cpp/stream/aio_stream.hpp" + +namespace acl +{ + +aio_stream::aio_stream(aio_handle* handle) + : handle_(handle) + , stream_(NULL) + , error_hooked_(false) +{ + acl_assert(handle); +} + +aio_stream::~aio_stream() +{ + if (stream_) + { + handle_->decrease(); + acl_aio_iocp_close(stream_); + } + std::list::iterator it = close_callbacks_.begin(); + for (; it != close_callbacks_.end(); ++it) + acl_myfree((*it)); + close_callbacks_.clear(); + + it = timeout_callbacks_.begin(); + for (; it != timeout_callbacks_.end(); ++it) + acl_myfree((*it)); + timeout_callbacks_.clear(); +} + +void aio_stream::destroy() +{ + delete this; +} + +void aio_stream::close() +{ + acl_assert(stream_); + acl_aio_iocp_close(stream_); +} + +aio_handle& aio_stream::get_handle() const +{ + return (*handle_); +} + +ACL_ASTREAM* aio_stream::get_astream() const +{ + return (stream_); +} + +ACL_VSTREAM* aio_stream::get_vstream() const +{ + if (stream_ == NULL) + return (NULL); + return (acl_aio_vstream(stream_)); +} + +ACL_SOCKET aio_stream::get_socket() const +{ + ACL_VSTREAM* stream = get_vstream(); + if (stream == NULL) + return (ACL_SOCKET_INVALID); + return (ACL_VSTREAM_SOCK(stream)); +} + +void aio_stream::add_close_callback(aio_callback* callback) +{ + acl_assert(callback); + + // 先查询该回调对象已经存在 + std::list::iterator it = + close_callbacks_.begin(); + for (; it != close_callbacks_.end(); ++it) + { + if ((*it)->callback == callback) + { + if ((*it)->enable == false) + (*it)->enable = true; + return; + } + } + + // 找一个空位 + it = close_callbacks_.begin(); + for (; it != close_callbacks_.end(); ++it) + { + if ((*it)->callback == NULL) + { + (*it)->enable = true; + (*it)->callback = callback; + return; + } + } + + // 分配一个新的位置 + AIO_CALLBACK* ac = (AIO_CALLBACK*) + acl_mycalloc(1, sizeof(AIO_CALLBACK)); + ac->enable = true; + ac->callback = callback; + + // 添加进回调对象队列中 + close_callbacks_.push_back(ac); +} + +void aio_stream::add_timeout_callback(aio_callback* callback) +{ + acl_assert(callback); + + // 先查询该回调对象已经存在 + std::list::iterator it = + timeout_callbacks_.begin(); + for (; it != timeout_callbacks_.end(); ++it) + { + if ((*it)->callback == callback) + { + if ((*it)->enable == false) + (*it)->enable = true; + return; + } + } + + // 找一个空位 + it = timeout_callbacks_.begin(); + for (; it != timeout_callbacks_.end(); ++it) + { + if ((*it)->callback == NULL) + { + (*it)->enable = true; + (*it)->callback = callback; + return; + } + } + + // 分配一个新的位置 + AIO_CALLBACK* ac = (AIO_CALLBACK*) + acl_mycalloc(1, sizeof(AIO_CALLBACK)); + ac->enable = true; + ac->callback = callback; + + // 添加进回调对象队列中 + timeout_callbacks_.push_back(ac); +} + +int aio_stream::del_close_callback(aio_callback* callback) +{ + std::list::iterator it = close_callbacks_.begin(); + int n = 0; + + if (callback == NULL) + { + for (; it != close_callbacks_.end(); ++it) + { + if ((*it)->callback == NULL) + continue; + (*it)->enable = false; + (*it)->callback = NULL; + n++; + } + } + else + { + for (; it != close_callbacks_.end(); ++it) + { + if ((*it)->callback != callback) + continue; + (*it)->enable = false; + (*it)->callback = NULL; + n++; + break; + } + } + + return (n); +} + +int aio_stream::del_timeout_callback(aio_callback* callback) +{ + std::list::iterator it = timeout_callbacks_.begin(); + int n = 0; + + if (callback == NULL) + { + for (; it != timeout_callbacks_.end(); ++it) + { + if ((*it)->callback == NULL) + continue; + (*it)->enable = false; + (*it)->callback = NULL; + n++; + } + } + else + { + for (; it != timeout_callbacks_.end(); ++it) + { + if ((*it)->callback != callback) + continue; + (*it)->enable = false; + (*it)->callback = NULL; + n++; + break; + } + } + + return (n); +} + +int aio_stream::disable_close_callback(aio_callback* callback) +{ + std::list::iterator it = close_callbacks_.begin(); + int n = 0; + + if (callback == NULL) + { + for (; it != close_callbacks_.end(); ++it) + { + if ((*it)->callback == NULL || (*it)->enable == false) + continue; + (*it)->enable = false; + n++; + } + } + else + { + for (; it != close_callbacks_.end(); ++it) + { + if ((*it)->callback != callback || (*it)->enable == false) + continue; + (*it)->enable = false; + n++; + break; + } + } + + return (n); +} + +int aio_stream::disable_timeout_callback(aio_callback* callback) +{ + std::list::iterator it = timeout_callbacks_.begin(); + int n = 0; + + if (callback == NULL) + { + for (; it != timeout_callbacks_.end(); ++it) + { + if ((*it)->callback == NULL || (*it)->enable == false) + continue; + (*it)->enable = false; + n++; + } + } + else + { + for (; it != timeout_callbacks_.end(); ++it) + { + if ((*it)->callback != callback || (*it)->enable == false) + continue; + (*it)->enable = false; + n++; + break; + } + } + + return (n); +} + +int aio_stream::enable_close_callback(aio_callback* callback /* = NULL */) +{ + std::list::iterator it = close_callbacks_.begin(); + int n = 0; + + if (callback == NULL) + { + for (; it != close_callbacks_.end(); ++it) + { + if ((*it)->enable == false && (*it)->callback != NULL) + { + (*it)->enable = true; + n++; + } + } + } + else + { + for (; it != close_callbacks_.end(); ++it) + { + if ((*it)->enable == false && (*it)->callback == callback) + { + (*it)->enable = true; + n++; + } + } + } + + return (n); +} + +int aio_stream::enable_timeout_callback(aio_callback* callback /* = NULL */) +{ + std::list::iterator it = timeout_callbacks_.begin(); + int n = 0; + + if (callback == NULL) + { + for (; it != timeout_callbacks_.end(); ++it) + { + if ((*it)->enable == false && (*it)->callback != NULL) + { + (*it)->enable = true; + n++; + } + } + } + else + { + for (; it != timeout_callbacks_.end(); ++it) + { + if ((*it)->enable == false && (*it)->callback == callback) + { + (*it)->enable = true; + n++; + } + } + } + + return (n); +} + +void aio_stream::hook_error() +{ + acl_assert(stream_); + if (error_hooked_) + return; + + error_hooked_ = true; + handle_->increase(); // 增加异步流计数 + + // 注册回调函数以截获关闭时的过程 + /* + acl_aio_ctl(stream_, + ACL_AIO_CTL_CLOSE_HOOK_ADD, close_callback, this, + ACL_AIO_CTL_END); + */ + acl_aio_add_close_hook(stream_, close_callback, this); + + // 注册回调函数以截获超时时的过程 + /* + acl_aio_ctl(stream_, + ACL_AIO_CTL_TIMEO_HOOK_ADD, timeout_callback, this, + ACL_AIO_CTL_END); + */ + acl_aio_add_timeo_hook(stream_, timeout_callback, this); +} + +int aio_stream::close_callback(ACL_ASTREAM* stream acl_unused, void* ctx) +{ + aio_stream* as = (aio_stream*) ctx; + std::list::iterator it = as->close_callbacks_.begin(); + for (; it != as->close_callbacks_.end(); ++it) + { + if ((*it)->enable == false || (*it)->callback == NULL) + continue; + + (*it)->callback->close_callback(); + } + + as->destroy(); + return (0); +} + +int aio_stream::timeout_callback(ACL_ASTREAM* stream acl_unused, void* ctx) +{ + aio_stream* as = (aio_stream*) ctx; + std::list::iterator it = as->timeout_callbacks_.begin(); + for (; it != as->timeout_callbacks_.end(); ++it) + { + if ((*it)->enable == false || (*it)->callback == NULL) + continue; + + if ((*it)->callback->timeout_callback() == false) + return (-1); + } + + return (0); +} + +} // namespace acl diff --git a/lib_acl_cpp/src/stream/fstream.cpp b/lib_acl_cpp/src/stream/fstream.cpp new file mode 100644 index 000000000..324cb94eb --- /dev/null +++ b/lib_acl_cpp/src/stream/fstream.cpp @@ -0,0 +1,113 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/stream/fstream.hpp" + +namespace acl { + +fstream::fstream() +{ + +} + +fstream::~fstream() +{ + close(); +} + +void fstream::open(ACL_FILE_HANDLE fh, unsigned int oflags) +{ + acl_assert(ACL_VSTREAM_FILE(m_pStream) == ACL_FILE_INVALID); + + m_pStream->fread_fn = acl_file_read; + m_pStream->fwrite_fn = acl_file_write; + m_pStream->fwritev_fn = acl_file_writev; + m_pStream->fclose_fn = acl_file_close; + + m_pStream->fd.h_file = fh; + m_pStream->type = ACL_VSTREAM_TYPE_FILE; + m_pStream->oflags = oflags; + m_bOpened = true; + m_bEof = false; +} + +bool fstream::open(const char* path, unsigned int oflags, int mode) +{ + if (path == NULL) + return (false); + + ACL_FILE_HANDLE fh; + + fh = acl_file_open(path, oflags, mode); + if (fh == ACL_FILE_INVALID) + return (false); + + m_pStream->fread_fn = acl_file_read; + m_pStream->fwrite_fn = acl_file_write; + m_pStream->fwritev_fn = acl_file_writev; + m_pStream->fclose_fn = acl_file_close; + + m_pStream->fd.h_file = fh; + m_pStream->type = ACL_VSTREAM_TYPE_FILE; + m_pStream->oflags = oflags; + ACL_SAFE_STRNCPY(m_pStream->remote_addr, path, + sizeof(m_pStream->remote_addr)); + m_bOpened = true; + m_bEof = false; + return (true); +} + +const char* fstream::file_path() const +{ + return m_pStream ? m_pStream->path : NULL; +} + +bool fstream::open_trunc(const char* path) +{ + return (open(path, O_RDWR | O_CREAT | O_TRUNC, 0600)); +} + +bool fstream::create(const char* path) +{ + return (open(path, O_RDWR | O_CREAT, 0600)); +} + +bool fstream::close() +{ + if (m_bOpened == false) + return (false); + + if (m_pStream == NULL) + return (true); + + if (m_pStream->type != ACL_VSTREAM_TYPE_FILE) + return (false); + + ACL_FILE_HANDLE fh = ACL_VSTREAM_FILE(m_pStream); + if (fh == ACL_FILE_INVALID) + return (false); + m_bEof = true; + m_bOpened = false; + return (acl_file_close(fh) == 0 ? true : false); +} + +acl_off_t fstream::fseek(acl_off_t offset, int whence) +{ + return (acl_vstream_fseek(m_pStream, offset, whence)); +} + +bool fstream::ftruncate(acl_off_t length) +{ + fseek(0, SEEK_SET); // 需要先将文件指针移到开始位置 + return (acl_file_ftruncate(m_pStream, length) == 0 ? true : false); +} + +acl_int64 fstream::fsize() const +{ + return (acl_vstream_fsize(m_pStream)); +} + +ACL_FILE_HANDLE fstream::file_handle() const +{ + return (ACL_VSTREAM_FILE(m_pStream)); +} + +} // namespace acl diff --git a/lib_acl_cpp/src/stream/ifstream.cpp b/lib_acl_cpp/src/stream/ifstream.cpp new file mode 100644 index 000000000..4ba593e52 --- /dev/null +++ b/lib_acl_cpp/src/stream/ifstream.cpp @@ -0,0 +1,40 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/stream/ifstream.hpp" + +namespace acl { + +bool ifstream::open_read(const char* path) +{ + return (open(path, O_RDONLY, 0200)); +} + +bool ifstream::load(acl::string* s) +{ + if (s == NULL) + return (false); + if (m_pStream == NULL) + return (false); + if (fseek(0, SEEK_SET) == -1) + return (false); + + char buf[4096]; + int ret; + while (1) { + if ((ret = read(buf, sizeof(buf), false)) < 0) + break; + + s->append(buf, ret); + } + + return (true); +} + +bool ifstream::load(const char* path, acl::string* s) +{ + acl::ifstream fp; + if (fp.open_read(path) == false) + return (false); + return (fp.load(s)); +} + +} // namespace acl diff --git a/lib_acl_cpp/src/stream/istream.cpp b/lib_acl_cpp/src/stream/istream.cpp new file mode 100644 index 000000000..bee95b850 --- /dev/null +++ b/lib_acl_cpp/src/stream/istream.cpp @@ -0,0 +1,224 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/stdlib/string.hpp" +#include "acl_cpp/stream/istream.hpp" + +namespace acl { + +int istream::read(void* buf, size_t size, bool loop /* = true */) +{ + int ret; + if (loop && size > 1) + ret = acl_vstream_readn(m_pStream, buf, size); + else + ret = acl_vstream_read(m_pStream, buf, size); + if (ret == ACL_VSTREAM_EOF) + { + m_bEof = true; + return (-1); + } else + return (ret); +} + +bool istream::readtags(void *buf, size_t* size, const char *tag, size_t taglen) +{ + int ret = acl_vstream_readtags(m_pStream, buf, *size, tag, taglen); + if (ret == ACL_VSTREAM_EOF) + m_bEof = true; + + if ((m_pStream->flag & ACL_VSTREAM_FLAG_TAGYES)) + return (true); + else + return (false); +} + +bool istream::gets(void* buf, size_t* size, bool nonl /* = true */) +{ + int ret; + if (nonl) + ret = acl_vstream_gets_nonl(m_pStream, buf, *size); + else + ret = acl_vstream_gets(m_pStream, buf, *size); + if (ret == ACL_VSTREAM_EOF) { + m_bEof = true; + *size = 0; + return (false); + } else { + *size = ret; + if ((m_pStream->flag | ACL_VSTREAM_FLAG_TAGYES)) + return (true); + return (false); + } +} + +bool istream::read(acl_int64& n, bool loop /* = true */) +{ + return (read(&n, sizeof(n), loop) == (int) sizeof(n)); +} + +bool istream::read(int& n, bool loop /* = true */) +{ + return (read(&n, sizeof(n), loop) == (int) sizeof(n)); +} + +bool istream::read(short& n, bool loop /* = true */) +{ + return (read(&n, sizeof(n), loop) == (int) sizeof(n)); +} + +bool istream::read(char& ch) +{ + return (read(&ch, sizeof(ch), false) == (int) sizeof(ch)); +} + +bool istream::read(string& s, bool loop /* = true */) +{ + s.clear(); + int ret; + + if ((ret = read(s.buf(), s.capacity(), loop)) == -1) + return (false); + s.set_offset(ret); + return (true); +} + +bool istream::read(string& s, size_t max, bool loop /* = true */) +{ + s.clear(); + s.space(max); + int ret = read(s.buf(), max, loop); + if (ret == -1) + return false; + s.set_offset(ret); + return true; +} + +bool istream::gets(string& s, bool nonl /* = true */) +{ + char buf[8192]; + + s.clear(); + while (!eof()) { + size_t size = sizeof(buf); + if (gets(buf, &size, nonl) == true) { + if (size > 0) + s.append(buf, size); + return (true); + } + if (size > 0) + s.append(buf, size); + } + return (false); +} + +bool istream::readtags(string& s, const string& tag) +{ + char buf[8192]; + + s.clear(); + + while (!eof()) { + size_t size = sizeof(buf); + if (readtags(buf, &size, tag.c_str(), tag.length()) == true) { + if (size > 0) + s.append(buf, size); + return (true); + } + if (size > 0) + s.append(buf, size); + } + return (false); +} + +int istream::getch() +{ + int ret = acl_vstream_getc(m_pStream); + if (ret == ACL_VSTREAM_EOF) + m_bEof = true; + return (ret); +} + +int istream::ugetch(int ch) +{ + int ret = acl_vstream_ungetc(m_pStream, ch); + if (ret == ACL_VSTREAM_EOF) + m_bEof = true; + return (ret); +} + +bool istream::gets_peek(string& buf, bool nonl /* = true */, + bool clear /* = false */) +{ + if (clear) + buf.clear(); + + int ready, ret; + ACL_VSTRING *vbf = (ACL_VSTRING*) buf.vstring(); + if (nonl) + ret = acl_vstream_gets_nonl_peek(m_pStream, vbf, &ready); + else + ret = acl_vstream_gets_peek(m_pStream, vbf, &ready); + if (ret == ACL_VSTREAM_EOF) + m_bEof = true; + return (ready ? true : false); +} + +bool istream::read_peek(string& buf, bool clear /* = false */) +{ + if (clear) + buf.clear(); + + if (acl_vstream_read_peek(m_pStream, buf.vstring()) == ACL_VSTREAM_EOF) + { + m_bEof = true; + return false; + } + else + return true; +} + +bool istream::readn_peek(string& buf, size_t cnt, bool clear /* = false */) +{ + if (clear) + buf.clear(); + + int ready; + if (acl_vstream_readn_peek(m_pStream, buf.vstring(), + (int) cnt, &ready) == ACL_VSTREAM_EOF) + { + m_bEof = true; + } + return (ready ? true : false); +} + +istream& istream::operator>>(acl::string& s) +{ + s.clear(); + (void) read(s.buf(), s.length(), true); + return (*this); +} + +istream& istream::operator>>(acl_int64& n) +{ + (void) read(n); + return (*this); +} + +istream& istream::operator>>(int& n) +{ + (void) read(n); + return (*this); +} + +istream& istream::operator>>(short& n) +{ + (void) read(n); + return (*this); +} + +istream& istream::operator>>(char& ch) +{ + (void) read(ch); + return (*this); +} + +} // namespace acl diff --git a/lib_acl_cpp/src/stream/ofstream.cpp b/lib_acl_cpp/src/stream/ofstream.cpp new file mode 100644 index 000000000..22fc87cac --- /dev/null +++ b/lib_acl_cpp/src/stream/ofstream.cpp @@ -0,0 +1,24 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/stream/ofstream.hpp" + +namespace acl { + +ofstream::ofstream() +{ +} + +ofstream::~ofstream() +{ +} + +bool ofstream::open_write(const char* path) +{ + return (open(path, O_WRONLY | O_TRUNC | O_CREAT, 0600)); +} + +bool ofstream::open_append(const char* path) +{ + return (open(path, O_WRONLY | O_APPEND | O_CREAT, 0600)); +} + +} // namespace acl diff --git a/lib_acl_cpp/src/stream/ostream.cpp b/lib_acl_cpp/src/stream/ostream.cpp new file mode 100644 index 000000000..5965ee4a3 --- /dev/null +++ b/lib_acl_cpp/src/stream/ostream.cpp @@ -0,0 +1,131 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/stream/ostream.hpp" + +namespace acl { + +int ostream::write(const void* data, size_t size, bool loop /* = true */) +{ + int ret; + if (loop) + ret = acl_vstream_writen(m_pStream, data, size); + else + ret = acl_vstream_write(m_pStream, data, (int) size); + if (ret == ACL_VSTREAM_EOF) + m_bEof = true; + return (ret); +} + +int ostream::writev(const struct iovec *v, int count, bool loop) +{ + int ret; + if (loop) + ret = acl_vstream_writevn(m_pStream, v, count); + else + ret = acl_vstream_writev(m_pStream, v, count); + if (ret == ACL_VSTREAM_EOF) + m_bEof = true; + return (ret); +} + +int ostream::vformat(const char* fmt, va_list ap) +{ + int ret = acl_vstream_vfprintf(m_pStream, fmt, ap); + if (ret == ACL_VSTREAM_EOF) + m_bEof = true; + return (ret); +} + +int ostream::write(acl_int64 n) +{ + return (write(&n, sizeof(n), true)); +} + +int ostream::write(int n) +{ + return (write(&n, sizeof(n), true)); +} + +int ostream::write(short n) +{ + return (write(&n, sizeof(n), true)); +} + +int ostream::write(char ch) +{ + return (write(&ch, sizeof(ch), false)); +} + +int ostream::write(const acl::string& s, bool loop) +{ + return (write(s.c_str(), s.length(), loop)); +} + +int ostream::format(const char* fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + int ret = vformat(fmt, ap); + va_end(ap); + return (ret); +} + +int ostream::puts(const char* s) +{ + return (format("%s\r\n", s)); +} + +ostream& ostream::operator<<(const acl::string& s) +{ + (void) write(s.c_str(), s.length(), true); + return (*this); +} + +ostream& ostream::operator<<(const char* s) +{ + (void) write(s, strlen(s), true); + return (*this); +} + +ostream& ostream::operator<<(acl_int64 n) +{ + (void) write(&n, sizeof(n), true); + return (*this); +} + +ostream& ostream::operator<<(int n) +{ + (void) write(&n, sizeof(n), true); + return (*this); +} + +ostream& ostream::operator<<(short n) +{ + (void) write(&n, sizeof(n), true); + return (*this); +} + +ostream& ostream::operator<<(char ch) +{ + (void) write(&ch, sizeof(ch), false); + return (*this); +} + +int ostream::push_pop(const char* in, size_t len, + string* out /* = NULL */ acl_unused, + size_t max /* = 0 */ acl_unused) +{ + if (in == NULL || len == 0) + return (0); + if ((size_t) write(in, len) != len) + return (-1); + if (out == NULL) + return (0); + if (max > 0 && len > max) + len = max; + out->append(in, len); + return (len); +} + + +} // namespace acl diff --git a/lib_acl_cpp/src/stream/server_socket.cpp b/lib_acl_cpp/src/stream/server_socket.cpp new file mode 100644 index 000000000..364fab457 --- /dev/null +++ b/lib_acl_cpp/src/stream/server_socket.cpp @@ -0,0 +1,99 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/stdlib/util.hpp" +#include "acl_cpp/stream/socket_stream.hpp" +#include "acl_cpp/stream/server_socket.hpp" + +namespace acl { + +server_socket::server_socket(int backlog /* = 128 */, bool block /* = true */) +: backlog_(backlog) +, block_(block) +, unix_sock_(false) +, fd_(ACL_SOCKET_INVALID) +{ +} + +server_socket::~server_socket() +{ + if (fd_ != ACL_SOCKET_INVALID) + acl_socket_close(fd_); +} + +bool server_socket::open(const char* addr) +{ + snprintf(addr_, sizeof(addr_), "%s", addr); + +#ifndef WIN32 + if (strchr(addr, '/') != NULL) + { + fd_ = acl_unix_listen(addr, backlog_, block_ + ? ACL_BLOCKING : ACL_NON_BLOCKING); + unix_sock_ = true; + } + else +#endif + fd_ = acl_inet_listen(addr, backlog_, block_ + ? ACL_BLOCKING : ACL_NON_BLOCKING); + + if (fd_ == ACL_SOCKET_INVALID) + { + logger_error("listen %s error %s", addr, last_serror()); + unix_sock_ = false; + return false; + } + + return true; +} + +bool server_socket::close() +{ + if (fd_ == ACL_SOCKET_INVALID) + return true; + bool ret = acl_socket_close(fd_) == 0 ? true : false; + fd_ = ACL_SOCKET_INVALID; + addr_[0] = 0; + return ret; +} + +socket_stream* server_socket::accept(int timeout /* = 0 */) +{ + if (fd_ == ACL_SOCKET_INVALID) + { + logger_error("server socket not opened!"); + return NULL; + } + + if (block_ && timeout > 0) + { + if (acl_read_wait(fd_, timeout) == -1) + return NULL; + } + + ACL_SOCKET fd = acl_accept(fd_, NULL, 0, NULL); + if (fd == ACL_SOCKET_INVALID) + { + if (block_) + logger_error("accept error %s", last_serror()); + else if (last_error() != ACL_EAGAIN + && last_error() != ACL_EWOULDBLOCK) + { + logger_error("accept error %s", last_serror()); + } + return NULL; + } + + socket_stream* client = new socket_stream(); + if (client->open(fd) == false) + { + logger_error("create socket_stream error!"); + return NULL; + } + + if (!unix_sock_) + acl_tcp_set_nodelay(fd); + + return client; +} + +} // namespace acl diff --git a/lib_acl_cpp/src/stream/socket_stream.cpp b/lib_acl_cpp/src/stream/socket_stream.cpp new file mode 100644 index 000000000..b07c43d1b --- /dev/null +++ b/lib_acl_cpp/src/stream/socket_stream.cpp @@ -0,0 +1,184 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/stream/socket_stream.hpp" + +namespace acl { + +socket_stream::socket_stream() +{ + dummy_[0] = 0; + peer_ip_[0] = 0; + local_ip_[0] = 0; +} + +socket_stream::~socket_stream() +{ + close(); +} + +bool socket_stream::open(ACL_SOCKET fd) +{ + ACL_VSTREAM* conn = acl_vstream_fdopen(fd, O_RDWR, + 8192, 0, ACL_VSTREAM_TYPE_SOCK); + acl_assert(conn); + return open(conn); +} + +bool socket_stream::open(const char* addr, int conn_timeout, int rw_timeout) +{ + ACL_VSTREAM* conn = acl_vstream_connect(addr, ACL_BLOCKING, + conn_timeout, rw_timeout, 8192); + if (conn == NULL) + return false; + + return open(conn); +} + +bool socket_stream::open(ACL_VSTREAM* vstream) +{ + // 先关闭旧的流对象 + if (m_pStream) + acl_vstream_close(m_pStream); + m_pStream = vstream; + m_bEof = false; + m_bOpened = true; + //acl_tcp_set_nodelay(ACL_VSTREAM_SOCK(vstream)); + return true; +} + +bool socket_stream::close() +{ + if (m_bOpened == false) + return false; + if (m_pStream == NULL) + return true; + + m_bEof = true; + m_bOpened = false; + + int ret = acl_vstream_close(m_pStream); + m_pStream = NULL; + + return (ret == 0 ? true : false); +} + +ACL_SOCKET socket_stream::sock_handle() const +{ + if (m_pStream == NULL) + return ACL_SOCKET_INVALID; + return ACL_VSTREAM_SOCK(m_pStream); +} + +ACL_SOCKET socket_stream::unbind_sock() +{ + if (m_pStream == NULL) + return ACL_SOCKET_INVALID; + ACL_SOCKET sock = ACL_VSTREAM_SOCK(m_pStream); + m_pStream->fd.sock = ACL_SOCKET_INVALID; + m_bEof = true; + m_bOpened = false; + return sock; +} + +const char* socket_stream::get_peer(bool full /* = false */) const +{ + if (m_pStream == NULL) + { + const_cast (this)->dummy_[0] = 0; + return dummy_; + } + + // xxx: acl_vstream 中没有对此地址赋值 + if (m_pStream->remote_addr[0] == 0) + { + if (acl_getpeername(ACL_VSTREAM_SOCK(m_pStream), + m_pStream->remote_addr, + sizeof(m_pStream->remote_addr)) == -1) + { + return dummy_; + } + } + + if (full) + return ACL_VSTREAM_PEER(m_pStream); + else + return get_peer_ip(); +} + +const char* socket_stream::get_peer_ip() const +{ + if (peer_ip_[0] != 0) + return peer_ip_; + + if (m_pStream->remote_addr[0] == 0) + { + if (acl_getpeername(ACL_VSTREAM_SOCK(m_pStream), + m_pStream->remote_addr, + sizeof(m_pStream->remote_addr)) == -1) + { + return dummy_; + } + } + + return const_cast (this)->get_ip( + m_pStream->remote_addr, + const_cast (this)->peer_ip_, + sizeof(peer_ip_)); +} + +const char* socket_stream::get_local(bool full /* = false */) const +{ + if (m_pStream == NULL) + { + const_cast (this)->dummy_[0] = 0; + return dummy_; + } + + // xxx: acl_vstream 中没有对此地址赋值 + if (m_pStream->local_addr[0] == 0) + { + if (acl_getsockname(ACL_VSTREAM_SOCK(m_pStream), + m_pStream->local_addr, + sizeof(m_pStream->local_addr)) == -1) + { + return dummy_; + } + } + + if (full) + return ACL_VSTREAM_LOCAL(m_pStream); + else + return get_local_ip(); +} + +const char* socket_stream::get_local_ip() const +{ + if (local_ip_[0] != 0) + return local_ip_; + + if (m_pStream->local_addr[0] == 0) + { + if (acl_getsockname(ACL_VSTREAM_SOCK(m_pStream), + m_pStream->local_addr, + sizeof(m_pStream->local_addr)) == -1) + { + return dummy_; + } + } + + return const_cast(this)->get_ip( + ACL_VSTREAM_LOCAL(m_pStream), + const_cast(this)->local_ip_, + sizeof(local_ip_)); +} + +const char* socket_stream::get_ip(const char* addr, char* buf, size_t size) +{ + snprintf(buf, size, "%s", addr); + char* ptr = strchr(buf, ':'); + if (ptr) + *ptr = 0; + return buf; +} + +} // namespace acl diff --git a/lib_acl_cpp/src/stream/ssl_aio_stream.cpp b/lib_acl_cpp/src/stream/ssl_aio_stream.cpp new file mode 100644 index 000000000..5cbec54c3 --- /dev/null +++ b/lib_acl_cpp/src/stream/ssl_aio_stream.cpp @@ -0,0 +1,336 @@ +#include "acl_stdafx.hpp" +#include "polarssl/ssl.h" +#include "polarssl/havege.h" +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/stream/ssl_aio_stream.hpp" + +//#ifndef HAS_POLARSSL +//#define HAS_POLARSSL +//#endif + +namespace acl +{ + +ssl_aio_stream::ssl_aio_stream(aio_handle* handle, ACL_ASTREAM* stream, + bool opened /* = false */, bool use_ssl /* = true */) +: aio_stream(handle), aio_socket_stream(handle, stream, opened) +{ +#ifdef HAS_POLARSSL + if (use_ssl) + { + ssl_ = (ssl_context*) acl_mycalloc(1, sizeof(ssl_context)); + ssn_ = (ssl_session*) acl_mycalloc(1, sizeof(ssl_session)); + hs_ = acl_mymalloc(sizeof(havege_state)); + } + else + { + ssl_ = NULL; + ssn_ = NULL; + hs_ = NULL; + } +#else + (void) use_ssl; +#endif +} + +ssl_aio_stream::ssl_aio_stream(aio_handle* handle, ACL_SOCKET fd, + bool use_ssl /* = true */) +: aio_stream(handle), aio_socket_stream(handle, fd) +{ +#ifdef HAS_POLARSSL + if (use_ssl) + { + ssl_ = (ssl_context*) acl_mycalloc(1, sizeof(ssl_context)); + ssn_ = (ssl_session*) acl_mycalloc(1, sizeof(ssl_session)); + hs_ = acl_mymalloc(sizeof(havege_state)); + } + else + { + ssl_ = NULL; + ssn_ = NULL; + hs_ = NULL; + } +#else + (void) use_ssl; +#endif +} + +ssl_aio_stream::~ssl_aio_stream() +{ + clear(); +} + +void ssl_aio_stream::clear() +{ +#ifdef HAS_POLARSSL + if (ssl_) + { + ssl_free(ssl_); + acl_myfree(ssl_); + ssl_ = NULL; + } + if (ssn_) + { + acl_myfree(ssn_); + ssn_ = NULL; + } + if (hs_) + { + acl_myfree(hs_); + hs_ = NULL; + } +#endif +} + +bool ssl_aio_stream::open_callback() +{ +#ifdef HAS_POLARSSL + if (ssl_) + { + acl_assert(ssn_); + acl_assert(hs_); + return (ssl_client_init()); + } + return (true); +#else + return (false); +#endif +} + +ssl_aio_stream* ssl_aio_stream::open(aio_handle* handle, + const char* addr, int timeout, bool use_ssl /* = true */) +{ + acl_assert(handle); + + ACL_ASTREAM* astream = + acl_aio_connect(handle->get_handle(), addr, timeout); + if (astream == NULL) + return (NULL); + + ssl_aio_stream* stream = NEW ssl_aio_stream(handle, astream, false); + + // 调用基类的 hook_error 以向 handle 中增加异步流计数, + // 同时 hook 关闭及超时回调过程 + stream->hook_error(); + // hook 连接成功的回调过程 + stream->hook_open(); + + // 如果是使用SSL,则注册本类对象为连接成功后的第一个回调过程 + if (use_ssl) + stream->add_open_callback(stream); + + return (stream); +} + +bool ssl_aio_stream::open_ssl(bool on) +{ + ACL_VSTREAM* stream = get_vstream(); + acl_assert(stream); + + if (stream == NULL) + { + logger_error("stream null"); + return (false); + } + + if (on) + { +#ifdef HAS_POLARSSL + // 如果打开已经是 SSL 模式的流,则直接返回 + if (ssl_ != NULL) + { + acl_assert(ssn_); + acl_assert(hs_); + return (true); + } +#endif + + // 打开 SSL 流模式 + return (ssl_client_init()); + } + else + { +#ifdef HAS_POLARSSL + // 如果关闭非 SSL 模式的流,则直接返回 + if (ssl_ == NULL) + { + ssl_ = NULL; + acl_assert(ssn_ == NULL); + acl_assert(hs_ == NULL); + return (true); + } +#endif + + // 清除与 SSL 相关的对象 + clear(); + + // 切换成非 SSL 流模式 + acl_vstream_ctl(stream, + ACL_VSTREAM_CTL_READ_FN, acl_socket_read, + ACL_VSTREAM_CTL_WRITE_FN, acl_socket_write, + ACL_VSTREAM_CTL_CTX, this, + ACL_VSTREAM_CTL_END); + return (true); + } +} + +bool ssl_aio_stream::ssl_client_init() +{ +#ifdef HAS_POLARSSL + ACL_VSTREAM* stream = get_vstream(); + acl_assert(stream); + + // 0. Initialize the RNG and the session data + havege_init((havege_state*) hs_); + + int ret; + if ((ret = ssl_init(ssl_)) != 0) + { + logger_error("failed, ssl_init returned %d", ret); + return (false); + } + + ssl_set_endpoint(ssl_, SSL_IS_CLIENT); + ssl_set_authmode(ssl_, SSL_VERIFY_NONE); + + ssl_set_rng(ssl_, ::havege_random, hs_); + //ssl_set_dbg(ssl_, my_debug, stdout); + ssl_set_bio(ssl_, __read, this, __send, this); + + ssl_set_ciphersuites(ssl_, ssl_default_ciphersuites); + ssl_set_session(ssl_, 1, 600, ssn_); + + acl_vstream_ctl(stream, + ACL_VSTREAM_CTL_READ_FN, __ssl_read, + ACL_VSTREAM_CTL_WRITE_FN, __ssl_send, + ACL_VSTREAM_CTL_CTX, this, + ACL_VSTREAM_CTL_END); + acl_tcp_set_nodelay(ACL_VSTREAM_SOCK(stream)); +#endif + return (true); +} + +int ssl_aio_stream::__read(void *ctx, unsigned char *buf, size_t len) +{ +#ifdef HAS_POLARSSL + ssl_aio_stream* cli = (ssl_aio_stream*) ctx; + ACL_VSTREAM* stream = cli->get_vstream(); + acl_assert(stream); + ACL_SOCKET fd = ACL_VSTREAM_SOCK(stream); + int ret, errnum; + + if ((ret = acl_socket_read(fd, buf, len, 0, NULL)) < 0) + { + errnum = acl_last_error(); + if (errnum == ACL_EINTR) + return (POLARSSL_ERR_NET_WANT_READ); + else if (errnum == ACL_EWOULDBLOCK) + return (POLARSSL_ERR_NET_WANT_READ); +#if ACL_EWOULDBLOCK != ACL_EAGAIN + else if (errnum == ACL_EAGAIN) + return (POLARSSL_ERR_NET_WANT_READ); +#endif + else if (errnum == ACL_ECONNRESET || errno == EPIPE) + return (POLARSSL_ERR_NET_CONN_RESET); + else + return (POLARSSL_ERR_NET_RECV_FAILED); + } + + return (ret); +#else + (void) ctx; + (void) buf; + (void) len; + return (-1); +#endif +} + +int ssl_aio_stream::__send(void *ctx, const unsigned char *buf, size_t len) +{ +#ifdef HAS_POLARSSL + ssl_aio_stream* cli = (ssl_aio_stream*) ctx; + ACL_VSTREAM* stream = cli->get_vstream(); + acl_assert(stream); + ACL_SOCKET fd = ACL_VSTREAM_SOCK(stream); + int ret, errnum; + + if ((ret = acl_socket_write(fd, buf, len, 0, NULL)) < 0) + { + errnum = acl_last_error(); + if (errnum == ACL_EINTR) + return (POLARSSL_ERR_NET_WANT_WRITE); + + else if (errnum == ACL_EWOULDBLOCK) + return (POLARSSL_ERR_NET_WANT_WRITE); +#if ACL_EWOULDBLOCK != ACL_EAGAIN + else if (errnum == ACL_EAGAIN) + return (POLARSSL_ERR_NET_WANT_WRITE); +#endif + else if (errnum == ACL_ECONNRESET || errno == EPIPE) + return (POLARSSL_ERR_NET_CONN_RESET); + else + return (POLARSSL_ERR_NET_SEND_FAILED); + } + + return (ret); +#else + (void) ctx; + (void) buf; + (void) len; + return (-1); +#endif +} + +int ssl_aio_stream::__ssl_read(ACL_SOCKET fd acl_unused, void *buf, + size_t len, int timeout acl_unused, void *ctx) +{ +#ifdef HAS_POLARSSL + ssl_aio_stream* cli = (ssl_aio_stream*) ctx; + int ret; + + while ((ret = ::ssl_read(cli->ssl_, (unsigned char*) buf, len)) <= 0) + { + if (ret == POLARSSL_ERR_NET_WANT_READ + || ret == POLARSSL_ERR_NET_WANT_WRITE) + { + if (acl_last_error() != ACL_EWOULDBLOCK) + acl_set_error(ACL_EWOULDBLOCK); + } + return (ACL_VSTREAM_EOF); + } + return (ret); +#else + (void) buf; + (void) len; + (void) ctx; + return (-1); +#endif +} + +int ssl_aio_stream::__ssl_send(ACL_SOCKET fd acl_unused, const void *buf, + size_t len, int timeout acl_unused, void *ctx) +{ +#ifdef HAS_POLARSSL + ssl_aio_stream* cli = (ssl_aio_stream*) ctx; + int ret; + + while ((ret = ::ssl_write(cli->ssl_, (unsigned char*) buf, len)) <= 0) + { + if (ret == POLARSSL_ERR_NET_WANT_READ + || ret == POLARSSL_ERR_NET_WANT_WRITE) + { + if (acl_last_error() != ACL_EWOULDBLOCK) + acl_set_error(ACL_EWOULDBLOCK); + } + return (ACL_VSTREAM_EOF); + } + return (ret); +#else + (void) buf; + (void) len; + (void) ctx; + return (-1); +#endif +} + +} // namespace acl diff --git a/lib_acl_cpp/src/stream/ssl_stream.cpp b/lib_acl_cpp/src/stream/ssl_stream.cpp new file mode 100644 index 000000000..f8dd7b4e4 --- /dev/null +++ b/lib_acl_cpp/src/stream/ssl_stream.cpp @@ -0,0 +1,287 @@ +#include "acl_stdafx.hpp" +#include "polarssl/ssl.h" +#include "polarssl/havege.h" +#include "acl_cpp/stdlib/log.hpp" +#include "acl_cpp/stream/ssl_stream.hpp" + +//#ifndef HAS_POLARSSL +//#define HAS_POLARSSL +//#endif + +namespace acl +{ + +ssl_stream::ssl_stream(void) +#ifdef HAS_POLARSSL +: ssl_(NULL) +, ssn_(NULL) +, hs_(NULL) +#endif +{ + +} + +ssl_stream::~ssl_stream(void) +{ + clear(); +} + +void ssl_stream::clear(void) +{ +#ifdef HAS_POLARSSL + if (ssl_) + { + ssl_free(ssl_); + acl_myfree(ssl_); + ssl_ = NULL; + } + if (ssn_) + { + acl_myfree(ssn_); + ssn_ = NULL; + } + if (hs_) + { + acl_myfree(hs_); + hs_ = NULL; + } +#endif +} + +bool ssl_stream::open_ssl(ACL_SOCKET fd, bool use_ssl /* = true */) +{ + ACL_VSTREAM* conn = acl_vstream_fdopen(fd, O_RDWR, + 8192, 0, ACL_VSTREAM_TYPE_SOCK); + acl_assert(conn); + return (open_ssl(conn, use_ssl)); +} + +bool ssl_stream::open_ssl(const char* addr, int conn_timeout, + int rw_timeout, bool use_ssl /* = true */) +{ + ACL_VSTREAM* conn = acl_vstream_connect(addr, ACL_BLOCKING, + conn_timeout, rw_timeout, 8192); + if (conn == NULL) + return (false); + return (open_ssl(conn, use_ssl)); +} + +bool ssl_stream::open_ssl(ACL_VSTREAM* vstream, bool use_ssl /* = true */) +{ + bool ret = open(vstream); + acl_assert(ret); + + if (use_ssl && ssl_client_init() == false) + { + (void) this->close(); + return (false); + } + + return (true); +} + +bool ssl_stream::open_ssl(bool on) +{ + if (m_pStream == NULL) + { + logger_error("m_pStream null"); + return (false); + } + + if (on) + { +#ifdef HAS_POLARSSL + // 如果打开已经是 SSL 模式的流,则直接返回 + if (ssl_ != NULL) + { + acl_assert(ssn_); + acl_assert(hs_); + return (true); + } +#endif + + // 打开 SSL 流模式 + return (ssl_client_init()); + } + else + { +#ifdef HAS_POLARSSL + // 如果关闭非 SSL 模式的流,则直接返回 + if (ssl_ == NULL) + { + ssl_ = NULL; + acl_assert(ssn_ == NULL); + acl_assert(hs_ == NULL); + return (true); + } +#endif + + // 清除与 SSL 相关的对象 + clear(); + + // 切换成非 SSL 流模式 + acl_vstream_ctl(m_pStream, + ACL_VSTREAM_CTL_READ_FN, acl_socket_read, + ACL_VSTREAM_CTL_WRITE_FN, acl_socket_write, + ACL_VSTREAM_CTL_CTX, this, + ACL_VSTREAM_CTL_END); + return (true); + } +} + +bool ssl_stream::ssl_client_init() +{ + acl_assert(m_pStream); + +#ifdef HAS_POLARSSL + ssl_ = (ssl_context*) acl_mycalloc(1, sizeof(ssl_context)); + ssn_ = (ssl_session*) acl_mycalloc(1, sizeof(ssl_session)); + hs_ = (havege_state*) acl_mymalloc(sizeof(havege_state)); + + // 0. Initialize the RNG and the session data + havege_init((havege_state*) hs_); + + int ret; + if ((ret = ssl_init(ssl_)) != 0) + { + logger_error("failed, ssl_init returned %d", ret); + return (false); + } + + ssl_set_endpoint(ssl_, SSL_IS_CLIENT); + ssl_set_authmode(ssl_, SSL_VERIFY_NONE); + + ssl_set_rng(ssl_, havege_random, hs_); + //ssl_set_dbg(ssl_, my_debug, stdout); + ssl_set_bio(ssl_, __read, this, __send, this); + + ssl_set_ciphersuites(ssl_, ssl_default_ciphersuites); + ssl_set_session(ssl_, 1, 600, ssn_); + + acl_vstream_ctl(m_pStream, + ACL_VSTREAM_CTL_READ_FN, __ssl_read, + ACL_VSTREAM_CTL_WRITE_FN, __ssl_send, + ACL_VSTREAM_CTL_CTX, this, + ACL_VSTREAM_CTL_END); + acl_tcp_set_nodelay(ACL_VSTREAM_SOCK(m_pStream)); +#endif + return (true); +} + +int ssl_stream::__read(void *ctx, unsigned char *buf, size_t len) +{ +#ifdef HAS_POLARSSL + ssl_stream* cli = (ssl_stream*) ctx; + ACL_VSTREAM* stream = cli->get_vstream(); + acl_assert(stream); + ACL_SOCKET fd = ACL_VSTREAM_SOCK(stream); + int ret, timeout = 120; + + if ((ret = acl_socket_read(fd, buf, len, timeout, NULL)) < 0) + { + int errnum = acl_last_error(); + if (ret == ACL_EINTR || ret == ACL_EWOULDBLOCK +#if ACL_EWOULDBLOCK != ACL_EAGAIN + || ret == ACL_EAGAIN +#endif + ) + return (POLARSSL_ERR_NET_WANT_READ); + else if (errnum == ACL_ECONNRESET || errno == EPIPE) + return (POLARSSL_ERR_NET_CONN_RESET); + else + return (POLARSSL_ERR_NET_RECV_FAILED); + } + + return (ret); +#else + (void) ctx; + (void) buf; + (void) len; + return (-1); +#endif +} + +int ssl_stream::__send(void *ctx, const unsigned char *buf, size_t len) +{ +#ifdef HAS_POLARSSL + ssl_stream* cli = (ssl_stream*) ctx; + ACL_VSTREAM* stream = cli->get_vstream(); + acl_assert(stream); + ACL_SOCKET fd = ACL_VSTREAM_SOCK(stream); + int ret, timeout = 120; + + if ((ret = acl_socket_write(fd, buf, len, timeout, NULL)) < 0) + { + int errnum = acl_last_error(); + if (ret == ACL_EINTR || ret == ACL_EWOULDBLOCK +#if ACL_EWOULDBLOCK != ACL_EAGAIN + || ret == ACL_EAGAIN +#endif + ) + return (POLARSSL_ERR_NET_WANT_WRITE); + else if (errnum == ACL_ECONNRESET || errno == EPIPE) + return (POLARSSL_ERR_NET_CONN_RESET); + else + return (POLARSSL_ERR_NET_SEND_FAILED); + } + + return (ret); +#else + (void) ctx; + (void) buf; + (void) len; + return (-1); +#endif +} + +int ssl_stream::__ssl_read(ACL_SOCKET fd acl_unused, void *buf, size_t len, + int timeout acl_unused, void *ctx) +{ +#ifdef HAS_POLARSSL + ssl_stream* cli = (ssl_stream*) ctx; + int ret; + + while ((ret = ::ssl_read(cli->ssl_, (unsigned char*) buf, len)) < 0) + { + if (ret != POLARSSL_ERR_NET_WANT_READ + && ret != POLARSSL_ERR_NET_WANT_WRITE) + { + return (ACL_VSTREAM_EOF); + } + } + + return (ret); +#else + (void) buf; + (void) len; + (void) ctx; + return (-1); +#endif +} + +int ssl_stream::__ssl_send(ACL_SOCKET fd acl_unused, const void *buf, size_t len, + int timeout acl_unused, void *ctx) +{ +#ifdef HAS_POLARSSL + ssl_stream* cli = (ssl_stream*) ctx; + int ret; + + while ((ret = ::ssl_write(cli->ssl_, (unsigned char*) buf, len)) < 0) + { + if (ret != POLARSSL_ERR_NET_WANT_READ + && ret != POLARSSL_ERR_NET_WANT_WRITE) + { + return (ACL_VSTREAM_EOF); + } + } + + return (ret); +#else + (void) buf; + (void) len; + (void) ctx; + return (-1); +#endif +} + +} // namespace acl diff --git a/lib_acl_cpp/src/stream/stream.cpp b/lib_acl_cpp/src/stream/stream.cpp new file mode 100644 index 000000000..058683ccb --- /dev/null +++ b/lib_acl_cpp/src/stream/stream.cpp @@ -0,0 +1,83 @@ +#include "acl_stdafx.hpp" +#include "acl_cpp/stream/stream.hpp" + +namespace acl { + +stream::stream(void) + : m_pStream(NULL) + , m_bEof(true) + , m_bOpened(false) + , ctx_(NULL) +{ + open_stream(); +} + +stream::~stream(void) +{ + if (m_pStream) + acl_vstream_free(m_pStream); +} + +bool stream::eof(void) const +{ + return (m_bEof); +} + +bool stream::opened(void) const +{ + return (m_bOpened); +} + +ACL_VSTREAM* stream::get_vstream() const +{ + return (m_pStream); +} + +void stream::set_rw_timeout(int n) +{ + if (m_pStream) + m_pStream->rw_timeout = n; +} + +int stream::get_rw_timeout() const +{ + if (m_pStream == NULL) + return -1; + return m_pStream->rw_timeout; +} + +ACL_VSTREAM* stream::unbind() +{ + m_bEof = true; + m_bOpened = false; + ACL_VSTREAM* vstream = m_pStream; + m_pStream = NULL; + return vstream; +} + +void stream::open_stream(void) +{ + if (m_pStream != NULL) + return; + m_pStream = acl_vstream_fdopen(ACL_SOCKET_INVALID, O_RDWR, + 8192, 0, ACL_VSTREAM_TYPE_SOCK); +} + +void stream::reopen_stream(void) +{ + if (m_pStream) + acl_vstream_free(m_pStream); + open_stream(); +} + +void stream::set_ctx(void* ctx) +{ + ctx_ = ctx; +} + +void* stream::get_ctx() const +{ + return (ctx_); +} + +} // namespace acl diff --git a/lib_acl_cpp/todo.txt b/lib_acl_cpp/todo.txt new file mode 100644 index 000000000..e5832d823 --- /dev/null +++ b/lib_acl_cpp/todo.txt @@ -0,0 +1,25 @@ +需要改进的内容列表: +1) hsclient.cpp: 其中的 unescape() 函数需要再优化一下 +2) hsclient.cpp: 当因为网络连接而失败,最好能提供重试功能 +3) winaio: 该工程只能在 DebugDll 和 ReleaseDll 下编译,不能在 Debug 和 Release 下编译, +原因是在 Debug/Release 编译时, lib_acl_cpp 以采用 /MTd 或 /MT 方式编译的,VC 会报依赖 +库中的函数冲突错误,所以为解决此问题,只能是将 Debug/Release 的编译方式同 DebugDll/ReleaseDll +一样的编译条件进行编译才能通过 +4) db_mysql.cpp: 在 WIN32 下还不能使用,需要找到 VC2003 版本的 libmysql.lib/libmysql.dll +5) 需要支持 c++ 版本的 acl_master 服务器框架: 2012.1.10, 已经完成此项功能!,并且发布了新的版本号 -- ok +6) zlib_stream.cpp: 还需要支持 gzip 的压缩,deflate 带头的方式 +7) string.cpp: space(size_t) 似乎有点问题 +8) zlib 库有一片BUG,在用 valgrind 检查时发现在 longest_match 函数中有未初始化使用的参数,参考文章: +http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=270070 +该BUG应该是在 zlib-1.2.5.1 版本中得到修复 +9) json/xml 两个库在使用 append 方法创建 json/xml 对象时,结点的显示顺序与创建时的不太一致 +10) http: 还需要增加网页模板库,才能完全支持所有的 WEB 应用开发 +11) db: 数据库部分还需要增加字段转义功能,以防止 SQL 注入攻击,已经在 db_handle 增加了字符转义功能, +---ok, zsx, 2012.6.1 +12) http 中的 WEB 编程模块应该支持 FCGI 模式 +13) session 应该增加一个 session_pool +14) 整合 thrift/buffer 协议到 acl_master 服务器框架中 +15) 应支持 redis 客户端协议 +16) 能支持 mysql 协议到 mongodb 协议的转换协议实现 +17) HttpServlet 支持 FCGI +18) mime 解析库针对 7BIT 格式兼容性支持 diff --git a/lib_dict/Makefile b/lib_dict/Makefile new file mode 100644 index 000000000..255ea219d --- /dev/null +++ b/lib_dict/Makefile @@ -0,0 +1,134 @@ +SHELL = /bin/sh +CC = gcc +#CC = g++ +CC = ${MY_ENV_CC} +AR = ar +ARFL = rv +#ARFL = cru +RANLIB = ranlib + +#CFLAGS = -c -g -W -Wall -Wcast-qual -Wcast-align \ +#-Waggregate-return -Wmissing-prototypes \ +#-Wpointer-arith -Werror -Wshadow -O2 \ +#-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO \ +#-Wno-long-long -DHAS_DB + +CFLAGS = -c -g -W -Wall -Wcast-align \ +-Waggregate-return -Wmissing-prototypes \ +-Wpointer-arith -Werror -Wshadow -O2 \ +-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO \ +-Wno-long-long \ +-fPIC +#CFLAGS = -c -g -W -Wall -Wcast-qual -Wcast-align \ +#-Waggregate-return -Wmissing-prototypes \ +#-Wpointer-arith -Werror -Wshadow -O2 \ +#-D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO +########################################################### +#Check system: +# Linux, SunOS, Solaris, BSD variants, AIX, HP-UX +SYSLIB = +CHECKSYSRES = @echo "Unknow system type!";exit 1 +UNIXNAME = $(shell uname -sm) + +ifeq ($(CC),) + CC = gcc +endif + +# For FreeBSD +ifeq ($(findstring FreeBSD, $(UNIXNAME)), FreeBSD) + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DFREEBSD -D_REENTRANT -pedantic +endif + +# For Linux +ifeq ($(findstring Linux, $(UNIXNAME)), Linux) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DLINUX2 -D_REENTRANT -pedantic +endif + +# For SunOS +ifeq ($(findstring SunOS, $(UNIXNAME)), SunOS) + ifeq ($(findstring 86, $(UNIXNAME)), 86) + SYSLIB = -lsocket -lnsl -lrt + endif + ifeq ($(findstring sun4u, $(UNIXNAME)), sun4u) + SYSLIB = -lsocket -lnsl -lrt + endif + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DSUNOS5 -D_REENTRANT -pedantic +endif + +# For HP-UX +ifeq ($(findstring HP-UX, $(UNIXNAME)), HP-UX) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DHP_UX -DHPUX11 + PLAT_NAME=hp-ux +endif + +#Find system type. +ifneq ($(SYSPATH),) + CHECKSYSRES = @echo "System is $(shell uname -sm)" +endif +########################################################### + +OUT_PATH = . +OBJ_PATH_DST = $(OUT_PATH)/debug +LIB_PATH_DST = $(OUT_PATH)/lib + +BASE_PATH = . +INC_PATH_SRC = $(BASE_PATH)/include +SRC_PATH_SRC = $(BASE_PATH)/src + +INC_COMPILE = -I$(INC_PATH_SRC) -I./cdb/include -I./tc/include +CFLAGS += $(INC_COMPILE) -DHAS_BDB +#CFLAGS += $(INC_COMPILE) +#CFLAGS += $(INC_COMPILE) -DHAS_DB -DHAS_TC -DHAS_CDB + +#Project's objs +DICT_SRC = $(wildcard $(SRC_PATH_SRC)/*.c) +SOURCES_SRC = $(DICT_SRC) + +DICT_OBJ = $(patsubst %.c, $(OBJ_PATH_DST)/%.o, $(notdir $(DICT_SRC))) +OBJS_DST = $(DICT_OBJ) + +########################################################### +ACL_PATH = ../lib_acl +ACL_INC = $(ACL_PATH)/include + +CFLAGS += -I $(ACL_INC) + +########################################################### + +LIB_NAME = lib_dict.a + +.PHONY = clean +COMPILE = $(CC) $(CFLAGS) + +all: $(LIB_NAME) + +$(shell mkdir -p $(OBJ_PATH_DST)) + +$(LIB_NAME): $(OBJS_DST) + $(AR) $(ARFL) $(LIB_PATH_DST)/$(LIB_NAME) $(OBJS_DST) + $(RANLIB) $(LIB_PATH_DST)/$(LIB_NAME) + +# dict +$(OBJ_PATH_DST)/%.o: $(SRC_PATH_SRC)/%.c + $(COMPILE) $< -o $@ + +# icmp +$(OBJ_PATH_DST)/%.o: $(SRC_PATH_SRC)/icmp/%.c + $(COMPILE) $< -o $@ + +clean: + rm -f $(LIB_PATH_DST)/$(LIB_NAME) + rm -f $(OBJS_DST) + diff --git a/lib_dict/ReadMe.txt b/lib_dict/ReadMe.txt new file mode 100644 index 000000000..9f72bab4b --- /dev/null +++ b/lib_dict/ReadMe.txt @@ -0,0 +1,20 @@ +======================================================================== + 静态库 : lib_dict 项目概况 +======================================================================== + +应用程序向导已为您创建了这个 lib_dict 库项目。 +没有任何源文件被创建为项目的一部分。 + + +lib_dict.vcproj + 这是用应用程序向导生成的 VC++ 项目的主项目文件。 + 它包含有关生成此文件的 Visual C++ 版本的信息,以及 + 有关用应用程序向导选择的 + 平台、配置和项目功能的信息。 + +///////////////////////////////////////////////////////////////////////////// +其他注释: + +应用程序向导使用 "TODO:" 注释指示应添加或自定义的源代码部分。 + +///////////////////////////////////////////////////////////////////////////// diff --git a/lib_dict/bdb/include/btree.h b/lib_dict/bdb/include/btree.h new file mode 100644 index 000000000..d6bb2c839 --- /dev/null +++ b/lib_dict/bdb/include/btree.h @@ -0,0 +1,321 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996-2004 + * Sleepycat Software. All rights reserved. + */ +/* + * Copyright (c) 1990, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + */ +/* + * Copyright (c) 1990, 1993, 1994, 1995 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Mike Olson. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: btree.h,v 11.50 2004/07/22 21:52:57 bostic Exp $ + */ +#ifndef _DB_BTREE_H_ +#define _DB_BTREE_H_ + +/* Forward structure declarations. */ +struct __btree; typedef struct __btree BTREE; +struct __cursor; typedef struct __cursor BTREE_CURSOR; +struct __epg; typedef struct __epg EPG; +struct __recno; typedef struct __recno RECNO; + +#define DEFMINKEYPAGE (2) + +/* + * A recno order of 0 indicates that we don't have an order, not that we've + * an order less than 1. + */ +#define INVALID_ORDER 0 + +#define ISINTERNAL(p) (TYPE(p) == P_IBTREE || TYPE(p) == P_IRECNO) +#define ISLEAF(p) (TYPE(p) == P_LBTREE || \ + TYPE(p) == P_LRECNO || TYPE(p) == P_LDUP) + +/* Flags for __bam_cadjust_log(). */ +#define CAD_UPDATEROOT 0x01 /* Root page count was updated. */ + +/* Flags for __bam_split_log(). */ +#define SPL_NRECS 0x01 /* Split tree has record count. */ + +/* Flags for __bam_iitem(). */ +#define BI_DELETED 0x01 /* Key/data pair only placeholder. */ + +/* Flags for __bam_stkrel(). */ +#define STK_CLRDBC 0x01 /* Clear dbc->page reference. */ +#define STK_NOLOCK 0x02 /* Don't retain locks. */ + +/* Flags for __ram_ca(). These get logged, so make the values explicit. */ +typedef enum { + CA_DELETE = 0, /* Delete the current record. */ + CA_IAFTER = 1, /* Insert before the current record. */ + CA_IBEFORE = 2, /* Insert after the current record. */ + CA_ICURRENT = 3 /* Overwrite the current record. */ +} ca_recno_arg; + +/* + * Flags for __bam_search() and __bam_rsearch(). + * + * Note, internal page searches must find the largest record less than key in + * the tree so that descents work. Leaf page searches must find the smallest + * record greater than key so that the returned index is the record's correct + * position for insertion. + * + * The flags parameter to the search routines describes three aspects of the + * search: the type of locking required (including if we're locking a pair of + * pages), the item to return in the presence of duplicates and whether or not + * to return deleted entries. To simplify both the mnemonic representation + * and the code that checks for various cases, we construct a set of bitmasks. + */ +#define S_READ 0x00001 /* Read locks. */ +#define S_WRITE 0x00002 /* Write locks. */ + +#define S_APPEND 0x00040 /* Append to the tree. */ +#define S_DELNO 0x00080 /* Don't return deleted items. */ +#define S_DUPFIRST 0x00100 /* Return first duplicate. */ +#define S_DUPLAST 0x00200 /* Return last duplicate. */ +#define S_EXACT 0x00400 /* Exact items only. */ +#define S_PARENT 0x00800 /* Lock page pair. */ +#define S_STACK 0x01000 /* Need a complete stack. */ +#define S_PAST_EOF 0x02000 /* If doing insert search (or keyfirst + * or keylast operations), or a split + * on behalf of an insert, it's okay to + * return an entry one past end-of-page. + */ +#define S_STK_ONLY 0x04000 /* Just return info in the stack */ + +#define S_DELETE (S_WRITE | S_DUPFIRST | S_DELNO | S_EXACT | S_STACK) +#define S_FIND (S_READ | S_DUPFIRST | S_DELNO) +#define S_FIND_WR (S_WRITE | S_DUPFIRST | S_DELNO) +#define S_INSERT (S_WRITE | S_DUPLAST | S_PAST_EOF | S_STACK) +#define S_KEYFIRST (S_WRITE | S_DUPFIRST | S_PAST_EOF | S_STACK) +#define S_KEYLAST (S_WRITE | S_DUPLAST | S_PAST_EOF | S_STACK) +#define S_WRPAIR (S_WRITE | S_DUPLAST | S_PAST_EOF | S_PARENT) + +/* + * Various routines pass around page references. A page reference is + * a pointer to the page, and the indx indicates an item on the page. + * Each page reference may include a lock. + */ +struct __epg { + PAGE *page; /* The page. */ + db_indx_t indx; /* The index on the page. */ + db_indx_t entries; /* The number of entries on page */ + DB_LOCK lock; /* The page's lock. */ + db_lockmode_t lock_mode; /* The lock mode. */ +}; + +/* + * We maintain a stack of the pages that we're locking in the tree. Grow + * the stack as necessary. + * + * XXX + * Temporary fix for #3243 -- clear the page and lock from the stack entry. + * The correct fix is to never release a stack that doesn't hold items. + */ +#define BT_STK_CLR(c) do { \ + (c)->csp = (c)->sp; \ + (c)->csp->page = NULL; \ + LOCK_INIT((c)->csp->lock); \ +} while (0) + +#define BT_STK_ENTER(dbenv, c, pagep, page_indx, l, mode, ret) do { \ + if ((ret = ((c)->csp == (c)->esp ? \ + __bam_stkgrow(dbenv, c) : 0)) == 0) { \ + (c)->csp->page = pagep; \ + (c)->csp->indx = page_indx; \ + (c)->csp->entries = NUM_ENT(pagep); \ + (c)->csp->lock = l; \ + (c)->csp->lock_mode = mode; \ + } \ +} while (0) + +#define BT_STK_PUSH(dbenv, c, pagep, page_indx, lock, mode, ret) do { \ + BT_STK_ENTER(dbenv, c, pagep, page_indx, lock, mode, ret); \ + ++(c)->csp; \ +} while (0) + +#define BT_STK_NUM(dbenv, c, pagep, page_indx, ret) do { \ + if ((ret = \ + (c)->csp == (c)->esp ? __bam_stkgrow(dbenv, c) : 0) == 0) { \ + (c)->csp->page = NULL; \ + (c)->csp->indx = page_indx; \ + (c)->csp->entries = NUM_ENT(pagep); \ + LOCK_INIT((c)->csp->lock); \ + (c)->csp->lock_mode = DB_LOCK_NG; \ + } \ +} while (0) + +#define BT_STK_NUMPUSH(dbenv, c, pagep, page_indx, ret) do { \ + BT_STK_NUM(dbenv, cp, pagep, page_indx, ret); \ + ++(c)->csp; \ +} while (0) + +#define BT_STK_POP(c) \ + ((c)->csp == (c)->sp ? NULL : --(c)->csp) + +/* Btree/Recno cursor. */ +struct __cursor { + /* struct __dbc_internal */ + __DBC_INTERNAL + + /* btree private part */ + EPG *sp; /* Stack pointer. */ + EPG *csp; /* Current stack entry. */ + EPG *esp; /* End stack pointer. */ + EPG stack[5]; + + db_indx_t ovflsize; /* Maximum key/data on-page size. */ + + db_recno_t recno; /* Current record number. */ + u_int32_t order; /* Relative order among deleted curs. */ + + /* + * Btree: + * We set a flag in the cursor structure if the underlying object has + * been deleted. It's not strictly necessary, we could get the same + * information by looking at the page itself, but this method doesn't + * require us to retrieve the page on cursor delete. + * + * Recno: + * When renumbering recno databases during deletes, cursors referencing + * "deleted" records end up positioned between two records, and so must + * be specially adjusted on the next operation. + */ +#define C_DELETED 0x0001 /* Record was deleted. */ + /* + * There are three tree types that require maintaining record numbers. + * Recno AM trees, Btree AM trees for which the DB_RECNUM flag was set, + * and Btree off-page duplicate trees. + */ +#define C_RECNUM 0x0002 /* Tree requires record counts. */ + /* + * Recno trees have immutable record numbers by default, but optionally + * support mutable record numbers. Off-page duplicate Recno trees have + * mutable record numbers. All Btrees with record numbers (including + * off-page duplicate trees) are mutable by design, no flag is needed. + */ +#define C_RENUMBER 0x0004 /* Tree records are mutable. */ + u_int32_t flags; +}; + +/* + * Threshhold value, as a function of bt_minkey, of the number of + * bytes a key/data pair can use before being placed on an overflow + * page. Assume every item requires the maximum alignment for + * padding, out of sheer paranoia. + */ +#define B_MINKEY_TO_OVFLSIZE(dbp, minkey, pgsize) \ + ((u_int16_t)(((pgsize) - P_OVERHEAD(dbp)) / ((minkey) * P_INDX) -\ + (BKEYDATA_PSIZE(0) + DB_ALIGN(1, sizeof(int32_t))))) + +/* + * The maximum space that a single item can ever take up on one page. + * Used by __bam_split to determine whether a split is still necessary. + */ +#define B_MAX(a,b) (((a) > (b)) ? (a) : (b)) +#define B_MAXSIZEONPAGE(ovflsize) \ + (B_MAX(BOVERFLOW_PSIZE, BKEYDATA_PSIZE(ovflsize))) + +/* + * The in-memory, per-tree btree/recno data structure. + */ +struct __btree { /* Btree access method. */ + /* + * !!! + * These fields are write-once (when the structure is created) and + * so are ignored as far as multi-threading is concerned. + */ + db_pgno_t bt_meta; /* Database meta-data page. */ + db_pgno_t bt_root; /* Database root page. */ + + u_int32_t bt_maxkey; /* Maximum keys per page. */ + u_int32_t bt_minkey; /* Minimum keys per page. */ + + /* Btree comparison function. */ + int (*bt_compare) __P((DB *, const DBT *, const DBT *)); + /* Btree prefix function. */ + size_t (*bt_prefix) __P((DB *, const DBT *, const DBT *)); + + /* Recno access method. */ + int re_pad; /* Fixed-length padding byte. */ + int re_delim; /* Variable-length delimiting byte. */ + u_int32_t re_len; /* Length for fixed-length records. */ + char *re_source; /* Source file name. */ + + /* + * !!! + * The bt_lpgno field is NOT protected by any mutex, and for this + * reason must be advisory only, so, while it is read/written by + * multiple threads, DB is completely indifferent to the quality + * of its information. + */ + db_pgno_t bt_lpgno; /* Last insert location. */ + DB_LSN bt_llsn; /* Last insert LSN. */ + + /* + * !!! + * The re_modified field is NOT protected by any mutex, and for this + * reason cannot be anything more complicated than a zero/non-zero + * value. The actual writing of the backing source file cannot be + * threaded, so clearing the flag isn't a problem. + */ + int re_modified; /* If the tree was modified. */ + + /* + * !!! + * These fields are ignored as far as multi-threading is concerned. + * There are no transaction semantics associated with backing files, + * nor is there any thread protection. + */ + FILE *re_fp; /* Source file handle. */ + int re_eof; /* Backing source file EOF reached. */ + db_recno_t re_last; /* Last record number read. */ +}; + +/* + * Modes for the __bam_curadj recovery records (btree_curadj). + * These appear in log records, so we wire the values and + * do not leave it up to the compiler. + */ +typedef enum { + DB_CA_DI = 1, + DB_CA_DUP = 2, + DB_CA_RSPLIT = 3, + DB_CA_SPLIT = 4 +} db_ca_mode; + +#include "dbinc_auto/btree_auto.h" +#include "dbinc_auto/btree_ext.h" +#include "dbinc/db_am.h" +#endif /* !_DB_BTREE_H_ */ diff --git a/lib_dict/bdb/include/btree_auto.h b/lib_dict/bdb/include/btree_auto.h new file mode 100644 index 000000000..d9d4e47ad --- /dev/null +++ b/lib_dict/bdb/include/btree_auto.h @@ -0,0 +1,142 @@ +/* Do not edit: automatically built by gen_rec.awk. */ + +#ifndef __bam_AUTO_H +#define __bam_AUTO_H +#define DB___bam_split 62 +typedef struct ___bam_split_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + db_pgno_t left; + DB_LSN llsn; + db_pgno_t right; + DB_LSN rlsn; + u_int32_t indx; + db_pgno_t npgno; + DB_LSN nlsn; + db_pgno_t root_pgno; + DBT pg; + u_int32_t opflags; +} __bam_split_args; + +#define DB___bam_rsplit 63 +typedef struct ___bam_rsplit_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + db_pgno_t pgno; + DBT pgdbt; + db_pgno_t root_pgno; + db_pgno_t nrec; + DBT rootent; + DB_LSN rootlsn; +} __bam_rsplit_args; + +#define DB___bam_adj 55 +typedef struct ___bam_adj_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + db_pgno_t pgno; + DB_LSN lsn; + u_int32_t indx; + u_int32_t indx_copy; + u_int32_t is_insert; +} __bam_adj_args; + +#define DB___bam_cadjust 56 +typedef struct ___bam_cadjust_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + db_pgno_t pgno; + DB_LSN lsn; + u_int32_t indx; + int32_t adjust; + u_int32_t opflags; +} __bam_cadjust_args; + +#define DB___bam_cdel 57 +typedef struct ___bam_cdel_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + db_pgno_t pgno; + DB_LSN lsn; + u_int32_t indx; +} __bam_cdel_args; + +#define DB___bam_repl 58 +typedef struct ___bam_repl_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + db_pgno_t pgno; + DB_LSN lsn; + u_int32_t indx; + u_int32_t isdeleted; + DBT orig; + DBT repl; + u_int32_t prefix; + u_int32_t suffix; +} __bam_repl_args; + +#define DB___bam_root 59 +typedef struct ___bam_root_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + db_pgno_t meta_pgno; + db_pgno_t root_pgno; + DB_LSN meta_lsn; +} __bam_root_args; + +#define DB___bam_curadj 64 +typedef struct ___bam_curadj_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + db_ca_mode mode; + db_pgno_t from_pgno; + db_pgno_t to_pgno; + db_pgno_t left_pgno; + u_int32_t first_indx; + u_int32_t from_indx; + u_int32_t to_indx; +} __bam_curadj_args; + +#define DB___bam_rcuradj 65 +typedef struct ___bam_rcuradj_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + ca_recno_arg mode; + db_pgno_t root; + db_recno_t recno; + u_int32_t order; +} __bam_rcuradj_args; + +#define DB___bam_relink 147 +typedef struct ___bam_relink_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + db_pgno_t pgno; + DB_LSN lsn; + db_pgno_t prev; + DB_LSN lsn_prev; + db_pgno_t next; + DB_LSN lsn_next; +} __bam_relink_args; + +#endif diff --git a/lib_dict/bdb/include/btree_ext.h b/lib_dict/bdb/include/btree_ext.h new file mode 100644 index 000000000..9acb14051 --- /dev/null +++ b/lib_dict/bdb/include/btree_ext.h @@ -0,0 +1,134 @@ +/* DO NOT EDIT: automatically built by dist/s_include. */ +#ifndef _btree_ext_h_ +#define _btree_ext_h_ + +#if defined(__cplusplus) +extern "C" { +#endif + +int __bam_cmp __P((DB *, const DBT *, PAGE *, u_int32_t, int (*)(DB *, const DBT *, const DBT *), int *)); +int __bam_defcmp __P((DB *, const DBT *, const DBT *)); +size_t __bam_defpfx __P((DB *, const DBT *, const DBT *)); +int __bam_pgin __P((DB_ENV *, DB *, db_pgno_t, void *, DBT *)); +int __bam_pgout __P((DB_ENV *, DB *, db_pgno_t, void *, DBT *)); +int __bam_mswap __P((PAGE *)); +int __bam_ca_delete __P((DB *, db_pgno_t, u_int32_t, int)); +int __ram_ca_delete __P((DB *, db_pgno_t)); +int __bam_ca_di __P((DBC *, db_pgno_t, u_int32_t, int)); +int __bam_ca_dup __P((DBC *, u_int32_t, db_pgno_t, u_int32_t, db_pgno_t, u_int32_t)); +int __bam_ca_undodup __P((DB *, u_int32_t, db_pgno_t, u_int32_t, u_int32_t)); +int __bam_ca_rsplit __P((DBC *, db_pgno_t, db_pgno_t)); +int __bam_ca_split __P((DBC *, db_pgno_t, db_pgno_t, db_pgno_t, u_int32_t, int)); +void __bam_ca_undosplit __P((DB *, db_pgno_t, db_pgno_t, db_pgno_t, u_int32_t)); +int __bam_c_init __P((DBC *, DBTYPE)); +int __bam_c_refresh __P((DBC *)); +int __bam_c_count __P((DBC *, db_recno_t *)); +int __bam_c_dup __P((DBC *, DBC *)); +int __bam_bulk_overflow __P((DBC *, u_int32_t, db_pgno_t, u_int8_t *)); +int __bam_bulk_duplicates __P((DBC *, db_pgno_t, u_int8_t *, int32_t *, int32_t **, u_int8_t **, u_int32_t *, int)); +int __bam_c_rget __P((DBC *, DBT *)); +int __bam_ditem __P((DBC *, PAGE *, u_int32_t)); +int __bam_adjindx __P((DBC *, PAGE *, u_int32_t, u_int32_t, int)); +int __bam_dpages __P((DBC *, EPG *)); +int __bam_relink __P((DBC *, PAGE *, PAGE **)); +int __bam_db_create __P((DB *)); +int __bam_db_close __P((DB *)); +void __bam_map_flags __P((DB *, u_int32_t *, u_int32_t *)); +int __bam_set_flags __P((DB *, u_int32_t *flagsp)); +int __bam_set_bt_compare __P((DB *, int (*)(DB *, const DBT *, const DBT *))); +int __bam_get_bt_minkey __P((DB *, u_int32_t *)); +void __ram_map_flags __P((DB *, u_int32_t *, u_int32_t *)); +int __ram_set_flags __P((DB *, u_int32_t *flagsp)); +int __ram_get_re_len __P((DB *, u_int32_t *)); +int __ram_get_re_pad __P((DB *, int *)); +int __bam_open __P((DB *, DB_TXN *, const char *, db_pgno_t, u_int32_t)); +int __bam_metachk __P((DB *, const char *, BTMETA *)); +int __bam_read_root __P((DB *, DB_TXN *, db_pgno_t, u_int32_t)); +int __bam_new_file __P((DB *, DB_TXN *, DB_FH *, const char *)); +int __bam_new_subdb __P((DB *, DB *, DB_TXN *)); +int __bam_iitem __P((DBC *, DBT *, DBT *, u_int32_t, u_int32_t)); +int __bam_ritem __P((DBC *, PAGE *, u_int32_t, DBT *)); +int __bam_split_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __bam_rsplit_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __bam_adj_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __bam_cadjust_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __bam_cdel_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __bam_repl_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __bam_root_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __bam_curadj_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __bam_rcuradj_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __bam_relink_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __bam_reclaim __P((DB *, DB_TXN *)); +int __bam_truncate __P((DBC *, u_int32_t *)); +int __ram_open __P((DB *, DB_TXN *, const char *, db_pgno_t, u_int32_t)); +int __ram_append __P((DBC *, DBT *, DBT *)); +int __ram_c_del __P((DBC *)); +int __ram_c_get __P((DBC *, DBT *, DBT *, u_int32_t, db_pgno_t *)); +int __ram_c_put __P((DBC *, DBT *, DBT *, u_int32_t, db_pgno_t *)); +int __ram_ca __P((DBC *, ca_recno_arg)); +int __ram_getno __P((DBC *, const DBT *, db_recno_t *, int)); +int __ram_writeback __P((DB *)); +int __bam_rsearch __P((DBC *, db_recno_t *, u_int32_t, int, int *)); +int __bam_adjust __P((DBC *, int32_t)); +int __bam_nrecs __P((DBC *, db_recno_t *)); +db_recno_t __bam_total __P((DB *, PAGE *)); +int __bam_search __P((DBC *, db_pgno_t, const DBT *, u_int32_t, int, db_recno_t *, int *)); +int __bam_stkrel __P((DBC *, u_int32_t)); +int __bam_stkgrow __P((DB_ENV *, BTREE_CURSOR *)); +int __bam_split __P((DBC *, void *, db_pgno_t *)); +int __bam_copy __P((DB *, PAGE *, PAGE *, u_int32_t, u_int32_t)); +int __bam_stat __P((DBC *, void *, u_int32_t)); +int __bam_stat_print __P((DBC *, u_int32_t)); +int __bam_stat_callback __P((DB *, PAGE *, void *, int *)); +void __bam_print_cursor __P((DBC *)); +int __bam_key_range __P((DBC *, DBT *, DB_KEY_RANGE *, u_int32_t)); +int __bam_traverse __P((DBC *, db_lockmode_t, db_pgno_t, int (*)(DB *, PAGE *, void *, int *), void *)); +int __bam_30_btreemeta __P((DB *, char *, u_int8_t *)); +int __bam_31_btreemeta __P((DB *, char *, u_int32_t, DB_FH *, PAGE *, int *)); +int __bam_31_lbtree __P((DB *, char *, u_int32_t, DB_FH *, PAGE *, int *)); +int __bam_vrfy_meta __P((DB *, VRFY_DBINFO *, BTMETA *, db_pgno_t, u_int32_t)); +int __ram_vrfy_leaf __P((DB *, VRFY_DBINFO *, PAGE *, db_pgno_t, u_int32_t)); +int __bam_vrfy __P((DB *, VRFY_DBINFO *, PAGE *, db_pgno_t, u_int32_t)); +int __bam_vrfy_itemorder __P((DB *, VRFY_DBINFO *, PAGE *, db_pgno_t, u_int32_t, int, int, u_int32_t)); +int __bam_vrfy_structure __P((DB *, VRFY_DBINFO *, db_pgno_t, u_int32_t)); +int __bam_vrfy_subtree __P((DB *, VRFY_DBINFO *, db_pgno_t, void *, void *, u_int32_t, u_int32_t *, u_int32_t *, u_int32_t *)); +int __bam_salvage __P((DB *, VRFY_DBINFO *, db_pgno_t, u_int32_t, PAGE *, void *, int (*)(void *, const void *), DBT *, u_int32_t)); +int __bam_salvage_walkdupint __P((DB *, VRFY_DBINFO *, PAGE *, DBT *, void *, int (*)(void *, const void *), u_int32_t)); +int __bam_meta2pgset __P((DB *, VRFY_DBINFO *, BTMETA *, u_int32_t, DB *)); +int __bam_split_log __P((DB *, DB_TXN *, DB_LSN *, u_int32_t, db_pgno_t, DB_LSN *, db_pgno_t, DB_LSN *, u_int32_t, db_pgno_t, DB_LSN *, db_pgno_t, const DBT *, u_int32_t)); +int __bam_split_read __P((DB_ENV *, void *, __bam_split_args **)); +int __bam_rsplit_log __P((DB *, DB_TXN *, DB_LSN *, u_int32_t, db_pgno_t, const DBT *, db_pgno_t, db_pgno_t, const DBT *, DB_LSN *)); +int __bam_rsplit_read __P((DB_ENV *, void *, __bam_rsplit_args **)); +int __bam_adj_log __P((DB *, DB_TXN *, DB_LSN *, u_int32_t, db_pgno_t, DB_LSN *, u_int32_t, u_int32_t, u_int32_t)); +int __bam_adj_read __P((DB_ENV *, void *, __bam_adj_args **)); +int __bam_cadjust_log __P((DB *, DB_TXN *, DB_LSN *, u_int32_t, db_pgno_t, DB_LSN *, u_int32_t, int32_t, u_int32_t)); +int __bam_cadjust_read __P((DB_ENV *, void *, __bam_cadjust_args **)); +int __bam_cdel_log __P((DB *, DB_TXN *, DB_LSN *, u_int32_t, db_pgno_t, DB_LSN *, u_int32_t)); +int __bam_cdel_read __P((DB_ENV *, void *, __bam_cdel_args **)); +int __bam_repl_log __P((DB *, DB_TXN *, DB_LSN *, u_int32_t, db_pgno_t, DB_LSN *, u_int32_t, u_int32_t, const DBT *, const DBT *, u_int32_t, u_int32_t)); +int __bam_repl_read __P((DB_ENV *, void *, __bam_repl_args **)); +int __bam_root_log __P((DB *, DB_TXN *, DB_LSN *, u_int32_t, db_pgno_t, db_pgno_t, DB_LSN *)); +int __bam_root_read __P((DB_ENV *, void *, __bam_root_args **)); +int __bam_curadj_log __P((DB *, DB_TXN *, DB_LSN *, u_int32_t, db_ca_mode, db_pgno_t, db_pgno_t, db_pgno_t, u_int32_t, u_int32_t, u_int32_t)); +int __bam_curadj_read __P((DB_ENV *, void *, __bam_curadj_args **)); +int __bam_rcuradj_log __P((DB *, DB_TXN *, DB_LSN *, u_int32_t, ca_recno_arg, db_pgno_t, db_recno_t, u_int32_t)); +int __bam_rcuradj_read __P((DB_ENV *, void *, __bam_rcuradj_args **)); +int __bam_relink_log __P((DB *, DB_TXN *, DB_LSN *, u_int32_t, db_pgno_t, DB_LSN *, db_pgno_t, DB_LSN *, db_pgno_t, DB_LSN *)); +int __bam_relink_read __P((DB_ENV *, void *, __bam_relink_args **)); +int __bam_init_recover __P((DB_ENV *, int (***)(DB_ENV *, DBT *, DB_LSN *, db_recops, void *), size_t *)); +int __bam_split_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __bam_rsplit_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __bam_adj_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __bam_cadjust_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __bam_cdel_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __bam_repl_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __bam_root_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __bam_curadj_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __bam_rcuradj_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __bam_relink_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __bam_init_print __P((DB_ENV *, int (***)(DB_ENV *, DBT *, DB_LSN *, db_recops, void *), size_t *)); + +#if defined(__cplusplus) +} +#endif +#endif /* !_btree_ext_h_ */ diff --git a/lib_dict/bdb/include/clib_ext.h b/lib_dict/bdb/include/clib_ext.h new file mode 100644 index 000000000..a471268e0 --- /dev/null +++ b/lib_dict/bdb/include/clib_ext.h @@ -0,0 +1,49 @@ +/* DO NOT EDIT: automatically built by dist/s_include. */ +#ifndef _clib_ext_h_ +#define _clib_ext_h_ + +#if defined(__cplusplus) +extern "C" { +#endif + +#ifndef HAVE_GETCWD +char *getcwd __P((char *, size_t)); +#endif +#ifndef HAVE_GETOPT +int getopt __P((int, char * const *, const char *)); +#endif +#ifndef HAVE_MEMCMP +int memcmp __P((const void *, const void *, size_t)); +#endif +#ifndef HAVE_MEMCPY +void *memcpy __P((void *, const void *, size_t)); +#endif +#ifndef HAVE_MEMMOVE +void *memmove __P((void *, const void *, size_t)); +#endif +#ifndef HAVE_RAISE +int raise __P((int)); +#endif +#ifndef HAVE_SNPRINTF +int snprintf __P((char *, size_t, const char *, ...)); +#endif +#ifndef HAVE_VSNPRINTF +int vsnprintf __P((char *, size_t, const char *, va_list)); +#endif +#ifndef HAVE_STRCASECMP +int strcasecmp __P((const char *, const char *)); +#endif +#ifndef HAVE_STRCASECMP +int strncasecmp __P((const char *, const char *, size_t)); +#endif +#ifndef HAVE_STRDUP +char *strdup __P((const char *)); +#endif +#ifndef HAVE_STRERROR +char *strerror __P((int)); +#endif + +#if defined(__cplusplus) +} +#endif +#endif /* !_clib_ext_h_ */ diff --git a/lib_dict/bdb/include/common_ext.h b/lib_dict/bdb/include/common_ext.h new file mode 100644 index 000000000..d9f05406d --- /dev/null +++ b/lib_dict/bdb/include/common_ext.h @@ -0,0 +1,50 @@ +/* DO NOT EDIT: automatically built by dist/s_include. */ +#ifndef _common_ext_h_ +#define _common_ext_h_ + +#if defined(__cplusplus) +extern "C" { +#endif + +int __crypto_region_init __P((DB_ENV *)); +int __db_isbigendian __P((void)); +int __db_byteorder __P((DB_ENV *, int)); +int __db_fchk __P((DB_ENV *, const char *, u_int32_t, u_int32_t)); +int __db_fcchk __P((DB_ENV *, const char *, u_int32_t, u_int32_t, u_int32_t)); +int __db_ferr __P((const DB_ENV *, const char *, int)); +int __db_fnl __P((const DB_ENV *, const char *)); +int __db_pgerr __P((DB *, db_pgno_t, int)); +int __db_pgfmt __P((DB_ENV *, db_pgno_t)); +#ifdef DIAGNOSTIC +void __db_assert __P((const char *, const char *, int)); +#endif +int __db_panic_msg __P((DB_ENV *)); +int __db_panic __P((DB_ENV *, int)); +void __db_err __P((const DB_ENV *, const char *, ...)) __attribute__ ((__format__ (__printf__, 2, 3))); +void __db_errcall __P((const DB_ENV *, int, int, const char *, va_list)); +void __db_errfile __P((const DB_ENV *, int, int, const char *, va_list)); +void __db_msgadd __P((DB_ENV *, DB_MSGBUF *, const char *, ...)) __attribute__ ((__format__ (__printf__, 3, 4))); +void __db_msg __P((const DB_ENV *, const char *, ...)) __attribute__ ((__format__ (__printf__, 2, 3))); +void __db_logmsg __P((const DB_ENV *, DB_TXN *, const char *, u_int32_t, const char *, ...)) __attribute__ ((__format__ (__printf__, 5, 6))); +int __db_unknown_flag __P((DB_ENV *, char *, u_int32_t)); +int __db_unknown_type __P((DB_ENV *, char *, DBTYPE)); +int __db_check_txn __P((DB *, DB_TXN *, u_int32_t, int)); +int __db_not_txn_env __P((DB_ENV *)); +int __db_rec_toobig __P((DB_ENV *, u_int32_t, u_int32_t)); +int __db_rec_repl __P((DB_ENV *, u_int32_t, u_int32_t)); +int __db_check_lsn __P((DB_ENV *, DB_LSN *, DB_LSN *)); +int __db_getlong __P((DB_ENV *, const char *, char *, long, long, long *)); +int __db_getulong __P((DB_ENV *, const char *, char *, u_long, u_long, u_long *)); +void __db_idspace __P((u_int32_t *, int, u_int32_t *, u_int32_t *)); +u_int32_t __db_log2 __P((u_int32_t)); +int __db_util_arg __P((char *, char *, int *, char ***)); +int __db_util_cache __P((DB *, u_int32_t *, int *)); +int __db_util_logset __P((const char *, char *)); +void __db_util_siginit __P((void)); +int __db_util_interrupted __P((void)); +void __db_util_sigresend __P((void)); + +#if defined(__cplusplus) +} +#endif +#endif /* !_common_ext_h_ */ diff --git a/lib_dict/bdb/include/crdel_auto.h b/lib_dict/bdb/include/crdel_auto.h new file mode 100644 index 000000000..bdae193fa --- /dev/null +++ b/lib_dict/bdb/include/crdel_auto.h @@ -0,0 +1,16 @@ +/* Do not edit: automatically built by gen_rec.awk. */ + +#ifndef __crdel_AUTO_H +#define __crdel_AUTO_H +#define DB___crdel_metasub 142 +typedef struct ___crdel_metasub_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + db_pgno_t pgno; + DBT page; + DB_LSN lsn; +} __crdel_metasub_args; + +#endif diff --git a/lib_dict/bdb/include/crypto.h b/lib_dict/bdb/include/crypto.h new file mode 100644 index 000000000..8eeebf81b --- /dev/null +++ b/lib_dict/bdb/include/crypto.h @@ -0,0 +1,78 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996-2004 + * Sleepycat Software. All rights reserved. + * + * $Id: crypto.h,v 1.12 2004/01/28 03:36:00 bostic Exp $ + */ + +#ifndef _DB_CRYPTO_H_ +#define _DB_CRYPTO_H_ + +/* + * !!! + * These are the internal representations of the algorithm flags. + * They are used in both the DB_CIPHER structure and the CIPHER + * structure so we can tell if users specified both passwd and alg + * correctly. + * + * CIPHER_ANY is used when an app joins an existing env but doesn't + * know the algorithm originally used. This is only valid in the + * DB_CIPHER structure until we open and can set the alg. + */ +/* + * We store the algorithm in an 8-bit field on the meta-page. So we + * use a numeric value, not bit fields. + * now we are limited to 8 algorithms before we cannot use bits and + * need numeric values. That should be plenty. It is okay for the + * CIPHER_ANY flag to go beyond that since that is never stored on disk. + */ + +/* + * This structure is per-process, not in shared memory. + */ +struct __db_cipher { + u_int (*adj_size) __P((size_t)); + int (*close) __P((DB_ENV *, void *)); + int (*decrypt) __P((DB_ENV *, void *, void *, u_int8_t *, size_t)); + int (*encrypt) __P((DB_ENV *, void *, void *, u_int8_t *, size_t)); + int (*init) __P((DB_ENV *, DB_CIPHER *)); + + u_int8_t mac_key[DB_MAC_KEY]; /* MAC key. */ + void *data; /* Algorithm-specific information */ + +#define CIPHER_AES 1 /* AES algorithm */ + u_int8_t alg; /* Algorithm used - See above */ + u_int8_t spare[3]; /* Spares */ + +#define CIPHER_ANY 0x00000001 /* Only for DB_CIPHER */ + u_int32_t flags; /* Other flags */ +}; + +#ifdef HAVE_CRYPTO + +#include "crypto/rijndael/rijndael-api-fst.h" + +/* + * Shared ciphering structure + * No DB_MUTEX needed because all information is read-only after creation. + */ +typedef struct __cipher { + roff_t passwd; /* Offset to shared passwd */ + size_t passwd_len; /* Length of passwd */ + u_int32_t flags; /* Algorithm used - see above */ +} CIPHER; + +#define DB_AES_KEYLEN 128 /* AES key length */ +#define DB_AES_CHUNK 16 /* AES byte unit size */ + +typedef struct __aes_cipher { + keyInstance decrypt_ki; /* Decryption key instance */ + keyInstance encrypt_ki; /* Encryption key instance */ + u_int32_t flags; /* AES-specific flags */ +} AES_CIPHER; + +#include "dbinc_auto/crypto_ext.h" +#endif /* HAVE_CRYPTO */ +#endif /* !_DB_CRYPTO_H_ */ diff --git a/lib_dict/bdb/include/crypto_ext.h b/lib_dict/bdb/include/crypto_ext.h new file mode 100644 index 000000000..b305ec5a7 --- /dev/null +++ b/lib_dict/bdb/include/crypto_ext.h @@ -0,0 +1,38 @@ +/* DO NOT EDIT: automatically built by dist/s_include. */ +#ifndef _crypto_ext_h_ +#define _crypto_ext_h_ + +#if defined(__cplusplus) +extern "C" { +#endif + +int __aes_setup __P((DB_ENV *, DB_CIPHER *)); +u_int __aes_adj_size __P((size_t)); +int __aes_close __P((DB_ENV *, void *)); +int __aes_decrypt __P((DB_ENV *, void *, void *, u_int8_t *, size_t)); +int __aes_encrypt __P((DB_ENV *, void *, void *, u_int8_t *, size_t)); +int __aes_init __P((DB_ENV *, DB_CIPHER *)); +int __crypto_dbenv_close __P((DB_ENV *)); +int __crypto_region_destroy __P((DB_ENV *)); +int __crypto_algsetup __P((DB_ENV *, DB_CIPHER *, u_int32_t, int)); +int __crypto_decrypt_meta __P((DB_ENV *, DB *, u_int8_t *, int)); +int __crypto_set_passwd __P((DB_ENV *, DB_ENV *)); +int __db_generate_iv __P((DB_ENV *, u_int32_t *)); +int __db_rijndaelKeySetupEnc __P((u32 *, const u8 *, int)); +int __db_rijndaelKeySetupDec __P((u32 *, const u8 *, int)); +void __db_rijndaelEncrypt __P((u32 *, int, const u8 *, u8 *)); +void __db_rijndaelDecrypt __P((u32 *, int, const u8 *, u8 *)); +void __db_rijndaelEncryptRound __P((const u32 *, int, u8 *, int)); +void __db_rijndaelDecryptRound __P((const u32 *, int, u8 *, int)); +int __db_makeKey __P((keyInstance *, int, int, char *)); +int __db_cipherInit __P((cipherInstance *, int, char *)); +int __db_blockEncrypt __P((cipherInstance *, keyInstance *, u_int8_t *, size_t, u_int8_t *)); +int __db_padEncrypt __P((cipherInstance *, keyInstance *, u_int8_t *, int, u_int8_t *)); +int __db_blockDecrypt __P((cipherInstance *, keyInstance *, u_int8_t *, size_t, u_int8_t *)); +int __db_padDecrypt __P((cipherInstance *, keyInstance *, u_int8_t *, int, u_int8_t *)); +int __db_cipherUpdateRounds __P((cipherInstance *, keyInstance *, u_int8_t *, int, u_int8_t *, int)); + +#if defined(__cplusplus) +} +#endif +#endif /* !_crypto_ext_h_ */ diff --git a/lib_dict/bdb/include/cxx_int.h b/lib_dict/bdb/include/cxx_int.h new file mode 100644 index 000000000..d71ca25d0 --- /dev/null +++ b/lib_dict/bdb/include/cxx_int.h @@ -0,0 +1,77 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997-2004 + * Sleepycat Software. All rights reserved. + * + * $Id: cxx_int.h,v 11.25 2004/09/22 22:20:31 mjc Exp $ + */ + +#ifndef _CXX_INT_H_ +#define _CXX_INT_H_ + +// private data structures known to the implementation only + +// +// Using FooImp classes will allow the implementation to change in the +// future without any modification to user code or even to header files +// that the user includes. FooImp * is just like void * except that it +// provides a little extra protection, since you cannot randomly assign +// any old pointer to a FooImp* as you can with void *. Currently, a +// pointer to such an opaque class is always just a pointer to the +// appropriate underlying implementation struct. These are converted +// back and forth using the various overloaded wrap()/unwrap() methods. +// This is essentially a use of the "Bridge" Design Pattern. +// +// WRAPPED_CLASS implements the appropriate wrap() and unwrap() methods +// for a wrapper class that has an underlying pointer representation. +// +#define WRAPPED_CLASS(_WRAPPER_CLASS, _IMP_CLASS, _WRAPPED_TYPE) \ + \ + class _IMP_CLASS {}; \ + \ + inline _WRAPPED_TYPE *unwrap(_WRAPPER_CLASS *val) \ + { \ + if (!val) return (0); \ + return (val->get_##_WRAPPED_TYPE()); \ + } \ + \ + inline const _WRAPPED_TYPE *unwrapConst(const _WRAPPER_CLASS *val) \ + { \ + if (!val) return (0); \ + return (val->get_const_##_WRAPPED_TYPE()); \ + } + +WRAPPED_CLASS(Db, DbImp, DB) +WRAPPED_CLASS(DbEnv, DbEnvImp, DB_ENV) +WRAPPED_CLASS(DbMpoolFile, DbMpoolFileImp, DB_MPOOLFILE) +WRAPPED_CLASS(DbSequence, DbSequenceImp, DB_SEQUENCE) +WRAPPED_CLASS(DbTxn, DbTxnImp, DB_TXN) + +// A tristate integer value used by the DB_ERROR macro below. +// We chose not to make this an enumerated type so it can +// be kept private, even though methods that return the +// tristate int can be declared in db_cxx.h . +// +#define ON_ERROR_THROW 1 +#define ON_ERROR_RETURN 0 +#define ON_ERROR_UNKNOWN (-1) + +// Macros that handle detected errors, in case we want to +// change the default behavior. The 'policy' is one of +// the tristate values given above. If UNKNOWN is specified, +// the behavior is taken from the last initialized DbEnv. +// +#define DB_ERROR(env, caller, ecode, policy) \ + DbEnv::runtime_error(env, caller, ecode, policy) + +#define DB_ERROR_DBT(env, caller, dbt, policy) \ + DbEnv::runtime_error_dbt(env, caller, dbt, policy) + +#define DB_OVERFLOWED_DBT(dbt) \ + (F_ISSET(dbt, DB_DBT_USERMEM) && dbt->size > dbt->ulen) + +/* values for Db::flags_ */ +#define DB_CXX_PRIVATE_ENV 0x00000001 + +#endif /* !_CXX_INT_H_ */ diff --git a/lib_dict/bdb/include/db.h b/lib_dict/bdb/include/db.h new file mode 100644 index 000000000..e0b06e5f3 --- /dev/null +++ b/lib_dict/bdb/include/db.h @@ -0,0 +1,2246 @@ +/* DO NOT EDIT: automatically built by dist/s_win32. */ +/* + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996-2004 + * Sleepycat Software. All rights reserved. + * + * $Id: db.in,v 11.463 2004/10/11 18:47:50 bostic Exp $ + * + * db.h include file layout: + * General. + * Database Environment. + * Locking subsystem. + * Logging subsystem. + * Shared buffer cache (mpool) subsystem. + * Transaction subsystem. + * Access methods. + * Access method cursors. + * Dbm/Ndbm, Hsearch historic interfaces. + */ + +#ifndef _DB_H_ +#define _DB_H_ + +#ifndef __NO_SYSTEM_INCLUDES +#include +#include +#include +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + + +#undef __P +#define __P(protos) protos + +/* + * Berkeley DB version information. + */ +#define DB_VERSION_MAJOR 4 +#define DB_VERSION_MINOR 3 +#define DB_VERSION_PATCH 29 +#define DB_VERSION_STRING "Sleepycat Software: Berkeley DB 4.3.29: (September 21, 2005)" + +/* + * !!! + * Berkeley DB uses specifically sized types. If they're not provided by + * the system, typedef them here. + * + * We protect them against multiple inclusion using __BIT_TYPES_DEFINED__, + * as does BIND and Kerberos, since we don't know for sure what #include + * files the user is using. + * + * !!! + * We also provide the standard u_int, u_long etc., if they're not provided + * by the system. + */ +#ifndef __BIT_TYPES_DEFINED__ +#define __BIT_TYPES_DEFINED__ +typedef unsigned char u_int8_t; +typedef short int16_t; +typedef unsigned short u_int16_t; +typedef int int32_t; +typedef unsigned int u_int32_t; +typedef __int64 int64_t; +typedef unsigned __int64 u_int64_t; +#endif + +#ifndef _WINSOCKAPI_ +typedef unsigned char u_char; +typedef unsigned short u_short; +typedef unsigned int u_int; +typedef unsigned long u_long; +#endif + +#ifndef ACL_MS_WINDOWS +#ifdef _WIN64 +typedef int64_t ssize_t; +#else +typedef int32_t ssize_t; +#endif +#endif + +/* + * uintmax_t -- + * Largest unsigned type, used to align structures in memory. We don't store + * floating point types in structures, so integral types should be sufficient + * (and we don't have to worry about systems that store floats in other than + * power-of-2 numbers of bytes). Additionally this fixes compilers that rewrite + * structure assignments and ANSI C memcpy calls to be in-line instructions + * that happen to require alignment. Note: this alignment isn't sufficient for + * mutexes, which depend on things like cache line alignment. Mutex alignment + * is handled separately, in mutex.h. + * + * uintptr_t -- + * Unsigned type that's the same size as a pointer. There are places where + * DB modifies pointers by discarding the bottom bits to guarantee alignment. + * We can't use uintmax_t, it may be larger than the pointer, and compilers + * get upset about that. So far we haven't run on any machine where there's + * no unsigned type the same size as a pointer -- here's hoping. + */ +typedef u_int64_t uintmax_t; +#ifdef _WIN64 +typedef u_int64_t uintptr_t; +#else +typedef u_int32_t uintptr_t; +#endif + +/* + * Sequences are only available on machines with 64-bit integral types. + */ +typedef int64_t db_seq_t; + +/* Basic types that are exported or quasi-exported. */ +typedef u_int32_t db_pgno_t; /* Page number type. */ +typedef u_int16_t db_indx_t; /* Page offset type. */ +#define DB_MAX_PAGES 0xffffffff /* >= # of pages in a file */ + +typedef u_int32_t db_recno_t; /* Record number type. */ +#define DB_MAX_RECORDS 0xffffffff /* >= # of records in a tree */ + +typedef u_int32_t db_timeout_t; /* Type of a timeout. */ + +/* + * Region offsets are the difference between a pointer in a region and the + * region's base address. With private environments, both addresses are the + * result of calling malloc, and we can't assume anything about what malloc + * will return, so region offsets have to be able to hold differences between + * arbitrary pointers. + */ +typedef uintptr_t roff_t; + +/* + * Forward structure declarations, so we can declare pointers and + * applications can get type checking. + */ +struct __db; typedef struct __db DB; +struct __db_bt_stat; typedef struct __db_bt_stat DB_BTREE_STAT; +struct __db_cipher; typedef struct __db_cipher DB_CIPHER; +struct __db_dbt; typedef struct __db_dbt DBT; +struct __db_env; typedef struct __db_env DB_ENV; +struct __db_h_stat; typedef struct __db_h_stat DB_HASH_STAT; +struct __db_ilock; typedef struct __db_ilock DB_LOCK_ILOCK; +struct __db_lock_stat; typedef struct __db_lock_stat DB_LOCK_STAT; +struct __db_lock_u; typedef struct __db_lock_u DB_LOCK; +struct __db_lockreq; typedef struct __db_lockreq DB_LOCKREQ; +struct __db_log_cursor; typedef struct __db_log_cursor DB_LOGC; +struct __db_log_stat; typedef struct __db_log_stat DB_LOG_STAT; +struct __db_lsn; typedef struct __db_lsn DB_LSN; +struct __db_mpool; typedef struct __db_mpool DB_MPOOL; +struct __db_mpool_fstat;typedef struct __db_mpool_fstat DB_MPOOL_FSTAT; +struct __db_mpool_stat; typedef struct __db_mpool_stat DB_MPOOL_STAT; +struct __db_mpoolfile; typedef struct __db_mpoolfile DB_MPOOLFILE; +struct __db_preplist; typedef struct __db_preplist DB_PREPLIST; +struct __db_qam_stat; typedef struct __db_qam_stat DB_QUEUE_STAT; +struct __db_rep; typedef struct __db_rep DB_REP; +struct __db_rep_stat; typedef struct __db_rep_stat DB_REP_STAT; +struct __db_sequence; typedef struct __db_sequence DB_SEQUENCE; +struct __db_seq_record; typedef struct __db_seq_record DB_SEQ_RECORD; +struct __db_seq_stat; typedef struct __db_seq_stat DB_SEQUENCE_STAT; +struct __db_txn; typedef struct __db_txn DB_TXN; +struct __db_txn_active; typedef struct __db_txn_active DB_TXN_ACTIVE; +struct __db_txn_stat; typedef struct __db_txn_stat DB_TXN_STAT; +struct __db_txnmgr; typedef struct __db_txnmgr DB_TXNMGR; +struct __dbc; typedef struct __dbc DBC; +struct __dbc_internal; typedef struct __dbc_internal DBC_INTERNAL; +struct __fh_t; typedef struct __fh_t DB_FH; +struct __fname; typedef struct __fname FNAME; +struct __key_range; typedef struct __key_range DB_KEY_RANGE; +struct __mpoolfile; typedef struct __mpoolfile MPOOLFILE; +struct __mutex_t; typedef struct __mutex_t DB_MUTEX; + +/* Key/data structure -- a Data-Base Thang. */ +struct __db_dbt { + /* + * data/size must be fields 1 and 2 for DB 1.85 compatibility. + */ + void *data; /* Key/data */ + u_int32_t size; /* key/data length */ + + u_int32_t ulen; /* RO: length of user buffer. */ + u_int32_t dlen; /* RO: get/put record length. */ + u_int32_t doff; /* RO: get/put record offset. */ + +#define DB_DBT_APPMALLOC 0x001 /* Callback allocated memory. */ +#define DB_DBT_ISSET 0x002 /* Lower level calls set value. */ +#define DB_DBT_MALLOC 0x004 /* Return in malloc'd memory. */ +#define DB_DBT_PARTIAL 0x008 /* Partial put/get. */ +#define DB_DBT_REALLOC 0x010 /* Return in realloc'd memory. */ +#define DB_DBT_USERMEM 0x020 /* Return in user's memory. */ +#define DB_DBT_DUPOK 0x040 /* Insert if duplicate. */ + u_int32_t flags; +}; + +/* + * Common flags -- + * Interfaces which use any of these common flags should never have + * interface specific flags in this range. + */ +#define DB_CREATE 0x0000001 /* Create file as necessary. */ +#define DB_CXX_NO_EXCEPTIONS 0x0000002 /* C++: return error values. */ +#define DB_FORCE 0x0000004 /* Force (anything). */ +#define DB_NOMMAP 0x0000008 /* Don't mmap underlying file. */ +#define DB_RDONLY 0x0000010 /* Read-only (O_RDONLY). */ +#define DB_RECOVER 0x0000020 /* Run normal recovery. */ +#define DB_THREAD 0x0000040 /* Applications are threaded. */ +#define DB_TRUNCATE 0x0000080 /* Discard existing DB (O_TRUNC). */ +#define DB_TXN_NOSYNC 0x0000100 /* Do not sync log on commit. */ +#define DB_TXN_NOT_DURABLE 0x0000200 /* Do not log changes. */ +#define DB_USE_ENVIRON 0x0000400 /* Use the environment. */ +#define DB_USE_ENVIRON_ROOT 0x0000800 /* Use the environment if root. */ + +/* + * Common flags -- + * Interfaces which use any of these common flags should never have + * interface specific flags in this range. + * + * DB_AUTO_COMMIT: + * DB_ENV->set_flags, DB->associate, DB->del, DB->put, DB->open, + * DB->remove, DB->rename, DB->truncate + * DB_DEGREE_2: + * DB->cursor, DB->get, DB->join, DBcursor->c_get, DB_ENV->txn_begin + * DB_DIRTY_READ: + * DB->cursor, DB->get, DB->join, DB->open, DBcursor->c_get, + * DB_ENV->txn_begin + * DB_NOAUTO_COMMIT + * DB->associate, DB->del, DB->put, DB->open, + * DB->remove, DB->rename, DB->truncate + * + * !!! + * The DB_DIRTY_READ and DB_DEGREE_2 bit masks can't be changed without + * also changing the masks for the flags that can be OR'd into DB + * access method and cursor operation values. + */ +#define DB_AUTO_COMMIT 0x01000000/* Implied transaction. */ +#define DB_DEGREE_2 0x02000000/* Degree 2. */ +#define DB_DIRTY_READ 0x04000000/* Dirty Read. */ +#define DB_NO_AUTO_COMMIT 0x08000000/* Override env-wide AUTOCOMMIT. */ + +/* + * Flags private to db_env_create. + */ +#define DB_RPCCLIENT 0x0000001 /* An RPC client environment. */ + +/* + * Flags private to db_create. + */ +#define DB_REP_CREATE 0x0000001 /* Open of an internal rep database. */ +#define DB_XA_CREATE 0x0000002 /* Open in an XA environment. */ + +/* + * Flags private to DB_ENV->open. + * Shared flags up to 0x0000800 */ +#define DB_INIT_CDB 0x0001000 /* Concurrent Access Methods. */ +#define DB_INIT_LOCK 0x0002000 /* Initialize locking. */ +#define DB_INIT_LOG 0x0004000 /* Initialize logging. */ +#define DB_INIT_MPOOL 0x0008000 /* Initialize mpool. */ +#define DB_INIT_REP 0x0010000 /* Initialize replication. */ +#define DB_INIT_TXN 0x0020000 /* Initialize transactions. */ +#define DB_JOINENV 0x0040000 /* Initialize all subsystems present. */ +#define DB_LOCKDOWN 0x0080000 /* Lock memory into physical core. */ +#define DB_PRIVATE 0x0100000 /* DB_ENV is process local. */ +#define DB_RECOVER_FATAL 0x0200000 /* Run catastrophic recovery. */ +#define DB_SYSTEM_MEM 0x0400000 /* Use system-backed memory. */ + +/* + * Flags private to DB->open. + * Shared flags up to 0x0000800 */ +#define DB_EXCL 0x0001000 /* Exclusive open (O_EXCL). */ +#define DB_FCNTL_LOCKING 0x0002000 /* UNDOC: fcntl(2) locking. */ +#define DB_RDWRMASTER 0x0004000 /* UNDOC: allow subdb master open R/W */ +#define DB_WRITEOPEN 0x0008000 /* UNDOC: open with write lock. */ + +/* + * Flags private to DB_ENV->txn_begin. + * Shared flags up to 0x0000800 */ +#define DB_TXN_NOWAIT 0x0001000 /* Do not wait for locks in this TXN. */ +#define DB_TXN_SYNC 0x0002000 /* Always sync log on commit. */ + +/* + * Flags private to DB_ENV->set_encrypt. + */ +#define DB_ENCRYPT_AES 0x0000001 /* AES, assumes SHA1 checksum */ + +/* + * Flags private to DB_ENV->set_flags. + * Shared flags up to 0x00000800 */ +#define DB_CDB_ALLDB 0x00001000/* Set CDB locking per environment. */ +#define DB_DIRECT_DB 0x00002000/* Don't buffer databases in the OS. */ +#define DB_DIRECT_LOG 0x00004000/* Don't buffer log files in the OS. */ +#define DB_DSYNC_LOG 0x00008000/* Set O_DSYNC on the log. */ +#define DB_LOG_AUTOREMOVE 0x00010000/* Automatically remove log files. */ +#define DB_LOG_INMEMORY 0x00020000/* Store logs in buffers in memory. */ +#define DB_NOLOCKING 0x00040000/* Set locking/mutex behavior. */ +#define DB_NOPANIC 0x00080000/* Set panic state per DB_ENV. */ +#define DB_OVERWRITE 0x00100000/* Overwrite unlinked region files. */ +#define DB_PANIC_ENVIRONMENT 0x00200000/* Set panic state per environment. */ +#define DB_REGION_INIT 0x00400000/* Page-fault regions on open. */ +#define DB_TIME_NOTGRANTED 0x00800000/* Return NOTGRANTED on timeout. */ +/* Shared flags at 0x01000000 */ +/* Shared flags at 0x02000000 */ +/* Shared flags at 0x04000000 */ +/* Shared flags at 0x08000000 */ +#define DB_TXN_WRITE_NOSYNC 0x10000000/* Write, don't sync, on txn commit. */ +#define DB_YIELDCPU 0x20000000/* Yield the CPU (a lot). */ + +/* + * Flags private to DB->set_feedback's callback. + */ +#define DB_UPGRADE 0x0000001 /* Upgrading. */ +#define DB_VERIFY 0x0000002 /* Verifying. */ + +/* + * Flags private to DB_MPOOLFILE->open. + * Shared flags up to 0x0000800 */ +#define DB_DIRECT 0x0001000 /* Don't buffer the file in the OS. */ +#define DB_DURABLE_UNKNOWN 0x0002000 /* internal: durability on open. */ +#define DB_EXTENT 0x0004000 /* internal: dealing with an extent. */ +#define DB_ODDFILESIZE 0x0008000 /* Truncate file to N * pgsize. */ + +/* + * Flags private to DB->set_flags. + */ +#define DB_CHKSUM 0x0000001 /* Do checksumming */ +#define DB_DUP 0x0000002 /* Btree, Hash: duplicate keys. */ +#define DB_DUPSORT 0x0000004 /* Btree, Hash: duplicate keys. */ +#define DB_ENCRYPT 0x0000008 /* Btree, Hash: duplicate keys. */ +#define DB_INORDER 0x0000010 /* Queue: strict ordering on consume. */ +#define DB_RECNUM 0x0000020 /* Btree: record numbers. */ +#define DB_RENUMBER 0x0000040 /* Recno: renumber on insert/delete. */ +#define DB_REVSPLITOFF 0x0000080 /* Btree: turn off reverse splits. */ +#define DB_SNAPSHOT 0x0000100 /* Recno: snapshot the input. */ + +/* + * Flags private to the DB_ENV->stat_print, DB->stat and DB->stat_print methods. + */ +#define DB_STAT_ALL 0x0000001 /* Print: Everything. */ +#define DB_STAT_CLEAR 0x0000002 /* Clear stat after returning values. */ +#define DB_STAT_LOCK_CONF 0x0000004 /* Print: Lock conflict matrix. */ +#define DB_STAT_LOCK_LOCKERS 0x0000008 /* Print: Lockers. */ +#define DB_STAT_LOCK_OBJECTS 0x0000010 /* Print: Lock objects. */ +#define DB_STAT_LOCK_PARAMS 0x0000020 /* Print: Lock parameters. */ +#define DB_STAT_MEMP_HASH 0x0000040 /* Print: Mpool hash buckets. */ +#define DB_STAT_SUBSYSTEM 0x0000080 /* Print: Subsystems too. */ + +/* + * Flags private to DB->join. + */ +#define DB_JOIN_NOSORT 0x0000001 /* Don't try to optimize join. */ + +/* + * Flags private to DB->verify. + */ +#define DB_AGGRESSIVE 0x0000001 /* Salvage whatever could be data.*/ +#define DB_NOORDERCHK 0x0000002 /* Skip sort order/hashing check. */ +#define DB_ORDERCHKONLY 0x0000004 /* Only perform the order check. */ +#define DB_PR_PAGE 0x0000008 /* Show page contents (-da). */ +#define DB_PR_RECOVERYTEST 0x0000010 /* Recovery test (-dr). */ +#define DB_PRINTABLE 0x0000020 /* Use printable format for salvage. */ +#define DB_SALVAGE 0x0000040 /* Salvage what looks like data. */ +#define DB_UNREF 0x0000080 /* Report unreferenced pages. */ +/* + * !!! + * These must not go over 0x8000, or they will collide with the flags + * used by __bam_vrfy_subtree. + */ + +/* + * Flags private to DB->set_rep_transport's send callback. + */ +#define DB_REP_NOBUFFER 0x0000001 /* Do not buffer this message. */ +#define DB_REP_PERMANENT 0x0000002 /* Important--app. may want to flush. */ + +/******************************************************* + * Locking. + *******************************************************/ +#define DB_LOCKVERSION 1 + +#define DB_FILE_ID_LEN 20 /* Unique file ID length. */ + +/* + * Deadlock detector modes; used in the DB_ENV structure to configure the + * locking subsystem. + */ +#define DB_LOCK_NORUN 0 +#define DB_LOCK_DEFAULT 1 /* Default policy. */ +#define DB_LOCK_EXPIRE 2 /* Only expire locks, no detection. */ +#define DB_LOCK_MAXLOCKS 3 /* Select locker with max locks. */ +#define DB_LOCK_MAXWRITE 4 /* Select locker with max writelocks. */ +#define DB_LOCK_MINLOCKS 5 /* Select locker with min locks. */ +#define DB_LOCK_MINWRITE 6 /* Select locker with min writelocks. */ +#define DB_LOCK_OLDEST 7 /* Select oldest locker. */ +#define DB_LOCK_RANDOM 8 /* Select random locker. */ +#define DB_LOCK_YOUNGEST 9 /* Select youngest locker. */ + +/* Flag values for lock_vec(), lock_get(). */ +#define DB_LOCK_ABORT 0x001 /* Internal: Lock during abort. */ +#define DB_LOCK_NOWAIT 0x002 /* Don't wait on unavailable lock. */ +#define DB_LOCK_RECORD 0x004 /* Internal: record lock. */ +#define DB_LOCK_REMOVE 0x008 /* Internal: flag object removed. */ +#define DB_LOCK_SET_TIMEOUT 0x010 /* Internal: set lock timeout. */ +#define DB_LOCK_SWITCH 0x020 /* Internal: switch existing lock. */ +#define DB_LOCK_UPGRADE 0x040 /* Internal: upgrade existing lock. */ + +/* + * Simple R/W lock modes and for multi-granularity intention locking. + * + * !!! + * These values are NOT random, as they are used as an index into the lock + * conflicts arrays, i.e., DB_LOCK_IWRITE must be == 3, and DB_LOCK_IREAD + * must be == 4. + */ +typedef enum { + DB_LOCK_NG=0, /* Not granted. */ + DB_LOCK_READ=1, /* Shared/read. */ + DB_LOCK_WRITE=2, /* Exclusive/write. */ + DB_LOCK_WAIT=3, /* Wait for event */ + DB_LOCK_IWRITE=4, /* Intent exclusive/write. */ + DB_LOCK_IREAD=5, /* Intent to share/read. */ + DB_LOCK_IWR=6, /* Intent to read and write. */ + DB_LOCK_DIRTY=7, /* Dirty Read. */ + DB_LOCK_WWRITE=8 /* Was Written. */ +} db_lockmode_t; + +/* + * Request types. + */ +typedef enum { + DB_LOCK_DUMP=0, /* Display held locks. */ + DB_LOCK_GET=1, /* Get the lock. */ + DB_LOCK_GET_TIMEOUT=2, /* Get lock with a timeout. */ + DB_LOCK_INHERIT=3, /* Pass locks to parent. */ + DB_LOCK_PUT=4, /* Release the lock. */ + DB_LOCK_PUT_ALL=5, /* Release locker's locks. */ + DB_LOCK_PUT_OBJ=6, /* Release locker's locks on obj. */ + DB_LOCK_PUT_READ=7, /* Release locker's read locks. */ + DB_LOCK_TIMEOUT=8, /* Force a txn to timeout. */ + DB_LOCK_TRADE=9, /* Trade locker ids on a lock. */ + DB_LOCK_UPGRADE_WRITE=10 /* Upgrade writes for dirty reads. */ +} db_lockop_t; + +/* + * Status of a lock. + */ +typedef enum { + DB_LSTAT_ABORTED=1, /* Lock belongs to an aborted txn. */ + DB_LSTAT_EXPIRED=2, /* Lock has expired. */ + DB_LSTAT_FREE=3, /* Lock is unallocated. */ + DB_LSTAT_HELD=4, /* Lock is currently held. */ + DB_LSTAT_NOTEXIST=5, /* Object on which lock was waiting + * was removed */ + DB_LSTAT_PENDING=6, /* Lock was waiting and has been + * promoted; waiting for the owner + * to run and upgrade it to held. */ + DB_LSTAT_WAITING=7 /* Lock is on the wait queue. */ +}db_status_t; + +/* Lock statistics structure. */ +struct __db_lock_stat { + u_int32_t st_id; /* Last allocated locker ID. */ + u_int32_t st_cur_maxid; /* Current maximum unused ID. */ + u_int32_t st_maxlocks; /* Maximum number of locks in table. */ + u_int32_t st_maxlockers; /* Maximum num of lockers in table. */ + u_int32_t st_maxobjects; /* Maximum num of objects in table. */ + int st_nmodes; /* Number of lock modes. */ + u_int32_t st_nlocks; /* Current number of locks. */ + u_int32_t st_maxnlocks; /* Maximum number of locks so far. */ + u_int32_t st_nlockers; /* Current number of lockers. */ + u_int32_t st_maxnlockers; /* Maximum number of lockers so far. */ + u_int32_t st_nobjects; /* Current number of objects. */ + u_int32_t st_maxnobjects; /* Maximum number of objects so far. */ + u_int32_t st_nconflicts; /* Number of lock conflicts. */ + u_int32_t st_nrequests; /* Number of lock gets. */ + u_int32_t st_nreleases; /* Number of lock puts. */ + u_int32_t st_nnowaits; /* Number of requests that would have + waited, but NOWAIT was set. */ + u_int32_t st_ndeadlocks; /* Number of lock deadlocks. */ + db_timeout_t st_locktimeout; /* Lock timeout. */ + u_int32_t st_nlocktimeouts; /* Number of lock timeouts. */ + db_timeout_t st_txntimeout; /* Transaction timeout. */ + u_int32_t st_ntxntimeouts; /* Number of transaction timeouts. */ + u_int32_t st_region_wait; /* Region lock granted after wait. */ + u_int32_t st_region_nowait; /* Region lock granted without wait. */ + roff_t st_regsize; /* Region size. */ +}; + +/* + * DB_LOCK_ILOCK -- + * Internal DB access method lock. + */ +struct __db_ilock { + db_pgno_t pgno; /* Page being locked. */ + u_int8_t fileid[DB_FILE_ID_LEN];/* File id. */ +#define DB_HANDLE_LOCK 1 +#define DB_RECORD_LOCK 2 +#define DB_PAGE_LOCK 3 + u_int32_t type; /* Type of lock. */ +}; + +/* + * DB_LOCK -- + * The structure is allocated by the caller and filled in during a + * lock_get request (or a lock_vec/DB_LOCK_GET). + */ +struct __db_lock_u { + roff_t off; /* Offset of the lock in the region */ + u_int32_t ndx; /* Index of the object referenced by + * this lock; used for locking. */ + u_int32_t gen; /* Generation number of this lock. */ + db_lockmode_t mode; /* mode of this lock. */ +}; + +/* Lock request structure. */ +struct __db_lockreq { + db_lockop_t op; /* Operation. */ + db_lockmode_t mode; /* Requested mode. */ + db_timeout_t timeout; /* Time to expire lock. */ + DBT *obj; /* Object being locked. */ + DB_LOCK lock; /* Lock returned. */ +}; + +/******************************************************* + * Logging. + *******************************************************/ +#define DB_LOGVERSION 10 /* Current log version. */ +#define DB_LOGOLDVER 10 /* Oldest log version supported. */ +#define DB_LOGMAGIC 0x040988 + +/* Flag values for DB_ENV->log_archive(). */ +#define DB_ARCH_ABS 0x001 /* Absolute pathnames. */ +#define DB_ARCH_DATA 0x002 /* Data files. */ +#define DB_ARCH_LOG 0x004 /* Log files. */ +#define DB_ARCH_REMOVE 0x008 /* Remove log files. */ + +/* Flag values for DB_ENV->log_put(). */ +#define DB_FLUSH 0x001 /* Flush data to disk (public). */ +#define DB_LOG_CHKPNT 0x002 /* Flush supports a checkpoint */ +#define DB_LOG_COMMIT 0x004 /* Flush supports a commit */ +#define DB_LOG_NOCOPY 0x008 /* Don't copy data */ +#define DB_LOG_NOT_DURABLE 0x010 /* Do not log; keep in memory */ +#define DB_LOG_PERM 0x020 /* Flag record with REP_PERMANENT */ +#define DB_LOG_RESEND 0x040 /* Resent log record */ +#define DB_LOG_WRNOSYNC 0x080 /* Write, don't sync log_put */ + +/* + * A DB_LSN has two parts, a fileid which identifies a specific file, and an + * offset within that file. The fileid is an unsigned 4-byte quantity that + * uniquely identifies a file within the log directory -- currently a simple + * counter inside the log. The offset is also an unsigned 4-byte value. The + * log manager guarantees the offset is never more than 4 bytes by switching + * to a new log file before the maximum length imposed by an unsigned 4-byte + * offset is reached. + */ +struct __db_lsn { + u_int32_t file; /* File ID. */ + u_int32_t offset; /* File offset. */ +}; + +/* + * Application-specified log record types start at DB_user_BEGIN, and must not + * equal or exceed DB_debug_FLAG. + * + * DB_debug_FLAG is the high-bit of the u_int32_t that specifies a log record + * type. If the flag is set, it's a log record that was logged for debugging + * purposes only, even if it reflects a database change -- the change was part + * of a non-durable transaction. + */ +#define DB_user_BEGIN 10000 +#define DB_debug_FLAG 0x80000000 + +/* + * DB_LOGC -- + * Log cursor. + */ +struct __db_log_cursor { + DB_ENV *dbenv; /* Enclosing dbenv. */ + + DB_FH *c_fhp; /* File handle. */ + DB_LSN c_lsn; /* Cursor: LSN */ + u_int32_t c_len; /* Cursor: record length */ + u_int32_t c_prev; /* Cursor: previous record's offset */ + + DBT c_dbt; /* Return DBT. */ + +#define DB_LOGC_BUF_SIZE (32 * 1024) + u_int8_t *bp; /* Allocated read buffer. */ + u_int32_t bp_size; /* Read buffer length in bytes. */ + u_int32_t bp_rlen; /* Read buffer valid data length. */ + DB_LSN bp_lsn; /* Read buffer first byte LSN. */ + + u_int32_t bp_maxrec; /* Max record length in the log file. */ + + /* Methods. */ + int (*close) __P((DB_LOGC *, u_int32_t)); + int (*get) __P((DB_LOGC *, DB_LSN *, DBT *, u_int32_t)); + +#define DB_LOG_DISK 0x01 /* Log record came from disk. */ +#define DB_LOG_LOCKED 0x02 /* Log region already locked */ +#define DB_LOG_SILENT_ERR 0x04 /* Turn-off error messages. */ + u_int32_t flags; +}; + +/* Log statistics structure. */ +struct __db_log_stat { + u_int32_t st_magic; /* Log file magic number. */ + u_int32_t st_version; /* Log file version number. */ + int st_mode; /* Log file mode. */ + u_int32_t st_lg_bsize; /* Log buffer size. */ + u_int32_t st_lg_size; /* Log file size. */ + u_int32_t st_w_bytes; /* Bytes to log. */ + u_int32_t st_w_mbytes; /* Megabytes to log. */ + u_int32_t st_wc_bytes; /* Bytes to log since checkpoint. */ + u_int32_t st_wc_mbytes; /* Megabytes to log since checkpoint. */ + u_int32_t st_wcount; /* Total writes to the log. */ + u_int32_t st_wcount_fill; /* Overflow writes to the log. */ + u_int32_t st_scount; /* Total syncs to the log. */ + u_int32_t st_region_wait; /* Region lock granted after wait. */ + u_int32_t st_region_nowait; /* Region lock granted without wait. */ + u_int32_t st_cur_file; /* Current log file number. */ + u_int32_t st_cur_offset; /* Current log file offset. */ + u_int32_t st_disk_file; /* Known on disk log file number. */ + u_int32_t st_disk_offset; /* Known on disk log file offset. */ + roff_t st_regsize; /* Region size. */ + u_int32_t st_maxcommitperflush; /* Max number of commits in a flush. */ + u_int32_t st_mincommitperflush; /* Min number of commits in a flush. */ +}; + +/* + * We need to record the first log record of a transaction. + * For user defined logging this macro returns the place to + * put that information, if it is need in rlsnp, otherwise it + * leaves it unchanged. + */ +#define DB_SET_BEGIN_LSNP(txn, rlsnp) ((txn)->set_begin_lsnp(txn, rlsnp)) + +/******************************************************* + * Shared buffer cache (mpool). + *******************************************************/ +/* Flag values for DB_MPOOLFILE->get. */ +#define DB_MPOOL_CREATE 0x001 /* Create a page. */ +#define DB_MPOOL_LAST 0x002 /* Return the last page. */ +#define DB_MPOOL_NEW 0x004 /* Create a new page. */ + +/* Flag values for DB_MPOOLFILE->put, DB_MPOOLFILE->set. */ +#define DB_MPOOL_CLEAN 0x001 /* Page is not modified. */ +#define DB_MPOOL_DIRTY 0x002 /* Page is modified. */ +#define DB_MPOOL_DISCARD 0x004 /* Don't cache the page. */ +#define DB_MPOOL_FREE 0x008 /* Free page if present. */ + +/* Flags values for DB_MPOOLFILE->set_flags. */ +#define DB_MPOOL_NOFILE 0x001 /* Never open a backing file. */ +#define DB_MPOOL_UNLINK 0x002 /* Unlink the file on last close. */ + +/* Priority values for DB_MPOOLFILE->set_priority. */ +typedef enum { + DB_PRIORITY_VERY_LOW=1, + DB_PRIORITY_LOW=2, + DB_PRIORITY_DEFAULT=3, + DB_PRIORITY_HIGH=4, + DB_PRIORITY_VERY_HIGH=5 +} DB_CACHE_PRIORITY; + +/* Per-process DB_MPOOLFILE information. */ +struct __db_mpoolfile { + DB_FH *fhp; /* Underlying file handle. */ + + /* + * !!! + * The ref, pinref and q fields are protected by the region lock. + */ + u_int32_t ref; /* Reference count. */ + + u_int32_t pinref; /* Pinned block reference count. */ + + /* + * !!! + * Explicit representations of structures from queue.h. + * TAILQ_ENTRY(__db_mpoolfile) q; + */ + struct { + struct __db_mpoolfile *tqe_next; + struct __db_mpoolfile **tqe_prev; + } q; /* Linked list of DB_MPOOLFILE's. */ + + /* + * !!! + * The rest of the fields (with the exception of the MP_FLUSH flag) + * are not thread-protected, even when they may be modified at any + * time by the application. The reason is the DB_MPOOLFILE handle + * is single-threaded from the viewpoint of the application, and so + * the only fields needing to be thread-protected are those accessed + * by checkpoint or sync threads when using DB_MPOOLFILE structures + * to flush buffers from the cache. + */ + DB_ENV *dbenv; /* Overlying DB_ENV. */ + MPOOLFILE *mfp; /* Underlying MPOOLFILE. */ + + u_int32_t clear_len; /* Cleared length on created pages. */ + u_int8_t /* Unique file ID. */ + fileid[DB_FILE_ID_LEN]; + int ftype; /* File type. */ + int32_t lsn_offset; /* LSN offset in page. */ + u_int32_t gbytes, bytes; /* Maximum file size. */ + DBT *pgcookie; /* Byte-string passed to pgin/pgout. */ + DB_CACHE_PRIORITY /* Cache priority. */ + priority; + + void *addr; /* Address of mmap'd region. */ + size_t len; /* Length of mmap'd region. */ + + u_int32_t config_flags; /* Flags to DB_MPOOLFILE->set_flags. */ + + /* Methods. */ + int (*close) __P((DB_MPOOLFILE *, u_int32_t)); + int (*get) __P((DB_MPOOLFILE *, db_pgno_t *, u_int32_t, void *)); + int (*open) __P((DB_MPOOLFILE *, const char *, u_int32_t, int, size_t)); + int (*put) __P((DB_MPOOLFILE *, void *, u_int32_t)); + int (*set) __P((DB_MPOOLFILE *, void *, u_int32_t)); + int (*get_clear_len) __P((DB_MPOOLFILE *, u_int32_t *)); + int (*set_clear_len) __P((DB_MPOOLFILE *, u_int32_t)); + int (*get_fileid) __P((DB_MPOOLFILE *, u_int8_t *)); + int (*set_fileid) __P((DB_MPOOLFILE *, u_int8_t *)); + int (*get_flags) __P((DB_MPOOLFILE *, u_int32_t *)); + int (*set_flags) __P((DB_MPOOLFILE *, u_int32_t, int)); + int (*get_ftype) __P((DB_MPOOLFILE *, int *)); + int (*set_ftype) __P((DB_MPOOLFILE *, int)); + int (*get_lsn_offset) __P((DB_MPOOLFILE *, int32_t *)); + int (*set_lsn_offset) __P((DB_MPOOLFILE *, int32_t)); + int (*get_maxsize) __P((DB_MPOOLFILE *, u_int32_t *, u_int32_t *)); + int (*set_maxsize) __P((DB_MPOOLFILE *, u_int32_t, u_int32_t)); + int (*get_pgcookie) __P((DB_MPOOLFILE *, DBT *)); + int (*set_pgcookie) __P((DB_MPOOLFILE *, DBT *)); + int (*get_priority) __P((DB_MPOOLFILE *, DB_CACHE_PRIORITY *)); + int (*set_priority) __P((DB_MPOOLFILE *, DB_CACHE_PRIORITY)); + int (*sync) __P((DB_MPOOLFILE *)); + + /* + * MP_FILEID_SET, MP_OPEN_CALLED and MP_READONLY do not need to be + * thread protected because they are initialized before the file is + * linked onto the per-process lists, and never modified. + * + * MP_FLUSH is thread protected because it is potentially read/set by + * multiple threads of control. + */ +#define MP_FILEID_SET 0x001 /* Application supplied a file ID. */ +#define MP_FLUSH 0x002 /* Was opened to flush a buffer. */ +#define MP_OPEN_CALLED 0x004 /* File opened. */ +#define MP_READONLY 0x008 /* File is readonly. */ + u_int32_t flags; +}; + +/* Mpool statistics structure. */ +struct __db_mpool_stat { + u_int32_t st_gbytes; /* Total cache size: GB. */ + u_int32_t st_bytes; /* Total cache size: B. */ + u_int32_t st_ncache; /* Number of caches. */ + roff_t st_regsize; /* Region size. */ + size_t st_mmapsize; /* Maximum file size for mmap. */ + int st_maxopenfd; /* Maximum number of open fd's. */ + int st_maxwrite; /* Maximum buffers to write. */ + int st_maxwrite_sleep; /* Sleep after writing max buffers. */ + u_int32_t st_map; /* Pages from mapped files. */ + u_int32_t st_cache_hit; /* Pages found in the cache. */ + u_int32_t st_cache_miss; /* Pages not found in the cache. */ + u_int32_t st_page_create; /* Pages created in the cache. */ + u_int32_t st_page_in; /* Pages read in. */ + u_int32_t st_page_out; /* Pages written out. */ + u_int32_t st_ro_evict; /* Clean pages forced from the cache. */ + u_int32_t st_rw_evict; /* Dirty pages forced from the cache. */ + u_int32_t st_page_trickle; /* Pages written by memp_trickle. */ + u_int32_t st_pages; /* Total number of pages. */ + u_int32_t st_page_clean; /* Clean pages. */ + u_int32_t st_page_dirty; /* Dirty pages. */ + u_int32_t st_hash_buckets; /* Number of hash buckets. */ + u_int32_t st_hash_searches; /* Total hash chain searches. */ + u_int32_t st_hash_longest; /* Longest hash chain searched. */ + u_int32_t st_hash_examined; /* Total hash entries searched. */ + u_int32_t st_hash_nowait; /* Hash lock granted with nowait. */ + u_int32_t st_hash_wait; /* Hash lock granted after wait. */ + u_int32_t st_hash_max_wait; /* Max hash lock granted after wait. */ + u_int32_t st_region_nowait; /* Region lock granted with nowait. */ + u_int32_t st_region_wait; /* Region lock granted after wait. */ + u_int32_t st_alloc; /* Number of page allocations. */ + u_int32_t st_alloc_buckets; /* Buckets checked during allocation. */ + u_int32_t st_alloc_max_buckets; /* Max checked during allocation. */ + u_int32_t st_alloc_pages; /* Pages checked during allocation. */ + u_int32_t st_alloc_max_pages; /* Max checked during allocation. */ +}; + +/* Mpool file statistics structure. */ +struct __db_mpool_fstat { + char *file_name; /* File name. */ + u_int32_t st_pagesize; /* Page size. */ + u_int32_t st_map; /* Pages from mapped files. */ + u_int32_t st_cache_hit; /* Pages found in the cache. */ + u_int32_t st_cache_miss; /* Pages not found in the cache. */ + u_int32_t st_page_create; /* Pages created in the cache. */ + u_int32_t st_page_in; /* Pages read in. */ + u_int32_t st_page_out; /* Pages written out. */ +}; + +/******************************************************* + * Transactions and recovery. + *******************************************************/ +#define DB_TXNVERSION 1 + +typedef enum { + DB_TXN_ABORT=0, /* Public. */ + DB_TXN_APPLY=1, /* Public. */ + DB_TXN_BACKWARD_ALLOC=2, /* Internal. */ + DB_TXN_BACKWARD_ROLL=3, /* Public. */ + DB_TXN_FORWARD_ROLL=4, /* Public. */ + DB_TXN_OPENFILES=5, /* Internal. */ + DB_TXN_POPENFILES=6, /* Internal. */ + DB_TXN_PRINT=7 /* Public. */ +} db_recops; + +/* + * BACKWARD_ALLOC is used during the forward pass to pick up any aborted + * allocations for files that were created during the forward pass. + * The main difference between _ALLOC and _ROLL is that the entry for + * the file not exist during the rollforward pass. + */ +#define DB_UNDO(op) ((op) == DB_TXN_ABORT || \ + (op) == DB_TXN_BACKWARD_ROLL || (op) == DB_TXN_BACKWARD_ALLOC) +#define DB_REDO(op) ((op) == DB_TXN_FORWARD_ROLL || (op) == DB_TXN_APPLY) + +struct __db_txn { + DB_TXNMGR *mgrp; /* Pointer to transaction manager. */ + DB_TXN *parent; /* Pointer to transaction's parent. */ + DB_LSN last_lsn; /* Lsn of last log write. */ + u_int32_t txnid; /* Unique transaction id. */ + u_int32_t tid; /* Thread id for use in MT XA. */ + roff_t off; /* Detail structure within region. */ + db_timeout_t lock_timeout; /* Timeout for locks for this txn. */ + db_timeout_t expire; /* Time this txn expires. */ + void *txn_list; /* Undo information for parent. */ + + /* + * !!! + * Explicit representations of structures from queue.h. + * TAILQ_ENTRY(__db_txn) links; + * TAILQ_ENTRY(__db_txn) xalinks; + */ + struct { + struct __db_txn *tqe_next; + struct __db_txn **tqe_prev; + } links; /* Links transactions off manager. */ + struct { + struct __db_txn *tqe_next; + struct __db_txn **tqe_prev; + } xalinks; /* Links active XA transactions. */ + + /* + * !!! + * Explicit representations of structures from queue.h. + * TAILQ_HEAD(__events, __txn_event) events; + */ + struct { + struct __txn_event *tqh_first; + struct __txn_event **tqh_last; + } events; + + /* + * !!! + * Explicit representations of structures from queue.h. + * STAILQ_HEAD(__logrec, __txn_logrec) logs; + */ + struct { + struct __txn_logrec *stqh_first; + struct __txn_logrec **stqh_last; + } logs; /* Links deferred events. */ + + /* + * !!! + * Explicit representations of structures from queue.h. + * TAILQ_HEAD(__kids, __db_txn) kids; + */ + struct __kids { + struct __db_txn *tqh_first; + struct __db_txn **tqh_last; + } kids; + + /* + * !!! + * Explicit representations of structures from queue.h. + * TAILQ_ENTRY(__db_txn) klinks; + */ + struct { + struct __db_txn *tqe_next; + struct __db_txn **tqe_prev; + } klinks; + + void *api_internal; /* C++ API private. */ + void *xml_internal; /* XML API private. */ + + u_int32_t cursors; /* Number of cursors open for txn */ + + /* Methods. */ + int (*abort) __P((DB_TXN *)); + int (*commit) __P((DB_TXN *, u_int32_t)); + int (*discard) __P((DB_TXN *, u_int32_t)); + u_int32_t (*id) __P((DB_TXN *)); + int (*prepare) __P((DB_TXN *, u_int8_t *)); + void (*set_begin_lsnp) __P((DB_TXN *txn, DB_LSN **)); + int (*set_timeout) __P((DB_TXN *, db_timeout_t, u_int32_t)); + +#define TXN_CHILDCOMMIT 0x001 /* Transaction that has committed. */ +#define TXN_COMPENSATE 0x002 /* Compensating transaction. */ +#define TXN_DEADLOCK 0x004 /* Transaction has deadlocked. */ +#define TXN_DEGREE_2 0x008 /* Has degree 2 isolation. */ +#define TXN_DIRTY_READ 0x010 /* Transaction does dirty reads. */ +#define TXN_LOCKTIMEOUT 0x020 /* Transaction has a lock timeout. */ +#define TXN_MALLOC 0x040 /* Structure allocated by TXN system. */ +#define TXN_NOSYNC 0x080 /* Do not sync on prepare and commit. */ +#define TXN_NOWAIT 0x100 /* Do not wait on locks. */ +#define TXN_RESTORED 0x200 /* Transaction has been restored. */ +#define TXN_SYNC 0x400 /* Sync on prepare and commit. */ + u_int32_t flags; +}; + +/* + * Structure used for two phase commit interface. Berkeley DB support for two + * phase commit is compatible with the X/open XA interface. + * + * The XA #define XIDDATASIZE defines the size of a global transaction ID. We + * have our own version here (for name space reasons) which must have the same + * value. + */ +#define DB_XIDDATASIZE 128 +struct __db_preplist { + DB_TXN *txn; + u_int8_t gid[DB_XIDDATASIZE]; +}; + +/* Transaction statistics structure. */ +struct __db_txn_active { + u_int32_t txnid; /* Transaction ID */ + u_int32_t parentid; /* Transaction ID of parent */ + DB_LSN lsn; /* LSN when transaction began */ + u_int32_t xa_status; /* XA status */ + u_int8_t xid[DB_XIDDATASIZE]; /* XA global transaction ID */ +}; + +struct __db_txn_stat { + DB_LSN st_last_ckp; /* lsn of the last checkpoint */ + time_t st_time_ckp; /* time of last checkpoint */ + u_int32_t st_last_txnid; /* last transaction id given out */ + u_int32_t st_maxtxns; /* maximum txns possible */ + u_int32_t st_naborts; /* number of aborted transactions */ + u_int32_t st_nbegins; /* number of begun transactions */ + u_int32_t st_ncommits; /* number of committed transactions */ + u_int32_t st_nactive; /* number of active transactions */ + u_int32_t st_nrestores; /* number of restored transactions + after recovery. */ + u_int32_t st_maxnactive; /* maximum active transactions */ + DB_TXN_ACTIVE *st_txnarray; /* array of active transactions */ + u_int32_t st_region_wait; /* Region lock granted after wait. */ + u_int32_t st_region_nowait; /* Region lock granted without wait. */ + roff_t st_regsize; /* Region size. */ +}; + +/******************************************************* + * Replication. + *******************************************************/ +/* Special, out-of-band environment IDs. */ +#define DB_EID_BROADCAST -1 +#define DB_EID_INVALID -2 + +/* rep_start flags values */ +#define DB_REP_CLIENT 0x001 +#define DB_REP_MASTER 0x002 + +/* Replication statistics. */ +struct __db_rep_stat { + /* !!! + * Many replication statistics fields cannot be protected by a mutex + * without an unacceptable performance penalty, since most message + * processing is done without the need to hold a region-wide lock. + * Fields whose comments end with a '+' may be updated without holding + * the replication or log mutexes (as appropriate), and thus may be + * off somewhat (or, on unreasonable architectures under unlucky + * circumstances, garbaged). + */ + u_int32_t st_status; /* Current replication status. */ + DB_LSN st_next_lsn; /* Next LSN to use or expect. */ + DB_LSN st_waiting_lsn; /* LSN we're awaiting, if any. */ + db_pgno_t st_next_pg; /* Next pg we expect. */ + db_pgno_t st_waiting_pg; /* pg we're awaiting, if any. */ + + u_int32_t st_dupmasters; /* # of times a duplicate master + condition was detected.+ */ + int st_env_id; /* Current environment ID. */ + int st_env_priority; /* Current environment priority. */ + u_int32_t st_gen; /* Current generation number. */ + u_int32_t st_egen; /* Current election gen number. */ + u_int32_t st_log_duplicated; /* Log records received multiply.+ */ + u_int32_t st_log_queued; /* Log records currently queued.+ */ + u_int32_t st_log_queued_max; /* Max. log records queued at once.+ */ + u_int32_t st_log_queued_total; /* Total # of log recs. ever queued.+ */ + u_int32_t st_log_records; /* Log records received and put.+ */ + u_int32_t st_log_requested; /* Log recs. missed and requested.+ */ + int st_master; /* Env. ID of the current master. */ + u_int32_t st_master_changes; /* # of times we've switched masters. */ + u_int32_t st_msgs_badgen; /* Messages with a bad generation #.+ */ + u_int32_t st_msgs_processed; /* Messages received and processed.+ */ + u_int32_t st_msgs_recover; /* Messages ignored because this site + was a client in recovery.+ */ + u_int32_t st_msgs_send_failures;/* # of failed message sends.+ */ + u_int32_t st_msgs_sent; /* # of successful message sends.+ */ + u_int32_t st_newsites; /* # of NEWSITE msgs. received.+ */ + int st_nsites; /* Current number of sites we will + assume during elections. */ + u_int32_t st_nthrottles; /* # of times we were throttled. */ + u_int32_t st_outdated; /* # of times we detected and returned + an OUTDATED condition.+ */ + u_int32_t st_pg_duplicated; /* Pages received multiply.+ */ + u_int32_t st_pg_records; /* Pages received and stored.+ */ + u_int32_t st_pg_requested; /* Pages missed and requested.+ */ + u_int32_t st_startup_complete; /* Site completed client sync-up. */ + u_int32_t st_txns_applied; /* # of transactions applied.+ */ + + /* Elections generally. */ + u_int32_t st_elections; /* # of elections held.+ */ + u_int32_t st_elections_won; /* # of elections won by this site.+ */ + + /* Statistics about an in-progress election. */ + int st_election_cur_winner; /* Current front-runner. */ + u_int32_t st_election_gen; /* Election generation number. */ + DB_LSN st_election_lsn; /* Max. LSN of current winner. */ + int st_election_nsites; /* # of "registered voters". */ + int st_election_nvotes; /* # of "registered voters" needed. */ + int st_election_priority; /* Current election priority. */ + int st_election_status; /* Current election status. */ + u_int32_t st_election_tiebreaker;/* Election tiebreaker value. */ + int st_election_votes; /* Votes received in this round. */ +}; +/* + * The storage record for a sequence. + */ +struct __db_seq_record { + u_int32_t seq_version; /* Version size/number. */ +#define DB_SEQ_DEC 0x00000001 /* Decrement sequence. */ +#define DB_SEQ_INC 0x00000002 /* Increment sequence. */ +#define DB_SEQ_RANGE_SET 0x00000004 /* Range set (internal). */ +#define DB_SEQ_WRAP 0x00000008 /* Wrap sequence at min/max. */ + u_int32_t flags; /* Flags. */ + db_seq_t seq_value; /* Current value. */ + db_seq_t seq_max; /* Max permitted. */ + db_seq_t seq_min; /* Min permitted. */ +}; + +/* + * Handle for a sequence object. + */ +struct __db_sequence { + DB *seq_dbp; /* DB handle for this sequence. */ + DB_MUTEX *seq_mutexp; /* Mutex if sequence is threaded. */ + DB_SEQ_RECORD *seq_rp; /* Pointer to current data. */ + DB_SEQ_RECORD seq_record; /* Data from DB_SEQUENCE. */ + int32_t seq_cache_size; /* Number of values cached. */ + db_seq_t seq_last_value; /* Last value cached. */ + DBT seq_key; /* DBT pointing to sequence key. */ + DBT seq_data; /* DBT pointing to seq_record. */ + + /* API-private structure: used by C++ and Java. */ + void *api_internal; + + int (*close) __P((DB_SEQUENCE *, u_int32_t)); + int (*get) __P((DB_SEQUENCE *, + DB_TXN *, int32_t, db_seq_t *, u_int32_t)); + int (*get_cachesize) __P((DB_SEQUENCE *, int32_t *)); + int (*get_db) __P((DB_SEQUENCE *, DB **)); + int (*get_flags) __P((DB_SEQUENCE *, u_int32_t *)); + int (*get_key) __P((DB_SEQUENCE *, DBT *)); + int (*get_range) __P((DB_SEQUENCE *, + db_seq_t *, db_seq_t *)); + int (*initial_value) __P((DB_SEQUENCE *, db_seq_t)); + int (*open) __P((DB_SEQUENCE *, + DB_TXN *, DBT *, u_int32_t)); + int (*remove) __P((DB_SEQUENCE *, DB_TXN *, u_int32_t)); + int (*set_cachesize) __P((DB_SEQUENCE *, int32_t)); + int (*set_flags) __P((DB_SEQUENCE *, u_int32_t)); + int (*set_range) __P((DB_SEQUENCE *, db_seq_t, db_seq_t)); + int (*stat) __P((DB_SEQUENCE *, + DB_SEQUENCE_STAT **, u_int32_t)); + int (*stat_print) __P((DB_SEQUENCE *, u_int32_t)); +}; + +struct __db_seq_stat { + u_int32_t st_wait; /* Sequence lock granted without wait. */ + u_int32_t st_nowait; /* Sequence lock granted after wait. */ + db_seq_t st_current; /* Current value in db. */ + db_seq_t st_value; /* Current cached value. */ + db_seq_t st_last_value; /* Last cached value. */ + db_seq_t st_min; /* Minimum value. */ + db_seq_t st_max; /* Maximum value. */ + int32_t st_cache_size; /* Cache size. */ + u_int32_t st_flags; /* Flag value. */ +}; + +/******************************************************* + * Access methods. + *******************************************************/ +typedef enum { + DB_BTREE=1, + DB_HASH=2, + DB_RECNO=3, + DB_QUEUE=4, + DB_UNKNOWN=5 /* Figure it out on open. */ +} DBTYPE; + +#define DB_RENAMEMAGIC 0x030800 /* File has been renamed. */ + +#define DB_BTREEVERSION 9 /* Current btree version. */ +#define DB_BTREEOLDVER 8 /* Oldest btree version supported. */ +#define DB_BTREEMAGIC 0x053162 + +#define DB_HASHVERSION 8 /* Current hash version. */ +#define DB_HASHOLDVER 7 /* Oldest hash version supported. */ +#define DB_HASHMAGIC 0x061561 + +#define DB_QAMVERSION 4 /* Current queue version. */ +#define DB_QAMOLDVER 3 /* Oldest queue version supported. */ +#define DB_QAMMAGIC 0x042253 + +#define DB_SEQUENCE_VERSION 2 /* Current sequence version. */ +#define DB_SEQUENCE_OLDVER 1 /* Oldest queue version supported. */ + +/* + * DB access method and cursor operation values. Each value is an operation + * code to which additional bit flags are added. + */ +#define DB_AFTER 1 /* c_put() */ +#define DB_APPEND 2 /* put() */ +#define DB_BEFORE 3 /* c_put() */ +#define DB_CACHED_COUNTS 4 /* stat() */ +#define DB_CONSUME 5 /* get() */ +#define DB_CONSUME_WAIT 6 /* get() */ +#define DB_CURRENT 7 /* c_get(), c_put(), DB_LOGC->get() */ +#define DB_FAST_STAT 8 /* stat() */ +#define DB_FIRST 9 /* c_get(), DB_LOGC->get() */ +#define DB_GET_BOTH 10 /* get(), c_get() */ +#define DB_GET_BOTHC 11 /* c_get() (internal) */ +#define DB_GET_BOTH_RANGE 12 /* get(), c_get() */ +#define DB_GET_RECNO 13 /* c_get() */ +#define DB_JOIN_ITEM 14 /* c_get(); do not do primary lookup */ +#define DB_KEYFIRST 15 /* c_put() */ +#define DB_KEYLAST 16 /* c_put() */ +#define DB_LAST 17 /* c_get(), DB_LOGC->get() */ +#define DB_NEXT 18 /* c_get(), DB_LOGC->get() */ +#define DB_NEXT_DUP 19 /* c_get() */ +#define DB_NEXT_NODUP 20 /* c_get() */ +#define DB_NODUPDATA 21 /* put(), c_put() */ +#define DB_NOOVERWRITE 22 /* put() */ +#define DB_NOSYNC 23 /* close() */ +#define DB_POSITION 24 /* c_dup() */ +#define DB_PREV 25 /* c_get(), DB_LOGC->get() */ +#define DB_PREV_NODUP 26 /* c_get(), DB_LOGC->get() */ +#define DB_RECORDCOUNT 27 /* stat() */ +#define DB_SET 28 /* c_get(), DB_LOGC->get() */ +#define DB_SET_LOCK_TIMEOUT 29 /* set_timout() */ +#define DB_SET_RANGE 30 /* c_get() */ +#define DB_SET_RECNO 31 /* get(), c_get() */ +#define DB_SET_TXN_NOW 32 /* set_timout() (internal) */ +#define DB_SET_TXN_TIMEOUT 33 /* set_timout() */ +#define DB_UPDATE_SECONDARY 34 /* c_get(), c_del() (internal) */ +#define DB_WRITECURSOR 35 /* cursor() */ +#define DB_WRITELOCK 36 /* cursor() (internal) */ + +/* This has to change when the max opcode hits 255. */ +#define DB_OPFLAGS_MASK 0x000000ff /* Mask for operations flags. */ + +/* + * Masks for flags that can be OR'd into DB access method and cursor + * operation values. + * + * DB_DIRTY_READ 0x04000000 Dirty Read. */ +#define DB_MULTIPLE 0x08000000 /* Return multiple data values. */ +#define DB_MULTIPLE_KEY 0x10000000 /* Return multiple data/key pairs. */ +#define DB_RMW 0x20000000 /* Acquire write flag immediately. */ + +/* + * DB (user visible) error return codes. + * + * !!! + * For source compatibility with DB 2.X deadlock return (EAGAIN), use the + * following: + * #include + * #define DB_LOCK_DEADLOCK EAGAIN + * + * !!! + * We don't want our error returns to conflict with other packages where + * possible, so pick a base error value that's hopefully not common. We + * document that we own the error name space from -30,800 to -30,999. + */ +/* DB (public) error return codes. */ +#define DB_BUFFER_SMALL (-30999)/* User memory too small for return. */ +#define DB_DONOTINDEX (-30998)/* "Null" return from 2ndary callbk. */ +#define DB_KEYEMPTY (-30997)/* Key/data deleted or never created. */ +#define DB_KEYEXIST (-30996)/* The key/data pair already exists. */ +#define DB_LOCK_DEADLOCK (-30995)/* Deadlock. */ +#define DB_LOCK_NOTGRANTED (-30994)/* Lock unavailable. */ +#define DB_LOG_BUFFER_FULL (-30993)/* In-memory log buffer full. */ +#define DB_NOSERVER (-30992)/* Server panic return. */ +#define DB_NOSERVER_HOME (-30991)/* Bad home sent to server. */ +#define DB_NOSERVER_ID (-30990)/* Bad ID sent to server. */ +#define DB_NOTFOUND (-30989)/* Key/data pair not found (EOF). */ +#define DB_OLD_VERSION (-30988)/* Out-of-date version. */ +#define DB_PAGE_NOTFOUND (-30987)/* Requested page not found. */ +#define DB_REP_DUPMASTER (-30986)/* There are two masters. */ +#define DB_REP_HANDLE_DEAD (-30985)/* Rolled back a commit. */ +#define DB_REP_HOLDELECTION (-30984)/* Time to hold an election. */ +#define DB_REP_ISPERM (-30983)/* Cached not written perm written.*/ +#define DB_REP_NEWMASTER (-30982)/* We have learned of a new master. */ +#define DB_REP_NEWSITE (-30981)/* New site entered system. */ +#define DB_REP_NOTPERM (-30980)/* Permanent log record not written. */ +#define DB_REP_STARTUPDONE (-30979)/* Client startup complete. */ +#define DB_REP_UNAVAIL (-30978)/* Site cannot currently be reached. */ +#define DB_RUNRECOVERY (-30977)/* Panic return. */ +#define DB_SECONDARY_BAD (-30976)/* Secondary index corrupt. */ +#define DB_VERIFY_BAD (-30975)/* Verify failed; bad format. */ +#define DB_VERSION_MISMATCH (-30974)/* Environment version mismatch. */ + +/* DB (private) error return codes. */ +#define DB_ALREADY_ABORTED (-30899) +#define DB_DELETED (-30898)/* Recovery file marked deleted. */ +#define DB_LOCK_NOTEXIST (-30897)/* Object to lock is gone. */ +#define DB_NEEDSPLIT (-30896)/* Page needs to be split. */ +#define DB_REP_EGENCHG (-30895)/* Egen changed while in election. */ +#define DB_REP_LOGREADY (-30894)/* Rep log ready for recovery. */ +#define DB_REP_PAGEDONE (-30893)/* This page was already done. */ +#define DB_SURPRISE_KID (-30892)/* Child commit where parent + didn't know it was a parent. */ +#define DB_SWAPBYTES (-30891)/* Database needs byte swapping. */ +#define DB_TIMEOUT (-30890)/* Timed out waiting for election. */ +#define DB_TXN_CKP (-30889)/* Encountered ckp record in log. */ +#define DB_VERIFY_FATAL (-30888)/* DB->verify cannot proceed. */ + +/* Database handle. */ +struct __db { + /******************************************************* + * Public: owned by the application. + *******************************************************/ + u_int32_t pgsize; /* Database logical page size. */ + + /* Callbacks. */ + int (*db_append_recno) __P((DB *, DBT *, db_recno_t)); + void (*db_feedback) __P((DB *, int, int)); + int (*dup_compare) __P((DB *, const DBT *, const DBT *)); + + void *app_private; /* Application-private handle. */ + + /******************************************************* + * Private: owned by DB. + *******************************************************/ + DB_ENV *dbenv; /* Backing environment. */ + + DBTYPE type; /* DB access method type. */ + + DB_MPOOLFILE *mpf; /* Backing buffer pool. */ + + DB_MUTEX *mutexp; /* Synchronization for free threading */ + + char *fname, *dname; /* File/database passed to DB->open. */ + u_int32_t open_flags; /* Flags passed to DB->open. */ + + u_int8_t fileid[DB_FILE_ID_LEN];/* File's unique ID for locking. */ + + u_int32_t adj_fileid; /* File's unique ID for curs. adj. */ + +#define DB_LOGFILEID_INVALID -1 + FNAME *log_filename; /* File's naming info for logging. */ + + db_pgno_t meta_pgno; /* Meta page number */ + u_int32_t lid; /* Locker id for handle locking. */ + u_int32_t cur_lid; /* Current handle lock holder. */ + u_int32_t associate_lid; /* Locker id for DB->associate call. */ + DB_LOCK handle_lock; /* Lock held on this handle. */ + + u_int cl_id; /* RPC: remote client id. */ + + time_t timestamp; /* Handle timestamp for replication. */ + + /* + * Returned data memory for DB->get() and friends. + */ + DBT my_rskey; /* Secondary key. */ + DBT my_rkey; /* [Primary] key. */ + DBT my_rdata; /* Data. */ + + /* + * !!! + * Some applications use DB but implement their own locking outside of + * DB. If they're using fcntl(2) locking on the underlying database + * file, and we open and close a file descriptor for that file, we will + * discard their locks. The DB_FCNTL_LOCKING flag to DB->open is an + * undocumented interface to support this usage which leaves any file + * descriptors we open until DB->close. This will only work with the + * DB->open interface and simple caches, e.g., creating a transaction + * thread may open/close file descriptors this flag doesn't protect. + * Locking with fcntl(2) on a file that you don't own is a very, very + * unsafe thing to do. 'Nuff said. + */ + DB_FH *saved_open_fhp; /* Saved file handle. */ + + /* + * Linked list of DBP's, linked from the DB_ENV, used to keep track + * of all open db handles for cursor adjustment. + * + * !!! + * Explicit representations of structures from queue.h. + * LIST_ENTRY(__db) dblistlinks; + */ + struct { + struct __db *le_next; + struct __db **le_prev; + } dblistlinks; + + /* + * Cursor queues. + * + * !!! + * Explicit representations of structures from queue.h. + * TAILQ_HEAD(__cq_fq, __dbc) free_queue; + * TAILQ_HEAD(__cq_aq, __dbc) active_queue; + * TAILQ_HEAD(__cq_jq, __dbc) join_queue; + */ + struct __cq_fq { + struct __dbc *tqh_first; + struct __dbc **tqh_last; + } free_queue; + struct __cq_aq { + struct __dbc *tqh_first; + struct __dbc **tqh_last; + } active_queue; + struct __cq_jq { + struct __dbc *tqh_first; + struct __dbc **tqh_last; + } join_queue; + + /* + * Secondary index support. + * + * Linked list of secondary indices -- set in the primary. + * + * !!! + * Explicit representations of structures from queue.h. + * LIST_HEAD(s_secondaries, __db); + */ + struct { + struct __db *lh_first; + } s_secondaries; + + /* + * List entries for secondaries, and reference count of how + * many threads are updating this secondary (see __db_c_put). + * + * !!! + * Note that these are synchronized by the primary's mutex, but + * filled in in the secondaries. + * + * !!! + * Explicit representations of structures from queue.h. + * LIST_ENTRY(__db) s_links; + */ + struct { + struct __db *le_next; + struct __db **le_prev; + } s_links; + u_int32_t s_refcnt; + + /* Secondary callback and free functions -- set in the secondary. */ + int (*s_callback) __P((DB *, const DBT *, const DBT *, DBT *)); + + /* Reference to primary -- set in the secondary. */ + DB *s_primary; + + /* API-private structure: used by DB 1.85, C++, Java, Perl and Tcl */ + void *api_internal; + + /* Subsystem-private structure. */ + void *bt_internal; /* Btree/Recno access method. */ + void *h_internal; /* Hash access method. */ + void *q_internal; /* Queue access method. */ + void *xa_internal; /* XA. */ + + /* Methods. */ + int (*associate) __P((DB *, DB_TXN *, DB *, int (*)(DB *, const DBT *, + const DBT *, DBT *), u_int32_t)); + int (*close) __P((DB *, u_int32_t)); + int (*cursor) __P((DB *, DB_TXN *, DBC **, u_int32_t)); + int (*del) __P((DB *, DB_TXN *, DBT *, u_int32_t)); + int (*dump) __P((DB *, + const char *, int (*)(void *, const void *), void *, int, int)); + void (*err) __P((DB *, int, const char *, ...)); + void (*errx) __P((DB *, const char *, ...)); + int (*fd) __P((DB *, int *)); + int (*get) __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t)); + int (*pget) __P((DB *, DB_TXN *, DBT *, DBT *, DBT *, u_int32_t)); + int (*get_byteswapped) __P((DB *, int *)); + int (*get_cachesize) __P((DB *, u_int32_t *, u_int32_t *, int *)); + int (*get_dbname) __P((DB *, const char **, const char **)); + int (*get_encrypt_flags) __P((DB *, u_int32_t *)); + DB_ENV *(*get_env) __P((DB *)); + void (*get_errfile) __P((DB *, FILE **)); + void (*get_errpfx) __P((DB *, const char **)); + int (*get_flags) __P((DB *, u_int32_t *)); + int (*get_lorder) __P((DB *, int *)); + int (*get_open_flags) __P((DB *, u_int32_t *)); + int (*get_pagesize) __P((DB *, u_int32_t *)); + int (*get_transactional) __P((DB *)); + int (*get_type) __P((DB *, DBTYPE *)); + int (*join) __P((DB *, DBC **, DBC **, u_int32_t)); + int (*key_range) __P((DB *, + DB_TXN *, DBT *, DB_KEY_RANGE *, u_int32_t)); + int (*open) __P((DB *, DB_TXN *, + const char *, const char *, DBTYPE, u_int32_t, int)); + int (*put) __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t)); + int (*remove) __P((DB *, const char *, const char *, u_int32_t)); + int (*rename) __P((DB *, + const char *, const char *, const char *, u_int32_t)); + int (*truncate) __P((DB *, DB_TXN *, u_int32_t *, u_int32_t)); + int (*set_append_recno) __P((DB *, int (*)(DB *, DBT *, db_recno_t))); + int (*set_alloc) __P((DB *, void *(*)(size_t), + void *(*)(void *, size_t), void (*)(void *))); + int (*set_cachesize) __P((DB *, u_int32_t, u_int32_t, int)); + int (*set_dup_compare) __P((DB *, + int (*)(DB *, const DBT *, const DBT *))); + int (*set_encrypt) __P((DB *, const char *, u_int32_t)); + void (*set_errcall) __P((DB *, + void (*)(const DB_ENV *, const char *, const char *))); + void (*set_errfile) __P((DB *, FILE *)); + void (*set_errpfx) __P((DB *, const char *)); + int (*set_feedback) __P((DB *, void (*)(DB *, int, int))); + int (*set_flags) __P((DB *, u_int32_t)); + int (*set_lorder) __P((DB *, int)); + void (*set_msgcall) __P((DB *, void (*)(const DB_ENV *, const char *))); + void (*get_msgfile) __P((DB *, FILE **)); + void (*set_msgfile) __P((DB *, FILE *)); + int (*set_pagesize) __P((DB *, u_int32_t)); + int (*set_paniccall) __P((DB *, void (*)(DB_ENV *, int))); + int (*stat) __P((DB *, DB_TXN *, void *, u_int32_t)); + int (*stat_print) __P((DB *, u_int32_t)); + int (*sync) __P((DB *, u_int32_t)); + int (*upgrade) __P((DB *, const char *, u_int32_t)); + int (*verify) __P((DB *, + const char *, const char *, FILE *, u_int32_t)); + + int (*get_bt_minkey) __P((DB *, u_int32_t *)); + int (*set_bt_compare) __P((DB *, + int (*)(DB *, const DBT *, const DBT *))); + int (*set_bt_maxkey) __P((DB *, u_int32_t)); + int (*set_bt_minkey) __P((DB *, u_int32_t)); + int (*set_bt_prefix) __P((DB *, + size_t (*)(DB *, const DBT *, const DBT *))); + + int (*get_h_ffactor) __P((DB *, u_int32_t *)); + int (*get_h_nelem) __P((DB *, u_int32_t *)); + int (*set_h_ffactor) __P((DB *, u_int32_t)); + int (*set_h_hash) __P((DB *, + u_int32_t (*)(DB *, const void *, u_int32_t))); + int (*set_h_nelem) __P((DB *, u_int32_t)); + + int (*get_re_delim) __P((DB *, int *)); + int (*get_re_len) __P((DB *, u_int32_t *)); + int (*get_re_pad) __P((DB *, int *)); + int (*get_re_source) __P((DB *, const char **)); + int (*set_re_delim) __P((DB *, int)); + int (*set_re_len) __P((DB *, u_int32_t)); + int (*set_re_pad) __P((DB *, int)); + int (*set_re_source) __P((DB *, const char *)); + + int (*get_q_extentsize) __P((DB *, u_int32_t *)); + int (*set_q_extentsize) __P((DB *, u_int32_t)); + + int (*db_am_remove) __P((DB *, DB_TXN *, const char *, const char *)); + int (*db_am_rename) __P((DB *, DB_TXN *, + const char *, const char *, const char *)); + + /* + * Never called; these are a place to save function pointers + * so that we can undo an associate. + */ + int (*stored_get) __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t)); + int (*stored_close) __P((DB *, u_int32_t)); + +#define DB_OK_BTREE 0x01 +#define DB_OK_HASH 0x02 +#define DB_OK_QUEUE 0x04 +#define DB_OK_RECNO 0x08 + u_int32_t am_ok; /* Legal AM choices. */ + +#define DB_AM_CHKSUM 0x00000001 /* Checksumming. */ +#define DB_AM_CL_WRITER 0x00000002 /* Allow writes in client replica. */ +#define DB_AM_COMPENSATE 0x00000004 /* Created by compensating txn. */ +#define DB_AM_CREATED 0x00000008 /* Database was created upon open. */ +#define DB_AM_CREATED_MSTR 0x00000010 /* Encompassing file was created. */ +#define DB_AM_DBM_ERROR 0x00000020 /* Error in DBM/NDBM database. */ +#define DB_AM_DELIMITER 0x00000040 /* Variable length delimiter set. */ +#define DB_AM_DIRTY 0x00000080 /* Support Dirty Reads. */ +#define DB_AM_DISCARD 0x00000100 /* Discard any cached pages. */ +#define DB_AM_DUP 0x00000200 /* DB_DUP. */ +#define DB_AM_DUPSORT 0x00000400 /* DB_DUPSORT. */ +#define DB_AM_ENCRYPT 0x00000800 /* Encryption. */ +#define DB_AM_FIXEDLEN 0x00001000 /* Fixed-length records. */ +#define DB_AM_INMEM 0x00002000 /* In-memory; no sync on close. */ +#define DB_AM_INORDER 0x00004000 /* DB_INORDER. */ +#define DB_AM_IN_RENAME 0x00008000 /* File is being renamed. */ +#define DB_AM_NOT_DURABLE 0x00010000 /* Do not log changes. */ +#define DB_AM_OPEN_CALLED 0x00020000 /* DB->open called. */ +#define DB_AM_PAD 0x00040000 /* Fixed-length record pad. */ +#define DB_AM_PGDEF 0x00080000 /* Page size was defaulted. */ +#define DB_AM_RDONLY 0x00100000 /* Database is readonly. */ +#define DB_AM_RECNUM 0x00200000 /* DB_RECNUM. */ +#define DB_AM_RECOVER 0x00400000 /* DB opened by recovery routine. */ +#define DB_AM_RENUMBER 0x00800000 /* DB_RENUMBER. */ +#define DB_AM_REPLICATION 0x01000000 /* An internal replication file. */ +#define DB_AM_REVSPLITOFF 0x02000000 /* DB_REVSPLITOFF. */ +#define DB_AM_SECONDARY 0x04000000 /* Database is a secondary index. */ +#define DB_AM_SNAPSHOT 0x08000000 /* DB_SNAPSHOT. */ +#define DB_AM_SUBDB 0x10000000 /* Subdatabases supported. */ +#define DB_AM_SWAP 0x20000000 /* Pages need to be byte-swapped. */ +#define DB_AM_TXN 0x40000000 /* Opened in a transaction. */ +#define DB_AM_VERIFYING 0x80000000 /* DB handle is in the verifier. */ + u_int32_t orig_flags; /* Flags at open, for refresh. */ + u_int32_t flags; +}; + +/* + * Macros for bulk get. These are only intended for the C API. + * For C++, use DbMultiple*Iterator. + */ +#define DB_MULTIPLE_INIT(pointer, dbt) \ + (pointer = (u_int8_t *)(dbt)->data + \ + (dbt)->ulen - sizeof(u_int32_t)) +#define DB_MULTIPLE_NEXT(pointer, dbt, retdata, retdlen) \ + do { \ + if (*((u_int32_t *)(pointer)) == (u_int32_t)-1) { \ + retdata = NULL; \ + pointer = NULL; \ + break; \ + } \ + retdata = (u_int8_t *) \ + (dbt)->data + *(u_int32_t *)(pointer); \ + (pointer) = (u_int32_t *)(pointer) - 1; \ + retdlen = *(u_int32_t *)(pointer); \ + (pointer) = (u_int32_t *)(pointer) - 1; \ + if (retdlen == 0 && \ + retdata == (u_int8_t *)(dbt)->data) \ + retdata = NULL; \ + } while (0) +#define DB_MULTIPLE_KEY_NEXT(pointer, dbt, retkey, retklen, retdata, retdlen) \ + do { \ + if (*((u_int32_t *)(pointer)) == (u_int32_t)-1) { \ + retdata = NULL; \ + retkey = NULL; \ + pointer = NULL; \ + break; \ + } \ + retkey = (u_int8_t *) \ + (dbt)->data + *(u_int32_t *)(pointer); \ + (pointer) = (u_int32_t *)(pointer) - 1; \ + retklen = *(u_int32_t *)(pointer); \ + (pointer) = (u_int32_t *)(pointer) - 1; \ + retdata = (u_int8_t *) \ + (dbt)->data + *(u_int32_t *)(pointer); \ + (pointer) = (u_int32_t *)(pointer) - 1; \ + retdlen = *(u_int32_t *)(pointer); \ + (pointer) = (u_int32_t *)(pointer) - 1; \ + } while (0) + +#define DB_MULTIPLE_RECNO_NEXT(pointer, dbt, recno, retdata, retdlen) \ + do { \ + if (*((u_int32_t *)(pointer)) == (u_int32_t)0) { \ + recno = 0; \ + retdata = NULL; \ + pointer = NULL; \ + break; \ + } \ + recno = *(u_int32_t *)(pointer); \ + (pointer) = (u_int32_t *)(pointer) - 1; \ + retdata = (u_int8_t *) \ + (dbt)->data + *(u_int32_t *)(pointer); \ + (pointer) = (u_int32_t *)(pointer) - 1; \ + retdlen = *(u_int32_t *)(pointer); \ + (pointer) = (u_int32_t *)(pointer) - 1; \ + } while (0) + +/******************************************************* + * Access method cursors. + *******************************************************/ +struct __dbc { + DB *dbp; /* Related DB access method. */ + DB_TXN *txn; /* Associated transaction. */ + + /* + * Active/free cursor queues. + * + * !!! + * Explicit representations of structures from queue.h. + * TAILQ_ENTRY(__dbc) links; + */ + struct { + DBC *tqe_next; + DBC **tqe_prev; + } links; + + /* + * The DBT *'s below are used by the cursor routines to return + * data to the user when DBT flags indicate that DB should manage + * the returned memory. They point at a DBT containing the buffer + * and length that will be used, and "belonging" to the handle that + * should "own" this memory. This may be a "my_*" field of this + * cursor--the default--or it may be the corresponding field of + * another cursor, a DB handle, a join cursor, etc. In general, it + * will be whatever handle the user originally used for the current + * DB interface call. + */ + DBT *rskey; /* Returned secondary key. */ + DBT *rkey; /* Returned [primary] key. */ + DBT *rdata; /* Returned data. */ + + DBT my_rskey; /* Space for returned secondary key. */ + DBT my_rkey; /* Space for returned [primary] key. */ + DBT my_rdata; /* Space for returned data. */ + + u_int32_t lid; /* Default process' locker id. */ + u_int32_t locker; /* Locker for this operation. */ + DBT lock_dbt; /* DBT referencing lock. */ + DB_LOCK_ILOCK lock; /* Object to be locked. */ + DB_LOCK mylock; /* CDB lock held on this cursor. */ + + u_int cl_id; /* Remote client id. */ + + DBTYPE dbtype; /* Cursor type. */ + + DBC_INTERNAL *internal; /* Access method private. */ + + int (*c_close) __P((DBC *)); /* Methods: public. */ + int (*c_count) __P((DBC *, db_recno_t *, u_int32_t)); + int (*c_del) __P((DBC *, u_int32_t)); + int (*c_dup) __P((DBC *, DBC **, u_int32_t)); + int (*c_get) __P((DBC *, DBT *, DBT *, u_int32_t)); + int (*c_pget) __P((DBC *, DBT *, DBT *, DBT *, u_int32_t)); + int (*c_put) __P((DBC *, DBT *, DBT *, u_int32_t)); + + /* Methods: private. */ + int (*c_am_bulk) __P((DBC *, DBT *, u_int32_t)); + int (*c_am_close) __P((DBC *, db_pgno_t, int *)); + int (*c_am_del) __P((DBC *)); + int (*c_am_destroy) __P((DBC *)); + int (*c_am_get) __P((DBC *, DBT *, DBT *, u_int32_t, db_pgno_t *)); + int (*c_am_put) __P((DBC *, DBT *, DBT *, u_int32_t, db_pgno_t *)); + int (*c_am_writelock) __P((DBC *)); + +#define DBC_ACTIVE 0x0001 /* Cursor in use. */ +#define DBC_COMPENSATE 0x0002 /* Cursor compensating, don't lock. */ +#define DBC_DEGREE_2 0x0004 /* Cursor has degree 2 isolation. */ +#define DBC_DIRTY_READ 0x0008 /* Cursor supports dirty reads. */ +#define DBC_OPD 0x0010 /* Cursor references off-page dups. */ +#define DBC_RECOVER 0x0020 /* Recovery cursor; don't log/lock. */ +#define DBC_RMW 0x0040 /* Acquire write flag in read op. */ +#define DBC_TRANSIENT 0x0080 /* Cursor is transient. */ +#define DBC_WRITECURSOR 0x0100 /* Cursor may be used to write (CDB). */ +#define DBC_WRITER 0x0200 /* Cursor immediately writing (CDB). */ +#define DBC_MULTIPLE 0x0400 /* Return Multiple data. */ +#define DBC_MULTIPLE_KEY 0x0800 /* Return Multiple keys and data. */ +#define DBC_OWN_LID 0x1000 /* Free lock id on destroy. */ + u_int32_t flags; +}; + +/* Key range statistics structure */ +struct __key_range { + double less; + double equal; + double greater; +}; + +/* Btree/Recno statistics structure. */ +struct __db_bt_stat { + u_int32_t bt_magic; /* Magic number. */ + u_int32_t bt_version; /* Version number. */ + u_int32_t bt_metaflags; /* Metadata flags. */ + u_int32_t bt_nkeys; /* Number of unique keys. */ + u_int32_t bt_ndata; /* Number of data items. */ + u_int32_t bt_pagesize; /* Page size. */ + u_int32_t bt_maxkey; /* Maxkey value. */ + u_int32_t bt_minkey; /* Minkey value. */ + u_int32_t bt_re_len; /* Fixed-length record length. */ + u_int32_t bt_re_pad; /* Fixed-length record pad. */ + u_int32_t bt_levels; /* Tree levels. */ + u_int32_t bt_int_pg; /* Internal pages. */ + u_int32_t bt_leaf_pg; /* Leaf pages. */ + u_int32_t bt_dup_pg; /* Duplicate pages. */ + u_int32_t bt_over_pg; /* Overflow pages. */ + u_int32_t bt_empty_pg; /* Empty pages. */ + u_int32_t bt_free; /* Pages on the free list. */ + u_int32_t bt_int_pgfree; /* Bytes free in internal pages. */ + u_int32_t bt_leaf_pgfree; /* Bytes free in leaf pages. */ + u_int32_t bt_dup_pgfree; /* Bytes free in duplicate pages. */ + u_int32_t bt_over_pgfree; /* Bytes free in overflow pages. */ +}; + +/* Hash statistics structure. */ +struct __db_h_stat { + u_int32_t hash_magic; /* Magic number. */ + u_int32_t hash_version; /* Version number. */ + u_int32_t hash_metaflags; /* Metadata flags. */ + u_int32_t hash_nkeys; /* Number of unique keys. */ + u_int32_t hash_ndata; /* Number of data items. */ + u_int32_t hash_pagesize; /* Page size. */ + u_int32_t hash_ffactor; /* Fill factor specified at create. */ + u_int32_t hash_buckets; /* Number of hash buckets. */ + u_int32_t hash_free; /* Pages on the free list. */ + u_int32_t hash_bfree; /* Bytes free on bucket pages. */ + u_int32_t hash_bigpages; /* Number of big key/data pages. */ + u_int32_t hash_big_bfree; /* Bytes free on big item pages. */ + u_int32_t hash_overflows; /* Number of overflow pages. */ + u_int32_t hash_ovfl_free; /* Bytes free on ovfl pages. */ + u_int32_t hash_dup; /* Number of dup pages. */ + u_int32_t hash_dup_free; /* Bytes free on duplicate pages. */ +}; + +/* Queue statistics structure. */ +struct __db_qam_stat { + u_int32_t qs_magic; /* Magic number. */ + u_int32_t qs_version; /* Version number. */ + u_int32_t qs_metaflags; /* Metadata flags. */ + u_int32_t qs_nkeys; /* Number of unique keys. */ + u_int32_t qs_ndata; /* Number of data items. */ + u_int32_t qs_pagesize; /* Page size. */ + u_int32_t qs_extentsize; /* Pages per extent. */ + u_int32_t qs_pages; /* Data pages. */ + u_int32_t qs_re_len; /* Fixed-length record length. */ + u_int32_t qs_re_pad; /* Fixed-length record pad. */ + u_int32_t qs_pgfree; /* Bytes free in data pages. */ + u_int32_t qs_first_recno; /* First not deleted record. */ + u_int32_t qs_cur_recno; /* Next available record number. */ +}; + +/******************************************************* + * Environment. + *******************************************************/ +#define DB_REGION_MAGIC 0x120897 /* Environment magic number. */ + +/* Database Environment handle. */ +struct __db_env { + /******************************************************* + * Public: owned by the application. + *******************************************************/ + /* Error message callback. */ + void (*db_errcall) __P((const DB_ENV *, const char *, const char *)); + FILE *db_errfile; /* Error message file stream. */ + const char *db_errpfx; /* Error message prefix. */ + + FILE *db_msgfile; /* Statistics message file stream. */ + /* Statistics message callback. */ + void (*db_msgcall) __P((const DB_ENV *, const char *)); + + /* Other Callbacks. */ + void (*db_feedback) __P((DB_ENV *, int, int)); + void (*db_paniccall) __P((DB_ENV *, int)); + + /* App-specified alloc functions. */ + void *(*db_malloc) __P((size_t)); + void *(*db_realloc) __P((void *, size_t)); + void (*db_free) __P((void *)); + + /* + * Currently, the verbose list is a bit field with room for 32 + * entries. There's no reason that it needs to be limited, if + * there are ever more than 32 entries, convert to a bit array. + */ +#define DB_VERB_DEADLOCK 0x0001 /* Deadlock detection information. */ +#define DB_VERB_RECOVERY 0x0002 /* Recovery information. */ +#define DB_VERB_REPLICATION 0x0004 /* Replication information. */ +#define DB_VERB_WAITSFOR 0x0008 /* Dump waits-for table. */ + u_int32_t verbose; /* Verbose output. */ + + void *app_private; /* Application-private handle. */ + + int (*app_dispatch) /* User-specified recovery dispatch. */ + __P((DB_ENV *, DBT *, DB_LSN *, db_recops)); + + /* Locking. */ + u_int8_t *lk_conflicts; /* Two dimensional conflict matrix. */ + int lk_modes; /* Number of lock modes in table. */ + u_int32_t lk_max; /* Maximum number of locks. */ + u_int32_t lk_max_lockers;/* Maximum number of lockers. */ + u_int32_t lk_max_objects;/* Maximum number of locked objects. */ + u_int32_t lk_detect; /* Deadlock detect on all conflicts. */ + db_timeout_t lk_timeout; /* Lock timeout period. */ + + /* Logging. */ + u_int32_t lg_bsize; /* Buffer size. */ + u_int32_t lg_size; /* Log file size. */ + u_int32_t lg_regionmax; /* Region size. */ + + /* Memory pool. */ + u_int32_t mp_gbytes; /* Cachesize: GB. */ + u_int32_t mp_bytes; /* Cachesize: Bytes. */ + u_int mp_ncache; /* Number of cache regions. */ + size_t mp_mmapsize; /* Maximum file size for mmap. */ + int mp_maxopenfd; /* Maximum open file descriptors. */ + int mp_maxwrite; /* Maximum buffers to write. */ + int /* Sleep after writing max buffers. */ + mp_maxwrite_sleep; + + /* Replication */ + int rep_eid; /* environment id. */ + int (*rep_send) /* Send function. */ + __P((DB_ENV *, const DBT *, const DBT *, + const DB_LSN *, int, u_int32_t)); + + /* Transactions. */ + u_int32_t tx_max; /* Maximum number of transactions. */ + time_t tx_timestamp; /* Recover to specific timestamp. */ + db_timeout_t tx_timeout; /* Timeout for transactions. */ + + /******************************************************* + * Private: owned by DB. + *******************************************************/ + /* User files, paths. */ + char *db_home; /* Database home. */ + char *db_log_dir; /* Database log file directory. */ + char *db_tmp_dir; /* Database tmp file directory. */ + + char **db_data_dir; /* Database data file directories. */ + int data_cnt; /* Database data file slots. */ + int data_next; /* Next Database data file slot. */ + + int db_mode; /* Default open permissions. */ + int dir_mode; /* Intermediate directory perms. */ + u_int32_t env_lid; /* Locker ID in non-threaded handles. */ + u_int32_t open_flags; /* Flags passed to DB_ENV->open. */ + + void *reginfo; /* REGINFO structure reference. */ + DB_FH *lockfhp; /* fcntl(2) locking file handle. */ + + int (**recover_dtab) /* Dispatch table for recover funcs. */ + __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + size_t recover_dtab_size; + /* Slots in the dispatch table. */ + + void *cl_handle; /* RPC: remote client handle. */ + u_int cl_id; /* RPC: remote client env id. */ + + int db_ref; /* DB reference count. */ + + long shm_key; /* shmget(2) key. */ + u_int32_t tas_spins; /* test-and-set spins. */ + + /* + * List of open DB handles for this DB_ENV, used for cursor + * adjustment. Must be protected for multi-threaded support. + * + * !!! + * As this structure is allocated in per-process memory, the + * mutex may need to be stored elsewhere on architectures unable + * to support mutexes in heap memory, e.g. HP/UX 9. + * + * !!! + * Explicit representation of structure in queue.h. + * LIST_HEAD(dblist, __db); + */ + DB_MUTEX *dblist_mutexp; /* Mutex. */ + struct { + struct __db *lh_first; + } dblist; + + /* + * XA support. + * + * !!! + * Explicit representations of structures from queue.h. + * TAILQ_ENTRY(__db_env) links; + * TAILQ_HEAD(xa_txn, __db_txn); + */ + struct { + struct __db_env *tqe_next; + struct __db_env **tqe_prev; + } links; + struct __xa_txn { /* XA Active Transactions. */ + struct __db_txn *tqh_first; + struct __db_txn **tqh_last; + } xa_txn; + int xa_rmid; /* XA Resource Manager ID. */ + + /* API-private structure. */ + void *api1_internal; /* C++, Perl API private */ + void *api2_internal; /* Java API private */ + + char *passwd; /* Cryptography support. */ + size_t passwd_len; + void *crypto_handle; /* Primary handle. */ + DB_MUTEX *mt_mutexp; /* Mersenne Twister mutex. */ + int mti; /* Mersenne Twister index. */ + u_long *mt; /* Mersenne Twister state vector. */ + + /* DB_ENV Methods. */ + int (*close) __P((DB_ENV *, u_int32_t)); + int (*dbremove) __P((DB_ENV *, + DB_TXN *, const char *, const char *, u_int32_t)); + int (*dbrename) __P((DB_ENV *, DB_TXN *, + const char *, const char *, const char *, u_int32_t)); + void (*err) __P((const DB_ENV *, int, const char *, ...)); + void (*errx) __P((const DB_ENV *, const char *, ...)); + int (*open) __P((DB_ENV *, const char *, u_int32_t, int)); + int (*remove) __P((DB_ENV *, const char *, u_int32_t)); + int (*stat_print) __P((DB_ENV *, u_int32_t)); + + /* House-keeping. */ + int (*fileid_reset) __P((DB_ENV *, char *, int)); + int (*is_bigendian) __P((void)); + int (*lsn_reset) __P((DB_ENV *, char *, int)); + int (*prdbt) __P((DBT *, + int, const char *, void *, int (*)(void *, const void *), int)); + + /* Setters/getters. */ + int (*set_alloc) __P((DB_ENV *, void *(*)(size_t), + void *(*)(void *, size_t), void (*)(void *))); + int (*set_app_dispatch) __P((DB_ENV *, + int (*)(DB_ENV *, DBT *, DB_LSN *, db_recops))); + int (*get_data_dirs) __P((DB_ENV *, const char ***)); + int (*set_data_dir) __P((DB_ENV *, const char *)); + int (*get_encrypt_flags) __P((DB_ENV *, u_int32_t *)); + int (*set_encrypt) __P((DB_ENV *, const char *, u_int32_t)); + void (*set_errcall) __P((DB_ENV *, + void (*)(const DB_ENV *, const char *, const char *))); + void (*get_errfile) __P((DB_ENV *, FILE **)); + void (*set_errfile) __P((DB_ENV *, FILE *)); + void (*get_errpfx) __P((DB_ENV *, const char **)); + void (*set_errpfx) __P((DB_ENV *, const char *)); + int (*set_feedback) __P((DB_ENV *, void (*)(DB_ENV *, int, int))); + int (*get_flags) __P((DB_ENV *, u_int32_t *)); + int (*set_flags) __P((DB_ENV *, u_int32_t, int)); + int (*get_home) __P((DB_ENV *, const char **)); + int (*set_intermediate_dir) __P((DB_ENV *, int, u_int32_t)); + int (*get_open_flags) __P((DB_ENV *, u_int32_t *)); + int (*set_paniccall) __P((DB_ENV *, void (*)(DB_ENV *, int))); + int (*set_rpc_server) __P((DB_ENV *, + void *, const char *, long, long, u_int32_t)); + int (*get_shm_key) __P((DB_ENV *, long *)); + int (*set_shm_key) __P((DB_ENV *, long)); + void (*set_msgcall) __P((DB_ENV *, + void (*)(const DB_ENV *, const char *))); + void (*get_msgfile) __P((DB_ENV *, FILE **)); + void (*set_msgfile) __P((DB_ENV *, FILE *)); + int (*get_tas_spins) __P((DB_ENV *, u_int32_t *)); + int (*set_tas_spins) __P((DB_ENV *, u_int32_t)); + int (*get_tmp_dir) __P((DB_ENV *, const char **)); + int (*set_tmp_dir) __P((DB_ENV *, const char *)); + int (*get_verbose) __P((DB_ENV *, u_int32_t, int *)); + int (*set_verbose) __P((DB_ENV *, u_int32_t, int)); + + void *lg_handle; /* Log handle and methods. */ + int (*get_lg_bsize) __P((DB_ENV *, u_int32_t *)); + int (*set_lg_bsize) __P((DB_ENV *, u_int32_t)); + int (*get_lg_dir) __P((DB_ENV *, const char **)); + int (*set_lg_dir) __P((DB_ENV *, const char *)); + int (*get_lg_max) __P((DB_ENV *, u_int32_t *)); + int (*set_lg_max) __P((DB_ENV *, u_int32_t)); + int (*get_lg_regionmax) __P((DB_ENV *, u_int32_t *)); + int (*set_lg_regionmax) __P((DB_ENV *, u_int32_t)); + int (*log_archive) __P((DB_ENV *, char **[], u_int32_t)); + int (*log_cursor) __P((DB_ENV *, DB_LOGC **, u_int32_t)); + int (*log_file) __P((DB_ENV *, const DB_LSN *, char *, size_t)); + int (*log_flush) __P((DB_ENV *, const DB_LSN *)); + int (*log_put) __P((DB_ENV *, DB_LSN *, const DBT *, u_int32_t)); + int (*log_stat) __P((DB_ENV *, DB_LOG_STAT **, u_int32_t)); + int (*log_stat_print) __P((DB_ENV *, u_int32_t)); + + void *lk_handle; /* Lock handle and methods. */ + int (*get_lk_conflicts) __P((DB_ENV *, const u_int8_t **, int *)); + int (*set_lk_conflicts) __P((DB_ENV *, u_int8_t *, int)); + int (*get_lk_detect) __P((DB_ENV *, u_int32_t *)); + int (*set_lk_detect) __P((DB_ENV *, u_int32_t)); + int (*set_lk_max) __P((DB_ENV *, u_int32_t)); + int (*get_lk_max_locks) __P((DB_ENV *, u_int32_t *)); + int (*set_lk_max_locks) __P((DB_ENV *, u_int32_t)); + int (*get_lk_max_lockers) __P((DB_ENV *, u_int32_t *)); + int (*set_lk_max_lockers) __P((DB_ENV *, u_int32_t)); + int (*get_lk_max_objects) __P((DB_ENV *, u_int32_t *)); + int (*set_lk_max_objects) __P((DB_ENV *, u_int32_t)); + int (*lock_detect) __P((DB_ENV *, u_int32_t, u_int32_t, int *)); + int (*lock_get) __P((DB_ENV *, + u_int32_t, u_int32_t, const DBT *, db_lockmode_t, DB_LOCK *)); + int (*lock_put) __P((DB_ENV *, DB_LOCK *)); + int (*lock_id) __P((DB_ENV *, u_int32_t *)); + int (*lock_id_free) __P((DB_ENV *, u_int32_t)); + int (*lock_stat) __P((DB_ENV *, DB_LOCK_STAT **, u_int32_t)); + int (*lock_stat_print) __P((DB_ENV *, u_int32_t)); + int (*lock_vec) __P((DB_ENV *, + u_int32_t, u_int32_t, DB_LOCKREQ *, int, DB_LOCKREQ **)); + + void *mp_handle; /* Mpool handle and methods. */ + int (*get_cachesize) __P((DB_ENV *, u_int32_t *, u_int32_t *, int *)); + int (*set_cachesize) __P((DB_ENV *, u_int32_t, u_int32_t, int)); + int (*get_mp_mmapsize) __P((DB_ENV *, size_t *)); + int (*set_mp_mmapsize) __P((DB_ENV *, size_t)); + int (*get_mp_max_openfd) __P((DB_ENV *, int *)); + int (*set_mp_max_openfd) __P((DB_ENV *, int)); + int (*get_mp_max_write) __P((DB_ENV *, int *, int *)); + int (*set_mp_max_write) __P((DB_ENV *, int, int)); + int (*memp_fcreate) __P((DB_ENV *, DB_MPOOLFILE **, u_int32_t)); + int (*memp_register) __P((DB_ENV *, int, + int (*)(DB_ENV *, db_pgno_t, void *, DBT *), + int (*)(DB_ENV *, db_pgno_t, void *, DBT *))); + int (*memp_stat) __P((DB_ENV *, + DB_MPOOL_STAT **, DB_MPOOL_FSTAT ***, u_int32_t)); + int (*memp_stat_print) __P((DB_ENV *, u_int32_t)); + int (*memp_sync) __P((DB_ENV *, DB_LSN *)); + int (*memp_trickle) __P((DB_ENV *, int, int *)); + + void *rep_handle; /* Replication handle and methods. */ + int (*rep_elect) __P((DB_ENV *, int, int, int, + u_int32_t, int *, u_int32_t)); + int (*rep_flush) __P((DB_ENV *)); + int (*rep_process_message) __P((DB_ENV *, DBT *, DBT *, + int *, DB_LSN *)); + int (*rep_start) __P((DB_ENV *, DBT *, u_int32_t)); + int (*rep_stat) __P((DB_ENV *, DB_REP_STAT **, u_int32_t)); + int (*rep_stat_print) __P((DB_ENV *, u_int32_t)); + int (*get_rep_limit) __P((DB_ENV *, u_int32_t *, u_int32_t *)); + int (*set_rep_limit) __P((DB_ENV *, u_int32_t, u_int32_t)); + int (*set_rep_request) __P((DB_ENV *, u_int32_t, u_int32_t)); + int (*set_rep_transport) __P((DB_ENV *, int, + int (*) (DB_ENV *, const DBT *, const DBT *, const DB_LSN *, + int, u_int32_t))); + + void *tx_handle; /* Txn handle and methods. */ + int (*get_tx_max) __P((DB_ENV *, u_int32_t *)); + int (*set_tx_max) __P((DB_ENV *, u_int32_t)); + int (*get_tx_timestamp) __P((DB_ENV *, time_t *)); + int (*set_tx_timestamp) __P((DB_ENV *, time_t *)); + int (*txn_begin) __P((DB_ENV *, DB_TXN *, DB_TXN **, u_int32_t)); + int (*txn_checkpoint) __P((DB_ENV *, u_int32_t, u_int32_t, u_int32_t)); + int (*txn_recover) __P((DB_ENV *, + DB_PREPLIST *, long, long *, u_int32_t)); + int (*txn_stat) __P((DB_ENV *, DB_TXN_STAT **, u_int32_t)); + int (*txn_stat_print) __P((DB_ENV *, u_int32_t)); + int (*get_timeout) __P((DB_ENV *, db_timeout_t *, u_int32_t)); + int (*set_timeout) __P((DB_ENV *, db_timeout_t, u_int32_t)); + +#define DB_TEST_ELECTINIT 1 /* after __rep_elect_init */ +#define DB_TEST_ELECTVOTE1 2 /* after sending VOTE1 */ +#define DB_TEST_POSTDESTROY 3 /* after destroy op */ +#define DB_TEST_POSTLOG 4 /* after logging all pages */ +#define DB_TEST_POSTLOGMETA 5 /* after logging meta in btree */ +#define DB_TEST_POSTOPEN 6 /* after __os_open */ +#define DB_TEST_POSTSYNC 7 /* after syncing the log */ +#define DB_TEST_PREDESTROY 8 /* before destroy op */ +#define DB_TEST_PREOPEN 9 /* before __os_open */ +#define DB_TEST_SUBDB_LOCKS 10 /* subdb locking tests */ + int test_abort; /* Abort value for testing. */ + int test_check; /* Checkpoint value for testing. */ + int test_copy; /* Copy value for testing. */ + +#define DB_ENV_AUTO_COMMIT 0x0000001 /* DB_AUTO_COMMIT. */ +#define DB_ENV_CDB 0x0000002 /* DB_INIT_CDB. */ +#define DB_ENV_CDB_ALLDB 0x0000004 /* CDB environment wide locking. */ +#define DB_ENV_CREATE 0x0000008 /* DB_CREATE set. */ +#define DB_ENV_DBLOCAL 0x0000010 /* DB_ENV allocated for private DB. */ +#define DB_ENV_DIRECT_DB 0x0000020 /* DB_DIRECT_DB set. */ +#define DB_ENV_DIRECT_LOG 0x0000040 /* DB_DIRECT_LOG set. */ +#define DB_ENV_DSYNC_LOG 0x0000080 /* DB_DSYNC_LOG set. */ +#define DB_ENV_FATAL 0x0000100 /* Doing fatal recovery in env. */ +#define DB_ENV_LOCKDOWN 0x0000200 /* DB_LOCKDOWN set. */ +#define DB_ENV_LOG_AUTOREMOVE 0x0000400 /* DB_LOG_AUTOREMOVE set. */ +#define DB_ENV_LOG_INMEMORY 0x0000800 /* DB_LOG_INMEMORY set. */ +#define DB_ENV_NOLOCKING 0x0001000 /* DB_NOLOCKING set. */ +#define DB_ENV_NOMMAP 0x0002000 /* DB_NOMMAP set. */ +#define DB_ENV_NOPANIC 0x0004000 /* Okay if panic set. */ +#define DB_ENV_OPEN_CALLED 0x0008000 /* DB_ENV->open called. */ +#define DB_ENV_OVERWRITE 0x0010000 /* DB_OVERWRITE set. */ +#define DB_ENV_PRIVATE 0x0020000 /* DB_PRIVATE set. */ +#define DB_ENV_REGION_INIT 0x0040000 /* DB_REGION_INIT set. */ +#define DB_ENV_RPCCLIENT 0x0080000 /* DB_RPCCLIENT set. */ +#define DB_ENV_RPCCLIENT_GIVEN 0x0100000 /* User-supplied RPC client struct */ +#define DB_ENV_SYSTEM_MEM 0x0200000 /* DB_SYSTEM_MEM set. */ +#define DB_ENV_THREAD 0x0400000 /* DB_THREAD set. */ +#define DB_ENV_TIME_NOTGRANTED 0x0800000 /* DB_TIME_NOTGRANTED set. */ +#define DB_ENV_TXN_NOSYNC 0x1000000 /* DB_TXN_NOSYNC set. */ +#define DB_ENV_TXN_WRITE_NOSYNC 0x2000000 /* DB_TXN_WRITE_NOSYNC set. */ +#define DB_ENV_YIELDCPU 0x4000000 /* DB_YIELDCPU set. */ + u_int32_t flags; +}; + +#ifndef DB_DBM_HSEARCH +#define DB_DBM_HSEARCH 0 /* No historic interfaces by default. */ +#endif +#if DB_DBM_HSEARCH != 0 +/******************************************************* + * Dbm/Ndbm historic interfaces. + *******************************************************/ +typedef struct __db DBM; + +#define DBM_INSERT 0 /* Flags to dbm_store(). */ +#define DBM_REPLACE 1 + +/* + * The DB support for ndbm(3) always appends this suffix to the + * file name to avoid overwriting the user's original database. + */ +#define DBM_SUFFIX ".db" + +#if defined(_XPG4_2) +typedef struct { + char *dptr; + size_t dsize; +} datum; +#else +typedef struct { + char *dptr; + int dsize; +} datum; +#endif + +/* + * Translate NDBM calls into DB calls so that DB doesn't step on the + * application's name space. + */ +#define dbm_clearerr(a) __db_ndbm_clearerr(a) +#define dbm_close(a) __db_ndbm_close(a) +#define dbm_delete(a, b) __db_ndbm_delete(a, b) +#define dbm_dirfno(a) __db_ndbm_dirfno(a) +#define dbm_error(a) __db_ndbm_error(a) +#define dbm_fetch(a, b) __db_ndbm_fetch(a, b) +#define dbm_firstkey(a) __db_ndbm_firstkey(a) +#define dbm_nextkey(a) __db_ndbm_nextkey(a) +#define dbm_open(a, b, c) __db_ndbm_open(a, b, c) +#define dbm_pagfno(a) __db_ndbm_pagfno(a) +#define dbm_rdonly(a) __db_ndbm_rdonly(a) +#define dbm_store(a, b, c, d) \ + __db_ndbm_store(a, b, c, d) + +/* + * Translate DBM calls into DB calls so that DB doesn't step on the + * application's name space. + * + * The global variables dbrdonly, dirf and pagf were not retained when 4BSD + * replaced the dbm interface with ndbm, and are not supported here. + */ +#define dbminit(a) __db_dbm_init(a) +#define dbmclose __db_dbm_close +#if !defined(__cplusplus) +#define delete(a) __db_dbm_delete(a) +#endif +#define fetch(a) __db_dbm_fetch(a) +#define firstkey __db_dbm_firstkey +#define nextkey(a) __db_dbm_nextkey(a) +#define store(a, b) __db_dbm_store(a, b) + +/******************************************************* + * Hsearch historic interface. + *******************************************************/ +typedef enum { + FIND, ENTER +} ACTION; + +typedef struct entry { + char *key; + char *data; +} ENTRY; + +#define hcreate(a) __db_hcreate(a) +#define hdestroy __db_hdestroy +#define hsearch(a, b) __db_hsearch(a, b) + +#endif /* DB_DBM_HSEARCH */ + +#if defined(__cplusplus) +} +#endif +#endif /* !_DB_H_ */ + +/* DO NOT EDIT: automatically built by dist/s_include. */ +#ifndef _DB_EXT_PROT_IN_ +#define _DB_EXT_PROT_IN_ + +#if defined(__cplusplus) +extern "C" { +#endif + +int db_create __P((DB **, DB_ENV *, u_int32_t)); +char *db_strerror __P((int)); +int db_env_create __P((DB_ENV **, u_int32_t)); +char *db_version __P((int *, int *, int *)); +int log_compare __P((const DB_LSN *, const DB_LSN *)); +int db_env_set_func_close __P((int (*)(int))); +int db_env_set_func_dirfree __P((void (*)(char **, int))); +int db_env_set_func_dirlist __P((int (*)(const char *, char ***, int *))); +int db_env_set_func_exists __P((int (*)(const char *, int *))); +int db_env_set_func_free __P((void (*)(void *))); +int db_env_set_func_fsync __P((int (*)(int))); +int db_env_set_func_ftruncate __P((int (*)(int, off_t))); +int db_env_set_func_ioinfo __P((int (*)(const char *, int, u_int32_t *, u_int32_t *, u_int32_t *))); +int db_env_set_func_malloc __P((void *(*)(size_t))); +int db_env_set_func_map __P((int (*)(char *, size_t, int, int, void **))); +int db_env_set_func_pread __P((int (*)(int, void *, size_t, off_t))); +int db_env_set_func_pwrite __P((int (*)(int, const void *, size_t, off_t))); +int db_env_set_func_open __P((int (*)(const char *, int, ...))); +int db_env_set_func_read __P((int (*)(int, void *, size_t))); +int db_env_set_func_realloc __P((void *(*)(void *, size_t))); +int db_env_set_func_rename __P((int (*)(const char *, const char *))); +int db_env_set_func_seek __P((int (*)(int, off_t, int))); +int db_env_set_func_sleep __P((int (*)(u_long, u_long))); +int db_env_set_func_unlink __P((int (*)(const char *))); +int db_env_set_func_unmap __P((int (*)(void *, size_t))); +int db_env_set_func_write __P((int (*)(int, const void *, size_t))); +int db_env_set_func_yield __P((int (*)(void))); +int db_sequence_create __P((DB_SEQUENCE **, DB *, u_int32_t)); +#if DB_DBM_HSEARCH != 0 +int __db_ndbm_clearerr __P((DBM *)); +void __db_ndbm_close __P((DBM *)); +int __db_ndbm_delete __P((DBM *, datum)); +int __db_ndbm_dirfno __P((DBM *)); +int __db_ndbm_error __P((DBM *)); +datum __db_ndbm_fetch __P((DBM *, datum)); +datum __db_ndbm_firstkey __P((DBM *)); +datum __db_ndbm_nextkey __P((DBM *)); +DBM *__db_ndbm_open __P((const char *, int, int)); +int __db_ndbm_pagfno __P((DBM *)); +int __db_ndbm_rdonly __P((DBM *)); +int __db_ndbm_store __P((DBM *, datum, datum, int)); +int __db_dbm_close __P((void)); +int __db_dbm_delete __P((datum)); +datum __db_dbm_fetch __P((datum)); +datum __db_dbm_firstkey __P((void)); +int __db_dbm_init __P((char *)); +datum __db_dbm_nextkey __P((datum)); +int __db_dbm_store __P((datum, datum)); +#endif +#if DB_DBM_HSEARCH != 0 +int __db_hcreate __P((size_t)); +ENTRY *__db_hsearch __P((ENTRY, ACTION)); +void __db_hdestroy __P((void)); +#endif + +#if defined(__cplusplus) +} +#endif +#endif /* !_DB_EXT_PROT_IN_ */ diff --git a/lib_dict/bdb/include/db.in b/lib_dict/bdb/include/db.in new file mode 100644 index 000000000..e8e17236c --- /dev/null +++ b/lib_dict/bdb/include/db.in @@ -0,0 +1,2166 @@ +/* + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996-2004 + * Sleepycat Software. All rights reserved. + * + * $Id: db.in,v 11.463 2004/10/11 18:47:50 bostic Exp $ + * + * db.h include file layout: + * General. + * Database Environment. + * Locking subsystem. + * Logging subsystem. + * Shared buffer cache (mpool) subsystem. + * Transaction subsystem. + * Access methods. + * Access method cursors. + * Dbm/Ndbm, Hsearch historic interfaces. + */ + +#ifndef _DB_H_ +#define _DB_H_ + +#ifndef __NO_SYSTEM_INCLUDES +#include +@inttypes_h_decl@ +@stdint_h_decl@ +@stddef_h_decl@ +#include +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + +@DB_CONST@ +@DB_PROTO1@ +@DB_PROTO2@ + +/* + * Berkeley DB version information. + */ +#define DB_VERSION_MAJOR @DB_VERSION_MAJOR@ +#define DB_VERSION_MINOR @DB_VERSION_MINOR@ +#define DB_VERSION_PATCH @DB_VERSION_PATCH@ +#define DB_VERSION_STRING @DB_VERSION_STRING@ + +/* + * !!! + * Berkeley DB uses specifically sized types. If they're not provided by + * the system, typedef them here. + * + * We protect them against multiple inclusion using __BIT_TYPES_DEFINED__, + * as does BIND and Kerberos, since we don't know for sure what #include + * files the user is using. + * + * !!! + * We also provide the standard u_int, u_long etc., if they're not provided + * by the system. + */ +#ifndef __BIT_TYPES_DEFINED__ +#define __BIT_TYPES_DEFINED__ +@u_int8_decl@ +@int16_decl@ +@u_int16_decl@ +@int32_decl@ +@u_int32_decl@ +@int64_decl@ +@u_int64_decl@ +#endif + +@u_char_decl@ +@u_short_decl@ +@u_int_decl@ +@u_long_decl@ +@ssize_t_decl@ + +/* + * uintmax_t -- + * Largest unsigned type, used to align structures in memory. We don't store + * floating point types in structures, so integral types should be sufficient + * (and we don't have to worry about systems that store floats in other than + * power-of-2 numbers of bytes). Additionally this fixes compilers that rewrite + * structure assignments and ANSI C memcpy calls to be in-line instructions + * that happen to require alignment. Note: this alignment isn't sufficient for + * mutexes, which depend on things like cache line alignment. Mutex alignment + * is handled separately, in mutex.h. + * + * uintptr_t -- + * Unsigned type that's the same size as a pointer. There are places where + * DB modifies pointers by discarding the bottom bits to guarantee alignment. + * We can't use uintmax_t, it may be larger than the pointer, and compilers + * get upset about that. So far we haven't run on any machine where there's + * no unsigned type the same size as a pointer -- here's hoping. + */ +@uintmax_t_decl@ +@uintptr_t_decl@ + +/* + * Sequences are only available on machines with 64-bit integral types. + */ +@db_seq_decl@ + +/* Basic types that are exported or quasi-exported. */ +typedef u_int32_t db_pgno_t; /* Page number type. */ +typedef u_int16_t db_indx_t; /* Page offset type. */ +#define DB_MAX_PAGES 0xffffffff /* >= # of pages in a file */ + +typedef u_int32_t db_recno_t; /* Record number type. */ +#define DB_MAX_RECORDS 0xffffffff /* >= # of records in a tree */ + +typedef u_int32_t db_timeout_t; /* Type of a timeout. */ + +/* + * Region offsets are the difference between a pointer in a region and the + * region's base address. With private environments, both addresses are the + * result of calling malloc, and we can't assume anything about what malloc + * will return, so region offsets have to be able to hold differences between + * arbitrary pointers. + */ +typedef uintptr_t roff_t; + +/* + * Forward structure declarations, so we can declare pointers and + * applications can get type checking. + */ +struct __db; typedef struct __db DB; +struct __db_bt_stat; typedef struct __db_bt_stat DB_BTREE_STAT; +struct __db_cipher; typedef struct __db_cipher DB_CIPHER; +struct __db_dbt; typedef struct __db_dbt DBT; +struct __db_env; typedef struct __db_env DB_ENV; +struct __db_h_stat; typedef struct __db_h_stat DB_HASH_STAT; +struct __db_ilock; typedef struct __db_ilock DB_LOCK_ILOCK; +struct __db_lock_stat; typedef struct __db_lock_stat DB_LOCK_STAT; +struct __db_lock_u; typedef struct __db_lock_u DB_LOCK; +struct __db_lockreq; typedef struct __db_lockreq DB_LOCKREQ; +struct __db_log_cursor; typedef struct __db_log_cursor DB_LOGC; +struct __db_log_stat; typedef struct __db_log_stat DB_LOG_STAT; +struct __db_lsn; typedef struct __db_lsn DB_LSN; +struct __db_mpool; typedef struct __db_mpool DB_MPOOL; +struct __db_mpool_fstat;typedef struct __db_mpool_fstat DB_MPOOL_FSTAT; +struct __db_mpool_stat; typedef struct __db_mpool_stat DB_MPOOL_STAT; +struct __db_mpoolfile; typedef struct __db_mpoolfile DB_MPOOLFILE; +struct __db_preplist; typedef struct __db_preplist DB_PREPLIST; +struct __db_qam_stat; typedef struct __db_qam_stat DB_QUEUE_STAT; +struct __db_rep; typedef struct __db_rep DB_REP; +struct __db_rep_stat; typedef struct __db_rep_stat DB_REP_STAT; +struct __db_sequence; typedef struct __db_sequence DB_SEQUENCE; +struct __db_seq_record; typedef struct __db_seq_record DB_SEQ_RECORD; +struct __db_seq_stat; typedef struct __db_seq_stat DB_SEQUENCE_STAT; +struct __db_txn; typedef struct __db_txn DB_TXN; +struct __db_txn_active; typedef struct __db_txn_active DB_TXN_ACTIVE; +struct __db_txn_stat; typedef struct __db_txn_stat DB_TXN_STAT; +struct __db_txnmgr; typedef struct __db_txnmgr DB_TXNMGR; +struct __dbc; typedef struct __dbc DBC; +struct __dbc_internal; typedef struct __dbc_internal DBC_INTERNAL; +struct __fh_t; typedef struct __fh_t DB_FH; +struct __fname; typedef struct __fname FNAME; +struct __key_range; typedef struct __key_range DB_KEY_RANGE; +struct __mpoolfile; typedef struct __mpoolfile MPOOLFILE; +struct __mutex_t; typedef struct __mutex_t DB_MUTEX; + +/* Key/data structure -- a Data-Base Thang. */ +struct __db_dbt { + /* + * data/size must be fields 1 and 2 for DB 1.85 compatibility. + */ + void *data; /* Key/data */ + u_int32_t size; /* key/data length */ + + u_int32_t ulen; /* RO: length of user buffer. */ + u_int32_t dlen; /* RO: get/put record length. */ + u_int32_t doff; /* RO: get/put record offset. */ + +#define DB_DBT_APPMALLOC 0x001 /* Callback allocated memory. */ +#define DB_DBT_ISSET 0x002 /* Lower level calls set value. */ +#define DB_DBT_MALLOC 0x004 /* Return in malloc'd memory. */ +#define DB_DBT_PARTIAL 0x008 /* Partial put/get. */ +#define DB_DBT_REALLOC 0x010 /* Return in realloc'd memory. */ +#define DB_DBT_USERMEM 0x020 /* Return in user's memory. */ +#define DB_DBT_DUPOK 0x040 /* Insert if duplicate. */ + u_int32_t flags; +}; + +/* + * Common flags -- + * Interfaces which use any of these common flags should never have + * interface specific flags in this range. + */ +#define DB_CREATE 0x0000001 /* Create file as necessary. */ +#define DB_CXX_NO_EXCEPTIONS 0x0000002 /* C++: return error values. */ +#define DB_FORCE 0x0000004 /* Force (anything). */ +#define DB_NOMMAP 0x0000008 /* Don't mmap underlying file. */ +#define DB_RDONLY 0x0000010 /* Read-only (O_RDONLY). */ +#define DB_RECOVER 0x0000020 /* Run normal recovery. */ +#define DB_THREAD 0x0000040 /* Applications are threaded. */ +#define DB_TRUNCATE 0x0000080 /* Discard existing DB (O_TRUNC). */ +#define DB_TXN_NOSYNC 0x0000100 /* Do not sync log on commit. */ +#define DB_TXN_NOT_DURABLE 0x0000200 /* Do not log changes. */ +#define DB_USE_ENVIRON 0x0000400 /* Use the environment. */ +#define DB_USE_ENVIRON_ROOT 0x0000800 /* Use the environment if root. */ + +/* + * Common flags -- + * Interfaces which use any of these common flags should never have + * interface specific flags in this range. + * + * DB_AUTO_COMMIT: + * DB_ENV->set_flags, DB->associate, DB->del, DB->put, DB->open, + * DB->remove, DB->rename, DB->truncate + * DB_DEGREE_2: + * DB->cursor, DB->get, DB->join, DBcursor->c_get, DB_ENV->txn_begin + * DB_DIRTY_READ: + * DB->cursor, DB->get, DB->join, DB->open, DBcursor->c_get, + * DB_ENV->txn_begin + * DB_NOAUTO_COMMIT + * DB->associate, DB->del, DB->put, DB->open, + * DB->remove, DB->rename, DB->truncate + * + * !!! + * The DB_DIRTY_READ and DB_DEGREE_2 bit masks can't be changed without + * also changing the masks for the flags that can be OR'd into DB + * access method and cursor operation values. + */ +#define DB_AUTO_COMMIT 0x01000000/* Implied transaction. */ +#define DB_DEGREE_2 0x02000000/* Degree 2. */ +#define DB_DIRTY_READ 0x04000000/* Dirty Read. */ +#define DB_NO_AUTO_COMMIT 0x08000000/* Override env-wide AUTOCOMMIT. */ + +/* + * Flags private to db_env_create. + */ +#define DB_RPCCLIENT 0x0000001 /* An RPC client environment. */ + +/* + * Flags private to db_create. + */ +#define DB_REP_CREATE 0x0000001 /* Open of an internal rep database. */ +#define DB_XA_CREATE 0x0000002 /* Open in an XA environment. */ + +/* + * Flags private to DB_ENV->open. + * Shared flags up to 0x0000800 */ +#define DB_INIT_CDB 0x0001000 /* Concurrent Access Methods. */ +#define DB_INIT_LOCK 0x0002000 /* Initialize locking. */ +#define DB_INIT_LOG 0x0004000 /* Initialize logging. */ +#define DB_INIT_MPOOL 0x0008000 /* Initialize mpool. */ +#define DB_INIT_REP 0x0010000 /* Initialize replication. */ +#define DB_INIT_TXN 0x0020000 /* Initialize transactions. */ +#define DB_JOINENV 0x0040000 /* Initialize all subsystems present. */ +#define DB_LOCKDOWN 0x0080000 /* Lock memory into physical core. */ +#define DB_PRIVATE 0x0100000 /* DB_ENV is process local. */ +#define DB_RECOVER_FATAL 0x0200000 /* Run catastrophic recovery. */ +#define DB_SYSTEM_MEM 0x0400000 /* Use system-backed memory. */ + +/* + * Flags private to DB->open. + * Shared flags up to 0x0000800 */ +#define DB_EXCL 0x0001000 /* Exclusive open (O_EXCL). */ +#define DB_FCNTL_LOCKING 0x0002000 /* UNDOC: fcntl(2) locking. */ +#define DB_RDWRMASTER 0x0004000 /* UNDOC: allow subdb master open R/W */ +#define DB_WRITEOPEN 0x0008000 /* UNDOC: open with write lock. */ + +/* + * Flags private to DB_ENV->txn_begin. + * Shared flags up to 0x0000800 */ +#define DB_TXN_NOWAIT 0x0001000 /* Do not wait for locks in this TXN. */ +#define DB_TXN_SYNC 0x0002000 /* Always sync log on commit. */ + +/* + * Flags private to DB_ENV->set_encrypt. + */ +#define DB_ENCRYPT_AES 0x0000001 /* AES, assumes SHA1 checksum */ + +/* + * Flags private to DB_ENV->set_flags. + * Shared flags up to 0x00000800 */ +#define DB_CDB_ALLDB 0x00001000/* Set CDB locking per environment. */ +#define DB_DIRECT_DB 0x00002000/* Don't buffer databases in the OS. */ +#define DB_DIRECT_LOG 0x00004000/* Don't buffer log files in the OS. */ +#define DB_DSYNC_LOG 0x00008000/* Set O_DSYNC on the log. */ +#define DB_LOG_AUTOREMOVE 0x00010000/* Automatically remove log files. */ +#define DB_LOG_INMEMORY 0x00020000/* Store logs in buffers in memory. */ +#define DB_NOLOCKING 0x00040000/* Set locking/mutex behavior. */ +#define DB_NOPANIC 0x00080000/* Set panic state per DB_ENV. */ +#define DB_OVERWRITE 0x00100000/* Overwrite unlinked region files. */ +#define DB_PANIC_ENVIRONMENT 0x00200000/* Set panic state per environment. */ +#define DB_REGION_INIT 0x00400000/* Page-fault regions on open. */ +#define DB_TIME_NOTGRANTED 0x00800000/* Return NOTGRANTED on timeout. */ +/* Shared flags at 0x01000000 */ +/* Shared flags at 0x02000000 */ +/* Shared flags at 0x04000000 */ +/* Shared flags at 0x08000000 */ +#define DB_TXN_WRITE_NOSYNC 0x10000000/* Write, don't sync, on txn commit. */ +#define DB_YIELDCPU 0x20000000/* Yield the CPU (a lot). */ + +/* + * Flags private to DB->set_feedback's callback. + */ +#define DB_UPGRADE 0x0000001 /* Upgrading. */ +#define DB_VERIFY 0x0000002 /* Verifying. */ + +/* + * Flags private to DB_MPOOLFILE->open. + * Shared flags up to 0x0000800 */ +#define DB_DIRECT 0x0001000 /* Don't buffer the file in the OS. */ +#define DB_DURABLE_UNKNOWN 0x0002000 /* internal: durability on open. */ +#define DB_EXTENT 0x0004000 /* internal: dealing with an extent. */ +#define DB_ODDFILESIZE 0x0008000 /* Truncate file to N * pgsize. */ + +/* + * Flags private to DB->set_flags. + */ +#define DB_CHKSUM 0x0000001 /* Do checksumming */ +#define DB_DUP 0x0000002 /* Btree, Hash: duplicate keys. */ +#define DB_DUPSORT 0x0000004 /* Btree, Hash: duplicate keys. */ +#define DB_ENCRYPT 0x0000008 /* Btree, Hash: duplicate keys. */ +#define DB_INORDER 0x0000010 /* Queue: strict ordering on consume. */ +#define DB_RECNUM 0x0000020 /* Btree: record numbers. */ +#define DB_RENUMBER 0x0000040 /* Recno: renumber on insert/delete. */ +#define DB_REVSPLITOFF 0x0000080 /* Btree: turn off reverse splits. */ +#define DB_SNAPSHOT 0x0000100 /* Recno: snapshot the input. */ + +/* + * Flags private to the DB_ENV->stat_print, DB->stat and DB->stat_print methods. + */ +#define DB_STAT_ALL 0x0000001 /* Print: Everything. */ +#define DB_STAT_CLEAR 0x0000002 /* Clear stat after returning values. */ +#define DB_STAT_LOCK_CONF 0x0000004 /* Print: Lock conflict matrix. */ +#define DB_STAT_LOCK_LOCKERS 0x0000008 /* Print: Lockers. */ +#define DB_STAT_LOCK_OBJECTS 0x0000010 /* Print: Lock objects. */ +#define DB_STAT_LOCK_PARAMS 0x0000020 /* Print: Lock parameters. */ +#define DB_STAT_MEMP_HASH 0x0000040 /* Print: Mpool hash buckets. */ +#define DB_STAT_SUBSYSTEM 0x0000080 /* Print: Subsystems too. */ + +/* + * Flags private to DB->join. + */ +#define DB_JOIN_NOSORT 0x0000001 /* Don't try to optimize join. */ + +/* + * Flags private to DB->verify. + */ +#define DB_AGGRESSIVE 0x0000001 /* Salvage whatever could be data.*/ +#define DB_NOORDERCHK 0x0000002 /* Skip sort order/hashing check. */ +#define DB_ORDERCHKONLY 0x0000004 /* Only perform the order check. */ +#define DB_PR_PAGE 0x0000008 /* Show page contents (-da). */ +#define DB_PR_RECOVERYTEST 0x0000010 /* Recovery test (-dr). */ +#define DB_PRINTABLE 0x0000020 /* Use printable format for salvage. */ +#define DB_SALVAGE 0x0000040 /* Salvage what looks like data. */ +#define DB_UNREF 0x0000080 /* Report unreferenced pages. */ +/* + * !!! + * These must not go over 0x8000, or they will collide with the flags + * used by __bam_vrfy_subtree. + */ + +/* + * Flags private to DB->set_rep_transport's send callback. + */ +#define DB_REP_NOBUFFER 0x0000001 /* Do not buffer this message. */ +#define DB_REP_PERMANENT 0x0000002 /* Important--app. may want to flush. */ + +/******************************************************* + * Locking. + *******************************************************/ +#define DB_LOCKVERSION 1 + +#define DB_FILE_ID_LEN 20 /* Unique file ID length. */ + +/* + * Deadlock detector modes; used in the DB_ENV structure to configure the + * locking subsystem. + */ +#define DB_LOCK_NORUN 0 +#define DB_LOCK_DEFAULT 1 /* Default policy. */ +#define DB_LOCK_EXPIRE 2 /* Only expire locks, no detection. */ +#define DB_LOCK_MAXLOCKS 3 /* Select locker with max locks. */ +#define DB_LOCK_MAXWRITE 4 /* Select locker with max writelocks. */ +#define DB_LOCK_MINLOCKS 5 /* Select locker with min locks. */ +#define DB_LOCK_MINWRITE 6 /* Select locker with min writelocks. */ +#define DB_LOCK_OLDEST 7 /* Select oldest locker. */ +#define DB_LOCK_RANDOM 8 /* Select random locker. */ +#define DB_LOCK_YOUNGEST 9 /* Select youngest locker. */ + +/* Flag values for lock_vec(), lock_get(). */ +#define DB_LOCK_ABORT 0x001 /* Internal: Lock during abort. */ +#define DB_LOCK_NOWAIT 0x002 /* Don't wait on unavailable lock. */ +#define DB_LOCK_RECORD 0x004 /* Internal: record lock. */ +#define DB_LOCK_REMOVE 0x008 /* Internal: flag object removed. */ +#define DB_LOCK_SET_TIMEOUT 0x010 /* Internal: set lock timeout. */ +#define DB_LOCK_SWITCH 0x020 /* Internal: switch existing lock. */ +#define DB_LOCK_UPGRADE 0x040 /* Internal: upgrade existing lock. */ + +/* + * Simple R/W lock modes and for multi-granularity intention locking. + * + * !!! + * These values are NOT random, as they are used as an index into the lock + * conflicts arrays, i.e., DB_LOCK_IWRITE must be == 3, and DB_LOCK_IREAD + * must be == 4. + */ +typedef enum { + DB_LOCK_NG=0, /* Not granted. */ + DB_LOCK_READ=1, /* Shared/read. */ + DB_LOCK_WRITE=2, /* Exclusive/write. */ + DB_LOCK_WAIT=3, /* Wait for event */ + DB_LOCK_IWRITE=4, /* Intent exclusive/write. */ + DB_LOCK_IREAD=5, /* Intent to share/read. */ + DB_LOCK_IWR=6, /* Intent to read and write. */ + DB_LOCK_DIRTY=7, /* Dirty Read. */ + DB_LOCK_WWRITE=8 /* Was Written. */ +} db_lockmode_t; + +/* + * Request types. + */ +typedef enum { + DB_LOCK_DUMP=0, /* Display held locks. */ + DB_LOCK_GET=1, /* Get the lock. */ + DB_LOCK_GET_TIMEOUT=2, /* Get lock with a timeout. */ + DB_LOCK_INHERIT=3, /* Pass locks to parent. */ + DB_LOCK_PUT=4, /* Release the lock. */ + DB_LOCK_PUT_ALL=5, /* Release locker's locks. */ + DB_LOCK_PUT_OBJ=6, /* Release locker's locks on obj. */ + DB_LOCK_PUT_READ=7, /* Release locker's read locks. */ + DB_LOCK_TIMEOUT=8, /* Force a txn to timeout. */ + DB_LOCK_TRADE=9, /* Trade locker ids on a lock. */ + DB_LOCK_UPGRADE_WRITE=10 /* Upgrade writes for dirty reads. */ +} db_lockop_t; + +/* + * Status of a lock. + */ +typedef enum { + DB_LSTAT_ABORTED=1, /* Lock belongs to an aborted txn. */ + DB_LSTAT_EXPIRED=2, /* Lock has expired. */ + DB_LSTAT_FREE=3, /* Lock is unallocated. */ + DB_LSTAT_HELD=4, /* Lock is currently held. */ + DB_LSTAT_NOTEXIST=5, /* Object on which lock was waiting + * was removed */ + DB_LSTAT_PENDING=6, /* Lock was waiting and has been + * promoted; waiting for the owner + * to run and upgrade it to held. */ + DB_LSTAT_WAITING=7 /* Lock is on the wait queue. */ +}db_status_t; + +/* Lock statistics structure. */ +struct __db_lock_stat { + u_int32_t st_id; /* Last allocated locker ID. */ + u_int32_t st_cur_maxid; /* Current maximum unused ID. */ + u_int32_t st_maxlocks; /* Maximum number of locks in table. */ + u_int32_t st_maxlockers; /* Maximum num of lockers in table. */ + u_int32_t st_maxobjects; /* Maximum num of objects in table. */ + int st_nmodes; /* Number of lock modes. */ + u_int32_t st_nlocks; /* Current number of locks. */ + u_int32_t st_maxnlocks; /* Maximum number of locks so far. */ + u_int32_t st_nlockers; /* Current number of lockers. */ + u_int32_t st_maxnlockers; /* Maximum number of lockers so far. */ + u_int32_t st_nobjects; /* Current number of objects. */ + u_int32_t st_maxnobjects; /* Maximum number of objects so far. */ + u_int32_t st_nconflicts; /* Number of lock conflicts. */ + u_int32_t st_nrequests; /* Number of lock gets. */ + u_int32_t st_nreleases; /* Number of lock puts. */ + u_int32_t st_nnowaits; /* Number of requests that would have + waited, but NOWAIT was set. */ + u_int32_t st_ndeadlocks; /* Number of lock deadlocks. */ + db_timeout_t st_locktimeout; /* Lock timeout. */ + u_int32_t st_nlocktimeouts; /* Number of lock timeouts. */ + db_timeout_t st_txntimeout; /* Transaction timeout. */ + u_int32_t st_ntxntimeouts; /* Number of transaction timeouts. */ + u_int32_t st_region_wait; /* Region lock granted after wait. */ + u_int32_t st_region_nowait; /* Region lock granted without wait. */ + roff_t st_regsize; /* Region size. */ +}; + +/* + * DB_LOCK_ILOCK -- + * Internal DB access method lock. + */ +struct __db_ilock { + db_pgno_t pgno; /* Page being locked. */ + u_int8_t fileid[DB_FILE_ID_LEN];/* File id. */ +#define DB_HANDLE_LOCK 1 +#define DB_RECORD_LOCK 2 +#define DB_PAGE_LOCK 3 + u_int32_t type; /* Type of lock. */ +}; + +/* + * DB_LOCK -- + * The structure is allocated by the caller and filled in during a + * lock_get request (or a lock_vec/DB_LOCK_GET). + */ +struct __db_lock_u { + roff_t off; /* Offset of the lock in the region */ + u_int32_t ndx; /* Index of the object referenced by + * this lock; used for locking. */ + u_int32_t gen; /* Generation number of this lock. */ + db_lockmode_t mode; /* mode of this lock. */ +}; + +/* Lock request structure. */ +struct __db_lockreq { + db_lockop_t op; /* Operation. */ + db_lockmode_t mode; /* Requested mode. */ + db_timeout_t timeout; /* Time to expire lock. */ + DBT *obj; /* Object being locked. */ + DB_LOCK lock; /* Lock returned. */ +}; + +/******************************************************* + * Logging. + *******************************************************/ +#define DB_LOGVERSION 10 /* Current log version. */ +#define DB_LOGOLDVER 10 /* Oldest log version supported. */ +#define DB_LOGMAGIC 0x040988 + +/* Flag values for DB_ENV->log_archive(). */ +#define DB_ARCH_ABS 0x001 /* Absolute pathnames. */ +#define DB_ARCH_DATA 0x002 /* Data files. */ +#define DB_ARCH_LOG 0x004 /* Log files. */ +#define DB_ARCH_REMOVE 0x008 /* Remove log files. */ + +/* Flag values for DB_ENV->log_put(). */ +#define DB_FLUSH 0x001 /* Flush data to disk (public). */ +#define DB_LOG_CHKPNT 0x002 /* Flush supports a checkpoint */ +#define DB_LOG_COMMIT 0x004 /* Flush supports a commit */ +#define DB_LOG_NOCOPY 0x008 /* Don't copy data */ +#define DB_LOG_NOT_DURABLE 0x010 /* Do not log; keep in memory */ +#define DB_LOG_PERM 0x020 /* Flag record with REP_PERMANENT */ +#define DB_LOG_RESEND 0x040 /* Resent log record */ +#define DB_LOG_WRNOSYNC 0x080 /* Write, don't sync log_put */ + +/* + * A DB_LSN has two parts, a fileid which identifies a specific file, and an + * offset within that file. The fileid is an unsigned 4-byte quantity that + * uniquely identifies a file within the log directory -- currently a simple + * counter inside the log. The offset is also an unsigned 4-byte value. The + * log manager guarantees the offset is never more than 4 bytes by switching + * to a new log file before the maximum length imposed by an unsigned 4-byte + * offset is reached. + */ +struct __db_lsn { + u_int32_t file; /* File ID. */ + u_int32_t offset; /* File offset. */ +}; + +/* + * Application-specified log record types start at DB_user_BEGIN, and must not + * equal or exceed DB_debug_FLAG. + * + * DB_debug_FLAG is the high-bit of the u_int32_t that specifies a log record + * type. If the flag is set, it's a log record that was logged for debugging + * purposes only, even if it reflects a database change -- the change was part + * of a non-durable transaction. + */ +#define DB_user_BEGIN 10000 +#define DB_debug_FLAG 0x80000000 + +/* + * DB_LOGC -- + * Log cursor. + */ +struct __db_log_cursor { + DB_ENV *dbenv; /* Enclosing dbenv. */ + + DB_FH *c_fhp; /* File handle. */ + DB_LSN c_lsn; /* Cursor: LSN */ + u_int32_t c_len; /* Cursor: record length */ + u_int32_t c_prev; /* Cursor: previous record's offset */ + + DBT c_dbt; /* Return DBT. */ + +#define DB_LOGC_BUF_SIZE (32 * 1024) + u_int8_t *bp; /* Allocated read buffer. */ + u_int32_t bp_size; /* Read buffer length in bytes. */ + u_int32_t bp_rlen; /* Read buffer valid data length. */ + DB_LSN bp_lsn; /* Read buffer first byte LSN. */ + + u_int32_t bp_maxrec; /* Max record length in the log file. */ + + /* Methods. */ + int (*close) __P((DB_LOGC *, u_int32_t)); + int (*get) __P((DB_LOGC *, DB_LSN *, DBT *, u_int32_t)); + +#define DB_LOG_DISK 0x01 /* Log record came from disk. */ +#define DB_LOG_LOCKED 0x02 /* Log region already locked */ +#define DB_LOG_SILENT_ERR 0x04 /* Turn-off error messages. */ + u_int32_t flags; +}; + +/* Log statistics structure. */ +struct __db_log_stat { + u_int32_t st_magic; /* Log file magic number. */ + u_int32_t st_version; /* Log file version number. */ + int st_mode; /* Log file mode. */ + u_int32_t st_lg_bsize; /* Log buffer size. */ + u_int32_t st_lg_size; /* Log file size. */ + u_int32_t st_w_bytes; /* Bytes to log. */ + u_int32_t st_w_mbytes; /* Megabytes to log. */ + u_int32_t st_wc_bytes; /* Bytes to log since checkpoint. */ + u_int32_t st_wc_mbytes; /* Megabytes to log since checkpoint. */ + u_int32_t st_wcount; /* Total writes to the log. */ + u_int32_t st_wcount_fill; /* Overflow writes to the log. */ + u_int32_t st_scount; /* Total syncs to the log. */ + u_int32_t st_region_wait; /* Region lock granted after wait. */ + u_int32_t st_region_nowait; /* Region lock granted without wait. */ + u_int32_t st_cur_file; /* Current log file number. */ + u_int32_t st_cur_offset; /* Current log file offset. */ + u_int32_t st_disk_file; /* Known on disk log file number. */ + u_int32_t st_disk_offset; /* Known on disk log file offset. */ + roff_t st_regsize; /* Region size. */ + u_int32_t st_maxcommitperflush; /* Max number of commits in a flush. */ + u_int32_t st_mincommitperflush; /* Min number of commits in a flush. */ +}; + +/* + * We need to record the first log record of a transaction. + * For user defined logging this macro returns the place to + * put that information, if it is need in rlsnp, otherwise it + * leaves it unchanged. + */ +#define DB_SET_BEGIN_LSNP(txn, rlsnp) ((txn)->set_begin_lsnp(txn, rlsnp)) + +/******************************************************* + * Shared buffer cache (mpool). + *******************************************************/ +/* Flag values for DB_MPOOLFILE->get. */ +#define DB_MPOOL_CREATE 0x001 /* Create a page. */ +#define DB_MPOOL_LAST 0x002 /* Return the last page. */ +#define DB_MPOOL_NEW 0x004 /* Create a new page. */ + +/* Flag values for DB_MPOOLFILE->put, DB_MPOOLFILE->set. */ +#define DB_MPOOL_CLEAN 0x001 /* Page is not modified. */ +#define DB_MPOOL_DIRTY 0x002 /* Page is modified. */ +#define DB_MPOOL_DISCARD 0x004 /* Don't cache the page. */ +#define DB_MPOOL_FREE 0x008 /* Free page if present. */ + +/* Flags values for DB_MPOOLFILE->set_flags. */ +#define DB_MPOOL_NOFILE 0x001 /* Never open a backing file. */ +#define DB_MPOOL_UNLINK 0x002 /* Unlink the file on last close. */ + +/* Priority values for DB_MPOOLFILE->set_priority. */ +typedef enum { + DB_PRIORITY_VERY_LOW=1, + DB_PRIORITY_LOW=2, + DB_PRIORITY_DEFAULT=3, + DB_PRIORITY_HIGH=4, + DB_PRIORITY_VERY_HIGH=5 +} DB_CACHE_PRIORITY; + +/* Per-process DB_MPOOLFILE information. */ +struct __db_mpoolfile { + DB_FH *fhp; /* Underlying file handle. */ + + /* + * !!! + * The ref, pinref and q fields are protected by the region lock. + */ + u_int32_t ref; /* Reference count. */ + + u_int32_t pinref; /* Pinned block reference count. */ + + /* + * !!! + * Explicit representations of structures from queue.h. + * TAILQ_ENTRY(__db_mpoolfile) q; + */ + struct { + struct __db_mpoolfile *tqe_next; + struct __db_mpoolfile **tqe_prev; + } q; /* Linked list of DB_MPOOLFILE's. */ + + /* + * !!! + * The rest of the fields (with the exception of the MP_FLUSH flag) + * are not thread-protected, even when they may be modified at any + * time by the application. The reason is the DB_MPOOLFILE handle + * is single-threaded from the viewpoint of the application, and so + * the only fields needing to be thread-protected are those accessed + * by checkpoint or sync threads when using DB_MPOOLFILE structures + * to flush buffers from the cache. + */ + DB_ENV *dbenv; /* Overlying DB_ENV. */ + MPOOLFILE *mfp; /* Underlying MPOOLFILE. */ + + u_int32_t clear_len; /* Cleared length on created pages. */ + u_int8_t /* Unique file ID. */ + fileid[DB_FILE_ID_LEN]; + int ftype; /* File type. */ + int32_t lsn_offset; /* LSN offset in page. */ + u_int32_t gbytes, bytes; /* Maximum file size. */ + DBT *pgcookie; /* Byte-string passed to pgin/pgout. */ + DB_CACHE_PRIORITY /* Cache priority. */ + priority; + + void *addr; /* Address of mmap'd region. */ + size_t len; /* Length of mmap'd region. */ + + u_int32_t config_flags; /* Flags to DB_MPOOLFILE->set_flags. */ + + /* Methods. */ + int (*close) __P((DB_MPOOLFILE *, u_int32_t)); + int (*get) __P((DB_MPOOLFILE *, db_pgno_t *, u_int32_t, void *)); + int (*open) __P((DB_MPOOLFILE *, const char *, u_int32_t, int, size_t)); + int (*put) __P((DB_MPOOLFILE *, void *, u_int32_t)); + int (*set) __P((DB_MPOOLFILE *, void *, u_int32_t)); + int (*get_clear_len) __P((DB_MPOOLFILE *, u_int32_t *)); + int (*set_clear_len) __P((DB_MPOOLFILE *, u_int32_t)); + int (*get_fileid) __P((DB_MPOOLFILE *, u_int8_t *)); + int (*set_fileid) __P((DB_MPOOLFILE *, u_int8_t *)); + int (*get_flags) __P((DB_MPOOLFILE *, u_int32_t *)); + int (*set_flags) __P((DB_MPOOLFILE *, u_int32_t, int)); + int (*get_ftype) __P((DB_MPOOLFILE *, int *)); + int (*set_ftype) __P((DB_MPOOLFILE *, int)); + int (*get_lsn_offset) __P((DB_MPOOLFILE *, int32_t *)); + int (*set_lsn_offset) __P((DB_MPOOLFILE *, int32_t)); + int (*get_maxsize) __P((DB_MPOOLFILE *, u_int32_t *, u_int32_t *)); + int (*set_maxsize) __P((DB_MPOOLFILE *, u_int32_t, u_int32_t)); + int (*get_pgcookie) __P((DB_MPOOLFILE *, DBT *)); + int (*set_pgcookie) __P((DB_MPOOLFILE *, DBT *)); + int (*get_priority) __P((DB_MPOOLFILE *, DB_CACHE_PRIORITY *)); + int (*set_priority) __P((DB_MPOOLFILE *, DB_CACHE_PRIORITY)); + int (*sync) __P((DB_MPOOLFILE *)); + + /* + * MP_FILEID_SET, MP_OPEN_CALLED and MP_READONLY do not need to be + * thread protected because they are initialized before the file is + * linked onto the per-process lists, and never modified. + * + * MP_FLUSH is thread protected because it is potentially read/set by + * multiple threads of control. + */ +#define MP_FILEID_SET 0x001 /* Application supplied a file ID. */ +#define MP_FLUSH 0x002 /* Was opened to flush a buffer. */ +#define MP_OPEN_CALLED 0x004 /* File opened. */ +#define MP_READONLY 0x008 /* File is readonly. */ + u_int32_t flags; +}; + +/* Mpool statistics structure. */ +struct __db_mpool_stat { + u_int32_t st_gbytes; /* Total cache size: GB. */ + u_int32_t st_bytes; /* Total cache size: B. */ + u_int32_t st_ncache; /* Number of caches. */ + roff_t st_regsize; /* Region size. */ + size_t st_mmapsize; /* Maximum file size for mmap. */ + int st_maxopenfd; /* Maximum number of open fd's. */ + int st_maxwrite; /* Maximum buffers to write. */ + int st_maxwrite_sleep; /* Sleep after writing max buffers. */ + u_int32_t st_map; /* Pages from mapped files. */ + u_int32_t st_cache_hit; /* Pages found in the cache. */ + u_int32_t st_cache_miss; /* Pages not found in the cache. */ + u_int32_t st_page_create; /* Pages created in the cache. */ + u_int32_t st_page_in; /* Pages read in. */ + u_int32_t st_page_out; /* Pages written out. */ + u_int32_t st_ro_evict; /* Clean pages forced from the cache. */ + u_int32_t st_rw_evict; /* Dirty pages forced from the cache. */ + u_int32_t st_page_trickle; /* Pages written by memp_trickle. */ + u_int32_t st_pages; /* Total number of pages. */ + u_int32_t st_page_clean; /* Clean pages. */ + u_int32_t st_page_dirty; /* Dirty pages. */ + u_int32_t st_hash_buckets; /* Number of hash buckets. */ + u_int32_t st_hash_searches; /* Total hash chain searches. */ + u_int32_t st_hash_longest; /* Longest hash chain searched. */ + u_int32_t st_hash_examined; /* Total hash entries searched. */ + u_int32_t st_hash_nowait; /* Hash lock granted with nowait. */ + u_int32_t st_hash_wait; /* Hash lock granted after wait. */ + u_int32_t st_hash_max_wait; /* Max hash lock granted after wait. */ + u_int32_t st_region_nowait; /* Region lock granted with nowait. */ + u_int32_t st_region_wait; /* Region lock granted after wait. */ + u_int32_t st_alloc; /* Number of page allocations. */ + u_int32_t st_alloc_buckets; /* Buckets checked during allocation. */ + u_int32_t st_alloc_max_buckets; /* Max checked during allocation. */ + u_int32_t st_alloc_pages; /* Pages checked during allocation. */ + u_int32_t st_alloc_max_pages; /* Max checked during allocation. */ +}; + +/* Mpool file statistics structure. */ +struct __db_mpool_fstat { + char *file_name; /* File name. */ + u_int32_t st_pagesize; /* Page size. */ + u_int32_t st_map; /* Pages from mapped files. */ + u_int32_t st_cache_hit; /* Pages found in the cache. */ + u_int32_t st_cache_miss; /* Pages not found in the cache. */ + u_int32_t st_page_create; /* Pages created in the cache. */ + u_int32_t st_page_in; /* Pages read in. */ + u_int32_t st_page_out; /* Pages written out. */ +}; + +/******************************************************* + * Transactions and recovery. + *******************************************************/ +#define DB_TXNVERSION 1 + +typedef enum { + DB_TXN_ABORT=0, /* Public. */ + DB_TXN_APPLY=1, /* Public. */ + DB_TXN_BACKWARD_ALLOC=2, /* Internal. */ + DB_TXN_BACKWARD_ROLL=3, /* Public. */ + DB_TXN_FORWARD_ROLL=4, /* Public. */ + DB_TXN_OPENFILES=5, /* Internal. */ + DB_TXN_POPENFILES=6, /* Internal. */ + DB_TXN_PRINT=7 /* Public. */ +} db_recops; + +/* + * BACKWARD_ALLOC is used during the forward pass to pick up any aborted + * allocations for files that were created during the forward pass. + * The main difference between _ALLOC and _ROLL is that the entry for + * the file not exist during the rollforward pass. + */ +#define DB_UNDO(op) ((op) == DB_TXN_ABORT || \ + (op) == DB_TXN_BACKWARD_ROLL || (op) == DB_TXN_BACKWARD_ALLOC) +#define DB_REDO(op) ((op) == DB_TXN_FORWARD_ROLL || (op) == DB_TXN_APPLY) + +struct __db_txn { + DB_TXNMGR *mgrp; /* Pointer to transaction manager. */ + DB_TXN *parent; /* Pointer to transaction's parent. */ + DB_LSN last_lsn; /* Lsn of last log write. */ + u_int32_t txnid; /* Unique transaction id. */ + u_int32_t tid; /* Thread id for use in MT XA. */ + roff_t off; /* Detail structure within region. */ + db_timeout_t lock_timeout; /* Timeout for locks for this txn. */ + db_timeout_t expire; /* Time this txn expires. */ + void *txn_list; /* Undo information for parent. */ + + /* + * !!! + * Explicit representations of structures from queue.h. + * TAILQ_ENTRY(__db_txn) links; + * TAILQ_ENTRY(__db_txn) xalinks; + */ + struct { + struct __db_txn *tqe_next; + struct __db_txn **tqe_prev; + } links; /* Links transactions off manager. */ + struct { + struct __db_txn *tqe_next; + struct __db_txn **tqe_prev; + } xalinks; /* Links active XA transactions. */ + + /* + * !!! + * Explicit representations of structures from queue.h. + * TAILQ_HEAD(__events, __txn_event) events; + */ + struct { + struct __txn_event *tqh_first; + struct __txn_event **tqh_last; + } events; + + /* + * !!! + * Explicit representations of structures from queue.h. + * STAILQ_HEAD(__logrec, __txn_logrec) logs; + */ + struct { + struct __txn_logrec *stqh_first; + struct __txn_logrec **stqh_last; + } logs; /* Links deferred events. */ + + /* + * !!! + * Explicit representations of structures from queue.h. + * TAILQ_HEAD(__kids, __db_txn) kids; + */ + struct __kids { + struct __db_txn *tqh_first; + struct __db_txn **tqh_last; + } kids; + + /* + * !!! + * Explicit representations of structures from queue.h. + * TAILQ_ENTRY(__db_txn) klinks; + */ + struct { + struct __db_txn *tqe_next; + struct __db_txn **tqe_prev; + } klinks; + + void *api_internal; /* C++ API private. */ + void *xml_internal; /* XML API private. */ + + u_int32_t cursors; /* Number of cursors open for txn */ + + /* Methods. */ + int (*abort) __P((DB_TXN *)); + int (*commit) __P((DB_TXN *, u_int32_t)); + int (*discard) __P((DB_TXN *, u_int32_t)); + u_int32_t (*id) __P((DB_TXN *)); + int (*prepare) __P((DB_TXN *, u_int8_t *)); + void (*set_begin_lsnp) __P((DB_TXN *txn, DB_LSN **)); + int (*set_timeout) __P((DB_TXN *, db_timeout_t, u_int32_t)); + +#define TXN_CHILDCOMMIT 0x001 /* Transaction that has committed. */ +#define TXN_COMPENSATE 0x002 /* Compensating transaction. */ +#define TXN_DEADLOCK 0x004 /* Transaction has deadlocked. */ +#define TXN_DEGREE_2 0x008 /* Has degree 2 isolation. */ +#define TXN_DIRTY_READ 0x010 /* Transaction does dirty reads. */ +#define TXN_LOCKTIMEOUT 0x020 /* Transaction has a lock timeout. */ +#define TXN_MALLOC 0x040 /* Structure allocated by TXN system. */ +#define TXN_NOSYNC 0x080 /* Do not sync on prepare and commit. */ +#define TXN_NOWAIT 0x100 /* Do not wait on locks. */ +#define TXN_RESTORED 0x200 /* Transaction has been restored. */ +#define TXN_SYNC 0x400 /* Sync on prepare and commit. */ + u_int32_t flags; +}; + +/* + * Structure used for two phase commit interface. Berkeley DB support for two + * phase commit is compatible with the X/open XA interface. + * + * The XA #define XIDDATASIZE defines the size of a global transaction ID. We + * have our own version here (for name space reasons) which must have the same + * value. + */ +#define DB_XIDDATASIZE 128 +struct __db_preplist { + DB_TXN *txn; + u_int8_t gid[DB_XIDDATASIZE]; +}; + +/* Transaction statistics structure. */ +struct __db_txn_active { + u_int32_t txnid; /* Transaction ID */ + u_int32_t parentid; /* Transaction ID of parent */ + DB_LSN lsn; /* LSN when transaction began */ + u_int32_t xa_status; /* XA status */ + u_int8_t xid[DB_XIDDATASIZE]; /* XA global transaction ID */ +}; + +struct __db_txn_stat { + DB_LSN st_last_ckp; /* lsn of the last checkpoint */ + time_t st_time_ckp; /* time of last checkpoint */ + u_int32_t st_last_txnid; /* last transaction id given out */ + u_int32_t st_maxtxns; /* maximum txns possible */ + u_int32_t st_naborts; /* number of aborted transactions */ + u_int32_t st_nbegins; /* number of begun transactions */ + u_int32_t st_ncommits; /* number of committed transactions */ + u_int32_t st_nactive; /* number of active transactions */ + u_int32_t st_nrestores; /* number of restored transactions + after recovery. */ + u_int32_t st_maxnactive; /* maximum active transactions */ + DB_TXN_ACTIVE *st_txnarray; /* array of active transactions */ + u_int32_t st_region_wait; /* Region lock granted after wait. */ + u_int32_t st_region_nowait; /* Region lock granted without wait. */ + roff_t st_regsize; /* Region size. */ +}; + +/******************************************************* + * Replication. + *******************************************************/ +/* Special, out-of-band environment IDs. */ +#define DB_EID_BROADCAST -1 +#define DB_EID_INVALID -2 + +/* rep_start flags values */ +#define DB_REP_CLIENT 0x001 +#define DB_REP_MASTER 0x002 + +/* Replication statistics. */ +struct __db_rep_stat { + /* !!! + * Many replication statistics fields cannot be protected by a mutex + * without an unacceptable performance penalty, since most message + * processing is done without the need to hold a region-wide lock. + * Fields whose comments end with a '+' may be updated without holding + * the replication or log mutexes (as appropriate), and thus may be + * off somewhat (or, on unreasonable architectures under unlucky + * circumstances, garbaged). + */ + u_int32_t st_status; /* Current replication status. */ + DB_LSN st_next_lsn; /* Next LSN to use or expect. */ + DB_LSN st_waiting_lsn; /* LSN we're awaiting, if any. */ + db_pgno_t st_next_pg; /* Next pg we expect. */ + db_pgno_t st_waiting_pg; /* pg we're awaiting, if any. */ + + u_int32_t st_dupmasters; /* # of times a duplicate master + condition was detected.+ */ + int st_env_id; /* Current environment ID. */ + int st_env_priority; /* Current environment priority. */ + u_int32_t st_gen; /* Current generation number. */ + u_int32_t st_egen; /* Current election gen number. */ + u_int32_t st_log_duplicated; /* Log records received multiply.+ */ + u_int32_t st_log_queued; /* Log records currently queued.+ */ + u_int32_t st_log_queued_max; /* Max. log records queued at once.+ */ + u_int32_t st_log_queued_total; /* Total # of log recs. ever queued.+ */ + u_int32_t st_log_records; /* Log records received and put.+ */ + u_int32_t st_log_requested; /* Log recs. missed and requested.+ */ + int st_master; /* Env. ID of the current master. */ + u_int32_t st_master_changes; /* # of times we've switched masters. */ + u_int32_t st_msgs_badgen; /* Messages with a bad generation #.+ */ + u_int32_t st_msgs_processed; /* Messages received and processed.+ */ + u_int32_t st_msgs_recover; /* Messages ignored because this site + was a client in recovery.+ */ + u_int32_t st_msgs_send_failures;/* # of failed message sends.+ */ + u_int32_t st_msgs_sent; /* # of successful message sends.+ */ + u_int32_t st_newsites; /* # of NEWSITE msgs. received.+ */ + int st_nsites; /* Current number of sites we will + assume during elections. */ + u_int32_t st_nthrottles; /* # of times we were throttled. */ + u_int32_t st_outdated; /* # of times we detected and returned + an OUTDATED condition.+ */ + u_int32_t st_pg_duplicated; /* Pages received multiply.+ */ + u_int32_t st_pg_records; /* Pages received and stored.+ */ + u_int32_t st_pg_requested; /* Pages missed and requested.+ */ + u_int32_t st_startup_complete; /* Site completed client sync-up. */ + u_int32_t st_txns_applied; /* # of transactions applied.+ */ + + /* Elections generally. */ + u_int32_t st_elections; /* # of elections held.+ */ + u_int32_t st_elections_won; /* # of elections won by this site.+ */ + + /* Statistics about an in-progress election. */ + int st_election_cur_winner; /* Current front-runner. */ + u_int32_t st_election_gen; /* Election generation number. */ + DB_LSN st_election_lsn; /* Max. LSN of current winner. */ + int st_election_nsites; /* # of "registered voters". */ + int st_election_nvotes; /* # of "registered voters" needed. */ + int st_election_priority; /* Current election priority. */ + int st_election_status; /* Current election status. */ + u_int32_t st_election_tiebreaker;/* Election tiebreaker value. */ + int st_election_votes; /* Votes received in this round. */ +}; +/* + * The storage record for a sequence. + */ +struct __db_seq_record { + u_int32_t seq_version; /* Version size/number. */ +#define DB_SEQ_DEC 0x00000001 /* Decrement sequence. */ +#define DB_SEQ_INC 0x00000002 /* Increment sequence. */ +#define DB_SEQ_RANGE_SET 0x00000004 /* Range set (internal). */ +#define DB_SEQ_WRAP 0x00000008 /* Wrap sequence at min/max. */ + u_int32_t flags; /* Flags. */ + db_seq_t seq_value; /* Current value. */ + db_seq_t seq_max; /* Max permitted. */ + db_seq_t seq_min; /* Min permitted. */ +}; + +/* + * Handle for a sequence object. + */ +struct __db_sequence { + DB *seq_dbp; /* DB handle for this sequence. */ + DB_MUTEX *seq_mutexp; /* Mutex if sequence is threaded. */ + DB_SEQ_RECORD *seq_rp; /* Pointer to current data. */ + DB_SEQ_RECORD seq_record; /* Data from DB_SEQUENCE. */ + int32_t seq_cache_size; /* Number of values cached. */ + db_seq_t seq_last_value; /* Last value cached. */ + DBT seq_key; /* DBT pointing to sequence key. */ + DBT seq_data; /* DBT pointing to seq_record. */ + + /* API-private structure: used by C++ and Java. */ + void *api_internal; + + int (*close) __P((DB_SEQUENCE *, u_int32_t)); + int (*get) __P((DB_SEQUENCE *, + DB_TXN *, int32_t, db_seq_t *, u_int32_t)); + int (*get_cachesize) __P((DB_SEQUENCE *, int32_t *)); + int (*get_db) __P((DB_SEQUENCE *, DB **)); + int (*get_flags) __P((DB_SEQUENCE *, u_int32_t *)); + int (*get_key) __P((DB_SEQUENCE *, DBT *)); + int (*get_range) __P((DB_SEQUENCE *, + db_seq_t *, db_seq_t *)); + int (*initial_value) __P((DB_SEQUENCE *, db_seq_t)); + int (*open) __P((DB_SEQUENCE *, + DB_TXN *, DBT *, u_int32_t)); + int (*remove) __P((DB_SEQUENCE *, DB_TXN *, u_int32_t)); + int (*set_cachesize) __P((DB_SEQUENCE *, int32_t)); + int (*set_flags) __P((DB_SEQUENCE *, u_int32_t)); + int (*set_range) __P((DB_SEQUENCE *, db_seq_t, db_seq_t)); + int (*stat) __P((DB_SEQUENCE *, + DB_SEQUENCE_STAT **, u_int32_t)); + int (*stat_print) __P((DB_SEQUENCE *, u_int32_t)); +}; + +struct __db_seq_stat { + u_int32_t st_wait; /* Sequence lock granted without wait. */ + u_int32_t st_nowait; /* Sequence lock granted after wait. */ + db_seq_t st_current; /* Current value in db. */ + db_seq_t st_value; /* Current cached value. */ + db_seq_t st_last_value; /* Last cached value. */ + db_seq_t st_min; /* Minimum value. */ + db_seq_t st_max; /* Maximum value. */ + int32_t st_cache_size; /* Cache size. */ + u_int32_t st_flags; /* Flag value. */ +}; + +/******************************************************* + * Access methods. + *******************************************************/ +typedef enum { + DB_BTREE=1, + DB_HASH=2, + DB_RECNO=3, + DB_QUEUE=4, + DB_UNKNOWN=5 /* Figure it out on open. */ +} DBTYPE; + +#define DB_RENAMEMAGIC 0x030800 /* File has been renamed. */ + +#define DB_BTREEVERSION 9 /* Current btree version. */ +#define DB_BTREEOLDVER 8 /* Oldest btree version supported. */ +#define DB_BTREEMAGIC 0x053162 + +#define DB_HASHVERSION 8 /* Current hash version. */ +#define DB_HASHOLDVER 7 /* Oldest hash version supported. */ +#define DB_HASHMAGIC 0x061561 + +#define DB_QAMVERSION 4 /* Current queue version. */ +#define DB_QAMOLDVER 3 /* Oldest queue version supported. */ +#define DB_QAMMAGIC 0x042253 + +#define DB_SEQUENCE_VERSION 2 /* Current sequence version. */ +#define DB_SEQUENCE_OLDVER 1 /* Oldest queue version supported. */ + +/* + * DB access method and cursor operation values. Each value is an operation + * code to which additional bit flags are added. + */ +#define DB_AFTER 1 /* c_put() */ +#define DB_APPEND 2 /* put() */ +#define DB_BEFORE 3 /* c_put() */ +#define DB_CACHED_COUNTS 4 /* stat() */ +#define DB_CONSUME 5 /* get() */ +#define DB_CONSUME_WAIT 6 /* get() */ +#define DB_CURRENT 7 /* c_get(), c_put(), DB_LOGC->get() */ +#define DB_FAST_STAT 8 /* stat() */ +#define DB_FIRST 9 /* c_get(), DB_LOGC->get() */ +#define DB_GET_BOTH 10 /* get(), c_get() */ +#define DB_GET_BOTHC 11 /* c_get() (internal) */ +#define DB_GET_BOTH_RANGE 12 /* get(), c_get() */ +#define DB_GET_RECNO 13 /* c_get() */ +#define DB_JOIN_ITEM 14 /* c_get(); do not do primary lookup */ +#define DB_KEYFIRST 15 /* c_put() */ +#define DB_KEYLAST 16 /* c_put() */ +#define DB_LAST 17 /* c_get(), DB_LOGC->get() */ +#define DB_NEXT 18 /* c_get(), DB_LOGC->get() */ +#define DB_NEXT_DUP 19 /* c_get() */ +#define DB_NEXT_NODUP 20 /* c_get() */ +#define DB_NODUPDATA 21 /* put(), c_put() */ +#define DB_NOOVERWRITE 22 /* put() */ +#define DB_NOSYNC 23 /* close() */ +#define DB_POSITION 24 /* c_dup() */ +#define DB_PREV 25 /* c_get(), DB_LOGC->get() */ +#define DB_PREV_NODUP 26 /* c_get(), DB_LOGC->get() */ +#define DB_RECORDCOUNT 27 /* stat() */ +#define DB_SET 28 /* c_get(), DB_LOGC->get() */ +#define DB_SET_LOCK_TIMEOUT 29 /* set_timout() */ +#define DB_SET_RANGE 30 /* c_get() */ +#define DB_SET_RECNO 31 /* get(), c_get() */ +#define DB_SET_TXN_NOW 32 /* set_timout() (internal) */ +#define DB_SET_TXN_TIMEOUT 33 /* set_timout() */ +#define DB_UPDATE_SECONDARY 34 /* c_get(), c_del() (internal) */ +#define DB_WRITECURSOR 35 /* cursor() */ +#define DB_WRITELOCK 36 /* cursor() (internal) */ + +/* This has to change when the max opcode hits 255. */ +#define DB_OPFLAGS_MASK 0x000000ff /* Mask for operations flags. */ + +/* + * Masks for flags that can be OR'd into DB access method and cursor + * operation values. + * + * DB_DIRTY_READ 0x04000000 Dirty Read. */ +#define DB_MULTIPLE 0x08000000 /* Return multiple data values. */ +#define DB_MULTIPLE_KEY 0x10000000 /* Return multiple data/key pairs. */ +#define DB_RMW 0x20000000 /* Acquire write flag immediately. */ + +/* + * DB (user visible) error return codes. + * + * !!! + * For source compatibility with DB 2.X deadlock return (EAGAIN), use the + * following: + * #include + * #define DB_LOCK_DEADLOCK EAGAIN + * + * !!! + * We don't want our error returns to conflict with other packages where + * possible, so pick a base error value that's hopefully not common. We + * document that we own the error name space from -30,800 to -30,999. + */ +/* DB (public) error return codes. */ +#define DB_BUFFER_SMALL (-30999)/* User memory too small for return. */ +#define DB_DONOTINDEX (-30998)/* "Null" return from 2ndary callbk. */ +#define DB_KEYEMPTY (-30997)/* Key/data deleted or never created. */ +#define DB_KEYEXIST (-30996)/* The key/data pair already exists. */ +#define DB_LOCK_DEADLOCK (-30995)/* Deadlock. */ +#define DB_LOCK_NOTGRANTED (-30994)/* Lock unavailable. */ +#define DB_LOG_BUFFER_FULL (-30993)/* In-memory log buffer full. */ +#define DB_NOSERVER (-30992)/* Server panic return. */ +#define DB_NOSERVER_HOME (-30991)/* Bad home sent to server. */ +#define DB_NOSERVER_ID (-30990)/* Bad ID sent to server. */ +#define DB_NOTFOUND (-30989)/* Key/data pair not found (EOF). */ +#define DB_OLD_VERSION (-30988)/* Out-of-date version. */ +#define DB_PAGE_NOTFOUND (-30987)/* Requested page not found. */ +#define DB_REP_DUPMASTER (-30986)/* There are two masters. */ +#define DB_REP_HANDLE_DEAD (-30985)/* Rolled back a commit. */ +#define DB_REP_HOLDELECTION (-30984)/* Time to hold an election. */ +#define DB_REP_ISPERM (-30983)/* Cached not written perm written.*/ +#define DB_REP_NEWMASTER (-30982)/* We have learned of a new master. */ +#define DB_REP_NEWSITE (-30981)/* New site entered system. */ +#define DB_REP_NOTPERM (-30980)/* Permanent log record not written. */ +#define DB_REP_STARTUPDONE (-30979)/* Client startup complete. */ +#define DB_REP_UNAVAIL (-30978)/* Site cannot currently be reached. */ +#define DB_RUNRECOVERY (-30977)/* Panic return. */ +#define DB_SECONDARY_BAD (-30976)/* Secondary index corrupt. */ +#define DB_VERIFY_BAD (-30975)/* Verify failed; bad format. */ +#define DB_VERSION_MISMATCH (-30974)/* Environment version mismatch. */ + +/* DB (private) error return codes. */ +#define DB_ALREADY_ABORTED (-30899) +#define DB_DELETED (-30898)/* Recovery file marked deleted. */ +#define DB_LOCK_NOTEXIST (-30897)/* Object to lock is gone. */ +#define DB_NEEDSPLIT (-30896)/* Page needs to be split. */ +#define DB_REP_EGENCHG (-30895)/* Egen changed while in election. */ +#define DB_REP_LOGREADY (-30894)/* Rep log ready for recovery. */ +#define DB_REP_PAGEDONE (-30893)/* This page was already done. */ +#define DB_SURPRISE_KID (-30892)/* Child commit where parent + didn't know it was a parent. */ +#define DB_SWAPBYTES (-30891)/* Database needs byte swapping. */ +#define DB_TIMEOUT (-30890)/* Timed out waiting for election. */ +#define DB_TXN_CKP (-30889)/* Encountered ckp record in log. */ +#define DB_VERIFY_FATAL (-30888)/* DB->verify cannot proceed. */ + +/* Database handle. */ +struct __db { + /******************************************************* + * Public: owned by the application. + *******************************************************/ + u_int32_t pgsize; /* Database logical page size. */ + + /* Callbacks. */ + int (*db_append_recno) __P((DB *, DBT *, db_recno_t)); + void (*db_feedback) __P((DB *, int, int)); + int (*dup_compare) __P((DB *, const DBT *, const DBT *)); + + void *app_private; /* Application-private handle. */ + + /******************************************************* + * Private: owned by DB. + *******************************************************/ + DB_ENV *dbenv; /* Backing environment. */ + + DBTYPE type; /* DB access method type. */ + + DB_MPOOLFILE *mpf; /* Backing buffer pool. */ + + DB_MUTEX *mutexp; /* Synchronization for free threading */ + + char *fname, *dname; /* File/database passed to DB->open. */ + u_int32_t open_flags; /* Flags passed to DB->open. */ + + u_int8_t fileid[DB_FILE_ID_LEN];/* File's unique ID for locking. */ + + u_int32_t adj_fileid; /* File's unique ID for curs. adj. */ + +#define DB_LOGFILEID_INVALID -1 + FNAME *log_filename; /* File's naming info for logging. */ + + db_pgno_t meta_pgno; /* Meta page number */ + u_int32_t lid; /* Locker id for handle locking. */ + u_int32_t cur_lid; /* Current handle lock holder. */ + u_int32_t associate_lid; /* Locker id for DB->associate call. */ + DB_LOCK handle_lock; /* Lock held on this handle. */ + + u_int cl_id; /* RPC: remote client id. */ + + time_t timestamp; /* Handle timestamp for replication. */ + + /* + * Returned data memory for DB->get() and friends. + */ + DBT my_rskey; /* Secondary key. */ + DBT my_rkey; /* [Primary] key. */ + DBT my_rdata; /* Data. */ + + /* + * !!! + * Some applications use DB but implement their own locking outside of + * DB. If they're using fcntl(2) locking on the underlying database + * file, and we open and close a file descriptor for that file, we will + * discard their locks. The DB_FCNTL_LOCKING flag to DB->open is an + * undocumented interface to support this usage which leaves any file + * descriptors we open until DB->close. This will only work with the + * DB->open interface and simple caches, e.g., creating a transaction + * thread may open/close file descriptors this flag doesn't protect. + * Locking with fcntl(2) on a file that you don't own is a very, very + * unsafe thing to do. 'Nuff said. + */ + DB_FH *saved_open_fhp; /* Saved file handle. */ + + /* + * Linked list of DBP's, linked from the DB_ENV, used to keep track + * of all open db handles for cursor adjustment. + * + * !!! + * Explicit representations of structures from queue.h. + * LIST_ENTRY(__db) dblistlinks; + */ + struct { + struct __db *le_next; + struct __db **le_prev; + } dblistlinks; + + /* + * Cursor queues. + * + * !!! + * Explicit representations of structures from queue.h. + * TAILQ_HEAD(__cq_fq, __dbc) free_queue; + * TAILQ_HEAD(__cq_aq, __dbc) active_queue; + * TAILQ_HEAD(__cq_jq, __dbc) join_queue; + */ + struct __cq_fq { + struct __dbc *tqh_first; + struct __dbc **tqh_last; + } free_queue; + struct __cq_aq { + struct __dbc *tqh_first; + struct __dbc **tqh_last; + } active_queue; + struct __cq_jq { + struct __dbc *tqh_first; + struct __dbc **tqh_last; + } join_queue; + + /* + * Secondary index support. + * + * Linked list of secondary indices -- set in the primary. + * + * !!! + * Explicit representations of structures from queue.h. + * LIST_HEAD(s_secondaries, __db); + */ + struct { + struct __db *lh_first; + } s_secondaries; + + /* + * List entries for secondaries, and reference count of how + * many threads are updating this secondary (see __db_c_put). + * + * !!! + * Note that these are synchronized by the primary's mutex, but + * filled in in the secondaries. + * + * !!! + * Explicit representations of structures from queue.h. + * LIST_ENTRY(__db) s_links; + */ + struct { + struct __db *le_next; + struct __db **le_prev; + } s_links; + u_int32_t s_refcnt; + + /* Secondary callback and free functions -- set in the secondary. */ + int (*s_callback) __P((DB *, const DBT *, const DBT *, DBT *)); + + /* Reference to primary -- set in the secondary. */ + DB *s_primary; + + /* API-private structure: used by DB 1.85, C++, Java, Perl and Tcl */ + void *api_internal; + + /* Subsystem-private structure. */ + void *bt_internal; /* Btree/Recno access method. */ + void *h_internal; /* Hash access method. */ + void *q_internal; /* Queue access method. */ + void *xa_internal; /* XA. */ + + /* Methods. */ + int (*associate) __P((DB *, DB_TXN *, DB *, int (*)(DB *, const DBT *, + const DBT *, DBT *), u_int32_t)); + int (*close) __P((DB *, u_int32_t)); + int (*cursor) __P((DB *, DB_TXN *, DBC **, u_int32_t)); + int (*del) __P((DB *, DB_TXN *, DBT *, u_int32_t)); + int (*dump) __P((DB *, + const char *, int (*)(void *, const void *), void *, int, int)); + void (*err) __P((DB *, int, const char *, ...)); + void (*errx) __P((DB *, const char *, ...)); + int (*fd) __P((DB *, int *)); + int (*get) __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t)); + int (*pget) __P((DB *, DB_TXN *, DBT *, DBT *, DBT *, u_int32_t)); + int (*get_byteswapped) __P((DB *, int *)); + int (*get_cachesize) __P((DB *, u_int32_t *, u_int32_t *, int *)); + int (*get_dbname) __P((DB *, const char **, const char **)); + int (*get_encrypt_flags) __P((DB *, u_int32_t *)); + DB_ENV *(*get_env) __P((DB *)); + void (*get_errfile) __P((DB *, FILE **)); + void (*get_errpfx) __P((DB *, const char **)); + int (*get_flags) __P((DB *, u_int32_t *)); + int (*get_lorder) __P((DB *, int *)); + int (*get_open_flags) __P((DB *, u_int32_t *)); + int (*get_pagesize) __P((DB *, u_int32_t *)); + int (*get_transactional) __P((DB *)); + int (*get_type) __P((DB *, DBTYPE *)); + int (*join) __P((DB *, DBC **, DBC **, u_int32_t)); + int (*key_range) __P((DB *, + DB_TXN *, DBT *, DB_KEY_RANGE *, u_int32_t)); + int (*open) __P((DB *, DB_TXN *, + const char *, const char *, DBTYPE, u_int32_t, int)); + int (*put) __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t)); + int (*remove) __P((DB *, const char *, const char *, u_int32_t)); + int (*rename) __P((DB *, + const char *, const char *, const char *, u_int32_t)); + int (*truncate) __P((DB *, DB_TXN *, u_int32_t *, u_int32_t)); + int (*set_append_recno) __P((DB *, int (*)(DB *, DBT *, db_recno_t))); + int (*set_alloc) __P((DB *, void *(*)(size_t), + void *(*)(void *, size_t), void (*)(void *))); + int (*set_cachesize) __P((DB *, u_int32_t, u_int32_t, int)); + int (*set_dup_compare) __P((DB *, + int (*)(DB *, const DBT *, const DBT *))); + int (*set_encrypt) __P((DB *, const char *, u_int32_t)); + void (*set_errcall) __P((DB *, + void (*)(const DB_ENV *, const char *, const char *))); + void (*set_errfile) __P((DB *, FILE *)); + void (*set_errpfx) __P((DB *, const char *)); + int (*set_feedback) __P((DB *, void (*)(DB *, int, int))); + int (*set_flags) __P((DB *, u_int32_t)); + int (*set_lorder) __P((DB *, int)); + void (*set_msgcall) __P((DB *, void (*)(const DB_ENV *, const char *))); + void (*get_msgfile) __P((DB *, FILE **)); + void (*set_msgfile) __P((DB *, FILE *)); + int (*set_pagesize) __P((DB *, u_int32_t)); + int (*set_paniccall) __P((DB *, void (*)(DB_ENV *, int))); + int (*stat) __P((DB *, DB_TXN *, void *, u_int32_t)); + int (*stat_print) __P((DB *, u_int32_t)); + int (*sync) __P((DB *, u_int32_t)); + int (*upgrade) __P((DB *, const char *, u_int32_t)); + int (*verify) __P((DB *, + const char *, const char *, FILE *, u_int32_t)); + + int (*get_bt_minkey) __P((DB *, u_int32_t *)); + int (*set_bt_compare) __P((DB *, + int (*)(DB *, const DBT *, const DBT *))); + int (*set_bt_maxkey) __P((DB *, u_int32_t)); + int (*set_bt_minkey) __P((DB *, u_int32_t)); + int (*set_bt_prefix) __P((DB *, + size_t (*)(DB *, const DBT *, const DBT *))); + + int (*get_h_ffactor) __P((DB *, u_int32_t *)); + int (*get_h_nelem) __P((DB *, u_int32_t *)); + int (*set_h_ffactor) __P((DB *, u_int32_t)); + int (*set_h_hash) __P((DB *, + u_int32_t (*)(DB *, const void *, u_int32_t))); + int (*set_h_nelem) __P((DB *, u_int32_t)); + + int (*get_re_delim) __P((DB *, int *)); + int (*get_re_len) __P((DB *, u_int32_t *)); + int (*get_re_pad) __P((DB *, int *)); + int (*get_re_source) __P((DB *, const char **)); + int (*set_re_delim) __P((DB *, int)); + int (*set_re_len) __P((DB *, u_int32_t)); + int (*set_re_pad) __P((DB *, int)); + int (*set_re_source) __P((DB *, const char *)); + + int (*get_q_extentsize) __P((DB *, u_int32_t *)); + int (*set_q_extentsize) __P((DB *, u_int32_t)); + + int (*db_am_remove) __P((DB *, DB_TXN *, const char *, const char *)); + int (*db_am_rename) __P((DB *, DB_TXN *, + const char *, const char *, const char *)); + + /* + * Never called; these are a place to save function pointers + * so that we can undo an associate. + */ + int (*stored_get) __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t)); + int (*stored_close) __P((DB *, u_int32_t)); + +#define DB_OK_BTREE 0x01 +#define DB_OK_HASH 0x02 +#define DB_OK_QUEUE 0x04 +#define DB_OK_RECNO 0x08 + u_int32_t am_ok; /* Legal AM choices. */ + +#define DB_AM_CHKSUM 0x00000001 /* Checksumming. */ +#define DB_AM_CL_WRITER 0x00000002 /* Allow writes in client replica. */ +#define DB_AM_COMPENSATE 0x00000004 /* Created by compensating txn. */ +#define DB_AM_CREATED 0x00000008 /* Database was created upon open. */ +#define DB_AM_CREATED_MSTR 0x00000010 /* Encompassing file was created. */ +#define DB_AM_DBM_ERROR 0x00000020 /* Error in DBM/NDBM database. */ +#define DB_AM_DELIMITER 0x00000040 /* Variable length delimiter set. */ +#define DB_AM_DIRTY 0x00000080 /* Support Dirty Reads. */ +#define DB_AM_DISCARD 0x00000100 /* Discard any cached pages. */ +#define DB_AM_DUP 0x00000200 /* DB_DUP. */ +#define DB_AM_DUPSORT 0x00000400 /* DB_DUPSORT. */ +#define DB_AM_ENCRYPT 0x00000800 /* Encryption. */ +#define DB_AM_FIXEDLEN 0x00001000 /* Fixed-length records. */ +#define DB_AM_INMEM 0x00002000 /* In-memory; no sync on close. */ +#define DB_AM_INORDER 0x00004000 /* DB_INORDER. */ +#define DB_AM_IN_RENAME 0x00008000 /* File is being renamed. */ +#define DB_AM_NOT_DURABLE 0x00010000 /* Do not log changes. */ +#define DB_AM_OPEN_CALLED 0x00020000 /* DB->open called. */ +#define DB_AM_PAD 0x00040000 /* Fixed-length record pad. */ +#define DB_AM_PGDEF 0x00080000 /* Page size was defaulted. */ +#define DB_AM_RDONLY 0x00100000 /* Database is readonly. */ +#define DB_AM_RECNUM 0x00200000 /* DB_RECNUM. */ +#define DB_AM_RECOVER 0x00400000 /* DB opened by recovery routine. */ +#define DB_AM_RENUMBER 0x00800000 /* DB_RENUMBER. */ +#define DB_AM_REPLICATION 0x01000000 /* An internal replication file. */ +#define DB_AM_REVSPLITOFF 0x02000000 /* DB_REVSPLITOFF. */ +#define DB_AM_SECONDARY 0x04000000 /* Database is a secondary index. */ +#define DB_AM_SNAPSHOT 0x08000000 /* DB_SNAPSHOT. */ +#define DB_AM_SUBDB 0x10000000 /* Subdatabases supported. */ +#define DB_AM_SWAP 0x20000000 /* Pages need to be byte-swapped. */ +#define DB_AM_TXN 0x40000000 /* Opened in a transaction. */ +#define DB_AM_VERIFYING 0x80000000 /* DB handle is in the verifier. */ + u_int32_t orig_flags; /* Flags at open, for refresh. */ + u_int32_t flags; +}; + +/* + * Macros for bulk get. These are only intended for the C API. + * For C++, use DbMultiple*Iterator. + */ +#define DB_MULTIPLE_INIT(pointer, dbt) \ + (pointer = (u_int8_t *)(dbt)->data + \ + (dbt)->ulen - sizeof(u_int32_t)) +#define DB_MULTIPLE_NEXT(pointer, dbt, retdata, retdlen) \ + do { \ + if (*((u_int32_t *)(pointer)) == (u_int32_t)-1) { \ + retdata = NULL; \ + pointer = NULL; \ + break; \ + } \ + retdata = (u_int8_t *) \ + (dbt)->data + *(u_int32_t *)(pointer); \ + (pointer) = (u_int32_t *)(pointer) - 1; \ + retdlen = *(u_int32_t *)(pointer); \ + (pointer) = (u_int32_t *)(pointer) - 1; \ + if (retdlen == 0 && \ + retdata == (u_int8_t *)(dbt)->data) \ + retdata = NULL; \ + } while (0) +#define DB_MULTIPLE_KEY_NEXT(pointer, dbt, retkey, retklen, retdata, retdlen) \ + do { \ + if (*((u_int32_t *)(pointer)) == (u_int32_t)-1) { \ + retdata = NULL; \ + retkey = NULL; \ + pointer = NULL; \ + break; \ + } \ + retkey = (u_int8_t *) \ + (dbt)->data + *(u_int32_t *)(pointer); \ + (pointer) = (u_int32_t *)(pointer) - 1; \ + retklen = *(u_int32_t *)(pointer); \ + (pointer) = (u_int32_t *)(pointer) - 1; \ + retdata = (u_int8_t *) \ + (dbt)->data + *(u_int32_t *)(pointer); \ + (pointer) = (u_int32_t *)(pointer) - 1; \ + retdlen = *(u_int32_t *)(pointer); \ + (pointer) = (u_int32_t *)(pointer) - 1; \ + } while (0) + +#define DB_MULTIPLE_RECNO_NEXT(pointer, dbt, recno, retdata, retdlen) \ + do { \ + if (*((u_int32_t *)(pointer)) == (u_int32_t)0) { \ + recno = 0; \ + retdata = NULL; \ + pointer = NULL; \ + break; \ + } \ + recno = *(u_int32_t *)(pointer); \ + (pointer) = (u_int32_t *)(pointer) - 1; \ + retdata = (u_int8_t *) \ + (dbt)->data + *(u_int32_t *)(pointer); \ + (pointer) = (u_int32_t *)(pointer) - 1; \ + retdlen = *(u_int32_t *)(pointer); \ + (pointer) = (u_int32_t *)(pointer) - 1; \ + } while (0) + +/******************************************************* + * Access method cursors. + *******************************************************/ +struct __dbc { + DB *dbp; /* Related DB access method. */ + DB_TXN *txn; /* Associated transaction. */ + + /* + * Active/free cursor queues. + * + * !!! + * Explicit representations of structures from queue.h. + * TAILQ_ENTRY(__dbc) links; + */ + struct { + DBC *tqe_next; + DBC **tqe_prev; + } links; + + /* + * The DBT *'s below are used by the cursor routines to return + * data to the user when DBT flags indicate that DB should manage + * the returned memory. They point at a DBT containing the buffer + * and length that will be used, and "belonging" to the handle that + * should "own" this memory. This may be a "my_*" field of this + * cursor--the default--or it may be the corresponding field of + * another cursor, a DB handle, a join cursor, etc. In general, it + * will be whatever handle the user originally used for the current + * DB interface call. + */ + DBT *rskey; /* Returned secondary key. */ + DBT *rkey; /* Returned [primary] key. */ + DBT *rdata; /* Returned data. */ + + DBT my_rskey; /* Space for returned secondary key. */ + DBT my_rkey; /* Space for returned [primary] key. */ + DBT my_rdata; /* Space for returned data. */ + + u_int32_t lid; /* Default process' locker id. */ + u_int32_t locker; /* Locker for this operation. */ + DBT lock_dbt; /* DBT referencing lock. */ + DB_LOCK_ILOCK lock; /* Object to be locked. */ + DB_LOCK mylock; /* CDB lock held on this cursor. */ + + u_int cl_id; /* Remote client id. */ + + DBTYPE dbtype; /* Cursor type. */ + + DBC_INTERNAL *internal; /* Access method private. */ + + int (*c_close) __P((DBC *)); /* Methods: public. */ + int (*c_count) __P((DBC *, db_recno_t *, u_int32_t)); + int (*c_del) __P((DBC *, u_int32_t)); + int (*c_dup) __P((DBC *, DBC **, u_int32_t)); + int (*c_get) __P((DBC *, DBT *, DBT *, u_int32_t)); + int (*c_pget) __P((DBC *, DBT *, DBT *, DBT *, u_int32_t)); + int (*c_put) __P((DBC *, DBT *, DBT *, u_int32_t)); + + /* Methods: private. */ + int (*c_am_bulk) __P((DBC *, DBT *, u_int32_t)); + int (*c_am_close) __P((DBC *, db_pgno_t, int *)); + int (*c_am_del) __P((DBC *)); + int (*c_am_destroy) __P((DBC *)); + int (*c_am_get) __P((DBC *, DBT *, DBT *, u_int32_t, db_pgno_t *)); + int (*c_am_put) __P((DBC *, DBT *, DBT *, u_int32_t, db_pgno_t *)); + int (*c_am_writelock) __P((DBC *)); + +#define DBC_ACTIVE 0x0001 /* Cursor in use. */ +#define DBC_COMPENSATE 0x0002 /* Cursor compensating, don't lock. */ +#define DBC_DEGREE_2 0x0004 /* Cursor has degree 2 isolation. */ +#define DBC_DIRTY_READ 0x0008 /* Cursor supports dirty reads. */ +#define DBC_OPD 0x0010 /* Cursor references off-page dups. */ +#define DBC_RECOVER 0x0020 /* Recovery cursor; don't log/lock. */ +#define DBC_RMW 0x0040 /* Acquire write flag in read op. */ +#define DBC_TRANSIENT 0x0080 /* Cursor is transient. */ +#define DBC_WRITECURSOR 0x0100 /* Cursor may be used to write (CDB). */ +#define DBC_WRITER 0x0200 /* Cursor immediately writing (CDB). */ +#define DBC_MULTIPLE 0x0400 /* Return Multiple data. */ +#define DBC_MULTIPLE_KEY 0x0800 /* Return Multiple keys and data. */ +#define DBC_OWN_LID 0x1000 /* Free lock id on destroy. */ + u_int32_t flags; +}; + +/* Key range statistics structure */ +struct __key_range { + double less; + double equal; + double greater; +}; + +/* Btree/Recno statistics structure. */ +struct __db_bt_stat { + u_int32_t bt_magic; /* Magic number. */ + u_int32_t bt_version; /* Version number. */ + u_int32_t bt_metaflags; /* Metadata flags. */ + u_int32_t bt_nkeys; /* Number of unique keys. */ + u_int32_t bt_ndata; /* Number of data items. */ + u_int32_t bt_pagesize; /* Page size. */ + u_int32_t bt_maxkey; /* Maxkey value. */ + u_int32_t bt_minkey; /* Minkey value. */ + u_int32_t bt_re_len; /* Fixed-length record length. */ + u_int32_t bt_re_pad; /* Fixed-length record pad. */ + u_int32_t bt_levels; /* Tree levels. */ + u_int32_t bt_int_pg; /* Internal pages. */ + u_int32_t bt_leaf_pg; /* Leaf pages. */ + u_int32_t bt_dup_pg; /* Duplicate pages. */ + u_int32_t bt_over_pg; /* Overflow pages. */ + u_int32_t bt_empty_pg; /* Empty pages. */ + u_int32_t bt_free; /* Pages on the free list. */ + u_int32_t bt_int_pgfree; /* Bytes free in internal pages. */ + u_int32_t bt_leaf_pgfree; /* Bytes free in leaf pages. */ + u_int32_t bt_dup_pgfree; /* Bytes free in duplicate pages. */ + u_int32_t bt_over_pgfree; /* Bytes free in overflow pages. */ +}; + +/* Hash statistics structure. */ +struct __db_h_stat { + u_int32_t hash_magic; /* Magic number. */ + u_int32_t hash_version; /* Version number. */ + u_int32_t hash_metaflags; /* Metadata flags. */ + u_int32_t hash_nkeys; /* Number of unique keys. */ + u_int32_t hash_ndata; /* Number of data items. */ + u_int32_t hash_pagesize; /* Page size. */ + u_int32_t hash_ffactor; /* Fill factor specified at create. */ + u_int32_t hash_buckets; /* Number of hash buckets. */ + u_int32_t hash_free; /* Pages on the free list. */ + u_int32_t hash_bfree; /* Bytes free on bucket pages. */ + u_int32_t hash_bigpages; /* Number of big key/data pages. */ + u_int32_t hash_big_bfree; /* Bytes free on big item pages. */ + u_int32_t hash_overflows; /* Number of overflow pages. */ + u_int32_t hash_ovfl_free; /* Bytes free on ovfl pages. */ + u_int32_t hash_dup; /* Number of dup pages. */ + u_int32_t hash_dup_free; /* Bytes free on duplicate pages. */ +}; + +/* Queue statistics structure. */ +struct __db_qam_stat { + u_int32_t qs_magic; /* Magic number. */ + u_int32_t qs_version; /* Version number. */ + u_int32_t qs_metaflags; /* Metadata flags. */ + u_int32_t qs_nkeys; /* Number of unique keys. */ + u_int32_t qs_ndata; /* Number of data items. */ + u_int32_t qs_pagesize; /* Page size. */ + u_int32_t qs_extentsize; /* Pages per extent. */ + u_int32_t qs_pages; /* Data pages. */ + u_int32_t qs_re_len; /* Fixed-length record length. */ + u_int32_t qs_re_pad; /* Fixed-length record pad. */ + u_int32_t qs_pgfree; /* Bytes free in data pages. */ + u_int32_t qs_first_recno; /* First not deleted record. */ + u_int32_t qs_cur_recno; /* Next available record number. */ +}; + +/******************************************************* + * Environment. + *******************************************************/ +#define DB_REGION_MAGIC 0x120897 /* Environment magic number. */ + +/* Database Environment handle. */ +struct __db_env { + /******************************************************* + * Public: owned by the application. + *******************************************************/ + /* Error message callback. */ + void (*db_errcall) __P((const DB_ENV *, const char *, const char *)); + FILE *db_errfile; /* Error message file stream. */ + const char *db_errpfx; /* Error message prefix. */ + + FILE *db_msgfile; /* Statistics message file stream. */ + /* Statistics message callback. */ + void (*db_msgcall) __P((const DB_ENV *, const char *)); + + /* Other Callbacks. */ + void (*db_feedback) __P((DB_ENV *, int, int)); + void (*db_paniccall) __P((DB_ENV *, int)); + + /* App-specified alloc functions. */ + void *(*db_malloc) __P((size_t)); + void *(*db_realloc) __P((void *, size_t)); + void (*db_free) __P((void *)); + + /* + * Currently, the verbose list is a bit field with room for 32 + * entries. There's no reason that it needs to be limited, if + * there are ever more than 32 entries, convert to a bit array. + */ +#define DB_VERB_DEADLOCK 0x0001 /* Deadlock detection information. */ +#define DB_VERB_RECOVERY 0x0002 /* Recovery information. */ +#define DB_VERB_REPLICATION 0x0004 /* Replication information. */ +#define DB_VERB_WAITSFOR 0x0008 /* Dump waits-for table. */ + u_int32_t verbose; /* Verbose output. */ + + void *app_private; /* Application-private handle. */ + + int (*app_dispatch) /* User-specified recovery dispatch. */ + __P((DB_ENV *, DBT *, DB_LSN *, db_recops)); + + /* Locking. */ + u_int8_t *lk_conflicts; /* Two dimensional conflict matrix. */ + int lk_modes; /* Number of lock modes in table. */ + u_int32_t lk_max; /* Maximum number of locks. */ + u_int32_t lk_max_lockers;/* Maximum number of lockers. */ + u_int32_t lk_max_objects;/* Maximum number of locked objects. */ + u_int32_t lk_detect; /* Deadlock detect on all conflicts. */ + db_timeout_t lk_timeout; /* Lock timeout period. */ + + /* Logging. */ + u_int32_t lg_bsize; /* Buffer size. */ + u_int32_t lg_size; /* Log file size. */ + u_int32_t lg_regionmax; /* Region size. */ + + /* Memory pool. */ + u_int32_t mp_gbytes; /* Cachesize: GB. */ + u_int32_t mp_bytes; /* Cachesize: Bytes. */ + u_int mp_ncache; /* Number of cache regions. */ + size_t mp_mmapsize; /* Maximum file size for mmap. */ + int mp_maxopenfd; /* Maximum open file descriptors. */ + int mp_maxwrite; /* Maximum buffers to write. */ + int /* Sleep after writing max buffers. */ + mp_maxwrite_sleep; + + /* Replication */ + int rep_eid; /* environment id. */ + int (*rep_send) /* Send function. */ + __P((DB_ENV *, const DBT *, const DBT *, + const DB_LSN *, int, u_int32_t)); + + /* Transactions. */ + u_int32_t tx_max; /* Maximum number of transactions. */ + time_t tx_timestamp; /* Recover to specific timestamp. */ + db_timeout_t tx_timeout; /* Timeout for transactions. */ + + /******************************************************* + * Private: owned by DB. + *******************************************************/ + /* User files, paths. */ + char *db_home; /* Database home. */ + char *db_log_dir; /* Database log file directory. */ + char *db_tmp_dir; /* Database tmp file directory. */ + + char **db_data_dir; /* Database data file directories. */ + int data_cnt; /* Database data file slots. */ + int data_next; /* Next Database data file slot. */ + + int db_mode; /* Default open permissions. */ + int dir_mode; /* Intermediate directory perms. */ + u_int32_t env_lid; /* Locker ID in non-threaded handles. */ + u_int32_t open_flags; /* Flags passed to DB_ENV->open. */ + + void *reginfo; /* REGINFO structure reference. */ + DB_FH *lockfhp; /* fcntl(2) locking file handle. */ + + int (**recover_dtab) /* Dispatch table for recover funcs. */ + __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + size_t recover_dtab_size; + /* Slots in the dispatch table. */ + + void *cl_handle; /* RPC: remote client handle. */ + u_int cl_id; /* RPC: remote client env id. */ + + int db_ref; /* DB reference count. */ + + long shm_key; /* shmget(2) key. */ + u_int32_t tas_spins; /* test-and-set spins. */ + + /* + * List of open DB handles for this DB_ENV, used for cursor + * adjustment. Must be protected for multi-threaded support. + * + * !!! + * As this structure is allocated in per-process memory, the + * mutex may need to be stored elsewhere on architectures unable + * to support mutexes in heap memory, e.g. HP/UX 9. + * + * !!! + * Explicit representation of structure in queue.h. + * LIST_HEAD(dblist, __db); + */ + DB_MUTEX *dblist_mutexp; /* Mutex. */ + struct { + struct __db *lh_first; + } dblist; + + /* + * XA support. + * + * !!! + * Explicit representations of structures from queue.h. + * TAILQ_ENTRY(__db_env) links; + * TAILQ_HEAD(xa_txn, __db_txn); + */ + struct { + struct __db_env *tqe_next; + struct __db_env **tqe_prev; + } links; + struct __xa_txn { /* XA Active Transactions. */ + struct __db_txn *tqh_first; + struct __db_txn **tqh_last; + } xa_txn; + int xa_rmid; /* XA Resource Manager ID. */ + + /* API-private structure. */ + void *api1_internal; /* C++, Perl API private */ + void *api2_internal; /* Java API private */ + + char *passwd; /* Cryptography support. */ + size_t passwd_len; + void *crypto_handle; /* Primary handle. */ + DB_MUTEX *mt_mutexp; /* Mersenne Twister mutex. */ + int mti; /* Mersenne Twister index. */ + u_long *mt; /* Mersenne Twister state vector. */ + + /* DB_ENV Methods. */ + int (*close) __P((DB_ENV *, u_int32_t)); + int (*dbremove) __P((DB_ENV *, + DB_TXN *, const char *, const char *, u_int32_t)); + int (*dbrename) __P((DB_ENV *, DB_TXN *, + const char *, const char *, const char *, u_int32_t)); + void (*err) __P((const DB_ENV *, int, const char *, ...)); + void (*errx) __P((const DB_ENV *, const char *, ...)); + int (*open) __P((DB_ENV *, const char *, u_int32_t, int)); + int (*remove) __P((DB_ENV *, const char *, u_int32_t)); + int (*stat_print) __P((DB_ENV *, u_int32_t)); + + /* House-keeping. */ + int (*fileid_reset) __P((DB_ENV *, char *, int)); + int (*is_bigendian) __P((void)); + int (*lsn_reset) __P((DB_ENV *, char *, int)); + int (*prdbt) __P((DBT *, + int, const char *, void *, int (*)(void *, const void *), int)); + + /* Setters/getters. */ + int (*set_alloc) __P((DB_ENV *, void *(*)(size_t), + void *(*)(void *, size_t), void (*)(void *))); + int (*set_app_dispatch) __P((DB_ENV *, + int (*)(DB_ENV *, DBT *, DB_LSN *, db_recops))); + int (*get_data_dirs) __P((DB_ENV *, const char ***)); + int (*set_data_dir) __P((DB_ENV *, const char *)); + int (*get_encrypt_flags) __P((DB_ENV *, u_int32_t *)); + int (*set_encrypt) __P((DB_ENV *, const char *, u_int32_t)); + void (*set_errcall) __P((DB_ENV *, + void (*)(const DB_ENV *, const char *, const char *))); + void (*get_errfile) __P((DB_ENV *, FILE **)); + void (*set_errfile) __P((DB_ENV *, FILE *)); + void (*get_errpfx) __P((DB_ENV *, const char **)); + void (*set_errpfx) __P((DB_ENV *, const char *)); + int (*set_feedback) __P((DB_ENV *, void (*)(DB_ENV *, int, int))); + int (*get_flags) __P((DB_ENV *, u_int32_t *)); + int (*set_flags) __P((DB_ENV *, u_int32_t, int)); + int (*get_home) __P((DB_ENV *, const char **)); + int (*set_intermediate_dir) __P((DB_ENV *, int, u_int32_t)); + int (*get_open_flags) __P((DB_ENV *, u_int32_t *)); + int (*set_paniccall) __P((DB_ENV *, void (*)(DB_ENV *, int))); + int (*set_rpc_server) __P((DB_ENV *, + void *, const char *, long, long, u_int32_t)); + int (*get_shm_key) __P((DB_ENV *, long *)); + int (*set_shm_key) __P((DB_ENV *, long)); + void (*set_msgcall) __P((DB_ENV *, + void (*)(const DB_ENV *, const char *))); + void (*get_msgfile) __P((DB_ENV *, FILE **)); + void (*set_msgfile) __P((DB_ENV *, FILE *)); + int (*get_tas_spins) __P((DB_ENV *, u_int32_t *)); + int (*set_tas_spins) __P((DB_ENV *, u_int32_t)); + int (*get_tmp_dir) __P((DB_ENV *, const char **)); + int (*set_tmp_dir) __P((DB_ENV *, const char *)); + int (*get_verbose) __P((DB_ENV *, u_int32_t, int *)); + int (*set_verbose) __P((DB_ENV *, u_int32_t, int)); + + void *lg_handle; /* Log handle and methods. */ + int (*get_lg_bsize) __P((DB_ENV *, u_int32_t *)); + int (*set_lg_bsize) __P((DB_ENV *, u_int32_t)); + int (*get_lg_dir) __P((DB_ENV *, const char **)); + int (*set_lg_dir) __P((DB_ENV *, const char *)); + int (*get_lg_max) __P((DB_ENV *, u_int32_t *)); + int (*set_lg_max) __P((DB_ENV *, u_int32_t)); + int (*get_lg_regionmax) __P((DB_ENV *, u_int32_t *)); + int (*set_lg_regionmax) __P((DB_ENV *, u_int32_t)); + int (*log_archive) __P((DB_ENV *, char **[], u_int32_t)); + int (*log_cursor) __P((DB_ENV *, DB_LOGC **, u_int32_t)); + int (*log_file) __P((DB_ENV *, const DB_LSN *, char *, size_t)); + int (*log_flush) __P((DB_ENV *, const DB_LSN *)); + int (*log_put) __P((DB_ENV *, DB_LSN *, const DBT *, u_int32_t)); + int (*log_stat) __P((DB_ENV *, DB_LOG_STAT **, u_int32_t)); + int (*log_stat_print) __P((DB_ENV *, u_int32_t)); + + void *lk_handle; /* Lock handle and methods. */ + int (*get_lk_conflicts) __P((DB_ENV *, const u_int8_t **, int *)); + int (*set_lk_conflicts) __P((DB_ENV *, u_int8_t *, int)); + int (*get_lk_detect) __P((DB_ENV *, u_int32_t *)); + int (*set_lk_detect) __P((DB_ENV *, u_int32_t)); + int (*set_lk_max) __P((DB_ENV *, u_int32_t)); + int (*get_lk_max_locks) __P((DB_ENV *, u_int32_t *)); + int (*set_lk_max_locks) __P((DB_ENV *, u_int32_t)); + int (*get_lk_max_lockers) __P((DB_ENV *, u_int32_t *)); + int (*set_lk_max_lockers) __P((DB_ENV *, u_int32_t)); + int (*get_lk_max_objects) __P((DB_ENV *, u_int32_t *)); + int (*set_lk_max_objects) __P((DB_ENV *, u_int32_t)); + int (*lock_detect) __P((DB_ENV *, u_int32_t, u_int32_t, int *)); + int (*lock_get) __P((DB_ENV *, + u_int32_t, u_int32_t, const DBT *, db_lockmode_t, DB_LOCK *)); + int (*lock_put) __P((DB_ENV *, DB_LOCK *)); + int (*lock_id) __P((DB_ENV *, u_int32_t *)); + int (*lock_id_free) __P((DB_ENV *, u_int32_t)); + int (*lock_stat) __P((DB_ENV *, DB_LOCK_STAT **, u_int32_t)); + int (*lock_stat_print) __P((DB_ENV *, u_int32_t)); + int (*lock_vec) __P((DB_ENV *, + u_int32_t, u_int32_t, DB_LOCKREQ *, int, DB_LOCKREQ **)); + + void *mp_handle; /* Mpool handle and methods. */ + int (*get_cachesize) __P((DB_ENV *, u_int32_t *, u_int32_t *, int *)); + int (*set_cachesize) __P((DB_ENV *, u_int32_t, u_int32_t, int)); + int (*get_mp_mmapsize) __P((DB_ENV *, size_t *)); + int (*set_mp_mmapsize) __P((DB_ENV *, size_t)); + int (*get_mp_max_openfd) __P((DB_ENV *, int *)); + int (*set_mp_max_openfd) __P((DB_ENV *, int)); + int (*get_mp_max_write) __P((DB_ENV *, int *, int *)); + int (*set_mp_max_write) __P((DB_ENV *, int, int)); + int (*memp_fcreate) __P((DB_ENV *, DB_MPOOLFILE **, u_int32_t)); + int (*memp_register) __P((DB_ENV *, int, + int (*)(DB_ENV *, db_pgno_t, void *, DBT *), + int (*)(DB_ENV *, db_pgno_t, void *, DBT *))); + int (*memp_stat) __P((DB_ENV *, + DB_MPOOL_STAT **, DB_MPOOL_FSTAT ***, u_int32_t)); + int (*memp_stat_print) __P((DB_ENV *, u_int32_t)); + int (*memp_sync) __P((DB_ENV *, DB_LSN *)); + int (*memp_trickle) __P((DB_ENV *, int, int *)); + + void *rep_handle; /* Replication handle and methods. */ + int (*rep_elect) __P((DB_ENV *, int, int, int, + u_int32_t, int *, u_int32_t)); + int (*rep_flush) __P((DB_ENV *)); + int (*rep_process_message) __P((DB_ENV *, DBT *, DBT *, + int *, DB_LSN *)); + int (*rep_start) __P((DB_ENV *, DBT *, u_int32_t)); + int (*rep_stat) __P((DB_ENV *, DB_REP_STAT **, u_int32_t)); + int (*rep_stat_print) __P((DB_ENV *, u_int32_t)); + int (*get_rep_limit) __P((DB_ENV *, u_int32_t *, u_int32_t *)); + int (*set_rep_limit) __P((DB_ENV *, u_int32_t, u_int32_t)); + int (*set_rep_request) __P((DB_ENV *, u_int32_t, u_int32_t)); + int (*set_rep_transport) __P((DB_ENV *, int, + int (*) (DB_ENV *, const DBT *, const DBT *, const DB_LSN *, + int, u_int32_t))); + + void *tx_handle; /* Txn handle and methods. */ + int (*get_tx_max) __P((DB_ENV *, u_int32_t *)); + int (*set_tx_max) __P((DB_ENV *, u_int32_t)); + int (*get_tx_timestamp) __P((DB_ENV *, time_t *)); + int (*set_tx_timestamp) __P((DB_ENV *, time_t *)); + int (*txn_begin) __P((DB_ENV *, DB_TXN *, DB_TXN **, u_int32_t)); + int (*txn_checkpoint) __P((DB_ENV *, u_int32_t, u_int32_t, u_int32_t)); + int (*txn_recover) __P((DB_ENV *, + DB_PREPLIST *, long, long *, u_int32_t)); + int (*txn_stat) __P((DB_ENV *, DB_TXN_STAT **, u_int32_t)); + int (*txn_stat_print) __P((DB_ENV *, u_int32_t)); + int (*get_timeout) __P((DB_ENV *, db_timeout_t *, u_int32_t)); + int (*set_timeout) __P((DB_ENV *, db_timeout_t, u_int32_t)); + +#define DB_TEST_ELECTINIT 1 /* after __rep_elect_init */ +#define DB_TEST_ELECTVOTE1 2 /* after sending VOTE1 */ +#define DB_TEST_POSTDESTROY 3 /* after destroy op */ +#define DB_TEST_POSTLOG 4 /* after logging all pages */ +#define DB_TEST_POSTLOGMETA 5 /* after logging meta in btree */ +#define DB_TEST_POSTOPEN 6 /* after __os_open */ +#define DB_TEST_POSTSYNC 7 /* after syncing the log */ +#define DB_TEST_PREDESTROY 8 /* before destroy op */ +#define DB_TEST_PREOPEN 9 /* before __os_open */ +#define DB_TEST_SUBDB_LOCKS 10 /* subdb locking tests */ + int test_abort; /* Abort value for testing. */ + int test_check; /* Checkpoint value for testing. */ + int test_copy; /* Copy value for testing. */ + +#define DB_ENV_AUTO_COMMIT 0x0000001 /* DB_AUTO_COMMIT. */ +#define DB_ENV_CDB 0x0000002 /* DB_INIT_CDB. */ +#define DB_ENV_CDB_ALLDB 0x0000004 /* CDB environment wide locking. */ +#define DB_ENV_CREATE 0x0000008 /* DB_CREATE set. */ +#define DB_ENV_DBLOCAL 0x0000010 /* DB_ENV allocated for private DB. */ +#define DB_ENV_DIRECT_DB 0x0000020 /* DB_DIRECT_DB set. */ +#define DB_ENV_DIRECT_LOG 0x0000040 /* DB_DIRECT_LOG set. */ +#define DB_ENV_DSYNC_LOG 0x0000080 /* DB_DSYNC_LOG set. */ +#define DB_ENV_FATAL 0x0000100 /* Doing fatal recovery in env. */ +#define DB_ENV_LOCKDOWN 0x0000200 /* DB_LOCKDOWN set. */ +#define DB_ENV_LOG_AUTOREMOVE 0x0000400 /* DB_LOG_AUTOREMOVE set. */ +#define DB_ENV_LOG_INMEMORY 0x0000800 /* DB_LOG_INMEMORY set. */ +#define DB_ENV_NOLOCKING 0x0001000 /* DB_NOLOCKING set. */ +#define DB_ENV_NOMMAP 0x0002000 /* DB_NOMMAP set. */ +#define DB_ENV_NOPANIC 0x0004000 /* Okay if panic set. */ +#define DB_ENV_OPEN_CALLED 0x0008000 /* DB_ENV->open called. */ +#define DB_ENV_OVERWRITE 0x0010000 /* DB_OVERWRITE set. */ +#define DB_ENV_PRIVATE 0x0020000 /* DB_PRIVATE set. */ +#define DB_ENV_REGION_INIT 0x0040000 /* DB_REGION_INIT set. */ +#define DB_ENV_RPCCLIENT 0x0080000 /* DB_RPCCLIENT set. */ +#define DB_ENV_RPCCLIENT_GIVEN 0x0100000 /* User-supplied RPC client struct */ +#define DB_ENV_SYSTEM_MEM 0x0200000 /* DB_SYSTEM_MEM set. */ +#define DB_ENV_THREAD 0x0400000 /* DB_THREAD set. */ +#define DB_ENV_TIME_NOTGRANTED 0x0800000 /* DB_TIME_NOTGRANTED set. */ +#define DB_ENV_TXN_NOSYNC 0x1000000 /* DB_TXN_NOSYNC set. */ +#define DB_ENV_TXN_WRITE_NOSYNC 0x2000000 /* DB_TXN_WRITE_NOSYNC set. */ +#define DB_ENV_YIELDCPU 0x4000000 /* DB_YIELDCPU set. */ + u_int32_t flags; +}; + +#ifndef DB_DBM_HSEARCH +#define DB_DBM_HSEARCH 0 /* No historic interfaces by default. */ +#endif +#if DB_DBM_HSEARCH != 0 +/******************************************************* + * Dbm/Ndbm historic interfaces. + *******************************************************/ +typedef struct __db DBM; + +#define DBM_INSERT 0 /* Flags to dbm_store(). */ +#define DBM_REPLACE 1 + +/* + * The DB support for ndbm(3) always appends this suffix to the + * file name to avoid overwriting the user's original database. + */ +#define DBM_SUFFIX ".db" + +#if defined(_XPG4_2) +typedef struct { + char *dptr; + size_t dsize; +} datum; +#else +typedef struct { + char *dptr; + int dsize; +} datum; +#endif + +/* + * Translate NDBM calls into DB calls so that DB doesn't step on the + * application's name space. + */ +#define dbm_clearerr(a) __db_ndbm_clearerr@DB_VERSION_UNIQUE_NAME@(a) +#define dbm_close(a) __db_ndbm_close@DB_VERSION_UNIQUE_NAME@(a) +#define dbm_delete(a, b) __db_ndbm_delete@DB_VERSION_UNIQUE_NAME@(a, b) +#define dbm_dirfno(a) __db_ndbm_dirfno@DB_VERSION_UNIQUE_NAME@(a) +#define dbm_error(a) __db_ndbm_error@DB_VERSION_UNIQUE_NAME@(a) +#define dbm_fetch(a, b) __db_ndbm_fetch@DB_VERSION_UNIQUE_NAME@(a, b) +#define dbm_firstkey(a) __db_ndbm_firstkey@DB_VERSION_UNIQUE_NAME@(a) +#define dbm_nextkey(a) __db_ndbm_nextkey@DB_VERSION_UNIQUE_NAME@(a) +#define dbm_open(a, b, c) __db_ndbm_open@DB_VERSION_UNIQUE_NAME@(a, b, c) +#define dbm_pagfno(a) __db_ndbm_pagfno@DB_VERSION_UNIQUE_NAME@(a) +#define dbm_rdonly(a) __db_ndbm_rdonly@DB_VERSION_UNIQUE_NAME@(a) +#define dbm_store(a, b, c, d) \ + __db_ndbm_store@DB_VERSION_UNIQUE_NAME@(a, b, c, d) + +/* + * Translate DBM calls into DB calls so that DB doesn't step on the + * application's name space. + * + * The global variables dbrdonly, dirf and pagf were not retained when 4BSD + * replaced the dbm interface with ndbm, and are not supported here. + */ +#define dbminit(a) __db_dbm_init@DB_VERSION_UNIQUE_NAME@(a) +#define dbmclose __db_dbm_close@DB_VERSION_UNIQUE_NAME@ +#if !defined(__cplusplus) +#define delete(a) __db_dbm_delete@DB_VERSION_UNIQUE_NAME@(a) +#endif +#define fetch(a) __db_dbm_fetch@DB_VERSION_UNIQUE_NAME@(a) +#define firstkey __db_dbm_firstkey@DB_VERSION_UNIQUE_NAME@ +#define nextkey(a) __db_dbm_nextkey@DB_VERSION_UNIQUE_NAME@(a) +#define store(a, b) __db_dbm_store@DB_VERSION_UNIQUE_NAME@(a, b) + +/******************************************************* + * Hsearch historic interface. + *******************************************************/ +typedef enum { + FIND, ENTER +} ACTION; + +typedef struct entry { + char *key; + char *data; +} ENTRY; + +#define hcreate(a) __db_hcreate@DB_VERSION_UNIQUE_NAME@(a) +#define hdestroy __db_hdestroy@DB_VERSION_UNIQUE_NAME@ +#define hsearch(a, b) __db_hsearch@DB_VERSION_UNIQUE_NAME@(a, b) + +#endif /* DB_DBM_HSEARCH */ + +#if defined(__cplusplus) +} +#endif +#endif /* !_DB_H_ */ diff --git a/lib_dict/bdb/include/db_185.in b/lib_dict/bdb/include/db_185.in new file mode 100644 index 000000000..338455a60 --- /dev/null +++ b/lib_dict/bdb/include/db_185.in @@ -0,0 +1,169 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996-2004 + * Sleepycat Software. All rights reserved. + */ +/* + * Copyright (c) 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: db_185.in,v 11.11 2004/01/28 03:36:01 bostic Exp $ + */ + +#ifndef _DB_185_H_ +#define _DB_185_H_ + +#include + +#include + +/* + * XXX + * Handle function prototypes and the keyword "const". This steps on name + * space that DB doesn't control, but all of the other solutions are worse. + */ +#undef __P +#if defined(__STDC__) || defined(__cplusplus) +#define __P(protos) protos /* ANSI C prototypes */ +#else +#define const +#define __P(protos) () /* K&R C preprocessor */ +#endif + +#define RET_ERROR -1 /* Return values. */ +#define RET_SUCCESS 0 +#define RET_SPECIAL 1 + +#ifndef __BIT_TYPES_DEFINED__ +#define __BIT_TYPES_DEFINED__ +@u_int8_decl@ +@int16_decl@ +@u_int16_decl@ +@int32_decl@ +@u_int32_decl@ +#endif + +/* + * XXX + * SGI/IRIX already has a pgno_t. + */ +#ifdef sgi +#define pgno_t db_pgno_t +#endif + +#define MAX_PAGE_NUMBER 0xffffffff /* >= # of pages in a file */ +typedef u_int32_t pgno_t; +#define MAX_PAGE_OFFSET 65535 /* >= # of bytes in a page */ +typedef u_int16_t indx_t; +#define MAX_REC_NUMBER 0xffffffff /* >= # of records in a tree */ +typedef u_int32_t recno_t; + +/* Key/data structure -- a Data-Base Thang. */ +typedef struct { + void *data; /* data */ + size_t size; /* data length */ +} DBT; + +/* Routine flags. */ +#define R_CURSOR 1 /* del, put, seq */ +#define __R_UNUSED 2 /* UNUSED */ +#define R_FIRST 3 /* seq */ +#define R_IAFTER 4 /* put (RECNO) */ +#define R_IBEFORE 5 /* put (RECNO) */ +#define R_LAST 6 /* seq (BTREE, RECNO) */ +#define R_NEXT 7 /* seq */ +#define R_NOOVERWRITE 8 /* put */ +#define R_PREV 9 /* seq (BTREE, RECNO) */ +#define R_SETCURSOR 10 /* put (RECNO) */ +#define R_RECNOSYNC 11 /* sync (RECNO) */ + +typedef enum { DB_BTREE, DB_HASH, DB_RECNO } DBTYPE; + +/* Access method description structure. */ +typedef struct __db { + DBTYPE type; /* Underlying db type. */ + int (*close) __P((struct __db *)); + int (*del) __P((const struct __db *, const DBT *, u_int)); + int (*get) __P((const struct __db *, const DBT *, DBT *, u_int)); + int (*put) __P((const struct __db *, DBT *, const DBT *, u_int)); + int (*seq) __P((const struct __db *, DBT *, DBT *, u_int)); + int (*sync) __P((const struct __db *, u_int)); + void *internal; /* Access method private. */ + int (*fd) __P((const struct __db *)); +} DB; + +#define BTREEMAGIC 0x053162 +#define BTREEVERSION 3 + +/* Structure used to pass parameters to the btree routines. */ +typedef struct { +#define R_DUP 0x01 /* duplicate keys */ + u_int32_t flags; + u_int32_t cachesize; /* bytes to cache */ + u_int32_t maxkeypage; /* maximum keys per page */ + u_int32_t minkeypage; /* minimum keys per page */ + u_int32_t psize; /* page size */ + int (*compare) /* comparison function */ + __P((const DBT *, const DBT *)); + size_t (*prefix) /* prefix function */ + __P((const DBT *, const DBT *)); + int lorder; /* byte order */ +} BTREEINFO; + +#define HASHMAGIC 0x061561 +#define HASHVERSION 2 + +/* Structure used to pass parameters to the hashing routines. */ +typedef struct { + u_int32_t bsize; /* bucket size */ + u_int32_t ffactor; /* fill factor */ + u_int32_t nelem; /* number of elements */ + u_int32_t cachesize; /* bytes to cache */ + u_int32_t /* hash function */ + (*hash) __P((const void *, size_t)); + int lorder; /* byte order */ +} HASHINFO; + +/* Structure used to pass parameters to the record routines. */ +typedef struct { +#define R_FIXEDLEN 0x01 /* fixed-length records */ +#define R_NOKEY 0x02 /* key not required */ +#define R_SNAPSHOT 0x04 /* snapshot the input */ + u_int32_t flags; + u_int32_t cachesize; /* bytes to cache */ + u_int32_t psize; /* page size */ + int lorder; /* byte order */ + size_t reclen; /* record length (fixed-length records) */ + u_char bval; /* delimiting byte (variable-length records */ + char *bfname; /* btree file name */ +} RECNOINFO; + +/* Re-define the user's dbopen calls. */ +#define dbopen __db185_open@DB_VERSION_UNIQUE_NAME@ + +#endif /* !_DB_185_H_ */ diff --git a/lib_dict/bdb/include/db_am.h b/lib_dict/bdb/include/db_am.h new file mode 100644 index 000000000..ed1956c66 --- /dev/null +++ b/lib_dict/bdb/include/db_am.h @@ -0,0 +1,154 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996-2004 + * Sleepycat Software. All rights reserved. + * + * $Id: db_am.h,v 11.78 2004/09/22 21:14:56 ubell Exp $ + */ +#ifndef _DB_AM_H_ +#define _DB_AM_H_ + +/* + * IS_AUTO_COMMIT -- + * Test for local auto-commit flag or global flag with no local DbTxn + * handle. + */ +#define IS_AUTO_COMMIT(dbenv, txn, flags) \ + (LF_ISSET(DB_AUTO_COMMIT) || \ + ((txn) == NULL && F_ISSET((dbenv), DB_ENV_AUTO_COMMIT) && \ + !LF_ISSET(DB_NO_AUTO_COMMIT))) + +/* DB recovery operation codes. */ +#define DB_ADD_DUP 1 +#define DB_REM_DUP 2 +#define DB_ADD_BIG 3 +#define DB_REM_BIG 4 + +/* + * Standard initialization and shutdown macros for all recovery functions. + */ +#define REC_INTRO(func, inc_count) do { \ + argp = NULL; \ + dbc = NULL; \ + file_dbp = NULL; \ + /* mpf isn't used by all of the recovery functions. */ \ + COMPQUIET(mpf, NULL); \ + if ((ret = func(dbenv, dbtp->data, &argp)) != 0) \ + goto out; \ + if ((ret = __dbreg_id_to_db(dbenv, argp->txnid, \ + &file_dbp, argp->fileid, inc_count)) != 0) { \ + if (ret == DB_DELETED) { \ + ret = 0; \ + goto done; \ + } \ + goto out; \ + } \ + if ((ret = __db_cursor(file_dbp, NULL, &dbc, 0)) != 0) \ + goto out; \ + F_SET(dbc, DBC_RECOVER); \ + mpf = file_dbp->mpf; \ +} while (0) + +#define REC_CLOSE { \ + int __t_ret; \ + if (argp != NULL) \ + __os_free(dbenv, argp); \ + if (dbc != NULL && \ + (__t_ret = __db_c_close(dbc)) != 0 && ret == 0) \ + ret = __t_ret; \ + } \ + return (ret) + +/* + * No-op versions of the same macros. + */ +#define REC_NOOP_INTRO(func) do { \ + argp = NULL; \ + if ((ret = func(dbenv, dbtp->data, &argp)) != 0) \ + return (ret); \ +} while (0) +#define REC_NOOP_CLOSE \ + if (argp != NULL) \ + __os_free(dbenv, argp); \ + return (ret) + +/* + * Macro for reading pages during recovery. In most cases we + * want to avoid an error if the page is not found during rollback + * or if we are using truncate to remove pages from the file. + */ +#ifndef HAVE_FTRUNCATE +#define REC_FGET(mpf, pgno, pagep, cont) \ + if ((ret = __memp_fget(mpf, &(pgno), 0, pagep)) != 0) { \ + if (ret != DB_PAGE_NOTFOUND || DB_REDO(op)) { \ + ret = __db_pgerr(file_dbp, pgno, ret); \ + goto out; \ + } else \ + goto cont; \ + } +#else +#define REC_FGET(mpf, pgno, pagep, cont) \ + if ((ret = __memp_fget(mpf, &(pgno), 0, pagep)) != 0) { \ + if (ret != DB_PAGE_NOTFOUND) { \ + ret = __db_pgerr(file_dbp, pgno, ret); \ + goto out; \ + } else \ + goto cont; \ + } +#endif + +/* + * Standard debugging macro for all recovery functions. + */ +#ifdef DEBUG_RECOVER +#define REC_PRINT(func) \ + (void)func(dbenv, dbtp, lsnp, op, info); +#else +#define REC_PRINT(func) +#endif + +/* + * Actions to __db_lget + */ +#define LCK_ALWAYS 1 /* Lock even for off page dup cursors */ +#define LCK_COUPLE 2 /* Lock Couple */ +#define LCK_COUPLE_ALWAYS 3 /* Lock Couple even in txn. */ +#define LCK_DOWNGRADE 4 /* Downgrade the lock. (internal) */ +#define LCK_ROLLBACK 5 /* Lock even if in rollback */ + +/* + * If doing transactions we have to hold the locks associated with a data item + * from a page for the entire transaction. However, we don't have to hold the + * locks associated with walking the tree. Distinguish between the two so that + * we don't tie up the internal pages of the tree longer than necessary. + */ +#define __LPUT(dbc, lock) \ + __ENV_LPUT((dbc)->dbp->dbenv, \ + lock, F_ISSET((dbc)->dbp, DB_AM_DIRTY) ? DB_LOCK_DOWNGRADE : 0) +#define __ENV_LPUT(dbenv, lock, flags) \ + (LOCK_ISSET(lock) ? __lock_put(dbenv, &(lock), flags) : 0) + +/* + * __TLPUT -- transactional lock put + * If the lock is valid then + * If we are not in a transaction put the lock. + * Else if the cursor is doing dirty reads and this was a read then + * put the lock. + * Else if the db is supporting dirty reads and this is a write then + * downgrade it. + * Else do nothing. + */ +#define __TLPUT(dbc, lock) \ + (LOCK_ISSET(lock) ? __db_lput(dbc, &(lock)) : 0) + +typedef struct { + DBC *dbc; + u_int32_t count; +} db_trunc_param; + +#include "dbinc/db_dispatch.h" +#include "dbinc_auto/db_auto.h" +#include "dbinc_auto/crdel_auto.h" +#include "dbinc_auto/db_ext.h" +#endif /* !_DB_AM_H_ */ diff --git a/lib_dict/bdb/include/db_auto.h b/lib_dict/bdb/include/db_auto.h new file mode 100644 index 000000000..c2edcedbc --- /dev/null +++ b/lib_dict/bdb/include/db_auto.h @@ -0,0 +1,153 @@ +/* Do not edit: automatically built by gen_rec.awk. */ + +#ifndef __db_AUTO_H +#define __db_AUTO_H +#define DB___db_addrem 41 +typedef struct ___db_addrem_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + u_int32_t opcode; + int32_t fileid; + db_pgno_t pgno; + u_int32_t indx; + u_int32_t nbytes; + DBT hdr; + DBT dbt; + DB_LSN pagelsn; +} __db_addrem_args; + +#define DB___db_big 43 +typedef struct ___db_big_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + u_int32_t opcode; + int32_t fileid; + db_pgno_t pgno; + db_pgno_t prev_pgno; + db_pgno_t next_pgno; + DBT dbt; + DB_LSN pagelsn; + DB_LSN prevlsn; + DB_LSN nextlsn; +} __db_big_args; + +#define DB___db_ovref 44 +typedef struct ___db_ovref_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + db_pgno_t pgno; + int32_t adjust; + DB_LSN lsn; +} __db_ovref_args; + +#define DB___db_debug 47 +typedef struct ___db_debug_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + DBT op; + int32_t fileid; + DBT key; + DBT data; + u_int32_t arg_flags; +} __db_debug_args; + +#define DB___db_noop 48 +typedef struct ___db_noop_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + db_pgno_t pgno; + DB_LSN prevlsn; +} __db_noop_args; + +#define DB___db_pg_alloc 49 +typedef struct ___db_pg_alloc_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + DB_LSN meta_lsn; + db_pgno_t meta_pgno; + DB_LSN page_lsn; + db_pgno_t pgno; + u_int32_t ptype; + db_pgno_t next; + db_pgno_t last_pgno; +} __db_pg_alloc_args; + +#define DB___db_pg_free 50 +typedef struct ___db_pg_free_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + db_pgno_t pgno; + DB_LSN meta_lsn; + db_pgno_t meta_pgno; + DBT header; + db_pgno_t next; + db_pgno_t last_pgno; +} __db_pg_free_args; + +#define DB___db_cksum 51 +typedef struct ___db_cksum_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; +} __db_cksum_args; + +#define DB___db_pg_freedata 52 +typedef struct ___db_pg_freedata_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + db_pgno_t pgno; + DB_LSN meta_lsn; + db_pgno_t meta_pgno; + DBT header; + db_pgno_t next; + db_pgno_t last_pgno; + DBT data; +} __db_pg_freedata_args; + +#define DB___db_pg_prepare 53 +typedef struct ___db_pg_prepare_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + db_pgno_t pgno; +} __db_pg_prepare_args; + +#define DB___db_pg_new 54 +typedef struct ___db_pg_new_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + db_pgno_t pgno; + DB_LSN meta_lsn; + db_pgno_t meta_pgno; + DBT header; + db_pgno_t next; +} __db_pg_new_args; + +#define DB___db_pg_init 60 +typedef struct ___db_pg_init_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + db_pgno_t pgno; + DBT header; + DBT data; +} __db_pg_init_args; + +#endif diff --git a/lib_dict/bdb/include/db_config.h b/lib_dict/bdb/include/db_config.h new file mode 100644 index 000000000..94c00b3de --- /dev/null +++ b/lib_dict/bdb/include/db_config.h @@ -0,0 +1,443 @@ +/* DO NOT EDIT: automatically built by dist/s_win32. */ +/* Define to 1 if you want to build a version for running the test suite. */ +/* #undef CONFIG_TEST */ + +/* We use DB_WIN32 much as one would use _WIN32 -- to specify that we're using + an operating system environment that supports Win32 calls and semantics. We + don't use _WIN32 because Cygwin/GCC also defines _WIN32, even though + Cygwin/GCC closely emulates the Unix environment. */ +#define DB_WIN32 1 + +/* Define to 1 if you want a debugging version. */ +/* #undef DEBUG */ +#if defined(_DEBUG) +#if !defined(DEBUG) +#define DEBUG 1 +#endif +#endif + +/* Define to 1 if you want a version that logs read operations. */ +/* #undef DEBUG_ROP */ + +/* Define to 1 if you want a version that logs write operations. */ +/* #undef DEBUG_WOP */ + +/* Define to 1 if you want a version with run-time diagnostic checking. */ +/* #undef DIAGNOSTIC */ + +/* Define to 1 if you have the `clock_gettime' function. */ +/* #undef HAVE_CLOCK_GETTIME */ + +/* Define to 1 if Berkeley DB release includes strong cryptography. */ +#ifndef HAVE_SMALLBUILD +#define HAVE_CRYPTO 1 +#endif + +/* Define to 1 if you have the `directio' function. */ +/* #undef HAVE_DIRECTIO */ + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +/* #undef HAVE_DIRENT_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_DLFCN_H */ + +/* Define to 1 if you have EXIT_SUCCESS/EXIT_FAILURE #defines. */ +#define HAVE_EXIT_SUCCESS 1 + +/* Define to 1 if fcntl/F_SETFD denies child access to file descriptors. */ +/* #undef HAVE_FCNTL_F_SETFD */ + +/* Define to 1 if you have the `fdatasync' function. */ +/* #undef HAVE_FDATASYNC */ + +/* Define to 1 if allocated filesystem blocks are not zeroed. */ +#define HAVE_FILESYSTEM_NOTZERO 1 + +/* Define to 1 if you have the `ftruncate' function. */ +#define HAVE_FTRUNCATE 1 + +/* Define to 1 if you have the `getcwd' function. */ +#define HAVE_GETCWD 1 + +/* Define to 1 if you have the `getopt' function. */ +/* #undef HAVE_GETOPT */ + +/* Define to 1 if you have the `getrusage' function. */ +/* #undef HAVE_GETRUSAGE */ + +/* Define to 1 if you have the `gettimeofday' function. */ +/* #undef HAVE_GETTIMEOFDAY */ + +/* Define to 1 if you have the `getuid' function. */ +/* #undef HAVE_GETUID */ + +/* Define to 1 if building Hash access method. */ +#ifndef HAVE_SMALLBUILD +#define HAVE_HASH 1 +#endif + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_INTTYPES_H */ + +/* Define to 1 if you have the `nsl' library (-lnsl). */ +/* #undef HAVE_LIBNSL */ + +/* Define to 1 if the system has the type `long long'. */ +#define HAVE_LONG_LONG 1 + +/* Define to 1 if you have the `memcmp' function. */ +#define HAVE_MEMCMP 1 + +/* Define to 1 if you have the `memcpy' function. */ +#define HAVE_MEMCPY 1 + +/* Define to 1 if you have the `memmove' function. */ +#define HAVE_MEMMOVE 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `mlock' function. */ +/* #undef HAVE_MLOCK */ + +/* Define to 1 if you have the `mmap' function. */ +/* #undef HAVE_MMAP */ + +/* Define to 1 if you have the `munlock' function. */ +/* #undef HAVE_MUNLOCK */ + +/* Define to 1 if you have the `munmap' function. */ +/* #undef HAVE_MUNMAP */ + +/* Define to 1 to use the GCC compiler and 68K assembly language mutexes. */ +/* #undef HAVE_MUTEX_68K_GCC_ASSEMBLY */ + +/* Define to 1 to use the AIX _check_lock mutexes. */ +/* #undef HAVE_MUTEX_AIX_CHECK_LOCK */ + +/* Define to 1 to use the GCC compiler and Alpha assembly language mutexes. */ +/* #undef HAVE_MUTEX_ALPHA_GCC_ASSEMBLY */ + +/* Define to 1 to use the GCC compiler and ARM assembly language mutexes. */ +/* #undef HAVE_MUTEX_ARM_GCC_ASSEMBLY */ + +/* Define to 1 to use the Apple/Darwin _spin_lock_try mutexes. */ +/* #undef HAVE_MUTEX_DARWIN_SPIN_LOCK_TRY */ + +/* Define to 1 to use the UNIX fcntl system call mutexes. */ +/* #undef HAVE_MUTEX_FCNTL */ + +/* Define to 1 to use the GCC compiler and PaRisc assembly language mutexes. + */ +/* #undef HAVE_MUTEX_HPPA_GCC_ASSEMBLY */ + +/* Define to 1 to use the msem_XXX mutexes on HP-UX. */ +/* #undef HAVE_MUTEX_HPPA_MSEM_INIT */ + +/* Define to 1 to use the GCC compiler and IA64 assembly language mutexes. */ +/* #undef HAVE_MUTEX_IA64_GCC_ASSEMBLY */ + +/* Define to 1 to use the msem_XXX mutexes on systems other than HP-UX. */ +/* #undef HAVE_MUTEX_MSEM_INIT */ + +/* Define to 1 to use the GCC compiler and PowerPC assembly language mutexes. + */ +/* #undef HAVE_MUTEX_PPC_GCC_ASSEMBLY */ + +/* Define to 1 to use POSIX 1003.1 pthread_XXX mutexes. */ +/* #undef HAVE_MUTEX_PTHREADS */ + +/* Define to 1 to use Reliant UNIX initspin mutexes. */ +/* #undef HAVE_MUTEX_RELIANTUNIX_INITSPIN */ + +/* Define to 1 to use the IBM C compiler and S/390 assembly language mutexes. + */ +/* #undef HAVE_MUTEX_S390_CC_ASSEMBLY */ + +/* Define to 1 to use the GCC compiler and S/390 assembly language mutexes. */ +/* #undef HAVE_MUTEX_S390_GCC_ASSEMBLY */ + +/* Define to 1 to use the SCO compiler and x86 assembly language mutexes. */ +/* #undef HAVE_MUTEX_SCO_X86_CC_ASSEMBLY */ + +/* Define to 1 to use the obsolete POSIX 1003.1 sema_XXX mutexes. */ +/* #undef HAVE_MUTEX_SEMA_INIT */ + +/* Define to 1 to use the SGI XXX_lock mutexes. */ +/* #undef HAVE_MUTEX_SGI_INIT_LOCK */ + +/* Define to 1 to use the Solaris _lock_XXX mutexes. */ +/* #undef HAVE_MUTEX_SOLARIS_LOCK_TRY */ + +/* Define to 1 to use the Solaris lwp threads mutexes. */ +/* #undef HAVE_MUTEX_SOLARIS_LWP */ + +/* Define to 1 to use the GCC compiler and Sparc assembly language mutexes. */ +/* #undef HAVE_MUTEX_SPARC_GCC_ASSEMBLY */ + +/* Define to 1 if mutexes hold system resources. */ +/* #undef HAVE_MUTEX_SYSTEM_RESOURCES */ + +/* Define to 1 if fast mutexes are available. */ +#define HAVE_MUTEX_THREADS 1 + +/* Define to 1 to configure mutexes intra-process only. */ +/* #undef HAVE_MUTEX_THREAD_ONLY */ + +/* Define to 1 to use the CC compiler and Tru64 assembly language mutexes. */ +/* #undef HAVE_MUTEX_TRU64_CC_ASSEMBLY */ + +/* Define to 1 to use the UNIX International mutexes. */ +/* #undef HAVE_MUTEX_UI_THREADS */ + +/* Define to 1 to use the UTS compiler and assembly language mutexes. */ +/* #undef HAVE_MUTEX_UTS_CC_ASSEMBLY */ + +/* Define to 1 to use VMS mutexes. */ +/* #undef HAVE_MUTEX_VMS */ + +/* Define to 1 to use VxWorks mutexes. */ +/* #undef HAVE_MUTEX_VXWORKS */ + +/* Define to 1 to use the MSVC compiler and Windows mutexes. */ +#define HAVE_MUTEX_WIN32 1 + +/* Define to 1 to use the GCC compiler and Windows mutexes. */ +/* #undef HAVE_MUTEX_WIN32_GCC */ + +/* Define to 1 to use the GCC compiler and x86 assembly language mutexes. */ +/* #undef HAVE_MUTEX_X86_GCC_ASSEMBLY */ + +/* Define to 1 if you have the header file, and it defines `DIR'. */ +/* #undef HAVE_NDIR_H */ + +/* Define to 1 if you have the O_DIRECT flag. */ +/* #undef HAVE_O_DIRECT */ + +/* Define to 1 if you have the `pread' function. */ +/* #undef HAVE_PREAD */ + +/* Define to 1 if you have the `pstat_getdynamic' function. */ +/* #undef HAVE_PSTAT_GETDYNAMIC */ + +/* Define to 1 if you have the `pwrite' function. */ +/* #undef HAVE_PWRITE */ + +/* Define to 1 if building on QNX. */ +/* #undef HAVE_QNX */ + +/* Define to 1 if building Queue access method. */ +#ifndef HAVE_SMALLBUILD +#define HAVE_QUEUE 1 +#endif + +/* Define to 1 if you have the `raise' function. */ +#define HAVE_RAISE 1 + +/* Define to 1 if you have the `rand' function. */ +#define HAVE_RAND 1 + +/* Define to 1 if building replication support. */ +#ifndef HAVE_SMALLBUILD +#define HAVE_REPLICATION 1 +#endif + +/* Define to 1 if building RPC client/server. */ +/* #undef HAVE_RPC */ + +/* Define to 1 if you have the `sched_yield' function. */ +/* #undef HAVE_SCHED_YIELD */ + +/* Define to 1 if you have the `select' function. */ +/* #undef HAVE_SELECT */ + +/* Define to 1 if building sequence support. */ +#define HAVE_SEQUENCE 1 + +/* Define to 1 if you have the `shmget' function. */ +/* #undef HAVE_SHMGET */ + +/* Define to 1 if you have the `snprintf' function. */ +#define HAVE_SNPRINTF 1 + +/* Define to 1 if you have the `srand' function. */ +#define HAVE_SRAND 1 + +/* Define to 1 if building statistics support. */ +#define HAVE_STATISTICS 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_STDINT_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the `strcasecmp' function. */ +/* #undef HAVE_STRCASECMP */ + +/* Define to 1 if you have the `strdup' function. */ +#define HAVE_STRDUP 1 + +/* Define to 1 if you have the `strerror' function. */ +#define HAVE_STRERROR 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 `strtol' function. */ +#define HAVE_STRTOL 1 + +/* Define to 1 if you have the `strtoul' function. */ +#define HAVE_STRTOUL 1 + +/* Define to 1 if `st_blksize' is member of `struct stat'. */ +/* #undef HAVE_STRUCT_STAT_ST_BLKSIZE */ + +/* Define to 1 if you have the `sysconf' function. */ +/* #undef HAVE_SYSCONF */ + +/* 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. */ +#define HAVE_SYS_FCNTL_H 1 + +/* 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. */ +/* #undef HAVE_SYS_SELECT_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. */ +/* #undef HAVE_SYS_TIME_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_UNISTD_H */ + +/* Define to 1 if unlink of file with open file descriptors will fail. */ +/* #undef HAVE_UNLINK_WITH_OPEN_FAILURE */ + +/* Define to 1 if the system has the type `unsigned long long'. */ +#define HAVE_UNSIGNED_LONG_LONG 1 + +/* Define to 1 if building access method verification support. */ +#ifndef HAVE_SMALLBUILD +#define HAVE_VERIFY 1 +#endif + +/* Define to 1 if you have the `vsnprintf' function. */ +#define HAVE_VSNPRINTF 1 + +/* Define to 1 if building VxWorks. */ +/* #undef HAVE_VXWORKS */ + +/* Define to 1 if you have the `yield' function. */ +/* #undef HAVE_YIELD */ + +/* Define to 1 if you have the `_fstati64' function. */ +#define HAVE__FSTATI64 1 + +/* Define to a value if using non-standard mutex alignment. */ +/* #undef MUTEX_ALIGN */ + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "support@sleepycat.com" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "Berkeley DB" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "Berkeley DB 4.3.29" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "db-4.3.29" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "4.3.29" + +/* Define to 1 if the `S_IS*' macros in do not work properly. */ +/* #undef STAT_MACROS_BROKEN */ + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define to 1 if you can safely include both and . */ +/* #undef TIME_WITH_SYS_TIME */ + +/* Define to 1 to mask harmless uninitialized memory read/writes. */ +/* #undef UMRW */ + +/* Number of bits in a file offset, on hosts where this is settable. */ +/* #undef _FILE_OFFSET_BITS */ + +/* Define for large files, on AIX-style hosts. */ +/* #undef _LARGE_FILES */ + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ + +/* + * Exit success/failure macros. + */ +#ifndef HAVE_EXIT_SUCCESS +#define EXIT_FAILURE 1 +#define EXIT_SUCCESS 0 +#endif + +/* + * Don't step on the namespace. Other libraries may have their own + * implementations of these functions, we don't want to use their + * implementations or force them to use ours based on the load order. + */ +#ifndef HAVE_GETCWD +#define getcwd __db_Cgetcwd +#endif +#ifndef HAVE_MEMCMP +#define memcmp __db_Cmemcmp +#endif +#ifndef HAVE_MEMCPY +#define memcpy __db_Cmemcpy +#endif +#ifndef HAVE_MEMMOVE +#define memmove __db_Cmemmove +#endif +#ifndef HAVE_RAISE +#define raise __db_Craise +#endif +#ifndef HAVE_SNPRINTF +#define snprintf __db_Csnprintf +#endif +#ifndef HAVE_STRCASECMP +#define strcasecmp __db_Cstrcasecmp +#define strncasecmp __db_Cstrncasecmp +#endif +#ifndef HAVE_STRERROR +#define strerror __db_Cstrerror +#endif +#ifndef HAVE_VSNPRINTF +#define vsnprintf __db_Cvsnprintf +#endif + +#include "win_db.h" + +/* + * Microsoft's compiler _doesn't_ define __STDC__ unless you invoke it with + * arguments turning OFF all vendor extensions. Even more unfortunately, if + * we do that, it fails to parse windows.h!!!!! So, we define __STDC__ here, + * after windows.h comes in. Note: the compiler knows we've defined it, and + * starts enforcing strict ANSI compliance from this point on. + */ +#define __STDC__ 1 diff --git a/lib_dict/bdb/include/db_cxx.h b/lib_dict/bdb/include/db_cxx.h new file mode 100644 index 000000000..abba7b635 --- /dev/null +++ b/lib_dict/bdb/include/db_cxx.h @@ -0,0 +1,1089 @@ +/* DO NOT EDIT: automatically built by dist/s_win32. */ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997-2004 + * Sleepycat Software. All rights reserved. + * + * $Id: db_cxx.in,v 11.147 2004/10/07 21:39:48 bostic Exp $ + */ + +#ifndef _DB_CXX_H_ +#define _DB_CXX_H_ +// +// C++ assumptions: +// +// To ensure portability to many platforms, both new and old, we make +// few assumptions about the C++ compiler and library. For example, +// we do not expect STL, templates or namespaces to be available. The +// "newest" C++ feature used is exceptions, which are used liberally +// to transmit error information. Even the use of exceptions can be +// disabled at runtime, to do so, use the DB_CXX_NO_EXCEPTIONS flags +// with the DbEnv or Db constructor. +// +// C++ naming conventions: +// +// - All top level class names start with Db. +// - All class members start with lower case letter. +// - All private data members are suffixed with underscore. +// - Use underscores to divide names into multiple words. +// - Simple data accessors are named with get_ or set_ prefix. +// - All method names are taken from names of functions in the C +// layer of db (usually by dropping a prefix like "db_"). +// These methods have the same argument types and order, +// other than dropping the explicit arg that acts as "this". +// +// As a rule, each DbFoo object has exactly one underlying DB_FOO struct +// (defined in db.h) associated with it. In some cases, we inherit directly +// from the DB_FOO structure to make this relationship explicit. Often, +// the underlying C layer allocates and deallocates these structures, so +// there is no easy way to add any data to the DbFoo class. When you see +// a comment about whether data is permitted to be added, this is what +// is going on. Of course, if we need to add data to such C++ classes +// in the future, we will arrange to have an indirect pointer to the +// DB_FOO struct (as some of the classes already have). +// + +//////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////// +// +// Forward declarations +// + +#include + +#define HAVE_CXX_STDHEADERS 1 +#ifdef HAVE_CXX_STDHEADERS +#include +#include +#define __DB_STD(x) std::x +#else +#include +#include +#define __DB_STD(x) x +#endif + +#include "db.h" + +class Db; // forward +class Dbc; // forward +class DbEnv; // forward +class DbInfo; // forward +class DbLock; // forward +class DbLogc; // forward +class DbLsn; // forward +class DbMpoolFile; // forward +class DbPreplist; // forward +class Dbt; // forward +class DbTxn; // forward +class DbLock; // forward +class DbSequence; // forward +class Dbt; // forward + +class DbMultipleIterator; // forward +class DbMultipleKeyDataIterator; // forward +class DbMultipleRecnoDataIterator; // forward +class DbMultipleDataIterator; // forward + +class DbException; // forward +class DbDeadlockException; // forward +class DbLockNotGrantedException; // forward +class DbMemoryException; // forward +class DbRunRecoveryException; // forward + +//////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////// +// +// Turn off inappropriate compiler warnings +// + +#ifdef _MSC_VER + +// These are level 4 warnings that are explicitly disabled. +// With Visual C++, by default you do not see above level 3 unless +// you use /W4. But we like to compile with the highest level +// warnings to catch other errors. +// +// 4201: nameless struct/union +// triggered by standard include file +// +// 4514: unreferenced inline function has been removed +// certain include files in MSVC define methods that are not called +// +#pragma warning(disable: 4201 4514) + +#endif + +//////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////// +// +// Mechanisms for declaring classes +// + +// +// Every class defined in this file has an _exported next to the class name. +// This is needed for WinTel machines so that the class methods can +// be exported or imported in a DLL as appropriate. Users of the DLL +// use the define DB_USE_DLL. When the DLL is built, DB_CREATE_DLL +// must be defined. +// +#if defined(_MSC_VER) + +# if defined(DB_CREATE_DLL) +# define _exported __declspec(dllexport) // creator of dll +# elif defined(DB_USE_DLL) +# define _exported __declspec(dllimport) // user of dll +# else +# define _exported // static lib creator or user +# endif + +#else /* _MSC_VER */ + +# define _exported + +#endif /* _MSC_VER */ + +// Some interfaces can be customized by allowing users to define +// callback functions. For performance and logistical reasons, some +// callback functions must be declared in extern "C" blocks. For others, +// we allow you to declare the callbacks in C++ or C (or an extern "C" +// block) as you wish. See the set methods for the callbacks for +// the choices. +// +extern "C" { + typedef void * (*db_malloc_fcn_type) + (size_t); + typedef void * (*db_realloc_fcn_type) + (void *, size_t); + typedef void (*db_free_fcn_type) + (void *); + typedef int (*bt_compare_fcn_type) /*C++ version available*/ + (DB *, const DBT *, const DBT *); + typedef size_t (*bt_prefix_fcn_type) /*C++ version available*/ + (DB *, const DBT *, const DBT *); + typedef int (*dup_compare_fcn_type) /*C++ version available*/ + (DB *, const DBT *, const DBT *); + typedef u_int32_t (*h_hash_fcn_type) /*C++ version available*/ + (DB *, const void *, u_int32_t); + typedef int (*pgin_fcn_type) + (DB_ENV *dbenv, db_pgno_t pgno, void *pgaddr, DBT *pgcookie); + typedef int (*pgout_fcn_type) + (DB_ENV *dbenv, db_pgno_t pgno, void *pgaddr, DBT *pgcookie); +} + +// +// Represents a database table = a set of keys with associated values. +// +class _exported Db +{ + friend class DbEnv; + +public: + Db(DbEnv*, u_int32_t); // create a Db object, then call open() + virtual ~Db(); // does *not* call close. + + // These methods exactly match those in the C interface. + // + virtual int associate(DbTxn *txn, Db *secondary, + int (*callback)(Db *, const Dbt *, const Dbt *, Dbt *), + u_int32_t flags); + virtual int close(u_int32_t flags); + virtual int cursor(DbTxn *txnid, Dbc **cursorp, u_int32_t flags); + virtual int del(DbTxn *txnid, Dbt *key, u_int32_t flags); + virtual void err(int, const char *, ...); + virtual void errx(const char *, ...); + virtual int fd(int *fdp); + virtual int get(DbTxn *txnid, Dbt *key, Dbt *data, u_int32_t flags); + virtual void *get_app_private() const; + virtual int get_byteswapped(int *); + virtual int get_dbname(const char **, const char **); + virtual int get_open_flags(u_int32_t *); + virtual int get_type(DBTYPE *); + virtual int get_transactional(); + virtual int join(Dbc **curslist, Dbc **dbcp, u_int32_t flags); + virtual int key_range(DbTxn *, Dbt *, DB_KEY_RANGE *, u_int32_t); + virtual int open(DbTxn *txnid, + const char *, const char *subname, DBTYPE, u_int32_t, int); + virtual int pget(DbTxn *txnid, Dbt *key, Dbt *pkey, Dbt *data, + u_int32_t flags); + virtual int put(DbTxn *, Dbt *, Dbt *, u_int32_t); + virtual int remove(const char *, const char *, u_int32_t); + virtual int rename(const char *, const char *, const char *, u_int32_t); + virtual int set_alloc(db_malloc_fcn_type, db_realloc_fcn_type, + db_free_fcn_type); + virtual void set_app_private(void *); + virtual int set_append_recno(int (*)(Db *, Dbt *, db_recno_t)); + virtual int set_bt_compare(bt_compare_fcn_type); /*deprecated*/ + virtual int set_bt_compare(int (*)(Db *, const Dbt *, const Dbt *)); + virtual int set_bt_maxkey(u_int32_t); + virtual int get_bt_minkey(u_int32_t *); + virtual int set_bt_minkey(u_int32_t); + virtual int set_bt_prefix(bt_prefix_fcn_type); /*deprecated*/ + virtual int set_bt_prefix(size_t (*)(Db *, const Dbt *, const Dbt *)); + virtual int get_cachesize(u_int32_t *, u_int32_t *, int *); + virtual int set_cachesize(u_int32_t, u_int32_t, int); + virtual int set_dup_compare(dup_compare_fcn_type); /*deprecated*/ + virtual int set_dup_compare(int (*)(Db *, const Dbt *, const Dbt *)); + virtual int get_encrypt_flags(u_int32_t *); + virtual int set_encrypt(const char *, u_int32_t); + virtual void set_errcall( + void (*)(const DbEnv *, const char *, const char *)); + virtual void get_errfile(FILE **); + virtual void set_errfile(FILE *); + virtual void get_errpfx(const char **); + virtual void set_errpfx(const char *); + virtual int set_feedback(void (*)(Db *, int, int)); + virtual int get_flags(u_int32_t *); + virtual int set_flags(u_int32_t); + virtual int get_h_ffactor(u_int32_t *); + virtual int set_h_ffactor(u_int32_t); + virtual int set_h_hash(h_hash_fcn_type); /*deprecated*/ + virtual int set_h_hash(u_int32_t (*)(Db *, const void *, u_int32_t)); + virtual int get_h_nelem(u_int32_t *); + virtual int set_h_nelem(u_int32_t); + virtual int get_lorder(int *); + virtual int set_lorder(int); + virtual void set_msgcall(void (*)(const DbEnv *, const char *)); + virtual void get_msgfile(FILE **); + virtual void set_msgfile(FILE *); + virtual int get_pagesize(u_int32_t *); + virtual int set_pagesize(u_int32_t); + virtual int set_paniccall(void (*)(DbEnv *, int)); + virtual int get_re_delim(int *); + virtual int set_re_delim(int); + virtual int get_re_len(u_int32_t *); + virtual int set_re_len(u_int32_t); + virtual int get_re_pad(int *); + virtual int set_re_pad(int); + virtual int get_re_source(const char **); + virtual int set_re_source(const char *); + virtual int get_q_extentsize(u_int32_t *); + virtual int set_q_extentsize(u_int32_t); + virtual int stat(DbTxn *, void *sp, u_int32_t flags); + virtual int stat_print(u_int32_t flags); + virtual int sync(u_int32_t flags); + virtual int truncate(DbTxn *, u_int32_t *, u_int32_t); + virtual int upgrade(const char *name, u_int32_t flags); + virtual int verify(const char *, const char *, __DB_STD(ostream) *, + u_int32_t); + + // These additional methods are not in the C interface, and + // are only available for C++. + // + virtual __DB_STD(ostream) *get_error_stream(); + virtual void set_error_stream(__DB_STD(ostream) *); + virtual __DB_STD(ostream) *get_message_stream(); + virtual void set_message_stream(__DB_STD(ostream) *); + + virtual DbEnv *get_env(); + virtual DbMpoolFile *get_mpf(); + + virtual DB *get_DB() + { + return imp_; + } + + virtual const DB *get_const_DB() const + { + return imp_; + } + + static Db* get_Db(DB *db) + { + return (Db *)db->api_internal; + } + + static const Db* get_const_Db(const DB *db) + { + return (const Db *)db->api_internal; + } + +private: + // no copying + Db(const Db &); + Db &operator = (const Db &); + + void cleanup(); + int initialize(); + int error_policy(); + + // instance data + DB *imp_; + DbEnv *env_; + DbMpoolFile *mpf_; + int construct_error_; + u_int32_t flags_; + u_int32_t construct_flags_; + +public: + // These are public only because they need to be called + // via C callback functions. They should never be used by + // external users of this class. + // + int (*append_recno_callback_)(Db *, Dbt *, db_recno_t); + int (*associate_callback_)(Db *, const Dbt *, const Dbt *, Dbt *); + int (*bt_compare_callback_)(Db *, const Dbt *, const Dbt *); + size_t (*bt_prefix_callback_)(Db *, const Dbt *, const Dbt *); + int (*dup_compare_callback_)(Db *, const Dbt *, const Dbt *); + void (*feedback_callback_)(Db *, int, int); + u_int32_t (*h_hash_callback_)(Db *, const void *, u_int32_t); +}; + +// +// Cursor +// +class _exported Dbc : protected DBC +{ + friend class Db; + +public: + int close(); + int count(db_recno_t *countp, u_int32_t flags); + int del(u_int32_t flags); + int dup(Dbc** cursorp, u_int32_t flags); + int get(Dbt* key, Dbt *data, u_int32_t flags); + int pget(Dbt* key, Dbt* pkey, Dbt *data, u_int32_t flags); + int put(Dbt* key, Dbt *data, u_int32_t flags); + +private: + // No data is permitted in this class (see comment at top) + + // Note: use Db::cursor() to get pointers to a Dbc, + // and call Dbc::close() rather than delete to release them. + // + Dbc(); + ~Dbc(); + + // no copying + Dbc(const Dbc &); + Dbc &operator = (const Dbc &); +}; + +// +// Berkeley DB environment class. Provides functions for opening databases. +// User of this library can use this class as a starting point for +// developing a DB application - derive their application class from +// this one, add application control logic. +// +// Note that if you use the default constructor, you must explicitly +// call appinit() before any other db activity (e.g. opening files) +// +class _exported DbEnv +{ + friend class Db; + friend class DbLock; + friend class DbMpoolFile; + +public: + // After using this constructor, you can set any needed + // parameters for the environment using the set_* methods. + // Then call open() to finish initializing the environment + // and attaching it to underlying files. + // + DbEnv(u_int32_t flags); + + virtual ~DbEnv(); + + // These methods match those in the C interface. + // + virtual int close(u_int32_t); + virtual int dbremove(DbTxn *txn, const char *name, const char *subdb, + u_int32_t flags); + virtual int dbrename(DbTxn *txn, const char *name, const char *subdb, + const char *newname, u_int32_t flags); + virtual void err(int, const char *, ...); + virtual void errx(const char *, ...); + virtual void *get_app_private() const; + virtual int get_home(const char **); + virtual int get_open_flags(u_int32_t *); + virtual int open(const char *, u_int32_t, int); + virtual int remove(const char *, u_int32_t); + virtual int set_alloc(db_malloc_fcn_type, db_realloc_fcn_type, + db_free_fcn_type); + virtual void set_app_private(void *); + virtual int get_cachesize(u_int32_t *, u_int32_t *, int *); + virtual int set_cachesize(u_int32_t, u_int32_t, int); + virtual int get_data_dirs(const char ***); + virtual int set_data_dir(const char *); + virtual int get_encrypt_flags(u_int32_t *); + virtual int set_encrypt(const char *, u_int32_t); + virtual void set_errcall( + void (*)(const DbEnv *, const char *, const char *)); + virtual void get_errfile(FILE **); + virtual void set_errfile(FILE *); + virtual void get_errpfx(const char **); + virtual void set_errpfx(const char *); + virtual int get_flags(u_int32_t *); + virtual int set_flags(u_int32_t, int); + virtual int set_feedback(void (*)(DbEnv *, int, int)); + virtual int get_lg_bsize(u_int32_t *); + virtual int set_lg_bsize(u_int32_t); + virtual int get_lg_dir(const char **); + virtual int set_lg_dir(const char *); + virtual int get_lg_max(u_int32_t *); + virtual int set_lg_max(u_int32_t); + virtual int get_lg_regionmax(u_int32_t *); + virtual int set_lg_regionmax(u_int32_t); + virtual int get_lk_conflicts(const u_int8_t **, int *); + virtual int set_lk_conflicts(u_int8_t *, int); + virtual int get_lk_detect(u_int32_t *); + virtual int set_lk_detect(u_int32_t); + virtual int set_lk_max(u_int32_t); + virtual int get_lk_max_lockers(u_int32_t *); + virtual int set_lk_max_lockers(u_int32_t); + virtual int get_lk_max_locks(u_int32_t *); + virtual int set_lk_max_locks(u_int32_t); + virtual int get_lk_max_objects(u_int32_t *); + virtual int set_lk_max_objects(u_int32_t); + virtual int get_mp_mmapsize(size_t *); + virtual int set_mp_mmapsize(size_t); + virtual void set_msgcall(void (*)(const DbEnv *, const char *)); + virtual void get_msgfile(FILE **); + virtual void set_msgfile(FILE *); + virtual int set_paniccall(void (*)(DbEnv *, int)); + virtual int set_rpc_server(void *, char *, long, long, u_int32_t); + virtual int get_shm_key(long *); + virtual int set_shm_key(long); + virtual int get_timeout(db_timeout_t *, u_int32_t); + virtual int set_timeout(db_timeout_t, u_int32_t); + virtual int get_tmp_dir(const char **); + virtual int set_tmp_dir(const char *); + virtual int get_tas_spins(u_int32_t *); + virtual int set_tas_spins(u_int32_t); + virtual int get_tx_max(u_int32_t *); + virtual int set_tx_max(u_int32_t); + virtual int set_app_dispatch(int (*)(DbEnv *, + Dbt *, DbLsn *, db_recops)); + virtual int get_tx_timestamp(time_t *); + virtual int set_tx_timestamp(time_t *); + virtual int get_verbose(u_int32_t which, int *); + virtual int set_verbose(u_int32_t which, int); + + // Version information. A static method so it can be obtained anytime. + // + static char *version(int *major, int *minor, int *patch); + + // Convert DB errors to strings + static char *strerror(int); + + // If an error is detected and the error call function + // or stream is set, a message is dispatched or printed. + // If a prefix is set, each message is prefixed. + // + // You can use set_errcall() or set_errfile() above to control + // error functionality. Alternatively, you can call + // set_error_stream() to force all errors to a C++ stream. + // It is unwise to mix these approaches. + // + virtual __DB_STD(ostream) *get_error_stream(); + virtual void set_error_stream(__DB_STD(ostream) *); + virtual __DB_STD(ostream) *get_message_stream(); + virtual void set_message_stream(__DB_STD(ostream) *); + + // used internally + static void runtime_error(DbEnv *env, const char *caller, int err, + int error_policy); + static void runtime_error_dbt(DbEnv *env, const char *caller, Dbt *dbt, + int error_policy); + static void runtime_error_lock_get(DbEnv *env, const char *caller, + int err, db_lockop_t op, db_lockmode_t mode, + const Dbt *obj, DbLock lock, int index, + int error_policy); + + // Lock functions + // + virtual int lock_detect(u_int32_t flags, u_int32_t atype, int *aborted); + virtual int lock_get(u_int32_t locker, u_int32_t flags, const Dbt *obj, + db_lockmode_t lock_mode, DbLock *lock); + virtual int lock_id(u_int32_t *idp); + virtual int lock_id_free(u_int32_t id); + virtual int lock_put(DbLock *lock); + virtual int lock_stat(DB_LOCK_STAT **statp, u_int32_t flags); + virtual int lock_stat_print(u_int32_t flags); + virtual int lock_vec(u_int32_t locker, u_int32_t flags, + DB_LOCKREQ list[], int nlist, DB_LOCKREQ **elistp); + + // Log functions + // + virtual int log_archive(char **list[], u_int32_t flags); + static int log_compare(const DbLsn *lsn0, const DbLsn *lsn1); + virtual int log_cursor(DbLogc **cursorp, u_int32_t flags); + virtual int log_file(DbLsn *lsn, char *namep, size_t len); + virtual int log_flush(const DbLsn *lsn); + virtual int log_put(DbLsn *lsn, const Dbt *data, u_int32_t flags); + + virtual int log_stat(DB_LOG_STAT **spp, u_int32_t flags); + virtual int log_stat_print(u_int32_t flags); + + // Mpool functions + // + virtual int memp_fcreate(DbMpoolFile **dbmfp, u_int32_t flags); + virtual int memp_register(int ftype, + pgin_fcn_type pgin_fcn, + pgout_fcn_type pgout_fcn); + virtual int memp_stat(DB_MPOOL_STAT + **gsp, DB_MPOOL_FSTAT ***fsp, u_int32_t flags); + virtual int memp_stat_print(u_int32_t flags); + virtual int memp_sync(DbLsn *lsn); + virtual int memp_trickle(int pct, int *nwrotep); + + // Transaction functions + // + virtual int txn_begin(DbTxn *pid, DbTxn **tid, u_int32_t flags); + virtual int txn_checkpoint(u_int32_t kbyte, u_int32_t min, + u_int32_t flags); + virtual int txn_recover(DbPreplist *preplist, long count, + long *retp, u_int32_t flags); + virtual int txn_stat(DB_TXN_STAT **statp, u_int32_t flags); + virtual int txn_stat_print(u_int32_t flags); + + // Replication functions + // + virtual int rep_elect(int, int, int, u_int32_t, int *, u_int32_t); + virtual int rep_process_message(Dbt *, Dbt *, int *, DbLsn *); + virtual int rep_start(Dbt *, u_int32_t); + virtual int rep_stat(DB_REP_STAT **statp, u_int32_t flags); + virtual int rep_stat_print(u_int32_t flags); + virtual int get_rep_limit(u_int32_t *, u_int32_t *); + virtual int set_rep_limit(u_int32_t, u_int32_t); + virtual int set_rep_transport(int, int (*)(DbEnv *, + const Dbt *, const Dbt *, const DbLsn *, int, u_int32_t)); + + // Conversion functions + // + virtual DB_ENV *get_DB_ENV() + { + return imp_; + } + + virtual const DB_ENV *get_const_DB_ENV() const + { + return imp_; + } + + static DbEnv* get_DbEnv(DB_ENV *dbenv) + { + return dbenv ? (DbEnv *)dbenv->api1_internal : 0; + } + + static const DbEnv* get_const_DbEnv(const DB_ENV *dbenv) + { + return dbenv ? (const DbEnv *)dbenv->api1_internal : 0; + } + + // For internal use only. + static DbEnv* wrap_DB_ENV(DB_ENV *dbenv); + + // These are public only because they need to be called + // via C functions. They should never be called by users + // of this class. + // + static int _app_dispatch_intercept(DB_ENV *env, DBT *dbt, DB_LSN *lsn, + db_recops op); + static void _paniccall_intercept(DB_ENV *env, int errval); + static void _feedback_intercept(DB_ENV *env, int opcode, int pct); + static int _rep_send_intercept(DB_ENV *env, + const DBT *cntrl, const DBT *data, + const DB_LSN *lsn, int id, + u_int32_t flags); + static void _stream_error_function(const DB_ENV *env, + const char *prefix, + const char *message); + static void _stream_message_function(const DB_ENV *env, + const char *message); + +private: + void cleanup(); + int initialize(DB_ENV *env); + int error_policy(); + + // For internal use only. + DbEnv(DB_ENV *, u_int32_t flags); + + // no copying + DbEnv(const DbEnv &); + void operator = (const DbEnv &); + + // instance data + DB_ENV *imp_; + int construct_error_; + u_int32_t construct_flags_; + __DB_STD(ostream) *error_stream_; + __DB_STD(ostream) *message_stream_; + + int (*app_dispatch_callback_)(DbEnv *, Dbt *, DbLsn *, db_recops); + void (*error_callback_)(const DbEnv *, const char *, const char *); + void (*feedback_callback_)(DbEnv *, int, int); + void (*message_callback_)(const DbEnv *, const char *); + void (*paniccall_callback_)(DbEnv *, int); + int (*pgin_callback_)(DbEnv *dbenv, db_pgno_t pgno, + void *pgaddr, Dbt *pgcookie); + int (*pgout_callback_)(DbEnv *dbenv, db_pgno_t pgno, + void *pgaddr, Dbt *pgcookie); + int (*rep_send_callback_)(DbEnv *, + const Dbt *, const Dbt *, const DbLsn *, int, u_int32_t); +}; + +// +// Lock +// +class _exported DbLock +{ + friend class DbEnv; + +public: + DbLock(); + DbLock(const DbLock &); + DbLock &operator = (const DbLock &); + +protected: + // We can add data to this class if needed + // since its contained class is not allocated by db. + // (see comment at top) + + DbLock(DB_LOCK); + DB_LOCK lock_; +}; + +// +// Log cursor +// +class _exported DbLogc : protected DB_LOGC +{ + friend class DbEnv; + +public: + int close(u_int32_t _flags); + int get(DbLsn *lsn, Dbt *data, u_int32_t _flags); + +private: + // No data is permitted in this class (see comment at top) + + // Note: use Db::cursor() to get pointers to a Dbc, + // and call Dbc::close() rather than delete to release them. + // + DbLogc(); + ~DbLogc(); + + // no copying + DbLogc(const Dbc &); + DbLogc &operator = (const Dbc &); +}; + +// +// Log sequence number +// +class _exported DbLsn : public DB_LSN +{ + friend class DbEnv; // friendship needed to cast to base class + friend class DbLogc; // friendship needed to cast to base class +}; + +// +// Memory pool file +// +class _exported DbMpoolFile +{ + friend class DbEnv; + friend class Db; + +public: + int close(u_int32_t flags); + int get(db_pgno_t *pgnoaddr, u_int32_t flags, void *pagep); + int open(const char *file, u_int32_t flags, int mode, size_t pagesize); + int get_transactional(void); + int put(void *pgaddr, u_int32_t flags); + int set(void *pgaddr, u_int32_t flags); + int get_clear_len(u_int32_t *len); + int set_clear_len(u_int32_t len); + int get_fileid(u_int8_t *fileid); + int set_fileid(u_int8_t *fileid); + int get_flags(u_int32_t *flagsp); + int set_flags(u_int32_t flags, int onoff); + int get_ftype(int *ftype); + int set_ftype(int ftype); + int get_lsn_offset(int32_t *offsetp); + int set_lsn_offset(int32_t offset); + int get_maxsize(u_int32_t *gbytes, u_int32_t *bytes); + int set_maxsize(u_int32_t gbytes, u_int32_t bytes); + int get_pgcookie(DBT *dbt); + int set_pgcookie(DBT *dbt); + int get_priority(DB_CACHE_PRIORITY *priorityp); + int set_priority(DB_CACHE_PRIORITY priority); + int sync(); + + virtual DB_MPOOLFILE *get_DB_MPOOLFILE() + { + return imp_; + } + + virtual const DB_MPOOLFILE *get_const_DB_MPOOLFILE() const + { + return imp_; + } + +private: + DB_MPOOLFILE *imp_; + + // We can add data to this class if needed + // since it is implemented via a pointer. + // (see comment at top) + + // Note: use DbEnv::memp_fcreate() to get pointers to a DbMpoolFile, + // and call DbMpoolFile::close() rather than delete to release them. + // + DbMpoolFile(); + + // Shut g++ up. +protected: + virtual ~DbMpoolFile(); + +private: + // no copying + DbMpoolFile(const DbMpoolFile &); + void operator = (const DbMpoolFile &); +}; + +// +// This is filled in and returned by the DbEnv::txn_recover() method. +// +class _exported DbPreplist +{ +public: + DbTxn *txn; + u_int8_t gid[DB_XIDDATASIZE]; +}; + +// +// A sequence record in a database +// +class _exported DbSequence +{ +public: + DbSequence(Db *db, u_int32_t flags); + virtual ~DbSequence(); + + int open(DbTxn *txnid, Dbt *key, u_int32_t flags); + int initial_value(db_seq_t value); + int close(u_int32_t flags); + int remove(DbTxn *txnid, u_int32_t flags); + int stat(DB_SEQUENCE_STAT **sp, u_int32_t flags); + int stat_print(u_int32_t flags); + + int get(DbTxn *txnid, int32_t delta, db_seq_t *retp, u_int32_t flags); + int get_cachesize(int32_t *sizep); + int set_cachesize(int32_t size); + int get_flags(u_int32_t *flagsp); + int set_flags(u_int32_t flags); + int get_range(db_seq_t *minp, db_seq_t *maxp); + int set_range(db_seq_t min, db_seq_t max); + + Db *get_db(); + Dbt *get_key(); + + virtual DB_SEQUENCE *get_DB_SEQUENCE() + { + return imp_; + } + + virtual const DB_SEQUENCE *get_const_DB_SEQUENCE() const + { + return imp_; + } + + static DbSequence* get_DbSequence(DB_SEQUENCE *seq) + { + return (DbSequence *)seq->api_internal; + } + + static const DbSequence* get_const_DbSequence(const DB_SEQUENCE *seq) + { + return (const DbSequence *)seq->api_internal; + } + + // For internal use only. + static DbSequence* wrap_DB_SEQUENCE(DB_SEQUENCE *seq); + +private: + DbSequence(DB_SEQUENCE *seq); + // no copying + DbSequence(const DbSequence &); + DbSequence &operator = (const DbSequence &); + + DB_SEQUENCE *imp_; + DBT key_; +}; + +// +// Transaction +// +class _exported DbTxn +{ + friend class DbEnv; + +public: + int abort(); + int commit(u_int32_t flags); + int discard(u_int32_t flags); + u_int32_t id(); + int prepare(u_int8_t *gid); + int set_timeout(db_timeout_t timeout, u_int32_t flags); + + virtual DB_TXN *get_DB_TXN() + { + return imp_; + } + + virtual const DB_TXN *get_const_DB_TXN() const + { + return imp_; + } + + static DbTxn* get_DbTxn(DB_TXN *txn) + { + return (DbTxn *)txn->api_internal; + } + + static const DbTxn* get_const_DbTxn(const DB_TXN *txn) + { + return (const DbTxn *)txn->api_internal; + } + + // For internal use only. + static DbTxn* wrap_DB_TXN(DB_TXN *txn); + +private: + DB_TXN *imp_; + + // We can add data to this class if needed + // since it is implemented via a pointer. + // (see comment at top) + + // Note: use DbEnv::txn_begin() to get pointers to a DbTxn, + // and call DbTxn::abort() or DbTxn::commit rather than + // delete to release them. + // + DbTxn(); + // For internal use only. + DbTxn(DB_TXN *txn); + virtual ~DbTxn(); + + // no copying + DbTxn(const DbTxn &); + void operator = (const DbTxn &); +}; + +// +// A chunk of data, maybe a key or value. +// +class _exported Dbt : private DBT +{ + friend class Db; + friend class Dbc; + friend class DbEnv; + friend class DbLogc; + friend class DbSequence; + +public: + // key/data + void *get_data() const { return data; } + void set_data(void *value) { data = value; } + + // key/data length + u_int32_t get_size() const { return size; } + void set_size(u_int32_t value) { size = value; } + + // RO: length of user buffer. + u_int32_t get_ulen() const { return ulen; } + void set_ulen(u_int32_t value) { ulen = value; } + + // RO: get/put record length. + u_int32_t get_dlen() const { return dlen; } + void set_dlen(u_int32_t value) { dlen = value; } + + // RO: get/put record offset. + u_int32_t get_doff() const { return doff; } + void set_doff(u_int32_t value) { doff = value; } + + // flags + u_int32_t get_flags() const { return flags; } + void set_flags(u_int32_t value) { flags = value; } + + // Conversion functions + DBT *get_DBT() { return (DBT *)this; } + const DBT *get_const_DBT() const { return (const DBT *)this; } + + static Dbt* get_Dbt(DBT *dbt) { return (Dbt *)dbt; } + static const Dbt* get_const_Dbt(const DBT *dbt) + { return (const Dbt *)dbt; } + + Dbt(void *data, u_int32_t size); + Dbt(); + ~Dbt(); + Dbt(const Dbt &); + Dbt &operator = (const Dbt &); + +private: + // Note: no extra data appears in this class (other than + // inherited from DBT) since we need DBT and Dbt objects + // to have interchangable pointers. + // + // When subclassing this class, remember that callback + // methods like bt_compare, bt_prefix, dup_compare may + // internally manufacture DBT objects (which later are + // cast to Dbt), so such callbacks might receive objects + // not of your subclassed type. +}; + +//////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////// +// +// multiple key/data/reco iterator classes +// + +// DbMultipleIterator is a shared private base class for the three types +// of bulk-return Iterator; it should never be instantiated directly, +// but it handles the functionality shared by its subclasses. +class _exported DbMultipleIterator +{ +public: + DbMultipleIterator(const Dbt &dbt); +protected: + u_int8_t *data_; + u_int32_t *p_; +}; + +class _exported DbMultipleKeyDataIterator : private DbMultipleIterator +{ +public: + DbMultipleKeyDataIterator(const Dbt &dbt) : DbMultipleIterator(dbt) {} + bool next(Dbt &key, Dbt &data); +}; + +class _exported DbMultipleRecnoDataIterator : private DbMultipleIterator +{ +public: + DbMultipleRecnoDataIterator(const Dbt &dbt) : DbMultipleIterator(dbt) {} + bool next(db_recno_t &recno, Dbt &data); +}; + +class _exported DbMultipleDataIterator : private DbMultipleIterator +{ +public: + DbMultipleDataIterator(const Dbt &dbt) : DbMultipleIterator(dbt) {} + bool next(Dbt &data); +}; + +//////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////// +// +// Exception classes +// + +// Almost any error in the DB library throws a DbException. +// Every exception should be considered an abnormality +// (e.g. bug, misuse of DB, file system error). +// +class _exported DbException : public __DB_STD(exception) +{ +public: + virtual ~DbException() throw(); + DbException(int err); + DbException(const char *description); + DbException(const char *description, int err); + DbException(const char *prefix, const char *description, int err); + int get_errno() const; + virtual const char *what() const throw(); + DbEnv *get_env() const; + void set_env(DbEnv *env); + + DbException(const DbException &); + DbException &operator = (const DbException &); + +private: + void describe(const char *prefix, const char *description); + + char *what_; + int err_; // errno + DbEnv *env_; +}; + +// +// A specific sort of exception that occurs when +// an operation is aborted to resolve a deadlock. +// +class _exported DbDeadlockException : public DbException +{ +public: + virtual ~DbDeadlockException() throw(); + DbDeadlockException(const char *description); + + DbDeadlockException(const DbDeadlockException &); + DbDeadlockException &operator = (const DbDeadlockException &); +}; + +// +// A specific sort of exception that occurs when +// a lock is not granted, e.g. by lock_get or lock_vec. +// Note that the Dbt is only live as long as the Dbt used +// in the offending call. +// +class _exported DbLockNotGrantedException : public DbException +{ +public: + virtual ~DbLockNotGrantedException() throw(); + DbLockNotGrantedException(const char *prefix, db_lockop_t op, + db_lockmode_t mode, const Dbt *obj, const DbLock lock, int index); + DbLockNotGrantedException(const char *description); + + DbLockNotGrantedException(const DbLockNotGrantedException &); + DbLockNotGrantedException &operator = + (const DbLockNotGrantedException &); + + db_lockop_t get_op() const; + db_lockmode_t get_mode() const; + const Dbt* get_obj() const; + DbLock *get_lock() const; + int get_index() const; + +private: + db_lockop_t op_; + db_lockmode_t mode_; + const Dbt *obj_; + DbLock *lock_; + int index_; +}; + +// +// A specific sort of exception that occurs when +// user declared memory is insufficient in a Dbt. +// +class _exported DbMemoryException : public DbException +{ +public: + virtual ~DbMemoryException() throw(); + DbMemoryException(Dbt *dbt); + DbMemoryException(const char *prefix, Dbt *dbt); + + DbMemoryException(const DbMemoryException &); + DbMemoryException &operator = (const DbMemoryException &); + + Dbt *get_dbt() const; +private: + Dbt *dbt_; +}; + +// +// A specific sort of exception that occurs when +// recovery is required before continuing DB activity. +// +class _exported DbRunRecoveryException : public DbException +{ +public: + virtual ~DbRunRecoveryException() throw(); + DbRunRecoveryException(const char *description); + + DbRunRecoveryException(const DbRunRecoveryException &); + DbRunRecoveryException &operator = (const DbRunRecoveryException &); +}; +#endif /* !_DB_CXX_H_ */ diff --git a/lib_dict/bdb/include/db_cxx.in b/lib_dict/bdb/include/db_cxx.in new file mode 100644 index 000000000..356145765 --- /dev/null +++ b/lib_dict/bdb/include/db_cxx.in @@ -0,0 +1,1088 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997-2004 + * Sleepycat Software. All rights reserved. + * + * $Id: db_cxx.in,v 11.147 2004/10/07 21:39:48 bostic Exp $ + */ + +#ifndef _DB_CXX_H_ +#define _DB_CXX_H_ +// +// C++ assumptions: +// +// To ensure portability to many platforms, both new and old, we make +// few assumptions about the C++ compiler and library. For example, +// we do not expect STL, templates or namespaces to be available. The +// "newest" C++ feature used is exceptions, which are used liberally +// to transmit error information. Even the use of exceptions can be +// disabled at runtime, to do so, use the DB_CXX_NO_EXCEPTIONS flags +// with the DbEnv or Db constructor. +// +// C++ naming conventions: +// +// - All top level class names start with Db. +// - All class members start with lower case letter. +// - All private data members are suffixed with underscore. +// - Use underscores to divide names into multiple words. +// - Simple data accessors are named with get_ or set_ prefix. +// - All method names are taken from names of functions in the C +// layer of db (usually by dropping a prefix like "db_"). +// These methods have the same argument types and order, +// other than dropping the explicit arg that acts as "this". +// +// As a rule, each DbFoo object has exactly one underlying DB_FOO struct +// (defined in db.h) associated with it. In some cases, we inherit directly +// from the DB_FOO structure to make this relationship explicit. Often, +// the underlying C layer allocates and deallocates these structures, so +// there is no easy way to add any data to the DbFoo class. When you see +// a comment about whether data is permitted to be added, this is what +// is going on. Of course, if we need to add data to such C++ classes +// in the future, we will arrange to have an indirect pointer to the +// DB_FOO struct (as some of the classes already have). +// + +//////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////// +// +// Forward declarations +// + +#include + +@cxx_have_stdheaders@ +#ifdef HAVE_CXX_STDHEADERS +#include +#include +#define __DB_STD(x) std::x +#else +#include +#include +#define __DB_STD(x) x +#endif + +#include "db.h" + +class Db; // forward +class Dbc; // forward +class DbEnv; // forward +class DbInfo; // forward +class DbLock; // forward +class DbLogc; // forward +class DbLsn; // forward +class DbMpoolFile; // forward +class DbPreplist; // forward +class Dbt; // forward +class DbTxn; // forward +class DbLock; // forward +class DbSequence; // forward +class Dbt; // forward + +class DbMultipleIterator; // forward +class DbMultipleKeyDataIterator; // forward +class DbMultipleRecnoDataIterator; // forward +class DbMultipleDataIterator; // forward + +class DbException; // forward +class DbDeadlockException; // forward +class DbLockNotGrantedException; // forward +class DbMemoryException; // forward +class DbRunRecoveryException; // forward + +//////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////// +// +// Turn off inappropriate compiler warnings +// + +#ifdef _MSC_VER + +// These are level 4 warnings that are explicitly disabled. +// With Visual C++, by default you do not see above level 3 unless +// you use /W4. But we like to compile with the highest level +// warnings to catch other errors. +// +// 4201: nameless struct/union +// triggered by standard include file +// +// 4514: unreferenced inline function has been removed +// certain include files in MSVC define methods that are not called +// +#pragma warning(disable: 4201 4514) + +#endif + +//////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////// +// +// Mechanisms for declaring classes +// + +// +// Every class defined in this file has an _exported next to the class name. +// This is needed for WinTel machines so that the class methods can +// be exported or imported in a DLL as appropriate. Users of the DLL +// use the define DB_USE_DLL. When the DLL is built, DB_CREATE_DLL +// must be defined. +// +#if defined(_MSC_VER) + +# if defined(DB_CREATE_DLL) +# define _exported __declspec(dllexport) // creator of dll +# elif defined(DB_USE_DLL) +# define _exported __declspec(dllimport) // user of dll +# else +# define _exported // static lib creator or user +# endif + +#else /* _MSC_VER */ + +# define _exported + +#endif /* _MSC_VER */ + +// Some interfaces can be customized by allowing users to define +// callback functions. For performance and logistical reasons, some +// callback functions must be declared in extern "C" blocks. For others, +// we allow you to declare the callbacks in C++ or C (or an extern "C" +// block) as you wish. See the set methods for the callbacks for +// the choices. +// +extern "C" { + typedef void * (*db_malloc_fcn_type) + (size_t); + typedef void * (*db_realloc_fcn_type) + (void *, size_t); + typedef void (*db_free_fcn_type) + (void *); + typedef int (*bt_compare_fcn_type) /*C++ version available*/ + (DB *, const DBT *, const DBT *); + typedef size_t (*bt_prefix_fcn_type) /*C++ version available*/ + (DB *, const DBT *, const DBT *); + typedef int (*dup_compare_fcn_type) /*C++ version available*/ + (DB *, const DBT *, const DBT *); + typedef u_int32_t (*h_hash_fcn_type) /*C++ version available*/ + (DB *, const void *, u_int32_t); + typedef int (*pgin_fcn_type) + (DB_ENV *dbenv, db_pgno_t pgno, void *pgaddr, DBT *pgcookie); + typedef int (*pgout_fcn_type) + (DB_ENV *dbenv, db_pgno_t pgno, void *pgaddr, DBT *pgcookie); +} + +// +// Represents a database table = a set of keys with associated values. +// +class _exported Db +{ + friend class DbEnv; + +public: + Db(DbEnv*, u_int32_t); // create a Db object, then call open() + virtual ~Db(); // does *not* call close. + + // These methods exactly match those in the C interface. + // + virtual int associate(DbTxn *txn, Db *secondary, + int (*callback)(Db *, const Dbt *, const Dbt *, Dbt *), + u_int32_t flags); + virtual int close(u_int32_t flags); + virtual int cursor(DbTxn *txnid, Dbc **cursorp, u_int32_t flags); + virtual int del(DbTxn *txnid, Dbt *key, u_int32_t flags); + virtual void err(int, const char *, ...); + virtual void errx(const char *, ...); + virtual int fd(int *fdp); + virtual int get(DbTxn *txnid, Dbt *key, Dbt *data, u_int32_t flags); + virtual void *get_app_private() const; + virtual int get_byteswapped(int *); + virtual int get_dbname(const char **, const char **); + virtual int get_open_flags(u_int32_t *); + virtual int get_type(DBTYPE *); + virtual int get_transactional(); + virtual int join(Dbc **curslist, Dbc **dbcp, u_int32_t flags); + virtual int key_range(DbTxn *, Dbt *, DB_KEY_RANGE *, u_int32_t); + virtual int open(DbTxn *txnid, + const char *, const char *subname, DBTYPE, u_int32_t, int); + virtual int pget(DbTxn *txnid, Dbt *key, Dbt *pkey, Dbt *data, + u_int32_t flags); + virtual int put(DbTxn *, Dbt *, Dbt *, u_int32_t); + virtual int remove(const char *, const char *, u_int32_t); + virtual int rename(const char *, const char *, const char *, u_int32_t); + virtual int set_alloc(db_malloc_fcn_type, db_realloc_fcn_type, + db_free_fcn_type); + virtual void set_app_private(void *); + virtual int set_append_recno(int (*)(Db *, Dbt *, db_recno_t)); + virtual int set_bt_compare(bt_compare_fcn_type); /*deprecated*/ + virtual int set_bt_compare(int (*)(Db *, const Dbt *, const Dbt *)); + virtual int set_bt_maxkey(u_int32_t); + virtual int get_bt_minkey(u_int32_t *); + virtual int set_bt_minkey(u_int32_t); + virtual int set_bt_prefix(bt_prefix_fcn_type); /*deprecated*/ + virtual int set_bt_prefix(size_t (*)(Db *, const Dbt *, const Dbt *)); + virtual int get_cachesize(u_int32_t *, u_int32_t *, int *); + virtual int set_cachesize(u_int32_t, u_int32_t, int); + virtual int set_dup_compare(dup_compare_fcn_type); /*deprecated*/ + virtual int set_dup_compare(int (*)(Db *, const Dbt *, const Dbt *)); + virtual int get_encrypt_flags(u_int32_t *); + virtual int set_encrypt(const char *, u_int32_t); + virtual void set_errcall( + void (*)(const DbEnv *, const char *, const char *)); + virtual void get_errfile(FILE **); + virtual void set_errfile(FILE *); + virtual void get_errpfx(const char **); + virtual void set_errpfx(const char *); + virtual int set_feedback(void (*)(Db *, int, int)); + virtual int get_flags(u_int32_t *); + virtual int set_flags(u_int32_t); + virtual int get_h_ffactor(u_int32_t *); + virtual int set_h_ffactor(u_int32_t); + virtual int set_h_hash(h_hash_fcn_type); /*deprecated*/ + virtual int set_h_hash(u_int32_t (*)(Db *, const void *, u_int32_t)); + virtual int get_h_nelem(u_int32_t *); + virtual int set_h_nelem(u_int32_t); + virtual int get_lorder(int *); + virtual int set_lorder(int); + virtual void set_msgcall(void (*)(const DbEnv *, const char *)); + virtual void get_msgfile(FILE **); + virtual void set_msgfile(FILE *); + virtual int get_pagesize(u_int32_t *); + virtual int set_pagesize(u_int32_t); + virtual int set_paniccall(void (*)(DbEnv *, int)); + virtual int get_re_delim(int *); + virtual int set_re_delim(int); + virtual int get_re_len(u_int32_t *); + virtual int set_re_len(u_int32_t); + virtual int get_re_pad(int *); + virtual int set_re_pad(int); + virtual int get_re_source(const char **); + virtual int set_re_source(const char *); + virtual int get_q_extentsize(u_int32_t *); + virtual int set_q_extentsize(u_int32_t); + virtual int stat(DbTxn *, void *sp, u_int32_t flags); + virtual int stat_print(u_int32_t flags); + virtual int sync(u_int32_t flags); + virtual int truncate(DbTxn *, u_int32_t *, u_int32_t); + virtual int upgrade(const char *name, u_int32_t flags); + virtual int verify(const char *, const char *, __DB_STD(ostream) *, + u_int32_t); + + // These additional methods are not in the C interface, and + // are only available for C++. + // + virtual __DB_STD(ostream) *get_error_stream(); + virtual void set_error_stream(__DB_STD(ostream) *); + virtual __DB_STD(ostream) *get_message_stream(); + virtual void set_message_stream(__DB_STD(ostream) *); + + virtual DbEnv *get_env(); + virtual DbMpoolFile *get_mpf(); + + virtual DB *get_DB() + { + return imp_; + } + + virtual const DB *get_const_DB() const + { + return imp_; + } + + static Db* get_Db(DB *db) + { + return (Db *)db->api_internal; + } + + static const Db* get_const_Db(const DB *db) + { + return (const Db *)db->api_internal; + } + +private: + // no copying + Db(const Db &); + Db &operator = (const Db &); + + void cleanup(); + int initialize(); + int error_policy(); + + // instance data + DB *imp_; + DbEnv *env_; + DbMpoolFile *mpf_; + int construct_error_; + u_int32_t flags_; + u_int32_t construct_flags_; + +public: + // These are public only because they need to be called + // via C callback functions. They should never be used by + // external users of this class. + // + int (*append_recno_callback_)(Db *, Dbt *, db_recno_t); + int (*associate_callback_)(Db *, const Dbt *, const Dbt *, Dbt *); + int (*bt_compare_callback_)(Db *, const Dbt *, const Dbt *); + size_t (*bt_prefix_callback_)(Db *, const Dbt *, const Dbt *); + int (*dup_compare_callback_)(Db *, const Dbt *, const Dbt *); + void (*feedback_callback_)(Db *, int, int); + u_int32_t (*h_hash_callback_)(Db *, const void *, u_int32_t); +}; + +// +// Cursor +// +class _exported Dbc : protected DBC +{ + friend class Db; + +public: + int close(); + int count(db_recno_t *countp, u_int32_t flags); + int del(u_int32_t flags); + int dup(Dbc** cursorp, u_int32_t flags); + int get(Dbt* key, Dbt *data, u_int32_t flags); + int pget(Dbt* key, Dbt* pkey, Dbt *data, u_int32_t flags); + int put(Dbt* key, Dbt *data, u_int32_t flags); + +private: + // No data is permitted in this class (see comment at top) + + // Note: use Db::cursor() to get pointers to a Dbc, + // and call Dbc::close() rather than delete to release them. + // + Dbc(); + ~Dbc(); + + // no copying + Dbc(const Dbc &); + Dbc &operator = (const Dbc &); +}; + +// +// Berkeley DB environment class. Provides functions for opening databases. +// User of this library can use this class as a starting point for +// developing a DB application - derive their application class from +// this one, add application control logic. +// +// Note that if you use the default constructor, you must explicitly +// call appinit() before any other db activity (e.g. opening files) +// +class _exported DbEnv +{ + friend class Db; + friend class DbLock; + friend class DbMpoolFile; + +public: + // After using this constructor, you can set any needed + // parameters for the environment using the set_* methods. + // Then call open() to finish initializing the environment + // and attaching it to underlying files. + // + DbEnv(u_int32_t flags); + + virtual ~DbEnv(); + + // These methods match those in the C interface. + // + virtual int close(u_int32_t); + virtual int dbremove(DbTxn *txn, const char *name, const char *subdb, + u_int32_t flags); + virtual int dbrename(DbTxn *txn, const char *name, const char *subdb, + const char *newname, u_int32_t flags); + virtual void err(int, const char *, ...); + virtual void errx(const char *, ...); + virtual void *get_app_private() const; + virtual int get_home(const char **); + virtual int get_open_flags(u_int32_t *); + virtual int open(const char *, u_int32_t, int); + virtual int remove(const char *, u_int32_t); + virtual int set_alloc(db_malloc_fcn_type, db_realloc_fcn_type, + db_free_fcn_type); + virtual void set_app_private(void *); + virtual int get_cachesize(u_int32_t *, u_int32_t *, int *); + virtual int set_cachesize(u_int32_t, u_int32_t, int); + virtual int get_data_dirs(const char ***); + virtual int set_data_dir(const char *); + virtual int get_encrypt_flags(u_int32_t *); + virtual int set_encrypt(const char *, u_int32_t); + virtual void set_errcall( + void (*)(const DbEnv *, const char *, const char *)); + virtual void get_errfile(FILE **); + virtual void set_errfile(FILE *); + virtual void get_errpfx(const char **); + virtual void set_errpfx(const char *); + virtual int get_flags(u_int32_t *); + virtual int set_flags(u_int32_t, int); + virtual int set_feedback(void (*)(DbEnv *, int, int)); + virtual int get_lg_bsize(u_int32_t *); + virtual int set_lg_bsize(u_int32_t); + virtual int get_lg_dir(const char **); + virtual int set_lg_dir(const char *); + virtual int get_lg_max(u_int32_t *); + virtual int set_lg_max(u_int32_t); + virtual int get_lg_regionmax(u_int32_t *); + virtual int set_lg_regionmax(u_int32_t); + virtual int get_lk_conflicts(const u_int8_t **, int *); + virtual int set_lk_conflicts(u_int8_t *, int); + virtual int get_lk_detect(u_int32_t *); + virtual int set_lk_detect(u_int32_t); + virtual int set_lk_max(u_int32_t); + virtual int get_lk_max_lockers(u_int32_t *); + virtual int set_lk_max_lockers(u_int32_t); + virtual int get_lk_max_locks(u_int32_t *); + virtual int set_lk_max_locks(u_int32_t); + virtual int get_lk_max_objects(u_int32_t *); + virtual int set_lk_max_objects(u_int32_t); + virtual int get_mp_mmapsize(size_t *); + virtual int set_mp_mmapsize(size_t); + virtual void set_msgcall(void (*)(const DbEnv *, const char *)); + virtual void get_msgfile(FILE **); + virtual void set_msgfile(FILE *); + virtual int set_paniccall(void (*)(DbEnv *, int)); + virtual int set_rpc_server(void *, char *, long, long, u_int32_t); + virtual int get_shm_key(long *); + virtual int set_shm_key(long); + virtual int get_timeout(db_timeout_t *, u_int32_t); + virtual int set_timeout(db_timeout_t, u_int32_t); + virtual int get_tmp_dir(const char **); + virtual int set_tmp_dir(const char *); + virtual int get_tas_spins(u_int32_t *); + virtual int set_tas_spins(u_int32_t); + virtual int get_tx_max(u_int32_t *); + virtual int set_tx_max(u_int32_t); + virtual int set_app_dispatch(int (*)(DbEnv *, + Dbt *, DbLsn *, db_recops)); + virtual int get_tx_timestamp(time_t *); + virtual int set_tx_timestamp(time_t *); + virtual int get_verbose(u_int32_t which, int *); + virtual int set_verbose(u_int32_t which, int); + + // Version information. A static method so it can be obtained anytime. + // + static char *version(int *major, int *minor, int *patch); + + // Convert DB errors to strings + static char *strerror(int); + + // If an error is detected and the error call function + // or stream is set, a message is dispatched or printed. + // If a prefix is set, each message is prefixed. + // + // You can use set_errcall() or set_errfile() above to control + // error functionality. Alternatively, you can call + // set_error_stream() to force all errors to a C++ stream. + // It is unwise to mix these approaches. + // + virtual __DB_STD(ostream) *get_error_stream(); + virtual void set_error_stream(__DB_STD(ostream) *); + virtual __DB_STD(ostream) *get_message_stream(); + virtual void set_message_stream(__DB_STD(ostream) *); + + // used internally + static void runtime_error(DbEnv *env, const char *caller, int err, + int error_policy); + static void runtime_error_dbt(DbEnv *env, const char *caller, Dbt *dbt, + int error_policy); + static void runtime_error_lock_get(DbEnv *env, const char *caller, + int err, db_lockop_t op, db_lockmode_t mode, + const Dbt *obj, DbLock lock, int index, + int error_policy); + + // Lock functions + // + virtual int lock_detect(u_int32_t flags, u_int32_t atype, int *aborted); + virtual int lock_get(u_int32_t locker, u_int32_t flags, const Dbt *obj, + db_lockmode_t lock_mode, DbLock *lock); + virtual int lock_id(u_int32_t *idp); + virtual int lock_id_free(u_int32_t id); + virtual int lock_put(DbLock *lock); + virtual int lock_stat(DB_LOCK_STAT **statp, u_int32_t flags); + virtual int lock_stat_print(u_int32_t flags); + virtual int lock_vec(u_int32_t locker, u_int32_t flags, + DB_LOCKREQ list[], int nlist, DB_LOCKREQ **elistp); + + // Log functions + // + virtual int log_archive(char **list[], u_int32_t flags); + static int log_compare(const DbLsn *lsn0, const DbLsn *lsn1); + virtual int log_cursor(DbLogc **cursorp, u_int32_t flags); + virtual int log_file(DbLsn *lsn, char *namep, size_t len); + virtual int log_flush(const DbLsn *lsn); + virtual int log_put(DbLsn *lsn, const Dbt *data, u_int32_t flags); + + virtual int log_stat(DB_LOG_STAT **spp, u_int32_t flags); + virtual int log_stat_print(u_int32_t flags); + + // Mpool functions + // + virtual int memp_fcreate(DbMpoolFile **dbmfp, u_int32_t flags); + virtual int memp_register(int ftype, + pgin_fcn_type pgin_fcn, + pgout_fcn_type pgout_fcn); + virtual int memp_stat(DB_MPOOL_STAT + **gsp, DB_MPOOL_FSTAT ***fsp, u_int32_t flags); + virtual int memp_stat_print(u_int32_t flags); + virtual int memp_sync(DbLsn *lsn); + virtual int memp_trickle(int pct, int *nwrotep); + + // Transaction functions + // + virtual int txn_begin(DbTxn *pid, DbTxn **tid, u_int32_t flags); + virtual int txn_checkpoint(u_int32_t kbyte, u_int32_t min, + u_int32_t flags); + virtual int txn_recover(DbPreplist *preplist, long count, + long *retp, u_int32_t flags); + virtual int txn_stat(DB_TXN_STAT **statp, u_int32_t flags); + virtual int txn_stat_print(u_int32_t flags); + + // Replication functions + // + virtual int rep_elect(int, int, int, u_int32_t, int *, u_int32_t); + virtual int rep_process_message(Dbt *, Dbt *, int *, DbLsn *); + virtual int rep_start(Dbt *, u_int32_t); + virtual int rep_stat(DB_REP_STAT **statp, u_int32_t flags); + virtual int rep_stat_print(u_int32_t flags); + virtual int get_rep_limit(u_int32_t *, u_int32_t *); + virtual int set_rep_limit(u_int32_t, u_int32_t); + virtual int set_rep_transport(int, int (*)(DbEnv *, + const Dbt *, const Dbt *, const DbLsn *, int, u_int32_t)); + + // Conversion functions + // + virtual DB_ENV *get_DB_ENV() + { + return imp_; + } + + virtual const DB_ENV *get_const_DB_ENV() const + { + return imp_; + } + + static DbEnv* get_DbEnv(DB_ENV *dbenv) + { + return dbenv ? (DbEnv *)dbenv->api1_internal : 0; + } + + static const DbEnv* get_const_DbEnv(const DB_ENV *dbenv) + { + return dbenv ? (const DbEnv *)dbenv->api1_internal : 0; + } + + // For internal use only. + static DbEnv* wrap_DB_ENV(DB_ENV *dbenv); + + // These are public only because they need to be called + // via C functions. They should never be called by users + // of this class. + // + static int _app_dispatch_intercept(DB_ENV *env, DBT *dbt, DB_LSN *lsn, + db_recops op); + static void _paniccall_intercept(DB_ENV *env, int errval); + static void _feedback_intercept(DB_ENV *env, int opcode, int pct); + static int _rep_send_intercept(DB_ENV *env, + const DBT *cntrl, const DBT *data, + const DB_LSN *lsn, int id, + u_int32_t flags); + static void _stream_error_function(const DB_ENV *env, + const char *prefix, + const char *message); + static void _stream_message_function(const DB_ENV *env, + const char *message); + +private: + void cleanup(); + int initialize(DB_ENV *env); + int error_policy(); + + // For internal use only. + DbEnv(DB_ENV *, u_int32_t flags); + + // no copying + DbEnv(const DbEnv &); + void operator = (const DbEnv &); + + // instance data + DB_ENV *imp_; + int construct_error_; + u_int32_t construct_flags_; + __DB_STD(ostream) *error_stream_; + __DB_STD(ostream) *message_stream_; + + int (*app_dispatch_callback_)(DbEnv *, Dbt *, DbLsn *, db_recops); + void (*error_callback_)(const DbEnv *, const char *, const char *); + void (*feedback_callback_)(DbEnv *, int, int); + void (*message_callback_)(const DbEnv *, const char *); + void (*paniccall_callback_)(DbEnv *, int); + int (*pgin_callback_)(DbEnv *dbenv, db_pgno_t pgno, + void *pgaddr, Dbt *pgcookie); + int (*pgout_callback_)(DbEnv *dbenv, db_pgno_t pgno, + void *pgaddr, Dbt *pgcookie); + int (*rep_send_callback_)(DbEnv *, + const Dbt *, const Dbt *, const DbLsn *, int, u_int32_t); +}; + +// +// Lock +// +class _exported DbLock +{ + friend class DbEnv; + +public: + DbLock(); + DbLock(const DbLock &); + DbLock &operator = (const DbLock &); + +protected: + // We can add data to this class if needed + // since its contained class is not allocated by db. + // (see comment at top) + + DbLock(DB_LOCK); + DB_LOCK lock_; +}; + +// +// Log cursor +// +class _exported DbLogc : protected DB_LOGC +{ + friend class DbEnv; + +public: + int close(u_int32_t _flags); + int get(DbLsn *lsn, Dbt *data, u_int32_t _flags); + +private: + // No data is permitted in this class (see comment at top) + + // Note: use Db::cursor() to get pointers to a Dbc, + // and call Dbc::close() rather than delete to release them. + // + DbLogc(); + ~DbLogc(); + + // no copying + DbLogc(const Dbc &); + DbLogc &operator = (const Dbc &); +}; + +// +// Log sequence number +// +class _exported DbLsn : public DB_LSN +{ + friend class DbEnv; // friendship needed to cast to base class + friend class DbLogc; // friendship needed to cast to base class +}; + +// +// Memory pool file +// +class _exported DbMpoolFile +{ + friend class DbEnv; + friend class Db; + +public: + int close(u_int32_t flags); + int get(db_pgno_t *pgnoaddr, u_int32_t flags, void *pagep); + int open(const char *file, u_int32_t flags, int mode, size_t pagesize); + int get_transactional(void); + int put(void *pgaddr, u_int32_t flags); + int set(void *pgaddr, u_int32_t flags); + int get_clear_len(u_int32_t *len); + int set_clear_len(u_int32_t len); + int get_fileid(u_int8_t *fileid); + int set_fileid(u_int8_t *fileid); + int get_flags(u_int32_t *flagsp); + int set_flags(u_int32_t flags, int onoff); + int get_ftype(int *ftype); + int set_ftype(int ftype); + int get_lsn_offset(int32_t *offsetp); + int set_lsn_offset(int32_t offset); + int get_maxsize(u_int32_t *gbytes, u_int32_t *bytes); + int set_maxsize(u_int32_t gbytes, u_int32_t bytes); + int get_pgcookie(DBT *dbt); + int set_pgcookie(DBT *dbt); + int get_priority(DB_CACHE_PRIORITY *priorityp); + int set_priority(DB_CACHE_PRIORITY priority); + int sync(); + + virtual DB_MPOOLFILE *get_DB_MPOOLFILE() + { + return imp_; + } + + virtual const DB_MPOOLFILE *get_const_DB_MPOOLFILE() const + { + return imp_; + } + +private: + DB_MPOOLFILE *imp_; + + // We can add data to this class if needed + // since it is implemented via a pointer. + // (see comment at top) + + // Note: use DbEnv::memp_fcreate() to get pointers to a DbMpoolFile, + // and call DbMpoolFile::close() rather than delete to release them. + // + DbMpoolFile(); + + // Shut g++ up. +protected: + virtual ~DbMpoolFile(); + +private: + // no copying + DbMpoolFile(const DbMpoolFile &); + void operator = (const DbMpoolFile &); +}; + +// +// This is filled in and returned by the DbEnv::txn_recover() method. +// +class _exported DbPreplist +{ +public: + DbTxn *txn; + u_int8_t gid[DB_XIDDATASIZE]; +}; + +// +// A sequence record in a database +// +class _exported DbSequence +{ +public: + DbSequence(Db *db, u_int32_t flags); + virtual ~DbSequence(); + + int open(DbTxn *txnid, Dbt *key, u_int32_t flags); + int initial_value(db_seq_t value); + int close(u_int32_t flags); + int remove(DbTxn *txnid, u_int32_t flags); + int stat(DB_SEQUENCE_STAT **sp, u_int32_t flags); + int stat_print(u_int32_t flags); + + int get(DbTxn *txnid, int32_t delta, db_seq_t *retp, u_int32_t flags); + int get_cachesize(int32_t *sizep); + int set_cachesize(int32_t size); + int get_flags(u_int32_t *flagsp); + int set_flags(u_int32_t flags); + int get_range(db_seq_t *minp, db_seq_t *maxp); + int set_range(db_seq_t min, db_seq_t max); + + Db *get_db(); + Dbt *get_key(); + + virtual DB_SEQUENCE *get_DB_SEQUENCE() + { + return imp_; + } + + virtual const DB_SEQUENCE *get_const_DB_SEQUENCE() const + { + return imp_; + } + + static DbSequence* get_DbSequence(DB_SEQUENCE *seq) + { + return (DbSequence *)seq->api_internal; + } + + static const DbSequence* get_const_DbSequence(const DB_SEQUENCE *seq) + { + return (const DbSequence *)seq->api_internal; + } + + // For internal use only. + static DbSequence* wrap_DB_SEQUENCE(DB_SEQUENCE *seq); + +private: + DbSequence(DB_SEQUENCE *seq); + // no copying + DbSequence(const DbSequence &); + DbSequence &operator = (const DbSequence &); + + DB_SEQUENCE *imp_; + DBT key_; +}; + +// +// Transaction +// +class _exported DbTxn +{ + friend class DbEnv; + +public: + int abort(); + int commit(u_int32_t flags); + int discard(u_int32_t flags); + u_int32_t id(); + int prepare(u_int8_t *gid); + int set_timeout(db_timeout_t timeout, u_int32_t flags); + + virtual DB_TXN *get_DB_TXN() + { + return imp_; + } + + virtual const DB_TXN *get_const_DB_TXN() const + { + return imp_; + } + + static DbTxn* get_DbTxn(DB_TXN *txn) + { + return (DbTxn *)txn->api_internal; + } + + static const DbTxn* get_const_DbTxn(const DB_TXN *txn) + { + return (const DbTxn *)txn->api_internal; + } + + // For internal use only. + static DbTxn* wrap_DB_TXN(DB_TXN *txn); + +private: + DB_TXN *imp_; + + // We can add data to this class if needed + // since it is implemented via a pointer. + // (see comment at top) + + // Note: use DbEnv::txn_begin() to get pointers to a DbTxn, + // and call DbTxn::abort() or DbTxn::commit rather than + // delete to release them. + // + DbTxn(); + // For internal use only. + DbTxn(DB_TXN *txn); + virtual ~DbTxn(); + + // no copying + DbTxn(const DbTxn &); + void operator = (const DbTxn &); +}; + +// +// A chunk of data, maybe a key or value. +// +class _exported Dbt : private DBT +{ + friend class Db; + friend class Dbc; + friend class DbEnv; + friend class DbLogc; + friend class DbSequence; + +public: + // key/data + void *get_data() const { return data; } + void set_data(void *value) { data = value; } + + // key/data length + u_int32_t get_size() const { return size; } + void set_size(u_int32_t value) { size = value; } + + // RO: length of user buffer. + u_int32_t get_ulen() const { return ulen; } + void set_ulen(u_int32_t value) { ulen = value; } + + // RO: get/put record length. + u_int32_t get_dlen() const { return dlen; } + void set_dlen(u_int32_t value) { dlen = value; } + + // RO: get/put record offset. + u_int32_t get_doff() const { return doff; } + void set_doff(u_int32_t value) { doff = value; } + + // flags + u_int32_t get_flags() const { return flags; } + void set_flags(u_int32_t value) { flags = value; } + + // Conversion functions + DBT *get_DBT() { return (DBT *)this; } + const DBT *get_const_DBT() const { return (const DBT *)this; } + + static Dbt* get_Dbt(DBT *dbt) { return (Dbt *)dbt; } + static const Dbt* get_const_Dbt(const DBT *dbt) + { return (const Dbt *)dbt; } + + Dbt(void *data, u_int32_t size); + Dbt(); + ~Dbt(); + Dbt(const Dbt &); + Dbt &operator = (const Dbt &); + +private: + // Note: no extra data appears in this class (other than + // inherited from DBT) since we need DBT and Dbt objects + // to have interchangable pointers. + // + // When subclassing this class, remember that callback + // methods like bt_compare, bt_prefix, dup_compare may + // internally manufacture DBT objects (which later are + // cast to Dbt), so such callbacks might receive objects + // not of your subclassed type. +}; + +//////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////// +// +// multiple key/data/reco iterator classes +// + +// DbMultipleIterator is a shared private base class for the three types +// of bulk-return Iterator; it should never be instantiated directly, +// but it handles the functionality shared by its subclasses. +class _exported DbMultipleIterator +{ +public: + DbMultipleIterator(const Dbt &dbt); +protected: + u_int8_t *data_; + u_int32_t *p_; +}; + +class _exported DbMultipleKeyDataIterator : private DbMultipleIterator +{ +public: + DbMultipleKeyDataIterator(const Dbt &dbt) : DbMultipleIterator(dbt) {} + bool next(Dbt &key, Dbt &data); +}; + +class _exported DbMultipleRecnoDataIterator : private DbMultipleIterator +{ +public: + DbMultipleRecnoDataIterator(const Dbt &dbt) : DbMultipleIterator(dbt) {} + bool next(db_recno_t &recno, Dbt &data); +}; + +class _exported DbMultipleDataIterator : private DbMultipleIterator +{ +public: + DbMultipleDataIterator(const Dbt &dbt) : DbMultipleIterator(dbt) {} + bool next(Dbt &data); +}; + +//////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////// +// +// Exception classes +// + +// Almost any error in the DB library throws a DbException. +// Every exception should be considered an abnormality +// (e.g. bug, misuse of DB, file system error). +// +class _exported DbException : public __DB_STD(exception) +{ +public: + virtual ~DbException() throw(); + DbException(int err); + DbException(const char *description); + DbException(const char *description, int err); + DbException(const char *prefix, const char *description, int err); + int get_errno() const; + virtual const char *what() const throw(); + DbEnv *get_env() const; + void set_env(DbEnv *env); + + DbException(const DbException &); + DbException &operator = (const DbException &); + +private: + void describe(const char *prefix, const char *description); + + char *what_; + int err_; // errno + DbEnv *env_; +}; + +// +// A specific sort of exception that occurs when +// an operation is aborted to resolve a deadlock. +// +class _exported DbDeadlockException : public DbException +{ +public: + virtual ~DbDeadlockException() throw(); + DbDeadlockException(const char *description); + + DbDeadlockException(const DbDeadlockException &); + DbDeadlockException &operator = (const DbDeadlockException &); +}; + +// +// A specific sort of exception that occurs when +// a lock is not granted, e.g. by lock_get or lock_vec. +// Note that the Dbt is only live as long as the Dbt used +// in the offending call. +// +class _exported DbLockNotGrantedException : public DbException +{ +public: + virtual ~DbLockNotGrantedException() throw(); + DbLockNotGrantedException(const char *prefix, db_lockop_t op, + db_lockmode_t mode, const Dbt *obj, const DbLock lock, int index); + DbLockNotGrantedException(const char *description); + + DbLockNotGrantedException(const DbLockNotGrantedException &); + DbLockNotGrantedException &operator = + (const DbLockNotGrantedException &); + + db_lockop_t get_op() const; + db_lockmode_t get_mode() const; + const Dbt* get_obj() const; + DbLock *get_lock() const; + int get_index() const; + +private: + db_lockop_t op_; + db_lockmode_t mode_; + const Dbt *obj_; + DbLock *lock_; + int index_; +}; + +// +// A specific sort of exception that occurs when +// user declared memory is insufficient in a Dbt. +// +class _exported DbMemoryException : public DbException +{ +public: + virtual ~DbMemoryException() throw(); + DbMemoryException(Dbt *dbt); + DbMemoryException(const char *prefix, Dbt *dbt); + + DbMemoryException(const DbMemoryException &); + DbMemoryException &operator = (const DbMemoryException &); + + Dbt *get_dbt() const; +private: + Dbt *dbt_; +}; + +// +// A specific sort of exception that occurs when +// recovery is required before continuing DB activity. +// +class _exported DbRunRecoveryException : public DbException +{ +public: + virtual ~DbRunRecoveryException() throw(); + DbRunRecoveryException(const char *description); + + DbRunRecoveryException(const DbRunRecoveryException &); + DbRunRecoveryException &operator = (const DbRunRecoveryException &); +}; +#endif /* !_DB_CXX_H_ */ diff --git a/lib_dict/bdb/include/db_dispatch.h b/lib_dict/bdb/include/db_dispatch.h new file mode 100644 index 000000000..bbaff69db --- /dev/null +++ b/lib_dict/bdb/include/db_dispatch.h @@ -0,0 +1,115 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996-2004 + * Sleepycat Software. All rights reserved. + */ +/* + * Copyright (c) 1995, 1996 + * The President and Fellows of Harvard University. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: db_dispatch.h,v 11.38 2004/07/26 19:54:08 margo Exp $ + */ + +#ifndef _DB_DISPATCH_H_ +#define _DB_DISPATCH_H_ + +/* + * Declarations and typedefs for the list of transaction IDs used during + * recovery. This is a generic list used to pass along whatever information + * we need during recovery. + */ +typedef enum { + TXNLIST_DELETE, + TXNLIST_LSN, + TXNLIST_PGNO, + TXNLIST_TXNID +} db_txnlist_type; + +#define DB_TXNLIST_MASK(hp, n) (n % hp->nslots) +struct __db_txnhead { + u_int32_t maxid; /* Maximum transaction id. */ + DB_LSN maxlsn; /* Maximum commit lsn. */ + DB_LSN ckplsn; /* LSN of last retained checkpoint. */ + DB_LSN trunc_lsn; /* Lsn to which we are going to truncate; + * make sure we abort anyone after this. */ + u_int32_t generation; /* Current generation number. */ + u_int32_t gen_alloc; /* Number of generations allocated. */ + struct { + u_int32_t generation; + u_int32_t txn_min; + u_int32_t txn_max; + } *gen_array; /* Array of txnids associated with a gen. */ + u_int nslots; + LIST_HEAD(__db_headlink, __db_txnlist) head[1]; +}; + +struct __db_txnlist { + db_txnlist_type type; + LIST_ENTRY(__db_txnlist) links; + union { + struct { + u_int32_t txnid; + u_int32_t generation; + u_int32_t status; + } t; + struct { + u_int32_t ntxns; + u_int32_t maxn; + DB_LSN *lsn_array; + } l; + struct { + u_int32_t nentries; + u_int32_t maxentry; + int32_t locked; + char *fname; + int32_t fileid; + db_pgno_t *pgno_array; + u_int8_t uid[DB_FILE_ID_LEN]; + } p; + } u; +}; + +/* + * Flag value for __db_txnlist_lsnadd. Distinguish whether we are replacing + * an entry in the transaction list or adding a new one. + */ +#define TXNLIST_NEW 0x1 + +/* + * States for limbo list processing. + */ + +typedef enum { + LIMBO_NORMAL, /* Normal processing. */ + LIMBO_PREPARE, /* We are preparing a transaction. */ + LIMBO_RECOVER, /* We are in recovery. */ + LIMBO_TIMESTAMP, /* We are recovering to a timestamp. */ + LIMBO_COMPENSATE /* After recover to ts, generate log records. */ +} db_limbo_state; + +#endif /* !_DB_DISPATCH_H_ */ diff --git a/lib_dict/bdb/include/db_ext.h b/lib_dict/bdb/include/db_ext.h new file mode 100644 index 000000000..c7124c350 --- /dev/null +++ b/lib_dict/bdb/include/db_ext.h @@ -0,0 +1,255 @@ +/* DO NOT EDIT: automatically built by dist/s_include. */ +#ifndef _db_ext_h_ +#define _db_ext_h_ + +#if defined(__cplusplus) +extern "C" { +#endif + +int __crdel_metasub_log __P((DB *, DB_TXN *, DB_LSN *, u_int32_t, db_pgno_t, const DBT *, DB_LSN *)); +int __crdel_metasub_read __P((DB_ENV *, void *, __crdel_metasub_args **)); +int __crdel_init_recover __P((DB_ENV *, int (***)(DB_ENV *, DBT *, DB_LSN *, db_recops, void *), size_t *)); +int __crdel_metasub_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __crdel_init_print __P((DB_ENV *, int (***)(DB_ENV *, DBT *, DB_LSN *, db_recops, void *), size_t *)); +int __crdel_metasub_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __db_master_open __P((DB *, DB_TXN *, const char *, u_int32_t, int, DB **)); +int __db_master_update __P((DB *, DB *, DB_TXN *, const char *, DBTYPE, mu_action, const char *, u_int32_t)); +int __db_dbenv_setup __P((DB *, DB_TXN *, const char *, u_int32_t, u_int32_t)); +int __db_dbenv_mpool __P((DB *, const char *, u_int32_t)); +int __db_close __P((DB *, DB_TXN *, u_int32_t)); +int __db_refresh __P((DB *, DB_TXN *, u_int32_t, int *)); +int __db_log_page __P((DB *, DB_TXN *, DB_LSN *, db_pgno_t, PAGE *)); +int __db_backup_name __P((DB_ENV *, const char *, DB_TXN *, char **)); +DB *__dblist_get __P((DB_ENV *, u_int32_t)); +#ifdef CONFIG_TEST +int __db_testcopy __P((DB_ENV *, DB *, const char *)); +#endif +int __db_cursor_int __P((DB *, DB_TXN *, DBTYPE, db_pgno_t, int, u_int32_t, DBC **)); +int __db_put __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t)); +int __db_del __P((DB *, DB_TXN *, DBT *, u_int32_t)); +int __db_sync __P((DB *)); +int __db_associate __P((DB *, DB_TXN *, DB *, int (*)(DB *, const DBT *, const DBT *, DBT *), u_int32_t)); +int __db_secondary_close __P((DB *, u_int32_t)); +int __db_addrem_log __P((DB *, DB_TXN *, DB_LSN *, u_int32_t, u_int32_t, db_pgno_t, u_int32_t, u_int32_t, const DBT *, const DBT *, DB_LSN *)); +int __db_addrem_read __P((DB_ENV *, void *, __db_addrem_args **)); +int __db_big_log __P((DB *, DB_TXN *, DB_LSN *, u_int32_t, u_int32_t, db_pgno_t, db_pgno_t, db_pgno_t, const DBT *, DB_LSN *, DB_LSN *, DB_LSN *)); +int __db_big_read __P((DB_ENV *, void *, __db_big_args **)); +int __db_ovref_log __P((DB *, DB_TXN *, DB_LSN *, u_int32_t, db_pgno_t, int32_t, DB_LSN *)); +int __db_ovref_read __P((DB_ENV *, void *, __db_ovref_args **)); +int __db_debug_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t, const DBT *, int32_t, const DBT *, const DBT *, u_int32_t)); +int __db_debug_read __P((DB_ENV *, void *, __db_debug_args **)); +int __db_noop_log __P((DB *, DB_TXN *, DB_LSN *, u_int32_t, db_pgno_t, DB_LSN *)); +int __db_noop_read __P((DB_ENV *, void *, __db_noop_args **)); +int __db_pg_alloc_log __P((DB *, DB_TXN *, DB_LSN *, u_int32_t, DB_LSN *, db_pgno_t, DB_LSN *, db_pgno_t, u_int32_t, db_pgno_t, db_pgno_t)); +int __db_pg_alloc_read __P((DB_ENV *, void *, __db_pg_alloc_args **)); +int __db_pg_free_log __P((DB *, DB_TXN *, DB_LSN *, u_int32_t, db_pgno_t, DB_LSN *, db_pgno_t, const DBT *, db_pgno_t, db_pgno_t)); +int __db_pg_free_read __P((DB_ENV *, void *, __db_pg_free_args **)); +int __db_cksum_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t)); +int __db_cksum_read __P((DB_ENV *, void *, __db_cksum_args **)); +int __db_pg_freedata_log __P((DB *, DB_TXN *, DB_LSN *, u_int32_t, db_pgno_t, DB_LSN *, db_pgno_t, const DBT *, db_pgno_t, db_pgno_t, const DBT *)); +int __db_pg_freedata_read __P((DB_ENV *, void *, __db_pg_freedata_args **)); +int __db_pg_prepare_log __P((DB *, DB_TXN *, DB_LSN *, u_int32_t, db_pgno_t)); +int __db_pg_prepare_read __P((DB_ENV *, void *, __db_pg_prepare_args **)); +int __db_pg_new_log __P((DB *, DB_TXN *, DB_LSN *, u_int32_t, db_pgno_t, DB_LSN *, db_pgno_t, const DBT *, db_pgno_t)); +int __db_pg_new_read __P((DB_ENV *, void *, __db_pg_new_args **)); +int __db_pg_init_log __P((DB *, DB_TXN *, DB_LSN *, u_int32_t, db_pgno_t, const DBT *, const DBT *)); +int __db_pg_init_read __P((DB_ENV *, void *, __db_pg_init_args **)); +int __db_init_recover __P((DB_ENV *, int (***)(DB_ENV *, DBT *, DB_LSN *, db_recops, void *), size_t *)); +int __db_addrem_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __db_big_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __db_ovref_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __db_debug_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __db_noop_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __db_pg_alloc_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __db_pg_free_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __db_cksum_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __db_pg_freedata_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __db_pg_prepare_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __db_pg_new_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __db_pg_init_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __db_init_print __P((DB_ENV *, int (***)(DB_ENV *, DBT *, DB_LSN *, db_recops, void *), size_t *)); +int __db_c_close __P((DBC *)); +int __db_c_destroy __P((DBC *)); +int __db_c_count __P((DBC *, db_recno_t *)); +int __db_c_del __P((DBC *, u_int32_t)); +int __db_c_dup __P((DBC *, DBC **, u_int32_t)); +int __db_c_idup __P((DBC *, DBC **, u_int32_t)); +int __db_c_newopd __P((DBC *, db_pgno_t, DBC *, DBC **)); +int __db_c_get __P((DBC *, DBT *, DBT *, u_int32_t)); +int __db_c_put __P((DBC *, DBT *, DBT *, u_int32_t)); +int __db_duperr __P((DB *, u_int32_t)); +int __db_c_secondary_get_pp __P((DBC *, DBT *, DBT *, u_int32_t)); +int __db_c_pget __P((DBC *, DBT *, DBT *, DBT *, u_int32_t)); +int __db_c_del_primary __P((DBC *)); +DB *__db_s_first __P((DB *)); +int __db_s_next __P((DB **)); +int __db_s_done __P((DB *)); +u_int32_t __db_partsize __P((u_int32_t, DBT *)); +int __db_pgin __P((DB_ENV *, db_pgno_t, void *, DBT *)); +int __db_pgout __P((DB_ENV *, db_pgno_t, void *, DBT *)); +void __db_metaswap __P((PAGE *)); +int __db_byteswap __P((DB_ENV *, DB *, db_pgno_t, PAGE *, size_t, int)); +int __db_dispatch __P((DB_ENV *, int (**)__P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)), size_t, DBT *, DB_LSN *, db_recops, void *)); +int __db_add_recovery __P((DB_ENV *, int (***)(DB_ENV *, DBT *, DB_LSN *, db_recops, void *), size_t *, int (*)(DB_ENV *, DBT *, DB_LSN *, db_recops, void *), u_int32_t)); +int __db_txnlist_init __P((DB_ENV *, u_int32_t, u_int32_t, DB_LSN *, void *)); +int __db_txnlist_add __P((DB_ENV *, void *, u_int32_t, u_int32_t, DB_LSN *)); +int __db_txnlist_remove __P((DB_ENV *, void *, u_int32_t)); +void __db_txnlist_ckp __P((DB_ENV *, void *, DB_LSN *)); +void __db_txnlist_end __P((DB_ENV *, void *)); +int __db_txnlist_find __P((DB_ENV *, void *, u_int32_t, u_int32_t *)); +int __db_txnlist_update __P((DB_ENV *, void *, u_int32_t, u_int32_t, DB_LSN *, u_int32_t *, int)); +int __db_txnlist_gen __P((DB_ENV *, void *, int, u_int32_t, u_int32_t)); +int __db_txnlist_lsnadd __P((DB_ENV *, void *, DB_LSN *, u_int32_t)); +int __db_txnlist_lsninit __P((DB_ENV *, DB_TXNHEAD *, DB_LSN *)); +#ifndef HAVE_FTRUNCATE +int __db_add_limbo __P((DB_ENV *, void *, int32_t, db_pgno_t, int32_t)); +#endif +#ifndef HAVE_FTRUNCATE +int __db_do_the_limbo __P((DB_ENV *, DB_TXN *, DB_TXN *, DB_TXNHEAD *, db_limbo_state)); +#endif +void __db_txnlist_print __P((void *)); +int __db_ditem __P((DBC *, PAGE *, u_int32_t, u_int32_t)); +int __db_pitem __P((DBC *, PAGE *, u_int32_t, u_int32_t, DBT *, DBT *)); +int __db_associate_pp __P((DB *, DB_TXN *, DB *, int (*)(DB *, const DBT *, const DBT *, DBT *), u_int32_t)); +int __db_close_pp __P((DB *, u_int32_t)); +int __db_cursor_pp __P((DB *, DB_TXN *, DBC **, u_int32_t)); +int __db_cursor __P((DB *, DB_TXN *, DBC **, u_int32_t)); +int __db_del_pp __P((DB *, DB_TXN *, DBT *, u_int32_t)); +int __db_fd_pp __P((DB *, int *)); +int __db_get_pp __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t)); +int __db_get __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t)); +int __db_join_pp __P((DB *, DBC **, DBC **, u_int32_t)); +int __db_key_range_pp __P((DB *, DB_TXN *, DBT *, DB_KEY_RANGE *, u_int32_t)); +int __db_open_pp __P((DB *, DB_TXN *, const char *, const char *, DBTYPE, u_int32_t, int)); +int __db_pget_pp __P((DB *, DB_TXN *, DBT *, DBT *, DBT *, u_int32_t)); +int __db_pget __P((DB *, DB_TXN *, DBT *, DBT *, DBT *, u_int32_t)); +int __db_put_pp __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t)); +int __db_sync_pp __P((DB *, u_int32_t)); +int __db_c_close_pp __P((DBC *)); +int __db_c_count_pp __P((DBC *, db_recno_t *, u_int32_t)); +int __db_c_del_pp __P((DBC *, u_int32_t)); +int __db_c_del_arg __P((DBC *, u_int32_t)); +int __db_c_dup_pp __P((DBC *, DBC **, u_int32_t)); +int __db_c_get_pp __P((DBC *, DBT *, DBT *, u_int32_t)); +int __db_secondary_close_pp __P((DB *, u_int32_t)); +int __db_c_pget_pp __P((DBC *, DBT *, DBT *, DBT *, u_int32_t)); +int __db_c_put_pp __P((DBC *, DBT *, DBT *, u_int32_t)); +int __db_txn_auto_init __P((DB_ENV *, DB_TXN **)); +int __db_txn_auto_resolve __P((DB_ENV *, DB_TXN *, int, int)); +int __db_join __P((DB *, DBC **, DBC **, u_int32_t)); +int __db_join_close __P((DBC *)); +int __db_secondary_corrupt __P((DB *)); +int __db_new __P((DBC *, u_int32_t, PAGE **)); +int __db_free __P((DBC *, PAGE *)); +int __db_lprint __P((DBC *)); +int __db_lget __P((DBC *, int, db_pgno_t, db_lockmode_t, u_int32_t, DB_LOCK *)); +int __db_lput __P((DBC *, DB_LOCK *)); +int __dbh_am_chk __P((DB *, u_int32_t)); +int __db_get_flags __P((DB *, u_int32_t *)); +int __db_set_flags __P((DB *, u_int32_t)); +int __db_get_lorder __P((DB *, int *)); +int __db_set_lorder __P((DB *, int)); +int __db_set_pagesize __P((DB *, u_int32_t)); +int __db_open __P((DB *, DB_TXN *, const char *, const char *, DBTYPE, u_int32_t, int, db_pgno_t)); +int __db_get_open_flags __P((DB *, u_int32_t *)); +int __db_new_file __P((DB *, DB_TXN *, DB_FH *, const char *)); +int __db_init_subdb __P((DB *, DB *, const char *, DB_TXN *)); +int __db_chk_meta __P((DB_ENV *, DB *, DBMETA *, int)); +int __db_meta_setup __P((DB_ENV *, DB *, const char *, DBMETA *, u_int32_t, int)); +int __db_goff __P((DB *, DBT *, u_int32_t, db_pgno_t, void **, u_int32_t *)); +int __db_poff __P((DBC *, const DBT *, db_pgno_t *)); +int __db_ovref __P((DBC *, db_pgno_t, int32_t)); +int __db_doff __P((DBC *, db_pgno_t)); +int __db_moff __P((DB *, const DBT *, db_pgno_t, u_int32_t, int (*)(DB *, const DBT *, const DBT *), int *)); +int __db_vrfy_overflow __P((DB *, VRFY_DBINFO *, PAGE *, db_pgno_t, u_int32_t)); +int __db_vrfy_ovfl_structure __P((DB *, VRFY_DBINFO *, db_pgno_t, u_int32_t, u_int32_t)); +int __db_safe_goff __P((DB *, VRFY_DBINFO *, db_pgno_t, DBT *, void *, u_int32_t)); +void __db_loadme __P((void)); +int __db_dumptree __P((DB *, char *, char *)); +const FN * __db_get_flags_fn __P((void)); +int __db_prnpage __P((DB *, db_pgno_t)); +int __db_prpage __P((DB *, PAGE *, u_int32_t)); +void __db_pr __P((DB_ENV *, DB_MSGBUF *, u_int8_t *, u_int32_t)); +void __db_prflags __P((DB_ENV *, DB_MSGBUF *, u_int32_t, const FN *, const char *, const char *)); +const char * __db_lockmode_to_string __P((db_lockmode_t)); +int __db_dumptree __P((DB *, char *, char *)); +const FN * __db_get_flags_fn __P((void)); +int __db_dump_pp __P((DB *, const char *, int (*)(void *, const void *), void *, int, int)); +int __db_dump __P((DB *, const char *, int (*)(void *, const void *), void *, int, int)); +int __db_prdbt __P((DBT *, int, const char *, void *, int (*)(void *, const void *), int)); +int __db_prheader __P((DB *, const char *, int, int, void *, int (*)(void *, const void *), VRFY_DBINFO *, db_pgno_t)); +int __db_prfooter __P((void *, int (*)(void *, const void *))); +int __db_pr_callback __P((void *, const void *)); +const char * __db_dbtype_to_string __P((DBTYPE)); +int __db_addrem_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __db_big_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __db_ovref_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __db_debug_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __db_noop_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __db_pg_alloc_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __db_pg_free_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __db_pg_new_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __db_pg_freedata_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __db_cksum_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __db_pg_prepare_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __db_pg_init_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __db_traverse_big __P((DB *, db_pgno_t, int (*)(DB *, PAGE *, void *, int *), void *)); +int __db_reclaim_callback __P((DB *, PAGE *, void *, int *)); +int __db_truncate_callback __P((DB *, PAGE *, void *, int *)); +int __dbenv_dbremove_pp __P((DB_ENV *, DB_TXN *, const char *, const char *, u_int32_t)); +int __db_remove_pp __P((DB *, const char *, const char *, u_int32_t)); +int __db_remove __P((DB *, DB_TXN *, const char *, const char *, u_int32_t)); +int __db_remove_int __P((DB *, DB_TXN *, const char *, const char *, u_int32_t)); +int __dbenv_dbrename_pp __P((DB_ENV *, DB_TXN *, const char *, const char *, const char *, u_int32_t)); +int __db_rename_pp __P((DB *, const char *, const char *, const char *, u_int32_t)); +int __db_rename __P((DB *, DB_TXN *, const char *, const char *, const char *)); +int __db_rename_int __P((DB *, DB_TXN *, const char *, const char *, const char *)); +int __db_ret __P((DB *, PAGE *, u_int32_t, DBT *, void **, u_int32_t *)); +int __db_retcopy __P((DB_ENV *, DBT *, void *, u_int32_t, void **, u_int32_t *)); +int __db_fileid_reset __P((DB_ENV *, char *, int)); +int __db_lsn_reset __P((DB_ENV *, char *, int)); +int __db_stat_pp __P((DB *, DB_TXN *, void *, u_int32_t)); +int __db_stat __P((DB *, DB_TXN *, void *, u_int32_t)); +int __db_stat_print_pp __P((DB *, u_int32_t)); +int __db_stat_print __P((DB *, u_int32_t)); +int __db_truncate_pp __P((DB *, DB_TXN *, u_int32_t *, u_int32_t)); +int __db_truncate __P((DB *, DB_TXN *, u_int32_t *)); +int __db_upgrade_pp __P((DB *, const char *, u_int32_t)); +int __db_upgrade __P((DB *, const char *, u_int32_t)); +int __db_lastpgno __P((DB *, char *, DB_FH *, db_pgno_t *)); +int __db_31_offdup __P((DB *, char *, DB_FH *, int, db_pgno_t *)); +int __db_verify_pp __P((DB *, const char *, const char *, FILE *, u_int32_t)); +int __db_verify_internal __P((DB *, const char *, const char *, void *, int (*)(void *, const void *), u_int32_t)); +int __db_vrfy_common __P((DB *, VRFY_DBINFO *, PAGE *, db_pgno_t, u_int32_t)); +int __db_vrfy_datapage __P((DB *, VRFY_DBINFO *, PAGE *, db_pgno_t, u_int32_t)); +int __db_vrfy_meta __P((DB *, VRFY_DBINFO *, DBMETA *, db_pgno_t, u_int32_t)); +void __db_vrfy_struct_feedback __P((DB *, VRFY_DBINFO *)); +int __db_salvage __P((DB *, VRFY_DBINFO *, db_pgno_t, PAGE *, void *, int (*)(void *, const void *), u_int32_t)); +int __db_vrfy_inpitem __P((DB *, PAGE *, db_pgno_t, u_int32_t, int, u_int32_t, u_int32_t *, u_int32_t *)); +int __db_vrfy_duptype __P((DB *, VRFY_DBINFO *, db_pgno_t, u_int32_t)); +int __db_salvage_duptree __P((DB *, VRFY_DBINFO *, db_pgno_t, DBT *, void *, int (*)(void *, const void *), u_int32_t)); +int __db_vrfy_dbinfo_create __P((DB_ENV *, u_int32_t, VRFY_DBINFO **)); +int __db_vrfy_dbinfo_destroy __P((DB_ENV *, VRFY_DBINFO *)); +int __db_vrfy_getpageinfo __P((VRFY_DBINFO *, db_pgno_t, VRFY_PAGEINFO **)); +int __db_vrfy_putpageinfo __P((DB_ENV *, VRFY_DBINFO *, VRFY_PAGEINFO *)); +int __db_vrfy_pgset __P((DB_ENV *, u_int32_t, DB **)); +int __db_vrfy_pgset_get __P((DB *, db_pgno_t, int *)); +int __db_vrfy_pgset_inc __P((DB *, db_pgno_t)); +int __db_vrfy_pgset_next __P((DBC *, db_pgno_t *)); +int __db_vrfy_childcursor __P((VRFY_DBINFO *, DBC **)); +int __db_vrfy_childput __P((VRFY_DBINFO *, db_pgno_t, VRFY_CHILDINFO *)); +int __db_vrfy_ccset __P((DBC *, db_pgno_t, VRFY_CHILDINFO **)); +int __db_vrfy_ccnext __P((DBC *, VRFY_CHILDINFO **)); +int __db_vrfy_ccclose __P((DBC *)); +int __db_salvage_init __P((VRFY_DBINFO *)); +void __db_salvage_destroy __P((VRFY_DBINFO *)); +int __db_salvage_getnext __P((VRFY_DBINFO *, db_pgno_t *, u_int32_t *)); +int __db_salvage_isdone __P((VRFY_DBINFO *, db_pgno_t)); +int __db_salvage_markdone __P((VRFY_DBINFO *, db_pgno_t)); +int __db_salvage_markneeded __P((VRFY_DBINFO *, db_pgno_t, u_int32_t)); +int __db_vrfy_prdbt __P((DBT *, int, const char *, void *, int (*)(void *, const void *), int, VRFY_DBINFO *)); + +#if defined(__cplusplus) +} +#endif +#endif /* !_db_ext_h_ */ diff --git a/lib_dict/bdb/include/db_int.h b/lib_dict/bdb/include/db_int.h new file mode 100644 index 000000000..046e3de5a --- /dev/null +++ b/lib_dict/bdb/include/db_int.h @@ -0,0 +1,592 @@ +/* DO NOT EDIT: automatically built by dist/s_win32. */ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996-2004 + * Sleepycat Software. All rights reserved. + * + * $Id: db_int.in,v 11.155 2004/10/28 16:07:38 ubell Exp $ + */ + +#ifndef _DB_INTERNAL_H_ +#define _DB_INTERNAL_H_ + +/******************************************************* + * System includes, db.h, a few general DB includes. The DB includes are + * here because it's OK if db_int.h includes queue structure declarations. + *******************************************************/ +#ifndef NO_SYSTEM_INCLUDES +#if defined(STDC_HEADERS) || defined(__cplusplus) +#include +#else +#include +#endif +#include +#endif + +#include "db.h" + +#include "dbinc/queue.h" +#include "dbinc/shqueue.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +/******************************************************* + * General purpose constants and macros. + *******************************************************/ +#ifndef UINT16_MAX +#define UINT16_MAX 65535 /* Maximum 16-bit unsigned. */ +#endif +#ifndef UINT32_MAX +#ifdef __STDC__ +#define UINT32_MAX 4294967295U /* Maximum 32-bit unsigned. */ +#else +#define UINT32_MAX 0xffffffff /* Maximum 32-bit unsigned. */ +#endif +#endif + +#if defined(HAVE_LONG_LONG) && defined(HAVE_UNSIGNED_LONG_LONG) +#undef INT64_MAX +#undef INT64_MIN +#undef UINT64_MAX + +#ifdef DB_WIN32 +#define INT64_MAX _I64_MAX +#define INT64_MIN _I64_MIN +#define UINT64_MAX _UI64_MAX + +#define INT64_FMT "%l64d" +#define UINT64_FMT "%l64u" +#else +/* + * Override the system's 64-bit min/max constants. AIX's 32-bit compiler can + * handle 64-bit values, but the system's constants don't include the LL/ULL + * suffix, and so can't be compiled using the 32-bit compiler. + */ +#define INT64_MAX 9223372036854775807LL +#define INT64_MIN (-INT64_MAX-1) +#define UINT64_MAX 18446744073709551615ULL + +#define INT64_FMT "%lld" +#define UINT64_FMT "%llu" +#endif /* DB_WIN32 */ +#endif /* HAVE_LONG_LONG && HAVE_UNSIGNED_LONG_LONG */ + +#define MEGABYTE 1048576 +#define GIGABYTE 1073741824 + +#define MS_PER_SEC 1000 /* Milliseconds in a second. */ +#define USEC_PER_MS 1000 /* Microseconds in a millisecond. */ + +#define RECNO_OOB 0 /* Illegal record number. */ + +/* Test for a power-of-two (tests true for zero, which doesn't matter here). */ +#define POWER_OF_TWO(x) (((x) & ((x) - 1)) == 0) + +/* Test for valid page sizes. */ +#define DB_MIN_PGSIZE 0x000200 /* Minimum page size (512). */ +#define DB_MAX_PGSIZE 0x010000 /* Maximum page size (65536). */ +#define IS_VALID_PAGESIZE(x) \ + (POWER_OF_TWO(x) && (x) >= DB_MIN_PGSIZE && ((x) <= DB_MAX_PGSIZE)) + +/* Minimum number of pages cached, by default. */ +#define DB_MINPAGECACHE 16 + +/* + * If we are unable to determine the underlying filesystem block size, use + * 8K on the grounds that most OS's use less than 8K for a VM page size. + */ +#define DB_DEF_IOSIZE (8 * 1024) + +/* Align an integer to a specific boundary. */ +#undef DB_ALIGN +#define DB_ALIGN(v, bound) \ + (((v) + (bound) - 1) & ~(((uintmax_t)bound) - 1)) + +/* Increment a pointer to a specific boundary. */ +#undef ALIGNP_INC +#define ALIGNP_INC(p, bound) \ + (void *)(((uintptr_t)(p) + (bound) - 1) & ~(((uintptr_t)bound) - 1)) + +/* Decrement a pointer to a specific boundary. */ +#undef ALIGNP_DEC +#define ALIGNP_DEC(p, bound) \ + (void *)((uintptr_t)(p) & ~(((uintptr_t)bound) - 1)) + +/* + * Print an address as a u_long (a u_long is the largest type we can print + * portably). Most 64-bit systems have made longs 64-bits, so this should + * work. + */ +#define P_TO_ULONG(p) ((u_long)(uintptr_t)(p)) + +/* + * Convert a pointer to a small integral value. + * + * The (u_int16_t)(uintptr_t) cast avoids warnings: the (uintptr_t) cast + * converts the value to an integral type, and the (u_int16_t) cast converts + * it to a small integral type so we don't get complaints when we assign the + * final result to an integral type smaller than uintptr_t. + */ +#define P_TO_UINT32(p) ((u_int32_t)(uintptr_t)(p)) +#define P_TO_UINT16(p) ((u_int16_t)(uintptr_t)(p)) + +/* + * There are several on-page structures that are declared to have a number of + * fields followed by a variable length array of items. The structure size + * without including the variable length array or the address of the first of + * those elements can be found using SSZ. + * + * This macro can also be used to find the offset of a structure element in a + * structure. This is used in various places to copy structure elements from + * unaligned memory references, e.g., pointers into a packed page. + * + * There are two versions because compilers object if you take the address of + * an array. + */ +#undef SSZ +#define SSZ(name, field) P_TO_UINT16(&(((name *)0)->field)) + +#undef SSZA +#define SSZA(name, field) P_TO_UINT16(&(((name *)0)->field[0])) + +/* Structure used to print flag values. */ +typedef struct __fn { + u_int32_t mask; /* Flag value. */ + const char *name; /* Flag name. */ +} FN; + +/* Set, clear and test flags. */ +#define FLD_CLR(fld, f) (fld) &= ~(f) +#define FLD_ISSET(fld, f) ((fld) & (f)) +#define FLD_SET(fld, f) (fld) |= (f) +#define F_CLR(p, f) (p)->flags &= ~(f) +#define F_ISSET(p, f) ((p)->flags & (f)) +#define F_SET(p, f) (p)->flags |= (f) +#define LF_CLR(f) ((flags) &= ~(f)) +#define LF_ISSET(f) ((flags) & (f)) +#define LF_SET(f) ((flags) |= (f)) + +/* + * Calculate a percentage. The values can overflow 32-bit integer arithmetic + * so we use floating point. + * + * When calculating a bytes-vs-page size percentage, we're getting the inverse + * of the percentage in all cases, that is, we want 100 minus the percentage we + * calculate. + */ +#define DB_PCT(v, total) \ + ((int)((total) == 0 ? 0 : ((double)(v) * 100) / (total))) +#define DB_PCT_PG(v, total, pgsize) \ + ((int)((total) == 0 ? 0 : \ + 100 - ((double)(v) * 100) / ((total) * (pgsize)))) + +/* + * Structure used for callback message aggregation. + * + * Display values in XXX_stat_print calls. + */ +typedef struct __db_msgbuf { + char *buf; /* Heap allocated buffer. */ + char *cur; /* Current end of message. */ + size_t len; /* Allocated length of buffer. */ +} DB_MSGBUF; +#define DB_MSGBUF_INIT(a) do { \ + (a)->buf = (a)->cur = NULL; \ + (a)->len = 0; \ +} while (0) +#define DB_MSGBUF_FLUSH(dbenv, a) do { \ + if ((a)->buf != NULL) { \ + if ((a)->cur != (a)->buf) \ + __db_msg(dbenv, "%s", (a)->buf); \ + __os_free(dbenv, (a)->buf); \ + DB_MSGBUF_INIT(a); \ + } \ +} while (0) +#define STAT_FMT(msg, fmt, type, v) do { \ + DB_MSGBUF __mb; \ + DB_MSGBUF_INIT(&__mb); \ + __db_msgadd(dbenv, &__mb, fmt, (type)(v)); \ + __db_msgadd(dbenv, &__mb, "\t%s", msg); \ + DB_MSGBUF_FLUSH(dbenv, &__mb); \ +} while (0) +#define STAT_HEX(msg, v) \ + __db_msg(dbenv, "%#lx\t%s", (u_long)(v), msg) +#define STAT_ISSET(msg, p) \ + __db_msg(dbenv, "%sSet\t%s", (p) == NULL ? "!" : " ", msg) +#define STAT_LONG(msg, v) \ + __db_msg(dbenv, "%ld\t%s", (long)(v), msg) +#define STAT_LSN(msg, lsnp) \ + __db_msg(dbenv, "%lu/%lu\t%s", \ + (u_long)(lsnp)->file, (u_long)(lsnp)->offset, msg) +#define STAT_STRING(msg, p) do { \ + const char *__p = p; /* p may be a function call. */ \ + __db_msg(dbenv, "%s\t%s", __p == NULL ? "!Set" : __p, msg); \ +} while (0) +#define STAT_ULONG(msg, v) \ + __db_msg(dbenv, "%lu\t%s", (u_long)(v), msg) + +/******************************************************* + * API return values + *******************************************************/ +/* + * Return values that are OK for each different call. Most calls have a + * standard 'return of 0 is only OK value', but some, like db->get have + * DB_NOTFOUND as a return value, but it really isn't an error. + */ +#define DB_RETOK_STD(ret) ((ret) == 0) +#define DB_RETOK_DBCDEL(ret) ((ret) == 0 || (ret) == DB_KEYEMPTY || \ + (ret) == DB_NOTFOUND) +#define DB_RETOK_DBCGET(ret) ((ret) == 0 || (ret) == DB_KEYEMPTY || \ + (ret) == DB_NOTFOUND) +#define DB_RETOK_DBCPUT(ret) ((ret) == 0 || (ret) == DB_KEYEXIST || \ + (ret) == DB_NOTFOUND) +#define DB_RETOK_DBDEL(ret) DB_RETOK_DBCDEL(ret) +#define DB_RETOK_DBGET(ret) DB_RETOK_DBCGET(ret) +#define DB_RETOK_DBPUT(ret) ((ret) == 0 || (ret) == DB_KEYEXIST) +#define DB_RETOK_LGGET(ret) ((ret) == 0 || (ret) == DB_NOTFOUND) +#define DB_RETOK_MPGET(ret) ((ret) == 0 || (ret) == DB_PAGE_NOTFOUND) +#define DB_RETOK_REPPMSG(ret) ((ret) == 0 || \ + (ret) == DB_REP_ISPERM || \ + (ret) == DB_REP_NEWMASTER || \ + (ret) == DB_REP_NEWSITE || \ + (ret) == DB_REP_NOTPERM || \ + (ret) == DB_REP_STARTUPDONE) + +/* Find a reasonable operation-not-supported error. */ +#ifdef EOPNOTSUPP +#define DB_OPNOTSUP EOPNOTSUPP +#else +#ifdef ENOTSUP +#define DB_OPNOTSUP ENOTSUP +#else +#define DB_OPNOTSUP EINVAL +#endif +#endif + +/******************************************************* + * Files. + *******************************************************/ +/* + * We use 1024 as the maximum path length. It's too hard to figure out what + * the real path length is, as it was traditionally stored in , + * and that file isn't always available. + */ +#undef MAXPATHLEN +#define MAXPATHLEN 1024 + +#define PATH_DOT "." /* Current working directory. */ + /* Path separator character(s). */ +#define PATH_SEPARATOR "\\/:" + +/******************************************************* + * Environment. + *******************************************************/ +/* Type passed to __db_appname(). */ +typedef enum { + DB_APP_NONE=0, /* No type (region). */ + DB_APP_DATA, /* Data file. */ + DB_APP_LOG, /* Log file. */ + DB_APP_TMP /* Temporary file. */ +} APPNAME; + +/* + * CDB_LOCKING CDB product locking. + * CRYPTO_ON Security has been configured. + * LOCKING_ON Locking has been configured. + * LOGGING_ON Logging has been configured. + * MPOOL_ON Memory pool has been configured. + * REP_ON Replication has been configured. + * RPC_ON RPC has been configured. + * TXN_ON Transactions have been configured. + */ +#define CDB_LOCKING(dbenv) F_ISSET(dbenv, DB_ENV_CDB) +#define CRYPTO_ON(dbenv) ((dbenv)->crypto_handle != NULL) +#define LOCKING_ON(dbenv) ((dbenv)->lk_handle != NULL) +#define LOGGING_ON(dbenv) ((dbenv)->lg_handle != NULL) +#define MPOOL_ON(dbenv) ((dbenv)->mp_handle != NULL) +#define REP_ON(dbenv) ((dbenv)->rep_handle != NULL) +#define RPC_ON(dbenv) ((dbenv)->cl_handle != NULL) +#define TXN_ON(dbenv) ((dbenv)->tx_handle != NULL) + +/* + * STD_LOCKING Standard locking, that is, locking was configured and CDB + * was not. We do not do locking in off-page duplicate trees, + * so we check for that in the cursor first. + */ +#define STD_LOCKING(dbc) \ + (!F_ISSET(dbc, DBC_OPD) && \ + !CDB_LOCKING((dbc)->dbp->dbenv) && LOCKING_ON((dbc)->dbp->dbenv)) + +/* + * IS_RECOVERING: The system is running recovery. + */ +#define IS_RECOVERING(dbenv) \ + (LOGGING_ON(dbenv) && \ + F_ISSET((DB_LOG *)(dbenv)->lg_handle, DBLOG_RECOVER)) + +/* Initialization methods are often illegal before/after open is called. */ +#define ENV_ILLEGAL_AFTER_OPEN(dbenv, name) \ + if (F_ISSET((dbenv), DB_ENV_OPEN_CALLED)) \ + return (__db_mi_open(dbenv, name, 1)); +#define ENV_ILLEGAL_BEFORE_OPEN(dbenv, name) \ + if (!F_ISSET((dbenv), DB_ENV_OPEN_CALLED)) \ + return (__db_mi_open(dbenv, name, 0)); + +/* We're not actually user hostile, honest. */ +#define ENV_REQUIRES_CONFIG(dbenv, handle, i, flags) \ + if (handle == NULL) \ + return (__db_env_config(dbenv, i, flags)); +#define ENV_NOT_CONFIGURED(dbenv, handle, i, flags) \ + if (F_ISSET((dbenv), DB_ENV_OPEN_CALLED)) \ + ENV_REQUIRES_CONFIG(dbenv, handle, i, flags) + +/******************************************************* + * Database Access Methods. + *******************************************************/ +/* + * DB_IS_THREADED -- + * The database handle is free-threaded (was opened with DB_THREAD). + */ +#define DB_IS_THREADED(dbp) \ + ((dbp)->mutexp != NULL) + +/* Initialization methods are often illegal before/after open is called. */ +#define DB_ILLEGAL_AFTER_OPEN(dbp, name) \ + if (F_ISSET((dbp), DB_AM_OPEN_CALLED)) \ + return (__db_mi_open((dbp)->dbenv, name, 1)); +#define DB_ILLEGAL_BEFORE_OPEN(dbp, name) \ + if (!F_ISSET((dbp), DB_AM_OPEN_CALLED)) \ + return (__db_mi_open((dbp)->dbenv, name, 0)); +/* Some initialization methods are illegal if environment isn't local. */ +#define DB_ILLEGAL_IN_ENV(dbp, name) \ + if (!F_ISSET((dbp)->dbenv, DB_ENV_DBLOCAL)) \ + return (__db_mi_env((dbp)->dbenv, name)); +#define DB_ILLEGAL_METHOD(dbp, flags) { \ + int __ret; \ + if ((__ret = __dbh_am_chk(dbp, flags)) != 0) \ + return (__ret); \ +} + +/* + * Common DBC->internal fields. Each access method adds additional fields + * to this list, but the initial fields are common. + */ +#define __DBC_INTERNAL \ + DBC *opd; /* Off-page duplicate cursor. */\ + \ + void *page; /* Referenced page. */ \ + db_pgno_t root; /* Tree root. */ \ + db_pgno_t pgno; /* Referenced page number. */ \ + db_indx_t indx; /* Referenced key item index. */\ + \ + DB_LOCK lock; /* Cursor lock. */ \ + db_lockmode_t lock_mode; /* Lock mode. */ + +struct __dbc_internal { + __DBC_INTERNAL +}; + +/* Actions that __db_master_update can take. */ +typedef enum { MU_REMOVE, MU_RENAME, MU_OPEN } mu_action; + +/* + * Access-method-common macro for determining whether a cursor + * has been initialized. + */ +#define IS_INITIALIZED(dbc) ((dbc)->internal->pgno != PGNO_INVALID) + +/* Free the callback-allocated buffer, if necessary, hanging off of a DBT. */ +#define FREE_IF_NEEDED(sdbp, dbt) \ + if (F_ISSET((dbt), DB_DBT_APPMALLOC)) { \ + __os_ufree((sdbp)->dbenv, (dbt)->data); \ + F_CLR((dbt), DB_DBT_APPMALLOC); \ + } + +/* + * Use memory belonging to object "owner" to return the results of + * any no-DBT-flag get ops on cursor "dbc". + */ +#define SET_RET_MEM(dbc, owner) \ + do { \ + (dbc)->rskey = &(owner)->my_rskey; \ + (dbc)->rkey = &(owner)->my_rkey; \ + (dbc)->rdata = &(owner)->my_rdata; \ + } while (0) + +/* Use the return-data memory src is currently set to use in dest as well. */ +#define COPY_RET_MEM(src, dest) \ + do { \ + (dest)->rskey = (src)->rskey; \ + (dest)->rkey = (src)->rkey; \ + (dest)->rdata = (src)->rdata; \ + } while (0) + +/* Reset the returned-memory pointers to their defaults. */ +#define RESET_RET_MEM(dbc) \ + do { \ + (dbc)->rskey = &(dbc)->my_rskey; \ + (dbc)->rkey = &(dbc)->my_rkey; \ + (dbc)->rdata = &(dbc)->my_rdata; \ + } while (0) + +/******************************************************* + * Mpool. + *******************************************************/ +/* + * File types for DB access methods. Negative numbers are reserved to DB. + */ +#define DB_FTYPE_SET -1 /* Call pgin/pgout functions. */ +#define DB_FTYPE_NOTSET 0 /* Don't call... */ + +/* Structure used as the DB pgin/pgout pgcookie. */ +typedef struct __dbpginfo { + size_t db_pagesize; /* Underlying page size. */ + u_int32_t flags; /* Some DB_AM flags needed. */ + DBTYPE type; /* DB type */ +} DB_PGINFO; + +/******************************************************* + * Log. + *******************************************************/ +/* Initialize an LSN to 'zero'. */ +#define ZERO_LSN(LSN) do { \ + (LSN).file = 0; \ + (LSN).offset = 0; \ +} while (0) +#define IS_ZERO_LSN(LSN) ((LSN).file == 0 && (LSN).offset == 0) + +#define IS_INIT_LSN(LSN) ((LSN).file == 1 && (LSN).offset == 0) +#define INIT_LSN(LSN) do { \ + (LSN).file = 1; \ + (LSN).offset = 0; \ +} while (0) + +#define MAX_LSN(LSN) do { \ + (LSN).file = UINT32_MAX; \ + (LSN).offset = UINT32_MAX; \ +} while (0) +#define IS_MAX_LSN(LSN) \ + ((LSN).file == UINT32_MAX && (LSN).offset == UINT32_MAX) + +/* If logging is turned off, smash the lsn. */ +#define LSN_NOT_LOGGED(LSN) do { \ + (LSN).file = 0; \ + (LSN).offset = 1; \ +} while (0) +#define IS_NOT_LOGGED_LSN(LSN) \ + ((LSN).file == 0 && (LSN).offset == 1) + +/******************************************************* + * Txn. + *******************************************************/ +#define DB_NONBLOCK(C) ((C)->txn != NULL && F_ISSET((C)->txn, TXN_NOWAIT)) +#define NOWAIT_FLAG(txn) \ + ((txn) != NULL && F_ISSET((txn), TXN_NOWAIT) ? DB_LOCK_NOWAIT : 0) +#define IS_SUBTRANSACTION(txn) \ + ((txn) != NULL && (txn)->parent != NULL) + +/******************************************************* + * Crypto. + *******************************************************/ +#define DB_IV_BYTES 16 /* Bytes per IV */ +#define DB_MAC_KEY 20 /* Bytes per MAC checksum */ + +/******************************************************* + * Secondaries over RPC. + *******************************************************/ +#ifdef CONFIG_TEST +/* + * These are flags passed to DB->associate calls by the Tcl API if running + * over RPC. The RPC server will mask out these flags before making the real + * DB->associate call. + * + * These flags must coexist with the valid flags to DB->associate (currently + * DB_AUTO_COMMIT and DB_CREATE). DB_AUTO_COMMIT is in the group of + * high-order shared flags (0xff000000), and DB_CREATE is in the low-order + * group (0x00000fff), so we pick a range in between. + */ +#define DB_RPC2ND_MASK 0x00f00000 /* Reserved bits. */ + +#define DB_RPC2ND_REVERSEDATA 0x00100000 /* callback_n(0) _s_reversedata. */ +#define DB_RPC2ND_NOOP 0x00200000 /* callback_n(1) _s_noop */ +#define DB_RPC2ND_CONCATKEYDATA 0x00300000 /* callback_n(2) _s_concatkeydata */ +#define DB_RPC2ND_CONCATDATAKEY 0x00400000 /* callback_n(3) _s_concatdatakey */ +#define DB_RPC2ND_REVERSECONCAT 0x00500000 /* callback_n(4) _s_reverseconcat */ +#define DB_RPC2ND_TRUNCDATA 0x00600000 /* callback_n(5) _s_truncdata */ +#define DB_RPC2ND_CONSTANT 0x00700000 /* callback_n(6) _s_constant */ +#define DB_RPC2ND_GETZIP 0x00800000 /* sj_getzip */ +#define DB_RPC2ND_GETNAME 0x00900000 /* sj_getname */ +#endif + +/******************************************************* + * Forward structure declarations. + *******************************************************/ +struct __db_reginfo_t; typedef struct __db_reginfo_t REGINFO; +struct __db_txnhead; typedef struct __db_txnhead DB_TXNHEAD; +struct __db_txnlist; typedef struct __db_txnlist DB_TXNLIST; +struct __vrfy_childinfo; typedef struct __vrfy_childinfo VRFY_CHILDINFO; +struct __vrfy_dbinfo; typedef struct __vrfy_dbinfo VRFY_DBINFO; +struct __vrfy_pageinfo; typedef struct __vrfy_pageinfo VRFY_PAGEINFO; + +#if defined(__cplusplus) +} +#endif + +/******************************************************* + * Remaining general DB includes. + *******************************************************/ + + +#include "dbinc/globals.h" +#include "dbinc/debug.h" +#include "dbinc/mutex.h" +#include "dbinc/region.h" +#include "dbinc_auto/mutex_ext.h" /* XXX: Include after region.h. */ +#include "dbinc_auto/env_ext.h" +#include "dbinc/os.h" +#include "dbinc/rep.h" +#include "dbinc_auto/clib_ext.h" +#include "dbinc_auto/common_ext.h" + +/******************************************************* + * Remaining Log. + * These need to be defined after the general includes + * because they need rep.h from above. + *******************************************************/ +/* + * Test if the environment is currently logging changes. If we're in recovery + * or we're a replication client, we don't need to log changes because they're + * already in the log, even though we have a fully functional log system. + */ +#define DBENV_LOGGING(dbenv) \ + (LOGGING_ON(dbenv) && !IS_REP_CLIENT(dbenv) && \ + (!IS_RECOVERING(dbenv))) + +/* + * Test if we need to log a change. By default, we don't log operations without + * associated transactions, unless DIAGNOSTIC, DEBUG_ROP or DEBUG_WOP are on. + * This is because we want to get log records for read/write operations, and, if + * we trying to debug something, more information is always better. + * + * The DBC_RECOVER flag is set when we're in abort, as well as during recovery; + * thus DBC_LOGGING may be false for a particular dbc even when DBENV_LOGGING + * is true. + * + * We explicitly use LOGGING_ON/IS_REP_CLIENT here because we don't want to pull + * in the log headers, which IS_RECOVERING (and thus DBENV_LOGGING) rely on, and + * because DBC_RECOVER should be set anytime IS_RECOVERING would be true. + */ +#if defined(DIAGNOSTIC) || defined(DEBUG_ROP) || defined(DEBUG_WOP) +#define DBC_LOGGING(dbc) \ + (LOGGING_ON((dbc)->dbp->dbenv) && \ + !F_ISSET((dbc), DBC_RECOVER) && !IS_REP_CLIENT((dbc)->dbp->dbenv)) +#else +#define DBC_LOGGING(dbc) \ + ((dbc)->txn != NULL && LOGGING_ON((dbc)->dbp->dbenv) && \ + !F_ISSET((dbc), DBC_RECOVER) && !IS_REP_CLIENT((dbc)->dbp->dbenv)) +#endif + +#endif /* !_DB_INTERNAL_H_ */ diff --git a/lib_dict/bdb/include/db_int.in b/lib_dict/bdb/include/db_int.in new file mode 100644 index 000000000..522f2f728 --- /dev/null +++ b/lib_dict/bdb/include/db_int.in @@ -0,0 +1,591 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996-2004 + * Sleepycat Software. All rights reserved. + * + * $Id: db_int.in,v 11.155 2004/10/28 16:07:38 ubell Exp $ + */ + +#ifndef _DB_INTERNAL_H_ +#define _DB_INTERNAL_H_ + +/******************************************************* + * System includes, db.h, a few general DB includes. The DB includes are + * here because it's OK if db_int.h includes queue structure declarations. + *******************************************************/ +#ifndef NO_SYSTEM_INCLUDES +#if defined(STDC_HEADERS) || defined(__cplusplus) +#include +#else +#include +#endif +#include +#endif + +#include "db.h" + +#include "dbinc/queue.h" +#include "dbinc/shqueue.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +/******************************************************* + * General purpose constants and macros. + *******************************************************/ +#ifndef UINT16_MAX +#define UINT16_MAX 65535 /* Maximum 16-bit unsigned. */ +#endif +#ifndef UINT32_MAX +#ifdef __STDC__ +#define UINT32_MAX 4294967295U /* Maximum 32-bit unsigned. */ +#else +#define UINT32_MAX 0xffffffff /* Maximum 32-bit unsigned. */ +#endif +#endif + +#if defined(HAVE_LONG_LONG) && defined(HAVE_UNSIGNED_LONG_LONG) +#undef INT64_MAX +#undef INT64_MIN +#undef UINT64_MAX + +#ifdef DB_WIN32 +#define INT64_MAX _I64_MAX +#define INT64_MIN _I64_MIN +#define UINT64_MAX _UI64_MAX + +#define INT64_FMT "%l64d" +#define UINT64_FMT "%l64u" +#else +/* + * Override the system's 64-bit min/max constants. AIX's 32-bit compiler can + * handle 64-bit values, but the system's constants don't include the LL/ULL + * suffix, and so can't be compiled using the 32-bit compiler. + */ +#define INT64_MAX 9223372036854775807LL +#define INT64_MIN (-INT64_MAX-1) +#define UINT64_MAX 18446744073709551615ULL + +#define INT64_FMT "%lld" +#define UINT64_FMT "%llu" +#endif /* DB_WIN32 */ +#endif /* HAVE_LONG_LONG && HAVE_UNSIGNED_LONG_LONG */ + +#define MEGABYTE 1048576 +#define GIGABYTE 1073741824 + +#define MS_PER_SEC 1000 /* Milliseconds in a second. */ +#define USEC_PER_MS 1000 /* Microseconds in a millisecond. */ + +#define RECNO_OOB 0 /* Illegal record number. */ + +/* Test for a power-of-two (tests true for zero, which doesn't matter here). */ +#define POWER_OF_TWO(x) (((x) & ((x) - 1)) == 0) + +/* Test for valid page sizes. */ +#define DB_MIN_PGSIZE 0x000200 /* Minimum page size (512). */ +#define DB_MAX_PGSIZE 0x010000 /* Maximum page size (65536). */ +#define IS_VALID_PAGESIZE(x) \ + (POWER_OF_TWO(x) && (x) >= DB_MIN_PGSIZE && ((x) <= DB_MAX_PGSIZE)) + +/* Minimum number of pages cached, by default. */ +#define DB_MINPAGECACHE 16 + +/* + * If we are unable to determine the underlying filesystem block size, use + * 8K on the grounds that most OS's use less than 8K for a VM page size. + */ +#define DB_DEF_IOSIZE (8 * 1024) + +/* Align an integer to a specific boundary. */ +#undef DB_ALIGN +#define DB_ALIGN(v, bound) \ + (((v) + (bound) - 1) & ~(((uintmax_t)bound) - 1)) + +/* Increment a pointer to a specific boundary. */ +#undef ALIGNP_INC +#define ALIGNP_INC(p, bound) \ + (void *)(((uintptr_t)(p) + (bound) - 1) & ~(((uintptr_t)bound) - 1)) + +/* Decrement a pointer to a specific boundary. */ +#undef ALIGNP_DEC +#define ALIGNP_DEC(p, bound) \ + (void *)((uintptr_t)(p) & ~(((uintptr_t)bound) - 1)) + +/* + * Print an address as a u_long (a u_long is the largest type we can print + * portably). Most 64-bit systems have made longs 64-bits, so this should + * work. + */ +#define P_TO_ULONG(p) ((u_long)(uintptr_t)(p)) + +/* + * Convert a pointer to a small integral value. + * + * The (u_int16_t)(uintptr_t) cast avoids warnings: the (uintptr_t) cast + * converts the value to an integral type, and the (u_int16_t) cast converts + * it to a small integral type so we don't get complaints when we assign the + * final result to an integral type smaller than uintptr_t. + */ +#define P_TO_UINT32(p) ((u_int32_t)(uintptr_t)(p)) +#define P_TO_UINT16(p) ((u_int16_t)(uintptr_t)(p)) + +/* + * There are several on-page structures that are declared to have a number of + * fields followed by a variable length array of items. The structure size + * without including the variable length array or the address of the first of + * those elements can be found using SSZ. + * + * This macro can also be used to find the offset of a structure element in a + * structure. This is used in various places to copy structure elements from + * unaligned memory references, e.g., pointers into a packed page. + * + * There are two versions because compilers object if you take the address of + * an array. + */ +#undef SSZ +#define SSZ(name, field) P_TO_UINT16(&(((name *)0)->field)) + +#undef SSZA +#define SSZA(name, field) P_TO_UINT16(&(((name *)0)->field[0])) + +/* Structure used to print flag values. */ +typedef struct __fn { + u_int32_t mask; /* Flag value. */ + const char *name; /* Flag name. */ +} FN; + +/* Set, clear and test flags. */ +#define FLD_CLR(fld, f) (fld) &= ~(f) +#define FLD_ISSET(fld, f) ((fld) & (f)) +#define FLD_SET(fld, f) (fld) |= (f) +#define F_CLR(p, f) (p)->flags &= ~(f) +#define F_ISSET(p, f) ((p)->flags & (f)) +#define F_SET(p, f) (p)->flags |= (f) +#define LF_CLR(f) ((flags) &= ~(f)) +#define LF_ISSET(f) ((flags) & (f)) +#define LF_SET(f) ((flags) |= (f)) + +/* + * Calculate a percentage. The values can overflow 32-bit integer arithmetic + * so we use floating point. + * + * When calculating a bytes-vs-page size percentage, we're getting the inverse + * of the percentage in all cases, that is, we want 100 minus the percentage we + * calculate. + */ +#define DB_PCT(v, total) \ + ((int)((total) == 0 ? 0 : ((double)(v) * 100) / (total))) +#define DB_PCT_PG(v, total, pgsize) \ + ((int)((total) == 0 ? 0 : \ + 100 - ((double)(v) * 100) / ((total) * (pgsize)))) + +/* + * Structure used for callback message aggregation. + * + * Display values in XXX_stat_print calls. + */ +typedef struct __db_msgbuf { + char *buf; /* Heap allocated buffer. */ + char *cur; /* Current end of message. */ + size_t len; /* Allocated length of buffer. */ +} DB_MSGBUF; +#define DB_MSGBUF_INIT(a) do { \ + (a)->buf = (a)->cur = NULL; \ + (a)->len = 0; \ +} while (0) +#define DB_MSGBUF_FLUSH(dbenv, a) do { \ + if ((a)->buf != NULL) { \ + if ((a)->cur != (a)->buf) \ + __db_msg(dbenv, "%s", (a)->buf); \ + __os_free(dbenv, (a)->buf); \ + DB_MSGBUF_INIT(a); \ + } \ +} while (0) +#define STAT_FMT(msg, fmt, type, v) do { \ + DB_MSGBUF __mb; \ + DB_MSGBUF_INIT(&__mb); \ + __db_msgadd(dbenv, &__mb, fmt, (type)(v)); \ + __db_msgadd(dbenv, &__mb, "\t%s", msg); \ + DB_MSGBUF_FLUSH(dbenv, &__mb); \ +} while (0) +#define STAT_HEX(msg, v) \ + __db_msg(dbenv, "%#lx\t%s", (u_long)(v), msg) +#define STAT_ISSET(msg, p) \ + __db_msg(dbenv, "%sSet\t%s", (p) == NULL ? "!" : " ", msg) +#define STAT_LONG(msg, v) \ + __db_msg(dbenv, "%ld\t%s", (long)(v), msg) +#define STAT_LSN(msg, lsnp) \ + __db_msg(dbenv, "%lu/%lu\t%s", \ + (u_long)(lsnp)->file, (u_long)(lsnp)->offset, msg) +#define STAT_STRING(msg, p) do { \ + const char *__p = p; /* p may be a function call. */ \ + __db_msg(dbenv, "%s\t%s", __p == NULL ? "!Set" : __p, msg); \ +} while (0) +#define STAT_ULONG(msg, v) \ + __db_msg(dbenv, "%lu\t%s", (u_long)(v), msg) + +/******************************************************* + * API return values + *******************************************************/ +/* + * Return values that are OK for each different call. Most calls have a + * standard 'return of 0 is only OK value', but some, like db->get have + * DB_NOTFOUND as a return value, but it really isn't an error. + */ +#define DB_RETOK_STD(ret) ((ret) == 0) +#define DB_RETOK_DBCDEL(ret) ((ret) == 0 || (ret) == DB_KEYEMPTY || \ + (ret) == DB_NOTFOUND) +#define DB_RETOK_DBCGET(ret) ((ret) == 0 || (ret) == DB_KEYEMPTY || \ + (ret) == DB_NOTFOUND) +#define DB_RETOK_DBCPUT(ret) ((ret) == 0 || (ret) == DB_KEYEXIST || \ + (ret) == DB_NOTFOUND) +#define DB_RETOK_DBDEL(ret) DB_RETOK_DBCDEL(ret) +#define DB_RETOK_DBGET(ret) DB_RETOK_DBCGET(ret) +#define DB_RETOK_DBPUT(ret) ((ret) == 0 || (ret) == DB_KEYEXIST) +#define DB_RETOK_LGGET(ret) ((ret) == 0 || (ret) == DB_NOTFOUND) +#define DB_RETOK_MPGET(ret) ((ret) == 0 || (ret) == DB_PAGE_NOTFOUND) +#define DB_RETOK_REPPMSG(ret) ((ret) == 0 || \ + (ret) == DB_REP_ISPERM || \ + (ret) == DB_REP_NEWMASTER || \ + (ret) == DB_REP_NEWSITE || \ + (ret) == DB_REP_NOTPERM || \ + (ret) == DB_REP_STARTUPDONE) + +/* Find a reasonable operation-not-supported error. */ +#ifdef EOPNOTSUPP +#define DB_OPNOTSUP EOPNOTSUPP +#else +#ifdef ENOTSUP +#define DB_OPNOTSUP ENOTSUP +#else +#define DB_OPNOTSUP EINVAL +#endif +#endif + +/******************************************************* + * Files. + *******************************************************/ +/* + * We use 1024 as the maximum path length. It's too hard to figure out what + * the real path length is, as it was traditionally stored in , + * and that file isn't always available. + */ +#undef MAXPATHLEN +#define MAXPATHLEN 1024 + +#define PATH_DOT "." /* Current working directory. */ + /* Path separator character(s). */ +#define PATH_SEPARATOR "@PATH_SEPARATOR@" + +/******************************************************* + * Environment. + *******************************************************/ +/* Type passed to __db_appname(). */ +typedef enum { + DB_APP_NONE=0, /* No type (region). */ + DB_APP_DATA, /* Data file. */ + DB_APP_LOG, /* Log file. */ + DB_APP_TMP /* Temporary file. */ +} APPNAME; + +/* + * CDB_LOCKING CDB product locking. + * CRYPTO_ON Security has been configured. + * LOCKING_ON Locking has been configured. + * LOGGING_ON Logging has been configured. + * MPOOL_ON Memory pool has been configured. + * REP_ON Replication has been configured. + * RPC_ON RPC has been configured. + * TXN_ON Transactions have been configured. + */ +#define CDB_LOCKING(dbenv) F_ISSET(dbenv, DB_ENV_CDB) +#define CRYPTO_ON(dbenv) ((dbenv)->crypto_handle != NULL) +#define LOCKING_ON(dbenv) ((dbenv)->lk_handle != NULL) +#define LOGGING_ON(dbenv) ((dbenv)->lg_handle != NULL) +#define MPOOL_ON(dbenv) ((dbenv)->mp_handle != NULL) +#define REP_ON(dbenv) ((dbenv)->rep_handle != NULL) +#define RPC_ON(dbenv) ((dbenv)->cl_handle != NULL) +#define TXN_ON(dbenv) ((dbenv)->tx_handle != NULL) + +/* + * STD_LOCKING Standard locking, that is, locking was configured and CDB + * was not. We do not do locking in off-page duplicate trees, + * so we check for that in the cursor first. + */ +#define STD_LOCKING(dbc) \ + (!F_ISSET(dbc, DBC_OPD) && \ + !CDB_LOCKING((dbc)->dbp->dbenv) && LOCKING_ON((dbc)->dbp->dbenv)) + +/* + * IS_RECOVERING: The system is running recovery. + */ +#define IS_RECOVERING(dbenv) \ + (LOGGING_ON(dbenv) && \ + F_ISSET((DB_LOG *)(dbenv)->lg_handle, DBLOG_RECOVER)) + +/* Initialization methods are often illegal before/after open is called. */ +#define ENV_ILLEGAL_AFTER_OPEN(dbenv, name) \ + if (F_ISSET((dbenv), DB_ENV_OPEN_CALLED)) \ + return (__db_mi_open(dbenv, name, 1)); +#define ENV_ILLEGAL_BEFORE_OPEN(dbenv, name) \ + if (!F_ISSET((dbenv), DB_ENV_OPEN_CALLED)) \ + return (__db_mi_open(dbenv, name, 0)); + +/* We're not actually user hostile, honest. */ +#define ENV_REQUIRES_CONFIG(dbenv, handle, i, flags) \ + if (handle == NULL) \ + return (__db_env_config(dbenv, i, flags)); +#define ENV_NOT_CONFIGURED(dbenv, handle, i, flags) \ + if (F_ISSET((dbenv), DB_ENV_OPEN_CALLED)) \ + ENV_REQUIRES_CONFIG(dbenv, handle, i, flags) + +/******************************************************* + * Database Access Methods. + *******************************************************/ +/* + * DB_IS_THREADED -- + * The database handle is free-threaded (was opened with DB_THREAD). + */ +#define DB_IS_THREADED(dbp) \ + ((dbp)->mutexp != NULL) + +/* Initialization methods are often illegal before/after open is called. */ +#define DB_ILLEGAL_AFTER_OPEN(dbp, name) \ + if (F_ISSET((dbp), DB_AM_OPEN_CALLED)) \ + return (__db_mi_open((dbp)->dbenv, name, 1)); +#define DB_ILLEGAL_BEFORE_OPEN(dbp, name) \ + if (!F_ISSET((dbp), DB_AM_OPEN_CALLED)) \ + return (__db_mi_open((dbp)->dbenv, name, 0)); +/* Some initialization methods are illegal if environment isn't local. */ +#define DB_ILLEGAL_IN_ENV(dbp, name) \ + if (!F_ISSET((dbp)->dbenv, DB_ENV_DBLOCAL)) \ + return (__db_mi_env((dbp)->dbenv, name)); +#define DB_ILLEGAL_METHOD(dbp, flags) { \ + int __ret; \ + if ((__ret = __dbh_am_chk(dbp, flags)) != 0) \ + return (__ret); \ +} + +/* + * Common DBC->internal fields. Each access method adds additional fields + * to this list, but the initial fields are common. + */ +#define __DBC_INTERNAL \ + DBC *opd; /* Off-page duplicate cursor. */\ + \ + void *page; /* Referenced page. */ \ + db_pgno_t root; /* Tree root. */ \ + db_pgno_t pgno; /* Referenced page number. */ \ + db_indx_t indx; /* Referenced key item index. */\ + \ + DB_LOCK lock; /* Cursor lock. */ \ + db_lockmode_t lock_mode; /* Lock mode. */ + +struct __dbc_internal { + __DBC_INTERNAL +}; + +/* Actions that __db_master_update can take. */ +typedef enum { MU_REMOVE, MU_RENAME, MU_OPEN } mu_action; + +/* + * Access-method-common macro for determining whether a cursor + * has been initialized. + */ +#define IS_INITIALIZED(dbc) ((dbc)->internal->pgno != PGNO_INVALID) + +/* Free the callback-allocated buffer, if necessary, hanging off of a DBT. */ +#define FREE_IF_NEEDED(sdbp, dbt) \ + if (F_ISSET((dbt), DB_DBT_APPMALLOC)) { \ + __os_ufree((sdbp)->dbenv, (dbt)->data); \ + F_CLR((dbt), DB_DBT_APPMALLOC); \ + } + +/* + * Use memory belonging to object "owner" to return the results of + * any no-DBT-flag get ops on cursor "dbc". + */ +#define SET_RET_MEM(dbc, owner) \ + do { \ + (dbc)->rskey = &(owner)->my_rskey; \ + (dbc)->rkey = &(owner)->my_rkey; \ + (dbc)->rdata = &(owner)->my_rdata; \ + } while (0) + +/* Use the return-data memory src is currently set to use in dest as well. */ +#define COPY_RET_MEM(src, dest) \ + do { \ + (dest)->rskey = (src)->rskey; \ + (dest)->rkey = (src)->rkey; \ + (dest)->rdata = (src)->rdata; \ + } while (0) + +/* Reset the returned-memory pointers to their defaults. */ +#define RESET_RET_MEM(dbc) \ + do { \ + (dbc)->rskey = &(dbc)->my_rskey; \ + (dbc)->rkey = &(dbc)->my_rkey; \ + (dbc)->rdata = &(dbc)->my_rdata; \ + } while (0) + +/******************************************************* + * Mpool. + *******************************************************/ +/* + * File types for DB access methods. Negative numbers are reserved to DB. + */ +#define DB_FTYPE_SET -1 /* Call pgin/pgout functions. */ +#define DB_FTYPE_NOTSET 0 /* Don't call... */ + +/* Structure used as the DB pgin/pgout pgcookie. */ +typedef struct __dbpginfo { + size_t db_pagesize; /* Underlying page size. */ + u_int32_t flags; /* Some DB_AM flags needed. */ + DBTYPE type; /* DB type */ +} DB_PGINFO; + +/******************************************************* + * Log. + *******************************************************/ +/* Initialize an LSN to 'zero'. */ +#define ZERO_LSN(LSN) do { \ + (LSN).file = 0; \ + (LSN).offset = 0; \ +} while (0) +#define IS_ZERO_LSN(LSN) ((LSN).file == 0 && (LSN).offset == 0) + +#define IS_INIT_LSN(LSN) ((LSN).file == 1 && (LSN).offset == 0) +#define INIT_LSN(LSN) do { \ + (LSN).file = 1; \ + (LSN).offset = 0; \ +} while (0) + +#define MAX_LSN(LSN) do { \ + (LSN).file = UINT32_MAX; \ + (LSN).offset = UINT32_MAX; \ +} while (0) +#define IS_MAX_LSN(LSN) \ + ((LSN).file == UINT32_MAX && (LSN).offset == UINT32_MAX) + +/* If logging is turned off, smash the lsn. */ +#define LSN_NOT_LOGGED(LSN) do { \ + (LSN).file = 0; \ + (LSN).offset = 1; \ +} while (0) +#define IS_NOT_LOGGED_LSN(LSN) \ + ((LSN).file == 0 && (LSN).offset == 1) + +/******************************************************* + * Txn. + *******************************************************/ +#define DB_NONBLOCK(C) ((C)->txn != NULL && F_ISSET((C)->txn, TXN_NOWAIT)) +#define NOWAIT_FLAG(txn) \ + ((txn) != NULL && F_ISSET((txn), TXN_NOWAIT) ? DB_LOCK_NOWAIT : 0) +#define IS_SUBTRANSACTION(txn) \ + ((txn) != NULL && (txn)->parent != NULL) + +/******************************************************* + * Crypto. + *******************************************************/ +#define DB_IV_BYTES 16 /* Bytes per IV */ +#define DB_MAC_KEY 20 /* Bytes per MAC checksum */ + +/******************************************************* + * Secondaries over RPC. + *******************************************************/ +#ifdef CONFIG_TEST +/* + * These are flags passed to DB->associate calls by the Tcl API if running + * over RPC. The RPC server will mask out these flags before making the real + * DB->associate call. + * + * These flags must coexist with the valid flags to DB->associate (currently + * DB_AUTO_COMMIT and DB_CREATE). DB_AUTO_COMMIT is in the group of + * high-order shared flags (0xff000000), and DB_CREATE is in the low-order + * group (0x00000fff), so we pick a range in between. + */ +#define DB_RPC2ND_MASK 0x00f00000 /* Reserved bits. */ + +#define DB_RPC2ND_REVERSEDATA 0x00100000 /* callback_n(0) _s_reversedata. */ +#define DB_RPC2ND_NOOP 0x00200000 /* callback_n(1) _s_noop */ +#define DB_RPC2ND_CONCATKEYDATA 0x00300000 /* callback_n(2) _s_concatkeydata */ +#define DB_RPC2ND_CONCATDATAKEY 0x00400000 /* callback_n(3) _s_concatdatakey */ +#define DB_RPC2ND_REVERSECONCAT 0x00500000 /* callback_n(4) _s_reverseconcat */ +#define DB_RPC2ND_TRUNCDATA 0x00600000 /* callback_n(5) _s_truncdata */ +#define DB_RPC2ND_CONSTANT 0x00700000 /* callback_n(6) _s_constant */ +#define DB_RPC2ND_GETZIP 0x00800000 /* sj_getzip */ +#define DB_RPC2ND_GETNAME 0x00900000 /* sj_getname */ +#endif + +/******************************************************* + * Forward structure declarations. + *******************************************************/ +struct __db_reginfo_t; typedef struct __db_reginfo_t REGINFO; +struct __db_txnhead; typedef struct __db_txnhead DB_TXNHEAD; +struct __db_txnlist; typedef struct __db_txnlist DB_TXNLIST; +struct __vrfy_childinfo; typedef struct __vrfy_childinfo VRFY_CHILDINFO; +struct __vrfy_dbinfo; typedef struct __vrfy_dbinfo VRFY_DBINFO; +struct __vrfy_pageinfo; typedef struct __vrfy_pageinfo VRFY_PAGEINFO; + +#if defined(__cplusplus) +} +#endif + +/******************************************************* + * Remaining general DB includes. + *******************************************************/ +@db_int_def@ + +#include "dbinc/globals.h" +#include "dbinc/debug.h" +#include "dbinc/mutex.h" +#include "dbinc/region.h" +#include "dbinc_auto/mutex_ext.h" /* XXX: Include after region.h. */ +#include "dbinc_auto/env_ext.h" +#include "dbinc/os.h" +#include "dbinc/rep.h" +#include "dbinc_auto/clib_ext.h" +#include "dbinc_auto/common_ext.h" + +/******************************************************* + * Remaining Log. + * These need to be defined after the general includes + * because they need rep.h from above. + *******************************************************/ +/* + * Test if the environment is currently logging changes. If we're in recovery + * or we're a replication client, we don't need to log changes because they're + * already in the log, even though we have a fully functional log system. + */ +#define DBENV_LOGGING(dbenv) \ + (LOGGING_ON(dbenv) && !IS_REP_CLIENT(dbenv) && \ + (!IS_RECOVERING(dbenv))) + +/* + * Test if we need to log a change. By default, we don't log operations without + * associated transactions, unless DIAGNOSTIC, DEBUG_ROP or DEBUG_WOP are on. + * This is because we want to get log records for read/write operations, and, if + * we trying to debug something, more information is always better. + * + * The DBC_RECOVER flag is set when we're in abort, as well as during recovery; + * thus DBC_LOGGING may be false for a particular dbc even when DBENV_LOGGING + * is true. + * + * We explicitly use LOGGING_ON/IS_REP_CLIENT here because we don't want to pull + * in the log headers, which IS_RECOVERING (and thus DBENV_LOGGING) rely on, and + * because DBC_RECOVER should be set anytime IS_RECOVERING would be true. + */ +#if defined(DIAGNOSTIC) || defined(DEBUG_ROP) || defined(DEBUG_WOP) +#define DBC_LOGGING(dbc) \ + (LOGGING_ON((dbc)->dbp->dbenv) && \ + !F_ISSET((dbc), DBC_RECOVER) && !IS_REP_CLIENT((dbc)->dbp->dbenv)) +#else +#define DBC_LOGGING(dbc) \ + ((dbc)->txn != NULL && LOGGING_ON((dbc)->dbp->dbenv) && \ + !F_ISSET((dbc), DBC_RECOVER) && !IS_REP_CLIENT((dbc)->dbp->dbenv)) +#endif + +#endif /* !_DB_INTERNAL_H_ */ diff --git a/lib_dict/bdb/include/db_join.h b/lib_dict/bdb/include/db_join.h new file mode 100644 index 000000000..3fea2ad2f --- /dev/null +++ b/lib_dict/bdb/include/db_join.h @@ -0,0 +1,31 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1998-2004 + * Sleepycat Software. All rights reserved. + * + * @(#)db_join.h 11.1 (Sleepycat) 7/25/99 + */ + +#ifndef _DB_JOIN_H_ +#define _DB_JOIN_H_ + +/* + * Joins use a join cursor that is similar to a regular DB cursor except + * that it only supports c_get and c_close functionality. Also, it does + * not support the full range of flags for get. + */ +typedef struct __join_cursor { + u_int8_t *j_exhausted; /* Array of flags; is cursor i exhausted? */ + DBC **j_curslist; /* Array of cursors in the join: constant. */ + DBC **j_fdupcurs; /* Cursors w/ first instances of current dup. */ + DBC **j_workcurs; /* Scratch cursor copies to muck with. */ + DB *j_primary; /* Primary dbp. */ + DBT j_key; /* Used to do lookups. */ + DBT j_rdata; /* Memory used for data return. */ + u_int32_t j_ncurs; /* How many cursors do we have? */ +#define JOIN_RETRY 0x01 /* Error on primary get; re-return same key. */ + u_int32_t flags; +} JOIN_CURSOR; + +#endif /* !_DB_JOIN_H_ */ diff --git a/lib_dict/bdb/include/db_page.h b/lib_dict/bdb/include/db_page.h new file mode 100644 index 000000000..59a1292ff --- /dev/null +++ b/lib_dict/bdb/include/db_page.h @@ -0,0 +1,657 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996-2004 + * Sleepycat Software. All rights reserved. + * + * $Id: db_page.h,v 11.63 2004/09/17 22:00:27 mjc Exp $ + */ + +#ifndef _DB_PAGE_H_ +#define _DB_PAGE_H_ + +#if defined(__cplusplus) +extern "C" { +#endif + +/* + * DB page formats. + * + * !!! + * This implementation requires that values within the following structures + * NOT be padded -- note, ANSI C permits random padding within structures. + * If your compiler pads randomly you can just forget ever making DB run on + * your system. In addition, no data type can require larger alignment than + * its own size, e.g., a 4-byte data element may not require 8-byte alignment. + * + * Note that key/data lengths are often stored in db_indx_t's -- this is + * not accidental, nor does it limit the key/data size. If the key/data + * item fits on a page, it's guaranteed to be small enough to fit into a + * db_indx_t, and storing it in one saves space. + */ + +#define PGNO_INVALID 0 /* Invalid page number in any database. */ +#define PGNO_BASE_MD 0 /* Base database: metadata page number. */ + +/* Page types. */ +#define P_INVALID 0 /* Invalid page type. */ +#define __P_DUPLICATE 1 /* Duplicate. DEPRECATED in 3.1 */ +#define P_HASH 2 /* Hash. */ +#define P_IBTREE 3 /* Btree internal. */ +#define P_IRECNO 4 /* Recno internal. */ +#define P_LBTREE 5 /* Btree leaf. */ +#define P_LRECNO 6 /* Recno leaf. */ +#define P_OVERFLOW 7 /* Overflow. */ +#define P_HASHMETA 8 /* Hash metadata page. */ +#define P_BTREEMETA 9 /* Btree metadata page. */ +#define P_QAMMETA 10 /* Queue metadata page. */ +#define P_QAMDATA 11 /* Queue data page. */ +#define P_LDUP 12 /* Off-page duplicate leaf. */ +#define P_PAGETYPE_MAX 13 + +/* + * When we create pages in mpool, we ask mpool to clear some number of bytes + * in the header. This number must be at least as big as the regular page + * headers and cover enough of the btree and hash meta-data pages to obliterate + * the page type. + */ +#define DB_PAGE_DB_LEN 32 +#define DB_PAGE_QUEUE_LEN 0 + +/************************************************************************ + GENERIC METADATA PAGE HEADER + * + * !!! + * The magic and version numbers have to be in the same place in all versions + * of the metadata page as the application may not have upgraded the database. + ************************************************************************/ +typedef struct _dbmeta33 { + DB_LSN lsn; /* 00-07: LSN. */ + db_pgno_t pgno; /* 08-11: Current page number. */ + u_int32_t magic; /* 12-15: Magic number. */ + u_int32_t version; /* 16-19: Version. */ + u_int32_t pagesize; /* 20-23: Pagesize. */ + u_int8_t encrypt_alg; /* 24: Encryption algorithm. */ + u_int8_t type; /* 25: Page type. */ +#define DBMETA_CHKSUM 0x01 + u_int8_t metaflags; /* 26: Meta-only flags */ + u_int8_t unused1; /* 27: Unused. */ + u_int32_t free; /* 28-31: Free list page number. */ + db_pgno_t last_pgno; /* 32-35: Page number of last page in db. */ + u_int32_t unused3; /* 36-39: Unused. */ + u_int32_t key_count; /* 40-43: Cached key count. */ + u_int32_t record_count; /* 44-47: Cached record count. */ + u_int32_t flags; /* 48-51: Flags: unique to each AM. */ + /* 52-71: Unique file ID. */ + u_int8_t uid[DB_FILE_ID_LEN]; +} DBMETA33, DBMETA; + +/************************************************************************ + BTREE METADATA PAGE LAYOUT + ************************************************************************/ +typedef struct _btmeta33 { +#define BTM_DUP 0x001 /* Duplicates. */ +#define BTM_RECNO 0x002 /* Recno tree. */ +#define BTM_RECNUM 0x004 /* Btree: maintain record count. */ +#define BTM_FIXEDLEN 0x008 /* Recno: fixed length records. */ +#define BTM_RENUMBER 0x010 /* Recno: renumber on insert/delete. */ +#define BTM_SUBDB 0x020 /* Subdatabases. */ +#define BTM_DUPSORT 0x040 /* Duplicates are sorted. */ +#define BTM_MASK 0x07f + DBMETA dbmeta; /* 00-71: Generic meta-data header. */ + + u_int32_t maxkey; /* 72-75: Btree: Maxkey. */ + u_int32_t minkey; /* 76-79: Btree: Minkey. */ + u_int32_t re_len; /* 80-83: Recno: fixed-length record length. */ + u_int32_t re_pad; /* 84-87: Recno: fixed-length record pad. */ + u_int32_t root; /* 88-91: Root page. */ + u_int32_t unused[92]; /* 92-459: Unused space */ + u_int32_t crypto_magic; /* 460-463: Crypto magic number */ + u_int32_t trash[3]; /* 464-475: Trash space - Do not use */ + u_int8_t iv[DB_IV_BYTES]; /* 476-495: Crypto IV */ + u_int8_t chksum[DB_MAC_KEY]; /* 496-511: Page chksum */ + + /* + * Minimum page size is 512. + */ +} BTMETA33, BTMETA; + +/************************************************************************ + HASH METADATA PAGE LAYOUT + ************************************************************************/ +typedef struct _hashmeta33 { +#define DB_HASH_DUP 0x01 /* Duplicates. */ +#define DB_HASH_SUBDB 0x02 /* Subdatabases. */ +#define DB_HASH_DUPSORT 0x04 /* Duplicates are sorted. */ + DBMETA dbmeta; /* 00-71: Generic meta-data page header. */ + + u_int32_t max_bucket; /* 72-75: ID of Maximum bucket in use */ + u_int32_t high_mask; /* 76-79: Modulo mask into table */ + u_int32_t low_mask; /* 80-83: Modulo mask into table lower half */ + u_int32_t ffactor; /* 84-87: Fill factor */ + u_int32_t nelem; /* 88-91: Number of keys in hash table */ + u_int32_t h_charkey; /* 92-95: Value of hash(CHARKEY) */ +#define NCACHED 32 /* number of spare points */ + /* 96-223: Spare pages for overflow */ + u_int32_t spares[NCACHED]; + u_int32_t unused[59]; /* 224-459: Unused space */ + u_int32_t crypto_magic; /* 460-463: Crypto magic number */ + u_int32_t trash[3]; /* 464-475: Trash space - Do not use */ + u_int8_t iv[DB_IV_BYTES]; /* 476-495: Crypto IV */ + u_int8_t chksum[DB_MAC_KEY]; /* 496-511: Page chksum */ + + /* + * Minimum page size is 512. + */ +} HMETA33, HMETA; + +/************************************************************************ + QUEUE METADATA PAGE LAYOUT + ************************************************************************/ +/* + * QAM Meta data page structure + * + */ +typedef struct _qmeta33 { + DBMETA dbmeta; /* 00-71: Generic meta-data header. */ + + u_int32_t first_recno; /* 72-75: First not deleted record. */ + u_int32_t cur_recno; /* 76-79: Next recno to be allocated. */ + u_int32_t re_len; /* 80-83: Fixed-length record length. */ + u_int32_t re_pad; /* 84-87: Fixed-length record pad. */ + u_int32_t rec_page; /* 88-91: Records Per Page. */ + u_int32_t page_ext; /* 92-95: Pages per extent */ + + u_int32_t unused[91]; /* 96-459: Unused space */ + u_int32_t crypto_magic; /* 460-463: Crypto magic number */ + u_int32_t trash[3]; /* 464-475: Trash space - Do not use */ + u_int8_t iv[DB_IV_BYTES]; /* 476-495: Crypto IV */ + u_int8_t chksum[DB_MAC_KEY]; /* 496-511: Page chksum */ + /* + * Minimum page size is 512. + */ +} QMETA33, QMETA; + +/* + * DBMETASIZE is a constant used by __db_file_setup and DB->verify + * as a buffer which is guaranteed to be larger than any possible + * metadata page size and smaller than any disk sector. + */ +#define DBMETASIZE 512 + +/************************************************************************ + BTREE/HASH MAIN PAGE LAYOUT + ************************************************************************/ +/* + * +-----------------------------------+ + * | lsn | pgno | prev pgno | + * +-----------------------------------+ + * | next pgno | entries | hf offset | + * +-----------------------------------+ + * | level | type | chksum | + * +-----------------------------------+ + * | iv | index | free --> | + * +-----------+-----------------------+ + * | F R E E A R E A | + * +-----------------------------------+ + * | <-- free | item | + * +-----------------------------------+ + * | item | item | item | + * +-----------------------------------+ + * + * sizeof(PAGE) == 26 bytes + possibly 20 bytes of checksum and possibly + * 16 bytes of IV (+ 2 bytes for alignment), and the following indices + * are guaranteed to be two-byte aligned. If we aren't doing crypto or + * checksumming the bytes are reclaimed for data storage. + * + * For hash and btree leaf pages, index items are paired, e.g., inp[0] is the + * key for inp[1]'s data. All other types of pages only contain single items. + */ +typedef struct __pg_chksum { + u_int8_t unused[2]; /* 26-27: For alignment */ + u_int8_t chksum[4]; /* 28-31: Checksum */ +} PG_CHKSUM; + +typedef struct __pg_crypto { + u_int8_t unused[2]; /* 26-27: For alignment */ + u_int8_t chksum[DB_MAC_KEY]; /* 28-47: Checksum */ + u_int8_t iv[DB_IV_BYTES]; /* 48-63: IV */ + /* !!! + * Must be 16-byte aligned for crypto + */ +} PG_CRYPTO; + +typedef struct _db_page { + DB_LSN lsn; /* 00-07: Log sequence number. */ + db_pgno_t pgno; /* 08-11: Current page number. */ + db_pgno_t prev_pgno; /* 12-15: Previous page number. */ + db_pgno_t next_pgno; /* 16-19: Next page number. */ + db_indx_t entries; /* 20-21: Number of items on the page. */ + db_indx_t hf_offset; /* 22-23: High free byte page offset. */ + + /* + * The btree levels are numbered from the leaf to the root, starting + * with 1, so the leaf is level 1, its parent is level 2, and so on. + * We maintain this level on all btree pages, but the only place that + * we actually need it is on the root page. It would not be difficult + * to hide the byte on the root page once it becomes an internal page, + * so we could get this byte back if we needed it for something else. + */ +#define LEAFLEVEL 1 +#define MAXBTREELEVEL 255 + u_int8_t level; /* 24: Btree tree level. */ + u_int8_t type; /* 25: Page type. */ +} PAGE; + +/* + * With many compilers sizeof(PAGE) == 28, while SIZEOF_PAGE == 26. + * We add in other things directly after the page header and need + * the SIZEOF_PAGE. When giving the sizeof(), many compilers will + * pad it out to the next 4-byte boundary. + */ +#define SIZEOF_PAGE 26 +/* + * !!! + * DB_AM_ENCRYPT always implies DB_AM_CHKSUM so that must come first. + */ +#define P_INP(dbp, pg) \ + ((db_indx_t *)((u_int8_t *)(pg) + SIZEOF_PAGE + \ + (F_ISSET((dbp), DB_AM_ENCRYPT) ? sizeof(PG_CRYPTO) : \ + (F_ISSET((dbp), DB_AM_CHKSUM) ? sizeof(PG_CHKSUM) : 0)))) + +#define P_IV(dbp, pg) \ + (F_ISSET((dbp), DB_AM_ENCRYPT) ? ((u_int8_t *)(pg) + \ + SIZEOF_PAGE + SSZA(PG_CRYPTO, iv)) \ + : NULL) + +#define P_CHKSUM(dbp, pg) \ + (F_ISSET((dbp), DB_AM_ENCRYPT) ? ((u_int8_t *)(pg) + \ + SIZEOF_PAGE + SSZA(PG_CRYPTO, chksum)) : \ + (F_ISSET((dbp), DB_AM_CHKSUM) ? ((u_int8_t *)(pg) + \ + SIZEOF_PAGE + SSZA(PG_CHKSUM, chksum)) \ + : NULL)) + +/* PAGE element macros. */ +#define LSN(p) (((PAGE *)p)->lsn) +#define PGNO(p) (((PAGE *)p)->pgno) +#define PREV_PGNO(p) (((PAGE *)p)->prev_pgno) +#define NEXT_PGNO(p) (((PAGE *)p)->next_pgno) +#define NUM_ENT(p) (((PAGE *)p)->entries) +#define HOFFSET(p) (((PAGE *)p)->hf_offset) +#define LEVEL(p) (((PAGE *)p)->level) +#define TYPE(p) (((PAGE *)p)->type) + +/************************************************************************ + QUEUE MAIN PAGE LAYOUT + ************************************************************************/ +/* + * Sizes of page below. Used to reclaim space if not doing + * crypto or checksumming. If you change the QPAGE below you + * MUST adjust this too. + */ +#define QPAGE_NORMAL 28 +#define QPAGE_CHKSUM 48 +#define QPAGE_SEC 64 + +typedef struct _qpage { + DB_LSN lsn; /* 00-07: Log sequence number. */ + db_pgno_t pgno; /* 08-11: Current page number. */ + u_int32_t unused0[3]; /* 12-23: Unused. */ + u_int8_t unused1[1]; /* 24: Unused. */ + u_int8_t type; /* 25: Page type. */ + u_int8_t unused2[2]; /* 26-27: Unused. */ + u_int8_t chksum[DB_MAC_KEY]; /* 28-47: Checksum */ + u_int8_t iv[DB_IV_BYTES]; /* 48-63: IV */ +} QPAGE; + +#define QPAGE_SZ(dbp) \ + (F_ISSET((dbp), DB_AM_ENCRYPT) ? QPAGE_SEC : \ + F_ISSET((dbp), DB_AM_CHKSUM) ? QPAGE_CHKSUM : QPAGE_NORMAL) +/* + * !!! + * The next_pgno and prev_pgno fields are not maintained for btree and recno + * internal pages. Doing so only provides a minor performance improvement, + * it's hard to do when deleting internal pages, and it increases the chance + * of deadlock during deletes and splits because we have to re-link pages at + * more than the leaf level. + * + * !!! + * The btree/recno access method needs db_recno_t bytes of space on the root + * page to specify how many records are stored in the tree. (The alternative + * is to store the number of records in the meta-data page, which will create + * a second hot spot in trees being actively modified, or recalculate it from + * the BINTERNAL fields on each access.) Overload the PREV_PGNO field. + */ +#define RE_NREC(p) \ + ((TYPE(p) == P_IBTREE || TYPE(p) == P_IRECNO) ? PREV_PGNO(p) : \ + (db_pgno_t)(TYPE(p) == P_LBTREE ? NUM_ENT(p) / 2 : NUM_ENT(p))) +#define RE_NREC_ADJ(p, adj) \ + PREV_PGNO(p) += adj; +#define RE_NREC_SET(p, num) \ + PREV_PGNO(p) = (num); + +/* + * Initialize a page. + * + * !!! + * Don't modify the page's LSN, code depends on it being unchanged after a + * P_INIT call. + */ +#define P_INIT(pg, pg_size, n, pg_prev, pg_next, btl, pg_type) do { \ + PGNO(pg) = (n); \ + PREV_PGNO(pg) = (pg_prev); \ + NEXT_PGNO(pg) = (pg_next); \ + NUM_ENT(pg) = (0); \ + HOFFSET(pg) = (db_indx_t)(pg_size); \ + LEVEL(pg) = (btl); \ + TYPE(pg) = (pg_type); \ +} while (0) + +/* Page header length (offset to first index). */ +#define P_OVERHEAD(dbp) P_TO_UINT16(P_INP(dbp, 0)) + +/* First free byte. */ +#define LOFFSET(dbp, pg) \ + (P_OVERHEAD(dbp) + NUM_ENT(pg) * sizeof(db_indx_t)) + +/* Free space on a regular page. */ +#define P_FREESPACE(dbp, pg) (HOFFSET(pg) - LOFFSET(dbp, pg)) + +/* Get a pointer to the bytes at a specific index. */ +#define P_ENTRY(dbp, pg, indx) ((u_int8_t *)pg + P_INP(dbp, pg)[indx]) + +/************************************************************************ + OVERFLOW PAGE LAYOUT + ************************************************************************/ + +/* + * Overflow items are referenced by HOFFPAGE and BOVERFLOW structures, which + * store a page number (the first page of the overflow item) and a length + * (the total length of the overflow item). The overflow item consists of + * some number of overflow pages, linked by the next_pgno field of the page. + * A next_pgno field of PGNO_INVALID flags the end of the overflow item. + * + * Overflow page overloads: + * The amount of overflow data stored on each page is stored in the + * hf_offset field. + * + * The implementation reference counts overflow items as it's possible + * for them to be promoted onto btree internal pages. The reference + * count is stored in the entries field. + */ +#define OV_LEN(p) (((PAGE *)p)->hf_offset) +#define OV_REF(p) (((PAGE *)p)->entries) + +/* Maximum number of bytes that you can put on an overflow page. */ +#define P_MAXSPACE(dbp, psize) ((psize) - P_OVERHEAD(dbp)) + +/* Free space on an overflow page. */ +#define P_OVFLSPACE(dbp, psize, pg) (P_MAXSPACE(dbp, psize) - HOFFSET(pg)) + +/************************************************************************ + HASH PAGE LAYOUT + ************************************************************************/ + +/* Each index references a group of bytes on the page. */ +#define H_KEYDATA 1 /* Key/data item. */ +#define H_DUPLICATE 2 /* Duplicate key/data item. */ +#define H_OFFPAGE 3 /* Overflow key/data item. */ +#define H_OFFDUP 4 /* Overflow page of duplicates. */ + +/* + * !!! + * Items on hash pages are (potentially) unaligned, so we can never cast the + * (page + offset) pointer to an HKEYDATA, HOFFPAGE or HOFFDUP structure, as + * we do with B+tree on-page structures. Because we frequently want the type + * field, it requires no alignment, and it's in the same location in all three + * structures, there's a pair of macros. + */ +#define HPAGE_PTYPE(p) (*(u_int8_t *)p) +#define HPAGE_TYPE(dbp, pg, indx) (*P_ENTRY(dbp, pg, indx)) + +/* + * The first and second types are H_KEYDATA and H_DUPLICATE, represented + * by the HKEYDATA structure: + * + * +-----------------------------------+ + * | type | key/data ... | + * +-----------------------------------+ + * + * For duplicates, the data field encodes duplicate elements in the data + * field: + * + * +---------------------------------------------------------------+ + * | type | len1 | element1 | len1 | len2 | element2 | len2 | + * +---------------------------------------------------------------+ + * + * Thus, by keeping track of the offset in the element, we can do both + * backward and forward traversal. + */ +typedef struct _hkeydata { + u_int8_t type; /* 00: Page type. */ + u_int8_t data[1]; /* Variable length key/data item. */ +} HKEYDATA; +#define HKEYDATA_DATA(p) (((u_int8_t *)p) + SSZA(HKEYDATA, data)) + +/* + * The length of any HKEYDATA item. Note that indx is an element index, + * not a PAIR index. + */ +#define LEN_HITEM(dbp, pg, pgsize, indx) \ + (((indx) == 0 ? (pgsize) : \ + (P_INP(dbp, pg)[(indx) - 1])) - (P_INP(dbp, pg)[indx])) + +#define LEN_HKEYDATA(dbp, pg, psize, indx) \ + (db_indx_t)(LEN_HITEM(dbp, pg, psize, indx) - HKEYDATA_SIZE(0)) + +/* + * Page space required to add a new HKEYDATA item to the page, with and + * without the index value. + */ +#define HKEYDATA_SIZE(len) \ + ((len) + SSZA(HKEYDATA, data)) +#define HKEYDATA_PSIZE(len) \ + (HKEYDATA_SIZE(len) + sizeof(db_indx_t)) + +/* Put a HKEYDATA item at the location referenced by a page entry. */ +#define PUT_HKEYDATA(pe, kd, len, type) { \ + ((HKEYDATA *)pe)->type = type; \ + memcpy((u_int8_t *)pe + sizeof(u_int8_t), kd, len); \ +} + +/* + * Macros the describe the page layout in terms of key-data pairs. + */ +#define H_NUMPAIRS(pg) (NUM_ENT(pg) / 2) +#define H_KEYINDEX(indx) (indx) +#define H_DATAINDEX(indx) ((indx) + 1) +#define H_PAIRKEY(dbp, pg, indx) P_ENTRY(dbp, pg, H_KEYINDEX(indx)) +#define H_PAIRDATA(dbp, pg, indx) P_ENTRY(dbp, pg, H_DATAINDEX(indx)) +#define H_PAIRSIZE(dbp, pg, psize, indx) \ + (LEN_HITEM(dbp, pg, psize, H_KEYINDEX(indx)) + \ + LEN_HITEM(dbp, pg, psize, H_DATAINDEX(indx))) +#define LEN_HDATA(dbp, p, psize, indx) \ + LEN_HKEYDATA(dbp, p, psize, H_DATAINDEX(indx)) +#define LEN_HKEY(dbp, p, psize, indx) \ + LEN_HKEYDATA(dbp, p, psize, H_KEYINDEX(indx)) + +/* + * The third type is the H_OFFPAGE, represented by the HOFFPAGE structure: + */ +typedef struct _hoffpage { + u_int8_t type; /* 00: Page type and delete flag. */ + u_int8_t unused[3]; /* 01-03: Padding, unused. */ + db_pgno_t pgno; /* 04-07: Offpage page number. */ + u_int32_t tlen; /* 08-11: Total length of item. */ +} HOFFPAGE; + +#define HOFFPAGE_PGNO(p) (((u_int8_t *)p) + SSZ(HOFFPAGE, pgno)) +#define HOFFPAGE_TLEN(p) (((u_int8_t *)p) + SSZ(HOFFPAGE, tlen)) + +/* + * Page space required to add a new HOFFPAGE item to the page, with and + * without the index value. + */ +#define HOFFPAGE_SIZE (sizeof(HOFFPAGE)) +#define HOFFPAGE_PSIZE (HOFFPAGE_SIZE + sizeof(db_indx_t)) + +/* + * The fourth type is H_OFFDUP represented by the HOFFDUP structure: + */ +typedef struct _hoffdup { + u_int8_t type; /* 00: Page type and delete flag. */ + u_int8_t unused[3]; /* 01-03: Padding, unused. */ + db_pgno_t pgno; /* 04-07: Offpage page number. */ +} HOFFDUP; +#define HOFFDUP_PGNO(p) (((u_int8_t *)p) + SSZ(HOFFDUP, pgno)) + +/* + * Page space required to add a new HOFFDUP item to the page, with and + * without the index value. + */ +#define HOFFDUP_SIZE (sizeof(HOFFDUP)) + +/************************************************************************ + BTREE PAGE LAYOUT + ************************************************************************/ + +/* Each index references a group of bytes on the page. */ +#define B_KEYDATA 1 /* Key/data item. */ +#define B_DUPLICATE 2 /* Duplicate key/data item. */ +#define B_OVERFLOW 3 /* Overflow key/data item. */ + +/* + * We have to store a deleted entry flag in the page. The reason is complex, + * but the simple version is that we can't delete on-page items referenced by + * a cursor -- the return order of subsequent insertions might be wrong. The + * delete flag is an overload of the top bit of the type byte. + */ +#define B_DELETE (0x80) +#define B_DCLR(t) (t) &= ~B_DELETE +#define B_DSET(t) (t) |= B_DELETE +#define B_DISSET(t) ((t) & B_DELETE) + +#define B_TYPE(t) ((t) & ~B_DELETE) +#define B_TSET(t, type, deleted) { \ + (t) = (type); \ + if (deleted) \ + B_DSET(t); \ +} + +/* + * The first type is B_KEYDATA, represented by the BKEYDATA structure: + */ +typedef struct _bkeydata { + db_indx_t len; /* 00-01: Key/data item length. */ + u_int8_t type; /* 02: Page type AND DELETE FLAG. */ + u_int8_t data[1]; /* Variable length key/data item. */ +} BKEYDATA; + +/* Get a BKEYDATA item for a specific index. */ +#define GET_BKEYDATA(dbp, pg, indx) \ + ((BKEYDATA *)P_ENTRY(dbp, pg, indx)) + +/* + * Page space required to add a new BKEYDATA item to the page, with and + * without the index value. The (u_int16_t) cast avoids warnings: DB_ALIGN + * casts to uintmax_t, the cast converts it to a small integral type so we + * don't get complaints when we assign the final result to an integral type + * smaller than uintmax_t. + */ +#define BKEYDATA_SIZE(len) \ + (u_int16_t)DB_ALIGN((len) + SSZA(BKEYDATA, data), sizeof(u_int32_t)) +#define BKEYDATA_PSIZE(len) \ + (BKEYDATA_SIZE(len) + sizeof(db_indx_t)) + +/* + * The second and third types are B_DUPLICATE and B_OVERFLOW, represented + * by the BOVERFLOW structure. + */ +typedef struct _boverflow { + db_indx_t unused1; /* 00-01: Padding, unused. */ + u_int8_t type; /* 02: Page type AND DELETE FLAG. */ + u_int8_t unused2; /* 03: Padding, unused. */ + db_pgno_t pgno; /* 04-07: Next page number. */ + u_int32_t tlen; /* 08-11: Total length of item. */ +} BOVERFLOW; + +/* Get a BOVERFLOW item for a specific index. */ +#define GET_BOVERFLOW(dbp, pg, indx) \ + ((BOVERFLOW *)P_ENTRY(dbp, pg, indx)) + +/* + * Page space required to add a new BOVERFLOW item to the page, with and + * without the index value. + */ +#define BOVERFLOW_SIZE \ + ((u_int16_t)DB_ALIGN(sizeof(BOVERFLOW), sizeof(u_int32_t))) +#define BOVERFLOW_PSIZE \ + (BOVERFLOW_SIZE + sizeof(db_indx_t)) + +/* + * Btree leaf and hash page layouts group indices in sets of two, one for the + * key and one for the data. Everything else does it in sets of one to save + * space. Use the following macros so that it's real obvious what's going on. + */ +#define O_INDX 1 +#define P_INDX 2 + +/************************************************************************ + BTREE INTERNAL PAGE LAYOUT + ************************************************************************/ + +/* + * Btree internal entry. + */ +typedef struct _binternal { + db_indx_t len; /* 00-01: Key/data item length. */ + u_int8_t type; /* 02: Page type AND DELETE FLAG. */ + u_int8_t unused; /* 03: Padding, unused. */ + db_pgno_t pgno; /* 04-07: Page number of referenced page. */ + db_recno_t nrecs; /* 08-11: Subtree record count. */ + u_int8_t data[1]; /* Variable length key item. */ +} BINTERNAL; + +/* Get a BINTERNAL item for a specific index. */ +#define GET_BINTERNAL(dbp, pg, indx) \ + ((BINTERNAL *)P_ENTRY(dbp, pg, indx)) + +/* + * Page space required to add a new BINTERNAL item to the page, with and + * without the index value. + */ +#define BINTERNAL_SIZE(len) \ + (u_int16_t)DB_ALIGN((len) + SSZA(BINTERNAL, data), sizeof(u_int32_t)) +#define BINTERNAL_PSIZE(len) \ + (BINTERNAL_SIZE(len) + sizeof(db_indx_t)) + +/************************************************************************ + RECNO INTERNAL PAGE LAYOUT + ************************************************************************/ + +/* + * The recno internal entry. + */ +typedef struct _rinternal { + db_pgno_t pgno; /* 00-03: Page number of referenced page. */ + db_recno_t nrecs; /* 04-07: Subtree record count. */ +} RINTERNAL; + +/* Get a RINTERNAL item for a specific index. */ +#define GET_RINTERNAL(dbp, pg, indx) \ + ((RINTERNAL *)P_ENTRY(dbp, pg, indx)) + +/* + * Page space required to add a new RINTERNAL item to the page, with and + * without the index value. + */ +#define RINTERNAL_SIZE \ + (u_int16_t)DB_ALIGN(sizeof(RINTERNAL), sizeof(u_int32_t)) +#define RINTERNAL_PSIZE \ + (RINTERNAL_SIZE + sizeof(db_indx_t)) + +#if defined(__cplusplus) +} +#endif + +#endif /* !_DB_PAGE_H_ */ diff --git a/lib_dict/bdb/include/db_server_int.h b/lib_dict/bdb/include/db_server_int.h new file mode 100644 index 000000000..eba36efcb --- /dev/null +++ b/lib_dict/bdb/include/db_server_int.h @@ -0,0 +1,148 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2000-2004 + * Sleepycat Software. All rights reserved. + * + * $Id: db_server_int.h,v 1.25 2004/01/28 03:36:02 bostic Exp $ + */ + +#ifndef _DB_SERVER_INT_H_ +#define _DB_SERVER_INT_H_ + +#define DB_SERVER_TIMEOUT 300 /* 5 minutes */ +#define DB_SERVER_MAXTIMEOUT 1200 /* 20 minutes */ +#define DB_SERVER_IDLETIMEOUT 86400 /* 1 day */ + +/* + * Ignore/mask off the following env->open flags: + * Most are illegal for a client to specify as they would control + * server resource usage. We will just ignore them. + * DB_LOCKDOWN + * DB_PRIVATE + * DB_RECOVER + * DB_RECOVER_FATAL + * DB_SYSTEM_MEM + * DB_USE_ENVIRON, DB_USE_ENVIRON_ROOT - handled on client + */ +#define DB_SERVER_FLAGMASK ( \ +DB_LOCKDOWN | DB_PRIVATE | DB_RECOVER | DB_RECOVER_FATAL | \ +DB_SYSTEM_MEM | DB_USE_ENVIRON | DB_USE_ENVIRON_ROOT) + +#define CT_CURSOR 0x001 /* Cursor */ +#define CT_DB 0x002 /* Database */ +#define CT_ENV 0x004 /* Env */ +#define CT_TXN 0x008 /* Txn */ + +#define CT_JOIN 0x10000000 /* Join cursor component */ +#define CT_JOINCUR 0x20000000 /* Join cursor */ + +typedef struct home_entry home_entry; +struct home_entry { + LIST_ENTRY(home_entry) entries; + char *home; + char *dir; + char *name; + char *passwd; +}; + +/* + * Data needed for sharing handles. + * To share an env handle, on the open call, they must have matching + * env flags, and matching set_flags. + * + * To share a db handle on the open call, the db, subdb and flags must + * all be the same. + */ +#define DB_SERVER_ENVFLAGS ( \ +DB_INIT_CDB | DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL | \ +DB_INIT_TXN | DB_JOINENV) + +#define DB_SERVER_DBFLAGS (DB_DIRTY_READ | DB_NOMMAP | DB_RDONLY) +#define DB_SERVER_DBNOSHARE (DB_EXCL | DB_TRUNCATE) + +typedef struct ct_envdata ct_envdata; +typedef struct ct_dbdata ct_dbdata; +struct ct_envdata { + u_int32_t envflags; + u_int32_t onflags; + u_int32_t offflags; + home_entry *home; +}; + +struct ct_dbdata { + u_int32_t dbflags; + u_int32_t setflags; + char *db; + char *subdb; + DBTYPE type; +}; + +/* + * We maintain an activity timestamp for each handle. However, we + * set it to point, possibly to the ct_active field of its own handle + * or it may point to the ct_active field of a parent. In the case + * of nested transactions and any cursors within transactions it must + * point to the ct_active field of the ultimate parent of the transaction + * no matter how deeply it is nested. + */ +typedef struct ct_entry ct_entry; +struct ct_entry { + LIST_ENTRY(ct_entry) entries; /* List of entries */ + union { +#ifdef __cplusplus + DbEnv *envp; /* H_ENV */ + DbTxn *txnp; /* H_TXN */ + Db *dbp; /* H_DB */ + Dbc *dbc; /* H_CURSOR */ +#else + DB_ENV *envp; /* H_ENV */ + DB_TXN *txnp; /* H_TXN */ + DB *dbp; /* H_DB */ + DBC *dbc; /* H_CURSOR */ +#endif + void *anyp; + } handle_u; + union { /* Private data per type */ + ct_envdata envdp; /* Env info */ + ct_dbdata dbdp; /* Db info */ + } private_u; + long ct_id; /* Client ID */ + long *ct_activep; /* Activity timestamp pointer*/ + long *ct_origp; /* Original timestamp pointer*/ + long ct_active; /* Activity timestamp */ + long ct_timeout; /* Resource timeout */ + long ct_idle; /* Idle timeout */ + u_int32_t ct_refcount; /* Ref count for sharing */ + u_int32_t ct_type; /* This entry's type */ + struct ct_entry *ct_parent; /* Its parent */ + struct ct_entry *ct_envparent; /* Its environment */ +}; + +#define ct_envp handle_u.envp +#define ct_txnp handle_u.txnp +#define ct_dbp handle_u.dbp +#define ct_dbc handle_u.dbc +#define ct_anyp handle_u.anyp + +#define ct_envdp private_u.envdp +#define ct_dbdp private_u.dbdp + +extern int __dbsrv_verbose; + +/* + * Get ctp and activate it. + * Assumes local variable 'replyp'. + * NOTE: May 'return' from macro. + */ +#define ACTIVATE_CTP(ctp, id, type) { \ + (ctp) = get_tableent(id); \ + if ((ctp) == NULL) { \ + replyp->status = DB_NOSERVER_ID;\ + return; \ + } \ + DB_ASSERT((ctp)->ct_type & (type)); \ + __dbsrv_active(ctp); \ +} + +#endif /* !_DB_SERVER_INT_H_ */ diff --git a/lib_dict/bdb/include/db_shash.h b/lib_dict/bdb/include/db_shash.h new file mode 100644 index 000000000..51277e5e0 --- /dev/null +++ b/lib_dict/bdb/include/db_shash.h @@ -0,0 +1,81 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996-2004 + * Sleepycat Software. All rights reserved. + * + * $Id: db_shash.h,v 11.13 2004/01/28 03:36:02 bostic Exp $ + */ + +#ifndef _DB_SHASH_H_ +#define _DB_SHASH_H_ + +/* Hash Headers */ +typedef SH_TAILQ_HEAD(__hash_head) DB_HASHTAB; + +/* + * HASHLOOKUP -- + * + * Look up something in a shared memory hash table. The "elt" argument + * should be a key, and cmp_func must know how to compare a key to whatever + * structure it is that appears in the hash table. The comparison function + * + * begin: address of the beginning of the hash table. + * ndx: index into table for this item. + * type: the structure type of the elements that are linked in each bucket. + * field: the name of the field by which the "type" structures are linked. + * elt: the item for which we are searching in the hash table. + * res: the variable into which we'll store the element if we find it. + * cmp: called as: cmp(lookup_elt, table_elt). + * + * If the element is not in the hash table, this macro exits with res set + * to NULL. + */ +#define HASHLOOKUP(begin, ndx, type, field, elt, res, cmp) do { \ + DB_HASHTAB *__bucket; \ + \ + __bucket = &begin[ndx]; \ + for (res = SH_TAILQ_FIRST(__bucket, type); \ + res != NULL; res = SH_TAILQ_NEXT(res, field, type)) \ + if (cmp(elt, res)) \ + break; \ +} while (0) + +/* + * HASHINSERT -- + * + * Insert a new entry into the hash table. This assumes that you already + * have the bucket locked and that lookup has failed; don't call it if you + * haven't already called HASHLOOKUP. If you do, you could get duplicate + * entries. + * + * begin: the beginning address of the hash table. + * ndx: the index for this element. + * type: the structure type of the elements that are linked in each bucket. + * field: the name of the field by which the "type" structures are linked. + * elt: the item to be inserted. + */ +#define HASHINSERT(begin, ndx, type, field, elt) do { \ + DB_HASHTAB *__bucket; \ + \ + __bucket = &begin[ndx]; \ + SH_TAILQ_INSERT_HEAD(__bucket, elt, field, type); \ +} while (0) + +/* + * HASHREMOVE_EL -- + * Given the object "obj" in the table, remove it. + * + * begin: address of the beginning of the hash table. + * ndx: index into hash table of where this element belongs. + * type: the structure type of the elements that are linked in each bucket. + * field: the name of the field by which the "type" structures are linked. + * obj: the object in the table that we with to delete. + */ +#define HASHREMOVE_EL(begin, ndx, type, field, obj) { \ + DB_HASHTAB *__bucket; \ + \ + __bucket = &begin[ndx]; \ + SH_TAILQ_REMOVE(__bucket, obj, field, type); \ +} +#endif /* !_DB_SHASH_H_ */ diff --git a/lib_dict/bdb/include/db_swap.h b/lib_dict/bdb/include/db_swap.h new file mode 100644 index 000000000..25391ce59 --- /dev/null +++ b/lib_dict/bdb/include/db_swap.h @@ -0,0 +1,170 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996-2004 + * Sleepycat Software. All rights reserved. + */ +/* + * Copyright (c) 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: db_swap.h,v 11.11 2004/01/28 03:36:02 bostic Exp $ + */ + +#ifndef _DB_SWAP_H_ +#define _DB_SWAP_H_ + +/* + * Little endian <==> big endian 64-bit swap macros. + * M_64_SWAP swap a memory location + * P_64_COPY copy potentially unaligned 4 byte quantities + * P_64_SWAP swap a referenced memory location + */ +#undef M_64_SWAP +#define M_64_SWAP(a) { \ + u_int64_t _tmp; \ + _tmp = a; \ + ((u_int8_t *)&a)[0] = ((u_int8_t *)&_tmp)[7]; \ + ((u_int8_t *)&a)[1] = ((u_int8_t *)&_tmp)[6]; \ + ((u_int8_t *)&a)[2] = ((u_int8_t *)&_tmp)[5]; \ + ((u_int8_t *)&a)[3] = ((u_int8_t *)&_tmp)[4]; \ + ((u_int8_t *)&a)[4] = ((u_int8_t *)&_tmp)[3]; \ + ((u_int8_t *)&a)[5] = ((u_int8_t *)&_tmp)[2]; \ + ((u_int8_t *)&a)[6] = ((u_int8_t *)&_tmp)[1]; \ + ((u_int8_t *)&a)[7] = ((u_int8_t *)&_tmp)[0]; \ +} +#undef P_64_COPY +#define P_64_COPY(a, b) { \ + ((u_int8_t *)b)[0] = ((u_int8_t *)a)[0]; \ + ((u_int8_t *)b)[1] = ((u_int8_t *)a)[1]; \ + ((u_int8_t *)b)[2] = ((u_int8_t *)a)[2]; \ + ((u_int8_t *)b)[3] = ((u_int8_t *)a)[3]; \ + ((u_int8_t *)b)[4] = ((u_int8_t *)a)[4]; \ + ((u_int8_t *)b)[5] = ((u_int8_t *)a)[5]; \ + ((u_int8_t *)b)[6] = ((u_int8_t *)a)[6]; \ + ((u_int8_t *)b)[7] = ((u_int8_t *)a)[7]; \ +} +#undef P_64_SWAP +#define P_64_SWAP(a) { \ + u_int64_t _tmp; \ + P_64_COPY(a, &_tmp); \ + ((u_int8_t *)a)[0] = ((u_int8_t *)&_tmp)[7]; \ + ((u_int8_t *)a)[1] = ((u_int8_t *)&_tmp)[6]; \ + ((u_int8_t *)a)[2] = ((u_int8_t *)&_tmp)[5]; \ + ((u_int8_t *)a)[3] = ((u_int8_t *)&_tmp)[4]; \ + ((u_int8_t *)a)[4] = ((u_int8_t *)&_tmp)[3]; \ + ((u_int8_t *)a)[5] = ((u_int8_t *)&_tmp)[2]; \ + ((u_int8_t *)a)[6] = ((u_int8_t *)&_tmp)[1]; \ + ((u_int8_t *)a)[7] = ((u_int8_t *)&_tmp)[0]; \ +} + +/* + * Little endian <==> big endian 32-bit swap macros. + * M_32_SWAP swap a memory location + * P_32_COPY copy potentially unaligned 4 byte quantities + * P_32_SWAP swap a referenced memory location + */ +#undef M_32_SWAP +#define M_32_SWAP(a) { \ + u_int32_t _tmp; \ + _tmp = a; \ + ((u_int8_t *)&a)[0] = ((u_int8_t *)&_tmp)[3]; \ + ((u_int8_t *)&a)[1] = ((u_int8_t *)&_tmp)[2]; \ + ((u_int8_t *)&a)[2] = ((u_int8_t *)&_tmp)[1]; \ + ((u_int8_t *)&a)[3] = ((u_int8_t *)&_tmp)[0]; \ +} +#undef P_32_COPY +#define P_32_COPY(a, b) { \ + ((u_int8_t *)b)[0] = ((u_int8_t *)a)[0]; \ + ((u_int8_t *)b)[1] = ((u_int8_t *)a)[1]; \ + ((u_int8_t *)b)[2] = ((u_int8_t *)a)[2]; \ + ((u_int8_t *)b)[3] = ((u_int8_t *)a)[3]; \ +} +#undef P_32_SWAP +#define P_32_SWAP(a) { \ + u_int32_t _tmp; \ + P_32_COPY(a, &_tmp); \ + ((u_int8_t *)a)[0] = ((u_int8_t *)&_tmp)[3]; \ + ((u_int8_t *)a)[1] = ((u_int8_t *)&_tmp)[2]; \ + ((u_int8_t *)a)[2] = ((u_int8_t *)&_tmp)[1]; \ + ((u_int8_t *)a)[3] = ((u_int8_t *)&_tmp)[0]; \ +} + +/* + * Little endian <==> big endian 16-bit swap macros. + * M_16_SWAP swap a memory location + * P_16_COPY copy potentially unaligned 2 byte quantities + * P_16_SWAP swap a referenced memory location + */ +#undef M_16_SWAP +#define M_16_SWAP(a) { \ + u_int16_t _tmp; \ + _tmp = (u_int16_t)a; \ + ((u_int8_t *)&a)[0] = ((u_int8_t *)&_tmp)[1]; \ + ((u_int8_t *)&a)[1] = ((u_int8_t *)&_tmp)[0]; \ +} +#undef P_16_COPY +#define P_16_COPY(a, b) { \ + ((u_int8_t *)b)[0] = ((u_int8_t *)a)[0]; \ + ((u_int8_t *)b)[1] = ((u_int8_t *)a)[1]; \ +} +#undef P_16_SWAP +#define P_16_SWAP(a) { \ + u_int16_t _tmp; \ + P_16_COPY(a, &_tmp); \ + ((u_int8_t *)a)[0] = ((u_int8_t *)&_tmp)[1]; \ + ((u_int8_t *)a)[1] = ((u_int8_t *)&_tmp)[0]; \ +} + +#undef SWAP32 +#define SWAP32(p) { \ + P_32_SWAP(p); \ + (p) += sizeof(u_int32_t); \ +} +#undef SWAP16 +#define SWAP16(p) { \ + P_16_SWAP(p); \ + (p) += sizeof(u_int16_t); \ +} + +/* + * Berkeley DB has local versions of htonl() and ntohl() that operate on + * pointers to the right size memory locations; the portability magic for + * finding the real system functions isn't worth the effort. + */ +#undef DB_HTONL +#define DB_HTONL(p) do { \ + if (!__db_isbigendian()) \ + P_32_SWAP(p); \ +} while (0) +#undef DB_NTOHL +#define DB_NTOHL(p) do { \ + if (!__db_isbigendian()) \ + P_32_SWAP(p); \ +} while (0) + +#endif /* !_DB_SWAP_H_ */ diff --git a/lib_dict/bdb/include/db_upgrade.h b/lib_dict/bdb/include/db_upgrade.h new file mode 100644 index 000000000..e7ac0bc96 --- /dev/null +++ b/lib_dict/bdb/include/db_upgrade.h @@ -0,0 +1,242 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996-2004 + * Sleepycat Software. All rights reserved. + * + * $Id: db_upgrade.h,v 1.12 2004/01/28 03:36:02 bostic Exp $ + */ + +#ifndef _DB_UPGRADE_H_ +#define _DB_UPGRADE_H_ + +/* + * This file defines the metadata pages from the previous release. + * These structures are only used to upgrade old versions of databases. + */ + +/* Structures from the 3.1 release */ +typedef struct _dbmeta31 { + DB_LSN lsn; /* 00-07: LSN. */ + db_pgno_t pgno; /* 08-11: Current page number. */ + u_int32_t magic; /* 12-15: Magic number. */ + u_int32_t version; /* 16-19: Version. */ + u_int32_t pagesize; /* 20-23: Pagesize. */ + u_int8_t unused1[1]; /* 24: Unused. */ + u_int8_t type; /* 25: Page type. */ + u_int8_t unused2[2]; /* 26-27: Unused. */ + u_int32_t free; /* 28-31: Free list page number. */ + DB_LSN unused3; /* 36-39: Unused. */ + u_int32_t key_count; /* 40-43: Cached key count. */ + u_int32_t record_count; /* 44-47: Cached record count. */ + u_int32_t flags; /* 48-51: Flags: unique to each AM. */ + /* 52-71: Unique file ID. */ + u_int8_t uid[DB_FILE_ID_LEN]; +} DBMETA31; + +typedef struct _btmeta31 { + DBMETA31 dbmeta; /* 00-71: Generic meta-data header. */ + + u_int32_t maxkey; /* 72-75: Btree: Maxkey. */ + u_int32_t minkey; /* 76-79: Btree: Minkey. */ + u_int32_t re_len; /* 80-83: Recno: fixed-length record length. */ + u_int32_t re_pad; /* 84-87: Recno: fixed-length record pad. */ + u_int32_t root; /* 88-92: Root page. */ + + /* + * Minimum page size is 128. + */ +} BTMETA31; + +/************************************************************************ + HASH METADATA PAGE LAYOUT + ************************************************************************/ +typedef struct _hashmeta31 { + DBMETA31 dbmeta; /* 00-71: Generic meta-data page header. */ + + u_int32_t max_bucket; /* 72-75: ID of Maximum bucket in use */ + u_int32_t high_mask; /* 76-79: Modulo mask into table */ + u_int32_t low_mask; /* 80-83: Modulo mask into table lower half */ + u_int32_t ffactor; /* 84-87: Fill factor */ + u_int32_t nelem; /* 88-91: Number of keys in hash table */ + u_int32_t h_charkey; /* 92-95: Value of hash(CHARKEY) */ +#define NCACHED 32 /* number of spare points */ + /* 96-223: Spare pages for overflow */ + u_int32_t spares[NCACHED]; + + /* + * Minimum page size is 256. + */ +} HMETA31; + +/* + * QAM Meta data page structure + * + */ +typedef struct _qmeta31 { + DBMETA31 dbmeta; /* 00-71: Generic meta-data header. */ + + u_int32_t start; /* 72-75: Start offset. */ + u_int32_t first_recno; /* 76-79: First not deleted record. */ + u_int32_t cur_recno; /* 80-83: Last recno allocated. */ + u_int32_t re_len; /* 84-87: Fixed-length record length. */ + u_int32_t re_pad; /* 88-91: Fixed-length record pad. */ + u_int32_t rec_page; /* 92-95: Records Per Page. */ + + /* + * Minimum page size is 128. + */ +} QMETA31; +/* Structures from the 3.2 release */ +typedef struct _qmeta32 { + DBMETA31 dbmeta; /* 00-71: Generic meta-data header. */ + + u_int32_t first_recno; /* 72-75: First not deleted record. */ + u_int32_t cur_recno; /* 76-79: Last recno allocated. */ + u_int32_t re_len; /* 80-83: Fixed-length record length. */ + u_int32_t re_pad; /* 84-87: Fixed-length record pad. */ + u_int32_t rec_page; /* 88-91: Records Per Page. */ + u_int32_t page_ext; /* 92-95: Pages per extent */ + + /* + * Minimum page size is 128. + */ +} QMETA32; + +/* Structures from the 3.0 release */ + +typedef struct _dbmeta30 { + DB_LSN lsn; /* 00-07: LSN. */ + db_pgno_t pgno; /* 08-11: Current page number. */ + u_int32_t magic; /* 12-15: Magic number. */ + u_int32_t version; /* 16-19: Version. */ + u_int32_t pagesize; /* 20-23: Pagesize. */ + u_int8_t unused1[1]; /* 24: Unused. */ + u_int8_t type; /* 25: Page type. */ + u_int8_t unused2[2]; /* 26-27: Unused. */ + u_int32_t free; /* 28-31: Free list page number. */ + u_int32_t flags; /* 32-35: Flags: unique to each AM. */ + /* 36-55: Unique file ID. */ + u_int8_t uid[DB_FILE_ID_LEN]; +} DBMETA30; + +/************************************************************************ + BTREE METADATA PAGE LAYOUT + ************************************************************************/ +typedef struct _btmeta30 { + DBMETA30 dbmeta; /* 00-55: Generic meta-data header. */ + + u_int32_t maxkey; /* 56-59: Btree: Maxkey. */ + u_int32_t minkey; /* 60-63: Btree: Minkey. */ + u_int32_t re_len; /* 64-67: Recno: fixed-length record length. */ + u_int32_t re_pad; /* 68-71: Recno: fixed-length record pad. */ + u_int32_t root; /* 72-75: Root page. */ + + /* + * Minimum page size is 128. + */ +} BTMETA30; + +/************************************************************************ + HASH METADATA PAGE LAYOUT + ************************************************************************/ +typedef struct _hashmeta30 { + DBMETA30 dbmeta; /* 00-55: Generic meta-data page header. */ + + u_int32_t max_bucket; /* 56-59: ID of Maximum bucket in use */ + u_int32_t high_mask; /* 60-63: Modulo mask into table */ + u_int32_t low_mask; /* 64-67: Modulo mask into table lower half */ + u_int32_t ffactor; /* 68-71: Fill factor */ + u_int32_t nelem; /* 72-75: Number of keys in hash table */ + u_int32_t h_charkey; /* 76-79: Value of hash(CHARKEY) */ +#define NCACHED30 32 /* number of spare points */ + /* 80-207: Spare pages for overflow */ + u_int32_t spares[NCACHED30]; + + /* + * Minimum page size is 256. + */ +} HMETA30; + +/************************************************************************ + QUEUE METADATA PAGE LAYOUT + ************************************************************************/ +/* + * QAM Meta data page structure + * + */ +typedef struct _qmeta30 { + DBMETA30 dbmeta; /* 00-55: Generic meta-data header. */ + + u_int32_t start; /* 56-59: Start offset. */ + u_int32_t first_recno; /* 60-63: First not deleted record. */ + u_int32_t cur_recno; /* 64-67: Last recno allocated. */ + u_int32_t re_len; /* 68-71: Fixed-length record length. */ + u_int32_t re_pad; /* 72-75: Fixed-length record pad. */ + u_int32_t rec_page; /* 76-79: Records Per Page. */ + + /* + * Minimum page size is 128. + */ +} QMETA30; + +/* Structures from Release 2.x */ + +/************************************************************************ + BTREE METADATA PAGE LAYOUT + ************************************************************************/ + +/* + * Btree metadata page layout: + */ +typedef struct _btmeta2X { + DB_LSN lsn; /* 00-07: LSN. */ + db_pgno_t pgno; /* 08-11: Current page number. */ + u_int32_t magic; /* 12-15: Magic number. */ + u_int32_t version; /* 16-19: Version. */ + u_int32_t pagesize; /* 20-23: Pagesize. */ + u_int32_t maxkey; /* 24-27: Btree: Maxkey. */ + u_int32_t minkey; /* 28-31: Btree: Minkey. */ + u_int32_t free; /* 32-35: Free list page number. */ + u_int32_t flags; /* 36-39: Flags. */ + u_int32_t re_len; /* 40-43: Recno: fixed-length record length. */ + u_int32_t re_pad; /* 44-47: Recno: fixed-length record pad. */ + /* 48-67: Unique file ID. */ + u_int8_t uid[DB_FILE_ID_LEN]; +} BTMETA2X; + +/************************************************************************ + HASH METADATA PAGE LAYOUT + ************************************************************************/ + +/* + * Hash metadata page layout: + */ +/* Hash Table Information */ +typedef struct hashhdr { /* Disk resident portion */ + DB_LSN lsn; /* 00-07: LSN of the header page */ + db_pgno_t pgno; /* 08-11: Page number (btree compatibility). */ + u_int32_t magic; /* 12-15: Magic NO for hash tables */ + u_int32_t version; /* 16-19: Version ID */ + u_int32_t pagesize; /* 20-23: Bucket/Page Size */ + u_int32_t ovfl_point; /* 24-27: Overflow page allocation location */ + u_int32_t last_freed; /* 28-31: Last freed overflow page pgno */ + u_int32_t max_bucket; /* 32-35: ID of Maximum bucket in use */ + u_int32_t high_mask; /* 36-39: Modulo mask into table */ + u_int32_t low_mask; /* 40-43: Modulo mask into table lower half */ + u_int32_t ffactor; /* 44-47: Fill factor */ + u_int32_t nelem; /* 48-51: Number of keys in hash table */ + u_int32_t h_charkey; /* 52-55: Value of hash(CHARKEY) */ + u_int32_t flags; /* 56-59: Allow duplicates. */ +#define NCACHED2X 32 /* number of spare points */ + /* 60-187: Spare pages for overflow */ + u_int32_t spares[NCACHED2X]; + /* 188-207: Unique file ID. */ + u_int8_t uid[DB_FILE_ID_LEN]; + + /* + * Minimum page size is 256. + */ +} HASHHDR; + +#endif /* !_DB_UPGRADE_H_ */ diff --git a/lib_dict/bdb/include/db_verify.h b/lib_dict/bdb/include/db_verify.h new file mode 100644 index 000000000..528ba8f04 --- /dev/null +++ b/lib_dict/bdb/include/db_verify.h @@ -0,0 +1,216 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1999-2004 + * Sleepycat Software. All rights reserved. + * + * $Id: db_verify.h,v 1.34 2004/05/20 14:34:12 bostic Exp $ + */ + +#ifndef _DB_VERIFY_H_ +#define _DB_VERIFY_H_ + +/* + * Structures and macros for the storage and retrieval of all information + * needed for inter-page verification of a database. + */ + +/* + * EPRINT is the macro for error printing. Takes as an arg the arg set + * for DB->err. + */ +#define EPRINT(x) do { \ + if (!LF_ISSET(DB_SALVAGE)) \ + __db_err x; \ +} while (0) + +/* For fatal type errors--i.e., verifier bugs. */ +#define TYPE_ERR_PRINT(dbenv, func, pgno, ptype) \ + EPRINT(((dbenv), \ + "Page %lu: %s called on nonsensical page of type %lu", \ + (u_long)(pgno), (func), (u_long)(ptype))); + +/* Complain about a totally zeroed page where we don't expect one. */ +#define ZEROPG_ERR_PRINT(dbenv, pgno, str) do { \ + EPRINT(((dbenv), "Page %lu: %s is of inappropriate type %lu", \ + (u_long)(pgno), str, (u_long)P_INVALID)); \ + EPRINT(((dbenv), "Page %lu: totally zeroed page", \ + (u_long)(pgno))); \ +} while (0) + +/* + * Note that 0 is, in general, a valid pgno, despite equalling PGNO_INVALID; + * we have to test it separately where it's not appropriate. + */ +#define IS_VALID_PGNO(x) ((x) <= vdp->last_pgno) + +/* + * Flags understood by the btree structure checks (esp. __bam_vrfy_subtree). + * These share the same space as the global flags to __db_verify, and must not + * dip below 0x00010000. + */ +#define ST_DUPOK 0x00010000 /* Duplicates are acceptable. */ +#define ST_DUPSET 0x00020000 /* Subtree is in a duplicate tree. */ +#define ST_DUPSORT 0x00040000 /* Duplicates are sorted. */ +#define ST_IS_RECNO 0x00080000 /* Subtree is a recno. */ +#define ST_OVFL_LEAF 0x00100000 /* Overflow reffed from leaf page. */ +#define ST_RECNUM 0x00200000 /* Subtree has record numbering on. */ +#define ST_RELEN 0x00400000 /* Subtree has fixed-length records. */ +#define ST_TOPLEVEL 0x00800000 /* Subtree == entire tree */ + +/* + * Flags understood by __bam_salvage and __db_salvage. These need not share + * the same space with the __bam_vrfy_subtree flags, but must share with + * __db_verify. + */ +#define SA_SKIPFIRSTKEY 0x00080000 + +/* + * VRFY_DBINFO is the fundamental structure; it either represents the database + * of subdatabases, or the sole database if there are no subdatabases. + */ +struct __vrfy_dbinfo { + /* Info about this database in particular. */ + DBTYPE type; + + /* List of subdatabase meta pages, if any. */ + LIST_HEAD(__subdbs, __vrfy_childinfo) subdbs; + + /* File-global info--stores VRFY_PAGEINFOs for each page. */ + DB *pgdbp; + + /* Child database--stores VRFY_CHILDINFOs of each page. */ + DB *cdbp; + + /* Page info structures currently in use. */ + LIST_HEAD(__activepips, __vrfy_pageinfo) activepips; + + /* + * DB we use to keep track of which pages are linked somehow + * during verification. 0 is the default, "unseen"; 1 is seen. + */ + DB *pgset; + + /* + * This is a database we use during salvaging to keep track of which + * overflow and dup pages we need to come back to at the end and print + * with key "UNKNOWN". Pages which print with a good key get set + * to SALVAGE_IGNORE; others get set, as appropriate, to SALVAGE_LDUP, + * SALVAGE_LRECNODUP, SALVAGE_OVERFLOW for normal db overflow pages, + * and SALVAGE_BTREE, SALVAGE_LRECNO, and SALVAGE_HASH for subdb + * pages. + */ +#define SALVAGE_INVALID 0 +#define SALVAGE_IGNORE 1 +#define SALVAGE_LDUP 2 +#define SALVAGE_LRECNODUP 3 +#define SALVAGE_OVERFLOW 4 +#define SALVAGE_LBTREE 5 +#define SALVAGE_HASH 6 +#define SALVAGE_LRECNO 7 + DB *salvage_pages; + + db_pgno_t last_pgno; + db_pgno_t pgs_remaining; /* For dbp->db_feedback(). */ + + /* + * These are used during __bam_vrfy_subtree to keep track, while + * walking up and down the Btree structure, of the prev- and next-page + * chain of leaf pages and verify that it's intact. Also, make sure + * that this chain contains pages of only one type. + */ + db_pgno_t prev_pgno; + db_pgno_t next_pgno; + u_int8_t leaf_type; + + /* Queue needs these to verify data pages in the first pass. */ + u_int32_t re_len; + u_int32_t rec_page; + u_int32_t page_ext; + u_int32_t first_recno; + u_int32_t last_recno; + int nextents; + db_pgno_t *extents; + +#define SALVAGE_PRINTABLE 0x01 /* Output printable chars literally. */ +#define SALVAGE_PRINTHEADER 0x02 /* Print the unknown-key header. */ +#define SALVAGE_PRINTFOOTER 0x04 /* Print the unknown-key footer. */ +#define VRFY_LEAFCHAIN_BROKEN 0x08 /* Lost one or more Btree leaf pgs. */ +#define VRFY_QMETA_SET 0x10 /* We've seen a QUEUE meta page and + set things up for it. */ + u_int32_t flags; +}; /* VRFY_DBINFO */ + +/* + * The amount of state information we need per-page is small enough that + * it's not worth the trouble to define separate structures for each + * possible type of page, and since we're doing verification with these we + * have to be open to the possibility that page N will be of a completely + * unexpected type anyway. So we define one structure here with all the + * info we need for inter-page verification. + */ +struct __vrfy_pageinfo { + u_int8_t type; + u_int8_t bt_level; + u_int8_t unused1; + u_int8_t unused2; + db_pgno_t pgno; + db_pgno_t prev_pgno; + db_pgno_t next_pgno; + + /* meta pages */ + db_pgno_t root; + db_pgno_t free; /* Free list head. */ + + db_indx_t entries; /* Actual number of entries. */ + u_int16_t unused; + db_recno_t rec_cnt; /* Record count. */ + u_int32_t re_len; /* Record length. */ + u_int32_t bt_minkey; + u_int32_t bt_maxkey; + u_int32_t h_ffactor; + u_int32_t h_nelem; + + /* overflow pages */ + /* + * Note that refcount is the refcount for an overflow page; pi_refcount + * is this structure's own refcount! + */ + u_int32_t refcount; + u_int32_t olen; + +#define VRFY_DUPS_UNSORTED 0x0001 /* Have to flag the negative! */ +#define VRFY_HAS_DUPS 0x0002 +#define VRFY_HAS_DUPSORT 0x0004 /* Has the flag set. */ +#define VRFY_HAS_SUBDBS 0x0008 +#define VRFY_HAS_RECNUMS 0x0010 +#define VRFY_INCOMPLETE 0x0020 /* Meta or item order checks incomp. */ +#define VRFY_IS_ALLZEROES 0x0040 /* Hash page we haven't touched? */ +#define VRFY_IS_FIXEDLEN 0x0080 +#define VRFY_IS_RECNO 0x0100 +#define VRFY_IS_RRECNO 0x0200 +#define VRFY_OVFL_LEAFSEEN 0x0400 + u_int32_t flags; + + LIST_ENTRY(__vrfy_pageinfo) links; + u_int32_t pi_refcount; +}; /* VRFY_PAGEINFO */ + +struct __vrfy_childinfo { + /* The following fields are set by the caller of __db_vrfy_childput. */ + db_pgno_t pgno; + +#define V_DUPLICATE 1 /* off-page dup metadata */ +#define V_OVERFLOW 2 /* overflow page */ +#define V_RECNO 3 /* btree internal or leaf page */ + u_int32_t type; + db_recno_t nrecs; /* record count on a btree subtree */ + u_int32_t tlen; /* ovfl. item total size */ + + /* The following field is maintained by __db_vrfy_childput. */ + u_int32_t refcnt; /* # of times parent points to child. */ + + LIST_ENTRY(__vrfy_childinfo) links; +}; /* VRFY_CHILDINFO */ + +#endif /* !_DB_VERIFY_H_ */ diff --git a/lib_dict/bdb/include/dbreg_auto.h b/lib_dict/bdb/include/dbreg_auto.h new file mode 100644 index 000000000..4d7d4a91b --- /dev/null +++ b/lib_dict/bdb/include/dbreg_auto.h @@ -0,0 +1,19 @@ +/* Do not edit: automatically built by gen_rec.awk. */ + +#ifndef __dbreg_AUTO_H +#define __dbreg_AUTO_H +#define DB___dbreg_register 2 +typedef struct ___dbreg_register_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + u_int32_t opcode; + DBT name; + DBT uid; + int32_t fileid; + DBTYPE ftype; + db_pgno_t meta_pgno; + u_int32_t id; +} __dbreg_register_args; + +#endif diff --git a/lib_dict/bdb/include/dbreg_ext.h b/lib_dict/bdb/include/dbreg_ext.h new file mode 100644 index 000000000..5902b9db9 --- /dev/null +++ b/lib_dict/bdb/include/dbreg_ext.h @@ -0,0 +1,39 @@ +/* DO NOT EDIT: automatically built by dist/s_include. */ +#ifndef _dbreg_ext_h_ +#define _dbreg_ext_h_ + +#if defined(__cplusplus) +extern "C" { +#endif + +int __dbreg_setup __P((DB *, const char *, u_int32_t)); +int __dbreg_teardown __P((DB *)); +int __dbreg_new_id __P((DB *, DB_TXN *)); +int __dbreg_get_id __P((DB *, DB_TXN *, int32_t *)); +int __dbreg_assign_id __P((DB *, int32_t)); +int __dbreg_revoke_id __P((DB *, int, int32_t)); +int __dbreg_close_id __P((DB *, DB_TXN *, u_int32_t)); +int __dbreg_register_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t, u_int32_t, const DBT *, const DBT *, int32_t, DBTYPE, db_pgno_t, u_int32_t)); +int __dbreg_register_read __P((DB_ENV *, void *, __dbreg_register_args **)); +int __dbreg_init_recover __P((DB_ENV *, int (***)(DB_ENV *, DBT *, DB_LSN *, db_recops, void *), size_t *)); +int __dbreg_register_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __dbreg_init_print __P((DB_ENV *, int (***)(DB_ENV *, DBT *, DB_LSN *, db_recops, void *), size_t *)); +int __dbreg_register_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +void __dbreg_print_fname __P((DB_ENV *, FNAME *)); +void __dbreg_print_dblist __P((DB_ENV *, u_int32_t)); +int __dbreg_add_dbentry __P((DB_ENV *, DB_LOG *, DB *, int32_t)); +void __dbreg_rem_dbentry __P((DB_LOG *, int32_t)); +int __dbreg_log_files __P((DB_ENV *)); +int __dbreg_close_files __P((DB_ENV *)); +int __dbreg_id_to_db __P((DB_ENV *, DB_TXN *, DB **, int32_t, int)); +int __dbreg_id_to_db_int __P((DB_ENV *, DB_TXN *, DB **, int32_t, int, int)); +int __dbreg_id_to_fname __P((DB_LOG *, int32_t, int, FNAME **)); +int __dbreg_fid_to_fname __P((DB_LOG *, u_int8_t *, int, FNAME **)); +int __dbreg_get_name __P((DB_ENV *, u_int8_t *, char **)); +int __dbreg_do_open __P((DB_ENV *, DB_TXN *, DB_LOG *, u_int8_t *, char *, DBTYPE, int32_t, db_pgno_t, void *, u_int32_t)); +int __dbreg_lazy_id __P((DB *)); + +#if defined(__cplusplus) +} +#endif +#endif /* !_dbreg_ext_h_ */ diff --git a/lib_dict/bdb/include/debug.h b/lib_dict/bdb/include/debug.h new file mode 100644 index 000000000..068c8af2b --- /dev/null +++ b/lib_dict/bdb/include/debug.h @@ -0,0 +1,264 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1998-2004 + * Sleepycat Software. All rights reserved. + * + * $Id: debug.h,v 11.44 2004/09/24 00:43:18 bostic Exp $ + */ + +#ifndef _DB_DEBUG_H_ +#define _DB_DEBUG_H_ + +#if defined(__cplusplus) +extern "C" { +#endif + +/* + * Turn on additional error checking in gcc 3.X. + */ +#if !defined(__GNUC__) || __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) +#define __attribute__(s) +#endif + +/* + * When running with #DIAGNOSTIC defined, we smash memory and do memory + * guarding with a special byte value. + */ +#define CLEAR_BYTE 0xdb +#define GUARD_BYTE 0xdc + +/* + * DB assertions. + * + * Use __STDC__ rather than STDC_HEADERS, the #e construct is ANSI C specific. + */ +#if defined(__STDC__) && defined(DIAGNOSTIC) +#define DB_ASSERT(e) ((e) ? (void)0 : __db_assert(#e, __FILE__, __LINE__)) +#else +#define DB_ASSERT(e) +#endif + +/* + * "Shut that bloody compiler up!" + * + * Unused, or not-used-yet variable. We need to write and then read the + * variable, some compilers are too bloody clever by half. + */ +#define COMPQUIET(n, v) \ + (n) = (v); \ + (n) = (n) + +/* + * Purify and other run-time tools complain about uninitialized reads/writes + * of structure fields whose only purpose is padding, as well as when heap + * memory that was never initialized is written to disk. + */ +#ifdef UMRW +#define UMRW_SET(v) (v) = 0 +#else +#define UMRW_SET(v) +#endif + +/* + * Message handling. Use a macro instead of a function because va_list + * references to variadic arguments cannot be reset to the beginning of the + * variadic argument list (and then rescanned), by functions other than the + * original routine that took the variadic list of arguments. + */ +#if defined(STDC_HEADERS) || defined(__cplusplus) +#define DB_REAL_ERR(env, error, error_set, default_stream, fmt) { \ + va_list ap; \ + \ + /* Call the application's callback function, if specified. */ \ + va_start(ap, fmt); \ + if ((env) != NULL && (env)->db_errcall != NULL) \ + __db_errcall(env, error, error_set, fmt, ap); \ + va_end(ap); \ + \ + /* Write to the application's file descriptor, if specified. */\ + va_start(ap, fmt); \ + if ((env) != NULL && (env)->db_errfile != NULL) \ + __db_errfile(env, error, error_set, fmt, ap); \ + va_end(ap); \ + \ + /* \ + * If we have a default and we didn't do either of the above, \ + * write to the default. \ + */ \ + va_start(ap, fmt); \ + if ((default_stream) && ((env) == NULL || \ + ((env)->db_errcall == NULL && (env)->db_errfile == NULL))) \ + __db_errfile(env, error, error_set, fmt, ap); \ + va_end(ap); \ +} +#else +#define DB_REAL_ERR(env, error, error_set, default_stream, fmt) { \ + va_list ap; \ + \ + /* Call the application's callback function, if specified. */ \ + va_start(ap); \ + if ((env) != NULL && (env)->db_errcall != NULL) \ + __db_errcall(env, error, error_set, fmt, ap); \ + va_end(ap); \ + \ + /* Write to the application's file descriptor, if specified. */\ + va_start(ap); \ + if ((env) != NULL && (env)->db_errfile != NULL) \ + __db_errfile(env, error, error_set, fmt, ap); \ + va_end(ap); \ + \ + /* \ + * If we have a default and we didn't do either of the above, \ + * write to the default. \ + */ \ + va_start(ap); \ + if ((default_stream) && ((env) == NULL || \ + ((env)->db_errcall == NULL && (env)->db_errfile == NULL))) \ + __db_errfile(env, error, error_set, fmt, ap); \ + va_end(ap); \ +} +#endif +#if defined(STDC_HEADERS) || defined(__cplusplus) +#define DB_REAL_MSG(env, fmt) { \ + va_list ap; \ + \ + /* Call the application's callback function, if specified. */ \ + va_start(ap, fmt); \ + if ((env) != NULL && (env)->db_msgcall != NULL) \ + __db_msgcall(env, fmt, ap); \ + va_end(ap); \ + \ + /* \ + * If the application specified a file descriptor, or we wrote \ + * to neither the application's callback routine or to its file \ + * descriptor, write to stdout. \ + */ \ + va_start(ap, fmt); \ + if ((env) == NULL || \ + (env)->db_msgfile != NULL || (env)->db_msgcall == NULL) { \ + __db_msgfile(env, fmt, ap); \ + } \ + va_end(ap); \ +} +#else +#define DB_REAL_MSG(env, fmt) { \ + va_list ap; \ + \ + /* Call the application's callback function, if specified. */ \ + va_start(ap); \ + if ((env) != NULL && (env)->db_msgcall != NULL) \ + __db_msgcall(env, fmt, ap); \ + va_end(ap); \ + \ + /* \ + * If the application specified a file descriptor, or we wrote \ + * to neither the application's callback routine or to its file \ + * descriptor, write to stdout. \ + */ \ + va_start(ap); \ + if ((env) == NULL || \ + (env)->db_msgfile != NULL || (env)->db_msgcall == NULL) { \ + __db_msgfile(env, fmt, ap); \ + } \ + va_end(ap); \ +} +#endif + +/* + * Debugging macro to log operations. + * If DEBUG_WOP is defined, log operations that modify the database. + * If DEBUG_ROP is defined, log operations that read the database. + * + * D dbp + * T txn + * O operation (string) + * K key + * A data + * F flags + */ +#define LOG_OP(C, T, O, K, A, F) { \ + DB_LSN __lsn; \ + DBT __op; \ + if (DBC_LOGGING((C))) { \ + memset(&__op, 0, sizeof(__op)); \ + __op.data = O; \ + __op.size = strlen(O) + 1; \ + (void)__db_debug_log((C)->dbp->dbenv, T, &__lsn, 0, \ + &__op, (C)->dbp->log_filename->id, K, A, F); \ + } \ +} +#ifdef DEBUG_ROP +#define DEBUG_LREAD(C, T, O, K, A, F) LOG_OP(C, T, O, K, A, F) +#else +#define DEBUG_LREAD(C, T, O, K, A, F) +#endif +#ifdef DEBUG_WOP +#define DEBUG_LWRITE(C, T, O, K, A, F) LOG_OP(C, T, O, K, A, F) +#else +#define DEBUG_LWRITE(C, T, O, K, A, F) +#endif + +/* + * Hook for testing recovery at various places in the create/delete paths. + * Hook for testing subdb locks. + */ +#if CONFIG_TEST +#define DB_TEST_SUBLOCKS(env, flags) do { \ + if ((env)->test_abort == DB_TEST_SUBDB_LOCKS) \ + (flags) |= DB_LOCK_NOWAIT; \ +} while (0) + +#define DB_ENV_TEST_RECOVERY(env, val, ret, name) do { \ + int __ret; \ + PANIC_CHECK((env)); \ + if ((env)->test_copy == (val)) { \ + /* COPY the FILE */ \ + if ((__ret = __db_testcopy((env), NULL, (name))) != 0) \ + (ret) = __db_panic((env), __ret); \ + } \ + if ((env)->test_abort == (val)) { \ + /* ABORT the TXN */ \ + (env)->test_abort = 0; \ + (ret) = EINVAL; \ + goto db_tr_err; \ + } \ +} while (0) + +#define DB_TEST_RECOVERY(dbp, val, ret, name) do { \ + int __ret; \ + PANIC_CHECK((dbp)->dbenv); \ + if ((dbp)->dbenv->test_copy == (val)) { \ + /* Copy the file. */ \ + if (F_ISSET((dbp), \ + DB_AM_OPEN_CALLED) && (dbp)->mpf != NULL) \ + (void)__db_sync(dbp); \ + if ((__ret = \ + __db_testcopy((dbp)->dbenv, (dbp), (name))) != 0) \ + (ret) = __db_panic((dbp)->dbenv, __ret); \ + } \ + if ((dbp)->dbenv->test_abort == (val)) { \ + /* Abort the transaction. */ \ + (dbp)->dbenv->test_abort = 0; \ + (ret) = EINVAL; \ + goto db_tr_err; \ + } \ +} while (0) + +#define DB_TEST_RECOVERY_LABEL db_tr_err: + +#define DB_TEST_CHECKPOINT(env, val) \ + if ((val) != 0) \ + __os_sleep((env), (u_long)(val), 0) +#else +#define DB_TEST_SUBLOCKS(env, flags) +#define DB_ENV_TEST_RECOVERY(env, val, ret, name) +#define DB_TEST_RECOVERY(dbp, val, ret, name) +#define DB_TEST_RECOVERY_LABEL +#define DB_TEST_CHECKPOINT(env, val) +#endif + +#if defined(__cplusplus) +} +#endif +#endif /* !_DB_DEBUG_H_ */ diff --git a/lib_dict/bdb/include/env_ext.h b/lib_dict/bdb/include/env_ext.h new file mode 100644 index 000000000..03b3ae995 --- /dev/null +++ b/lib_dict/bdb/include/env_ext.h @@ -0,0 +1,68 @@ +/* DO NOT EDIT: automatically built by dist/s_include. */ +#ifndef _env_ext_h_ +#define _env_ext_h_ + +#if defined(__cplusplus) +extern "C" { +#endif + +void __db_shalloc_init __P((REGINFO *, size_t)); +size_t __db_shalloc_size __P((size_t, size_t)); +int __db_shalloc __P((REGINFO *, size_t, size_t, void *)); +void __db_shalloc_free __P((REGINFO *, void *)); +size_t __db_shalloc_sizeof __P((void *)); +u_int32_t __db_tablesize __P((u_int32_t)); +void __db_hashinit __P((void *, u_int32_t)); +int __db_fileinit __P((DB_ENV *, DB_FH *, size_t, int)); +int __db_overwrite __P((DB_ENV *, const char *)); +int __dbenv_set_alloc __P((DB_ENV *, void *(*)(size_t), void *(*)(void *, size_t), void (*)(void *))); +int __dbenv_get_encrypt_flags __P((DB_ENV *, u_int32_t *)); +int __dbenv_set_encrypt __P((DB_ENV *, const char *, u_int32_t)); +int __dbenv_set_flags __P((DB_ENV *, u_int32_t, int)); +int __dbenv_set_data_dir __P((DB_ENV *, const char *)); +int __dbenv_set_intermediate_dir __P((DB_ENV *, int, u_int32_t)); +void __dbenv_set_errcall __P((DB_ENV *, void (*)(const DB_ENV *, const char *, const char *))); +void __dbenv_get_errfile __P((DB_ENV *, FILE **)); +void __dbenv_set_errfile __P((DB_ENV *, FILE *)); +void __dbenv_get_errpfx __P((DB_ENV *, const char **)); +void __dbenv_set_errpfx __P((DB_ENV *, const char *)); +void __dbenv_set_msgcall __P((DB_ENV *, void (*)(const DB_ENV *, const char *))); +void __dbenv_get_msgfile __P((DB_ENV *, FILE **)); +void __dbenv_set_msgfile __P((DB_ENV *, FILE *)); +int __dbenv_set_paniccall __P((DB_ENV *, void (*)(DB_ENV *, int))); +int __dbenv_set_shm_key __P((DB_ENV *, long)); +int __dbenv_set_tas_spins __P((DB_ENV *, u_int32_t)); +int __dbenv_set_tmp_dir __P((DB_ENV *, const char *)); +int __dbenv_set_verbose __P((DB_ENV *, u_int32_t, int)); +int __db_mi_env __P((DB_ENV *, const char *)); +int __db_mi_open __P((DB_ENV *, const char *, int)); +int __db_env_config __P((DB_ENV *, char *, u_int32_t)); +int __dbenv_open __P((DB_ENV *, const char *, u_int32_t, int)); +int __dbenv_remove __P((DB_ENV *, const char *, u_int32_t)); +int __dbenv_close_pp __P((DB_ENV *, u_int32_t)); +int __dbenv_close __P((DB_ENV *, int)); +int __dbenv_get_open_flags __P((DB_ENV *, u_int32_t *)); +int __db_appname __P((DB_ENV *, APPNAME, const char *, u_int32_t, DB_FH **, char **)); +int __db_home __P((DB_ENV *, const char *, u_int32_t)); +int __db_apprec __P((DB_ENV *, DB_LSN *, DB_LSN *, int, u_int32_t)); +int __log_backup __P((DB_ENV *, DB_LOGC *, DB_LSN *, DB_LSN *, u_int32_t)); +int __env_openfiles __P((DB_ENV *, DB_LOGC *, void *, DBT *, DB_LSN *, DB_LSN *, double, int)); +int __db_e_attach __P((DB_ENV *, u_int32_t *)); +int __db_e_detach __P((DB_ENV *, int)); +int __db_e_remove __P((DB_ENV *, u_int32_t)); +int __db_r_attach __P((DB_ENV *, REGINFO *, size_t)); +int __db_r_detach __P((DB_ENV *, REGINFO *, int)); +int __dbenv_stat_print_pp __P((DB_ENV *, u_int32_t)); +void __db_print_fh __P((DB_ENV *, DB_FH *, u_int32_t)); +void __db_print_fileid __P((DB_ENV *, u_int8_t *, const char *)); +void __db_print_mutex __P((DB_ENV *, DB_MSGBUF *, DB_MUTEX *, const char *, u_int32_t)); +void __db_dl __P((DB_ENV *, const char *, u_long)); +void __db_dl_pct __P((DB_ENV *, const char *, u_long, int, const char *)); +void __db_dlbytes __P((DB_ENV *, const char *, u_long, u_long, u_long)); +void __db_print_reginfo __P((DB_ENV *, REGINFO *, const char *)); +int __db_stat_not_built __P((DB_ENV *)); + +#if defined(__cplusplus) +} +#endif +#endif /* !_env_ext_h_ */ diff --git a/lib_dict/bdb/include/ext_185_def.in b/lib_dict/bdb/include/ext_185_def.in new file mode 100644 index 000000000..8da68a8df --- /dev/null +++ b/lib_dict/bdb/include/ext_185_def.in @@ -0,0 +1,12 @@ + +/* DO NOT EDIT: automatically built by dist/s_include. */ +#ifndef _DB_EXT_185_DEF_IN_ +#define _DB_EXT_185_DEF_IN_ + +#ifdef _DB185_INT_H_ +#define __db185_open __db185_open@DB_VERSION_UNIQUE_NAME@ +#else +#define __db185_open __db185_open@DB_VERSION_UNIQUE_NAME@ +#endif + +#endif /* !_DB_EXT_185_DEF_IN_ */ diff --git a/lib_dict/bdb/include/ext_185_prot.in b/lib_dict/bdb/include/ext_185_prot.in new file mode 100644 index 000000000..dfd8d3d47 --- /dev/null +++ b/lib_dict/bdb/include/ext_185_prot.in @@ -0,0 +1,19 @@ + +/* DO NOT EDIT: automatically built by dist/s_include. */ +#ifndef _DB_EXT_185_PROT_IN_ +#define _DB_EXT_185_PROT_IN_ + +#if defined(__cplusplus) +extern "C" { +#endif + +#ifdef _DB185_INT_H_ +DB185 *__db185_open __P((const char *, int, int, DBTYPE, const void *)); +#else +DB *__db185_open __P((const char *, int, int, DBTYPE, const void *)); +#endif + +#if defined(__cplusplus) +} +#endif +#endif /* !_DB_EXT_185_PROT_IN_ */ diff --git a/lib_dict/bdb/include/ext_def.in b/lib_dict/bdb/include/ext_def.in new file mode 100644 index 000000000..37577a77e --- /dev/null +++ b/lib_dict/bdb/include/ext_def.in @@ -0,0 +1,62 @@ + +/* DO NOT EDIT: automatically built by dist/s_include. */ +#ifndef _DB_EXT_DEF_IN_ +#define _DB_EXT_DEF_IN_ + +#define db_create db_create@DB_VERSION_UNIQUE_NAME@ +#define db_strerror db_strerror@DB_VERSION_UNIQUE_NAME@ +#define db_env_create db_env_create@DB_VERSION_UNIQUE_NAME@ +#define db_version db_version@DB_VERSION_UNIQUE_NAME@ +#define log_compare log_compare@DB_VERSION_UNIQUE_NAME@ +#define db_env_set_func_close db_env_set_func_close@DB_VERSION_UNIQUE_NAME@ +#define db_env_set_func_dirfree db_env_set_func_dirfree@DB_VERSION_UNIQUE_NAME@ +#define db_env_set_func_dirlist db_env_set_func_dirlist@DB_VERSION_UNIQUE_NAME@ +#define db_env_set_func_exists db_env_set_func_exists@DB_VERSION_UNIQUE_NAME@ +#define db_env_set_func_free db_env_set_func_free@DB_VERSION_UNIQUE_NAME@ +#define db_env_set_func_fsync db_env_set_func_fsync@DB_VERSION_UNIQUE_NAME@ +#define db_env_set_func_ftruncate db_env_set_func_ftruncate@DB_VERSION_UNIQUE_NAME@ +#define db_env_set_func_ioinfo db_env_set_func_ioinfo@DB_VERSION_UNIQUE_NAME@ +#define db_env_set_func_malloc db_env_set_func_malloc@DB_VERSION_UNIQUE_NAME@ +#define db_env_set_func_map db_env_set_func_map@DB_VERSION_UNIQUE_NAME@ +#define db_env_set_func_pread db_env_set_func_pread@DB_VERSION_UNIQUE_NAME@ +#define db_env_set_func_pwrite db_env_set_func_pwrite@DB_VERSION_UNIQUE_NAME@ +#define db_env_set_func_open db_env_set_func_open@DB_VERSION_UNIQUE_NAME@ +#define db_env_set_func_read db_env_set_func_read@DB_VERSION_UNIQUE_NAME@ +#define db_env_set_func_realloc db_env_set_func_realloc@DB_VERSION_UNIQUE_NAME@ +#define db_env_set_func_rename db_env_set_func_rename@DB_VERSION_UNIQUE_NAME@ +#define db_env_set_func_seek db_env_set_func_seek@DB_VERSION_UNIQUE_NAME@ +#define db_env_set_func_sleep db_env_set_func_sleep@DB_VERSION_UNIQUE_NAME@ +#define db_env_set_func_unlink db_env_set_func_unlink@DB_VERSION_UNIQUE_NAME@ +#define db_env_set_func_unmap db_env_set_func_unmap@DB_VERSION_UNIQUE_NAME@ +#define db_env_set_func_write db_env_set_func_write@DB_VERSION_UNIQUE_NAME@ +#define db_env_set_func_yield db_env_set_func_yield@DB_VERSION_UNIQUE_NAME@ +#define db_sequence_create db_sequence_create@DB_VERSION_UNIQUE_NAME@ +#if DB_DBM_HSEARCH != 0 +#define __db_ndbm_clearerr __db_ndbm_clearerr@DB_VERSION_UNIQUE_NAME@ +#define __db_ndbm_close __db_ndbm_close@DB_VERSION_UNIQUE_NAME@ +#define __db_ndbm_delete __db_ndbm_delete@DB_VERSION_UNIQUE_NAME@ +#define __db_ndbm_dirfno __db_ndbm_dirfno@DB_VERSION_UNIQUE_NAME@ +#define __db_ndbm_error __db_ndbm_error@DB_VERSION_UNIQUE_NAME@ +#define __db_ndbm_fetch __db_ndbm_fetch@DB_VERSION_UNIQUE_NAME@ +#define __db_ndbm_firstkey __db_ndbm_firstkey@DB_VERSION_UNIQUE_NAME@ +#define __db_ndbm_nextkey __db_ndbm_nextkey@DB_VERSION_UNIQUE_NAME@ +#define __db_ndbm_open __db_ndbm_open@DB_VERSION_UNIQUE_NAME@ +#define __db_ndbm_pagfno __db_ndbm_pagfno@DB_VERSION_UNIQUE_NAME@ +#define __db_ndbm_rdonly __db_ndbm_rdonly@DB_VERSION_UNIQUE_NAME@ +#define __db_ndbm_store __db_ndbm_store@DB_VERSION_UNIQUE_NAME@ +#define __db_dbm_close __db_dbm_close@DB_VERSION_UNIQUE_NAME@ +#define __db_dbm_delete __db_dbm_delete@DB_VERSION_UNIQUE_NAME@ +#define __db_dbm_fetch __db_dbm_fetch@DB_VERSION_UNIQUE_NAME@ +#define __db_dbm_firstkey __db_dbm_firstkey@DB_VERSION_UNIQUE_NAME@ +#define __db_dbm_init __db_dbm_init@DB_VERSION_UNIQUE_NAME@ +#define __db_dbm_nextkey __db_dbm_nextkey@DB_VERSION_UNIQUE_NAME@ +#define __db_dbm_store __db_dbm_store@DB_VERSION_UNIQUE_NAME@ +#endif +#if DB_DBM_HSEARCH != 0 +#define __db_hcreate __db_hcreate@DB_VERSION_UNIQUE_NAME@ +#define __db_hsearch __db_hsearch@DB_VERSION_UNIQUE_NAME@ +#define __db_hdestroy __db_hdestroy@DB_VERSION_UNIQUE_NAME@ +#endif +#define db_xa_switch db_xa_switch@DB_VERSION_UNIQUE_NAME@ + +#endif /* !_DB_EXT_DEF_IN_ */ diff --git a/lib_dict/bdb/include/ext_prot.in b/lib_dict/bdb/include/ext_prot.in new file mode 100644 index 000000000..d4e49ed4c --- /dev/null +++ b/lib_dict/bdb/include/ext_prot.in @@ -0,0 +1,68 @@ + +/* DO NOT EDIT: automatically built by dist/s_include. */ +#ifndef _DB_EXT_PROT_IN_ +#define _DB_EXT_PROT_IN_ + +#if defined(__cplusplus) +extern "C" { +#endif + +int db_create __P((DB **, DB_ENV *, u_int32_t)); +char *db_strerror __P((int)); +int db_env_create __P((DB_ENV **, u_int32_t)); +char *db_version __P((int *, int *, int *)); +int log_compare __P((const DB_LSN *, const DB_LSN *)); +int db_env_set_func_close __P((int (*)(int))); +int db_env_set_func_dirfree __P((void (*)(char **, int))); +int db_env_set_func_dirlist __P((int (*)(const char *, char ***, int *))); +int db_env_set_func_exists __P((int (*)(const char *, int *))); +int db_env_set_func_free __P((void (*)(void *))); +int db_env_set_func_fsync __P((int (*)(int))); +int db_env_set_func_ftruncate __P((int (*)(int, off_t))); +int db_env_set_func_ioinfo __P((int (*)(const char *, int, u_int32_t *, u_int32_t *, u_int32_t *))); +int db_env_set_func_malloc __P((void *(*)(size_t))); +int db_env_set_func_map __P((int (*)(char *, size_t, int, int, void **))); +int db_env_set_func_pread __P((ssize_t (*)(int, void *, size_t, off_t))); +int db_env_set_func_pwrite __P((ssize_t (*)(int, const void *, size_t, off_t))); +int db_env_set_func_open __P((int (*)(const char *, int, ...))); +int db_env_set_func_read __P((ssize_t (*)(int, void *, size_t))); +int db_env_set_func_realloc __P((void *(*)(void *, size_t))); +int db_env_set_func_rename __P((int (*)(const char *, const char *))); +int db_env_set_func_seek __P((int (*)(int, off_t, int))); +int db_env_set_func_sleep __P((int (*)(u_long, u_long))); +int db_env_set_func_unlink __P((int (*)(const char *))); +int db_env_set_func_unmap __P((int (*)(void *, size_t))); +int db_env_set_func_write __P((ssize_t (*)(int, const void *, size_t))); +int db_env_set_func_yield __P((int (*)(void))); +int db_sequence_create __P((DB_SEQUENCE **, DB *, u_int32_t)); +#if DB_DBM_HSEARCH != 0 +int __db_ndbm_clearerr __P((DBM *)); +void __db_ndbm_close __P((DBM *)); +int __db_ndbm_delete __P((DBM *, datum)); +int __db_ndbm_dirfno __P((DBM *)); +int __db_ndbm_error __P((DBM *)); +datum __db_ndbm_fetch __P((DBM *, datum)); +datum __db_ndbm_firstkey __P((DBM *)); +datum __db_ndbm_nextkey __P((DBM *)); +DBM *__db_ndbm_open __P((const char *, int, int)); +int __db_ndbm_pagfno __P((DBM *)); +int __db_ndbm_rdonly __P((DBM *)); +int __db_ndbm_store __P((DBM *, datum, datum, int)); +int __db_dbm_close __P((void)); +int __db_dbm_delete __P((datum)); +datum __db_dbm_fetch __P((datum)); +datum __db_dbm_firstkey __P((void)); +int __db_dbm_init __P((char *)); +datum __db_dbm_nextkey __P((datum)); +int __db_dbm_store __P((datum, datum)); +#endif +#if DB_DBM_HSEARCH != 0 +int __db_hcreate __P((size_t)); +ENTRY *__db_hsearch __P((ENTRY, ACTION)); +void __db_hdestroy __P((void)); +#endif + +#if defined(__cplusplus) +} +#endif +#endif /* !_DB_EXT_PROT_IN_ */ diff --git a/lib_dict/bdb/include/fileops_auto.h b/lib_dict/bdb/include/fileops_auto.h new file mode 100644 index 000000000..12440264d --- /dev/null +++ b/lib_dict/bdb/include/fileops_auto.h @@ -0,0 +1,62 @@ +/* Do not edit: automatically built by gen_rec.awk. */ + +#ifndef __fop_AUTO_H +#define __fop_AUTO_H +#define DB___fop_create 143 +typedef struct ___fop_create_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + DBT name; + u_int32_t appname; + u_int32_t mode; +} __fop_create_args; + +#define DB___fop_remove 144 +typedef struct ___fop_remove_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + DBT name; + DBT fid; + u_int32_t appname; +} __fop_remove_args; + +#define DB___fop_write 145 +typedef struct ___fop_write_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + DBT name; + u_int32_t appname; + u_int32_t pgsize; + db_pgno_t pageno; + u_int32_t offset; + DBT page; + u_int32_t flag; +} __fop_write_args; + +#define DB___fop_rename 146 +typedef struct ___fop_rename_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + DBT oldname; + DBT newname; + DBT fileid; + u_int32_t appname; +} __fop_rename_args; + +#define DB___fop_file_remove 141 +typedef struct ___fop_file_remove_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + DBT real_fid; + DBT tmp_fid; + DBT name; + u_int32_t appname; + u_int32_t child; +} __fop_file_remove_args; + +#endif diff --git a/lib_dict/bdb/include/fileops_ext.h b/lib_dict/bdb/include/fileops_ext.h new file mode 100644 index 000000000..25b2fe625 --- /dev/null +++ b/lib_dict/bdb/include/fileops_ext.h @@ -0,0 +1,46 @@ +/* DO NOT EDIT: automatically built by dist/s_include. */ +#ifndef _fileops_ext_h_ +#define _fileops_ext_h_ + +#if defined(__cplusplus) +extern "C" { +#endif + +int __fop_create_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t, const DBT *, u_int32_t, u_int32_t)); +int __fop_create_read __P((DB_ENV *, void *, __fop_create_args **)); +int __fop_remove_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t, const DBT *, const DBT *, u_int32_t)); +int __fop_remove_read __P((DB_ENV *, void *, __fop_remove_args **)); +int __fop_write_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t, const DBT *, u_int32_t, u_int32_t, db_pgno_t, u_int32_t, const DBT *, u_int32_t)); +int __fop_write_read __P((DB_ENV *, void *, __fop_write_args **)); +int __fop_rename_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t, const DBT *, const DBT *, const DBT *, u_int32_t)); +int __fop_rename_read __P((DB_ENV *, void *, __fop_rename_args **)); +int __fop_file_remove_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t, const DBT *, const DBT *, const DBT *, u_int32_t, u_int32_t)); +int __fop_file_remove_read __P((DB_ENV *, void *, __fop_file_remove_args **)); +int __fop_init_recover __P((DB_ENV *, int (***)(DB_ENV *, DBT *, DB_LSN *, db_recops, void *), size_t *)); +int __fop_create_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __fop_remove_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __fop_write_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __fop_rename_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __fop_file_remove_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __fop_init_print __P((DB_ENV *, int (***)(DB_ENV *, DBT *, DB_LSN *, db_recops, void *), size_t *)); +int __fop_create __P((DB_ENV *, DB_TXN *, DB_FH **, const char *, APPNAME, int, u_int32_t)); +int __fop_remove __P((DB_ENV *, DB_TXN *, u_int8_t *, const char *, APPNAME, u_int32_t)); +int __fop_write __P((DB_ENV *, DB_TXN *, const char *, APPNAME, DB_FH *, u_int32_t, db_pgno_t, u_int32_t, u_int8_t *, u_int32_t, u_int32_t, u_int32_t)); +int __fop_rename __P((DB_ENV *, DB_TXN *, const char *, const char *, u_int8_t *, APPNAME, u_int32_t)); +int __fop_create_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __fop_remove_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __fop_write_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __fop_rename_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __fop_file_remove_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __fop_lock_handle __P((DB_ENV *, DB *, u_int32_t, db_lockmode_t, DB_LOCK *, u_int32_t)); +int __fop_file_setup __P((DB *, DB_TXN *, const char *, int, u_int32_t, u_int32_t *)); +int __fop_subdb_setup __P((DB *, DB_TXN *, const char *, const char *, int, u_int32_t)); +int __fop_remove_setup __P((DB *, DB_TXN *, const char *, u_int32_t)); +int __fop_read_meta __P((DB_ENV *, const char *, u_int8_t *, size_t, DB_FH *, int, size_t *)); +int __fop_dummy __P((DB *, DB_TXN *, const char *, const char *, u_int32_t)); +int __fop_dbrename __P((DB *, const char *, const char *)); + +#if defined(__cplusplus) +} +#endif +#endif /* !_fileops_ext_h_ */ diff --git a/lib_dict/bdb/include/fop.h b/lib_dict/bdb/include/fop.h new file mode 100644 index 000000000..ef87ff6e2 --- /dev/null +++ b/lib_dict/bdb/include/fop.h @@ -0,0 +1,16 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2001-2004 + * Sleepycat Software. All rights reserved. + * + * $Id: fop.h,v 11.5 2004/01/28 03:36:02 bostic Exp $ + */ + +#ifndef _FOP_H_ +#define _FOP_H_ + +#include "dbinc_auto/fileops_auto.h" +#include "dbinc_auto/fileops_ext.h" + +#endif /* !_FOP_H_ */ diff --git a/lib_dict/bdb/include/globals.h b/lib_dict/bdb/include/globals.h new file mode 100644 index 000000000..95d96533a --- /dev/null +++ b/lib_dict/bdb/include/globals.h @@ -0,0 +1,92 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996-2004 + * Sleepycat Software. All rights reserved. + * + * $Id: globals.h,v 11.9 2004/09/17 22:00:27 mjc Exp $ + */ + +/******************************************************* + * Global variables. + * + * Held in a single structure to minimize the name-space pollution. + *******************************************************/ +#ifdef HAVE_VXWORKS +#include "semLib.h" +#endif + +typedef struct __db_globals { +#ifdef HAVE_VXWORKS + u_int32_t db_global_init; /* VxWorks: inited */ + SEM_ID db_global_lock; /* VxWorks: global semaphore */ +#endif + /* XA: list of opened environments. */ + TAILQ_HEAD(__db_envq, __db_env) db_envq; + + char *db_line; /* DB display string. */ + + int (*j_close) __P((int)); /* Underlying OS interface jump table.*/ + void (*j_dirfree) __P((char **, int)); + int (*j_dirlist) __P((const char *, char ***, int *)); + int (*j_exists) __P((const char *, int *)); + void (*j_free) __P((void *)); + int (*j_fsync) __P((int)); + int (*j_ftruncate) __P((int, off_t)); + int (*j_ioinfo) __P((const char *, + int, u_int32_t *, u_int32_t *, u_int32_t *)); + void *(*j_malloc) __P((size_t)); + int (*j_map) __P((char *, size_t, int, int, void **)); + int (*j_open) __P((const char *, int, ...)); + ssize_t (*j_pread) __P((int, void *, size_t, off_t)); + ssize_t (*j_pwrite) __P((int, const void *, size_t, off_t)); + ssize_t (*j_read) __P((int, void *, size_t)); + void *(*j_realloc) __P((void *, size_t)); + int (*j_rename) __P((const char *, const char *)); + int (*j_seek) __P((int, off_t, int)); + int (*j_sleep) __P((u_long, u_long)); + int (*j_unlink) __P((const char *)); + int (*j_unmap) __P((void *, size_t)); + ssize_t (*j_write) __P((int, const void *, size_t)); + int (*j_yield) __P((void)); +} DB_GLOBALS; + +#ifdef DB_INITIALIZE_DB_GLOBALS +DB_GLOBALS __db_global_values = { +#ifdef HAVE_VXWORKS + 0, /* VxWorks: initialized */ + NULL, /* VxWorks: global semaphore */ +#endif + /* XA: list of opened environments. */ + {NULL, &__db_global_values.db_envq.tqh_first}, + + "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=", + + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL +}; +#else +extern DB_GLOBALS __db_global_values; +#endif + +#define DB_GLOBAL(v) __db_global_values.v diff --git a/lib_dict/bdb/include/hash.h b/lib_dict/bdb/include/hash.h new file mode 100644 index 000000000..10059a5e0 --- /dev/null +++ b/lib_dict/bdb/include/hash.h @@ -0,0 +1,147 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996-2004 + * Sleepycat Software. All rights reserved. + */ +/* + * Copyright (c) 1990, 1993, 1994 + * Margo Seltzer. All rights reserved. + */ +/* + * Copyright (c) 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Margo Seltzer. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: hash.h,v 11.28 2004/01/28 03:36:02 bostic Exp $ + */ + +#ifndef _DB_HASH_H_ +#define _DB_HASH_H_ + +/* Hash internal structure. */ +typedef struct hash_t { + db_pgno_t meta_pgno; /* Page number of the meta data page. */ + u_int32_t h_ffactor; /* Fill factor. */ + u_int32_t h_nelem; /* Number of elements. */ + /* Hash function. */ + u_int32_t (*h_hash) __P((DB *, const void *, u_int32_t)); +} HASH; + +/* Cursor structure definitions. */ +typedef struct cursor_t { + /* struct __dbc_internal */ + __DBC_INTERNAL + + /* Hash private part */ + + /* Per-thread information */ + DB_LOCK hlock; /* Metadata page lock. */ + HMETA *hdr; /* Pointer to meta-data page. */ + PAGE *split_buf; /* Temporary buffer for splits. */ + + /* Hash cursor information */ + db_pgno_t bucket; /* Bucket we are traversing. */ + db_pgno_t lbucket; /* Bucket for which we are locked. */ + db_indx_t dup_off; /* Offset within a duplicate set. */ + db_indx_t dup_len; /* Length of current duplicate. */ + db_indx_t dup_tlen; /* Total length of duplicate entry. */ + u_int32_t seek_size; /* Number of bytes we need for add. */ + db_pgno_t seek_found_page;/* Page on which we can insert. */ + u_int32_t order; /* Relative order among deleted curs. */ + +#define H_CONTINUE 0x0001 /* Join--search strictly fwd for data */ +#define H_DELETED 0x0002 /* Cursor item is deleted. */ +#define H_DIRTY 0x0004 /* Meta-data page needs to be written */ +#define H_DUPONLY 0x0008 /* Dups only; do not change key. */ +#define H_EXPAND 0x0010 /* Table expanded. */ +#define H_ISDUP 0x0020 /* Cursor is within duplicate set. */ +#define H_NEXT_NODUP 0x0040 /* Get next non-dup entry. */ +#define H_NOMORE 0x0080 /* No more entries in bucket. */ +#define H_OK 0x0100 /* Request succeeded. */ + u_int32_t flags; +} HASH_CURSOR; + +/* Test string. */ +#define CHARKEY "%$sniglet^&" + +/* Overflow management */ +/* + * The spares table indicates the page number at which each doubling begins. + * From this page number we subtract the number of buckets already allocated + * so that we can do a simple addition to calculate the page number here. + */ +#define BS_TO_PAGE(bucket, spares) \ + ((bucket) + (spares)[__db_log2((bucket) + 1)]) +#define BUCKET_TO_PAGE(I, B) (BS_TO_PAGE((B), (I)->hdr->spares)) + +/* Constraints about much data goes on a page. */ + +#define MINFILL 4 +#define ISBIG(I, N) (((N) > ((I)->hdr->dbmeta.pagesize / MINFILL)) ? 1 : 0) + +/* Shorthands for accessing structure */ +#define NDX_INVALID 0xFFFF +#define BUCKET_INVALID 0xFFFFFFFF + +/* On page duplicates are stored as a string of size-data-size triples. */ +#define DUP_SIZE(len) ((len) + 2 * sizeof(db_indx_t)) + +/* Log messages types (these are subtypes within a record type) */ +#define PAIR_KEYMASK 0x1 +#define PAIR_DATAMASK 0x2 +#define PAIR_DUPMASK 0x4 +#define PAIR_MASK 0xf +#define PAIR_ISKEYBIG(N) (N & PAIR_KEYMASK) +#define PAIR_ISDATABIG(N) (N & PAIR_DATAMASK) +#define PAIR_ISDATADUP(N) (N & PAIR_DUPMASK) +#define OPCODE_OF(N) (N & ~PAIR_MASK) + +#define PUTPAIR 0x20 +#define DELPAIR 0x30 +#define PUTOVFL 0x40 +#define DELOVFL 0x50 +#define HASH_UNUSED1 0x60 +#define HASH_UNUSED2 0x70 +#define SPLITOLD 0x80 +#define SPLITNEW 0x90 + +typedef enum { + DB_HAM_CHGPG = 1, + DB_HAM_DELFIRSTPG = 2, + DB_HAM_DELMIDPG = 3, + DB_HAM_DELLASTPG = 4, + DB_HAM_DUP = 5, + DB_HAM_SPLIT = 6 +} db_ham_mode; + +#include "dbinc_auto/hash_auto.h" +#include "dbinc_auto/hash_ext.h" +#include "dbinc/db_am.h" +#endif /* !_DB_HASH_H_ */ diff --git a/lib_dict/bdb/include/hash_auto.h b/lib_dict/bdb/include/hash_auto.h new file mode 100644 index 000000000..5b5525363 --- /dev/null +++ b/lib_dict/bdb/include/hash_auto.h @@ -0,0 +1,134 @@ +/* Do not edit: automatically built by gen_rec.awk. */ + +#ifndef __ham_AUTO_H +#define __ham_AUTO_H +#define DB___ham_insdel 21 +typedef struct ___ham_insdel_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + u_int32_t opcode; + int32_t fileid; + db_pgno_t pgno; + u_int32_t ndx; + DB_LSN pagelsn; + DBT key; + DBT data; +} __ham_insdel_args; + +#define DB___ham_newpage 22 +typedef struct ___ham_newpage_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + u_int32_t opcode; + int32_t fileid; + db_pgno_t prev_pgno; + DB_LSN prevlsn; + db_pgno_t new_pgno; + DB_LSN pagelsn; + db_pgno_t next_pgno; + DB_LSN nextlsn; +} __ham_newpage_args; + +#define DB___ham_splitdata 24 +typedef struct ___ham_splitdata_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + u_int32_t opcode; + db_pgno_t pgno; + DBT pageimage; + DB_LSN pagelsn; +} __ham_splitdata_args; + +#define DB___ham_replace 25 +typedef struct ___ham_replace_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + db_pgno_t pgno; + u_int32_t ndx; + DB_LSN pagelsn; + int32_t off; + DBT olditem; + DBT newitem; + u_int32_t makedup; +} __ham_replace_args; + +#define DB___ham_copypage 28 +typedef struct ___ham_copypage_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + db_pgno_t pgno; + DB_LSN pagelsn; + db_pgno_t next_pgno; + DB_LSN nextlsn; + db_pgno_t nnext_pgno; + DB_LSN nnextlsn; + DBT page; +} __ham_copypage_args; + +#define DB___ham_metagroup 29 +typedef struct ___ham_metagroup_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + u_int32_t bucket; + db_pgno_t mmpgno; + DB_LSN mmetalsn; + db_pgno_t mpgno; + DB_LSN metalsn; + db_pgno_t pgno; + DB_LSN pagelsn; + u_int32_t newalloc; + db_pgno_t last_pgno; +} __ham_metagroup_args; + +#define DB___ham_groupalloc 32 +typedef struct ___ham_groupalloc_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + DB_LSN meta_lsn; + db_pgno_t start_pgno; + u_int32_t num; + db_pgno_t free; + db_pgno_t last_pgno; +} __ham_groupalloc_args; + +#define DB___ham_curadj 33 +typedef struct ___ham_curadj_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + db_pgno_t pgno; + u_int32_t indx; + u_int32_t len; + u_int32_t dup_off; + int add; + int is_dup; + u_int32_t order; +} __ham_curadj_args; + +#define DB___ham_chgpg 34 +typedef struct ___ham_chgpg_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + db_ham_mode mode; + db_pgno_t old_pgno; + db_pgno_t new_pgno; + u_int32_t old_indx; + u_int32_t new_indx; +} __ham_chgpg_args; + +#endif diff --git a/lib_dict/bdb/include/hash_ext.h b/lib_dict/bdb/include/hash_ext.h new file mode 100644 index 000000000..4869df741 --- /dev/null +++ b/lib_dict/bdb/include/hash_ext.h @@ -0,0 +1,119 @@ +/* DO NOT EDIT: automatically built by dist/s_include. */ +#ifndef _hash_ext_h_ +#define _hash_ext_h_ + +#if defined(__cplusplus) +extern "C" { +#endif + +int __ham_quick_delete __P((DBC *)); +int __ham_c_init __P((DBC *)); +int __ham_c_count __P((DBC *, db_recno_t *)); +int __ham_c_dup __P((DBC *, DBC *)); +u_int32_t __ham_call_hash __P((DBC *, u_int8_t *, u_int32_t)); +int __ham_init_dbt __P((DB_ENV *, DBT *, u_int32_t, void **, u_int32_t *)); +int __ham_c_update __P((DBC *, u_int32_t, int, int)); +int __ham_get_clist __P((DB *, db_pgno_t, u_int32_t, DBC ***)); +int __ham_insdel_log __P((DB *, DB_TXN *, DB_LSN *, u_int32_t, u_int32_t, db_pgno_t, u_int32_t, DB_LSN *, const DBT *, const DBT *)); +int __ham_insdel_read __P((DB_ENV *, void *, __ham_insdel_args **)); +int __ham_newpage_log __P((DB *, DB_TXN *, DB_LSN *, u_int32_t, u_int32_t, db_pgno_t, DB_LSN *, db_pgno_t, DB_LSN *, db_pgno_t, DB_LSN *)); +int __ham_newpage_read __P((DB_ENV *, void *, __ham_newpage_args **)); +int __ham_splitdata_log __P((DB *, DB_TXN *, DB_LSN *, u_int32_t, u_int32_t, db_pgno_t, const DBT *, DB_LSN *)); +int __ham_splitdata_read __P((DB_ENV *, void *, __ham_splitdata_args **)); +int __ham_replace_log __P((DB *, DB_TXN *, DB_LSN *, u_int32_t, db_pgno_t, u_int32_t, DB_LSN *, int32_t, const DBT *, const DBT *, u_int32_t)); +int __ham_replace_read __P((DB_ENV *, void *, __ham_replace_args **)); +int __ham_copypage_log __P((DB *, DB_TXN *, DB_LSN *, u_int32_t, db_pgno_t, DB_LSN *, db_pgno_t, DB_LSN *, db_pgno_t, DB_LSN *, const DBT *)); +int __ham_copypage_read __P((DB_ENV *, void *, __ham_copypage_args **)); +int __ham_metagroup_log __P((DB *, DB_TXN *, DB_LSN *, u_int32_t, u_int32_t, db_pgno_t, DB_LSN *, db_pgno_t, DB_LSN *, db_pgno_t, DB_LSN *, u_int32_t, db_pgno_t)); +int __ham_metagroup_read __P((DB_ENV *, void *, __ham_metagroup_args **)); +int __ham_groupalloc_log __P((DB *, DB_TXN *, DB_LSN *, u_int32_t, DB_LSN *, db_pgno_t, u_int32_t, db_pgno_t, db_pgno_t)); +int __ham_groupalloc_read __P((DB_ENV *, void *, __ham_groupalloc_args **)); +int __ham_curadj_log __P((DB *, DB_TXN *, DB_LSN *, u_int32_t, db_pgno_t, u_int32_t, u_int32_t, u_int32_t, int, int, u_int32_t)); +int __ham_curadj_read __P((DB_ENV *, void *, __ham_curadj_args **)); +int __ham_chgpg_log __P((DB *, DB_TXN *, DB_LSN *, u_int32_t, db_ham_mode, db_pgno_t, db_pgno_t, u_int32_t, u_int32_t)); +int __ham_chgpg_read __P((DB_ENV *, void *, __ham_chgpg_args **)); +int __ham_init_recover __P((DB_ENV *, int (***)(DB_ENV *, DBT *, DB_LSN *, db_recops, void *), size_t *)); +int __ham_insdel_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __ham_newpage_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __ham_splitdata_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __ham_replace_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __ham_copypage_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __ham_metagroup_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __ham_groupalloc_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __ham_curadj_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __ham_chgpg_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __ham_init_print __P((DB_ENV *, int (***)(DB_ENV *, DBT *, DB_LSN *, db_recops, void *), size_t *)); +int __ham_pgin __P((DB_ENV *, DB *, db_pgno_t, void *, DBT *)); +int __ham_pgout __P((DB_ENV *, DB *, db_pgno_t, void *, DBT *)); +int __ham_mswap __P((void *)); +int __ham_add_dup __P((DBC *, DBT *, u_int32_t, db_pgno_t *)); +int __ham_dup_convert __P((DBC *)); +int __ham_make_dup __P((DB_ENV *, const DBT *, DBT *d, void **, u_int32_t *)); +void __ham_dsearch __P((DBC *, DBT *, u_int32_t *, int *, u_int32_t)); +u_int32_t __ham_func2 __P((DB *, const void *, u_int32_t)); +u_int32_t __ham_func3 __P((DB *, const void *, u_int32_t)); +u_int32_t __ham_func4 __P((DB *, const void *, u_int32_t)); +u_int32_t __ham_func5 __P((DB *, const void *, u_int32_t)); +u_int32_t __ham_test __P((DB *, const void *, u_int32_t)); +int __ham_get_meta __P((DBC *)); +int __ham_release_meta __P((DBC *)); +int __ham_dirty_meta __P((DBC *)); +int __ham_db_create __P((DB *)); +int __ham_db_close __P((DB *)); +int __ham_get_h_ffactor __P((DB *, u_int32_t *)); +int __ham_get_h_nelem __P((DB *, u_int32_t *)); +int __ham_open __P((DB *, DB_TXN *, const char * name, db_pgno_t, u_int32_t)); +int __ham_metachk __P((DB *, const char *, HMETA *)); +int __ham_new_file __P((DB *, DB_TXN *, DB_FH *, const char *)); +int __ham_new_subdb __P((DB *, DB *, DB_TXN *)); +int __ham_item __P((DBC *, db_lockmode_t, db_pgno_t *)); +int __ham_item_reset __P((DBC *)); +int __ham_item_init __P((DBC *)); +int __ham_item_last __P((DBC *, db_lockmode_t, db_pgno_t *)); +int __ham_item_first __P((DBC *, db_lockmode_t, db_pgno_t *)); +int __ham_item_prev __P((DBC *, db_lockmode_t, db_pgno_t *)); +int __ham_item_next __P((DBC *, db_lockmode_t, db_pgno_t *)); +void __ham_putitem __P((DB *, PAGE *p, const DBT *, int)); +void __ham_reputpair __P((DB *, PAGE *, u_int32_t, const DBT *, const DBT *)); +int __ham_del_pair __P((DBC *, int)); +int __ham_replpair __P((DBC *, DBT *, u_int32_t)); +void __ham_onpage_replace __P((DB *, PAGE *, u_int32_t, int32_t, u_int32_t, int, DBT *)); +int __ham_split_page __P((DBC *, u_int32_t, u_int32_t)); +int __ham_add_el __P((DBC *, const DBT *, const DBT *, int)); +void __ham_copy_item __P((DB *, PAGE *, u_int32_t, PAGE *)); +int __ham_add_ovflpage __P((DBC *, PAGE *, int, PAGE **)); +int __ham_get_cpage __P((DBC *, db_lockmode_t)); +int __ham_next_cpage __P((DBC *, db_pgno_t, int)); +int __ham_lock_bucket __P((DBC *, db_lockmode_t)); +void __ham_dpair __P((DB *, PAGE *, u_int32_t)); +int __ham_insdel_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __ham_newpage_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __ham_replace_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __ham_splitdata_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __ham_copypage_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __ham_metagroup_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __ham_groupalloc_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __ham_curadj_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __ham_chgpg_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __ham_reclaim __P((DB *, DB_TXN *txn)); +int __ham_truncate __P((DBC *, u_int32_t *)); +int __ham_stat __P((DBC *, void *, u_int32_t)); +int __ham_stat_print __P((DBC *, u_int32_t)); +void __ham_print_cursor __P((DBC *)); +int __ham_traverse __P((DBC *, db_lockmode_t, int (*)(DB *, PAGE *, void *, int *), void *, int)); +int __db_no_hash_am __P((DB_ENV *)); +int __ham_30_hashmeta __P((DB *, char *, u_int8_t *)); +int __ham_30_sizefix __P((DB *, DB_FH *, char *, u_int8_t *)); +int __ham_31_hashmeta __P((DB *, char *, u_int32_t, DB_FH *, PAGE *, int *)); +int __ham_31_hash __P((DB *, char *, u_int32_t, DB_FH *, PAGE *, int *)); +int __ham_vrfy_meta __P((DB *, VRFY_DBINFO *, HMETA *, db_pgno_t, u_int32_t)); +int __ham_vrfy __P((DB *, VRFY_DBINFO *, PAGE *, db_pgno_t, u_int32_t)); +int __ham_vrfy_structure __P((DB *, VRFY_DBINFO *, db_pgno_t, u_int32_t)); +int __ham_vrfy_hashing __P((DB *, u_int32_t, HMETA *, u_int32_t, db_pgno_t, u_int32_t, u_int32_t (*) __P((DB *, const void *, u_int32_t)))); +int __ham_salvage __P((DB *, VRFY_DBINFO *, db_pgno_t, PAGE *, void *, int (*)(void *, const void *), u_int32_t)); +int __ham_meta2pgset __P((DB *, VRFY_DBINFO *, HMETA *, u_int32_t, DB *)); + +#if defined(__cplusplus) +} +#endif +#endif /* !_hash_ext_h_ */ diff --git a/lib_dict/bdb/include/hmac.h b/lib_dict/bdb/include/hmac.h new file mode 100644 index 000000000..439537927 --- /dev/null +++ b/lib_dict/bdb/include/hmac.h @@ -0,0 +1,32 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996-2004 + * Sleepycat Software. All rights reserved. + * + * $Id: hmac.h,v 1.5 2004/01/28 03:36:02 bostic Exp $ + */ + +#ifndef _DB_HMAC_H_ +#define _DB_HMAC_H_ + +/* + * Algorithm specific information. + */ +/* + * SHA1 checksumming + */ +typedef struct { + u_int32_t state[5]; + u_int32_t count[2]; + unsigned char buffer[64]; +} SHA1_CTX; + +/* + * AES assumes the SHA1 checksumming (also called MAC) + */ +#define DB_MAC_MAGIC "mac derivation key magic value" +#define DB_ENC_MAGIC "encryption and decryption key value magic" + +#include "dbinc_auto/hmac_ext.h" +#endif /* !_DB_HMAC_H_ */ diff --git a/lib_dict/bdb/include/hmac_ext.h b/lib_dict/bdb/include/hmac_ext.h new file mode 100644 index 000000000..d161a7291 --- /dev/null +++ b/lib_dict/bdb/include/hmac_ext.h @@ -0,0 +1,20 @@ +/* DO NOT EDIT: automatically built by dist/s_include. */ +#ifndef _hmac_ext_h_ +#define _hmac_ext_h_ + +#if defined(__cplusplus) +extern "C" { +#endif + +void __db_chksum __P((u_int8_t *, size_t, u_int8_t *, u_int8_t *)); +void __db_derive_mac __P((u_int8_t *, size_t, u_int8_t *)); +int __db_check_chksum __P((DB_ENV *, DB_CIPHER *, u_int8_t *, void *, size_t, int)); +void __db_SHA1Transform __P((u_int32_t *, unsigned char *)); +void __db_SHA1Init __P((SHA1_CTX *)); +void __db_SHA1Update __P((SHA1_CTX *, unsigned char *, size_t)); +void __db_SHA1Final __P((unsigned char *, SHA1_CTX *)); + +#if defined(__cplusplus) +} +#endif +#endif /* !_hmac_ext_h_ */ diff --git a/lib_dict/bdb/include/int_def.in b/lib_dict/bdb/include/int_def.in new file mode 100644 index 000000000..eb8756bf4 --- /dev/null +++ b/lib_dict/bdb/include/int_def.in @@ -0,0 +1,1479 @@ +/* DO NOT EDIT: automatically built by dist/s_include. */ +#ifndef _DB_INT_DEF_IN_ +#define _DB_INT_DEF_IN_ + +#define __crdel_metasub_log __crdel_metasub_log@DB_VERSION_UNIQUE_NAME@ +#define __crdel_metasub_read __crdel_metasub_read@DB_VERSION_UNIQUE_NAME@ +#define __crdel_init_recover __crdel_init_recover@DB_VERSION_UNIQUE_NAME@ +#define __crdel_metasub_print __crdel_metasub_print@DB_VERSION_UNIQUE_NAME@ +#define __crdel_init_print __crdel_init_print@DB_VERSION_UNIQUE_NAME@ +#define __crdel_metasub_recover __crdel_metasub_recover@DB_VERSION_UNIQUE_NAME@ +#define __db_master_open __db_master_open@DB_VERSION_UNIQUE_NAME@ +#define __db_master_update __db_master_update@DB_VERSION_UNIQUE_NAME@ +#define __db_dbenv_setup __db_dbenv_setup@DB_VERSION_UNIQUE_NAME@ +#define __db_dbenv_mpool __db_dbenv_mpool@DB_VERSION_UNIQUE_NAME@ +#define __db_close __db_close@DB_VERSION_UNIQUE_NAME@ +#define __db_refresh __db_refresh@DB_VERSION_UNIQUE_NAME@ +#define __db_log_page __db_log_page@DB_VERSION_UNIQUE_NAME@ +#define __db_backup_name __db_backup_name@DB_VERSION_UNIQUE_NAME@ +#define __dblist_get __dblist_get@DB_VERSION_UNIQUE_NAME@ +#ifdef CONFIG_TEST +#define __db_testcopy __db_testcopy@DB_VERSION_UNIQUE_NAME@ +#endif +#define __db_cursor_int __db_cursor_int@DB_VERSION_UNIQUE_NAME@ +#define __db_put __db_put@DB_VERSION_UNIQUE_NAME@ +#define __db_del __db_del@DB_VERSION_UNIQUE_NAME@ +#define __db_sync __db_sync@DB_VERSION_UNIQUE_NAME@ +#define __db_associate __db_associate@DB_VERSION_UNIQUE_NAME@ +#define __db_secondary_close __db_secondary_close@DB_VERSION_UNIQUE_NAME@ +#define __db_addrem_log __db_addrem_log@DB_VERSION_UNIQUE_NAME@ +#define __db_addrem_read __db_addrem_read@DB_VERSION_UNIQUE_NAME@ +#define __db_big_log __db_big_log@DB_VERSION_UNIQUE_NAME@ +#define __db_big_read __db_big_read@DB_VERSION_UNIQUE_NAME@ +#define __db_ovref_log __db_ovref_log@DB_VERSION_UNIQUE_NAME@ +#define __db_ovref_read __db_ovref_read@DB_VERSION_UNIQUE_NAME@ +#define __db_debug_log __db_debug_log@DB_VERSION_UNIQUE_NAME@ +#define __db_debug_read __db_debug_read@DB_VERSION_UNIQUE_NAME@ +#define __db_noop_log __db_noop_log@DB_VERSION_UNIQUE_NAME@ +#define __db_noop_read __db_noop_read@DB_VERSION_UNIQUE_NAME@ +#define __db_pg_alloc_log __db_pg_alloc_log@DB_VERSION_UNIQUE_NAME@ +#define __db_pg_alloc_read __db_pg_alloc_read@DB_VERSION_UNIQUE_NAME@ +#define __db_pg_free_log __db_pg_free_log@DB_VERSION_UNIQUE_NAME@ +#define __db_pg_free_read __db_pg_free_read@DB_VERSION_UNIQUE_NAME@ +#define __db_cksum_log __db_cksum_log@DB_VERSION_UNIQUE_NAME@ +#define __db_cksum_read __db_cksum_read@DB_VERSION_UNIQUE_NAME@ +#define __db_pg_freedata_log __db_pg_freedata_log@DB_VERSION_UNIQUE_NAME@ +#define __db_pg_freedata_read __db_pg_freedata_read@DB_VERSION_UNIQUE_NAME@ +#define __db_pg_prepare_log __db_pg_prepare_log@DB_VERSION_UNIQUE_NAME@ +#define __db_pg_prepare_read __db_pg_prepare_read@DB_VERSION_UNIQUE_NAME@ +#define __db_pg_new_log __db_pg_new_log@DB_VERSION_UNIQUE_NAME@ +#define __db_pg_new_read __db_pg_new_read@DB_VERSION_UNIQUE_NAME@ +#define __db_pg_init_log __db_pg_init_log@DB_VERSION_UNIQUE_NAME@ +#define __db_pg_init_read __db_pg_init_read@DB_VERSION_UNIQUE_NAME@ +#define __db_init_recover __db_init_recover@DB_VERSION_UNIQUE_NAME@ +#define __db_addrem_print __db_addrem_print@DB_VERSION_UNIQUE_NAME@ +#define __db_big_print __db_big_print@DB_VERSION_UNIQUE_NAME@ +#define __db_ovref_print __db_ovref_print@DB_VERSION_UNIQUE_NAME@ +#define __db_debug_print __db_debug_print@DB_VERSION_UNIQUE_NAME@ +#define __db_noop_print __db_noop_print@DB_VERSION_UNIQUE_NAME@ +#define __db_pg_alloc_print __db_pg_alloc_print@DB_VERSION_UNIQUE_NAME@ +#define __db_pg_free_print __db_pg_free_print@DB_VERSION_UNIQUE_NAME@ +#define __db_cksum_print __db_cksum_print@DB_VERSION_UNIQUE_NAME@ +#define __db_pg_freedata_print __db_pg_freedata_print@DB_VERSION_UNIQUE_NAME@ +#define __db_pg_prepare_print __db_pg_prepare_print@DB_VERSION_UNIQUE_NAME@ +#define __db_pg_new_print __db_pg_new_print@DB_VERSION_UNIQUE_NAME@ +#define __db_pg_init_print __db_pg_init_print@DB_VERSION_UNIQUE_NAME@ +#define __db_init_print __db_init_print@DB_VERSION_UNIQUE_NAME@ +#define __db_c_close __db_c_close@DB_VERSION_UNIQUE_NAME@ +#define __db_c_destroy __db_c_destroy@DB_VERSION_UNIQUE_NAME@ +#define __db_c_count __db_c_count@DB_VERSION_UNIQUE_NAME@ +#define __db_c_del __db_c_del@DB_VERSION_UNIQUE_NAME@ +#define __db_c_dup __db_c_dup@DB_VERSION_UNIQUE_NAME@ +#define __db_c_idup __db_c_idup@DB_VERSION_UNIQUE_NAME@ +#define __db_c_newopd __db_c_newopd@DB_VERSION_UNIQUE_NAME@ +#define __db_c_get __db_c_get@DB_VERSION_UNIQUE_NAME@ +#define __db_c_put __db_c_put@DB_VERSION_UNIQUE_NAME@ +#define __db_duperr __db_duperr@DB_VERSION_UNIQUE_NAME@ +#define __db_c_secondary_get_pp __db_c_secondary_get_pp@DB_VERSION_UNIQUE_NAME@ +#define __db_c_pget __db_c_pget@DB_VERSION_UNIQUE_NAME@ +#define __db_c_del_primary __db_c_del_primary@DB_VERSION_UNIQUE_NAME@ +#define __db_s_first __db_s_first@DB_VERSION_UNIQUE_NAME@ +#define __db_s_next __db_s_next@DB_VERSION_UNIQUE_NAME@ +#define __db_s_done __db_s_done@DB_VERSION_UNIQUE_NAME@ +#define __db_partsize __db_partsize@DB_VERSION_UNIQUE_NAME@ +#define __db_pgin __db_pgin@DB_VERSION_UNIQUE_NAME@ +#define __db_pgout __db_pgout@DB_VERSION_UNIQUE_NAME@ +#define __db_metaswap __db_metaswap@DB_VERSION_UNIQUE_NAME@ +#define __db_byteswap __db_byteswap@DB_VERSION_UNIQUE_NAME@ +#define __db_dispatch __db_dispatch@DB_VERSION_UNIQUE_NAME@ +#define __db_add_recovery __db_add_recovery@DB_VERSION_UNIQUE_NAME@ +#define __db_txnlist_init __db_txnlist_init@DB_VERSION_UNIQUE_NAME@ +#define __db_txnlist_add __db_txnlist_add@DB_VERSION_UNIQUE_NAME@ +#define __db_txnlist_remove __db_txnlist_remove@DB_VERSION_UNIQUE_NAME@ +#define __db_txnlist_ckp __db_txnlist_ckp@DB_VERSION_UNIQUE_NAME@ +#define __db_txnlist_end __db_txnlist_end@DB_VERSION_UNIQUE_NAME@ +#define __db_txnlist_find __db_txnlist_find@DB_VERSION_UNIQUE_NAME@ +#define __db_txnlist_update __db_txnlist_update@DB_VERSION_UNIQUE_NAME@ +#define __db_txnlist_gen __db_txnlist_gen@DB_VERSION_UNIQUE_NAME@ +#define __db_txnlist_lsnadd __db_txnlist_lsnadd@DB_VERSION_UNIQUE_NAME@ +#define __db_txnlist_lsninit __db_txnlist_lsninit@DB_VERSION_UNIQUE_NAME@ +#ifndef HAVE_FTRUNCATE +#define __db_add_limbo __db_add_limbo@DB_VERSION_UNIQUE_NAME@ +#endif +#ifndef HAVE_FTRUNCATE +#define __db_do_the_limbo __db_do_the_limbo@DB_VERSION_UNIQUE_NAME@ +#endif +#define __db_txnlist_print __db_txnlist_print@DB_VERSION_UNIQUE_NAME@ +#define __db_ditem __db_ditem@DB_VERSION_UNIQUE_NAME@ +#define __db_pitem __db_pitem@DB_VERSION_UNIQUE_NAME@ +#define __db_associate_pp __db_associate_pp@DB_VERSION_UNIQUE_NAME@ +#define __db_close_pp __db_close_pp@DB_VERSION_UNIQUE_NAME@ +#define __db_cursor_pp __db_cursor_pp@DB_VERSION_UNIQUE_NAME@ +#define __db_cursor __db_cursor@DB_VERSION_UNIQUE_NAME@ +#define __db_del_pp __db_del_pp@DB_VERSION_UNIQUE_NAME@ +#define __db_fd_pp __db_fd_pp@DB_VERSION_UNIQUE_NAME@ +#define __db_get_pp __db_get_pp@DB_VERSION_UNIQUE_NAME@ +#define __db_get __db_get@DB_VERSION_UNIQUE_NAME@ +#define __db_join_pp __db_join_pp@DB_VERSION_UNIQUE_NAME@ +#define __db_key_range_pp __db_key_range_pp@DB_VERSION_UNIQUE_NAME@ +#define __db_open_pp __db_open_pp@DB_VERSION_UNIQUE_NAME@ +#define __db_pget_pp __db_pget_pp@DB_VERSION_UNIQUE_NAME@ +#define __db_pget __db_pget@DB_VERSION_UNIQUE_NAME@ +#define __db_put_pp __db_put_pp@DB_VERSION_UNIQUE_NAME@ +#define __db_sync_pp __db_sync_pp@DB_VERSION_UNIQUE_NAME@ +#define __db_c_close_pp __db_c_close_pp@DB_VERSION_UNIQUE_NAME@ +#define __db_c_count_pp __db_c_count_pp@DB_VERSION_UNIQUE_NAME@ +#define __db_c_del_pp __db_c_del_pp@DB_VERSION_UNIQUE_NAME@ +#define __db_c_del_arg __db_c_del_arg@DB_VERSION_UNIQUE_NAME@ +#define __db_c_dup_pp __db_c_dup_pp@DB_VERSION_UNIQUE_NAME@ +#define __db_c_get_pp __db_c_get_pp@DB_VERSION_UNIQUE_NAME@ +#define __db_secondary_close_pp __db_secondary_close_pp@DB_VERSION_UNIQUE_NAME@ +#define __db_c_pget_pp __db_c_pget_pp@DB_VERSION_UNIQUE_NAME@ +#define __db_c_put_pp __db_c_put_pp@DB_VERSION_UNIQUE_NAME@ +#define __db_txn_auto_init __db_txn_auto_init@DB_VERSION_UNIQUE_NAME@ +#define __db_txn_auto_resolve __db_txn_auto_resolve@DB_VERSION_UNIQUE_NAME@ +#define __db_join __db_join@DB_VERSION_UNIQUE_NAME@ +#define __db_join_close __db_join_close@DB_VERSION_UNIQUE_NAME@ +#define __db_secondary_corrupt __db_secondary_corrupt@DB_VERSION_UNIQUE_NAME@ +#define __db_new __db_new@DB_VERSION_UNIQUE_NAME@ +#define __db_free __db_free@DB_VERSION_UNIQUE_NAME@ +#define __db_lprint __db_lprint@DB_VERSION_UNIQUE_NAME@ +#define __db_lget __db_lget@DB_VERSION_UNIQUE_NAME@ +#define __db_lput __db_lput@DB_VERSION_UNIQUE_NAME@ +#define __dbh_am_chk __dbh_am_chk@DB_VERSION_UNIQUE_NAME@ +#define __db_get_flags __db_get_flags@DB_VERSION_UNIQUE_NAME@ +#define __db_set_flags __db_set_flags@DB_VERSION_UNIQUE_NAME@ +#define __db_get_lorder __db_get_lorder@DB_VERSION_UNIQUE_NAME@ +#define __db_set_lorder __db_set_lorder@DB_VERSION_UNIQUE_NAME@ +#define __db_set_pagesize __db_set_pagesize@DB_VERSION_UNIQUE_NAME@ +#define __db_open __db_open@DB_VERSION_UNIQUE_NAME@ +#define __db_get_open_flags __db_get_open_flags@DB_VERSION_UNIQUE_NAME@ +#define __db_new_file __db_new_file@DB_VERSION_UNIQUE_NAME@ +#define __db_init_subdb __db_init_subdb@DB_VERSION_UNIQUE_NAME@ +#define __db_chk_meta __db_chk_meta@DB_VERSION_UNIQUE_NAME@ +#define __db_meta_setup __db_meta_setup@DB_VERSION_UNIQUE_NAME@ +#define __db_goff __db_goff@DB_VERSION_UNIQUE_NAME@ +#define __db_poff __db_poff@DB_VERSION_UNIQUE_NAME@ +#define __db_ovref __db_ovref@DB_VERSION_UNIQUE_NAME@ +#define __db_doff __db_doff@DB_VERSION_UNIQUE_NAME@ +#define __db_moff __db_moff@DB_VERSION_UNIQUE_NAME@ +#define __db_vrfy_overflow __db_vrfy_overflow@DB_VERSION_UNIQUE_NAME@ +#define __db_vrfy_ovfl_structure __db_vrfy_ovfl_structure@DB_VERSION_UNIQUE_NAME@ +#define __db_safe_goff __db_safe_goff@DB_VERSION_UNIQUE_NAME@ +#define __db_loadme __db_loadme@DB_VERSION_UNIQUE_NAME@ +#define __db_dumptree __db_dumptree@DB_VERSION_UNIQUE_NAME@ +#define __db_get_flags_fn __db_get_flags_fn@DB_VERSION_UNIQUE_NAME@ +#define __db_prnpage __db_prnpage@DB_VERSION_UNIQUE_NAME@ +#define __db_prpage __db_prpage@DB_VERSION_UNIQUE_NAME@ +#define __db_pr __db_pr@DB_VERSION_UNIQUE_NAME@ +#define __db_prflags __db_prflags@DB_VERSION_UNIQUE_NAME@ +#define __db_lockmode_to_string __db_lockmode_to_string@DB_VERSION_UNIQUE_NAME@ +#define __db_dumptree __db_dumptree@DB_VERSION_UNIQUE_NAME@ +#define __db_get_flags_fn __db_get_flags_fn@DB_VERSION_UNIQUE_NAME@ +#define __db_dump_pp __db_dump_pp@DB_VERSION_UNIQUE_NAME@ +#define __db_dump __db_dump@DB_VERSION_UNIQUE_NAME@ +#define __db_prdbt __db_prdbt@DB_VERSION_UNIQUE_NAME@ +#define __db_prheader __db_prheader@DB_VERSION_UNIQUE_NAME@ +#define __db_prfooter __db_prfooter@DB_VERSION_UNIQUE_NAME@ +#define __db_pr_callback __db_pr_callback@DB_VERSION_UNIQUE_NAME@ +#define __db_dbtype_to_string __db_dbtype_to_string@DB_VERSION_UNIQUE_NAME@ +#define __db_addrem_recover __db_addrem_recover@DB_VERSION_UNIQUE_NAME@ +#define __db_big_recover __db_big_recover@DB_VERSION_UNIQUE_NAME@ +#define __db_ovref_recover __db_ovref_recover@DB_VERSION_UNIQUE_NAME@ +#define __db_debug_recover __db_debug_recover@DB_VERSION_UNIQUE_NAME@ +#define __db_noop_recover __db_noop_recover@DB_VERSION_UNIQUE_NAME@ +#define __db_pg_alloc_recover __db_pg_alloc_recover@DB_VERSION_UNIQUE_NAME@ +#define __db_pg_free_recover __db_pg_free_recover@DB_VERSION_UNIQUE_NAME@ +#define __db_pg_new_recover __db_pg_new_recover@DB_VERSION_UNIQUE_NAME@ +#define __db_pg_freedata_recover __db_pg_freedata_recover@DB_VERSION_UNIQUE_NAME@ +#define __db_cksum_recover __db_cksum_recover@DB_VERSION_UNIQUE_NAME@ +#define __db_pg_prepare_recover __db_pg_prepare_recover@DB_VERSION_UNIQUE_NAME@ +#define __db_pg_init_recover __db_pg_init_recover@DB_VERSION_UNIQUE_NAME@ +#define __db_traverse_big __db_traverse_big@DB_VERSION_UNIQUE_NAME@ +#define __db_reclaim_callback __db_reclaim_callback@DB_VERSION_UNIQUE_NAME@ +#define __db_truncate_callback __db_truncate_callback@DB_VERSION_UNIQUE_NAME@ +#define __dbenv_dbremove_pp __dbenv_dbremove_pp@DB_VERSION_UNIQUE_NAME@ +#define __db_remove_pp __db_remove_pp@DB_VERSION_UNIQUE_NAME@ +#define __db_remove __db_remove@DB_VERSION_UNIQUE_NAME@ +#define __db_remove_int __db_remove_int@DB_VERSION_UNIQUE_NAME@ +#define __dbenv_dbrename_pp __dbenv_dbrename_pp@DB_VERSION_UNIQUE_NAME@ +#define __db_rename_pp __db_rename_pp@DB_VERSION_UNIQUE_NAME@ +#define __db_rename __db_rename@DB_VERSION_UNIQUE_NAME@ +#define __db_rename_int __db_rename_int@DB_VERSION_UNIQUE_NAME@ +#define __db_ret __db_ret@DB_VERSION_UNIQUE_NAME@ +#define __db_retcopy __db_retcopy@DB_VERSION_UNIQUE_NAME@ +#define __db_fileid_reset __db_fileid_reset@DB_VERSION_UNIQUE_NAME@ +#define __db_lsn_reset __db_lsn_reset@DB_VERSION_UNIQUE_NAME@ +#define __db_stat_pp __db_stat_pp@DB_VERSION_UNIQUE_NAME@ +#define __db_stat __db_stat@DB_VERSION_UNIQUE_NAME@ +#define __db_stat_print_pp __db_stat_print_pp@DB_VERSION_UNIQUE_NAME@ +#define __db_stat_print __db_stat_print@DB_VERSION_UNIQUE_NAME@ +#define __db_truncate_pp __db_truncate_pp@DB_VERSION_UNIQUE_NAME@ +#define __db_truncate __db_truncate@DB_VERSION_UNIQUE_NAME@ +#define __db_upgrade_pp __db_upgrade_pp@DB_VERSION_UNIQUE_NAME@ +#define __db_upgrade __db_upgrade@DB_VERSION_UNIQUE_NAME@ +#define __db_lastpgno __db_lastpgno@DB_VERSION_UNIQUE_NAME@ +#define __db_31_offdup __db_31_offdup@DB_VERSION_UNIQUE_NAME@ +#define __db_verify_pp __db_verify_pp@DB_VERSION_UNIQUE_NAME@ +#define __db_verify_internal __db_verify_internal@DB_VERSION_UNIQUE_NAME@ +#define __db_vrfy_common __db_vrfy_common@DB_VERSION_UNIQUE_NAME@ +#define __db_vrfy_datapage __db_vrfy_datapage@DB_VERSION_UNIQUE_NAME@ +#define __db_vrfy_meta __db_vrfy_meta@DB_VERSION_UNIQUE_NAME@ +#define __db_vrfy_struct_feedback __db_vrfy_struct_feedback@DB_VERSION_UNIQUE_NAME@ +#define __db_salvage __db_salvage@DB_VERSION_UNIQUE_NAME@ +#define __db_vrfy_inpitem __db_vrfy_inpitem@DB_VERSION_UNIQUE_NAME@ +#define __db_vrfy_duptype __db_vrfy_duptype@DB_VERSION_UNIQUE_NAME@ +#define __db_salvage_duptree __db_salvage_duptree@DB_VERSION_UNIQUE_NAME@ +#define __db_vrfy_dbinfo_create __db_vrfy_dbinfo_create@DB_VERSION_UNIQUE_NAME@ +#define __db_vrfy_dbinfo_destroy __db_vrfy_dbinfo_destroy@DB_VERSION_UNIQUE_NAME@ +#define __db_vrfy_getpageinfo __db_vrfy_getpageinfo@DB_VERSION_UNIQUE_NAME@ +#define __db_vrfy_putpageinfo __db_vrfy_putpageinfo@DB_VERSION_UNIQUE_NAME@ +#define __db_vrfy_pgset __db_vrfy_pgset@DB_VERSION_UNIQUE_NAME@ +#define __db_vrfy_pgset_get __db_vrfy_pgset_get@DB_VERSION_UNIQUE_NAME@ +#define __db_vrfy_pgset_inc __db_vrfy_pgset_inc@DB_VERSION_UNIQUE_NAME@ +#define __db_vrfy_pgset_next __db_vrfy_pgset_next@DB_VERSION_UNIQUE_NAME@ +#define __db_vrfy_childcursor __db_vrfy_childcursor@DB_VERSION_UNIQUE_NAME@ +#define __db_vrfy_childput __db_vrfy_childput@DB_VERSION_UNIQUE_NAME@ +#define __db_vrfy_ccset __db_vrfy_ccset@DB_VERSION_UNIQUE_NAME@ +#define __db_vrfy_ccnext __db_vrfy_ccnext@DB_VERSION_UNIQUE_NAME@ +#define __db_vrfy_ccclose __db_vrfy_ccclose@DB_VERSION_UNIQUE_NAME@ +#define __db_salvage_init __db_salvage_init@DB_VERSION_UNIQUE_NAME@ +#define __db_salvage_destroy __db_salvage_destroy@DB_VERSION_UNIQUE_NAME@ +#define __db_salvage_getnext __db_salvage_getnext@DB_VERSION_UNIQUE_NAME@ +#define __db_salvage_isdone __db_salvage_isdone@DB_VERSION_UNIQUE_NAME@ +#define __db_salvage_markdone __db_salvage_markdone@DB_VERSION_UNIQUE_NAME@ +#define __db_salvage_markneeded __db_salvage_markneeded@DB_VERSION_UNIQUE_NAME@ +#define __db_vrfy_prdbt __db_vrfy_prdbt@DB_VERSION_UNIQUE_NAME@ +#define __bam_cmp __bam_cmp@DB_VERSION_UNIQUE_NAME@ +#define __bam_defcmp __bam_defcmp@DB_VERSION_UNIQUE_NAME@ +#define __bam_defpfx __bam_defpfx@DB_VERSION_UNIQUE_NAME@ +#define __bam_pgin __bam_pgin@DB_VERSION_UNIQUE_NAME@ +#define __bam_pgout __bam_pgout@DB_VERSION_UNIQUE_NAME@ +#define __bam_mswap __bam_mswap@DB_VERSION_UNIQUE_NAME@ +#define __bam_ca_delete __bam_ca_delete@DB_VERSION_UNIQUE_NAME@ +#define __ram_ca_delete __ram_ca_delete@DB_VERSION_UNIQUE_NAME@ +#define __bam_ca_di __bam_ca_di@DB_VERSION_UNIQUE_NAME@ +#define __bam_ca_dup __bam_ca_dup@DB_VERSION_UNIQUE_NAME@ +#define __bam_ca_undodup __bam_ca_undodup@DB_VERSION_UNIQUE_NAME@ +#define __bam_ca_rsplit __bam_ca_rsplit@DB_VERSION_UNIQUE_NAME@ +#define __bam_ca_split __bam_ca_split@DB_VERSION_UNIQUE_NAME@ +#define __bam_ca_undosplit __bam_ca_undosplit@DB_VERSION_UNIQUE_NAME@ +#define __bam_c_init __bam_c_init@DB_VERSION_UNIQUE_NAME@ +#define __bam_c_refresh __bam_c_refresh@DB_VERSION_UNIQUE_NAME@ +#define __bam_c_count __bam_c_count@DB_VERSION_UNIQUE_NAME@ +#define __bam_c_dup __bam_c_dup@DB_VERSION_UNIQUE_NAME@ +#define __bam_bulk_overflow __bam_bulk_overflow@DB_VERSION_UNIQUE_NAME@ +#define __bam_bulk_duplicates __bam_bulk_duplicates@DB_VERSION_UNIQUE_NAME@ +#define __bam_c_rget __bam_c_rget@DB_VERSION_UNIQUE_NAME@ +#define __bam_ditem __bam_ditem@DB_VERSION_UNIQUE_NAME@ +#define __bam_adjindx __bam_adjindx@DB_VERSION_UNIQUE_NAME@ +#define __bam_dpages __bam_dpages@DB_VERSION_UNIQUE_NAME@ +#define __bam_relink __bam_relink@DB_VERSION_UNIQUE_NAME@ +#define __bam_db_create __bam_db_create@DB_VERSION_UNIQUE_NAME@ +#define __bam_db_close __bam_db_close@DB_VERSION_UNIQUE_NAME@ +#define __bam_map_flags __bam_map_flags@DB_VERSION_UNIQUE_NAME@ +#define __bam_set_flags __bam_set_flags@DB_VERSION_UNIQUE_NAME@ +#define __bam_set_bt_compare __bam_set_bt_compare@DB_VERSION_UNIQUE_NAME@ +#define __bam_get_bt_minkey __bam_get_bt_minkey@DB_VERSION_UNIQUE_NAME@ +#define __ram_map_flags __ram_map_flags@DB_VERSION_UNIQUE_NAME@ +#define __ram_set_flags __ram_set_flags@DB_VERSION_UNIQUE_NAME@ +#define __ram_get_re_len __ram_get_re_len@DB_VERSION_UNIQUE_NAME@ +#define __ram_get_re_pad __ram_get_re_pad@DB_VERSION_UNIQUE_NAME@ +#define __bam_open __bam_open@DB_VERSION_UNIQUE_NAME@ +#define __bam_metachk __bam_metachk@DB_VERSION_UNIQUE_NAME@ +#define __bam_read_root __bam_read_root@DB_VERSION_UNIQUE_NAME@ +#define __bam_new_file __bam_new_file@DB_VERSION_UNIQUE_NAME@ +#define __bam_new_subdb __bam_new_subdb@DB_VERSION_UNIQUE_NAME@ +#define __bam_iitem __bam_iitem@DB_VERSION_UNIQUE_NAME@ +#define __bam_ritem __bam_ritem@DB_VERSION_UNIQUE_NAME@ +#define __bam_split_recover __bam_split_recover@DB_VERSION_UNIQUE_NAME@ +#define __bam_rsplit_recover __bam_rsplit_recover@DB_VERSION_UNIQUE_NAME@ +#define __bam_adj_recover __bam_adj_recover@DB_VERSION_UNIQUE_NAME@ +#define __bam_cadjust_recover __bam_cadjust_recover@DB_VERSION_UNIQUE_NAME@ +#define __bam_cdel_recover __bam_cdel_recover@DB_VERSION_UNIQUE_NAME@ +#define __bam_repl_recover __bam_repl_recover@DB_VERSION_UNIQUE_NAME@ +#define __bam_root_recover __bam_root_recover@DB_VERSION_UNIQUE_NAME@ +#define __bam_curadj_recover __bam_curadj_recover@DB_VERSION_UNIQUE_NAME@ +#define __bam_rcuradj_recover __bam_rcuradj_recover@DB_VERSION_UNIQUE_NAME@ +#define __bam_relink_recover __bam_relink_recover@DB_VERSION_UNIQUE_NAME@ +#define __bam_reclaim __bam_reclaim@DB_VERSION_UNIQUE_NAME@ +#define __bam_truncate __bam_truncate@DB_VERSION_UNIQUE_NAME@ +#define __ram_open __ram_open@DB_VERSION_UNIQUE_NAME@ +#define __ram_append __ram_append@DB_VERSION_UNIQUE_NAME@ +#define __ram_c_del __ram_c_del@DB_VERSION_UNIQUE_NAME@ +#define __ram_c_get __ram_c_get@DB_VERSION_UNIQUE_NAME@ +#define __ram_c_put __ram_c_put@DB_VERSION_UNIQUE_NAME@ +#define __ram_ca __ram_ca@DB_VERSION_UNIQUE_NAME@ +#define __ram_getno __ram_getno@DB_VERSION_UNIQUE_NAME@ +#define __ram_writeback __ram_writeback@DB_VERSION_UNIQUE_NAME@ +#define __bam_rsearch __bam_rsearch@DB_VERSION_UNIQUE_NAME@ +#define __bam_adjust __bam_adjust@DB_VERSION_UNIQUE_NAME@ +#define __bam_nrecs __bam_nrecs@DB_VERSION_UNIQUE_NAME@ +#define __bam_total __bam_total@DB_VERSION_UNIQUE_NAME@ +#define __bam_search __bam_search@DB_VERSION_UNIQUE_NAME@ +#define __bam_stkrel __bam_stkrel@DB_VERSION_UNIQUE_NAME@ +#define __bam_stkgrow __bam_stkgrow@DB_VERSION_UNIQUE_NAME@ +#define __bam_split __bam_split@DB_VERSION_UNIQUE_NAME@ +#define __bam_copy __bam_copy@DB_VERSION_UNIQUE_NAME@ +#define __bam_stat __bam_stat@DB_VERSION_UNIQUE_NAME@ +#define __bam_stat_print __bam_stat_print@DB_VERSION_UNIQUE_NAME@ +#define __bam_stat_callback __bam_stat_callback@DB_VERSION_UNIQUE_NAME@ +#define __bam_print_cursor __bam_print_cursor@DB_VERSION_UNIQUE_NAME@ +#define __bam_key_range __bam_key_range@DB_VERSION_UNIQUE_NAME@ +#define __bam_traverse __bam_traverse@DB_VERSION_UNIQUE_NAME@ +#define __bam_30_btreemeta __bam_30_btreemeta@DB_VERSION_UNIQUE_NAME@ +#define __bam_31_btreemeta __bam_31_btreemeta@DB_VERSION_UNIQUE_NAME@ +#define __bam_31_lbtree __bam_31_lbtree@DB_VERSION_UNIQUE_NAME@ +#define __bam_vrfy_meta __bam_vrfy_meta@DB_VERSION_UNIQUE_NAME@ +#define __ram_vrfy_leaf __ram_vrfy_leaf@DB_VERSION_UNIQUE_NAME@ +#define __bam_vrfy __bam_vrfy@DB_VERSION_UNIQUE_NAME@ +#define __bam_vrfy_itemorder __bam_vrfy_itemorder@DB_VERSION_UNIQUE_NAME@ +#define __bam_vrfy_structure __bam_vrfy_structure@DB_VERSION_UNIQUE_NAME@ +#define __bam_vrfy_subtree __bam_vrfy_subtree@DB_VERSION_UNIQUE_NAME@ +#define __bam_salvage __bam_salvage@DB_VERSION_UNIQUE_NAME@ +#define __bam_salvage_walkdupint __bam_salvage_walkdupint@DB_VERSION_UNIQUE_NAME@ +#define __bam_meta2pgset __bam_meta2pgset@DB_VERSION_UNIQUE_NAME@ +#define __bam_split_log __bam_split_log@DB_VERSION_UNIQUE_NAME@ +#define __bam_split_read __bam_split_read@DB_VERSION_UNIQUE_NAME@ +#define __bam_rsplit_log __bam_rsplit_log@DB_VERSION_UNIQUE_NAME@ +#define __bam_rsplit_read __bam_rsplit_read@DB_VERSION_UNIQUE_NAME@ +#define __bam_adj_log __bam_adj_log@DB_VERSION_UNIQUE_NAME@ +#define __bam_adj_read __bam_adj_read@DB_VERSION_UNIQUE_NAME@ +#define __bam_cadjust_log __bam_cadjust_log@DB_VERSION_UNIQUE_NAME@ +#define __bam_cadjust_read __bam_cadjust_read@DB_VERSION_UNIQUE_NAME@ +#define __bam_cdel_log __bam_cdel_log@DB_VERSION_UNIQUE_NAME@ +#define __bam_cdel_read __bam_cdel_read@DB_VERSION_UNIQUE_NAME@ +#define __bam_repl_log __bam_repl_log@DB_VERSION_UNIQUE_NAME@ +#define __bam_repl_read __bam_repl_read@DB_VERSION_UNIQUE_NAME@ +#define __bam_root_log __bam_root_log@DB_VERSION_UNIQUE_NAME@ +#define __bam_root_read __bam_root_read@DB_VERSION_UNIQUE_NAME@ +#define __bam_curadj_log __bam_curadj_log@DB_VERSION_UNIQUE_NAME@ +#define __bam_curadj_read __bam_curadj_read@DB_VERSION_UNIQUE_NAME@ +#define __bam_rcuradj_log __bam_rcuradj_log@DB_VERSION_UNIQUE_NAME@ +#define __bam_rcuradj_read __bam_rcuradj_read@DB_VERSION_UNIQUE_NAME@ +#define __bam_relink_log __bam_relink_log@DB_VERSION_UNIQUE_NAME@ +#define __bam_relink_read __bam_relink_read@DB_VERSION_UNIQUE_NAME@ +#define __bam_init_recover __bam_init_recover@DB_VERSION_UNIQUE_NAME@ +#define __bam_split_print __bam_split_print@DB_VERSION_UNIQUE_NAME@ +#define __bam_rsplit_print __bam_rsplit_print@DB_VERSION_UNIQUE_NAME@ +#define __bam_adj_print __bam_adj_print@DB_VERSION_UNIQUE_NAME@ +#define __bam_cadjust_print __bam_cadjust_print@DB_VERSION_UNIQUE_NAME@ +#define __bam_cdel_print __bam_cdel_print@DB_VERSION_UNIQUE_NAME@ +#define __bam_repl_print __bam_repl_print@DB_VERSION_UNIQUE_NAME@ +#define __bam_root_print __bam_root_print@DB_VERSION_UNIQUE_NAME@ +#define __bam_curadj_print __bam_curadj_print@DB_VERSION_UNIQUE_NAME@ +#define __bam_rcuradj_print __bam_rcuradj_print@DB_VERSION_UNIQUE_NAME@ +#define __bam_relink_print __bam_relink_print@DB_VERSION_UNIQUE_NAME@ +#define __bam_init_print __bam_init_print@DB_VERSION_UNIQUE_NAME@ +#ifndef HAVE_GETCWD +#define getcwd getcwd@DB_VERSION_UNIQUE_NAME@ +#endif +#ifndef HAVE_GETOPT +#define getopt getopt@DB_VERSION_UNIQUE_NAME@ +#endif +#ifndef HAVE_MEMCMP +#define memcmp memcmp@DB_VERSION_UNIQUE_NAME@ +#endif +#ifndef HAVE_MEMCPY +#define memcpy memcpy@DB_VERSION_UNIQUE_NAME@ +#endif +#ifndef HAVE_MEMMOVE +#define memmove memmove@DB_VERSION_UNIQUE_NAME@ +#endif +#ifndef HAVE_RAISE +#define raise raise@DB_VERSION_UNIQUE_NAME@ +#endif +#ifndef HAVE_SNPRINTF +#define snprintf snprintf@DB_VERSION_UNIQUE_NAME@ +#endif +#ifndef HAVE_VSNPRINTF +#define vsnprintf vsnprintf@DB_VERSION_UNIQUE_NAME@ +#endif +#ifndef HAVE_STRCASECMP +#define strcasecmp strcasecmp@DB_VERSION_UNIQUE_NAME@ +#endif +#ifndef HAVE_STRCASECMP +#define strncasecmp strncasecmp@DB_VERSION_UNIQUE_NAME@ +#endif +#ifndef HAVE_STRDUP +#define strdup strdup@DB_VERSION_UNIQUE_NAME@ +#endif +#ifndef HAVE_STRERROR +#define strerror strerror@DB_VERSION_UNIQUE_NAME@ +#endif +#define __crypto_region_init __crypto_region_init@DB_VERSION_UNIQUE_NAME@ +#define __db_isbigendian __db_isbigendian@DB_VERSION_UNIQUE_NAME@ +#define __db_byteorder __db_byteorder@DB_VERSION_UNIQUE_NAME@ +#define __db_fchk __db_fchk@DB_VERSION_UNIQUE_NAME@ +#define __db_fcchk __db_fcchk@DB_VERSION_UNIQUE_NAME@ +#define __db_ferr __db_ferr@DB_VERSION_UNIQUE_NAME@ +#define __db_fnl __db_fnl@DB_VERSION_UNIQUE_NAME@ +#define __db_pgerr __db_pgerr@DB_VERSION_UNIQUE_NAME@ +#define __db_pgfmt __db_pgfmt@DB_VERSION_UNIQUE_NAME@ +#ifdef DIAGNOSTIC +#define __db_assert __db_assert@DB_VERSION_UNIQUE_NAME@ +#endif +#define __db_panic_msg __db_panic_msg@DB_VERSION_UNIQUE_NAME@ +#define __db_panic __db_panic@DB_VERSION_UNIQUE_NAME@ +#define __db_err __db_err@DB_VERSION_UNIQUE_NAME@ +#define __db_errcall __db_errcall@DB_VERSION_UNIQUE_NAME@ +#define __db_errfile __db_errfile@DB_VERSION_UNIQUE_NAME@ +#define __db_msgadd __db_msgadd@DB_VERSION_UNIQUE_NAME@ +#define __db_msg __db_msg@DB_VERSION_UNIQUE_NAME@ +#define __db_logmsg __db_logmsg@DB_VERSION_UNIQUE_NAME@ +#define __db_unknown_flag __db_unknown_flag@DB_VERSION_UNIQUE_NAME@ +#define __db_unknown_type __db_unknown_type@DB_VERSION_UNIQUE_NAME@ +#define __db_check_txn __db_check_txn@DB_VERSION_UNIQUE_NAME@ +#define __db_not_txn_env __db_not_txn_env@DB_VERSION_UNIQUE_NAME@ +#define __db_rec_toobig __db_rec_toobig@DB_VERSION_UNIQUE_NAME@ +#define __db_rec_repl __db_rec_repl@DB_VERSION_UNIQUE_NAME@ +#define __db_check_lsn __db_check_lsn@DB_VERSION_UNIQUE_NAME@ +#define __db_getlong __db_getlong@DB_VERSION_UNIQUE_NAME@ +#define __db_getulong __db_getulong@DB_VERSION_UNIQUE_NAME@ +#define __db_idspace __db_idspace@DB_VERSION_UNIQUE_NAME@ +#define __db_log2 __db_log2@DB_VERSION_UNIQUE_NAME@ +#define __db_util_arg __db_util_arg@DB_VERSION_UNIQUE_NAME@ +#define __db_util_cache __db_util_cache@DB_VERSION_UNIQUE_NAME@ +#define __db_util_logset __db_util_logset@DB_VERSION_UNIQUE_NAME@ +#define __db_util_siginit __db_util_siginit@DB_VERSION_UNIQUE_NAME@ +#define __db_util_interrupted __db_util_interrupted@DB_VERSION_UNIQUE_NAME@ +#define __db_util_sigresend __db_util_sigresend@DB_VERSION_UNIQUE_NAME@ +#define __aes_setup __aes_setup@DB_VERSION_UNIQUE_NAME@ +#define __aes_adj_size __aes_adj_size@DB_VERSION_UNIQUE_NAME@ +#define __aes_close __aes_close@DB_VERSION_UNIQUE_NAME@ +#define __aes_decrypt __aes_decrypt@DB_VERSION_UNIQUE_NAME@ +#define __aes_encrypt __aes_encrypt@DB_VERSION_UNIQUE_NAME@ +#define __aes_init __aes_init@DB_VERSION_UNIQUE_NAME@ +#define __crypto_dbenv_close __crypto_dbenv_close@DB_VERSION_UNIQUE_NAME@ +#define __crypto_region_destroy __crypto_region_destroy@DB_VERSION_UNIQUE_NAME@ +#define __crypto_algsetup __crypto_algsetup@DB_VERSION_UNIQUE_NAME@ +#define __crypto_decrypt_meta __crypto_decrypt_meta@DB_VERSION_UNIQUE_NAME@ +#define __crypto_set_passwd __crypto_set_passwd@DB_VERSION_UNIQUE_NAME@ +#define __db_generate_iv __db_generate_iv@DB_VERSION_UNIQUE_NAME@ +#define __db_rijndaelKeySetupEnc __db_rijndaelKeySetupEnc@DB_VERSION_UNIQUE_NAME@ +#define __db_rijndaelKeySetupDec __db_rijndaelKeySetupDec@DB_VERSION_UNIQUE_NAME@ +#define __db_rijndaelEncrypt __db_rijndaelEncrypt@DB_VERSION_UNIQUE_NAME@ +#define __db_rijndaelDecrypt __db_rijndaelDecrypt@DB_VERSION_UNIQUE_NAME@ +#define __db_rijndaelEncryptRound __db_rijndaelEncryptRound@DB_VERSION_UNIQUE_NAME@ +#define __db_rijndaelDecryptRound __db_rijndaelDecryptRound@DB_VERSION_UNIQUE_NAME@ +#define __db_makeKey __db_makeKey@DB_VERSION_UNIQUE_NAME@ +#define __db_cipherInit __db_cipherInit@DB_VERSION_UNIQUE_NAME@ +#define __db_blockEncrypt __db_blockEncrypt@DB_VERSION_UNIQUE_NAME@ +#define __db_padEncrypt __db_padEncrypt@DB_VERSION_UNIQUE_NAME@ +#define __db_blockDecrypt __db_blockDecrypt@DB_VERSION_UNIQUE_NAME@ +#define __db_padDecrypt __db_padDecrypt@DB_VERSION_UNIQUE_NAME@ +#define __db_cipherUpdateRounds __db_cipherUpdateRounds@DB_VERSION_UNIQUE_NAME@ +#define __dbreg_setup __dbreg_setup@DB_VERSION_UNIQUE_NAME@ +#define __dbreg_teardown __dbreg_teardown@DB_VERSION_UNIQUE_NAME@ +#define __dbreg_new_id __dbreg_new_id@DB_VERSION_UNIQUE_NAME@ +#define __dbreg_get_id __dbreg_get_id@DB_VERSION_UNIQUE_NAME@ +#define __dbreg_assign_id __dbreg_assign_id@DB_VERSION_UNIQUE_NAME@ +#define __dbreg_revoke_id __dbreg_revoke_id@DB_VERSION_UNIQUE_NAME@ +#define __dbreg_close_id __dbreg_close_id@DB_VERSION_UNIQUE_NAME@ +#define __dbreg_register_log __dbreg_register_log@DB_VERSION_UNIQUE_NAME@ +#define __dbreg_register_read __dbreg_register_read@DB_VERSION_UNIQUE_NAME@ +#define __dbreg_init_recover __dbreg_init_recover@DB_VERSION_UNIQUE_NAME@ +#define __dbreg_register_print __dbreg_register_print@DB_VERSION_UNIQUE_NAME@ +#define __dbreg_init_print __dbreg_init_print@DB_VERSION_UNIQUE_NAME@ +#define __dbreg_register_recover __dbreg_register_recover@DB_VERSION_UNIQUE_NAME@ +#define __dbreg_print_fname __dbreg_print_fname@DB_VERSION_UNIQUE_NAME@ +#define __dbreg_print_dblist __dbreg_print_dblist@DB_VERSION_UNIQUE_NAME@ +#define __dbreg_add_dbentry __dbreg_add_dbentry@DB_VERSION_UNIQUE_NAME@ +#define __dbreg_rem_dbentry __dbreg_rem_dbentry@DB_VERSION_UNIQUE_NAME@ +#define __dbreg_log_files __dbreg_log_files@DB_VERSION_UNIQUE_NAME@ +#define __dbreg_close_files __dbreg_close_files@DB_VERSION_UNIQUE_NAME@ +#define __dbreg_id_to_db __dbreg_id_to_db@DB_VERSION_UNIQUE_NAME@ +#define __dbreg_id_to_db_int __dbreg_id_to_db_int@DB_VERSION_UNIQUE_NAME@ +#define __dbreg_id_to_fname __dbreg_id_to_fname@DB_VERSION_UNIQUE_NAME@ +#define __dbreg_fid_to_fname __dbreg_fid_to_fname@DB_VERSION_UNIQUE_NAME@ +#define __dbreg_get_name __dbreg_get_name@DB_VERSION_UNIQUE_NAME@ +#define __dbreg_do_open __dbreg_do_open@DB_VERSION_UNIQUE_NAME@ +#define __dbreg_lazy_id __dbreg_lazy_id@DB_VERSION_UNIQUE_NAME@ +#define __db_shalloc_init __db_shalloc_init@DB_VERSION_UNIQUE_NAME@ +#define __db_shalloc_size __db_shalloc_size@DB_VERSION_UNIQUE_NAME@ +#define __db_shalloc __db_shalloc@DB_VERSION_UNIQUE_NAME@ +#define __db_shalloc_free __db_shalloc_free@DB_VERSION_UNIQUE_NAME@ +#define __db_shalloc_sizeof __db_shalloc_sizeof@DB_VERSION_UNIQUE_NAME@ +#define __db_tablesize __db_tablesize@DB_VERSION_UNIQUE_NAME@ +#define __db_hashinit __db_hashinit@DB_VERSION_UNIQUE_NAME@ +#define __db_fileinit __db_fileinit@DB_VERSION_UNIQUE_NAME@ +#define __db_overwrite __db_overwrite@DB_VERSION_UNIQUE_NAME@ +#define __dbenv_set_alloc __dbenv_set_alloc@DB_VERSION_UNIQUE_NAME@ +#define __dbenv_get_encrypt_flags __dbenv_get_encrypt_flags@DB_VERSION_UNIQUE_NAME@ +#define __dbenv_set_encrypt __dbenv_set_encrypt@DB_VERSION_UNIQUE_NAME@ +#define __dbenv_set_flags __dbenv_set_flags@DB_VERSION_UNIQUE_NAME@ +#define __dbenv_set_data_dir __dbenv_set_data_dir@DB_VERSION_UNIQUE_NAME@ +#define __dbenv_set_intermediate_dir __dbenv_set_intermediate_dir@DB_VERSION_UNIQUE_NAME@ +#define __dbenv_set_errcall __dbenv_set_errcall@DB_VERSION_UNIQUE_NAME@ +#define __dbenv_get_errfile __dbenv_get_errfile@DB_VERSION_UNIQUE_NAME@ +#define __dbenv_set_errfile __dbenv_set_errfile@DB_VERSION_UNIQUE_NAME@ +#define __dbenv_get_errpfx __dbenv_get_errpfx@DB_VERSION_UNIQUE_NAME@ +#define __dbenv_set_errpfx __dbenv_set_errpfx@DB_VERSION_UNIQUE_NAME@ +#define __dbenv_set_msgcall __dbenv_set_msgcall@DB_VERSION_UNIQUE_NAME@ +#define __dbenv_get_msgfile __dbenv_get_msgfile@DB_VERSION_UNIQUE_NAME@ +#define __dbenv_set_msgfile __dbenv_set_msgfile@DB_VERSION_UNIQUE_NAME@ +#define __dbenv_set_paniccall __dbenv_set_paniccall@DB_VERSION_UNIQUE_NAME@ +#define __dbenv_set_shm_key __dbenv_set_shm_key@DB_VERSION_UNIQUE_NAME@ +#define __dbenv_set_tas_spins __dbenv_set_tas_spins@DB_VERSION_UNIQUE_NAME@ +#define __dbenv_set_tmp_dir __dbenv_set_tmp_dir@DB_VERSION_UNIQUE_NAME@ +#define __dbenv_set_verbose __dbenv_set_verbose@DB_VERSION_UNIQUE_NAME@ +#define __db_mi_env __db_mi_env@DB_VERSION_UNIQUE_NAME@ +#define __db_mi_open __db_mi_open@DB_VERSION_UNIQUE_NAME@ +#define __db_env_config __db_env_config@DB_VERSION_UNIQUE_NAME@ +#define __dbenv_open __dbenv_open@DB_VERSION_UNIQUE_NAME@ +#define __dbenv_remove __dbenv_remove@DB_VERSION_UNIQUE_NAME@ +#define __dbenv_close_pp __dbenv_close_pp@DB_VERSION_UNIQUE_NAME@ +#define __dbenv_close __dbenv_close@DB_VERSION_UNIQUE_NAME@ +#define __dbenv_get_open_flags __dbenv_get_open_flags@DB_VERSION_UNIQUE_NAME@ +#define __db_appname __db_appname@DB_VERSION_UNIQUE_NAME@ +#define __db_home __db_home@DB_VERSION_UNIQUE_NAME@ +#define __db_apprec __db_apprec@DB_VERSION_UNIQUE_NAME@ +#define __log_backup __log_backup@DB_VERSION_UNIQUE_NAME@ +#define __env_openfiles __env_openfiles@DB_VERSION_UNIQUE_NAME@ +#define __db_e_attach __db_e_attach@DB_VERSION_UNIQUE_NAME@ +#define __db_e_detach __db_e_detach@DB_VERSION_UNIQUE_NAME@ +#define __db_e_remove __db_e_remove@DB_VERSION_UNIQUE_NAME@ +#define __db_r_attach __db_r_attach@DB_VERSION_UNIQUE_NAME@ +#define __db_r_detach __db_r_detach@DB_VERSION_UNIQUE_NAME@ +#define __dbenv_stat_print_pp __dbenv_stat_print_pp@DB_VERSION_UNIQUE_NAME@ +#define __db_print_fh __db_print_fh@DB_VERSION_UNIQUE_NAME@ +#define __db_print_fileid __db_print_fileid@DB_VERSION_UNIQUE_NAME@ +#define __db_print_mutex __db_print_mutex@DB_VERSION_UNIQUE_NAME@ +#define __db_dl __db_dl@DB_VERSION_UNIQUE_NAME@ +#define __db_dl_pct __db_dl_pct@DB_VERSION_UNIQUE_NAME@ +#define __db_dlbytes __db_dlbytes@DB_VERSION_UNIQUE_NAME@ +#define __db_print_reginfo __db_print_reginfo@DB_VERSION_UNIQUE_NAME@ +#define __db_stat_not_built __db_stat_not_built@DB_VERSION_UNIQUE_NAME@ +#define __fop_create_log __fop_create_log@DB_VERSION_UNIQUE_NAME@ +#define __fop_create_read __fop_create_read@DB_VERSION_UNIQUE_NAME@ +#define __fop_remove_log __fop_remove_log@DB_VERSION_UNIQUE_NAME@ +#define __fop_remove_read __fop_remove_read@DB_VERSION_UNIQUE_NAME@ +#define __fop_write_log __fop_write_log@DB_VERSION_UNIQUE_NAME@ +#define __fop_write_read __fop_write_read@DB_VERSION_UNIQUE_NAME@ +#define __fop_rename_log __fop_rename_log@DB_VERSION_UNIQUE_NAME@ +#define __fop_rename_read __fop_rename_read@DB_VERSION_UNIQUE_NAME@ +#define __fop_file_remove_log __fop_file_remove_log@DB_VERSION_UNIQUE_NAME@ +#define __fop_file_remove_read __fop_file_remove_read@DB_VERSION_UNIQUE_NAME@ +#define __fop_init_recover __fop_init_recover@DB_VERSION_UNIQUE_NAME@ +#define __fop_create_print __fop_create_print@DB_VERSION_UNIQUE_NAME@ +#define __fop_remove_print __fop_remove_print@DB_VERSION_UNIQUE_NAME@ +#define __fop_write_print __fop_write_print@DB_VERSION_UNIQUE_NAME@ +#define __fop_rename_print __fop_rename_print@DB_VERSION_UNIQUE_NAME@ +#define __fop_file_remove_print __fop_file_remove_print@DB_VERSION_UNIQUE_NAME@ +#define __fop_init_print __fop_init_print@DB_VERSION_UNIQUE_NAME@ +#define __fop_create __fop_create@DB_VERSION_UNIQUE_NAME@ +#define __fop_remove __fop_remove@DB_VERSION_UNIQUE_NAME@ +#define __fop_write __fop_write@DB_VERSION_UNIQUE_NAME@ +#define __fop_rename __fop_rename@DB_VERSION_UNIQUE_NAME@ +#define __fop_create_recover __fop_create_recover@DB_VERSION_UNIQUE_NAME@ +#define __fop_remove_recover __fop_remove_recover@DB_VERSION_UNIQUE_NAME@ +#define __fop_write_recover __fop_write_recover@DB_VERSION_UNIQUE_NAME@ +#define __fop_rename_recover __fop_rename_recover@DB_VERSION_UNIQUE_NAME@ +#define __fop_file_remove_recover __fop_file_remove_recover@DB_VERSION_UNIQUE_NAME@ +#define __fop_lock_handle __fop_lock_handle@DB_VERSION_UNIQUE_NAME@ +#define __fop_file_setup __fop_file_setup@DB_VERSION_UNIQUE_NAME@ +#define __fop_subdb_setup __fop_subdb_setup@DB_VERSION_UNIQUE_NAME@ +#define __fop_remove_setup __fop_remove_setup@DB_VERSION_UNIQUE_NAME@ +#define __fop_read_meta __fop_read_meta@DB_VERSION_UNIQUE_NAME@ +#define __fop_dummy __fop_dummy@DB_VERSION_UNIQUE_NAME@ +#define __fop_dbrename __fop_dbrename@DB_VERSION_UNIQUE_NAME@ +#define __ham_quick_delete __ham_quick_delete@DB_VERSION_UNIQUE_NAME@ +#define __ham_c_init __ham_c_init@DB_VERSION_UNIQUE_NAME@ +#define __ham_c_count __ham_c_count@DB_VERSION_UNIQUE_NAME@ +#define __ham_c_dup __ham_c_dup@DB_VERSION_UNIQUE_NAME@ +#define __ham_call_hash __ham_call_hash@DB_VERSION_UNIQUE_NAME@ +#define __ham_init_dbt __ham_init_dbt@DB_VERSION_UNIQUE_NAME@ +#define __ham_c_update __ham_c_update@DB_VERSION_UNIQUE_NAME@ +#define __ham_get_clist __ham_get_clist@DB_VERSION_UNIQUE_NAME@ +#define __ham_insdel_log __ham_insdel_log@DB_VERSION_UNIQUE_NAME@ +#define __ham_insdel_read __ham_insdel_read@DB_VERSION_UNIQUE_NAME@ +#define __ham_newpage_log __ham_newpage_log@DB_VERSION_UNIQUE_NAME@ +#define __ham_newpage_read __ham_newpage_read@DB_VERSION_UNIQUE_NAME@ +#define __ham_splitdata_log __ham_splitdata_log@DB_VERSION_UNIQUE_NAME@ +#define __ham_splitdata_read __ham_splitdata_read@DB_VERSION_UNIQUE_NAME@ +#define __ham_replace_log __ham_replace_log@DB_VERSION_UNIQUE_NAME@ +#define __ham_replace_read __ham_replace_read@DB_VERSION_UNIQUE_NAME@ +#define __ham_copypage_log __ham_copypage_log@DB_VERSION_UNIQUE_NAME@ +#define __ham_copypage_read __ham_copypage_read@DB_VERSION_UNIQUE_NAME@ +#define __ham_metagroup_log __ham_metagroup_log@DB_VERSION_UNIQUE_NAME@ +#define __ham_metagroup_read __ham_metagroup_read@DB_VERSION_UNIQUE_NAME@ +#define __ham_groupalloc_log __ham_groupalloc_log@DB_VERSION_UNIQUE_NAME@ +#define __ham_groupalloc_read __ham_groupalloc_read@DB_VERSION_UNIQUE_NAME@ +#define __ham_curadj_log __ham_curadj_log@DB_VERSION_UNIQUE_NAME@ +#define __ham_curadj_read __ham_curadj_read@DB_VERSION_UNIQUE_NAME@ +#define __ham_chgpg_log __ham_chgpg_log@DB_VERSION_UNIQUE_NAME@ +#define __ham_chgpg_read __ham_chgpg_read@DB_VERSION_UNIQUE_NAME@ +#define __ham_init_recover __ham_init_recover@DB_VERSION_UNIQUE_NAME@ +#define __ham_insdel_print __ham_insdel_print@DB_VERSION_UNIQUE_NAME@ +#define __ham_newpage_print __ham_newpage_print@DB_VERSION_UNIQUE_NAME@ +#define __ham_splitdata_print __ham_splitdata_print@DB_VERSION_UNIQUE_NAME@ +#define __ham_replace_print __ham_replace_print@DB_VERSION_UNIQUE_NAME@ +#define __ham_copypage_print __ham_copypage_print@DB_VERSION_UNIQUE_NAME@ +#define __ham_metagroup_print __ham_metagroup_print@DB_VERSION_UNIQUE_NAME@ +#define __ham_groupalloc_print __ham_groupalloc_print@DB_VERSION_UNIQUE_NAME@ +#define __ham_curadj_print __ham_curadj_print@DB_VERSION_UNIQUE_NAME@ +#define __ham_chgpg_print __ham_chgpg_print@DB_VERSION_UNIQUE_NAME@ +#define __ham_init_print __ham_init_print@DB_VERSION_UNIQUE_NAME@ +#define __ham_pgin __ham_pgin@DB_VERSION_UNIQUE_NAME@ +#define __ham_pgout __ham_pgout@DB_VERSION_UNIQUE_NAME@ +#define __ham_mswap __ham_mswap@DB_VERSION_UNIQUE_NAME@ +#define __ham_add_dup __ham_add_dup@DB_VERSION_UNIQUE_NAME@ +#define __ham_dup_convert __ham_dup_convert@DB_VERSION_UNIQUE_NAME@ +#define __ham_make_dup __ham_make_dup@DB_VERSION_UNIQUE_NAME@ +#define __ham_dsearch __ham_dsearch@DB_VERSION_UNIQUE_NAME@ +#define __ham_func2 __ham_func2@DB_VERSION_UNIQUE_NAME@ +#define __ham_func3 __ham_func3@DB_VERSION_UNIQUE_NAME@ +#define __ham_func4 __ham_func4@DB_VERSION_UNIQUE_NAME@ +#define __ham_func5 __ham_func5@DB_VERSION_UNIQUE_NAME@ +#define __ham_test __ham_test@DB_VERSION_UNIQUE_NAME@ +#define __ham_get_meta __ham_get_meta@DB_VERSION_UNIQUE_NAME@ +#define __ham_release_meta __ham_release_meta@DB_VERSION_UNIQUE_NAME@ +#define __ham_dirty_meta __ham_dirty_meta@DB_VERSION_UNIQUE_NAME@ +#define __ham_db_create __ham_db_create@DB_VERSION_UNIQUE_NAME@ +#define __ham_db_close __ham_db_close@DB_VERSION_UNIQUE_NAME@ +#define __ham_get_h_ffactor __ham_get_h_ffactor@DB_VERSION_UNIQUE_NAME@ +#define __ham_get_h_nelem __ham_get_h_nelem@DB_VERSION_UNIQUE_NAME@ +#define __ham_open __ham_open@DB_VERSION_UNIQUE_NAME@ +#define __ham_metachk __ham_metachk@DB_VERSION_UNIQUE_NAME@ +#define __ham_new_file __ham_new_file@DB_VERSION_UNIQUE_NAME@ +#define __ham_new_subdb __ham_new_subdb@DB_VERSION_UNIQUE_NAME@ +#define __ham_item __ham_item@DB_VERSION_UNIQUE_NAME@ +#define __ham_item_reset __ham_item_reset@DB_VERSION_UNIQUE_NAME@ +#define __ham_item_init __ham_item_init@DB_VERSION_UNIQUE_NAME@ +#define __ham_item_last __ham_item_last@DB_VERSION_UNIQUE_NAME@ +#define __ham_item_first __ham_item_first@DB_VERSION_UNIQUE_NAME@ +#define __ham_item_prev __ham_item_prev@DB_VERSION_UNIQUE_NAME@ +#define __ham_item_next __ham_item_next@DB_VERSION_UNIQUE_NAME@ +#define __ham_putitem __ham_putitem@DB_VERSION_UNIQUE_NAME@ +#define __ham_reputpair __ham_reputpair@DB_VERSION_UNIQUE_NAME@ +#define __ham_del_pair __ham_del_pair@DB_VERSION_UNIQUE_NAME@ +#define __ham_replpair __ham_replpair@DB_VERSION_UNIQUE_NAME@ +#define __ham_onpage_replace __ham_onpage_replace@DB_VERSION_UNIQUE_NAME@ +#define __ham_split_page __ham_split_page@DB_VERSION_UNIQUE_NAME@ +#define __ham_add_el __ham_add_el@DB_VERSION_UNIQUE_NAME@ +#define __ham_copy_item __ham_copy_item@DB_VERSION_UNIQUE_NAME@ +#define __ham_add_ovflpage __ham_add_ovflpage@DB_VERSION_UNIQUE_NAME@ +#define __ham_get_cpage __ham_get_cpage@DB_VERSION_UNIQUE_NAME@ +#define __ham_next_cpage __ham_next_cpage@DB_VERSION_UNIQUE_NAME@ +#define __ham_lock_bucket __ham_lock_bucket@DB_VERSION_UNIQUE_NAME@ +#define __ham_dpair __ham_dpair@DB_VERSION_UNIQUE_NAME@ +#define __ham_insdel_recover __ham_insdel_recover@DB_VERSION_UNIQUE_NAME@ +#define __ham_newpage_recover __ham_newpage_recover@DB_VERSION_UNIQUE_NAME@ +#define __ham_replace_recover __ham_replace_recover@DB_VERSION_UNIQUE_NAME@ +#define __ham_splitdata_recover __ham_splitdata_recover@DB_VERSION_UNIQUE_NAME@ +#define __ham_copypage_recover __ham_copypage_recover@DB_VERSION_UNIQUE_NAME@ +#define __ham_metagroup_recover __ham_metagroup_recover@DB_VERSION_UNIQUE_NAME@ +#define __ham_groupalloc_recover __ham_groupalloc_recover@DB_VERSION_UNIQUE_NAME@ +#define __ham_curadj_recover __ham_curadj_recover@DB_VERSION_UNIQUE_NAME@ +#define __ham_chgpg_recover __ham_chgpg_recover@DB_VERSION_UNIQUE_NAME@ +#define __ham_reclaim __ham_reclaim@DB_VERSION_UNIQUE_NAME@ +#define __ham_truncate __ham_truncate@DB_VERSION_UNIQUE_NAME@ +#define __ham_stat __ham_stat@DB_VERSION_UNIQUE_NAME@ +#define __ham_stat_print __ham_stat_print@DB_VERSION_UNIQUE_NAME@ +#define __ham_print_cursor __ham_print_cursor@DB_VERSION_UNIQUE_NAME@ +#define __ham_traverse __ham_traverse@DB_VERSION_UNIQUE_NAME@ +#define __db_no_hash_am __db_no_hash_am@DB_VERSION_UNIQUE_NAME@ +#define __ham_30_hashmeta __ham_30_hashmeta@DB_VERSION_UNIQUE_NAME@ +#define __ham_30_sizefix __ham_30_sizefix@DB_VERSION_UNIQUE_NAME@ +#define __ham_31_hashmeta __ham_31_hashmeta@DB_VERSION_UNIQUE_NAME@ +#define __ham_31_hash __ham_31_hash@DB_VERSION_UNIQUE_NAME@ +#define __ham_vrfy_meta __ham_vrfy_meta@DB_VERSION_UNIQUE_NAME@ +#define __ham_vrfy __ham_vrfy@DB_VERSION_UNIQUE_NAME@ +#define __ham_vrfy_structure __ham_vrfy_structure@DB_VERSION_UNIQUE_NAME@ +#define __ham_vrfy_hashing __ham_vrfy_hashing@DB_VERSION_UNIQUE_NAME@ +#define __ham_salvage __ham_salvage@DB_VERSION_UNIQUE_NAME@ +#define __ham_meta2pgset __ham_meta2pgset@DB_VERSION_UNIQUE_NAME@ +#define __db_chksum __db_chksum@DB_VERSION_UNIQUE_NAME@ +#define __db_derive_mac __db_derive_mac@DB_VERSION_UNIQUE_NAME@ +#define __db_check_chksum __db_check_chksum@DB_VERSION_UNIQUE_NAME@ +#define __db_SHA1Transform __db_SHA1Transform@DB_VERSION_UNIQUE_NAME@ +#define __db_SHA1Init __db_SHA1Init@DB_VERSION_UNIQUE_NAME@ +#define __db_SHA1Update __db_SHA1Update@DB_VERSION_UNIQUE_NAME@ +#define __db_SHA1Final __db_SHA1Final@DB_VERSION_UNIQUE_NAME@ +#define __lock_vec_pp __lock_vec_pp@DB_VERSION_UNIQUE_NAME@ +#define __lock_vec __lock_vec@DB_VERSION_UNIQUE_NAME@ +#define __lock_get_pp __lock_get_pp@DB_VERSION_UNIQUE_NAME@ +#define __lock_get __lock_get@DB_VERSION_UNIQUE_NAME@ +#define __lock_get_internal __lock_get_internal@DB_VERSION_UNIQUE_NAME@ +#define __lock_put_pp __lock_put_pp@DB_VERSION_UNIQUE_NAME@ +#define __lock_put __lock_put@DB_VERSION_UNIQUE_NAME@ +#define __lock_downgrade __lock_downgrade@DB_VERSION_UNIQUE_NAME@ +#define __lock_locker_is_parent __lock_locker_is_parent@DB_VERSION_UNIQUE_NAME@ +#define __lock_promote __lock_promote@DB_VERSION_UNIQUE_NAME@ +#define __lock_detect_pp __lock_detect_pp@DB_VERSION_UNIQUE_NAME@ +#define __lock_detect __lock_detect@DB_VERSION_UNIQUE_NAME@ +#define __lock_id_pp __lock_id_pp@DB_VERSION_UNIQUE_NAME@ +#define __lock_id __lock_id@DB_VERSION_UNIQUE_NAME@ +#define __lock_id_free_pp __lock_id_free_pp@DB_VERSION_UNIQUE_NAME@ +#define __lock_id_free __lock_id_free@DB_VERSION_UNIQUE_NAME@ +#define __lock_id_set __lock_id_set@DB_VERSION_UNIQUE_NAME@ +#define __lock_getlocker __lock_getlocker@DB_VERSION_UNIQUE_NAME@ +#define __lock_addfamilylocker __lock_addfamilylocker@DB_VERSION_UNIQUE_NAME@ +#define __lock_freefamilylocker __lock_freefamilylocker@DB_VERSION_UNIQUE_NAME@ +#define __lock_freelocker __lock_freelocker@DB_VERSION_UNIQUE_NAME@ +#define __lock_fix_list __lock_fix_list@DB_VERSION_UNIQUE_NAME@ +#define __lock_get_list __lock_get_list@DB_VERSION_UNIQUE_NAME@ +#define __lock_list_print __lock_list_print@DB_VERSION_UNIQUE_NAME@ +#define __lock_dbenv_create __lock_dbenv_create@DB_VERSION_UNIQUE_NAME@ +#define __lock_dbenv_close __lock_dbenv_close@DB_VERSION_UNIQUE_NAME@ +#define __lock_set_lk_detect __lock_set_lk_detect@DB_VERSION_UNIQUE_NAME@ +#define __lock_set_lk_max __lock_set_lk_max@DB_VERSION_UNIQUE_NAME@ +#define __lock_set_lk_max_locks __lock_set_lk_max_locks@DB_VERSION_UNIQUE_NAME@ +#define __lock_set_lk_max_lockers __lock_set_lk_max_lockers@DB_VERSION_UNIQUE_NAME@ +#define __lock_set_lk_max_objects __lock_set_lk_max_objects@DB_VERSION_UNIQUE_NAME@ +#define __lock_set_env_timeout __lock_set_env_timeout@DB_VERSION_UNIQUE_NAME@ +#define __lock_open __lock_open@DB_VERSION_UNIQUE_NAME@ +#define __lock_dbenv_refresh __lock_dbenv_refresh@DB_VERSION_UNIQUE_NAME@ +#define __lock_region_destroy __lock_region_destroy@DB_VERSION_UNIQUE_NAME@ +#define __lock_stat_pp __lock_stat_pp@DB_VERSION_UNIQUE_NAME@ +#define __lock_stat_print_pp __lock_stat_print_pp@DB_VERSION_UNIQUE_NAME@ +#define __lock_stat_print __lock_stat_print@DB_VERSION_UNIQUE_NAME@ +#define __lock_printlock __lock_printlock@DB_VERSION_UNIQUE_NAME@ +#define __lock_set_timeout __lock_set_timeout@DB_VERSION_UNIQUE_NAME@ +#define __lock_set_timeout_internal __lock_set_timeout_internal@DB_VERSION_UNIQUE_NAME@ +#define __lock_inherit_timeout __lock_inherit_timeout@DB_VERSION_UNIQUE_NAME@ +#define __lock_expires __lock_expires@DB_VERSION_UNIQUE_NAME@ +#define __lock_expired __lock_expired@DB_VERSION_UNIQUE_NAME@ +#define __lock_cmp __lock_cmp@DB_VERSION_UNIQUE_NAME@ +#define __lock_locker_cmp __lock_locker_cmp@DB_VERSION_UNIQUE_NAME@ +#define __lock_ohash __lock_ohash@DB_VERSION_UNIQUE_NAME@ +#define __lock_lhash __lock_lhash@DB_VERSION_UNIQUE_NAME@ +#define __lock_locker_hash __lock_locker_hash@DB_VERSION_UNIQUE_NAME@ +#define __lock_nomem __lock_nomem@DB_VERSION_UNIQUE_NAME@ +#define __log_open __log_open@DB_VERSION_UNIQUE_NAME@ +#define __log_find __log_find@DB_VERSION_UNIQUE_NAME@ +#define __log_valid __log_valid@DB_VERSION_UNIQUE_NAME@ +#define __log_dbenv_refresh __log_dbenv_refresh@DB_VERSION_UNIQUE_NAME@ +#define __log_get_cached_ckp_lsn __log_get_cached_ckp_lsn@DB_VERSION_UNIQUE_NAME@ +#define __log_region_destroy __log_region_destroy@DB_VERSION_UNIQUE_NAME@ +#define __log_vtruncate __log_vtruncate@DB_VERSION_UNIQUE_NAME@ +#define __log_is_outdated __log_is_outdated@DB_VERSION_UNIQUE_NAME@ +#define __log_inmem_lsnoff __log_inmem_lsnoff@DB_VERSION_UNIQUE_NAME@ +#define __log_inmem_newfile __log_inmem_newfile@DB_VERSION_UNIQUE_NAME@ +#define __log_inmem_chkspace __log_inmem_chkspace@DB_VERSION_UNIQUE_NAME@ +#define __log_inmem_copyout __log_inmem_copyout@DB_VERSION_UNIQUE_NAME@ +#define __log_inmem_copyin __log_inmem_copyin@DB_VERSION_UNIQUE_NAME@ +#define __log_archive_pp __log_archive_pp@DB_VERSION_UNIQUE_NAME@ +#define __log_autoremove __log_autoremove@DB_VERSION_UNIQUE_NAME@ +#define __log_cursor_pp __log_cursor_pp@DB_VERSION_UNIQUE_NAME@ +#define __log_cursor __log_cursor@DB_VERSION_UNIQUE_NAME@ +#define __log_c_close __log_c_close@DB_VERSION_UNIQUE_NAME@ +#define __log_c_get __log_c_get@DB_VERSION_UNIQUE_NAME@ +#define __log_dbenv_create __log_dbenv_create@DB_VERSION_UNIQUE_NAME@ +#define __log_set_lg_bsize __log_set_lg_bsize@DB_VERSION_UNIQUE_NAME@ +#define __log_set_lg_max __log_set_lg_max@DB_VERSION_UNIQUE_NAME@ +#define __log_set_lg_regionmax __log_set_lg_regionmax@DB_VERSION_UNIQUE_NAME@ +#define __log_set_lg_dir __log_set_lg_dir@DB_VERSION_UNIQUE_NAME@ +#define __log_get_flags __log_get_flags@DB_VERSION_UNIQUE_NAME@ +#define __log_set_flags __log_set_flags@DB_VERSION_UNIQUE_NAME@ +#define __log_check_sizes __log_check_sizes@DB_VERSION_UNIQUE_NAME@ +#define __log_put_pp __log_put_pp@DB_VERSION_UNIQUE_NAME@ +#define __log_put __log_put@DB_VERSION_UNIQUE_NAME@ +#define __log_txn_lsn __log_txn_lsn@DB_VERSION_UNIQUE_NAME@ +#define __log_newfile __log_newfile@DB_VERSION_UNIQUE_NAME@ +#define __log_flush_pp __log_flush_pp@DB_VERSION_UNIQUE_NAME@ +#define __log_flush __log_flush@DB_VERSION_UNIQUE_NAME@ +#define __log_flush_int __log_flush_int@DB_VERSION_UNIQUE_NAME@ +#define __log_file_pp __log_file_pp@DB_VERSION_UNIQUE_NAME@ +#define __log_name __log_name@DB_VERSION_UNIQUE_NAME@ +#define __log_rep_put __log_rep_put@DB_VERSION_UNIQUE_NAME@ +#define __log_stat_pp __log_stat_pp@DB_VERSION_UNIQUE_NAME@ +#define __log_stat_print_pp __log_stat_print_pp@DB_VERSION_UNIQUE_NAME@ +#define __log_stat_print __log_stat_print@DB_VERSION_UNIQUE_NAME@ +#define __memp_alloc __memp_alloc@DB_VERSION_UNIQUE_NAME@ +#ifdef DIAGNOSTIC +#define __memp_check_order __memp_check_order@DB_VERSION_UNIQUE_NAME@ +#endif +#define __memp_bhwrite __memp_bhwrite@DB_VERSION_UNIQUE_NAME@ +#define __memp_pgread __memp_pgread@DB_VERSION_UNIQUE_NAME@ +#define __memp_pg __memp_pg@DB_VERSION_UNIQUE_NAME@ +#define __memp_bhfree __memp_bhfree@DB_VERSION_UNIQUE_NAME@ +#define __memp_fget_pp __memp_fget_pp@DB_VERSION_UNIQUE_NAME@ +#define __memp_fget __memp_fget@DB_VERSION_UNIQUE_NAME@ +#define __memp_fcreate_pp __memp_fcreate_pp@DB_VERSION_UNIQUE_NAME@ +#define __memp_fcreate __memp_fcreate@DB_VERSION_UNIQUE_NAME@ +#define __memp_set_clear_len __memp_set_clear_len@DB_VERSION_UNIQUE_NAME@ +#define __memp_get_fileid __memp_get_fileid@DB_VERSION_UNIQUE_NAME@ +#define __memp_set_fileid __memp_set_fileid@DB_VERSION_UNIQUE_NAME@ +#define __memp_get_flags __memp_get_flags@DB_VERSION_UNIQUE_NAME@ +#define __memp_set_flags __memp_set_flags@DB_VERSION_UNIQUE_NAME@ +#define __memp_get_ftype __memp_get_ftype@DB_VERSION_UNIQUE_NAME@ +#define __memp_set_ftype __memp_set_ftype@DB_VERSION_UNIQUE_NAME@ +#define __memp_set_lsn_offset __memp_set_lsn_offset@DB_VERSION_UNIQUE_NAME@ +#define __memp_set_pgcookie __memp_set_pgcookie@DB_VERSION_UNIQUE_NAME@ +#define __memp_last_pgno __memp_last_pgno@DB_VERSION_UNIQUE_NAME@ +#define __memp_fn __memp_fn@DB_VERSION_UNIQUE_NAME@ +#define __memp_fns __memp_fns@DB_VERSION_UNIQUE_NAME@ +#define __memp_fopen_pp __memp_fopen_pp@DB_VERSION_UNIQUE_NAME@ +#define __memp_fopen __memp_fopen@DB_VERSION_UNIQUE_NAME@ +#define __memp_fclose_pp __memp_fclose_pp@DB_VERSION_UNIQUE_NAME@ +#define __memp_fclose __memp_fclose@DB_VERSION_UNIQUE_NAME@ +#define __memp_mf_discard __memp_mf_discard@DB_VERSION_UNIQUE_NAME@ +#define __memp_fput_pp __memp_fput_pp@DB_VERSION_UNIQUE_NAME@ +#define __memp_fput __memp_fput@DB_VERSION_UNIQUE_NAME@ +#define __memp_fset_pp __memp_fset_pp@DB_VERSION_UNIQUE_NAME@ +#define __memp_fset __memp_fset@DB_VERSION_UNIQUE_NAME@ +#define __memp_dbenv_create __memp_dbenv_create@DB_VERSION_UNIQUE_NAME@ +#define __memp_get_cachesize __memp_get_cachesize@DB_VERSION_UNIQUE_NAME@ +#define __memp_set_cachesize __memp_set_cachesize@DB_VERSION_UNIQUE_NAME@ +#define __memp_set_mp_max_openfd __memp_set_mp_max_openfd@DB_VERSION_UNIQUE_NAME@ +#define __memp_set_mp_max_write __memp_set_mp_max_write@DB_VERSION_UNIQUE_NAME@ +#define __memp_set_mp_mmapsize __memp_set_mp_mmapsize@DB_VERSION_UNIQUE_NAME@ +#define __memp_nameop __memp_nameop@DB_VERSION_UNIQUE_NAME@ +#define __memp_get_refcnt __memp_get_refcnt@DB_VERSION_UNIQUE_NAME@ +#define __memp_ftruncate __memp_ftruncate@DB_VERSION_UNIQUE_NAME@ +#define __memp_open __memp_open@DB_VERSION_UNIQUE_NAME@ +#define __memp_dbenv_refresh __memp_dbenv_refresh@DB_VERSION_UNIQUE_NAME@ +#define __memp_region_destroy __memp_region_destroy@DB_VERSION_UNIQUE_NAME@ +#define __memp_register_pp __memp_register_pp@DB_VERSION_UNIQUE_NAME@ +#define __memp_register __memp_register@DB_VERSION_UNIQUE_NAME@ +#define __memp_stat_pp __memp_stat_pp@DB_VERSION_UNIQUE_NAME@ +#define __memp_stat_print_pp __memp_stat_print_pp@DB_VERSION_UNIQUE_NAME@ +#define __memp_stat_print __memp_stat_print@DB_VERSION_UNIQUE_NAME@ +#define __memp_stat_hash __memp_stat_hash@DB_VERSION_UNIQUE_NAME@ +#define __memp_sync_pp __memp_sync_pp@DB_VERSION_UNIQUE_NAME@ +#define __memp_sync __memp_sync@DB_VERSION_UNIQUE_NAME@ +#define __memp_fsync_pp __memp_fsync_pp@DB_VERSION_UNIQUE_NAME@ +#define __memp_fsync __memp_fsync@DB_VERSION_UNIQUE_NAME@ +#define __mp_xxx_fh __mp_xxx_fh@DB_VERSION_UNIQUE_NAME@ +#define __memp_sync_int __memp_sync_int@DB_VERSION_UNIQUE_NAME@ +#define __memp_mf_sync __memp_mf_sync@DB_VERSION_UNIQUE_NAME@ +#define __memp_trickle_pp __memp_trickle_pp@DB_VERSION_UNIQUE_NAME@ +#define __db_fcntl_mutex_init __db_fcntl_mutex_init@DB_VERSION_UNIQUE_NAME@ +#define __db_fcntl_mutex_lock __db_fcntl_mutex_lock@DB_VERSION_UNIQUE_NAME@ +#define __db_fcntl_mutex_unlock __db_fcntl_mutex_unlock@DB_VERSION_UNIQUE_NAME@ +#define __db_fcntl_mutex_destroy __db_fcntl_mutex_destroy@DB_VERSION_UNIQUE_NAME@ +#define __db_pthread_mutex_init __db_pthread_mutex_init@DB_VERSION_UNIQUE_NAME@ +#define __db_pthread_mutex_lock __db_pthread_mutex_lock@DB_VERSION_UNIQUE_NAME@ +#define __db_pthread_mutex_unlock __db_pthread_mutex_unlock@DB_VERSION_UNIQUE_NAME@ +#define __db_pthread_mutex_destroy __db_pthread_mutex_destroy@DB_VERSION_UNIQUE_NAME@ +#define __db_tas_mutex_init __db_tas_mutex_init@DB_VERSION_UNIQUE_NAME@ +#define __db_tas_mutex_lock __db_tas_mutex_lock@DB_VERSION_UNIQUE_NAME@ +#define __db_tas_mutex_unlock __db_tas_mutex_unlock@DB_VERSION_UNIQUE_NAME@ +#define __db_tas_mutex_destroy __db_tas_mutex_destroy@DB_VERSION_UNIQUE_NAME@ +#define __db_win32_mutex_init __db_win32_mutex_init@DB_VERSION_UNIQUE_NAME@ +#define __db_win32_mutex_lock __db_win32_mutex_lock@DB_VERSION_UNIQUE_NAME@ +#define __db_win32_mutex_unlock __db_win32_mutex_unlock@DB_VERSION_UNIQUE_NAME@ +#define __db_win32_mutex_destroy __db_win32_mutex_destroy@DB_VERSION_UNIQUE_NAME@ +#define __db_mutex_setup __db_mutex_setup@DB_VERSION_UNIQUE_NAME@ +#define __db_mutex_free __db_mutex_free@DB_VERSION_UNIQUE_NAME@ +#define __db_shreg_locks_clear __db_shreg_locks_clear@DB_VERSION_UNIQUE_NAME@ +#define __db_shreg_locks_destroy __db_shreg_locks_destroy@DB_VERSION_UNIQUE_NAME@ +#define __db_shreg_mutex_init __db_shreg_mutex_init@DB_VERSION_UNIQUE_NAME@ +#define __db_shreg_maintinit __db_shreg_maintinit@DB_VERSION_UNIQUE_NAME@ +#define __os_abspath __os_abspath@DB_VERSION_UNIQUE_NAME@ +#define __os_umalloc __os_umalloc@DB_VERSION_UNIQUE_NAME@ +#define __os_urealloc __os_urealloc@DB_VERSION_UNIQUE_NAME@ +#define __os_ufree __os_ufree@DB_VERSION_UNIQUE_NAME@ +#define __os_strdup __os_strdup@DB_VERSION_UNIQUE_NAME@ +#define __os_calloc __os_calloc@DB_VERSION_UNIQUE_NAME@ +#define __os_malloc __os_malloc@DB_VERSION_UNIQUE_NAME@ +#define __os_realloc __os_realloc@DB_VERSION_UNIQUE_NAME@ +#define __os_free __os_free@DB_VERSION_UNIQUE_NAME@ +#define __ua_memcpy __ua_memcpy@DB_VERSION_UNIQUE_NAME@ +#define __os_clock __os_clock@DB_VERSION_UNIQUE_NAME@ +#define __os_fs_notzero __os_fs_notzero@DB_VERSION_UNIQUE_NAME@ +#define __os_dirlist __os_dirlist@DB_VERSION_UNIQUE_NAME@ +#define __os_dirfree __os_dirfree@DB_VERSION_UNIQUE_NAME@ +#define __os_get_errno_ret_zero __os_get_errno_ret_zero@DB_VERSION_UNIQUE_NAME@ +#define __os_get_errno __os_get_errno@DB_VERSION_UNIQUE_NAME@ +#define __os_set_errno __os_set_errno@DB_VERSION_UNIQUE_NAME@ +#define __os_fileid __os_fileid@DB_VERSION_UNIQUE_NAME@ +#define __os_fsync __os_fsync@DB_VERSION_UNIQUE_NAME@ +#define __os_openhandle __os_openhandle@DB_VERSION_UNIQUE_NAME@ +#define __os_closehandle __os_closehandle@DB_VERSION_UNIQUE_NAME@ +#define __os_id __os_id@DB_VERSION_UNIQUE_NAME@ +#define __os_unique_id __os_unique_id@DB_VERSION_UNIQUE_NAME@ +#define __os_r_sysattach __os_r_sysattach@DB_VERSION_UNIQUE_NAME@ +#define __os_r_sysdetach __os_r_sysdetach@DB_VERSION_UNIQUE_NAME@ +#define __os_mapfile __os_mapfile@DB_VERSION_UNIQUE_NAME@ +#define __os_unmapfile __os_unmapfile@DB_VERSION_UNIQUE_NAME@ +#define __db_oflags __db_oflags@DB_VERSION_UNIQUE_NAME@ +#define __db_omode __db_omode@DB_VERSION_UNIQUE_NAME@ +#define __db_shm_mode __db_shm_mode@DB_VERSION_UNIQUE_NAME@ +#define __os_have_direct __os_have_direct@DB_VERSION_UNIQUE_NAME@ +#define __os_open __os_open@DB_VERSION_UNIQUE_NAME@ +#define __os_open_extend __os_open_extend@DB_VERSION_UNIQUE_NAME@ +#ifdef HAVE_QNX +#define __os_shmname __os_shmname@DB_VERSION_UNIQUE_NAME@ +#endif +#define __os_r_attach __os_r_attach@DB_VERSION_UNIQUE_NAME@ +#define __os_r_detach __os_r_detach@DB_VERSION_UNIQUE_NAME@ +#define __os_rename __os_rename@DB_VERSION_UNIQUE_NAME@ +#define __os_isroot __os_isroot@DB_VERSION_UNIQUE_NAME@ +#define __db_rpath __db_rpath@DB_VERSION_UNIQUE_NAME@ +#define __os_io __os_io@DB_VERSION_UNIQUE_NAME@ +#define __os_read __os_read@DB_VERSION_UNIQUE_NAME@ +#define __os_write __os_write@DB_VERSION_UNIQUE_NAME@ +#define __os_seek __os_seek@DB_VERSION_UNIQUE_NAME@ +#define __os_sleep __os_sleep@DB_VERSION_UNIQUE_NAME@ +#define __os_spin __os_spin@DB_VERSION_UNIQUE_NAME@ +#define __os_yield __os_yield@DB_VERSION_UNIQUE_NAME@ +#define __os_exists __os_exists@DB_VERSION_UNIQUE_NAME@ +#define __os_ioinfo __os_ioinfo@DB_VERSION_UNIQUE_NAME@ +#define __os_tmpdir __os_tmpdir@DB_VERSION_UNIQUE_NAME@ +#define __os_truncate __os_truncate@DB_VERSION_UNIQUE_NAME@ +#define __os_region_unlink __os_region_unlink@DB_VERSION_UNIQUE_NAME@ +#define __os_unlink __os_unlink@DB_VERSION_UNIQUE_NAME@ +#define __os_is_winnt __os_is_winnt@DB_VERSION_UNIQUE_NAME@ +#define __os_have_direct __os_have_direct@DB_VERSION_UNIQUE_NAME@ +#define __os_unlink __os_unlink@DB_VERSION_UNIQUE_NAME@ +#define __qam_position __qam_position@DB_VERSION_UNIQUE_NAME@ +#define __qam_pitem __qam_pitem@DB_VERSION_UNIQUE_NAME@ +#define __qam_append __qam_append@DB_VERSION_UNIQUE_NAME@ +#define __qam_c_dup __qam_c_dup@DB_VERSION_UNIQUE_NAME@ +#define __qam_c_init __qam_c_init@DB_VERSION_UNIQUE_NAME@ +#define __qam_truncate __qam_truncate@DB_VERSION_UNIQUE_NAME@ +#define __qam_incfirst_log __qam_incfirst_log@DB_VERSION_UNIQUE_NAME@ +#define __qam_incfirst_read __qam_incfirst_read@DB_VERSION_UNIQUE_NAME@ +#define __qam_mvptr_log __qam_mvptr_log@DB_VERSION_UNIQUE_NAME@ +#define __qam_mvptr_read __qam_mvptr_read@DB_VERSION_UNIQUE_NAME@ +#define __qam_del_log __qam_del_log@DB_VERSION_UNIQUE_NAME@ +#define __qam_del_read __qam_del_read@DB_VERSION_UNIQUE_NAME@ +#define __qam_add_log __qam_add_log@DB_VERSION_UNIQUE_NAME@ +#define __qam_add_read __qam_add_read@DB_VERSION_UNIQUE_NAME@ +#define __qam_delext_log __qam_delext_log@DB_VERSION_UNIQUE_NAME@ +#define __qam_delext_read __qam_delext_read@DB_VERSION_UNIQUE_NAME@ +#define __qam_init_recover __qam_init_recover@DB_VERSION_UNIQUE_NAME@ +#define __qam_incfirst_print __qam_incfirst_print@DB_VERSION_UNIQUE_NAME@ +#define __qam_mvptr_print __qam_mvptr_print@DB_VERSION_UNIQUE_NAME@ +#define __qam_del_print __qam_del_print@DB_VERSION_UNIQUE_NAME@ +#define __qam_add_print __qam_add_print@DB_VERSION_UNIQUE_NAME@ +#define __qam_delext_print __qam_delext_print@DB_VERSION_UNIQUE_NAME@ +#define __qam_init_print __qam_init_print@DB_VERSION_UNIQUE_NAME@ +#define __qam_mswap __qam_mswap@DB_VERSION_UNIQUE_NAME@ +#define __qam_pgin_out __qam_pgin_out@DB_VERSION_UNIQUE_NAME@ +#define __qam_fprobe __qam_fprobe@DB_VERSION_UNIQUE_NAME@ +#define __qam_fclose __qam_fclose@DB_VERSION_UNIQUE_NAME@ +#define __qam_fremove __qam_fremove@DB_VERSION_UNIQUE_NAME@ +#define __qam_sync __qam_sync@DB_VERSION_UNIQUE_NAME@ +#define __qam_gen_filelist __qam_gen_filelist@DB_VERSION_UNIQUE_NAME@ +#define __qam_extent_names __qam_extent_names@DB_VERSION_UNIQUE_NAME@ +#define __qam_exid __qam_exid@DB_VERSION_UNIQUE_NAME@ +#define __qam_nameop __qam_nameop@DB_VERSION_UNIQUE_NAME@ +#define __qam_db_create __qam_db_create@DB_VERSION_UNIQUE_NAME@ +#define __qam_db_close __qam_db_close@DB_VERSION_UNIQUE_NAME@ +#define __qam_get_extentsize __qam_get_extentsize@DB_VERSION_UNIQUE_NAME@ +#define __queue_pageinfo __queue_pageinfo@DB_VERSION_UNIQUE_NAME@ +#define __db_prqueue __db_prqueue@DB_VERSION_UNIQUE_NAME@ +#define __qam_remove __qam_remove@DB_VERSION_UNIQUE_NAME@ +#define __qam_rename __qam_rename@DB_VERSION_UNIQUE_NAME@ +#define __qam_map_flags __qam_map_flags@DB_VERSION_UNIQUE_NAME@ +#define __qam_set_flags __qam_set_flags@DB_VERSION_UNIQUE_NAME@ +#define __qam_open __qam_open@DB_VERSION_UNIQUE_NAME@ +#define __qam_set_ext_data __qam_set_ext_data@DB_VERSION_UNIQUE_NAME@ +#define __qam_metachk __qam_metachk@DB_VERSION_UNIQUE_NAME@ +#define __qam_new_file __qam_new_file@DB_VERSION_UNIQUE_NAME@ +#define __qam_incfirst_recover __qam_incfirst_recover@DB_VERSION_UNIQUE_NAME@ +#define __qam_mvptr_recover __qam_mvptr_recover@DB_VERSION_UNIQUE_NAME@ +#define __qam_del_recover __qam_del_recover@DB_VERSION_UNIQUE_NAME@ +#define __qam_delext_recover __qam_delext_recover@DB_VERSION_UNIQUE_NAME@ +#define __qam_add_recover __qam_add_recover@DB_VERSION_UNIQUE_NAME@ +#define __qam_stat __qam_stat@DB_VERSION_UNIQUE_NAME@ +#define __qam_stat_print __qam_stat_print@DB_VERSION_UNIQUE_NAME@ +#define __db_no_queue_am __db_no_queue_am@DB_VERSION_UNIQUE_NAME@ +#define __qam_31_qammeta __qam_31_qammeta@DB_VERSION_UNIQUE_NAME@ +#define __qam_32_qammeta __qam_32_qammeta@DB_VERSION_UNIQUE_NAME@ +#define __qam_vrfy_meta __qam_vrfy_meta@DB_VERSION_UNIQUE_NAME@ +#define __qam_vrfy_data __qam_vrfy_data@DB_VERSION_UNIQUE_NAME@ +#define __qam_vrfy_structure __qam_vrfy_structure@DB_VERSION_UNIQUE_NAME@ +#define __qam_vrfy_walkqueue __qam_vrfy_walkqueue@DB_VERSION_UNIQUE_NAME@ +#define __qam_salvage __qam_salvage@DB_VERSION_UNIQUE_NAME@ +#define __rep_update_buf __rep_update_buf@DB_VERSION_UNIQUE_NAME@ +#define __rep_update_read __rep_update_read@DB_VERSION_UNIQUE_NAME@ +#define __rep_fileinfo_buf __rep_fileinfo_buf@DB_VERSION_UNIQUE_NAME@ +#define __rep_fileinfo_read __rep_fileinfo_read@DB_VERSION_UNIQUE_NAME@ +#define __rep_update_req __rep_update_req@DB_VERSION_UNIQUE_NAME@ +#define __rep_page_req __rep_page_req@DB_VERSION_UNIQUE_NAME@ +#define __rep_update_setup __rep_update_setup@DB_VERSION_UNIQUE_NAME@ +#define __rep_page __rep_page@DB_VERSION_UNIQUE_NAME@ +#define __rep_page_fail __rep_page_fail@DB_VERSION_UNIQUE_NAME@ +#define __rep_pggap_req __rep_pggap_req@DB_VERSION_UNIQUE_NAME@ +#define __rep_loggap_req __rep_loggap_req@DB_VERSION_UNIQUE_NAME@ +#define __rep_finfo_alloc __rep_finfo_alloc@DB_VERSION_UNIQUE_NAME@ +#define __rep_dbenv_create __rep_dbenv_create@DB_VERSION_UNIQUE_NAME@ +#define __rep_open __rep_open@DB_VERSION_UNIQUE_NAME@ +#define __rep_client_dbinit __rep_client_dbinit@DB_VERSION_UNIQUE_NAME@ +#define __rep_elect_master __rep_elect_master@DB_VERSION_UNIQUE_NAME@ +#define __rep_process_message __rep_process_message@DB_VERSION_UNIQUE_NAME@ +#define __rep_process_txn __rep_process_txn@DB_VERSION_UNIQUE_NAME@ +#define __rep_tally __rep_tally@DB_VERSION_UNIQUE_NAME@ +#define __rep_cmp_vote __rep_cmp_vote@DB_VERSION_UNIQUE_NAME@ +#define __rep_cmp_vote2 __rep_cmp_vote2@DB_VERSION_UNIQUE_NAME@ +#define __rep_check_doreq __rep_check_doreq@DB_VERSION_UNIQUE_NAME@ +#define __rep_lockout __rep_lockout@DB_VERSION_UNIQUE_NAME@ +#define __rep_region_init __rep_region_init@DB_VERSION_UNIQUE_NAME@ +#define __rep_region_destroy __rep_region_destroy@DB_VERSION_UNIQUE_NAME@ +#define __rep_dbenv_refresh __rep_dbenv_refresh@DB_VERSION_UNIQUE_NAME@ +#define __rep_dbenv_close __rep_dbenv_close@DB_VERSION_UNIQUE_NAME@ +#define __rep_preclose __rep_preclose@DB_VERSION_UNIQUE_NAME@ +#define __rep_write_egen __rep_write_egen@DB_VERSION_UNIQUE_NAME@ +#define __rep_stat_pp __rep_stat_pp@DB_VERSION_UNIQUE_NAME@ +#define __rep_stat_print_pp __rep_stat_print_pp@DB_VERSION_UNIQUE_NAME@ +#define __rep_stat_print __rep_stat_print@DB_VERSION_UNIQUE_NAME@ +#define __rep_send_message __rep_send_message@DB_VERSION_UNIQUE_NAME@ +#define __rep_new_master __rep_new_master@DB_VERSION_UNIQUE_NAME@ +#define __rep_is_client __rep_is_client@DB_VERSION_UNIQUE_NAME@ +#define __rep_noarchive __rep_noarchive@DB_VERSION_UNIQUE_NAME@ +#define __rep_send_vote __rep_send_vote@DB_VERSION_UNIQUE_NAME@ +#define __rep_elect_done __rep_elect_done@DB_VERSION_UNIQUE_NAME@ +#define __rep_grow_sites __rep_grow_sites@DB_VERSION_UNIQUE_NAME@ +#define __env_rep_enter __env_rep_enter@DB_VERSION_UNIQUE_NAME@ +#define __env_db_rep_exit __env_db_rep_exit@DB_VERSION_UNIQUE_NAME@ +#define __db_rep_enter __db_rep_enter@DB_VERSION_UNIQUE_NAME@ +#define __op_rep_enter __op_rep_enter@DB_VERSION_UNIQUE_NAME@ +#define __op_rep_exit __op_rep_exit@DB_VERSION_UNIQUE_NAME@ +#define __rep_get_gen __rep_get_gen@DB_VERSION_UNIQUE_NAME@ +#define __rep_print_message __rep_print_message@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_envrpcserver __dbcl_envrpcserver@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_env_close_wrap __dbcl_env_close_wrap@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_env_open_wrap __dbcl_env_open_wrap@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_open_wrap __dbcl_db_open_wrap@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_refresh __dbcl_refresh@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_retcopy __dbcl_retcopy@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_txn_end __dbcl_txn_end@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_txn_setup __dbcl_txn_setup@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_c_refresh __dbcl_c_refresh@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_c_setup __dbcl_c_setup@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_dbclose_common __dbcl_dbclose_common@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_env_alloc __dbcl_env_alloc@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_set_app_dispatch __dbcl_set_app_dispatch@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_env_get_cachesize __dbcl_env_get_cachesize@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_env_cachesize __dbcl_env_cachesize@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_env_close __dbcl_env_close@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_env_create __dbcl_env_create@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_get_data_dirs __dbcl_get_data_dirs@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_set_data_dir __dbcl_set_data_dir@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_env_dbremove __dbcl_env_dbremove@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_env_dbrename __dbcl_env_dbrename@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_env_get_encrypt_flags __dbcl_env_get_encrypt_flags@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_env_encrypt __dbcl_env_encrypt@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_env_set_feedback __dbcl_env_set_feedback@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_env_get_flags __dbcl_env_get_flags@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_env_flags __dbcl_env_flags@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_get_lg_bsize __dbcl_get_lg_bsize@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_set_lg_bsize __dbcl_set_lg_bsize@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_get_lg_dir __dbcl_get_lg_dir@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_set_lg_dir __dbcl_set_lg_dir@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_get_lg_max __dbcl_get_lg_max@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_set_lg_max __dbcl_set_lg_max@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_get_lg_regionmax __dbcl_get_lg_regionmax@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_set_lg_regionmax __dbcl_set_lg_regionmax@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_get_lk_conflicts __dbcl_get_lk_conflicts@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_set_lk_conflict __dbcl_set_lk_conflict@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_get_lk_detect __dbcl_get_lk_detect@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_set_lk_detect __dbcl_set_lk_detect@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_set_lk_max __dbcl_set_lk_max@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_get_lk_max_locks __dbcl_get_lk_max_locks@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_set_lk_max_locks __dbcl_set_lk_max_locks@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_get_lk_max_lockers __dbcl_get_lk_max_lockers@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_set_lk_max_lockers __dbcl_set_lk_max_lockers@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_get_lk_max_objects __dbcl_get_lk_max_objects@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_set_lk_max_objects __dbcl_set_lk_max_objects@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_get_mp_max_openfd __dbcl_get_mp_max_openfd@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_set_mp_max_openfd __dbcl_set_mp_max_openfd@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_get_mp_max_write __dbcl_get_mp_max_write@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_set_mp_max_write __dbcl_set_mp_max_write@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_get_mp_mmapsize __dbcl_get_mp_mmapsize@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_set_mp_mmapsize __dbcl_set_mp_mmapsize@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_env_get_home __dbcl_env_get_home@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_env_get_open_flags __dbcl_env_get_open_flags@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_env_open __dbcl_env_open@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_env_paniccall __dbcl_env_paniccall@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_env_remove __dbcl_env_remove@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_get_shm_key __dbcl_get_shm_key@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_set_shm_key __dbcl_set_shm_key@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_get_tas_spins __dbcl_get_tas_spins@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_set_tas_spins __dbcl_set_tas_spins@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_get_timeout __dbcl_get_timeout@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_set_timeout __dbcl_set_timeout@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_get_tmp_dir __dbcl_get_tmp_dir@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_set_tmp_dir __dbcl_set_tmp_dir@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_get_tx_max __dbcl_get_tx_max@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_set_tx_max __dbcl_set_tx_max@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_get_tx_timestamp __dbcl_get_tx_timestamp@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_set_tx_timestamp __dbcl_set_tx_timestamp@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_get_verbose __dbcl_get_verbose@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_set_verbose __dbcl_set_verbose@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_txn_abort __dbcl_txn_abort@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_txn_begin __dbcl_txn_begin@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_txn_checkpoint __dbcl_txn_checkpoint@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_txn_commit __dbcl_txn_commit@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_txn_discard __dbcl_txn_discard@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_txn_prepare __dbcl_txn_prepare@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_txn_recover __dbcl_txn_recover@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_txn_stat __dbcl_txn_stat@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_txn_timeout __dbcl_txn_timeout@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_rep_elect __dbcl_rep_elect@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_rep_flush __dbcl_rep_flush@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_rep_process_message __dbcl_rep_process_message@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_rep_get_limit __dbcl_rep_get_limit@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_rep_set_limit __dbcl_rep_set_limit@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_rep_set_request __dbcl_rep_set_request@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_rep_set_rep_transport __dbcl_rep_set_rep_transport@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_rep_start __dbcl_rep_start@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_rep_stat __dbcl_rep_stat@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_alloc __dbcl_db_alloc@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_associate __dbcl_db_associate@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_bt_compare __dbcl_db_bt_compare@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_bt_maxkey __dbcl_db_bt_maxkey@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_get_bt_minkey __dbcl_db_get_bt_minkey@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_bt_minkey __dbcl_db_bt_minkey@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_bt_prefix __dbcl_db_bt_prefix@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_set_append_recno __dbcl_db_set_append_recno@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_get_cachesize __dbcl_db_get_cachesize@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_cachesize __dbcl_db_cachesize@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_close __dbcl_db_close@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_create __dbcl_db_create@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_del __dbcl_db_del@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_dup_compare __dbcl_db_dup_compare@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_get_encrypt_flags __dbcl_db_get_encrypt_flags@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_encrypt __dbcl_db_encrypt@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_get_extentsize __dbcl_db_get_extentsize@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_extentsize __dbcl_db_extentsize@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_fd __dbcl_db_fd@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_feedback __dbcl_db_feedback@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_get_flags __dbcl_db_get_flags@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_flags __dbcl_db_flags@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_get __dbcl_db_get@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_get_name __dbcl_db_get_name@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_get_open_flags __dbcl_db_get_open_flags@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_get_h_ffactor __dbcl_db_get_h_ffactor@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_h_ffactor __dbcl_db_h_ffactor@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_h_hash __dbcl_db_h_hash@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_get_h_nelem __dbcl_db_get_h_nelem@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_h_nelem __dbcl_db_h_nelem@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_key_range __dbcl_db_key_range@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_get_lorder __dbcl_db_get_lorder@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_lorder __dbcl_db_lorder@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_open __dbcl_db_open@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_get_pagesize __dbcl_db_get_pagesize@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_pagesize __dbcl_db_pagesize@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_panic __dbcl_db_panic@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_pget __dbcl_db_pget@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_put __dbcl_db_put@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_get_re_delim __dbcl_db_get_re_delim@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_re_delim __dbcl_db_re_delim@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_get_re_len __dbcl_db_get_re_len@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_re_len __dbcl_db_re_len@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_re_pad __dbcl_db_re_pad@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_get_re_pad __dbcl_db_get_re_pad@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_get_re_source __dbcl_db_get_re_source@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_re_source __dbcl_db_re_source@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_remove __dbcl_db_remove@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_rename __dbcl_db_rename@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_stat __dbcl_db_stat@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_sync __dbcl_db_sync@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_truncate __dbcl_db_truncate@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_upgrade __dbcl_db_upgrade@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_verify __dbcl_db_verify@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_cursor __dbcl_db_cursor@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_join __dbcl_db_join@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_dbc_close __dbcl_dbc_close@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_dbc_count __dbcl_dbc_count@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_dbc_del __dbcl_dbc_del@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_dbc_dup __dbcl_dbc_dup@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_dbc_get __dbcl_dbc_get@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_dbc_pget __dbcl_dbc_pget@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_dbc_put __dbcl_dbc_put@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_lock_detect __dbcl_lock_detect@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_lock_get __dbcl_lock_get@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_lock_id __dbcl_lock_id@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_lock_id_free __dbcl_lock_id_free@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_lock_put __dbcl_lock_put@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_lock_stat __dbcl_lock_stat@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_lock_vec __dbcl_lock_vec@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_log_archive __dbcl_log_archive@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_log_cursor __dbcl_log_cursor@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_log_file __dbcl_log_file@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_log_flush __dbcl_log_flush@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_log_put __dbcl_log_put@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_log_stat __dbcl_log_stat@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_memp_register __dbcl_memp_register@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_memp_stat __dbcl_memp_stat@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_memp_sync __dbcl_memp_sync@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_memp_trickle __dbcl_memp_trickle@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_memp_fget __dbcl_memp_fget@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_memp_fopen __dbcl_memp_fopen@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_memp_fput __dbcl_memp_fput@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_memp_fset __dbcl_memp_fset@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_memp_get_clear_len __dbcl_memp_get_clear_len@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_memp_set_clear_len __dbcl_memp_set_clear_len@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_memp_get_fileid __dbcl_memp_get_fileid@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_memp_set_fileid __dbcl_memp_set_fileid@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_memp_get_flags __dbcl_memp_get_flags@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_memp_set_flags __dbcl_memp_set_flags@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_memp_get_ftype __dbcl_memp_get_ftype@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_memp_set_ftype __dbcl_memp_set_ftype@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_memp_get_lsn_offset __dbcl_memp_get_lsn_offset@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_memp_set_lsn_offset __dbcl_memp_set_lsn_offset@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_memp_get_maxsize __dbcl_memp_get_maxsize@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_memp_set_maxsize __dbcl_memp_set_maxsize@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_memp_get_pgcookie __dbcl_memp_get_pgcookie@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_memp_set_pgcookie __dbcl_memp_set_pgcookie@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_memp_get_priority __dbcl_memp_get_priority@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_memp_set_priority __dbcl_memp_set_priority@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_memp_fsync __dbcl_memp_fsync@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_env_create_ret __dbcl_env_create_ret@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_env_open_ret __dbcl_env_open_ret@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_env_remove_ret __dbcl_env_remove_ret@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_txn_abort_ret __dbcl_txn_abort_ret@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_txn_begin_ret __dbcl_txn_begin_ret@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_txn_commit_ret __dbcl_txn_commit_ret@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_txn_discard_ret __dbcl_txn_discard_ret@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_txn_recover_ret __dbcl_txn_recover_ret@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_close_ret __dbcl_db_close_ret@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_create_ret __dbcl_db_create_ret@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_get_ret __dbcl_db_get_ret@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_key_range_ret __dbcl_db_key_range_ret@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_open_ret __dbcl_db_open_ret@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_pget_ret __dbcl_db_pget_ret@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_put_ret __dbcl_db_put_ret@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_remove_ret __dbcl_db_remove_ret@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_rename_ret __dbcl_db_rename_ret@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_stat_ret __dbcl_db_stat_ret@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_truncate_ret __dbcl_db_truncate_ret@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_cursor_ret __dbcl_db_cursor_ret@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_db_join_ret __dbcl_db_join_ret@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_dbc_close_ret __dbcl_dbc_close_ret@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_dbc_count_ret __dbcl_dbc_count_ret@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_dbc_dup_ret __dbcl_dbc_dup_ret@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_dbc_get_ret __dbcl_dbc_get_ret@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_dbc_pget_ret __dbcl_dbc_pget_ret@DB_VERSION_UNIQUE_NAME@ +#define __dbcl_dbc_put_ret __dbcl_dbc_put_ret@DB_VERSION_UNIQUE_NAME@ +#define __env_get_cachesize_proc __env_get_cachesize_proc@DB_VERSION_UNIQUE_NAME@ +#define __env_cachesize_proc __env_cachesize_proc@DB_VERSION_UNIQUE_NAME@ +#define __env_close_proc __env_close_proc@DB_VERSION_UNIQUE_NAME@ +#define __env_create_proc __env_create_proc@DB_VERSION_UNIQUE_NAME@ +#define __env_dbremove_proc __env_dbremove_proc@DB_VERSION_UNIQUE_NAME@ +#define __env_dbrename_proc __env_dbrename_proc@DB_VERSION_UNIQUE_NAME@ +#define __env_get_encrypt_flags_proc __env_get_encrypt_flags_proc@DB_VERSION_UNIQUE_NAME@ +#define __env_encrypt_proc __env_encrypt_proc@DB_VERSION_UNIQUE_NAME@ +#define __env_get_flags_proc __env_get_flags_proc@DB_VERSION_UNIQUE_NAME@ +#define __env_flags_proc __env_flags_proc@DB_VERSION_UNIQUE_NAME@ +#define __env_get_home_proc __env_get_home_proc@DB_VERSION_UNIQUE_NAME@ +#define __env_get_open_flags_proc __env_get_open_flags_proc@DB_VERSION_UNIQUE_NAME@ +#define __env_open_proc __env_open_proc@DB_VERSION_UNIQUE_NAME@ +#define __env_remove_proc __env_remove_proc@DB_VERSION_UNIQUE_NAME@ +#define __txn_abort_proc __txn_abort_proc@DB_VERSION_UNIQUE_NAME@ +#define __txn_begin_proc __txn_begin_proc@DB_VERSION_UNIQUE_NAME@ +#define __txn_commit_proc __txn_commit_proc@DB_VERSION_UNIQUE_NAME@ +#define __txn_discard_proc __txn_discard_proc@DB_VERSION_UNIQUE_NAME@ +#define __txn_prepare_proc __txn_prepare_proc@DB_VERSION_UNIQUE_NAME@ +#define __txn_recover_proc __txn_recover_proc@DB_VERSION_UNIQUE_NAME@ +#define __db_bt_maxkey_proc __db_bt_maxkey_proc@DB_VERSION_UNIQUE_NAME@ +#define __db_associate_proc __db_associate_proc@DB_VERSION_UNIQUE_NAME@ +#define __db_get_bt_minkey_proc __db_get_bt_minkey_proc@DB_VERSION_UNIQUE_NAME@ +#define __db_bt_minkey_proc __db_bt_minkey_proc@DB_VERSION_UNIQUE_NAME@ +#define __db_close_proc __db_close_proc@DB_VERSION_UNIQUE_NAME@ +#define __db_create_proc __db_create_proc@DB_VERSION_UNIQUE_NAME@ +#define __db_del_proc __db_del_proc@DB_VERSION_UNIQUE_NAME@ +#define __db_get_encrypt_flags_proc __db_get_encrypt_flags_proc@DB_VERSION_UNIQUE_NAME@ +#define __db_encrypt_proc __db_encrypt_proc@DB_VERSION_UNIQUE_NAME@ +#define __db_get_extentsize_proc __db_get_extentsize_proc@DB_VERSION_UNIQUE_NAME@ +#define __db_extentsize_proc __db_extentsize_proc@DB_VERSION_UNIQUE_NAME@ +#define __db_get_flags_proc __db_get_flags_proc@DB_VERSION_UNIQUE_NAME@ +#define __db_flags_proc __db_flags_proc@DB_VERSION_UNIQUE_NAME@ +#define __db_get_proc __db_get_proc@DB_VERSION_UNIQUE_NAME@ +#define __db_get_h_ffactor_proc __db_get_h_ffactor_proc@DB_VERSION_UNIQUE_NAME@ +#define __db_h_ffactor_proc __db_h_ffactor_proc@DB_VERSION_UNIQUE_NAME@ +#define __db_get_h_nelem_proc __db_get_h_nelem_proc@DB_VERSION_UNIQUE_NAME@ +#define __db_h_nelem_proc __db_h_nelem_proc@DB_VERSION_UNIQUE_NAME@ +#define __db_key_range_proc __db_key_range_proc@DB_VERSION_UNIQUE_NAME@ +#define __db_get_lorder_proc __db_get_lorder_proc@DB_VERSION_UNIQUE_NAME@ +#define __db_lorder_proc __db_lorder_proc@DB_VERSION_UNIQUE_NAME@ +#define __db_get_name_proc __db_get_name_proc@DB_VERSION_UNIQUE_NAME@ +#define __db_get_open_flags_proc __db_get_open_flags_proc@DB_VERSION_UNIQUE_NAME@ +#define __db_open_proc __db_open_proc@DB_VERSION_UNIQUE_NAME@ +#define __db_get_pagesize_proc __db_get_pagesize_proc@DB_VERSION_UNIQUE_NAME@ +#define __db_pagesize_proc __db_pagesize_proc@DB_VERSION_UNIQUE_NAME@ +#define __db_pget_proc __db_pget_proc@DB_VERSION_UNIQUE_NAME@ +#define __db_put_proc __db_put_proc@DB_VERSION_UNIQUE_NAME@ +#define __db_get_re_delim_proc __db_get_re_delim_proc@DB_VERSION_UNIQUE_NAME@ +#define __db_re_delim_proc __db_re_delim_proc@DB_VERSION_UNIQUE_NAME@ +#define __db_get_re_len_proc __db_get_re_len_proc@DB_VERSION_UNIQUE_NAME@ +#define __db_re_len_proc __db_re_len_proc@DB_VERSION_UNIQUE_NAME@ +#define __db_get_re_pad_proc __db_get_re_pad_proc@DB_VERSION_UNIQUE_NAME@ +#define __db_re_pad_proc __db_re_pad_proc@DB_VERSION_UNIQUE_NAME@ +#define __db_remove_proc __db_remove_proc@DB_VERSION_UNIQUE_NAME@ +#define __db_rename_proc __db_rename_proc@DB_VERSION_UNIQUE_NAME@ +#define __db_stat_proc __db_stat_proc@DB_VERSION_UNIQUE_NAME@ +#define __db_sync_proc __db_sync_proc@DB_VERSION_UNIQUE_NAME@ +#define __db_truncate_proc __db_truncate_proc@DB_VERSION_UNIQUE_NAME@ +#define __db_cursor_proc __db_cursor_proc@DB_VERSION_UNIQUE_NAME@ +#define __db_join_proc __db_join_proc@DB_VERSION_UNIQUE_NAME@ +#define __dbc_close_proc __dbc_close_proc@DB_VERSION_UNIQUE_NAME@ +#define __dbc_count_proc __dbc_count_proc@DB_VERSION_UNIQUE_NAME@ +#define __dbc_del_proc __dbc_del_proc@DB_VERSION_UNIQUE_NAME@ +#define __dbc_dup_proc __dbc_dup_proc@DB_VERSION_UNIQUE_NAME@ +#define __dbc_get_proc __dbc_get_proc@DB_VERSION_UNIQUE_NAME@ +#define __dbc_pget_proc __dbc_pget_proc@DB_VERSION_UNIQUE_NAME@ +#define __dbc_put_proc __dbc_put_proc@DB_VERSION_UNIQUE_NAME@ +#define __dbsrv_settimeout __dbsrv_settimeout@DB_VERSION_UNIQUE_NAME@ +#define __dbsrv_timeout __dbsrv_timeout@DB_VERSION_UNIQUE_NAME@ +#define __dbclear_ctp __dbclear_ctp@DB_VERSION_UNIQUE_NAME@ +#define __dbdel_ctp __dbdel_ctp@DB_VERSION_UNIQUE_NAME@ +#define new_ct_ent new_ct_ent@DB_VERSION_UNIQUE_NAME@ +#define get_tableent get_tableent@DB_VERSION_UNIQUE_NAME@ +#define __dbsrv_sharedb __dbsrv_sharedb@DB_VERSION_UNIQUE_NAME@ +#define __dbsrv_shareenv __dbsrv_shareenv@DB_VERSION_UNIQUE_NAME@ +#define __dbsrv_active __dbsrv_active@DB_VERSION_UNIQUE_NAME@ +#define __db_close_int __db_close_int@DB_VERSION_UNIQUE_NAME@ +#define __dbc_close_int __dbc_close_int@DB_VERSION_UNIQUE_NAME@ +#define __dbenv_close_int __dbenv_close_int@DB_VERSION_UNIQUE_NAME@ +#define get_fullhome get_fullhome@DB_VERSION_UNIQUE_NAME@ +#define __seq_stat __seq_stat@DB_VERSION_UNIQUE_NAME@ +#define __seq_stat_print __seq_stat_print@DB_VERSION_UNIQUE_NAME@ +#define __db_get_seq_flags_fn __db_get_seq_flags_fn@DB_VERSION_UNIQUE_NAME@ +#define __db_get_seq_flags_fn __db_get_seq_flags_fn@DB_VERSION_UNIQUE_NAME@ +#define bdb_HCommand bdb_HCommand@DB_VERSION_UNIQUE_NAME@ +#if DB_DBM_HSEARCH != 0 +#define bdb_NdbmOpen bdb_NdbmOpen@DB_VERSION_UNIQUE_NAME@ +#endif +#if DB_DBM_HSEARCH != 0 +#define bdb_DbmCommand bdb_DbmCommand@DB_VERSION_UNIQUE_NAME@ +#endif +#define ndbm_Cmd ndbm_Cmd@DB_VERSION_UNIQUE_NAME@ +#define _DbInfoDelete _DbInfoDelete@DB_VERSION_UNIQUE_NAME@ +#define db_Cmd db_Cmd@DB_VERSION_UNIQUE_NAME@ +#define dbc_Cmd dbc_Cmd@DB_VERSION_UNIQUE_NAME@ +#define env_Cmd env_Cmd@DB_VERSION_UNIQUE_NAME@ +#define tcl_EnvRemove tcl_EnvRemove@DB_VERSION_UNIQUE_NAME@ +#define tcl_EnvVerbose tcl_EnvVerbose@DB_VERSION_UNIQUE_NAME@ +#define tcl_EnvAttr tcl_EnvAttr@DB_VERSION_UNIQUE_NAME@ +#define tcl_EnvSetFlags tcl_EnvSetFlags@DB_VERSION_UNIQUE_NAME@ +#define tcl_EnvTest tcl_EnvTest@DB_VERSION_UNIQUE_NAME@ +#define tcl_EnvGetEncryptFlags tcl_EnvGetEncryptFlags@DB_VERSION_UNIQUE_NAME@ +#define tcl_EnvSetErrfile tcl_EnvSetErrfile@DB_VERSION_UNIQUE_NAME@ +#define tcl_EnvSetErrpfx tcl_EnvSetErrpfx@DB_VERSION_UNIQUE_NAME@ +#define _NewInfo _NewInfo@DB_VERSION_UNIQUE_NAME@ +#define _NameToPtr _NameToPtr@DB_VERSION_UNIQUE_NAME@ +#define _PtrToInfo _PtrToInfo@DB_VERSION_UNIQUE_NAME@ +#define _NameToInfo _NameToInfo@DB_VERSION_UNIQUE_NAME@ +#define _SetInfoData _SetInfoData@DB_VERSION_UNIQUE_NAME@ +#define _DeleteInfo _DeleteInfo@DB_VERSION_UNIQUE_NAME@ +#define _SetListElem _SetListElem@DB_VERSION_UNIQUE_NAME@ +#define _SetListElemInt _SetListElemInt@DB_VERSION_UNIQUE_NAME@ +#define _SetListElemWideInt _SetListElemWideInt@DB_VERSION_UNIQUE_NAME@ +#define _SetListRecnoElem _SetListRecnoElem@DB_VERSION_UNIQUE_NAME@ +#define _Set3DBTList _Set3DBTList@DB_VERSION_UNIQUE_NAME@ +#define _SetMultiList _SetMultiList@DB_VERSION_UNIQUE_NAME@ +#define _GetGlobPrefix _GetGlobPrefix@DB_VERSION_UNIQUE_NAME@ +#define _ReturnSetup _ReturnSetup@DB_VERSION_UNIQUE_NAME@ +#define _ErrorSetup _ErrorSetup@DB_VERSION_UNIQUE_NAME@ +#define _ErrorFunc _ErrorFunc@DB_VERSION_UNIQUE_NAME@ +#define _GetLsn _GetLsn@DB_VERSION_UNIQUE_NAME@ +#define _GetUInt32 _GetUInt32@DB_VERSION_UNIQUE_NAME@ +#define _GetFlagsList _GetFlagsList@DB_VERSION_UNIQUE_NAME@ +#define _debug_check _debug_check@DB_VERSION_UNIQUE_NAME@ +#define _CopyObjBytes _CopyObjBytes@DB_VERSION_UNIQUE_NAME@ +#define tcl_LockDetect tcl_LockDetect@DB_VERSION_UNIQUE_NAME@ +#define tcl_LockGet tcl_LockGet@DB_VERSION_UNIQUE_NAME@ +#define tcl_LockStat tcl_LockStat@DB_VERSION_UNIQUE_NAME@ +#define tcl_LockTimeout tcl_LockTimeout@DB_VERSION_UNIQUE_NAME@ +#define tcl_LockVec tcl_LockVec@DB_VERSION_UNIQUE_NAME@ +#define tcl_LogArchive tcl_LogArchive@DB_VERSION_UNIQUE_NAME@ +#define tcl_LogCompare tcl_LogCompare@DB_VERSION_UNIQUE_NAME@ +#define tcl_LogFile tcl_LogFile@DB_VERSION_UNIQUE_NAME@ +#define tcl_LogFlush tcl_LogFlush@DB_VERSION_UNIQUE_NAME@ +#define tcl_LogGet tcl_LogGet@DB_VERSION_UNIQUE_NAME@ +#define tcl_LogPut tcl_LogPut@DB_VERSION_UNIQUE_NAME@ +#define tcl_LogStat tcl_LogStat@DB_VERSION_UNIQUE_NAME@ +#define logc_Cmd logc_Cmd@DB_VERSION_UNIQUE_NAME@ +#define _MpInfoDelete _MpInfoDelete@DB_VERSION_UNIQUE_NAME@ +#define tcl_MpSync tcl_MpSync@DB_VERSION_UNIQUE_NAME@ +#define tcl_MpTrickle tcl_MpTrickle@DB_VERSION_UNIQUE_NAME@ +#define tcl_Mp tcl_Mp@DB_VERSION_UNIQUE_NAME@ +#define tcl_MpStat tcl_MpStat@DB_VERSION_UNIQUE_NAME@ +#define tcl_RepElect tcl_RepElect@DB_VERSION_UNIQUE_NAME@ +#define tcl_RepFlush tcl_RepFlush@DB_VERSION_UNIQUE_NAME@ +#define tcl_RepLimit tcl_RepLimit@DB_VERSION_UNIQUE_NAME@ +#define tcl_RepRequest tcl_RepRequest@DB_VERSION_UNIQUE_NAME@ +#define tcl_RepStart tcl_RepStart@DB_VERSION_UNIQUE_NAME@ +#define tcl_RepProcessMessage tcl_RepProcessMessage@DB_VERSION_UNIQUE_NAME@ +#define tcl_RepStat tcl_RepStat@DB_VERSION_UNIQUE_NAME@ +#define seq_Cmd seq_Cmd@DB_VERSION_UNIQUE_NAME@ +#define _TxnInfoDelete _TxnInfoDelete@DB_VERSION_UNIQUE_NAME@ +#define tcl_TxnCheckpoint tcl_TxnCheckpoint@DB_VERSION_UNIQUE_NAME@ +#define tcl_Txn tcl_Txn@DB_VERSION_UNIQUE_NAME@ +#define tcl_TxnStat tcl_TxnStat@DB_VERSION_UNIQUE_NAME@ +#define tcl_TxnTimeout tcl_TxnTimeout@DB_VERSION_UNIQUE_NAME@ +#define tcl_TxnRecover tcl_TxnRecover@DB_VERSION_UNIQUE_NAME@ +#define bdb_RandCommand bdb_RandCommand@DB_VERSION_UNIQUE_NAME@ +#define tcl_Mutex tcl_Mutex@DB_VERSION_UNIQUE_NAME@ +#define __txn_begin_pp __txn_begin_pp@DB_VERSION_UNIQUE_NAME@ +#define __txn_begin __txn_begin@DB_VERSION_UNIQUE_NAME@ +#define __txn_xa_begin __txn_xa_begin@DB_VERSION_UNIQUE_NAME@ +#define __txn_compensate_begin __txn_compensate_begin@DB_VERSION_UNIQUE_NAME@ +#define __txn_commit __txn_commit@DB_VERSION_UNIQUE_NAME@ +#define __txn_abort __txn_abort@DB_VERSION_UNIQUE_NAME@ +#define __txn_discard __txn_discard@DB_VERSION_UNIQUE_NAME@ +#define __txn_prepare __txn_prepare@DB_VERSION_UNIQUE_NAME@ +#define __txn_id __txn_id@DB_VERSION_UNIQUE_NAME@ +#define __txn_set_timeout __txn_set_timeout@DB_VERSION_UNIQUE_NAME@ +#define __txn_checkpoint_pp __txn_checkpoint_pp@DB_VERSION_UNIQUE_NAME@ +#define __txn_checkpoint __txn_checkpoint@DB_VERSION_UNIQUE_NAME@ +#define __txn_getactive __txn_getactive@DB_VERSION_UNIQUE_NAME@ +#define __txn_getckp __txn_getckp@DB_VERSION_UNIQUE_NAME@ +#define __txn_activekids __txn_activekids@DB_VERSION_UNIQUE_NAME@ +#define __txn_force_abort __txn_force_abort@DB_VERSION_UNIQUE_NAME@ +#define __txn_preclose __txn_preclose@DB_VERSION_UNIQUE_NAME@ +#define __txn_reset __txn_reset@DB_VERSION_UNIQUE_NAME@ +#define __txn_updateckp __txn_updateckp@DB_VERSION_UNIQUE_NAME@ +#define __txn_regop_log __txn_regop_log@DB_VERSION_UNIQUE_NAME@ +#define __txn_regop_read __txn_regop_read@DB_VERSION_UNIQUE_NAME@ +#define __txn_ckp_log __txn_ckp_log@DB_VERSION_UNIQUE_NAME@ +#define __txn_ckp_read __txn_ckp_read@DB_VERSION_UNIQUE_NAME@ +#define __txn_child_log __txn_child_log@DB_VERSION_UNIQUE_NAME@ +#define __txn_child_read __txn_child_read@DB_VERSION_UNIQUE_NAME@ +#define __txn_xa_regop_log __txn_xa_regop_log@DB_VERSION_UNIQUE_NAME@ +#define __txn_xa_regop_read __txn_xa_regop_read@DB_VERSION_UNIQUE_NAME@ +#define __txn_recycle_log __txn_recycle_log@DB_VERSION_UNIQUE_NAME@ +#define __txn_recycle_read __txn_recycle_read@DB_VERSION_UNIQUE_NAME@ +#define __txn_init_recover __txn_init_recover@DB_VERSION_UNIQUE_NAME@ +#define __txn_regop_print __txn_regop_print@DB_VERSION_UNIQUE_NAME@ +#define __txn_ckp_print __txn_ckp_print@DB_VERSION_UNIQUE_NAME@ +#define __txn_child_print __txn_child_print@DB_VERSION_UNIQUE_NAME@ +#define __txn_xa_regop_print __txn_xa_regop_print@DB_VERSION_UNIQUE_NAME@ +#define __txn_recycle_print __txn_recycle_print@DB_VERSION_UNIQUE_NAME@ +#define __txn_init_print __txn_init_print@DB_VERSION_UNIQUE_NAME@ +#define __txn_dbenv_create __txn_dbenv_create@DB_VERSION_UNIQUE_NAME@ +#define __txn_set_tx_max __txn_set_tx_max@DB_VERSION_UNIQUE_NAME@ +#define __txn_regop_recover __txn_regop_recover@DB_VERSION_UNIQUE_NAME@ +#define __txn_xa_regop_recover __txn_xa_regop_recover@DB_VERSION_UNIQUE_NAME@ +#define __txn_ckp_recover __txn_ckp_recover@DB_VERSION_UNIQUE_NAME@ +#define __txn_child_recover __txn_child_recover@DB_VERSION_UNIQUE_NAME@ +#define __txn_restore_txn __txn_restore_txn@DB_VERSION_UNIQUE_NAME@ +#define __txn_recycle_recover __txn_recycle_recover@DB_VERSION_UNIQUE_NAME@ +#define __txn_continue __txn_continue@DB_VERSION_UNIQUE_NAME@ +#define __txn_map_gid __txn_map_gid@DB_VERSION_UNIQUE_NAME@ +#define __txn_recover_pp __txn_recover_pp@DB_VERSION_UNIQUE_NAME@ +#define __txn_recover __txn_recover@DB_VERSION_UNIQUE_NAME@ +#define __txn_get_prepared __txn_get_prepared@DB_VERSION_UNIQUE_NAME@ +#define __txn_openfiles __txn_openfiles@DB_VERSION_UNIQUE_NAME@ +#define __txn_open __txn_open@DB_VERSION_UNIQUE_NAME@ +#define __txn_findlastckp __txn_findlastckp@DB_VERSION_UNIQUE_NAME@ +#define __txn_dbenv_refresh __txn_dbenv_refresh@DB_VERSION_UNIQUE_NAME@ +#define __txn_region_destroy __txn_region_destroy@DB_VERSION_UNIQUE_NAME@ +#define __txn_id_set __txn_id_set@DB_VERSION_UNIQUE_NAME@ +#define __txn_stat_pp __txn_stat_pp@DB_VERSION_UNIQUE_NAME@ +#define __txn_stat_print_pp __txn_stat_print_pp@DB_VERSION_UNIQUE_NAME@ +#define __txn_stat_print __txn_stat_print@DB_VERSION_UNIQUE_NAME@ +#define __txn_closeevent __txn_closeevent@DB_VERSION_UNIQUE_NAME@ +#define __txn_remevent __txn_remevent@DB_VERSION_UNIQUE_NAME@ +#define __txn_remrem __txn_remrem@DB_VERSION_UNIQUE_NAME@ +#define __txn_lockevent __txn_lockevent@DB_VERSION_UNIQUE_NAME@ +#define __txn_remlock __txn_remlock@DB_VERSION_UNIQUE_NAME@ +#define __txn_doevents __txn_doevents@DB_VERSION_UNIQUE_NAME@ +#define __xa_get_txn __xa_get_txn@DB_VERSION_UNIQUE_NAME@ +#define __db_xa_create __db_xa_create@DB_VERSION_UNIQUE_NAME@ +#define __db_rmid_to_env __db_rmid_to_env@DB_VERSION_UNIQUE_NAME@ +#define __db_xid_to_txn __db_xid_to_txn@DB_VERSION_UNIQUE_NAME@ +#define __db_map_rmid __db_map_rmid@DB_VERSION_UNIQUE_NAME@ +#define __db_unmap_rmid __db_unmap_rmid@DB_VERSION_UNIQUE_NAME@ +#define __db_map_xid __db_map_xid@DB_VERSION_UNIQUE_NAME@ +#define __db_unmap_xid __db_unmap_xid@DB_VERSION_UNIQUE_NAME@ +#define __db_global_values __db_global_values@DB_VERSION_UNIQUE_NAME@ +#define __db_jump __db_jump@DB_VERSION_UNIQUE_NAME@ + +#endif /* !_DB_INT_DEF_IN_ */ diff --git a/lib_dict/bdb/include/lock.h b/lib_dict/bdb/include/lock.h new file mode 100644 index 000000000..e59abbff8 --- /dev/null +++ b/lib_dict/bdb/include/lock.h @@ -0,0 +1,222 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996-2004 + * Sleepycat Software. All rights reserved. + * + * $Id: lock.h,v 11.53 2004/09/22 21:14:56 ubell Exp $ + */ + +#ifndef _DB_LOCK_H_ +#define _DB_LOCK_H_ + +#define DB_LOCK_DEFAULT_N 1000 /* Default # of locks in region. */ + +/* + * The locker id space is divided between the transaction manager and the lock + * manager. Lock IDs start at 1 and go to DB_LOCK_MAXID. Txn IDs start at + * DB_LOCK_MAXID + 1 and go up to TXN_MAXIMUM. + */ +#define DB_LOCK_INVALIDID 0 +#define DB_LOCK_MAXID 0x7fffffff + +/* + * Out of band value for a lock. Locks contain an offset into a lock region, + * so we use an invalid region offset to indicate an invalid or unset lock. + */ +#define LOCK_INVALID INVALID_ROFF +#define LOCK_ISSET(lock) ((lock).off != LOCK_INVALID) +#define LOCK_INIT(lock) ((lock).off = LOCK_INVALID) + +/* + * Macro to identify a write lock for the purpose of counting locks + * for the NUMWRITES option to deadlock detection. + */ +#define IS_WRITELOCK(m) \ + ((m) == DB_LOCK_WRITE || (m) == DB_LOCK_WWRITE || \ + (m) == DB_LOCK_IWRITE || (m) == DB_LOCK_IWR) + +/* + * Lock timers. + */ +typedef struct { + u_int32_t tv_sec; /* Seconds. */ + u_int32_t tv_usec; /* Microseconds. */ +} db_timeval_t; + +#define LOCK_TIME_ISVALID(time) ((time)->tv_sec != 0) +#define LOCK_SET_TIME_INVALID(time) ((time)->tv_sec = 0) +#define LOCK_TIME_ISMAX(time) ((time)->tv_sec == UINT32_MAX) +#define LOCK_SET_TIME_MAX(time) ((time)->tv_sec = UINT32_MAX) +#define LOCK_TIME_EQUAL(t1, t2) \ + ((t1)->tv_sec == (t2)->tv_sec && (t1)->tv_usec == (t2)->tv_usec) +#define LOCK_TIME_GREATER(t1, t2) \ + ((t1)->tv_sec > (t2)->tv_sec || \ + ((t1)->tv_sec == (t2)->tv_sec && (t1)->tv_usec > (t2)->tv_usec)) + +/* + * DB_LOCKREGION -- + * The lock shared region. + */ +typedef struct __db_lockregion { + u_int32_t need_dd; /* flag for deadlock detector */ + u_int32_t detect; /* run dd on every conflict */ + db_timeval_t next_timeout; /* next time to expire a lock */ + /* free lock header */ + SH_TAILQ_HEAD(__flock) free_locks; + /* free obj header */ + SH_TAILQ_HEAD(__fobj) free_objs; + /* free locker header */ + SH_TAILQ_HEAD(__flocker) free_lockers; + SH_TAILQ_HEAD(__dobj) dd_objs; /* objects with waiters */ + SH_TAILQ_HEAD(__lkrs) lockers; /* list of lockers */ + + db_timeout_t lk_timeout; /* timeout for locks. */ + db_timeout_t tx_timeout; /* timeout for txns. */ + + u_int32_t locker_t_size; /* size of locker hash table */ + u_int32_t object_t_size; /* size of object hash table */ + + roff_t conf_off; /* offset of conflicts array */ + roff_t obj_off; /* offset of object hash table */ + roff_t osynch_off; /* offset of the object mutex table */ + roff_t locker_off; /* offset of locker hash table */ + roff_t lsynch_off; /* offset of the locker mutex table */ + + DB_LOCK_STAT stat; /* stats about locking. */ + +#ifdef HAVE_MUTEX_SYSTEM_RESOURCES + roff_t maint_off; /* offset of region maintenance info */ +#endif +} DB_LOCKREGION; + +/* + * Since we will store DBTs in shared memory, we need the equivalent of a + * DBT that will work in shared memory. + */ +typedef struct __sh_dbt { + u_int32_t size; /* Byte length. */ + roff_t off; /* Region offset. */ +} SH_DBT; + +#define SH_DBT_PTR(p) ((void *)(((u_int8_t *)(p)) + (p)->off)) + +/* + * Object structures; these live in the object hash table. + */ +typedef struct __db_lockobj { + SH_DBT lockobj; /* Identifies object locked. */ + SH_TAILQ_ENTRY links; /* Links for free list or hash list. */ + SH_TAILQ_ENTRY dd_links; /* Links for dd list. */ + SH_TAILQ_HEAD(__waitl) waiters; /* List of waiting locks. */ + SH_TAILQ_HEAD(__holdl) holders; /* List of held locks. */ + /* Declare room in the object to hold + * typical DB lock structures so that + * we do not have to allocate them from + * shalloc at run-time. */ + u_int8_t objdata[sizeof(struct __db_ilock)]; +} DB_LOCKOBJ; + +/* + * Locker structures; these live in the locker hash table. + */ +typedef struct __db_locker { + u_int32_t id; /* Locker id. */ + u_int32_t dd_id; /* Deadlock detector id. */ + u_int32_t nlocks; /* Number of locks held. */ + u_int32_t nwrites; /* Number of write locks held. */ + roff_t master_locker; /* Locker of master transaction. */ + roff_t parent_locker; /* Parent of this child. */ + SH_LIST_HEAD(_child) child_locker; /* List of descendant txns; + only used in a "master" + txn. */ + SH_LIST_ENTRY child_link; /* Links transactions in the family; + elements of the child_locker + list. */ + SH_TAILQ_ENTRY links; /* Links for free and hash list. */ + SH_TAILQ_ENTRY ulinks; /* Links in-use list. */ + SH_LIST_HEAD(_held) heldby; /* Locks held by this locker. */ + db_timeval_t lk_expire; /* When current lock expires. */ + db_timeval_t tx_expire; /* When this txn expires. */ + db_timeout_t lk_timeout; /* How long do we let locks live. */ + +#define DB_LOCKER_DELETED 0x0001 +#define DB_LOCKER_DIRTY 0x0002 +#define DB_LOCKER_INABORT 0x0004 +#define DB_LOCKER_TIMEOUT 0x0008 + u_int32_t flags; +} DB_LOCKER; + +/* + * DB_LOCKTAB -- + * The primary library lock data structure (i.e., the one referenced + * by the environment, as opposed to the internal one laid out in the region.) + */ +typedef struct __db_locktab { + DB_ENV *dbenv; /* Environment. */ + REGINFO reginfo; /* Region information. */ + u_int8_t *conflicts; /* Pointer to conflict matrix. */ + DB_HASHTAB *obj_tab; /* Beginning of object hash table. */ + DB_HASHTAB *locker_tab; /* Beginning of locker hash table. */ +} DB_LOCKTAB; + +/* + * Test for conflicts. + * + * Cast HELD and WANTED to ints, they are usually db_lockmode_t enums. + */ +#define CONFLICTS(T, R, HELD, WANTED) \ + (T)->conflicts[((int)HELD) * (R)->stat.st_nmodes + ((int)WANTED)] + +#define OBJ_LINKS_VALID(L) ((L)->links.stqe_prev != -1) + +struct __db_lock { + /* + * Wait on mutex to wait on lock. You reference your own mutex with + * ID 0 and others reference your mutex with ID 1. + */ + DB_MUTEX mutex; + + u_int32_t holder; /* Who holds this lock. */ + u_int32_t gen; /* Generation count. */ + SH_TAILQ_ENTRY links; /* Free or holder/waiter list. */ + SH_LIST_ENTRY locker_links; /* List of locks held by a locker. */ + u_int32_t refcount; /* Reference count the lock. */ + db_lockmode_t mode; /* What sort of lock. */ + roff_t obj; /* Relative offset of object struct. */ + db_status_t status; /* Status of this lock. */ +}; + +/* + * Flag values for __lock_put_internal: + * DB_LOCK_DOALL: Unlock all references in this lock (instead of only 1). + * DB_LOCK_FREE: Free the lock (used in checklocker). + * DB_LOCK_NOPROMOTE: Don't bother running promotion when releasing locks + * (used by __lock_put_internal). + * DB_LOCK_UNLINK: Remove from the locker links (used in checklocker). + * Make sure that these do not conflict with the interface flags because + * we pass some of those around (i.e., DB_LOCK_REMOVE). + */ +#define DB_LOCK_DOALL 0x010000 +#define DB_LOCK_DOWNGRADE 0x020000 +#define DB_LOCK_FREE 0x040000 +#define DB_LOCK_NOPROMOTE 0x080000 +#define DB_LOCK_UNLINK 0x100000 +#define DB_LOCK_NOREGION 0x200000 +#define DB_LOCK_NOWAITERS 0x400000 + +/* + * Macros to get/release different types of mutexes. + */ +#define OBJECT_LOCK(lt, reg, obj, ndx) \ + ndx = __lock_ohash(obj) % (reg)->object_t_size +#define SHOBJECT_LOCK(lt, reg, shobj, ndx) \ + ndx = __lock_lhash(shobj) % (reg)->object_t_size +#define LOCKER_LOCK(lt, reg, locker, ndx) \ + ndx = __lock_locker_hash(locker) % (reg)->locker_t_size; + +#define LOCKREGION(dbenv, lt) R_LOCK((dbenv), &((DB_LOCKTAB *)lt)->reginfo) +#define UNLOCKREGION(dbenv, lt) R_UNLOCK((dbenv), &((DB_LOCKTAB *)lt)->reginfo) + +#include "dbinc_auto/lock_ext.h" +#endif /* !_DB_LOCK_H_ */ diff --git a/lib_dict/bdb/include/lock_ext.h b/lib_dict/bdb/include/lock_ext.h new file mode 100644 index 000000000..4b3ab4905 --- /dev/null +++ b/lib_dict/bdb/include/lock_ext.h @@ -0,0 +1,63 @@ +/* DO NOT EDIT: automatically built by dist/s_include. */ +#ifndef _lock_ext_h_ +#define _lock_ext_h_ + +#if defined(__cplusplus) +extern "C" { +#endif + +int __lock_vec_pp __P((DB_ENV *, u_int32_t, u_int32_t, DB_LOCKREQ *, int, DB_LOCKREQ **)); +int __lock_vec __P((DB_ENV *, u_int32_t, u_int32_t, DB_LOCKREQ *, int, DB_LOCKREQ **)); +int __lock_get_pp __P((DB_ENV *, u_int32_t, u_int32_t, const DBT *, db_lockmode_t, DB_LOCK *)); +int __lock_get __P((DB_ENV *, u_int32_t, u_int32_t, const DBT *, db_lockmode_t, DB_LOCK *)); +int __lock_get_internal __P((DB_LOCKTAB *, u_int32_t, u_int32_t, const DBT *, db_lockmode_t, db_timeout_t, DB_LOCK *)); +int __lock_put_pp __P((DB_ENV *, DB_LOCK *)); +int __lock_put __P((DB_ENV *, DB_LOCK *, u_int32_t)); +int __lock_downgrade __P((DB_ENV *, DB_LOCK *, db_lockmode_t, u_int32_t)); +int __lock_locker_is_parent __P((DB_ENV *, u_int32_t, u_int32_t, int *)); +int __lock_promote __P((DB_LOCKTAB *, DB_LOCKOBJ *, u_int32_t)); +int __lock_detect_pp __P((DB_ENV *, u_int32_t, u_int32_t, int *)); +int __lock_detect __P((DB_ENV *, u_int32_t, int *)); +int __lock_id_pp __P((DB_ENV *, u_int32_t *)); +int __lock_id __P((DB_ENV *, u_int32_t *)); +int __lock_id_free_pp __P((DB_ENV *, u_int32_t)); +int __lock_id_free __P((DB_ENV *, u_int32_t)); +int __lock_id_set __P((DB_ENV *, u_int32_t, u_int32_t)); +int __lock_getlocker __P((DB_LOCKTAB *, u_int32_t, u_int32_t, int, DB_LOCKER **)); +int __lock_addfamilylocker __P((DB_ENV *, u_int32_t, u_int32_t)); +int __lock_freefamilylocker __P((DB_LOCKTAB *, u_int32_t)); +void __lock_freelocker __P((DB_LOCKTAB *, DB_LOCKREGION *, DB_LOCKER *, u_int32_t)); +int __lock_fix_list __P((DB_ENV *, DBT *, u_int32_t)); +int __lock_get_list __P((DB_ENV *, u_int32_t, u_int32_t, db_lockmode_t, DBT *)); +void __lock_list_print __P((DB_ENV *, DBT *)); +void __lock_dbenv_create __P((DB_ENV *)); +int __lock_dbenv_close __P((DB_ENV *)); +int __lock_set_lk_detect __P((DB_ENV *, u_int32_t)); +int __lock_set_lk_max __P((DB_ENV *, u_int32_t)); +int __lock_set_lk_max_locks __P((DB_ENV *, u_int32_t)); +int __lock_set_lk_max_lockers __P((DB_ENV *, u_int32_t)); +int __lock_set_lk_max_objects __P((DB_ENV *, u_int32_t)); +int __lock_set_env_timeout __P((DB_ENV *, db_timeout_t, u_int32_t)); +int __lock_open __P((DB_ENV *)); +int __lock_dbenv_refresh __P((DB_ENV *)); +void __lock_region_destroy __P((DB_ENV *, REGINFO *)); +int __lock_stat_pp __P((DB_ENV *, DB_LOCK_STAT **, u_int32_t)); +int __lock_stat_print_pp __P((DB_ENV *, u_int32_t)); +int __lock_stat_print __P((DB_ENV *, u_int32_t)); +void __lock_printlock __P((DB_LOCKTAB *, DB_MSGBUF *mbp, struct __db_lock *, int)); +int __lock_set_timeout __P(( DB_ENV *, u_int32_t, db_timeout_t, u_int32_t)); +int __lock_set_timeout_internal __P((DB_ENV *, u_int32_t, db_timeout_t, u_int32_t)); +int __lock_inherit_timeout __P(( DB_ENV *, u_int32_t, u_int32_t)); +void __lock_expires __P((DB_ENV *, db_timeval_t *, db_timeout_t)); +int __lock_expired __P((DB_ENV *, db_timeval_t *, db_timeval_t *)); +int __lock_cmp __P((const DBT *, DB_LOCKOBJ *)); +int __lock_locker_cmp __P((u_int32_t, DB_LOCKER *)); +u_int32_t __lock_ohash __P((const DBT *)); +u_int32_t __lock_lhash __P((DB_LOCKOBJ *)); +u_int32_t __lock_locker_hash __P((u_int32_t)); +int __lock_nomem __P((DB_ENV *, const char *)); + +#if defined(__cplusplus) +} +#endif +#endif /* !_lock_ext_h_ */ diff --git a/lib_dict/bdb/include/log.h b/lib_dict/bdb/include/log.h new file mode 100644 index 000000000..9a8690138 --- /dev/null +++ b/lib_dict/bdb/include/log.h @@ -0,0 +1,379 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996-2004 + * Sleepycat Software. All rights reserved. + * + * $Id: log.h,v 11.90 2004/10/15 16:59:39 bostic Exp $ + */ + +#ifndef _LOG_H_ +#define _LOG_H_ + +/******************************************************* + * DBREG: + * The DB file register code keeps track of open files. It's stored + * in the log subsystem's shared region, and so appears in the log.h + * header file, but is logically separate. + *******************************************************/ +/* + * The per-process table that maps log file-id's to DB structures. + */ +typedef struct __db_entry { + DB *dbp; /* Open dbp for this file id. */ + int deleted; /* File was not found during open. */ +} DB_ENTRY; + +/* + * FNAME -- + * File name and id. + */ +struct __fname { + SH_TAILQ_ENTRY q; /* File name queue. */ + + int32_t id; /* Logging file id. */ + DBTYPE s_type; /* Saved DB type. */ + + roff_t name_off; /* Name offset. */ + db_pgno_t meta_pgno; /* Page number of the meta page. */ + u_int8_t ufid[DB_FILE_ID_LEN]; /* Unique file id. */ + + u_int32_t create_txnid; /* + * Txn ID of the DB create, stored so + * we can log it at register time. + */ + int is_durable; /* Is this file durable or not. */ +}; + +/* File open/close register log record opcodes. */ +#define DBREG_CHKPNT 1 /* Checkpoint: file name/id dump. */ +#define DBREG_CLOSE 2 /* File close. */ +#define DBREG_OPEN 3 /* File open. */ +#define DBREG_RCLOSE 4 /* File close after recovery. */ + +/******************************************************* + * LOG: + * The log subsystem information. + *******************************************************/ +struct __db_log; typedef struct __db_log DB_LOG; +struct __hdr; typedef struct __hdr HDR; +struct __log; typedef struct __log LOG; +struct __log_persist; typedef struct __log_persist LOGP; + +#define LFPREFIX "log." /* Log file name prefix. */ +#define LFNAME "log.%010d" /* Log file name template. */ +#define LFNAME_V1 "log.%05d" /* Log file name template, rev 1. */ + +#define LG_MAX_DEFAULT (10 * MEGABYTE) /* 10 MB. */ +#define LG_MAX_INMEM (256 * 1024) /* 256 KB. */ +#define LG_BSIZE_DEFAULT (32 * 1024) /* 32 KB. */ +#define LG_BSIZE_INMEM (1 * MEGABYTE) /* 1 MB. */ +#define LG_BASE_REGION_SIZE (60 * 1024) /* 60 KB. */ + +/* + * DB_LOG + * Per-process log structure. + */ +struct __db_log { +/* + * These fields need to be protected for multi-threaded support. + * + * !!! + * As this structure is allocated in per-process memory, the mutex may need + * to be stored elsewhere on architectures unable to support mutexes in heap + * memory, e.g., HP/UX 9. + */ + DB_MUTEX *mutexp; /* Mutex for thread protection. */ + + DB_ENTRY *dbentry; /* Recovery file-id mapping. */ +#define DB_GROW_SIZE 64 + int32_t dbentry_cnt; /* Entries. Grows by DB_GROW_SIZE. */ + +/* + * These fields are always accessed while the region lock is held, so they do + * not have to be protected by the thread lock as well. + */ + u_int32_t lfname; /* Log file "name". */ + DB_FH *lfhp; /* Log file handle. */ + + u_int8_t *bufp; /* Region buffer. */ + +/* These fields are not protected. */ + DB_ENV *dbenv; /* Reference to error information. */ + REGINFO reginfo; /* Region information. */ + +#define DBLOG_RECOVER 0x01 /* We are in recovery. */ +#define DBLOG_FORCE_OPEN 0x02 /* Force the DB open even if it appears + * to be deleted. */ + u_int32_t flags; +}; + +/* + * HDR -- + * Log record header. + */ +struct __hdr { + u_int32_t prev; /* Previous offset. */ + u_int32_t len; /* Current length. */ + u_int8_t chksum[DB_MAC_KEY]; /* Current checksum. */ + u_int8_t iv[DB_IV_BYTES]; /* IV */ + u_int32_t orig_size; /* Original size of log record */ + /* !!! - 'size' is not written to log, must be last in hdr */ + size_t size; /* Size of header to use */ +}; + +/* + * We use HDR internally, and then when we write out, we write out + * prev, len, and then a 4-byte checksum if normal operation or + * a crypto-checksum and IV and original size if running in crypto + * mode. We must store the original size in case we pad. Set the + * size when we set up the header. We compute a DB_MAC_KEY size + * checksum regardless, but we can safely just use the first 4 bytes. + */ +#define HDR_NORMAL_SZ 12 +#define HDR_CRYPTO_SZ 12 + DB_MAC_KEY + DB_IV_BYTES + +struct __log_persist { + u_int32_t magic; /* DB_LOGMAGIC */ + u_int32_t version; /* DB_LOGVERSION */ + + u_int32_t log_size; /* Log file size. */ + u_int32_t mode; /* Log file mode. */ +}; + +/* + * LOG -- + * Shared log region. One of these is allocated in shared memory, + * and describes the log. + */ +struct __log { + /* + * Due to alignment constraints on some architectures (e.g. HP-UX), + * DB_MUTEXes must be the first element of shalloced structures, + * and as a corollary there can be only one per structure. Thus, + * flush_mutex_off points to a mutex in a separately-allocated chunk. + */ + DB_MUTEX fq_mutex; /* Mutex guarding file name list. */ + + LOGP persist; /* Persistent information. */ + + SH_TAILQ_HEAD(__fq1) fq; /* List of file names. */ + int32_t fid_max; /* Max fid allocated. */ + roff_t free_fid_stack; /* Stack of free file ids. */ + u_int free_fids; /* Height of free fid stack. */ + u_int free_fids_alloced; /* N free fid slots allocated. */ + + /* + * The lsn LSN is the file offset that we're about to write and which + * we will return to the user. + */ + DB_LSN lsn; /* LSN at current file offset. */ + + /* + * The f_lsn LSN is the LSN (returned to the user) that "owns" the + * first byte of the buffer. If the record associated with the LSN + * spans buffers, it may not reflect the physical file location of + * the first byte of the buffer. + */ + DB_LSN f_lsn; /* LSN of first byte in the buffer. */ + size_t b_off; /* Current offset in the buffer. */ + u_int32_t w_off; /* Current write offset in the file. */ + u_int32_t len; /* Length of the last record. */ + + DB_LSN active_lsn; /* Oldest active LSN in the buffer. */ + size_t a_off; /* Offset in the buffer of first active + file. */ + + /* + * Due to alignment constraints on some architectures (e.g. HP-UX), + * DB_MUTEXes must be the first element of shalloced structures, + * and as a corollary there can be only one per structure. Thus, + * flush_mutex_off points to a mutex in a separately-allocated chunk. + * + * The s_lsn LSN is the last LSN that we know is on disk, not just + * written, but synced. This field is protected by the flush mutex + * rather than by the region mutex. + */ + int in_flush; /* Log flush in progress. */ + roff_t flush_mutex_off; /* Mutex guarding flushing. */ + DB_LSN s_lsn; /* LSN of the last sync. */ + + DB_LOG_STAT stat; /* Log statistics. */ + + /* + * !!! - NOTE that the next 7 fields, waiting_lsn, verify_lsn, + * max_wait_lsn, maxperm_lsn, wait_recs, rcvd_recs, + * and ready_lsn are NOT protected + * by the log region lock. They are protected by db_rep->db_mutexp. + * If you need access to both, you must acquire db_rep->db_mutexp + * before acquiring the log region lock. + * + * The waiting_lsn is used by the replication system. It is the + * first LSN that we are holding without putting in the log, because + * we received one or more log records out of order. Associated with + * the waiting_lsn is the number of log records that we still have to + * receive before we decide that we should request it again. + * + * The max_wait_lsn is used to control retransmission in the face + * of dropped messages. If we are requesting all records from the + * current gap (i.e., chunk of the log that we are missing), then + * the max_wait_lsn contains the first LSN that we are known to have + * in the __db.rep.db. If we requested only a single record, then + * the max_wait_lsn has the LSN of that record we requested. + */ + DB_LSN waiting_lsn; /* First log record after a gap. */ + DB_LSN verify_lsn; /* LSN we are waiting to verify. */ + DB_LSN max_wait_lsn; /* Maximum LSN requested. */ + DB_LSN max_perm_lsn; /* Maximum PERMANENT LSN processed. */ + u_int32_t wait_recs; /* Records to wait before requesting. */ + u_int32_t rcvd_recs; /* Records received while waiting. */ + /* + * The ready_lsn is also used by the replication system. It is the + * next LSN we expect to receive. It's normally equal to "lsn", + * except at the beginning of a log file, at which point it's set + * to the LSN of the first record of the new file (after the + * header), rather than to 0. + */ + DB_LSN ready_lsn; + + /* + * During initialization, the log system walks forward through the + * last log file to find its end. If it runs into a checkpoint + * while it's doing so, it caches it here so that the transaction + * system doesn't need to walk through the file again on its + * initialization. + */ + DB_LSN cached_ckp_lsn; + + u_int32_t regionmax; /* Configured size of the region. */ + + roff_t buffer_off; /* Log buffer offset in the region. */ + u_int32_t buffer_size; /* Log buffer size. */ + + u_int32_t log_size; /* Log file's size. */ + u_int32_t log_nsize; /* Next log file's size. */ + + /* + * DB_LOG_AUTOREMOVE and DB_LOG_INMEMORY: not protected by a mutex, + * all we care about is if they're zero or non-zero. + */ + int db_log_autoremove; + int db_log_inmemory; + + u_int32_t ncommit; /* Number of txns waiting to commit. */ + DB_LSN t_lsn; /* LSN of first commit */ + SH_TAILQ_HEAD(__commit) commits;/* list of txns waiting to commit. */ + SH_TAILQ_HEAD(__free) free_commits;/* free list of commit structs. */ + + /* + * In-memory logs maintain a list of the start positions of all log + * files currently active in the in-memory buffer. This is to make the + * lookup from LSN to log buffer offset efficient. + */ + SH_TAILQ_HEAD(__logfile) logfiles; + SH_TAILQ_HEAD(__free_logfile) free_logfiles; + +#ifdef HAVE_MUTEX_SYSTEM_RESOURCES +#define LG_MAINT_SIZE (sizeof(roff_t) * DB_MAX_HANDLES) + + roff_t maint_off; /* offset of region maintenance info */ +#endif +}; + +/* + * __db_commit structure -- + * One of these is allocated for each transaction waiting to commit. + */ +struct __db_commit { + DB_MUTEX mutex; /* Mutex for txn to wait on. */ + DB_LSN lsn; /* LSN of commit record. */ + SH_TAILQ_ENTRY links; /* Either on free or waiting list. */ + +#define DB_COMMIT_FLUSH 0x0001 /* Flush the log when you wake up. */ + u_int32_t flags; +}; + +/* + * Check for the proper progression of Log Sequence Numbers. + * If we are rolling forward the LSN on the page must be greater + * than or equal to the previous LSN in log record. + * We ignore NOT LOGGED LSNs. The user did an unlogged update. + * We should eventually see a log record that matches and continue + * forward. + * If truncate is supported then a ZERO LSN implies a page that was + * allocated prior to the recovery start pont and then truncated + * later in the log. An allocation of a page after this + * page will extend the file, leaving a hole. We want to + * ignore this page until it is truncated again. + * + */ + +#ifdef HAVE_FTRUNCATE +#define CHECK_LSN(redo, cmp, lsn, prev) \ + if (DB_REDO(redo) && (cmp) < 0 && \ + !IS_NOT_LOGGED_LSN(*(lsn)) && !IS_ZERO_LSN(*(lsn))) { \ + ret = __db_check_lsn(dbenv, lsn, prev); \ + goto out; \ + } +#else +#define CHECK_LSN(redo, cmp, lsn, prev) \ + if (DB_REDO(redo) && (cmp) < 0 && !IS_NOT_LOGGED_LSN(*(lsn))) { \ + ret = __db_check_lsn(dbenv, lsn, prev); \ + goto out; \ + } +#endif + +/* + * Helper for in-memory logs -- check whether an offset is in range + * in a ring buffer (inclusive of start, exclusive of end). + */ +struct __db_filestart { + u_int32_t file; + size_t b_off; + + SH_TAILQ_ENTRY links; /* Either on free or waiting list. */ +}; + +#define RINGBUF_LEN(lp, start, end) \ + ((start) < (end) ? \ + (end) - (start) : (lp)->buffer_size - ((start) - (end))) + +/* + * Internal macro to set pointer to the begin_lsn for generated + * logging routines. If begin_lsn is already set then do nothing. + */ +#undef DB_SET_BEGIN_LSNP +#define DB_SET_BEGIN_LSNP(txn, rlsnp) do { \ + DB_LSN *__lsnp; \ + TXN_DETAIL *__td; \ + __td = R_ADDR(&(txn)->mgrp->reginfo, (txn)->off); \ + while (__td->parent != INVALID_ROFF) \ + __td = R_ADDR(&(txn)->mgrp->reginfo, __td->parent); \ + __lsnp = &__td->begin_lsn; \ + if (IS_ZERO_LSN(*__lsnp)) \ + *(rlsnp) = __lsnp; \ +} while (0) + +/* + * These are used in __log_backup to determine which LSN in the + * checkpoint record to compare and return. + */ +#define CKPLSN_CMP 0 +#define LASTCKP_CMP 1 + +/* + * Status codes indicating the validity of a log file examined by + * __log_valid(). + */ +typedef enum { + DB_LV_INCOMPLETE, + DB_LV_NONEXISTENT, + DB_LV_NORMAL, + DB_LV_OLD_READABLE, + DB_LV_OLD_UNREADABLE +} logfile_validity; + +#include "dbinc_auto/dbreg_auto.h" +#include "dbinc_auto/dbreg_ext.h" +#include "dbinc_auto/log_ext.h" +#endif /* !_LOG_H_ */ diff --git a/lib_dict/bdb/include/log_ext.h b/lib_dict/bdb/include/log_ext.h new file mode 100644 index 000000000..c1fbd211b --- /dev/null +++ b/lib_dict/bdb/include/log_ext.h @@ -0,0 +1,53 @@ +/* DO NOT EDIT: automatically built by dist/s_include. */ +#ifndef _log_ext_h_ +#define _log_ext_h_ + +#if defined(__cplusplus) +extern "C" { +#endif + +int __log_open __P((DB_ENV *)); +int __log_find __P((DB_LOG *, int, u_int32_t *, logfile_validity *)); +int __log_valid __P((DB_LOG *, u_int32_t, int, DB_FH **, u_int32_t, logfile_validity *)); +int __log_dbenv_refresh __P((DB_ENV *)); +void __log_get_cached_ckp_lsn __P((DB_ENV *, DB_LSN *)); +void __log_region_destroy __P((DB_ENV *, REGINFO *)); +int __log_vtruncate __P((DB_ENV *, DB_LSN *, DB_LSN *, DB_LSN *)); +int __log_is_outdated __P((DB_ENV *, u_int32_t, int *)); +int __log_inmem_lsnoff __P((DB_LOG *, DB_LSN *, size_t *)); +int __log_inmem_newfile __P((DB_LOG *, u_int32_t)); +int __log_inmem_chkspace __P((DB_LOG *, size_t)); +void __log_inmem_copyout __P((DB_LOG *, size_t, void *, size_t)); +void __log_inmem_copyin __P((DB_LOG *, size_t, void *, size_t)); +int __log_archive_pp __P((DB_ENV *, char **[], u_int32_t)); +void __log_autoremove __P((DB_ENV *)); +int __log_cursor_pp __P((DB_ENV *, DB_LOGC **, u_int32_t)); +int __log_cursor __P((DB_ENV *, DB_LOGC **)); +int __log_c_close __P((DB_LOGC *)); +int __log_c_get __P((DB_LOGC *, DB_LSN *, DBT *, u_int32_t)); +void __log_dbenv_create __P((DB_ENV *)); +int __log_set_lg_bsize __P((DB_ENV *, u_int32_t)); +int __log_set_lg_max __P((DB_ENV *, u_int32_t)); +int __log_set_lg_regionmax __P((DB_ENV *, u_int32_t)); +int __log_set_lg_dir __P((DB_ENV *, const char *)); +void __log_get_flags __P((DB_ENV *, u_int32_t *)); +void __log_set_flags __P((DB_ENV *, u_int32_t, int)); +int __log_check_sizes __P((DB_ENV *, u_int32_t, u_int32_t)); +int __log_put_pp __P((DB_ENV *, DB_LSN *, const DBT *, u_int32_t)); +int __log_put __P((DB_ENV *, DB_LSN *, const DBT *, u_int32_t)); +void __log_txn_lsn __P((DB_ENV *, DB_LSN *, u_int32_t *, u_int32_t *)); +int __log_newfile __P((DB_LOG *, DB_LSN *, u_int32_t)); +int __log_flush_pp __P((DB_ENV *, const DB_LSN *)); +int __log_flush __P((DB_ENV *, const DB_LSN *)); +int __log_flush_int __P((DB_LOG *, const DB_LSN *, int)); +int __log_file_pp __P((DB_ENV *, const DB_LSN *, char *, size_t)); +int __log_name __P((DB_LOG *, u_int32_t, char **, DB_FH **, u_int32_t)); +int __log_rep_put __P((DB_ENV *, DB_LSN *, const DBT *)); +int __log_stat_pp __P((DB_ENV *, DB_LOG_STAT **, u_int32_t)); +int __log_stat_print_pp __P((DB_ENV *, u_int32_t)); +int __log_stat_print __P((DB_ENV *, u_int32_t)); + +#if defined(__cplusplus) +} +#endif +#endif /* !_log_ext_h_ */ diff --git a/lib_dict/bdb/include/mp.h b/lib_dict/bdb/include/mp.h new file mode 100644 index 000000000..871bd6df9 --- /dev/null +++ b/lib_dict/bdb/include/mp.h @@ -0,0 +1,356 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996-2004 + * Sleepycat Software. All rights reserved. + * + * $Id: mp.h,v 11.61 2004/09/17 22:00:27 mjc Exp $ + */ + +#ifndef _DB_MP_H_ +#define _DB_MP_H_ + +struct __bh; typedef struct __bh BH; +struct __db_mpool_hash; typedef struct __db_mpool_hash DB_MPOOL_HASH; +struct __db_mpreg; typedef struct __db_mpreg DB_MPREG; +struct __mpool; typedef struct __mpool MPOOL; + + /* We require at least 20KB of cache. */ +#define DB_CACHESIZE_MIN (20 * 1024) + +/* + * DB_MPOOLFILE initialization methods cannot be called after open is called, + * other methods cannot be called before open is called + */ +#define MPF_ILLEGAL_AFTER_OPEN(dbmfp, name) \ + if (F_ISSET(dbmfp, MP_OPEN_CALLED)) \ + return (__db_mi_open((dbmfp)->dbenv, name, 1)); +#define MPF_ILLEGAL_BEFORE_OPEN(dbmfp, name) \ + if (!F_ISSET(dbmfp, MP_OPEN_CALLED)) \ + return (__db_mi_open((dbmfp)->dbenv, name, 0)); + +typedef enum { + DB_SYNC_ALLOC, /* Flush for allocation. */ + DB_SYNC_CACHE, /* Checkpoint or flush entire cache. */ + DB_SYNC_FILE, /* Flush file. */ + DB_SYNC_TRICKLE /* Trickle sync. */ +} db_sync_op; + +/* + * DB_MPOOL -- + * Per-process memory pool structure. + */ +struct __db_mpool { + /* These fields need to be protected for multi-threaded support. */ + DB_MUTEX *mutexp; /* Structure thread lock. */ + + /* List of pgin/pgout routines. */ + LIST_HEAD(__db_mpregh, __db_mpreg) dbregq; + + /* List of DB_MPOOLFILE's. */ + TAILQ_HEAD(__db_mpoolfileh, __db_mpoolfile) dbmfq; + + /* + * The dbenv, nreg and reginfo fields are not thread protected, + * as they are initialized during mpool creation, and not modified + * again. + */ + DB_ENV *dbenv; /* Enclosing environment. */ + + u_int32_t nreg; /* N underlying cache regions. */ + REGINFO *reginfo; /* Underlying cache regions. */ +}; + +/* + * DB_MPREG -- + * DB_MPOOL registry of pgin/pgout functions. + */ +struct __db_mpreg { + LIST_ENTRY(__db_mpreg) q; /* Linked list. */ + + int32_t ftype; /* File type. */ + /* Pgin, pgout routines. */ + int (*pgin) __P((DB_ENV *, db_pgno_t, void *, DBT *)); + int (*pgout) __P((DB_ENV *, db_pgno_t, void *, DBT *)); +}; + +/* + * NCACHE -- + * Select a cache based on the file and the page number. Assumes accesses + * are uniform across pages, which is probably OK. What we really want to + * avoid is anything that puts all pages from any single file in the same + * cache, as we expect that file access will be bursty, and to avoid + * putting all page number N pages in the same cache as we expect access + * to the metapages (page 0) and the root of a btree (page 1) to be much + * more frequent than a random data page. + */ +#define NCACHE(mp, mf_offset, pgno) \ + (((pgno) ^ ((u_int32_t)(mf_offset) >> 3)) % ((MPOOL *)mp)->nreg) + +/* + * NBUCKET -- + * We make the assumption that early pages of the file are more likely + * to be retrieved than the later pages, which means the top bits will + * be more interesting for hashing as they're less likely to collide. + * That said, as 512 8K pages represents a 4MB file, so only reasonably + * large files will have page numbers with any other than the bottom 9 + * bits set. We XOR in the MPOOL offset of the MPOOLFILE that backs the + * page, since that should also be unique for the page. We don't want + * to do anything very fancy -- speed is more important to us than using + * good hashing. + */ +#define NBUCKET(mc, mf_offset, pgno) \ + (((pgno) ^ ((mf_offset) << 9)) % (mc)->htab_buckets) + +/* + * MPOOL -- + * Shared memory pool region. + */ +struct __mpool { + /* + * The memory pool can be broken up into individual pieces/files. + * Not what we would have liked, but on Solaris you can allocate + * only a little more than 2GB of memory in a contiguous chunk, + * and I expect to see more systems with similar issues. + * + * While this structure is duplicated in each piece of the cache, + * the first of these pieces/files describes the entire pool, the + * second only describe a piece of the cache. + */ + + /* + * The lsn field and list of underlying MPOOLFILEs are thread protected + * by the region lock. + */ + DB_LSN lsn; /* Maximum checkpoint LSN. */ + + SH_TAILQ_HEAD(__mpfq) mpfq; /* List of MPOOLFILEs. */ + + /* Configuration information: protected by the region lock. */ + size_t mp_mmapsize; /* Maximum file size for mmap. */ + int mp_maxopenfd; /* Maximum open file descriptors. */ + int mp_maxwrite; /* Maximum buffers to write. */ + int mp_maxwrite_sleep; /* Sleep after writing max buffers. */ + + /* + * The nreg, regids and maint_off fields are not thread protected, + * as they are initialized during mpool creation, and not modified + * again. + */ + u_int32_t nreg; /* Number of underlying REGIONS. */ + roff_t regids; /* Array of underlying REGION Ids. */ + +#ifdef HAVE_MUTEX_SYSTEM_RESOURCES + roff_t maint_off; /* Maintenance information offset */ +#endif + + /* + * The following structure fields only describe the per-cache portion + * of the region. + * + * The htab and htab_buckets fields are not thread protected as they + * are initialized during mpool creation, and not modified again. + * + * The last_checked and lru_count fields are thread protected by + * the region lock. + */ + u_int32_t htab_buckets; /* Number of hash table entries. */ + roff_t htab; /* Hash table offset. */ + u_int32_t last_checked; /* Last bucket checked for free. */ + u_int32_t lru_count; /* Counter for buffer LRU */ + + /* + * The stat fields are generally not thread protected, and cannot be + * trusted. Note that st_pages is an exception, and is always updated + * inside a region lock (although it is sometimes read outside of the + * region lock). + */ + DB_MPOOL_STAT stat; /* Per-cache mpool statistics. */ + + /* + * We track page puts so that we can decide when allocation is never + * going to succeed. We don't lock the field, all we care about is + * if it changes. + */ + u_int32_t put_counter; /* Count of page put calls. */ +}; + +struct __db_mpool_hash { + DB_MUTEX hash_mutex; /* Per-bucket mutex. */ + + DB_HASHTAB hash_bucket; /* Head of bucket. */ + + u_int32_t hash_page_dirty;/* Count of dirty pages. */ + u_int32_t hash_priority; /* Minimum priority of bucket buffer. */ + +#ifdef HPUX_MUTEX_PAD + /* + * !!! + * We allocate the mpool hash buckets as an array, which means that + * they are not individually aligned. This fails on one platform: + * HPUX 10.20, where mutexes require 16 byte alignment. This is a + * grievous hack for that single platform. + */ + u_int8_t pad[HPUX_MUTEX_PAD]; +#endif +}; + +/* + * The base mpool priority is 1/4th of the name space, or just under 2^30. + * When the LRU counter wraps, we shift everybody down to a base-relative + * value. + */ +#define MPOOL_BASE_DECREMENT (UINT32_MAX - (UINT32_MAX / 4)) + +/* + * Mpool priorities from low to high. Defined in terms of fractions of the + * buffers in the pool. + */ +#define MPOOL_PRI_VERY_LOW -1 /* Dead duck. Check and set to 0. */ +#define MPOOL_PRI_LOW -2 /* Low. */ +#define MPOOL_PRI_DEFAULT 0 /* No adjustment -- special case.*/ +#define MPOOL_PRI_HIGH 10 /* With the dirty buffers. */ +#define MPOOL_PRI_DIRTY 10 /* Dirty gets a 10% boost. */ +#define MPOOL_PRI_VERY_HIGH 1 /* Add number of buffers in pool. */ + +/* + * MPOOLFILE -- + * Shared DB_MPOOLFILE information. + */ +struct __mpoolfile { + DB_MUTEX mutex; + + /* Protected by MPOOLFILE mutex. */ + u_int32_t mpf_cnt; /* Ref count: DB_MPOOLFILEs. */ + u_int32_t block_cnt; /* Ref count: blocks in cache. */ + + roff_t path_off; /* File name location. */ + + /* + * We normally don't lock the deadfile field when we read it since we + * only care if the field is zero or non-zero. We do lock on read when + * searching for a matching MPOOLFILE -- see that code for more detail. + */ + int32_t deadfile; /* Dirty pages can be discarded. */ + + /* Protected by mpool cache 0 region lock. */ + SH_TAILQ_ENTRY q; /* List of MPOOLFILEs */ + db_pgno_t last_pgno; /* Last page in the file. */ + db_pgno_t orig_last_pgno; /* Original last page in the file. */ + db_pgno_t maxpgno; /* Maximum page number. */ + + /* + * None of the following fields are thread protected. + * + * There are potential races with the ftype field because it's read + * without holding a lock. However, it has to be set before adding + * any buffers to the cache that depend on it being set, so there + * would need to be incorrect operation ordering to have a problem. + */ + int32_t ftype; /* File type. */ + + /* + * There are potential races with the priority field because it's read + * without holding a lock. However, a collision is unlikely and if it + * happens is of little consequence. + */ + int32_t priority; /* Priority when unpinning buffer. */ + + /* + * There are potential races with the file_written field (many threads + * may be writing blocks at the same time), and with no_backing_file + * and unlink_on_close fields, as they may be set while other threads + * are reading them. However, we only care if the field value is zero + * or non-zero, so don't lock the memory. + * + * !!! + * Theoretically, a 64-bit architecture could put two of these fields + * in a single memory operation and we could race. I have never seen + * an architecture where that's a problem, and I believe Java requires + * that to never be the case. + * + * File_written is set whenever a buffer is marked dirty in the cache. + * It can be cleared in some cases, after all dirty buffers have been + * written AND the file has been flushed to disk. + */ + int32_t file_written; /* File was written. */ + int32_t no_backing_file; /* Never open a backing file. */ + int32_t unlink_on_close; /* Unlink file on last close. */ + + /* + * We do not protect the statistics in "stat" because of the cost of + * the mutex in the get/put routines. There is a chance that a count + * will get lost. + */ + DB_MPOOL_FSTAT stat; /* Per-file mpool statistics. */ + + /* + * The remaining fields are initialized at open and never subsequently + * modified. + */ + int32_t lsn_off; /* Page's LSN offset. */ + u_int32_t clear_len; /* Bytes to clear on page create. */ + + roff_t fileid_off; /* File ID string location. */ + + roff_t pgcookie_len; /* Pgin/pgout cookie length. */ + roff_t pgcookie_off; /* Pgin/pgout cookie location. */ + + /* + * The flags are initialized at open and never subsequently modified. + */ +#define MP_CAN_MMAP 0x001 /* If the file can be mmap'd. */ +#define MP_DIRECT 0x002 /* No OS buffering. */ +#define MP_DURABLE_UNKNOWN 0x004 /* We don't care about durability. */ +#define MP_EXTENT 0x008 /* Extent file. */ +#define MP_FAKE_DEADFILE 0x010 /* Deadfile field: fake flag. */ +#define MP_FAKE_FILEWRITTEN 0x020 /* File_written field: fake flag. */ +#define MP_FAKE_NB 0x040 /* No_backing_file field: fake flag. */ +#define MP_FAKE_UOC 0x080 /* Unlink_on_close field: fake flag. */ +#define MP_NOT_DURABLE 0x100 /* File is not durable. */ +#define MP_TEMP 0x200 /* Backing file is a temporary. */ + u_int32_t flags; +}; + +/* + * Flags to __memp_bh_free. + */ +#define BH_FREE_FREEMEM 0x01 +#define BH_FREE_UNLOCKED 0x02 + +/* + * BH -- + * Buffer header. + */ +struct __bh { + DB_MUTEX mutex; /* Buffer thread/process lock. */ + + u_int16_t ref; /* Reference count. */ + u_int16_t ref_sync; /* Sync wait-for reference count. */ + +#define BH_CALLPGIN 0x001 /* Convert the page before use. */ +#define BH_DIRTY 0x002 /* Page was modified. */ +#define BH_DIRTY_CREATE 0x004 /* Page created, must be written. */ +#define BH_DISCARD 0x008 /* Page is useless. */ +#define BH_LOCKED 0x010 /* Page is locked (I/O in progress). */ +#define BH_TRASH 0x020 /* Page is garbage. */ + u_int16_t flags; + + u_int32_t priority; /* LRU priority. */ + SH_TAILQ_ENTRY hq; /* MPOOL hash bucket queue. */ + + db_pgno_t pgno; /* Underlying MPOOLFILE page number. */ + roff_t mf_offset; /* Associated MPOOLFILE offset. */ + + /* + * !!! + * This array must be at least size_t aligned -- the DB access methods + * put PAGE and other structures into it, and then access them directly. + * (We guarantee size_t alignment to applications in the documentation, + * too.) + */ + u_int8_t buf[1]; /* Variable length data. */ +}; + +#include "dbinc_auto/mp_ext.h" +#endif /* !_DB_MP_H_ */ diff --git a/lib_dict/bdb/include/mp_ext.h b/lib_dict/bdb/include/mp_ext.h new file mode 100644 index 000000000..ada970431 --- /dev/null +++ b/lib_dict/bdb/include/mp_ext.h @@ -0,0 +1,72 @@ +/* DO NOT EDIT: automatically built by dist/s_include. */ +#ifndef _mp_ext_h_ +#define _mp_ext_h_ + +#if defined(__cplusplus) +extern "C" { +#endif + +int __memp_alloc __P((DB_MPOOL *, REGINFO *, MPOOLFILE *, size_t, roff_t *, void *)); +#ifdef DIAGNOSTIC +void __memp_check_order __P((DB_MPOOL_HASH *)); +#endif +int __memp_bhwrite __P((DB_MPOOL *, DB_MPOOL_HASH *, MPOOLFILE *, BH *, int)); +int __memp_pgread __P((DB_MPOOLFILE *, DB_MUTEX *, BH *, int)); +int __memp_pg __P((DB_MPOOLFILE *, BH *, int)); +void __memp_bhfree __P((DB_MPOOL *, DB_MPOOL_HASH *, BH *, u_int32_t)); +int __memp_fget_pp __P((DB_MPOOLFILE *, db_pgno_t *, u_int32_t, void *)); +int __memp_fget __P((DB_MPOOLFILE *, db_pgno_t *, u_int32_t, void *)); +int __memp_fcreate_pp __P((DB_ENV *, DB_MPOOLFILE **, u_int32_t)); +int __memp_fcreate __P((DB_ENV *, DB_MPOOLFILE **)); +int __memp_set_clear_len __P((DB_MPOOLFILE *, u_int32_t)); +int __memp_get_fileid __P((DB_MPOOLFILE *, u_int8_t *)); +int __memp_set_fileid __P((DB_MPOOLFILE *, u_int8_t *)); +int __memp_get_flags __P((DB_MPOOLFILE *, u_int32_t *)); +int __memp_set_flags __P((DB_MPOOLFILE *, u_int32_t, int)); +int __memp_get_ftype __P((DB_MPOOLFILE *, int *)); +int __memp_set_ftype __P((DB_MPOOLFILE *, int)); +int __memp_set_lsn_offset __P((DB_MPOOLFILE *, int32_t)); +int __memp_set_pgcookie __P((DB_MPOOLFILE *, DBT *)); +void __memp_last_pgno __P((DB_MPOOLFILE *, db_pgno_t *)); +char * __memp_fn __P((DB_MPOOLFILE *)); +char * __memp_fns __P((DB_MPOOL *, MPOOLFILE *)); +int __memp_fopen_pp __P((DB_MPOOLFILE *, const char *, u_int32_t, int, size_t)); +int __memp_fopen __P((DB_MPOOLFILE *, MPOOLFILE *, const char *, u_int32_t, int, size_t)); +int __memp_fclose_pp __P((DB_MPOOLFILE *, u_int32_t)); +int __memp_fclose __P((DB_MPOOLFILE *, u_int32_t)); +int __memp_mf_discard __P((DB_MPOOL *, MPOOLFILE *)); +int __memp_fput_pp __P((DB_MPOOLFILE *, void *, u_int32_t)); +int __memp_fput __P((DB_MPOOLFILE *, void *, u_int32_t)); +int __memp_fset_pp __P((DB_MPOOLFILE *, void *, u_int32_t)); +int __memp_fset __P((DB_MPOOLFILE *, void *, u_int32_t)); +void __memp_dbenv_create __P((DB_ENV *)); +int __memp_get_cachesize __P((DB_ENV *, u_int32_t *, u_int32_t *, int *)); +int __memp_set_cachesize __P((DB_ENV *, u_int32_t, u_int32_t, int)); +int __memp_set_mp_max_openfd __P((DB_ENV *, int)); +int __memp_set_mp_max_write __P((DB_ENV *, int, int)); +int __memp_set_mp_mmapsize __P((DB_ENV *, size_t)); +int __memp_nameop __P((DB_ENV *, u_int8_t *, const char *, const char *, const char *)); +int __memp_get_refcnt __P((DB_ENV *, u_int8_t *, u_int32_t *)); +int __memp_ftruncate __P((DB_MPOOLFILE *, db_pgno_t, u_int32_t)); +int __memp_open __P((DB_ENV *)); +int __memp_dbenv_refresh __P((DB_ENV *)); +void __memp_region_destroy __P((DB_ENV *, REGINFO *)); +int __memp_register_pp __P((DB_ENV *, int, int (*)(DB_ENV *, db_pgno_t, void *, DBT *), int (*)(DB_ENV *, db_pgno_t, void *, DBT *))); +int __memp_register __P((DB_ENV *, int, int (*)(DB_ENV *, db_pgno_t, void *, DBT *), int (*)(DB_ENV *, db_pgno_t, void *, DBT *))); +int __memp_stat_pp __P((DB_ENV *, DB_MPOOL_STAT **, DB_MPOOL_FSTAT ***, u_int32_t)); +int __memp_stat_print_pp __P((DB_ENV *, u_int32_t)); +int __memp_stat_print __P((DB_ENV *, u_int32_t)); +void __memp_stat_hash __P((REGINFO *, MPOOL *, u_int32_t *)); +int __memp_sync_pp __P((DB_ENV *, DB_LSN *)); +int __memp_sync __P((DB_ENV *, DB_LSN *)); +int __memp_fsync_pp __P((DB_MPOOLFILE *)); +int __memp_fsync __P((DB_MPOOLFILE *)); +int __mp_xxx_fh __P((DB_MPOOLFILE *, DB_FH **)); +int __memp_sync_int __P((DB_ENV *, DB_MPOOLFILE *, u_int32_t, db_sync_op, u_int32_t *)); +int __memp_mf_sync __P((DB_MPOOL *, MPOOLFILE *)); +int __memp_trickle_pp __P((DB_ENV *, int, int *)); + +#if defined(__cplusplus) +} +#endif +#endif /* !_mp_ext_h_ */ diff --git a/lib_dict/bdb/include/mutex.h b/lib_dict/bdb/include/mutex.h new file mode 100644 index 000000000..0d32d12f1 --- /dev/null +++ b/lib_dict/bdb/include/mutex.h @@ -0,0 +1,981 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996-2004 + * Sleepycat Software. All rights reserved. + * + * $Id: mutex.h,v 11.100 2004/10/05 14:41:12 mjc Exp $ + */ + +#ifndef _DB_MUTEX_H_ +#define _DB_MUTEX_H_ + +/* + * Some of the Berkeley DB ports require single-threading at various + * places in the code. In those cases, these #defines will be set. + */ +#define DB_BEGIN_SINGLE_THREAD +#define DB_END_SINGLE_THREAD + +/********************************************************************* + * POSIX.1 pthreads interface. + *********************************************************************/ +#ifdef HAVE_MUTEX_PTHREADS +#include + +#define MUTEX_FIELDS \ + pthread_mutex_t mutex; /* Mutex. */ \ + pthread_cond_t cond; /* Condition variable. */ +#endif + +/********************************************************************* + * Solaris lwp threads interface. + * + * !!! + * We use LWP mutexes on Solaris instead of UI or POSIX mutexes (both of + * which are available), for two reasons. First, the Solaris C library + * includes versions of the both UI and POSIX thread mutex interfaces, but + * they are broken in that they don't support inter-process locking, and + * there's no way to detect it, e.g., calls to configure the mutexes for + * inter-process locking succeed without error. So, we use LWP mutexes so + * that we don't fail in fairly undetectable ways because the application + * wasn't linked with the appropriate threads library. Second, there were + * bugs in SunOS 5.7 (Solaris 7) where if an application loaded the C library + * before loading the libthread/libpthread threads libraries (e.g., by using + * dlopen to load the DB library), the pwrite64 interface would be translated + * into a call to pwrite and DB would drop core. + *********************************************************************/ +#ifdef HAVE_MUTEX_SOLARIS_LWP +/* + * XXX + * Don't change to -- although lwp.h is listed in the + * Solaris manual page as the correct include to use, it causes the Solaris + * compiler on SunOS 2.6 to fail. + */ +#include + +#define MUTEX_FIELDS \ + lwp_mutex_t mutex; /* Mutex. */ \ + lwp_cond_t cond; /* Condition variable. */ +#endif + +/********************************************************************* + * Solaris/Unixware threads interface. + *********************************************************************/ +#ifdef HAVE_MUTEX_UI_THREADS +#include +#include + +#define MUTEX_FIELDS \ + mutex_t mutex; /* Mutex. */ \ + cond_t cond; /* Condition variable. */ +#endif + +/********************************************************************* + * AIX C library functions. + *********************************************************************/ +#ifdef HAVE_MUTEX_AIX_CHECK_LOCK +#include +typedef int tsl_t; + +#ifndef MUTEX_ALIGN +#define MUTEX_ALIGN sizeof(int) +#endif + +#ifdef LOAD_ACTUAL_MUTEX_CODE +#define MUTEX_INIT(x) 0 +#define MUTEX_SET(x) (!_check_lock(x, 0, 1)) +#define MUTEX_UNSET(x) _clear_lock(x, 0) +#endif +#endif + +/********************************************************************* + * Apple/Darwin library functions. + *********************************************************************/ +#ifdef HAVE_MUTEX_DARWIN_SPIN_LOCK_TRY +typedef u_int32_t tsl_t; + +#ifndef MUTEX_ALIGN +#define MUTEX_ALIGN sizeof(int) +#endif + +#ifdef LOAD_ACTUAL_MUTEX_CODE +extern int _spin_lock_try(tsl_t *); +extern void _spin_unlock(tsl_t *); +#define MUTEX_SET(tsl) _spin_lock_try(tsl) +#define MUTEX_UNSET(tsl) _spin_unlock(tsl) +#define MUTEX_INIT(tsl) (MUTEX_UNSET(tsl), 0) +#endif +#endif + +/********************************************************************* + * General C library functions (msemaphore). + * + * !!! + * Check for HPPA as a special case, because it requires unusual alignment, + * and doesn't support semaphores in malloc(3) or shmget(2) memory. + * + * !!! + * Do not remove the MSEM_IF_NOWAIT flag. The problem is that if a single + * process makes two msem_lock() calls in a row, the second one returns an + * error. We depend on the fact that we can lock against ourselves in the + * locking subsystem, where we set up a mutex so that we can block ourselves. + * Tested on OSF1 v4.0. + *********************************************************************/ +#ifdef HAVE_MUTEX_HPPA_MSEM_INIT +#define MUTEX_NO_MALLOC_LOCKS +#define MUTEX_NO_SHMGET_LOCKS + +#ifndef MUTEX_ALIGN +#define MUTEX_ALIGN 16 +#define HPUX_MUTEX_PAD 8 +#endif +#endif + +#if defined(HAVE_MUTEX_MSEM_INIT) || defined(HAVE_MUTEX_HPPA_MSEM_INIT) +#include +typedef msemaphore tsl_t; + +#ifndef MUTEX_ALIGN +#define MUTEX_ALIGN sizeof(int) +#endif + +#ifdef LOAD_ACTUAL_MUTEX_CODE +#define MUTEX_INIT(x) (msem_init(x, MSEM_UNLOCKED) <= (msemaphore *)0) +#define MUTEX_SET(x) (!msem_lock(x, MSEM_IF_NOWAIT)) +#define MUTEX_UNSET(x) msem_unlock(x, 0) +#endif +#endif + +/********************************************************************* + * Plan 9 library functions. + *********************************************************************/ +#ifdef HAVE_MUTEX_PLAN9 +typedef Lock tsl_t; + +#ifndef MUTEX_ALIGN +#define MUTEX_ALIGN sizeof(int) +#endif + +#define MUTEX_INIT(x) (memset(x, 0, sizeof(Lock)), 0) +#define MUTEX_SET(x) canlock(x) +#define MUTEX_UNSET(x) unlock(x) +#endif + +/********************************************************************* + * Reliant UNIX C library functions. + *********************************************************************/ +#ifdef HAVE_MUTEX_RELIANTUNIX_INITSPIN +#include +typedef spinlock_t tsl_t; + +#ifdef LOAD_ACTUAL_MUTEX_CODE +#define MUTEX_INIT(x) (initspin(x, 1), 0) +#define MUTEX_SET(x) (cspinlock(x) == 0) +#define MUTEX_UNSET(x) spinunlock(x) +#endif +#endif + +/********************************************************************* + * General C library functions (POSIX 1003.1 sema_XXX). + * + * !!! + * Never selected by autoconfig in this release (semaphore calls are known + * to not work in Solaris 5.5). + *********************************************************************/ +#ifdef HAVE_MUTEX_SEMA_INIT +#include +typedef sema_t tsl_t; + +#ifndef MUTEX_ALIGN +#define MUTEX_ALIGN sizeof(int) +#endif + +#ifdef LOAD_ACTUAL_MUTEX_CODE +#define MUTEX_DESTROY(x) sema_destroy(x) +#define MUTEX_INIT(x) (sema_init(x, 1, USYNC_PROCESS, NULL) != 0) +#define MUTEX_SET(x) (sema_wait(x) == 0) +#define MUTEX_UNSET(x) sema_post(x) +#endif +#endif + +/********************************************************************* + * SGI C library functions. + *********************************************************************/ +#ifdef HAVE_MUTEX_SGI_INIT_LOCK +#include +typedef abilock_t tsl_t; + +#ifndef MUTEX_ALIGN +#define MUTEX_ALIGN sizeof(int) +#endif + +#ifdef LOAD_ACTUAL_MUTEX_CODE +#define MUTEX_INIT(x) (init_lock(x) != 0) +#define MUTEX_SET(x) (!acquire_lock(x)) +#define MUTEX_UNSET(x) release_lock(x) +#endif +#endif + +/********************************************************************* + * Solaris C library functions. + * + * !!! + * These are undocumented functions, but they're the only ones that work + * correctly as far as we know. + *********************************************************************/ +#ifdef HAVE_MUTEX_SOLARIS_LOCK_TRY +#include +typedef lock_t tsl_t; + +#ifndef MUTEX_ALIGN +#define MUTEX_ALIGN sizeof(int) +#endif + +#ifdef LOAD_ACTUAL_MUTEX_CODE +#define MUTEX_INIT(x) 0 +#define MUTEX_SET(x) _lock_try(x) +#define MUTEX_UNSET(x) _lock_clear(x) +#endif +#endif + +/********************************************************************* + * VMS. + *********************************************************************/ +#ifdef HAVE_MUTEX_VMS +#include ; +#include +typedef volatile unsigned char tsl_t; + +#ifndef MUTEX_ALIGN +#define MUTEX_ALIGN sizeof(unsigned int) +#endif + +#ifdef LOAD_ACTUAL_MUTEX_CODE +#ifdef __ALPHA +#define MUTEX_SET(tsl) (!__TESTBITSSI(tsl, 0)) +#else /* __VAX */ +#define MUTEX_SET(tsl) (!(int)_BBSSI(0, tsl)) +#endif +#define MUTEX_UNSET(tsl) (*(tsl) = 0) +#define MUTEX_INIT(tsl) MUTEX_UNSET(tsl) +#endif +#endif + +/********************************************************************* + * VxWorks + * Use basic binary semaphores in VxWorks, as we currently do not need + * any special features. We do need the ability to single-thread the + * entire system, however, because VxWorks doesn't support the open(2) + * flag O_EXCL, the mechanism we normally use to single thread access + * when we're first looking for a DB environment. + *********************************************************************/ +#ifdef HAVE_MUTEX_VXWORKS +#include "taskLib.h" +typedef SEM_ID tsl_t; + +#ifndef MUTEX_ALIGN +#define MUTEX_ALIGN sizeof(unsigned int) +#endif + +#ifdef LOAD_ACTUAL_MUTEX_CODE +#define MUTEX_SET(tsl) (semTake((*tsl), WAIT_FOREVER) == OK) +#define MUTEX_UNSET(tsl) (semGive((*tsl))) +#define MUTEX_INIT(tsl) \ + ((*(tsl) = semBCreate(SEM_Q_FIFO, SEM_FULL)) == NULL) +#define MUTEX_DESTROY(tsl) semDelete(*tsl) +#endif + +/* + * Use the taskLock() mutex to eliminate a race where two tasks are + * trying to initialize the global lock at the same time. + */ +#undef DB_BEGIN_SINGLE_THREAD +#define DB_BEGIN_SINGLE_THREAD do { \ + if (DB_GLOBAL(db_global_init)) \ + (void)semTake(DB_GLOBAL(db_global_lock), WAIT_FOREVER); \ + else { \ + taskLock(); \ + if (DB_GLOBAL(db_global_init)) { \ + taskUnlock(); \ + (void)semTake(DB_GLOBAL(db_global_lock), \ + WAIT_FOREVER); \ + continue; \ + } \ + DB_GLOBAL(db_global_lock) = \ + semBCreate(SEM_Q_FIFO, SEM_EMPTY); \ + if (DB_GLOBAL(db_global_lock) != NULL) \ + DB_GLOBAL(db_global_init) = 1; \ + taskUnlock(); \ + } \ +} while (DB_GLOBAL(db_global_init) == 0) +#undef DB_END_SINGLE_THREAD +#define DB_END_SINGLE_THREAD (void)semGive(DB_GLOBAL(db_global_lock)) +#endif + +/********************************************************************* + * Win16 + * + * Win16 spinlocks are simple because we cannot possibly be preempted. + * + * !!! + * We should simplify this by always returning a no-need-to-lock lock + * when we initialize the mutex. + *********************************************************************/ +#ifdef HAVE_MUTEX_WIN16 +typedef unsigned int tsl_t; + +#ifndef MUTEX_ALIGN +#define MUTEX_ALIGN sizeof(unsigned int) +#endif + +#ifdef LOAD_ACTUAL_MUTEX_CODE +#define MUTEX_INIT(x) 0 +#define MUTEX_SET(tsl) (*(tsl) = 1) +#define MUTEX_UNSET(tsl) (*(tsl) = 0) +#endif +#endif + +/********************************************************************* + * Win32 + *********************************************************************/ +#if defined(HAVE_MUTEX_WIN32) || defined(HAVE_MUTEX_WIN32_GCC) +#define MUTEX_FIELDS \ + LONG volatile tas; \ + LONG nwaiters; \ + u_int32_t id; /* ID used for creating events */ \ + +#if defined(LOAD_ACTUAL_MUTEX_CODE) +#define MUTEX_SET(tsl) (InterlockedExchange((PLONG)(tsl), 1) == 0) +#define MUTEX_UNSET(tsl) (InterlockedExchange((PLONG)(tsl), 0)) +#define MUTEX_INIT(tsl) MUTEX_UNSET(tsl) + +/* + * From Intel's performance tuning documentation (and see SR #6975): + * ftp://download.intel.com/design/perftool/cbts/appnotes/sse2/w_spinlock.pdf + * + * "For this reason, it is highly recommended that you insert the PAUSE + * instruction into all spin-wait code immediately. Using the PAUSE + * instruction does not affect the correctness of programs on existing + * platforms, and it improves performance on Pentium 4 processor platforms." + */ +#ifdef HAVE_MUTEX_WIN32 +#ifndef _WIN64 +#define MUTEX_PAUSE {__asm{_emit 0xf3}; __asm{_emit 0x90}} +#endif +#endif +#ifdef HAVE_MUTEX_WIN32_GCC +#define MUTEX_PAUSE asm volatile ("rep; nop" : : ); +#endif +#endif +#endif + +/********************************************************************* + * 68K/gcc assembly. + *********************************************************************/ +#ifdef HAVE_MUTEX_68K_GCC_ASSEMBLY +typedef unsigned char tsl_t; + +#ifdef LOAD_ACTUAL_MUTEX_CODE +#define MUTEX_SET_TEST 1 /* gcc/68K: 0 is clear, 1 is set. */ + +#define MUTEX_SET(tsl) ({ \ + register tsl_t *__l = (tsl); \ + int __r; \ + asm volatile("tas %1; \n \ + seq %0" \ + : "=dm" (__r), "=m" (*__l) \ + : "1" (*__l) \ + ); \ + __r & 1; \ +}) + +#define MUTEX_UNSET(tsl) (*(tsl) = 0) +#define MUTEX_INIT(tsl) MUTEX_UNSET(tsl) +#endif +#endif + +/********************************************************************* + * ALPHA/gcc assembly. + *********************************************************************/ +#ifdef HAVE_MUTEX_ALPHA_GCC_ASSEMBLY +typedef u_int32_t tsl_t; + +#ifndef MUTEX_ALIGN +#define MUTEX_ALIGN 4 +#endif + +#ifdef LOAD_ACTUAL_MUTEX_CODE +/* + * For gcc/alpha. Should return 0 if could not acquire the lock, 1 if + * lock was acquired properly. + */ +static inline int +MUTEX_SET(tsl_t *tsl) { + register tsl_t *__l = tsl; + register tsl_t __r; + asm volatile( + "1: ldl_l %0,%2\n" + " blbs %0,2f\n" + " or $31,1,%0\n" + " stl_c %0,%1\n" + " beq %0,3f\n" + " mb\n" + " br 3f\n" + "2: xor %0,%0\n" + "3:" + : "=&r"(__r), "=m"(*__l) : "1"(*__l) : "memory"); + return __r; +} + +/* + * Unset mutex. Judging by Alpha Architecture Handbook, the mb instruction + * might be necessary before unlocking + */ +static inline int +MUTEX_UNSET(tsl_t *tsl) { + asm volatile(" mb\n"); + return *tsl = 0; +} + +#define MUTEX_INIT(tsl) MUTEX_UNSET(tsl) +#endif +#endif + +/********************************************************************* + * Tru64/cc assembly. + *********************************************************************/ +#ifdef HAVE_MUTEX_TRU64_CC_ASSEMBLY +typedef volatile u_int32_t tsl_t; + +#ifndef MUTEX_ALIGN +#define MUTEX_ALIGN 4 +#endif + +#ifdef LOAD_ACTUAL_MUTEX_CODE +#include +#define MUTEX_SET(tsl) (__LOCK_LONG_RETRY((tsl), 1) != 0) +#define MUTEX_UNSET(tsl) (__UNLOCK_LONG(tsl)) + +#define MUTEX_INIT(tsl) (MUTEX_UNSET(tsl), 0) +#endif +#endif + +/********************************************************************* + * ARM/gcc assembly. + *********************************************************************/ +#ifdef HAVE_MUTEX_ARM_GCC_ASSEMBLY +typedef unsigned char tsl_t; + +#ifdef LOAD_ACTUAL_MUTEX_CODE +#define MUTEX_SET_TEST 1 /* gcc/arm: 0 is clear, 1 is set. */ + +#define MUTEX_SET(tsl) ({ \ + int __r; \ + asm volatile( \ + "swpb %0, %1, [%2]\n\t" \ + "eor %0, %0, #1\n\t" \ + : "=&r" (__r) \ + : "r" (1), "r" (tsl) \ + ); \ + __r & 1; \ +}) + +#define MUTEX_UNSET(tsl) (*(volatile tsl_t *)(tsl) = 0) +#define MUTEX_INIT(tsl) MUTEX_UNSET(tsl) +#endif +#endif + +/********************************************************************* + * HPPA/gcc assembly. + *********************************************************************/ +#ifdef HAVE_MUTEX_HPPA_GCC_ASSEMBLY +typedef u_int32_t tsl_t; + +#ifndef MUTEX_ALIGN +#define MUTEX_ALIGN 16 +#define HPUX_MUTEX_PAD 8 +#endif + +#ifdef LOAD_ACTUAL_MUTEX_CODE +/* + * The PA-RISC has a "load and clear" instead of a "test and set" instruction. + * The 32-bit word used by that instruction must be 16-byte aligned. We could + * use the "aligned" attribute in GCC but that doesn't work for stack variables. + */ +#define MUTEX_SET(tsl) ({ \ + register tsl_t *__l = (tsl); \ + int __r; \ + asm volatile("ldcws 0(%1),%0" : "=r" (__r) : "r" (__l)); \ + __r & 1; \ +}) + +#define MUTEX_UNSET(tsl) (*(tsl) = -1) +#define MUTEX_INIT(tsl) (MUTEX_UNSET(tsl), 0) +#endif +#endif + +/********************************************************************* + * IA64/gcc assembly. + *********************************************************************/ +#ifdef HAVE_MUTEX_IA64_GCC_ASSEMBLY +typedef unsigned char tsl_t; + +#ifdef LOAD_ACTUAL_MUTEX_CODE +#define MUTEX_SET_TEST 1 /* gcc/ia64: 0 is clear, 1 is set. */ + +#define MUTEX_SET(tsl) ({ \ + register tsl_t *__l = (tsl); \ + long __r; \ + asm volatile("xchg1 %0=%1,%3" : "=r"(__r), "=m"(*__l) : "1"(*__l), "r"(1));\ + __r ^ 1; \ +}) + +/* + * Store through a "volatile" pointer so we get a store with "release" + * semantics. + */ +#define MUTEX_UNSET(tsl) (*(volatile unsigned char *)(tsl) = 0) +#define MUTEX_INIT(tsl) MUTEX_UNSET(tsl) +#endif +#endif + +/********************************************************************* + * PowerPC/gcc assembly. + *********************************************************************/ +#if defined(HAVE_MUTEX_PPC_GCC_ASSEMBLY) +typedef u_int32_t tsl_t; + +#ifdef LOAD_ACTUAL_MUTEX_CODE +/* + * The PowerPC does a sort of pseudo-atomic locking. You set up a + * 'reservation' on a chunk of memory containing a mutex by loading the + * mutex value with LWARX. If the mutex has an 'unlocked' (arbitrary) + * value, you then try storing into it with STWCX. If no other process or + * thread broke your 'reservation' by modifying the memory containing the + * mutex, then the STCWX succeeds; otherwise it fails and you try to get + * a reservation again. + * + * While mutexes are explicitly 4 bytes, a 'reservation' applies to an + * entire cache line, normally 32 bytes, aligned naturally. If the mutex + * lives near data that gets changed a lot, there's a chance that you'll + * see more broken reservations than you might otherwise. The only + * situation in which this might be a problem is if one processor is + * beating on a variable in the same cache block as the mutex while another + * processor tries to acquire the mutex. That's bad news regardless + * because of the way it bashes caches, but if you can't guarantee that a + * mutex will reside in a relatively quiescent cache line, you might + * consider padding the mutex to force it to live in a cache line by + * itself. No, you aren't guaranteed that cache lines are 32 bytes. Some + * embedded processors use 16-byte cache lines, while some 64-bit + * processors use 128-bit cache lines. But assuming a 32-byte cache line + * won't get you into trouble for now. + * + * If mutex locking is a bottleneck, then you can speed it up by adding a + * regular LWZ load before the LWARX load, so that you can test for the + * common case of a locked mutex without wasting cycles making a reservation. + * + * 'set' mutexes have the value 1, like on Intel; the returned value from + * MUTEX_SET() is 1 if the mutex previously had its low bit clear, 0 otherwise. + */ +#define MUTEX_SET_TEST 1 /* gcc/ppc: 0 is clear, 1 is set. */ + +static inline int +MUTEX_SET(int *tsl) { + int __r; + int __tmp = (int)tsl; + asm volatile ( +"0: \n\t" +" lwarx %0,0,%2 \n\t" +" cmpwi %0,0 \n\t" +" bne- 1f \n\t" +" stwcx. %2,0,%2 \n\t" +" isync \n\t" +" beq+ 2f \n\t" +" b 0b \n\t" +"1: \n\t" +" li %1, 0 \n\t" +"2: \n\t" + : "=&r" (__r), "=r" (tsl) + : "r" (__tmp) + : "cr0", "memory"); + return (int)tsl; +} + +static inline int +MUTEX_UNSET(tsl_t *tsl) { + asm volatile("sync" : : : "memory"); + return *tsl = 0; +} +#define MUTEX_INIT(tsl) MUTEX_UNSET(tsl) +#endif +#endif + +/********************************************************************* + * OS/390 C + *********************************************************************/ +#ifdef HAVE_MUTEX_S390_CC_ASSEMBLY +typedef int tsl_t; + +#ifndef MUTEX_ALIGN +#define MUTEX_ALIGN sizeof(int) +#endif + +#ifdef LOAD_ACTUAL_MUTEX_CODE +/* + * cs() is declared in but is built in to the compiler. + * Must use LANGLVL(EXTENDED) to get its declaration. + */ +#define MUTEX_SET(tsl) (!cs(&zero, (tsl), 1)) +#define MUTEX_UNSET(tsl) (*(tsl) = 0) +#define MUTEX_INIT(tsl) MUTEX_UNSET(tsl) +#endif +#endif + +/********************************************************************* + * S/390 32-bit assembly. + *********************************************************************/ +#ifdef HAVE_MUTEX_S390_GCC_ASSEMBLY +typedef int tsl_t; + +#ifdef LOAD_ACTUAL_MUTEX_CODE +#define MUTEX_SET_TEST 1 /* gcc/S390: 0 is clear, 1 is set. */ + +static inline int +MUTEX_SET(tsl_t *tsl) { \ + register tsl_t *__l = (tsl); \ + int __r; \ + asm volatile( \ + " la 1,%1\n" \ + " lhi 0,1\n" \ + " l %0,%1\n" \ + "0: cs %0,0,0(1)\n" \ + " jl 0b" \ + : "=&d" (__r), "+m" (*__l) \ + : : "0", "1", "cc"); \ + return !__r; \ +} + +#define MUTEX_UNSET(tsl) (*(tsl) = 0) +#define MUTEX_INIT(tsl) MUTEX_UNSET(tsl) +#endif +#endif + +/********************************************************************* + * SCO/cc assembly. + *********************************************************************/ +#ifdef HAVE_MUTEX_SCO_X86_CC_ASSEMBLY +typedef unsigned char tsl_t; + +#ifdef LOAD_ACTUAL_MUTEX_CODE +/* + * UnixWare has threads in libthread, but OpenServer doesn't (yet). + */ +#define MUTEX_SET_TEST 1 /* cc/x86: 0 is clear, 1 is set. */ + +#if defined(__USLC__) +asm int +_tsl_set(void *tsl) +{ +%mem tsl + movl tsl, %ecx + movl $1, %eax + lock + xchgb (%ecx),%al + xorl $1,%eax +} +#endif + +#define MUTEX_SET(tsl) _tsl_set(tsl) +#define MUTEX_UNSET(tsl) (*(tsl) = 0) +#define MUTEX_INIT(tsl) MUTEX_UNSET(tsl) +#endif +#endif + +/********************************************************************* + * Sparc/gcc assembly. + *********************************************************************/ +#ifdef HAVE_MUTEX_SPARC_GCC_ASSEMBLY +typedef unsigned char tsl_t; + +#ifdef LOAD_ACTUAL_MUTEX_CODE +/* + * + * The ldstub instruction takes the location specified by its first argument + * (a register containing a memory address) and loads its contents into its + * second argument (a register) and atomically sets the contents the location + * specified by its first argument to a byte of 1s. (The value in the second + * argument is never read, but only overwritten.) + * + * The stbar is needed for v8, and is implemented as membar #sync on v9, + * so is functional there as well. For v7, stbar may generate an illegal + * instruction and we have no way to tell what we're running on. Some + * operating systems notice and skip this instruction in the fault handler. + */ +#define MUTEX_SET_TEST 1 /* gcc/sparc: 0 is clear, 1 is set. */ + +#define MUTEX_SET(tsl) ({ \ + register tsl_t *__l = (tsl); \ + register tsl_t __r; \ + __asm__ volatile \ + ("ldstub [%1],%0; stbar" \ + : "=r"( __r) : "r" (__l)); \ + !__r; \ +}) + +#define MUTEX_UNSET(tsl) (*(tsl) = 0) +#define MUTEX_INIT(tsl) MUTEX_UNSET(tsl) +#endif +#endif + +/********************************************************************* + * UTS/cc assembly. + *********************************************************************/ +#ifdef HAVE_MUTEX_UTS_CC_ASSEMBLY +typedef int tsl_t; + +#ifndef MUTEX_ALIGN +#define MUTEX_ALIGN sizeof(int) +#endif + +#ifdef LOAD_ACTUAL_MUTEX_CODE +#define MUTEX_INIT(x) 0 +#define MUTEX_SET(x) (!uts_lock(x, 1)) +#define MUTEX_UNSET(x) (*(x) = 0) +#endif +#endif + +/********************************************************************* + * x86/gcc assembly. + *********************************************************************/ +#ifdef HAVE_MUTEX_X86_GCC_ASSEMBLY +typedef unsigned char tsl_t; + +#ifdef LOAD_ACTUAL_MUTEX_CODE +#define MUTEX_SET_TEST 1 /* gcc/x86: 0 is clear, 1 is set. */ + +#define MUTEX_SET(tsl) ({ \ + register tsl_t *__l = (tsl); \ + int __r; \ + asm volatile("movl $1,%%eax; lock; xchgb %1,%%al; xorl $1,%%eax"\ + : "=&a" (__r), "=m" (*__l) \ + : "1" (*__l) \ + ); \ + __r & 1; \ +}) + +#define MUTEX_UNSET(tsl) (*(tsl) = 0) +#define MUTEX_INIT(tsl) MUTEX_UNSET(tsl) + +/* + * From Intel's performance tuning documentation (and see SR #6975): + * ftp://download.intel.com/design/perftool/cbts/appnotes/sse2/w_spinlock.pdf + * + * "For this reason, it is highly recommended that you insert the PAUSE + * instruction into all spin-wait code immediately. Using the PAUSE + * instruction does not affect the correctness of programs on existing + * platforms, and it improves performance on Pentium 4 processor platforms." + */ +#define MUTEX_PAUSE asm volatile ("rep; nop" : : ); +#endif +#endif + +/* + * Mutex alignment defaults to one byte. + * + * !!! + * Various systems require different alignments for mutexes (the worst we've + * seen so far is 16-bytes on some HP architectures). Malloc(3) is assumed + * to return reasonable alignment, all other mutex users must ensure proper + * alignment locally. + */ +#ifndef MUTEX_ALIGN +#define MUTEX_ALIGN 1 +#endif + +/* + * Mutex destruction defaults to a no-op. + */ +#ifdef LOAD_ACTUAL_MUTEX_CODE +#ifndef MUTEX_DESTROY +#define MUTEX_DESTROY(x) +#endif +#endif + +/* + * !!! + * The flag arguments for __db_mutex_setup (and the underlying initialization + * function for the mutex type, for example, __db_tas_mutex_init), and flags + * stored in the DB_MUTEX structure are combined, and may not overlap. Flags + * to __db_mutex_setup: + * + * MUTEX_ALLOC: + * Use when the mutex to initialize needs to be allocated. The 'ptr' + * arg to __db_mutex_setup should be a DB_MUTEX ** whenever you use + * this flag. If this flag is not set, the 'ptr' arg is a DB_MUTEX *. + * MUTEX_NO_RECORD: + * Explicitly do not record the mutex in the region. Otherwise the + * mutex will be recorded by default. If you set this you need to + * understand why you don't need it recorded. The *only* ones not + * recorded are those that are part of region structures that only + * get destroyed when the regions are destroyed. + * MUTEX_NO_RLOCK: + * Explicitly do not lock the given region otherwise the region will + * be locked by default. + * MUTEX_SELF_BLOCK: + * Set if self blocking mutex. + * MUTEX_THREAD: + * Set if mutex is a thread-only mutex. + */ +#define MUTEX_ALLOC 0x0001 /* Allocate and init a mutex */ +#define MUTEX_IGNORE 0x0002 /* Ignore, no lock required. */ +#define MUTEX_INITED 0x0004 /* Mutex is successfully initialized */ +#define MUTEX_LOGICAL_LOCK 0x0008 /* Mutex backs database lock. */ +#define MUTEX_MPOOL 0x0010 /* Allocated from mpool. */ +#define MUTEX_NO_RECORD 0x0020 /* Do not record lock */ +#define MUTEX_NO_RLOCK 0x0040 /* Do not acquire region lock */ +#define MUTEX_SELF_BLOCK 0x0080 /* Must block self. */ +#define MUTEX_THREAD 0x0100 /* Thread-only mutex. */ + +/* Mutex. */ +struct __mutex_t { +#ifdef HAVE_MUTEX_THREADS +#ifdef MUTEX_FIELDS + MUTEX_FIELDS +#else + tsl_t tas; /* Test and set. */ +#endif + u_int32_t locked; /* !0 if locked. */ +#else + u_int32_t off; /* Byte offset to lock. */ + u_int32_t pid; /* Lock holder: 0 or process pid. */ +#endif + u_int32_t mutex_set_wait; /* Granted after wait. */ + u_int32_t mutex_set_nowait; /* Granted without waiting. */ + u_int32_t mutex_set_spin; /* Granted without spinning. */ + u_int32_t mutex_set_spins; /* Total number of spins. */ +#ifdef HAVE_MUTEX_SYSTEM_RESOURCES + roff_t reg_off; /* Shared lock info offset. */ +#endif + /* + * Flags should be an unsigned integer even if it's not required by + * the possible flags values, getting a single byte on some machines + * is expensive, and the mutex structure is a MP hot spot. + */ + u_int32_t flags; /* MUTEX_XXX */ +}; + +/* Macro to clear mutex statistics. */ +#define MUTEX_CLEAR(mp) { \ + (mp)->mutex_set_wait = (mp)->mutex_set_nowait = 0; \ +} + +/* Redirect calls to the correct functions. */ +#ifdef HAVE_MUTEX_THREADS +#if defined(HAVE_MUTEX_PTHREADS) || \ + defined(HAVE_MUTEX_SOLARIS_LWP) || \ + defined(HAVE_MUTEX_UI_THREADS) +#define __db_mutex_init_int(a, b, c, d) __db_pthread_mutex_init(a, b, d) +#define __db_mutex_lock(a, b) __db_pthread_mutex_lock(a, b) +#define __db_mutex_unlock(a, b) __db_pthread_mutex_unlock(a, b) +#define __db_mutex_destroy(a) __db_pthread_mutex_destroy(a) +#else +#if defined(HAVE_MUTEX_WIN32) || defined(HAVE_MUTEX_WIN32_GCC) +#define __db_mutex_init_int(a, b, c, d) __db_win32_mutex_init(a, b, d) +#define __db_mutex_lock(a, b) __db_win32_mutex_lock(a, b) +#define __db_mutex_unlock(a, b) __db_win32_mutex_unlock(a, b) +#define __db_mutex_destroy(a) __db_win32_mutex_destroy(a) +#else +#define __db_mutex_init_int(a, b, c, d) __db_tas_mutex_init(a, b, d) +#define __db_mutex_lock(a, b) __db_tas_mutex_lock(a, b) +#define __db_mutex_unlock(a, b) __db_tas_mutex_unlock(a, b) +#define __db_mutex_destroy(a) __db_tas_mutex_destroy(a) +#endif +#endif +#else +#define __db_mutex_init_int(a, b, c, d) __db_fcntl_mutex_init(a, b, c) +#define __db_mutex_lock(a, b) __db_fcntl_mutex_lock(a, b) +#define __db_mutex_unlock(a, b) __db_fcntl_mutex_unlock(a, b) +#define __db_mutex_destroy(a) __db_fcntl_mutex_destroy(a) +#endif + +/* Redirect system resource calls to correct functions */ +#ifdef HAVE_MUTEX_SYSTEM_RESOURCES +#define __db_maintinit(a, b, c) __db_shreg_maintinit(a, b, c) +#define __db_shlocks_clear(a, b, c) __db_shreg_locks_clear(a, b, c) +#define __db_shlocks_destroy(a, b) __db_shreg_locks_destroy(a, b) +#define __db_mutex_init(a, b, c, d, e, f) \ + __db_shreg_mutex_init(a, b, c, d, e, f) +#else +#define __db_maintinit(a, b, c) +#define __db_shlocks_clear(a, b, c) +#define __db_shlocks_destroy(a, b) +#define __db_mutex_init(a, b, c, d, e, f) __db_mutex_init_int(a, b, c, d) +#endif + +/* + * Lock/unlock a mutex. If the mutex was marked as uninteresting, the thread + * of control can proceed without it. + * + * If the lock is for threads-only, then it was optionally not allocated and + * file handles aren't necessary, as threaded applications aren't supported by + * fcntl(2) locking. + */ +#ifdef DIAGNOSTIC + /* + * XXX + * We want to switch threads as often as possible. Yield every time + * we get a mutex to ensure contention. + */ +#define MUTEX_LOCK(dbenv, mp) \ + if (!F_ISSET((mp), MUTEX_IGNORE)) \ + DB_ASSERT(__db_mutex_lock(dbenv, mp) == 0); \ + if (F_ISSET(dbenv, DB_ENV_YIELDCPU)) \ + __os_yield(NULL, 1); +#else +#define MUTEX_LOCK(dbenv, mp) \ + if (!F_ISSET((mp), MUTEX_IGNORE)) \ + (void)__db_mutex_lock(dbenv, mp); +#endif +#define MUTEX_UNLOCK(dbenv, mp) \ + if (!F_ISSET((mp), MUTEX_IGNORE)) \ + (void)__db_mutex_unlock(dbenv, mp); +#define MUTEX_THREAD_LOCK(dbenv, mp) \ + if (mp != NULL) \ + MUTEX_LOCK(dbenv, mp) +#define MUTEX_THREAD_UNLOCK(dbenv, mp) \ + if (mp != NULL) \ + MUTEX_UNLOCK(dbenv, mp) + +/* + * We use a single file descriptor for fcntl(2) locking, and (generally) the + * object's offset in a shared region as the byte that we're locking. So, + * there's a (remote) possibility that two objects might have the same offsets + * such that the locks could conflict, resulting in deadlock. To avoid this + * possibility, we offset the region offset by a small integer value, using a + * different offset for each subsystem's locks. Since all region objects are + * suitably aligned, the offset guarantees that we don't collide with another + * region's objects. + */ +#define DB_FCNTL_OFF_GEN 0 /* Everything else. */ +#define DB_FCNTL_OFF_LOCK 1 /* Lock subsystem offset. */ +#define DB_FCNTL_OFF_MPOOL 2 /* Mpool subsystem offset. */ + +#ifdef HAVE_MUTEX_SYSTEM_RESOURCES +/* + * When the underlying mutexes require library (most likely heap) or system + * resources, we have to clean up when we discard mutexes (for the library + * resources) and both when discarding mutexes and after application failure + * (for the mutexes requiring system resources). This violates the rule that + * we never look at a shared region after application failure, but we've no + * other choice. In those cases, the #define HAVE_MUTEX_SYSTEM_RESOURCES is + * set. + * + * To support mutex release after application failure, allocate thread-handle + * mutexes in shared memory instead of in the heap. The number of slots we + * allocate for this purpose isn't configurable, but this tends to be an issue + * only on embedded systems where we don't expect large server applications. + */ +#define DB_MAX_HANDLES 100 /* Mutex slots for handles. */ +#endif +#endif /* !_DB_MUTEX_H_ */ diff --git a/lib_dict/bdb/include/mutex_ext.h b/lib_dict/bdb/include/mutex_ext.h new file mode 100644 index 000000000..a40f04d55 --- /dev/null +++ b/lib_dict/bdb/include/mutex_ext.h @@ -0,0 +1,35 @@ +/* DO NOT EDIT: automatically built by dist/s_include. */ +#ifndef _mutex_ext_h_ +#define _mutex_ext_h_ + +#if defined(__cplusplus) +extern "C" { +#endif + +int __db_fcntl_mutex_init __P((DB_ENV *, DB_MUTEX *, u_int32_t)); +int __db_fcntl_mutex_lock __P((DB_ENV *, DB_MUTEX *)); +int __db_fcntl_mutex_unlock __P((DB_ENV *, DB_MUTEX *)); +int __db_fcntl_mutex_destroy __P((DB_MUTEX *)); +int __db_pthread_mutex_init __P((DB_ENV *, DB_MUTEX *, u_int32_t)); +int __db_pthread_mutex_lock __P((DB_ENV *, DB_MUTEX *)); +int __db_pthread_mutex_unlock __P((DB_ENV *, DB_MUTEX *)); +int __db_pthread_mutex_destroy __P((DB_MUTEX *)); +int __db_tas_mutex_init __P((DB_ENV *, DB_MUTEX *, u_int32_t)); +int __db_tas_mutex_lock __P((DB_ENV *, DB_MUTEX *)); +int __db_tas_mutex_unlock __P((DB_ENV *, DB_MUTEX *)); +int __db_tas_mutex_destroy __P((DB_MUTEX *)); +int __db_win32_mutex_init __P((DB_ENV *, DB_MUTEX *, u_int32_t)); +int __db_win32_mutex_lock __P((DB_ENV *, DB_MUTEX *)); +int __db_win32_mutex_unlock __P((DB_ENV *, DB_MUTEX *)); +int __db_win32_mutex_destroy __P((DB_MUTEX *)); +int __db_mutex_setup __P((DB_ENV *, REGINFO *, void *, u_int32_t)); +void __db_mutex_free __P((DB_ENV *, REGINFO *, DB_MUTEX *)); +void __db_shreg_locks_clear __P((DB_MUTEX *, REGINFO *, REGMAINT *)); +void __db_shreg_locks_destroy __P((REGINFO *, REGMAINT *)); +int __db_shreg_mutex_init __P((DB_ENV *, DB_MUTEX *, u_int32_t, u_int32_t, REGINFO *, REGMAINT *)); +void __db_shreg_maintinit __P((REGINFO *, void *addr, size_t)); + +#if defined(__cplusplus) +} +#endif +#endif /* !_mutex_ext_h_ */ diff --git a/lib_dict/bdb/include/os.h b/lib_dict/bdb/include/os.h new file mode 100644 index 000000000..24685a4a7 --- /dev/null +++ b/lib_dict/bdb/include/os.h @@ -0,0 +1,95 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997-2004 + * Sleepycat Software. All rights reserved. + * + * $Id: os.h,v 11.25 2004/09/22 03:40:20 bostic Exp $ + */ + +#ifndef _DB_OS_H_ +#define _DB_OS_H_ + +#if defined(__cplusplus) +extern "C" { +#endif + +/* Number of times to retry system calls that return EINTR or EBUSY. */ +#define DB_RETRY 100 + +#define RETRY_CHK(op, ret) do { \ + int __retries = DB_RETRY; \ + do { \ + (ret) = (op); \ + } while ((ret) != 0 && (((ret) = __os_get_errno()) == EAGAIN || \ + (ret) == EBUSY || (ret) == EINTR) && --__retries > 0); \ +} while (0) + +/* + * Flags understood by __os_open. + */ +#define DB_OSO_CREATE 0x0001 /* POSIX: O_CREAT */ +#define DB_OSO_DIRECT 0x0002 /* Don't buffer the file in the OS. */ +#define DB_OSO_DSYNC 0x0004 /* POSIX: O_DSYNC. */ +#define DB_OSO_EXCL 0x0008 /* POSIX: O_EXCL */ +#define DB_OSO_LOG 0x0010 /* Opening a log file. */ +#define DB_OSO_RDONLY 0x0020 /* POSIX: O_RDONLY */ +#define DB_OSO_REGION 0x0040 /* Opening a region file. */ +#define DB_OSO_SEQ 0x0080 /* Expected sequential access. */ +#define DB_OSO_TEMP 0x0100 /* Remove after last close. */ +#define DB_OSO_TRUNC 0x0200 /* POSIX: O_TRUNC */ + +/* + * Seek options understood by __os_seek. + */ +typedef enum { + DB_OS_SEEK_CUR, /* POSIX: SEEK_CUR */ + DB_OS_SEEK_END, /* POSIX: SEEK_END */ + DB_OS_SEEK_SET /* POSIX: SEEK_SET */ +} DB_OS_SEEK; + +/* + * We group certain seek/write calls into a single function so that we + * can use pread(2)/pwrite(2) where they're available. + */ +#define DB_IO_READ 1 +#define DB_IO_WRITE 2 + +/* DB filehandle. */ +struct __fh_t { + /* + * The file-handle mutex is only used to protect the handle/fd + * across seek and read/write pairs, it does not protect the + * the reference count, or any other fields in the structure. + */ + DB_MUTEX *mutexp; /* Mutex to lock. */ + + int ref; /* Reference count. */ + +#if defined(DB_WIN32) + HANDLE handle; /* Windows/32 file handle. */ +#endif + int fd; /* POSIX file descriptor. */ + + char *name; /* File name (ref DB_FH_UNLINK) */ + + /* + * Last seek statistics, used for zero-filling on filesystems + * that don't support it directly. + */ + db_pgno_t pgno; + u_int32_t pgsize; + u_int32_t offset; + +#define DB_FH_NOSYNC 0x01 /* Handle doesn't need to be sync'd. */ +#define DB_FH_OPENED 0x02 /* Handle is valid. */ +#define DB_FH_UNLINK 0x04 /* Unlink on close */ + u_int8_t flags; +}; + +#if defined(__cplusplus) +} +#endif + +#include "dbinc_auto/os_ext.h" +#endif /* !_DB_OS_H_ */ diff --git a/lib_dict/bdb/include/os_ext.h b/lib_dict/bdb/include/os_ext.h new file mode 100644 index 000000000..a26958501 --- /dev/null +++ b/lib_dict/bdb/include/os_ext.h @@ -0,0 +1,70 @@ +/* DO NOT EDIT: automatically built by dist/s_include. */ +#ifndef _os_ext_h_ +#define _os_ext_h_ + +#if defined(__cplusplus) +extern "C" { +#endif + +int __os_abspath __P((const char *)); +int __os_umalloc __P((DB_ENV *, size_t, void *)); +int __os_urealloc __P((DB_ENV *, size_t, void *)); +void __os_ufree __P((DB_ENV *, void *)); +int __os_strdup __P((DB_ENV *, const char *, void *)); +int __os_calloc __P((DB_ENV *, size_t, size_t, void *)); +int __os_malloc __P((DB_ENV *, size_t, void *)); +int __os_realloc __P((DB_ENV *, size_t, void *)); +void __os_free __P((DB_ENV *, void *)); +void *__ua_memcpy __P((void *, const void *, size_t)); +void __os_clock __P((DB_ENV *, u_int32_t *, u_int32_t *)); +int __os_fs_notzero __P((void)); +int __os_dirlist __P((DB_ENV *, const char *, char ***, int *)); +void __os_dirfree __P((DB_ENV *, char **, int)); +int __os_get_errno_ret_zero __P((void)); +int __os_get_errno __P((void)); +void __os_set_errno __P((int)); +int __os_fileid __P((DB_ENV *, const char *, int, u_int8_t *)); +int __os_fsync __P((DB_ENV *, DB_FH *)); +int __os_openhandle __P((DB_ENV *, const char *, int, int, DB_FH **)); +int __os_closehandle __P((DB_ENV *, DB_FH *)); +void __os_id __P((u_int32_t *)); +void __os_unique_id __P((DB_ENV *, u_int32_t *)); +int __os_r_sysattach __P((DB_ENV *, REGINFO *, REGION *)); +int __os_r_sysdetach __P((DB_ENV *, REGINFO *, int)); +int __os_mapfile __P((DB_ENV *, char *, DB_FH *, size_t, int, void **)); +int __os_unmapfile __P((DB_ENV *, void *, size_t)); +u_int32_t __db_oflags __P((int)); +int __db_omode __P((const char *)); +int __db_shm_mode __P((DB_ENV *)); +int __os_have_direct __P((void)); +int __os_open __P((DB_ENV *, const char *, u_int32_t, int, DB_FH **)); +int __os_open_extend __P((DB_ENV *, const char *, u_int32_t, u_int32_t, int, DB_FH **)); +#ifdef HAVE_QNX +int __os_shmname __P((DB_ENV *, const char *, char **)); +#endif +int __os_r_attach __P((DB_ENV *, REGINFO *, REGION *)); +int __os_r_detach __P((DB_ENV *, REGINFO *, int)); +int __os_rename __P((DB_ENV *, const char *, const char *, u_int32_t)); +int __os_isroot __P((void)); +char *__db_rpath __P((const char *)); +int __os_io __P((DB_ENV *, int, DB_FH *, db_pgno_t, u_int32_t, u_int8_t *, size_t *)); +int __os_read __P((DB_ENV *, DB_FH *, void *, size_t, size_t *)); +int __os_write __P((DB_ENV *, DB_FH *, void *, size_t, size_t *)); +int __os_seek __P((DB_ENV *, DB_FH *, u_int32_t, db_pgno_t, u_int32_t, int, DB_OS_SEEK)); +void __os_sleep __P((DB_ENV *, u_long, u_long)); +void __os_spin __P((DB_ENV *)); +void __os_yield __P((DB_ENV*, u_long)); +int __os_exists __P((const char *, int *)); +int __os_ioinfo __P((DB_ENV *, const char *, DB_FH *, u_int32_t *, u_int32_t *, u_int32_t *)); +int __os_tmpdir __P((DB_ENV *, u_int32_t)); +int __os_truncate __P((DB_ENV *, DB_FH *, db_pgno_t, u_int32_t)); +int __os_region_unlink __P((DB_ENV *, const char *)); +int __os_unlink __P((DB_ENV *, const char *)); +int __os_is_winnt __P((void)); +int __os_have_direct __P((void)); +int __os_unlink __P((DB_ENV *, const char *)); + +#if defined(__cplusplus) +} +#endif +#endif /* !_os_ext_h_ */ diff --git a/lib_dict/bdb/include/qam.h b/lib_dict/bdb/include/qam.h new file mode 100644 index 000000000..43910d01d --- /dev/null +++ b/lib_dict/bdb/include/qam.h @@ -0,0 +1,176 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1999-2004 + * Sleepycat Software. All rights reserved. + * + * $Id: qam.h,v 11.49 2004/09/17 22:00:27 mjc Exp $ + */ + +#ifndef _DB_QAM_H_ +#define _DB_QAM_H_ + +/* + * QAM data elements: a status field and the data. + */ +typedef struct _qamdata { + u_int8_t flags; /* 00: delete bit. */ +#define QAM_VALID 0x01 +#define QAM_SET 0x02 + u_int8_t data[1]; /* Record. */ +} QAMDATA; + +struct __queue; typedef struct __queue QUEUE; +struct __qcursor; typedef struct __qcursor QUEUE_CURSOR; + +struct __qcursor { + /* struct __dbc_internal */ + __DBC_INTERNAL + + /* Queue private part */ + + /* Per-thread information: queue private. */ + db_recno_t recno; /* Current record number. */ + + u_int32_t flags; +}; + +typedef struct __mpfarray { + u_int32_t n_extent; /* Number of extents in table. */ + u_int32_t low_extent; /* First extent open. */ + u_int32_t hi_extent; /* Last extent open. */ + struct __qmpf { + int pinref; + DB_MPOOLFILE *mpf; + } *mpfarray; /* Array of open extents. */ +} MPFARRAY; + +/* + * The in-memory, per-tree queue data structure. + */ +struct __queue { + db_pgno_t q_meta; /* Database meta-data page. */ + db_pgno_t q_root; /* Database root page. */ + + int re_pad; /* Fixed-length padding byte. */ + u_int32_t re_len; /* Length for fixed-length records. */ + u_int32_t rec_page; /* records per page */ + u_int32_t page_ext; /* Pages per extent */ + MPFARRAY array1, array2; /* File arrays. */ + + /* Extent file configuration: */ + DBT pgcookie; /* Initialized pgcookie. */ + DB_PGINFO pginfo; /* Initialized pginfo struct. */ + + char *path; /* Space allocated to file pathname. */ + char *name; /* The name of the file. */ + char *dir; /* The dir of the file. */ + int mode; /* Mode to open extents. */ +}; + +/* Format for queue extent names. */ +#define QUEUE_EXTENT "%s%c__dbq.%s.%d" +#define QUEUE_EXTENT_HEAD "__dbq.%s." + +typedef struct __qam_filelist { + DB_MPOOLFILE *mpf; + u_int32_t id; +} QUEUE_FILELIST; + +/* + * Calculate the page number of a recno. + * + * Number of records per page = + * Divide the available space on the page by the record len + header. + * + * Page number for record = + * divide the physical record number by the records per page + * add the root page number + * For now the root page will always be 1, but we might want to change + * in the future (e.g. multiple fixed len queues per file). + * + * Index of record on page = + * physical record number, less the logical pno times records/page + */ +#define CALC_QAM_RECNO_PER_PAGE(dbp) \ + (((dbp)->pgsize - QPAGE_SZ(dbp)) / \ + (u_int32_t)DB_ALIGN((uintmax_t)SSZA(QAMDATA, data) + \ + ((QUEUE *)(dbp)->q_internal)->re_len, sizeof(u_int32_t))) + +#define QAM_RECNO_PER_PAGE(dbp) (((QUEUE*)(dbp)->q_internal)->rec_page) + +#define QAM_RECNO_PAGE(dbp, recno) \ + (((QUEUE *)(dbp)->q_internal)->q_root \ + + (((recno) - 1) / QAM_RECNO_PER_PAGE(dbp))) + +#define QAM_PAGE_EXTENT(dbp, pgno) \ + (((pgno) - 1) / ((QUEUE *)(dbp)->q_internal)->page_ext) + +#define QAM_RECNO_EXTENT(dbp, recno) \ + QAM_PAGE_EXTENT(dbp, QAM_RECNO_PAGE(dbp, recno)) + +#define QAM_RECNO_INDEX(dbp, pgno, recno) \ + (((recno) - 1) - (QAM_RECNO_PER_PAGE(dbp) \ + * (pgno - ((QUEUE *)(dbp)->q_internal)->q_root))) + +#define QAM_GET_RECORD(dbp, page, index) \ + ((QAMDATA *)((u_int8_t *)(page) + (QPAGE_SZ(dbp) + \ + (DB_ALIGN((uintmax_t)SSZA(QAMDATA, data) + \ + ((QUEUE *)(dbp)->q_internal)->re_len, sizeof(u_int32_t)) * index)))) + +#define QAM_AFTER_CURRENT(meta, recno) \ + ((recno) > (meta)->cur_recno && \ + ((meta)->first_recno <= (meta)->cur_recno || \ + ((recno) < (meta)->first_recno && \ + (recno) - (meta)->cur_recno < (meta)->first_recno - (recno)))) + +#define QAM_BEFORE_FIRST(meta, recno) \ + ((recno) < (meta)->first_recno && \ + ((meta->first_recno <= (meta)->cur_recno || \ + ((recno) > (meta)->cur_recno && \ + (recno) - (meta)->cur_recno > (meta)->first_recno - (recno))))) + +#define QAM_NOT_VALID(meta, recno) \ + (recno == RECNO_OOB || \ + QAM_BEFORE_FIRST(meta, recno) || QAM_AFTER_CURRENT(meta, recno)) + +/* + * Log opcodes for the mvptr routine. + */ +#define QAM_SETFIRST 0x01 +#define QAM_SETCUR 0x02 +#define QAM_TRUNCATE 0x04 + +/* + * Parameter to __qam_position. + */ +typedef enum { + QAM_READ, + QAM_WRITE, + QAM_CONSUME +} qam_position_mode; + +typedef enum { + QAM_PROBE_GET, + QAM_PROBE_PUT, + QAM_PROBE_MPF +} qam_probe_mode; + +/* + * Ops for __qam_nameop. + */ +typedef enum { + QAM_NAME_DISCARD, + QAM_NAME_RENAME, + QAM_NAME_REMOVE +} qam_name_op; + +#define __qam_fget(dbp, pgnoaddr, flags, addrp) \ + __qam_fprobe(dbp, *pgnoaddr, addrp, QAM_PROBE_GET, flags) + +#define __qam_fput(dbp, pageno, addrp, flags) \ + __qam_fprobe(dbp, pageno, addrp, QAM_PROBE_PUT, flags) + +#include "dbinc_auto/qam_auto.h" +#include "dbinc_auto/qam_ext.h" +#endif /* !_DB_QAM_H_ */ diff --git a/lib_dict/bdb/include/qam_auto.h b/lib_dict/bdb/include/qam_auto.h new file mode 100644 index 000000000..655c6d028 --- /dev/null +++ b/lib_dict/bdb/include/qam_auto.h @@ -0,0 +1,70 @@ +/* Do not edit: automatically built by gen_rec.awk. */ + +#ifndef __qam_AUTO_H +#define __qam_AUTO_H +#define DB___qam_incfirst 84 +typedef struct ___qam_incfirst_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + db_recno_t recno; + db_pgno_t meta_pgno; +} __qam_incfirst_args; + +#define DB___qam_mvptr 85 +typedef struct ___qam_mvptr_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + u_int32_t opcode; + int32_t fileid; + db_recno_t old_first; + db_recno_t new_first; + db_recno_t old_cur; + db_recno_t new_cur; + DB_LSN metalsn; + db_pgno_t meta_pgno; +} __qam_mvptr_args; + +#define DB___qam_del 79 +typedef struct ___qam_del_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + DB_LSN lsn; + db_pgno_t pgno; + u_int32_t indx; + db_recno_t recno; +} __qam_del_args; + +#define DB___qam_add 80 +typedef struct ___qam_add_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + DB_LSN lsn; + db_pgno_t pgno; + u_int32_t indx; + db_recno_t recno; + DBT data; + u_int32_t vflag; + DBT olddata; +} __qam_add_args; + +#define DB___qam_delext 83 +typedef struct ___qam_delext_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + int32_t fileid; + DB_LSN lsn; + db_pgno_t pgno; + u_int32_t indx; + db_recno_t recno; + DBT data; +} __qam_delext_args; + +#endif diff --git a/lib_dict/bdb/include/qam_ext.h b/lib_dict/bdb/include/qam_ext.h new file mode 100644 index 000000000..98ca31c03 --- /dev/null +++ b/lib_dict/bdb/include/qam_ext.h @@ -0,0 +1,74 @@ +/* DO NOT EDIT: automatically built by dist/s_include. */ +#ifndef _qam_ext_h_ +#define _qam_ext_h_ + +#if defined(__cplusplus) +extern "C" { +#endif + +int __qam_position __P((DBC *, db_recno_t *, qam_position_mode, int *)); +int __qam_pitem __P((DBC *, QPAGE *, u_int32_t, db_recno_t, DBT *)); +int __qam_append __P((DBC *, DBT *, DBT *)); +int __qam_c_dup __P((DBC *, DBC *)); +int __qam_c_init __P((DBC *)); +int __qam_truncate __P((DBC *, u_int32_t *)); +int __qam_incfirst_log __P((DB *, DB_TXN *, DB_LSN *, u_int32_t, db_recno_t, db_pgno_t)); +int __qam_incfirst_read __P((DB_ENV *, void *, __qam_incfirst_args **)); +int __qam_mvptr_log __P((DB *, DB_TXN *, DB_LSN *, u_int32_t, u_int32_t, db_recno_t, db_recno_t, db_recno_t, db_recno_t, DB_LSN *, db_pgno_t)); +int __qam_mvptr_read __P((DB_ENV *, void *, __qam_mvptr_args **)); +int __qam_del_log __P((DB *, DB_TXN *, DB_LSN *, u_int32_t, DB_LSN *, db_pgno_t, u_int32_t, db_recno_t)); +int __qam_del_read __P((DB_ENV *, void *, __qam_del_args **)); +int __qam_add_log __P((DB *, DB_TXN *, DB_LSN *, u_int32_t, DB_LSN *, db_pgno_t, u_int32_t, db_recno_t, const DBT *, u_int32_t, const DBT *)); +int __qam_add_read __P((DB_ENV *, void *, __qam_add_args **)); +int __qam_delext_log __P((DB *, DB_TXN *, DB_LSN *, u_int32_t, DB_LSN *, db_pgno_t, u_int32_t, db_recno_t, const DBT *)); +int __qam_delext_read __P((DB_ENV *, void *, __qam_delext_args **)); +int __qam_init_recover __P((DB_ENV *, int (***)(DB_ENV *, DBT *, DB_LSN *, db_recops, void *), size_t *)); +int __qam_incfirst_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __qam_mvptr_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __qam_del_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __qam_add_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __qam_delext_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __qam_init_print __P((DB_ENV *, int (***)(DB_ENV *, DBT *, DB_LSN *, db_recops, void *), size_t *)); +int __qam_mswap __P((PAGE *)); +int __qam_pgin_out __P((DB_ENV *, db_pgno_t, void *, DBT *)); +int __qam_fprobe __P((DB *, db_pgno_t, void *, qam_probe_mode, u_int32_t)); +int __qam_fclose __P((DB *, db_pgno_t)); +int __qam_fremove __P((DB *, db_pgno_t)); +int __qam_sync __P((DB *)); +int __qam_gen_filelist __P(( DB *, QUEUE_FILELIST **)); +int __qam_extent_names __P((DB_ENV *, char *, char ***)); +void __qam_exid __P((DB *, u_int8_t *, u_int32_t)); +int __qam_nameop __P((DB *, DB_TXN *, const char *, qam_name_op)); +int __qam_db_create __P((DB *)); +int __qam_db_close __P((DB *, u_int32_t)); +int __qam_get_extentsize __P((DB *, u_int32_t *)); +int __queue_pageinfo __P((DB *, db_pgno_t *, db_pgno_t *, int *, int, u_int32_t)); +int __db_prqueue __P((DB *, u_int32_t)); +int __qam_remove __P((DB *, DB_TXN *, const char *, const char *)); +int __qam_rename __P((DB *, DB_TXN *, const char *, const char *, const char *)); +void __qam_map_flags __P((DB *, u_int32_t *, u_int32_t *)); +int __qam_set_flags __P((DB *, u_int32_t *flagsp)); +int __qam_open __P((DB *, DB_TXN *, const char *, db_pgno_t, int, u_int32_t)); +int __qam_set_ext_data __P((DB*, const char *)); +int __qam_metachk __P((DB *, const char *, QMETA *)); +int __qam_new_file __P((DB *, DB_TXN *, DB_FH *, const char *)); +int __qam_incfirst_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __qam_mvptr_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __qam_del_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __qam_delext_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __qam_add_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __qam_stat __P((DBC *, void *, u_int32_t)); +int __qam_stat_print __P((DBC *, u_int32_t)); +int __db_no_queue_am __P((DB_ENV *)); +int __qam_31_qammeta __P((DB *, char *, u_int8_t *)); +int __qam_32_qammeta __P((DB *, char *, u_int8_t *)); +int __qam_vrfy_meta __P((DB *, VRFY_DBINFO *, QMETA *, db_pgno_t, u_int32_t)); +int __qam_vrfy_data __P((DB *, VRFY_DBINFO *, QPAGE *, db_pgno_t, u_int32_t)); +int __qam_vrfy_structure __P((DB *, VRFY_DBINFO *, u_int32_t)); +int __qam_vrfy_walkqueue __P((DB *, VRFY_DBINFO *, void *, int (*)(void *, const void *), u_int32_t)); +int __qam_salvage __P((DB *, VRFY_DBINFO *, db_pgno_t, PAGE *, void *, int (*)(void *, const void *), u_int32_t)); + +#if defined(__cplusplus) +} +#endif +#endif /* !_qam_ext_h_ */ diff --git a/lib_dict/bdb/include/queue.h b/lib_dict/bdb/include/queue.h new file mode 100644 index 000000000..bf09b12d7 --- /dev/null +++ b/lib_dict/bdb/include/queue.h @@ -0,0 +1,564 @@ + +/* + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + * $FreeBSD: src/sys/sys/queue.h,v 1.54 2002/08/05 05:18:43 alfred Exp $ + */ + +#ifndef _DB_QUEUE_H_ +#define _DB_QUEUE_H_ + +#if defined(__cplusplus) +extern "C" { +#endif + +/* + * This file defines four types of data structures: singly-linked lists, + * singly-linked tail queues, lists and tail queues. + * + * A singly-linked list is headed by a single forward pointer. The elements + * are singly linked for minimum space and pointer manipulation overhead at + * the expense of O(n) removal for arbitrary elements. New elements can be + * added to the list after an existing element or at the head of the list. + * Elements being removed from the head of the list should use the explicit + * macro for this purpose for optimum efficiency. A singly-linked list may + * only be traversed in the forward direction. Singly-linked lists are ideal + * for applications with large datasets and few or no removals or for + * implementing a LIFO queue. + * + * A singly-linked tail queue is headed by a pair of pointers, one to the + * head of the list and the other to the tail of the list. The elements are + * singly linked for minimum space and pointer manipulation overhead at the + * expense of O(n) removal for arbitrary elements. New elements can be added + * to the list after an existing element, at the head of the list, or at the + * end of the list. Elements being removed from the head of the tail queue + * should use the explicit macro for this purpose for optimum efficiency. + * A singly-linked tail queue may only be traversed in the forward direction. + * Singly-linked tail queues are ideal for applications with large datasets + * and few or no removals or for implementing a FIFO queue. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + * + * A tail queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or + * after an existing element, at the head of the list, or at the end of + * the list. A tail queue may be traversed in either direction. + * + * For details on the use of these macros, see the queue(3) manual page. + * + * + * SLIST LIST STAILQ TAILQ + * _HEAD + + + + + * _HEAD_INITIALIZER + + + + + * _ENTRY + + + + + * _INIT + + + + + * _EMPTY + + + + + * _FIRST + + + + + * _NEXT + + + + + * _PREV - - - + + * _LAST - - + + + * _FOREACH + + + + + * _FOREACH_REVERSE - - - + + * _INSERT_HEAD + + + + + * _INSERT_BEFORE - + - + + * _INSERT_AFTER + + + + + * _INSERT_TAIL - - + + + * _CONCAT - - + + + * _REMOVE_HEAD + - + - + * _REMOVE + + + + + * + */ + +/* + * XXX + * We #undef all of the macros because there are incompatible versions of this + * file and these macros on various systems. What makes the problem worse is + * they are included and/or defined by system include files which we may have + * already loaded into Berkeley DB before getting here. For example, FreeBSD's + * includes its system , and VxWorks UnixLib.h defines + * several of the LIST_XXX macros. Visual C.NET 7.0 also defines some of these + * same macros in Vc7\PlatformSDK\Include\WinNT.h. Make sure we use ours. + */ +#undef LIST_EMPTY +#undef LIST_ENTRY +#undef LIST_FIRST +#undef LIST_FOREACH +#undef LIST_HEAD +#undef LIST_HEAD_INITIALIZER +#undef LIST_INIT +#undef LIST_INSERT_AFTER +#undef LIST_INSERT_BEFORE +#undef LIST_INSERT_HEAD +#undef LIST_NEXT +#undef LIST_REMOVE +#undef QMD_TRACE_ELEM +#undef QMD_TRACE_HEAD +#undef QUEUE_MACRO_DEBUG +#undef SLIST_EMPTY +#undef SLIST_ENTRY +#undef SLIST_FIRST +#undef SLIST_FOREACH +#undef SLIST_FOREACH_PREVPTR +#undef SLIST_HEAD +#undef SLIST_HEAD_INITIALIZER +#undef SLIST_INIT +#undef SLIST_INSERT_AFTER +#undef SLIST_INSERT_HEAD +#undef SLIST_NEXT +#undef SLIST_REMOVE +#undef SLIST_REMOVE_HEAD +#undef STAILQ_CONCAT +#undef STAILQ_EMPTY +#undef STAILQ_ENTRY +#undef STAILQ_FIRST +#undef STAILQ_FOREACH +#undef STAILQ_HEAD +#undef STAILQ_HEAD_INITIALIZER +#undef STAILQ_INIT +#undef STAILQ_INSERT_AFTER +#undef STAILQ_INSERT_HEAD +#undef STAILQ_INSERT_TAIL +#undef STAILQ_LAST +#undef STAILQ_NEXT +#undef STAILQ_REMOVE +#undef STAILQ_REMOVE_HEAD +#undef STAILQ_REMOVE_HEAD_UNTIL +#undef TAILQ_CONCAT +#undef TAILQ_EMPTY +#undef TAILQ_ENTRY +#undef TAILQ_FIRST +#undef TAILQ_FOREACH +#undef TAILQ_FOREACH_REVERSE +#undef TAILQ_HEAD +#undef TAILQ_HEAD_INITIALIZER +#undef TAILQ_INIT +#undef TAILQ_INSERT_AFTER +#undef TAILQ_INSERT_BEFORE +#undef TAILQ_INSERT_HEAD +#undef TAILQ_INSERT_TAIL +#undef TAILQ_LAST +#undef TAILQ_NEXT +#undef TAILQ_PREV +#undef TAILQ_REMOVE +#undef TRACEBUF +#undef TRASHIT + +#define QUEUE_MACRO_DEBUG 0 +#if QUEUE_MACRO_DEBUG +/* Store the last 2 places the queue element or head was altered */ +struct qm_trace { + char * lastfile; + int lastline; + char * prevfile; + int prevline; +}; + +#define TRACEBUF struct qm_trace trace; +#define TRASHIT(x) do {(x) = (void *)-1;} while (0) + +#define QMD_TRACE_HEAD(head) do { \ + (head)->trace.prevline = (head)->trace.lastline; \ + (head)->trace.prevfile = (head)->trace.lastfile; \ + (head)->trace.lastline = __LINE__; \ + (head)->trace.lastfile = __FILE__; \ +} while (0) + +#define QMD_TRACE_ELEM(elem) do { \ + (elem)->trace.prevline = (elem)->trace.lastline; \ + (elem)->trace.prevfile = (elem)->trace.lastfile; \ + (elem)->trace.lastline = __LINE__; \ + (elem)->trace.lastfile = __FILE__; \ +} while (0) + +#else +#define QMD_TRACE_ELEM(elem) +#define QMD_TRACE_HEAD(head) +#define TRACEBUF +#define TRASHIT(x) +#endif /* QUEUE_MACRO_DEBUG */ + +/* + * Singly-linked List declarations. + */ +#define SLIST_HEAD(name, type) \ +struct name { \ + struct type *slh_first; /* first element */ \ +} + +#define SLIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define SLIST_ENTRY(type) \ +struct { \ + struct type *sle_next; /* next element */ \ +} + +/* + * Singly-linked List functions. + */ +#define SLIST_EMPTY(head) ((head)->slh_first == NULL) + +#define SLIST_FIRST(head) ((head)->slh_first) + +#define SLIST_FOREACH(var, head, field) \ + for ((var) = SLIST_FIRST((head)); \ + (var); \ + (var) = SLIST_NEXT((var), field)) + +#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \ + for ((varp) = &SLIST_FIRST((head)); \ + ((var) = *(varp)) != NULL; \ + (varp) = &SLIST_NEXT((var), field)) + +#define SLIST_INIT(head) do { \ + SLIST_FIRST((head)) = NULL; \ +} while (0) + +#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ + SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \ + SLIST_NEXT((slistelm), field) = (elm); \ +} while (0) + +#define SLIST_INSERT_HEAD(head, elm, field) do { \ + SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \ + SLIST_FIRST((head)) = (elm); \ +} while (0) + +#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) + +#define SLIST_REMOVE(head, elm, type, field) do { \ + if (SLIST_FIRST((head)) == (elm)) { \ + SLIST_REMOVE_HEAD((head), field); \ + } \ + else { \ + struct type *curelm = SLIST_FIRST((head)); \ + while (SLIST_NEXT(curelm, field) != (elm)) \ + curelm = SLIST_NEXT(curelm, field); \ + SLIST_NEXT(curelm, field) = \ + SLIST_NEXT(SLIST_NEXT(curelm, field), field); \ + } \ +} while (0) + +#define SLIST_REMOVE_HEAD(head, field) do { \ + SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \ +} while (0) + +/* + * Singly-linked Tail queue declarations. + */ +#define STAILQ_HEAD(name, type) \ +struct name { \ + struct type *stqh_first;/* first element */ \ + struct type **stqh_last;/* addr of last next element */ \ +} + +#define STAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).stqh_first } + +#define STAILQ_ENTRY(type) \ +struct { \ + struct type *stqe_next; /* next element */ \ +} + +/* + * Singly-linked Tail queue functions. + */ +#define STAILQ_CONCAT(head1, head2) do { \ + if (!STAILQ_EMPTY((head2))) { \ + *(head1)->stqh_last = (head2)->stqh_first; \ + (head1)->stqh_last = (head2)->stqh_last; \ + STAILQ_INIT((head2)); \ + } \ +} while (0) + +#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL) + +#define STAILQ_FIRST(head) ((head)->stqh_first) + +#define STAILQ_FOREACH(var, head, field) \ + for ((var) = STAILQ_FIRST((head)); \ + (var); \ + (var) = STAILQ_NEXT((var), field)) + +#define STAILQ_INIT(head) do { \ + STAILQ_FIRST((head)) = NULL; \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \ + if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ + STAILQ_NEXT((tqelm), field) = (elm); \ +} while (0) + +#define STAILQ_INSERT_HEAD(head, elm, field) do { \ + if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ + STAILQ_FIRST((head)) = (elm); \ +} while (0) + +#define STAILQ_INSERT_TAIL(head, elm, field) do { \ + STAILQ_NEXT((elm), field) = NULL; \ + *(head)->stqh_last = (elm); \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ +} while (0) + +#define STAILQ_LAST(head, type, field) \ + (STAILQ_EMPTY((head)) ? \ + NULL : \ + ((struct type *) \ + ((char *)((head)->stqh_last) - __offsetof(struct type, field)))) + +#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) + +#define STAILQ_REMOVE(head, elm, type, field) do { \ + if (STAILQ_FIRST((head)) == (elm)) { \ + STAILQ_REMOVE_HEAD((head), field); \ + } \ + else { \ + struct type *curelm = STAILQ_FIRST((head)); \ + while (STAILQ_NEXT(curelm, field) != (elm)) \ + curelm = STAILQ_NEXT(curelm, field); \ + if ((STAILQ_NEXT(curelm, field) = \ + STAILQ_NEXT(STAILQ_NEXT(curelm, field), field)) == NULL)\ + (head)->stqh_last = &STAILQ_NEXT((curelm), field);\ + } \ +} while (0) + +#define STAILQ_REMOVE_HEAD(head, field) do { \ + if ((STAILQ_FIRST((head)) = \ + STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +#define STAILQ_REMOVE_HEAD_UNTIL(head, elm, field) do { \ + if ((STAILQ_FIRST((head)) = STAILQ_NEXT((elm), field)) == NULL) \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +/* + * List declarations. + */ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +#define LIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} + +/* + * List functions. + */ + +#define LIST_EMPTY(head) ((head)->lh_first == NULL) + +#define LIST_FIRST(head) ((head)->lh_first) + +#define LIST_FOREACH(var, head, field) \ + for ((var) = LIST_FIRST((head)); \ + (var); \ + (var) = LIST_NEXT((var), field)) + +#define LIST_INIT(head) do { \ + LIST_FIRST((head)) = NULL; \ +} while (0) + +#define LIST_INSERT_AFTER(listelm, elm, field) do { \ + if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\ + LIST_NEXT((listelm), field)->field.le_prev = \ + &LIST_NEXT((elm), field); \ + LIST_NEXT((listelm), field) = (elm); \ + (elm)->field.le_prev = &LIST_NEXT((listelm), field); \ +} while (0) + +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + LIST_NEXT((elm), field) = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &LIST_NEXT((elm), field); \ +} while (0) + +#define LIST_INSERT_HEAD(head, elm, field) do { \ + if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \ + LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\ + LIST_FIRST((head)) = (elm); \ + (elm)->field.le_prev = &LIST_FIRST((head)); \ +} while (0) + +#define LIST_NEXT(elm, field) ((elm)->field.le_next) + +#define LIST_REMOVE(elm, field) do { \ + if (LIST_NEXT((elm), field) != NULL) \ + LIST_NEXT((elm), field)->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = LIST_NEXT((elm), field); \ +} while (0) + +/* + * Tail queue declarations. + */ +#define TAILQ_HEAD(name, type) \ +struct name { \ + struct type *tqh_first; /* first element */ \ + struct type **tqh_last; /* addr of last next element */ \ + TRACEBUF \ +} + +#define TAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).tqh_first } + +#define TAILQ_ENTRY(type) \ +struct { \ + struct type *tqe_next; /* next element */ \ + struct type **tqe_prev; /* address of previous next element */ \ + TRACEBUF \ +} + +/* + * Tail queue functions. + */ +#define TAILQ_CONCAT(head1, head2, field) do { \ + if (!TAILQ_EMPTY(head2)) { \ + *(head1)->tqh_last = (head2)->tqh_first; \ + (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \ + (head1)->tqh_last = (head2)->tqh_last; \ + TAILQ_INIT((head2)); \ + QMD_TRACE_HEAD(head); \ + QMD_TRACE_HEAD(head2); \ + } \ +} while (0) + +#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) + +#define TAILQ_FIRST(head) ((head)->tqh_first) + +#define TAILQ_FOREACH(var, head, field) \ + for ((var) = TAILQ_FIRST((head)); \ + (var); \ + (var) = TAILQ_NEXT((var), field)) + +#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ + for ((var) = TAILQ_LAST((head), headname); \ + (var); \ + (var) = TAILQ_PREV((var), headname, field)) + +#define TAILQ_INIT(head) do { \ + TAILQ_FIRST((head)) = NULL; \ + (head)->tqh_last = &TAILQ_FIRST((head)); \ + QMD_TRACE_HEAD(head); \ +} while (0) + +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\ + TAILQ_NEXT((elm), field)->field.tqe_prev = \ + &TAILQ_NEXT((elm), field); \ + else { \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + QMD_TRACE_HEAD(head); \ + } \ + TAILQ_NEXT((listelm), field) = (elm); \ + (elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \ + QMD_TRACE_ELEM(&(elm)->field); \ + QMD_TRACE_ELEM(&listelm->field); \ +} while (0) + +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + TAILQ_NEXT((elm), field) = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \ + QMD_TRACE_ELEM(&(elm)->field); \ + QMD_TRACE_ELEM(&listelm->field); \ +} while (0) + +#define TAILQ_INSERT_HEAD(head, elm, field) do { \ + if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \ + TAILQ_FIRST((head))->field.tqe_prev = \ + &TAILQ_NEXT((elm), field); \ + else \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + TAILQ_FIRST((head)) = (elm); \ + (elm)->field.tqe_prev = &TAILQ_FIRST((head)); \ + QMD_TRACE_HEAD(head); \ + QMD_TRACE_ELEM(&(elm)->field); \ +} while (0) + +#define TAILQ_INSERT_TAIL(head, elm, field) do { \ + TAILQ_NEXT((elm), field) = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + QMD_TRACE_HEAD(head); \ + QMD_TRACE_ELEM(&(elm)->field); \ +} while (0) + +#define TAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) + +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) + +#define TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) + +#define TAILQ_REMOVE(head, elm, field) do { \ + if ((TAILQ_NEXT((elm), field)) != NULL) \ + TAILQ_NEXT((elm), field)->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else { \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + QMD_TRACE_HEAD(head); \ + } \ + *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \ + TRASHIT((elm)->field.tqe_next); \ + TRASHIT((elm)->field.tqe_prev); \ + QMD_TRACE_ELEM(&(elm)->field); \ +} while (0) + +#if defined(__cplusplus) +} +#endif +#endif /* !_DB_QUEUE_H_ */ diff --git a/lib_dict/bdb/include/region.h b/lib_dict/bdb/include/region.h new file mode 100644 index 000000000..98f6ea07b --- /dev/null +++ b/lib_dict/bdb/include/region.h @@ -0,0 +1,303 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1998-2004 + * Sleepycat Software. All rights reserved. + * + * $Id: region.h,v 11.51 2004/10/15 16:59:39 bostic Exp $ + */ + +#ifndef _DB_REGION_H_ +#define _DB_REGION_H_ + +/* + * The DB environment consists of some number of "regions", which are described + * by the following four structures: + * + * REGENV -- shared information about the environment + * REGENV_REF -- file describing system memory version of REGENV + * REGION -- shared information about a single region + * REGINFO -- per-process information about a REGION + * + * There are three types of memory that hold regions: + * per-process heap (malloc) + * file mapped into memory (mmap, MapViewOfFile) + * system memory (shmget, CreateFileMapping) + * + * If the regions are private to a process, they're in malloc. If they're + * public, they're in file mapped memory, or, optionally, in system memory. + * Regions in the filesystem are named "__db.001", "__db.002" and so on. If + * we're not using a private environment allocated using malloc(3), the file + * "__db.001" will always exist, as we use it to synchronize on the regions, + * whether they exist in file mapped memory or system memory. + * + * The file "__db.001" contains a REGENV structure and a linked list of some + * number of REGION structures. Each of the REGION structures describes and + * locks one of the underlying shared regions used by DB. + * + * __db.001 + * +---------+ + * |REGENV | + * +---------+ +----------+ + * |REGION |-> | __db.002 | + * | | +----------+ + * +---------+ +----------+ + * |REGION |-> | __db.003 | + * | | +----------+ + * +---------+ +----------+ + * |REGION |-> | __db.004 | + * | | +----------+ + * +---------+ + * + * The only tricky part about manipulating the regions is correctly creating + * or joining the REGENV file, i.e., __db.001. We have to be absolutely sure + * that only one process creates it, and that everyone else joins it without + * seeing inconsistent data. Once that region is created, we can use normal + * shared locking procedures to do mutual exclusion for all other regions. + * + * One of the REGION structures in the main environment region describes the + * environment region itself. + * + * To lock a region, locate the REGION structure that describes it and acquire + * the region's mutex. There is one exception to this rule -- the lock for the + * environment region itself is in the REGENV structure, and not in the REGION + * that describes the environment region. That's so that we can acquire a lock + * without walking linked lists that could potentially change underneath us. + * The REGION will not be moved or removed during the life of the region, and + * so long-lived references to it can be held by the process. + * + * All requests to create or join a region return a REGINFO structure, which + * is held by the caller and used to open and subsequently close the reference + * to the region. The REGINFO structure contains the per-process information + * that we need to access the region. + * + * The one remaining complication. If the regions (including the environment + * region) live in system memory, and the system memory isn't "named" somehow + * in the filesystem name space, we need some way of finding it. Do this by + * by writing the REGENV_REF structure into the "__db.001" file. When we find + * a __db.001 file that is too small to be a real, on-disk environment, we use + * the information it contains to redirect to the real "__db.001" file/memory. + * This currently only happens when the REGENV file is in shared system memory. + * + * Although DB does not currently grow regions when they run out of memory, it + * would be possible to do so. To grow a region, allocate a new region of the + * appropriate size, then copy the old region over it and insert the additional + * space into the already existing shalloc arena. Callers may have to fix up + * local references, but that should be easy to do. This failed in historic + * versions of DB because the region lock lived in the mapped memory, and when + * it was unmapped and remapped (or copied), threads could lose track of it. + * Once we moved that lock into a region that is never unmapped, growing should + * work. That all said, current versions of DB don't implement region grow + * because some systems don't support mutex copying, e.g., from OSF1 V4.0: + * + * The address of an msemaphore structure may be significant. If the + * msemaphore structure contains any value copied from an msemaphore + * structure at a different address, the result is undefined. + */ + +#if defined(__cplusplus) +extern "C" { +#endif + +#define DB_REGION_PREFIX "__db" /* DB file name prefix. */ +#define DB_REGION_FMT "__db.%03d" /* Region file name format. */ +#define DB_REGION_ENV "__db.001" /* Primary environment name. */ +#define DB_REGION_NAME_LENGTH 8 /* Length of file names. */ + +#define INVALID_REGION_ID 0 /* Out-of-band region ID. */ +#define REGION_ID_ENV 1 /* Primary environment ID. */ + +typedef enum { + INVALID_REGION_TYPE=0, /* Region type. */ + REGION_TYPE_ENV, + REGION_TYPE_LOCK, + REGION_TYPE_LOG, + REGION_TYPE_MPOOL, + REGION_TYPE_MUTEX, + REGION_TYPE_TXN } reg_type_t; + +#define INVALID_REGION_SEGID -1 /* Segment IDs are either shmget(2) or + * Win16 segment identifiers. They are + * both stored in a "long", and we need + * an out-of-band value. + */ +/* + * Nothing can live at region offset 0, because, in all cases, that's where + * we store *something*. Lots of code needs an out-of-band value for region + * offsets, so we use 0. + */ +#define INVALID_ROFF 0 + +/* Reference describing system memory version of REGENV. */ +typedef struct __db_reg_env_ref { + roff_t size; /* Region size. */ + long segid; /* UNIX shmget ID, VxWorks ID. */ +} REGENV_REF; + +/* Per-environment region information. */ +typedef struct __db_reg_env { + /* + * !!! + * The mutex must be the first entry in the structure to guarantee + * correct alignment. + */ + DB_MUTEX mutex; /* Environment mutex. */ + + /* + * !!! + * Note, the magic and panic fields are NOT protected by any mutex, + * and for this reason cannot be anything more complicated than a + * zero/non-zero value. + */ + u_int32_t magic; /* Valid region magic number. */ + u_int32_t envid; /* Unique environment ID. */ + + int envpanic; /* Environment is dead. */ + + int majver; /* Major DB version number. */ + int minver; /* Minor DB version number. */ + int patch; /* Patch DB version number. */ + + u_int32_t init_flags; /* Flags the env was initialized with.*/ + roff_t cipher_off; /* Offset of cipher area */ + + /* List of regions. */ + SH_LIST_HEAD(__db_regionh) regionq; + + u_int32_t refcnt; /* References to the environment. */ + + roff_t rep_off; /* Offset of the replication area. */ +#define DB_REGENV_REPLOCKED 0x0001 /* Env locked for rep backup. */ + u_int32_t flags; /* Shared environment flags. */ +#define DB_REGENV_TIMEOUT 30 /* Backup timeout. */ + time_t op_timestamp; /* Timestamp for operations. */ + time_t rep_timestamp; /* Timestamp for rep db handles. */ + + size_t pad; /* Guarantee that following memory is + * size_t aligned. This is necessary + * because we're going to store the + * allocation region information there. + */ +} REGENV; + +/* Per-region shared region information. */ +typedef struct __db_region { + /* + * !!! + * The mutex must be the first entry in the structure to guarantee + * correct alignment. + */ + DB_MUTEX mutex; /* Region mutex. */ + + SH_LIST_ENTRY q; /* Linked list of REGIONs. */ + + reg_type_t type; /* Region type. */ + u_int32_t id; /* Region id. */ + + roff_t size_orig; /* Region size in bytes (original). */ + roff_t size; /* Region size in bytes (adjusted). */ + + roff_t primary; /* Primary data structure offset. */ + + long segid; /* UNIX shmget(2), Win16 segment ID. */ +} REGION; + +/* + * Per-process/per-attachment information about a single region. + */ +struct __db_reginfo_t { /* __db_r_attach IN parameters. */ + DB_ENV *dbenv; /* Enclosing environment. */ + reg_type_t type; /* Region type. */ + u_int32_t id; /* Region id. */ + + /* __db_r_attach OUT parameters. */ + REGION *rp; /* Shared region. */ + + char *name; /* Region file name. */ + + void *addr_orig; /* Region address (original). */ + void *addr; /* Region address (adjusted). */ + void *primary; /* Primary data structure address. */ + + size_t max_alloc; /* Maximum bytes allocated. */ + size_t allocated; /* Bytes allocated. */ + +#ifdef DB_WIN32 + HANDLE wnt_handle; /* Win/NT HANDLE. */ +#endif + +#define REGION_CREATE 0x01 /* Caller created region. */ +#define REGION_CREATE_OK 0x02 /* Caller willing to create region. */ +#define REGION_JOIN_OK 0x04 /* Caller is looking for a match. */ + u_int32_t flags; +}; + +/* + * Mutex maintenance information each subsystem region must keep track + * of to manage resources adequately. + */ +typedef struct __db_regmaint_stat_t { + u_int32_t st_hint_hit; + u_int32_t st_hint_miss; + u_int32_t st_records; + u_int32_t st_clears; + u_int32_t st_destroys; + u_int32_t st_max_locks; +} REGMAINT_STAT; + +typedef struct __db_regmaint_t { + u_int32_t reglocks; /* Maximum # of mutexes we track. */ + u_int32_t regmutex_hint; /* Hint for next slot */ + REGMAINT_STAT stat; /* Stats */ + roff_t regmutexes[1]; /* Region mutexes in use. */ +} REGMAINT; + +/* + * R_ADDR Return a per-process address for a shared region offset. + * R_OFFSET Return a shared region offset for a per-process address. + */ +#define R_ADDR(reginfop, offset) \ + (F_ISSET((reginfop)->dbenv, DB_ENV_PRIVATE) ? (void *)(offset) :\ + (void *)((u_int8_t *)((reginfop)->addr) + (offset))) +#define R_OFFSET(reginfop, p) \ + (F_ISSET((reginfop)->dbenv, DB_ENV_PRIVATE) ? (roff_t)(p) : \ + (roff_t)((u_int8_t *)(p) - (u_int8_t *)(reginfop)->addr)) + +/* + * R_LOCK Lock/unlock a region. + * R_UNLOCK + */ +#define R_LOCK(dbenv, reginfo) \ + MUTEX_LOCK(dbenv, &(reginfo)->rp->mutex) +#define R_UNLOCK(dbenv, reginfo) \ + MUTEX_UNLOCK(dbenv, &(reginfo)->rp->mutex) + +/* PANIC_CHECK: Check to see if the DB environment is dead. */ +#define PANIC_CHECK(dbenv) \ + if (!F_ISSET((dbenv), DB_ENV_NOPANIC) && \ + (dbenv)->reginfo != NULL && ((REGENV *) \ + ((REGINFO *)(dbenv)->reginfo)->primary)->envpanic != 0) \ + return (__db_panic_msg(dbenv)); + +#define PANIC_SET(dbenv, onoff) \ + if ((dbenv)->reginfo != NULL) \ + ((REGENV *)((REGINFO *) \ + (dbenv)->reginfo)->primary)->envpanic = (onoff); + +/* + * All regions are created on 8K boundaries out of sheer paranoia, so we + * don't make some underlying VM unhappy. Make sure we don't overflow or + * underflow. + */ +#define OS_VMPAGESIZE (8 * 1024) +#define OS_VMROUNDOFF(i) { \ + if ((i) < \ + (UINT32_MAX - OS_VMPAGESIZE) + 1 || (i) < OS_VMPAGESIZE) \ + (i) += OS_VMPAGESIZE - 1; \ + (i) -= (i) % OS_VMPAGESIZE; \ +} + +#if defined(__cplusplus) +} +#endif +#endif /* !_DB_REGION_H_ */ diff --git a/lib_dict/bdb/include/rep.h b/lib_dict/bdb/include/rep.h new file mode 100644 index 000000000..ec1f290f4 --- /dev/null +++ b/lib_dict/bdb/include/rep.h @@ -0,0 +1,317 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2001-2004 + * Sleepycat Software. All rights reserved. + */ + +#ifndef _REP_H_ +#define _REP_H_ + +#include "dbinc_auto/rep_auto.h" + +#define REP_ALIVE 1 /* I am alive message. */ +#define REP_ALIVE_REQ 2 /* Request for alive messages. */ +#define REP_ALL_REQ 3 /* Request all log records greater than LSN. */ +#define REP_DUPMASTER 4 /* Duplicate master detected; propagate. */ +#define REP_FILE 5 /* Page of a database file. NOTUSED */ +#define REP_FILE_FAIL 6 /* File requested does not exist. */ +#define REP_FILE_REQ 7 /* Request for a database file. NOTUSED */ +#define REP_LOG 8 /* Log record. */ +#define REP_LOG_MORE 9 /* There are more log records to request. */ +#define REP_LOG_REQ 10 /* Request for a log record. */ +#define REP_MASTER_REQ 11 /* Who is the master */ +#define REP_NEWCLIENT 12 /* Announces the presence of a new client. */ +#define REP_NEWFILE 13 /* Announce a log file change. */ +#define REP_NEWMASTER 14 /* Announces who the master is. */ +#define REP_NEWSITE 15 /* Announces that a site has heard from a new + * site; like NEWCLIENT, but indirect. A + * NEWCLIENT message comes directly from the new + * client while a NEWSITE comes indirectly from + * someone who heard about a NEWSITE. + */ +#define REP_PAGE 16 /* Database page. */ +#define REP_PAGE_FAIL 17 /* Requested page does not exist. */ +#define REP_PAGE_MORE 18 /* There are more pages to request. */ +#define REP_PAGE_REQ 19 /* Request for a database page. */ +#define REP_UPDATE 20 /* Environment hotcopy information. */ +#define REP_UPDATE_REQ 21 /* Request for hotcopy information. */ +#define REP_VERIFY 22 /* A log record for verification. */ +#define REP_VERIFY_FAIL 23 /* The client is outdated. */ +#define REP_VERIFY_REQ 24 /* Request for a log record to verify. */ +#define REP_VOTE1 25 /* Send out your information for an election. */ +#define REP_VOTE2 26 /* Send a "you are master" vote. */ + +/* + * REP_PRINT_MESSAGE + * A function to print a debugging message. + * + * RPRINT + * A macro for debug printing. Takes as an arg the arg set for __db_msg. + * + * !!! This function assumes a local DB_MSGBUF variable called 'mb'. + */ +#ifdef DIAGNOSTIC +#define REP_PRINT_MESSAGE(dbenv, eid, rp, str) \ + __rep_print_message(dbenv, eid, rp, str) +#define RPRINT(e, r, x) do { \ + if (FLD_ISSET((e)->verbose, DB_VERB_REPLICATION)) { \ + DB_MSGBUF_INIT(&mb); \ + if ((e)->db_errpfx == NULL) { \ + if (F_ISSET((r), REP_F_CLIENT)) \ + __db_msgadd((e), &mb, "CLIENT: "); \ + else if (F_ISSET((r), REP_F_MASTER)) \ + __db_msgadd((e), &mb, "MASTER: "); \ + else \ + __db_msgadd((e), &mb, "REP_UNDEF: "); \ + } else \ + __db_msgadd((e), &mb, "%s: ",(e)->db_errpfx); \ + __db_msgadd x; \ + DB_MSGBUF_FLUSH((e), &mb); \ + } \ +} while (0) +#else +#define REP_PRINT_MESSAGE(dbenv, eid, rp, str) +#define RPRINT(e, r, x) +#endif + +/* + * Election gen file name + * The file contains an egen number for an election this client + * has NOT participated in. I.e. it is the number of a future + * election. We create it when we create the rep region, if it + * doesn't already exist and initialize egen to 1. If it does + * exist, we read it when we create the rep region. We write it + * immediately before sending our VOTE1 in an election. That way, + * if a client has ever sent a vote for any election, the file is + * already going to be updated to reflect a future election, + * should it crash. + */ +#define REP_EGENNAME "__db.rep.egen" + +/* + * Database types for __rep_client_dbinit + */ +typedef enum { + REP_DB, /* Log record database. */ + REP_PG /* Pg database. */ +} repdb_t; + +/* Shared replication structure. */ + +typedef struct __rep { + /* + * Due to alignment constraints on some architectures (e.g. HP-UX), + * DB_MUTEXes must be the first element of shalloced structures, + * and as a corollary there can be only one per structure. Thus, + * db_mutex_off points to a mutex in a separately-allocated chunk. + */ + DB_MUTEX mutex; /* Region lock. */ + roff_t db_mutex_off; /* Client database mutex. */ + roff_t tally_off; /* Offset of the tally region. */ + roff_t v2tally_off; /* Offset of the vote2 tally region. */ + int eid; /* Environment id. */ + int master_id; /* ID of the master site. */ + u_int32_t egen; /* Replication election generation. */ + u_int32_t gen; /* Replication generation number. */ + u_int32_t recover_gen; /* Last generation number in log. */ + int asites; /* Space allocated for sites. */ + int nsites; /* Number of sites in group. */ + int nvotes; /* Number of votes needed. */ + int priority; /* My priority in an election. */ + u_int32_t gbytes; /* Limit on data sent in single... */ + u_int32_t bytes; /* __rep_process_message call. */ +#define DB_REP_REQUEST_GAP 4 +#define DB_REP_MAX_GAP 128 + u_int32_t request_gap; /* # of records to receive before we + * request a missing log record. */ + u_int32_t max_gap; /* Maximum number of records before + * requesting a missing log record. */ + /* Status change information */ + int elect_th; /* A thread is in rep_elect. */ + u_int32_t msg_th; /* Number of callers in rep_proc_msg. */ + int start_th; /* A thread is in rep_start. */ + u_int32_t handle_cnt; /* Count of handles in library. */ + u_int32_t op_cnt; /* Multi-step operation count.*/ + int in_recovery; /* Running recovery now. */ + + /* Backup information. */ + int nfiles; /* Number of files we have info on. */ + int curfile; /* Current file we're getting. */ + __rep_fileinfo_args *curinfo; /* Current file info ptr. */ + void *finfo; /* Current file info buffer. */ + void *nextinfo; /* Next file info buffer. */ + void *originfo; /* Original file info buffer. */ + DB_LSN first_lsn; /* Earliest LSN we need. */ + DB_LSN last_lsn; /* Latest LSN we need. */ + db_pgno_t ready_pg; /* Next pg expected. */ + db_pgno_t waiting_pg; /* First pg after gap. */ + db_pgno_t max_wait_pg; /* Maximum pg requested. */ + u_int32_t npages; /* Num of pages rcvd for this file. */ + DB_MPOOLFILE *file_mpf; /* Mpoolfile for in-mem database. */ + DB *file_dbp; /* This file's page info. */ + DB *queue_dbp; /* Dbp for a queue file. */ + + /* Vote tallying information. */ + int sites; /* Sites heard from. */ + int winner; /* Current winner. */ + int w_priority; /* Winner priority. */ + u_int32_t w_gen; /* Winner generation. */ + DB_LSN w_lsn; /* Winner LSN. */ + u_int32_t w_tiebreaker; /* Winner tiebreaking value. */ + int votes; /* Number of votes for this site. */ + + /* Statistics. */ + DB_REP_STAT stat; + +#define REP_F_CLIENT 0x00001 /* Client replica. */ +#define REP_F_EPHASE1 0x00002 /* In phase 1 of election. */ +#define REP_F_EPHASE2 0x00004 /* In phase 2 of election. */ +#define REP_F_MASTER 0x00008 /* Master replica. */ +#define REP_F_MASTERELECT 0x00010 /* Master elect */ +#define REP_F_NOARCHIVE 0x00020 /* Rep blocks log_archive */ +#define REP_F_READY 0x00040 /* Wait for txn_cnt to be 0. */ +#define REP_F_RECOVER_LOG 0x00080 /* In recovery - log. */ +#define REP_F_RECOVER_PAGE 0x00100 /* In recovery - pages. */ +#define REP_F_RECOVER_UPDATE 0x00200 /* In recovery - files. */ +#define REP_F_RECOVER_VERIFY 0x00400 /* In recovery - verify. */ +#define REP_F_TALLY 0x00800 /* Tallied vote before elect. */ + u_int32_t flags; +} REP; + +/* + * Recovery flag mask to easily check any/all recovery bits. That is + * REP_F_READY and all REP_F_RECOVER*. This must change if the values + * of the flags change. + */ +#define REP_F_RECOVER_MASK \ + (REP_F_READY | REP_F_RECOVER_LOG | REP_F_RECOVER_PAGE | \ + REP_F_RECOVER_UPDATE | REP_F_RECOVER_VERIFY) + +#define IN_ELECTION(R) F_ISSET((R), REP_F_EPHASE1 | REP_F_EPHASE2) +#define IN_ELECTION_TALLY(R) \ + F_ISSET((R), REP_F_EPHASE1 | REP_F_EPHASE2 | REP_F_TALLY) +#define IS_REP_MASTER(dbenv) \ + (REP_ON(dbenv) && ((DB_REP *)(dbenv)->rep_handle)->region && \ + F_ISSET(((REP *)((DB_REP *)(dbenv)->rep_handle)->region), \ + REP_F_MASTER)) + +#define IS_REP_CLIENT(dbenv) \ + (REP_ON(dbenv) && ((DB_REP *)(dbenv)->rep_handle)->region && \ + F_ISSET(((REP *)((DB_REP *)(dbenv)->rep_handle)->region), \ + REP_F_CLIENT)) + +#define IS_CLIENT_PGRECOVER(dbenv) \ + (IS_REP_CLIENT(dbenv) && \ + F_ISSET(((REP *)((DB_REP *)(dbenv)->rep_handle)->region), \ + REP_F_RECOVER_PAGE)) + +/* + * Macros to figure out if we need to do replication pre/post-amble + * processing. + */ +#define IS_REPLICATED(E, D) \ + (!F_ISSET((D), DB_AM_RECOVER | DB_AM_REPLICATION) && \ + REP_ON(E) && ((DB_REP *)((E)->rep_handle))->region != NULL && \ + ((DB_REP *)((E)->rep_handle))->region->flags != 0) + +#define IS_ENV_REPLICATED(E) (REP_ON(E) && \ + ((DB_REP *)((E)->rep_handle))->region != NULL && \ + ((DB_REP *)((E)->rep_handle))->region->flags != 0) + +/* + * Per-process replication structure. + * + * There are 2 mutexes used in replication. + * 1. rep_mutexp - This protects the fields of the rep region above. + * 2. db_mutexp - This protects the per-process flags, and bookkeeping + * database and all of the components that maintain it. Those + * components include the following fields in the log region (see log.h): + * a. ready_lsn + * b. waiting_lsn + * c. verify_lsn + * d. wait_recs + * e. rcvd_recs + * f. max_wait_lsn + * These fields in the log region are NOT protected by the log + * region lock at all. + * + * Note that the per-process flags should truly be protected by a + * special per-process thread mutex, but it is currently set in so + * isolated a manner that it didn't make sense to do so and in most + * case we're already holding the db_mutexp anyway. + * + * The lock ordering protocol is that db_mutexp must be acquired + * first and then either rep_mutexp, or the log region mutex may + * be acquired if necessary. + */ +struct __db_rep { + DB_MUTEX *rep_mutexp; /* Mutex for rep region */ + + DB_MUTEX *db_mutexp; /* Mutex for bookkeeping database. */ + DB *rep_db; /* Bookkeeping database. */ + + REP *region; /* In memory structure. */ +#define DBREP_OPENFILES 0x0001 /* This handle has opened files. */ + u_int32_t flags; /* per-process flags. */ +}; + +/* + * Control structure for replication communication infrastructure. + * + * Note that the version information should be at the beginning of the + * structure, so that we can rearrange the rest of it while letting the + * version checks continue to work. DB_REPVERSION should be revved any time + * the rest of the structure changes or when the message numbers change. + */ +typedef struct __rep_control { +#define DB_REPVERSION 2 + u_int32_t rep_version; /* Replication version number. */ + u_int32_t log_version; /* Log version number. */ + + DB_LSN lsn; /* Log sequence number. */ + u_int32_t rectype; /* Message type. */ + u_int32_t gen; /* Generation number. */ + u_int32_t flags; /* log_put flag value. */ +} REP_CONTROL; + +/* Election vote information. */ +typedef struct __rep_vote { + u_int32_t egen; /* Election generation. */ + int nsites; /* Number of sites I've been in + * communication with. */ + int nvotes; /* Number of votes needed to win. */ + int priority; /* My site's priority. */ + u_int32_t tiebreaker; /* Tie-breaking quasi-random value. */ +} REP_VOTE_INFO; + +typedef struct __rep_vtally { + u_int32_t egen; /* Voter's election generation. */ + int eid; /* Voter's ID. */ +} REP_VTALLY; + +/* + * This structure takes care of representing a transaction. + * It holds all the records, sorted by page number so that + * we can obtain locks and apply updates in a deadlock free + * order. + */ +typedef struct __lsn_collection { + u_int nlsns; + u_int nalloc; + DB_LSN *array; +} LSN_COLLECTION; + +/* + * This is used by the page-prep routines to do the lock_vec call to + * apply the updates for a single transaction or a collection of + * transactions. + */ +typedef struct _linfo { + int n; + DB_LOCKREQ *reqs; + DBT *objs; +} linfo_t; + +#include "dbinc_auto/rep_ext.h" +#endif /* !_REP_H_ */ diff --git a/lib_dict/bdb/include/rep_auto.h b/lib_dict/bdb/include/rep_auto.h new file mode 100644 index 000000000..5e8b7818c --- /dev/null +++ b/lib_dict/bdb/include/rep_auto.h @@ -0,0 +1,22 @@ +/* Do not edit: automatically built by gen_rec.awk. */ + +#ifndef __rep_AUTO_H +#define __rep_AUTO_H +typedef struct ___rep_update_args { + DB_LSN first_lsn; + int num_files; +} __rep_update_args; + +typedef struct ___rep_fileinfo_args { + size_t pgsize; + db_pgno_t pgno; + db_pgno_t max_pgno; + int filenum; + int32_t id; + u_int32_t type; + u_int32_t flags; + DBT uid; + DBT info; +} __rep_fileinfo_args; + +#endif diff --git a/lib_dict/bdb/include/rep_ext.h b/lib_dict/bdb/include/rep_ext.h new file mode 100644 index 000000000..13486c735 --- /dev/null +++ b/lib_dict/bdb/include/rep_ext.h @@ -0,0 +1,59 @@ +/* DO NOT EDIT: automatically built by dist/s_include. */ +#ifndef _rep_ext_h_ +#define _rep_ext_h_ + +#if defined(__cplusplus) +extern "C" { +#endif + +int __rep_update_buf __P((u_int8_t *, size_t, size_t *, DB_LSN *, int)); +int __rep_update_read __P((DB_ENV *, void *, void **, __rep_update_args **)); +int __rep_fileinfo_buf __P((u_int8_t *, size_t, size_t *, size_t, db_pgno_t, db_pgno_t, int, int32_t, u_int32_t, u_int32_t, const DBT *, const DBT *)); +int __rep_fileinfo_read __P((DB_ENV *, void *, void **, __rep_fileinfo_args **)); +int __rep_update_req __P((DB_ENV *, int)); +int __rep_page_req __P((DB_ENV *, int, DBT *)); +int __rep_update_setup __P((DB_ENV *, int, REP_CONTROL *, DBT *)); +int __rep_page __P((DB_ENV *, int, REP_CONTROL *, DBT *)); +int __rep_page_fail __P((DB_ENV *, int, DBT *)); +int __rep_pggap_req __P((DB_ENV *, REP *, __rep_fileinfo_args *, int)); +void __rep_loggap_req __P((DB_ENV *, REP *, DB_LSN *, int)); +int __rep_finfo_alloc __P((DB_ENV *, __rep_fileinfo_args *, __rep_fileinfo_args **)); +void __rep_dbenv_create __P((DB_ENV *)); +int __rep_open __P((DB_ENV *)); +int __rep_client_dbinit __P((DB_ENV *, int, repdb_t)); +void __rep_elect_master __P((DB_ENV *, REP *, int *)); +int __rep_process_message __P((DB_ENV *, DBT *, DBT *, int *, DB_LSN *)); +int __rep_process_txn __P((DB_ENV *, DBT *)); +int __rep_tally __P((DB_ENV *, REP *, int, int *, u_int32_t, roff_t)); +void __rep_cmp_vote __P((DB_ENV *, REP *, int *, DB_LSN *, int, u_int32_t, u_int32_t)); +int __rep_cmp_vote2 __P((DB_ENV *, REP *, int, u_int32_t)); +int __rep_check_doreq __P((DB_ENV *, REP *)); +void __rep_lockout __P((DB_ENV *, DB_REP *, REP *, u_int32_t)); +int __rep_region_init __P((DB_ENV *)); +int __rep_region_destroy __P((DB_ENV *)); +void __rep_dbenv_refresh __P((DB_ENV *)); +int __rep_dbenv_close __P((DB_ENV *)); +int __rep_preclose __P((DB_ENV *, int)); +int __rep_write_egen __P((DB_ENV *, u_int32_t)); +int __rep_stat_pp __P((DB_ENV *, DB_REP_STAT **, u_int32_t)); +int __rep_stat_print_pp __P((DB_ENV *, u_int32_t)); +int __rep_stat_print __P((DB_ENV *, u_int32_t)); +int __rep_send_message __P((DB_ENV *, int, u_int32_t, DB_LSN *, const DBT *, u_int32_t)); +int __rep_new_master __P((DB_ENV *, REP_CONTROL *, int)); +int __rep_is_client __P((DB_ENV *)); +int __rep_noarchive __P((DB_ENV *)); +void __rep_send_vote __P((DB_ENV *, DB_LSN *, int, int, int, u_int32_t, u_int32_t, int, u_int32_t)); +void __rep_elect_done __P((DB_ENV *, REP *)); +int __rep_grow_sites __P((DB_ENV *dbenv, int nsites)); +void __env_rep_enter __P((DB_ENV *)); +void __env_db_rep_exit __P((DB_ENV *)); +int __db_rep_enter __P((DB *, int, int, int)); +void __op_rep_enter __P((DB_ENV *)); +void __op_rep_exit __P((DB_ENV *)); +void __rep_get_gen __P((DB_ENV *, u_int32_t *)); +void __rep_print_message __P((DB_ENV *, int, REP_CONTROL *, char *)); + +#if defined(__cplusplus) +} +#endif +#endif /* !_rep_ext_h_ */ diff --git a/lib_dict/bdb/include/rpc_client_ext.h b/lib_dict/bdb/include/rpc_client_ext.h new file mode 100644 index 000000000..b58047136 --- /dev/null +++ b/lib_dict/bdb/include/rpc_client_ext.h @@ -0,0 +1,229 @@ +/* DO NOT EDIT: automatically built by dist/s_include. */ +#ifndef _rpc_client_ext_h_ +#define _rpc_client_ext_h_ + +#if defined(__cplusplus) +extern "C" { +#endif + +int __dbcl_envrpcserver __P((DB_ENV *, void *, const char *, long, long, u_int32_t)); +int __dbcl_env_close_wrap __P((DB_ENV *, u_int32_t)); +int __dbcl_env_open_wrap __P((DB_ENV *, const char *, u_int32_t, int)); +int __dbcl_db_open_wrap __P((DB *, DB_TXN *, const char *, const char *, DBTYPE, u_int32_t, int)); +int __dbcl_refresh __P((DB_ENV *)); +int __dbcl_retcopy __P((DB_ENV *, DBT *, void *, u_int32_t, void **, u_int32_t *)); +void __dbcl_txn_end __P((DB_TXN *)); +void __dbcl_txn_setup __P((DB_ENV *, DB_TXN *, DB_TXN *, u_int32_t)); +void __dbcl_c_refresh __P((DBC *)); +int __dbcl_c_setup __P((u_int, DB *, DBC **)); +int __dbcl_dbclose_common __P((DB *)); +int __dbcl_env_alloc __P((DB_ENV *, void *(*)(size_t), void *(*)(void *, size_t), void (*)(void *))); +int __dbcl_set_app_dispatch __P((DB_ENV *, int (*)(DB_ENV *, DBT *, DB_LSN *, db_recops))); +int __dbcl_env_get_cachesize __P((DB_ENV *, u_int32_t *, u_int32_t *, int *)); +int __dbcl_env_cachesize __P((DB_ENV *, u_int32_t, u_int32_t, int)); +int __dbcl_env_close __P((DB_ENV *, u_int32_t)); +int __dbcl_env_create __P((DB_ENV *, long)); +int __dbcl_get_data_dirs __P((DB_ENV *, const char ***)); +int __dbcl_set_data_dir __P((DB_ENV *, const char *)); +int __dbcl_env_dbremove __P((DB_ENV *, DB_TXN *, const char *, const char *, u_int32_t)); +int __dbcl_env_dbrename __P((DB_ENV *, DB_TXN *, const char *, const char *, const char *, u_int32_t)); +int __dbcl_env_get_encrypt_flags __P((DB_ENV *, u_int32_t *)); +int __dbcl_env_encrypt __P((DB_ENV *, const char *, u_int32_t)); +int __dbcl_env_set_feedback __P((DB_ENV *, void (*)(DB_ENV *, int, int))); +int __dbcl_env_get_flags __P((DB_ENV *, u_int32_t *)); +int __dbcl_env_flags __P((DB_ENV *, u_int32_t, int)); +int __dbcl_get_lg_bsize __P((DB_ENV *, u_int32_t *)); +int __dbcl_set_lg_bsize __P((DB_ENV *, u_int32_t)); +int __dbcl_get_lg_dir __P((DB_ENV *, const char * *)); +int __dbcl_set_lg_dir __P((DB_ENV *, const char *)); +int __dbcl_get_lg_max __P((DB_ENV *, u_int32_t *)); +int __dbcl_set_lg_max __P((DB_ENV *, u_int32_t)); +int __dbcl_get_lg_regionmax __P((DB_ENV *, u_int32_t *)); +int __dbcl_set_lg_regionmax __P((DB_ENV *, u_int32_t)); +int __dbcl_get_lk_conflicts __P((DB_ENV *, const u_int8_t **, int *)); +int __dbcl_set_lk_conflict __P((DB_ENV *, u_int8_t *, int)); +int __dbcl_get_lk_detect __P((DB_ENV *, u_int32_t *)); +int __dbcl_set_lk_detect __P((DB_ENV *, u_int32_t)); +int __dbcl_set_lk_max __P((DB_ENV *, u_int32_t)); +int __dbcl_get_lk_max_locks __P((DB_ENV *, u_int32_t *)); +int __dbcl_set_lk_max_locks __P((DB_ENV *, u_int32_t)); +int __dbcl_get_lk_max_lockers __P((DB_ENV *, u_int32_t *)); +int __dbcl_set_lk_max_lockers __P((DB_ENV *, u_int32_t)); +int __dbcl_get_lk_max_objects __P((DB_ENV *, u_int32_t *)); +int __dbcl_set_lk_max_objects __P((DB_ENV *, u_int32_t)); +int __dbcl_get_mp_max_openfd __P((DB_ENV *, int *)); +int __dbcl_set_mp_max_openfd __P((DB_ENV *, int)); +int __dbcl_get_mp_max_write __P((DB_ENV *, int *, int *)); +int __dbcl_set_mp_max_write __P((DB_ENV *, int, int)); +int __dbcl_get_mp_mmapsize __P((DB_ENV *, size_t *)); +int __dbcl_set_mp_mmapsize __P((DB_ENV *, size_t)); +int __dbcl_env_get_home __P((DB_ENV *, const char * *)); +int __dbcl_env_get_open_flags __P((DB_ENV *, u_int32_t *)); +int __dbcl_env_open __P((DB_ENV *, const char *, u_int32_t, int)); +int __dbcl_env_paniccall __P((DB_ENV *, void (*)(DB_ENV *, int))); +int __dbcl_env_remove __P((DB_ENV *, const char *, u_int32_t)); +int __dbcl_get_shm_key __P((DB_ENV *, long *)); +int __dbcl_set_shm_key __P((DB_ENV *, long)); +int __dbcl_get_tas_spins __P((DB_ENV *, u_int32_t *)); +int __dbcl_set_tas_spins __P((DB_ENV *, u_int32_t)); +int __dbcl_get_timeout __P((DB_ENV *, u_int32_t *, u_int32_t)); +int __dbcl_set_timeout __P((DB_ENV *, u_int32_t, u_int32_t)); +int __dbcl_get_tmp_dir __P((DB_ENV *, const char * *)); +int __dbcl_set_tmp_dir __P((DB_ENV *, const char *)); +int __dbcl_get_tx_max __P((DB_ENV *, u_int32_t *)); +int __dbcl_set_tx_max __P((DB_ENV *, u_int32_t)); +int __dbcl_get_tx_timestamp __P((DB_ENV *, time_t *)); +int __dbcl_set_tx_timestamp __P((DB_ENV *, time_t *)); +int __dbcl_get_verbose __P((DB_ENV *, u_int32_t, int *)); +int __dbcl_set_verbose __P((DB_ENV *, u_int32_t, int)); +int __dbcl_txn_abort __P((DB_TXN *)); +int __dbcl_txn_begin __P((DB_ENV *, DB_TXN *, DB_TXN **, u_int32_t)); +int __dbcl_txn_checkpoint __P((DB_ENV *, u_int32_t, u_int32_t, u_int32_t)); +int __dbcl_txn_commit __P((DB_TXN *, u_int32_t)); +int __dbcl_txn_discard __P((DB_TXN *, u_int32_t)); +int __dbcl_txn_prepare __P((DB_TXN *, u_int8_t *)); +int __dbcl_txn_recover __P((DB_ENV *, DB_PREPLIST *, long, long *, u_int32_t)); +int __dbcl_txn_stat __P((DB_ENV *, DB_TXN_STAT **, u_int32_t)); +int __dbcl_txn_timeout __P((DB_TXN *, u_int32_t, u_int32_t)); +int __dbcl_rep_elect __P((DB_ENV *, int, int, int, u_int32_t, int *, u_int32_t)); +int __dbcl_rep_flush __P((DB_ENV *)); +int __dbcl_rep_process_message __P((DB_ENV *, DBT *, DBT *, int *, DB_LSN *)); +int __dbcl_rep_get_limit __P((DB_ENV *, u_int32_t *, u_int32_t *)); +int __dbcl_rep_set_limit __P((DB_ENV *, u_int32_t, u_int32_t)); +int __dbcl_rep_set_request __P((DB_ENV *, u_int32_t, u_int32_t)); +int __dbcl_rep_set_rep_transport __P((DB_ENV *, int, int (*)(DB_ENV *, const DBT *, const DBT *, const DB_LSN *, int, u_int32_t))); +int __dbcl_rep_start __P((DB_ENV *, DBT *, u_int32_t)); +int __dbcl_rep_stat __P((DB_ENV *, DB_REP_STAT **, u_int32_t)); +int __dbcl_db_alloc __P((DB *, void *(*)(size_t), void *(*)(void *, size_t), void (*)(void *))); +int __dbcl_db_associate __P((DB *, DB_TXN *, DB *, int (*)(DB *, const DBT *, const DBT *, DBT *), u_int32_t)); +int __dbcl_db_bt_compare __P((DB *, int (*)(DB *, const DBT *, const DBT *))); +int __dbcl_db_bt_maxkey __P((DB *, u_int32_t)); +int __dbcl_db_get_bt_minkey __P((DB *, u_int32_t *)); +int __dbcl_db_bt_minkey __P((DB *, u_int32_t)); +int __dbcl_db_bt_prefix __P((DB *, size_t(*)(DB *, const DBT *, const DBT *))); +int __dbcl_db_set_append_recno __P((DB *, int (*)(DB *, DBT *, db_recno_t))); +int __dbcl_db_get_cachesize __P((DB *, u_int32_t *, u_int32_t *, int *)); +int __dbcl_db_cachesize __P((DB *, u_int32_t, u_int32_t, int)); +int __dbcl_db_close __P((DB *, u_int32_t)); +int __dbcl_db_create __P((DB *, DB_ENV *, u_int32_t)); +int __dbcl_db_del __P((DB *, DB_TXN *, DBT *, u_int32_t)); +int __dbcl_db_dup_compare __P((DB *, int (*)(DB *, const DBT *, const DBT *))); +int __dbcl_db_get_encrypt_flags __P((DB *, u_int32_t *)); +int __dbcl_db_encrypt __P((DB *, const char *, u_int32_t)); +int __dbcl_db_get_extentsize __P((DB *, u_int32_t *)); +int __dbcl_db_extentsize __P((DB *, u_int32_t)); +int __dbcl_db_fd __P((DB *, int *)); +int __dbcl_db_feedback __P((DB *, void (*)(DB *, int, int))); +int __dbcl_db_get_flags __P((DB *, u_int32_t *)); +int __dbcl_db_flags __P((DB *, u_int32_t)); +int __dbcl_db_get __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t)); +int __dbcl_db_get_name __P((DB *, const char * *, const char * *)); +int __dbcl_db_get_open_flags __P((DB *, u_int32_t *)); +int __dbcl_db_get_h_ffactor __P((DB *, u_int32_t *)); +int __dbcl_db_h_ffactor __P((DB *, u_int32_t)); +int __dbcl_db_h_hash __P((DB *, u_int32_t(*)(DB *, const void *, u_int32_t))); +int __dbcl_db_get_h_nelem __P((DB *, u_int32_t *)); +int __dbcl_db_h_nelem __P((DB *, u_int32_t)); +int __dbcl_db_key_range __P((DB *, DB_TXN *, DBT *, DB_KEY_RANGE *, u_int32_t)); +int __dbcl_db_get_lorder __P((DB *, int *)); +int __dbcl_db_lorder __P((DB *, int)); +int __dbcl_db_open __P((DB *, DB_TXN *, const char *, const char *, DBTYPE, u_int32_t, int)); +int __dbcl_db_get_pagesize __P((DB *, u_int32_t *)); +int __dbcl_db_pagesize __P((DB *, u_int32_t)); +int __dbcl_db_panic __P((DB *, void (*)(DB_ENV *, int))); +int __dbcl_db_pget __P((DB *, DB_TXN *, DBT *, DBT *, DBT *, u_int32_t)); +int __dbcl_db_put __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t)); +int __dbcl_db_get_re_delim __P((DB *, int *)); +int __dbcl_db_re_delim __P((DB *, int)); +int __dbcl_db_get_re_len __P((DB *, u_int32_t *)); +int __dbcl_db_re_len __P((DB *, u_int32_t)); +int __dbcl_db_re_pad __P((DB *, int)); +int __dbcl_db_get_re_pad __P((DB *, int *)); +int __dbcl_db_get_re_source __P((DB *, const char * *)); +int __dbcl_db_re_source __P((DB *, const char *)); +int __dbcl_db_remove __P((DB *, const char *, const char *, u_int32_t)); +int __dbcl_db_rename __P((DB *, const char *, const char *, const char *, u_int32_t)); +int __dbcl_db_stat __P((DB *, DB_TXN *, void *, u_int32_t)); +int __dbcl_db_sync __P((DB *, u_int32_t)); +int __dbcl_db_truncate __P((DB *, DB_TXN *, u_int32_t *, u_int32_t)); +int __dbcl_db_upgrade __P((DB *, const char *, u_int32_t)); +int __dbcl_db_verify __P((DB *, const char *, const char *, FILE *, u_int32_t)); +int __dbcl_db_cursor __P((DB *, DB_TXN *, DBC **, u_int32_t)); +int __dbcl_db_join __P((DB *, DBC **, DBC **, u_int32_t)); +int __dbcl_dbc_close __P((DBC *)); +int __dbcl_dbc_count __P((DBC *, db_recno_t *, u_int32_t)); +int __dbcl_dbc_del __P((DBC *, u_int32_t)); +int __dbcl_dbc_dup __P((DBC *, DBC **, u_int32_t)); +int __dbcl_dbc_get __P((DBC *, DBT *, DBT *, u_int32_t)); +int __dbcl_dbc_pget __P((DBC *, DBT *, DBT *, DBT *, u_int32_t)); +int __dbcl_dbc_put __P((DBC *, DBT *, DBT *, u_int32_t)); +int __dbcl_lock_detect __P((DB_ENV *, u_int32_t, u_int32_t, int *)); +int __dbcl_lock_get __P((DB_ENV *, u_int32_t, u_int32_t, const DBT *, db_lockmode_t, DB_LOCK *)); +int __dbcl_lock_id __P((DB_ENV *, u_int32_t *)); +int __dbcl_lock_id_free __P((DB_ENV *, u_int32_t)); +int __dbcl_lock_put __P((DB_ENV *, DB_LOCK *)); +int __dbcl_lock_stat __P((DB_ENV *, DB_LOCK_STAT **, u_int32_t)); +int __dbcl_lock_vec __P((DB_ENV *, u_int32_t, u_int32_t, DB_LOCKREQ *, int, DB_LOCKREQ **)); +int __dbcl_log_archive __P((DB_ENV *, char ***, u_int32_t)); +int __dbcl_log_cursor __P((DB_ENV *, DB_LOGC **, u_int32_t)); +int __dbcl_log_file __P((DB_ENV *, const DB_LSN *, char *, size_t)); +int __dbcl_log_flush __P((DB_ENV *, const DB_LSN *)); +int __dbcl_log_put __P((DB_ENV *, DB_LSN *, const DBT *, u_int32_t)); +int __dbcl_log_stat __P((DB_ENV *, DB_LOG_STAT **, u_int32_t)); +int __dbcl_memp_register __P((DB_ENV *, int, int (*)(DB_ENV *, db_pgno_t, void *, DBT *), int (*)(DB_ENV *, db_pgno_t, void *, DBT *))); +int __dbcl_memp_stat __P((DB_ENV *, DB_MPOOL_STAT **, DB_MPOOL_FSTAT ***, u_int32_t)); +int __dbcl_memp_sync __P((DB_ENV *, DB_LSN *)); +int __dbcl_memp_trickle __P((DB_ENV *, int, int *)); +int __dbcl_memp_fget __P((DB_MPOOLFILE *, u_int32_t *, u_int32_t, void *)); +int __dbcl_memp_fopen __P((DB_MPOOLFILE *, const char *, u_int32_t, int, size_t)); +int __dbcl_memp_fput __P((DB_MPOOLFILE *, void *, u_int32_t)); +int __dbcl_memp_fset __P((DB_MPOOLFILE *, void *, u_int32_t)); +int __dbcl_memp_get_clear_len __P((DB_MPOOLFILE *, u_int32_t *)); +int __dbcl_memp_set_clear_len __P((DB_MPOOLFILE *, u_int32_t)); +int __dbcl_memp_get_fileid __P((DB_MPOOLFILE *, u_int8_t *)); +int __dbcl_memp_set_fileid __P((DB_MPOOLFILE *, u_int8_t *)); +int __dbcl_memp_get_flags __P((DB_MPOOLFILE *, u_int32_t *)); +int __dbcl_memp_set_flags __P((DB_MPOOLFILE *, u_int32_t, int)); +int __dbcl_memp_get_ftype __P((DB_MPOOLFILE *, int *)); +int __dbcl_memp_set_ftype __P((DB_MPOOLFILE *, int)); +int __dbcl_memp_get_lsn_offset __P((DB_MPOOLFILE *, int32_t *)); +int __dbcl_memp_set_lsn_offset __P((DB_MPOOLFILE *, int32_t)); +int __dbcl_memp_get_maxsize __P((DB_MPOOLFILE *, u_int32_t *, u_int32_t *)); +int __dbcl_memp_set_maxsize __P((DB_MPOOLFILE *, u_int32_t, u_int32_t)); +int __dbcl_memp_get_pgcookie __P((DB_MPOOLFILE *, DBT *)); +int __dbcl_memp_set_pgcookie __P((DB_MPOOLFILE *, DBT *)); +int __dbcl_memp_get_priority __P((DB_MPOOLFILE *, DB_CACHE_PRIORITY *)); +int __dbcl_memp_set_priority __P((DB_MPOOLFILE *, DB_CACHE_PRIORITY)); +int __dbcl_memp_fsync __P((DB_MPOOLFILE *)); +int __dbcl_env_create_ret __P((DB_ENV *, long, __env_create_reply *)); +int __dbcl_env_open_ret __P((DB_ENV *, const char *, u_int32_t, int, __env_open_reply *)); +int __dbcl_env_remove_ret __P((DB_ENV *, const char *, u_int32_t, __env_remove_reply *)); +int __dbcl_txn_abort_ret __P((DB_TXN *, __txn_abort_reply *)); +int __dbcl_txn_begin_ret __P((DB_ENV *, DB_TXN *, DB_TXN **, u_int32_t, __txn_begin_reply *)); +int __dbcl_txn_commit_ret __P((DB_TXN *, u_int32_t, __txn_commit_reply *)); +int __dbcl_txn_discard_ret __P((DB_TXN *, u_int32_t, __txn_discard_reply *)); +int __dbcl_txn_recover_ret __P((DB_ENV *, DB_PREPLIST *, long, long *, u_int32_t, __txn_recover_reply *)); +int __dbcl_db_close_ret __P((DB *, u_int32_t, __db_close_reply *)); +int __dbcl_db_create_ret __P((DB *, DB_ENV *, u_int32_t, __db_create_reply *)); +int __dbcl_db_get_ret __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t, __db_get_reply *)); +int __dbcl_db_key_range_ret __P((DB *, DB_TXN *, DBT *, DB_KEY_RANGE *, u_int32_t, __db_key_range_reply *)); +int __dbcl_db_open_ret __P((DB *, DB_TXN *, const char *, const char *, DBTYPE, u_int32_t, int, __db_open_reply *)); +int __dbcl_db_pget_ret __P((DB *, DB_TXN *, DBT *, DBT *, DBT *, u_int32_t, __db_pget_reply *)); +int __dbcl_db_put_ret __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t, __db_put_reply *)); +int __dbcl_db_remove_ret __P((DB *, const char *, const char *, u_int32_t, __db_remove_reply *)); +int __dbcl_db_rename_ret __P((DB *, const char *, const char *, const char *, u_int32_t, __db_rename_reply *)); +int __dbcl_db_stat_ret __P((DB *, DB_TXN *, void *, u_int32_t, __db_stat_reply *)); +int __dbcl_db_truncate_ret __P((DB *, DB_TXN *, u_int32_t *, u_int32_t, __db_truncate_reply *)); +int __dbcl_db_cursor_ret __P((DB *, DB_TXN *, DBC **, u_int32_t, __db_cursor_reply *)); +int __dbcl_db_join_ret __P((DB *, DBC **, DBC **, u_int32_t, __db_join_reply *)); +int __dbcl_dbc_close_ret __P((DBC *, __dbc_close_reply *)); +int __dbcl_dbc_count_ret __P((DBC *, db_recno_t *, u_int32_t, __dbc_count_reply *)); +int __dbcl_dbc_dup_ret __P((DBC *, DBC **, u_int32_t, __dbc_dup_reply *)); +int __dbcl_dbc_get_ret __P((DBC *, DBT *, DBT *, u_int32_t, __dbc_get_reply *)); +int __dbcl_dbc_pget_ret __P((DBC *, DBT *, DBT *, DBT *, u_int32_t, __dbc_pget_reply *)); +int __dbcl_dbc_put_ret __P((DBC *, DBT *, DBT *, u_int32_t, __dbc_put_reply *)); + +#if defined(__cplusplus) +} +#endif +#endif /* !_rpc_client_ext_h_ */ diff --git a/lib_dict/bdb/include/rpc_server_ext.h b/lib_dict/bdb/include/rpc_server_ext.h new file mode 100644 index 000000000..6d8cbc71f --- /dev/null +++ b/lib_dict/bdb/include/rpc_server_ext.h @@ -0,0 +1,94 @@ +/* DO NOT EDIT: automatically built by dist/s_include. */ +#ifndef _rpc_server_ext_h_ +#define _rpc_server_ext_h_ + +#if defined(__cplusplus) +extern "C" { +#endif + +void __env_get_cachesize_proc __P((long, __env_get_cachesize_reply *)); +void __env_cachesize_proc __P((long, u_int32_t, u_int32_t, u_int32_t, __env_cachesize_reply *)); +void __env_close_proc __P((long, u_int32_t, __env_close_reply *)); +void __env_create_proc __P((u_int32_t, __env_create_reply *)); +void __env_dbremove_proc __P((long, long, char *, char *, u_int32_t, __env_dbremove_reply *)); +void __env_dbrename_proc __P((long, long, char *, char *, char *, u_int32_t, __env_dbrename_reply *)); +void __env_get_encrypt_flags_proc __P((long, __env_get_encrypt_flags_reply *)); +void __env_encrypt_proc __P((long, char *, u_int32_t, __env_encrypt_reply *)); +void __env_get_flags_proc __P((long, __env_get_flags_reply *)); +void __env_flags_proc __P((long, u_int32_t, u_int32_t, __env_flags_reply *)); +void __env_get_home_proc __P((long, __env_get_home_reply *)); +void __env_get_open_flags_proc __P((long, __env_get_open_flags_reply *)); +void __env_open_proc __P((long, char *, u_int32_t, u_int32_t, __env_open_reply *)); +void __env_remove_proc __P((long, char *, u_int32_t, __env_remove_reply *)); +void __txn_abort_proc __P((long, __txn_abort_reply *)); +void __txn_begin_proc __P((long, long, u_int32_t, __txn_begin_reply *)); +void __txn_commit_proc __P((long, u_int32_t, __txn_commit_reply *)); +void __txn_discard_proc __P((long, u_int32_t, __txn_discard_reply *)); +void __txn_prepare_proc __P((long, u_int8_t *, __txn_prepare_reply *)); +void __txn_recover_proc __P((long, u_int32_t, u_int32_t, __txn_recover_reply *, int *)); +void __db_bt_maxkey_proc __P((long, u_int32_t, __db_bt_maxkey_reply *)); +void __db_associate_proc __P((long, long, long, u_int32_t, __db_associate_reply *)); +void __db_get_bt_minkey_proc __P((long, __db_get_bt_minkey_reply *)); +void __db_bt_minkey_proc __P((long, u_int32_t, __db_bt_minkey_reply *)); +void __db_close_proc __P((long, u_int32_t, __db_close_reply *)); +void __db_create_proc __P((long, u_int32_t, __db_create_reply *)); +void __db_del_proc __P((long, long, u_int32_t, u_int32_t, u_int32_t, u_int32_t, void *, u_int32_t, u_int32_t, __db_del_reply *)); +void __db_get_encrypt_flags_proc __P((long, __db_get_encrypt_flags_reply *)); +void __db_encrypt_proc __P((long, char *, u_int32_t, __db_encrypt_reply *)); +void __db_get_extentsize_proc __P((long, __db_get_extentsize_reply *)); +void __db_extentsize_proc __P((long, u_int32_t, __db_extentsize_reply *)); +void __db_get_flags_proc __P((long, __db_get_flags_reply *)); +void __db_flags_proc __P((long, u_int32_t, __db_flags_reply *)); +void __db_get_proc __P((long, long, u_int32_t, u_int32_t, u_int32_t, u_int32_t, void *, u_int32_t, u_int32_t, u_int32_t, u_int32_t, u_int32_t, void *, u_int32_t, u_int32_t, __db_get_reply *, int *)); +void __db_get_h_ffactor_proc __P((long, __db_get_h_ffactor_reply *)); +void __db_h_ffactor_proc __P((long, u_int32_t, __db_h_ffactor_reply *)); +void __db_get_h_nelem_proc __P((long, __db_get_h_nelem_reply *)); +void __db_h_nelem_proc __P((long, u_int32_t, __db_h_nelem_reply *)); +void __db_key_range_proc __P((long, long, u_int32_t, u_int32_t, u_int32_t, u_int32_t, void *, u_int32_t, u_int32_t, __db_key_range_reply *)); +void __db_get_lorder_proc __P((long, __db_get_lorder_reply *)); +void __db_lorder_proc __P((long, u_int32_t, __db_lorder_reply *)); +void __db_get_name_proc __P((long, __db_get_name_reply *)); +void __db_get_open_flags_proc __P((long, __db_get_open_flags_reply *)); +void __db_open_proc __P((long, long, char *, char *, u_int32_t, u_int32_t, u_int32_t, __db_open_reply *)); +void __db_get_pagesize_proc __P((long, __db_get_pagesize_reply *)); +void __db_pagesize_proc __P((long, u_int32_t, __db_pagesize_reply *)); +void __db_pget_proc __P((long, long, u_int32_t, u_int32_t, u_int32_t, u_int32_t, void *, u_int32_t, u_int32_t, u_int32_t, u_int32_t, u_int32_t, void *, u_int32_t, u_int32_t, u_int32_t, u_int32_t, u_int32_t, void *, u_int32_t, u_int32_t, __db_pget_reply *, int *)); +void __db_put_proc __P((long, long, u_int32_t, u_int32_t, u_int32_t, u_int32_t, void *, u_int32_t, u_int32_t, u_int32_t, u_int32_t, u_int32_t, void *, u_int32_t, u_int32_t, __db_put_reply *, int *)); +void __db_get_re_delim_proc __P((long, __db_get_re_delim_reply *)); +void __db_re_delim_proc __P((long, u_int32_t, __db_re_delim_reply *)); +void __db_get_re_len_proc __P((long, __db_get_re_len_reply *)); +void __db_re_len_proc __P((long, u_int32_t, __db_re_len_reply *)); +void __db_get_re_pad_proc __P((long, __db_get_re_pad_reply *)); +void __db_re_pad_proc __P((long, u_int32_t, __db_re_pad_reply *)); +void __db_remove_proc __P((long, char *, char *, u_int32_t, __db_remove_reply *)); +void __db_rename_proc __P((long, char *, char *, char *, u_int32_t, __db_rename_reply *)); +void __db_stat_proc __P((long, long, u_int32_t, __db_stat_reply *, int *)); +void __db_sync_proc __P((long, u_int32_t, __db_sync_reply *)); +void __db_truncate_proc __P((long, long, u_int32_t, __db_truncate_reply *)); +void __db_cursor_proc __P((long, long, u_int32_t, __db_cursor_reply *)); +void __db_join_proc __P((long, u_int32_t *, u_int32_t, u_int32_t, __db_join_reply *)); +void __dbc_close_proc __P((long, __dbc_close_reply *)); +void __dbc_count_proc __P((long, u_int32_t, __dbc_count_reply *)); +void __dbc_del_proc __P((long, u_int32_t, __dbc_del_reply *)); +void __dbc_dup_proc __P((long, u_int32_t, __dbc_dup_reply *)); +void __dbc_get_proc __P((long, u_int32_t, u_int32_t, u_int32_t, u_int32_t, void *, u_int32_t, u_int32_t, u_int32_t, u_int32_t, u_int32_t, void *, u_int32_t, u_int32_t, __dbc_get_reply *, int *)); +void __dbc_pget_proc __P((long, u_int32_t, u_int32_t, u_int32_t, u_int32_t, void *, u_int32_t, u_int32_t, u_int32_t, u_int32_t, u_int32_t, void *, u_int32_t, u_int32_t, u_int32_t, u_int32_t, u_int32_t, void *, u_int32_t, u_int32_t, __dbc_pget_reply *, int *)); +void __dbc_put_proc __P((long, u_int32_t, u_int32_t, u_int32_t, u_int32_t, void *, u_int32_t, u_int32_t, u_int32_t, u_int32_t, u_int32_t, void *, u_int32_t, u_int32_t, __dbc_put_reply *, int *)); +void __dbsrv_settimeout __P((ct_entry *, u_int32_t)); +void __dbsrv_timeout __P((int)); +void __dbclear_ctp __P((ct_entry *)); +void __dbdel_ctp __P((ct_entry *)); +ct_entry *new_ct_ent __P((int *)); +ct_entry *get_tableent __P((long)); +ct_entry *__dbsrv_sharedb __P((ct_entry *, const char *, const char *, DBTYPE, u_int32_t)); +ct_entry *__dbsrv_shareenv __P((ct_entry *, home_entry *, u_int32_t)); +void __dbsrv_active __P((ct_entry *)); +int __db_close_int __P((long, u_int32_t)); +int __dbc_close_int __P((ct_entry *)); +int __dbenv_close_int __P((long, u_int32_t, int)); +home_entry *get_fullhome __P((char *)); + +#if defined(__cplusplus) +} +#endif +#endif /* !_rpc_server_ext_h_ */ diff --git a/lib_dict/bdb/include/sequence_ext.h b/lib_dict/bdb/include/sequence_ext.h new file mode 100644 index 000000000..a2c114cf3 --- /dev/null +++ b/lib_dict/bdb/include/sequence_ext.h @@ -0,0 +1,17 @@ +/* DO NOT EDIT: automatically built by dist/s_include. */ +#ifndef _sequence_ext_h_ +#define _sequence_ext_h_ + +#if defined(__cplusplus) +extern "C" { +#endif + +int __seq_stat __P((DB_SEQUENCE *, DB_SEQUENCE_STAT **, u_int32_t)); +int __seq_stat_print __P((DB_SEQUENCE *, u_int32_t)); +const FN * __db_get_seq_flags_fn __P((void)); +const FN * __db_get_seq_flags_fn __P((void)); + +#if defined(__cplusplus) +} +#endif +#endif /* !_sequence_ext_h_ */ diff --git a/lib_dict/bdb/include/shqueue.h b/lib_dict/bdb/include/shqueue.h new file mode 100644 index 000000000..8d7e4eef9 --- /dev/null +++ b/lib_dict/bdb/include/shqueue.h @@ -0,0 +1,345 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996-2004 + * Sleepycat Software. All rights reserved. + * + * $Id: shqueue.h,v 11.15 2004/03/24 20:37:37 bostic Exp $ + */ + +#ifndef _SYS_SHQUEUE_H_ +#define _SYS_SHQUEUE_H_ + +/* + * This file defines two types of data structures: lists and tail queues + * similarly to the include file . + * + * The difference is that this set of macros can be used for structures that + * reside in shared memory that may be mapped at different addresses in each + * process. In most cases, the macros for shared structures exactly mirror + * the normal macros, although the macro calls require an additional type + * parameter, only used by the HEAD and ENTRY macros of the standard macros. + * + * Since we use relative offsets of type ssize_t rather than pointers, 0 + * (aka NULL) is a valid offset and cannot be used to indicate the end + * of a list. Therefore, we use -1 to indicate end of list. + * + * The macros ending in "P" return pointers without checking for end or + * beginning of lists, the others check for end of list and evaluate to + * either a pointer or NULL. + * + * For details on the use of these macros, see the queue(3) manual page. + */ + +#if defined(__cplusplus) +extern "C" { +#endif + +/* + * Shared memory list definitions. + */ +#define SH_LIST_HEAD(name) \ +struct name { \ + ssize_t slh_first; /* first element */ \ +} + +#define SH_LIST_HEAD_INITIALIZER(head) \ + { -1 } + +#define SH_LIST_ENTRY \ +struct { \ + ssize_t sle_next; /* relative offset to next element */ \ + ssize_t sle_prev; /* relative offset of prev element */ \ +} + +/* + * Shared memory list functions. + */ + +#define SH_LIST_EMPTY(head) \ + ((head)->slh_first == -1) + +#define SH_LIST_FIRSTP(head, type) \ + ((struct type *)(((u_int8_t *)(head)) + (head)->slh_first)) + +#define SH_LIST_FIRST(head, type) \ + (SH_LIST_EMPTY(head) ? NULL : \ + ((struct type *)(((u_int8_t *)(head)) + (head)->slh_first))) + +#define SH_LIST_NEXTP(elm, field, type) \ + ((struct type *)(((u_int8_t *)(elm)) + (elm)->field.sle_next)) + +#define SH_LIST_NEXT(elm, field, type) \ + ((elm)->field.sle_next == -1 ? NULL : \ + ((struct type *)(((u_int8_t *)(elm)) + (elm)->field.sle_next))) + + /* + *__SH_LIST_PREV_OFF is private API. It calculates the address of + * the elm->field.sle_next member of a SH_LIST structure. All offsets + * between elements are relative to that point in SH_LIST structures. + */ +#define __SH_LIST_PREV_OFF(elm, field) \ + ((ssize_t *)(((u_int8_t *)(elm)) + (elm)->field.sle_prev)) + +#define SH_LIST_PREV(elm, field, type) \ + (struct type *)((ssize_t)elm - (*__SH_LIST_PREV_OFF(elm, field))) + +#define SH_LIST_FOREACH(var, head, field, type) \ + for ((var) = SH_LIST_FIRST((head), type); \ + (var); \ + (var) = SH_LIST_NEXT((var), field, type)) + +#define SH_PTR_TO_OFF(src, dest) \ + ((ssize_t)(((u_int8_t *)(dest)) - ((u_int8_t *)(src)))) + +/* + * Given correct A.next: B.prev = SH_LIST_NEXT_TO_PREV(A) + * in a list [A, B] + * The prev value is always the offset from an element to its preceding + * element's next location, not the beginning of the structure. To get + * to the beginning of an element structure in memory given an element + * do the following: + * A = B - (B.prev + (&B.next - B)) + * Take the element's next pointer and calculate what the corresponding + * Prev pointer should be -- basically it is the negation plus the offset + * of the next field in the structure. + */ +#define SH_LIST_NEXT_TO_PREV(elm, field) \ + (((elm)->field.sle_next == -1 ? 0 : -(elm)->field.sle_next) + \ + SH_PTR_TO_OFF(elm, &(elm)->field.sle_next)) + +#define SH_LIST_INIT(head) (head)->slh_first = -1 + +#define SH_LIST_INSERT_BEFORE(head, listelm, elm, field, type) do { \ + if (listelm == SH_LIST_FIRST(head, type)) { \ + SH_LIST_INSERT_HEAD(head, elm, field, type); \ + } else { \ + (elm)->field.sle_next = SH_PTR_TO_OFF(elm, listelm); \ + (elm)->field.sle_prev = SH_LIST_NEXT_TO_PREV( \ + SH_LIST_PREV((listelm), field, type), field) + \ + (elm)->field.sle_next; \ + (SH_LIST_PREV(listelm, field, type))->field.sle_next = \ + (SH_PTR_TO_OFF((SH_LIST_PREV(listelm, field, \ + type)), elm)); \ + (listelm)->field.sle_prev = SH_LIST_NEXT_TO_PREV(elm, field); \ + } \ +} while (0) + +#define SH_LIST_INSERT_AFTER(listelm, elm, field, type) do { \ + if ((listelm)->field.sle_next != -1) { \ + (elm)->field.sle_next = SH_PTR_TO_OFF(elm, \ + SH_LIST_NEXTP(listelm, field, type)); \ + SH_LIST_NEXTP(listelm, field, type)->field.sle_prev = \ + SH_LIST_NEXT_TO_PREV(elm, field); \ + } else \ + (elm)->field.sle_next = -1; \ + (listelm)->field.sle_next = SH_PTR_TO_OFF(listelm, elm); \ + (elm)->field.sle_prev = SH_LIST_NEXT_TO_PREV(listelm, field); \ +} while (0) + +#define SH_LIST_INSERT_HEAD(head, elm, field, type) do { \ + if ((head)->slh_first != -1) { \ + (elm)->field.sle_next = \ + (head)->slh_first - SH_PTR_TO_OFF(head, elm); \ + SH_LIST_FIRSTP(head, type)->field.sle_prev = \ + SH_LIST_NEXT_TO_PREV(elm, field); \ + } else \ + (elm)->field.sle_next = -1; \ + (head)->slh_first = SH_PTR_TO_OFF(head, elm); \ + (elm)->field.sle_prev = SH_PTR_TO_OFF(elm, &(head)->slh_first); \ +} while (0) + +#define SH_LIST_REMOVE(elm, field, type) do { \ + if ((elm)->field.sle_next != -1) { \ + SH_LIST_NEXTP(elm, field, type)->field.sle_prev = \ + (elm)->field.sle_prev - (elm)->field.sle_next; \ + *__SH_LIST_PREV_OFF(elm, field) += (elm)->field.sle_next;\ + } else \ + *__SH_LIST_PREV_OFF(elm, field) = -1; \ +} while (0) + +#define SH_LIST_REMOVE_HEAD(head, field, type) do { \ + if (!SH_LIST_EMPTY(head)) { \ + SH_LIST_REMOVE(SH_LIST_FIRSTP(head, type), field, type);\ + } \ +} while (0) + +/* + * Shared memory tail queue definitions. + */ +#define SH_TAILQ_HEAD(name) \ +struct name { \ + ssize_t stqh_first; /* relative offset of first element */ \ + ssize_t stqh_last; /* relative offset of last's next */ \ +} + +#define SH_TAILQ_HEAD_INITIALIZER(head) \ + { -1, 0 } + +#define SH_TAILQ_ENTRY \ +struct { \ + ssize_t stqe_next; /* relative offset of next element */ \ + ssize_t stqe_prev; /* relative offset of prev's next */ \ +} + +/* + * Shared memory tail queue functions. + */ + +#define SH_TAILQ_EMPTY(head) \ + ((head)->stqh_first == -1) + +#define SH_TAILQ_FIRSTP(head, type) \ + ((struct type *)((u_int8_t *)(head) + (head)->stqh_first)) + +#define SH_TAILQ_FIRST(head, type) \ + (SH_TAILQ_EMPTY(head) ? NULL : SH_TAILQ_FIRSTP(head, type)) + +#define SH_TAILQ_NEXTP(elm, field, type) \ + ((struct type *)((u_int8_t *)(elm) + (elm)->field.stqe_next)) + +#define SH_TAILQ_NEXT(elm, field, type) \ + ((elm)->field.stqe_next == -1 ? NULL : \ + ((struct type *)((u_int8_t *)(elm) + (elm)->field.stqe_next))) + + /* + * __SH_TAILQ_PREV_OFF is private API. It calculates the address of + * the elm->field.stqe_next member of a SH_TAILQ structure. All + * offsets between elements are relative to that point in SH_TAILQ + * structures. + */ +#define __SH_TAILQ_PREV_OFF(elm, field) \ + ((ssize_t *)(((u_int8_t *)(elm)) + (elm)->field.stqe_prev)) + +#define SH_TAILQ_PREVP(elm, field, type) \ + (struct type *)((ssize_t)elm - (*__SH_TAILQ_PREV_OFF(elm, field))) + +#define SH_TAILQ_PREV(head, elm, field, type) \ + (((elm) == SH_TAILQ_FIRST(head, type)) ? NULL : \ + (struct type *)((ssize_t)elm - (*__SH_TAILQ_PREV_OFF(elm, field)))) + + /* + * __SH_TAILQ_LAST_OFF is private API. It calculates the address of + * the stqe_next member of a SH_TAILQ structure in the last element + * of this list. All offsets between elements are relative to that + * point in SH_TAILQ structures. + */ +#define __SH_TAILQ_LAST_OFF(head) \ + ((ssize_t *)(((u_int8_t *)(head)) + (head)->stqh_last)) + +#define SH_TAILQ_LAST(head, field, type) \ + (SH_TAILQ_EMPTY(head) ? NULL : \ + (struct type *)((ssize_t)(head) + \ + ((ssize_t)((head)->stqh_last) - \ + ((ssize_t)SH_PTR_TO_OFF(SH_TAILQ_FIRST(head, type), \ + &(SH_TAILQ_FIRST(head, type)->field.stqe_next)))))) + +/* + * Given correct A.next: B.prev = SH_TAILQ_NEXT_TO_PREV(A) + * in a list [A, B] + * The prev value is always the offset from an element to its preceding + * element's next location, not the beginning of the structure. To get + * to the beginning of an element structure in memory given an element + * do the following: + * A = B - (B.prev + (&B.next - B)) + */ +#define SH_TAILQ_NEXT_TO_PREV(elm, field) \ + (((elm)->field.stqe_next == -1 ? 0 : \ + (-(elm)->field.stqe_next) + \ + SH_PTR_TO_OFF(elm, &(elm)->field.stqe_next))) + +#define SH_TAILQ_FOREACH(var, head, field, type) \ + for ((var) = SH_TAILQ_FIRST((head), type); \ + (var); \ + (var) = SH_TAILQ_NEXT((var), field, type)) + +#define SH_TAILQ_FOREACH_REVERSE(var, head, field, type) \ + for ((var) = SH_TAILQ_LAST((head), field, type); \ + (var); \ + (var) = SH_TAILQ_PREV((head), (var), field, type)) + +#define SH_TAILQ_INIT(head) { \ + (head)->stqh_first = -1; \ + (head)->stqh_last = SH_PTR_TO_OFF(head, &(head)->stqh_first); \ +} + +#define SH_TAILQ_INSERT_HEAD(head, elm, field, type) do { \ + if ((head)->stqh_first != -1) { \ + (elm)->field.stqe_next = \ + (head)->stqh_first - SH_PTR_TO_OFF(head, elm); \ + SH_TAILQ_FIRSTP(head, type)->field.stqe_prev = \ + SH_TAILQ_NEXT_TO_PREV(elm, field); \ + } else { \ + (head)->stqh_last = \ + SH_PTR_TO_OFF(head, &(elm)->field.stqe_next); \ + (elm)->field.stqe_next = -1; \ + } \ + (head)->stqh_first = SH_PTR_TO_OFF(head, elm); \ + (elm)->field.stqe_prev = \ + SH_PTR_TO_OFF(elm, &(head)->stqh_first); \ +} while (0) + +#define SH_TAILQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.stqe_next = -1; \ + (elm)->field.stqe_prev = \ + -SH_PTR_TO_OFF(head, elm) + (head)->stqh_last; \ + if ((head)->stqh_last == \ + SH_PTR_TO_OFF((head), &(head)->stqh_first)) \ + (head)->stqh_first = SH_PTR_TO_OFF(head, elm); \ + else \ + *__SH_TAILQ_LAST_OFF(head) = -(head)->stqh_last + \ + SH_PTR_TO_OFF((elm), &(elm)->field.stqe_next) + \ + SH_PTR_TO_OFF(head, elm); \ + (head)->stqh_last = \ + SH_PTR_TO_OFF(head, &((elm)->field.stqe_next)); \ +} while (0) + +#define SH_TAILQ_INSERT_BEFORE(head, listelm, elm, field, type) do { \ + if (listelm == SH_TAILQ_FIRST(head, type)) { \ + SH_TAILQ_INSERT_HEAD(head, elm, field, type); \ + } else { \ + (elm)->field.stqe_next = SH_PTR_TO_OFF(elm, listelm); \ + (elm)->field.stqe_prev = SH_TAILQ_NEXT_TO_PREV( \ + SH_TAILQ_PREVP((listelm), field, type), field) + \ + (elm)->field.stqe_next; \ + (SH_TAILQ_PREVP(listelm, field, type))->field.stqe_next =\ + (SH_PTR_TO_OFF((SH_TAILQ_PREVP(listelm, field, type)), \ + elm)); \ + (listelm)->field.stqe_prev = \ + SH_TAILQ_NEXT_TO_PREV(elm, field); \ + } \ +} while (0) + +#define SH_TAILQ_INSERT_AFTER(head, listelm, elm, field, type) do { \ + if ((listelm)->field.stqe_next != -1) { \ + (elm)->field.stqe_next = (listelm)->field.stqe_next - \ + SH_PTR_TO_OFF(listelm, elm); \ + SH_TAILQ_NEXTP(listelm, field, type)->field.stqe_prev = \ + SH_TAILQ_NEXT_TO_PREV(elm, field); \ + } else { \ + (elm)->field.stqe_next = -1; \ + (head)->stqh_last = \ + SH_PTR_TO_OFF(head, &elm->field.stqe_next); \ + } \ + (listelm)->field.stqe_next = SH_PTR_TO_OFF(listelm, elm); \ + (elm)->field.stqe_prev = SH_TAILQ_NEXT_TO_PREV(listelm, field); \ +} while (0) + +#define SH_TAILQ_REMOVE(head, elm, field, type) do { \ + if ((elm)->field.stqe_next != -1) { \ + SH_TAILQ_NEXTP(elm, field, type)->field.stqe_prev = \ + (elm)->field.stqe_prev + \ + SH_PTR_TO_OFF(SH_TAILQ_NEXTP(elm, \ + field, type), elm); \ + *__SH_TAILQ_PREV_OFF(elm, field) += elm->field.stqe_next;\ + } else { \ + (head)->stqh_last = (elm)->field.stqe_prev + \ + SH_PTR_TO_OFF(head, elm); \ + *__SH_TAILQ_PREV_OFF(elm, field) = -1; \ + } \ +} while (0) + +#if defined(__cplusplus) +} +#endif +#endif /* !_SYS_SHQUEUE_H_ */ diff --git a/lib_dict/bdb/include/tcl_db.h b/lib_dict/bdb/include/tcl_db.h new file mode 100644 index 000000000..f1adea5ae --- /dev/null +++ b/lib_dict/bdb/include/tcl_db.h @@ -0,0 +1,270 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1999-2004 + * Sleepycat Software. All rights reserved. + * + * $Id: tcl_db.h,v 11.40 2004/09/22 03:40:20 bostic Exp $ + */ + +#ifndef _DB_TCL_DB_H_ +#define _DB_TCL_DB_H_ + +#define MSG_SIZE 100 /* Message size */ + +enum INFOTYPE { + I_ENV, I_DB, I_DBC, I_TXN, I_MP, + I_PG, I_LOCK, I_LOGC, I_NDBM, I_MUTEX, I_SEQ}; + +#define MAX_ID 8 /* Maximum number of sub-id's we need */ +#define DBTCL_PREP 64 /* Size of txn_recover preplist */ + +#define DBTCL_DBM 1 +#define DBTCL_NDBM 2 + +typedef struct _mutex_entry { + union { + struct { + DB_MUTEX real_m; + int real_val; + } r; + /* + * This is here to make sure that each of the mutex structures + * are 16-byte aligned, which is required on HP architectures. + * The db_mutex_t structure might be >32 bytes itself, or the + * real_val might push it over the 32 byte boundary. The best + * we can do is use a 48 byte boundary. + */ + char c[48]; + } u; +} _MUTEX_ENTRY; + +#define m u.r.real_m +#define val u.r.real_val + +typedef struct _mutex_data { + DB_ENV *env; + REGINFO reginfo; + _MUTEX_ENTRY *marray; + size_t size; +} _MUTEX_DATA; + +/* + * Why use a home grown package over the Tcl_Hash functions? + * + * We could have implemented the stuff below without maintaining our + * own list manipulation, efficiently hashing it with the available + * Tcl functions (Tcl_CreateHashEntry, Tcl_GetHashValue, etc). I chose + * not to do so for these reasons: + * + * We still need the information below. Using the hashing only removes + * us from needing the next/prev pointers. We still need the structure + * itself because we need more than one value associated with a widget. + * We need to keep track of parent pointers for sub-widgets (like cursors) + * so we can correctly close. We need to keep track of individual widget's + * id counters for any sub-widgets they may have. We need to be able to + * associate the name/client data outside the scope of the widget. + * + * So, is it better to use the hashing rather than + * the linear list we have now? I decided against it for the simple reason + * that to access the structure would require two calls. The first is + * Tcl_FindHashEntry(table, key) and then, once we have the entry, we'd + * have to do Tcl_GetHashValue(entry) to get the pointer of the structure. + * + * I believe the number of simultaneous DB widgets in existence at one time + * is not going to be that large (more than several dozen) such that + * linearly searching the list is not going to impact performance in a + * noticeable way. Should performance be impacted due to the size of the + * info list, then perhaps it is time to revisit this decision. + */ +typedef struct dbtcl_info { + LIST_ENTRY(dbtcl_info) entries; + Tcl_Interp *i_interp; + char *i_name; + enum INFOTYPE i_type; + union infop { + DB_ENV *envp; + void *anyp; + DB *dbp; + DBC *dbcp; + DB_TXN *txnp; + DB_MPOOLFILE *mp; + DB_LOCK *lock; + _MUTEX_DATA *mutex; + DB_LOGC *logc; + } un; + union data { + int anydata; + db_pgno_t pgno; + u_int32_t lockid; + } und; + union data2 { + int anydata; + int pagesz; + } und2; + DBT i_lockobj; + FILE *i_err; + char *i_errpfx; + + /* Callbacks--Tcl_Objs containing proc names */ + Tcl_Obj *i_btcompare; + Tcl_Obj *i_dupcompare; + Tcl_Obj *i_hashproc; + Tcl_Obj *i_rep_send; + Tcl_Obj *i_second_call; + + /* Environment ID for the i_rep_send callback. */ + Tcl_Obj *i_rep_eid; + + struct dbtcl_info *i_parent; + int i_otherid[MAX_ID]; +} DBTCL_INFO; + +#define i_anyp un.anyp +#define i_pagep un.anyp +#define i_envp un.envp +#define i_dbp un.dbp +#define i_dbcp un.dbcp +#define i_txnp un.txnp +#define i_mp un.mp +#define i_lock un.lock +#define i_mutex un.mutex +#define i_logc un.logc + +#define i_data und.anydata +#define i_pgno und.pgno +#define i_locker und.lockid +#define i_data2 und2.anydata +#define i_pgsz und2.pagesz + +#define i_envtxnid i_otherid[0] +#define i_envmpid i_otherid[1] +#define i_envlockid i_otherid[2] +#define i_envmutexid i_otherid[3] +#define i_envlogcid i_otherid[4] + +#define i_mppgid i_otherid[0] + +#define i_dbdbcid i_otherid[0] + +extern int __debug_on, __debug_print, __debug_stop, __debug_test; + +typedef struct dbtcl_global { + LIST_HEAD(infohead, dbtcl_info) g_infohead; +} DBTCL_GLOBAL; +#define __db_infohead __dbtcl_global.g_infohead + +extern DBTCL_GLOBAL __dbtcl_global; + +/* + * Tcl_NewStringObj takes an "int" length argument, when the typical use is to + * call it with a size_t length (for example, returned by strlen). Tcl is in + * the wrong, but that doesn't help us much -- cast the argument. + */ +#define NewStringObj(a, b) \ + Tcl_NewStringObj(a, (int)b) + +#define NAME_TO_DB(name) (DB *)_NameToPtr((name)) +#define NAME_TO_DBC(name) (DBC *)_NameToPtr((name)) +#define NAME_TO_ENV(name) (DB_ENV *)_NameToPtr((name)) +#define NAME_TO_LOCK(name) (DB_LOCK *)_NameToPtr((name)) +#define NAME_TO_MP(name) (DB_MPOOLFILE *)_NameToPtr((name)) +#define NAME_TO_TXN(name) (DB_TXN *)_NameToPtr((name)) +#define NAME_TO_SEQUENCE(name) (DB_SEQUENCE *)_NameToPtr((name)) + +/* + * MAKE_STAT_LIST appends a {name value} pair to a result list that MUST be + * called 'res' that is a Tcl_Obj * in the local function. This macro also + * assumes a label "error" to go to in the event of a Tcl error. For stat + * functions this will typically go before the "free" function to free the + * stat structure returned by DB. + */ +#define MAKE_STAT_LIST(s, v) do { \ + result = _SetListElemInt(interp, res, (s), (long)(v)); \ + if (result != TCL_OK) \ + goto error; \ +} while (0) + +#define MAKE_WSTAT_LIST(s, v) do { \ + result = _SetListElemWideInt(interp, res, (s), (int64_t)(v)); \ + if (result != TCL_OK) \ + goto error; \ +} while (0) + +/* + * MAKE_STAT_LSN appends a {name {LSNfile LSNoffset}} pair to a result list + * that MUST be called 'res' that is a Tcl_Obj * in the local + * function. This macro also assumes a label "error" to go to + * in the even of a Tcl error. For stat functions this will + * typically go before the "free" function to free the stat structure + * returned by DB. + */ +#define MAKE_STAT_LSN(s, lsn) do { \ + myobjc = 2; \ + myobjv[0] = Tcl_NewLongObj((long)(lsn)->file); \ + myobjv[1] = Tcl_NewLongObj((long)(lsn)->offset); \ + lsnlist = Tcl_NewListObj(myobjc, myobjv); \ + myobjc = 2; \ + myobjv[0] = Tcl_NewStringObj((s), (int)strlen(s)); \ + myobjv[1] = lsnlist; \ + thislist = Tcl_NewListObj(myobjc, myobjv); \ + result = Tcl_ListObjAppendElement(interp, res, thislist); \ + if (result != TCL_OK) \ + goto error; \ +} while (0) + +/* + * MAKE_STAT_STRLIST appends a {name string} pair to a result list + * that MUST be called 'res' that is a Tcl_Obj * in the local + * function. This macro also assumes a label "error" to go to + * in the even of a Tcl error. For stat functions this will + * typically go before the "free" function to free the stat structure + * returned by DB. + */ +#define MAKE_STAT_STRLIST(s,s1) do { \ + result = _SetListElem(interp, res, (s), strlen(s), \ + (s1), strlen(s1)); \ + if (result != TCL_OK) \ + goto error; \ +} while (0) + +/* + * FLAG_CHECK checks that the given flag is not set yet. + * If it is, it sets up an error message. + */ +#define FLAG_CHECK(flag) do { \ + if ((flag) != 0) { \ + Tcl_SetResult(interp, \ + " Only 1 policy can be specified.\n", \ + TCL_STATIC); \ + result = TCL_ERROR; \ + break; \ + } \ +} while (0) + +/* + * FLAG_CHECK2 checks that the given flag is not set yet or is + * only set to the given allowed value. + * If it is, it sets up an error message. + */ +#define FLAG_CHECK2(flag, val) do { \ + if (((flag) & ~(val)) != 0) { \ + Tcl_SetResult(interp, \ + " Only 1 policy can be specified.\n", \ + TCL_STATIC); \ + result = TCL_ERROR; \ + break; \ + } \ +} while (0) + +/* + * IS_HELP checks whether the arg we bombed on is -?, which is a help option. + * If it is, we return TCL_OK (but leave the result set to whatever + * Tcl_GetIndexFromObj says, which lists all the valid options. Otherwise + * return TCL_ERROR. + */ +#define IS_HELP(s) \ + (strcmp(Tcl_GetStringFromObj(s,NULL), "-?") == 0) ? TCL_OK : TCL_ERROR + +#include "dbinc_auto/tcl_ext.h" +#endif /* !_DB_TCL_DB_H_ */ diff --git a/lib_dict/bdb/include/tcl_ext.h b/lib_dict/bdb/include/tcl_ext.h new file mode 100644 index 000000000..d147bd4f8 --- /dev/null +++ b/lib_dict/bdb/include/tcl_ext.h @@ -0,0 +1,88 @@ +/* DO NOT EDIT: automatically built by dist/s_include. */ +#ifndef _tcl_ext_h_ +#define _tcl_ext_h_ + +#if defined(__cplusplus) +extern "C" { +#endif + +int bdb_HCommand __P((Tcl_Interp *, int, Tcl_Obj * CONST*)); +#if DB_DBM_HSEARCH != 0 +int bdb_NdbmOpen __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DBM **)); +#endif +#if DB_DBM_HSEARCH != 0 +int bdb_DbmCommand __P((Tcl_Interp *, int, Tcl_Obj * CONST*, int, DBM *)); +#endif +int ndbm_Cmd __P((ClientData, Tcl_Interp *, int, Tcl_Obj * CONST*)); +void _DbInfoDelete __P((Tcl_Interp *, DBTCL_INFO *)); +int db_Cmd __P((ClientData, Tcl_Interp *, int, Tcl_Obj * CONST*)); +int dbc_Cmd __P((ClientData, Tcl_Interp *, int, Tcl_Obj * CONST*)); +int env_Cmd __P((ClientData, Tcl_Interp *, int, Tcl_Obj * CONST*)); +int tcl_EnvRemove __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_ENV *, DBTCL_INFO *)); +int tcl_EnvVerbose __P((Tcl_Interp *, DB_ENV *, Tcl_Obj *, Tcl_Obj *)); +int tcl_EnvAttr __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_ENV *)); +int tcl_EnvSetFlags __P((Tcl_Interp *, DB_ENV *, Tcl_Obj *, Tcl_Obj *)); +int tcl_EnvTest __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_ENV *)); +int tcl_EnvGetEncryptFlags __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_ENV *)); +void tcl_EnvSetErrfile __P((Tcl_Interp *, DB_ENV *, DBTCL_INFO *, char *)); +int tcl_EnvSetErrpfx __P((Tcl_Interp *, DB_ENV *, DBTCL_INFO *, char *)); +DBTCL_INFO *_NewInfo __P((Tcl_Interp *, void *, char *, enum INFOTYPE)); +void *_NameToPtr __P((CONST char *)); +DBTCL_INFO *_PtrToInfo __P((CONST void *)); +DBTCL_INFO *_NameToInfo __P((CONST char *)); +void _SetInfoData __P((DBTCL_INFO *, void *)); +void _DeleteInfo __P((DBTCL_INFO *)); +int _SetListElem __P((Tcl_Interp *, Tcl_Obj *, void *, u_int32_t, void *, u_int32_t)); +int _SetListElemInt __P((Tcl_Interp *, Tcl_Obj *, void *, long)); +int _SetListElemWideInt __P((Tcl_Interp *, Tcl_Obj *, void *, int64_t)); +int _SetListRecnoElem __P((Tcl_Interp *, Tcl_Obj *, db_recno_t, u_char *, u_int32_t)); +int _Set3DBTList __P((Tcl_Interp *, Tcl_Obj *, DBT *, int, DBT *, int, DBT *)); +int _SetMultiList __P((Tcl_Interp *, Tcl_Obj *, DBT *, DBT*, DBTYPE, u_int32_t)); +int _GetGlobPrefix __P((char *, char **)); +int _ReturnSetup __P((Tcl_Interp *, int, int, char *)); +int _ErrorSetup __P((Tcl_Interp *, int, char *)); +void _ErrorFunc __P((const DB_ENV *, CONST char *, const char *)); +int _GetLsn __P((Tcl_Interp *, Tcl_Obj *, DB_LSN *)); +int _GetUInt32 __P((Tcl_Interp *, Tcl_Obj *, u_int32_t *)); +Tcl_Obj *_GetFlagsList __P((Tcl_Interp *, u_int32_t, const FN *)); +void _debug_check __P((void)); +int _CopyObjBytes __P((Tcl_Interp *, Tcl_Obj *obj, void **, u_int32_t *, int *)); +int tcl_LockDetect __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_ENV *)); +int tcl_LockGet __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_ENV *)); +int tcl_LockStat __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_ENV *)); +int tcl_LockTimeout __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_ENV *)); +int tcl_LockVec __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_ENV *)); +int tcl_LogArchive __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_ENV *)); +int tcl_LogCompare __P((Tcl_Interp *, int, Tcl_Obj * CONST*)); +int tcl_LogFile __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_ENV *)); +int tcl_LogFlush __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_ENV *)); +int tcl_LogGet __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_ENV *)); +int tcl_LogPut __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_ENV *)); +int tcl_LogStat __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_ENV *)); +int logc_Cmd __P((ClientData, Tcl_Interp *, int, Tcl_Obj * CONST*)); +void _MpInfoDelete __P((Tcl_Interp *, DBTCL_INFO *)); +int tcl_MpSync __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_ENV *)); +int tcl_MpTrickle __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_ENV *)); +int tcl_Mp __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_ENV *, DBTCL_INFO *)); +int tcl_MpStat __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_ENV *)); +int tcl_RepElect __P((Tcl_Interp *, int, Tcl_Obj * CONST *, DB_ENV *)); +int tcl_RepFlush __P((Tcl_Interp *, int, Tcl_Obj * CONST *, DB_ENV *)); +int tcl_RepLimit __P((Tcl_Interp *, int, Tcl_Obj * CONST *, DB_ENV *)); +int tcl_RepRequest __P((Tcl_Interp *, int, Tcl_Obj * CONST *, DB_ENV *)); +int tcl_RepStart __P((Tcl_Interp *, int, Tcl_Obj * CONST *, DB_ENV *)); +int tcl_RepProcessMessage __P((Tcl_Interp *, int, Tcl_Obj * CONST *, DB_ENV *)); +int tcl_RepStat __P((Tcl_Interp *, int, Tcl_Obj * CONST *, DB_ENV *)); +int seq_Cmd __P((ClientData, Tcl_Interp *, int, Tcl_Obj * CONST*)); +void _TxnInfoDelete __P((Tcl_Interp *, DBTCL_INFO *)); +int tcl_TxnCheckpoint __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_ENV *)); +int tcl_Txn __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_ENV *, DBTCL_INFO *)); +int tcl_TxnStat __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_ENV *)); +int tcl_TxnTimeout __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_ENV *)); +int tcl_TxnRecover __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_ENV *, DBTCL_INFO *)); +int bdb_RandCommand __P((Tcl_Interp *, int, Tcl_Obj * CONST*)); +int tcl_Mutex __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_ENV *, DBTCL_INFO *)); + +#if defined(__cplusplus) +} +#endif +#endif /* !_tcl_ext_h_ */ diff --git a/lib_dict/bdb/include/txn.h b/lib_dict/bdb/include/txn.h new file mode 100644 index 000000000..514b740e8 --- /dev/null +++ b/lib_dict/bdb/include/txn.h @@ -0,0 +1,215 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996-2004 + * Sleepycat Software. All rights reserved. + * + * $Id: txn.h,v 11.54 2004/09/24 00:43:18 bostic Exp $ + */ + +#ifndef _TXN_H_ +#define _TXN_H_ + +#include "dbinc/xa.h" + +/* Operation parameters to the delayed commit processing code. */ +typedef enum { + TXN_CLOSE, /* Close a DB handle whose close had failed. */ + TXN_REMOVE, /* Remove a file. */ + TXN_TRADE, /* Trade lockers. */ + TXN_TRADED /* Already traded; downgrade lock. */ +} TXN_EVENT_T; + +struct __db_txnregion; typedef struct __db_txnregion DB_TXNREGION; +struct __txn_logrec; typedef struct __txn_logrec DB_TXNLOGREC; + +/* + * !!! + * TXN_MINIMUM = (DB_LOCK_MAXID + 1) but this makes compilers complain. + */ +#define TXN_MINIMUM 0x80000000 +#define TXN_MAXIMUM 0xffffffff /* Maximum number of txn ids. */ +#define TXN_INVALID 0 /* Invalid transaction ID. */ + +#define DEF_MAX_TXNS 20 /* Default max transactions. */ + +/* + * Internal data maintained in shared memory for each transaction. + */ +typedef struct __txn_detail { + u_int32_t txnid; /* current transaction id + used to link free list also */ + DB_LSN last_lsn; /* last lsn written for this txn */ + DB_LSN begin_lsn; /* lsn of begin record */ + roff_t parent; /* Offset of transaction's parent. */ + +#define TXN_RUNNING 1 +#define TXN_ABORTED 2 +#define TXN_PREPARED 3 +#define TXN_COMMITTED 4 + u_int32_t status; /* status of the transaction */ +#define TXN_DTL_COLLECTED 0x1 +#define TXN_DTL_RESTORED 0x2 + u_int32_t flags; /* collected during txn_recover */ + + SH_TAILQ_ENTRY links; /* free/active list */ + +#define TXN_XA_ABORTED 1 +#define TXN_XA_DEADLOCKED 2 +#define TXN_XA_ENDED 3 +#define TXN_XA_PREPARED 4 +#define TXN_XA_STARTED 5 +#define TXN_XA_SUSPENDED 6 + u_int32_t xa_status; /* XA status */ + + /* + * XID (xid_t) structure: because these fields are logged, the + * sizes have to be explicit. + */ + u_int8_t xid[XIDDATASIZE]; /* XA global transaction id */ + u_int32_t bqual; /* bqual_length from XID */ + u_int32_t gtrid; /* gtrid_length from XID */ + int32_t format; /* XA format */ +} TXN_DETAIL; + +/* + * DB_TXNMGR -- + * The transaction manager encapsulates the transaction system. + */ +struct __db_txnmgr { + /* + * These fields need to be protected for multi-threaded support. + * + * !!! + * As this structure is allocated in per-process memory, the mutex may + * need to be stored elsewhere on architectures unable to support + * mutexes in heap memory, e.g., HP/UX 9. + */ + DB_MUTEX *mutexp; /* Lock list of active transactions + * (including the content of each + * TXN_DETAIL structure on the list). + */ + /* List of active transactions. */ + TAILQ_HEAD(_chain, __db_txn) txn_chain; + u_int32_t n_discards; /* Number of txns discarded. */ + +/* These fields are never updated after creation, and so not protected. */ + DB_ENV *dbenv; /* Environment. */ + REGINFO reginfo; /* Region information. */ +}; + +/* + * DB_TXNREGION -- + * The primary transaction data structure in the shared memory region. + */ +struct __db_txnregion { + u_int32_t maxtxns; /* maximum number of active TXNs */ + u_int32_t last_txnid; /* last transaction id given out */ + u_int32_t cur_maxid; /* current max unused id. */ + + DB_LSN last_ckp; /* lsn of the last checkpoint */ + time_t time_ckp; /* time of last checkpoint */ + + DB_TXN_STAT stat; /* Statistics for txns. */ + +#define TXN_IN_RECOVERY 0x01 /* environment is being recovered */ + u_int32_t flags; + /* active TXN list */ + SH_TAILQ_HEAD(__active) active_txn; +#ifdef HAVE_MUTEX_SYSTEM_RESOURCES +#define TXN_MAINT_SIZE (sizeof(roff_t) * DB_MAX_HANDLES) + + roff_t maint_off; /* offset of region maintenance info */ +#endif +}; + +/* + * DB_TXNLOGREC -- + * An in-memory, linked-list copy of a log record. + */ +struct __txn_logrec { + STAILQ_ENTRY(__txn_logrec) links;/* Linked list. */ + + u_int8_t data[1]; /* Log record. */ +}; + +/* + * Log record types. Note that these are *not* alphabetical. This is + * intentional so that we don't change the meaning of values between + * software upgrades. + * + * EXPECTED, UNEXPECTED, IGNORE, and OK are used in the txnlist functions. + * Here is an explanation of how the statuses are used. + * + * TXN_OK + * BEGIN records for transactions found on the txnlist during + * OPENFILES (BEGIN records are those with a prev_lsn of 0,0) + * + * TXN_COMMIT + * Transaction committed and should be rolled forward. + * + * TXN_ABORT + * This transaction's changes must be undone. Either there was + * never a prepare or commit record for this transaction OR there + * was a commit, but we are recovering to a timestamp or particular + * LSN and that point is before this transaction's commit. + * + * TXN_PREPARE + * Prepare record, but no commit record is in the log. + * + * TXN_IGNORE + * Generic meaning is that this transaction should not be + * processed during later recovery passes. We use it in a + * number of different manners: + * + * 1. We never saw its BEGIN record. Therefore, the logs have + * been reclaimed and we *know* that this transaction doesn't + * need to be aborted, because in order for it to be + * reclaimed, there must have been a subsequent checkpoint + * (and any dirty pages for this transaction made it to + * disk). + * + * 2. This is a child transaction that created a database. + * For some reason, we don't want to recreate that database + * (i.e., it already exists or some other database created + * after it exists). + * + * 3. During recovery open of subdatabases, if the master check fails, + * we use a TXN_IGNORE on the create of the subdb in the nested + * transaction. + * + * 4. During a remove, the file with the name being removed isn't + * the file for which we are recovering a remove. + * + * TXN_EXPECTED + * After a successful open during recovery, we update the + * transaction's status to TXN_EXPECTED. The open was done + * in the parent, but in the open log record, we record the + * child transaction's ID if we also did a create. When there + * is a valid ID in that field, we use it and mark the child's + * status as TXN_EXPECTED (indicating that we don't need to redo + * a create for this file). + * + * When recovering a remove, if we don't find or can't open + * the file, the child (which does the remove) gets marked + * EXPECTED (indicating that we don't need to redo the remove). + * + * TXN_UNEXPECTED + * During recovery, we attempted an open that should have succeeded + * and we got ENOENT, so like with the EXPECTED case, we indicate + * in the child that we got the UNEXPECTED return so that we do redo + * the creating/deleting operation. + * + */ +#define TXN_OK 0 +#define TXN_COMMIT 1 +#define TXN_PREPARE 2 +#define TXN_ABORT 3 +#define TXN_IGNORE 4 +#define TXN_EXPECTED 5 +#define TXN_UNEXPECTED 6 + +#include "dbinc_auto/txn_auto.h" +#include "dbinc_auto/txn_ext.h" +#include "dbinc_auto/xa_ext.h" +#endif /* !_TXN_H_ */ diff --git a/lib_dict/bdb/include/txn_auto.h b/lib_dict/bdb/include/txn_auto.h new file mode 100644 index 000000000..2611df15e --- /dev/null +++ b/lib_dict/bdb/include/txn_auto.h @@ -0,0 +1,59 @@ +/* Do not edit: automatically built by gen_rec.awk. */ + +#ifndef __txn_AUTO_H +#define __txn_AUTO_H +#define DB___txn_regop 10 +typedef struct ___txn_regop_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + u_int32_t opcode; + int32_t timestamp; + DBT locks; +} __txn_regop_args; + +#define DB___txn_ckp 11 +typedef struct ___txn_ckp_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + DB_LSN ckp_lsn; + DB_LSN last_ckp; + int32_t timestamp; + u_int32_t envid; + u_int32_t rep_gen; +} __txn_ckp_args; + +#define DB___txn_child 12 +typedef struct ___txn_child_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + u_int32_t child; + DB_LSN c_lsn; +} __txn_child_args; + +#define DB___txn_xa_regop 13 +typedef struct ___txn_xa_regop_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + u_int32_t opcode; + DBT xid; + int32_t formatID; + u_int32_t gtrid; + u_int32_t bqual; + DB_LSN begin_lsn; + DBT locks; +} __txn_xa_regop_args; + +#define DB___txn_recycle 14 +typedef struct ___txn_recycle_args { + u_int32_t type; + DB_TXN *txnid; + DB_LSN prev_lsn; + u_int32_t min; + u_int32_t max; +} __txn_recycle_args; + +#endif diff --git a/lib_dict/bdb/include/txn_ext.h b/lib_dict/bdb/include/txn_ext.h new file mode 100644 index 000000000..94ca6f332 --- /dev/null +++ b/lib_dict/bdb/include/txn_ext.h @@ -0,0 +1,77 @@ +/* DO NOT EDIT: automatically built by dist/s_include. */ +#ifndef _txn_ext_h_ +#define _txn_ext_h_ + +#if defined(__cplusplus) +extern "C" { +#endif + +int __txn_begin_pp __P((DB_ENV *, DB_TXN *, DB_TXN **, u_int32_t)); +int __txn_begin __P((DB_ENV *, DB_TXN *, DB_TXN **, u_int32_t)); +int __txn_xa_begin __P((DB_ENV *, DB_TXN *)); +int __txn_compensate_begin __P((DB_ENV *, DB_TXN **txnp)); +int __txn_commit __P((DB_TXN *, u_int32_t)); +int __txn_abort __P((DB_TXN *)); +int __txn_discard __P((DB_TXN *, u_int32_t flags)); +int __txn_prepare __P((DB_TXN *, u_int8_t *)); +u_int32_t __txn_id __P((DB_TXN *)); +int __txn_set_timeout __P((DB_TXN *, db_timeout_t, u_int32_t)); +int __txn_checkpoint_pp __P((DB_ENV *, u_int32_t, u_int32_t, u_int32_t)); +int __txn_checkpoint __P((DB_ENV *, u_int32_t, u_int32_t, u_int32_t)); +void __txn_getactive __P((DB_ENV *, DB_LSN *)); +int __txn_getckp __P((DB_ENV *, DB_LSN *)); +int __txn_activekids __P((DB_ENV *, u_int32_t, DB_TXN *)); +int __txn_force_abort __P((DB_ENV *, u_int8_t *)); +int __txn_preclose __P((DB_ENV *)); +int __txn_reset __P((DB_ENV *)); +void __txn_updateckp __P((DB_ENV *, DB_LSN *)); +int __txn_regop_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t, u_int32_t, int32_t, const DBT *)); +int __txn_regop_read __P((DB_ENV *, void *, __txn_regop_args **)); +int __txn_ckp_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t, DB_LSN *, DB_LSN *, int32_t, u_int32_t, u_int32_t)); +int __txn_ckp_read __P((DB_ENV *, void *, __txn_ckp_args **)); +int __txn_child_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t, u_int32_t, DB_LSN *)); +int __txn_child_read __P((DB_ENV *, void *, __txn_child_args **)); +int __txn_xa_regop_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t, u_int32_t, const DBT *, int32_t, u_int32_t, u_int32_t, DB_LSN *, const DBT *)); +int __txn_xa_regop_read __P((DB_ENV *, void *, __txn_xa_regop_args **)); +int __txn_recycle_log __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t, u_int32_t, u_int32_t)); +int __txn_recycle_read __P((DB_ENV *, void *, __txn_recycle_args **)); +int __txn_init_recover __P((DB_ENV *, int (***)(DB_ENV *, DBT *, DB_LSN *, db_recops, void *), size_t *)); +int __txn_regop_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __txn_ckp_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __txn_child_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __txn_xa_regop_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __txn_recycle_print __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __txn_init_print __P((DB_ENV *, int (***)(DB_ENV *, DBT *, DB_LSN *, db_recops, void *), size_t *)); +void __txn_dbenv_create __P((DB_ENV *)); +int __txn_set_tx_max __P((DB_ENV *, u_int32_t)); +int __txn_regop_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __txn_xa_regop_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __txn_ckp_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __txn_child_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +int __txn_restore_txn __P((DB_ENV *, DB_LSN *, __txn_xa_regop_args *)); +int __txn_recycle_recover __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); +void __txn_continue __P((DB_ENV *, DB_TXN *, TXN_DETAIL *, size_t)); +int __txn_map_gid __P((DB_ENV *, u_int8_t *, TXN_DETAIL **, roff_t *)); +int __txn_recover_pp __P((DB_ENV *, DB_PREPLIST *, long, long *, u_int32_t)); +int __txn_recover __P((DB_ENV *, DB_PREPLIST *, long, long *, u_int32_t)); +int __txn_get_prepared __P((DB_ENV *, XID *, DB_PREPLIST *, long, long *, u_int32_t)); +int __txn_openfiles __P((DB_ENV *, DB_LSN *, int)); +int __txn_open __P((DB_ENV *)); +int __txn_findlastckp __P((DB_ENV *, DB_LSN *, DB_LSN *)); +int __txn_dbenv_refresh __P((DB_ENV *)); +void __txn_region_destroy __P((DB_ENV *, REGINFO *)); +int __txn_id_set __P((DB_ENV *, u_int32_t, u_int32_t)); +int __txn_stat_pp __P((DB_ENV *, DB_TXN_STAT **, u_int32_t)); +int __txn_stat_print_pp __P((DB_ENV *, u_int32_t)); +int __txn_stat_print __P((DB_ENV *, u_int32_t)); +int __txn_closeevent __P((DB_ENV *, DB_TXN *, DB *)); +int __txn_remevent __P((DB_ENV *, DB_TXN *, const char *, u_int8_t*)); +void __txn_remrem __P((DB_ENV *, DB_TXN *, const char *)); +int __txn_lockevent __P((DB_ENV *, DB_TXN *, DB *, DB_LOCK *, u_int32_t)); +void __txn_remlock __P((DB_ENV *, DB_TXN *, DB_LOCK *, u_int32_t)); +int __txn_doevents __P((DB_ENV *, DB_TXN *, int, int)); + +#if defined(__cplusplus) +} +#endif +#endif /* !_txn_ext_h_ */ diff --git a/lib_dict/bdb/include/win_db.h b/lib_dict/bdb/include/win_db.h new file mode 100644 index 000000000..609d8460a --- /dev/null +++ b/lib_dict/bdb/include/win_db.h @@ -0,0 +1,100 @@ +/*- + * $Id: win_db.in,v 11.4 2004/10/07 13:59:24 carol Exp $ + * + * The following provides the information necessary to build Berkeley + * DB on native Windows, and other Windows environments such as MinGW. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * To build Tcl interface libraries, the include path must be configured to + * use the directory containing , usually the include directory in + * the Tcl distribution. + */ +#ifdef DB_TCL_SUPPORT +#include +#endif + +#define WIN32_LEAN_AND_MEAN +#include + +/* + * All of the necessary includes have been included, ignore the #includes + * in the Berkeley DB source files. + */ +#define NO_SYSTEM_INCLUDES + +/* + * Win32 has getcwd, snprintf and vsnprintf, but under different names. + */ +#define getcwd(buf, size) _getcwd(buf, size) +#define snprintf _snprintf +#define vsnprintf _vsnprintf + +/* + * Windows defines off_t to long (i.e., 32 bits). + */ +#define off_t __db_off_t +typedef __int64 off_t; + +/* + * Win32 does not define getopt and friends in any header file, so we must. + */ +#if defined(__cplusplus) +extern "C" { +#endif +extern int optind; +extern char *optarg; +extern int getopt(int, char * const *, const char *); +#if defined(__cplusplus) +} +#endif + +#ifdef _UNICODE +#define TO_TSTRING(dbenv, s, ts, ret) do { \ + int __len = strlen(s) + 1; \ + ts = NULL; \ + if ((ret = __os_malloc((dbenv), \ + __len * sizeof (_TCHAR), &(ts))) == 0 && \ + MultiByteToWideChar(CP_UTF8, 0, \ + (s), -1, (ts), __len) == 0) \ + ret = __os_get_errno(); \ + } while (0) + +#define FROM_TSTRING(dbenv, ts, s, ret) { \ + int __len = WideCharToMultiByte(CP_UTF8, 0, ts, -1, \ + NULL, 0, NULL, NULL); \ + s = NULL; \ + if ((ret = __os_malloc((dbenv), __len, &(s))) == 0 && \ + WideCharToMultiByte(CP_UTF8, 0, \ + (ts), -1, (s), __len, NULL, NULL) == 0) \ + ret = __os_get_errno(); \ + } while (0) + +#define FREE_STRING(dbenv, s) do { \ + if ((s) != NULL) { \ + __os_free((dbenv), (s)); \ + (s) = NULL; \ + } \ + } while (0) + +#else +#define TO_TSTRING(dbenv, s, ts, ret) (ret) = 0, (ts) = (_TCHAR *)(s) +#define FROM_TSTRING(dbenv, ts, s, ret) (ret) = 0, (s) = (char *)(ts) +#define FREE_STRING(dbenv, ts) +#endif diff --git a/lib_dict/bdb/include/xa.h b/lib_dict/bdb/include/xa.h new file mode 100644 index 000000000..71333c2c9 --- /dev/null +++ b/lib_dict/bdb/include/xa.h @@ -0,0 +1,179 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1998-2004 + * Sleepycat Software. All rights reserved. + * + * $Id: xa.h,v 11.7 2004/01/28 03:36:02 bostic Exp $ + */ +/* + * Start of xa.h header + * + * Define a symbol to prevent multiple inclusions of this header file + */ +#ifndef XA_H +#define XA_H + +/* + * Transaction branch identification: XID and NULLXID: + */ +#define XIDDATASIZE 128 /* size in bytes */ +#define MAXGTRIDSIZE 64 /* maximum size in bytes of gtrid */ +#define MAXBQUALSIZE 64 /* maximum size in bytes of bqual */ + +struct xid_t { + long formatID; /* format identifier */ + long gtrid_length; /* value from 1 through 64 */ + long bqual_length; /* value from 1 through 64 */ + char data[XIDDATASIZE]; +}; +typedef struct xid_t XID; +/* + * A value of -1 in formatID means that the XID is null. + */ + +/* + * Declarations of routines by which RMs call TMs: + */ +extern int ax_reg __P((int, XID *, long)); +extern int ax_unreg __P((int, long)); + +/* + * XA Switch Data Structure + */ +#define RMNAMESZ 32 /* length of resource manager name, */ + /* including the null terminator */ +#define MAXINFOSIZE 256 /* maximum size in bytes of xa_info */ + /* strings, including the null + terminator */ +struct xa_switch_t { + char name[RMNAMESZ]; /* name of resource manager */ + long flags; /* resource manager specific options */ + long version; /* must be 0 */ + int (*xa_open_entry) /* xa_open function pointer */ + __P((char *, int, long)); + int (*xa_close_entry) /* xa_close function pointer */ + __P((char *, int, long)); + int (*xa_start_entry) /* xa_start function pointer */ + __P((XID *, int, long)); + int (*xa_end_entry) /* xa_end function pointer */ + __P((XID *, int, long)); + int (*xa_rollback_entry) /* xa_rollback function pointer */ + __P((XID *, int, long)); + int (*xa_prepare_entry) /* xa_prepare function pointer */ + __P((XID *, int, long)); + int (*xa_commit_entry) /* xa_commit function pointer */ + __P((XID *, int, long)); + int (*xa_recover_entry) /* xa_recover function pointer */ + __P((XID *, long, int, long)); + int (*xa_forget_entry) /* xa_forget function pointer */ + __P((XID *, int, long)); + int (*xa_complete_entry) /* xa_complete function pointer */ + __P((int *, int *, int, long)); +}; + +/* + * Flag definitions for the RM switch + */ +#define TMNOFLAGS 0x00000000L /* no resource manager features + selected */ +#define TMREGISTER 0x00000001L /* resource manager dynamically + registers */ +#define TMNOMIGRATE 0x00000002L /* resource manager does not support + association migration */ +#define TMUSEASYNC 0x00000004L /* resource manager supports + asynchronous operations */ +/* + * Flag definitions for xa_ and ax_ routines + */ +/* use TMNOFLAGGS, defined above, when not specifying other flags */ +#define TMASYNC 0x80000000L /* perform routine asynchronously */ +#define TMONEPHASE 0x40000000L /* caller is using one-phase commit + optimisation */ +#define TMFAIL 0x20000000L /* dissociates caller and marks + transaction branch rollback-only */ +#define TMNOWAIT 0x10000000L /* return if blocking condition + exists */ +#define TMRESUME 0x08000000L /* caller is resuming association with + suspended transaction branch */ +#define TMSUCCESS 0x04000000L /* dissociate caller from transaction + branch */ +#define TMSUSPEND 0x02000000L /* caller is suspending, not ending, + association */ +#define TMSTARTRSCAN 0x01000000L /* start a recovery scan */ +#define TMENDRSCAN 0x00800000L /* end a recovery scan */ +#define TMMULTIPLE 0x00400000L /* wait for any asynchronous + operation */ +#define TMJOIN 0x00200000L /* caller is joining existing + transaction branch */ +#define TMMIGRATE 0x00100000L /* caller intends to perform + migration */ + +/* + * ax_() return codes (transaction manager reports to resource manager) + */ +#define TM_JOIN 2 /* caller is joining existing + transaction branch */ +#define TM_RESUME 1 /* caller is resuming association with + suspended transaction branch */ +#define TM_OK 0 /* normal execution */ +#define TMER_TMERR -1 /* an error occurred in the transaction + manager */ +#define TMER_INVAL -2 /* invalid arguments were given */ +#define TMER_PROTO -3 /* routine invoked in an improper + context */ + +/* + * xa_() return codes (resource manager reports to transaction manager) + */ +#define XA_RBBASE 100 /* The inclusive lower bound of the + rollback codes */ +#define XA_RBROLLBACK XA_RBBASE /* The rollback was caused by an + unspecified reason */ +#define XA_RBCOMMFAIL XA_RBBASE+1 /* The rollback was caused by a + communication failure */ +#define XA_RBDEADLOCK XA_RBBASE+2 /* A deadlock was detected */ +#define XA_RBINTEGRITY XA_RBBASE+3 /* A condition that violates the + integrity of the resources was + detected */ +#define XA_RBOTHER XA_RBBASE+4 /* The resource manager rolled back the + transaction branch for a reason not + on this list */ +#define XA_RBPROTO XA_RBBASE+5 /* A protocol error occurred in the + resource manager */ +#define XA_RBTIMEOUT XA_RBBASE+6 /* A transaction branch took too long */ +#define XA_RBTRANSIENT XA_RBBASE+7 /* May retry the transaction branch */ +#define XA_RBEND XA_RBTRANSIENT /* The inclusive upper bound of the + rollback codes */ +#define XA_NOMIGRATE 9 /* resumption must occur where + suspension occurred */ +#define XA_HEURHAZ 8 /* the transaction branch may have + been heuristically completed */ +#define XA_HEURCOM 7 /* the transaction branch has been + heuristically committed */ +#define XA_HEURRB 6 /* the transaction branch has been + heuristically rolled back */ +#define XA_HEURMIX 5 /* the transaction branch has been + heuristically committed and rolled + back */ +#define XA_RETRY 4 /* routine returned with no effect and + may be re-issued */ +#define XA_RDONLY 3 /* the transaction branch was read-only + and has been committed */ +#define XA_OK 0 /* normal execution */ +#define XAER_ASYNC -2 /* asynchronous operation already + outstanding */ +#define XAER_RMERR -3 /* a resource manager error occurred in + the transaction branch */ +#define XAER_NOTA -4 /* the XID is not valid */ +#define XAER_INVAL -5 /* invalid arguments were given */ +#define XAER_PROTO -6 /* routine invoked in an improper + context */ +#define XAER_RMFAIL -7 /* resource manager unavailable */ +#define XAER_DUPID -8 /* the XID already exists */ +#define XAER_OUTSIDE -9 /* resource manager doing work outside + transaction */ +#endif /* ifndef XA_H */ +/* + * End of xa.h header + */ diff --git a/lib_dict/bdb/include/xa_ext.h b/lib_dict/bdb/include/xa_ext.h new file mode 100644 index 000000000..3247b5bb7 --- /dev/null +++ b/lib_dict/bdb/include/xa_ext.h @@ -0,0 +1,21 @@ +/* DO NOT EDIT: automatically built by dist/s_include. */ +#ifndef _xa_ext_h_ +#define _xa_ext_h_ + +#if defined(__cplusplus) +extern "C" { +#endif + +int __xa_get_txn __P((DB_ENV *, DB_TXN **, int)); +int __db_xa_create __P((DB *)); +int __db_rmid_to_env __P((int rmid, DB_ENV **envp)); +int __db_xid_to_txn __P((DB_ENV *, XID *, roff_t *)); +int __db_map_rmid __P((int, DB_ENV *)); +int __db_unmap_rmid __P((int)); +int __db_map_xid __P((DB_ENV *, XID *, size_t)); +void __db_unmap_xid __P((DB_ENV *, XID *, size_t)); + +#if defined(__cplusplus) +} +#endif +#endif /* !_xa_ext_h_ */ diff --git a/lib_dict/cdb/include/alloc.h b/lib_dict/cdb/include/alloc.h new file mode 100644 index 000000000..1b1d8936a --- /dev/null +++ b/lib_dict/cdb/include/alloc.h @@ -0,0 +1,8 @@ +#ifndef ALLOC_H +#define ALLOC_H + +extern /*@null@*//*@out@*/char *alloc(); +extern void alloc_free(); +extern int alloc_re(); + +#endif diff --git a/lib_dict/cdb/include/auto_home.h b/lib_dict/cdb/include/auto_home.h new file mode 100644 index 000000000..a756cd063 --- /dev/null +++ b/lib_dict/cdb/include/auto_home.h @@ -0,0 +1,6 @@ +#ifndef AUTO_HOME_H +#define AUTO_HOME_H + +extern char auto_home[]; + +#endif diff --git a/lib_dict/cdb/include/buffer.h b/lib_dict/cdb/include/buffer.h new file mode 100644 index 000000000..12539b3f2 --- /dev/null +++ b/lib_dict/cdb/include/buffer.h @@ -0,0 +1,56 @@ +#ifndef BUFFER_H +#define BUFFER_H + +typedef struct buffer { + char *x; + unsigned int p; + unsigned int n; + int fd; + int (*op)(); +} buffer; + +#define BUFFER_INIT(op,fd,buf,len) { (buf), 0, (len), (fd), (op) } +#define BUFFER_INSIZE 8192 +#define BUFFER_OUTSIZE 8192 + +extern void buffer_init(buffer *,int (*)(),int,char *,unsigned int); + +extern int buffer_flush(buffer *); +extern int buffer_put(buffer *,char *,unsigned int); +extern int buffer_putalign(buffer *,char *,unsigned int); +extern int buffer_putflush(buffer *,char *,unsigned int); +extern int buffer_puts(buffer *,char *); +extern int buffer_putsalign(buffer *,char *); +extern int buffer_putsflush(buffer *,char *); + +#define buffer_PUTC(s,c) \ + ( ((s)->n != (s)->p) \ + ? ( (s)->x[(s)->p++] = (c), 0 ) \ + : buffer_put((s),&(c),1) \ + ) + +extern int buffer_get(buffer *,char *,unsigned int); +extern int buffer_bget(buffer *,char *,unsigned int); +extern int buffer_feed(buffer *); + +extern char *buffer_peek(buffer *); +extern void buffer_seek(buffer *,unsigned int); + +#define buffer_PEEK(s) ( (s)->x + (s)->n ) +#define buffer_SEEK(s,len) ( ( (s)->p -= (len) ) , ( (s)->n += (len) ) ) + +#define buffer_GETC(s,c) \ + ( ((s)->p > 0) \ + ? ( *(c) = (s)->x[(s)->n], buffer_SEEK((s),1), 1 ) \ + : buffer_get((s),(c),1) \ + ) + +extern int buffer_copy(buffer *,buffer *); + +extern buffer *buffer_0; +extern buffer *buffer_0small; +extern buffer *buffer_1; +extern buffer *buffer_1small; +extern buffer *buffer_2; + +#endif diff --git a/lib_dict/cdb/include/byte.h b/lib_dict/cdb/include/byte.h new file mode 100644 index 000000000..de06c699d --- /dev/null +++ b/lib_dict/cdb/include/byte.h @@ -0,0 +1,13 @@ +#ifndef BYTE_H +#define BYTE_H + +extern unsigned int byte_chr(); +extern unsigned int byte_rchr(); +extern void byte_copy(); +extern void byte_copyr(); +extern int byte_diff(); +extern void byte_zero(); + +#define byte_equal(s,n,t) (!byte_diff((s),(n),(t))) + +#endif diff --git a/lib_dict/cdb/include/cdb.h b/lib_dict/cdb/include/cdb.h new file mode 100644 index 000000000..ff998103f --- /dev/null +++ b/lib_dict/cdb/include/cdb.h @@ -0,0 +1,37 @@ +/* Public domain. */ + +#ifndef CDB_H +#define CDB_H + +#include "uint32.h" + +#define CDB_HASHSTART 5381 +extern uint32 cdb_hashadd(uint32,unsigned char); +extern uint32 cdb_hash(char *,unsigned int); + +struct cdb { + char *map; /* 0 if no map is available */ + int fd; + uint32 size; /* initialized if map is nonzero */ + uint32 loop; /* number of hash slots searched under this key */ + uint32 khash; /* initialized if loop is nonzero */ + uint32 kpos; /* initialized if loop is nonzero */ + uint32 hpos; /* initialized if loop is nonzero */ + uint32 hslots; /* initialized if loop is nonzero */ + uint32 dpos; /* initialized if cdb_findnext() returns 1 */ + uint32 dlen; /* initialized if cdb_findnext() returns 1 */ +} ; + +extern void cdb_free(struct cdb *); +extern void cdb_init(struct cdb *,int fd); + +extern int cdb_read(struct cdb *,char *,unsigned int,uint32); + +extern void cdb_findstart(struct cdb *); +extern int cdb_findnext(struct cdb *,char *,unsigned int); +extern int cdb_find(struct cdb *,char *,unsigned int); + +#define cdb_datapos(c) ((c)->dpos) +#define cdb_datalen(c) ((c)->dlen) + +#endif diff --git a/lib_dict/cdb/include/cdb_make.h b/lib_dict/cdb/include/cdb_make.h new file mode 100644 index 000000000..b8bbe4d0f --- /dev/null +++ b/lib_dict/cdb/include/cdb_make.h @@ -0,0 +1,39 @@ +/* Public domain. */ + +#ifndef CDB_MAKE_H +#define CDB_MAKE_H + +#include "buffer.h" +#include "uint32.h" + +#define CDB_HPLIST 1000 + +struct cdb_hp { uint32 h; uint32 p; } ; + +struct cdb_hplist { + struct cdb_hp hp[CDB_HPLIST]; + struct cdb_hplist *next; + int num; +} ; + +struct cdb_make { + char bspace[8192]; + char final[2048]; + uint32 count[256]; + uint32 start[256]; + struct cdb_hplist *head; + struct cdb_hp *split; /* includes space for hash */ + struct cdb_hp *hash; + uint32 numentries; + buffer b; + uint32 pos; + int fd; +} ; + +extern int cdb_make_start(struct cdb_make *,int); +extern int cdb_make_addbegin(struct cdb_make *,unsigned int,unsigned int); +extern int cdb_make_addend(struct cdb_make *,unsigned int,unsigned int,uint32); +extern int cdb_make_add(struct cdb_make *,char *,unsigned int,char *,unsigned int); +extern int cdb_make_finish(struct cdb_make *); + +#endif diff --git a/lib_dict/cdb/include/error.h b/lib_dict/cdb/include/error.h new file mode 100644 index 000000000..e3cc2ae36 --- /dev/null +++ b/lib_dict/cdb/include/error.h @@ -0,0 +1,25 @@ +#ifndef ERROR_H +#define ERROR_H + +extern int errno; + +extern int error_intr; +extern int error_nomem; +extern int error_noent; +extern int error_txtbsy; +extern int error_io; +extern int error_exist; +extern int error_timeout; +extern int error_inprogress; +extern int error_wouldblock; +extern int error_again; +extern int error_pipe; +extern int error_perm; +extern int error_acces; +extern int error_nodevice; +extern int error_proto; + +extern char *error_str(int); +extern int error_temp(int); + +#endif diff --git a/lib_dict/cdb/include/exit.h b/lib_dict/cdb/include/exit.h new file mode 100644 index 000000000..39011c88d --- /dev/null +++ b/lib_dict/cdb/include/exit.h @@ -0,0 +1,6 @@ +#ifndef EXIT_H +#define EXIT_H + +extern void _exit(); + +#endif diff --git a/lib_dict/cdb/include/fmt.h b/lib_dict/cdb/include/fmt.h new file mode 100644 index 000000000..6fd8fef72 --- /dev/null +++ b/lib_dict/cdb/include/fmt.h @@ -0,0 +1,25 @@ +#ifndef FMT_H +#define FMT_H + +#define FMT_ULONG 40 /* enough space to hold 2^128 - 1 in decimal, plus \0 */ +#define FMT_LEN ((char *) 0) /* convenient abbreviation */ + +extern unsigned int fmt_uint(char *,unsigned int); +extern unsigned int fmt_uint0(char *,unsigned int,unsigned int); +extern unsigned int fmt_xint(char *,unsigned int); +extern unsigned int fmt_nbbint(char *,unsigned int,unsigned int,unsigned int,unsigned int); +extern unsigned int fmt_ushort(char *,unsigned short); +extern unsigned int fmt_xshort(char *,unsigned short); +extern unsigned int fmt_nbbshort(char *,unsigned int,unsigned int,unsigned int,unsigned short); +extern unsigned int fmt_ulong(char *,unsigned long); +extern unsigned int fmt_xlong(char *,unsigned long); +extern unsigned int fmt_nbblong(char *,unsigned int,unsigned int,unsigned int,unsigned long); + +extern unsigned int fmt_plusminus(char *,int); +extern unsigned int fmt_minus(char *,int); +extern unsigned int fmt_0x(char *,int); + +extern unsigned int fmt_str(char *,char *); +extern unsigned int fmt_strn(char *,char *,unsigned int); + +#endif diff --git a/lib_dict/cdb/include/open.h b/lib_dict/cdb/include/open.h new file mode 100644 index 000000000..2963fa70c --- /dev/null +++ b/lib_dict/cdb/include/open.h @@ -0,0 +1,10 @@ +#ifndef OPEN_H +#define OPEN_H + +extern int open_read(char *); +extern int open_excl(char *); +extern int open_append(char *); +extern int open_trunc(char *); +extern int open_write(char *); + +#endif diff --git a/lib_dict/cdb/include/readwrite.h b/lib_dict/cdb/include/readwrite.h new file mode 100644 index 000000000..2a64968e4 --- /dev/null +++ b/lib_dict/cdb/include/readwrite.h @@ -0,0 +1,7 @@ +#ifndef READWRITE_H +#define READWRITE_H + +extern int read(); +extern int write(); + +#endif diff --git a/lib_dict/cdb/include/scan.h b/lib_dict/cdb/include/scan.h new file mode 100644 index 000000000..758138c61 --- /dev/null +++ b/lib_dict/cdb/include/scan.h @@ -0,0 +1,28 @@ +#ifndef SCAN_H +#define SCAN_H + +extern unsigned int scan_uint(char *,unsigned int *); +extern unsigned int scan_xint(char *,unsigned int *); +extern unsigned int scan_nbbint(char *,unsigned int,unsigned int,unsigned int,unsigned int *); +extern unsigned int scan_ushort(char *,unsigned short *); +extern unsigned int scan_xshort(char *,unsigned short *); +extern unsigned int scan_nbbshort(char *,unsigned int,unsigned int,unsigned int,unsigned short *); +extern unsigned int scan_ulong(char *,unsigned long *); +extern unsigned int scan_xlong(char *,unsigned long *); +extern unsigned int scan_nbblong(char *,unsigned int,unsigned int,unsigned int,unsigned long *); + +extern unsigned int scan_plusminus(char *,int *); +extern unsigned int scan_0x(char *,unsigned int *); + +extern unsigned int scan_whitenskip(char *,unsigned int); +extern unsigned int scan_nonwhitenskip(char *,unsigned int); +extern unsigned int scan_charsetnskip(char *,char *,unsigned int); +extern unsigned int scan_noncharsetnskip(char *,char *,unsigned int); + +extern unsigned int scan_strncmp(char *,char *,unsigned int); +extern unsigned int scan_memcmp(char *,char *,unsigned int); + +extern unsigned int scan_long(char *,long *); +extern unsigned int scan_8long(char *,unsigned long *); + +#endif diff --git a/lib_dict/cdb/include/seek.h b/lib_dict/cdb/include/seek.h new file mode 100644 index 000000000..06aad9791 --- /dev/null +++ b/lib_dict/cdb/include/seek.h @@ -0,0 +1,15 @@ +#ifndef SEEK_H +#define SEEK_H + +typedef unsigned long seek_pos; + +extern seek_pos seek_cur(int); + +extern int seek_set(int,seek_pos); +extern int seek_end(int); + +extern int seek_trunc(int,seek_pos); + +#define seek_begin(fd) (seek_set((fd),(seek_pos) 0)) + +#endif diff --git a/lib_dict/cdb/include/str.h b/lib_dict/cdb/include/str.h new file mode 100644 index 000000000..ab4aedda0 --- /dev/null +++ b/lib_dict/cdb/include/str.h @@ -0,0 +1,14 @@ +#ifndef STR_H +#define STR_H + +extern unsigned int str_copy(char *,char *); +extern int str_diff(char *,char *); +extern int str_diffn(char *,char *,unsigned int); +extern unsigned int str_len(char *); +extern unsigned int str_chr(char *,int); +extern unsigned int str_rchr(char *,int); +extern int str_start(char *,char *); + +#define str_equal(s,t) (!str_diff((s),(t))) + +#endif diff --git a/lib_dict/cdb/include/strerr.h b/lib_dict/cdb/include/strerr.h new file mode 100644 index 000000000..702f58895 --- /dev/null +++ b/lib_dict/cdb/include/strerr.h @@ -0,0 +1,78 @@ +#ifndef STRERR_H +#define STRERR_H + +struct strerr { + struct strerr *who; + char *x; + char *y; + char *z; +} ; + +extern struct strerr strerr_sys; +extern void strerr_sysinit(void); + +extern char *strerr(struct strerr *); +extern void strerr_warn(char *,char *,char *,char *,char *,char *,struct strerr *); +extern void strerr_die(int,char *,char *,char *,char *,char *,char *,struct strerr *); + +#define STRERR(r,se,a) \ +{ se.who = 0; se.x = a; se.y = 0; se.z = 0; return r; } + +#define STRERR_SYS(r,se,a) \ +{ se.who = &strerr_sys; se.x = a; se.y = 0; se.z = 0; return r; } +#define STRERR_SYS3(r,se,a,b,c) \ +{ se.who = &strerr_sys; se.x = a; se.y = b; se.z = c; return r; } + +#define strerr_warn6(x1,x2,x3,x4,x5,x6,se) \ +strerr_warn((x1),(x2),(x3),(x4),(x5),(x6),(se)) +#define strerr_warn5(x1,x2,x3,x4,x5,se) \ +strerr_warn((x1),(x2),(x3),(x4),(x5),0,(se)) +#define strerr_warn4(x1,x2,x3,x4,se) \ +strerr_warn((x1),(x2),(x3),(x4),0,0,(se)) +#define strerr_warn3(x1,x2,x3,se) \ +strerr_warn((x1),(x2),(x3),0,0,0,(se)) +#define strerr_warn2(x1,x2,se) \ +strerr_warn((x1),(x2),0,0,0,0,(se)) +#define strerr_warn1(x1,se) \ +strerr_warn((x1),0,0,0,0,0,(se)) + +#define strerr_die6(e,x1,x2,x3,x4,x5,x6,se) \ +strerr_die((e),(x1),(x2),(x3),(x4),(x5),(x6),(se)) +#define strerr_die5(e,x1,x2,x3,x4,x5,se) \ +strerr_die((e),(x1),(x2),(x3),(x4),(x5),0,(se)) +#define strerr_die4(e,x1,x2,x3,x4,se) \ +strerr_die((e),(x1),(x2),(x3),(x4),0,0,(se)) +#define strerr_die3(e,x1,x2,x3,se) \ +strerr_die((e),(x1),(x2),(x3),0,0,0,(se)) +#define strerr_die2(e,x1,x2,se) \ +strerr_die((e),(x1),(x2),0,0,0,0,(se)) +#define strerr_die1(e,x1,se) \ +strerr_die((e),(x1),0,0,0,0,0,(se)) + +#define strerr_die6sys(e,x1,x2,x3,x4,x5,x6) \ +strerr_die((e),(x1),(x2),(x3),(x4),(x5),(x6),&strerr_sys) +#define strerr_die5sys(e,x1,x2,x3,x4,x5) \ +strerr_die((e),(x1),(x2),(x3),(x4),(x5),0,&strerr_sys) +#define strerr_die4sys(e,x1,x2,x3,x4) \ +strerr_die((e),(x1),(x2),(x3),(x4),0,0,&strerr_sys) +#define strerr_die3sys(e,x1,x2,x3) \ +strerr_die((e),(x1),(x2),(x3),0,0,0,&strerr_sys) +#define strerr_die2sys(e,x1,x2) \ +strerr_die((e),(x1),(x2),0,0,0,0,&strerr_sys) +#define strerr_die1sys(e,x1) \ +strerr_die((e),(x1),0,0,0,0,0,&strerr_sys) + +#define strerr_die6x(e,x1,x2,x3,x4,x5,x6) \ +strerr_die((e),(x1),(x2),(x3),(x4),(x5),(x6),0) +#define strerr_die5x(e,x1,x2,x3,x4,x5) \ +strerr_die((e),(x1),(x2),(x3),(x4),(x5),0,0) +#define strerr_die4x(e,x1,x2,x3,x4) \ +strerr_die((e),(x1),(x2),(x3),(x4),0,0,0) +#define strerr_die3x(e,x1,x2,x3) \ +strerr_die((e),(x1),(x2),(x3),0,0,0,0) +#define strerr_die2x(e,x1,x2) \ +strerr_die((e),(x1),(x2),0,0,0,0,0) +#define strerr_die1x(e,x1) \ +strerr_die((e),(x1),0,0,0,0,0,0) + +#endif diff --git a/lib_dict/cdb/include/uint32.h b/lib_dict/cdb/include/uint32.h new file mode 100644 index 000000000..b5c7f40e1 --- /dev/null +++ b/lib_dict/cdb/include/uint32.h @@ -0,0 +1,11 @@ +#ifndef UINT32_H +#define UINT32_H + +typedef unsigned long uint32; + +extern void uint32_pack(char *,uint32); +extern void uint32_pack_big(char *,uint32); +extern void uint32_unpack(char *,uint32 *); +extern void uint32_unpack_big(char *,uint32 *); + +#endif diff --git a/lib_dict/changes.txt b/lib_dict/changes.txt new file mode 100644 index 000000000..d05131aa5 --- /dev/null +++ b/lib_dict/changes.txt @@ -0,0 +1,59 @@ +16) 2012.7.10 +16.1) compile: 支持 VC2003 的预编译功能,从而使编译速度更快 + +15) 2012.4.9 +15.1) bugfix: 修复了变参参数不对的地方 + +14) 2009.7.30 +14.1) 增加了对 tokyocabinet 的支持。该DB库功能比较全,在有些地方效率比BDB高, +但随机性比较大的情况下,还是BDB比较好些,并且BDB的稳定性还是最高的。 +注:有关 tokyocabinet 请参: http://tokyocabinet.sourceforge.net/ + +13) 2009.6.2-2009.6.4 +13.1) 完善了一些接口,增加了 key 的长度参数 key_len + +12) 2009.5.27 +12.1) bugfix: 在64位机上编译通过 +12.2) 直接将所依赖的库放在本项目内 + +11) 2009.5.22 +11.1) bugfix: dict_db.c 中自定义的比较函数有误 +11.2) feature: dict_db.c 引出几个全局变量 + +10) 2009.5.21 +10.1) dict_pool: 增加了分区表功能, 可以将存储分布在不同的磁盘分区上,从而 +提高磁盘的利用率 +10.2) bdb: 增加了排序功能 + +9) 2009.5.19 +9.1) dict_pool: 增加了可以对存储池中的具体的存储加锁的功能 + +8) 2009.4.24 +8.1) 其中的一个参数定义与 C++ 的语法 delete 冲突,统一改为 delete_it + +7) 2009.3.30 +7.1) unix_aio: 由BDB分配的内存应该统一采用 acl_myfree()/1 进行释放 +7.2) unix: 由BDB分配的内存应该统一采用 acl_myfree()/1 进行释放 + +6) 2009.3.16 +6.1) dict_db: 分配内存需要调用, acl_mymalloc/1, acl_myrealloc/2, 释放内存需要 +调用 acl_myfree/1 + +5) 2009.3.15 +5.1) dict_pool: 增加了删除接口 + +4) 2009.2.17 +4.1) unix/unix_aio: 完善了HTTP协议通讯的模式,可以支持长连接及短连接;错误信息 +回复的完善 +4.2) unix: http_service.c 中的宏调用 RETURN()内部不应调用函数,否则将会出现意外 + +3) 2009.1.23 +3.1) 增加了异步IO的服务器, 其效率要比多线程半非阻塞式的服务器提高50%以上, +如多线程服务器的速度为:38000 次每秒;而非阻塞式的效率可以达到62000 +次每秒以上, 而BDB的性能可以达到10-20万次每秒,所以瓶颈应该还在系统的网络IO上 + +2) 2009.1.22 +2.1) 以 ioctl_server 的 acl_master 服务器模板编写了个支持HTTP通信模式的 +服务器 +1) 2009.1.21 +1.1) dict 1.0.0 release diff --git a/lib_dict/include/dict.h b/lib_dict/include/dict.h new file mode 100644 index 000000000..8c8ed3490 --- /dev/null +++ b/lib_dict/include/dict.h @@ -0,0 +1,181 @@ +#ifndef _DICT_H_INCLUDED_ +#define _DICT_H_INCLUDED_ + +#include "lib_acl.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef DICT_DLL +# ifdef DICT_EXPORTS +# define DICT_API __declspec(dllexport) +# else +# define DICT_API __declspec(dllimport) +# endif +#else +# define DICT_API +#endif + + /* + * Generic dictionary interface - in reality, a dictionary extends this + * structure with private members to maintain internal state. + */ +typedef struct DICT { + char *type; /* for diagnostics */ + char *name; /* for diagnostics */ + int flags; /* see below */ + const char *(*lookup) (struct DICT *, char *, size_t, char **, size_t *); + void (*update) (struct DICT *, char *, size_t, char *, size_t); + int (*delete_it) (struct DICT *, char *, size_t); + int (*sequence) (struct DICT *, int, char **, size_t *, char **, size_t *); + void (*sequence_reset)(struct DICT *); + int (*sequence_delcur)(struct DICT *); + void (*close) (struct DICT *); + ACL_FILE_HANDLE lock_fd; /* for dict_update() lock */ + ACL_FILE_HANDLE stat_fd; /* change detection */ + char db_path[256]; + time_t mtime; /* mod time at open */ + ACL_VSTRING *fold_buf; /* key folding buffer */ +} DICT; + +DICT_API DICT *dict_alloc(const char *dict_type, const char *dict_name, size_t size); +DICT_API void dict_free(DICT *dict); + +DICT_API DICT *dict_debug_main(DICT *dict); + +#define DICT_DEBUG(d) ((d)->flags & DICT_FLAG_DEBUG ? dict_debug_main(d) : (d)) + +#define DICT_FLAG_NONE (0) +#define DICT_FLAG_DUP_WARN (1<<0) /* if file, warn about dups */ +#define DICT_FLAG_DUP_IGNORE (1<<1) /* if file, ignore dups */ +#define DICT_FLAG_TRY0NULL (1<<2) /* do not append 0 to key/value */ +#define DICT_FLAG_TRY1NULL (1<<3) /* append 0 to key/value */ +#define DICT_FLAG_FIXED (1<<4) /* fixed key map */ +#define DICT_FLAG_PATTERN (1<<5) /* keys are patterns */ +#define DICT_FLAG_LOCK (1<<6) /* lock before access */ +#define DICT_FLAG_DUP_REPLACE (1<<7) /* if file, replace dups */ +#define DICT_FLAG_SYNC_UPDATE (1<<8) /* if file, sync updates */ +#define DICT_FLAG_DEBUG (1<<9) /* log access */ +#define DICT_FLAG_NO_REGSUB (1<<11) /* disallow regexp substitution */ +#define DICT_FLAG_NO_PROXY (1<<12) /* disallow proxy mapping */ +#define DICT_FLAG_NO_UNAUTH (1<<13) /* disallow unauthenticated data */ +#define DICT_FLAG_FOLD_FIX (1<<14) /* case-fold key with fixed-case map */ +#define DICT_FLAG_FOLD_MUL (1<<15) /* case-fold key with multi-case map */ +#define DICT_FLAG_FOLD_ANY (DICT_FLAG_FOLD_FIX | DICT_FLAG_FOLD_MUL) + + /* IMPORTANT: Update the dict_mask[] table when the above changes */ + + /* + * The subsets of flags that control how a map is used. These are relevant + * mainly for proxymap support. Note: some categories overlap. + * + * DICT_FLAG_PARANOID - flags that forbid the use of insecure map types for + * security-sensitive operations. These flags are specified by the caller, + * and are checked by the map implementation itself upon open, lookup etc. + * requests. + * + * DICT_FLAG_IMPL_MASK - flags that specify properties of the lookup table + * implementation. These flags are set by the map implementation itself. + * + * DICT_FLAG_INST_MASK - flags that control how a specific table instance is + * opened or used. The caller specifies these flags, and the caller may not + * change them between open, lookup, etc. requests (although the map itself + * may make changes to some of these flags). + * + * DICT_FLAG_NP_INST_MASK - ditto, but without the paranoia flags. + * + * DICT_FLAG_RQST_MASK - flags that the caller specifies, and that the caller + * may change between open, lookup etc. requests. + */ +#define DICT_FLAG_PARANOID \ + (DICT_FLAG_NO_REGSUB | DICT_FLAG_NO_PROXY | DICT_FLAG_NO_UNAUTH) +#define DICT_FLAG_IMPL_MASK (DICT_FLAG_FIXED | DICT_FLAG_PATTERN) +#define DICT_FLAG_RQST_MASK (DICT_FLAG_FOLD_ANY | DICT_FLAG_LOCK | \ + DICT_FLAG_DUP_REPLACE | DICT_FLAG_DUP_WARN | \ + DICT_FLAG_SYNC_UPDATE) +#define DICT_FLAG_NP_INST_MASK ~(DICT_FLAG_IMPL_MASK | DICT_FLAG_RQST_MASK) +#define DICT_FLAG_INST_MASK (DICT_FLAG_NP_INST_MASK | DICT_FLAG_PARANOID) + +/* global variables */ +extern int dict_unknown_allowed; +extern __thread int dict_errno; + +/* bdb global variables */ +extern int dict_db_cache_size; +extern int dict_db_page_size; + +#ifdef HAS_DB +#include "db.h" +extern int (*dict_db_cmpkey_fn)(DB*, const DBT*, const DBT*); +#endif + +#define DICT_ERR_NONE 0 /* no error */ +#define DICT_ERR_RETRY 1 /* soft error */ + + /* + * Sequence function types. + */ +#define DICT_SEQ_FUN_FIRST 0 /* set cursor to first record */ +#define DICT_SEQ_FUN_NEXT 1 /* set cursor to next record */ + + /* + * Interface for dictionary types. + */ +DICT_API ACL_ARGV *dict_mapnames(void); + + /* + * High-level interface, with logical dictionary names. + */ +DICT_API void dict_init(void); +DICT_API void dict_register(const char *dict_name, DICT *dict_info); +DICT_API DICT *dict_handle(const char *dict_name); +DICT_API void dict_unregister(const char *dict_name); +DICT_API void dict_update(const char *dict_name, char *key, char *value, size_t len); +DICT_API const char *dict_lookup(const char *dict_name, char *member, + char **value, size_t *size); +DICT_API int dict_delete(const char *dict_name, char *key); +DICT_API int dict_sequence(const char *dict_name, const int func, char **key, + size_t *key_size, char **value, size_t *value_size); +DICT_API void dict_sequence_reset(const char *dict_name); +DICT_API int dict_sequence_delcur(const char *dict_name); +DICT_API void dict_load_file(const char *dict_name, const char *path); +DICT_API void dict_load_fp(const char *dict_name, ACL_VSTREAM *fp); +DICT_API const char *dict_eval(char *dict_name, const char *value, int recursive); + + /* + * Low-level interface, with physical dictionary handles. + */ +DICT_API void dict_open_init(void); +DICT_API DICT *dict_open(const char *dict_spec, int open_flags, int dict_flags); +DICT_API DICT *dict_open3(const char *dict_type, const char *dict_name, + int open_flags, int dict_flags); +DICT_API void dict_open_register(const char *type, DICT *(*open_fn) (const char *, int, int)); + +#define DICT_GET(dp, key, key_len, value, size) \ + ((const char *) (dp)->lookup((dp), (key), (key_len), (value), (size))) +#define DICT_PUT(dp, key, key_len, val, len) \ + (dp)->update((dp), (key), (key_len), (val), (len)) +#define DICT_DEL(dp, key, key_len) \ + (dp)->delete_it((dp), (key), (key_len)) +#define DICT_SEQ(dp, f, key, key_size, val, val_size) \ + (dp)->sequence((dp), (f), (key), (key_size), (val), (val_size)) +#define DICT_RESET(dp) \ + (dp->sequence_reset(dp)) +#define DICT_DELCUR(dp) \ + (dp->sequence_delcur(dp)) +#define DICT_CLOSE(dp) \ + (dp)->close(dp) + +typedef void (*DICT_WALK_ACTION) (const char *, DICT *, char *); +DICT_API void dict_walk(DICT_WALK_ACTION action, char *ptr); +DICT_API int dict_changed(void); +DICT_API const char *dict_changed_name(void); +DICT_API const char *dict_flags_str(int dict_flags); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_dict/include/dict_pool.h b/lib_dict/include/dict_pool.h new file mode 100644 index 000000000..b5b0754d0 --- /dev/null +++ b/lib_dict/include/dict_pool.h @@ -0,0 +1,178 @@ +#ifndef __DICT_POOL_INCLUDE_H__ +#define __DICT_POOL_INCLUDE_H__ + +#include "lib_acl.h" +#include "dict.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct DICT_POOL DICT_POOL; + +typedef struct DICT_POOL_DB DICT_POOL_DB; + +/** + * 初始化,仅能被调用一次 + */ +DICT_API void dict_pool_init(void); + +/** + * 创建一个存储池 + * @param partions {const char*} 存储分区情况的字符串数组 + * @param partions_size {int} partions 分区的个数 + * @param dict_type {const char*} 存储类型 (btree/hash/cdb) + * @param dict_name {const char*} 存储池名 + * @param dict_size {int} 该存储池被分为几个存储分区 + * @return {DICT_POOL*} 存储池的对象指针, 若为 NULL 则表示创建失败 + */ +DICT_API DICT_POOL *dict_pool_new(const char **partions, int partions_size, + const char *dict_type, const char *dict_path, + const char *dict_name, int pool_size); + +/** + * 关闭并释放一个存储池 + * @param pool {DICT_POOL*} 某个存储池的对象指针 + */ +DICT_API void dict_pool_free(DICT_POOL *pool); + +/** + * 添加一个 key/value 对至一个存储池 + * @param pool {DICT_POOL*} 某个存储池的对象指针 + * @param key {char*} 健值地址 + * @param key_len {size_t} key 的长度 + * @param value {char*} 数据地址 + * @param len {size_t} value 数据的长度大小(字节) + * @return {int} 0: OK, < 0: Error + */ +DICT_API int dict_pool_set(DICT_POOL *pool, char *key, size_t key_len, char *value, size_t len); + +/** + * 从一个存储池中读取数据 + * @param pool {DICT_POOL*} 某个存储池的对象指针 + * @param key {char*} 健值地址 + * @param key_len {size_t} key 的长度 + * @param size {size_t*} 存储所读到数据对象的长度大小(字节) + * @param {char*} 所读到的数据地址,当为空时则表示该对象不存在, + * 注:如果返回的数据地址不为空,则调用者需在用完该返回数据对象后 + * 用 acl_myfree/1 释放掉该返回的动态内存地址 + */ +DICT_API char *dict_pool_get(DICT_POOL *pool, char *key, size_t key_len, size_t *size); + +/** + * 从一个存储池中删除数据 + * @param pool {DICT_POOL*} 某个存储池的对象指针 + * @param key {char*} 健值地址 + * @param key_len {size_t} key 的长度 + * @return {int} 0: ok; != 0: error + */ +DICT_API int dict_pool_del(DICT_POOL *pool, char *key, size_t key_len); + +/** + * 遍历存储中的所有数据 + * @param pool {DICT_POOL*} 某个存储池的对象指针 + * @param key {char**} 如果结果非空则存储健值结果, 如果返回值不为空, + * 则释放 key 需要调用: acl_myfree/1, 否则会造成内存泄露 + * @param key_size {size_t*} 若结果非空则存储健值结果的长度 + * @param val {char**} 如果结果非空则存储数据结果, 如果返回值不为空, + * 则释放 val 需要调用: acl_myfree/1, 否则 会造成内存泄露 + * @param val_size {size_t*} 如果结果非空则存储数据结果的长度 + * @return {int} 0: 表示结果非空, != 0: 表示结果为空 + */ +DICT_API int dict_pool_seq(DICT_POOL *pool, char **key, size_t *key_size, + char **val, size_t *val_size); + +/** + * 重置存储遍历对象 + * @param pool {DICT_POOL*} 某个存储池的对象指针 + */ +DICT_API void dict_pool_seq_reset(DICT_POOL *pool); + +/** + * 删除当前数据遍历光标所指的数据 + * @param pool {DICT_POOL*} 某个存储池的对象指针 + * @return {int} 0: 删除OK, != 0: 不存在或删除失败 + */ +DICT_API int dict_pool_seq_delcur(DICT_POOL *pool); + +/** + * 根据健值从存储池中获得该健所在的存储DB + * @param pool {DICT_POOL*} 某个存储池的对象指针 + * @param key {char*} 健值地址 + * @param key_len {size_t} key 的长度 + * @return {DICT_POOL_DB*} 存储DB + */ +DICT_API DICT_POOL_DB *dict_pool_db(DICT_POOL *pool, const char *key, size_t key_len); + +/** + * 获得某存储DB的文件全路径 + * @param pool {DICT_POOL*} 某个存储池的对象指针 + * @return {const char*} 存储文件名 + */ +DICT_API const char *dict_pool_db_path(DICT_POOL_DB *db); + +/** + * 加锁某个存储DB + * @param {DICT_POOL_DB*} 存储DB + */ +DICT_API void dict_pool_db_lock(DICT_POOL_DB *db); + +/** + * 解锁某个存储DB + * @param {DICT_POOL_DB*} 存储DB + */ +DICT_API void dict_pool_db_unlock(DICT_POOL_DB *db); + +/** + * 添加或修改数据 + * @param {DICT_POOL_DB*} 存储DB + * @param key {char*} 健值地址 + * @param key_len {size_t} key 的长度 + * @param value {char*} 值 + * @param len {size_t} value 长度 + * @return {int} 0: ok; < 0: error + */ +DICT_API int dict_pool_db_set(DICT_POOL_DB *db, char *key, size_t key_len, char *value, size_t len); + +/** + * 从存储DB中获得某个健所对应的值 + * @param {DICT_POOL_DB*} 存储DB + * @param key {char*} 健值地址 + * @param key_len {size_t} key 的长度 + * @param size {size_t*} 如果查询结果非空则存储返回结果的长度 + * @return {char*} 健所对应的值, 需要用 acl_myfree()/1 释放 + */ +DICT_API char *dict_pool_db_get(DICT_POOL_DB *db, char *key, size_t key_len, size_t *size); + +/** + * 从存储DB中删除某个健对应的值 + * @param {DICT_POOL_DB*} 存储DB + * @param key {char*} 健值地址 + * @param key_len {size_t} key 的长度 + * @return {int} 0: ok; != 0: error + */ +DICT_API int dict_pool_db_del(DICT_POOL_DB *db, char *key, size_t key_len); + +/** + * 重置之前曾遍历的存储DB + * @param {DICT_POOL_DB*} 存储DB + */ +DICT_API void dict_pool_db_seq_reset(DICT_POOL_DB *db); + +/** + * 遍历某个存储DB + * @param {DICT_POOL_DB*} 存储DB + * @param key {char**} 存储健的地址 + * @param key_size {size_t*} 存储在 key 中数据的长度 + * @param value {char**} 存储值的地址 + * @param value_size {size_t*} 存储在 value 中数据的长度 + * @return {int} 0: 表示结果非空, != 0: 表示结果为空 + */ +DICT_API int dict_pool_db_seq(DICT_POOL_DB *db, char **key, size_t *key_size, + char **val, size_t *val_size); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_dict/include/unescape.h b/lib_dict/include/unescape.h new file mode 100644 index 000000000..b136261de --- /dev/null +++ b/lib_dict/include/unescape.h @@ -0,0 +1,18 @@ +#ifndef __UNESCAPE_INCLUDE_H__ +#define __UNESCAPE_INCLUDE_H__ + +#include "lib_acl.h" +#include "dict.h" + +#ifdef __cplusplus +extern "C" { +#endif + +DICT_API ACL_VSTRING *unescape(ACL_VSTRING *result, const char *data); +DICT_API ACL_VSTRING *escape(ACL_VSTRING *result, const char *data, ssize_t len); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_dict/lib_dict.vcproj b/lib_dict/lib_dict.vcproj new file mode 100644 index 000000000..1f143b162 --- /dev/null +++ b/lib_dict/lib_dict.vcproj @@ -0,0 +1,331 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_dict/lib_dict.vcxproj b/lib_dict/lib_dict.vcxproj new file mode 100644 index 000000000..fd4f0de04 --- /dev/null +++ b/lib_dict/lib_dict.vcxproj @@ -0,0 +1,209 @@ +锘 + + + + Debug + Win32 + + + DebugDll + Win32 + + + ReleaseDll + Win32 + + + Release + Win32 + + + + {9E6E9FE9-EAAC-44BA-B463-70DE0233822E} + Win32Proj + + + + DynamicLibrary + MultiByte + + + DynamicLibrary + MultiByte + + + StaticLibrary + MultiByte + + + StaticLibrary + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + .\ + Debug\ + .\ + Release\ + .\ + DebugDll\ + .\ + ReleaseDll\ + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + $(ProjectName)_vc2010d + $(ProjectName)_d + $(ProjectName)_vc2010 + + + + Disabled + ..\lib_acl\include;.\include;.\bdb\include;.\src;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;HAS_BDB;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Use + $(ProjectName)_vc2010d.pdb + Level3 + ProgramDatabase + + + $(ProjectName)_vc2010d.lib + + + copy $(TargetName).lib ..\dist\lib\win32\$(TargetName).lib /Y + + + + + ..\lib_acl\include;.\include;.\bdb\include;.\src;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;HAS_BDB;%(PreprocessorDefinitions) + MultiThreaded + Use + $(ProjectName)_vc2010.pdb + Level3 + ProgramDatabase + + + $(ProjectName)_vc2010.lib + + + copy $(TargetName).lib ..\dist\lib\win32\$(TargetName).lib /Y + + + + + Disabled + ..\lib_acl\include;.\include;.\bdb\include;.\src;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;HAS_BDB;DICT_DLL;DICT_EXPORTS;ACL_DLL;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Use + Level3 + ProgramDatabase + + + libdb43.lib;lib_acl_d.lib;ws2_32.lib;%(AdditionalDependencies) + $(ProjectName)_d.dll + ..\lib\bdb;..\lib_acl;%(AdditionalLibraryDirectories) + true + true + true + + + copy $(TargetName).lib ..\dist\lib\win32\$(TargetName).lib /Y +copy $(TargetName).dll ..\dist\lib\win32\$(TargetName).dll /Y + + + + + + ..\lib_acl\include;.\include;.\bdb\include;.\src;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;HAS_BDB;DICT_DLL;DICT_EXPORTS;ACL_DLL;%(PreprocessorDefinitions) + MultiThreadedDLL + Use + Level3 + ProgramDatabase + + + libdb43.lib;lib_acl.lib;ws2_32.lib;%(AdditionalDependencies) + $(ProjectName).dll + ..\lib\bdb;..\lib_acl;%(AdditionalLibraryDirectories) + + + copy $(TargetName).lib ..\dist\lib\win32\$(TargetName).lib /Y +copy $(TargetName).dll ..\dist\lib\win32\$(TargetName).dll /Y + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Create + Create + Create + Create + + + + + + + + + + diff --git a/lib_dict/lib_dict.vcxproj.filters b/lib_dict/lib_dict.vcxproj.filters new file mode 100644 index 000000000..26b30ffbb --- /dev/null +++ b/lib_dict/lib_dict.vcxproj.filters @@ -0,0 +1,105 @@ +锘 + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx + + + + + 婧愭枃浠 + + + 婧愭枃浠 + + + 婧愭枃浠 + + + 婧愭枃浠 + + + 婧愭枃浠 + + + 婧愭枃浠 + + + 婧愭枃浠 + + + 婧愭枃浠 + + + 婧愭枃浠 + + + 澶存枃浠 + + + 澶存枃浠 + + + 澶存枃浠 + + + + + 婧愭枃浠 + + + 婧愭枃浠 + + + 婧愭枃浠 + + + 婧愭枃浠 + + + 婧愭枃浠 + + + 婧愭枃浠 + + + 婧愭枃浠 + + + 婧愭枃浠 + + + 婧愭枃浠 + + + 婧愭枃浠 + + + 婧愭枃浠 + + + 婧愭枃浠 + + + 婧愭枃浠 + + + 婧愭枃浠 + + + 婧愭枃浠 + + + + + + diff --git a/lib_dict/src/StdAfx.c b/lib_dict/src/StdAfx.c new file mode 100644 index 000000000..e717491df --- /dev/null +++ b/lib_dict/src/StdAfx.c @@ -0,0 +1 @@ +#include "StdAfx.h" diff --git a/lib_dict/src/StdAfx.h b/lib_dict/src/StdAfx.h new file mode 100644 index 000000000..71a8b21de --- /dev/null +++ b/lib_dict/src/StdAfx.h @@ -0,0 +1,22 @@ +#ifndef __STD_AFX_INCLUDE_H__ +#define __STD_AFX_INCLUDE_H__ + +# ifdef WIN32 +# include +# include +# ifdef __STDC_WANT_SECURE_LIB__ +int dict_secure_snprintf(char *buf, size_t size, const char *fmt, ...); +int dict_securev_snprintf(char *buf, size_t size, const char *fmt, va_list ap); +# define snprintf dict_secure_snprintf +# define vsnprintf dict_securev_snprintf +# else +# ifndef snprintf +# define snprintf _snprintf +# endif +# ifndef vsnprintf +# define vsnprintf _vsnprintf +# endif +# endif +# endif /* WIN2 */ +#include "lib_acl.h" +#endif diff --git a/lib_dict/src/debug_var.h b/lib_dict/src/debug_var.h new file mode 100644 index 000000000..86bd59170 --- /dev/null +++ b/lib_dict/src/debug_var.h @@ -0,0 +1,12 @@ +#ifndef __DEBUG_VAR_INCLUDE_H__ + +#define DEBUG_BASE 100 +#define DEBUG_MAC (DEBUG_BASE + 1) +#define DEBUG_NAME_MASK (DEBUG_BASE + 2) +#define DEBUG_DICT (DEBUG_BASE + 3) +#define DEBUG_DICT_OPEN (DEBUG_BASE + 4) +#define DEBUG_DICT_DB (DEBUG_BASE + 5) +#define DEBUG_DICT_POOL (DEBUG_BASE + 6) + +#define __DEBUG_VAR_INCLUDE_H__ +#endif diff --git a/lib_dict/src/dict.c b/lib_dict/src/dict.c new file mode 100644 index 000000000..31fce4042 --- /dev/null +++ b/lib_dict/src/dict.c @@ -0,0 +1,450 @@ +#include "StdAfx.h" +#include +#include +#include +#include +#include "debug_var.h" +#include "mac_expand.h" +#include "dict.h" +#include "name_mask.h" +#include "dict_ht.h" + +/* + * By default, use a sane default for an unknown name. + */ +int dict_unknown_allowed = 1; +__thread int dict_errno = 0; + +static ACL_HTABLE *dict_table; + +/* + * Each (name, dictionary) instance has a reference count. The count is part + * of the name, not the dictionary. The same dictionary may be registered + * under multiple names. The structure below keeps track of instances and + * reference counts. + */ +typedef struct { + DICT *dict; + int refcount; +} DICT_NODE; + +#define dict_node(dict) \ + (dict_table ? (DICT_NODE *) acl_htable_find(dict_table, dict) : 0) + +#define STR(x) acl_vstring_str(x) + +void dict_init() +{ + const char *myname = "dict_init"; + + if (dict_table != 0) { + acl_msg_warn("%s: multiple initialization, return", myname); + return; + } + + dict_open_init(); + dict_table = acl_htable_create(0, 0); +} + +/* dict_register - make association with dictionary */ + +void dict_register(const char *dict_name, DICT *dict_info) +{ + const char *myname = "dict_register"; + DICT_NODE *node; + + if (dict_table == 0) + acl_msg_fatal("%s(%d): call dict_init first", myname, __LINE__); + if ((node = dict_node(dict_name)) == 0) { + node = (DICT_NODE *) acl_mymalloc(sizeof(*node)); + node->dict = dict_info; + node->refcount = 0; + acl_htable_enter(dict_table, dict_name, (char *) node); + } else if (dict_info != node->dict) + acl_msg_fatal("%s: dictionary name exists: %s", myname, dict_name); + node->refcount++; + acl_debug(DEBUG_DICT, 2) ("%s: %s %d", myname, dict_name, node->refcount); +} + +/* dict_handle - locate generic dictionary handle */ + +DICT *dict_handle(const char *dict_name) +{ + DICT_NODE *node; + + return ((node = dict_node(dict_name)) != 0 ? node->dict : 0); +} + +/* dict_node_free - dict_unregister() callback */ + +static void dict_node_free(void *ptr) +{ + DICT_NODE *node = (DICT_NODE *) ptr; + DICT *dict = node->dict; + + if (dict->close) + dict->close(dict); + acl_myfree(node); +} + +/* dict_unregister - break association with named dictionary */ + +void dict_unregister(const char *dict_name) +{ + const char *myname = "dict_unregister"; + DICT_NODE *node; + + if (dict_table == 0) + acl_msg_fatal("%s(%d): call dict_init first", myname, __LINE__); + if ((node = dict_node(dict_name)) == 0) + acl_msg_panic("non-existing dictionary: %s", dict_name); + acl_debug(DEBUG_DICT, 2)("%s: %s %d", myname, dict_name, node->refcount); + if (--(node->refcount) == 0) + acl_htable_delete(dict_table, dict_name, dict_node_free); +} + +/* dict_update - replace or add dictionary entry */ + +void dict_update(const char *dict_name, char *key, char *value, size_t len) +{ + const char *myname = "dict_update"; + DICT_NODE *node; + DICT *dict; + + if (dict_table == 0) + acl_msg_fatal("%s(%d): call dict_init first", myname, __LINE__); + if ((node = dict_node(dict_name)) == 0) { + if (dict_unknown_allowed == 0) + acl_msg_fatal("%s: unknown dictionary: %s", myname, dict_name); + dict = dict_ht_open(dict_name, + acl_htable_create(0, 0), + (void (*)(void*)) acl_myfree_fn); + dict_register(dict_name, dict); + } else + dict = node->dict; + acl_debug(DEBUG_DICT, 2)("%s: %s = %s", myname, key, value); + dict->update(dict, key, strlen(key), value, len); +} + +/* dict_lookup - look up dictionary entry */ + +const char *dict_lookup(const char *dict_name, char *key, + char **value, size_t *size) +{ + const char *myname = "dict_lookup"; + DICT_NODE *node; + DICT *dict; + const char *ret = 0; + + if (dict_table == 0) + acl_msg_fatal("%s(%d): call dict_init first", myname, __LINE__); + if ((node = dict_node(dict_name)) == 0) { + if (dict_unknown_allowed == 0) + acl_msg_fatal("%s: unknown dictionary: %s", myname, dict_name); + } else { + dict = node->dict; + ret = dict->lookup(dict, key, strlen(key), value, size); + if (ret == 0 && dict_unknown_allowed == 0) + acl_msg_fatal("dictionary %s: unknown member: %s", dict_name, key); + } + acl_debug(DEBUG_DICT, 2)("%s: %s = %s", myname, key, ret ? ret : "(not found)"); + return (ret); +} + +/* dict_delete - delete dictionary entry */ + +int dict_delete(const char *dict_name, char *key) +{ + const char *myname = "dict_delete"; + DICT_NODE *node; + DICT *dict; + int result; + + if (dict_table == 0) + acl_msg_fatal("%s(%d): call dict_init first", myname, __LINE__); + if ((node = dict_node(dict_name)) == 0) { + if (dict_unknown_allowed == 0) + acl_msg_fatal("%s: unknown dictionary: %s", myname, dict_name); + dict = dict_ht_open(dict_name, + acl_htable_create(0, 0), + (void (*)(void*)) acl_myfree_fn); + dict_register(dict_name, dict); + } else + dict = node->dict; + acl_debug(DEBUG_DICT, 2)("%s: delete %s", myname, key); + if ((result = dict->delete_it(dict, key, strlen(key))) != 0 && dict_unknown_allowed == 0) + acl_msg_fatal("%s: dictionary %s: unknown member: %s", + myname, dict_name, key); + return (result); +} + +/* dict_sequence_reset - close the sequence cursor */ + +void dict_sequence_reset(const char *dict_name) +{ + const char *myname = "dict_sequence_reset"; + DICT_NODE *node; + DICT *dict; + + if (dict_table == 0) + acl_msg_fatal("%s(%d): call dict_init first", myname, __LINE__); + if ((node = dict_node(dict_name)) == 0) { + if (dict_unknown_allowed == 0) + acl_msg_fatal("%s: unknown dictionary: %s", myname, dict_name); + dict = dict_ht_open(dict_name, + acl_htable_create(0, 0), + (void (*)(void*)) acl_myfree_fn); + dict_register(dict_name, dict); + } else + dict = node->dict; + + if (dict->sequence_reset != NULL) + dict->sequence_reset(dict); +} + +/* dict_sequence_delcur - delete the data refered by the cursor */ + +int dict_sequence_delcur(const char *dict_name) +{ + const char *myname = "dict_sequence_delcur"; + DICT_NODE *node; + DICT *dict; + + if (dict_table == 0) + acl_msg_fatal("%s(%d): call dict_init first", myname, __LINE__); + if ((node = dict_node(dict_name)) == 0) { + if (dict_unknown_allowed == 0) + acl_msg_fatal("%s: unknown dictionary: %s", myname, dict_name); + dict = dict_ht_open(dict_name, + acl_htable_create(0, 0), + (void (*)(void*)) acl_myfree_fn); + dict_register(dict_name, dict); + } else + dict = node->dict; + + if (dict->sequence_delcur != NULL) + return (dict->sequence_delcur(dict)); + + return (-1); +} + +/* dict_sequence - traverse dictionary */ + +int dict_sequence(const char *dict_name, const int func, + char **key, size_t *key_size, char **value, size_t *value_size) +{ + const char *myname = "dict_sequence"; + DICT_NODE *node; + DICT *dict; + + if (dict_table == 0) + acl_msg_fatal("%s(%d): call dict_init first", myname, __LINE__); + if ((node = dict_node(dict_name)) == 0) { + if (dict_unknown_allowed == 0) + acl_msg_fatal("%s: unknown dictionary: %s", myname, dict_name); + dict = dict_ht_open(dict_name, + acl_htable_create(0, 0), + (void (*)(void*)) acl_myfree_fn); + dict_register(dict_name, dict); + } else + dict = node->dict; + acl_debug(DEBUG_DICT, 2)("%s: sequence func %d", myname, func); + return (dict->sequence(dict, func, key, key_size, value, value_size)); +} + +/* dict_load_file - read entries from text file */ + +void dict_load_file(const char *dict_name, const char *path) +{ + ACL_VSTREAM *fp; + struct acl_stat st; + time_t before; + time_t after; + + /* + * Read the file again if it is hot. This may result in reading a partial + * parameter name when a file changes in the middle of a read. + */ + for (before = time((time_t *) 0); /* see below */ ; before = after) { + if ((fp = acl_vstream_fopen(path, O_RDONLY, 0600, 0)) == 0) + acl_msg_fatal("open %s: %s", path, acl_last_serror()); + dict_load_fp(dict_name, fp); + if (acl_stat(ACL_VSTREAM_PATH(fp), &st) < 0) + acl_msg_fatal("fstat %s: %s", path, acl_last_serror()); + after = time((time_t *) 0); + if (st.st_mtime < before - 1 || st.st_mtime > after) + break; + acl_debug(DEBUG_DICT, 2)("pausing to let %s cool down", path); + acl_doze(300000); + } +} + +/* dict_load_fp - read entries from open stream */ + +void dict_load_fp(const char *dict_name, ACL_VSTREAM *fp) +{ + ACL_VSTRING *buf; + char *member; + char *val; + int lineno; + const char *err; + + buf = acl_vstring_alloc(100); + lineno = 0; + + while (acl_readlline(buf, fp, &lineno)) { + if ((err = acl_split_nameval(STR(buf), &member, &val)) != 0) + acl_msg_fatal("%s, line %d: %s: \"%s\"", + ACL_VSTREAM_PATH(fp), lineno, err, STR(buf)); + dict_update(dict_name, member, val, strlen(val)); + } + acl_vstring_free(buf); +} + +/* dict_eval_lookup - macro parser call-back routine */ + +static const char *dict_eval_lookup(char *key, int type acl_unused, + const char *dict_name, char **value, size_t *size) +{ + /* + * XXX how would one recover? + */ + if (dict_lookup(dict_name, key, value, size) == 0 && dict_errno != 0) + acl_msg_fatal("dictionary %s: lookup %s: temporary error", dict_name, key); + + return (*value); +} + +static void free_vstring_fn(void *arg) +{ + ACL_VSTRING *buf = (ACL_VSTRING*) arg; + + acl_vstring_free(buf); +} + +/* dict_eval - expand embedded dictionary references */ + +const char *dict_eval(char *dict_name, const char *value, int recursive) +{ + const char *myname = "dict_eval"; + static __thread ACL_VSTRING *buf = NULL; + int status; + + /* + * Initialize. + */ + if (buf == 0) { + buf = acl_vstring_alloc(10); + acl_pthread_atexit_add(buf, free_vstring_fn); + } + + /* + * Expand macros, possibly recursively. + */ +#define DONT_FILTER (char *) 0 + + status = mac_expand(buf, value, + recursive ? MAC_EXP_FLAG_RECURSE : MAC_EXP_FLAG_NONE, + DONT_FILTER, dict_eval_lookup, (char *) dict_name); + if (status & MAC_PARSE_ERROR) + acl_msg_fatal("dictionary %s: macro processing error", dict_name); + if (acl_do_debug(DEBUG_DICT, 2)) { + if (strcmp(value, STR(buf)) != 0) + acl_msg_info("%s: expand %s -> %s", myname, value, STR(buf)); + else + acl_msg_info("%s: const %s", myname, value); + } + return (STR(buf)); +} + +/* dict_walk - iterate over all dictionaries in arbitrary order */ + +void dict_walk(DICT_WALK_ACTION action, char *ptr) +{ + const char *myname = "dict_walk"; + ACL_HTABLE_INFO **ht_info_list; + ACL_HTABLE_INFO **ht; + ACL_HTABLE_INFO *h; + + if (dict_table == 0) + acl_msg_fatal("%s(%d): call dict_init first", myname, __LINE__); + ht_info_list = acl_htable_list(dict_table); + for (ht = ht_info_list; (h = *ht) != 0; ht++) + action(h->key.key, (DICT *) h->value, ptr); + acl_myfree(ht_info_list); +} + +/* dict_changed_name - see if any dictionary has changed */ + +const char *dict_changed_name(void) +{ + const char *myname = "dict_changed_name"; + struct acl_stat st; + ACL_HTABLE_INFO **ht_info_list; + ACL_HTABLE_INFO **ht; + ACL_HTABLE_INFO *h; + const char *status; + char ebuf[256]; + DICT *dict; + + if (dict_table == 0) + acl_msg_fatal("%s(%d): call dict_init first", myname, __LINE__); + ht_info_list = acl_htable_list(dict_table); + for (status = 0, ht = ht_info_list; status == 0 && (h = *ht) != 0; ht++) { + dict = ((DICT_NODE *) h->value)->dict; + if (dict->stat_fd < 0) /* not file-based */ + continue; + if (dict->mtime == 0) /* not bloody likely */ + acl_msg_warn("%s: table %s: null time stamp", myname, h->key.c_key); + if (acl_stat(dict->db_path, &st) < 0) + acl_msg_fatal("%s: fstat: %s", + myname, acl_last_strerror(ebuf, sizeof(ebuf))); + if (st.st_mtime != dict->mtime || st.st_nlink == 0) + status = h->key.c_key; + } + acl_myfree(ht_info_list); + return (status); +} + +/* dict_changed - backwards compatibility */ + +int dict_changed(void) +{ + return (dict_changed_name() != 0); +} + +/* + * Mapping between flag names and flag values. + */ +static const NAME_MASK dict_mask[] = { + { "warn_dup", (1 << 0), }, /* if file, warn about dups */ + { "ignore_dup", (1 << 1), }, /* if file, ignore dups */ + { "try0null", (1 << 2), }, /* do not append 0 to key/value */ + { "try1null", (1 << 3), }, /* append 0 to key/value */ + { "fixed", (1 << 4), }, /* fixed key map */ + { "pattern", (1 << 5), }, /* keys are patterns */ + { "lock", (1 << 6), }, /* lock before access */ + { "replace", (1 << 7), }, /* if file, replace dups */ + { "sync_update", (1 << 8), }, /* if file, sync updates */ + { "debug", (1 << 9), }, /* log access */ + { "no_regsub", (1 << 11), }, /* disallow regexp substitution */ + { "no_proxy", (1 << 12), }, /* disallow proxy mapping */ + { "no_unauth", (1 << 13), }, /* disallow unauthenticated data */ + { "fold_fix", (1 << 14), }, /* case-fold with fixed-case key map */ + { "fold_mul", (1 << 15), }, /* case-fold with multi-case key map */ +}; + +/* dict_flags_str - convert mask to string for debugging purposes */ + +const char *dict_flags_str(int dict_flags) +{ + static __thread ACL_VSTRING *buf = 0; + + if (buf == 0) { + buf = acl_vstring_alloc(1); + acl_pthread_atexit_add(buf, free_vstring_fn); + } + + return (str_name_mask_opt(buf, "dictionary flags", dict_mask, dict_flags, + NAME_MASK_RETURN | NAME_MASK_PIPE)); +} diff --git a/lib_dict/src/dict_alloc.c b/lib_dict/src/dict_alloc.c new file mode 100644 index 000000000..67df56414 --- /dev/null +++ b/lib_dict/src/dict_alloc.c @@ -0,0 +1,101 @@ +#include "StdAfx.h" +#include "dict.h" + +/* dict_default_lookup - trap unimplemented operation */ + +static const char *dict_default_lookup(DICT *dict, char *key acl_unused, size_t key_len acl_unused, + char **value acl_unused, size_t *size acl_unused) +{ + acl_msg_fatal("%s table %s: lookup operation is not supported", + dict->type, dict->name); + return (NULL); +} + +/* dict_default_update - trap unimplemented operation */ + +static void dict_default_update(DICT *dict, char *key acl_unused, size_t key_len acl_unused, + char *value acl_unused, size_t len acl_unused) +{ + acl_msg_fatal("%s table %s: update operation is not supported", + dict->type, dict->name); +} + +/* dict_default_delete - trap unimplemented operation */ + +static int dict_default_delete(DICT *dict, char *key acl_unused, size_t key_len acl_unused) +{ + acl_msg_fatal("%s table %s: delete operation is not supported", + dict->type, dict->name); + /* not reached */ + return (-1); +} + +/* dict_default_sequence_reset - trap unimplemented operation */ + +static void dict_default_sequence_reset(DICT *dict) +{ + acl_msg_fatal("%s table %s: sequence_reset operation is not supported", + dict->type, dict->name); +} + +/* dict_default_sequence_delcur - trap unimplemented operation */ + +static int dict_default_sequence_delcur(DICT *dict) +{ + acl_msg_fatal("%s table %s: sequence_delcur operation is not supported", + dict->type, dict->name); + /* not reached */ + return (-1); +} + +/* dict_default_sequence - trap unimplemented operation */ + +static int dict_default_sequence(DICT *dict, int function acl_unused, + char **key acl_unused, size_t *key_size acl_unused, + char **value acl_unused, size_t *value_size acl_unused) +{ + acl_msg_fatal("%s table %s: sequence operation is not supported", + dict->type, dict->name); + /* not reached */ + return (-1); +} + +/* dict_default_close - trap unimplemented operation */ + +static void dict_default_close(DICT *dict) +{ + acl_msg_fatal("%s table %s: close operation is not supported", + dict->type, dict->name); +} + +/* dict_alloc - allocate dictionary object, initialize super-class */ + +DICT *dict_alloc(const char *dict_type, const char *dict_name, size_t size) +{ + DICT *dict = (DICT *) acl_mymalloc(size); + + dict->type = acl_mystrdup(dict_type); + dict->name = acl_mystrdup(dict_name); + dict->flags = DICT_FLAG_FIXED; + dict->lookup = dict_default_lookup; + dict->update = dict_default_update; + dict->delete_it = dict_default_delete; + dict->sequence = dict_default_sequence; + dict->sequence_reset = dict_default_sequence_reset; + dict->sequence_delcur = dict_default_sequence_delcur; + dict->close = dict_default_close; + dict->lock_fd = ACL_FILE_INVALID; + dict->stat_fd = ACL_FILE_INVALID; + dict->mtime = 0; + dict->fold_buf = 0; + return (dict); +} + +/* dict_free - super-class destructor */ + +void dict_free(DICT *dict) +{ + acl_myfree(dict->type); + acl_myfree(dict->name); + acl_myfree(dict); +} diff --git a/lib_dict/src/dict_cdb.c b/lib_dict/src/dict_cdb.c new file mode 100644 index 000000000..a0a1431d7 --- /dev/null +++ b/lib_dict/src/dict_cdb.c @@ -0,0 +1,376 @@ +#include "StdAfx.h" + +#ifdef HAS_CDB +#include +#include +#include +#include +#include + +#include "debug_var.h" +#include "dict.h" +#include "dict_cdb.h" + +#include +#ifndef TINYCDB_VERSION +#include +#endif +#ifndef cdb_fileno +#define cdb_fileno(c) ((c)->fd) +#endif + +#ifndef CDB_SUFFIX +#define CDB_SUFFIX ".cdb" +#endif +#ifndef CDB_TMP_SUFFIX +#define CDB_TMP_SUFFIX CDB_SUFFIX ".tmp" +#endif + +/* Application-specific. */ + +typedef struct { + DICT dict; /* generic members */ + struct cdb cdb; /* cdb structure */ +} DICT_CDBQ; /* query interface */ + +typedef struct { + DICT dict; /* generic members */ + struct cdb_make cdbm; /* cdb_make structure */ + char *cdb_path; /* cdb pathname (.cdb) */ + char *tmp_path; /* temporary pathname (.tmp) */ +} DICT_CDBM; /* rebuild interface */ + +/* dict_cdbq_lookup - find database entry, query mode */ + +static const char *dict_cdbq_lookup(DICT *dict, char *name, size_t name_len, char **value, size_t *size) +{ + DICT_CDBQ *dict_cdbq = (DICT_CDBQ *) dict; + unsigned vlen; + int status = 0; + char *buf = NULL; + char *result = NULL; + + dict_errno = 0; + + if (size) + *size = 0; + if (value == NULL) + acl_msg_fatal("dict_db_lookup: value null"); + + /* CDB is constant, so do not try to acquire a lock. */ + + /* + * Optionally fold the key. + */ + if (dict->flags & DICT_FLAG_FOLD_FIX) { + if (dict->fold_buf == 0) + dict->fold_buf = acl_vstring_alloc(10); + acl_vstring_strcpy(dict->fold_buf, name); + name = acl_lowercase(acl_vstring_str(dict->fold_buf)); + } + + /* + * See if this CDB file was written with one null byte appended to key + * and value. + */ + if (dict->flags & DICT_FLAG_TRY1NULL) { + status = cdb_find(&dict_cdbq->cdb, name, name_len + 1); + if (status > 0) + dict->flags &= ~DICT_FLAG_TRY0NULL; + } + + /* + * See if this CDB file was written with no null byte appended to key and + * value. + */ + if (status == 0 && (dict->flags & DICT_FLAG_TRY0NULL)) { + status = cdb_find(&dict_cdbq->cdb, name, name_len); + if (status > 0) + dict->flags &= ~DICT_FLAG_TRY1NULL; + } + if (status < 0) + acl_msg_fatal("error reading %s: %s", dict->name, acl_last_serror()); + + if (status) { + vlen = cdb_datalen(&dict_cdbq->cdb); + buf = acl_mymalloc(vlen + 1); + if (cdb_read(&dict_cdbq->cdb, buf, vlen, + cdb_datapos(&dict_cdbq->cdb)) < 0) + acl_msg_fatal("error reading %s: %s", dict->name, acl_last_serror()); + buf[vlen] = '\0'; + result = buf; + } + /* No locking so not release the lock. */ + + *value = result; + return (result); +} + +/* dict_cdbq_close - close data base, query mode */ + +static void dict_cdbq_close(DICT *dict) +{ + DICT_CDBQ *dict_cdbq = (DICT_CDBQ *) dict; + + cdb_free(&dict_cdbq->cdb); + close(dict->stat_fd); + if (dict->fold_buf) + acl_vstring_free(dict->fold_buf); + dict_free(dict); +} + +/* dict_cdbq_open - open data base, query mode */ + +static DICT *dict_cdbq_open(const char *path, int dict_flags) +{ + DICT_CDBQ *dict_cdbq; + struct stat st; + char *cdb_path; + int fd; + + cdb_path = acl_concatenate(path, CDB_SUFFIX, (char *) 0); + + if ((fd = open(cdb_path, O_RDONLY)) < 0) + acl_msg_fatal("%s(%d), %s: open database %s: %s", + __FILE__, __LINE__, __FUNCTION__, cdb_path, acl_last_serror()); + + dict_cdbq = (DICT_CDBQ *) dict_alloc(DICT_TYPE_CDB, + cdb_path, sizeof(*dict_cdbq)); +#if defined(TINYCDB_VERSION) + if (cdb_init(&(dict_cdbq->cdb), fd) != 0) + acl_msg_fatal("dict_cdbq_open: unable to init %s: %s", + cdb_path, acl_last_serror()); +#else + cdb_init(&(dict_cdbq->cdb), fd); +#endif + dict_cdbq->dict.lookup = dict_cdbq_lookup; + dict_cdbq->dict.close = dict_cdbq_close; + dict_cdbq->dict.stat_fd = fd; + if (fstat(fd, &st) < 0) + acl_msg_fatal("dict_dbq_open: fstat: %s", acl_last_serror()); + dict_cdbq->dict.mtime = st.st_mtime; + acl_close_on_exec(fd, ACL_CLOSE_ON_EXEC); + + /* + * Warn if the source file is newer than the indexed file, except when + * the source file changed only seconds ago. + */ + if (stat(path, &st) == 0 + && st.st_mtime > dict_cdbq->dict.mtime + && st.st_mtime < time((time_t *) 0) - 100) + acl_msg_warn("database %s is older than source file %s", cdb_path, path); + + /* + * If undecided about appending a null byte to key and value, choose to + * try both in query mode. + */ + if ((dict_flags & (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL)) == 0) + dict_flags |= DICT_FLAG_TRY0NULL | DICT_FLAG_TRY1NULL; + dict_cdbq->dict.flags = dict_flags | DICT_FLAG_FIXED; + if (dict_flags & DICT_FLAG_FOLD_FIX) + dict_cdbq->dict.fold_buf = acl_vstring_alloc(10); + + acl_myfree(cdb_path); + return (&dict_cdbq->dict); +} + +/* dict_cdbm_update - add database entry, create mode */ + +static void dict_cdbm_update(DICT *dict, char *name, size_t name_len, char *value, size_t size) +{ + DICT_CDBM *dict_cdbm = (DICT_CDBM *) dict; + unsigned ksize, vsize; +#ifdef TINYCDB_VERSION + int r; +#endif + + /* + * Optionally fold the key. + */ + if (dict->flags & DICT_FLAG_FOLD_FIX) { + if (dict->fold_buf == 0) + dict->fold_buf = acl_vstring_alloc(10); + acl_vstring_strcpy(dict->fold_buf, name); + name = acl_lowercase(acl_vstring_str(dict->fold_buf)); + } + ksize = name_len; + vsize = size; + + /* + * Optionally append a null byte to key and value. + */ + if (dict->flags & DICT_FLAG_TRY1NULL) { + ksize++; + vsize++; + } + + /* + * Do the add operation. No locking is done. + */ +#ifdef TINYCDB_VERSION +#ifndef CDB_PUT_ADD +#error please upgrate tinycdb to at least 0.5 version +#endif + if (dict->flags & DICT_FLAG_DUP_IGNORE) + r = CDB_PUT_ADD; + else if (dict->flags & DICT_FLAG_DUP_REPLACE) + r = CDB_PUT_REPLACE; + else + r = CDB_PUT_INSERT; + r = cdb_make_put(&dict_cdbm->cdbm, name, ksize, value, vsize, r); + if (r < 0) + acl_msg_fatal("error writing %s: %s", + dict_cdbm->tmp_path, acl_last_serror()); + else if (r > 0) { + if (dict->flags & (DICT_FLAG_DUP_IGNORE | DICT_FLAG_DUP_REPLACE)) + /* void */ ; + else if (dict->flags & DICT_FLAG_DUP_WARN) + acl_msg_warn("%s: duplicate entry: \"%s\"", + dict_cdbm->dict.name, name); + else + acl_msg_fatal("%s: duplicate entry: \"%s\"", + dict_cdbm->dict.name, name); + } +#else + if (cdb_make_add(&dict_cdbm->cdbm, name, ksize, value, vsize) < 0) + acl_msg_fatal("error writing %s: %s", + dict_cdbm->tmp_path, acl_last_serror()); +#endif +} + +/* dict_cdbm_close - close data base and rename file.tmp to file.cdb */ + +static void dict_cdbm_close(DICT *dict) +{ + DICT_CDBM *dict_cdbm = (DICT_CDBM *) dict; + int fd = cdb_fileno(&dict_cdbm->cdbm); + + /* + * Note: if FCNTL locking is used, closing any file descriptor on a + * locked file cancels all locks that the process may have on that file. + * CDB is FCNTL locking safe, because it uses the same file descriptor + * for database I/O and locking. + */ + if (cdb_make_finish(&dict_cdbm->cdbm) < 0) + acl_msg_fatal("finish database %s: %s", + dict_cdbm->tmp_path, acl_last_serror()); + + if (strcasecmp(dict_cdbm->tmp_path, dict_cdbm->cdb_path) != 0) { + if (rename(dict_cdbm->tmp_path, dict_cdbm->cdb_path) < 0) + acl_msg_fatal("rename database from %s to %s: %s", + dict_cdbm->tmp_path, dict_cdbm->cdb_path, acl_last_serror()); + } + + if (close(fd) < 0) /* releases a lock */ + acl_msg_fatal("close database %s: %s", + dict_cdbm->cdb_path, acl_last_serror()); + acl_myfree(dict_cdbm->cdb_path); + acl_myfree(dict_cdbm->tmp_path); + if (dict->fold_buf) + acl_vstring_free(dict->fold_buf); + dict_free(dict); +} + +/* dict_cdbm_open - create database as file.tmp */ + +static DICT *dict_cdbm_open(const char *path, int dict_flags) +{ + DICT_CDBM *dict_cdbm; + char *cdb_path; + char *tmp_path; + int fd; + struct stat st0, st1; + + cdb_path = acl_concatenate(path, CDB_SUFFIX, (char *) 0); +#if 0 + tmp_path = acl_concatenate(path, CDB_SUFFIX, (char *) 0); +#else + tmp_path = acl_concatenate(path, CDB_TMP_SUFFIX, (char *) 0); +#endif + + /* + * Repeat until we have opened *and* locked *existing* file. Since the + * new (tmp) file will be renamed to be .cdb file, locking here is + * somewhat funny to work around possible race conditions. Note that we + * can't open a file with O_TRUNC as we can't know if another process + * isn't creating it at the same time. + */ + for (;;) { + if ((fd = open(tmp_path, O_RDWR | O_CREAT, 0644)) < 0 + || fstat(fd, &st0) < 0) + acl_msg_fatal("%s(%d), %s: open database %s: %s", + __FILE__, __LINE__, __FUNCTION__, tmp_path, acl_last_serror()); + + /* + * Get an exclusive lock - we're going to change the database so we + * can't have any spectators. + */ + if (acl_myflock(fd, ACL_INTERNAL_LOCK, ACL_MYFLOCK_OP_EXCLUSIVE) < 0) + acl_msg_fatal("lock %s: %s", tmp_path, acl_last_serror()); + + if (stat(tmp_path, &st1) < 0) + acl_msg_fatal("stat(%s): %s", tmp_path, acl_last_serror()); + + /* + * Compare file's state before and after lock: should be the same, + * and nlinks should be >0, or else we opened non-existing file... + */ + if (st0.st_ino == st1.st_ino && st0.st_dev == st1.st_dev + && st0.st_rdev == st1.st_rdev && st0.st_nlink == st1.st_nlink + && st0.st_nlink > 0) + break; /* successefully opened */ + + close(fd); + } + +#ifndef NO_FTRUNCATE + if (st0.st_size) + ftruncate(fd, 0); +#endif + + dict_cdbm = (DICT_CDBM *) dict_alloc(DICT_TYPE_CDB, path, + sizeof(*dict_cdbm)); + if (cdb_make_start(&dict_cdbm->cdbm, fd) < 0) + acl_msg_fatal("initialize database %s: %s", tmp_path, acl_last_serror()); + dict_cdbm->dict.close = dict_cdbm_close; + dict_cdbm->dict.update = dict_cdbm_update; + dict_cdbm->cdb_path = cdb_path; + dict_cdbm->tmp_path = tmp_path; + acl_close_on_exec(fd, ACL_CLOSE_ON_EXEC); + + /* + * If undecided about appending a null byte to key and value, choose a + * default to not append a null byte when creating a cdb. + */ + if ((dict_flags & (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL)) == 0) + dict_flags |= DICT_FLAG_TRY0NULL; + else if ((dict_flags & DICT_FLAG_TRY1NULL) + && (dict_flags & DICT_FLAG_TRY0NULL)) + dict_flags &= ~DICT_FLAG_TRY0NULL; + dict_cdbm->dict.flags = dict_flags | DICT_FLAG_FIXED; + if (dict_flags & DICT_FLAG_FOLD_FIX) + dict_cdbm->dict.fold_buf = acl_vstring_alloc(10); + + return (&dict_cdbm->dict); +} + +/* dict_cdb_open - open data base for query mode or create mode */ + +DICT *dict_cdb_open(const char *path, int open_flags, int dict_flags) +{ + switch (open_flags & (O_RDONLY | O_RDWR | O_WRONLY | O_CREAT | O_TRUNC)) { + case O_RDONLY: /* query mode */ + return dict_cdbq_open(path, dict_flags); + case O_WRONLY | O_CREAT | O_TRUNC: /* create mode */ + case O_RDWR | O_CREAT | O_TRUNC: /* sloppiness */ + return dict_cdbm_open(path, dict_flags); + default: + acl_msg_fatal("dict_cdb_open: inappropriate open flags for cdb database" + " - specify O_RDONLY or O_WRONLY|O_CREAT|O_TRUNC"); + } + + /* not reached */ + return (NULL); +} + +#endif /* HAS_CDB */ diff --git a/lib_dict/src/dict_cdb.h b/lib_dict/src/dict_cdb.h new file mode 100644 index 000000000..77195d842 --- /dev/null +++ b/lib_dict/src/dict_cdb.h @@ -0,0 +1,18 @@ +#ifndef _DICT_CDB_H_INCLUDED_ +#define _DICT_CDB_H_INCLUDED_ + +#ifdef HAS_CDB + +#include + + /* + * External interface. + */ +#define DICT_TYPE_CDB "cdb" + +extern DICT *dict_cdb_open(const char *, int, int); + +#endif + +#endif /* _DICT_CDB_H_INCLUDED_ */ + diff --git a/lib_dict/src/dict_db.c b/lib_dict/src/dict_db.c new file mode 100644 index 000000000..3957ac6c3 --- /dev/null +++ b/lib_dict/src/dict_db.c @@ -0,0 +1,1101 @@ +#include "StdAfx.h" +#include "dict.h" + +/* + * You can override the default dict_db_cache_size setting before calling + * dict_hash_open() or dict_btree_open(). This is done in mkmap_db_open() to + * set a larger memory pool for database (re)builds. + * + * XXX This should be specified via the DICT interface so that it becomes an + * object property, instead of being specified by poking a global variable + * so that it becomes a class property. + */ +int dict_db_cache_size = (1024 * 1024 * 1); /* default memory pool */ +int dict_db_page_size = 0; /* default same as the system pagesize */ + +#ifdef HAS_BDB +#include "debug_var.h" + +#ifdef WIN32 +# include "db.h" +# include +# define getcwd _getcwd +#else +# include "db.h" +#endif + +/* System library. */ + +#include +#include +#include +#include +#ifdef ACL_UNIX +# include +#endif +#include + +#if defined(_DB_185_H_) && defined(USE_FCNTL_LOCK) +#error "Error: this system must not use the db 1.85 compatibility interface" +#endif + +#ifndef DB_VERSION_MAJOR +#define DB_VERSION_MAJOR 1 +#define DICT_DB_GET(db, key, val, flag) db->get(db, key, val, flag) +#define DICT_DB_PUT(db, key, val, flag) db->put(db, key, val, flag) +#define DICT_DB_DEL(db, key, flag) db->del(db, key, flag) +#define DICT_DB_SYNC(db, flag) db->sync(db, flag) +#define DICT_DB_CLOSE(db) db->close(db) +#define DONT_CLOBBER R_NOOVERWRITE +#endif + +#if DB_VERSION_MAJOR > 1 +#define DICT_DB_GET(db, key, val, flag) sanitize(db->get(db, 0, key, val, flag)) +#define DICT_DB_PUT(db, tid, key, val, flag) sanitize(db->put(db, tid, key, val, flag)) +#define DICT_DB_DEL(db, key, flag) sanitize(db->del(db, 0, key, flag)) +#define DICT_DB_SYNC(db, flag) ((errno = db->sync(db, flag)) ? -1 : 0) +#define DICT_DB_CLOSE(db) ((errno = db->close(db, 0)) ? -1 : 0) +#define DONT_CLOBBER DB_NOOVERWRITE +#endif + +#if (DB_VERSION_MAJOR == 2 && DB_VERSION_MINOR < 6) +#define DICT_DB_CURSOR(db, curs) (db)->cursor((db), NULL, (curs)) +#else +#define DICT_DB_CURSOR(db, curs) (db)->cursor((db), NULL, (curs), 0) +#endif + +#ifndef DB_FCNTL_LOCKING +#define DB_FCNTL_LOCKING 0 +#endif + +#include "dict.h" +#include "dict_db.h" + +/* Application-specific. */ + +typedef struct { + DICT dict; /* generic members */ + DB *db; /* open db file */ +#if DB_VERSION_MAJOR > 1 + DBC *cursor; /* dict_db_sequence() */ + DB_ENV *dbenv; + int quit; +#endif +} DICT_DB; + +#define DICT_DB_NELM (1024 * 1024 * 10) + +__thread char ebuf[256]; + +static int compare_key(DB *dbp acl_unused, const DBT *a, const DBT *b); + +int (*dict_db_cmpkey_fn)(DB*, const DBT*, const DBT*) = compare_key; + +/*----------------------------------------------------------------------------*/ + +static void *dict_mem_malloc(size_t size) +{ + return (acl_mymalloc(size)); +} + +static void *dict_mem_realloc(void *ptr, size_t size) +{ + return (acl_myrealloc(ptr, size)); +} + +static void dict_mem_free(void *ptr) +{ + acl_myfree(ptr); +} + +#if DB_VERSION_MAJOR > 1 + +/* sanitize - sanitize db_get/put/del result */ + +static int sanitize(int status) +{ + /* + * XXX This is unclean but avoids a lot of clutter elsewhere. Categorize + * results into non-fatal errors (i.e., errors that we can deal with), + * success, or fatal error (i.e., all other errors). + */ + switch (status) { + case DB_NOTFOUND: /* get, del */ + case DB_KEYEXIST: /* put */ + errno = status; + return (1); /* non-fatal */ + case 0: + return (0); /* success */ + + case DB_KEYEMPTY: /* get, others? */ + status = EINVAL; + /* FALLTHROUGH */ + default: + errno = status; + return (-1); /* fatal */ + } +} + +#endif + +/* dict_db_lookup - find database entry */ + +static const char *dict_db_lookup(DICT *dict, char *name, size_t name_len, char **value, size_t *size) +{ + DICT_DB *dict_db = (DICT_DB *) dict; + DB *db = dict_db->db; + DBT db_key; + DBT db_value; + int status; + char *result = NULL; + + /* + * Sanity check. + */ + if ((dict->flags & (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL)) == 0) + acl_msg_panic("dict_db_lookup: no DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL flag"); + + if (size) + *size = 0; + if (value == NULL) + acl_msg_fatal("dict_db_lookup: value null"); + + dict_errno = 0; + memset(&db_key, 0, sizeof(db_key)); + memset(&db_value, 0, sizeof(db_value)); + db_value.flags = DB_DBT_MALLOC; + + /* + * Optionally fold the key. + */ + if (dict->flags & DICT_FLAG_FOLD_FIX) { + if (dict->fold_buf == 0) + dict->fold_buf = acl_vstring_alloc(10); + acl_vstring_strcpy(dict->fold_buf, name); + name = acl_lowercase(acl_vstring_str(dict->fold_buf)); + } + + /* + * Acquire a shared lock. + */ + + if ((dict->flags & DICT_FLAG_LOCK) + && acl_myflock(dict->lock_fd, ACL_MYFLOCK_STYLE_FLOCK, ACL_MYFLOCK_OP_SHARED) < 0) + acl_msg_fatal("%s: lock dictionary: %s", dict_db->dict.name, + acl_last_strerror(ebuf, sizeof(ebuf))); + + /* + * See if this DB file was written with one null byte appended to key and + * value. + */ + if (dict->flags & DICT_FLAG_TRY1NULL) { + db_key.data = (void *) name; + db_key.size = (int) name_len + 1; + if ((status = DICT_DB_GET(db, &db_key, &db_value, 0)) < 0) + acl_msg_fatal("error reading %s: %s", dict_db->dict.name, + db_strerror(errno)); + if (status == 0) { + dict->flags &= ~DICT_FLAG_TRY0NULL; + if (size) + *size = db_value.size; + result = db_value.data; + } + } + + /* + * See if this DB file was written with no null byte appended to key and + * value. + */ + if (result == 0 && (dict->flags & DICT_FLAG_TRY0NULL)) { + db_key.data = (void *) name; + db_key.size = (int) name_len; + if ((status = DICT_DB_GET(db, &db_key, &db_value, 0)) < 0) + acl_msg_fatal("error reading %s: %s", dict_db->dict.name, + db_strerror(errno)); + if (status == 0) { + dict->flags &= ~DICT_FLAG_TRY1NULL; + if (size) + *size = db_value.size; + result = db_value.data; + } + } + + /* + * Release the shared lock. + */ + if ((dict->flags & DICT_FLAG_LOCK) + && acl_myflock(dict->lock_fd, ACL_MYFLOCK_STYLE_FLOCK, ACL_MYFLOCK_OP_NONE) < 0) + acl_msg_fatal("%s: unlock dictionary: %s", dict_db->dict.name, + acl_last_strerror(ebuf, sizeof(ebuf))); + + *value = result; + return (result); +} + +/* dict_db_update - add or update database entry */ + +static void dict_db_update(DICT *dict, char *name, size_t name_len, char *value, size_t len) +{ + const char *myname = "dict_db_update"; + DICT_DB *dict_db = (DICT_DB *) dict; + DB *db = dict_db->db; + DBT db_key; + DBT db_value; + DB_TXN *tid = NULL; + int status; + + /* + * Sanity check. + */ + if ((dict->flags & (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL)) == 0) + acl_msg_panic("%s(%d): dict_db_update: no DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL flag", + myname, __LINE__); + + /* + * Avoid deadlock + */ + if (dict_db->cursor) { + dict_db->cursor->c_close(dict_db->cursor); + dict_db->cursor = NULL; + } + + /* + * Optionally fold the key. + */ + if (dict->flags & DICT_FLAG_FOLD_FIX) { + if (dict->fold_buf == 0) + dict->fold_buf = acl_vstring_alloc(10); + acl_vstring_strcpy(dict->fold_buf, name); + name = acl_lowercase(acl_vstring_str(dict->fold_buf)); + } + memset(&db_key, 0, sizeof(db_key)); + memset(&db_value, 0, sizeof(db_value)); + db_key.data = (void *) name; + db_key.size = (int) name_len; + db_value.data = (void *) value; + db_value.size = (int) len; + + /* + * If undecided about appending a null byte to key and value, choose a + * default depending on the platform. + */ + if ((dict->flags & DICT_FLAG_TRY1NULL) + && (dict->flags & DICT_FLAG_TRY0NULL)) { +#ifdef DB_NO_TRAILING_NULL + dict->flags &= ~DICT_FLAG_TRY1NULL; +#else + dict->flags &= ~DICT_FLAG_TRY0NULL; +#endif + } + + /* + * Optionally append a null byte to key and value. + */ + if (dict->flags & DICT_FLAG_TRY1NULL) { + db_key.size++; + db_value.size++; + } + + /* + * Acquire an exclusive lock. + */ + if ((dict->flags & DICT_FLAG_LOCK) + && acl_myflock(dict->lock_fd, ACL_MYFLOCK_STYLE_FLOCK, ACL_MYFLOCK_OP_EXCLUSIVE) < 0) + acl_msg_fatal("%s(%d): %s lock dictionary error %s", + myname, __LINE__, dict_db->dict.name, acl_last_strerror(ebuf, sizeof(ebuf))); + + /* + * Do the update. + */ + + while (1) { + /* Begin the transaction. */ + if (0 && (status = dict_db->dbenv->txn_begin(dict_db->dbenv, NULL, &tid, 0)) != 0) + acl_msg_fatal("txn_begin: %s", db_strerror(status)); + if ((status = DICT_DB_PUT(db, tid, &db_key, &db_value, + (dict->flags & DICT_FLAG_DUP_REPLACE) ? 0 : DONT_CLOBBER)) != 0) { + acl_msg_warn("%s(%d): (%u) writing %s: %s", myname, __LINE__, + (unsigned) acl_pthread_self(), dict_db->dict.name, db_strerror(errno)); + if (errno != DB_LOCK_DEADLOCK) + break; + if (tid && (status = tid->abort(tid)) != 0) + acl_msg_fatal("%s(%d): DB_TXN->abort error(%s)", + myname, __LINE__, db_strerror(status)); + } else + break; + } + + if (status) { + if (dict->flags & DICT_FLAG_DUP_IGNORE) { + /* void */ ; + } else if (dict->flags & DICT_FLAG_DUP_WARN) { + acl_msg_warn("%s(%d): %s: duplicate entry: \"%s\"", + myname, __LINE__, dict_db->dict.name, name); + } else { + acl_msg_fatal("%s(%d): %s: duplicate entry: \"%s\", %s", + myname, __LINE__, dict_db->dict.name, name, db_strerror(errno)); + } + } + + if (dict->flags & DICT_FLAG_SYNC_UPDATE) { + while (1) { + if ((status = DICT_DB_SYNC(db, 0)) != 0) { + acl_msg_warn("%s(%d): %s: flush dictionary: %s", + myname, __LINE__, dict_db->dict.name, db_strerror(errno)); + if (errno != DB_LOCK_DEADLOCK) + break; + } else + break; + } + } + + if (tid && (status = tid->commit(tid, 0)) != 0) { + acl_msg_fatal("%s(%d): commit error(%s)", + myname, __LINE__, db_strerror(status)); + } + + /* + * Release the exclusive lock. + */ + if ((dict->flags & DICT_FLAG_LOCK) + && acl_myflock(dict->lock_fd, ACL_MYFLOCK_STYLE_FLOCK, ACL_MYFLOCK_OP_NONE) < 0) + acl_msg_fatal("%s(%d): %s: unlock dictionary: %s", myname, __LINE__, + dict_db->dict.name, acl_last_strerror(ebuf, sizeof(ebuf))); +} + +/* delete one entry from the dictionary */ + +static int dict_db_delete(DICT *dict, char *name, size_t name_len) +{ + DICT_DB *dict_db = (DICT_DB *) dict; + DB *db = dict_db->db; + DBT db_key; + int status = 1; + int flags = 0; + + /* + * Sanity check. + */ + if ((dict->flags & (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL)) == 0) + acl_msg_panic("dict_db_delete: no DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL flag"); + + /* + * Avoid deadlock + */ + if (dict_db->cursor) { + dict_db->cursor->c_close(dict_db->cursor); + dict_db->cursor = NULL; + } + + /* + * Optionally fold the key. + */ + if (dict->flags & DICT_FLAG_FOLD_FIX) { + if (dict->fold_buf == 0) + dict->fold_buf = acl_vstring_alloc(10); + acl_vstring_strcpy(dict->fold_buf, name); + name = acl_lowercase(acl_vstring_str(dict->fold_buf)); + } + memset(&db_key, 0, sizeof(db_key)); + + /* + * Acquire an exclusive lock. + */ + if ((dict->flags & DICT_FLAG_LOCK) + && acl_myflock(dict->lock_fd, ACL_MYFLOCK_STYLE_FLOCK, ACL_MYFLOCK_OP_EXCLUSIVE) < 0) + acl_msg_fatal("%s: lock dictionary: %s", dict_db->dict.name, + acl_last_strerror(ebuf, sizeof(ebuf))); + + /* + * See if this DB file was written with one null byte appended to key and + * value. + */ + if (dict->flags & DICT_FLAG_TRY1NULL) { + db_key.data = (void *) name; + db_key.size = (int) name_len + 1; + while (1) { + if ((status = DICT_DB_DEL(db, &db_key, flags)) != 0) + acl_msg_warn("deleting from %s: %s", dict_db->dict.name, + db_strerror(errno)); + if (status == 0) { + dict->flags &= ~DICT_FLAG_TRY0NULL; + break; + } + } + } + + /* + * See if this DB file was written with no null byte appended to key and + * value. + */ + if (status > 0 && (dict->flags & DICT_FLAG_TRY0NULL)) { + db_key.data = (void *) name; + db_key.size = (int) name_len; + while (1) { + if ((status = DICT_DB_DEL(db, &db_key, flags)) != 0) + acl_msg_warn("deleting from %s: %s", dict_db->dict.name, + acl_last_strerror(ebuf, sizeof(ebuf))); + if (status == 0) { + dict->flags &= ~DICT_FLAG_TRY1NULL; + break; + } + } + } + if (dict->flags & DICT_FLAG_SYNC_UPDATE) { + while (1) { + if ((status = DICT_DB_SYNC(db, 0)) != 0) + acl_msg_fatal("%s: flush dictionary: %s", dict_db->dict.name, + db_strerror(errno)); + else + break; + } + } + + /* + * Release the exclusive lock. + */ + if ((dict->flags & DICT_FLAG_LOCK) + && acl_myflock(dict->lock_fd, ACL_MYFLOCK_STYLE_FLOCK, ACL_MYFLOCK_OP_NONE) < 0) + acl_msg_fatal("%s: unlock dictionary: %s", dict_db->dict.name, + acl_last_strerror(ebuf, sizeof(ebuf))); + + return status; +} + +/* dict_db_sequence_reset */ + +static void dict_db_sequence_reset(DICT *dict) +{ + DICT_DB *dict_db = (DICT_DB *) dict; + + if (dict_db->cursor) { + dict_db->cursor->c_close(dict_db->cursor); + dict_db->cursor = NULL; + } +} + +static int dict_db_sequence_delcur(DICT *dict) +{ + DICT_DB *dict_db = (DICT_DB *) dict; + + if (dict_db->cursor) { + return (dict_db->cursor->c_del(dict_db->cursor, 0)); + } + return (-1); +} + +/* dict_db_sequence - traverse the dictionary */ + +static int dict_db_sequence(DICT *dict, int function, + char **key, size_t *key_size, char **value, size_t *value_size) +{ + const char *myname = "dict_db_sequence"; + DICT_DB *dict_db = (DICT_DB *) dict; + DB *db = dict_db->db; + DBT db_key; + DBT db_value; + int status = 0; + int db_function = 0; + + *key = NULL; + if (key_size) + *key_size = 0; + *value = NULL; + if (value_size) + *value_size = 0; + +#if DB_VERSION_MAJOR > 1 + + /* + * Initialize. + */ + + dict_errno = 0; + memset(&db_key, 0, sizeof(db_key)); + memset(&db_value, 0, sizeof(db_value)); + db_key.flags = DB_DBT_MALLOC; + db_value.flags = DB_DBT_MALLOC; + + /* + * Determine the function. + */ + switch (function) { + case DICT_SEQ_FUN_FIRST: + if (dict_db->cursor == 0) + DICT_DB_CURSOR(db, &(dict_db->cursor)); + db_function = DB_FIRST; + break; + case DICT_SEQ_FUN_NEXT: + if (dict_db->cursor == 0) { + /* If the cursor is not yet initialized, + * DB_NEXT is identical to DB_FIRST--see BDB help + */ + DICT_DB_CURSOR(db, &(dict_db->cursor)); + /* acl_msg_panic("%s: no cursor", myname); */ + } + db_function = DB_NEXT; + break; + default: + acl_msg_panic("%s: invalid function %d", myname, function); + } + + /* + * Acquire a shared lock. + */ + if ((dict->flags & DICT_FLAG_LOCK) + && acl_myflock(dict->lock_fd, ACL_MYFLOCK_STYLE_FLOCK, ACL_MYFLOCK_OP_SHARED) < 0) + acl_msg_fatal("%s: lock dictionary: %s", dict_db->dict.name, + acl_last_strerror(ebuf, sizeof(ebuf))); + + /* + * Database lookup. + */ + status = dict_db->cursor->c_get(dict_db->cursor, &db_key, &db_value, db_function); + if (status != 0 && status != DB_NOTFOUND) + acl_msg_fatal("error [%d] seeking %s: %s", status, dict_db->dict.name, + db_strerror(errno)); + + /* + * Release the shared lock. + */ + if ((dict->flags & DICT_FLAG_LOCK) + && acl_myflock(dict->lock_fd, ACL_MYFLOCK_STYLE_FLOCK, ACL_MYFLOCK_OP_NONE) < 0) + acl_msg_fatal("%s: unlock dictionary: %s", dict_db->dict.name, + acl_last_strerror(ebuf, sizeof(ebuf))); + + if (status == 0) { + /* + * Copy the result so it is guaranteed null terminated. + */ + *key = db_key.data; + if (key_size) + *key_size = db_key.size; + *value = db_value.data; + if (value_size) + *value_size = db_value.size; + } else { + /* + * Avoid deadlock in update and delete functions + */ + if (dict_db->cursor) { + dict_db->cursor->c_close(dict_db->cursor); + dict_db->cursor = NULL; + } + + } + return (status); +#else + + /* + * determine the function + */ + switch (function) { + case DICT_SEQ_FUN_FIRST: + db_function = R_FIRST; + break; + case DICT_SEQ_FUN_NEXT: + db_function = R_NEXT; + break; + default: + acl_msg_panic("%s: invalid function %d", myname, function); + } + + /* + * Acquire a shared lock. + */ + if ((dict->flags & DICT_FLAG_LOCK) + && acl_myflock(dict->lock_fd, ACL_MYFLOCK_STYLE_FLOCK, ACL_MYFLOCK_OP_SHARED) < 0) + acl_msg_fatal("%s: lock dictionary: %s", dict_db->dict.name, + acl_last_strerror(ebuf, sizeof(ebuf))); + + if ((status = db->seq(db, &db_key, &db_value, db_function)) < 0) + acl_msg_fatal("error seeking %s: %s", dict_db->dict.name, + db_strerror(errno)); + + /* + * Release the shared lock. + */ + if ((dict->flags & DICT_FLAG_LOCK) + && myflock(dict->lock_fd, ACL_MYFLOCK_STYLE_FLOCK, ACL_MYFLOCK_OP_NONE) < 0) + acl_msg_fatal("%s: unlock dictionary: %s", dict_db->dict.name, + acl_last_strerror(ebuf, sizeof(ebuf))); + + if (status == 0) { + /* + * Copy the result so that it is guaranteed null terminated. + */ + *key = db_key.data; + if (key_size) + *key_size = db_key.size; + *value = db_value.data; + if (value_size) + *value_size = db_value.size; + } + return status; +#endif +} + +/* dict_db_close - close data base */ + +static void dict_db_close(DICT *dict) +{ + DICT_DB *dict_db = (DICT_DB *) dict; + int status; + +#if DB_VERSION_MAJOR > 1 + if (dict_db->cursor) + dict_db->cursor->c_close(dict_db->cursor); +#endif + if ((status = DICT_DB_SYNC(dict_db->db, 0)) != 0) + acl_msg_fatal("flush database %s: %s", dict_db->dict.name, + db_strerror(errno)); + if ((status = DICT_DB_CLOSE(dict_db->db)) != 0) + acl_msg_fatal("close database %s: %s", dict_db->dict.name, + db_strerror(errno)); +#if DB_VERSION_MAJOR > 2 + if (dict_db->dbenv) { + dict_db->quit = 1; + while (1) { + if (dict_db->quit == 2) + break; + sleep(1); + } + acl_msg_info("begin to sync db..."); + (void) dict_db->dbenv->memp_sync(dict_db->dbenv, NULL); + acl_msg_info("sync db ok."); + acl_msg_info("begin to close db..."); + (void) dict_db->dbenv->close(dict_db->dbenv, 0); + acl_msg_info("close db ok."); + } +#endif + if (dict->fold_buf) + acl_vstring_free(dict->fold_buf); + dict_free(dict); +} + +/* check_lock_thread - check deadlock for multi-threads */ + +static void *check_lock_thread(void *arg) +{ + DICT_DB *dict_db = (DICT_DB*) arg; + + while (!dict_db->quit) { + sleep(1); + (void) dict_db->dbenv->lock_detect(dict_db->dbenv, 0, DB_LOCK_YOUNGEST, NULL); + } + + return (NULL); +} + +/* memp_trickle_thread - put data from mem to disk */ + +static void *memp_trickle_thread(void *arg) +{ + DICT_DB *dict_db = (DICT_DB*) arg; + int wrote; + + while (!dict_db->quit) { + sleep(1); + (void) dict_db->dbenv->memp_trickle(dict_db->dbenv, 100, &wrote); + } + + dict_db->quit = 2; + return (NULL); +} + +/* create_backend_threads - open two backend threads */ + +static void create_backend_threads(DICT_DB* dict_db) +{ + acl_pthread_attr_t attr; + acl_pthread_t tid; + + acl_pthread_attr_init(&attr); + acl_pthread_attr_setdetachstate(&attr, 1); + acl_pthread_create(&tid, &attr, check_lock_thread, dict_db); + acl_pthread_create(&tid, &attr, memp_trickle_thread, dict_db); +} + +/* dict_db_open - open data base */ + +static int compare_key(DB *dbp acl_unused, const DBT *a, const DBT *b) +{ + size_t n = a->size > b->size ? b->size : b->size; + int ret = memcmp(a->data, b->data, n); + + if (ret != 0) + return (ret); + return (a->size - b->size); +} + +static DICT *dict_db_open(const char *class, const char *path, int open_flags, + int type, void *tweak acl_unused, int dict_flags) +{ + const char *myname = "dict_db_open"; + DICT_DB *dict_db; + struct acl_stat st; + DB *db; + char *saved_path = acl_mystrdup(path); /* [path/]dict_name */ + char *db_root, *db_home, *db_name, *db_path; + ACL_FILE_HANDLE lock_fd = ACL_FILE_INVALID; + int dbfd; + +#if DB_VERSION_MAJOR > 1 + int db_flags, env_flags = 0, size; +#endif +#if DB_VERSION_MAJOR > 2 + DB_ENV *dbenv; +#endif + + /* + * Mismatches between #include file and library are a common cause for + * trouble. + */ +#if DB_VERSION_MAJOR > 1 + int major_version; + int minor_version; + int patch_version; + + (void) db_version(&major_version, &minor_version, &patch_version); + if (major_version != DB_VERSION_MAJOR || minor_version != DB_VERSION_MINOR) + acl_msg_fatal("%s(%d): incorrect version of Berkeley DB: " + "compiled against %d.%d.%d, run-time linked against %d.%d.%d", + myname, __LINE__, + DB_VERSION_MAJOR, DB_VERSION_MINOR, DB_VERSION_PATCH, + major_version, minor_version, patch_version); + if (acl_do_debug(DEBUG_DICT_DB, 1)) { + acl_msg_info("Compiled against Berkeley DB: %d.%d.%d\n", + DB_VERSION_MAJOR, DB_VERSION_MINOR, DB_VERSION_PATCH); + acl_msg_info("Run-time linked against Berkeley DB: %d.%d.%d\n", + major_version, minor_version, patch_version); + } +#else + acl_debug(DEBUG_DICT_DB, 1) ("Compiled against Berkeley DB version 1"); +#endif + + /* saved_path: [path/]db_name */ + + db_name = strrchr(saved_path, '/'); + if (db_name == NULL) { + db_root = acl_mystrdup("db"); + db_home = acl_concatenate(db_root, "/", saved_path, ".d", (char*) 0); + db_name = acl_concatenate(saved_path, ".db", (char*) 0); + db_path = acl_concatenate(db_home, "/", db_name, (char*) 0); + } else { + *db_name++ = 0; + db_root = acl_mystrdup(saved_path); + db_home = acl_concatenate(db_root, "/", db_name, ".d", (char*) 0); + db_name = acl_concatenate(db_name, ".db", (char*) 0); + db_path = acl_concatenate(db_home, "/", db_name, (char*) 0); + } + + acl_make_dirs(db_home, 0700); + + /* + * Note: DICT_FLAG_LOCK is used only by programs that do fine-grained (in + * the time domain) locking while accessing individual database records. + * + * Programs such as postmap/postalias use their own large-grained (in the + * time domain) locks while rewriting the entire file. + * + * XXX DB version 4.1 will not open a zero-length file. This means we must + * open an existing file without O_CREAT|O_TRUNC, and that we must let + * db_open() create a non-existent file for us. + */ +#define LOCK_OPEN_FLAGS(f) ((f) & ~(O_CREAT|O_TRUNC)) + + if (dict_flags & DICT_FLAG_LOCK) { + if ((lock_fd = acl_file_open(db_path, LOCK_OPEN_FLAGS(open_flags), 0644)) == ACL_FILE_INVALID) { + if (errno != ENOENT) { +#ifdef ACL_MS_WINDOWS + if (acl_last_error() != ERROR_FILE_NOT_FOUND) +#endif + acl_msg_fatal("%s(%d): open file %s: %s(%d)", myname, __LINE__, + db_path, acl_last_strerror(ebuf, sizeof(ebuf)), acl_last_error()); + } + } else { + if (acl_myflock(lock_fd, ACL_MYFLOCK_STYLE_FLOCK, ACL_MYFLOCK_OP_SHARED) < 0) + acl_msg_fatal("%s(%d): shared-lock database %s for open: %s", + myname, __LINE__, path, acl_last_strerror(ebuf, sizeof(ebuf))); + } + } + + /* + * Use the DB 1.x programming interface. This is the default interface + * with 4.4BSD systems. It is also available via the db_185 compatibility + * interface, but that interface does not have the undocumented feature + * that we need to make file locking safe with POSIX fcntl() locking. + */ +#if DB_VERSION_MAJOR < 2 + if ((db = dbopen(db_path, open_flags, 0644, type, tweak)) == 0) + acl_msg_fatal("%s(%d): open database %s: %s", + myname, __LINE__, db_path, + acl_last_strerror(ebuf, sizeof(ebuf))); + dbfd = db->fd(db); +#endif + + /* + * Use the DB 2.x programming interface. Jump a couple extra hoops. + */ +#if DB_VERSION_MAJOR == 2 + db_flags = DB_FCNTL_LOCKING; + if (open_flags == O_RDONLY) + db_flags |= DB_RDONLY; + if (open_flags & O_CREAT) + db_flags |= DB_CREATE; + if (open_flags & O_TRUNC) + db_flags |= DB_TRUNCATE; + if ((errno = db_open(db_path, type, db_flags, 0644, 0, tweak, &db)) != 0) + acl_msg_fatal("%s(%d): open database %s: %s", + myname, __LINE__, db_path, + acl_last_strerror(ebuf, sizeof(ebuf))); + if (db == 0) + acl_msg_panic("db_open null result"); + if ((errno = db->fd(db, &dbfd)) != 0) + acl_msg_fatal("%s(%d): get database file descriptor: %s", + myname, __LINE__, acl_last_strerror(ebuf, sizeof(ebuf))); +#endif + + /* + * Use the DB 3.x programming interface. Jump even more hoops. + */ +#if DB_VERSION_MAJOR > 2 + if ((errno = db_env_create(&dbenv, 0)) != 0) { + acl_msg_fatal("%s(%d): db_env_create error(%s)", + myname, __LINE__, db_strerror(errno)); + } + dbenv->set_errfile(dbenv, NULL); + dbenv->set_errpfx(dbenv, NULL); + dbenv->set_alloc(dbenv, dict_mem_malloc, dict_mem_realloc, dict_mem_free); + if ((errno = dbenv->set_cachesize(dbenv, 0, dict_db_cache_size, 0)) != 0) { + acl_msg_fatal("%s(%d): set DB_ENV cache size %d: %s", + myname, __LINE__, dict_db_cache_size, db_strerror(errno)); + } + if ((errno = dbenv->set_mp_mmapsize(dbenv, 1024 * 1024 * 256)) != 0) { + acl_msg_fatal("%s(%d): set DB_ENV mmapsize size %d: %s", + myname, __LINE__, 1024 * 1024 * 100, db_strerror(errno)); + } +#if 0 + if ((errno = dbenv->set_flags(dbenv, DB_CDB_ALLDB | DB_REGION_INIT, 1)) != 0) { + acl_msg_fatal("set_flags error(%s)", db_strerror(errno)); + } + if ((errno = dbenv->set_encrypt(dbenv, "zsxxsz", DB_ENCRYPT_AES)) != 0) { + acl_msg_fatal("set_encrypt error(%s), errno(%d)", db_strerror(errno), errno); + } +#endif + env_flags = DB_CREATE + /* | DB_INIT_LOCK */ + | DB_INIT_LOG + | DB_PRIVATE + | DB_INIT_MPOOL + | DB_INIT_TXN + | DB_THREAD + /* | DB_USE_ENVIRON */; + /* + if ((errno = dbenv->set_data_dir(dbenv, db_home)) != 0) { + acl_msg_fatal("%s(%d): set_data_dir(%s) error(%s)", + myname, __LINE__, db_root, db_strerror(errno)); + } + */ + + if ((errno = dbenv->open(dbenv, db_home, env_flags, 0)) != 0) { + char curpath[256]; + + curpath[0] = 0; + getcwd(curpath, sizeof(curpath)); + acl_msg_fatal("%s(%d): open db_home=%s, %s, current path=%s", + myname, __LINE__, db_home, db_strerror(errno), curpath); + } else { + char curpath[256]; + + curpath[0] = 0; + getcwd(curpath, sizeof(curpath)); + acl_msg_info("%s(%d): current path=%s", myname, __LINE__, curpath); + } + + db_flags = /* DB_FCNTL_LOCKING |*/ DB_CREATE | DB_THREAD /* | DB_AUTO_COMMIT */; + if (open_flags == O_RDONLY) + db_flags |= DB_RDONLY; + if (open_flags & O_CREAT) + db_flags |= DB_CREATE; + if (open_flags & O_TRUNC) + db_flags |= DB_TRUNCATE; + + if ((errno = db_create(&db, dbenv, 0)) != 0) + acl_msg_fatal("%s(%d): create DB database: %s, %s", + myname, __LINE__, + acl_last_strerror(ebuf, sizeof(ebuf)), db_strerror(errno)); + if (db == 0) + acl_msg_panic("db_create null result"); + + if (dict_db_page_size > 0) { + if ((errno = db->set_pagesize(db, dict_db_page_size)) != 0) { + acl_msg_warn("set pagesize error %s", db_strerror(errno)); + } + } + if ((errno = db->get_pagesize(db, (unsigned *) &size)) == 0) { + acl_msg_info("open database: pagesize %d", size); + } + + db->set_errfile(db, NULL); + db->set_errpfx(db, NULL); + if ((errno = db->set_bt_compare(db, dict_db_cmpkey_fn)) != 0) { + acl_msg_fatal("%s(%d): set_bt_compare error(%s)", + myname, __LINE__, db_strerror(errno)); + } + + if (type == DB_HASH && db->set_h_nelem(db, DICT_DB_NELM) != 0) + acl_msg_fatal("%s(%d): set DB hash element count %d: %s", + myname, __LINE__, DICT_DB_NELM, + acl_last_strerror(ebuf, sizeof(ebuf))); +#if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR > 0) + if ((errno = db->open(db, 0, db_name, 0, type, db_flags, 0644)) != 0) { + char curpath[256]; + + curpath[0] = 0; + (void) getcwd(curpath, sizeof(curpath)); + acl_msg_fatal("%s(%d): open database %s: %s, %s, current path=%s", + myname, __LINE__, db_path, + acl_last_strerror(ebuf, sizeof(ebuf)), db_strerror(errno), + curpath); + } +#elif (DB_VERSION_MAJOR == 3 || DB_VERSION_MAJOR == 4) + if ((errno = db->open(db, db_name, 0, type, db_flags, 0644)) != 0) + acl_msg_fatal("%s(%d): open database %s: %s", + myname, __LINE__, db_path, + acl_last_strerror(ebuf, sizeof(ebuf))); +#else +#error "Unsupported Berkeley DB version" +#endif + if ((errno = db->fd(db, &dbfd)) != 0) + acl_msg_fatal("%s(%d): get database file descriptor: %s", + myname, __LINE__, acl_last_strerror(ebuf, sizeof(ebuf))); +#endif + if ((dict_flags & DICT_FLAG_LOCK) && lock_fd != ACL_FILE_INVALID) { + if (acl_myflock(lock_fd, ACL_MYFLOCK_STYLE_FLOCK, ACL_MYFLOCK_OP_NONE) < 0) + acl_msg_fatal("%s(%d): unlock database %s for open: %s", + myname, __LINE__, db_path, + acl_last_strerror(ebuf, sizeof(ebuf))); + if (acl_file_close(lock_fd) < 0) + acl_msg_fatal("%s(%d): close database %s: %s", + myname, __LINE__, db_path, + acl_last_strerror(ebuf, sizeof(ebuf))); + } + dict_db = (DICT_DB *) dict_alloc(class, path, sizeof(*dict_db)); + dict_db->dict.lookup = dict_db_lookup; + dict_db->dict.update = dict_db_update; + dict_db->dict.delete_it = dict_db_delete; + dict_db->dict.sequence = dict_db_sequence; + dict_db->dict.sequence_reset = dict_db_sequence_reset; + dict_db->dict.sequence_delcur = dict_db_sequence_delcur; + dict_db->dict.close = dict_db_close; + dict_db->dict.lock_fd = (ACL_FILE_HANDLE) FILE_HANDLE(dbfd); + dict_db->dict.stat_fd = (ACL_FILE_HANDLE) FILE_HANDLE(dbfd); +#if DB_VERSION_MAJOR > 2 + dict_db->dbenv = dbenv; + dict_db->quit = 0; +#endif + snprintf(dict_db->dict.db_path, sizeof(dict_db->dict.db_path), "%s", db_path); + if (acl_stat(dict_db->dict.db_path, &st) < 0) + acl_msg_fatal("%s(%d): dict_db_open: fstat(%s): %s", + myname, __LINE__, db_path, + acl_last_strerror(ebuf, sizeof(ebuf))); + dict_db->dict.mtime = st.st_mtime; + + /* + * Warn if the source file is newer than the indexed file, except when + * the source file changed only seconds ago. + */ + if ((dict_flags & DICT_FLAG_LOCK) != 0 + && acl_stat(path, &st) == 0 + && st.st_mtime > dict_db->dict.mtime + && st.st_mtime < time((time_t *) 0) - 100) + acl_msg_warn("database %s is older than source file %s", db_path, path); + +#ifdef ACL_UNIX + acl_close_on_exec(dict_db->dict.lock_fd, ACL_CLOSE_ON_EXEC); + acl_close_on_exec(dict_db->dict.stat_fd, ACL_CLOSE_ON_EXEC); +#endif + dict_db->dict.flags = dict_flags | DICT_FLAG_FIXED; + if ((dict_flags & (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL)) == 0) + dict_db->dict.flags |= (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL); + if (dict_flags & DICT_FLAG_FOLD_FIX) + dict_db->dict.fold_buf = acl_vstring_alloc(10); + dict_db->db = db; +#if DB_VERSION_MAJOR > 1 + dict_db->cursor = 0; +#endif + + acl_myfree(db_root); + acl_myfree(db_home); + acl_myfree(db_name); + acl_myfree(db_path); + acl_myfree(saved_path); + + if (dict_db) + create_backend_threads(dict_db); + + return (DICT_DEBUG (&dict_db->dict)); +} + +/* dict_hash_open - create association with data base */ + +DICT *dict_hash_open(const char *path, int open_flags, int dict_flags) +{ +#if DB_VERSION_MAJOR < 2 + HASHINFO tweak; + + memset((char *) &tweak, 0, sizeof(tweak)); + tweak.nelem = DICT_DB_NELM; + tweak.cachesize = dict_db_cache_size; +#endif +#if DB_VERSION_MAJOR == 2 + DB_INFO tweak; + + memset((char *) &tweak, 0, sizeof(tweak)); + tweak.h_nelem = DICT_DB_NELM; + tweak.db_cachesize = dict_db_cache_size; +#endif +#if DB_VERSION_MAJOR > 2 + void *tweak; + + tweak = 0; +#endif + return (dict_db_open(DICT_TYPE_HASH, path, open_flags, DB_HASH, + (void *) &tweak, dict_flags)); +} + +/* dict_btree_open - create association with data base */ + +DICT *dict_btree_open(const char *path, int open_flags, int dict_flags) +{ +#if DB_VERSION_MAJOR < 2 + BTREEINFO tweak; + + memset((char *) &tweak, 0, sizeof(tweak)); + tweak.cachesize = dict_db_cache_size; +#endif +#if DB_VERSION_MAJOR == 2 + DB_INFO tweak; + + memset((char *) &tweak, 0, sizeof(tweak)); + tweak.db_cachesize = dict_db_cache_size; +#endif +#if DB_VERSION_MAJOR > 2 + void *tweak; + + tweak = 0; +#endif + + return (dict_db_open(DICT_TYPE_BTREE, path, open_flags, DB_BTREE, + (void *) &tweak, dict_flags)); +} + +DB_ENV *dict_db_env(DICT *dict) +{ + DICT_DB *dict_db = (DICT_DB *) dict; + + return (dict_db->dbenv); +} + +#endif /* HAS_BDB */ diff --git a/lib_dict/src/dict_db.h b/lib_dict/src/dict_db.h new file mode 100644 index 000000000..c8541b7ff --- /dev/null +++ b/lib_dict/src/dict_db.h @@ -0,0 +1,26 @@ +#ifndef _DICT_DB_H_INCLUDED_ +#define _DICT_DB_H_INCLUDED_ + +#ifdef HAS_BDB +# include "db.h" +# include "dict.h" + + /* + * External interface. + */ +#define DICT_TYPE_HASH "hash" +#define DICT_TYPE_BTREE "btree" + +#ifdef ACL_UNIX +# define FILE_HANDLE(x) (x) +#elif defined(ACL_MS_WINDOWS) +# include +# define FILE_HANDLE(x) _get_osfhandle(x) +#endif +DICT *dict_hash_open(const char *path, int open_flags, int dict_flags); +DICT *dict_btree_open(const char *path, int open_flags, int dict_flags); +DB_ENV *dict_db_env(DICT *dict); + +#endif + +#endif diff --git a/lib_dict/src/dict_debug.c b/lib_dict/src/dict_debug.c new file mode 100644 index 000000000..c1b9af486 --- /dev/null +++ b/lib_dict/src/dict_debug.c @@ -0,0 +1,92 @@ +#include "StdAfx.h" +#include "dict.h" + +/* Application-specific. */ + +typedef struct { + DICT dict; /* the proxy service */ + DICT *real_dict; /* encapsulated object */ +} DICT_DEBUG; + +/* dict_debug_lookup - log lookup operation */ + +static const char *dict_debug_lookup(DICT *dict, char *key, size_t key_len, + char **value, size_t *size) +{ + DICT_DEBUG *dict_debug = (DICT_DEBUG *) dict; + const char *result; + + result = DICT_GET(dict_debug->real_dict, key, key_len, value, size); + acl_msg_info("%s:%s lookup: \"%s\" = \"%s\"", dict->type, dict->name, key, + result ? result : dict_errno ? "try again" : "not_found"); + return (result); +} + +/* dict_debug_update - log update operation */ + +static void dict_debug_update(DICT *dict, char *key, size_t key_len, char *value, size_t len) +{ + DICT_DEBUG *dict_debug = (DICT_DEBUG *) dict; + + acl_msg_info("%s:%s update: \"%s\" = \"%s\"", dict->type, dict->name, + key, value); + DICT_PUT(dict_debug->real_dict, key, key_len, value, len); +} + +/* dict_debug_delete - log delete operation */ + +static int dict_debug_delete(DICT *dict, char *key, size_t key_len) +{ + DICT_DEBUG *dict_debug = (DICT_DEBUG *) dict; + int result; + + result = DICT_DEL(dict_debug->real_dict, key, key_len); + acl_msg_info("%s:%s delete: \"%s\" = \"%s\"", dict->type, dict->name, key, + result ? "failed" : "success"); + return (result); +} + +/* dict_debug_sequence - log sequence operation */ + +static int dict_debug_sequence(DICT *dict, int function, + char **key, size_t *key_size, char **value, size_t *value_size) +{ + DICT_DEBUG *dict_debug = (DICT_DEBUG *) dict; + int result; + + result = DICT_SEQ(dict_debug->real_dict, function, key, key_size, value, value_size); + if (result == 0) + acl_msg_info("%s:%s sequence: \"%s\" = \"%s\"", + dict->type, dict->name, *key, *value); + else + acl_msg_info("%s:%s sequence: found EOF", dict->type, dict->name); + return (result); +} + +/* dict_debug_close - log operation */ + +static void dict_debug_close(DICT *dict) +{ + DICT_DEBUG *dict_debug = (DICT_DEBUG *) dict; + + DICT_CLOSE(dict_debug->real_dict); + dict_free(dict); +} + +/* dict_debug_main - encapsulate dictionary object and install proxies */ + +DICT *dict_debug_main(DICT *real_dict) +{ + DICT_DEBUG *dict_debug; + + dict_debug = (DICT_DEBUG *) dict_alloc(real_dict->type, + real_dict->name, sizeof(*dict_debug)); + dict_debug->dict.flags = real_dict->flags; /* XXX not synchronized */ + dict_debug->dict.lookup = dict_debug_lookup; + dict_debug->dict.update = dict_debug_update; + dict_debug->dict.delete_it = dict_debug_delete; + dict_debug->dict.sequence = dict_debug_sequence; + dict_debug->dict.close = dict_debug_close; + dict_debug->real_dict = real_dict; + return (&dict_debug->dict); +} diff --git a/lib_dict/src/dict_ht.c b/lib_dict/src/dict_ht.c new file mode 100644 index 000000000..6bb362c48 --- /dev/null +++ b/lib_dict/src/dict_ht.c @@ -0,0 +1,67 @@ +#include "StdAfx.h" +#include "dict.h" +#include "dict_ht.h" + +/* Application-specific. */ + +typedef struct { + DICT dict; /* generic members */ + ACL_HTABLE *table; /* hash table */ + void (*remove_fn) (void *); /* callback */ +} DICT_HT; + +/* dict_ht_lookup - find hash-table entry */ + +static const char *dict_ht_lookup(DICT *dict, char *name, size_t name_len acl_unused, + char **value, size_t *size) +{ + DICT_HT *dict_ht = (DICT_HT *) dict; + + dict_errno = 0; + + *value = acl_htable_find(dict_ht->table, name); + if (*value) + *size = strlen(*value); + return (*value); +} + +/* dict_ht_update - add or update hash-table entry */ + +static void dict_ht_update(DICT *dict, char *name, size_t name_len acl_unused, char *value, size_t len) +{ + DICT_HT *dict_ht = (DICT_HT *) dict; + ACL_HTABLE_INFO *ht; + + if ((ht = acl_htable_locate(dict_ht->table, name)) != 0) { + acl_myfree(ht->value); + } else { + ht = acl_htable_enter(dict_ht->table, name, (char *) 0); + } + ht->value = acl_mymemdup(value, len); +} + +/* dict_ht_close - disassociate from hash table */ + +static void dict_ht_close(DICT *dict) +{ + DICT_HT *dict_ht = (DICT_HT *) dict; + + if (dict_ht->remove_fn) + acl_htable_free(dict_ht->table, dict_ht->remove_fn); + dict_free(dict); +} + +/* dict_ht_open - create association with hash table */ + +DICT *dict_ht_open(const char *name, ACL_HTABLE *table, void (*remove_fn) (void *)) +{ + DICT_HT *dict_ht; + + dict_ht = (DICT_HT *) dict_alloc(DICT_TYPE_HT, name, sizeof(*dict_ht)); + dict_ht->dict.lookup = dict_ht_lookup; + dict_ht->dict.update = dict_ht_update; + dict_ht->dict.close = dict_ht_close; + dict_ht->table = table; + dict_ht->remove_fn = remove_fn; + return (&dict_ht->dict); +} diff --git a/lib_dict/src/dict_ht.h b/lib_dict/src/dict_ht.h new file mode 100644 index 000000000..d8a817fb2 --- /dev/null +++ b/lib_dict/src/dict_ht.h @@ -0,0 +1,14 @@ +#ifndef _DICT_HT_H_INCLUDED_ +#define _DICT_HT_H_INCLUDED_ + +#include "lib_acl.h" +#include + + /* + * External interface. + */ +#define DICT_TYPE_HT "internal" + +extern DICT *dict_ht_open(const char *, ACL_HTABLE *, void (*) (void *)); + +#endif diff --git a/lib_dict/src/dict_open.c b/lib_dict/src/dict_open.c new file mode 100644 index 000000000..d62fb6be1 --- /dev/null +++ b/lib_dict/src/dict_open.c @@ -0,0 +1,161 @@ +#include "StdAfx.h" +#include "dict_db.h" +#include "dict_cdb.h" +#include "dict_tc.h" +#include +#include +#include "debug_var.h" +#include "dict.h" + + /* + * lookup table for available map types. + */ +typedef struct { + char *type; + struct DICT *(*open) (const char *, int, int); +} DICT_OPEN_INFO; + +static DICT_OPEN_INFO dict_open_info[] = { +#ifdef HAS_CDB + { DICT_TYPE_CDB, dict_cdb_open, }, +#endif +#ifdef HAS_TC + { DICT_TYPE_TC, dict_tc_open }, +#endif +#ifdef SNAPSHOT + { DICT_TYPE_TCP, dict_tcp_open, }, +#endif +#ifdef HAS_SDBM + { DICT_TYPE_SDBM, dict_sdbm_open, }, +#endif +#ifdef HAS_DBM + { DICT_TYPE_DBM, dict_dbm_open, }, +#endif +#ifdef HAS_BDB + { DICT_TYPE_HASH, dict_hash_open, }, + { DICT_TYPE_BTREE, dict_btree_open, }, +#endif +#ifdef HAS_NIS + { DICT_TYPE_NIS, dict_nis_open, }, +#endif +#ifdef HAS_NISPLUS + { DICT_TYPE_NISPLUS, dict_nisplus_open, }, +#endif +#ifdef HAS_NETINFO + { DICT_TYPE_NETINFO, dict_ni_open, }, +#endif +#ifdef HAS_PCRE + { DICT_TYPE_PCRE, dict_pcre_open, }, +#endif +#ifdef HAS_POSIX_REGEXP + { DICT_TYPE_REGEXP, dict_regexp_open, }, +#endif + { NULL, NULL, }, +}; + +static ACL_HTABLE *dict_open_hash; + +/* dict_open_init - one-off initialization */ + +void dict_open_init(void) +{ + const char *myname = "dict_open_init"; + DICT_OPEN_INFO *dp; + + if (dict_open_hash != 0) { + acl_msg_warn("%s: multiple initialization, return", myname); + return; + } + dict_open_hash = acl_htable_create(10, 0); + + for (dp = dict_open_info; dp->type; dp++) + acl_htable_enter(dict_open_hash, dp->type, (char *) dp); +} + +/* dict_open - open dictionary */ + +DICT *dict_open(const char *dict_spec, int open_flags, int dict_flags) +{ + const char *myname = "dict_open"; + char *saved_dict_spec = acl_mystrdup(dict_spec); + char *dict_name; + DICT *dict; + + if ((dict_name = acl_split_at(saved_dict_spec, ':')) == 0) + acl_msg_fatal("%s: open dictionary: expecting \"type:[path/]name\" form instead of \"%s\"", + myname, dict_spec); + dict = dict_open3(saved_dict_spec, dict_name, open_flags, dict_flags); + acl_myfree(saved_dict_spec); + return (dict); +} + +/* dict_open3 - open dictionary */ + +DICT *dict_open3(const char *dict_type, const char *dict_name, + int open_flags, int dict_flags) +{ + const char *myname = "dict_open3"; + DICT_OPEN_INFO *dp; + DICT *dict; + + if (*dict_type == 0 || *dict_name == 0) + acl_msg_fatal("%s: open dictionary: expecting \"type:name\" form instead of \"%s:%s\"", + myname, dict_type, dict_name); + if (dict_open_hash == 0) + acl_msg_fatal("%s: dict_open_init should be called first", myname); + if ((dp = (DICT_OPEN_INFO *) acl_htable_find(dict_open_hash, dict_type)) == 0) + acl_msg_fatal("unsupported dictionary type: %s", dict_type); + if ((dict = dp->open(dict_name, open_flags, dict_flags)) == 0) + acl_msg_fatal("opening %s:%s %s", dict_type, dict_name, acl_last_serror()); + acl_debug(DEBUG_DICT_OPEN, 1)("%s: %s:%s", myname, dict_type, dict_name); + return (dict); +} + +/* dict_open_register - register dictionary type */ + +void dict_open_register(const char *type, + DICT *(*open_fn) (const char *, int, int)) +{ + const char *myname = "dict_open_register"; + DICT_OPEN_INFO *dp; + + if (dict_open_hash == 0) + acl_msg_fatal("%s: dict_open_init should be called first", myname); + if (acl_htable_find(dict_open_hash, type)) + acl_msg_panic("%s: dictionary type exists: %s", myname, type); + dp = (DICT_OPEN_INFO *) acl_mymalloc(sizeof(*dp)); + dp->type = acl_mystrdup(type); + dp->open = open_fn; + acl_htable_enter(dict_open_hash, dp->type, (char *) dp); +} + +/* dict_sort_alpha_cpp - qsort() callback */ + +static int dict_sort_alpha_cpp(const void *a, const void *b) +{ + return (strcmp(((char **) a)[0], ((char **) b)[0])); +} + +/* dict_mapnames - return an ARGV of available map_names */ + +ACL_ARGV *dict_mapnames() +{ + const char *myname = "dict_mapnames"; + ACL_HTABLE_INFO **ht_info; + ACL_HTABLE_INFO **ht; + DICT_OPEN_INFO *dp; + ACL_ARGV *mapnames; + + if (dict_open_hash == 0) + acl_msg_fatal("%s: dict_open_init should be called first", myname); + mapnames = acl_argv_alloc(acl_htable_used(dict_open_hash) + 1); + for (ht_info = ht = acl_htable_list(dict_open_hash); *ht; ht++) { + dp = (DICT_OPEN_INFO *) ht[0]->value; + acl_argv_add(mapnames, dp->type, ACL_ARGV_END); + } + qsort((void *) mapnames->argv, mapnames->argc, sizeof(mapnames->argv[0]), + dict_sort_alpha_cpp); + acl_myfree(ht_info); + acl_argv_terminate(mapnames); + return mapnames; +} diff --git a/lib_dict/src/dict_pool.c b/lib_dict/src/dict_pool.c new file mode 100644 index 000000000..487d87082 --- /dev/null +++ b/lib_dict/src/dict_pool.c @@ -0,0 +1,353 @@ +#include "StdAfx.h" +#include "dict.h" +#include "debug_var.h" +#include "dict_pool.h" + +#define STR acl_vstring_str +#define LEN ACL_VSTRING_LEN + +typedef struct POOL_PARTION { + ACL_VSTRING *path; + int db_cnt; + int obj_cnt; +} POOL_PARTION; + +struct DICT_POOL_DB { + DICT_POOL *pool; + ACL_VSTRING *dpath; + DICT *dict_read; + DICT *dict_write; + acl_pthread_mutex_t lock; + int seqcnt; + POOL_PARTION *partion; +}; + +struct DICT_POOL { + char *dict_name; + int pool_size; + unsigned (*hash_fn)(const void *key, size_t len); + int dict_cur; + DICT_POOL_DB *dbpool; + + POOL_PARTION *partions; + int partions_size; +}; + +void dict_pool_init(void) +{ + dict_init(); +} + +DICT_POOL *dict_pool_new(const char **partions, int partions_size, + const char *dict_type, const char *dict_path, + const char *dict_name, int pool_size) +{ + const char *myname = "dict_pool_new"; + DICT_POOL *pool = (DICT_POOL*) acl_mycalloc(1, sizeof(DICT_POOL)); + int i, j; + int open_flags; + int dict_flags = /* DICT_FLAG_LOCK | */ DICT_FLAG_DUP_REPLACE | DICT_FLAG_TRY0NULL; + int two_db = 0; + + if (partions == NULL) + acl_msg_fatal("%s(%d): partions null", myname, __LINE__); + if (partions_size <= 0) + acl_msg_fatal("%s(%d): partions_size(%d) <= 0", myname, __LINE__, partions_size); + if (dict_type == NULL || *dict_type == 0) + acl_msg_fatal("%s(%d): dict_type invalid", myname, __LINE__); + if (dict_path == NULL || *dict_path == 0) + acl_msg_fatal("%s(%d): dict_path invalid", myname, __LINE__); + if (dict_name == NULL || *dict_name == 0) + acl_msg_fatal("%s(%d): dict_name invalid", myname, __LINE__); + if (pool_size <= 0) + acl_msg_fatal("%s(%d): pool_size(%d) invalid", myname, __LINE__, pool_size); + + if (strncasecmp(dict_type, "cdb", 3) == 0) { + two_db = 1; + } else if (strncasecmp(dict_type, "btree", 5) == 0) { + two_db = 0; + open_flags = O_CREAT | O_RDWR; + } else if (strncasecmp(dict_type, "hash", 4) == 0) { + two_db = 0; + open_flags = O_CREAT | O_RDWR; + } else if (strncasecmp(dict_type, "tc", 2) == 0) { + two_db = 0; + open_flags = O_CREAT | O_RDWR; + } else { + acl_msg_fatal("unknown dict type from %s", dict_type); + } + + pool->dbpool = (DICT_POOL_DB*) acl_mycalloc(pool_size, sizeof(DICT_POOL_DB)); + pool->partions = (POOL_PARTION*) acl_mycalloc(partions_size, sizeof(POOL_PARTION)); + pool->partions_size = partions_size; + + for (i = 0; i < partions_size; i++) { + pool->partions[i].path = acl_vstring_alloc(256); + acl_vstring_strcpy(pool->partions[i].path, partions[i]); + pool->partions[i].db_cnt = 0; + pool->partions[i].obj_cnt = 0; + } + + for (j = 0, i = 0; i < pool_size; i++) { + acl_pthread_mutex_init(&pool->dbpool[i].lock, NULL); + pool->dbpool[i].dpath = acl_vstring_alloc(256); + if (j >= partions_size) + j = 0; + acl_vstring_sprintf(pool->dbpool[i].dpath, "%s:%s/%s/%s_%d", + dict_type, STR(pool->partions[j].path), dict_path, dict_name, i); + pool->partions[j].db_cnt++; + pool->dbpool[i].partion = &pool->partions[j]; + j++; + + pool->dbpool[i].seqcnt = 0; + if (two_db) { + open_flags = O_WRONLY|O_CREAT|O_TRUNC; + pool->dbpool[i].dict_write = dict_open(STR(pool->dbpool[i].dpath), open_flags, dict_flags); + if (pool->dbpool[i].dict_write == NULL) + acl_msg_fatal("%s(%d): open dict(%s) error", + myname, __LINE__, STR(pool->dbpool[i].dpath)); + + open_flags = O_RDONLY; + pool->dbpool[i].dict_read = dict_open(STR(pool->dbpool[i].dpath), open_flags, dict_flags); + if (pool->dbpool[i].dict_read == NULL) + acl_msg_fatal("%s(%d): open dict(%s) error", + myname, __LINE__, STR(pool->dbpool[i].dpath)); + } else { + open_flags = O_CREAT | O_RDWR; + pool->dbpool[i].dict_read = dict_open(STR(pool->dbpool[i].dpath), open_flags, dict_flags); + if (pool->dbpool[i].dict_read == NULL) + acl_msg_fatal("%s(%d): open dict(%s) error", + myname, __LINE__, STR(pool->dbpool[i].dpath)); + + pool->dbpool[i].dict_write = pool->dbpool[i].dict_read; +#if 0 + dict_register(STR(pool->dbpool[i].dpath), pool->dbpool[i].dict); +#endif + } + } + + pool->dict_name = acl_mystrdup(dict_name); + pool->pool_size = pool_size; + pool->hash_fn = acl_hash_crc32; + return (pool); +} + +void dict_pool_free(DICT_POOL *pool) +{ + const char *myname = "dict_pool_free"; + int i; + + if (pool == NULL) + acl_msg_fatal("%s(%d): dict_name invalid", myname, __LINE__); + + for (i = 0; i < pool->pool_size; i++) { +#if 0 + dict_unregister(STR(pool->dbpool[i].dpath)); +#endif + if (pool->dbpool[i].dict_read == pool->dbpool[i].dict_write) { + if (pool->dbpool[i].dict_read != NULL) + DICT_CLOSE(pool->dbpool[i].dict_read); + } else { + if (pool->dbpool[i].dict_read != NULL) + DICT_CLOSE(pool->dbpool[i].dict_read); + if (pool->dbpool[i].dict_write != NULL) + DICT_CLOSE(pool->dbpool[i].dict_write); + } + acl_vstring_free(pool->dbpool[i].dpath); + acl_pthread_mutex_destroy(&pool->dbpool[i].lock); + } + + for (i = 0; i < pool->partions_size; i++) { + acl_vstring_free(pool->partions[i].path); + } + + acl_myfree(pool->partions); + acl_myfree(pool->dbpool); + acl_myfree(pool->dict_name); + acl_myfree(pool); +} + +int dict_pool_set(DICT_POOL *pool, char *key, size_t key_len, char *value, size_t len) +{ + unsigned int n; + + n = (pool->hash_fn(key, key_len)) % (pool->pool_size); + dict_pool_db_lock(&pool->dbpool[n]); + DICT_PUT(pool->dbpool[n].dict_write, key, key_len, value, len); + pool->dbpool[n].partion->obj_cnt++; + dict_pool_db_unlock(&pool->dbpool[n]); + return (0); +} + +char *dict_pool_get(DICT_POOL *pool, char *key, size_t key_len, size_t *size) +{ + const char *myname = "dict_pool_get"; + unsigned int n; + char *value; + + n = (pool->hash_fn(key, key_len)) % (pool->pool_size); + dict_pool_db_lock(&pool->dbpool[n]); + if (DICT_GET(pool->dbpool[n].dict_read, key, key_len, &value, size) == NULL) { + if (dict_errno == DICT_ERR_RETRY) + acl_msg_error("%s(%d): soft error", myname, __LINE__); + } + dict_pool_db_unlock(&pool->dbpool[n]); + return (value); +} + +int dict_pool_del(DICT_POOL *pool, char *key, size_t key_len) +{ + unsigned int n; + int ret; + + n = (pool->hash_fn(key, key_len)) % (pool->pool_size); + dict_pool_db_lock(&pool->dbpool[n]); + ret = DICT_DEL(pool->dbpool[n].dict_write, key, key_len); + if (ret == 0) + pool->dbpool[n].partion->obj_cnt--; + dict_pool_db_unlock(&pool->dbpool[n]); + return (ret); +} + +void dict_pool_seq_reset(DICT_POOL *pool) +{ + int i; + + pool->dict_cur = 0; + + for (i = 0; i < pool->pool_size; i++) { + DICT_RESET(pool->dbpool[i].dict_read); + pool->dbpool[i].seqcnt = 0; + } +} + +int dict_pool_seq_delcur(DICT_POOL *pool) +{ + const char *myname = "dict_pool_seq_delcur"; + int ret; + + if (pool->dict_cur < 0) + acl_msg_fatal("%s(%d), %s): dict_cur(%d) < 0", + __FILE__, __LINE__, myname, pool->dict_cur); + if (pool->dict_cur >= pool->pool_size) + acl_msg_fatal("%s(%d), %s): dict_cur(%d) >= pool_size(%d)", + __FILE__, __LINE__, myname, + pool->dict_cur, pool->pool_size); + dict_pool_db_lock(&pool->dbpool[pool->dict_cur]); + ret = DICT_DELCUR(pool->dbpool[pool->dict_cur].dict_read); + dict_pool_db_unlock(&pool->dbpool[pool->dict_cur]); + return (ret); +} + +int dict_pool_seq(DICT_POOL *pool, char **key, size_t *key_size, + char **val, size_t *val_size) +{ + int ret; + + while (1) { + if (pool->dict_cur < 0) + pool->dict_cur = 0; + else if (pool->dict_cur >= pool->pool_size) { + *key = NULL; + *key_size = 0; + *val = NULL; + *val_size = 0; + pool->dict_cur = 0; + return (-1); + } + + dict_pool_db_lock(&pool->dbpool[pool->dict_cur]); + if (pool->dbpool[pool->dict_cur].seqcnt == 0) + ret = DICT_SEQ(pool->dbpool[pool->dict_cur].dict_read, + DICT_SEQ_FUN_FIRST, key, key_size, val, val_size); + else + ret = DICT_SEQ(pool->dbpool[pool->dict_cur].dict_read, + DICT_SEQ_FUN_NEXT, key, key_size, val, val_size); + dict_pool_db_unlock(&pool->dbpool[pool->dict_cur]); + + if (ret == 0) { + pool->dbpool[pool->dict_cur].seqcnt++; + return (0); + } + pool->dbpool[pool->dict_cur].seqcnt = 0; + + /* 返回非0值,有可能是当前的DB结点已经遍历完毕, xxx: 应该进一步判断才是 */ + pool->dict_cur++; + } +} + +DICT_POOL_DB *dict_pool_db(DICT_POOL *pool, const char *key, size_t key_len) +{ + unsigned int n; + + n = (pool->hash_fn(key, key_len)) % (pool->pool_size); + return (&pool->dbpool[n]); +} + +const char *dict_pool_db_path(DICT_POOL_DB *db) +{ + return (acl_vstring_str(db->dpath)); +} + +void dict_pool_db_lock(DICT_POOL_DB *db) +{ + acl_pthread_mutex_lock(&db->lock); +} + +void dict_pool_db_unlock(DICT_POOL_DB *db) +{ + acl_pthread_mutex_unlock(&db->lock); +} + +int dict_pool_db_set(DICT_POOL_DB *db, char *key, size_t key_len, char *value, size_t len) +{ + DICT_PUT(db->dict_write, key, key_len, value, len); + db->partion->obj_cnt++; + return (0); +} + +char *dict_pool_db_get(DICT_POOL_DB *db, char *key, size_t key_len, size_t *size) +{ + const char *myname = "dict_pool_db_get"; + char *value; + + if (DICT_GET(db->dict_read, key, key_len, &value, size) == NULL) { + if (dict_errno == DICT_ERR_RETRY) + acl_msg_error("%s(%d): soft error", myname, __LINE__); + } + return (value); +} + +int dict_pool_db_del(DICT_POOL_DB *db, char *key, size_t key_len) +{ + int ret; + + ret = DICT_DEL(db->dict_write, key, key_len); + if (ret == 0) + db->partion->obj_cnt--; + return (ret); +} + +void dict_pool_db_seq_reset(DICT_POOL_DB *db) +{ + DICT_RESET(db->dict_read); +} + +int dict_pool_db_seq(DICT_POOL_DB *db, char **key, size_t *key_size, + char **val, size_t *val_size) +{ + int ret; + + if (db->seqcnt == 0) + ret = DICT_SEQ(db->dict_read, DICT_SEQ_FUN_FIRST, + key, key_size, val, val_size); + else + ret = DICT_SEQ(db->dict_read, DICT_SEQ_FUN_NEXT, + key, key_size, val, val_size); + if (ret == 0) { + db->seqcnt++; + return (0); + } + return (-1); +} + diff --git a/lib_dict/src/dict_tc.c b/lib_dict/src/dict_tc.c new file mode 100644 index 000000000..1ed99d2c0 --- /dev/null +++ b/lib_dict/src/dict_tc.c @@ -0,0 +1,381 @@ +#include "StdAfx.h" + +#ifdef HAS_TC + +#include +#include +#include +#include +#include + +#include "debug_var.h" +#include "dict.h" +#include "dict_tc.h" + +#include +#include + +/* Application-specific. */ + +typedef struct { + DICT dict; /* generic members */ + TCADB *adb; /* TCADB structure */ +#define DICT_TC_HDB 0 +#define DICT_TC_BDB 1 +#define DICT_TC_FDB 2 +#define DICT_TC_TDB 3 +#define DICT_TC_HMDB 4 +#define DICT_TC_BMDB 5 + int type; +} DICT_TC; + +/* dict_tc_error - get the error status */ + +static const char *dict_tc_error(DICT_TC *dict_tc, int *ecode) +{ + const char *myname = "dict_tc_error"; + const char *err = "unknown error"; + int ret; + + switch (dict_tc->type) { + case DICT_TC_HDB: + if (dict_tc->adb->hdb == NULL) + acl_msg_fatal("%s: hdb null", myname); + ret = tchdbecode(dict_tc->adb->hdb); + if (ecode) + *ecode = ret; + err = tchdberrmsg(ret); + break; + case DICT_TC_BDB: + if (dict_tc->adb->bdb == NULL) + acl_msg_fatal("%s: bdb null", myname); + ret = tcbdbecode(dict_tc->adb->bdb); + if (ecode) + *ecode = ret; + err = tcbdberrmsg(ret); + break; + case DICT_TC_FDB: + if (dict_tc->adb->fdb == NULL) + acl_msg_fatal("%s: fdb null", myname); + ret = tcfdbecode(dict_tc->adb->fdb); + if (ecode) + *ecode = ret; + err = tcfdberrmsg(ret); + break; + case DICT_TC_TDB: + if (dict_tc->adb->tdb == NULL) + acl_msg_fatal("%s: tdb null", myname); + ret = tctdbecode(dict_tc->adb->tdb); + if (ecode) + *ecode = ret; + err = tctdberrmsg(ret); + break; + case DICT_TC_HMDB: + if (dict_tc->adb->mdb == NULL) + acl_msg_fatal("%s: mdb null", myname); + case DICT_TC_BMDB: + if (dict_tc->adb->ndb == NULL) + acl_msg_fatal("%s: ndb null", myname); + default: + if (ecode) + *ecode = -1; + break; + } + return (err); +} + +/* dict_tc_lookup - find database entry */ + +static const char *dict_tc_lookup(DICT *dict, char *name, size_t name_len, char **value, size_t *size) +{ + DICT_TC *dict_tc = (DICT_TC *) dict; + char *buf = NULL; + char *result = NULL; + + dict_errno = 0; + + if (size) + *size = 0; + if (value == NULL) + acl_msg_fatal("dict_db_lookup: value null"); + + /* + * Optionally fold the key. + */ + if (dict->flags & DICT_FLAG_FOLD_FIX) { + if (dict->fold_buf == 0) + dict->fold_buf = acl_vstring_alloc(10); + acl_vstring_strcpy(dict->fold_buf, name); + name = acl_lowercase(acl_vstring_str(dict->fold_buf)); + } + + /* + * See if this TC file was written with one null byte appended to key + * and value. + */ + if (dict->flags & DICT_FLAG_TRY1NULL) { + result = tcadbget(dict_tc->adb, name, (int) name_len + 1, (int*) size); + if (result != NULL) + dict->flags &= ~DICT_FLAG_TRY0NULL; + } + + /* + * See if this TC file was written with no null byte appended to key and + * value. + */ + if (result == 0 && (dict->flags & DICT_FLAG_TRY0NULL)) { + result = tcadbget(dict_tc->adb, name, (int) name_len, (int*) size); + if (result != NULL) + dict->flags &= ~DICT_FLAG_TRY1NULL; + } + + if (result) { + buf = acl_mymalloc(*size + 1); + memcpy(buf, result, *size); + buf[*size] = '\0'; + free(result); /* free the memory allocated by TC db */ + result = buf; + } + /* No locking so not release the lock. */ + + *value = result; + return (result); +} + +/* dict_tc_update - add database entry */ + +static void dict_tc_update(DICT *dict, char *name, size_t name_len, char *value, size_t size) +{ + const char *myname = "dict_tc_update"; + DICT_TC *dict_tc = (DICT_TC *) dict; + int ksize, vsize; + const char *ptr; + int ecode = 0; + + /* + * Optionally fold the key. + */ + if (dict->flags & DICT_FLAG_FOLD_FIX) { + if (dict->fold_buf == 0) + dict->fold_buf = acl_vstring_alloc(10); + acl_vstring_strcpy(dict->fold_buf, name); + name = acl_lowercase(acl_vstring_str(dict->fold_buf)); + } + ksize = (int) name_len; + vsize = (int) size; + + /* + * Optionally append a null byte to key and value. + */ + if (dict->flags & DICT_FLAG_TRY1NULL) { + ksize++; + vsize++; + } + + /* + * Do the add operation. No locking is done. + */ + if (dict->flags & DICT_FLAG_DUP_IGNORE) { + if (!tcadbputcat(dict_tc->adb, name, ksize, value, vsize)) { + ptr = dict_tc_error(dict_tc, &ecode); + acl_msg_fatal("%s(%d): add error(%d, %s)", + myname, __LINE__, ecode, ptr); + } + } else if (dict->flags & DICT_FLAG_DUP_WARN) { + if (!tcadbput(dict_tc->adb, name, ksize, value, vsize)) { + ptr = dict_tc_error(dict_tc, &ecode); + acl_msg_warn("%s(%d): add error(%d, %s)", + myname, __LINE__, ecode, ptr); + } + } else { +#if 1 + if (!tcadbput(dict_tc->adb, name, ksize, value, vsize)) { + ptr = dict_tc_error(dict_tc, &ecode); + acl_msg_fatal("%s(%d): add error(%d, %s)", + myname, __LINE__, ecode, ptr); + } +#else + if (!tcadbputkeep(dict_tc->adb, name, ksize, value, vsize)) { + ptr = dict_tc_error(dict_tc, &ecode); + acl_msg_fatal("%s(%d): add error(%d, %s)", + myname, __LINE__, ecode, ptr); + } +#endif + } + + if (!ecode && (dict->flags & DICT_FLAG_SYNC_UPDATE)) { + if (!tcadbsync(dict_tc->adb)) { + ptr = dict_tc_error(dict_tc, &ecode); + acl_msg_warn("%s(%d): delete from %s error(%d, %s)", + myname, __LINE__, dict_tc->dict.name, ecode, ptr); + } + } +} + +/* dict_tc_delete - delete one entry from the dictionary */ + +static int dict_tc_delete(DICT *dict, char *name, size_t name_len) +{ + const char *myname = "dict_tc_delete"; + DICT_TC *dict_tc = (DICT_TC *) dict; + int ecode = 0; + const char *ptr; + + /* + * Sanity check. + */ + if ((dict->flags & (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL)) == 0) + acl_msg_panic("dict_db_delete: no DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL flag"); + + /* + * Optionally fold the key. + */ + if (dict->flags & DICT_FLAG_FOLD_FIX) { + if (dict->fold_buf == 0) + dict->fold_buf = acl_vstring_alloc(10); + acl_vstring_strcpy(dict->fold_buf, name); + name = acl_lowercase(acl_vstring_str(dict->fold_buf)); + } + + /* + * See if this DB file was written with one null byte appended to key and + * value. + */ + if (dict->flags & DICT_FLAG_TRY1NULL) { + if (!tcadbout(dict_tc->adb, name, (int) name_len + 1)) { + ptr = dict_tc_error(dict_tc, &ecode); + acl_msg_warn("%s(%d): delete from %s error(%d, %s)", + myname, __LINE__, dict_tc->dict.name, ecode, ptr); + } + } + + /* + * See if this DB file was written with no null byte appended to key and + * value. + */ + if (!ecode && (dict->flags & DICT_FLAG_TRY0NULL)) { + if (!tcadbout(dict_tc->adb, name, (int) name_len)) { + ptr = dict_tc_error(dict_tc, &ecode); + acl_msg_warn("%s(%d): delete from %s error(%d, %s)", + myname, __LINE__, dict_tc->dict.name, ecode, ptr); + } + } + + if (!ecode && (dict->flags & DICT_FLAG_SYNC_UPDATE)) { + if (!tcadbsync(dict_tc->adb)) { + ptr = dict_tc_error(dict_tc, &ecode); + acl_msg_warn("%s(%d): delete from %s error(%d, %s)", + myname, __LINE__, dict_tc->dict.name, ecode, ptr); + } + } + + return (ecode); +} + + +/* dict_tc_close - close data base */ + +static void dict_tc_close(DICT *dict) +{ + const char *myname = "dict_tc_close"; + DICT_TC *dict_tc = (DICT_TC *) dict; + const char *ptr; + int ecode; + + if (!tcadbclose(dict_tc->adb)) { + ptr = dict_tc_error(dict_tc, &ecode); + acl_msg_error("%s: close tc db error(%d, %s)", + myname, ecode, ptr); + } + if (dict->fold_buf) + acl_vstring_free(dict->fold_buf); + dict_free(dict); +} + +/* dict_tc_open - open data base */ + +static DICT *dict_tc_open2(const char *path, int dict_flags) +{ + const char *myname = "dict_tc_open2"; + DICT_TC *dict_tc; + struct stat st; + const char *ptr; + + dict_tc = (DICT_TC *) dict_alloc(DICT_TYPE_TC, path, sizeof(*dict_tc)); + + dict_tc->adb = tcadbnew(); + + ptr = strrchr(path, '.'); + if (strcmp(path, "*") == 0 || strncmp(path, "*#", 2) == 0) { + dict_tc->type = DICT_TC_HMDB; + } else if (strcmp(path, "+") == 0 || strncmp(path, "+#", 2) == 0) { + dict_tc->type = DICT_TC_BMDB; + } else if (ptr && strncmp(ptr, ".tch", 4) == 0) { + dict_tc->type = DICT_TC_HDB; + } else if (ptr && strncmp(ptr, ".tcb", 4) == 0) { + dict_tc->type = DICT_TC_BDB; + } else if (ptr && strncmp(ptr, ".tcf", 4) == 0) { + dict_tc->type = DICT_TC_FDB; + } else if (ptr && strncmp(ptr, ".tct", 4) == 0) { + dict_tc->type = DICT_TC_TDB; + } else { + acl_msg_fatal("%s(%d): ext(%s) in path(%s) invalid", + myname, __LINE__, ptr, path); + } + + if(!tcadbopen(dict_tc->adb, path)) + acl_msg_fatal("%s: tcadbopen %s error", myname, path); + + dict_tc->dict.lookup = dict_tc_lookup; + dict_tc->dict.update = dict_tc_update; + dict_tc->dict.delete_it = dict_tc_delete; + dict_tc->dict.close = dict_tc_close; + + dict_tc->dict.stat_fd = -1; + + /* + dict_cdbq->dict.mtime = st.st_mtime; + acl_close_on_exec(fd, ACL_CLOSE_ON_EXEC); + */ + + /* + * Warn if the source file is newer than the indexed file, except when + * the source file changed only seconds ago. + */ + if (stat(path, &st) == 0 + && st.st_mtime > dict_tc->dict.mtime + && st.st_mtime < time((time_t *) 0) - 100) + acl_msg_warn("database %s is older than source file %s", path, path); + + /* + * If undecided about appending a null byte to key and value, choose to + * try both in query mode. + */ + if ((dict_flags & (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL)) == 0) + dict_flags |= DICT_FLAG_TRY0NULL | DICT_FLAG_TRY1NULL; + dict_tc->dict.flags = dict_flags | DICT_FLAG_FIXED; + if (dict_flags & DICT_FLAG_FOLD_FIX) + dict_tc->dict.fold_buf = acl_vstring_alloc(10); + + return (&dict_tc->dict); +} + +/* dict_tc_open - open data base */ + +DICT *dict_tc_open(const char *path, int open_flags, int dict_flags) +{ + switch (open_flags & (O_RDONLY | O_RDWR | O_WRONLY | O_CREAT | O_TRUNC)) { + case O_RDONLY: /* query mode */ + case O_WRONLY | O_CREAT | O_TRUNC: /* create mode */ + case O_RDWR | O_CREAT | O_TRUNC: /* sloppiness */ + return dict_tc_open2(path, dict_flags); + default: + acl_msg_fatal("dict_cdb_open: inappropriate open flags for cdb database" + " - specify O_RDONLY or O_WRONLY|O_CREAT|O_TRUNC"); + } + + /* not reached */ + return (NULL); +} + +#endif /* HAS_TC */ diff --git a/lib_dict/src/dict_tc.h b/lib_dict/src/dict_tc.h new file mode 100644 index 000000000..6d827f177 --- /dev/null +++ b/lib_dict/src/dict_tc.h @@ -0,0 +1,18 @@ +#ifndef _DICT_TC_H_INCLUDED_ +#define _DICT_TC_H_INCLUDED_ + +#ifdef HAS_DB + +#include + + /* + * External interface. + */ +#define DICT_TYPE_TC "tc" + +extern DICT *dict_tc_open(const char *, int, int); + +#endif + +#endif /* _DICT_TC_H_INCLUDED_ */ + diff --git a/lib_dict/src/mac_expand.c b/lib_dict/src/mac_expand.c new file mode 100644 index 000000000..61bde2679 --- /dev/null +++ b/lib_dict/src/mac_expand.c @@ -0,0 +1,222 @@ +#include "StdAfx.h" +#include +#include +#include "mac_parse.h" +#include "mac_expand.h" + + /* + * Little helper structure. + */ +typedef struct { + ACL_VSTRING *result; /* result buffer */ + int flags; /* features */ + const char *filter; /* character filter */ + MAC_EXP_LOOKUP_FN lookup; /* lookup routine */ + char *context; /* caller context */ + int status; /* findings */ + int level; /* nesting level */ +} MAC_EXP; + +/* mac_expand_callback - callback for mac_parse */ + +static int mac_expand_callback(int type, ACL_VSTRING *buf, char *ptr) +{ + MAC_EXP *mc = (MAC_EXP *) ptr; + int lookup_mode; + const char *text; + char *cp, *pp = NULL; + int ch; + ssize_t len; + size_t size; + + /* + * Sanity check. + */ + if (mc->level++ > 100) { + acl_msg_warn("unreasonable macro call nesting: \"%s\"", acl_vstring_str(buf)); + mc->status |= MAC_PARSE_ERROR; + } + if (mc->status & MAC_PARSE_ERROR) + return (mc->status); + + /* + * $Name etc. reference. + * + * In order to support expansion of lookup results, we must save the lookup + * result. We use the input buffer since it will not be needed anymore. + */ + if (type == MAC_PARSE_EXPR) { + + /* + * Look for the ? or : delimiter. In case of a syntax error, return + * without doing damage, and issue a warning instead. + */ + for (cp = acl_vstring_str(buf); /* void */ ; cp++) { + if ((ch = *cp) == 0) { + lookup_mode = MAC_EXP_MODE_USE; + break; + } + if (ch == '?' || ch == ':') { + *cp++ = 0; + lookup_mode = MAC_EXP_MODE_TEST; + break; + } + if (!ACL_ISALNUM(ch) && ch != '_') { + acl_msg_warn("macro name syntax error: \"%s\"", acl_vstring_str(buf)); + mc->status |= MAC_PARSE_ERROR; + return (mc->status); + } + } + + /* + * Look up the named parameter. + */ + text = mc->lookup(acl_vstring_str(buf), lookup_mode, mc->context, &pp, &size); + + /* + * Perform the requested substitution. + */ + switch (ch) { + case '?': + if (text != 0 && *text != 0) + mac_parse(cp, mac_expand_callback, (char *) mc); + break; + case ':': + if (text == 0 || *text == 0) + mac_parse(cp, mac_expand_callback, (char *) mc); + break; + default: + if (text == 0) { + mc->status |= MAC_PARSE_UNDEF; + } else if (*text == 0) { + /* void */ ; + } else if (mc->flags & MAC_EXP_FLAG_RECURSE) { + acl_vstring_strcpy(buf, text); + mac_parse(acl_vstring_str(buf), mac_expand_callback, (char *) mc); + } else { + len = (int) ACL_VSTRING_LEN(mc->result); + acl_vstring_strcat(mc->result, text); + if (mc->filter) { + cp = acl_vstring_str(mc->result) + len; + while (*(cp += strspn(cp, mc->filter))) + *cp++ = '_'; + } + } + break; + } + } + + /* + * Literal text. + */ + else { + acl_vstring_strcat(mc->result, acl_vstring_str(buf)); + } + + mc->level--; + if (pp) + free(pp); + + return (mc->status); +} + +/* mac_expand - expand $name instances */ + +int mac_expand(ACL_VSTRING *result, const char *pattern, int flags, + const char *filter, + MAC_EXP_LOOKUP_FN lookup, char *context) +{ + MAC_EXP mc; + int status; + + /* + * Bundle up the request and do the substitutions. + */ + mc.result = result; + mc.flags = flags; + mc.filter = filter; + mc.lookup = lookup; + mc.context = context; + mc.status = 0; + mc.level = 0; + ACL_VSTRING_RESET(result); + status = mac_parse(pattern, mac_expand_callback, (char *) &mc); + ACL_VSTRING_TERMINATE(result); + + return (status); +} + +#ifdef TEST + + /* + * This code certainly deserves a stand-alone test program. + */ +#include +#include +#include +#include +#include + +static const char *lookup(const char *name, int unused_mode, char *context) +{ + HTABLE *table = (HTABLE *) context; + + return (htable_find(table, name)); +} + +int main(int unused_argc, char **unused_argv) +{ + VSTRING *buf = vstring_alloc(100); + VSTRING *result = vstring_alloc(100); + char *cp; + char *name; + char *value; + HTABLE *table; + int stat; + + while (!vstream_feof(VSTREAM_IN)) { + + table = htable_create(0); + + /* + * Read a block of definitions, terminated with an empty line. + */ + while (vstring_get_nonl(buf, VSTREAM_IN) != VSTREAM_EOF) { + vstream_printf("<< %s\n", vstring_str(buf)); + vstream_fflush(VSTREAM_OUT); + if (VSTRING_LEN(buf) == 0) + break; + cp = vstring_str(buf); + name = mystrtok(&cp, " \t\r\n="); + value = mystrtok(&cp, " \t\r\n="); + htable_enter(table, name, value ? mystrdup(value) : 0); + } + + /* + * Read a block of patterns, terminated with an empty line or EOF. + */ + while (vstring_get_nonl(buf, VSTREAM_IN) != VSTREAM_EOF) { + vstream_printf("<< %s\n", vstring_str(buf)); + vstream_fflush(VSTREAM_OUT); + if (VSTRING_LEN(buf) == 0) + break; + cp = vstring_str(buf); + VSTRING_RESET(result); + stat = mac_expand(result, vstring_str(buf), MAC_EXP_FLAG_NONE, + (char *) 0, lookup, (char *) table); + vstream_printf("stat=%d result=%s\n", stat, vstring_str(result)); + vstream_fflush(VSTREAM_OUT); + } + htable_free(table, myfree); + vstream_printf("\n"); + } + + /* + * Clean up. + */ + vstring_free(buf); + vstring_free(result); + exit(0); +} + +#endif diff --git a/lib_dict/src/mac_expand.h b/lib_dict/src/mac_expand.h new file mode 100644 index 000000000..398c985d9 --- /dev/null +++ b/lib_dict/src/mac_expand.h @@ -0,0 +1,23 @@ +#ifndef _MAC_EXPAND_H_INCLUDED_ +#define _MAC_EXPAND_H_INCLUDED_ + +#include "lib_acl.h" +#include "mac_parse.h" + + /* + * Features. + */ +#define MAC_EXP_FLAG_NONE (0) +#define MAC_EXP_FLAG_RECURSE (1<<0) + + /* + * Real lookup or just a test? + */ +#define MAC_EXP_MODE_TEST (0) +#define MAC_EXP_MODE_USE (1) + +typedef const char *(*MAC_EXP_LOOKUP_FN)(char *, int, const char *, char **, size_t *); + +extern int mac_expand(ACL_VSTRING *, const char *, int, const char *, MAC_EXP_LOOKUP_FN, char *); + +#endif diff --git a/lib_dict/src/mac_parse.c b/lib_dict/src/mac_parse.c new file mode 100644 index 000000000..da97c7dfe --- /dev/null +++ b/lib_dict/src/mac_parse.c @@ -0,0 +1,130 @@ +#include "StdAfx.h" +#include "debug_var.h" +#include +#include "mac_parse.h" + + /* + * Helper macro for consistency. Null-terminate the temporary buffer, + * execute the action, and reset the temporary buffer for re-use. + */ +#define MAC_PARSE_ACTION(status, type, buf, context) \ + do { \ + ACL_VSTRING_TERMINATE(buf); \ + status |= action((type), (buf), (context)); \ + ACL_VSTRING_RESET(buf); \ + } while(0) + +/* mac_parse - split string into literal text and macro references */ + +int mac_parse(const char *value, MAC_PARSE_FN action, char *context) +{ + const char *myname = "mac_parse"; + ACL_VSTRING *buf = acl_vstring_alloc(1); /* result buffer */ + const char *vp; /* value pointer */ + const char *pp; /* open_paren pointer */ + const char *ep; /* string end pointer */ + static char open_paren[] = "({"; + static char close_paren[] = ")}"; + int level; + int status = 0; + +#define SKIP(start, var, cond) \ + for (var = start; *var && (cond); var++); + + acl_debug(DEBUG_MAC, 2) ("%s: %s", myname, value); + + for (vp = value; *vp;) { + if (*vp != '$') { /* ordinary character */ + ACL_VSTRING_ADDCH(buf, *vp); + vp += 1; + } else if (vp[1] == '$') { /* $$ becomes $ */ + ACL_VSTRING_ADDCH(buf, *vp); + vp += 2; + } else { /* found bare $ */ + if (ACL_VSTRING_LEN(buf) > 0) + MAC_PARSE_ACTION(status, MAC_PARSE_LITERAL, buf, context); + vp += 1; + pp = open_paren; + if (*vp == *pp || *vp == *++pp) { /* ${x} or $(x) */ + level = 1; + vp += 1; + for (ep = vp; level > 0; ep++) { + if (*ep == 0) { + acl_msg_warn("truncated macro reference: \"%s\"", value); + status |= MAC_PARSE_ERROR; + break; + } + if (*ep == *pp) + level++; + if (*ep == close_paren[pp - open_paren]) + level--; + } + if (status & MAC_PARSE_ERROR) + break; + acl_vstring_strncat(buf, vp, level > 0 ? ep - vp : ep - vp - 1); + vp = ep; + } else { /* plain $x */ + SKIP(vp, ep, ACL_ISALNUM(*ep) || *ep == '_'); + acl_vstring_strncat(buf, vp, ep - vp); + vp = ep; + } + if (ACL_VSTRING_LEN(buf) == 0) { + status |= MAC_PARSE_ERROR; + acl_msg_warn("empty macro name: \"%s\"", value); + break; + } + MAC_PARSE_ACTION(status, MAC_PARSE_EXPR, buf, context); + } + } + if (ACL_VSTRING_LEN(buf) > 0 && (status & MAC_PARSE_ERROR) == 0) + MAC_PARSE_ACTION(status, MAC_PARSE_LITERAL, buf, context); + + /* + * Cleanup. + */ + acl_vstring_free(buf); + + return (status); +} + +#ifdef TEST + + /* + * Proof-of-concept test program. Read strings from stdin, print parsed + * result to stdout. + */ +#include + +/* mac_parse_print - print parse tree */ + +static int mac_parse_print(int type, VSTRING *buf, char *unused_context) +{ + char *type_name; + + switch (type) { + case MAC_PARSE_EXPR: + type_name = "MAC_PARSE_EXPR"; + break; + case MAC_PARSE_LITERAL: + type_name = "MAC_PARSE_LITERAL"; + break; + default: + msg_panic("unknown token type %d", type); + } + vstream_printf("%s \"%s\"\n", type_name, vstring_str(buf)); + return (0); +} + +int main(int unused_argc, char **unused_argv) +{ + VSTRING *buf = vstring_alloc(1); + + while (vstring_fgets_nonl(buf, VSTREAM_IN)) { + mac_parse(vstring_str(buf), mac_parse_print, (char *) 0); + vstream_fflush(VSTREAM_OUT); + } + vstring_free(buf); + return (0); +} + +#endif diff --git a/lib_dict/src/mac_parse.h b/lib_dict/src/mac_parse.h new file mode 100644 index 000000000..a9d1e4e8a --- /dev/null +++ b/lib_dict/src/mac_parse.h @@ -0,0 +1,22 @@ +#ifndef _MAC_PARSE_H_INCLUDED_ +#define _MAC_PARSE_H_INCLUDED_ + +#include "lib_acl.h" + + /* + * External interface. + */ +#define MAC_PARSE_LITERAL 1 +#define MAC_PARSE_EXPR 2 +#define MAC_PARSE_VARNAME MAC_PARSE_EXPR /* 2.1 compatibility */ + +#define MAC_PARSE_OK 0 +#define MAC_PARSE_ERROR (1<<0) +#define MAC_PARSE_UNDEF (1<<1) +#define MAC_PARSE_USER 2 /* start user definitions */ + +typedef int (*MAC_PARSE_FN)(int, ACL_VSTRING *, char *); + +extern int mac_parse(const char *, MAC_PARSE_FN, char *); + +#endif diff --git a/lib_dict/src/name_mask.c b/lib_dict/src/name_mask.c new file mode 100644 index 000000000..92a9aac5e --- /dev/null +++ b/lib_dict/src/name_mask.c @@ -0,0 +1,133 @@ +#include "StdAfx.h" +#include +#ifdef STRCASECMP_IN_STRINGS_H +#include +#endif + +#include "debug_var.h" +#include "name_mask.h" + +#define STR(x) acl_vstring_str(x) + +/* name_mask_delim_opt - compute mask corresponding to list of names */ + +int name_mask_delim_opt(const char *context, const NAME_MASK *table, + const char *names, const char *delim, int flags) +{ + const char *myname = "name_mask"; + char *saved_names = acl_mystrdup(names); + char *bp = saved_names; + int result = 0; + const NAME_MASK *np; + char *name; + int (*lookup) (const char *, const char *); + + if (flags & NAME_MASK_ANY_CASE) + lookup = strcasecmp; + else + lookup = strcmp; + + /* + * Break up the names string, and look up each component in the table. If + * the name is found, merge its mask with the result. + */ + while ((name = acl_mystrtok(&bp, delim)) != 0) { + for (np = table; /* void */ ; np++) { + if (np->name == 0) { + if (flags & NAME_MASK_FATAL) + acl_msg_fatal("unknown %s value \"%s\" in \"%s\"", + context, name, names); + if (flags & NAME_MASK_RETURN) { + acl_msg_warn("unknown %s value \"%s\" in \"%s\"", + context, name, names); + return (0); + } + break; + } + if (lookup(name, np->name) == 0) { + acl_debug(DEBUG_NAME_MASK, 1) ("%s: %s", myname, name); + result |= np->mask; + break; + } + } + } + acl_myfree(saved_names); + return (result); +} + +/* str_name_mask_opt - mask to string */ + +const char *str_name_mask_opt(ACL_VSTRING *buf, const char *context, + const NAME_MASK *table, + int mask, int flags) +{ + const char *myname = "name_mask"; + const NAME_MASK *np; + int len; + static ACL_VSTRING *my_buf = 0; + int delim = (flags & NAME_MASK_COMMA ? ',' : + (flags & NAME_MASK_PIPE ? '|' : ' ')); + + if (buf == 0) { + if (my_buf == 0) + my_buf = acl_vstring_alloc(1); + buf = my_buf; + } + ACL_VSTRING_RESET(buf); + + for (np = table; mask != 0; np++) { + if (np->name == 0) { + if (flags & NAME_MASK_FATAL) { + acl_msg_fatal("%s: unknown %s bit in mask: 0x%x", + myname, context, mask); + } else if (flags & NAME_MASK_RETURN) { + acl_msg_warn("%s: unknown %s bit in mask: 0x%x", + myname, context, mask); + return (0); + } else if (flags & NAME_MASK_NUMBER) { + acl_vstring_sprintf_append(buf, "0x%x%c", mask, delim); + } + break; + } + if (mask & np->mask) { + mask &= ~np->mask; + acl_vstring_sprintf_append(buf, "%s%c", np->name, delim); + } + } + if ((len = (int) ACL_VSTRING_LEN(buf)) > 0) + acl_vstring_truncate(buf, len - 1); + ACL_VSTRING_TERMINATE(buf); + + return (STR(buf)); +} + +#ifdef TEST + +/* + * Stand-alone test program. + */ +#include + +int main(int argc, char **argv) +{ + static const NAME_MASK table[] = { + "zero", 1 << 0, + "one", 1 << 1, + "two", 1 << 2, + "three", 1 << 3, + 0, 0, + }; + int mask; + ACL_VSTRING *buf = acl_vstring_alloc(1); + + while (--argc && *++argv) { + mask = name_mask("test", table, *argv); + acl_vstream_printf("%s -> 0x%x -> %s\n", + *argv, mask, str_name_mask("mask_test", table, mask)); + acl_vstream_fflush(VSTREAM_OUT); + } + acl_vstring_free(buf); + exit(0); +} + +#endif diff --git a/lib_dict/src/name_mask.h b/lib_dict/src/name_mask.h new file mode 100644 index 000000000..de9c0d99b --- /dev/null +++ b/lib_dict/src/name_mask.h @@ -0,0 +1,38 @@ +#ifndef _NAME_MASK_H_INCLUDED_ +#define _NAME_MASK_H_INCLUDED_ + +#include "lib_acl.h" + + /* + * External interface. + */ +typedef struct { + const char *name; + int mask; +} NAME_MASK; + +#define NAME_MASK_FATAL (1<<0) +#define NAME_MASK_ANY_CASE (1<<1) +#define NAME_MASK_RETURN (1<<2) +#define NAME_MASK_COMMA (1<<3) +#define NAME_MASK_PIPE (1<<4) +#define NAME_MASK_NUMBER (1<<5) + +#define NAME_MASK_MATCH_REQ NAME_MASK_FATAL + +#define NAME_MASK_NONE 0 +#define NAME_MASK_DEFAULT (NAME_MASK_FATAL) +#define NAME_MASK_DEFAULT_DELIM ", \t\r\n" + +#define name_mask_opt(tag, table, str, flags) \ + name_mask_delim_opt((tag), (table), (str), \ + NAME_MASK_DEFAULT_DELIM, (flags)) +#define name_mask(tag, table, str) \ + name_mask_opt((tag), (table), (str), NAME_MASK_DEFAULT) +#define str_name_mask(tag, table, mask) \ + str_name_mask_opt(((VSTRING *) 0), (tag), (table), (mask), NAME_MASK_DEFAULT) + +extern int name_mask_delim_opt(const char *, const NAME_MASK *, const char *, const char *, int); +extern const char *str_name_mask_opt(ACL_VSTRING *, const char *, const NAME_MASK *, int, int); + +#endif diff --git a/lib_dict/src/snprintf.c b/lib_dict/src/snprintf.c new file mode 100644 index 000000000..07c70bbec --- /dev/null +++ b/lib_dict/src/snprintf.c @@ -0,0 +1,24 @@ +#include "StdAfx.h" +#ifdef __STDC_WANT_SECURE_LIB__ +#include + +int dict_secure_snprintf(char *buf, size_t size, const char *fmt, ...) +{ + va_list ap; + int ret; + + va_start(ap, fmt); + ret = _vsnprintf_s(buf, size, size, fmt, ap); + va_end(ap); + return (ret); +} + +int dict_securev_snprintf(char *buf, size_t size, const char *fmt, va_list ap) +{ + int ret; + + ret = _vsnprintf_s(buf, size, size, fmt, ap); + return (ret); +} + +#endif diff --git a/lib_dict/src/unescape.c b/lib_dict/src/unescape.c new file mode 100644 index 000000000..cc43eed6e --- /dev/null +++ b/lib_dict/src/unescape.c @@ -0,0 +1,147 @@ +#include "StdAfx.h" +#include +#include "unescape.h" + +/* unescape - process escape sequences */ + +ACL_VSTRING *unescape(ACL_VSTRING *result, const char *data) +{ + int ch; + int oval; + int i; + +#define UCHAR(cp) ((const unsigned char *) (cp)) +#define ISOCTAL(ch) (ACL_ISDIGIT(ch) && (ch) != '8' && (ch) != '9') + + ACL_VSTRING_RESET(result); + + while ((ch = *UCHAR(data++)) != 0) { + if (ch == '\\') { + if ((ch = *UCHAR(data++)) == 0) + break; + switch (ch) { + case 'a': /* \a -> audible bell */ + ch = '\a'; + break; + case 'b': /* \b -> backspace */ + ch = '\b'; + break; + case 'f': /* \f -> formfeed */ + ch = '\f'; + break; + case 'n': /* \n -> newline */ + ch = '\n'; + break; + case 'r': /* \r -> carriagereturn */ + ch = '\r'; + break; + case 't': /* \t -> horizontal tab */ + ch = '\t'; + break; + case 'v': /* \v -> vertical tab */ + ch = '\v'; + break; + case '0': /* \nnn -> ASCII value */ + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + for (oval = ch - '0', i = 0; + i < 2 && (ch = *UCHAR(data)) != 0 && ISOCTAL(ch); + i++, data++) { + oval = (oval << 3) | (ch - '0'); + } + ch = oval; + break; + default: /* \any -> any */ + break; + } + } + ACL_VSTRING_ADDCH(result, ch); + } + ACL_VSTRING_TERMINATE(result); + return (result); +} + +/* escape - reverse transformation */ + +ACL_VSTRING *escape(ACL_VSTRING *result, const char *data, ssize_t len) +{ + int ch; + + ACL_VSTRING_RESET(result); + while (len-- > 0) { + ch = *UCHAR(data++); + if (ACL_ISASCII(ch)) { + if (ACL_ISPRINT(ch)) { + if (ch == '\\') + ACL_VSTRING_ADDCH(result, ch); + ACL_VSTRING_ADDCH(result, ch); + continue; + } else if (ch == '\a') { /* \a -> audible bell */ + acl_vstring_strcat(result, "\\a"); + continue; + } else if (ch == '\b') { /* \b -> backspace */ + acl_vstring_strcat(result, "\\b"); + continue; + } else if (ch == '\f') { /* \f -> formfeed */ + acl_vstring_strcat(result, "\\f"); + continue; + } else if (ch == '\n') { /* \n -> newline */ + acl_vstring_strcat(result, "\\n"); + continue; + } else if (ch == '\r') { /* \r -> carriagereturn */ + acl_vstring_strcat(result, "\\r"); + continue; + } else if (ch == '\t') { /* \t -> horizontal tab */ + acl_vstring_strcat(result, "\\t"); + continue; + } else if (ch == '\v') { /* \v -> vertical tab */ + acl_vstring_strcat(result, "\\v"); + continue; + } + } + if (ACL_ISDIGIT(*UCHAR(data))) + acl_vstring_sprintf_append(result, "\\%03d", ch); + else + acl_vstring_sprintf_append(result, "\\%d", ch); + } + ACL_VSTRING_TERMINATE(result); + return (result); +} + +#ifdef TEST + +#include +#include +#include +#include + +int main(int argc, char **argv) +{ + VSTRING *in = vstring_alloc(10); + VSTRING *out = vstring_alloc(10); + int un_escape = 1; + + if (argc > 2 || (argc > 1 && (un_escape = strcmp(argv[1], "-e"))) != 0) + msg_fatal("usage: %s [-e (escape)]", argv[0]); + + if (un_escape) { + while (vstring_fgets_nonl(in, VSTREAM_IN)) { + unescape(out, vstring_str(in)); + vstream_fwrite(VSTREAM_OUT, vstring_str(out), VSTRING_LEN(out)); + } + } else { + while (vstring_fgets(in, VSTREAM_IN)) { + escape(out, vstring_str(in), VSTRING_LEN(in)); + vstream_fwrite(VSTREAM_OUT, vstring_str(out), VSTRING_LEN(out)); + } + } + vstream_fflush(VSTREAM_OUT); + exit(0); +} + +#endif diff --git a/lib_dict/tc/include/tcadb.h b/lib_dict/tc/include/tcadb.h new file mode 100644 index 000000000..6afaeba65 --- /dev/null +++ b/lib_dict/tc/include/tcadb.h @@ -0,0 +1,545 @@ +/************************************************************************************************* + * The abstract database API of Tokyo Cabinet + * Copyright (C) 2006-2009 Mikio Hirabayashi + * This file is part of Tokyo Cabinet. + * Tokyo Cabinet is free software; you can redistribute it and/or modify it under the terms of + * the GNU Lesser General Public License as published by the Free Software Foundation; either + * version 2.1 of the License or any later version. Tokyo Cabinet is distributed in the hope + * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * You should have received a copy of the GNU Lesser General Public License along with Tokyo + * Cabinet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA. + *************************************************************************************************/ + + +#ifndef _TCADB_H /* duplication check */ +#define _TCADB_H + +#if defined(__cplusplus) +#define __TCADB_CLINKAGEBEGIN extern "C" { +#define __TCADB_CLINKAGEEND } +#else +#define __TCADB_CLINKAGEBEGIN +#define __TCADB_CLINKAGEEND +#endif +__TCADB_CLINKAGEBEGIN + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + +/************************************************************************************************* + * API + *************************************************************************************************/ + + +typedef struct { /* type of structure for an abstract database */ + int omode; /* open mode */ + TCMDB *mdb; /* on-memory hash database object */ + TCNDB *ndb; /* on-memory tree database object */ + TCHDB *hdb; /* hash database object */ + TCBDB *bdb; /* B+ tree database object */ + TCFDB *fdb; /* fixed-length databae object */ + TCTDB *tdb; /* table database object */ + int64_t capnum; /* capacity number of records */ + int64_t capsiz; /* capacity size of using memory */ + uint32_t capcnt; /* count for capacity check */ + BDBCUR *cur; /* cursor of B+ tree */ + void *skel; /* skeleton database */ +} TCADB; + +enum { /* enumeration for open modes */ + ADBOVOID, /* not opened */ + ADBOMDB, /* on-memory hash database */ + ADBONDB, /* on-memory tree database */ + ADBOHDB, /* hash database */ + ADBOBDB, /* B+ tree database */ + ADBOFDB, /* fixed-length database */ + ADBOTDB, /* table database */ + ADBOSKEL /* skeleton database */ +}; + + +/* Create an abstract database object. + The return value is the new abstract database object. */ +TCADB *tcadbnew(void); + + +/* Delete an abstract database object. + `adb' specifies the abstract database object. */ +void tcadbdel(TCADB *adb); + + +/* Open an abstract database. + `adb' specifies the abstract database object. + `name' specifies the name of the database. If it is "*", the database will be an on-memory + hash database. If it is "+", the database will be an on-memory tree database. If its suffix + is ".tch", the database will be a hash database. If its suffix is ".tcb", the database will + be a B+ tree database. If its suffix is ".tcf", the database will be a fixed-length database. + If its suffix is ".tct", the database will be a table database. Otherwise, this function + fails. Tuning parameters can trail the name, separated by "#". Each parameter is composed of + the name and the value, separated by "=". On-memory hash database supports "bnum", "capnum", + and "capsiz". On-memory tree database supports "capnum" and "capsiz". Hash database supports + "mode", "bnum", "apow", "fpow", "opts", "rcnum", "xmsiz", and "dfunit". B+ tree database + supports "mode", "lmemb", "nmemb", "bnum", "apow", "fpow", "opts", "lcnum", "ncnum", "xmsiz", + and "dfunit". Fixed-length database supports "mode", "width", and "limsiz". Table database + supports "mode", "bnum", "apow", "fpow", "opts", "rcnum", "lcnum", "ncnum", "xmsiz", "dfunit", + and "idx". + If successful, the return value is true, else, it is false. + The tuning parameter "capnum" specifies the capacity number of records. "capsiz" specifies + the capacity size of using memory. Records spilled the capacity are removed by the storing + order. "mode" can contain "w" of writer, "r" of reader, "c" of creating, "t" of truncating, + "e" of no locking, and "f" of non-blocking lock. The default mode is relevant to "wc". + "opts" can contains "l" of large option, "d" of Deflate option, "b" of BZIP2 option, and "t" + of TCBS option. "idx" specifies the column name of an index and its type separated by ":". + For example, "casket.tch#bnum=1000000#opts=ld" means that the name of the database file is + "casket.tch", and the bucket number is 1000000, and the options are large and Deflate. */ +bool tcadbopen(TCADB *adb, const char *name); + + +/* Close an abstract database object. + `adb' specifies the abstract database object. + If successful, the return value is true, else, it is false. + Update of a database is assured to be written when the database is closed. If a writer opens + a database but does not close it appropriately, the database will be broken. */ +bool tcadbclose(TCADB *adb); + + +/* Store a record into an abstract database object. + `adb' specifies the abstract database object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `vbuf' specifies the pointer to the region of the value. + `vsiz' specifies the size of the region of the value. + If successful, the return value is true, else, it is false. + If a record with the same key exists in the database, it is overwritten. */ +bool tcadbput(TCADB *adb, const void *kbuf, int ksiz, const void *vbuf, int vsiz); + + +/* Store a string record into an abstract object. + `adb' specifies the abstract database object. + `kstr' specifies the string of the key. + `vstr' specifies the string of the value. + If successful, the return value is true, else, it is false. + If a record with the same key exists in the database, it is overwritten. */ +bool tcadbput2(TCADB *adb, const char *kstr, const char *vstr); + + +/* Store a new record into an abstract database object. + `adb' specifies the abstract database object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `vbuf' specifies the pointer to the region of the value. + `vsiz' specifies the size of the region of the value. + If successful, the return value is true, else, it is false. + If a record with the same key exists in the database, this function has no effect. */ +bool tcadbputkeep(TCADB *adb, const void *kbuf, int ksiz, const void *vbuf, int vsiz); + + +/* Store a new string record into an abstract database object. + `adb' specifies the abstract database object. + `kstr' specifies the string of the key. + `vstr' specifies the string of the value. + If successful, the return value is true, else, it is false. + If a record with the same key exists in the database, this function has no effect. */ +bool tcadbputkeep2(TCADB *adb, const char *kstr, const char *vstr); + + +/* Concatenate a value at the end of the existing record in an abstract database object. + `adb' specifies the abstract database object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `vbuf' specifies the pointer to the region of the value. + `vsiz' specifies the size of the region of the value. + If successful, the return value is true, else, it is false. + If there is no corresponding record, a new record is created. */ +bool tcadbputcat(TCADB *adb, const void *kbuf, int ksiz, const void *vbuf, int vsiz); + + +/* Concatenate a string value at the end of the existing record in an abstract database object. + `adb' specifies the abstract database object. + `kstr' specifies the string of the key. + `vstr' specifies the string of the value. + If successful, the return value is true, else, it is false. + If there is no corresponding record, a new record is created. */ +bool tcadbputcat2(TCADB *adb, const char *kstr, const char *vstr); + + +/* Remove a record of an abstract database object. + `adb' specifies the abstract database object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + If successful, the return value is true, else, it is false. */ +bool tcadbout(TCADB *adb, const void *kbuf, int ksiz); + + +/* Remove a string record of an abstract database object. + `adb' specifies the abstract database object. + `kstr' specifies the string of the key. + If successful, the return value is true, else, it is false. */ +bool tcadbout2(TCADB *adb, const char *kstr); + + +/* Retrieve a record in an abstract database object. + `adb' specifies the abstract database object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `sp' specifies the pointer to the variable into which the size of the region of the return + value is assigned. + If successful, the return value is the pointer to the region of the value of the corresponding + record. `NULL' is returned if no record corresponds. + Because an additional zero code is appended at the end of the region of the return value, + the return value can be treated as a character string. Because the region of the return + value is allocated with the `malloc' call, it should be released with the `free' call when + it is no longer in use. */ +void *tcadbget(TCADB *adb, const void *kbuf, int ksiz, int *sp); + + +/* Retrieve a string record in an abstract database object. + `adb' specifies the abstract database object. + `kstr' specifies the string of the key. + If successful, the return value is the string of the value of the corresponding record. + `NULL' is returned if no record corresponds. + Because the region of the return value is allocated with the `malloc' call, it should be + released with the `free' call when it is no longer in use. */ +char *tcadbget2(TCADB *adb, const char *kstr); + + +/* Get the size of the value of a record in an abstract database object. + `adb' specifies the abstract database object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + If successful, the return value is the size of the value of the corresponding record, else, + it is -1. */ +int tcadbvsiz(TCADB *adb, const void *kbuf, int ksiz); + + +/* Get the size of the value of a string record in an abstract database object. + `adb' specifies the abstract database object. + `kstr' specifies the string of the key. + If successful, the return value is the size of the value of the corresponding record, else, + it is -1. */ +int tcadbvsiz2(TCADB *adb, const char *kstr); + + +/* Initialize the iterator of an abstract database object. + `adb' specifies the abstract database object. + If successful, the return value is true, else, it is false. + The iterator is used in order to access the key of every record stored in a database. */ +bool tcadbiterinit(TCADB *adb); + + +/* Get the next key of the iterator of an abstract database object. + `adb' specifies the abstract database object. + `sp' specifies the pointer to the variable into which the size of the region of the return + value is assigned. + If successful, the return value is the pointer to the region of the next key, else, it is + `NULL'. `NULL' is returned when no record is to be get out of the iterator. + Because an additional zero code is appended at the end of the region of the return value, the + return value can be treated as a character string. Because the region of the return value is + allocated with the `malloc' call, it should be released with the `free' call when it is no + longer in use. It is possible to access every record by iteration of calling this function. + It is allowed to update or remove records whose keys are fetched while the iteration. + However, it is not assured if updating the database is occurred while the iteration. Besides, + the order of this traversal access method is arbitrary, so it is not assured that the order of + storing matches the one of the traversal access. */ +void *tcadbiternext(TCADB *adb, int *sp); + + +/* Get the next key string of the iterator of an abstract database object. + `adb' specifies the abstract database object. + If successful, the return value is the string of the next key, else, it is `NULL'. `NULL' is + returned when no record is to be get out of the iterator. + Because the region of the return value is allocated with the `malloc' call, it should be + released with the `free' call when it is no longer in use. It is possible to access every + record by iteration of calling this function. However, it is not assured if updating the + database is occurred while the iteration. Besides, the order of this traversal access method + is arbitrary, so it is not assured that the order of storing matches the one of the traversal + access. */ +char *tcadbiternext2(TCADB *adb); + + +/* Get forward matching keys in an abstract database object. + `adb' specifies the abstract database object. + `pbuf' specifies the pointer to the region of the prefix. + `psiz' specifies the size of the region of the prefix. + `max' specifies the maximum number of keys to be fetched. If it is negative, no limit is + specified. + The return value is a list object of the corresponding keys. This function does never fail. + It returns an empty list even if no key corresponds. + Because the object of the return value is created with the function `tclistnew', it should be + deleted with the function `tclistdel' when it is no longer in use. Note that this function + may be very slow because every key in the database is scanned. */ +TCLIST *tcadbfwmkeys(TCADB *adb, const void *pbuf, int psiz, int max); + + +/* Get forward matching string keys in an abstract database object. + `adb' specifies the abstract database object. + `pstr' specifies the string of the prefix. + `max' specifies the maximum number of keys to be fetched. If it is negative, no limit is + specified. + The return value is a list object of the corresponding keys. This function does never fail. + It returns an empty list even if no key corresponds. + Because the object of the return value is created with the function `tclistnew', it should be + deleted with the function `tclistdel' when it is no longer in use. Note that this function + may be very slow because every key in the database is scanned. */ +TCLIST *tcadbfwmkeys2(TCADB *adb, const char *pstr, int max); + + +/* Add an integer to a record in an abstract database object. + `adb' specifies the abstract database object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `num' specifies the additional value. + If successful, the return value is the summation value, else, it is `INT_MIN'. + If the corresponding record exists, the value is treated as an integer and is added to. If no + record corresponds, a new record of the additional value is stored. */ +int tcadbaddint(TCADB *adb, const void *kbuf, int ksiz, int num); + + +/* Add a real number to a record in an abstract database object. + `adb' specifies the abstract database object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `num' specifies the additional value. + If successful, the return value is the summation value, else, it is Not-a-Number. + If the corresponding record exists, the value is treated as a real number and is added to. If + no record corresponds, a new record of the additional value is stored. */ +double tcadbadddouble(TCADB *adb, const void *kbuf, int ksiz, double num); + + +/* Synchronize updated contents of an abstract database object with the file and the device. + `adb' specifies the abstract database object. + If successful, the return value is true, else, it is false. */ +bool tcadbsync(TCADB *adb); + + +/* Optimize the storage of an abstract database object. + `adb' specifies the abstract database object. + `params' specifies the string of the tuning parameters, which works as with the tuning + of parameters the function `tcadbopen'. If it is `NULL', it is not used. + If successful, the return value is true, else, it is false. + This function is useful to reduce the size of the database storage with data fragmentation by + successive updating. */ +bool tcadboptimize(TCADB *adb, const char *params); + + +/* Remove all records of an abstract database object. + `adb' specifies the abstract database object. + If successful, the return value is true, else, it is false. */ +bool tcadbvanish(TCADB *adb); + + +/* Copy the database file of an abstract database object. + `adb' specifies the abstract database object. + `path' specifies the path of the destination file. If it begins with `@', the trailing + substring is executed as a command line. + If successful, the return value is true, else, it is false. False is returned if the executed + command returns non-zero code. + The database file is assured to be kept synchronized and not modified while the copying or + executing operation is in progress. So, this function is useful to create a backup file of + the database file. */ +bool tcadbcopy(TCADB *adb, const char *path); + + +/* Begin the transaction of an abstract database object. + `adb' specifies the abstract database object. + If successful, the return value is true, else, it is false. + The database is locked by the thread while the transaction so that only one transaction can be + activated with a database object at the same time. Thus, the serializable isolation level is + assumed if every database operation is performed in the transaction. All updated regions are + kept track of by write ahead logging while the transaction. If the database is closed during + transaction, the transaction is aborted implicitly. */ +bool tcadbtranbegin(TCADB *adb); + + +/* Commit the transaction of an abstract database object. + `adb' specifies the abstract database object. + If successful, the return value is true, else, it is false. + Update in the transaction is fixed when it is committed successfully. */ +bool tcadbtrancommit(TCADB *adb); + + +/* Abort the transaction of an abstract database object. + `adb' specifies the abstract database object. + If successful, the return value is true, else, it is false. + Update in the transaction is discarded when it is aborted. The state of the database is + rollbacked to before transaction. */ +bool tcadbtranabort(TCADB *adb); + + +/* Get the file path of an abstract database object. + `adb' specifies the abstract database object. + The return value is the path of the database file or `NULL' if the object does not connect to + any database. "*" stands for on-memory hash database. "+" stands for on-memory tree + database. */ +const char *tcadbpath(TCADB *adb); + + +/* Get the number of records of an abstract database object. + `adb' specifies the abstract database object. + The return value is the number of records or 0 if the object does not connect to any database + instance. */ +uint64_t tcadbrnum(TCADB *adb); + + +/* Get the size of the database of an abstract database object. + `adb' specifies the abstract database object. + The return value is the size of the database or 0 if the object does not connect to any + database instance. */ +uint64_t tcadbsize(TCADB *adb); + + +/* Call a versatile function for miscellaneous operations of an abstract database object. + `adb' specifies the abstract database object. + `name' specifies the name of the function. All databases support "put", "out", "get", + "putlist", "outlist", and "getlist". "put" is to store a record. It receives a key and a + value, and returns an empty list. "out" is to remove a record. It receives a key, and + returns an empty list. "get" is to retrieve a record. It receives a key, and returns a list + of the values. "putlist" is to store records. It receives keys and values one after the + other, and returns an empty list. "outlist" is to remove records. It receives keys, and + returns an empty list. "getlist" is to retrieve records. It receives keys, and returns keys + and values of corresponding records one after the other. + `args' specifies a list object containing arguments. + If successful, the return value is a list object of the result. `NULL' is returned on failure. + Because the object of the return value is created with the function `tclistnew', it + should be deleted with the function `tclistdel' when it is no longer in use. */ +TCLIST *tcadbmisc(TCADB *adb, const char *name, const TCLIST *args); + + + +/************************************************************************************************* + * features for experts + *************************************************************************************************/ + + +typedef struct { /* type of structure for a extra database skeleton */ + void *opq; /* opaque pointer */ + void (*del)(void *); /* destructor */ + bool (*open)(void *, const char *); + bool (*close)(void *); + bool (*put)(void *, const void *, int, const void *, int); + bool (*putkeep)(void *, const void *, int, const void *, int); + bool (*putcat)(void *, const void *, int, const void *, int); + bool (*out)(void *, const void *, int); + void *(*get)(void *, const void *, int, int *); + int (*vsiz)(void *, const void *, int); + bool (*iterinit)(void *); + void *(*iternext)(void *, int *); + TCLIST *(*fwmkeys)(void *, const void *, int, int); + int (*addint)(void *, const void *, int, int); + double (*adddouble)(void *, const void *, int, double); + bool (*sync)(void *); + bool (*optimize)(void *, const char *); + bool (*vanish)(void *); + bool (*copy)(void *, const char *); + bool (*tranbegin)(void *); + bool (*trancommit)(void *); + bool (*tranabort)(void *); + const char *(*path)(void *); + uint64_t (*rnum)(void *); + uint64_t (*size)(void *); + TCLIST *(*misc)(void *, const char *, const TCLIST *); + bool (*putproc)(void *, const void *, int, const void *, int, TCPDPROC, void *); + bool (*foreach)(void *, TCITER, void *); +} ADBSKEL; + +/* type of the pointer to a mapping function. + `map' specifies the pointer to the destination manager. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `vbuf' specifies the pointer to the region of the value. + `vsiz' specifies the size of the region of the value. + `op' specifies the pointer to the optional opaque object. + The return value is true to continue iteration or false to stop iteration. */ +typedef bool (*ADBMAPPROC)(void *map, const char *kbuf, int ksiz, const char *vbuf, int vsiz, + void *op); + + +/* Set an extra database sleleton to an abstract database object. + `adb' specifies the abstract database object. + `skel' specifies the extra database skeleton. + If successful, the return value is true, else, it is false. */ +bool tcadbsetskel(TCADB *adb, ADBSKEL *skel); + + +/* Get the open mode of an abstract database object. + `adb' specifies the abstract database object. + The return value is `ADBOVOID' for not opened database, `ADBOMDB' for on-memory hash database, + `ADBONDB' for on-memory tree database, `ADBOHDB' for hash database, `ADBOBDB' for B+ tree + database, `ADBOFDB' for fixed-length database, `ADBOTDB' for table database. */ +int tcadbomode(TCADB *adb); + + +/* Get the concrete database object of an abstract database object. + `adb' specifies the abstract database object. + The return value is the concrete database object depend on the open mode or 0 if the object + does not connect to any database instance. */ +void *tcadbreveal(TCADB *adb); + + +/* Store a record into an abstract database object with a duplication handler. + `adb' specifies the abstract database object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `vbuf' specifies the pointer to the region of the value. + `vsiz' specifies the size of the region of the value. + `proc' specifies the pointer to the callback function to process duplication. + `op' specifies an arbitrary pointer to be given as a parameter of the callback function. If + it is not needed, `NULL' can be specified. + If successful, the return value is true, else, it is false. + This function does not work for the table database. */ +bool tcadbputproc(TCADB *adb, const void *kbuf, int ksiz, const void *vbuf, int vsiz, + TCPDPROC proc, void *op); + + +/* Process each record atomically of an abstract database object. + `adb' specifies the abstract database object. + `iter' specifies the pointer to the iterator function called for each record. + `op' specifies an arbitrary pointer to be given as a parameter of the iterator function. If + it is not needed, `NULL' can be specified. + If successful, the return value is true, else, it is false. */ +bool tcadbforeach(TCADB *adb, TCITER iter, void *op); + + +/* Map records of an abstract database object into another B+ tree database. + `adb' specifies the abstract database object. + `keys' specifies a list object of the keys of the target records. If it is `NULL', every + record is processed. + `bdb' specifies the B+ tree database object into which records emitted by the mapping function + are stored. + `proc' specifies the pointer to the mapping function called for each record. + `op' specifies specifies the pointer to the optional opaque object for the mapping function. + `csiz' specifies the size of the cache to sort emitted records. If it is negative, the + default size is specified. The default size is 268435456. + If successful, the return value is true, else, it is false. */ +bool tcadbmapbdb(TCADB *adb, TCLIST *keys, TCBDB *bdb, ADBMAPPROC proc, void *op, int64_t csiz); + + +/* Emit records generated by the mapping function into the result map. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `vbuf' specifies the pointer to the region of the value. + `vsiz' specifies the size of the region of the value. + If successful, the return value is true, else, it is false. */ +bool tcadbmapbdbemit(void *map, const char *kbuf, int ksiz, const char *vbuf, int vsiz); + + + +__TCADB_CLINKAGEEND +#endif /* duplication check */ + + +/* END OF FILE */ diff --git a/lib_dict/tc/include/tcbdb.h b/lib_dict/tc/include/tcbdb.h new file mode 100644 index 000000000..fcdc1b68b --- /dev/null +++ b/lib_dict/tc/include/tcbdb.h @@ -0,0 +1,1107 @@ +/************************************************************************************************* + * The B+ tree database API of Tokyo Cabinet + * Copyright (C) 2006-2009 Mikio Hirabayashi + * This file is part of Tokyo Cabinet. + * Tokyo Cabinet is free software; you can redistribute it and/or modify it under the terms of + * the GNU Lesser General Public License as published by the Free Software Foundation; either + * version 2.1 of the License or any later version. Tokyo Cabinet is distributed in the hope + * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * You should have received a copy of the GNU Lesser General Public License along with Tokyo + * Cabinet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA. + *************************************************************************************************/ + + +#ifndef _TCBDB_H /* duplication check */ +#define _TCBDB_H + +#if defined(__cplusplus) +#define __TCBDB_CLINKAGEBEGIN extern "C" { +#define __TCBDB_CLINKAGEEND } +#else +#define __TCBDB_CLINKAGEBEGIN +#define __TCBDB_CLINKAGEEND +#endif +__TCBDB_CLINKAGEBEGIN + + +#include +#include +#include +#include +#include +#include +#include +#include + + + +/************************************************************************************************* + * API + *************************************************************************************************/ + + +typedef struct { /* type of structure for a B+ tree database */ + void *mmtx; /* mutex for method */ + void *cmtx; /* mutex for cache */ + TCHDB *hdb; /* internal database object */ + char *opaque; /* opaque buffer */ + bool open; /* whether the internal database is opened */ + bool wmode; /* whether to be writable */ + uint32_t lmemb; /* number of members in each leaf */ + uint32_t nmemb; /* number of members in each node */ + uint8_t opts; /* options */ + uint64_t root; /* ID number of the root page */ + uint64_t first; /* ID number of the first leaf */ + uint64_t last; /* ID number of the last leaf */ + uint64_t lnum; /* number of leaves */ + uint64_t nnum; /* number of nodes */ + uint64_t rnum; /* number of records */ + TCMAP *leafc; /* cache for leaves */ + TCMAP *nodec; /* cache for nodes */ + TCCMP cmp; /* pointer to the comparison function */ + void *cmpop; /* opaque object for the comparison function */ + uint32_t lcnum; /* maximum number of cached leaves */ + uint32_t ncnum; /* maximum number of cached nodes */ + uint32_t lsmax; /* maximum size of each leaf */ + uint32_t lschk; /* counter for leaf size checking */ + uint64_t capnum; /* capacity number of records */ + uint64_t *hist; /* history array of visited nodes */ + int hnum; /* number of element of the history array */ + uint64_t hleaf; /* ID number of the leaf referred by the history */ + uint64_t lleaf; /* ID number of the last visited leaf */ + bool tran; /* whether in the transaction */ + char *rbopaque; /* opaque for rollback */ + uint64_t clock; /* logical clock */ + int64_t cnt_saveleaf; /* tesing counter for leaf save times */ + int64_t cnt_loadleaf; /* tesing counter for leaf load times */ + int64_t cnt_killleaf; /* tesing counter for leaf kill times */ + int64_t cnt_adjleafc; /* tesing counter for node cache adjust times */ + int64_t cnt_savenode; /* tesing counter for node save times */ + int64_t cnt_loadnode; /* tesing counter for node load times */ + int64_t cnt_adjnodec; /* tesing counter for node cache adjust times */ +} TCBDB; + +enum { /* enumeration for additional flags */ + BDBFOPEN = HDBFOPEN, /* whether opened */ + BDBFFATAL = HDBFFATAL /* whetehr with fatal error */ +}; + +enum { /* enumeration for tuning options */ + BDBTLARGE = 1 << 0, /* use 64-bit bucket array */ + BDBTDEFLATE = 1 << 1, /* compress each page with Deflate */ + BDBTBZIP = 1 << 2, /* compress each record with BZIP2 */ + BDBTTCBS = 1 << 3, /* compress each page with TCBS */ + BDBTEXCODEC = 1 << 4 /* compress each record with outer functions */ +}; + +enum { /* enumeration for open modes */ + BDBOREADER = 1 << 0, /* open as a reader */ + BDBOWRITER = 1 << 1, /* open as a writer */ + BDBOCREAT = 1 << 2, /* writer creating */ + BDBOTRUNC = 1 << 3, /* writer truncating */ + BDBONOLCK = 1 << 4, /* open without locking */ + BDBOLCKNB = 1 << 5, /* lock without blocking */ + BDBOTSYNC = 1 << 6 /* synchronize every transaction */ +}; + +typedef struct { /* type of structure for a B+ tree cursor */ + TCBDB *bdb; /* database object */ + uint64_t clock; /* logical clock */ + uint64_t id; /* ID number of the leaf */ + int32_t kidx; /* number of the key */ + int32_t vidx; /* number of the value */ +} BDBCUR; + +enum { /* enumeration for cursor put mode */ + BDBCPCURRENT, /* current */ + BDBCPBEFORE, /* before */ + BDBCPAFTER /* after */ +}; + + +/* Get the message string corresponding to an error code. + `ecode' specifies the error code. + The return value is the message string of the error code. */ +const char *tcbdberrmsg(int ecode); + + +/* Create a B+ tree database object. + The return value is the new B+ tree database object. */ +TCBDB *tcbdbnew(void); + + +/* Delete a B+ tree database object. + `bdb' specifies the B+ tree database object. + If the database is not closed, it is closed implicitly. Note that the deleted object and its + derivatives can not be used anymore. */ +void tcbdbdel(TCBDB *bdb); + + +/* Get the last happened error code of a B+ tree database object. + `bdb' specifies the B+ tree database object. + The return value is the last happened error code. + The following error codes are defined: `TCESUCCESS' for success, `TCETHREAD' for threading + error, `TCEINVALID' for invalid operation, `TCENOFILE' for file not found, `TCENOPERM' for no + permission, `TCEMETA' for invalid meta data, `TCERHEAD' for invalid record header, `TCEOPEN' + for open error, `TCECLOSE' for close error, `TCETRUNC' for trunc error, `TCESYNC' for sync + error, `TCESTAT' for stat error, `TCESEEK' for seek error, `TCEREAD' for read error, + `TCEWRITE' for write error, `TCEMMAP' for mmap error, `TCELOCK' for lock error, `TCEUNLINK' + for unlink error, `TCERENAME' for rename error, `TCEMKDIR' for mkdir error, `TCERMDIR' for + rmdir error, `TCEKEEP' for existing record, `TCENOREC' for no record found, and `TCEMISC' for + miscellaneous error. */ +int tcbdbecode(TCBDB *bdb); + + +/* Set mutual exclusion control of a B+ tree database object for threading. + `bdb' specifies the B+ tree database object which is not opened. + If successful, the return value is true, else, it is false. + Note that the mutual exclusion control is needed if the object is shared by plural threads and + this function should should be called before the database is opened. */ +bool tcbdbsetmutex(TCBDB *bdb); + + +/* Set the custom comparison function of a B+ tree database object. + `bdb' specifies the B+ tree database object which is not opened. + `cmp' specifies the pointer to the custom comparison function. It receives five parameters. + The first parameter is the pointer to the region of one key. The second parameter is the size + of the region of one key. The third parameter is the pointer to the region of the other key. + The fourth parameter is the size of the region of the other key. The fifth parameter is the + pointer to the optional opaque object. It returns positive if the former is big, negative if + the latter is big, 0 if both are equivalent. + `cmpop' specifies an arbitrary pointer to be given as a parameter of the comparison function. + If it is not needed, `NULL' can be specified. + If successful, the return value is true, else, it is false. + The default comparison function compares keys of two records by lexical order. The functions + `tctccmplexical' (dafault), `tctccmpdecimal', `tctccmpint32', and `tctccmpint64' are built-in. + Note that the comparison function should be set before the database is opened. Moreover, + user-defined comparison functions should be set every time the database is being opened. */ +bool tcbdbsetcmpfunc(TCBDB *bdb, TCCMP cmp, void *cmpop); + + +/* Set the tuning parameters of a B+ tree database object. + `bdb' specifies the B+ tree database object which is not opened. + `lmemb' specifies the number of members in each leaf page. If it is not more than 0, the + default value is specified. The default value is 128. + `nmemb' specifies the number of members in each non-leaf page. If it is not more than 0, the + default value is specified. The default value is 256. + `bnum' specifies the number of elements of the bucket array. If it is not more than 0, the + default value is specified. The default value is 32749. Suggested size of the bucket array + is about from 1 to 4 times of the number of all pages to be stored. + `apow' specifies the size of record alignment by power of 2. If it is negative, the default + value is specified. The default value is 8 standing for 2^8=256. + `fpow' specifies the maximum number of elements of the free block pool by power of 2. If it + is negative, the default value is specified. The default value is 10 standing for 2^10=1024. + `opts' specifies options by bitwise-or: `BDBTLARGE' specifies that the size of the database + can be larger than 2GB by using 64-bit bucket array, `BDBTDEFLATE' specifies that each page + is compressed with Deflate encoding, `BDBTBZIP' specifies that each page is compressed with + BZIP2 encoding, `BDBTTCBS' specifies that each page is compressed with TCBS encoding. + If successful, the return value is true, else, it is false. + Note that the tuning parameters should be set before the database is opened. */ +bool tcbdbtune(TCBDB *bdb, int32_t lmemb, int32_t nmemb, + int64_t bnum, int8_t apow, int8_t fpow, uint8_t opts); + + +/* Set the caching parameters of a B+ tree database object. + `bdb' specifies the B+ tree database object which is not opened. + `lcnum' specifies the maximum number of leaf nodes to be cached. If it is not more than 0, + the default value is specified. The default value is 1024. + `ncnum' specifies the maximum number of non-leaf nodes to be cached. If it is not more than 0, + the default value is specified. The default value is 512. + If successful, the return value is true, else, it is false. + Note that the caching parameters should be set before the database is opened. */ +bool tcbdbsetcache(TCBDB *bdb, int32_t lcnum, int32_t ncnum); + + +/* Set the size of the extra mapped memory of a B+ tree database object. + `bdb' specifies the B+ tree database object which is not opened. + `xmsiz' specifies the size of the extra mapped memory. If it is not more than 0, the extra + mapped memory is disabled. It is disabled by default. + If successful, the return value is true, else, it is false. + Note that the mapping parameters should be set before the database is opened. */ +bool tcbdbsetxmsiz(TCBDB *bdb, int64_t xmsiz); + + +/* Set the unit step number of auto defragmentation of a B+ tree database object. + `bdb' specifies the B+ tree database object which is not opened. + `dfunit' specifie the unit step number. If it is not more than 0, the auto defragmentation + is disabled. It is disabled by default. + If successful, the return value is true, else, it is false. + Note that the defragmentation parameter should be set before the database is opened. */ +bool tcbdbsetdfunit(TCBDB *bdb, int32_t dfunit); + + +/* Open a database file and connect a B+ tree database object. + `bdb' specifies the B+ tree database object which is not opened. + `path' specifies the path of the database file. + `omode' specifies the connection mode: `BDBOWRITER' as a writer, `BDBOREADER' as a reader. + If the mode is `BDBOWRITER', the following may be added by bitwise-or: `BDBOCREAT', which + means it creates a new database if not exist, `BDBOTRUNC', which means it creates a new + database regardless if one exists, `BDBOTSYNC', which means every transaction synchronizes + updated contents with the device. Both of `BDBOREADER' and `BDBOWRITER' can be added to by + bitwise-or: `BDBONOLCK', which means it opens the database file without file locking, or + `BDBOLCKNB', which means locking is performed without blocking. + If successful, the return value is true, else, it is false. */ +bool tcbdbopen(TCBDB *bdb, const char *path, int omode); + + +/* Close a B+ tree database object. + `bdb' specifies the B+ tree database object. + If successful, the return value is true, else, it is false. + Update of a database is assured to be written when the database is closed. If a writer opens + a database but does not close it appropriately, the database will be broken. */ +bool tcbdbclose(TCBDB *bdb); + + +/* Store a record into a B+ tree database object. + `bdb' specifies the B+ tree database object connected as a writer. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `vbuf' specifies the pointer to the region of the value. + `vsiz' specifies the size of the region of the value. + If successful, the return value is true, else, it is false. + If a record with the same key exists in the database, it is overwritten. */ +bool tcbdbput(TCBDB *bdb, const void *kbuf, int ksiz, const void *vbuf, int vsiz); + + +/* Store a string record into a B+ tree database object. + `bdb' specifies the B+ tree database object connected as a writer. + `kstr' specifies the string of the key. + `vstr' specifies the string of the value. + If successful, the return value is true, else, it is false. + If a record with the same key exists in the database, it is overwritten. */ +bool tcbdbput2(TCBDB *bdb, const char *kstr, const char *vstr); + + +/* Store a new record into a B+ tree database object. + `bdb' specifies the B+ tree database object connected as a writer. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `vbuf' specifies the pointer to the region of the value. + `vsiz' specifies the size of the region of the value. + If successful, the return value is true, else, it is false. + If a record with the same key exists in the database, this function has no effect. */ +bool tcbdbputkeep(TCBDB *bdb, const void *kbuf, int ksiz, const void *vbuf, int vsiz); + + +/* Store a new string record into a B+ tree database object. + `bdb' specifies the B+ tree database object connected as a writer. + `kstr' specifies the string of the key. + `vstr' specifies the string of the value. + If successful, the return value is true, else, it is false. + If a record with the same key exists in the database, this function has no effect. */ +bool tcbdbputkeep2(TCBDB *bdb, const char *kstr, const char *vstr); + + +/* Concatenate a value at the end of the existing record in a B+ tree database object. + `bdb' specifies the B+ tree database object connected as a writer. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `vbuf' specifies the pointer to the region of the value. + `vsiz' specifies the size of the region of the value. + If successful, the return value is true, else, it is false. + If there is no corresponding record, a new record is created. */ +bool tcbdbputcat(TCBDB *bdb, const void *kbuf, int ksiz, const void *vbuf, int vsiz); + + +/* Concatenate a string value at the end of the existing record in a B+ tree database object. + `bdb' specifies the B+ tree database object connected as a writer. + `kstr' specifies the string of the key. + `vstr' specifies the string of the value. + If successful, the return value is true, else, it is false. + If there is no corresponding record, a new record is created. */ +bool tcbdbputcat2(TCBDB *bdb, const char *kstr, const char *vstr); + + +/* Store a record into a B+ tree database object with allowing duplication of keys. + `bdb' specifies the B+ tree database object connected as a writer. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `vbuf' specifies the pointer to the region of the value. + `vsiz' specifies the size of the region of the value. + If successful, the return value is true, else, it is false. + If a record with the same key exists in the database, the new record is placed after the + existing one. */ +bool tcbdbputdup(TCBDB *bdb, const void *kbuf, int ksiz, const void *vbuf, int vsiz); + + +/* Store a string record into a B+ tree database object with allowing duplication of keys. + `bdb' specifies the B+ tree database object connected as a writer. + `kstr' specifies the string of the key. + `vstr' specifies the string of the value. + If successful, the return value is true, else, it is false. + If a record with the same key exists in the database, the new record is placed after the + existing one. */ +bool tcbdbputdup2(TCBDB *bdb, const char *kstr, const char *vstr); + + +/* Store records into a B+ tree database object with allowing duplication of keys. + `bdb' specifies the B+ tree database object connected as a writer. + `kbuf' specifies the pointer to the region of the common key. + `ksiz' specifies the size of the region of the common key. + `vals' specifies a list object containing values. + If successful, the return value is true, else, it is false. + If a record with the same key exists in the database, the new records are placed after the + existing one. */ +bool tcbdbputdup3(TCBDB *bdb, const void *kbuf, int ksiz, const TCLIST *vals); + + +/* Remove a record of a B+ tree database object. + `bdb' specifies the B+ tree database object connected as a writer. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + If successful, the return value is true, else, it is false. + If the key of duplicated records is specified, the first one is selected. */ +bool tcbdbout(TCBDB *bdb, const void *kbuf, int ksiz); + + +/* Remove a string record of a B+ tree database object. + `bdb' specifies the B+ tree database object connected as a writer. + `kstr' specifies the string of the key. + If successful, the return value is true, else, it is false. + If the key of duplicated records is specified, the first one is selected. */ +bool tcbdbout2(TCBDB *bdb, const char *kstr); + + +/* Remove records of a B+ tree database object. + `bdb' specifies the B+ tree database object connected as a writer. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + If successful, the return value is true, else, it is false. + If the key of duplicated records is specified, all of them are removed. */ +bool tcbdbout3(TCBDB *bdb, const void *kbuf, int ksiz); + + +/* Retrieve a record in a B+ tree database object. + `bdb' specifies the B+ tree database object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `sp' specifies the pointer to the variable into which the size of the region of the return + value is assigned. + If successful, the return value is the pointer to the region of the value of the corresponding + record. `NULL' is returned if no record corresponds. + If the key of duplicated records is specified, the first one is selected. Because an + additional zero code is appended at the end of the region of the return value, the return + value can be treated as a character string. Because the region of the return value is + allocated with the `malloc' call, it should be released with the `free' call when it is no + longer in use. */ +void *tcbdbget(TCBDB *bdb, const void *kbuf, int ksiz, int *sp); + + +/* Retrieve a string record in a B+ tree database object. + `bdb' specifies the B+ tree database object. + `kstr' specifies the string of the key. + If successful, the return value is the string of the value of the corresponding record. + `NULL' is returned if no record corresponds. + If the key of duplicated records is specified, the first one is selected. Because the region + of the return value is allocated with the `malloc' call, it should be released with the `free' + call when it is no longer in use. */ +char *tcbdbget2(TCBDB *bdb, const char *kstr); + + +/* Retrieve a record in a B+ tree database object as a volatile buffer. + `bdb' specifies the B+ tree database object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `sp' specifies the pointer to the variable into which the size of the region of the return + value is assigned. + If successful, the return value is the pointer to the region of the value of the corresponding + record. `NULL' is returned if no record corresponds. + If the key of duplicated records is specified, the first one is selected. Because an + additional zero code is appended at the end of the region of the return value, the return + value can be treated as a character string. Because the region of the return value is + volatile and it may be spoiled by another operation of the database, the data should be copied + into another involatile buffer immediately. */ +const void *tcbdbget3(TCBDB *bdb, const void *kbuf, int ksiz, int *sp); + + +/* Retrieve records in a B+ tree database object. + `bdb' specifies the B+ tree database object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + If successful, the return value is a list object of the values of the corresponding records. + `NULL' is returned if no record corresponds. + Because the object of the return value is created with the function `tclistnew', it should + be deleted with the function `tclistdel' when it is no longer in use. */ +TCLIST *tcbdbget4(TCBDB *bdb, const void *kbuf, int ksiz); + + +/* Get the number of records corresponding a key in a B+ tree database object. + `bdb' specifies the B+ tree database object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + If successful, the return value is the number of the corresponding records, else, it is 0. */ +int tcbdbvnum(TCBDB *bdb, const void *kbuf, int ksiz); + + +/* Get the number of records corresponding a string key in a B+ tree database object. + `bdb' specifies the B+ tree database object. + `kstr' specifies the string of the key. + If successful, the return value is the number of the corresponding records, else, it is 0. */ +int tcbdbvnum2(TCBDB *bdb, const char *kstr); + + +/* Get the size of the value of a record in a B+ tree database object. + `bdb' specifies the B+ tree database object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + If successful, the return value is the size of the value of the corresponding record, else, + it is -1. + If the key of duplicated records is specified, the first one is selected. */ +int tcbdbvsiz(TCBDB *bdb, const void *kbuf, int ksiz); + + +/* Get the size of the value of a string record in a B+ tree database object. + `bdb' specifies the B+ tree database object. + `kstr' specifies the string of the key. + If successful, the return value is the size of the value of the corresponding record, else, + it is -1. + If the key of duplicated records is specified, the first one is selected. */ +int tcbdbvsiz2(TCBDB *bdb, const char *kstr); + + +/* Get keys of ranged records in a B+ tree database object. + `bdb' specifies the B+ tree database object. + `bkbuf' specifies the pointer to the region of the key of the beginning border. If it is + `NULL', the first record is specified. + `bksiz' specifies the size of the region of the beginning key. + `binc' specifies whether the beginning border is inclusive or not. + `ekbuf' specifies the pointer to the region of the key of the ending border. If it is `NULL', + the last record is specified. + `eksiz' specifies the size of the region of the ending key. + `einc' specifies whether the ending border is inclusive or not. + `max' specifies the maximum number of keys to be fetched. If it is negative, no limit is + specified. + The return value is a list object of the keys of the corresponding records. This function + does never fail. It returns an empty list even if no record corresponds. + Because the object of the return value is created with the function `tclistnew', it should + be deleted with the function `tclistdel' when it is no longer in use. */ +TCLIST *tcbdbrange(TCBDB *bdb, const void *bkbuf, int bksiz, bool binc, + const void *ekbuf, int eksiz, bool einc, int max); + + +/* Get string keys of ranged records in a B+ tree database object. + `bdb' specifies the B+ tree database object. + `bkstr' specifies the string of the key of the beginning border. If it is `NULL', the first + record is specified. + `binc' specifies whether the beginning border is inclusive or not. + `ekstr' specifies the string of the key of the ending border. If it is `NULL', the last + record is specified. + `einc' specifies whether the ending border is inclusive or not. + `max' specifies the maximum number of keys to be fetched. If it is negative, no limit is + specified. + The return value is a list object of the keys of the corresponding records. This function + does never fail. It returns an empty list even if no record corresponds. + Because the object of the return value is created with the function `tclistnew', it should + be deleted with the function `tclistdel' when it is no longer in use. */ +TCLIST *tcbdbrange2(TCBDB *bdb, const char *bkstr, bool binc, + const char *ekstr, bool einc, int max); + + +/* Get forward matching keys in a B+ tree database object. + `bdb' specifies the B+ tree database object. + `pbuf' specifies the pointer to the region of the prefix. + `psiz' specifies the size of the region of the prefix. + `max' specifies the maximum number of keys to be fetched. If it is negative, no limit is + specified. + The return value is a list object of the corresponding keys. This function does never fail. + It returns an empty list even if no key corresponds. + Because the object of the return value is created with the function `tclistnew', it should be + deleted with the function `tclistdel' when it is no longer in use. */ +TCLIST *tcbdbfwmkeys(TCBDB *bdb, const void *pbuf, int psiz, int max); + + +/* Get forward matching string keys in a B+ tree database object. + `bdb' specifies the B+ tree database object. + `pstr' specifies the string of the prefix. + `max' specifies the maximum number of keys to be fetched. If it is negative, no limit is + specified. + The return value is a list object of the corresponding keys. This function does never fail. + It returns an empty list even if no key corresponds. + Because the object of the return value is created with the function `tclistnew', it should be + deleted with the function `tclistdel' when it is no longer in use. */ +TCLIST *tcbdbfwmkeys2(TCBDB *bdb, const char *pstr, int max); + + +/* Add an integer to a record in a B+ tree database object. + `bdb' specifies the B+ tree database object connected as a writer. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `num' specifies the additional value. + If successful, the return value is the summation value, else, it is `INT_MIN'. + If the corresponding record exists, the value is treated as an integer and is added to. If no + record corresponds, a new record of the additional value is stored. */ +int tcbdbaddint(TCBDB *bdb, const void *kbuf, int ksiz, int num); + + +/* Add a real number to a record in a B+ tree database object. + `bdb' specifies the B+ tree database object connected as a writer. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `num' specifies the additional value. + If successful, the return value is the summation value, else, it is Not-a-Number. + If the corresponding record exists, the value is treated as a real number and is added to. If + no record corresponds, a new record of the additional value is stored. */ +double tcbdbadddouble(TCBDB *bdb, const void *kbuf, int ksiz, double num); + + +/* Synchronize updated contents of a B+ tree database object with the file and the device. + `bdb' specifies the B+ tree database object connected as a writer. + If successful, the return value is true, else, it is false. + This function is useful when another process connects to the same database file. */ +bool tcbdbsync(TCBDB *bdb); + + +/* Optimize the file of a B+ tree database object. + `bdb' specifies the B+ tree database object connected as a writer. + `lmemb' specifies the number of members in each leaf page. If it is not more than 0, the + current setting is not changed. + `nmemb' specifies the number of members in each non-leaf page. If it is not more than 0, the + current setting is not changed. + `bnum' specifies the number of elements of the bucket array. If it is not more than 0, the + default value is specified. The default value is two times of the number of pages. + `apow' specifies the size of record alignment by power of 2. If it is negative, the current + setting is not changed. + `fpow' specifies the maximum number of elements of the free block pool by power of 2. If it + is negative, the current setting is not changed. + `opts' specifies options by bitwise-or: `BDBTLARGE' specifies that the size of the database + can be larger than 2GB by using 64-bit bucket array, `BDBTDEFLATE' specifies that each record + is compressed with Deflate encoding, `BDBTBZIP' specifies that each page is compressed with + BZIP2 encoding, `BDBTTCBS' specifies that each page is compressed with TCBS encoding. If it + is `UINT8_MAX', the current setting is not changed. + If successful, the return value is true, else, it is false. + This function is useful to reduce the size of the database file with data fragmentation by + successive updating. */ +bool tcbdboptimize(TCBDB *bdb, int32_t lmemb, int32_t nmemb, + int64_t bnum, int8_t apow, int8_t fpow, uint8_t opts); + + +/* Remove all records of a B+ tree database object. + `bdb' specifies the B+ tree database object connected as a writer. + If successful, the return value is true, else, it is false. */ +bool tcbdbvanish(TCBDB *bdb); + + +/* Copy the database file of a B+ tree database object. + `bdb' specifies the B+ tree database object. + `path' specifies the path of the destination file. If it begins with `@', the trailing + substring is executed as a command line. + If successful, the return value is true, else, it is false. False is returned if the executed + command returns non-zero code. + The database file is assured to be kept synchronized and not modified while the copying or + executing operation is in progress. So, this function is useful to create a backup file of + the database file. */ +bool tcbdbcopy(TCBDB *bdb, const char *path); + + +/* Begin the transaction of a B+ tree database object. + `bdb' specifies the B+ tree database object connected as a writer. + If successful, the return value is true, else, it is false. + The database is locked by the thread while the transaction so that only one transaction can be + activated with a database object at the same time. Thus, the serializable isolation level is + assumed if every database operation is performed in the transaction. Because all pages are + cached on memory while the transaction, the amount of referred records is limited by the + memory capacity. If the database is closed during transaction, the transaction is aborted + implicitly. */ +bool tcbdbtranbegin(TCBDB *bdb); + + +/* Commit the transaction of a B+ tree database object. + `bdb' specifies the B+ tree database object connected as a writer. + If successful, the return value is true, else, it is false. + Update in the transaction is fixed when it is committed successfully. */ +bool tcbdbtrancommit(TCBDB *bdb); + + +/* Abort the transaction of a B+ tree database object. + `bdb' specifies the B+ tree database object connected as a writer. + If successful, the return value is true, else, it is false. + Update in the transaction is discarded when it is aborted. The state of the database is + rollbacked to before transaction. */ +bool tcbdbtranabort(TCBDB *bdb); + + +/* Get the file path of a B+ tree database object. + `bdb' specifies the B+ tree database object. + The return value is the path of the database file or `NULL' if the object does not connect to + any database file. */ +const char *tcbdbpath(TCBDB *bdb); + + +/* Get the number of records of a B+ tree database object. + `bdb' specifies the B+ tree database object. + The return value is the number of records or 0 if the object does not connect to any database + file. */ +uint64_t tcbdbrnum(TCBDB *bdb); + + +/* Get the size of the database file of a B+ tree database object. + `bdb' specifies the B+ tree database object. + The return value is the size of the database file or 0 if the object does not connect to any + database file. */ +uint64_t tcbdbfsiz(TCBDB *bdb); + + +/* Create a cursor object. + `bdb' specifies the B+ tree database object. + The return value is the new cursor object. + Note that the cursor is available only after initialization with the `tcbdbcurfirst' or the + `tcbdbcurjump' functions and so on. Moreover, the position of the cursor will be indefinite + when the database is updated after the initialization of the cursor. */ +BDBCUR *tcbdbcurnew(TCBDB *bdb); + + +/* Delete a cursor object. + `cur' specifies the cursor object. */ +void tcbdbcurdel(BDBCUR *cur); + + +/* Move a cursor object to the first record. + `cur' specifies the cursor object. + If successful, the return value is true, else, it is false. False is returned if there is + no record in the database. */ +bool tcbdbcurfirst(BDBCUR *cur); + + +/* Move a cursor object to the last record. + `cur' specifies the cursor object. + If successful, the return value is true, else, it is false. False is returned if there is + no record in the database. */ +bool tcbdbcurlast(BDBCUR *cur); + + +/* Move a cursor object to the front of records corresponding a key. + `cur' specifies the cursor object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + If successful, the return value is true, else, it is false. False is returned if there is + no record corresponding the condition. + The cursor is set to the first record corresponding the key or the next substitute if + completely matching record does not exist. */ +bool tcbdbcurjump(BDBCUR *cur, const void *kbuf, int ksiz); + + +/* Move a cursor object to the front of records corresponding a key string. + `cur' specifies the cursor object. + `kstr' specifies the string of the key. + If successful, the return value is true, else, it is false. False is returned if there is + no record corresponding the condition. + The cursor is set to the first record corresponding the key or the next substitute if + completely matching record does not exist. */ +bool tcbdbcurjump2(BDBCUR *cur, const char *kstr); + + +/* Move a cursor object to the previous record. + `cur' specifies the cursor object. + If successful, the return value is true, else, it is false. False is returned if there is + no previous record. */ +bool tcbdbcurprev(BDBCUR *cur); + + +/* Move a cursor object to the next record. + `cur' specifies the cursor object. + If successful, the return value is true, else, it is false. False is returned if there is + no next record. */ +bool tcbdbcurnext(BDBCUR *cur); + + +/* Insert a record around a cursor object. + `cur' specifies the cursor object of writer connection. + `vbuf' specifies the pointer to the region of the value. + `vsiz' specifies the size of the region of the value. + `cpmode' specifies detail adjustment: `BDBCPCURRENT', which means that the value of the + current record is overwritten, `BDBCPBEFORE', which means that the new record is inserted + before the current record, `BDBCPAFTER', which means that the new record is inserted after the + current record. + If successful, the return value is true, else, it is false. False is returned when the cursor + is at invalid position. + After insertion, the cursor is moved to the inserted record. */ +bool tcbdbcurput(BDBCUR *cur, const void *vbuf, int vsiz, int cpmode); + + +/* Insert a string record around a cursor object. + `cur' specifies the cursor object of writer connection. + `vstr' specifies the string of the value. + `cpmode' specifies detail adjustment: `BDBCPCURRENT', which means that the value of the + current record is overwritten, `BDBCPBEFORE', which means that the new record is inserted + before the current record, `BDBCPAFTER', which means that the new record is inserted after the + current record. + If successful, the return value is true, else, it is false. False is returned when the cursor + is at invalid position. + After insertion, the cursor is moved to the inserted record. */ +bool tcbdbcurput2(BDBCUR *cur, const char *vstr, int cpmode); + + +/* Remove the record where a cursor object is. + `cur' specifies the cursor object of writer connection. + If successful, the return value is true, else, it is false. False is returned when the cursor + is at invalid position. + After deletion, the cursor is moved to the next record if possible. */ +bool tcbdbcurout(BDBCUR *cur); + + +/* Get the key of the record where the cursor object is. + `cur' specifies the cursor object. + `sp' specifies the pointer to the variable into which the size of the region of the return + value is assigned. + If successful, the return value is the pointer to the region of the key, else, it is `NULL'. + `NULL' is returned when the cursor is at invalid position. + Because an additional zero code is appended at the end of the region of the return value, + the return value can be treated as a character string. Because the region of the return + value is allocated with the `malloc' call, it should be released with the `free' call when + it is no longer in use. */ +void *tcbdbcurkey(BDBCUR *cur, int *sp); + + +/* Get the key string of the record where the cursor object is. + `cur' specifies the cursor object. + If successful, the return value is the string of the key, else, it is `NULL'. `NULL' is + returned when the cursor is at invalid position. + Because the region of the return value is allocated with the `malloc' call, it should be + released with the `free' call when it is no longer in use. */ +char *tcbdbcurkey2(BDBCUR *cur); + + +/* Get the key of the record where the cursor object is, as a volatile buffer. + `cur' specifies the cursor object. + `sp' specifies the pointer to the variable into which the size of the region of the return + value is assigned. + If successful, the return value is the pointer to the region of the key, else, it is `NULL'. + `NULL' is returned when the cursor is at invalid position. + Because an additional zero code is appended at the end of the region of the return value, + the return value can be treated as a character string. Because the region of the return value + is volatile and it may be spoiled by another operation of the database, the data should be + copied into another involatile buffer immediately. */ +const void *tcbdbcurkey3(BDBCUR *cur, int *sp); + + +/* Get the value of the record where the cursor object is. + `cur' specifies the cursor object. + `sp' specifies the pointer to the variable into which the size of the region of the return + value is assigned. + If successful, the return value is the pointer to the region of the value, else, it is `NULL'. + `NULL' is returned when the cursor is at invalid position. + Because an additional zero code is appended at the end of the region of the return value, + the return value can be treated as a character string. Because the region of the return + value is allocated with the `malloc' call, it should be released with the `free' call when + it is no longer in use. */ +void *tcbdbcurval(BDBCUR *cur, int *sp); + + +/* Get the value string of the record where the cursor object is. + `cur' specifies the cursor object. + If successful, the return value is the string of the value, else, it is `NULL'. `NULL' is + returned when the cursor is at invalid position. + Because the region of the return value is allocated with the `malloc' call, it should be + released with the `free' call when it is no longer in use. */ +char *tcbdbcurval2(BDBCUR *cur); + + +/* Get the value of the record where the cursor object is, as a volatile buffer. + `cur' specifies the cursor object. + `sp' specifies the pointer to the variable into which the size of the region of the return + value is assigned. + If successful, the return value is the pointer to the region of the value, else, it is `NULL'. + `NULL' is returned when the cursor is at invalid position. + Because an additional zero code is appended at the end of the region of the return value, + the return value can be treated as a character string. Because the region of the return value + is volatile and it may be spoiled by another operation of the database, the data should be + copied into another involatile buffer immediately. */ +const void *tcbdbcurval3(BDBCUR *cur, int *sp); + + +/* Get the key and the value of the record where the cursor object is. + `cur' specifies the cursor object. + `kxstr' specifies the object into which the key is wrote down. + `vxstr' specifies the object into which the value is wrote down. + If successful, the return value is true, else, it is false. False is returned when the cursor + is at invalid position. */ +bool tcbdbcurrec(BDBCUR *cur, TCXSTR *kxstr, TCXSTR *vxstr); + + + +/************************************************************************************************* + * features for experts + *************************************************************************************************/ + + +/* Set the error code of a B+ tree database object. + `bdb' specifies the B+ tree database object. + `ecode' specifies the error code. + `file' specifies the file name of the code. + `line' specifies the line number of the code. + `func' specifies the function name of the code. */ +void tcbdbsetecode(TCBDB *bdb, int ecode, const char *filename, int line, const char *func); + + +/* Set the file descriptor for debugging output. + `bdb' specifies the B+ tree database object. + `fd' specifies the file descriptor for debugging output. */ +void tcbdbsetdbgfd(TCBDB *bdb, int fd); + + +/* Get the file descriptor for debugging output. + `bdb' specifies the B+ tree database object. + The return value is the file descriptor for debugging output. */ +int tcbdbdbgfd(TCBDB *bdb); + + +/* Check whether mutual exclusion control is set to a B+ tree database object. + `bdb' specifies the B+ tree database object. + If mutual exclusion control is set, it is true, else it is false. */ +bool tcbdbhasmutex(TCBDB *bdb); + + +/* Synchronize updating contents on memory of a B+ tree database object. + `bdb' specifies the B+ tree database object connected as a writer. + `phys' specifies whether to synchronize physically. + If successful, the return value is true, else, it is false. */ +bool tcbdbmemsync(TCBDB *bdb, bool phys); + + +/* Clear the cache of a B+ tree database object. + `bdb' specifies the B+ tree database object. + If successful, the return value is true, else, it is false. */ +bool tcbdbcacheclear(TCBDB *bdb); + + +/* Get the comparison function of a B+ tree database object. + `bdb' specifies the B+ tree database object. + The return value is the pointer to the comparison function. */ +TCCMP tcbdbcmpfunc(TCBDB *bdb); + + +/* Get the opaque object for the comparison function of a B+ tree database object. + `bdb' specifies the B+ tree database object. + The return value is the opaque object for the comparison function. */ +void *tcbdbcmpop(TCBDB *bdb); + + +/* Get the maximum number of cached leaf nodes of a B+ tree database object. + `bdb' specifies the B+ tree database object. + The return value is the maximum number of cached leaf nodes. */ +uint32_t tcbdblmemb(TCBDB *bdb); + + +/* Get the maximum number of cached non-leaf nodes of a B+ tree database object. + `bdb' specifies the B+ tree database object. + The return value is the maximum number of cached non-leaf nodes. */ +uint32_t tcbdbnmemb(TCBDB *bdb); + + +/* Get the number of the leaf nodes of B+ tree database object. + `bdb' specifies the B+ tree database object. + If successful, the return value is the number of the leaf nodes or 0 if the object does not + connect to any database file. */ +uint64_t tcbdblnum(TCBDB *bdb); + + +/* Get the number of the non-leaf nodes of B+ tree database object. + `bdb' specifies the B+ tree database object. + If successful, the return value is the number of the non-leaf nodes or 0 if the object does + not connect to any database file. */ +uint64_t tcbdbnnum(TCBDB *bdb); + + +/* Get the number of elements of the bucket array of a B+ tree database object. + `bdb' specifies the B+ tree database object. + The return value is the number of elements of the bucket array or 0 if the object does not + connect to any database file. */ +uint64_t tcbdbbnum(TCBDB *bdb); + + +/* Get the record alignment of a B+ tree database object. + `bdb' specifies the B+ tree database object. + The return value is the record alignment or 0 if the object does not connect to any database + file. */ +uint32_t tcbdbalign(TCBDB *bdb); + + +/* Get the maximum number of the free block pool of a B+ tree database object. + `bdb' specifies the B+ tree database object. + The return value is the maximum number of the free block pool or 0 if the object does not + connect to any database file. */ +uint32_t tcbdbfbpmax(TCBDB *bdb); + + +/* Get the inode number of the database file of a B+ tree database object. + `bdb' specifies the B+ tree database object. + The return value is the inode number of the database file or 0 if the object does not connect + to any database file. */ +uint64_t tcbdbinode(TCBDB *bdb); + + +/* Get the modification time of the database file of a B+ tree database object. + `bdb' specifies the B+ tree database object. + The return value is the inode number of the database file or 0 if the object does not connect + to any database file. */ +time_t tcbdbmtime(TCBDB *bdb); + + +/* Get the additional flags of a B+ tree database object. + `bdb' specifies the B+ tree database object. + The return value is the additional flags. */ +uint8_t tcbdbflags(TCBDB *bdb); + + +/* Get the options of a B+ tree database object. + `bdb' specifies the B+ tree database object. + The return value is the options. */ +uint8_t tcbdbopts(TCBDB *bdb); + + +/* Get the pointer to the opaque field of a B+ tree database object. + `bdb' specifies the B+ tree database object. + The return value is the pointer to the opaque field whose size is 128 bytes. */ +char *tcbdbopaque(TCBDB *bdb); + + +/* Get the number of used elements of the bucket array of a B+ tree database object. + `bdb' specifies the B+ tree database object. + The return value is the number of used elements of the bucket array or 0 if the object does not + connect to any database file. */ +uint64_t tcbdbbnumused(TCBDB *bdb); + + +/* Set the maximum size of each leaf node. + `bdb' specifies the B+ tree database object which is not opened. + `lsmax' specifies the maximum size of each leaf node. If it is not more than 0, the default + value is specified. The default value is 16386. + If successful, the return value is true, else, it is false. + Note that the tuning parameters of the database should be set before the database is opened. */ +bool tcbdbsetlsmax(TCBDB *bdb, uint32_t lsmax); + + +/* Set the capacity number of records. + `bdb' specifies the B+ tree database object which is not opened. + `capnum' specifies the capacity number of records. If it is not more than 0, the capacity is + unlimited. + If successful, the return value is true, else, it is false. + When the number of records exceeds the capacity, forehand records are removed implicitly. + Note that the tuning parameters of the database should be set before the database is opened. */ +bool tcbdbsetcapnum(TCBDB *bdb, uint64_t capnum); + + +/* Set the custom codec functions of a B+ tree database object. + `bdb' specifies the B+ tree database object. + `enc' specifies the pointer to the custom encoding function. It receives four parameters. + The first parameter is the pointer to the region. The second parameter is the size of the + region. The third parameter is the pointer to the variable into which the size of the region + of the return value is assigned. The fourth parameter is the pointer to the optional opaque + object. It returns the pointer to the result object allocated with `malloc' call if + successful, else, it returns `NULL'. + `encop' specifies an arbitrary pointer to be given as a parameter of the encoding function. + If it is not needed, `NULL' can be specified. + `dec' specifies the pointer to the custom decoding function. + `decop' specifies an arbitrary pointer to be given as a parameter of the decoding function. + If it is not needed, `NULL' can be specified. + If successful, the return value is true, else, it is false. + Note that the custom codec functions should be set before the database is opened and should be + set every time the database is being opened. */ +bool tcbdbsetcodecfunc(TCBDB *bdb, TCCODEC enc, void *encop, TCCODEC dec, void *decop); + + +/* Get the unit step number of auto defragmentation of a B+ tree database object. + `bdb' specifies the B+ tree database object. + The return value is the unit step number of auto defragmentation. */ +uint32_t tcbdbdfunit(TCBDB *bdb); + + +/* Perform dynamic defragmentation of a B+ tree database object. + `bdb' specifies the B+ tree database object connected as a writer. + `step' specifie the number of steps. If it is not more than 0, the whole file is defragmented + gradually without keeping a continuous lock. + If successful, the return value is true, else, it is false. */ +bool tcbdbdefrag(TCBDB *bdb, int64_t step); + + +/* Store a new record into a B+ tree database object with backward duplication. + `bdb' specifies the B+ tree database object connected as a writer. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `vbuf' specifies the pointer to the region of the value. + `vsiz' specifies the size of the region of the value. + If successful, the return value is true, else, it is false. + If a record with the same key exists in the database, the new record is placed after the + existing one. */ +bool tcbdbputdupback(TCBDB *bdb, const void *kbuf, int ksiz, const void *vbuf, int vsiz); + + +/* Store a new string record into a B+ tree database object with backward duplication. + `bdb' specifies the B+ tree database object connected as a writer. + `kstr' specifies the string of the key. + `vstr' specifies the string of the value. + If successful, the return value is true, else, it is false. + If a record with the same key exists in the database, the new record is placed after the + existing one. */ +bool tcbdbputdupback2(TCBDB *bdb, const char *kstr, const char *vstr); + + +/* Store a record into a B+ tree database object with a duplication handler. + `bdb' specifies the B+ tree database object connected as a writer. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `vbuf' specifies the pointer to the region of the value. `NULL' means that record addition is + ommited if there is no corresponding record. + `vsiz' specifies the size of the region of the value. + `proc' specifies the pointer to the callback function to process duplication. It receives + four parameters. The first parameter is the pointer to the region of the value. The second + parameter is the size of the region of the value. The third parameter is the pointer to the + variable into which the size of the region of the return value is assigned. The fourth + parameter is the pointer to the optional opaque object. It returns the pointer to the result + object allocated with `malloc'. It is released by the caller. If it is `NULL', the record is + not modified. If it is `(void *)-1', the record is removed. + `op' specifies an arbitrary pointer to be given as a parameter of the callback function. If + it is not needed, `NULL' can be specified. + If successful, the return value is true, else, it is false. + Note that the callback function can not perform any database operation because the function + is called in the critical section guarded by the same locks of database operations. */ +bool tcbdbputproc(TCBDB *bdb, const void *kbuf, int ksiz, const void *vbuf, int vsiz, + TCPDPROC proc, void *op); + + +/* Move a cursor object to the rear of records corresponding a key. + `cur' specifies the cursor object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + If successful, the return value is true, else, it is false. False is returned if there is + no record corresponding the condition. + The cursor is set to the last record corresponding the key or the previous substitute if + completely matching record does not exist. */ +bool tcbdbcurjumpback(BDBCUR *cur, const void *kbuf, int ksiz); + + +/* Move a cursor object to the rear of records corresponding a key string. + `cur' specifies the cursor object. + `kstr' specifies the string of the key. + If successful, the return value is true, else, it is false. False is returned if there is + no record corresponding the condition. + The cursor is set to the last record corresponding the key or the previous substitute if + completely matching record does not exist. */ +bool tcbdbcurjumpback2(BDBCUR *cur, const char *kstr); + + +/* Process each record atomically of a B+ tree database object. + `bdb' specifies the B+ tree database object. + `iter' specifies the pointer to the iterator function called for each record. It receives + five parameters. The first parameter is the pointer to the region of the key. The second + parameter is the size of the region of the key. The third parameter is the pointer to the + region of the value. The fourth parameter is the size of the region of the value. The fifth + parameter is the pointer to the optional opaque object. It returns true to continue iteration + or false to stop iteration. + `op' specifies an arbitrary pointer to be given as a parameter of the iterator function. If + it is not needed, `NULL' can be specified. + If successful, the return value is true, else, it is false. + Note that the callback function can not perform any database operation because the function + is called in the critical section guarded by the same locks of database operations. */ +bool tcbdbforeach(TCBDB *bdb, TCITER iter, void *op); + + + +__TCBDB_CLINKAGEEND +#endif /* duplication check */ + + +/* END OF FILE */ diff --git a/lib_dict/tc/include/tcfdb.h b/lib_dict/tc/include/tcfdb.h new file mode 100644 index 000000000..2154fc8ae --- /dev/null +++ b/lib_dict/tc/include/tcfdb.h @@ -0,0 +1,864 @@ +/************************************************************************************************* + * The fixed-length database API of Tokyo Cabinet + * Copyright (C) 2006-2009 Mikio Hirabayashi + * This file is part of Tokyo Cabinet. + * Tokyo Cabinet is free software; you can redistribute it and/or modify it under the terms of + * the GNU Lesser General Public License as published by the Free Software Foundation; either + * version 2.1 of the License or any later version. Tokyo Cabinet is distributed in the hope + * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * You should have received a copy of the GNU Lesser General Public License along with Tokyo + * Cabinet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA. + *************************************************************************************************/ + + +#ifndef _TCFDB_H /* duplication check */ +#define _TCFDB_H + +#if defined(__cplusplus) +#define __TCFDB_CLINKAGEBEGIN extern "C" { +#define __TCFDB_CLINKAGEEND } +#else +#define __TCFDB_CLINKAGEBEGIN +#define __TCFDB_CLINKAGEEND +#endif +__TCFDB_CLINKAGEBEGIN + + +#include +#include +#include +#include +#include +#include +#include + + + +/************************************************************************************************* + * API + *************************************************************************************************/ + + +typedef struct { /* type of structure for a fixed-length database */ + void *mmtx; /* mutex for method */ + void *amtx; /* mutex for attribute */ + void *rmtxs; /* mutexes for records */ + void *tmtx; /* mutex for transaction */ + void *wmtx; /* mutex for write ahead logging */ + void *eckey; /* key for thread specific error code */ + char *rpath; /* real path for locking */ + uint8_t type; /* database type */ + uint8_t flags; /* additional flags */ + uint32_t width; /* width of the value of each record */ + uint64_t limsiz; /* limit size of the file */ + int wsiz; /* size of the width region */ + int rsiz; /* size of each record */ + uint64_t limid; /* limit ID number */ + char *path; /* path of the database file */ + int fd; /* file descriptor of the database file */ + uint32_t omode; /* open mode */ + uint64_t rnum; /* number of the records */ + uint64_t fsiz; /* size of the database file */ + uint64_t min; /* minimum ID number */ + uint64_t max; /* maximum ID number */ + uint64_t iter; /* ID number of the iterator */ + char *map; /* pointer to the mapped memory */ + unsigned char *array; /* pointer to the array region */ + int ecode; /* last happened error code */ + bool fatal; /* whether a fatal error occured */ + uint64_t inode; /* inode number */ + time_t mtime; /* modification time */ + bool tran; /* whether in the transaction */ + int walfd; /* file descriptor of write ahead logging */ + uint64_t walend; /* end offset of write ahead logging */ + int dbgfd; /* file descriptor for debugging */ + int64_t cnt_writerec; /* tesing counter for record write times */ + int64_t cnt_readrec; /* tesing counter for record read times */ + int64_t cnt_truncfile; /* tesing counter for file truncate times */ +} TCFDB; + +enum { /* enumeration for additional flags */ + FDBFOPEN = 1 << 0, /* whether opened */ + FDBFFATAL = 1 << 1 /* whetehr with fatal error */ +}; + +enum { /* enumeration for open modes */ + FDBOREADER = 1 << 0, /* open as a reader */ + FDBOWRITER = 1 << 1, /* open as a writer */ + FDBOCREAT = 1 << 2, /* writer creating */ + FDBOTRUNC = 1 << 3, /* writer truncating */ + FDBONOLCK = 1 << 4, /* open without locking */ + FDBOLCKNB = 1 << 5, /* lock without blocking */ + FDBOTSYNC = 1 << 6 /* synchronize every transaction */ +}; + +enum { /* enumeration for ID constants */ + FDBIDMIN = -1, /* minimum number */ + FDBIDPREV = -2, /* less by one than the minimum */ + FDBIDMAX = -3, /* maximum number */ + FDBIDNEXT = -4 /* greater by one than the miximum */ +}; + + +/* Get the message string corresponding to an error code. + `ecode' specifies the error code. + The return value is the message string of the error code. */ +const char *tcfdberrmsg(int ecode); + + +/* Create a fixed-length database object. + The return value is the new fixed-length database object. */ +TCFDB *tcfdbnew(void); + + +/* Delete a fixed-length database object. + `fdb' specifies the fixed-length database object. + If the database is not closed, it is closed implicitly. Note that the deleted object and its + derivatives can not be used anymore. */ +void tcfdbdel(TCFDB *fdb); + + +/* Get the last happened error code of a fixed-length database object. + `fdb' specifies the fixed-length database object. + The return value is the last happened error code. + The following error codes are defined: `TCESUCCESS' for success, `TCETHREAD' for threading + error, `TCEINVALID' for invalid operation, `TCENOFILE' for file not found, `TCENOPERM' for no + permission, `TCEMETA' for invalid meta data, `TCERHEAD' for invalid record header, `TCEOPEN' + for open error, `TCECLOSE' for close error, `TCETRUNC' for trunc error, `TCESYNC' for sync + error, `TCESTAT' for stat error, `TCESEEK' for seek error, `TCEREAD' for read error, + `TCEWRITE' for write error, `TCEMMAP' for mmap error, `TCELOCK' for lock error, `TCEUNLINK' + for unlink error, `TCERENAME' for rename error, `TCEMKDIR' for mkdir error, `TCERMDIR' for + rmdir error, `TCEKEEP' for existing record, `TCENOREC' for no record found, and `TCEMISC' for + miscellaneous error. */ +int tcfdbecode(TCFDB *fdb); + + +/* Set mutual exclusion control of a fixed-length database object for threading. + `fdb' specifies the fixed-length database object which is not opened. + If successful, the return value is true, else, it is false. + Note that the mutual exclusion control is needed if the object is shared by plural threads and + this function should should be called before the database is opened. */ +bool tcfdbsetmutex(TCFDB *fdb); + + +/* Set the tuning parameters of a fixed-length database object. + `fdb' specifies the fixed-length database object which is not opened. + `width' specifies the width of the value of each record. If it is not more than 0, the + default value is specified. The default value is 255. + `limsiz' specifies the limit size of the database file. If it is not more than 0, the default + value is specified. The default value is 268435456. + If successful, the return value is true, else, it is false. + Note that the tuning parameters should be set before the database is opened. */ +bool tcfdbtune(TCFDB *fdb, int32_t width, int64_t limsiz); + + +/* Open a database file and connect a fixed-length database object. + `fdb' specifies the fixed-length database object which is not opened. + `path' specifies the path of the database file. + `omode' specifies the connection mode: `FDBOWRITER' as a writer, `FDBOREADER' as a reader. + If the mode is `FDBOWRITER', the following may be added by bitwise-or: `FDBOCREAT', which + means it creates a new database if not exist, `FDBOTRUNC', which means it creates a new + database regardless if one exists, `FDBOTSYNC', which means every transaction synchronizes + updated contents with the device. Both of `FDBOREADER' and `FDBOWRITER' can be added to by + bitwise-or: `FDBONOLCK', which means it opens the database file without file locking, or + `FDBOLCKNB', which means locking is performed without blocking. + If successful, the return value is true, else, it is false. */ +bool tcfdbopen(TCFDB *fdb, const char *path, int omode); + + +/* Close a fixed-length database object. + `fdb' specifies the fixed-length database object. + If successful, the return value is true, else, it is false. + Update of a database is assured to be written when the database is closed. If a writer opens + a database but does not close it appropriately, the database will be broken. */ +bool tcfdbclose(TCFDB *fdb); + + +/* Store a record into a fixed-length database object. + `fdb' specifies the fixed-length database object connected as a writer. + `id' specifies the ID number. It should be more than 0. If it is `FDBIDMIN', the minimum ID + number of existing records is specified. If it is `FDBIDPREV', the number less by one than + the minimum ID number of existing records is specified. If it is `FDBIDMAX', the maximum ID + number of existing records is specified. If it is `FDBIDNEXT', the number greater by one than + the maximum ID number of existing records is specified. + `vbuf' specifies the pointer to the region of the value. + `vsiz' specifies the size of the region of the value. If the size of the value is greater + than the width tuning parameter of the database, the size is cut down to the width. + If successful, the return value is true, else, it is false. + If a record with the same key exists in the database, it is overwritten. */ +bool tcfdbput(TCFDB *fdb, int64_t id, const void *vbuf, int vsiz); + + +/* Store a record with a decimal key into a fixed-length database object. + `fdb' specifies the fixed-length database object connected as a writer. + `kbuf' specifies the pointer to the region of the decimal key. It should be more than 0. If + it is "min", the minimum ID number of existing records is specified. If it is "prev", the + number less by one than the minimum ID number of existing records is specified. If it is + "max", the maximum ID number of existing records is specified. If it is "next", the number + greater by one than the maximum ID number of existing records is specified. + `ksiz' specifies the size of the region of the key. + `vbuf' specifies the pointer to the region of the value. + `vsiz' specifies the size of the region of the value. If the size of the value is greater + than the width tuning parameter of the database, the size is cut down to the width. + If successful, the return value is true, else, it is false. + If a record with the same key exists in the database, it is overwritten. */ +bool tcfdbput2(TCFDB *fdb, const void *kbuf, int ksiz, const void *vbuf, int vsiz); + + +/* Store a string record with a decimal key into a fixed-length database object. + `fdb' specifies the fixed-length database object connected as a writer. + `kstr' specifies the string of the decimal key. It should be more than 0. If it is "min", + the minimum ID number of existing records is specified. If it is "prev", the number less by + one than the minimum ID number of existing records is specified. If it is "max", the maximum + ID number of existing records is specified. If it is "next", the number greater by one than + the maximum ID number of existing records is specified. + `vstr' specifies the string of the value. + If successful, the return value is true, else, it is false. + If a record with the same key exists in the database, it is overwritten. */ +bool tcfdbput3(TCFDB *fdb, const char *kstr, const void *vstr); + + +/* Store a new record into a fixed-length database object. + `fdb' specifies the fixed-length database object connected as a writer. + `id' specifies the ID number. It should be more than 0. If it is `FDBIDMIN', the minimum ID + number of existing records is specified. If it is `FDBIDPREV', the number less by one than + the minimum ID number of existing records is specified. If it is `FDBIDMAX', the maximum ID + number of existing records is specified. If it is `FDBIDNEXT', the number greater by one than + the maximum ID number of existing records is specified. + `vbuf' specifies the pointer to the region of the value. + `vsiz' specifies the size of the region of the value. If the size of the value is greater + than the width tuning parameter of the database, the size is cut down to the width. + If successful, the return value is true, else, it is false. + If a record with the same key exists in the database, this function has no effect. */ +bool tcfdbputkeep(TCFDB *fdb, int64_t id, const void *vbuf, int vsiz); + + +/* Store a new record with a decimal key into a fixed-length database object. + `fdb' specifies the fixed-length database object connected as a writer. + `kbuf' specifies the pointer to the region of the decimal key. It should be more than 0. If + it is "min", the minimum ID number of existing records is specified. If it is "prev", the + number less by one than the minimum ID number of existing records is specified. If it is + "max", the maximum ID number of existing records is specified. If it is "next", the number + greater by one than the maximum ID number of existing records is specified. + `ksiz' specifies the size of the region of the key. + `vbuf' specifies the pointer to the region of the value. + `vsiz' specifies the size of the region of the value. If the size of the value is greater + than the width tuning parameter of the database, the size is cut down to the width. + If successful, the return value is true, else, it is false. + If a record with the same key exists in the database, this function has no effect. */ +bool tcfdbputkeep2(TCFDB *fdb, const void *kbuf, int ksiz, const void *vbuf, int vsiz); + + +/* Store a new string record with a decimal key into a fixed-length database object. + `fdb' specifies the fixed-length database object connected as a writer. + `kstr' specifies the string of the decimal key. It should be more than 0. If it is "min", + the minimum ID number of existing records is specified. If it is "prev", the number less by + one than the minimum ID number of existing records is specified. If it is "max", the maximum + ID number of existing records is specified. If it is "next", the number greater by one than + the maximum ID number of existing records is specified. + `vstr' specifies the string of the value. + If successful, the return value is true, else, it is false. + If a record with the same key exists in the database, this function has no effect. */ +bool tcfdbputkeep3(TCFDB *fdb, const char *kstr, const void *vstr); + + +/* Concatenate a value at the end of the existing record in a fixed-length database object. + `fdb' specifies the fixed-length database object connected as a writer. + `id' specifies the ID number. It should be more than 0. If it is `FDBIDMIN', the minimum ID + number of existing records is specified. If it is `FDBIDPREV', the number less by one than + the minimum ID number of existing records is specified. If it is `FDBIDMAX', the maximum ID + number of existing records is specified. If it is `FDBIDNEXT', the number greater by one than + the maximum ID number of existing records is specified. + `vbuf' specifies the pointer to the region of the value. + `vsiz' specifies the size of the region of the value. If the size of the value is greater + than the width tuning parameter of the database, the size is cut down to the width. + If successful, the return value is true, else, it is false. + If there is no corresponding record, a new record is created. */ +bool tcfdbputcat(TCFDB *fdb, int64_t id, const void *vbuf, int vsiz); + + +/* Concatenate a value with a decimal key in a fixed-length database object. + `fdb' specifies the fixed-length database object connected as a writer. + `kbuf' specifies the pointer to the region of the decimal key. It should be more than 0. If + it is "min", the minimum ID number of existing records is specified. If it is "prev", the + number less by one than the minimum ID number of existing records is specified. If it is + "max", the maximum ID number of existing records is specified. If it is "next", the number + greater by one than the maximum ID number of existing records is specified. + `ksiz' specifies the size of the region of the key. + `vbuf' specifies the pointer to the region of the value. + `vsiz' specifies the size of the region of the value. If the size of the value is greater + than the width tuning parameter of the database, the size is cut down to the width. + If successful, the return value is true, else, it is false. + If there is no corresponding record, a new record is created. */ +bool tcfdbputcat2(TCFDB *fdb, const void *kbuf, int ksiz, const void *vbuf, int vsiz); + + +/* Concatenate a string value with a decimal key in a fixed-length database object. + `fdb' specifies the fixed-length database object connected as a writer. + `kstr' specifies the string of the decimal key. It should be more than 0. If it is "min", + the minimum ID number of existing records is specified. If it is "prev", the number less by + one than the minimum ID number of existing records is specified. If it is "max", the maximum + ID number of existing records is specified. If it is "next", the number greater by one than + the maximum ID number of existing records is specified. + `vstr' specifies the string of the value. + If successful, the return value is true, else, it is false. + If there is no corresponding record, a new record is created. */ +bool tcfdbputcat3(TCFDB *fdb, const char *kstr, const void *vstr); + + +/* Remove a record of a fixed-length database object. + `fdb' specifies the fixed-length database object connected as a writer. + `id' specifies the ID number. It should be more than 0. If it is `FDBIDMIN', the minimum ID + number of existing records is specified. If it is `FDBIDMAX', the maximum ID number of + existing records is specified. + If successful, the return value is true, else, it is false. */ +bool tcfdbout(TCFDB *fdb, int64_t id); + + +/* Remove a record with a decimal key of a fixed-length database object. + `fdb' specifies the fixed-length database object connected as a writer. + `kbuf' specifies the pointer to the region of the decimal key. It should be more than 0. If + it is "min", the minimum ID number of existing records is specified. If it is "max", the + maximum ID number of existing records is specified. + `ksiz' specifies the size of the region of the key. + If successful, the return value is true, else, it is false. */ +bool tcfdbout2(TCFDB *fdb, const void *kbuf, int ksiz); + + +/* Remove a string record with a decimal key of a fixed-length database object. + `fdb' specifies the fixed-length database object connected as a writer. + `kstr' specifies the string of the decimal key. It should be more than 0. If it is "min", + the minimum ID number of existing records is specified. If it is "max", the maximum ID number + of existing records is specified. + If successful, the return value is true, else, it is false. */ +bool tcfdbout3(TCFDB *fdb, const char *kstr); + + +/* Retrieve a record in a fixed-length database object. + `fdb' specifies the fixed-length database object. + `id' specifies the ID number. It should be more than 0. If it is `FDBIDMIN', the minimum ID + number of existing records is specified. If it is `FDBIDMAX', the maximum ID number of + existing records is specified. + `sp' specifies the pointer to the variable into which the size of the region of the return + value is assigned. + If successful, the return value is the pointer to the region of the value of the corresponding + record. `NULL' is returned if no record corresponds. + Because an additional zero code is appended at the end of the region of the return value, + the return value can be treated as a character string. Because the region of the return + value is allocated with the `malloc' call, it should be released with the `free' call when + it is no longer in use. */ +void *tcfdbget(TCFDB *fdb, int64_t id, int *sp); + + +/* Retrieve a record with a decimal key in a fixed-length database object. + `fdb' specifies the fixed-length database object. + `kbuf' specifies the pointer to the region of the decimal key. It should be more than 0. If + it is "min", the minimum ID number of existing records is specified. If it is "max", the + maximum ID number of existing records is specified. + `ksiz' specifies the size of the region of the key. + `sp' specifies the pointer to the variable into which the size of the region of the return + value is assigned. + If successful, the return value is the pointer to the region of the value of the corresponding + record. `NULL' is returned if no record corresponds. + Because an additional zero code is appended at the end of the region of the return value, + the return value can be treated as a character string. Because the region of the return + value is allocated with the `malloc' call, it should be released with the `free' call when + it is no longer in use. */ +void *tcfdbget2(TCFDB *fdb, const void *kbuf, int ksiz, int *sp); + + +/* Retrieve a string record with a decimal key in a fixed-length database object. + `fdb' specifies the fixed-length database object. + `kstr' specifies the string of the decimal key. It should be more than 0. If it is "min", + the minimum ID number of existing records is specified. If it is "max", the maximum ID number + of existing records is specified. + If successful, the return value is the string of the value of the corresponding record. + `NULL' is returned if no record corresponds. + Because an additional zero code is appended at the end of the region of the return value, + the return value can be treated as a character string. Because the region of the return + value is allocated with the `malloc' call, it should be released with the `free' call when + it is no longer in use. */ +char *tcfdbget3(TCFDB *fdb, const char *kstr); + + +/* Retrieve a record in a fixed-length database object and write the value into a buffer. + `fdb' specifies the fixed-length database object. + `id' specifies the ID number. It should be more than 0. If it is `FDBIDMIN', the minimum ID + number of existing records is specified. If it is `FDBIDMAX', the maximum ID number of + existing records is specified. + `vbuf' specifies the pointer to the buffer into which the value of the corresponding record is + written. + `max' specifies the size of the buffer. + If successful, the return value is the size of the written data, else, it is -1. -1 is + returned if no record corresponds to the specified key. + Note that an additional zero code is not appended at the end of the region of the writing + buffer. */ +int tcfdbget4(TCFDB *fdb, int64_t id, void *vbuf, int max); + + +/* Get the size of the value of a record in a fixed-length database object. + `fdb' specifies the fixed-length database object. + `id' specifies the ID number. It should be more than 0. If it is `FDBIDMIN', the minimum ID + number of existing records is specified. If it is `FDBIDMAX', the maximum ID number of + existing records is specified. + If successful, the return value is the size of the value of the corresponding record, else, + it is -1. */ +int tcfdbvsiz(TCFDB *fdb, int64_t id); + + +/* Get the size of the value with a decimal key in a fixed-length database object. + `fdb' specifies the fixed-length database object. + `kbuf' specifies the pointer to the region of the decimal key. It should be more than 0. If + it is "min", the minimum ID number of existing records is specified. If it is "max", the + maximum ID number of existing records is specified. + `ksiz' specifies the size of the region of the key. + If successful, the return value is the size of the value of the corresponding record, else, + it is -1. */ +int tcfdbvsiz2(TCFDB *fdb, const void *kbuf, int ksiz); + + +/* Get the size of the string value with a decimal key in a fixed-length database object. + `fdb' specifies the fixed-length database object. + `kstr' specifies the string of the decimal key. It should be more than 0. If it is "min", + the minimum ID number of existing records is specified. If it is "max", the maximum ID number + of existing records is specified. + If successful, the return value is the size of the value of the corresponding record, else, + it is -1. */ +int tcfdbvsiz3(TCFDB *fdb, const char *kstr); + + +/* Initialize the iterator of a fixed-length database object. + `fdb' specifies the fixed-length database object. + If successful, the return value is true, else, it is false. + The iterator is used in order to access the key of every record stored in a database. */ +bool tcfdbiterinit(TCFDB *fdb); + + +/* Get the next ID number of the iterator of a fixed-length database object. + `fdb' specifies the fixed-length database object. + If successful, the return value is the next ID number of the iterator, else, it is 0. 0 is + returned when no record is to be get out of the iterator. + It is possible to access every record by iteration of calling this function. It is allowed to + update or remove records whose keys are fetched while the iteration. The order of this + traversal access method is ascending of the ID number. */ +uint64_t tcfdbiternext(TCFDB *fdb); + + +/* Get the next decimay key of the iterator of a fixed-length database object. + `fdb' specifies the fixed-length database object. + `sp' specifies the pointer to the variable into which the size of the region of the return + value is assigned. + If successful, the return value is the pointer to the region of the next decimal key, else, it + is `NULL'. `NULL' is returned when no record is to be get out of the iterator. + Because an additional zero code is appended at the end of the region of the return value, the + return value can be treated as a character string. Because the region of the return value is + allocated with the `malloc' call, it should be released with the `free' call when it is no + longer in use. It is possible to access every record by iteration of calling this function. + It is allowed to update or remove records whose keys are fetched while the iteration. The + order of this traversal access method is ascending of the ID number. */ +void *tcfdbiternext2(TCFDB *fdb, int *sp); + + +/* Get the next decimay key string of the iterator of a fixed-length database object. + `fdb' specifies the fixed-length database object. + If successful, the return value is the string of the next decimal key, else, it is `NULL'. + `NULL' is returned when no record is to be get out of the iterator. + Because the region of the return value is allocated with the `malloc' call, it should be + released with the `free' call when it is no longer in use. It is possible to access every + record by iteration of calling this function. It is allowed to update or remove records whose + keys are fetched while the iteration. The order of this traversal access method is ascending + of the ID number. */ +char *tcfdbiternext3(TCFDB *fdb); + + +/* Get range matching ID numbers in a fixed-length database object. + `fdb' specifies the fixed-length database object. + `lower' specifies the lower limit of the range. If it is `FDBIDMIN', the minimum ID is + specified. + `upper' specifies the upper limit of the range. If it is `FDBIDMAX', the maximum ID is + specified. + `max' specifies the maximum number of keys to be fetched. If it is negative, no limit is + specified. + `np' specifies the pointer to the variable into which the number of elements of the return + value is assigned. + If successful, the return value is the pointer to an array of ID numbers of the corresponding + records. `NULL' is returned on failure. This function does never fail. It returns an empty + array even if no key corresponds. + Because the region of the return value is allocated with the `malloc' call, it should be + released with the `free' call when it is no longer in use. */ +uint64_t *tcfdbrange(TCFDB *fdb, int64_t lower, int64_t upper, int max, int *np); + + +/* Get range matching decimal keys in a fixed-length database object. + `fdb' specifies the fixed-length database object. + `lbuf' specifies the pointer to the region of the lower key. If it is "min", the minimum ID + number of existing records is specified. + `lsiz' specifies the size of the region of the lower key. + `ubuf' specifies the pointer to the region of the upper key. If it is "max", the maximum ID + number of existing records is specified. + `usiz' specifies the size of the region of the upper key. + `max' specifies the maximum number of keys to be fetched. If it is negative, no limit is + specified. + The return value is a list object of the corresponding decimal keys. This function does never + fail. It returns an empty list even if no key corresponds. + Because the object of the return value is created with the function `tclistnew', it should be + deleted with the function `tclistdel' when it is no longer in use. Note that this function + may be very slow because every key in the database is scanned. */ +TCLIST *tcfdbrange2(TCFDB *fdb, const void *lbuf, int lsiz, const void *ubuf, int usiz, int max); + + +/* Get range matching decimal keys with strings in a fixed-length database object. + `fdb' specifies the fixed-length database object. + `lstr' specifies the string of the lower key. If it is "min", the minimum ID number of + existing records is specified. + `ustr' specifies the string of the upper key. If it is "max", the maximum ID number of + existing records is specified. + `max' specifies the maximum number of keys to be fetched. If it is negative, no limit is + specified. + The return value is a list object of the corresponding decimal keys. This function does never + fail. It returns an empty list even if no key corresponds. + Because the object of the return value is created with the function `tclistnew', it should be + deleted with the function `tclistdel' when it is no longer in use. Note that this function + may be very slow because every key in the database is scanned. */ +TCLIST *tcfdbrange3(TCFDB *fdb, const char *lstr, const char *ustr, int max); + + +/* Get keys with an interval notation in a fixed-length database object. + `fdb' specifies the fixed-length database object. + `ibuf' specifies the pointer to the region of the interval notation. + `isiz' specifies the size of the region of the interval notation. + `max' specifies the maximum number of keys to be fetched. If it is negative, no limit is + specified. + The return value is a list object of the corresponding decimal keys. This function does never + fail. It returns an empty list even if no key corresponds. + Because the object of the return value is created with the function `tclistnew', it should be + deleted with the function `tclistdel' when it is no longer in use. Note that this function + may be very slow because every key in the database is scanned. */ +TCLIST *tcfdbrange4(TCFDB *fdb, const void *ibuf, int isiz, int max); + + +/* Get keys with an interval notation string in a fixed-length database object. + `fdb' specifies the fixed-length database object. + `istr' specifies the pointer to the region of the interval notation string. + `max' specifies the maximum number of keys to be fetched. If it is negative, no limit is + specified. + The return value is a list object of the corresponding decimal keys. This function does never + fail. It returns an empty list even if no key corresponds. + Because the object of the return value is created with the function `tclistnew', it should be + deleted with the function `tclistdel' when it is no longer in use. Note that this function + may be very slow because every key in the database is scanned. */ +TCLIST *tcfdbrange5(TCFDB *fdb, const void *istr, int max); + + +/* Add an integer to a record in a fixed-length database object. + `fdb' specifies the fixed-length database object connected as a writer. + `id' specifies the ID number. It should be more than 0. If it is `FDBIDMIN', the minimum ID + number of existing records is specified. If it is `FDBIDPREV', the number less by one than + the minimum ID number of existing records is specified. If it is `FDBIDMAX', the maximum ID + number of existing records is specified. If it is `FDBIDNEXT', the number greater by one than + the maximum ID number of existing records is specified. + `num' specifies the additional value. + If successful, the return value is the summation value, else, it is `INT_MIN'. + If the corresponding record exists, the value is treated as an integer and is added to. If no + record corresponds, a new record of the additional value is stored. */ +int tcfdbaddint(TCFDB *fdb, int64_t id, int num); + + +/* Add a real number to a record in a fixed-length database object. + `fdb' specifies the fixed-length database object connected as a writer. + `id' specifies the ID number. It should be more than 0. If it is `FDBIDMIN', the minimum ID + number of existing records is specified. If it is `FDBIDPREV', the number less by one than + the minimum ID number of existing records is specified. If it is `FDBIDMAX', the maximum ID + number of existing records is specified. If it is `FDBIDNEXT', the number greater by one than + the maximum ID number of existing records is specified. + `num' specifies the additional value. + If successful, the return value is the summation value, else, it is Not-a-Number. + If the corresponding record exists, the value is treated as a real number and is added to. If + no record corresponds, a new record of the additional value is stored. */ +double tcfdbadddouble(TCFDB *fdb, int64_t id, double num); + + +/* Synchronize updated contents of a fixed-length database object with the file and the device. + `fdb' specifies the fixed-length database object connected as a writer. + If successful, the return value is true, else, it is false. + This function is useful when another process connects to the same database file. */ +bool tcfdbsync(TCFDB *fdb); + + +/* Optimize the file of a fixed-length database object. + `fdb' specifies the fixed-length database object connected as a writer. + `width' specifies the width of the value of each record. If it is not more than 0, the current + setting is not changed. + `limsiz' specifies the limit size of the database file. If it is not more than 0, the current + setting is not changed. + If successful, the return value is true, else, it is false. */ +bool tcfdboptimize(TCFDB *fdb, int32_t width, int64_t limsiz); + + +/* Remove all records of a fixed-length database object. + `fdb' specifies the fixed-length database object connected as a writer. + If successful, the return value is true, else, it is false. */ +bool tcfdbvanish(TCFDB *fdb); + + +/* Copy the database file of a fixed-length database object. + `fdb' specifies the fixed-length database object. + `path' specifies the path of the destination file. If it begins with `@', the trailing + substring is executed as a command line. + If successful, the return value is true, else, it is false. False is returned if the executed + command returns non-zero code. + The database file is assured to be kept synchronized and not modified while the copying or + executing operation is in progress. So, this function is useful to create a backup file of + the database file. */ +bool tcfdbcopy(TCFDB *fdb, const char *path); + + +/* Begin the transaction of a fixed-length database object. + `fdb' specifies the fixed-length database object connected as a writer. + If successful, the return value is true, else, it is false. + The database is locked by the thread while the transaction so that only one transaction can be + activated with a database object at the same time. Thus, the serializable isolation level is + assumed if every database operation is performed in the transaction. All updated regions are + kept track of by write ahead logging while the transaction. If the database is closed during + transaction, the transaction is aborted implicitly. */ +bool tcfdbtranbegin(TCFDB *fdb); + + +/* Commit the transaction of a fixed-length database object. + `fdb' specifies the fixed-length database object connected as a writer. + If successful, the return value is true, else, it is false. + Update in the transaction is fixed when it is committed successfully. */ +bool tcfdbtrancommit(TCFDB *fdb); + + +/* Abort the transaction of a fixed-length database object. + `fdb' specifies the fixed-length database object connected as a writer. + If successful, the return value is true, else, it is false. + Update in the transaction is discarded when it is aborted. The state of the database is + rollbacked to before transaction. */ +bool tcfdbtranabort(TCFDB *fdb); + + +/* Get the file path of a fixed-length database object. + `fdb' specifies the fixed-length database object. + The return value is the path of the database file or `NULL' if the object does not connect to + any database file. */ +const char *tcfdbpath(TCFDB *fdb); + + +/* Get the number of records of a fixed-length database object. + `fdb' specifies the fixed-length database object. + The return value is the number of records or 0 if the object does not connect to any database + file. */ +uint64_t tcfdbrnum(TCFDB *fdb); + + +/* Get the size of the database file of a fixed-length database object. + `fdb' specifies the fixed-length database object. + The return value is the size of the database file or 0 if the object does not connect to any + database file. */ +uint64_t tcfdbfsiz(TCFDB *fdb); + + + +/************************************************************************************************* + * features for experts + *************************************************************************************************/ + + +/* Set the error code of a fixed-length database object. + `fdb' specifies the fixed-length database object. + `ecode' specifies the error code. + `file' specifies the file name of the code. + `line' specifies the line number of the code. + `func' specifies the function name of the code. */ +void tcfdbsetecode(TCFDB *fdb, int ecode, const char *filename, int line, const char *func); + + +/* Set the file descriptor for debugging output. + `fdb' specifies the fixed-length database object. + `fd' specifies the file descriptor for debugging output. */ +void tcfdbsetdbgfd(TCFDB *fdb, int fd); + + +/* Get the file descriptor for debugging output. + `fdb' specifies the fixed-length database object. + The return value is the file descriptor for debugging output. */ +int tcfdbdbgfd(TCFDB *fdb); + + +/* Check whether mutual exclusion control is set to a fixed-length database object. + `fdb' specifies the fixed-length database object. + If mutual exclusion control is set, it is true, else it is false. */ +bool tcfdbhasmutex(TCFDB *fdb); + + +/* Synchronize updating contents on memory of a fixed-length database object. + `fdb' specifies the fixed-length database object connected as a writer. + `phys' specifies whether to synchronize physically. + If successful, the return value is true, else, it is false. */ +bool tcfdbmemsync(TCFDB *fdb, bool phys); + + +/* Get the minimum ID number of records of a fixed-length database object. + `fdb' specifies the fixed-length database object. + The return value is the minimum ID number of records or 0 if the object does not connect to + any database file. */ +uint64_t tcfdbmin(TCFDB *fdb); + + +/* Get the maximum ID number of records of a fixed-length database object. + `fdb' specifies the fixed-length database object. + The return value is the maximum ID number of records or 0 if the object does not connect to + any database file. */ +uint64_t tcfdbmax(TCFDB *fdb); + + +/* Get the width of the value of each record of a fixed-length database object. + `fdb' specifies the fixed-length database object. + The return value is the width of the value of each record or 0 if the object does not connect + to any database file. */ +uint32_t tcfdbwidth(TCFDB *fdb); + + +/* Get the limit file size of a fixed-length database object. + `fdb' specifies the fixed-length database object. + The return value is the limit file size or 0 if the object does not connect to any database + file. */ +uint64_t tcfdblimsiz(TCFDB *fdb); + + +/* Get the limit ID number of a fixed-length database object. + `fdb' specifies the fixed-length database object. + The return value is the limit ID number or 0 if the object does not connect to any database + file. */ +uint64_t tcfdblimid(TCFDB *fdb); + + +/* Get the inode number of the database file of a fixed-length database object. + `fdb' specifies the fixed-length database object. + The return value is the inode number of the database file or 0 if the object does not connect + to any database file. */ +uint64_t tcfdbinode(TCFDB *fdb); + + +/* Get the modification time of the database file of a fixed-length database object. + `fdb' specifies the fixed-length database object. + The return value is the inode number of the database file or 0 if the object does not connect + to any database file. */ +time_t tcfdbmtime(TCFDB *fdb); + + +/* Get the connection mode of a fixed-length database object. + `fdb' specifies the fixed-length database object. + The return value is the connection mode. */ +int tcfdbomode(TCFDB *fdb); + + +/* Get the database type of a fixed-length database object. + `fdb' specifies the fixed-length database object. + The return value is the database type. */ +uint8_t tcfdbtype(TCFDB *fdb); + + +/* Get the additional flags of a fixed-length database object. + `fdb' specifies the fixed-length database object. + The return value is the additional flags. */ +uint8_t tcfdbflags(TCFDB *fdb); + + +/* Get the pointer to the opaque field of a fixed-length database object. + `fdb' specifies the fixed-length database object. + The return value is the pointer to the opaque field whose size is 128 bytes. */ +char *tcfdbopaque(TCFDB *fdb); + + +/* Store a record into a fixed-length database object with a duplication handler. + `fdb' specifies the fixed-length database object connected as a writer. + `id' specifies the ID number. It should be more than 0. If it is `FDBIDMIN', the minimum ID + number of existing records is specified. If it is `FDBIDPREV', the number less by one than + the minimum ID number of existing records is specified. If it is `FDBIDMAX', the maximum ID + number of existing records is specified. If it is `FDBIDNEXT', the number greater by one than + the maximum ID number of existing records is specified. + `vbuf' specifies the pointer to the region of the value. `NULL' means that record addition is + ommited if there is no corresponding record. + `vsiz' specifies the size of the region of the value. If the size of the value is greater + than the width tuning parameter of the database, the size is cut down to the width. + `proc' specifies the pointer to the callback function to process duplication. It receives + four parameters. The first parameter is the pointer to the region of the value. The second + parameter is the size of the region of the value. The third parameter is the pointer to the + variable into which the size of the region of the return value is assigned. The fourth + parameter is the pointer to the optional opaque object. It returns the pointer to the result + object allocated with `malloc'. It is released by the caller. If it is `NULL', the record is + not modified. If it is `(void *)-1', the record is removed. + `op' specifies an arbitrary pointer to be given as a parameter of the callback function. If + it is not needed, `NULL' can be specified. + If successful, the return value is true, else, it is false. + Note that the callback function can not perform any database operation because the function + is called in the critical section guarded by the same locks of database operations. */ +bool tcfdbputproc(TCFDB *fdb, int64_t id, const void *vbuf, int vsiz, TCPDPROC proc, void *op); + + +/* Move the iterator to the record corresponding a key of a fixed-length database object. + `fdb' specifies the fixed-length database object. + `id' specifies the ID number. It should be more than 0. If it is `FDBIDMIN', the minimum ID + number of existing records is specified. If it is `FDBIDMAX', the maximum ID number of + existing records is specified. + If successful, the return value is true, else, it is false. False is returned if there is + no record corresponding the condition. */ +bool tcfdbiterinit2(TCFDB *fdb, int64_t id); + + +/* Move the iterator to the decimal record of a fixed-length database object. + `fdb' specifies the fixed-length database object. + `kbuf' specifies the pointer to the region of the decimal key. It should be more than 0. If + it is "min", the minimum ID number of existing records is specified. If it is "max", the + maximum ID number of existing records is specified. + `ksiz' specifies the size of the region of the key. + If successful, the return value is true, else, it is false. False is returned if there is + no record corresponding the condition. */ +bool tcfdbiterinit3(TCFDB *fdb, const void *kbuf, int ksiz); + + +/* Move the iterator to the decimal string record of a fixed-length database object. + `fdb' specifies the fixed-length database object. + `kstr' specifies the string of the decimal key. It should be more than 0. If it is "min", + the minimum ID number of existing records is specified. If it is "max", the maximum ID number + of existing records is specified. + If successful, the return value is true, else, it is false. False is returned if there is + no record corresponding the condition. */ +bool tcfdbiterinit4(TCFDB *fdb, const char *kstr); + + +/* Process each record atomically of a fixed-length database object. + `fdb' specifies the fixed-length database object. + `iter' specifies the pointer to the iterator function called for each record. It receives + five parameters. The first parameter is the pointer to the region of the key. The second + parameter is the size of the region of the key. The third parameter is the pointer to the + region of the value. The fourth parameter is the size of the region of the value. The fifth + parameter is the pointer to the optional opaque object. It returns true to continue iteration + or false to stop iteration. + `op' specifies an arbitrary pointer to be given as a parameter of the iterator function. If + it is not needed, `NULL' can be specified. + If successful, the return value is true, else, it is false. + Note that the callback function can not perform any database operation because the function + is called in the critical section guarded by the same locks of database operations. */ +bool tcfdbforeach(TCFDB *fdb, TCITER iter, void *op); + + +/* Generate the ID number from arbitrary binary data. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + The return value is the ID number. */ +int64_t tcfdbkeytoid(const char *kbuf, int ksiz); + + + +__TCFDB_CLINKAGEEND +#endif /* duplication check */ + + +/* END OF FILE */ diff --git a/lib_dict/tc/include/tchdb.h b/lib_dict/tc/include/tchdb.h new file mode 100644 index 000000000..3fb775de9 --- /dev/null +++ b/lib_dict/tc/include/tchdb.h @@ -0,0 +1,877 @@ +/************************************************************************************************* + * The hash database API of Tokyo Cabinet + * Copyright (C) 2006-2009 Mikio Hirabayashi + * This file is part of Tokyo Cabinet. + * Tokyo Cabinet is free software; you can redistribute it and/or modify it under the terms of + * the GNU Lesser General Public License as published by the Free Software Foundation; either + * version 2.1 of the License or any later version. Tokyo Cabinet is distributed in the hope + * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * You should have received a copy of the GNU Lesser General Public License along with Tokyo + * Cabinet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA. + *************************************************************************************************/ + + +#ifndef _TCHDB_H /* duplication check */ +#define _TCHDB_H + +#if defined(__cplusplus) +#define __TCHDB_CLINKAGEBEGIN extern "C" { +#define __TCHDB_CLINKAGEEND } +#else +#define __TCHDB_CLINKAGEBEGIN +#define __TCHDB_CLINKAGEEND +#endif +__TCHDB_CLINKAGEBEGIN + + +#include +#include +#include +#include +#include +#include +#include + + + +/************************************************************************************************* + * API + *************************************************************************************************/ + + +typedef struct { /* type of structure for a hash database */ + void *mmtx; /* mutex for method */ + void *rmtxs; /* mutexes for records */ + void *dmtx; /* mutex for the while database */ + void *tmtx; /* mutex for transaction */ + void *wmtx; /* mutex for write ahead logging */ + void *eckey; /* key for thread specific error code */ + char *rpath; /* real path for locking */ + uint8_t type; /* database type */ + uint8_t flags; /* additional flags */ + uint64_t bnum; /* number of the bucket array */ + uint8_t apow; /* power of record alignment */ + uint8_t fpow; /* power of free block pool number */ + uint8_t opts; /* options */ + char *path; /* path of the database file */ + int fd; /* file descriptor of the database file */ + uint32_t omode; /* open mode */ + uint64_t rnum; /* number of the records */ + uint64_t fsiz; /* size of the database file */ + uint64_t frec; /* offset of the first record */ + uint64_t dfcur; /* offset of the cursor for defragmentation */ + uint64_t iter; /* offset of the iterator */ + char *map; /* pointer to the mapped memory */ + uint64_t msiz; /* size of the mapped memory */ + uint64_t xmsiz; /* size of the extra mapped memory */ + uint64_t xfsiz; /* extra size of the file for mapped memory */ + uint32_t *ba32; /* 32-bit bucket array */ + uint64_t *ba64; /* 64-bit bucket array */ + uint32_t align; /* record alignment */ + uint32_t runit; /* record reading unit */ + bool zmode; /* whether compression is used */ + int32_t fbpmax; /* maximum number of the free block pool */ + void *fbpool; /* free block pool */ + int32_t fbpnum; /* number of the free block pool */ + int32_t fbpmis; /* number of missing retrieval of the free block pool */ + bool async; /* whether asynchronous storing is called */ + TCXSTR *drpool; /* delayed record pool */ + TCXSTR *drpdef; /* deferred records of the delayed record pool */ + uint64_t drpoff; /* offset of the delayed record pool */ + TCMDB *recc; /* cache for records */ + uint32_t rcnum; /* maximum number of cached records */ + TCCODEC enc; /* pointer to the encoding function */ + void *encop; /* opaque object for the encoding functions */ + TCCODEC dec; /* pointer to the decoding function */ + void *decop; /* opaque object for the decoding functions */ + int ecode; /* last happened error code */ + bool fatal; /* whether a fatal error occured */ + uint64_t inode; /* inode number */ + time_t mtime; /* modification time */ + uint32_t dfunit; /* unit step number of auto defragmentation */ + uint32_t dfcnt; /* counter of auto defragmentation */ + bool tran; /* whether in the transaction */ + int walfd; /* file descriptor of write ahead logging */ + uint64_t walend; /* end offset of write ahead logging */ + int dbgfd; /* file descriptor for debugging */ + int64_t cnt_writerec; /* tesing counter for record write times */ + int64_t cnt_reuserec; /* tesing counter for record reuse times */ + int64_t cnt_moverec; /* tesing counter for record move times */ + int64_t cnt_readrec; /* tesing counter for record read times */ + int64_t cnt_searchfbp; /* tesing counter for FBP search times */ + int64_t cnt_insertfbp; /* tesing counter for FBP insert times */ + int64_t cnt_splicefbp; /* tesing counter for FBP splice times */ + int64_t cnt_dividefbp; /* tesing counter for FBP divide times */ + int64_t cnt_mergefbp; /* tesing counter for FBP merge times */ + int64_t cnt_reducefbp; /* tesing counter for FBP reduce times */ + int64_t cnt_appenddrp; /* tesing counter for DRP append times */ + int64_t cnt_deferdrp; /* tesing counter for DRP defer times */ + int64_t cnt_flushdrp; /* tesing counter for DRP flush times */ + int64_t cnt_adjrecc; /* tesing counter for record cache adjust times */ + int64_t cnt_defrag; /* tesing counter for defragmentation times */ + int64_t cnt_shiftrec; /* tesing counter for record shift times */ + int64_t cnt_trunc; /* tesing counter for truncation times */ +} TCHDB; + +enum { /* enumeration for additional flags */ + HDBFOPEN = 1 << 0, /* whether opened */ + HDBFFATAL = 1 << 1 /* whetehr with fatal error */ +}; + +enum { /* enumeration for tuning options */ + HDBTLARGE = 1 << 0, /* use 64-bit bucket array */ + HDBTDEFLATE = 1 << 1, /* compress each record with Deflate */ + HDBTBZIP = 1 << 2, /* compress each record with BZIP2 */ + HDBTTCBS = 1 << 3, /* compress each record with TCBS */ + HDBTEXCODEC = 1 << 4 /* compress each record with custom functions */ +}; + +enum { /* enumeration for open modes */ + HDBOREADER = 1 << 0, /* open as a reader */ + HDBOWRITER = 1 << 1, /* open as a writer */ + HDBOCREAT = 1 << 2, /* writer creating */ + HDBOTRUNC = 1 << 3, /* writer truncating */ + HDBONOLCK = 1 << 4, /* open without locking */ + HDBOLCKNB = 1 << 5, /* lock without blocking */ + HDBOTSYNC = 1 << 6 /* synchronize every transaction */ +}; + + +/* Get the message string corresponding to an error code. + `ecode' specifies the error code. + The return value is the message string of the error code. */ +const char *tchdberrmsg(int ecode); + + +/* Create a hash database object. + The return value is the new hash database object. */ +TCHDB *tchdbnew(void); + + +/* Delete a hash database object. + `hdb' specifies the hash database object. + If the database is not closed, it is closed implicitly. Note that the deleted object and its + derivatives can not be used anymore. */ +void tchdbdel(TCHDB *hdb); + + +/* Get the last happened error code of a hash database object. + `hdb' specifies the hash database object. + The return value is the last happened error code. + The following error codes are defined: `TCESUCCESS' for success, `TCETHREAD' for threading + error, `TCEINVALID' for invalid operation, `TCENOFILE' for file not found, `TCENOPERM' for no + permission, `TCEMETA' for invalid meta data, `TCERHEAD' for invalid record header, `TCEOPEN' + for open error, `TCECLOSE' for close error, `TCETRUNC' for trunc error, `TCESYNC' for sync + error, `TCESTAT' for stat error, `TCESEEK' for seek error, `TCEREAD' for read error, + `TCEWRITE' for write error, `TCEMMAP' for mmap error, `TCELOCK' for lock error, `TCEUNLINK' + for unlink error, `TCERENAME' for rename error, `TCEMKDIR' for mkdir error, `TCERMDIR' for + rmdir error, `TCEKEEP' for existing record, `TCENOREC' for no record found, and `TCEMISC' for + miscellaneous error. */ +int tchdbecode(TCHDB *hdb); + + +/* Set mutual exclusion control of a hash database object for threading. + `hdb' specifies the hash database object which is not opened. + If successful, the return value is true, else, it is false. + Note that the mutual exclusion control is needed if the object is shared by plural threads and + this function should should be called before the database is opened. */ +bool tchdbsetmutex(TCHDB *hdb); + + +/* Set the tuning parameters of a hash database object. + `hdb' specifies the hash database object which is not opened. + `bnum' specifies the number of elements of the bucket array. If it is not more than 0, the + default value is specified. The default value is 131071. Suggested size of the bucket array + is about from 0.5 to 4 times of the number of all records to be stored. + `apow' specifies the size of record alignment by power of 2. If it is negative, the default + value is specified. The default value is 4 standing for 2^4=16. + `fpow' specifies the maximum number of elements of the free block pool by power of 2. If it + is negative, the default value is specified. The default value is 10 standing for 2^10=1024. + `opts' specifies options by bitwise-or: `HDBTLARGE' specifies that the size of the database + can be larger than 2GB by using 64-bit bucket array, `HDBTDEFLATE' specifies that each record + is compressed with Deflate encoding, `HDBTBZIP' specifies that each record is compressed with + BZIP2 encoding, `HDBTTCBS' specifies that each record is compressed with TCBS encoding. + If successful, the return value is true, else, it is false. + Note that the tuning parameters should be set before the database is opened. */ +bool tchdbtune(TCHDB *hdb, int64_t bnum, int8_t apow, int8_t fpow, uint8_t opts); + + +/* Set the caching parameters of a hash database object. + `hdb' specifies the hash database object which is not opened. + `rcnum' specifies the maximum number of records to be cached. If it is not more than 0, the + record cache is disabled. It is disabled by default. + If successful, the return value is true, else, it is false. + Note that the caching parameters should be set before the database is opened. */ +bool tchdbsetcache(TCHDB *hdb, int32_t rcnum); + + +/* Set the size of the extra mapped memory of a hash database object. + `hdb' specifies the hash database object which is not opened. + `xmsiz' specifies the size of the extra mapped memory. If it is not more than 0, the extra + mapped memory is disabled. The default size is 67108864. + If successful, the return value is true, else, it is false. + Note that the mapping parameters should be set before the database is opened. */ +bool tchdbsetxmsiz(TCHDB *hdb, int64_t xmsiz); + + +/* Set the unit step number of auto defragmentation of a hash database object. + `hdb' specifies the hash database object which is not opened. + `dfunit' specifie the unit step number. If it is not more than 0, the auto defragmentation + is disabled. It is disabled by default. + If successful, the return value is true, else, it is false. + Note that the defragmentation parameters should be set before the database is opened. */ +bool tchdbsetdfunit(TCHDB *hdb, int32_t dfunit); + + +/* Open a database file and connect a hash database object. + `hdb' specifies the hash database object which is not opened. + `path' specifies the path of the database file. + `omode' specifies the connection mode: `HDBOWRITER' as a writer, `HDBOREADER' as a reader. + If the mode is `HDBOWRITER', the following may be added by bitwise-or: `HDBOCREAT', which + means it creates a new database if not exist, `HDBOTRUNC', which means it creates a new + database regardless if one exists, `HDBOTSYNC', which means every transaction synchronizes + updated contents with the device. Both of `HDBOREADER' and `HDBOWRITER' can be added to by + bitwise-or: `HDBONOLCK', which means it opens the database file without file locking, or + `HDBOLCKNB', which means locking is performed without blocking. + If successful, the return value is true, else, it is false. */ +bool tchdbopen(TCHDB *hdb, const char *path, int omode); + + +/* Close a hash database object. + `hdb' specifies the hash database object. + If successful, the return value is true, else, it is false. + Update of a database is assured to be written when the database is closed. If a writer opens + a database but does not close it appropriately, the database will be broken. */ +bool tchdbclose(TCHDB *hdb); + + +/* Store a record into a hash database object. + `hdb' specifies the hash database object connected as a writer. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `vbuf' specifies the pointer to the region of the value. + `vsiz' specifies the size of the region of the value. + If successful, the return value is true, else, it is false. + If a record with the same key exists in the database, it is overwritten. */ +bool tchdbput(TCHDB *hdb, const void *kbuf, int ksiz, const void *vbuf, int vsiz); + + +/* Store a string record into a hash database object. + `hdb' specifies the hash database object connected as a writer. + `kstr' specifies the string of the key. + `vstr' specifies the string of the value. + If successful, the return value is true, else, it is false. + If a record with the same key exists in the database, it is overwritten. */ +bool tchdbput2(TCHDB *hdb, const char *kstr, const char *vstr); + + +/* Store a new record into a hash database object. + `hdb' specifies the hash database object connected as a writer. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `vbuf' specifies the pointer to the region of the value. + `vsiz' specifies the size of the region of the value. + If successful, the return value is true, else, it is false. + If a record with the same key exists in the database, this function has no effect. */ +bool tchdbputkeep(TCHDB *hdb, const void *kbuf, int ksiz, const void *vbuf, int vsiz); + + +/* Store a new string record into a hash database object. + `hdb' specifies the hash database object connected as a writer. + `kstr' specifies the string of the key. + `vstr' specifies the string of the value. + If successful, the return value is true, else, it is false. + If a record with the same key exists in the database, this function has no effect. */ +bool tchdbputkeep2(TCHDB *hdb, const char *kstr, const char *vstr); + + +/* Concatenate a value at the end of the existing record in a hash database object. + `hdb' specifies the hash database object connected as a writer. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `vbuf' specifies the pointer to the region of the value. + `vsiz' specifies the size of the region of the value. + If successful, the return value is true, else, it is false. + If there is no corresponding record, a new record is created. */ +bool tchdbputcat(TCHDB *hdb, const void *kbuf, int ksiz, const void *vbuf, int vsiz); + + +/* Concatenate a string value at the end of the existing record in a hash database object. + `hdb' specifies the hash database object connected as a writer. + `kstr' specifies the string of the key. + `vstr' specifies the string of the value. + If successful, the return value is true, else, it is false. + If there is no corresponding record, a new record is created. */ +bool tchdbputcat2(TCHDB *hdb, const char *kstr, const char *vstr); + + +/* Store a record into a hash database object in asynchronous fashion. + `hdb' specifies the hash database object connected as a writer. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `vbuf' specifies the pointer to the region of the value. + `vsiz' specifies the size of the region of the value. + If successful, the return value is true, else, it is false. + If a record with the same key exists in the database, it is overwritten. Records passed to + this function are accumulated into the inner buffer and wrote into the file at a blast. */ +bool tchdbputasync(TCHDB *hdb, const void *kbuf, int ksiz, const void *vbuf, int vsiz); + + +/* Store a string record into a hash database object in asynchronous fashion. + `hdb' specifies the hash database object connected as a writer. + `kstr' specifies the string of the key. + `vstr' specifies the string of the value. + If successful, the return value is true, else, it is false. + If a record with the same key exists in the database, it is overwritten. Records passed to + this function are accumulated into the inner buffer and wrote into the file at a blast. */ +bool tchdbputasync2(TCHDB *hdb, const char *kstr, const char *vstr); + + +/* Remove a record of a hash database object. + `hdb' specifies the hash database object connected as a writer. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + If successful, the return value is true, else, it is false. */ +bool tchdbout(TCHDB *hdb, const void *kbuf, int ksiz); + + +/* Remove a string record of a hash database object. + `hdb' specifies the hash database object connected as a writer. + `kstr' specifies the string of the key. + If successful, the return value is true, else, it is false. */ +bool tchdbout2(TCHDB *hdb, const char *kstr); + + +/* Retrieve a record in a hash database object. + `hdb' specifies the hash database object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `sp' specifies the pointer to the variable into which the size of the region of the return + value is assigned. + If successful, the return value is the pointer to the region of the value of the corresponding + record. `NULL' is returned if no record corresponds. + Because an additional zero code is appended at the end of the region of the return value, + the return value can be treated as a character string. Because the region of the return + value is allocated with the `malloc' call, it should be released with the `free' call when + it is no longer in use. */ +void *tchdbget(TCHDB *hdb, const void *kbuf, int ksiz, int *sp); + + +/* Retrieve a string record in a hash database object. + `hdb' specifies the hash database object. + `kstr' specifies the string of the key. + If successful, the return value is the string of the value of the corresponding record. + `NULL' is returned if no record corresponds. + Because the region of the return value is allocated with the `malloc' call, it should be + released with the `free' call when it is no longer in use. */ +char *tchdbget2(TCHDB *hdb, const char *kstr); + + +/* Retrieve a record in a hash database object and write the value into a buffer. + `hdb' specifies the hash database object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `vbuf' specifies the pointer to the buffer into which the value of the corresponding record is + written. + `max' specifies the size of the buffer. + If successful, the return value is the size of the written data, else, it is -1. -1 is + returned if no record corresponds to the specified key. + Note that an additional zero code is not appended at the end of the region of the writing + buffer. */ +int tchdbget3(TCHDB *hdb, const void *kbuf, int ksiz, void *vbuf, int max); + + +/* Get the size of the value of a record in a hash database object. + `hdb' specifies the hash database object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + If successful, the return value is the size of the value of the corresponding record, else, + it is -1. */ +int tchdbvsiz(TCHDB *hdb, const void *kbuf, int ksiz); + + +/* Get the size of the value of a string record in a hash database object. + `hdb' specifies the hash database object. + `kstr' specifies the string of the key. + If successful, the return value is the size of the value of the corresponding record, else, + it is -1. */ +int tchdbvsiz2(TCHDB *hdb, const char *kstr); + + +/* Initialize the iterator of a hash database object. + `hdb' specifies the hash database object. + If successful, the return value is true, else, it is false. + The iterator is used in order to access the key of every record stored in a database. */ +bool tchdbiterinit(TCHDB *hdb); + + +/* Get the next key of the iterator of a hash database object. + `hdb' specifies the hash database object. + `sp' specifies the pointer to the variable into which the size of the region of the return + value is assigned. + If successful, the return value is the pointer to the region of the next key, else, it is + `NULL'. `NULL' is returned when no record is to be get out of the iterator. + Because an additional zero code is appended at the end of the region of the return value, the + return value can be treated as a character string. Because the region of the return value is + allocated with the `malloc' call, it should be released with the `free' call when it is no + longer in use. It is possible to access every record by iteration of calling this function. + It is allowed to update or remove records whose keys are fetched while the iteration. + However, it is not assured if updating the database is occurred while the iteration. Besides, + the order of this traversal access method is arbitrary, so it is not assured that the order of + storing matches the one of the traversal access. */ +void *tchdbiternext(TCHDB *hdb, int *sp); + + +/* Get the next key string of the iterator of a hash database object. + `hdb' specifies the hash database object. + If successful, the return value is the string of the next key, else, it is `NULL'. `NULL' is + returned when no record is to be get out of the iterator. + Because the region of the return value is allocated with the `malloc' call, it should be + released with the `free' call when it is no longer in use. It is possible to access every + record by iteration of calling this function. However, it is not assured if updating the + database is occurred while the iteration. Besides, the order of this traversal access method + is arbitrary, so it is not assured that the order of storing matches the one of the traversal + access. */ +char *tchdbiternext2(TCHDB *hdb); + + +/* Get the next extensible objects of the iterator of a hash database object. + `hdb' specifies the hash database object. + `kxstr' specifies the object into which the next key is wrote down. + `vxstr' specifies the object into which the next value is wrote down. + If successful, the return value is true, else, it is false. False is returned when no record + is to be get out of the iterator. */ +bool tchdbiternext3(TCHDB *hdb, TCXSTR *kxstr, TCXSTR *vxstr); + + +/* Get forward matching keys in a hash database object. + `hdb' specifies the hash database object. + `pbuf' specifies the pointer to the region of the prefix. + `psiz' specifies the size of the region of the prefix. + `max' specifies the maximum number of keys to be fetched. If it is negative, no limit is + specified. + The return value is a list object of the corresponding keys. This function does never fail. + It returns an empty list even if no key corresponds. + Because the object of the return value is created with the function `tclistnew', it should be + deleted with the function `tclistdel' when it is no longer in use. Note that this function + may be very slow because every key in the database is scanned. */ +TCLIST *tchdbfwmkeys(TCHDB *hdb, const void *pbuf, int psiz, int max); + + +/* Get forward matching string keys in a hash database object. + `hdb' specifies the hash database object. + `pstr' specifies the string of the prefix. + `max' specifies the maximum number of keys to be fetched. If it is negative, no limit is + specified. + The return value is a list object of the corresponding keys. This function does never fail. + It returns an empty list even if no key corresponds. + Because the object of the return value is created with the function `tclistnew', it should be + deleted with the function `tclistdel' when it is no longer in use. Note that this function + may be very slow because every key in the database is scanned. */ +TCLIST *tchdbfwmkeys2(TCHDB *hdb, const char *pstr, int max); + + +/* Add an integer to a record in a hash database object. + `hdb' specifies the hash database object connected as a writer. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `num' specifies the additional value. + If successful, the return value is the summation value, else, it is `INT_MIN'. + If the corresponding record exists, the value is treated as an integer and is added to. If no + record corresponds, a new record of the additional value is stored. */ +int tchdbaddint(TCHDB *hdb, const void *kbuf, int ksiz, int num); + + +/* Add a real number to a record in a hash database object. + `hdb' specifies the hash database object connected as a writer. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `num' specifies the additional value. + If successful, the return value is the summation value, else, it is Not-a-Number. + If the corresponding record exists, the value is treated as a real number and is added to. If + no record corresponds, a new record of the additional value is stored. */ +double tchdbadddouble(TCHDB *hdb, const void *kbuf, int ksiz, double num); + + +/* Synchronize updated contents of a hash database object with the file and the device. + `hdb' specifies the hash database object connected as a writer. + If successful, the return value is true, else, it is false. + This function is useful when another process connects to the same database file. */ +bool tchdbsync(TCHDB *hdb); + + +/* Optimize the file of a hash database object. + `hdb' specifies the hash database object connected as a writer. + `bnum' specifies the number of elements of the bucket array. If it is not more than 0, the + default value is specified. The default value is two times of the number of records. + `apow' specifies the size of record alignment by power of 2. If it is negative, the current + setting is not changed. + `fpow' specifies the maximum number of elements of the free block pool by power of 2. If it + is negative, the current setting is not changed. + `opts' specifies options by bitwise-or: `HDBTLARGE' specifies that the size of the database + can be larger than 2GB by using 64-bit bucket array, `HDBTDEFLATE' specifies that each record + is compressed with Deflate encoding, `HDBTBZIP' specifies that each record is compressed with + BZIP2 encoding, `HDBTTCBS' specifies that each record is compressed with TCBS encoding. If it + is `UINT8_MAX', the current setting is not changed. + If successful, the return value is true, else, it is false. + This function is useful to reduce the size of the database file with data fragmentation by + successive updating. */ +bool tchdboptimize(TCHDB *hdb, int64_t bnum, int8_t apow, int8_t fpow, uint8_t opts); + + +/* Remove all records of a hash database object. + `hdb' specifies the hash database object connected as a writer. + If successful, the return value is true, else, it is false. */ +bool tchdbvanish(TCHDB *hdb); + + +/* Copy the database file of a hash database object. + `hdb' specifies the hash database object. + `path' specifies the path of the destination file. If it begins with `@', the trailing + substring is executed as a command line. + If successful, the return value is true, else, it is false. False is returned if the executed + command returns non-zero code. + The database file is assured to be kept synchronized and not modified while the copying or + executing operation is in progress. So, this function is useful to create a backup file of + the database file. */ +bool tchdbcopy(TCHDB *hdb, const char *path); + + +/* Begin the transaction of a hash database object. + `hdb' specifies the hash database object connected as a writer. + If successful, the return value is true, else, it is false. + The database is locked by the thread while the transaction so that only one transaction can be + activated with a database object at the same time. Thus, the serializable isolation level is + assumed if every database operation is performed in the transaction. All updated regions are + kept track of by write ahead logging while the transaction. If the database is closed during + transaction, the transaction is aborted implicitly. */ +bool tchdbtranbegin(TCHDB *hdb); + + +/* Commit the transaction of a hash database object. + `hdb' specifies the hash database object connected as a writer. + If successful, the return value is true, else, it is false. + Update in the transaction is fixed when it is committed successfully. */ +bool tchdbtrancommit(TCHDB *hdb); + + +/* Abort the transaction of a hash database object. + `hdb' specifies the hash database object connected as a writer. + If successful, the return value is true, else, it is false. + Update in the transaction is discarded when it is aborted. The state of the database is + rollbacked to before transaction. */ +bool tchdbtranabort(TCHDB *hdb); + + +/* Get the file path of a hash database object. + `hdb' specifies the hash database object. + The return value is the path of the database file or `NULL' if the object does not connect to + any database file. */ +const char *tchdbpath(TCHDB *hdb); + + +/* Get the number of records of a hash database object. + `hdb' specifies the hash database object. + The return value is the number of records or 0 if the object does not connect to any database + file. */ +uint64_t tchdbrnum(TCHDB *hdb); + + +/* Get the size of the database file of a hash database object. + `hdb' specifies the hash database object. + The return value is the size of the database file or 0 if the object does not connect to any + database file. */ +uint64_t tchdbfsiz(TCHDB *hdb); + + + +/************************************************************************************************* + * features for experts + *************************************************************************************************/ + + +/* Set the error code of a hash database object. + `hdb' specifies the hash database object. + `ecode' specifies the error code. + `file' specifies the file name of the code. + `line' specifies the line number of the code. + `func' specifies the function name of the code. */ +void tchdbsetecode(TCHDB *hdb, int ecode, const char *filename, int line, const char *func); + + +/* Set the type of a hash database object. + `hdb' specifies the hash database object. + `type' specifies the database type. */ +void tchdbsettype(TCHDB *hdb, uint8_t type); + + +/* Set the file descriptor for debugging output. + `hdb' specifies the hash database object. + `fd' specifies the file descriptor for debugging output. */ +void tchdbsetdbgfd(TCHDB *hdb, int fd); + + +/* Get the file descriptor for debugging output. + `hdb' specifies the hash database object. + The return value is the file descriptor for debugging output. */ +int tchdbdbgfd(TCHDB *hdb); + + +/* Check whether mutual exclusion control is set to a hash database object. + `hdb' specifies the hash database object. + If mutual exclusion control is set, it is true, else it is false. */ +bool tchdbhasmutex(TCHDB *hdb); + + +/* Synchronize updating contents on memory of a hash database object. + `hdb' specifies the hash database object connected as a writer. + `phys' specifies whether to synchronize physically. + If successful, the return value is true, else, it is false. */ +bool tchdbmemsync(TCHDB *hdb, bool phys); + + +/* Clear the cache of a hash tree database object. + `hdb' specifies the hash tree database object. + If successful, the return value is true, else, it is false. */ +bool tchdbcacheclear(TCHDB *hdb); + + +/* Get the number of elements of the bucket array of a hash database object. + `hdb' specifies the hash database object. + The return value is the number of elements of the bucket array or 0 if the object does not + connect to any database file. */ +uint64_t tchdbbnum(TCHDB *hdb); + + +/* Get the record alignment of a hash database object. + `hdb' specifies the hash database object. + The return value is the record alignment or 0 if the object does not connect to any database + file. */ +uint32_t tchdbalign(TCHDB *hdb); + + +/* Get the maximum number of the free block pool of a a hash database object. + `hdb' specifies the hash database object. + The return value is the maximum number of the free block pool or 0 if the object does not + connect to any database file. */ +uint32_t tchdbfbpmax(TCHDB *hdb); + + +/* Get the size of the extra mapped memory of a hash database object. + `hdb' specifies the hash database object. + The return value is the size of the extra mapped memory or 0 if the object does not connect to + any database file. */ +uint64_t tchdbxmsiz(TCHDB *hdb); + + +/* Get the inode number of the database file of a hash database object. + `hdb' specifies the hash database object. + The return value is the inode number of the database file or 0 if the object does not connect + to any database file. */ +uint64_t tchdbinode(TCHDB *hdb); + + +/* Get the modification time of the database file of a hash database object. + `hdb' specifies the hash database object. + The return value is the inode number of the database file or 0 if the object does not connect + to any database file. */ +time_t tchdbmtime(TCHDB *hdb); + + +/* Get the connection mode of a hash database object. + `hdb' specifies the hash database object. + The return value is the connection mode. */ +int tchdbomode(TCHDB *hdb); + + +/* Get the database type of a hash database object. + `hdb' specifies the hash database object. + The return value is the database type. */ +uint8_t tchdbtype(TCHDB *hdb); + + +/* Get the additional flags of a hash database object. + `hdb' specifies the hash database object. + The return value is the additional flags. */ +uint8_t tchdbflags(TCHDB *hdb); + + +/* Get the options of a hash database object. + `hdb' specifies the hash database object. + The return value is the options. */ +uint8_t tchdbopts(TCHDB *hdb); + + +/* Get the pointer to the opaque field of a hash database object. + `hdb' specifies the hash database object. + The return value is the pointer to the opaque field whose size is 128 bytes. */ +char *tchdbopaque(TCHDB *hdb); + + +/* Get the number of used elements of the bucket array of a hash database object. + `hdb' specifies the hash database object. + The return value is the number of used elements of the bucket array or 0 if the object does + not connect to any database file. */ +uint64_t tchdbbnumused(TCHDB *hdb); + + +/* Set the custom codec functions of a hash database object. + `hdb' specifies the hash database object. + `enc' specifies the pointer to the custom encoding function. It receives four parameters. + The first parameter is the pointer to the region. The second parameter is the size of the + region. The third parameter is the pointer to the variable into which the size of the region + of the return value is assigned. The fourth parameter is the pointer to the optional opaque + object. It returns the pointer to the result object allocated with `malloc' call if + successful, else, it returns `NULL'. + `encop' specifies an arbitrary pointer to be given as a parameter of the encoding function. + If it is not needed, `NULL' can be specified. + `dec' specifies the pointer to the custom decoding function. + `decop' specifies an arbitrary pointer to be given as a parameter of the decoding function. + If it is not needed, `NULL' can be specified. + If successful, the return value is true, else, it is false. + Note that the custom codec functions should be set before the database is opened and should be + set every time the database is being opened. */ +bool tchdbsetcodecfunc(TCHDB *hdb, TCCODEC enc, void *encop, TCCODEC dec, void *decop); + + +/* Get the custom codec functions of a hash database object. + `hdb' specifies the hash database object. + `ep' specifies the pointer to a variable into which the pointer to the custom encoding + function is assigned + `eop' specifies the pointer to a variable into which the arbitrary pointer to be given to the + encoding function is assigned. + `dp' specifies the pointer to a variable into which the pointer to the custom decoding + function is assigned + `dop' specifies the pointer to a variable into which the arbitrary pointer to be given to the + decoding function is assigned. */ +void tchdbcodecfunc(TCHDB *hdb, TCCODEC *ep, void **eop, TCCODEC *dp, void **dop); + + +/* Get the unit step number of auto defragmentation of a hash database object. + `hdb' specifies the hash database object. + The return value is the unit step number of auto defragmentation. */ +uint32_t tchdbdfunit(TCHDB *hdb); + + +/* Perform dynamic defragmentation of a hash database object. + `hdb' specifies the hash database object connected as a writer. + `step' specifie the number of steps. If it is not more than 0, the whole file is defragmented + gradually without keeping a continuous lock. + If successful, the return value is true, else, it is false. */ +bool tchdbdefrag(TCHDB *hdb, int64_t step); + + +/* Store a record into a hash database object with a duplication handler. + `hdb' specifies the hash database object connected as a writer. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `vbuf' specifies the pointer to the region of the value. `NULL' means that record addition is + ommited if there is no corresponding record. + `vsiz' specifies the size of the region of the value. + `proc' specifies the pointer to the callback function to process duplication. It receives + four parameters. The first parameter is the pointer to the region of the value. The second + parameter is the size of the region of the value. The third parameter is the pointer to the + variable into which the size of the region of the return value is assigned. The fourth + parameter is the pointer to the optional opaque object. It returns the pointer to the result + object allocated with `malloc'. It is released by the caller. If it is `NULL', the record is + not modified. If it is `(void *)-1', the record is removed. + `op' specifies an arbitrary pointer to be given as a parameter of the callback function. If + it is not needed, `NULL' can be specified. + If successful, the return value is true, else, it is false. + Note that the callback function can not perform any database operation because the function + is called in the critical section guarded by the same locks of database operations. */ +bool tchdbputproc(TCHDB *hdb, const void *kbuf, int ksiz, const void *vbuf, int vsiz, + TCPDPROC proc, void *op); + + +/* Retrieve the next record of a record in a hash database object. + `hdb' specifies the hash database object. + `kbuf' specifies the pointer to the region of the key. If it is `NULL', the first record is + retrieved. + `ksiz' specifies the size of the region of the key. + `sp' specifies the pointer to the variable into which the size of the region of the return + value is assigned. + If successful, the return value is the pointer to the region of the key of the next record. + `NULL' is returned if no record corresponds. + Because an additional zero code is appended at the end of the region of the return value, + the return value can be treated as a character string. Because the region of the return + value is allocated with the `malloc' call, it should be released with the `free' call when + it is no longer in use. */ +void *tchdbgetnext(TCHDB *hdb, const void *kbuf, int ksiz, int *sp); + + +/* Retrieve the next string record in a hash database object. + `hdb' specifies the hash database object. + `kstr' specifies the string of the key. If it is `NULL', the first record is retrieved. + If successful, the return value is the string of the key of the next record. `NULL' is + returned if no record corresponds. + Because the region of the return value is allocated with the `malloc' call, it should be + released with the `free' call when it is no longer in use. */ +char *tchdbgetnext2(TCHDB *hdb, const char *kstr); + + +/* Retrieve the key and the value of the next record of a record in a hash database object. + `hdb' specifies the hash database object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `sp' specifies the pointer to the variable into which the size of the region of the return + value is assigned. + `vbp' specifies the pointer to the variable into which the pointer to the value is assigned. + `vsp' specifies the pointer to the variable into which the size of the value is assigned. + If successful, the return value is the pointer to the region of the key of the next + record. + Because the region of the return value is allocated with the `malloc' call, it should be + released with the `free' call when it is no longer in use. The retion pointed to by `vbp' + should not be released. */ +char *tchdbgetnext3(TCHDB *hdb, const char *kbuf, int ksiz, int *sp, const char **vbp, int *vsp); + + +/* Move the iterator to the record corresponding a key of a hash database object. + `hdb' specifies the hash database object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + If successful, the return value is true, else, it is false. False is returned if there is + no record corresponding the condition. */ +bool tchdbiterinit2(TCHDB *hdb, const void *kbuf, int ksiz); + + +/* Move the iterator to the record corresponding a key string of a hash database object. + `hdb' specifies the hash database object. + `kstr' specifies the string of the key. + If successful, the return value is true, else, it is false. False is returned if there is + no record corresponding the condition. */ +bool tchdbiterinit3(TCHDB *hdb, const char *kstr); + + +/* Process each record atomically of a hash database object. + `hdb' specifies the hash database object. + `iter' specifies the pointer to the iterator function called for each record. It receives + five parameters. The first parameter is the pointer to the region of the key. The second + parameter is the size of the region of the key. The third parameter is the pointer to the + region of the value. The fourth parameter is the size of the region of the value. The fifth + parameter is the pointer to the optional opaque object. It returns true to continue iteration + or false to stop iteration. + `op' specifies an arbitrary pointer to be given as a parameter of the iterator function. If + it is not needed, `NULL' can be specified. + If successful, the return value is true, else, it is false. + Note that the callback function can not perform any database operation because the function + is called in the critical section guarded by the same locks of database operations. */ +bool tchdbforeach(TCHDB *hdb, TCITER iter, void *op); + + +/* Void the transaction of a hash database object. + `hdb' specifies the hash database object connected as a writer. + If successful, the return value is true, else, it is false. + This function should be called only when no update in the transaction. */ +bool tchdbtranvoid(TCHDB *hdb); + + + +__TCHDB_CLINKAGEEND +#endif /* duplication check */ + + +/* END OF FILE */ diff --git a/lib_dict/tc/include/tctdb.h b/lib_dict/tc/include/tctdb.h new file mode 100644 index 000000000..b2c2a7247 --- /dev/null +++ b/lib_dict/tc/include/tctdb.h @@ -0,0 +1,1008 @@ +/************************************************************************************************* + * The table database API of Tokyo Cabinet + * Copyright (C) 2006-2009 Mikio Hirabayashi + * This file is part of Tokyo Cabinet. + * Tokyo Cabinet is free software; you can redistribute it and/or modify it under the terms of + * the GNU Lesser General Public License as published by the Free Software Foundation; either + * version 2.1 of the License or any later version. Tokyo Cabinet is distributed in the hope + * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * You should have received a copy of the GNU Lesser General Public License along with Tokyo + * Cabinet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA. + *************************************************************************************************/ + + +#ifndef _TCTDB_H /* duplication check */ +#define _TCTDB_H + +#if defined(__cplusplus) +#define __TCTDB_CLINKAGEBEGIN extern "C" { +#define __TCTDB_CLINKAGEEND } +#else +#define __TCTDB_CLINKAGEBEGIN +#define __TCTDB_CLINKAGEEND +#endif +__TCTDB_CLINKAGEBEGIN + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + +/************************************************************************************************* + * API + *************************************************************************************************/ + + +typedef struct { /* type of structure for a column index */ + char *name; /* column name */ + int type; /* data type */ + void *db; /* internal database object */ + void *cc; /* internal cache object */ +} TDBIDX; + +typedef struct { /* type of structure for a table database */ + void *mmtx; /* mutex for method */ + TCHDB *hdb; /* internal database object */ + bool open; /* whether the internal database is opened */ + bool wmode; /* whether to be writable */ + uint8_t opts; /* options */ + int32_t lcnum; /* max number of cached leaves */ + int32_t ncnum; /* max number of cached nodes */ + TDBIDX *idxs; /* column indices */ + int inum; /* number of column indices */ + bool tran; /* whether in the transaction */ +} TCTDB; + +enum { /* enumeration for additional flags */ + TDBFOPEN = HDBFOPEN, /* whether opened */ + TDBFFATAL = HDBFFATAL /* whetehr with fatal error */ +}; + +enum { /* enumeration for tuning options */ + TDBTLARGE = 1 << 0, /* use 64-bit bucket array */ + TDBTDEFLATE = 1 << 1, /* compress each page with Deflate */ + TDBTBZIP = 1 << 2, /* compress each record with BZIP2 */ + TDBTTCBS = 1 << 3, /* compress each page with TCBS */ + TDBTEXCODEC = 1 << 4 /* compress each record with outer functions */ +}; + +enum { /* enumeration for open modes */ + TDBOREADER = 1 << 0, /* open as a reader */ + TDBOWRITER = 1 << 1, /* open as a writer */ + TDBOCREAT = 1 << 2, /* writer creating */ + TDBOTRUNC = 1 << 3, /* writer truncating */ + TDBONOLCK = 1 << 4, /* open without locking */ + TDBOLCKNB = 1 << 5, /* lock without blocking */ + TDBOTSYNC = 1 << 6 /* synchronize every transaction */ +}; + +enum { /* enumeration for index types */ + TDBITLEXICAL, /* lexical string */ + TDBITDECIMAL, /* decimal string */ + TDBITTOKEN, /* token inverted index */ + TDBITQGRAM, /* q-gram inverted index */ + TDBITOPT = 9998, /* optimize */ + TDBITVOID = 9999, /* void */ + TDBITKEEP = 1 << 24 /* keep existing index */ +}; + +typedef struct { /* type of structure for a condition */ + char *name; /* column name */ + int nsiz; /* size of the column name */ + int op; /* operation type */ + bool sign; /* positive sign */ + bool noidx; /* no index flag */ + char *expr; /* operand expression */ + int esiz; /* size of the operand expression */ + void *regex; /* regular expression object */ + void *ftsunits; /* full-text search units */ + int ftsnum; /* number of full-text search units */ + bool alive; /* alive flag */ +} TDBCOND; + +typedef struct { /* type of structure for a query */ + TCTDB *tdb; /* database object */ + TDBCOND *conds; /* condition objects */ + int cnum; /* number of conditions */ + char *oname; /* column name for ordering */ + int otype; /* type of order */ + int max; /* max number of retrieval */ + int skip; /* skipping number of retrieval */ + TCXSTR *hint; /* hint string */ + int count; /* count of corresponding records */ +} TDBQRY; + +enum { /* enumeration for query conditions */ + TDBQCSTREQ, /* string is equal to */ + TDBQCSTRINC, /* string is included in */ + TDBQCSTRBW, /* string begins with */ + TDBQCSTREW, /* string ends with */ + TDBQCSTRAND, /* string includes all tokens in */ + TDBQCSTROR, /* string includes at least one token in */ + TDBQCSTROREQ, /* string is equal to at least one token in */ + TDBQCSTRRX, /* string matches regular expressions of */ + TDBQCNUMEQ, /* number is equal to */ + TDBQCNUMGT, /* number is greater than */ + TDBQCNUMGE, /* number is greater than or equal to */ + TDBQCNUMLT, /* number is less than */ + TDBQCNUMLE, /* number is less than or equal to */ + TDBQCNUMBT, /* number is between two tokens of */ + TDBQCNUMOREQ, /* number is equal to at least one token in */ + TDBQCFTSPH, /* full-text search with the phrase of */ + TDBQCFTSAND, /* full-text search with all tokens in */ + TDBQCFTSOR, /* full-text search with at least one token in */ + TDBQCFTSEX, /* full-text search with the compound expression of */ + TDBQCNEGATE = 1 << 24, /* negation flag */ + TDBQCNOIDX = 1 << 25 /* no index flag */ +}; + +enum { /* enumeration for order types */ + TDBQOSTRASC, /* string ascending */ + TDBQOSTRDESC, /* string descending */ + TDBQONUMASC, /* number ascending */ + TDBQONUMDESC /* number descending */ +}; + +enum { /* enumeration for post treatments */ + TDBQPPUT = 1 << 0, /* modify the record */ + TDBQPOUT = 1 << 1, /* remove the record */ + TDBQPSTOP = 1 << 24 /* stop the iteration */ +}; + +/* type of the pointer to a iterator function for each table record. + `pkbuf' specifies the pointer to the region of the primary key. + `pksiz' specifies the size of the region of the primary key. + `cols' specifies a map object containing columns. + `op' specifies the pointer to the optional opaque object. + The return value is flags of the post treatment by bitwise-or: `TDBQPPUT' to modify the + record, `TDBQPOUT' to remove the record, `TDBQPSTOP' to stop the iteration. */ +typedef int (*TDBQRYPROC)(const void *pkbuf, int pksiz, TCMAP *cols, void *op); + + +/* Get the message string corresponding to an error code. + `ecode' specifies the error code. + The return value is the message string of the error code. */ +const char *tctdberrmsg(int ecode); + + +/* Create a table database object. + The return value is the new table database object. */ +TCTDB *tctdbnew(void); + + +/* Delete a table database object. + `tdb' specifies the table database object. + If the database is not closed, it is closed implicitly. Note that the deleted object and its + derivatives can not be used anymore. */ +void tctdbdel(TCTDB *tdb); + + +/* Get the last happened error code of a table database object. + `tdb' specifies the table database object. + The return value is the last happened error code. + The following error code is defined: `TCESUCCESS' for success, `TCETHREAD' for threading + error, `TCEINVALID' for invalid operation, `TCENOFILE' for file not found, `TCENOPERM' for no + permission, `TCEMETA' for invalid meta data, `TCERHEAD' for invalid record header, `TCEOPEN' + for open error, `TCECLOSE' for close error, `TCETRUNC' for trunc error, `TCESYNC' for sync + error, `TCESTAT' for stat error, `TCESEEK' for seek error, `TCEREAD' for read error, + `TCEWRITE' for write error, `TCEMMAP' for mmap error, `TCELOCK' for lock error, `TCEUNLINK' + for unlink error, `TCERENAME' for rename error, `TCEMKDIR' for mkdir error, `TCERMDIR' for + rmdir error, `TCEKEEP' for existing record, `TCENOREC' for no record found, and `TCEMISC' for + miscellaneous error. */ +int tctdbecode(TCTDB *tdb); + + +/* Set mutual exclusion control of a table database object for threading. + `tdb' specifies the table database object which is not opened. + If successful, the return value is true, else, it is false. + Note that the mutual exclusion control is needed if the object is shared by plural threads and + this function should should be called before the database is opened. */ +bool tctdbsetmutex(TCTDB *tdb); + + +/* Set the tuning parameters of a table database object. + `tdb' specifies the table database object which is not opened. + `bnum' specifies the number of elements of the bucket array. If it is not more than 0, the + default value is specified. The default value is 131071. Suggested size of the bucket array + is about from 0.5 to 4 times of the number of all records to be stored. + `apow' specifies the size of record alignment by power of 2. If it is negative, the default + value is specified. The default value is 4 standing for 2^4=16. + `fpow' specifies the maximum number of elements of the free block pool by power of 2. If it + is negative, the default value is specified. The default value is 10 standing for 2^10=1024. + `opts' specifies options by bitwise-or: `TDBTLARGE' specifies that the size of the database + can be larger than 2GB by using 64-bit bucket array, `TDBTDEFLATE' specifies that each record + is compressed with Deflate encoding, `TDBTBZIP' specifies that each record is compressed with + BZIP2 encoding, `TDBTTCBS' specifies that each record is compressed with TCBS encoding. + If successful, the return value is true, else, it is false. + Note that the tuning parameters should be set before the database is opened. */ +bool tctdbtune(TCTDB *tdb, int64_t bnum, int8_t apow, int8_t fpow, uint8_t opts); + + +/* Set the caching parameters of a table database object. + `tdb' specifies the table database object which is not opened. + `rcnum' specifies the maximum number of records to be cached. If it is not more than 0, the + record cache is disabled. It is disabled by default. + `lcnum' specifies the maximum number of leaf nodes to be cached. If it is not more than 0, + the default value is specified. The default value is 4096. + `ncnum' specifies the maximum number of non-leaf nodes to be cached. If it is not more than 0, + the default value is specified. The default value is 512. + If successful, the return value is true, else, it is false. + Note that the caching parameters should be set before the database is opened. Leaf nodes and + non-leaf nodes are used in column indices. */ +bool tctdbsetcache(TCTDB *tdb, int32_t rcnum, int32_t lcnum, int32_t ncnum); + + +/* Set the size of the extra mapped memory of a table database object. + `tdb' specifies the table database object which is not opened. + `xmsiz' specifies the size of the extra mapped memory. If it is not more than 0, the extra + mapped memory is disabled. The default size is 67108864. + If successful, the return value is true, else, it is false. + Note that the mapping parameters should be set before the database is opened. */ +bool tctdbsetxmsiz(TCTDB *tdb, int64_t xmsiz); + + +/* Set the unit step number of auto defragmentation of a table database object. + `tdb' specifies the table database object which is not opened. + `dfunit' specifie the unit step number. If it is not more than 0, the auto defragmentation + is disabled. It is disabled by default. + If successful, the return value is true, else, it is false. + Note that the defragmentation parameters should be set before the database is opened. */ +bool tctdbsetdfunit(TCTDB *tdb, int32_t dfunit); + + +/* Open a database file and connect a table database object. + `tdb' specifies the table database object which is not opened. + `path' specifies the path of the database file. + `omode' specifies the connection mode: `TDBOWRITER' as a writer, `TDBOREADER' as a reader. + If the mode is `TDBOWRITER', the following may be added by bitwise-or: `TDBOCREAT', which + means it creates a new database if not exist, `TDBOTRUNC', which means it creates a new + database regardless if one exists, `TDBOTSYNC', which means every transaction synchronizes + updated contents with the device. Both of `TDBOREADER' and `TDBOWRITER' can be added to by + bitwise-or: `TDBONOLCK', which means it opens the database file without file locking, or + `TDBOLCKNB', which means locking is performed without blocking. + If successful, the return value is true, else, it is false. */ +bool tctdbopen(TCTDB *tdb, const char *path, int omode); + + +/* Close a table database object. + `tdb' specifies the table database object. + If successful, the return value is true, else, it is false. + Update of a database is assured to be written when the database is closed. If a writer opens + a database but does not close it appropriately, the database will be broken. */ +bool tctdbclose(TCTDB *tdb); + + +/* Store a record into a table database object. + `tdb' specifies the table database object connected as a writer. + `pkbuf' specifies the pointer to the region of the primary key. + `pksiz' specifies the size of the region of the primary key. + `cols' specifies a map object containing columns. + If successful, the return value is true, else, it is false. + If a record with the same key exists in the database, it is overwritten. */ +bool tctdbput(TCTDB *tdb, const void *pkbuf, int pksiz, TCMAP *cols); + + +/* Store a string record into a table database object with a zero separated column string. + `tdb' specifies the table database object connected as a writer. + `pkbuf' specifies the pointer to the region of the primary key. + `pksiz' specifies the size of the region of the primary key. + `cbuf' specifies the pointer to the region of the zero separated column string where the name + and the value of each column are situated one after the other. + `csiz' specifies the size of the region of the column string. + If successful, the return value is true, else, it is false. + If a record with the same key exists in the database, it is overwritten. */ +bool tctdbput2(TCTDB *tdb, const void *pkbuf, int pksiz, const void *cbuf, int csiz); + + +/* Store a string record into a table database object with a tab separated column string. + `tdb' specifies the table database object connected as a writer. + `pkstr' specifies the string of the primary key. + `cstr' specifies the string of the the tab separated column string where the name and the + value of each column are situated one after the other. + If successful, the return value is true, else, it is false. + If a record with the same key exists in the database, it is overwritten. */ +bool tctdbput3(TCTDB *tdb, const char *pkstr, const char *cstr); + + +/* Store a new record into a table database object. + `tdb' specifies the table database object connected as a writer. + `pkbuf' specifies the pointer to the region of the primary key. + `pksiz' specifies the size of the region of the primary key. + `cols' specifies a map object containing columns. + If successful, the return value is true, else, it is false. + If a record with the same key exists in the database, this function has no effect. */ +bool tctdbputkeep(TCTDB *tdb, const void *pkbuf, int pksiz, TCMAP *cols); + + +/* Store a new string record into a table database object with a zero separated column string. + `tdb' specifies the table database object connected as a writer. + `pkbuf' specifies the pointer to the region of the primary key. + `pksiz' specifies the size of the region of the primary key. + `cbuf' specifies the pointer to the region of the zero separated column string where the name + and the value of each column are situated one after the other. + `csiz' specifies the size of the region of the column string. + If successful, the return value is true, else, it is false. + If a record with the same key exists in the database, this function has no effect. */ +bool tctdbputkeep2(TCTDB *tdb, const void *pkbuf, int pksiz, const void *cbuf, int csiz); + + +/* Store a new string record into a table database object with a tab separated column string. + `tdb' specifies the table database object connected as a writer. + `pkstr' specifies the string of the primary key. + `cstr' specifies the string of the the tab separated column string where the name and the + value of each column are situated one after the other. + If successful, the return value is true, else, it is false. + If a record with the same key exists in the database, this function has no effect. */ +bool tctdbputkeep3(TCTDB *tdb, const char *pkstr, const char *cstr); + + +/* Concatenate columns of the existing record in a table database object. + `tdb' specifies the table database object connected as a writer. + `pkbuf' specifies the pointer to the region of the primary key. + `pksiz' specifies the size of the region of the primary key. + `cols' specifies a map object containing columns. + If successful, the return value is true, else, it is false. + If there is no corresponding record, a new record is created. */ +bool tctdbputcat(TCTDB *tdb, const void *pkbuf, int pksiz, TCMAP *cols); + + +/* Concatenate columns in a table database object with a zero separated column string. + `tdb' specifies the table database object connected as a writer. + `pkbuf' specifies the pointer to the region of the primary key. + `pksiz' specifies the size of the region of the primary key. + `cbuf' specifies the pointer to the region of the zero separated column string where the name + and the value of each column are situated one after the other. + `csiz' specifies the size of the region of the column string. + If successful, the return value is true, else, it is false. + If there is no corresponding record, a new record is created. */ +bool tctdbputcat2(TCTDB *tdb, const void *pkbuf, int pksiz, const void *cbuf, int csiz); + + +/* Concatenate columns in a table database object with with a tab separated column string. + `tdb' specifies the table database object connected as a writer. + `pkstr' specifies the string of the primary key. + `cstr' specifies the string of the the tab separated column string where the name and the + value of each column are situated one after the other. + If successful, the return value is true, else, it is false. + If there is no corresponding record, a new record is created. */ +bool tctdbputcat3(TCTDB *tdb, const char *pkstr, const char *cstr); + + +/* Remove a record of a table database object. + `tdb' specifies the table database object connected as a writer. + `pkbuf' specifies the pointer to the region of the primary key. + `pksiz' specifies the size of the region of the primary key. + If successful, the return value is true, else, it is false. */ +bool tctdbout(TCTDB *tdb, const void *pkbuf, int pksiz); + + +/* Remove a string record of a table database object. + `tdb' specifies the table database object connected as a writer. + `pkstr' specifies the string of the primary key. + If successful, the return value is true, else, it is false. */ +bool tctdbout2(TCTDB *tdb, const char *pkstr); + + +/* Retrieve a record in a table database object. + `tdb' specifies the table database object. + `pkbuf' specifies the pointer to the region of the primary key. + `pksiz' specifies the size of the region of the primary key. + If successful, the return value is a map object of the columns of the corresponding record. + `NULL' is returned if no record corresponds. + Because the object of the return value is created with the function `tcmapnew', it should be + deleted with the function `tcmapdel' when it is no longer in use. */ +TCMAP *tctdbget(TCTDB *tdb, const void *pkbuf, int pksiz); + + +/* Retrieve a record in a table database object as a zero separated column string. + `tdb' specifies the table database object. + `pkbuf' specifies the pointer to the region of the primary key. + `pksiz' specifies the size of the region of the primary key. + `sp' specifies the pointer to the variable into which the size of the region of the return + value is assigned. + If successful, the return value is the pointer to the region of the column string of the + corresponding record. `NULL' is returned if no record corresponds. + Because an additional zero code is appended at the end of the region of the return value, + the return value can be treated as a character string. Because the region of the return + value is allocated with the `malloc' call, it should be released with the `free' call when + it is no longer in use. */ +char *tctdbget2(TCTDB *tdb, const void *pkbuf, int pksiz, int *sp); + + +/* Retrieve a string record in a table database object as a tab separated column string. + `tdb' specifies the table database object. + `pkstr' specifies the string of the primary key. + If successful, the return value is the tab separated column string of the corresponding + record. `NULL' is returned if no record corresponds. + Because the region of the return value is allocated with the `malloc' call, it should be + released with the `free' call when it is no longer in use. */ +char *tctdbget3(TCTDB *tdb, const char *pkstr); + + +/* Get the size of the value of a record in a table database object. + `tdb' specifies the table database object. + `kbuf' specifies the pointer to the region of the primary key. + `ksiz' specifies the size of the region of the primary key. + If successful, the return value is the size of the value of the corresponding record, else, + it is -1. */ +int tctdbvsiz(TCTDB *tdb, const void *pkbuf, int pksiz); + + +/* Get the size of the value of a string record in a table database object. + `tdb' specifies the table database object. + `kstr' specifies the string of the primary key. + If successful, the return value is the size of the value of the corresponding record, else, + it is -1. */ +int tctdbvsiz2(TCTDB *tdb, const char *pkstr); + + +/* Initialize the iterator of a table database object. + `tdb' specifies the table database object. + If successful, the return value is true, else, it is false. + The iterator is used in order to access the primary key of every record stored in a + database. */ +bool tctdbiterinit(TCTDB *tdb); + + +/* Get the next primary key of the iterator of a table database object. + `tdb' specifies the table database object. + `sp' specifies the pointer to the variable into which the size of the region of the return + value is assigned. + If successful, the return value is the pointer to the region of the next primary key, else, it + is `NULL'. `NULL' is returned when no record is to be get out of the iterator. + Because an additional zero code is appended at the end of the region of the return value, the + return value can be treated as a character string. Because the region of the return value is + allocated with the `malloc' call, it should be released with the `free' call when it is no + longer in use. It is possible to access every record by iteration of calling this function. + It is allowed to update or remove records whose keys are fetched while the iteration. + However, it is not assured if updating the database is occurred while the iteration. Besides, + the order of this traversal access method is arbitrary, so it is not assured that the order of + storing matches the one of the traversal access. */ +void *tctdbiternext(TCTDB *tdb, int *sp); + + +/* Get the next primary key string of the iterator of a table database object. + `tdb' specifies the table database object. + If successful, the return value is the string of the next primary key, else, it is `NULL'. + `NULL' is returned when no record is to be get out of the iterator. + Because the region of the return value is allocated with the `malloc' call, it should be + released with the `free' call when it is no longer in use. It is possible to access every + record by iteration of calling this function. However, it is not assured if updating the + database is occurred while the iteration. Besides, the order of this traversal access method + is arbitrary, so it is not assured that the order of storing matches the one of the traversal + access. */ +char *tctdbiternext2(TCTDB *tdb); + + +/* Get the columns of the next record of the iterator of a table database object. + `tdb' specifies the table database object. + If successful, the return value is a map object of the columns of the next record, else, it is + `NULL'. `NULL' is returned when no record is to be get out of the iterator. The primary key + is added into the map as a column of an empty string key. + Because the object of the return value is created with the function `tcmapnew', it should be + deleted with the function `tcmapdel' when it is no longer in use. It is possible to access + every record by iteration of calling this function. However, it is not assured if updating + the database is occurred while the iteration. Besides, the order of this traversal access + method is arbitrary, so it is not assured that the order of storing matches the one of the + traversal access. */ +TCMAP *tctdbiternext3(TCTDB *tdb); + + +/* Get forward matching primary keys in a table database object. + `tdb' specifies the table database object. + `pbuf' specifies the pointer to the region of the prefix. + `psiz' specifies the size of the region of the prefix. + `max' specifies the maximum number of keys to be fetched. If it is negative, no limit is + specified. + The return value is a list object of the corresponding keys. This function does never fail. + It returns an empty list even if no key corresponds. + Because the object of the return value is created with the function `tclistnew', it should be + deleted with the function `tclistdel' when it is no longer in use. Note that this function + may be very slow because every key in the database is scanned. */ +TCLIST *tctdbfwmkeys(TCTDB *tdb, const void *pbuf, int psiz, int max); + + +/* Get forward matching string primary keys in a table database object. + `tdb' specifies the table database object. + `pstr' specifies the string of the prefix. + `max' specifies the maximum number of keys to be fetched. If it is negative, no limit is + specified. + The return value is a list object of the corresponding keys. This function does never fail. + It returns an empty list even if no key corresponds. + Because the object of the return value is created with the function `tclistnew', it should be + deleted with the function `tclistdel' when it is no longer in use. Note that this function + may be very slow because every key in the database is scanned. */ +TCLIST *tctdbfwmkeys2(TCTDB *tdb, const char *pstr, int max); + + +/* Add an integer to a column of a record in a table database object. + `tdb' specifies the table database object connected as a writer. + `kbuf' specifies the pointer to the region of the primary key. + `ksiz' specifies the size of the region of the primary key. + `num' specifies the additional value. + If successful, the return value is the summation value, else, it is `INT_MIN'. + The additional value is stored as a decimal string value of a column whose name is "_num". + If no record corresponds, a new record with the additional value is stored. */ +int tctdbaddint(TCTDB *tdb, const void *pkbuf, int pksiz, int num); + + +/* Add a real number to a column of a record in a table database object. + `tdb' specifies the table database object connected as a writer. + `kbuf' specifies the pointer to the region of the primary key. + `ksiz' specifies the size of the region of the primary key. + `num' specifies the additional value. + If successful, the return value is the summation value, else, it is Not-a-Number. + The additional value is stored as a decimal string value of a column whose name is "_num". + If no record corresponds, a new record with the additional value is stored. */ +double tctdbadddouble(TCTDB *tdb, const void *pkbuf, int pksiz, double num); + + +/* Synchronize updated contents of a table database object with the file and the device. + `tdb' specifies the table database object connected as a writer. + If successful, the return value is true, else, it is false. + This function is useful when another process connects to the same database file. */ +bool tctdbsync(TCTDB *tdb); + + +/* Optimize the file of a table database object. + `tdb' specifies the table database object connected as a writer. + `bnum' specifies the number of elements of the bucket array. If it is not more than 0, the + default value is specified. The default value is two times of the number of records. + `apow' specifies the size of record alignment by power of 2. If it is negative, the current + setting is not changed. + `fpow' specifies the maximum number of elements of the free block pool by power of 2. If it + is negative, the current setting is not changed. + `opts' specifies options by bitwise-or: `BDBTLARGE' specifies that the size of the database + can be larger than 2GB by using 64-bit bucket array, `BDBTDEFLATE' specifies that each record + is compressed with Deflate encoding, `BDBTBZIP' specifies that each record is compressed with + BZIP2 encoding, `BDBTTCBS' specifies that each record is compressed with TCBS encoding. If it + is `UINT8_MAX', the current setting is not changed. + If successful, the return value is true, else, it is false. + This function is useful to reduce the size of the database file with data fragmentation by + successive updating. */ +bool tctdboptimize(TCTDB *tdb, int64_t bnum, int8_t apow, int8_t fpow, uint8_t opts); + + +/* Remove all records of a table database object. + `tdb' specifies the table database object connected as a writer. + If successful, the return value is true, else, it is false. */ +bool tctdbvanish(TCTDB *tdb); + + +/* Copy the database file of a table database object. + `tdb' specifies the table database object. + `path' specifies the path of the destination file. If it begins with `@', the trailing + substring is executed as a command line. + If successful, the return value is true, else, it is false. False is returned if the executed + command returns non-zero code. + The database file is assured to be kept synchronized and not modified while the copying or + executing operation is in progress. So, this function is useful to create a backup file of + the database file. */ +bool tctdbcopy(TCTDB *tdb, const char *path); + + +/* Begin the transaction of a table database object. + `tdb' specifies the table database object connected as a writer. + If successful, the return value is true, else, it is false. + The database is locked by the thread while the transaction so that only one transaction can be + activated with a database object at the same time. Thus, the serializable isolation level is + assumed if every database operation is performed in the transaction. Because all pages are + cached on memory while the transaction, the amount of referred records is limited by the + memory capacity. If the database is closed during transaction, the transaction is aborted + implicitly. */ +bool tctdbtranbegin(TCTDB *tdb); + + +/* Commit the transaction of a table database object. + `tdb' specifies the table database object connected as a writer. + If successful, the return value is true, else, it is false. + Update in the transaction is fixed when it is committed successfully. */ +bool tctdbtrancommit(TCTDB *tdb); + + +/* Abort the transaction of a table database object. + `tdb' specifies the table database object connected as a writer. + If successful, the return value is true, else, it is false. + Update in the transaction is discarded when it is aborted. The state of the database is + rollbacked to before transaction. */ +bool tctdbtranabort(TCTDB *tdb); + + +/* Get the file path of a table database object. + `tdb' specifies the table database object. + The return value is the path of the database file or `NULL' if the object does not connect to + any database file. */ +const char *tctdbpath(TCTDB *tdb); + + +/* Get the number of records ccccof a table database object. + `tdb' specifies the table database object. + The return value is the number of records or 0 if the object does not connect to any database + file. */ +uint64_t tctdbrnum(TCTDB *tdb); + + +/* Get the size of the database file of a table database object. + `tdb' specifies the table database object. + The return value is the size of the database file or 0 if the object does not connect to any + database file. */ +uint64_t tctdbfsiz(TCTDB *tdb); + + +/* Set a column index to a table database object. + `tdb' specifies the table database object connected as a writer. + `name' specifies the name of a column. If the name of an existing index is specified, the + index is rebuilt. An empty string means the primary key. + `type' specifies the index type: `TDBITLEXICAL' for lexical string, `TDBITDECIMAL' for decimal + string, `TDBITTOKEN' for token inverted index, `TDBITQGRAM' for q-gram inverted index. If it + is `TDBITOPT', the index is optimized. If it is `TDBITVOID', the index is removed. If + `TDBITKEEP' is added by bitwise-or and the index exists, this function merely returns failure. + If successful, the return value is true, else, it is false. + Note that the setting indices should be set after the database is opened. */ +bool tctdbsetindex(TCTDB *tdb, const char *name, int type); + + +/* Generate a unique ID number of a table database object. + `tdb' specifies the table database object connected as a writer. + The return value is the new unique ID number or -1 on failure. */ +int64_t tctdbgenuid(TCTDB *tdb); + + +/* Create a query object. + `tdb' specifies the table database object. + The return value is the new query object. */ +TDBQRY *tctdbqrynew(TCTDB *tdb); + + +/* Delete a query object. + `qry' specifies the query object. */ +void tctdbqrydel(TDBQRY *qry); + + +/* Add a narrowing condition to a query object. + `qry' specifies the query object. + `name' specifies the name of a column. An empty string means the primary key. + `op' specifies an operation type: `TDBQCSTREQ' for string which is equal to the expression, + `TDBQCSTRINC' for string which is included in the expression, `TDBQCSTRBW' for string which + begins with the expression, `TDBQCSTREW' for string which ends with the expression, + `TDBQCSTRAND' for string which includes all tokens in the expression, `TDBQCSTROR' for string + which includes at least one token in the expression, `TDBQCSTROREQ' for string which is equal + to at least one token in the expression, `TDBQCSTRRX' for string which matches regular + expressions of the expression, `TDBQCNUMEQ' for number which is equal to the expression, + `TDBQCNUMGT' for number which is greater than the expression, `TDBQCNUMGE' for number which is + greater than or equal to the expression, `TDBQCNUMLT' for number which is less than the + expression, `TDBQCNUMLE' for number which is less than or equal to the expression, `TDBQCNUMBT' + for number which is between two tokens of the expression, `TDBQCNUMOREQ' for number which is + equal to at least one token in the expression, `TDBQCFTSPH' for full-text search with the + phrase of the expression, `TDBQCFTSAND' for full-text search with all tokens in the expression, + `TDBQCFTSOR' for full-text search with at least one token in the expression, `TDBQCFTSEX' for + full-text search with the compound expression. All operations can be flagged by bitwise-or: + `TDBQCNEGATE' for negation, `TDBQCNOIDX' for using no index. + `expr' specifies an operand exression. */ +void tctdbqryaddcond(TDBQRY *qry, const char *name, int op, const char *expr); + + +/* Set the order of a query object. + `qry' specifies the query object. + `name' specifies the name of a column. An empty string means the primary key. + `type' specifies the order type: `TDBQOSTRASC' for string ascending, `TDBQOSTRDESC' for + string descending, `TDBQONUMASC' for number ascending, `TDBQONUMDESC' for number descending. */ +void tctdbqrysetorder(TDBQRY *qry, const char *name, int type); + + +/* Set the limit number of records of the result of a query object. + `qry' specifies the query object. + `max' specifies the maximum number of records of the result. If it is negative, no limit is + specified. + `skip' specifies the number of skipped records of the result. If it is not more than 0, no + record is skipped. */ +void tctdbqrysetlimit(TDBQRY *qry, int max, int skip); + + +/* Execute the search of a query object. + `qry' specifies the query object. + The return value is a list object of the primary keys of the corresponding records. This + function does never fail. It returns an empty list even if no record corresponds. + Because the object of the return value is created with the function `tclistnew', it should + be deleted with the function `tclistdel' when it is no longer in use. */ +TCLIST *tctdbqrysearch(TDBQRY *qry); + + +/* Remove each record corresponding to a query object. + `qry' specifies the query object of the database connected as a writer. + If successful, the return value is true, else, it is false. */ +bool tctdbqrysearchout(TDBQRY *qry); + + +/* Process each record corresponding to a query object. + `qry' specifies the query object of the database connected as a writer. + `proc' specifies the pointer to the iterator function called for each record. It receives + four parameters. The first parameter is the pointer to the region of the primary key. The + second parameter is the size of the region of the primary key. The third parameter is a map + object containing columns. The fourth parameter is the pointer to the optional opaque object. + It returns flags of the post treatment by bitwise-or: `TDBQPPUT' to modify the record, + `TDBQPOUT' to remove the record, `TDBQPSTOP' to stop the iteration. + `op' specifies an arbitrary pointer to be given as a parameter of the iterator function. If + it is not needed, `NULL' can be specified. + If successful, the return value is true, else, it is false. */ +bool tctdbqryproc(TDBQRY *qry, TDBQRYPROC proc, void *op); + + +/* Get the hint of a query object. + `qry' specifies the query object. + The return value is the hint string. + This function should be called after the query execution by `tctdbqrysearch' and so on. The + region of the return value is overwritten when this function is called again. */ +const char *tctdbqryhint(TDBQRY *qry); + + + +/************************************************************************************************* + * features for experts + *************************************************************************************************/ + + +/* Set the error code of a table database object. + `tdb' specifies the table database object. + `ecode' specifies the error code. + `file' specifies the file name of the code. + `line' specifies the line number of the code. + `func' specifies the function name of the code. */ +void tctdbsetecode(TCTDB *tdb, int ecode, const char *filename, int line, const char *func); + + +/* Set the file descriptor for debugging output. + `tdb' specifies the table database object. + `fd' specifies the file descriptor for debugging output. */ +void tctdbsetdbgfd(TCTDB *tdb, int fd); + + +/* Get the file descriptor for debugging output. + `tdb' specifies the table database object. + The return value is the file descriptor for debugging output. */ +int tctdbdbgfd(TCTDB *tdb); + + +/* Check whether mutual exclusion control is set to a table database object. + `tdb' specifies the table database object. + If mutual exclusion control is set, it is true, else it is false. */ +bool tctdbhasmutex(TCTDB *tdb); + + +/* Synchronize updating contents on memory of a table database object. + `tdb' specifies the table database object connected as a writer. + `phys' specifies whether to synchronize physically. + If successful, the return value is true, else, it is false. */ +bool tctdbmemsync(TCTDB *tdb, bool phys); + + +/* Get the number of elements of the bucket array of a table database object. + `tdb' specifies the table database object. + The return value is the number of elements of the bucket array or 0 if the object does not + connect to any database file. */ +uint64_t tctdbbnum(TCTDB *tdb); + + +/* Get the record alignment of a table database object. + `tdb' specifies the table database object. + The return value is the record alignment or 0 if the object does not connect to any database + file. */ +uint32_t tctdbalign(TCTDB *tdb); + + +/* Get the maximum number of the free block pool of a table database object. + `tdb' specifies the table database object. + The return value is the maximum number of the free block pool or 0 if the object does not + connect to any database file. */ +uint32_t tctdbfbpmax(TCTDB *tdb); + + +/* Get the inode number of the database file of a table database object. + `tdb' specifies the table database object. + The return value is the inode number of the database file or 0 if the object does not connect + to any database file. */ +uint64_t tctdbinode(TCTDB *tdb); + + +/* Get the modification time of the database file of a table database object. + `tdb' specifies the table database object. + The return value is the inode number of the database file or 0 if the object does not connect + to any database file. */ +time_t tctdbmtime(TCTDB *tdb); + + +/* Get the additional flags of a table database object. + `tdb' specifies the table database object. + The return value is the additional flags. */ +uint8_t tctdbflags(TCTDB *tdb); + + +/* Get the options of a table database object. + `tdb' specifies the table database object. + The return value is the options. */ +uint8_t tctdbopts(TCTDB *tdb); + + +/* Get the pointer to the opaque field of a table database object. + `tdb' specifies the table database object. + The return value is the pointer to the opaque field whose size is 128 bytes. */ +char *tctdbopaque(TCTDB *tdb); + + +/* Get the number of used elements of the bucket array of a table database object. + `tdb' specifies the table database object. + The return value is the number of used elements of the bucket array or 0 if the object does not + connect to any database file. */ +uint64_t tctdbbnumused(TCTDB *tdb); + + +/* Get the number of column indices of a table database object. + `tdb' specifies the table database object. + The return value is the number of column indices or 0 if the object does not connect to any + database file. */ +int tctdbinum(TCTDB *tdb); + + +/* Get the seed of unique ID unumbers of a table database object. + `tdb' specifies the table database object. + The return value is the seed of unique ID numbers or -1 on failure. */ +int64_t tctdbuidseed(TCTDB *tdb); + + +/* Set the seed of unique ID unumbers of a table database object. + `tdb' specifies the table database object connected as a writer. + If successful, the return value is true, else, it is false. */ +bool tctdbsetuidseed(TCTDB *tdb, int64_t seed); + + +/* Set the custom codec functions of a table database object. + `tdb' specifies the table database object. + `enc' specifies the pointer to the custom encoding function. It receives four parameters. + The first parameter is the pointer to the region. The second parameter is the size of the + region. The third parameter is the pointer to the variable into which the size of the region + of the return value is assigned. The fourth parameter is the pointer to the optional opaque + object. It returns the pointer to the result object allocated with `malloc' call if + successful, else, it returns `NULL'. + `encop' specifies an arbitrary pointer to be given as a parameter of the encoding function. + If it is not needed, `NULL' can be specified. + `dec' specifies the pointer to the custom decoding function. + `decop' specifies an arbitrary pointer to be given as a parameter of the decoding function. + If it is not needed, `NULL' can be specified. + If successful, the return value is true, else, it is false. + Note that the custom codec functions should be set before the database is opened and should be + set every time the database is being opened. */ +bool tctdbsetcodecfunc(TCTDB *tdb, TCCODEC enc, void *encop, TCCODEC dec, void *decop); + + +/* Get the unit step number of auto defragmentation of a table database object. + `tdb' specifies the table database object. + The return value is the unit step number of auto defragmentation. */ +uint32_t tctdbdfunit(TCTDB *tdb); + + +/* Perform dynamic defragmentation of a table database object. + `tdb' specifies the table database object connected as a writer. + `step' specifie the number of steps. If it is not more than 0, the whole file is defragmented + gradually without keeping a continuous lock. + If successful, the return value is true, else, it is false. */ +bool tctdbdefrag(TCTDB *tdb, int64_t step); + + +/* Store a record into a table database object with a duplication handler. + `tdb' specifies the table database object connected as a writer. + `pkbuf' specifies the pointer to the region of the primary key. + `pksiz' specifies the size of the region of the primary key. + `cbuf' specifies the pointer to the region of the zero separated column string where the name + and the value of each column are situated one after the other. `NULL' means that record + addition is ommited if there is no corresponding record. + `csiz' specifies the size of the region of the column string. + `proc' specifies the pointer to the callback function to process duplication. It receives + four parameters. The first parameter is the pointer to the region of the value. The second + parameter is the size of the region of the value. The third parameter is the pointer to the + variable into which the size of the region of the return value is assigned. The fourth + parameter is the pointer to the optional opaque object. It returns the pointer to the result + object allocated with `malloc'. It is released by the caller. If it is `NULL', the record is + not modified. If it is `(void *)-1', the record is removed. + `op' specifies an arbitrary pointer to be given as a parameter of the callback function. If + it is not needed, `NULL' can be specified. + If successful, the return value is true, else, it is false. + Note that the callback function can not perform any database operation because the function + is called in the critical section guarded by the same locks of database operations. */ +bool tctdbputproc(TCTDB *tdb, const void *pkbuf, int pksiz, const void *cbuf, int csiz, + TCPDPROC proc, void *op); + + +/* Move the iterator to the record corresponding a key of a table database object. + `tdb' specifies the table database object. + `pkbuf' specifies the pointer to the region of the primary key. + `pksiz' specifies the size of the region of the primary key. + If successful, the return value is true, else, it is false. False is returned if there is + no record corresponding the condition. */ +bool tctdbiterinit2(TCTDB *tdb, const void *pkbuf, int pksiz); + + +/* Move the iterator to the record corresponding a key string of a table database object. + `tdb' specifies the table database object. + `kstr' specifies the string of the primary key. + If successful, the return value is true, else, it is false. False is returned if there is + no record corresponding the condition. */ +bool tctdbiterinit3(TCTDB *tdb, const char *kstr); + + +/* Process each record atomically of a table database object. + `tdb' specifies the table database object. + `iter' specifies the pointer to the iterator function called for each record. It receives + five parameters. The first parameter is the pointer to the region of the key. The second + parameter is the size of the region of the key. The third parameter is the pointer to the + region of the value. The fourth parameter is the size of the region of the value. The fifth + parameter is the pointer to the optional opaque object. It returns true to continue iteration + or false to stop iteration. + `op' specifies an arbitrary pointer to be given as a parameter of the iterator function. If + it is not needed, `NULL' can be specified. + If successful, the return value is true, else, it is false. + Note that the callback function can not perform any database operation because the function + is called in the critical section guarded by the same locks of database operations. */ +bool tctdbforeach(TCTDB *tdb, TCITER iter, void *op); + + +/* Process each record corresponding to a query object with non-atomic fashion. + `qry' specifies the query object of the database connected as a writer. + `proc' specifies the pointer to the iterator function called for each record. It receives + four parameters. The first parameter is the pointer to the region of the primary key. The + second parameter is the size of the region of the primary key. The third parameter is a map + object containing columns. The fourth parameter is the pointer to the optional opaque object. + It returns flags of the post treatment by bitwise-or: `TDBQPPUT' to modify the record, + `TDBQPOUT' to remove the record, `TDBQPSTOP' to stop the iteration. + `op' specifies an arbitrary pointer to be given as a parameter of the iterator function. If + it is not needed, `NULL' can be specified. + If successful, the return value is true, else, it is false. */ +bool tctdbqryproc2(TDBQRY *qry, TDBQRYPROC proc, void *op); + + +/* Remove each record corresponding to a query object with non-atomic fashion. + `qry' specifies the query object of the database connected as a writer. + If successful, the return value is true, else, it is false. */ +bool tctdbqrysearchout2(TDBQRY *qry); + + +/* Convert a string into the index type number. + `str' specifies a string. + The return value is the index type number or -1 on failure. */ +int tctdbstrtoindextype(const char *str); + + +/* Get the count of corresponding records of a query object. + `qry' specifies the query object. + The return value is the count of corresponding records. */ +int tctdbqrycount(TDBQRY *qry); + + +/* Convert a string into the query operation number. + `str' specifies a string. + The return value is the query operation number or -1 on failure. */ +int tctdbqrystrtocondop(const char *str); + + +/* Convert a string into the query order type number. + `str' specifies a string. + The return value is the query order type or -1 on failure. */ +int tctdbqrystrtoordertype(const char *str); + + + +__TCTDB_CLINKAGEEND +#endif /* duplication check */ + + +/* END OF FILE */ diff --git a/lib_dict/tc/include/tcutil.h b/lib_dict/tc/include/tcutil.h new file mode 100644 index 000000000..a33821248 --- /dev/null +++ b/lib_dict/tc/include/tcutil.h @@ -0,0 +1,4081 @@ +/************************************************************************************************* + * The utility API of Tokyo Cabinet + * Copyright (C) 2006-2009 Mikio Hirabayashi + * This file is part of Tokyo Cabinet. + * Tokyo Cabinet is free software; you can redistribute it and/or modify it under the terms of + * the GNU Lesser General Public License as published by the Free Software Foundation; either + * version 2.1 of the License or any later version. Tokyo Cabinet is distributed in the hope + * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * You should have received a copy of the GNU Lesser General Public License along with Tokyo + * Cabinet; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA. + *************************************************************************************************/ + + +#ifndef _TCUTIL_H /* duplication check */ +#define _TCUTIL_H + +#if defined(__cplusplus) +#define __TCUTIL_CLINKAGEBEGIN extern "C" { +#define __TCUTIL_CLINKAGEEND } +#else +#define __TCUTIL_CLINKAGEBEGIN +#define __TCUTIL_CLINKAGEEND +#endif +__TCUTIL_CLINKAGEBEGIN + + +#include +#include +#include +#include +#include +#include + + + +/************************************************************************************************* + * basic utilities + *************************************************************************************************/ + + +/* String containing the version information. */ +extern const char *tcversion; + + +/* Pointer to the call back function for handling a fatal error. + The argument specifies the error message. + The initial value of this variable is `NULL'. If the value is `NULL', the default function is + called when a fatal error occurs. A fatal error occurs when memory allocation is failed. */ +extern void (*tcfatalfunc)(const char *); + + +/* Allocate a region on memory. + `size' specifies the size of the region. + The return value is the pointer to the allocated region. + This function handles failure of memory allocation implicitly. Because the region of the + return value is allocated with the `malloc' call, it should be released with the `free' call + when it is no longer in use. */ +void *tcmalloc(size_t size); + + +/* Allocate a nullified region on memory. + `nmemb' specifies the number of elements. + `size' specifies the size of each element. + The return value is the pointer to the allocated nullified region. + This function handles failure of memory allocation implicitly. Because the region of the + return value is allocated with the `calloc' call, it should be released with the `free' call + when it is no longer in use. */ +void *tccalloc(size_t nmemb, size_t size); + + +/* Re-allocate a region on memory. + `ptr' specifies the pointer to the region. + `size' specifies the size of the region. + The return value is the pointer to the re-allocated region. + This function handles failure of memory allocation implicitly. Because the region of the + return value is allocated with the `realloc' call, it should be released with the `free' call + when it is no longer in use. */ +void *tcrealloc(void *ptr, size_t size); + + +/* Duplicate a region on memory. + `ptr' specifies the pointer to the region. + `size' specifies the size of the region. + The return value is the pointer to the allocated region of the duplicate. + Because an additional zero code is appended at the end of the region of the return value, + the return value can be treated as a character string. Because the region of the return + value is allocated with the `malloc' call, it should be released with the `free' call when + it is no longer in use. */ +void *tcmemdup(const void *ptr, size_t size); + + +/* Duplicate a string on memory. + `str' specifies the string. + The return value is the allocated string equivalent to the specified string. + Because the region of the return value is allocated with the `malloc' call, it should be + released with the `free' call when it is no longer in use. */ +char *tcstrdup(const void *str); + + +/* Free a region on memory. + `ptr' specifies the pointer to the region. If it is `NULL', this function has no effect. + Although this function is just a wrapper of `free' call, this is useful in applications using + another package of the `malloc' series. */ +void tcfree(void *ptr); + + + +/************************************************************************************************* + * basic utilities (for experts) + *************************************************************************************************/ + + +/* type of the pointer to a comparison function. + `aptr' specifies the pointer to the region of one key. + `asiz' specifies the size of the region of one key. + `bptr' specifies the pointer to the region of the other key. + `bsiz' specifies the size of the region of the other key. + `op' specifies the pointer to the optional opaque object. + The return value is positive if the former is big, negative if the latter is big, 0 if both + are equivalent. */ +typedef int (*TCCMP)(const char *aptr, int asiz, const char *bptr, int bsiz, void *op); + +/* type of the pointer to a encoding or decoding function. + `ptr' specifies the pointer to the region. + `size' specifies the size of the region. + `sp' specifies the pointer to the variable into which the size of the region of the return + value is assigned. + `op' specifies the pointer to the optional opaque object. + If successful, the return value is the pointer to the result object allocated with `malloc' + call, else, it is `NULL'. */ +typedef void *(*TCCODEC)(const void *ptr, int size, int *sp, void *op); + +/* type of the pointer to a callback function to process record duplication. + `vbuf' specifies the pointer to the region of the value. + `vsiz' specifies the size of the region of the value. + `sp' specifies the pointer to the variable into which the size of the region of the return + value is assigned. + `op' specifies the pointer to the optional opaque object. + The return value is the pointer to the result object allocated with `malloc'. It is + released by the caller. If it is `NULL', the record is not modified. */ +typedef void *(*TCPDPROC)(const void *vbuf, int vsiz, int *sp, void *op); + +/* type of the pointer to a iterator function. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `vbuf' specifies the pointer to the region of the value. + `vsiz' specifies the size of the region of the value. + `op' specifies the pointer to the optional opaque object. + The return value is true to continue iteration or false to stop iteration. */ +typedef bool (*TCITER)(const void *kbuf, int ksiz, const void *vbuf, int vsiz, void *op); + + + +/************************************************************************************************* + * extensible string + *************************************************************************************************/ + + +typedef struct { /* type of structure for an extensible string object */ + char *ptr; /* pointer to the region */ + int size; /* size of the region */ + int asize; /* size of the allocated region */ +} TCXSTR; + + +/* Create an extensible string object. + The return value is the new extensible string object. */ +TCXSTR *tcxstrnew(void); + + +/* Create an extensible string object from a character string. + `str' specifies the string of the initial content. + The return value is the new extensible string object containing the specified string. */ +TCXSTR *tcxstrnew2(const char *str); + + +/* Create an extensible string object with the initial allocation size. + `asiz' specifies the initial allocation size. + The return value is the new extensible string object. */ +TCXSTR *tcxstrnew3(int asiz); + + +/* Copy an extensible string object. + `xstr' specifies the extensible string object. + The return value is the new extensible string object equivalent to the specified object. */ +TCXSTR *tcxstrdup(const TCXSTR *xstr); + + +/* Delete an extensible string object. + `xstr' specifies the extensible string object. + Note that the deleted object and its derivatives can not be used anymore. */ +void tcxstrdel(TCXSTR *xstr); + + +/* Concatenate a region to the end of an extensible string object. + `xstr' specifies the extensible string object. + `ptr' specifies the pointer to the region to be appended. + `size' specifies the size of the region. */ +void tcxstrcat(TCXSTR *xstr, const void *ptr, int size); + + +/* Concatenate a character string to the end of an extensible string object. + `xstr' specifies the extensible string object. + `str' specifies the string to be appended. */ +void tcxstrcat2(TCXSTR *xstr, const char *str); + + +/* Get the pointer of the region of an extensible string object. + `xstr' specifies the extensible string object. + The return value is the pointer of the region of the object. + Because an additional zero code is appended at the end of the region of the return value, + the return value can be treated as a character string. */ +const void *tcxstrptr(const TCXSTR *xstr); + + +/* Get the size of the region of an extensible string object. + `xstr' specifies the extensible string object. + The return value is the size of the region of the object. */ +int tcxstrsize(const TCXSTR *xstr); + + +/* Clear an extensible string object. + `xstr' specifies the extensible string object. + The internal buffer of the object is cleared and the size is set zero. */ +void tcxstrclear(TCXSTR *xstr); + + +/* Perform formatted output into an extensible string object. + `xstr' specifies the extensible string object. + `format' specifies the printf-like format string. The conversion character `%' can be used + with such flag characters as `s', `d', `o', `u', `x', `X', `c', `e', `E', `f', `g', `G', `@', + `?', `b', and `%'. `@' works as with `s' but escapes meta characters of XML. `?' works as + with `s' but escapes meta characters of URL. `b' converts an integer to the string as binary + numbers. The other conversion character work as with each original. + The other arguments are used according to the format string. */ +void tcxstrprintf(TCXSTR *xstr, const char *format, ...); + + +/* Allocate a formatted string on memory. + `format' specifies the printf-like format string. The conversion character `%' can be used + with such flag characters as `s', `d', `o', `u', `x', `X', `c', `e', `E', `f', `g', `G', `@', + `?', `b', and `%'. `@' works as with `s' but escapes meta characters of XML. `?' works as + with `s' but escapes meta characters of URL. `b' converts an integer to the string as binary + numbers. The other conversion character work as with each original. + The other arguments are used according to the format string. + The return value is the pointer to the region of the result string. + Because the region of the return value is allocated with the `malloc' call, it should be + released with the `free' call when it is no longer in use. */ +char *tcsprintf(const char *format, ...); + + + +/************************************************************************************************* + * extensible string (for experts) + *************************************************************************************************/ + + +/* Convert an extensible string object into a usual allocated region. + `xstr' specifies the extensible string object. + The return value is the pointer to the allocated region of the object. + Because an additional zero code is appended at the end of the region of the return value, + the return value can be treated as a character string. Because the region of the return + value is allocated with the `malloc' call, it should be released with the `free' call when it + is no longer in use. Because the region of the original object is deleted, it should not be + deleted again. */ +void *tcxstrtomalloc(TCXSTR *xstr); + + +/* Create an extensible string object from an allocated region. + `ptr' specifies the pointer to the region allocated with `malloc' call. + `size' specifies the size of the region. + The return value is the new extensible string object wrapping the specified region. + Note that the specified region is released when the object is deleted. */ +TCXSTR *tcxstrfrommalloc(void *ptr, int size); + + + +/************************************************************************************************* + * array list + *************************************************************************************************/ + + +typedef struct { /* type of structure for an element of a list */ + char *ptr; /* pointer to the region */ + int size; /* size of the effective region */ +} TCLISTDATUM; + +typedef struct { /* type of structure for an array list */ + TCLISTDATUM *array; /* array of data */ + int anum; /* number of the elements of the array */ + int start; /* start index of used elements */ + int num; /* number of used elements */ +} TCLIST; + + +/* Create a list object. + The return value is the new list object. */ +TCLIST *tclistnew(void); + + +/* Create a list object with expecting the number of elements. + `anum' specifies the number of elements expected to be stored in the list. + The return value is the new list object. */ +TCLIST *tclistnew2(int anum); + + +/* Create a list object with initial string elements. + `str' specifies the string of the first element. + The other arguments are other elements. They should be trailed by a `NULL' argument. + The return value is the new list object. */ +TCLIST *tclistnew3(const char *str, ...); + + +/* Copy a list object. + `list' specifies the list object. + The return value is the new list object equivalent to the specified object. */ +TCLIST *tclistdup(const TCLIST *list); + + +/* Delete a list object. + `list' specifies the list object. + Note that the deleted object and its derivatives can not be used anymore. */ +void tclistdel(TCLIST *list); + + +/* Get the number of elements of a list object. + `list' specifies the list object. + The return value is the number of elements of the list. */ +int tclistnum(const TCLIST *list); + + +/* Get the pointer to the region of an element of a list object. + `list' specifies the list object. + `index' specifies the index of the element. + `sp' specifies the pointer to the variable into which the size of the region of the return + value is assigned. + The return value is the pointer to the region of the value. + Because an additional zero code is appended at the end of the region of the return value, + the return value can be treated as a character string. If `index' is equal to or more than + the number of elements, the return value is `NULL'. */ +const void *tclistval(const TCLIST *list, int index_, int *sp); + + +/* Get the string of an element of a list object. + `list' specifies the list object. + `index' specifies the index of the element. + The return value is the string of the value. + If `index' is equal to or more than the number of elements, the return value is `NULL'. */ +const char *tclistval2(const TCLIST *list, int index_); + + +/* Add an element at the end of a list object. + `list' specifies the list object. + `ptr' specifies the pointer to the region of the new element. + `size' specifies the size of the region. */ +void tclistpush(TCLIST *list, const void *ptr, int size); + + +/* Add a string element at the end of a list object. + `list' specifies the list object. + `str' specifies the string of the new element. */ +void tclistpush2(TCLIST *list, const char *str); + + +/* Remove an element of the end of a list object. + `list' specifies the list object. + `sp' specifies the pointer to the variable into which the size of the region of the return + value is assigned. + The return value is the pointer to the region of the removed element. + Because an additional zero code is appended at the end of the region of the return value, + the return value can be treated as a character string. Because the region of the return + value is allocated with the `malloc' call, it should be released with the `free' call when it + is no longer in use. If the list is empty, the return value is `NULL'. */ +void *tclistpop(TCLIST *list, int *sp); + + +/* Remove a string element of the end of a list object. + `list' specifies the list object. + The return value is the string of the removed element. + Because the region of the return value is allocated with the `malloc' call, it should be + released with the `free' call when it is no longer in use. If the list is empty, the return + value is `NULL'. */ +char *tclistpop2(TCLIST *list); + + +/* Add an element at the top of a list object. + `list' specifies the list object. + `ptr' specifies the pointer to the region of the new element. + `size' specifies the size of the region. */ +void tclistunshift(TCLIST *list, const void *ptr, int size); + + +/* Add a string element at the top of a list object. + `list' specifies the list object. + `str' specifies the string of the new element. */ +void tclistunshift2(TCLIST *list, const char *str); + + +/* Remove an element of the top of a list object. + `list' specifies the list object. + `sp' specifies the pointer to the variable into which the size of the region of the return + value is assigned. + The return value is the pointer to the region of the removed element. + Because an additional zero code is appended at the end of the region of the return value, + the return value can be treated as a character string. Because the region of the return + value is allocated with the `malloc' call, it should be released with the `free' call when it + is no longer in use. If the list is empty, the return value is `NULL'. */ +void *tclistshift(TCLIST *list, int *sp); + + +/* Remove a string element of the top of a list object. + `list' specifies the list object. + The return value is the string of the removed element. + Because the region of the return value is allocated with the `malloc' call, it should be + released with the `free' call when it is no longer in use. If the list is empty, the return + value is `NULL'. */ +char *tclistshift2(TCLIST *list); + + +/* Add an element at the specified location of a list object. + `list' specifies the list object. + `index' specifies the index of the new element. + `ptr' specifies the pointer to the region of the new element. + `size' specifies the size of the region. + If `index' is equal to or more than the number of elements, this function has no effect. */ +void tclistinsert(TCLIST *list, int index_, const void *ptr, int size); + + +/* Add a string element at the specified location of a list object. + `list' specifies the list object. + `index' specifies the index of the new element. + `str' specifies the string of the new element. + If `index' is equal to or more than the number of elements, this function has no effect. */ +void tclistinsert2(TCLIST *list, int index_, const char *str); + + +/* Remove an element at the specified location of a list object. + `list' specifies the list object. + `index' specifies the index of the element to be removed. + `sp' specifies the pointer to the variable into which the size of the region of the return + value is assigned. + The return value is the pointer to the region of the removed element. + Because an additional zero code is appended at the end of the region of the return value, + the return value can be treated as a character string. Because the region of the return + value is allocated with the `malloc' call, it should be released with the `free' call when it + is no longer in use. If `index' is equal to or more than the number of elements, no element + is removed and the return value is `NULL'. */ +void *tclistremove(TCLIST *list, int index_, int *sp); + + +/* Remove a string element at the specified location of a list object. + `list' specifies the list object. + `index' specifies the index of the element to be removed. + The return value is the string of the removed element. + Because the region of the return value is allocated with the `malloc' call, it should be + released with the `free' call when it is no longer in use. If `index' is equal to or more + than the number of elements, no element is removed and the return value is `NULL'. */ +char *tclistremove2(TCLIST *list, int index_); + + +/* Overwrite an element at the specified location of a list object. + `list' specifies the list object. + `index' specifies the index of the element to be overwritten. + `ptr' specifies the pointer to the region of the new content. + `size' specifies the size of the new content. + If `index' is equal to or more than the number of elements, this function has no effect. */ +void tclistover(TCLIST *list, int index_, const void *ptr, int size); + + +/* Overwrite a string element at the specified location of a list object. + `list' specifies the list object. + `index' specifies the index of the element to be overwritten. + `str' specifies the string of the new content. + If `index' is equal to or more than the number of elements, this function has no effect. */ +void tclistover2(TCLIST *list, int index_, const char *str); + + +/* Sort elements of a list object in lexical order. + `list' specifies the list object. */ +void tclistsort(TCLIST *list); + + +/* Search a list object for an element using liner search. + `list' specifies the list object. + `ptr' specifies the pointer to the region of the key. + `size' specifies the size of the region. + The return value is the index of a corresponding element or -1 if there is no corresponding + element. + If two or more elements correspond, the former returns. */ +int tclistlsearch(const TCLIST *list, const void *ptr, int size); + + +/* Search a list object for an element using binary search. + `list' specifies the list object. It should be sorted in lexical order. + `ptr' specifies the pointer to the region of the key. + `size' specifies the size of the region. + The return value is the index of a corresponding element or -1 if there is no corresponding + element. + If two or more elements correspond, which returns is not defined. */ +int tclistbsearch(const TCLIST *list, const void *ptr, int size); + + +/* Clear a list object. + `list' specifies the list object. + All elements are removed. */ +void tclistclear(TCLIST *list); + + +/* Serialize a list object into a byte array. + `list' specifies the list object. + `sp' specifies the pointer to the variable into which the size of the region of the return + value is assigned. + The return value is the pointer to the region of the result serial region. + Because the region of the return value is allocated with the `malloc' call, it should be + released with the `free' call when it is no longer in use. */ +void *tclistdump(const TCLIST *list, int *sp); + + +/* Create a list object from a serialized byte array. + `ptr' specifies the pointer to the region of serialized byte array. + `size' specifies the size of the region. + The return value is a new list object. + Because the object of the return value is created with the function `tclistnew', it should + be deleted with the function `tclistdel' when it is no longer in use. */ +TCLIST *tclistload(const void *ptr, int size); + + + +/************************************************************************************************* + * array list (for experts) + *************************************************************************************************/ + + +/* Add an allocated element at the end of a list object. + `list' specifies the list object. + `ptr' specifies the pointer to the region allocated with `malloc' call. + `size' specifies the size of the region. + Note that the specified region is released when the object is deleted. */ +void tclistpushmalloc(TCLIST *list, void *ptr, int size); + + +/* Sort elements of a list object in case-insensitive lexical order. + `list' specifies the list object. */ +void tclistsortci(TCLIST *list); + + +/* Sort elements of a list object by an arbitrary comparison function. + `list' specifies the list object. + `cmp' specifies the pointer to the comparison function. The structure TCLISTDATUM has the + member "ptr" which is the pointer to the region of the element, and the member "size" which is + the size of the region. */ +void tclistsortex(TCLIST *list, int (*cmp)(const TCLISTDATUM *, const TCLISTDATUM *)); + + +/* Invert elements of a list object. + `list' specifies the list object. */ +void tclistinvert(TCLIST *list); + + +/* Perform formatted output into a list object. + `list' specifies the list object. + `format' specifies the printf-like format string. The conversion character `%' can be used + with such flag characters as `s', `d', `o', `u', `x', `X', `c', `e', `E', `f', `g', `G', `@', + `?', `b', and `%'. `@' works as with `s' but escapes meta characters of XML. `?' works as + with `s' but escapes meta characters of URL. `b' converts an integer to the string as binary + numbers. The other conversion character work as with each original. + The other arguments are used according to the format string. */ +void tclistprintf(TCLIST *list, const char *format, ...); + + + +/************************************************************************************************* + * hash map + *************************************************************************************************/ + + +typedef struct _TCMAPREC { /* type of structure for an element of a map */ + int32_t ksiz; /* size of the region of the key */ + int32_t vsiz; /* size of the region of the value */ + struct _TCMAPREC *left; /* pointer to the left child */ + struct _TCMAPREC *right; /* pointer to the right child */ + struct _TCMAPREC *prev; /* pointer to the previous element */ + struct _TCMAPREC *next; /* pointer to the next element */ +} TCMAPREC; + +typedef struct { /* type of structure for a map */ + TCMAPREC **buckets; /* bucket array */ + TCMAPREC *first; /* pointer to the first element */ + TCMAPREC *last; /* pointer to the last element */ + TCMAPREC *cur; /* pointer to the current element */ + uint32_t bnum; /* number of buckets */ + uint64_t rnum; /* number of records */ + uint64_t msiz; /* total size of records */ +} TCMAP; + + +/* Create a map object. + The return value is the new map object. */ +TCMAP *tcmapnew(void); + + +/* Create a map object with specifying the number of the buckets. + `bnum' specifies the number of the buckets. + The return value is the new map object. */ +TCMAP *tcmapnew2(uint32_t bnum); + + +/* Create a map object with initial string elements. + `str' specifies the string of the first element. + The other arguments are other elements. They should be trailed by a `NULL' argument. + The return value is the new map object. + The key and the value of each record are situated one after the other. */ +TCMAP *tcmapnew3(const char *str, ...); + + +/* Copy a map object. + `map' specifies the map object. + The return value is the new map object equivalent to the specified object. */ +TCMAP *tcmapdup(const TCMAP *map); + + +/* Delete a map object. + `map' specifies the map object. + Note that the deleted object and its derivatives can not be used anymore. */ +void tcmapdel(TCMAP *map); + + +/* Store a record into a map object. + `map' specifies the map object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `vbuf' specifies the pointer to the region of the value. + `vsiz' specifies the size of the region of the value. + If a record with the same key exists in the map, it is overwritten. */ +void tcmapput(TCMAP *map, const void *kbuf, int ksiz, const void *vbuf, int vsiz); + + +/* Store a string record into a map object. + `map' specifies the map object. + `kstr' specifies the string of the key. + `vstr' specifies the string of the value. + If a record with the same key exists in the map, it is overwritten. */ +void tcmapput2(TCMAP *map, const char *kstr, const char *vstr); + + +/* Store a new record into a map object. + `map' specifies the map object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `vbuf' specifies the pointer to the region of the value. + `vsiz' specifies the size of the region of the value. + If successful, the return value is true, else, it is false. + If a record with the same key exists in the map, this function has no effect. */ +bool tcmapputkeep(TCMAP *map, const void *kbuf, int ksiz, const void *vbuf, int vsiz); + + +/* Store a new string record into a map object. + `map' specifies the map object. + `kstr' specifies the string of the key. + `vstr' specifies the string of the value. + If successful, the return value is true, else, it is false. + If a record with the same key exists in the map, this function has no effect. */ +bool tcmapputkeep2(TCMAP *map, const char *kstr, const char *vstr); + + +/* Concatenate a value at the end of the value of the existing record in a map object. + `map' specifies the map object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `vbuf' specifies the pointer to the region of the value. + `vsiz' specifies the size of the region of the value. + If there is no corresponding record, a new record is created. */ +void tcmapputcat(TCMAP *map, const void *kbuf, int ksiz, const void *vbuf, int vsiz); + + +/* Concatenate a string value at the end of the value of the existing record in a map object. + `map' specifies the map object. + `kstr' specifies the string of the key. + `vstr' specifies the string of the value. + If there is no corresponding record, a new record is created. */ +void tcmapputcat2(TCMAP *map, const char *kstr, const char *vstr); + + +/* Remove a record of a map object. + `map' specifies the map object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + If successful, the return value is true. False is returned when no record corresponds to + the specified key. */ +bool tcmapout(TCMAP *map, const void *kbuf, int ksiz); + + +/* Remove a string record of a map object. + `map' specifies the map object. + `kstr' specifies the string of the key. + If successful, the return value is true. False is returned when no record corresponds to + the specified key. */ +bool tcmapout2(TCMAP *map, const char *kstr); + + +/* Retrieve a record in a map object. + `map' specifies the map object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `sp' specifies the pointer to the variable into which the size of the region of the return + value is assigned. + If successful, the return value is the pointer to the region of the value of the + corresponding record. `NULL' is returned when no record corresponds. + Because an additional zero code is appended at the end of the region of the return value, + the return value can be treated as a character string. */ +const void *tcmapget(const TCMAP *map, const void *kbuf, int ksiz, int *sp); + + +/* Retrieve a string record in a map object. + `map' specifies the map object. + `kstr' specifies the string of the key. + If successful, the return value is the string of the value of the corresponding record. + `NULL' is returned when no record corresponds. */ +const char *tcmapget2(const TCMAP *map, const char *kstr); + + +/* Move a record to the edge of a map object. + `map' specifies the map object. + `kbuf' specifies the pointer to the region of a key. + `ksiz' specifies the size of the region of the key. + `head' specifies the destination which is the head if it is true or the tail if else. + If successful, the return value is true. False is returned when no record corresponds to + the specified key. */ +bool tcmapmove(TCMAP *map, const void *kbuf, int ksiz, bool head); + + +/* Move a string record to the edge of a map object. + `map' specifies the map object. + `kstr' specifies the string of a key. + `head' specifies the destination which is the head if it is true or the tail if else. + If successful, the return value is true. False is returned when no record corresponds to + the specified key. */ +bool tcmapmove2(TCMAP *map, const char *kstr, bool head); + + +/* Initialize the iterator of a map object. + `map' specifies the map object. + The iterator is used in order to access the key of every record stored in the map object. */ +void tcmapiterinit(TCMAP *map); + + +/* Get the next key of the iterator of a map object. + `map' specifies the map object. + `sp' specifies the pointer to the variable into which the size of the region of the return + value is assigned. + If successful, the return value is the pointer to the region of the next key, else, it is + `NULL'. `NULL' is returned when no record can be fetched from the iterator. + Because an additional zero code is appended at the end of the region of the return value, + the return value can be treated as a character string. + The order of iteration is assured to be the same as the stored order. */ +const void *tcmapiternext(TCMAP *map, int *sp); + + +/* Get the next key string of the iterator of a map object. + `map' specifies the map object. + If successful, the return value is the pointer to the region of the next key, else, it is + `NULL'. `NULL' is returned when no record can be fetched from the iterator. + The order of iteration is assured to be the same as the stored order. */ +const char *tcmapiternext2(TCMAP *map); + + +/* Get the number of records stored in a map object. + `map' specifies the map object. + The return value is the number of the records stored in the map object. */ +uint64_t tcmaprnum(const TCMAP *map); + + +/* Get the total size of memory used in a map object. + `map' specifies the map object. + The return value is the total size of memory used in a map object. */ +uint64_t tcmapmsiz(const TCMAP *map); + + +/* Create a list object containing all keys in a map object. + `map' specifies the map object. + The return value is the new list object containing all keys in the map object. + Because the object of the return value is created with the function `tclistnew', it should + be deleted with the function `tclistdel' when it is no longer in use. */ +TCLIST *tcmapkeys(const TCMAP *map); + + +/* Create a list object containing all values in a map object. + `map' specifies the map object. + The return value is the new list object containing all values in the map object. + Because the object of the return value is created with the function `tclistnew', it should + be deleted with the function `tclistdel' when it is no longer in use. */ +TCLIST *tcmapvals(const TCMAP *map); + + +/* Add an integer to a record in a map object. + `map' specifies the map object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `num' specifies the additional value. + The return value is the summation value. + If the corresponding record exists, the value is treated as an integer and is added to. If no + record corresponds, a new record of the additional value is stored. */ +int tcmapaddint(TCMAP *map, const void *kbuf, int ksiz, int num); + + +/* Add a real number to a record in a map object. + `map' specifies the map object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `num' specifies the additional value. + The return value is the summation value. + If the corresponding record exists, the value is treated as a real number and is added to. If + no record corresponds, a new record of the additional value is stored. */ +double tcmapadddouble(TCMAP *map, const void *kbuf, int ksiz, double num); + + +/* Clear a map object. + `map' specifies the map object. + All records are removed. */ +void tcmapclear(TCMAP *map); + + +/* Remove front records of a map object. + `map' specifies the map object. + `num' specifies the number of records to be removed. */ +void tcmapcutfront(TCMAP *map, int num); + + +/* Serialize a map object into a byte array. + `map' specifies the map object. + `sp' specifies the pointer to the variable into which the size of the region of the return + value is assigned. + The return value is the pointer to the region of the result serial region. + Because the region of the return value is allocated with the `malloc' call, it should be + released with the `free' call when it is no longer in use. */ +void *tcmapdump(const TCMAP *map, int *sp); + + +/* Create a map object from a serialized byte array. + `ptr' specifies the pointer to the region of serialized byte array. + `size' specifies the size of the region. + The return value is a new map object. + Because the object of the return value is created with the function `tcmapnew', it should be + deleted with the function `tcmapdel' when it is no longer in use. */ +TCMAP *tcmapload(const void *ptr, int size); + + + +/************************************************************************************************* + * hash map (for experts) + *************************************************************************************************/ + + +/* Store a record and make it semivolatile in a map object. + `map' specifies the map object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `vbuf' specifies the pointer to the region of the value. + `vsiz' specifies the size of the region of the value. + If a record with the same key exists in the map, it is overwritten. The record is moved to + the tail. */ +void tcmapput3(TCMAP *map, const void *kbuf, int ksiz, const char *vbuf, int vsiz); + + +/* Store a record of the value of two regions into a map object. + `map' specifies the map object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `fvbuf' specifies the pointer to the former region of the value. + `fvsiz' specifies the size of the former region of the value. + `lvbuf' specifies the pointer to the latter region of the value. + `lvsiz' specifies the size of the latter region of the value. + If a record with the same key exists in the map, it is overwritten. */ +void tcmapput4(TCMAP *map, const void *kbuf, int ksiz, + const void *fvbuf, int fvsiz, const void *lvbuf, int lvsiz); + + +/* Concatenate a value at the existing record and make it semivolatile in a map object. + `map' specifies the map object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `vbuf' specifies the pointer to the region of the value. + `vsiz' specifies the size of the region of the value. + If there is no corresponding record, a new record is created. */ +void tcmapputcat3(TCMAP *map, const void *kbuf, int ksiz, const void *vbuf, int vsiz); + + +/* Store a record into a map object with a duplication handler. + `map' specifies the map object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `vbuf' specifies the pointer to the region of the value. `NULL' means that record addition is + ommited if there is no corresponding record. + `vsiz' specifies the size of the region of the value. + `proc' specifies the pointer to the callback function to process duplication. It receives + four parameters. The first parameter is the pointer to the region of the value. The second + parameter is the size of the region of the value. The third parameter is the pointer to the + variable into which the size of the region of the return value is assigned. The fourth + parameter is the pointer to the optional opaque object. It returns the pointer to the result + object allocated with `malloc'. It is released by the caller. If it is `NULL', the record is + not modified. If it is `(void *)-1', the record is removed. + `op' specifies an arbitrary pointer to be given as a parameter of the callback function. If + it is not needed, `NULL' can be specified. + If successful, the return value is true, else, it is false. */ +bool tcmapputproc(TCMAP *map, const void *kbuf, int ksiz, const void *vbuf, int vsiz, + TCPDPROC proc, void *op); + + +/* Retrieve a semivolatile record in a map object. + `map' specifies the map object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `sp' specifies the pointer to the variable into which the size of the region of the return + value is assigned. + If successful, the return value is the pointer to the region of the value of the + corresponding record. `NULL' is returned when no record corresponds. + Because an additional zero code is appended at the end of the region of the return value, + the return value can be treated as a character string. The internal region of the returned + record is moved to the tail so that the record will survive for a time under LRU cache + algorithm removing records from the head. */ +const void *tcmapget3(TCMAP *map, const void *kbuf, int ksiz, int *sp); + + +/* Retrieve a string record in a map object with specifying the default value string. + `map' specifies the map object. + `kstr' specifies the string of the key. + `dstr' specifies the string of the default value. + The return value is the string of the value of the corresponding record or the default value + string. */ +const char *tcmapget4(TCMAP *map, const char *kstr, const char *dstr); + + +/* Initialize the iterator of a map object at the record corresponding a key. + `map' specifies the map object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + If there is no record corresponding the condition, the iterator is not modified. */ +void tcmapiterinit2(TCMAP *map, const void *kbuf, int ksiz); + + +/* Initialize the iterator of a map object at the record corresponding a key string. + `map' specifies the map object. + `kstr' specifies the string of the key. + If there is no record corresponding the condition, the iterator is not modified. */ +void tcmapiterinit3(TCMAP *map, const char *kstr); + + +/* Get the value bound to the key fetched from the iterator of a map object. + `kbuf' specifies the pointer to the region of the iteration key. + `sp' specifies the pointer to the variable into which the size of the region of the return + value is assigned. + The return value is the pointer to the region of the value of the corresponding record. + Because an additional zero code is appended at the end of the region of the return value, + the return value can be treated as a character string. */ +const void *tcmapiterval(const void *kbuf, int *sp); + + +/* Get the value string bound to the key fetched from the iterator of a map object. + `kstr' specifies the string of the iteration key. + The return value is the pointer to the region of the value of the corresponding record. */ +const char *tcmapiterval2(const char *kstr); + + +/* Create an array of strings of all keys in a map object. + `map' specifies the map object. + `np' specifies the pointer to a variable into which the number of elements of the return value + is assigned. + The return value is the pointer to the array of all string keys in the map object. + Because the region of the return value is allocated with the `malloc' call, it should be + released with the `free' call if when is no longer in use. Note that elements of the array + point to the inner objects, whose life duration is synchronous with the map object. */ +const char **tcmapkeys2(const TCMAP *map, int *np); + + +/* Create an array of strings of all values in a map object. + `map' specifies the map object. + `np' specifies the pointer to a variable into which the number of elements of the return value + is assigned. + The return value is the pointer to the array of all string values in the map object. + Because the region of the return value is allocated with the `malloc' call, it should be + released with the `free' call if when is no longer in use. Note that elements of the array + point to the inner objects, whose life duration is synchronous with the map object. */ +const char **tcmapvals2(const TCMAP *map, int *np); + + +/* Extract a map record from a serialized byte array. + `ptr' specifies the pointer to the region of serialized byte array. + `size' specifies the size of the region. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `sp' specifies the pointer to the variable into which the size of the region of the return + value is assigned. + If successful, the return value is the pointer to the region of the value of the + corresponding record. `NULL' is returned when no record corresponds. + Because an additional zero code is appended at the end of the region of the return value, + the return value can be treated as a character string. */ +void *tcmaploadone(const void *ptr, int size, const void *kbuf, int ksiz, int *sp); + + +/* Perform formatted output into a map object. + `map' specifies the map object. + `kstr' specifies the string of the key. + `format' specifies the printf-like format string. The conversion character `%' can be used + with such flag characters as `s', `d', `o', `u', `x', `X', `c', `e', `E', `f', `g', `G', `@', + `?', `b', and `%'. `@' works as with `s' but escapes meta characters of XML. `?' works as + with `s' but escapes meta characters of URL. `b' converts an integer to the string as binary + numbers. The other conversion character work as with each original. + The other arguments are used according to the format string. */ +void tcmapprintf(TCMAP *map, const char *kstr, const char *format, ...); + + + +/************************************************************************************************* + * ordered tree + *************************************************************************************************/ + + +typedef struct _TCTREEREC { /* type of structure for an element of a tree */ + int32_t ksiz; /* size of the region of the key */ + int32_t vsiz; /* size of the region of the value */ + struct _TCTREEREC *left; /* pointer to the left child */ + struct _TCTREEREC *right; /* pointer to the right child */ +} TCTREEREC; + +typedef struct { /* type of structure for a tree */ + TCTREEREC *root; /* pointer to the root element */ + TCTREEREC *cur; /* pointer to the current element */ + uint64_t rnum; /* number of records */ + uint64_t msiz; /* total size of records */ + TCCMP cmp; /* pointer to the comparison function */ + void *cmpop; /* opaque object for the comparison function */ +} TCTREE; + + +/* Create a tree object. + The return value is the new tree object. */ +TCTREE *tctreenew(void); + + +/* Create a tree object with specifying the custom comparison function. + `cmp' specifies the pointer to the custom comparison function. It receives five parameters. + The first parameter is the pointer to the region of one key. The second parameter is the size + of the region of one key. The third parameter is the pointer to the region of the other key. + The fourth parameter is the size of the region of the other key. The fifth parameter is the + pointer to the optional opaque object. It returns positive if the former is big, negative if + the latter is big, 0 if both are equivalent. + `cmpop' specifies an arbitrary pointer to be given as a parameter of the comparison function. + If it is not needed, `NULL' can be specified. + The return value is the new tree object. + The default comparison function compares keys of two records by lexical order. The functions + `tccmplexical' (dafault), `tccmpdecimal', `tccmpint32', and `tccmpint64' are built-in. */ +TCTREE *tctreenew2(TCCMP cmp, void *cmpop); + + +/* Copy a tree object. + `tree' specifies the tree object. + The return value is the new tree object equivalent to the specified object. */ +TCTREE *tctreedup(const TCTREE *tree); + + +/* Delete a tree object. + `tree' specifies the tree object. + Note that the deleted object and its derivatives can not be used anymore. */ +void tctreedel(TCTREE *tree); + + +/* Store a record into a tree object. + `tree' specifies the tree object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `vbuf' specifies the pointer to the region of the value. + `vsiz' specifies the size of the region of the value. + If a record with the same key exists in the tree, it is overwritten. */ +void tctreeput(TCTREE *tree, const void *kbuf, int ksiz, const void *vbuf, int vsiz); + + +/* Store a string record into a tree object. + `tree' specifies the tree object. + `kstr' specifies the string of the key. + `vstr' specifies the string of the value. + If a record with the same key exists in the tree, it is overwritten. */ +void tctreeput2(TCTREE *tree, const char *kstr, const char *vstr); + + +/* Store a new record into a tree object. + `tree' specifies the tree object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `vbuf' specifies the pointer to the region of the value. + `vsiz' specifies the size of the region of the value. + If successful, the return value is true, else, it is false. + If a record with the same key exists in the tree, this function has no effect. */ +bool tctreeputkeep(TCTREE *tree, const void *kbuf, int ksiz, const void *vbuf, int vsiz); + + +/* Store a new string record into a tree object. + `tree' specifies the tree object. + `kstr' specifies the string of the key. + `vstr' specifies the string of the value. + If successful, the return value is true, else, it is false. + If a record with the same key exists in the tree, this function has no effect. */ +bool tctreeputkeep2(TCTREE *tree, const char *kstr, const char *vstr); + + +/* Concatenate a value at the end of the value of the existing record in a tree object. + `tree' specifies the tree object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `vbuf' specifies the pointer to the region of the value. + `vsiz' specifies the size of the region of the value. + If there is no corresponding record, a new record is created. */ +void tctreeputcat(TCTREE *tree, const void *kbuf, int ksiz, const void *vbuf, int vsiz); + + +/* Concatenate a string value at the end of the value of the existing record in a tree object. + `tree' specifies the tree object. + `kstr' specifies the string of the key. + `vstr' specifies the string of the value. + If there is no corresponding record, a new record is created. */ +void tctreeputcat2(TCTREE *tree, const char *kstr, const char *vstr); + + +/* Store a record into a tree object with a duplication handler. + `tree' specifies the tree object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `vbuf' specifies the pointer to the region of the value. `NULL' means that record addition is + ommited if there is no corresponding record. + `vsiz' specifies the size of the region of the value. + `proc' specifies the pointer to the callback function to process duplication. It receives + four parameters. The first parameter is the pointer to the region of the value. The second + parameter is the size of the region of the value. The third parameter is the pointer to the + variable into which the size of the region of the return value is assigned. The fourth + parameter is the pointer to the optional opaque object. It returns the pointer to the result + object allocated with `malloc'. It is released by the caller. If it is `NULL', the record is + not modified. If it is `(void *)-1', the record is removed. + `op' specifies an arbitrary pointer to be given as a parameter of the callback function. If + it is not needed, `NULL' can be specified. + If successful, the return value is true, else, it is false. */ +bool tctreeputproc(TCTREE *tree, const void *kbuf, int ksiz, const void *vbuf, int vsiz, + TCPDPROC proc, void *op); + + +/* Remove a record of a tree object. + `tree' specifies the tree object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + If successful, the return value is true. False is returned when no record corresponds to + the specified key. */ +bool tctreeout(TCTREE *tree, const void *kbuf, int ksiz); + + +/* Remove a string record of a tree object. + `tree' specifies the tree object. + `kstr' specifies the string of the key. + If successful, the return value is true. False is returned when no record corresponds to + the specified key. */ +bool tctreeout2(TCTREE *tree, const char *kstr); + + +/* Retrieve a record in a tree object. + `tree' specifies the tree object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `sp' specifies the pointer to the variable into which the size of the region of the return + value is assigned. + If successful, the return value is the pointer to the region of the value of the + corresponding record. `NULL' is returned when no record corresponds. + Because an additional zero code is appended at the end of the region of the return value, + the return value can be treated as a character string. */ +const void *tctreeget(TCTREE *tree, const void *kbuf, int ksiz, int *sp); + + +/* Retrieve a string record in a tree object. + `tree' specifies the tree object. + `kstr' specifies the string of the key. + If successful, the return value is the string of the value of the corresponding record. + `NULL' is returned when no record corresponds. */ +const char *tctreeget2(TCTREE *tree, const char *kstr); + + +/* Initialize the iterator of a tree object. + `tree' specifies the tree object. + The iterator is used in order to access the key of every record stored in the tree object. */ +void tctreeiterinit(TCTREE *tree); + + +/* Get the next key of the iterator of a tree object. + `tree' specifies the tree object. + `sp' specifies the pointer to the variable into which the size of the region of the return + value is assigned. + If successful, the return value is the pointer to the region of the next key, else, it is + `NULL'. `NULL' is returned when no record can be fetched from the iterator. + Because an additional zero code is appended at the end of the region of the return value, + the return value can be treated as a character string. + The order of iteration is assured to be ascending of the keys. */ +const void *tctreeiternext(TCTREE *tree, int *sp); + + +/* Get the next key string of the iterator of a tree object. + `tree' specifies the tree object. + If successful, the return value is the pointer to the region of the next key, else, it is + `NULL'. `NULL' is returned when no record can be fetched from the iterator. + The order of iteration is assured to be ascending of the keys. */ +const char *tctreeiternext2(TCTREE *tree); + + +/* Get the number of records stored in a tree object. + `tree' specifies the tree object. + The return value is the number of the records stored in the tree object. */ +uint64_t tctreernum(const TCTREE *tree); + + +/* Get the total size of memory used in a tree object. + `tree' specifies the tree object. + The return value is the total size of memory used in a tree object. */ +uint64_t tctreemsiz(const TCTREE *tree); + + +/* Create a list object containing all keys in a tree object. + `tree' specifies the tree object. + The return value is the new list object containing all keys in the tree object. + Because the object of the return value is created with the function `tclistnew', it should + be deleted with the function `tclistdel' when it is no longer in use. */ +TCLIST *tctreekeys(const TCTREE *tree); + + +/* Create a list object containing all values in a tree object. + `tree' specifies the tree object. + The return value is the new list object containing all values in the tree object. + Because the object of the return value is created with the function `tclistnew', it should + be deleted with the function `tclistdel' when it is no longer in use. */ +TCLIST *tctreevals(const TCTREE *tree); + + +/* Add an integer to a record in a tree object. + `tree' specifies the tree object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `num' specifies the additional value. + The return value is the summation value. + If the corresponding record exists, the value is treated as an integer and is added to. If no + record corresponds, a new record of the additional value is stored. */ +int tctreeaddint(TCTREE *tree, const void *kbuf, int ksiz, int num); + + +/* Add a real number to a record in a tree object. + `tree' specifies the tree object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `num' specifies the additional value. + The return value is the summation value. + If the corresponding record exists, the value is treated as a real number and is added to. If + no record corresponds, a new record of the additional value is stored. */ +double tctreeadddouble(TCTREE *tree, const void *kbuf, int ksiz, double num); + + +/* Clear a tree object. + `tree' specifies the tree object. + All records are removed. */ +void tctreeclear(TCTREE *tree); + + +/* Remove fringe records of a tree object. + `tree' specifies the tree object. + `num' specifies the number of records to be removed. */ +void tctreecutfringe(TCTREE *tree, int num); + + +/* Serialize a tree object into a byte array. + `tree' specifies the tree object. + `sp' specifies the pointer to the variable into which the size of the region of the return + value is assigned. + The return value is the pointer to the region of the result serial region. + Because the region of the return value is allocated with the `malloc' call, it should be + released with the `free' call when it is no longer in use. */ +void *tctreedump(const TCTREE *tree, int *sp); + + +/* Create a tree object from a serialized byte array. + `ptr' specifies the pointer to the region of serialized byte array. + `size' specifies the size of the region. + `cmp' specifies the pointer to the custom comparison function. + `cmpop' specifies an arbitrary pointer to be given as a parameter of the comparison function. + If it is not needed, `NULL' can be specified. + The return value is a new tree object. + Because the object of the return value is created with the function `tctreenew', it should be + deleted with the function `tctreedel' when it is no longer in use. */ +TCTREE *tctreeload(const void *ptr, int size, TCCMP cmp, void *cmpop); + + + +/************************************************************************************************* + * ordered tree (for experts) + *************************************************************************************************/ + + +/* Store a record into a tree object without balancing nodes. + `tree' specifies the tree object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `vbuf' specifies the pointer to the region of the value. + `vsiz' specifies the size of the region of the value. + If a record with the same key exists in the tree, it is overwritten. The structure of the + tree is not modifed by this function. */ +void tctreeput3(TCTREE *tree, const void *kbuf, int ksiz, const void *vbuf, int vsiz); + + +/* Store a new record into a tree object without balancing nodes. + `tree' specifies the tree object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `vbuf' specifies the pointer to the region of the value. + `vsiz' specifies the size of the region of the value. + If successful, the return value is true, else, it is false. + If a record with the same key exists in the tree, this function has no effect. The structure + of the tree is not modifed by this function. */ +bool tctreeputkeep3(TCTREE *tree, const void *kbuf, int ksiz, const void *vbuf, int vsiz); + + +/* Concatenate a value at the existing record in a tree object without balancing nodes. + `tree' specifies the tree object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `vbuf' specifies the pointer to the region of the value. + `vsiz' specifies the size of the region of the value. + If there is no corresponding record, a new record is created. The structure of the tree is + not modifed by this function. */ +void tctreeputcat3(TCTREE *tree, const void *kbuf, int ksiz, const void *vbuf, int vsiz); + + +/* Retrieve a record in a tree object without balancing nodes. + `tree' specifies the tree object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `sp' specifies the pointer to the variable into which the size of the region of the return + value is assigned. + If successful, the return value is the pointer to the region of the value of the + corresponding record. `NULL' is returned when no record corresponds. + Because an additional zero code is appended at the end of the region of the return value, + the return value can be treated as a character string. The structure of the tree is not + modifed by this function. */ +const void *tctreeget3(const TCTREE *tree, const void *kbuf, int ksiz, int *sp); + + +/* Retrieve a string record in a tree object with specifying the default value string. + `tree' specifies the tree object. + `kstr' specifies the string of the key. + `dstr' specifies the string of the default value. + The return value is the string of the value of the corresponding record or the default value + string. */ +const char *tctreeget4(TCTREE *tree, const char *kstr, const char *dstr); + + +/* Initialize the iterator of a tree object in front of records corresponding a key. + `tree' specifies the tree object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + The iterator is set to the first record corresponding the key or the next substitute if + completely matching record does not exist. */ +void tctreeiterinit2(TCTREE *tree, const void *kbuf, int ksiz); + + +/* Initialize the iterator of a tree object in front of records corresponding a key string. + `tree' specifies the tree object. + `kstr' specifies the string of the key. + The iterator is set to the first record corresponding the key or the next substitute if + completely matching record does not exist. */ +void tctreeiterinit3(TCTREE *tree, const char *kstr); + + +/* Get the value bound to the key fetched from the iterator of a tree object. + `kbuf' specifies the pointer to the region of the iteration key. + `sp' specifies the pointer to the variable into which the size of the region of the return + value is assigned. + The return value is the pointer to the region of the value of the corresponding record. + Because an additional zero code is appended at the end of the region of the return value, + the return value can be treated as a character string. */ +const void *tctreeiterval(const void *kbuf, int *sp); + + +/* Get the value string bound to the key fetched from the iterator of a tree object. + `kstr' specifies the string of the iteration key. + The return value is the pointer to the region of the value of the corresponding record. */ +const char *tctreeiterval2(const char *kstr); + + +/* Create an array of strings of all keys in a tree object. + `tree' specifies the tree object. + `np' specifies the pointer to a variable into which the number of elements of the return value + is assigned. + The return value is the pointer to the array of all string keys in the tree object. + Because the region of the return value is allocated with the `malloc' call, it should be + released with the `free' call if when is no longer in use. Note that elements of the array + point to the inner objects, whose life duration is synchronous with the tree object. */ +const char **tctreekeys2(const TCTREE *tree, int *np); + + +/* Create an array of strings of all values in a tree object. + `tree' specifies the tree object. + `np' specifies the pointer to a variable into which the number of elements of the return value + is assigned. + The return value is the pointer to the array of all string values in the tree object. + Because the region of the return value is allocated with the `malloc' call, it should be + released with the `free' call if when is no longer in use. Note that elements of the array + point to the inner objects, whose life duration is synchronous with the tree object. */ +const char **tctreevals2(const TCTREE *tree, int *np); + + +/* Extract a tree record from a serialized byte array. + `ptr' specifies the pointer to the region of serialized byte array. + `size' specifies the size of the region. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `sp' specifies the pointer to the variable into which the size of the region of the return + value is assigned. + If successful, the return value is the pointer to the region of the value of the + corresponding record. `NULL' is returned when no record corresponds. + Because an additional zero code is appended at the end of the region of the return value, + the return value can be treated as a character string. */ +void *tctreeloadone(const void *ptr, int size, const void *kbuf, int ksiz, int *sp); + + +/* Perform formatted output into a tree object. + `map' specifies the tree object. + `kstr' specifies the string of the key. + `format' specifies the printf-like format string. The conversion character `%' can be used + with such flag characters as `s', `d', `o', `u', `x', `X', `c', `e', `E', `f', `g', `G', `@', + `?', `b', and `%'. `@' works as with `s' but escapes meta characters of XML. `?' works as + with `s' but escapes meta characters of URL. `b' converts an integer to the string as binary + numbers. The other conversion character work as with each original. + The other arguments are used according to the format string. */ +void tctreeprintf(TCTREE *tree, const char *kstr, const char *format, ...); + + + +/************************************************************************************************* + * on-memory hash database + *************************************************************************************************/ + + +typedef struct { /* type of structure for a on-memory hash database */ + void **mmtxs; /* mutexes for method */ + void *imtx; /* mutex for iterator */ + TCMAP **maps; /* internal map objects */ + int iter; /* index of maps for the iterator */ +} TCMDB; + + +/* Create an on-memory hash database object. + The return value is the new on-memory hash database object. + The object can be shared by plural threads because of the internal mutex. */ +TCMDB *tcmdbnew(void); + + +/* Create an on-memory hash database object with specifying the number of the buckets. + `bnum' specifies the number of the buckets. + The return value is the new on-memory hash database object. + The object can be shared by plural threads because of the internal mutex. */ +TCMDB *tcmdbnew2(uint32_t bnum); + + +/* Delete an on-memory hash database object. + `mdb' specifies the on-memory hash database object. */ +void tcmdbdel(TCMDB *mdb); + + +/* Store a record into an on-memory hash database object. + `mdb' specifies the on-memory hash database object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `vbuf' specifies the pointer to the region of the value. + `vsiz' specifies the size of the region of the value. + If a record with the same key exists in the database, it is overwritten. */ +void tcmdbput(TCMDB *mdb, const void *kbuf, int ksiz, const void *vbuf, int vsiz); + + +/* Store a string record into an on-memory hash database object. + `mdb' specifies the on-memory hash database object. + `kstr' specifies the string of the key. + `vstr' specifies the string of the value. + If a record with the same key exists in the database, it is overwritten. */ +void tcmdbput2(TCMDB *mdb, const char *kstr, const char *vstr); + + +/* Store a new record into an on-memory hash database object. + `mdb' specifies the on-memory hash database object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `vbuf' specifies the pointer to the region of the value. + `vsiz' specifies the size of the region of the value. + If successful, the return value is true, else, it is false. + If a record with the same key exists in the database, this function has no effect. */ +bool tcmdbputkeep(TCMDB *mdb, const void *kbuf, int ksiz, const void *vbuf, int vsiz); + + +/* Store a new string record into an on-memory hash database object. + `mdb' specifies the on-memory hash database object. + `kstr' specifies the string of the key. + `vstr' specifies the string of the value. + If successful, the return value is true, else, it is false. + If a record with the same key exists in the database, this function has no effect. */ +bool tcmdbputkeep2(TCMDB *mdb, const char *kstr, const char *vstr); + + +/* Concatenate a value at the end of the existing record in an on-memory hash database. + `mdb' specifies the on-memory hash database object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `vbuf' specifies the pointer to the region of the value. + `vsiz' specifies the size of the region of the value. + If there is no corresponding record, a new record is created. */ +void tcmdbputcat(TCMDB *mdb, const void *kbuf, int ksiz, const void *vbuf, int vsiz); + + +/* Concatenate a string at the end of the existing record in an on-memory hash database. + `mdb' specifies the on-memory hash database object. + `kstr' specifies the string of the key. + `vstr' specifies the string of the value. + If there is no corresponding record, a new record is created. */ +void tcmdbputcat2(TCMDB *mdb, const char *kstr, const char *vstr); + + +/* Remove a record of an on-memory hash database object. + `mdb' specifies the on-memory hash database object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + If successful, the return value is true. False is returned when no record corresponds to + the specified key. */ +bool tcmdbout(TCMDB *mdb, const void *kbuf, int ksiz); + + +/* Remove a string record of an on-memory hash database object. + `mdb' specifies the on-memory hash database object. + `kstr' specifies the string of the key. + If successful, the return value is true. False is returned when no record corresponds to + the specified key. */ +bool tcmdbout2(TCMDB *mdb, const char *kstr); + + +/* Retrieve a record in an on-memory hash database object. + `mdb' specifies the on-memory hash database object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `sp' specifies the pointer to the variable into which the size of the region of the return + value is assigned. + If successful, the return value is the pointer to the region of the value of the + corresponding record. `NULL' is returned when no record corresponds. + Because an additional zero code is appended at the end of the region of the return value, + the return value can be treated as a character string. Because the region of the return + value is allocated with the `malloc' call, it should be released with the `free' call when + it is no longer in use. */ +void *tcmdbget(TCMDB *mdb, const void *kbuf, int ksiz, int *sp); + + +/* Retrieve a string record in an on-memory hash database object. + `mdb' specifies the on-memory hash database object. + `kstr' specifies the string of the key. + If successful, the return value is the string of the value of the corresponding record. + `NULL' is returned when no record corresponds. + Because the region of the return value is allocated with the `malloc' call, it should be + released with the `free' call when it is no longer in use. */ +char *tcmdbget2(TCMDB *mdb, const char *kstr); + + +/* Get the size of the value of a record in an on-memory hash database object. + `mdb' specifies the on-memory hash database object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + If successful, the return value is the size of the value of the corresponding record, else, + it is -1. */ +int tcmdbvsiz(TCMDB *mdb, const void *kbuf, int ksiz); + + +/* Get the size of the value of a string record in an on-memory hash database object. + `mdb' specifies the on-memory hash database object. + `kstr' specifies the string of the key. + If successful, the return value is the size of the value of the corresponding record, else, + it is -1. */ +int tcmdbvsiz2(TCMDB *mdb, const char *kstr); + + +/* Initialize the iterator of an on-memory hash database object. + `mdb' specifies the on-memory hash database object. + The iterator is used in order to access the key of every record stored in the on-memory + database. */ +void tcmdbiterinit(TCMDB *mdb); + + +/* Get the next key of the iterator of an on-memory hash database object. + `mdb' specifies the on-memory hash database object. + `sp' specifies the pointer to the variable into which the size of the region of the return + value is assigned. + If successful, the return value is the pointer to the region of the next key, else, it is + `NULL'. `NULL' is returned when no record can be fetched from the iterator. + Because an additional zero code is appended at the end of the region of the return value, + the return value can be treated as a character string. Because the region of the return + value is allocated with the `malloc' call, it should be released with the `free' call when + it is no longer in use. The order of iteration is assured to be the same as the stored + order. */ +void *tcmdbiternext(TCMDB *mdb, int *sp); + + +/* Get the next key string of the iterator of an on-memory hash database object. + `mdb' specifies the on-memory hash database object. + If successful, the return value is the pointer to the region of the next key, else, it is + `NULL'. `NULL' is returned when no record can be fetched from the iterator. + Because the region of the return value is allocated with the `malloc' call, it should be + released with the `free' call when it is no longer in use. The order of iteration is assured + to be the same as the stored order. */ +char *tcmdbiternext2(TCMDB *mdb); + + +/* Get forward matching keys in an on-memory hash database object. + `mdb' specifies the on-memory hash database object. + `pbuf' specifies the pointer to the region of the prefix. + `psiz' specifies the size of the region of the prefix. + `max' specifies the maximum number of keys to be fetched. If it is negative, no limit is + specified. + The return value is a list object of the corresponding keys. This function does never fail. + It returns an empty list even if no key corresponds. + Because the object of the return value is created with the function `tclistnew', it should be + deleted with the function `tclistdel' when it is no longer in use. Note that this function + may be very slow because every key in the database is scanned. */ +TCLIST *tcmdbfwmkeys(TCMDB *mdb, const void *pbuf, int psiz, int max); + + +/* Get forward matching string keys in an on-memory hash database object. + `mdb' specifies the on-memory hash database object. + `pstr' specifies the string of the prefix. + `max' specifies the maximum number of keys to be fetched. If it is negative, no limit is + specified. + The return value is a list object of the corresponding keys. This function does never fail. + It returns an empty list even if no key corresponds. + Because the object of the return value is created with the function `tclistnew', it should be + deleted with the function `tclistdel' when it is no longer in use. Note that this function + may be very slow because every key in the database is scanned. */ +TCLIST *tcmdbfwmkeys2(TCMDB *mdb, const char *pstr, int max); + + +/* Get the number of records stored in an on-memory hash database object. + `mdb' specifies the on-memory hash database object. + The return value is the number of the records stored in the database. */ +uint64_t tcmdbrnum(TCMDB *mdb); + + +/* Get the total size of memory used in an on-memory hash database object. + `mdb' specifies the on-memory hash database object. + The return value is the total size of memory used in the database. */ +uint64_t tcmdbmsiz(TCMDB *mdb); + + +/* Add an integer to a record in an on-memory hash database object. + `mdb' specifies the on-memory hash database object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `num' specifies the additional value. + The return value is the summation value. + If the corresponding record exists, the value is treated as an integer and is added to. If no + record corresponds, a new record of the additional value is stored. */ +int tcmdbaddint(TCMDB *mdb, const void *kbuf, int ksiz, int num); + + +/* Add a real number to a record in an on-memory hash database object. + `mdb' specifies the on-memory hash database object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `num' specifies the additional value. + The return value is the summation value. + If the corresponding record exists, the value is treated as a real number and is added to. If + no record corresponds, a new record of the additional value is stored. */ +double tcmdbadddouble(TCMDB *mdb, const void *kbuf, int ksiz, double num); + + +/* Clear an on-memory hash database object. + `mdb' specifies the on-memory hash database object. + All records are removed. */ +void tcmdbvanish(TCMDB *mdb); + + +/* Remove front records of an on-memory hash database object. + `mdb' specifies the on-memory hash database object. + `num' specifies the number of records to be removed. */ +void tcmdbcutfront(TCMDB *mdb, int num); + + + +/************************************************************************************************* + * on-memory hash database (for experts) + *************************************************************************************************/ + + +/* Store a record and make it semivolatile in an on-memory hash database object. + `mdb' specifies the on-memory hash database object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `vbuf' specifies the pointer to the region of the value. + `vsiz' specifies the size of the region of the value. + If a record with the same key exists in the map, it is overwritten. The record is moved to + the tail. */ +void tcmdbput3(TCMDB *mdb, const void *kbuf, int ksiz, const char *vbuf, int vsiz); + + +/* Store a record of the value of two regions into an on-memory hash database object. + `mdb' specifies the on-memory hash database object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `fvbuf' specifies the pointer to the former region of the value. + `fvsiz' specifies the size of the former region of the value. + `lvbuf' specifies the pointer to the latter region of the value. + `lvsiz' specifies the size of the latter region of the value. + If a record with the same key exists in the database, it is overwritten. */ +void tcmdbput4(TCMDB *mdb, const void *kbuf, int ksiz, + const void *fvbuf, int fvsiz, const void *lvbuf, int lvsiz); + + +/* Concatenate a value and make it semivolatile in on-memory hash database object. + `mdb' specifies the on-memory hash database object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `vbuf' specifies the pointer to the region of the value. + `vsiz' specifies the size of the region of the value. + If there is no corresponding record, a new record is created. */ +void tcmdbputcat3(TCMDB *mdb, const void *kbuf, int ksiz, const void *vbuf, int vsiz); + + +/* Store a record into a on-memory hash database object with a duplication handler. + `mdb' specifies the on-memory hash database object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `vbuf' specifies the pointer to the region of the value. `NULL' means that record addition is + ommited if there is no corresponding record. + `vsiz' specifies the size of the region of the value. + `proc' specifies the pointer to the callback function to process duplication. It receives + four parameters. The first parameter is the pointer to the region of the value. The second + parameter is the size of the region of the value. The third parameter is the pointer to the + variable into which the size of the region of the return value is assigned. The fourth + parameter is the pointer to the optional opaque object. It returns the pointer to the result + object allocated with `malloc'. It is released by the caller. If it is `NULL', the record is + not modified. If it is `(void *)-1', the record is removed. + `op' specifies an arbitrary pointer to be given as a parameter of the callback function. If + it is not needed, `NULL' can be specified. + If successful, the return value is true, else, it is false. */ +bool tcmdbputproc(TCMDB *mdb, const void *kbuf, int ksiz, const void *vbuf, int vsiz, + TCPDPROC proc, void *op); + + +/* Retrieve a record and move it astern in an on-memory hash database object. + `mdb' specifies the on-memory hash database object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `sp' specifies the pointer to the variable into which the size of the region of the return + value is assigned. + If successful, the return value is the pointer to the region of the value of the + corresponding record. `NULL' is returned when no record corresponds. + Because an additional zero code is appended at the end of the region of the return value, + the return value can be treated as a character string. Because the region of the return value + is allocated with the `malloc' call, it should be released with the `free' call when it is no + longer in use. The internal region of the returned record is moved to the tail so that the + record will survive for a time under LRU cache algorithm removing records from the head. */ +void *tcmdbget3(TCMDB *mdb, const void *kbuf, int ksiz, int *sp); + + +/* Initialize the iterator of an on-memory map database object in front of a key. + `mdb' specifies the on-memory map database object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + If there is no record corresponding the condition, the iterator is not modified. */ +void tcmdbiterinit2(TCMDB *mdb, const void *kbuf, int ksiz); + + +/* Initialize the iterator of an on-memory map database object in front of a key string. + `mdb' specifies the on-memory map database object. + `kstr' specifies the string of the key. + If there is no record corresponding the condition, the iterator is not modified. */ +void tcmdbiterinit3(TCMDB *mdb, const char *kstr); + + +/* Process each record atomically of an on-memory hash database object. + `iter' specifies the pointer to the iterator function called for each record. It receives + five parameters. The first parameter is the pointer to the region of the key. The second + parameter is the size of the region of the key. The third parameter is the pointer to the + region of the value. The fourth parameter is the size of the region of the value. The fifth + parameter is the pointer to the optional opaque object. It returns true to continue iteration + or false to stop iteration. + `op' specifies an arbitrary pointer to be given as a parameter of the iterator function. If + it is not needed, `NULL' can be specified. */ +void tcmdbforeach(TCMDB *mdb, TCITER iter, void *op); + + + +/************************************************************************************************* + * on-memory tree database + *************************************************************************************************/ + + +typedef struct { /* type of structure for a on-memory tree database */ + void *mmtx; /* mutex for method */ + TCTREE *tree; /* internal tree object */ +} TCNDB; + + +/* Create an on-memory tree database object. + The return value is the new on-memory tree database object. + The object can be shared by plural threads because of the internal mutex. */ +TCNDB *tcndbnew(void); + + +/* Create an on-memory tree database object with specifying the custom comparison function. + `cmp' specifies the pointer to the custom comparison function. + `cmpop' specifies an arbitrary pointer to be given as a parameter of the comparison function. + If it is not needed, `NULL' can be specified. + The return value is the new on-memory tree database object. + The default comparison function compares keys of two records by lexical order. The functions + `tccmplexical' (dafault), `tccmpdecimal', `tccmpint32', and `tccmpint64' are built-in. The + object can be shared by plural threads because of the internal mutex. */ +TCNDB *tcndbnew2(TCCMP cmp, void *cmpop); + + +/* Delete an on-memory tree database object. + `ndb' specifies the on-memory tree database object. */ +void tcndbdel(TCNDB *ndb); + + +/* Store a record into an on-memory tree database object. + `ndb' specifies the on-memory tree database object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `vbuf' specifies the pointer to the region of the value. + `vsiz' specifies the size of the region of the value. + If a record with the same key exists in the database, it is overwritten. */ +void tcndbput(TCNDB *ndb, const void *kbuf, int ksiz, const void *vbuf, int vsiz); + + +/* Store a string record into an on-memory tree database object. + `ndb' specifies the on-memory tree database object. + `kstr' specifies the string of the key. + `vstr' specifies the string of the value. + If a record with the same key exists in the database, it is overwritten. */ +void tcndbput2(TCNDB *ndb, const char *kstr, const char *vstr); + + +/* Store a new record into an on-memory tree database object. + `ndb' specifies the on-memory tree database object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `vbuf' specifies the pointer to the region of the value. + `vsiz' specifies the size of the region of the value. + If successful, the return value is true, else, it is false. + If a record with the same key exists in the database, this function has no effect. */ +bool tcndbputkeep(TCNDB *ndb, const void *kbuf, int ksiz, const void *vbuf, int vsiz); + + +/* Store a new string record into an on-memory tree database object. + `ndb' specifies the on-memory tree database object. + `kstr' specifies the string of the key. + `vstr' specifies the string of the value. + If successful, the return value is true, else, it is false. + If a record with the same key exists in the database, this function has no effect. */ +bool tcndbputkeep2(TCNDB *ndb, const char *kstr, const char *vstr); + + +/* Concatenate a value at the end of the existing record in an on-memory tree database. + `ndb' specifies the on-memory tree database object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `vbuf' specifies the pointer to the region of the value. + `vsiz' specifies the size of the region of the value. + If there is no corresponding record, a new record is created. */ +void tcndbputcat(TCNDB *ndb, const void *kbuf, int ksiz, const void *vbuf, int vsiz); + + +/* Concatenate a string at the end of the existing record in an on-memory tree database. + `ndb' specifies the on-memory tree database object. + `kstr' specifies the string of the key. + `vstr' specifies the string of the value. + If there is no corresponding record, a new record is created. */ +void tcndbputcat2(TCNDB *ndb, const char *kstr, const char *vstr); + + +/* Remove a record of an on-memory tree database object. + `ndb' specifies the on-memory tree database object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + If successful, the return value is true. False is returned when no record corresponds to + the specified key. */ +bool tcndbout(TCNDB *ndb, const void *kbuf, int ksiz); + + +/* Remove a string record of an on-memory tree database object. + `ndb' specifies the on-memory tree database object. + `kstr' specifies the string of the key. + If successful, the return value is true. False is returned when no record corresponds to + the specified key. */ +bool tcndbout2(TCNDB *ndb, const char *kstr); + + +/* Retrieve a record in an on-memory tree database object. + `ndb' specifies the on-memory tree database object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `sp' specifies the pointer to the variable into which the size of the region of the return + value is assigned. + If successful, the return value is the pointer to the region of the value of the + corresponding record. `NULL' is returned when no record corresponds. + Because an additional zero code is appended at the end of the region of the return value, + the return value can be treated as a character string. Because the region of the return + value is allocated with the `malloc' call, it should be released with the `free' call when + it is no longer in use. */ +void *tcndbget(TCNDB *ndb, const void *kbuf, int ksiz, int *sp); + + +/* Retrieve a string record in an on-memory tree database object. + `ndb' specifies the on-memory tree database object. + `kstr' specifies the string of the key. + If successful, the return value is the string of the value of the corresponding record. + `NULL' is returned when no record corresponds. + Because the region of the return value is allocated with the `malloc' call, it should be + released with the `free' call when it is no longer in use. */ +char *tcndbget2(TCNDB *ndb, const char *kstr); + + +/* Get the size of the value of a record in an on-memory tree database object. + `ndb' specifies the on-memory tree database object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + If successful, the return value is the size of the value of the corresponding record, else, + it is -1. */ +int tcndbvsiz(TCNDB *ndb, const void *kbuf, int ksiz); + + +/* Get the size of the value of a string record in an on-memory tree database object. + `ndb' specifies the on-memory tree database object. + `kstr' specifies the string of the key. + If successful, the return value is the size of the value of the corresponding record, else, + it is -1. */ +int tcndbvsiz2(TCNDB *ndb, const char *kstr); + + +/* Initialize the iterator of an on-memory tree database object. + `ndb' specifies the on-memory tree database object. + The iterator is used in order to access the key of every record stored in the on-memory + database. */ +void tcndbiterinit(TCNDB *ndb); + + +/* Get the next key of the iterator of an on-memory tree database object. + `ndb' specifies the on-memory tree database object. + `sp' specifies the pointer to the variable into which the size of the region of the return + value is assigned. + If successful, the return value is the pointer to the region of the next key, else, it is + `NULL'. `NULL' is returned when no record can be fetched from the iterator. + Because an additional zero code is appended at the end of the region of the return value, + the return value can be treated as a character string. Because the region of the return + value is allocated with the `malloc' call, it should be released with the `free' call when + it is no longer in use. The order of iteration is assured to be the same as the stored + order. */ +void *tcndbiternext(TCNDB *ndb, int *sp); + + +/* Get the next key string of the iterator of an on-memory tree database object. + `ndb' specifies the on-memory tree database object. + If successful, the return value is the pointer to the region of the next key, else, it is + `NULL'. `NULL' is returned when no record can be fetched from the iterator. + Because the region of the return value is allocated with the `malloc' call, it should be + released with the `free' call when it is no longer in use. The order of iteration is assured + to be the same as the stored order. */ +char *tcndbiternext2(TCNDB *ndb); + + +/* Get forward matching keys in an on-memory tree database object. + `ndb' specifies the on-memory tree database object. + `pbuf' specifies the pointer to the region of the prefix. + `psiz' specifies the size of the region of the prefix. + `max' specifies the maximum number of keys to be fetched. If it is negative, no limit is + specified. + The return value is a list object of the corresponding keys. This function does never fail. + It returns an empty list even if no key corresponds. + Because the object of the return value is created with the function `tclistnew', it should be + deleted with the function `tclistdel' when it is no longer in use. */ +TCLIST *tcndbfwmkeys(TCNDB *ndb, const void *pbuf, int psiz, int max); + + +/* Get forward matching string keys in an on-memory tree database object. + `ndb' specifies the on-memory tree database object. + `pstr' specifies the string of the prefix. + `max' specifies the maximum number of keys to be fetched. If it is negative, no limit is + specified. + The return value is a list object of the corresponding keys. This function does never fail. + It returns an empty list even if no key corresponds. + Because the object of the return value is created with the function `tclistnew', it should be + deleted with the function `tclistdel' when it is no longer in use. */ +TCLIST *tcndbfwmkeys2(TCNDB *ndb, const char *pstr, int max); + + +/* Get the number of records stored in an on-memory tree database object. + `ndb' specifies the on-memory tree database object. + The return value is the number of the records stored in the database. */ +uint64_t tcndbrnum(TCNDB *ndb); + + +/* Get the total size of memory used in an on-memory tree database object. + `ndb' specifies the on-memory tree database object. + The return value is the total size of memory used in the database. */ +uint64_t tcndbmsiz(TCNDB *ndb); + + +/* Add an integer to a record in an on-memory tree database object. + `ndb' specifies the on-memory tree database object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `num' specifies the additional value. + The return value is the summation value. + If the corresponding record exists, the value is treated as an integer and is added to. If no + record corresponds, a new record of the additional value is stored. */ +int tcndbaddint(TCNDB *ndb, const void *kbuf, int ksiz, int num); + + +/* Add a real number to a record in an on-memory tree database object. + `ndb' specifies the on-memory tree database object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `num' specifies the additional value. + The return value is the summation value. + If the corresponding record exists, the value is treated as a real number and is added to. If + no record corresponds, a new record of the additional value is stored. */ +double tcndbadddouble(TCNDB *ndb, const void *kbuf, int ksiz, double num); + + +/* Clear an on-memory tree database object. + `ndb' specifies the on-memory tree database object. + All records are removed. */ +void tcndbvanish(TCNDB *ndb); + + +/* Remove fringe records of an on-memory tree database object. + `ndb' specifies the on-memory tree database object. + `num' specifies the number of records to be removed. */ +void tcndbcutfringe(TCNDB *ndb, int num); + + + +/************************************************************************************************* + * ordered tree (for experts) + *************************************************************************************************/ + + +/* Store a record into a on-memory tree database without balancing nodes. + `ndb' specifies the on-memory tree database. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `vbuf' specifies the pointer to the region of the value. + `vsiz' specifies the size of the region of the value. + If a record with the same key exists in the database, it is overwritten. The structure of the + tree is not modifed by this function. */ +void tcndbput3(TCNDB *ndb, const void *kbuf, int ksiz, const void *vbuf, int vsiz); + + +/* Store a new record into a on-memory tree database object without balancing nodes. + `ndb' specifies the on-memory tree database. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `vbuf' specifies the pointer to the region of the value. + `vsiz' specifies the size of the region of the value. + If successful, the return value is true, else, it is false. + If a record with the same key exists in the database, this function has no effect. The + structure of the tree is not modifed by this function. */ +bool tcndbputkeep3(TCNDB *ndb, const void *kbuf, int ksiz, const void *vbuf, int vsiz); + + +/* Concatenate a value in a on-memory tree database without balancing nodes. + `ndb' specifies the on-memory tree database. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `vbuf' specifies the pointer to the region of the value. + `vsiz' specifies the size of the region of the value. + If there is no corresponding record, a new record is created. The structure of the tree is + not modifed by this function. */ +void tcndbputcat3(TCNDB *ndb, const void *kbuf, int ksiz, const void *vbuf, int vsiz); + + +/* Store a record into a on-memory tree database object with a duplication handler. + `ndb' specifies the on-memory tree database. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `vbuf' specifies the pointer to the region of the value. `NULL' means that record addition is + ommited if there is no corresponding record. + `vsiz' specifies the size of the region of the value. + `proc' specifies the pointer to the callback function to process duplication. It receives + four parameters. The first parameter is the pointer to the region of the value. The second + parameter is the size of the region of the value. The third parameter is the pointer to the + variable into which the size of the region of the return value is assigned. The fourth + parameter is the pointer to the optional opaque object. It returns the pointer to the result + object allocated with `malloc'. It is released by the caller. If it is `NULL', the record is + not modified. If it is `(void *)-1', the record is removed. + `op' specifies an arbitrary pointer to be given as a parameter of the callback function. If + it is not needed, `NULL' can be specified. + If successful, the return value is true, else, it is false. */ +bool tcndbputproc(TCNDB *ndb, const void *kbuf, int ksiz, const void *vbuf, int vsiz, + TCPDPROC proc, void *op); + + +/* Retrieve a record in an on-memory tree database object without balancing nodes. + `ndb' specifies the on-memory tree database object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + `sp' specifies the pointer to the variable into which the size of the region of the return + value is assigned. + If successful, the return value is the pointer to the region of the value of the + corresponding record. `NULL' is returned when no record corresponds. + Because an additional zero code is appended at the end of the region of the return value, + the return value can be treated as a character string. Because the region of the return value + is allocated with the `malloc' call, it should be released with the `free' call when it is no + longer in use. The structure of the tree is not modifed by this function. */ +void *tcndbget3(TCNDB *ndb, const void *kbuf, int ksiz, int *sp); + + +/* Initialize the iterator of an on-memory tree database object in front of a key. + `ndb' specifies the on-memory tree database object. + `kbuf' specifies the pointer to the region of the key. + `ksiz' specifies the size of the region of the key. + The iterator is set to the first record corresponding the key or the next substitute if + completely matching record does not exist. */ +void tcndbiterinit2(TCNDB *ndb, const void *kbuf, int ksiz); + + +/* Initialize the iterator of an on-memory tree database object in front of a key string. + `ndb' specifies the on-memory tree database object. + `kstr' specifies the string of the key. + The iterator is set to the first record corresponding the key or the next substitute if + completely matching record does not exist. */ +void tcndbiterinit3(TCNDB *ndb, const char *kstr); + + +/* Process each record atomically of an on-memory tree database object. + `iter' specifies the pointer to the iterator function called for each record. It receives + five parameters. The first parameter is the pointer to the region of the key. The second + parameter is the size of the region of the key. The third parameter is the pointer to the + region of the value. The fourth parameter is the size of the region of the value. The fifth + parameter is the pointer to the optional opaque object. It returns true to continue iteration + or false to stop iteration. + `op' specifies an arbitrary pointer to be given as a parameter of the iterator function. If + it is not needed, `NULL' can be specified. */ +void tcndbforeach(TCNDB *ndb, TCITER iter, void *op); + + + +/************************************************************************************************* + * memory pool + *************************************************************************************************/ + + +typedef struct { /* type of an element of memory pool */ + void *ptr; /* pointer */ + void (*del)(void *); /* deleting function */ +} TCMPELEM; + +typedef struct { /* type of structure for a memory pool object */ + void *mutex; /* mutex for operations */ + TCMPELEM *elems; /* array of elements */ + int anum; /* number of the elements of the array */ + int num; /* number of used elements */ +} TCMPOOL; + + +/* Create a memory pool object. + The return value is the new memory pool object. */ +TCMPOOL *tcmpoolnew(void); + + +/* Delete a memory pool object. + `mpool' specifies the memory pool object. + Note that the deleted object and its derivatives can not be used anymore. */ +void tcmpooldel(TCMPOOL *mpool); + + +/* Relegate an arbitrary object to a memory pool object. + `mpool' specifies the memory pool object. + `ptr' specifies the pointer to the object to be relegated. If it is `NULL', this function has + no effect. + `del' specifies the pointer to the function to delete the object. + The return value is the pointer to the given object. + This function assures that the specified object is deleted when the memory pool object is + deleted. */ +void *tcmpoolpush(TCMPOOL *mpool, void *ptr, void (*del)(void *)); + + +/* Relegate an allocated region to a memory pool object. + `mpool' specifies the memory pool object. + `ptr' specifies the pointer to the region to be relegated. If it is `NULL', this function has + no effect. + The return value is the pointer to the given object. + This function assures that the specified region is released when the memory pool object is + deleted. */ +void *tcmpoolpushptr(TCMPOOL *mpool, void *ptr); + + +/* Relegate an extensible string object to a memory pool object. + `mpool' specifies the memory pool object. + `xstr' specifies the extensible string object. If it is `NULL', this function has no effect. + The return value is the pointer to the given object. + This function assures that the specified object is deleted when the memory pool object is + deleted. */ +TCXSTR *tcmpoolpushxstr(TCMPOOL *mpool, TCXSTR *xstr); + + +/* Relegate a list object to a memory pool object. + `mpool' specifies the memory pool object. + `list' specifies the list object. If it is `NULL', this function has no effect. + The return value is the pointer to the given object. + This function assures that the specified object is deleted when the memory pool object is + deleted. */ +TCLIST *tcmpoolpushlist(TCMPOOL *mpool, TCLIST *list); + + +/* Relegate a map object to a memory pool object. + `mpool' specifies the memory pool object. + `map' specifies the map object. If it is `NULL', this function has no effect. + The return value is the pointer to the given object. + This function assures that the specified object is deleted when the memory pool object is + deleted. */ +TCMAP *tcmpoolpushmap(TCMPOOL *mpool, TCMAP *map); + + +/* Relegate a tree object to a memory pool object. + `mpool' specifies the memory pool object. + `tree' specifies the tree object. If it is `NULL', this function has no effect. + The return value is the pointer to the given object. + This function assures that the specified object is deleted when the memory pool object is + deleted. */ +TCTREE *tcmpoolpushtree(TCMPOOL *mpool, TCTREE *tree); + + +/* Allocate a region relegated to a memory pool object. + `mpool' specifies the memory pool object. + The return value is the pointer to the allocated region under the memory pool. */ +void *tcmpoolmalloc(TCMPOOL *mpool, size_t size); + + +/* Create an extensible string object relegated to a memory pool object. + The return value is the new extensible string object under the memory pool. */ +TCXSTR *tcmpoolxstrnew(TCMPOOL *mpool); + + +/* Create a list object relegated to a memory pool object. + The return value is the new list object under the memory pool. */ +TCLIST *tcmpoollistnew(TCMPOOL *mpool); + + +/* Create a map object relegated to a memory pool object. + The return value is the new map object under the memory pool. */ +TCMAP *tcmpoolmapnew(TCMPOOL *mpool); + + +/* Create a tree object relegated to a memory pool object. + The return value is the new tree object under the memory pool. */ +TCTREE *tcmpooltreenew(TCMPOOL *mpool); + + +/* Get the global memory pool object. + The return value is the global memory pool object. + The global memory pool object is a singleton and assured to be deleted when the porcess is + terminating normally. */ +TCMPOOL *tcmpoolglobal(void); + + + +/************************************************************************************************* + * miscellaneous utilities + *************************************************************************************************/ + + +/* Get the larger value of two integers. + `a' specifies an integer. + `b' specifies the other integer. + The return value is the larger value of the two. */ +long tclmax(long a, long b); + + +/* Get the lesser value of two integers. + `a' specifies an integer. + `b' specifies the other integer. + The return value is the lesser value of the two. */ +long tclmin(long a, long b); + + +/* Get a random number as long integer based on uniform distribution. + The return value is the random number between 0 and `ULONG_MAX'. + This function uses the random number source device and generates a real random number if + possible. */ +unsigned long tclrand(void); + + +/* Get a random number as double decimal based on uniform distribution. + The return value is the random number equal to or greater than 0, and less than 1.0. + This function uses the random number source device and generates a real random number if + possible. */ +double tcdrand(void); + + +/* Get a random number as double decimal based on normal distribution. + `avg' specifies the average. + `sd' specifies the standard deviation. + The return value is the random number. + This function uses the random number source device and generates a real random number if + possible. */ +double tcdrandnd(double avg, double sd); + + +/* Compare two strings with case insensitive evaluation. + `astr' specifies a string. + `bstr' specifies of the other string. + The return value is positive if the former is big, negative if the latter is big, 0 if both + are equivalent. */ +int tcstricmp(const char *astr, const char *bstr); + + +/* Check whether a string begins with a key. + `str' specifies the target string. + `key' specifies the forward matching key string. + The return value is true if the target string begins with the key, else, it is false. */ +bool tcstrfwm(const char *str, const char *key); + + +/* Check whether a string begins with a key with case insensitive evaluation. + `str' specifies the target string. + `key' specifies the forward matching key string. + The return value is true if the target string begins with the key, else, it is false. */ +bool tcstrifwm(const char *str, const char *key); + + +/* Check whether a string ends with a key. + `str' specifies the target string. + `key' specifies the backward matching key string. + The return value is true if the target string ends with the key, else, it is false. */ +bool tcstrbwm(const char *str, const char *key); + + +/* Check whether a string ends with a key with case insensitive evaluation. + `str' specifies the target string. + `key' specifies the backward matching key string. + The return value is true if the target string ends with the key, else, it is false. */ +bool tcstribwm(const char *str, const char *key); + + +/* Calculate the edit distance of two strings. + `astr' specifies a string. + `bstr' specifies of the other string. + The return value is the edit distance which is known as the Levenshtein distance. The cost is + calculated by byte. */ +int tcstrdist(const char *astr, const char *bstr); + + +/* Calculate the edit distance of two UTF-8 strings. + `astr' specifies a string. + `bstr' specifies of the other string. + The return value is the edit distance which is known as the Levenshtein distance. The cost is + calculated by Unicode character. */ +int tcstrdistutf(const char *astr, const char *bstr); + + +/* Convert the letters of a string into upper case. + `str' specifies the string to be converted. + The return value is the string itself. */ +char *tcstrtoupper(char *str); + + +/* Convert the letters of a string into lower case. + `str' specifies the string to be converted. + The return value is the string itself. */ +char *tcstrtolower(char *str); + + +/* Cut space characters at head or tail of a string. + `str' specifies the string to be converted. + The return value is the string itself. */ +char *tcstrtrim(char *str); + + +/* Squeeze space characters in a string and trim it. + `str' specifies the string to be converted. + The return value is the string itself. */ +char *tcstrsqzspc(char *str); + + +/* Substitute characters in a string. + `str' specifies the string to be converted. + `rstr' specifies the string containing characters to be replaced. + `sstr' specifies the string containing characters to be substituted. + If the substitute string is shorter then the replacement string, corresponding characters are + removed. */ +char *tcstrsubchr(char *str, const char *rstr, const char *sstr); + + +/* Count the number of characters in a string of UTF-8. + `str' specifies the string of UTF-8. + The return value is the number of characters in the string. */ +int tcstrcntutf(const char *str); + + +/* Cut a string of UTF-8 at the specified number of characters. + `str' specifies the string of UTF-8. + `num' specifies the number of characters to be kept. + The return value is the string itself. */ +char *tcstrcututf(char *str, int num); + + +/* Convert a UTF-8 string into a UCS-2 array. + `str' specifies the UTF-8 string. + `ary' specifies the pointer to the region into which the result UCS-2 codes are written. The + size of the buffer should be sufficient. + `np' specifies the pointer to a variable into which the number of elements of the result array + is assigned. */ +void tcstrutftoucs(const char *str, uint16_t *ary, int *np); + + +/* Convert a UCS-2 array into a UTF-8 string. + `ary' specifies the array of UCS-2 code codes. + `num' specifies the number of the array. + `str' specifies the pointer to the region into which the result UTF-8 string is written. The + size of the buffer should be sufficient. */ +void tcstrucstoutf(const uint16_t *ary, int num, char *str); + + +/* Create a list object by splitting a string. + `str' specifies the source string. + `delim' specifies a string containing delimiting characters. + The return value is a list object of the split elements. + If two delimiters are successive, it is assumed that an empty element is between the two. + Because the object of the return value is created with the function `tclistnew', it should be + deleted with the function `tclistdel' when it is no longer in use. */ +TCLIST *tcstrsplit(const char *str, const char *delims); + + +/* Create a string by joining all elements of a list object. + `list' specifies a list object. + `delim' specifies a delimiting character. + The return value is the result string. + Because the region of the return value is allocated with the `malloc' call, it should be + released with the `free' call when it is no longer in use. */ +char *tcstrjoin(const TCLIST *list, char delim); + + +/* Convert a string to an integer. + `str' specifies the string. + The return value is the integer. If the string does not contain numeric expression, 0 is + returned. + This function is equivalent to `atoll' except that it does not depend on the locale. */ +int64_t tcatoi(const char *str); + + +/* Convert a string with a metric prefix to an integer. + `str' specifies the string, which can be trailed by a binary metric prefix. "K", "M", "G", + "T", "P", and "E" are supported. They are case-insensitive. + The return value is the integer. If the string does not contain numeric expression, 0 is + returned. If the integer overflows the domain, `INT64_MAX' or `INT64_MIN' is returned + according to the sign. */ +int64_t tcatoix(const char *str); + + +/* Convert a string to a real number. + `str' specifies the string. + The return value is the real number. If the string does not contain numeric expression, 0.0 + is returned. + This function is equivalent to `atof' except that it does not depend on the locale. */ +double tcatof(const char *str); + + +/* Check whether a string matches a regular expression. + `str' specifies the target string. + `regex' specifies the regular expression string. If it begins with `*', the trailing + substring is used as a case-insensitive regular expression. + The return value is true if matching is success, else, it is false. */ +bool tcregexmatch(const char *str, const char *regex); + + +/* Replace each substring matching a regular expression string. + `str' specifies the target string. + `regex' specifies the regular expression string for substrings. If it begins with `*', the + trailing substring is used as a case-insensitive regular expression. + `alt' specifies the alternative string with which each substrings is replaced. Each `&' in + the string is replaced with the matched substring. Each `\' in the string escapes the + following character. Special escapes "\1" through "\9" referring to the corresponding + matching sub-expressions in the regular expression string are supported. + The return value is a new converted string. Even if the regular expression is invalid, a copy + of the original string is returned. + Because the region of the return value is allocated with the `malloc' call, it should be + released with the `free' call when it is no longer in use. */ +char *tcregexreplace(const char *str, const char *regex, const char *alt); + + +/* Get the MD5 hash value of a record. + `ptr' specifies the pointer to the region of the record. + `size' specifies the size of the region. + `buf' specifies the pointer to the region into which the result string is written. The size + of the buffer should be equal to or more than 48 bytes. */ +void tcmd5hash(const void *ptr, int size, char *buf); + + +/* Get the time of day in seconds. + The return value is the time of day in seconds. The accuracy is in microseconds. */ +double tctime(void); + + +/* Get the Gregorian calendar of a time. + `t' specifies the source time in seconds from the epoch. If it is `INT64_MAX', the current + time is specified. + `jl' specifies the jet lag of a location in seconds. If it is `INT_MAX', the local jet lag is + specified. + `yearp' specifies the pointer to a variable to which the year is assigned. If it is `NULL', + it is not used. + `monp' specifies the pointer to a variable to which the month is assigned. If it is `NULL', + it is not used. 1 means January and 12 means December. + `dayp' specifies the pointer to a variable to which the day of the month is assigned. If it + is `NULL', it is not used. + `hourp' specifies the pointer to a variable to which the hours is assigned. If it is `NULL', + it is not used. + `minp' specifies the pointer to a variable to which the minutes is assigned. If it is `NULL', + it is not used. + `secp' specifies the pointer to a variable to which the seconds is assigned. If it is `NULL', + it is not used. */ +void tccalendar(int64_t t, int jl, int *yearp, int *monp, int *dayp, + int *hourp, int *minp, int *secp); + + +/* Format a date as a string in W3CDTF. + `t' specifies the source time in seconds from the epoch. If it is `INT64_MAX', the current + time is specified. + `jl' specifies the jet lag of a location in seconds. If it is `INT_MAX', the local jet lag is + specified. + `buf' specifies the pointer to the region into which the result string is written. The size + of the buffer should be equal to or more than 48 bytes. + W3CDTF represents a date as "YYYY-MM-DDThh:mm:ddTZD". */ +void tcdatestrwww(int64_t t, int jl, char *buf); + + +/* Format a date as a string in RFC 1123 format. + `t' specifies the source time in seconds from the epoch. If it is `INT64_MAX', the current + time is specified. + `jl' specifies the jet lag of a location in seconds. If it is `INT_MAX', the local jet lag is + specified. + `buf' specifies the pointer to the region into which the result string is written. The size + of the buffer should be equal to or more than 48 bytes. + RFC 1123 format represents a date as "Wdy, DD-Mon-YYYY hh:mm:dd TZD". */ +void tcdatestrhttp(int64_t t, int jl, char *buf); + + +/* Get the time value of a date string. + `str' specifies the date string in decimal, hexadecimal, W3CDTF, or RFC 822 (1123). Decimal + can be trailed by "s" for in seconds, "m" for in minutes, "h" for in hours, and "d" for in + days. + The return value is the time value of the date or `INT64_MAX' if the format is invalid. */ +int64_t tcstrmktime(const char *str); + + +/* Get the jet lag of the local time. + The return value is the jet lag of the local time in seconds. */ +int tcjetlag(void); + + +/* Get the day of week of a date. + `year' specifies the year of a date. + `mon' specifies the month of the date. + `day' specifies the day of the date. + The return value is the day of week of the date. 0 means Sunday and 6 means Saturday. */ +int tcdayofweek(int year, int mon, int day); + + + +/************************************************************************************************* + * miscellaneous utilities (for experts) + *************************************************************************************************/ + + +enum { /* enumeration for UCS normalization */ + TCUNLOWER = 1 << 0, /* lower case normalization */ + TCUNNOACC = 1 << 1, /* strip accent marks */ + TCUNSPACE = 1 << 2 /* white space normalization */ +}; + +typedef struct { /* type of structure for a consistent hashing node */ + uint32_t seq; /* sequential number */ + uint32_t hash; /* hash value */ +} TCCHIDXNODE; + +typedef struct { /* type of structure for a consistent hashing object */ + TCCHIDXNODE *nodes; /* node array */ + int nnum; /* number of the node array */ +} TCCHIDX; + + +/* Check whether a string is numeric completely or not. + `str' specifies the string to be checked. + The return value is true if the string is numeric, else, it is false. */ +bool tcstrisnum(const char *str); + + +/* Convert a hexadecimal string to an integer. + `str' specifies the string. + The return value is the integer. If the string does not contain numeric expression, 0 is + returned. */ +int64_t tcatoih(const char *str); + + +/* Skip space characters at head of a string. + `str' specifies the string. + The return value is the pointer to the first non-space character. */ +const char *tcstrskipspc(const char *str); + + +/* Normalize a UCS-2 array. + `ary' specifies the array of UCS-2 code codes. + `num' specifies the number of elements of the array. + `opts' specifies options by bitwise-or: `TCUNLOWER' specifies that alphabetical characters are + normalized into lower cases, `TCUNNOACC' specifies that alphabetical characters with accent + marks are normalized without accent marks, `TCUNSPACE' specifies that white space characters + are normalized into the ASCII space and they are squeezed into one. + The return value is the number of elements of the result array. */ +int tcstrucsnorm(uint16_t *ary, int num, int opts); + + +/* Create a list object by splitting a region by zero code. + `ptr' specifies the pointer to the region. + `size' specifies the size of the region. + The return value is a list object of the split elements. + If two delimiters are successive, it is assumed that an empty element is between the two. + Because the object of the return value is created with the function `tclistnew', it should be + deleted with the function `tclistdel' when it is no longer in use. */ +TCLIST *tcstrsplit2(const void *ptr, int size); + + +/* Create a map object by splitting a string. + `str' specifies the source string where the key and the value of each record are situated one + after the other. + `delim' specifies a string containing delimiting characters. + The return value is a map object of the split records. + Because the object of the return value is created with the function `tcmapnew', it should be + deleted with the function `tcmapdel' when it is no longer in use. */ +TCMAP *tcstrsplit3(const char *str, const char *delims); + + +/* Create a map object by splitting a region by zero code. + `ptr' specifies the pointer to the region where the key and the value of each record are + situated one after the other. + `size' specifies the size of the region. + The return value is a map object of the split records. + Because the object of the return value is created with the function `tcmapnew', it should be + deleted with the function `tcmapdel' when it is no longer in use. */ +TCMAP *tcstrsplit4(const void *ptr, int size); + + +/* Create a region separated by zero code by joining all elements of a list object. + `list' specifies a list object. + The return value is the result region. + `sp' specifies the pointer to the variable into which the size of the region of the return + value is assigned. + Because the region of the return value is allocated with the `malloc' call, it should be + released with the `free' call when it is no longer in use. */ +void *tcstrjoin2(const TCLIST *list, int *sp); + + +/* Create a string by joining all records of a map object. + `map' specifies a map object. + `delim' specifies a delimiting character. + The return value is the result string where the key and the value of each record are situated + one after the other. + Because the region of the return value is allocated with the `malloc' call, it should be + released with the `free' call when it is no longer in use. */ +char *tcstrjoin3(const TCMAP *map, char delim); + + +/* Create a region separated by zero code by joining all records of a map object. + `list' specifies a list object. + The return value is the result region, where the key and the value of each record are + situated one after the other. + `sp' specifies the pointer to the variable into which the size of the region of the return + value is assigned. + Because the region of the return value is allocated with the `malloc' call, it should be + released with the `free' call when it is no longer in use. */ +void *tcstrjoin4(const TCMAP *map, int *sp); + + +/* Sort top records of an array. + `base' spacifies the pointer to an array. + `nmemb' specifies the number of elements of the array. + `size' specifies the size of each element. + `top' specifies the number of top records. + `compar' specifies the pointer to comparing function. The two arguments specify the pointers + of elements. The comparing function should returns positive if the former is big, negative + if the latter is big, 0 if both are equal. */ +void tctopsort(void *base, size_t nmemb, size_t size, size_t top, + int(*compar)(const void *, const void *)); + + +/* Suspend execution of the current thread. + `sec' specifies the interval of the suspension in seconds. + If successful, the return value is true, else, it is false. */ +bool tcsleep(double sec); + + +/* Get the current system information. + The return value is a map object of the current system information or `NULL' on failure. The + key "size" specifies the process size in bytes. The "rss" specifies the resident set size in + bytes. + Because the object of the return value is created with the function `tcmapnew', it should be + deleted with the function `tcmapdel' when it is no longer in use. */ +TCMAP *tcsysinfo(void); + + +/* Create a consistent hashing object. + `range' specifies the number of nodes. It should be more than 0. The range of hash values is + from 0 to less than the specified number. + The return value is the new consistent hashing object. + Consistent hashing is useful because the addition or removal of one node does not + significantly change the mapping of keys to nodes. */ +TCCHIDX *tcchidxnew(int range); + + +/* Delete a consistent hashing object. + `chidx' specifies the consistent hashing object. */ +void tcchidxdel(TCCHIDX *chidx); + + +/* Get the consistent hashing value of a record. + `chidx' specifies the consistent hashing object. + `ptr' specifies the pointer to the region of the record. + `size' specifies the size of the region. + The return value is the hash value of the record. */ +int tcchidxhash(TCCHIDX *chidx, const void *ptr, int size); + + + +/************************************************************************************************* + * filesystem utilities + *************************************************************************************************/ + + +/* Get the canonicalized absolute path of a file. + `path' specifies the path of the file. + The return value is the canonicalized absolute path of a file, or `NULL' if the path is + invalid. + Because the region of the return value is allocated with the `malloc' call, it should be + released with the `free' call when it is no longer in use. */ +char *tcrealpath(const char *path); + + +/* Read whole data of a file. + `path' specifies the path of the file. If it is `NULL', the standard input is specified. + `limit' specifies the limiting size of reading data. If it is not more than 0, the limitation + is not specified. + `sp' specifies the pointer to the variable into which the size of the region of the return + value is assigned. If it is `NULL', it is not used. + The return value is the pointer to the allocated region of the read data, or `NULL' if the + file could not be opened. + Because an additional zero code is appended at the end of the region of the return value, the + return value can be treated as a character string. Because the region of the return value is + allocated with the `malloc' call, it should be released with the `free' call when when is no + longer in use. */ +void *tcreadfile(const char *path, int limit, int *sp); + + +/* Read every line of a file. + `path' specifies the path of the file. If it is `NULL', the standard input is specified. + The return value is a list object of every lines if successful, else it is `NULL'. + Line separators are cut out. Because the object of the return value is created with the + function `tclistnew', it should be deleted with the function `tclistdel' when it is no longer + in use. */ +TCLIST *tcreadfilelines(const char *path); + + +/* Write data into a file. + `path' specifies the path of the file. If it is `NULL', the standard output is specified. + `ptr' specifies the pointer to the data region. + `size' specifies the size of the region. + If successful, the return value is true, else, it is false. */ +bool tcwritefile(const char *path, const void *ptr, int size); + + +/* Copy a file. + `src' specifies the path of the source file. + `dest' specifies the path of the destination file. + The return value is true if successful, else, it is false. + If the destination file exists, it is overwritten. */ +bool tccopyfile(const char *src, const char *dest); + + +/* Read names of files in a directory. + `path' specifies the path of the directory. + The return value is a list object of names if successful, else it is `NULL'. + Links to the directory itself and to the parent directory are ignored. + Because the object of the return value is created with the function `tclistnew', it should + be deleted with the function `tclistdel' when it is no longer in use. */ +TCLIST *tcreaddir(const char *path); + + +/* Expand a pattern into a list of matched paths. + `pattern' specifies the matching pattern. + The return value is a list object of matched paths. If no path is matched, an empty list is + returned. + Because the object of the return value is created with the function `tclistnew', it should + be deleted with the function `tclistdel' when it is no longer in use. */ +TCLIST *tcglobpat(const char *pattern); + + +/* Remove a file or a directory and its sub ones recursively. + `path' specifies the path of the link. + If successful, the return value is true, else, it is false. False is returned when the link + does not exist or the permission is denied. */ +bool tcremovelink(const char *path); + + +/* Write data into a file. + `fd' specifies the file descriptor. + `buf' specifies the buffer to be written. + `size' specifies the size of the buffer. + The return value is true if successful, else, it is false. */ +bool tcwrite(int fd, const void *buf, size_t size); + + +/* Read data from a file. + `fd' specifies the file descriptor. + `buf' specifies the buffer to store into. + `size' specifies the size of the buffer. + The return value is true if successful, else, it is false. */ +bool tcread(int fd, void *buf, size_t size); + + +/* Lock a file. + `fd' specifies the file descriptor. + `ex' specifies whether an exclusive lock or a shared lock is performed. + `nb' specifies whether to request with non-blocking. + The return value is true if successful, else, it is false. */ +bool tclock(int fd, bool ex, bool nb); + + +/* Unlock a file. + `fd' specifies the file descriptor. + The return value is true if successful, else, it is false. */ +bool tcunlock(int fd); + + +/* Execute a shell command. + `args' specifies an array of the command name and its arguments. + `anum' specifies the number of elements of the array. + The return value is the exit code of the command or `INT_MAX' on failure. + The command name and the arguments are quoted and meta characters are escaped. */ +int tcsystem(const char **args, int anum); + + + +/************************************************************************************************* + * encoding utilities + *************************************************************************************************/ + + +/* Encode a serial object with URL encoding. + `ptr' specifies the pointer to the region. + `size' specifies the size of the region. + The return value is the result string. + Because the region of the return value is allocated with the `malloc' call, it should be + released with the `free' call if when is no longer in use. */ +char *tcurlencode(const char *ptr, int size); + + +/* Decode a string encoded with URL encoding. + `str' specifies the encoded string. + `sp' specifies the pointer to a variable into which the size of the region of the return + value is assigned. + The return value is the pointer to the region of the result. + Because an additional zero code is appended at the end of the region of the return value, + the return value can be treated as a character string. Because the region of the return + value is allocated with the `malloc' call, it should be released with the `free' call when + it is no longer in use. */ +char *tcurldecode(const char *str, int *sp); + + +/* Break up a URL into elements. + `str' specifies the URL string. + The return value is the map object whose keys are the name of elements. The key "self" + specifies the URL itself. The key "scheme" specifies the scheme. The key "host" specifies + the host of the server. The key "port" specifies the port number of the server. The key + "authority" specifies the authority information. The key "path" specifies the path of the + resource. The key "file" specifies the file name without the directory section. The key + "query" specifies the query string. The key "fragment" specifies the fragment string. + Supported schema are HTTP, HTTPS, FTP, and FILE. Absolute URL and relative URL are supported. + Because the object of the return value is created with the function `tcmapnew', it should be + deleted with the function `tcmapdel' when it is no longer in use. */ +TCMAP *tcurlbreak(const char *str); + + +/* Resolve a relative URL with an absolute URL. + `base' specifies the absolute URL of the base location. + `target' specifies the URL to be resolved. + The return value is the resolved URL. If the target URL is relative, a new URL of relative + location from the base location is returned. Else, a copy of the target URL is returned. + Because the region of the return value is allocated with the `malloc' call, it should be + released with the `free' call when it is no longer in use. */ +char *tcurlresolve(const char *base, const char *target); + + +/* Encode a serial object with Base64 encoding. + `ptr' specifies the pointer to the region. + `size' specifies the size of the region. + The return value is the result string. + Because the region of the return value is allocated with the `malloc' call, it should be + released with the `free' call if when is no longer in use. */ +char *tcbaseencode(const char *ptr, int size); + + +/* Decode a string encoded with Base64 encoding. + `str' specifies the encoded string. + `sp' specifies the pointer to a variable into which the size of the region of the return + value is assigned. + The return value is the pointer to the region of the result. + Because an additional zero code is appended at the end of the region of the return value, + the return value can be treated as a character string. Because the region of the return + value is allocated with the `malloc' call, it should be released with the `free' call when + it is no longer in use. */ +char *tcbasedecode(const char *str, int *sp); + + +/* Encode a serial object with Quoted-printable encoding. + `ptr' specifies the pointer to the region. + `size' specifies the size of the region. + The return value is the result string. + Because the region of the return value is allocated with the `malloc' call, it should be + released with the `free' call if when is no longer in use. */ +char *tcquoteencode(const char *ptr, int size); + + +/* Decode a string encoded with Quoted-printable encoding. + `str' specifies the encoded string. + `sp' specifies the pointer to a variable into which the size of the region of the return + value is assigned. + The return value is the pointer to the region of the result. + Because an additional zero code is appended at the end of the region of the return value, + the return value can be treated as a character string. Because the region of the return + value is allocated with the `malloc' call, it should be released with the `free' call when + it is no longer in use. */ +char *tcquotedecode(const char *str, int *sp); + + +/* Encode a string with MIME encoding. + `str' specifies the string. + `encname' specifies the string of the name of the character encoding. + `base' specifies whether to use Base64 encoding. If it is false, Quoted-printable is used. + The return value is the result string. + Because the region of the return value is allocated with the `malloc' call, it should be + released with the `free' call when it is no longer in use. */ +char *tcmimeencode(const char *str, const char *encname, bool base); + + +/* Decode a string encoded with MIME encoding. + `str' specifies the encoded string. + `enp' specifies the pointer to the region into which the name of encoding is written. If it + is `NULL', it is not used. The size of the buffer should be equal to or more than 32 bytes. + The return value is the result string. + Because the region of the return value is allocated with the `malloc' call, it should be + released with the `free' call when it is no longer in use. */ +char *tcmimedecode(const char *str, char *enp); + + +/* Split a string of MIME into headers and the body. + `ptr' specifies the pointer to the region of MIME data. + `size' specifies the size of the region. + `headers' specifies a map object to store headers. If it is `NULL', it is not used. Each key + of the map is an uncapitalized header name. + `sp' specifies the pointer to the variable into which the size of the region of the return + value is assigned. + The return value is the pointer to the region of the body data. + If the content type is defined, the header map has the key "TYPE" specifying the type. If the + character encoding is defined, the key "CHARSET" specifies the encoding name. If the boundary + string of multipart is defined, the key "BOUNDARY" specifies the string. If the content + disposition is defined, the key "DISPOSITION" specifies the direction. If the file name is + defined, the key "FILENAME" specifies the name. If the attribute name is defined, the key + "NAME" specifies the name. Because the region of the return value is allocated with the + `malloc' call, it should be released with the `free' call when it is no longer in use. */ +char *tcmimebreak(const char *ptr, int size, TCMAP *headers, int *sp); + + +/* Split multipart data of MIME into its parts. + `ptr' specifies the pointer to the region of multipart data of MIME. + `size' specifies the size of the region. + `boundary' specifies the boundary string. + The return value is a list object. Each element of the list is the data of a part. + Because the object of the return value is created with the function `tclistnew', it should be + deleted with the function `tclistdel' when it is no longer in use. */ +TCLIST *tcmimeparts(const char *ptr, int size, const char *boundary); + + +/* Encode a serial object with hexadecimal encoding. + `ptr' specifies the pointer to the region. + `size' specifies the size of the region. + The return value is the result string. + Because the region of the return value is allocated with the `malloc' call, it should be + released with the `free' call if when is no longer in use. */ +char *tchexencode(const char *ptr, int size); + + +/* Decode a string encoded with hexadecimal encoding. + `str' specifies the encoded string. + `sp' specifies the pointer to a variable into which the size of the region of the return + value is assigned. + The return value is the pointer to the region of the result. + Because an additional zero code is appended at the end of the region of the return value, + the return value can be treated as a character string. Because the region of the return + value is allocated with the `malloc' call, it should be released with the `free' call when + it is no longer in use. */ +char *tchexdecode(const char *str, int *sp); + + +/* Compress a serial object with Packbits encoding. + `ptr' specifies the pointer to the region. + `size' specifies the size of the region. + `sp' specifies the pointer to the variable into which the size of the region of the return + value is assigned. + If successful, the return value is the pointer to the result object, else, it is `NULL'. + Because the region of the return value is allocated with the `malloc' call, it should be + released with the `free' call when it is no longer in use. */ +char *tcpackencode(const char *ptr, int size, int *sp); + + +/* Decompress a serial object compressed with Packbits encoding. + `ptr' specifies the pointer to the region. + `size' specifies the size of the region. + `sp' specifies the pointer to a variable into which the size of the region of the return + value is assigned. + If successful, the return value is the pointer to the result object, else, it is `NULL'. + Because an additional zero code is appended at the end of the region of the return value, + the return value can be treated as a character string. Because the region of the return + value is allocated with the `malloc' call, it should be released with the `free' call when it + is no longer in use. */ +char *tcpackdecode(const char *ptr, int size, int *sp); + + +/* Compress a serial object with TCBS encoding. + `ptr' specifies the pointer to the region. + `size' specifies the size of the region. + `sp' specifies the pointer to the variable into which the size of the region of the return + value is assigned. + If successful, the return value is the pointer to the result object, else, it is `NULL'. + Because the region of the return value is allocated with the `malloc' call, it should be + released with the `free' call when it is no longer in use. */ +char *tcbsencode(const char *ptr, int size, int *sp); + + +/* Decompress a serial object compressed with TCBS encoding. + `ptr' specifies the pointer to the region. + `size' specifies the size of the region. + `sp' specifies the pointer to a variable into which the size of the region of the return + value is assigned. + If successful, the return value is the pointer to the result object, else, it is `NULL'. + Because an additional zero code is appended at the end of the region of the return value, + the return value can be treated as a character string. Because the region of the return + value is allocated with the `malloc' call, it should be released with the `free' call when it + is no longer in use. */ +char *tcbsdecode(const char *ptr, int size, int *sp); + + +/* Compress a serial object with Deflate encoding. + `ptr' specifies the pointer to the region. + `size' specifies the size of the region. + `sp' specifies the pointer to the variable into which the size of the region of the return + value is assigned. + If successful, the return value is the pointer to the result object, else, it is `NULL'. + Because the region of the return value is allocated with the `malloc' call, it should be + released with the `free' call when it is no longer in use. */ +char *tcdeflate(const char *ptr, int size, int *sp); + + +/* Decompress a serial object compressed with Deflate encoding. + `ptr' specifies the pointer to the region. + `size' specifies the size of the region. + `sp' specifies the pointer to a variable into which the size of the region of the return + value is assigned. + If successful, the return value is the pointer to the result object, else, it is `NULL'. + Because an additional zero code is appended at the end of the region of the return value, + the return value can be treated as a character string. Because the region of the return + value is allocated with the `malloc' call, it should be released with the `free' call when it + is no longer in use. */ +char *tcinflate(const char *ptr, int size, int *sp); + + +/* Compress a serial object with GZIP encoding. + `ptr' specifies the pointer to the region. + `size' specifies the size of the region. + `sp' specifies the pointer to the variable into which the size of the region of the return + value is assigned. + If successful, the return value is the pointer to the result object, else, it is `NULL'. + Because the region of the return value is allocated with the `malloc' call, it should be + released with the `free' call when it is no longer in use. */ +char *tcgzipencode(const char *ptr, int size, int *sp); + + +/* Decompress a serial object compressed with GZIP encoding. + `ptr' specifies the pointer to the region. + `size' specifies the size of the region. + `sp' specifies the pointer to a variable into which the size of the region of the return + value is assigned. + If successful, the return value is the pointer to the result object, else, it is `NULL'. + Because an additional zero code is appended at the end of the region of the return value, + the return value can be treated as a character string. Because the region of the return + value is allocated with the `malloc' call, it should be released with the `free' call when it + is no longer in use. */ +char *tcgzipdecode(const char *ptr, int size, int *sp); + + +/* Get the CRC32 checksum of a serial object. + `ptr' specifies the pointer to the region. + `size' specifies the size of the region. + The return value is the CRC32 checksum of the object. */ +unsigned int tcgetcrc(const char *ptr, int size); + + +/* Compress a serial object with BZIP2 encoding. + `ptr' specifies the pointer to the region. + `size' specifies the size of the region. + `sp' specifies the pointer to the variable into which the size of the region of the return + value is assigned. + If successful, the return value is the pointer to the result object, else, it is `NULL'. + Because the region of the return value is allocated with the `malloc' call, it should be + released with the `free' call when it is no longer in use. */ +char *tcbzipencode(const char *ptr, int size, int *sp); + + +/* Decompress a serial object compressed with BZIP2 encoding. + `ptr' specifies the pointer to the region. + `size' specifies the size of the region. + `sp' specifies the pointer to a variable into which the size of the region of the return + value is assigned. + If successful, the return value is the pointer to the result object, else, it is `NULL'. + Because an additional zero code is appended at the end of the region of the return value, + the return value can be treated as a character string. Because the region of the return + value is allocated with the `malloc' call, it should be released with the `free' call when it + is no longer in use. */ +char *tcbzipdecode(const char *ptr, int size, int *sp); + + +/* Encode an array of nonnegative integers with BER encoding. + `ary' specifies the pointer to the array of nonnegative integers. + `anum' specifies the size of the array. + `sp' specifies the pointer to a variable into which the size of the region of the return + value is assigned. + The return value is the pointer to the region of the result. + Because the region of the return value is allocated with the `malloc' call, it should be + released with the `free' call if when is no longer in use. */ +char *tcberencode(const unsigned int *ary, int anum, int *sp); + + +/* Decode a serial object encoded with BER encoding. + `ptr' specifies the pointer to the region. + `size' specifies the size of the region. + `np' specifies the pointer to a variable into which the number of elements of the return value + is assigned. + The return value is the pointer to the array of the result. + Because the region of the return value is allocated with the `malloc' call, it should be + released with the `free' call if when is no longer in use. */ +unsigned int *tcberdecode(const char *ptr, int size, int *np); + + +/* Escape meta characters in a string with the entity references of XML. + `str' specifies the string. + The return value is the pointer to the escaped string. + This function escapes only `&', `<', `>', and `"'. Because the region of the return value + is allocated with the `malloc' call, it should be released with the `free' call when it is no + longer in use. */ +char *tcxmlescape(const char *str); + + +/* Unescape entity references in a string of XML. + `str' specifies the string. + The return value is the unescaped string. + This function restores only `&', `<', `>', and `"'. Because the region of the + return value is allocated with the `malloc' call, it should be released with the `free' call + when it is no longer in use. */ +char *tcxmlunescape(const char *str); + + + +/************************************************************************************************* + * encoding utilities (for experts) + *************************************************************************************************/ + + +/* Encode a map object into a string in the x-www-form-urlencoded format. + `params' specifies a map object of parameters. + The return value is the result string. + Because the region of the return value is allocated with the `malloc' call, it should be + released with the `free' call when it is no longer in use. */ +char *tcwwwformencode(const TCMAP *params); + + +/* Decode a query string in the x-www-form-urlencoded format. + `str' specifies the query string. + `params' specifies a map object into which the result parameters are stored. */ +void tcwwwformdecode(const char *str, TCMAP *params); + + +/* Split an XML string into tags and text sections. + `str' specifies the string. + The return value is the list object whose elements are strings of tags or text sections. + Because the object of the return value is created with the function `tclistnew', it should + be deleted with the function `tclistdel' when it is no longer in use. Because this function + does not check validation, it can handle also HTML and SGML. */ +TCLIST *tcxmlbreak(const char *str); + + +/* Get the map of attributes of an XML tag. + `str' specifies the pointer to the region of a tag string. + The return value is the map object containing attribute names and their values which are + unescaped. You can get the name of the tag with the key of an empty string. + Because the object of the return value is created with the function `tcmapnew', it should + be deleted with the function `tcmapdel' when it is no longer in use. */ +TCMAP *tcxmlattrs(const char *str); + + +/* Escape meta characters in a string with backslash escaping of the C language. + `str' specifies the string. + The return value is the pointer to the escaped string. + Because the region of the return value is allocated with the `malloc' call, it should be + released with the `free' call if when is no longer in use. */ +char *tccstrescape(const char *str); + + +/* Unescape a string escaped by backslash escaping of the C language. + `str' specifies the string. + The return value is the unescaped string. + Because the region of the return value is allocated with the `malloc' call, it should be + released with the `free' call if when is no longer in use. */ +char *tccstrunescape(const char *str); + + +/* Escape meta characters in a string with backslash escaping of JSON. + `str' specifies the string. + The return value is the pointer to the escaped string. + Because the region of the return value is allocated with the `malloc' call, it should be + released with the `free' call if when is no longer in use. */ +char *tcjsonescape(const char *str); + + +/* Unescape a string escaped by backslash escaping of JSON. + `str' specifies the string. + The return value is the unescaped string. + Because the region of the return value is allocated with the `malloc' call, it should be + released with the `free' call if when is no longer in use. */ +char *tcjsonunescape(const char *str); + + + +/************************************************************************************************* + * template serializer + *************************************************************************************************/ + + +typedef struct { /* type of structure for a template */ + TCLIST *elems; /* elements separated by the separators */ + char *begsep; /* beginning separator */ + char *endsep; /* ending separator */ + TCMAP *conf; /* configuration variables */ +} TCTMPL; + + +/* Create a template object. + The return value is the new template object. */ +TCTMPL *tctmplnew(void); + + +/* Delete a template object. + `tmpl' specifies the template object. */ +void tctmpldel(TCTMPL *tmpl); + + +/* Set the separator strings of a template object. + `tmpl' specifies the template object. + `begsep' specifies the beginning separator string. By default, it is "[%". + `endsep' specifies the ending separator string. By default, it is "%]". */ +void tctmplsetsep(TCTMPL *tmpl, const char *begsep, const char *endsep); + + +/* Load a template string into a template object. + `tmpl' specifies the template object. + `str' specifies the template string. Directives between "[%" and "%]" can be included in the + template string. If the variable name is specified in the directive, it is expanded as the + value of the variable. "." is used in order to access a record of a hash variable. For + example, "[% foo.bar.baz %]" is expanded as the value of the record whose key is "baz" in the + hash variable of the record whose key is "bar" in the hash variable whose name is "foo". + Moreover, control flow directives are also supported. "[% IF ... %]", "[% ELSE %]", and + "[% END %]" are conditional directives. "[% FOREACH ... %]" and "[% END %]" are iterator + directives for a list object. "[% CONF ... %]" is a configuration directive. If the ending + separator of a directive is leaded by "\", the next linefeed character is ignored. Variable + expansion directive needs the parameter for the variable name. The optional parameter "DEF" + trailed by a string specifies the default value. The optional parameter "ENC" trailed by a + string specifies the encoding format. "URL" for the URL escape encoding, "XML" for the XML + escape encoding, "CSTR" for C-string escape encoding, and "JSON" for JSON escape encoding are + supported. The conditional directive needs the parameter for the variable name. If the + variable exists, the block to the correspondent ending directive is evaluated, else, the block + is ignored. The optional parameter "EQ" trailed by a string specifies the string full + matching test. The optional parameter "RX" trailed by a string specifies the regular + expression matching test. The optional parameter "NOT" inverts the logical determination. + The iterator directive needs the parameter for the variable name of a list object. The block + to the correspondent ending directive is evaluated for each element of the list. The optional + parameter specifies the local variable name of each element. The configuration directive + needs the parameters for the variable name and its value. */ +void tctmplload(TCTMPL *tmpl, const char *str); + + +/* Load a template string from a file into a template object. + `tmpl' specifies the template object. + `path' specifies the input file. + If successful, the return value is true, else, it is false. */ +bool tctmplload2(TCTMPL *tmpl, const char *path); + + +/* Serialize the template string of a template object. + `tmpl' specifies the template object. + `vars' specifies the variables to be applied into the template. + The return value is the dumped template string. + Because the region of the return value is allocated with the `malloc' call, it should be + released with the `free' call when it is no longer in use. */ +char *tctmpldump(TCTMPL *tmpl, const TCMAP *vars); + + +/* Get the value of a configuration variable of a template object. + `tmpl' specifies the template object. + `name' specifies the name of the configuration variable. + The return value is the string value of the configuration variable or `NULL' if it is not + defined. */ +const char *tctmplconf(TCTMPL *tmpl, const char *name); + + +/* Store a list object into a list object with the type information. + `list' specifies the container list object. + `obj' specifies the list object to be stored. */ +void tclistpushlist(TCLIST *list, const TCLIST *obj); + + +/* Store a map object into a list object with the type information. + `list' specifies the container list object. + `obj' specifies the map object to be stored. */ +void tclistpushmap(TCLIST *list, const TCMAP *obj); + + +/* Store a list object into a map object with the type information. + `map' specifies the container map object. + `kstr' specifies the string of the key. + `obj' specifies the list object to be stored. */ +void tcmapputlist(TCMAP *map, const char *kstr, const TCLIST *obj); + + +/* Store a map object into a map object with the type information. + `map' specifies the container map object. + `kstr' specifies the string of the key. + `obj' specifies the map object to be stored. */ +void tcmapputmap(TCMAP *map, const char *kstr, const TCMAP *obj); + + + +/************************************************************************************************* + * pointer list + *************************************************************************************************/ + + +typedef struct { /* type of structure for a pointer list */ + void **array; /* array of pointers */ + int anum; /* number of the elements of the array */ + int start; /* start index of used elements */ + int num; /* number of used elements */ +} TCPTRLIST; + + +/* Create a pointer list object. + The return value is the new pointer list object. */ +TCPTRLIST *tcptrlistnew(void); + + +/* Create a pointer list object with expecting the number of elements. + `anum' specifies the number of elements expected to be stored in the list. + The return value is the new pointer list object. */ +TCPTRLIST *tcptrlistnew2(int anum); + + +/* Copy a pointer list object. + `ptrlist' specifies the pointer list object. + The return value is the new pointer list object equivalent to the specified object. */ +TCPTRLIST *tcptrlistdup(const TCPTRLIST *ptrlist); + + +/* Delete a pointer list object. + `ptrlist' specifies the pointer list object. + Note that the deleted object and its derivatives can not be used anymore. */ +void tcptrlistdel(TCPTRLIST *ptrlist); + + +/* Get the number of elements of a pointer list object. + `ptrlist' specifies the pointer list object. + The return value is the number of elements of the list. */ +int tcptrlistnum(const TCPTRLIST *ptrlist); + + +/* Get the pointer to the region of an element of a pointer list object. + `ptrlist' specifies the pointer list object. + `index' specifies the index of the element. + The return value is the pointer to the region of the value. + If `index' is equal to or more than the number of elements, the return value is `NULL'. */ +void *tcptrlistval(const TCPTRLIST *ptrlist, int index_); + + +/* Add an element at the end of a pointer list object. + `ptrlist' specifies the pointer list object. + `ptr' specifies the pointer to the region of the new element. */ +void tcptrlistpush(TCPTRLIST *ptrlist, void *ptr); + + +/* Remove an element of the end of a pointer list object. + `ptrlist' specifies the pointer list object. + The return value is the pointer to the region of the removed element. + If the list is empty, the return value is `NULL'. */ +void *tcptrlistpop(TCPTRLIST *ptrlist); + + +/* Add an element at the top of a pointer list object. + `ptrlist' specifies the pointer list object. + `ptr' specifies the pointer to the region of the new element. */ +void tcptrlistunshift(TCPTRLIST *ptrlist, void *ptr); + + +/* Remove an element of the top of a pointer list object. + `ptrlist' specifies the pointer list object. + The return value is the pointer to the region of the removed element. + If the list is empty, the return value is `NULL'. */ +void *tcptrlistshift(TCPTRLIST *ptrlist); + + +/* Add an element at the specified location of a pointer list object. + `ptrlist' specifies the pointer list object. + `index' specifies the index of the new element. + `ptr' specifies the pointer to the region of the new element. + If `index' is equal to or more than the number of elements, this function has no effect. */ +void tcptrlistinsert(TCPTRLIST *ptrlist, int index_, void *ptr); + + +/* Remove an element at the specified location of a pointer list object. + `ptrlist' specifies the pointer list object. + `index' specifies the index of the element to be removed. + The return value is the pointer to the region of the removed element. + If `index' is equal to or more than the number of elements, no element is removed and the + return value is `NULL'. */ +void *tcptrlistremove(TCPTRLIST *ptrlist, int index_); + + +/* Overwrite an element at the specified location of a pointer list object. + `ptrlist' specifies the pointer list object. + `index' specifies the index of the element to be overwritten. + `ptr' specifies the pointer to the region of the new content. + If `index' is equal to or more than the number of elements, this function has no effect. */ +void tcptrlistover(TCPTRLIST *ptrlist, int index_, void *ptr); + + +/* Clear a pointer list object. + `ptrlist' specifies the pointer list object. + All elements are removed. */ +void tcptrlistclear(TCPTRLIST *ptrlist); + + + +/************************************************************************************************* + * bit operation utilities + *************************************************************************************************/ + + +typedef struct { /* type of structure for a bit stream object */ + uint8_t *sp; /* start pointer */ + uint8_t *cp; /* current pointer */ + int idx; /* bit index */ + int size; /* size of used region */ +} TCBITSTRM; + +typedef unsigned char TCBITMAP; /* type of a bit map object */ + + +/* Create a bitmap object. */ +#define TCBITMAPNEW(TC_num) \ + tccalloc(((TC_num) >> 3) + 1, 1); + + +/* Delete a bitmap object */ +#define TCBITMAPDEL(TC_bitmap) \ + do { \ + tcfree((TC_bitmap)); \ + } while(false); + + +/* Turn on a field of a bitmap object. */ +#define TCBITMAPON(TC_bitmap, TC_idx) \ + do { \ + (TC_bitmap)[(TC_idx)>>3] |= 0x1 << ((TC_idx) & 0x7); \ + } while(false); + + +/* Turn off a field of a bitmap object. */ +#define TCBITMAPOFF(TC_bitmap, TC_idx) \ + do { \ + (TC_bitmap)[(TC_idx)>>3] &= ~(0x1 << ((TC_idx) & 0x7)); \ + } while(false); + + +/* Check a field of a bitmap object. */ +#define TCBITMAPCHECK(TC_bitmap, TC_idx) \ + ((TC_bitmap)[(TC_idx)>>3] & 0x1 << ((TC_idx) & 0x7)) + + +/* Initialize a bit stream object as writer. */ +#define TCBITSTRMINITW(TC_bitstrm, TC_ptr) \ + do { \ + (TC_bitstrm).sp = (uint8_t *)(TC_ptr); \ + (TC_bitstrm).cp = (TC_bitstrm).sp; \ + *(TC_bitstrm).cp = 0; \ + (TC_bitstrm).idx = 3; \ + (TC_bitstrm).size = 1; \ + } while(false); + + +/* Concatenate a bit to a bit stream object. */ +#define TCBITSTRMCAT(TC_bitstrm, sign) \ + do { \ + if((TC_bitstrm).idx >= 8){ \ + *(++(TC_bitstrm).cp) = 0; \ + (TC_bitstrm).idx = 0; \ + (TC_bitstrm).size++; \ + } \ + *(TC_bitstrm).cp |= (sign << (TC_bitstrm).idx); \ + (TC_bitstrm).idx++; \ + } while(false); + + +/* Set the end mark to a bit stream object. */ +#define TCBITSTRMSETEND(TC_bitstrm) \ + do { \ + if((TC_bitstrm).idx >= 8){ \ + *(++(TC_bitstrm).cp) = 0; \ + (TC_bitstrm).idx = 0; \ + (TC_bitstrm).size++; \ + } \ + *(TC_bitstrm).sp |= (TC_bitstrm).idx & 7; \ + } while(false); + + +/* Get the size of the used region of a bit stream object. */ +#define TCBITSTRMSIZE(TC_bitstrm) \ + ((TC_bitstrm).size) + + +/* Initialize a bit stream object as reader. */ +#define TCBITSTRMINITR(TC_bitstrm, TC_ptr, TC_size) \ + do { \ + (TC_bitstrm).sp = (uint8_t *)(TC_ptr); \ + (TC_bitstrm).cp = (TC_bitstrm).sp; \ + (TC_bitstrm).idx = 3; \ + (TC_bitstrm).size = (TC_size); \ + } while(false); + + +/* Read a bit from a bit stream object. */ +#define TCBITSTRMREAD(TC_bitstrm, TC_sign) \ + do { \ + if((TC_bitstrm).idx >= 8){ \ + (TC_bitstrm).cp++; \ + (TC_bitstrm).idx = 0; \ + } \ + (TC_sign) = (*((TC_bitstrm).cp) & (1 << (TC_bitstrm).idx)) > 0; \ + (TC_bitstrm).idx++; \ + } while(false); + + +/* Get the number of bits of a bit stream object. */ +#define TCBITSTRMNUM(TC_bitstrm) \ + ((((TC_bitstrm).size - 1) << 3) + (*(TC_bitstrm).sp & 7) - 3) + + + +/************************************************************************************************* + * features for experts + *************************************************************************************************/ + + +#include + +#define _TC_VERSION "1.4.27" +#define _TC_LIBVER 818 +#define _TC_FORMATVER "1.0" + +enum { /* enumeration for error codes */ + TCESUCCESS, /* success */ + TCETHREAD, /* threading error */ + TCEINVALID, /* invalid operation */ + TCENOFILE, /* file not found */ + TCENOPERM, /* no permission */ + TCEMETA, /* invalid meta data */ + TCERHEAD, /* invalid record header */ + TCEOPEN, /* open error */ + TCECLOSE, /* close error */ + TCETRUNC, /* trunc error */ + TCESYNC, /* sync error */ + TCESTAT, /* stat error */ + TCESEEK, /* seek error */ + TCEREAD, /* read error */ + TCEWRITE, /* write error */ + TCEMMAP, /* mmap error */ + TCELOCK, /* lock error */ + TCEUNLINK, /* unlink error */ + TCERENAME, /* rename error */ + TCEMKDIR, /* mkdir error */ + TCERMDIR, /* rmdir error */ + TCEKEEP, /* existing record */ + TCENOREC, /* no record found */ + TCEMISC = 9999 /* miscellaneous error */ +}; + +enum { /* enumeration for database type */ + TCDBTHASH, /* hash table */ + TCDBTBTREE, /* B+ tree */ + TCDBTFIXED, /* fixed-length */ + TCDBTTABLE /* table */ +}; + + +/* Get the message string corresponding to an error code. + `ecode' specifies the error code. + The return value is the message string of the error code. */ +const char *tcerrmsg(int ecode); + + +/* Show error message on the standard error output and exit. + `message' specifies an error message. + This function does not return. */ +void *tcmyfatal(const char *message); + + +/* Allocate a large nullified region. + `size' specifies the size of the region. + The return value is the pointer to the allocated nullified region. + This function handles failure of memory allocation implicitly. The region of the return value + should be released with the function `tczerounmap' when it is no longer in use. */ +void *tczeromap(uint64_t size); + + +/* Free a large nullfied region. + `ptr' specifies the pointer to the region. */ +void tczerounmap(void *ptr); + + +/* Lock the global mutex object. + If successful, the return value is true, else, it is false. */ +bool tcglobalmutexlock(void); + + +/* Lock the global mutex object by shared locking. + If successful, the return value is true, else, it is false. */ +bool tcglobalmutexlockshared(void); + + +/* Unlock the global mutex object. + If successful, the return value is true, else, it is false. */ +bool tcglobalmutexunlock(void); + + +/* Lock the absolute path of a file. + `path' specifies the path of the file. + If successful, the return value is true, else, it is false. */ +bool tcpathlock(const char *path); + + +/* Unock the absolute path of a file. + `path' specifies the path of the file. + If successful, the return value is true, else, it is false. */ +bool tcpathunlock(const char *path); + + +/* Convert an integer to the string as binary numbers. + `num' specifies the integer. + `buf' specifies the pointer to the region into which the result string is written. The size + of the buffer should be equal to or more than 65 bytes. + `col' specifies the number of columns. If it is not more than 0, it depends on the integer. + `fc' specifies the filling character. + The return value is the length of the result string. */ +int tcnumtostrbin(uint64_t num, char *buf, int col, int fc); + + +/* Compare two keys by lexical order. + `aptr' specifies the pointer to the region of one key. + `asiz' specifies the size of the region of one key. + `bptr' specifies the pointer to the region of the other key. + `bsiz' specifies the size of the region of the other key. + `op' is ignored. + The return value is positive if the former is big, negative if the latter is big, 0 if both + are equivalent. */ +int tccmplexical(const char *aptr, int asiz, const char *bptr, int bsiz, void *op); + + +/* Compare two keys as decimal strings of real numbers. + `aptr' specifies the pointer to the region of one key. + `asiz' specifies the size of the region of one key. + `bptr' specifies the pointer to the region of the other key. + `bsiz' specifies the size of the region of the other key. + `op' is ignored. + The return value is positive if the former is big, negative if the latter is big, 0 if both + are equivalent. */ +int tccmpdecimal(const char *aptr, int asiz, const char *bptr, int bsiz, void *op); + + +/* Compare two keys as 32-bit integers in the native byte order. + `aptr' specifies the pointer to the region of one key. + `asiz' specifies the size of the region of one key. + `bptr' specifies the pointer to the region of the other key. + `bsiz' specifies the size of the region of the other key. + `op' is ignored. + The return value is positive if the former is big, negative if the latter is big, 0 if both + are equivalent. */ +int tccmpint32(const char *aptr, int asiz, const char *bptr, int bsiz, void *op); + + +/* Compare two keys as 64-bit integers in the native byte order. + `aptr' specifies the pointer to the region of one key. + `asiz' specifies the size of the region of one key. + `bptr' specifies the pointer to the region of the other key. + `bsiz' specifies the size of the region of the other key. + `op' is ignored. + The return value is positive if the former is big, negative if the latter is big, 0 if both + are equivalent. */ +int tccmpint64(const char *aptr, int asiz, const char *bptr, int bsiz, void *op); + + +/* Encode a serial object with BWT encoding. + `ptr' specifies the pointer to the region. + `size' specifies the size of the region. + `idxp' specifies the pointer to the variable into which the index of the original string in + the rotation array is assigned. + The return value is the pointer to the result object. + Because an additional zero code is appended at the end of the region of the return value, + the return value can be treated as a character string. Because the region of the return + value is allocated with the `malloc' call, it should be released with the `free' call when it + is no longer in use. */ +char *tcbwtencode(const char *ptr, int size, int *idxp); + + +/* Decode a serial object encoded with BWT encoding. + `ptr' specifies the pointer to the region. + `size' specifies the size of the region. + `idx' specifies the index of the original string in the rotation array is assigned. + The return value is the pointer to the result object. + Because an additional zero code is appended at the end of the region of the return value, + the return value can be treated as a character string. Because the region of the return + value is allocated with the `malloc' call, it should be released with the `free' call when it + is no longer in use. */ +char *tcbwtdecode(const char *ptr, int size, int idx); + + +/* Get the binary logarithm of an integer. + `num' specifies an integer. + The return value is the binary logarithm. */ +long tclog2l(long num); + + +/* Get the binary logarithm of a real number. + `num' specifies a real number. + The return value is the binary logarithm. */ +double tclog2d(double num); + + +/* Get the aligned offset of a file offset. + `off' specifies the file offset. + The return value is the aligned offset. */ +uint64_t tcpagealign(uint64_t off); + + +/* Print debug information with a formatted string as with `printf'. */ +#if __STDC_VERSION__ >= 199901L +#define TCDPRINTF(...) \ + do { \ + fprintf(stderr, "%s:%d:%s: ", __FILE__, __LINE__, __func__); \ + fprintf(stderr, __VA_ARGS__); \ + fprintf(stderr, "\n"); \ + } while(false); +#else +#define TCDPRINTF(TC_str) \ + do { \ + fprintf(stderr, "%s:%d:%s: %s\n", __FILE__, __LINE__, __func__, TC_str); \ + } while(false); +#endif + + +/* Print hexadecimal pattern of a binary region. */ +#define TCPRINTHEX(TC_ptr, TC_size) \ + do { \ + for(int TC_i = 0; TC_i < (TC_size); TC_i++){ \ + if(TC_i > 0) putchar(' '); \ + printf("%02X", ((unsigned char *)(TC_ptr))[TC_i]); \ + } \ + putchar('\n'); \ + } while(false); + + +/* Print an extensible string object. */ +#define TCPRINTXSTR(TC_xstr) \ + do { \ + fwrite(tcxstrptr((TC_xstr)), tcxstrsize((TC_xstr)), 1, stdout); \ + putchar('\n'); \ + } while(false); + + +/* Print all elements of a list object. */ +#define TCPRINTLIST(TC_list) \ + do { \ + for(int TC_i = 0; TC_i < tclistnum((TC_list)); TC_i++){ \ + int TC_size; \ + const char *TC_ptr = tclistval((TC_list), TC_i, &TC_size); \ + printf("%p\t", (void *)(TC_list)); \ + fwrite(TC_ptr, TC_size, 1, stdout); \ + putchar('\n'); \ + } \ + putchar('\n'); \ + } while(false); + + +/* Print all records of a list object. */ +#define TCPRINTMAP(TC_map) \ + do { \ + TCLIST *TC_keys = tcmapkeys((TC_map)); \ + for(int TC_i = 0; TC_i < tclistnum(TC_keys); TC_i++){ \ + int TC_ksiz; \ + const char *TC_kbuf = tclistval(TC_keys, TC_i, &TC_ksiz); \ + int TC_vsiz; \ + const char *TC_vbuf = tcmapget((TC_map), TC_kbuf, TC_ksiz, &TC_vsiz); \ + printf("%p\t", (void *)(TC_map)); \ + fwrite(TC_kbuf, TC_ksiz, 1, stdout); \ + putchar('\t'); \ + fwrite(TC_vbuf, TC_vsiz, 1, stdout); \ + putchar('\n'); \ + } \ + putchar('\n'); \ + tclistdel(TC_keys); \ + } while(false); + + +/* Alias of `tcmalloc'. */ +#if defined(_MYFASTEST) +#define TCMALLOC(TC_res, TC_size) \ + do { \ + (TC_res) = MYMALLOC(TC_size); \ + } while(false) +#else +#define TCMALLOC(TC_res, TC_size) \ + do { \ + if(!((TC_res) = MYMALLOC(TC_size))) tcmyfatal("out of memory"); \ + } while(false) +#endif + + +/* Alias of `tccalloc'. */ +#if defined(_MYFASTEST) +#define TCCALLOC(TC_res, TC_nmemb, TC_size) \ + do { \ + (TC_res) = MYCALLOC((TC_nmemb), (TC_size)); \ + } while(false) +#else +#define TCCALLOC(TC_res, TC_nmemb, TC_size) \ + do { \ + if(!((TC_res) = MYCALLOC((TC_nmemb), (TC_size)))) tcmyfatal("out of memory"); \ + } while(false) +#endif + + +/* Alias of `tcrealloc'. */ +#if defined(_MYFASTEST) +#define TCREALLOC(TC_res, TC_ptr, TC_size) \ + do { \ + (TC_res) = MYREALLOC((TC_ptr), (TC_size)); \ + } while(false) +#else +#define TCREALLOC(TC_res, TC_ptr, TC_size) \ + do { \ + if(!((TC_res) = MYREALLOC((TC_ptr), (TC_size)))) tcmyfatal("out of memory"); \ + } while(false) +#endif + + +/* Alias of `tcmemdup'. */ +#define TCMEMDUP(TC_res, TC_ptr, TC_size) \ + do { \ + TCMALLOC((TC_res), (TC_size) + 1); \ + memcpy((TC_res), (TC_ptr), (TC_size)); \ + (TC_res)[TC_size] = '\0'; \ + } while(false) + + +/* Alias of `tcfree'. */ +#define TCFREE(TC_ptr) \ + do { \ + MYFREE(TC_ptr); \ + } while(false) + + +/* Get the size of padding bytes for pointer alignment. */ +#define TCALIGNPAD(TC_hsiz) \ + (((TC_hsiz | ~-(int)sizeof(void *)) + 1) - TC_hsiz) + + +/* Alias of `tcxstrcat'. */ +#define TCXSTRCAT(TC_xstr, TC_ptr, TC_size) \ + do { \ + int TC_mysize = (TC_size); \ + int TC_nsize = (TC_xstr)->size + TC_mysize + 1; \ + if((TC_xstr)->asize < TC_nsize){ \ + while((TC_xstr)->asize < TC_nsize){ \ + (TC_xstr)->asize *= 2; \ + if((TC_xstr)->asize < TC_nsize) (TC_xstr)->asize = TC_nsize; \ + } \ + TCREALLOC((TC_xstr)->ptr, (TC_xstr)->ptr, (TC_xstr)->asize); \ + } \ + memcpy((TC_xstr)->ptr + (TC_xstr)->size, (TC_ptr), TC_mysize); \ + (TC_xstr)->size += TC_mysize; \ + (TC_xstr)->ptr[(TC_xstr)->size] = '\0'; \ + } while(false) + + +/* Alias of `tcxstrptr'. */ +#define TCXSTRPTR(TC_xstr) \ + ((TC_xstr)->ptr) + + +/* Alias of `tcxstrsize'. */ +#define TCXSTRSIZE(TC_xstr) \ + ((TC_xstr)->size) + + +/* Alias of `tclistnum'. */ +#define TCLISTNUM(TC_list) \ + ((TC_list)->num) + + +/* Alias of `tclistval' but not checking size. */ +#define TCLISTVAL(TC_ptr, TC_list, TC_index, TC_size) \ + do { \ + (TC_ptr) = (TC_list)->array[(TC_index)+(TC_list)->start].ptr; \ + (TC_size) = (TC_list)->array[(TC_index)+(TC_list)->start].size; \ + } while(false) + + +/* Alias of `tclistval' but not checking size and not using the third parameter. */ +#define TCLISTVALPTR(TC_list, TC_index) \ + ((void *)((TC_list)->array[(TC_index)+(TC_list)->start].ptr)) + + +/* Alias of `tclistval' but not checking size and returning the size of the value. */ +#define TCLISTVALSIZ(TC_list, TC_index) \ + ((TC_list)->array[(TC_index)+(TC_list)->start].size) + + +/* Alias of `tclistpush'. */ +#define TCLISTPUSH(TC_list, TC_ptr, TC_size) \ + do { \ + int TC_mysize = (TC_size); \ + int TC_index = (TC_list)->start + (TC_list)->num; \ + if(TC_index >= (TC_list)->anum){ \ + (TC_list)->anum += (TC_list)->num + 1; \ + TCREALLOC((TC_list)->array, (TC_list)->array, \ + (TC_list)->anum * sizeof((TC_list)->array[0])); \ + } \ + TCLISTDATUM *array = (TC_list)->array; \ + TCMALLOC(array[TC_index].ptr, TC_mysize + 1); \ + memcpy(array[TC_index].ptr, (TC_ptr), TC_mysize); \ + array[TC_index].ptr[TC_mysize] = '\0'; \ + array[TC_index].size = TC_mysize; \ + (TC_list)->num++; \ + } while(false) + + +/* Alias of `tclistinsert'. */ +#define TCLISTINSERT(TC_list, TC_index, TC_ptr, TC_size) \ + do { \ + int TC_myindex = (TC_index); \ + TC_myindex += (TC_list)->start; \ + if((TC_list)->start + (TC_list)->num >= (TC_list)->anum){ \ + (TC_list)->anum += (TC_list)->num + 1; \ + TCREALLOC((TC_list)->array, (TC_list)->array, \ + (TC_list)->anum * sizeof((TC_list)->array[0])); \ + } \ + memmove((TC_list)->array + TC_myindex + 1, (TC_list)->array + TC_myindex, \ + sizeof((TC_list)->array[0]) * ((TC_list)->start + (TC_list)->num - TC_myindex)); \ + TCMALLOC((TC_list)->array[TC_myindex].ptr, (TC_size) + 1); \ + memcpy((TC_list)->array[TC_myindex].ptr, (TC_ptr), (TC_size)); \ + (TC_list)->array[TC_myindex].ptr[(TC_size)] = '\0'; \ + (TC_list)->array[TC_myindex].size = (TC_size); \ + (TC_list)->num++; \ + } while(false) + + +/* Truncate a list object. */ +#define TCLISTTRUNC(TC_list, TC_num) \ + do { \ + while((TC_list)->num > (TC_num)){ \ + TCFREE((TC_list)->array[--(TC_list)->num].ptr); \ + } \ + } while(false) + + +/* Alias of `tcmaprnum'. */ +#define TCMAPRNUM(TC_map) \ + ((TC_map)->rnum) + + +/* Alias of `tcptrlistnum'. */ +#define TCPTRLISTNUM(TC_ptrlist) \ + ((TC_ptrlist)->num) + + +/* Alias of `tcptrlistval'. */ +#define TCPTRLISTVAL(TC_ptrlist, TC_index) \ + ((void *)((TC_ptrlist)->array[(TC_index)+(TC_ptrlist)->start])) + + +/* Alias of `tcptrlistpush'. */ +#define TCPTRLISTPUSH(TC_ptrlist, TC_ptr) \ + do { \ + int TC_index = (TC_ptrlist)->start + (TC_ptrlist)->num; \ + if(TC_index >= (TC_ptrlist)->anum){ \ + (TC_ptrlist)->anum += (TC_ptrlist)->num + 1; \ + TCREALLOC((TC_ptrlist)->array, (TC_ptrlist)->array, \ + (TC_ptrlist)->anum * sizeof((TC_ptrlist)->array[0])); \ + } \ + (TC_ptrlist)->array[TC_index] = (TC_ptr); \ + (TC_ptrlist)->num++; \ + } while(false) + + +/* Alias of `tcptrlistinsert'. */ +#define TCPTRLISTINSERT(TC_ptrlist, TC_index, TC_ptr) \ + do { \ + int TC_myindex = (TC_index); \ + TC_myindex += (TC_ptrlist)->start; \ + if((TC_ptrlist)->start + (TC_ptrlist)->num >= (TC_ptrlist)->anum){ \ + (TC_ptrlist)->anum += (TC_ptrlist)->num + 1; \ + TCREALLOC((TC_ptrlist)->array, (TC_ptrlist)->array, \ + (TC_ptrlist)->anum * sizeof((TC_ptrlist)->array[0])); \ + } \ + memmove((TC_ptrlist)->array + TC_myindex + 1, (TC_ptrlist)->array + TC_myindex, \ + sizeof((TC_ptrlist)->array[0]) * ((TC_ptrlist)->start + \ + (TC_ptrlist)->num - TC_myindex)); \ + (TC_ptrlist)->array[TC_myindex] = (TC_ptr); \ + (TC_ptrlist)->num++; \ + } while(false) + + +/* Truncate a pointer list object. */ +#define TCPTRLISTTRUNC(TC_ptrlist, TC_num) \ + do { \ + (TC_ptrlist)->num = (TC_num); \ + } while(false) + + +/* tricks for backward compatibility */ +#define BDBCMP TCCMP +#define tcbdbrange3 tcbdbfwmkeys2 +#define tcbdbcmplexical tccmplexical +#define tcbdbcmpdecimal tccmpdecimal +#define tcbdbcmpint32 tccmpint32 +#define tcbdbcmpint64 tccmpint64 +#define tctdbqryprocout tctdbqrysearchout +#define tctdbqrysetmax(TC_tdb, TC_max) \ + tctdbqrysetlimit((TC_tdb), (TC_max), 0) + + + +__TCUTIL_CLINKAGEEND +#endif /* duplication check */ + + +/* END OF FILE */ diff --git a/lib_protocol/Doxyfile b/lib_protocol/Doxyfile new file mode 100644 index 000000000..7b891ff78 --- /dev/null +++ b/lib_protocol/Doxyfile @@ -0,0 +1,1844 @@ +# Doxyfile 1.8.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 = protocol + +# 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 = 2.1.2_8 + +# 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 = + +# 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 = E:\work\online_help\acl\protocol + +# 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 = Chinese + +# 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 = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# 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. Note that you specify absolute paths here, but also +# relative paths, which will be relative from the directory where doxygen is +# started. + +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 = YES + +# 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 = NO + +# 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 = YES + +# 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 = YES + +# 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 + +# When enabled doxygen tries to link words that correspond to documented classes, +# or namespaces to their corresponding documentation. Such a link can be +# prevented in individual cases by by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. + +AUTOLINK_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 = NO + +# 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 = YES + +# 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. + +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 = *.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 + +# 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 = YES + +# 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 = NO + +# 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 left blank doxygen will +# generate a default style sheet. Note that it is recommended to use +# HTML_EXTRA_STYLESHEET instead of this one, as it is more robust and this +# tag will in the future become obsolete. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional +# user-defined cascading style sheet that is included after the standard +# style sheets created by doxygen. Using this option one can overrule +# certain style aspects. This is preferred over using HTML_STYLESHEET +# since it does not replace the standard style sheet and is therefor more +# robust against future updates. Doxygen will copy the style sheet file to +# the output directory. + +HTML_EXTRA_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 = YES + +# 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 = YES + +# 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://www.mathjax.org/mathjax + +# 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 = YES + +#--------------------------------------------------------------------------- +# 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 = NO + +# 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 = NO + +# 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 = YES + +# 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 = YES + +# 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 = YES + +# 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 = YES + +# 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/lib_protocol/Makefile b/lib_protocol/Makefile new file mode 100644 index 000000000..b80b0ada8 --- /dev/null +++ b/lib_protocol/Makefile @@ -0,0 +1,150 @@ +SHELL = /bin/sh +CC = gcc +#CC = g++ +CC = ${MY_ENV_CC} +AR = ar +ARFL = rv +#ARFL = cru +RANLIB = ranlib + +CFLAGS = -c -g -W -Wall -Wcast-qual -Wcast-align \ +-Waggregate-return -Wmissing-prototypes \ +-Wpointer-arith -Werror -Wshadow -O3 \ +-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO \ +-Wno-long-long \ +-fPIC + +#CFLAGS = -c -g -W -Wall -Wcast-qual -Wcast-align \ +#-Waggregate-return -Wmissing-prototypes \ +#-Wpointer-arith -Werror -Wshadow -O2 \ +#-D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO +########################################################### +#Check system: +# Linux, SunOS, Solaris, BSD variants, AIX, HP-UX +SYSLIB = +CHECKSYSRES = @echo "Unknow system type!";exit 1 +UNIXNAME = $(shell uname -sm) + +ifeq ($(CC),) + CC = gcc +endif + +ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes +endif + +# For FreeBSD +ifeq ($(findstring FreeBSD, $(UNIXNAME)), FreeBSD) + CFLAGS += -DFREEBSD -D_REENTRANT -pedantic +endif + +# For Darwin +ifeq ($(findstring Darwin, $(UNIXNAME)), Darwin) + CFLAGS += -DMACOSX -D_REENTRANT -pedantic +endif + +# For Linux +ifeq ($(findstring Linux, $(UNIXNAME)), Linux) + CFLAGS += -DLINUX2 -D_REENTRANT -pedantic +endif + +# For SunOS +ifeq ($(findstring SunOS, $(UNIXNAME)), SunOS) + ifeq ($(findstring 86, $(UNIXNAME)), 86) + SYSLIB = -lsocket -lnsl -lrt + endif + ifeq ($(findstring sun4u, $(UNIXNAME)), sun4u) + SYSLIB = -lsocket -lnsl -lrt + endif + CFLAGS += -DSUNOS5 -D_REENTRANT -pedantic +endif + +# For HP-UX +ifeq ($(findstring HP-UX, $(UNIXNAME)), HP-UX) + CFLAGS += -DHP_UX -DHPUX11 + PLAT_NAME=hp-ux +endif + +#Find system type. +ifneq ($(SYSPATH),) + CHECKSYSRES = @echo "System is $(shell uname -sm)" +endif +########################################################### + +OUT_PATH = . +OBJ_PATH_DST = $(OUT_PATH)/debug +LIB_PATH_DST = $(OUT_PATH)/lib + +BASE_PATH = . +INC_PATH_SRC = $(BASE_PATH)/include +SRC_PATH_SRC = $(BASE_PATH)/src + +INC_COMPILE = -I$(INC_PATH_SRC) -I./src +CFLAGS += $(INC_COMPILE) + +#Project's objs +BASE_SRC = $(wildcard $(SRC_PATH_SRC)/*.c) +HTTP_SRC = $(wildcard $(SRC_PATH_SRC)/http/*.c) +ICMP_SRC = $(wildcard $(SRC_PATH_SRC)/icmp/*.c) +SMTP_SRC = $(wildcard $(SRC_PATH_SRC)/smtp/*.c) +SOURCES_SRC = $(HTTP_SRC) $(ICMP_SRC) $(SMTP_SRC) + +BASE_OBJ = $(patsubst %.c, $(OBJ_PATH_DST)/%.o, $(notdir $(BASE_SRC))) +HTTP_OBJ = $(patsubst %.c, $(OBJ_PATH_DST)/%.o, $(notdir $(HTTP_SRC))) +ICMP_OBJ = $(patsubst %.c, $(OBJ_PATH_DST)/%.o, $(notdir $(ICMP_SRC))) +SMTP_OBJ = $(patsubst %.c, $(OBJ_PATH_DST)/%.o, $(notdir $(SMTP_SRC))) +OBJS_DST = $(BASE_OBJ) $(HTTP_OBJ) $(ICMP_OBJ) $(SMTP_OBJ) +########################################################### + +LIB_ACL_PATH = ../lib_acl +CFLAGS += -I $(LIB_ACL_PATH)/include + +########################################################### + +.PHONY = static shared clean +COMPILE = $(CC) $(CFLAGS) + +all: static shared + +$(shell mkdir -p $(OBJ_PATH_DST)) + +static: $(OBJS_DST) + $(AR) $(ARFL) $(LIB_PATH_DST)/lib_protocol.a $(OBJS_DST) + $(RANLIB) $(LIB_PATH_DST)/lib_protocol.a + +SHARED_FDFLAGS = -l_acl -lrt -lpthread +shared: $(OBJS_DST) + @echo 'creating $(LIB_PATH_DST)/lib_protocol.so' + @if test -n "$(rpath)"; then \ + $(CC) -shared -o $(LIB_PATH_DST)/lib_protocol.so $(OBJS_DST) $(SHARED_FDFLAGS) \ + -L$(rpath) -Wl,-rpath,$(rpath); \ + echo 'build $(LIB_PATH_DST)/lib_protocol.so ok!'; \ + else \ + echo 'skip build $(LIB_PATH_DST)/lib_protocol.so; usage: make shared rpath=xxx'; \ + fi + +$(OBJ_PATH_DST)/%.o: $(SRC_PATH_SRC)/%.c + $(COMPILE) $< -o $@ + +# http +$(OBJ_PATH_DST)/%.o: $(SRC_PATH_SRC)/http/%.c + $(COMPILE) $< -o $@ + +# icmp +$(OBJ_PATH_DST)/%.o: $(SRC_PATH_SRC)/icmp/%.c + $(COMPILE) $< -o $@ + +# smtp +$(OBJ_PATH_DST)/%.o: $(SRC_PATH_SRC)/smtp/%.c + $(COMPILE) $< -o $@ + +clean: + rm -f $(LIB_PATH_DST)/lib_protocol.a + rm -f $(LIB_PATH_DST)/lib_protocol.so + rm -f $(OBJS_DST) + +all_lib: $(OBJS_DST) + @(cd debug; ar x ../../lib_acl/lib/lib_acl.a) + $(AR) $(ARFL) $(LIB_PATH_DST)/lib_protocol.a debug/*.o + $(RANLIB) $(LIB_PATH_DST)/lib_protocol.a + @(cd debug; rm -f `ar -t ../../lib_acl/lib/lib_acl.a`) diff --git a/lib_protocol/ReadMe.txt b/lib_protocol/ReadMe.txt new file mode 100644 index 000000000..b318d6351 --- /dev/null +++ b/lib_protocol/ReadMe.txt @@ -0,0 +1,20 @@ +======================================================================== + 静态库 : protocol 项目概况 +======================================================================== + +应用程序向导已为您创建了这个 protocol 库项目。 +没有任何源文件被创建为项目的一部分。 + + +protocol.vcproj + 这是用应用程序向导生成的 VC++ 项目的主项目文件。 + 它包含有关生成此文件的 Visual C++ 版本的信息,以及 + 有关用应用程序向导选择的 + 平台、配置和项目功能的信息。 + +///////////////////////////////////////////////////////////////////////////// +其他注释: + +应用程序向导使用 "TODO:" 注释指示应添加或自定义的源代码部分。 + +///////////////////////////////////////////////////////////////////////////// diff --git a/lib_protocol/changes.txt b/lib_protocol/changes.txt new file mode 100644 index 000000000..69233f7b3 --- /dev/null +++ b/lib_protocol/changes.txt @@ -0,0 +1,233 @@ +240) 2013.7.30 +240.1) warning: http_hdr_req.c::http_hdr_req_new() 内部使用了线程局部变量, +当用 valgrind 检查时会报内存泄露警告,通过在主线程中将其释放去掉了此警告 + +239) 2013.7.23 +239.1) bugfix: http_hdr_req.c->http_hdr_req_create() 分离 URL 时有误 + +238) 2013.5.22 +238.1) performance: http 协议库提高了 HTTP 头的解析速度,由原来的每秒 5 万 +多次提升至每秒 17 万多次 +238.2) bugfix: http 协议库中 http_hdr_reset 函数判断 hh 参数是否合法时有误 + +237) 2013.3.24 +237.1) bugfix: http_hdr_req.c->__strip_url_path 解析有误导致第一个 / 丢失 + +236) 2012.12.30 +236.1) feature: smtp_client 模块中添加了 smtp_printf 函数,更方便发送数据 + +235) 2012.12.17 +235.1) feature: smtp 协议模块增加了 smtp_greet 函数,通过它可以直接调用 +smtp_helo/smtp_ehlo + +234) 2012.11.7 +334.1) feature: 增加了 smtp 协议的支持 + +233) 2012.7.10 +233.1) compile: 支持 VC2003 的预编译功能,从而使编译速度更快 + +233) 2012.4.29 +233.1) bugfix: 因为 acl_aio_request_timer 的时间单位由原来的秒改为微秒, +所以需要修改 icmp_chat_aio.c 中的时间单位 + +232) 2012.4.9 +232.1) 通过添加函数声明前缀:__attribute__((format(printf,3,4))) 来帮助 +编译器识别变参参数 + +231) 2011.6.21 +231.1) bugfix: http_util.c, 当 http_util_req_new 中的 http_hdr_req_host +返回 NULL 会导致 http_util_req_new 产生 core +231.2) http_hdr_req.c: http_hdr_req_create 改变了提取 Host 字段的方式 + +230) 2011.6.15 +230.1) http_hdr_req.c: http_hdr_req_create() 形成的 HTTP 请求格式为: +{METHOD} http://xxx.xxx.xxx/xxx?xxx HTTP/1.x +但该格式 tomcat 不能识别,所以现在改为: +{METHOD} /xxx?xxx HTTP/1.x + +229) 2011.4.18 +229.1) performance: http_hdr_req.c, http_hdr_res.c 增加线程局部内存池的缓存 +功能,可以重复使用 HTTP 头对象,只要在程序开始时调用一次 http_hdr_cache 即可 + +228) 2011.4.11 +228.1) performance: http_req_body_get_sync(), http_res_body_get_sync() 内部 +的 ctx 临时变量的生存周期原来是以流的生命周期为准,因为一个流的生命周期内会 +有多产请求或响应,所以会导致在 HTTP 长连接情况下,性能随着请求或响应次数的 +增加而下降,现在将 ctx 的生命周期改为以每一次请求或响应的会话的生命周期为准 + +227) 2010.11.23 +227.1) 修改了一些容易引起误解的函数返回值 +227.2) bugfix: http_hdr.c, http_hdr_entry_value 内部对于设置了 off 标志位的 +项应视为无效项 + +226) 2010.11.22 +226.1) bugfix: http_hdr_req.c +http_hdr_req_cookies_parse() 中的 cookies_table 判断方式错误 + +225) 2010.2.2 +225.1) http_chat_asyn.c: body_can_read() 中当回调返回 -1 时则也直接返回 -1 + +224) 2010.1.22 +224.1) performance: http_chat_async.c, 重新设计了异步读数据体的过程,大大提高 +了效率 + +223) 2010.1.11 +223.1) feature: 增加了 http_util.c, 可以非常方便地使用 http 协议库里的函数 +223.2) samples: 增加了 http/ 目录下的三个例子 + +222) 2010.1.8 +222.1) http_chat_async.c: 去掉了无用的回调函数 + +221) 2010.1.1 +221.1) 完善了HTTP协议异步读的接口,目前可以提供两种读HTTP头的方式, 将来可以 +对外提供控制接口以允许用户自行设置读HTTP头的方式 + +220) 2009.12.30 - 12.31 +220.1) http_chat_async.c: 重新设计了异步读数据体的框架, 使代码更加清晰明了, +同时更加灵活(采用注册勾子方式添加读的回调函数,原来只能注册一个读回调,现在 +采用最新的 acl_aio 的可以注册多个回调的方式,这样其它程序也可以注册自己的 +回调处理过程) +220.2) http_chat_async.c: 提供另一种异步读的模式 + +219) 2009.12.16 +219.1) lib_http_struct.h: 去掉了 HTTP_HDR_RES 中无用的成员字段 + +218) 2009.12.14 +218.1) http_hdr_req.c: 将 http_hdr_req_redirect 改名为 http_hdr_req_rewrite, +将 http_hdr_req_redirect2 改名为 http_hdr_req_rewrite2 +218.2) http_hdr_req.c: http_hdr_req_url() 中去掉了以 __thread 方式使用线程 +局部变量的方式,改为 acl_pthread_tls_get() 方式,这样当 lib_protocol 库被 +调用者动态加载时可以避免动态库加载时线程局部变量引用的问题 + +217) 2009.12.4 +217.1) feature: http_hdr.c 增加了 http_hdr_entry_replace2()/5 支持 HTTP 头里 +部分字符串的多次匹配替换操作 + +216) 2009.12.3 +216.1) http_hdr.c: 在分析 keep-alive 功能时增加了针对 chunked 传输的判断条件, +因为 HTTP1.1 在 chunked 传输模式下, 可以不必有 Connection: keep-alive 内容即 +可保持长连接, 所以如果没有 Connection: keep-alive 但属于 chunked 传输则允许 +保持长连接. + +215) 2009.11.26 +215.1) http: 整理了头文件, 从而便于使用 +215.2) http_hdr_req.c: 添加了函数 http_hdr_req_url()/1 用来取得完整的请求URL + +214) 2009.11.11 +214.1) bugfix: http_hdr_req.c: __add_request_item() 当出现重复键时会有内存泄露问题 + +213) 2009.11.10 +213.1) http_hdr_entry_value, http_hdr_entry 返回值去掉了 const 限制 + +212) 2009.6.22 +212.1) Makefile: 可以通过 make all_lib 合并 lib_acl.a 至 lib_protocol.a, +这样用户再使用 lib_protocol.a 时就不必再包含 lib_acl.a 了 + +211) 2009.4.9 +211.1) http 协议库中的通信部分进行了适合调整,使同步通信库与异步通信库中 +的有些变量定义的含义更加一致 +211.2) imcp 协议库中的 icmp_stat_host()/2 函数及结构 ICMP_HOST 由内部变 +为外部直接可用,从而方便应用的使用 +211.3) imcp 中的 ping 功能在时间精度上更细,原因是ACL库中win32平台下的 +gettimeofday()/2 的精度更细 + +210) 2009.4.8 +210.1) 使HTTP异步通信库更加易用;同时去掉了HTTP同步通信库中旧的通信模式 + +209) 2009.4.3 +209.1) 因为 aio 库的修改,所以对HTTP异步通信部分进行了修改 + +208) 2009.3.6 +208.1) feature: http_tmpl.c, 增加了 1xx, 2xx, 3xx 的信息提示功能 + +207) 2009.2.26 +207.1) 因为 lib_acl 中的 aio 模块增加了一些新的功能特性,故修改了 +http_chat_async.c 模块,使之处理异步IO问题更加灵活,而不干扰之前的IO设置 + +206) 2009.2.17 +206.1) feature: http/http_tmpl.c 增加了 http_tmpl_title()/1 函数便于根据 +HTTP响应码查找提示标题信息 + +205) 2009.1.5 +205.1) comment: icmp/ 的头文件中增加了 JavaDoc 方式的注释 +205.2) icmp: 修改个别接口的定义方式 + +19) 2009.1.1-2009.1.3 +19.1) 整理了工程目录(vc6, vc2003, vc2008):增加了目录 src/http, src/icmp, +include/http, include/icmp, 并增加了统一的协议支持头文件 lib_protocol.h +19.2) 添加了 ICMP 协议的实现,目前仅支持 ping 操作 + +18) 2008.12.4 +18.1) feature: http_chat_sync.c, 增加了读操作时的预缓冲功能,可以提高读的效率, +同时提供了控制接口,可以设置读时是否要采用预缓冲策略 + +17) 2008.11.21 +17.1) feature: http_hdr_req.c 增加了 http_hdr_req_redirect2() 接口,可以在 +原有的请求头进行重定向重写请求头 + +16) 2008.10.23 +16.1) feature: 添加了 http_hdr_req_range 及 http_hdr_res_range 两个分析偏移 +传输的函数分析 + +15) 2008.10.11 +15.1) 重新将HTTP协议的头文件的注释整理了一遍 + +14) 2008.10.10 +14.1) bugfix: 修复了有关sscanf 针对64位整数操作时的BUG,受影响的函数有 +http_chat_sync.c: chunked_hdr_get2(), http_chat_async: chunked_hdr_get_ready() + +13) 2008.10.9 +13.1) workaround: 重新整理了VC6、VC2003编译环境下的工程组织,将动态库以 +lib_http.dll, lib_http.lib, lib_http_d.dll, lib_http_d.lib 命名,将静态库以 +lib_http_vc6.lib, lib_http_vc6d.lib, lib_http_vc2003.lib, lib_http_vc2003d.lib +命名,其中动态库是用VC2003编译的,可以在VC6下使用 + +12) 2008.10.7 +12.1) bugfix: HTTP_HDR 结构中引入的两个成员(chat_ctx,chat_free_ctx_fn),当调用 +http_hdr_clone() 时,应该将这两个值赋空,否则会引起二次释放同一内存对象,造成存非 +法访问,当初之所以引入这两个成员变量,是为了避免在HTTP异步通信时通过ACL_VSTREAM 的 +acl_vstream_add_close_handle() 来回调释放函数;另外,现在HTTP同步通信中依然采用 +acl_vstream_add_close_handle() 模式来回调释放函数,将来需要改成与异步通信的释放模式 + +11) 2008.10.6 +11.1) compile bugfix: 在编译动态库时没有将http_hdr_res_get_sync引出 + +10) 2008.9.29 +10.1) feature: 修改了所有头文件的函数定义,添加了 HTTP_API 定义,允许 +以DLL方式引出, 可以方便其它编程语言使用 HTTP 库,当其它应用以DLL方式使用 +HTTP 库时,需要增加一个预定义宏:HTTP_DLL + +9) 2008.9 +9.1) 调整了 http_chat_async.c 中的部分接口 + +8) 2008.7.23 +8.1) 兼容性: 腾讯修改的APACHE存在问题,对于自己不认识的HTTP请求头字段采取超时关闭 +的方式,以前在关闭某一HTTP请求项时通常采用将第一个字母替换为 "_" 的方式(cresondo +的做法),看来这种方法对于QQ的服务器存在问题,所以现在采用另外的方法来禁掉某一请求项 + +7) 2008.7.17 +7.1) safety: http_chat_async.c 中增加了 ctx_nested_check() 函数,以避免关闭或超时 +回调函数被嵌套调用 + +6) 2008.3.19 +6.1) feature: 支持 content-length 大于 unsigned int 最大值的情况 + +5) 2008.3.10 +5.1) feature: http_hdr_req.c, 增加了http_hdr_req_redirect,以便应用进行重定向操作 + +4) 2008.3.6 +4.1) bugfix: http_hdr_req.c, 在由客户端的请求头中获取 Host 字段时,在请求方法为 +CONNECT方法时,如果没有HOST字段,则取不到HOST信息,增加一条功能:此时可以尝试 +在 CONNECT ip[domain]:port HTTP/1.1 中由 ip[domain] 来填充HOST信息 + +url行且 +3) 2008.3.2 +3.1) features: http_chat_sync.c, 增加了一组同步获取服务器返回数据的函数接口 + +2) 2008.2.13 +2.1) features: add http_hdr_clone() in http_hdr.c, add http_hdr_res_clone() +in http_hdr_res.c, add http_hdr_req_clone() in http_hdr_req.c + +1) 2008.1.8 +1.1) bugfix: http_hdr_req.c->__add_request_item,__add_cookie_item,中对变量对 +的存储原来未处理重复变量名的情况,会导致内存泄漏。 diff --git a/lib_protocol/include/http/lib_http.h b/lib_protocol/include/http/lib_http.h new file mode 100644 index 000000000..c1437b0a3 --- /dev/null +++ b/lib_protocol/include/http/lib_http.h @@ -0,0 +1,731 @@ +#ifndef __LIB_HTTP_INCLUDE_H__ +#define __LIB_HTTP_INCLUDE_H__ + +#include "lib_http_status.h" +#include "lib_http_struct.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*---------------------------- 通用 HTTP 头操作函数 --------------------------*/ +/* in http_hdr.c */ + +/** + * 生成一个通用HTTP协议头的结构对象 + * @param size {size_t} 所需分配内存大小, 等于 HTTP_HDR_REQ 或 HTTP_HDR_RES 的尺寸 + * @return {HTTP_HDR*} !NULL: 返回一个HTTP_HDR结构指针; NULL: 出错. + */ +HTTP_API HTTP_HDR *http_hdr_new(size_t size); + +/** + * 从源HTTP通用头拷贝内部成员变量至一个新的HTTP通用头结构中 + * @param src {const HTTP_HDR*} 源HTTP通用头对象,不能为空 + * @param dst {HTTP_HDR*} 目的HTTP通用头对象,不能为空 + */ +HTTP_API void http_hdr_clone(const HTTP_HDR *src, HTTP_HDR *dst); + +/** + * 释放一个HTTP_HDR结构内存 + * @param hh {HTTP_HDR*} 类型的数据指针,不能为空 + */ +HTTP_API void http_hdr_free(HTTP_HDR *hh); + +/** + * 重置一个HTTP通用头的状态,释放内部成员变量,主要用于keep-alive的长连接多次请求 + * @param hh {HTTP_HDR*} HTTP通用头类型的数据指针,不能为空 + */ +HTTP_API void http_hdr_reset(HTTP_HDR *hh); + +/** + * 向 HTTP_HDR 头中增加一个条目 + * @param hh {HTTP_HDR*} 通用头类型的数据指针,不能为空 + * @param entry {HTTP_HDR_ENTRY*} HTTP头条目结构指针, 不能为空 + */ +HTTP_API void http_hdr_append_entry(HTTP_HDR *hh, HTTP_HDR_ENTRY *entry); + +/** + * 分析所给数据, 解析出协议, 主/次版本号,并将结果存在通用HTTP头结构内 + * @param hh {HTTP_HDR*} 类型的数据指针,不能为空 + * @param data {const char*} 数据格式须为: HTTP/1.0 + * @return {int} 0: OK; < 0: error. + */ +HTTP_API int http_hdr_parse_version(HTTP_HDR *hh, const char *data); + +/** + * 分析所有的通用HTTP协议头并存储在 hh 结构中 + * @param hh {HTTP_HDR*} 通用HTTP头类型的数据指针,不能为空 + * @return {int} 0: ok; < 0: error + */ +HTTP_API int http_hdr_parse(HTTP_HDR *hh); + +/** + * 由传入的 name, value 对产生一个 HTTP_HDR_ENTRY 对象 + * @param name {const char*} 变量名 + * @param value {const char*} 变量值 + * @return {HTTP_HDR_ENTRY*} 如果为空则是因为输入参数有误 + */ +HTTP_API HTTP_HDR_ENTRY *http_hdr_entry_build(const char *name, const char *value); + +/** + * 根据传入的一行数据进行分析, 生成一个 HTTP_HDR_ENTRY + * @param data {const char*} HTTP 协议头中的一行数据, 如: Content-Length: 200 + * @return {HTTP_HDR_ENTRY*} !NULL: ok; NULL: err. + */ +HTTP_API HTTP_HDR_ENTRY *http_hdr_entry_new(const char *data); +HTTP_API HTTP_HDR_ENTRY *http_hdr_entry_head(char *data); +HTTP_API HTTP_HDR_ENTRY *http_hdr_entry_new2(char *data); + +/** + * 获取一个 HTTP_HDR_ENTRY 条目 + * @param hh {HTTP_HDR*} 通用HTTP头类型的数据指针,不能为空 + * @param name {const char*} 该 HTTP_HDR_ENTRY 条目的标识名, 不能为空. 如: Content-Length. + * @return ret {HTTP_HDR_ENTRY *} ret != NULL: ok; ret == NULL: 出错或不存在. + */ +HTTP_API HTTP_HDR_ENTRY *http_hdr_entry(const HTTP_HDR *hh, const char *name); + +/** + * 获取HTTP协议头里某个实体头的变量值,如某个实体头为:Host: www.test.com + * 要获得 Host 变量的值,调用该函数后便可以取得 www.test.com + * @param hh {HTTP_HDR*} 通用HTTP头类型的数据指针,不能为空 + * @param name {const char*} 该 HTTP_HDR_ENTRY 条目的标识名, 不能为空. 如: Content-Length + * @return ret {char*} ret != NULL: ok; ret == NULL: 出错或不存在. + */ +HTTP_API char *http_hdr_entry_value(const HTTP_HDR *hh, const char *name); + +/** + * 将 HTTP 头中的某个字段进行替换, 该功能起初主要是为了实现 keep-alive 字段的替换 + * @param hh {HTTP_HDR*} 通用HTTP头类型的数据指针,不能为空 + * @param name {const char*} 该 HTTP_HDR_ENTRY 条目的标识名, 不能为空. 如: Content-Length + * @param value {const char*} 该 name 字段所对应的新的值 + * @param force {int} 如果所替换的字段在原始HTTP请求里不存在, 则强行产生新的 entry 字段并 + * 填至该请求头, 当该值为非0值时进行强行添加, 否则若该name在请求里不存在则不添加. + * @return {int} 0 表示替换成功; < 0 表示输入参数出错或该 name 字段在该HTTP请求头里不存在 + */ +HTTP_API int http_hdr_entry_replace(HTTP_HDR *hh, const char *name, const char *value, int force); + +/** + * 将 HTTP 头中的某个字段中包含某个字符串的源字符串进行替换, 可以支持多次匹配替换 + * @param hh {HTTP_HDR*} 通用HTTP头类型的数据指针,不能为空 + * @param name {const char*} 该 HTTP_HDR_ENTRY 条目的标识名, 不能为空. 如: Cookie + * @param from {const char*} 替换时的源字符串 + * @param to {const char*} 替换时的目标字符串 + * @param ignore_case {int} 在查找替换时是否忽略源字符串的大小写 + * @return {int} 0: 表示未做任何替换, > 0: 表示替换的次数 + */ +HTTP_API int http_hdr_entry_replace2(HTTP_HDR *hh, const char *name, + const char *from, const char *to, int ignore_case); + +/** + * 禁止HTTP协议头中的某项 + * @param hh {HTTP_HDR* } 通用HTTP头类型的数据指针,不能为空 + * @param name {const char*} 该 HTTP_HDR_ENTRY 条目的标识名, 不能为空. 如: Content-Length + */ +HTTP_API void http_hdr_entry_off(HTTP_HDR *hh, const char *name); + +/** + * 调试输出HTTP协议头部数据,调试类接口 + * @param hh {HTTP_HDR*} 通用HTTP头类型的数据指针,不能为空 + * @param msg {const char*} 用户希望与头部信息一起输出的自定义信息, 可以为空 + */ +HTTP_API void http_hdr_print(const HTTP_HDR *hh, const char *msg); + +/** + * 调试输出HTTP协议头部数据,调试类接口 + * @param fp {ACL_VSTREAM*} 某个流指针,输出结果将会定向至该数据流(可以为网络流或文件流) + * @param hh {HTTP_HDR*} 通用HTTP头类型的数据指针,不能为空 + * @param msg {const char*} 用户希望与头部信息一起输出的自定义信息, 可以为空 +*/ +HTTP_API void http_hdr_fprint(ACL_VSTREAM *fp, const HTTP_HDR *hh, const char *msg); + +/*-------------------------------- HTTP 请求头操作函数 -----------------------*/ +/* in http_hdr_req.c */ + +/** + * 分配一个请求的HTTP协议头对象 + * @return {HTTP_HDR_REQ*} HTTP请求头对象 + */ +HTTP_API HTTP_HDR_REQ *http_hdr_req_new(void); + +/** + * 根据请求的URL,请求的方法,HTTP版本创建一个HTTP请求头对象 + * @param url {const char*} 请求的URL,必须是完整的URL,如: + * http://www.test.com/path/proc?name=value + * http://www.test.com/path/proc + * http://www.test.com/ + * @param method {const char*} HTTP请求方法,必须为如下之一: + * GET, POST, CONNECT, HEAD, 且要注意必须都为大写 + * @param version {const char *} HTTP版本,必须为如下之一: + * HTTP/1.0, HTTP/1.1 + * @return {HTTP_HDR_REQ*} HTTP请求头对象 + */ +HTTP_API HTTP_HDR_REQ *http_hdr_req_create(const char *url, + const char *method, const char *version); + +/** + * 克隆一个HTTP请求头对象,但不复制其中的 chat_ctx, chat_free_ctx_fn + * 两个成员变量 + * @param hdr_req {const HTTP_HDR_REQ*} HTTP请求头对象 + * @return {HTTP_HDR_REQ*} 克隆的HTTP请求头对象 + */ +HTTP_API HTTP_HDR_REQ *http_hdr_req_clone(const HTTP_HDR_REQ* hdr_req); + +/** + * 根据上次HTTP请求头内容及重定向的URL产生一个新的HTTP请求头 + * @param hh {const HTTP_HDR_REQ*} 上次的HTTP请求头对象 + * @param url {const char *} 重定向的URL,如果有 http[s]:// 前缀,则认为 + * 是完整的URL,新的 Host 字段将由该URL中提取,否则则继承源HTTP请求头中 + * 的 Host 字段 + * @return {HTTP_HDR_REQ*} 新产生的重定向的HTTP请求头 + */ +HTTP_API HTTP_HDR_REQ *http_hdr_req_rewrite(const HTTP_HDR_REQ *hh, const char *url); + +/** + * 根据HTTP请求头内容及重定向的URL重新设置该HTTP请求头的信息 + * @param hh {const HTTP_HDR_REQ*} 上次的HTTP请求头对象 + * @param url {const char *} 重定向的URL,如果有 http[s]:// 前缀,则认为 + * 是完整的URL,新的 Host 字段将由该URL中提取,否则则继承源HTTP请求头中 + * 的 Host 字段 + * @return {int} 0: ok; < 0: error + */ +HTTP_API int http_hdr_req_rewrite2(HTTP_HDR_REQ *hh, const char *url); + +/** + * 释放HTTP请求头对象 + * @param hh {HTTP_HDR_REQ*} HTTP请求头对象 + */ +HTTP_API void http_hdr_req_free(HTTP_HDR_REQ *hh); + +/** + * 将HTTP请求头对象的成员变量释放并重新初始化 + * @param hh {HTTP_HDR_REQ*} HTTP请求头对象 + */ +HTTP_API void http_hdr_req_reset(HTTP_HDR_REQ *hh); + +/** + * 分析HTTP协议头的cookies + * @param hh {HTTP_HDR_REQ*} HTTP请求头类型的数据指针,不能为空 + * @return {int} 0: ok; -1: err. + */ +HTTP_API int http_hdr_req_cookies_parse(HTTP_HDR_REQ *hh); + +/** + * 分析HTTP请求首行数据(如: GET /cgi-bin/test.cgi?name=value&name2=value2 HTTP/1.0) + * 请求的方法(GET)-->hdr_request_method + * URL数据分析结果(name=value)-->hdr_request_table + * HTTP协议版本号(HTTP/1.0)-->hdr_request_proto + * URL数据中的路径部分(/cgi-bin/test.cgi)-->hdr_request_url + * @param hh {HTTP_HDR_REQ*} HTTP请求头类型的数据指针,不能为空 + * @return {int} 0: ok; -1: err. + */ +HTTP_API int http_hdr_req_line_parse(HTTP_HDR_REQ *hh); + +/** + * 分析HTTP请求头协议数据, 其内部会调用 http_hdr_req_line_parse, http_hdr_req_cookies_parse + * @param hh {HTTP_HDR_REQ*} HTTP请求头类型的数据指针,不能为空 + * @return {int} 0: ok; -1: err. + */ +HTTP_API int http_hdr_req_parse(HTTP_HDR_REQ *hh); + +/** + * 分析HTTP请求头协议数据, 其内部会调用 http_hdr_req_line_parse, http_hdr_req_cookies_parse + * 如果 parse_params 非 0 则分析HTTP请求 url 中的参数部分; 如果 parse_cookie 非 0 则分析 + * HTTP请求中的 cookie 内容 + * @param hh {HTTP_HDR_REQ*} HTTP请求头类型的数据指针,不能为空 + * @param parse_params {int} 是否分析请求 url 中的参数部分 + * @param parse_cookie {int} 是否分析请求中的 cookie 内容 + * @return {int} 0: ok; -1: err. + */ +HTTP_API int http_hdr_req_parse3(HTTP_HDR_REQ *hh, int parse_params, int parse_cookie); + +/** + * 从HTTP请求头中获得某个cookie值 + * @param hh {HTTP_HDR_REQ*) HTTP请求头类型的数据指针,不能为空 + * @param name {const char*} 某个cookie的变量名, 不能为空 + * @return {const char*} !NULL: 该返回值即为所要求的cookie; NULL: 出错或所要求的cookie不存在 + */ +HTTP_API const char *http_hdr_req_cookie_get(HTTP_HDR_REQ *hh, const char *name); + +/** + * 从HTTP请求头中取得HTTP请求的方法, 如: POST, GET, CONNECT + * @param hh {HTTP_HDR_REQ*} HTTP请求头类型的数据指针,不能为空 + * @return {const char*} 返回请示方法. NULL: error; !NULL: OK. + */ +HTTP_API const char *http_hdr_req_method(HTTP_HDR_REQ *hh); + +/** + * 从HTTP请求头中获取请求URL中某个请求字段的数据, + * 如取: /cgi-bin/test.cgi?n1=v1&n2=v2 中的 n2的值v2 + * @param hh {HTTP_HDR_REQ*} HTTP请求头类型的数据指针,不能为空 + * @param name {const char*} 请求参数中的变量名 + * @return {const char*} !NULL: ok, 返回变量值的内存指针; NULL: 出错,或请求的变量名不存在. + */ +HTTP_API const char *http_hdr_req_param(HTTP_HDR_REQ *hh, const char *name); + +/** + * 从HTTP请求头中获取请求行中的访问路径部分, 不包含主机名但包含参数. + * 如原请求行数据为: + * GET /cgi-bin/test.cgi?n1=v1&n2=v2 HTTP/1.1 + * or + * GET http://www.test.com[:80]/cgi-bin/test.cgi?n1=v1&n2=v2 HTTP/1.1 + * 则分析后的结果数据为: + * /cgi-bin/test.cgi?n1=v1&n2=v2 + * @param hh {HTTP_HDR_REQ*} HTTP请求头类型的数据指针,不能为空 + * @return {const char*} 请示的URL. !NULL: OK; NULL: error. + */ +HTTP_API const char *http_hdr_req_url_part(HTTP_HDR_REQ *hh); + +/** + * 从HTTP请求头中获取请求行中的访问路径部分, 不包含主机名及参数. + * 如原请求行数据为: + * GET /cgi-bin/test.cgi?n1=v1&n2=v2 HTTP/1.1 + * or + * GET http://www.test.com[:80]/cgi-bin/test.cgi?n1=v1&n2=v2 HTTP/1.1 + * 则分析后的结果数据为: + * /cgi-bin/test.cgi + * @param hh {HTTP_HDR_REQ*} HTTP请求头类型的数据指针,不能为空 + * @return {const char*} 请示的URL. !NULL: OK; NULL: error. + */ +HTTP_API const char *http_hdr_req_url_path(HTTP_HDR_REQ *hh); + +/** + * 从HTTP请求协议头中获得服务器的主机IP或域名,格式为:IP|domain[:PORT] + * 如: 192.168.0.22:80, or www.test.com:8088 + * @param hh {HTTP_HDR_REQ*} HTTP请求头类型的数据指针,不能为空 + * @return {const char*} 返回用户请示的主机名. !NULL: ok; NULL: error. + */ +HTTP_API const char *http_hdr_req_host(HTTP_HDR_REQ *hh); + +/** + * 从HTTP请求头协议中获得完整的URL请求字符串 + * 如原HTTP请求头为: + * GET /cgi-bin/test.cgi?n1=v1&n2=v2 HTTP/1.1 + * HOST: www.test.com + * 则经该函数后则返回: + * http://www.test.com/cgi-bin/test.cgi?n1=v1&n2=v2 + * @param hh {HTTP_HDR_REQ*} HTTP请求头类型的数据指针,不能为空 + * @return {const char*} 请示的URL. !NULL: OK; NULL: error. + * @example: + * void test(HTTP_HDR_REQ *hh) + * { + * const char *url = http_hdr_req_url(hh); + * printf(">>> url: %s\r\n", url ? url : "null"); + * } + * 注意, 因为 http_hdr_req_url 内部使用到了一个线程局部静态变量内存区, 所以 + * 不可如下使用,否则会使返回的数据发生重叠. + * void test(HTTP_HDR_REQ *hh1, HTTP_HDR_REQ *hh2) + * { + * const char *url1 = http_hdr_req_url(hh1); + * const char *url2 = http_hdr_req_url(hh2); + * printf(">>> url1: %s, url2: %s\n", url1, url2); + * } + * 因为 url1, url2 实际上都是指向的同一内存区, 所以最终的结果将是 url1, url2 + * 内容相同. 如遇此类情形, 应该如下操作: + * void test(HTTP_HDR_REQ *hh1, HTTP_HDR_REQ *hh2) + * { + * const char *ptr; + * static char dummy[1]; + * char *url1 = dummy, *url2 = dummy; + * ptr = http_hdr_req_url(hh1); + * if (ptr) + * url1 = acl_mystrdup(ptr); + * ptr = http_hdr_req_url(hh2); + * if (ptr) + * url2 = acl_mystrdup(ptr); + * printf(">>> url1: %s, url2: %s\n", url1, url2); + * if (url1 != dummy) + * acl_myfree(url1); + * if (url2 != dummy) + * acl_myfree(url2); + * } + */ +HTTP_API const char *http_hdr_req_url(HTTP_HDR_REQ *hh); + +/** + * 分析HTTP请求头中的 Range 字段 + * @param hdr_req {HTTP_HDR_REQ*} 请求HTTP协议头, 不能为空 + * @param range_from {http_off_t*} 存储偏移起始位置 + * @param range_to {http_off_t*} 存储偏移结束位置 + * 注: * {range_from}, {range_to} 下标从0开始 + * 请求的 Range 格式: + * Range: bytes={range_from}-, bytes={range_from}-{range_to} + */ +HTTP_API int http_hdr_req_range(HTTP_HDR_REQ *hdr_req, http_off_t *range_from, + http_off_t *range_to); + +/*---------------------------- HTTP 响应头操作函数 ---------------------------*/ +/* in http_hdr_res.c */ + +/** + * 分析HTTP响应头中的状态行 + *@param hh {HTTP_HDR_RES*} HTTP响应头类型的数据指针,不能为空 + *@param dbuf {const char*} 状态行数据, 如: HTTP/1.0 200 OK,不能为空 + *@return {int} 0: ok; < 0: error,分析结果存储在 hh 结构中 + */ +HTTP_API int http_hdr_res_status_parse(HTTP_HDR_RES *hh, const char *dbuf); + +/** + * 创建一个新的HTTP响应头 + * @return {HTTP_HDR_RES*} + */ +HTTP_API HTTP_HDR_RES *http_hdr_res_new(void); + +/** + * 克隆一个HTTP响应头 + * @param hdr_res {const HTTP_HDR_RES*} 源HTTP响应头 + * @return {HTTP_HDR_RES *} 新产生的HTTP响应头 + */ +HTTP_API HTTP_HDR_RES *http_hdr_res_clone(const HTTP_HDR_RES *hdr_res); + +/** + * 释放一个HTTP响应头 + * @param hh {HTTP_HDR_RES*} HTTP响应头 + */ +HTTP_API void http_hdr_res_free(HTTP_HDR_RES *hh); + +/** + * 向HTTP响应头重新初始化并释放其中的成员变量 + * @param hh {HTTP_HDR_RES*} HTTP响应头 + */ +HTTP_API void http_hdr_res_reset(HTTP_HDR_RES *hh); + +/** + * 分析HTTP响应头里的数据,并存储分析结果 + * @param hdr_res {HTTP_HDR_RES*} HTTP响应头 + */ +HTTP_API int http_hdr_res_parse(HTTP_HDR_RES *hdr_res); + +/** + * 分析HTTP响应头中的 Range 字段 + * @param hdr_res {HTTP_HDR_RES*} 响应HTTP协议头, 不能为空 + * @param range_from {http_off_t*} 存储偏移起始位置, 不能为空 + * @param range_to {http_off_t*} 存储偏移结束位置, 不能为空 + * @param total_length {http_off_t*} 整个数据文件的总长度, 可为空 + * 注: * {range_from}, {range_to} 下标从0开始 + * 响应的 Range 格式: + * Content-Range: bytes {range_from}-{range_to}/{total_length} + */ +HTTP_API int http_hdr_res_range(HTTP_HDR_RES *hdr_res, http_off_t *range_from, + http_off_t *range_to, http_off_t *total_length); + +/* in http_rfc1123.c */ + +/** + * 将时间值转换成RFC1123所要求的格式 + * @param buf {char*} 存储空间 + * @param size {size_t} buf 的空间大小 + * @param t {time_t} 时间值 + */ +HTTP_API const char *http_mkrfc1123(char *buf, size_t size, time_t t); + +/*----------------------- HTTP 异步读操作函数 --------------------------------*/ +/* in http_chat_async.c */ + +/** + * 异步获取一个HTTP REQUEST协议头,数据结果存储在hdr中, 当取得一个完整的HTTP头或 + * 出错时调用用户的注册函数 notify + * @param hdr {HTTP_HDR_REQ*} HTTP请求头类型结构指针,不能为空 + * @param astream {ACL_ASTREAM*} 与客户端连接的数据流, 不能为空 + * @param notify {HTTP_HDR_NOTIFY} 当HTTP协议头读完或出错时调用的用户的注册函数 + * @param arg {void*} notify 调用时的一个参数 + * @param timeout {int} 接收数据过程中的读超时时间 + */ +HTTP_API void http_hdr_req_get_async(HTTP_HDR_REQ *hdr, ACL_ASTREAM *astream, + HTTP_HDR_NOTIFY notify, void *arg, int timeout); + +/** + * 异步获取一个HTTP RESPOND协议头,数据结果存储在hdr中, 当取得一个完整的HTTP头或 + * 出错时调用用户的注册函数 notify + * @param hdr {HTTP_HDR_REQ*} HTTP响应头类型结构指针,不能为空 + * @param astream {ACL_ASTREAM*} 与服务端连接的数据流, 不能为空 + * @param notify {HTTP_HDR_NOTIFY} 当HTTP协议头读完或出错时调用的用户的注册函数 + * @param arg {void*} notify 调用时的一个参数 + * @param timeout {int} 接收数据过程中的读超时时间 + */ +HTTP_API void http_hdr_res_get_async(HTTP_HDR_RES *hdr, ACL_ASTREAM *astream, + HTTP_HDR_NOTIFY notify, void *arg, int timeout); + +/** + * 异步从客户端读取请求的BODY协议体, 在接收过程中边接收连回调用户的 notify + * 回调函数, 如果 notify 返回小于 0 的值, 则认为出错且不再继续接收数据 + * @param request {HTTP_REQ*} HTTP请求体类型指针, 不能为空, 且 request->hdr 为空 + * @param astream {ACL_ASTREAM*} 与客户端连接的数据流, 不能为空 + * @param notify {HTTP_BODY_NOTIFY} 接收客户端数据过程中回调的用户的注册函数 + * @param arg {void*} notify 调用时的一个参数 + * @param timeout {int} 接收数据过程中的读超时时间 + */ +HTTP_API void http_req_body_get_async(HTTP_REQ *request, ACL_ASTREAM *astream, + HTTP_BODY_NOTIFY notify, void *arg, int timeout); +/* + * 异步从服务器端读取响应数据的BODY协议体, 在接收过程中连接收连回调用户的 + * notify 回调函数, 如果 notify 返回小于 0 的值, 则认为出错且不再继续接收数据 + * @param respond {HTTP_RES*} HTTP响应体类型指针, 不能为空,且 respond->hdr 不为空 + * @param astream {ACL_ASTREAM*} 与服务端连接的数据流, 不能为空 + * @param notify {HTTP_BODY_NOTIFY} 接收服务端数据过程中回调的用户的注册函数 + * @param arg {void*} notify 调用时的一个参数 + * @param timeout {int} 接收数据过程中的读超时时间 + */ +HTTP_API void http_res_body_get_async(HTTP_RES *respond, ACL_ASTREAM *astream, + HTTP_BODY_NOTIFY notify, void *arg, int timeout); + +/*----------------------- HTTP 同步读操作函数 --------------------------------*/ +/* in http_chat_sync.c */ + +/** +* 同步获取一个HTTP REQUEST协议头,数据结果存储在hdr中, 当取得一个完整的HTTP头或 +* 出错时调用用户的注册函数 notify +* @param hdr {HTTP_HDR_REQ*} HTTP请求头类型结构指针,不能为空 +* @param stream {ACL_VSTREAM*} 与客户端连接的数据流, 不能为空 +* @param timeout {int} 接收数据过程中的读超时时间 +* @return {int} 0: 成功; < 0: 失败 +*/ +HTTP_API int http_hdr_req_get_sync(HTTP_HDR_REQ *hdr, + ACL_VSTREAM *stream, int timeout); + +/** + * 同步获取一个HTTP RESPOND协议头,数据结果存储在hdr中, 当取得一个完整的HTTP头或 + * 出错时调用用户的注册函数 notify + * @param hdr {HTTP_HDR_REQ*} HTTP响应头类型结构指针,不能为空 + * @param stream {ACL_VSTREAM*} 与服务端连接的数据流, 不能为空 + * @param timeout {int} 接收数据过程中的读超时时间 + * @return {int} 0: 成功; < 0: 失败 + */ +HTTP_API int http_hdr_res_get_sync(HTTP_HDR_RES *hdr, + ACL_VSTREAM *stream, int timeout); + +/** + * 同步从客户端读取请求的BODY协议体 + * @param request {HTTP_REQ*} HTTP请求体类型指针, 不能为空, 且 request->hdr 为空 + * @param stream {ACL_VSTREAM*} 与客户端连接的数据流, 不能为空 + * @param buf {void *} 存储结果的内容空间 + * @param size {int} buf 的空间大小 + * @return ret {http_off_t} 本次读到的HTTP请求体的内容 + * 0: 表示读完了HTTP数据体内容,但并不代表数据流已经关闭; + * < 0: 表示读出错,流关闭或出错; + * > 0: 表示未读完,目前读到ret 个字节的数据 + */ +HTTP_API http_off_t http_req_body_get_sync(HTTP_REQ *request, ACL_VSTREAM *stream, + void *buf, int size); +#define http_req_body_get_sync2 http_req_body_get_sync + +/** + * 同步从服务端读取响应的BODY协议体 + * @param respond {HTTP_RES*} HTTP响应体类型指针, 不能为空, 且 respond->hdr 为空 + * @param stream {ACL_VSTREAM*} 与客户端连接的数据流, 不能为空 + * @param buf {void *} 存储结果的内容空间 + * @param size {int} buf 的空间大小 + * @return ret {http_off_t} 本次读到的HTTP响应体的内容 + * 0: 表示读完了HTTP数据体内容,但并不代表数据流已经关闭; + * < 0: 表示读出错,流关闭或出错; + * > 0: 表示未读完,目前读到ret 个字节的数据 + */ +HTTP_API http_off_t http_res_body_get_sync(HTTP_RES *respond, ACL_VSTREAM *stream, + void *buf, int size); +#define http_res_body_get_sync2 http_res_body_get_sync + +/** + * 设置请求协议的控制标志位 + * @param request {HTTP_REQ*} HTTP请求体类型指针, 不能为空, 且 request->hdr 为空 + * @param name {int} 第一个标志位,当最后一个标志位为 HTTP_CHAT_SYNC_CTL_END 时 + * 表示结束 + */ +HTTP_API void http_chat_sync_reqctl(HTTP_REQ *request, int name, ...); + +/** + * 设置响应协议的控制标志位 + * @param respond {HTTP_RES*} HTTP响应体类型指针, 不能为空, 且 respond->hdr 为空 + * @param name {int} 第一个标志位,当最后一个标志位为 HTTP_CHAT_SYNC_CTL_END 时 + * 表示结束 + */ +HTTP_API void http_chat_sync_resctl(HTTP_RES *respond, int name, ...); +#define HTTP_CHAT_SYNC_CTL_END 0 /**< 结束标志位 */ +#define HTTP_CHAT_CTL_BUFF_ONOFF 1 /**< 是否打开数据接收时的预缓冲策略 */ + +/*------------------------ HTTP 请求体构造及释放函数 ------------------------*/ +/* in http_req.c */ + +/** + * 根据HTTP请求头分配一个请求体对象 + * @param hdr_req {HTTP_HDR_REQ*} 请求头对象 + * @return {HTTP_REQ*} 请求体对象 + */ +HTTP_API HTTP_REQ *http_req_new(HTTP_HDR_REQ *hdr_req); + +/** + * 释放请求体对象 + * @param request {HTTP_REQ*} 请求体对象 + */ +HTTP_API void http_req_free(HTTP_REQ *request); + +/*------------------------ HTTP 响应体构造及释放函数 ------------------------*/ +/* in http_res.c */ + +/** +* 根据HTTP响应头分配一个响应体对象 +* @param hdr_res {HTTP_HDR_RES*} 响应头对象 +* @return {HTTP_RES*} 响应体对象 +*/ +HTTP_API HTTP_RES *http_res_new(HTTP_HDR_RES *hdr_res); + +/** + * 释放响应体对象 + * @param respond {HTTP_RES*} 响应体对象 + */ +HTTP_API void http_res_free(HTTP_RES *respond); + +/*------------------------------ HTTP 头构造函数 -----------------------------*/ +/* in http_hdr_build.c */ + +/** + * 向通用HTTP头中添加数据 + * @param hdr {HTTP_HDR*} 通用HTTP头对象 + * @param name {const char*} 变量名,如 Accept-Encoding: deflate, gzip 中的 Accept-Encoding + * @param value {const char*} 变量值,如 Accept-Encoding: deflate, gzip 中的 deflate, gzip + */ +HTTP_API void http_hdr_put_str(HTTP_HDR *hdr, const char *name, const char *value); + +/** + * 向通用HTTP头中添加数据 + * @param hdr {HTTP_HDR*} 通用HTTP头对象 + * @param name {const char*} 变量名,如 Content-Length: 1024 中的 Conteng-Length + * @param value {const int} 变量值,如 Content-Length: 1024 中的 1024 + */ +HTTP_API void http_hdr_put_int(HTTP_HDR *hdr, const char *name, int value); + +/** + * 向通用HTTP头中添加数据 + * @param hdr {HTTP_HDR*} 通用HTTP头对象 + * @param name {const char*} 变量名,如 Accept-Encoding: deflate, gzip 中的 Accept-Encoding + * @param fmt {const char*} 变参格式字符串 + */ +#ifdef WIN32 +HTTP_API void http_hdr_put_fmt(HTTP_HDR *hdr, const char *name, const char *fmt, ...); +#else +HTTP_API void __attribute__((format(printf,3,4))) + http_hdr_put_fmt(HTTP_HDR *hdr, const char *name, const char *fmt, ...); +#endif + +/** + * 向通用HTTP头中添加时间数据 + * @param hdr {HTTP_HDR*} 通用HTTP头对象 + * @param name {const char*} 变量名 + * @param t {time_t} 时间值 + */ +HTTP_API void http_hdr_put_time(HTTP_HDR *hdr, const char *name, time_t t); + +/** + * 根据HTTP请求头的字段来设置是否与服务端保持长连接, 结果存储于HTTP响应头中 + * @param req {const HTTP_HDR_REQ*} HTTP请求头 + * @param res {HTTP_HDR_RES*} HTTP响应头,存储分析结果 + */ +HTTP_API int http_hdr_set_keepalive(const HTTP_HDR_REQ *req, HTTP_HDR_RES *res); + +/** + * 用返回状态(1xx, 2xx, 3xx, 4xx, 5xx) 初始化一个HTTP响应头 + * @param hdr_res {HTTP_HDR_RES*} HTTP响应头,存储分析结果 + * @param status {int} 状态号,nxx(1xx, 2xx, 3xx, 4xx, 5xx) + */ +HTTP_API void http_hdr_res_init(HTTP_HDR_RES *hdr_res, int status); + +/** + * 用返回状态(nxx)生成一个HTTP响应头 + * @param status {int} 状态号,nxx(1xx, 2xx, 3xx, 4xx, 5xx) + * @return {HTTP_HDR_RES*} 生成的HTTP响应头 + */ +HTTP_API HTTP_HDR_RES *http_hdr_res_static(int status); + +/** +* 用返回状态(nxx)生成一个HTTP响应头 +* @param status {int} 状态号,nxx(4xx, 5xx) +* @return {HTTP_HDR_RES*} 生成的HTTP响应头 +*/ +HTTP_API HTTP_HDR_RES *http_hdr_res_error(int status); + +/** + * 根据HTTP通用头生成头的完整内容于BUF中 + * @param hdr {const HTTP_HDR*} 通用HTTP头 + * @param strbuf {ACL_VSTRING*} 存储结果的缓冲区 + */ +HTTP_API void http_hdr_build(const HTTP_HDR *hdr, ACL_VSTRING *strbuf); + +/** + * 根据HTTP请求头生成请求头内容于BUF中 + * @param hdr_req {const HTTP_HDR_REQ*} HTTP请求头 + * @param strbuf {ACL_VSTRING*} 存储结果的缓冲区 + */ +HTTP_API void http_hdr_build_request(const HTTP_HDR_REQ *hdr_req, ACL_VSTRING *strbuf); + +/*----------------------------- HTTP 响应状态信息函数 ------------------------*/ +/* in http_status.c */ + +/** + * 根据HTTP响应号(nxx)返回该值所代表的字符串 + * @param status {int} 状态号,nxx(1xx, 2xx, 3xx, 4xx, 5xx) + * @return {const char*} 响应号所对应的字符串表示 + */ +HTTP_API const char *http_status_line(int status); + +/*---------------------------- HTTP HTML 模板操作函数 ------------------------*/ +/* in http_tmpl.c */ + +/** + * 装载HTTP响应代码的HTML模板 + * @param tmpl_path {const char*} HTML模板文件所在的路径 + */ +HTTP_API void http_tmpl_load(const char *tmpl_path); + +/** + * 读取对应HTTP响应状态码的模板信息 + * @param status {int} HTTP 状态响应码 + * @return {const ACL_VSTRING*} 对应HTTP响应状态码的模板信息 + */ +HTTP_API const ACL_VSTRING *http_tmpl_get(int status); + +/** + * 读取对应HTTP响应状态码的标题提示信息 + * @param status {int} HTTP 状态响应码 + * @return {const char*} 对应HTTP响应状态码的标题提示信息 + */ +HTTP_API const char *http_tmpl_title(int status); + +/** + * 获得相应HTTP响应状态码的模板提示信息的长度大小 + * @param status {int} HTTP 状态响应码 + * @return {int} 模板提示信息的长度大小 + */ +HTTP_API int http_tmpl_size(int status); + +/*---------------------------- HTTP HTML 模板初始化函数 ----------------------*/ +/* in http_init.c */ + +/** + * 初始化HTTP应用协议 + * @param tmpl_path {const char*} 模板信息文件的存放路径 + */ +HTTP_API void http_init(const char *tmpl_path); + +/** + * 是否自动缓冲被释放的 HTTP 头对象,从而使其内存可以重复使用, 该函数在程序初始化 + * 时只能被调用一次 + * @param max {int} 当该值 > 0 时便自动启用 HTTP 头对象缓冲功能 + */ +HTTP_API void http_hdr_cache(int max); + +/** + * 设置在进行 HTTP 协议体数据传输时的缓冲区大小 + * @param size {http_off_t} 缓冲区大小 + */ +HTTP_API void http_buf_size_set(http_off_t size); + +/** + * 获得进行 HTTP 协议体数据传输时的缓冲区大小 + * @return {http_off_t} 缓冲区大小 + */ +HTTP_API http_off_t http_buf_size_get(void); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_protocol/include/http/lib_http_status.h b/lib_protocol/include/http/lib_http_status.h new file mode 100644 index 000000000..24a0ecbee --- /dev/null +++ b/lib_protocol/include/http/lib_http_status.h @@ -0,0 +1,47 @@ + +#ifndef __LIB_HTTP_STATUS_INCLUDE_H__ +#define __LIB_HTTP_STATUS_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#define HTTP_STATUS_400 "400" +#define HTTP_STATUS_401 "401" +#define HTTP_STATUS_402 "402" +#define HTTP_STATUS_403 "403" +#define HTTP_STATUS_404 "404" +#define HTTP_STATUS_405 "405" +#define HTTP_STATUS_406 "406" +#define HTTP_STATUS_407 "407" +#define HTTP_STATUS_408 "408" +#define HTTP_STATUS_409 "409" +#define HTTP_STATUS_410 "410" +#define HTTP_STATUS_411 "411" +#define HTTP_STATUS_412 "412" +#define HTTP_STATUS_413 "413" +#define HTTP_STATUS_414 "414" +#define HTTP_STATUS_415 "415" +#define HTTP_STATUS_416 "416" +#define HTTP_STATUS_417 "417" +#define HTTP_STATUS_422 "422" +#define HTTP_STATUS_423 "423" +#define HTTP_STATUS_424 "424" +#define HTTP_STATUS_425 "425" +#define HTTP_STATUS_426 "426" + +#define HTTP_STATUS_500 "500" +#define HTTP_STATUS_501 "501" +#define HTTP_STATUS_502 "502" +#define HTTP_STATUS_503 "503" +#define HTTP_STATUS_504 "504" +#define HTTP_STATUS_505 "505" +#define HTTP_STATUS_506 "506" +#define HTTP_STATUS_507 "507" +#define HTTP_STATUS_510 "510" + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_protocol/include/http/lib_http_struct.h b/lib_protocol/include/http/lib_http_struct.h new file mode 100644 index 000000000..fa729f746 --- /dev/null +++ b/lib_protocol/include/http/lib_http_struct.h @@ -0,0 +1,187 @@ + +#ifndef __LIB_HTTP_STRUCT_INCLUDE_H__ +#define __LIB_HTTP_STRUCT_INCLUDE_H__ + +#include "lib_acl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef HTTP_DLL +# ifdef HTTP_EXPORTS +# define HTTP_API __declspec(dllexport) +# else +# define HTTP_API __declspec(dllimport) +# endif +#else +# define HTTP_API +#endif + +typedef acl_int64 http_off_t; + +/* 结构类型定义 */ +typedef struct HTTP_HDR HTTP_HDR; +typedef struct HTTP_HDR_REQ HTTP_HDR_REQ; +typedef struct HTTP_HDR_RES HTTP_HDR_RES; +typedef struct HTTP_REQ HTTP_REQ; +typedef struct HTTP_RES HTTP_RES; +typedef struct HTTP_HDR_ENTRY HTTP_HDR_ENTRY; + +/* 函数类型定义 */ + +/** + * 数据头过程中的回回调函数类型定义 + * @param status {int} HTTP_CHAT_XXX + * status: + * HTTP_CHAT_OK: 读到完整的数据头 + * HTTP_CHAT_ERR_TOO_MANY_LINES: 数据头中的行数太多 + * @param arg {void*} 回调函数的参数 + * @return {int} 该回调函数如果返回值为 -1 则上级调用者便结束; 若返回 0 + * 上级调用者继续 + */ +typedef int (*HTTP_HDR_NOTIFY)(int status, void *arg); + +/** + * 数据体请求过程中的回调函数类型定义 + * @param status {int} HTTP_CHAT_XXX + * status: + * HTTP_CHAT_OK: 已经读完整个数据体,且 data 代表最后一部分数据, dlen 表示 + * data 的数据长度 + * HTTP_CHAT_DATA: 当为块传输方式时,表示每个数据块中的数据体中的部分数据; + * 当非块传输方式时,表示整个数据体的一部分数据 + * HTTP_CHAT_CHUNK_HDR: 表示块传输方式中的某个数据块的头数据 + * HTTP_CHAT_CHUNK_TRAILER: 表示块传输方式中的最后一个数据块的头数据 + * HTTP_CHAT_CHUNK_DATA_ENDL: 表示块传输方式中每块数据中最后的分隔行数据 + * HTTP_CHAT_ERR_PROTO: 表示协议出错 + * @param data {char *} 所读到的数据开始地址,永远不为空 + * @param dlen {int} 表示当前 data 数据长度 + * @return {int} 该回调函数如果返回值为 -1 则上级调用者便结束; 若返回 0 + * 上级调用者继续 + */ +typedef int (*HTTP_BODY_NOTIFY)(int status, char *data, int dlen, void *arg); + +/* 通信过程状态字定义 */ +#define HTTP_CHAT_OK 0 /**< 读完了整个数据 */ +#define HTTP_CHAT_CONTINUE 1 /**< 内部用 */ +#define HTTP_CHAT_DATA 2 /**< 数据体中的部分数据 */ +#define HTTP_CHAT_CHUNK_HDR 3 /**< 块数据头中的数据 */ +#define HTTP_CHAT_CHUNK_DATA_ENDL 4 /**< 块数据体中的分隔行数据 */ +#define HTTP_CHAT_CHUNK_TRAILER 5 /**< 最后一个数据块的头部分数据 */ +#define HTTP_CHAT_ERR_MIN 100 /**< 做为错误值的最小值 */ +#define HTTP_CHAT_ERR_IO 101 /**< IO出错 */ +#define HTTP_CHAT_ERR_PROTO 102 /**< 请求数据或响应数据的协议出错 */ +#define HTTP_CHAT_ERR_TOO_MANY_LINES 103 /**< 数据头太多行 */ +#define HTTP_CHAT_ERR_MAX 1000 /**< 最大错误范围 */ + +/* 设置的标志位 */ +#define HTTP_CHAT_FLAG_BUFFED 0x0001 + +/* HTTP 协议头部字段的定义 */ +#define HTTP_HDR_ENTRY_VIA "via" /**< HTTP 头添加字段,防止递归请求 */ +#define HTTP_HDR_ENTRY_FORWARD_FOR "X-Forwarded-For" /**< HTTP 请求头添加字段 */ + +/* HTTP 协议请求结构 */ +struct HTTP_REQ { + HTTP_HDR_REQ *hdr_req; /**< 与 client 相关 */ + int status; /**< 是否出错, defined above: HTTP_STATUS_ */ + unsigned int flag; /**< defined as: HTTP_CHAT_FLAG_XXX */ + void *ctx; + void (*free_ctx)(void*); +}; + +struct HTTP_RES { + HTTP_HDR_RES *hdr_res; /**< 与 client 相关 */ + int read_cnt; + int status; /**< 是否出错, defined above: HTTP_STATUS_ */ + unsigned int flag; /**< defined as: HTTP_CHAT_FLAG_XXX */ + void *ctx; + void (*free_ctx)(void*); +}; + +/* name-value 格式的条目 */ +struct HTTP_HDR_ENTRY { + char *name; + char *value; + int off; +}; + +/* HTTP 协议头 */ + +struct HTTP_HDR { + /* 通用实体 */ + char proto[32]; /**< 支持的协议: HTTP */ + struct { + unsigned int major; /**< 主版本号 */ + unsigned int minor; /**< 次版本号 */ + } version; + + int keep_alive; /**< 是否保持长连接 */ + http_off_t content_length; /**< HTTP协议体数据长度 */ + int chunked; /** + * 该字段本来对HTTP协议响应有意义, + * 为了将来的扩展, 故定义于此 + */ + + /* 内部变量 */ + int cur_lines; + int max_lines; + int valid_lines; + int status; + int keep_alive_count; /**< 处理次数 */ + + ACL_ARRAY *entry_lnk; /**< 存储着 HTTP_HDR_ENTRY 类型的元素 */ + void *chat_ctx; + void (*chat_free_ctx_fn)(void*); + + int debug; /**< 调试信息头的标志位 */ +}; + +#define HDR_RESTORE(hdr_ptr, hdr_type, hdr_member) \ + ((hdr_type *) (((char *) (hdr_ptr)) - offsetof(hdr_type, hdr_member))) + +/* HTTP 请求头 */ +struct HTTP_HDR_REQ { + HTTP_HDR hdr; /**< 包裹了通用的HDR头, 便于通用分析 */ + + int port; /**< 所请求的服务端的服务端口号 */ + /* 请求实体 */ + char method[32]; /**< 请求方法: POST, GET, CONNECT */ + char host[512]; /**< 所请示的主机的域名或IP地址 */ + ACL_VSTRING *url_part; /** + * 存储着请求行 URL 中的后半部分, + * 如: + * 1) http://test.com.cn/cgi-bin/test?name=value + * => /cgi-bin/test?name=value + */ + ACL_VSTRING *url_path; /** + * 存储着请求行 URL 中的相对路径发(不包含主机部分), + * 如对于 /path/test.cgi?name=value, + * 仅存储 /path/test.cgi, 剩余的 + * 参数部分则由 url_params 存储. + */ + ACL_VSTRING *url_params; /**< 存储着 URL 中的参数部分 */ + ACL_VSTRING *file_path; + + ACL_HTABLE *params_table; /**< 存储着 URL 请求行的各个字段的数据 */ + ACL_HTABLE *cookies_table; /**< 存储着的 cookie 项 */ + unsigned int flag; /**< 标志位 */ +#define HTTP_HDR_REQ_FLAG_PARSE_PARAMS (1 << 0) +#define HTTP_HDR_REQ_FLAG_PARSE_COOKIE (1 << 1) +}; + +/* HTTP 响应头 */ + +struct HTTP_HDR_RES { + HTTP_HDR hdr; /**< 包裹了通用的HDR头, 便于通用分析 */ + + /* 响应实体 */ + int reply_status; /**< 服务器的响应代码,如: 100, 200, 404, 304, 500 */ +}; + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_protocol/include/http/lib_http_util.h b/lib_protocol/include/http/lib_http_util.h new file mode 100644 index 000000000..c52ed227a --- /dev/null +++ b/lib_protocol/include/http/lib_http_util.h @@ -0,0 +1,234 @@ +#ifndef __LIB_HTTP_UTIL_INCLUDE_H__ +#define __LIB_HTTP_UTIL_INCLUDE_H__ + +#include "lib_http_struct.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct HTTP_UTIL { + HTTP_HDR_REQ *hdr_req; /**< HTTP 请求头 */ + HTTP_HDR_RES *hdr_res; /**< HTTP 响应头 */ + HTTP_RES *http_res; /**< HTTP 响应体 */ + char server_addr[256]; /**< 远程 HTTP 服务器地址 */ + ACL_VSTREAM *stream; /**< 与 HTTP 服务器建立的网络流 */ + int conn_timeout; /**< 连接 HTTP 服务器的超时时间 */ + int rw_timeout; /**< 与 HTTP 服务器通信时每次 IO 的超时时间 */ + ACL_VSTRING *req_buf; /**< 缓冲区 */ + int res_body_dlen; /**< HTTP 响应数据体的长度 */ + ACL_VSTREAM *dump_stream; /**< 转储接收数据的流 */ + unsigned int flag; /**< 标志位 */ +#define HTTP_UTIL_FLAG_SET_DUMP_FILE (1 << 0) /**< 允许转储响应体至文件 */ +#define HTTP_UTIL_FLAG_SET_DUMP_STREAM (1 << 1) /**< 允许转储响应体至流 */ +#define HTTP_UTIL_FLAG_HAS_RES_BODY (1 << 2) /**< 有 HTTP 响应体 */ +#define HTTP_UTIL_FLAG_NO_RES_BODY (1 << 3) /**< 无 HTTP 响应体 */ +} HTTP_UTIL; + +/** + * 创建一个 HTTP_UTIL 请求对象 + * @param url {const char*} 完整的请求 url + * @param method {const char*} 请求方法,有效的请求方法有:GET, POST, HEAD, CONNECT + * @return {HTTP_UTIL*} + */ +HTTP_API HTTP_UTIL *http_util_req_new(const char *url, const char *method); + +/** + * 构建一个 HTTP_UTIL 响应对象 + * @param status {int} 状态码,有效的状态码为: 1xx, 2xx, 3xx, 4xx, 5xx + * @return {HTTP_UTIL*} + */ +HTTP_API HTTP_UTIL *http_util_res_new(int status); + +/** + * 释放一个 HTTP_UTIL 对象 + * @param http_util {HTTP_UTIL*} + */ +HTTP_API void http_util_free(HTTP_UTIL *http_util); + +/** + * 设置 HTTP 请求头信息, 如: Accept-Encoding: gzip,deflate + * @param http_util {HTTP_UTIL*} + * @param name {const char*} 请求头中字段名称, 如 Accept-Encoding + * @param value {const char*} 请求头中字段的值, 如 gzip,deflate + */ +HTTP_API void http_util_set_req_entry(HTTP_UTIL *http_util, const char *name, const char *value); + +/** + * 关闭 HTTP 请求头中的某个请求字段,该请求字段不会发往服务器 + * @param http_util {HTTP_UTIL*} + * @param name {const char*} 请求头中字段名称, 如 Accept-Encoding + */ +HTTP_API void http_util_off_req_entry(HTTP_UTIL *http_util, const char *name); + +/** + * 获得请求头中某个字段的值 + * @param http_util {HTTP_UTIL*} + * @param name {const char*} 请求头中字段名称, 如 Accept-Encoding + * @return {char*} 如果非空则为请求字段值,否则表明该字段不存在 + */ +HTTP_API char *http_util_get_req_value(HTTP_UTIL *http_util, const char *name); + +/** + * 获得请求头中某个字段的 HTTP_HDR_ENTRY 对象 + * @param http_util {HTTP_UTIL*} + * @param name {const char*} 请求头中字段名称, 如 Accept-Encoding + * @return {HTTP_HDR_ENTRY*} 若为空则表示该字段不存在 + */ +HTTP_API HTTP_HDR_ENTRY *http_util_get_req_entry(HTTP_UTIL *http_util, const char *name); + +/** + * 设置请求头中 HTTP 数据体的数据长度 + * @param http_util {HTTP_UTIL*} + * @param len {int} HTTP 数据体长度(必须 >= 0) + */ +HTTP_API void http_util_set_req_content_length(HTTP_UTIL *http_util, int len); + +/** + * 设置请求头中 HTTP 会话保持长连接的存活时间(单位为秒) + * @param http_util {HTTP_UTIL*} + * @param timeout {int} HTTP 长连接的存活时间(单位为秒) + */ +HTTP_API void http_util_set_req_keep_alive(HTTP_UTIL *http_util, int timeout); + +/** + * 设置请求头中 Connection 字段 + * @param http_util {HTTP_UTIL*} + * @param value {const char*} 字段值,有效的字段为: keep-alive, close + */ +HTTP_API void http_util_set_req_connection(HTTP_UTIL *http_util, const char *value); + +/** + * 设置请求头中的 Referer 字段 + * @param http_util {HTTP_UTIL*} + * @param refer {const char*} 完整的 url, 如: http://www.test.com + */ +HTTP_API void http_util_set_req_refer(HTTP_UTIL *http_util, const char *refer); + +/** + * 设置请求头中的 Cookie 字段,采用的是追加方式 + * @param http_util {HTTP_UTIL*} + * @param name {const char*} Cookie 名称 + * @param value {const char*} Cookie 值 + */ +HTTP_API void http_util_set_req_cookie(HTTP_UTIL *http_util, const char *name, const char *value); + +/** + * 设置 HTTP 代理服务器地址 + * @param http_util {HTTP_UTIL*} + * @param proxy {const char*} 代理服务器地址,有效格式为: IP:PORT, DOMAIN:PORT, + * 如: 192.168.0.1:80, 192.168.0.2:8088, www.g.cn:80 + */ +HTTP_API void http_util_set_req_proxy(HTTP_UTIL *http_util, const char *proxy); + +/** + * 设置 HTTP 响应体的转储流,设置后 HTTP 响应体数据便会同时向该流转发 + * @param http_util {HTTP_UTIL*} + * @param stream {ACL_VSTREAM *} 转储流 + */ +HTTP_API void http_util_set_dump_stream(HTTP_UTIL *http_util, ACL_VSTREAM *stream); + +/** + * 设置 HTTP 响应体的转储文件,设置后 HTTP 响应体数据便会转储于该文件 + * @param http_util {HTTP_UTIL*} + * @param filename {const char*} 转储文件名 + * @return {int} 如果返回值 < 0 则表示无法打开该文件, 否则表示打开文件成功 + */ +HTTP_API int http_util_set_dump_file(HTTP_UTIL *http_util, const char *filename); + +/** + * 打开远程 HTTP 服务器或代理服务器连接,同时构建 HTTP 请求头数据并且将该数据 + * 发给新建立的网络连接 + * @param http_util {HTTP_UTIL*} + * @return {int} 0: 成功; -1: 无法打开连接或发送请求头数据失败 + */ +HTTP_API int http_util_req_open(HTTP_UTIL *http_util); + +/** + * 当采用 POST 方法时,可以通过此函数向 HTTP 服务器或代理服务器发送请求体数据, + * 在一个请求过程中,可以多次调用本函数直至发送完请求体数据 + * @param http_util {HTTP_UTIL*} + * @param data {const char*} 本次发送的数据地址,必须非空 + * @param dlen {size_t} data 数据长度, 必须大于 0 + * @param {int} > 0 表示本次成功发送的数据; -1: 表示发送数据失败, 应调用 + * http_util_free 关闭网络流且释放内存资源 + */ +HTTP_API int http_util_put_req_data(HTTP_UTIL *http_util, const char *data, size_t dlen); + +/** + * 发送完请求数据后调用此函数从 HTTP 服务器读取完整的 HTTP 响应头 + * @param http_util {HTTP_UTIL*} + * @return {int} 0: 成功; -1: 失败 + */ +HTTP_API int http_util_get_res_hdr(HTTP_UTIL *http_util); + +/** + * 从 HTTP 响应头中获得某个字段值 + * @param http_util {HTTP_UTIL*} + * @param name {const char*} 字段名称, 如 Content-Length + * @return {char*} 对应 name 的字段值, 如果为空则表示该字段不存在 + */ +HTTP_API char *http_util_get_res_value(HTTP_UTIL *http_util, const char *name); + +/** + * 从 HTTP 响应头中获得某个字段对象 + * @param http_util {HTTP_UTIL*} + * @param name {const char*} 字段名称, 如 Content-Length + * @return {HTTP_HDR_ENTRY*} 对应 name 的字段对象, 如果为空则表示该字段不存在 + */ +HTTP_API HTTP_HDR_ENTRY *http_util_get_res_entry(HTTP_UTIL *http_util, const char *name); + +/** + * 设置 HTTP 响应头中的某个字段值 + * @param http_util {HTTP_UTIL*} + * @param name {const char*} 字段名称, 如 Content-Type + * @param value {const char*} 字段值, 如 text/html + */ +HTTP_API void http_util_set_res_entry(HTTP_UTIL *http_util, const char *name, const char *value); + +/** + * 关闭 HTTP 响应头中的某个字段 + * @param http_util {HTTP_UTIL*} + * @param name {const char*} 字段名称, 如 Content-Type + */ +HTTP_API void http_util_off_res_entry(HTTP_UTIL *http_util, const char *name); + +/** + * 读完 HTTP 响应头后调用此函数判断是否有 HTTP 响应体 + * @param http_util {HTTP_UTIL*} + * @return {int} 0: 表示无响应体; !0: 表示有响应体 + */ +HTTP_API int http_util_has_res_body(HTTP_UTIL *http_util); + +/** + * 读完 HTTP 响应头后调用此函数从 HTTP 服务器读取 HTTP 数据体数据,需要连续调用 + * 此函数,直至返回值 <= 0, 如果之前设置了转储文件或转储则在读取数据过程中同时会 + * 拷贝一份数据给转储文件或转储流 + * @param http_util {HTTP_UTIL*} + * @param buf {char *} 存储 HTTP 响应体的缓冲区 + * @param size {size_t} buf 的空间大小 + * @return {int} <= 0: 表示读结束; > 0: 表示本次读到的数据长度 + */ +HTTP_API int http_util_get_res_body(HTTP_UTIL *http_util, char *buf, size_t size); + +/** + * 将某个 url 的响应体数据转储至某个文件中 + * @param url {const char*} 完整请求 url, 如: http://www.g.cn + * @param dump {const char*} 转储文件名 + * @param {int} 读到的响应体数据长度, >=0: 表示成功, -1: 表示失败 + */ +HTTP_API int http_util_dump_url(const char *url, const char *dump); + +/** + * 将某个 url 的响应体数据转储至某个流中 + * @param url {const char*} 完整请求 url, 如: http://www.g.cn + * @param stream {ACL_VSTREAM *} 转储流 + * @param {int} 读到的响应体数据长度, >=0: 表示成功, -1: 表示失败 + */ +HTTP_API int http_util_dump_url_to_stream(const char *url, ACL_VSTREAM *stream); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_protocol/include/icmp/lib_icmp.h b/lib_protocol/include/icmp/lib_icmp.h new file mode 100644 index 000000000..a5bc0b8ce --- /dev/null +++ b/lib_protocol/include/icmp/lib_icmp.h @@ -0,0 +1,138 @@ +#ifndef __LIB_ICMP_INCLUDE_H__ +#define __LIB_ICMP_INCLUDE_H__ + +#include "lib_acl.h" +#include "lib_icmp_type.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef ICMP_DLL +# ifdef ICMP_EXPORTS +# define ICMP_API __declspec(dllexport) +# else +# define ICMP_API __declspec(dllimport) +# endif +#else +# define ICMP_API +#endif + +/* in icmp_chat.c */ +/** + * 创建ICMP会话对象 + * @param aio {ACL_AIO*} 如果该项不为空,则内部在通信过程中采用非阻塞模式, + * 否则采用阻塞模式 + * @param check_tid {int} 是否在校验响应包时检查数据中的线程号字段 + * @return {ICMP_CHAT*} ICMP会话对象句柄 + */ +ICMP_API ICMP_CHAT *icmp_chat_create(ACL_AIO *aio, int check_tid); + +/** + * 释放ICMP会话对象 + * @param chat {ICMP_CHAT*} ICMP会话对象句柄 + */ +ICMP_API void icmp_chat_free(ICMP_CHAT *chat); + +/** + * 开始与某个目的主机进行会话 + * @param host {ICMP_HOST*} 调用 icmp_host_new 返回的对象 + */ +ICMP_API void icmp_chat(ICMP_HOST* host); + +/** + * 当前的ICMP会话对象中被探测的主机个数 + * @param chat {ICMP_CHAT*} 会话对象句柄 + * @return {int} 被探测主机个数 + */ +ICMP_API int icmp_chat_size(ICMP_CHAT *chat); + +/** + * 当前的ICMP会话对象中已经完成的探测的主机个数 + * @param chat {ICMP_CHAT*} 会话对象句柄 + * @return {int} 已完成的被探测主机个数 + */ +ICMP_API int icmp_chat_count(ICMP_CHAT *chat); + +/** + * 判断当前的ICMP会话对象中所有探测任务是否已经完成 + * @param chat {ICMP_CHAT*} 会话对象句柄 + * @return {int} != 0: 表示完成; 0: 表示未完成 + */ +ICMP_API int icmp_chat_finish(ICMP_CHAT *chat); + +/** + * 取得当前ICMP会话对象中的当前会话序列号值 + * @param chat {ICMP_CHAT*} 会话对象句柄 + * @return {unsigned short} 会话序列号值 + */ +ICMP_API unsigned short icmp_chat_seqno(ICMP_CHAT *chat); + +/* in icmp_stat.c */ +/** + * 输出当前ICMP的会话状态 + * @param chat {ICMP_CHAT*} 会话对象句柄 + */ +ICMP_API void icmp_stat(ICMP_CHAT *chat); + +/** + * 计算某个主机的ICMP会话状态 + * @param host {ICMP_HOST*} 被探测主机对象 + * @param show_flag {int} 是否输出结果至日志文件 + */ +ICMP_API void icmp_stat_host(ICMP_HOST *host, int show_flag); + +/* in icmp_host.c */ +/** + * 创建一个新的被探测的主机对象 + * @param chat {ICMP_CHAT*} 会话对象句柄 + * @param domain {const char*} 域名标识字符串,可以为空 + * @param ip {const char*} 主机IP地址,不能为空 + * @param npkt {size_t} 对该主机发送的数据包个数 + * @param dlen {size_t} 每个探测数据包的长度 + * @param delay {int} 发送探测数据包的时间间隔(秒) + * @param timeout {int} 被探测主机的响应包超时时间(秒) + * @return {ICMP_HOST*} 被探测主机对象, 如果为空则表示出错 + */ +ICMP_API ICMP_HOST* icmp_host_new(ICMP_CHAT *chat, const char *domain, + const char *ip, size_t npkt, size_t dlen, int delay, int timeout); + +/** + * 释放一个被探测主机对象 + * @param host {ICMP_HOST*} 被探测主机对象 + */ +ICMP_API void icmp_host_free(ICMP_HOST *host); + +/** + * 设置探测结果的回调函数 + * @param host {ICMP_HOST*} 被探测主机对象 + * @param arg {void*} 回调函数的参数之一 + * @param stat_respond {void (*)(ICMP_PKT_STATUS*)} 正常响应时的回调函数 + * @param stat_timeout {void (*)(ICMP_PKT_STATUS*)} 超时响应时的回调函数 + * @param stat_unreach {void (*)(ICMP_PKT_STATUS*}} 主机不可达时的回调函数 + * @param stat_finish {void (*)(ICMP_HOST*)} 针对该主机的探测任务时的回调函数 + */ +ICMP_API void icmp_host_set(ICMP_HOST *host, void *arg, + void (*stat_respond)(ICMP_PKT_STATUS*, void*), + void (*stat_timeout)(ICMP_PKT_STATUS*, void*), + void (*stat_unreach)(ICMP_PKT_STATUS*, void*), + void (*stat_finish)(ICMP_HOST*, void*)); + +/* in icmp_ping.c */ +/** + * ping 一台主机(内部默认每个探测包长度为64个字节) + * @param chat {ICMP_CHAT*} 会话对象句柄 + * @param domain {const char*} 域名标识字符串,可以为空 + * @param ip {const char*} 主机IP地址,不能为空 + * @param npkt {size_t} 对该主机发送的数据包个数 + * @param delay {int} 发送探测数据包的时间间隔(秒) + * @param timeout {int} 被探测主机的响应包超时时间(秒) + */ +ICMP_API void icmp_ping_one(ICMP_CHAT *chat, const char *domain, + const char *ip, size_t npkt, int delay, int timeout); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_protocol/include/icmp/lib_icmp_type.h b/lib_protocol/include/icmp/lib_icmp_type.h new file mode 100644 index 000000000..3d6228203 --- /dev/null +++ b/lib_protocol/include/icmp/lib_icmp_type.h @@ -0,0 +1,69 @@ +#ifndef __LIB_ICMP_TYPE_INCLUDE_H__ +#define __LIB_ICMP_TYPE_INCLUDE_H__ + +typedef struct ICMP_CHAT ICMP_CHAT; +typedef struct ICMP_STAT ICMP_STAT; +typedef struct ICMP_HOST ICMP_HOST; +typedef struct ICMP_PKT ICMP_PKT; +typedef struct ICMP_PKT_STATUS ICMP_PKT_STATUS; + +/**< ICMP 通信过程中每个主机的 PING 响应状态信息汇总 */ +struct ICMP_STAT { + double tmin; /**< 最短时间 */ + double tmax; /**< 最长时间 */ + double tsum; /**< 总时间 */ + double tave; /**< 平均时间 */ + size_t nsent; /**< 已经发送的包个数 */ + size_t nreceived; /**< 已经收到的包个数 */ + double loss; /**< 丢失的包个数 */ +}; + +/**< ICMP 所发送的每个 PING 包之后的主机状态应答 */ +struct ICMP_PKT_STATUS { + size_t reply_len; /**< 包回复的数据长度 */ + char frome_ip[32]; /**< 源地址 */ + + double rtt; /**< 往返时间(毫秒)(Round Trip Time) */ + unsigned short seq; /**< 序列号(seq no) */ + unsigned char ttl; /**< 生存时间(time to live) */ + char status; +#define ICMP_STATUS_OK 0 +#define ICMP_STATUS_UNREACH 1 +#define ICMP_STATUS_TIMEOUT 2 +}; + +/**< 目的主机信息结构 */ +struct ICMP_HOST { + ICMP_STAT icmp_stat; /**< ICMP 通信过程中的状态 */ + char dest_ip[32]; /**< 目的主机IP地址 */ + char domain[64]; /**< 目的主机IP所对应的域名 */ + struct sockaddr_in dest; /**< 发送包时目的主机地址 */ + struct sockaddr_in from; /**< 接收包时源主机地址 */ + int from_len; /**< 接收包时存储在 from 中的地址长度 */ + int delay; /**< 间隔发送PING包的时间,单位为秒 */ + int timeout; /**< 超时时间 */ + size_t dlen; /**< 每个发送包的大小(字节) */ + size_t npkt; /**< 设置的向该目的主机发送包的个数 */ + size_t nsent; /**< 已经发送给该目的主机包的个数 */ + + char enable_log; /**< 是否将响应包的信息记日志 */ + ACL_RING host_ring; /**< 由此链入 ICMP_CHAT->host_head 链中 */ + ACL_RING pkt_head; /**< 发送给目的主机数据包的链的链头 */ + ICMP_CHAT *chat; /**< 所属的通信对象 */ + + /**< 汇报发送包的响应包状态 */ + void (*stat_respond)(ICMP_PKT_STATUS*, void*); + + /**< 该发送包的响应包超时 */ + void (*stat_timeout)(ICMP_PKT_STATUS*, void*); + + /**< 该主机不可达 */ + void (*stat_unreach)(ICMP_PKT_STATUS*, void*); + + /**< 当主机的包发完时的回调函数 */ + void (*stat_finish)(ICMP_HOST*, void*); + + void *arg; /**< 应用传递的私有参数地址 */ +}; + +#endif diff --git a/lib_protocol/include/lib_protocol.h b/lib_protocol/include/lib_protocol.h new file mode 100644 index 000000000..539f9c7b7 --- /dev/null +++ b/lib_protocol/include/lib_protocol.h @@ -0,0 +1,9 @@ +#ifndef __LIB_PROTOCOL_INCLUDE_H__ +#define __LIB_PROTOCOL_INCLUDE_H__ + +#include "http/lib_http.h" +#include "http/lib_http_util.h" +#include "icmp/lib_icmp.h" +#include "smtp/smtp_client.h" + +#endif diff --git a/lib_protocol/include/smtp/smtp_client.h b/lib_protocol/include/smtp/smtp_client.h new file mode 100644 index 000000000..85b7af7a2 --- /dev/null +++ b/lib_protocol/include/smtp/smtp_client.h @@ -0,0 +1,200 @@ +#ifndef __SMTP_CLIENT_INCLUDE_H__ +#define __SMTP_CLIENT_INCLUDE_H__ + +#include "lib_acl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef SMTP_DLL +# ifdef SMTP_EXPORTS +# define SMTP_API __declspec(dllexport) +# else +# define SMTP_API __declspec(dllimport) +# endif +#else +# define SMTP_API +#endif + +typedef struct SMTP_CLIENT { + ACL_VSTREAM *conn; + int smtp_code; + char* buf; + int size; + unsigned int flag; +#define SMTP_FLAG_PIPELINING (1 << 0) +#define SMTP_FLAG_AUTH (1 << 1) +#define SMTP_FLAG_8BITMIME (1 << 2) +#define SMTP_FLAG_DSN (1 << 3) +#define SMTP_FLAG_VRFY (1 << 4) +#define SMTP_FLAG_ETRN (1 << 5) +#define SMTP_FLAG_SIZE (1 << 6) + int message_size_limit; +} SMTP_CLIENT; + +/** + * 远程连接 SMTP 服务器 + * @param addr {const char*} SMTP 服务器地址,格式:domain:port + * @param conn_timeout {int} 连接超时时间 + * @param rw_timeout {int} IO读写超时时间 + * @param line_limit {int} SMTP 会话过程中每行的最大长度限制 + * @return {SMTP_CLIENT*} 连接成功返回非空值,否则返回 NULL + */ +SMTP_API SMTP_CLIENT *smtp_open(const char *addr, int conn_timeout, + int rw_timeout, int line_limit); + +/** + * 关闭由 smtp_open 打开的 SMTP 连接并释放对象 + * @param client {SMTP_CLIENT*} SMTP 连接对象 + */ +SMTP_API void smtp_close(SMTP_CLIENT *client); + +/** + * 获得 SMTP 服务器的欢迎信息 + * @param client {SMTP_CLIENT*} SMTP 连接对象 + * @return {int} 0 表示成功(SMTP_CLIENT::smtp_code 表示返回码, + * SMTP_CLIENT::buf 存储响应内容),否则表示出错,应该关闭连接对象 + */ +SMTP_API int smtp_get_banner(SMTP_CLIENT *client); + +/** + * 向 SMTP 服务器发送 HELO/EHLO 命令 + * @param client {SMTP_CLIENT*} SMTP 连接对象 + * @param name {const char*} 握手信息,一般用域名 + * @param ehlo {int} 非 0 时使用 EHLO,否则使用 HELO + * @return {int} 0 表示成功(SMTP_CLIENT::smtp_code 表示返回码, + * SMTP_CLIENT::buf 存储响应内容),否则表示出错,应该关闭连接对象 + */ + +SMTP_API int smtp_greet(SMTP_CLIENT *client, const char* name, int ehlo); + +/** + * 向 SMTP 服务器发送 HELO 命令 + * @param client {SMTP_CLIENT*} SMTP 连接对象 + * @param helo {const char*} 握手信息,一般用域名 + * @return {int} 0 表示成功(SMTP_CLIENT::smtp_code 表示返回码, + * SMTP_CLIENT::buf 存储响应内容),否则表示出错,应该关闭连接对象 + */ +SMTP_API int smtp_helo(SMTP_CLIENT *client, const char *helo); + +/** + * 向 SMTP 服务器发送 EHLO 命令 + * @param client {SMTP_CLIENT*} SMTP 连接对象 + * @param ehlo {const char*} 握手信息,一般用域名 + * @return {int} 0 表示成功(SMTP_CLIENT::smtp_code 表示返回码, + * SMTP_CLIENT::buf 存储响应内容),否则表示出错,应该关闭连接对象 + */ +SMTP_API int smtp_ehlo(SMTP_CLIENT *client, const char *ehlo); + +/** + * 向 SMTP 服务器发送验证信息 + * @param client {SMTP_CLIENT*} SMTP 连接对象 + * @param user {const char*} SMTP 邮件账号 + * @param pass {const char*} SMTP 邮件账号密码 + * @return {int} 0 表示成功(SMTP_CLIENT::smtp_code 表示返回码, + * SMTP_CLIENT::buf 存储响应内容),否则表示出错,应该关闭连接对象 + */ +SMTP_API int smtp_auth(SMTP_CLIENT *client, const char *user, const char *pass); + +/** + * 向 SMTP 服务器发送 MAIL FROM 命令 + * @param client {SMTP_CLIENT*} SMTP 连接对象 + * @param from {const char*} 发送者邮箱 + * @return {int} 0 表示成功(SMTP_CLIENT::smtp_code 表示返回码, + * SMTP_CLIENT::buf 存储响应内容),否则表示出错,应该关闭连接对象 + */ +SMTP_API int smtp_mail(SMTP_CLIENT *client, const char *from); + +/** + * 向 SMTP 服务器发送 RCPT TO 命令 + * @param client {SMTP_CLIENT*} SMTP 连接对象 + * @param to {const char*} 接收者邮箱 + * @return {int} 0 表示成功(SMTP_CLIENT::smtp_code 表示返回码, + * SMTP_CLIENT::buf 存储响应内容),否则表示出错,应该关闭连接对象 + */ +SMTP_API int smtp_rcpt(SMTP_CLIENT *client, const char *to); + +/** + * 向 SMTP 服务器发送 DATA 命令 + * @param client {SMTP_CLIENT*} SMTP 连接对象 + * @return {int} 0 表示成功(SMTP_CLIENT::smtp_code 表示返回码, + * SMTP_CLIENT::buf 存储响应内容),否则表示出错,应该关闭连接对象 + */ +SMTP_API int smtp_data(SMTP_CLIENT *client); + +/** + * 向 SMTP 服务器发送邮件体内容,可以循环调用本函数直至数据发送完毕 + * @param client {SMTP_CLIENT*} SMTP 连接对象 + * @param src {const char*} 遵守邮件 MIME 编码格式的邮件体内容 + * @param len {size_t} src 数据长度 + * @return {int} 0 表示成功(SMTP_CLIENT::smtp_code 表示返回码, + * SMTP_CLIENT::buf 存储响应内容),否则表示出错,应该关闭连接对象 + */ +SMTP_API int smtp_send(SMTP_CLIENT *client, const char* src, size_t len); + +/** + * 向 SMTP 服务器发送邮件体内容,可以循环调用本函数直至数据发送完毕 + * @param client {SMTP_CLIENT*} SMTP 连接对象 + * @param fmt {const char*} 格式字符串 + * @param ... 变参 + * @return {int} 0 表示成功(SMTP_CLIENT::smtp_code 表示返回码, + * SMTP_CLIENT::buf 存储响应内容),否则表示出错,应该关闭连接对象 + */ +SMTP_API int smtp_printf(SMTP_CLIENT *client, const char* fmt, ...); + +/** + * 发送完邮件内容后调用本函数告诉 SMTP 服务器邮件数据完毕 + * @param client {SMTP_CLIENT*} SMTP 连接对象 + * @return {int} 0 表示成功(SMTP_CLIENT::smtp_code 表示返回码, + * SMTP_CLIENT::buf 存储响应内容),否则表示出错,应该关闭连接对象 + */ +SMTP_API int smtp_data_end(SMTP_CLIENT *client); + +/** + * 向 SMTP 服务器发送指定件路径的邮件文件 + * @param client {SMTP_CLIENT*} SMTP 连接对象 + * @param filepath {const char*} 邮件文件路径 + * @return {int} 0 表示成功(SMTP_CLIENT::smtp_code 表示返回码, + * SMTP_CLIENT::buf 存储响应内容),否则表示出错,应该关闭连接对象 + */ +SMTP_API int smtp_send_file(SMTP_CLIENT *client, const char *filepath); + +/** + * 向 SMTP 服务器发送给定文件流的邮件内容 + * @param client {SMTP_CLIENT*} SMTP 连接对象 + * @param int {ACL_VSTREAM*} 邮件文件输入流 + * @return {int} 0 表示成功(SMTP_CLIENT::smtp_code 表示返回码, + * SMTP_CLIENT::buf 存储响应内容),否则表示出错,应该关闭连接对象 + */ +SMTP_API int smtp_send_stream(SMTP_CLIENT *client, ACL_VSTREAM *in); + +/** + * 向 SMTP 服务器发送退出(QUIT)命令 + * @param client {SMTP_CLIENT*} SMTP 连接对象 + * @return {int} 0 表示成功(SMTP_CLIENT::smtp_code 表示返回码, + * SMTP_CLIENT::buf 存储响应内容),否则表示出错,应该关闭连接对象 + */ +SMTP_API int smtp_quit(SMTP_CLIENT *client); + +/** + * 向 SMTP 服务器发送 NOOP 命令 + * @param client {SMTP_CLIENT*} SMTP 连接对象 + * @return {int} 0 表示成功(SMTP_CLIENT::smtp_code 表示返回码, + * SMTP_CLIENT::buf 存储响应内容),否则表示出错,应该关闭连接对象 + */ +SMTP_API int smtp_noop(SMTP_CLIENT *client); + +/** + * 向 SMTP 服务器发送 RSET 命令 + * @param client {SMTP_CLIENT*} SMTP 连接对象 + * @return {int} 0 表示成功(SMTP_CLIENT::smtp_code 表示返回码, + * SMTP_CLIENT::buf 存储响应内容),否则表示出错,应该关闭连接对象 + */ +SMTP_API int smtp_rset(SMTP_CLIENT *client); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_protocol/lib/keep b/lib_protocol/lib/keep new file mode 100644 index 000000000..533667ccd --- /dev/null +++ b/lib_protocol/lib/keep @@ -0,0 +1,2 @@ +keepme + diff --git a/lib_protocol/lib_protocol.rc b/lib_protocol/lib_protocol.rc new file mode 100644 index 000000000..085372f89 --- /dev/null +++ b/lib_protocol/lib_protocol.rc @@ -0,0 +1,102 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// ??(???????) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) +#ifdef _WIN32 +LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED +#pragma code_page(936) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x17L +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x7L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "080404b0" + BEGIN + VALUE "Comments", "主要包括HTTP协议,ICMP协议的实现" + VALUE "FileDescription", "protocol" + VALUE "FileVersion", "1, 0, 0, 1" + VALUE "InternalName", "lib_prot" + VALUE "LegalCopyright", "zsx (C) 2011" + VALUE "OriginalFilename", "lib_prot.lib" + VALUE "ProductName", "protocol" + VALUE "ProductVersion", "1, 0, 0, 1" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x804, 1200 + END +END + +#endif // ??(???????) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/lib_protocol/lib_protocol_vc2003.vcproj b/lib_protocol/lib_protocol_vc2003.vcproj new file mode 100644 index 000000000..f81438194 --- /dev/null +++ b/lib_protocol/lib_protocol_vc2003.vcproj @@ -0,0 +1,412 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_protocol/lib_protocol_vc2010.vcxproj b/lib_protocol/lib_protocol_vc2010.vcxproj new file mode 100644 index 000000000..22e5ff0d1 --- /dev/null +++ b/lib_protocol/lib_protocol_vc2010.vcxproj @@ -0,0 +1,246 @@ +锘 + + + + Debug + Win32 + + + DebugDll + Win32 + + + ReleaseDll + Win32 + + + Release + Win32 + + + + lib_protocol + {FE724EF7-3763-4E78-BDF5-BCBC075719FD} + lib_protocol + Win32Proj + + + + DynamicLibrary + + + DynamicLibrary + + + StaticLibrary + MultiByte + + + StaticLibrary + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + .\ + Debug\ + *.obj%3b*.ilk%3b*.pdb%3b*.tlb%3b*.tli%3b*.tlh%3b*.tmp%3b*.rsp%3b*.bat%3b*.map%3b*.pch%3b$(TargetPath) + .\ + Release\ + *.obj%3b*.ilk%3b*.pdb%3b*.tlb%3b*.tli%3b*.tlh%3b*.tmp%3b*.rsp%3b*.bat%3b*.map%3b*.pch%3b$(TargetPath) + .\ + ReleaseDll\ + *.obj%3b*.ilk%3b*.pdb%3b*.tlb%3b*.tli%3b*.tlh%3b*.tmp%3b*.rsp%3b*.bat%3b*.map%3b*.pch%3b$(TargetPath) + .\ + DebugDll\ + *.obj%3b*.ilk%3b*.pdb%3b*.tlb%3b*.tli%3b*.tlh%3b*.tmp%3b*.rsp%3b*.bat%3b*.map%3b*.pch%3b$(TargetPath) + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + $(ProjectName)_vc2010d + $(ProjectName)_d + $(ProjectName)_vc2010 + + + + Disabled + Size + .\include;.\src;..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Use + $(ProjectName)_vc2010d.pdb + Level3 + ProgramDatabase + Default + + + /MACHINE:X86 %(AdditionalOptions) + $(ProjectName)_vc2010d.lib + + + copy $(TargetName).lib ..\dist\lib\win32\$(TargetName).lib /Y +copy $(TargetName).pdb ..\dist\lib\win32\$(TargetName).pdb /Y + + + + + MinSpace + Size + .\include;.\src;..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + false + Use + $(ProjectName)_vc2010.pdb + Level3 + ProgramDatabase + + + /MACHINE:X86 %(AdditionalOptions) + $(ProjectName)_vc2010.lib + + + copy $(TargetName).lib ..\dist\lib\win32\$(TargetName).lib /Y +copy $(TargetName).pdb ..\dist\lib\win32\$(TargetName).pdb /Y + + + + + .\include;.\src;..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;ACL_DLL;HTTP_DLL;HTTP_EXPORTS;ICMP_DLL;ICMP_EXPORTS;%(PreprocessorDefinitions) + MultiThreadedDLL + Use + $(ProjectName).pdb + ProgramDatabase + + + ws2_32.lib;lib_acl.lib;%(AdditionalDependencies) + $(ProjectName).dll + ..\lib_acl;%(AdditionalLibraryDirectories) + MachineX86 + + + copy $(TargetName).lib ..\dist\lib\win32\$(TargetName).lib /Y +copy $(TargetName).dll ..\dist\lib\win32\$(TargetName).dll /Y +copy $(TargetName).pdb ..\dist\lib\win32\$(TargetName).pdb /Y + + + + + + Disabled + .\include;.\src;..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;ACL_DLL;HTTP_DLL;HTTP_EXPORTS;ICMP_DLL;ICMP_EXPORTS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Use + $(ProjectName)_d.pdb + ProgramDatabase + + + ws2_32.lib;lib_acl_d.lib;%(AdditionalDependencies) + $(ProjectName)_d.dll + ..\lib_acl;%(AdditionalLibraryDirectories) + true + true + true + false + + + + + $(OutDir)$(TargetName).lib + MachineX86 + + + copy $(TargetName).lib ..\dist\lib\win32\$(TargetName).lib /Y +copy $(TargetName).dll ..\dist\lib\win32\$(TargetName).dll /Y +copy $(TargetName).pdb ..\dist\lib\win32\$(TargetName).pdb /Y + + + + + + + + + Create + Create + Create + Create + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib_protocol/lib_protocol_vc2010.vcxproj.filters b/lib_protocol/lib_protocol_vc2010.vcxproj.filters new file mode 100644 index 000000000..4117ff6a6 --- /dev/null +++ b/lib_protocol/lib_protocol_vc2010.vcxproj.filters @@ -0,0 +1,163 @@ +锘 + + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx + + + {112f4d94-c098-4a94-bbc8-ee5abbc2e187} + cpp;c;cxx;rc;def;r;odl;idl;hpj;bat + + + {16b35991-96a0-4a5c-9342-60b9c54a9ddf} + + + {cba2cd1e-331b-43e7-b2b0-7b3f12a11f6d} + + + {0089ea56-3dab-4e03-8a93-d86523b2d3e0} + + + {0c7db2e6-7635-418f-9252-218a91894992} + + + {63bcbe09-2abf-4583-9827-73c1fbe6987a} + + + {32468a59-0a82-4ab3-9c3a-424addc3a127} + + + {f7b3e5d1-078a-4d9e-b0d0-cd38185af6d5} + + + {f34ea68e-eb1d-41af-9b2e-13a64479daa7} + + + + + 璧勬簮鏂囦欢 + + + + + Source Files + + + Source Files\http + + + Source Files\http + + + Source Files\http + + + Source Files\http + + + Source Files\http + + + Source Files\http + + + Source Files\http + + + Source Files\http + + + Source Files\http + + + Source Files\http + + + Source Files\http + + + Source Files\http + + + Source Files\http + + + Source Files\icmp + + + Source Files\icmp + + + Source Files\icmp + + + Source Files\icmp + + + Source Files\icmp + + + Source Files\icmp + + + Source Files\icmp + + + Source Files\icmp + + + Source Files\icmp + + + Source Files + + + Source Files\smtp + + + + + Source Files + + + Source Files\http + + + Source Files\icmp + + + Source Files\icmp + + + Header Files + + + Header Files\http + + + Header Files\http + + + Header Files\http + + + Header Files\http + + + Header Files\icmp + + + Header Files\icmp + + + Header Files\smtp + + + + + doc + + + + \ No newline at end of file diff --git a/lib_protocol/lib_protocol_vc2012.vcxproj b/lib_protocol/lib_protocol_vc2012.vcxproj new file mode 100644 index 000000000..42e66e559 --- /dev/null +++ b/lib_protocol/lib_protocol_vc2012.vcxproj @@ -0,0 +1,250 @@ +锘 + + + + Debug + Win32 + + + DebugDll + Win32 + + + ReleaseDll + Win32 + + + Release + Win32 + + + + lib_protocol + {FE724EF7-3763-4E78-BDF5-BCBC075719FD} + lib_protocol + Win32Proj + + + + DynamicLibrary + v110 + + + DynamicLibrary + v110 + + + StaticLibrary + MultiByte + v110 + + + StaticLibrary + MultiByte + v110 + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + .\ + Debug\ + *.obj%3b*.ilk%3b*.pdb%3b*.tlb%3b*.tli%3b*.tlh%3b*.tmp%3b*.rsp%3b*.bat%3b*.map%3b*.pch%3b$(TargetPath) + .\ + Release\ + *.obj%3b*.ilk%3b*.pdb%3b*.tlb%3b*.tli%3b*.tlh%3b*.tmp%3b*.rsp%3b*.bat%3b*.map%3b*.pch%3b$(TargetPath) + .\ + ReleaseDll\ + *.obj%3b*.ilk%3b*.pdb%3b*.tlb%3b*.tli%3b*.tlh%3b*.tmp%3b*.rsp%3b*.bat%3b*.map%3b*.pch%3b$(TargetPath) + .\ + DebugDll\ + *.obj%3b*.ilk%3b*.pdb%3b*.tlb%3b*.tli%3b*.tlh%3b*.tmp%3b*.rsp%3b*.bat%3b*.map%3b*.pch%3b$(TargetPath) + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + $(ProjectName)_vc2012d + $(ProjectName)_d + $(ProjectName)_vc2012 + + + + Disabled + Size + .\include;.\src;..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Use + $(ProjectName)_vc2012d.pdb + Level3 + ProgramDatabase + Default + + + /MACHINE:X86 %(AdditionalOptions) + $(ProjectName)_vc2012d.lib + + + copy $(TargetName).lib ..\dist\lib\win32\$(TargetName).lib /Y +copy $(TargetName).pdb ..\dist\lib\win32\$(TargetName).pdb /Y + + + + + MinSpace + Size + .\include;.\src;..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + false + Use + $(ProjectName)_vc2012.pdb + Level3 + ProgramDatabase + + + /MACHINE:X86 %(AdditionalOptions) + $(ProjectName)_vc2012.lib + + + copy $(TargetName).lib ..\dist\lib\win32\$(TargetName).lib /Y +copy $(TargetName).pdb ..\dist\lib\win32\$(TargetName).pdb /Y + + + + + .\include;.\src;..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;ACL_DLL;HTTP_DLL;HTTP_EXPORTS;ICMP_DLL;ICMP_EXPORTS;%(PreprocessorDefinitions) + MultiThreadedDLL + Use + $(ProjectName).pdb + ProgramDatabase + + + ws2_32.lib;lib_acl.lib;%(AdditionalDependencies) + $(ProjectName).dll + ..\lib_acl;%(AdditionalLibraryDirectories) + MachineX86 + + + copy $(TargetName).lib ..\dist\lib\win32\$(TargetName).lib /Y +copy $(TargetName).dll ..\dist\lib\win32\$(TargetName).dll /Y +copy $(TargetName).pdb ..\dist\lib\win32\$(TargetName).pdb /Y + + + + + + Disabled + .\include;.\src;..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;ACL_DLL;HTTP_DLL;HTTP_EXPORTS;ICMP_DLL;ICMP_EXPORTS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Use + $(ProjectName)_d.pdb + ProgramDatabase + + + ws2_32.lib;lib_acl_d.lib;%(AdditionalDependencies) + $(ProjectName)_d.dll + ..\lib_acl;%(AdditionalLibraryDirectories) + true + true + true + false + + + + + $(OutDir)$(TargetName).lib + MachineX86 + + + copy $(TargetName).lib ..\dist\lib\win32\$(TargetName).lib /Y +copy $(TargetName).dll ..\dist\lib\win32\$(TargetName).dll /Y +copy $(TargetName).pdb ..\dist\lib\win32\$(TargetName).pdb /Y + + + + + + + + + Create + Create + Create + Create + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib_protocol/lib_protocol_vc2012.vcxproj.filters b/lib_protocol/lib_protocol_vc2012.vcxproj.filters new file mode 100644 index 000000000..0267746ed --- /dev/null +++ b/lib_protocol/lib_protocol_vc2012.vcxproj.filters @@ -0,0 +1,163 @@ +锘 + + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx + + + {112f4d94-c098-4a94-bbc8-ee5abbc2e187} + cpp;c;cxx;rc;def;r;odl;idl;hpj;bat + + + {16b35991-96a0-4a5c-9342-60b9c54a9ddf} + + + {cba2cd1e-331b-43e7-b2b0-7b3f12a11f6d} + + + {0089ea56-3dab-4e03-8a93-d86523b2d3e0} + + + {0c7db2e6-7635-418f-9252-218a91894992} + + + {63bcbe09-2abf-4583-9827-73c1fbe6987a} + + + {32468a59-0a82-4ab3-9c3a-424addc3a127} + + + {474743d2-f4d7-4525-8eb5-9bf65f7d6f21} + + + {0a4abcbb-914a-472f-b553-191ecd38ffe5} + + + + + 璧勬簮鏂囦欢 + + + + + Source Files + + + Source Files\http + + + Source Files\http + + + Source Files\http + + + Source Files\http + + + Source Files\http + + + Source Files\http + + + Source Files\http + + + Source Files\http + + + Source Files\http + + + Source Files\http + + + Source Files\http + + + Source Files\http + + + Source Files\http + + + Source Files\icmp + + + Source Files\icmp + + + Source Files\icmp + + + Source Files\icmp + + + Source Files\icmp + + + Source Files\icmp + + + Source Files\icmp + + + Source Files\icmp + + + Source Files\icmp + + + Source Files + + + Source Files\smtp + + + + + Source Files + + + Source Files\http + + + Source Files\icmp + + + Source Files\icmp + + + Header Files + + + Header Files\http + + + Header Files\http + + + Header Files\http + + + Header Files\http + + + Header Files\icmp + + + Header Files\icmp + + + Header Files\smtp + + + + + doc + + + + \ No newline at end of file diff --git a/lib_protocol/resource.h b/lib_protocol/resource.h new file mode 100644 index 000000000..ba50f7015 --- /dev/null +++ b/lib_protocol/resource.h @@ -0,0 +1,14 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by lib_protocol.rc + +// 新对象的下一些默认值 +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/lib_protocol/src/StdAfx.c b/lib_protocol/src/StdAfx.c new file mode 100644 index 000000000..45cf0e1b9 --- /dev/null +++ b/lib_protocol/src/StdAfx.c @@ -0,0 +1,2 @@ +#include "StdAfx.h" + diff --git a/lib_protocol/src/StdAfx.h b/lib_protocol/src/StdAfx.h new file mode 100644 index 000000000..bd0f74e41 --- /dev/null +++ b/lib_protocol/src/StdAfx.h @@ -0,0 +1,22 @@ +#ifndef __STD_AFX_INCLUDE_H__ +#define __STD_AFX_INCLUDE_H__ + +# ifdef WIN32 +# include +# include +# ifdef __STDC_WANT_SECURE_LIB__ +int proto_secure_snprintf(char *buf, size_t size, const char *fmt, ...); +int proto_securev_snprintf(char *buf, size_t size, const char *fmt, va_list ap); +# define snprintf proto_secure_snprintf +# define vsnprintf proto_securev_snprintf +# else +# ifndef snprintf +# define snprintf _snprintf +# endif +# ifndef vsnprintf +# define vsnprintf _vsnprintf +# endif +# endif +# endif /* WIN2 */ +#include "lib_acl.h" +#endif diff --git a/lib_protocol/src/http/http.h b/lib_protocol/src/http/http.h new file mode 100644 index 000000000..f418b2de2 --- /dev/null +++ b/lib_protocol/src/http/http.h @@ -0,0 +1,11 @@ +#ifndef __HTTP_INCLUDE_H__ +#define __HTTP_INCLUDE_H__ + +#include "http/lib_http_struct.h" + +#define HTTP_BSIZE 8192 + +extern http_off_t var_http_buf_size; +extern int var_http_tls_cache; + +#endif diff --git a/lib_protocol/src/http/http_chat_async.c b/lib_protocol/src/http/http_chat_async.c new file mode 100644 index 000000000..78fb1123a --- /dev/null +++ b/lib_protocol/src/http/http_chat_async.c @@ -0,0 +1,507 @@ +#include "StdAfx.h" +#include +#include +#include + +#include "http/lib_http.h" +#include "http.h" + +/* 标识是请求还是响应 */ +typedef enum { CTX_TYPE_REQ, CTX_TYPE_RES } ctx_type; + +typedef struct HTTP_CHAT_CTX { + HTTP_HDR *hdr; /**< 通用HTTP头(请求头或响应头) */ + ACL_ASTREAM *stream; /**< 流指针 */ + int timeout; /**< 读写超时时间,秒 */ + int chunked; /**< 是否是块传输模式 */ + ctx_type type; /**< 仅为了调试方便 */ + int status; /**< 当前所处IO状态 */ +#define CHAT_S_HDR (1 << 0) /**< 读 HTTP 头 */ +#define CHAT_S_CHUNK_HDR (1 << 1) /**< 读 chunk 头 */ +#define CHAT_S_CHUNK_DAT (1 << 2) /**< 读 chunk 体 */ +#define CHAT_S_CHUNK_SEP (1 << 3) /**< 读 chunk 体分隔行 */ +#define CHAT_S_CHUNK_TAL (1 << 4) /**< 读结束尾 */ + + http_off_t chunk_len; /**< 当前数据块所需要读的数据长度(字节) */ + http_off_t read_cnt; /**< 当前数据块所读数据长度(字节) */ + http_off_t body_len; /**< 所读到数据体总长度(字节) */ + union { + HTTP_HDR_NOTIFY hdr_notify; /**< 数据头回调函数 */ + HTTP_BODY_NOTIFY body_notify; /**< 数据体回调函数 */ + } notify; /**< 回调函数 */ + void *arg; /**< 回调参数 */ +} HTTP_CHAT_CTX; + +#define HTTP_LEN_ROUND(_ctx) \ + (_ctx->chunk_len > 0 ? \ + (_ctx->chunk_len - _ctx->read_cnt > var_http_buf_size ? \ + var_http_buf_size : _ctx->chunk_len - _ctx->read_cnt) \ + : var_http_buf_size) + +#if 1 +#define DISABLE_READ(x) do { \ + acl_aio_disable_read((x)); \ +} while (0) +#else +#define DISABLE_READ (void) +#endif +/*----------------------------------------------------------------------------*/ +static HTTP_CHAT_CTX *new_ctx(ctx_type type) +{ + const char *myname = "__new_ctx"; + HTTP_CHAT_CTX *ctx; + + ctx = (HTTP_CHAT_CTX*) acl_mycalloc(1, sizeof(HTTP_CHAT_CTX)); + if (ctx == NULL) { + acl_msg_fatal("%s, %s(%d): calloc error(%s)", + __FILE__, myname, __LINE__, acl_last_serror()); + } + + ctx->type = type; + return (ctx); +} + +static void free_ctx_fn(void *ctx) +{ + acl_myfree(ctx); +} + +/*----------------------------------------------------------------------------*/ + +/* 分析一行数据, 是否是一个完整的HTTP协议头 */ + +static int hdr_ready(HTTP_HDR *hdr, char *line, int dlen) +{ + const char *myname = "hdr_ready"; + HTTP_HDR_ENTRY *entry; + + hdr->cur_lines++; + if (hdr->max_lines > 0 && hdr->cur_lines > hdr->max_lines) { + acl_msg_error("%s(%d): cur_lines(%d) > max_lines(%d)", + myname, __LINE__, hdr->cur_lines, hdr->max_lines); + return (HTTP_CHAT_ERR_TOO_MANY_LINES); + } + + if (dlen > 0) + hdr->valid_lines++; + + if (dlen == 0) { + if (hdr->valid_lines > 0) + return (HTTP_CHAT_OK); + else + return (HTTP_CHAT_CONTINUE); + } + + if (hdr->valid_lines == 1) + entry = http_hdr_entry_head(line); + else + entry = http_hdr_entry_new2(line); + if (entry == NULL) { /* ignore invalid entry line */ + return (HTTP_CHAT_CONTINUE); + } + + http_hdr_append_entry(hdr, entry); + return (HTTP_CHAT_CONTINUE); +} + +/* 异步读取一行数据的回调函数 */ + +static int hdr_gets_ready(ACL_ASTREAM *astream, void *context, + char *data, int dlen) +{ + HTTP_CHAT_CTX *ctx = (HTTP_CHAT_CTX *) context; + HTTP_HDR *hdr = ctx->hdr; + HTTP_HDR_NOTIFY notify = ctx->notify.hdr_notify; + void *arg = ctx->arg; + ACL_VSTRING *sbuf; + int ret; + + while (1) { + ret = hdr_ready(hdr, data, dlen); + switch (ret) { + case HTTP_CHAT_CONTINUE: + break; + case HTTP_CHAT_OK: + acl_aio_del_read_hook(astream, hdr_gets_ready, context); + if (notify(ret, arg) < 0) { + return (-1); + } + return (0); + default: + acl_aio_del_read_hook(astream, hdr_gets_ready, context); + (void) notify(ret, arg); + return (-1); + } + sbuf = acl_aio_gets_nonl_peek(astream); + if (sbuf == NULL) + break; + data = acl_vstring_str(sbuf); + dlen = (int) ACL_VSTRING_LEN(sbuf); + ACL_VSTRING_RESET(sbuf); + } + + acl_aio_gets_nonl(astream); + return (0); +} + +static int hdr_can_read(ACL_ASTREAM *astream, void *context) +{ + HTTP_CHAT_CTX *ctx = (HTTP_CHAT_CTX *) context; + HTTP_HDR *hdr = ctx->hdr; + HTTP_HDR_NOTIFY notify = ctx->notify.hdr_notify; + void *arg = ctx->arg; + ACL_VSTRING *sbuf; + char *data; + int dlen; + int ret; + + while (1) { + if ((ret = acl_aio_can_read(astream)) == ACL_VSTREAM_EOF) { + notify(HTTP_CHAT_ERR_IO, arg); + return (-1); + } else if (ret == 0) { + break; + } + sbuf = acl_aio_gets_nonl_peek(astream); + if (sbuf == NULL) { + break; + } + data = acl_vstring_str(sbuf); + dlen = (int) ACL_VSTRING_LEN(sbuf); + ACL_VSTRING_RESET(sbuf); + + ret = hdr_ready(hdr, data, dlen); + switch (ret) { + case HTTP_CHAT_CONTINUE: + break; + case HTTP_CHAT_OK: + DISABLE_READ(astream); + if (notify(ret, arg) < 0) { + return (0); + } + return (0); + default: + DISABLE_READ(astream); + (void) notify(ret, arg); + return (0); + } + } + + acl_aio_enable_read(astream, hdr_can_read, ctx); + return (0); +} + +/* 异步读取一个完整的HTTP协议头 */ + +static void hdr_get_async(ctx_type type, HTTP_HDR *hdr, ACL_ASTREAM *astream, + HTTP_HDR_NOTIFY notify, void *arg, int timeout) +{ + const char *myname = "hdr_get_async"; + HTTP_CHAT_CTX *ctx; + ACL_VSTREAM *stream; + + if (hdr == NULL || astream == NULL || notify == NULL) + acl_msg_fatal("%s: input invalid", myname); + + stream = acl_aio_vstream(astream); + stream->rw_timeout = 0; /* bug fix, --zsx, 2007.7.7 */ + + if (hdr->chat_ctx == NULL) { + hdr->chat_ctx = new_ctx(type); + hdr->chat_free_ctx_fn = free_ctx_fn; + } + ctx = (HTTP_CHAT_CTX*) hdr->chat_ctx; + ctx->hdr = hdr; + ctx->timeout = timeout; + ctx->notify.hdr_notify = notify; + ctx->arg = arg; + ctx->status = CHAT_S_HDR; + + if (0) { + acl_aio_ctl(astream, + ACL_AIO_CTL_READ_HOOK_ADD, hdr_gets_ready, ctx, + ACL_AIO_CTL_TIMEOUT, timeout, + ACL_AIO_CTL_END); + acl_aio_gets_nonl(astream); + } else { + acl_aio_ctl(astream, ACL_AIO_CTL_TIMEOUT, timeout, + ACL_AIO_CTL_END); + acl_aio_enable_read(astream, hdr_can_read, ctx); + } +} + +void http_hdr_req_get_async(HTTP_HDR_REQ *hdr_req, ACL_ASTREAM *astream, + HTTP_HDR_NOTIFY notify, void *arg, int timeout) +{ + hdr_get_async(CTX_TYPE_REQ, &hdr_req->hdr, astream, notify, arg, timeout); +} + +void http_hdr_res_get_async(HTTP_HDR_RES *hdr_res, ACL_ASTREAM *astream, + HTTP_HDR_NOTIFY notify, void *arg, int timeout) +{ + hdr_get_async(CTX_TYPE_RES, &hdr_res->hdr, astream, notify, arg, timeout); +} + +/*------------------------ read http body data -------------------------------*/ + +/* 当读到块数据体中的最后一个分隔行时的回调函数 */ + +static int chunked_data_endl(ACL_ASTREAM *astream, HTTP_CHAT_CTX *ctx) +{ + HTTP_BODY_NOTIFY notify = ctx->notify.body_notify; + void *arg = ctx->arg; + ACL_VSTRING *sbuf; + char *data; + int dlen; + + sbuf = acl_aio_gets_peek(astream); + if (sbuf == NULL) + return (0); + + data = acl_vstring_str(sbuf); + dlen = (int) ACL_VSTRING_LEN(sbuf); + ACL_VSTRING_RESET(sbuf); + + ctx->body_len += dlen; + + if (notify(HTTP_CHAT_CHUNK_DATA_ENDL, data, dlen, arg) < 0) + return (-1); + ctx->status = CHAT_S_CHUNK_HDR; + return (0); +} + +static int chunked_data(ACL_ASTREAM *astream, HTTP_CHAT_CTX *ctx) +{ + HTTP_BODY_NOTIFY notify = ctx->notify.body_notify; + void *arg = ctx->arg; + ACL_VSTRING *sbuf; + char *data; + int dlen, ret; + + if (ctx->chunked) { + ret = (int) HTTP_LEN_ROUND(ctx); + sbuf = acl_aio_readn_peek(astream, ret); + } else if (ctx->hdr->content_length <= 0) { + sbuf = acl_aio_read_peek(astream); + } else { + ret = (int) HTTP_LEN_ROUND(ctx); + sbuf = acl_aio_readn_peek(astream, ret); + } + + if (sbuf == NULL) { + return (0); + } + + data = acl_vstring_str(sbuf); + dlen = (int) ACL_VSTRING_LEN(sbuf); + ACL_VSTRING_RESET(sbuf); + + ctx->body_len += dlen; + ctx->read_cnt += dlen; + + if (ctx->chunk_len > 0 && ctx->read_cnt >= ctx->chunk_len) { + if (!ctx->chunked) { + /* xxx: 禁止连续读 */ + DISABLE_READ(astream); + if (notify(HTTP_CHAT_OK, data, dlen, arg) < 0) + return (-1); + return (1); + } + + if (notify(HTTP_CHAT_DATA, data, dlen, arg) < 0) + return (-1); + + /* 设置标志位开始读取块数据体的分隔行数据 */ + ctx->status = CHAT_S_CHUNK_SEP; + return (0); + } + + if (notify(HTTP_CHAT_DATA, data, dlen, arg) < 0) + return (-1); + return (0); +} + +static int chunked_trailer(ACL_ASTREAM *astream, HTTP_CHAT_CTX *ctx) +{ + HTTP_BODY_NOTIFY notify = ctx->notify.body_notify; + void *arg = ctx->arg; + ACL_VSTRING *sbuf; + char *data; + int dlen; + + sbuf = acl_aio_gets_peek(astream); + if (sbuf == NULL) + return (0); + + data = acl_vstring_str(sbuf); + dlen = (int) ACL_VSTRING_LEN(sbuf); + ACL_VSTRING_RESET(sbuf); + + ctx->body_len += dlen; + + if (strcmp(data, "\r\n") == 0 || strcmp(data, "\n") == 0) { + DISABLE_READ(astream); + if ((dlen = notify(HTTP_CHAT_OK, data, dlen, arg)) < 0) + return (-1); + return (1); + } + if (notify(HTTP_CHAT_CHUNK_TRAILER, data, dlen, arg) < 0) + return (-1); + return (0); +} + +static int chunked_hdr(ACL_ASTREAM *astream, HTTP_CHAT_CTX *ctx) +{ + HTTP_BODY_NOTIFY notify = ctx->notify.body_notify; + void *arg = ctx->arg; + ACL_VSTRING *sbuf; + char *data, *ptr; + int dlen; + + sbuf = acl_aio_gets_peek(astream); + if (sbuf == NULL) + return (0); + + data = acl_vstring_str(sbuf); + dlen = (int) ACL_VSTRING_LEN(sbuf); + ACL_VSTRING_RESET(sbuf); + + ctx->body_len += dlen; + ctx->read_cnt = 0; + + ptr = strchr(data, ' '); + if (ptr) + *ptr = 0; + ctx->chunk_len = strtoul(data, NULL, 16); + if (ptr) + *ptr = ' '; + + if (notify(HTTP_CHAT_CHUNK_HDR, data, dlen, arg) < 0) + return (-1); + + if (ctx->chunk_len == 0) { + ctx->status = CHAT_S_CHUNK_TAL; + return (0); + } + + ctx->status = CHAT_S_CHUNK_DAT; + return (0); +} + +static int body_can_read(ACL_ASTREAM *astream, void *context) +{ + const char *myname = "body_can_read"; + HTTP_CHAT_CTX *ctx = (HTTP_CHAT_CTX*) context; + HTTP_BODY_NOTIFY notify = ctx->notify.body_notify; + void *arg = ctx->arg; + int ret; + + while (1) { + if ((ret = acl_aio_can_read(astream)) == ACL_VSTREAM_EOF) { + (void) notify(HTTP_CHAT_ERR_IO, NULL, 0, arg); + return (-1); + } else if (ret == 0) { + break; + } + + switch (ctx->status) { + case CHAT_S_CHUNK_HDR: + ret = chunked_hdr(astream, ctx); + break; + case CHAT_S_CHUNK_DAT: + ret = chunked_data(astream, ctx); + break; + case CHAT_S_CHUNK_SEP: + ret = chunked_data_endl(astream, ctx); + break; + case CHAT_S_CHUNK_TAL: + ret = chunked_trailer(astream, ctx); + break; + default: + acl_msg_error("%s(%d): unknown status(%d)", + myname, __LINE__, ctx->status); + return (-1); + } + if (ret < 0) { + return (-1); + } else if (ret == 1) { + return (0); + } + } + + acl_aio_enable_read(astream, body_can_read, ctx); + return (0); +} + +static void body_get(ACL_ASTREAM *astream, HTTP_CHAT_CTX *ctx) +{ + if (ctx->chunked) + ctx->status = CHAT_S_CHUNK_HDR; + else + ctx->status = CHAT_S_CHUNK_DAT; + + acl_aio_enable_read(astream, body_can_read, ctx); +} + +void http_req_body_get_async(HTTP_REQ *request, ACL_ASTREAM *astream, + HTTP_BODY_NOTIFY notify, void *arg, int timeout) +{ + const char *myname = "http_req_body_get_async"; + HTTP_CHAT_CTX *ctx; + HTTP_HDR *hdr; + + if (request == NULL || astream == NULL || notify == NULL) + acl_msg_fatal("%s: input invalid", myname); + if (request->hdr_req == NULL) + acl_msg_fatal("%s: hdr null", myname); + + hdr = &(request->hdr_req->hdr); + if (hdr->content_length <= 0) { + acl_msg_warn("%s: content_length(%lld)", myname, hdr->content_length); + } + + ctx = request->hdr_req->hdr.chat_ctx; + ctx->hdr = hdr; + ctx->stream = astream; + ctx->timeout = timeout; + ctx->chunk_len = hdr->content_length; + ctx->chunked = 0; + ctx->notify.body_notify = notify; + ctx->arg = arg; + ctx->body_len = 0; + + body_get(astream, ctx); +} + +void http_res_body_get_async(HTTP_RES *respond, ACL_ASTREAM *astream, + HTTP_BODY_NOTIFY notify, void *arg, int timeout) +{ + const char *myname = "http_res_body_get_async"; + HTTP_CHAT_CTX *ctx; + HTTP_HDR *hdr; + + if (respond == NULL || astream == NULL || notify == NULL) + acl_msg_fatal("%s, %s(%d): input invalid", myname, __FILE__, __LINE__); + if (respond->hdr_res == NULL) + acl_msg_fatal("%s: hdr null", myname); + + hdr = &(respond->hdr_res->hdr); + if (hdr->debug && hdr->content_length <= 0 && !hdr->chunked) { + acl_msg_warn("%s, %s(%d): content_length(%lld), status(%d)", + __FILE__, myname, __LINE__, + hdr->content_length, respond->hdr_res->reply_status); + } + + ctx = respond->hdr_res->hdr.chat_ctx; + ctx->hdr = hdr; + ctx->stream = astream; + ctx->timeout = timeout; + ctx->chunk_len = hdr->content_length; + ctx->chunked = hdr->chunked; + ctx->notify.body_notify = notify; + ctx->arg = arg; + ctx->body_len = 0; + + body_get(astream, ctx); +} +/*----------------------------------------------------------------------------*/ diff --git a/lib_protocol/src/http/http_chat_async.c.bak b/lib_protocol/src/http/http_chat_async.c.bak new file mode 100644 index 000000000..e042454a3 --- /dev/null +++ b/lib_protocol/src/http/http_chat_async.c.bak @@ -0,0 +1,482 @@ + +#include "lib_acl.h" +#include +#include +#include +#include + +#ifdef ACL_BCB_COMPILER +#pragma hdrstop +#endif +#include "http/lib_http.h" +#include "http.h" + +/* 标识是请求还是响应 */ +typedef enum { CTX_TYPE_REQ, CTX_TYPE_RES } ctx_type; + +typedef struct HTTP_CHAT_CTX { + HTTP_HDR *hdr; /**< 通用HTTP头(请求头或响应头) */ + ACL_ASTREAM *stream; /**< 流指针 */ + int timeout; /**< 读写超时时间,秒 */ + int chunked; /**< 是否是块传输模式 */ + ctx_type type; /**< 仅为了调试方便 */ + int status; /**< 当前所处IO状态 */ +#define CHAT_S_HDR (1 << 0) /**< 读 HTTP 头 */ +#define CHAT_S_CHUNK_HDR (1 << 1) /**< 读 chunk 头 */ +#define CHAT_S_CHUNK_DAT (1 << 2) /**< 读 chunk 体 */ +#define CHAT_S_CHUNK_SEP (1 << 3) /**< 读 chunk 体分隔行 */ +#define CHAT_S_CHUNK_TAL (1 << 4) /**< 读结束尾 */ + + http_off_t chunk_len; /**< 当前数据块所需要读的数据长度(字节) */ + http_off_t read_cnt; /**< 当前数据块所读数据长度(字节) */ + http_off_t body_len; /**< 所读到数据体总长度(字节) */ + union { + HTTP_HDR_NOTIFY hdr_notify; /**< 数据头回调函数 */ + HTTP_BODY_NOTIFY body_notify; /**< 数据体回调函数 */ + } notify; /**< 回调函数 */ + void *arg; /**< 回调参数 */ +} HTTP_CHAT_CTX; + +#define HTTP_LEN_ROUND(_ctx) \ + (_ctx->chunk_len > 0 ? \ + (_ctx->chunk_len - _ctx->read_cnt > var_http_buf_size ? \ + var_http_buf_size : _ctx->chunk_len - _ctx->read_cnt) \ + : var_http_buf_size) + +/*----------------------------------------------------------------------------*/ +static HTTP_CHAT_CTX *new_ctx(ctx_type type) +{ + const char *myname = "__new_ctx"; + HTTP_CHAT_CTX *ctx; + + ctx = (HTTP_CHAT_CTX*) acl_mycalloc(1, sizeof(HTTP_CHAT_CTX)); + if (ctx == NULL) { + acl_msg_fatal("%s, %s(%d): calloc error(%s)", + __FILE__, myname, __LINE__, acl_last_serror()); + } + + ctx->type = type; + return (ctx); +} + +static void free_ctx_fn(void *ctx) +{ + acl_myfree(ctx); +} + +/*----------------------------------------------------------------------------*/ + +/* 分析一行数据, 是否是一个完整的HTTP协议头 */ + +static int hdr_ready(HTTP_HDR *hdr, const char *line, int dlen) +{ + const char *myname = "hdr_ready"; + HTTP_HDR_ENTRY *entry; + + hdr->cur_lines++; + if (hdr->max_lines > 0 && hdr->cur_lines > hdr->max_lines) { + acl_msg_error("%s(%d): cur_lines(%d) > max_lines(%d)", + myname, __LINE__, hdr->cur_lines, hdr->max_lines); + return (HTTP_CHAT_ERR_TOO_MANY_LINES); + } + + if (dlen > 0) + hdr->valid_lines++; + + if (dlen == 0) { + if (hdr->valid_lines > 0) + return (HTTP_CHAT_OK); + else + return (HTTP_CHAT_CONTINUE); + } + + entry = http_hdr_entry_new(line); + if (entry == NULL) { /* ignore invalid entry line */ + return (HTTP_CHAT_CONTINUE); + } + + http_hdr_append_entry(hdr, entry); + return (HTTP_CHAT_CONTINUE); +} + +/* 异步读取一行数据的回调函数 */ + +static int hdr_gets_ready(ACL_ASTREAM *astream, void *context, + const char *data, int dlen) +{ + HTTP_CHAT_CTX *ctx = (HTTP_CHAT_CTX *) context; + HTTP_HDR *hdr = ctx->hdr; + HTTP_HDR_NOTIFY notify = ctx->notify.hdr_notify; + void *arg = ctx->arg; + ACL_VSTRING *sbuf; + int ret; + + while (1) { + ret = hdr_ready(hdr, data, dlen); + switch (ret) { + case HTTP_CHAT_CONTINUE: + break; + case HTTP_CHAT_OK: + acl_aio_del_read_hook(astream, hdr_gets_ready, context); + if (notify(ret, arg) < 0) { + return (-1); + } + return (0); + default: + acl_aio_del_read_hook(astream, hdr_gets_ready, context); + (void) notify(ret, arg); + return (-1); + } + sbuf = acl_aio_gets_nonl_peek(astream); + if (sbuf == NULL) + break; + data = acl_vstring_str(sbuf); + dlen = (int) ACL_VSTRING_LEN(sbuf); + ACL_VSTRING_RESET(sbuf); + } + + acl_aio_gets_nonl(astream); + return (0); +} + +static int hdr_can_read(ACL_ASTREAM *astream, void *context) +{ + HTTP_CHAT_CTX *ctx = (HTTP_CHAT_CTX *) context; + HTTP_HDR *hdr = ctx->hdr; + HTTP_HDR_NOTIFY notify = ctx->notify.hdr_notify; + void *arg = ctx->arg; + ACL_VSTRING *sbuf; + const char *data; + int dlen; + int ret; + + while (1) { + if ((ret = acl_aio_can_read(astream)) == ACL_VSTREAM_EOF) { + notify(HTTP_CHAT_ERR_IO, arg); + return (-1); + } else if (ret == 0) { + break; + } + sbuf = acl_aio_gets_nonl_peek(astream); + if (sbuf == NULL) { + break; + } + data = acl_vstring_str(sbuf); + dlen = (int) ACL_VSTRING_LEN(sbuf); + ACL_VSTRING_RESET(sbuf); + + ret = hdr_ready(hdr, data, dlen); + switch (ret) { + case HTTP_CHAT_CONTINUE: + break; + case HTTP_CHAT_OK: + acl_aio_disable_read(astream); + if (notify(ret, arg) < 0) { + return (-1); + } + return (0); + default: + acl_aio_disable_read(astream); + (void) notify(ret, arg); + return (-1); + } + } + + acl_aio_enable_read(astream, hdr_can_read, ctx); + return (0); +} + +/* 异步读取一个完整的HTTP协议头 */ + +static void hdr_get_async(ctx_type type, HTTP_HDR *hdr, ACL_ASTREAM *astream, + HTTP_HDR_NOTIFY notify, void *arg, int timeout) +{ + const char *myname = "hdr_get_async"; + HTTP_CHAT_CTX *ctx; + ACL_VSTREAM *stream; + + if (hdr == NULL || astream == NULL || notify == NULL) + acl_msg_fatal("%s: input invalid", myname); + + stream = acl_aio_vstream(astream); + stream->rw_timeout = 0; /* bug fix, --zsx, 2007.7.7 */ + + if (hdr->chat_ctx == NULL) { + hdr->chat_ctx = new_ctx(type); + hdr->chat_free_ctx_fn = free_ctx_fn; + } + ctx = (HTTP_CHAT_CTX*) hdr->chat_ctx; + ctx->hdr = hdr; + ctx->timeout = timeout; + ctx->notify.hdr_notify = notify; + ctx->arg = arg; + ctx->status = CHAT_S_HDR; + + if (0) { + acl_aio_ctl(astream, + ACL_AIO_CTL_READ_HOOK_ADD, hdr_gets_ready, ctx, + ACL_AIO_CTL_TIMEOUT, timeout, + ACL_AIO_CTL_END); + acl_aio_gets_nonl(astream); + } else { + acl_aio_ctl(astream, + ACL_AIO_CTL_TIMEOUT, timeout, + ACL_AIO_CTL_END); + acl_aio_enable_read(astream, hdr_can_read, ctx); + } +} + +void http_hdr_req_get_async(HTTP_HDR_REQ *hdr_req, ACL_ASTREAM *astream, + HTTP_HDR_NOTIFY notify, void *arg, int timeout) +{ + hdr_get_async(CTX_TYPE_REQ, &hdr_req->hdr, astream, notify, arg, timeout); +} + +void http_hdr_res_get_async(HTTP_HDR_RES *hdr_res, ACL_ASTREAM *astream, + HTTP_HDR_NOTIFY notify, void *arg, int timeout) +{ + hdr_get_async(CTX_TYPE_RES, &hdr_res->hdr, astream, notify, arg, timeout); +} + +/*------------------------ read http body data -------------------------------*/ + +/* 当读到块数据体中的最后一个分隔行时的回调函数 */ + +static int chunked_data_endl(ACL_ASTREAM *astream, HTTP_CHAT_CTX *ctx, + const char *data, int dlen) +{ + HTTP_BODY_NOTIFY notify = ctx->notify.body_notify; + void *arg = ctx->arg; + + ctx->body_len += dlen; + + if (notify(HTTP_CHAT_CHUNK_DATA_ENDL, data, dlen, arg) < 0) + return (-1); + ctx->status = CHAT_S_CHUNK_HDR; + acl_aio_gets(astream); + return (0); +} + +static int chunked_data(ACL_ASTREAM *astream, HTTP_CHAT_CTX *ctx, + const char *data, int dlen) +{ + const char *myname = "chunked_data"; + HTTP_BODY_NOTIFY notify = ctx->notify.body_notify; + void *arg = ctx->arg; + + ctx->body_len += dlen; + ctx->read_cnt += dlen; + + if (ctx->chunk_len > 0 && ctx->read_cnt >= ctx->chunk_len) { + if (!ctx->chunked) { + return (notify(HTTP_CHAT_OK, data, dlen, arg)); + } + + if (notify(HTTP_CHAT_DATA, data, dlen, arg) < 0) + return (-1); + + ctx->status = CHAT_S_CHUNK_SEP; + /* 开始读取块数据体的分隔行数据 */ + acl_aio_gets(astream); + return (0); + } + + if (notify(HTTP_CHAT_DATA, data, dlen, arg) < 0) + return (-1); + + if (!ctx->chunked && ctx->hdr->content_length <= 0) { + acl_aio_read(astream); + } else { + http_off_t ret = HTTP_LEN_ROUND(ctx); + + if (ret <= 0) + acl_msg_fatal("%s(%d), %s: ret: %d invalid", + __FILE__, __LINE__, myname, (int) ret); + acl_aio_readn(astream, (int) ret); + } + return (0); +} + +static int chunked_trailer(ACL_ASTREAM *astream, HTTP_CHAT_CTX *ctx, + const char *data, int dlen) +{ + HTTP_BODY_NOTIFY notify = ctx->notify.body_notify; + void *arg = ctx->arg; + + ctx->body_len += dlen; + + if (strcmp(data, "\r\n") == 0 || strcmp(data, "\n") == 0) { + if (notify(HTTP_CHAT_OK, data, dlen, arg) < 0) + return (-1); + return (1); + } + if (notify(HTTP_CHAT_CHUNK_TRAILER, data, dlen, arg) < 0) + return (-1); + acl_aio_gets(astream); + return (0); +} + +static int chunked_hdr(ACL_ASTREAM *astream, HTTP_CHAT_CTX *ctx, + const char *data, int dlen) +{ + const char *myname = "chunked_hdr"; + HTTP_BODY_NOTIFY notify = ctx->notify.body_notify; + void *arg = ctx->arg; + char *pext = NULL; + int ret; + int chunk_len; + + ctx->body_len += dlen; + ctx->chunk_len = 0; + ctx->read_cnt = 0; + + if (notify(HTTP_CHAT_CHUNK_HDR, data, dlen, arg) < 0) + return (-1); + + ret = sscanf(data, "%X %s", (unsigned int *) &chunk_len, pext); + if (ret < 0 || chunk_len < 0) { + (void) notify(HTTP_CHAT_ERR_PROTO, data, dlen, arg); + return (-1); + } + ctx->chunk_len = chunk_len; + + if (ctx->chunk_len == 0) { + ctx->status = CHAT_S_CHUNK_TAL; + acl_aio_gets(astream); + return (0); + } + + ctx->status = CHAT_S_CHUNK_DAT; + ret = (int) HTTP_LEN_ROUND(ctx); + if (ret > 0) { + acl_aio_readn(astream, ret); + return (0); + } + + acl_msg_warn("%s(%d), %s: ret: %d invalid", + __FILE__, __LINE__, myname, ret); + (void) notify(HTTP_CHAT_ERR_PROTO, data, dlen, arg); + return (-1); +} + +static int body_get_ready(ACL_ASTREAM *astream, void *context, + const char *data, int dlen) +{ + HTTP_CHAT_CTX *ctx = (HTTP_CHAT_CTX*) context; + int ret; + + if (ctx->chunked) { + switch (ctx->status) { + case CHAT_S_CHUNK_HDR: + ret = chunked_hdr(astream, ctx, data, dlen); + break; + case CHAT_S_CHUNK_DAT: + ret = chunked_data(astream, ctx, data, dlen); + break; + case CHAT_S_CHUNK_SEP: + ret = chunked_data_endl(astream, ctx, data, dlen); + break; + case CHAT_S_CHUNK_TAL: + ret = chunked_trailer(astream, ctx, data, dlen); + break; + default: + ret = -1; + break; + } + } else { + ret = chunked_data(astream, ctx, data, dlen); + } + + if (ret != 0) { + acl_aio_del_read_hook(astream, body_get_ready, ctx); + } + return (0); +} + +static void body_get(ACL_ASTREAM *astream, HTTP_CHAT_CTX *ctx) +{ + const char *myname = "body_get"; + http_off_t ret; + + acl_aio_add_read_hook(astream, body_get_ready, ctx); + + if (ctx->chunked) { + ctx->status = CHAT_S_CHUNK_HDR; + acl_aio_gets(astream); + return; + } + + ctx->status = CHAT_S_CHUNK_DAT; + if (ctx->hdr->content_length <= 0) { + acl_aio_read(astream); + } else { + ret = HTTP_LEN_ROUND(ctx); + if (ret <= 0) + acl_msg_fatal("%s(%d), %s: read count(%d) invalid", + __FILE__, __LINE__, myname, ret); + acl_aio_readn(astream, (int) ret); + } +} + +void http_req_body_get_async(HTTP_REQ *request, ACL_ASTREAM *astream, + HTTP_BODY_NOTIFY notify, void *arg, int timeout) +{ + const char *myname = "http_req_body_get_async"; + HTTP_CHAT_CTX *ctx; + HTTP_HDR *hdr; + + if (request == NULL || astream == NULL || notify == NULL) + acl_msg_fatal("%s: input invalid", myname); + if (request->hdr_req == NULL) + acl_msg_fatal("%s: hdr null", myname); + + hdr = &(request->hdr_req->hdr); + if (hdr->content_length <= 0) { + acl_msg_warn("%s: content_length(%d)", myname, hdr->content_length); + } + + ctx = request->hdr_req->hdr.chat_ctx; + ctx->hdr = hdr; + ctx->stream = astream; + ctx->timeout = timeout; + ctx->chunk_len = hdr->content_length; + ctx->chunked = 0; + ctx->notify.body_notify = notify; + ctx->arg = arg; + ctx->body_len = 0; + + body_get(astream, ctx); +} + +void http_res_body_get_async(HTTP_RES *respond, ACL_ASTREAM *astream, + HTTP_BODY_NOTIFY notify, void *arg, int timeout) +{ + const char *myname = "http_res_body_get_async"; + HTTP_CHAT_CTX *ctx; + HTTP_HDR *hdr; + + if (respond == NULL || astream == NULL || notify == NULL) + acl_msg_fatal("%s, %s(%d): input invalid", myname); + if (respond->hdr_res == NULL) + acl_msg_fatal("%s: hdr null", myname); + + hdr = &(respond->hdr_res->hdr); + if (hdr->debug && hdr->content_length <= 0 && !hdr->chunked) { + acl_msg_warn("%s, %s(%d): content_length(%d), status(%d)", + __FILE__, myname, __LINE__, + hdr->content_length, respond->hdr_res->reply_status); + } + + ctx = respond->hdr_res->hdr.chat_ctx; + ctx->hdr = hdr; + ctx->stream = astream; + ctx->timeout = timeout; + ctx->chunk_len = hdr->content_length; + ctx->chunked = hdr->chunked; + ctx->notify.body_notify = notify; + ctx->arg = arg; + ctx->body_len = 0; + + body_get(astream, ctx); +} +/*----------------------------------------------------------------------------*/ diff --git a/lib_protocol/src/http/http_chat_sync.c b/lib_protocol/src/http/http_chat_sync.c new file mode 100644 index 000000000..7c1e62a6b --- /dev/null +++ b/lib_protocol/src/http/http_chat_sync.c @@ -0,0 +1,366 @@ +#include "StdAfx.h" +#include +#include +#include + +#include "http/lib_http.h" +#include "http.h" + +typedef struct HTTP_CHAT_CTX { + HTTP_HDR *hdr; + ACL_VSTREAM *stream; + unsigned int flag; /**< 继承的标志位, defined as HTTP_CHAT_FLAG_XXX */ + int timeout; + int chunked; + http_off_t chunk_len; /**< 当前数据块所需要读的数据长度(字节) */ + http_off_t read_cnt; /**< 当前数据块所读数据长度(字节) */ + http_off_t body_len; /**< 所读到数据体总长度(字节) */ + union { + HTTP_HDR_NOTIFY hdr_notify; + HTTP_BODY_NOTIFY body_notify; + } notify; + void *arg; + struct { + int chunk_oper; +#define CHUNK_OPER_HEAD 1 +#define CHUNK_OPER_BODY 2 +#define CHUNK_OPER_LINE 3 +#define CHUNK_OPER_TAIL 4 + } chunk; +} HTTP_CHAT_CTX; + +/*----------------------------------------------------------------------------*/ +static HTTP_CHAT_CTX *new_ctx(void) +{ + const char *myname = "new_ctx"; + HTTP_CHAT_CTX *ctx; + + ctx = (HTTP_CHAT_CTX*) acl_mycalloc(1, sizeof(HTTP_CHAT_CTX)); + if (ctx == NULL) { + char ebuf[256]; + + acl_msg_fatal("%s, %s(%d): calloc error(%s)", + __FILE__, myname, __LINE__, acl_last_strerror(ebuf, sizeof(ebuf))); + } + + return (ctx); +} + +static void free_ctx(void *ctx) +{ + acl_myfree(ctx); +} + +/*----------------------------------------------------------------------------*/ +/* 分析一行数据, 是否是一个完整的HTTP协议头 */ + +static int hdr_ready(HTTP_HDR *hdr, const char *line, int dlen) +{ + HTTP_HDR_ENTRY *entry; + + hdr->cur_lines++; + if (hdr->max_lines > 0 && hdr->cur_lines > hdr->max_lines) + return (HTTP_CHAT_ERR_TOO_MANY_LINES); + + if (dlen > 0) + hdr->valid_lines++; + + if (dlen == 0) { + if (hdr->valid_lines > 0) + return (HTTP_CHAT_OK); + else + return (HTTP_CHAT_CONTINUE); + } + + entry = http_hdr_entry_new(line); + if (entry == NULL) /* ignore invalid entry line */ + return (HTTP_CHAT_CONTINUE); + + http_hdr_append_entry(hdr, entry); + return (HTTP_CHAT_CONTINUE); +} + +/* 同步读取一个完整的HTTP协议头 */ + +static int hdr_get(HTTP_HDR *hdr, ACL_VSTREAM *stream, int timeout) +{ + char buf[8192]; + int ret; + + stream->rw_timeout = timeout; + + while (1) { + ret = acl_vstream_gets_nonl(stream, buf, sizeof(buf) - 1); + if (ret == ACL_VSTREAM_EOF) + return (HTTP_CHAT_ERR_IO); + + ret = hdr_ready(hdr, buf, ret); + if (ret != HTTP_CHAT_CONTINUE) + break; + } + + /* ret: HTTP_CHAT_OK or error */ + return (ret); +} + +int http_hdr_req_get_sync(HTTP_HDR_REQ *hdr_req, ACL_VSTREAM *stream, int timeout) +{ + return (hdr_get(&hdr_req->hdr, stream, timeout) == HTTP_CHAT_OK ? 0 : -1); +} + +int http_hdr_res_get_sync(HTTP_HDR_RES *hdr_res, ACL_VSTREAM *stream, int timeout) +{ + return (hdr_get(&hdr_res->hdr, stream, timeout) == HTTP_CHAT_OK ? 0 : -1); +} +/*------------------------ read http body data -------------------------------*/ + +static http_off_t chunked_data_get(HTTP_CHAT_CTX *ctx, void *buf, int size) +{ + if (ctx->chunk_len > 0) { + char *ptr = buf; + http_off_t ntotal = 0, ret, n; + + n = ctx->chunk_len - ctx->read_cnt; + n = n > size ? size : n; + while (n > 0) { + ret = acl_vstream_read(ctx->stream, ptr, (size_t) n); + if (ret == ACL_VSTREAM_EOF) { + if (ntotal == 0) + ntotal = -1; + break; + } + ntotal += ret; + n -= ret; + ptr += ret; + ctx->body_len += ret; + ctx->read_cnt += ret; + if ((ctx->flag & HTTP_CHAT_FLAG_BUFFED) == 0) + break; + } + return (ntotal); + } else { + http_off_t ret; + + ret = acl_vstream_read(ctx->stream, buf, (size_t) size); + if (ret == ACL_VSTREAM_EOF) + return (-1); + ctx->body_len += ret; + ctx->read_cnt += ret; + return (ret); + } +} + +static int chunked_hdr_get(HTTP_CHAT_CTX *ctx) +{ + const char *myname = "chunked_hdr_get"; + char *pext = NULL; + char buf[HTTP_BSIZE]; + int ret, n, chunk_len; + + n = acl_vstream_gets(ctx->stream, buf, sizeof(buf)); + if (n == ACL_VSTREAM_EOF) + return (-1); + + ctx->read_cnt = 0; /* reset the len to be read */ + ctx->body_len += n; + + ret = sscanf(buf, "%X %s", (unsigned int *) &chunk_len, pext); + if (ret < 0 || chunk_len < 0) { + acl_msg_error("%s(%d): chunked hdr(%s) invalid, dlen(%d), '\\n': %d, %d", + myname, __LINE__, buf, n, buf[0], '\n'); + return (-1); + } + + ctx->chunk_len = chunk_len; + return (0); +} + +static int chunked_sep_gets(HTTP_CHAT_CTX *ctx) +{ + const char *myname = "chunked_sep_gets2"; + char buf[HTTP_BSIZE]; + int n; + + n = acl_vstream_gets(ctx->stream, buf, sizeof(buf)); + if (n == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): gets sep line error", myname, __LINE__); + return (-1); + } + + ctx->body_len += n; + return (0); +} + +static int chunked_trailer_get(HTTP_CHAT_CTX *ctx) +{ + const char *myname = "chunked_tailer_get2"; + char buf[HTTP_BSIZE]; + int n; + + while (1) { + n = acl_vstream_gets(ctx->stream, buf, sizeof(buf)); + if (n == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): get line error", myname, __LINE__); + return (-1); + } + ctx->body_len += n; + if (strcmp(buf, "\r\n") == 0 || strcmp(buf, "\n") == 0) + break; + } + + return (0); +} + +static http_off_t body_get(HTTP_CHAT_CTX *ctx, void *buf, int size) +{ + const char *myname = "body_get"; + http_off_t ret; + + /* Transfer-Encoding: chunked 的优先级要高于 Conteng-Length */ + + if (!ctx->chunked) { + if (ctx->chunk_len > 0 && ctx->read_cnt >= ctx->chunk_len) + return (0); + return (chunked_data_get(ctx, buf, size)); + } + + while (1) { + if (ctx->chunk.chunk_oper == CHUNK_OPER_HEAD) { + ret = chunked_hdr_get(ctx); + if (ret < 0) + return (-1); + if (ctx->chunk_len == 0) + ctx->chunk.chunk_oper = CHUNK_OPER_TAIL; + else + ctx->chunk.chunk_oper = CHUNK_OPER_BODY; + } else if (ctx->chunk.chunk_oper == CHUNK_OPER_BODY) { + ret = chunked_data_get(ctx, buf, size); + if (ret < 0) + return (-1); + if (ctx->read_cnt >= ctx->chunk_len) { + if (chunked_sep_gets(ctx) < 0) + return (-1); + ctx->chunk.chunk_oper = CHUNK_OPER_HEAD; + } + return (ret); + } else if (ctx->chunk.chunk_oper == CHUNK_OPER_TAIL) { + ret = chunked_trailer_get(ctx); + return (ret); + } else { + acl_msg_error("%s(%d): unknown oper status(%d)", + myname, __LINE__, ctx->chunk.chunk_oper); + return (-1); + } + } +} + +http_off_t http_req_body_get_sync(HTTP_REQ *request, ACL_VSTREAM *stream, + void *buf, int size) +{ + HTTP_CHAT_CTX *ctx; + + if (request->hdr_req->hdr.content_length == 0) { + /* 扩展了HTTP请求协议部分, 允许请求数据为块传输 */ + if (request->hdr_req->hdr.chunked == 0) + return (0); + } + + if (request->ctx == NULL) { + ctx = new_ctx(); + ctx->hdr = &request->hdr_req->hdr; + ctx->stream = stream; + + /* 扩展了HTTP请求协议部分, 允许请求数据为块传输 */ + ctx->chunked = request->hdr_req->hdr.chunked; + ctx->chunk_len = request->hdr_req->hdr.content_length; + ctx->body_len = 0; + ctx->read_cnt = 0; + request->ctx = (void*) ctx; + request->free_ctx = free_ctx; + } else + ctx = (HTTP_CHAT_CTX*) request->ctx; + + ctx->flag = request->flag; + return (body_get(ctx, buf, size)); +} + +http_off_t http_res_body_get_sync(HTTP_RES *respond, ACL_VSTREAM *stream, + void *buf, int size) +{ + HTTP_CHAT_CTX *ctx; + + if (respond->hdr_res->hdr.content_length == 0) { + /* 块传输协议优先于 content-length */ + if (respond->hdr_res->hdr.chunked == 0) + return (0); + } + + if (respond->ctx == NULL) { + ctx = new_ctx(); + ctx->hdr = &respond->hdr_res->hdr; + ctx->stream = stream; + ctx->chunked = respond->hdr_res->hdr.chunked; + ctx->chunk_len = respond->hdr_res->hdr.content_length; + ctx->body_len = 0; + ctx->read_cnt = 0; + if (ctx->chunked) + ctx->chunk.chunk_oper = CHUNK_OPER_HEAD; + respond->ctx = (void*) ctx; + respond->free_ctx = free_ctx; + } else + ctx = (HTTP_CHAT_CTX*) respond->ctx; + + ctx->flag = respond->flag; + return (body_get(ctx, buf, size)); +} + +void http_chat_sync_reqctl(HTTP_REQ *request, int name, ...) +{ + const char *myname = "http_chat_sync_reqctl"; + va_list ap; + int n; + + va_start(ap, name); + for (; name != HTTP_CHAT_SYNC_CTL_END; name = va_arg(ap, int)) { + switch (name) { + case HTTP_CHAT_CTL_BUFF_ONOFF: + n = va_arg(ap, int); + if (n) + request->flag |= HTTP_CHAT_FLAG_BUFFED; + else + request->flag &= ~HTTP_CHAT_FLAG_BUFFED; + break; + default: + acl_msg_panic("%s, %s(%d): bad name %d", + myname, __FILE__, __LINE__, name); + break; + } + } + va_end(ap); +} + +void http_chat_sync_resctl(HTTP_RES *respond, int name, ...) +{ + const char *myname = "http_chat_sync_resctl"; + va_list ap; + int n; + + va_start(ap, name); + for (; name != HTTP_CHAT_SYNC_CTL_END; name = va_arg(ap, int)) { + switch (name) { + case HTTP_CHAT_CTL_BUFF_ONOFF: + n = va_arg(ap, int); + if (n) + respond->flag |= HTTP_CHAT_FLAG_BUFFED; + else + respond->flag &= ~HTTP_CHAT_FLAG_BUFFED; + break; + default: + acl_msg_panic("%s, %s(%d): bad name %d", + myname, __FILE__, __LINE__, name); + break; + } + } + va_end(ap); +} +/*----------------------------------------------------------------------------*/ diff --git a/lib_protocol/src/http/http_hdr.c b/lib_protocol/src/http/http_hdr.c new file mode 100644 index 000000000..4c8ccf36e --- /dev/null +++ b/lib_protocol/src/http/http_hdr.c @@ -0,0 +1,592 @@ +#include "StdAfx.h" +#include +#include +#include + +#include "http/lib_http.h" + +static int __http_hdr_def_entry = 25; +static int __http_hdr_max_lines = 1024; + +/*-------------------------- for general http header -------------------------*/ +/* 生成一个新的 HTTP_HDR 数据结构 */ +static void __hdr_init(HTTP_HDR *hh) +{ + hh->max_lines = __http_hdr_max_lines; + hh->cur_lines = 0; + hh->valid_lines = 0; + hh->content_length = -1; + hh->chunked = 0; + hh->keep_alive = 0; +} + +/* 分配一个HTTP协议头的基础结构 */ + +HTTP_HDR *http_hdr_new(size_t size) +{ + const char *myname = "http_hdr_new"; + HTTP_HDR *hh; + + if (size != sizeof(HTTP_HDR_REQ) && size != sizeof(HTTP_HDR_RES)) + acl_msg_fatal("%s, %s(%d): size(%d) invalid", + __FILE__, myname, __LINE__, (int) size); + + hh = (HTTP_HDR*) acl_mycalloc(1, (int) size); + hh->entry_lnk = acl_array_create(__http_hdr_def_entry); + __hdr_init(hh); + return hh; +} + +/* 克隆一个HTTP协议头的基础结构 */ + +void http_hdr_clone(const HTTP_HDR *src, HTTP_HDR *dst) +{ + ACL_ARRAY *entry_lnk_saved = dst->entry_lnk; /* 先保留原指针 */ + HTTP_HDR_ENTRY *entry, *entry_from; + int i, n; + + memcpy(dst, src, sizeof(HTTP_HDR)); + dst->entry_lnk = entry_lnk_saved; /* 恢复原始指针 */ + dst->chat_ctx = NULL; /* bugfix, 2008.10.7 , zsx */ + dst->chat_free_ctx_fn = NULL; /* bugfix, 2008.10.7 , zsx */ + + n = acl_array_size(src->entry_lnk); + for (i = 0; i < n; i++) { + entry_from = (HTTP_HDR_ENTRY*) acl_array_index(src->entry_lnk, i); + entry = http_hdr_entry_build(entry_from->name, entry_from->value); + http_hdr_append_entry(dst, entry); + } +} + +/* 释放 HTTP_HDR */ + +void http_hdr_free(HTTP_HDR *hh) +{ + if (hh == NULL) + return; + if (hh->entry_lnk != NULL) + acl_array_free(hh->entry_lnk, acl_myfree_fn); + + if (hh->chat_free_ctx_fn && hh->chat_ctx) + hh->chat_free_ctx_fn(hh->chat_ctx); + acl_myfree(hh); +} + +void http_hdr_reset(HTTP_HDR *hh) +{ + if (hh != NULL) { + if (hh->entry_lnk != NULL) + acl_array_clean(hh->entry_lnk, acl_myfree_fn); + __hdr_init(hh); + } +} + +/*----------------------------------------------------------------------------*/ + +HTTP_HDR_ENTRY *http_hdr_entry_build(const char *name, const char *value) +{ + HTTP_HDR_ENTRY *entry; + size_t n0 = sizeof(HTTP_HDR_ENTRY), n1 = strlen(name), n2 = strlen(value); + + entry = (HTTP_HDR_ENTRY*) acl_mymalloc(n0 + n1 + n2 + 2); + entry->off = 0; + + entry->name = (char*) entry + n0; + memcpy(entry->name, name, n1); + entry->name[n1] = 0; + + entry->value = entry->name + n1 + 1; + memcpy(entry->value, value, n2); + entry->value[n2] = 0; + + return entry; +} + +/* 根据传入的一行数据进行分析, 生成一个 HTTP_HDR_ENTRY */ + +HTTP_HDR_ENTRY *http_hdr_entry_new(const char *data) +{ + /* data format: Content-Length: 245 */ + char buf_fixed[512], *name, *value, *buf = NULL; + HTTP_HDR_ENTRY *entry; + size_t n; + + while (*data == ' ' || *data == '\t' || *data == ':') + data++; + if (*data == 0) + return NULL; + + n = strlen(data); + if (n >= sizeof(buf_fixed) - 1) { + buf = acl_mystrdup(data); + name = buf; + } else { + name = buf_fixed; + memcpy(name, data, n); + name[n] = 0; + } + + value = name + 1; + while (*value != 0) { + if (*value == ':' || *value == ' ' || *value == '\t') { + *value++ = 0; + break; + } + else + value++; + } + + while (*value == ':' || *value == ' ' || *value == '\t') + value++; + if (*value == 0) { + if (buf) + acl_myfree(buf); + return NULL; + } + + entry = http_hdr_entry_build(name, value); + if (buf) + acl_myfree(buf); + return entry; +} + +HTTP_HDR_ENTRY *http_hdr_entry_head(char *data) +{ + /* data format: GET / HTTP/1.1 or 200 OK */ + const char *myname = "http_hdr_entry_head"; + char *ptr, *pname, *psep = NULL; + HTTP_HDR_ENTRY *entry; + + pname = ptr = data; + while (*ptr) { + if (*ptr == ' ') { + psep = ptr; + *ptr++ = 0; + break; + } + ptr++; + } + if (*ptr == 0) { + acl_msg_error("%s, %s(%d): invalid data=%s", + __FILE__, myname, __LINE__, data); + return (NULL); + } + while (*ptr == ' ' || *ptr == '\t') + ptr++; + if (*ptr == 0) { + if (psep) + *psep = ' '; + acl_msg_error("%s, %s(%d): invalid data=%s", + __FILE__, myname, __LINE__, data); + return (NULL); + } + + entry = http_hdr_entry_build(pname, ptr); + return entry; +} + +HTTP_HDR_ENTRY *http_hdr_entry_new2(char *data) +{ +/* data format: Content-Length: 245 */ + const char *myname = "http_hdr_entry_new2"; + char *ptr, *pname, *psep = NULL; + HTTP_HDR_ENTRY *entry; + + pname = ptr = data; + while (*ptr) { + if (*ptr == ':') { + psep = ptr; + *ptr++ = 0; + break; + } + ptr++; + } + if (*ptr == 0) { + acl_msg_error("%s, %s(%d): invalid data=%s", + __FILE__, myname, __LINE__, data); + return (NULL); + } + while (*ptr == ':' || *ptr == ' ' || *ptr == '\t') + ptr++; + if (*ptr == 0) { + if (psep) + *psep = ':'; + acl_msg_error("%s, %s(%d): invalid data=%s", + __FILE__, myname, __LINE__, data); + return (NULL); + } + + entry = http_hdr_entry_build(pname, ptr); + return entry; +} + +/* 将 HTTP_HDR_ENTRY 放入 HTTP_HDR 中 */ + +void http_hdr_append_entry(HTTP_HDR *hh, HTTP_HDR_ENTRY *entry) +{ + const char *myname = "http_hdr_append_entry"; + + if (acl_array_append(hh->entry_lnk, entry) < 0) + acl_msg_fatal("%s, %s(%d): acl_array_append error(%s)", + __FILE__, myname, __LINE__, acl_last_serror()); +} + +int http_hdr_parse_version(HTTP_HDR *hh, const char *data) +{ + const char *myname = "http_hdr_parse_version"; + + if (hh == NULL) + acl_msg_fatal("%s, %s(%d): hh null", + __FILE__, myname, __LINE__); + + if (data == NULL || *data == 0) + return -1; + + if (strncasecmp(data, "HTTP/", 5) != 0) + return -1; + if (sscanf(data + 5, "%u.%u", &hh->version.major, &hh->version.minor) != 2) + return -1; + + ACL_SAFE_STRNCPY(hh->proto, "HTTP", sizeof(hh->proto)); + return 0; +} + +/*----------------------------------------------------------------------------*/ + +/* 根据变量名取得后面的整个数据项 */ + +static HTTP_HDR_ENTRY *__get_hdr_entry(const HTTP_HDR *hh, const char *name) +{ + const char *myname = "__get_hdr_entry"; + HTTP_HDR_ENTRY *entry; + ACL_ITER iter; + + if (hh->entry_lnk == NULL) + acl_msg_fatal("%s, %s(%d): entry_lnk null", + __FILE__, myname, __LINE__); + + acl_foreach(iter, hh->entry_lnk) { + entry = (HTTP_HDR_ENTRY *) iter.data; + if (strcasecmp(name, entry->name) == 0) + return (entry); + } + + return NULL; +} + +HTTP_HDR_ENTRY *http_hdr_entry(const HTTP_HDR *hh, const char *name) +{ + return __get_hdr_entry(hh, name); +} + +char *http_hdr_entry_value(const HTTP_HDR *hh, const char *name) +{ + HTTP_HDR_ENTRY *hdr_entry; + + hdr_entry = http_hdr_entry(hh, name); + if (hdr_entry == NULL) + return (NULL); + return hdr_entry->value; +} + +int http_hdr_entry_replace(HTTP_HDR *hh, const char *name, + const char *value, int force) +{ + const char *myname = "http_hdr_entry_replace"; + HTTP_HDR_ENTRY *entry; + + if (hh == NULL || name == NULL || value == NULL) + acl_msg_fatal("%s, %s(%d): input invalid", + __FILE__, myname, __LINE__); + + entry = __get_hdr_entry(hh, name); + if (entry == NULL) { + if (force == 0) + return -1; + entry = http_hdr_entry_build(name, value); + } else { + acl_array_delete_obj(hh->entry_lnk, entry, NULL); + acl_myfree(entry); + entry = http_hdr_entry_build(name, value); + } + + http_hdr_append_entry(hh, entry); + return 0; +} + +int http_hdr_entry_replace2(HTTP_HDR *hh, const char *name, + const char *from, const char *to, int ignore_case) +{ + HTTP_HDR_ENTRY *entry; + ACL_VSTRING *value = acl_vstring_alloc(256); + int once, n = 0, len = (int) strlen(from), i; + char *(*find_fn)(char *, const char*); + + if (strcasecmp(name, "Set-Cookie") == 0) + once = 0; + else + once = 1; + if (ignore_case) + find_fn = acl_strcasestr; + else + find_fn = (char *(*)(char*, const char*)) strstr; + + for (i = 0; i < hh->entry_lnk->count; i++) { + char *ptr_prev, *ptr; + + entry = (HTTP_HDR_ENTRY*) hh->entry_lnk->items[i]; + if (strcasecmp(entry->name, name) != 0) + continue; + + ACL_VSTRING_RESET(value); + ptr_prev = entry->value; + + while (*ptr_prev) { + ptr = find_fn(ptr_prev, from); + if (ptr == NULL) { + acl_vstring_strcat(value, ptr_prev); + break; + } + if (ptr > ptr_prev) + acl_vstring_strncat(value, ptr_prev, + ptr - ptr_prev); + acl_vstring_strcat(value, to); + ptr_prev = ptr + len; + n++; + } + + if (n > 0) { + acl_myfree(entry); + hh->entry_lnk->items[i] = http_hdr_entry_build(name, + acl_vstring_str(value)); + } + if (once) + break; + } + + acl_vstring_free(value); + return n; +} + +void http_hdr_entry_off(HTTP_HDR *hh, const char *name) +{ + const char *myname = "http_hdr_entry_off"; + HTTP_HDR_ENTRY *entry; + + if (hh == NULL || name == NULL) + acl_msg_fatal("%s, %s(%d): input invalid", + __FILE__, myname, __LINE__); + + entry = __get_hdr_entry(hh, name); + if (entry == NULL) + return; + + /* xxx: 腾讯的视频WEB服务器不支持此种方式 -- 2008-7-23, zsx */ + /* entry->name[0] = '_'; */ + entry->off = 1; +} + +int http_hdr_parse(HTTP_HDR *hh) +{ + const char *myname = "http_hdr_parse"; + int keep_alive = -1; + HTTP_HDR_ENTRY *entry; + ACL_ITER iter; + + struct HEADER_LIST { + char *name; + }; + +#if 0 + static const struct HEADER_LIST header_list[] = { + { "Accept-Ranges" }, + { "Age" }, + { "Cache-Control" }, + { "Connection" }, + { "Content-Encoding" }, + { "Content-Length" }, + { "Content-Type" }, + { "Date" }, + { "ETag" }, + { "Last-Modified" }, + { "Server" }, + { "Transfer-Encoding" }, + }; + int care_size = sizeof(header_list)/sizeof(struct HEADER_LIST), care_cnt = 0, i, n; + + n = acl_array_size(hh->entry_lnk); + for (i = 0; i < n; i++) { + if (care_cnt >= care_size) + break; + + entry = (HTTP_HDR_ENTRY *) acl_array_index(hh->entry_lnk, i); + + if (strcasecmp(entry->name, "Accept-Ranges") == 0) { + care_cnt++; + } else if (strcasecmp(entry->name, "Age") == 0) { + care_cnt++; + } else if (strcasecmp(entry->name, "Cache-Control") == 0) { + care_cnt++; + } else if (strcasecmp(entry->name, "Connection") == 0) { + care_cnt++; + if (strcasecmp(entry->value, "keep-alive") == 0) + keep_alive = 1; + else + keep_alive = 0; + } else if (strcasecmp(entry->name, "Proxy-Connection") == 0) { + care_cnt++; + if (strcasecmp(entry->value, "keep-alive") == 0) + keep_alive = 1; + else + keep_alive = 0; + } else if (strcasecmp(entry->name, "Content-Encoding") == 0) { + care_cnt++; + } else if (strcasecmp(entry->name, "Content-Length") == 0) { +#ifdef MS_VC6 + hh->content_length = acl_atoui64(entry->value); +#else + hh->content_length = acl_atoui64(entry->value) * 1ll; +#endif + if (hh->content_length < 0) { + acl_msg_error("%s: content_length(%s) invalid", + myname, entry->value); + return (-1); + } + care_cnt++; + } else if (strcasecmp(entry->name, "Content-Type") == 0) { + care_cnt++; + } else if (strcasecmp(entry->name, "Date") == 0) { + care_cnt++; + } else if (strcasecmp(entry->name, "ETag") == 0) { + care_cnt++; + } else if (strcasecmp(entry->name, "Last-Modified") == 0) { + care_cnt++; + } else if (strcasecmp(entry->name, "Server") == 0) { + care_cnt++; + } else if (strcasecmp(entry->name, "Transfer-Encoding") == 0) { + if (strcasecmp(entry->value, "chunked") == 0) + hh->chunked = 1; + care_cnt++; + } + } +#else + static const struct HEADER_LIST header_list[] = { + { "Connection" }, + { "Proxy-Connection" }, + { "Content-Length" }, + { "Transfer-Encoding" }, + }; + int care_size = sizeof(header_list)/sizeof(struct HEADER_LIST), care_cnt = 0; + + acl_foreach(iter, hh->entry_lnk) { + entry = (HTTP_HDR_ENTRY *) iter.data; + + if (strcasecmp(entry->name, "Connection") == 0) { + if (strcasecmp(entry->value, "keep-alive") == 0) + keep_alive = 1; + else + keep_alive = 0; + care_cnt++; + } else if (strcasecmp(entry->name, "Proxy-Connection") == 0) { + if (strcasecmp(entry->value, "keep-alive") == 0) + keep_alive = 1; + else + keep_alive = 0; + care_cnt++; + } else if (strcasecmp(entry->name, "Content-Length") == 0) { +#ifdef MS_VC6 + hh->content_length = acl_atoui64(entry->value); +#else + hh->content_length = acl_atoui64(entry->value) * 1ll; +#endif + if (hh->content_length < 0) { + acl_msg_error("%s: content_length(%s) invalid", + myname, entry->value); + return (-1); + } + care_cnt++; + } else if (strcasecmp(entry->name, "Transfer-Encoding") == 0) { + if (strcasecmp(entry->value, "chunked") == 0) + hh->chunked = 1; + care_cnt++; + } + if (care_cnt >= care_size) + break; + } +#endif + + if (hh->chunked) { + if (keep_alive != 0) + hh->keep_alive = 1; + else + hh->keep_alive = 0; + } else if (keep_alive == 1) { + hh->keep_alive = 1; + } else { + hh->keep_alive = 0; + } + + return 0; +} + +void http_hdr_print(const HTTP_HDR *hh, const char *msg) +{ + const char *myname = "http_hdr_print"; + HTTP_HDR_ENTRY *entry; + int n, i; + + if (hh == NULL) + acl_msg_fatal("%s, %s(%d): invalid input", + __FILE__, myname, __LINE__); + n = acl_array_size(hh->entry_lnk); + if (n <= 0) { + acl_msg_info("%s, %s(%d): array empty", + __FILE__, myname, __LINE__); + return; + } + + printf("------------- in %s - msg=(%s)----------------\r\n", + myname, msg ? msg : "null"); + entry = (HTTP_HDR_ENTRY *) acl_array_index(hh->entry_lnk, 0); + if (entry) + printf("%s %s\r\n", entry->name, entry->value); + for (i = 1; i < n; i++) { + entry = (HTTP_HDR_ENTRY *) acl_array_index(hh->entry_lnk, i); + if (entry == NULL) + break; + printf("%s: %s\r\n", entry->name, entry->value); + } + printf("--------------- end -----------------\r\n"); +} + +void http_hdr_fprint(ACL_VSTREAM *fp, const HTTP_HDR *hh, const char *msg) +{ + const char *myname = "http_hdr_fprint"; + HTTP_HDR_ENTRY *entry; + int n, i; + + if (fp == NULL || hh == NULL) { + acl_msg_error("%s(%d): input invalid", myname, __LINE__); + return; + } + + n = acl_array_size(hh->entry_lnk); + if (n <= 0) { + acl_msg_info("%s, %s(%d): array empty", myname, __FILE__, __LINE__); + return; + } + + acl_vstream_fprintf(fp, "------------- in %s - (%s)----------------\r\n", + myname, msg ? msg : "begin"); + entry = (HTTP_HDR_ENTRY *) acl_array_index(hh->entry_lnk, 0); + if (entry) + acl_vstream_fprintf(fp, "%s %s\r\n", entry->name, entry->value); + for (i = 1; i < n; i++) { + entry = (HTTP_HDR_ENTRY *) acl_array_index(hh->entry_lnk, i); + if (entry == NULL) + break; + acl_vstream_fprintf(fp, "%s: %s\r\n", entry->name, entry->value); + } + acl_vstream_fprintf(fp, "--------------- end -----------------\r\n"); +} + diff --git a/lib_protocol/src/http/http_hdr_build.c b/lib_protocol/src/http/http_hdr_build.c new file mode 100644 index 000000000..69b614e17 --- /dev/null +++ b/lib_protocol/src/http/http_hdr_build.c @@ -0,0 +1,201 @@ +#include "StdAfx.h" +#include +#include +#include +#include +#include + +#include "http/lib_http.h" + +void http_hdr_put_str(HTTP_HDR *hdr, const char *name, const char *value) +{ + HTTP_HDR_ENTRY *entry; + + entry = http_hdr_entry_build(name, value); + if (entry) + http_hdr_append_entry(hdr, entry); +} + +void http_hdr_put_int(HTTP_HDR *hdr, const char *name, int value) +{ + char buf[32]; + HTTP_HDR_ENTRY *entry; + + snprintf(buf, sizeof(buf) - 1, "%d", value); + entry = http_hdr_entry_build(name, buf); + if (entry) + http_hdr_append_entry(hdr, entry); +} + +void http_hdr_put_fmt(HTTP_HDR *hdr, const char *name, const char *fmt, ...) +{ + char myname[] = "http_hdr_put_fmt"; + va_list ap; + HTTP_HDR_ENTRY *entry; + ACL_VSTRING *strbuf = acl_vstring_alloc(1024); + + if (strbuf == NULL) { + char ebuf[256]; + acl_msg_fatal("%s, %s(%d): calloc error(%s)", + __FILE__, myname, __LINE__, acl_last_strerror(ebuf, sizeof(ebuf))); + } + + va_start(ap, fmt); + acl_vstring_vsprintf_append(strbuf, fmt, ap); + va_end(ap); + + entry = http_hdr_entry_build(name, acl_vstring_str(strbuf)); + if (entry) + http_hdr_append_entry(hdr, entry); + + acl_vstring_free(strbuf); +} + +void http_hdr_put_time(HTTP_HDR *hdr, const char *name, time_t t) +{ + char buf[128]; + HTTP_HDR_ENTRY *entry; + + buf[sizeof(buf) - 1] = '\0'; + + (void) http_mkrfc1123(buf, sizeof(buf) - 1, t); + entry = http_hdr_entry_build(name, buf); + if (entry) + http_hdr_append_entry(hdr, entry); +} + +int http_hdr_set_keepalive(const HTTP_HDR_REQ *req, HTTP_HDR_RES *res) +{ +#if 0 + int left; + + if (req->hdr.keep_alive == 0 + || req->server == NULL + || req->server->keep_alive_timeout <= 0) { + http_hdr_put_str(&res->hdr, "Connection", "close"); + return (0); + } + + left = req->server->keep_alive_max - req->nkeepalive; + + if (req->server->keep_alive_max > 0) + http_hdr_put_fmt(&res->hdr, + "Keep-Alive", + "timeout=%d, max=%d", + req->server->keep_alive_timeout, + left); + else + http_hdr_put_int(&res->hdr, + "Keep-Alive", + req->server->keep_alive_timeout); + + http_hdr_put_str(&res->hdr, "Connection", "Keep-Alive"); + + return (1); +#else + const char *ptr; + + ptr = http_hdr_entry_value(&req->hdr, "Connection"); + + if (ptr == NULL || strcasecmp(ptr, "keep-alive") != 0) { + http_hdr_put_str(&res->hdr, "Connection", "close"); + res->hdr.keep_alive = 0; + return (0); + } + + http_hdr_put_str(&res->hdr, "Connection", "Keep-Alive"); + res->hdr.keep_alive = 1; + + return (1); +#endif +} + +void http_hdr_res_init(HTTP_HDR_RES *hdr_res, int status) +{ + const char *ptr; + + ptr = http_status_line(status); + http_hdr_put_str(&hdr_res->hdr, "HTTP/1.1", ptr); + http_hdr_put_str(&hdr_res->hdr, "Server", "acl_httpd"); +} + +HTTP_HDR_RES *http_hdr_res_static(int status) +{ + HTTP_HDR_RES *res_hdr; + + res_hdr = http_hdr_res_new(); + http_hdr_res_init(res_hdr, status); + http_hdr_put_time(&res_hdr->hdr, "Date", time(NULL)); + return (res_hdr); +} + +HTTP_HDR_RES *http_hdr_res_error(int status) +{ + int n; + HTTP_HDR_RES *res_hdr; + + res_hdr = http_hdr_res_new(); + http_hdr_res_init(res_hdr, status); + http_hdr_put_time(&res_hdr->hdr, "Date", time(NULL)); + http_hdr_put_str(&res_hdr->hdr, "Content-Type", "text/html"); + http_hdr_put_str(&res_hdr->hdr, "Connection", "close"); + + n = http_tmpl_size(status); + http_hdr_put_int(&res_hdr->hdr, "Content-Length", n); + + return (res_hdr); +} + +void http_hdr_build(const HTTP_HDR *hdr, ACL_VSTRING *strbuf) +{ + ACL_ARRAY *entries; + HTTP_HDR_ENTRY *entry; + int i, n; + + entries = hdr->entry_lnk; + n = acl_array_size(entries); + + entry = (HTTP_HDR_ENTRY *) acl_array_index(entries, 0); + acl_vstring_sprintf(strbuf, "%s %s\r\n", entry->name, entry->value); + + for (i = 1; i < n; i++) { + entry = (HTTP_HDR_ENTRY *) acl_array_index(entries, i); + if (entry == NULL) + break; + if (entry->off) + continue; + acl_vstring_sprintf_append(strbuf, "%s: %s\r\n", entry->name, entry->value); + } + + acl_vstring_strcat(strbuf, "\r\n"); +} + +void http_hdr_build_request(const HTTP_HDR_REQ *hdr_req, ACL_VSTRING *strbuf) +{ + ACL_ARRAY *entries; + HTTP_HDR_ENTRY *entry; + int i, n; + + entries = hdr_req->hdr.entry_lnk; + n = acl_array_size(entries); + + entry = (HTTP_HDR_ENTRY *) acl_array_index(entries, 0); +#if 0 + acl_vstring_sprintf(strbuf, "%s %s\r\n", entry->name, entry->value); +#else + acl_vstring_sprintf(strbuf, "%s %s HTTP/%d.%d\r\n", entry->name, + acl_vstring_str(hdr_req->url_part), + hdr_req->hdr.version.major, hdr_req->hdr.version.minor); +#endif + + for (i = 1; i < n; i++) { + entry = (HTTP_HDR_ENTRY *) acl_array_index(entries, i); + if (entry == NULL) + break; + if (entry->off) + continue; + acl_vstring_sprintf_append(strbuf, "%s: %s\r\n", entry->name, entry->value); + } + + acl_vstring_strcat(strbuf, "\r\n"); +} diff --git a/lib_protocol/src/http/http_hdr_req.c b/lib_protocol/src/http/http_hdr_req.c new file mode 100644 index 000000000..fb8155899 --- /dev/null +++ b/lib_protocol/src/http/http_hdr_req.c @@ -0,0 +1,975 @@ +#include "StdAfx.h" +#include +#include +#include + +#include "stdlib/acl_iterator.h" +#include "http.h" +#include "http/lib_http.h" + +static int __http_hdr_max_request = 30; +static int __http_hdr_max_cookies = 30; +static void __get_host_from_url(char *buf, size_t size, const char *url); + +static void __hdr_init(HTTP_HDR_REQ *hh) +{ + const char *myname = "__hdr_init"; + + hh->url_part = acl_vstring_alloc(128); + if (hh->url_part == NULL) + acl_msg_fatal("%s, %s(%d): alloc error(%s)", + __FILE__, myname, __LINE__, acl_last_serror()); + hh->url_path = acl_vstring_alloc(64); + if (hh->url_path == NULL) + acl_msg_fatal("%s, %s(%d): alloc error(%s)", + __FILE__, myname, __LINE__, acl_last_serror()); + + hh->url_params = acl_vstring_alloc(64); + if (hh->url_params == NULL) + acl_msg_fatal("%s, %s(%d): alloc error(%s)", + __FILE__, myname, __LINE__, acl_last_serror()); + + hh->file_path = acl_vstring_alloc(256); + if (hh->file_path == NULL) + acl_msg_fatal("%s, %s(%d): alloc error(%s)", + __FILE__, myname, __LINE__, acl_last_serror()); +} + +static void __request_args_free_fn(void *arg) +{ + acl_myfree(arg); +} + +static void __cookies_args_free_fn(void *arg) +{ + acl_myfree(arg); +} + +static void __hdr_free_member(HTTP_HDR_REQ *hh) +{ + if (hh->url_part) + acl_vstring_free(hh->url_part); + if (hh->url_path) + acl_vstring_free(hh->url_path); + if (hh->url_params) + acl_vstring_free(hh->url_params); + if (hh->file_path) + acl_vstring_free(hh->file_path); + if (hh->params_table) { + acl_htable_free(hh->params_table, __request_args_free_fn); + hh->params_table = NULL; + } + if (hh->cookies_table) { + acl_htable_free(hh->cookies_table, __cookies_args_free_fn); + hh->cookies_table = NULL; + } +} + +static void __hdr_reset(HTTP_HDR_REQ *hh, int clear_cookies) +{ + hh->port = 80; + hh->method[0] = 0; + hh->host[0] = 0; + hh->flag = 0; + + if (hh->url_part) + ACL_VSTRING_RESET(hh->url_part); + + if (hh->url_path) + ACL_VSTRING_RESET(hh->url_path); + if (hh->url_params) + ACL_VSTRING_RESET(hh->url_params); + + if (hh->file_path) + ACL_VSTRING_RESET(hh->file_path); + if (hh->params_table) + acl_htable_reset(hh->params_table, __request_args_free_fn); + if (clear_cookies && hh->cookies_table) + acl_htable_reset(hh->cookies_table, __cookies_args_free_fn); +} + +static void cache_free(ACL_ARRAY *pool) +{ + acl_array_free(pool, (void (*)(void*)) http_hdr_req_free); +} + +static acl_pthread_key_t cache_key = -1; + +#ifndef USE_TLS_EX +static ACL_ARRAY *cache_pool = NULL; +static void main_cache_free(void) +{ + if (cache_pool) { + cache_free(cache_pool); + cache_pool = NULL; + } +} + +static void dummy_free(void *arg acl_unused) +{ +} + +static acl_pthread_once_t once_control = ACL_PTHREAD_ONCE_INIT; +static void cache_init(void) +{ + if ((unsigned long) acl_pthread_self() == acl_main_thread_self()) { + acl_pthread_key_create(&cache_key, dummy_free); + atexit(main_cache_free); + } else + acl_pthread_key_create(&cache_key, (void (*)(void*)) cache_free); +} +#endif + +/* 生成一个新的 HTTP_HDR_REQ 数据结构 */ + +HTTP_HDR_REQ *http_hdr_req_new(void) +{ + HTTP_HDR_REQ *hh; + ACL_ARRAY *pool; + + if (var_http_tls_cache <= 0) { + hh = (HTTP_HDR_REQ *) http_hdr_new(sizeof(HTTP_HDR_REQ)); + __hdr_init(hh); + return hh; + } + +#ifdef USE_TLS_EX + pool = (ACL_ARRAY*) acl_pthread_tls_get(&cache_key); + if (pool == NULL) { + pool = acl_array_create(100); + acl_pthread_tls_set(cache_key, pool, (void (*)(void*)) cache_free); + } + + pool = (ACL_ARRAY*) acl_pthread_tls_get(&cache_key); + hh = (HTTP_HDR_REQ*) pool->pop_back(pool); + if (hh) { + __hdr_reset(hh, 1); + http_hdr_reset((HTTP_HDR *) hh); + return hh; + } +#else + acl_pthread_once(&once_control, cache_init); + pool = (ACL_ARRAY*) acl_pthread_getspecific(cache_key); + if (pool == NULL) { + pool = acl_array_create(100); + acl_pthread_setspecific(cache_key, pool); + if ((unsigned long) acl_pthread_self() == acl_main_thread_self()) + cache_pool = pool; + } + hh = (HTTP_HDR_REQ*) pool->pop_back(pool); + if (hh) { + __hdr_reset(hh, 1); + http_hdr_reset((HTTP_HDR *) hh); + return hh; + } +#endif + + hh = (HTTP_HDR_REQ *) http_hdr_new(sizeof(HTTP_HDR_REQ)); + __hdr_init(hh); + return hh; +} + +HTTP_HDR_REQ *http_hdr_req_create(const char *url, + const char *method, const char *version) +{ + const char *myname = "http_hdr_req_create"; + HTTP_HDR_REQ *hdr_req; + ACL_VSTRING *req_line = acl_vstring_alloc(256); + HTTP_HDR_ENTRY *entry; + const char *ptr; + static char *__user_agent = "Mozilla/5.0 (Windows; U; Windows NT 5.0" + "; zh-CN; rv:1.9.0.3) Gecko/2008092417 ACL/3.0.6"; + + if (url == NULL || *url == 0) { + acl_msg_error("%s(%d): url invalid", myname, __LINE__); + return NULL; + } + if (method == NULL || *method == 0) { + acl_msg_error("%s(%d): method invalid", myname, __LINE__); + return NULL; + } + if (version == NULL || *version == 0) { + acl_msg_error("%s(%d): version invalid", myname, __LINE__); + return NULL; + } + + acl_vstring_strcpy(req_line, method); + acl_vstring_strcat(req_line, " "); + + if (strncasecmp(url, "http://", sizeof("http://") - 1) == 0) + url += sizeof("http://") - 1; + else if (strncasecmp(url, "https://", sizeof("https://") - 1) == 0) + url += sizeof("https://") -1; + ptr = strchr(url, '/'); + if (ptr) + acl_vstring_strcat(req_line, ptr); + else { + ACL_VSTRING_ADDCH(req_line, '/'); + ACL_VSTRING_TERMINATE(req_line); + } + + acl_vstring_strcat(req_line, " "); + acl_vstring_strcat(req_line, version); + + entry = http_hdr_entry_new(acl_vstring_str(req_line)); + acl_vstring_free(req_line); + + if (entry == NULL) { + acl_msg_error("%s(%d): http_hdr_entry_new return null for (%s)", + myname, __LINE__, acl_vstring_str(req_line)); + return NULL; + } + + hdr_req = http_hdr_req_new(); + http_hdr_append_entry(&hdr_req->hdr, entry); + hdr_req->flag |= (HTTP_HDR_REQ_FLAG_PARSE_PARAMS | HTTP_HDR_REQ_FLAG_PARSE_COOKIE); + if (http_hdr_req_line_parse(hdr_req) < 0) { + http_hdr_req_free(hdr_req); + return NULL; + } + + hdr_req->host[0] = 0; + __get_host_from_url(hdr_req->host, sizeof(hdr_req->host), url); + if (hdr_req->host[0] != 0) + http_hdr_put_str(&hdr_req->hdr, "Host", hdr_req->host); + http_hdr_put_str(&hdr_req->hdr, "Connection", "Close"); + http_hdr_put_str(&hdr_req->hdr, "User-Agent", __user_agent); + + return hdr_req; +} + +static void clone_table_entry(ACL_HTABLE_INFO *info, void *arg) +{ + const char *myname = "clone_table_entry"; + ACL_HTABLE *table = (ACL_HTABLE*) arg; + char *value; + + value = acl_mystrdup(info->value); + + if (acl_htable_enter(table, info->key.key, value) == NULL) + acl_msg_fatal("%s, %s(%d): acl_htable_enter error=%s", + __FILE__, myname, __LINE__, acl_last_serror()); +} + +HTTP_HDR_REQ *http_hdr_req_clone(const HTTP_HDR_REQ* hdr_req) +{ + HTTP_HDR_REQ *hh; + + hh = http_hdr_req_new(); + http_hdr_clone(&hdr_req->hdr, &hh->hdr); + + hh->port = hdr_req->port; + strcpy(hh->method, hdr_req->method); + strcpy(hh->host, hdr_req->host); + acl_vstring_strcpy(hh->url_part, acl_vstring_str(hdr_req->url_part)); + acl_vstring_strcpy(hh->url_path, acl_vstring_str(hdr_req->url_path)); + acl_vstring_strcpy(hh->url_params, acl_vstring_str(hdr_req->url_params)); + acl_vstring_strcpy(hh->file_path, acl_vstring_str(hdr_req->file_path)); + + if (hdr_req->params_table) { + hh->params_table = acl_htable_create(__http_hdr_max_request, 0); + acl_htable_walk(hdr_req->params_table, clone_table_entry, + (void*) hh->params_table); + } + if (hdr_req->cookies_table) { + hh->cookies_table = acl_htable_create(__http_hdr_max_cookies, 0); + acl_htable_walk(hdr_req->cookies_table, clone_table_entry, + (void*) hh->cookies_table); + } + + return hh; +} + +/* 释放一个 HTTP_HDR_REQ 结构 */ + +void http_hdr_req_free(HTTP_HDR_REQ *hh) +{ + ACL_ARRAY *pool; + + if (hh == NULL) + return; + + if (var_http_tls_cache <= 0) { + __hdr_free_member(hh); + http_hdr_free((HTTP_HDR *) hh); + return; + } + +#ifdef USE_TLS_EX + pool = (ACL_ARRAY*) acl_pthread_tls_get(&cache_key); + if (pool != NULL) { + pool->push_back(pool, hh); + return; + } +#else + pool = (ACL_ARRAY*) acl_pthread_getspecific(cache_key); + if (pool != NULL && acl_array_size(pool) < var_http_tls_cache) { + pool->push_back(pool, hh); + return; + } +#endif + __hdr_free_member(hh); + http_hdr_free((HTTP_HDR *) hh); +} + +void http_hdr_req_reset(HTTP_HDR_REQ *hh) +{ + if (hh == NULL) + return; + + http_hdr_reset((HTTP_HDR *) hh); + __hdr_free_member(hh); + __hdr_init(hh); +} + +/*----------------------------------------------------------------------------*/ + +/* 将 cookie 行中的 name=value 对置入哈希表中, 以便于查询 */ + +static void __add_cookie_item(ACL_HTABLE *table, const char *data) +{ +/* data format: name=value */ + const char *myname = "__add_cookie_item"; + ACL_ARGV *argv = NULL; + ACL_VSTRING *str = NULL; + const char *name; + char *value; + char *ptr; + int i, j; + +#undef RETURN +#define RETURN do { \ + if (argv) \ + acl_argv_free(argv); \ + return; \ +} while(0); + +#undef TRUNC_BLANK +#define TRUNC_BLANK(_x_) do { \ + char *_ptr_; \ + while(*_x_ == ' ' || *_x_ == '\t') \ + _x_++; \ + if (*_x_ == 0) \ + RETURN; \ + _ptr_ = _x_; \ + while (*_ptr_) { \ + if (*_ptr_ == ' ' || *_ptr_ == '\t') { \ + *_ptr_ = 0; \ + break; \ + } \ + _ptr_++; \ + } \ +} while (0); + +#undef TRUNC_BLANK_NORETURN +#define TRUNC_BLANK_NORETURN(_x_) do { \ + char *_ptr_; \ + while(*_x_ == ' ' || *_x_ == '\t') \ + _x_++; \ + _ptr_ = _x_; \ + while (*_ptr_) { \ + if (*_ptr_ == ' ' || *_ptr_ == '\t') { \ + *_ptr_ = 0; \ + break; \ + } \ + _ptr_++; \ + } \ +} while (0); + + argv = acl_argv_split(data, "="); + if (argv->argc < 2) /* data: "name" or "name="*/ + RETURN; + + ptr = acl_argv_index(argv, 0); + TRUNC_BLANK(ptr); + name = ptr; + + /* 有些站点的COOKIE比较弱,如和讯的reg.hexun.com,COOKIE名会有重复 + * 的情况,所以必须判断一下,不必重复存储相同名字的COOKIE值,即如果 + * 出现重复COOKIE名,则只存储第一个,这样就避免了采用哈希方式存储的 + * 漏内存的现象发生。--- zsx, 2008.1.8 + */ + if (acl_htable_find(table, name) != NULL) { + RETURN; + } + + str = acl_vstring_alloc(256); + if (str == NULL) + acl_msg_fatal("%s, %s(%d): vstring_alloc error=%s", + __FILE__, myname, __LINE__, acl_last_serror()); + j = 0; + + for (i = 1; i < argv->argc; i++) { + ptr = acl_argv_index(argv, i); + if (ptr == NULL) + break; + TRUNC_BLANK_NORETURN(ptr); + if (*ptr == 0) + continue; + if (j == 0) { + acl_vstring_sprintf_append(str, "%s", ptr); + j++; + } else { + acl_vstring_sprintf_append(str, "=%s", ptr); + j++; + } + } + + /* 将真实的存储数据的区域内存引出, 同时将外包结构内存释放, + * POSTFIX真是个好东西:) ---zsx + */ + value = acl_vstring_export(str); + + if (acl_htable_enter(table, name, value) == NULL) + acl_msg_fatal("%s, %s(%d): acl_htable_enter error=%s", + __FILE__, myname, __LINE__, acl_last_serror()); + + RETURN; +} + +int http_hdr_req_cookies_parse(HTTP_HDR_REQ *hh) +{ + /* data format: "name1=value1; name2=value2; name3=value3" */ + const char *myname = "http_hdr_req_cookies_parse"; + const HTTP_HDR_ENTRY *entry; + ACL_ARGV *argv; + const char *ptr; + ACL_ITER iter; + + if (hh == NULL) + acl_msg_fatal("%s, %s(%d): input invalid", + __FILE__, myname, __LINE__); + if ((hh->flag & HTTP_HDR_REQ_FLAG_PARSE_COOKIE) == 0) + return 0; + + entry = http_hdr_entry((HTTP_HDR *) hh, "Cookie"); + if (entry == NULL) + return 0; + + if (hh->cookies_table == NULL) + hh->cookies_table = acl_htable_create(__http_hdr_max_cookies, + ACL_HTABLE_FLAG_KEY_REUSE); + if (hh->cookies_table == NULL) + acl_msg_fatal("%s, %s(%d): htable create error(%s)", + __FILE__, myname, __LINE__, acl_last_serror()); + + /* 分隔数据段 */ + argv = acl_argv_split(entry->value, ";"); + acl_foreach(iter, argv) { + ptr = (const char*) iter.data; + __add_cookie_item(hh->cookies_table, ptr); + } + acl_argv_free(argv); + return 0; +} + +const char *http_hdr_req_cookie_get(HTTP_HDR_REQ *hh, const char *name) +{ + const char *myname = "http_hdr_req_cookie_get"; + + if (hh == NULL || name == NULL) { + acl_msg_error("%s, %s(%d): input invalid", + __FILE__, myname, __LINE__); + return NULL; + } + + if (hh->cookies_table == NULL) { + acl_msg_warn("%s, %s(%d): cookies_table null", + __FILE__, myname, __LINE__); + return NULL; + } + + return acl_htable_find(hh->cookies_table, name); +} + +/*--------------- 分析HTTP协议请求头中第一行数据信息的函数集合 -------------*/ + +/* 将HTTP请求行中的 name=value 对置入哈希表中, 以便于查询 */ +static void __add_request_item(ACL_HTABLE *table, const char *data) +{ + /* data format: name=value */ + const char *myname = "__add_request_item"; + ACL_ARGV *argv; + const char *name; + char *value; + + argv = acl_argv_split(data, "="); + if (argv->argc != 2) { + acl_argv_free(argv); + return; + } + + name = acl_argv_index(argv, 0); + + /* 先判断是否已经存在该变量名,防止出现重复现象, + * 避免采用哈希存储时的内存泄漏 ---zsx, 2008.1.8 + */ + if (acl_htable_find(table, name) != NULL) { + acl_argv_free(argv); /* bugfix: add by zsx, 2009-11-11 */ + return; + } + + value = acl_mystrdup(acl_argv_index(argv, 1)); + if (value == NULL) + acl_msg_fatal("%s, %s(%d): strdup error=%s", __FILE__, myname, + __LINE__, acl_last_serror()); + + if (acl_htable_enter(table, name, value) == NULL) + acl_msg_error("%s, %s(%d): acl_htable_enter error=%s", __FILE__, + myname, __LINE__, acl_last_serror()); + + acl_argv_free(argv); +} + +/* 如果没有 Host 实体,则需要从首行的URL分析以期获得Host */ + +/* data: "http://www.gmail.com:443/path/test.cgi?name=value&name2=value2 */ + +static void __get_host_from_url(char *buf, size_t size, const char *url) +{ + const char *ptr1, *ptr2; + size_t n; + + buf[0] = 0; + if (strncasecmp(url, "http://", sizeof("http://") - 1) == 0) + ptr1 = url + sizeof("http://") - 1; + else if (strncasecmp(url, "https://", sizeof("https://") - 1) == 0) + ptr1 = url + sizeof("https://") - 1; + else + ptr1 = url; + + if (ptr1 == NULL || *ptr1 == 0 || *ptr1 == '/') + return; + + ptr2 = strchr(ptr1, '/'); + if (ptr2) + n = ptr2 - ptr1; + else + n = strlen(ptr1); + + n++; + + if (n > size) + n = size; + + ACL_SAFE_STRNCPY(buf, ptr1, (int) n); +} + +static void __strip_url_path(ACL_VSTRING *buf, const char *url) +{ + ACL_ARGV *argv; + const char *ptr; + const char last_ch = *(url + strlen(url) - 1); + ACL_ITER iter; + + ACL_VSTRING_RESET(buf); + argv = acl_argv_split(url, "/"); + acl_foreach(iter, argv) { + ptr = (const char*) iter.data; + if (strcmp(ptr, ".") == 0 || strcmp(ptr, "..") == 0) + continue; + ACL_VSTRING_ADDCH(buf, '/'); + acl_vstring_strcat(buf, ptr); + } + + /* make the last char is ok */ + if (last_ch == '/') { + ACL_VSTRING_ADDCH(buf, '/'); + ACL_VSTRING_TERMINATE(buf); + } + + acl_argv_free(argv); +} + +static void __parse_url_and_port(HTTP_HDR_REQ *hh, const char *url) +{ + const char *myname = "__parse_url_and_port"; + int i; + ACL_ARGV *url_argv; + const char *ptr; + + hh->port = 80; /* set the default server port */ + ptr = strchr(hh->host, ':'); + if (ptr) { + ptr++; + hh->port = atoi(ptr); + } + + if (strncasecmp(url, "http://", sizeof("http://") - 1) == 0) + url += sizeof("http://") - 1; + else if (strncasecmp(url, "https://", sizeof("https://") - 1) == 0) { + url += sizeof("https://") - 1; + hh->port = 443; /* set the default https server port */ + } + + if (strcasecmp(hh->method, "CONNECT") == 0) { + ptr = strchr(url, ':'); + if (ptr) { + ptr++; + hh->port = atoi(ptr); + } + } + + /* sanity check */ + if (hh->port <= 0) + hh->port = 80; + + if (*url == '/') + acl_vstring_strcpy(hh->url_part, url); + else if ((url = strchr(url, '/')) == NULL) { + ACL_VSTRING_ADDCH(hh->url_part, '/'); + ACL_VSTRING_TERMINATE(hh->url_part); + ACL_VSTRING_ADDCH(hh->url_path, '/'); + ACL_VSTRING_TERMINATE(hh->url_path); + return; + } + + /* get url_path and url_params */ + ptr = strchr(url, '?'); + if (ptr == NULL) + __strip_url_path(hh->url_path, url); + else if (*url != '?') { + acl_vstring_strncpy(hh->url_path, url, ptr - url); + __strip_url_path(hh->url_path, acl_vstring_str(hh->url_path)); + ptr++; /* skip '?' */ + if (*ptr) + acl_vstring_strcpy(hh->url_params, ptr); + } else + acl_vstring_strcpy(hh->url_path, "/"); /* xxx */ + + if ((hh->flag & HTTP_HDR_REQ_FLAG_PARSE_PARAMS) == 0) + return; + if (ACL_VSTRING_LEN(hh->url_params) == 0) + return; + if (hh->params_table == NULL) + hh->params_table = acl_htable_create(__http_hdr_max_request, 0); + if (hh->params_table == NULL) + acl_msg_fatal("%s, %s(%d): htable create error(%s)", + __FILE__, myname, __LINE__, acl_last_serror()); + url_argv = acl_argv_split(acl_vstring_str(hh->url_params), "&"); + for (i = 0; i < url_argv->argc; i++) { + ptr = acl_argv_index(url_argv, i); + if (ptr == NULL) + break; + __add_request_item(hh->params_table, ptr); + } + acl_argv_free(url_argv); +} + +int http_hdr_req_line_parse(HTTP_HDR_REQ *hh) +{ + const char *myname = "http_hdr_req_line_parse"; + ACL_ARGV *request_argv; + HTTP_HDR_ENTRY *entry; + char *purl; + const char *ptr; + int ret; + + if (hh == NULL) { + acl_msg_error("%s, %s(%d): input invalid", + __FILE__, myname, __LINE__); + return -1; + } + if (hh->hdr.entry_lnk == NULL) + acl_msg_fatal("%s, %s(%d): entry_lnk null", + __FILE__, myname, __LINE__); + + if (acl_array_size(hh->hdr.entry_lnk) <= 0) { + acl_msg_error("%s, %s(%d): no method", + __FILE__, myname, __LINE__); + return -1; + } + + entry = (HTTP_HDR_ENTRY *) acl_array_index(hh->hdr.entry_lnk, 0); + if (entry == NULL) { + acl_msg_error("%s, %s(%d): null array", + __FILE__, myname, __LINE__); + return -1; + } + + if (entry->value == NULL || *(entry->value) == 0) { + acl_msg_error("%s, %s(%d): entry->value invalid", + __FILE__, myname, __LINE__); + return -1; + } + + if (strcasecmp(entry->name, "POST") != 0 + && strcasecmp(entry->name, "GET") != 0 + && strcasecmp(entry->name, "CONNECT") != 0 + && strcasecmp(entry->name, "HEAD") != 0) + { + acl_msg_error("%s, %s(%d): invalid http method=%s", + __FILE__, myname, __LINE__, + entry->name); + return -1; + + } + + ACL_SAFE_STRNCPY(hh->method, entry->name, sizeof(hh->method)); + + /* data: "/path/test.cgi?name=value&name2=value2 HTTP/1.0" + * or: "http://www.test.com/path/test.cgi?name=value&name2=value2 HTTP/1.0" + */ + request_argv = acl_argv_split(entry->value, "\t "); + if (request_argv->argc != 2) { + acl_msg_error("%s, %s(%d): invalid request line=%s, argc=%d", + __FILE__, myname, __LINE__, + entry->value, request_argv->argc); + acl_argv_free(request_argv); + return -1; + } + + /* data[0]: "/path/test.cgi?name=value&name2=value2" + * or: "http://www.test.com/path/test.cgi?name=value&name2=value2" + * data[1]: "HTTP/1.0" + */ + + purl = acl_argv_index(request_argv, 0); + + /* get HOST item */ + ptr = http_hdr_entry_value(&hh->hdr, "Host"); + if (ptr) + ACL_SAFE_STRNCPY(hh->host, ptr, sizeof(hh->host)); + else + __get_host_from_url(hh->host, sizeof(hh->host), purl); + + /* parse the first line's url and get server side's port */ + __parse_url_and_port(hh, purl); + + ptr = acl_argv_index(request_argv, 1); + + ret = http_hdr_parse_version(&hh->hdr, ptr); + + acl_argv_free(request_argv); + + return ret; +} + +int http_hdr_req_parse(HTTP_HDR_REQ *hh) +{ + return http_hdr_req_parse3(hh, 1, 1); +} + +int http_hdr_req_parse3(HTTP_HDR_REQ *hh, int parse_params, int parse_cookie) +{ + if (parse_params) + hh->flag |= HTTP_HDR_REQ_FLAG_PARSE_PARAMS; + if (http_hdr_req_line_parse(hh) < 0) + return -1; + if (parse_cookie) { + hh->flag |= HTTP_HDR_REQ_FLAG_PARSE_COOKIE; + if (http_hdr_req_cookies_parse(hh) < 0) + return -1; + } + return http_hdr_parse(&hh->hdr); +} + +int http_hdr_req_rewrite2(HTTP_HDR_REQ *hh, const char *url) +{ + const char *myname = "http_hdr_req_rewrite2"; + HTTP_HDR_ENTRY *first_entry, *entry; + ACL_VSTRING *buf; + char host[256], *ptr; + const char *phost, *purl; + int i, n; + + if (hh->hdr.entry_lnk == NULL) + acl_msg_fatal("%s(%d): entry_lnk null", myname, __LINE__); + + n = acl_array_size(hh->hdr.entry_lnk); + if (n <= 0) { + acl_msg_error("%s(%d): first entry null", myname, __LINE__); + return -1; + } + + /* url: http[s]://domain[/path?params], /[path?params] */ + if (strncasecmp(url, "http://", strlen("http://")) == 0) { + phost = url + strlen("http://"); + purl = strchr(phost, '/'); + if (purl == NULL) + purl = "/"; + } else if (strncasecmp(url, "https://", strlen("https://")) == 0) { + phost = url + strlen("https://"); + purl = strchr(phost, '/'); + if (purl == NULL) + purl = "/"; + } else { + phost = hh->host; /* 如果URL中没有 http[s]:// 则默认采用原 Host 字段 */ + purl = url; + } + host[0] = 0; + ACL_SAFE_STRNCPY(host, phost, sizeof(host)); + ptr = strchr(host, '/'); + if (ptr) + *ptr = 0; + + /* 将新的主机信息覆盖旧信息 */ + ACL_SAFE_STRNCPY(hh->host, host, sizeof(hh->host)); + + buf = acl_vstring_alloc(256); + if (phost == hh->host) { + if (*url == '/') + acl_vstring_sprintf(buf, "%s HTTP/%d.%d", + purl, hh->hdr.version.major, hh->hdr.version.minor); + else + acl_vstring_sprintf(buf, "/%s HTTP/%d.%d", + purl, hh->hdr.version.major, hh->hdr.version.minor); + } else { + acl_vstring_sprintf(buf, "%s HTTP/%d.%d", + purl, hh->hdr.version.major, hh->hdr.version.minor); + } + first_entry = (HTTP_HDR_ENTRY *) acl_array_index(hh->hdr.entry_lnk, 0); + if (first_entry == NULL || first_entry->value == NULL) + acl_msg_fatal("%s(%d): first_entry invalid", myname, __LINE__); + acl_myfree(first_entry->value); + first_entry->value = acl_vstring_export(buf); + __hdr_reset(hh, 0); + + if (host[0] != 0) { + for (i = 1; i < n; i++) { + entry = (HTTP_HDR_ENTRY*) acl_array_index(hh->hdr.entry_lnk, i); + if (strcasecmp(entry->name, "host") == 0) { + acl_myfree(entry->value); + entry->value = acl_mystrdup(host); + break; + } + } + } + + hh->flag |= (HTTP_HDR_REQ_FLAG_PARSE_PARAMS | HTTP_HDR_REQ_FLAG_PARSE_COOKIE); + if (http_hdr_req_line_parse(hh) < 0) + return (-1); + return 0; +} + +HTTP_HDR_REQ *http_hdr_req_rewrite(const HTTP_HDR_REQ *hh, const char *url) +{ + HTTP_HDR_REQ *hdr_req = http_hdr_req_clone(hh); + + if (http_hdr_req_rewrite2(hdr_req, url) < 0) { + http_hdr_req_free(hdr_req); + return NULL; + } + return hdr_req; +} + +/* 取得HTTP请求的方法 */ + +const char *http_hdr_req_method(HTTP_HDR_REQ *hh) +{ + return hh->method; +} + +/* 获取请求URL中某个请求字段的数据, 如取: /cgi-bin/n1=v1&n2=v2 中的 n2的值v2 */ + +const char *http_hdr_req_param(HTTP_HDR_REQ *hh, const char *name) +{ + const char *myname = "http_hdr_req_get"; + + if (hh == NULL || name == NULL) { + acl_msg_error("%s, %s(%d): input invalid", + __FILE__, myname, __LINE__); + return NULL; + } + + if (hh->params_table == NULL) + return NULL; + + return acl_htable_find(hh->params_table, name); +} + +const char *http_hdr_req_url_part(HTTP_HDR_REQ *hh) +{ + const char *myname = "http_hdr_req_url_part"; + + if (hh == NULL) { + acl_msg_error("%s, %s(%d): input invalid", + __FILE__, myname, __LINE__); + return NULL; + } + + if (ACL_VSTRING_LEN(hh->url_part) == 0) + return NULL; + return acl_vstring_str(hh->url_part); +} + +const char *http_hdr_req_url_path(HTTP_HDR_REQ *hh) +{ + if (ACL_VSTRING_LEN(hh->url_path) == 0) + return NULL; + + return acl_vstring_str(hh->url_path); +} + +const char *http_hdr_req_host(HTTP_HDR_REQ *hh) +{ + if (hh->host[0] != 0) + return hh->host; + else + return NULL; +} + +static void free_vstring(ACL_VSTRING *buf) +{ + acl_vstring_free(buf); +} + +const char *http_hdr_req_url(HTTP_HDR_REQ *hh) +{ + static acl_pthread_key_t key = -1; + ACL_VSTRING *buf; + + buf = acl_pthread_tls_get(&key); + if (buf == NULL) { + buf = acl_vstring_alloc(256); + acl_pthread_tls_set(key, buf, (void (*)(void*)) free_vstring); + } + + acl_vstring_strcpy(buf, hh->host); + acl_vstring_strcat(buf, acl_vstring_str(hh->url_part)); + return acl_vstring_str(buf); +} + +int http_hdr_req_range(HTTP_HDR_REQ *hdr_req, http_off_t *range_from, + http_off_t *range_to) +{ + const char *myname = "http_hdr_req_range"; + char buf[256], *ptr1; + const char *ptr; + + if (range_from == NULL) + acl_msg_fatal("%s(%d): range_from null", myname, __LINE__); + if (range_to == NULL) + acl_msg_fatal("%s(%d): range_to null", myname, __LINE__); + + /* 数据格式: Range: bytes={range_from}-{range_to} + * 或: Range: bytes={range_from}- + */ + ptr = http_hdr_entry_value(&hdr_req->hdr, "Range"); + if (ptr == NULL) + return -1; + ptr = strstr(ptr, "bytes="); + if (ptr == NULL) + return -1; + ptr += strlen("bytes="); + ACL_SAFE_STRNCPY(buf, ptr, sizeof(buf)); + ptr1 = buf; + while (*ptr1) { + if (*ptr1 == '-' || *ptr1 == ' ') { + *ptr1 = 0; + *range_from = acl_atoi64(buf); + if (*range_from < 0) + return (-1); + if (*(++ptr1) == 0) + *range_to = -1; + else + *range_to = acl_atoi64(ptr1); + if (*range_to <= 0) + *range_to = -1; + return 0; + } + ptr1++; + } + + return -1; +} diff --git a/lib_protocol/src/http/http_hdr_res.c b/lib_protocol/src/http/http_hdr_res.c new file mode 100644 index 000000000..04a039ca3 --- /dev/null +++ b/lib_protocol/src/http/http_hdr_res.c @@ -0,0 +1,290 @@ +#include "StdAfx.h" +#include +#include +#include + +#include "http.h" +#include "http/lib_http.h" + +static void __hdr_init(HTTP_HDR_RES *hh) +{ + hh->reply_status = 0; +} + +static void cache_free(ACL_ARRAY *pool) +{ + acl_array_free(pool, (void (*)(void*)) http_hdr_res_free); +} + +static acl_pthread_key_t cache_key = -1; +#ifndef USE_TLS_EX +static acl_pthread_once_t once_control = ACL_PTHREAD_ONCE_INIT; +static void cache_init(void) +{ + acl_pthread_key_create(&cache_key, (void (*)(void*)) cache_free); +} +#endif + +/* 生成一个新的 HTTP_HDR_RES 数据结构 */ + +HTTP_HDR_RES *http_hdr_res_new(void) +{ + HTTP_HDR_RES *hh; + ACL_ARRAY *pool; + + if (var_http_tls_cache <= 0) { + hh = (HTTP_HDR_RES *) http_hdr_new(sizeof(HTTP_HDR_RES)); + __hdr_init(hh); + return (hh); + } + +#ifdef USE_TLS_EX + pool = (ACL_ARRAY*) acl_pthread_tls_get(&cache_key); + if (pool == NULL) { + pool = acl_array_create(100); + acl_pthread_tls_set(cache_key, pool, (void (*)(void*)) cache_free); + } + + pool = (ACL_ARRAY*) acl_pthread_tls_get(&cache_key); + hh = (HTTP_HDR_RES*) pool->pop_back(pool); + if (hh) { + http_hdr_reset((HTTP_HDR *) hh); + __hdr_init(hh); + return (hh); + } +#else + acl_pthread_once(&once_control, cache_init); + pool = (ACL_ARRAY*) acl_pthread_getspecific(cache_key); + if (pool == NULL) { + pool = acl_array_create(100); + acl_pthread_setspecific(cache_key, pool); + } + hh = (HTTP_HDR_RES*) pool->pop_back(pool); + if (hh) { + http_hdr_reset((HTTP_HDR *) hh); + __hdr_init(hh); + return (hh); + } +#endif + + hh = (HTTP_HDR_RES *) http_hdr_new(sizeof(HTTP_HDR_RES)); + __hdr_init(hh); + return (hh); +} + +HTTP_HDR_RES *http_hdr_res_clone(const HTTP_HDR_RES *hdr_res) +{ + HTTP_HDR_RES *hh; + + hh = http_hdr_res_new(); + http_hdr_clone(&hdr_res->hdr, &hh->hdr); + + hh->reply_status = hdr_res->reply_status; + return (hh); +} + +static void __hdr_free_member(HTTP_HDR_RES *hh acl_unused) +{ +} + +/* 释放一个 HTTP_HDR_RES 结构 */ + +void http_hdr_res_free(HTTP_HDR_RES *hh) +{ + ACL_ARRAY *pool; + + if (hh == NULL) + return; + + if (var_http_tls_cache <= 0) { + __hdr_free_member(hh); + http_hdr_free((HTTP_HDR *) hh); + return; + } + +#ifdef USE_TLS_EX + pool = (ACL_ARRAY*) acl_pthread_tls_get(&cache_key); + if (pool != NULL) { + pool->push_back(pool, hh); + return; + } +#else + pool = (ACL_ARRAY*) acl_pthread_getspecific(cache_key); + if (pool != NULL && acl_array_size(pool) < var_http_tls_cache) { + pool->push_back(pool, hh); + return; + } +#endif + + __hdr_free_member(hh); + http_hdr_free((HTTP_HDR *) hh); +} + +void http_hdr_res_reset(HTTP_HDR_RES *hh) +{ + if (hh == NULL) + return; + + http_hdr_reset((HTTP_HDR *) hh); + __hdr_free_member(hh); + __hdr_init(hh); +} + +int http_hdr_res_status_parse(HTTP_HDR_RES *hh, const char *dbuf) +{ + char myname[] = "http_hdr_res_status_parse"; + ACL_ARGV *status_argv; + char *ptr; + + if (hh == NULL || dbuf == NULL) { + acl_msg_error("%s, %s(%d): input invalid", + __FILE__, myname, __LINE__); + return (-1); + } + + /* data: HTTP/1.1 XXX info */ + + status_argv = acl_argv_split(dbuf, "\t "); + if (status_argv->argc < 2) { + acl_msg_error("%s, %s(%d): invalid reply status line=%s", + __FILE__, myname, __LINE__, dbuf); + acl_argv_free(status_argv); + return (-1); + } + + ptr = acl_argv_index(status_argv, 0); + if (http_hdr_parse_version(&hh->hdr, ptr) < 0) { + acl_argv_free(status_argv); + return (-1); + } + + ptr = acl_argv_index(status_argv, 1); + if (ptr == NULL) + acl_msg_fatal("%s, %s(%d): null value, idx=1, argc=%d", + __FILE__, myname, __LINE__, status_argv->argc); + hh->reply_status = atoi(ptr); + if (hh->reply_status < 0) { + acl_msg_error("%s, %s(%d): invalid status(%d)", + __FILE__, myname, __LINE__, hh->reply_status); + acl_argv_free(status_argv); + return (-1); + } + acl_argv_free(status_argv); + return (0); +} + +int http_hdr_res_parse(HTTP_HDR_RES *hdr_res) +{ + const char *myname = "http_hdr_res_parse"; + HTTP_HDR *hdr = (HTTP_HDR *) hdr_res; + HTTP_HDR_ENTRY *entry; + char *ptr; + char buf[32]; /* 2xx, 3xx, 4xx, 5xx */ + int n; + + if (hdr == NULL) + acl_msg_fatal("%s: hdr_res null", myname); + if (hdr->entry_lnk == NULL) + acl_msg_fatal("%s: entry_lnk null", myname); + n = acl_array_size(hdr->entry_lnk); + if (n <= 0) { + acl_msg_error("%s: entry_lnk's size %d invalid", myname, n); + return (-1); + } + + /* data format: xxx info */ + entry = (HTTP_HDR_ENTRY *) acl_array_index(hdr->entry_lnk, 0); + + ptr = entry->value; + while (*ptr == ' ' || *ptr == '\t') + ptr++; + if (*ptr == 0) { + acl_msg_error("%s: status empty", myname); + return (-1); + } + + snprintf(buf, sizeof(buf), "%s", ptr); + ptr = buf; + while (*ptr) { + if (*ptr == ' ' || *ptr == '\t') { + *ptr = 0; + break; + } + ptr++; + } + + hdr_res->reply_status = atoi(buf); + if (hdr_res->reply_status < 100 || hdr_res->reply_status >= 600) { + acl_msg_error("%s: status(%d) invalid", myname, hdr_res->reply_status); + return (-1); + } + + return (http_hdr_parse(hdr)); +} + +int http_hdr_res_range(HTTP_HDR_RES *hdr_res, http_off_t *range_from, + http_off_t *range_to, http_off_t *total_length) +{ + const char* myname = "http_hdr_res_range"; + const char* value; + char buf[256], *ptr, *pfrom, *pto; + + if (hdr_res == NULL) + acl_msg_fatal("%s(%d): hdr_res null", myname, __LINE__); + if (range_from == NULL) + acl_msg_fatal("%s(%d): range_from null", myname, __LINE__); + if (range_to == NULL) + acl_msg_fatal("%s(%d): range_to null", myname, __LINE__); + + value = http_hdr_entry_value(&hdr_res->hdr, "Content-Range"); + if (value == NULL) + return (-1); + + ACL_SAFE_STRNCPY(buf, value, sizeof(buf)); + /* 响应的 Range 数据格式:Content-Range: bytes {range_from}-{range_to}/{total_length} + * 其中: {range_from}, {range_to} 的下标是从0开始的 + */ + /* Content-Range: bytes 2250000-11665200/11665201 */ + /* value: bytes 2250000-11665200/11665201 */ + if (strncasecmp(buf, "bytes", sizeof("bytes") - 1) != 0) + return (-1); + + ptr = buf + sizeof("bytes") -1; + while (*ptr == ' ' || *ptr == '\t') { + ptr++; + } + if (*ptr == 0) + return (-1); + + /* ptr: 2250000-11665200/11665201 */ + pfrom = ptr; + pto = strchr(pfrom, '-'); + if (pto == NULL || pto == pfrom) + return (-1); + *pto++ = 0; + /* pto: 11665200/11665201 */ + + ptr = strchr(pto, '/'); + if (ptr == NULL || ptr == pto) + return (-1); + + *ptr++ = 0; + + /* pto: 11665200; ptr: 11665201 */ + + *range_from = acl_atoi64(pfrom); + if (*range_from < 0) + return (-1); + + *range_to = acl_atoi64(pto); + if (*range_to < 0) + return (-1); + + /* 可选项 */ + if (total_length) { + *total_length = acl_atoi64(ptr); + if (*total_length < 0) + return (-1); + } + return (0); +} diff --git a/lib_protocol/src/http/http_init.c b/lib_protocol/src/http/http_init.c new file mode 100644 index 000000000..b1cd5a130 --- /dev/null +++ b/lib_protocol/src/http/http_init.c @@ -0,0 +1,33 @@ +#include "StdAfx.h" +#include +#include + +#include "http/lib_http_struct.h" +#include "http/lib_http.h" +#include "http.h" + +http_off_t var_http_buf_size = HTTP_BSIZE; +int var_http_tls_cache = 50; + +void http_buf_size_set(http_off_t size) +{ + if (size > 1024) + var_http_buf_size = size; +} + +http_off_t http_buf_size_get(void) +{ + return (var_http_buf_size); +} + +void http_init(const char *tmpl_path) +{ + const char *path = tmpl_path ? tmpl_path : "/opt/acl/httpd/pub"; + + http_tmpl_load(path); +} + +void http_hdr_cache(int max) +{ + var_http_tls_cache = max; +} diff --git a/lib_protocol/src/http/http_req.c b/lib_protocol/src/http/http_req.c new file mode 100644 index 000000000..813072cd2 --- /dev/null +++ b/lib_protocol/src/http/http_req.c @@ -0,0 +1,34 @@ +#include "StdAfx.h" +#include +#include +#include + +#include "http/lib_http.h" + +HTTP_REQ *http_req_new(HTTP_HDR_REQ *hdr_req) +{ + char myname[] = "http_req_new"; + HTTP_REQ *request; + + request = (HTTP_REQ*) acl_mycalloc(1, sizeof(HTTP_REQ)); + if (request == NULL) { + char ebuf[256]; + acl_msg_fatal("%s, %s(%d): calloc error(%s)", + __FILE__, myname, __LINE__, acl_last_strerror(ebuf, sizeof(ebuf))); + } + + request->hdr_req = hdr_req; + return (request); +} + +void http_req_free(HTTP_REQ *request) +{ + if (request) { + if (request->hdr_req) + http_hdr_req_free(request->hdr_req); + if (request->ctx && request->free_ctx) + request->free_ctx(request->ctx); + acl_myfree(request); + } +} + diff --git a/lib_protocol/src/http/http_res.c b/lib_protocol/src/http/http_res.c new file mode 100644 index 000000000..9bfbdaa99 --- /dev/null +++ b/lib_protocol/src/http/http_res.c @@ -0,0 +1,33 @@ +#include "StdAfx.h" +#include +#include +#include + +#include "http/lib_http.h" + +HTTP_RES *http_res_new(HTTP_HDR_RES *hdr_res) +{ + char myname[] = "http_res_new"; + HTTP_RES *respond; + + respond = (HTTP_RES*) acl_mycalloc(1, sizeof(HTTP_RES)); + if (respond == NULL) { + char ebuf[256]; + acl_msg_fatal("%s, %s(%d): calloc error(%s)", + __FILE__, myname, __LINE__, acl_last_strerror(ebuf, sizeof(ebuf))); + } + respond->hdr_res = hdr_res; + return (respond); +} + +void http_res_free(HTTP_RES *respond) +{ + if (respond) { + if (respond->hdr_res) + http_hdr_res_free(respond->hdr_res); + if (respond->ctx && respond->free_ctx) + respond->free_ctx(respond->ctx); + acl_myfree(respond); + } +} + diff --git a/lib_protocol/src/http/http_rfc1123.c b/lib_protocol/src/http/http_rfc1123.c new file mode 100644 index 000000000..0625c6c90 --- /dev/null +++ b/lib_protocol/src/http/http_rfc1123.c @@ -0,0 +1,15 @@ +#include "StdAfx.h" +#include + +#include "http/lib_http.h" + +#define RFC1123_STRFTIME "%a, %d %b %Y %H:%M:%S GMT" + +const char *http_mkrfc1123(char *buf, size_t size, time_t t) +{ + struct tm *gmt = gmtime(&t); + + strftime(buf, size - 1, RFC1123_STRFTIME, gmt); + return (buf); +} + diff --git a/lib_protocol/src/http/http_status.c b/lib_protocol/src/http/http_status.c new file mode 100644 index 000000000..b4653b0d4 --- /dev/null +++ b/lib_protocol/src/http/http_status.c @@ -0,0 +1,121 @@ +#include "StdAfx.h" +#include +#include +#include + +#include "http/lib_http.h" + +typedef struct STATUS_LINE { + int status; + const char *info; +} STATUS_LINE; + +static STATUS_LINE __status_lines_100[] = { + { 100, "100 Continue" }, + { 101, "101 Switching Protocols" }, + { 102, "102 Processing" }, +}; + +static STATUS_LINE __status_lines_200[] = { + { 200, "200 OK" }, + { 201, "201 Created" }, + { 202, "202 Accepted" }, + { 203, "203 Non-Authoritative Information" }, + { 204, "204 No Content" }, + { 205, "205 Reset Content" }, + { 206, "206 Partial Content" }, + { 207, "207 Multi-Status" }, +}; + +static STATUS_LINE __status_lines_300[] = { + { 300, "300 Multiple Choices" }, + { 301, "301 Moved Permanently" }, + { 302, "302 Found" }, + { 303, "303 See Other" }, + { 304, "304 Not Modified" }, + { 305, "305 Use Proxy" }, + { 306, "306 unused" }, + { 307, "307 Temporary Redirect" }, +}; + +static STATUS_LINE __status_lines_400[] = { + { 400, "400 Bad Request" }, + { 401, "401 Authorization Required" }, + { 402, "402 Payment Required" }, + { 403, "403 Forbidden" }, + { 404, "404 Not Found" }, + { 405, "405 Method Not Allowed" }, + { 406, "406 Not Acceptable" }, + { 407, "407 Proxy Authentication Required" }, + { 408, "408 Request Time-out" }, + { 409, "409 Conflict" }, + { 410, "410 Gone" }, + { 411, "411 Length Required" }, + { 412, "412 Precondition Failed" }, + { 413, "413 Request Entity Too Large" }, + { 414, "414 Request-URI Too Large" }, + { 415, "415 Unsupported Media Type" }, + { 416, "416 Requested Range Not Satisfiable" }, + { 417, "417 Expectation Failed" }, + { 418, NULL }, + { 419, NULL }, + { 420, NULL }, + { 421, NULL }, + { 422, "422 Unprocessable Entity" }, + { 423, "423 Locked" }, + { 424, "424 Failed Dependency" }, + { 425, "425 No code" }, + { 426, "426 Upgrade Required" }, +}; + +static STATUS_LINE __status_lines_500[] = { + { 500, "500 Internal Server Error" }, + { 501, "501 Method Not Implemented" }, + { 502, "502 Bad Gateway" }, + { 503, "503 Service Temporarily Unavailable" }, + { 504, "504 Gateway Time-out" }, + { 505, "505 HTTP Version Not Supported" }, + { 506, "506 Variant Also Negotiates" }, + { 507, "507 Insufficient Storage" }, + { 508, NULL }, + { 509, NULL }, + { 510, "510 Not Extended" }, +}; + +typedef struct STATUS_MAP { + int level; + int size; + STATUS_LINE *status_lines; +} STATUS_MAP; + +static STATUS_MAP __status_maps[] = { + { 100, sizeof(__status_lines_100) / sizeof(STATUS_LINE), __status_lines_100 }, + { 200, sizeof(__status_lines_200) / sizeof(STATUS_LINE), __status_lines_200 }, + { 300, sizeof(__status_lines_300) / sizeof(STATUS_LINE), __status_lines_300 }, + { 400, sizeof(__status_lines_400) / sizeof(STATUS_LINE), __status_lines_400 }, + { 500, sizeof(__status_lines_500) / sizeof(STATUS_LINE), __status_lines_500 }, +}; + +#define UNKNOWN_ERROR_INFO "500 Internal Server Error(unknown)" + +const char *http_status_line(int status) +{ + int i, pos; + + i = status / 100; + if (i < 1 || i > 5) + return (UNKNOWN_ERROR_INFO); + + i--; + pos = status - __status_maps[i].level; + + if (pos >= __status_maps[i].size) + return (UNKNOWN_ERROR_INFO); + + if (__status_maps[i].status_lines[pos].info == NULL) + return (UNKNOWN_ERROR_INFO); + + return (__status_maps[i].status_lines[pos].info); +} + + diff --git a/lib_protocol/src/http/http_tmpl.c b/lib_protocol/src/http/http_tmpl.c new file mode 100644 index 000000000..f7909c972 --- /dev/null +++ b/lib_protocol/src/http/http_tmpl.c @@ -0,0 +1,261 @@ +#include "StdAfx.h" +#include +#include +#include + +#include "http/lib_http.h" + +typedef struct HTTP_TMPL { + int status; + const char *title; + const char *filename; + ACL_VSTRING *buf; +} HTTP_TMPL; + +static HTTP_TMPL __tmpl_1xx_tab[] = { + /* 1xx */ + { 100, "Continue", "100.html", NULL }, + { 101, "Switching Protocols", "101.html", NULL }, + { 102, "Processing", "102.html", NULL }, /* RFC2518 section 10.1 */ +}; + +static HTTP_TMPL __tmpl_2xx_tab[] = { + /* 2xx */ + { 200, "OK", "200.html", NULL }, + { 201, "Created", "201.html", NULL }, + { 202, "Accepted", "202.html", NULL }, + { 203, "Non Authoritative Information", "203.html", NULL }, + { 204, "No Content", "204.html", NULL }, + { 205, "Reset Content", "205.html", NULL }, + { 206, "Partial Content", "206.html", NULL }, + { 207, "Multi Status", "207.html", NULL }, /* RFC2518 section 10.2 */ +}; + +static HTTP_TMPL __tmpl_3xx_tab[] = { + /* 3xx */ + { 300, "Multiple Choices", "300.html", NULL }, + { 301, "Moved Permanently", "301.html", NULL }, + { 302, "Moved Temporarily", "302.html", NULL }, + { 303, "See Other", "303.html", NULL }, + { 304, "Not Modified", "304.html", NULL }, + { 305, "Use Proxy", "305.html", NULL }, + { 307, "Temporary Redirect", "307.html", NULL }, +}; + +static HTTP_TMPL __tmpl_4xx_tab[] = { + /* 4xx */ + { 400, "Bad Request", "400.html", NULL }, + { 401, "Authorization Required", "401.html", NULL }, + { 402, "Payment Required", "402.html", NULL }, + { 403, "Forbidden", "403.html", NULL }, + { 404, "Not Found", "404.html", NULL }, + { 405, "Method Not Allowed", "405.html", NULL }, + { 406, "Not Acceptable", "406.html", NULL }, + { 407, "Proxy Authentication Required", "407.html", NULL }, + { 408, "Request Time-out", "408.html", NULL }, + { 409, "Conflict", "409.html", NULL }, + { 410, "Gone", "410.html", NULL }, + { 411, "Length Required", "411.html", NULL }, + { 412, "Precondition Failed", "412.html", NULL }, + { 413, "Request Entity Too Large", "413.html", NULL }, + { 414, "Request-URI Too Large", "414.html", NULL }, + { 415, "Unsupported Media Type", "415.html", NULL }, + { 416, "Requested Range Not Satisfiable", "416.html", NULL }, + { 417, "Expectation Failed", "417.html", NULL }, + { 418, NULL, NULL, NULL }, + { 419, NULL, NULL, NULL }, + { 420, NULL, NULL, NULL }, + { 421, NULL, NULL, NULL }, + { 422, "Unprocessable Entity", "422.html", NULL }, + { 423, "Locked", "423.html", NULL }, + { 424, "Failed Dependency", "424.html", NULL }, + { 425, "No code", "425.html", NULL }, + { 426, "Upgrade Required", "426.html", NULL }, +}; + +static HTTP_TMPL __tmpl_5xx_tab[] = { + /* 5xx */ + { 500, "Internal Server Error", "500.html", NULL }, + { 501, "Method Not Implemented", "501.html", NULL }, + { 502, "Bad Gateway", "502.html", NULL }, + { 503, "Service Temporarily Unavailable", "503.html", NULL }, + { 504, "Gateway Time-out", "504.html", NULL }, + { 505, "HTTP Version Not Supported", "505.html", NULL }, + { 506, "Variant Also Negotiates", "506.html", NULL }, + { 507, "Insufficient Storage", "507.html", NULL }, + { 508, NULL, NULL, NULL }, + { 509, NULL, NULL, NULL }, + { 510, "Not Extended", "508.html", NULL }, +}; + +typedef struct TMPL_MAP { + int level; + int size; + HTTP_TMPL *tmpl; +} TMPL_MAP; + +static TMPL_MAP __tmpl_maps[] = { + { 100, sizeof(__tmpl_1xx_tab) / sizeof(HTTP_TMPL), __tmpl_1xx_tab }, + { 200, sizeof(__tmpl_2xx_tab) / sizeof(HTTP_TMPL), __tmpl_2xx_tab }, + { 300, sizeof(__tmpl_3xx_tab) / sizeof(HTTP_TMPL), __tmpl_3xx_tab }, + { 400, sizeof(__tmpl_4xx_tab) / sizeof(HTTP_TMPL), __tmpl_4xx_tab }, + { 500, sizeof(__tmpl_5xx_tab) / sizeof(HTTP_TMPL), __tmpl_5xx_tab }, +}; + +static ACL_VSTRING *__unknown_tmpl; +static char *__unknown_status = "unknow status"; + +static void __load_tmpl(const char *tmpl_path, HTTP_TMPL *tmpl) +{ + const char *myname = "__load_tmpl"; + ACL_VSTRING *buf = acl_vstring_alloc(256); + char tbuf[4096]; + const char *ptr; + ACL_VSTREAM *fp; + int n; + char ebuf[256]; + + if (buf == NULL) + acl_msg_fatal("%s, %s(%d): calloc error(%s)", + __FILE__, myname, __LINE__, acl_last_strerror(ebuf, sizeof(ebuf))); + + ptr = tmpl_path + strlen(tmpl_path); + ptr--; + + if (*ptr == '/') + acl_vstring_sprintf(buf, "%s%s", tmpl_path, tmpl->filename); + else + acl_vstring_sprintf(buf, "%s/%s", tmpl_path, tmpl->filename); + + tmpl->buf = acl_vstring_alloc(4096); + if (tmpl->buf == NULL) + acl_msg_fatal("%s, %s(%d): calloc error(%s)", + __FILE__, myname, __LINE__, acl_last_strerror(ebuf, sizeof(ebuf))); + + fp = acl_vstream_fopen(acl_vstring_str(buf), O_WRONLY, 0660, 4096); + if (fp == NULL) { + acl_vstring_sprintf(tmpl->buf, "%d %s", tmpl->status, tmpl->title); + acl_vstring_free(buf); + return; + } + + while (1) { + n = acl_vstream_gets(fp, tbuf, sizeof(tbuf)); + if (n == ACL_VSTREAM_EOF) + break; + acl_vstring_sprintf_append(tmpl->buf, "%s", tbuf); + } + + acl_vstream_close(fp); + acl_vstring_free(buf); +} + +void http_tmpl_load(const char *tmpl_path) +{ + const char *myname = "http_tmpl_init"; + int i, n; + + if (tmpl_path == NULL || strlen(tmpl_path) == 0) + acl_msg_fatal("%s, %s(%d): tmpl_path invalid", + __FILE__, myname, __LINE__); + + __unknown_tmpl = acl_vstring_alloc(256); + if (__unknown_tmpl == NULL) { + char ebuf[256]; + acl_msg_fatal("%s, %s(%d): alloc error(%s)", + __FILE__, myname, __LINE__, acl_last_strerror(ebuf, sizeof(ebuf))); + } + acl_vstring_sprintf(__unknown_tmpl, "500 unknown error"); + + n = sizeof(__tmpl_1xx_tab) / sizeof(HTTP_TMPL); + for (i = 0; i < n; i++) { + if (__tmpl_1xx_tab[i].title != NULL) + __load_tmpl(tmpl_path, &__tmpl_1xx_tab[i]); + } + + n = sizeof(__tmpl_2xx_tab) / sizeof(HTTP_TMPL); + for (i = 0; i < n; i++) { + if (__tmpl_2xx_tab[i].title != NULL) + __load_tmpl(tmpl_path, &__tmpl_2xx_tab[i]); + } + + n = sizeof(__tmpl_3xx_tab) / sizeof(HTTP_TMPL); + for (i = 0; i < n; i++) { + if (__tmpl_3xx_tab[i].title != NULL) + __load_tmpl(tmpl_path, &__tmpl_3xx_tab[i]); + } + + n = sizeof(__tmpl_4xx_tab) / sizeof(HTTP_TMPL); + for (i = 0; i < n; i++) { + if (__tmpl_4xx_tab[i].title != NULL) + __load_tmpl(tmpl_path, &__tmpl_4xx_tab[i]); + } + + n = sizeof(__tmpl_5xx_tab) / sizeof(HTTP_TMPL); + for (i = 0; i < n; i++) { + if (__tmpl_5xx_tab[i].title != NULL) + __load_tmpl(tmpl_path, &__tmpl_5xx_tab[i]); + } +} + +const ACL_VSTRING *http_tmpl_get(int status) +{ + int i, pos; + + i = status / 100; + if (i < 1 || i > 5) + return (__unknown_tmpl); + + i--; + pos = status - __tmpl_maps[i].level; + + if (pos >= __tmpl_maps[i].size) + return (__unknown_tmpl); + + if (__tmpl_maps[i].tmpl[pos].buf == NULL) + return (__unknown_tmpl); + + return (__tmpl_maps[i].tmpl[pos].buf); +} + +const char *http_tmpl_title(int status) +{ + int i, pos; + + i = status / 100; + if (i < 1 || i > 5) + return (__unknown_status); + + i--; + pos = status - __tmpl_maps[i].level; + + if (pos >= __tmpl_maps[i].size) + return (__unknown_status); + + if (__tmpl_maps[i].tmpl[pos].buf == NULL) + return (__unknown_status); + + return (__tmpl_maps[i].tmpl[pos].title); +} + +int http_tmpl_size(int status) +{ + int i, pos; + + i = status / 100; + + if (i < 1 || i > 5) + return ((int) ACL_VSTRING_LEN(__unknown_tmpl)); + + i--; + pos = status - __tmpl_maps[i].level; + + if (pos >= __tmpl_maps[i].size) + return ((int) ACL_VSTRING_LEN(__unknown_tmpl)); + + if (__tmpl_maps[i].tmpl[pos].buf == NULL) + return ((int) ACL_VSTRING_LEN(__unknown_tmpl)); + + return ((int) ACL_VSTRING_LEN(__tmpl_maps[i].tmpl[pos].buf)); +} + diff --git a/lib_protocol/src/http/http_util.c b/lib_protocol/src/http/http_util.c new file mode 100644 index 000000000..b91a3ab27 --- /dev/null +++ b/lib_protocol/src/http/http_util.c @@ -0,0 +1,458 @@ +#include "StdAfx.h" +#include +#include "http/lib_http_struct.h" +#include "http/lib_http.h" +#include "http/lib_http_util.h" + +void http_util_free(HTTP_UTIL *http_util) +{ + if ((http_util->flag & HTTP_UTIL_FLAG_SET_DUMP_FILE)) { + if (http_util->dump_stream) + acl_vstream_close(http_util->dump_stream); + } + + if (http_util->stream) + acl_vstream_close(http_util->stream); + if (http_util->req_buf) + acl_vstring_free(http_util->req_buf); + if (http_util->hdr_req) + http_hdr_req_free(http_util->hdr_req); + if (http_util->http_res) + http_res_free(http_util->http_res); + else if (http_util->hdr_res) + http_hdr_res_free(http_util->hdr_res); + acl_myfree(http_util); +} + +HTTP_UTIL *http_util_req_new(const char *url, const char *method) +{ + const char *myname = "http_util_req_new"; + HTTP_UTIL *http_util = (HTTP_UTIL*) acl_mycalloc(1, sizeof(HTTP_UTIL)); + const char *ptr, *host; + + if (url == NULL || *url == 0) { + acl_msg_error("%s(%d): url invalid", myname, __LINE__); + return (NULL); + } + if (method == NULL || *method == 0) { + acl_msg_error("%s(%d): method invalid", myname, __LINE__); + return (NULL); + } + + if (acl_strncasecmp(url, "http://", sizeof("http://") - 1) != 0) { + acl_msg_error("%s(%d): url(%s) invalid", myname, __LINE__, url); + return (NULL); + } + + if (strcmp(method, "GET") != 0 && strcmp(method, "POST") != 0 + && strcmp(method, "HEAD") != 0 && strcmp(method, "CONNECT") != 0) + { + acl_msg_error("%s(%d): method(%s) invalid", myname, __LINE__, method); + return (NULL); + } + + http_util->hdr_req = http_hdr_req_create(url, method, "HTTP/1.1"); + http_util->hdr_res = http_hdr_res_new(); + http_util->http_res = http_res_new(http_util->hdr_res); + http_util->req_buf = acl_vstring_alloc(4096); + + host = http_hdr_req_host(http_util->hdr_req); + if (host) { + ptr = strchr(host, ':'); + if (ptr == NULL) + snprintf(http_util->server_addr, + sizeof(http_util->server_addr), "%s:80", host); + else + ACL_SAFE_STRNCPY(http_util->server_addr, host, + sizeof(http_util->server_addr)); + } + + http_util->conn_timeout = 10; + http_util->rw_timeout = 10; + return (http_util); +} + +HTTP_UTIL *http_util_res_new(int status) +{ + HTTP_UTIL *http_util = (HTTP_UTIL*) acl_mycalloc(1, sizeof(HTTP_UTIL)); + + http_util->hdr_res = http_hdr_res_static(status); + return (http_util); +} + +void http_util_set_req_entry(HTTP_UTIL *http_util, const char *name, const char *value) +{ + if (name && *name && value && *value) + http_hdr_entry_replace(&http_util->hdr_req->hdr, name, value, 1); +} + +void http_util_off_req_entry(HTTP_UTIL *http_util, const char *name) +{ + if (name && *name) + http_hdr_entry_off(&http_util->hdr_req->hdr, name); +} + +char *http_util_get_req_value(HTTP_UTIL *http_util, const char *name) +{ + if (name == NULL || *name == 0) + return (NULL); + return (http_hdr_entry_value(&http_util->hdr_req->hdr, name)); +} + +HTTP_HDR_ENTRY *http_util_get_req_entry(HTTP_UTIL *http_util, const char *name) +{ + if (name == NULL || *name == 0) + return (NULL); + return (http_hdr_entry(&http_util->hdr_req->hdr, name)); +} + +void http_util_set_req_content_length(HTTP_UTIL *http_util, int len) +{ + char buf[32]; + + if (len < 0) + return; + + snprintf(buf, sizeof(buf), "%d", len); + http_hdr_entry_replace(&http_util->hdr_req->hdr, "Content-Length", buf, 1); +} + +void http_util_set_req_keep_alive(HTTP_UTIL *http_util, int timeout) +{ + char buf[32]; + + snprintf(buf, sizeof(buf), "%d", timeout); + http_hdr_entry_replace(&http_util->hdr_req->hdr, "Connection", "keep-alive", 1); + http_hdr_entry_replace(&http_util->hdr_req->hdr, "Keep-Alive", buf, 1); +} + +void http_util_set_req_connection(HTTP_UTIL *http_util, const char *value) +{ + if (value == NULL || *value == 0) + return; + http_hdr_entry_replace(&http_util->hdr_req->hdr, "Connection", value, 1); +} + +void http_util_set_req_refer(HTTP_UTIL *http_util, const char *refer) +{ + if (refer == NULL || *refer == 0) + return; + http_hdr_entry_replace(&http_util->hdr_req->hdr, "Referer", refer, 1); +} + +void http_util_set_req_cookie(HTTP_UTIL *http_util, const char *name, const char *value) +{ + HTTP_HDR_ENTRY *hdr_entry; + char *ptr; + + if (name == NULL || *name == 0 || value == NULL) + return; + hdr_entry = http_hdr_entry(&http_util->hdr_req->hdr, name); + if (hdr_entry == NULL) { + http_hdr_put_str(&http_util->hdr_req->hdr, name, value); + return; + } + + ptr = acl_concatenate(hdr_entry->value, "; ", name, "=", value, NULL); + acl_myfree(hdr_entry->value); + hdr_entry->value = ptr; +} + +void http_util_set_req_proxy(HTTP_UTIL *http_util, const char *proxy) +{ + if (proxy && *proxy) + ACL_SAFE_STRNCPY(http_util->server_addr, proxy, + sizeof(http_util->server_addr)); +} + +void http_util_set_dump_stream(HTTP_UTIL *http_util, ACL_VSTREAM *stream) +{ + const char *myname = "http_util_set_dump_stream"; + + if (stream == NULL) + return; + + if ((http_util->flag & HTTP_UTIL_FLAG_SET_DUMP_FILE)) { + acl_msg_error("%s(%d): You've called http_util_set_dump_file before!", + myname, __LINE__); + return; + } + + http_util->dump_stream = stream; + http_util->flag |= HTTP_UTIL_FLAG_SET_DUMP_STREAM; +} + +int http_util_set_dump_file(HTTP_UTIL *http_util, const char *filename) +{ + const char *myname = "http_util_set_dump_file"; + + if (filename == NULL || *filename == 0) { + acl_msg_error("%s(%d): filename invalid", myname, __LINE__); + return (-1); + } + if ((http_util->flag & HTTP_UTIL_FLAG_SET_DUMP_STREAM)) { + acl_msg_error("%s(%d): You've called http_util_set_dump_stream before!", + myname, __LINE__); + return (-1); + } + + http_util->dump_stream = acl_vstream_fopen(filename, + O_CREAT | O_TRUNC | O_WRONLY, 0600, 4096); + if (http_util->dump_stream == NULL) { + acl_msg_error("%s(%d): open dump file(%s) error(%s)", + myname, __LINE__, filename, acl_last_serror()); + return (-1); + } + http_util->flag |= HTTP_UTIL_FLAG_SET_DUMP_FILE; + return (0); +} + +int http_util_req_open(HTTP_UTIL *http_util) +{ + const char *myname = "http_util_req_open"; + int ret; + + /* 连接远程 http 服务器 */ + + http_util->stream = acl_vstream_connect(http_util->server_addr, + ACL_BLOCKING /* 采用阻塞方式 */, + http_util->conn_timeout /* 连接超时时间 */, + http_util->rw_timeout /* 网络 IO 操作超时时间 */, + 4096 /* stream 流缓冲区大小为 4096 字节 */); + if (http_util->stream == NULL) { + acl_msg_error("%s(%d): connect %s error(%s)", + myname, __LINE__, http_util->server_addr, + acl_last_serror()); + return (-1); + } + + /* 构建 HTTP 请求头数据 */ + + http_hdr_build_request(http_util->hdr_req, http_util->req_buf); + + /* 向 HTTP 服务器发送请求 */ + + ret = acl_vstream_writen(http_util->stream, + acl_vstring_str(http_util->req_buf), + ACL_VSTRING_LEN(http_util->req_buf)); + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): send request to server(%s) error(%s)", + myname, __LINE__, http_util->server_addr, + acl_last_serror()); + return (-1); + } + + return (0); +} + +int http_util_put_req_data(HTTP_UTIL *http_util, const char *data, size_t dlen) +{ + const char *myname = "http_util_put_req_data"; + + if (data == NULL || dlen == 0) { + acl_msg_info("%s(%d): data %s, dlen %d invalid", + myname, __LINE__, data ? "not null" : "null", (int) dlen); + return (-1); + } + if (acl_vstream_writen(http_util->stream, data, dlen) == ACL_VSTREAM_EOF) + return (-1); + return ((int) dlen); +} + +int http_util_get_res_hdr(HTTP_UTIL *http_util) +{ + const char *myname = "http_util_get_res_hdr"; + int ret; + + /* 读取 HTTP 服务器响应头*/ + + ret = http_hdr_res_get_sync(http_util->hdr_res, + http_util->stream, http_util->rw_timeout); + if (ret < 0) { + acl_msg_error("%s(%d): get respond header error(%s)", + myname, __LINE__, acl_last_serror()); + return (-1); + } else if (http_hdr_res_parse(http_util->hdr_res) < 0) { + acl_msg_error("%s(%d): parse respond header error", + myname, __LINE__); + return (-1); + } else + return (0); +} + +char *http_util_get_res_value(HTTP_UTIL *http_util, const char *name) +{ + if (name == NULL || *name == 0) + return (NULL); + return (http_hdr_entry_value(&http_util->hdr_res->hdr, name)); +} + +HTTP_HDR_ENTRY *http_util_get_res_entry(HTTP_UTIL *http_util, const char *name) +{ + if (name == NULL || *name == 0) + return (NULL); + return (http_hdr_entry(&http_util->hdr_res->hdr, name)); +} + +void http_util_set_res_entry(HTTP_UTIL *http_util, const char *name, const char *value) +{ + if (name == NULL || *name == 0 || value == NULL || *value == 0) + return; + http_hdr_entry_replace(&http_util->hdr_res->hdr, name, value, 1); +} + +void http_util_off_res_entry(HTTP_UTIL *http_util, const char *name) +{ + if (name == NULL || *name == 0) + return; + http_hdr_entry_off(&http_util->hdr_res->hdr, name); +} + +int http_util_has_res_body(HTTP_UTIL *http_util) +{ + if (http_util->hdr_res->hdr.content_length == 0 + || (http_util->hdr_res->hdr.content_length == -1 + && !http_util->hdr_res->hdr.chunked + && http_util->hdr_res->reply_status > 300 + && http_util->hdr_res->reply_status < 400)) + { + http_util->flag |= HTTP_UTIL_FLAG_NO_RES_BODY; + http_util->flag &= ~HTTP_UTIL_FLAG_HAS_RES_BODY; + return (0); + } else { + http_util->flag |= HTTP_UTIL_FLAG_HAS_RES_BODY; + http_util->flag &= ~HTTP_UTIL_FLAG_NO_RES_BODY; + return (1); + } +} + +int http_util_get_res_body(HTTP_UTIL *http_util, char *buf, size_t size) +{ + const char *myname = "http_util_get_res_body"; + int ret; + + if (buf == NULL || size == 0) { + acl_msg_error("%s(%d): buf(%s), size(%d) invalid", + myname, __LINE__, buf ? "not null" : "null", (int) size); + return (-1); + } + + if ((http_util->flag & (HTTP_UTIL_FLAG_HAS_RES_BODY + | HTTP_UTIL_FLAG_NO_RES_BODY)) == 0) + { + if (!http_util_has_res_body(http_util)) + return (http_util->res_body_dlen); + } + + ret = (int) http_res_body_get_sync(http_util->http_res, + http_util->stream, buf, (int) size); + if (ret <= 0) + return (ret); + http_util->res_body_dlen += ret; + if (http_util->dump_stream == NULL) + return (ret); + + if (acl_vstream_writen(http_util->dump_stream, buf, ret) == ACL_VSTREAM_EOF) + { + /* 如果有一次不能转储数据至文件或流则关闭该功能不再进行转储 */ + + acl_msg_error("%s(%d): dump to stream(%s) error(%s)", + myname, __LINE__, ACL_VSTREAM_PATH(http_util->dump_stream), + acl_last_serror()); + if ((http_util->flag & HTTP_UTIL_FLAG_SET_DUMP_FILE)) { + if (http_util->dump_stream) + acl_vstream_close(http_util->dump_stream); + http_util->flag &= ~HTTP_UTIL_FLAG_SET_DUMP_FILE; + } else + http_util->flag &= ~HTTP_UTIL_FLAG_SET_DUMP_STREAM; + + http_util->dump_stream = NULL; + } + + return (ret); +} + +int http_util_dump_url(const char *url, const char *dump) +{ + const char *myname = "http_util_dump_url"; + HTTP_UTIL *http_util = http_util_req_new(url, "GET"); + char buf[4096]; + int ret; + + if (http_util == NULL) + return (-1); + if (dump == NULL || *dump == 0) { + acl_msg_error("%s(%d): dump invalid", myname, __LINE__); + return (-1); + } + + if (http_util_set_dump_file(http_util, dump) < 0) { + acl_msg_error("%s(%d): open dump file(%s) error(%s)", + myname, __LINE__, dump, acl_last_serror()); + http_util_free(http_util); + return (-1); + } + + if (http_util_req_open(http_util) < 0) { + acl_msg_error("%s(%d): open url(%s) error(%s)", + myname, __LINE__, url, acl_last_serror()); + http_util_free(http_util); + return (-1); + } + + if (http_util_get_res_hdr(http_util) < 0) { + acl_msg_error("%s(%d): url(%s)'s respond error", + myname, __LINE__, url); + http_util_free(http_util); + return (-1); + } + + while (1) { + if (http_util_get_res_body(http_util, buf, sizeof(buf)) <= 0) + break; + } + + ret = http_util->res_body_dlen; + http_util_free(http_util); + return (ret); +} + +int http_util_dump_url_to_stream(const char *url, ACL_VSTREAM *stream) +{ + const char *myname = "http_util_dump_url_to_stream"; + HTTP_UTIL *http_util = http_util_req_new(url, "GET"); + char buf[4096]; + int ret; + + if (http_util == NULL) + return (-1); + if (stream == NULL) { + acl_msg_error("%s(%d): dump invalid", myname, __LINE__); + return (-1); + } + + http_util_set_dump_stream(http_util, stream); + + if (http_util_req_open(http_util) < 0) { + acl_msg_error("%s(%d): open url(%s) error(%s)", + myname, __LINE__, url, acl_last_serror()); + http_util_free(http_util); + return (-1); + } + + if (http_util_get_res_hdr(http_util) < 0) { + acl_msg_error("%s(%d): url(%s)'s respond error", + myname, __LINE__, url); + http_util_free(http_util); + return (-1); + } + + while (1) { + if (http_util_get_res_body(http_util, buf, sizeof(buf)) <= 0) + break; + } + + ret = http_util->res_body_dlen; + http_util_free(http_util); + return (ret); +} diff --git a/lib_protocol/src/icmp/icmp_chat.c b/lib_protocol/src/icmp/icmp_chat.c new file mode 100644 index 000000000..0a595eb45 --- /dev/null +++ b/lib_protocol/src/icmp/icmp_chat.c @@ -0,0 +1,74 @@ +#include "StdAfx.h" +#include "icmp_struct.h" +#include "icmp_private.h" +#include "icmp/lib_icmp.h" + +#ifdef WIN32 +#include +#elif defined(ACL_UNIX) +#include +#endif + +ICMP_CHAT *icmp_chat_create(ACL_AIO* aio, int check_tid) +{ + ICMP_CHAT *chat; + + chat = (ICMP_CHAT*) acl_mycalloc(1, sizeof(ICMP_CHAT)); + chat->aio = aio; + acl_ring_init(&chat->host_head); + chat->is = icmp_stream_open(aio); + chat->seq_no = 0; + chat->count = 0; +#ifdef ACL_UNIX + chat->pid = getpid(); +#elif defined(ACL_MS_WINDOWS) + chat->pid = _getpid(); +#endif + chat->tid = (unsigned long) acl_pthread_self(); + chat->check_tid = check_tid; + + if (aio != NULL) + icmp_chat_aio_init(chat, aio); + else + icmp_chat_sio_init(chat); + + return (chat); +} + +void icmp_chat_free(ICMP_CHAT *chat) +{ + if (chat->aio) + icmp_chat_aio_free(chat); + else + icmp_chat_sio_free(chat); +} + +unsigned short icmp_chat_seqno(ICMP_CHAT *chat) +{ + return (chat->seq_no); +} + +void icmp_chat(ICMP_HOST *host) +{ + if (host->chat->aio) + icmp_chat_aio(host); + else + icmp_chat_sio(host); +} + +int icmp_chat_count(ICMP_CHAT *chat) +{ + return (chat->count); +} + +int icmp_chat_size(ICMP_CHAT *chat) +{ + return (acl_ring_size(&chat->host_head)); +} + +int icmp_chat_finish(ICMP_CHAT *chat) +{ + if (chat->count == acl_ring_size(&chat->host_head)) + return (1); + return (0); +} diff --git a/lib_protocol/src/icmp/icmp_chat_aio.c b/lib_protocol/src/icmp/icmp_chat_aio.c new file mode 100644 index 000000000..e6790cd1a --- /dev/null +++ b/lib_protocol/src/icmp/icmp_chat_aio.c @@ -0,0 +1,242 @@ +#include "StdAfx.h" +#include "icmp/lib_icmp.h" +#include "icmp_struct.h" +#include "icmp_private.h" + +static void delay_send_pkt(ICMP_PKT*, int); +static int read_close_fn(ACL_ASTREAM*, void*); +static int read_ready_fn(ACL_ASTREAM*, void *, const char*, int); + +static void check_timer(int event_type acl_unused, void *context) +{ + const char *myname = "check_timer"; + ICMP_CHAT *chat = (ICMP_CHAT*) context; + ICMP_PKT *pkt, *pkt_next; + + if (chat == NULL) + acl_msg_fatal("%s(%d): chat null", myname, __LINE__); + + while (1) { + pkt = (ICMP_PKT*) chat->timer->popup(chat->timer); + if (pkt == NULL) + break; + /* 汇报请求包超时 */ + icmp_stat_timeout(pkt); + + /* 获得发往该主机的下一个数据包 */ + pkt_next = ICMP_PKT_NEXT(&pkt->icmp_host->pkt_head, &pkt->pkt_ring); + /* 定时发送下一个请求数据包 */ + if (pkt_next != NULL) + delay_send_pkt(pkt_next, 0); + else { + /* 如果对该主机的包发送完毕,则回调状态汇报函数 */ + if (pkt->icmp_host->stat_finish) + pkt->icmp_host->stat_finish(pkt->icmp_host, pkt->icmp_host->arg); + /* 已完成主机检测数加1 */ + chat->count++; + } + } + + /* 启动下一次定时器 */ + acl_aio_request_timer(chat->aio, check_timer, chat, chat->check_inter, 0); +} + +static void send_pkt(ICMP_PKT *pkt) +{ + ICMP_CHAT *chat = pkt->pkt_chat; + ACL_ASTREAM *astream = chat->is->astream; + ACL_VSTREAM *vstream = acl_aio_vstream(astream); + int ret; + + /* 组建发送数据包 */ + icmp_pkt_build(pkt, chat->seq_no++); + + /* 指定当前包的目的主机地址,间接传递给 acl_vstream_writen 中的回调函数 */ + chat->is->curr_host = pkt->icmp_host; + /* 采用同步发送的模式 */ + ret = acl_vstream_writen(vstream, (const char*) pkt, (int) pkt->write_len); + pkt->icmp_host->nsent++; + + if (ret == ACL_VSTREAM_EOF) { + ICMP_PKT *pkt_next; + + /* 汇报主机不可达信息 */ + icmp_stat_unreach(pkt); + + pkt_next = ICMP_PKT_NEXT(&pkt->icmp_host->pkt_head, &pkt->pkt_ring); + if (pkt_next != NULL) { + /* 延迟发送下一个数据包 */ + delay_send_pkt(pkt_next, pkt_next->icmp_host->delay); + } else { + /* 因一个 ICMP_HOST 对象的 ICMP 包已发完, 所以将 count 值加 1 */ + chat->count++; + + /* 汇报该 ICMP_HOST 对象的 ICMP 包可达状态 */ + if (pkt->icmp_host->stat_finish) + pkt->icmp_host->stat_finish(pkt->icmp_host, pkt->icmp_host->arg); + } + } else { + /* 将该包置入超时队列中 */ + chat->timer->request(chat->timer, pkt, pkt->icmp_host->timeout); + } +} + +void icmp_chat_aio(ICMP_HOST* host) +{ + const char *myname = "icmp_chat_aio"; + ICMP_PKT *pkt; + + pkt = ICMP_PKT_NEXT(&host->pkt_head, &host->pkt_head); + if (pkt == NULL) + acl_msg_fatal("%s(%d): first icmp pkt null", myname, __LINE__); + + /* 发送的第一个请求包不需要启动写定时器 */ + send_pkt(pkt); +} + +/* 某个包的发送定时器到达的回调函数 */ +static void delay_send_timer(int event_type acl_unused, void *context) +{ + ICMP_PKT *pkt = (ICMP_PKT*) context; + + /* 发送该 ICMP 包 */ + send_pkt(pkt); +} + +static void delay_send_pkt(ICMP_PKT *pkt, int delay) +{ + const char *myname = "delay_send_pkt"; + + if (pkt == NULL) + acl_msg_fatal("%s(%d): pkt null", myname, __LINE__); + + /* 启动写定时器,因为传入的 delay 是秒级,而 acl_aio_request_timer + * 的时间单位是微秒, 所以需要将 dely 由秒转为微秒 + */ + acl_aio_request_timer(pkt->pkt_chat->aio, delay_send_timer, pkt, delay * 1000000, 0); +} + +static int read_close_fn(ACL_ASTREAM *astream acl_unused, void *arg) +{ + const char *myname = "read_close_fn"; + ICMP_CHAT *chat = (ICMP_CHAT*) arg; + + /* 当该函数被调用时,就已经表明该套接字有问题,所以需要重启一个流 */ + + acl_msg_warn("%s(%d): sock read error", myname, __LINE__); + icmp_stream_reopen(chat->aio, chat->is); + + /* 重新启动异步读过程,注:此时chat->is->astream 已经不同于 + * 该函数的参数 astream 了! + */ + acl_aio_read(chat->is->astream); + + /* 返回-1,使本异步流被自动关闭 */ + return (-1); +} + +static int read_ready_fn(ACL_ASTREAM *astream, void *arg, const char *data, int dlen) +{ + const char *myname = "read_ready_fn"; + ICMP_CHAT *chat = (ICMP_CHAT*) arg; + ICMP_PKT *pkt_next, *pkt_src, pkt; + +#define READ_RETURN(_x_) do { \ + acl_aio_read(astream); \ + return(_x_); \ +} while (0) + + if (chat == NULL) + acl_msg_fatal("%s(%d): chat null", __FILE__, __LINE__); + + if (icmp_pkt_unpack(chat, data, dlen, &pkt) < 0) { + READ_RETURN(0); + } + + /* 读到所需数据,取消该发送包的读超时定时器 */ + pkt_src = chat->timer->find_delete(chat->timer, pkt.hdr.seq); + + if (pkt_src == NULL) { + acl_msg_warn("%s(%d): seq(%d) not found", + myname, __LINE__, pkt.hdr.seq); + READ_RETURN(0); + } + + icmp_pkt_save(pkt_src, &pkt); + + /* 汇报状态 */ + icmp_stat_report(pkt_src); + + pkt_next = ICMP_PKT_NEXT(&pkt_src->icmp_host->pkt_head, &pkt_src->pkt_ring); + if (pkt_next == NULL) { + if (pkt_src->icmp_host->stat_finish) + pkt_src->icmp_host->stat_finish(pkt_src->icmp_host, pkt_src->icmp_host->arg); + chat->count++; + READ_RETURN(0); + } + + /* 定时发送下一个请求数据包 */ + delay_send_pkt(pkt_next, pkt_next->icmp_host->delay); + READ_RETURN(0); +} + +static int timeout_fn(ACL_ASTREAM *astream acl_unused, void *arg acl_unused) +{ + const char *myname = "timeout_fn"; + + acl_msg_fatal("%s(%d): be called", myname, __LINE__); + + /* not reached */ + return (-1); +} + +static int write_ready_fn(ACL_ASTREAM *astream acl_unused, void *arg acl_unused) +{ + const char *myname = "write_ready_fn"; + + acl_msg_fatal("%s(%d): be called", myname, __LINE__); + return (-1); +} + +void icmp_chat_aio_init(ICMP_CHAT *chat, ACL_AIO *aio) +{ + acl_aio_set_delay_sec(aio, 0); + acl_aio_set_delay_usec(aio, 50); + + acl_aio_ctl(chat->is->astream, + ACL_AIO_CTL_READ_HOOK_ADD, read_ready_fn, chat, + ACL_AIO_CTL_WRITE_HOOK_ADD, write_ready_fn, chat, + ACL_AIO_CTL_CLOSE_HOOK_ADD, read_close_fn, chat, + ACL_AIO_CTL_TIMEO_HOOK_ADD, timeout_fn, chat, + ACL_AIO_CTL_TIMEOUT, 0, /* 初始化时先设置读超时为 0 */ + ACL_AIO_CTL_END); + + chat->timer = icmp_timer_new(); + + chat->check_inter = 2000000; /* one second check timer */ + acl_aio_request_timer(aio, check_timer, chat, chat->check_inter, 0); + /* 开始异步读该包的响应数据 */ + acl_aio_read(chat->is->astream); +} + +static void icmp_rset(ICMP_CHAT *chat) +{ + ACL_RING *ring_ptr; + ICMP_HOST *host; + + while ((ring_ptr = acl_ring_pop_head(&chat->host_head)) != NULL) { + host = RING_TO_HOST(ring_ptr); + icmp_host_free(host); + } + + chat->count = 0; + acl_ring_init(&chat->host_head); +} + +void icmp_chat_aio_free(ICMP_CHAT *chat) +{ + icmp_rset(chat); + icmp_timer_free(chat->timer); + icmp_stream_close(chat->is); + acl_myfree(chat); +} diff --git a/lib_protocol/src/icmp/icmp_chat_sio.c b/lib_protocol/src/icmp/icmp_chat_sio.c new file mode 100644 index 000000000..1a1503326 --- /dev/null +++ b/lib_protocol/src/icmp/icmp_chat_sio.c @@ -0,0 +1,82 @@ +#include "StdAfx.h" +#include "icmp_struct.h" +#include "icmp_private.h" + +static void read_pkt(ACL_VSTREAM *stream, ICMP_PKT *pkt_src) +{ + ICMP_PKT pkt; + char buf[2048]; + int ret; + + while (1) { + if (acl_read_wait(ACL_VSTREAM_SOCK(stream), pkt_src->icmp_host->timeout) < 0) { + /* 汇报请求包超时 */ + icmp_stat_timeout(pkt_src); + return; + } + + ret = acl_vstream_read(stream, buf, sizeof(buf)); + if (ret == ACL_VSTREAM_EOF) { + char tbuf[256]; + acl_msg_error("read error(%s)", acl_last_strerror(tbuf, sizeof(tbuf))); + continue; + } + + if (icmp_pkt_unpack(pkt_src->pkt_chat, buf, ret, &pkt) < 0) + continue; + + icmp_pkt_save(pkt_src, &pkt); + icmp_stat_report(pkt_src); + break; + } +} + +static void send_pkt(ACL_VSTREAM *stream, ICMP_PKT *pkt) +{ + int ret; + + /* 指定当前包的目的主机地址,间接传递给 acl_vstream_writen 中的回调函数 */ + pkt->pkt_chat->is->curr_host = pkt->icmp_host; + + /* 组建发送数据包 */ + icmp_pkt_build(pkt, pkt->pkt_chat->seq_no++); + + /* 采用同步发送的模式 */ + ret = acl_vstream_writen(stream, (const char*) pkt, (int) pkt->write_len); + pkt->icmp_host->nsent++; + + if (ret == ACL_VSTREAM_EOF) { + /* 汇报主机不可达信息 */ + icmp_stat_unreach(pkt); + } +} + +void icmp_chat_sio(ICMP_HOST* host) +{ + ICMP_PKT *pkt; + ACL_VSTREAM *stream; + + pkt = ICMP_PKT_NEXT(&host->pkt_head, &host->pkt_head); + stream = host->chat->is->vstream; + + while (pkt != NULL) { + send_pkt(stream, pkt); + read_pkt(stream, pkt); + sleep(host->delay); + pkt = ICMP_PKT_NEXT(&host->pkt_head, &pkt->pkt_ring); + } + + host->chat->count++; + if (host->stat_finish) + host->stat_finish(host, host->arg); +} + +void icmp_chat_sio_init(ICMP_CHAT *chat acl_unused) +{ +} + +void icmp_chat_sio_free(ICMP_CHAT *chat) +{ + icmp_stream_close(chat->is); + acl_myfree(chat); +} diff --git a/lib_protocol/src/icmp/icmp_host.c b/lib_protocol/src/icmp/icmp_host.c new file mode 100644 index 000000000..c328680f6 --- /dev/null +++ b/lib_protocol/src/icmp/icmp_host.c @@ -0,0 +1,79 @@ +#include "StdAfx.h" +#include "icmp_struct.h" +#include "icmp_private.h" +#include "icmp/lib_icmp.h" + +void icmp_host_free(ICMP_HOST *host) +{ + ICMP_PKT *pkt; + ACL_RING *ring_ptr; + + while ((ring_ptr = acl_ring_pop_head(&host->pkt_head)) != NULL) { + pkt = RING_TO_PKT(ring_ptr); + imcp_pkt_free(pkt); + } + + acl_myfree(host); +} + +ICMP_HOST* icmp_host_new(ICMP_CHAT *chat, const char *domain, const char *ip, + size_t npkt, size_t dlen, int delay, int timeout) +{ + const char* myname = "icmp_host_new"; + ICMP_HOST *host; + ICMP_PKT *pkt; + size_t i; + char *ptr; + + if (ip == NULL || *ip == 0) + acl_msg_fatal("%s(%d): ip invalid", myname, __LINE__); + + if (npkt == 0) + npkt = 5; + else if (npkt > 10240) + npkt = 10240; + + /* 分配内存块 */ + + host = (ICMP_HOST*) acl_mycalloc(1, sizeof(ICMP_HOST)); + + if (domain && *domain) + ACL_SAFE_STRNCPY(host->domain, domain, sizeof(host->domain)); + ACL_SAFE_STRNCPY(host->dest_ip, ip, sizeof(host->dest_ip)); + ptr = strchr(host->dest_ip, ':'); + if (ptr) + *ptr = 0; /* 去掉端口字段 */ + + host->dest.sin_family = AF_INET; + host->dest.sin_addr.s_addr = inet_addr(host->dest_ip); + /* host->dest.sin_port = htons(53); */ + host->chat = chat; + host->timeout = timeout; + host->delay = delay; + host->dlen = dlen; + host->npkt = npkt; + host->nsent = 0; + + acl_ring_init(&host->pkt_head); + for (i = 0; i < npkt; i++) { + pkt = imcp_pkt_pack(dlen, host); + acl_ring_prepend(&host->pkt_head, &pkt->pkt_ring); + } + + acl_ring_prepend(&chat->host_head, &host->host_ring); + return (host); +} + +void icmp_host_set(ICMP_HOST *host, void *arg, + void (*stat_respond)(ICMP_PKT_STATUS*, void*), + void (*stat_timeout)(ICMP_PKT_STATUS*, void*), + void (*stat_unreach)(ICMP_PKT_STATUS*, void*), + void (*stat_finish)(ICMP_HOST*, void*)) +{ + host->arg = arg; + host->stat_respond = stat_respond; + host->stat_unreach = stat_unreach; + host->stat_timeout = stat_timeout; + host->stat_finish = stat_finish; +} + diff --git a/lib_protocol/src/icmp/icmp_ping.c b/lib_protocol/src/icmp/icmp_ping.c new file mode 100644 index 000000000..9d9536774 --- /dev/null +++ b/lib_protocol/src/icmp/icmp_ping.c @@ -0,0 +1,16 @@ +#include "StdAfx.h" +#include +#include "icmp_struct.h" +#include "icmp_private.h" +#include "icmp/lib_icmp.h" + +void icmp_ping_one(ICMP_CHAT *chat, const char *domain, const char *ip, + size_t npkt, int delay, int timeout) +{ + ICMP_HOST *host; + + acl_assert(chat); + host = icmp_host_new(chat, domain, ip, npkt, 64, delay, timeout); + host->enable_log = 1; + icmp_chat(host); +} diff --git a/lib_protocol/src/icmp/icmp_pkt.c b/lib_protocol/src/icmp/icmp_pkt.c new file mode 100644 index 000000000..de3d31527 --- /dev/null +++ b/lib_protocol/src/icmp/icmp_pkt.c @@ -0,0 +1,150 @@ +#include "StdAfx.h" +#include +#include "icmp_struct.h" +#include "icmp_private.h" +#include "icmp/lib_icmp.h" + +static double stamp_sub(const struct timeval *from, const struct timeval *sub_by) +{ + struct timeval res; + + memcpy(&res, from, sizeof(struct timeval)); + + res.tv_usec -= sub_by->tv_usec; + if (res.tv_usec < 0) { + --res.tv_sec; + res.tv_usec += 1000000; + } + res.tv_sec -= sub_by->tv_sec; + + return (res.tv_sec * 1000.0 + res.tv_usec/1000.0); +} + +static unsigned short checksum(unsigned short *buffer, size_t size) +{ + unsigned long cksum = 0; + + while (size > 1) { + cksum += *buffer++; + size -= sizeof(unsigned short); + } + + if (size) + cksum += *(unsigned char *) buffer; + + cksum = (cksum >> 16) + (cksum & 0xffff); + cksum += (cksum >> 16); + return (unsigned short) (~cksum); +} + +static void icmp_hdr_pack(char *icmp_data, unsigned short id) +{ + struct ICMP_HDR *icmp_hdr; + + icmp_hdr = (struct ICMP_HDR *) icmp_data; + + icmp_hdr->type = ICMP_ECHO; + icmp_hdr->code = 0; + icmp_hdr->id = id; + icmp_hdr->cksum = 0; + icmp_hdr->seq = 0; +} + +ICMP_PKT *imcp_pkt_pack(size_t dlen, ICMP_HOST *host) +{ + ICMP_PKT *pkt; + + if (dlen > MAX_PACKET) + dlen = MAX_PACKET; + if (dlen < MIN_PACKET) + dlen = MIN_PACKET; + + pkt = (ICMP_PKT*) acl_mycalloc(1, sizeof(ICMP_PKT)); + pkt->dlen = dlen; + + icmp_hdr_pack((char*) pkt, host->chat->pid); + /* icmp body data */ + memset(pkt->body.data, 'E', dlen - sizeof(struct ICMP_HDR)); + pkt->body.tid = host->chat->tid; + + pkt->pkt_status.status = ICMP_STATUS_UNREACH; + pkt->pkt_status.rtt = 65535; /* large enough ? */ + + pkt->icmp_host = host; + pkt->write_len = dlen + sizeof(struct ICMP_HDR); + pkt->read_len = dlen + sizeof(struct ICMP_HDR) + sizeof(struct IP_HDR) - 4; + return (pkt); +} + +void icmp_pkt_build(ICMP_PKT *pkt, unsigned short seq_no) +{ + pkt->hdr.seq = seq_no; + pkt->pkt_status.seq = pkt->hdr.seq; + + gettimeofday(&pkt->stamp, NULL); + pkt->hdr.cksum = checksum((unsigned short *) pkt, + pkt->dlen + sizeof(struct ICMP_HDR)); +} + +void imcp_pkt_free(ICMP_PKT *ipkt) +{ + acl_myfree(ipkt); +} + +void icmp_pkt_save(ICMP_PKT* to, const ICMP_PKT* from) +{ + to->pkt_status.reply_len = from->pkt_status.reply_len; + to->pkt_status.rtt = stamp_sub(&from->stamp, &to->stamp); + to->pkt_status.ttl = from->pkt_status.ttl; + snprintf(to->pkt_status.frome_ip, sizeof(to->pkt_status.frome_ip), + "%s", from->pkt_status.frome_ip); + + to->pkt_status.status = ICMP_STATUS_OK; +} + +int icmp_pkt_unpack(const ICMP_CHAT *chat, const char *buf, int bytes, ICMP_PKT *pkt) +{ + const IP_HDR *iphdr; + const ICMP_HDR *icmphdr; + const ICMP_PKT *icmppkt; + unsigned short iphdrlen; + + iphdr = (const IP_HDR *) buf; + iphdrlen = iphdr->h_len * 4 ; /* number of 32-bit words *4 = bytes */ + + if (bytes < iphdrlen + ICMP_MIN) { + acl_msg_error("Too few bytes from %s", + inet_ntoa(chat->is->from.sin_addr)); + return (-1); + } + + icmppkt = (const ICMP_PKT *) (buf + iphdrlen); + icmphdr = &icmppkt->hdr; + + if (icmphdr->type != ICMP_ECHOREPLY) { + return (-1); + } + + if (icmphdr->id != chat->pid) { + return (-1); + } + + pkt->pkt_status.reply_len = bytes - (iphdrlen + sizeof(struct ICMP_HDR)); + if (pkt->pkt_status.reply_len < MIN_PACKET) { + return (-1); + } + + pkt->body.tid = icmppkt->body.tid; + if (chat->check_tid && pkt->body.tid != chat->tid) + return (-1); + + pkt->hdr.seq = icmphdr->seq; + gettimeofday(&pkt->stamp, NULL); + + pkt->pkt_status.status = ICMP_STATUS_OK; + pkt->pkt_status.seq = icmphdr->seq; + pkt->pkt_status.ttl = iphdr->ttl; + snprintf(pkt->pkt_status.frome_ip, sizeof(pkt->pkt_status.frome_ip), + "%s", inet_ntoa(chat->is->from.sin_addr)); + return (0); +} diff --git a/lib_protocol/src/icmp/icmp_private.h b/lib_protocol/src/icmp/icmp_private.h new file mode 100644 index 000000000..a15e452b7 --- /dev/null +++ b/lib_protocol/src/icmp/icmp_private.h @@ -0,0 +1,39 @@ +#ifndef __ICMP_PRIVATE_INCLUDE_H__ +#define __ICMP_PRIVATE_INCLUDE_H__ + +#include "lib_acl.h" +#include "icmp/lib_icmp_type.h" + +/* in icmp_stream.c */ +void icmp_stream_close(ICMP_STREAM* is); +ICMP_STREAM* icmp_stream_open(ACL_AIO *aio); +void icmp_stream_reopen(ACL_AIO *aio, ICMP_STREAM *is); + +/* in icmp_chat_aio.c */ +void icmp_chat_aio_init(ICMP_CHAT *chat, ACL_AIO *aio); +void icmp_chat_aio_free(ICMP_CHAT *chat); +void icmp_chat_aio(ICMP_HOST* host); + +/* in icmp_chat_sio.c */ +void icmp_chat_sio_init(ICMP_CHAT *chat); +void icmp_chat_sio_free(ICMP_CHAT *chat); +void icmp_chat_sio(ICMP_HOST* host); + +/* in icmp_pkt.c */ +ICMP_PKT *imcp_pkt_pack(size_t dlen, ICMP_HOST *host); +void icmp_pkt_build(ICMP_PKT *pkt, unsigned short seq_no); +void imcp_pkt_free(ICMP_PKT *ipkt); +void icmp_pkt_save(ICMP_PKT* to, const ICMP_PKT* from); +int icmp_pkt_unpack(const ICMP_CHAT *chat, const char *buf, int bytes, ICMP_PKT *pkt); + +/* in icmp_stat.c */ +void icmp_stat_timeout(ICMP_PKT *pkt); +void icmp_stat_unreach(ICMP_PKT *pkt); +void icmp_stat_report(ICMP_PKT *pkt); +void icmp_stat_finish(ICMP_HOST *host); + +/* in icmp_timer.c */ +ICMP_TIMER *icmp_timer_new(void); +void icmp_timer_free(ICMP_TIMER* timer); + +#endif diff --git a/lib_protocol/src/icmp/icmp_stat.c b/lib_protocol/src/icmp/icmp_stat.c new file mode 100644 index 000000000..8e4c4903e --- /dev/null +++ b/lib_protocol/src/icmp/icmp_stat.c @@ -0,0 +1,103 @@ +#include "StdAfx.h" +#include "icmp_struct.h" +#include "icmp_private.h" +#include "icmp/lib_icmp.h" + +void icmp_stat_timeout(ICMP_PKT *pkt) +{ + pkt->pkt_status.status = ICMP_STATUS_TIMEOUT; + if (pkt->icmp_host->enable_log) + acl_msg_info("%s Ping timeout, icmp_seq %d", + pkt->icmp_host->dest_ip, pkt->hdr.seq); + if (pkt->icmp_host->stat_timeout != NULL) + pkt->icmp_host->stat_timeout(&pkt->pkt_status, pkt->icmp_host->arg); +} + +void icmp_stat_unreach(ICMP_PKT *pkt) +{ + pkt->pkt_status.status = ICMP_STATUS_UNREACH; + if (pkt->icmp_host->enable_log) + acl_msg_info("%s Destination host unreachable.", pkt->icmp_host->dest_ip); + if (pkt->icmp_host->stat_unreach != NULL) + pkt->icmp_host->stat_unreach(&pkt->pkt_status, pkt->icmp_host->arg); +} + +void icmp_stat_report(ICMP_PKT *pkt) +{ + pkt->pkt_status.status = ICMP_STATUS_OK; + if (pkt->icmp_host->enable_log) + acl_msg_info("Reply from %s: bytes=%d time=%.3fms TTL=%d icmp_seq=%d status=%d", + pkt->pkt_status.frome_ip, (int) pkt->pkt_status.reply_len, + pkt->pkt_status.rtt, pkt->pkt_status.ttl, + pkt->pkt_status.seq, pkt->pkt_status.status); + + if (pkt->icmp_host->stat_respond != NULL) + pkt->icmp_host->stat_respond(&pkt->pkt_status, pkt->icmp_host->arg); +} + +static void icmp_status(ICMP_HOST *host, int flag) +{ + int nok = 0; + double Minimun = 65535, Maximum = 0, Total = 0; + ICMP_PKT *pkt; + + pkt = ICMP_PKT_NEXT(&host->pkt_head, &host->pkt_head); + while (pkt) { + if (pkt->pkt_status.status == ICMP_STATUS_OK) { + nok++; + if (pkt->pkt_status.rtt < Minimun) + Minimun = pkt->pkt_status.rtt; + if (pkt->pkt_status.rtt > Maximum) + Maximum = pkt->pkt_status.rtt; + Total += pkt->pkt_status.rtt; + } + pkt = ICMP_PKT_NEXT(&host->pkt_head, &pkt->pkt_ring); + } + + host->icmp_stat.nsent = host->nsent; + host->icmp_stat.nreceived = nok; + host->icmp_stat.loss = host->nsent > 0 ? + (host->nsent - nok) * 100/host->nsent : 0; + host->icmp_stat.tmax = Maximum; + host->icmp_stat.tmin = Minimun; + host->icmp_stat.tsum = Total; + host->icmp_stat.tave = nok > 0 ? host->icmp_stat.tsum/nok : 0; + + if (flag) { + acl_msg_info("Ping statistics for %s: %s", + host->dest_ip, host->domain[0] != 0 ? host->domain : ""); + acl_msg_info("\tPackets: Sent = %d, Received = %d, Lost = %d (%.2f%% loss),", + (int) host->icmp_stat.nsent, (int) host->icmp_stat.nreceived, + (int) (host->icmp_stat.nsent - host->icmp_stat.nreceived), + host->icmp_stat.loss); + + if (nok > 0) { + acl_msg_info("Approximate round trip times in milli-seconds:"); + acl_msg_info("\tMinimum = %.3f ms, Maximum = %.3f ms, Average = %.3f ms", + host->icmp_stat.tmin, host->icmp_stat.tmax, host->icmp_stat.tave); + } + } +} + +void icmp_stat_host(ICMP_HOST *host, int show_flag) +{ + icmp_status(host, show_flag); +} + +void icmp_stat_finish(ICMP_HOST *host) +{ + icmp_status(host, 0); +} + +void icmp_stat(ICMP_CHAT *chat) +{ + ICMP_HOST *host; + + acl_msg_info("\r\n>>>hosts' size=%d", acl_ring_size(&chat->host_head)); + + host = ICMP_HOST_NEXT(&chat->host_head, &chat->host_head); + while (host) { + icmp_stat_host(host, 1); + host = ICMP_HOST_NEXT(&chat->host_head, &host->host_ring); + } +} diff --git a/lib_protocol/src/icmp/icmp_stream.c b/lib_protocol/src/icmp/icmp_stream.c new file mode 100644 index 000000000..34ee556ff --- /dev/null +++ b/lib_protocol/src/icmp/icmp_stream.c @@ -0,0 +1,97 @@ +#include "StdAfx.h" +#include "icmp_struct.h" +#include "icmp_private.h" + +static int icmp_read(ACL_SOCKET fd, void *buf, size_t size, int timeout acl_unused, void *arg) +{ + ICMP_STREAM *is = (ICMP_STREAM*) arg; + int ret; + +#ifdef ACL_UNIX + ret = recvfrom(fd, buf, size, 0, (struct sockaddr*) &is->from, + (socklen_t*) &is->from_len); +#elif defined(WIN32) + ret = recvfrom(fd, (char*) buf, (int) size, 0, (struct sockaddr*) &is->from, + &is->from_len); +#else +#error "unknown OS" +#endif + if (ret < 0) { + char tbuf[256]; + printf("%s(%d): recvfrom error(%s)\r\n", + __FILE__, __LINE__, acl_last_strerror(tbuf, sizeof(tbuf))); + } + return (ret); +} + +static int icmp_write(ACL_SOCKET fd, const void *buf, size_t size, int timeout acl_unused, void *arg) +{ + ICMP_STREAM *is = (ICMP_STREAM*) arg; + int ret; + +#ifdef ACL_UNIX + ret = sendto(fd, buf, size, 0, + (struct sockaddr*) &is->curr_host->dest, + sizeof(is->curr_host->dest)); +#elif defined(WIN32) + ret = sendto(fd, (const char*) buf, (int) size, 0, + (struct sockaddr*) &is->curr_host->dest, + sizeof(is->curr_host->dest)); +#else +#error "unknown OS" +#endif + return (ret); +} + +void icmp_stream_close(ICMP_STREAM* is) +{ + if (is->astream) + acl_aio_iocp_close(is->astream); + else if (is->vstream) + acl_vstream_close(is->vstream); + acl_myfree(is); +} + +ICMP_STREAM* icmp_stream_open(ACL_AIO *aio) +{ + const char* myname = "icmp_stream_open"; + ACL_SOCKET fd; + ICMP_STREAM *is = (ICMP_STREAM*) acl_mycalloc(1, sizeof(ICMP_STREAM)); + + is->from_len = sizeof(is->from); + + /* 创建通信流 */ + + fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); + if (fd == ACL_SOCKET_INVALID) + acl_msg_fatal("%s(%d): socket create error", myname, __LINE__); + + is->vstream = acl_vstream_fdopen(fd, O_RDWR, 1024, 0, ACL_VSTREAM_TYPE_SOCK); + acl_vstream_ctl(is->vstream, + ACL_VSTREAM_CTL_READ_FN, icmp_read, + ACL_VSTREAM_CTL_WRITE_FN, icmp_write, + ACL_VSTREAM_CTL_CONTEXT, is, + ACL_VSTREAM_CTL_END); + + /* 如果采用异步方式,则打开异步流 */ + if (aio) + is->astream = acl_aio_open(aio, is->vstream); + + return (is); +} + +void icmp_stream_reopen(ACL_AIO *aio, ICMP_STREAM *is) +{ + ACL_SOCKET fd = ACL_VSTREAM_SOCK(is->vstream); + ACL_VSTREAM_SOCK(is->vstream) = ACL_SOCKET_INVALID; /* 防止原SOCKET被关闭:) */ + + is->vstream = acl_vstream_fdopen(fd, O_RDWR, 1024, 0, ACL_VSTREAM_TYPE_SOCK); + acl_vstream_ctl(is->vstream, + ACL_VSTREAM_CTL_READ_FN, icmp_read, + ACL_VSTREAM_CTL_WRITE_FN, icmp_write, + ACL_VSTREAM_CTL_CONTEXT, is, + ACL_VSTREAM_CTL_END); + + if (aio) + is->astream = acl_aio_open(aio, is->vstream); +} diff --git a/lib_protocol/src/icmp/icmp_struct.h b/lib_protocol/src/icmp/icmp_struct.h new file mode 100644 index 000000000..cf9715685 --- /dev/null +++ b/lib_protocol/src/icmp/icmp_struct.h @@ -0,0 +1,136 @@ +#ifndef __ICMP_INCLUDE_H__ +#define __ICMP_INCLUDE_H__ + +#include "lib_acl.h" +#include +#include "icmp/lib_icmp_type.h" + +typedef struct ICMP_TIMER ICMP_TIMER; +typedef struct ICMP_STREAM ICMP_STREAM; +typedef struct IP_HDR IP_HDR; +typedef struct ICMP_HDR ICMP_HDR; + +/* in icmp_timer.cpp */ +/**< 定时器信息结构 */ +struct ICMP_TIMER { + /**< 设置定时任务 */ + time_t (*request)(ICMP_TIMER* timer, ICMP_PKT* pkt, int delay); + /**< 取消定时任务 */ + time_t (*cancel)(ICMP_TIMER* timer, ICMP_PKT* pkt); + /**< 查找并删除定时任务 */ + ICMP_PKT* (*find_delete)(ICMP_TIMER* timer, unsigned short i_seq); + /**< 弹出下一个定时任务 */ + ICMP_PKT* (*popup)(ICMP_TIMER* timer); + + ACL_RING timer_header; /**< 定时任务的链表头 */ + time_t present; /**< 当前时间 */ + time_t time_left; /**< 距下一个定时任务的时间 */ +}; + +/**< 发送与接收 ICMP 包的通信流 */ +struct ICMP_STREAM { + ACL_VSTREAM *vstream; /**< 同步流指针 */ + ACL_ASTREAM *astream; /**< 异步流指针 */ + + struct sockaddr_in from; /**< 接收数据的源地址 */ + int from_len; /**< 存储在 from 中的地址大小 */ + + ICMP_HOST *curr_host; /**< 当前的目的主机对象 */ +}; + +/**< ICMP 通信句柄 */ +struct ICMP_CHAT { + /* 通用的成员变量 */ + unsigned short seq_no; /**< 每个 icmp 包的序列号 */ + ICMP_STREAM *is; /**< 与某个客户机相关的流 */ + ACL_RING host_head; /**< 当前 ICMP 通信对象中的主机组成的链 */ + unsigned short pid; /**< 由当前进程ID表示 */ + unsigned int tid; /**< 由线程ID表示 */ + int check_tid; /**< 是否检查响应包中的 tid 值 */ + + /* 异步IO的成员变量 */ + ACL_AIO *aio; /**< 异步IO句柄 */ + int count; /**< 当前 ICMP 通信对象中已经完成的主机数 */ + int check_inter; /**< 每隔多少秒检查一下定时器里的任务 */ + ICMP_TIMER *timer; /**< 包发完后等待包应答的定时器 */ +}; + +#define ICMP_ECHO 8 +#define ICMP_ECHOREPLY 0 + +#define ICMP_MIN 8 /**< Minimum 8 byte icmp packet (just header) */ + +/**< IP 协议头结构 */ +struct IP_HDR { +#if __BYTE_ORDER == __LITTLE_ENDIAN + unsigned int h_len:4; /**< length of the header */ + unsigned int version:4; /**< Version of IP */ +#elif __BYTE_ORDER == __BIG_ENDIAN + unsigned int version:4; /**< Version of IP */ + unsigned int h_len:4; /**< length of the header */ +#else +# error "unknown __BYTE_ORDER" +#endif + + unsigned char tos; /**< Type of service */ + unsigned short total_len; /**< total length of the packet */ + unsigned short ident; /**< unique identifier */ + unsigned short frag_and_flags; /**< flags */ + unsigned char ttl; /**< time to live */ + unsigned char proto; /**< protocol (TCP, UDP etc) */ + unsigned short checksum; /**< IP checksum */ + + unsigned int source_ip; /**< source IP*/ + unsigned int dest_ip; /**< dest IP */ +}; + +/**< ICMP header */ +struct ICMP_HDR { + unsigned char type; + unsigned char code; /* type sub code */ + unsigned short cksum; + unsigned short id; + unsigned short seq; +}; + +#define MIN_PACKET 32 +#define MAX_PACKET 1024 + +/**< ICMP 包数据结构 */ +struct ICMP_PKT { + /* 发送的数据包 */ + ICMP_HDR hdr; /**< icmp 头 */ + union { + unsigned int tid; /**< 线程ID号 */ + char data[MAX_PACKET]; /**< icmp 数据体 */ + } body; + + /* 本地存储的数据成员,主要为了解析方便 */ + ICMP_HOST *icmp_host; /**< 目的主机 */ +#define pkt_chat icmp_host->chat /**< ICMP_PKT 中指向 ICMP_CHAT 的快捷方式 */ + + ACL_RING pkt_ring; /**< 发送数据包的双向链 */ + ACL_RING timer_ring; /**< 定时器结点 */ + + size_t write_len; /**< 发送的数据长度 */ + size_t read_len; /**< 接收的数据长度 */ + + size_t dlen; /**< 数据包中数据体长度 */ + struct timeval stamp; /**< time stamp */ + + /* 响应的数据包的分析结果 */ + ICMP_PKT_STATUS pkt_status; +}; + +#define RING_TO_PKT(r) \ + ((ICMP_PKT *) ((char *) (r) - offsetof(ICMP_PKT, pkt_ring))) +#define ICMP_PKT_NEXT(head, curr) \ + (acl_ring_succ(curr) != (head) ? RING_TO_PKT(acl_ring_succ(curr)) : NULL) + +#define RING_TO_HOST(r) \ + ((ICMP_HOST *) ((char *) (r) - offsetof(ICMP_HOST, host_ring))) +#define ICMP_HOST_NEXT(head, curr) \ + (acl_ring_succ(curr) != (head) ? RING_TO_HOST(acl_ring_succ(curr)) : NULL) + +#endif + diff --git a/lib_protocol/src/icmp/icmp_timer.c b/lib_protocol/src/icmp/icmp_timer.c new file mode 100644 index 000000000..53d68e418 --- /dev/null +++ b/lib_protocol/src/icmp/icmp_timer.c @@ -0,0 +1,134 @@ +#include "StdAfx.h" +#include "icmp_struct.h" +#include "icmp_private.h" + +typedef struct TimerItem +{ + ICMP_PKT *pkt; + ACL_RING entry; /* 内部用的定时链 */ + time_t when; /* 被触发的时间截 */ +} TimerItem; + +#define RING_TO_TIMER(r) \ + ((TimerItem *) ((char *) (r) - offsetof(TimerItem, entry))) + +#define FIRST_TIMER(head) \ + (acl_ring_succ(head) != (head) ? RING_TO_TIMER(acl_ring_succ(head)) : 0) + +static time_t timer_request(ICMP_TIMER* timer, ICMP_PKT *pkt, int delay) +{ + ACL_RING_ITER iter; + TimerItem *pTimerItem = NULL; + + time(&timer->present); + + acl_ring_foreach(iter, &timer->timer_header) { + pTimerItem = RING_TO_TIMER(iter.ptr); + if (pTimerItem->pkt == pkt) { + pTimerItem->when = timer->present + delay; + acl_ring_detach(iter.ptr); + break; + } + } + + /* If not found, schedule a new timer request. */ + if (iter.ptr == &timer->timer_header) { + pTimerItem = (TimerItem*) acl_mycalloc(1, sizeof(TimerItem)); + pTimerItem->when = timer->present + delay; + pTimerItem->pkt = pkt; + } + + acl_ring_foreach(iter, &timer->timer_header) { + TimerItem *pItem = RING_TO_TIMER(iter.ptr); + if (pTimerItem->when < pItem->when) + break; + } + acl_ring_prepend(iter.ptr, &pTimerItem->entry); + + return (pTimerItem->when); +} + +static time_t timer_cancel(ICMP_TIMER* timer, ICMP_PKT *pkt) +{ + ACL_RING_ITER iter; + time_t time_left = -1; + + time(&timer->present); + + acl_ring_foreach(iter, &timer->timer_header) { + TimerItem *pItem = RING_TO_TIMER(iter.ptr); + if (pItem->pkt == pkt) { + if ((time_left = pItem->when - timer->present) < 0) + time_left = 0; + acl_ring_detach(iter.ptr); + acl_myfree(pItem); + break; + } + } + + timer->time_left = time_left; + return (time_left); +} + +static ICMP_PKT* timer_find_delete(ICMP_TIMER* timer, unsigned short seq) +{ + ACL_RING_ITER iter; + time_t time_left = -1; + ICMP_PKT* pkt = NULL; + + acl_ring_foreach(iter, &timer->timer_header) { + TimerItem *pItem = RING_TO_TIMER(iter.ptr); + if (pItem->pkt->hdr.seq == seq) { + pkt = pItem->pkt; + + if ((time_left = pItem->when - timer->present) < 0) + time_left = 0; + acl_ring_detach(iter.ptr); + acl_myfree(pItem); + break; + } + } + + return (pkt); +} + +static ICMP_PKT* timer_popup(ICMP_TIMER* timer) +{ + TimerItem *pTimerItem; + ICMP_PKT *pkt; + + time(&timer->present); + + pTimerItem = FIRST_TIMER(&timer->timer_header); + if (pTimerItem == NULL) + return (NULL); + + if (pTimerItem->when > timer->present) + return (NULL); + + acl_ring_detach(&pTimerItem->entry); /* first this */ + pkt = pTimerItem->pkt; + acl_myfree(pTimerItem); + + return (pkt); +} + +ICMP_TIMER *icmp_timer_new() +{ + ICMP_TIMER *timer; + + timer = (ICMP_TIMER*) acl_mycalloc(1, sizeof(ICMP_TIMER)); + timer->request = timer_request; + timer->cancel = timer_cancel; + timer->popup = timer_popup; + timer->find_delete = timer_find_delete; + + acl_ring_init(&timer->timer_header); + + return (timer); +} + +void icmp_timer_free(ICMP_TIMER* timer) +{ + acl_myfree(timer); +} diff --git a/lib_protocol/src/proto_snprintf.c b/lib_protocol/src/proto_snprintf.c new file mode 100644 index 000000000..3b56932ad --- /dev/null +++ b/lib_protocol/src/proto_snprintf.c @@ -0,0 +1,24 @@ +#include "StdAfx.h" +#ifdef __STDC_WANT_SECURE_LIB__ +#include + +int proto_secure_snprintf(char *buf, size_t size, const char *fmt, ...) +{ + va_list ap; + int ret; + + va_start(ap, fmt); + ret = _vsnprintf_s(buf, size, size, fmt, ap); + va_end(ap); + return (ret); +} + +int proto_securevsnprintf(char *buf, size_t size, const char *fmt, va_list ap) +{ + int ret; + + ret = _vsnprintf_s(buf, size, size, fmt, ap); + return (ret); +} + +#endif diff --git a/lib_protocol/src/smtp/smtp_client.c b/lib_protocol/src/smtp/smtp_client.c new file mode 100644 index 000000000..9796a1297 --- /dev/null +++ b/lib_protocol/src/smtp/smtp_client.c @@ -0,0 +1,650 @@ +#include "StdAfx.h" +#include "lib_acl.h" +#include +#include +#include "smtp/smtp_client.h" + +/* 创建 SMTP_CLIENT 对象并连接远程邮件服务器地址 */ + +SMTP_CLIENT *smtp_open(const char *addr, int conn_timeout, + int rw_timeout, int line_limit) +{ + SMTP_CLIENT *client; + ACL_VSTREAM *conn; + + conn = acl_vstream_connect(addr, ACL_BLOCKING, conn_timeout, + rw_timeout, 4096); + if (conn == NULL) { + acl_msg_error("%s(%d): connect %s error(%s)", + __FUNCTION__, __LINE__, addr, + acl_last_serror()); + return NULL; + } + + client = (SMTP_CLIENT*) acl_mycalloc(1, sizeof(SMTP_CLIENT)); + client->conn = conn; + client->buf = (char*) acl_mymalloc(line_limit); + client->size = line_limit; + + return client; +} + +/* 释放 SMTP_CLIENT 资源 */ + +void smtp_close(SMTP_CLIENT *client) +{ + acl_vstream_close(client->conn); + acl_myfree(client->buf); + acl_myfree(client); +} + +/* 接收服务器的欢迎信息 */ + +int smtp_get_banner(SMTP_CLIENT *client) +{ + int ret; + char *ptr; + + client->smtp_code = 0; + client->buf[0] = 0; + + /* 读取欢迎信息 */ + ret = acl_vstream_gets_nonl(client->conn, client->buf, client->size); + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): gets banner error", + __FUNCTION__, __LINE__); + return -1; + } + + ptr = strchr(client->buf, ' '); + if (ptr == NULL) + ptr = strchr(client->buf, '\t'); + if (ptr == NULL) { + acl_msg_error("%s(%d): get banner(%s) invalid", + __FUNCTION__, __LINE__, client->buf); + return -1; + } + *ptr = 0; + client->smtp_code = atoi(client->buf); + *ptr = ' '; /* 恢复原始值 */ + if (client->smtp_code != 220) { + acl_msg_error("%s(%d): get banner code(%d) error(%s)", + __FUNCTION__, __LINE__, client->smtp_code, client->buf); + return -1; + } + return 0; +} + +int smtp_greet(SMTP_CLIENT *client, const char* name, int ehlo) +{ + if (ehlo) + return smtp_ehlo(client, name); + else + return smtp_helo(client, name); +} + +/* 向服务器发送 HELO 命令 */ + +int smtp_helo(SMTP_CLIENT *client, const char *helo) +{ + int ret; + char *ptr; + + client->smtp_code = 0; + client->buf[0] = 0; + + /* 发送 helo 信息 */ + ret = acl_vstream_fprintf(client->conn, "HELO %s\r\n", helo); + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): send helo error(%s)", + __FUNCTION__, __LINE__, acl_last_serror()); + return -1; + } + + /* 读取响应信息 */ + ret = acl_vstream_gets_nonl(client->conn, client->buf, client->size); + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): gets helo's error(%s)", + __FUNCTION__, __LINE__, acl_last_serror()); + return -1; + } + + ptr = strchr(client->buf, ' '); + if (ptr == NULL) + ptr = strchr(client->buf, '\t'); + if (ptr == NULL) { + acl_msg_error("%s(%d): get helo reply error, line(%s)", + __FUNCTION__, __LINE__, client->buf); + return -1; + } + *ptr = 0; + client->smtp_code = atoi(client->buf); + *ptr = ' '; + if (client->smtp_code != 250) { + acl_msg_error("%s(%d): helo's reply code: %d, line(%s)", + __FUNCTION__, __LINE__, client->smtp_code, client->buf); + return -1; + } + return 0; +} + +static void smtp_ehlo_flag(SMTP_CLIENT *client, ACL_ARGV *tokens) +{ + if (strcasecmp(tokens->argv[0], "PIPELINING") == 0) { + client->flag |= SMTP_FLAG_PIPELINING; + } else if (strcasecmp(tokens->argv[0], "AUTH") == 0) { + client->flag |= SMTP_FLAG_AUTH; + } else if (strcasecmp(tokens->argv[0], "8BITMIME") == 0) { + client->flag |= SMTP_FLAG_8BITMIME; + } else if (strcasecmp(tokens->argv[0], "DSN") == 0) { + client->flag |= SMTP_FLAG_DSN; + } else if (strcasecmp(tokens->argv[0], "ETRN") == 0) { + client->flag |= SMTP_FLAG_ETRN; + } else if (strcasecmp(tokens->argv[0], "SIZE") == 0) { + if (tokens->argc >= 2) + client->message_size_limit = atoi(tokens->argv[1]); + if (client->message_size_limit > 0) + client->flag |= SMTP_FLAG_SIZE; + } +} + +/* 向服务器发送 EHLO 命令 */ + +int smtp_ehlo(SMTP_CLIENT *client, const char *ehlo) +{ + int ret; + char *ptr; + ACL_ARGV *tokens; + + client->buf[0] = 0; + client->smtp_code = 0; + + ret = acl_vstream_fprintf(client->conn, "EHLO %s\r\n", ehlo); + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): set EHLO error(%s)", + __FUNCTION__, __LINE__, acl_last_serror()); + return -1; + } + + while (1) { + ret = acl_vstream_gets_nonl(client->conn, client->buf, client->size); + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): get EHLO's reply error(%s)", + __FUNCTION__, __LINE__, acl_last_serror()); + return -1; + } else if (ret < 3) { + acl_msg_warn("%s(%d): EHLO's reply(%s) tool short", + __FUNCTION__, __LINE__, client->buf); + continue; + } + + if (strncmp(client->buf, "250", 3) != 0) { + ret = client->buf[3]; + client->buf[3] = 0; + client->smtp_code = atoi(client->buf); + client->buf[3] = ret; + + acl_msg_error("%s(%d): EHLO's reply(%s) code(%d) error", + __FUNCTION__, __LINE__, client->buf, ret); + return -1; + } else + client->smtp_code = 250; + + if (ret == 3) + break; + + ptr = client->buf + 4; + tokens = acl_argv_split(ptr, " ="); + smtp_ehlo_flag(client, tokens); + acl_argv_free(tokens); + + if (client->buf[3] == ' ') + break; + } + + return 0; +} + +/* 向服务器发送身份认证信息 */ + +int smtp_auth(SMTP_CLIENT *client, const char *user, const char *pass) +{ + int ret; + ACL_ARGV *tokens = NULL; + char *user_encoded = NULL, *pass_encoded = NULL; + +#undef RETURN +#define RETURN(x) do { \ + if (tokens) \ + acl_argv_free(tokens); \ + if (user_encoded) \ + acl_myfree(user_encoded); \ + if (pass_encoded) \ + acl_myfree(pass_encoded); \ + return (x); \ +} while (0) + + client->smtp_code = 0; + client->buf[0] = 0; + + /* 发送认证命令 */ + + ret = acl_vstream_fprintf(client->conn, "AUTH LOGIN\r\n"); + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): send AUTH LOGIN to error(%s)", + __FUNCTION__, __LINE__, acl_last_serror()); + RETURN (-1); + } + + ret = acl_vstream_gets_nonl(client->conn, client->buf, client->size); + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): gets AUTH LOGIN's reply error(%s)", + __FUNCTION__, __LINE__, acl_last_serror()); + RETURN (-1); + } + + tokens = acl_argv_split(client->buf, "\t "); + client->smtp_code = atoi(tokens->argv[0]); + if (client->smtp_code != 334) { + acl_msg_error("%s(%d): AUTH LOGIN failed, line(%s)", + __FUNCTION__, __LINE__, client->buf); + RETURN (-1); + } + + /* 发送邮箱帐号 */ + + user_encoded = (char*) acl_base64_encode(user, (int) strlen(user)); + ret = acl_vstream_fprintf(client->conn, "%s\r\n", user_encoded); + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): send user error(%s)", + __FUNCTION__, __LINE__, acl_last_serror()); + RETURN (-1); + } + + ret = acl_vstream_gets_nonl(client->conn, client->buf, client->size); + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): auth gets error(%s)", + __FUNCTION__, __LINE__, acl_last_serror()); + RETURN (-1); + } + acl_argv_free(tokens); + tokens = acl_argv_split(client->buf, "\t "); + client->smtp_code = atoi(tokens->argv[0]); + if (client->smtp_code != 334) { + acl_msg_error("%s(%d): AUTH LOGIN failed, line(%s)", + __FUNCTION__, __LINE__, client->buf); + RETURN (-1); + } + + /* 发送 password */ + + pass_encoded = (char*) acl_base64_encode(pass, (int) strlen(pass)); + ret = acl_vstream_fprintf(client->conn, "%s\r\n", pass_encoded); + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): send pass error(%s)", + __FUNCTION__, __LINE__, acl_last_serror()); + RETURN (-1); + } + ret = acl_vstream_gets_nonl(client->conn, client->buf, client->size); + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): auth gets pass's reply error(%s)", + __FUNCTION__, __LINE__, acl_last_serror()); + RETURN (-1); + } + acl_argv_free(tokens); + tokens = acl_argv_split(client->buf, "\t "); + client->smtp_code = atoi(tokens->argv[0]); + if (client->smtp_code != 235) { + acl_msg_error("%s(%d): AUTH LOGIN failed, line(%s)", + __FUNCTION__, __LINE__, client->buf); + RETURN (-1); + } + + RETURN (0); +} + +/* 向服务器发送 MAIL FROM 命令 */ + +int smtp_mail(SMTP_CLIENT *client, const char *from) +{ + int ret; + ACL_ARGV *tokens; + + client->smtp_code = 0; + client->buf[0] = 0; + + /* 发送 mail from 信息 */ + ret = acl_vstream_fprintf(client->conn, "MAIL FROM: <%s>\r\n", from); + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): send mail from error(%s)", + __FUNCTION__, __LINE__, acl_last_serror()); + return -1; + } + + + /* 读取响应信息 */ + ret = acl_vstream_gets_nonl(client->conn, client->buf, client->size); + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): gets mail from's reply error(%s)", + __FUNCTION__, __LINE__, acl_last_serror()); + return (-1); + } + + tokens = acl_argv_split(client->buf, "\t "); + client->smtp_code = atoi(tokens->argv[0]); + if (client->smtp_code != 250) { + acl_msg_error("%s(%d): mail from error(%d), line(%s)", + __FUNCTION__, __LINE__, client->smtp_code, client->buf); + acl_argv_free(tokens); + return -1; + } + + acl_argv_free(tokens); + return 0; +} + +/* 向服务器发送一个 RCPT TO 命令 */ + +int smtp_rcpt(SMTP_CLIENT *client, const char *to) +{ + int ret; + ACL_ARGV *tokens; + + client->smtp_code = 0; + client->buf[0] = 0; + + ret = acl_vstream_fprintf(client->conn, "RCPT TO: <%s>\r\n", to); + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): send rcpt error(%s)", + __FUNCTION__, __LINE__, acl_last_serror()); + return -1; + } + + ret = acl_vstream_gets_nonl(client->conn, client->buf, client->size); + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): gets rcpt's reply error(%s)", + __FUNCTION__, __LINE__, acl_last_serror()); + return -1; + } + + tokens = acl_argv_split(client->buf, "\t "); + client->smtp_code = atoi(tokens->argv[0]); + if (client->smtp_code != 250) { + acl_msg_error("%s(%d): rcpt's reply error(%d), line(%s)", + __FUNCTION__, __LINE__, client->smtp_code, client->buf); + acl_argv_free(tokens); + return -1; + } + + acl_argv_free(tokens); + return 0; +} + +/* 发送 DATA 命令 */ + +int smtp_data(SMTP_CLIENT *client) +{ + ACL_ARGV *tokens; + int ret; + + client->smtp_code = 0; + client->buf[0] = 0; + + ret = acl_vstream_fprintf(client->conn, "DATA\r\n"); + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): send data error(%s)", + __FUNCTION__, __LINE__, acl_last_serror()); + return -1; + } + + ret = acl_vstream_gets_nonl(client->conn, client->buf, client->size); + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): gets data's reply error(%s)", + __FUNCTION__, __LINE__, acl_last_serror()); + return -1; + } + + tokens = acl_argv_split(client->buf, "\t "); + client->smtp_code = atoi(tokens->argv[0]); + if (client->smtp_code != 354) { + acl_msg_error("%s(%d): data denied, error(%d), line(%s)", + __FUNCTION__, __LINE__, client->smtp_code, client->buf); + acl_argv_free(tokens); + return -1; + } + acl_argv_free(tokens); + + return 0; +} + +/* 发送 \r\n.\r\n */ + +int smtp_data_end(SMTP_CLIENT *client) +{ + int ret; + ACL_ARGV *tokens; + + client->smtp_code = 0; + client->buf[0] = 0; + + ret = acl_vstream_fprintf(client->conn, "\r\n.\r\n"); + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): send mail eof error(%s)", + __FUNCTION__, __LINE__, acl_last_serror()); + return -1; + } + + ret = acl_vstream_gets_nonl(client->conn, client->buf, client->size); + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): gets mail eof's reply error(%s)", + __FUNCTION__, __LINE__, acl_last_serror()); + return -1; + } + + tokens = acl_argv_split(client->buf, "\t "); + client->smtp_code = atoi(tokens->argv[0]); + if (client->smtp_code != 250) { + acl_msg_error("%s(%d): send mail error(%d), line: %s", + __FUNCTION__, __LINE__, client->smtp_code, client->buf); + acl_argv_free(tokens); + return -1; + } + + acl_argv_free(tokens); + return 0; +} + +int smtp_send(SMTP_CLIENT *client, const char* src, size_t len) +{ + if (acl_vstream_writen(client->conn, src, len) == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): write data error(%s)", + __FUNCTION__, __LINE__, acl_last_serror()); + return -1; + } + + return 0; +} + +int smtp_printf(SMTP_CLIENT *client, const char* fmt, ...) +{ + va_list ap; + int ret; + + va_start(ap, fmt); + ret = acl_vstream_vfprintf(client->conn, fmt, ap); + va_end(ap); + + return ret == ACL_VSTREAM_EOF ? -1 : 0; +} + +/* 发送邮件内容 */ + +int smtp_send_stream(SMTP_CLIENT *client, ACL_VSTREAM *in) +{ + int n = 0, ret; + + while (1) { + ret = acl_vstream_read(in, client->buf, client->size); + if (ret == ACL_VSTREAM_EOF) + break; + if (acl_vstream_writen(client->conn, client->buf, ret) + == ACL_VSTREAM_EOF) + { + acl_msg_error("%s(%d): write data error(%s)", + __FUNCTION__, __LINE__, acl_last_serror()); + return -1; + } + n += ret; + } + + if (n == 0) { + acl_msg_error("%s(%d): in stream is empty", + __FUNCTION__, __LINE__); + return -1; + } + return 0; +} + +/* 向服务器发送邮件内容 */ + +int smtp_send_file(SMTP_CLIENT *client, const char* filepath) +{ + int ret; + ACL_VSTREAM *in = acl_vstream_fopen(filepath, O_RDONLY, 0600, 4096); + + if (in == NULL) { + acl_msg_error("%s(%d): open %s error(%s)", __FUNCTION__, + __LINE__, filepath, acl_last_serror()); + return -1; + } + ret = smtp_send_stream(client, in); + acl_vstream_close(in); + return ret; +} + +/* 发送 QUIT 命令 */ + +int smtp_quit(SMTP_CLIENT *client) +{ + int ret; + ACL_ARGV *tokens; + + client->smtp_code = 0; + client->buf[0] = 0; + + ret = acl_vstream_fprintf(client->conn, "QUIT\r\n"); + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): send quit cmd error(%s)", + __FUNCTION__, __LINE__, acl_last_serror()); + return -1; + } + + ret = acl_vstream_gets_nonl(client->conn, client->buf, client->size); + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): gets quit's reply error(%s)", + __FUNCTION__, __LINE__, acl_last_serror()); + return -1; + } + + tokens = acl_argv_split(client->buf, "\t "); + client->smtp_code = atoi(tokens->argv[0]); + if (client->smtp_code != 221) { + acl_msg_error("%s(%d): quit's reply: %d", + __FUNCTION__, __LINE__, client->smtp_code); + acl_argv_free(tokens); + return -1; + } + acl_argv_free(tokens); + return 0; +} + +/* 发送 NOOP 命令 */ + +int smtp_noop(SMTP_CLIENT *client) +{ + int ret; + char *ptr; + + client->buf[0] = 0; + client->smtp_code = 0; + + ret = acl_vstream_fprintf(client->conn, "NOOP\r\n"); + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): write NOOP error(%s)", + __FUNCTION__, __LINE__, acl_last_serror()); + return -1; + } + + ret = acl_vstream_gets_nonl(client->conn, client->buf, client->size); + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): get NOOP's reply error(%s)", + __FUNCTION__, __LINE__, acl_last_serror()); + return -1; + } + + ptr = strchr(client->buf, ' '); + if (ptr == NULL) + ptr = strchr(client->buf, '\t'); + if (ptr == NULL) { + acl_msg_error("%s(%d): NOOP's reply(%s) invalid", + __FUNCTION__, __LINE__, client->buf); + return -1; + } + ret = *ptr; + *ptr = 0; + client->smtp_code = atoi(client->buf); + *ptr = ret; + if (client->smtp_code != 250) { + acl_msg_error("%s(%d): NOOP's reply(%s) code(%d) error", + __FUNCTION__, __LINE__, client->buf, client->smtp_code); + return -1; + } + + return 0; +} + +/* 发送 RSET 命令 */ + +int smtp_rset(SMTP_CLIENT *client) +{ + int ret; + char *ptr; + + client->buf[0] = 0; + client->smtp_code = 0; + + ret = acl_vstream_fprintf(client->conn, "RSET\r\n"); + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): write RSET error(%s)", + __FUNCTION__, __LINE__, acl_last_serror()); + return -1; + } + ret = acl_vstream_gets_nonl(client->conn, client->buf, client->size); + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): get RSET's reply error(%s)", + __FUNCTION__, __LINE__, acl_last_serror()); + return -1; + } + + ptr = strchr(client->buf, ' '); + if (ptr == NULL) + ptr = strchr(client->buf, '\t'); + if (ptr == NULL) { + acl_msg_error("%s(%d): RSET's reply(%s) invalid", + __FUNCTION__, __LINE__, client->buf); + return -1; + } + + ret = *ptr; + *ptr = 0; + client->smtp_code = atoi(client->buf); + *ptr = ret; + + if (client->smtp_code != 250) { + acl_msg_error("%s(%d): RSET's reply(%s) code(%d) error", + __FUNCTION__, __LINE__, client->buf, client->smtp_code); + return -1; + } + + return 0; +} diff --git a/lib_rpc/Makefile b/lib_rpc/Makefile new file mode 100644 index 000000000..644d5efb8 --- /dev/null +++ b/lib_rpc/Makefile @@ -0,0 +1,128 @@ +SHELL = /bin/sh +CC = g++ +AR = ar +ARFL = rv +#ARFL = cru +RANLIB = ranlib + +#-Wcast-qual +CFLAGS = -c -g -W -Wall -Wcast-align \ +-Wpointer-arith -Werror -Wshadow -O3 \ +-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS \ +-Wno-long-long \ +-fPIC \ +-Wformat \ +-DDEBUG +#-DHAS_POLARSSL +#-DUSE_DYNAMIC + +########################################################### +#Check system: +# Linux, SunOS, Solaris, BSD variants, AIX, HP-UX +SYSLIB = +CHECKSYSRES = @echo "Unknow system type!";exit 1 +UNIXNAME = $(shell uname -sm) + +ifeq ($(CC),) + CC = g++ +endif + +# For FreeBSD +ifeq ($(findstring FreeBSD, $(UNIXNAME)), FreeBSD) + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DFREEBSD -D_REENTRANT +endif + +# For Linux +ifeq ($(findstring Linux, $(UNIXNAME)), Linux) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DLINUX2 -D_REENTRANT +endif + +# For SunOS +ifeq ($(findstring SunOS, $(UNIXNAME)), SunOS) + ifeq ($(findstring 86, $(UNIXNAME)), 86) + SYSLIB = -lsocket -lnsl -lrt + endif + ifeq ($(findstring sun4u, $(UNIXNAME)), sun4u) + SYSLIB = -lsocket -lnsl -lrt + endif + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DSUNOS5 -D_REENTRANT +endif + +# For HP-UX +ifeq ($(findstring HP-UX, $(UNIXNAME)), HP-UX) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DHP_UX -DHPUX11 + PLAT_NAME=hp-ux +endif + +#Find system type. +ifneq ($(SYSPATH),) + CHECKSYSRES = @echo "System is $(shell uname -sm)" +endif +########################################################### + +OBJ_PATH_DST = ./Debug +LIB_PATH_DST = . +DEF_PATH_DST = ./Debug + +CFLAGS += -I./include -I../lib_acl_cpp/include -I../lib_acl/include -I../include + +#Project's objs +OBJS_DST = $(patsubst %.cpp, $(OBJ_PATH_DST)/%.o, $(notdir $(wildcard src/*.cpp))) + +OBJS_DEF = $(patsubst %.cpp, $(DEF_PATH_DST)/%.inc, $(notdir $(wildcard src/*.cpp))) + +########################################################### +.PHONY = static clean +VERSION = 1.0 +DATE_NOW = 20`date +%y`.`date +%m`.`date +%d` + +all: static + +$(shell mkdir -p $(DEF_PATH_DST)) +ifneq ($(MAKECMDGOALS),clean) +-include $(OBJS_DEF) +endif + +COMPILE = $(CC) $(CFLAGS) +COMPILE_OBJ = @(echo 'building $<'; $(COMPILE) $< -o $@) +CREATE_DEF = @(echo 'creating $@'; rm -f $@; \ + $(COMPILE) -MM $< > $@.$$$$; \ + sed 's,.*.o\( \)*:,$(patsubst %.inc,%.o,$@) $@ :,g' < $@.$$$$ > $@; \ + rm -f $@.$$$$) + +########################################################### + +static: depends $(OBJS_DST) + @echo 'creating $(LIB_PATH_DST)/lib_rpc.a' + @$(AR) $(ARFL) $(LIB_PATH_DST)/lib_rpc.a $(OBJS_DST) + @$(RANLIB) $(LIB_PATH_DST)/lib_rpc.a + @echo 'create $(LIB_PATH_DST)/lib_rpc.a ok!' + +depends: $(OBJS_DEF) + +# src +$(OBJ_PATH_DST)/%.o: ./src/%.cpp + $(COMPILE_OBJ) + +$(DEF_PATH_DST)/%.inc: ./src/%.cpp + $(CREATE_DEF) + +samples: $(lib_rpc.a) + @(cd samples; make) +clean: + rm -f $(LIB_PATH_DST)/lib_rpc.a + rm -f $(OBJS_DST) + rm -f $(OBJS_DEF) + @(cd samples; make clean) diff --git a/lib_rpc/ReadMe.txt b/lib_rpc/ReadMe.txt new file mode 100644 index 000000000..0d75619ea --- /dev/null +++ b/lib_rpc/ReadMe.txt @@ -0,0 +1,28 @@ +======================================================================== + 静态库 : lib_rpc 项目概况 +======================================================================== + +应用程序向导已为您创建了这个 lib_rpc 库项目。 +此文件包含组成 lib_rpc 应用程序 +的每个文件的内容摘要。 + + +lib_rpc.vcproj + 这是用应用程序向导生成的 VC++ 项目的主项目文件。 + 它包含有关生成此文件的 Visual C++ 版本的信息,以及 + 有关用应用程序向导选择的 + 平台、配置和项目功能的信息。 + + +///////////////////////////////////////////////////////////////////////////// + +StdAfx.h、StdAfx.cpp + 这些文件用于生成名为 lib_rpc.pch + 的预编译头(PCH)文件以及名为 StdAfx.obj 的预编译类型文件。 + +///////////////////////////////////////////////////////////////////////////// +其他注释: + +应用程序向导使用 "TODO:" 注释指示应添加或自定义的源代码部分。 + +///////////////////////////////////////////////////////////////////////////// diff --git a/lib_rpc/bin/protoc b/lib_rpc/bin/protoc new file mode 100644 index 000000000..beefd2398 --- /dev/null +++ b/lib_rpc/bin/protoc @@ -0,0 +1,228 @@ +#! /bin/sh + +# protoc - temporary wrapper script for .libs/protoc +# Generated by libtool (GNU libtool) 2.4.2 Debian-2.4.2-1ubuntu1 +# +# The protoc program cannot be directly executed until all the libtool +# libraries that it depends on are installed. +# +# This wrapper script should never be moved out of the build directory. +# If it is, it will not operate correctly. + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +sed_quote_subst='s/\([`"$\\]\)/\\\1/g' + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac +fi +BIN_SH=xpg4; export BIN_SH # for Tru64 +DUALCASE=1; export DUALCASE # for MKS sh + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +relink_command="(cd /home/zsx/download/protocol_buffers/protobuf-2.5.0/src; { test -z \"\${LIBRARY_PATH+set}\" || unset LIBRARY_PATH || { LIBRARY_PATH=; export LIBRARY_PATH; }; }; { test -z \"\${COMPILER_PATH+set}\" || unset COMPILER_PATH || { COMPILER_PATH=; export COMPILER_PATH; }; }; { test -z \"\${GCC_EXEC_PREFIX+set}\" || unset GCC_EXEC_PREFIX || { GCC_EXEC_PREFIX=; export GCC_EXEC_PREFIX; }; }; { test -z \"\${LD_RUN_PATH+set}\" || unset LD_RUN_PATH || { LD_RUN_PATH=; export LD_RUN_PATH; }; }; LD_LIBRARY_PATH=:/usr/local/lib; export LD_LIBRARY_PATH; PATH=/usr/lib64/qt-3.3/bin:/usr/kerberos/bin:/usr/local/bin:/bin:/usr/bin:/home/zsx/bin:/home/zsx/download/d/dmd.2.060/dmd2/linux/bin64:/home/zsx/download/nodejs/node-v0.6.7/bin/bin; export PATH; g++ -pthread -Wall -Wwrite-strings -Woverloaded-virtual -Wno-sign-compare -O2 -g -DNDEBUG -pthread -o \$progdir/\$file main.o -lpthread ./.libs/libprotobuf.so ./.libs/libprotoc.so -lz -pthread -Wl,-rpath -Wl,/home/zsx/download/protocol_buffers/protobuf-2.5.0/src/.libs -Wl,-rpath -Wl,/home/zsx/tools/protobuf/lib)" + +# This environment variable determines our operation mode. +if test "$libtool_install_magic" = "%%%MAGIC variable%%%"; then + # install mode needs the following variables: + generated_by_libtool_version='2.4.2' + notinst_deplibs=' libprotobuf.la libprotoc.la' +else + # When we are sourced in execute mode, $file and $ECHO are already set. + if test "$libtool_execute_magic" != "%%%MAGIC variable%%%"; then + file="$0" + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +$1 +_LTECHO_EOF' +} + ECHO="printf %s\\n" + fi + +# Very basic option parsing. These options are (a) specific to +# the libtool wrapper, (b) are identical between the wrapper +# /script/ and the wrapper /executable/ which is used only on +# windows platforms, and (c) all begin with the string --lt- +# (application programs are unlikely to have options which match +# this pattern). +# +# There are only two supported options: --lt-debug and +# --lt-dump-script. There is, deliberately, no --lt-help. +# +# The first argument to this parsing function should be the +# script's ../libtool value, followed by no. +lt_option_debug= +func_parse_lt_options () +{ + lt_script_arg0=$0 + shift + for lt_opt + do + case "$lt_opt" in + --lt-debug) lt_option_debug=1 ;; + --lt-dump-script) + lt_dump_D=`$ECHO "X$lt_script_arg0" | /bin/sed -e 's/^X//' -e 's%/[^/]*$%%'` + test "X$lt_dump_D" = "X$lt_script_arg0" && lt_dump_D=. + lt_dump_F=`$ECHO "X$lt_script_arg0" | /bin/sed -e 's/^X//' -e 's%^.*/%%'` + cat "$lt_dump_D/$lt_dump_F" + exit 0 + ;; + --lt-*) + $ECHO "Unrecognized --lt- option: '$lt_opt'" 1>&2 + exit 1 + ;; + esac + done + + # Print the debug banner immediately: + if test -n "$lt_option_debug"; then + echo "protoc:protoc:${LINENO}: libtool wrapper (GNU libtool) 2.4.2 Debian-2.4.2-1ubuntu1" 1>&2 + fi +} + +# Used when --lt-debug. Prints its arguments to stdout +# (redirection is the responsibility of the caller) +func_lt_dump_args () +{ + lt_dump_args_N=1; + for lt_arg + do + $ECHO "protoc:protoc:${LINENO}: newargv[$lt_dump_args_N]: $lt_arg" + lt_dump_args_N=`expr $lt_dump_args_N + 1` + done +} + +# Core function for launching the target application +func_exec_program_core () +{ + + if test -n "$lt_option_debug"; then + $ECHO "protoc:protoc:${LINENO}: newargv[0]: $progdir/$program" 1>&2 + func_lt_dump_args ${1+"$@"} 1>&2 + fi + exec "$progdir/$program" ${1+"$@"} + + $ECHO "$0: cannot exec $program $*" 1>&2 + exit 1 +} + +# A function to encapsulate launching the target application +# Strips options in the --lt-* namespace from $@ and +# launches target application with the remaining arguments. +func_exec_program () +{ + case " $* " in + *\ --lt-*) + for lt_wr_arg + do + case $lt_wr_arg in + --lt-*) ;; + *) set x "$@" "$lt_wr_arg"; shift;; + esac + shift + done ;; + esac + func_exec_program_core ${1+"$@"} +} + + # Parse options + func_parse_lt_options "$0" ${1+"$@"} + + # Find the directory that this script lives in. + thisdir=`$ECHO "$file" | /bin/sed 's%/[^/]*$%%'` + test "x$thisdir" = "x$file" && thisdir=. + + # Follow symbolic links until we get to the real thisdir. + file=`ls -ld "$file" | /bin/sed -n 's/.*-> //p'` + while test -n "$file"; do + destdir=`$ECHO "$file" | /bin/sed 's%/[^/]*$%%'` + + # If there was a directory component, then change thisdir. + if test "x$destdir" != "x$file"; then + case "$destdir" in + [\\/]* | [A-Za-z]:[\\/]*) thisdir="$destdir" ;; + *) thisdir="$thisdir/$destdir" ;; + esac + fi + + file=`$ECHO "$file" | /bin/sed 's%^.*/%%'` + file=`ls -ld "$thisdir/$file" | /bin/sed -n 's/.*-> //p'` + done + + # Usually 'no', except on cygwin/mingw when embedded into + # the cwrapper. + WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=no + if test "$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR" = "yes"; then + # special case for '.' + if test "$thisdir" = "."; then + thisdir=`pwd` + fi + # remove .libs from thisdir + case "$thisdir" in + *[\\/].libs ) thisdir=`$ECHO "$thisdir" | /bin/sed 's%[\\/][^\\/]*$%%'` ;; + .libs ) thisdir=. ;; + esac + fi + + # Try to get the absolute directory name. + absdir=`cd "$thisdir" && pwd` + test -n "$absdir" && thisdir="$absdir" + + program=lt-'protoc' + progdir="$thisdir/.libs" + + if test ! -f "$progdir/$program" || + { file=`ls -1dt "$progdir/$program" "$progdir/../$program" 2>/dev/null | /bin/sed 1q`; \ + test "X$file" != "X$progdir/$program"; }; then + + file="$$-$program" + + if test ! -d "$progdir"; then + mkdir "$progdir" + else + rm -f "$progdir/$file" + fi + + # relink executable if necessary + if test -n "$relink_command"; then + if relink_command_output=`eval $relink_command 2>&1`; then : + else + printf %s\n "$relink_command_output" >&2 + rm -f "$progdir/$file" + exit 1 + fi + fi + + mv -f "$progdir/$file" "$progdir/$program" 2>/dev/null || + { rm -f "$progdir/$program"; + mv -f "$progdir/$file" "$progdir/$program"; } + rm -f "$progdir/$file" + fi + + if test -f "$progdir/$program"; then + if test "$libtool_execute_magic" != "%%%MAGIC variable%%%"; then + # Run the actual program with our arguments. + func_exec_program ${1+"$@"} + fi + else + # The program doesn't exist. + $ECHO "$0: error: \`$progdir/$program' does not exist" 1>&2 + $ECHO "This script is just a wrapper for $program." 1>&2 + $ECHO "See the libtool documentation for more information." 1>&2 + exit 1 + fi +fi diff --git a/lib_rpc/bin/protoc.exe b/lib_rpc/bin/protoc.exe new file mode 100644 index 000000000..ef37d8c13 Binary files /dev/null and b/lib_rpc/bin/protoc.exe differ diff --git a/lib_rpc/include/google/protobuf/io/acl_fstream.h b/lib_rpc/include/google/protobuf/io/acl_fstream.h new file mode 100644 index 000000000..9e0b742cf --- /dev/null +++ b/lib_rpc/include/google/protobuf/io/acl_fstream.h @@ -0,0 +1,83 @@ +#pragma once + +#include +#include +#include +#include "acl_cpp/stream/istream.hpp" +#include "acl_cpp/stream/ofstream.hpp" + +namespace google { +namespace protobuf { +namespace io { + +class LIBPROTOBUF_EXPORT acl_ifstream : public ZeroCopyInputStream +{ +public: + explicit acl_ifstream(acl::istream* in, int block_size = -1); + ~acl_ifstream(); + + //基类 ZeroCopyInputStream 虚函数实现 + bool Next(const void** data, int* size); + void BackUp(int count); + bool Skip(int count); + int64 ByteCount() const; +private: + class LIBPROTOBUF_EXPORT CopyingAclInputStream : public CopyingInputStream + { + public: + CopyingAclInputStream(acl::istream* input); + ~CopyingAclInputStream(); + + // implements CopyingInputStream + int Read(void* buffer, int size); + // (We usse the default implementation of Skip().) + + private: + acl::istream* input_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CopyingAclInputStream); + }; + + CopyingAclInputStream copying_input_; + CopyingInputStreamAdaptor impl_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(acl_ifstream); +}; + +class LIBPROTOBUF_EXPORT acl_ofstream : public ZeroCopyOutputStream +{ +public: + explicit acl_ofstream(acl::ostream* output, int block_size = -1); + ~acl_ofstream(); + + bool Flush(); + + //基类 ZeroCopyInputStream 虚函数实现 + bool Next(void** data, int* size); + void BackUp(int count); + int64 ByteCount() const; +private: + class LIBPROTOBUF_EXPORT CopyingAclOutputStream : public CopyingOutputStream + { + public: + CopyingAclOutputStream(acl::ostream* output); + ~CopyingAclOutputStream(); + + // implements CopyingOutputStream + bool Write(const void* buffer, int size); + + private: + acl::ostream* output_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CopyingAclOutputStream); + }; + + CopyingAclOutputStream copying_output_; + CopyingOutputStreamAdaptor impl_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(acl_ofstream); +}; + +} // namespace io +} // namespace protobuf +} // namespace google diff --git a/lib_rpc/include/google/protobuf/io/http_stream.h b/lib_rpc/include/google/protobuf/io/http_stream.h new file mode 100644 index 000000000..c5f5af05c --- /dev/null +++ b/lib_rpc/include/google/protobuf/io/http_stream.h @@ -0,0 +1,143 @@ +#pragma once +#include +#include +#include +#include "acl_cpp/http/http_request.hpp" +#include "acl_cpp/http/http_response.hpp" + +namespace google { +namespace protobuf { + +class MessageLite; + +namespace io { + +/** + * 使用 HTTP 传输协议发送 protobuf 请求数据至服务端,同时等待服务端响应结果 + */ +class LIBPROTOBUF_EXPORT http_request +{ +public: + /** + * 构造函数(一):使用输入的 HTTP 请求对象,用户需自行释放之,长连接时 + * 可以使用本构造函数,从而允许客户端在一个连接上发送多次请求 + * @param request {acl::http_request*} HTTP 客户端请求对象,非空 + */ + explicit http_request(acl::http_request* request); + + /** + * 构造函数(二):内部创建 HTTP 请求对象,用完后自动释放之,短连接时 + * 可以使用本构造函数 + * @param addr {const char*} http 服务器监听地址,格式:ip:port + * @param conn_timeout {int} 连接服务器的超时时间(秒) + * @param rw_timeout {int} IO 超时时间(秒) + */ + explicit http_request(const char* addr, int conn_timeout = 60, + int rw_timeout = 60); + + ~http_request(); + + /** + * 发送经 protobuf 序列化的数据包,同时接收服务器响应的序列化数据包 + * @param in {const MessageLite&} 客户端生成的请求数据包 + * @param out {MessageLite*} 存储服务端响应的数据包 + * @return {bool} 是否成功 + */ + bool rpc_request(const MessageLite& in, MessageLite* out); + + double request_spent() const + { + return request_spent_; + } + + double response_spent() const + { + return response_spent_; + } + + double build_spent() const + { + return build_spent_; + } + + double parse_spent() const + { + return parse_spent_; + } +private: + acl::http_request* request_; + acl::http_request* request_inner_; + char* addr_; + int conn_timeout_; + int rw_timeout_; + + double request_spent_; + double response_spent_; + double build_spent_; + double parse_spent_; +}; + +/** + * 服务端使用本类对象接收客户端请求,同时将结果返回给客户端 + */ +class LIBPROTOBUF_EXPORT http_response +{ +public: + /** + * 构造函数 + * @param response {acl::http_response*} 与客户端相连的服务端连接对象 + */ + explicit http_response(acl::http_response* response); + + ~http_response(); + + /** + * 服务端调用本过程读取客户端的数据请求 + * @param out {MessageLite*} 存储客户端请求数据 + * @return {bool} 读过程是否成功 + */ + bool read_request(MessageLite* out); + + /** + * 将处理结果通过本过程返回给客户端 + * @param int {const MessageLite&} 服务端生成的结果数据 + * @return {bool} 写过程是否成功 + */ + bool send_response(const MessageLite& in); + + double header_spent() const + { + return header_spent_; + } + + double body_spent() const + { + return body_spent_; + } + + double parse_spent() const + { + return parse_spent_; + } + + double build_spent() const + { + return build_spent_; + } + + double response_spent() const + { + return response_spent_; + } +private: + acl::http_response* response_; + double header_spent_; + double body_spent_; + double parse_spent_; + double build_spent_; + double response_spent_; +}; + +} // namespace io +} // namespace protobuf +} // namespace google diff --git a/lib_rpc/lib_rpc.vcxproj b/lib_rpc/lib_rpc.vcxproj new file mode 100644 index 000000000..9596dd685 --- /dev/null +++ b/lib_rpc/lib_rpc.vcxproj @@ -0,0 +1,102 @@ +锘 + + + + Debug + Win32 + + + Release + Win32 + + + + {2B0C9A86-6C14-4CEF-BD7A-4A6752386A44} + Win32Proj + + + + StaticLibrary + MultiByte + v110 + + + StaticLibrary + MultiByte + v110 + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + Release\ + Release\ + AllRules.ruleset + + + AllRules.ruleset + + + $(ProjectName)_vc2012d + $(ProjectName)_vc2012 + + + + Disabled + .\include;..\lib_acl_cpp\include;..\include;..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Use + Level3 + EditAndContinue + $(IntDir)vc$(PlatformToolsetVersion)_vc2012d.pdb + + + $(OutDir)lib_rpc_vc2012d.lib + + + + + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreaded + Use + Level3 + ProgramDatabase + .\include;..\lib_acl_cpp\include;..\include;..\lib_acl\include;%(AdditionalIncludeDirectories) + + + $(OutDir)lib_rpc_vc2012.lib + + + + + + + Create + Create + + + + + + + + + + + + + + diff --git a/lib_rpc/lib_rpc.vcxproj.filters b/lib_rpc/lib_rpc.vcxproj.filters new file mode 100644 index 000000000..92514c9fb --- /dev/null +++ b/lib_rpc/lib_rpc.vcxproj.filters @@ -0,0 +1,42 @@ +锘 + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx + + + + + 婧愭枃浠 + + + 婧愭枃浠 + + + 婧愭枃浠 + + + + + 澶存枃浠 + + + 澶存枃浠 + + + 澶存枃浠 + + + + + + \ No newline at end of file diff --git a/lib_rpc/samples/Makefile b/lib_rpc/samples/Makefile new file mode 100644 index 000000000..f8cd911a6 --- /dev/null +++ b/lib_rpc/samples/Makefile @@ -0,0 +1,9 @@ +all: + @(cd fstream; make) + @(cd http_rpc_server; make) + @(cd http_rpc_client; make) + +clean: + @(cd fstream; make clean) + @(cd http_rpc_server; make clean) + @(cd http_rpc_client; make clean) diff --git a/lib_rpc/samples/Makefile.in b/lib_rpc/samples/Makefile.in new file mode 100644 index 000000000..2d9da0d74 --- /dev/null +++ b/lib_rpc/samples/Makefile.in @@ -0,0 +1,108 @@ +CC = g++ + +CFLAGS = -c -g -W -Wall -Wcast-qual -Wcast-align \ +-Wno-long-long \ +-Wpointer-arith -Werror -O3 \ +-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO +#-Wshadow +#-Waggregate-return +########################################################### +#Check system: +# Linux, SunOS, Solaris, BSD variants, AIX, HP-UX +SYSLIB = -lpthread -lcrypt -lz +CHECKSYSRES = @echo "Unknow system type!";exit 1 +UNIXNAME = $(shell uname -sm) +OSTYPE = $(shell uname -p) + +RPATH = + +ifeq ($(CC),) + CC = gcc +endif + +# For FreeBSD +ifeq ($(findstring FreeBSD, $(UNIXNAME)), FreeBSD) + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DFREEBSD -D_REENTRANT + SYSLIB = -lcrypt -lpthread +endif + +#Path for Linux +ifeq ($(findstring Linux, $(UNIXNAME)), Linux) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + ifeq ($(findstring i686, $(OSTYPE)), i686) + RPATH = linux32 + endif + ifeq ($(findstring x86_64, $(OSTYPE)), x86_64) + RPATH = linux64 + endif + CFLAGS += -DLINUX2 -D_REENTRANT +endif + +#Path for SunOS +ifeq ($(findstring SunOS, $(UNIXNAME)), SunOS) + ifeq ($(findstring 86, $(UNIXNAME)), 86) + SYSLIB += -lsocket -lnsl -lrt + endif + ifeq ($(findstring sun4u, $(UNIXNAME)), sun4u) + SYSLIB += -lsocket -lnsl -lrt + endif + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DSUNOS5 -D_REENTRANT +endif + +#Path for HP-UX +ifeq ($(findstring HP-UX, $(UNIXNAME)), HP-UX) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DHP_UX -DHPUX11 + PLAT_NAME=hp-ux +endif + +#Find system type. +ifneq ($(SYSPATH),) + CHECKSYSRES = @echo "System is $(shell uname -sm)" +endif +########################################################### + +CFLAGS += -I../../include -I../../../include -I. -I.. \ + -I../../../lib_acl_cpp/include -I../../../lib_acl/include +EXTLIBS = +LDFLAGS = -L../.. -l_rpc \ + -L../../../lib_acl_cpp/lib -l_acl_cpp -L../../../lib_protocol/lib -l_protocol -L../../../lib_acl/lib -l_acl \ + -L../../../lib/protobuf/$(RPATH) -lprotobuf-lite \ + $(EXTLIBS) $(SYSLIB) + +COMPILE = $(CC) $(CFLAGS) +LINK = $(CC) $(OBJ) $(LDFLAGS) +########################################################### +OBJ_PATH = . + +#Project's objs +SRC = $(wildcard *.cpp) $(wildcard ../*.cpp) +OBJ = $(patsubst %.cpp, $(OBJ_PATH)/%.o, $(notdir $(SRC))) + +$(OBJ_PATH)/%.o: %.cpp + $(COMPILE) $< -o $@ +$(OBJ_PATH)/%.o: ../%.cpp + $(COMPILE) $< -o $@ + +.PHONY = all clean +all: RM $(OBJ) + $(LINK) -o $(PROG) + @echo "" + @echo "All ok! Output:$(PROG)" + @echo "" +RM: + rm -f $(PROG) +clean: + rm -f $(PROG) + rm -f $(OBJ) +########################################################### diff --git a/lib_rpc/samples/fstream/Makefile b/lib_rpc/samples/fstream/Makefile new file mode 100644 index 000000000..677bfa1c1 --- /dev/null +++ b/lib_rpc/samples/fstream/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = fstream diff --git a/lib_rpc/samples/fstream/ReadMe.txt b/lib_rpc/samples/fstream/ReadMe.txt new file mode 100644 index 000000000..48b12e897 --- /dev/null +++ b/lib_rpc/samples/fstream/ReadMe.txt @@ -0,0 +1,40 @@ +======================================================================== + CONSOLE APPLICATION : protobuf_client Project Overview +======================================================================== + +AppWizard has created this protobuf_client application for you. + +This file contains a summary of what you will find in each of the files that +make up your protobuf_client application. + + +protobuf_client.vcxproj + This is the main project file for VC++ projects generated using an Application Wizard. + It contains information about the version of Visual C++ that generated the file, and + information about the platforms, configurations, and project features selected with the + Application Wizard. + +protobuf_client.vcxproj.filters + This is the filters file for VC++ projects generated using an Application Wizard. + It contains information about the association between the files in your project + and the filters. This association is used in the IDE to show grouping of files with + similar extensions under a specific node (for e.g. ".cpp" files are associated with the + "Source Files" filter). + +protobuf_client.cpp + This is the main application source file. + +///////////////////////////////////////////////////////////////////////////// +Other standard files: + +StdAfx.h, StdAfx.cpp + These files are used to build a precompiled header (PCH) file + named protobuf_client.pch and a precompiled types file named StdAfx.obj. + +///////////////////////////////////////////////////////////////////////////// +Other notes: + +AppWizard uses "TODO:" comments to indicate parts of the source code you +should add to or customize. + +///////////////////////////////////////////////////////////////////////////// diff --git a/lib_rpc/samples/fstream/main.cpp b/lib_rpc/samples/fstream/main.cpp new file mode 100644 index 000000000..de8bea037 --- /dev/null +++ b/lib_rpc/samples/fstream/main.cpp @@ -0,0 +1,171 @@ +// protobuf_client.cpp : Defines the entry point for the console application. +// + +#include "stdafx.h" +#include "acl_cpp/stream/ifstream.hpp" +#include "acl_cpp/stream/ofstream.hpp" +#include "acl_cpp/stdlib/string.hpp" +#include "google/protobuf/io/acl_fstream.h" + +#include "../util.h" +#include "../test.pb.h" + +using namespace google::protobuf::io; + +static void usage(const char* procname) +{ + printf("usage: %s -h [help] -n max\r\n", procname); +} + +int main(int argc, char* argv[]) +{ + int total = 10000; + int ch; + + while ((ch = getopt(argc, argv, "hn:")) > 0) + { + switch (ch) + { + case 'h': + usage(argv[0]); + return 0; + case 'n': + total = atoi(optarg); + if (total <= 0) + total = 10000; + break; + default: + break; + } + } + + const char* path = "test.txt"; + + // 将用户的信息序列化输出至文件中 + + //打开本地文件进行数据写入 + acl::ofstream out_fp; + if (out_fp.open_write(path) == false) + { + printf("open file %s error\r\n", path); + return 1; + } + + // 将文件输出流与系列化输出流进行关联 + acl_ofstream output(&out_fp); + + tutorial::AddressBook address; + size_t person_count = 5; + + acl::string buf; + + // 给地址簿中添加用户列表 + for (size_t i = 0; i < person_count; i++) + { + tutorial::Person* person = address.add_person(); + buf.format("zsxxsz-%d", i); + person->set_name(buf.c_str()); + buf.format("zsxxsz-%d@test.com", i); + person->set_email(buf.c_str()); + person->set_id(i); + + // 给一个用户添加多个电话号码 + for (size_t j = 0; j < tutorial::Person::WORK; j++) + { + tutorial::Person::PhoneNumber* phone = person->add_phone(); + buf.format("11111111-%d-%d", i, j); + phone->set_number(buf.c_str()); + } + } + + // 将地址簿数据序列化至磁盘文件流中 + address.SerializeToZeroCopyStream(&output); + if (output.Flush() == false) + { + printf("flush failed!\r\n"); + return 1; + } + out_fp.close(); + + ///////////////////////////////////////////////////////////////////////// + + // 从序列化文件中读取用户信息 + + // 打开本地文件输入流 + acl::ifstream in_fp; + if (in_fp.open_read(path) == false) + { + printf("open file %s error\r\n", path); + return 1; + } + + // 将文件输入流与系列化输入流进行关联 + acl_ifstream input(&in_fp); + + address.Clear(); + + // 从文件流中解析地址簿信息 + if (!address.ParseFromZeroCopyStream(&input)) + { + printf("parse file %s failed\r\n", path); + return 1; + } + + // 列出地址簿中所有用户信息 + for (int i = 0; i < address.person_size(); i++) + { + const tutorial::Person& person = address.person(i); + printf("person->name: %s\r\n", person.name().c_str()); + printf("person->id: %d\r\n", person.id()); + printf("person->email: %s\r\n", person.has_email() ? + person.email().c_str() : "null"); + + // 列出该用户的所有电话 + for (int j = 0; j < person.phone_size(); j++) + { + const tutorial::Person::PhoneNumber& phone = person.phone(j); + printf("\tphone number: %s\r\n", phone.number().c_str()); + } + printf("------------------------------------------\r\n"); + } + + acl::string buf1; + acl::ifstream::load(path, &buf1); + + struct timeval begin; + gettimeofday(&begin, NULL); + + ACL_METER_TIME("begin run"); + for (int i = 0; i < total; i++) + { + address.Clear(); + std::string data(buf1.c_str(), buf1.length()); + if (address.ParseFromString(data) == false) + { + printf("parse failed\r\n"); + break; + } + if (i % 1000 == 0) + { + char tmp[64]; + snprintf(tmp, sizeof(tmp), "total: %d, curr: %d", total, i); + ACL_METER_TIME(tmp); + } + } + + struct timeval end; + gettimeofday(&end, NULL); + double n = util::stamp_sub(&end, &begin); + printf("total check: %d, spent: %0.2f ms, speed: %0.2f\r\n", + total, n, (total * 1000) /(n > 0 ? n : 1)); + + // Optional: Delete all global objects allocated by libprotobuf. + google::protobuf::ShutdownProtobufLibrary(); + +#ifdef WIN32 + printf("Enter any key to exit\r\n"); + getchar(); +#endif + + return 0; +} diff --git a/lib_rpc/samples/fstream/protobuf_fstream.vcxproj b/lib_rpc/samples/fstream/protobuf_fstream.vcxproj new file mode 100644 index 000000000..28b6cfdc1 --- /dev/null +++ b/lib_rpc/samples/fstream/protobuf_fstream.vcxproj @@ -0,0 +1,106 @@ +锘 + + + + Debug + Win32 + + + Release + Win32 + + + + {E8A3F4F4-0217-4775-9AC4-BD10E12298D4} + Win32Proj + protobuf_fstream + + + + Application + true + Unicode + + + Application + false + true + Unicode + + + + + + + + + + + + + true + $(Configuration)\ + + + false + $(Configuration)\ + $(ProjectName) + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;_SCL_SECURE_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + ..\..\include;..\..\..\lib_acl_cpp\include;..\..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + MultiThreadedDebug + + + Console + true + ..\..\Debug;..\..\..\lib\protobuf\win32;..\..\..\dist\lib\win32 + libprotobuf-lite-debug.lib;lib_rpc_vc2010d.lib;lib_acl_cpp_vc2010d.lib;lib_acl_vc2010d.lib;%(AdditionalDependencies) + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;_SCL_SECURE_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + ..\..\include;..\..\..\lib_acl_cpp\include;..\..\..\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + MultiThreaded + + + Console + true + true + true + ..\..\Release;..\..\..\lib\protobuf\win32;..\..\..\dist\lib\win32 + libprotobuf-lite.lib;lib_rpc_vc2010.lib;lib_acl_cpp_vc2010.lib;lib_acl_vc2010.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + + + Create + Create + + + + + + \ No newline at end of file diff --git a/lib_rpc/samples/fstream/protobuf_fstream.vcxproj.filters b/lib_rpc/samples/fstream/protobuf_fstream.vcxproj.filters new file mode 100644 index 000000000..4bc0678c4 --- /dev/null +++ b/lib_rpc/samples/fstream/protobuf_fstream.vcxproj.filters @@ -0,0 +1,46 @@ +锘 + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + + + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/lib_rpc/samples/fstream/protobuf_fstream.vcxproj.user b/lib_rpc/samples/fstream/protobuf_fstream.vcxproj.user new file mode 100644 index 000000000..ace9a86ac --- /dev/null +++ b/lib_rpc/samples/fstream/protobuf_fstream.vcxproj.user @@ -0,0 +1,3 @@ +锘 + + \ No newline at end of file diff --git a/lib_rpc/samples/fstream/stdafx.cpp b/lib_rpc/samples/fstream/stdafx.cpp new file mode 100644 index 000000000..d3d3b8646 --- /dev/null +++ b/lib_rpc/samples/fstream/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// protobuf_client.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/lib_rpc/samples/fstream/stdafx.h b/lib_rpc/samples/fstream/stdafx.h new file mode 100644 index 000000000..3566e9bb9 --- /dev/null +++ b/lib_rpc/samples/fstream/stdafx.h @@ -0,0 +1,21 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#include "targetver.h" + +#include +//#include + + + +// TODO: reference additional headers your program requires here + +#include "lib_acl.h" + +#ifdef WIN32 +#define snprintf _snprintf +#endif diff --git a/lib_rpc/samples/fstream/targetver.h b/lib_rpc/samples/fstream/targetver.h new file mode 100644 index 000000000..a92219b0e --- /dev/null +++ b/lib_rpc/samples/fstream/targetver.h @@ -0,0 +1,10 @@ +#pragma once + +// Including SDKDDKVer.h defines the highest available Windows platform. + +// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and +// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. + +#ifdef WIN32 +#include +#endif diff --git a/lib_rpc/samples/http_rpc_client/Makefile b/lib_rpc/samples/http_rpc_client/Makefile new file mode 100644 index 000000000..3bab03150 --- /dev/null +++ b/lib_rpc/samples/http_rpc_client/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = http_rpc_client diff --git a/lib_rpc/samples/http_rpc_client/ReadMe.txt b/lib_rpc/samples/http_rpc_client/ReadMe.txt new file mode 100644 index 000000000..8aba2d14c --- /dev/null +++ b/lib_rpc/samples/http_rpc_client/ReadMe.txt @@ -0,0 +1,40 @@ +======================================================================== + CONSOLE APPLICATION : http_rpc_client Project Overview +======================================================================== + +AppWizard has created this http_rpc_client application for you. + +This file contains a summary of what you will find in each of the files that +make up your http_rpc_client application. + + +http_rpc_client.vcxproj + This is the main project file for VC++ projects generated using an Application Wizard. + It contains information about the version of Visual C++ that generated the file, and + information about the platforms, configurations, and project features selected with the + Application Wizard. + +http_rpc_client.vcxproj.filters + This is the filters file for VC++ projects generated using an Application Wizard. + It contains information about the association between the files in your project + and the filters. This association is used in the IDE to show grouping of files with + similar extensions under a specific node (for e.g. ".cpp" files are associated with the + "Source Files" filter). + +http_rpc_client.cpp + This is the main application source file. + +///////////////////////////////////////////////////////////////////////////// +Other standard files: + +StdAfx.h, StdAfx.cpp + These files are used to build a precompiled header (PCH) file + named http_rpc_client.pch and a precompiled types file named StdAfx.obj. + +///////////////////////////////////////////////////////////////////////////// +Other notes: + +AppWizard uses "TODO:" comments to indicate parts of the source code you +should add to or customize. + +///////////////////////////////////////////////////////////////////////////// diff --git a/lib_rpc/samples/http_rpc_client/http_rpc_client.cpp b/lib_rpc/samples/http_rpc_client/http_rpc_client.cpp new file mode 100644 index 000000000..505d22944 --- /dev/null +++ b/lib_rpc/samples/http_rpc_client/http_rpc_client.cpp @@ -0,0 +1,177 @@ +// http_rpc_client.cpp : Defines the entry point for the console application. +// + +#include "stdafx.h" +#include "acl_cpp/acl_cpp_init.hpp" +#include "acl_cpp/stdlib/string.hpp" +#include "acl_cpp/http/http_request.hpp" +#include "google/protobuf/io/http_stream.h" + +#include "util.h" +#include "test.pb.h" + +using namespace google::protobuf::io; + +static double __request_spent, __response_spent, __build_spent, __parse_spent; + +static bool handle_one(http_request& rpc, bool output) +{ + ////////////////////////////////////////////////////////////////// + // 请求过程 + + static tutorial::AddressBook address; + size_t person_count = 5; + + address.Clear(); + + acl::string buf; + + // 给地址簿中添加用户列表 + for (size_t i = 0; i < person_count; i++) + { + tutorial::Person* person = address.add_person(); + buf.format("zsxxsz-%d", i); + person->set_name(buf.c_str()); + buf.format("zsxxsz-%d@test.com", i); + person->set_email(buf.c_str()); + person->set_id(i); + + // 给一个用户添加多个电话号码 + for (size_t j = 0; j < tutorial::Person::WORK; j++) + { + tutorial::Person::PhoneNumber* phone = person->add_phone(); + buf.format("11111111-%d-%d", i, j); + phone->set_number(buf.c_str()); + } + } + + ////////////////////////////////////////////////////////////////// + // 发送请求数据至服务端,并读取服务端的响应 + + static tutorial::AddressBook address_result; + address_result.Clear(); + + if (rpc.rpc_request(address, &address_result) == false) + { + printf("rpc_request error\r\n"); + return false; + } + + __request_spent += rpc.request_spent(); + __response_spent += rpc.response_spent(); + __build_spent += rpc.build_spent(); + __parse_spent += rpc.parse_spent(); + + ////////////////////////////////////////////////////////////////// + // 分析响应数据 + + // 列出地址簿中所有用户信息 + for (int i = 0; i < address_result.person_size(); i++) + { + const tutorial::Person& person = address_result.person(i); + if (output) + { + printf("person->name: %s\r\n", person.name().c_str()); + printf("person->id: %d\r\n", person.id()); + printf("person->email: %s\r\n", person.has_email() ? + person.email().c_str() : "null"); + } + + // 列出该用户的所有电话 + for (int j = 0; j < person.phone_size(); j++) + { + const tutorial::Person::PhoneNumber& phone = person.phone(j); + if (output) + printf("\tphone number: %s\r\n", phone.number().c_str()); + } + if (output) + printf("------------------------------------------\r\n"); + } + + return true; +} + +static void handle_rpc(const char* addr, int max) +{ + http_request rpc(addr); + + struct timeval begin; + gettimeofday(&begin, NULL); + + char buf[64]; + ACL_METER_TIME("begin run"); + for (int i = 0; i < max;) + { + if (handle_one(rpc, i >= 1 ? false : true) == false) + break; + if (++i % 1000 == 0) + { + snprintf(buf, sizeof(buf), "total count: %d, curr: %d", max, i); + ACL_METER_TIME(buf); + } + } + + struct timeval end; + gettimeofday(&end, NULL); + double n = util::stamp_sub(&end, &begin); + printf("total check: %d, spent: %0.2f ms, speed: %0.2f\r\n" + "total_build: %0.2f, total_parse: %0.2f, " + "total_request: %0.2f, total_reponse: %0.2f\r\n", + max, n, (max * 1000) /(n > 0 ? n : 1), + __build_spent, __parse_spent, + __request_spent, __response_spent); +} + +static void usage(const char* procname) +{ + printf("usage: %s -h [help] -s server_addr [127.0.0.1:8088] -n max_request\r\n", procname); +} + +int main(int argc, char* argv[]) +{ + if (1) + acl_mem_slice_init(8, 1024, 100000, + ACL_SLICE_FLAG_GC2 | + ACL_SLICE_FLAG_RTGC_OFF | + ACL_SLICE_FLAG_LP64_ALIGN); + +#ifdef WIN32 + acl::acl_cpp_init(); +#endif + + char addr[64]; + int ch, max = 1; + + snprintf(addr, sizeof(addr), "127.0.0.1:8088"); + + while ((ch = getopt(argc, argv, "hs:n:")) > 0) + { + switch (ch) + { + case 'h': + usage(argv[0]); + return 0; + case 's': + snprintf(addr, sizeof(addr), "%s", optarg); + break; + case 'n': + max = atoi(optarg); + if (max <= 0) + max = 1; + break; + default: + break; + } + } + + handle_rpc(addr, max); + + // Optional: Delete all global objects allocated by libprotobuf. + google::protobuf::ShutdownProtobufLibrary(); + +#ifdef WIN32 + printf("Enter any key to exit\r\n"); + getchar(); +#endif + return 0; +} diff --git a/lib_rpc/samples/http_rpc_client/http_rpc_client.vcxproj b/lib_rpc/samples/http_rpc_client/http_rpc_client.vcxproj new file mode 100644 index 000000000..66ab92a6e --- /dev/null +++ b/lib_rpc/samples/http_rpc_client/http_rpc_client.vcxproj @@ -0,0 +1,106 @@ +锘 + + + + Debug + Win32 + + + Release + Win32 + + + + {48ACE73F-73AD-43CC-99FB-35DFF71B8E9E} + Win32Proj + http_rpc_client + + + + Application + true + Unicode + + + Application + false + true + Unicode + + + + + + + + + + + + + true + $(Configuration)\ + + + false + $(Configuration)\ + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;_SCL_SECURE_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + ..\..\include;..\..\..\lib_acl_cpp\include;..\..\..\include;..;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + MultiThreadedDebug + + + Console + true + libprotobuf-lite-debug.lib;lib_rpc_vc2010d.lib;lib_acl_cpp_vc2010d.lib;lib_acl_vc2010d.lib;lib_protocol_vc2003d.lib;%(AdditionalDependencies) + ..\..\Debug;..\..\..\lib\protobuf\win32;..\..\..\dist\lib\win32 + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;_SCL_SECURE_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + ..\..\include;..\..\..\lib_acl_cpp\include;..\..\..\include;..;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + MultiThreaded + + + Console + true + true + true + ..\..\Release;..\..\..\lib\protobuf\win32;..\..\..\dist\lib\win32 + libprotobuf-lite.lib;lib_rpc_vc2010.lib;lib_acl_cpp_vc2010.lib;lib_acl_vc2010.lib;lib_protocol_vc2003.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + + + + Create + Create + + + + + + \ No newline at end of file diff --git a/lib_rpc/samples/http_rpc_client/http_rpc_client.vcxproj.filters b/lib_rpc/samples/http_rpc_client/http_rpc_client.vcxproj.filters new file mode 100644 index 000000000..9b5e0ae32 --- /dev/null +++ b/lib_rpc/samples/http_rpc_client/http_rpc_client.vcxproj.filters @@ -0,0 +1,49 @@ +锘 + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/lib_rpc/samples/http_rpc_client/http_rpc_client.vcxproj.user b/lib_rpc/samples/http_rpc_client/http_rpc_client.vcxproj.user new file mode 100644 index 000000000..ace9a86ac --- /dev/null +++ b/lib_rpc/samples/http_rpc_client/http_rpc_client.vcxproj.user @@ -0,0 +1,3 @@ +锘 + + \ No newline at end of file diff --git a/lib_rpc/samples/http_rpc_client/stdafx.cpp b/lib_rpc/samples/http_rpc_client/stdafx.cpp new file mode 100644 index 000000000..e80adfe59 --- /dev/null +++ b/lib_rpc/samples/http_rpc_client/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// http_rpc_client.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/lib_rpc/samples/http_rpc_client/stdafx.h b/lib_rpc/samples/http_rpc_client/stdafx.h new file mode 100644 index 000000000..3566e9bb9 --- /dev/null +++ b/lib_rpc/samples/http_rpc_client/stdafx.h @@ -0,0 +1,21 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#include "targetver.h" + +#include +//#include + + + +// TODO: reference additional headers your program requires here + +#include "lib_acl.h" + +#ifdef WIN32 +#define snprintf _snprintf +#endif diff --git a/lib_rpc/samples/http_rpc_client/targetver.h b/lib_rpc/samples/http_rpc_client/targetver.h new file mode 100644 index 000000000..a92219b0e --- /dev/null +++ b/lib_rpc/samples/http_rpc_client/targetver.h @@ -0,0 +1,10 @@ +#pragma once + +// Including SDKDDKVer.h defines the highest available Windows platform. + +// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and +// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. + +#ifdef WIN32 +#include +#endif diff --git a/lib_rpc/samples/http_rpc_server/Makefile b/lib_rpc/samples/http_rpc_server/Makefile new file mode 100644 index 000000000..a503a5a1d --- /dev/null +++ b/lib_rpc/samples/http_rpc_server/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = http_rpc_server diff --git a/lib_rpc/samples/http_rpc_server/ReadMe.txt b/lib_rpc/samples/http_rpc_server/ReadMe.txt new file mode 100644 index 000000000..fc86d0149 --- /dev/null +++ b/lib_rpc/samples/http_rpc_server/ReadMe.txt @@ -0,0 +1,40 @@ +======================================================================== + CONSOLE APPLICATION : http_rpc_server Project Overview +======================================================================== + +AppWizard has created this http_rpc_server application for you. + +This file contains a summary of what you will find in each of the files that +make up your http_rpc_server application. + + +http_rpc_server.vcxproj + This is the main project file for VC++ projects generated using an Application Wizard. + It contains information about the version of Visual C++ that generated the file, and + information about the platforms, configurations, and project features selected with the + Application Wizard. + +http_rpc_server.vcxproj.filters + This is the filters file for VC++ projects generated using an Application Wizard. + It contains information about the association between the files in your project + and the filters. This association is used in the IDE to show grouping of files with + similar extensions under a specific node (for e.g. ".cpp" files are associated with the + "Source Files" filter). + +http_rpc_server.cpp + This is the main application source file. + +///////////////////////////////////////////////////////////////////////////// +Other standard files: + +StdAfx.h, StdAfx.cpp + These files are used to build a precompiled header (PCH) file + named http_rpc_server.pch and a precompiled types file named StdAfx.obj. + +///////////////////////////////////////////////////////////////////////////// +Other notes: + +AppWizard uses "TODO:" comments to indicate parts of the source code you +should add to or customize. + +///////////////////////////////////////////////////////////////////////////// diff --git a/lib_rpc/samples/http_rpc_server/http_rpc_server.cpp b/lib_rpc/samples/http_rpc_server/http_rpc_server.cpp new file mode 100644 index 000000000..fc6dae148 --- /dev/null +++ b/lib_rpc/samples/http_rpc_server/http_rpc_server.cpp @@ -0,0 +1,154 @@ +// http_rpc_server.cpp : Defines the entry point for the console application. +// + +#include "stdafx.h" +#include "acl_cpp/stdlib/string.hpp" +#include "acl_cpp/http/http_request.hpp" +#include "acl_cpp/acl_cpp_init.hpp" +#include "acl_cpp/stream/socket_stream.hpp" +#include "google/protobuf/io/http_stream.h" +#include "lib_acl.h" +#include "test.pb.h" + +using namespace google::protobuf::io; + +static double __header_spent, __body_spent, __parse_spent, __build_spent, __response_spent; + +static bool handle_one(http_response& response, bool output) +{ + tutorial::AddressBook addr_req; + if (response.read_request(&addr_req) == false) + return false; + + tutorial::AddressBook addr_res; + + for (int i = 0; i < addr_req.person_size(); i++) + { + const tutorial::Person& person = addr_req.person(i); + if (output) + { + printf("person->name: %s\r\n", person.name().c_str()); + printf("person->id: %d\r\n", person.id()); + printf("person->email: %s\r\n", person.has_email() ? + person.email().c_str() : "null"); + } + + tutorial::Person* person2 = addr_res.add_person(); + person2->set_name(person.name().c_str()); + person2->set_email(person.has_email() ? + person.email().c_str() : "null"); + person2->set_id(i); + + // 列出该用户的所有电话 + for (int j = 0; j < person.phone_size(); j++) + { + const tutorial::Person::PhoneNumber& phone = person.phone(j); + if (output) + printf("\tphone number: %s\r\n", phone.number().c_str()); + + tutorial::Person::PhoneNumber* phone2 = person2->add_phone(); + phone2->set_number(phone.number().c_str()); + } + if (output) + printf("------------------------------------------\r\n"); + } + + return response.send_response(addr_res); +} + +static void handle_client(ACL_VSTREAM* conn) +{ + acl::socket_stream client; + (void) client.open(conn); + + acl::http_response res(&client); + http_response response(&res); + + int i = 0; + + __header_spent = 0; + __body_spent = 0; + __parse_spent = 0; + __build_spent = 0; + __response_spent = 0; + + char buf[64]; + ACL_METER_TIME("begin run"); + while (true) + { + if (handle_one(response, i > 1 ? false : true) == false) + break; + + __header_spent += response.header_spent(); + __body_spent += response.body_spent(); + __parse_spent += response.parse_spent(); + __build_spent += response.build_spent(); + __response_spent += response.response_spent(); + + if (++i % 1000 == 0) + { + snprintf(buf, sizeof(buf), "total: %d", i); + ACL_METER_TIME(buf); + } + } + + printf("total count: %d, header_spent: %0.2f, body_spent: %0.2f, " + "parse_spent: %0.2f, build_spent: %0.2f, response_spent: %0.2f\r\n", + i, __header_spent, __body_spent, __parse_spent, + __build_spent, __response_spent); +} + +static void usage(const char* procname) +{ + printf("usage: %s -h [help] -s listen_addr [127.0.0.1:8088]\r\n", procname); +} + +int main(int argc, char* argv[]) +{ + if (1) + acl_mem_slice_init(8, 1024, 100000, + ACL_SLICE_FLAG_GC2 | + ACL_SLICE_FLAG_RTGC_OFF | + ACL_SLICE_FLAG_LP64_ALIGN); + +#ifdef WIN32 + acl::acl_cpp_init(); +#endif + char addr[64]; + int ch; + + snprintf(addr, sizeof(addr), "127.0.0.1:8088"); + + while ((ch = getopt(argc, argv, "hs:")) > 0) + { + switch (ch) + { + case 'h': + usage(argv[0]); + return 0; + case 's': + snprintf(addr, sizeof(addr), "%s", optarg); + break; + default: + break; + } + } + + ACL_VSTREAM* listener = acl_vstream_listen(addr, 128); + if (listener == NULL) + { + printf("can't listen on %s\r\n", addr); + return 1; + } + + printf("listen on: %s ok\r\n", addr); + + while(true) + { + ACL_VSTREAM* conn = acl_vstream_accept(listener, NULL, 0); + if (conn == NULL) + break; + handle_client(conn); + } + return 0; +} diff --git a/lib_rpc/samples/http_rpc_server/http_rpc_server.vcxproj b/lib_rpc/samples/http_rpc_server/http_rpc_server.vcxproj new file mode 100644 index 000000000..f8f25d97e --- /dev/null +++ b/lib_rpc/samples/http_rpc_server/http_rpc_server.vcxproj @@ -0,0 +1,104 @@ +锘 + + + + Debug + Win32 + + + Release + Win32 + + + + {8D69EA4C-C980-4168-85B6-BAC9CB99E0DC} + Win32Proj + http_rpc_server + + + + Application + true + Unicode + + + Application + false + true + Unicode + + + + + + + + + + + + + true + $(Configuration)\ + + + false + $(Configuration)\ + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;_SCL_SECURE_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + ..\..\include;..\..\..\lib_acl_cpp\include;..\..\..\include;..\..\..\lib_acl\include;..;%(AdditionalIncludeDirectories) + MultiThreadedDebug + + + Console + true + ..\..\Debug;..\..\..\lib\protobuf\win32;..\..\..\dist\lib\win32 + libprotobuf-lite-debug.lib;lib_rpc_vc2010d.lib;lib_acl_cpp_vc2010d.lib;lib_acl_vc2010d.lib;lib_protocol_vc2003d.lib;%(AdditionalDependencies) + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;_SCL_SECURE_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + ..\..\include;..\..\..\lib_acl_cpp\include;..\..\..\include;..\..\..\lib_acl\include;..;%(AdditionalIncludeDirectories) + + + Console + true + true + true + libprotobuf-lite.lib;lib_rpc_vc2010.lib;lib_acl_cpp_vc2010.lib;lib_acl_vc2010.lib;lib_protocol_vc2003.lib;%(AdditionalDependencies) + ..\..\Release;..\..\..\lib\protobuf\win32;..\..\..\dist\lib\win32 + + + + + + + + + + + + + + + + Create + Create + + + + + + \ No newline at end of file diff --git a/lib_rpc/samples/http_rpc_server/http_rpc_server.vcxproj.filters b/lib_rpc/samples/http_rpc_server/http_rpc_server.vcxproj.filters new file mode 100644 index 000000000..6014173e4 --- /dev/null +++ b/lib_rpc/samples/http_rpc_server/http_rpc_server.vcxproj.filters @@ -0,0 +1,43 @@ +锘 + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + + + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/lib_rpc/samples/http_rpc_server/http_rpc_server.vcxproj.user b/lib_rpc/samples/http_rpc_server/http_rpc_server.vcxproj.user new file mode 100644 index 000000000..ace9a86ac --- /dev/null +++ b/lib_rpc/samples/http_rpc_server/http_rpc_server.vcxproj.user @@ -0,0 +1,3 @@ +锘 + + \ No newline at end of file diff --git a/lib_rpc/samples/http_rpc_server/stdafx.cpp b/lib_rpc/samples/http_rpc_server/stdafx.cpp new file mode 100644 index 000000000..d26e71cf2 --- /dev/null +++ b/lib_rpc/samples/http_rpc_server/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// http_rpc_server.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/lib_rpc/samples/http_rpc_server/stdafx.h b/lib_rpc/samples/http_rpc_server/stdafx.h new file mode 100644 index 000000000..3566e9bb9 --- /dev/null +++ b/lib_rpc/samples/http_rpc_server/stdafx.h @@ -0,0 +1,21 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#include "targetver.h" + +#include +//#include + + + +// TODO: reference additional headers your program requires here + +#include "lib_acl.h" + +#ifdef WIN32 +#define snprintf _snprintf +#endif diff --git a/lib_rpc/samples/http_rpc_server/targetver.h b/lib_rpc/samples/http_rpc_server/targetver.h new file mode 100644 index 000000000..a92219b0e --- /dev/null +++ b/lib_rpc/samples/http_rpc_server/targetver.h @@ -0,0 +1,10 @@ +#pragma once + +// Including SDKDDKVer.h defines the highest available Windows platform. + +// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and +// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. + +#ifdef WIN32 +#include +#endif diff --git a/lib_rpc/samples/test.pb.cpp b/lib_rpc/samples/test.pb.cpp new file mode 100644 index 000000000..ee1a195b2 --- /dev/null +++ b/lib_rpc/samples/test.pb.cpp @@ -0,0 +1,743 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: test.proto +#include "stdafx.h" +#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION +#include "test.pb.h" + +#include + +#include +#include +#include +#include +// @@protoc_insertion_point(includes) + +namespace tutorial { + +void protobuf_ShutdownFile_test_2eproto() { + delete Person::default_instance_; + delete Person_PhoneNumber::default_instance_; + delete AddressBook::default_instance_; +} + +#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER +void protobuf_AddDesc_test_2eproto_impl() { + GOOGLE_PROTOBUF_VERIFY_VERSION; + +#else +void protobuf_AddDesc_test_2eproto() { + static bool already_here = false; + if (already_here) return; + already_here = true; + GOOGLE_PROTOBUF_VERIFY_VERSION; + +#endif + Person::default_instance_ = new Person(); + Person_PhoneNumber::default_instance_ = new Person_PhoneNumber(); + AddressBook::default_instance_ = new AddressBook(); + Person::default_instance_->InitAsDefaultInstance(); + Person_PhoneNumber::default_instance_->InitAsDefaultInstance(); + AddressBook::default_instance_->InitAsDefaultInstance(); + ::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_test_2eproto); +} + +#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER +GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AddDesc_test_2eproto_once_); +void protobuf_AddDesc_test_2eproto() { + ::google::protobuf::::google::protobuf::GoogleOnceInit(&protobuf_AddDesc_test_2eproto_once_, + &protobuf_AddDesc_test_2eproto_impl); +} +#else +// Force AddDescriptors() to be called at static initialization time. +struct StaticDescriptorInitializer_test_2eproto { + StaticDescriptorInitializer_test_2eproto() { + protobuf_AddDesc_test_2eproto(); + } +} static_descriptor_initializer_test_2eproto_; +#endif + +// =================================================================== + +bool Person_PhoneType_IsValid(int value) { + switch(value) { + case 0: + case 1: + case 2: + return true; + default: + return false; + } +} + +#ifndef _MSC_VER +const Person_PhoneType Person::MOBILE; +const Person_PhoneType Person::HOME; +const Person_PhoneType Person::WORK; +const Person_PhoneType Person::PhoneType_MIN; +const Person_PhoneType Person::PhoneType_MAX; +const int Person::PhoneType_ARRAYSIZE; +#endif // _MSC_VER +#ifndef _MSC_VER +const int Person_PhoneNumber::kNumberFieldNumber; +const int Person_PhoneNumber::kTypeFieldNumber; +#endif // !_MSC_VER + +Person_PhoneNumber::Person_PhoneNumber() + : ::google::protobuf::MessageLite() { + SharedCtor(); +} + +void Person_PhoneNumber::InitAsDefaultInstance() { +} + +Person_PhoneNumber::Person_PhoneNumber(const Person_PhoneNumber& from) + : ::google::protobuf::MessageLite() { + SharedCtor(); + MergeFrom(from); +} + +void Person_PhoneNumber::SharedCtor() { + _cached_size_ = 0; + number_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + type_ = 1; + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + +Person_PhoneNumber::~Person_PhoneNumber() { + SharedDtor(); +} + +void Person_PhoneNumber::SharedDtor() { + if (number_ != &::google::protobuf::internal::kEmptyString) { + delete number_; + } + #ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER + if (this != &default_instance()) { + #else + if (this != default_instance_) { + #endif + } +} + +void Person_PhoneNumber::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} +const Person_PhoneNumber& Person_PhoneNumber::default_instance() { +#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER + protobuf_AddDesc_test_2eproto(); +#else + if (default_instance_ == NULL) protobuf_AddDesc_test_2eproto(); +#endif + return *default_instance_; +} + +Person_PhoneNumber* Person_PhoneNumber::default_instance_ = NULL; + +Person_PhoneNumber* Person_PhoneNumber::New() const { + return new Person_PhoneNumber; +} + +void Person_PhoneNumber::Clear() { + if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { + if (has_number()) { + if (number_ != &::google::protobuf::internal::kEmptyString) { + number_->clear(); + } + } + type_ = 1; + } + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + +bool Person_PhoneNumber::MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input) { +#define DO_(EXPRESSION) if (!(EXPRESSION)) return false + ::google::protobuf::uint32 tag; + while ((tag = input->ReadTag()) != 0) { + switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { + // required string number = 1; + case 1: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_number())); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(16)) goto parse_type; + break; + } + + // optional .tutorial.Person.PhoneType type = 2 [default = HOME]; + case 2: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_type: + int value; + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>( + input, &value))); + if (::tutorial::Person_PhoneType_IsValid(value)) { + set_type(static_cast< ::tutorial::Person_PhoneType >(value)); + } + } else { + goto handle_uninterpreted; + } + if (input->ExpectAtEnd()) return true; + break; + } + + default: { + handle_uninterpreted: + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { + return true; + } + DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag)); + break; + } + } + } + return true; +#undef DO_ +} + +void Person_PhoneNumber::SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const { + // required string number = 1; + if (has_number()) { + ::google::protobuf::internal::WireFormatLite::WriteString( + 1, this->number(), output); + } + + // optional .tutorial.Person.PhoneType type = 2 [default = HOME]; + if (has_type()) { + ::google::protobuf::internal::WireFormatLite::WriteEnum( + 2, this->type(), output); + } + +} + +int Person_PhoneNumber::ByteSize() const { + int total_size = 0; + + if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { + // required string number = 1; + if (has_number()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::StringSize( + this->number()); + } + + // optional .tutorial.Person.PhoneType type = 2 [default = HOME]; + if (has_type()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::EnumSize(this->type()); + } + + } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); + return total_size; +} + +void Person_PhoneNumber::CheckTypeAndMergeFrom( + const ::google::protobuf::MessageLite& from) { + MergeFrom(*::google::protobuf::down_cast(&from)); +} + +void Person_PhoneNumber::MergeFrom(const Person_PhoneNumber& from) { + GOOGLE_CHECK_NE(&from, this); + if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { + if (from.has_number()) { + set_number(from.number()); + } + if (from.has_type()) { + set_type(from.type()); + } + } +} + +void Person_PhoneNumber::CopyFrom(const Person_PhoneNumber& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool Person_PhoneNumber::IsInitialized() const { + if ((_has_bits_[0] & 0x00000001) != 0x00000001) return false; + + return true; +} + +void Person_PhoneNumber::Swap(Person_PhoneNumber* other) { + if (other != this) { + std::swap(number_, other->number_); + std::swap(type_, other->type_); + std::swap(_has_bits_[0], other->_has_bits_[0]); + std::swap(_cached_size_, other->_cached_size_); + } +} + +::std::string Person_PhoneNumber::GetTypeName() const { + return "tutorial.Person.PhoneNumber"; +} + + +// ------------------------------------------------------------------- + +#ifndef _MSC_VER +const int Person::kNameFieldNumber; +const int Person::kIdFieldNumber; +const int Person::kEmailFieldNumber; +const int Person::kPhoneFieldNumber; +#endif // !_MSC_VER + +Person::Person() + : ::google::protobuf::MessageLite() { + SharedCtor(); +} + +void Person::InitAsDefaultInstance() { +} + +Person::Person(const Person& from) + : ::google::protobuf::MessageLite() { + SharedCtor(); + MergeFrom(from); +} + +void Person::SharedCtor() { + _cached_size_ = 0; + name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + id_ = 0; + email_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + +Person::~Person() { + SharedDtor(); +} + +void Person::SharedDtor() { + if (name_ != &::google::protobuf::internal::kEmptyString) { + delete name_; + } + if (email_ != &::google::protobuf::internal::kEmptyString) { + delete email_; + } + #ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER + if (this != &default_instance()) { + #else + if (this != default_instance_) { + #endif + } +} + +void Person::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} +const Person& Person::default_instance() { +#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER + protobuf_AddDesc_test_2eproto(); +#else + if (default_instance_ == NULL) protobuf_AddDesc_test_2eproto(); +#endif + return *default_instance_; +} + +Person* Person::default_instance_ = NULL; + +Person* Person::New() const { + return new Person; +} + +void Person::Clear() { + if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { + if (has_name()) { + if (name_ != &::google::protobuf::internal::kEmptyString) { + name_->clear(); + } + } + id_ = 0; + if (has_email()) { + if (email_ != &::google::protobuf::internal::kEmptyString) { + email_->clear(); + } + } + } + phone_.Clear(); + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + +bool Person::MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input) { +#define DO_(EXPRESSION) if (!(EXPRESSION)) return false + ::google::protobuf::uint32 tag; + while ((tag = input->ReadTag()) != 0) { + switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { + // required string name = 1; + case 1: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_name())); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(16)) goto parse_id; + break; + } + + // required int32 id = 2; + case 2: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_id: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>( + input, &id_))); + set_has_id(); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(26)) goto parse_email; + break; + } + + // optional string email = 3; + case 3: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_email: + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_email())); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(34)) goto parse_phone; + break; + } + + // repeated .tutorial.Person.PhoneNumber phone = 4; + case 4: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_phone: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_phone())); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(34)) goto parse_phone; + if (input->ExpectAtEnd()) return true; + break; + } + + default: { + handle_uninterpreted: + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { + return true; + } + DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag)); + break; + } + } + } + return true; +#undef DO_ +} + +void Person::SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const { + // required string name = 1; + if (has_name()) { + ::google::protobuf::internal::WireFormatLite::WriteString( + 1, this->name(), output); + } + + // required int32 id = 2; + if (has_id()) { + ::google::protobuf::internal::WireFormatLite::WriteInt32(2, this->id(), output); + } + + // optional string email = 3; + if (has_email()) { + ::google::protobuf::internal::WireFormatLite::WriteString( + 3, this->email(), output); + } + + // repeated .tutorial.Person.PhoneNumber phone = 4; + for (int i = 0; i < this->phone_size(); i++) { + ::google::protobuf::internal::WireFormatLite::WriteMessage( + 4, this->phone(i), output); + } + +} + +int Person::ByteSize() const { + int total_size = 0; + + if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { + // required string name = 1; + if (has_name()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::StringSize( + this->name()); + } + + // required int32 id = 2; + if (has_id()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::Int32Size( + this->id()); + } + + // optional string email = 3; + if (has_email()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::StringSize( + this->email()); + } + + } + // repeated .tutorial.Person.PhoneNumber phone = 4; + total_size += 1 * this->phone_size(); + for (int i = 0; i < this->phone_size(); i++) { + total_size += + ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( + this->phone(i)); + } + + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); + return total_size; +} + +void Person::CheckTypeAndMergeFrom( + const ::google::protobuf::MessageLite& from) { + MergeFrom(*::google::protobuf::down_cast(&from)); +} + +void Person::MergeFrom(const Person& from) { + GOOGLE_CHECK_NE(&from, this); + phone_.MergeFrom(from.phone_); + if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { + if (from.has_name()) { + set_name(from.name()); + } + if (from.has_id()) { + set_id(from.id()); + } + if (from.has_email()) { + set_email(from.email()); + } + } +} + +void Person::CopyFrom(const Person& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool Person::IsInitialized() const { + if ((_has_bits_[0] & 0x00000003) != 0x00000003) return false; + + for (int i = 0; i < phone_size(); i++) { + if (!this->phone(i).IsInitialized()) return false; + } + return true; +} + +void Person::Swap(Person* other) { + if (other != this) { + std::swap(name_, other->name_); + std::swap(id_, other->id_); + std::swap(email_, other->email_); + phone_.Swap(&other->phone_); + std::swap(_has_bits_[0], other->_has_bits_[0]); + std::swap(_cached_size_, other->_cached_size_); + } +} + +::std::string Person::GetTypeName() const { + return "tutorial.Person"; +} + + +// =================================================================== + +#ifndef _MSC_VER +const int AddressBook::kPersonFieldNumber; +#endif // !_MSC_VER + +AddressBook::AddressBook() + : ::google::protobuf::MessageLite() { + SharedCtor(); +} + +void AddressBook::InitAsDefaultInstance() { +} + +AddressBook::AddressBook(const AddressBook& from) + : ::google::protobuf::MessageLite() { + SharedCtor(); + MergeFrom(from); +} + +void AddressBook::SharedCtor() { + _cached_size_ = 0; + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + +AddressBook::~AddressBook() { + SharedDtor(); +} + +void AddressBook::SharedDtor() { + #ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER + if (this != &default_instance()) { + #else + if (this != default_instance_) { + #endif + } +} + +void AddressBook::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} +const AddressBook& AddressBook::default_instance() { +#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER + protobuf_AddDesc_test_2eproto(); +#else + if (default_instance_ == NULL) protobuf_AddDesc_test_2eproto(); +#endif + return *default_instance_; +} + +AddressBook* AddressBook::default_instance_ = NULL; + +AddressBook* AddressBook::New() const { + return new AddressBook; +} + +void AddressBook::Clear() { + person_.Clear(); + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + +bool AddressBook::MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input) { +#define DO_(EXPRESSION) if (!(EXPRESSION)) return false + ::google::protobuf::uint32 tag; + while ((tag = input->ReadTag()) != 0) { + switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { + // repeated .tutorial.Person person = 1; + case 1: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_person: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_person())); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(10)) goto parse_person; + if (input->ExpectAtEnd()) return true; + break; + } + + default: { + handle_uninterpreted: + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { + return true; + } + DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag)); + break; + } + } + } + return true; +#undef DO_ +} + +void AddressBook::SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const { + // repeated .tutorial.Person person = 1; + for (int i = 0; i < this->person_size(); i++) { + ::google::protobuf::internal::WireFormatLite::WriteMessage( + 1, this->person(i), output); + } + +} + +int AddressBook::ByteSize() const { + int total_size = 0; + + // repeated .tutorial.Person person = 1; + total_size += 1 * this->person_size(); + for (int i = 0; i < this->person_size(); i++) { + total_size += + ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( + this->person(i)); + } + + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); + return total_size; +} + +void AddressBook::CheckTypeAndMergeFrom( + const ::google::protobuf::MessageLite& from) { + MergeFrom(*::google::protobuf::down_cast(&from)); +} + +void AddressBook::MergeFrom(const AddressBook& from) { + GOOGLE_CHECK_NE(&from, this); + person_.MergeFrom(from.person_); +} + +void AddressBook::CopyFrom(const AddressBook& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool AddressBook::IsInitialized() const { + + for (int i = 0; i < person_size(); i++) { + if (!this->person(i).IsInitialized()) return false; + } + return true; +} + +void AddressBook::Swap(AddressBook* other) { + if (other != this) { + person_.Swap(&other->person_); + std::swap(_has_bits_[0], other->_has_bits_[0]); + std::swap(_cached_size_, other->_cached_size_); + } +} + +::std::string AddressBook::GetTypeName() const { + return "tutorial.AddressBook"; +} + + +// @@protoc_insertion_point(namespace_scope) + +} // namespace tutorial + +// @@protoc_insertion_point(global_scope) diff --git a/lib_rpc/samples/test.pb.h b/lib_rpc/samples/test.pb.h new file mode 100644 index 000000000..87e34f0d6 --- /dev/null +++ b/lib_rpc/samples/test.pb.h @@ -0,0 +1,702 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: test.proto + +#ifndef PROTOBUF_test_2eproto__INCLUDED +#define PROTOBUF_test_2eproto__INCLUDED + +#include + +#include + +#if GOOGLE_PROTOBUF_VERSION < 2005000 +#error This file was generated by a newer version of protoc which is +#error incompatible with your Protocol Buffer headers. Please update +#error your headers. +#endif +#if 2005000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION +#error This file was generated by an older version of protoc which is +#error incompatible with your Protocol Buffer headers. Please +#error regenerate this file with a newer version of protoc. +#endif + +#include +#include +#include +#include +// @@protoc_insertion_point(includes) + +namespace tutorial { + +// Internal implementation detail -- do not call these. +void protobuf_AddDesc_test_2eproto(); +void protobuf_AssignDesc_test_2eproto(); +void protobuf_ShutdownFile_test_2eproto(); + +class Person; +class Person_PhoneNumber; +class AddressBook; + +enum Person_PhoneType { + Person_PhoneType_MOBILE = 0, + Person_PhoneType_HOME = 1, + Person_PhoneType_WORK = 2 +}; +bool Person_PhoneType_IsValid(int value); +const Person_PhoneType Person_PhoneType_PhoneType_MIN = Person_PhoneType_MOBILE; +const Person_PhoneType Person_PhoneType_PhoneType_MAX = Person_PhoneType_WORK; +const int Person_PhoneType_PhoneType_ARRAYSIZE = Person_PhoneType_PhoneType_MAX + 1; + +// =================================================================== + +class Person_PhoneNumber : public ::google::protobuf::MessageLite { + public: + Person_PhoneNumber(); + virtual ~Person_PhoneNumber(); + + Person_PhoneNumber(const Person_PhoneNumber& from); + + inline Person_PhoneNumber& operator=(const Person_PhoneNumber& from) { + CopyFrom(from); + return *this; + } + + static const Person_PhoneNumber& default_instance(); + + #ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER + // Returns the internal default instance pointer. This function can + // return NULL thus should not be used by the user. This is intended + // for Protobuf internal code. Please use default_instance() declared + // above instead. + static inline const Person_PhoneNumber* internal_default_instance() { + return default_instance_; + } + #endif + + void Swap(Person_PhoneNumber* other); + + // implements Message ---------------------------------------------- + + Person_PhoneNumber* New() const; + void CheckTypeAndMergeFrom(const ::google::protobuf::MessageLite& from); + void CopyFrom(const Person_PhoneNumber& from); + void MergeFrom(const Person_PhoneNumber& from); + void Clear(); + bool IsInitialized() const; + + int ByteSize() const; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input); + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const; + int GetCachedSize() const { return _cached_size_; } + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + public: + + ::std::string GetTypeName() const; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + // required string number = 1; + inline bool has_number() const; + inline void clear_number(); + static const int kNumberFieldNumber = 1; + inline const ::std::string& number() const; + inline void set_number(const ::std::string& value); + inline void set_number(const char* value); + inline void set_number(const char* value, size_t size); + inline ::std::string* mutable_number(); + inline ::std::string* release_number(); + inline void set_allocated_number(::std::string* number); + + // optional .tutorial.Person.PhoneType type = 2 [default = HOME]; + inline bool has_type() const; + inline void clear_type(); + static const int kTypeFieldNumber = 2; + inline ::tutorial::Person_PhoneType type() const; + inline void set_type(::tutorial::Person_PhoneType value); + + // @@protoc_insertion_point(class_scope:tutorial.Person.PhoneNumber) + private: + inline void set_has_number(); + inline void clear_has_number(); + inline void set_has_type(); + inline void clear_has_type(); + + ::std::string* number_; + int type_; + + mutable int _cached_size_; + ::google::protobuf::uint32 _has_bits_[(2 + 31) / 32]; + + #ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER + friend void protobuf_AddDesc_test_2eproto_impl(); + #else + friend void protobuf_AddDesc_test_2eproto(); + #endif + friend void protobuf_AssignDesc_test_2eproto(); + friend void protobuf_ShutdownFile_test_2eproto(); + + void InitAsDefaultInstance(); + static Person_PhoneNumber* default_instance_; +}; +// ------------------------------------------------------------------- + +class Person : public ::google::protobuf::MessageLite { + public: + Person(); + virtual ~Person(); + + Person(const Person& from); + + inline Person& operator=(const Person& from) { + CopyFrom(from); + return *this; + } + + static const Person& default_instance(); + + #ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER + // Returns the internal default instance pointer. This function can + // return NULL thus should not be used by the user. This is intended + // for Protobuf internal code. Please use default_instance() declared + // above instead. + static inline const Person* internal_default_instance() { + return default_instance_; + } + #endif + + void Swap(Person* other); + + // implements Message ---------------------------------------------- + + Person* New() const; + void CheckTypeAndMergeFrom(const ::google::protobuf::MessageLite& from); + void CopyFrom(const Person& from); + void MergeFrom(const Person& from); + void Clear(); + bool IsInitialized() const; + + int ByteSize() const; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input); + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const; + int GetCachedSize() const { return _cached_size_; } + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + public: + + ::std::string GetTypeName() const; + + // nested types ---------------------------------------------------- + + typedef Person_PhoneNumber PhoneNumber; + + typedef Person_PhoneType PhoneType; + static const PhoneType MOBILE = Person_PhoneType_MOBILE; + static const PhoneType HOME = Person_PhoneType_HOME; + static const PhoneType WORK = Person_PhoneType_WORK; + static inline bool PhoneType_IsValid(int value) { + return Person_PhoneType_IsValid(value); + } + static const PhoneType PhoneType_MIN = + Person_PhoneType_PhoneType_MIN; + static const PhoneType PhoneType_MAX = + Person_PhoneType_PhoneType_MAX; + static const int PhoneType_ARRAYSIZE = + Person_PhoneType_PhoneType_ARRAYSIZE; + + // accessors ------------------------------------------------------- + + // required string name = 1; + inline bool has_name() const; + inline void clear_name(); + static const int kNameFieldNumber = 1; + inline const ::std::string& name() const; + inline void set_name(const ::std::string& value); + inline void set_name(const char* value); + inline void set_name(const char* value, size_t size); + inline ::std::string* mutable_name(); + inline ::std::string* release_name(); + inline void set_allocated_name(::std::string* name); + + // required int32 id = 2; + inline bool has_id() const; + inline void clear_id(); + static const int kIdFieldNumber = 2; + inline ::google::protobuf::int32 id() const; + inline void set_id(::google::protobuf::int32 value); + + // optional string email = 3; + inline bool has_email() const; + inline void clear_email(); + static const int kEmailFieldNumber = 3; + inline const ::std::string& email() const; + inline void set_email(const ::std::string& value); + inline void set_email(const char* value); + inline void set_email(const char* value, size_t size); + inline ::std::string* mutable_email(); + inline ::std::string* release_email(); + inline void set_allocated_email(::std::string* email); + + // repeated .tutorial.Person.PhoneNumber phone = 4; + inline int phone_size() const; + inline void clear_phone(); + static const int kPhoneFieldNumber = 4; + inline const ::tutorial::Person_PhoneNumber& phone(int index) const; + inline ::tutorial::Person_PhoneNumber* mutable_phone(int index); + inline ::tutorial::Person_PhoneNumber* add_phone(); + inline const ::google::protobuf::RepeatedPtrField< ::tutorial::Person_PhoneNumber >& + phone() const; + inline ::google::protobuf::RepeatedPtrField< ::tutorial::Person_PhoneNumber >* + mutable_phone(); + + // @@protoc_insertion_point(class_scope:tutorial.Person) + private: + inline void set_has_name(); + inline void clear_has_name(); + inline void set_has_id(); + inline void clear_has_id(); + inline void set_has_email(); + inline void clear_has_email(); + + ::std::string* name_; + ::std::string* email_; + ::google::protobuf::RepeatedPtrField< ::tutorial::Person_PhoneNumber > phone_; + ::google::protobuf::int32 id_; + + mutable int _cached_size_; + ::google::protobuf::uint32 _has_bits_[(4 + 31) / 32]; + + #ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER + friend void protobuf_AddDesc_test_2eproto_impl(); + #else + friend void protobuf_AddDesc_test_2eproto(); + #endif + friend void protobuf_AssignDesc_test_2eproto(); + friend void protobuf_ShutdownFile_test_2eproto(); + + void InitAsDefaultInstance(); + static Person* default_instance_; +}; +// ------------------------------------------------------------------- + +class AddressBook : public ::google::protobuf::MessageLite { + public: + AddressBook(); + virtual ~AddressBook(); + + AddressBook(const AddressBook& from); + + inline AddressBook& operator=(const AddressBook& from) { + CopyFrom(from); + return *this; + } + + static const AddressBook& default_instance(); + + #ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER + // Returns the internal default instance pointer. This function can + // return NULL thus should not be used by the user. This is intended + // for Protobuf internal code. Please use default_instance() declared + // above instead. + static inline const AddressBook* internal_default_instance() { + return default_instance_; + } + #endif + + void Swap(AddressBook* other); + + // implements Message ---------------------------------------------- + + AddressBook* New() const; + void CheckTypeAndMergeFrom(const ::google::protobuf::MessageLite& from); + void CopyFrom(const AddressBook& from); + void MergeFrom(const AddressBook& from); + void Clear(); + bool IsInitialized() const; + + int ByteSize() const; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input); + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const; + int GetCachedSize() const { return _cached_size_; } + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + public: + + ::std::string GetTypeName() const; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + // repeated .tutorial.Person person = 1; + inline int person_size() const; + inline void clear_person(); + static const int kPersonFieldNumber = 1; + inline const ::tutorial::Person& person(int index) const; + inline ::tutorial::Person* mutable_person(int index); + inline ::tutorial::Person* add_person(); + inline const ::google::protobuf::RepeatedPtrField< ::tutorial::Person >& + person() const; + inline ::google::protobuf::RepeatedPtrField< ::tutorial::Person >* + mutable_person(); + + // @@protoc_insertion_point(class_scope:tutorial.AddressBook) + private: + + ::google::protobuf::RepeatedPtrField< ::tutorial::Person > person_; + + mutable int _cached_size_; + ::google::protobuf::uint32 _has_bits_[(1 + 31) / 32]; + + #ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER + friend void protobuf_AddDesc_test_2eproto_impl(); + #else + friend void protobuf_AddDesc_test_2eproto(); + #endif + friend void protobuf_AssignDesc_test_2eproto(); + friend void protobuf_ShutdownFile_test_2eproto(); + + void InitAsDefaultInstance(); + static AddressBook* default_instance_; +}; +// =================================================================== + + +// =================================================================== + +// Person_PhoneNumber + +// required string number = 1; +inline bool Person_PhoneNumber::has_number() const { + return (_has_bits_[0] & 0x00000001u) != 0; +} +inline void Person_PhoneNumber::set_has_number() { + _has_bits_[0] |= 0x00000001u; +} +inline void Person_PhoneNumber::clear_has_number() { + _has_bits_[0] &= ~0x00000001u; +} +inline void Person_PhoneNumber::clear_number() { + if (number_ != &::google::protobuf::internal::kEmptyString) { + number_->clear(); + } + clear_has_number(); +} +inline const ::std::string& Person_PhoneNumber::number() const { + return *number_; +} +inline void Person_PhoneNumber::set_number(const ::std::string& value) { + set_has_number(); + if (number_ == &::google::protobuf::internal::kEmptyString) { + number_ = new ::std::string; + } + number_->assign(value); +} +inline void Person_PhoneNumber::set_number(const char* value) { + set_has_number(); + if (number_ == &::google::protobuf::internal::kEmptyString) { + number_ = new ::std::string; + } + number_->assign(value); +} +inline void Person_PhoneNumber::set_number(const char* value, size_t size) { + set_has_number(); + if (number_ == &::google::protobuf::internal::kEmptyString) { + number_ = new ::std::string; + } + number_->assign(reinterpret_cast(value), size); +} +inline ::std::string* Person_PhoneNumber::mutable_number() { + set_has_number(); + if (number_ == &::google::protobuf::internal::kEmptyString) { + number_ = new ::std::string; + } + return number_; +} +inline ::std::string* Person_PhoneNumber::release_number() { + clear_has_number(); + if (number_ == &::google::protobuf::internal::kEmptyString) { + return NULL; + } else { + ::std::string* temp = number_; + number_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + return temp; + } +} +inline void Person_PhoneNumber::set_allocated_number(::std::string* number) { + if (number_ != &::google::protobuf::internal::kEmptyString) { + delete number_; + } + if (number) { + set_has_number(); + number_ = number; + } else { + clear_has_number(); + number_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + } +} + +// optional .tutorial.Person.PhoneType type = 2 [default = HOME]; +inline bool Person_PhoneNumber::has_type() const { + return (_has_bits_[0] & 0x00000002u) != 0; +} +inline void Person_PhoneNumber::set_has_type() { + _has_bits_[0] |= 0x00000002u; +} +inline void Person_PhoneNumber::clear_has_type() { + _has_bits_[0] &= ~0x00000002u; +} +inline void Person_PhoneNumber::clear_type() { + type_ = 1; + clear_has_type(); +} +inline ::tutorial::Person_PhoneType Person_PhoneNumber::type() const { + return static_cast< ::tutorial::Person_PhoneType >(type_); +} +inline void Person_PhoneNumber::set_type(::tutorial::Person_PhoneType value) { + assert(::tutorial::Person_PhoneType_IsValid(value)); + set_has_type(); + type_ = value; +} + +// ------------------------------------------------------------------- + +// Person + +// required string name = 1; +inline bool Person::has_name() const { + return (_has_bits_[0] & 0x00000001u) != 0; +} +inline void Person::set_has_name() { + _has_bits_[0] |= 0x00000001u; +} +inline void Person::clear_has_name() { + _has_bits_[0] &= ~0x00000001u; +} +inline void Person::clear_name() { + if (name_ != &::google::protobuf::internal::kEmptyString) { + name_->clear(); + } + clear_has_name(); +} +inline const ::std::string& Person::name() const { + return *name_; +} +inline void Person::set_name(const ::std::string& value) { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + name_->assign(value); +} +inline void Person::set_name(const char* value) { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + name_->assign(value); +} +inline void Person::set_name(const char* value, size_t size) { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + name_->assign(reinterpret_cast(value), size); +} +inline ::std::string* Person::mutable_name() { + set_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + name_ = new ::std::string; + } + return name_; +} +inline ::std::string* Person::release_name() { + clear_has_name(); + if (name_ == &::google::protobuf::internal::kEmptyString) { + return NULL; + } else { + ::std::string* temp = name_; + name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + return temp; + } +} +inline void Person::set_allocated_name(::std::string* name) { + if (name_ != &::google::protobuf::internal::kEmptyString) { + delete name_; + } + if (name) { + set_has_name(); + name_ = name; + } else { + clear_has_name(); + name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + } +} + +// required int32 id = 2; +inline bool Person::has_id() const { + return (_has_bits_[0] & 0x00000002u) != 0; +} +inline void Person::set_has_id() { + _has_bits_[0] |= 0x00000002u; +} +inline void Person::clear_has_id() { + _has_bits_[0] &= ~0x00000002u; +} +inline void Person::clear_id() { + id_ = 0; + clear_has_id(); +} +inline ::google::protobuf::int32 Person::id() const { + return id_; +} +inline void Person::set_id(::google::protobuf::int32 value) { + set_has_id(); + id_ = value; +} + +// optional string email = 3; +inline bool Person::has_email() const { + return (_has_bits_[0] & 0x00000004u) != 0; +} +inline void Person::set_has_email() { + _has_bits_[0] |= 0x00000004u; +} +inline void Person::clear_has_email() { + _has_bits_[0] &= ~0x00000004u; +} +inline void Person::clear_email() { + if (email_ != &::google::protobuf::internal::kEmptyString) { + email_->clear(); + } + clear_has_email(); +} +inline const ::std::string& Person::email() const { + return *email_; +} +inline void Person::set_email(const ::std::string& value) { + set_has_email(); + if (email_ == &::google::protobuf::internal::kEmptyString) { + email_ = new ::std::string; + } + email_->assign(value); +} +inline void Person::set_email(const char* value) { + set_has_email(); + if (email_ == &::google::protobuf::internal::kEmptyString) { + email_ = new ::std::string; + } + email_->assign(value); +} +inline void Person::set_email(const char* value, size_t size) { + set_has_email(); + if (email_ == &::google::protobuf::internal::kEmptyString) { + email_ = new ::std::string; + } + email_->assign(reinterpret_cast(value), size); +} +inline ::std::string* Person::mutable_email() { + set_has_email(); + if (email_ == &::google::protobuf::internal::kEmptyString) { + email_ = new ::std::string; + } + return email_; +} +inline ::std::string* Person::release_email() { + clear_has_email(); + if (email_ == &::google::protobuf::internal::kEmptyString) { + return NULL; + } else { + ::std::string* temp = email_; + email_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + return temp; + } +} +inline void Person::set_allocated_email(::std::string* email) { + if (email_ != &::google::protobuf::internal::kEmptyString) { + delete email_; + } + if (email) { + set_has_email(); + email_ = email; + } else { + clear_has_email(); + email_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); + } +} + +// repeated .tutorial.Person.PhoneNumber phone = 4; +inline int Person::phone_size() const { + return phone_.size(); +} +inline void Person::clear_phone() { + phone_.Clear(); +} +inline const ::tutorial::Person_PhoneNumber& Person::phone(int index) const { + return phone_.Get(index); +} +inline ::tutorial::Person_PhoneNumber* Person::mutable_phone(int index) { + return phone_.Mutable(index); +} +inline ::tutorial::Person_PhoneNumber* Person::add_phone() { + return phone_.Add(); +} +inline const ::google::protobuf::RepeatedPtrField< ::tutorial::Person_PhoneNumber >& +Person::phone() const { + return phone_; +} +inline ::google::protobuf::RepeatedPtrField< ::tutorial::Person_PhoneNumber >* +Person::mutable_phone() { + return &phone_; +} + +// ------------------------------------------------------------------- + +// AddressBook + +// repeated .tutorial.Person person = 1; +inline int AddressBook::person_size() const { + return person_.size(); +} +inline void AddressBook::clear_person() { + person_.Clear(); +} +inline const ::tutorial::Person& AddressBook::person(int index) const { + return person_.Get(index); +} +inline ::tutorial::Person* AddressBook::mutable_person(int index) { + return person_.Mutable(index); +} +inline ::tutorial::Person* AddressBook::add_person() { + return person_.Add(); +} +inline const ::google::protobuf::RepeatedPtrField< ::tutorial::Person >& +AddressBook::person() const { + return person_; +} +inline ::google::protobuf::RepeatedPtrField< ::tutorial::Person >* +AddressBook::mutable_person() { + return &person_; +} + + +// @@protoc_insertion_point(namespace_scope) + +} // namespace tutorial + +// @@protoc_insertion_point(global_scope) + +#endif // PROTOBUF_test_2eproto__INCLUDED diff --git a/lib_rpc/samples/test.proto b/lib_rpc/samples/test.proto new file mode 100644 index 000000000..2de83f2fe --- /dev/null +++ b/lib_rpc/samples/test.proto @@ -0,0 +1,25 @@ +package tutorial; +option optimize_for = LITE_RUNTIME; + +message Person { + required string name=1; + required int32 id=2; + optional string email=3; + + enum PhoneType { + MOBILE=0; + HOME=1; + WORK=2; + } + + message PhoneNumber { + required string number=1; + optional PhoneType type=2 [default=HOME]; + } + + repeated PhoneNumber phone=4; +} + +message AddressBook { + repeated Person person=1; +} diff --git a/lib_rpc/samples/util.cpp b/lib_rpc/samples/util.cpp new file mode 100644 index 000000000..95a33ea94 --- /dev/null +++ b/lib_rpc/samples/util.cpp @@ -0,0 +1,18 @@ +#include "stdafx.h" +#include "util.h" + +double util::stamp_sub(const struct timeval *from, const struct timeval *sub_by) +{ + struct timeval res; + + memcpy(&res, from, sizeof(struct timeval)); + + res.tv_usec -= sub_by->tv_usec; + if (res.tv_usec < 0) { + --res.tv_sec; + res.tv_usec += 1000000; + } + res.tv_sec -= sub_by->tv_sec; + + return (res.tv_sec * 1000.0 + res.tv_usec/1000.0); +} diff --git a/lib_rpc/samples/util.h b/lib_rpc/samples/util.h new file mode 100644 index 000000000..e686072f1 --- /dev/null +++ b/lib_rpc/samples/util.h @@ -0,0 +1,10 @@ +#pragma once + +class util +{ +public: + util() {} + ~util() {} + + static double stamp_sub(const struct timeval *from, const struct timeval *sub_by); +}; diff --git a/lib_rpc/src/acl_fstream.cpp b/lib_rpc/src/acl_fstream.cpp new file mode 100644 index 000000000..84870a885 --- /dev/null +++ b/lib_rpc/src/acl_fstream.cpp @@ -0,0 +1,107 @@ +#include "stdafx.h" +#include "google/protobuf/io/acl_fstream.h" + +namespace google { +namespace protobuf { +namespace io { + +acl_ifstream::acl_ifstream(acl::istream* input, int block_size) +: copying_input_(input) +, impl_(©ing_input_, block_size) +{ +} + +acl_ifstream::~acl_ifstream() +{ +} + +bool acl_ifstream::Next(const void** data, int* size) +{ + return impl_.Next(data, size); +} + +void acl_ifstream::BackUp(int count) +{ + impl_.BackUp(count); +} + +bool acl_ifstream::Skip(int count) +{ + return impl_.Skip(count); +} + +int64 acl_ifstream::ByteCount() const +{ + return impl_.ByteCount(); +} + +acl_ifstream::CopyingAclInputStream::CopyingAclInputStream(acl::istream* input) + : input_(input) +{ +} + +acl_ifstream::CopyingAclInputStream::~CopyingAclInputStream() +{ +} + +int acl_ifstream::CopyingAclInputStream::Read(void* buffer, int size) +{ + int ret = input_->read(buffer, (size_t) size, false); + return ret; +} + +////////////////////////////////////////////////////////////////////////// + +acl_ofstream::acl_ofstream(acl::ostream* output, + int block_size /* = -1 */) +: copying_output_(output) +, impl_(©ing_output_, block_size) +{ + +} + +acl_ofstream::~acl_ofstream() +{ + impl_.Flush(); +} + +bool acl_ofstream::Flush() +{ + return impl_.Flush(); +} + +bool acl_ofstream::Next(void** data, int* size) +{ + return impl_.Next(data, size); +} + +void acl_ofstream::BackUp(int count) +{ + impl_.BackUp(count); +} + +int64 acl_ofstream::ByteCount() const +{ + return impl_.ByteCount(); +} + +acl_ofstream::CopyingAclOutputStream::CopyingAclOutputStream( + acl::ostream* output) + : output_(output) +{ +} + +acl_ofstream::CopyingAclOutputStream::~CopyingAclOutputStream() +{ +} + +bool acl_ofstream::CopyingAclOutputStream::Write( + const void* buffer, int size) +{ + printf("write called, size: %d\r\n", size); + return output_->write(buffer, (size_t) size) == size ? true : false; +} + +} // namespace io +} // namespace protobuf +} // namespace google diff --git a/lib_rpc/src/http_stream.cpp b/lib_rpc/src/http_stream.cpp new file mode 100644 index 000000000..e440e207f --- /dev/null +++ b/lib_rpc/src/http_stream.cpp @@ -0,0 +1,230 @@ +#include "stdafx.h" +#include "google/protobuf/message_lite.h" +#include "google/protobuf/io/http_stream.h" +#include "acl_cpp/stream/socket_stream.hpp" +#include "acl_cpp/http/http_client.hpp" +#include "acl_cpp/stdlib/string.hpp" +#include "lib_acl.h" + +namespace google { +namespace protobuf { +namespace io { + +#ifdef DEBUG +static double stamp_sub(const struct timeval *from, const struct timeval *sub_by) +{ + struct timeval res; + + memcpy(&res, from, sizeof(struct timeval)); + + res.tv_usec -= sub_by->tv_usec; + if (res.tv_usec < 0) { + --res.tv_sec; + res.tv_usec += 1000000; + } + res.tv_sec -= sub_by->tv_sec; + + return (res.tv_sec * 1000.0 + res.tv_usec/1000.0); +} +#endif + +http_request::http_request(acl::http_request* request) +: request_(request) +, request_inner_(NULL) +, addr_(NULL) +, conn_timeout_(0) +, rw_timeout_(0) +{ + assert(request); +} + +http_request::http_request(const char* addr, int conn_timeout /* = 60 */, + int rw_timeout /* = 60 */) +: request_(NULL) +, request_inner_(NULL) +, conn_timeout_(conn_timeout) +, rw_timeout_(rw_timeout) +, request_spent_(0) +, response_spent_(0) +, build_spent_(0) +, parse_spent_(0) +{ + addr_ = acl_mystrdup(addr); +} + +http_request::~http_request() +{ + if (request_inner_) + delete request_inner_; + if (addr_) + acl_myfree(addr_); +} + +bool http_request::rpc_request(const MessageLite& in, MessageLite* out) +{ + if (request_ == NULL) + { + if (addr_ == NULL) + return false; + request_inner_ = new acl::http_request(addr_, + conn_timeout_, rw_timeout_); + request_ = request_inner_; + } + + std::string buf; + +#ifdef DEBUG + struct timeval begin, end; + gettimeofday(&begin, NULL); +#endif + + in.SerializeToString(&buf); + +#ifdef DEBUG + gettimeofday(&end, NULL); + build_spent_ = stamp_sub(&end, &begin); + + gettimeofday(&begin, NULL); +#endif + if (request_->request(buf.c_str(), buf.length()) == false) + return false; + +#ifdef DEBUG + gettimeofday(&end, NULL); + request_spent_ = stamp_sub(&end, &begin); +#endif + + if (out == NULL) + return true; + + buf.clear(); + acl::string tmp; + int ret; + +#ifdef DEBUG + gettimeofday(&begin, NULL); +#endif + while (true) + { + ret = request_->read_body(tmp, true); + if (ret < 0) + return false; + else if (ret == 0) + break; + buf.append(tmp.c_str(), (size_t) ret); + } + +#ifdef DEBUG + gettimeofday(&end, NULL); + response_spent_ = stamp_sub(&end, &begin); + + gettimeofday(&begin, NULL); +#endif + + if (out->ParseFromString(buf) == false) + return false; + +#ifdef DEBUG + gettimeofday(&end, NULL); + parse_spent_ = stamp_sub(&end, &begin); +#endif + + return true; +} + +////////////////////////////////////////////////////////////////////////// + +http_response::http_response(acl::http_response* response) +: response_(response) +, header_spent_(0) +, body_spent_(0) +, parse_spent_(0) +, build_spent_(0) +, response_spent_(0) +{ + assert(response); +} + +http_response::~http_response() +{ +} + +bool http_response::read_request(MessageLite* out) +{ + if (out == NULL) + return false; + +#ifdef DEBUG + struct timeval begin, end; + gettimeofday(&begin, NULL); +#endif + + if (response_->read_header() == false) + return false; + +#ifdef DEBUG + gettimeofday(&end, NULL); + header_spent_ = stamp_sub(&end, &begin); +#endif + + acl::string buf; + +#ifdef DEBUG + gettimeofday(&begin, NULL); +#endif + + if (response_->get_body(buf) == false) + return false; + +#ifdef DEBUG + gettimeofday(&end, NULL); + body_spent_ = stamp_sub(&end, &begin); +#endif + + std::string data(buf.c_str(), (int) buf.length()); + +#ifdef DEBUG + gettimeofday(&begin, NULL); +#endif + + bool ret = out->ParseFromString(data); + +#ifdef DEBUG + gettimeofday(&end, NULL); + parse_spent_ = stamp_sub(&end, &begin); +#endif + + return ret; +} + +bool http_response::send_response(const MessageLite& in) +{ + std::string buf; + +#ifdef DEBUG + struct timeval begin, end; + gettimeofday(&begin, NULL); +#endif + + in.SerializeToString(&buf); + +#ifdef DEBUG + gettimeofday(&end, NULL); + build_spent_ = stamp_sub(&end, &begin); + + gettimeofday(&begin, NULL); +#endif + + bool ret = response_->response(buf.c_str(), buf.length()); + +#ifdef DEBUG + gettimeofday(&end, NULL); + response_spent_ = stamp_sub(&end, &begin); +#endif + + return ret; +} + +} // namespace io +} // namespace protobuf +} // namespace google diff --git a/lib_rpc/src/stdafx.cpp b/lib_rpc/src/stdafx.cpp new file mode 100644 index 000000000..0e8ad0f11 --- /dev/null +++ b/lib_rpc/src/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// lib_rpc.pch 将成为预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + +// TODO: 在 STDAFX.H 中 +//引用任何所需的附加头文件,而不是在此文件中引用 diff --git a/lib_rpc/src/stdafx.h b/lib_rpc/src/stdafx.h new file mode 100644 index 000000000..36d9cabf1 --- /dev/null +++ b/lib_rpc/src/stdafx.h @@ -0,0 +1,10 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是常用但不常更改的项目特定的包含文件 +// + +#pragma once + + +#define WIN32_LEAN_AND_MEAN // 从 Windows 头中排除极少使用的资料 + +// TODO: 在此处引用程序要求的附加头文件 diff --git a/lib_tls/Makefile b/lib_tls/Makefile new file mode 100644 index 000000000..21a312042 --- /dev/null +++ b/lib_tls/Makefile @@ -0,0 +1,130 @@ +SHELL = /bin/sh +CC = gcc +#CC = g++ +CC = ${MY_ENV_CC} +AR = ar +ARFL = rv +#ARFL = cru +RANLIB = ranlib + +CFLAGS = -c -g -W -Wall -Wcast-align \ +-Waggregate-return -Wmissing-prototypes \ +-Wpointer-arith -Werror -Wshadow -O2 \ +-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO \ +-Wno-long-long \ +-DUSE_TLS \ +-fPIC +#-Wcast-qual +#CFLAGS = -c -g -W -Wall -Wcast-qual -Wcast-align \ +#-Waggregate-return -Wmissing-prototypes \ +#-Wpointer-arith -Werror -Wshadow -O2 \ +#-D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO +########################################################### +#Check system: +# Linux, SunOS, Solaris, BSD variants, AIX, HP-UX +SYSLIB = +CHECKSYSRES = @echo "Unknow system type!";exit 1 +UNIXNAME = $(shell uname -sm) + +ifeq ($(CC),) + CC = gcc +endif + +# For FreeBSD +ifeq ($(findstring FreeBSD, $(UNIXNAME)), FreeBSD) + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DFREEBSD -D_REENTRANT -pedantic +endif + +# For Linux +ifeq ($(findstring Linux, $(UNIXNAME)), Linux) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DLINUX2 -D_REENTRANT -pedantic +endif + +# For SunOS +ifeq ($(findstring SunOS, $(UNIXNAME)), SunOS) + ifeq ($(findstring 86, $(UNIXNAME)), 86) + SYSLIB = -lsocket -lnsl -lrt + endif + ifeq ($(findstring sun4u, $(UNIXNAME)), sun4u) + SYSLIB = -lsocket -lnsl -lrt + endif + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DSUNOS5 -D_REENTRANT -pedantic +endif + +# For HP-UX +ifeq ($(findstring HP-UX, $(UNIXNAME)), HP-UX) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DHP_UX -DHPUX11 + PLAT_NAME=hp-ux +endif + +#Find system type. +ifneq ($(SYSPATH),) + CHECKSYSRES = @echo "System is $(shell uname -sm)" +endif +########################################################### + +OUT_PATH = . +OBJ_PATH_DST = $(OUT_PATH)/debug +LIB_PATH_DST = $(OUT_PATH)/lib + +#Project's objs +TLS_SRC = $(wildcard ./*.c) \ + $(wildcard ./util/*.c) \ + $(wildcard ./attr/*.c) \ + $(wildcard ./tls/*.c) + +TLS_OBJ = $(patsubst %.c, $(OBJ_PATH_DST)/%.o, $(notdir $(TLS_SRC))) + +#CFLAGS += -I./attr -I./util +########################################################### + +ACL_PATH = ../lib_acl +ACL_INC = $(ACL_PATH)/include +DICT_PATH = ../lib_dict +DICT_INC = $(DICT_PATH)/include + +CFLAGS += -I. -I./include -I$(ACL_INC) -I$(DICT_INC) + +########################################################### +.PHONY = clean LIB_NAME + +LIB_NAME = lib_tls.a + +COMPILE = $(CC) $(CFLAGS) + +all: TLSMGR + +$(shell mkdir -p $(OBJ_PATH_DST)) + +TLSMGR: $(LIB_NAME) + @(cd tlsmgr; make) + +$(LIB_NAME): $(TLS_OBJ) + $(AR) $(ARFL) $(LIB_PATH_DST)/$(LIB_NAME) $(TLS_OBJ) + $(RANLIB) $(LIB_PATH_DST)/$(LIB_NAME) + +$(OBJ_PATH_DST)/%.o: ./%.c + $(COMPILE) $< -o $@ +$(OBJ_PATH_DST)/%.o: ./tls/%.c + $(COMPILE) $< -o $@ +$(OBJ_PATH_DST)/%.o: ./util/%.c + $(COMPILE) $< -o $@ +$(OBJ_PATH_DST)/%.o: ./attr/%.c + $(COMPILE) $< -o $@ + +clean: + rm -f $(LIB_PATH_DST)/$(LIB_NAME) + rm -f $(TLS_OBJ) + @(cd tlsmgr; make clean) diff --git a/lib_tls/ReadMe.txt b/lib_tls/ReadMe.txt new file mode 100644 index 000000000..a4aa13adc --- /dev/null +++ b/lib_tls/ReadMe.txt @@ -0,0 +1,20 @@ +======================================================================== + 静态库 : lib_tls 项目概况 +======================================================================== + +应用程序向导已为您创建了这个 lib_tls 库项目。 +没有任何源文件被创建为项目的一部分。 + + +lib_tls.vcproj + 这是用应用程序向导生成的 VC++ 项目的主项目文件。 + 它包含有关生成此文件的 Visual C++ 版本的信息,以及 + 有关用应用程序向导选择的 + 平台、配置和项目功能的信息。 + +///////////////////////////////////////////////////////////////////////////// +其他注释: + +应用程序向导使用 "TODO:" 注释指示应添加或自定义的源代码部分。 + +///////////////////////////////////////////////////////////////////////////// diff --git a/lib_tls/StdAfx.c b/lib_tls/StdAfx.c new file mode 100644 index 000000000..e717491df --- /dev/null +++ b/lib_tls/StdAfx.c @@ -0,0 +1 @@ +#include "StdAfx.h" diff --git a/lib_tls/StdAfx.h b/lib_tls/StdAfx.h new file mode 100644 index 000000000..7081cfe88 --- /dev/null +++ b/lib_tls/StdAfx.h @@ -0,0 +1,22 @@ +#ifndef __STD_AFX_INCLUDE_H__ +#define __STD_AFX_INCLUDE_H__ + +# ifdef WIN32 +# include +# include +# ifdef __STDC_WANT_SECURE_LIB__ +int tls_secure_snprintf(char *buf, size_t size, const char *fmt, ...); +int tls_secure_vsnprintf(char *buf, size_t size, const char *fmt, va_list ap); +# define snprintf tls_secure_snprintf +# define vsnprintf tls_secure_vsnprintf +# else +# ifndef snprintf +# define snprintf _snprintf +# endif +# ifndef vsnprintf +# define vsnprintf _vsnprintf +# endif +# endif +# endif /* WIN2 */ +#include "lib_acl.h" +#endif diff --git a/lib_tls/attr/attr.h b/lib_tls/attr/attr.h new file mode 100644 index 000000000..6b5172a9f --- /dev/null +++ b/lib_tls/attr/attr.h @@ -0,0 +1,127 @@ +#ifndef _ATTR_H_INCLUDED_ +#define _ATTR_H_INCLUDED_ + +/*++ + * NAME + * attr 3h + * SUMMARY + * attribute list manipulations + * SYNOPSIS + * #include "attr.h" + DESCRIPTION + .nf + */ + +/* + * + * System library. + */ +#include + + /* + * Utility library. + */ +#include "lib_acl.h" + + /* + * Attribute types. See attr_scan(3) for documentation. + */ +#define ATTR_TYPE_END 0 /* end of data */ +#define ATTR_TYPE_INT 1 /* Unsigned integer */ +#define ATTR_TYPE_NUM ATTR_TYPE_INT +#define ATTR_TYPE_STR 2 /* Character string */ +#define ATTR_TYPE_HASH 3 /* Hash table */ +#define ATTR_TYPE_NV 3 /* Name-value table */ +#define ATTR_TYPE_LONG 4 /* Unsigned long */ +#define ATTR_TYPE_DATA 5 /* Binary data */ +#define ATTR_TYPE_FUNC 6 /* Function pointer */ + +#define ATTR_HASH_LIMIT 1024 /* Size of hash table */ + + /* + * Flags that control processing. See attr_scan(3) for documentation. + */ +#define ATTR_FLAG_NONE 0 +#define ATTR_FLAG_MISSING (1<<0) /* Flag missing attribute */ +#define ATTR_FLAG_EXTRA (1<<1) /* Flag spurious attribute */ +#define ATTR_FLAG_MORE (1<<2) /* Don't skip or terminate */ + +#define ATTR_FLAG_STRICT (ATTR_FLAG_MISSING | ATTR_FLAG_EXTRA) +#define ATTR_FLAG_ALL (07) + + /* + * Delegation for better data abstraction. + */ +typedef int (*ATTR_SCAN_MASTER_FN) (ACL_VSTREAM *, int, ...); +typedef int (*ATTR_SCAN_SLAVE_FN) (ATTR_SCAN_MASTER_FN, ACL_VSTREAM *, int, void *); +typedef int (*ATTR_PRINT_MASTER_FN) (ACL_VSTREAM *, int,...); +typedef int (*ATTR_PRINT_SLAVE_FN) (ATTR_PRINT_MASTER_FN, ACL_VSTREAM *, int, void *); + + /* + * Default to null-terminated, as opposed to base64-encoded. + */ +#define attr_print attr_print0 +#define attr_vprint attr_vprint0 +#define attr_scan attr_scan0 +#define attr_vscan attr_vscan0 + + /* + * attr_print64.c. + */ +extern int attr_print64(ACL_VSTREAM *, int,...); +extern int attr_vprint64(ACL_VSTREAM *, int, va_list); + + /* + * attr_scan64.c. + */ +extern int attr_scan64(ACL_VSTREAM *, int,...); +extern int attr_vscan64(ACL_VSTREAM *, int, va_list); + + /* + * attr_print0.c. + */ +extern int attr_print0(ACL_VSTREAM *, int,...); +extern int attr_vprint0(ACL_VSTREAM *, int, va_list); + + /* + * attr_scan0.c. + */ +extern int attr_scan0(ACL_VSTREAM *, int,...); +extern int attr_vscan0(ACL_VSTREAM *, int, va_list); + + /* + * attr_scan_plain.c. + */ +extern int attr_print_plain(ACL_VSTREAM *, int,...); +extern int attr_vprint_plain(ACL_VSTREAM *, int, va_list); + + /* + * attr_print_plain.c. + */ +extern int attr_scan_plain(ACL_VSTREAM *, int,...); +extern int attr_vscan_plain(ACL_VSTREAM *, int, va_list); + + + /* + * Attribute names for testing the compatibility of the read and write + * routines. + */ +#ifdef TEST +#define ATTR_NAME_INT "number" +#define ATTR_NAME_STR "string" +#define ATTR_NAME_LONG "long_number" +#define ATTR_NAME_DATA "data" +#endif + +/* LICENSE + * .ad + * .fi + * The Secure Mailer license must be distributed with this software. + * AUTHOR(S) + * Wietse Venema + * IBM T.J. Watson Research + * P.O. Box 704 + * Yorktown Heights, NY 10598, USA + *--*/ + +#endif diff --git a/lib_tls/attr/attr_clnt.c b/lib_tls/attr/attr_clnt.c new file mode 100644 index 000000000..b2e6e476e --- /dev/null +++ b/lib_tls/attr/attr_clnt.c @@ -0,0 +1,212 @@ +/*++ + * NAME + * attr_clnt 3 + * SUMMARY + * attribute query-reply client + * SYNOPSIS + * #include + * + * typedef int (*ATTR_CLNT_PRINT_FN) (VSTREAM *, int, va_list); + * typedef int (*ATTR_CLNT_SCAN_FN) (VSTREAM *, int, va_list); + * + * ATTR_CLNT *attr_clnt_create(server, timeout, max_idle, max_ttl) + * const char *server; + * int timeout; + * int max_idle; + * int max_ttl; + * + * int attr_clnt_request(client, + * send_flags, send_type, send_name, ..., ATTR_TYPE_END, + * recv_flags, recv_type, recv_name, ..., ATTR_TYPE_END) + * ATTR_CLNT *client; + * int send_flags; + * int send_type; + * const char *send_name; + * int recv_flags; + * int recv_type; + * const char *recv_name; + * + * void attr_clnt_free(client) + * ATTR_CLNT *client; + * + * void attr_clnt_control(client, name, value, ... ATTR_CLNT_CTL_END) + * ATTR_CLNT *client; + * int name; + * DESCRIPTION + * This module implements a client for a simple attribute-based + * protocol. The default protocol is described in attr_scan_plain(3). + * + * attr_clnt_create() creates a client handle. See auto_clnt(3) for + * a description of the arguments. + * + * attr_clnt_request() sends the specified request attributes and + * receives a reply. The reply argument specifies a name-value table. + * The other arguments are as described in attr_print_plain(3). The + * result is the number of attributes received or -1 in case of trouble. + * + * attr_clnt_free() destroys a client handle and closes its connection. + * + * attr_clnt_control() allows the user to fine tune the behavior of + * the specified client. The arguments are a list of (name, value) + * terminated with ATTR_CLNT_CTL_END. + * The following lists the names and the types of the corresponding + * value arguments. + * .IP "ATTR_CLNT_CTL_PROTO(ATTR_CLNT_PRINT_FN, ATTR_CLNT_SCAN_FN)" + * Specifies alternatives for the attr_plain_print() and + * attr_plain_scan() functions. + * DIAGNOSTICS + * Warnings: communication failure. + * SEE ALSO + * auto_clnt(3), client endpoint management + * attr_scan_plain(3), attribute protocol + * attr_print_plain(3), attribute protocol + * LICENSE + * .ad + * .fi + * The Secure Mailer license must be distributed with this software. + * AUTHOR(S) + * Wietse Venema + * IBM T.J. Watson Research + * P.O. Box 704 + * Yorktown Heights, NY 10598, USA + *--*/ + +#include "StdAfx.h" +#ifdef ACL_UNIX +#include +#endif +#include + +#include "attr.h" +#include "auto_clnt.h" +#include "attr_clnt.h" + +/* Application-specific. */ + +struct ATTR_CLNT { + AUTO_CLNT *auto_clnt; + ATTR_CLNT_PRINT_FN print; + ATTR_CLNT_SCAN_FN scan; +}; + +/* attr_clnt_free - destroy attribute client */ + +void attr_clnt_free(ATTR_CLNT *client) +{ + auto_clnt_free(client->auto_clnt); + acl_myfree(client); +} + +/* attr_clnt_create - create attribute client */ + +ATTR_CLNT *attr_clnt_create(ACL_EVENT *eventp, const char *service, + int timeout, int max_idle, int max_ttl) +{ + ATTR_CLNT *client; + + client = (ATTR_CLNT *) acl_mymalloc(sizeof(*client)); + client->auto_clnt = auto_clnt_create(eventp, service, + timeout, max_idle, max_ttl); + client->scan = attr_vscan_plain; + client->print = attr_vprint_plain; + return (client); +} + +/* attr_clnt_request - send query, receive reply */ + +int attr_clnt_request(ATTR_CLNT *client, int send_flags,...) +{ + const char *myname = "attr_clnt_request"; + ACL_VSTREAM *stream; + int count = 0; + va_list ap; + int type; + int recv_flags; + int err; + int ret; + + /* + * XXX If the stream is readable before we send anything, then assume the + * remote end disconnected. + * + * XXX For some reason we can't simply call the scan routine after the print + * routine, that messes up the argument list. + */ +#define SKIP_ARG(ap, type) { \ + (void) va_arg(ap, char *); \ + (void) va_arg(ap, type); \ +} +#define SKIP_ARG2(ap, t1, t2) { \ + SKIP_ARG(ap, t1); \ + (void) va_arg(ap, t2); \ +} + + for (;;) { + errno = 0; + if ((stream = auto_clnt_access(client->auto_clnt)) != 0 + && acl_readable(ACL_VSTREAM_SOCK(stream)) == 0) { + errno = 0; + va_start(ap, send_flags); + err = (client->print(stream, send_flags, ap) == ACL_VSTREAM_EOF + || acl_vstream_fflush(stream) == ACL_VSTREAM_EOF); + va_end(ap); + if (err == 0) { + va_start(ap, send_flags); + while ((type = va_arg(ap, int)) != ATTR_TYPE_END) { + switch (type) { + case ATTR_TYPE_STR: + SKIP_ARG(ap, char *); + break; + case ATTR_TYPE_DATA: + SKIP_ARG2(ap, ssize_t, char *); + break; + case ATTR_TYPE_INT: + SKIP_ARG(ap, int); + break; + case ATTR_TYPE_LONG: + SKIP_ARG(ap, long); + break; + case ATTR_TYPE_HASH: + (void) va_arg(ap, ACL_HTABLE *); + break; + default: + acl_msg_panic("%s: unexpected attribute type %d", myname, type); + } + } + recv_flags = va_arg(ap, int); + ret = client->scan(stream, recv_flags, ap); + va_end(ap); + if (ret > 0) + return (ret); + } + } + if (++count >= 2 || acl_msg_verbose + || (errno && errno != EPIPE && errno != ENOENT && errno != ACL_ECONNRESET)) + acl_msg_warn("%s: problem talking to server %s: %s", + myname, auto_clnt_name(client->auto_clnt), acl_last_serror()); + if (count >= 2) + return (-1); + sleep(1); /* XXX make configurable */ + auto_clnt_recover(client->auto_clnt); + } +} + +/* attr_clnt_control - fine control */ + +void attr_clnt_control(ATTR_CLNT *client, int name,...) +{ + const char *myname = "attr_clnt_control"; + va_list ap; + + for (va_start(ap, name); name != ATTR_CLNT_CTL_END; name = va_arg(ap, int)) { + switch (name) { + case ATTR_CLNT_CTL_PROTO: + client->print = va_arg(ap, ATTR_CLNT_PRINT_FN); + client->scan = va_arg(ap, ATTR_CLNT_SCAN_FN); + break; + default: + acl_msg_panic("%s: bad name %d", myname, name); + } + } + va_end(ap); +} diff --git a/lib_tls/attr/attr_clnt.h b/lib_tls/attr/attr_clnt.h new file mode 100644 index 000000000..09a7322df --- /dev/null +++ b/lib_tls/attr/attr_clnt.h @@ -0,0 +1,46 @@ +#ifndef _ATTR_CLNT_H_INCLUDED_ +#define _ATTR_CLNT_H_INCLUDED_ + +/*++ + * NAME + * attr_clnt 3h + * SUMMARY + * attribute query-reply client + * SYNOPSIS + * #include + * DESCRIPTION + * .nf + + * + * Utility library. + */ +#include "lib_acl.h" +#include "attr.h" + + /* + * External interface. + */ +typedef struct ATTR_CLNT ATTR_CLNT; +typedef int (*ATTR_CLNT_PRINT_FN) (ACL_VSTREAM *, int, va_list); +typedef int (*ATTR_CLNT_SCAN_FN) (ACL_VSTREAM *, int, va_list); + +extern ATTR_CLNT *attr_clnt_create(ACL_EVENT *, const char *, int, int, int); +extern int attr_clnt_request(ATTR_CLNT *, int,...); +extern void attr_clnt_free(ATTR_CLNT *); +extern void attr_clnt_control(ATTR_CLNT *, int, ...); + +#define ATTR_CLNT_CTL_END 0 +#define ATTR_CLNT_CTL_PROTO 1 + +/* LICENSE + * .ad + * .fi + * The Secure Mailer license must be distributed with this software. + * AUTHOR(S) + * Wietse Venema + * IBM T.J. Watson Research + * P.O. Box 704 + * Yorktown Heights, NY 10598, USA + *--*/ + +#endif diff --git a/lib_tls/attr/attr_print0.c b/lib_tls/attr/attr_print0.c new file mode 100644 index 000000000..7a2ff2f75 --- /dev/null +++ b/lib_tls/attr/attr_print0.c @@ -0,0 +1,254 @@ +/*++ + * NAME + * attr_print0 3 + * SUMMARY + * send attributes over byte stream + * SYNOPSIS + * #include + * + * int attr_print0(fp, flags, type, name, ..., ATTR_TYPE_END) + * ACL_VSTREAM fp; + * int flags; + * int type; + * char *name; + * + * int attr_vprint0(fp, flags, ap) + * ACL_VSTREAM fp; + * int flags; + * va_list ap; + * DESCRIPTION + * attr_print0() takes zero or more (name, value) simple attributes + * and converts its input to a byte stream that can be recovered with + * attr_scan0(). The stream is not flushed. + * + * attr_vprint0() provides an alternate interface that is convenient + * for calling from within variadic functions. + * + * Attributes are sent in the requested order as specified with the + * attr_print0() argument list. This routine satisfies the formatting + * rules as outlined in attr_scan0(3). + * + * Arguments: + * .IP fp + * Stream to write the result to. + * .IP flags + * The bit-wise OR of zero or more of the following. + * .RS + * .IP ATTR_FLAG_MORE + * After sending the requested attributes, leave the output stream in + * a state that is usable for more attribute sending operations on + * the same output attribute list. + * By default, attr_print0() automatically appends an attribute list + * terminator when it has sent the last requested attribute. + * .RE + * .IP type + * The type determines the arguments that follow. + * .RS + * .IP "ATTR_TYPE_INT (char *, int)" + * This argument is followed by an attribute name and an integer. + * .IP "ATTR_TYPE_LONG (char *, long)" + * This argument is followed by an attribute name and a long integer. + * .IP "ATTR_TYPE_STR (char *, char *)" + * This argument is followed by an attribute name and a null-terminated + * string. + * .IP "ATTR_TYPE_DATA (char *, ssize_t, char *)" + * This argument is followed by an attribute name, an attribute value + * length, and an attribute value pointer. + * .IP "ATTR_TYPE_FUNC (ATTR_PRINT_SLAVE_FN, void *)" + * This argument is followed by a function pointer and generic data + * pointer. The caller-specified function returns whatever the + * specified attribute printing function returns. + * .IP "ATTR_TYPE_HASH (HTABLE *)" + * .IP "ATTR_TYPE_NAMEVAL (NVTABLE *)" + * The content of the table is sent as a sequence of string-valued + * attributes with names equal to the table lookup keys. + * .IP ATTR_TYPE_END + * This terminates the attribute list. + * .RE + * DIAGNOSTICS + * The result value is 0 in case of success, ACL_VSTREAM_EOF in case + * of trouble. + * + * Panic: interface violation. All system call errors are fatal. + * SEE ALSO + * attr_scan0(3) recover attributes from byte stream + * LICENSE + * .ad + * .fi + * The Secure Mailer license must be distributed with this software. + * AUTHOR(S) + * Wietse Venema + * IBM T.J. Watson Research + * P.O. Box 704 + * Yorktown Heights, NY 10598, USA + *--*/ + +#include "StdAfx.h" +#include +#include + +#include "attr.h" + +#define STR(x) acl_vstring_str(x) +#define LEN(x) ACL_VSTRING_LEN(x) + +static void free_vstring_fn(void *arg) +{ + ACL_VSTRING *s = (ACL_VSTRING*) arg; + + acl_vstring_free(s); +} + +/* attr_vprint0 - send attribute list to stream */ + +int attr_vprint0(ACL_VSTREAM *fp, int flags, va_list ap) +{ + const char *myname = "attr_vprint0"; + int attr_type; + char *attr_name; + unsigned int_val; + unsigned long long_val; + char *str_val; + ACL_HTABLE_INFO **ht_info_list; + ACL_HTABLE_INFO **ht; + ssize_t len_val; + static __thread ACL_VSTRING *base64_buf; + ATTR_PRINT_SLAVE_FN print_fn; + void *print_arg; + + /* + * Sanity check. + */ + if (flags & ~ATTR_FLAG_ALL) + acl_msg_panic("%s: bad flags: 0x%x", myname, flags); + + /* + * Iterate over all (type, name, value) triples, and produce output on + * the fly. + */ + while ((attr_type = va_arg(ap, int)) != ATTR_TYPE_END) { + switch (attr_type) { + case ATTR_TYPE_INT: + attr_name = va_arg(ap, char *); + if (acl_vstream_buffed_writen(fp, attr_name, strlen(attr_name) + 1) == ACL_VSTREAM_EOF) + return (ACL_VSTREAM_EOF); + int_val = va_arg(ap, int); + if (acl_vstream_buffed_fprintf(fp, "%u", (unsigned) int_val) == ACL_VSTREAM_EOF) + return (ACL_VSTREAM_EOF); + if (ACL_VSTREAM_PUTC('\0', fp) == ACL_VSTREAM_EOF) + return (ACL_VSTREAM_EOF); + if (acl_msg_verbose) + acl_msg_info("send attr %s = %u", attr_name, int_val); + break; + case ATTR_TYPE_LONG: + attr_name = va_arg(ap, char *); + if (acl_vstream_buffed_fwrite(fp, attr_name, strlen(attr_name) + 1) == ACL_VSTREAM_EOF) + return (ACL_VSTREAM_EOF); + long_val = va_arg(ap, unsigned long); + if (acl_vstream_buffed_fprintf(fp, "%lu", (unsigned long) long_val) == ACL_VSTREAM_EOF) + return (ACL_VSTREAM_EOF); + if (ACL_VSTREAM_PUTC('\0', fp) == ACL_VSTREAM_EOF) + return (ACL_VSTREAM_EOF); + if (acl_msg_verbose) + acl_msg_info("send attr %s = %lu", attr_name, long_val); + break; + case ATTR_TYPE_STR: + attr_name = va_arg(ap, char *); + if (acl_vstream_buffed_fwrite(fp, attr_name, strlen(attr_name) + 1) == ACL_VSTREAM_EOF) + return (ACL_VSTREAM_EOF); + str_val = va_arg(ap, char *); + if (acl_vstream_buffed_fwrite(fp, str_val, strlen(str_val) + 1) == ACL_VSTREAM_EOF) + return (ACL_VSTREAM_EOF); + if (acl_msg_verbose) + acl_msg_info("send attr %s = %s", attr_name, str_val); + break; + case ATTR_TYPE_DATA: + attr_name = va_arg(ap, char *); + if (acl_vstream_buffed_fwrite(fp, attr_name, strlen(attr_name) + 1) == ACL_VSTREAM_EOF) + return (ACL_VSTREAM_EOF); + len_val = va_arg(ap, ssize_t); + str_val = va_arg(ap, char *); + if (base64_buf == 0) { + base64_buf = acl_vstring_alloc(10); + acl_pthread_atexit_add(base64_buf, free_vstring_fn); + } + acl_vstring_base64_encode(base64_buf, str_val, len_val); + if (acl_vstream_buffed_fwrite(fp, STR(base64_buf), LEN(base64_buf) + 1) == ACL_VSTREAM_EOF) + return (ACL_VSTREAM_EOF); + if (acl_msg_verbose) + acl_msg_info("send attr %s = [data %ld bytes]", + attr_name, (long) len_val); + break; + case ATTR_TYPE_FUNC: + print_fn = va_arg(ap, ATTR_PRINT_SLAVE_FN); + print_arg = va_arg(ap, void *); + print_fn(attr_print0, fp, flags | ATTR_FLAG_MORE, print_arg); + break; + case ATTR_TYPE_HASH: + ht_info_list = acl_htable_list(va_arg(ap, ACL_HTABLE *)); + for (ht = ht_info_list; *ht; ht++) { + if (acl_vstream_buffed_fwrite(fp, ht[0]->key.c_key, strlen(ht[0]->key.c_key) + 1) == ACL_VSTREAM_EOF) + return (ACL_VSTREAM_EOF); + if (acl_vstream_buffed_fwrite(fp, ht[0]->value, strlen(ht[0]->value) + 1) == ACL_VSTREAM_EOF) + return (ACL_VSTREAM_EOF); + if (acl_msg_verbose) + acl_msg_info("send attr name %s value %s", ht[0]->key.c_key, (char*) ht[0]->value); + } + acl_myfree(ht_info_list); + break; + default: + acl_msg_panic("%s: unknown type code: %d", myname, attr_type); + } + } + if ((flags & ATTR_FLAG_MORE) == 0) + if (ACL_VSTREAM_PUTC('\0', fp) == ACL_VSTREAM_EOF) + return (ACL_VSTREAM_EOF); + return (acl_vstream_fflush(fp)); +} + +int attr_print0(ACL_VSTREAM *fp, int flags,...) +{ + va_list ap; + int ret; + + va_start(ap, flags); + ret = attr_vprint0(fp, flags, ap); + va_end(ap); + return (ret); +} + +#ifdef TEST + + /* + * Proof of concept test program. Mirror image of the attr_scan0 test + * program. + */ + +int main(int unused_argc, char **argv) +{ + ACL_HTABLE *table = acl_htable_create(1); + + acl_msg_verbose = 1; + acl_htable_enter(table, "foo-name", mystrdup("foo-value")); + acl_htable_enter(table, "bar-name", mystrdup("bar-value")); + attr_print0(ACL_VSTREAM_OUT, ATTR_FLAG_NONE, + ATTR_TYPE_INT, ATTR_NAME_INT, 4711, + ATTR_TYPE_LONG, ATTR_NAME_LONG, 1234, + ATTR_TYPE_STR, ATTR_NAME_STR, "whoopee", + ATTR_TYPE_DATA, ATTR_NAME_DATA, strlen("whoopee"), "whoopee", + ATTR_TYPE_HASH, table, + ATTR_TYPE_END); + attr_print0(ACL_VSTREAM_OUT, ATTR_FLAG_NONE, + ATTR_TYPE_INT, ATTR_NAME_INT, 4711, + ATTR_TYPE_LONG, ATTR_NAME_LONG, 1234, + ATTR_TYPE_STR, ATTR_NAME_STR, "whoopee", + ATTR_TYPE_DATA, ATTR_NAME_DATA, strlen("whoopee"), "whoopee", + ATTR_TYPE_END); + if (acl_vstream_fflush(ACL_VSTREAM_OUT) == ACL_VSTREAM_EOF) + acl_msg_fatal("%s: write error", __FUNCTION__); + + acl_htable_free(table, myfree); + return (0); +} + +#endif diff --git a/lib_tls/attr/attr_print64.c b/lib_tls/attr/attr_print64.c new file mode 100644 index 000000000..9ee30f670 --- /dev/null +++ b/lib_tls/attr/attr_print64.c @@ -0,0 +1,285 @@ +/*++ + * NAME + * attr_print64 3 + * SUMMARY + * send attributes over byte stream + * SYNOPSIS + * #include + * + * int attr_print64(fp, flags, type, name, ..., ATTR_TYPE_END) + * ACL_VSTREAM fp; + * int flags; + * int type; + * char *name; + * + * int attr_vprint64(fp, flags, ap) + * ACL_VSTREAM fp; + * int flags; + * va_list ap; + * DESCRIPTION + * attr_print64() takes zero or more (name, value) simple attributes + * and converts its input to a byte stream that can be recovered with + * attr_scan64(). The stream is not flushed. + * + * attr_vprint64() provides an alternate interface that is convenient + * for calling from within variadic functions. + * + * Attributes are sent in the requested order as specified with the + * attr_print64() argument list. This routine satisfies the formatting + * rules as outlined in attr_scan64(3). + * + * Arguments: + * .IP fp + * Stream to write the result to. + * .IP flags + * The bit-wise OR of zero or more of the following. + * .RS + * .IP ATTR_FLAG_MORE + * After sending the requested attributes, leave the output stream in + * a state that is usable for more attribute sending operations on + * the same output attribute list. + * By default, attr_print64() automatically appends an attribute list + * terminator when it has sent the last requested attribute. + * .RE + * .IP type + * The type determines the arguments that follow. + * .RS + * .IP "ATTR_TYPE_INT (char *, int)" + * This argument is followed by an attribute name and an integer. + * .IP "ATTR_TYPE_LONG (char *, long)" + * This argument is followed by an attribute name and a long integer. + * .IP "ATTR_TYPE_STR (char *, char *)" + * This argument is followed by an attribute name and a null-terminated + * string. + * .IP "ATTR_TYPE_DATA (char *, ssize_t, char *)" + * This argument is followed by an attribute name, an attribute value + * length, and an attribute value pointer. + * .IP "ATTR_TYPE_FUNC (ATTR_PRINT_SLAVE_FN, void *)" + * This argument is followed by a function pointer and generic data + * pointer. The caller-specified function returns whatever the + * specified attribute printing function returns. + * .IP "ATTR_TYPE_HASH (HTABLE *)" + * .IP "ATTR_TYPE_NAMEVAL (NVTABLE *)" + * The content of the table is sent as a sequence of string-valued + * attributes with names equal to the table lookup keys. + * .IP ATTR_TYPE_END + * This terminates the attribute list. + * .RE + * DIAGNOSTICS + * The result value is 0 in case of success, ACL_VSTREAM_EOF in case + * of trouble. + * + * Panic: interface violation. All system call errors are fatal. + * SEE ALSO + * attr_scan64(3) recover attributes from byte stream + * LICENSE + * .ad + * .fi + * The Secure Mailer license must be distributed with this software. + * AUTHOR(S) + * Wietse Venema + * IBM T.J. Watson Research + * P.O. Box 704 + * Yorktown Heights, NY 10598, USA + *--*/ + +#include "StdAfx.h" +#include +#include + +#include "attr.h" + +#define STR(x) acl_vstring_str(x) +#define LEN(x) ACL_VSTRING_LEN(x) + +static void free_vstring(void *arg) +{ + ACL_VSTRING *s = (ACL_VSTRING*) arg; + + acl_vstring_free(s); +} + +/* attr_print64_str - encode and send attribute information */ + +static void attr_print64_str(ACL_VSTREAM *fp, const char *str, ssize_t len) +{ + static __thread ACL_VSTRING *base64_buf; + + if (base64_buf == 0) { + base64_buf = acl_vstring_alloc(10); + acl_pthread_atexit_add(base64_buf, free_vstring); + } + + acl_vstring_base64_encode(base64_buf, str, len); + acl_vstream_buffed_fputs(STR(base64_buf), fp); +} + +static void attr_print64_num(ACL_VSTREAM *fp, unsigned num) +{ + static __thread ACL_VSTRING *plain; + + if (plain == 0) { + plain = acl_vstring_alloc(10); + acl_pthread_atexit_add(plain, free_vstring); + } + + acl_vstring_sprintf(plain, "%u", num); + attr_print64_str(fp, STR(plain), (int) LEN(plain)); +} + +static void attr_print64_long_num(ACL_VSTREAM *fp, unsigned long long_num) +{ + static __thread ACL_VSTRING *plain; + + if (plain == 0) { + plain = acl_vstring_alloc(10); + acl_pthread_atexit_add(plain, free_vstring); + } + + acl_vstring_sprintf(plain, "%lu", long_num); + attr_print64_str(fp, STR(plain), (int) LEN(plain)); +} + +/* attr_vprint64 - send attribute list to stream */ + +int attr_vprint64(ACL_VSTREAM *fp, int flags, va_list ap) +{ + const char *myname = "attr_print64"; + int attr_type; + char *attr_name; + unsigned int_val; + unsigned long long_val; + char *str_val; + ACL_HTABLE_INFO **ht_info_list; + ACL_HTABLE_INFO **ht; + ssize_t len_val; + ATTR_PRINT_SLAVE_FN print_fn; + void *print_arg; + + /* + * Sanity check. + */ + if (flags & ~ATTR_FLAG_ALL) + acl_msg_panic("%s: bad flags: 0x%x", myname, flags); + + /* + * Iterate over all (type, name, value) triples, and produce output on + * the fly. + */ + while ((attr_type = va_arg(ap, int)) != ATTR_TYPE_END) { + switch (attr_type) { + case ATTR_TYPE_INT: + attr_name = va_arg(ap, char *); + attr_print64_str(fp, attr_name, (int) strlen(attr_name)); + int_val = va_arg(ap, int); + ACL_VSTREAM_PUTC(':', fp); + attr_print64_num(fp, (unsigned) int_val); + ACL_VSTREAM_PUTC('\n', fp); + if (acl_msg_verbose) + acl_msg_info("send attr %s = %u", attr_name, int_val); + break; + case ATTR_TYPE_LONG: + attr_name = va_arg(ap, char *); + attr_print64_str(fp, attr_name, (int) strlen(attr_name)); + long_val = va_arg(ap, long); + ACL_VSTREAM_PUTC(':', fp); + attr_print64_long_num(fp, (unsigned long) long_val); + ACL_VSTREAM_PUTC('\n', fp); + if (acl_msg_verbose) + acl_msg_info("send attr %s = %lu", attr_name, long_val); + break; + case ATTR_TYPE_STR: + attr_name = va_arg(ap, char *); + attr_print64_str(fp, attr_name, (int) strlen(attr_name)); + str_val = va_arg(ap, char *); + ACL_VSTREAM_PUTC(':', fp); + attr_print64_str(fp, str_val, (int) strlen(str_val)); + ACL_VSTREAM_PUTC('\n', fp); + if (acl_msg_verbose) + acl_msg_info("send attr %s = %s", attr_name, str_val); + break; + case ATTR_TYPE_DATA: + attr_name = va_arg(ap, char *); + attr_print64_str(fp, attr_name, (int) strlen(attr_name)); + len_val = va_arg(ap, ssize_t); + str_val = va_arg(ap, char *); + ACL_VSTREAM_PUTC(':', fp); + attr_print64_str(fp, str_val, len_val); + ACL_VSTREAM_PUTC('\n', fp); + if (acl_msg_verbose) + acl_msg_info("send attr %s = [data %ld bytes]", + attr_name, (long) len_val); + break; + case ATTR_TYPE_FUNC: + print_fn = va_arg(ap, ATTR_PRINT_SLAVE_FN); + print_arg = va_arg(ap, void *); + print_fn(attr_print64, fp, flags | ATTR_FLAG_MORE, print_arg); + break; + case ATTR_TYPE_HASH: + ht_info_list = acl_htable_list(va_arg(ap, ACL_HTABLE *)); + for (ht = ht_info_list; *ht; ht++) { + attr_print64_str(fp, ht[0]->key.c_key, (int) strlen(ht[0]->key.c_key)); + ACL_VSTREAM_PUTC(':', fp); + attr_print64_str(fp, ht[0]->value, (int) strlen(ht[0]->value)); + ACL_VSTREAM_PUTC('\n', fp); + if (acl_msg_verbose) + acl_msg_info("send attr name %s value %s", + ht[0]->key.c_key, (char*) ht[0]->value); + } + acl_myfree(ht_info_list); + break; + default: + acl_msg_panic("%s: unknown type code: %d", myname, attr_type); + } + } + if ((flags & ATTR_FLAG_MORE) == 0) + ACL_VSTREAM_PUTC('\n', fp); + return (acl_vstream_fflush(fp)); +} + +int attr_print64(ACL_VSTREAM *fp, int flags,...) +{ + va_list ap; + int ret; + + va_start(ap, flags); + ret = attr_vprint64(fp, flags, ap); + va_end(ap); + return (ret); +} + +#ifdef TEST + + /* + * Proof of concept test program. Mirror image of the attr_scan64 test + * program. + */ + +int main(int unused_argc, char **argv) +{ + ACL_HTABLE *table = acl_htable_create(1); + + acl_msg_verbose = 1; + acl_htable_enter(table, "foo-name", mystrdup("foo-value")); + acl_htable_enter(table, "bar-name", mystrdup("bar-value")); + attr_print64(ACL_VSTREAM_OUT, ATTR_FLAG_NONE, + ATTR_TYPE_INT, ATTR_NAME_INT, 4711, + ATTR_TYPE_LONG, ATTR_NAME_LONG, 1234, + ATTR_TYPE_STR, ATTR_NAME_STR, "whoopee", + ATTR_TYPE_DATA, ATTR_NAME_DATA, strlen("whoopee"), "whoopee", + ATTR_TYPE_HASH, table, + ATTR_TYPE_END); + attr_print64(ACL_VSTREAM_OUT, ATTR_FLAG_NONE, + ATTR_TYPE_INT, ATTR_NAME_INT, 4711, + ATTR_TYPE_LONG, ATTR_NAME_LONG, 1234, + ATTR_TYPE_STR, ATTR_NAME_STR, "whoopee", + ATTR_TYPE_DATA, ATTR_NAME_DATA, strlen("whoopee"), "whoopee", + ATTR_TYPE_END); + if (acl_vstream_fflush(ACL_VSTREAM_OUT) == ACL_VSTREAM_EOF) + acl_msg_fatal("%s: write error", __FUNCTION__); + + acl_htable_free(table, myfree); + return (0); +} + +#endif diff --git a/lib_tls/attr/attr_print_plain.c b/lib_tls/attr/attr_print_plain.c new file mode 100644 index 000000000..5fecf5837 --- /dev/null +++ b/lib_tls/attr/attr_print_plain.c @@ -0,0 +1,234 @@ +/*++ + * NAME + * attr_print_plain 3 + * SUMMARY + * send attributes over byte stream + * SYNOPSIS + * #include + * + * int attr_print_plain(fp, flags, type, name, ..., ATTR_TYPE_END) + * ACL_VSTREAM fp; + * int flags; + * int type; + * char *name; + * + * int attr_vprint_plain(fp, flags, ap) + * ACL_VSTREAM fp; + * int flags; + * va_list ap; + * DESCRIPTION + * attr_print_plain() takes zero or more (name, value) simple attributes + * and converts its input to a byte stream that can be recovered with + * attr_scan_plain(). The stream is not flushed. + * + * attr_vprint_plain() provides an alternate interface that is convenient + * for calling from within variadic functions. + * + * Attributes are sent in the requested order as specified with the + * attr_print_plain() argument list. This routine satisfies the formatting + * rules as outlined in attr_scan_plain(3). + * + * Arguments: + * .IP fp + * Stream to write the result to. + * .IP flags + * The bit-wise OR of zero or more of the following. + * .RS + * .IP ATTR_FLAG_MORE + * After sending the requested attributes, leave the output stream in + * a state that is usable for more attribute sending operations on + * the same output attribute list. + * By default, attr_print_plain() automatically appends an attribute list + * terminator when it has sent the last requested attribute. + * .RE + * .IP type + * The type determines the arguments that follow. + * .RS + * .IP "ATTR_TYPE_INT (char *, int)" + * This argument is followed by an attribute name and an integer. + * .IP "ATTR_TYPE_LONG (char *, long)" + * This argument is followed by an attribute name and a long integer. + * .IP "ATTR_TYPE_STR (char *, char *)" + * This argument is followed by an attribute name and a null-terminated + * string. + * .IP "ATTR_TYPE_DATA (char *, ssize_t, char *)" + * This argument is followed by an attribute name, an attribute value + * length, and a pointer to attribute value. + * .IP "ATTR_TYPE_FUNC (ATTR_PRINT_SLAVE_FN, void *)" + * This argument is followed by a function pointer and generic data + * pointer. The caller-specified function returns whatever the + * specified attribute printing function returns. + * .IP "ATTR_TYPE_HASH (ACL_HTABLE *)" + * .IP "ATTR_TYPE_NAMEVAL (NVTABLE *)" + * The content of the table is sent as a sequence of string-valued + * attributes with names equal to the table lookup keys. + * .IP ATTR_TYPE_END + * This terminates the attribute list. + * .RE + * DIAGNOSTICS + * The result value is 0 in case of success, ACL_VSTREAM_EOF in case + * of trouble. + * + * Panic: interface violation. All system call errors are fatal. + * SEE ALSO + * attr_scan_plain(3) recover attributes from byte stream + * LICENSE + * .ad + * .fi + * The Secure Mailer license must be distributed with this software. + * AUTHOR(S) + * Wietse Venema + * IBM T.J. Watson Research + * P.O. Box 704 + * Yorktown Heights, NY 10598, USA + *--*/ + +#include "StdAfx.h" +#include +#include + +#include "attr.h" + +#define STR(x) acl_vstring_str(x) +#define LEN(x) ACL_VSTRING_LEN(x) + +static void free_vstring(void *arg) +{ + ACL_VSTRING *s = (ACL_VSTRING*) arg; + + acl_vstring_free(s); +} + +/* attr_vprint_plain - send attribute list to stream */ + +int attr_vprint_plain(ACL_VSTREAM *fp, int flags, va_list ap) +{ + const char *myname = "attr_print_plain"; + int attr_type; + char *attr_name; + unsigned int_val; + unsigned long long_val; + char *str_val; + ACL_HTABLE_INFO **ht_info_list; + ACL_HTABLE_INFO **ht; + static __thread ACL_VSTRING *base64_buf; + ssize_t len_val; + ATTR_PRINT_SLAVE_FN print_fn; + void *print_arg; + + /* + * Sanity check. + */ + if (flags & ~ATTR_FLAG_ALL) + acl_msg_panic("%s: bad flags: 0x%x", myname, flags); + + /* + * Iterate over all (type, name, value) triples, and produce output on + * the fly. + */ + while ((attr_type = va_arg(ap, int)) != ATTR_TYPE_END) { + switch (attr_type) { + case ATTR_TYPE_INT: + attr_name = va_arg(ap, char *); + int_val = va_arg(ap, int); + acl_vstream_buffed_fprintf(fp, "%s=%u\n", attr_name, (unsigned) int_val); + if (acl_msg_verbose) + acl_msg_info("send attr %s = %u", attr_name, (unsigned) int_val); + break; + case ATTR_TYPE_LONG: + attr_name = va_arg(ap, char *); + long_val = va_arg(ap, long); + acl_vstream_buffed_fprintf(fp, "%s=%lu\n", attr_name, long_val); + if (acl_msg_verbose) + acl_msg_info("send attr %s = %lu", attr_name, long_val); + break; + case ATTR_TYPE_STR: + attr_name = va_arg(ap, char *); + str_val = va_arg(ap, char *); + acl_vstream_buffed_fprintf(fp, "%s=%s\n", attr_name, str_val); + if (acl_msg_verbose) + acl_msg_info("send attr %s = %s", attr_name, str_val); + break; + case ATTR_TYPE_DATA: + attr_name = va_arg(ap, char *); + len_val = va_arg(ap, ssize_t); + str_val = va_arg(ap, char *); + if (base64_buf == 0) { + base64_buf = acl_vstring_alloc(10); + acl_pthread_atexit_add(base64_buf, free_vstring); + } + acl_vstring_base64_encode(base64_buf, str_val, len_val); + acl_vstream_buffed_fprintf(fp, "%s=%s\n", attr_name, STR(base64_buf)); + if (acl_msg_verbose) + acl_msg_info("send attr %s = [data %ld bytes]", + attr_name, (long) len_val); + break; + case ATTR_TYPE_FUNC: + print_fn = va_arg(ap, ATTR_PRINT_SLAVE_FN); + print_arg = va_arg(ap, void *); + print_fn(attr_print_plain, fp, flags | ATTR_FLAG_MORE, print_arg); + break; + case ATTR_TYPE_HASH: + ht_info_list = acl_htable_list(va_arg(ap, ACL_HTABLE *)); + for (ht = ht_info_list; *ht; ht++) { + acl_vstream_buffed_fprintf(fp, "%s=%s\n", ht[0]->key.c_key, (char*) ht[0]->value); + if (acl_msg_verbose) + acl_msg_info("send attr name %s value %s", ht[0]->key.c_key, (char*) ht[0]->value); + } + acl_myfree(ht_info_list); + break; + default: + acl_msg_panic("%s: unknown type code: %d", myname, attr_type); + } + } + if ((flags & ATTR_FLAG_MORE) == 0) + ACL_VSTREAM_PUTC('\n', fp); + return (acl_vstream_fflush(fp)); +} + +int attr_print_plain(ACL_VSTREAM *fp, int flags,...) +{ + va_list ap; + int ret; + + va_start(ap, flags); + ret = attr_vprint_plain(fp, flags, ap); + va_end(ap); + return (ret); +} + +#ifdef TEST + + /* + * Proof of concept test program. Mirror image of the attr_scan_plain test + * program. + */ + +int main(int unused_argc, char **argv) +{ + ACL_HTABLE *table = acl_htable_create(1); + + acl_msg_verbose = 1; + acl_htable_enter(table, "foo-name", mystrdup("foo-value")); + acl_htable_enter(table, "bar-name", mystrdup("bar-value")); + attr_print_plain(ACL_VSTREAM_OUT, ATTR_FLAG_NONE, + ATTR_TYPE_INT, ATTR_NAME_INT, 4711, + ATTR_TYPE_LONG, ATTR_NAME_LONG, 1234, + ATTR_TYPE_STR, ATTR_NAME_STR, "whoopee", + ATTR_TYPE_DATA, ATTR_NAME_DATA, strlen("whoopee"), "whoopee", + ATTR_TYPE_HASH, table, + ATTR_TYPE_END); + attr_print_plain(ACL_VSTREAM_OUT, ATTR_FLAG_NONE, + ATTR_TYPE_INT, ATTR_NAME_INT, 4711, + ATTR_TYPE_LONG, ATTR_NAME_LONG, 1234, + ATTR_TYPE_STR, ATTR_NAME_STR, "whoopee", + ATTR_TYPE_DATA, ATTR_NAME_DATA, strlen("whoopee"), "whoopee", + ATTR_TYPE_END); + if (acl_vstream_fflush(ACL_VSTREAM_OUT) != 0) + acl_msg_fatal("%s: write error", __FUNCTION__); + + acl_htable_free(table, myfree); + return (0); +} + +#endif diff --git a/lib_tls/attr/attr_scan0.c b/lib_tls/attr/attr_scan0.c new file mode 100644 index 000000000..fec38e001 --- /dev/null +++ b/lib_tls/attr/attr_scan0.c @@ -0,0 +1,499 @@ +/*++ + * NAME + * attr_scan0 3 + * SUMMARY + * recover attributes from byte stream + * SYNOPSIS + * #include + * + * int attr_scan0(fp, flags, type, name, ..., ATTR_TYPE_END) + * ACL_VSTREAM fp; + * int flags; + * int type; + * char *name; + * + * int attr_vscan0(fp, flags, ap) + * ACL_VSTREAM fp; + * int flags; + * va_list ap; + * DESCRIPTION + * attr_scan0() takes zero or more (name, value) request attributes + * and recovers the attribute values from the byte stream that was + * possibly generated by attr_print0(). + * + * attr_vscan0() provides an alternative interface that is convenient + * for calling from within a variadic function. + * + * The input stream is formatted as follows, where (item)* stands + * for zero or more instances of the specified item, and where + * (item1 | item2) stands for choice: + * + * .in +5 + * attr-list :== simple-attr* null + * .br + * simple-attr :== attr-name null attr-value null + * .br + * attr-name :== any string not containing null + * .br + * attr-value :== any string not containing null + * .br + * null :== the ASCII null character + * .in + * + * All attribute names and attribute values are sent as null terminated + * strings. Each string must be no longer than 4*var_line_limit + * characters including the terminator. + * These formatting rules favor implementations in C. + * + * Normally, attributes must be received in the sequence as specified with + * the attr_scan0() argument list. The input stream may contain additional + * attributes at any point in the input stream, including additional + * instances of requested attributes. + * + * Additional input attributes or input attribute instances are silently + * skipped over, unless the ATTR_FLAG_EXTRA processing flag is specified + * (see below). This allows for some flexibility in the evolution of + * protocols while still providing the option of being strict where + * this is desirable. + * + * Arguments: + * .IP fp + * Stream to recover the input attributes from. + * .IP flags + * The bit-wise OR of zero or more of the following. + * .RS + * .IP ATTR_FLAG_MISSING + * Log a warning when the input attribute list terminates before all + * requested attributes are recovered. It is always an error when the + * input stream ends without the newline attribute list terminator. + * .IP ATTR_FLAG_EXTRA + * Log a warning and stop attribute recovery when the input stream + * contains an attribute that was not requested. This includes the + * case of additional instances of a requested attribute. + * .IP ATTR_FLAG_MORE + * After recovering the requested attributes, leave the input stream + * in a state that is usable for more attr_scan0() operations from the + * same input attribute list. + * By default, attr_scan0() skips forward past the input attribute list + * terminator. + * .IP ATTR_FLAG_STRICT + * For convenience, this value combines both ATTR_FLAG_MISSING and + * ATTR_FLAG_EXTRA. + * .IP ATTR_FLAG_NONE + * For convenience, this value requests none of the above. + * .RE + * .IP type + * The type argument determines the arguments that follow. + * .RS + * .IP "ATTR_TYPE_INT (char *, int *)" + * This argument is followed by an attribute name and an integer pointer. + * .IP "ATTR_TYPE_LONG (char *, long *)" + * This argument is followed by an attribute name and a long pointer. + * .IP "ATTR_TYPE_STR (char *, ACL_VSTRING *)" + * This argument is followed by an attribute name and a ACL_VSTRING pointer. + * .IP "ATTR_TYPE_DATA (char *, ACL_VSTRING *)" + * This argument is followed by an attribute name and a ACL_VSTRING pointer. + * .IP "ATTR_TYPE_FUNC (ATTR_SCAN_SLAVE_FN, void *)" + * This argument is followed by a function pointer and a generic data + * pointer. The caller-specified function returns < 0 in case of + * error. + * .IP "ATTR_TYPE_HASH (ACL_HTABLE *)" + * .IP "ATTR_TYPE_NAMEVAL (NVTABLE *)" + * All further input attributes are processed as string attributes. + * No specific attribute sequence is enforced. + * All attributes up to the attribute list terminator are read, + * but only the first instance of each attribute is stored. + * There can be no more than 1024 attributes in a hash table. + * .sp + * The attribute string values are stored in the hash table under + * keys equal to the attribute name (obtained from the input stream). + * Values from the input stream are added to the hash table. Existing + * hash table entries are not replaced. + * .sp + * N.B. This construct must be followed by an ATTR_TYPE_END argument. + * .IP ATTR_TYPE_END + * This argument terminates the requested attribute list. + * .RE + * BUGS + * ATTR_TYPE_HASH (ATTR_TYPE_NAMEVAL) accepts attributes with arbitrary + * names from possibly untrusted sources. + * This is unsafe, unless the resulting table is queried only with + * known to be good attribute names. + * DIAGNOSTICS + * attr_scan0() and attr_vscan0() return -1 when malformed input is + * detected (string too long, incomplete line, missing end marker). + * Otherwise, the result value is the number of attributes that were + * successfully recovered from the input stream (a hash table counts + * as the number of entries stored into the table). + * + * Panic: interface violation. All system call errors are fatal. + * SEE ALSO + * attr_print0(3) send attributes over byte stream. + * LICENSE + * .ad + * .fi + * The Secure Mailer license must be distributed with this software. + * AUTHOR(S) + * Wietse Venema + * IBM T.J. Watson Research + * P.O. Box 704 + * Yorktown Heights, NY 10598, USA +*--*/ + +#include "StdAfx.h" +#include +#include +#include + +#include "attr.h" + +/* Application specific. */ + +#define STR(x) acl_vstring_str(x) +#define LEN(x) ACL_VSTRING_LEN(x) + +static void free_vstring(void *arg) +{ + ACL_VSTRING *s = (ACL_VSTRING*) arg; + + acl_vstring_free(s); +} + +/* attr_scan0_string - pull a string from the input stream */ + +static int attr_scan0_string(ACL_VSTREAM *fp, ACL_VSTRING *plain_buf, const char *context) +{ + const char *myname = "attr_scan0_string"; + int ch; + + if ((ch = acl_vstring_gets_null(plain_buf, fp)) == ACL_VSTREAM_EOF) { + acl_msg_warn("%s: %s on %s while reading %s", + myname, acl_vstream_ftimeout(fp) ? "timeout" : "premature end-of-input", + ACL_VSTREAM_PATH(fp), context); + return (-1); + } + if (ch != 0) { + acl_msg_warn("%s: unexpected end-of-input from %s while reading %s", + myname, ACL_VSTREAM_PATH(fp), context); + return (-1); + } + if (acl_msg_verbose) + acl_msg_info("%s: %s: %s", myname, context, *STR(plain_buf) ? STR(plain_buf) : "(end)"); + return (ch); +} + +/* attr_scan0_data - pull a data blob from the input stream */ + +static int attr_scan0_data(ACL_VSTREAM *fp, ACL_VSTRING *str_buf, + const char *context) +{ + const char *myname = "attr_scan0_data"; + static __thread ACL_VSTRING *base64_buf = 0; + int ch; + + if (base64_buf == 0) { + base64_buf = acl_vstring_alloc(10); + acl_pthread_atexit_add(base64_buf, free_vstring); + } + if ((ch = attr_scan0_string(fp, base64_buf, context)) < 0) + return (-1); + if (acl_vstring_base64_decode(str_buf, STR(base64_buf), (int) LEN(base64_buf)) == 0) { + acl_msg_warn("%s: malformed base64 data from %s while reading %s: %.100s", + myname, ACL_VSTREAM_PATH(fp), context, STR(base64_buf)); + return (-1); + } + return (ch); +} + +/* attr_scan0_number - pull a number from the input stream */ + +static int attr_scan0_number(ACL_VSTREAM *fp, unsigned *ptr, + ACL_VSTRING *str_buf, const char *context) +{ + const char *myname = "attr_scan0_number"; + char junk = 0; + int ch; + + if ((ch = attr_scan0_string(fp, str_buf, context)) < 0) + return (-1); + if (sscanf(STR(str_buf), "%u%c", ptr, &junk) != 1 || junk != 0) { + acl_msg_warn("%s: malformed numerical data from %s while reading %s: %.100s", + myname, ACL_VSTREAM_PATH(fp), context, STR(str_buf)); + return (-1); + } + return (ch); +} + +/* attr_scan0_long_number - pull a number from the input stream */ + +static int attr_scan0_long_number(ACL_VSTREAM *fp, unsigned long *ptr, + ACL_VSTRING *str_buf, const char *context) +{ + const char *myname = "attr_scan0_long_number"; + char junk = 0; + int ch; + + if ((ch = attr_scan0_string(fp, str_buf, context)) < 0) + return (-1); + if (sscanf(STR(str_buf), "%lu%c", ptr, &junk) != 1 || junk != 0) { + acl_msg_warn("%s: malformed numerical data from %s while reading %s: %.100s", + myname, ACL_VSTREAM_PATH(fp), context, STR(str_buf)); + return (-1); + } + return (ch); +} + +/* attr_vscan0 - receive attribute list from stream */ + +int attr_vscan0(ACL_VSTREAM *fp, int flags, va_list ap) +{ + const char *myname = "attr_scan0"; + static __thread ACL_VSTRING *str_buf = 0; + static __thread ACL_VSTRING *name_buf = 0; + int wanted_type = -1; + char *wanted_name = 0; + unsigned int *number; + unsigned long *long_number; + ACL_VSTRING *string; + ACL_HTABLE *hash_table = 0; + int ch; + int conversions; + ATTR_SCAN_SLAVE_FN scan_fn; + void *scan_arg; + + /* + * Sanity check. + */ + if (flags & ~ATTR_FLAG_ALL) + acl_msg_panic("%s: bad flags: 0x%x", myname, flags); + + /* + * EOF check. + */ + if ((ch = ACL_VSTREAM_GETC(fp)) == ACL_VSTREAM_EOF) + return (0); + acl_vstream_ungetc(fp, ch); + + /* + * Initialize. + */ + if (str_buf == 0) { + str_buf = acl_vstring_alloc(10); + name_buf = acl_vstring_alloc(10); + acl_pthread_atexit_add(str_buf, free_vstring); + acl_pthread_atexit_add(name_buf, free_vstring); + } + + /* + * Iterate over all (type, name, value) triples. + */ + for (conversions = 0; /* void */ ; conversions++) { + + /* + * Determine the next attribute type and attribute name on the + * caller's wish list. + * + * If we're reading into a hash table, we already know that the + * attribute value is string-valued, and we get the attribute name + * from the input stream instead. This is secure only when the + * resulting table is queried with known to be good attribute names. + */ + if (wanted_type != ATTR_TYPE_HASH) { + wanted_type = va_arg(ap, int); + if (wanted_type == ATTR_TYPE_END) { + if ((flags & ATTR_FLAG_MORE) != 0) + return (conversions); + wanted_name = "(list terminator)"; + } else if (wanted_type == ATTR_TYPE_HASH) { + wanted_name = "(any attribute name or list terminator)"; + hash_table = va_arg(ap, ACL_HTABLE *); + if (va_arg(ap, int) != ATTR_TYPE_END) + acl_msg_panic("%s: ATTR_TYPE_HASH not followed by ATTR_TYPE_END", + myname); + } else if (wanted_type != ATTR_TYPE_FUNC) { + wanted_name = va_arg(ap, char *); + } + } + + /* + * Locate the next attribute of interest in the input stream. + */ + while (wanted_type != ATTR_TYPE_FUNC) { + + /* + * Get the name of the next attribute. Hitting EOF is always bad. + * Hitting the end-of-input early is OK if the caller is prepared + * to deal with missing inputs. + */ + if (acl_msg_verbose) + acl_msg_info("%s: wanted attribute: %s", + ACL_VSTREAM_PATH(fp), wanted_name); + if ((ch = attr_scan0_string(fp, name_buf, + "input attribute name")) < 0) + return (-1); + if (LEN(name_buf) == 0) { + if (wanted_type == ATTR_TYPE_END + || wanted_type == ATTR_TYPE_HASH) + return (conversions); + if ((flags & ATTR_FLAG_MISSING) != 0) + acl_msg_warn("%s: missing attribute %s in input from %s", + myname, wanted_name, ACL_VSTREAM_PATH(fp)); + return (conversions); + } + + /* + * See if the caller asks for this attribute. + */ + if (wanted_type == ATTR_TYPE_HASH + || (wanted_type != ATTR_TYPE_END + && strcmp(wanted_name, STR(name_buf)) == 0)) + break; + if ((flags & ATTR_FLAG_EXTRA) != 0) { + acl_msg_warn("%s: unexpected attribute %s from %s (expecting: %s)", + myname, STR(name_buf), ACL_VSTREAM_PATH(fp), wanted_name); + return (conversions); + } + + /* + * Skip over this attribute. The caller does not ask for it. + */ + (void) attr_scan0_string(fp, str_buf, "input attribute value"); + } + + /* + * Do the requested conversion. + */ + switch (wanted_type) { + case ATTR_TYPE_INT: + number = va_arg(ap, unsigned int *); + if ((ch = attr_scan0_number(fp, number, str_buf, "input attribute value")) < 0) + return (-1); + break; + case ATTR_TYPE_LONG: + long_number = va_arg(ap, unsigned long *); + if ((ch = attr_scan0_long_number(fp, long_number, str_buf, "input attribute value")) < 0) + return (-1); + break; + case ATTR_TYPE_STR: + string = va_arg(ap, ACL_VSTRING *); + if ((ch = attr_scan0_string(fp, string, "input attribute value")) < 0) + return (-1); + break; + case ATTR_TYPE_DATA: + string = va_arg(ap, ACL_VSTRING *); + if ((ch = attr_scan0_data(fp, string, "input attribute value")) < 0) + return (-1); + break; + case ATTR_TYPE_FUNC: + scan_fn = va_arg(ap, ATTR_SCAN_SLAVE_FN); + scan_arg = va_arg(ap, void *); + if (scan_fn(attr_scan0, fp, flags | ATTR_FLAG_MORE, scan_arg) < 0) + return (-1); + break; + case ATTR_TYPE_HASH: + if ((ch = attr_scan0_string(fp, str_buf, + "input attribute value")) < 0) + return (-1); + if (acl_htable_locate(hash_table, STR(name_buf)) != 0) { + if ((flags & ATTR_FLAG_EXTRA) != 0) { + acl_msg_warn("%s: duplicate attribute %s in input from %s", + myname, STR(name_buf), ACL_VSTREAM_PATH(fp)); + return (conversions); + } + } else if (acl_htable_used(hash_table) >= ATTR_HASH_LIMIT) { + acl_msg_warn("%s: attribute count exceeds limit %d in input from %s", + myname, ATTR_HASH_LIMIT, ACL_VSTREAM_PATH(fp)); + return (conversions); + } else { + acl_htable_enter(hash_table, STR(name_buf), + acl_mystrdup(STR(str_buf))); + } + break; + default: + acl_msg_panic("%s: unknown type code: %d", myname, wanted_type); + } + } +} + +/* attr_scan0 - read attribute list from stream */ + +int attr_scan0(ACL_VSTREAM *fp, int flags,...) +{ + va_list ap; + int ret; + + va_start(ap, flags); + ret = attr_vscan0(fp, flags, ap); + va_end(ap); + return (ret); +} + +#ifdef TEST + + /* + * Proof of concept test program. Mirror image of the attr_scan0 test + * program. + */ + +int var_line_limit = 2048; + +int main(int unused_argc, char **used_argv) +{ + ACL_VSTRING *data_val = acl_vstring_alloc(1); + ACL_VSTRING *str_val = acl_vstring_alloc(1); + ACL_HTABLE *table = acl_htable_create(1); + ACL_HTABLE_INFO **ht_info_list; + ACL_HTABLE_INFO **ht; + int int_val; + long long_val; + int ret; + + acl_msg_verbose = 1; + if ((ret = attr_scan0(ACL_VSTREAM_IN, + ATTR_FLAG_STRICT, + ATTR_TYPE_INT, ATTR_NAME_INT, &int_val, + ATTR_TYPE_LONG, ATTR_NAME_LONG, &long_val, + ATTR_TYPE_STR, ATTR_NAME_STR, str_val, + ATTR_TYPE_DATA, ATTR_NAME_DATA, data_val, + ATTR_TYPE_HASH, table, + ATTR_TYPE_END)) > 4) { + acl_vstream_printf("%s %d\n", ATTR_NAME_INT, int_val); + acl_vstream_printf("%s %ld\n", ATTR_NAME_LONG, long_val); + acl_vstream_printf("%s %s\n", ATTR_NAME_STR, STR(str_val)); + acl_vstream_printf("%s %s\n", ATTR_NAME_DATA, STR(str_val)); + ht_info_list = acl_htable_list(table); + for (ht = ht_info_list; *ht; ht++) + acl_vstream_printf("(hash) %s %s\n", ht[0]->key, ht[0]->value); + acl_myfree((char *) ht_info_list); + } else { + acl_vstream_printf("return: %d\n", ret); + } + if ((ret = attr_scan0(ACL_VSTREAM_IN, + ATTR_FLAG_STRICT, + ATTR_TYPE_INT, ATTR_NAME_INT, &int_val, + ATTR_TYPE_LONG, ATTR_NAME_LONG, &long_val, + ATTR_TYPE_STR, ATTR_NAME_STR, str_val, + ATTR_TYPE_DATA, ATTR_NAME_DATA, data_val, + ATTR_TYPE_END)) == 4) { + acl_vstream_printf("%s %d\n", ATTR_NAME_INT, int_val); + acl_vstream_printf("%s %ld\n", ATTR_NAME_LONG, long_val); + acl_vstream_printf("%s %s\n", ATTR_NAME_STR, STR(str_val)); + acl_vstream_printf("%s %s\n", ATTR_NAME_DATA, STR(data_val)); + ht_info_list = acl_htable_list(table); + for (ht = ht_info_list; *ht; ht++) + acl_vstream_printf("(hash) %s %s\n", ht[0]->key, ht[0]->value); + acl_myfree((char *) ht_info_list); + } else { + acl_vstream_printf("return: %d\n", ret); + } + if (acl_vstream_fflush(ACL_VSTREAM_OUT) == ACL_VSTREAM_EOF) + acl_msg_fatal("%s: write error: %s", __FUNCTION__, acl_last_serror()); + + acl_vstring_free(data_val); + acl_vstring_free(str_val); + acl_htable_free(table, myfree); + + return (0); +} + +#endif diff --git a/lib_tls/attr/attr_scan64.c b/lib_tls/attr/attr_scan64.c new file mode 100644 index 000000000..5698b9a52 --- /dev/null +++ b/lib_tls/attr/attr_scan64.c @@ -0,0 +1,564 @@ +/*++ + * NAME + * attr_scan64 3 + * SUMMARY + * recover attributes from byte stream + * SYNOPSIS + * #include + * + * int attr_scan64(fp, flags, type, name, ..., ATTR_TYPE_END) + * ACL_VSTREAM fp; + * int flags; + * int type; + * char *name; + * + * int attr_vscan64(fp, flags, ap) + * ACL_VSTREAM fp; + * int flags; + * va_list ap; + * DESCRIPTION + * attr_scan64() takes zero or more (name, value) request attributes + * and recovers the attribute values from the byte stream that was + * possibly generated by attr_print64(). + * + * attr_vscan64() provides an alternative interface that is convenient + * for calling from within a variadic function. + * + * The input stream is formatted as follows, where (item)* stands + * for zero or more instances of the specified item, and where + * (item1 | item2) stands for choice: + * + * .in +5 + * attr-list :== simple-attr* newline + * .br + * simple-attr :== attr-name colon attr-value newline + * .br + * attr-name :== any base64 encoded string + * .br + * attr-value :== any base64 encoded string + * .br + * colon :== the ASCII colon character + * .br + * newline :== the ASCII newline character + * .in + * + * All attribute names and attribute values are sent as base64-encoded + * strings. Each base64 encoding must be no longer than 4*var_line_limit + * characters. The formatting rules aim to make implementations in PERL + * and other languages easy. + * + * Normally, attributes must be received in the sequence as specified with + * the attr_scan64() argument list. The input stream may contain additional + * attributes at any point in the input stream, including additional + * instances of requested attributes. + * + * Additional input attributes or input attribute instances are silently + * skipped over, unless the ATTR_FLAG_EXTRA processing flag is specified + * (see below). This allows for some flexibility in the evolution of + * protocols while still providing the option of being strict where + * this is desirable. + * + * Arguments: + * .IP fp + * Stream to recover the input attributes from. + * .IP flags + * The bit-wise OR of zero or more of the following. + * .RS + * .IP ATTR_FLAG_MISSING + * Log a warning when the input attribute list terminates before all + * requested attributes are recovered. It is always an error when the + * input stream ends without the newline attribute list terminator. + * .IP ATTR_FLAG_EXTRA + * Log a warning and stop attribute recovery when the input stream + * contains an attribute that was not requested. This includes the + * case of additional instances of a requested attribute. + * .IP ATTR_FLAG_MORE + * After recovering the requested attributes, leave the input stream + * in a state that is usable for more attr_scan64() operations from the + * same input attribute list. + * By default, attr_scan64() skips forward past the input attribute list + * terminator. + * .IP ATTR_FLAG_STRICT + * For convenience, this value combines both ATTR_FLAG_MISSING and + * ATTR_FLAG_EXTRA. + * .IP ATTR_FLAG_NONE + * For convenience, this value requests none of the above. + * .RE + * .IP type + * The type argument determines the arguments that follow. + * .RS + * .IP "ATTR_TYPE_INT (char *, int *)" + * This argument is followed by an attribute name and an integer pointer. + * .IP "ATTR_TYPE_LONG (char *, long *)" + * This argument is followed by an attribute name and a long pointer. + * .IP "ATTR_TYPE_STR (char *, ACL_VSTRING *)" + * This argument is followed by an attribute name and a ACL_VSTRING pointer. + * .IP "ATTR_TYPE_DATA (char *, ACL_VSTRING *)" + * This argument is followed by an attribute name and a ACL_VSTRING pointer. + * .IP "ATTR_TYPE_FUNC (ATTR_SCAN_SLAVE_FN, void *)" + * This argument is followed by a function pointer and a generic data + * pointer. The caller-specified function returns < 0 in case of + * error. + * .IP "ATTR_TYPE_HASH (ACL_HTABLE *)" + * .IP "ATTR_TYPE_NAMEVAL (NVTABLE *)" + * All further input attributes are processed as string attributes. + * No specific attribute sequence is enforced. + * All attributes up to the attribute list terminator are read, + * but only the first instance of each attribute is stored. + * There can be no more than 1024 attributes in a hash table. + * .sp + * The attribute string values are stored in the hash table under + * keys equal to the attribute name (obtained from the input stream). + * Values from the input stream are added to the hash table. Existing + * hash table entries are not replaced. + * .sp + * N.B. This construct must be followed by an ATTR_TYPE_END argument. + * .IP ATTR_TYPE_END + * This argument terminates the requested attribute list. + * .RE + * BUGS + * ATTR_TYPE_HASH (ATTR_TYPE_NAMEVAL) accepts attributes with arbitrary + * names from possibly untrusted sources. + * This is unsafe, unless the resulting table is queried only with + * known to be good attribute names. + * DIAGNOSTICS + * attr_scan64() and attr_vscan64() return -1 when malformed input is + * detected (string too long, incomplete line, missing end marker). + * Otherwise, the result value is the number of attributes that were + * successfully recovered from the input stream (a hash table counts + * as the number of entries stored into the table). + * + * Panic: interface violation. All system call errors are fatal. + * SEE ALSO + * attr_print64(3) send attributes over byte stream. + * LICENSE + * .ad + * .fi + * The Secure Mailer license must be distributed with this software. + * AUTHOR(S) + * Wietse Venema + * IBM T.J. Watson Research + * P.O. Box 704 + * Yorktown Heights, NY 10598, USA + *--*/ + +#include "StdAfx.h" +#include +#include +#include + +#include "attr.h" + +/* Application specific. */ + +#define STR(x) acl_vstring_str(x) +#define LEN(x) ACL_VSTRING_LEN(x) + +static void free_vstring_fn(void *arg) +{ + ACL_VSTRING *s = (ACL_VSTRING*) arg; + + acl_vstring_free(s); +} + +/* attr_scan64_string - pull a string from the input stream */ + +static int attr_scan64_string(ACL_VSTREAM *fp, ACL_VSTRING *plain_buf, const char *context) +{ + const char *myname = "attr_scan64_string"; + static __thread ACL_VSTRING *base64_buf = 0; + +#if 0 + extern int var_line_limit; /* XXX */ + int limit = var_line_limit * 4; + +#endif + int ch; + + if (base64_buf == 0) { + base64_buf = acl_vstring_alloc(10); + acl_pthread_atexit_add(base64_buf, free_vstring_fn); + } + + ACL_VSTRING_RESET(base64_buf); + while ((ch = ACL_VSTREAM_GETC(fp)) != ':' && ch != '\n') { + if (ch == ACL_VSTREAM_EOF) { + acl_msg_warn("%s: %s on %s while reading %s", + myname, acl_vstream_ftimeout(fp) ? "timeout" : "premature end-of-input", + ACL_VSTREAM_PATH(fp), context); + return (-1); + } + ACL_VSTRING_ADDCH(base64_buf, ch); +#if 0 + if (LEN(base64_buf) > limit) { + acl_msg_warn("%s: string length > %d characters from %s while reading %s", + myname, limit, ACL_VSTREAM_PATH(fp), context); + return (-1); + } +#endif + } + ACL_VSTRING_TERMINATE(base64_buf); + if (acl_vstring_base64_decode(plain_buf, STR(base64_buf), (int) LEN(base64_buf)) == 0) { + acl_msg_warn("%s: malformed base64 data from %s: %.100s", + myname, ACL_VSTREAM_PATH(fp), STR(base64_buf)); + return (-1); + } + if (acl_msg_verbose) + acl_msg_info("%s: %s", context, *STR(plain_buf) ? STR(plain_buf) : "(end)"); + return (ch); +} + +/* attr_scan64_number - pull a number from the input stream */ + +static int attr_scan64_number(ACL_VSTREAM *fp, unsigned *ptr, + ACL_VSTRING *str_buf, const char *context) +{ + const char *myname = "attr_scan64_number"; + char junk = 0; + int ch; + + if ((ch = attr_scan64_string(fp, str_buf, context)) < 0) + return (-1); + if (sscanf(STR(str_buf), "%u%c", ptr, &junk) != 1 || junk != 0) { + acl_msg_warn("%s: malformed numerical data from %s while reading %s: %.100s", + myname, ACL_VSTREAM_PATH(fp), context, STR(str_buf)); + return (-1); + } + return (ch); +} + +/* attr_scan64_long_number - pull a number from the input stream */ + +static int attr_scan64_long_number(ACL_VSTREAM *fp, unsigned long *ptr, + ACL_VSTRING *str_buf, const char *context) +{ + const char *myname = "attr_scan64_long_number"; + char junk = 0; + int ch; + + if ((ch = attr_scan64_string(fp, str_buf, context)) < 0) + return (-1); + if (sscanf(STR(str_buf), "%lu%c", ptr, &junk) != 1 || junk != 0) { + acl_msg_warn("%s: malformed numerical data from %s while reading %s: %.100s", + myname, ACL_VSTREAM_PATH(fp), context, STR(str_buf)); + return (-1); + } + return (ch); +} + +/* attr_vscan64 - receive attribute list from stream */ + +int attr_vscan64(ACL_VSTREAM *fp, int flags, va_list ap) +{ + const char *myname = "attr_scan64"; + static __thread ACL_VSTRING *str_buf = 0; + static __thread ACL_VSTRING *name_buf = 0; + int wanted_type = -1; + char *wanted_name = 0; + unsigned int *number; + unsigned long *long_number; + ACL_VSTRING *string; + ACL_HTABLE *hash_table = 0; + int ch; + int conversions; + ATTR_SCAN_SLAVE_FN scan_fn; + void *scan_arg; + + /* + * Sanity check. + */ + if (flags & ~ATTR_FLAG_ALL) + acl_msg_panic("%s: bad flags: 0x%x", myname, flags); + + /* + * EOF check. + */ + if ((ch = ACL_VSTREAM_GETC(fp)) == ACL_VSTREAM_EOF) + return (0); + acl_vstream_ungetc(fp, ch); + + /* + * Initialize. + */ + if (str_buf == 0) { + str_buf = acl_vstring_alloc(10); + name_buf = acl_vstring_alloc(10); + acl_pthread_atexit_add(str_buf, free_vstring_fn); + acl_pthread_atexit_add(name_buf, free_vstring_fn); + } + + /* + * Iterate over all (type, name, value) triples. + */ + for (conversions = 0; /* void */ ; conversions++) { + + /* + * Determine the next attribute type and attribute name on the + * caller's wish list. + * + * If we're reading into a hash table, we already know that the + * attribute value is string-valued, and we get the attribute name + * from the input stream instead. This is secure only when the + * resulting table is queried with known to be good attribute names. + */ + if (wanted_type != ATTR_TYPE_HASH) { + wanted_type = va_arg(ap, int); + if (wanted_type == ATTR_TYPE_END) { + if ((flags & ATTR_FLAG_MORE) != 0) + return (conversions); + wanted_name = "(list terminator)"; + } else if (wanted_type == ATTR_TYPE_HASH) { + wanted_name = "(any attribute name or list terminator)"; + hash_table = va_arg(ap, ACL_HTABLE *); + if (va_arg(ap, int) != ATTR_TYPE_END) + acl_msg_panic("%s: ATTR_TYPE_HASH not followed by ATTR_TYPE_END", + myname); + } else if (wanted_type != ATTR_TYPE_FUNC) { + wanted_name = va_arg(ap, char *); + } + } + + /* + * Locate the next attribute of interest in the input stream. + */ + while (wanted_type != ATTR_TYPE_FUNC) { + + /* + * Get the name of the next attribute. Hitting EOF is always bad. + * Hitting the end-of-input early is OK if the caller is prepared + * to deal with missing inputs. + */ + if (acl_msg_verbose) + acl_msg_info("%s: wanted attribute: %s", + ACL_VSTREAM_PATH(fp), wanted_name); + if ((ch = attr_scan64_string(fp, name_buf, + "input attribute name")) == ACL_VSTREAM_EOF) + return (-1); + if (ch == '\n' && LEN(name_buf) == 0) { + if (wanted_type == ATTR_TYPE_END + || wanted_type == ATTR_TYPE_HASH) + return (conversions); + if ((flags & ATTR_FLAG_MISSING) != 0) + acl_msg_warn("%s: missing attribute %s in input from %s", + myname, wanted_name, ACL_VSTREAM_PATH(fp)); + return (conversions); + } + + /* + * See if the caller asks for this attribute. + */ + if (wanted_type == ATTR_TYPE_HASH + || (wanted_type != ATTR_TYPE_END + && strcmp(wanted_name, STR(name_buf)) == 0)) + break; + if ((flags & ATTR_FLAG_EXTRA) != 0) { + acl_msg_warn("%s: unexpected attribute %s from %s (expecting: %s)", + myname, STR(name_buf), ACL_VSTREAM_PATH(fp), wanted_name); + return (conversions); + } + + /* + * Skip over this attribute. The caller does not ask for it. + */ + while (ch != '\n' && (ch = ACL_VSTREAM_GETC(fp)) != ACL_VSTREAM_EOF) + /* void */ ; + } + + /* + * Do the requested conversion. If the target attribute is a + * non-array type, disallow sending a multi-valued attribute, and + * disallow sending no value. If the target attribute is an array + * type, allow the sender to send a zero-element array (i.e. no value + * at all). XXX Need to impose a bound on the number of array + * elements. + */ + switch (wanted_type) { + case ATTR_TYPE_INT: + if (ch != ':') { + acl_msg_warn("%s: missing value for number attribute %s from %s", + myname, STR(name_buf), ACL_VSTREAM_PATH(fp)); + return (-1); + } + number = va_arg(ap, unsigned int *); + if ((ch = attr_scan64_number(fp, number, str_buf, + "input attribute value")) < 0) + return (-1); + if (ch != '\n') { + acl_msg_warn("%s: multiple values for attribute %s from %s", + myname, STR(name_buf), ACL_VSTREAM_PATH(fp)); + return (-1); + } + break; + case ATTR_TYPE_LONG: + if (ch != ':') { + acl_msg_warn("%s: missing value for number attribute %s from %s", + myname, STR(name_buf), ACL_VSTREAM_PATH(fp)); + return (-1); + } + long_number = va_arg(ap, unsigned long *); + if ((ch = attr_scan64_long_number(fp, long_number, str_buf, + "input attribute value")) < 0) + return (-1); + if (ch != '\n') { + acl_msg_warn("%s: multiple values for attribute %s from %s", + myname, STR(name_buf), ACL_VSTREAM_PATH(fp)); + return (-1); + } + break; + case ATTR_TYPE_STR: + if (ch != ':') { + acl_msg_warn("%s: missing value for string attribute %s from %s", + myname, STR(name_buf), ACL_VSTREAM_PATH(fp)); + return (-1); + } + string = va_arg(ap, ACL_VSTRING *); + if ((ch = attr_scan64_string(fp, string, + "input attribute value")) < 0) + return (-1); + if (ch != '\n') { + acl_msg_warn("%s: multiple values for attribute %s from %s", + myname, STR(name_buf), ACL_VSTREAM_PATH(fp)); + return (-1); + } + break; + case ATTR_TYPE_DATA: + if (ch != ':') { + acl_msg_warn("%s: missing value for data attribute %s from %s", + myname, STR(name_buf), ACL_VSTREAM_PATH(fp)); + return (-1); + } + string = va_arg(ap, ACL_VSTRING *); + if ((ch = attr_scan64_string(fp, string, + "input attribute value")) < 0) + return (-1); + if (ch != '\n') { + acl_msg_warn("%s: multiple values for attribute %s from %s", + myname, STR(name_buf), ACL_VSTREAM_PATH(fp)); + return (-1); + } + break; + case ATTR_TYPE_FUNC: + scan_fn = va_arg(ap, ATTR_SCAN_SLAVE_FN); + scan_arg = va_arg(ap, void *); + if (scan_fn(attr_scan64, fp, flags | ATTR_FLAG_MORE, scan_arg) < 0) + return (-1); + break; + case ATTR_TYPE_HASH: + if (ch != ':') { + acl_msg_warn("%s: missing value for string attribute %s from %s", + myname, STR(name_buf), ACL_VSTREAM_PATH(fp)); + return (-1); + } + if ((ch = attr_scan64_string(fp, str_buf, + "input attribute value")) < 0) + return (-1); + if (ch != '\n') { + acl_msg_warn("%s: multiple values for attribute %s from %s", + myname, STR(name_buf), ACL_VSTREAM_PATH(fp)); + return (-1); + } + if (acl_htable_locate(hash_table, STR(name_buf)) != 0) { + if ((flags & ATTR_FLAG_EXTRA) != 0) { + acl_msg_warn("%s: duplicate attribute %s in input from %s", + myname, STR(name_buf), ACL_VSTREAM_PATH(fp)); + return (conversions); + } + } else if (acl_htable_used(hash_table) >= ATTR_HASH_LIMIT) { + acl_msg_warn("%s: attribute count exceeds limit %d in input from %s", + myname, ATTR_HASH_LIMIT, ACL_VSTREAM_PATH(fp)); + return (conversions); + } else { + acl_htable_enter(hash_table, STR(name_buf), + acl_mystrdup(STR(str_buf))); + } + break; + default: + acl_msg_panic("%s: unknown type code: %d", myname, wanted_type); + } + } +} + +/* attr_scan64 - read attribute list from stream */ + +int attr_scan64(ACL_VSTREAM *fp, int flags,...) +{ + va_list ap; + int ret; + + va_start(ap, flags); + ret = attr_vscan64(fp, flags, ap); + va_end(ap); + return (ret); +} + +#ifdef TEST + + /* + * Proof of concept test program. Mirror image of the attr_scan64 test + * program. + */ +#include + +int var_line_limit = 2048; + +int main(int unused_argc, char **used_argv) +{ + ACL_VSTRING *data_val = acl_vstring_alloc(1); + ACL_VSTRING *str_val = acl_vstring_alloc(1); + ACL_HTABLE *table = acl_htable_create(1); + ACL_HTABLE_INFO **ht_info_list; + ACL_HTABLE_INFO **ht; + int int_val; + long long_val; + int ret; + + acl_msg_verbose = 1; + acl_msg_acl_vstream_init(used_argv[0], ACL_VSTREAM_ERR); + if ((ret = attr_scan64(ACL_VSTREAM_IN, + ATTR_FLAG_STRICT, + ATTR_TYPE_INT, ATTR_NAME_INT, &int_val, + ATTR_TYPE_LONG, ATTR_NAME_LONG, &long_val, + ATTR_TYPE_STR, ATTR_NAME_STR, str_val, + ATTR_TYPE_DATA, ATTR_NAME_DATA, data_val, + ATTR_TYPE_HASH, table, + ATTR_TYPE_END)) > 4) { + acl_vstream_printf("%s %d\n", ATTR_NAME_INT, int_val); + acl_vstream_printf("%s %ld\n", ATTR_NAME_LONG, long_val); + acl_vstream_printf("%s %s\n", ATTR_NAME_STR, STR(str_val)); + acl_vstream_printf("%s %s\n", ATTR_NAME_DATA, STR(data_val)); + ht_info_list = acl_htable_list(table); + for (ht = ht_info_list; *ht; ht++) + acl_vstream_printf("(hash) %s %s\n", ht[0]->key, ht[0]->value); + myfree((char *) ht_info_list); + } else { + acl_vstream_printf("return: %d\n", ret); + } + if ((ret = attr_scan64(ACL_VSTREAM_IN, + ATTR_FLAG_STRICT, + ATTR_TYPE_INT, ATTR_NAME_INT, &int_val, + ATTR_TYPE_LONG, ATTR_NAME_LONG, &long_val, + ATTR_TYPE_STR, ATTR_NAME_STR, str_val, + ATTR_TYPE_DATA, ATTR_NAME_DATA, data_val, + ATTR_TYPE_END)) == 4) { + acl_vstream_printf("%s %d\n", ATTR_NAME_INT, int_val); + acl_vstream_printf("%s %ld\n", ATTR_NAME_LONG, long_val); + acl_vstream_printf("%s %s\n", ATTR_NAME_STR, STR(str_val)); + acl_vstream_printf("%s %s\n", ATTR_NAME_DATA, STR(data_val)); + ht_info_list = acl_htable_list(table); + for (ht = ht_info_list; *ht; ht++) + acl_vstream_printf("(hash) %s %s\n", ht[0]->key, ht[0]->value); + myfree((char *) ht_info_list); + } else { + acl_vstream_printf("return: %d\n", ret); + } + if (acl_vstream_fflush(ACL_VSTREAM_OUT) != 0) + acl_msg_fatal("%s: write error: %s", __FUNCTION__, acl_last_serror()); + + acl_vstring_free(data_val); + acl_vstring_free(str_val); + acl_htable_free(table, myfree); + + return (0); +} + +#endif diff --git a/lib_tls/attr/attr_scan_plain.c b/lib_tls/attr/attr_scan_plain.c new file mode 100644 index 000000000..c9c694491 --- /dev/null +++ b/lib_tls/attr/attr_scan_plain.c @@ -0,0 +1,546 @@ +/*++ + * NAME + * attr_scan_plain 3 + * SUMMARY + * recover attributes from byte stream + * SYNOPSIS + * #include + * + * int attr_scan_plain(fp, flags, type, name, ..., ATTR_TYPE_END) + * ACL_VSTREAM fp; + * int flags; + * int type; + * char *name; + * + * int attr_vscan_plain(fp, flags, ap) + * ACL_VSTREAM fp; + * int flags; + * va_list ap; + * DESCRIPTION + * attr_scan_plain() takes zero or more (name, value) request attributes + * and recovers the attribute values from the byte stream that was + * possibly generated by attr_print_plain(). + * + * attr_vscan_plain() provides an alternative interface that is convenient + * for calling from within a variadic function. + * + * The input stream is formatted as follows, where (item)* stands + * for zero or more instances of the specified item, and where + * (item1 | item2) stands for choice: + * + * .in +5 + * attr-list :== simple-attr* newline + * .br + * simple-attr :== attr-name "=" attr-value newline + * .br + * attr-name :== any string without null or "=" or newline. + * .br + * attr-value :== any string without null or newline. + * .br + * newline :== the ASCII newline character + * .in + * + * All attribute names and attribute values are sent as plain + * strings. Each string must be no longer than 4*var_line_limit + * characters. The formatting rules aim to make implementations in PERL + * and other languages easy. + * + * Normally, attributes must be received in the sequence as specified + * with the attr_scan_plain() argument list. The input stream may + * contain additional attributes at any point in the input stream, + * including additional instances of requested attributes. + * + * Additional input attributes or input attribute instances are silently + * skipped over, unless the ATTR_FLAG_EXTRA processing flag is specified + * (see below). This allows for some flexibility in the evolution of + * protocols while still providing the option of being strict where + * this is desirable. + * + * Arguments: + * .IP fp + * Stream to recover the input attributes from. + * .IP flags + * The bit-wise OR of zero or more of the following. + * .RS + * .IP ATTR_FLAG_MISSING + * Log a warning when the input attribute list terminates before all + * requested attributes are recovered. It is always an error when the + * input stream ends without the newline attribute list terminator. + * .IP ATTR_FLAG_EXTRA + * Log a warning and stop attribute recovery when the input stream + * contains an attribute that was not requested. This includes the + * case of additional instances of a requested attribute. + * .IP ATTR_FLAG_MORE + * After recovering the requested attributes, leave the input stream + * in a state that is usable for more attr_scan_plain() operations + * from the same input attribute list. + * By default, attr_scan_plain() skips forward past the input attribute + * list terminator. + * .IP ATTR_FLAG_STRICT + * For convenience, this value combines both ATTR_FLAG_MISSING and + * ATTR_FLAG_EXTRA. + * .IP ATTR_FLAG_NONE + * For convenience, this value requests none of the above. + * .RE + * .IP type + * The type argument determines the arguments that follow. + * .RS + * .IP "ATTR_TYPE_INT (char *, int *)" + * This argument is followed by an attribute name and an integer pointer. + * .IP "ATTR_TYPE_LONG (char *, long *)" + * This argument is followed by an attribute name and a long pointer. + * .IP "ATTR_TYPE_STR (char *, ACL_VSTRING *)" + * This argument is followed by an attribute name and a ACL_VSTRING pointer. + * .IP "ATTR_TYPE_DATA (char *, ACL_VSTRING *)" + * This argument is followed by an attribute name and a ACL_VSTRING pointer. + * .IP "ATTR_TYPE_FUNC (ATTR_SCAN_SLAVE_FN, void *)" + * This argument is followed by a function pointer and a generic data + * pointer. The caller-specified function returns < 0 in case of + * error. + * .IP "ATTR_TYPE_HASH (ACL_HTABLE *)" + * .IP "ATTR_TYPE_NAMEVAL (NVTABLE *)" + * All further input attributes are processed as string attributes. + * No specific attribute sequence is enforced. + * All attributes up to the attribute list terminator are read, + * but only the first instance of each attribute is stored. + * There can be no more than 1024 attributes in a hash table. + * .sp + * The attribute string values are stored in the hash table under + * keys equal to the attribute name (obtained from the input stream). + * Values from the input stream are added to the hash table. Existing + * hash table entries are not replaced. + * .sp + * N.B. This construct must be followed by an ATTR_TYPE_END argument. + * .IP ATTR_TYPE_END + * This argument terminates the requested attribute list. + * .RE + * BUGS + * ATTR_TYPE_HASH (ATTR_TYPE_NAMEVAL) accepts attributes with arbitrary + * names from possibly untrusted sources. + * This is unsafe, unless the resulting table is queried only with + * known to be good attribute names. + * DIAGNOSTICS + * attr_scan_plain() and attr_vscan_plain() return -1 when malformed input + * is detected (string too long, incomplete line, missing end marker). + * Otherwise, the result value is the number of attributes that were + * successfully recovered from the input stream (a hash table counts + * as the number of entries stored into the table). + * + * Panic: interface violation. All system call errors are fatal. + * SEE ALSO + * attr_print_plain(3) send attributes over byte stream. + * LICENSE + * .ad + * .fi + * The Secure Mailer license must be distributed with this software. + * AUTHOR(S) + * Wietse Venema + * IBM T.J. Watson Research + * P.O. Box 704 + * Yorktown Heights, NY 10598, USA + *--*/ + +#include "StdAfx.h" +#include +#include +#include + +#include "attr.h" + +/* Application specific. */ + +#define STR(x) acl_vstring_str(x) +#define LEN(x) ACL_VSTRING_LEN(x) + +static void free_vstring_fn(void *arg) +{ + ACL_VSTRING *s = (ACL_VSTRING*) arg; + + acl_vstring_free(s); +} + +/* attr_scan_plain_string - pull a string from the input stream */ + +static int attr_scan_plain_string(ACL_VSTREAM *fp, ACL_VSTRING *plain_buf, + int terminator, const char *context) +{ + const char *myname = "attr_scan_plain_string"; +#if 0 + extern int var_line_limit; /* XXX */ + int limit = var_line_limit * 4; + +#endif + int ch; + + ACL_VSTRING_RESET(plain_buf); + while ((ch = ACL_VSTREAM_GETC(fp)) != '\n' + && (terminator == 0 || ch != terminator)) { + if (ch == ACL_VSTREAM_EOF) { + acl_msg_warn("%s: %s on %s while reading %s", + myname, acl_vstream_ftimeout(fp) ? "timeout" : "premature end-of-input", + ACL_VSTREAM_PATH(fp), context); + return (-1); + } + ACL_VSTRING_ADDCH(plain_buf, ch); +#if 0 + if (LEN(plain_buf) > limit) { + acl_msg_warn("%s: string length > %d characters from %s while reading %s", + myname, limit, ACL_VSTREAM_PATH(fp), context); + return (-1); + } +#endif + } + ACL_VSTRING_TERMINATE(plain_buf); + + if (acl_msg_verbose) + acl_msg_info("%s: %s", context, *STR(plain_buf) ? STR(plain_buf) : "(end)"); + return (ch); +} + +/* attr_scan_plain_data - pull a data blob from the input stream */ + +static int attr_scan_plain_data(ACL_VSTREAM *fp, ACL_VSTRING *str_buf, + int terminator, const char *context) +{ + const char *myname = "attr_scan_plain_data"; + static __thread ACL_VSTRING *base64_buf = 0; + int ch; + + if (base64_buf == 0) { + base64_buf = acl_vstring_alloc(10); + acl_pthread_atexit_add(base64_buf, free_vstring_fn); + } + if ((ch = attr_scan_plain_string(fp, base64_buf, terminator, context)) < 0) + return (-1); + if (acl_vstring_base64_decode(str_buf, STR(base64_buf), (int) LEN(base64_buf)) == 0) { + acl_msg_warn("%s: malformed base64 data from %s while reading %s: %.100s", + myname, ACL_VSTREAM_PATH(fp), context, STR(base64_buf)); + return (-1); + } + return (ch); +} + +/* attr_scan_plain_number - pull a number from the input stream */ + +static int attr_scan_plain_number(ACL_VSTREAM *fp, unsigned *ptr, ACL_VSTRING *str_buf, + int terminator, const char *context) +{ + const char *myname = "attr_scan_plain_number"; + char junk = 0; + int ch; + + if ((ch = attr_scan_plain_string(fp, str_buf, terminator, context)) < 0) + return (-1); + if (sscanf(STR(str_buf), "%u%c", ptr, &junk) != 1 || junk != 0) { + acl_msg_warn("%s: malformed numerical data from %s while reading %s: %.100s", + myname, ACL_VSTREAM_PATH(fp), context, STR(str_buf)); + return (-1); + } + return (ch); +} + +/* attr_scan_plain_long_number - pull a number from the input stream */ + +static int attr_scan_plain_long_number(ACL_VSTREAM *fp, unsigned long *ptr, + ACL_VSTRING *str_buf, + int terminator, + const char *context) +{ + const char *myname = "attr_scan_plain_long_number"; + char junk = 0; + int ch; + + if ((ch = attr_scan_plain_string(fp, str_buf, terminator, context)) < 0) + return (-1); + if (sscanf(STR(str_buf), "%lu%c", ptr, &junk) != 1 || junk != 0) { + acl_msg_warn("%s: malformed numerical data from %s while reading %s: %.100s", + myname, ACL_VSTREAM_PATH(fp), context, STR(str_buf)); + return (-1); + } + return (ch); +} + +/* attr_vscan_plain - receive attribute list from stream */ + +int attr_vscan_plain(ACL_VSTREAM *fp, int flags, va_list ap) +{ + const char *myname = "attr_scan_plain"; + static __thread ACL_VSTRING *str_buf = 0; + static __thread ACL_VSTRING *name_buf = 0; + int wanted_type = -1; + char *wanted_name = 0; + unsigned int *number; + unsigned long *long_number; + ACL_VSTRING *string; + ACL_HTABLE *hash_table = 0; + int ch; + int conversions; + ATTR_SCAN_SLAVE_FN scan_fn; + void *scan_arg; + + /* + * Sanity check. + */ + if (flags & ~ATTR_FLAG_ALL) + acl_msg_panic("%s: bad flags: 0x%x", myname, flags); + + /* + * EOF check. + */ + if ((ch = ACL_VSTREAM_GETC(fp)) == ACL_VSTREAM_EOF) + return (0); + acl_vstream_ungetc(fp, ch); + + /* + * Initialize. + */ + if (str_buf == 0) { + str_buf = acl_vstring_alloc(10); + name_buf = acl_vstring_alloc(10); + acl_pthread_atexit_add(str_buf, free_vstring_fn); + acl_pthread_atexit_add(name_buf, free_vstring_fn); + } + + /* + * Iterate over all (type, name, value) triples. + */ + for (conversions = 0; /* void */ ; conversions++) { + + /* + * Determine the next attribute type and attribute name on the + * caller's wish list. + * + * If we're reading into a hash table, we already know that the + * attribute value is string-valued, and we get the attribute name + * from the input stream instead. This is secure only when the + * resulting table is queried with known to be good attribute names. + */ + if (wanted_type != ATTR_TYPE_HASH) { + wanted_type = va_arg(ap, int); + if (wanted_type == ATTR_TYPE_END) { + if ((flags & ATTR_FLAG_MORE) != 0) + return (conversions); + wanted_name = "(list terminator)"; + } else if (wanted_type == ATTR_TYPE_HASH) { + wanted_name = "(any attribute name or list terminator)"; + hash_table = va_arg(ap, ACL_HTABLE *); + if (va_arg(ap, int) != ATTR_TYPE_END) + acl_msg_panic("%s: ATTR_TYPE_HASH not followed by ATTR_TYPE_END", + myname); + } else if (wanted_type != ATTR_TYPE_FUNC) { + wanted_name = va_arg(ap, char *); + } + } + + /* + * Locate the next attribute of interest in the input stream. + */ + while (wanted_type != ATTR_TYPE_FUNC) { + + /* + * Get the name of the next attribute. Hitting EOF is always bad. + * Hitting the end-of-input early is OK if the caller is prepared + * to deal with missing inputs. + */ + if (acl_msg_verbose) + acl_msg_info("%s: wanted attribute: %s", + ACL_VSTREAM_PATH(fp), wanted_name); + if ((ch = attr_scan_plain_string(fp, name_buf, '=', + "input attribute name")) < 0) + return (-1); + if (ch == '\n' && LEN(name_buf) == 0) { + if (wanted_type == ATTR_TYPE_END + || wanted_type == ATTR_TYPE_HASH) + return (conversions); + if ((flags & ATTR_FLAG_MISSING) != 0) + acl_msg_warn("%s: missing attribute %s in input from %s", + myname, wanted_name, ACL_VSTREAM_PATH(fp)); + return (conversions); + } + + /* + * See if the caller asks for this attribute. + */ + if (wanted_type == ATTR_TYPE_HASH + || (wanted_type != ATTR_TYPE_END + && strcmp(wanted_name, STR(name_buf)) == 0)) + break; + if ((flags & ATTR_FLAG_EXTRA) != 0) { + acl_msg_warn("%s: unexpected attribute %s from %s (expecting: %s)", + myname, STR(name_buf), ACL_VSTREAM_PATH(fp), wanted_name); + return (conversions); + } + + /* + * Skip over this attribute. The caller does not ask for it. + */ + while (ch != '\n' && (ch = ACL_VSTREAM_GETC(fp)) != ACL_VSTREAM_EOF) + /* void */ ; + } + + /* + * Do the requested conversion. + */ + switch (wanted_type) { + case ATTR_TYPE_INT: + if (ch != '=') { + acl_msg_warn("%s: missing value for number attribute %s from %s", + myname, STR(name_buf), ACL_VSTREAM_PATH(fp)); + return (-1); + } + number = va_arg(ap, unsigned int *); + if ((ch = attr_scan_plain_number(fp, number, str_buf, 0, + "input attribute value")) < 0) + return (-1); + break; + case ATTR_TYPE_LONG: + if (ch != '=') { + acl_msg_warn("%s: missing value for number attribute %s from %s", + myname, STR(name_buf), ACL_VSTREAM_PATH(fp)); + return (-1); + } + long_number = va_arg(ap, unsigned long *); + if ((ch = attr_scan_plain_long_number(fp, long_number, str_buf, + 0, "input attribute value")) < 0) + return (-1); + break; + case ATTR_TYPE_STR: + if (ch != '=') { + acl_msg_warn("%s: missing value for string attribute %s from %s", + myname, STR(name_buf), ACL_VSTREAM_PATH(fp)); + return (-1); + } + string = va_arg(ap, ACL_VSTRING *); + if ((ch = attr_scan_plain_string(fp, string, 0, + "input attribute value")) < 0) + return (-1); + break; + case ATTR_TYPE_DATA: + if (ch != '=') { + acl_msg_warn("%s: missing value for data attribute %s from %s", + myname, STR(name_buf), ACL_VSTREAM_PATH(fp)); + return (-1); + } + string = va_arg(ap, ACL_VSTRING *); + if ((ch = attr_scan_plain_data(fp, string, 0, + "input attribute value")) < 0) + return (-1); + break; + case ATTR_TYPE_FUNC: + scan_fn = va_arg(ap, ATTR_SCAN_SLAVE_FN); + scan_arg = va_arg(ap, void *); + if (scan_fn(attr_scan_plain, fp, flags | ATTR_FLAG_MORE, scan_arg) < 0) + return (-1); + break; + case ATTR_TYPE_HASH: + if (ch != '=') { + acl_msg_warn("%s: missing value for string attribute %s from %s", + myname, STR(name_buf), ACL_VSTREAM_PATH(fp)); + return (-1); + } + if ((ch = attr_scan_plain_string(fp, str_buf, 0, + "input attribute value")) < 0) + return (-1); + if (acl_htable_locate(hash_table, STR(name_buf)) != 0) { + if ((flags & ATTR_FLAG_EXTRA) != 0) { + acl_msg_warn("%s: duplicate attribute %s in input from %s", + myname, STR(name_buf), ACL_VSTREAM_PATH(fp)); + return (conversions); + } + } else if (acl_htable_used(hash_table) >= ATTR_HASH_LIMIT) { + acl_msg_warn("%s: attribute count exceeds limit %d in input from %s", + myname, ATTR_HASH_LIMIT, ACL_VSTREAM_PATH(fp)); + return (conversions); + } else { + acl_htable_enter(hash_table, STR(name_buf), + acl_mystrdup(STR(str_buf))); + } + break; + default: + acl_msg_panic("%s: unknown type code: %d", myname, wanted_type); + } + } +} + +/* attr_scan_plain - read attribute list from stream */ + +int attr_scan_plain(ACL_VSTREAM *fp, int flags,...) +{ + va_list ap; + int ret; + + va_start(ap, flags); + ret = attr_vscan_plain(fp, flags, ap); + va_end(ap); + return (ret); +} + +#ifdef TEST + + /* + * Proof of concept test program. Mirror image of the attr_scan_plain test + * program. + */ + +int var_line_limit = 2048; + +int main(int unused_argc, char **used_argv) +{ + ACL_VSTRING *data_val = acl_vstring_alloc(1); + ACL_VSTRING *str_val = acl_vstring_alloc(1); + ACL_HTABLE *table = acl_htable_create(1); + ACL_HTABLE_INFO **ht_info_list; + ACL_HTABLE_INFO **ht; + int int_val; + long long_val; + int ret; + + acl_msg_verbose = 1; + if ((ret = attr_scan_plain(ACL_VSTREAM_IN, + ATTR_FLAG_STRICT, + ATTR_TYPE_INT, ATTR_NAME_INT, &int_val, + ATTR_TYPE_LONG, ATTR_NAME_LONG, &long_val, + ATTR_TYPE_STR, ATTR_NAME_STR, str_val, + ATTR_TYPE_DATA, ATTR_NAME_DATA, data_val, + ATTR_TYPE_HASH, table, + ATTR_TYPE_END)) > 4) { + acl_vstream_printf("%s %d\n", ATTR_NAME_INT, int_val); + acl_vstream_printf("%s %ld\n", ATTR_NAME_LONG, long_val); + acl_vstream_printf("%s %s\n", ATTR_NAME_STR, STR(str_val)); + acl_vstream_printf("%s %s\n", ATTR_NAME_DATA, STR(data_val)); + ht_info_list = acl_htable_list(table); + for (ht = ht_info_list; *ht; ht++) + acl_vstream_printf("(hash) %s %s\n", ht[0]->key, ht[0]->value); + acl_myfree(ht_info_list); + } else { + acl_vstream_printf("return: %d\n", ret); + } + if ((ret = attr_scan_plain(ACL_VSTREAM_IN, + ATTR_FLAG_STRICT, + ATTR_TYPE_INT, ATTR_NAME_INT, &int_val, + ATTR_TYPE_LONG, ATTR_NAME_LONG, &long_val, + ATTR_TYPE_STR, ATTR_NAME_STR, str_val, + ATTR_TYPE_DATA, ATTR_NAME_DATA, data_val, + ATTR_TYPE_END)) == 4) { + acl_vstream_printf("%s %d\n", ATTR_NAME_INT, int_val); + acl_vstream_printf("%s %ld\n", ATTR_NAME_LONG, long_val); + acl_vstream_printf("%s %s\n", ATTR_NAME_STR, STR(str_val)); + acl_vstream_printf("%s %s\n", ATTR_NAME_DATA, STR(data_val)); + ht_info_list = acl_htable_list(table); + for (ht = ht_info_list; *ht; ht++) + acl_vstream_printf("(hash) %s %s\n", ht[0]->key, ht[0]->value); + acl_myfree(ht_info_list); + } else { + acl_vstream_printf("return: %d\n", ret); + } + if (acl_vstream_fflush(ACL_VSTREAM_OUT) != 0) + acl_msg_fatal("write error: %s", acl_last_serror()); + + acl_vstring_free(data_val); + acl_vstring_free(str_val); + acl_htable_free(table, myfree); + + return (0); +} + +#endif diff --git a/lib_tls/attr/auto_clnt.c b/lib_tls/attr/auto_clnt.c new file mode 100644 index 000000000..1a4807060 --- /dev/null +++ b/lib_tls/attr/auto_clnt.c @@ -0,0 +1,321 @@ +/*++ + * NAME + * auto_clnt 3 + * SUMMARY + * client endpoint maintenance + * SYNOPSIS + * #include + * + * AUTO_CLNT *auto_clnt_create(service, timeout, max_idle, max_ttl) + * const char *service; + * int timeout; + * int max_idle; + * int max_ttl; + * + * ACL_VSTREAM *auto_clnt_access(auto_clnt) + * AUTO_CLNT *auto_clnt; + * + * void auto_clnt_recover(auto_clnt) + * AUTO_CLNT *auto_clnt; + * + * const char *auto_clnt_name(auto_clnt) + * AUTO_CLNT *auto_clnt; + * + * void auto_clnt_free(auto_clnt) + * AUTO_CLNT *auto_clnt; + * DESCRIPTION + * This module maintains IPC client endpoints that automatically + * disconnect after a being idle for a configurable amount of time, + * that disconnect after a configurable time to live, + * and that transparently handle most server-initiated disconnects. + * + * This module tries each operation only a limited number of + * times and then reports an error. This is unlike the + * clnt_stream(3) module which will retry forever, so that + * the application never experiences an error. + * + * auto_clnt_create() instantiates a client endpoint. + * + * auto_clnt_access() returns an open stream to the service specified + * to auto_clnt_create(). The stream instance may change between calls. + * The result is a null pointer in case of failure. + * + * auto_clnt_recover() recovers from a server-initiated disconnect + * that happened in the middle of an I/O operation. + * + * auto_clnt_name() returns the name of the specified client endpoint. + * + * auto_clnt_free() destroys of the specified client endpoint. + * + * Arguments: + * .IP service + * The service argument specifies "transport:servername" where + * transport is currently limited to one of the following: + * .RS + * .IP inet + * servername has the form "inet:host:port". + * .IP local + * servername has the form "local:private/servicename" or + * "local:public/servicename". This is the preferred way to + * specify Postfix daemons that are configured as "unix" in + * master.cf. + * .IP unix + * servername has the form "unix:private/servicename" or + * "unix:public/servicename". This does not work on Solaris, + * where Postfix uses STREAMS instead of UNIX-domain sockets. + * .RE + * .IP timeout + * The time limit for sending, receiving, or for connecting + * to a server. Specify a value <=0 to disable the time limit. + * .IP max_idle + * Idle time after which the client disconnects. Specify 0 to + * disable the limit. + * .IP max_ttl + * Upper bound on the time that a connection is allowed to persist. + * Specify 0 to disable the limit. + * .IP open_action + * Application call-back routine that opens a stream or returns a + * null pointer upon failure. In case of success, the call-back routine + * is expected to set the stream pathname to the server endpoint name. + * .IP context + * Application context that is passed to the open_action routine. + * DIAGNOSTICS + * Warnings: communication failure. Fatal error: out of memory. + * LICENSE + * .ad + * .fi + * The Secure Mailer license must be distributed with this software. + * AUTHOR(S) + * Wietse Venema + * IBM T.J. Watson Research + * P.O. Box 704 + * Yorktown Heights, NY 10598, USA + *--*/ + +#include "StdAfx.h" +#include + +#include "auto_clnt.h" + +/* Application-specific. */ + + /* + * AUTO_CLNT is an opaque structure. None of the access methods can easily + * be implemented as a macro, and access is not performance critical anyway. + */ +struct AUTO_CLNT { + ACL_EVENT *event; /* event handle */ + ACL_VSTREAM *vstream; /* buffered I/O */ + char *endpoint; /* host:port or pathname */ + int timeout; /* I/O time limit */ + int max_idle; /* time before client disconnect */ + int max_ttl; /* time before client disconnect */ + ACL_SOCKET (*connect) (const char *, int, int); /* unix, local, inet */ +}; + +static void auto_clnt_close(AUTO_CLNT *); + +/* auto_clnt_event - server-initiated disconnect or client-side max_idle */ + +static void auto_clnt_event(int unused_event acl_unused, void *context) +{ + AUTO_CLNT *auto_clnt = (AUTO_CLNT *) context; + + /* + * Sanity check. This routine causes the stream to be closed, so it + * cannot be called when the stream is already closed. + */ + if (auto_clnt->vstream == 0) + acl_msg_panic("auto_clnt_event: stream is closed"); + + auto_clnt_close(auto_clnt); +} + +/* auto_clnt_ttl_event - client-side expiration */ + +static void auto_clnt_ttl_event(int event, void *context) +{ + + /* + * XXX This function is needed only because event_request_timer() cannot + * distinguish between requests that specify the same call-back routine + * and call-back context. The fix is obvious: specify a request ID along + * with the call-back routine, but there is too much code that would have + * to be changed. + * + * XXX Should we be concerned that an overly agressive optimizer will + * eliminate this function and replace calls to auto_clnt_ttl_event() by + * direct calls to auto_clnt_event()? It should not, because there exists + * code that takes the address of both functions. + */ + auto_clnt_event(event, context); +} + +/* auto_clnt_open - connect to service */ + +static void auto_clnt_open(AUTO_CLNT *auto_clnt) +{ + const char *myname = "auto_clnt_open"; + ACL_SOCKET fd; + + /* + * Sanity check. + */ + if (auto_clnt->vstream) + acl_msg_panic("auto_clnt_open: stream is open"); + + /* + * Schedule a read event so that we can clean up when the remote side + * disconnects, and schedule a timer event so that we can cleanup an idle + * connection. Note that both events are handled by the same routine. + * + * Finally, schedule an event to force disconnection even when the + * connection is not idle. This is to prevent one client from clinging on + * to a server forever. + */ + fd = auto_clnt->connect(auto_clnt->endpoint, ACL_BLOCKING, auto_clnt->timeout); + if (fd < 0) { + acl_msg_warn("%s: connect to %s: %s", myname, auto_clnt->endpoint, acl_last_serror()); + } else { + if (acl_msg_verbose) + acl_msg_info("%s: connected to %s", myname, auto_clnt->endpoint); + auto_clnt->vstream = acl_vstream_fdopen(fd, O_RDWR, 4096, + auto_clnt->timeout, ACL_VSTREAM_TYPE_SOCK); + acl_vstream_ctl(auto_clnt->vstream, + ACL_VSTREAM_CTL_PATH, auto_clnt->endpoint, + /* ACL_VSTREAM_CTL_TIMEOUT, auto_clnt->timeout, */ + ACL_VSTREAM_CTL_END); + } + + if (auto_clnt->vstream != 0) { +#ifdef ACL_UNIX + acl_close_on_exec(ACL_VSTREAM_SOCK(auto_clnt->vstream), ACL_CLOSE_ON_EXEC); +#endif + acl_event_enable_read(auto_clnt->event, auto_clnt->vstream, 0, + auto_clnt_event, (char *) auto_clnt); + if (auto_clnt->max_idle > 0) + acl_event_request_timer(auto_clnt->event, auto_clnt_event, + (char *) auto_clnt, auto_clnt->max_idle, 0); + if (auto_clnt->max_ttl > 0) + acl_event_request_timer(auto_clnt->event, auto_clnt_ttl_event, + (char *) auto_clnt, auto_clnt->max_ttl, 0); + } +} + +/* auto_clnt_close - disconnect from service */ + +static void auto_clnt_close(AUTO_CLNT *auto_clnt) +{ + const char *myname = "auto_clnt_close"; + + /* + * Sanity check. + */ + if (auto_clnt->vstream == 0) + acl_msg_panic("%s: stream is closed", myname); + + /* + * Be sure to disable read and timer events. + */ + if (acl_msg_verbose) + acl_msg_info("%s: disconnect %s stream", + myname, ACL_VSTREAM_PATH(auto_clnt->vstream)); + acl_event_disable_readwrite(auto_clnt->event, auto_clnt->vstream); + acl_event_cancel_timer(auto_clnt->event, auto_clnt_event, (char *) auto_clnt); + acl_event_cancel_timer(auto_clnt->event, auto_clnt_ttl_event, (char *) auto_clnt); + (void) acl_vstream_fclose(auto_clnt->vstream); + auto_clnt->vstream = 0; +} + +/* auto_clnt_recover - recover from server-initiated disconnect */ + +void auto_clnt_recover(AUTO_CLNT *auto_clnt) +{ + /* + * Clean up. Don't re-connect until the caller needs it. + */ + if (auto_clnt->vstream) + auto_clnt_close(auto_clnt); +} + +/* auto_clnt_access - access a client stream */ + +ACL_VSTREAM *auto_clnt_access(AUTO_CLNT *auto_clnt) +{ + /* + * Open a stream or restart the idle timer. + * + * Important! Do not restart the TTL timer! + */ + if (auto_clnt->vstream == 0) { + auto_clnt_open(auto_clnt); + } else if (auto_clnt->max_idle > 0) { + acl_event_request_timer(auto_clnt->event, auto_clnt_event, + (char *) auto_clnt, auto_clnt->max_idle, 0); + } + return (auto_clnt->vstream); +} + +/* auto_clnt_create - create client stream object */ + +AUTO_CLNT *auto_clnt_create(ACL_EVENT *eventp, const char *service, + int timeout, int max_idle, int max_ttl) +{ + const char *myname = "auto_clnt_create"; + char *transport = acl_mystrdup(service); + char *endpoint; + AUTO_CLNT *auto_clnt; + + if (eventp == 0) + acl_msg_fatal("%s(%d): evenpt null", myname, __LINE__); + + /* + * Don't open the stream until the caller needs it. + */ + if ((endpoint = acl_split_at(transport, ':')) == 0 + || *endpoint == 0 || *transport == 0) + acl_msg_fatal("%s: need service transport:endpoint instead of \"%s\"", + myname, service); + if (acl_msg_verbose) + acl_msg_info("%s: transport=%s endpoint=%s", myname, transport, endpoint); + auto_clnt = (AUTO_CLNT *) acl_mymalloc(sizeof(*auto_clnt)); + auto_clnt->event = eventp; + auto_clnt->vstream = 0; + auto_clnt->endpoint = acl_mystrdup(endpoint); + auto_clnt->timeout = timeout; + auto_clnt->max_idle = max_idle; + auto_clnt->max_ttl = max_ttl; + if (strcmp(transport, "inet") == 0) { + auto_clnt->connect = acl_inet_connect; + } +#ifdef ACL_UNIX + else if (strcmp(transport, "local") == 0) { + auto_clnt->connect = LOCAL_CONNECT; + } else if (strcmp(transport, "unix") == 0) { + auto_clnt->connect = acl_unix_connect; + } +#endif + else { + acl_msg_fatal("%s: invalid transport name: %s in service: %s", + myname, transport, service); + } + acl_myfree(transport); + return (auto_clnt); +} + +/* auto_clnt_name - return client stream name */ + +const char *auto_clnt_name(AUTO_CLNT *auto_clnt) +{ + return (auto_clnt->endpoint); +} + +/* auto_clnt_free - destroy client stream instance */ + +void auto_clnt_free(AUTO_CLNT *auto_clnt) +{ + if (auto_clnt->vstream) + auto_clnt_close(auto_clnt); + acl_myfree(auto_clnt->endpoint); + acl_myfree(auto_clnt); +} diff --git a/lib_tls/attr/auto_clnt.h b/lib_tls/attr/auto_clnt.h new file mode 100644 index 000000000..89425d692 --- /dev/null +++ b/lib_tls/attr/auto_clnt.h @@ -0,0 +1,47 @@ +#ifndef _AUTO_CLNT_H_INCLUDED_ +#define _AUTO_CLNT_H_INCLUDED_ + +/*++ + * NAME + * auto_clnt 3h + * SUMMARY + * client endpoint maintenance + * SYNOPSIS + * #include + * DESCRIPTION + * .nf + + * + * Utility library. + */ +#include "lib_acl.h" + +#ifdef ACL_SUNOS5 +#define LOCAL_CONNECT acl_stream_connect +#else +#define LOCAL_CONNECT acl_unix_connect +#endif + + /* + * External interface. + */ +typedef struct AUTO_CLNT AUTO_CLNT; + +extern AUTO_CLNT *auto_clnt_create(ACL_EVENT *, const char *, int, int, int); +extern ACL_VSTREAM *auto_clnt_access(AUTO_CLNT *); +extern void auto_clnt_recover(AUTO_CLNT *); +extern const char *auto_clnt_name(AUTO_CLNT *); +extern void auto_clnt_free(AUTO_CLNT *); + +/* LICENSE + * .ad + * .fi + * The Secure Mailer license must be distributed with this software. + * AUTHOR(S) + * Wietse Venema + * IBM T.J. Watson Research + * P.O. Box 704 + * Yorktown Heights, NY 10598, USA + *--*/ + +#endif diff --git a/lib_tls/changes.txt b/lib_tls/changes.txt new file mode 100644 index 000000000..abbae8efe --- /dev/null +++ b/lib_tls/changes.txt @@ -0,0 +1,9 @@ +3) 2012.7.10 +3.1) compile: 支持 VC2003 的预编译功能,从而使编译速度更快 +3.2) compile: 消除了几处编译警告 + +2.) 2009.9.14 +2.1) 支持WIN32平台了 + +1) 2009.7.30 +1.1) 目前仅支持UNIX平台 diff --git a/lib_tls/include/lib_tls.h b/lib_tls/include/lib_tls.h new file mode 100644 index 000000000..c6b19a309 --- /dev/null +++ b/lib_tls/include/lib_tls.h @@ -0,0 +1,14 @@ +#ifndef __LIB_TLS_INCLUDE_H__ +#define __LIB_TLS_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "tls.h" +#include "tls_params.h" + +#ifdef __cplusplus +} +#endif +#endif diff --git a/lib_tls/include/openssl/aes.h b/lib_tls/include/openssl/aes.h new file mode 100644 index 000000000..baf0222d4 --- /dev/null +++ b/lib_tls/include/openssl/aes.h @@ -0,0 +1,144 @@ +/* crypto/aes/aes.h -*- mode:C; c-file-style: "eay" -*- */ +/* ==================================================================== + * Copyright (c) 1998-2002 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + */ + +#ifndef HEADER_AES_H +#define HEADER_AES_H + +#include + +#ifdef OPENSSL_NO_AES +#error AES is disabled. +#endif + +#define AES_ENCRYPT 1 +#define AES_DECRYPT 0 + +/* Because array size can't be a const in C, the following two are macros. + Both sizes are in bytes. */ +#define AES_MAXNR 14 +#define AES_BLOCK_SIZE 16 + +#ifdef __cplusplus +extern "C" { +#endif + +/* This should be a hidden type, but EVP requires that the size be known */ +struct aes_key_st { +#ifdef AES_LONG + unsigned long rd_key[4 *(AES_MAXNR + 1)]; +#else + unsigned int rd_key[4 *(AES_MAXNR + 1)]; +#endif + int rounds; +}; +typedef struct aes_key_st AES_KEY; + +const char *AES_options(void); + +int AES_set_encrypt_key(const unsigned char *userKey, const int bits, + AES_KEY *key); +int AES_set_decrypt_key(const unsigned char *userKey, const int bits, + AES_KEY *key); + +void AES_encrypt(const unsigned char *in, unsigned char *out, + const AES_KEY *key); +void AES_decrypt(const unsigned char *in, unsigned char *out, + const AES_KEY *key); + +void AES_ecb_encrypt(const unsigned char *in, unsigned char *out, + const AES_KEY *key, const int enc); +void AES_cbc_encrypt(const unsigned char *in, unsigned char *out, + const unsigned long length, const AES_KEY *key, + unsigned char *ivec, const int enc); +void AES_cfb128_encrypt(const unsigned char *in, unsigned char *out, + const unsigned long length, const AES_KEY *key, + unsigned char *ivec, int *num, const int enc); +void AES_cfb1_encrypt(const unsigned char *in, unsigned char *out, + const unsigned long length, const AES_KEY *key, + unsigned char *ivec, int *num, const int enc); +void AES_cfb8_encrypt(const unsigned char *in, unsigned char *out, + const unsigned long length, const AES_KEY *key, + unsigned char *ivec, int *num, const int enc); +void AES_cfbr_encrypt_block(const unsigned char *in,unsigned char *out, + const int nbits,const AES_KEY *key, + unsigned char *ivec,const int enc); +void AES_ofb128_encrypt(const unsigned char *in, unsigned char *out, + const unsigned long length, const AES_KEY *key, + unsigned char *ivec, int *num); +void AES_ctr128_encrypt(const unsigned char *in, unsigned char *out, + const unsigned long length, const AES_KEY *key, + unsigned char ivec[AES_BLOCK_SIZE], + unsigned char ecount_buf[AES_BLOCK_SIZE], + unsigned int *num); + +/* For IGE, see also http://www.links.org/files/openssl-ige.pdf */ +/* NB: the IV is _two_ blocks long */ +void AES_ige_encrypt(const unsigned char *in, unsigned char *out, + const unsigned long length, const AES_KEY *key, + unsigned char *ivec, const int enc); +/* NB: the IV is _four_ blocks long */ +void AES_bi_ige_encrypt(const unsigned char *in, unsigned char *out, + const unsigned long length, const AES_KEY *key, + const AES_KEY *key2, const unsigned char *ivec, + const int enc); + +int AES_wrap_key(AES_KEY *key, const unsigned char *iv, + unsigned char *out, + const unsigned char *in, unsigned int inlen); +int AES_unwrap_key(AES_KEY *key, const unsigned char *iv, + unsigned char *out, + const unsigned char *in, unsigned int inlen); + +#ifdef __cplusplus +} +#endif + +#endif /* !HEADER_AES_H */ diff --git a/lib_tls/include/openssl/asn1.h b/lib_tls/include/openssl/asn1.h new file mode 100644 index 000000000..424cd348b --- /dev/null +++ b/lib_tls/include/openssl/asn1.h @@ -0,0 +1,1326 @@ +/* crypto/asn1/asn1.h */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#ifndef HEADER_ASN1_H +#define HEADER_ASN1_H + +#include +#include +#ifndef OPENSSL_NO_BIO +#include +#endif +#include +#include + +#include + +#include +#ifndef OPENSSL_NO_DEPRECATED +#include +#endif + +#ifdef OPENSSL_BUILD_SHLIBCRYPTO +# undef OPENSSL_EXTERN +# define OPENSSL_EXTERN OPENSSL_EXPORT +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#define V_ASN1_UNIVERSAL 0x00 +#define V_ASN1_APPLICATION 0x40 +#define V_ASN1_CONTEXT_SPECIFIC 0x80 +#define V_ASN1_PRIVATE 0xc0 + +#define V_ASN1_CONSTRUCTED 0x20 +#define V_ASN1_PRIMITIVE_TAG 0x1f +#define V_ASN1_PRIMATIVE_TAG 0x1f + +#define V_ASN1_APP_CHOOSE -2 /* let the recipient choose */ +#define V_ASN1_OTHER -3 /* used in ASN1_TYPE */ +#define V_ASN1_ANY -4 /* used in ASN1 template code */ + +#define V_ASN1_NEG 0x100 /* negative flag */ + +#define V_ASN1_UNDEF -1 +#define V_ASN1_EOC 0 +#define V_ASN1_BOOLEAN 1 /**/ +#define V_ASN1_INTEGER 2 +#define V_ASN1_NEG_INTEGER (2 | V_ASN1_NEG) +#define V_ASN1_BIT_STRING 3 +#define V_ASN1_OCTET_STRING 4 +#define V_ASN1_NULL 5 +#define V_ASN1_OBJECT 6 +#define V_ASN1_OBJECT_DESCRIPTOR 7 +#define V_ASN1_EXTERNAL 8 +#define V_ASN1_REAL 9 +#define V_ASN1_ENUMERATED 10 +#define V_ASN1_NEG_ENUMERATED (10 | V_ASN1_NEG) +#define V_ASN1_UTF8STRING 12 +#define V_ASN1_SEQUENCE 16 +#define V_ASN1_SET 17 +#define V_ASN1_NUMERICSTRING 18 /**/ +#define V_ASN1_PRINTABLESTRING 19 +#define V_ASN1_T61STRING 20 +#define V_ASN1_TELETEXSTRING 20 /* alias */ +#define V_ASN1_VIDEOTEXSTRING 21 /**/ +#define V_ASN1_IA5STRING 22 +#define V_ASN1_UTCTIME 23 +#define V_ASN1_GENERALIZEDTIME 24 /**/ +#define V_ASN1_GRAPHICSTRING 25 /**/ +#define V_ASN1_ISO64STRING 26 /**/ +#define V_ASN1_VISIBLESTRING 26 /* alias */ +#define V_ASN1_GENERALSTRING 27 /**/ +#define V_ASN1_UNIVERSALSTRING 28 /**/ +#define V_ASN1_BMPSTRING 30 + +/* For use with d2i_ASN1_type_bytes() */ +#define B_ASN1_NUMERICSTRING 0x0001 +#define B_ASN1_PRINTABLESTRING 0x0002 +#define B_ASN1_T61STRING 0x0004 +#define B_ASN1_TELETEXSTRING 0x0004 +#define B_ASN1_VIDEOTEXSTRING 0x0008 +#define B_ASN1_IA5STRING 0x0010 +#define B_ASN1_GRAPHICSTRING 0x0020 +#define B_ASN1_ISO64STRING 0x0040 +#define B_ASN1_VISIBLESTRING 0x0040 +#define B_ASN1_GENERALSTRING 0x0080 +#define B_ASN1_UNIVERSALSTRING 0x0100 +#define B_ASN1_OCTET_STRING 0x0200 +#define B_ASN1_BIT_STRING 0x0400 +#define B_ASN1_BMPSTRING 0x0800 +#define B_ASN1_UNKNOWN 0x1000 +#define B_ASN1_UTF8STRING 0x2000 +#define B_ASN1_UTCTIME 0x4000 +#define B_ASN1_GENERALIZEDTIME 0x8000 +#define B_ASN1_SEQUENCE 0x10000 + +/* For use with ASN1_mbstring_copy() */ +#define MBSTRING_FLAG 0x1000 +#define MBSTRING_UTF8 (MBSTRING_FLAG) +#define MBSTRING_ASC (MBSTRING_FLAG|1) +#define MBSTRING_BMP (MBSTRING_FLAG|2) +#define MBSTRING_UNIV (MBSTRING_FLAG|4) + +#define SMIME_OLDMIME 0x400 +#define SMIME_CRLFEOL 0x800 +#define SMIME_STREAM 0x1000 + +struct X509_algor_st; +DECLARE_STACK_OF(X509_ALGOR) + +#define DECLARE_ASN1_SET_OF(type) /* filled in by mkstack.pl */ +#define IMPLEMENT_ASN1_SET_OF(type) /* nothing, no longer needed */ + +/* We MUST make sure that, except for constness, asn1_ctx_st and + asn1_const_ctx are exactly the same. Fortunately, as soon as + the old ASN1 parsing macros are gone, we can throw this away + as well... */ +typedef struct asn1_ctx_st + { + unsigned char *p;/* work char pointer */ + int eos; /* end of sequence read for indefinite encoding */ + int error; /* error code to use when returning an error */ + int inf; /* constructed if 0x20, indefinite is 0x21 */ + int tag; /* tag from last 'get object' */ + int xclass; /* class from last 'get object' */ + long slen; /* length of last 'get object' */ + unsigned char *max; /* largest value of p allowed */ + unsigned char *q;/* temporary variable */ + unsigned char **pp;/* variable */ + int line; /* used in error processing */ + } ASN1_CTX; + +typedef struct asn1_const_ctx_st + { + const unsigned char *p;/* work char pointer */ + int eos; /* end of sequence read for indefinite encoding */ + int error; /* error code to use when returning an error */ + int inf; /* constructed if 0x20, indefinite is 0x21 */ + int tag; /* tag from last 'get object' */ + int xclass; /* class from last 'get object' */ + long slen; /* length of last 'get object' */ + const unsigned char *max; /* largest value of p allowed */ + const unsigned char *q;/* temporary variable */ + const unsigned char **pp;/* variable */ + int line; /* used in error processing */ + } ASN1_const_CTX; + +/* These are used internally in the ASN1_OBJECT to keep track of + * whether the names and data need to be free()ed */ +#define ASN1_OBJECT_FLAG_DYNAMIC 0x01 /* internal use */ +#define ASN1_OBJECT_FLAG_CRITICAL 0x02 /* critical x509v3 object id */ +#define ASN1_OBJECT_FLAG_DYNAMIC_STRINGS 0x04 /* internal use */ +#define ASN1_OBJECT_FLAG_DYNAMIC_DATA 0x08 /* internal use */ +typedef struct asn1_object_st + { + const char *sn,*ln; + int nid; + int length; + unsigned char *data; + int flags; /* Should we free this one */ + } ASN1_OBJECT; + +#define ASN1_STRING_FLAG_BITS_LEFT 0x08 /* Set if 0x07 has bits left value */ +/* This indicates that the ASN1_STRING is not a real value but just a place + * holder for the location where indefinite length constructed data should + * be inserted in the memory buffer + */ +#define ASN1_STRING_FLAG_NDEF 0x010 + +/* This flag is used by the CMS code to indicate that a string is not + * complete and is a place holder for content when it had all been + * accessed. The flag will be reset when content has been written to it. + */ +#define ASN1_STRING_FLAG_CONT 0x020 + +/* This is the base type that holds just about everything :-) */ +typedef struct asn1_string_st + { + int length; + int type; + unsigned char *data; + /* The value of the following field depends on the type being + * held. It is mostly being used for BIT_STRING so if the + * input data has a non-zero 'unused bits' value, it will be + * handled correctly */ + long flags; + } ASN1_STRING; + +/* ASN1_ENCODING structure: this is used to save the received + * encoding of an ASN1 type. This is useful to get round + * problems with invalid encodings which can break signatures. + */ + +typedef struct ASN1_ENCODING_st + { + unsigned char *enc; /* DER encoding */ + long len; /* Length of encoding */ + int modified; /* set to 1 if 'enc' is invalid */ + } ASN1_ENCODING; + +/* Used with ASN1 LONG type: if a long is set to this it is omitted */ +#define ASN1_LONG_UNDEF 0x7fffffffL + +#define STABLE_FLAGS_MALLOC 0x01 +#define STABLE_NO_MASK 0x02 +#define DIRSTRING_TYPE \ + (B_ASN1_PRINTABLESTRING|B_ASN1_T61STRING|B_ASN1_BMPSTRING|B_ASN1_UTF8STRING) +#define PKCS9STRING_TYPE (DIRSTRING_TYPE|B_ASN1_IA5STRING) + +typedef struct asn1_string_table_st { + int nid; + long minsize; + long maxsize; + unsigned long mask; + unsigned long flags; +} ASN1_STRING_TABLE; + +DECLARE_STACK_OF(ASN1_STRING_TABLE) + +/* size limits: this stuff is taken straight from RFC2459 */ + +#define ub_name 32768 +#define ub_common_name 64 +#define ub_locality_name 128 +#define ub_state_name 128 +#define ub_organization_name 64 +#define ub_organization_unit_name 64 +#define ub_title 64 +#define ub_email_address 128 + +/* Declarations for template structures: for full definitions + * see asn1t.h + */ +typedef struct ASN1_TEMPLATE_st ASN1_TEMPLATE; +typedef struct ASN1_ITEM_st ASN1_ITEM; +typedef struct ASN1_TLC_st ASN1_TLC; +/* This is just an opaque pointer */ +typedef struct ASN1_VALUE_st ASN1_VALUE; + +/* Declare ASN1 functions: the implement macro in in asn1t.h */ + +#define DECLARE_ASN1_FUNCTIONS(type) DECLARE_ASN1_FUNCTIONS_name(type, type) + +#define DECLARE_ASN1_ALLOC_FUNCTIONS(type) \ + DECLARE_ASN1_ALLOC_FUNCTIONS_name(type, type) + +#define DECLARE_ASN1_FUNCTIONS_name(type, name) \ + DECLARE_ASN1_ALLOC_FUNCTIONS_name(type, name) \ + DECLARE_ASN1_ENCODE_FUNCTIONS(type, name, name) + +#define DECLARE_ASN1_FUNCTIONS_fname(type, itname, name) \ + DECLARE_ASN1_ALLOC_FUNCTIONS_name(type, name) \ + DECLARE_ASN1_ENCODE_FUNCTIONS(type, itname, name) + +#define DECLARE_ASN1_ENCODE_FUNCTIONS(type, itname, name) \ + type *d2i_##name(type **a, const unsigned char **in, long len); \ + int i2d_##name(type *a, unsigned char **out); \ + DECLARE_ASN1_ITEM(itname) + +#define DECLARE_ASN1_ENCODE_FUNCTIONS_const(type, name) \ + type *d2i_##name(type **a, const unsigned char **in, long len); \ + int i2d_##name(const type *a, unsigned char **out); \ + DECLARE_ASN1_ITEM(name) + +#define DECLARE_ASN1_NDEF_FUNCTION(name) \ + int i2d_##name##_NDEF(name *a, unsigned char **out); + +#define DECLARE_ASN1_FUNCTIONS_const(name) \ + DECLARE_ASN1_ALLOC_FUNCTIONS(name) \ + DECLARE_ASN1_ENCODE_FUNCTIONS_const(name, name) + +#define DECLARE_ASN1_ALLOC_FUNCTIONS_name(type, name) \ + type *name##_new(void); \ + void name##_free(type *a); + +#define D2I_OF(type) type *(*)(type **,const unsigned char **,long) +#define I2D_OF(type) int (*)(type *,unsigned char **) +#define I2D_OF_const(type) int (*)(const type *,unsigned char **) + +#define CHECKED_D2I_OF(type, d2i) \ + ((d2i_of_void*) (1 ? d2i : ((D2I_OF(type))0))) +#define CHECKED_I2D_OF(type, i2d) \ + ((i2d_of_void*) (1 ? i2d : ((I2D_OF(type))0))) +#define CHECKED_NEW_OF(type, xnew) \ + ((void *(*)(void)) (1 ? xnew : ((type *(*)(void))0))) +#define CHECKED_PTR_OF(type, p) \ + ((void*) (1 ? p : (type*)0)) +#define CHECKED_PPTR_OF(type, p) \ + ((void**) (1 ? p : (type**)0)) + +#define TYPEDEF_D2I_OF(type) typedef type *d2i_of_##type(type **,const unsigned char **,long) +#define TYPEDEF_I2D_OF(type) typedef int i2d_of_##type(type *,unsigned char **) +#define TYPEDEF_D2I2D_OF(type) TYPEDEF_D2I_OF(type); TYPEDEF_I2D_OF(type) + +TYPEDEF_D2I2D_OF(void); + +/* The following macros and typedefs allow an ASN1_ITEM + * to be embedded in a structure and referenced. Since + * the ASN1_ITEM pointers need to be globally accessible + * (possibly from shared libraries) they may exist in + * different forms. On platforms that support it the + * ASN1_ITEM structure itself will be globally exported. + * Other platforms will export a function that returns + * an ASN1_ITEM pointer. + * + * To handle both cases transparently the macros below + * should be used instead of hard coding an ASN1_ITEM + * pointer in a structure. + * + * The structure will look like this: + * + * typedef struct SOMETHING_st { + * ... + * ASN1_ITEM_EXP *iptr; + * ... + * } SOMETHING; + * + * It would be initialised as e.g.: + * + * SOMETHING somevar = {...,ASN1_ITEM_ref(X509),...}; + * + * and the actual pointer extracted with: + * + * const ASN1_ITEM *it = ASN1_ITEM_ptr(somevar.iptr); + * + * Finally an ASN1_ITEM pointer can be extracted from an + * appropriate reference with: ASN1_ITEM_rptr(X509). This + * would be used when a function takes an ASN1_ITEM * argument. + * + */ + +#ifndef OPENSSL_EXPORT_VAR_AS_FUNCTION + +/* ASN1_ITEM pointer exported type */ +typedef const ASN1_ITEM ASN1_ITEM_EXP; + +/* Macro to obtain ASN1_ITEM pointer from exported type */ +#define ASN1_ITEM_ptr(iptr) (iptr) + +/* Macro to include ASN1_ITEM pointer from base type */ +#define ASN1_ITEM_ref(iptr) (&(iptr##_it)) + +#define ASN1_ITEM_rptr(ref) (&(ref##_it)) + +#define DECLARE_ASN1_ITEM(name) \ + OPENSSL_EXTERN const ASN1_ITEM name##_it; + +#else + +/* Platforms that can't easily handle shared global variables are declared + * as functions returning ASN1_ITEM pointers. + */ + +/* ASN1_ITEM pointer exported type */ +typedef const ASN1_ITEM * ASN1_ITEM_EXP(void); + +/* Macro to obtain ASN1_ITEM pointer from exported type */ +#define ASN1_ITEM_ptr(iptr) (iptr()) + +/* Macro to include ASN1_ITEM pointer from base type */ +#define ASN1_ITEM_ref(iptr) (iptr##_it) + +#define ASN1_ITEM_rptr(ref) (ref##_it()) + +#define DECLARE_ASN1_ITEM(name) \ + const ASN1_ITEM * name##_it(void); + +#endif + +/* Parameters used by ASN1_STRING_print_ex() */ + +/* These determine which characters to escape: + * RFC2253 special characters, control characters and + * MSB set characters + */ + +#define ASN1_STRFLGS_ESC_2253 1 +#define ASN1_STRFLGS_ESC_CTRL 2 +#define ASN1_STRFLGS_ESC_MSB 4 + + +/* This flag determines how we do escaping: normally + * RC2253 backslash only, set this to use backslash and + * quote. + */ + +#define ASN1_STRFLGS_ESC_QUOTE 8 + + +/* These three flags are internal use only. */ + +/* Character is a valid PrintableString character */ +#define CHARTYPE_PRINTABLESTRING 0x10 +/* Character needs escaping if it is the first character */ +#define CHARTYPE_FIRST_ESC_2253 0x20 +/* Character needs escaping if it is the last character */ +#define CHARTYPE_LAST_ESC_2253 0x40 + +/* NB the internal flags are safely reused below by flags + * handled at the top level. + */ + +/* If this is set we convert all character strings + * to UTF8 first + */ + +#define ASN1_STRFLGS_UTF8_CONVERT 0x10 + +/* If this is set we don't attempt to interpret content: + * just assume all strings are 1 byte per character. This + * will produce some pretty odd looking output! + */ + +#define ASN1_STRFLGS_IGNORE_TYPE 0x20 + +/* If this is set we include the string type in the output */ +#define ASN1_STRFLGS_SHOW_TYPE 0x40 + +/* This determines which strings to display and which to + * 'dump' (hex dump of content octets or DER encoding). We can + * only dump non character strings or everything. If we + * don't dump 'unknown' they are interpreted as character + * strings with 1 octet per character and are subject to + * the usual escaping options. + */ + +#define ASN1_STRFLGS_DUMP_ALL 0x80 +#define ASN1_STRFLGS_DUMP_UNKNOWN 0x100 + +/* These determine what 'dumping' does, we can dump the + * content octets or the DER encoding: both use the + * RFC2253 #XXXXX notation. + */ + +#define ASN1_STRFLGS_DUMP_DER 0x200 + +/* All the string flags consistent with RFC2253, + * escaping control characters isn't essential in + * RFC2253 but it is advisable anyway. + */ + +#define ASN1_STRFLGS_RFC2253 (ASN1_STRFLGS_ESC_2253 | \ + ASN1_STRFLGS_ESC_CTRL | \ + ASN1_STRFLGS_ESC_MSB | \ + ASN1_STRFLGS_UTF8_CONVERT | \ + ASN1_STRFLGS_DUMP_UNKNOWN | \ + ASN1_STRFLGS_DUMP_DER) + +DECLARE_STACK_OF(ASN1_INTEGER) +DECLARE_ASN1_SET_OF(ASN1_INTEGER) + +DECLARE_STACK_OF(ASN1_GENERALSTRING) + +typedef struct asn1_type_st + { + int type; + union { + char *ptr; + ASN1_BOOLEAN boolean; + ASN1_STRING * asn1_string; + ASN1_OBJECT * object; + ASN1_INTEGER * integer; + ASN1_ENUMERATED * enumerated; + ASN1_BIT_STRING * bit_string; + ASN1_OCTET_STRING * octet_string; + ASN1_PRINTABLESTRING * printablestring; + ASN1_T61STRING * t61string; + ASN1_IA5STRING * ia5string; + ASN1_GENERALSTRING * generalstring; + ASN1_BMPSTRING * bmpstring; + ASN1_UNIVERSALSTRING * universalstring; + ASN1_UTCTIME * utctime; + ASN1_GENERALIZEDTIME * generalizedtime; + ASN1_VISIBLESTRING * visiblestring; + ASN1_UTF8STRING * utf8string; + /* set and sequence are left complete and still + * contain the set or sequence bytes */ + ASN1_STRING * set; + ASN1_STRING * sequence; + ASN1_VALUE * asn1_value; + } value; + } ASN1_TYPE; + +DECLARE_STACK_OF(ASN1_TYPE) +DECLARE_ASN1_SET_OF(ASN1_TYPE) + +typedef struct asn1_method_st + { + i2d_of_void *i2d; + d2i_of_void *d2i; + void *(*create)(void); + void (*destroy)(void *); + } ASN1_METHOD; + +/* This is used when parsing some Netscape objects */ +typedef struct asn1_header_st + { + ASN1_OCTET_STRING *header; + void *data; + ASN1_METHOD *meth; + } ASN1_HEADER; + +/* This is used to contain a list of bit names */ +typedef struct BIT_STRING_BITNAME_st { + int bitnum; + const char *lname; + const char *sname; +} BIT_STRING_BITNAME; + + +#define M_ASN1_STRING_length(x) ((x)->length) +#define M_ASN1_STRING_length_set(x, n) ((x)->length = (n)) +#define M_ASN1_STRING_type(x) ((x)->type) +#define M_ASN1_STRING_data(x) ((x)->data) + +/* Macros for string operations */ +#define M_ASN1_BIT_STRING_new() (ASN1_BIT_STRING *)\ + ASN1_STRING_type_new(V_ASN1_BIT_STRING) +#define M_ASN1_BIT_STRING_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_ASN1_BIT_STRING_dup(a) (ASN1_BIT_STRING *)\ + ASN1_STRING_dup((ASN1_STRING *)a) +#define M_ASN1_BIT_STRING_cmp(a,b) ASN1_STRING_cmp(\ + (ASN1_STRING *)a,(ASN1_STRING *)b) +#define M_ASN1_BIT_STRING_set(a,b,c) ASN1_STRING_set((ASN1_STRING *)a,b,c) + +#define M_ASN1_INTEGER_new() (ASN1_INTEGER *)\ + ASN1_STRING_type_new(V_ASN1_INTEGER) +#define M_ASN1_INTEGER_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_ASN1_INTEGER_dup(a) (ASN1_INTEGER *)ASN1_STRING_dup((ASN1_STRING *)a) +#define M_ASN1_INTEGER_cmp(a,b) ASN1_STRING_cmp(\ + (ASN1_STRING *)a,(ASN1_STRING *)b) + +#define M_ASN1_ENUMERATED_new() (ASN1_ENUMERATED *)\ + ASN1_STRING_type_new(V_ASN1_ENUMERATED) +#define M_ASN1_ENUMERATED_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_ASN1_ENUMERATED_dup(a) (ASN1_ENUMERATED *)ASN1_STRING_dup((ASN1_STRING *)a) +#define M_ASN1_ENUMERATED_cmp(a,b) ASN1_STRING_cmp(\ + (ASN1_STRING *)a,(ASN1_STRING *)b) + +#define M_ASN1_OCTET_STRING_new() (ASN1_OCTET_STRING *)\ + ASN1_STRING_type_new(V_ASN1_OCTET_STRING) +#define M_ASN1_OCTET_STRING_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_ASN1_OCTET_STRING_dup(a) (ASN1_OCTET_STRING *)\ + ASN1_STRING_dup((ASN1_STRING *)a) +#define M_ASN1_OCTET_STRING_cmp(a,b) ASN1_STRING_cmp(\ + (ASN1_STRING *)a,(ASN1_STRING *)b) +#define M_ASN1_OCTET_STRING_set(a,b,c) ASN1_STRING_set((ASN1_STRING *)a,b,c) +#define M_ASN1_OCTET_STRING_print(a,b) ASN1_STRING_print(a,(ASN1_STRING *)b) +#define M_i2d_ASN1_OCTET_STRING(a,pp) \ + i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_OCTET_STRING,\ + V_ASN1_UNIVERSAL) + +#define B_ASN1_TIME \ + B_ASN1_UTCTIME | \ + B_ASN1_GENERALIZEDTIME + +#define B_ASN1_PRINTABLE \ + B_ASN1_PRINTABLESTRING| \ + B_ASN1_T61STRING| \ + B_ASN1_IA5STRING| \ + B_ASN1_BIT_STRING| \ + B_ASN1_UNIVERSALSTRING|\ + B_ASN1_BMPSTRING|\ + B_ASN1_UTF8STRING|\ + B_ASN1_SEQUENCE|\ + B_ASN1_UNKNOWN + +#define B_ASN1_DIRECTORYSTRING \ + B_ASN1_PRINTABLESTRING| \ + B_ASN1_TELETEXSTRING|\ + B_ASN1_BMPSTRING|\ + B_ASN1_UNIVERSALSTRING|\ + B_ASN1_UTF8STRING + +#define B_ASN1_DISPLAYTEXT \ + B_ASN1_IA5STRING| \ + B_ASN1_VISIBLESTRING| \ + B_ASN1_BMPSTRING|\ + B_ASN1_UTF8STRING + +#define M_ASN1_PRINTABLE_new() ASN1_STRING_type_new(V_ASN1_T61STRING) +#define M_ASN1_PRINTABLE_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_i2d_ASN1_PRINTABLE(a,pp) i2d_ASN1_bytes((ASN1_STRING *)a,\ + pp,a->type,V_ASN1_UNIVERSAL) +#define M_d2i_ASN1_PRINTABLE(a,pp,l) \ + d2i_ASN1_type_bytes((ASN1_STRING **)a,pp,l, \ + B_ASN1_PRINTABLE) + +#define M_DIRECTORYSTRING_new() ASN1_STRING_type_new(V_ASN1_PRINTABLESTRING) +#define M_DIRECTORYSTRING_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_i2d_DIRECTORYSTRING(a,pp) i2d_ASN1_bytes((ASN1_STRING *)a,\ + pp,a->type,V_ASN1_UNIVERSAL) +#define M_d2i_DIRECTORYSTRING(a,pp,l) \ + d2i_ASN1_type_bytes((ASN1_STRING **)a,pp,l, \ + B_ASN1_DIRECTORYSTRING) + +#define M_DISPLAYTEXT_new() ASN1_STRING_type_new(V_ASN1_VISIBLESTRING) +#define M_DISPLAYTEXT_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_i2d_DISPLAYTEXT(a,pp) i2d_ASN1_bytes((ASN1_STRING *)a,\ + pp,a->type,V_ASN1_UNIVERSAL) +#define M_d2i_DISPLAYTEXT(a,pp,l) \ + d2i_ASN1_type_bytes((ASN1_STRING **)a,pp,l, \ + B_ASN1_DISPLAYTEXT) + +#define M_ASN1_PRINTABLESTRING_new() (ASN1_PRINTABLESTRING *)\ + ASN1_STRING_type_new(V_ASN1_PRINTABLESTRING) +#define M_ASN1_PRINTABLESTRING_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_i2d_ASN1_PRINTABLESTRING(a,pp) \ + i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_PRINTABLESTRING,\ + V_ASN1_UNIVERSAL) +#define M_d2i_ASN1_PRINTABLESTRING(a,pp,l) \ + (ASN1_PRINTABLESTRING *)d2i_ASN1_type_bytes\ + ((ASN1_STRING **)a,pp,l,B_ASN1_PRINTABLESTRING) + +#define M_ASN1_T61STRING_new() (ASN1_T61STRING *)\ + ASN1_STRING_type_new(V_ASN1_T61STRING) +#define M_ASN1_T61STRING_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_i2d_ASN1_T61STRING(a,pp) \ + i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_T61STRING,\ + V_ASN1_UNIVERSAL) +#define M_d2i_ASN1_T61STRING(a,pp,l) \ + (ASN1_T61STRING *)d2i_ASN1_type_bytes\ + ((ASN1_STRING **)a,pp,l,B_ASN1_T61STRING) + +#define M_ASN1_IA5STRING_new() (ASN1_IA5STRING *)\ + ASN1_STRING_type_new(V_ASN1_IA5STRING) +#define M_ASN1_IA5STRING_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_ASN1_IA5STRING_dup(a) \ + (ASN1_IA5STRING *)ASN1_STRING_dup((ASN1_STRING *)a) +#define M_i2d_ASN1_IA5STRING(a,pp) \ + i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_IA5STRING,\ + V_ASN1_UNIVERSAL) +#define M_d2i_ASN1_IA5STRING(a,pp,l) \ + (ASN1_IA5STRING *)d2i_ASN1_type_bytes((ASN1_STRING **)a,pp,l,\ + B_ASN1_IA5STRING) + +#define M_ASN1_UTCTIME_new() (ASN1_UTCTIME *)\ + ASN1_STRING_type_new(V_ASN1_UTCTIME) +#define M_ASN1_UTCTIME_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_ASN1_UTCTIME_dup(a) (ASN1_UTCTIME *)ASN1_STRING_dup((ASN1_STRING *)a) + +#define M_ASN1_GENERALIZEDTIME_new() (ASN1_GENERALIZEDTIME *)\ + ASN1_STRING_type_new(V_ASN1_GENERALIZEDTIME) +#define M_ASN1_GENERALIZEDTIME_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_ASN1_GENERALIZEDTIME_dup(a) (ASN1_GENERALIZEDTIME *)ASN1_STRING_dup(\ + (ASN1_STRING *)a) + +#define M_ASN1_TIME_new() (ASN1_TIME *)\ + ASN1_STRING_type_new(V_ASN1_UTCTIME) +#define M_ASN1_TIME_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_ASN1_TIME_dup(a) (ASN1_TIME *)ASN1_STRING_dup((ASN1_STRING *)a) + +#define M_ASN1_GENERALSTRING_new() (ASN1_GENERALSTRING *)\ + ASN1_STRING_type_new(V_ASN1_GENERALSTRING) +#define M_ASN1_GENERALSTRING_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_i2d_ASN1_GENERALSTRING(a,pp) \ + i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_GENERALSTRING,\ + V_ASN1_UNIVERSAL) +#define M_d2i_ASN1_GENERALSTRING(a,pp,l) \ + (ASN1_GENERALSTRING *)d2i_ASN1_type_bytes\ + ((ASN1_STRING **)a,pp,l,B_ASN1_GENERALSTRING) + +#define M_ASN1_UNIVERSALSTRING_new() (ASN1_UNIVERSALSTRING *)\ + ASN1_STRING_type_new(V_ASN1_UNIVERSALSTRING) +#define M_ASN1_UNIVERSALSTRING_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_i2d_ASN1_UNIVERSALSTRING(a,pp) \ + i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_UNIVERSALSTRING,\ + V_ASN1_UNIVERSAL) +#define M_d2i_ASN1_UNIVERSALSTRING(a,pp,l) \ + (ASN1_UNIVERSALSTRING *)d2i_ASN1_type_bytes\ + ((ASN1_STRING **)a,pp,l,B_ASN1_UNIVERSALSTRING) + +#define M_ASN1_BMPSTRING_new() (ASN1_BMPSTRING *)\ + ASN1_STRING_type_new(V_ASN1_BMPSTRING) +#define M_ASN1_BMPSTRING_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_i2d_ASN1_BMPSTRING(a,pp) \ + i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_BMPSTRING,\ + V_ASN1_UNIVERSAL) +#define M_d2i_ASN1_BMPSTRING(a,pp,l) \ + (ASN1_BMPSTRING *)d2i_ASN1_type_bytes\ + ((ASN1_STRING **)a,pp,l,B_ASN1_BMPSTRING) + +#define M_ASN1_VISIBLESTRING_new() (ASN1_VISIBLESTRING *)\ + ASN1_STRING_type_new(V_ASN1_VISIBLESTRING) +#define M_ASN1_VISIBLESTRING_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_i2d_ASN1_VISIBLESTRING(a,pp) \ + i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_VISIBLESTRING,\ + V_ASN1_UNIVERSAL) +#define M_d2i_ASN1_VISIBLESTRING(a,pp,l) \ + (ASN1_VISIBLESTRING *)d2i_ASN1_type_bytes\ + ((ASN1_STRING **)a,pp,l,B_ASN1_VISIBLESTRING) + +#define M_ASN1_UTF8STRING_new() (ASN1_UTF8STRING *)\ + ASN1_STRING_type_new(V_ASN1_UTF8STRING) +#define M_ASN1_UTF8STRING_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_i2d_ASN1_UTF8STRING(a,pp) \ + i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_UTF8STRING,\ + V_ASN1_UNIVERSAL) +#define M_d2i_ASN1_UTF8STRING(a,pp,l) \ + (ASN1_UTF8STRING *)d2i_ASN1_type_bytes\ + ((ASN1_STRING **)a,pp,l,B_ASN1_UTF8STRING) + + /* for the is_set parameter to i2d_ASN1_SET */ +#define IS_SEQUENCE 0 +#define IS_SET 1 + +DECLARE_ASN1_FUNCTIONS_fname(ASN1_TYPE, ASN1_ANY, ASN1_TYPE) + +int ASN1_TYPE_get(ASN1_TYPE *a); +void ASN1_TYPE_set(ASN1_TYPE *a, int type, void *value); +int ASN1_TYPE_set1(ASN1_TYPE *a, int type, const void *value); + +ASN1_OBJECT * ASN1_OBJECT_new(void ); +void ASN1_OBJECT_free(ASN1_OBJECT *a); +int i2d_ASN1_OBJECT(ASN1_OBJECT *a,unsigned char **pp); +ASN1_OBJECT * c2i_ASN1_OBJECT(ASN1_OBJECT **a,const unsigned char **pp, + long length); +ASN1_OBJECT * d2i_ASN1_OBJECT(ASN1_OBJECT **a,const unsigned char **pp, + long length); + +DECLARE_ASN1_ITEM(ASN1_OBJECT) + +DECLARE_STACK_OF(ASN1_OBJECT) +DECLARE_ASN1_SET_OF(ASN1_OBJECT) + +ASN1_STRING * ASN1_STRING_new(void); +void ASN1_STRING_free(ASN1_STRING *a); +ASN1_STRING * ASN1_STRING_dup(ASN1_STRING *a); +ASN1_STRING * ASN1_STRING_type_new(int type ); +int ASN1_STRING_cmp(ASN1_STRING *a, ASN1_STRING *b); + /* Since this is used to store all sorts of things, via macros, for now, make + its data void * */ +int ASN1_STRING_set(ASN1_STRING *str, const void *data, int len); +void ASN1_STRING_set0(ASN1_STRING *str, void *data, int len); +int ASN1_STRING_length(ASN1_STRING *x); +void ASN1_STRING_length_set(ASN1_STRING *x, int n); +int ASN1_STRING_type(ASN1_STRING *x); +unsigned char * ASN1_STRING_data(ASN1_STRING *x); + +DECLARE_ASN1_FUNCTIONS(ASN1_BIT_STRING) +int i2c_ASN1_BIT_STRING(ASN1_BIT_STRING *a,unsigned char **pp); +ASN1_BIT_STRING *c2i_ASN1_BIT_STRING(ASN1_BIT_STRING **a,const unsigned char **pp, + long length); +int ASN1_BIT_STRING_set(ASN1_BIT_STRING *a, unsigned char *d, + int length ); +int ASN1_BIT_STRING_set_bit(ASN1_BIT_STRING *a, int n, int value); +int ASN1_BIT_STRING_get_bit(ASN1_BIT_STRING *a, int n); + +#ifndef OPENSSL_NO_BIO +int ASN1_BIT_STRING_name_print(BIO *out, ASN1_BIT_STRING *bs, + BIT_STRING_BITNAME *tbl, int indent); +#endif +int ASN1_BIT_STRING_num_asc(char *name, BIT_STRING_BITNAME *tbl); +int ASN1_BIT_STRING_set_asc(ASN1_BIT_STRING *bs, char *name, int value, + BIT_STRING_BITNAME *tbl); + +int i2d_ASN1_BOOLEAN(int a,unsigned char **pp); +int d2i_ASN1_BOOLEAN(int *a,const unsigned char **pp,long length); + +DECLARE_ASN1_FUNCTIONS(ASN1_INTEGER) +int i2c_ASN1_INTEGER(ASN1_INTEGER *a,unsigned char **pp); +ASN1_INTEGER *c2i_ASN1_INTEGER(ASN1_INTEGER **a,const unsigned char **pp, + long length); +ASN1_INTEGER *d2i_ASN1_UINTEGER(ASN1_INTEGER **a,const unsigned char **pp, + long length); +ASN1_INTEGER * ASN1_INTEGER_dup(ASN1_INTEGER *x); +int ASN1_INTEGER_cmp(ASN1_INTEGER *x, ASN1_INTEGER *y); + +DECLARE_ASN1_FUNCTIONS(ASN1_ENUMERATED) + +int ASN1_UTCTIME_check(ASN1_UTCTIME *a); +ASN1_UTCTIME *ASN1_UTCTIME_set(ASN1_UTCTIME *s,time_t t); +int ASN1_UTCTIME_set_string(ASN1_UTCTIME *s, const char *str); +int ASN1_UTCTIME_cmp_time_t(const ASN1_UTCTIME *s, time_t t); +#if 0 +time_t ASN1_UTCTIME_get(const ASN1_UTCTIME *s); +#endif + +int ASN1_GENERALIZEDTIME_check(ASN1_GENERALIZEDTIME *a); +ASN1_GENERALIZEDTIME *ASN1_GENERALIZEDTIME_set(ASN1_GENERALIZEDTIME *s,time_t t); +int ASN1_GENERALIZEDTIME_set_string(ASN1_GENERALIZEDTIME *s, const char *str); + +DECLARE_ASN1_FUNCTIONS(ASN1_OCTET_STRING) +ASN1_OCTET_STRING * ASN1_OCTET_STRING_dup(ASN1_OCTET_STRING *a); +int ASN1_OCTET_STRING_cmp(ASN1_OCTET_STRING *a, ASN1_OCTET_STRING *b); +int ASN1_OCTET_STRING_set(ASN1_OCTET_STRING *str, const unsigned char *data, int len); + +DECLARE_ASN1_FUNCTIONS(ASN1_VISIBLESTRING) +DECLARE_ASN1_FUNCTIONS(ASN1_UNIVERSALSTRING) +DECLARE_ASN1_FUNCTIONS(ASN1_UTF8STRING) +DECLARE_ASN1_FUNCTIONS(ASN1_NULL) +DECLARE_ASN1_FUNCTIONS(ASN1_BMPSTRING) + +int UTF8_getc(const unsigned char *str, int len, unsigned long *val); +int UTF8_putc(unsigned char *str, int len, unsigned long value); + +DECLARE_ASN1_FUNCTIONS_name(ASN1_STRING, ASN1_PRINTABLE) + +DECLARE_ASN1_FUNCTIONS_name(ASN1_STRING, DIRECTORYSTRING) +DECLARE_ASN1_FUNCTIONS_name(ASN1_STRING, DISPLAYTEXT) +DECLARE_ASN1_FUNCTIONS(ASN1_PRINTABLESTRING) +DECLARE_ASN1_FUNCTIONS(ASN1_T61STRING) +DECLARE_ASN1_FUNCTIONS(ASN1_IA5STRING) +DECLARE_ASN1_FUNCTIONS(ASN1_GENERALSTRING) +DECLARE_ASN1_FUNCTIONS(ASN1_UTCTIME) +DECLARE_ASN1_FUNCTIONS(ASN1_GENERALIZEDTIME) +DECLARE_ASN1_FUNCTIONS(ASN1_TIME) + +DECLARE_ASN1_ITEM(ASN1_OCTET_STRING_NDEF) + +ASN1_TIME *ASN1_TIME_set(ASN1_TIME *s,time_t t); +int ASN1_TIME_check(ASN1_TIME *t); +ASN1_GENERALIZEDTIME *ASN1_TIME_to_generalizedtime(ASN1_TIME *t, ASN1_GENERALIZEDTIME **out); + +int i2d_ASN1_SET(STACK *a, unsigned char **pp, + i2d_of_void *i2d, int ex_tag, int ex_class, int is_set); +STACK * d2i_ASN1_SET(STACK **a, const unsigned char **pp, long length, + d2i_of_void *d2i, void (*free_func)(void *), + int ex_tag, int ex_class); + +#ifndef OPENSSL_NO_BIO +int i2a_ASN1_INTEGER(BIO *bp, ASN1_INTEGER *a); +int a2i_ASN1_INTEGER(BIO *bp,ASN1_INTEGER *bs,char *buf,int size); +int i2a_ASN1_ENUMERATED(BIO *bp, ASN1_ENUMERATED *a); +int a2i_ASN1_ENUMERATED(BIO *bp,ASN1_ENUMERATED *bs,char *buf,int size); +int i2a_ASN1_OBJECT(BIO *bp,ASN1_OBJECT *a); +int a2i_ASN1_STRING(BIO *bp,ASN1_STRING *bs,char *buf,int size); +int i2a_ASN1_STRING(BIO *bp, ASN1_STRING *a, int type); +#endif +int i2t_ASN1_OBJECT(char *buf,int buf_len,ASN1_OBJECT *a); + +int a2d_ASN1_OBJECT(unsigned char *out,int olen, const char *buf, int num); +ASN1_OBJECT *ASN1_OBJECT_create(int nid, unsigned char *data,int len, + const char *sn, const char *ln); + +int ASN1_INTEGER_set(ASN1_INTEGER *a, long v); +long ASN1_INTEGER_get(ASN1_INTEGER *a); +ASN1_INTEGER *BN_to_ASN1_INTEGER(BIGNUM *bn, ASN1_INTEGER *ai); +BIGNUM *ASN1_INTEGER_to_BN(ASN1_INTEGER *ai,BIGNUM *bn); + +int ASN1_ENUMERATED_set(ASN1_ENUMERATED *a, long v); +long ASN1_ENUMERATED_get(ASN1_ENUMERATED *a); +ASN1_ENUMERATED *BN_to_ASN1_ENUMERATED(BIGNUM *bn, ASN1_ENUMERATED *ai); +BIGNUM *ASN1_ENUMERATED_to_BN(ASN1_ENUMERATED *ai,BIGNUM *bn); + +/* General */ +/* given a string, return the correct type, max is the maximum length */ +int ASN1_PRINTABLE_type(const unsigned char *s, int max); + +int i2d_ASN1_bytes(ASN1_STRING *a, unsigned char **pp, int tag, int xclass); +ASN1_STRING *d2i_ASN1_bytes(ASN1_STRING **a, const unsigned char **pp, + long length, int Ptag, int Pclass); +unsigned long ASN1_tag2bit(int tag); +/* type is one or more of the B_ASN1_ values. */ +ASN1_STRING *d2i_ASN1_type_bytes(ASN1_STRING **a,const unsigned char **pp, + long length,int type); + +/* PARSING */ +int asn1_Finish(ASN1_CTX *c); +int asn1_const_Finish(ASN1_const_CTX *c); + +/* SPECIALS */ +int ASN1_get_object(const unsigned char **pp, long *plength, int *ptag, + int *pclass, long omax); +int ASN1_check_infinite_end(unsigned char **p,long len); +int ASN1_const_check_infinite_end(const unsigned char **p,long len); +void ASN1_put_object(unsigned char **pp, int constructed, int length, + int tag, int xclass); +int ASN1_put_eoc(unsigned char **pp); +int ASN1_object_size(int constructed, int length, int tag); + +/* Used to implement other functions */ +void *ASN1_dup(i2d_of_void *i2d, d2i_of_void *d2i, char *x); + +#define ASN1_dup_of(type,i2d,d2i,x) \ + ((type*)ASN1_dup(CHECKED_I2D_OF(type, i2d), \ + CHECKED_D2I_OF(type, d2i), \ + CHECKED_PTR_OF(type, x))) + +#define ASN1_dup_of_const(type,i2d,d2i,x) \ + ((type*)ASN1_dup(CHECKED_I2D_OF(const type, i2d), \ + CHECKED_D2I_OF(type, d2i), \ + CHECKED_PTR_OF(const type, x))) + +void *ASN1_item_dup(const ASN1_ITEM *it, void *x); + +/* ASN1 alloc/free macros for when a type is only used internally */ + +#define M_ASN1_new_of(type) (type *)ASN1_item_new(ASN1_ITEM_rptr(type)) +#define M_ASN1_free_of(x, type) \ + ASN1_item_free(CHECKED_PTR_OF(type, x), ASN1_ITEM_rptr(type)) + +#ifndef OPENSSL_NO_FP_API +void *ASN1_d2i_fp(void *(*xnew)(void), d2i_of_void *d2i, FILE *in, void **x); + +#define ASN1_d2i_fp_of(type,xnew,d2i,in,x) \ + ((type*)ASN1_d2i_fp(CHECKED_NEW_OF(type, xnew), \ + CHECKED_D2I_OF(type, d2i), \ + in, \ + CHECKED_PPTR_OF(type, x))) + +void *ASN1_item_d2i_fp(const ASN1_ITEM *it, FILE *in, void *x); +int ASN1_i2d_fp(i2d_of_void *i2d,FILE *out,void *x); + +#define ASN1_i2d_fp_of(type,i2d,out,x) \ + (ASN1_i2d_fp(CHECKED_I2D_OF(type, i2d), \ + out, \ + CHECKED_PTR_OF(type, x))) + +#define ASN1_i2d_fp_of_const(type,i2d,out,x) \ + (ASN1_i2d_fp(CHECKED_I2D_OF(const type, i2d), \ + out, \ + CHECKED_PTR_OF(const type, x))) + +int ASN1_item_i2d_fp(const ASN1_ITEM *it, FILE *out, void *x); +int ASN1_STRING_print_ex_fp(FILE *fp, ASN1_STRING *str, unsigned long flags); +#endif + +int ASN1_STRING_to_UTF8(unsigned char **out, ASN1_STRING *in); + +#ifndef OPENSSL_NO_BIO +void *ASN1_d2i_bio(void *(*xnew)(void), d2i_of_void *d2i, BIO *in, void **x); + +#define ASN1_d2i_bio_of(type,xnew,d2i,in,x) \ + ((type*)ASN1_d2i_bio( CHECKED_NEW_OF(type, xnew), \ + CHECKED_D2I_OF(type, d2i), \ + in, \ + CHECKED_PPTR_OF(type, x))) + +void *ASN1_item_d2i_bio(const ASN1_ITEM *it, BIO *in, void *x); +int ASN1_i2d_bio(i2d_of_void *i2d,BIO *out, unsigned char *x); + +#define ASN1_i2d_bio_of(type,i2d,out,x) \ + (ASN1_i2d_bio(CHECKED_I2D_OF(type, i2d), \ + out, \ + CHECKED_PTR_OF(type, x))) + +#define ASN1_i2d_bio_of_const(type,i2d,out,x) \ + (ASN1_i2d_bio(CHECKED_I2D_OF(const type, i2d), \ + out, \ + CHECKED_PTR_OF(const type, x))) + +int ASN1_item_i2d_bio(const ASN1_ITEM *it, BIO *out, void *x); +int ASN1_UTCTIME_print(BIO *fp,ASN1_UTCTIME *a); +int ASN1_GENERALIZEDTIME_print(BIO *fp,ASN1_GENERALIZEDTIME *a); +int ASN1_TIME_print(BIO *fp,ASN1_TIME *a); +int ASN1_STRING_print(BIO *bp,ASN1_STRING *v); +int ASN1_STRING_print_ex(BIO *out, ASN1_STRING *str, unsigned long flags); +int ASN1_parse(BIO *bp,const unsigned char *pp,long len,int indent); +int ASN1_parse_dump(BIO *bp,const unsigned char *pp,long len,int indent,int dump); +#endif +const char *ASN1_tag2str(int tag); + +/* Used to load and write netscape format cert/key */ +int i2d_ASN1_HEADER(ASN1_HEADER *a,unsigned char **pp); +ASN1_HEADER *d2i_ASN1_HEADER(ASN1_HEADER **a,const unsigned char **pp, long length); +ASN1_HEADER *ASN1_HEADER_new(void ); +void ASN1_HEADER_free(ASN1_HEADER *a); + +int ASN1_UNIVERSALSTRING_to_string(ASN1_UNIVERSALSTRING *s); + +/* Not used that much at this point, except for the first two */ +ASN1_METHOD *X509_asn1_meth(void); +ASN1_METHOD *RSAPrivateKey_asn1_meth(void); +ASN1_METHOD *ASN1_IA5STRING_asn1_meth(void); +ASN1_METHOD *ASN1_BIT_STRING_asn1_meth(void); + +int ASN1_TYPE_set_octetstring(ASN1_TYPE *a, + unsigned char *data, int len); +int ASN1_TYPE_get_octetstring(ASN1_TYPE *a, + unsigned char *data, int max_len); +int ASN1_TYPE_set_int_octetstring(ASN1_TYPE *a, long num, + unsigned char *data, int len); +int ASN1_TYPE_get_int_octetstring(ASN1_TYPE *a,long *num, + unsigned char *data, int max_len); + +STACK *ASN1_seq_unpack(const unsigned char *buf, int len, + d2i_of_void *d2i, void (*free_func)(void *)); +unsigned char *ASN1_seq_pack(STACK *safes, i2d_of_void *i2d, + unsigned char **buf, int *len ); +void *ASN1_unpack_string(ASN1_STRING *oct, d2i_of_void *d2i); +void *ASN1_item_unpack(ASN1_STRING *oct, const ASN1_ITEM *it); +ASN1_STRING *ASN1_pack_string(void *obj, i2d_of_void *i2d, + ASN1_OCTET_STRING **oct); + +#define ASN1_pack_string_of(type,obj,i2d,oct) \ + (ASN1_pack_string(CHECKED_PTR_OF(type, obj), \ + CHECKED_I2D_OF(type, i2d), \ + oct)) + +ASN1_STRING *ASN1_item_pack(void *obj, const ASN1_ITEM *it, ASN1_OCTET_STRING **oct); + +void ASN1_STRING_set_default_mask(unsigned long mask); +int ASN1_STRING_set_default_mask_asc(char *p); +unsigned long ASN1_STRING_get_default_mask(void); +int ASN1_mbstring_copy(ASN1_STRING **out, const unsigned char *in, int len, + int inform, unsigned long mask); +int ASN1_mbstring_ncopy(ASN1_STRING **out, const unsigned char *in, int len, + int inform, unsigned long mask, + long minsize, long maxsize); + +ASN1_STRING *ASN1_STRING_set_by_NID(ASN1_STRING **out, + const unsigned char *in, int inlen, int inform, int nid); +ASN1_STRING_TABLE *ASN1_STRING_TABLE_get(int nid); +int ASN1_STRING_TABLE_add(int, long, long, unsigned long, unsigned long); +void ASN1_STRING_TABLE_cleanup(void); + +/* ASN1 template functions */ + +/* Old API compatible functions */ +ASN1_VALUE *ASN1_item_new(const ASN1_ITEM *it); +void ASN1_item_free(ASN1_VALUE *val, const ASN1_ITEM *it); +ASN1_VALUE * ASN1_item_d2i(ASN1_VALUE **val, const unsigned char **in, long len, const ASN1_ITEM *it); +int ASN1_item_i2d(ASN1_VALUE *val, unsigned char **out, const ASN1_ITEM *it); +int ASN1_item_ndef_i2d(ASN1_VALUE *val, unsigned char **out, const ASN1_ITEM *it); + +void ASN1_add_oid_module(void); + +ASN1_TYPE *ASN1_generate_nconf(char *str, CONF *nconf); +ASN1_TYPE *ASN1_generate_v3(char *str, X509V3_CTX *cnf); + +typedef int asn1_output_data_fn(BIO *out, BIO *data, ASN1_VALUE *val, int flags, + const ASN1_ITEM *it); + +int int_smime_write_ASN1(BIO *bio, ASN1_VALUE *val, BIO *data, int flags, + int ctype_nid, int econt_nid, + STACK_OF(X509_ALGOR) *mdalgs, + asn1_output_data_fn *data_fn, + const ASN1_ITEM *it); +ASN1_VALUE *SMIME_read_ASN1(BIO *bio, BIO **bcont, const ASN1_ITEM *it); + +/* BEGIN ERROR CODES */ +/* The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ +void ERR_load_ASN1_strings(void); + +/* Error codes for the ASN1 functions. */ + +/* Function codes. */ +#define ASN1_F_A2D_ASN1_OBJECT 100 +#define ASN1_F_A2I_ASN1_ENUMERATED 101 +#define ASN1_F_A2I_ASN1_INTEGER 102 +#define ASN1_F_A2I_ASN1_STRING 103 +#define ASN1_F_APPEND_EXP 176 +#define ASN1_F_ASN1_BIT_STRING_SET_BIT 183 +#define ASN1_F_ASN1_CB 177 +#define ASN1_F_ASN1_CHECK_TLEN 104 +#define ASN1_F_ASN1_COLLATE_PRIMITIVE 105 +#define ASN1_F_ASN1_COLLECT 106 +#define ASN1_F_ASN1_D2I_EX_PRIMITIVE 108 +#define ASN1_F_ASN1_D2I_FP 109 +#define ASN1_F_ASN1_D2I_READ_BIO 107 +#define ASN1_F_ASN1_DIGEST 184 +#define ASN1_F_ASN1_DO_ADB 110 +#define ASN1_F_ASN1_DUP 111 +#define ASN1_F_ASN1_ENUMERATED_SET 112 +#define ASN1_F_ASN1_ENUMERATED_TO_BN 113 +#define ASN1_F_ASN1_EX_C2I 204 +#define ASN1_F_ASN1_FIND_END 190 +#define ASN1_F_ASN1_GENERALIZEDTIME_SET 185 +#define ASN1_F_ASN1_GENERATE_V3 178 +#define ASN1_F_ASN1_GET_OBJECT 114 +#define ASN1_F_ASN1_HEADER_NEW 115 +#define ASN1_F_ASN1_I2D_BIO 116 +#define ASN1_F_ASN1_I2D_FP 117 +#define ASN1_F_ASN1_INTEGER_SET 118 +#define ASN1_F_ASN1_INTEGER_TO_BN 119 +#define ASN1_F_ASN1_ITEM_D2I_FP 206 +#define ASN1_F_ASN1_ITEM_DUP 191 +#define ASN1_F_ASN1_ITEM_EX_COMBINE_NEW 121 +#define ASN1_F_ASN1_ITEM_EX_D2I 120 +#define ASN1_F_ASN1_ITEM_I2D_BIO 192 +#define ASN1_F_ASN1_ITEM_I2D_FP 193 +#define ASN1_F_ASN1_ITEM_PACK 198 +#define ASN1_F_ASN1_ITEM_SIGN 195 +#define ASN1_F_ASN1_ITEM_UNPACK 199 +#define ASN1_F_ASN1_ITEM_VERIFY 197 +#define ASN1_F_ASN1_MBSTRING_NCOPY 122 +#define ASN1_F_ASN1_OBJECT_NEW 123 +#define ASN1_F_ASN1_OUTPUT_DATA 207 +#define ASN1_F_ASN1_PACK_STRING 124 +#define ASN1_F_ASN1_PCTX_NEW 205 +#define ASN1_F_ASN1_PKCS5_PBE_SET 125 +#define ASN1_F_ASN1_SEQ_PACK 126 +#define ASN1_F_ASN1_SEQ_UNPACK 127 +#define ASN1_F_ASN1_SIGN 128 +#define ASN1_F_ASN1_STR2TYPE 179 +#define ASN1_F_ASN1_STRING_SET 186 +#define ASN1_F_ASN1_STRING_TABLE_ADD 129 +#define ASN1_F_ASN1_STRING_TYPE_NEW 130 +#define ASN1_F_ASN1_TEMPLATE_EX_D2I 132 +#define ASN1_F_ASN1_TEMPLATE_NEW 133 +#define ASN1_F_ASN1_TEMPLATE_NOEXP_D2I 131 +#define ASN1_F_ASN1_TIME_SET 175 +#define ASN1_F_ASN1_TYPE_GET_INT_OCTETSTRING 134 +#define ASN1_F_ASN1_TYPE_GET_OCTETSTRING 135 +#define ASN1_F_ASN1_UNPACK_STRING 136 +#define ASN1_F_ASN1_UTCTIME_SET 187 +#define ASN1_F_ASN1_VERIFY 137 +#define ASN1_F_B64_READ_ASN1 208 +#define ASN1_F_B64_WRITE_ASN1 209 +#define ASN1_F_BITSTR_CB 180 +#define ASN1_F_BN_TO_ASN1_ENUMERATED 138 +#define ASN1_F_BN_TO_ASN1_INTEGER 139 +#define ASN1_F_C2I_ASN1_BIT_STRING 189 +#define ASN1_F_C2I_ASN1_INTEGER 194 +#define ASN1_F_C2I_ASN1_OBJECT 196 +#define ASN1_F_COLLECT_DATA 140 +#define ASN1_F_D2I_ASN1_BIT_STRING 141 +#define ASN1_F_D2I_ASN1_BOOLEAN 142 +#define ASN1_F_D2I_ASN1_BYTES 143 +#define ASN1_F_D2I_ASN1_GENERALIZEDTIME 144 +#define ASN1_F_D2I_ASN1_HEADER 145 +#define ASN1_F_D2I_ASN1_INTEGER 146 +#define ASN1_F_D2I_ASN1_OBJECT 147 +#define ASN1_F_D2I_ASN1_SET 148 +#define ASN1_F_D2I_ASN1_TYPE_BYTES 149 +#define ASN1_F_D2I_ASN1_UINTEGER 150 +#define ASN1_F_D2I_ASN1_UTCTIME 151 +#define ASN1_F_D2I_NETSCAPE_RSA 152 +#define ASN1_F_D2I_NETSCAPE_RSA_2 153 +#define ASN1_F_D2I_PRIVATEKEY 154 +#define ASN1_F_D2I_PUBLICKEY 155 +#define ASN1_F_D2I_RSA_NET 200 +#define ASN1_F_D2I_RSA_NET_2 201 +#define ASN1_F_D2I_X509 156 +#define ASN1_F_D2I_X509_CINF 157 +#define ASN1_F_D2I_X509_PKEY 159 +#define ASN1_F_I2D_ASN1_SET 188 +#define ASN1_F_I2D_ASN1_TIME 160 +#define ASN1_F_I2D_DSA_PUBKEY 161 +#define ASN1_F_I2D_EC_PUBKEY 181 +#define ASN1_F_I2D_PRIVATEKEY 163 +#define ASN1_F_I2D_PUBLICKEY 164 +#define ASN1_F_I2D_RSA_NET 162 +#define ASN1_F_I2D_RSA_PUBKEY 165 +#define ASN1_F_LONG_C2I 166 +#define ASN1_F_OID_MODULE_INIT 174 +#define ASN1_F_PARSE_TAGGING 182 +#define ASN1_F_PKCS5_PBE2_SET 167 +#define ASN1_F_PKCS5_PBE_SET 202 +#define ASN1_F_SMIME_READ_ASN1 210 +#define ASN1_F_SMIME_TEXT 211 +#define ASN1_F_X509_CINF_NEW 168 +#define ASN1_F_X509_CRL_ADD0_REVOKED 169 +#define ASN1_F_X509_INFO_NEW 170 +#define ASN1_F_X509_NAME_ENCODE 203 +#define ASN1_F_X509_NAME_EX_D2I 158 +#define ASN1_F_X509_NAME_EX_NEW 171 +#define ASN1_F_X509_NEW 172 +#define ASN1_F_X509_PKEY_NEW 173 + +/* Reason codes. */ +#define ASN1_R_ADDING_OBJECT 171 +#define ASN1_R_ASN1_PARSE_ERROR 198 +#define ASN1_R_ASN1_SIG_PARSE_ERROR 199 +#define ASN1_R_AUX_ERROR 100 +#define ASN1_R_BAD_CLASS 101 +#define ASN1_R_BAD_OBJECT_HEADER 102 +#define ASN1_R_BAD_PASSWORD_READ 103 +#define ASN1_R_BAD_TAG 104 +#define ASN1_R_BN_LIB 105 +#define ASN1_R_BOOLEAN_IS_WRONG_LENGTH 106 +#define ASN1_R_BUFFER_TOO_SMALL 107 +#define ASN1_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER 108 +#define ASN1_R_DATA_IS_WRONG 109 +#define ASN1_R_DECODE_ERROR 110 +#define ASN1_R_DECODING_ERROR 111 +#define ASN1_R_DEPTH_EXCEEDED 174 +#define ASN1_R_ENCODE_ERROR 112 +#define ASN1_R_ERROR_GETTING_TIME 173 +#define ASN1_R_ERROR_LOADING_SECTION 172 +#define ASN1_R_ERROR_PARSING_SET_ELEMENT 113 +#define ASN1_R_ERROR_SETTING_CIPHER_PARAMS 114 +#define ASN1_R_EXPECTING_AN_INTEGER 115 +#define ASN1_R_EXPECTING_AN_OBJECT 116 +#define ASN1_R_EXPECTING_A_BOOLEAN 117 +#define ASN1_R_EXPECTING_A_TIME 118 +#define ASN1_R_EXPLICIT_LENGTH_MISMATCH 119 +#define ASN1_R_EXPLICIT_TAG_NOT_CONSTRUCTED 120 +#define ASN1_R_FIELD_MISSING 121 +#define ASN1_R_FIRST_NUM_TOO_LARGE 122 +#define ASN1_R_HEADER_TOO_LONG 123 +#define ASN1_R_ILLEGAL_BITSTRING_FORMAT 175 +#define ASN1_R_ILLEGAL_BOOLEAN 176 +#define ASN1_R_ILLEGAL_CHARACTERS 124 +#define ASN1_R_ILLEGAL_FORMAT 177 +#define ASN1_R_ILLEGAL_HEX 178 +#define ASN1_R_ILLEGAL_IMPLICIT_TAG 179 +#define ASN1_R_ILLEGAL_INTEGER 180 +#define ASN1_R_ILLEGAL_NESTED_TAGGING 181 +#define ASN1_R_ILLEGAL_NULL 125 +#define ASN1_R_ILLEGAL_NULL_VALUE 182 +#define ASN1_R_ILLEGAL_OBJECT 183 +#define ASN1_R_ILLEGAL_OPTIONAL_ANY 126 +#define ASN1_R_ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE 170 +#define ASN1_R_ILLEGAL_TAGGED_ANY 127 +#define ASN1_R_ILLEGAL_TIME_VALUE 184 +#define ASN1_R_INTEGER_NOT_ASCII_FORMAT 185 +#define ASN1_R_INTEGER_TOO_LARGE_FOR_LONG 128 +#define ASN1_R_INVALID_BMPSTRING_LENGTH 129 +#define ASN1_R_INVALID_DIGIT 130 +#define ASN1_R_INVALID_MIME_TYPE 200 +#define ASN1_R_INVALID_MODIFIER 186 +#define ASN1_R_INVALID_NUMBER 187 +#define ASN1_R_INVALID_SEPARATOR 131 +#define ASN1_R_INVALID_TIME_FORMAT 132 +#define ASN1_R_INVALID_UNIVERSALSTRING_LENGTH 133 +#define ASN1_R_INVALID_UTF8STRING 134 +#define ASN1_R_IV_TOO_LARGE 135 +#define ASN1_R_LENGTH_ERROR 136 +#define ASN1_R_LIST_ERROR 188 +#define ASN1_R_MIME_NO_CONTENT_TYPE 201 +#define ASN1_R_MIME_PARSE_ERROR 202 +#define ASN1_R_MIME_SIG_PARSE_ERROR 203 +#define ASN1_R_MISSING_EOC 137 +#define ASN1_R_MISSING_SECOND_NUMBER 138 +#define ASN1_R_MISSING_VALUE 189 +#define ASN1_R_MSTRING_NOT_UNIVERSAL 139 +#define ASN1_R_MSTRING_WRONG_TAG 140 +#define ASN1_R_NESTED_ASN1_STRING 197 +#define ASN1_R_NON_HEX_CHARACTERS 141 +#define ASN1_R_NOT_ASCII_FORMAT 190 +#define ASN1_R_NOT_ENOUGH_DATA 142 +#define ASN1_R_NO_CONTENT_TYPE 204 +#define ASN1_R_NO_MATCHING_CHOICE_TYPE 143 +#define ASN1_R_NO_MULTIPART_BODY_FAILURE 205 +#define ASN1_R_NO_MULTIPART_BOUNDARY 206 +#define ASN1_R_NO_SIG_CONTENT_TYPE 207 +#define ASN1_R_NULL_IS_WRONG_LENGTH 144 +#define ASN1_R_OBJECT_NOT_ASCII_FORMAT 191 +#define ASN1_R_ODD_NUMBER_OF_CHARS 145 +#define ASN1_R_PRIVATE_KEY_HEADER_MISSING 146 +#define ASN1_R_SECOND_NUMBER_TOO_LARGE 147 +#define ASN1_R_SEQUENCE_LENGTH_MISMATCH 148 +#define ASN1_R_SEQUENCE_NOT_CONSTRUCTED 149 +#define ASN1_R_SEQUENCE_OR_SET_NEEDS_CONFIG 192 +#define ASN1_R_SHORT_LINE 150 +#define ASN1_R_SIG_INVALID_MIME_TYPE 208 +#define ASN1_R_STREAMING_NOT_SUPPORTED 209 +#define ASN1_R_STRING_TOO_LONG 151 +#define ASN1_R_STRING_TOO_SHORT 152 +#define ASN1_R_TAG_VALUE_TOO_HIGH 153 +#define ASN1_R_THE_ASN1_OBJECT_IDENTIFIER_IS_NOT_KNOWN_FOR_THIS_MD 154 +#define ASN1_R_TIME_NOT_ASCII_FORMAT 193 +#define ASN1_R_TOO_LONG 155 +#define ASN1_R_TYPE_NOT_CONSTRUCTED 156 +#define ASN1_R_UNABLE_TO_DECODE_RSA_KEY 157 +#define ASN1_R_UNABLE_TO_DECODE_RSA_PRIVATE_KEY 158 +#define ASN1_R_UNEXPECTED_EOC 159 +#define ASN1_R_UNKNOWN_FORMAT 160 +#define ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM 161 +#define ASN1_R_UNKNOWN_OBJECT_TYPE 162 +#define ASN1_R_UNKNOWN_PUBLIC_KEY_TYPE 163 +#define ASN1_R_UNKNOWN_TAG 194 +#define ASN1_R_UNKOWN_FORMAT 195 +#define ASN1_R_UNSUPPORTED_ANY_DEFINED_BY_TYPE 164 +#define ASN1_R_UNSUPPORTED_CIPHER 165 +#define ASN1_R_UNSUPPORTED_ENCRYPTION_ALGORITHM 166 +#define ASN1_R_UNSUPPORTED_PUBLIC_KEY_TYPE 167 +#define ASN1_R_UNSUPPORTED_TYPE 196 +#define ASN1_R_WRONG_TAG 168 +#define ASN1_R_WRONG_TYPE 169 + +#ifdef __cplusplus +} +#endif +#endif diff --git a/lib_tls/include/openssl/asn1_mac.h b/lib_tls/include/openssl/asn1_mac.h new file mode 100644 index 000000000..d958ca60d --- /dev/null +++ b/lib_tls/include/openssl/asn1_mac.h @@ -0,0 +1,571 @@ +/* crypto/asn1/asn1_mac.h */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#ifndef HEADER_ASN1_MAC_H +#define HEADER_ASN1_MAC_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef ASN1_MAC_ERR_LIB +#define ASN1_MAC_ERR_LIB ERR_LIB_ASN1 +#endif + +#define ASN1_MAC_H_err(f,r,line) \ + ERR_PUT_error(ASN1_MAC_ERR_LIB,(f),(r),__FILE__,(line)) + +#define M_ASN1_D2I_vars(a,type,func) \ + ASN1_const_CTX c; \ + type ret=NULL; \ + \ + c.pp=(const unsigned char **)pp; \ + c.q= *(const unsigned char **)pp; \ + c.error=ERR_R_NESTED_ASN1_ERROR; \ + if ((a == NULL) || ((*a) == NULL)) \ + { if ((ret=(type)func()) == NULL) \ + { c.line=__LINE__; goto err; } } \ + else ret=(*a); + +#define M_ASN1_D2I_Init() \ + c.p= *(const unsigned char **)pp; \ + c.max=(length == 0)?0:(c.p+length); + +#define M_ASN1_D2I_Finish_2(a) \ + if (!asn1_const_Finish(&c)) \ + { c.line=__LINE__; goto err; } \ + *(const unsigned char **)pp=c.p; \ + if (a != NULL) (*a)=ret; \ + return(ret); + +#define M_ASN1_D2I_Finish(a,func,e) \ + M_ASN1_D2I_Finish_2(a); \ +err:\ + ASN1_MAC_H_err((e),c.error,c.line); \ + asn1_add_error(*(const unsigned char **)pp,(int)(c.q- *pp)); \ + if ((ret != NULL) && ((a == NULL) || (*a != ret))) func(ret); \ + return(NULL) + +#define M_ASN1_D2I_start_sequence() \ + if (!asn1_GetSequence(&c,&length)) \ + { c.line=__LINE__; goto err; } +/* Begin reading ASN1 without a surrounding sequence */ +#define M_ASN1_D2I_begin() \ + c.slen = length; + +/* End reading ASN1 with no check on length */ +#define M_ASN1_D2I_Finish_nolen(a, func, e) \ + *pp=c.p; \ + if (a != NULL) (*a)=ret; \ + return(ret); \ +err:\ + ASN1_MAC_H_err((e),c.error,c.line); \ + asn1_add_error(*pp,(int)(c.q- *pp)); \ + if ((ret != NULL) && ((a == NULL) || (*a != ret))) func(ret); \ + return(NULL) + +#define M_ASN1_D2I_end_sequence() \ + (((c.inf&1) == 0)?(c.slen <= 0): \ + (c.eos=ASN1_const_check_infinite_end(&c.p,c.slen))) + +/* Don't use this with d2i_ASN1_BOOLEAN() */ +#define M_ASN1_D2I_get(b, func) \ + c.q=c.p; \ + if (func(&(b),&c.p,c.slen) == NULL) \ + {c.line=__LINE__; goto err; } \ + c.slen-=(c.p-c.q); + +/* Don't use this with d2i_ASN1_BOOLEAN() */ +#define M_ASN1_D2I_get_x(type,b,func) \ + c.q=c.p; \ + if (((D2I_OF(type))func)(&(b),&c.p,c.slen) == NULL) \ + {c.line=__LINE__; goto err; } \ + c.slen-=(c.p-c.q); + +/* use this instead () */ +#define M_ASN1_D2I_get_int(b,func) \ + c.q=c.p; \ + if (func(&(b),&c.p,c.slen) < 0) \ + {c.line=__LINE__; goto err; } \ + c.slen-=(c.p-c.q); + +#define M_ASN1_D2I_get_opt(b,func,type) \ + if ((c.slen != 0) && ((M_ASN1_next & (~V_ASN1_CONSTRUCTED)) \ + == (V_ASN1_UNIVERSAL|(type)))) \ + { \ + M_ASN1_D2I_get(b,func); \ + } + +#define M_ASN1_D2I_get_imp(b,func, type) \ + M_ASN1_next=(_tmp& V_ASN1_CONSTRUCTED)|type; \ + c.q=c.p; \ + if (func(&(b),&c.p,c.slen) == NULL) \ + {c.line=__LINE__; M_ASN1_next_prev = _tmp; goto err; } \ + c.slen-=(c.p-c.q);\ + M_ASN1_next_prev=_tmp; + +#define M_ASN1_D2I_get_IMP_opt(b,func,tag,type) \ + if ((c.slen != 0) && ((M_ASN1_next & (~V_ASN1_CONSTRUCTED)) == \ + (V_ASN1_CONTEXT_SPECIFIC|(tag)))) \ + { \ + unsigned char _tmp = M_ASN1_next; \ + M_ASN1_D2I_get_imp(b,func, type);\ + } + +#define M_ASN1_D2I_get_set(r,func,free_func) \ + M_ASN1_D2I_get_imp_set(r,func,free_func, \ + V_ASN1_SET,V_ASN1_UNIVERSAL); + +#define M_ASN1_D2I_get_set_type(type,r,func,free_func) \ + M_ASN1_D2I_get_imp_set_type(type,r,func,free_func, \ + V_ASN1_SET,V_ASN1_UNIVERSAL); + +#define M_ASN1_D2I_get_set_opt(r,func,free_func) \ + if ((c.slen != 0) && (M_ASN1_next == (V_ASN1_UNIVERSAL| \ + V_ASN1_CONSTRUCTED|V_ASN1_SET)))\ + { M_ASN1_D2I_get_set(r,func,free_func); } + +#define M_ASN1_D2I_get_set_opt_type(type,r,func,free_func) \ + if ((c.slen != 0) && (M_ASN1_next == (V_ASN1_UNIVERSAL| \ + V_ASN1_CONSTRUCTED|V_ASN1_SET)))\ + { M_ASN1_D2I_get_set_type(type,r,func,free_func); } + +#define M_ASN1_I2D_len_SET_opt(a,f) \ + if ((a != NULL) && (sk_num(a) != 0)) \ + M_ASN1_I2D_len_SET(a,f); + +#define M_ASN1_I2D_put_SET_opt(a,f) \ + if ((a != NULL) && (sk_num(a) != 0)) \ + M_ASN1_I2D_put_SET(a,f); + +#define M_ASN1_I2D_put_SEQUENCE_opt(a,f) \ + if ((a != NULL) && (sk_num(a) != 0)) \ + M_ASN1_I2D_put_SEQUENCE(a,f); + +#define M_ASN1_I2D_put_SEQUENCE_opt_type(type,a,f) \ + if ((a != NULL) && (sk_##type##_num(a) != 0)) \ + M_ASN1_I2D_put_SEQUENCE_type(type,a,f); + +#define M_ASN1_D2I_get_IMP_set_opt(b,func,free_func,tag) \ + if ((c.slen != 0) && \ + (M_ASN1_next == \ + (V_ASN1_CONTEXT_SPECIFIC|V_ASN1_CONSTRUCTED|(tag))))\ + { \ + M_ASN1_D2I_get_imp_set(b,func,free_func,\ + tag,V_ASN1_CONTEXT_SPECIFIC); \ + } + +#define M_ASN1_D2I_get_IMP_set_opt_type(type,b,func,free_func,tag) \ + if ((c.slen != 0) && \ + (M_ASN1_next == \ + (V_ASN1_CONTEXT_SPECIFIC|V_ASN1_CONSTRUCTED|(tag))))\ + { \ + M_ASN1_D2I_get_imp_set_type(type,b,func,free_func,\ + tag,V_ASN1_CONTEXT_SPECIFIC); \ + } + +#define M_ASN1_D2I_get_seq(r,func,free_func) \ + M_ASN1_D2I_get_imp_set(r,func,free_func,\ + V_ASN1_SEQUENCE,V_ASN1_UNIVERSAL); + +#define M_ASN1_D2I_get_seq_type(type,r,func,free_func) \ + M_ASN1_D2I_get_imp_set_type(type,r,func,free_func,\ + V_ASN1_SEQUENCE,V_ASN1_UNIVERSAL) + +#define M_ASN1_D2I_get_seq_opt(r,func,free_func) \ + if ((c.slen != 0) && (M_ASN1_next == (V_ASN1_UNIVERSAL| \ + V_ASN1_CONSTRUCTED|V_ASN1_SEQUENCE)))\ + { M_ASN1_D2I_get_seq(r,func,free_func); } + +#define M_ASN1_D2I_get_seq_opt_type(type,r,func,free_func) \ + if ((c.slen != 0) && (M_ASN1_next == (V_ASN1_UNIVERSAL| \ + V_ASN1_CONSTRUCTED|V_ASN1_SEQUENCE)))\ + { M_ASN1_D2I_get_seq_type(type,r,func,free_func); } + +#define M_ASN1_D2I_get_IMP_set(r,func,free_func,x) \ + M_ASN1_D2I_get_imp_set(r,func,free_func,\ + x,V_ASN1_CONTEXT_SPECIFIC); + +#define M_ASN1_D2I_get_IMP_set_type(type,r,func,free_func,x) \ + M_ASN1_D2I_get_imp_set_type(type,r,func,free_func,\ + x,V_ASN1_CONTEXT_SPECIFIC); + +#define M_ASN1_D2I_get_imp_set(r,func,free_func,a,b) \ + c.q=c.p; \ + if (d2i_ASN1_SET(&(r),&c.p,c.slen,(char *(*)())func,\ + (void (*)())free_func,a,b) == NULL) \ + { c.line=__LINE__; goto err; } \ + c.slen-=(c.p-c.q); + +#define M_ASN1_D2I_get_imp_set_type(type,r,func,free_func,a,b) \ + c.q=c.p; \ + if (d2i_ASN1_SET_OF_##type(&(r),&c.p,c.slen,func,\ + free_func,a,b) == NULL) \ + { c.line=__LINE__; goto err; } \ + c.slen-=(c.p-c.q); + +#define M_ASN1_D2I_get_set_strings(r,func,a,b) \ + c.q=c.p; \ + if (d2i_ASN1_STRING_SET(&(r),&c.p,c.slen,a,b) == NULL) \ + { c.line=__LINE__; goto err; } \ + c.slen-=(c.p-c.q); + +#define M_ASN1_D2I_get_EXP_opt(r,func,tag) \ + if ((c.slen != 0L) && (M_ASN1_next == \ + (V_ASN1_CONSTRUCTED|V_ASN1_CONTEXT_SPECIFIC|tag))) \ + { \ + int Tinf,Ttag,Tclass; \ + long Tlen; \ + \ + c.q=c.p; \ + Tinf=ASN1_get_object(&c.p,&Tlen,&Ttag,&Tclass,c.slen); \ + if (Tinf & 0x80) \ + { c.error=ERR_R_BAD_ASN1_OBJECT_HEADER; \ + c.line=__LINE__; goto err; } \ + if (Tinf == (V_ASN1_CONSTRUCTED+1)) \ + Tlen = c.slen - (c.p - c.q) - 2; \ + if (func(&(r),&c.p,Tlen) == NULL) \ + { c.line=__LINE__; goto err; } \ + if (Tinf == (V_ASN1_CONSTRUCTED+1)) { \ + Tlen = c.slen - (c.p - c.q); \ + if(!ASN1_const_check_infinite_end(&c.p, Tlen)) \ + { c.error=ERR_R_MISSING_ASN1_EOS; \ + c.line=__LINE__; goto err; } \ + }\ + c.slen-=(c.p-c.q); \ + } + +#define M_ASN1_D2I_get_EXP_set_opt(r,func,free_func,tag,b) \ + if ((c.slen != 0) && (M_ASN1_next == \ + (V_ASN1_CONSTRUCTED|V_ASN1_CONTEXT_SPECIFIC|tag))) \ + { \ + int Tinf,Ttag,Tclass; \ + long Tlen; \ + \ + c.q=c.p; \ + Tinf=ASN1_get_object(&c.p,&Tlen,&Ttag,&Tclass,c.slen); \ + if (Tinf & 0x80) \ + { c.error=ERR_R_BAD_ASN1_OBJECT_HEADER; \ + c.line=__LINE__; goto err; } \ + if (Tinf == (V_ASN1_CONSTRUCTED+1)) \ + Tlen = c.slen - (c.p - c.q) - 2; \ + if (d2i_ASN1_SET(&(r),&c.p,Tlen,(char *(*)())func, \ + (void (*)())free_func, \ + b,V_ASN1_UNIVERSAL) == NULL) \ + { c.line=__LINE__; goto err; } \ + if (Tinf == (V_ASN1_CONSTRUCTED+1)) { \ + Tlen = c.slen - (c.p - c.q); \ + if(!ASN1_check_infinite_end(&c.p, Tlen)) \ + { c.error=ERR_R_MISSING_ASN1_EOS; \ + c.line=__LINE__; goto err; } \ + }\ + c.slen-=(c.p-c.q); \ + } + +#define M_ASN1_D2I_get_EXP_set_opt_type(type,r,func,free_func,tag,b) \ + if ((c.slen != 0) && (M_ASN1_next == \ + (V_ASN1_CONSTRUCTED|V_ASN1_CONTEXT_SPECIFIC|tag))) \ + { \ + int Tinf,Ttag,Tclass; \ + long Tlen; \ + \ + c.q=c.p; \ + Tinf=ASN1_get_object(&c.p,&Tlen,&Ttag,&Tclass,c.slen); \ + if (Tinf & 0x80) \ + { c.error=ERR_R_BAD_ASN1_OBJECT_HEADER; \ + c.line=__LINE__; goto err; } \ + if (Tinf == (V_ASN1_CONSTRUCTED+1)) \ + Tlen = c.slen - (c.p - c.q) - 2; \ + if (d2i_ASN1_SET_OF_##type(&(r),&c.p,Tlen,func, \ + free_func,b,V_ASN1_UNIVERSAL) == NULL) \ + { c.line=__LINE__; goto err; } \ + if (Tinf == (V_ASN1_CONSTRUCTED+1)) { \ + Tlen = c.slen - (c.p - c.q); \ + if(!ASN1_check_infinite_end(&c.p, Tlen)) \ + { c.error=ERR_R_MISSING_ASN1_EOS; \ + c.line=__LINE__; goto err; } \ + }\ + c.slen-=(c.p-c.q); \ + } + +/* New macros */ +#define M_ASN1_New_Malloc(ret,type) \ + if ((ret=(type *)OPENSSL_malloc(sizeof(type))) == NULL) \ + { c.line=__LINE__; goto err2; } + +#define M_ASN1_New(arg,func) \ + if (((arg)=func()) == NULL) return(NULL) + +#define M_ASN1_New_Error(a) \ +/* err: ASN1_MAC_H_err((a),ERR_R_NESTED_ASN1_ERROR,c.line); \ + return(NULL);*/ \ + err2: ASN1_MAC_H_err((a),ERR_R_MALLOC_FAILURE,c.line); \ + return(NULL) + + +/* BIG UGLY WARNING! This is so damn ugly I wanna puke. Unfortunately, + some macros that use ASN1_const_CTX still insist on writing in the input + stream. ARGH! ARGH! ARGH! Let's get rid of this macro package. + Please? -- Richard Levitte */ +#define M_ASN1_next (*((unsigned char *)(c.p))) +#define M_ASN1_next_prev (*((unsigned char *)(c.q))) + +/*************************************************/ + +#define M_ASN1_I2D_vars(a) int r=0,ret=0; \ + unsigned char *p; \ + if (a == NULL) return(0) + +/* Length Macros */ +#define M_ASN1_I2D_len(a,f) ret+=f(a,NULL) +#define M_ASN1_I2D_len_IMP_opt(a,f) if (a != NULL) M_ASN1_I2D_len(a,f) + +#define M_ASN1_I2D_len_SET(a,f) \ + ret+=i2d_ASN1_SET(a,NULL,f,V_ASN1_SET,V_ASN1_UNIVERSAL,IS_SET); + +#define M_ASN1_I2D_len_SET_type(type,a,f) \ + ret+=i2d_ASN1_SET_OF_##type(a,NULL,f,V_ASN1_SET, \ + V_ASN1_UNIVERSAL,IS_SET); + +#define M_ASN1_I2D_len_SEQUENCE(a,f) \ + ret+=i2d_ASN1_SET(a,NULL,f,V_ASN1_SEQUENCE,V_ASN1_UNIVERSAL, \ + IS_SEQUENCE); + +#define M_ASN1_I2D_len_SEQUENCE_type(type,a,f) \ + ret+=i2d_ASN1_SET_OF_##type(a,NULL,f,V_ASN1_SEQUENCE, \ + V_ASN1_UNIVERSAL,IS_SEQUENCE) + +#define M_ASN1_I2D_len_SEQUENCE_opt(a,f) \ + if ((a != NULL) && (sk_num(a) != 0)) \ + M_ASN1_I2D_len_SEQUENCE(a,f); + +#define M_ASN1_I2D_len_SEQUENCE_opt_type(type,a,f) \ + if ((a != NULL) && (sk_##type##_num(a) != 0)) \ + M_ASN1_I2D_len_SEQUENCE_type(type,a,f); + +#define M_ASN1_I2D_len_IMP_SET(a,f,x) \ + ret+=i2d_ASN1_SET(a,NULL,f,x,V_ASN1_CONTEXT_SPECIFIC,IS_SET); + +#define M_ASN1_I2D_len_IMP_SET_type(type,a,f,x) \ + ret+=i2d_ASN1_SET_OF_##type(a,NULL,f,x, \ + V_ASN1_CONTEXT_SPECIFIC,IS_SET); + +#define M_ASN1_I2D_len_IMP_SET_opt(a,f,x) \ + if ((a != NULL) && (sk_num(a) != 0)) \ + ret+=i2d_ASN1_SET(a,NULL,f,x,V_ASN1_CONTEXT_SPECIFIC, \ + IS_SET); + +#define M_ASN1_I2D_len_IMP_SET_opt_type(type,a,f,x) \ + if ((a != NULL) && (sk_##type##_num(a) != 0)) \ + ret+=i2d_ASN1_SET_OF_##type(a,NULL,f,x, \ + V_ASN1_CONTEXT_SPECIFIC,IS_SET); + +#define M_ASN1_I2D_len_IMP_SEQUENCE(a,f,x) \ + ret+=i2d_ASN1_SET(a,NULL,f,x,V_ASN1_CONTEXT_SPECIFIC, \ + IS_SEQUENCE); + +#define M_ASN1_I2D_len_IMP_SEQUENCE_opt(a,f,x) \ + if ((a != NULL) && (sk_num(a) != 0)) \ + ret+=i2d_ASN1_SET(a,NULL,f,x,V_ASN1_CONTEXT_SPECIFIC, \ + IS_SEQUENCE); + +#define M_ASN1_I2D_len_IMP_SEQUENCE_opt_type(type,a,f,x) \ + if ((a != NULL) && (sk_##type##_num(a) != 0)) \ + ret+=i2d_ASN1_SET_OF_##type(a,NULL,f,x, \ + V_ASN1_CONTEXT_SPECIFIC, \ + IS_SEQUENCE); + +#define M_ASN1_I2D_len_EXP_opt(a,f,mtag,v) \ + if (a != NULL)\ + { \ + v=f(a,NULL); \ + ret+=ASN1_object_size(1,v,mtag); \ + } + +#define M_ASN1_I2D_len_EXP_SET_opt(a,f,mtag,tag,v) \ + if ((a != NULL) && (sk_num(a) != 0))\ + { \ + v=i2d_ASN1_SET(a,NULL,f,tag,V_ASN1_UNIVERSAL,IS_SET); \ + ret+=ASN1_object_size(1,v,mtag); \ + } + +#define M_ASN1_I2D_len_EXP_SEQUENCE_opt(a,f,mtag,tag,v) \ + if ((a != NULL) && (sk_num(a) != 0))\ + { \ + v=i2d_ASN1_SET(a,NULL,f,tag,V_ASN1_UNIVERSAL, \ + IS_SEQUENCE); \ + ret+=ASN1_object_size(1,v,mtag); \ + } + +#define M_ASN1_I2D_len_EXP_SEQUENCE_opt_type(type,a,f,mtag,tag,v) \ + if ((a != NULL) && (sk_##type##_num(a) != 0))\ + { \ + v=i2d_ASN1_SET_OF_##type(a,NULL,f,tag, \ + V_ASN1_UNIVERSAL, \ + IS_SEQUENCE); \ + ret+=ASN1_object_size(1,v,mtag); \ + } + +/* Put Macros */ +#define M_ASN1_I2D_put(a,f) f(a,&p) + +#define M_ASN1_I2D_put_IMP_opt(a,f,t) \ + if (a != NULL) \ + { \ + unsigned char *q=p; \ + f(a,&p); \ + *q=(V_ASN1_CONTEXT_SPECIFIC|t|(*q&V_ASN1_CONSTRUCTED));\ + } + +#define M_ASN1_I2D_put_SET(a,f) i2d_ASN1_SET(a,&p,f,V_ASN1_SET,\ + V_ASN1_UNIVERSAL,IS_SET) +#define M_ASN1_I2D_put_SET_type(type,a,f) \ + i2d_ASN1_SET_OF_##type(a,&p,f,V_ASN1_SET,V_ASN1_UNIVERSAL,IS_SET) +#define M_ASN1_I2D_put_IMP_SET(a,f,x) i2d_ASN1_SET(a,&p,f,x,\ + V_ASN1_CONTEXT_SPECIFIC,IS_SET) +#define M_ASN1_I2D_put_IMP_SET_type(type,a,f,x) \ + i2d_ASN1_SET_OF_##type(a,&p,f,x,V_ASN1_CONTEXT_SPECIFIC,IS_SET) +#define M_ASN1_I2D_put_IMP_SEQUENCE(a,f,x) i2d_ASN1_SET(a,&p,f,x,\ + V_ASN1_CONTEXT_SPECIFIC,IS_SEQUENCE) + +#define M_ASN1_I2D_put_SEQUENCE(a,f) i2d_ASN1_SET(a,&p,f,V_ASN1_SEQUENCE,\ + V_ASN1_UNIVERSAL,IS_SEQUENCE) + +#define M_ASN1_I2D_put_SEQUENCE_type(type,a,f) \ + i2d_ASN1_SET_OF_##type(a,&p,f,V_ASN1_SEQUENCE,V_ASN1_UNIVERSAL, \ + IS_SEQUENCE) + +#define M_ASN1_I2D_put_SEQUENCE_opt(a,f) \ + if ((a != NULL) && (sk_num(a) != 0)) \ + M_ASN1_I2D_put_SEQUENCE(a,f); + +#define M_ASN1_I2D_put_IMP_SET_opt(a,f,x) \ + if ((a != NULL) && (sk_num(a) != 0)) \ + { i2d_ASN1_SET(a,&p,f,x,V_ASN1_CONTEXT_SPECIFIC, \ + IS_SET); } + +#define M_ASN1_I2D_put_IMP_SET_opt_type(type,a,f,x) \ + if ((a != NULL) && (sk_##type##_num(a) != 0)) \ + { i2d_ASN1_SET_OF_##type(a,&p,f,x, \ + V_ASN1_CONTEXT_SPECIFIC, \ + IS_SET); } + +#define M_ASN1_I2D_put_IMP_SEQUENCE_opt(a,f,x) \ + if ((a != NULL) && (sk_num(a) != 0)) \ + { i2d_ASN1_SET(a,&p,f,x,V_ASN1_CONTEXT_SPECIFIC, \ + IS_SEQUENCE); } + +#define M_ASN1_I2D_put_IMP_SEQUENCE_opt_type(type,a,f,x) \ + if ((a != NULL) && (sk_##type##_num(a) != 0)) \ + { i2d_ASN1_SET_OF_##type(a,&p,f,x, \ + V_ASN1_CONTEXT_SPECIFIC, \ + IS_SEQUENCE); } + +#define M_ASN1_I2D_put_EXP_opt(a,f,tag,v) \ + if (a != NULL) \ + { \ + ASN1_put_object(&p,1,v,tag,V_ASN1_CONTEXT_SPECIFIC); \ + f(a,&p); \ + } + +#define M_ASN1_I2D_put_EXP_SET_opt(a,f,mtag,tag,v) \ + if ((a != NULL) && (sk_num(a) != 0)) \ + { \ + ASN1_put_object(&p,1,v,mtag,V_ASN1_CONTEXT_SPECIFIC); \ + i2d_ASN1_SET(a,&p,f,tag,V_ASN1_UNIVERSAL,IS_SET); \ + } + +#define M_ASN1_I2D_put_EXP_SEQUENCE_opt(a,f,mtag,tag,v) \ + if ((a != NULL) && (sk_num(a) != 0)) \ + { \ + ASN1_put_object(&p,1,v,mtag,V_ASN1_CONTEXT_SPECIFIC); \ + i2d_ASN1_SET(a,&p,f,tag,V_ASN1_UNIVERSAL,IS_SEQUENCE); \ + } + +#define M_ASN1_I2D_put_EXP_SEQUENCE_opt_type(type,a,f,mtag,tag,v) \ + if ((a != NULL) && (sk_##type##_num(a) != 0)) \ + { \ + ASN1_put_object(&p,1,v,mtag,V_ASN1_CONTEXT_SPECIFIC); \ + i2d_ASN1_SET_OF_##type(a,&p,f,tag,V_ASN1_UNIVERSAL, \ + IS_SEQUENCE); \ + } + +#define M_ASN1_I2D_seq_total() \ + r=ASN1_object_size(1,ret,V_ASN1_SEQUENCE); \ + if (pp == NULL) return(r); \ + p= *pp; \ + ASN1_put_object(&p,1,ret,V_ASN1_SEQUENCE,V_ASN1_UNIVERSAL) + +#define M_ASN1_I2D_INF_seq_start(tag,ctx) \ + *(p++)=(V_ASN1_CONSTRUCTED|(tag)|(ctx)); \ + *(p++)=0x80 + +#define M_ASN1_I2D_INF_seq_end() *(p++)=0x00; *(p++)=0x00 + +#define M_ASN1_I2D_finish() *pp=p; \ + return(r); + +int asn1_GetSequence(ASN1_const_CTX *c, long *length); +void asn1_add_error(const unsigned char *address,int offset); +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_tls/include/openssl/asn1t.h b/lib_tls/include/openssl/asn1t.h new file mode 100644 index 000000000..bf315e65e --- /dev/null +++ b/lib_tls/include/openssl/asn1t.h @@ -0,0 +1,893 @@ +/* asn1t.h */ +/* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL + * project 2000. + */ +/* ==================================================================== + * Copyright (c) 2000 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +#ifndef HEADER_ASN1T_H +#define HEADER_ASN1T_H + +#include +#include +#include + +#ifdef OPENSSL_BUILD_SHLIBCRYPTO +# undef OPENSSL_EXTERN +# define OPENSSL_EXTERN OPENSSL_EXPORT +#endif + +/* ASN1 template defines, structures and functions */ + +#ifdef __cplusplus +extern "C" { +#endif + + +#ifndef OPENSSL_EXPORT_VAR_AS_FUNCTION + +/* Macro to obtain ASN1_ADB pointer from a type (only used internally) */ +#define ASN1_ADB_ptr(iptr) ((const ASN1_ADB *)(iptr)) + + +/* Macros for start and end of ASN1_ITEM definition */ + +#define ASN1_ITEM_start(itname) \ + OPENSSL_GLOBAL const ASN1_ITEM itname##_it = { + +#define ASN1_ITEM_end(itname) \ + }; + +#else + +/* Macro to obtain ASN1_ADB pointer from a type (only used internally) */ +#define ASN1_ADB_ptr(iptr) ((const ASN1_ADB *)(iptr())) + + +/* Macros for start and end of ASN1_ITEM definition */ + +#define ASN1_ITEM_start(itname) \ + const ASN1_ITEM * itname##_it(void) \ + { \ + static const ASN1_ITEM local_it = { + +#define ASN1_ITEM_end(itname) \ + }; \ + return &local_it; \ + } + +#endif + + +/* Macros to aid ASN1 template writing */ + +#define ASN1_ITEM_TEMPLATE(tname) \ + static const ASN1_TEMPLATE tname##_item_tt + +#define ASN1_ITEM_TEMPLATE_END(tname) \ + ;\ + ASN1_ITEM_start(tname) \ + ASN1_ITYPE_PRIMITIVE,\ + -1,\ + &tname##_item_tt,\ + 0,\ + NULL,\ + 0,\ + #tname \ + ASN1_ITEM_end(tname) + + +/* This is a ASN1 type which just embeds a template */ + +/* This pair helps declare a SEQUENCE. We can do: + * + * ASN1_SEQUENCE(stname) = { + * ... SEQUENCE components ... + * } ASN1_SEQUENCE_END(stname) + * + * This will produce an ASN1_ITEM called stname_it + * for a structure called stname. + * + * If you want the same structure but a different + * name then use: + * + * ASN1_SEQUENCE(itname) = { + * ... SEQUENCE components ... + * } ASN1_SEQUENCE_END_name(stname, itname) + * + * This will create an item called itname_it using + * a structure called stname. + */ + +#define ASN1_SEQUENCE(tname) \ + static const ASN1_TEMPLATE tname##_seq_tt[] + +#define ASN1_SEQUENCE_END(stname) ASN1_SEQUENCE_END_name(stname, stname) + +#define ASN1_SEQUENCE_END_name(stname, tname) \ + ;\ + ASN1_ITEM_start(tname) \ + ASN1_ITYPE_SEQUENCE,\ + V_ASN1_SEQUENCE,\ + tname##_seq_tt,\ + sizeof(tname##_seq_tt) / sizeof(ASN1_TEMPLATE),\ + NULL,\ + sizeof(stname),\ + #stname \ + ASN1_ITEM_end(tname) + +#define ASN1_NDEF_SEQUENCE(tname) \ + ASN1_SEQUENCE(tname) + +#define ASN1_NDEF_SEQUENCE_cb(tname, cb) \ + ASN1_SEQUENCE_cb(tname, cb) + +#define ASN1_SEQUENCE_cb(tname, cb) \ + static const ASN1_AUX tname##_aux = {NULL, 0, 0, 0, cb, 0}; \ + ASN1_SEQUENCE(tname) + +#define ASN1_BROKEN_SEQUENCE(tname) \ + static const ASN1_AUX tname##_aux = {NULL, ASN1_AFLG_BROKEN, 0, 0, 0, 0}; \ + ASN1_SEQUENCE(tname) + +#define ASN1_SEQUENCE_ref(tname, cb, lck) \ + static const ASN1_AUX tname##_aux = {NULL, ASN1_AFLG_REFCOUNT, offsetof(tname, references), lck, cb, 0}; \ + ASN1_SEQUENCE(tname) + +#define ASN1_SEQUENCE_enc(tname, enc, cb) \ + static const ASN1_AUX tname##_aux = {NULL, ASN1_AFLG_ENCODING, 0, 0, cb, offsetof(tname, enc)}; \ + ASN1_SEQUENCE(tname) + +#define ASN1_NDEF_SEQUENCE_END(tname) \ + ;\ + ASN1_ITEM_start(tname) \ + ASN1_ITYPE_NDEF_SEQUENCE,\ + V_ASN1_SEQUENCE,\ + tname##_seq_tt,\ + sizeof(tname##_seq_tt) / sizeof(ASN1_TEMPLATE),\ + NULL,\ + sizeof(tname),\ + #tname \ + ASN1_ITEM_end(tname) + +#define ASN1_BROKEN_SEQUENCE_END(stname) ASN1_SEQUENCE_END_ref(stname, stname) + +#define ASN1_SEQUENCE_END_enc(stname, tname) ASN1_SEQUENCE_END_ref(stname, tname) + +#define ASN1_SEQUENCE_END_cb(stname, tname) ASN1_SEQUENCE_END_ref(stname, tname) + +#define ASN1_SEQUENCE_END_ref(stname, tname) \ + ;\ + ASN1_ITEM_start(tname) \ + ASN1_ITYPE_SEQUENCE,\ + V_ASN1_SEQUENCE,\ + tname##_seq_tt,\ + sizeof(tname##_seq_tt) / sizeof(ASN1_TEMPLATE),\ + &tname##_aux,\ + sizeof(stname),\ + #stname \ + ASN1_ITEM_end(tname) + + +/* This pair helps declare a CHOICE type. We can do: + * + * ASN1_CHOICE(chname) = { + * ... CHOICE options ... + * ASN1_CHOICE_END(chname) + * + * This will produce an ASN1_ITEM called chname_it + * for a structure called chname. The structure + * definition must look like this: + * typedef struct { + * int type; + * union { + * ASN1_SOMETHING *opt1; + * ASN1_SOMEOTHER *opt2; + * } value; + * } chname; + * + * the name of the selector must be 'type'. + * to use an alternative selector name use the + * ASN1_CHOICE_END_selector() version. + */ + +#define ASN1_CHOICE(tname) \ + static const ASN1_TEMPLATE tname##_ch_tt[] + +#define ASN1_CHOICE_cb(tname, cb) \ + static const ASN1_AUX tname##_aux = {NULL, 0, 0, 0, cb, 0}; \ + ASN1_CHOICE(tname) + +#define ASN1_CHOICE_END(stname) ASN1_CHOICE_END_name(stname, stname) + +#define ASN1_CHOICE_END_name(stname, tname) ASN1_CHOICE_END_selector(stname, tname, type) + +#define ASN1_CHOICE_END_selector(stname, tname, selname) \ + ;\ + ASN1_ITEM_start(tname) \ + ASN1_ITYPE_CHOICE,\ + offsetof(stname,selname) ,\ + tname##_ch_tt,\ + sizeof(tname##_ch_tt) / sizeof(ASN1_TEMPLATE),\ + NULL,\ + sizeof(stname),\ + #stname \ + ASN1_ITEM_end(tname) + +#define ASN1_CHOICE_END_cb(stname, tname, selname) \ + ;\ + ASN1_ITEM_start(tname) \ + ASN1_ITYPE_CHOICE,\ + offsetof(stname,selname) ,\ + tname##_ch_tt,\ + sizeof(tname##_ch_tt) / sizeof(ASN1_TEMPLATE),\ + &tname##_aux,\ + sizeof(stname),\ + #stname \ + ASN1_ITEM_end(tname) + +/* This helps with the template wrapper form of ASN1_ITEM */ + +#define ASN1_EX_TEMPLATE_TYPE(flags, tag, name, type) { \ + (flags), (tag), 0,\ + #name, ASN1_ITEM_ref(type) } + +/* These help with SEQUENCE or CHOICE components */ + +/* used to declare other types */ + +#define ASN1_EX_TYPE(flags, tag, stname, field, type) { \ + (flags), (tag), offsetof(stname, field),\ + #field, ASN1_ITEM_ref(type) } + +/* used when the structure is combined with the parent */ + +#define ASN1_EX_COMBINE(flags, tag, type) { \ + (flags)|ASN1_TFLG_COMBINE, (tag), 0, NULL, ASN1_ITEM_ref(type) } + +/* implicit and explicit helper macros */ + +#define ASN1_IMP_EX(stname, field, type, tag, ex) \ + ASN1_EX_TYPE(ASN1_TFLG_IMPLICIT | ex, tag, stname, field, type) + +#define ASN1_EXP_EX(stname, field, type, tag, ex) \ + ASN1_EX_TYPE(ASN1_TFLG_EXPLICIT | ex, tag, stname, field, type) + +/* Any defined by macros: the field used is in the table itself */ + +#ifndef OPENSSL_EXPORT_VAR_AS_FUNCTION +#define ASN1_ADB_OBJECT(tblname) { ASN1_TFLG_ADB_OID, -1, 0, #tblname, (const ASN1_ITEM *)&(tblname##_adb) } +#define ASN1_ADB_INTEGER(tblname) { ASN1_TFLG_ADB_INT, -1, 0, #tblname, (const ASN1_ITEM *)&(tblname##_adb) } +#else +#define ASN1_ADB_OBJECT(tblname) { ASN1_TFLG_ADB_OID, -1, 0, #tblname, tblname##_adb } +#define ASN1_ADB_INTEGER(tblname) { ASN1_TFLG_ADB_INT, -1, 0, #tblname, tblname##_adb } +#endif +/* Plain simple type */ +#define ASN1_SIMPLE(stname, field, type) ASN1_EX_TYPE(0,0, stname, field, type) + +/* OPTIONAL simple type */ +#define ASN1_OPT(stname, field, type) ASN1_EX_TYPE(ASN1_TFLG_OPTIONAL, 0, stname, field, type) + +/* IMPLICIT tagged simple type */ +#define ASN1_IMP(stname, field, type, tag) ASN1_IMP_EX(stname, field, type, tag, 0) + +/* IMPLICIT tagged OPTIONAL simple type */ +#define ASN1_IMP_OPT(stname, field, type, tag) ASN1_IMP_EX(stname, field, type, tag, ASN1_TFLG_OPTIONAL) + +/* Same as above but EXPLICIT */ + +#define ASN1_EXP(stname, field, type, tag) ASN1_EXP_EX(stname, field, type, tag, 0) +#define ASN1_EXP_OPT(stname, field, type, tag) ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_OPTIONAL) + +/* SEQUENCE OF type */ +#define ASN1_SEQUENCE_OF(stname, field, type) \ + ASN1_EX_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, stname, field, type) + +/* OPTIONAL SEQUENCE OF */ +#define ASN1_SEQUENCE_OF_OPT(stname, field, type) \ + ASN1_EX_TYPE(ASN1_TFLG_SEQUENCE_OF|ASN1_TFLG_OPTIONAL, 0, stname, field, type) + +/* Same as above but for SET OF */ + +#define ASN1_SET_OF(stname, field, type) \ + ASN1_EX_TYPE(ASN1_TFLG_SET_OF, 0, stname, field, type) + +#define ASN1_SET_OF_OPT(stname, field, type) \ + ASN1_EX_TYPE(ASN1_TFLG_SET_OF|ASN1_TFLG_OPTIONAL, 0, stname, field, type) + +/* Finally compound types of SEQUENCE, SET, IMPLICIT, EXPLICIT and OPTIONAL */ + +#define ASN1_IMP_SET_OF(stname, field, type, tag) \ + ASN1_IMP_EX(stname, field, type, tag, ASN1_TFLG_SET_OF) + +#define ASN1_EXP_SET_OF(stname, field, type, tag) \ + ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_SET_OF) + +#define ASN1_IMP_SET_OF_OPT(stname, field, type, tag) \ + ASN1_IMP_EX(stname, field, type, tag, ASN1_TFLG_SET_OF|ASN1_TFLG_OPTIONAL) + +#define ASN1_EXP_SET_OF_OPT(stname, field, type, tag) \ + ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_SET_OF|ASN1_TFLG_OPTIONAL) + +#define ASN1_IMP_SEQUENCE_OF(stname, field, type, tag) \ + ASN1_IMP_EX(stname, field, type, tag, ASN1_TFLG_SEQUENCE_OF) + +#define ASN1_IMP_SEQUENCE_OF_OPT(stname, field, type, tag) \ + ASN1_IMP_EX(stname, field, type, tag, ASN1_TFLG_SEQUENCE_OF|ASN1_TFLG_OPTIONAL) + +#define ASN1_EXP_SEQUENCE_OF(stname, field, type, tag) \ + ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_SEQUENCE_OF) + +#define ASN1_EXP_SEQUENCE_OF_OPT(stname, field, type, tag) \ + ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_SEQUENCE_OF|ASN1_TFLG_OPTIONAL) + +/* EXPLICIT using indefinite length constructed form */ +#define ASN1_NDEF_EXP(stname, field, type, tag) \ + ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_NDEF) + +/* EXPLICIT OPTIONAL using indefinite length constructed form */ +#define ASN1_NDEF_EXP_OPT(stname, field, type, tag) \ + ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_OPTIONAL|ASN1_TFLG_NDEF) + +/* Macros for the ASN1_ADB structure */ + +#define ASN1_ADB(name) \ + static const ASN1_ADB_TABLE name##_adbtbl[] + +#ifndef OPENSSL_EXPORT_VAR_AS_FUNCTION + +#define ASN1_ADB_END(name, flags, field, app_table, def, none) \ + ;\ + static const ASN1_ADB name##_adb = {\ + flags,\ + offsetof(name, field),\ + app_table,\ + name##_adbtbl,\ + sizeof(name##_adbtbl) / sizeof(ASN1_ADB_TABLE),\ + def,\ + none\ + } + +#else + +#define ASN1_ADB_END(name, flags, field, app_table, def, none) \ + ;\ + static const ASN1_ITEM *name##_adb(void) \ + { \ + static const ASN1_ADB internal_adb = \ + {\ + flags,\ + offsetof(name, field),\ + app_table,\ + name##_adbtbl,\ + sizeof(name##_adbtbl) / sizeof(ASN1_ADB_TABLE),\ + def,\ + none\ + }; \ + return (const ASN1_ITEM *) &internal_adb; \ + } \ + void dummy_function(void) + +#endif + +#define ADB_ENTRY(val, template) {val, template} + +#define ASN1_ADB_TEMPLATE(name) \ + static const ASN1_TEMPLATE name##_tt + +/* This is the ASN1 template structure that defines + * a wrapper round the actual type. It determines the + * actual position of the field in the value structure, + * various flags such as OPTIONAL and the field name. + */ + +struct ASN1_TEMPLATE_st { +unsigned long flags; /* Various flags */ +long tag; /* tag, not used if no tagging */ +unsigned long offset; /* Offset of this field in structure */ +#ifndef NO_ASN1_FIELD_NAMES +const char *field_name; /* Field name */ +#endif +ASN1_ITEM_EXP *item; /* Relevant ASN1_ITEM or ASN1_ADB */ +}; + +/* Macro to extract ASN1_ITEM and ASN1_ADB pointer from ASN1_TEMPLATE */ + +#define ASN1_TEMPLATE_item(t) (t->item_ptr) +#define ASN1_TEMPLATE_adb(t) (t->item_ptr) + +typedef struct ASN1_ADB_TABLE_st ASN1_ADB_TABLE; +typedef struct ASN1_ADB_st ASN1_ADB; + +struct ASN1_ADB_st { + unsigned long flags; /* Various flags */ + unsigned long offset; /* Offset of selector field */ + STACK_OF(ASN1_ADB_TABLE) **app_items; /* Application defined items */ + const ASN1_ADB_TABLE *tbl; /* Table of possible types */ + long tblcount; /* Number of entries in tbl */ + const ASN1_TEMPLATE *default_tt; /* Type to use if no match */ + const ASN1_TEMPLATE *null_tt; /* Type to use if selector is NULL */ +}; + +struct ASN1_ADB_TABLE_st { + long value; /* NID for an object or value for an int */ + const ASN1_TEMPLATE tt; /* item for this value */ +}; + +/* template flags */ + +/* Field is optional */ +#define ASN1_TFLG_OPTIONAL (0x1) + +/* Field is a SET OF */ +#define ASN1_TFLG_SET_OF (0x1 << 1) + +/* Field is a SEQUENCE OF */ +#define ASN1_TFLG_SEQUENCE_OF (0x2 << 1) + +/* Special case: this refers to a SET OF that + * will be sorted into DER order when encoded *and* + * the corresponding STACK will be modified to match + * the new order. + */ +#define ASN1_TFLG_SET_ORDER (0x3 << 1) + +/* Mask for SET OF or SEQUENCE OF */ +#define ASN1_TFLG_SK_MASK (0x3 << 1) + +/* These flags mean the tag should be taken from the + * tag field. If EXPLICIT then the underlying type + * is used for the inner tag. + */ + +/* IMPLICIT tagging */ +#define ASN1_TFLG_IMPTAG (0x1 << 3) + + +/* EXPLICIT tagging, inner tag from underlying type */ +#define ASN1_TFLG_EXPTAG (0x2 << 3) + +#define ASN1_TFLG_TAG_MASK (0x3 << 3) + +/* context specific IMPLICIT */ +#define ASN1_TFLG_IMPLICIT ASN1_TFLG_IMPTAG|ASN1_TFLG_CONTEXT + +/* context specific EXPLICIT */ +#define ASN1_TFLG_EXPLICIT ASN1_TFLG_EXPTAG|ASN1_TFLG_CONTEXT + +/* If tagging is in force these determine the + * type of tag to use. Otherwise the tag is + * determined by the underlying type. These + * values reflect the actual octet format. + */ + +/* Universal tag */ +#define ASN1_TFLG_UNIVERSAL (0x0<<6) +/* Application tag */ +#define ASN1_TFLG_APPLICATION (0x1<<6) +/* Context specific tag */ +#define ASN1_TFLG_CONTEXT (0x2<<6) +/* Private tag */ +#define ASN1_TFLG_PRIVATE (0x3<<6) + +#define ASN1_TFLG_TAG_CLASS (0x3<<6) + +/* These are for ANY DEFINED BY type. In this case + * the 'item' field points to an ASN1_ADB structure + * which contains a table of values to decode the + * relevant type + */ + +#define ASN1_TFLG_ADB_MASK (0x3<<8) + +#define ASN1_TFLG_ADB_OID (0x1<<8) + +#define ASN1_TFLG_ADB_INT (0x1<<9) + +/* This flag means a parent structure is passed + * instead of the field: this is useful is a + * SEQUENCE is being combined with a CHOICE for + * example. Since this means the structure and + * item name will differ we need to use the + * ASN1_CHOICE_END_name() macro for example. + */ + +#define ASN1_TFLG_COMBINE (0x1<<10) + +/* This flag when present in a SEQUENCE OF, SET OF + * or EXPLICIT causes indefinite length constructed + * encoding to be used if required. + */ + +#define ASN1_TFLG_NDEF (0x1<<11) + +/* This is the actual ASN1 item itself */ + +struct ASN1_ITEM_st { +char itype; /* The item type, primitive, SEQUENCE, CHOICE or extern */ +long utype; /* underlying type */ +const ASN1_TEMPLATE *templates; /* If SEQUENCE or CHOICE this contains the contents */ +long tcount; /* Number of templates if SEQUENCE or CHOICE */ +const void *funcs; /* functions that handle this type */ +long size; /* Structure size (usually)*/ +#ifndef NO_ASN1_FIELD_NAMES +const char *sname; /* Structure name */ +#endif +}; + +/* These are values for the itype field and + * determine how the type is interpreted. + * + * For PRIMITIVE types the underlying type + * determines the behaviour if items is NULL. + * + * Otherwise templates must contain a single + * template and the type is treated in the + * same way as the type specified in the template. + * + * For SEQUENCE types the templates field points + * to the members, the size field is the + * structure size. + * + * For CHOICE types the templates field points + * to each possible member (typically a union) + * and the 'size' field is the offset of the + * selector. + * + * The 'funcs' field is used for application + * specific functions. + * + * For COMPAT types the funcs field gives a + * set of functions that handle this type, this + * supports the old d2i, i2d convention. + * + * The EXTERN type uses a new style d2i/i2d. + * The new style should be used where possible + * because it avoids things like the d2i IMPLICIT + * hack. + * + * MSTRING is a multiple string type, it is used + * for a CHOICE of character strings where the + * actual strings all occupy an ASN1_STRING + * structure. In this case the 'utype' field + * has a special meaning, it is used as a mask + * of acceptable types using the B_ASN1 constants. + * + * NDEF_SEQUENCE is the same as SEQUENCE except + * that it will use indefinite length constructed + * encoding if requested. + * + */ + +#define ASN1_ITYPE_PRIMITIVE 0x0 + +#define ASN1_ITYPE_SEQUENCE 0x1 + +#define ASN1_ITYPE_CHOICE 0x2 + +#define ASN1_ITYPE_COMPAT 0x3 + +#define ASN1_ITYPE_EXTERN 0x4 + +#define ASN1_ITYPE_MSTRING 0x5 + +#define ASN1_ITYPE_NDEF_SEQUENCE 0x6 + +/* Cache for ASN1 tag and length, so we + * don't keep re-reading it for things + * like CHOICE + */ + +struct ASN1_TLC_st{ + char valid; /* Values below are valid */ + int ret; /* return value */ + long plen; /* length */ + int ptag; /* class value */ + int pclass; /* class value */ + int hdrlen; /* header length */ +}; + +/* Typedefs for ASN1 function pointers */ + +typedef ASN1_VALUE * ASN1_new_func(void); +typedef void ASN1_free_func(ASN1_VALUE *a); +typedef ASN1_VALUE * ASN1_d2i_func(ASN1_VALUE **a, const unsigned char ** in, long length); +typedef int ASN1_i2d_func(ASN1_VALUE * a, unsigned char **in); + +typedef int ASN1_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, const ASN1_ITEM *it, + int tag, int aclass, char opt, ASN1_TLC *ctx); + +typedef int ASN1_ex_i2d(ASN1_VALUE **pval, unsigned char **out, const ASN1_ITEM *it, int tag, int aclass); +typedef int ASN1_ex_new_func(ASN1_VALUE **pval, const ASN1_ITEM *it); +typedef void ASN1_ex_free_func(ASN1_VALUE **pval, const ASN1_ITEM *it); + +typedef int ASN1_primitive_i2c(ASN1_VALUE **pval, unsigned char *cont, int *putype, const ASN1_ITEM *it); +typedef int ASN1_primitive_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len, int utype, char *free_cont, const ASN1_ITEM *it); + +typedef struct ASN1_COMPAT_FUNCS_st { + ASN1_new_func *asn1_new; + ASN1_free_func *asn1_free; + ASN1_d2i_func *asn1_d2i; + ASN1_i2d_func *asn1_i2d; +} ASN1_COMPAT_FUNCS; + +typedef struct ASN1_EXTERN_FUNCS_st { + void *app_data; + ASN1_ex_new_func *asn1_ex_new; + ASN1_ex_free_func *asn1_ex_free; + ASN1_ex_free_func *asn1_ex_clear; + ASN1_ex_d2i *asn1_ex_d2i; + ASN1_ex_i2d *asn1_ex_i2d; +} ASN1_EXTERN_FUNCS; + +typedef struct ASN1_PRIMITIVE_FUNCS_st { + void *app_data; + unsigned long flags; + ASN1_ex_new_func *prim_new; + ASN1_ex_free_func *prim_free; + ASN1_ex_free_func *prim_clear; + ASN1_primitive_c2i *prim_c2i; + ASN1_primitive_i2c *prim_i2c; +} ASN1_PRIMITIVE_FUNCS; + +/* This is the ASN1_AUX structure: it handles various + * miscellaneous requirements. For example the use of + * reference counts and an informational callback. + * + * The "informational callback" is called at various + * points during the ASN1 encoding and decoding. It can + * be used to provide minor customisation of the structures + * used. This is most useful where the supplied routines + * *almost* do the right thing but need some extra help + * at a few points. If the callback returns zero then + * it is assumed a fatal error has occurred and the + * main operation should be abandoned. + * + * If major changes in the default behaviour are required + * then an external type is more appropriate. + */ + +typedef int ASN1_aux_cb(int operation, ASN1_VALUE **in, const ASN1_ITEM *it); + +typedef struct ASN1_AUX_st { + void *app_data; + int flags; + int ref_offset; /* Offset of reference value */ + int ref_lock; /* Lock type to use */ + ASN1_aux_cb *asn1_cb; + int enc_offset; /* Offset of ASN1_ENCODING structure */ +} ASN1_AUX; + +/* Flags in ASN1_AUX */ + +/* Use a reference count */ +#define ASN1_AFLG_REFCOUNT 1 +/* Save the encoding of structure (useful for signatures) */ +#define ASN1_AFLG_ENCODING 2 +/* The Sequence length is invalid */ +#define ASN1_AFLG_BROKEN 4 + +/* operation values for asn1_cb */ + +#define ASN1_OP_NEW_PRE 0 +#define ASN1_OP_NEW_POST 1 +#define ASN1_OP_FREE_PRE 2 +#define ASN1_OP_FREE_POST 3 +#define ASN1_OP_D2I_PRE 4 +#define ASN1_OP_D2I_POST 5 +#define ASN1_OP_I2D_PRE 6 +#define ASN1_OP_I2D_POST 7 + +/* Macro to implement a primitive type */ +#define IMPLEMENT_ASN1_TYPE(stname) IMPLEMENT_ASN1_TYPE_ex(stname, stname, 0) +#define IMPLEMENT_ASN1_TYPE_ex(itname, vname, ex) \ + ASN1_ITEM_start(itname) \ + ASN1_ITYPE_PRIMITIVE, V_##vname, NULL, 0, NULL, ex, #itname \ + ASN1_ITEM_end(itname) + +/* Macro to implement a multi string type */ +#define IMPLEMENT_ASN1_MSTRING(itname, mask) \ + ASN1_ITEM_start(itname) \ + ASN1_ITYPE_MSTRING, mask, NULL, 0, NULL, sizeof(ASN1_STRING), #itname \ + ASN1_ITEM_end(itname) + +/* Macro to implement an ASN1_ITEM in terms of old style funcs */ + +#define IMPLEMENT_COMPAT_ASN1(sname) IMPLEMENT_COMPAT_ASN1_type(sname, V_ASN1_SEQUENCE) + +#define IMPLEMENT_COMPAT_ASN1_type(sname, tag) \ + static const ASN1_COMPAT_FUNCS sname##_ff = { \ + (ASN1_new_func *)sname##_new, \ + (ASN1_free_func *)sname##_free, \ + (ASN1_d2i_func *)d2i_##sname, \ + (ASN1_i2d_func *)i2d_##sname, \ + }; \ + ASN1_ITEM_start(sname) \ + ASN1_ITYPE_COMPAT, \ + tag, \ + NULL, \ + 0, \ + &sname##_ff, \ + 0, \ + #sname \ + ASN1_ITEM_end(sname) + +#define IMPLEMENT_EXTERN_ASN1(sname, tag, fptrs) \ + ASN1_ITEM_start(sname) \ + ASN1_ITYPE_EXTERN, \ + tag, \ + NULL, \ + 0, \ + &fptrs, \ + 0, \ + #sname \ + ASN1_ITEM_end(sname) + +/* Macro to implement standard functions in terms of ASN1_ITEM structures */ + +#define IMPLEMENT_ASN1_FUNCTIONS(stname) IMPLEMENT_ASN1_FUNCTIONS_fname(stname, stname, stname) + +#define IMPLEMENT_ASN1_FUNCTIONS_name(stname, itname) IMPLEMENT_ASN1_FUNCTIONS_fname(stname, itname, itname) + +#define IMPLEMENT_ASN1_FUNCTIONS_ENCODE_name(stname, itname) \ + IMPLEMENT_ASN1_FUNCTIONS_ENCODE_fname(stname, itname, itname) + +#define IMPLEMENT_ASN1_ALLOC_FUNCTIONS(stname) \ + IMPLEMENT_ASN1_ALLOC_FUNCTIONS_fname(stname, stname, stname) + +#define IMPLEMENT_ASN1_ALLOC_FUNCTIONS_fname(stname, itname, fname) \ + stname *fname##_new(void) \ + { \ + return (stname *)ASN1_item_new(ASN1_ITEM_rptr(itname)); \ + } \ + void fname##_free(stname *a) \ + { \ + ASN1_item_free((ASN1_VALUE *)a, ASN1_ITEM_rptr(itname)); \ + } + +#define IMPLEMENT_ASN1_FUNCTIONS_fname(stname, itname, fname) \ + IMPLEMENT_ASN1_ENCODE_FUNCTIONS_fname(stname, itname, fname) \ + IMPLEMENT_ASN1_ALLOC_FUNCTIONS_fname(stname, itname, fname) + +#define IMPLEMENT_ASN1_ENCODE_FUNCTIONS_fname(stname, itname, fname) \ + stname *d2i_##fname(stname **a, const unsigned char **in, long len) \ + { \ + return (stname *)ASN1_item_d2i((ASN1_VALUE **)a, in, len, ASN1_ITEM_rptr(itname));\ + } \ + int i2d_##fname(stname *a, unsigned char **out) \ + { \ + return ASN1_item_i2d((ASN1_VALUE *)a, out, ASN1_ITEM_rptr(itname));\ + } + +#define IMPLEMENT_ASN1_NDEF_FUNCTION(stname) \ + int i2d_##stname##_NDEF(stname *a, unsigned char **out) \ + { \ + return ASN1_item_ndef_i2d((ASN1_VALUE *)a, out, ASN1_ITEM_rptr(stname));\ + } + +/* This includes evil casts to remove const: they will go away when full + * ASN1 constification is done. + */ +#define IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(stname, itname, fname) \ + stname *d2i_##fname(stname **a, const unsigned char **in, long len) \ + { \ + return (stname *)ASN1_item_d2i((ASN1_VALUE **)a, in, len, ASN1_ITEM_rptr(itname));\ + } \ + int i2d_##fname(const stname *a, unsigned char **out) \ + { \ + return ASN1_item_i2d((ASN1_VALUE *)a, out, ASN1_ITEM_rptr(itname));\ + } + +#define IMPLEMENT_ASN1_DUP_FUNCTION(stname) \ + stname * stname##_dup(stname *x) \ + { \ + return ASN1_item_dup(ASN1_ITEM_rptr(stname), x); \ + } + +#define IMPLEMENT_ASN1_FUNCTIONS_const(name) \ + IMPLEMENT_ASN1_FUNCTIONS_const_fname(name, name, name) + +#define IMPLEMENT_ASN1_FUNCTIONS_const_fname(stname, itname, fname) \ + IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(stname, itname, fname) \ + IMPLEMENT_ASN1_ALLOC_FUNCTIONS_fname(stname, itname, fname) + +/* external definitions for primitive types */ + +DECLARE_ASN1_ITEM(ASN1_BOOLEAN) +DECLARE_ASN1_ITEM(ASN1_TBOOLEAN) +DECLARE_ASN1_ITEM(ASN1_FBOOLEAN) +DECLARE_ASN1_ITEM(ASN1_SEQUENCE) +DECLARE_ASN1_ITEM(CBIGNUM) +DECLARE_ASN1_ITEM(BIGNUM) +DECLARE_ASN1_ITEM(LONG) +DECLARE_ASN1_ITEM(ZLONG) + +DECLARE_STACK_OF(ASN1_VALUE) + +/* Functions used internally by the ASN1 code */ + +int ASN1_item_ex_new(ASN1_VALUE **pval, const ASN1_ITEM *it); +void ASN1_item_ex_free(ASN1_VALUE **pval, const ASN1_ITEM *it); +int ASN1_template_new(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt); +int ASN1_primitive_new(ASN1_VALUE **pval, const ASN1_ITEM *it); + +void ASN1_template_free(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt); +int ASN1_template_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, const ASN1_TEMPLATE *tt); +int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, const ASN1_ITEM *it, + int tag, int aclass, char opt, ASN1_TLC *ctx); + +int ASN1_item_ex_i2d(ASN1_VALUE **pval, unsigned char **out, const ASN1_ITEM *it, int tag, int aclass); +int ASN1_template_i2d(ASN1_VALUE **pval, unsigned char **out, const ASN1_TEMPLATE *tt); +void ASN1_primitive_free(ASN1_VALUE **pval, const ASN1_ITEM *it); + +int asn1_ex_i2c(ASN1_VALUE **pval, unsigned char *cont, int *putype, const ASN1_ITEM *it); +int asn1_ex_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len, int utype, char *free_cont, const ASN1_ITEM *it); + +int asn1_get_choice_selector(ASN1_VALUE **pval, const ASN1_ITEM *it); +int asn1_set_choice_selector(ASN1_VALUE **pval, int value, const ASN1_ITEM *it); + +ASN1_VALUE ** asn1_get_field_ptr(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt); + +const ASN1_TEMPLATE *asn1_do_adb(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt, int nullerr); + +int asn1_do_lock(ASN1_VALUE **pval, int op, const ASN1_ITEM *it); + +void asn1_enc_init(ASN1_VALUE **pval, const ASN1_ITEM *it); +void asn1_enc_free(ASN1_VALUE **pval, const ASN1_ITEM *it); +int asn1_enc_restore(int *len, unsigned char **out, ASN1_VALUE **pval, const ASN1_ITEM *it); +int asn1_enc_save(ASN1_VALUE **pval, const unsigned char *in, int inlen, const ASN1_ITEM *it); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/lib_tls/include/openssl/bio.h b/lib_tls/include/openssl/bio.h new file mode 100644 index 000000000..cecb6a720 --- /dev/null +++ b/lib_tls/include/openssl/bio.h @@ -0,0 +1,776 @@ +/* crypto/bio/bio.h */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#ifndef HEADER_BIO_H +#define HEADER_BIO_H + +#include + +#ifndef OPENSSL_NO_FP_API +# include +#endif +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* These are the 'types' of BIOs */ +#define BIO_TYPE_NONE 0 +#define BIO_TYPE_MEM (1|0x0400) +#define BIO_TYPE_FILE (2|0x0400) + +#define BIO_TYPE_FD (4|0x0400|0x0100) +#define BIO_TYPE_SOCKET (5|0x0400|0x0100) +#define BIO_TYPE_NULL (6|0x0400) +#define BIO_TYPE_SSL (7|0x0200) +#define BIO_TYPE_MD (8|0x0200) /* passive filter */ +#define BIO_TYPE_BUFFER (9|0x0200) /* filter */ +#define BIO_TYPE_CIPHER (10|0x0200) /* filter */ +#define BIO_TYPE_BASE64 (11|0x0200) /* filter */ +#define BIO_TYPE_CONNECT (12|0x0400|0x0100) /* socket - connect */ +#define BIO_TYPE_ACCEPT (13|0x0400|0x0100) /* socket for accept */ +#define BIO_TYPE_PROXY_CLIENT (14|0x0200) /* client proxy BIO */ +#define BIO_TYPE_PROXY_SERVER (15|0x0200) /* server proxy BIO */ +#define BIO_TYPE_NBIO_TEST (16|0x0200) /* server proxy BIO */ +#define BIO_TYPE_NULL_FILTER (17|0x0200) +#define BIO_TYPE_BER (18|0x0200) /* BER -> bin filter */ +#define BIO_TYPE_BIO (19|0x0400) /* (half a) BIO pair */ +#define BIO_TYPE_LINEBUFFER (20|0x0200) /* filter */ +#define BIO_TYPE_DGRAM (21|0x0400|0x0100) +#define BIO_TYPE_COMP (23|0x0200) /* filter */ + +#define BIO_TYPE_DESCRIPTOR 0x0100 /* socket, fd, connect or accept */ +#define BIO_TYPE_FILTER 0x0200 +#define BIO_TYPE_SOURCE_SINK 0x0400 + +/* BIO_FILENAME_READ|BIO_CLOSE to open or close on free. + * BIO_set_fp(in,stdin,BIO_NOCLOSE); */ +#define BIO_NOCLOSE 0x00 +#define BIO_CLOSE 0x01 + +/* These are used in the following macros and are passed to + * BIO_ctrl() */ +#define BIO_CTRL_RESET 1 /* opt - rewind/zero etc */ +#define BIO_CTRL_EOF 2 /* opt - are we at the eof */ +#define BIO_CTRL_INFO 3 /* opt - extra tit-bits */ +#define BIO_CTRL_SET 4 /* man - set the 'IO' type */ +#define BIO_CTRL_GET 5 /* man - get the 'IO' type */ +#define BIO_CTRL_PUSH 6 /* opt - internal, used to signify change */ +#define BIO_CTRL_POP 7 /* opt - internal, used to signify change */ +#define BIO_CTRL_GET_CLOSE 8 /* man - set the 'close' on free */ +#define BIO_CTRL_SET_CLOSE 9 /* man - set the 'close' on free */ +#define BIO_CTRL_PENDING 10 /* opt - is their more data buffered */ +#define BIO_CTRL_FLUSH 11 /* opt - 'flush' buffered output */ +#define BIO_CTRL_DUP 12 /* man - extra stuff for 'duped' BIO */ +#define BIO_CTRL_WPENDING 13 /* opt - number of bytes still to write */ +/* callback is int cb(BIO *bio,state,ret); */ +#define BIO_CTRL_SET_CALLBACK 14 /* opt - set callback function */ +#define BIO_CTRL_GET_CALLBACK 15 /* opt - set callback function */ + +#define BIO_CTRL_SET_FILENAME 30 /* BIO_s_file special */ + +/* dgram BIO stuff */ +#define BIO_CTRL_DGRAM_CONNECT 31 /* BIO dgram special */ +#define BIO_CTRL_DGRAM_SET_CONNECTED 32 /* allow for an externally + * connected socket to be + * passed in */ +#define BIO_CTRL_DGRAM_SET_RECV_TIMEOUT 33 /* setsockopt, essentially */ +#define BIO_CTRL_DGRAM_GET_RECV_TIMEOUT 34 /* getsockopt, essentially */ +#define BIO_CTRL_DGRAM_SET_SEND_TIMEOUT 35 /* setsockopt, essentially */ +#define BIO_CTRL_DGRAM_GET_SEND_TIMEOUT 36 /* getsockopt, essentially */ + +#define BIO_CTRL_DGRAM_GET_RECV_TIMER_EXP 37 /* flag whether the last */ +#define BIO_CTRL_DGRAM_GET_SEND_TIMER_EXP 38 /* I/O operation tiemd out */ + +/* #ifdef IP_MTU_DISCOVER */ +#define BIO_CTRL_DGRAM_MTU_DISCOVER 39 /* set DF bit on egress packets */ +/* #endif */ + +#define BIO_CTRL_DGRAM_QUERY_MTU 40 /* as kernel for current MTU */ +#define BIO_CTRL_DGRAM_GET_MTU 41 /* get cached value for MTU */ +#define BIO_CTRL_DGRAM_SET_MTU 42 /* set cached value for + * MTU. want to use this + * if asking the kernel + * fails */ + +#define BIO_CTRL_DGRAM_MTU_EXCEEDED 43 /* check whether the MTU + * was exceed in the + * previous write + * operation */ + +#define BIO_CTRL_DGRAM_SET_PEER 44 /* Destination for the data */ + + +/* modifiers */ +#define BIO_FP_READ 0x02 +#define BIO_FP_WRITE 0x04 +#define BIO_FP_APPEND 0x08 +#define BIO_FP_TEXT 0x10 + +#define BIO_FLAGS_READ 0x01 +#define BIO_FLAGS_WRITE 0x02 +#define BIO_FLAGS_IO_SPECIAL 0x04 +#define BIO_FLAGS_RWS (BIO_FLAGS_READ|BIO_FLAGS_WRITE|BIO_FLAGS_IO_SPECIAL) +#define BIO_FLAGS_SHOULD_RETRY 0x08 +#ifndef BIO_FLAGS_UPLINK +/* "UPLINK" flag denotes file descriptors provided by application. + It defaults to 0, as most platforms don't require UPLINK interface. */ +#define BIO_FLAGS_UPLINK 0 +#endif + +/* Used in BIO_gethostbyname() */ +#define BIO_GHBN_CTRL_HITS 1 +#define BIO_GHBN_CTRL_MISSES 2 +#define BIO_GHBN_CTRL_CACHE_SIZE 3 +#define BIO_GHBN_CTRL_GET_ENTRY 4 +#define BIO_GHBN_CTRL_FLUSH 5 + +/* Mostly used in the SSL BIO */ +/* Not used anymore + * #define BIO_FLAGS_PROTOCOL_DELAYED_READ 0x10 + * #define BIO_FLAGS_PROTOCOL_DELAYED_WRITE 0x20 + * #define BIO_FLAGS_PROTOCOL_STARTUP 0x40 + */ + +#define BIO_FLAGS_BASE64_NO_NL 0x100 + +/* This is used with memory BIOs: it means we shouldn't free up or change the + * data in any way. + */ +#define BIO_FLAGS_MEM_RDONLY 0x200 + +typedef struct bio_st BIO; + +void BIO_set_flags(BIO *b, int flags); +int BIO_test_flags(const BIO *b, int flags); +void BIO_clear_flags(BIO *b, int flags); + +#define BIO_get_flags(b) BIO_test_flags(b, ~(0x0)) +#define BIO_set_retry_special(b) \ + BIO_set_flags(b, (BIO_FLAGS_IO_SPECIAL|BIO_FLAGS_SHOULD_RETRY)) +#define BIO_set_retry_read(b) \ + BIO_set_flags(b, (BIO_FLAGS_READ|BIO_FLAGS_SHOULD_RETRY)) +#define BIO_set_retry_write(b) \ + BIO_set_flags(b, (BIO_FLAGS_WRITE|BIO_FLAGS_SHOULD_RETRY)) + +/* These are normally used internally in BIOs */ +#define BIO_clear_retry_flags(b) \ + BIO_clear_flags(b, (BIO_FLAGS_RWS|BIO_FLAGS_SHOULD_RETRY)) +#define BIO_get_retry_flags(b) \ + BIO_test_flags(b, (BIO_FLAGS_RWS|BIO_FLAGS_SHOULD_RETRY)) + +/* These should be used by the application to tell why we should retry */ +#define BIO_should_read(a) BIO_test_flags(a, BIO_FLAGS_READ) +#define BIO_should_write(a) BIO_test_flags(a, BIO_FLAGS_WRITE) +#define BIO_should_io_special(a) BIO_test_flags(a, BIO_FLAGS_IO_SPECIAL) +#define BIO_retry_type(a) BIO_test_flags(a, BIO_FLAGS_RWS) +#define BIO_should_retry(a) BIO_test_flags(a, BIO_FLAGS_SHOULD_RETRY) + +/* The next three are used in conjunction with the + * BIO_should_io_special() condition. After this returns true, + * BIO *BIO_get_retry_BIO(BIO *bio, int *reason); will walk the BIO + * stack and return the 'reason' for the special and the offending BIO. + * Given a BIO, BIO_get_retry_reason(bio) will return the code. */ +/* Returned from the SSL bio when the certificate retrieval code had an error */ +#define BIO_RR_SSL_X509_LOOKUP 0x01 +/* Returned from the connect BIO when a connect would have blocked */ +#define BIO_RR_CONNECT 0x02 +/* Returned from the accept BIO when an accept would have blocked */ +#define BIO_RR_ACCEPT 0x03 + +/* These are passed by the BIO callback */ +#define BIO_CB_FREE 0x01 +#define BIO_CB_READ 0x02 +#define BIO_CB_WRITE 0x03 +#define BIO_CB_PUTS 0x04 +#define BIO_CB_GETS 0x05 +#define BIO_CB_CTRL 0x06 + +/* The callback is called before and after the underling operation, + * The BIO_CB_RETURN flag indicates if it is after the call */ +#define BIO_CB_RETURN 0x80 +#define BIO_CB_return(a) ((a)|BIO_CB_RETURN)) +#define BIO_cb_pre(a) (!((a)&BIO_CB_RETURN)) +#define BIO_cb_post(a) ((a)&BIO_CB_RETURN) + +long (*BIO_get_callback(const BIO *b)) (struct bio_st *,int,const char *,int, long,long); +void BIO_set_callback(BIO *b, + long (*callback)(struct bio_st *,int,const char *,int, long,long)); +char *BIO_get_callback_arg(const BIO *b); +void BIO_set_callback_arg(BIO *b, char *arg); + +const char * BIO_method_name(const BIO *b); +int BIO_method_type(const BIO *b); + +typedef void bio_info_cb(struct bio_st *, int, const char *, int, long, long); + +#ifndef OPENSSL_SYS_WIN16 +typedef struct bio_method_st + { + int type; + const char *name; + int (*bwrite)(BIO *, const char *, int); + int (*bread)(BIO *, char *, int); + int (*bputs)(BIO *, const char *); + int (*bgets)(BIO *, char *, int); + long (*ctrl)(BIO *, int, long, void *); + int (*create)(BIO *); + int (*destroy)(BIO *); + long (*callback_ctrl)(BIO *, int, bio_info_cb *); + } BIO_METHOD; +#else +typedef struct bio_method_st + { + int type; + const char *name; + int (_far *bwrite)(); + int (_far *bread)(); + int (_far *bputs)(); + int (_far *bgets)(); + long (_far *ctrl)(); + int (_far *create)(); + int (_far *destroy)(); + long (_far *callback_ctrl)(); + } BIO_METHOD; +#endif + +struct bio_st + { + BIO_METHOD *method; + /* bio, mode, argp, argi, argl, ret */ + long (*callback)(struct bio_st *,int,const char *,int, long,long); + char *cb_arg; /* first argument for the callback */ + + int init; + int shutdown; + int flags; /* extra storage */ + int retry_reason; + int num; + void *ptr; + struct bio_st *next_bio; /* used by filter BIOs */ + struct bio_st *prev_bio; /* used by filter BIOs */ + int references; + unsigned long num_read; + unsigned long num_write; + + CRYPTO_EX_DATA ex_data; + }; + +DECLARE_STACK_OF(BIO) + +typedef struct bio_f_buffer_ctx_struct + { + /* BIO *bio; */ /* this is now in the BIO struct */ + int ibuf_size; /* how big is the input buffer */ + int obuf_size; /* how big is the output buffer */ + + char *ibuf; /* the char array */ + int ibuf_len; /* how many bytes are in it */ + int ibuf_off; /* write/read offset */ + + char *obuf; /* the char array */ + int obuf_len; /* how many bytes are in it */ + int obuf_off; /* write/read offset */ + } BIO_F_BUFFER_CTX; + +/* connect BIO stuff */ +#define BIO_CONN_S_BEFORE 1 +#define BIO_CONN_S_GET_IP 2 +#define BIO_CONN_S_GET_PORT 3 +#define BIO_CONN_S_CREATE_SOCKET 4 +#define BIO_CONN_S_CONNECT 5 +#define BIO_CONN_S_OK 6 +#define BIO_CONN_S_BLOCKED_CONNECT 7 +#define BIO_CONN_S_NBIO 8 +/*#define BIO_CONN_get_param_hostname BIO_ctrl */ + +#define BIO_C_SET_CONNECT 100 +#define BIO_C_DO_STATE_MACHINE 101 +#define BIO_C_SET_NBIO 102 +#define BIO_C_SET_PROXY_PARAM 103 +#define BIO_C_SET_FD 104 +#define BIO_C_GET_FD 105 +#define BIO_C_SET_FILE_PTR 106 +#define BIO_C_GET_FILE_PTR 107 +#define BIO_C_SET_FILENAME 108 +#define BIO_C_SET_SSL 109 +#define BIO_C_GET_SSL 110 +#define BIO_C_SET_MD 111 +#define BIO_C_GET_MD 112 +#define BIO_C_GET_CIPHER_STATUS 113 +#define BIO_C_SET_BUF_MEM 114 +#define BIO_C_GET_BUF_MEM_PTR 115 +#define BIO_C_GET_BUFF_NUM_LINES 116 +#define BIO_C_SET_BUFF_SIZE 117 +#define BIO_C_SET_ACCEPT 118 +#define BIO_C_SSL_MODE 119 +#define BIO_C_GET_MD_CTX 120 +#define BIO_C_GET_PROXY_PARAM 121 +#define BIO_C_SET_BUFF_READ_DATA 122 /* data to read first */ +#define BIO_C_GET_CONNECT 123 +#define BIO_C_GET_ACCEPT 124 +#define BIO_C_SET_SSL_RENEGOTIATE_BYTES 125 +#define BIO_C_GET_SSL_NUM_RENEGOTIATES 126 +#define BIO_C_SET_SSL_RENEGOTIATE_TIMEOUT 127 +#define BIO_C_FILE_SEEK 128 +#define BIO_C_GET_CIPHER_CTX 129 +#define BIO_C_SET_BUF_MEM_EOF_RETURN 130/*return end of input value*/ +#define BIO_C_SET_BIND_MODE 131 +#define BIO_C_GET_BIND_MODE 132 +#define BIO_C_FILE_TELL 133 +#define BIO_C_GET_SOCKS 134 +#define BIO_C_SET_SOCKS 135 + +#define BIO_C_SET_WRITE_BUF_SIZE 136/* for BIO_s_bio */ +#define BIO_C_GET_WRITE_BUF_SIZE 137 +#define BIO_C_MAKE_BIO_PAIR 138 +#define BIO_C_DESTROY_BIO_PAIR 139 +#define BIO_C_GET_WRITE_GUARANTEE 140 +#define BIO_C_GET_READ_REQUEST 141 +#define BIO_C_SHUTDOWN_WR 142 +#define BIO_C_NREAD0 143 +#define BIO_C_NREAD 144 +#define BIO_C_NWRITE0 145 +#define BIO_C_NWRITE 146 +#define BIO_C_RESET_READ_REQUEST 147 +#define BIO_C_SET_MD_CTX 148 + + +#define BIO_set_app_data(s,arg) BIO_set_ex_data(s,0,arg) +#define BIO_get_app_data(s) BIO_get_ex_data(s,0) + +/* BIO_s_connect() and BIO_s_socks4a_connect() */ +#define BIO_set_conn_hostname(b,name) BIO_ctrl(b,BIO_C_SET_CONNECT,0,(char *)name) +#define BIO_set_conn_port(b,port) BIO_ctrl(b,BIO_C_SET_CONNECT,1,(char *)port) +#define BIO_set_conn_ip(b,ip) BIO_ctrl(b,BIO_C_SET_CONNECT,2,(char *)ip) +#define BIO_set_conn_int_port(b,port) BIO_ctrl(b,BIO_C_SET_CONNECT,3,(char *)port) +#define BIO_get_conn_hostname(b) BIO_ptr_ctrl(b,BIO_C_GET_CONNECT,0) +#define BIO_get_conn_port(b) BIO_ptr_ctrl(b,BIO_C_GET_CONNECT,1) +#define BIO_get_conn_ip(b) BIO_ptr_ctrl(b,BIO_C_GET_CONNECT,2) +#define BIO_get_conn_int_port(b) BIO_int_ctrl(b,BIO_C_GET_CONNECT,3) + + +#define BIO_set_nbio(b,n) BIO_ctrl(b,BIO_C_SET_NBIO,(n),NULL) + +/* BIO_s_accept_socket() */ +#define BIO_set_accept_port(b,name) BIO_ctrl(b,BIO_C_SET_ACCEPT,0,(char *)name) +#define BIO_get_accept_port(b) BIO_ptr_ctrl(b,BIO_C_GET_ACCEPT,0) +/* #define BIO_set_nbio(b,n) BIO_ctrl(b,BIO_C_SET_NBIO,(n),NULL) */ +#define BIO_set_nbio_accept(b,n) BIO_ctrl(b,BIO_C_SET_ACCEPT,1,(n)?"a":NULL) +#define BIO_set_accept_bios(b,bio) BIO_ctrl(b,BIO_C_SET_ACCEPT,2,(char *)bio) + +#define BIO_BIND_NORMAL 0 +#define BIO_BIND_REUSEADDR_IF_UNUSED 1 +#define BIO_BIND_REUSEADDR 2 +#define BIO_set_bind_mode(b,mode) BIO_ctrl(b,BIO_C_SET_BIND_MODE,mode,NULL) +#define BIO_get_bind_mode(b,mode) BIO_ctrl(b,BIO_C_GET_BIND_MODE,0,NULL) + +#define BIO_do_connect(b) BIO_do_handshake(b) +#define BIO_do_accept(b) BIO_do_handshake(b) +#define BIO_do_handshake(b) BIO_ctrl(b,BIO_C_DO_STATE_MACHINE,0,NULL) + +/* BIO_s_proxy_client() */ +#define BIO_set_url(b,url) BIO_ctrl(b,BIO_C_SET_PROXY_PARAM,0,(char *)(url)) +#define BIO_set_proxies(b,p) BIO_ctrl(b,BIO_C_SET_PROXY_PARAM,1,(char *)(p)) +/* BIO_set_nbio(b,n) */ +#define BIO_set_filter_bio(b,s) BIO_ctrl(b,BIO_C_SET_PROXY_PARAM,2,(char *)(s)) +/* BIO *BIO_get_filter_bio(BIO *bio); */ +#define BIO_set_proxy_cb(b,cb) BIO_callback_ctrl(b,BIO_C_SET_PROXY_PARAM,3,(void *(*cb)())) +#define BIO_set_proxy_header(b,sk) BIO_ctrl(b,BIO_C_SET_PROXY_PARAM,4,(char *)sk) +#define BIO_set_no_connect_return(b,bool) BIO_int_ctrl(b,BIO_C_SET_PROXY_PARAM,5,bool) + +#define BIO_get_proxy_header(b,skp) BIO_ctrl(b,BIO_C_GET_PROXY_PARAM,0,(char *)skp) +#define BIO_get_proxies(b,pxy_p) BIO_ctrl(b,BIO_C_GET_PROXY_PARAM,1,(char *)(pxy_p)) +#define BIO_get_url(b,url) BIO_ctrl(b,BIO_C_GET_PROXY_PARAM,2,(char *)(url)) +#define BIO_get_no_connect_return(b) BIO_ctrl(b,BIO_C_GET_PROXY_PARAM,5,NULL) + +#define BIO_set_fd(b,fd,c) BIO_int_ctrl(b,BIO_C_SET_FD,c,fd) +#define BIO_get_fd(b,c) BIO_ctrl(b,BIO_C_GET_FD,0,(char *)c) + +#define BIO_set_fp(b,fp,c) BIO_ctrl(b,BIO_C_SET_FILE_PTR,c,(char *)fp) +#define BIO_get_fp(b,fpp) BIO_ctrl(b,BIO_C_GET_FILE_PTR,0,(char *)fpp) + +#define BIO_seek(b,ofs) (int)BIO_ctrl(b,BIO_C_FILE_SEEK,ofs,NULL) +#define BIO_tell(b) (int)BIO_ctrl(b,BIO_C_FILE_TELL,0,NULL) + +/* name is cast to lose const, but might be better to route through a function + so we can do it safely */ +#ifdef CONST_STRICT +/* If you are wondering why this isn't defined, its because CONST_STRICT is + * purely a compile-time kludge to allow const to be checked. + */ +int BIO_read_filename(BIO *b,const char *name); +#else +#define BIO_read_filename(b,name) BIO_ctrl(b,BIO_C_SET_FILENAME, \ + BIO_CLOSE|BIO_FP_READ,(char *)name) +#endif +#define BIO_write_filename(b,name) BIO_ctrl(b,BIO_C_SET_FILENAME, \ + BIO_CLOSE|BIO_FP_WRITE,name) +#define BIO_append_filename(b,name) BIO_ctrl(b,BIO_C_SET_FILENAME, \ + BIO_CLOSE|BIO_FP_APPEND,name) +#define BIO_rw_filename(b,name) BIO_ctrl(b,BIO_C_SET_FILENAME, \ + BIO_CLOSE|BIO_FP_READ|BIO_FP_WRITE,name) + +/* WARNING WARNING, this ups the reference count on the read bio of the + * SSL structure. This is because the ssl read BIO is now pointed to by + * the next_bio field in the bio. So when you free the BIO, make sure + * you are doing a BIO_free_all() to catch the underlying BIO. */ +#define BIO_set_ssl(b,ssl,c) BIO_ctrl(b,BIO_C_SET_SSL,c,(char *)ssl) +#define BIO_get_ssl(b,sslp) BIO_ctrl(b,BIO_C_GET_SSL,0,(char *)sslp) +#define BIO_set_ssl_mode(b,client) BIO_ctrl(b,BIO_C_SSL_MODE,client,NULL) +#define BIO_set_ssl_renegotiate_bytes(b,num) \ + BIO_ctrl(b,BIO_C_SET_SSL_RENEGOTIATE_BYTES,num,NULL); +#define BIO_get_num_renegotiates(b) \ + BIO_ctrl(b,BIO_C_GET_SSL_NUM_RENEGOTIATES,0,NULL); +#define BIO_set_ssl_renegotiate_timeout(b,seconds) \ + BIO_ctrl(b,BIO_C_SET_SSL_RENEGOTIATE_TIMEOUT,seconds,NULL); + +/* defined in evp.h */ +/* #define BIO_set_md(b,md) BIO_ctrl(b,BIO_C_SET_MD,1,(char *)md) */ + +#define BIO_get_mem_data(b,pp) BIO_ctrl(b,BIO_CTRL_INFO,0,(char *)pp) +#define BIO_set_mem_buf(b,bm,c) BIO_ctrl(b,BIO_C_SET_BUF_MEM,c,(char *)bm) +#define BIO_get_mem_ptr(b,pp) BIO_ctrl(b,BIO_C_GET_BUF_MEM_PTR,0,(char *)pp) +#define BIO_set_mem_eof_return(b,v) \ + BIO_ctrl(b,BIO_C_SET_BUF_MEM_EOF_RETURN,v,NULL) + +/* For the BIO_f_buffer() type */ +#define BIO_get_buffer_num_lines(b) BIO_ctrl(b,BIO_C_GET_BUFF_NUM_LINES,0,NULL) +#define BIO_set_buffer_size(b,size) BIO_ctrl(b,BIO_C_SET_BUFF_SIZE,size,NULL) +#define BIO_set_read_buffer_size(b,size) BIO_int_ctrl(b,BIO_C_SET_BUFF_SIZE,size,0) +#define BIO_set_write_buffer_size(b,size) BIO_int_ctrl(b,BIO_C_SET_BUFF_SIZE,size,1) +#define BIO_set_buffer_read_data(b,buf,num) BIO_ctrl(b,BIO_C_SET_BUFF_READ_DATA,num,buf) + +/* Don't use the next one unless you know what you are doing :-) */ +#define BIO_dup_state(b,ret) BIO_ctrl(b,BIO_CTRL_DUP,0,(char *)(ret)) + +#define BIO_reset(b) (int)BIO_ctrl(b,BIO_CTRL_RESET,0,NULL) +#define BIO_eof(b) (int)BIO_ctrl(b,BIO_CTRL_EOF,0,NULL) +#define BIO_set_close(b,c) (int)BIO_ctrl(b,BIO_CTRL_SET_CLOSE,(c),NULL) +#define BIO_get_close(b) (int)BIO_ctrl(b,BIO_CTRL_GET_CLOSE,0,NULL) +#define BIO_pending(b) (int)BIO_ctrl(b,BIO_CTRL_PENDING,0,NULL) +#define BIO_wpending(b) (int)BIO_ctrl(b,BIO_CTRL_WPENDING,0,NULL) +/* ...pending macros have inappropriate return type */ +size_t BIO_ctrl_pending(BIO *b); +size_t BIO_ctrl_wpending(BIO *b); +#define BIO_flush(b) (int)BIO_ctrl(b,BIO_CTRL_FLUSH,0,NULL) +#define BIO_get_info_callback(b,cbp) (int)BIO_ctrl(b,BIO_CTRL_GET_CALLBACK,0, \ + cbp) +#define BIO_set_info_callback(b,cb) (int)BIO_callback_ctrl(b,BIO_CTRL_SET_CALLBACK,cb) + +/* For the BIO_f_buffer() type */ +#define BIO_buffer_get_num_lines(b) BIO_ctrl(b,BIO_CTRL_GET,0,NULL) + +/* For BIO_s_bio() */ +#define BIO_set_write_buf_size(b,size) (int)BIO_ctrl(b,BIO_C_SET_WRITE_BUF_SIZE,size,NULL) +#define BIO_get_write_buf_size(b,size) (size_t)BIO_ctrl(b,BIO_C_GET_WRITE_BUF_SIZE,size,NULL) +#define BIO_make_bio_pair(b1,b2) (int)BIO_ctrl(b1,BIO_C_MAKE_BIO_PAIR,0,b2) +#define BIO_destroy_bio_pair(b) (int)BIO_ctrl(b,BIO_C_DESTROY_BIO_PAIR,0,NULL) +#define BIO_shutdown_wr(b) (int)BIO_ctrl(b, BIO_C_SHUTDOWN_WR, 0, NULL) +/* macros with inappropriate type -- but ...pending macros use int too: */ +#define BIO_get_write_guarantee(b) (int)BIO_ctrl(b,BIO_C_GET_WRITE_GUARANTEE,0,NULL) +#define BIO_get_read_request(b) (int)BIO_ctrl(b,BIO_C_GET_READ_REQUEST,0,NULL) +size_t BIO_ctrl_get_write_guarantee(BIO *b); +size_t BIO_ctrl_get_read_request(BIO *b); +int BIO_ctrl_reset_read_request(BIO *b); + +/* ctrl macros for dgram */ +#define BIO_ctrl_dgram_connect(b,peer) \ + (int)BIO_ctrl(b,BIO_CTRL_DGRAM_CONNECT,0, (char *)peer) +#define BIO_ctrl_set_connected(b, state, peer) \ + (int)BIO_ctrl(b, BIO_CTRL_DGRAM_SET_CONNECTED, state, (char *)peer) +#define BIO_dgram_recv_timedout(b) \ + (int)BIO_ctrl(b, BIO_CTRL_DGRAM_GET_RECV_TIMER_EXP, 0, NULL) +#define BIO_dgram_send_timedout(b) \ + (int)BIO_ctrl(b, BIO_CTRL_DGRAM_GET_SEND_TIMER_EXP, 0, NULL) +#define BIO_dgram_set_peer(b,peer) \ + (int)BIO_ctrl(b, BIO_CTRL_DGRAM_SET_PEER, 0, (char *)peer) + +/* These two aren't currently implemented */ +/* int BIO_get_ex_num(BIO *bio); */ +/* void BIO_set_ex_free_func(BIO *bio,int idx,void (*cb)()); */ +int BIO_set_ex_data(BIO *bio,int idx,void *data); +void *BIO_get_ex_data(BIO *bio,int idx); +int BIO_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func, + CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func); +unsigned long BIO_number_read(BIO *bio); +unsigned long BIO_number_written(BIO *bio); + +# ifndef OPENSSL_NO_FP_API +# if defined(OPENSSL_SYS_WIN16) && defined(_WINDLL) +BIO_METHOD *BIO_s_file_internal(void); +BIO *BIO_new_file_internal(char *filename, char *mode); +BIO *BIO_new_fp_internal(FILE *stream, int close_flag); +# define BIO_s_file BIO_s_file_internal +# define BIO_new_file BIO_new_file_internal +# define BIO_new_fp BIO_new_fp_internal +# else /* FP_API */ +BIO_METHOD *BIO_s_file(void ); +BIO *BIO_new_file(const char *filename, const char *mode); +BIO *BIO_new_fp(FILE *stream, int close_flag); +# define BIO_s_file_internal BIO_s_file +# define BIO_new_file_internal BIO_new_file +# define BIO_new_fp_internal BIO_s_file +# endif /* FP_API */ +# endif +BIO * BIO_new(BIO_METHOD *type); +int BIO_set(BIO *a,BIO_METHOD *type); +int BIO_free(BIO *a); +void BIO_vfree(BIO *a); +int BIO_read(BIO *b, void *data, int len); +int BIO_gets(BIO *bp,char *buf, int size); +int BIO_write(BIO *b, const void *data, int len); +int BIO_puts(BIO *bp,const char *buf); +int BIO_indent(BIO *b,int indent,int max); +long BIO_ctrl(BIO *bp,int cmd,long larg,void *parg); +long BIO_callback_ctrl(BIO *b, int cmd, void (*fp)(struct bio_st *, int, const char *, int, long, long)); +char * BIO_ptr_ctrl(BIO *bp,int cmd,long larg); +long BIO_int_ctrl(BIO *bp,int cmd,long larg,int iarg); +BIO * BIO_push(BIO *b,BIO *append); +BIO * BIO_pop(BIO *b); +void BIO_free_all(BIO *a); +BIO * BIO_find_type(BIO *b,int bio_type); +BIO * BIO_next(BIO *b); +BIO * BIO_get_retry_BIO(BIO *bio, int *reason); +int BIO_get_retry_reason(BIO *bio); +BIO * BIO_dup_chain(BIO *in); + +int BIO_nread0(BIO *bio, char **buf); +int BIO_nread(BIO *bio, char **buf, int num); +int BIO_nwrite0(BIO *bio, char **buf); +int BIO_nwrite(BIO *bio, char **buf, int num); + +#ifndef OPENSSL_SYS_WIN16 +long BIO_debug_callback(BIO *bio,int cmd,const char *argp,int argi, + long argl,long ret); +#else +long _far _loadds BIO_debug_callback(BIO *bio,int cmd,const char *argp,int argi, + long argl,long ret); +#endif + +BIO_METHOD *BIO_s_mem(void); +BIO *BIO_new_mem_buf(void *buf, int len); +BIO_METHOD *BIO_s_socket(void); +BIO_METHOD *BIO_s_connect(void); +BIO_METHOD *BIO_s_accept(void); +BIO_METHOD *BIO_s_fd(void); +#ifndef OPENSSL_SYS_OS2 +BIO_METHOD *BIO_s_log(void); +#endif +BIO_METHOD *BIO_s_bio(void); +BIO_METHOD *BIO_s_null(void); +BIO_METHOD *BIO_f_null(void); +BIO_METHOD *BIO_f_buffer(void); +#ifdef OPENSSL_SYS_VMS +BIO_METHOD *BIO_f_linebuffer(void); +#endif +BIO_METHOD *BIO_f_nbio_test(void); +#ifndef OPENSSL_NO_DGRAM +BIO_METHOD *BIO_s_datagram(void); +#endif + +/* BIO_METHOD *BIO_f_ber(void); */ + +int BIO_sock_should_retry(int i); +int BIO_sock_non_fatal_error(int error); +int BIO_dgram_non_fatal_error(int error); + +int BIO_fd_should_retry(int i); +int BIO_fd_non_fatal_error(int error); +int BIO_dump_cb(int (*cb)(const void *data, size_t len, void *u), + void *u, const char *s, int len); +int BIO_dump_indent_cb(int (*cb)(const void *data, size_t len, void *u), + void *u, const char *s, int len, int indent); +int BIO_dump(BIO *b,const char *bytes,int len); +int BIO_dump_indent(BIO *b,const char *bytes,int len,int indent); +#ifndef OPENSSL_NO_FP_API +int BIO_dump_fp(FILE *fp, const char *s, int len); +int BIO_dump_indent_fp(FILE *fp, const char *s, int len, int indent); +#endif +struct hostent *BIO_gethostbyname(const char *name); +/* We might want a thread-safe interface too: + * struct hostent *BIO_gethostbyname_r(const char *name, + * struct hostent *result, void *buffer, size_t buflen); + * or something similar (caller allocates a struct hostent, + * pointed to by "result", and additional buffer space for the various + * substructures; if the buffer does not suffice, NULL is returned + * and an appropriate error code is set). + */ +int BIO_sock_error(int sock); +int BIO_socket_ioctl(int fd, long type, void *arg); +int BIO_socket_nbio(int fd,int mode); +int BIO_get_port(const char *str, unsigned short *port_ptr); +int BIO_get_host_ip(const char *str, unsigned char *ip); +int BIO_get_accept_socket(char *host_port,int mode); +int BIO_accept(int sock,char **ip_port); +int BIO_sock_init(void ); +void BIO_sock_cleanup(void); +int BIO_set_tcp_ndelay(int sock,int turn_on); + +BIO *BIO_new_socket(int sock, int close_flag); +BIO *BIO_new_dgram(int fd, int close_flag); +BIO *BIO_new_fd(int fd, int close_flag); +BIO *BIO_new_connect(char *host_port); +BIO *BIO_new_accept(char *host_port); + +int BIO_new_bio_pair(BIO **bio1, size_t writebuf1, + BIO **bio2, size_t writebuf2); +/* If successful, returns 1 and in *bio1, *bio2 two BIO pair endpoints. + * Otherwise returns 0 and sets *bio1 and *bio2 to NULL. + * Size 0 uses default value. + */ + +void BIO_copy_next_retry(BIO *b); + +/*long BIO_ghbn_ctrl(int cmd,int iarg,char *parg);*/ + +#ifdef __GNUC__ +# define __bio_h__attr__ __attribute__ +#else +# define __bio_h__attr__(x) +#endif +int BIO_printf(BIO *bio, const char *format, ...) + __bio_h__attr__((__format__(__printf__,2,3))); +int BIO_vprintf(BIO *bio, const char *format, va_list args) + __bio_h__attr__((__format__(__printf__,2,0))); +int BIO_snprintf(char *buf, size_t n, const char *format, ...) + __bio_h__attr__((__format__(__printf__,3,4))); +int BIO_vsnprintf(char *buf, size_t n, const char *format, va_list args) + __bio_h__attr__((__format__(__printf__,3,0))); +#undef __bio_h__attr__ + +/* BEGIN ERROR CODES */ +/* The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ +void ERR_load_BIO_strings(void); + +/* Error codes for the BIO functions. */ + +/* Function codes. */ +#define BIO_F_ACPT_STATE 100 +#define BIO_F_BIO_ACCEPT 101 +#define BIO_F_BIO_BER_GET_HEADER 102 +#define BIO_F_BIO_CALLBACK_CTRL 131 +#define BIO_F_BIO_CTRL 103 +#define BIO_F_BIO_GETHOSTBYNAME 120 +#define BIO_F_BIO_GETS 104 +#define BIO_F_BIO_GET_ACCEPT_SOCKET 105 +#define BIO_F_BIO_GET_HOST_IP 106 +#define BIO_F_BIO_GET_PORT 107 +#define BIO_F_BIO_MAKE_PAIR 121 +#define BIO_F_BIO_NEW 108 +#define BIO_F_BIO_NEW_FILE 109 +#define BIO_F_BIO_NEW_MEM_BUF 126 +#define BIO_F_BIO_NREAD 123 +#define BIO_F_BIO_NREAD0 124 +#define BIO_F_BIO_NWRITE 125 +#define BIO_F_BIO_NWRITE0 122 +#define BIO_F_BIO_PUTS 110 +#define BIO_F_BIO_READ 111 +#define BIO_F_BIO_SOCK_INIT 112 +#define BIO_F_BIO_WRITE 113 +#define BIO_F_BUFFER_CTRL 114 +#define BIO_F_CONN_CTRL 127 +#define BIO_F_CONN_STATE 115 +#define BIO_F_FILE_CTRL 116 +#define BIO_F_FILE_READ 130 +#define BIO_F_LINEBUFFER_CTRL 129 +#define BIO_F_MEM_READ 128 +#define BIO_F_MEM_WRITE 117 +#define BIO_F_SSL_NEW 118 +#define BIO_F_WSASTARTUP 119 + +/* Reason codes. */ +#define BIO_R_ACCEPT_ERROR 100 +#define BIO_R_BAD_FOPEN_MODE 101 +#define BIO_R_BAD_HOSTNAME_LOOKUP 102 +#define BIO_R_BROKEN_PIPE 124 +#define BIO_R_CONNECT_ERROR 103 +#define BIO_R_EOF_ON_MEMORY_BIO 127 +#define BIO_R_ERROR_SETTING_NBIO 104 +#define BIO_R_ERROR_SETTING_NBIO_ON_ACCEPTED_SOCKET 105 +#define BIO_R_ERROR_SETTING_NBIO_ON_ACCEPT_SOCKET 106 +#define BIO_R_GETHOSTBYNAME_ADDR_IS_NOT_AF_INET 107 +#define BIO_R_INVALID_ARGUMENT 125 +#define BIO_R_INVALID_IP_ADDRESS 108 +#define BIO_R_IN_USE 123 +#define BIO_R_KEEPALIVE 109 +#define BIO_R_NBIO_CONNECT_ERROR 110 +#define BIO_R_NO_ACCEPT_PORT_SPECIFIED 111 +#define BIO_R_NO_HOSTNAME_SPECIFIED 112 +#define BIO_R_NO_PORT_DEFINED 113 +#define BIO_R_NO_PORT_SPECIFIED 114 +#define BIO_R_NO_SUCH_FILE 128 +#define BIO_R_NULL_PARAMETER 115 +#define BIO_R_TAG_MISMATCH 116 +#define BIO_R_UNABLE_TO_BIND_SOCKET 117 +#define BIO_R_UNABLE_TO_CREATE_SOCKET 118 +#define BIO_R_UNABLE_TO_LISTEN_SOCKET 119 +#define BIO_R_UNINITIALIZED 120 +#define BIO_R_UNSUPPORTED_METHOD 121 +#define BIO_R_WRITE_TO_READ_ONLY_BIO 126 +#define BIO_R_WSASTARTUP 122 + +#ifdef __cplusplus +} +#endif +#endif diff --git a/lib_tls/include/openssl/blowfish.h b/lib_tls/include/openssl/blowfish.h new file mode 100644 index 000000000..cd49e85ab --- /dev/null +++ b/lib_tls/include/openssl/blowfish.h @@ -0,0 +1,127 @@ +/* crypto/bf/blowfish.h */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#ifndef HEADER_BLOWFISH_H +#define HEADER_BLOWFISH_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef OPENSSL_NO_BF +#error BF is disabled. +#endif + +#define BF_ENCRYPT 1 +#define BF_DECRYPT 0 + +/* + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + * ! BF_LONG has to be at least 32 bits wide. If it's wider, then ! + * ! BF_LONG_LOG2 has to be defined along. ! + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + */ + +#if defined(OPENSSL_SYS_WIN16) || defined(__LP32__) +#define BF_LONG unsigned long +#elif defined(OPENSSL_SYS_CRAY) || defined(__ILP64__) +#define BF_LONG unsigned long +#define BF_LONG_LOG2 3 +/* + * _CRAY note. I could declare short, but I have no idea what impact + * does it have on performance on none-T3E machines. I could declare + * int, but at least on C90 sizeof(int) can be chosen at compile time. + * So I've chosen long... + * + */ +#else +#define BF_LONG unsigned int +#endif + +#define BF_ROUNDS 16 +#define BF_BLOCK 8 + +typedef struct bf_key_st + { + BF_LONG P[BF_ROUNDS+2]; + BF_LONG S[4*256]; + } BF_KEY; + + +void BF_set_key(BF_KEY *key, int len, const unsigned char *data); + +void BF_encrypt(BF_LONG *data,const BF_KEY *key); +void BF_decrypt(BF_LONG *data,const BF_KEY *key); + +void BF_ecb_encrypt(const unsigned char *in, unsigned char *out, + const BF_KEY *key, int enc); +void BF_cbc_encrypt(const unsigned char *in, unsigned char *out, long length, + const BF_KEY *schedule, unsigned char *ivec, int enc); +void BF_cfb64_encrypt(const unsigned char *in, unsigned char *out, long length, + const BF_KEY *schedule, unsigned char *ivec, int *num, int enc); +void BF_ofb64_encrypt(const unsigned char *in, unsigned char *out, long length, + const BF_KEY *schedule, unsigned char *ivec, int *num); +const char *BF_options(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_tls/include/openssl/bn.h b/lib_tls/include/openssl/bn.h new file mode 100644 index 000000000..6d754d554 --- /dev/null +++ b/lib_tls/include/openssl/bn.h @@ -0,0 +1,844 @@ +/* crypto/bn/bn.h */ +/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * + * Portions of the attached software ("Contribution") are developed by + * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. + * + * The Contribution is licensed pursuant to the Eric Young open source + * license provided above. + * + * The binary polynomial arithmetic software is originally written by + * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems Laboratories. + * + */ + +#ifndef HEADER_BN_H +#define HEADER_BN_H + +#include +#ifndef OPENSSL_NO_FP_API +#include /* FILE */ +#endif +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* These preprocessor symbols control various aspects of the bignum headers and + * library code. They're not defined by any "normal" configuration, as they are + * intended for development and testing purposes. NB: defining all three can be + * useful for debugging application code as well as openssl itself. + * + * BN_DEBUG - turn on various debugging alterations to the bignum code + * BN_DEBUG_RAND - uses random poisoning of unused words to trip up + * mismanagement of bignum internals. You must also define BN_DEBUG. + */ +/* #define BN_DEBUG */ +/* #define BN_DEBUG_RAND */ + +#define BN_MUL_COMBA +#define BN_SQR_COMBA +#define BN_RECURSION + +/* This next option uses the C libraries (2 word)/(1 word) function. + * If it is not defined, I use my C version (which is slower). + * The reason for this flag is that when the particular C compiler + * library routine is used, and the library is linked with a different + * compiler, the library is missing. This mostly happens when the + * library is built with gcc and then linked using normal cc. This would + * be a common occurrence because gcc normally produces code that is + * 2 times faster than system compilers for the big number stuff. + * For machines with only one compiler (or shared libraries), this should + * be on. Again this in only really a problem on machines + * using "long long's", are 32bit, and are not using my assembler code. */ +#if defined(OPENSSL_SYS_MSDOS) || defined(OPENSSL_SYS_WINDOWS) || \ + defined(OPENSSL_SYS_WIN32) || defined(linux) +# ifndef BN_DIV2W +# define BN_DIV2W +# endif +#endif + +/* assuming long is 64bit - this is the DEC Alpha + * unsigned long long is only 64 bits :-(, don't define + * BN_LLONG for the DEC Alpha */ +#ifdef SIXTY_FOUR_BIT_LONG +#define BN_ULLONG unsigned long long +#define BN_ULONG unsigned long +#define BN_LONG long +#define BN_BITS 128 +#define BN_BYTES 8 +#define BN_BITS2 64 +#define BN_BITS4 32 +#define BN_MASK (0xffffffffffffffffffffffffffffffffLL) +#define BN_MASK2 (0xffffffffffffffffL) +#define BN_MASK2l (0xffffffffL) +#define BN_MASK2h (0xffffffff00000000L) +#define BN_MASK2h1 (0xffffffff80000000L) +#define BN_TBIT (0x8000000000000000L) +#define BN_DEC_CONV (10000000000000000000UL) +#define BN_DEC_FMT1 "%lu" +#define BN_DEC_FMT2 "%019lu" +#define BN_DEC_NUM 19 +#endif + +/* This is where the long long data type is 64 bits, but long is 32. + * For machines where there are 64bit registers, this is the mode to use. + * IRIX, on R4000 and above should use this mode, along with the relevant + * assembler code :-). Do NOT define BN_LLONG. + */ +#ifdef SIXTY_FOUR_BIT +#undef BN_LLONG +#undef BN_ULLONG +#define BN_ULONG unsigned long long +#define BN_LONG long long +#define BN_BITS 128 +#define BN_BYTES 8 +#define BN_BITS2 64 +#define BN_BITS4 32 +#define BN_MASK2 (0xffffffffffffffffLL) +#define BN_MASK2l (0xffffffffL) +#define BN_MASK2h (0xffffffff00000000LL) +#define BN_MASK2h1 (0xffffffff80000000LL) +#define BN_TBIT (0x8000000000000000LL) +#define BN_DEC_CONV (10000000000000000000ULL) +#define BN_DEC_FMT1 "%llu" +#define BN_DEC_FMT2 "%019llu" +#define BN_DEC_NUM 19 +#endif + +#ifdef THIRTY_TWO_BIT +#ifdef BN_LLONG +# if defined(OPENSSL_SYS_WIN32) && !defined(__GNUC__) +# define BN_ULLONG unsigned __int64 +# else +# define BN_ULLONG unsigned long long +# endif +#endif +#define BN_ULONG unsigned long +#define BN_LONG long +#define BN_BITS 64 +#define BN_BYTES 4 +#define BN_BITS2 32 +#define BN_BITS4 16 +#ifdef OPENSSL_SYS_WIN32 +/* VC++ doesn't like the LL suffix */ +#define BN_MASK (0xffffffffffffffffL) +#else +#define BN_MASK (0xffffffffffffffffLL) +#endif +#define BN_MASK2 (0xffffffffL) +#define BN_MASK2l (0xffff) +#define BN_MASK2h1 (0xffff8000L) +#define BN_MASK2h (0xffff0000L) +#define BN_TBIT (0x80000000L) +#define BN_DEC_CONV (1000000000L) +#define BN_DEC_FMT1 "%lu" +#define BN_DEC_FMT2 "%09lu" +#define BN_DEC_NUM 9 +#endif + +#ifdef SIXTEEN_BIT +#ifndef BN_DIV2W +#define BN_DIV2W +#endif +#define BN_ULLONG unsigned long +#define BN_ULONG unsigned short +#define BN_LONG short +#define BN_BITS 32 +#define BN_BYTES 2 +#define BN_BITS2 16 +#define BN_BITS4 8 +#define BN_MASK (0xffffffff) +#define BN_MASK2 (0xffff) +#define BN_MASK2l (0xff) +#define BN_MASK2h1 (0xff80) +#define BN_MASK2h (0xff00) +#define BN_TBIT (0x8000) +#define BN_DEC_CONV (100000) +#define BN_DEC_FMT1 "%u" +#define BN_DEC_FMT2 "%05u" +#define BN_DEC_NUM 5 +#endif + +#ifdef EIGHT_BIT +#ifndef BN_DIV2W +#define BN_DIV2W +#endif +#define BN_ULLONG unsigned short +#define BN_ULONG unsigned char +#define BN_LONG char +#define BN_BITS 16 +#define BN_BYTES 1 +#define BN_BITS2 8 +#define BN_BITS4 4 +#define BN_MASK (0xffff) +#define BN_MASK2 (0xff) +#define BN_MASK2l (0xf) +#define BN_MASK2h1 (0xf8) +#define BN_MASK2h (0xf0) +#define BN_TBIT (0x80) +#define BN_DEC_CONV (100) +#define BN_DEC_FMT1 "%u" +#define BN_DEC_FMT2 "%02u" +#define BN_DEC_NUM 2 +#endif + +#define BN_DEFAULT_BITS 1280 + +#define BN_FLG_MALLOCED 0x01 +#define BN_FLG_STATIC_DATA 0x02 +#define BN_FLG_CONSTTIME 0x04 /* avoid leaking exponent information through timing, + * BN_mod_exp_mont() will call BN_mod_exp_mont_consttime, + * BN_div() will call BN_div_no_branch, + * BN_mod_inverse() will call BN_mod_inverse_no_branch. + */ + +#ifndef OPENSSL_NO_DEPRECATED +#define BN_FLG_EXP_CONSTTIME BN_FLG_CONSTTIME /* deprecated name for the flag */ + /* avoid leaking exponent information through timings + * (BN_mod_exp_mont() will call BN_mod_exp_mont_consttime) */ +#endif + +#ifndef OPENSSL_NO_DEPRECATED +#define BN_FLG_FREE 0x8000 /* used for debuging */ +#endif +#define BN_set_flags(b,n) ((b)->flags|=(n)) +#define BN_get_flags(b,n) ((b)->flags&(n)) + +/* get a clone of a BIGNUM with changed flags, for *temporary* use only + * (the two BIGNUMs cannot not be used in parallel!) */ +#define BN_with_flags(dest,b,n) ((dest)->d=(b)->d, \ + (dest)->top=(b)->top, \ + (dest)->dmax=(b)->dmax, \ + (dest)->neg=(b)->neg, \ + (dest)->flags=(((dest)->flags & BN_FLG_MALLOCED) \ + | ((b)->flags & ~BN_FLG_MALLOCED) \ + | BN_FLG_STATIC_DATA \ + | (n))) + +/* Already declared in ossl_typ.h */ +#if 0 +typedef struct bignum_st BIGNUM; +/* Used for temp variables (declaration hidden in bn_lcl.h) */ +typedef struct bignum_ctx BN_CTX; +typedef struct bn_blinding_st BN_BLINDING; +typedef struct bn_mont_ctx_st BN_MONT_CTX; +typedef struct bn_recp_ctx_st BN_RECP_CTX; +typedef struct bn_gencb_st BN_GENCB; +#endif + +struct bignum_st + { + BN_ULONG *d; /* Pointer to an array of 'BN_BITS2' bit chunks. */ + int top; /* Index of last used d +1. */ + /* The next are internal book keeping for bn_expand. */ + int dmax; /* Size of the d array. */ + int neg; /* one if the number is negative */ + int flags; + }; + +/* Used for montgomery multiplication */ +struct bn_mont_ctx_st + { + int ri; /* number of bits in R */ + BIGNUM RR; /* used to convert to montgomery form */ + BIGNUM N; /* The modulus */ + BIGNUM Ni; /* R*(1/R mod N) - N*Ni = 1 + * (Ni is only stored for bignum algorithm) */ +#if 0 + /* OpenSSL 0.9.9 preview: */ + BN_ULONG n0[2];/* least significant word(s) of Ni */ +#else + BN_ULONG n0; /* least significant word of Ni */ +#endif + int flags; + }; + +/* Used for reciprocal division/mod functions + * It cannot be shared between threads + */ +struct bn_recp_ctx_st + { + BIGNUM N; /* the divisor */ + BIGNUM Nr; /* the reciprocal */ + int num_bits; + int shift; + int flags; + }; + +/* Used for slow "generation" functions. */ +struct bn_gencb_st + { + unsigned int ver; /* To handle binary (in)compatibility */ + void *arg; /* callback-specific data */ + union + { + /* if(ver==1) - handles old style callbacks */ + void (*cb_1)(int, int, void *); + /* if(ver==2) - new callback style */ + int (*cb_2)(int, int, BN_GENCB *); + } cb; + }; +/* Wrapper function to make using BN_GENCB easier, */ +int BN_GENCB_call(BN_GENCB *cb, int a, int b); +/* Macro to populate a BN_GENCB structure with an "old"-style callback */ +#define BN_GENCB_set_old(gencb, callback, cb_arg) { \ + BN_GENCB *tmp_gencb = (gencb); \ + tmp_gencb->ver = 1; \ + tmp_gencb->arg = (cb_arg); \ + tmp_gencb->cb.cb_1 = (callback); } +/* Macro to populate a BN_GENCB structure with a "new"-style callback */ +#define BN_GENCB_set(gencb, callback, cb_arg) { \ + BN_GENCB *tmp_gencb = (gencb); \ + tmp_gencb->ver = 2; \ + tmp_gencb->arg = (cb_arg); \ + tmp_gencb->cb.cb_2 = (callback); } + +#define BN_prime_checks 0 /* default: select number of iterations + based on the size of the number */ + +/* number of Miller-Rabin iterations for an error rate of less than 2^-80 + * for random 'b'-bit input, b >= 100 (taken from table 4.4 in the Handbook + * of Applied Cryptography [Menezes, van Oorschot, Vanstone; CRC Press 1996]; + * original paper: Damgaard, Landrock, Pomerance: Average case error estimates + * for the strong probable prime test. -- Math. Comp. 61 (1993) 177-194) */ +#define BN_prime_checks_for_size(b) ((b) >= 1300 ? 2 : \ + (b) >= 850 ? 3 : \ + (b) >= 650 ? 4 : \ + (b) >= 550 ? 5 : \ + (b) >= 450 ? 6 : \ + (b) >= 400 ? 7 : \ + (b) >= 350 ? 8 : \ + (b) >= 300 ? 9 : \ + (b) >= 250 ? 12 : \ + (b) >= 200 ? 15 : \ + (b) >= 150 ? 18 : \ + /* b >= 100 */ 27) + +#define BN_num_bytes(a) ((BN_num_bits(a)+7)/8) + +/* Note that BN_abs_is_word didn't work reliably for w == 0 until 0.9.8 */ +#define BN_abs_is_word(a,w) ((((a)->top == 1) && ((a)->d[0] == (BN_ULONG)(w))) || \ + (((w) == 0) && ((a)->top == 0))) +#define BN_is_zero(a) ((a)->top == 0) +#define BN_is_one(a) (BN_abs_is_word((a),1) && !(a)->neg) +#define BN_is_word(a,w) (BN_abs_is_word((a),(w)) && (!(w) || !(a)->neg)) +#define BN_is_odd(a) (((a)->top > 0) && ((a)->d[0] & 1)) + +#define BN_one(a) (BN_set_word((a),1)) +#define BN_zero_ex(a) \ + do { \ + BIGNUM *_tmp_bn = (a); \ + _tmp_bn->top = 0; \ + _tmp_bn->neg = 0; \ + } while(0) +#ifdef OPENSSL_NO_DEPRECATED +#define BN_zero(a) BN_zero_ex(a) +#else +#define BN_zero(a) (BN_set_word((a),0)) +#endif + +const BIGNUM *BN_value_one(void); +char * BN_options(void); +BN_CTX *BN_CTX_new(void); +#ifndef OPENSSL_NO_DEPRECATED +void BN_CTX_init(BN_CTX *c); +#endif +void BN_CTX_free(BN_CTX *c); +void BN_CTX_start(BN_CTX *ctx); +BIGNUM *BN_CTX_get(BN_CTX *ctx); +void BN_CTX_end(BN_CTX *ctx); +int BN_rand(BIGNUM *rnd, int bits, int top,int bottom); +int BN_pseudo_rand(BIGNUM *rnd, int bits, int top,int bottom); +int BN_rand_range(BIGNUM *rnd, BIGNUM *range); +int BN_pseudo_rand_range(BIGNUM *rnd, BIGNUM *range); +int BN_num_bits(const BIGNUM *a); +int BN_num_bits_word(BN_ULONG); +BIGNUM *BN_new(void); +void BN_init(BIGNUM *); +void BN_clear_free(BIGNUM *a); +BIGNUM *BN_copy(BIGNUM *a, const BIGNUM *b); +void BN_swap(BIGNUM *a, BIGNUM *b); +BIGNUM *BN_bin2bn(const unsigned char *s,int len,BIGNUM *ret); +int BN_bn2bin(const BIGNUM *a, unsigned char *to); +BIGNUM *BN_mpi2bn(const unsigned char *s,int len,BIGNUM *ret); +int BN_bn2mpi(const BIGNUM *a, unsigned char *to); +int BN_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b); +int BN_usub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b); +int BN_uadd(BIGNUM *r, const BIGNUM *a, const BIGNUM *b); +int BN_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b); +int BN_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx); +int BN_sqr(BIGNUM *r, const BIGNUM *a,BN_CTX *ctx); +/** BN_set_negative sets sign of a BIGNUM + * \param b pointer to the BIGNUM object + * \param n 0 if the BIGNUM b should be positive and a value != 0 otherwise + */ +void BN_set_negative(BIGNUM *b, int n); +/** BN_is_negative returns 1 if the BIGNUM is negative + * \param a pointer to the BIGNUM object + * \return 1 if a < 0 and 0 otherwise + */ +#define BN_is_negative(a) ((a)->neg != 0) + +int BN_div(BIGNUM *dv, BIGNUM *rem, const BIGNUM *m, const BIGNUM *d, + BN_CTX *ctx); +#define BN_mod(rem,m,d,ctx) BN_div(NULL,(rem),(m),(d),(ctx)) +int BN_nnmod(BIGNUM *r, const BIGNUM *m, const BIGNUM *d, BN_CTX *ctx); +int BN_mod_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m, BN_CTX *ctx); +int BN_mod_add_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m); +int BN_mod_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m, BN_CTX *ctx); +int BN_mod_sub_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m); +int BN_mod_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, + const BIGNUM *m, BN_CTX *ctx); +int BN_mod_sqr(BIGNUM *r, const BIGNUM *a, const BIGNUM *m, BN_CTX *ctx); +int BN_mod_lshift1(BIGNUM *r, const BIGNUM *a, const BIGNUM *m, BN_CTX *ctx); +int BN_mod_lshift1_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *m); +int BN_mod_lshift(BIGNUM *r, const BIGNUM *a, int n, const BIGNUM *m, BN_CTX *ctx); +int BN_mod_lshift_quick(BIGNUM *r, const BIGNUM *a, int n, const BIGNUM *m); + +BN_ULONG BN_mod_word(const BIGNUM *a, BN_ULONG w); +BN_ULONG BN_div_word(BIGNUM *a, BN_ULONG w); +int BN_mul_word(BIGNUM *a, BN_ULONG w); +int BN_add_word(BIGNUM *a, BN_ULONG w); +int BN_sub_word(BIGNUM *a, BN_ULONG w); +int BN_set_word(BIGNUM *a, BN_ULONG w); +BN_ULONG BN_get_word(const BIGNUM *a); + +int BN_cmp(const BIGNUM *a, const BIGNUM *b); +void BN_free(BIGNUM *a); +int BN_is_bit_set(const BIGNUM *a, int n); +int BN_lshift(BIGNUM *r, const BIGNUM *a, int n); +int BN_lshift1(BIGNUM *r, const BIGNUM *a); +int BN_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,BN_CTX *ctx); + +int BN_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m,BN_CTX *ctx); +int BN_mod_exp_mont(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx); +int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *in_mont); +int BN_mod_exp_mont_word(BIGNUM *r, BN_ULONG a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx); +int BN_mod_exp2_mont(BIGNUM *r, const BIGNUM *a1, const BIGNUM *p1, + const BIGNUM *a2, const BIGNUM *p2,const BIGNUM *m, + BN_CTX *ctx,BN_MONT_CTX *m_ctx); +int BN_mod_exp_simple(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m,BN_CTX *ctx); + +int BN_mask_bits(BIGNUM *a,int n); +#ifndef OPENSSL_NO_FP_API +int BN_print_fp(FILE *fp, const BIGNUM *a); +#endif +#ifdef HEADER_BIO_H +int BN_print(BIO *fp, const BIGNUM *a); +#else +int BN_print(void *fp, const BIGNUM *a); +#endif +int BN_reciprocal(BIGNUM *r, const BIGNUM *m, int len, BN_CTX *ctx); +int BN_rshift(BIGNUM *r, const BIGNUM *a, int n); +int BN_rshift1(BIGNUM *r, const BIGNUM *a); +void BN_clear(BIGNUM *a); +BIGNUM *BN_dup(const BIGNUM *a); +int BN_ucmp(const BIGNUM *a, const BIGNUM *b); +int BN_set_bit(BIGNUM *a, int n); +int BN_clear_bit(BIGNUM *a, int n); +char * BN_bn2hex(const BIGNUM *a); +char * BN_bn2dec(const BIGNUM *a); +int BN_hex2bn(BIGNUM **a, const char *str); +int BN_dec2bn(BIGNUM **a, const char *str); +int BN_gcd(BIGNUM *r,const BIGNUM *a,const BIGNUM *b,BN_CTX *ctx); +int BN_kronecker(const BIGNUM *a,const BIGNUM *b,BN_CTX *ctx); /* returns -2 for error */ +BIGNUM *BN_mod_inverse(BIGNUM *ret, + const BIGNUM *a, const BIGNUM *n,BN_CTX *ctx); +BIGNUM *BN_mod_sqrt(BIGNUM *ret, + const BIGNUM *a, const BIGNUM *n,BN_CTX *ctx); + +/* Deprecated versions */ +#ifndef OPENSSL_NO_DEPRECATED +BIGNUM *BN_generate_prime(BIGNUM *ret,int bits,int safe, + const BIGNUM *add, const BIGNUM *rem, + void (*callback)(int,int,void *),void *cb_arg); +int BN_is_prime(const BIGNUM *p,int nchecks, + void (*callback)(int,int,void *), + BN_CTX *ctx,void *cb_arg); +int BN_is_prime_fasttest(const BIGNUM *p,int nchecks, + void (*callback)(int,int,void *),BN_CTX *ctx,void *cb_arg, + int do_trial_division); +#endif /* !defined(OPENSSL_NO_DEPRECATED) */ + +/* Newer versions */ +int BN_generate_prime_ex(BIGNUM *ret,int bits,int safe, const BIGNUM *add, + const BIGNUM *rem, BN_GENCB *cb); +int BN_is_prime_ex(const BIGNUM *p,int nchecks, BN_CTX *ctx, BN_GENCB *cb); +int BN_is_prime_fasttest_ex(const BIGNUM *p,int nchecks, BN_CTX *ctx, + int do_trial_division, BN_GENCB *cb); + +BN_MONT_CTX *BN_MONT_CTX_new(void ); +void BN_MONT_CTX_init(BN_MONT_CTX *ctx); +int BN_mod_mul_montgomery(BIGNUM *r,const BIGNUM *a,const BIGNUM *b, + BN_MONT_CTX *mont, BN_CTX *ctx); +#define BN_to_montgomery(r,a,mont,ctx) BN_mod_mul_montgomery(\ + (r),(a),&((mont)->RR),(mont),(ctx)) +int BN_from_montgomery(BIGNUM *r,const BIGNUM *a, + BN_MONT_CTX *mont, BN_CTX *ctx); +void BN_MONT_CTX_free(BN_MONT_CTX *mont); +int BN_MONT_CTX_set(BN_MONT_CTX *mont,const BIGNUM *mod,BN_CTX *ctx); +BN_MONT_CTX *BN_MONT_CTX_copy(BN_MONT_CTX *to,BN_MONT_CTX *from); +BN_MONT_CTX *BN_MONT_CTX_set_locked(BN_MONT_CTX **pmont, int lock, + const BIGNUM *mod, BN_CTX *ctx); + +/* BN_BLINDING flags */ +#define BN_BLINDING_NO_UPDATE 0x00000001 +#define BN_BLINDING_NO_RECREATE 0x00000002 + +BN_BLINDING *BN_BLINDING_new(const BIGNUM *A, const BIGNUM *Ai, /* const */ BIGNUM *mod); +void BN_BLINDING_free(BN_BLINDING *b); +int BN_BLINDING_update(BN_BLINDING *b,BN_CTX *ctx); +int BN_BLINDING_convert(BIGNUM *n, BN_BLINDING *b, BN_CTX *ctx); +int BN_BLINDING_invert(BIGNUM *n, BN_BLINDING *b, BN_CTX *ctx); +int BN_BLINDING_convert_ex(BIGNUM *n, BIGNUM *r, BN_BLINDING *b, BN_CTX *); +int BN_BLINDING_invert_ex(BIGNUM *n, const BIGNUM *r, BN_BLINDING *b, BN_CTX *); +unsigned long BN_BLINDING_get_thread_id(const BN_BLINDING *); +void BN_BLINDING_set_thread_id(BN_BLINDING *, unsigned long); +unsigned long BN_BLINDING_get_flags(const BN_BLINDING *); +void BN_BLINDING_set_flags(BN_BLINDING *, unsigned long); +BN_BLINDING *BN_BLINDING_create_param(BN_BLINDING *b, + const BIGNUM *e, /* const */ BIGNUM *m, BN_CTX *ctx, + int (*bn_mod_exp)(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx), + BN_MONT_CTX *m_ctx); + +#ifndef OPENSSL_NO_DEPRECATED +void BN_set_params(int mul,int high,int low,int mont); +int BN_get_params(int which); /* 0, mul, 1 high, 2 low, 3 mont */ +#endif + +void BN_RECP_CTX_init(BN_RECP_CTX *recp); +BN_RECP_CTX *BN_RECP_CTX_new(void); +void BN_RECP_CTX_free(BN_RECP_CTX *recp); +int BN_RECP_CTX_set(BN_RECP_CTX *recp,const BIGNUM *rdiv,BN_CTX *ctx); +int BN_mod_mul_reciprocal(BIGNUM *r, const BIGNUM *x, const BIGNUM *y, + BN_RECP_CTX *recp,BN_CTX *ctx); +int BN_mod_exp_recp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx); +int BN_div_recp(BIGNUM *dv, BIGNUM *rem, const BIGNUM *m, + BN_RECP_CTX *recp, BN_CTX *ctx); + +/* Functions for arithmetic over binary polynomials represented by BIGNUMs. + * + * The BIGNUM::neg property of BIGNUMs representing binary polynomials is + * ignored. + * + * Note that input arguments are not const so that their bit arrays can + * be expanded to the appropriate size if needed. + */ + +int BN_GF2m_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b); /*r = a + b*/ +#define BN_GF2m_sub(r, a, b) BN_GF2m_add(r, a, b) +int BN_GF2m_mod(BIGNUM *r, const BIGNUM *a, const BIGNUM *p); /*r=a mod p*/ +int BN_GF2m_mod_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, + const BIGNUM *p, BN_CTX *ctx); /* r = (a * b) mod p */ +int BN_GF2m_mod_sqr(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + BN_CTX *ctx); /* r = (a * a) mod p */ +int BN_GF2m_mod_inv(BIGNUM *r, const BIGNUM *b, const BIGNUM *p, + BN_CTX *ctx); /* r = (1 / b) mod p */ +int BN_GF2m_mod_div(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, + const BIGNUM *p, BN_CTX *ctx); /* r = (a / b) mod p */ +int BN_GF2m_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, + const BIGNUM *p, BN_CTX *ctx); /* r = (a ^ b) mod p */ +int BN_GF2m_mod_sqrt(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + BN_CTX *ctx); /* r = sqrt(a) mod p */ +int BN_GF2m_mod_solve_quad(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + BN_CTX *ctx); /* r^2 + r = a mod p */ +#define BN_GF2m_cmp(a, b) BN_ucmp((a), (b)) +/* Some functions allow for representation of the irreducible polynomials + * as an unsigned int[], say p. The irreducible f(t) is then of the form: + * t^p[0] + t^p[1] + ... + t^p[k] + * where m = p[0] > p[1] > ... > p[k] = 0. + */ +int BN_GF2m_mod_arr(BIGNUM *r, const BIGNUM *a, const unsigned int p[]); + /* r = a mod p */ +int BN_GF2m_mod_mul_arr(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, + const unsigned int p[], BN_CTX *ctx); /* r = (a * b) mod p */ +int BN_GF2m_mod_sqr_arr(BIGNUM *r, const BIGNUM *a, const unsigned int p[], + BN_CTX *ctx); /* r = (a * a) mod p */ +int BN_GF2m_mod_inv_arr(BIGNUM *r, const BIGNUM *b, const unsigned int p[], + BN_CTX *ctx); /* r = (1 / b) mod p */ +int BN_GF2m_mod_div_arr(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, + const unsigned int p[], BN_CTX *ctx); /* r = (a / b) mod p */ +int BN_GF2m_mod_exp_arr(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, + const unsigned int p[], BN_CTX *ctx); /* r = (a ^ b) mod p */ +int BN_GF2m_mod_sqrt_arr(BIGNUM *r, const BIGNUM *a, + const unsigned int p[], BN_CTX *ctx); /* r = sqrt(a) mod p */ +int BN_GF2m_mod_solve_quad_arr(BIGNUM *r, const BIGNUM *a, + const unsigned int p[], BN_CTX *ctx); /* r^2 + r = a mod p */ +int BN_GF2m_poly2arr(const BIGNUM *a, unsigned int p[], int max); +int BN_GF2m_arr2poly(const unsigned int p[], BIGNUM *a); + +/* faster mod functions for the 'NIST primes' + * 0 <= a < p^2 */ +int BN_nist_mod_192(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx); +int BN_nist_mod_224(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx); +int BN_nist_mod_256(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx); +int BN_nist_mod_384(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx); +int BN_nist_mod_521(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx); + +const BIGNUM *BN_get0_nist_prime_192(void); +const BIGNUM *BN_get0_nist_prime_224(void); +const BIGNUM *BN_get0_nist_prime_256(void); +const BIGNUM *BN_get0_nist_prime_384(void); +const BIGNUM *BN_get0_nist_prime_521(void); + +/* library internal functions */ + +#define bn_expand(a,bits) ((((((bits+BN_BITS2-1))/BN_BITS2)) <= (a)->dmax)?\ + (a):bn_expand2((a),(bits+BN_BITS2-1)/BN_BITS2)) +#define bn_wexpand(a,words) (((words) <= (a)->dmax)?(a):bn_expand2((a),(words))) +BIGNUM *bn_expand2(BIGNUM *a, int words); +#ifndef OPENSSL_NO_DEPRECATED +BIGNUM *bn_dup_expand(const BIGNUM *a, int words); /* unused */ +#endif + +/* Bignum consistency macros + * There is one "API" macro, bn_fix_top(), for stripping leading zeroes from + * bignum data after direct manipulations on the data. There is also an + * "internal" macro, bn_check_top(), for verifying that there are no leading + * zeroes. Unfortunately, some auditing is required due to the fact that + * bn_fix_top() has become an overabused duct-tape because bignum data is + * occasionally passed around in an inconsistent state. So the following + * changes have been made to sort this out; + * - bn_fix_top()s implementation has been moved to bn_correct_top() + * - if BN_DEBUG isn't defined, bn_fix_top() maps to bn_correct_top(), and + * bn_check_top() is as before. + * - if BN_DEBUG *is* defined; + * - bn_check_top() tries to pollute unused words even if the bignum 'top' is + * consistent. (ed: only if BN_DEBUG_RAND is defined) + * - bn_fix_top() maps to bn_check_top() rather than "fixing" anything. + * The idea is to have debug builds flag up inconsistent bignums when they + * occur. If that occurs in a bn_fix_top(), we examine the code in question; if + * the use of bn_fix_top() was appropriate (ie. it follows directly after code + * that manipulates the bignum) it is converted to bn_correct_top(), and if it + * was not appropriate, we convert it permanently to bn_check_top() and track + * down the cause of the bug. Eventually, no internal code should be using the + * bn_fix_top() macro. External applications and libraries should try this with + * their own code too, both in terms of building against the openssl headers + * with BN_DEBUG defined *and* linking with a version of OpenSSL built with it + * defined. This not only improves external code, it provides more test + * coverage for openssl's own code. + */ + +#ifdef BN_DEBUG + +/* We only need assert() when debugging */ +#include + +#ifdef BN_DEBUG_RAND +/* To avoid "make update" cvs wars due to BN_DEBUG, use some tricks */ +#ifndef RAND_pseudo_bytes +int RAND_pseudo_bytes(unsigned char *buf,int num); +#define BN_DEBUG_TRIX +#endif +#define bn_pollute(a) \ + do { \ + const BIGNUM *_bnum1 = (a); \ + if(_bnum1->top < _bnum1->dmax) { \ + unsigned char _tmp_char; \ + /* We cast away const without the compiler knowing, any \ + * *genuinely* constant variables that aren't mutable \ + * wouldn't be constructed with top!=dmax. */ \ + BN_ULONG *_not_const; \ + memcpy(&_not_const, &_bnum1->d, sizeof(BN_ULONG*)); \ + RAND_pseudo_bytes(&_tmp_char, 1); \ + memset((unsigned char *)(_not_const + _bnum1->top), _tmp_char, \ + (_bnum1->dmax - _bnum1->top) * sizeof(BN_ULONG)); \ + } \ + } while(0) +#ifdef BN_DEBUG_TRIX +#undef RAND_pseudo_bytes +#endif +#else +#define bn_pollute(a) +#endif +#define bn_check_top(a) \ + do { \ + const BIGNUM *_bnum2 = (a); \ + if (_bnum2 != NULL) { \ + assert((_bnum2->top == 0) || \ + (_bnum2->d[_bnum2->top - 1] != 0)); \ + bn_pollute(_bnum2); \ + } \ + } while(0) + +#define bn_fix_top(a) bn_check_top(a) + +#else /* !BN_DEBUG */ + +#define bn_pollute(a) +#define bn_check_top(a) +#define bn_fix_top(a) bn_correct_top(a) + +#endif + +#define bn_correct_top(a) \ + { \ + BN_ULONG *ftl; \ + if ((a)->top > 0) \ + { \ + for (ftl= &((a)->d[(a)->top-1]); (a)->top > 0; (a)->top--) \ + if (*(ftl--)) break; \ + } \ + bn_pollute(a); \ + } + +BN_ULONG bn_mul_add_words(BN_ULONG *rp, const BN_ULONG *ap, int num, BN_ULONG w); +BN_ULONG bn_mul_words(BN_ULONG *rp, const BN_ULONG *ap, int num, BN_ULONG w); +void bn_sqr_words(BN_ULONG *rp, const BN_ULONG *ap, int num); +BN_ULONG bn_div_words(BN_ULONG h, BN_ULONG l, BN_ULONG d); +BN_ULONG bn_add_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,int num); +BN_ULONG bn_sub_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,int num); + +/* Primes from RFC 2409 */ +BIGNUM *get_rfc2409_prime_768(BIGNUM *bn); +BIGNUM *get_rfc2409_prime_1024(BIGNUM *bn); + +/* Primes from RFC 3526 */ +BIGNUM *get_rfc3526_prime_1536(BIGNUM *bn); +BIGNUM *get_rfc3526_prime_2048(BIGNUM *bn); +BIGNUM *get_rfc3526_prime_3072(BIGNUM *bn); +BIGNUM *get_rfc3526_prime_4096(BIGNUM *bn); +BIGNUM *get_rfc3526_prime_6144(BIGNUM *bn); +BIGNUM *get_rfc3526_prime_8192(BIGNUM *bn); + +int BN_bntest_rand(BIGNUM *rnd, int bits, int top,int bottom); + +/* BEGIN ERROR CODES */ +/* The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ +void ERR_load_BN_strings(void); + +/* Error codes for the BN functions. */ + +/* Function codes. */ +#define BN_F_BNRAND 127 +#define BN_F_BN_BLINDING_CONVERT_EX 100 +#define BN_F_BN_BLINDING_CREATE_PARAM 128 +#define BN_F_BN_BLINDING_INVERT_EX 101 +#define BN_F_BN_BLINDING_NEW 102 +#define BN_F_BN_BLINDING_UPDATE 103 +#define BN_F_BN_BN2DEC 104 +#define BN_F_BN_BN2HEX 105 +#define BN_F_BN_CTX_GET 116 +#define BN_F_BN_CTX_NEW 106 +#define BN_F_BN_CTX_START 129 +#define BN_F_BN_DIV 107 +#define BN_F_BN_DIV_NO_BRANCH 138 +#define BN_F_BN_DIV_RECP 130 +#define BN_F_BN_EXP 123 +#define BN_F_BN_EXPAND2 108 +#define BN_F_BN_EXPAND_INTERNAL 120 +#define BN_F_BN_GF2M_MOD 131 +#define BN_F_BN_GF2M_MOD_EXP 132 +#define BN_F_BN_GF2M_MOD_MUL 133 +#define BN_F_BN_GF2M_MOD_SOLVE_QUAD 134 +#define BN_F_BN_GF2M_MOD_SOLVE_QUAD_ARR 135 +#define BN_F_BN_GF2M_MOD_SQR 136 +#define BN_F_BN_GF2M_MOD_SQRT 137 +#define BN_F_BN_MOD_EXP2_MONT 118 +#define BN_F_BN_MOD_EXP_MONT 109 +#define BN_F_BN_MOD_EXP_MONT_CONSTTIME 124 +#define BN_F_BN_MOD_EXP_MONT_WORD 117 +#define BN_F_BN_MOD_EXP_RECP 125 +#define BN_F_BN_MOD_EXP_SIMPLE 126 +#define BN_F_BN_MOD_INVERSE 110 +#define BN_F_BN_MOD_INVERSE_NO_BRANCH 139 +#define BN_F_BN_MOD_LSHIFT_QUICK 119 +#define BN_F_BN_MOD_MUL_RECIPROCAL 111 +#define BN_F_BN_MOD_SQRT 121 +#define BN_F_BN_MPI2BN 112 +#define BN_F_BN_NEW 113 +#define BN_F_BN_RAND 114 +#define BN_F_BN_RAND_RANGE 122 +#define BN_F_BN_USUB 115 + +/* Reason codes. */ +#define BN_R_ARG2_LT_ARG3 100 +#define BN_R_BAD_RECIPROCAL 101 +#define BN_R_BIGNUM_TOO_LONG 114 +#define BN_R_CALLED_WITH_EVEN_MODULUS 102 +#define BN_R_DIV_BY_ZERO 103 +#define BN_R_ENCODING_ERROR 104 +#define BN_R_EXPAND_ON_STATIC_BIGNUM_DATA 105 +#define BN_R_INPUT_NOT_REDUCED 110 +#define BN_R_INVALID_LENGTH 106 +#define BN_R_INVALID_RANGE 115 +#define BN_R_NOT_A_SQUARE 111 +#define BN_R_NOT_INITIALIZED 107 +#define BN_R_NO_INVERSE 108 +#define BN_R_NO_SOLUTION 116 +#define BN_R_P_IS_NOT_PRIME 112 +#define BN_R_TOO_MANY_ITERATIONS 113 +#define BN_R_TOO_MANY_TEMPORARY_VARIABLES 109 + +#ifdef __cplusplus +} +#endif +#endif diff --git a/lib_tls/include/openssl/buffer.h b/lib_tls/include/openssl/buffer.h new file mode 100644 index 000000000..1db960745 --- /dev/null +++ b/lib_tls/include/openssl/buffer.h @@ -0,0 +1,118 @@ +/* crypto/buffer/buffer.h */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#ifndef HEADER_BUFFER_H +#define HEADER_BUFFER_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#if !defined(NO_SYS_TYPES_H) +#include +#endif + +/* Already declared in ossl_typ.h */ +/* typedef struct buf_mem_st BUF_MEM; */ + +struct buf_mem_st + { + int length; /* current number of bytes */ + char *data; + int max; /* size of buffer */ + }; + +BUF_MEM *BUF_MEM_new(void); +void BUF_MEM_free(BUF_MEM *a); +int BUF_MEM_grow(BUF_MEM *str, int len); +int BUF_MEM_grow_clean(BUF_MEM *str, int len); +char * BUF_strdup(const char *str); +char * BUF_strndup(const char *str, size_t siz); +void * BUF_memdup(const void *data, size_t siz); + +/* safe string functions */ +size_t BUF_strlcpy(char *dst,const char *src,size_t siz); +size_t BUF_strlcat(char *dst,const char *src,size_t siz); + + +/* BEGIN ERROR CODES */ +/* The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ +void ERR_load_BUF_strings(void); + +/* Error codes for the BUF functions. */ + +/* Function codes. */ +#define BUF_F_BUF_MEMDUP 103 +#define BUF_F_BUF_MEM_GROW 100 +#define BUF_F_BUF_MEM_GROW_CLEAN 105 +#define BUF_F_BUF_MEM_NEW 101 +#define BUF_F_BUF_STRDUP 102 +#define BUF_F_BUF_STRNDUP 104 + +/* Reason codes. */ + +#ifdef __cplusplus +} +#endif +#endif diff --git a/lib_tls/include/openssl/cast.h b/lib_tls/include/openssl/cast.h new file mode 100644 index 000000000..90b45b950 --- /dev/null +++ b/lib_tls/include/openssl/cast.h @@ -0,0 +1,105 @@ +/* crypto/cast/cast.h */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#ifndef HEADER_CAST_H +#define HEADER_CAST_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#ifdef OPENSSL_NO_CAST +#error CAST is disabled. +#endif + +#define CAST_ENCRYPT 1 +#define CAST_DECRYPT 0 + +#define CAST_LONG unsigned long + +#define CAST_BLOCK 8 +#define CAST_KEY_LENGTH 16 + +typedef struct cast_key_st + { + CAST_LONG data[32]; + int short_key; /* Use reduced rounds for short key */ + } CAST_KEY; + + +void CAST_set_key(CAST_KEY *key, int len, const unsigned char *data); +void CAST_ecb_encrypt(const unsigned char *in,unsigned char *out,CAST_KEY *key, + int enc); +void CAST_encrypt(CAST_LONG *data,CAST_KEY *key); +void CAST_decrypt(CAST_LONG *data,CAST_KEY *key); +void CAST_cbc_encrypt(const unsigned char *in, unsigned char *out, long length, + CAST_KEY *ks, unsigned char *iv, int enc); +void CAST_cfb64_encrypt(const unsigned char *in, unsigned char *out, + long length, CAST_KEY *schedule, unsigned char *ivec, + int *num, int enc); +void CAST_ofb64_encrypt(const unsigned char *in, unsigned char *out, + long length, CAST_KEY *schedule, unsigned char *ivec, + int *num); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_tls/include/openssl/comp.h b/lib_tls/include/openssl/comp.h new file mode 100644 index 000000000..4b405c7d4 --- /dev/null +++ b/lib_tls/include/openssl/comp.h @@ -0,0 +1,80 @@ + +#ifndef HEADER_COMP_H +#define HEADER_COMP_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct comp_ctx_st COMP_CTX; + +typedef struct comp_method_st + { + int type; /* NID for compression library */ + const char *name; /* A text string to identify the library */ + int (*init)(COMP_CTX *ctx); + void (*finish)(COMP_CTX *ctx); + int (*compress)(COMP_CTX *ctx, + unsigned char *out, unsigned int olen, + unsigned char *in, unsigned int ilen); + int (*expand)(COMP_CTX *ctx, + unsigned char *out, unsigned int olen, + unsigned char *in, unsigned int ilen); + /* The following two do NOTHING, but are kept for backward compatibility */ + long (*ctrl)(void); + long (*callback_ctrl)(void); + } COMP_METHOD; + +struct comp_ctx_st + { + COMP_METHOD *meth; + unsigned long compress_in; + unsigned long compress_out; + unsigned long expand_in; + unsigned long expand_out; + + CRYPTO_EX_DATA ex_data; + }; + + +COMP_CTX *COMP_CTX_new(COMP_METHOD *meth); +void COMP_CTX_free(COMP_CTX *ctx); +int COMP_compress_block(COMP_CTX *ctx, unsigned char *out, int olen, + unsigned char *in, int ilen); +int COMP_expand_block(COMP_CTX *ctx, unsigned char *out, int olen, + unsigned char *in, int ilen); +COMP_METHOD *COMP_rle(void ); +COMP_METHOD *COMP_zlib(void ); +void COMP_zlib_cleanup(void); + +#ifdef HEADER_BIO_H +#ifdef ZLIB +BIO_METHOD *BIO_f_zlib(void); +#endif +#endif + +/* BEGIN ERROR CODES */ +/* The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ +void ERR_load_COMP_strings(void); + +/* Error codes for the COMP functions. */ + +/* Function codes. */ +#define COMP_F_BIO_ZLIB_FLUSH 99 +#define COMP_F_BIO_ZLIB_NEW 100 +#define COMP_F_BIO_ZLIB_READ 101 +#define COMP_F_BIO_ZLIB_WRITE 102 + +/* Reason codes. */ +#define COMP_R_ZLIB_DEFLATE_ERROR 99 +#define COMP_R_ZLIB_INFLATE_ERROR 100 +#define COMP_R_ZLIB_NOT_SUPPORTED 101 + +#ifdef __cplusplus +} +#endif +#endif diff --git a/lib_tls/include/openssl/conf.h b/lib_tls/include/openssl/conf.h new file mode 100644 index 000000000..8aa06bc5e --- /dev/null +++ b/lib_tls/include/openssl/conf.h @@ -0,0 +1,254 @@ +/* crypto/conf/conf.h */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#ifndef HEADER_CONF_H +#define HEADER_CONF_H + +#include +#include +#include +#include +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct + { + char *section; + char *name; + char *value; + } CONF_VALUE; + +DECLARE_STACK_OF(CONF_VALUE) +DECLARE_STACK_OF(CONF_MODULE) +DECLARE_STACK_OF(CONF_IMODULE) + +struct conf_st; +struct conf_method_st; +typedef struct conf_method_st CONF_METHOD; + +struct conf_method_st + { + const char *name; + CONF *(*create)(CONF_METHOD *meth); + int (*init)(CONF *conf); + int (*destroy)(CONF *conf); + int (*destroy_data)(CONF *conf); + int (*load_bio)(CONF *conf, BIO *bp, long *eline); + int (*dump)(const CONF *conf, BIO *bp); + int (*is_number)(const CONF *conf, char c); + int (*to_int)(const CONF *conf, char c); + int (*load)(CONF *conf, const char *name, long *eline); + }; + +/* Module definitions */ + +typedef struct conf_imodule_st CONF_IMODULE; +typedef struct conf_module_st CONF_MODULE; + +/* DSO module function typedefs */ +typedef int conf_init_func(CONF_IMODULE *md, const CONF *cnf); +typedef void conf_finish_func(CONF_IMODULE *md); + +#define CONF_MFLAGS_IGNORE_ERRORS 0x1 +#define CONF_MFLAGS_IGNORE_RETURN_CODES 0x2 +#define CONF_MFLAGS_SILENT 0x4 +#define CONF_MFLAGS_NO_DSO 0x8 +#define CONF_MFLAGS_IGNORE_MISSING_FILE 0x10 +#define CONF_MFLAGS_DEFAULT_SECTION 0x20 + +int CONF_set_default_method(CONF_METHOD *meth); +void CONF_set_nconf(CONF *conf,LHASH *hash); +LHASH *CONF_load(LHASH *conf,const char *file,long *eline); +#ifndef OPENSSL_NO_FP_API +LHASH *CONF_load_fp(LHASH *conf, FILE *fp,long *eline); +#endif +LHASH *CONF_load_bio(LHASH *conf, BIO *bp,long *eline); +STACK_OF(CONF_VALUE) *CONF_get_section(LHASH *conf,const char *section); +char *CONF_get_string(LHASH *conf,const char *group,const char *name); +long CONF_get_number(LHASH *conf,const char *group,const char *name); +void CONF_free(LHASH *conf); +int CONF_dump_fp(LHASH *conf, FILE *out); +int CONF_dump_bio(LHASH *conf, BIO *out); + +void OPENSSL_config(const char *config_name); +void OPENSSL_no_config(void); + +/* New conf code. The semantics are different from the functions above. + If that wasn't the case, the above functions would have been replaced */ + +struct conf_st + { + CONF_METHOD *meth; + void *meth_data; + LHASH *data; + }; + +CONF *NCONF_new(CONF_METHOD *meth); +CONF_METHOD *NCONF_default(void); +CONF_METHOD *NCONF_WIN32(void); +#if 0 /* Just to give you an idea of what I have in mind */ +CONF_METHOD *NCONF_XML(void); +#endif +void NCONF_free(CONF *conf); +void NCONF_free_data(CONF *conf); + +int NCONF_load(CONF *conf,const char *file,long *eline); +#ifndef OPENSSL_NO_FP_API +int NCONF_load_fp(CONF *conf, FILE *fp,long *eline); +#endif +int NCONF_load_bio(CONF *conf, BIO *bp,long *eline); +STACK_OF(CONF_VALUE) *NCONF_get_section(const CONF *conf,const char *section); +char *NCONF_get_string(const CONF *conf,const char *group,const char *name); +int NCONF_get_number_e(const CONF *conf,const char *group,const char *name, + long *result); +int NCONF_dump_fp(const CONF *conf, FILE *out); +int NCONF_dump_bio(const CONF *conf, BIO *out); + +#if 0 /* The following function has no error checking, + and should therefore be avoided */ +long NCONF_get_number(CONF *conf,char *group,char *name); +#else +#define NCONF_get_number(c,g,n,r) NCONF_get_number_e(c,g,n,r) +#endif + +/* Module functions */ + +int CONF_modules_load(const CONF *cnf, const char *appname, + unsigned long flags); +int CONF_modules_load_file(const char *filename, const char *appname, + unsigned long flags); +void CONF_modules_unload(int all); +void CONF_modules_finish(void); +void CONF_modules_free(void); +int CONF_module_add(const char *name, conf_init_func *ifunc, + conf_finish_func *ffunc); + +const char *CONF_imodule_get_name(const CONF_IMODULE *md); +const char *CONF_imodule_get_value(const CONF_IMODULE *md); +void *CONF_imodule_get_usr_data(const CONF_IMODULE *md); +void CONF_imodule_set_usr_data(CONF_IMODULE *md, void *usr_data); +CONF_MODULE *CONF_imodule_get_module(const CONF_IMODULE *md); +unsigned long CONF_imodule_get_flags(const CONF_IMODULE *md); +void CONF_imodule_set_flags(CONF_IMODULE *md, unsigned long flags); +void *CONF_module_get_usr_data(CONF_MODULE *pmod); +void CONF_module_set_usr_data(CONF_MODULE *pmod, void *usr_data); + +char *CONF_get1_default_config_file(void); + +int CONF_parse_list(const char *list, int sep, int nospc, + int (*list_cb)(const char *elem, int len, void *usr), void *arg); + +void OPENSSL_load_builtin_modules(void); + +/* BEGIN ERROR CODES */ +/* The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ +void ERR_load_CONF_strings(void); + +/* Error codes for the CONF functions. */ + +/* Function codes. */ +#define CONF_F_CONF_DUMP_FP 104 +#define CONF_F_CONF_LOAD 100 +#define CONF_F_CONF_LOAD_BIO 102 +#define CONF_F_CONF_LOAD_FP 103 +#define CONF_F_CONF_MODULES_LOAD 116 +#define CONF_F_DEF_LOAD 120 +#define CONF_F_DEF_LOAD_BIO 121 +#define CONF_F_MODULE_INIT 115 +#define CONF_F_MODULE_LOAD_DSO 117 +#define CONF_F_MODULE_RUN 118 +#define CONF_F_NCONF_DUMP_BIO 105 +#define CONF_F_NCONF_DUMP_FP 106 +#define CONF_F_NCONF_GET_NUMBER 107 +#define CONF_F_NCONF_GET_NUMBER_E 112 +#define CONF_F_NCONF_GET_SECTION 108 +#define CONF_F_NCONF_GET_STRING 109 +#define CONF_F_NCONF_LOAD 113 +#define CONF_F_NCONF_LOAD_BIO 110 +#define CONF_F_NCONF_LOAD_FP 114 +#define CONF_F_NCONF_NEW 111 +#define CONF_F_STR_COPY 101 + +/* Reason codes. */ +#define CONF_R_ERROR_LOADING_DSO 110 +#define CONF_R_MISSING_CLOSE_SQUARE_BRACKET 100 +#define CONF_R_MISSING_EQUAL_SIGN 101 +#define CONF_R_MISSING_FINISH_FUNCTION 111 +#define CONF_R_MISSING_INIT_FUNCTION 112 +#define CONF_R_MODULE_INITIALIZATION_ERROR 109 +#define CONF_R_NO_CLOSE_BRACE 102 +#define CONF_R_NO_CONF 105 +#define CONF_R_NO_CONF_OR_ENVIRONMENT_VARIABLE 106 +#define CONF_R_NO_SECTION 107 +#define CONF_R_NO_SUCH_FILE 114 +#define CONF_R_NO_VALUE 108 +#define CONF_R_UNABLE_TO_CREATE_NEW_SECTION 103 +#define CONF_R_UNKNOWN_MODULE_NAME 113 +#define CONF_R_VARIABLE_HAS_NO_VALUE 104 + +#ifdef __cplusplus +} +#endif +#endif diff --git a/lib_tls/include/openssl/conf_api.h b/lib_tls/include/openssl/conf_api.h new file mode 100644 index 000000000..87a954aff --- /dev/null +++ b/lib_tls/include/openssl/conf_api.h @@ -0,0 +1,89 @@ +/* conf_api.h */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#ifndef HEADER_CONF_API_H +#define HEADER_CONF_API_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Up until OpenSSL 0.9.5a, this was new_section */ +CONF_VALUE *_CONF_new_section(CONF *conf, const char *section); +/* Up until OpenSSL 0.9.5a, this was get_section */ +CONF_VALUE *_CONF_get_section(const CONF *conf, const char *section); +/* Up until OpenSSL 0.9.5a, this was CONF_get_section */ +STACK_OF(CONF_VALUE) *_CONF_get_section_values(const CONF *conf, + const char *section); + +int _CONF_add_string(CONF *conf, CONF_VALUE *section, CONF_VALUE *value); +char *_CONF_get_string(const CONF *conf, const char *section, + const char *name); +long _CONF_get_number(const CONF *conf, const char *section, const char *name); + +int _CONF_new_data(CONF *conf); +void _CONF_free_data(CONF *conf); + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/lib_tls/include/openssl/crypto.h b/lib_tls/include/openssl/crypto.h new file mode 100644 index 000000000..d2b5ffe33 --- /dev/null +++ b/lib_tls/include/openssl/crypto.h @@ -0,0 +1,550 @@ +/* crypto/crypto.h */ +/* ==================================================================== + * Copyright (c) 1998-2003 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * ECDH support in OpenSSL originally developed by + * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project. + */ + +#ifndef HEADER_CRYPTO_H +#define HEADER_CRYPTO_H + +#include + +#include + +#ifndef OPENSSL_NO_FP_API +#include +#endif + +#include +#include +#include +#include + +#ifdef CHARSET_EBCDIC +#include +#endif + +/* Resolve problems on some operating systems with symbol names that clash + one way or another */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Backward compatibility to SSLeay */ +/* This is more to be used to check the correct DLL is being used + * in the MS world. */ +#define SSLEAY_VERSION_NUMBER OPENSSL_VERSION_NUMBER +#define SSLEAY_VERSION 0 +/* #define SSLEAY_OPTIONS 1 no longer supported */ +#define SSLEAY_CFLAGS 2 +#define SSLEAY_BUILT_ON 3 +#define SSLEAY_PLATFORM 4 +#define SSLEAY_DIR 5 + +/* Already declared in ossl_typ.h */ +#if 0 +typedef struct crypto_ex_data_st CRYPTO_EX_DATA; +/* Called when a new object is created */ +typedef int CRYPTO_EX_new(void *parent, void *ptr, CRYPTO_EX_DATA *ad, + int idx, long argl, void *argp); +/* Called when an object is free()ed */ +typedef void CRYPTO_EX_free(void *parent, void *ptr, CRYPTO_EX_DATA *ad, + int idx, long argl, void *argp); +/* Called when we need to dup an object */ +typedef int CRYPTO_EX_dup(CRYPTO_EX_DATA *to, CRYPTO_EX_DATA *from, void *from_d, + int idx, long argl, void *argp); +#endif + +/* A generic structure to pass assorted data in a expandable way */ +typedef struct openssl_item_st + { + int code; + void *value; /* Not used for flag attributes */ + size_t value_size; /* Max size of value for output, length for input */ + size_t *value_length; /* Returned length of value for output */ + } OPENSSL_ITEM; + + +/* When changing the CRYPTO_LOCK_* list, be sure to maintin the text lock + * names in cryptlib.c + */ + +#define CRYPTO_LOCK_ERR 1 +#define CRYPTO_LOCK_EX_DATA 2 +#define CRYPTO_LOCK_X509 3 +#define CRYPTO_LOCK_X509_INFO 4 +#define CRYPTO_LOCK_X509_PKEY 5 +#define CRYPTO_LOCK_X509_CRL 6 +#define CRYPTO_LOCK_X509_REQ 7 +#define CRYPTO_LOCK_DSA 8 +#define CRYPTO_LOCK_RSA 9 +#define CRYPTO_LOCK_EVP_PKEY 10 +#define CRYPTO_LOCK_X509_STORE 11 +#define CRYPTO_LOCK_SSL_CTX 12 +#define CRYPTO_LOCK_SSL_CERT 13 +#define CRYPTO_LOCK_SSL_SESSION 14 +#define CRYPTO_LOCK_SSL_SESS_CERT 15 +#define CRYPTO_LOCK_SSL 16 +#define CRYPTO_LOCK_SSL_METHOD 17 +#define CRYPTO_LOCK_RAND 18 +#define CRYPTO_LOCK_RAND2 19 +#define CRYPTO_LOCK_MALLOC 20 +#define CRYPTO_LOCK_BIO 21 +#define CRYPTO_LOCK_GETHOSTBYNAME 22 +#define CRYPTO_LOCK_GETSERVBYNAME 23 +#define CRYPTO_LOCK_READDIR 24 +#define CRYPTO_LOCK_RSA_BLINDING 25 +#define CRYPTO_LOCK_DH 26 +#define CRYPTO_LOCK_MALLOC2 27 +#define CRYPTO_LOCK_DSO 28 +#define CRYPTO_LOCK_DYNLOCK 29 +#define CRYPTO_LOCK_ENGINE 30 +#define CRYPTO_LOCK_UI 31 +#define CRYPTO_LOCK_ECDSA 32 +#define CRYPTO_LOCK_EC 33 +#define CRYPTO_LOCK_ECDH 34 +#define CRYPTO_LOCK_BN 35 +#define CRYPTO_LOCK_EC_PRE_COMP 36 +#define CRYPTO_LOCK_STORE 37 +#define CRYPTO_LOCK_COMP 38 +#define CRYPTO_NUM_LOCKS 39 + +#define CRYPTO_LOCK 1 +#define CRYPTO_UNLOCK 2 +#define CRYPTO_READ 4 +#define CRYPTO_WRITE 8 + +#ifndef OPENSSL_NO_LOCKING +#ifndef CRYPTO_w_lock +#define CRYPTO_w_lock(type) \ + CRYPTO_lock(CRYPTO_LOCK|CRYPTO_WRITE,type,__FILE__,__LINE__) +#define CRYPTO_w_unlock(type) \ + CRYPTO_lock(CRYPTO_UNLOCK|CRYPTO_WRITE,type,__FILE__,__LINE__) +#define CRYPTO_r_lock(type) \ + CRYPTO_lock(CRYPTO_LOCK|CRYPTO_READ,type,__FILE__,__LINE__) +#define CRYPTO_r_unlock(type) \ + CRYPTO_lock(CRYPTO_UNLOCK|CRYPTO_READ,type,__FILE__,__LINE__) +#define CRYPTO_add(addr,amount,type) \ + CRYPTO_add_lock(addr,amount,type,__FILE__,__LINE__) +#endif +#else +#define CRYPTO_w_lock(a) +#define CRYPTO_w_unlock(a) +#define CRYPTO_r_lock(a) +#define CRYPTO_r_unlock(a) +#define CRYPTO_add(a,b,c) ((*(a))+=(b)) +#endif + +/* Some applications as well as some parts of OpenSSL need to allocate + and deallocate locks in a dynamic fashion. The following typedef + makes this possible in a type-safe manner. */ +/* struct CRYPTO_dynlock_value has to be defined by the application. */ +typedef struct + { + int references; + struct CRYPTO_dynlock_value *data; + } CRYPTO_dynlock; + + +/* The following can be used to detect memory leaks in the SSLeay library. + * It used, it turns on malloc checking */ + +#define CRYPTO_MEM_CHECK_OFF 0x0 /* an enume */ +#define CRYPTO_MEM_CHECK_ON 0x1 /* a bit */ +#define CRYPTO_MEM_CHECK_ENABLE 0x2 /* a bit */ +#define CRYPTO_MEM_CHECK_DISABLE 0x3 /* an enume */ + +/* The following are bit values to turn on or off options connected to the + * malloc checking functionality */ + +/* Adds time to the memory checking information */ +#define V_CRYPTO_MDEBUG_TIME 0x1 /* a bit */ +/* Adds thread number to the memory checking information */ +#define V_CRYPTO_MDEBUG_THREAD 0x2 /* a bit */ + +#define V_CRYPTO_MDEBUG_ALL (V_CRYPTO_MDEBUG_TIME | V_CRYPTO_MDEBUG_THREAD) + + +/* predec of the BIO type */ +typedef struct bio_st BIO_dummy; + +struct crypto_ex_data_st + { + STACK *sk; + int dummy; /* gcc is screwing up this data structure :-( */ + }; + +/* This stuff is basically class callback functions + * The current classes are SSL_CTX, SSL, SSL_SESSION, and a few more */ + +typedef struct crypto_ex_data_func_st + { + long argl; /* Arbitary long */ + void *argp; /* Arbitary void * */ + CRYPTO_EX_new *new_func; + CRYPTO_EX_free *free_func; + CRYPTO_EX_dup *dup_func; + } CRYPTO_EX_DATA_FUNCS; + +DECLARE_STACK_OF(CRYPTO_EX_DATA_FUNCS) + +/* Per class, we have a STACK of CRYPTO_EX_DATA_FUNCS for each CRYPTO_EX_DATA + * entry. + */ + +#define CRYPTO_EX_INDEX_BIO 0 +#define CRYPTO_EX_INDEX_SSL 1 +#define CRYPTO_EX_INDEX_SSL_CTX 2 +#define CRYPTO_EX_INDEX_SSL_SESSION 3 +#define CRYPTO_EX_INDEX_X509_STORE 4 +#define CRYPTO_EX_INDEX_X509_STORE_CTX 5 +#define CRYPTO_EX_INDEX_RSA 6 +#define CRYPTO_EX_INDEX_DSA 7 +#define CRYPTO_EX_INDEX_DH 8 +#define CRYPTO_EX_INDEX_ENGINE 9 +#define CRYPTO_EX_INDEX_X509 10 +#define CRYPTO_EX_INDEX_UI 11 +#define CRYPTO_EX_INDEX_ECDSA 12 +#define CRYPTO_EX_INDEX_ECDH 13 +#define CRYPTO_EX_INDEX_COMP 14 +#define CRYPTO_EX_INDEX_STORE 15 + +/* Dynamically assigned indexes start from this value (don't use directly, use + * via CRYPTO_ex_data_new_class). */ +#define CRYPTO_EX_INDEX_USER 100 + + +/* This is the default callbacks, but we can have others as well: + * this is needed in Win32 where the application malloc and the + * library malloc may not be the same. + */ +#define CRYPTO_malloc_init() CRYPTO_set_mem_functions(\ + malloc, realloc, free) + +#if defined CRYPTO_MDEBUG_ALL || defined CRYPTO_MDEBUG_TIME || defined CRYPTO_MDEBUG_THREAD +# ifndef CRYPTO_MDEBUG /* avoid duplicate #define */ +# define CRYPTO_MDEBUG +# endif +#endif + +/* Set standard debugging functions (not done by default + * unless CRYPTO_MDEBUG is defined) */ +#define CRYPTO_malloc_debug_init() do {\ + CRYPTO_set_mem_debug_functions(\ + CRYPTO_dbg_malloc,\ + CRYPTO_dbg_realloc,\ + CRYPTO_dbg_free,\ + CRYPTO_dbg_set_options,\ + CRYPTO_dbg_get_options);\ + } while(0) + +int CRYPTO_mem_ctrl(int mode); +int CRYPTO_is_mem_check_on(void); + +/* for applications */ +#define MemCheck_start() CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON) +#define MemCheck_stop() CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_OFF) + +/* for library-internal use */ +#define MemCheck_on() CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE) +#define MemCheck_off() CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE) +#define is_MemCheck_on() CRYPTO_is_mem_check_on() + +#define OPENSSL_malloc(num) CRYPTO_malloc((int)num,__FILE__,__LINE__) +#define OPENSSL_realloc(addr,num) \ + CRYPTO_realloc((char *)addr,(int)num,__FILE__,__LINE__) +#define OPENSSL_realloc_clean(addr,old_num,num) \ + CRYPTO_realloc_clean(addr,old_num,num,__FILE__,__LINE__) +#define OPENSSL_remalloc(addr,num) \ + CRYPTO_remalloc((char **)addr,(int)num,__FILE__,__LINE__) +#define OPENSSL_freeFunc CRYPTO_free +#define OPENSSL_free(addr) CRYPTO_free(addr) + +#define OPENSSL_malloc_locked(num) \ + CRYPTO_malloc_locked((int)num,__FILE__,__LINE__) +#define OPENSSL_free_locked(addr) CRYPTO_free_locked(addr) + + +const char *SSLeay_version(int type); +unsigned long SSLeay(void); + +int OPENSSL_issetugid(void); + +/* An opaque type representing an implementation of "ex_data" support */ +typedef struct st_CRYPTO_EX_DATA_IMPL CRYPTO_EX_DATA_IMPL; +/* Return an opaque pointer to the current "ex_data" implementation */ +const CRYPTO_EX_DATA_IMPL *CRYPTO_get_ex_data_implementation(void); +/* Sets the "ex_data" implementation to be used (if it's not too late) */ +int CRYPTO_set_ex_data_implementation(const CRYPTO_EX_DATA_IMPL *i); +/* Get a new "ex_data" class, and return the corresponding "class_index" */ +int CRYPTO_ex_data_new_class(void); +/* Within a given class, get/register a new index */ +int CRYPTO_get_ex_new_index(int class_index, long argl, void *argp, + CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func, + CRYPTO_EX_free *free_func); +/* Initialise/duplicate/free CRYPTO_EX_DATA variables corresponding to a given + * class (invokes whatever per-class callbacks are applicable) */ +int CRYPTO_new_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad); +int CRYPTO_dup_ex_data(int class_index, CRYPTO_EX_DATA *to, + CRYPTO_EX_DATA *from); +void CRYPTO_free_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad); +/* Get/set data in a CRYPTO_EX_DATA variable corresponding to a particular index + * (relative to the class type involved) */ +int CRYPTO_set_ex_data(CRYPTO_EX_DATA *ad, int idx, void *val); +void *CRYPTO_get_ex_data(const CRYPTO_EX_DATA *ad,int idx); +/* This function cleans up all "ex_data" state. It mustn't be called under + * potential race-conditions. */ +void CRYPTO_cleanup_all_ex_data(void); + +int CRYPTO_get_new_lockid(char *name); + +int CRYPTO_num_locks(void); /* return CRYPTO_NUM_LOCKS (shared libs!) */ +void CRYPTO_lock(int mode, int type,const char *file,int line); +void CRYPTO_set_locking_callback(void (*func)(int mode,int type, + const char *file,int line)); +void (*CRYPTO_get_locking_callback(void))(int mode,int type,const char *file, + int line); +void CRYPTO_set_add_lock_callback(int (*func)(int *num,int mount,int type, + const char *file, int line)); +int (*CRYPTO_get_add_lock_callback(void))(int *num,int mount,int type, + const char *file,int line); +void CRYPTO_set_id_callback(unsigned long (*func)(void)); +unsigned long (*CRYPTO_get_id_callback(void))(void); +unsigned long CRYPTO_thread_id(void); +const char *CRYPTO_get_lock_name(int type); +int CRYPTO_add_lock(int *pointer,int amount,int type, const char *file, + int line); + +int CRYPTO_get_new_dynlockid(void); +void CRYPTO_destroy_dynlockid(int i); +struct CRYPTO_dynlock_value *CRYPTO_get_dynlock_value(int i); +void CRYPTO_set_dynlock_create_callback(struct CRYPTO_dynlock_value *(*dyn_create_function)(const char *file, int line)); +void CRYPTO_set_dynlock_lock_callback(void (*dyn_lock_function)(int mode, struct CRYPTO_dynlock_value *l, const char *file, int line)); +void CRYPTO_set_dynlock_destroy_callback(void (*dyn_destroy_function)(struct CRYPTO_dynlock_value *l, const char *file, int line)); +struct CRYPTO_dynlock_value *(*CRYPTO_get_dynlock_create_callback(void))(const char *file,int line); +void (*CRYPTO_get_dynlock_lock_callback(void))(int mode, struct CRYPTO_dynlock_value *l, const char *file,int line); +void (*CRYPTO_get_dynlock_destroy_callback(void))(struct CRYPTO_dynlock_value *l, const char *file,int line); + +/* CRYPTO_set_mem_functions includes CRYPTO_set_locked_mem_functions -- + * call the latter last if you need different functions */ +int CRYPTO_set_mem_functions(void *(*m)(size_t),void *(*r)(void *,size_t), void (*f)(void *)); +int CRYPTO_set_locked_mem_functions(void *(*m)(size_t), void (*free_func)(void *)); +int CRYPTO_set_mem_ex_functions(void *(*m)(size_t,const char *,int), + void *(*r)(void *,size_t,const char *,int), + void (*f)(void *)); +int CRYPTO_set_locked_mem_ex_functions(void *(*m)(size_t,const char *,int), + void (*free_func)(void *)); +int CRYPTO_set_mem_debug_functions(void (*m)(void *,int,const char *,int,int), + void (*r)(void *,void *,int,const char *,int,int), + void (*f)(void *,int), + void (*so)(long), + long (*go)(void)); +void CRYPTO_get_mem_functions(void *(**m)(size_t),void *(**r)(void *, size_t), void (**f)(void *)); +void CRYPTO_get_locked_mem_functions(void *(**m)(size_t), void (**f)(void *)); +void CRYPTO_get_mem_ex_functions(void *(**m)(size_t,const char *,int), + void *(**r)(void *, size_t,const char *,int), + void (**f)(void *)); +void CRYPTO_get_locked_mem_ex_functions(void *(**m)(size_t,const char *,int), + void (**f)(void *)); +void CRYPTO_get_mem_debug_functions(void (**m)(void *,int,const char *,int,int), + void (**r)(void *,void *,int,const char *,int,int), + void (**f)(void *,int), + void (**so)(long), + long (**go)(void)); + +void *CRYPTO_malloc_locked(int num, const char *file, int line); +void CRYPTO_free_locked(void *); +void *CRYPTO_malloc(int num, const char *file, int line); +void CRYPTO_free(void *); +void *CRYPTO_realloc(void *addr,int num, const char *file, int line); +void *CRYPTO_realloc_clean(void *addr,int old_num,int num,const char *file, + int line); +void *CRYPTO_remalloc(void *addr,int num, const char *file, int line); + +void OPENSSL_cleanse(void *ptr, size_t len); + +void CRYPTO_set_mem_debug_options(long bits); +long CRYPTO_get_mem_debug_options(void); + +#define CRYPTO_push_info(info) \ + CRYPTO_push_info_(info, __FILE__, __LINE__); +int CRYPTO_push_info_(const char *info, const char *file, int line); +int CRYPTO_pop_info(void); +int CRYPTO_remove_all_info(void); + + +/* Default debugging functions (enabled by CRYPTO_malloc_debug_init() macro; + * used as default in CRYPTO_MDEBUG compilations): */ +/* The last argument has the following significance: + * + * 0: called before the actual memory allocation has taken place + * 1: called after the actual memory allocation has taken place + */ +void CRYPTO_dbg_malloc(void *addr,int num,const char *file,int line,int before_p); +void CRYPTO_dbg_realloc(void *addr1,void *addr2,int num,const char *file,int line,int before_p); +void CRYPTO_dbg_free(void *addr,int before_p); +/* Tell the debugging code about options. By default, the following values + * apply: + * + * 0: Clear all options. + * V_CRYPTO_MDEBUG_TIME (1): Set the "Show Time" option. + * V_CRYPTO_MDEBUG_THREAD (2): Set the "Show Thread Number" option. + * V_CRYPTO_MDEBUG_ALL (3): 1 + 2 + */ +void CRYPTO_dbg_set_options(long bits); +long CRYPTO_dbg_get_options(void); + + +#ifndef OPENSSL_NO_FP_API +void CRYPTO_mem_leaks_fp(FILE *); +#endif +void CRYPTO_mem_leaks(struct bio_st *bio); +/* unsigned long order, char *file, int line, int num_bytes, char *addr */ +typedef void *CRYPTO_MEM_LEAK_CB(unsigned long, const char *, int, int, void *); +void CRYPTO_mem_leaks_cb(CRYPTO_MEM_LEAK_CB *cb); + +/* die if we have to */ +void OpenSSLDie(const char *file,int line,const char *assertion); +#define OPENSSL_assert(e) (void)((e) ? 0 : (OpenSSLDie(__FILE__, __LINE__, #e),1)) + +unsigned long *OPENSSL_ia32cap_loc(void); +#define OPENSSL_ia32cap (*(OPENSSL_ia32cap_loc())) + +/* BEGIN ERROR CODES */ +/* The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ +void ERR_load_CRYPTO_strings(void); + +/* Error codes for the CRYPTO functions. */ + +/* Function codes. */ +#define CRYPTO_F_CRYPTO_GET_EX_NEW_INDEX 100 +#define CRYPTO_F_CRYPTO_GET_NEW_DYNLOCKID 103 +#define CRYPTO_F_CRYPTO_GET_NEW_LOCKID 101 +#define CRYPTO_F_CRYPTO_SET_EX_DATA 102 +#define CRYPTO_F_DEF_ADD_INDEX 104 +#define CRYPTO_F_DEF_GET_CLASS 105 +#define CRYPTO_F_INT_DUP_EX_DATA 106 +#define CRYPTO_F_INT_FREE_EX_DATA 107 +#define CRYPTO_F_INT_NEW_EX_DATA 108 + +/* Reason codes. */ +#define CRYPTO_R_NO_DYNLOCK_CREATE_CALLBACK 100 + +#ifdef __cplusplus +} +#endif +#endif diff --git a/lib_tls/include/openssl/des.h b/lib_tls/include/openssl/des.h new file mode 100644 index 000000000..92b666359 --- /dev/null +++ b/lib_tls/include/openssl/des.h @@ -0,0 +1,245 @@ +/* crypto/des/des.h */ +/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#ifndef HEADER_NEW_DES_H +#define HEADER_NEW_DES_H + +#include /* OPENSSL_EXTERN, OPENSSL_NO_DES, + DES_LONG (via openssl/opensslconf.h */ + +#ifdef OPENSSL_NO_DES +#error DES is disabled. +#endif + +#ifdef OPENSSL_BUILD_SHLIBCRYPTO +# undef OPENSSL_EXTERN +# define OPENSSL_EXTERN OPENSSL_EXPORT +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef unsigned char DES_cblock[8]; +typedef /* const */ unsigned char const_DES_cblock[8]; +/* With "const", gcc 2.8.1 on Solaris thinks that DES_cblock * + * and const_DES_cblock * are incompatible pointer types. */ + +typedef struct DES_ks + { + union + { + DES_cblock cblock; + /* make sure things are correct size on machines with + * 8 byte longs */ + DES_LONG deslong[2]; + } ks[16]; + } DES_key_schedule; + +#ifndef OPENSSL_DISABLE_OLD_DES_SUPPORT +# ifndef OPENSSL_ENABLE_OLD_DES_SUPPORT +# define OPENSSL_ENABLE_OLD_DES_SUPPORT +# endif +#endif + +#ifdef OPENSSL_ENABLE_OLD_DES_SUPPORT +# include +#endif + +#define DES_KEY_SZ (sizeof(DES_cblock)) +#define DES_SCHEDULE_SZ (sizeof(DES_key_schedule)) + +#define DES_ENCRYPT 1 +#define DES_DECRYPT 0 + +#define DES_CBC_MODE 0 +#define DES_PCBC_MODE 1 + +#define DES_ecb2_encrypt(i,o,k1,k2,e) \ + DES_ecb3_encrypt((i),(o),(k1),(k2),(k1),(e)) + +#define DES_ede2_cbc_encrypt(i,o,l,k1,k2,iv,e) \ + DES_ede3_cbc_encrypt((i),(o),(l),(k1),(k2),(k1),(iv),(e)) + +#define DES_ede2_cfb64_encrypt(i,o,l,k1,k2,iv,n,e) \ + DES_ede3_cfb64_encrypt((i),(o),(l),(k1),(k2),(k1),(iv),(n),(e)) + +#define DES_ede2_ofb64_encrypt(i,o,l,k1,k2,iv,n) \ + DES_ede3_ofb64_encrypt((i),(o),(l),(k1),(k2),(k1),(iv),(n)) + +OPENSSL_DECLARE_GLOBAL(int,DES_check_key); /* defaults to false */ +#define DES_check_key OPENSSL_GLOBAL_REF(DES_check_key) +OPENSSL_DECLARE_GLOBAL(int,DES_rw_mode); /* defaults to DES_PCBC_MODE */ +#define DES_rw_mode OPENSSL_GLOBAL_REF(DES_rw_mode) + +const char *DES_options(void); +void DES_ecb3_encrypt(const_DES_cblock *input, DES_cblock *output, + DES_key_schedule *ks1,DES_key_schedule *ks2, + DES_key_schedule *ks3, int enc); +DES_LONG DES_cbc_cksum(const unsigned char *input,DES_cblock *output, + long length,DES_key_schedule *schedule, + const_DES_cblock *ivec); +/* DES_cbc_encrypt does not update the IV! Use DES_ncbc_encrypt instead. */ +void DES_cbc_encrypt(const unsigned char *input,unsigned char *output, + long length,DES_key_schedule *schedule,DES_cblock *ivec, + int enc); +void DES_ncbc_encrypt(const unsigned char *input,unsigned char *output, + long length,DES_key_schedule *schedule,DES_cblock *ivec, + int enc); +void DES_xcbc_encrypt(const unsigned char *input,unsigned char *output, + long length,DES_key_schedule *schedule,DES_cblock *ivec, + const_DES_cblock *inw,const_DES_cblock *outw,int enc); +void DES_cfb_encrypt(const unsigned char *in,unsigned char *out,int numbits, + long length,DES_key_schedule *schedule,DES_cblock *ivec, + int enc); +void DES_ecb_encrypt(const_DES_cblock *input,DES_cblock *output, + DES_key_schedule *ks,int enc); + +/* This is the DES encryption function that gets called by just about + every other DES routine in the library. You should not use this + function except to implement 'modes' of DES. I say this because the + functions that call this routine do the conversion from 'char *' to + long, and this needs to be done to make sure 'non-aligned' memory + access do not occur. The characters are loaded 'little endian'. + Data is a pointer to 2 unsigned long's and ks is the + DES_key_schedule to use. enc, is non zero specifies encryption, + zero if decryption. */ +void DES_encrypt1(DES_LONG *data,DES_key_schedule *ks, int enc); + +/* This functions is the same as DES_encrypt1() except that the DES + initial permutation (IP) and final permutation (FP) have been left + out. As for DES_encrypt1(), you should not use this function. + It is used by the routines in the library that implement triple DES. + IP() DES_encrypt2() DES_encrypt2() DES_encrypt2() FP() is the same + as DES_encrypt1() DES_encrypt1() DES_encrypt1() except faster :-). */ +void DES_encrypt2(DES_LONG *data,DES_key_schedule *ks, int enc); + +void DES_encrypt3(DES_LONG *data, DES_key_schedule *ks1, + DES_key_schedule *ks2, DES_key_schedule *ks3); +void DES_decrypt3(DES_LONG *data, DES_key_schedule *ks1, + DES_key_schedule *ks2, DES_key_schedule *ks3); +void DES_ede3_cbc_encrypt(const unsigned char *input,unsigned char *output, + long length, + DES_key_schedule *ks1,DES_key_schedule *ks2, + DES_key_schedule *ks3,DES_cblock *ivec,int enc); +void DES_ede3_cbcm_encrypt(const unsigned char *in,unsigned char *out, + long length, + DES_key_schedule *ks1,DES_key_schedule *ks2, + DES_key_schedule *ks3, + DES_cblock *ivec1,DES_cblock *ivec2, + int enc); +void DES_ede3_cfb64_encrypt(const unsigned char *in,unsigned char *out, + long length,DES_key_schedule *ks1, + DES_key_schedule *ks2,DES_key_schedule *ks3, + DES_cblock *ivec,int *num,int enc); +void DES_ede3_cfb_encrypt(const unsigned char *in,unsigned char *out, + int numbits,long length,DES_key_schedule *ks1, + DES_key_schedule *ks2,DES_key_schedule *ks3, + DES_cblock *ivec,int enc); +void DES_ede3_ofb64_encrypt(const unsigned char *in,unsigned char *out, + long length,DES_key_schedule *ks1, + DES_key_schedule *ks2,DES_key_schedule *ks3, + DES_cblock *ivec,int *num); +#if 0 +void DES_xwhite_in2out(const_DES_cblock *DES_key,const_DES_cblock *in_white, + DES_cblock *out_white); +#endif + +int DES_enc_read(int fd,void *buf,int len,DES_key_schedule *sched, + DES_cblock *iv); +int DES_enc_write(int fd,const void *buf,int len,DES_key_schedule *sched, + DES_cblock *iv); +char *DES_fcrypt(const char *buf,const char *salt, char *ret); +char *DES_crypt(const char *buf,const char *salt); +void DES_ofb_encrypt(const unsigned char *in,unsigned char *out,int numbits, + long length,DES_key_schedule *schedule,DES_cblock *ivec); +void DES_pcbc_encrypt(const unsigned char *input,unsigned char *output, + long length,DES_key_schedule *schedule,DES_cblock *ivec, + int enc); +DES_LONG DES_quad_cksum(const unsigned char *input,DES_cblock output[], + long length,int out_count,DES_cblock *seed); +int DES_random_key(DES_cblock *ret); +void DES_set_odd_parity(DES_cblock *key); +int DES_check_key_parity(const_DES_cblock *key); +int DES_is_weak_key(const_DES_cblock *key); +/* DES_set_key (= set_key = DES_key_sched = key_sched) calls + * DES_set_key_checked if global variable DES_check_key is set, + * DES_set_key_unchecked otherwise. */ +int DES_set_key(const_DES_cblock *key,DES_key_schedule *schedule); +int DES_key_sched(const_DES_cblock *key,DES_key_schedule *schedule); +int DES_set_key_checked(const_DES_cblock *key,DES_key_schedule *schedule); +void DES_set_key_unchecked(const_DES_cblock *key,DES_key_schedule *schedule); +void DES_string_to_key(const char *str,DES_cblock *key); +void DES_string_to_2keys(const char *str,DES_cblock *key1,DES_cblock *key2); +void DES_cfb64_encrypt(const unsigned char *in,unsigned char *out,long length, + DES_key_schedule *schedule,DES_cblock *ivec,int *num, + int enc); +void DES_ofb64_encrypt(const unsigned char *in,unsigned char *out,long length, + DES_key_schedule *schedule,DES_cblock *ivec,int *num); + +int DES_read_password(DES_cblock *key, const char *prompt, int verify); +int DES_read_2passwords(DES_cblock *key1, DES_cblock *key2, const char *prompt, + int verify); + +#define DES_fixup_key_parity DES_set_odd_parity + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_tls/include/openssl/des_old.h b/lib_tls/include/openssl/des_old.h new file mode 100644 index 000000000..2b2c37235 --- /dev/null +++ b/lib_tls/include/openssl/des_old.h @@ -0,0 +1,446 @@ +/* crypto/des/des_old.h -*- mode:C; c-file-style: "eay" -*- */ + +/* WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING + * + * The function names in here are deprecated and are only present to + * provide an interface compatible with openssl 0.9.6 and older as + * well as libdes. OpenSSL now provides functions where "des_" has + * been replaced with "DES_" in the names, to make it possible to + * make incompatible changes that are needed for C type security and + * other stuff. + * + * This include files has two compatibility modes: + * + * - If OPENSSL_DES_LIBDES_COMPATIBILITY is defined, you get an API + * that is compatible with libdes and SSLeay. + * - If OPENSSL_DES_LIBDES_COMPATIBILITY isn't defined, you get an + * API that is compatible with OpenSSL 0.9.5x to 0.9.6x. + * + * Note that these modes break earlier snapshots of OpenSSL, where + * libdes compatibility was the only available mode or (later on) the + * prefered compatibility mode. However, after much consideration + * (and more or less violent discussions with external parties), it + * was concluded that OpenSSL should be compatible with earlier versions + * of itself before anything else. Also, in all honesty, libdes is + * an old beast that shouldn't really be used any more. + * + * Please consider starting to use the DES_ functions rather than the + * des_ ones. The des_ functions will disappear completely before + * OpenSSL 1.0! + * + * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING + */ + +/* Written by Richard Levitte (richard@levitte.org) for the OpenSSL + * project 2001. + */ +/* ==================================================================== + * Copyright (c) 1998-2002 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#ifndef HEADER_DES_H +#define HEADER_DES_H + +#include /* OPENSSL_EXTERN, OPENSSL_NO_DES, DES_LONG */ + +#ifdef OPENSSL_NO_DES +#error DES is disabled. +#endif + +#ifndef HEADER_NEW_DES_H +#error You must include des.h, not des_old.h directly. +#endif + +#ifdef _KERBEROS_DES_H +#error replaces . +#endif + +#include + +#ifdef OPENSSL_BUILD_SHLIBCRYPTO +# undef OPENSSL_EXTERN +# define OPENSSL_EXTERN OPENSSL_EXPORT +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _ +#undef _ +#endif + +typedef unsigned char _ossl_old_des_cblock[8]; +typedef struct _ossl_old_des_ks_struct + { + union { + _ossl_old_des_cblock _; + /* make sure things are correct size on machines with + * 8 byte longs */ + DES_LONG pad[2]; + } ks; + } _ossl_old_des_key_schedule[16]; + +#ifndef OPENSSL_DES_LIBDES_COMPATIBILITY +#define des_cblock DES_cblock +#define const_des_cblock const_DES_cblock +#define des_key_schedule DES_key_schedule +#define des_ecb3_encrypt(i,o,k1,k2,k3,e)\ + DES_ecb3_encrypt((i),(o),&(k1),&(k2),&(k3),(e)) +#define des_ede3_cbc_encrypt(i,o,l,k1,k2,k3,iv,e)\ + DES_ede3_cbc_encrypt((i),(o),(l),&(k1),&(k2),&(k3),(iv),(e)) +#define des_ede3_cbcm_encrypt(i,o,l,k1,k2,k3,iv1,iv2,e)\ + DES_ede3_cbcm_encrypt((i),(o),(l),&(k1),&(k2),&(k3),(iv1),(iv2),(e)) +#define des_ede3_cfb64_encrypt(i,o,l,k1,k2,k3,iv,n,e)\ + DES_ede3_cfb64_encrypt((i),(o),(l),&(k1),&(k2),&(k3),(iv),(n),(e)) +#define des_ede3_ofb64_encrypt(i,o,l,k1,k2,k3,iv,n)\ + DES_ede3_ofb64_encrypt((i),(o),(l),&(k1),&(k2),&(k3),(iv),(n)) +#define des_options()\ + DES_options() +#define des_cbc_cksum(i,o,l,k,iv)\ + DES_cbc_cksum((i),(o),(l),&(k),(iv)) +#define des_cbc_encrypt(i,o,l,k,iv,e)\ + DES_cbc_encrypt((i),(o),(l),&(k),(iv),(e)) +#define des_ncbc_encrypt(i,o,l,k,iv,e)\ + DES_ncbc_encrypt((i),(o),(l),&(k),(iv),(e)) +#define des_xcbc_encrypt(i,o,l,k,iv,inw,outw,e)\ + DES_xcbc_encrypt((i),(o),(l),&(k),(iv),(inw),(outw),(e)) +#define des_cfb_encrypt(i,o,n,l,k,iv,e)\ + DES_cfb_encrypt((i),(o),(n),(l),&(k),(iv),(e)) +#define des_ecb_encrypt(i,o,k,e)\ + DES_ecb_encrypt((i),(o),&(k),(e)) +#define des_encrypt1(d,k,e)\ + DES_encrypt1((d),&(k),(e)) +#define des_encrypt2(d,k,e)\ + DES_encrypt2((d),&(k),(e)) +#define des_encrypt3(d,k1,k2,k3)\ + DES_encrypt3((d),&(k1),&(k2),&(k3)) +#define des_decrypt3(d,k1,k2,k3)\ + DES_decrypt3((d),&(k1),&(k2),&(k3)) +#define des_xwhite_in2out(k,i,o)\ + DES_xwhite_in2out((k),(i),(o)) +#define des_enc_read(f,b,l,k,iv)\ + DES_enc_read((f),(b),(l),&(k),(iv)) +#define des_enc_write(f,b,l,k,iv)\ + DES_enc_write((f),(b),(l),&(k),(iv)) +#define des_fcrypt(b,s,r)\ + DES_fcrypt((b),(s),(r)) +#if 0 +#define des_crypt(b,s)\ + DES_crypt((b),(s)) +#if !defined(PERL5) && !defined(__FreeBSD__) && !defined(NeXT) && !defined(__OpenBSD__) +#define crypt(b,s)\ + DES_crypt((b),(s)) +#endif +#endif +#define des_ofb_encrypt(i,o,n,l,k,iv)\ + DES_ofb_encrypt((i),(o),(n),(l),&(k),(iv)) +#define des_pcbc_encrypt(i,o,l,k,iv,e)\ + DES_pcbc_encrypt((i),(o),(l),&(k),(iv),(e)) +#define des_quad_cksum(i,o,l,c,s)\ + DES_quad_cksum((i),(o),(l),(c),(s)) +#define des_random_seed(k)\ + _ossl_096_des_random_seed((k)) +#define des_random_key(r)\ + DES_random_key((r)) +#define des_read_password(k,p,v) \ + DES_read_password((k),(p),(v)) +#define des_read_2passwords(k1,k2,p,v) \ + DES_read_2passwords((k1),(k2),(p),(v)) +#define des_set_odd_parity(k)\ + DES_set_odd_parity((k)) +#define des_check_key_parity(k)\ + DES_check_key_parity((k)) +#define des_is_weak_key(k)\ + DES_is_weak_key((k)) +#define des_set_key(k,ks)\ + DES_set_key((k),&(ks)) +#define des_key_sched(k,ks)\ + DES_key_sched((k),&(ks)) +#define des_set_key_checked(k,ks)\ + DES_set_key_checked((k),&(ks)) +#define des_set_key_unchecked(k,ks)\ + DES_set_key_unchecked((k),&(ks)) +#define des_string_to_key(s,k)\ + DES_string_to_key((s),(k)) +#define des_string_to_2keys(s,k1,k2)\ + DES_string_to_2keys((s),(k1),(k2)) +#define des_cfb64_encrypt(i,o,l,ks,iv,n,e)\ + DES_cfb64_encrypt((i),(o),(l),&(ks),(iv),(n),(e)) +#define des_ofb64_encrypt(i,o,l,ks,iv,n)\ + DES_ofb64_encrypt((i),(o),(l),&(ks),(iv),(n)) + + +#define des_ecb2_encrypt(i,o,k1,k2,e) \ + des_ecb3_encrypt((i),(o),(k1),(k2),(k1),(e)) + +#define des_ede2_cbc_encrypt(i,o,l,k1,k2,iv,e) \ + des_ede3_cbc_encrypt((i),(o),(l),(k1),(k2),(k1),(iv),(e)) + +#define des_ede2_cfb64_encrypt(i,o,l,k1,k2,iv,n,e) \ + des_ede3_cfb64_encrypt((i),(o),(l),(k1),(k2),(k1),(iv),(n),(e)) + +#define des_ede2_ofb64_encrypt(i,o,l,k1,k2,iv,n) \ + des_ede3_ofb64_encrypt((i),(o),(l),(k1),(k2),(k1),(iv),(n)) + +#define des_check_key DES_check_key +#define des_rw_mode DES_rw_mode +#else /* libdes compatibility */ +/* Map all symbol names to _ossl_old_des_* form, so we avoid all + clashes with libdes */ +#define des_cblock _ossl_old_des_cblock +#define des_key_schedule _ossl_old_des_key_schedule +#define des_ecb3_encrypt(i,o,k1,k2,k3,e)\ + _ossl_old_des_ecb3_encrypt((i),(o),(k1),(k2),(k3),(e)) +#define des_ede3_cbc_encrypt(i,o,l,k1,k2,k3,iv,e)\ + _ossl_old_des_ede3_cbc_encrypt((i),(o),(l),(k1),(k2),(k3),(iv),(e)) +#define des_ede3_cfb64_encrypt(i,o,l,k1,k2,k3,iv,n,e)\ + _ossl_old_des_ede3_cfb64_encrypt((i),(o),(l),(k1),(k2),(k3),(iv),(n),(e)) +#define des_ede3_ofb64_encrypt(i,o,l,k1,k2,k3,iv,n)\ + _ossl_old_des_ede3_ofb64_encrypt((i),(o),(l),(k1),(k2),(k3),(iv),(n)) +#define des_options()\ + _ossl_old_des_options() +#define des_cbc_cksum(i,o,l,k,iv)\ + _ossl_old_des_cbc_cksum((i),(o),(l),(k),(iv)) +#define des_cbc_encrypt(i,o,l,k,iv,e)\ + _ossl_old_des_cbc_encrypt((i),(o),(l),(k),(iv),(e)) +#define des_ncbc_encrypt(i,o,l,k,iv,e)\ + _ossl_old_des_ncbc_encrypt((i),(o),(l),(k),(iv),(e)) +#define des_xcbc_encrypt(i,o,l,k,iv,inw,outw,e)\ + _ossl_old_des_xcbc_encrypt((i),(o),(l),(k),(iv),(inw),(outw),(e)) +#define des_cfb_encrypt(i,o,n,l,k,iv,e)\ + _ossl_old_des_cfb_encrypt((i),(o),(n),(l),(k),(iv),(e)) +#define des_ecb_encrypt(i,o,k,e)\ + _ossl_old_des_ecb_encrypt((i),(o),(k),(e)) +#define des_encrypt(d,k,e)\ + _ossl_old_des_encrypt((d),(k),(e)) +#define des_encrypt2(d,k,e)\ + _ossl_old_des_encrypt2((d),(k),(e)) +#define des_encrypt3(d,k1,k2,k3)\ + _ossl_old_des_encrypt3((d),(k1),(k2),(k3)) +#define des_decrypt3(d,k1,k2,k3)\ + _ossl_old_des_decrypt3((d),(k1),(k2),(k3)) +#define des_xwhite_in2out(k,i,o)\ + _ossl_old_des_xwhite_in2out((k),(i),(o)) +#define des_enc_read(f,b,l,k,iv)\ + _ossl_old_des_enc_read((f),(b),(l),(k),(iv)) +#define des_enc_write(f,b,l,k,iv)\ + _ossl_old_des_enc_write((f),(b),(l),(k),(iv)) +#define des_fcrypt(b,s,r)\ + _ossl_old_des_fcrypt((b),(s),(r)) +#define des_crypt(b,s)\ + _ossl_old_des_crypt((b),(s)) +#if 0 +#define crypt(b,s)\ + _ossl_old_crypt((b),(s)) +#endif +#define des_ofb_encrypt(i,o,n,l,k,iv)\ + _ossl_old_des_ofb_encrypt((i),(o),(n),(l),(k),(iv)) +#define des_pcbc_encrypt(i,o,l,k,iv,e)\ + _ossl_old_des_pcbc_encrypt((i),(o),(l),(k),(iv),(e)) +#define des_quad_cksum(i,o,l,c,s)\ + _ossl_old_des_quad_cksum((i),(o),(l),(c),(s)) +#define des_random_seed(k)\ + _ossl_old_des_random_seed((k)) +#define des_random_key(r)\ + _ossl_old_des_random_key((r)) +#define des_read_password(k,p,v) \ + _ossl_old_des_read_password((k),(p),(v)) +#define des_read_2passwords(k1,k2,p,v) \ + _ossl_old_des_read_2passwords((k1),(k2),(p),(v)) +#define des_set_odd_parity(k)\ + _ossl_old_des_set_odd_parity((k)) +#define des_is_weak_key(k)\ + _ossl_old_des_is_weak_key((k)) +#define des_set_key(k,ks)\ + _ossl_old_des_set_key((k),(ks)) +#define des_key_sched(k,ks)\ + _ossl_old_des_key_sched((k),(ks)) +#define des_string_to_key(s,k)\ + _ossl_old_des_string_to_key((s),(k)) +#define des_string_to_2keys(s,k1,k2)\ + _ossl_old_des_string_to_2keys((s),(k1),(k2)) +#define des_cfb64_encrypt(i,o,l,ks,iv,n,e)\ + _ossl_old_des_cfb64_encrypt((i),(o),(l),(ks),(iv),(n),(e)) +#define des_ofb64_encrypt(i,o,l,ks,iv,n)\ + _ossl_old_des_ofb64_encrypt((i),(o),(l),(ks),(iv),(n)) + + +#define des_ecb2_encrypt(i,o,k1,k2,e) \ + des_ecb3_encrypt((i),(o),(k1),(k2),(k1),(e)) + +#define des_ede2_cbc_encrypt(i,o,l,k1,k2,iv,e) \ + des_ede3_cbc_encrypt((i),(o),(l),(k1),(k2),(k1),(iv),(e)) + +#define des_ede2_cfb64_encrypt(i,o,l,k1,k2,iv,n,e) \ + des_ede3_cfb64_encrypt((i),(o),(l),(k1),(k2),(k1),(iv),(n),(e)) + +#define des_ede2_ofb64_encrypt(i,o,l,k1,k2,iv,n) \ + des_ede3_ofb64_encrypt((i),(o),(l),(k1),(k2),(k1),(iv),(n)) + +#define des_check_key DES_check_key +#define des_rw_mode DES_rw_mode +#endif + +const char *_ossl_old_des_options(void); +void _ossl_old_des_ecb3_encrypt(_ossl_old_des_cblock *input,_ossl_old_des_cblock *output, + _ossl_old_des_key_schedule ks1,_ossl_old_des_key_schedule ks2, + _ossl_old_des_key_schedule ks3, int enc); +DES_LONG _ossl_old_des_cbc_cksum(_ossl_old_des_cblock *input,_ossl_old_des_cblock *output, + long length,_ossl_old_des_key_schedule schedule,_ossl_old_des_cblock *ivec); +void _ossl_old_des_cbc_encrypt(_ossl_old_des_cblock *input,_ossl_old_des_cblock *output,long length, + _ossl_old_des_key_schedule schedule,_ossl_old_des_cblock *ivec,int enc); +void _ossl_old_des_ncbc_encrypt(_ossl_old_des_cblock *input,_ossl_old_des_cblock *output,long length, + _ossl_old_des_key_schedule schedule,_ossl_old_des_cblock *ivec,int enc); +void _ossl_old_des_xcbc_encrypt(_ossl_old_des_cblock *input,_ossl_old_des_cblock *output,long length, + _ossl_old_des_key_schedule schedule,_ossl_old_des_cblock *ivec, + _ossl_old_des_cblock *inw,_ossl_old_des_cblock *outw,int enc); +void _ossl_old_des_cfb_encrypt(unsigned char *in,unsigned char *out,int numbits, + long length,_ossl_old_des_key_schedule schedule,_ossl_old_des_cblock *ivec,int enc); +void _ossl_old_des_ecb_encrypt(_ossl_old_des_cblock *input,_ossl_old_des_cblock *output, + _ossl_old_des_key_schedule ks,int enc); +void _ossl_old_des_encrypt(DES_LONG *data,_ossl_old_des_key_schedule ks, int enc); +void _ossl_old_des_encrypt2(DES_LONG *data,_ossl_old_des_key_schedule ks, int enc); +void _ossl_old_des_encrypt3(DES_LONG *data, _ossl_old_des_key_schedule ks1, + _ossl_old_des_key_schedule ks2, _ossl_old_des_key_schedule ks3); +void _ossl_old_des_decrypt3(DES_LONG *data, _ossl_old_des_key_schedule ks1, + _ossl_old_des_key_schedule ks2, _ossl_old_des_key_schedule ks3); +void _ossl_old_des_ede3_cbc_encrypt(_ossl_old_des_cblock *input, _ossl_old_des_cblock *output, + long length, _ossl_old_des_key_schedule ks1, _ossl_old_des_key_schedule ks2, + _ossl_old_des_key_schedule ks3, _ossl_old_des_cblock *ivec, int enc); +void _ossl_old_des_ede3_cfb64_encrypt(unsigned char *in, unsigned char *out, + long length, _ossl_old_des_key_schedule ks1, _ossl_old_des_key_schedule ks2, + _ossl_old_des_key_schedule ks3, _ossl_old_des_cblock *ivec, int *num, int enc); +void _ossl_old_des_ede3_ofb64_encrypt(unsigned char *in, unsigned char *out, + long length, _ossl_old_des_key_schedule ks1, _ossl_old_des_key_schedule ks2, + _ossl_old_des_key_schedule ks3, _ossl_old_des_cblock *ivec, int *num); +#if 0 +void _ossl_old_des_xwhite_in2out(_ossl_old_des_cblock (*des_key), _ossl_old_des_cblock (*in_white), + _ossl_old_des_cblock (*out_white)); +#endif + +int _ossl_old_des_enc_read(int fd,char *buf,int len,_ossl_old_des_key_schedule sched, + _ossl_old_des_cblock *iv); +int _ossl_old_des_enc_write(int fd,char *buf,int len,_ossl_old_des_key_schedule sched, + _ossl_old_des_cblock *iv); +char *_ossl_old_des_fcrypt(const char *buf,const char *salt, char *ret); +char *_ossl_old_des_crypt(const char *buf,const char *salt); +#if !defined(PERL5) && !defined(NeXT) +char *_ossl_old_crypt(const char *buf,const char *salt); +#endif +void _ossl_old_des_ofb_encrypt(unsigned char *in,unsigned char *out, + int numbits,long length,_ossl_old_des_key_schedule schedule,_ossl_old_des_cblock *ivec); +void _ossl_old_des_pcbc_encrypt(_ossl_old_des_cblock *input,_ossl_old_des_cblock *output,long length, + _ossl_old_des_key_schedule schedule,_ossl_old_des_cblock *ivec,int enc); +DES_LONG _ossl_old_des_quad_cksum(_ossl_old_des_cblock *input,_ossl_old_des_cblock *output, + long length,int out_count,_ossl_old_des_cblock *seed); +void _ossl_old_des_random_seed(_ossl_old_des_cblock key); +void _ossl_old_des_random_key(_ossl_old_des_cblock ret); +int _ossl_old_des_read_password(_ossl_old_des_cblock *key,const char *prompt,int verify); +int _ossl_old_des_read_2passwords(_ossl_old_des_cblock *key1,_ossl_old_des_cblock *key2, + const char *prompt,int verify); +void _ossl_old_des_set_odd_parity(_ossl_old_des_cblock *key); +int _ossl_old_des_is_weak_key(_ossl_old_des_cblock *key); +int _ossl_old_des_set_key(_ossl_old_des_cblock *key,_ossl_old_des_key_schedule schedule); +int _ossl_old_des_key_sched(_ossl_old_des_cblock *key,_ossl_old_des_key_schedule schedule); +void _ossl_old_des_string_to_key(char *str,_ossl_old_des_cblock *key); +void _ossl_old_des_string_to_2keys(char *str,_ossl_old_des_cblock *key1,_ossl_old_des_cblock *key2); +void _ossl_old_des_cfb64_encrypt(unsigned char *in, unsigned char *out, long length, + _ossl_old_des_key_schedule schedule, _ossl_old_des_cblock *ivec, int *num, int enc); +void _ossl_old_des_ofb64_encrypt(unsigned char *in, unsigned char *out, long length, + _ossl_old_des_key_schedule schedule, _ossl_old_des_cblock *ivec, int *num); + +void _ossl_096_des_random_seed(des_cblock *key); + +/* The following definitions provide compatibility with the MIT Kerberos + * library. The _ossl_old_des_key_schedule structure is not binary compatible. */ + +#define _KERBEROS_DES_H + +#define KRBDES_ENCRYPT DES_ENCRYPT +#define KRBDES_DECRYPT DES_DECRYPT + +#ifdef KERBEROS +# define ENCRYPT DES_ENCRYPT +# define DECRYPT DES_DECRYPT +#endif + +#ifndef NCOMPAT +# define C_Block des_cblock +# define Key_schedule des_key_schedule +# define KEY_SZ DES_KEY_SZ +# define string_to_key des_string_to_key +# define read_pw_string des_read_pw_string +# define random_key des_random_key +# define pcbc_encrypt des_pcbc_encrypt +# define set_key des_set_key +# define key_sched des_key_sched +# define ecb_encrypt des_ecb_encrypt +# define cbc_encrypt des_cbc_encrypt +# define ncbc_encrypt des_ncbc_encrypt +# define xcbc_encrypt des_xcbc_encrypt +# define cbc_cksum des_cbc_cksum +# define quad_cksum des_quad_cksum +# define check_parity des_check_key_parity +#endif + +#define des_fixup_key_parity DES_fixup_key_parity + +#ifdef __cplusplus +} +#endif + +/* for DES_read_pw_string et al */ +#include + +#endif diff --git a/lib_tls/include/openssl/dh.h b/lib_tls/include/openssl/dh.h new file mode 100644 index 000000000..ccdf35ae1 --- /dev/null +++ b/lib_tls/include/openssl/dh.h @@ -0,0 +1,234 @@ +/* crypto/dh/dh.h */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#ifndef HEADER_DH_H +#define HEADER_DH_H + +#include + +#ifdef OPENSSL_NO_DH +#error DH is disabled. +#endif + +#ifndef OPENSSL_NO_BIO +#include +#endif +#include +#ifndef OPENSSL_NO_DEPRECATED +#include +#endif + +#ifndef OPENSSL_DH_MAX_MODULUS_BITS +# define OPENSSL_DH_MAX_MODULUS_BITS 10000 +#endif + +#define DH_FLAG_CACHE_MONT_P 0x01 +#define DH_FLAG_NO_EXP_CONSTTIME 0x02 /* new with 0.9.7h; the built-in DH + * implementation now uses constant time + * modular exponentiation for secret exponents + * by default. This flag causes the + * faster variable sliding window method to + * be used for all exponents. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Already defined in ossl_typ.h */ +/* typedef struct dh_st DH; */ +/* typedef struct dh_method DH_METHOD; */ + +struct dh_method + { + const char *name; + /* Methods here */ + int (*generate_key)(DH *dh); + int (*compute_key)(unsigned char *key,const BIGNUM *pub_key,DH *dh); + int (*bn_mod_exp)(const DH *dh, BIGNUM *r, const BIGNUM *a, + const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx, + BN_MONT_CTX *m_ctx); /* Can be null */ + + int (*init)(DH *dh); + int (*finish)(DH *dh); + int flags; + char *app_data; + /* If this is non-NULL, it will be used to generate parameters */ + int (*generate_params)(DH *dh, int prime_len, int generator, BN_GENCB *cb); + }; + +struct dh_st + { + /* This first argument is used to pick up errors when + * a DH is passed instead of a EVP_PKEY */ + int pad; + int version; + BIGNUM *p; + BIGNUM *g; + long length; /* optional */ + BIGNUM *pub_key; /* g^x */ + BIGNUM *priv_key; /* x */ + + int flags; + BN_MONT_CTX *method_mont_p; + /* Place holders if we want to do X9.42 DH */ + BIGNUM *q; + BIGNUM *j; + unsigned char *seed; + int seedlen; + BIGNUM *counter; + + int references; + CRYPTO_EX_DATA ex_data; + const DH_METHOD *meth; + ENGINE *engine; + }; + +#define DH_GENERATOR_2 2 +/* #define DH_GENERATOR_3 3 */ +#define DH_GENERATOR_5 5 + +/* DH_check error codes */ +#define DH_CHECK_P_NOT_PRIME 0x01 +#define DH_CHECK_P_NOT_SAFE_PRIME 0x02 +#define DH_UNABLE_TO_CHECK_GENERATOR 0x04 +#define DH_NOT_SUITABLE_GENERATOR 0x08 + +/* DH_check_pub_key error codes */ +#define DH_CHECK_PUBKEY_TOO_SMALL 0x01 +#define DH_CHECK_PUBKEY_TOO_LARGE 0x02 + +/* primes p where (p-1)/2 is prime too are called "safe"; we define + this for backward compatibility: */ +#define DH_CHECK_P_NOT_STRONG_PRIME DH_CHECK_P_NOT_SAFE_PRIME + +#define DHparams_dup(x) ASN1_dup_of_const(DH,i2d_DHparams,d2i_DHparams,x) +#define d2i_DHparams_fp(fp,x) (DH *)ASN1_d2i_fp((char *(*)())DH_new, \ + (char *(*)())d2i_DHparams,(fp),(unsigned char **)(x)) +#define i2d_DHparams_fp(fp,x) ASN1_i2d_fp(i2d_DHparams,(fp), \ + (unsigned char *)(x)) +#define d2i_DHparams_bio(bp,x) ASN1_d2i_bio_of(DH,DH_new,d2i_DHparams,bp,x) +#define i2d_DHparams_bio(bp,x) ASN1_i2d_bio_of_const(DH,i2d_DHparams,bp,x) + +const DH_METHOD *DH_OpenSSL(void); + +void DH_set_default_method(const DH_METHOD *meth); +const DH_METHOD *DH_get_default_method(void); +int DH_set_method(DH *dh, const DH_METHOD *meth); +DH *DH_new_method(ENGINE *engine); + +DH * DH_new(void); +void DH_free(DH *dh); +int DH_up_ref(DH *dh); +int DH_size(const DH *dh); +int DH_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func, + CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func); +int DH_set_ex_data(DH *d, int idx, void *arg); +void *DH_get_ex_data(DH *d, int idx); + +/* Deprecated version */ +#ifndef OPENSSL_NO_DEPRECATED +DH * DH_generate_parameters(int prime_len,int generator, + void (*callback)(int,int,void *),void *cb_arg); +#endif /* !defined(OPENSSL_NO_DEPRECATED) */ + +/* New version */ +int DH_generate_parameters_ex(DH *dh, int prime_len,int generator, BN_GENCB *cb); + +int DH_check(const DH *dh,int *codes); +int DH_check_pub_key(const DH *dh,const BIGNUM *pub_key, int *codes); +int DH_generate_key(DH *dh); +int DH_compute_key(unsigned char *key,const BIGNUM *pub_key,DH *dh); +DH * d2i_DHparams(DH **a,const unsigned char **pp, long length); +int i2d_DHparams(const DH *a,unsigned char **pp); +#ifndef OPENSSL_NO_FP_API +int DHparams_print_fp(FILE *fp, const DH *x); +#endif +#ifndef OPENSSL_NO_BIO +int DHparams_print(BIO *bp, const DH *x); +#else +int DHparams_print(char *bp, const DH *x); +#endif + +/* BEGIN ERROR CODES */ +/* The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ +void ERR_load_DH_strings(void); + +/* Error codes for the DH functions. */ + +/* Function codes. */ +#define DH_F_COMPUTE_KEY 102 +#define DH_F_DHPARAMS_PRINT 100 +#define DH_F_DHPARAMS_PRINT_FP 101 +#define DH_F_DH_BUILTIN_GENPARAMS 106 +#define DH_F_DH_NEW_METHOD 105 +#define DH_F_GENERATE_KEY 103 +#define DH_F_GENERATE_PARAMETERS 104 + +/* Reason codes. */ +#define DH_R_BAD_GENERATOR 101 +#define DH_R_INVALID_PUBKEY 102 +#define DH_R_MODULUS_TOO_LARGE 103 +#define DH_R_NO_PRIVATE_VALUE 100 + +#ifdef __cplusplus +} +#endif +#endif diff --git a/lib_tls/include/openssl/dsa.h b/lib_tls/include/openssl/dsa.h new file mode 100644 index 000000000..3a8fe5b56 --- /dev/null +++ b/lib_tls/include/openssl/dsa.h @@ -0,0 +1,285 @@ +/* crypto/dsa/dsa.h */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +/* + * The DSS routines are based on patches supplied by + * Steven Schoch . He basically did the + * work and I have just tweaked them a little to fit into my + * stylistic vision for SSLeay :-) */ + +#ifndef HEADER_DSA_H +#define HEADER_DSA_H + +#include + +#ifdef OPENSSL_NO_DSA +#error DSA is disabled. +#endif + +#ifndef OPENSSL_NO_BIO +#include +#endif +#include +#include + +#ifndef OPENSSL_NO_DEPRECATED +#include +#ifndef OPENSSL_NO_DH +# include +#endif +#endif + +#ifndef OPENSSL_DSA_MAX_MODULUS_BITS +# define OPENSSL_DSA_MAX_MODULUS_BITS 10000 +#endif + +#define DSA_FLAG_CACHE_MONT_P 0x01 +#define DSA_FLAG_NO_EXP_CONSTTIME 0x02 /* new with 0.9.7h; the built-in DSA + * implementation now uses constant time + * modular exponentiation for secret exponents + * by default. This flag causes the + * faster variable sliding window method to + * be used for all exponents. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Already defined in ossl_typ.h */ +/* typedef struct dsa_st DSA; */ +/* typedef struct dsa_method DSA_METHOD; */ + +typedef struct DSA_SIG_st + { + BIGNUM *r; + BIGNUM *s; + } DSA_SIG; + +struct dsa_method + { + const char *name; + DSA_SIG * (*dsa_do_sign)(const unsigned char *dgst, int dlen, DSA *dsa); + int (*dsa_sign_setup)(DSA *dsa, BN_CTX *ctx_in, BIGNUM **kinvp, + BIGNUM **rp); + int (*dsa_do_verify)(const unsigned char *dgst, int dgst_len, + DSA_SIG *sig, DSA *dsa); + int (*dsa_mod_exp)(DSA *dsa, BIGNUM *rr, BIGNUM *a1, BIGNUM *p1, + BIGNUM *a2, BIGNUM *p2, BIGNUM *m, BN_CTX *ctx, + BN_MONT_CTX *in_mont); + int (*bn_mod_exp)(DSA *dsa, BIGNUM *r, BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx, + BN_MONT_CTX *m_ctx); /* Can be null */ + int (*init)(DSA *dsa); + int (*finish)(DSA *dsa); + int flags; + char *app_data; + /* If this is non-NULL, it is used to generate DSA parameters */ + int (*dsa_paramgen)(DSA *dsa, int bits, + unsigned char *seed, int seed_len, + int *counter_ret, unsigned long *h_ret, + BN_GENCB *cb); + /* If this is non-NULL, it is used to generate DSA keys */ + int (*dsa_keygen)(DSA *dsa); + }; + +struct dsa_st + { + /* This first variable is used to pick up errors where + * a DSA is passed instead of of a EVP_PKEY */ + int pad; + long version; + int write_params; + BIGNUM *p; + BIGNUM *q; /* == 20 */ + BIGNUM *g; + + BIGNUM *pub_key; /* y public key */ + BIGNUM *priv_key; /* x private key */ + + BIGNUM *kinv; /* Signing pre-calc */ + BIGNUM *r; /* Signing pre-calc */ + + int flags; + /* Normally used to cache montgomery values */ + BN_MONT_CTX *method_mont_p; + int references; + CRYPTO_EX_DATA ex_data; + const DSA_METHOD *meth; + /* functional reference if 'meth' is ENGINE-provided */ + ENGINE *engine; + }; + +#define DSAparams_dup(x) ASN1_dup_of_const(DSA,i2d_DSAparams,d2i_DSAparams,x) +#define d2i_DSAparams_fp(fp,x) (DSA *)ASN1_d2i_fp((char *(*)())DSA_new, \ + (char *(*)())d2i_DSAparams,(fp),(unsigned char **)(x)) +#define i2d_DSAparams_fp(fp,x) ASN1_i2d_fp(i2d_DSAparams,(fp), \ + (unsigned char *)(x)) +#define d2i_DSAparams_bio(bp,x) ASN1_d2i_bio_of(DSA,DSA_new,d2i_DSAparams,bp,x) +#define i2d_DSAparams_bio(bp,x) ASN1_i2d_bio_of_const(DSA,i2d_DSAparams,bp,x) + + +DSA_SIG * DSA_SIG_new(void); +void DSA_SIG_free(DSA_SIG *a); +int i2d_DSA_SIG(const DSA_SIG *a, unsigned char **pp); +DSA_SIG * d2i_DSA_SIG(DSA_SIG **v, const unsigned char **pp, long length); + +DSA_SIG * DSA_do_sign(const unsigned char *dgst,int dlen,DSA *dsa); +int DSA_do_verify(const unsigned char *dgst,int dgst_len, + DSA_SIG *sig,DSA *dsa); + +const DSA_METHOD *DSA_OpenSSL(void); + +void DSA_set_default_method(const DSA_METHOD *); +const DSA_METHOD *DSA_get_default_method(void); +int DSA_set_method(DSA *dsa, const DSA_METHOD *); + +DSA * DSA_new(void); +DSA * DSA_new_method(ENGINE *engine); +void DSA_free (DSA *r); +/* "up" the DSA object's reference count */ +int DSA_up_ref(DSA *r); +int DSA_size(const DSA *); + /* next 4 return -1 on error */ +int DSA_sign_setup( DSA *dsa,BN_CTX *ctx_in,BIGNUM **kinvp,BIGNUM **rp); +int DSA_sign(int type,const unsigned char *dgst,int dlen, + unsigned char *sig, unsigned int *siglen, DSA *dsa); +int DSA_verify(int type,const unsigned char *dgst,int dgst_len, + const unsigned char *sigbuf, int siglen, DSA *dsa); +int DSA_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func, + CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func); +int DSA_set_ex_data(DSA *d, int idx, void *arg); +void *DSA_get_ex_data(DSA *d, int idx); + +DSA * d2i_DSAPublicKey(DSA **a, const unsigned char **pp, long length); +DSA * d2i_DSAPrivateKey(DSA **a, const unsigned char **pp, long length); +DSA * d2i_DSAparams(DSA **a, const unsigned char **pp, long length); + +/* Deprecated version */ +#ifndef OPENSSL_NO_DEPRECATED +DSA * DSA_generate_parameters(int bits, + unsigned char *seed,int seed_len, + int *counter_ret, unsigned long *h_ret,void + (*callback)(int, int, void *),void *cb_arg); +#endif /* !defined(OPENSSL_NO_DEPRECATED) */ + +/* New version */ +int DSA_generate_parameters_ex(DSA *dsa, int bits, + unsigned char *seed,int seed_len, + int *counter_ret, unsigned long *h_ret, BN_GENCB *cb); + +int DSA_generate_key(DSA *a); +int i2d_DSAPublicKey(const DSA *a, unsigned char **pp); +int i2d_DSAPrivateKey(const DSA *a, unsigned char **pp); +int i2d_DSAparams(const DSA *a,unsigned char **pp); + +#ifndef OPENSSL_NO_BIO +int DSAparams_print(BIO *bp, const DSA *x); +int DSA_print(BIO *bp, const DSA *x, int off); +#endif +#ifndef OPENSSL_NO_FP_API +int DSAparams_print_fp(FILE *fp, const DSA *x); +int DSA_print_fp(FILE *bp, const DSA *x, int off); +#endif + +#define DSS_prime_checks 50 +/* Primality test according to FIPS PUB 186[-1], Appendix 2.1: + * 50 rounds of Rabin-Miller */ +#define DSA_is_prime(n, callback, cb_arg) \ + BN_is_prime(n, DSS_prime_checks, callback, NULL, cb_arg) + +#ifndef OPENSSL_NO_DH +/* Convert DSA structure (key or just parameters) into DH structure + * (be careful to avoid small subgroup attacks when using this!) */ +DH *DSA_dup_DH(const DSA *r); +#endif + +/* BEGIN ERROR CODES */ +/* The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ +void ERR_load_DSA_strings(void); + +/* Error codes for the DSA functions. */ + +/* Function codes. */ +#define DSA_F_D2I_DSA_SIG 110 +#define DSA_F_DSAPARAMS_PRINT 100 +#define DSA_F_DSAPARAMS_PRINT_FP 101 +#define DSA_F_DSA_DO_SIGN 112 +#define DSA_F_DSA_DO_VERIFY 113 +#define DSA_F_DSA_NEW_METHOD 103 +#define DSA_F_DSA_PRINT 104 +#define DSA_F_DSA_PRINT_FP 105 +#define DSA_F_DSA_SIGN 106 +#define DSA_F_DSA_SIGN_SETUP 107 +#define DSA_F_DSA_SIG_NEW 109 +#define DSA_F_DSA_VERIFY 108 +#define DSA_F_I2D_DSA_SIG 111 +#define DSA_F_SIG_CB 114 + +/* Reason codes. */ +#define DSA_R_BAD_Q_VALUE 102 +#define DSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE 100 +#define DSA_R_MISSING_PARAMETERS 101 +#define DSA_R_MODULUS_TOO_LARGE 103 + +#ifdef __cplusplus +} +#endif +#endif diff --git a/lib_tls/include/openssl/dso.h b/lib_tls/include/openssl/dso.h new file mode 100644 index 000000000..3e51913a7 --- /dev/null +++ b/lib_tls/include/openssl/dso.h @@ -0,0 +1,368 @@ +/* dso.h -*- mode:C; c-file-style: "eay" -*- */ +/* Written by Geoff Thorpe (geoff@geoffthorpe.net) for the OpenSSL + * project 2000. + */ +/* ==================================================================== + * Copyright (c) 2000 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#ifndef HEADER_DSO_H +#define HEADER_DSO_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* These values are used as commands to DSO_ctrl() */ +#define DSO_CTRL_GET_FLAGS 1 +#define DSO_CTRL_SET_FLAGS 2 +#define DSO_CTRL_OR_FLAGS 3 + +/* By default, DSO_load() will translate the provided filename into a form + * typical for the platform (more specifically the DSO_METHOD) using the + * dso_name_converter function of the method. Eg. win32 will transform "blah" + * into "blah.dll", and dlfcn will transform it into "libblah.so". The + * behaviour can be overriden by setting the name_converter callback in the DSO + * object (using DSO_set_name_converter()). This callback could even utilise + * the DSO_METHOD's converter too if it only wants to override behaviour for + * one or two possible DSO methods. However, the following flag can be set in a + * DSO to prevent *any* native name-translation at all - eg. if the caller has + * prompted the user for a path to a driver library so the filename should be + * interpreted as-is. */ +#define DSO_FLAG_NO_NAME_TRANSLATION 0x01 +/* An extra flag to give if only the extension should be added as + * translation. This is obviously only of importance on Unix and + * other operating systems where the translation also may prefix + * the name with something, like 'lib', and ignored everywhere else. + * This flag is also ignored if DSO_FLAG_NO_NAME_TRANSLATION is used + * at the same time. */ +#define DSO_FLAG_NAME_TRANSLATION_EXT_ONLY 0x02 + +/* The following flag controls the translation of symbol names to upper + * case. This is currently only being implemented for OpenVMS. + */ +#define DSO_FLAG_UPCASE_SYMBOL 0x10 + +/* This flag loads the library with public symbols. + * Meaning: The exported symbols of this library are public + * to all libraries loaded after this library. + * At the moment only implemented in unix. + */ +#define DSO_FLAG_GLOBAL_SYMBOLS 0x20 + + +typedef void (*DSO_FUNC_TYPE)(void); + +typedef struct dso_st DSO; + +/* The function prototype used for method functions (or caller-provided + * callbacks) that transform filenames. They are passed a DSO structure pointer + * (or NULL if they are to be used independantly of a DSO object) and a + * filename to transform. They should either return NULL (if there is an error + * condition) or a newly allocated string containing the transformed form that + * the caller will need to free with OPENSSL_free() when done. */ +typedef char* (*DSO_NAME_CONVERTER_FUNC)(DSO *, const char *); +/* The function prototype used for method functions (or caller-provided + * callbacks) that merge two file specifications. They are passed a + * DSO structure pointer (or NULL if they are to be used independantly of + * a DSO object) and two file specifications to merge. They should + * either return NULL (if there is an error condition) or a newly allocated + * string containing the result of merging that the caller will need + * to free with OPENSSL_free() when done. + * Here, merging means that bits and pieces are taken from each of the + * file specifications and added together in whatever fashion that is + * sensible for the DSO method in question. The only rule that really + * applies is that if the two specification contain pieces of the same + * type, the copy from the first string takes priority. One could see + * it as the first specification is the one given by the user and the + * second being a bunch of defaults to add on if they're missing in the + * first. */ +typedef char* (*DSO_MERGER_FUNC)(DSO *, const char *, const char *); + +typedef struct dso_meth_st + { + const char *name; + /* Loads a shared library, NB: new DSO_METHODs must ensure that a + * successful load populates the loaded_filename field, and likewise a + * successful unload OPENSSL_frees and NULLs it out. */ + int (*dso_load)(DSO *dso); + /* Unloads a shared library */ + int (*dso_unload)(DSO *dso); + /* Binds a variable */ + void *(*dso_bind_var)(DSO *dso, const char *symname); + /* Binds a function - assumes a return type of DSO_FUNC_TYPE. + * This should be cast to the real function prototype by the + * caller. Platforms that don't have compatible representations + * for different prototypes (this is possible within ANSI C) + * are highly unlikely to have shared libraries at all, let + * alone a DSO_METHOD implemented for them. */ + DSO_FUNC_TYPE (*dso_bind_func)(DSO *dso, const char *symname); + +/* I don't think this would actually be used in any circumstances. */ +#if 0 + /* Unbinds a variable */ + int (*dso_unbind_var)(DSO *dso, char *symname, void *symptr); + /* Unbinds a function */ + int (*dso_unbind_func)(DSO *dso, char *symname, DSO_FUNC_TYPE symptr); +#endif + /* The generic (yuck) "ctrl()" function. NB: Negative return + * values (rather than zero) indicate errors. */ + long (*dso_ctrl)(DSO *dso, int cmd, long larg, void *parg); + /* The default DSO_METHOD-specific function for converting filenames to + * a canonical native form. */ + DSO_NAME_CONVERTER_FUNC dso_name_converter; + /* The default DSO_METHOD-specific function for converting filenames to + * a canonical native form. */ + DSO_MERGER_FUNC dso_merger; + + /* [De]Initialisation handlers. */ + int (*init)(DSO *dso); + int (*finish)(DSO *dso); + } DSO_METHOD; + +/**********************************************************************/ +/* The low-level handle type used to refer to a loaded shared library */ + +struct dso_st + { + DSO_METHOD *meth; + /* Standard dlopen uses a (void *). Win32 uses a HANDLE. VMS + * doesn't use anything but will need to cache the filename + * for use in the dso_bind handler. All in all, let each + * method control its own destiny. "Handles" and such go in + * a STACK. */ + STACK *meth_data; + int references; + int flags; + /* For use by applications etc ... use this for your bits'n'pieces, + * don't touch meth_data! */ + CRYPTO_EX_DATA ex_data; + /* If this callback function pointer is set to non-NULL, then it will + * be used in DSO_load() in place of meth->dso_name_converter. NB: This + * should normally set using DSO_set_name_converter(). */ + DSO_NAME_CONVERTER_FUNC name_converter; + /* If this callback function pointer is set to non-NULL, then it will + * be used in DSO_load() in place of meth->dso_merger. NB: This + * should normally set using DSO_set_merger(). */ + DSO_MERGER_FUNC merger; + /* This is populated with (a copy of) the platform-independant + * filename used for this DSO. */ + char *filename; + /* This is populated with (a copy of) the translated filename by which + * the DSO was actually loaded. It is NULL iff the DSO is not currently + * loaded. NB: This is here because the filename translation process + * may involve a callback being invoked more than once not only to + * convert to a platform-specific form, but also to try different + * filenames in the process of trying to perform a load. As such, this + * variable can be used to indicate (a) whether this DSO structure + * corresponds to a loaded library or not, and (b) the filename with + * which it was actually loaded. */ + char *loaded_filename; + }; + + +DSO * DSO_new(void); +DSO * DSO_new_method(DSO_METHOD *method); +int DSO_free(DSO *dso); +int DSO_flags(DSO *dso); +int DSO_up_ref(DSO *dso); +long DSO_ctrl(DSO *dso, int cmd, long larg, void *parg); + +/* This function sets the DSO's name_converter callback. If it is non-NULL, + * then it will be used instead of the associated DSO_METHOD's function. If + * oldcb is non-NULL then it is set to the function pointer value being + * replaced. Return value is non-zero for success. */ +int DSO_set_name_converter(DSO *dso, DSO_NAME_CONVERTER_FUNC cb, + DSO_NAME_CONVERTER_FUNC *oldcb); +/* These functions can be used to get/set the platform-independant filename + * used for a DSO. NB: set will fail if the DSO is already loaded. */ +const char *DSO_get_filename(DSO *dso); +int DSO_set_filename(DSO *dso, const char *filename); +/* This function will invoke the DSO's name_converter callback to translate a + * filename, or if the callback isn't set it will instead use the DSO_METHOD's + * converter. If "filename" is NULL, the "filename" in the DSO itself will be + * used. If the DSO_FLAG_NO_NAME_TRANSLATION flag is set, then the filename is + * simply duplicated. NB: This function is usually called from within a + * DSO_METHOD during the processing of a DSO_load() call, and is exposed so that + * caller-created DSO_METHODs can do the same thing. A non-NULL return value + * will need to be OPENSSL_free()'d. */ +char *DSO_convert_filename(DSO *dso, const char *filename); +/* This function will invoke the DSO's merger callback to merge two file + * specifications, or if the callback isn't set it will instead use the + * DSO_METHOD's merger. A non-NULL return value will need to be + * OPENSSL_free()'d. */ +char *DSO_merge(DSO *dso, const char *filespec1, const char *filespec2); +/* If the DSO is currently loaded, this returns the filename that it was loaded + * under, otherwise it returns NULL. So it is also useful as a test as to + * whether the DSO is currently loaded. NB: This will not necessarily return + * the same value as DSO_convert_filename(dso, dso->filename), because the + * DSO_METHOD's load function may have tried a variety of filenames (with + * and/or without the aid of the converters) before settling on the one it + * actually loaded. */ +const char *DSO_get_loaded_filename(DSO *dso); + +void DSO_set_default_method(DSO_METHOD *meth); +DSO_METHOD *DSO_get_default_method(void); +DSO_METHOD *DSO_get_method(DSO *dso); +DSO_METHOD *DSO_set_method(DSO *dso, DSO_METHOD *meth); + +/* The all-singing all-dancing load function, you normally pass NULL + * for the first and third parameters. Use DSO_up and DSO_free for + * subsequent reference count handling. Any flags passed in will be set + * in the constructed DSO after its init() function but before the + * load operation. If 'dso' is non-NULL, 'flags' is ignored. */ +DSO *DSO_load(DSO *dso, const char *filename, DSO_METHOD *meth, int flags); + +/* This function binds to a variable inside a shared library. */ +void *DSO_bind_var(DSO *dso, const char *symname); + +/* This function binds to a function inside a shared library. */ +DSO_FUNC_TYPE DSO_bind_func(DSO *dso, const char *symname); + +/* This method is the default, but will beg, borrow, or steal whatever + * method should be the default on any particular platform (including + * DSO_METH_null() if necessary). */ +DSO_METHOD *DSO_METHOD_openssl(void); + +/* This method is defined for all platforms - if a platform has no + * DSO support then this will be the only method! */ +DSO_METHOD *DSO_METHOD_null(void); + +/* If DSO_DLFCN is defined, the standard dlfcn.h-style functions + * (dlopen, dlclose, dlsym, etc) will be used and incorporated into + * this method. If not, this method will return NULL. */ +DSO_METHOD *DSO_METHOD_dlfcn(void); + +/* If DSO_DL is defined, the standard dl.h-style functions (shl_load, + * shl_unload, shl_findsym, etc) will be used and incorporated into + * this method. If not, this method will return NULL. */ +DSO_METHOD *DSO_METHOD_dl(void); + +/* If WIN32 is defined, use DLLs. If not, return NULL. */ +DSO_METHOD *DSO_METHOD_win32(void); + +/* If VMS is defined, use shared images. If not, return NULL. */ +DSO_METHOD *DSO_METHOD_vms(void); + +/* BEGIN ERROR CODES */ +/* The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ +void ERR_load_DSO_strings(void); + +/* Error codes for the DSO functions. */ + +/* Function codes. */ +#define DSO_F_DLFCN_BIND_FUNC 100 +#define DSO_F_DLFCN_BIND_VAR 101 +#define DSO_F_DLFCN_LOAD 102 +#define DSO_F_DLFCN_MERGER 130 +#define DSO_F_DLFCN_NAME_CONVERTER 123 +#define DSO_F_DLFCN_UNLOAD 103 +#define DSO_F_DL_BIND_FUNC 104 +#define DSO_F_DL_BIND_VAR 105 +#define DSO_F_DL_LOAD 106 +#define DSO_F_DL_MERGER 131 +#define DSO_F_DL_NAME_CONVERTER 124 +#define DSO_F_DL_UNLOAD 107 +#define DSO_F_DSO_BIND_FUNC 108 +#define DSO_F_DSO_BIND_VAR 109 +#define DSO_F_DSO_CONVERT_FILENAME 126 +#define DSO_F_DSO_CTRL 110 +#define DSO_F_DSO_FREE 111 +#define DSO_F_DSO_GET_FILENAME 127 +#define DSO_F_DSO_GET_LOADED_FILENAME 128 +#define DSO_F_DSO_LOAD 112 +#define DSO_F_DSO_MERGE 132 +#define DSO_F_DSO_NEW_METHOD 113 +#define DSO_F_DSO_SET_FILENAME 129 +#define DSO_F_DSO_SET_NAME_CONVERTER 122 +#define DSO_F_DSO_UP_REF 114 +#define DSO_F_VMS_BIND_SYM 115 +#define DSO_F_VMS_LOAD 116 +#define DSO_F_VMS_MERGER 133 +#define DSO_F_VMS_UNLOAD 117 +#define DSO_F_WIN32_BIND_FUNC 118 +#define DSO_F_WIN32_BIND_VAR 119 +#define DSO_F_WIN32_JOINER 135 +#define DSO_F_WIN32_LOAD 120 +#define DSO_F_WIN32_MERGER 134 +#define DSO_F_WIN32_NAME_CONVERTER 125 +#define DSO_F_WIN32_SPLITTER 136 +#define DSO_F_WIN32_UNLOAD 121 + +/* Reason codes. */ +#define DSO_R_CTRL_FAILED 100 +#define DSO_R_DSO_ALREADY_LOADED 110 +#define DSO_R_EMPTY_FILE_STRUCTURE 113 +#define DSO_R_FAILURE 114 +#define DSO_R_FILENAME_TOO_BIG 101 +#define DSO_R_FINISH_FAILED 102 +#define DSO_R_INCORRECT_FILE_SYNTAX 115 +#define DSO_R_LOAD_FAILED 103 +#define DSO_R_NAME_TRANSLATION_FAILED 109 +#define DSO_R_NO_FILENAME 111 +#define DSO_R_NO_FILE_SPECIFICATION 116 +#define DSO_R_NULL_HANDLE 104 +#define DSO_R_SET_FILENAME_FAILED 112 +#define DSO_R_STACK_ERROR 105 +#define DSO_R_SYM_FAILURE 106 +#define DSO_R_UNLOAD_FAILED 107 +#define DSO_R_UNSUPPORTED 108 + +#ifdef __cplusplus +} +#endif +#endif diff --git a/lib_tls/include/openssl/dtls1.h b/lib_tls/include/openssl/dtls1.h new file mode 100644 index 000000000..a663cf85f --- /dev/null +++ b/lib_tls/include/openssl/dtls1.h @@ -0,0 +1,211 @@ +/* ssl/dtls1.h */ +/* + * DTLS implementation written by Nagendra Modadugu + * (nagendra@cs.stanford.edu) for the OpenSSL project 2005. + */ +/* ==================================================================== + * Copyright (c) 1999-2005 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#ifndef HEADER_DTLS1_H +#define HEADER_DTLS1_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define DTLS1_VERSION 0xFEFF +#define DTLS1_BAD_VER 0x0100 + +#define DTLS1_AD_MISSING_HANDSHAKE_MESSAGE 110 + +/* lengths of messages */ +#define DTLS1_COOKIE_LENGTH 32 + +#define DTLS1_RT_HEADER_LENGTH 13 + +#define DTLS1_HM_HEADER_LENGTH 12 + +#define DTLS1_HM_BAD_FRAGMENT -2 +#define DTLS1_HM_FRAGMENT_RETRY -3 + +#define DTLS1_CCS_HEADER_LENGTH 1 + +#define DTLS1_AL_HEADER_LENGTH 7 + + +typedef struct dtls1_bitmap_st + { + PQ_64BIT map; + unsigned long length; /* sizeof the bitmap in bits */ + PQ_64BIT max_seq_num; /* max record number seen so far */ + } DTLS1_BITMAP; + +struct hm_header_st + { + unsigned char type; + unsigned long msg_len; + unsigned short seq; + unsigned long frag_off; + unsigned long frag_len; + unsigned int is_ccs; + }; + +struct ccs_header_st + { + unsigned char type; + unsigned short seq; + }; + +struct dtls1_timeout_st + { + /* Number of read timeouts so far */ + unsigned int read_timeouts; + + /* Number of write timeouts so far */ + unsigned int write_timeouts; + + /* Number of alerts received so far */ + unsigned int num_alerts; + }; + +typedef struct record_pqueue_st + { + unsigned short epoch; + pqueue q; + } record_pqueue; + +typedef struct hm_fragment_st + { + struct hm_header_st msg_header; + unsigned char *fragment; + } hm_fragment; + +typedef struct dtls1_state_st + { + unsigned int send_cookie; + unsigned char cookie[DTLS1_COOKIE_LENGTH]; + unsigned char rcvd_cookie[DTLS1_COOKIE_LENGTH]; + unsigned int cookie_len; + + /* + * The current data and handshake epoch. This is initially + * undefined, and starts at zero once the initial handshake is + * completed + */ + unsigned short r_epoch; + unsigned short w_epoch; + + /* records being received in the current epoch */ + DTLS1_BITMAP bitmap; + + /* renegotiation starts a new set of sequence numbers */ + DTLS1_BITMAP next_bitmap; + + /* handshake message numbers */ + unsigned short handshake_write_seq; + unsigned short next_handshake_write_seq; + + unsigned short handshake_read_seq; + + /* Received handshake records (processed and unprocessed) */ + record_pqueue unprocessed_rcds; + record_pqueue processed_rcds; + + /* Buffered handshake messages */ + pqueue buffered_messages; + + /* Buffered (sent) handshake records */ + pqueue sent_messages; + + unsigned int mtu; /* max wire packet size */ + + struct hm_header_st w_msg_hdr; + struct hm_header_st r_msg_hdr; + + struct dtls1_timeout_st timeout; + + /* storage for Alert/Handshake protocol data received but not + * yet processed by ssl3_read_bytes: */ + unsigned char alert_fragment[DTLS1_AL_HEADER_LENGTH]; + unsigned int alert_fragment_len; + unsigned char handshake_fragment[DTLS1_HM_HEADER_LENGTH]; + unsigned int handshake_fragment_len; + + unsigned int retransmitting; + + } DTLS1_STATE; + +typedef struct dtls1_record_data_st + { + unsigned char *packet; + unsigned int packet_length; + SSL3_BUFFER rbuf; + SSL3_RECORD rrec; + } DTLS1_RECORD_DATA; + + +/* Timeout multipliers (timeout slice is defined in apps/timeouts.h */ +#define DTLS1_TMO_READ_COUNT 2 +#define DTLS1_TMO_WRITE_COUNT 2 + +#define DTLS1_TMO_ALERT_COUNT 12 + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/lib_tls/include/openssl/e_os2.h b/lib_tls/include/openssl/e_os2.h new file mode 100644 index 000000000..9da0b6544 --- /dev/null +++ b/lib_tls/include/openssl/e_os2.h @@ -0,0 +1,279 @@ +/* e_os2.h */ +/* ==================================================================== + * Copyright (c) 1998-2000 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#include + +#ifndef HEADER_E_OS2_H +#define HEADER_E_OS2_H + +#ifdef __cplusplus +extern "C" { +#endif + +/****************************************************************************** + * Detect operating systems. This probably needs completing. + * The result is that at least one OPENSSL_SYS_os macro should be defined. + * However, if none is defined, Unix is assumed. + **/ + +#define OPENSSL_SYS_UNIX + +/* ----------------------- Macintosh, before MacOS X ----------------------- */ +#if defined(__MWERKS__) && defined(macintosh) || defined(OPENSSL_SYSNAME_MAC) +# undef OPENSSL_SYS_UNIX +# define OPENSSL_SYS_MACINTOSH_CLASSIC +#endif + +/* ----------------------- NetWare ----------------------------------------- */ +#if defined(NETWARE) || defined(OPENSSL_SYSNAME_NETWARE) +# undef OPENSSL_SYS_UNIX +# define OPENSSL_SYS_NETWARE +#endif + +/* ---------------------- Microsoft operating systems ---------------------- */ + +/* Note that MSDOS actually denotes 32-bit environments running on top of + MS-DOS, such as DJGPP one. */ +#if defined(OPENSSL_SYSNAME_MSDOS) +# undef OPENSSL_SYS_UNIX +# define OPENSSL_SYS_MSDOS +#endif + +/* For 32 bit environment, there seems to be the CygWin environment and then + all the others that try to do the same thing Microsoft does... */ +#if defined(OPENSSL_SYSNAME_UWIN) +# undef OPENSSL_SYS_UNIX +# define OPENSSL_SYS_WIN32_UWIN +#else +# if defined(__CYGWIN32__) || defined(OPENSSL_SYSNAME_CYGWIN32) +# undef OPENSSL_SYS_UNIX +# define OPENSSL_SYS_WIN32_CYGWIN +# else +# if defined(_WIN32) || defined(OPENSSL_SYSNAME_WIN32) +# undef OPENSSL_SYS_UNIX +# define OPENSSL_SYS_WIN32 +# endif +# if defined(OPENSSL_SYSNAME_WINNT) +# undef OPENSSL_SYS_UNIX +# define OPENSSL_SYS_WINNT +# endif +# if defined(OPENSSL_SYSNAME_WINCE) +# undef OPENSSL_SYS_UNIX +# define OPENSSL_SYS_WINCE +# endif +# endif +#endif + +/* Anything that tries to look like Microsoft is "Windows" */ +#if defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_WINNT) || defined(OPENSSL_SYS_WINCE) +# undef OPENSSL_SYS_UNIX +# define OPENSSL_SYS_WINDOWS +# ifndef OPENSSL_SYS_MSDOS +# define OPENSSL_SYS_MSDOS +# endif +#endif + +/* DLL settings. This part is a bit tough, because it's up to the application + implementor how he or she will link the application, so it requires some + macro to be used. */ +#ifdef OPENSSL_SYS_WINDOWS +# ifndef OPENSSL_OPT_WINDLL +# if defined(_WINDLL) /* This is used when building OpenSSL to indicate that + DLL linkage should be used */ +# define OPENSSL_OPT_WINDLL +# endif +# endif +#endif + +/* -------------------------------- OpenVMS -------------------------------- */ +#if defined(__VMS) || defined(VMS) || defined(OPENSSL_SYSNAME_VMS) +# undef OPENSSL_SYS_UNIX +# define OPENSSL_SYS_VMS +# if defined(__DECC) +# define OPENSSL_SYS_VMS_DECC +# elif defined(__DECCXX) +# define OPENSSL_SYS_VMS_DECC +# define OPENSSL_SYS_VMS_DECCXX +# else +# define OPENSSL_SYS_VMS_NODECC +# endif +#endif + +/* --------------------------------- OS/2 ---------------------------------- */ +#if defined(__EMX__) || defined(__OS2__) +# undef OPENSSL_SYS_UNIX +# define OPENSSL_SYS_OS2 +#endif + +/* --------------------------------- Unix ---------------------------------- */ +#ifdef OPENSSL_SYS_UNIX +# if defined(linux) || defined(__linux__) || defined(OPENSSL_SYSNAME_LINUX) +# define OPENSSL_SYS_LINUX +# endif +# ifdef OPENSSL_SYSNAME_MPE +# define OPENSSL_SYS_MPE +# endif +# ifdef OPENSSL_SYSNAME_SNI +# define OPENSSL_SYS_SNI +# endif +# ifdef OPENSSL_SYSNAME_ULTRASPARC +# define OPENSSL_SYS_ULTRASPARC +# endif +# ifdef OPENSSL_SYSNAME_NEWS4 +# define OPENSSL_SYS_NEWS4 +# endif +# ifdef OPENSSL_SYSNAME_MACOSX +# define OPENSSL_SYS_MACOSX +# endif +# ifdef OPENSSL_SYSNAME_MACOSX_RHAPSODY +# define OPENSSL_SYS_MACOSX_RHAPSODY +# define OPENSSL_SYS_MACOSX +# endif +# ifdef OPENSSL_SYSNAME_SUNOS +# define OPENSSL_SYS_SUNOS +#endif +# if defined(_CRAY) || defined(OPENSSL_SYSNAME_CRAY) +# define OPENSSL_SYS_CRAY +# endif +# if defined(_AIX) || defined(OPENSSL_SYSNAME_AIX) +# define OPENSSL_SYS_AIX +# endif +#endif + +/* --------------------------------- VOS ----------------------------------- */ +#ifdef OPENSSL_SYSNAME_VOS +# define OPENSSL_SYS_VOS +#endif + +/* ------------------------------- VxWorks --------------------------------- */ +#ifdef OPENSSL_SYSNAME_VXWORKS +# define OPENSSL_SYS_VXWORKS +#endif + +/** + * That's it for OS-specific stuff + *****************************************************************************/ + + +/* Specials for I/O an exit */ +#ifdef OPENSSL_SYS_MSDOS +# define OPENSSL_UNISTD_IO +# define OPENSSL_DECLARE_EXIT extern void exit(int); +#else +# define OPENSSL_UNISTD_IO OPENSSL_UNISTD +# define OPENSSL_DECLARE_EXIT /* declared in unistd.h */ +#endif + +/* Definitions of OPENSSL_GLOBAL and OPENSSL_EXTERN, to define and declare + certain global symbols that, with some compilers under VMS, have to be + defined and declared explicitely with globaldef and globalref. + Definitions of OPENSSL_EXPORT and OPENSSL_IMPORT, to define and declare + DLL exports and imports for compilers under Win32. These are a little + more complicated to use. Basically, for any library that exports some + global variables, the following code must be present in the header file + that declares them, before OPENSSL_EXTERN is used: + + #ifdef SOME_BUILD_FLAG_MACRO + # undef OPENSSL_EXTERN + # define OPENSSL_EXTERN OPENSSL_EXPORT + #endif + + The default is to have OPENSSL_EXPORT, OPENSSL_IMPORT and OPENSSL_GLOBAL + have some generally sensible values, and for OPENSSL_EXTERN to have the + value OPENSSL_IMPORT. +*/ + +#if defined(OPENSSL_SYS_VMS_NODECC) +# define OPENSSL_EXPORT globalref +# define OPENSSL_IMPORT globalref +# define OPENSSL_GLOBAL globaldef +#elif defined(OPENSSL_SYS_WINDOWS) && defined(OPENSSL_OPT_WINDLL) +# define OPENSSL_EXPORT extern __declspec(dllexport) +# define OPENSSL_IMPORT extern __declspec(dllimport) +# define OPENSSL_GLOBAL +#else +# define OPENSSL_EXPORT extern +# define OPENSSL_IMPORT extern +# define OPENSSL_GLOBAL +#endif +#define OPENSSL_EXTERN OPENSSL_IMPORT + +/* Macros to allow global variables to be reached through function calls when + required (if a shared library version requvres it, for example. + The way it's done allows definitions like this: + + // in foobar.c + OPENSSL_IMPLEMENT_GLOBAL(int,foobar) = 0; + // in foobar.h + OPENSSL_DECLARE_GLOBAL(int,foobar); + #define foobar OPENSSL_GLOBAL_REF(foobar) +*/ +#ifdef OPENSSL_EXPORT_VAR_AS_FUNCTION +# define OPENSSL_IMPLEMENT_GLOBAL(type,name) \ + extern type _hide_##name; \ + type *_shadow_##name(void) { return &_hide_##name; } \ + static type _hide_##name +# define OPENSSL_DECLARE_GLOBAL(type,name) type *_shadow_##name(void) +# define OPENSSL_GLOBAL_REF(name) (*(_shadow_##name())) +#else +# define OPENSSL_IMPLEMENT_GLOBAL(type,name) OPENSSL_GLOBAL type _shadow_##name +# define OPENSSL_DECLARE_GLOBAL(type,name) OPENSSL_EXPORT type _shadow_##name +# define OPENSSL_GLOBAL_REF(name) _shadow_##name +#endif + +#ifdef __cplusplus +} +#endif +#endif diff --git a/lib_tls/include/openssl/ebcdic.h b/lib_tls/include/openssl/ebcdic.h new file mode 100644 index 000000000..6d65afcf9 --- /dev/null +++ b/lib_tls/include/openssl/ebcdic.h @@ -0,0 +1,19 @@ +/* crypto/ebcdic.h */ + +#ifndef HEADER_EBCDIC_H +#define HEADER_EBCDIC_H + +#include + +/* Avoid name clashes with other applications */ +#define os_toascii _openssl_os_toascii +#define os_toebcdic _openssl_os_toebcdic +#define ebcdic2ascii _openssl_ebcdic2ascii +#define ascii2ebcdic _openssl_ascii2ebcdic + +extern const unsigned char os_toascii[256]; +extern const unsigned char os_toebcdic[256]; +void *ebcdic2ascii(void *dest, const void *srce, size_t count); +void *ascii2ebcdic(void *dest, const void *srce, size_t count); + +#endif diff --git a/lib_tls/include/openssl/ec.h b/lib_tls/include/openssl/ec.h new file mode 100644 index 000000000..8bc2a235b --- /dev/null +++ b/lib_tls/include/openssl/ec.h @@ -0,0 +1,526 @@ +/* crypto/ec/ec.h */ +/* + * Originally written by Bodo Moeller for the OpenSSL project. + */ +/* ==================================================================== + * Copyright (c) 1998-2003 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * + * Portions of the attached software ("Contribution") are developed by + * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. + * + * The Contribution is licensed pursuant to the OpenSSL open source + * license provided above. + * + * The elliptic curve binary polynomial software is originally written by + * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems Laboratories. + * + */ + +#ifndef HEADER_EC_H +#define HEADER_EC_H + +#include + +#ifdef OPENSSL_NO_EC +#error EC is disabled. +#endif + +#include +#include +#ifndef OPENSSL_NO_DEPRECATED +#include +#endif + +#ifdef __cplusplus +extern "C" { +#elif defined(__SUNPRO_C) +# if __SUNPRO_C >= 0x520 +# pragma error_messages (off,E_ARRAY_OF_INCOMPLETE_NONAME,E_ARRAY_OF_INCOMPLETE) +# endif +#endif + + +#ifndef OPENSSL_ECC_MAX_FIELD_BITS +# define OPENSSL_ECC_MAX_FIELD_BITS 661 +#endif + +typedef enum { + /* values as defined in X9.62 (ECDSA) and elsewhere */ + POINT_CONVERSION_COMPRESSED = 2, + POINT_CONVERSION_UNCOMPRESSED = 4, + POINT_CONVERSION_HYBRID = 6 +} point_conversion_form_t; + + +typedef struct ec_method_st EC_METHOD; + +typedef struct ec_group_st + /* + EC_METHOD *meth; + -- field definition + -- curve coefficients + -- optional generator with associated information (order, cofactor) + -- optional extra data (precomputed table for fast computation of multiples of generator) + -- ASN1 stuff + */ + EC_GROUP; + +typedef struct ec_point_st EC_POINT; + + +/* EC_METHODs for curves over GF(p). + * EC_GFp_simple_method provides the basis for the optimized methods. + */ +const EC_METHOD *EC_GFp_simple_method(void); +const EC_METHOD *EC_GFp_mont_method(void); +const EC_METHOD *EC_GFp_nist_method(void); + +/* EC_METHOD for curves over GF(2^m). + */ +const EC_METHOD *EC_GF2m_simple_method(void); + + +EC_GROUP *EC_GROUP_new(const EC_METHOD *); +void EC_GROUP_free(EC_GROUP *); +void EC_GROUP_clear_free(EC_GROUP *); +int EC_GROUP_copy(EC_GROUP *, const EC_GROUP *); +EC_GROUP *EC_GROUP_dup(const EC_GROUP *); + +const EC_METHOD *EC_GROUP_method_of(const EC_GROUP *); +int EC_METHOD_get_field_type(const EC_METHOD *); + +int EC_GROUP_set_generator(EC_GROUP *, const EC_POINT *generator, const BIGNUM *order, const BIGNUM *cofactor); +const EC_POINT *EC_GROUP_get0_generator(const EC_GROUP *); +int EC_GROUP_get_order(const EC_GROUP *, BIGNUM *order, BN_CTX *); +int EC_GROUP_get_cofactor(const EC_GROUP *, BIGNUM *cofactor, BN_CTX *); + +void EC_GROUP_set_curve_name(EC_GROUP *, int nid); +int EC_GROUP_get_curve_name(const EC_GROUP *); + +void EC_GROUP_set_asn1_flag(EC_GROUP *, int flag); +int EC_GROUP_get_asn1_flag(const EC_GROUP *); + +void EC_GROUP_set_point_conversion_form(EC_GROUP *, point_conversion_form_t); +point_conversion_form_t EC_GROUP_get_point_conversion_form(const EC_GROUP *); + +unsigned char *EC_GROUP_get0_seed(const EC_GROUP *); +size_t EC_GROUP_get_seed_len(const EC_GROUP *); +size_t EC_GROUP_set_seed(EC_GROUP *, const unsigned char *, size_t len); + +int EC_GROUP_set_curve_GFp(EC_GROUP *, const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *); +int EC_GROUP_get_curve_GFp(const EC_GROUP *, BIGNUM *p, BIGNUM *a, BIGNUM *b, BN_CTX *); +int EC_GROUP_set_curve_GF2m(EC_GROUP *, const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *); +int EC_GROUP_get_curve_GF2m(const EC_GROUP *, BIGNUM *p, BIGNUM *a, BIGNUM *b, BN_CTX *); + +/* returns the number of bits needed to represent a field element */ +int EC_GROUP_get_degree(const EC_GROUP *); + +/* EC_GROUP_check() returns 1 if 'group' defines a valid group, 0 otherwise */ +int EC_GROUP_check(const EC_GROUP *group, BN_CTX *ctx); +/* EC_GROUP_check_discriminant() returns 1 if the discriminant of the + * elliptic curve is not zero, 0 otherwise */ +int EC_GROUP_check_discriminant(const EC_GROUP *, BN_CTX *); + +/* EC_GROUP_cmp() returns 0 if both groups are equal and 1 otherwise */ +int EC_GROUP_cmp(const EC_GROUP *, const EC_GROUP *, BN_CTX *); + +/* EC_GROUP_new_GF*() calls EC_GROUP_new() and EC_GROUP_set_GF*() + * after choosing an appropriate EC_METHOD */ +EC_GROUP *EC_GROUP_new_curve_GFp(const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *); +EC_GROUP *EC_GROUP_new_curve_GF2m(const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *); + +/* EC_GROUP_new_by_curve_name() creates a EC_GROUP structure + * specified by a curve name (in form of a NID) */ +EC_GROUP *EC_GROUP_new_by_curve_name(int nid); +/* handling of internal curves */ +typedef struct { + int nid; + const char *comment; + } EC_builtin_curve; +/* EC_builtin_curves(EC_builtin_curve *r, size_t size) returns number + * of all available curves or zero if a error occurred. + * In case r ist not zero nitems EC_builtin_curve structures + * are filled with the data of the first nitems internal groups */ +size_t EC_get_builtin_curves(EC_builtin_curve *r, size_t nitems); + + +/* EC_POINT functions */ + +EC_POINT *EC_POINT_new(const EC_GROUP *); +void EC_POINT_free(EC_POINT *); +void EC_POINT_clear_free(EC_POINT *); +int EC_POINT_copy(EC_POINT *, const EC_POINT *); +EC_POINT *EC_POINT_dup(const EC_POINT *, const EC_GROUP *); + +const EC_METHOD *EC_POINT_method_of(const EC_POINT *); + +int EC_POINT_set_to_infinity(const EC_GROUP *, EC_POINT *); +int EC_POINT_set_Jprojective_coordinates_GFp(const EC_GROUP *, EC_POINT *, + const BIGNUM *x, const BIGNUM *y, const BIGNUM *z, BN_CTX *); +int EC_POINT_get_Jprojective_coordinates_GFp(const EC_GROUP *, const EC_POINT *, + BIGNUM *x, BIGNUM *y, BIGNUM *z, BN_CTX *); +int EC_POINT_set_affine_coordinates_GFp(const EC_GROUP *, EC_POINT *, + const BIGNUM *x, const BIGNUM *y, BN_CTX *); +int EC_POINT_get_affine_coordinates_GFp(const EC_GROUP *, const EC_POINT *, + BIGNUM *x, BIGNUM *y, BN_CTX *); +int EC_POINT_set_compressed_coordinates_GFp(const EC_GROUP *, EC_POINT *, + const BIGNUM *x, int y_bit, BN_CTX *); + +int EC_POINT_set_affine_coordinates_GF2m(const EC_GROUP *, EC_POINT *, + const BIGNUM *x, const BIGNUM *y, BN_CTX *); +int EC_POINT_get_affine_coordinates_GF2m(const EC_GROUP *, const EC_POINT *, + BIGNUM *x, BIGNUM *y, BN_CTX *); +int EC_POINT_set_compressed_coordinates_GF2m(const EC_GROUP *, EC_POINT *, + const BIGNUM *x, int y_bit, BN_CTX *); + +size_t EC_POINT_point2oct(const EC_GROUP *, const EC_POINT *, point_conversion_form_t form, + unsigned char *buf, size_t len, BN_CTX *); +int EC_POINT_oct2point(const EC_GROUP *, EC_POINT *, + const unsigned char *buf, size_t len, BN_CTX *); + +/* other interfaces to point2oct/oct2point: */ +BIGNUM *EC_POINT_point2bn(const EC_GROUP *, const EC_POINT *, + point_conversion_form_t form, BIGNUM *, BN_CTX *); +EC_POINT *EC_POINT_bn2point(const EC_GROUP *, const BIGNUM *, + EC_POINT *, BN_CTX *); +char *EC_POINT_point2hex(const EC_GROUP *, const EC_POINT *, + point_conversion_form_t form, BN_CTX *); +EC_POINT *EC_POINT_hex2point(const EC_GROUP *, const char *, + EC_POINT *, BN_CTX *); + +int EC_POINT_add(const EC_GROUP *, EC_POINT *r, const EC_POINT *a, const EC_POINT *b, BN_CTX *); +int EC_POINT_dbl(const EC_GROUP *, EC_POINT *r, const EC_POINT *a, BN_CTX *); +int EC_POINT_invert(const EC_GROUP *, EC_POINT *, BN_CTX *); + +int EC_POINT_is_at_infinity(const EC_GROUP *, const EC_POINT *); +int EC_POINT_is_on_curve(const EC_GROUP *, const EC_POINT *, BN_CTX *); +int EC_POINT_cmp(const EC_GROUP *, const EC_POINT *a, const EC_POINT *b, BN_CTX *); + +int EC_POINT_make_affine(const EC_GROUP *, EC_POINT *, BN_CTX *); +int EC_POINTs_make_affine(const EC_GROUP *, size_t num, EC_POINT *[], BN_CTX *); + + +int EC_POINTs_mul(const EC_GROUP *, EC_POINT *r, const BIGNUM *, size_t num, const EC_POINT *[], const BIGNUM *[], BN_CTX *); +int EC_POINT_mul(const EC_GROUP *, EC_POINT *r, const BIGNUM *, const EC_POINT *, const BIGNUM *, BN_CTX *); + +/* EC_GROUP_precompute_mult() stores multiples of generator for faster point multiplication */ +int EC_GROUP_precompute_mult(EC_GROUP *, BN_CTX *); +/* EC_GROUP_have_precompute_mult() reports whether such precomputation has been done */ +int EC_GROUP_have_precompute_mult(const EC_GROUP *); + + + +/* ASN1 stuff */ + +/* EC_GROUP_get_basis_type() returns the NID of the basis type + * used to represent the field elements */ +int EC_GROUP_get_basis_type(const EC_GROUP *); +int EC_GROUP_get_trinomial_basis(const EC_GROUP *, unsigned int *k); +int EC_GROUP_get_pentanomial_basis(const EC_GROUP *, unsigned int *k1, + unsigned int *k2, unsigned int *k3); + +#define OPENSSL_EC_NAMED_CURVE 0x001 + +typedef struct ecpk_parameters_st ECPKPARAMETERS; + +EC_GROUP *d2i_ECPKParameters(EC_GROUP **, const unsigned char **in, long len); +int i2d_ECPKParameters(const EC_GROUP *, unsigned char **out); + +#define d2i_ECPKParameters_bio(bp,x) ASN1_d2i_bio_of(EC_GROUP,NULL,d2i_ECPKParameters,bp,x) +#define i2d_ECPKParameters_bio(bp,x) ASN1_i2d_bio_of_const(EC_GROUP,i2d_ECPKParameters,bp,x) +#define d2i_ECPKParameters_fp(fp,x) (EC_GROUP *)ASN1_d2i_fp(NULL, \ + (char *(*)())d2i_ECPKParameters,(fp),(unsigned char **)(x)) +#define i2d_ECPKParameters_fp(fp,x) ASN1_i2d_fp(i2d_ECPKParameters,(fp), \ + (unsigned char *)(x)) + +#ifndef OPENSSL_NO_BIO +int ECPKParameters_print(BIO *bp, const EC_GROUP *x, int off); +#endif +#ifndef OPENSSL_NO_FP_API +int ECPKParameters_print_fp(FILE *fp, const EC_GROUP *x, int off); +#endif + +/* the EC_KEY stuff */ +typedef struct ec_key_st EC_KEY; + +/* some values for the encoding_flag */ +#define EC_PKEY_NO_PARAMETERS 0x001 +#define EC_PKEY_NO_PUBKEY 0x002 + +EC_KEY *EC_KEY_new(void); +EC_KEY *EC_KEY_new_by_curve_name(int nid); +void EC_KEY_free(EC_KEY *); +EC_KEY *EC_KEY_copy(EC_KEY *, const EC_KEY *); +EC_KEY *EC_KEY_dup(const EC_KEY *); + +int EC_KEY_up_ref(EC_KEY *); + +const EC_GROUP *EC_KEY_get0_group(const EC_KEY *); +int EC_KEY_set_group(EC_KEY *, const EC_GROUP *); +const BIGNUM *EC_KEY_get0_private_key(const EC_KEY *); +int EC_KEY_set_private_key(EC_KEY *, const BIGNUM *); +const EC_POINT *EC_KEY_get0_public_key(const EC_KEY *); +int EC_KEY_set_public_key(EC_KEY *, const EC_POINT *); +unsigned EC_KEY_get_enc_flags(const EC_KEY *); +void EC_KEY_set_enc_flags(EC_KEY *, unsigned int); +point_conversion_form_t EC_KEY_get_conv_form(const EC_KEY *); +void EC_KEY_set_conv_form(EC_KEY *, point_conversion_form_t); +/* functions to set/get method specific data */ +void *EC_KEY_get_key_method_data(EC_KEY *, + void *(*dup_func)(void *), void (*free_func)(void *), void (*clear_free_func)(void *)); +void EC_KEY_insert_key_method_data(EC_KEY *, void *data, + void *(*dup_func)(void *), void (*free_func)(void *), void (*clear_free_func)(void *)); +/* wrapper functions for the underlying EC_GROUP object */ +void EC_KEY_set_asn1_flag(EC_KEY *, int); +int EC_KEY_precompute_mult(EC_KEY *, BN_CTX *ctx); + +/* EC_KEY_generate_key() creates a ec private (public) key */ +int EC_KEY_generate_key(EC_KEY *); +/* EC_KEY_check_key() */ +int EC_KEY_check_key(const EC_KEY *); + +/* de- and encoding functions for SEC1 ECPrivateKey */ +EC_KEY *d2i_ECPrivateKey(EC_KEY **a, const unsigned char **in, long len); +int i2d_ECPrivateKey(EC_KEY *a, unsigned char **out); +/* de- and encoding functions for EC parameters */ +EC_KEY *d2i_ECParameters(EC_KEY **a, const unsigned char **in, long len); +int i2d_ECParameters(EC_KEY *a, unsigned char **out); +/* de- and encoding functions for EC public key + * (octet string, not DER -- hence 'o2i' and 'i2o') */ +EC_KEY *o2i_ECPublicKey(EC_KEY **a, const unsigned char **in, long len); +int i2o_ECPublicKey(EC_KEY *a, unsigned char **out); + +#ifndef OPENSSL_NO_BIO +int ECParameters_print(BIO *bp, const EC_KEY *x); +int EC_KEY_print(BIO *bp, const EC_KEY *x, int off); +#endif +#ifndef OPENSSL_NO_FP_API +int ECParameters_print_fp(FILE *fp, const EC_KEY *x); +int EC_KEY_print_fp(FILE *fp, const EC_KEY *x, int off); +#endif + +#define ECParameters_dup(x) ASN1_dup_of(EC_KEY,i2d_ECParameters,d2i_ECParameters,x) + +#ifndef __cplusplus +#if defined(__SUNPRO_C) +# if __SUNPRO_C >= 0x520 +# pragma error_messages (default,E_ARRAY_OF_INCOMPLETE_NONAME,E_ARRAY_OF_INCOMPLETE) +# endif +# endif +#endif + +/* BEGIN ERROR CODES */ +/* The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ +void ERR_load_EC_strings(void); + +/* Error codes for the EC functions. */ + +/* Function codes. */ +#define EC_F_COMPUTE_WNAF 143 +#define EC_F_D2I_ECPARAMETERS 144 +#define EC_F_D2I_ECPKPARAMETERS 145 +#define EC_F_D2I_ECPRIVATEKEY 146 +#define EC_F_ECPARAMETERS_PRINT 147 +#define EC_F_ECPARAMETERS_PRINT_FP 148 +#define EC_F_ECPKPARAMETERS_PRINT 149 +#define EC_F_ECPKPARAMETERS_PRINT_FP 150 +#define EC_F_ECP_NIST_MOD_192 203 +#define EC_F_ECP_NIST_MOD_224 204 +#define EC_F_ECP_NIST_MOD_256 205 +#define EC_F_ECP_NIST_MOD_521 206 +#define EC_F_EC_ASN1_GROUP2CURVE 153 +#define EC_F_EC_ASN1_GROUP2FIELDID 154 +#define EC_F_EC_ASN1_GROUP2PARAMETERS 155 +#define EC_F_EC_ASN1_GROUP2PKPARAMETERS 156 +#define EC_F_EC_ASN1_PARAMETERS2GROUP 157 +#define EC_F_EC_ASN1_PKPARAMETERS2GROUP 158 +#define EC_F_EC_EX_DATA_SET_DATA 211 +#define EC_F_EC_GF2M_MONTGOMERY_POINT_MULTIPLY 208 +#define EC_F_EC_GF2M_SIMPLE_GROUP_CHECK_DISCRIMINANT 159 +#define EC_F_EC_GF2M_SIMPLE_GROUP_SET_CURVE 195 +#define EC_F_EC_GF2M_SIMPLE_OCT2POINT 160 +#define EC_F_EC_GF2M_SIMPLE_POINT2OCT 161 +#define EC_F_EC_GF2M_SIMPLE_POINT_GET_AFFINE_COORDINATES 162 +#define EC_F_EC_GF2M_SIMPLE_POINT_SET_AFFINE_COORDINATES 163 +#define EC_F_EC_GF2M_SIMPLE_SET_COMPRESSED_COORDINATES 164 +#define EC_F_EC_GFP_MONT_FIELD_DECODE 133 +#define EC_F_EC_GFP_MONT_FIELD_ENCODE 134 +#define EC_F_EC_GFP_MONT_FIELD_MUL 131 +#define EC_F_EC_GFP_MONT_FIELD_SET_TO_ONE 209 +#define EC_F_EC_GFP_MONT_FIELD_SQR 132 +#define EC_F_EC_GFP_MONT_GROUP_SET_CURVE 189 +#define EC_F_EC_GFP_MONT_GROUP_SET_CURVE_GFP 135 +#define EC_F_EC_GFP_NIST_FIELD_MUL 200 +#define EC_F_EC_GFP_NIST_FIELD_SQR 201 +#define EC_F_EC_GFP_NIST_GROUP_SET_CURVE 202 +#define EC_F_EC_GFP_SIMPLE_GROUP_CHECK_DISCRIMINANT 165 +#define EC_F_EC_GFP_SIMPLE_GROUP_SET_CURVE 166 +#define EC_F_EC_GFP_SIMPLE_GROUP_SET_CURVE_GFP 100 +#define EC_F_EC_GFP_SIMPLE_GROUP_SET_GENERATOR 101 +#define EC_F_EC_GFP_SIMPLE_MAKE_AFFINE 102 +#define EC_F_EC_GFP_SIMPLE_OCT2POINT 103 +#define EC_F_EC_GFP_SIMPLE_POINT2OCT 104 +#define EC_F_EC_GFP_SIMPLE_POINTS_MAKE_AFFINE 137 +#define EC_F_EC_GFP_SIMPLE_POINT_GET_AFFINE_COORDINATES 167 +#define EC_F_EC_GFP_SIMPLE_POINT_GET_AFFINE_COORDINATES_GFP 105 +#define EC_F_EC_GFP_SIMPLE_POINT_SET_AFFINE_COORDINATES 168 +#define EC_F_EC_GFP_SIMPLE_POINT_SET_AFFINE_COORDINATES_GFP 128 +#define EC_F_EC_GFP_SIMPLE_SET_COMPRESSED_COORDINATES 169 +#define EC_F_EC_GFP_SIMPLE_SET_COMPRESSED_COORDINATES_GFP 129 +#define EC_F_EC_GROUP_CHECK 170 +#define EC_F_EC_GROUP_CHECK_DISCRIMINANT 171 +#define EC_F_EC_GROUP_COPY 106 +#define EC_F_EC_GROUP_GET0_GENERATOR 139 +#define EC_F_EC_GROUP_GET_COFACTOR 140 +#define EC_F_EC_GROUP_GET_CURVE_GF2M 172 +#define EC_F_EC_GROUP_GET_CURVE_GFP 130 +#define EC_F_EC_GROUP_GET_DEGREE 173 +#define EC_F_EC_GROUP_GET_ORDER 141 +#define EC_F_EC_GROUP_GET_PENTANOMIAL_BASIS 193 +#define EC_F_EC_GROUP_GET_TRINOMIAL_BASIS 194 +#define EC_F_EC_GROUP_NEW 108 +#define EC_F_EC_GROUP_NEW_BY_CURVE_NAME 174 +#define EC_F_EC_GROUP_NEW_FROM_DATA 175 +#define EC_F_EC_GROUP_PRECOMPUTE_MULT 142 +#define EC_F_EC_GROUP_SET_CURVE_GF2M 176 +#define EC_F_EC_GROUP_SET_CURVE_GFP 109 +#define EC_F_EC_GROUP_SET_EXTRA_DATA 110 +#define EC_F_EC_GROUP_SET_GENERATOR 111 +#define EC_F_EC_KEY_CHECK_KEY 177 +#define EC_F_EC_KEY_COPY 178 +#define EC_F_EC_KEY_GENERATE_KEY 179 +#define EC_F_EC_KEY_NEW 182 +#define EC_F_EC_KEY_PRINT 180 +#define EC_F_EC_KEY_PRINT_FP 181 +#define EC_F_EC_POINTS_MAKE_AFFINE 136 +#define EC_F_EC_POINTS_MUL 138 +#define EC_F_EC_POINT_ADD 112 +#define EC_F_EC_POINT_CMP 113 +#define EC_F_EC_POINT_COPY 114 +#define EC_F_EC_POINT_DBL 115 +#define EC_F_EC_POINT_GET_AFFINE_COORDINATES_GF2M 183 +#define EC_F_EC_POINT_GET_AFFINE_COORDINATES_GFP 116 +#define EC_F_EC_POINT_GET_JPROJECTIVE_COORDINATES_GFP 117 +#define EC_F_EC_POINT_INVERT 210 +#define EC_F_EC_POINT_IS_AT_INFINITY 118 +#define EC_F_EC_POINT_IS_ON_CURVE 119 +#define EC_F_EC_POINT_MAKE_AFFINE 120 +#define EC_F_EC_POINT_MUL 184 +#define EC_F_EC_POINT_NEW 121 +#define EC_F_EC_POINT_OCT2POINT 122 +#define EC_F_EC_POINT_POINT2OCT 123 +#define EC_F_EC_POINT_SET_AFFINE_COORDINATES_GF2M 185 +#define EC_F_EC_POINT_SET_AFFINE_COORDINATES_GFP 124 +#define EC_F_EC_POINT_SET_COMPRESSED_COORDINATES_GF2M 186 +#define EC_F_EC_POINT_SET_COMPRESSED_COORDINATES_GFP 125 +#define EC_F_EC_POINT_SET_JPROJECTIVE_COORDINATES_GFP 126 +#define EC_F_EC_POINT_SET_TO_INFINITY 127 +#define EC_F_EC_PRE_COMP_DUP 207 +#define EC_F_EC_PRE_COMP_NEW 196 +#define EC_F_EC_WNAF_MUL 187 +#define EC_F_EC_WNAF_PRECOMPUTE_MULT 188 +#define EC_F_I2D_ECPARAMETERS 190 +#define EC_F_I2D_ECPKPARAMETERS 191 +#define EC_F_I2D_ECPRIVATEKEY 192 +#define EC_F_I2O_ECPUBLICKEY 151 +#define EC_F_O2I_ECPUBLICKEY 152 + +/* Reason codes. */ +#define EC_R_ASN1_ERROR 115 +#define EC_R_ASN1_UNKNOWN_FIELD 116 +#define EC_R_BUFFER_TOO_SMALL 100 +#define EC_R_D2I_ECPKPARAMETERS_FAILURE 117 +#define EC_R_DISCRIMINANT_IS_ZERO 118 +#define EC_R_EC_GROUP_NEW_BY_NAME_FAILURE 119 +#define EC_R_FIELD_TOO_LARGE 138 +#define EC_R_GROUP2PKPARAMETERS_FAILURE 120 +#define EC_R_I2D_ECPKPARAMETERS_FAILURE 121 +#define EC_R_INCOMPATIBLE_OBJECTS 101 +#define EC_R_INVALID_ARGUMENT 112 +#define EC_R_INVALID_COMPRESSED_POINT 110 +#define EC_R_INVALID_COMPRESSION_BIT 109 +#define EC_R_INVALID_ENCODING 102 +#define EC_R_INVALID_FIELD 103 +#define EC_R_INVALID_FORM 104 +#define EC_R_INVALID_GROUP_ORDER 122 +#define EC_R_INVALID_PENTANOMIAL_BASIS 132 +#define EC_R_INVALID_PRIVATE_KEY 123 +#define EC_R_INVALID_TRINOMIAL_BASIS 137 +#define EC_R_MISSING_PARAMETERS 124 +#define EC_R_MISSING_PRIVATE_KEY 125 +#define EC_R_NOT_A_NIST_PRIME 135 +#define EC_R_NOT_A_SUPPORTED_NIST_PRIME 136 +#define EC_R_NOT_IMPLEMENTED 126 +#define EC_R_NOT_INITIALIZED 111 +#define EC_R_NO_FIELD_MOD 133 +#define EC_R_PASSED_NULL_PARAMETER 134 +#define EC_R_PKPARAMETERS2GROUP_FAILURE 127 +#define EC_R_POINT_AT_INFINITY 106 +#define EC_R_POINT_IS_NOT_ON_CURVE 107 +#define EC_R_SLOT_FULL 108 +#define EC_R_UNDEFINED_GENERATOR 113 +#define EC_R_UNDEFINED_ORDER 128 +#define EC_R_UNKNOWN_GROUP 129 +#define EC_R_UNKNOWN_ORDER 114 +#define EC_R_UNSUPPORTED_FIELD 131 +#define EC_R_WRONG_ORDER 130 + +#ifdef __cplusplus +} +#endif +#endif diff --git a/lib_tls/include/openssl/ecdh.h b/lib_tls/include/openssl/ecdh.h new file mode 100644 index 000000000..b4b58ee65 --- /dev/null +++ b/lib_tls/include/openssl/ecdh.h @@ -0,0 +1,123 @@ +/* crypto/ecdh/ecdh.h */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * + * The Elliptic Curve Public-Key Crypto Library (ECC Code) included + * herein is developed by SUN MICROSYSTEMS, INC., and is contributed + * to the OpenSSL project. + * + * The ECC Code is licensed pursuant to the OpenSSL open source + * license provided below. + * + * The ECDH software is originally written by Douglas Stebila of + * Sun Microsystems Laboratories. + * + */ +/* ==================================================================== + * Copyright (c) 2000-2002 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +#ifndef HEADER_ECDH_H +#define HEADER_ECDH_H + +#include + +#ifdef OPENSSL_NO_ECDH +#error ECDH is disabled. +#endif + +#include +#include +#ifndef OPENSSL_NO_DEPRECATED +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +const ECDH_METHOD *ECDH_OpenSSL(void); + +void ECDH_set_default_method(const ECDH_METHOD *); +const ECDH_METHOD *ECDH_get_default_method(void); +int ECDH_set_method(EC_KEY *, const ECDH_METHOD *); + +int ECDH_compute_key(void *out, size_t outlen, const EC_POINT *pub_key, EC_KEY *ecdh, + void *(*KDF)(const void *in, size_t inlen, void *out, size_t *outlen)); + +int ECDH_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new + *new_func, CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func); +int ECDH_set_ex_data(EC_KEY *d, int idx, void *arg); +void *ECDH_get_ex_data(EC_KEY *d, int idx); + + +/* BEGIN ERROR CODES */ +/* The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ +void ERR_load_ECDH_strings(void); + +/* Error codes for the ECDH functions. */ + +/* Function codes. */ +#define ECDH_F_ECDH_COMPUTE_KEY 100 +#define ECDH_F_ECDH_DATA_NEW_METHOD 101 + +/* Reason codes. */ +#define ECDH_R_KDF_FAILED 102 +#define ECDH_R_NO_PRIVATE_VALUE 100 +#define ECDH_R_POINT_ARITHMETIC_FAILURE 101 + +#ifdef __cplusplus +} +#endif +#endif diff --git a/lib_tls/include/openssl/ecdsa.h b/lib_tls/include/openssl/ecdsa.h new file mode 100644 index 000000000..f20c8ee73 --- /dev/null +++ b/lib_tls/include/openssl/ecdsa.h @@ -0,0 +1,271 @@ +/* crypto/ecdsa/ecdsa.h */ +/** + * \file crypto/ecdsa/ecdsa.h Include file for the OpenSSL ECDSA functions + * \author Written by Nils Larsch for the OpenSSL project + */ +/* ==================================================================== + * Copyright (c) 2000-2003 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +#ifndef HEADER_ECDSA_H +#define HEADER_ECDSA_H + +#include + +#ifdef OPENSSL_NO_ECDSA +#error ECDSA is disabled. +#endif + +#include +#include +#ifndef OPENSSL_NO_DEPRECATED +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct ECDSA_SIG_st + { + BIGNUM *r; + BIGNUM *s; + } ECDSA_SIG; + +/** ECDSA_SIG *ECDSA_SIG_new(void) + * allocates and initialize a ECDSA_SIG structure + * \return pointer to a ECDSA_SIG structure or NULL if an error occurred + */ +ECDSA_SIG *ECDSA_SIG_new(void); + +/** ECDSA_SIG_free + * frees a ECDSA_SIG structure + * \param a pointer to the ECDSA_SIG structure + */ +void ECDSA_SIG_free(ECDSA_SIG *a); + +/** i2d_ECDSA_SIG + * DER encode content of ECDSA_SIG object (note: this function modifies *pp + * (*pp += length of the DER encoded signature)). + * \param a pointer to the ECDSA_SIG object + * \param pp pointer to a unsigned char pointer for the output or NULL + * \return the length of the DER encoded ECDSA_SIG object or 0 + */ +int i2d_ECDSA_SIG(const ECDSA_SIG *a, unsigned char **pp); + +/** d2i_ECDSA_SIG + * decodes a DER encoded ECDSA signature (note: this function changes *pp + * (*pp += len)). + * \param v pointer to ECDSA_SIG pointer (may be NULL) + * \param pp buffer with the DER encoded signature + * \param len bufferlength + * \return pointer to the decoded ECDSA_SIG structure (or NULL) + */ +ECDSA_SIG *d2i_ECDSA_SIG(ECDSA_SIG **v, const unsigned char **pp, long len); + +/** ECDSA_do_sign + * computes the ECDSA signature of the given hash value using + * the supplied private key and returns the created signature. + * \param dgst pointer to the hash value + * \param dgst_len length of the hash value + * \param eckey pointer to the EC_KEY object containing a private EC key + * \return pointer to a ECDSA_SIG structure or NULL + */ +ECDSA_SIG *ECDSA_do_sign(const unsigned char *dgst,int dgst_len,EC_KEY *eckey); + +/** ECDSA_do_sign_ex + * computes ECDSA signature of a given hash value using the supplied + * private key (note: sig must point to ECDSA_size(eckey) bytes of memory). + * \param dgst pointer to the hash value to sign + * \param dgstlen length of the hash value + * \param kinv optional pointer to a pre-computed inverse k + * \param rp optional pointer to the pre-computed rp value (see + * ECDSA_sign_setup + * \param eckey pointer to the EC_KEY object containing a private EC key + * \return pointer to a ECDSA_SIG structure or NULL + */ +ECDSA_SIG *ECDSA_do_sign_ex(const unsigned char *dgst, int dgstlen, + const BIGNUM *kinv, const BIGNUM *rp, EC_KEY *eckey); + +/** ECDSA_do_verify + * verifies that the supplied signature is a valid ECDSA + * signature of the supplied hash value using the supplied public key. + * \param dgst pointer to the hash value + * \param dgst_len length of the hash value + * \param sig pointer to the ECDSA_SIG structure + * \param eckey pointer to the EC_KEY object containing a public EC key + * \return 1 if the signature is valid, 0 if the signature is invalid and -1 on error + */ +int ECDSA_do_verify(const unsigned char *dgst, int dgst_len, + const ECDSA_SIG *sig, EC_KEY* eckey); + +const ECDSA_METHOD *ECDSA_OpenSSL(void); + +/** ECDSA_set_default_method + * sets the default ECDSA method + * \param meth the new default ECDSA_METHOD + */ +void ECDSA_set_default_method(const ECDSA_METHOD *meth); + +/** ECDSA_get_default_method + * returns the default ECDSA method + * \return pointer to ECDSA_METHOD structure containing the default method + */ +const ECDSA_METHOD *ECDSA_get_default_method(void); + +/** ECDSA_set_method + * sets method to be used for the ECDSA operations + * \param eckey pointer to the EC_KEY object + * \param meth pointer to the new method + * \return 1 on success and 0 otherwise + */ +int ECDSA_set_method(EC_KEY *eckey, const ECDSA_METHOD *meth); + +/** ECDSA_size + * returns the maximum length of the DER encoded signature + * \param eckey pointer to a EC_KEY object + * \return numbers of bytes required for the DER encoded signature + */ +int ECDSA_size(const EC_KEY *eckey); + +/** ECDSA_sign_setup + * precompute parts of the signing operation. + * \param eckey pointer to the EC_KEY object containing a private EC key + * \param ctx pointer to a BN_CTX object (may be NULL) + * \param kinv pointer to a BIGNUM pointer for the inverse of k + * \param rp pointer to a BIGNUM pointer for x coordinate of k * generator + * \return 1 on success and 0 otherwise + */ +int ECDSA_sign_setup(EC_KEY *eckey, BN_CTX *ctx, BIGNUM **kinv, + BIGNUM **rp); + +/** ECDSA_sign + * computes ECDSA signature of a given hash value using the supplied + * private key (note: sig must point to ECDSA_size(eckey) bytes of memory). + * \param type this parameter is ignored + * \param dgst pointer to the hash value to sign + * \param dgstlen length of the hash value + * \param sig buffer to hold the DER encoded signature + * \param siglen pointer to the length of the returned signature + * \param eckey pointer to the EC_KEY object containing a private EC key + * \return 1 on success and 0 otherwise + */ +int ECDSA_sign(int type, const unsigned char *dgst, int dgstlen, + unsigned char *sig, unsigned int *siglen, EC_KEY *eckey); + + +/** ECDSA_sign_ex + * computes ECDSA signature of a given hash value using the supplied + * private key (note: sig must point to ECDSA_size(eckey) bytes of memory). + * \param type this parameter is ignored + * \param dgst pointer to the hash value to sign + * \param dgstlen length of the hash value + * \param sig buffer to hold the DER encoded signature + * \param siglen pointer to the length of the returned signature + * \param kinv optional pointer to a pre-computed inverse k + * \param rp optional pointer to the pre-computed rp value (see + * ECDSA_sign_setup + * \param eckey pointer to the EC_KEY object containing a private EC key + * \return 1 on success and 0 otherwise + */ +int ECDSA_sign_ex(int type, const unsigned char *dgst, int dgstlen, + unsigned char *sig, unsigned int *siglen, const BIGNUM *kinv, + const BIGNUM *rp, EC_KEY *eckey); + +/** ECDSA_verify + * verifies that the given signature is valid ECDSA signature + * of the supplied hash value using the specified public key. + * \param type this parameter is ignored + * \param dgst pointer to the hash value + * \param dgstlen length of the hash value + * \param sig pointer to the DER encoded signature + * \param siglen length of the DER encoded signature + * \param eckey pointer to the EC_KEY object containing a public EC key + * \return 1 if the signature is valid, 0 if the signature is invalid and -1 on error + */ +int ECDSA_verify(int type, const unsigned char *dgst, int dgstlen, + const unsigned char *sig, int siglen, EC_KEY *eckey); + +/* the standard ex_data functions */ +int ECDSA_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new + *new_func, CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func); +int ECDSA_set_ex_data(EC_KEY *d, int idx, void *arg); +void *ECDSA_get_ex_data(EC_KEY *d, int idx); + + +/* BEGIN ERROR CODES */ +/* The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ +void ERR_load_ECDSA_strings(void); + +/* Error codes for the ECDSA functions. */ + +/* Function codes. */ +#define ECDSA_F_ECDSA_DATA_NEW_METHOD 100 +#define ECDSA_F_ECDSA_DO_SIGN 101 +#define ECDSA_F_ECDSA_DO_VERIFY 102 +#define ECDSA_F_ECDSA_SIGN_SETUP 103 + +/* Reason codes. */ +#define ECDSA_R_BAD_SIGNATURE 100 +#define ECDSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE 101 +#define ECDSA_R_ERR_EC_LIB 102 +#define ECDSA_R_MISSING_PARAMETERS 103 +#define ECDSA_R_NEED_NEW_SETUP_VALUES 106 +#define ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED 104 +#define ECDSA_R_SIGNATURE_MALLOC_FAILED 105 + +#ifdef __cplusplus +} +#endif +#endif diff --git a/lib_tls/include/openssl/engine.h b/lib_tls/include/openssl/engine.h new file mode 100644 index 000000000..3ec59338f --- /dev/null +++ b/lib_tls/include/openssl/engine.h @@ -0,0 +1,785 @@ +/* openssl/engine.h */ +/* Written by Geoff Thorpe (geoff@geoffthorpe.net) for the OpenSSL + * project 2000. + */ +/* ==================================================================== + * Copyright (c) 1999-2004 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * ECDH support in OpenSSL originally developed by + * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project. + */ + +#ifndef HEADER_ENGINE_H +#define HEADER_ENGINE_H + +#include + +#ifdef OPENSSL_NO_ENGINE +#error ENGINE is disabled. +#endif + +#ifndef OPENSSL_NO_DEPRECATED +#include +#ifndef OPENSSL_NO_RSA +#include +#endif +#ifndef OPENSSL_NO_DSA +#include +#endif +#ifndef OPENSSL_NO_DH +#include +#endif +#ifndef OPENSSL_NO_ECDH +#include +#endif +#ifndef OPENSSL_NO_ECDSA +#include +#endif +#include +#include +#include +#include +#endif + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* These flags are used to control combinations of algorithm (methods) + * by bitwise "OR"ing. */ +#define ENGINE_METHOD_RSA (unsigned int)0x0001 +#define ENGINE_METHOD_DSA (unsigned int)0x0002 +#define ENGINE_METHOD_DH (unsigned int)0x0004 +#define ENGINE_METHOD_RAND (unsigned int)0x0008 +#define ENGINE_METHOD_ECDH (unsigned int)0x0010 +#define ENGINE_METHOD_ECDSA (unsigned int)0x0020 +#define ENGINE_METHOD_CIPHERS (unsigned int)0x0040 +#define ENGINE_METHOD_DIGESTS (unsigned int)0x0080 +#define ENGINE_METHOD_STORE (unsigned int)0x0100 +/* Obvious all-or-nothing cases. */ +#define ENGINE_METHOD_ALL (unsigned int)0xFFFF +#define ENGINE_METHOD_NONE (unsigned int)0x0000 + +/* This(ese) flag(s) controls behaviour of the ENGINE_TABLE mechanism used + * internally to control registration of ENGINE implementations, and can be set + * by ENGINE_set_table_flags(). The "NOINIT" flag prevents attempts to + * initialise registered ENGINEs if they are not already initialised. */ +#define ENGINE_TABLE_FLAG_NOINIT (unsigned int)0x0001 + +/* ENGINE flags that can be set by ENGINE_set_flags(). */ +/* #define ENGINE_FLAGS_MALLOCED 0x0001 */ /* Not used */ + +/* This flag is for ENGINEs that wish to handle the various 'CMD'-related + * control commands on their own. Without this flag, ENGINE_ctrl() handles these + * control commands on behalf of the ENGINE using their "cmd_defns" data. */ +#define ENGINE_FLAGS_MANUAL_CMD_CTRL (int)0x0002 + +/* This flag is for ENGINEs who return new duplicate structures when found via + * "ENGINE_by_id()". When an ENGINE must store state (eg. if ENGINE_ctrl() + * commands are called in sequence as part of some stateful process like + * key-generation setup and execution), it can set this flag - then each attempt + * to obtain the ENGINE will result in it being copied into a new structure. + * Normally, ENGINEs don't declare this flag so ENGINE_by_id() just increments + * the existing ENGINE's structural reference count. */ +#define ENGINE_FLAGS_BY_ID_COPY (int)0x0004 + +/* ENGINEs can support their own command types, and these flags are used in + * ENGINE_CTRL_GET_CMD_FLAGS to indicate to the caller what kind of input each + * command expects. Currently only numeric and string input is supported. If a + * control command supports none of the _NUMERIC, _STRING, or _NO_INPUT options, + * then it is regarded as an "internal" control command - and not for use in + * config setting situations. As such, they're not available to the + * ENGINE_ctrl_cmd_string() function, only raw ENGINE_ctrl() access. Changes to + * this list of 'command types' should be reflected carefully in + * ENGINE_cmd_is_executable() and ENGINE_ctrl_cmd_string(). */ + +/* accepts a 'long' input value (3rd parameter to ENGINE_ctrl) */ +#define ENGINE_CMD_FLAG_NUMERIC (unsigned int)0x0001 +/* accepts string input (cast from 'void*' to 'const char *', 4th parameter to + * ENGINE_ctrl) */ +#define ENGINE_CMD_FLAG_STRING (unsigned int)0x0002 +/* Indicates that the control command takes *no* input. Ie. the control command + * is unparameterised. */ +#define ENGINE_CMD_FLAG_NO_INPUT (unsigned int)0x0004 +/* Indicates that the control command is internal. This control command won't + * be shown in any output, and is only usable through the ENGINE_ctrl_cmd() + * function. */ +#define ENGINE_CMD_FLAG_INTERNAL (unsigned int)0x0008 + +/* NB: These 3 control commands are deprecated and should not be used. ENGINEs + * relying on these commands should compile conditional support for + * compatibility (eg. if these symbols are defined) but should also migrate the + * same functionality to their own ENGINE-specific control functions that can be + * "discovered" by calling applications. The fact these control commands + * wouldn't be "executable" (ie. usable by text-based config) doesn't change the + * fact that application code can find and use them without requiring per-ENGINE + * hacking. */ + +/* These flags are used to tell the ctrl function what should be done. + * All command numbers are shared between all engines, even if some don't + * make sense to some engines. In such a case, they do nothing but return + * the error ENGINE_R_CTRL_COMMAND_NOT_IMPLEMENTED. */ +#define ENGINE_CTRL_SET_LOGSTREAM 1 +#define ENGINE_CTRL_SET_PASSWORD_CALLBACK 2 +#define ENGINE_CTRL_HUP 3 /* Close and reinitialise any + handles/connections etc. */ +#define ENGINE_CTRL_SET_USER_INTERFACE 4 /* Alternative to callback */ +#define ENGINE_CTRL_SET_CALLBACK_DATA 5 /* User-specific data, used + when calling the password + callback and the user + interface */ +#define ENGINE_CTRL_LOAD_CONFIGURATION 6 /* Load a configuration, given + a string that represents a + file name or so */ +#define ENGINE_CTRL_LOAD_SECTION 7 /* Load data from a given + section in the already loaded + configuration */ + +/* These control commands allow an application to deal with an arbitrary engine + * in a dynamic way. Warn: Negative return values indicate errors FOR THESE + * COMMANDS because zero is used to indicate 'end-of-list'. Other commands, + * including ENGINE-specific command types, return zero for an error. + * + * An ENGINE can choose to implement these ctrl functions, and can internally + * manage things however it chooses - it does so by setting the + * ENGINE_FLAGS_MANUAL_CMD_CTRL flag (using ENGINE_set_flags()). Otherwise the + * ENGINE_ctrl() code handles this on the ENGINE's behalf using the cmd_defns + * data (set using ENGINE_set_cmd_defns()). This means an ENGINE's ctrl() + * handler need only implement its own commands - the above "meta" commands will + * be taken care of. */ + +/* Returns non-zero if the supplied ENGINE has a ctrl() handler. If "not", then + * all the remaining control commands will return failure, so it is worth + * checking this first if the caller is trying to "discover" the engine's + * capabilities and doesn't want errors generated unnecessarily. */ +#define ENGINE_CTRL_HAS_CTRL_FUNCTION 10 +/* Returns a positive command number for the first command supported by the + * engine. Returns zero if no ctrl commands are supported. */ +#define ENGINE_CTRL_GET_FIRST_CMD_TYPE 11 +/* The 'long' argument specifies a command implemented by the engine, and the + * return value is the next command supported, or zero if there are no more. */ +#define ENGINE_CTRL_GET_NEXT_CMD_TYPE 12 +/* The 'void*' argument is a command name (cast from 'const char *'), and the + * return value is the command that corresponds to it. */ +#define ENGINE_CTRL_GET_CMD_FROM_NAME 13 +/* The next two allow a command to be converted into its corresponding string + * form. In each case, the 'long' argument supplies the command. In the NAME_LEN + * case, the return value is the length of the command name (not counting a + * trailing EOL). In the NAME case, the 'void*' argument must be a string buffer + * large enough, and it will be populated with the name of the command (WITH a + * trailing EOL). */ +#define ENGINE_CTRL_GET_NAME_LEN_FROM_CMD 14 +#define ENGINE_CTRL_GET_NAME_FROM_CMD 15 +/* The next two are similar but give a "short description" of a command. */ +#define ENGINE_CTRL_GET_DESC_LEN_FROM_CMD 16 +#define ENGINE_CTRL_GET_DESC_FROM_CMD 17 +/* With this command, the return value is the OR'd combination of + * ENGINE_CMD_FLAG_*** values that indicate what kind of input a given + * engine-specific ctrl command expects. */ +#define ENGINE_CTRL_GET_CMD_FLAGS 18 + +/* ENGINE implementations should start the numbering of their own control + * commands from this value. (ie. ENGINE_CMD_BASE, ENGINE_CMD_BASE + 1, etc). */ +#define ENGINE_CMD_BASE 200 + +/* NB: These 2 nCipher "chil" control commands are deprecated, and their + * functionality is now available through ENGINE-specific control commands + * (exposed through the above-mentioned 'CMD'-handling). Code using these 2 + * commands should be migrated to the more general command handling before these + * are removed. */ + +/* Flags specific to the nCipher "chil" engine */ +#define ENGINE_CTRL_CHIL_SET_FORKCHECK 100 + /* Depending on the value of the (long)i argument, this sets or + * unsets the SimpleForkCheck flag in the CHIL API to enable or + * disable checking and workarounds for applications that fork(). + */ +#define ENGINE_CTRL_CHIL_NO_LOCKING 101 + /* This prevents the initialisation function from providing mutex + * callbacks to the nCipher library. */ + +/* If an ENGINE supports its own specific control commands and wishes the + * framework to handle the above 'ENGINE_CMD_***'-manipulation commands on its + * behalf, it should supply a null-terminated array of ENGINE_CMD_DEFN entries + * to ENGINE_set_cmd_defns(). It should also implement a ctrl() handler that + * supports the stated commands (ie. the "cmd_num" entries as described by the + * array). NB: The array must be ordered in increasing order of cmd_num. + * "null-terminated" means that the last ENGINE_CMD_DEFN element has cmd_num set + * to zero and/or cmd_name set to NULL. */ +typedef struct ENGINE_CMD_DEFN_st + { + unsigned int cmd_num; /* The command number */ + const char *cmd_name; /* The command name itself */ + const char *cmd_desc; /* A short description of the command */ + unsigned int cmd_flags; /* The input the command expects */ + } ENGINE_CMD_DEFN; + +/* Generic function pointer */ +typedef int (*ENGINE_GEN_FUNC_PTR)(void); +/* Generic function pointer taking no arguments */ +typedef int (*ENGINE_GEN_INT_FUNC_PTR)(ENGINE *); +/* Specific control function pointer */ +typedef int (*ENGINE_CTRL_FUNC_PTR)(ENGINE *, int, long, void *, void (*f)(void)); +/* Generic load_key function pointer */ +typedef EVP_PKEY * (*ENGINE_LOAD_KEY_PTR)(ENGINE *, const char *, + UI_METHOD *ui_method, void *callback_data); +/* These callback types are for an ENGINE's handler for cipher and digest logic. + * These handlers have these prototypes; + * int foo(ENGINE *e, const EVP_CIPHER **cipher, const int **nids, int nid); + * int foo(ENGINE *e, const EVP_MD **digest, const int **nids, int nid); + * Looking at how to implement these handlers in the case of cipher support, if + * the framework wants the EVP_CIPHER for 'nid', it will call; + * foo(e, &p_evp_cipher, NULL, nid); (return zero for failure) + * If the framework wants a list of supported 'nid's, it will call; + * foo(e, NULL, &p_nids, 0); (returns number of 'nids' or -1 for error) + */ +/* Returns to a pointer to the array of supported cipher 'nid's. If the second + * parameter is non-NULL it is set to the size of the returned array. */ +typedef int (*ENGINE_CIPHERS_PTR)(ENGINE *, const EVP_CIPHER **, const int **, int); +typedef int (*ENGINE_DIGESTS_PTR)(ENGINE *, const EVP_MD **, const int **, int); + +/* STRUCTURE functions ... all of these functions deal with pointers to ENGINE + * structures where the pointers have a "structural reference". This means that + * their reference is to allowed access to the structure but it does not imply + * that the structure is functional. To simply increment or decrement the + * structural reference count, use ENGINE_by_id and ENGINE_free. NB: This is not + * required when iterating using ENGINE_get_next as it will automatically + * decrement the structural reference count of the "current" ENGINE and + * increment the structural reference count of the ENGINE it returns (unless it + * is NULL). */ + +/* Get the first/last "ENGINE" type available. */ +ENGINE *ENGINE_get_first(void); +ENGINE *ENGINE_get_last(void); +/* Iterate to the next/previous "ENGINE" type (NULL = end of the list). */ +ENGINE *ENGINE_get_next(ENGINE *e); +ENGINE *ENGINE_get_prev(ENGINE *e); +/* Add another "ENGINE" type into the array. */ +int ENGINE_add(ENGINE *e); +/* Remove an existing "ENGINE" type from the array. */ +int ENGINE_remove(ENGINE *e); +/* Retrieve an engine from the list by its unique "id" value. */ +ENGINE *ENGINE_by_id(const char *id); +/* Add all the built-in engines. */ +void ENGINE_load_openssl(void); +void ENGINE_load_dynamic(void); +#ifndef OPENSSL_NO_STATIC_ENGINE +void ENGINE_load_4758cca(void); +void ENGINE_load_aep(void); +void ENGINE_load_atalla(void); +void ENGINE_load_chil(void); +void ENGINE_load_cswift(void); +#ifndef OPENSSL_NO_GMP +void ENGINE_load_gmp(void); +#endif +void ENGINE_load_nuron(void); +void ENGINE_load_sureware(void); +void ENGINE_load_ubsec(void); +#endif +void ENGINE_load_cryptodev(void); +void ENGINE_load_padlock(void); +void ENGINE_load_builtin_engines(void); + +/* Get and set global flags (ENGINE_TABLE_FLAG_***) for the implementation + * "registry" handling. */ +unsigned int ENGINE_get_table_flags(void); +void ENGINE_set_table_flags(unsigned int flags); + +/* Manage registration of ENGINEs per "table". For each type, there are 3 + * functions; + * ENGINE_register_***(e) - registers the implementation from 'e' (if it has one) + * ENGINE_unregister_***(e) - unregister the implementation from 'e' + * ENGINE_register_all_***() - call ENGINE_register_***() for each 'e' in the list + * Cleanup is automatically registered from each table when required, so + * ENGINE_cleanup() will reverse any "register" operations. */ + +int ENGINE_register_RSA(ENGINE *e); +void ENGINE_unregister_RSA(ENGINE *e); +void ENGINE_register_all_RSA(void); + +int ENGINE_register_DSA(ENGINE *e); +void ENGINE_unregister_DSA(ENGINE *e); +void ENGINE_register_all_DSA(void); + +int ENGINE_register_ECDH(ENGINE *e); +void ENGINE_unregister_ECDH(ENGINE *e); +void ENGINE_register_all_ECDH(void); + +int ENGINE_register_ECDSA(ENGINE *e); +void ENGINE_unregister_ECDSA(ENGINE *e); +void ENGINE_register_all_ECDSA(void); + +int ENGINE_register_DH(ENGINE *e); +void ENGINE_unregister_DH(ENGINE *e); +void ENGINE_register_all_DH(void); + +int ENGINE_register_RAND(ENGINE *e); +void ENGINE_unregister_RAND(ENGINE *e); +void ENGINE_register_all_RAND(void); + +int ENGINE_register_STORE(ENGINE *e); +void ENGINE_unregister_STORE(ENGINE *e); +void ENGINE_register_all_STORE(void); + +int ENGINE_register_ciphers(ENGINE *e); +void ENGINE_unregister_ciphers(ENGINE *e); +void ENGINE_register_all_ciphers(void); + +int ENGINE_register_digests(ENGINE *e); +void ENGINE_unregister_digests(ENGINE *e); +void ENGINE_register_all_digests(void); + +/* These functions register all support from the above categories. Note, use of + * these functions can result in static linkage of code your application may not + * need. If you only need a subset of functionality, consider using more + * selective initialisation. */ +int ENGINE_register_complete(ENGINE *e); +int ENGINE_register_all_complete(void); + +/* Send parametrised control commands to the engine. The possibilities to send + * down an integer, a pointer to data or a function pointer are provided. Any of + * the parameters may or may not be NULL, depending on the command number. In + * actuality, this function only requires a structural (rather than functional) + * reference to an engine, but many control commands may require the engine be + * functional. The caller should be aware of trying commands that require an + * operational ENGINE, and only use functional references in such situations. */ +int ENGINE_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)(void)); + +/* This function tests if an ENGINE-specific command is usable as a "setting". + * Eg. in an application's config file that gets processed through + * ENGINE_ctrl_cmd_string(). If this returns zero, it is not available to + * ENGINE_ctrl_cmd_string(), only ENGINE_ctrl(). */ +int ENGINE_cmd_is_executable(ENGINE *e, int cmd); + +/* This function works like ENGINE_ctrl() with the exception of taking a + * command name instead of a command number, and can handle optional commands. + * See the comment on ENGINE_ctrl_cmd_string() for an explanation on how to + * use the cmd_name and cmd_optional. */ +int ENGINE_ctrl_cmd(ENGINE *e, const char *cmd_name, + long i, void *p, void (*f)(void), int cmd_optional); + +/* This function passes a command-name and argument to an ENGINE. The cmd_name + * is converted to a command number and the control command is called using + * 'arg' as an argument (unless the ENGINE doesn't support such a command, in + * which case no control command is called). The command is checked for input + * flags, and if necessary the argument will be converted to a numeric value. If + * cmd_optional is non-zero, then if the ENGINE doesn't support the given + * cmd_name the return value will be success anyway. This function is intended + * for applications to use so that users (or config files) can supply + * engine-specific config data to the ENGINE at run-time to control behaviour of + * specific engines. As such, it shouldn't be used for calling ENGINE_ctrl() + * functions that return data, deal with binary data, or that are otherwise + * supposed to be used directly through ENGINE_ctrl() in application code. Any + * "return" data from an ENGINE_ctrl() operation in this function will be lost - + * the return value is interpreted as failure if the return value is zero, + * success otherwise, and this function returns a boolean value as a result. In + * other words, vendors of 'ENGINE'-enabled devices should write ENGINE + * implementations with parameterisations that work in this scheme, so that + * compliant ENGINE-based applications can work consistently with the same + * configuration for the same ENGINE-enabled devices, across applications. */ +int ENGINE_ctrl_cmd_string(ENGINE *e, const char *cmd_name, const char *arg, + int cmd_optional); + +/* These functions are useful for manufacturing new ENGINE structures. They + * don't address reference counting at all - one uses them to populate an ENGINE + * structure with personalised implementations of things prior to using it + * directly or adding it to the builtin ENGINE list in OpenSSL. These are also + * here so that the ENGINE structure doesn't have to be exposed and break binary + * compatibility! */ +ENGINE *ENGINE_new(void); +int ENGINE_free(ENGINE *e); +int ENGINE_up_ref(ENGINE *e); +int ENGINE_set_id(ENGINE *e, const char *id); +int ENGINE_set_name(ENGINE *e, const char *name); +int ENGINE_set_RSA(ENGINE *e, const RSA_METHOD *rsa_meth); +int ENGINE_set_DSA(ENGINE *e, const DSA_METHOD *dsa_meth); +int ENGINE_set_ECDH(ENGINE *e, const ECDH_METHOD *ecdh_meth); +int ENGINE_set_ECDSA(ENGINE *e, const ECDSA_METHOD *ecdsa_meth); +int ENGINE_set_DH(ENGINE *e, const DH_METHOD *dh_meth); +int ENGINE_set_RAND(ENGINE *e, const RAND_METHOD *rand_meth); +int ENGINE_set_STORE(ENGINE *e, const STORE_METHOD *store_meth); +int ENGINE_set_destroy_function(ENGINE *e, ENGINE_GEN_INT_FUNC_PTR destroy_f); +int ENGINE_set_init_function(ENGINE *e, ENGINE_GEN_INT_FUNC_PTR init_f); +int ENGINE_set_finish_function(ENGINE *e, ENGINE_GEN_INT_FUNC_PTR finish_f); +int ENGINE_set_ctrl_function(ENGINE *e, ENGINE_CTRL_FUNC_PTR ctrl_f); +int ENGINE_set_load_privkey_function(ENGINE *e, ENGINE_LOAD_KEY_PTR loadpriv_f); +int ENGINE_set_load_pubkey_function(ENGINE *e, ENGINE_LOAD_KEY_PTR loadpub_f); +int ENGINE_set_ciphers(ENGINE *e, ENGINE_CIPHERS_PTR f); +int ENGINE_set_digests(ENGINE *e, ENGINE_DIGESTS_PTR f); +int ENGINE_set_flags(ENGINE *e, int flags); +int ENGINE_set_cmd_defns(ENGINE *e, const ENGINE_CMD_DEFN *defns); +/* These functions allow control over any per-structure ENGINE data. */ +int ENGINE_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func, + CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func); +int ENGINE_set_ex_data(ENGINE *e, int idx, void *arg); +void *ENGINE_get_ex_data(const ENGINE *e, int idx); + +/* This function cleans up anything that needs it. Eg. the ENGINE_add() function + * automatically ensures the list cleanup function is registered to be called + * from ENGINE_cleanup(). Similarly, all ENGINE_register_*** functions ensure + * ENGINE_cleanup() will clean up after them. */ +void ENGINE_cleanup(void); + +/* These return values from within the ENGINE structure. These can be useful + * with functional references as well as structural references - it depends + * which you obtained. Using the result for functional purposes if you only + * obtained a structural reference may be problematic! */ +const char *ENGINE_get_id(const ENGINE *e); +const char *ENGINE_get_name(const ENGINE *e); +const RSA_METHOD *ENGINE_get_RSA(const ENGINE *e); +const DSA_METHOD *ENGINE_get_DSA(const ENGINE *e); +const ECDH_METHOD *ENGINE_get_ECDH(const ENGINE *e); +const ECDSA_METHOD *ENGINE_get_ECDSA(const ENGINE *e); +const DH_METHOD *ENGINE_get_DH(const ENGINE *e); +const RAND_METHOD *ENGINE_get_RAND(const ENGINE *e); +const STORE_METHOD *ENGINE_get_STORE(const ENGINE *e); +ENGINE_GEN_INT_FUNC_PTR ENGINE_get_destroy_function(const ENGINE *e); +ENGINE_GEN_INT_FUNC_PTR ENGINE_get_init_function(const ENGINE *e); +ENGINE_GEN_INT_FUNC_PTR ENGINE_get_finish_function(const ENGINE *e); +ENGINE_CTRL_FUNC_PTR ENGINE_get_ctrl_function(const ENGINE *e); +ENGINE_LOAD_KEY_PTR ENGINE_get_load_privkey_function(const ENGINE *e); +ENGINE_LOAD_KEY_PTR ENGINE_get_load_pubkey_function(const ENGINE *e); +ENGINE_CIPHERS_PTR ENGINE_get_ciphers(const ENGINE *e); +ENGINE_DIGESTS_PTR ENGINE_get_digests(const ENGINE *e); +const EVP_CIPHER *ENGINE_get_cipher(ENGINE *e, int nid); +const EVP_MD *ENGINE_get_digest(ENGINE *e, int nid); +const ENGINE_CMD_DEFN *ENGINE_get_cmd_defns(const ENGINE *e); +int ENGINE_get_flags(const ENGINE *e); + +/* FUNCTIONAL functions. These functions deal with ENGINE structures + * that have (or will) be initialised for use. Broadly speaking, the + * structural functions are useful for iterating the list of available + * engine types, creating new engine types, and other "list" operations. + * These functions actually deal with ENGINEs that are to be used. As + * such these functions can fail (if applicable) when particular + * engines are unavailable - eg. if a hardware accelerator is not + * attached or not functioning correctly. Each ENGINE has 2 reference + * counts; structural and functional. Every time a functional reference + * is obtained or released, a corresponding structural reference is + * automatically obtained or released too. */ + +/* Initialise a engine type for use (or up its reference count if it's + * already in use). This will fail if the engine is not currently + * operational and cannot initialise. */ +int ENGINE_init(ENGINE *e); +/* Free a functional reference to a engine type. This does not require + * a corresponding call to ENGINE_free as it also releases a structural + * reference. */ +int ENGINE_finish(ENGINE *e); + +/* The following functions handle keys that are stored in some secondary + * location, handled by the engine. The storage may be on a card or + * whatever. */ +EVP_PKEY *ENGINE_load_private_key(ENGINE *e, const char *key_id, + UI_METHOD *ui_method, void *callback_data); +EVP_PKEY *ENGINE_load_public_key(ENGINE *e, const char *key_id, + UI_METHOD *ui_method, void *callback_data); + +/* This returns a pointer for the current ENGINE structure that + * is (by default) performing any RSA operations. The value returned + * is an incremented reference, so it should be free'd (ENGINE_finish) + * before it is discarded. */ +ENGINE *ENGINE_get_default_RSA(void); +/* Same for the other "methods" */ +ENGINE *ENGINE_get_default_DSA(void); +ENGINE *ENGINE_get_default_ECDH(void); +ENGINE *ENGINE_get_default_ECDSA(void); +ENGINE *ENGINE_get_default_DH(void); +ENGINE *ENGINE_get_default_RAND(void); +/* These functions can be used to get a functional reference to perform + * ciphering or digesting corresponding to "nid". */ +ENGINE *ENGINE_get_cipher_engine(int nid); +ENGINE *ENGINE_get_digest_engine(int nid); + +/* This sets a new default ENGINE structure for performing RSA + * operations. If the result is non-zero (success) then the ENGINE + * structure will have had its reference count up'd so the caller + * should still free their own reference 'e'. */ +int ENGINE_set_default_RSA(ENGINE *e); +int ENGINE_set_default_string(ENGINE *e, const char *def_list); +/* Same for the other "methods" */ +int ENGINE_set_default_DSA(ENGINE *e); +int ENGINE_set_default_ECDH(ENGINE *e); +int ENGINE_set_default_ECDSA(ENGINE *e); +int ENGINE_set_default_DH(ENGINE *e); +int ENGINE_set_default_RAND(ENGINE *e); +int ENGINE_set_default_ciphers(ENGINE *e); +int ENGINE_set_default_digests(ENGINE *e); + +/* The combination "set" - the flags are bitwise "OR"d from the + * ENGINE_METHOD_*** defines above. As with the "ENGINE_register_complete()" + * function, this function can result in unnecessary static linkage. If your + * application requires only specific functionality, consider using more + * selective functions. */ +int ENGINE_set_default(ENGINE *e, unsigned int flags); + +void ENGINE_add_conf_module(void); + +/* Deprecated functions ... */ +/* int ENGINE_clear_defaults(void); */ + +/**************************/ +/* DYNAMIC ENGINE SUPPORT */ +/**************************/ + +/* Binary/behaviour compatibility levels */ +#define OSSL_DYNAMIC_VERSION (unsigned long)0x00020000 +/* Binary versions older than this are too old for us (whether we're a loader or + * a loadee) */ +#define OSSL_DYNAMIC_OLDEST (unsigned long)0x00020000 + +/* When compiling an ENGINE entirely as an external shared library, loadable by + * the "dynamic" ENGINE, these types are needed. The 'dynamic_fns' structure + * type provides the calling application's (or library's) error functionality + * and memory management function pointers to the loaded library. These should + * be used/set in the loaded library code so that the loading application's + * 'state' will be used/changed in all operations. The 'static_state' pointer + * allows the loaded library to know if it shares the same static data as the + * calling application (or library), and thus whether these callbacks need to be + * set or not. */ +typedef void *(*dyn_MEM_malloc_cb)(size_t); +typedef void *(*dyn_MEM_realloc_cb)(void *, size_t); +typedef void (*dyn_MEM_free_cb)(void *); +typedef struct st_dynamic_MEM_fns { + dyn_MEM_malloc_cb malloc_cb; + dyn_MEM_realloc_cb realloc_cb; + dyn_MEM_free_cb free_cb; + } dynamic_MEM_fns; +/* FIXME: Perhaps the memory and locking code (crypto.h) should declare and use + * these types so we (and any other dependant code) can simplify a bit?? */ +typedef void (*dyn_lock_locking_cb)(int,int,const char *,int); +typedef int (*dyn_lock_add_lock_cb)(int*,int,int,const char *,int); +typedef struct CRYPTO_dynlock_value *(*dyn_dynlock_create_cb)( + const char *,int); +typedef void (*dyn_dynlock_lock_cb)(int,struct CRYPTO_dynlock_value *, + const char *,int); +typedef void (*dyn_dynlock_destroy_cb)(struct CRYPTO_dynlock_value *, + const char *,int); +typedef struct st_dynamic_LOCK_fns { + dyn_lock_locking_cb lock_locking_cb; + dyn_lock_add_lock_cb lock_add_lock_cb; + dyn_dynlock_create_cb dynlock_create_cb; + dyn_dynlock_lock_cb dynlock_lock_cb; + dyn_dynlock_destroy_cb dynlock_destroy_cb; + } dynamic_LOCK_fns; +/* The top-level structure */ +typedef struct st_dynamic_fns { + void *static_state; + const ERR_FNS *err_fns; + const CRYPTO_EX_DATA_IMPL *ex_data_fns; + dynamic_MEM_fns mem_fns; + dynamic_LOCK_fns lock_fns; + } dynamic_fns; + +/* The version checking function should be of this prototype. NB: The + * ossl_version value passed in is the OSSL_DYNAMIC_VERSION of the loading code. + * If this function returns zero, it indicates a (potential) version + * incompatibility and the loaded library doesn't believe it can proceed. + * Otherwise, the returned value is the (latest) version supported by the + * loading library. The loader may still decide that the loaded code's version + * is unsatisfactory and could veto the load. The function is expected to + * be implemented with the symbol name "v_check", and a default implementation + * can be fully instantiated with IMPLEMENT_DYNAMIC_CHECK_FN(). */ +typedef unsigned long (*dynamic_v_check_fn)(unsigned long ossl_version); +#define IMPLEMENT_DYNAMIC_CHECK_FN() \ + OPENSSL_EXPORT unsigned long v_check(unsigned long v) { \ + if(v >= OSSL_DYNAMIC_OLDEST) return OSSL_DYNAMIC_VERSION; \ + return 0; } + +/* This function is passed the ENGINE structure to initialise with its own + * function and command settings. It should not adjust the structural or + * functional reference counts. If this function returns zero, (a) the load will + * be aborted, (b) the previous ENGINE state will be memcpy'd back onto the + * structure, and (c) the shared library will be unloaded. So implementations + * should do their own internal cleanup in failure circumstances otherwise they + * could leak. The 'id' parameter, if non-NULL, represents the ENGINE id that + * the loader is looking for. If this is NULL, the shared library can choose to + * return failure or to initialise a 'default' ENGINE. If non-NULL, the shared + * library must initialise only an ENGINE matching the passed 'id'. The function + * is expected to be implemented with the symbol name "bind_engine". A standard + * implementation can be instantiated with IMPLEMENT_DYNAMIC_BIND_FN(fn) where + * the parameter 'fn' is a callback function that populates the ENGINE structure + * and returns an int value (zero for failure). 'fn' should have prototype; + * [static] int fn(ENGINE *e, const char *id); */ +typedef int (*dynamic_bind_engine)(ENGINE *e, const char *id, + const dynamic_fns *fns); +#define IMPLEMENT_DYNAMIC_BIND_FN(fn) \ + OPENSSL_EXPORT \ + int bind_engine(ENGINE *e, const char *id, const dynamic_fns *fns) { \ + if(ENGINE_get_static_state() == fns->static_state) goto skip_cbs; \ + if(!CRYPTO_set_mem_functions(fns->mem_fns.malloc_cb, \ + fns->mem_fns.realloc_cb, fns->mem_fns.free_cb)) \ + return 0; \ + CRYPTO_set_locking_callback(fns->lock_fns.lock_locking_cb); \ + CRYPTO_set_add_lock_callback(fns->lock_fns.lock_add_lock_cb); \ + CRYPTO_set_dynlock_create_callback(fns->lock_fns.dynlock_create_cb); \ + CRYPTO_set_dynlock_lock_callback(fns->lock_fns.dynlock_lock_cb); \ + CRYPTO_set_dynlock_destroy_callback(fns->lock_fns.dynlock_destroy_cb); \ + if(!CRYPTO_set_ex_data_implementation(fns->ex_data_fns)) \ + return 0; \ + if(!ERR_set_implementation(fns->err_fns)) return 0; \ + skip_cbs: \ + if(!fn(e,id)) return 0; \ + return 1; } + +/* If the loading application (or library) and the loaded ENGINE library share + * the same static data (eg. they're both dynamically linked to the same + * libcrypto.so) we need a way to avoid trying to set system callbacks - this + * would fail, and for the same reason that it's unnecessary to try. If the + * loaded ENGINE has (or gets from through the loader) its own copy of the + * libcrypto static data, we will need to set the callbacks. The easiest way to + * detect this is to have a function that returns a pointer to some static data + * and let the loading application and loaded ENGINE compare their respective + * values. */ +void *ENGINE_get_static_state(void); + +#if defined(__OpenBSD__) || defined(__FreeBSD__) +void ENGINE_setup_bsd_cryptodev(void); +#endif + +/* BEGIN ERROR CODES */ +/* The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ +void ERR_load_ENGINE_strings(void); + +/* Error codes for the ENGINE functions. */ + +/* Function codes. */ +#define ENGINE_F_DYNAMIC_CTRL 180 +#define ENGINE_F_DYNAMIC_GET_DATA_CTX 181 +#define ENGINE_F_DYNAMIC_LOAD 182 +#define ENGINE_F_DYNAMIC_SET_DATA_CTX 183 +#define ENGINE_F_ENGINE_ADD 105 +#define ENGINE_F_ENGINE_BY_ID 106 +#define ENGINE_F_ENGINE_CMD_IS_EXECUTABLE 170 +#define ENGINE_F_ENGINE_CTRL 142 +#define ENGINE_F_ENGINE_CTRL_CMD 178 +#define ENGINE_F_ENGINE_CTRL_CMD_STRING 171 +#define ENGINE_F_ENGINE_FINISH 107 +#define ENGINE_F_ENGINE_FREE_UTIL 108 +#define ENGINE_F_ENGINE_GET_CIPHER 185 +#define ENGINE_F_ENGINE_GET_DEFAULT_TYPE 177 +#define ENGINE_F_ENGINE_GET_DIGEST 186 +#define ENGINE_F_ENGINE_GET_NEXT 115 +#define ENGINE_F_ENGINE_GET_PREV 116 +#define ENGINE_F_ENGINE_INIT 119 +#define ENGINE_F_ENGINE_LIST_ADD 120 +#define ENGINE_F_ENGINE_LIST_REMOVE 121 +#define ENGINE_F_ENGINE_LOAD_PRIVATE_KEY 150 +#define ENGINE_F_ENGINE_LOAD_PUBLIC_KEY 151 +#define ENGINE_F_ENGINE_NEW 122 +#define ENGINE_F_ENGINE_REMOVE 123 +#define ENGINE_F_ENGINE_SET_DEFAULT_STRING 189 +#define ENGINE_F_ENGINE_SET_DEFAULT_TYPE 126 +#define ENGINE_F_ENGINE_SET_ID 129 +#define ENGINE_F_ENGINE_SET_NAME 130 +#define ENGINE_F_ENGINE_TABLE_REGISTER 184 +#define ENGINE_F_ENGINE_UNLOAD_KEY 152 +#define ENGINE_F_ENGINE_UNLOCKED_FINISH 191 +#define ENGINE_F_ENGINE_UP_REF 190 +#define ENGINE_F_INT_CTRL_HELPER 172 +#define ENGINE_F_INT_ENGINE_CONFIGURE 188 +#define ENGINE_F_INT_ENGINE_MODULE_INIT 187 +#define ENGINE_F_LOG_MESSAGE 141 + +/* Reason codes. */ +#define ENGINE_R_ALREADY_LOADED 100 +#define ENGINE_R_ARGUMENT_IS_NOT_A_NUMBER 133 +#define ENGINE_R_CMD_NOT_EXECUTABLE 134 +#define ENGINE_R_COMMAND_TAKES_INPUT 135 +#define ENGINE_R_COMMAND_TAKES_NO_INPUT 136 +#define ENGINE_R_CONFLICTING_ENGINE_ID 103 +#define ENGINE_R_CTRL_COMMAND_NOT_IMPLEMENTED 119 +#define ENGINE_R_DH_NOT_IMPLEMENTED 139 +#define ENGINE_R_DSA_NOT_IMPLEMENTED 140 +#define ENGINE_R_DSO_FAILURE 104 +#define ENGINE_R_DSO_NOT_FOUND 132 +#define ENGINE_R_ENGINES_SECTION_ERROR 148 +#define ENGINE_R_ENGINE_IS_NOT_IN_LIST 105 +#define ENGINE_R_ENGINE_SECTION_ERROR 149 +#define ENGINE_R_FAILED_LOADING_PRIVATE_KEY 128 +#define ENGINE_R_FAILED_LOADING_PUBLIC_KEY 129 +#define ENGINE_R_FINISH_FAILED 106 +#define ENGINE_R_GET_HANDLE_FAILED 107 +#define ENGINE_R_ID_OR_NAME_MISSING 108 +#define ENGINE_R_INIT_FAILED 109 +#define ENGINE_R_INTERNAL_LIST_ERROR 110 +#define ENGINE_R_INVALID_ARGUMENT 143 +#define ENGINE_R_INVALID_CMD_NAME 137 +#define ENGINE_R_INVALID_CMD_NUMBER 138 +#define ENGINE_R_INVALID_INIT_VALUE 151 +#define ENGINE_R_INVALID_STRING 150 +#define ENGINE_R_NOT_INITIALISED 117 +#define ENGINE_R_NOT_LOADED 112 +#define ENGINE_R_NO_CONTROL_FUNCTION 120 +#define ENGINE_R_NO_INDEX 144 +#define ENGINE_R_NO_LOAD_FUNCTION 125 +#define ENGINE_R_NO_REFERENCE 130 +#define ENGINE_R_NO_SUCH_ENGINE 116 +#define ENGINE_R_NO_UNLOAD_FUNCTION 126 +#define ENGINE_R_PROVIDE_PARAMETERS 113 +#define ENGINE_R_RSA_NOT_IMPLEMENTED 141 +#define ENGINE_R_UNIMPLEMENTED_CIPHER 146 +#define ENGINE_R_UNIMPLEMENTED_DIGEST 147 +#define ENGINE_R_VERSION_INCOMPATIBILITY 145 + +#ifdef __cplusplus +} +#endif +#endif diff --git a/lib_tls/include/openssl/err.h b/lib_tls/include/openssl/err.h new file mode 100644 index 000000000..bf28fce49 --- /dev/null +++ b/lib_tls/include/openssl/err.h @@ -0,0 +1,320 @@ +/* crypto/err/err.h */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#ifndef HEADER_ERR_H +#define HEADER_ERR_H + +#include + +#ifndef OPENSSL_NO_FP_API +#include +#include +#endif + +#include +#ifndef OPENSSL_NO_BIO +#include +#endif +#ifndef OPENSSL_NO_LHASH +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef OPENSSL_NO_ERR +#define ERR_PUT_error(a,b,c,d,e) ERR_put_error(a,b,c,d,e) +#else +#define ERR_PUT_error(a,b,c,d,e) ERR_put_error(a,b,c,NULL,0) +#endif + +#include + +#define ERR_TXT_MALLOCED 0x01 +#define ERR_TXT_STRING 0x02 + +#define ERR_FLAG_MARK 0x01 + +#define ERR_NUM_ERRORS 16 +typedef struct err_state_st + { + unsigned long pid; + int err_flags[ERR_NUM_ERRORS]; + unsigned long err_buffer[ERR_NUM_ERRORS]; + char *err_data[ERR_NUM_ERRORS]; + int err_data_flags[ERR_NUM_ERRORS]; + const char *err_file[ERR_NUM_ERRORS]; + int err_line[ERR_NUM_ERRORS]; + int top,bottom; + } ERR_STATE; + +/* library */ +#define ERR_LIB_NONE 1 +#define ERR_LIB_SYS 2 +#define ERR_LIB_BN 3 +#define ERR_LIB_RSA 4 +#define ERR_LIB_DH 5 +#define ERR_LIB_EVP 6 +#define ERR_LIB_BUF 7 +#define ERR_LIB_OBJ 8 +#define ERR_LIB_PEM 9 +#define ERR_LIB_DSA 10 +#define ERR_LIB_X509 11 +/* #define ERR_LIB_METH 12 */ +#define ERR_LIB_ASN1 13 +#define ERR_LIB_CONF 14 +#define ERR_LIB_CRYPTO 15 +#define ERR_LIB_EC 16 +#define ERR_LIB_SSL 20 +/* #define ERR_LIB_SSL23 21 */ +/* #define ERR_LIB_SSL2 22 */ +/* #define ERR_LIB_SSL3 23 */ +/* #define ERR_LIB_RSAREF 30 */ +/* #define ERR_LIB_PROXY 31 */ +#define ERR_LIB_BIO 32 +#define ERR_LIB_PKCS7 33 +#define ERR_LIB_X509V3 34 +#define ERR_LIB_PKCS12 35 +#define ERR_LIB_RAND 36 +#define ERR_LIB_DSO 37 +#define ERR_LIB_ENGINE 38 +#define ERR_LIB_OCSP 39 +#define ERR_LIB_UI 40 +#define ERR_LIB_COMP 41 +#define ERR_LIB_ECDSA 42 +#define ERR_LIB_ECDH 43 +#define ERR_LIB_STORE 44 +#define ERR_LIB_CMS 45 + +#define ERR_LIB_USER 128 + +#define SYSerr(f,r) ERR_PUT_error(ERR_LIB_SYS,(f),(r),__FILE__,__LINE__) +#define BNerr(f,r) ERR_PUT_error(ERR_LIB_BN,(f),(r),__FILE__,__LINE__) +#define RSAerr(f,r) ERR_PUT_error(ERR_LIB_RSA,(f),(r),__FILE__,__LINE__) +#define DHerr(f,r) ERR_PUT_error(ERR_LIB_DH,(f),(r),__FILE__,__LINE__) +#define EVPerr(f,r) ERR_PUT_error(ERR_LIB_EVP,(f),(r),__FILE__,__LINE__) +#define BUFerr(f,r) ERR_PUT_error(ERR_LIB_BUF,(f),(r),__FILE__,__LINE__) +#define OBJerr(f,r) ERR_PUT_error(ERR_LIB_OBJ,(f),(r),__FILE__,__LINE__) +#define PEMerr(f,r) ERR_PUT_error(ERR_LIB_PEM,(f),(r),__FILE__,__LINE__) +#define DSAerr(f,r) ERR_PUT_error(ERR_LIB_DSA,(f),(r),__FILE__,__LINE__) +#define X509err(f,r) ERR_PUT_error(ERR_LIB_X509,(f),(r),__FILE__,__LINE__) +#define ASN1err(f,r) ERR_PUT_error(ERR_LIB_ASN1,(f),(r),__FILE__,__LINE__) +#define CONFerr(f,r) ERR_PUT_error(ERR_LIB_CONF,(f),(r),__FILE__,__LINE__) +#define CRYPTOerr(f,r) ERR_PUT_error(ERR_LIB_CRYPTO,(f),(r),__FILE__,__LINE__) +#define ECerr(f,r) ERR_PUT_error(ERR_LIB_EC,(f),(r),__FILE__,__LINE__) +#define SSLerr(f,r) ERR_PUT_error(ERR_LIB_SSL,(f),(r),__FILE__,__LINE__) +#define BIOerr(f,r) ERR_PUT_error(ERR_LIB_BIO,(f),(r),__FILE__,__LINE__) +#define PKCS7err(f,r) ERR_PUT_error(ERR_LIB_PKCS7,(f),(r),__FILE__,__LINE__) +#define X509V3err(f,r) ERR_PUT_error(ERR_LIB_X509V3,(f),(r),__FILE__,__LINE__) +#define PKCS12err(f,r) ERR_PUT_error(ERR_LIB_PKCS12,(f),(r),__FILE__,__LINE__) +#define RANDerr(f,r) ERR_PUT_error(ERR_LIB_RAND,(f),(r),__FILE__,__LINE__) +#define DSOerr(f,r) ERR_PUT_error(ERR_LIB_DSO,(f),(r),__FILE__,__LINE__) +#define ENGINEerr(f,r) ERR_PUT_error(ERR_LIB_ENGINE,(f),(r),__FILE__,__LINE__) +#define OCSPerr(f,r) ERR_PUT_error(ERR_LIB_OCSP,(f),(r),__FILE__,__LINE__) +#define UIerr(f,r) ERR_PUT_error(ERR_LIB_UI,(f),(r),__FILE__,__LINE__) +#define COMPerr(f,r) ERR_PUT_error(ERR_LIB_COMP,(f),(r),__FILE__,__LINE__) +#define ECDSAerr(f,r) ERR_PUT_error(ERR_LIB_ECDSA,(f),(r),__FILE__,__LINE__) +#define ECDHerr(f,r) ERR_PUT_error(ERR_LIB_ECDH,(f),(r),__FILE__,__LINE__) +#define STOREerr(f,r) ERR_PUT_error(ERR_LIB_STORE,(f),(r),__FILE__,__LINE__) +#define CMSerr(f,r) ERR_PUT_error(ERR_LIB_CMS,(f),(r),__FILE__,__LINE__) + +/* Borland C seems too stupid to be able to shift and do longs in + * the pre-processor :-( */ +#define ERR_PACK(l,f,r) (((((unsigned long)l)&0xffL)*0x1000000)| \ + ((((unsigned long)f)&0xfffL)*0x1000)| \ + ((((unsigned long)r)&0xfffL))) +#define ERR_GET_LIB(l) (int)((((unsigned long)l)>>24L)&0xffL) +#define ERR_GET_FUNC(l) (int)((((unsigned long)l)>>12L)&0xfffL) +#define ERR_GET_REASON(l) (int)((l)&0xfffL) +#define ERR_FATAL_ERROR(l) (int)((l)&ERR_R_FATAL) + + +/* OS functions */ +#define SYS_F_FOPEN 1 +#define SYS_F_CONNECT 2 +#define SYS_F_GETSERVBYNAME 3 +#define SYS_F_SOCKET 4 +#define SYS_F_IOCTLSOCKET 5 +#define SYS_F_BIND 6 +#define SYS_F_LISTEN 7 +#define SYS_F_ACCEPT 8 +#define SYS_F_WSASTARTUP 9 /* Winsock stuff */ +#define SYS_F_OPENDIR 10 +#define SYS_F_FREAD 11 + + +/* reasons */ +#define ERR_R_SYS_LIB ERR_LIB_SYS /* 2 */ +#define ERR_R_BN_LIB ERR_LIB_BN /* 3 */ +#define ERR_R_RSA_LIB ERR_LIB_RSA /* 4 */ +#define ERR_R_DH_LIB ERR_LIB_DH /* 5 */ +#define ERR_R_EVP_LIB ERR_LIB_EVP /* 6 */ +#define ERR_R_BUF_LIB ERR_LIB_BUF /* 7 */ +#define ERR_R_OBJ_LIB ERR_LIB_OBJ /* 8 */ +#define ERR_R_PEM_LIB ERR_LIB_PEM /* 9 */ +#define ERR_R_DSA_LIB ERR_LIB_DSA /* 10 */ +#define ERR_R_X509_LIB ERR_LIB_X509 /* 11 */ +#define ERR_R_ASN1_LIB ERR_LIB_ASN1 /* 13 */ +#define ERR_R_CONF_LIB ERR_LIB_CONF /* 14 */ +#define ERR_R_CRYPTO_LIB ERR_LIB_CRYPTO /* 15 */ +#define ERR_R_EC_LIB ERR_LIB_EC /* 16 */ +#define ERR_R_SSL_LIB ERR_LIB_SSL /* 20 */ +#define ERR_R_BIO_LIB ERR_LIB_BIO /* 32 */ +#define ERR_R_PKCS7_LIB ERR_LIB_PKCS7 /* 33 */ +#define ERR_R_X509V3_LIB ERR_LIB_X509V3 /* 34 */ +#define ERR_R_PKCS12_LIB ERR_LIB_PKCS12 /* 35 */ +#define ERR_R_RAND_LIB ERR_LIB_RAND /* 36 */ +#define ERR_R_DSO_LIB ERR_LIB_DSO /* 37 */ +#define ERR_R_ENGINE_LIB ERR_LIB_ENGINE /* 38 */ +#define ERR_R_OCSP_LIB ERR_LIB_OCSP /* 39 */ +#define ERR_R_UI_LIB ERR_LIB_UI /* 40 */ +#define ERR_R_COMP_LIB ERR_LIB_COMP /* 41 */ +#define ERR_R_ECDSA_LIB ERR_LIB_ECDSA /* 42 */ +#define ERR_R_ECDH_LIB ERR_LIB_ECDH /* 43 */ +#define ERR_R_STORE_LIB ERR_LIB_STORE /* 44 */ + +#define ERR_R_NESTED_ASN1_ERROR 58 +#define ERR_R_BAD_ASN1_OBJECT_HEADER 59 +#define ERR_R_BAD_GET_ASN1_OBJECT_CALL 60 +#define ERR_R_EXPECTING_AN_ASN1_SEQUENCE 61 +#define ERR_R_ASN1_LENGTH_MISMATCH 62 +#define ERR_R_MISSING_ASN1_EOS 63 + +/* fatal error */ +#define ERR_R_FATAL 64 +#define ERR_R_MALLOC_FAILURE (1|ERR_R_FATAL) +#define ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED (2|ERR_R_FATAL) +#define ERR_R_PASSED_NULL_PARAMETER (3|ERR_R_FATAL) +#define ERR_R_INTERNAL_ERROR (4|ERR_R_FATAL) +#define ERR_R_DISABLED (5|ERR_R_FATAL) + +/* 99 is the maximum possible ERR_R_... code, higher values + * are reserved for the individual libraries */ + + +typedef struct ERR_string_data_st + { + unsigned long error; + const char *string; + } ERR_STRING_DATA; + +void ERR_put_error(int lib, int func,int reason,const char *file,int line); +void ERR_set_error_data(char *data,int flags); + +unsigned long ERR_get_error(void); +unsigned long ERR_get_error_line(const char **file,int *line); +unsigned long ERR_get_error_line_data(const char **file,int *line, + const char **data, int *flags); +unsigned long ERR_peek_error(void); +unsigned long ERR_peek_error_line(const char **file,int *line); +unsigned long ERR_peek_error_line_data(const char **file,int *line, + const char **data,int *flags); +unsigned long ERR_peek_last_error(void); +unsigned long ERR_peek_last_error_line(const char **file,int *line); +unsigned long ERR_peek_last_error_line_data(const char **file,int *line, + const char **data,int *flags); +void ERR_clear_error(void ); +char *ERR_error_string(unsigned long e,char *buf); +void ERR_error_string_n(unsigned long e, char *buf, size_t len); +const char *ERR_lib_error_string(unsigned long e); +const char *ERR_func_error_string(unsigned long e); +const char *ERR_reason_error_string(unsigned long e); +void ERR_print_errors_cb(int (*cb)(const char *str, size_t len, void *u), + void *u); +#ifndef OPENSSL_NO_FP_API +void ERR_print_errors_fp(FILE *fp); +#endif +#ifndef OPENSSL_NO_BIO +void ERR_print_errors(BIO *bp); +void ERR_add_error_data(int num, ...); +#endif +void ERR_load_strings(int lib,ERR_STRING_DATA str[]); +void ERR_unload_strings(int lib,ERR_STRING_DATA str[]); +void ERR_load_ERR_strings(void); +void ERR_load_crypto_strings(void); +void ERR_free_strings(void); + +void ERR_remove_state(unsigned long pid); /* if zero we look it up */ +ERR_STATE *ERR_get_state(void); + +#ifndef OPENSSL_NO_LHASH +LHASH *ERR_get_string_table(void); +LHASH *ERR_get_err_state_table(void); +void ERR_release_err_state_table(LHASH **hash); +#endif + +int ERR_get_next_error_library(void); + +int ERR_set_mark(void); +int ERR_pop_to_mark(void); + +/* Already defined in ossl_typ.h */ +/* typedef struct st_ERR_FNS ERR_FNS; */ +/* An application can use this function and provide the return value to loaded + * modules that should use the application's ERR state/functionality */ +const ERR_FNS *ERR_get_implementation(void); +/* A loaded module should call this function prior to any ERR operations using + * the application's "ERR_FNS". */ +int ERR_set_implementation(const ERR_FNS *fns); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_tls/include/openssl/evp.h b/lib_tls/include/openssl/evp.h new file mode 100644 index 000000000..bdd3b7eca --- /dev/null +++ b/lib_tls/include/openssl/evp.h @@ -0,0 +1,979 @@ +/* crypto/evp/evp.h */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#ifndef HEADER_ENVELOPE_H +#define HEADER_ENVELOPE_H + +#ifdef OPENSSL_ALGORITHM_DEFINES +# include +#else +# define OPENSSL_ALGORITHM_DEFINES +# include +# undef OPENSSL_ALGORITHM_DEFINES +#endif + +#include + +#include + +#ifndef OPENSSL_NO_BIO +#include +#endif + +/* +#define EVP_RC2_KEY_SIZE 16 +#define EVP_RC4_KEY_SIZE 16 +#define EVP_BLOWFISH_KEY_SIZE 16 +#define EVP_CAST5_KEY_SIZE 16 +#define EVP_RC5_32_12_16_KEY_SIZE 16 +*/ +#define EVP_MAX_MD_SIZE 64 /* longest known is SHA512 */ +#define EVP_MAX_KEY_LENGTH 32 +#define EVP_MAX_IV_LENGTH 16 +#define EVP_MAX_BLOCK_LENGTH 32 + +#define PKCS5_SALT_LEN 8 +/* Default PKCS#5 iteration count */ +#define PKCS5_DEFAULT_ITER 2048 + +#include + +#define EVP_PK_RSA 0x0001 +#define EVP_PK_DSA 0x0002 +#define EVP_PK_DH 0x0004 +#define EVP_PK_EC 0x0008 +#define EVP_PKT_SIGN 0x0010 +#define EVP_PKT_ENC 0x0020 +#define EVP_PKT_EXCH 0x0040 +#define EVP_PKS_RSA 0x0100 +#define EVP_PKS_DSA 0x0200 +#define EVP_PKS_EC 0x0400 +#define EVP_PKT_EXP 0x1000 /* <= 512 bit key */ + +#define EVP_PKEY_NONE NID_undef +#define EVP_PKEY_RSA NID_rsaEncryption +#define EVP_PKEY_RSA2 NID_rsa +#define EVP_PKEY_DSA NID_dsa +#define EVP_PKEY_DSA1 NID_dsa_2 +#define EVP_PKEY_DSA2 NID_dsaWithSHA +#define EVP_PKEY_DSA3 NID_dsaWithSHA1 +#define EVP_PKEY_DSA4 NID_dsaWithSHA1_2 +#define EVP_PKEY_DH NID_dhKeyAgreement +#define EVP_PKEY_EC NID_X9_62_id_ecPublicKey + +#ifdef __cplusplus +extern "C" { +#endif + +/* Type needs to be a bit field + * Sub-type needs to be for variations on the method, as in, can it do + * arbitrary encryption.... */ +struct evp_pkey_st + { + int type; + int save_type; + int references; + union { + char *ptr; +#ifndef OPENSSL_NO_RSA + struct rsa_st *rsa; /* RSA */ +#endif +#ifndef OPENSSL_NO_DSA + struct dsa_st *dsa; /* DSA */ +#endif +#ifndef OPENSSL_NO_DH + struct dh_st *dh; /* DH */ +#endif +#ifndef OPENSSL_NO_EC + struct ec_key_st *ec; /* ECC */ +#endif + } pkey; + int save_parameters; + STACK_OF(X509_ATTRIBUTE) *attributes; /* [ 0 ] */ + } /* EVP_PKEY */; + +#define EVP_PKEY_MO_SIGN 0x0001 +#define EVP_PKEY_MO_VERIFY 0x0002 +#define EVP_PKEY_MO_ENCRYPT 0x0004 +#define EVP_PKEY_MO_DECRYPT 0x0008 + +#if 0 +/* This structure is required to tie the message digest and signing together. + * The lookup can be done by md/pkey_method, oid, oid/pkey_method, or + * oid, md and pkey. + * This is required because for various smart-card perform the digest and + * signing/verification on-board. To handle this case, the specific + * EVP_MD and EVP_PKEY_METHODs need to be closely associated. + * When a PKEY is created, it will have a EVP_PKEY_METHOD associated with it. + * This can either be software or a token to provide the required low level + * routines. + */ +typedef struct evp_pkey_md_st + { + int oid; + EVP_MD *md; + EVP_PKEY_METHOD *pkey; + } EVP_PKEY_MD; + +#define EVP_rsa_md2() \ + EVP_PKEY_MD_add(NID_md2WithRSAEncryption,\ + EVP_rsa_pkcs1(),EVP_md2()) +#define EVP_rsa_md5() \ + EVP_PKEY_MD_add(NID_md5WithRSAEncryption,\ + EVP_rsa_pkcs1(),EVP_md5()) +#define EVP_rsa_sha0() \ + EVP_PKEY_MD_add(NID_shaWithRSAEncryption,\ + EVP_rsa_pkcs1(),EVP_sha()) +#define EVP_rsa_sha1() \ + EVP_PKEY_MD_add(NID_sha1WithRSAEncryption,\ + EVP_rsa_pkcs1(),EVP_sha1()) +#define EVP_rsa_ripemd160() \ + EVP_PKEY_MD_add(NID_ripemd160WithRSA,\ + EVP_rsa_pkcs1(),EVP_ripemd160()) +#define EVP_rsa_mdc2() \ + EVP_PKEY_MD_add(NID_mdc2WithRSA,\ + EVP_rsa_octet_string(),EVP_mdc2()) +#define EVP_dsa_sha() \ + EVP_PKEY_MD_add(NID_dsaWithSHA,\ + EVP_dsa(),EVP_sha()) +#define EVP_dsa_sha1() \ + EVP_PKEY_MD_add(NID_dsaWithSHA1,\ + EVP_dsa(),EVP_sha1()) + +typedef struct evp_pkey_method_st + { + char *name; + int flags; + int type; /* RSA, DSA, an SSLeay specific constant */ + int oid; /* For the pub-key type */ + int encrypt_oid; /* pub/priv key encryption */ + + int (*sign)(); + int (*verify)(); + struct { + int (*set)(); /* get and/or set the underlying type */ + int (*get)(); + int (*encrypt)(); + int (*decrypt)(); + int (*i2d)(); + int (*d2i)(); + int (*dup)(); + } pub,priv; + int (*set_asn1_parameters)(); + int (*get_asn1_parameters)(); + } EVP_PKEY_METHOD; +#endif + +#ifndef EVP_MD +struct env_md_st + { + int type; + int pkey_type; + int md_size; + unsigned long flags; + int (*init)(EVP_MD_CTX *ctx); + int (*update)(EVP_MD_CTX *ctx,const void *data,size_t count); + int (*final)(EVP_MD_CTX *ctx,unsigned char *md); + int (*copy)(EVP_MD_CTX *to,const EVP_MD_CTX *from); + int (*cleanup)(EVP_MD_CTX *ctx); + + /* FIXME: prototype these some day */ + int (*sign)(int type, const unsigned char *m, unsigned int m_length, + unsigned char *sigret, unsigned int *siglen, void *key); + int (*verify)(int type, const unsigned char *m, unsigned int m_length, + const unsigned char *sigbuf, unsigned int siglen, + void *key); + int required_pkey_type[5]; /*EVP_PKEY_xxx */ + int block_size; + int ctx_size; /* how big does the ctx->md_data need to be */ + } /* EVP_MD */; + +typedef int evp_sign_method(int type,const unsigned char *m, + unsigned int m_length,unsigned char *sigret, + unsigned int *siglen, void *key); +typedef int evp_verify_method(int type,const unsigned char *m, + unsigned int m_length,const unsigned char *sigbuf, + unsigned int siglen, void *key); + +#define EVP_MD_FLAG_ONESHOT 0x0001 /* digest can only handle a single + * block */ + +#define EVP_PKEY_NULL_method NULL,NULL,{0,0,0,0} + +#ifndef OPENSSL_NO_DSA +#define EVP_PKEY_DSA_method (evp_sign_method *)DSA_sign, \ + (evp_verify_method *)DSA_verify, \ + {EVP_PKEY_DSA,EVP_PKEY_DSA2,EVP_PKEY_DSA3, \ + EVP_PKEY_DSA4,0} +#else +#define EVP_PKEY_DSA_method EVP_PKEY_NULL_method +#endif + +#ifndef OPENSSL_NO_ECDSA +#define EVP_PKEY_ECDSA_method (evp_sign_method *)ECDSA_sign, \ + (evp_verify_method *)ECDSA_verify, \ + {EVP_PKEY_EC,0,0,0} +#else +#define EVP_PKEY_ECDSA_method EVP_PKEY_NULL_method +#endif + +#ifndef OPENSSL_NO_RSA +#define EVP_PKEY_RSA_method (evp_sign_method *)RSA_sign, \ + (evp_verify_method *)RSA_verify, \ + {EVP_PKEY_RSA,EVP_PKEY_RSA2,0,0} +#define EVP_PKEY_RSA_ASN1_OCTET_STRING_method \ + (evp_sign_method *)RSA_sign_ASN1_OCTET_STRING, \ + (evp_verify_method *)RSA_verify_ASN1_OCTET_STRING, \ + {EVP_PKEY_RSA,EVP_PKEY_RSA2,0,0} +#else +#define EVP_PKEY_RSA_method EVP_PKEY_NULL_method +#define EVP_PKEY_RSA_ASN1_OCTET_STRING_method EVP_PKEY_NULL_method +#endif + +#endif /* !EVP_MD */ + +struct env_md_ctx_st + { + const EVP_MD *digest; + ENGINE *engine; /* functional reference if 'digest' is ENGINE-provided */ + unsigned long flags; + void *md_data; + } /* EVP_MD_CTX */; + +/* values for EVP_MD_CTX flags */ + +#define EVP_MD_CTX_FLAG_ONESHOT 0x0001 /* digest update will be called + * once only */ +#define EVP_MD_CTX_FLAG_CLEANED 0x0002 /* context has already been + * cleaned */ +#define EVP_MD_CTX_FLAG_REUSE 0x0004 /* Don't free up ctx->md_data + * in EVP_MD_CTX_cleanup */ + +struct evp_cipher_st + { + int nid; + int block_size; + int key_len; /* Default value for variable length ciphers */ + int iv_len; + unsigned long flags; /* Various flags */ + int (*init)(EVP_CIPHER_CTX *ctx, const unsigned char *key, + const unsigned char *iv, int enc); /* init key */ + int (*do_cipher)(EVP_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, unsigned int inl);/* encrypt/decrypt data */ + int (*cleanup)(EVP_CIPHER_CTX *); /* cleanup ctx */ + int ctx_size; /* how big ctx->cipher_data needs to be */ + int (*set_asn1_parameters)(EVP_CIPHER_CTX *, ASN1_TYPE *); /* Populate a ASN1_TYPE with parameters */ + int (*get_asn1_parameters)(EVP_CIPHER_CTX *, ASN1_TYPE *); /* Get parameters from a ASN1_TYPE */ + int (*ctrl)(EVP_CIPHER_CTX *, int type, int arg, void *ptr); /* Miscellaneous operations */ + void *app_data; /* Application data */ + } /* EVP_CIPHER */; + +/* Values for cipher flags */ + +/* Modes for ciphers */ + +#define EVP_CIPH_STREAM_CIPHER 0x0 +#define EVP_CIPH_ECB_MODE 0x1 +#define EVP_CIPH_CBC_MODE 0x2 +#define EVP_CIPH_CFB_MODE 0x3 +#define EVP_CIPH_OFB_MODE 0x4 +#define EVP_CIPH_MODE 0x7 +/* Set if variable length cipher */ +#define EVP_CIPH_VARIABLE_LENGTH 0x8 +/* Set if the iv handling should be done by the cipher itself */ +#define EVP_CIPH_CUSTOM_IV 0x10 +/* Set if the cipher's init() function should be called if key is NULL */ +#define EVP_CIPH_ALWAYS_CALL_INIT 0x20 +/* Call ctrl() to init cipher parameters */ +#define EVP_CIPH_CTRL_INIT 0x40 +/* Don't use standard key length function */ +#define EVP_CIPH_CUSTOM_KEY_LENGTH 0x80 +/* Don't use standard block padding */ +#define EVP_CIPH_NO_PADDING 0x100 +/* cipher handles random key generation */ +#define EVP_CIPH_RAND_KEY 0x200 + +/* ctrl() values */ + +#define EVP_CTRL_INIT 0x0 +#define EVP_CTRL_SET_KEY_LENGTH 0x1 +#define EVP_CTRL_GET_RC2_KEY_BITS 0x2 +#define EVP_CTRL_SET_RC2_KEY_BITS 0x3 +#define EVP_CTRL_GET_RC5_ROUNDS 0x4 +#define EVP_CTRL_SET_RC5_ROUNDS 0x5 +#define EVP_CTRL_RAND_KEY 0x6 + +typedef struct evp_cipher_info_st + { + const EVP_CIPHER *cipher; + unsigned char iv[EVP_MAX_IV_LENGTH]; + } EVP_CIPHER_INFO; + +struct evp_cipher_ctx_st + { + const EVP_CIPHER *cipher; + ENGINE *engine; /* functional reference if 'cipher' is ENGINE-provided */ + int encrypt; /* encrypt or decrypt */ + int buf_len; /* number we have left */ + + unsigned char oiv[EVP_MAX_IV_LENGTH]; /* original iv */ + unsigned char iv[EVP_MAX_IV_LENGTH]; /* working iv */ + unsigned char buf[EVP_MAX_BLOCK_LENGTH];/* saved partial block */ + int num; /* used by cfb/ofb mode */ + + void *app_data; /* application stuff */ + int key_len; /* May change for variable length cipher */ + unsigned long flags; /* Various flags */ + void *cipher_data; /* per EVP data */ + int final_used; + int block_mask; + unsigned char final[EVP_MAX_BLOCK_LENGTH];/* possible final block */ + } /* EVP_CIPHER_CTX */; + +typedef struct evp_Encode_Ctx_st + { + int num; /* number saved in a partial encode/decode */ + int length; /* The length is either the output line length + * (in input bytes) or the shortest input line + * length that is ok. Once decoding begins, + * the length is adjusted up each time a longer + * line is decoded */ + unsigned char enc_data[80]; /* data to encode */ + int line_num; /* number read on current line */ + int expect_nl; + } EVP_ENCODE_CTX; + +/* Password based encryption function */ +typedef int (EVP_PBE_KEYGEN)(EVP_CIPHER_CTX *ctx, const char *pass, int passlen, + ASN1_TYPE *param, const EVP_CIPHER *cipher, + const EVP_MD *md, int en_de); + +#ifndef OPENSSL_NO_RSA +#define EVP_PKEY_assign_RSA(pkey,rsa) EVP_PKEY_assign((pkey),EVP_PKEY_RSA,\ + (char *)(rsa)) +#endif + +#ifndef OPENSSL_NO_DSA +#define EVP_PKEY_assign_DSA(pkey,dsa) EVP_PKEY_assign((pkey),EVP_PKEY_DSA,\ + (char *)(dsa)) +#endif + +#ifndef OPENSSL_NO_DH +#define EVP_PKEY_assign_DH(pkey,dh) EVP_PKEY_assign((pkey),EVP_PKEY_DH,\ + (char *)(dh)) +#endif + +#ifndef OPENSSL_NO_EC +#define EVP_PKEY_assign_EC_KEY(pkey,eckey) EVP_PKEY_assign((pkey),EVP_PKEY_EC,\ + (char *)(eckey)) +#endif + +/* Add some extra combinations */ +#define EVP_get_digestbynid(a) EVP_get_digestbyname(OBJ_nid2sn(a)) +#define EVP_get_digestbyobj(a) EVP_get_digestbynid(OBJ_obj2nid(a)) +#define EVP_get_cipherbynid(a) EVP_get_cipherbyname(OBJ_nid2sn(a)) +#define EVP_get_cipherbyobj(a) EVP_get_cipherbynid(OBJ_obj2nid(a)) + +int EVP_MD_type(const EVP_MD *md); +#define EVP_MD_nid(e) EVP_MD_type(e) +#define EVP_MD_name(e) OBJ_nid2sn(EVP_MD_nid(e)) +int EVP_MD_pkey_type(const EVP_MD *md); +int EVP_MD_size(const EVP_MD *md); +int EVP_MD_block_size(const EVP_MD *md); + +const EVP_MD * EVP_MD_CTX_md(const EVP_MD_CTX *ctx); +#define EVP_MD_CTX_size(e) EVP_MD_size(EVP_MD_CTX_md(e)) +#define EVP_MD_CTX_block_size(e) EVP_MD_block_size(EVP_MD_CTX_md(e)) +#define EVP_MD_CTX_type(e) EVP_MD_type(EVP_MD_CTX_md(e)) + +int EVP_CIPHER_nid(const EVP_CIPHER *cipher); +#define EVP_CIPHER_name(e) OBJ_nid2sn(EVP_CIPHER_nid(e)) +int EVP_CIPHER_block_size(const EVP_CIPHER *cipher); +int EVP_CIPHER_key_length(const EVP_CIPHER *cipher); +int EVP_CIPHER_iv_length(const EVP_CIPHER *cipher); +unsigned long EVP_CIPHER_flags(const EVP_CIPHER *cipher); +#define EVP_CIPHER_mode(e) (EVP_CIPHER_flags(e) & EVP_CIPH_MODE) + +const EVP_CIPHER * EVP_CIPHER_CTX_cipher(const EVP_CIPHER_CTX *ctx); +int EVP_CIPHER_CTX_nid(const EVP_CIPHER_CTX *ctx); +int EVP_CIPHER_CTX_block_size(const EVP_CIPHER_CTX *ctx); +int EVP_CIPHER_CTX_key_length(const EVP_CIPHER_CTX *ctx); +int EVP_CIPHER_CTX_iv_length(const EVP_CIPHER_CTX *ctx); +void * EVP_CIPHER_CTX_get_app_data(const EVP_CIPHER_CTX *ctx); +void EVP_CIPHER_CTX_set_app_data(EVP_CIPHER_CTX *ctx, void *data); +#define EVP_CIPHER_CTX_type(c) EVP_CIPHER_type(EVP_CIPHER_CTX_cipher(c)) +unsigned long EVP_CIPHER_CTX_flags(const EVP_CIPHER_CTX *ctx); +#define EVP_CIPHER_CTX_mode(e) (EVP_CIPHER_CTX_flags(e) & EVP_CIPH_MODE) + +#define EVP_ENCODE_LENGTH(l) (((l+2)/3*4)+(l/48+1)*2+80) +#define EVP_DECODE_LENGTH(l) ((l+3)/4*3+80) + +#define EVP_SignInit_ex(a,b,c) EVP_DigestInit_ex(a,b,c) +#define EVP_SignInit(a,b) EVP_DigestInit(a,b) +#define EVP_SignUpdate(a,b,c) EVP_DigestUpdate(a,b,c) +#define EVP_VerifyInit_ex(a,b,c) EVP_DigestInit_ex(a,b,c) +#define EVP_VerifyInit(a,b) EVP_DigestInit(a,b) +#define EVP_VerifyUpdate(a,b,c) EVP_DigestUpdate(a,b,c) +#define EVP_OpenUpdate(a,b,c,d,e) EVP_DecryptUpdate(a,b,c,d,e) +#define EVP_SealUpdate(a,b,c,d,e) EVP_EncryptUpdate(a,b,c,d,e) + +#ifdef CONST_STRICT +void BIO_set_md(BIO *,const EVP_MD *md); +#else +# define BIO_set_md(b,md) BIO_ctrl(b,BIO_C_SET_MD,0,(char *)md) +#endif +#define BIO_get_md(b,mdp) BIO_ctrl(b,BIO_C_GET_MD,0,(char *)mdp) +#define BIO_get_md_ctx(b,mdcp) BIO_ctrl(b,BIO_C_GET_MD_CTX,0,(char *)mdcp) +#define BIO_set_md_ctx(b,mdcp) BIO_ctrl(b,BIO_C_SET_MD_CTX,0,(char *)mdcp) +#define BIO_get_cipher_status(b) BIO_ctrl(b,BIO_C_GET_CIPHER_STATUS,0,NULL) +#define BIO_get_cipher_ctx(b,c_pp) BIO_ctrl(b,BIO_C_GET_CIPHER_CTX,0,(char *)c_pp) + +int EVP_Cipher(EVP_CIPHER_CTX *c, + unsigned char *out, + const unsigned char *in, + unsigned int inl); + +#define EVP_add_cipher_alias(n,alias) \ + OBJ_NAME_add((alias),OBJ_NAME_TYPE_CIPHER_METH|OBJ_NAME_ALIAS,(n)) +#define EVP_add_digest_alias(n,alias) \ + OBJ_NAME_add((alias),OBJ_NAME_TYPE_MD_METH|OBJ_NAME_ALIAS,(n)) +#define EVP_delete_cipher_alias(alias) \ + OBJ_NAME_remove(alias,OBJ_NAME_TYPE_CIPHER_METH|OBJ_NAME_ALIAS); +#define EVP_delete_digest_alias(alias) \ + OBJ_NAME_remove(alias,OBJ_NAME_TYPE_MD_METH|OBJ_NAME_ALIAS); + +void EVP_MD_CTX_init(EVP_MD_CTX *ctx); +int EVP_MD_CTX_cleanup(EVP_MD_CTX *ctx); +EVP_MD_CTX *EVP_MD_CTX_create(void); +void EVP_MD_CTX_destroy(EVP_MD_CTX *ctx); +int EVP_MD_CTX_copy_ex(EVP_MD_CTX *out,const EVP_MD_CTX *in); +void EVP_MD_CTX_set_flags(EVP_MD_CTX *ctx, int flags); +void EVP_MD_CTX_clear_flags(EVP_MD_CTX *ctx, int flags); +int EVP_MD_CTX_test_flags(const EVP_MD_CTX *ctx,int flags); +int EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl); +int EVP_DigestUpdate(EVP_MD_CTX *ctx,const void *d, + size_t cnt); +int EVP_DigestFinal_ex(EVP_MD_CTX *ctx,unsigned char *md,unsigned int *s); +int EVP_Digest(const void *data, size_t count, + unsigned char *md, unsigned int *size, const EVP_MD *type, ENGINE *impl); + +int EVP_MD_CTX_copy(EVP_MD_CTX *out,const EVP_MD_CTX *in); +int EVP_DigestInit(EVP_MD_CTX *ctx, const EVP_MD *type); +int EVP_DigestFinal(EVP_MD_CTX *ctx,unsigned char *md,unsigned int *s); + +int EVP_read_pw_string(char *buf,int length,const char *prompt,int verify); +void EVP_set_pw_prompt(const char *prompt); +char * EVP_get_pw_prompt(void); + +int EVP_BytesToKey(const EVP_CIPHER *type,const EVP_MD *md, + const unsigned char *salt, const unsigned char *data, + int datal, int count, unsigned char *key,unsigned char *iv); + +int EVP_EncryptInit(EVP_CIPHER_CTX *ctx,const EVP_CIPHER *cipher, + const unsigned char *key, const unsigned char *iv); +int EVP_EncryptInit_ex(EVP_CIPHER_CTX *ctx,const EVP_CIPHER *cipher, ENGINE *impl, + const unsigned char *key, const unsigned char *iv); +int EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, + int *outl, const unsigned char *in, int inl); +int EVP_EncryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl); +int EVP_EncryptFinal(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl); + +int EVP_DecryptInit(EVP_CIPHER_CTX *ctx,const EVP_CIPHER *cipher, + const unsigned char *key, const unsigned char *iv); +int EVP_DecryptInit_ex(EVP_CIPHER_CTX *ctx,const EVP_CIPHER *cipher, ENGINE *impl, + const unsigned char *key, const unsigned char *iv); +int EVP_DecryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, + int *outl, const unsigned char *in, int inl); +int EVP_DecryptFinal(EVP_CIPHER_CTX *ctx, unsigned char *outm, int *outl); +int EVP_DecryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *outm, int *outl); + +int EVP_CipherInit(EVP_CIPHER_CTX *ctx,const EVP_CIPHER *cipher, + const unsigned char *key,const unsigned char *iv, + int enc); +int EVP_CipherInit_ex(EVP_CIPHER_CTX *ctx,const EVP_CIPHER *cipher, ENGINE *impl, + const unsigned char *key,const unsigned char *iv, + int enc); +int EVP_CipherUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, + int *outl, const unsigned char *in, int inl); +int EVP_CipherFinal(EVP_CIPHER_CTX *ctx, unsigned char *outm, int *outl); +int EVP_CipherFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *outm, int *outl); + +int EVP_SignFinal(EVP_MD_CTX *ctx,unsigned char *md,unsigned int *s, + EVP_PKEY *pkey); + +int EVP_VerifyFinal(EVP_MD_CTX *ctx,const unsigned char *sigbuf, + unsigned int siglen,EVP_PKEY *pkey); + +int EVP_OpenInit(EVP_CIPHER_CTX *ctx,const EVP_CIPHER *type, + const unsigned char *ek, int ekl, const unsigned char *iv, + EVP_PKEY *priv); +int EVP_OpenFinal(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl); + +int EVP_SealInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type, + unsigned char **ek, int *ekl, unsigned char *iv, + EVP_PKEY **pubk, int npubk); +int EVP_SealFinal(EVP_CIPHER_CTX *ctx,unsigned char *out,int *outl); + +void EVP_EncodeInit(EVP_ENCODE_CTX *ctx); +void EVP_EncodeUpdate(EVP_ENCODE_CTX *ctx,unsigned char *out,int *outl, + const unsigned char *in,int inl); +void EVP_EncodeFinal(EVP_ENCODE_CTX *ctx,unsigned char *out,int *outl); +int EVP_EncodeBlock(unsigned char *t, const unsigned char *f, int n); + +void EVP_DecodeInit(EVP_ENCODE_CTX *ctx); +int EVP_DecodeUpdate(EVP_ENCODE_CTX *ctx,unsigned char *out,int *outl, + const unsigned char *in, int inl); +int EVP_DecodeFinal(EVP_ENCODE_CTX *ctx, unsigned + char *out, int *outl); +int EVP_DecodeBlock(unsigned char *t, const unsigned char *f, int n); + +void EVP_CIPHER_CTX_init(EVP_CIPHER_CTX *a); +int EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *a); +EVP_CIPHER_CTX *EVP_CIPHER_CTX_new(void); +void EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *a); +int EVP_CIPHER_CTX_set_key_length(EVP_CIPHER_CTX *x, int keylen); +int EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX *c, int pad); +int EVP_CIPHER_CTX_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr); +int EVP_CIPHER_CTX_rand_key(EVP_CIPHER_CTX *ctx, unsigned char *key); + +#ifndef OPENSSL_NO_BIO +BIO_METHOD *BIO_f_md(void); +BIO_METHOD *BIO_f_base64(void); +BIO_METHOD *BIO_f_cipher(void); +BIO_METHOD *BIO_f_reliable(void); +void BIO_set_cipher(BIO *b,const EVP_CIPHER *c,const unsigned char *k, + const unsigned char *i, int enc); +#endif + +const EVP_MD *EVP_md_null(void); +#ifndef OPENSSL_NO_MD2 +const EVP_MD *EVP_md2(void); +#endif +#ifndef OPENSSL_NO_MD4 +const EVP_MD *EVP_md4(void); +#endif +#ifndef OPENSSL_NO_MD5 +const EVP_MD *EVP_md5(void); +#endif +#ifndef OPENSSL_NO_SHA +const EVP_MD *EVP_sha(void); +const EVP_MD *EVP_sha1(void); +const EVP_MD *EVP_dss(void); +const EVP_MD *EVP_dss1(void); +const EVP_MD *EVP_ecdsa(void); +#endif +#ifndef OPENSSL_NO_SHA256 +const EVP_MD *EVP_sha224(void); +const EVP_MD *EVP_sha256(void); +#endif +#ifndef OPENSSL_NO_SHA512 +const EVP_MD *EVP_sha384(void); +const EVP_MD *EVP_sha512(void); +#endif +#ifndef OPENSSL_NO_MDC2 +const EVP_MD *EVP_mdc2(void); +#endif +#ifndef OPENSSL_NO_RIPEMD +const EVP_MD *EVP_ripemd160(void); +#endif +const EVP_CIPHER *EVP_enc_null(void); /* does nothing :-) */ +#ifndef OPENSSL_NO_DES +const EVP_CIPHER *EVP_des_ecb(void); +const EVP_CIPHER *EVP_des_ede(void); +const EVP_CIPHER *EVP_des_ede3(void); +const EVP_CIPHER *EVP_des_ede_ecb(void); +const EVP_CIPHER *EVP_des_ede3_ecb(void); +const EVP_CIPHER *EVP_des_cfb64(void); +# define EVP_des_cfb EVP_des_cfb64 +const EVP_CIPHER *EVP_des_cfb1(void); +const EVP_CIPHER *EVP_des_cfb8(void); +const EVP_CIPHER *EVP_des_ede_cfb64(void); +# define EVP_des_ede_cfb EVP_des_ede_cfb64 +#if 0 +const EVP_CIPHER *EVP_des_ede_cfb1(void); +const EVP_CIPHER *EVP_des_ede_cfb8(void); +#endif +const EVP_CIPHER *EVP_des_ede3_cfb64(void); +# define EVP_des_ede3_cfb EVP_des_ede3_cfb64 +const EVP_CIPHER *EVP_des_ede3_cfb1(void); +const EVP_CIPHER *EVP_des_ede3_cfb8(void); +const EVP_CIPHER *EVP_des_ofb(void); +const EVP_CIPHER *EVP_des_ede_ofb(void); +const EVP_CIPHER *EVP_des_ede3_ofb(void); +const EVP_CIPHER *EVP_des_cbc(void); +const EVP_CIPHER *EVP_des_ede_cbc(void); +const EVP_CIPHER *EVP_des_ede3_cbc(void); +const EVP_CIPHER *EVP_desx_cbc(void); +/* This should now be supported through the dev_crypto ENGINE. But also, why are + * rc4 and md5 declarations made here inside a "NO_DES" precompiler branch? */ +#if 0 +# ifdef OPENSSL_OPENBSD_DEV_CRYPTO +const EVP_CIPHER *EVP_dev_crypto_des_ede3_cbc(void); +const EVP_CIPHER *EVP_dev_crypto_rc4(void); +const EVP_MD *EVP_dev_crypto_md5(void); +# endif +#endif +#endif +#ifndef OPENSSL_NO_RC4 +const EVP_CIPHER *EVP_rc4(void); +const EVP_CIPHER *EVP_rc4_40(void); +#endif +#ifndef OPENSSL_NO_IDEA +const EVP_CIPHER *EVP_idea_ecb(void); +const EVP_CIPHER *EVP_idea_cfb64(void); +# define EVP_idea_cfb EVP_idea_cfb64 +const EVP_CIPHER *EVP_idea_ofb(void); +const EVP_CIPHER *EVP_idea_cbc(void); +#endif +#ifndef OPENSSL_NO_RC2 +const EVP_CIPHER *EVP_rc2_ecb(void); +const EVP_CIPHER *EVP_rc2_cbc(void); +const EVP_CIPHER *EVP_rc2_40_cbc(void); +const EVP_CIPHER *EVP_rc2_64_cbc(void); +const EVP_CIPHER *EVP_rc2_cfb64(void); +# define EVP_rc2_cfb EVP_rc2_cfb64 +const EVP_CIPHER *EVP_rc2_ofb(void); +#endif +#ifndef OPENSSL_NO_BF +const EVP_CIPHER *EVP_bf_ecb(void); +const EVP_CIPHER *EVP_bf_cbc(void); +const EVP_CIPHER *EVP_bf_cfb64(void); +# define EVP_bf_cfb EVP_bf_cfb64 +const EVP_CIPHER *EVP_bf_ofb(void); +#endif +#ifndef OPENSSL_NO_CAST +const EVP_CIPHER *EVP_cast5_ecb(void); +const EVP_CIPHER *EVP_cast5_cbc(void); +const EVP_CIPHER *EVP_cast5_cfb64(void); +# define EVP_cast5_cfb EVP_cast5_cfb64 +const EVP_CIPHER *EVP_cast5_ofb(void); +#endif +#ifndef OPENSSL_NO_RC5 +const EVP_CIPHER *EVP_rc5_32_12_16_cbc(void); +const EVP_CIPHER *EVP_rc5_32_12_16_ecb(void); +const EVP_CIPHER *EVP_rc5_32_12_16_cfb64(void); +# define EVP_rc5_32_12_16_cfb EVP_rc5_32_12_16_cfb64 +const EVP_CIPHER *EVP_rc5_32_12_16_ofb(void); +#endif +#ifndef OPENSSL_NO_AES +const EVP_CIPHER *EVP_aes_128_ecb(void); +const EVP_CIPHER *EVP_aes_128_cbc(void); +const EVP_CIPHER *EVP_aes_128_cfb1(void); +const EVP_CIPHER *EVP_aes_128_cfb8(void); +const EVP_CIPHER *EVP_aes_128_cfb128(void); +# define EVP_aes_128_cfb EVP_aes_128_cfb128 +const EVP_CIPHER *EVP_aes_128_ofb(void); +#if 0 +const EVP_CIPHER *EVP_aes_128_ctr(void); +#endif +const EVP_CIPHER *EVP_aes_192_ecb(void); +const EVP_CIPHER *EVP_aes_192_cbc(void); +const EVP_CIPHER *EVP_aes_192_cfb1(void); +const EVP_CIPHER *EVP_aes_192_cfb8(void); +const EVP_CIPHER *EVP_aes_192_cfb128(void); +# define EVP_aes_192_cfb EVP_aes_192_cfb128 +const EVP_CIPHER *EVP_aes_192_ofb(void); +#if 0 +const EVP_CIPHER *EVP_aes_192_ctr(void); +#endif +const EVP_CIPHER *EVP_aes_256_ecb(void); +const EVP_CIPHER *EVP_aes_256_cbc(void); +const EVP_CIPHER *EVP_aes_256_cfb1(void); +const EVP_CIPHER *EVP_aes_256_cfb8(void); +const EVP_CIPHER *EVP_aes_256_cfb128(void); +# define EVP_aes_256_cfb EVP_aes_256_cfb128 +const EVP_CIPHER *EVP_aes_256_ofb(void); +#if 0 +const EVP_CIPHER *EVP_aes_256_ctr(void); +#endif +#endif +#ifndef OPENSSL_NO_CAMELLIA +const EVP_CIPHER *EVP_camellia_128_ecb(void); +const EVP_CIPHER *EVP_camellia_128_cbc(void); +const EVP_CIPHER *EVP_camellia_128_cfb1(void); +const EVP_CIPHER *EVP_camellia_128_cfb8(void); +const EVP_CIPHER *EVP_camellia_128_cfb128(void); +# define EVP_camellia_128_cfb EVP_camellia_128_cfb128 +const EVP_CIPHER *EVP_camellia_128_ofb(void); +const EVP_CIPHER *EVP_camellia_192_ecb(void); +const EVP_CIPHER *EVP_camellia_192_cbc(void); +const EVP_CIPHER *EVP_camellia_192_cfb1(void); +const EVP_CIPHER *EVP_camellia_192_cfb8(void); +const EVP_CIPHER *EVP_camellia_192_cfb128(void); +# define EVP_camellia_192_cfb EVP_camellia_192_cfb128 +const EVP_CIPHER *EVP_camellia_192_ofb(void); +const EVP_CIPHER *EVP_camellia_256_ecb(void); +const EVP_CIPHER *EVP_camellia_256_cbc(void); +const EVP_CIPHER *EVP_camellia_256_cfb1(void); +const EVP_CIPHER *EVP_camellia_256_cfb8(void); +const EVP_CIPHER *EVP_camellia_256_cfb128(void); +# define EVP_camellia_256_cfb EVP_camellia_256_cfb128 +const EVP_CIPHER *EVP_camellia_256_ofb(void); +#endif + +#ifndef OPENSSL_NO_SEED +const EVP_CIPHER *EVP_seed_ecb(void); +const EVP_CIPHER *EVP_seed_cbc(void); +const EVP_CIPHER *EVP_seed_cfb128(void); +# define EVP_seed_cfb EVP_seed_cfb128 +const EVP_CIPHER *EVP_seed_ofb(void); +#endif + +void OPENSSL_add_all_algorithms_noconf(void); +void OPENSSL_add_all_algorithms_conf(void); + +#ifdef OPENSSL_LOAD_CONF +#define OpenSSL_add_all_algorithms() \ + OPENSSL_add_all_algorithms_conf() +#else +#define OpenSSL_add_all_algorithms() \ + OPENSSL_add_all_algorithms_noconf() +#endif + +void OpenSSL_add_all_ciphers(void); +void OpenSSL_add_all_digests(void); +#define SSLeay_add_all_algorithms() OpenSSL_add_all_algorithms() +#define SSLeay_add_all_ciphers() OpenSSL_add_all_ciphers() +#define SSLeay_add_all_digests() OpenSSL_add_all_digests() + +int EVP_add_cipher(const EVP_CIPHER *cipher); +int EVP_add_digest(const EVP_MD *digest); + +const EVP_CIPHER *EVP_get_cipherbyname(const char *name); +const EVP_MD *EVP_get_digestbyname(const char *name); +void EVP_cleanup(void); + +int EVP_PKEY_decrypt(unsigned char *dec_key, + const unsigned char *enc_key,int enc_key_len, + EVP_PKEY *private_key); +int EVP_PKEY_encrypt(unsigned char *enc_key, + const unsigned char *key,int key_len, + EVP_PKEY *pub_key); +int EVP_PKEY_type(int type); +int EVP_PKEY_bits(EVP_PKEY *pkey); +int EVP_PKEY_size(EVP_PKEY *pkey); +int EVP_PKEY_assign(EVP_PKEY *pkey,int type,char *key); + +#ifndef OPENSSL_NO_RSA +struct rsa_st; +int EVP_PKEY_set1_RSA(EVP_PKEY *pkey,struct rsa_st *key); +struct rsa_st *EVP_PKEY_get1_RSA(EVP_PKEY *pkey); +#endif +#ifndef OPENSSL_NO_DSA +struct dsa_st; +int EVP_PKEY_set1_DSA(EVP_PKEY *pkey,struct dsa_st *key); +struct dsa_st *EVP_PKEY_get1_DSA(EVP_PKEY *pkey); +#endif +#ifndef OPENSSL_NO_DH +struct dh_st; +int EVP_PKEY_set1_DH(EVP_PKEY *pkey,struct dh_st *key); +struct dh_st *EVP_PKEY_get1_DH(EVP_PKEY *pkey); +#endif +#ifndef OPENSSL_NO_EC +struct ec_key_st; +int EVP_PKEY_set1_EC_KEY(EVP_PKEY *pkey,struct ec_key_st *key); +struct ec_key_st *EVP_PKEY_get1_EC_KEY(EVP_PKEY *pkey); +#endif + +EVP_PKEY * EVP_PKEY_new(void); +void EVP_PKEY_free(EVP_PKEY *pkey); + +EVP_PKEY * d2i_PublicKey(int type,EVP_PKEY **a, const unsigned char **pp, + long length); +int i2d_PublicKey(EVP_PKEY *a, unsigned char **pp); + +EVP_PKEY * d2i_PrivateKey(int type,EVP_PKEY **a, const unsigned char **pp, + long length); +EVP_PKEY * d2i_AutoPrivateKey(EVP_PKEY **a, const unsigned char **pp, + long length); +int i2d_PrivateKey(EVP_PKEY *a, unsigned char **pp); + +int EVP_PKEY_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from); +int EVP_PKEY_missing_parameters(const EVP_PKEY *pkey); +int EVP_PKEY_save_parameters(EVP_PKEY *pkey,int mode); +int EVP_PKEY_cmp_parameters(const EVP_PKEY *a, const EVP_PKEY *b); + +int EVP_PKEY_cmp(const EVP_PKEY *a, const EVP_PKEY *b); + +int EVP_CIPHER_type(const EVP_CIPHER *ctx); + +/* calls methods */ +int EVP_CIPHER_param_to_asn1(EVP_CIPHER_CTX *c, ASN1_TYPE *type); +int EVP_CIPHER_asn1_to_param(EVP_CIPHER_CTX *c, ASN1_TYPE *type); + +/* These are used by EVP_CIPHER methods */ +int EVP_CIPHER_set_asn1_iv(EVP_CIPHER_CTX *c,ASN1_TYPE *type); +int EVP_CIPHER_get_asn1_iv(EVP_CIPHER_CTX *c,ASN1_TYPE *type); + +/* PKCS5 password based encryption */ +int PKCS5_PBE_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass, int passlen, + ASN1_TYPE *param, const EVP_CIPHER *cipher, const EVP_MD *md, + int en_de); +int PKCS5_PBKDF2_HMAC_SHA1(const char *pass, int passlen, + const unsigned char *salt, int saltlen, int iter, + int keylen, unsigned char *out); +int PKCS5_v2_PBE_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass, int passlen, + ASN1_TYPE *param, const EVP_CIPHER *cipher, const EVP_MD *md, + int en_de); + +void PKCS5_PBE_add(void); + +int EVP_PBE_CipherInit (ASN1_OBJECT *pbe_obj, const char *pass, int passlen, + ASN1_TYPE *param, EVP_CIPHER_CTX *ctx, int en_de); +int EVP_PBE_alg_add(int nid, const EVP_CIPHER *cipher, const EVP_MD *md, + EVP_PBE_KEYGEN *keygen); +void EVP_PBE_cleanup(void); + +/* BEGIN ERROR CODES */ +/* The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ +void ERR_load_EVP_strings(void); + +/* Error codes for the EVP functions. */ + +/* Function codes. */ +#define EVP_F_AES_INIT_KEY 133 +#define EVP_F_CAMELLIA_INIT_KEY 159 +#define EVP_F_D2I_PKEY 100 +#define EVP_F_DSAPKEY2PKCS8 134 +#define EVP_F_DSA_PKEY2PKCS8 135 +#define EVP_F_ECDSA_PKEY2PKCS8 129 +#define EVP_F_ECKEY_PKEY2PKCS8 132 +#define EVP_F_EVP_CIPHERINIT_EX 123 +#define EVP_F_EVP_CIPHER_CTX_CTRL 124 +#define EVP_F_EVP_CIPHER_CTX_SET_KEY_LENGTH 122 +#define EVP_F_EVP_DECRYPTFINAL_EX 101 +#define EVP_F_EVP_DIGESTINIT_EX 128 +#define EVP_F_EVP_ENCRYPTFINAL_EX 127 +#define EVP_F_EVP_MD_CTX_COPY_EX 110 +#define EVP_F_EVP_OPENINIT 102 +#define EVP_F_EVP_PBE_ALG_ADD 115 +#define EVP_F_EVP_PBE_CIPHERINIT 116 +#define EVP_F_EVP_PKCS82PKEY 111 +#define EVP_F_EVP_PKEY2PKCS8_BROKEN 113 +#define EVP_F_EVP_PKEY_COPY_PARAMETERS 103 +#define EVP_F_EVP_PKEY_DECRYPT 104 +#define EVP_F_EVP_PKEY_ENCRYPT 105 +#define EVP_F_EVP_PKEY_GET1_DH 119 +#define EVP_F_EVP_PKEY_GET1_DSA 120 +#define EVP_F_EVP_PKEY_GET1_ECDSA 130 +#define EVP_F_EVP_PKEY_GET1_EC_KEY 131 +#define EVP_F_EVP_PKEY_GET1_RSA 121 +#define EVP_F_EVP_PKEY_NEW 106 +#define EVP_F_EVP_RIJNDAEL 126 +#define EVP_F_EVP_SIGNFINAL 107 +#define EVP_F_EVP_VERIFYFINAL 108 +#define EVP_F_PKCS5_PBE_KEYIVGEN 117 +#define EVP_F_PKCS5_V2_PBE_KEYIVGEN 118 +#define EVP_F_PKCS8_SET_BROKEN 112 +#define EVP_F_RC2_MAGIC_TO_METH 109 +#define EVP_F_RC5_CTRL 125 + +/* Reason codes. */ +#define EVP_R_AES_KEY_SETUP_FAILED 143 +#define EVP_R_ASN1_LIB 140 +#define EVP_R_BAD_BLOCK_LENGTH 136 +#define EVP_R_BAD_DECRYPT 100 +#define EVP_R_BAD_KEY_LENGTH 137 +#define EVP_R_BN_DECODE_ERROR 112 +#define EVP_R_BN_PUBKEY_ERROR 113 +#define EVP_R_CAMELLIA_KEY_SETUP_FAILED 157 +#define EVP_R_CIPHER_PARAMETER_ERROR 122 +#define EVP_R_CTRL_NOT_IMPLEMENTED 132 +#define EVP_R_CTRL_OPERATION_NOT_IMPLEMENTED 133 +#define EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH 138 +#define EVP_R_DECODE_ERROR 114 +#define EVP_R_DIFFERENT_KEY_TYPES 101 +#define EVP_R_ENCODE_ERROR 115 +#define EVP_R_EVP_PBE_CIPHERINIT_ERROR 119 +#define EVP_R_EXPECTING_AN_RSA_KEY 127 +#define EVP_R_EXPECTING_A_DH_KEY 128 +#define EVP_R_EXPECTING_A_DSA_KEY 129 +#define EVP_R_EXPECTING_A_ECDSA_KEY 141 +#define EVP_R_EXPECTING_A_EC_KEY 142 +#define EVP_R_INITIALIZATION_ERROR 134 +#define EVP_R_INPUT_NOT_INITIALIZED 111 +#define EVP_R_INVALID_KEY_LENGTH 130 +#define EVP_R_IV_TOO_LARGE 102 +#define EVP_R_KEYGEN_FAILURE 120 +#define EVP_R_MISSING_PARAMETERS 103 +#define EVP_R_NO_CIPHER_SET 131 +#define EVP_R_NO_DIGEST_SET 139 +#define EVP_R_NO_DSA_PARAMETERS 116 +#define EVP_R_NO_SIGN_FUNCTION_CONFIGURED 104 +#define EVP_R_NO_VERIFY_FUNCTION_CONFIGURED 105 +#define EVP_R_PKCS8_UNKNOWN_BROKEN_TYPE 117 +#define EVP_R_PUBLIC_KEY_NOT_RSA 106 +#define EVP_R_UNKNOWN_PBE_ALGORITHM 121 +#define EVP_R_UNSUPORTED_NUMBER_OF_ROUNDS 135 +#define EVP_R_UNSUPPORTED_CIPHER 107 +#define EVP_R_UNSUPPORTED_KEYLENGTH 123 +#define EVP_R_UNSUPPORTED_KEY_DERIVATION_FUNCTION 124 +#define EVP_R_UNSUPPORTED_KEY_SIZE 108 +#define EVP_R_UNSUPPORTED_PRF 125 +#define EVP_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM 118 +#define EVP_R_UNSUPPORTED_SALT_TYPE 126 +#define EVP_R_WRONG_FINAL_BLOCK_LENGTH 109 +#define EVP_R_WRONG_PUBLIC_KEY_TYPE 110 +#define EVP_R_SEED_KEY_SETUP_FAILED 162 + +#ifdef __cplusplus +} +#endif +#endif diff --git a/lib_tls/include/openssl/hmac.h b/lib_tls/include/openssl/hmac.h new file mode 100644 index 000000000..719fc408a --- /dev/null +++ b/lib_tls/include/openssl/hmac.h @@ -0,0 +1,108 @@ +/* crypto/hmac/hmac.h */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +#ifndef HEADER_HMAC_H +#define HEADER_HMAC_H + +#include + +#ifdef OPENSSL_NO_HMAC +#error HMAC is disabled. +#endif + +#include + +#define HMAC_MAX_MD_CBLOCK 128 /* largest known is SHA512 */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct hmac_ctx_st + { + const EVP_MD *md; + EVP_MD_CTX md_ctx; + EVP_MD_CTX i_ctx; + EVP_MD_CTX o_ctx; + unsigned int key_length; + unsigned char key[HMAC_MAX_MD_CBLOCK]; + } HMAC_CTX; + +#define HMAC_size(e) (EVP_MD_size((e)->md)) + + +void HMAC_CTX_init(HMAC_CTX *ctx); +void HMAC_CTX_cleanup(HMAC_CTX *ctx); + +#define HMAC_cleanup(ctx) HMAC_CTX_cleanup(ctx) /* deprecated */ + +void HMAC_Init(HMAC_CTX *ctx, const void *key, int len, + const EVP_MD *md); /* deprecated */ +void HMAC_Init_ex(HMAC_CTX *ctx, const void *key, int len, + const EVP_MD *md, ENGINE *impl); +void HMAC_Update(HMAC_CTX *ctx, const unsigned char *data, size_t len); +void HMAC_Final(HMAC_CTX *ctx, unsigned char *md, unsigned int *len); +unsigned char *HMAC(const EVP_MD *evp_md, const void *key, int key_len, + const unsigned char *d, size_t n, unsigned char *md, + unsigned int *md_len); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_tls/include/openssl/idea.h b/lib_tls/include/openssl/idea.h new file mode 100644 index 000000000..bf97a37e3 --- /dev/null +++ b/lib_tls/include/openssl/idea.h @@ -0,0 +1,100 @@ +/* crypto/idea/idea.h */ +/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#ifndef HEADER_IDEA_H +#define HEADER_IDEA_H + +#include /* IDEA_INT, OPENSSL_NO_IDEA */ + +#ifdef OPENSSL_NO_IDEA +#error IDEA is disabled. +#endif + +#define IDEA_ENCRYPT 1 +#define IDEA_DECRYPT 0 + +#define IDEA_BLOCK 8 +#define IDEA_KEY_LENGTH 16 + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct idea_key_st + { + IDEA_INT data[9][6]; + } IDEA_KEY_SCHEDULE; + +const char *idea_options(void); +void idea_ecb_encrypt(const unsigned char *in, unsigned char *out, + IDEA_KEY_SCHEDULE *ks); +void idea_set_encrypt_key(const unsigned char *key, IDEA_KEY_SCHEDULE *ks); +void idea_set_decrypt_key(const IDEA_KEY_SCHEDULE *ek, IDEA_KEY_SCHEDULE *dk); +void idea_cbc_encrypt(const unsigned char *in, unsigned char *out, + long length, IDEA_KEY_SCHEDULE *ks, unsigned char *iv,int enc); +void idea_cfb64_encrypt(const unsigned char *in, unsigned char *out, + long length, IDEA_KEY_SCHEDULE *ks, unsigned char *iv, + int *num,int enc); +void idea_ofb64_encrypt(const unsigned char *in, unsigned char *out, + long length, IDEA_KEY_SCHEDULE *ks, unsigned char *iv, int *num); +void idea_encrypt(unsigned long *in, IDEA_KEY_SCHEDULE *ks); +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_tls/include/openssl/krb5_asn.h b/lib_tls/include/openssl/krb5_asn.h new file mode 100644 index 000000000..41725d0dc --- /dev/null +++ b/lib_tls/include/openssl/krb5_asn.h @@ -0,0 +1,256 @@ +/* krb5_asn.h */ +/* Written by Vern Staats for the OpenSSL project, +** using ocsp/{*.h,*asn*.c} as a starting point +*/ + +/* ==================================================================== + * Copyright (c) 1998-2000 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#ifndef HEADER_KRB5_ASN_H +#define HEADER_KRB5_ASN_H + +/* +#include +*/ +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +/* ASN.1 from Kerberos RFC 1510 +*/ + +/* EncryptedData ::= SEQUENCE { +** etype[0] INTEGER, -- EncryptionType +** kvno[1] INTEGER OPTIONAL, +** cipher[2] OCTET STRING -- ciphertext +** } +*/ +typedef struct krb5_encdata_st + { + ASN1_INTEGER *etype; + ASN1_INTEGER *kvno; + ASN1_OCTET_STRING *cipher; + } KRB5_ENCDATA; + +DECLARE_STACK_OF(KRB5_ENCDATA) + +/* PrincipalName ::= SEQUENCE { +** name-type[0] INTEGER, +** name-string[1] SEQUENCE OF GeneralString +** } +*/ +typedef struct krb5_princname_st + { + ASN1_INTEGER *nametype; + STACK_OF(ASN1_GENERALSTRING) *namestring; + } KRB5_PRINCNAME; + +DECLARE_STACK_OF(KRB5_PRINCNAME) + + +/* Ticket ::= [APPLICATION 1] SEQUENCE { +** tkt-vno[0] INTEGER, +** realm[1] Realm, +** sname[2] PrincipalName, +** enc-part[3] EncryptedData +** } +*/ +typedef struct krb5_tktbody_st + { + ASN1_INTEGER *tktvno; + ASN1_GENERALSTRING *realm; + KRB5_PRINCNAME *sname; + KRB5_ENCDATA *encdata; + } KRB5_TKTBODY; + +typedef STACK_OF(KRB5_TKTBODY) KRB5_TICKET; +DECLARE_STACK_OF(KRB5_TKTBODY) + + +/* AP-REQ ::= [APPLICATION 14] SEQUENCE { +** pvno[0] INTEGER, +** msg-type[1] INTEGER, +** ap-options[2] APOptions, +** ticket[3] Ticket, +** authenticator[4] EncryptedData +** } +** +** APOptions ::= BIT STRING { +** reserved(0), use-session-key(1), mutual-required(2) } +*/ +typedef struct krb5_ap_req_st + { + ASN1_INTEGER *pvno; + ASN1_INTEGER *msgtype; + ASN1_BIT_STRING *apoptions; + KRB5_TICKET *ticket; + KRB5_ENCDATA *authenticator; + } KRB5_APREQBODY; + +typedef STACK_OF(KRB5_APREQBODY) KRB5_APREQ; +DECLARE_STACK_OF(KRB5_APREQBODY) + + +/* Authenticator Stuff */ + + +/* Checksum ::= SEQUENCE { +** cksumtype[0] INTEGER, +** checksum[1] OCTET STRING +** } +*/ +typedef struct krb5_checksum_st + { + ASN1_INTEGER *ctype; + ASN1_OCTET_STRING *checksum; + } KRB5_CHECKSUM; + +DECLARE_STACK_OF(KRB5_CHECKSUM) + + +/* EncryptionKey ::= SEQUENCE { +** keytype[0] INTEGER, +** keyvalue[1] OCTET STRING +** } +*/ +typedef struct krb5_encryptionkey_st + { + ASN1_INTEGER *ktype; + ASN1_OCTET_STRING *keyvalue; + } KRB5_ENCKEY; + +DECLARE_STACK_OF(KRB5_ENCKEY) + + +/* AuthorizationData ::= SEQUENCE OF SEQUENCE { +** ad-type[0] INTEGER, +** ad-data[1] OCTET STRING +** } +*/ +typedef struct krb5_authorization_st + { + ASN1_INTEGER *adtype; + ASN1_OCTET_STRING *addata; + } KRB5_AUTHDATA; + +DECLARE_STACK_OF(KRB5_AUTHDATA) + + +/* -- Unencrypted authenticator +** Authenticator ::= [APPLICATION 2] SEQUENCE { +** authenticator-vno[0] INTEGER, +** crealm[1] Realm, +** cname[2] PrincipalName, +** cksum[3] Checksum OPTIONAL, +** cusec[4] INTEGER, +** ctime[5] KerberosTime, +** subkey[6] EncryptionKey OPTIONAL, +** seq-number[7] INTEGER OPTIONAL, +** authorization-data[8] AuthorizationData OPTIONAL +** } +*/ +typedef struct krb5_authenticator_st + { + ASN1_INTEGER *avno; + ASN1_GENERALSTRING *crealm; + KRB5_PRINCNAME *cname; + KRB5_CHECKSUM *cksum; + ASN1_INTEGER *cusec; + ASN1_GENERALIZEDTIME *ctime; + KRB5_ENCKEY *subkey; + ASN1_INTEGER *seqnum; + KRB5_AUTHDATA *authorization; + } KRB5_AUTHENTBODY; + +typedef STACK_OF(KRB5_AUTHENTBODY) KRB5_AUTHENT; +DECLARE_STACK_OF(KRB5_AUTHENTBODY) + + +/* DECLARE_ASN1_FUNCTIONS(type) = DECLARE_ASN1_FUNCTIONS_name(type, type) = +** type *name##_new(void); +** void name##_free(type *a); +** DECLARE_ASN1_ENCODE_FUNCTIONS(type, name, name) = +** DECLARE_ASN1_ENCODE_FUNCTIONS(type, itname, name) = +** type *d2i_##name(type **a, const unsigned char **in, long len); +** int i2d_##name(type *a, unsigned char **out); +** DECLARE_ASN1_ITEM(itname) = OPENSSL_EXTERN const ASN1_ITEM itname##_it +*/ + +DECLARE_ASN1_FUNCTIONS(KRB5_ENCDATA) +DECLARE_ASN1_FUNCTIONS(KRB5_PRINCNAME) +DECLARE_ASN1_FUNCTIONS(KRB5_TKTBODY) +DECLARE_ASN1_FUNCTIONS(KRB5_APREQBODY) +DECLARE_ASN1_FUNCTIONS(KRB5_TICKET) +DECLARE_ASN1_FUNCTIONS(KRB5_APREQ) + +DECLARE_ASN1_FUNCTIONS(KRB5_CHECKSUM) +DECLARE_ASN1_FUNCTIONS(KRB5_ENCKEY) +DECLARE_ASN1_FUNCTIONS(KRB5_AUTHDATA) +DECLARE_ASN1_FUNCTIONS(KRB5_AUTHENTBODY) +DECLARE_ASN1_FUNCTIONS(KRB5_AUTHENT) + + +/* BEGIN ERROR CODES */ +/* The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/lib_tls/include/openssl/kssl.h b/lib_tls/include/openssl/kssl.h new file mode 100644 index 000000000..a3d20e1cc --- /dev/null +++ b/lib_tls/include/openssl/kssl.h @@ -0,0 +1,179 @@ +/* ssl/kssl.h -*- mode: C; c-file-style: "eay" -*- */ +/* Written by Vern Staats for the OpenSSL project 2000. + * project 2000. + */ +/* ==================================================================== + * Copyright (c) 2000 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +/* +** 19990701 VRS Started. +*/ + +#ifndef KSSL_H +#define KSSL_H + +#include + +#ifndef OPENSSL_NO_KRB5 + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** Depending on which KRB5 implementation used, some types from +** the other may be missing. Resolve that here and now +*/ +#ifdef KRB5_HEIMDAL +typedef unsigned char krb5_octet; +#define FAR +#else + +#ifndef FAR +#define FAR +#endif + +#endif + +/* Uncomment this to debug kssl problems or +** to trace usage of the Kerberos session key +** +** #define KSSL_DEBUG +*/ + +#ifndef KRB5SVC +#define KRB5SVC "host" +#endif + +#ifndef KRB5KEYTAB +#define KRB5KEYTAB "/etc/krb5.keytab" +#endif + +#ifndef KRB5SENDAUTH +#define KRB5SENDAUTH 1 +#endif + +#ifndef KRB5CHECKAUTH +#define KRB5CHECKAUTH 1 +#endif + +#ifndef KSSL_CLOCKSKEW +#define KSSL_CLOCKSKEW 300; +#endif + +#define KSSL_ERR_MAX 255 +typedef struct kssl_err_st { + int reason; + char text[KSSL_ERR_MAX+1]; + } KSSL_ERR; + + +/* Context for passing +** (1) Kerberos session key to SSL, and +** (2) Config data between application and SSL lib +*/ +typedef struct kssl_ctx_st + { + /* used by: disposition: */ + char *service_name; /* C,S default ok (kssl) */ + char *service_host; /* C input, REQUIRED */ + char *client_princ; /* S output from krb5 ticket */ + char *keytab_file; /* S NULL (/etc/krb5.keytab) */ + char *cred_cache; /* C NULL (default) */ + krb5_enctype enctype; + int length; + krb5_octet FAR *key; + } KSSL_CTX; + +#define KSSL_CLIENT 1 +#define KSSL_SERVER 2 +#define KSSL_SERVICE 3 +#define KSSL_KEYTAB 4 + +#define KSSL_CTX_OK 0 +#define KSSL_CTX_ERR 1 +#define KSSL_NOMEM 2 + +/* Public (for use by applications that use OpenSSL with Kerberos 5 support */ +krb5_error_code kssl_ctx_setstring(KSSL_CTX *kssl_ctx, int which, char *text); +KSSL_CTX *kssl_ctx_new(void); +KSSL_CTX *kssl_ctx_free(KSSL_CTX *kssl_ctx); +void kssl_ctx_show(KSSL_CTX *kssl_ctx); +krb5_error_code kssl_ctx_setprinc(KSSL_CTX *kssl_ctx, int which, + krb5_data *realm, krb5_data *entity, int nentities); +krb5_error_code kssl_cget_tkt(KSSL_CTX *kssl_ctx, krb5_data **enc_tktp, + krb5_data *authenp, KSSL_ERR *kssl_err); +krb5_error_code kssl_sget_tkt(KSSL_CTX *kssl_ctx, krb5_data *indata, + krb5_ticket_times *ttimes, KSSL_ERR *kssl_err); +krb5_error_code kssl_ctx_setkey(KSSL_CTX *kssl_ctx, krb5_keyblock *session); +void kssl_err_set(KSSL_ERR *kssl_err, int reason, char *text); +void kssl_krb5_free_data_contents(krb5_context context, krb5_data *data); +krb5_error_code kssl_build_principal_2(krb5_context context, + krb5_principal *princ, int rlen, const char *realm, + int slen, const char *svc, int hlen, const char *host); +krb5_error_code kssl_validate_times(krb5_timestamp atime, + krb5_ticket_times *ttimes); +krb5_error_code kssl_check_authent(KSSL_CTX *kssl_ctx, krb5_data *authentp, + krb5_timestamp *atimep, KSSL_ERR *kssl_err); +unsigned char *kssl_skip_confound(krb5_enctype enctype, unsigned char *authn); + +#ifdef __cplusplus +} +#endif +#endif /* OPENSSL_NO_KRB5 */ +#endif /* KSSL_H */ diff --git a/lib_tls/include/openssl/lhash.h b/lib_tls/include/openssl/lhash.h new file mode 100644 index 000000000..d392d0cd8 --- /dev/null +++ b/lib_tls/include/openssl/lhash.h @@ -0,0 +1,200 @@ +/* crypto/lhash/lhash.h */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +/* Header for dynamic hash table routines + * Author - Eric Young + */ + +#ifndef HEADER_LHASH_H +#define HEADER_LHASH_H + +#include +#ifndef OPENSSL_NO_FP_API +#include +#endif + +#ifndef OPENSSL_NO_BIO +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct lhash_node_st + { + void *data; + struct lhash_node_st *next; +#ifndef OPENSSL_NO_HASH_COMP + unsigned long hash; +#endif + } LHASH_NODE; + +typedef int (*LHASH_COMP_FN_TYPE)(const void *, const void *); +typedef unsigned long (*LHASH_HASH_FN_TYPE)(const void *); +typedef void (*LHASH_DOALL_FN_TYPE)(void *); +typedef void (*LHASH_DOALL_ARG_FN_TYPE)(void *, void *); + +/* Macros for declaring and implementing type-safe wrappers for LHASH callbacks. + * This way, callbacks can be provided to LHASH structures without function + * pointer casting and the macro-defined callbacks provide per-variable casting + * before deferring to the underlying type-specific callbacks. NB: It is + * possible to place a "static" in front of both the DECLARE and IMPLEMENT + * macros if the functions are strictly internal. */ + +/* First: "hash" functions */ +#define DECLARE_LHASH_HASH_FN(f_name,o_type) \ + unsigned long f_name##_LHASH_HASH(const void *); +#define IMPLEMENT_LHASH_HASH_FN(f_name,o_type) \ + unsigned long f_name##_LHASH_HASH(const void *arg) { \ + o_type a = (o_type)arg; \ + return f_name(a); } +#define LHASH_HASH_FN(f_name) f_name##_LHASH_HASH + +/* Second: "compare" functions */ +#define DECLARE_LHASH_COMP_FN(f_name,o_type) \ + int f_name##_LHASH_COMP(const void *, const void *); +#define IMPLEMENT_LHASH_COMP_FN(f_name,o_type) \ + int f_name##_LHASH_COMP(const void *arg1, const void *arg2) { \ + o_type a = (o_type)arg1; \ + o_type b = (o_type)arg2; \ + return f_name(a,b); } +#define LHASH_COMP_FN(f_name) f_name##_LHASH_COMP + +/* Third: "doall" functions */ +#define DECLARE_LHASH_DOALL_FN(f_name,o_type) \ + void f_name##_LHASH_DOALL(void *); +#define IMPLEMENT_LHASH_DOALL_FN(f_name,o_type) \ + void f_name##_LHASH_DOALL(void *arg) { \ + o_type a = (o_type)arg; \ + f_name(a); } +#define LHASH_DOALL_FN(f_name) f_name##_LHASH_DOALL + +/* Fourth: "doall_arg" functions */ +#define DECLARE_LHASH_DOALL_ARG_FN(f_name,o_type,a_type) \ + void f_name##_LHASH_DOALL_ARG(void *, void *); +#define IMPLEMENT_LHASH_DOALL_ARG_FN(f_name,o_type,a_type) \ + void f_name##_LHASH_DOALL_ARG(void *arg1, void *arg2) { \ + o_type a = (o_type)arg1; \ + a_type b = (a_type)arg2; \ + f_name(a,b); } +#define LHASH_DOALL_ARG_FN(f_name) f_name##_LHASH_DOALL_ARG + +typedef struct lhash_st + { + LHASH_NODE **b; + LHASH_COMP_FN_TYPE comp; + LHASH_HASH_FN_TYPE hash; + unsigned int num_nodes; + unsigned int num_alloc_nodes; + unsigned int p; + unsigned int pmax; + unsigned long up_load; /* load times 256 */ + unsigned long down_load; /* load times 256 */ + unsigned long num_items; + + unsigned long num_expands; + unsigned long num_expand_reallocs; + unsigned long num_contracts; + unsigned long num_contract_reallocs; + unsigned long num_hash_calls; + unsigned long num_comp_calls; + unsigned long num_insert; + unsigned long num_replace; + unsigned long num_delete; + unsigned long num_no_delete; + unsigned long num_retrieve; + unsigned long num_retrieve_miss; + unsigned long num_hash_comps; + + int error; + } LHASH; + +#define LH_LOAD_MULT 256 + +/* Indicates a malloc() error in the last call, this is only bad + * in lh_insert(). */ +#define lh_error(lh) ((lh)->error) + +LHASH *lh_new(LHASH_HASH_FN_TYPE h, LHASH_COMP_FN_TYPE c); +void lh_free(LHASH *lh); +void *lh_insert(LHASH *lh, void *data); +void *lh_delete(LHASH *lh, const void *data); +void *lh_retrieve(LHASH *lh, const void *data); +void lh_doall(LHASH *lh, LHASH_DOALL_FN_TYPE func); +void lh_doall_arg(LHASH *lh, LHASH_DOALL_ARG_FN_TYPE func, void *arg); +unsigned long lh_strhash(const char *c); +unsigned long lh_num_items(const LHASH *lh); + +#ifndef OPENSSL_NO_FP_API +void lh_stats(const LHASH *lh, FILE *out); +void lh_node_stats(const LHASH *lh, FILE *out); +void lh_node_usage_stats(const LHASH *lh, FILE *out); +#endif + +#ifndef OPENSSL_NO_BIO +void lh_stats_bio(const LHASH *lh, BIO *out); +void lh_node_stats_bio(const LHASH *lh, BIO *out); +void lh_node_usage_stats_bio(const LHASH *lh, BIO *out); +#endif +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_tls/include/openssl/md2.h b/lib_tls/include/openssl/md2.h new file mode 100644 index 000000000..a46120e7d --- /dev/null +++ b/lib_tls/include/openssl/md2.h @@ -0,0 +1,92 @@ +/* crypto/md/md2.h */ +/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#ifndef HEADER_MD2_H +#define HEADER_MD2_H + +#include /* OPENSSL_NO_MD2, MD2_INT */ +#ifdef OPENSSL_NO_MD2 +#error MD2 is disabled. +#endif +#include + +#define MD2_DIGEST_LENGTH 16 +#define MD2_BLOCK 16 + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct MD2state_st + { + unsigned int num; + unsigned char data[MD2_BLOCK]; + MD2_INT cksm[MD2_BLOCK]; + MD2_INT state[MD2_BLOCK]; + } MD2_CTX; + +const char *MD2_options(void); +int MD2_Init(MD2_CTX *c); +int MD2_Update(MD2_CTX *c, const unsigned char *data, size_t len); +int MD2_Final(unsigned char *md, MD2_CTX *c); +unsigned char *MD2(const unsigned char *d, size_t n,unsigned char *md); +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_tls/include/openssl/md4.h b/lib_tls/include/openssl/md4.h new file mode 100644 index 000000000..5598c93a4 --- /dev/null +++ b/lib_tls/include/openssl/md4.h @@ -0,0 +1,117 @@ +/* crypto/md4/md4.h */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#ifndef HEADER_MD4_H +#define HEADER_MD4_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef OPENSSL_NO_MD4 +#error MD4 is disabled. +#endif + +/* + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + * ! MD4_LONG has to be at least 32 bits wide. If it's wider, then ! + * ! MD4_LONG_LOG2 has to be defined along. ! + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + */ + +#if defined(OPENSSL_SYS_WIN16) || defined(__LP32__) +#define MD4_LONG unsigned long +#elif defined(OPENSSL_SYS_CRAY) || defined(__ILP64__) +#define MD4_LONG unsigned long +#define MD4_LONG_LOG2 3 +/* + * _CRAY note. I could declare short, but I have no idea what impact + * does it have on performance on none-T3E machines. I could declare + * int, but at least on C90 sizeof(int) can be chosen at compile time. + * So I've chosen long... + * + */ +#else +#define MD4_LONG unsigned int +#endif + +#define MD4_CBLOCK 64 +#define MD4_LBLOCK (MD4_CBLOCK/4) +#define MD4_DIGEST_LENGTH 16 + +typedef struct MD4state_st + { + MD4_LONG A,B,C,D; + MD4_LONG Nl,Nh; + MD4_LONG data[MD4_LBLOCK]; + unsigned int num; + } MD4_CTX; + +int MD4_Init(MD4_CTX *c); +int MD4_Update(MD4_CTX *c, const void *data, size_t len); +int MD4_Final(unsigned char *md, MD4_CTX *c); +unsigned char *MD4(const unsigned char *d, size_t n, unsigned char *md); +void MD4_Transform(MD4_CTX *c, const unsigned char *b); +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_tls/include/openssl/md5.h b/lib_tls/include/openssl/md5.h new file mode 100644 index 000000000..dbdc0e1ab --- /dev/null +++ b/lib_tls/include/openssl/md5.h @@ -0,0 +1,117 @@ +/* crypto/md5/md5.h */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#ifndef HEADER_MD5_H +#define HEADER_MD5_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef OPENSSL_NO_MD5 +#error MD5 is disabled. +#endif + +/* + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + * ! MD5_LONG has to be at least 32 bits wide. If it's wider, then ! + * ! MD5_LONG_LOG2 has to be defined along. ! + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + */ + +#if defined(OPENSSL_SYS_WIN16) || defined(__LP32__) +#define MD5_LONG unsigned long +#elif defined(OPENSSL_SYS_CRAY) || defined(__ILP64__) +#define MD5_LONG unsigned long +#define MD5_LONG_LOG2 3 +/* + * _CRAY note. I could declare short, but I have no idea what impact + * does it have on performance on none-T3E machines. I could declare + * int, but at least on C90 sizeof(int) can be chosen at compile time. + * So I've chosen long... + * + */ +#else +#define MD5_LONG unsigned int +#endif + +#define MD5_CBLOCK 64 +#define MD5_LBLOCK (MD5_CBLOCK/4) +#define MD5_DIGEST_LENGTH 16 + +typedef struct MD5state_st + { + MD5_LONG A,B,C,D; + MD5_LONG Nl,Nh; + MD5_LONG data[MD5_LBLOCK]; + unsigned int num; + } MD5_CTX; + +int MD5_Init(MD5_CTX *c); +int MD5_Update(MD5_CTX *c, const void *data, size_t len); +int MD5_Final(unsigned char *md, MD5_CTX *c); +unsigned char *MD5(const unsigned char *d, size_t n, unsigned char *md); +void MD5_Transform(MD5_CTX *c, const unsigned char *b); +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_tls/include/openssl/obj_mac.h b/lib_tls/include/openssl/obj_mac.h new file mode 100644 index 000000000..76d5ec9c0 --- /dev/null +++ b/lib_tls/include/openssl/obj_mac.h @@ -0,0 +1,3482 @@ +/* crypto/objects/obj_mac.h */ + +/* THIS FILE IS GENERATED FROM objects.txt by objects.pl via the + * following command: + * perl objects.pl objects.txt obj_mac.num obj_mac.h + */ + +/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#define SN_undef "UNDEF" +#define LN_undef "undefined" +#define NID_undef 0 +#define OBJ_undef 0L + +#define SN_itu_t "ITU-T" +#define LN_itu_t "itu-t" +#define NID_itu_t 645 +#define OBJ_itu_t 0L + +#define NID_ccitt 404 +#define OBJ_ccitt OBJ_itu_t + +#define SN_iso "ISO" +#define LN_iso "iso" +#define NID_iso 181 +#define OBJ_iso 1L + +#define SN_joint_iso_itu_t "JOINT-ISO-ITU-T" +#define LN_joint_iso_itu_t "joint-iso-itu-t" +#define NID_joint_iso_itu_t 646 +#define OBJ_joint_iso_itu_t 2L + +#define NID_joint_iso_ccitt 393 +#define OBJ_joint_iso_ccitt OBJ_joint_iso_itu_t + +#define SN_member_body "member-body" +#define LN_member_body "ISO Member Body" +#define NID_member_body 182 +#define OBJ_member_body OBJ_iso,2L + +#define SN_identified_organization "identified-organization" +#define NID_identified_organization 676 +#define OBJ_identified_organization OBJ_iso,3L + +#define SN_hmac_md5 "HMAC-MD5" +#define LN_hmac_md5 "hmac-md5" +#define NID_hmac_md5 780 +#define OBJ_hmac_md5 OBJ_identified_organization,6L,1L,5L,5L,8L,1L,1L + +#define SN_hmac_sha1 "HMAC-SHA1" +#define LN_hmac_sha1 "hmac-sha1" +#define NID_hmac_sha1 781 +#define OBJ_hmac_sha1 OBJ_identified_organization,6L,1L,5L,5L,8L,1L,2L + +#define SN_certicom_arc "certicom-arc" +#define NID_certicom_arc 677 +#define OBJ_certicom_arc OBJ_identified_organization,132L + +#define SN_international_organizations "international-organizations" +#define LN_international_organizations "International Organizations" +#define NID_international_organizations 647 +#define OBJ_international_organizations OBJ_joint_iso_itu_t,23L + +#define SN_wap "wap" +#define NID_wap 678 +#define OBJ_wap OBJ_international_organizations,43L + +#define SN_wap_wsg "wap-wsg" +#define NID_wap_wsg 679 +#define OBJ_wap_wsg OBJ_wap,13L + +#define SN_selected_attribute_types "selected-attribute-types" +#define LN_selected_attribute_types "Selected Attribute Types" +#define NID_selected_attribute_types 394 +#define OBJ_selected_attribute_types OBJ_joint_iso_itu_t,5L,1L,5L + +#define SN_clearance "clearance" +#define NID_clearance 395 +#define OBJ_clearance OBJ_selected_attribute_types,55L + +#define SN_ISO_US "ISO-US" +#define LN_ISO_US "ISO US Member Body" +#define NID_ISO_US 183 +#define OBJ_ISO_US OBJ_member_body,840L + +#define SN_X9_57 "X9-57" +#define LN_X9_57 "X9.57" +#define NID_X9_57 184 +#define OBJ_X9_57 OBJ_ISO_US,10040L + +#define SN_X9cm "X9cm" +#define LN_X9cm "X9.57 CM ?" +#define NID_X9cm 185 +#define OBJ_X9cm OBJ_X9_57,4L + +#define SN_dsa "DSA" +#define LN_dsa "dsaEncryption" +#define NID_dsa 116 +#define OBJ_dsa OBJ_X9cm,1L + +#define SN_dsaWithSHA1 "DSA-SHA1" +#define LN_dsaWithSHA1 "dsaWithSHA1" +#define NID_dsaWithSHA1 113 +#define OBJ_dsaWithSHA1 OBJ_X9cm,3L + +#define SN_ansi_X9_62 "ansi-X9-62" +#define LN_ansi_X9_62 "ANSI X9.62" +#define NID_ansi_X9_62 405 +#define OBJ_ansi_X9_62 OBJ_ISO_US,10045L + +#define OBJ_X9_62_id_fieldType OBJ_ansi_X9_62,1L + +#define SN_X9_62_prime_field "prime-field" +#define NID_X9_62_prime_field 406 +#define OBJ_X9_62_prime_field OBJ_X9_62_id_fieldType,1L + +#define SN_X9_62_characteristic_two_field "characteristic-two-field" +#define NID_X9_62_characteristic_two_field 407 +#define OBJ_X9_62_characteristic_two_field OBJ_X9_62_id_fieldType,2L + +#define SN_X9_62_id_characteristic_two_basis "id-characteristic-two-basis" +#define NID_X9_62_id_characteristic_two_basis 680 +#define OBJ_X9_62_id_characteristic_two_basis OBJ_X9_62_characteristic_two_field,3L + +#define SN_X9_62_onBasis "onBasis" +#define NID_X9_62_onBasis 681 +#define OBJ_X9_62_onBasis OBJ_X9_62_id_characteristic_two_basis,1L + +#define SN_X9_62_tpBasis "tpBasis" +#define NID_X9_62_tpBasis 682 +#define OBJ_X9_62_tpBasis OBJ_X9_62_id_characteristic_two_basis,2L + +#define SN_X9_62_ppBasis "ppBasis" +#define NID_X9_62_ppBasis 683 +#define OBJ_X9_62_ppBasis OBJ_X9_62_id_characteristic_two_basis,3L + +#define OBJ_X9_62_id_publicKeyType OBJ_ansi_X9_62,2L + +#define SN_X9_62_id_ecPublicKey "id-ecPublicKey" +#define NID_X9_62_id_ecPublicKey 408 +#define OBJ_X9_62_id_ecPublicKey OBJ_X9_62_id_publicKeyType,1L + +#define OBJ_X9_62_ellipticCurve OBJ_ansi_X9_62,3L + +#define OBJ_X9_62_c_TwoCurve OBJ_X9_62_ellipticCurve,0L + +#define SN_X9_62_c2pnb163v1 "c2pnb163v1" +#define NID_X9_62_c2pnb163v1 684 +#define OBJ_X9_62_c2pnb163v1 OBJ_X9_62_c_TwoCurve,1L + +#define SN_X9_62_c2pnb163v2 "c2pnb163v2" +#define NID_X9_62_c2pnb163v2 685 +#define OBJ_X9_62_c2pnb163v2 OBJ_X9_62_c_TwoCurve,2L + +#define SN_X9_62_c2pnb163v3 "c2pnb163v3" +#define NID_X9_62_c2pnb163v3 686 +#define OBJ_X9_62_c2pnb163v3 OBJ_X9_62_c_TwoCurve,3L + +#define SN_X9_62_c2pnb176v1 "c2pnb176v1" +#define NID_X9_62_c2pnb176v1 687 +#define OBJ_X9_62_c2pnb176v1 OBJ_X9_62_c_TwoCurve,4L + +#define SN_X9_62_c2tnb191v1 "c2tnb191v1" +#define NID_X9_62_c2tnb191v1 688 +#define OBJ_X9_62_c2tnb191v1 OBJ_X9_62_c_TwoCurve,5L + +#define SN_X9_62_c2tnb191v2 "c2tnb191v2" +#define NID_X9_62_c2tnb191v2 689 +#define OBJ_X9_62_c2tnb191v2 OBJ_X9_62_c_TwoCurve,6L + +#define SN_X9_62_c2tnb191v3 "c2tnb191v3" +#define NID_X9_62_c2tnb191v3 690 +#define OBJ_X9_62_c2tnb191v3 OBJ_X9_62_c_TwoCurve,7L + +#define SN_X9_62_c2onb191v4 "c2onb191v4" +#define NID_X9_62_c2onb191v4 691 +#define OBJ_X9_62_c2onb191v4 OBJ_X9_62_c_TwoCurve,8L + +#define SN_X9_62_c2onb191v5 "c2onb191v5" +#define NID_X9_62_c2onb191v5 692 +#define OBJ_X9_62_c2onb191v5 OBJ_X9_62_c_TwoCurve,9L + +#define SN_X9_62_c2pnb208w1 "c2pnb208w1" +#define NID_X9_62_c2pnb208w1 693 +#define OBJ_X9_62_c2pnb208w1 OBJ_X9_62_c_TwoCurve,10L + +#define SN_X9_62_c2tnb239v1 "c2tnb239v1" +#define NID_X9_62_c2tnb239v1 694 +#define OBJ_X9_62_c2tnb239v1 OBJ_X9_62_c_TwoCurve,11L + +#define SN_X9_62_c2tnb239v2 "c2tnb239v2" +#define NID_X9_62_c2tnb239v2 695 +#define OBJ_X9_62_c2tnb239v2 OBJ_X9_62_c_TwoCurve,12L + +#define SN_X9_62_c2tnb239v3 "c2tnb239v3" +#define NID_X9_62_c2tnb239v3 696 +#define OBJ_X9_62_c2tnb239v3 OBJ_X9_62_c_TwoCurve,13L + +#define SN_X9_62_c2onb239v4 "c2onb239v4" +#define NID_X9_62_c2onb239v4 697 +#define OBJ_X9_62_c2onb239v4 OBJ_X9_62_c_TwoCurve,14L + +#define SN_X9_62_c2onb239v5 "c2onb239v5" +#define NID_X9_62_c2onb239v5 698 +#define OBJ_X9_62_c2onb239v5 OBJ_X9_62_c_TwoCurve,15L + +#define SN_X9_62_c2pnb272w1 "c2pnb272w1" +#define NID_X9_62_c2pnb272w1 699 +#define OBJ_X9_62_c2pnb272w1 OBJ_X9_62_c_TwoCurve,16L + +#define SN_X9_62_c2pnb304w1 "c2pnb304w1" +#define NID_X9_62_c2pnb304w1 700 +#define OBJ_X9_62_c2pnb304w1 OBJ_X9_62_c_TwoCurve,17L + +#define SN_X9_62_c2tnb359v1 "c2tnb359v1" +#define NID_X9_62_c2tnb359v1 701 +#define OBJ_X9_62_c2tnb359v1 OBJ_X9_62_c_TwoCurve,18L + +#define SN_X9_62_c2pnb368w1 "c2pnb368w1" +#define NID_X9_62_c2pnb368w1 702 +#define OBJ_X9_62_c2pnb368w1 OBJ_X9_62_c_TwoCurve,19L + +#define SN_X9_62_c2tnb431r1 "c2tnb431r1" +#define NID_X9_62_c2tnb431r1 703 +#define OBJ_X9_62_c2tnb431r1 OBJ_X9_62_c_TwoCurve,20L + +#define OBJ_X9_62_primeCurve OBJ_X9_62_ellipticCurve,1L + +#define SN_X9_62_prime192v1 "prime192v1" +#define NID_X9_62_prime192v1 409 +#define OBJ_X9_62_prime192v1 OBJ_X9_62_primeCurve,1L + +#define SN_X9_62_prime192v2 "prime192v2" +#define NID_X9_62_prime192v2 410 +#define OBJ_X9_62_prime192v2 OBJ_X9_62_primeCurve,2L + +#define SN_X9_62_prime192v3 "prime192v3" +#define NID_X9_62_prime192v3 411 +#define OBJ_X9_62_prime192v3 OBJ_X9_62_primeCurve,3L + +#define SN_X9_62_prime239v1 "prime239v1" +#define NID_X9_62_prime239v1 412 +#define OBJ_X9_62_prime239v1 OBJ_X9_62_primeCurve,4L + +#define SN_X9_62_prime239v2 "prime239v2" +#define NID_X9_62_prime239v2 413 +#define OBJ_X9_62_prime239v2 OBJ_X9_62_primeCurve,5L + +#define SN_X9_62_prime239v3 "prime239v3" +#define NID_X9_62_prime239v3 414 +#define OBJ_X9_62_prime239v3 OBJ_X9_62_primeCurve,6L + +#define SN_X9_62_prime256v1 "prime256v1" +#define NID_X9_62_prime256v1 415 +#define OBJ_X9_62_prime256v1 OBJ_X9_62_primeCurve,7L + +#define OBJ_X9_62_id_ecSigType OBJ_ansi_X9_62,4L + +#define SN_ecdsa_with_SHA1 "ecdsa-with-SHA1" +#define NID_ecdsa_with_SHA1 416 +#define OBJ_ecdsa_with_SHA1 OBJ_X9_62_id_ecSigType,1L + +#define OBJ_secg_ellipticCurve OBJ_certicom_arc,0L + +#define SN_secp112r1 "secp112r1" +#define NID_secp112r1 704 +#define OBJ_secp112r1 OBJ_secg_ellipticCurve,6L + +#define SN_secp112r2 "secp112r2" +#define NID_secp112r2 705 +#define OBJ_secp112r2 OBJ_secg_ellipticCurve,7L + +#define SN_secp128r1 "secp128r1" +#define NID_secp128r1 706 +#define OBJ_secp128r1 OBJ_secg_ellipticCurve,28L + +#define SN_secp128r2 "secp128r2" +#define NID_secp128r2 707 +#define OBJ_secp128r2 OBJ_secg_ellipticCurve,29L + +#define SN_secp160k1 "secp160k1" +#define NID_secp160k1 708 +#define OBJ_secp160k1 OBJ_secg_ellipticCurve,9L + +#define SN_secp160r1 "secp160r1" +#define NID_secp160r1 709 +#define OBJ_secp160r1 OBJ_secg_ellipticCurve,8L + +#define SN_secp160r2 "secp160r2" +#define NID_secp160r2 710 +#define OBJ_secp160r2 OBJ_secg_ellipticCurve,30L + +#define SN_secp192k1 "secp192k1" +#define NID_secp192k1 711 +#define OBJ_secp192k1 OBJ_secg_ellipticCurve,31L + +#define SN_secp224k1 "secp224k1" +#define NID_secp224k1 712 +#define OBJ_secp224k1 OBJ_secg_ellipticCurve,32L + +#define SN_secp224r1 "secp224r1" +#define NID_secp224r1 713 +#define OBJ_secp224r1 OBJ_secg_ellipticCurve,33L + +#define SN_secp256k1 "secp256k1" +#define NID_secp256k1 714 +#define OBJ_secp256k1 OBJ_secg_ellipticCurve,10L + +#define SN_secp384r1 "secp384r1" +#define NID_secp384r1 715 +#define OBJ_secp384r1 OBJ_secg_ellipticCurve,34L + +#define SN_secp521r1 "secp521r1" +#define NID_secp521r1 716 +#define OBJ_secp521r1 OBJ_secg_ellipticCurve,35L + +#define SN_sect113r1 "sect113r1" +#define NID_sect113r1 717 +#define OBJ_sect113r1 OBJ_secg_ellipticCurve,4L + +#define SN_sect113r2 "sect113r2" +#define NID_sect113r2 718 +#define OBJ_sect113r2 OBJ_secg_ellipticCurve,5L + +#define SN_sect131r1 "sect131r1" +#define NID_sect131r1 719 +#define OBJ_sect131r1 OBJ_secg_ellipticCurve,22L + +#define SN_sect131r2 "sect131r2" +#define NID_sect131r2 720 +#define OBJ_sect131r2 OBJ_secg_ellipticCurve,23L + +#define SN_sect163k1 "sect163k1" +#define NID_sect163k1 721 +#define OBJ_sect163k1 OBJ_secg_ellipticCurve,1L + +#define SN_sect163r1 "sect163r1" +#define NID_sect163r1 722 +#define OBJ_sect163r1 OBJ_secg_ellipticCurve,2L + +#define SN_sect163r2 "sect163r2" +#define NID_sect163r2 723 +#define OBJ_sect163r2 OBJ_secg_ellipticCurve,15L + +#define SN_sect193r1 "sect193r1" +#define NID_sect193r1 724 +#define OBJ_sect193r1 OBJ_secg_ellipticCurve,24L + +#define SN_sect193r2 "sect193r2" +#define NID_sect193r2 725 +#define OBJ_sect193r2 OBJ_secg_ellipticCurve,25L + +#define SN_sect233k1 "sect233k1" +#define NID_sect233k1 726 +#define OBJ_sect233k1 OBJ_secg_ellipticCurve,26L + +#define SN_sect233r1 "sect233r1" +#define NID_sect233r1 727 +#define OBJ_sect233r1 OBJ_secg_ellipticCurve,27L + +#define SN_sect239k1 "sect239k1" +#define NID_sect239k1 728 +#define OBJ_sect239k1 OBJ_secg_ellipticCurve,3L + +#define SN_sect283k1 "sect283k1" +#define NID_sect283k1 729 +#define OBJ_sect283k1 OBJ_secg_ellipticCurve,16L + +#define SN_sect283r1 "sect283r1" +#define NID_sect283r1 730 +#define OBJ_sect283r1 OBJ_secg_ellipticCurve,17L + +#define SN_sect409k1 "sect409k1" +#define NID_sect409k1 731 +#define OBJ_sect409k1 OBJ_secg_ellipticCurve,36L + +#define SN_sect409r1 "sect409r1" +#define NID_sect409r1 732 +#define OBJ_sect409r1 OBJ_secg_ellipticCurve,37L + +#define SN_sect571k1 "sect571k1" +#define NID_sect571k1 733 +#define OBJ_sect571k1 OBJ_secg_ellipticCurve,38L + +#define SN_sect571r1 "sect571r1" +#define NID_sect571r1 734 +#define OBJ_sect571r1 OBJ_secg_ellipticCurve,39L + +#define OBJ_wap_wsg_idm_ecid OBJ_wap_wsg,4L + +#define SN_wap_wsg_idm_ecid_wtls1 "wap-wsg-idm-ecid-wtls1" +#define NID_wap_wsg_idm_ecid_wtls1 735 +#define OBJ_wap_wsg_idm_ecid_wtls1 OBJ_wap_wsg_idm_ecid,1L + +#define SN_wap_wsg_idm_ecid_wtls3 "wap-wsg-idm-ecid-wtls3" +#define NID_wap_wsg_idm_ecid_wtls3 736 +#define OBJ_wap_wsg_idm_ecid_wtls3 OBJ_wap_wsg_idm_ecid,3L + +#define SN_wap_wsg_idm_ecid_wtls4 "wap-wsg-idm-ecid-wtls4" +#define NID_wap_wsg_idm_ecid_wtls4 737 +#define OBJ_wap_wsg_idm_ecid_wtls4 OBJ_wap_wsg_idm_ecid,4L + +#define SN_wap_wsg_idm_ecid_wtls5 "wap-wsg-idm-ecid-wtls5" +#define NID_wap_wsg_idm_ecid_wtls5 738 +#define OBJ_wap_wsg_idm_ecid_wtls5 OBJ_wap_wsg_idm_ecid,5L + +#define SN_wap_wsg_idm_ecid_wtls6 "wap-wsg-idm-ecid-wtls6" +#define NID_wap_wsg_idm_ecid_wtls6 739 +#define OBJ_wap_wsg_idm_ecid_wtls6 OBJ_wap_wsg_idm_ecid,6L + +#define SN_wap_wsg_idm_ecid_wtls7 "wap-wsg-idm-ecid-wtls7" +#define NID_wap_wsg_idm_ecid_wtls7 740 +#define OBJ_wap_wsg_idm_ecid_wtls7 OBJ_wap_wsg_idm_ecid,7L + +#define SN_wap_wsg_idm_ecid_wtls8 "wap-wsg-idm-ecid-wtls8" +#define NID_wap_wsg_idm_ecid_wtls8 741 +#define OBJ_wap_wsg_idm_ecid_wtls8 OBJ_wap_wsg_idm_ecid,8L + +#define SN_wap_wsg_idm_ecid_wtls9 "wap-wsg-idm-ecid-wtls9" +#define NID_wap_wsg_idm_ecid_wtls9 742 +#define OBJ_wap_wsg_idm_ecid_wtls9 OBJ_wap_wsg_idm_ecid,9L + +#define SN_wap_wsg_idm_ecid_wtls10 "wap-wsg-idm-ecid-wtls10" +#define NID_wap_wsg_idm_ecid_wtls10 743 +#define OBJ_wap_wsg_idm_ecid_wtls10 OBJ_wap_wsg_idm_ecid,10L + +#define SN_wap_wsg_idm_ecid_wtls11 "wap-wsg-idm-ecid-wtls11" +#define NID_wap_wsg_idm_ecid_wtls11 744 +#define OBJ_wap_wsg_idm_ecid_wtls11 OBJ_wap_wsg_idm_ecid,11L + +#define SN_wap_wsg_idm_ecid_wtls12 "wap-wsg-idm-ecid-wtls12" +#define NID_wap_wsg_idm_ecid_wtls12 745 +#define OBJ_wap_wsg_idm_ecid_wtls12 OBJ_wap_wsg_idm_ecid,12L + +#define SN_cast5_cbc "CAST5-CBC" +#define LN_cast5_cbc "cast5-cbc" +#define NID_cast5_cbc 108 +#define OBJ_cast5_cbc OBJ_ISO_US,113533L,7L,66L,10L + +#define SN_cast5_ecb "CAST5-ECB" +#define LN_cast5_ecb "cast5-ecb" +#define NID_cast5_ecb 109 + +#define SN_cast5_cfb64 "CAST5-CFB" +#define LN_cast5_cfb64 "cast5-cfb" +#define NID_cast5_cfb64 110 + +#define SN_cast5_ofb64 "CAST5-OFB" +#define LN_cast5_ofb64 "cast5-ofb" +#define NID_cast5_ofb64 111 + +#define LN_pbeWithMD5AndCast5_CBC "pbeWithMD5AndCast5CBC" +#define NID_pbeWithMD5AndCast5_CBC 112 +#define OBJ_pbeWithMD5AndCast5_CBC OBJ_ISO_US,113533L,7L,66L,12L + +#define SN_id_PasswordBasedMAC "id-PasswordBasedMAC" +#define LN_id_PasswordBasedMAC "password based MAC" +#define NID_id_PasswordBasedMAC 782 +#define OBJ_id_PasswordBasedMAC OBJ_ISO_US,113533L,7L,66L,13L + +#define SN_id_DHBasedMac "id-DHBasedMac" +#define LN_id_DHBasedMac "Diffie-Hellman based MAC" +#define NID_id_DHBasedMac 783 +#define OBJ_id_DHBasedMac OBJ_ISO_US,113533L,7L,66L,30L + +#define SN_rsadsi "rsadsi" +#define LN_rsadsi "RSA Data Security, Inc." +#define NID_rsadsi 1 +#define OBJ_rsadsi OBJ_ISO_US,113549L + +#define SN_pkcs "pkcs" +#define LN_pkcs "RSA Data Security, Inc. PKCS" +#define NID_pkcs 2 +#define OBJ_pkcs OBJ_rsadsi,1L + +#define SN_pkcs1 "pkcs1" +#define NID_pkcs1 186 +#define OBJ_pkcs1 OBJ_pkcs,1L + +#define LN_rsaEncryption "rsaEncryption" +#define NID_rsaEncryption 6 +#define OBJ_rsaEncryption OBJ_pkcs1,1L + +#define SN_md2WithRSAEncryption "RSA-MD2" +#define LN_md2WithRSAEncryption "md2WithRSAEncryption" +#define NID_md2WithRSAEncryption 7 +#define OBJ_md2WithRSAEncryption OBJ_pkcs1,2L + +#define SN_md4WithRSAEncryption "RSA-MD4" +#define LN_md4WithRSAEncryption "md4WithRSAEncryption" +#define NID_md4WithRSAEncryption 396 +#define OBJ_md4WithRSAEncryption OBJ_pkcs1,3L + +#define SN_md5WithRSAEncryption "RSA-MD5" +#define LN_md5WithRSAEncryption "md5WithRSAEncryption" +#define NID_md5WithRSAEncryption 8 +#define OBJ_md5WithRSAEncryption OBJ_pkcs1,4L + +#define SN_sha1WithRSAEncryption "RSA-SHA1" +#define LN_sha1WithRSAEncryption "sha1WithRSAEncryption" +#define NID_sha1WithRSAEncryption 65 +#define OBJ_sha1WithRSAEncryption OBJ_pkcs1,5L + +#define SN_sha256WithRSAEncryption "RSA-SHA256" +#define LN_sha256WithRSAEncryption "sha256WithRSAEncryption" +#define NID_sha256WithRSAEncryption 668 +#define OBJ_sha256WithRSAEncryption OBJ_pkcs1,11L + +#define SN_sha384WithRSAEncryption "RSA-SHA384" +#define LN_sha384WithRSAEncryption "sha384WithRSAEncryption" +#define NID_sha384WithRSAEncryption 669 +#define OBJ_sha384WithRSAEncryption OBJ_pkcs1,12L + +#define SN_sha512WithRSAEncryption "RSA-SHA512" +#define LN_sha512WithRSAEncryption "sha512WithRSAEncryption" +#define NID_sha512WithRSAEncryption 670 +#define OBJ_sha512WithRSAEncryption OBJ_pkcs1,13L + +#define SN_sha224WithRSAEncryption "RSA-SHA224" +#define LN_sha224WithRSAEncryption "sha224WithRSAEncryption" +#define NID_sha224WithRSAEncryption 671 +#define OBJ_sha224WithRSAEncryption OBJ_pkcs1,14L + +#define SN_pkcs3 "pkcs3" +#define NID_pkcs3 27 +#define OBJ_pkcs3 OBJ_pkcs,3L + +#define LN_dhKeyAgreement "dhKeyAgreement" +#define NID_dhKeyAgreement 28 +#define OBJ_dhKeyAgreement OBJ_pkcs3,1L + +#define SN_pkcs5 "pkcs5" +#define NID_pkcs5 187 +#define OBJ_pkcs5 OBJ_pkcs,5L + +#define SN_pbeWithMD2AndDES_CBC "PBE-MD2-DES" +#define LN_pbeWithMD2AndDES_CBC "pbeWithMD2AndDES-CBC" +#define NID_pbeWithMD2AndDES_CBC 9 +#define OBJ_pbeWithMD2AndDES_CBC OBJ_pkcs5,1L + +#define SN_pbeWithMD5AndDES_CBC "PBE-MD5-DES" +#define LN_pbeWithMD5AndDES_CBC "pbeWithMD5AndDES-CBC" +#define NID_pbeWithMD5AndDES_CBC 10 +#define OBJ_pbeWithMD5AndDES_CBC OBJ_pkcs5,3L + +#define SN_pbeWithMD2AndRC2_CBC "PBE-MD2-RC2-64" +#define LN_pbeWithMD2AndRC2_CBC "pbeWithMD2AndRC2-CBC" +#define NID_pbeWithMD2AndRC2_CBC 168 +#define OBJ_pbeWithMD2AndRC2_CBC OBJ_pkcs5,4L + +#define SN_pbeWithMD5AndRC2_CBC "PBE-MD5-RC2-64" +#define LN_pbeWithMD5AndRC2_CBC "pbeWithMD5AndRC2-CBC" +#define NID_pbeWithMD5AndRC2_CBC 169 +#define OBJ_pbeWithMD5AndRC2_CBC OBJ_pkcs5,6L + +#define SN_pbeWithSHA1AndDES_CBC "PBE-SHA1-DES" +#define LN_pbeWithSHA1AndDES_CBC "pbeWithSHA1AndDES-CBC" +#define NID_pbeWithSHA1AndDES_CBC 170 +#define OBJ_pbeWithSHA1AndDES_CBC OBJ_pkcs5,10L + +#define SN_pbeWithSHA1AndRC2_CBC "PBE-SHA1-RC2-64" +#define LN_pbeWithSHA1AndRC2_CBC "pbeWithSHA1AndRC2-CBC" +#define NID_pbeWithSHA1AndRC2_CBC 68 +#define OBJ_pbeWithSHA1AndRC2_CBC OBJ_pkcs5,11L + +#define LN_id_pbkdf2 "PBKDF2" +#define NID_id_pbkdf2 69 +#define OBJ_id_pbkdf2 OBJ_pkcs5,12L + +#define LN_pbes2 "PBES2" +#define NID_pbes2 161 +#define OBJ_pbes2 OBJ_pkcs5,13L + +#define LN_pbmac1 "PBMAC1" +#define NID_pbmac1 162 +#define OBJ_pbmac1 OBJ_pkcs5,14L + +#define SN_pkcs7 "pkcs7" +#define NID_pkcs7 20 +#define OBJ_pkcs7 OBJ_pkcs,7L + +#define LN_pkcs7_data "pkcs7-data" +#define NID_pkcs7_data 21 +#define OBJ_pkcs7_data OBJ_pkcs7,1L + +#define LN_pkcs7_signed "pkcs7-signedData" +#define NID_pkcs7_signed 22 +#define OBJ_pkcs7_signed OBJ_pkcs7,2L + +#define LN_pkcs7_enveloped "pkcs7-envelopedData" +#define NID_pkcs7_enveloped 23 +#define OBJ_pkcs7_enveloped OBJ_pkcs7,3L + +#define LN_pkcs7_signedAndEnveloped "pkcs7-signedAndEnvelopedData" +#define NID_pkcs7_signedAndEnveloped 24 +#define OBJ_pkcs7_signedAndEnveloped OBJ_pkcs7,4L + +#define LN_pkcs7_digest "pkcs7-digestData" +#define NID_pkcs7_digest 25 +#define OBJ_pkcs7_digest OBJ_pkcs7,5L + +#define LN_pkcs7_encrypted "pkcs7-encryptedData" +#define NID_pkcs7_encrypted 26 +#define OBJ_pkcs7_encrypted OBJ_pkcs7,6L + +#define SN_pkcs9 "pkcs9" +#define NID_pkcs9 47 +#define OBJ_pkcs9 OBJ_pkcs,9L + +#define LN_pkcs9_emailAddress "emailAddress" +#define NID_pkcs9_emailAddress 48 +#define OBJ_pkcs9_emailAddress OBJ_pkcs9,1L + +#define LN_pkcs9_unstructuredName "unstructuredName" +#define NID_pkcs9_unstructuredName 49 +#define OBJ_pkcs9_unstructuredName OBJ_pkcs9,2L + +#define LN_pkcs9_contentType "contentType" +#define NID_pkcs9_contentType 50 +#define OBJ_pkcs9_contentType OBJ_pkcs9,3L + +#define LN_pkcs9_messageDigest "messageDigest" +#define NID_pkcs9_messageDigest 51 +#define OBJ_pkcs9_messageDigest OBJ_pkcs9,4L + +#define LN_pkcs9_signingTime "signingTime" +#define NID_pkcs9_signingTime 52 +#define OBJ_pkcs9_signingTime OBJ_pkcs9,5L + +#define LN_pkcs9_countersignature "countersignature" +#define NID_pkcs9_countersignature 53 +#define OBJ_pkcs9_countersignature OBJ_pkcs9,6L + +#define LN_pkcs9_challengePassword "challengePassword" +#define NID_pkcs9_challengePassword 54 +#define OBJ_pkcs9_challengePassword OBJ_pkcs9,7L + +#define LN_pkcs9_unstructuredAddress "unstructuredAddress" +#define NID_pkcs9_unstructuredAddress 55 +#define OBJ_pkcs9_unstructuredAddress OBJ_pkcs9,8L + +#define LN_pkcs9_extCertAttributes "extendedCertificateAttributes" +#define NID_pkcs9_extCertAttributes 56 +#define OBJ_pkcs9_extCertAttributes OBJ_pkcs9,9L + +#define SN_ext_req "extReq" +#define LN_ext_req "Extension Request" +#define NID_ext_req 172 +#define OBJ_ext_req OBJ_pkcs9,14L + +#define SN_SMIMECapabilities "SMIME-CAPS" +#define LN_SMIMECapabilities "S/MIME Capabilities" +#define NID_SMIMECapabilities 167 +#define OBJ_SMIMECapabilities OBJ_pkcs9,15L + +#define SN_SMIME "SMIME" +#define LN_SMIME "S/MIME" +#define NID_SMIME 188 +#define OBJ_SMIME OBJ_pkcs9,16L + +#define SN_id_smime_mod "id-smime-mod" +#define NID_id_smime_mod 189 +#define OBJ_id_smime_mod OBJ_SMIME,0L + +#define SN_id_smime_ct "id-smime-ct" +#define NID_id_smime_ct 190 +#define OBJ_id_smime_ct OBJ_SMIME,1L + +#define SN_id_smime_aa "id-smime-aa" +#define NID_id_smime_aa 191 +#define OBJ_id_smime_aa OBJ_SMIME,2L + +#define SN_id_smime_alg "id-smime-alg" +#define NID_id_smime_alg 192 +#define OBJ_id_smime_alg OBJ_SMIME,3L + +#define SN_id_smime_cd "id-smime-cd" +#define NID_id_smime_cd 193 +#define OBJ_id_smime_cd OBJ_SMIME,4L + +#define SN_id_smime_spq "id-smime-spq" +#define NID_id_smime_spq 194 +#define OBJ_id_smime_spq OBJ_SMIME,5L + +#define SN_id_smime_cti "id-smime-cti" +#define NID_id_smime_cti 195 +#define OBJ_id_smime_cti OBJ_SMIME,6L + +#define SN_id_smime_mod_cms "id-smime-mod-cms" +#define NID_id_smime_mod_cms 196 +#define OBJ_id_smime_mod_cms OBJ_id_smime_mod,1L + +#define SN_id_smime_mod_ess "id-smime-mod-ess" +#define NID_id_smime_mod_ess 197 +#define OBJ_id_smime_mod_ess OBJ_id_smime_mod,2L + +#define SN_id_smime_mod_oid "id-smime-mod-oid" +#define NID_id_smime_mod_oid 198 +#define OBJ_id_smime_mod_oid OBJ_id_smime_mod,3L + +#define SN_id_smime_mod_msg_v3 "id-smime-mod-msg-v3" +#define NID_id_smime_mod_msg_v3 199 +#define OBJ_id_smime_mod_msg_v3 OBJ_id_smime_mod,4L + +#define SN_id_smime_mod_ets_eSignature_88 "id-smime-mod-ets-eSignature-88" +#define NID_id_smime_mod_ets_eSignature_88 200 +#define OBJ_id_smime_mod_ets_eSignature_88 OBJ_id_smime_mod,5L + +#define SN_id_smime_mod_ets_eSignature_97 "id-smime-mod-ets-eSignature-97" +#define NID_id_smime_mod_ets_eSignature_97 201 +#define OBJ_id_smime_mod_ets_eSignature_97 OBJ_id_smime_mod,6L + +#define SN_id_smime_mod_ets_eSigPolicy_88 "id-smime-mod-ets-eSigPolicy-88" +#define NID_id_smime_mod_ets_eSigPolicy_88 202 +#define OBJ_id_smime_mod_ets_eSigPolicy_88 OBJ_id_smime_mod,7L + +#define SN_id_smime_mod_ets_eSigPolicy_97 "id-smime-mod-ets-eSigPolicy-97" +#define NID_id_smime_mod_ets_eSigPolicy_97 203 +#define OBJ_id_smime_mod_ets_eSigPolicy_97 OBJ_id_smime_mod,8L + +#define SN_id_smime_ct_receipt "id-smime-ct-receipt" +#define NID_id_smime_ct_receipt 204 +#define OBJ_id_smime_ct_receipt OBJ_id_smime_ct,1L + +#define SN_id_smime_ct_authData "id-smime-ct-authData" +#define NID_id_smime_ct_authData 205 +#define OBJ_id_smime_ct_authData OBJ_id_smime_ct,2L + +#define SN_id_smime_ct_publishCert "id-smime-ct-publishCert" +#define NID_id_smime_ct_publishCert 206 +#define OBJ_id_smime_ct_publishCert OBJ_id_smime_ct,3L + +#define SN_id_smime_ct_TSTInfo "id-smime-ct-TSTInfo" +#define NID_id_smime_ct_TSTInfo 207 +#define OBJ_id_smime_ct_TSTInfo OBJ_id_smime_ct,4L + +#define SN_id_smime_ct_TDTInfo "id-smime-ct-TDTInfo" +#define NID_id_smime_ct_TDTInfo 208 +#define OBJ_id_smime_ct_TDTInfo OBJ_id_smime_ct,5L + +#define SN_id_smime_ct_contentInfo "id-smime-ct-contentInfo" +#define NID_id_smime_ct_contentInfo 209 +#define OBJ_id_smime_ct_contentInfo OBJ_id_smime_ct,6L + +#define SN_id_smime_ct_DVCSRequestData "id-smime-ct-DVCSRequestData" +#define NID_id_smime_ct_DVCSRequestData 210 +#define OBJ_id_smime_ct_DVCSRequestData OBJ_id_smime_ct,7L + +#define SN_id_smime_ct_DVCSResponseData "id-smime-ct-DVCSResponseData" +#define NID_id_smime_ct_DVCSResponseData 211 +#define OBJ_id_smime_ct_DVCSResponseData OBJ_id_smime_ct,8L + +#define SN_id_smime_ct_compressedData "id-smime-ct-compressedData" +#define NID_id_smime_ct_compressedData 786 +#define OBJ_id_smime_ct_compressedData OBJ_id_smime_ct,9L + +#define SN_id_ct_asciiTextWithCRLF "id-ct-asciiTextWithCRLF" +#define NID_id_ct_asciiTextWithCRLF 787 +#define OBJ_id_ct_asciiTextWithCRLF OBJ_id_smime_ct,27L + +#define SN_id_smime_aa_receiptRequest "id-smime-aa-receiptRequest" +#define NID_id_smime_aa_receiptRequest 212 +#define OBJ_id_smime_aa_receiptRequest OBJ_id_smime_aa,1L + +#define SN_id_smime_aa_securityLabel "id-smime-aa-securityLabel" +#define NID_id_smime_aa_securityLabel 213 +#define OBJ_id_smime_aa_securityLabel OBJ_id_smime_aa,2L + +#define SN_id_smime_aa_mlExpandHistory "id-smime-aa-mlExpandHistory" +#define NID_id_smime_aa_mlExpandHistory 214 +#define OBJ_id_smime_aa_mlExpandHistory OBJ_id_smime_aa,3L + +#define SN_id_smime_aa_contentHint "id-smime-aa-contentHint" +#define NID_id_smime_aa_contentHint 215 +#define OBJ_id_smime_aa_contentHint OBJ_id_smime_aa,4L + +#define SN_id_smime_aa_msgSigDigest "id-smime-aa-msgSigDigest" +#define NID_id_smime_aa_msgSigDigest 216 +#define OBJ_id_smime_aa_msgSigDigest OBJ_id_smime_aa,5L + +#define SN_id_smime_aa_encapContentType "id-smime-aa-encapContentType" +#define NID_id_smime_aa_encapContentType 217 +#define OBJ_id_smime_aa_encapContentType OBJ_id_smime_aa,6L + +#define SN_id_smime_aa_contentIdentifier "id-smime-aa-contentIdentifier" +#define NID_id_smime_aa_contentIdentifier 218 +#define OBJ_id_smime_aa_contentIdentifier OBJ_id_smime_aa,7L + +#define SN_id_smime_aa_macValue "id-smime-aa-macValue" +#define NID_id_smime_aa_macValue 219 +#define OBJ_id_smime_aa_macValue OBJ_id_smime_aa,8L + +#define SN_id_smime_aa_equivalentLabels "id-smime-aa-equivalentLabels" +#define NID_id_smime_aa_equivalentLabels 220 +#define OBJ_id_smime_aa_equivalentLabels OBJ_id_smime_aa,9L + +#define SN_id_smime_aa_contentReference "id-smime-aa-contentReference" +#define NID_id_smime_aa_contentReference 221 +#define OBJ_id_smime_aa_contentReference OBJ_id_smime_aa,10L + +#define SN_id_smime_aa_encrypKeyPref "id-smime-aa-encrypKeyPref" +#define NID_id_smime_aa_encrypKeyPref 222 +#define OBJ_id_smime_aa_encrypKeyPref OBJ_id_smime_aa,11L + +#define SN_id_smime_aa_signingCertificate "id-smime-aa-signingCertificate" +#define NID_id_smime_aa_signingCertificate 223 +#define OBJ_id_smime_aa_signingCertificate OBJ_id_smime_aa,12L + +#define SN_id_smime_aa_smimeEncryptCerts "id-smime-aa-smimeEncryptCerts" +#define NID_id_smime_aa_smimeEncryptCerts 224 +#define OBJ_id_smime_aa_smimeEncryptCerts OBJ_id_smime_aa,13L + +#define SN_id_smime_aa_timeStampToken "id-smime-aa-timeStampToken" +#define NID_id_smime_aa_timeStampToken 225 +#define OBJ_id_smime_aa_timeStampToken OBJ_id_smime_aa,14L + +#define SN_id_smime_aa_ets_sigPolicyId "id-smime-aa-ets-sigPolicyId" +#define NID_id_smime_aa_ets_sigPolicyId 226 +#define OBJ_id_smime_aa_ets_sigPolicyId OBJ_id_smime_aa,15L + +#define SN_id_smime_aa_ets_commitmentType "id-smime-aa-ets-commitmentType" +#define NID_id_smime_aa_ets_commitmentType 227 +#define OBJ_id_smime_aa_ets_commitmentType OBJ_id_smime_aa,16L + +#define SN_id_smime_aa_ets_signerLocation "id-smime-aa-ets-signerLocation" +#define NID_id_smime_aa_ets_signerLocation 228 +#define OBJ_id_smime_aa_ets_signerLocation OBJ_id_smime_aa,17L + +#define SN_id_smime_aa_ets_signerAttr "id-smime-aa-ets-signerAttr" +#define NID_id_smime_aa_ets_signerAttr 229 +#define OBJ_id_smime_aa_ets_signerAttr OBJ_id_smime_aa,18L + +#define SN_id_smime_aa_ets_otherSigCert "id-smime-aa-ets-otherSigCert" +#define NID_id_smime_aa_ets_otherSigCert 230 +#define OBJ_id_smime_aa_ets_otherSigCert OBJ_id_smime_aa,19L + +#define SN_id_smime_aa_ets_contentTimestamp "id-smime-aa-ets-contentTimestamp" +#define NID_id_smime_aa_ets_contentTimestamp 231 +#define OBJ_id_smime_aa_ets_contentTimestamp OBJ_id_smime_aa,20L + +#define SN_id_smime_aa_ets_CertificateRefs "id-smime-aa-ets-CertificateRefs" +#define NID_id_smime_aa_ets_CertificateRefs 232 +#define OBJ_id_smime_aa_ets_CertificateRefs OBJ_id_smime_aa,21L + +#define SN_id_smime_aa_ets_RevocationRefs "id-smime-aa-ets-RevocationRefs" +#define NID_id_smime_aa_ets_RevocationRefs 233 +#define OBJ_id_smime_aa_ets_RevocationRefs OBJ_id_smime_aa,22L + +#define SN_id_smime_aa_ets_certValues "id-smime-aa-ets-certValues" +#define NID_id_smime_aa_ets_certValues 234 +#define OBJ_id_smime_aa_ets_certValues OBJ_id_smime_aa,23L + +#define SN_id_smime_aa_ets_revocationValues "id-smime-aa-ets-revocationValues" +#define NID_id_smime_aa_ets_revocationValues 235 +#define OBJ_id_smime_aa_ets_revocationValues OBJ_id_smime_aa,24L + +#define SN_id_smime_aa_ets_escTimeStamp "id-smime-aa-ets-escTimeStamp" +#define NID_id_smime_aa_ets_escTimeStamp 236 +#define OBJ_id_smime_aa_ets_escTimeStamp OBJ_id_smime_aa,25L + +#define SN_id_smime_aa_ets_certCRLTimestamp "id-smime-aa-ets-certCRLTimestamp" +#define NID_id_smime_aa_ets_certCRLTimestamp 237 +#define OBJ_id_smime_aa_ets_certCRLTimestamp OBJ_id_smime_aa,26L + +#define SN_id_smime_aa_ets_archiveTimeStamp "id-smime-aa-ets-archiveTimeStamp" +#define NID_id_smime_aa_ets_archiveTimeStamp 238 +#define OBJ_id_smime_aa_ets_archiveTimeStamp OBJ_id_smime_aa,27L + +#define SN_id_smime_aa_signatureType "id-smime-aa-signatureType" +#define NID_id_smime_aa_signatureType 239 +#define OBJ_id_smime_aa_signatureType OBJ_id_smime_aa,28L + +#define SN_id_smime_aa_dvcs_dvc "id-smime-aa-dvcs-dvc" +#define NID_id_smime_aa_dvcs_dvc 240 +#define OBJ_id_smime_aa_dvcs_dvc OBJ_id_smime_aa,29L + +#define SN_id_smime_alg_ESDHwith3DES "id-smime-alg-ESDHwith3DES" +#define NID_id_smime_alg_ESDHwith3DES 241 +#define OBJ_id_smime_alg_ESDHwith3DES OBJ_id_smime_alg,1L + +#define SN_id_smime_alg_ESDHwithRC2 "id-smime-alg-ESDHwithRC2" +#define NID_id_smime_alg_ESDHwithRC2 242 +#define OBJ_id_smime_alg_ESDHwithRC2 OBJ_id_smime_alg,2L + +#define SN_id_smime_alg_3DESwrap "id-smime-alg-3DESwrap" +#define NID_id_smime_alg_3DESwrap 243 +#define OBJ_id_smime_alg_3DESwrap OBJ_id_smime_alg,3L + +#define SN_id_smime_alg_RC2wrap "id-smime-alg-RC2wrap" +#define NID_id_smime_alg_RC2wrap 244 +#define OBJ_id_smime_alg_RC2wrap OBJ_id_smime_alg,4L + +#define SN_id_smime_alg_ESDH "id-smime-alg-ESDH" +#define NID_id_smime_alg_ESDH 245 +#define OBJ_id_smime_alg_ESDH OBJ_id_smime_alg,5L + +#define SN_id_smime_alg_CMS3DESwrap "id-smime-alg-CMS3DESwrap" +#define NID_id_smime_alg_CMS3DESwrap 246 +#define OBJ_id_smime_alg_CMS3DESwrap OBJ_id_smime_alg,6L + +#define SN_id_smime_alg_CMSRC2wrap "id-smime-alg-CMSRC2wrap" +#define NID_id_smime_alg_CMSRC2wrap 247 +#define OBJ_id_smime_alg_CMSRC2wrap OBJ_id_smime_alg,7L + +#define SN_id_smime_cd_ldap "id-smime-cd-ldap" +#define NID_id_smime_cd_ldap 248 +#define OBJ_id_smime_cd_ldap OBJ_id_smime_cd,1L + +#define SN_id_smime_spq_ets_sqt_uri "id-smime-spq-ets-sqt-uri" +#define NID_id_smime_spq_ets_sqt_uri 249 +#define OBJ_id_smime_spq_ets_sqt_uri OBJ_id_smime_spq,1L + +#define SN_id_smime_spq_ets_sqt_unotice "id-smime-spq-ets-sqt-unotice" +#define NID_id_smime_spq_ets_sqt_unotice 250 +#define OBJ_id_smime_spq_ets_sqt_unotice OBJ_id_smime_spq,2L + +#define SN_id_smime_cti_ets_proofOfOrigin "id-smime-cti-ets-proofOfOrigin" +#define NID_id_smime_cti_ets_proofOfOrigin 251 +#define OBJ_id_smime_cti_ets_proofOfOrigin OBJ_id_smime_cti,1L + +#define SN_id_smime_cti_ets_proofOfReceipt "id-smime-cti-ets-proofOfReceipt" +#define NID_id_smime_cti_ets_proofOfReceipt 252 +#define OBJ_id_smime_cti_ets_proofOfReceipt OBJ_id_smime_cti,2L + +#define SN_id_smime_cti_ets_proofOfDelivery "id-smime-cti-ets-proofOfDelivery" +#define NID_id_smime_cti_ets_proofOfDelivery 253 +#define OBJ_id_smime_cti_ets_proofOfDelivery OBJ_id_smime_cti,3L + +#define SN_id_smime_cti_ets_proofOfSender "id-smime-cti-ets-proofOfSender" +#define NID_id_smime_cti_ets_proofOfSender 254 +#define OBJ_id_smime_cti_ets_proofOfSender OBJ_id_smime_cti,4L + +#define SN_id_smime_cti_ets_proofOfApproval "id-smime-cti-ets-proofOfApproval" +#define NID_id_smime_cti_ets_proofOfApproval 255 +#define OBJ_id_smime_cti_ets_proofOfApproval OBJ_id_smime_cti,5L + +#define SN_id_smime_cti_ets_proofOfCreation "id-smime-cti-ets-proofOfCreation" +#define NID_id_smime_cti_ets_proofOfCreation 256 +#define OBJ_id_smime_cti_ets_proofOfCreation OBJ_id_smime_cti,6L + +#define LN_friendlyName "friendlyName" +#define NID_friendlyName 156 +#define OBJ_friendlyName OBJ_pkcs9,20L + +#define LN_localKeyID "localKeyID" +#define NID_localKeyID 157 +#define OBJ_localKeyID OBJ_pkcs9,21L + +#define SN_ms_csp_name "CSPName" +#define LN_ms_csp_name "Microsoft CSP Name" +#define NID_ms_csp_name 417 +#define OBJ_ms_csp_name 1L,3L,6L,1L,4L,1L,311L,17L,1L + +#define OBJ_certTypes OBJ_pkcs9,22L + +#define LN_x509Certificate "x509Certificate" +#define NID_x509Certificate 158 +#define OBJ_x509Certificate OBJ_certTypes,1L + +#define LN_sdsiCertificate "sdsiCertificate" +#define NID_sdsiCertificate 159 +#define OBJ_sdsiCertificate OBJ_certTypes,2L + +#define OBJ_crlTypes OBJ_pkcs9,23L + +#define LN_x509Crl "x509Crl" +#define NID_x509Crl 160 +#define OBJ_x509Crl OBJ_crlTypes,1L + +#define OBJ_pkcs12 OBJ_pkcs,12L + +#define OBJ_pkcs12_pbeids OBJ_pkcs12,1L + +#define SN_pbe_WithSHA1And128BitRC4 "PBE-SHA1-RC4-128" +#define LN_pbe_WithSHA1And128BitRC4 "pbeWithSHA1And128BitRC4" +#define NID_pbe_WithSHA1And128BitRC4 144 +#define OBJ_pbe_WithSHA1And128BitRC4 OBJ_pkcs12_pbeids,1L + +#define SN_pbe_WithSHA1And40BitRC4 "PBE-SHA1-RC4-40" +#define LN_pbe_WithSHA1And40BitRC4 "pbeWithSHA1And40BitRC4" +#define NID_pbe_WithSHA1And40BitRC4 145 +#define OBJ_pbe_WithSHA1And40BitRC4 OBJ_pkcs12_pbeids,2L + +#define SN_pbe_WithSHA1And3_Key_TripleDES_CBC "PBE-SHA1-3DES" +#define LN_pbe_WithSHA1And3_Key_TripleDES_CBC "pbeWithSHA1And3-KeyTripleDES-CBC" +#define NID_pbe_WithSHA1And3_Key_TripleDES_CBC 146 +#define OBJ_pbe_WithSHA1And3_Key_TripleDES_CBC OBJ_pkcs12_pbeids,3L + +#define SN_pbe_WithSHA1And2_Key_TripleDES_CBC "PBE-SHA1-2DES" +#define LN_pbe_WithSHA1And2_Key_TripleDES_CBC "pbeWithSHA1And2-KeyTripleDES-CBC" +#define NID_pbe_WithSHA1And2_Key_TripleDES_CBC 147 +#define OBJ_pbe_WithSHA1And2_Key_TripleDES_CBC OBJ_pkcs12_pbeids,4L + +#define SN_pbe_WithSHA1And128BitRC2_CBC "PBE-SHA1-RC2-128" +#define LN_pbe_WithSHA1And128BitRC2_CBC "pbeWithSHA1And128BitRC2-CBC" +#define NID_pbe_WithSHA1And128BitRC2_CBC 148 +#define OBJ_pbe_WithSHA1And128BitRC2_CBC OBJ_pkcs12_pbeids,5L + +#define SN_pbe_WithSHA1And40BitRC2_CBC "PBE-SHA1-RC2-40" +#define LN_pbe_WithSHA1And40BitRC2_CBC "pbeWithSHA1And40BitRC2-CBC" +#define NID_pbe_WithSHA1And40BitRC2_CBC 149 +#define OBJ_pbe_WithSHA1And40BitRC2_CBC OBJ_pkcs12_pbeids,6L + +#define OBJ_pkcs12_Version1 OBJ_pkcs12,10L + +#define OBJ_pkcs12_BagIds OBJ_pkcs12_Version1,1L + +#define LN_keyBag "keyBag" +#define NID_keyBag 150 +#define OBJ_keyBag OBJ_pkcs12_BagIds,1L + +#define LN_pkcs8ShroudedKeyBag "pkcs8ShroudedKeyBag" +#define NID_pkcs8ShroudedKeyBag 151 +#define OBJ_pkcs8ShroudedKeyBag OBJ_pkcs12_BagIds,2L + +#define LN_certBag "certBag" +#define NID_certBag 152 +#define OBJ_certBag OBJ_pkcs12_BagIds,3L + +#define LN_crlBag "crlBag" +#define NID_crlBag 153 +#define OBJ_crlBag OBJ_pkcs12_BagIds,4L + +#define LN_secretBag "secretBag" +#define NID_secretBag 154 +#define OBJ_secretBag OBJ_pkcs12_BagIds,5L + +#define LN_safeContentsBag "safeContentsBag" +#define NID_safeContentsBag 155 +#define OBJ_safeContentsBag OBJ_pkcs12_BagIds,6L + +#define SN_md2 "MD2" +#define LN_md2 "md2" +#define NID_md2 3 +#define OBJ_md2 OBJ_rsadsi,2L,2L + +#define SN_md4 "MD4" +#define LN_md4 "md4" +#define NID_md4 257 +#define OBJ_md4 OBJ_rsadsi,2L,4L + +#define SN_md5 "MD5" +#define LN_md5 "md5" +#define NID_md5 4 +#define OBJ_md5 OBJ_rsadsi,2L,5L + +#define SN_md5_sha1 "MD5-SHA1" +#define LN_md5_sha1 "md5-sha1" +#define NID_md5_sha1 114 + +#define LN_hmacWithSHA1 "hmacWithSHA1" +#define NID_hmacWithSHA1 163 +#define OBJ_hmacWithSHA1 OBJ_rsadsi,2L,7L + +#define SN_rc2_cbc "RC2-CBC" +#define LN_rc2_cbc "rc2-cbc" +#define NID_rc2_cbc 37 +#define OBJ_rc2_cbc OBJ_rsadsi,3L,2L + +#define SN_rc2_ecb "RC2-ECB" +#define LN_rc2_ecb "rc2-ecb" +#define NID_rc2_ecb 38 + +#define SN_rc2_cfb64 "RC2-CFB" +#define LN_rc2_cfb64 "rc2-cfb" +#define NID_rc2_cfb64 39 + +#define SN_rc2_ofb64 "RC2-OFB" +#define LN_rc2_ofb64 "rc2-ofb" +#define NID_rc2_ofb64 40 + +#define SN_rc2_40_cbc "RC2-40-CBC" +#define LN_rc2_40_cbc "rc2-40-cbc" +#define NID_rc2_40_cbc 98 + +#define SN_rc2_64_cbc "RC2-64-CBC" +#define LN_rc2_64_cbc "rc2-64-cbc" +#define NID_rc2_64_cbc 166 + +#define SN_rc4 "RC4" +#define LN_rc4 "rc4" +#define NID_rc4 5 +#define OBJ_rc4 OBJ_rsadsi,3L,4L + +#define SN_rc4_40 "RC4-40" +#define LN_rc4_40 "rc4-40" +#define NID_rc4_40 97 + +#define SN_des_ede3_cbc "DES-EDE3-CBC" +#define LN_des_ede3_cbc "des-ede3-cbc" +#define NID_des_ede3_cbc 44 +#define OBJ_des_ede3_cbc OBJ_rsadsi,3L,7L + +#define SN_rc5_cbc "RC5-CBC" +#define LN_rc5_cbc "rc5-cbc" +#define NID_rc5_cbc 120 +#define OBJ_rc5_cbc OBJ_rsadsi,3L,8L + +#define SN_rc5_ecb "RC5-ECB" +#define LN_rc5_ecb "rc5-ecb" +#define NID_rc5_ecb 121 + +#define SN_rc5_cfb64 "RC5-CFB" +#define LN_rc5_cfb64 "rc5-cfb" +#define NID_rc5_cfb64 122 + +#define SN_rc5_ofb64 "RC5-OFB" +#define LN_rc5_ofb64 "rc5-ofb" +#define NID_rc5_ofb64 123 + +#define SN_ms_ext_req "msExtReq" +#define LN_ms_ext_req "Microsoft Extension Request" +#define NID_ms_ext_req 171 +#define OBJ_ms_ext_req 1L,3L,6L,1L,4L,1L,311L,2L,1L,14L + +#define SN_ms_code_ind "msCodeInd" +#define LN_ms_code_ind "Microsoft Individual Code Signing" +#define NID_ms_code_ind 134 +#define OBJ_ms_code_ind 1L,3L,6L,1L,4L,1L,311L,2L,1L,21L + +#define SN_ms_code_com "msCodeCom" +#define LN_ms_code_com "Microsoft Commercial Code Signing" +#define NID_ms_code_com 135 +#define OBJ_ms_code_com 1L,3L,6L,1L,4L,1L,311L,2L,1L,22L + +#define SN_ms_ctl_sign "msCTLSign" +#define LN_ms_ctl_sign "Microsoft Trust List Signing" +#define NID_ms_ctl_sign 136 +#define OBJ_ms_ctl_sign 1L,3L,6L,1L,4L,1L,311L,10L,3L,1L + +#define SN_ms_sgc "msSGC" +#define LN_ms_sgc "Microsoft Server Gated Crypto" +#define NID_ms_sgc 137 +#define OBJ_ms_sgc 1L,3L,6L,1L,4L,1L,311L,10L,3L,3L + +#define SN_ms_efs "msEFS" +#define LN_ms_efs "Microsoft Encrypted File System" +#define NID_ms_efs 138 +#define OBJ_ms_efs 1L,3L,6L,1L,4L,1L,311L,10L,3L,4L + +#define SN_ms_smartcard_login "msSmartcardLogin" +#define LN_ms_smartcard_login "Microsoft Smartcardlogin" +#define NID_ms_smartcard_login 648 +#define OBJ_ms_smartcard_login 1L,3L,6L,1L,4L,1L,311L,20L,2L,2L + +#define SN_ms_upn "msUPN" +#define LN_ms_upn "Microsoft Universal Principal Name" +#define NID_ms_upn 649 +#define OBJ_ms_upn 1L,3L,6L,1L,4L,1L,311L,20L,2L,3L + +#define SN_idea_cbc "IDEA-CBC" +#define LN_idea_cbc "idea-cbc" +#define NID_idea_cbc 34 +#define OBJ_idea_cbc 1L,3L,6L,1L,4L,1L,188L,7L,1L,1L,2L + +#define SN_idea_ecb "IDEA-ECB" +#define LN_idea_ecb "idea-ecb" +#define NID_idea_ecb 36 + +#define SN_idea_cfb64 "IDEA-CFB" +#define LN_idea_cfb64 "idea-cfb" +#define NID_idea_cfb64 35 + +#define SN_idea_ofb64 "IDEA-OFB" +#define LN_idea_ofb64 "idea-ofb" +#define NID_idea_ofb64 46 + +#define SN_bf_cbc "BF-CBC" +#define LN_bf_cbc "bf-cbc" +#define NID_bf_cbc 91 +#define OBJ_bf_cbc 1L,3L,6L,1L,4L,1L,3029L,1L,2L + +#define SN_bf_ecb "BF-ECB" +#define LN_bf_ecb "bf-ecb" +#define NID_bf_ecb 92 + +#define SN_bf_cfb64 "BF-CFB" +#define LN_bf_cfb64 "bf-cfb" +#define NID_bf_cfb64 93 + +#define SN_bf_ofb64 "BF-OFB" +#define LN_bf_ofb64 "bf-ofb" +#define NID_bf_ofb64 94 + +#define SN_id_pkix "PKIX" +#define NID_id_pkix 127 +#define OBJ_id_pkix 1L,3L,6L,1L,5L,5L,7L + +#define SN_id_pkix_mod "id-pkix-mod" +#define NID_id_pkix_mod 258 +#define OBJ_id_pkix_mod OBJ_id_pkix,0L + +#define SN_id_pe "id-pe" +#define NID_id_pe 175 +#define OBJ_id_pe OBJ_id_pkix,1L + +#define SN_id_qt "id-qt" +#define NID_id_qt 259 +#define OBJ_id_qt OBJ_id_pkix,2L + +#define SN_id_kp "id-kp" +#define NID_id_kp 128 +#define OBJ_id_kp OBJ_id_pkix,3L + +#define SN_id_it "id-it" +#define NID_id_it 260 +#define OBJ_id_it OBJ_id_pkix,4L + +#define SN_id_pkip "id-pkip" +#define NID_id_pkip 261 +#define OBJ_id_pkip OBJ_id_pkix,5L + +#define SN_id_alg "id-alg" +#define NID_id_alg 262 +#define OBJ_id_alg OBJ_id_pkix,6L + +#define SN_id_cmc "id-cmc" +#define NID_id_cmc 263 +#define OBJ_id_cmc OBJ_id_pkix,7L + +#define SN_id_on "id-on" +#define NID_id_on 264 +#define OBJ_id_on OBJ_id_pkix,8L + +#define SN_id_pda "id-pda" +#define NID_id_pda 265 +#define OBJ_id_pda OBJ_id_pkix,9L + +#define SN_id_aca "id-aca" +#define NID_id_aca 266 +#define OBJ_id_aca OBJ_id_pkix,10L + +#define SN_id_qcs "id-qcs" +#define NID_id_qcs 267 +#define OBJ_id_qcs OBJ_id_pkix,11L + +#define SN_id_cct "id-cct" +#define NID_id_cct 268 +#define OBJ_id_cct OBJ_id_pkix,12L + +#define SN_id_ppl "id-ppl" +#define NID_id_ppl 662 +#define OBJ_id_ppl OBJ_id_pkix,21L + +#define SN_id_ad "id-ad" +#define NID_id_ad 176 +#define OBJ_id_ad OBJ_id_pkix,48L + +#define SN_id_pkix1_explicit_88 "id-pkix1-explicit-88" +#define NID_id_pkix1_explicit_88 269 +#define OBJ_id_pkix1_explicit_88 OBJ_id_pkix_mod,1L + +#define SN_id_pkix1_implicit_88 "id-pkix1-implicit-88" +#define NID_id_pkix1_implicit_88 270 +#define OBJ_id_pkix1_implicit_88 OBJ_id_pkix_mod,2L + +#define SN_id_pkix1_explicit_93 "id-pkix1-explicit-93" +#define NID_id_pkix1_explicit_93 271 +#define OBJ_id_pkix1_explicit_93 OBJ_id_pkix_mod,3L + +#define SN_id_pkix1_implicit_93 "id-pkix1-implicit-93" +#define NID_id_pkix1_implicit_93 272 +#define OBJ_id_pkix1_implicit_93 OBJ_id_pkix_mod,4L + +#define SN_id_mod_crmf "id-mod-crmf" +#define NID_id_mod_crmf 273 +#define OBJ_id_mod_crmf OBJ_id_pkix_mod,5L + +#define SN_id_mod_cmc "id-mod-cmc" +#define NID_id_mod_cmc 274 +#define OBJ_id_mod_cmc OBJ_id_pkix_mod,6L + +#define SN_id_mod_kea_profile_88 "id-mod-kea-profile-88" +#define NID_id_mod_kea_profile_88 275 +#define OBJ_id_mod_kea_profile_88 OBJ_id_pkix_mod,7L + +#define SN_id_mod_kea_profile_93 "id-mod-kea-profile-93" +#define NID_id_mod_kea_profile_93 276 +#define OBJ_id_mod_kea_profile_93 OBJ_id_pkix_mod,8L + +#define SN_id_mod_cmp "id-mod-cmp" +#define NID_id_mod_cmp 277 +#define OBJ_id_mod_cmp OBJ_id_pkix_mod,9L + +#define SN_id_mod_qualified_cert_88 "id-mod-qualified-cert-88" +#define NID_id_mod_qualified_cert_88 278 +#define OBJ_id_mod_qualified_cert_88 OBJ_id_pkix_mod,10L + +#define SN_id_mod_qualified_cert_93 "id-mod-qualified-cert-93" +#define NID_id_mod_qualified_cert_93 279 +#define OBJ_id_mod_qualified_cert_93 OBJ_id_pkix_mod,11L + +#define SN_id_mod_attribute_cert "id-mod-attribute-cert" +#define NID_id_mod_attribute_cert 280 +#define OBJ_id_mod_attribute_cert OBJ_id_pkix_mod,12L + +#define SN_id_mod_timestamp_protocol "id-mod-timestamp-protocol" +#define NID_id_mod_timestamp_protocol 281 +#define OBJ_id_mod_timestamp_protocol OBJ_id_pkix_mod,13L + +#define SN_id_mod_ocsp "id-mod-ocsp" +#define NID_id_mod_ocsp 282 +#define OBJ_id_mod_ocsp OBJ_id_pkix_mod,14L + +#define SN_id_mod_dvcs "id-mod-dvcs" +#define NID_id_mod_dvcs 283 +#define OBJ_id_mod_dvcs OBJ_id_pkix_mod,15L + +#define SN_id_mod_cmp2000 "id-mod-cmp2000" +#define NID_id_mod_cmp2000 284 +#define OBJ_id_mod_cmp2000 OBJ_id_pkix_mod,16L + +#define SN_info_access "authorityInfoAccess" +#define LN_info_access "Authority Information Access" +#define NID_info_access 177 +#define OBJ_info_access OBJ_id_pe,1L + +#define SN_biometricInfo "biometricInfo" +#define LN_biometricInfo "Biometric Info" +#define NID_biometricInfo 285 +#define OBJ_biometricInfo OBJ_id_pe,2L + +#define SN_qcStatements "qcStatements" +#define NID_qcStatements 286 +#define OBJ_qcStatements OBJ_id_pe,3L + +#define SN_ac_auditEntity "ac-auditEntity" +#define NID_ac_auditEntity 287 +#define OBJ_ac_auditEntity OBJ_id_pe,4L + +#define SN_ac_targeting "ac-targeting" +#define NID_ac_targeting 288 +#define OBJ_ac_targeting OBJ_id_pe,5L + +#define SN_aaControls "aaControls" +#define NID_aaControls 289 +#define OBJ_aaControls OBJ_id_pe,6L + +#define SN_sbgp_ipAddrBlock "sbgp-ipAddrBlock" +#define NID_sbgp_ipAddrBlock 290 +#define OBJ_sbgp_ipAddrBlock OBJ_id_pe,7L + +#define SN_sbgp_autonomousSysNum "sbgp-autonomousSysNum" +#define NID_sbgp_autonomousSysNum 291 +#define OBJ_sbgp_autonomousSysNum OBJ_id_pe,8L + +#define SN_sbgp_routerIdentifier "sbgp-routerIdentifier" +#define NID_sbgp_routerIdentifier 292 +#define OBJ_sbgp_routerIdentifier OBJ_id_pe,9L + +#define SN_ac_proxying "ac-proxying" +#define NID_ac_proxying 397 +#define OBJ_ac_proxying OBJ_id_pe,10L + +#define SN_sinfo_access "subjectInfoAccess" +#define LN_sinfo_access "Subject Information Access" +#define NID_sinfo_access 398 +#define OBJ_sinfo_access OBJ_id_pe,11L + +#define SN_proxyCertInfo "proxyCertInfo" +#define LN_proxyCertInfo "Proxy Certificate Information" +#define NID_proxyCertInfo 663 +#define OBJ_proxyCertInfo OBJ_id_pe,14L + +#define SN_id_qt_cps "id-qt-cps" +#define LN_id_qt_cps "Policy Qualifier CPS" +#define NID_id_qt_cps 164 +#define OBJ_id_qt_cps OBJ_id_qt,1L + +#define SN_id_qt_unotice "id-qt-unotice" +#define LN_id_qt_unotice "Policy Qualifier User Notice" +#define NID_id_qt_unotice 165 +#define OBJ_id_qt_unotice OBJ_id_qt,2L + +#define SN_textNotice "textNotice" +#define NID_textNotice 293 +#define OBJ_textNotice OBJ_id_qt,3L + +#define SN_server_auth "serverAuth" +#define LN_server_auth "TLS Web Server Authentication" +#define NID_server_auth 129 +#define OBJ_server_auth OBJ_id_kp,1L + +#define SN_client_auth "clientAuth" +#define LN_client_auth "TLS Web Client Authentication" +#define NID_client_auth 130 +#define OBJ_client_auth OBJ_id_kp,2L + +#define SN_code_sign "codeSigning" +#define LN_code_sign "Code Signing" +#define NID_code_sign 131 +#define OBJ_code_sign OBJ_id_kp,3L + +#define SN_email_protect "emailProtection" +#define LN_email_protect "E-mail Protection" +#define NID_email_protect 132 +#define OBJ_email_protect OBJ_id_kp,4L + +#define SN_ipsecEndSystem "ipsecEndSystem" +#define LN_ipsecEndSystem "IPSec End System" +#define NID_ipsecEndSystem 294 +#define OBJ_ipsecEndSystem OBJ_id_kp,5L + +#define SN_ipsecTunnel "ipsecTunnel" +#define LN_ipsecTunnel "IPSec Tunnel" +#define NID_ipsecTunnel 295 +#define OBJ_ipsecTunnel OBJ_id_kp,6L + +#define SN_ipsecUser "ipsecUser" +#define LN_ipsecUser "IPSec User" +#define NID_ipsecUser 296 +#define OBJ_ipsecUser OBJ_id_kp,7L + +#define SN_time_stamp "timeStamping" +#define LN_time_stamp "Time Stamping" +#define NID_time_stamp 133 +#define OBJ_time_stamp OBJ_id_kp,8L + +#define SN_OCSP_sign "OCSPSigning" +#define LN_OCSP_sign "OCSP Signing" +#define NID_OCSP_sign 180 +#define OBJ_OCSP_sign OBJ_id_kp,9L + +#define SN_dvcs "DVCS" +#define LN_dvcs "dvcs" +#define NID_dvcs 297 +#define OBJ_dvcs OBJ_id_kp,10L + +#define SN_id_it_caProtEncCert "id-it-caProtEncCert" +#define NID_id_it_caProtEncCert 298 +#define OBJ_id_it_caProtEncCert OBJ_id_it,1L + +#define SN_id_it_signKeyPairTypes "id-it-signKeyPairTypes" +#define NID_id_it_signKeyPairTypes 299 +#define OBJ_id_it_signKeyPairTypes OBJ_id_it,2L + +#define SN_id_it_encKeyPairTypes "id-it-encKeyPairTypes" +#define NID_id_it_encKeyPairTypes 300 +#define OBJ_id_it_encKeyPairTypes OBJ_id_it,3L + +#define SN_id_it_preferredSymmAlg "id-it-preferredSymmAlg" +#define NID_id_it_preferredSymmAlg 301 +#define OBJ_id_it_preferredSymmAlg OBJ_id_it,4L + +#define SN_id_it_caKeyUpdateInfo "id-it-caKeyUpdateInfo" +#define NID_id_it_caKeyUpdateInfo 302 +#define OBJ_id_it_caKeyUpdateInfo OBJ_id_it,5L + +#define SN_id_it_currentCRL "id-it-currentCRL" +#define NID_id_it_currentCRL 303 +#define OBJ_id_it_currentCRL OBJ_id_it,6L + +#define SN_id_it_unsupportedOIDs "id-it-unsupportedOIDs" +#define NID_id_it_unsupportedOIDs 304 +#define OBJ_id_it_unsupportedOIDs OBJ_id_it,7L + +#define SN_id_it_subscriptionRequest "id-it-subscriptionRequest" +#define NID_id_it_subscriptionRequest 305 +#define OBJ_id_it_subscriptionRequest OBJ_id_it,8L + +#define SN_id_it_subscriptionResponse "id-it-subscriptionResponse" +#define NID_id_it_subscriptionResponse 306 +#define OBJ_id_it_subscriptionResponse OBJ_id_it,9L + +#define SN_id_it_keyPairParamReq "id-it-keyPairParamReq" +#define NID_id_it_keyPairParamReq 307 +#define OBJ_id_it_keyPairParamReq OBJ_id_it,10L + +#define SN_id_it_keyPairParamRep "id-it-keyPairParamRep" +#define NID_id_it_keyPairParamRep 308 +#define OBJ_id_it_keyPairParamRep OBJ_id_it,11L + +#define SN_id_it_revPassphrase "id-it-revPassphrase" +#define NID_id_it_revPassphrase 309 +#define OBJ_id_it_revPassphrase OBJ_id_it,12L + +#define SN_id_it_implicitConfirm "id-it-implicitConfirm" +#define NID_id_it_implicitConfirm 310 +#define OBJ_id_it_implicitConfirm OBJ_id_it,13L + +#define SN_id_it_confirmWaitTime "id-it-confirmWaitTime" +#define NID_id_it_confirmWaitTime 311 +#define OBJ_id_it_confirmWaitTime OBJ_id_it,14L + +#define SN_id_it_origPKIMessage "id-it-origPKIMessage" +#define NID_id_it_origPKIMessage 312 +#define OBJ_id_it_origPKIMessage OBJ_id_it,15L + +#define SN_id_it_suppLangTags "id-it-suppLangTags" +#define NID_id_it_suppLangTags 784 +#define OBJ_id_it_suppLangTags OBJ_id_it,16L + +#define SN_id_regCtrl "id-regCtrl" +#define NID_id_regCtrl 313 +#define OBJ_id_regCtrl OBJ_id_pkip,1L + +#define SN_id_regInfo "id-regInfo" +#define NID_id_regInfo 314 +#define OBJ_id_regInfo OBJ_id_pkip,2L + +#define SN_id_regCtrl_regToken "id-regCtrl-regToken" +#define NID_id_regCtrl_regToken 315 +#define OBJ_id_regCtrl_regToken OBJ_id_regCtrl,1L + +#define SN_id_regCtrl_authenticator "id-regCtrl-authenticator" +#define NID_id_regCtrl_authenticator 316 +#define OBJ_id_regCtrl_authenticator OBJ_id_regCtrl,2L + +#define SN_id_regCtrl_pkiPublicationInfo "id-regCtrl-pkiPublicationInfo" +#define NID_id_regCtrl_pkiPublicationInfo 317 +#define OBJ_id_regCtrl_pkiPublicationInfo OBJ_id_regCtrl,3L + +#define SN_id_regCtrl_pkiArchiveOptions "id-regCtrl-pkiArchiveOptions" +#define NID_id_regCtrl_pkiArchiveOptions 318 +#define OBJ_id_regCtrl_pkiArchiveOptions OBJ_id_regCtrl,4L + +#define SN_id_regCtrl_oldCertID "id-regCtrl-oldCertID" +#define NID_id_regCtrl_oldCertID 319 +#define OBJ_id_regCtrl_oldCertID OBJ_id_regCtrl,5L + +#define SN_id_regCtrl_protocolEncrKey "id-regCtrl-protocolEncrKey" +#define NID_id_regCtrl_protocolEncrKey 320 +#define OBJ_id_regCtrl_protocolEncrKey OBJ_id_regCtrl,6L + +#define SN_id_regInfo_utf8Pairs "id-regInfo-utf8Pairs" +#define NID_id_regInfo_utf8Pairs 321 +#define OBJ_id_regInfo_utf8Pairs OBJ_id_regInfo,1L + +#define SN_id_regInfo_certReq "id-regInfo-certReq" +#define NID_id_regInfo_certReq 322 +#define OBJ_id_regInfo_certReq OBJ_id_regInfo,2L + +#define SN_id_alg_des40 "id-alg-des40" +#define NID_id_alg_des40 323 +#define OBJ_id_alg_des40 OBJ_id_alg,1L + +#define SN_id_alg_noSignature "id-alg-noSignature" +#define NID_id_alg_noSignature 324 +#define OBJ_id_alg_noSignature OBJ_id_alg,2L + +#define SN_id_alg_dh_sig_hmac_sha1 "id-alg-dh-sig-hmac-sha1" +#define NID_id_alg_dh_sig_hmac_sha1 325 +#define OBJ_id_alg_dh_sig_hmac_sha1 OBJ_id_alg,3L + +#define SN_id_alg_dh_pop "id-alg-dh-pop" +#define NID_id_alg_dh_pop 326 +#define OBJ_id_alg_dh_pop OBJ_id_alg,4L + +#define SN_id_cmc_statusInfo "id-cmc-statusInfo" +#define NID_id_cmc_statusInfo 327 +#define OBJ_id_cmc_statusInfo OBJ_id_cmc,1L + +#define SN_id_cmc_identification "id-cmc-identification" +#define NID_id_cmc_identification 328 +#define OBJ_id_cmc_identification OBJ_id_cmc,2L + +#define SN_id_cmc_identityProof "id-cmc-identityProof" +#define NID_id_cmc_identityProof 329 +#define OBJ_id_cmc_identityProof OBJ_id_cmc,3L + +#define SN_id_cmc_dataReturn "id-cmc-dataReturn" +#define NID_id_cmc_dataReturn 330 +#define OBJ_id_cmc_dataReturn OBJ_id_cmc,4L + +#define SN_id_cmc_transactionId "id-cmc-transactionId" +#define NID_id_cmc_transactionId 331 +#define OBJ_id_cmc_transactionId OBJ_id_cmc,5L + +#define SN_id_cmc_senderNonce "id-cmc-senderNonce" +#define NID_id_cmc_senderNonce 332 +#define OBJ_id_cmc_senderNonce OBJ_id_cmc,6L + +#define SN_id_cmc_recipientNonce "id-cmc-recipientNonce" +#define NID_id_cmc_recipientNonce 333 +#define OBJ_id_cmc_recipientNonce OBJ_id_cmc,7L + +#define SN_id_cmc_addExtensions "id-cmc-addExtensions" +#define NID_id_cmc_addExtensions 334 +#define OBJ_id_cmc_addExtensions OBJ_id_cmc,8L + +#define SN_id_cmc_encryptedPOP "id-cmc-encryptedPOP" +#define NID_id_cmc_encryptedPOP 335 +#define OBJ_id_cmc_encryptedPOP OBJ_id_cmc,9L + +#define SN_id_cmc_decryptedPOP "id-cmc-decryptedPOP" +#define NID_id_cmc_decryptedPOP 336 +#define OBJ_id_cmc_decryptedPOP OBJ_id_cmc,10L + +#define SN_id_cmc_lraPOPWitness "id-cmc-lraPOPWitness" +#define NID_id_cmc_lraPOPWitness 337 +#define OBJ_id_cmc_lraPOPWitness OBJ_id_cmc,11L + +#define SN_id_cmc_getCert "id-cmc-getCert" +#define NID_id_cmc_getCert 338 +#define OBJ_id_cmc_getCert OBJ_id_cmc,15L + +#define SN_id_cmc_getCRL "id-cmc-getCRL" +#define NID_id_cmc_getCRL 339 +#define OBJ_id_cmc_getCRL OBJ_id_cmc,16L + +#define SN_id_cmc_revokeRequest "id-cmc-revokeRequest" +#define NID_id_cmc_revokeRequest 340 +#define OBJ_id_cmc_revokeRequest OBJ_id_cmc,17L + +#define SN_id_cmc_regInfo "id-cmc-regInfo" +#define NID_id_cmc_regInfo 341 +#define OBJ_id_cmc_regInfo OBJ_id_cmc,18L + +#define SN_id_cmc_responseInfo "id-cmc-responseInfo" +#define NID_id_cmc_responseInfo 342 +#define OBJ_id_cmc_responseInfo OBJ_id_cmc,19L + +#define SN_id_cmc_queryPending "id-cmc-queryPending" +#define NID_id_cmc_queryPending 343 +#define OBJ_id_cmc_queryPending OBJ_id_cmc,21L + +#define SN_id_cmc_popLinkRandom "id-cmc-popLinkRandom" +#define NID_id_cmc_popLinkRandom 344 +#define OBJ_id_cmc_popLinkRandom OBJ_id_cmc,22L + +#define SN_id_cmc_popLinkWitness "id-cmc-popLinkWitness" +#define NID_id_cmc_popLinkWitness 345 +#define OBJ_id_cmc_popLinkWitness OBJ_id_cmc,23L + +#define SN_id_cmc_confirmCertAcceptance "id-cmc-confirmCertAcceptance" +#define NID_id_cmc_confirmCertAcceptance 346 +#define OBJ_id_cmc_confirmCertAcceptance OBJ_id_cmc,24L + +#define SN_id_on_personalData "id-on-personalData" +#define NID_id_on_personalData 347 +#define OBJ_id_on_personalData OBJ_id_on,1L + +#define SN_id_pda_dateOfBirth "id-pda-dateOfBirth" +#define NID_id_pda_dateOfBirth 348 +#define OBJ_id_pda_dateOfBirth OBJ_id_pda,1L + +#define SN_id_pda_placeOfBirth "id-pda-placeOfBirth" +#define NID_id_pda_placeOfBirth 349 +#define OBJ_id_pda_placeOfBirth OBJ_id_pda,2L + +#define SN_id_pda_gender "id-pda-gender" +#define NID_id_pda_gender 351 +#define OBJ_id_pda_gender OBJ_id_pda,3L + +#define SN_id_pda_countryOfCitizenship "id-pda-countryOfCitizenship" +#define NID_id_pda_countryOfCitizenship 352 +#define OBJ_id_pda_countryOfCitizenship OBJ_id_pda,4L + +#define SN_id_pda_countryOfResidence "id-pda-countryOfResidence" +#define NID_id_pda_countryOfResidence 353 +#define OBJ_id_pda_countryOfResidence OBJ_id_pda,5L + +#define SN_id_aca_authenticationInfo "id-aca-authenticationInfo" +#define NID_id_aca_authenticationInfo 354 +#define OBJ_id_aca_authenticationInfo OBJ_id_aca,1L + +#define SN_id_aca_accessIdentity "id-aca-accessIdentity" +#define NID_id_aca_accessIdentity 355 +#define OBJ_id_aca_accessIdentity OBJ_id_aca,2L + +#define SN_id_aca_chargingIdentity "id-aca-chargingIdentity" +#define NID_id_aca_chargingIdentity 356 +#define OBJ_id_aca_chargingIdentity OBJ_id_aca,3L + +#define SN_id_aca_group "id-aca-group" +#define NID_id_aca_group 357 +#define OBJ_id_aca_group OBJ_id_aca,4L + +#define SN_id_aca_role "id-aca-role" +#define NID_id_aca_role 358 +#define OBJ_id_aca_role OBJ_id_aca,5L + +#define SN_id_aca_encAttrs "id-aca-encAttrs" +#define NID_id_aca_encAttrs 399 +#define OBJ_id_aca_encAttrs OBJ_id_aca,6L + +#define SN_id_qcs_pkixQCSyntax_v1 "id-qcs-pkixQCSyntax-v1" +#define NID_id_qcs_pkixQCSyntax_v1 359 +#define OBJ_id_qcs_pkixQCSyntax_v1 OBJ_id_qcs,1L + +#define SN_id_cct_crs "id-cct-crs" +#define NID_id_cct_crs 360 +#define OBJ_id_cct_crs OBJ_id_cct,1L + +#define SN_id_cct_PKIData "id-cct-PKIData" +#define NID_id_cct_PKIData 361 +#define OBJ_id_cct_PKIData OBJ_id_cct,2L + +#define SN_id_cct_PKIResponse "id-cct-PKIResponse" +#define NID_id_cct_PKIResponse 362 +#define OBJ_id_cct_PKIResponse OBJ_id_cct,3L + +#define SN_id_ppl_anyLanguage "id-ppl-anyLanguage" +#define LN_id_ppl_anyLanguage "Any language" +#define NID_id_ppl_anyLanguage 664 +#define OBJ_id_ppl_anyLanguage OBJ_id_ppl,0L + +#define SN_id_ppl_inheritAll "id-ppl-inheritAll" +#define LN_id_ppl_inheritAll "Inherit all" +#define NID_id_ppl_inheritAll 665 +#define OBJ_id_ppl_inheritAll OBJ_id_ppl,1L + +#define SN_Independent "id-ppl-independent" +#define LN_Independent "Independent" +#define NID_Independent 667 +#define OBJ_Independent OBJ_id_ppl,2L + +#define SN_ad_OCSP "OCSP" +#define LN_ad_OCSP "OCSP" +#define NID_ad_OCSP 178 +#define OBJ_ad_OCSP OBJ_id_ad,1L + +#define SN_ad_ca_issuers "caIssuers" +#define LN_ad_ca_issuers "CA Issuers" +#define NID_ad_ca_issuers 179 +#define OBJ_ad_ca_issuers OBJ_id_ad,2L + +#define SN_ad_timeStamping "ad_timestamping" +#define LN_ad_timeStamping "AD Time Stamping" +#define NID_ad_timeStamping 363 +#define OBJ_ad_timeStamping OBJ_id_ad,3L + +#define SN_ad_dvcs "AD_DVCS" +#define LN_ad_dvcs "ad dvcs" +#define NID_ad_dvcs 364 +#define OBJ_ad_dvcs OBJ_id_ad,4L + +#define SN_caRepository "caRepository" +#define LN_caRepository "CA Repository" +#define NID_caRepository 785 +#define OBJ_caRepository OBJ_id_ad,5L + +#define OBJ_id_pkix_OCSP OBJ_ad_OCSP + +#define SN_id_pkix_OCSP_basic "basicOCSPResponse" +#define LN_id_pkix_OCSP_basic "Basic OCSP Response" +#define NID_id_pkix_OCSP_basic 365 +#define OBJ_id_pkix_OCSP_basic OBJ_id_pkix_OCSP,1L + +#define SN_id_pkix_OCSP_Nonce "Nonce" +#define LN_id_pkix_OCSP_Nonce "OCSP Nonce" +#define NID_id_pkix_OCSP_Nonce 366 +#define OBJ_id_pkix_OCSP_Nonce OBJ_id_pkix_OCSP,2L + +#define SN_id_pkix_OCSP_CrlID "CrlID" +#define LN_id_pkix_OCSP_CrlID "OCSP CRL ID" +#define NID_id_pkix_OCSP_CrlID 367 +#define OBJ_id_pkix_OCSP_CrlID OBJ_id_pkix_OCSP,3L + +#define SN_id_pkix_OCSP_acceptableResponses "acceptableResponses" +#define LN_id_pkix_OCSP_acceptableResponses "Acceptable OCSP Responses" +#define NID_id_pkix_OCSP_acceptableResponses 368 +#define OBJ_id_pkix_OCSP_acceptableResponses OBJ_id_pkix_OCSP,4L + +#define SN_id_pkix_OCSP_noCheck "noCheck" +#define LN_id_pkix_OCSP_noCheck "OCSP No Check" +#define NID_id_pkix_OCSP_noCheck 369 +#define OBJ_id_pkix_OCSP_noCheck OBJ_id_pkix_OCSP,5L + +#define SN_id_pkix_OCSP_archiveCutoff "archiveCutoff" +#define LN_id_pkix_OCSP_archiveCutoff "OCSP Archive Cutoff" +#define NID_id_pkix_OCSP_archiveCutoff 370 +#define OBJ_id_pkix_OCSP_archiveCutoff OBJ_id_pkix_OCSP,6L + +#define SN_id_pkix_OCSP_serviceLocator "serviceLocator" +#define LN_id_pkix_OCSP_serviceLocator "OCSP Service Locator" +#define NID_id_pkix_OCSP_serviceLocator 371 +#define OBJ_id_pkix_OCSP_serviceLocator OBJ_id_pkix_OCSP,7L + +#define SN_id_pkix_OCSP_extendedStatus "extendedStatus" +#define LN_id_pkix_OCSP_extendedStatus "Extended OCSP Status" +#define NID_id_pkix_OCSP_extendedStatus 372 +#define OBJ_id_pkix_OCSP_extendedStatus OBJ_id_pkix_OCSP,8L + +#define SN_id_pkix_OCSP_valid "valid" +#define NID_id_pkix_OCSP_valid 373 +#define OBJ_id_pkix_OCSP_valid OBJ_id_pkix_OCSP,9L + +#define SN_id_pkix_OCSP_path "path" +#define NID_id_pkix_OCSP_path 374 +#define OBJ_id_pkix_OCSP_path OBJ_id_pkix_OCSP,10L + +#define SN_id_pkix_OCSP_trustRoot "trustRoot" +#define LN_id_pkix_OCSP_trustRoot "Trust Root" +#define NID_id_pkix_OCSP_trustRoot 375 +#define OBJ_id_pkix_OCSP_trustRoot OBJ_id_pkix_OCSP,11L + +#define SN_algorithm "algorithm" +#define LN_algorithm "algorithm" +#define NID_algorithm 376 +#define OBJ_algorithm 1L,3L,14L,3L,2L + +#define SN_md5WithRSA "RSA-NP-MD5" +#define LN_md5WithRSA "md5WithRSA" +#define NID_md5WithRSA 104 +#define OBJ_md5WithRSA OBJ_algorithm,3L + +#define SN_des_ecb "DES-ECB" +#define LN_des_ecb "des-ecb" +#define NID_des_ecb 29 +#define OBJ_des_ecb OBJ_algorithm,6L + +#define SN_des_cbc "DES-CBC" +#define LN_des_cbc "des-cbc" +#define NID_des_cbc 31 +#define OBJ_des_cbc OBJ_algorithm,7L + +#define SN_des_ofb64 "DES-OFB" +#define LN_des_ofb64 "des-ofb" +#define NID_des_ofb64 45 +#define OBJ_des_ofb64 OBJ_algorithm,8L + +#define SN_des_cfb64 "DES-CFB" +#define LN_des_cfb64 "des-cfb" +#define NID_des_cfb64 30 +#define OBJ_des_cfb64 OBJ_algorithm,9L + +#define SN_rsaSignature "rsaSignature" +#define NID_rsaSignature 377 +#define OBJ_rsaSignature OBJ_algorithm,11L + +#define SN_dsa_2 "DSA-old" +#define LN_dsa_2 "dsaEncryption-old" +#define NID_dsa_2 67 +#define OBJ_dsa_2 OBJ_algorithm,12L + +#define SN_dsaWithSHA "DSA-SHA" +#define LN_dsaWithSHA "dsaWithSHA" +#define NID_dsaWithSHA 66 +#define OBJ_dsaWithSHA OBJ_algorithm,13L + +#define SN_shaWithRSAEncryption "RSA-SHA" +#define LN_shaWithRSAEncryption "shaWithRSAEncryption" +#define NID_shaWithRSAEncryption 42 +#define OBJ_shaWithRSAEncryption OBJ_algorithm,15L + +#define SN_des_ede_ecb "DES-EDE" +#define LN_des_ede_ecb "des-ede" +#define NID_des_ede_ecb 32 +#define OBJ_des_ede_ecb OBJ_algorithm,17L + +#define SN_des_ede3_ecb "DES-EDE3" +#define LN_des_ede3_ecb "des-ede3" +#define NID_des_ede3_ecb 33 + +#define SN_des_ede_cbc "DES-EDE-CBC" +#define LN_des_ede_cbc "des-ede-cbc" +#define NID_des_ede_cbc 43 + +#define SN_des_ede_cfb64 "DES-EDE-CFB" +#define LN_des_ede_cfb64 "des-ede-cfb" +#define NID_des_ede_cfb64 60 + +#define SN_des_ede3_cfb64 "DES-EDE3-CFB" +#define LN_des_ede3_cfb64 "des-ede3-cfb" +#define NID_des_ede3_cfb64 61 + +#define SN_des_ede_ofb64 "DES-EDE-OFB" +#define LN_des_ede_ofb64 "des-ede-ofb" +#define NID_des_ede_ofb64 62 + +#define SN_des_ede3_ofb64 "DES-EDE3-OFB" +#define LN_des_ede3_ofb64 "des-ede3-ofb" +#define NID_des_ede3_ofb64 63 + +#define SN_desx_cbc "DESX-CBC" +#define LN_desx_cbc "desx-cbc" +#define NID_desx_cbc 80 + +#define SN_sha "SHA" +#define LN_sha "sha" +#define NID_sha 41 +#define OBJ_sha OBJ_algorithm,18L + +#define SN_sha1 "SHA1" +#define LN_sha1 "sha1" +#define NID_sha1 64 +#define OBJ_sha1 OBJ_algorithm,26L + +#define SN_dsaWithSHA1_2 "DSA-SHA1-old" +#define LN_dsaWithSHA1_2 "dsaWithSHA1-old" +#define NID_dsaWithSHA1_2 70 +#define OBJ_dsaWithSHA1_2 OBJ_algorithm,27L + +#define SN_sha1WithRSA "RSA-SHA1-2" +#define LN_sha1WithRSA "sha1WithRSA" +#define NID_sha1WithRSA 115 +#define OBJ_sha1WithRSA OBJ_algorithm,29L + +#define SN_ripemd160 "RIPEMD160" +#define LN_ripemd160 "ripemd160" +#define NID_ripemd160 117 +#define OBJ_ripemd160 1L,3L,36L,3L,2L,1L + +#define SN_ripemd160WithRSA "RSA-RIPEMD160" +#define LN_ripemd160WithRSA "ripemd160WithRSA" +#define NID_ripemd160WithRSA 119 +#define OBJ_ripemd160WithRSA 1L,3L,36L,3L,3L,1L,2L + +#define SN_sxnet "SXNetID" +#define LN_sxnet "Strong Extranet ID" +#define NID_sxnet 143 +#define OBJ_sxnet 1L,3L,101L,1L,4L,1L + +#define SN_X500 "X500" +#define LN_X500 "directory services (X.500)" +#define NID_X500 11 +#define OBJ_X500 2L,5L + +#define SN_X509 "X509" +#define NID_X509 12 +#define OBJ_X509 OBJ_X500,4L + +#define SN_commonName "CN" +#define LN_commonName "commonName" +#define NID_commonName 13 +#define OBJ_commonName OBJ_X509,3L + +#define SN_surname "SN" +#define LN_surname "surname" +#define NID_surname 100 +#define OBJ_surname OBJ_X509,4L + +#define LN_serialNumber "serialNumber" +#define NID_serialNumber 105 +#define OBJ_serialNumber OBJ_X509,5L + +#define SN_countryName "C" +#define LN_countryName "countryName" +#define NID_countryName 14 +#define OBJ_countryName OBJ_X509,6L + +#define SN_localityName "L" +#define LN_localityName "localityName" +#define NID_localityName 15 +#define OBJ_localityName OBJ_X509,7L + +#define SN_stateOrProvinceName "ST" +#define LN_stateOrProvinceName "stateOrProvinceName" +#define NID_stateOrProvinceName 16 +#define OBJ_stateOrProvinceName OBJ_X509,8L + +#define LN_streetAddress "streetAddress" +#define NID_streetAddress 660 +#define OBJ_streetAddress OBJ_X509,9L + +#define SN_organizationName "O" +#define LN_organizationName "organizationName" +#define NID_organizationName 17 +#define OBJ_organizationName OBJ_X509,10L + +#define SN_organizationalUnitName "OU" +#define LN_organizationalUnitName "organizationalUnitName" +#define NID_organizationalUnitName 18 +#define OBJ_organizationalUnitName OBJ_X509,11L + +#define LN_title "title" +#define NID_title 106 +#define OBJ_title OBJ_X509,12L + +#define LN_description "description" +#define NID_description 107 +#define OBJ_description OBJ_X509,13L + +#define LN_postalCode "postalCode" +#define NID_postalCode 661 +#define OBJ_postalCode OBJ_X509,17L + +#define SN_name "name" +#define LN_name "name" +#define NID_name 173 +#define OBJ_name OBJ_X509,41L + +#define SN_givenName "GN" +#define LN_givenName "givenName" +#define NID_givenName 99 +#define OBJ_givenName OBJ_X509,42L + +#define LN_initials "initials" +#define NID_initials 101 +#define OBJ_initials OBJ_X509,43L + +#define LN_generationQualifier "generationQualifier" +#define NID_generationQualifier 509 +#define OBJ_generationQualifier OBJ_X509,44L + +#define LN_x500UniqueIdentifier "x500UniqueIdentifier" +#define NID_x500UniqueIdentifier 503 +#define OBJ_x500UniqueIdentifier OBJ_X509,45L + +#define SN_dnQualifier "dnQualifier" +#define LN_dnQualifier "dnQualifier" +#define NID_dnQualifier 174 +#define OBJ_dnQualifier OBJ_X509,46L + +#define LN_pseudonym "pseudonym" +#define NID_pseudonym 510 +#define OBJ_pseudonym OBJ_X509,65L + +#define SN_role "role" +#define LN_role "role" +#define NID_role 400 +#define OBJ_role OBJ_X509,72L + +#define SN_X500algorithms "X500algorithms" +#define LN_X500algorithms "directory services - algorithms" +#define NID_X500algorithms 378 +#define OBJ_X500algorithms OBJ_X500,8L + +#define SN_rsa "RSA" +#define LN_rsa "rsa" +#define NID_rsa 19 +#define OBJ_rsa OBJ_X500algorithms,1L,1L + +#define SN_mdc2WithRSA "RSA-MDC2" +#define LN_mdc2WithRSA "mdc2WithRSA" +#define NID_mdc2WithRSA 96 +#define OBJ_mdc2WithRSA OBJ_X500algorithms,3L,100L + +#define SN_mdc2 "MDC2" +#define LN_mdc2 "mdc2" +#define NID_mdc2 95 +#define OBJ_mdc2 OBJ_X500algorithms,3L,101L + +#define SN_id_ce "id-ce" +#define NID_id_ce 81 +#define OBJ_id_ce OBJ_X500,29L + +#define SN_subject_directory_attributes "subjectDirectoryAttributes" +#define LN_subject_directory_attributes "X509v3 Subject Directory Attributes" +#define NID_subject_directory_attributes 769 +#define OBJ_subject_directory_attributes OBJ_id_ce,9L + +#define SN_subject_key_identifier "subjectKeyIdentifier" +#define LN_subject_key_identifier "X509v3 Subject Key Identifier" +#define NID_subject_key_identifier 82 +#define OBJ_subject_key_identifier OBJ_id_ce,14L + +#define SN_key_usage "keyUsage" +#define LN_key_usage "X509v3 Key Usage" +#define NID_key_usage 83 +#define OBJ_key_usage OBJ_id_ce,15L + +#define SN_private_key_usage_period "privateKeyUsagePeriod" +#define LN_private_key_usage_period "X509v3 Private Key Usage Period" +#define NID_private_key_usage_period 84 +#define OBJ_private_key_usage_period OBJ_id_ce,16L + +#define SN_subject_alt_name "subjectAltName" +#define LN_subject_alt_name "X509v3 Subject Alternative Name" +#define NID_subject_alt_name 85 +#define OBJ_subject_alt_name OBJ_id_ce,17L + +#define SN_issuer_alt_name "issuerAltName" +#define LN_issuer_alt_name "X509v3 Issuer Alternative Name" +#define NID_issuer_alt_name 86 +#define OBJ_issuer_alt_name OBJ_id_ce,18L + +#define SN_basic_constraints "basicConstraints" +#define LN_basic_constraints "X509v3 Basic Constraints" +#define NID_basic_constraints 87 +#define OBJ_basic_constraints OBJ_id_ce,19L + +#define SN_crl_number "crlNumber" +#define LN_crl_number "X509v3 CRL Number" +#define NID_crl_number 88 +#define OBJ_crl_number OBJ_id_ce,20L + +#define SN_crl_reason "CRLReason" +#define LN_crl_reason "X509v3 CRL Reason Code" +#define NID_crl_reason 141 +#define OBJ_crl_reason OBJ_id_ce,21L + +#define SN_invalidity_date "invalidityDate" +#define LN_invalidity_date "Invalidity Date" +#define NID_invalidity_date 142 +#define OBJ_invalidity_date OBJ_id_ce,24L + +#define SN_delta_crl "deltaCRL" +#define LN_delta_crl "X509v3 Delta CRL Indicator" +#define NID_delta_crl 140 +#define OBJ_delta_crl OBJ_id_ce,27L + +#define SN_issuing_distribution_point "issuingDistributionPoint" +#define LN_issuing_distribution_point "X509v3 Issuing Distrubution Point" +#define NID_issuing_distribution_point 770 +#define OBJ_issuing_distribution_point OBJ_id_ce,28L + +#define SN_certificate_issuer "certificateIssuer" +#define LN_certificate_issuer "X509v3 Certificate Issuer" +#define NID_certificate_issuer 771 +#define OBJ_certificate_issuer OBJ_id_ce,29L + +#define SN_name_constraints "nameConstraints" +#define LN_name_constraints "X509v3 Name Constraints" +#define NID_name_constraints 666 +#define OBJ_name_constraints OBJ_id_ce,30L + +#define SN_crl_distribution_points "crlDistributionPoints" +#define LN_crl_distribution_points "X509v3 CRL Distribution Points" +#define NID_crl_distribution_points 103 +#define OBJ_crl_distribution_points OBJ_id_ce,31L + +#define SN_certificate_policies "certificatePolicies" +#define LN_certificate_policies "X509v3 Certificate Policies" +#define NID_certificate_policies 89 +#define OBJ_certificate_policies OBJ_id_ce,32L + +#define SN_any_policy "anyPolicy" +#define LN_any_policy "X509v3 Any Policy" +#define NID_any_policy 746 +#define OBJ_any_policy OBJ_certificate_policies,0L + +#define SN_policy_mappings "policyMappings" +#define LN_policy_mappings "X509v3 Policy Mappings" +#define NID_policy_mappings 747 +#define OBJ_policy_mappings OBJ_id_ce,33L + +#define SN_authority_key_identifier "authorityKeyIdentifier" +#define LN_authority_key_identifier "X509v3 Authority Key Identifier" +#define NID_authority_key_identifier 90 +#define OBJ_authority_key_identifier OBJ_id_ce,35L + +#define SN_policy_constraints "policyConstraints" +#define LN_policy_constraints "X509v3 Policy Constraints" +#define NID_policy_constraints 401 +#define OBJ_policy_constraints OBJ_id_ce,36L + +#define SN_ext_key_usage "extendedKeyUsage" +#define LN_ext_key_usage "X509v3 Extended Key Usage" +#define NID_ext_key_usage 126 +#define OBJ_ext_key_usage OBJ_id_ce,37L + +#define SN_inhibit_any_policy "inhibitAnyPolicy" +#define LN_inhibit_any_policy "X509v3 Inhibit Any Policy" +#define NID_inhibit_any_policy 748 +#define OBJ_inhibit_any_policy OBJ_id_ce,54L + +#define SN_target_information "targetInformation" +#define LN_target_information "X509v3 AC Targeting" +#define NID_target_information 402 +#define OBJ_target_information OBJ_id_ce,55L + +#define SN_no_rev_avail "noRevAvail" +#define LN_no_rev_avail "X509v3 No Revocation Available" +#define NID_no_rev_avail 403 +#define OBJ_no_rev_avail OBJ_id_ce,56L + +#define SN_netscape "Netscape" +#define LN_netscape "Netscape Communications Corp." +#define NID_netscape 57 +#define OBJ_netscape 2L,16L,840L,1L,113730L + +#define SN_netscape_cert_extension "nsCertExt" +#define LN_netscape_cert_extension "Netscape Certificate Extension" +#define NID_netscape_cert_extension 58 +#define OBJ_netscape_cert_extension OBJ_netscape,1L + +#define SN_netscape_data_type "nsDataType" +#define LN_netscape_data_type "Netscape Data Type" +#define NID_netscape_data_type 59 +#define OBJ_netscape_data_type OBJ_netscape,2L + +#define SN_netscape_cert_type "nsCertType" +#define LN_netscape_cert_type "Netscape Cert Type" +#define NID_netscape_cert_type 71 +#define OBJ_netscape_cert_type OBJ_netscape_cert_extension,1L + +#define SN_netscape_base_url "nsBaseUrl" +#define LN_netscape_base_url "Netscape Base Url" +#define NID_netscape_base_url 72 +#define OBJ_netscape_base_url OBJ_netscape_cert_extension,2L + +#define SN_netscape_revocation_url "nsRevocationUrl" +#define LN_netscape_revocation_url "Netscape Revocation Url" +#define NID_netscape_revocation_url 73 +#define OBJ_netscape_revocation_url OBJ_netscape_cert_extension,3L + +#define SN_netscape_ca_revocation_url "nsCaRevocationUrl" +#define LN_netscape_ca_revocation_url "Netscape CA Revocation Url" +#define NID_netscape_ca_revocation_url 74 +#define OBJ_netscape_ca_revocation_url OBJ_netscape_cert_extension,4L + +#define SN_netscape_renewal_url "nsRenewalUrl" +#define LN_netscape_renewal_url "Netscape Renewal Url" +#define NID_netscape_renewal_url 75 +#define OBJ_netscape_renewal_url OBJ_netscape_cert_extension,7L + +#define SN_netscape_ca_policy_url "nsCaPolicyUrl" +#define LN_netscape_ca_policy_url "Netscape CA Policy Url" +#define NID_netscape_ca_policy_url 76 +#define OBJ_netscape_ca_policy_url OBJ_netscape_cert_extension,8L + +#define SN_netscape_ssl_server_name "nsSslServerName" +#define LN_netscape_ssl_server_name "Netscape SSL Server Name" +#define NID_netscape_ssl_server_name 77 +#define OBJ_netscape_ssl_server_name OBJ_netscape_cert_extension,12L + +#define SN_netscape_comment "nsComment" +#define LN_netscape_comment "Netscape Comment" +#define NID_netscape_comment 78 +#define OBJ_netscape_comment OBJ_netscape_cert_extension,13L + +#define SN_netscape_cert_sequence "nsCertSequence" +#define LN_netscape_cert_sequence "Netscape Certificate Sequence" +#define NID_netscape_cert_sequence 79 +#define OBJ_netscape_cert_sequence OBJ_netscape_data_type,5L + +#define SN_ns_sgc "nsSGC" +#define LN_ns_sgc "Netscape Server Gated Crypto" +#define NID_ns_sgc 139 +#define OBJ_ns_sgc OBJ_netscape,4L,1L + +#define SN_org "ORG" +#define LN_org "org" +#define NID_org 379 +#define OBJ_org OBJ_iso,3L + +#define SN_dod "DOD" +#define LN_dod "dod" +#define NID_dod 380 +#define OBJ_dod OBJ_org,6L + +#define SN_iana "IANA" +#define LN_iana "iana" +#define NID_iana 381 +#define OBJ_iana OBJ_dod,1L + +#define OBJ_internet OBJ_iana + +#define SN_Directory "directory" +#define LN_Directory "Directory" +#define NID_Directory 382 +#define OBJ_Directory OBJ_internet,1L + +#define SN_Management "mgmt" +#define LN_Management "Management" +#define NID_Management 383 +#define OBJ_Management OBJ_internet,2L + +#define SN_Experimental "experimental" +#define LN_Experimental "Experimental" +#define NID_Experimental 384 +#define OBJ_Experimental OBJ_internet,3L + +#define SN_Private "private" +#define LN_Private "Private" +#define NID_Private 385 +#define OBJ_Private OBJ_internet,4L + +#define SN_Security "security" +#define LN_Security "Security" +#define NID_Security 386 +#define OBJ_Security OBJ_internet,5L + +#define SN_SNMPv2 "snmpv2" +#define LN_SNMPv2 "SNMPv2" +#define NID_SNMPv2 387 +#define OBJ_SNMPv2 OBJ_internet,6L + +#define LN_Mail "Mail" +#define NID_Mail 388 +#define OBJ_Mail OBJ_internet,7L + +#define SN_Enterprises "enterprises" +#define LN_Enterprises "Enterprises" +#define NID_Enterprises 389 +#define OBJ_Enterprises OBJ_Private,1L + +#define SN_dcObject "dcobject" +#define LN_dcObject "dcObject" +#define NID_dcObject 390 +#define OBJ_dcObject OBJ_Enterprises,1466L,344L + +#define SN_mime_mhs "mime-mhs" +#define LN_mime_mhs "MIME MHS" +#define NID_mime_mhs 504 +#define OBJ_mime_mhs OBJ_Mail,1L + +#define SN_mime_mhs_headings "mime-mhs-headings" +#define LN_mime_mhs_headings "mime-mhs-headings" +#define NID_mime_mhs_headings 505 +#define OBJ_mime_mhs_headings OBJ_mime_mhs,1L + +#define SN_mime_mhs_bodies "mime-mhs-bodies" +#define LN_mime_mhs_bodies "mime-mhs-bodies" +#define NID_mime_mhs_bodies 506 +#define OBJ_mime_mhs_bodies OBJ_mime_mhs,2L + +#define SN_id_hex_partial_message "id-hex-partial-message" +#define LN_id_hex_partial_message "id-hex-partial-message" +#define NID_id_hex_partial_message 507 +#define OBJ_id_hex_partial_message OBJ_mime_mhs_headings,1L + +#define SN_id_hex_multipart_message "id-hex-multipart-message" +#define LN_id_hex_multipart_message "id-hex-multipart-message" +#define NID_id_hex_multipart_message 508 +#define OBJ_id_hex_multipart_message OBJ_mime_mhs_headings,2L + +#define SN_rle_compression "RLE" +#define LN_rle_compression "run length compression" +#define NID_rle_compression 124 +#define OBJ_rle_compression 1L,1L,1L,1L,666L,1L + +#define SN_zlib_compression "ZLIB" +#define LN_zlib_compression "zlib compression" +#define NID_zlib_compression 125 +#define OBJ_zlib_compression OBJ_id_smime_alg,8L + +#define OBJ_csor 2L,16L,840L,1L,101L,3L + +#define OBJ_nistAlgorithms OBJ_csor,4L + +#define OBJ_aes OBJ_nistAlgorithms,1L + +#define SN_aes_128_ecb "AES-128-ECB" +#define LN_aes_128_ecb "aes-128-ecb" +#define NID_aes_128_ecb 418 +#define OBJ_aes_128_ecb OBJ_aes,1L + +#define SN_aes_128_cbc "AES-128-CBC" +#define LN_aes_128_cbc "aes-128-cbc" +#define NID_aes_128_cbc 419 +#define OBJ_aes_128_cbc OBJ_aes,2L + +#define SN_aes_128_ofb128 "AES-128-OFB" +#define LN_aes_128_ofb128 "aes-128-ofb" +#define NID_aes_128_ofb128 420 +#define OBJ_aes_128_ofb128 OBJ_aes,3L + +#define SN_aes_128_cfb128 "AES-128-CFB" +#define LN_aes_128_cfb128 "aes-128-cfb" +#define NID_aes_128_cfb128 421 +#define OBJ_aes_128_cfb128 OBJ_aes,4L + +#define SN_aes_192_ecb "AES-192-ECB" +#define LN_aes_192_ecb "aes-192-ecb" +#define NID_aes_192_ecb 422 +#define OBJ_aes_192_ecb OBJ_aes,21L + +#define SN_aes_192_cbc "AES-192-CBC" +#define LN_aes_192_cbc "aes-192-cbc" +#define NID_aes_192_cbc 423 +#define OBJ_aes_192_cbc OBJ_aes,22L + +#define SN_aes_192_ofb128 "AES-192-OFB" +#define LN_aes_192_ofb128 "aes-192-ofb" +#define NID_aes_192_ofb128 424 +#define OBJ_aes_192_ofb128 OBJ_aes,23L + +#define SN_aes_192_cfb128 "AES-192-CFB" +#define LN_aes_192_cfb128 "aes-192-cfb" +#define NID_aes_192_cfb128 425 +#define OBJ_aes_192_cfb128 OBJ_aes,24L + +#define SN_aes_256_ecb "AES-256-ECB" +#define LN_aes_256_ecb "aes-256-ecb" +#define NID_aes_256_ecb 426 +#define OBJ_aes_256_ecb OBJ_aes,41L + +#define SN_aes_256_cbc "AES-256-CBC" +#define LN_aes_256_cbc "aes-256-cbc" +#define NID_aes_256_cbc 427 +#define OBJ_aes_256_cbc OBJ_aes,42L + +#define SN_aes_256_ofb128 "AES-256-OFB" +#define LN_aes_256_ofb128 "aes-256-ofb" +#define NID_aes_256_ofb128 428 +#define OBJ_aes_256_ofb128 OBJ_aes,43L + +#define SN_aes_256_cfb128 "AES-256-CFB" +#define LN_aes_256_cfb128 "aes-256-cfb" +#define NID_aes_256_cfb128 429 +#define OBJ_aes_256_cfb128 OBJ_aes,44L + +#define SN_aes_128_cfb1 "AES-128-CFB1" +#define LN_aes_128_cfb1 "aes-128-cfb1" +#define NID_aes_128_cfb1 650 + +#define SN_aes_192_cfb1 "AES-192-CFB1" +#define LN_aes_192_cfb1 "aes-192-cfb1" +#define NID_aes_192_cfb1 651 + +#define SN_aes_256_cfb1 "AES-256-CFB1" +#define LN_aes_256_cfb1 "aes-256-cfb1" +#define NID_aes_256_cfb1 652 + +#define SN_aes_128_cfb8 "AES-128-CFB8" +#define LN_aes_128_cfb8 "aes-128-cfb8" +#define NID_aes_128_cfb8 653 + +#define SN_aes_192_cfb8 "AES-192-CFB8" +#define LN_aes_192_cfb8 "aes-192-cfb8" +#define NID_aes_192_cfb8 654 + +#define SN_aes_256_cfb8 "AES-256-CFB8" +#define LN_aes_256_cfb8 "aes-256-cfb8" +#define NID_aes_256_cfb8 655 + +#define SN_des_cfb1 "DES-CFB1" +#define LN_des_cfb1 "des-cfb1" +#define NID_des_cfb1 656 + +#define SN_des_cfb8 "DES-CFB8" +#define LN_des_cfb8 "des-cfb8" +#define NID_des_cfb8 657 + +#define SN_des_ede3_cfb1 "DES-EDE3-CFB1" +#define LN_des_ede3_cfb1 "des-ede3-cfb1" +#define NID_des_ede3_cfb1 658 + +#define SN_des_ede3_cfb8 "DES-EDE3-CFB8" +#define LN_des_ede3_cfb8 "des-ede3-cfb8" +#define NID_des_ede3_cfb8 659 + +#define SN_id_aes128_wrap "id-aes128-wrap" +#define NID_id_aes128_wrap 788 +#define OBJ_id_aes128_wrap OBJ_aes,5L + +#define SN_id_aes192_wrap "id-aes192-wrap" +#define NID_id_aes192_wrap 789 +#define OBJ_id_aes192_wrap OBJ_aes,25L + +#define SN_id_aes256_wrap "id-aes256-wrap" +#define NID_id_aes256_wrap 790 +#define OBJ_id_aes256_wrap OBJ_aes,45L + +#define OBJ_nist_hashalgs OBJ_nistAlgorithms,2L + +#define SN_sha256 "SHA256" +#define LN_sha256 "sha256" +#define NID_sha256 672 +#define OBJ_sha256 OBJ_nist_hashalgs,1L + +#define SN_sha384 "SHA384" +#define LN_sha384 "sha384" +#define NID_sha384 673 +#define OBJ_sha384 OBJ_nist_hashalgs,2L + +#define SN_sha512 "SHA512" +#define LN_sha512 "sha512" +#define NID_sha512 674 +#define OBJ_sha512 OBJ_nist_hashalgs,3L + +#define SN_sha224 "SHA224" +#define LN_sha224 "sha224" +#define NID_sha224 675 +#define OBJ_sha224 OBJ_nist_hashalgs,4L + +#define SN_hold_instruction_code "holdInstructionCode" +#define LN_hold_instruction_code "Hold Instruction Code" +#define NID_hold_instruction_code 430 +#define OBJ_hold_instruction_code OBJ_id_ce,23L + +#define OBJ_holdInstruction OBJ_X9_57,2L + +#define SN_hold_instruction_none "holdInstructionNone" +#define LN_hold_instruction_none "Hold Instruction None" +#define NID_hold_instruction_none 431 +#define OBJ_hold_instruction_none OBJ_holdInstruction,1L + +#define SN_hold_instruction_call_issuer "holdInstructionCallIssuer" +#define LN_hold_instruction_call_issuer "Hold Instruction Call Issuer" +#define NID_hold_instruction_call_issuer 432 +#define OBJ_hold_instruction_call_issuer OBJ_holdInstruction,2L + +#define SN_hold_instruction_reject "holdInstructionReject" +#define LN_hold_instruction_reject "Hold Instruction Reject" +#define NID_hold_instruction_reject 433 +#define OBJ_hold_instruction_reject OBJ_holdInstruction,3L + +#define SN_data "data" +#define NID_data 434 +#define OBJ_data OBJ_itu_t,9L + +#define SN_pss "pss" +#define NID_pss 435 +#define OBJ_pss OBJ_data,2342L + +#define SN_ucl "ucl" +#define NID_ucl 436 +#define OBJ_ucl OBJ_pss,19200300L + +#define SN_pilot "pilot" +#define NID_pilot 437 +#define OBJ_pilot OBJ_ucl,100L + +#define LN_pilotAttributeType "pilotAttributeType" +#define NID_pilotAttributeType 438 +#define OBJ_pilotAttributeType OBJ_pilot,1L + +#define LN_pilotAttributeSyntax "pilotAttributeSyntax" +#define NID_pilotAttributeSyntax 439 +#define OBJ_pilotAttributeSyntax OBJ_pilot,3L + +#define LN_pilotObjectClass "pilotObjectClass" +#define NID_pilotObjectClass 440 +#define OBJ_pilotObjectClass OBJ_pilot,4L + +#define LN_pilotGroups "pilotGroups" +#define NID_pilotGroups 441 +#define OBJ_pilotGroups OBJ_pilot,10L + +#define LN_iA5StringSyntax "iA5StringSyntax" +#define NID_iA5StringSyntax 442 +#define OBJ_iA5StringSyntax OBJ_pilotAttributeSyntax,4L + +#define LN_caseIgnoreIA5StringSyntax "caseIgnoreIA5StringSyntax" +#define NID_caseIgnoreIA5StringSyntax 443 +#define OBJ_caseIgnoreIA5StringSyntax OBJ_pilotAttributeSyntax,5L + +#define LN_pilotObject "pilotObject" +#define NID_pilotObject 444 +#define OBJ_pilotObject OBJ_pilotObjectClass,3L + +#define LN_pilotPerson "pilotPerson" +#define NID_pilotPerson 445 +#define OBJ_pilotPerson OBJ_pilotObjectClass,4L + +#define SN_account "account" +#define NID_account 446 +#define OBJ_account OBJ_pilotObjectClass,5L + +#define SN_document "document" +#define NID_document 447 +#define OBJ_document OBJ_pilotObjectClass,6L + +#define SN_room "room" +#define NID_room 448 +#define OBJ_room OBJ_pilotObjectClass,7L + +#define LN_documentSeries "documentSeries" +#define NID_documentSeries 449 +#define OBJ_documentSeries OBJ_pilotObjectClass,9L + +#define SN_Domain "domain" +#define LN_Domain "Domain" +#define NID_Domain 392 +#define OBJ_Domain OBJ_pilotObjectClass,13L + +#define LN_rFC822localPart "rFC822localPart" +#define NID_rFC822localPart 450 +#define OBJ_rFC822localPart OBJ_pilotObjectClass,14L + +#define LN_dNSDomain "dNSDomain" +#define NID_dNSDomain 451 +#define OBJ_dNSDomain OBJ_pilotObjectClass,15L + +#define LN_domainRelatedObject "domainRelatedObject" +#define NID_domainRelatedObject 452 +#define OBJ_domainRelatedObject OBJ_pilotObjectClass,17L + +#define LN_friendlyCountry "friendlyCountry" +#define NID_friendlyCountry 453 +#define OBJ_friendlyCountry OBJ_pilotObjectClass,18L + +#define LN_simpleSecurityObject "simpleSecurityObject" +#define NID_simpleSecurityObject 454 +#define OBJ_simpleSecurityObject OBJ_pilotObjectClass,19L + +#define LN_pilotOrganization "pilotOrganization" +#define NID_pilotOrganization 455 +#define OBJ_pilotOrganization OBJ_pilotObjectClass,20L + +#define LN_pilotDSA "pilotDSA" +#define NID_pilotDSA 456 +#define OBJ_pilotDSA OBJ_pilotObjectClass,21L + +#define LN_qualityLabelledData "qualityLabelledData" +#define NID_qualityLabelledData 457 +#define OBJ_qualityLabelledData OBJ_pilotObjectClass,22L + +#define SN_userId "UID" +#define LN_userId "userId" +#define NID_userId 458 +#define OBJ_userId OBJ_pilotAttributeType,1L + +#define LN_textEncodedORAddress "textEncodedORAddress" +#define NID_textEncodedORAddress 459 +#define OBJ_textEncodedORAddress OBJ_pilotAttributeType,2L + +#define SN_rfc822Mailbox "mail" +#define LN_rfc822Mailbox "rfc822Mailbox" +#define NID_rfc822Mailbox 460 +#define OBJ_rfc822Mailbox OBJ_pilotAttributeType,3L + +#define SN_info "info" +#define NID_info 461 +#define OBJ_info OBJ_pilotAttributeType,4L + +#define LN_favouriteDrink "favouriteDrink" +#define NID_favouriteDrink 462 +#define OBJ_favouriteDrink OBJ_pilotAttributeType,5L + +#define LN_roomNumber "roomNumber" +#define NID_roomNumber 463 +#define OBJ_roomNumber OBJ_pilotAttributeType,6L + +#define SN_photo "photo" +#define NID_photo 464 +#define OBJ_photo OBJ_pilotAttributeType,7L + +#define LN_userClass "userClass" +#define NID_userClass 465 +#define OBJ_userClass OBJ_pilotAttributeType,8L + +#define SN_host "host" +#define NID_host 466 +#define OBJ_host OBJ_pilotAttributeType,9L + +#define SN_manager "manager" +#define NID_manager 467 +#define OBJ_manager OBJ_pilotAttributeType,10L + +#define LN_documentIdentifier "documentIdentifier" +#define NID_documentIdentifier 468 +#define OBJ_documentIdentifier OBJ_pilotAttributeType,11L + +#define LN_documentTitle "documentTitle" +#define NID_documentTitle 469 +#define OBJ_documentTitle OBJ_pilotAttributeType,12L + +#define LN_documentVersion "documentVersion" +#define NID_documentVersion 470 +#define OBJ_documentVersion OBJ_pilotAttributeType,13L + +#define LN_documentAuthor "documentAuthor" +#define NID_documentAuthor 471 +#define OBJ_documentAuthor OBJ_pilotAttributeType,14L + +#define LN_documentLocation "documentLocation" +#define NID_documentLocation 472 +#define OBJ_documentLocation OBJ_pilotAttributeType,15L + +#define LN_homeTelephoneNumber "homeTelephoneNumber" +#define NID_homeTelephoneNumber 473 +#define OBJ_homeTelephoneNumber OBJ_pilotAttributeType,20L + +#define SN_secretary "secretary" +#define NID_secretary 474 +#define OBJ_secretary OBJ_pilotAttributeType,21L + +#define LN_otherMailbox "otherMailbox" +#define NID_otherMailbox 475 +#define OBJ_otherMailbox OBJ_pilotAttributeType,22L + +#define LN_lastModifiedTime "lastModifiedTime" +#define NID_lastModifiedTime 476 +#define OBJ_lastModifiedTime OBJ_pilotAttributeType,23L + +#define LN_lastModifiedBy "lastModifiedBy" +#define NID_lastModifiedBy 477 +#define OBJ_lastModifiedBy OBJ_pilotAttributeType,24L + +#define SN_domainComponent "DC" +#define LN_domainComponent "domainComponent" +#define NID_domainComponent 391 +#define OBJ_domainComponent OBJ_pilotAttributeType,25L + +#define LN_aRecord "aRecord" +#define NID_aRecord 478 +#define OBJ_aRecord OBJ_pilotAttributeType,26L + +#define LN_pilotAttributeType27 "pilotAttributeType27" +#define NID_pilotAttributeType27 479 +#define OBJ_pilotAttributeType27 OBJ_pilotAttributeType,27L + +#define LN_mXRecord "mXRecord" +#define NID_mXRecord 480 +#define OBJ_mXRecord OBJ_pilotAttributeType,28L + +#define LN_nSRecord "nSRecord" +#define NID_nSRecord 481 +#define OBJ_nSRecord OBJ_pilotAttributeType,29L + +#define LN_sOARecord "sOARecord" +#define NID_sOARecord 482 +#define OBJ_sOARecord OBJ_pilotAttributeType,30L + +#define LN_cNAMERecord "cNAMERecord" +#define NID_cNAMERecord 483 +#define OBJ_cNAMERecord OBJ_pilotAttributeType,31L + +#define LN_associatedDomain "associatedDomain" +#define NID_associatedDomain 484 +#define OBJ_associatedDomain OBJ_pilotAttributeType,37L + +#define LN_associatedName "associatedName" +#define NID_associatedName 485 +#define OBJ_associatedName OBJ_pilotAttributeType,38L + +#define LN_homePostalAddress "homePostalAddress" +#define NID_homePostalAddress 486 +#define OBJ_homePostalAddress OBJ_pilotAttributeType,39L + +#define LN_personalTitle "personalTitle" +#define NID_personalTitle 487 +#define OBJ_personalTitle OBJ_pilotAttributeType,40L + +#define LN_mobileTelephoneNumber "mobileTelephoneNumber" +#define NID_mobileTelephoneNumber 488 +#define OBJ_mobileTelephoneNumber OBJ_pilotAttributeType,41L + +#define LN_pagerTelephoneNumber "pagerTelephoneNumber" +#define NID_pagerTelephoneNumber 489 +#define OBJ_pagerTelephoneNumber OBJ_pilotAttributeType,42L + +#define LN_friendlyCountryName "friendlyCountryName" +#define NID_friendlyCountryName 490 +#define OBJ_friendlyCountryName OBJ_pilotAttributeType,43L + +#define LN_organizationalStatus "organizationalStatus" +#define NID_organizationalStatus 491 +#define OBJ_organizationalStatus OBJ_pilotAttributeType,45L + +#define LN_janetMailbox "janetMailbox" +#define NID_janetMailbox 492 +#define OBJ_janetMailbox OBJ_pilotAttributeType,46L + +#define LN_mailPreferenceOption "mailPreferenceOption" +#define NID_mailPreferenceOption 493 +#define OBJ_mailPreferenceOption OBJ_pilotAttributeType,47L + +#define LN_buildingName "buildingName" +#define NID_buildingName 494 +#define OBJ_buildingName OBJ_pilotAttributeType,48L + +#define LN_dSAQuality "dSAQuality" +#define NID_dSAQuality 495 +#define OBJ_dSAQuality OBJ_pilotAttributeType,49L + +#define LN_singleLevelQuality "singleLevelQuality" +#define NID_singleLevelQuality 496 +#define OBJ_singleLevelQuality OBJ_pilotAttributeType,50L + +#define LN_subtreeMinimumQuality "subtreeMinimumQuality" +#define NID_subtreeMinimumQuality 497 +#define OBJ_subtreeMinimumQuality OBJ_pilotAttributeType,51L + +#define LN_subtreeMaximumQuality "subtreeMaximumQuality" +#define NID_subtreeMaximumQuality 498 +#define OBJ_subtreeMaximumQuality OBJ_pilotAttributeType,52L + +#define LN_personalSignature "personalSignature" +#define NID_personalSignature 499 +#define OBJ_personalSignature OBJ_pilotAttributeType,53L + +#define LN_dITRedirect "dITRedirect" +#define NID_dITRedirect 500 +#define OBJ_dITRedirect OBJ_pilotAttributeType,54L + +#define SN_audio "audio" +#define NID_audio 501 +#define OBJ_audio OBJ_pilotAttributeType,55L + +#define LN_documentPublisher "documentPublisher" +#define NID_documentPublisher 502 +#define OBJ_documentPublisher OBJ_pilotAttributeType,56L + +#define SN_id_set "id-set" +#define LN_id_set "Secure Electronic Transactions" +#define NID_id_set 512 +#define OBJ_id_set OBJ_international_organizations,42L + +#define SN_set_ctype "set-ctype" +#define LN_set_ctype "content types" +#define NID_set_ctype 513 +#define OBJ_set_ctype OBJ_id_set,0L + +#define SN_set_msgExt "set-msgExt" +#define LN_set_msgExt "message extensions" +#define NID_set_msgExt 514 +#define OBJ_set_msgExt OBJ_id_set,1L + +#define SN_set_attr "set-attr" +#define NID_set_attr 515 +#define OBJ_set_attr OBJ_id_set,3L + +#define SN_set_policy "set-policy" +#define NID_set_policy 516 +#define OBJ_set_policy OBJ_id_set,5L + +#define SN_set_certExt "set-certExt" +#define LN_set_certExt "certificate extensions" +#define NID_set_certExt 517 +#define OBJ_set_certExt OBJ_id_set,7L + +#define SN_set_brand "set-brand" +#define NID_set_brand 518 +#define OBJ_set_brand OBJ_id_set,8L + +#define SN_setct_PANData "setct-PANData" +#define NID_setct_PANData 519 +#define OBJ_setct_PANData OBJ_set_ctype,0L + +#define SN_setct_PANToken "setct-PANToken" +#define NID_setct_PANToken 520 +#define OBJ_setct_PANToken OBJ_set_ctype,1L + +#define SN_setct_PANOnly "setct-PANOnly" +#define NID_setct_PANOnly 521 +#define OBJ_setct_PANOnly OBJ_set_ctype,2L + +#define SN_setct_OIData "setct-OIData" +#define NID_setct_OIData 522 +#define OBJ_setct_OIData OBJ_set_ctype,3L + +#define SN_setct_PI "setct-PI" +#define NID_setct_PI 523 +#define OBJ_setct_PI OBJ_set_ctype,4L + +#define SN_setct_PIData "setct-PIData" +#define NID_setct_PIData 524 +#define OBJ_setct_PIData OBJ_set_ctype,5L + +#define SN_setct_PIDataUnsigned "setct-PIDataUnsigned" +#define NID_setct_PIDataUnsigned 525 +#define OBJ_setct_PIDataUnsigned OBJ_set_ctype,6L + +#define SN_setct_HODInput "setct-HODInput" +#define NID_setct_HODInput 526 +#define OBJ_setct_HODInput OBJ_set_ctype,7L + +#define SN_setct_AuthResBaggage "setct-AuthResBaggage" +#define NID_setct_AuthResBaggage 527 +#define OBJ_setct_AuthResBaggage OBJ_set_ctype,8L + +#define SN_setct_AuthRevReqBaggage "setct-AuthRevReqBaggage" +#define NID_setct_AuthRevReqBaggage 528 +#define OBJ_setct_AuthRevReqBaggage OBJ_set_ctype,9L + +#define SN_setct_AuthRevResBaggage "setct-AuthRevResBaggage" +#define NID_setct_AuthRevResBaggage 529 +#define OBJ_setct_AuthRevResBaggage OBJ_set_ctype,10L + +#define SN_setct_CapTokenSeq "setct-CapTokenSeq" +#define NID_setct_CapTokenSeq 530 +#define OBJ_setct_CapTokenSeq OBJ_set_ctype,11L + +#define SN_setct_PInitResData "setct-PInitResData" +#define NID_setct_PInitResData 531 +#define OBJ_setct_PInitResData OBJ_set_ctype,12L + +#define SN_setct_PI_TBS "setct-PI-TBS" +#define NID_setct_PI_TBS 532 +#define OBJ_setct_PI_TBS OBJ_set_ctype,13L + +#define SN_setct_PResData "setct-PResData" +#define NID_setct_PResData 533 +#define OBJ_setct_PResData OBJ_set_ctype,14L + +#define SN_setct_AuthReqTBS "setct-AuthReqTBS" +#define NID_setct_AuthReqTBS 534 +#define OBJ_setct_AuthReqTBS OBJ_set_ctype,16L + +#define SN_setct_AuthResTBS "setct-AuthResTBS" +#define NID_setct_AuthResTBS 535 +#define OBJ_setct_AuthResTBS OBJ_set_ctype,17L + +#define SN_setct_AuthResTBSX "setct-AuthResTBSX" +#define NID_setct_AuthResTBSX 536 +#define OBJ_setct_AuthResTBSX OBJ_set_ctype,18L + +#define SN_setct_AuthTokenTBS "setct-AuthTokenTBS" +#define NID_setct_AuthTokenTBS 537 +#define OBJ_setct_AuthTokenTBS OBJ_set_ctype,19L + +#define SN_setct_CapTokenData "setct-CapTokenData" +#define NID_setct_CapTokenData 538 +#define OBJ_setct_CapTokenData OBJ_set_ctype,20L + +#define SN_setct_CapTokenTBS "setct-CapTokenTBS" +#define NID_setct_CapTokenTBS 539 +#define OBJ_setct_CapTokenTBS OBJ_set_ctype,21L + +#define SN_setct_AcqCardCodeMsg "setct-AcqCardCodeMsg" +#define NID_setct_AcqCardCodeMsg 540 +#define OBJ_setct_AcqCardCodeMsg OBJ_set_ctype,22L + +#define SN_setct_AuthRevReqTBS "setct-AuthRevReqTBS" +#define NID_setct_AuthRevReqTBS 541 +#define OBJ_setct_AuthRevReqTBS OBJ_set_ctype,23L + +#define SN_setct_AuthRevResData "setct-AuthRevResData" +#define NID_setct_AuthRevResData 542 +#define OBJ_setct_AuthRevResData OBJ_set_ctype,24L + +#define SN_setct_AuthRevResTBS "setct-AuthRevResTBS" +#define NID_setct_AuthRevResTBS 543 +#define OBJ_setct_AuthRevResTBS OBJ_set_ctype,25L + +#define SN_setct_CapReqTBS "setct-CapReqTBS" +#define NID_setct_CapReqTBS 544 +#define OBJ_setct_CapReqTBS OBJ_set_ctype,26L + +#define SN_setct_CapReqTBSX "setct-CapReqTBSX" +#define NID_setct_CapReqTBSX 545 +#define OBJ_setct_CapReqTBSX OBJ_set_ctype,27L + +#define SN_setct_CapResData "setct-CapResData" +#define NID_setct_CapResData 546 +#define OBJ_setct_CapResData OBJ_set_ctype,28L + +#define SN_setct_CapRevReqTBS "setct-CapRevReqTBS" +#define NID_setct_CapRevReqTBS 547 +#define OBJ_setct_CapRevReqTBS OBJ_set_ctype,29L + +#define SN_setct_CapRevReqTBSX "setct-CapRevReqTBSX" +#define NID_setct_CapRevReqTBSX 548 +#define OBJ_setct_CapRevReqTBSX OBJ_set_ctype,30L + +#define SN_setct_CapRevResData "setct-CapRevResData" +#define NID_setct_CapRevResData 549 +#define OBJ_setct_CapRevResData OBJ_set_ctype,31L + +#define SN_setct_CredReqTBS "setct-CredReqTBS" +#define NID_setct_CredReqTBS 550 +#define OBJ_setct_CredReqTBS OBJ_set_ctype,32L + +#define SN_setct_CredReqTBSX "setct-CredReqTBSX" +#define NID_setct_CredReqTBSX 551 +#define OBJ_setct_CredReqTBSX OBJ_set_ctype,33L + +#define SN_setct_CredResData "setct-CredResData" +#define NID_setct_CredResData 552 +#define OBJ_setct_CredResData OBJ_set_ctype,34L + +#define SN_setct_CredRevReqTBS "setct-CredRevReqTBS" +#define NID_setct_CredRevReqTBS 553 +#define OBJ_setct_CredRevReqTBS OBJ_set_ctype,35L + +#define SN_setct_CredRevReqTBSX "setct-CredRevReqTBSX" +#define NID_setct_CredRevReqTBSX 554 +#define OBJ_setct_CredRevReqTBSX OBJ_set_ctype,36L + +#define SN_setct_CredRevResData "setct-CredRevResData" +#define NID_setct_CredRevResData 555 +#define OBJ_setct_CredRevResData OBJ_set_ctype,37L + +#define SN_setct_PCertReqData "setct-PCertReqData" +#define NID_setct_PCertReqData 556 +#define OBJ_setct_PCertReqData OBJ_set_ctype,38L + +#define SN_setct_PCertResTBS "setct-PCertResTBS" +#define NID_setct_PCertResTBS 557 +#define OBJ_setct_PCertResTBS OBJ_set_ctype,39L + +#define SN_setct_BatchAdminReqData "setct-BatchAdminReqData" +#define NID_setct_BatchAdminReqData 558 +#define OBJ_setct_BatchAdminReqData OBJ_set_ctype,40L + +#define SN_setct_BatchAdminResData "setct-BatchAdminResData" +#define NID_setct_BatchAdminResData 559 +#define OBJ_setct_BatchAdminResData OBJ_set_ctype,41L + +#define SN_setct_CardCInitResTBS "setct-CardCInitResTBS" +#define NID_setct_CardCInitResTBS 560 +#define OBJ_setct_CardCInitResTBS OBJ_set_ctype,42L + +#define SN_setct_MeAqCInitResTBS "setct-MeAqCInitResTBS" +#define NID_setct_MeAqCInitResTBS 561 +#define OBJ_setct_MeAqCInitResTBS OBJ_set_ctype,43L + +#define SN_setct_RegFormResTBS "setct-RegFormResTBS" +#define NID_setct_RegFormResTBS 562 +#define OBJ_setct_RegFormResTBS OBJ_set_ctype,44L + +#define SN_setct_CertReqData "setct-CertReqData" +#define NID_setct_CertReqData 563 +#define OBJ_setct_CertReqData OBJ_set_ctype,45L + +#define SN_setct_CertReqTBS "setct-CertReqTBS" +#define NID_setct_CertReqTBS 564 +#define OBJ_setct_CertReqTBS OBJ_set_ctype,46L + +#define SN_setct_CertResData "setct-CertResData" +#define NID_setct_CertResData 565 +#define OBJ_setct_CertResData OBJ_set_ctype,47L + +#define SN_setct_CertInqReqTBS "setct-CertInqReqTBS" +#define NID_setct_CertInqReqTBS 566 +#define OBJ_setct_CertInqReqTBS OBJ_set_ctype,48L + +#define SN_setct_ErrorTBS "setct-ErrorTBS" +#define NID_setct_ErrorTBS 567 +#define OBJ_setct_ErrorTBS OBJ_set_ctype,49L + +#define SN_setct_PIDualSignedTBE "setct-PIDualSignedTBE" +#define NID_setct_PIDualSignedTBE 568 +#define OBJ_setct_PIDualSignedTBE OBJ_set_ctype,50L + +#define SN_setct_PIUnsignedTBE "setct-PIUnsignedTBE" +#define NID_setct_PIUnsignedTBE 569 +#define OBJ_setct_PIUnsignedTBE OBJ_set_ctype,51L + +#define SN_setct_AuthReqTBE "setct-AuthReqTBE" +#define NID_setct_AuthReqTBE 570 +#define OBJ_setct_AuthReqTBE OBJ_set_ctype,52L + +#define SN_setct_AuthResTBE "setct-AuthResTBE" +#define NID_setct_AuthResTBE 571 +#define OBJ_setct_AuthResTBE OBJ_set_ctype,53L + +#define SN_setct_AuthResTBEX "setct-AuthResTBEX" +#define NID_setct_AuthResTBEX 572 +#define OBJ_setct_AuthResTBEX OBJ_set_ctype,54L + +#define SN_setct_AuthTokenTBE "setct-AuthTokenTBE" +#define NID_setct_AuthTokenTBE 573 +#define OBJ_setct_AuthTokenTBE OBJ_set_ctype,55L + +#define SN_setct_CapTokenTBE "setct-CapTokenTBE" +#define NID_setct_CapTokenTBE 574 +#define OBJ_setct_CapTokenTBE OBJ_set_ctype,56L + +#define SN_setct_CapTokenTBEX "setct-CapTokenTBEX" +#define NID_setct_CapTokenTBEX 575 +#define OBJ_setct_CapTokenTBEX OBJ_set_ctype,57L + +#define SN_setct_AcqCardCodeMsgTBE "setct-AcqCardCodeMsgTBE" +#define NID_setct_AcqCardCodeMsgTBE 576 +#define OBJ_setct_AcqCardCodeMsgTBE OBJ_set_ctype,58L + +#define SN_setct_AuthRevReqTBE "setct-AuthRevReqTBE" +#define NID_setct_AuthRevReqTBE 577 +#define OBJ_setct_AuthRevReqTBE OBJ_set_ctype,59L + +#define SN_setct_AuthRevResTBE "setct-AuthRevResTBE" +#define NID_setct_AuthRevResTBE 578 +#define OBJ_setct_AuthRevResTBE OBJ_set_ctype,60L + +#define SN_setct_AuthRevResTBEB "setct-AuthRevResTBEB" +#define NID_setct_AuthRevResTBEB 579 +#define OBJ_setct_AuthRevResTBEB OBJ_set_ctype,61L + +#define SN_setct_CapReqTBE "setct-CapReqTBE" +#define NID_setct_CapReqTBE 580 +#define OBJ_setct_CapReqTBE OBJ_set_ctype,62L + +#define SN_setct_CapReqTBEX "setct-CapReqTBEX" +#define NID_setct_CapReqTBEX 581 +#define OBJ_setct_CapReqTBEX OBJ_set_ctype,63L + +#define SN_setct_CapResTBE "setct-CapResTBE" +#define NID_setct_CapResTBE 582 +#define OBJ_setct_CapResTBE OBJ_set_ctype,64L + +#define SN_setct_CapRevReqTBE "setct-CapRevReqTBE" +#define NID_setct_CapRevReqTBE 583 +#define OBJ_setct_CapRevReqTBE OBJ_set_ctype,65L + +#define SN_setct_CapRevReqTBEX "setct-CapRevReqTBEX" +#define NID_setct_CapRevReqTBEX 584 +#define OBJ_setct_CapRevReqTBEX OBJ_set_ctype,66L + +#define SN_setct_CapRevResTBE "setct-CapRevResTBE" +#define NID_setct_CapRevResTBE 585 +#define OBJ_setct_CapRevResTBE OBJ_set_ctype,67L + +#define SN_setct_CredReqTBE "setct-CredReqTBE" +#define NID_setct_CredReqTBE 586 +#define OBJ_setct_CredReqTBE OBJ_set_ctype,68L + +#define SN_setct_CredReqTBEX "setct-CredReqTBEX" +#define NID_setct_CredReqTBEX 587 +#define OBJ_setct_CredReqTBEX OBJ_set_ctype,69L + +#define SN_setct_CredResTBE "setct-CredResTBE" +#define NID_setct_CredResTBE 588 +#define OBJ_setct_CredResTBE OBJ_set_ctype,70L + +#define SN_setct_CredRevReqTBE "setct-CredRevReqTBE" +#define NID_setct_CredRevReqTBE 589 +#define OBJ_setct_CredRevReqTBE OBJ_set_ctype,71L + +#define SN_setct_CredRevReqTBEX "setct-CredRevReqTBEX" +#define NID_setct_CredRevReqTBEX 590 +#define OBJ_setct_CredRevReqTBEX OBJ_set_ctype,72L + +#define SN_setct_CredRevResTBE "setct-CredRevResTBE" +#define NID_setct_CredRevResTBE 591 +#define OBJ_setct_CredRevResTBE OBJ_set_ctype,73L + +#define SN_setct_BatchAdminReqTBE "setct-BatchAdminReqTBE" +#define NID_setct_BatchAdminReqTBE 592 +#define OBJ_setct_BatchAdminReqTBE OBJ_set_ctype,74L + +#define SN_setct_BatchAdminResTBE "setct-BatchAdminResTBE" +#define NID_setct_BatchAdminResTBE 593 +#define OBJ_setct_BatchAdminResTBE OBJ_set_ctype,75L + +#define SN_setct_RegFormReqTBE "setct-RegFormReqTBE" +#define NID_setct_RegFormReqTBE 594 +#define OBJ_setct_RegFormReqTBE OBJ_set_ctype,76L + +#define SN_setct_CertReqTBE "setct-CertReqTBE" +#define NID_setct_CertReqTBE 595 +#define OBJ_setct_CertReqTBE OBJ_set_ctype,77L + +#define SN_setct_CertReqTBEX "setct-CertReqTBEX" +#define NID_setct_CertReqTBEX 596 +#define OBJ_setct_CertReqTBEX OBJ_set_ctype,78L + +#define SN_setct_CertResTBE "setct-CertResTBE" +#define NID_setct_CertResTBE 597 +#define OBJ_setct_CertResTBE OBJ_set_ctype,79L + +#define SN_setct_CRLNotificationTBS "setct-CRLNotificationTBS" +#define NID_setct_CRLNotificationTBS 598 +#define OBJ_setct_CRLNotificationTBS OBJ_set_ctype,80L + +#define SN_setct_CRLNotificationResTBS "setct-CRLNotificationResTBS" +#define NID_setct_CRLNotificationResTBS 599 +#define OBJ_setct_CRLNotificationResTBS OBJ_set_ctype,81L + +#define SN_setct_BCIDistributionTBS "setct-BCIDistributionTBS" +#define NID_setct_BCIDistributionTBS 600 +#define OBJ_setct_BCIDistributionTBS OBJ_set_ctype,82L + +#define SN_setext_genCrypt "setext-genCrypt" +#define LN_setext_genCrypt "generic cryptogram" +#define NID_setext_genCrypt 601 +#define OBJ_setext_genCrypt OBJ_set_msgExt,1L + +#define SN_setext_miAuth "setext-miAuth" +#define LN_setext_miAuth "merchant initiated auth" +#define NID_setext_miAuth 602 +#define OBJ_setext_miAuth OBJ_set_msgExt,3L + +#define SN_setext_pinSecure "setext-pinSecure" +#define NID_setext_pinSecure 603 +#define OBJ_setext_pinSecure OBJ_set_msgExt,4L + +#define SN_setext_pinAny "setext-pinAny" +#define NID_setext_pinAny 604 +#define OBJ_setext_pinAny OBJ_set_msgExt,5L + +#define SN_setext_track2 "setext-track2" +#define NID_setext_track2 605 +#define OBJ_setext_track2 OBJ_set_msgExt,7L + +#define SN_setext_cv "setext-cv" +#define LN_setext_cv "additional verification" +#define NID_setext_cv 606 +#define OBJ_setext_cv OBJ_set_msgExt,8L + +#define SN_set_policy_root "set-policy-root" +#define NID_set_policy_root 607 +#define OBJ_set_policy_root OBJ_set_policy,0L + +#define SN_setCext_hashedRoot "setCext-hashedRoot" +#define NID_setCext_hashedRoot 608 +#define OBJ_setCext_hashedRoot OBJ_set_certExt,0L + +#define SN_setCext_certType "setCext-certType" +#define NID_setCext_certType 609 +#define OBJ_setCext_certType OBJ_set_certExt,1L + +#define SN_setCext_merchData "setCext-merchData" +#define NID_setCext_merchData 610 +#define OBJ_setCext_merchData OBJ_set_certExt,2L + +#define SN_setCext_cCertRequired "setCext-cCertRequired" +#define NID_setCext_cCertRequired 611 +#define OBJ_setCext_cCertRequired OBJ_set_certExt,3L + +#define SN_setCext_tunneling "setCext-tunneling" +#define NID_setCext_tunneling 612 +#define OBJ_setCext_tunneling OBJ_set_certExt,4L + +#define SN_setCext_setExt "setCext-setExt" +#define NID_setCext_setExt 613 +#define OBJ_setCext_setExt OBJ_set_certExt,5L + +#define SN_setCext_setQualf "setCext-setQualf" +#define NID_setCext_setQualf 614 +#define OBJ_setCext_setQualf OBJ_set_certExt,6L + +#define SN_setCext_PGWYcapabilities "setCext-PGWYcapabilities" +#define NID_setCext_PGWYcapabilities 615 +#define OBJ_setCext_PGWYcapabilities OBJ_set_certExt,7L + +#define SN_setCext_TokenIdentifier "setCext-TokenIdentifier" +#define NID_setCext_TokenIdentifier 616 +#define OBJ_setCext_TokenIdentifier OBJ_set_certExt,8L + +#define SN_setCext_Track2Data "setCext-Track2Data" +#define NID_setCext_Track2Data 617 +#define OBJ_setCext_Track2Data OBJ_set_certExt,9L + +#define SN_setCext_TokenType "setCext-TokenType" +#define NID_setCext_TokenType 618 +#define OBJ_setCext_TokenType OBJ_set_certExt,10L + +#define SN_setCext_IssuerCapabilities "setCext-IssuerCapabilities" +#define NID_setCext_IssuerCapabilities 619 +#define OBJ_setCext_IssuerCapabilities OBJ_set_certExt,11L + +#define SN_setAttr_Cert "setAttr-Cert" +#define NID_setAttr_Cert 620 +#define OBJ_setAttr_Cert OBJ_set_attr,0L + +#define SN_setAttr_PGWYcap "setAttr-PGWYcap" +#define LN_setAttr_PGWYcap "payment gateway capabilities" +#define NID_setAttr_PGWYcap 621 +#define OBJ_setAttr_PGWYcap OBJ_set_attr,1L + +#define SN_setAttr_TokenType "setAttr-TokenType" +#define NID_setAttr_TokenType 622 +#define OBJ_setAttr_TokenType OBJ_set_attr,2L + +#define SN_setAttr_IssCap "setAttr-IssCap" +#define LN_setAttr_IssCap "issuer capabilities" +#define NID_setAttr_IssCap 623 +#define OBJ_setAttr_IssCap OBJ_set_attr,3L + +#define SN_set_rootKeyThumb "set-rootKeyThumb" +#define NID_set_rootKeyThumb 624 +#define OBJ_set_rootKeyThumb OBJ_setAttr_Cert,0L + +#define SN_set_addPolicy "set-addPolicy" +#define NID_set_addPolicy 625 +#define OBJ_set_addPolicy OBJ_setAttr_Cert,1L + +#define SN_setAttr_Token_EMV "setAttr-Token-EMV" +#define NID_setAttr_Token_EMV 626 +#define OBJ_setAttr_Token_EMV OBJ_setAttr_TokenType,1L + +#define SN_setAttr_Token_B0Prime "setAttr-Token-B0Prime" +#define NID_setAttr_Token_B0Prime 627 +#define OBJ_setAttr_Token_B0Prime OBJ_setAttr_TokenType,2L + +#define SN_setAttr_IssCap_CVM "setAttr-IssCap-CVM" +#define NID_setAttr_IssCap_CVM 628 +#define OBJ_setAttr_IssCap_CVM OBJ_setAttr_IssCap,3L + +#define SN_setAttr_IssCap_T2 "setAttr-IssCap-T2" +#define NID_setAttr_IssCap_T2 629 +#define OBJ_setAttr_IssCap_T2 OBJ_setAttr_IssCap,4L + +#define SN_setAttr_IssCap_Sig "setAttr-IssCap-Sig" +#define NID_setAttr_IssCap_Sig 630 +#define OBJ_setAttr_IssCap_Sig OBJ_setAttr_IssCap,5L + +#define SN_setAttr_GenCryptgrm "setAttr-GenCryptgrm" +#define LN_setAttr_GenCryptgrm "generate cryptogram" +#define NID_setAttr_GenCryptgrm 631 +#define OBJ_setAttr_GenCryptgrm OBJ_setAttr_IssCap_CVM,1L + +#define SN_setAttr_T2Enc "setAttr-T2Enc" +#define LN_setAttr_T2Enc "encrypted track 2" +#define NID_setAttr_T2Enc 632 +#define OBJ_setAttr_T2Enc OBJ_setAttr_IssCap_T2,1L + +#define SN_setAttr_T2cleartxt "setAttr-T2cleartxt" +#define LN_setAttr_T2cleartxt "cleartext track 2" +#define NID_setAttr_T2cleartxt 633 +#define OBJ_setAttr_T2cleartxt OBJ_setAttr_IssCap_T2,2L + +#define SN_setAttr_TokICCsig "setAttr-TokICCsig" +#define LN_setAttr_TokICCsig "ICC or token signature" +#define NID_setAttr_TokICCsig 634 +#define OBJ_setAttr_TokICCsig OBJ_setAttr_IssCap_Sig,1L + +#define SN_setAttr_SecDevSig "setAttr-SecDevSig" +#define LN_setAttr_SecDevSig "secure device signature" +#define NID_setAttr_SecDevSig 635 +#define OBJ_setAttr_SecDevSig OBJ_setAttr_IssCap_Sig,2L + +#define SN_set_brand_IATA_ATA "set-brand-IATA-ATA" +#define NID_set_brand_IATA_ATA 636 +#define OBJ_set_brand_IATA_ATA OBJ_set_brand,1L + +#define SN_set_brand_Diners "set-brand-Diners" +#define NID_set_brand_Diners 637 +#define OBJ_set_brand_Diners OBJ_set_brand,30L + +#define SN_set_brand_AmericanExpress "set-brand-AmericanExpress" +#define NID_set_brand_AmericanExpress 638 +#define OBJ_set_brand_AmericanExpress OBJ_set_brand,34L + +#define SN_set_brand_JCB "set-brand-JCB" +#define NID_set_brand_JCB 639 +#define OBJ_set_brand_JCB OBJ_set_brand,35L + +#define SN_set_brand_Visa "set-brand-Visa" +#define NID_set_brand_Visa 640 +#define OBJ_set_brand_Visa OBJ_set_brand,4L + +#define SN_set_brand_MasterCard "set-brand-MasterCard" +#define NID_set_brand_MasterCard 641 +#define OBJ_set_brand_MasterCard OBJ_set_brand,5L + +#define SN_set_brand_Novus "set-brand-Novus" +#define NID_set_brand_Novus 642 +#define OBJ_set_brand_Novus OBJ_set_brand,6011L + +#define SN_des_cdmf "DES-CDMF" +#define LN_des_cdmf "des-cdmf" +#define NID_des_cdmf 643 +#define OBJ_des_cdmf OBJ_rsadsi,3L,10L + +#define SN_rsaOAEPEncryptionSET "rsaOAEPEncryptionSET" +#define NID_rsaOAEPEncryptionSET 644 +#define OBJ_rsaOAEPEncryptionSET OBJ_rsadsi,1L,1L,6L + +#define SN_ipsec3 "Oakley-EC2N-3" +#define LN_ipsec3 "ipsec3" +#define NID_ipsec3 749 + +#define SN_ipsec4 "Oakley-EC2N-4" +#define LN_ipsec4 "ipsec4" +#define NID_ipsec4 750 + +#define SN_camellia_128_cbc "CAMELLIA-128-CBC" +#define LN_camellia_128_cbc "camellia-128-cbc" +#define NID_camellia_128_cbc 751 +#define OBJ_camellia_128_cbc 1L,2L,392L,200011L,61L,1L,1L,1L,2L + +#define SN_camellia_192_cbc "CAMELLIA-192-CBC" +#define LN_camellia_192_cbc "camellia-192-cbc" +#define NID_camellia_192_cbc 752 +#define OBJ_camellia_192_cbc 1L,2L,392L,200011L,61L,1L,1L,1L,3L + +#define SN_camellia_256_cbc "CAMELLIA-256-CBC" +#define LN_camellia_256_cbc "camellia-256-cbc" +#define NID_camellia_256_cbc 753 +#define OBJ_camellia_256_cbc 1L,2L,392L,200011L,61L,1L,1L,1L,4L + +#define OBJ_ntt_ds 0L,3L,4401L,5L + +#define OBJ_camellia OBJ_ntt_ds,3L,1L,9L + +#define SN_camellia_128_ecb "CAMELLIA-128-ECB" +#define LN_camellia_128_ecb "camellia-128-ecb" +#define NID_camellia_128_ecb 754 +#define OBJ_camellia_128_ecb OBJ_camellia,1L + +#define SN_camellia_128_ofb128 "CAMELLIA-128-OFB" +#define LN_camellia_128_ofb128 "camellia-128-ofb" +#define NID_camellia_128_ofb128 766 +#define OBJ_camellia_128_ofb128 OBJ_camellia,3L + +#define SN_camellia_128_cfb128 "CAMELLIA-128-CFB" +#define LN_camellia_128_cfb128 "camellia-128-cfb" +#define NID_camellia_128_cfb128 757 +#define OBJ_camellia_128_cfb128 OBJ_camellia,4L + +#define SN_camellia_192_ecb "CAMELLIA-192-ECB" +#define LN_camellia_192_ecb "camellia-192-ecb" +#define NID_camellia_192_ecb 755 +#define OBJ_camellia_192_ecb OBJ_camellia,21L + +#define SN_camellia_192_ofb128 "CAMELLIA-192-OFB" +#define LN_camellia_192_ofb128 "camellia-192-ofb" +#define NID_camellia_192_ofb128 767 +#define OBJ_camellia_192_ofb128 OBJ_camellia,23L + +#define SN_camellia_192_cfb128 "CAMELLIA-192-CFB" +#define LN_camellia_192_cfb128 "camellia-192-cfb" +#define NID_camellia_192_cfb128 758 +#define OBJ_camellia_192_cfb128 OBJ_camellia,24L + +#define SN_camellia_256_ecb "CAMELLIA-256-ECB" +#define LN_camellia_256_ecb "camellia-256-ecb" +#define NID_camellia_256_ecb 756 +#define OBJ_camellia_256_ecb OBJ_camellia,41L + +#define SN_camellia_256_ofb128 "CAMELLIA-256-OFB" +#define LN_camellia_256_ofb128 "camellia-256-ofb" +#define NID_camellia_256_ofb128 768 +#define OBJ_camellia_256_ofb128 OBJ_camellia,43L + +#define SN_camellia_256_cfb128 "CAMELLIA-256-CFB" +#define LN_camellia_256_cfb128 "camellia-256-cfb" +#define NID_camellia_256_cfb128 759 +#define OBJ_camellia_256_cfb128 OBJ_camellia,44L + +#define SN_camellia_128_cfb1 "CAMELLIA-128-CFB1" +#define LN_camellia_128_cfb1 "camellia-128-cfb1" +#define NID_camellia_128_cfb1 760 + +#define SN_camellia_192_cfb1 "CAMELLIA-192-CFB1" +#define LN_camellia_192_cfb1 "camellia-192-cfb1" +#define NID_camellia_192_cfb1 761 + +#define SN_camellia_256_cfb1 "CAMELLIA-256-CFB1" +#define LN_camellia_256_cfb1 "camellia-256-cfb1" +#define NID_camellia_256_cfb1 762 + +#define SN_camellia_128_cfb8 "CAMELLIA-128-CFB8" +#define LN_camellia_128_cfb8 "camellia-128-cfb8" +#define NID_camellia_128_cfb8 763 + +#define SN_camellia_192_cfb8 "CAMELLIA-192-CFB8" +#define LN_camellia_192_cfb8 "camellia-192-cfb8" +#define NID_camellia_192_cfb8 764 + +#define SN_camellia_256_cfb8 "CAMELLIA-256-CFB8" +#define LN_camellia_256_cfb8 "camellia-256-cfb8" +#define NID_camellia_256_cfb8 765 + +#define SN_kisa "KISA" +#define LN_kisa "kisa" +#define NID_kisa 773 +#define OBJ_kisa OBJ_member_body,410L,200004L + +#define SN_seed_ecb "SEED-ECB" +#define LN_seed_ecb "seed-ecb" +#define NID_seed_ecb 776 +#define OBJ_seed_ecb OBJ_kisa,1L,3L + +#define SN_seed_cbc "SEED-CBC" +#define LN_seed_cbc "seed-cbc" +#define NID_seed_cbc 777 +#define OBJ_seed_cbc OBJ_kisa,1L,4L + +#define SN_seed_cfb128 "SEED-CFB" +#define LN_seed_cfb128 "seed-cfb" +#define NID_seed_cfb128 779 +#define OBJ_seed_cfb128 OBJ_kisa,1L,5L + +#define SN_seed_ofb128 "SEED-OFB" +#define LN_seed_ofb128 "seed-ofb" +#define NID_seed_ofb128 778 +#define OBJ_seed_ofb128 OBJ_kisa,1L,6L + diff --git a/lib_tls/include/openssl/objects.h b/lib_tls/include/openssl/objects.h new file mode 100644 index 000000000..7242f76fb --- /dev/null +++ b/lib_tls/include/openssl/objects.h @@ -0,0 +1,1049 @@ +/* crypto/objects/objects.h */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#ifndef HEADER_OBJECTS_H +#define HEADER_OBJECTS_H + +#define USE_OBJ_MAC + +#ifdef USE_OBJ_MAC +#include +#else +#define SN_undef "UNDEF" +#define LN_undef "undefined" +#define NID_undef 0 +#define OBJ_undef 0L + +#define SN_Algorithm "Algorithm" +#define LN_algorithm "algorithm" +#define NID_algorithm 38 +#define OBJ_algorithm 1L,3L,14L,3L,2L + +#define LN_rsadsi "rsadsi" +#define NID_rsadsi 1 +#define OBJ_rsadsi 1L,2L,840L,113549L + +#define LN_pkcs "pkcs" +#define NID_pkcs 2 +#define OBJ_pkcs OBJ_rsadsi,1L + +#define SN_md2 "MD2" +#define LN_md2 "md2" +#define NID_md2 3 +#define OBJ_md2 OBJ_rsadsi,2L,2L + +#define SN_md5 "MD5" +#define LN_md5 "md5" +#define NID_md5 4 +#define OBJ_md5 OBJ_rsadsi,2L,5L + +#define SN_rc4 "RC4" +#define LN_rc4 "rc4" +#define NID_rc4 5 +#define OBJ_rc4 OBJ_rsadsi,3L,4L + +#define LN_rsaEncryption "rsaEncryption" +#define NID_rsaEncryption 6 +#define OBJ_rsaEncryption OBJ_pkcs,1L,1L + +#define SN_md2WithRSAEncryption "RSA-MD2" +#define LN_md2WithRSAEncryption "md2WithRSAEncryption" +#define NID_md2WithRSAEncryption 7 +#define OBJ_md2WithRSAEncryption OBJ_pkcs,1L,2L + +#define SN_md5WithRSAEncryption "RSA-MD5" +#define LN_md5WithRSAEncryption "md5WithRSAEncryption" +#define NID_md5WithRSAEncryption 8 +#define OBJ_md5WithRSAEncryption OBJ_pkcs,1L,4L + +#define SN_pbeWithMD2AndDES_CBC "PBE-MD2-DES" +#define LN_pbeWithMD2AndDES_CBC "pbeWithMD2AndDES-CBC" +#define NID_pbeWithMD2AndDES_CBC 9 +#define OBJ_pbeWithMD2AndDES_CBC OBJ_pkcs,5L,1L + +#define SN_pbeWithMD5AndDES_CBC "PBE-MD5-DES" +#define LN_pbeWithMD5AndDES_CBC "pbeWithMD5AndDES-CBC" +#define NID_pbeWithMD5AndDES_CBC 10 +#define OBJ_pbeWithMD5AndDES_CBC OBJ_pkcs,5L,3L + +#define LN_X500 "X500" +#define NID_X500 11 +#define OBJ_X500 2L,5L + +#define LN_X509 "X509" +#define NID_X509 12 +#define OBJ_X509 OBJ_X500,4L + +#define SN_commonName "CN" +#define LN_commonName "commonName" +#define NID_commonName 13 +#define OBJ_commonName OBJ_X509,3L + +#define SN_countryName "C" +#define LN_countryName "countryName" +#define NID_countryName 14 +#define OBJ_countryName OBJ_X509,6L + +#define SN_localityName "L" +#define LN_localityName "localityName" +#define NID_localityName 15 +#define OBJ_localityName OBJ_X509,7L + +/* Postal Address? PA */ + +/* should be "ST" (rfc1327) but MS uses 'S' */ +#define SN_stateOrProvinceName "ST" +#define LN_stateOrProvinceName "stateOrProvinceName" +#define NID_stateOrProvinceName 16 +#define OBJ_stateOrProvinceName OBJ_X509,8L + +#define SN_organizationName "O" +#define LN_organizationName "organizationName" +#define NID_organizationName 17 +#define OBJ_organizationName OBJ_X509,10L + +#define SN_organizationalUnitName "OU" +#define LN_organizationalUnitName "organizationalUnitName" +#define NID_organizationalUnitName 18 +#define OBJ_organizationalUnitName OBJ_X509,11L + +#define SN_rsa "RSA" +#define LN_rsa "rsa" +#define NID_rsa 19 +#define OBJ_rsa OBJ_X500,8L,1L,1L + +#define LN_pkcs7 "pkcs7" +#define NID_pkcs7 20 +#define OBJ_pkcs7 OBJ_pkcs,7L + +#define LN_pkcs7_data "pkcs7-data" +#define NID_pkcs7_data 21 +#define OBJ_pkcs7_data OBJ_pkcs7,1L + +#define LN_pkcs7_signed "pkcs7-signedData" +#define NID_pkcs7_signed 22 +#define OBJ_pkcs7_signed OBJ_pkcs7,2L + +#define LN_pkcs7_enveloped "pkcs7-envelopedData" +#define NID_pkcs7_enveloped 23 +#define OBJ_pkcs7_enveloped OBJ_pkcs7,3L + +#define LN_pkcs7_signedAndEnveloped "pkcs7-signedAndEnvelopedData" +#define NID_pkcs7_signedAndEnveloped 24 +#define OBJ_pkcs7_signedAndEnveloped OBJ_pkcs7,4L + +#define LN_pkcs7_digest "pkcs7-digestData" +#define NID_pkcs7_digest 25 +#define OBJ_pkcs7_digest OBJ_pkcs7,5L + +#define LN_pkcs7_encrypted "pkcs7-encryptedData" +#define NID_pkcs7_encrypted 26 +#define OBJ_pkcs7_encrypted OBJ_pkcs7,6L + +#define LN_pkcs3 "pkcs3" +#define NID_pkcs3 27 +#define OBJ_pkcs3 OBJ_pkcs,3L + +#define LN_dhKeyAgreement "dhKeyAgreement" +#define NID_dhKeyAgreement 28 +#define OBJ_dhKeyAgreement OBJ_pkcs3,1L + +#define SN_des_ecb "DES-ECB" +#define LN_des_ecb "des-ecb" +#define NID_des_ecb 29 +#define OBJ_des_ecb OBJ_algorithm,6L + +#define SN_des_cfb64 "DES-CFB" +#define LN_des_cfb64 "des-cfb" +#define NID_des_cfb64 30 +/* IV + num */ +#define OBJ_des_cfb64 OBJ_algorithm,9L + +#define SN_des_cbc "DES-CBC" +#define LN_des_cbc "des-cbc" +#define NID_des_cbc 31 +/* IV */ +#define OBJ_des_cbc OBJ_algorithm,7L + +#define SN_des_ede "DES-EDE" +#define LN_des_ede "des-ede" +#define NID_des_ede 32 +/* ?? */ +#define OBJ_des_ede OBJ_algorithm,17L + +#define SN_des_ede3 "DES-EDE3" +#define LN_des_ede3 "des-ede3" +#define NID_des_ede3 33 + +#define SN_idea_cbc "IDEA-CBC" +#define LN_idea_cbc "idea-cbc" +#define NID_idea_cbc 34 +#define OBJ_idea_cbc 1L,3L,6L,1L,4L,1L,188L,7L,1L,1L,2L + +#define SN_idea_cfb64 "IDEA-CFB" +#define LN_idea_cfb64 "idea-cfb" +#define NID_idea_cfb64 35 + +#define SN_idea_ecb "IDEA-ECB" +#define LN_idea_ecb "idea-ecb" +#define NID_idea_ecb 36 + +#define SN_rc2_cbc "RC2-CBC" +#define LN_rc2_cbc "rc2-cbc" +#define NID_rc2_cbc 37 +#define OBJ_rc2_cbc OBJ_rsadsi,3L,2L + +#define SN_rc2_ecb "RC2-ECB" +#define LN_rc2_ecb "rc2-ecb" +#define NID_rc2_ecb 38 + +#define SN_rc2_cfb64 "RC2-CFB" +#define LN_rc2_cfb64 "rc2-cfb" +#define NID_rc2_cfb64 39 + +#define SN_rc2_ofb64 "RC2-OFB" +#define LN_rc2_ofb64 "rc2-ofb" +#define NID_rc2_ofb64 40 + +#define SN_sha "SHA" +#define LN_sha "sha" +#define NID_sha 41 +#define OBJ_sha OBJ_algorithm,18L + +#define SN_shaWithRSAEncryption "RSA-SHA" +#define LN_shaWithRSAEncryption "shaWithRSAEncryption" +#define NID_shaWithRSAEncryption 42 +#define OBJ_shaWithRSAEncryption OBJ_algorithm,15L + +#define SN_des_ede_cbc "DES-EDE-CBC" +#define LN_des_ede_cbc "des-ede-cbc" +#define NID_des_ede_cbc 43 + +#define SN_des_ede3_cbc "DES-EDE3-CBC" +#define LN_des_ede3_cbc "des-ede3-cbc" +#define NID_des_ede3_cbc 44 +#define OBJ_des_ede3_cbc OBJ_rsadsi,3L,7L + +#define SN_des_ofb64 "DES-OFB" +#define LN_des_ofb64 "des-ofb" +#define NID_des_ofb64 45 +#define OBJ_des_ofb64 OBJ_algorithm,8L + +#define SN_idea_ofb64 "IDEA-OFB" +#define LN_idea_ofb64 "idea-ofb" +#define NID_idea_ofb64 46 + +#define LN_pkcs9 "pkcs9" +#define NID_pkcs9 47 +#define OBJ_pkcs9 OBJ_pkcs,9L + +#define SN_pkcs9_emailAddress "Email" +#define LN_pkcs9_emailAddress "emailAddress" +#define NID_pkcs9_emailAddress 48 +#define OBJ_pkcs9_emailAddress OBJ_pkcs9,1L + +#define LN_pkcs9_unstructuredName "unstructuredName" +#define NID_pkcs9_unstructuredName 49 +#define OBJ_pkcs9_unstructuredName OBJ_pkcs9,2L + +#define LN_pkcs9_contentType "contentType" +#define NID_pkcs9_contentType 50 +#define OBJ_pkcs9_contentType OBJ_pkcs9,3L + +#define LN_pkcs9_messageDigest "messageDigest" +#define NID_pkcs9_messageDigest 51 +#define OBJ_pkcs9_messageDigest OBJ_pkcs9,4L + +#define LN_pkcs9_signingTime "signingTime" +#define NID_pkcs9_signingTime 52 +#define OBJ_pkcs9_signingTime OBJ_pkcs9,5L + +#define LN_pkcs9_countersignature "countersignature" +#define NID_pkcs9_countersignature 53 +#define OBJ_pkcs9_countersignature OBJ_pkcs9,6L + +#define LN_pkcs9_challengePassword "challengePassword" +#define NID_pkcs9_challengePassword 54 +#define OBJ_pkcs9_challengePassword OBJ_pkcs9,7L + +#define LN_pkcs9_unstructuredAddress "unstructuredAddress" +#define NID_pkcs9_unstructuredAddress 55 +#define OBJ_pkcs9_unstructuredAddress OBJ_pkcs9,8L + +#define LN_pkcs9_extCertAttributes "extendedCertificateAttributes" +#define NID_pkcs9_extCertAttributes 56 +#define OBJ_pkcs9_extCertAttributes OBJ_pkcs9,9L + +#define SN_netscape "Netscape" +#define LN_netscape "Netscape Communications Corp." +#define NID_netscape 57 +#define OBJ_netscape 2L,16L,840L,1L,113730L + +#define SN_netscape_cert_extension "nsCertExt" +#define LN_netscape_cert_extension "Netscape Certificate Extension" +#define NID_netscape_cert_extension 58 +#define OBJ_netscape_cert_extension OBJ_netscape,1L + +#define SN_netscape_data_type "nsDataType" +#define LN_netscape_data_type "Netscape Data Type" +#define NID_netscape_data_type 59 +#define OBJ_netscape_data_type OBJ_netscape,2L + +#define SN_des_ede_cfb64 "DES-EDE-CFB" +#define LN_des_ede_cfb64 "des-ede-cfb" +#define NID_des_ede_cfb64 60 + +#define SN_des_ede3_cfb64 "DES-EDE3-CFB" +#define LN_des_ede3_cfb64 "des-ede3-cfb" +#define NID_des_ede3_cfb64 61 + +#define SN_des_ede_ofb64 "DES-EDE-OFB" +#define LN_des_ede_ofb64 "des-ede-ofb" +#define NID_des_ede_ofb64 62 + +#define SN_des_ede3_ofb64 "DES-EDE3-OFB" +#define LN_des_ede3_ofb64 "des-ede3-ofb" +#define NID_des_ede3_ofb64 63 + +/* I'm not sure about the object ID */ +#define SN_sha1 "SHA1" +#define LN_sha1 "sha1" +#define NID_sha1 64 +#define OBJ_sha1 OBJ_algorithm,26L +/* 28 Jun 1996 - eay */ +/* #define OBJ_sha1 1L,3L,14L,2L,26L,05L <- wrong */ + +#define SN_sha1WithRSAEncryption "RSA-SHA1" +#define LN_sha1WithRSAEncryption "sha1WithRSAEncryption" +#define NID_sha1WithRSAEncryption 65 +#define OBJ_sha1WithRSAEncryption OBJ_pkcs,1L,5L + +#define SN_dsaWithSHA "DSA-SHA" +#define LN_dsaWithSHA "dsaWithSHA" +#define NID_dsaWithSHA 66 +#define OBJ_dsaWithSHA OBJ_algorithm,13L + +#define SN_dsa_2 "DSA-old" +#define LN_dsa_2 "dsaEncryption-old" +#define NID_dsa_2 67 +#define OBJ_dsa_2 OBJ_algorithm,12L + +/* proposed by microsoft to RSA */ +#define SN_pbeWithSHA1AndRC2_CBC "PBE-SHA1-RC2-64" +#define LN_pbeWithSHA1AndRC2_CBC "pbeWithSHA1AndRC2-CBC" +#define NID_pbeWithSHA1AndRC2_CBC 68 +#define OBJ_pbeWithSHA1AndRC2_CBC OBJ_pkcs,5L,11L + +/* proposed by microsoft to RSA as pbeWithSHA1AndRC4: it is now + * defined explicitly in PKCS#5 v2.0 as id-PBKDF2 which is something + * completely different. + */ +#define LN_id_pbkdf2 "PBKDF2" +#define NID_id_pbkdf2 69 +#define OBJ_id_pbkdf2 OBJ_pkcs,5L,12L + +#define SN_dsaWithSHA1_2 "DSA-SHA1-old" +#define LN_dsaWithSHA1_2 "dsaWithSHA1-old" +#define NID_dsaWithSHA1_2 70 +/* Got this one from 'sdn706r20.pdf' which is actually an NSA document :-) */ +#define OBJ_dsaWithSHA1_2 OBJ_algorithm,27L + +#define SN_netscape_cert_type "nsCertType" +#define LN_netscape_cert_type "Netscape Cert Type" +#define NID_netscape_cert_type 71 +#define OBJ_netscape_cert_type OBJ_netscape_cert_extension,1L + +#define SN_netscape_base_url "nsBaseUrl" +#define LN_netscape_base_url "Netscape Base Url" +#define NID_netscape_base_url 72 +#define OBJ_netscape_base_url OBJ_netscape_cert_extension,2L + +#define SN_netscape_revocation_url "nsRevocationUrl" +#define LN_netscape_revocation_url "Netscape Revocation Url" +#define NID_netscape_revocation_url 73 +#define OBJ_netscape_revocation_url OBJ_netscape_cert_extension,3L + +#define SN_netscape_ca_revocation_url "nsCaRevocationUrl" +#define LN_netscape_ca_revocation_url "Netscape CA Revocation Url" +#define NID_netscape_ca_revocation_url 74 +#define OBJ_netscape_ca_revocation_url OBJ_netscape_cert_extension,4L + +#define SN_netscape_renewal_url "nsRenewalUrl" +#define LN_netscape_renewal_url "Netscape Renewal Url" +#define NID_netscape_renewal_url 75 +#define OBJ_netscape_renewal_url OBJ_netscape_cert_extension,7L + +#define SN_netscape_ca_policy_url "nsCaPolicyUrl" +#define LN_netscape_ca_policy_url "Netscape CA Policy Url" +#define NID_netscape_ca_policy_url 76 +#define OBJ_netscape_ca_policy_url OBJ_netscape_cert_extension,8L + +#define SN_netscape_ssl_server_name "nsSslServerName" +#define LN_netscape_ssl_server_name "Netscape SSL Server Name" +#define NID_netscape_ssl_server_name 77 +#define OBJ_netscape_ssl_server_name OBJ_netscape_cert_extension,12L + +#define SN_netscape_comment "nsComment" +#define LN_netscape_comment "Netscape Comment" +#define NID_netscape_comment 78 +#define OBJ_netscape_comment OBJ_netscape_cert_extension,13L + +#define SN_netscape_cert_sequence "nsCertSequence" +#define LN_netscape_cert_sequence "Netscape Certificate Sequence" +#define NID_netscape_cert_sequence 79 +#define OBJ_netscape_cert_sequence OBJ_netscape_data_type,5L + +#define SN_desx_cbc "DESX-CBC" +#define LN_desx_cbc "desx-cbc" +#define NID_desx_cbc 80 + +#define SN_id_ce "id-ce" +#define NID_id_ce 81 +#define OBJ_id_ce 2L,5L,29L + +#define SN_subject_key_identifier "subjectKeyIdentifier" +#define LN_subject_key_identifier "X509v3 Subject Key Identifier" +#define NID_subject_key_identifier 82 +#define OBJ_subject_key_identifier OBJ_id_ce,14L + +#define SN_key_usage "keyUsage" +#define LN_key_usage "X509v3 Key Usage" +#define NID_key_usage 83 +#define OBJ_key_usage OBJ_id_ce,15L + +#define SN_private_key_usage_period "privateKeyUsagePeriod" +#define LN_private_key_usage_period "X509v3 Private Key Usage Period" +#define NID_private_key_usage_period 84 +#define OBJ_private_key_usage_period OBJ_id_ce,16L + +#define SN_subject_alt_name "subjectAltName" +#define LN_subject_alt_name "X509v3 Subject Alternative Name" +#define NID_subject_alt_name 85 +#define OBJ_subject_alt_name OBJ_id_ce,17L + +#define SN_issuer_alt_name "issuerAltName" +#define LN_issuer_alt_name "X509v3 Issuer Alternative Name" +#define NID_issuer_alt_name 86 +#define OBJ_issuer_alt_name OBJ_id_ce,18L + +#define SN_basic_constraints "basicConstraints" +#define LN_basic_constraints "X509v3 Basic Constraints" +#define NID_basic_constraints 87 +#define OBJ_basic_constraints OBJ_id_ce,19L + +#define SN_crl_number "crlNumber" +#define LN_crl_number "X509v3 CRL Number" +#define NID_crl_number 88 +#define OBJ_crl_number OBJ_id_ce,20L + +#define SN_certificate_policies "certificatePolicies" +#define LN_certificate_policies "X509v3 Certificate Policies" +#define NID_certificate_policies 89 +#define OBJ_certificate_policies OBJ_id_ce,32L + +#define SN_authority_key_identifier "authorityKeyIdentifier" +#define LN_authority_key_identifier "X509v3 Authority Key Identifier" +#define NID_authority_key_identifier 90 +#define OBJ_authority_key_identifier OBJ_id_ce,35L + +#define SN_bf_cbc "BF-CBC" +#define LN_bf_cbc "bf-cbc" +#define NID_bf_cbc 91 +#define OBJ_bf_cbc 1L,3L,6L,1L,4L,1L,3029L,1L,2L + +#define SN_bf_ecb "BF-ECB" +#define LN_bf_ecb "bf-ecb" +#define NID_bf_ecb 92 + +#define SN_bf_cfb64 "BF-CFB" +#define LN_bf_cfb64 "bf-cfb" +#define NID_bf_cfb64 93 + +#define SN_bf_ofb64 "BF-OFB" +#define LN_bf_ofb64 "bf-ofb" +#define NID_bf_ofb64 94 + +#define SN_mdc2 "MDC2" +#define LN_mdc2 "mdc2" +#define NID_mdc2 95 +#define OBJ_mdc2 2L,5L,8L,3L,101L +/* An alternative? 1L,3L,14L,3L,2L,19L */ + +#define SN_mdc2WithRSA "RSA-MDC2" +#define LN_mdc2WithRSA "mdc2withRSA" +#define NID_mdc2WithRSA 96 +#define OBJ_mdc2WithRSA 2L,5L,8L,3L,100L + +#define SN_rc4_40 "RC4-40" +#define LN_rc4_40 "rc4-40" +#define NID_rc4_40 97 + +#define SN_rc2_40_cbc "RC2-40-CBC" +#define LN_rc2_40_cbc "rc2-40-cbc" +#define NID_rc2_40_cbc 98 + +#define SN_givenName "G" +#define LN_givenName "givenName" +#define NID_givenName 99 +#define OBJ_givenName OBJ_X509,42L + +#define SN_surname "S" +#define LN_surname "surname" +#define NID_surname 100 +#define OBJ_surname OBJ_X509,4L + +#define SN_initials "I" +#define LN_initials "initials" +#define NID_initials 101 +#define OBJ_initials OBJ_X509,43L + +#define SN_uniqueIdentifier "UID" +#define LN_uniqueIdentifier "uniqueIdentifier" +#define NID_uniqueIdentifier 102 +#define OBJ_uniqueIdentifier OBJ_X509,45L + +#define SN_crl_distribution_points "crlDistributionPoints" +#define LN_crl_distribution_points "X509v3 CRL Distribution Points" +#define NID_crl_distribution_points 103 +#define OBJ_crl_distribution_points OBJ_id_ce,31L + +#define SN_md5WithRSA "RSA-NP-MD5" +#define LN_md5WithRSA "md5WithRSA" +#define NID_md5WithRSA 104 +#define OBJ_md5WithRSA OBJ_algorithm,3L + +#define SN_serialNumber "SN" +#define LN_serialNumber "serialNumber" +#define NID_serialNumber 105 +#define OBJ_serialNumber OBJ_X509,5L + +#define SN_title "T" +#define LN_title "title" +#define NID_title 106 +#define OBJ_title OBJ_X509,12L + +#define SN_description "D" +#define LN_description "description" +#define NID_description 107 +#define OBJ_description OBJ_X509,13L + +/* CAST5 is CAST-128, I'm just sticking with the documentation */ +#define SN_cast5_cbc "CAST5-CBC" +#define LN_cast5_cbc "cast5-cbc" +#define NID_cast5_cbc 108 +#define OBJ_cast5_cbc 1L,2L,840L,113533L,7L,66L,10L + +#define SN_cast5_ecb "CAST5-ECB" +#define LN_cast5_ecb "cast5-ecb" +#define NID_cast5_ecb 109 + +#define SN_cast5_cfb64 "CAST5-CFB" +#define LN_cast5_cfb64 "cast5-cfb" +#define NID_cast5_cfb64 110 + +#define SN_cast5_ofb64 "CAST5-OFB" +#define LN_cast5_ofb64 "cast5-ofb" +#define NID_cast5_ofb64 111 + +#define LN_pbeWithMD5AndCast5_CBC "pbeWithMD5AndCast5CBC" +#define NID_pbeWithMD5AndCast5_CBC 112 +#define OBJ_pbeWithMD5AndCast5_CBC 1L,2L,840L,113533L,7L,66L,12L + +/* This is one sun will soon be using :-( + * id-dsa-with-sha1 ID ::= { + * iso(1) member-body(2) us(840) x9-57 (10040) x9cm(4) 3 } + */ +#define SN_dsaWithSHA1 "DSA-SHA1" +#define LN_dsaWithSHA1 "dsaWithSHA1" +#define NID_dsaWithSHA1 113 +#define OBJ_dsaWithSHA1 1L,2L,840L,10040L,4L,3L + +#define NID_md5_sha1 114 +#define SN_md5_sha1 "MD5-SHA1" +#define LN_md5_sha1 "md5-sha1" + +#define SN_sha1WithRSA "RSA-SHA1-2" +#define LN_sha1WithRSA "sha1WithRSA" +#define NID_sha1WithRSA 115 +#define OBJ_sha1WithRSA OBJ_algorithm,29L + +#define SN_dsa "DSA" +#define LN_dsa "dsaEncryption" +#define NID_dsa 116 +#define OBJ_dsa 1L,2L,840L,10040L,4L,1L + +#define SN_ripemd160 "RIPEMD160" +#define LN_ripemd160 "ripemd160" +#define NID_ripemd160 117 +#define OBJ_ripemd160 1L,3L,36L,3L,2L,1L + +/* The name should actually be rsaSignatureWithripemd160, but I'm going + * to continue using the convention I'm using with the other ciphers */ +#define SN_ripemd160WithRSA "RSA-RIPEMD160" +#define LN_ripemd160WithRSA "ripemd160WithRSA" +#define NID_ripemd160WithRSA 119 +#define OBJ_ripemd160WithRSA 1L,3L,36L,3L,3L,1L,2L + +/* Taken from rfc2040 + * RC5_CBC_Parameters ::= SEQUENCE { + * version INTEGER (v1_0(16)), + * rounds INTEGER (8..127), + * blockSizeInBits INTEGER (64, 128), + * iv OCTET STRING OPTIONAL + * } + */ +#define SN_rc5_cbc "RC5-CBC" +#define LN_rc5_cbc "rc5-cbc" +#define NID_rc5_cbc 120 +#define OBJ_rc5_cbc OBJ_rsadsi,3L,8L + +#define SN_rc5_ecb "RC5-ECB" +#define LN_rc5_ecb "rc5-ecb" +#define NID_rc5_ecb 121 + +#define SN_rc5_cfb64 "RC5-CFB" +#define LN_rc5_cfb64 "rc5-cfb" +#define NID_rc5_cfb64 122 + +#define SN_rc5_ofb64 "RC5-OFB" +#define LN_rc5_ofb64 "rc5-ofb" +#define NID_rc5_ofb64 123 + +#define SN_rle_compression "RLE" +#define LN_rle_compression "run length compression" +#define NID_rle_compression 124 +#define OBJ_rle_compression 1L,1L,1L,1L,666L,1L + +#define SN_zlib_compression "ZLIB" +#define LN_zlib_compression "zlib compression" +#define NID_zlib_compression 125 +#define OBJ_zlib_compression 1L,1L,1L,1L,666L,2L + +#define SN_ext_key_usage "extendedKeyUsage" +#define LN_ext_key_usage "X509v3 Extended Key Usage" +#define NID_ext_key_usage 126 +#define OBJ_ext_key_usage OBJ_id_ce,37 + +#define SN_id_pkix "PKIX" +#define NID_id_pkix 127 +#define OBJ_id_pkix 1L,3L,6L,1L,5L,5L,7L + +#define SN_id_kp "id-kp" +#define NID_id_kp 128 +#define OBJ_id_kp OBJ_id_pkix,3L + +/* PKIX extended key usage OIDs */ + +#define SN_server_auth "serverAuth" +#define LN_server_auth "TLS Web Server Authentication" +#define NID_server_auth 129 +#define OBJ_server_auth OBJ_id_kp,1L + +#define SN_client_auth "clientAuth" +#define LN_client_auth "TLS Web Client Authentication" +#define NID_client_auth 130 +#define OBJ_client_auth OBJ_id_kp,2L + +#define SN_code_sign "codeSigning" +#define LN_code_sign "Code Signing" +#define NID_code_sign 131 +#define OBJ_code_sign OBJ_id_kp,3L + +#define SN_email_protect "emailProtection" +#define LN_email_protect "E-mail Protection" +#define NID_email_protect 132 +#define OBJ_email_protect OBJ_id_kp,4L + +#define SN_time_stamp "timeStamping" +#define LN_time_stamp "Time Stamping" +#define NID_time_stamp 133 +#define OBJ_time_stamp OBJ_id_kp,8L + +/* Additional extended key usage OIDs: Microsoft */ + +#define SN_ms_code_ind "msCodeInd" +#define LN_ms_code_ind "Microsoft Individual Code Signing" +#define NID_ms_code_ind 134 +#define OBJ_ms_code_ind 1L,3L,6L,1L,4L,1L,311L,2L,1L,21L + +#define SN_ms_code_com "msCodeCom" +#define LN_ms_code_com "Microsoft Commercial Code Signing" +#define NID_ms_code_com 135 +#define OBJ_ms_code_com 1L,3L,6L,1L,4L,1L,311L,2L,1L,22L + +#define SN_ms_ctl_sign "msCTLSign" +#define LN_ms_ctl_sign "Microsoft Trust List Signing" +#define NID_ms_ctl_sign 136 +#define OBJ_ms_ctl_sign 1L,3L,6L,1L,4L,1L,311L,10L,3L,1L + +#define SN_ms_sgc "msSGC" +#define LN_ms_sgc "Microsoft Server Gated Crypto" +#define NID_ms_sgc 137 +#define OBJ_ms_sgc 1L,3L,6L,1L,4L,1L,311L,10L,3L,3L + +#define SN_ms_efs "msEFS" +#define LN_ms_efs "Microsoft Encrypted File System" +#define NID_ms_efs 138 +#define OBJ_ms_efs 1L,3L,6L,1L,4L,1L,311L,10L,3L,4L + +/* Additional usage: Netscape */ + +#define SN_ns_sgc "nsSGC" +#define LN_ns_sgc "Netscape Server Gated Crypto" +#define NID_ns_sgc 139 +#define OBJ_ns_sgc OBJ_netscape,4L,1L + +#define SN_delta_crl "deltaCRL" +#define LN_delta_crl "X509v3 Delta CRL Indicator" +#define NID_delta_crl 140 +#define OBJ_delta_crl OBJ_id_ce,27L + +#define SN_crl_reason "CRLReason" +#define LN_crl_reason "CRL Reason Code" +#define NID_crl_reason 141 +#define OBJ_crl_reason OBJ_id_ce,21L + +#define SN_invalidity_date "invalidityDate" +#define LN_invalidity_date "Invalidity Date" +#define NID_invalidity_date 142 +#define OBJ_invalidity_date OBJ_id_ce,24L + +#define SN_sxnet "SXNetID" +#define LN_sxnet "Strong Extranet ID" +#define NID_sxnet 143 +#define OBJ_sxnet 1L,3L,101L,1L,4L,1L + +/* PKCS12 and related OBJECT IDENTIFIERS */ + +#define OBJ_pkcs12 OBJ_pkcs,12L +#define OBJ_pkcs12_pbeids OBJ_pkcs12, 1 + +#define SN_pbe_WithSHA1And128BitRC4 "PBE-SHA1-RC4-128" +#define LN_pbe_WithSHA1And128BitRC4 "pbeWithSHA1And128BitRC4" +#define NID_pbe_WithSHA1And128BitRC4 144 +#define OBJ_pbe_WithSHA1And128BitRC4 OBJ_pkcs12_pbeids, 1L + +#define SN_pbe_WithSHA1And40BitRC4 "PBE-SHA1-RC4-40" +#define LN_pbe_WithSHA1And40BitRC4 "pbeWithSHA1And40BitRC4" +#define NID_pbe_WithSHA1And40BitRC4 145 +#define OBJ_pbe_WithSHA1And40BitRC4 OBJ_pkcs12_pbeids, 2L + +#define SN_pbe_WithSHA1And3_Key_TripleDES_CBC "PBE-SHA1-3DES" +#define LN_pbe_WithSHA1And3_Key_TripleDES_CBC "pbeWithSHA1And3-KeyTripleDES-CBC" +#define NID_pbe_WithSHA1And3_Key_TripleDES_CBC 146 +#define OBJ_pbe_WithSHA1And3_Key_TripleDES_CBC OBJ_pkcs12_pbeids, 3L + +#define SN_pbe_WithSHA1And2_Key_TripleDES_CBC "PBE-SHA1-2DES" +#define LN_pbe_WithSHA1And2_Key_TripleDES_CBC "pbeWithSHA1And2-KeyTripleDES-CBC" +#define NID_pbe_WithSHA1And2_Key_TripleDES_CBC 147 +#define OBJ_pbe_WithSHA1And2_Key_TripleDES_CBC OBJ_pkcs12_pbeids, 4L + +#define SN_pbe_WithSHA1And128BitRC2_CBC "PBE-SHA1-RC2-128" +#define LN_pbe_WithSHA1And128BitRC2_CBC "pbeWithSHA1And128BitRC2-CBC" +#define NID_pbe_WithSHA1And128BitRC2_CBC 148 +#define OBJ_pbe_WithSHA1And128BitRC2_CBC OBJ_pkcs12_pbeids, 5L + +#define SN_pbe_WithSHA1And40BitRC2_CBC "PBE-SHA1-RC2-40" +#define LN_pbe_WithSHA1And40BitRC2_CBC "pbeWithSHA1And40BitRC2-CBC" +#define NID_pbe_WithSHA1And40BitRC2_CBC 149 +#define OBJ_pbe_WithSHA1And40BitRC2_CBC OBJ_pkcs12_pbeids, 6L + +#define OBJ_pkcs12_Version1 OBJ_pkcs12, 10L + +#define OBJ_pkcs12_BagIds OBJ_pkcs12_Version1, 1L + +#define LN_keyBag "keyBag" +#define NID_keyBag 150 +#define OBJ_keyBag OBJ_pkcs12_BagIds, 1L + +#define LN_pkcs8ShroudedKeyBag "pkcs8ShroudedKeyBag" +#define NID_pkcs8ShroudedKeyBag 151 +#define OBJ_pkcs8ShroudedKeyBag OBJ_pkcs12_BagIds, 2L + +#define LN_certBag "certBag" +#define NID_certBag 152 +#define OBJ_certBag OBJ_pkcs12_BagIds, 3L + +#define LN_crlBag "crlBag" +#define NID_crlBag 153 +#define OBJ_crlBag OBJ_pkcs12_BagIds, 4L + +#define LN_secretBag "secretBag" +#define NID_secretBag 154 +#define OBJ_secretBag OBJ_pkcs12_BagIds, 5L + +#define LN_safeContentsBag "safeContentsBag" +#define NID_safeContentsBag 155 +#define OBJ_safeContentsBag OBJ_pkcs12_BagIds, 6L + +#define LN_friendlyName "friendlyName" +#define NID_friendlyName 156 +#define OBJ_friendlyName OBJ_pkcs9, 20L + +#define LN_localKeyID "localKeyID" +#define NID_localKeyID 157 +#define OBJ_localKeyID OBJ_pkcs9, 21L + +#define OBJ_certTypes OBJ_pkcs9, 22L + +#define LN_x509Certificate "x509Certificate" +#define NID_x509Certificate 158 +#define OBJ_x509Certificate OBJ_certTypes, 1L + +#define LN_sdsiCertificate "sdsiCertificate" +#define NID_sdsiCertificate 159 +#define OBJ_sdsiCertificate OBJ_certTypes, 2L + +#define OBJ_crlTypes OBJ_pkcs9, 23L + +#define LN_x509Crl "x509Crl" +#define NID_x509Crl 160 +#define OBJ_x509Crl OBJ_crlTypes, 1L + +/* PKCS#5 v2 OIDs */ + +#define LN_pbes2 "PBES2" +#define NID_pbes2 161 +#define OBJ_pbes2 OBJ_pkcs,5L,13L + +#define LN_pbmac1 "PBMAC1" +#define NID_pbmac1 162 +#define OBJ_pbmac1 OBJ_pkcs,5L,14L + +#define LN_hmacWithSHA1 "hmacWithSHA1" +#define NID_hmacWithSHA1 163 +#define OBJ_hmacWithSHA1 OBJ_rsadsi,2L,7L + +/* Policy Qualifier Ids */ + +#define LN_id_qt_cps "Policy Qualifier CPS" +#define SN_id_qt_cps "id-qt-cps" +#define NID_id_qt_cps 164 +#define OBJ_id_qt_cps OBJ_id_pkix,2L,1L + +#define LN_id_qt_unotice "Policy Qualifier User Notice" +#define SN_id_qt_unotice "id-qt-unotice" +#define NID_id_qt_unotice 165 +#define OBJ_id_qt_unotice OBJ_id_pkix,2L,2L + +#define SN_rc2_64_cbc "RC2-64-CBC" +#define LN_rc2_64_cbc "rc2-64-cbc" +#define NID_rc2_64_cbc 166 + +#define SN_SMIMECapabilities "SMIME-CAPS" +#define LN_SMIMECapabilities "S/MIME Capabilities" +#define NID_SMIMECapabilities 167 +#define OBJ_SMIMECapabilities OBJ_pkcs9,15L + +#define SN_pbeWithMD2AndRC2_CBC "PBE-MD2-RC2-64" +#define LN_pbeWithMD2AndRC2_CBC "pbeWithMD2AndRC2-CBC" +#define NID_pbeWithMD2AndRC2_CBC 168 +#define OBJ_pbeWithMD2AndRC2_CBC OBJ_pkcs,5L,4L + +#define SN_pbeWithMD5AndRC2_CBC "PBE-MD5-RC2-64" +#define LN_pbeWithMD5AndRC2_CBC "pbeWithMD5AndRC2-CBC" +#define NID_pbeWithMD5AndRC2_CBC 169 +#define OBJ_pbeWithMD5AndRC2_CBC OBJ_pkcs,5L,6L + +#define SN_pbeWithSHA1AndDES_CBC "PBE-SHA1-DES" +#define LN_pbeWithSHA1AndDES_CBC "pbeWithSHA1AndDES-CBC" +#define NID_pbeWithSHA1AndDES_CBC 170 +#define OBJ_pbeWithSHA1AndDES_CBC OBJ_pkcs,5L,10L + +/* Extension request OIDs */ + +#define LN_ms_ext_req "Microsoft Extension Request" +#define SN_ms_ext_req "msExtReq" +#define NID_ms_ext_req 171 +#define OBJ_ms_ext_req 1L,3L,6L,1L,4L,1L,311L,2L,1L,14L + +#define LN_ext_req "Extension Request" +#define SN_ext_req "extReq" +#define NID_ext_req 172 +#define OBJ_ext_req OBJ_pkcs9,14L + +#define SN_name "name" +#define LN_name "name" +#define NID_name 173 +#define OBJ_name OBJ_X509,41L + +#define SN_dnQualifier "dnQualifier" +#define LN_dnQualifier "dnQualifier" +#define NID_dnQualifier 174 +#define OBJ_dnQualifier OBJ_X509,46L + +#define SN_id_pe "id-pe" +#define NID_id_pe 175 +#define OBJ_id_pe OBJ_id_pkix,1L + +#define SN_id_ad "id-ad" +#define NID_id_ad 176 +#define OBJ_id_ad OBJ_id_pkix,48L + +#define SN_info_access "authorityInfoAccess" +#define LN_info_access "Authority Information Access" +#define NID_info_access 177 +#define OBJ_info_access OBJ_id_pe,1L + +#define SN_ad_OCSP "OCSP" +#define LN_ad_OCSP "OCSP" +#define NID_ad_OCSP 178 +#define OBJ_ad_OCSP OBJ_id_ad,1L + +#define SN_ad_ca_issuers "caIssuers" +#define LN_ad_ca_issuers "CA Issuers" +#define NID_ad_ca_issuers 179 +#define OBJ_ad_ca_issuers OBJ_id_ad,2L + +#define SN_OCSP_sign "OCSPSigning" +#define LN_OCSP_sign "OCSP Signing" +#define NID_OCSP_sign 180 +#define OBJ_OCSP_sign OBJ_id_kp,9L +#endif /* USE_OBJ_MAC */ + +#include +#include + +#define OBJ_NAME_TYPE_UNDEF 0x00 +#define OBJ_NAME_TYPE_MD_METH 0x01 +#define OBJ_NAME_TYPE_CIPHER_METH 0x02 +#define OBJ_NAME_TYPE_PKEY_METH 0x03 +#define OBJ_NAME_TYPE_COMP_METH 0x04 +#define OBJ_NAME_TYPE_NUM 0x05 + +#define OBJ_NAME_ALIAS 0x8000 + +#define OBJ_BSEARCH_VALUE_ON_NOMATCH 0x01 +#define OBJ_BSEARCH_FIRST_VALUE_ON_MATCH 0x02 + + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct obj_name_st + { + int type; + int alias; + const char *name; + const char *data; + } OBJ_NAME; + +#define OBJ_create_and_add_object(a,b,c) OBJ_create(a,b,c) + + +int OBJ_NAME_init(void); +int OBJ_NAME_new_index(unsigned long (*hash_func)(const char *), + int (*cmp_func)(const char *, const char *), + void (*free_func)(const char *, int, const char *)); +const char *OBJ_NAME_get(const char *name,int type); +int OBJ_NAME_add(const char *name,int type,const char *data); +int OBJ_NAME_remove(const char *name,int type); +void OBJ_NAME_cleanup(int type); /* -1 for everything */ +void OBJ_NAME_do_all(int type,void (*fn)(const OBJ_NAME *,void *arg), + void *arg); +void OBJ_NAME_do_all_sorted(int type,void (*fn)(const OBJ_NAME *,void *arg), + void *arg); + +ASN1_OBJECT * OBJ_dup(const ASN1_OBJECT *o); +ASN1_OBJECT * OBJ_nid2obj(int n); +const char * OBJ_nid2ln(int n); +const char * OBJ_nid2sn(int n); +int OBJ_obj2nid(const ASN1_OBJECT *o); +ASN1_OBJECT * OBJ_txt2obj(const char *s, int no_name); +int OBJ_obj2txt(char *buf, int buf_len, const ASN1_OBJECT *a, int no_name); +int OBJ_txt2nid(const char *s); +int OBJ_ln2nid(const char *s); +int OBJ_sn2nid(const char *s); +int OBJ_cmp(const ASN1_OBJECT *a,const ASN1_OBJECT *b); +const char * OBJ_bsearch(const char *key,const char *base,int num,int size, + int (*cmp)(const void *, const void *)); +const char * OBJ_bsearch_ex(const char *key,const char *base,int num, + int size, int (*cmp)(const void *, const void *), int flags); + +int OBJ_new_nid(int num); +int OBJ_add_object(const ASN1_OBJECT *obj); +int OBJ_create(const char *oid,const char *sn,const char *ln); +void OBJ_cleanup(void ); +int OBJ_create_objects(BIO *in); + +/* BEGIN ERROR CODES */ +/* The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ +void ERR_load_OBJ_strings(void); + +/* Error codes for the OBJ functions. */ + +/* Function codes. */ +#define OBJ_F_OBJ_ADD_OBJECT 105 +#define OBJ_F_OBJ_CREATE 100 +#define OBJ_F_OBJ_DUP 101 +#define OBJ_F_OBJ_NAME_NEW_INDEX 106 +#define OBJ_F_OBJ_NID2LN 102 +#define OBJ_F_OBJ_NID2OBJ 103 +#define OBJ_F_OBJ_NID2SN 104 + +/* Reason codes. */ +#define OBJ_R_MALLOC_FAILURE 100 +#define OBJ_R_UNKNOWN_NID 101 + +#ifdef __cplusplus +} +#endif +#endif diff --git a/lib_tls/include/openssl/ocsp.h b/lib_tls/include/openssl/ocsp.h new file mode 100644 index 000000000..4bda67322 --- /dev/null +++ b/lib_tls/include/openssl/ocsp.h @@ -0,0 +1,623 @@ +/* ocsp.h */ +/* Written by Tom Titchener for the OpenSSL + * project. */ + +/* History: + This file was transfered to Richard Levitte from CertCo by Kathy + Weinhold in mid-spring 2000 to be included in OpenSSL or released + as a patch kit. */ + +/* ==================================================================== + * Copyright (c) 1998-2000 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#ifndef HEADER_OCSP_H +#define HEADER_OCSP_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Various flags and values */ + +#define OCSP_DEFAULT_NONCE_LENGTH 16 + +#define OCSP_NOCERTS 0x1 +#define OCSP_NOINTERN 0x2 +#define OCSP_NOSIGS 0x4 +#define OCSP_NOCHAIN 0x8 +#define OCSP_NOVERIFY 0x10 +#define OCSP_NOEXPLICIT 0x20 +#define OCSP_NOCASIGN 0x40 +#define OCSP_NODELEGATED 0x80 +#define OCSP_NOCHECKS 0x100 +#define OCSP_TRUSTOTHER 0x200 +#define OCSP_RESPID_KEY 0x400 +#define OCSP_NOTIME 0x800 + +/* CertID ::= SEQUENCE { + * hashAlgorithm AlgorithmIdentifier, + * issuerNameHash OCTET STRING, -- Hash of Issuer's DN + * issuerKeyHash OCTET STRING, -- Hash of Issuers public key (excluding the tag & length fields) + * serialNumber CertificateSerialNumber } + */ +typedef struct ocsp_cert_id_st + { + X509_ALGOR *hashAlgorithm; + ASN1_OCTET_STRING *issuerNameHash; + ASN1_OCTET_STRING *issuerKeyHash; + ASN1_INTEGER *serialNumber; + } OCSP_CERTID; + +DECLARE_STACK_OF(OCSP_CERTID) + +/* Request ::= SEQUENCE { + * reqCert CertID, + * singleRequestExtensions [0] EXPLICIT Extensions OPTIONAL } + */ +typedef struct ocsp_one_request_st + { + OCSP_CERTID *reqCert; + STACK_OF(X509_EXTENSION) *singleRequestExtensions; + } OCSP_ONEREQ; + +DECLARE_STACK_OF(OCSP_ONEREQ) +DECLARE_ASN1_SET_OF(OCSP_ONEREQ) + + +/* TBSRequest ::= SEQUENCE { + * version [0] EXPLICIT Version DEFAULT v1, + * requestorName [1] EXPLICIT GeneralName OPTIONAL, + * requestList SEQUENCE OF Request, + * requestExtensions [2] EXPLICIT Extensions OPTIONAL } + */ +typedef struct ocsp_req_info_st + { + ASN1_INTEGER *version; + GENERAL_NAME *requestorName; + STACK_OF(OCSP_ONEREQ) *requestList; + STACK_OF(X509_EXTENSION) *requestExtensions; + } OCSP_REQINFO; + +/* Signature ::= SEQUENCE { + * signatureAlgorithm AlgorithmIdentifier, + * signature BIT STRING, + * certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL } + */ +typedef struct ocsp_signature_st + { + X509_ALGOR *signatureAlgorithm; + ASN1_BIT_STRING *signature; + STACK_OF(X509) *certs; + } OCSP_SIGNATURE; + +/* OCSPRequest ::= SEQUENCE { + * tbsRequest TBSRequest, + * optionalSignature [0] EXPLICIT Signature OPTIONAL } + */ +typedef struct ocsp_request_st + { + OCSP_REQINFO *tbsRequest; + OCSP_SIGNATURE *optionalSignature; /* OPTIONAL */ + } OCSP_REQUEST; + +/* OCSPResponseStatus ::= ENUMERATED { + * successful (0), --Response has valid confirmations + * malformedRequest (1), --Illegal confirmation request + * internalError (2), --Internal error in issuer + * tryLater (3), --Try again later + * --(4) is not used + * sigRequired (5), --Must sign the request + * unauthorized (6) --Request unauthorized + * } + */ +#define OCSP_RESPONSE_STATUS_SUCCESSFUL 0 +#define OCSP_RESPONSE_STATUS_MALFORMEDREQUEST 1 +#define OCSP_RESPONSE_STATUS_INTERNALERROR 2 +#define OCSP_RESPONSE_STATUS_TRYLATER 3 +#define OCSP_RESPONSE_STATUS_SIGREQUIRED 5 +#define OCSP_RESPONSE_STATUS_UNAUTHORIZED 6 + +/* ResponseBytes ::= SEQUENCE { + * responseType OBJECT IDENTIFIER, + * response OCTET STRING } + */ +typedef struct ocsp_resp_bytes_st + { + ASN1_OBJECT *responseType; + ASN1_OCTET_STRING *response; + } OCSP_RESPBYTES; + +/* OCSPResponse ::= SEQUENCE { + * responseStatus OCSPResponseStatus, + * responseBytes [0] EXPLICIT ResponseBytes OPTIONAL } + */ +typedef struct ocsp_response_st + { + ASN1_ENUMERATED *responseStatus; + OCSP_RESPBYTES *responseBytes; + } OCSP_RESPONSE; + +/* ResponderID ::= CHOICE { + * byName [1] Name, + * byKey [2] KeyHash } + */ +#define V_OCSP_RESPID_NAME 0 +#define V_OCSP_RESPID_KEY 1 +struct ocsp_responder_id_st + { + int type; + union { + X509_NAME* byName; + ASN1_OCTET_STRING *byKey; + } value; + }; + +DECLARE_STACK_OF(OCSP_RESPID) +DECLARE_ASN1_FUNCTIONS(OCSP_RESPID) + +/* KeyHash ::= OCTET STRING --SHA-1 hash of responder's public key + * --(excluding the tag and length fields) + */ + +/* RevokedInfo ::= SEQUENCE { + * revocationTime GeneralizedTime, + * revocationReason [0] EXPLICIT CRLReason OPTIONAL } + */ +typedef struct ocsp_revoked_info_st + { + ASN1_GENERALIZEDTIME *revocationTime; + ASN1_ENUMERATED *revocationReason; + } OCSP_REVOKEDINFO; + +/* CertStatus ::= CHOICE { + * good [0] IMPLICIT NULL, + * revoked [1] IMPLICIT RevokedInfo, + * unknown [2] IMPLICIT UnknownInfo } + */ +#define V_OCSP_CERTSTATUS_GOOD 0 +#define V_OCSP_CERTSTATUS_REVOKED 1 +#define V_OCSP_CERTSTATUS_UNKNOWN 2 +typedef struct ocsp_cert_status_st + { + int type; + union { + ASN1_NULL *good; + OCSP_REVOKEDINFO *revoked; + ASN1_NULL *unknown; + } value; + } OCSP_CERTSTATUS; + +/* SingleResponse ::= SEQUENCE { + * certID CertID, + * certStatus CertStatus, + * thisUpdate GeneralizedTime, + * nextUpdate [0] EXPLICIT GeneralizedTime OPTIONAL, + * singleExtensions [1] EXPLICIT Extensions OPTIONAL } + */ +typedef struct ocsp_single_response_st + { + OCSP_CERTID *certId; + OCSP_CERTSTATUS *certStatus; + ASN1_GENERALIZEDTIME *thisUpdate; + ASN1_GENERALIZEDTIME *nextUpdate; + STACK_OF(X509_EXTENSION) *singleExtensions; + } OCSP_SINGLERESP; + +DECLARE_STACK_OF(OCSP_SINGLERESP) +DECLARE_ASN1_SET_OF(OCSP_SINGLERESP) + +/* ResponseData ::= SEQUENCE { + * version [0] EXPLICIT Version DEFAULT v1, + * responderID ResponderID, + * producedAt GeneralizedTime, + * responses SEQUENCE OF SingleResponse, + * responseExtensions [1] EXPLICIT Extensions OPTIONAL } + */ +typedef struct ocsp_response_data_st + { + ASN1_INTEGER *version; + OCSP_RESPID *responderId; + ASN1_GENERALIZEDTIME *producedAt; + STACK_OF(OCSP_SINGLERESP) *responses; + STACK_OF(X509_EXTENSION) *responseExtensions; + } OCSP_RESPDATA; + +/* BasicOCSPResponse ::= SEQUENCE { + * tbsResponseData ResponseData, + * signatureAlgorithm AlgorithmIdentifier, + * signature BIT STRING, + * certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL } + */ + /* Note 1: + The value for "signature" is specified in the OCSP rfc2560 as follows: + "The value for the signature SHALL be computed on the hash of the DER + encoding ResponseData." This means that you must hash the DER-encoded + tbsResponseData, and then run it through a crypto-signing function, which + will (at least w/RSA) do a hash-'n'-private-encrypt operation. This seems + a bit odd, but that's the spec. Also note that the data structures do not + leave anywhere to independently specify the algorithm used for the initial + hash. So, we look at the signature-specification algorithm, and try to do + something intelligent. -- Kathy Weinhold, CertCo */ + /* Note 2: + It seems that the mentioned passage from RFC 2560 (section 4.2.1) is open + for interpretation. I've done tests against another responder, and found + that it doesn't do the double hashing that the RFC seems to say one + should. Therefore, all relevant functions take a flag saying which + variant should be used. -- Richard Levitte, OpenSSL team and CeloCom */ +typedef struct ocsp_basic_response_st + { + OCSP_RESPDATA *tbsResponseData; + X509_ALGOR *signatureAlgorithm; + ASN1_BIT_STRING *signature; + STACK_OF(X509) *certs; + } OCSP_BASICRESP; + +/* + * CRLReason ::= ENUMERATED { + * unspecified (0), + * keyCompromise (1), + * cACompromise (2), + * affiliationChanged (3), + * superseded (4), + * cessationOfOperation (5), + * certificateHold (6), + * removeFromCRL (8) } + */ +#define OCSP_REVOKED_STATUS_NOSTATUS -1 +#define OCSP_REVOKED_STATUS_UNSPECIFIED 0 +#define OCSP_REVOKED_STATUS_KEYCOMPROMISE 1 +#define OCSP_REVOKED_STATUS_CACOMPROMISE 2 +#define OCSP_REVOKED_STATUS_AFFILIATIONCHANGED 3 +#define OCSP_REVOKED_STATUS_SUPERSEDED 4 +#define OCSP_REVOKED_STATUS_CESSATIONOFOPERATION 5 +#define OCSP_REVOKED_STATUS_CERTIFICATEHOLD 6 +#define OCSP_REVOKED_STATUS_REMOVEFROMCRL 8 + +/* CrlID ::= SEQUENCE { + * crlUrl [0] EXPLICIT IA5String OPTIONAL, + * crlNum [1] EXPLICIT INTEGER OPTIONAL, + * crlTime [2] EXPLICIT GeneralizedTime OPTIONAL } + */ +typedef struct ocsp_crl_id_st + { + ASN1_IA5STRING *crlUrl; + ASN1_INTEGER *crlNum; + ASN1_GENERALIZEDTIME *crlTime; + } OCSP_CRLID; + +/* ServiceLocator ::= SEQUENCE { + * issuer Name, + * locator AuthorityInfoAccessSyntax OPTIONAL } + */ +typedef struct ocsp_service_locator_st + { + X509_NAME* issuer; + STACK_OF(ACCESS_DESCRIPTION) *locator; + } OCSP_SERVICELOC; + +#define PEM_STRING_OCSP_REQUEST "OCSP REQUEST" +#define PEM_STRING_OCSP_RESPONSE "OCSP RESPONSE" + +#define d2i_OCSP_REQUEST_bio(bp,p) ASN1_d2i_bio_of(OCSP_REQUEST,OCSP_REQUEST_new,d2i_OCSP_REQUEST,bp,p) + +#define d2i_OCSP_RESPONSE_bio(bp,p) ASN1_d2i_bio_of(OCSP_RESPONSE,OCSP_RESPONSE_new,d2i_OCSP_RESPONSE,bp,p) + +#define PEM_read_bio_OCSP_REQUEST(bp,x,cb) (OCSP_REQUEST *)PEM_ASN1_read_bio( \ + (char *(*)())d2i_OCSP_REQUEST,PEM_STRING_OCSP_REQUEST,bp,(char **)x,cb,NULL) + +#define PEM_read_bio_OCSP_RESPONSE(bp,x,cb)(OCSP_RESPONSE *)PEM_ASN1_read_bio(\ + (char *(*)())d2i_OCSP_RESPONSE,PEM_STRING_OCSP_RESPONSE,bp,(char **)x,cb,NULL) + +#define PEM_write_bio_OCSP_REQUEST(bp,o) \ + PEM_ASN1_write_bio((int (*)())i2d_OCSP_REQUEST,PEM_STRING_OCSP_REQUEST,\ + bp,(char *)o, NULL,NULL,0,NULL,NULL) + +#define PEM_write_bio_OCSP_RESPONSE(bp,o) \ + PEM_ASN1_write_bio((int (*)())i2d_OCSP_RESPONSE,PEM_STRING_OCSP_RESPONSE,\ + bp,(char *)o, NULL,NULL,0,NULL,NULL) + +#define i2d_OCSP_RESPONSE_bio(bp,o) ASN1_i2d_bio_of(OCSP_RESPONSE,i2d_OCSP_RESPONSE,bp,o) + +#define i2d_OCSP_REQUEST_bio(bp,o) ASN1_i2d_bio_of(OCSP_REQUEST,i2d_OCSP_REQUEST,bp,o) + +#define OCSP_REQUEST_sign(o,pkey,md) \ + ASN1_item_sign(ASN1_ITEM_rptr(OCSP_REQINFO),\ + o->optionalSignature->signatureAlgorithm,NULL,\ + o->optionalSignature->signature,o->tbsRequest,pkey,md) + +#define OCSP_BASICRESP_sign(o,pkey,md,d) \ + ASN1_item_sign(ASN1_ITEM_rptr(OCSP_RESPDATA),o->signatureAlgorithm,NULL,\ + o->signature,o->tbsResponseData,pkey,md) + +#define OCSP_REQUEST_verify(a,r) ASN1_item_verify(ASN1_ITEM_rptr(OCSP_REQINFO),\ + a->optionalSignature->signatureAlgorithm,\ + a->optionalSignature->signature,a->tbsRequest,r) + +#define OCSP_BASICRESP_verify(a,r,d) ASN1_item_verify(ASN1_ITEM_rptr(OCSP_RESPDATA),\ + a->signatureAlgorithm,a->signature,a->tbsResponseData,r) + +#define ASN1_BIT_STRING_digest(data,type,md,len) \ + ASN1_item_digest(ASN1_ITEM_rptr(ASN1_BIT_STRING),type,data,md,len) + +#define OCSP_CERTID_dup(cid) ASN1_dup_of(OCSP_CERTID,i2d_OCSP_CERTID,d2i_OCSP_CERTID,cid) + +#define OCSP_CERTSTATUS_dup(cs)\ + (OCSP_CERTSTATUS*)ASN1_dup((int(*)())i2d_OCSP_CERTSTATUS,\ + (char *(*)())d2i_OCSP_CERTSTATUS,(char *)(cs)) + +OCSP_RESPONSE *OCSP_sendreq_bio(BIO *b, char *path, OCSP_REQUEST *req); +OCSP_REQ_CTX *OCSP_sendreq_new(BIO *io, char *path, OCSP_REQUEST *req, + int maxline); +int OCSP_sendreq_nbio(OCSP_RESPONSE **presp, OCSP_REQ_CTX *rctx); +void OCSP_REQ_CTX_free(OCSP_REQ_CTX *rctx); + +OCSP_CERTID *OCSP_cert_to_id(const EVP_MD *dgst, X509 *subject, X509 *issuer); + +OCSP_CERTID *OCSP_cert_id_new(const EVP_MD *dgst, + X509_NAME *issuerName, + ASN1_BIT_STRING* issuerKey, + ASN1_INTEGER *serialNumber); + +OCSP_ONEREQ *OCSP_request_add0_id(OCSP_REQUEST *req, OCSP_CERTID *cid); + +int OCSP_request_add1_nonce(OCSP_REQUEST *req, unsigned char *val, int len); +int OCSP_basic_add1_nonce(OCSP_BASICRESP *resp, unsigned char *val, int len); +int OCSP_check_nonce(OCSP_REQUEST *req, OCSP_BASICRESP *bs); +int OCSP_copy_nonce(OCSP_BASICRESP *resp, OCSP_REQUEST *req); + +int OCSP_request_set1_name(OCSP_REQUEST *req, X509_NAME *nm); +int OCSP_request_add1_cert(OCSP_REQUEST *req, X509 *cert); + +int OCSP_request_sign(OCSP_REQUEST *req, + X509 *signer, + EVP_PKEY *key, + const EVP_MD *dgst, + STACK_OF(X509) *certs, + unsigned long flags); + +int OCSP_response_status(OCSP_RESPONSE *resp); +OCSP_BASICRESP *OCSP_response_get1_basic(OCSP_RESPONSE *resp); + +int OCSP_resp_count(OCSP_BASICRESP *bs); +OCSP_SINGLERESP *OCSP_resp_get0(OCSP_BASICRESP *bs, int idx); +int OCSP_resp_find(OCSP_BASICRESP *bs, OCSP_CERTID *id, int last); +int OCSP_single_get0_status(OCSP_SINGLERESP *single, int *reason, + ASN1_GENERALIZEDTIME **revtime, + ASN1_GENERALIZEDTIME **thisupd, + ASN1_GENERALIZEDTIME **nextupd); +int OCSP_resp_find_status(OCSP_BASICRESP *bs, OCSP_CERTID *id, int *status, + int *reason, + ASN1_GENERALIZEDTIME **revtime, + ASN1_GENERALIZEDTIME **thisupd, + ASN1_GENERALIZEDTIME **nextupd); +int OCSP_check_validity(ASN1_GENERALIZEDTIME *thisupd, + ASN1_GENERALIZEDTIME *nextupd, + long sec, long maxsec); + +int OCSP_request_verify(OCSP_REQUEST *req, STACK_OF(X509) *certs, X509_STORE *store, unsigned long flags); + +int OCSP_parse_url(char *url, char **phost, char **pport, char **ppath, int *pssl); + +int OCSP_id_issuer_cmp(OCSP_CERTID *a, OCSP_CERTID *b); +int OCSP_id_cmp(OCSP_CERTID *a, OCSP_CERTID *b); + +int OCSP_request_onereq_count(OCSP_REQUEST *req); +OCSP_ONEREQ *OCSP_request_onereq_get0(OCSP_REQUEST *req, int i); +OCSP_CERTID *OCSP_onereq_get0_id(OCSP_ONEREQ *one); +int OCSP_id_get0_info(ASN1_OCTET_STRING **piNameHash, ASN1_OBJECT **pmd, + ASN1_OCTET_STRING **pikeyHash, + ASN1_INTEGER **pserial, OCSP_CERTID *cid); +int OCSP_request_is_signed(OCSP_REQUEST *req); +OCSP_RESPONSE *OCSP_response_create(int status, OCSP_BASICRESP *bs); +OCSP_SINGLERESP *OCSP_basic_add1_status(OCSP_BASICRESP *rsp, + OCSP_CERTID *cid, + int status, int reason, + ASN1_TIME *revtime, + ASN1_TIME *thisupd, ASN1_TIME *nextupd); +int OCSP_basic_add1_cert(OCSP_BASICRESP *resp, X509 *cert); +int OCSP_basic_sign(OCSP_BASICRESP *brsp, + X509 *signer, EVP_PKEY *key, const EVP_MD *dgst, + STACK_OF(X509) *certs, unsigned long flags); + +ASN1_STRING *ASN1_STRING_encode(ASN1_STRING *s, i2d_of_void *i2d, + void *data, STACK_OF(ASN1_OBJECT) *sk); +#define ASN1_STRING_encode_of(type,s,i2d,data,sk) \ + ASN1_STRING_encode(s, CHECKED_I2D_OF(type, i2d), data, sk) + +X509_EXTENSION *OCSP_crlID_new(char *url, long *n, char *tim); + +X509_EXTENSION *OCSP_accept_responses_new(char **oids); + +X509_EXTENSION *OCSP_archive_cutoff_new(char* tim); + +X509_EXTENSION *OCSP_url_svcloc_new(X509_NAME* issuer, char **urls); + +int OCSP_REQUEST_get_ext_count(OCSP_REQUEST *x); +int OCSP_REQUEST_get_ext_by_NID(OCSP_REQUEST *x, int nid, int lastpos); +int OCSP_REQUEST_get_ext_by_OBJ(OCSP_REQUEST *x, ASN1_OBJECT *obj, int lastpos); +int OCSP_REQUEST_get_ext_by_critical(OCSP_REQUEST *x, int crit, int lastpos); +X509_EXTENSION *OCSP_REQUEST_get_ext(OCSP_REQUEST *x, int loc); +X509_EXTENSION *OCSP_REQUEST_delete_ext(OCSP_REQUEST *x, int loc); +void *OCSP_REQUEST_get1_ext_d2i(OCSP_REQUEST *x, int nid, int *crit, int *idx); +int OCSP_REQUEST_add1_ext_i2d(OCSP_REQUEST *x, int nid, void *value, int crit, + unsigned long flags); +int OCSP_REQUEST_add_ext(OCSP_REQUEST *x, X509_EXTENSION *ex, int loc); + +int OCSP_ONEREQ_get_ext_count(OCSP_ONEREQ *x); +int OCSP_ONEREQ_get_ext_by_NID(OCSP_ONEREQ *x, int nid, int lastpos); +int OCSP_ONEREQ_get_ext_by_OBJ(OCSP_ONEREQ *x, ASN1_OBJECT *obj, int lastpos); +int OCSP_ONEREQ_get_ext_by_critical(OCSP_ONEREQ *x, int crit, int lastpos); +X509_EXTENSION *OCSP_ONEREQ_get_ext(OCSP_ONEREQ *x, int loc); +X509_EXTENSION *OCSP_ONEREQ_delete_ext(OCSP_ONEREQ *x, int loc); +void *OCSP_ONEREQ_get1_ext_d2i(OCSP_ONEREQ *x, int nid, int *crit, int *idx); +int OCSP_ONEREQ_add1_ext_i2d(OCSP_ONEREQ *x, int nid, void *value, int crit, + unsigned long flags); +int OCSP_ONEREQ_add_ext(OCSP_ONEREQ *x, X509_EXTENSION *ex, int loc); + +int OCSP_BASICRESP_get_ext_count(OCSP_BASICRESP *x); +int OCSP_BASICRESP_get_ext_by_NID(OCSP_BASICRESP *x, int nid, int lastpos); +int OCSP_BASICRESP_get_ext_by_OBJ(OCSP_BASICRESP *x, ASN1_OBJECT *obj, int lastpos); +int OCSP_BASICRESP_get_ext_by_critical(OCSP_BASICRESP *x, int crit, int lastpos); +X509_EXTENSION *OCSP_BASICRESP_get_ext(OCSP_BASICRESP *x, int loc); +X509_EXTENSION *OCSP_BASICRESP_delete_ext(OCSP_BASICRESP *x, int loc); +void *OCSP_BASICRESP_get1_ext_d2i(OCSP_BASICRESP *x, int nid, int *crit, int *idx); +int OCSP_BASICRESP_add1_ext_i2d(OCSP_BASICRESP *x, int nid, void *value, int crit, + unsigned long flags); +int OCSP_BASICRESP_add_ext(OCSP_BASICRESP *x, X509_EXTENSION *ex, int loc); + +int OCSP_SINGLERESP_get_ext_count(OCSP_SINGLERESP *x); +int OCSP_SINGLERESP_get_ext_by_NID(OCSP_SINGLERESP *x, int nid, int lastpos); +int OCSP_SINGLERESP_get_ext_by_OBJ(OCSP_SINGLERESP *x, ASN1_OBJECT *obj, int lastpos); +int OCSP_SINGLERESP_get_ext_by_critical(OCSP_SINGLERESP *x, int crit, int lastpos); +X509_EXTENSION *OCSP_SINGLERESP_get_ext(OCSP_SINGLERESP *x, int loc); +X509_EXTENSION *OCSP_SINGLERESP_delete_ext(OCSP_SINGLERESP *x, int loc); +void *OCSP_SINGLERESP_get1_ext_d2i(OCSP_SINGLERESP *x, int nid, int *crit, int *idx); +int OCSP_SINGLERESP_add1_ext_i2d(OCSP_SINGLERESP *x, int nid, void *value, int crit, + unsigned long flags); +int OCSP_SINGLERESP_add_ext(OCSP_SINGLERESP *x, X509_EXTENSION *ex, int loc); + +DECLARE_ASN1_FUNCTIONS(OCSP_SINGLERESP) +DECLARE_ASN1_FUNCTIONS(OCSP_CERTSTATUS) +DECLARE_ASN1_FUNCTIONS(OCSP_REVOKEDINFO) +DECLARE_ASN1_FUNCTIONS(OCSP_BASICRESP) +DECLARE_ASN1_FUNCTIONS(OCSP_RESPDATA) +DECLARE_ASN1_FUNCTIONS(OCSP_RESPID) +DECLARE_ASN1_FUNCTIONS(OCSP_RESPONSE) +DECLARE_ASN1_FUNCTIONS(OCSP_RESPBYTES) +DECLARE_ASN1_FUNCTIONS(OCSP_ONEREQ) +DECLARE_ASN1_FUNCTIONS(OCSP_CERTID) +DECLARE_ASN1_FUNCTIONS(OCSP_REQUEST) +DECLARE_ASN1_FUNCTIONS(OCSP_SIGNATURE) +DECLARE_ASN1_FUNCTIONS(OCSP_REQINFO) +DECLARE_ASN1_FUNCTIONS(OCSP_CRLID) +DECLARE_ASN1_FUNCTIONS(OCSP_SERVICELOC) + +char *OCSP_response_status_str(long s); +char *OCSP_cert_status_str(long s); +char *OCSP_crl_reason_str(long s); + +int OCSP_REQUEST_print(BIO *bp, OCSP_REQUEST* a, unsigned long flags); +int OCSP_RESPONSE_print(BIO *bp, OCSP_RESPONSE* o, unsigned long flags); + +int OCSP_basic_verify(OCSP_BASICRESP *bs, STACK_OF(X509) *certs, + X509_STORE *st, unsigned long flags); + +/* BEGIN ERROR CODES */ +/* The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ +void ERR_load_OCSP_strings(void); + +/* Error codes for the OCSP functions. */ + +/* Function codes. */ +#define OCSP_F_ASN1_STRING_ENCODE 100 +#define OCSP_F_D2I_OCSP_NONCE 102 +#define OCSP_F_OCSP_BASIC_ADD1_STATUS 103 +#define OCSP_F_OCSP_BASIC_SIGN 104 +#define OCSP_F_OCSP_BASIC_VERIFY 105 +#define OCSP_F_OCSP_CERT_ID_NEW 101 +#define OCSP_F_OCSP_CHECK_DELEGATED 106 +#define OCSP_F_OCSP_CHECK_IDS 107 +#define OCSP_F_OCSP_CHECK_ISSUER 108 +#define OCSP_F_OCSP_CHECK_VALIDITY 115 +#define OCSP_F_OCSP_MATCH_ISSUERID 109 +#define OCSP_F_OCSP_PARSE_URL 114 +#define OCSP_F_OCSP_REQUEST_SIGN 110 +#define OCSP_F_OCSP_REQUEST_VERIFY 116 +#define OCSP_F_OCSP_RESPONSE_GET1_BASIC 111 +#define OCSP_F_OCSP_SENDREQ_BIO 112 +#define OCSP_F_PARSE_HTTP_LINE1 117 +#define OCSP_F_REQUEST_VERIFY 113 + +/* Reason codes. */ +#define OCSP_R_BAD_DATA 100 +#define OCSP_R_CERTIFICATE_VERIFY_ERROR 101 +#define OCSP_R_DIGEST_ERR 102 +#define OCSP_R_ERROR_IN_NEXTUPDATE_FIELD 122 +#define OCSP_R_ERROR_IN_THISUPDATE_FIELD 123 +#define OCSP_R_ERROR_PARSING_URL 121 +#define OCSP_R_MISSING_OCSPSIGNING_USAGE 103 +#define OCSP_R_NEXTUPDATE_BEFORE_THISUPDATE 124 +#define OCSP_R_NOT_BASIC_RESPONSE 104 +#define OCSP_R_NO_CERTIFICATES_IN_CHAIN 105 +#define OCSP_R_NO_CONTENT 106 +#define OCSP_R_NO_PUBLIC_KEY 107 +#define OCSP_R_NO_RESPONSE_DATA 108 +#define OCSP_R_NO_REVOKED_TIME 109 +#define OCSP_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE 110 +#define OCSP_R_REQUEST_NOT_SIGNED 128 +#define OCSP_R_RESPONSE_CONTAINS_NO_REVOCATION_DATA 111 +#define OCSP_R_ROOT_CA_NOT_TRUSTED 112 +#define OCSP_R_SERVER_READ_ERROR 113 +#define OCSP_R_SERVER_RESPONSE_ERROR 114 +#define OCSP_R_SERVER_RESPONSE_PARSE_ERROR 115 +#define OCSP_R_SERVER_WRITE_ERROR 116 +#define OCSP_R_SIGNATURE_FAILURE 117 +#define OCSP_R_SIGNER_CERTIFICATE_NOT_FOUND 118 +#define OCSP_R_STATUS_EXPIRED 125 +#define OCSP_R_STATUS_NOT_YET_VALID 126 +#define OCSP_R_STATUS_TOO_OLD 127 +#define OCSP_R_UNKNOWN_MESSAGE_DIGEST 119 +#define OCSP_R_UNKNOWN_NID 120 +#define OCSP_R_UNSUPPORTED_REQUESTORNAME_TYPE 129 + +#ifdef __cplusplus +} +#endif +#endif diff --git a/lib_tls/include/openssl/opensslconf.h b/lib_tls/include/openssl/opensslconf.h new file mode 100644 index 000000000..0850d4a69 --- /dev/null +++ b/lib_tls/include/openssl/opensslconf.h @@ -0,0 +1,232 @@ +/* opensslconf.h */ +/* WARNING: Generated automatically from opensslconf.h.in by Configure. */ + +/* OpenSSL was configured with the following options: */ +#ifndef OPENSSL_DOING_MAKEDEPEND + +#ifndef OPENSSL_NO_CAMELLIA +# define OPENSSL_NO_CAMELLIA +#endif +#ifndef OPENSSL_NO_CMS +# define OPENSSL_NO_CMS +#endif +#ifndef OPENSSL_NO_GMP +# define OPENSSL_NO_GMP +#endif +#ifndef OPENSSL_NO_KRB5 +# define OPENSSL_NO_KRB5 +#endif +#ifndef OPENSSL_NO_MDC2 +# define OPENSSL_NO_MDC2 +#endif +#ifndef OPENSSL_NO_RC5 +# define OPENSSL_NO_RC5 +#endif +#ifndef OPENSSL_NO_RFC3779 +# define OPENSSL_NO_RFC3779 +#endif +#ifndef OPENSSL_NO_SEED +# define OPENSSL_NO_SEED +#endif +#ifndef OPENSSL_NO_TLSEXT +# define OPENSSL_NO_TLSEXT +#endif + +#endif /* OPENSSL_DOING_MAKEDEPEND */ +#ifndef OPENSSL_NO_DYNAMIC_ENGINE +# define OPENSSL_NO_DYNAMIC_ENGINE +#endif + +/* The OPENSSL_NO_* macros are also defined as NO_* if the application + asks for it. This is a transient feature that is provided for those + who haven't had the time to do the appropriate changes in their + applications. */ +#ifdef OPENSSL_ALGORITHM_DEFINES +# if defined(OPENSSL_NO_CAMELLIA) && !defined(NO_CAMELLIA) +# define NO_CAMELLIA +# endif +# if defined(OPENSSL_NO_CMS) && !defined(NO_CMS) +# define NO_CMS +# endif +# if defined(OPENSSL_NO_GMP) && !defined(NO_GMP) +# define NO_GMP +# endif +# if defined(OPENSSL_NO_KRB5) && !defined(NO_KRB5) +# define NO_KRB5 +# endif +# if defined(OPENSSL_NO_MDC2) && !defined(NO_MDC2) +# define NO_MDC2 +# endif +# if defined(OPENSSL_NO_RC5) && !defined(NO_RC5) +# define NO_RC5 +# endif +# if defined(OPENSSL_NO_RFC3779) && !defined(NO_RFC3779) +# define NO_RFC3779 +# endif +# if defined(OPENSSL_NO_SEED) && !defined(NO_SEED) +# define NO_SEED +# endif +# if defined(OPENSSL_NO_TLSEXT) && !defined(NO_TLSEXT) +# define NO_TLSEXT +# endif +#endif + +/* crypto/opensslconf.h.in */ + +/* Generate 80386 code? */ +#undef I386_ONLY + +#if !(defined(VMS) || defined(__VMS)) /* VMS uses logical names instead */ +#if defined(HEADER_CRYPTLIB_H) && !defined(OPENSSLDIR) +#define ENGINESDIR "/usr/local/ssl/lib/engines" +#define OPENSSLDIR "/usr/local/ssl" +#endif +#endif + +#undef OPENSSL_UNISTD +#define OPENSSL_UNISTD + +#undef OPENSSL_EXPORT_VAR_AS_FUNCTION + +#if defined(HEADER_IDEA_H) && !defined(IDEA_INT) +#define IDEA_INT unsigned int +#endif + +#if defined(HEADER_MD2_H) && !defined(MD2_INT) +#define MD2_INT unsigned int +#endif + +#if defined(HEADER_RC2_H) && !defined(RC2_INT) +/* I need to put in a mod for the alpha - eay */ +#define RC2_INT unsigned int +#endif + +#if defined(HEADER_RC4_H) +#if !defined(RC4_INT) +/* using int types make the structure larger but make the code faster + * on most boxes I have tested - up to %20 faster. */ +/* + * I don't know what does "most" mean, but declaring "int" is a must on: + * - Intel P6 because partial register stalls are very expensive; + * - elder Alpha because it lacks byte load/store instructions; + */ +#define RC4_INT unsigned int +#endif +#if !defined(RC4_CHUNK) +/* + * This enables code handling data aligned at natural CPU word + * boundary. See crypto/rc4/rc4_enc.c for further details. + */ +#undef RC4_CHUNK +#endif +#endif + +#if (defined(HEADER_NEW_DES_H) || defined(HEADER_DES_H)) && !defined(DES_LONG) +/* If this is set to 'unsigned int' on a DEC Alpha, this gives about a + * %20 speed up (longs are 8 bytes, int's are 4). */ +#ifndef DES_LONG +#define DES_LONG unsigned long +#endif +#endif + +#if defined(HEADER_BN_H) && !defined(CONFIG_HEADER_BN_H) +#define CONFIG_HEADER_BN_H +#undef BN_LLONG + +/* Should we define BN_DIV2W here? */ + +/* Only one for the following should be defined */ +/* The prime number generation stuff may not work when + * EIGHT_BIT but I don't care since I've only used this mode + * for debuging the bignum libraries */ +#undef SIXTY_FOUR_BIT_LONG +#undef SIXTY_FOUR_BIT +#define THIRTY_TWO_BIT +#undef SIXTEEN_BIT +#undef EIGHT_BIT +#endif + +#if defined(HEADER_RC4_LOCL_H) && !defined(CONFIG_HEADER_RC4_LOCL_H) +#define CONFIG_HEADER_RC4_LOCL_H +/* if this is defined data[i] is used instead of *data, this is a %20 + * speedup on x86 */ +#undef RC4_INDEX +#endif + +#if defined(HEADER_BF_LOCL_H) && !defined(CONFIG_HEADER_BF_LOCL_H) +#define CONFIG_HEADER_BF_LOCL_H +#undef BF_PTR +#endif /* HEADER_BF_LOCL_H */ + +#if defined(HEADER_DES_LOCL_H) && !defined(CONFIG_HEADER_DES_LOCL_H) +#define CONFIG_HEADER_DES_LOCL_H +#ifndef DES_DEFAULT_OPTIONS +/* the following is tweaked from a config script, that is why it is a + * protected undef/define */ +#ifndef DES_PTR +#undef DES_PTR +#endif + +/* This helps C compiler generate the correct code for multiple functional + * units. It reduces register dependancies at the expense of 2 more + * registers */ +#ifndef DES_RISC1 +#undef DES_RISC1 +#endif + +#ifndef DES_RISC2 +#undef DES_RISC2 +#endif + +#if defined(DES_RISC1) && defined(DES_RISC2) +YOU SHOULD NOT HAVE BOTH DES_RISC1 AND DES_RISC2 DEFINED!!!!! +#endif + +/* Unroll the inner loop, this sometimes helps, sometimes hinders. + * Very mucy CPU dependant */ +#ifndef DES_UNROLL +#undef DES_UNROLL +#endif + +/* These default values were supplied by + * Peter Gutman + * They are only used if nothing else has been defined */ +#if !defined(DES_PTR) && !defined(DES_RISC1) && !defined(DES_RISC2) && !defined(DES_UNROLL) +/* Special defines which change the way the code is built depending on the + CPU and OS. For SGI machines you can use _MIPS_SZLONG (32 or 64) to find + even newer MIPS CPU's, but at the moment one size fits all for + optimization options. Older Sparc's work better with only UNROLL, but + there's no way to tell at compile time what it is you're running on */ + +#if defined( sun ) /* Newer Sparc's */ +# define DES_PTR +# define DES_RISC1 +# define DES_UNROLL +#elif defined( __ultrix ) /* Older MIPS */ +# define DES_PTR +# define DES_RISC2 +# define DES_UNROLL +#elif defined( __osf1__ ) /* Alpha */ +# define DES_PTR +# define DES_RISC2 +#elif defined ( _AIX ) /* RS6000 */ + /* Unknown */ +#elif defined( __hpux ) /* HP-PA */ + /* Unknown */ +#elif defined( __aux ) /* 68K */ + /* Unknown */ +#elif defined( __dgux ) /* 88K (but P6 in latest boxes) */ +# define DES_UNROLL +#elif defined( __sgi ) /* Newer MIPS */ +# define DES_PTR +# define DES_RISC2 +# define DES_UNROLL +#elif defined(i386) || defined(__i386__) /* x86 boxes, should be gcc */ +# define DES_PTR +# define DES_RISC1 +# define DES_UNROLL +#endif /* Systems-specific speed defines */ +#endif + +#endif /* DES_DEFAULT_OPTIONS */ +#endif /* HEADER_DES_LOCL_H */ diff --git a/lib_tls/include/openssl/opensslv.h b/lib_tls/include/openssl/opensslv.h new file mode 100644 index 000000000..b308894f1 --- /dev/null +++ b/lib_tls/include/openssl/opensslv.h @@ -0,0 +1,89 @@ +#ifndef HEADER_OPENSSLV_H +#define HEADER_OPENSSLV_H + +/* Numeric release version identifier: + * MNNFFPPS: major minor fix patch status + * The status nibble has one of the values 0 for development, 1 to e for betas + * 1 to 14, and f for release. The patch level is exactly that. + * For example: + * 0.9.3-dev 0x00903000 + * 0.9.3-beta1 0x00903001 + * 0.9.3-beta2-dev 0x00903002 + * 0.9.3-beta2 0x00903002 (same as ...beta2-dev) + * 0.9.3 0x0090300f + * 0.9.3a 0x0090301f + * 0.9.4 0x0090400f + * 1.2.3z 0x102031af + * + * For continuity reasons (because 0.9.5 is already out, and is coded + * 0x00905100), between 0.9.5 and 0.9.6 the coding of the patch level + * part is slightly different, by setting the highest bit. This means + * that 0.9.5a looks like this: 0x0090581f. At 0.9.6, we can start + * with 0x0090600S... + * + * (Prior to 0.9.3-dev a different scheme was used: 0.9.2b is 0x0922.) + * (Prior to 0.9.5a beta1, a different scheme was used: MMNNFFRBB for + * major minor fix final patch/beta) + */ +#define OPENSSL_VERSION_NUMBER 0x0090808fL +#ifdef OPENSSL_FIPS +#define OPENSSL_VERSION_TEXT "OpenSSL 0.9.8h-fips 28 May 2008" +#else +#define OPENSSL_VERSION_TEXT "OpenSSL 0.9.8h 28 May 2008" +#endif +#define OPENSSL_VERSION_PTEXT " part of " OPENSSL_VERSION_TEXT + + +/* The macros below are to be used for shared library (.so, .dll, ...) + * versioning. That kind of versioning works a bit differently between + * operating systems. The most usual scheme is to set a major and a minor + * number, and have the runtime loader check that the major number is equal + * to what it was at application link time, while the minor number has to + * be greater or equal to what it was at application link time. With this + * scheme, the version number is usually part of the file name, like this: + * + * libcrypto.so.0.9 + * + * Some unixen also make a softlink with the major verson number only: + * + * libcrypto.so.0 + * + * On Tru64 and IRIX 6.x it works a little bit differently. There, the + * shared library version is stored in the file, and is actually a series + * of versions, separated by colons. The rightmost version present in the + * library when linking an application is stored in the application to be + * matched at run time. When the application is run, a check is done to + * see if the library version stored in the application matches any of the + * versions in the version string of the library itself. + * This version string can be constructed in any way, depending on what + * kind of matching is desired. However, to implement the same scheme as + * the one used in the other unixen, all compatible versions, from lowest + * to highest, should be part of the string. Consecutive builds would + * give the following versions strings: + * + * 3.0 + * 3.0:3.1 + * 3.0:3.1:3.2 + * 4.0 + * 4.0:4.1 + * + * Notice how version 4 is completely incompatible with version, and + * therefore give the breach you can see. + * + * There may be other schemes as well that I haven't yet discovered. + * + * So, here's the way it works here: first of all, the library version + * number doesn't need at all to match the overall OpenSSL version. + * However, it's nice and more understandable if it actually does. + * The current library version is stored in the macro SHLIB_VERSION_NUMBER, + * which is just a piece of text in the format "M.m.e" (Major, minor, edit). + * For the sake of Tru64, IRIX, and any other OS that behaves in similar ways, + * we need to keep a history of version numbers, which is done in the + * macro SHLIB_VERSION_HISTORY. The numbers are separated by colons and + * should only keep the versions that are binary compatible with the current. + */ +#define SHLIB_VERSION_HISTORY "" +#define SHLIB_VERSION_NUMBER "0.9.8" + + +#endif /* HEADER_OPENSSLV_H */ diff --git a/lib_tls/include/openssl/ossl_typ.h b/lib_tls/include/openssl/ossl_typ.h new file mode 100644 index 000000000..cc4900444 --- /dev/null +++ b/lib_tls/include/openssl/ossl_typ.h @@ -0,0 +1,179 @@ +/* ==================================================================== + * Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#ifndef HEADER_OPENSSL_TYPES_H +#define HEADER_OPENSSL_TYPES_H + +#include + +#ifdef NO_ASN1_TYPEDEFS +#define ASN1_INTEGER ASN1_STRING +#define ASN1_ENUMERATED ASN1_STRING +#define ASN1_BIT_STRING ASN1_STRING +#define ASN1_OCTET_STRING ASN1_STRING +#define ASN1_PRINTABLESTRING ASN1_STRING +#define ASN1_T61STRING ASN1_STRING +#define ASN1_IA5STRING ASN1_STRING +#define ASN1_UTCTIME ASN1_STRING +#define ASN1_GENERALIZEDTIME ASN1_STRING +#define ASN1_TIME ASN1_STRING +#define ASN1_GENERALSTRING ASN1_STRING +#define ASN1_UNIVERSALSTRING ASN1_STRING +#define ASN1_BMPSTRING ASN1_STRING +#define ASN1_VISIBLESTRING ASN1_STRING +#define ASN1_UTF8STRING ASN1_STRING +#define ASN1_BOOLEAN int +#define ASN1_NULL int +#else +typedef struct asn1_string_st ASN1_INTEGER; +typedef struct asn1_string_st ASN1_ENUMERATED; +typedef struct asn1_string_st ASN1_BIT_STRING; +typedef struct asn1_string_st ASN1_OCTET_STRING; +typedef struct asn1_string_st ASN1_PRINTABLESTRING; +typedef struct asn1_string_st ASN1_T61STRING; +typedef struct asn1_string_st ASN1_IA5STRING; +typedef struct asn1_string_st ASN1_GENERALSTRING; +typedef struct asn1_string_st ASN1_UNIVERSALSTRING; +typedef struct asn1_string_st ASN1_BMPSTRING; +typedef struct asn1_string_st ASN1_UTCTIME; +typedef struct asn1_string_st ASN1_TIME; +typedef struct asn1_string_st ASN1_GENERALIZEDTIME; +typedef struct asn1_string_st ASN1_VISIBLESTRING; +typedef struct asn1_string_st ASN1_UTF8STRING; +typedef int ASN1_BOOLEAN; +typedef int ASN1_NULL; +#endif + +#ifdef OPENSSL_SYS_WIN32 +#undef X509_NAME +#undef X509_EXTENSIONS +#undef X509_CERT_PAIR +#undef PKCS7_ISSUER_AND_SERIAL +#endif + +#ifdef BIGNUM +#undef BIGNUM +#endif +typedef struct bignum_st BIGNUM; +typedef struct bignum_ctx BN_CTX; +typedef struct bn_blinding_st BN_BLINDING; +typedef struct bn_mont_ctx_st BN_MONT_CTX; +typedef struct bn_recp_ctx_st BN_RECP_CTX; +typedef struct bn_gencb_st BN_GENCB; + +typedef struct buf_mem_st BUF_MEM; + +typedef struct evp_cipher_st EVP_CIPHER; +typedef struct evp_cipher_ctx_st EVP_CIPHER_CTX; +typedef struct env_md_st EVP_MD; +typedef struct env_md_ctx_st EVP_MD_CTX; +typedef struct evp_pkey_st EVP_PKEY; + +typedef struct dh_st DH; +typedef struct dh_method DH_METHOD; + +typedef struct dsa_st DSA; +typedef struct dsa_method DSA_METHOD; + +typedef struct rsa_st RSA; +typedef struct rsa_meth_st RSA_METHOD; + +typedef struct rand_meth_st RAND_METHOD; + +typedef struct ecdh_method ECDH_METHOD; +typedef struct ecdsa_method ECDSA_METHOD; + +typedef struct x509_st X509; +typedef struct X509_algor_st X509_ALGOR; +typedef struct X509_crl_st X509_CRL; +typedef struct X509_name_st X509_NAME; +typedef struct x509_store_st X509_STORE; +typedef struct x509_store_ctx_st X509_STORE_CTX; + +typedef struct v3_ext_ctx X509V3_CTX; +typedef struct conf_st CONF; + +typedef struct store_st STORE; +typedef struct store_method_st STORE_METHOD; + +typedef struct ui_st UI; +typedef struct ui_method_st UI_METHOD; + +typedef struct st_ERR_FNS ERR_FNS; + +typedef struct engine_st ENGINE; + +typedef struct X509_POLICY_NODE_st X509_POLICY_NODE; +typedef struct X509_POLICY_LEVEL_st X509_POLICY_LEVEL; +typedef struct X509_POLICY_TREE_st X509_POLICY_TREE; +typedef struct X509_POLICY_CACHE_st X509_POLICY_CACHE; + + /* If placed in pkcs12.h, we end up with a circular depency with pkcs7.h */ +#define DECLARE_PKCS12_STACK_OF(type) /* Nothing */ +#define IMPLEMENT_PKCS12_STACK_OF(type) /* Nothing */ + +typedef struct crypto_ex_data_st CRYPTO_EX_DATA; +/* Callback types for crypto.h */ +typedef int CRYPTO_EX_new(void *parent, void *ptr, CRYPTO_EX_DATA *ad, + int idx, long argl, void *argp); +typedef void CRYPTO_EX_free(void *parent, void *ptr, CRYPTO_EX_DATA *ad, + int idx, long argl, void *argp); +typedef int CRYPTO_EX_dup(CRYPTO_EX_DATA *to, CRYPTO_EX_DATA *from, void *from_d, + int idx, long argl, void *argp); + +typedef struct ocsp_req_ctx_st OCSP_REQ_CTX; +/* typedef struct ocsp_response_st OCSP_RESPONSE; */ +typedef struct ocsp_responder_id_st OCSP_RESPID; + +#endif /* def HEADER_OPENSSL_TYPES_H */ diff --git a/lib_tls/include/openssl/pem.h b/lib_tls/include/openssl/pem.h new file mode 100644 index 000000000..670afa670 --- /dev/null +++ b/lib_tls/include/openssl/pem.h @@ -0,0 +1,777 @@ +/* crypto/pem/pem.h */ +/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#ifndef HEADER_PEM_H +#define HEADER_PEM_H + +#include +#ifndef OPENSSL_NO_BIO +#include +#endif +#ifndef OPENSSL_NO_STACK +#include +#endif +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define PEM_BUFSIZE 1024 + +#define PEM_OBJ_UNDEF 0 +#define PEM_OBJ_X509 1 +#define PEM_OBJ_X509_REQ 2 +#define PEM_OBJ_CRL 3 +#define PEM_OBJ_SSL_SESSION 4 +#define PEM_OBJ_PRIV_KEY 10 +#define PEM_OBJ_PRIV_RSA 11 +#define PEM_OBJ_PRIV_DSA 12 +#define PEM_OBJ_PRIV_DH 13 +#define PEM_OBJ_PUB_RSA 14 +#define PEM_OBJ_PUB_DSA 15 +#define PEM_OBJ_PUB_DH 16 +#define PEM_OBJ_DHPARAMS 17 +#define PEM_OBJ_DSAPARAMS 18 +#define PEM_OBJ_PRIV_RSA_PUBLIC 19 +#define PEM_OBJ_PRIV_ECDSA 20 +#define PEM_OBJ_PUB_ECDSA 21 +#define PEM_OBJ_ECPARAMETERS 22 + +#define PEM_ERROR 30 +#define PEM_DEK_DES_CBC 40 +#define PEM_DEK_IDEA_CBC 45 +#define PEM_DEK_DES_EDE 50 +#define PEM_DEK_DES_ECB 60 +#define PEM_DEK_RSA 70 +#define PEM_DEK_RSA_MD2 80 +#define PEM_DEK_RSA_MD5 90 + +#define PEM_MD_MD2 NID_md2 +#define PEM_MD_MD5 NID_md5 +#define PEM_MD_SHA NID_sha +#define PEM_MD_MD2_RSA NID_md2WithRSAEncryption +#define PEM_MD_MD5_RSA NID_md5WithRSAEncryption +#define PEM_MD_SHA_RSA NID_sha1WithRSAEncryption + +#define PEM_STRING_X509_OLD "X509 CERTIFICATE" +#define PEM_STRING_X509 "CERTIFICATE" +#define PEM_STRING_X509_PAIR "CERTIFICATE PAIR" +#define PEM_STRING_X509_TRUSTED "TRUSTED CERTIFICATE" +#define PEM_STRING_X509_REQ_OLD "NEW CERTIFICATE REQUEST" +#define PEM_STRING_X509_REQ "CERTIFICATE REQUEST" +#define PEM_STRING_X509_CRL "X509 CRL" +#define PEM_STRING_EVP_PKEY "ANY PRIVATE KEY" +#define PEM_STRING_PUBLIC "PUBLIC KEY" +#define PEM_STRING_RSA "RSA PRIVATE KEY" +#define PEM_STRING_RSA_PUBLIC "RSA PUBLIC KEY" +#define PEM_STRING_DSA "DSA PRIVATE KEY" +#define PEM_STRING_DSA_PUBLIC "DSA PUBLIC KEY" +#define PEM_STRING_PKCS7 "PKCS7" +#define PEM_STRING_PKCS8 "ENCRYPTED PRIVATE KEY" +#define PEM_STRING_PKCS8INF "PRIVATE KEY" +#define PEM_STRING_DHPARAMS "DH PARAMETERS" +#define PEM_STRING_SSL_SESSION "SSL SESSION PARAMETERS" +#define PEM_STRING_DSAPARAMS "DSA PARAMETERS" +#define PEM_STRING_ECDSA_PUBLIC "ECDSA PUBLIC KEY" +#define PEM_STRING_ECPARAMETERS "EC PARAMETERS" +#define PEM_STRING_ECPRIVATEKEY "EC PRIVATE KEY" +#define PEM_STRING_CMS "CMS" + + /* Note that this structure is initialised by PEM_SealInit and cleaned up + by PEM_SealFinal (at least for now) */ +typedef struct PEM_Encode_Seal_st + { + EVP_ENCODE_CTX encode; + EVP_MD_CTX md; + EVP_CIPHER_CTX cipher; + } PEM_ENCODE_SEAL_CTX; + +/* enc_type is one off */ +#define PEM_TYPE_ENCRYPTED 10 +#define PEM_TYPE_MIC_ONLY 20 +#define PEM_TYPE_MIC_CLEAR 30 +#define PEM_TYPE_CLEAR 40 + +typedef struct pem_recip_st + { + char *name; + X509_NAME *dn; + + int cipher; + int key_enc; + /* char iv[8]; unused and wrong size */ + } PEM_USER; + +typedef struct pem_ctx_st + { + int type; /* what type of object */ + + struct { + int version; + int mode; + } proc_type; + + char *domain; + + struct { + int cipher; + /* unused, and wrong size + unsigned char iv[8]; */ + } DEK_info; + + PEM_USER *originator; + + int num_recipient; + PEM_USER **recipient; + +#ifndef OPENSSL_NO_STACK + STACK *x509_chain; /* certificate chain */ +#else + char *x509_chain; /* certificate chain */ +#endif + EVP_MD *md; /* signature type */ + + int md_enc; /* is the md encrypted or not? */ + int md_len; /* length of md_data */ + char *md_data; /* message digest, could be pkey encrypted */ + + EVP_CIPHER *dec; /* date encryption cipher */ + int key_len; /* key length */ + unsigned char *key; /* key */ + /* unused, and wrong size + unsigned char iv[8]; */ + + + int data_enc; /* is the data encrypted */ + int data_len; + unsigned char *data; + } PEM_CTX; + +/* These macros make the PEM_read/PEM_write functions easier to maintain and + * write. Now they are all implemented with either: + * IMPLEMENT_PEM_rw(...) or IMPLEMENT_PEM_rw_cb(...) + */ + +#ifdef OPENSSL_NO_FP_API + +#define IMPLEMENT_PEM_read_fp(name, type, str, asn1) /**/ +#define IMPLEMENT_PEM_write_fp(name, type, str, asn1) /**/ +#define IMPLEMENT_PEM_write_cb_fp(name, type, str, asn1) /**/ + +#else + +#define IMPLEMENT_PEM_read_fp(name, type, str, asn1) \ +type *PEM_read_##name(FILE *fp, type **x, pem_password_cb *cb, void *u)\ +{ \ + return (type*)PEM_ASN1_read(CHECKED_D2I_OF(type, d2i_##asn1), \ + str, fp, \ + CHECKED_PPTR_OF(type, x), \ + cb, u); \ +} + +#define IMPLEMENT_PEM_write_fp(name, type, str, asn1) \ +int PEM_write_##name(FILE *fp, type *x) \ +{ \ + return PEM_ASN1_write(CHECKED_I2D_OF(type, i2d_##asn1), \ + str, fp, \ + CHECKED_PTR_OF(type, x), \ + NULL, NULL, 0, NULL, NULL); \ +} + +#define IMPLEMENT_PEM_write_fp_const(name, type, str, asn1) \ +int PEM_write_##name(FILE *fp, const type *x) \ +{ \ + return PEM_ASN1_write(CHECKED_I2D_OF(const type, i2d_##asn1), \ + str, fp, \ + CHECKED_PTR_OF(const type, x), \ + NULL, NULL, 0, NULL, NULL); \ +} + +#define IMPLEMENT_PEM_write_cb_fp(name, type, str, asn1) \ +int PEM_write_##name(FILE *fp, type *x, const EVP_CIPHER *enc, \ + unsigned char *kstr, int klen, pem_password_cb *cb, \ + void *u) \ + { \ + return PEM_ASN1_write(CHECKED_I2D_OF(type, i2d_##asn1), \ + str, fp, \ + CHECKED_PTR_OF(type, x), \ + enc, kstr, klen, cb, u); \ + } + +#define IMPLEMENT_PEM_write_cb_fp_const(name, type, str, asn1) \ +int PEM_write_##name(FILE *fp, type *x, const EVP_CIPHER *enc, \ + unsigned char *kstr, int klen, pem_password_cb *cb, \ + void *u) \ + { \ + return PEM_ASN1_write(CHECKED_I2D_OF(const type, i2d_##asn1), \ + str, fp, \ + CHECKED_PTR_OF(const type, x), \ + enc, kstr, klen, cb, u); \ + } + +#endif + +#define IMPLEMENT_PEM_read_bio(name, type, str, asn1) \ +type *PEM_read_bio_##name(BIO *bp, type **x, pem_password_cb *cb, void *u)\ +{ \ + return (type*)PEM_ASN1_read_bio(CHECKED_D2I_OF(type, d2i_##asn1), \ + str, bp, \ + CHECKED_PPTR_OF(type, x), \ + cb, u); \ +} + +#define IMPLEMENT_PEM_write_bio(name, type, str, asn1) \ +int PEM_write_bio_##name(BIO *bp, type *x) \ +{ \ + return PEM_ASN1_write_bio(CHECKED_I2D_OF(type, i2d_##asn1), \ + str, bp, \ + CHECKED_PTR_OF(type, x), \ + NULL, NULL, 0, NULL, NULL); \ +} + +#define IMPLEMENT_PEM_write_bio_const(name, type, str, asn1) \ +int PEM_write_bio_##name(BIO *bp, const type *x) \ +{ \ + return PEM_ASN1_write_bio(CHECKED_I2D_OF(const type, i2d_##asn1), \ + str, bp, \ + CHECKED_PTR_OF(const type, x), \ + NULL, NULL, 0, NULL, NULL); \ +} + +#define IMPLEMENT_PEM_write_cb_bio(name, type, str, asn1) \ +int PEM_write_bio_##name(BIO *bp, type *x, const EVP_CIPHER *enc, \ + unsigned char *kstr, int klen, pem_password_cb *cb, void *u) \ + { \ + return PEM_ASN1_write_bio(CHECKED_I2D_OF(type, i2d_##asn1), \ + str, bp, \ + CHECKED_PTR_OF(type, x), \ + enc, kstr, klen, cb, u); \ + } + +#define IMPLEMENT_PEM_write_cb_bio_const(name, type, str, asn1) \ +int PEM_write_bio_##name(BIO *bp, type *x, const EVP_CIPHER *enc, \ + unsigned char *kstr, int klen, pem_password_cb *cb, void *u) \ + { \ + return PEM_ASN1_write_bio(CHECKED_I2D_OF(const type, i2d_##asn1), \ + str, bp, \ + CHECKED_PTR_OF(const type, x), \ + enc, kstr, klen, cb, u); \ + } + +#define IMPLEMENT_PEM_write(name, type, str, asn1) \ + IMPLEMENT_PEM_write_bio(name, type, str, asn1) \ + IMPLEMENT_PEM_write_fp(name, type, str, asn1) + +#define IMPLEMENT_PEM_write_const(name, type, str, asn1) \ + IMPLEMENT_PEM_write_bio_const(name, type, str, asn1) \ + IMPLEMENT_PEM_write_fp_const(name, type, str, asn1) + +#define IMPLEMENT_PEM_write_cb(name, type, str, asn1) \ + IMPLEMENT_PEM_write_cb_bio(name, type, str, asn1) \ + IMPLEMENT_PEM_write_cb_fp(name, type, str, asn1) + +#define IMPLEMENT_PEM_write_cb_const(name, type, str, asn1) \ + IMPLEMENT_PEM_write_cb_bio_const(name, type, str, asn1) \ + IMPLEMENT_PEM_write_cb_fp_const(name, type, str, asn1) + +#define IMPLEMENT_PEM_read(name, type, str, asn1) \ + IMPLEMENT_PEM_read_bio(name, type, str, asn1) \ + IMPLEMENT_PEM_read_fp(name, type, str, asn1) + +#define IMPLEMENT_PEM_rw(name, type, str, asn1) \ + IMPLEMENT_PEM_read(name, type, str, asn1) \ + IMPLEMENT_PEM_write(name, type, str, asn1) + +#define IMPLEMENT_PEM_rw_const(name, type, str, asn1) \ + IMPLEMENT_PEM_read(name, type, str, asn1) \ + IMPLEMENT_PEM_write_const(name, type, str, asn1) + +#define IMPLEMENT_PEM_rw_cb(name, type, str, asn1) \ + IMPLEMENT_PEM_read(name, type, str, asn1) \ + IMPLEMENT_PEM_write_cb(name, type, str, asn1) + +/* These are the same except they are for the declarations */ + +#if defined(OPENSSL_SYS_WIN16) || defined(OPENSSL_NO_FP_API) + +#define DECLARE_PEM_read_fp(name, type) /**/ +#define DECLARE_PEM_write_fp(name, type) /**/ +#define DECLARE_PEM_write_cb_fp(name, type) /**/ + +#else + +#define DECLARE_PEM_read_fp(name, type) \ + type *PEM_read_##name(FILE *fp, type **x, pem_password_cb *cb, void *u); + +#define DECLARE_PEM_write_fp(name, type) \ + int PEM_write_##name(FILE *fp, type *x); + +#define DECLARE_PEM_write_fp_const(name, type) \ + int PEM_write_##name(FILE *fp, const type *x); + +#define DECLARE_PEM_write_cb_fp(name, type) \ + int PEM_write_##name(FILE *fp, type *x, const EVP_CIPHER *enc, \ + unsigned char *kstr, int klen, pem_password_cb *cb, void *u); + +#endif + +#ifndef OPENSSL_NO_BIO +#define DECLARE_PEM_read_bio(name, type) \ + type *PEM_read_bio_##name(BIO *bp, type **x, pem_password_cb *cb, void *u); + +#define DECLARE_PEM_write_bio(name, type) \ + int PEM_write_bio_##name(BIO *bp, type *x); + +#define DECLARE_PEM_write_bio_const(name, type) \ + int PEM_write_bio_##name(BIO *bp, const type *x); + +#define DECLARE_PEM_write_cb_bio(name, type) \ + int PEM_write_bio_##name(BIO *bp, type *x, const EVP_CIPHER *enc, \ + unsigned char *kstr, int klen, pem_password_cb *cb, void *u); + +#else + +#define DECLARE_PEM_read_bio(name, type) /**/ +#define DECLARE_PEM_write_bio(name, type) /**/ +#define DECLARE_PEM_write_cb_bio(name, type) /**/ + +#endif + +#define DECLARE_PEM_write(name, type) \ + DECLARE_PEM_write_bio(name, type) \ + DECLARE_PEM_write_fp(name, type) + +#define DECLARE_PEM_write_const(name, type) \ + DECLARE_PEM_write_bio_const(name, type) \ + DECLARE_PEM_write_fp_const(name, type) + +#define DECLARE_PEM_write_cb(name, type) \ + DECLARE_PEM_write_cb_bio(name, type) \ + DECLARE_PEM_write_cb_fp(name, type) + +#define DECLARE_PEM_read(name, type) \ + DECLARE_PEM_read_bio(name, type) \ + DECLARE_PEM_read_fp(name, type) + +#define DECLARE_PEM_rw(name, type) \ + DECLARE_PEM_read(name, type) \ + DECLARE_PEM_write(name, type) + +#define DECLARE_PEM_rw_const(name, type) \ + DECLARE_PEM_read(name, type) \ + DECLARE_PEM_write_const(name, type) + +#define DECLARE_PEM_rw_cb(name, type) \ + DECLARE_PEM_read(name, type) \ + DECLARE_PEM_write_cb(name, type) + +#ifdef SSLEAY_MACROS + +#define PEM_write_SSL_SESSION(fp,x) \ + PEM_ASN1_write((int (*)())i2d_SSL_SESSION, \ + PEM_STRING_SSL_SESSION,fp, (char *)x, NULL,NULL,0,NULL,NULL) +#define PEM_write_X509(fp,x) \ + PEM_ASN1_write((int (*)())i2d_X509,PEM_STRING_X509,fp, \ + (char *)x, NULL,NULL,0,NULL,NULL) +#define PEM_write_X509_REQ(fp,x) PEM_ASN1_write( \ + (int (*)())i2d_X509_REQ,PEM_STRING_X509_REQ,fp,(char *)x, \ + NULL,NULL,0,NULL,NULL) +#define PEM_write_X509_CRL(fp,x) \ + PEM_ASN1_write((int (*)())i2d_X509_CRL,PEM_STRING_X509_CRL, \ + fp,(char *)x, NULL,NULL,0,NULL,NULL) +#define PEM_write_RSAPrivateKey(fp,x,enc,kstr,klen,cb,u) \ + PEM_ASN1_write((int (*)())i2d_RSAPrivateKey,PEM_STRING_RSA,fp,\ + (char *)x,enc,kstr,klen,cb,u) +#define PEM_write_RSAPublicKey(fp,x) \ + PEM_ASN1_write((int (*)())i2d_RSAPublicKey,\ + PEM_STRING_RSA_PUBLIC,fp,(char *)x,NULL,NULL,0,NULL,NULL) +#define PEM_write_DSAPrivateKey(fp,x,enc,kstr,klen,cb,u) \ + PEM_ASN1_write((int (*)())i2d_DSAPrivateKey,PEM_STRING_DSA,fp,\ + (char *)x,enc,kstr,klen,cb,u) +#define PEM_write_PrivateKey(bp,x,enc,kstr,klen,cb,u) \ + PEM_ASN1_write((int (*)())i2d_PrivateKey,\ + (((x)->type == EVP_PKEY_DSA)?PEM_STRING_DSA:PEM_STRING_RSA),\ + bp,(char *)x,enc,kstr,klen,cb,u) +#define PEM_write_PKCS7(fp,x) \ + PEM_ASN1_write((int (*)())i2d_PKCS7,PEM_STRING_PKCS7,fp, \ + (char *)x, NULL,NULL,0,NULL,NULL) +#define PEM_write_DHparams(fp,x) \ + PEM_ASN1_write((int (*)())i2d_DHparams,PEM_STRING_DHPARAMS,fp,\ + (char *)x,NULL,NULL,0,NULL,NULL) + +#define PEM_write_NETSCAPE_CERT_SEQUENCE(fp,x) \ + PEM_ASN1_write((int (*)())i2d_NETSCAPE_CERT_SEQUENCE, \ + PEM_STRING_X509,fp, \ + (char *)x, NULL,NULL,0,NULL,NULL) + +#define PEM_read_SSL_SESSION(fp,x,cb,u) (SSL_SESSION *)PEM_ASN1_read( \ + (char *(*)())d2i_SSL_SESSION,PEM_STRING_SSL_SESSION,fp,(char **)x,cb,u) +#define PEM_read_X509(fp,x,cb,u) (X509 *)PEM_ASN1_read( \ + (char *(*)())d2i_X509,PEM_STRING_X509,fp,(char **)x,cb,u) +#define PEM_read_X509_REQ(fp,x,cb,u) (X509_REQ *)PEM_ASN1_read( \ + (char *(*)())d2i_X509_REQ,PEM_STRING_X509_REQ,fp,(char **)x,cb,u) +#define PEM_read_X509_CRL(fp,x,cb,u) (X509_CRL *)PEM_ASN1_read( \ + (char *(*)())d2i_X509_CRL,PEM_STRING_X509_CRL,fp,(char **)x,cb,u) +#define PEM_read_RSAPrivateKey(fp,x,cb,u) (RSA *)PEM_ASN1_read( \ + (char *(*)())d2i_RSAPrivateKey,PEM_STRING_RSA,fp,(char **)x,cb,u) +#define PEM_read_RSAPublicKey(fp,x,cb,u) (RSA *)PEM_ASN1_read( \ + (char *(*)())d2i_RSAPublicKey,PEM_STRING_RSA_PUBLIC,fp,(char **)x,cb,u) +#define PEM_read_DSAPrivateKey(fp,x,cb,u) (DSA *)PEM_ASN1_read( \ + (char *(*)())d2i_DSAPrivateKey,PEM_STRING_DSA,fp,(char **)x,cb,u) +#define PEM_read_PrivateKey(fp,x,cb,u) (EVP_PKEY *)PEM_ASN1_read( \ + (char *(*)())d2i_PrivateKey,PEM_STRING_EVP_PKEY,fp,(char **)x,cb,u) +#define PEM_read_PKCS7(fp,x,cb,u) (PKCS7 *)PEM_ASN1_read( \ + (char *(*)())d2i_PKCS7,PEM_STRING_PKCS7,fp,(char **)x,cb,u) +#define PEM_read_DHparams(fp,x,cb,u) (DH *)PEM_ASN1_read( \ + (char *(*)())d2i_DHparams,PEM_STRING_DHPARAMS,fp,(char **)x,cb,u) + +#define PEM_read_NETSCAPE_CERT_SEQUENCE(fp,x,cb,u) \ + (NETSCAPE_CERT_SEQUENCE *)PEM_ASN1_read( \ + (char *(*)())d2i_NETSCAPE_CERT_SEQUENCE,PEM_STRING_X509,fp,\ + (char **)x,cb,u) + +#define PEM_write_bio_X509(bp,x) \ + PEM_ASN1_write_bio((int (*)())i2d_X509,PEM_STRING_X509,bp, \ + (char *)x, NULL,NULL,0,NULL,NULL) +#define PEM_write_bio_X509_REQ(bp,x) PEM_ASN1_write_bio( \ + (int (*)())i2d_X509_REQ,PEM_STRING_X509_REQ,bp,(char *)x, \ + NULL,NULL,0,NULL,NULL) +#define PEM_write_bio_X509_CRL(bp,x) \ + PEM_ASN1_write_bio((int (*)())i2d_X509_CRL,PEM_STRING_X509_CRL,\ + bp,(char *)x, NULL,NULL,0,NULL,NULL) +#define PEM_write_bio_RSAPrivateKey(bp,x,enc,kstr,klen,cb,u) \ + PEM_ASN1_write_bio((int (*)())i2d_RSAPrivateKey,PEM_STRING_RSA,\ + bp,(char *)x,enc,kstr,klen,cb,u) +#define PEM_write_bio_RSAPublicKey(bp,x) \ + PEM_ASN1_write_bio((int (*)())i2d_RSAPublicKey, \ + PEM_STRING_RSA_PUBLIC,\ + bp,(char *)x,NULL,NULL,0,NULL,NULL) +#define PEM_write_bio_DSAPrivateKey(bp,x,enc,kstr,klen,cb,u) \ + PEM_ASN1_write_bio((int (*)())i2d_DSAPrivateKey,PEM_STRING_DSA,\ + bp,(char *)x,enc,kstr,klen,cb,u) +#define PEM_write_bio_PrivateKey(bp,x,enc,kstr,klen,cb,u) \ + PEM_ASN1_write_bio((int (*)())i2d_PrivateKey,\ + (((x)->type == EVP_PKEY_DSA)?PEM_STRING_DSA:PEM_STRING_RSA),\ + bp,(char *)x,enc,kstr,klen,cb,u) +#define PEM_write_bio_PKCS7(bp,x) \ + PEM_ASN1_write_bio((int (*)())i2d_PKCS7,PEM_STRING_PKCS7,bp, \ + (char *)x, NULL,NULL,0,NULL,NULL) +#define PEM_write_bio_DHparams(bp,x) \ + PEM_ASN1_write_bio((int (*)())i2d_DHparams,PEM_STRING_DHPARAMS,\ + bp,(char *)x,NULL,NULL,0,NULL,NULL) +#define PEM_write_bio_DSAparams(bp,x) \ + PEM_ASN1_write_bio((int (*)())i2d_DSAparams, \ + PEM_STRING_DSAPARAMS,bp,(char *)x,NULL,NULL,0,NULL,NULL) + +#define PEM_write_bio_NETSCAPE_CERT_SEQUENCE(bp,x) \ + PEM_ASN1_write_bio((int (*)())i2d_NETSCAPE_CERT_SEQUENCE, \ + PEM_STRING_X509,bp, \ + (char *)x, NULL,NULL,0,NULL,NULL) + +#define PEM_read_bio_X509(bp,x,cb,u) (X509 *)PEM_ASN1_read_bio( \ + (char *(*)())d2i_X509,PEM_STRING_X509,bp,(char **)x,cb,u) +#define PEM_read_bio_X509_REQ(bp,x,cb,u) (X509_REQ *)PEM_ASN1_read_bio( \ + (char *(*)())d2i_X509_REQ,PEM_STRING_X509_REQ,bp,(char **)x,cb,u) +#define PEM_read_bio_X509_CRL(bp,x,cb,u) (X509_CRL *)PEM_ASN1_read_bio( \ + (char *(*)())d2i_X509_CRL,PEM_STRING_X509_CRL,bp,(char **)x,cb,u) +#define PEM_read_bio_RSAPrivateKey(bp,x,cb,u) (RSA *)PEM_ASN1_read_bio( \ + (char *(*)())d2i_RSAPrivateKey,PEM_STRING_RSA,bp,(char **)x,cb,u) +#define PEM_read_bio_RSAPublicKey(bp,x,cb,u) (RSA *)PEM_ASN1_read_bio( \ + (char *(*)())d2i_RSAPublicKey,PEM_STRING_RSA_PUBLIC,bp,(char **)x,cb,u) +#define PEM_read_bio_DSAPrivateKey(bp,x,cb,u) (DSA *)PEM_ASN1_read_bio( \ + (char *(*)())d2i_DSAPrivateKey,PEM_STRING_DSA,bp,(char **)x,cb,u) +#define PEM_read_bio_PrivateKey(bp,x,cb,u) (EVP_PKEY *)PEM_ASN1_read_bio( \ + (char *(*)())d2i_PrivateKey,PEM_STRING_EVP_PKEY,bp,(char **)x,cb,u) + +#define PEM_read_bio_PKCS7(bp,x,cb,u) (PKCS7 *)PEM_ASN1_read_bio( \ + (char *(*)())d2i_PKCS7,PEM_STRING_PKCS7,bp,(char **)x,cb,u) +#define PEM_read_bio_DHparams(bp,x,cb,u) (DH *)PEM_ASN1_read_bio( \ + (char *(*)())d2i_DHparams,PEM_STRING_DHPARAMS,bp,(char **)x,cb,u) +#define PEM_read_bio_DSAparams(bp,x,cb,u) (DSA *)PEM_ASN1_read_bio( \ + (char *(*)())d2i_DSAparams,PEM_STRING_DSAPARAMS,bp,(char **)x,cb,u) + +#define PEM_read_bio_NETSCAPE_CERT_SEQUENCE(bp,x,cb,u) \ + (NETSCAPE_CERT_SEQUENCE *)PEM_ASN1_read_bio( \ + (char *(*)())d2i_NETSCAPE_CERT_SEQUENCE,PEM_STRING_X509,bp,\ + (char **)x,cb,u) + +#endif + +#if 1 +/* "userdata": new with OpenSSL 0.9.4 */ +typedef int pem_password_cb(char *buf, int size, int rwflag, void *userdata); +#else +/* OpenSSL 0.9.3, 0.9.3a */ +typedef int pem_password_cb(char *buf, int size, int rwflag); +#endif + +int PEM_get_EVP_CIPHER_INFO(char *header, EVP_CIPHER_INFO *cipher); +int PEM_do_header (EVP_CIPHER_INFO *cipher, unsigned char *data,long *len, + pem_password_cb *callback,void *u); + +#ifndef OPENSSL_NO_BIO +int PEM_read_bio(BIO *bp, char **name, char **header, + unsigned char **data,long *len); +int PEM_write_bio(BIO *bp,const char *name,char *hdr,unsigned char *data, + long len); +int PEM_bytes_read_bio(unsigned char **pdata, long *plen, char **pnm, const char *name, BIO *bp, + pem_password_cb *cb, void *u); +void * PEM_ASN1_read_bio(d2i_of_void *d2i, const char *name, BIO *bp, + void **x, pem_password_cb *cb, void *u); + +#define PEM_ASN1_read_bio_of(type,d2i,name,bp,x,cb,u) \ + ((type*)PEM_ASN1_read_bio(CHECKED_D2I_OF(type, d2i), \ + name, bp, \ + CHECKED_PPTR_OF(type, x), \ + cb, u)) + +int PEM_ASN1_write_bio(i2d_of_void *i2d,const char *name,BIO *bp,char *x, + const EVP_CIPHER *enc,unsigned char *kstr,int klen, + pem_password_cb *cb, void *u); + +#define PEM_ASN1_write_bio_of(type,i2d,name,bp,x,enc,kstr,klen,cb,u) \ + (PEM_ASN1_write_bio(CHECKED_I2D_OF(type, i2d), \ + name, bp, \ + CHECKED_PTR_OF(type, x), \ + enc, kstr, klen, cb, u)) + +STACK_OF(X509_INFO) * PEM_X509_INFO_read_bio(BIO *bp, STACK_OF(X509_INFO) *sk, pem_password_cb *cb, void *u); +int PEM_X509_INFO_write_bio(BIO *bp,X509_INFO *xi, EVP_CIPHER *enc, + unsigned char *kstr, int klen, pem_password_cb *cd, void *u); +#endif + +#ifndef OPENSSL_SYS_WIN16 +int PEM_read(FILE *fp, char **name, char **header, + unsigned char **data,long *len); +int PEM_write(FILE *fp,char *name,char *hdr,unsigned char *data,long len); +void * PEM_ASN1_read(d2i_of_void *d2i, const char *name, FILE *fp, void **x, + pem_password_cb *cb, void *u); +int PEM_ASN1_write(i2d_of_void *i2d,const char *name,FILE *fp, + char *x,const EVP_CIPHER *enc,unsigned char *kstr, + int klen,pem_password_cb *callback, void *u); +STACK_OF(X509_INFO) * PEM_X509_INFO_read(FILE *fp, STACK_OF(X509_INFO) *sk, + pem_password_cb *cb, void *u); +#endif + +int PEM_SealInit(PEM_ENCODE_SEAL_CTX *ctx, EVP_CIPHER *type, + EVP_MD *md_type, unsigned char **ek, int *ekl, + unsigned char *iv, EVP_PKEY **pubk, int npubk); +void PEM_SealUpdate(PEM_ENCODE_SEAL_CTX *ctx, unsigned char *out, int *outl, + unsigned char *in, int inl); +int PEM_SealFinal(PEM_ENCODE_SEAL_CTX *ctx, unsigned char *sig,int *sigl, + unsigned char *out, int *outl, EVP_PKEY *priv); + +void PEM_SignInit(EVP_MD_CTX *ctx, EVP_MD *type); +void PEM_SignUpdate(EVP_MD_CTX *ctx,unsigned char *d,unsigned int cnt); +int PEM_SignFinal(EVP_MD_CTX *ctx, unsigned char *sigret, + unsigned int *siglen, EVP_PKEY *pkey); + +int PEM_def_callback(char *buf, int num, int w, void *key); +void PEM_proc_type(char *buf, int type); +void PEM_dek_info(char *buf, const char *type, int len, char *str); + +#ifndef SSLEAY_MACROS + +#include + +DECLARE_PEM_rw(X509, X509) + +DECLARE_PEM_rw(X509_AUX, X509) + +DECLARE_PEM_rw(X509_CERT_PAIR, X509_CERT_PAIR) + +DECLARE_PEM_rw(X509_REQ, X509_REQ) +DECLARE_PEM_write(X509_REQ_NEW, X509_REQ) + +DECLARE_PEM_rw(X509_CRL, X509_CRL) + +DECLARE_PEM_rw(PKCS7, PKCS7) + +DECLARE_PEM_rw(NETSCAPE_CERT_SEQUENCE, NETSCAPE_CERT_SEQUENCE) + +DECLARE_PEM_rw(PKCS8, X509_SIG) + +DECLARE_PEM_rw(PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO) + +#ifndef OPENSSL_NO_RSA + +DECLARE_PEM_rw_cb(RSAPrivateKey, RSA) + +DECLARE_PEM_rw_const(RSAPublicKey, RSA) +DECLARE_PEM_rw(RSA_PUBKEY, RSA) + +#endif + +#ifndef OPENSSL_NO_DSA + +DECLARE_PEM_rw_cb(DSAPrivateKey, DSA) + +DECLARE_PEM_rw(DSA_PUBKEY, DSA) + +DECLARE_PEM_rw_const(DSAparams, DSA) + +#endif + +#ifndef OPENSSL_NO_EC +DECLARE_PEM_rw_const(ECPKParameters, EC_GROUP) +DECLARE_PEM_rw_cb(ECPrivateKey, EC_KEY) +DECLARE_PEM_rw(EC_PUBKEY, EC_KEY) +#endif + +#ifndef OPENSSL_NO_DH + +DECLARE_PEM_rw_const(DHparams, DH) + +#endif + +DECLARE_PEM_rw_cb(PrivateKey, EVP_PKEY) + +DECLARE_PEM_rw(PUBKEY, EVP_PKEY) + +int PEM_write_bio_PKCS8PrivateKey_nid(BIO *bp, EVP_PKEY *x, int nid, + char *kstr, int klen, + pem_password_cb *cb, void *u); +int PEM_write_bio_PKCS8PrivateKey(BIO *, EVP_PKEY *, const EVP_CIPHER *, + char *, int, pem_password_cb *, void *); +int i2d_PKCS8PrivateKey_bio(BIO *bp, EVP_PKEY *x, const EVP_CIPHER *enc, + char *kstr, int klen, + pem_password_cb *cb, void *u); +int i2d_PKCS8PrivateKey_nid_bio(BIO *bp, EVP_PKEY *x, int nid, + char *kstr, int klen, + pem_password_cb *cb, void *u); +EVP_PKEY *d2i_PKCS8PrivateKey_bio(BIO *bp, EVP_PKEY **x, pem_password_cb *cb, void *u); + +int i2d_PKCS8PrivateKey_fp(FILE *fp, EVP_PKEY *x, const EVP_CIPHER *enc, + char *kstr, int klen, + pem_password_cb *cb, void *u); +int i2d_PKCS8PrivateKey_nid_fp(FILE *fp, EVP_PKEY *x, int nid, + char *kstr, int klen, + pem_password_cb *cb, void *u); +int PEM_write_PKCS8PrivateKey_nid(FILE *fp, EVP_PKEY *x, int nid, + char *kstr, int klen, + pem_password_cb *cb, void *u); + +EVP_PKEY *d2i_PKCS8PrivateKey_fp(FILE *fp, EVP_PKEY **x, pem_password_cb *cb, void *u); + +int PEM_write_PKCS8PrivateKey(FILE *fp,EVP_PKEY *x,const EVP_CIPHER *enc, + char *kstr,int klen, pem_password_cb *cd, void *u); + +#endif /* SSLEAY_MACROS */ + + +/* BEGIN ERROR CODES */ +/* The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ +void ERR_load_PEM_strings(void); + +/* Error codes for the PEM functions. */ + +/* Function codes. */ +#define PEM_F_D2I_PKCS8PRIVATEKEY_BIO 120 +#define PEM_F_D2I_PKCS8PRIVATEKEY_FP 121 +#define PEM_F_DO_PK8PKEY 126 +#define PEM_F_DO_PK8PKEY_FP 125 +#define PEM_F_LOAD_IV 101 +#define PEM_F_PEM_ASN1_READ 102 +#define PEM_F_PEM_ASN1_READ_BIO 103 +#define PEM_F_PEM_ASN1_WRITE 104 +#define PEM_F_PEM_ASN1_WRITE_BIO 105 +#define PEM_F_PEM_DEF_CALLBACK 100 +#define PEM_F_PEM_DO_HEADER 106 +#define PEM_F_PEM_F_PEM_WRITE_PKCS8PRIVATEKEY 118 +#define PEM_F_PEM_GET_EVP_CIPHER_INFO 107 +#define PEM_F_PEM_PK8PKEY 119 +#define PEM_F_PEM_READ 108 +#define PEM_F_PEM_READ_BIO 109 +#define PEM_F_PEM_READ_BIO_PRIVATEKEY 123 +#define PEM_F_PEM_READ_PRIVATEKEY 124 +#define PEM_F_PEM_SEALFINAL 110 +#define PEM_F_PEM_SEALINIT 111 +#define PEM_F_PEM_SIGNFINAL 112 +#define PEM_F_PEM_WRITE 113 +#define PEM_F_PEM_WRITE_BIO 114 +#define PEM_F_PEM_X509_INFO_READ 115 +#define PEM_F_PEM_X509_INFO_READ_BIO 116 +#define PEM_F_PEM_X509_INFO_WRITE_BIO 117 + +/* Reason codes. */ +#define PEM_R_BAD_BASE64_DECODE 100 +#define PEM_R_BAD_DECRYPT 101 +#define PEM_R_BAD_END_LINE 102 +#define PEM_R_BAD_IV_CHARS 103 +#define PEM_R_BAD_PASSWORD_READ 104 +#define PEM_R_ERROR_CONVERTING_PRIVATE_KEY 115 +#define PEM_R_NOT_DEK_INFO 105 +#define PEM_R_NOT_ENCRYPTED 106 +#define PEM_R_NOT_PROC_TYPE 107 +#define PEM_R_NO_START_LINE 108 +#define PEM_R_PROBLEMS_GETTING_PASSWORD 109 +#define PEM_R_PUBLIC_KEY_NO_RSA 110 +#define PEM_R_READ_KEY 111 +#define PEM_R_SHORT_HEADER 112 +#define PEM_R_UNSUPPORTED_CIPHER 113 +#define PEM_R_UNSUPPORTED_ENCRYPTION 114 + +#ifdef __cplusplus +} +#endif +#endif diff --git a/lib_tls/include/openssl/pem2.h b/lib_tls/include/openssl/pem2.h new file mode 100644 index 000000000..f31790d69 --- /dev/null +++ b/lib_tls/include/openssl/pem2.h @@ -0,0 +1,70 @@ +/* ==================================================================== + * Copyright (c) 1999 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +/* + * This header only exists to break a circular dependency between pem and err + * Ben 30 Jan 1999. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef HEADER_PEM_H +void ERR_load_PEM_strings(void); +#endif + +#ifdef __cplusplus +} +#endif diff --git a/lib_tls/include/openssl/pkcs12.h b/lib_tls/include/openssl/pkcs12.h new file mode 100644 index 000000000..a2d7e359a --- /dev/null +++ b/lib_tls/include/openssl/pkcs12.h @@ -0,0 +1,333 @@ +/* pkcs12.h */ +/* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL + * project 1999. + */ +/* ==================================================================== + * Copyright (c) 1999 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#ifndef HEADER_PKCS12_H +#define HEADER_PKCS12_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define PKCS12_KEY_ID 1 +#define PKCS12_IV_ID 2 +#define PKCS12_MAC_ID 3 + +/* Default iteration count */ +#ifndef PKCS12_DEFAULT_ITER +#define PKCS12_DEFAULT_ITER PKCS5_DEFAULT_ITER +#endif + +#define PKCS12_MAC_KEY_LENGTH 20 + +#define PKCS12_SALT_LEN 8 + +/* Uncomment out next line for unicode password and names, otherwise ASCII */ + +/*#define PBE_UNICODE*/ + +#ifdef PBE_UNICODE +#define PKCS12_key_gen PKCS12_key_gen_uni +#define PKCS12_add_friendlyname PKCS12_add_friendlyname_uni +#else +#define PKCS12_key_gen PKCS12_key_gen_asc +#define PKCS12_add_friendlyname PKCS12_add_friendlyname_asc +#endif + +/* MS key usage constants */ + +#define KEY_EX 0x10 +#define KEY_SIG 0x80 + +typedef struct { +X509_SIG *dinfo; +ASN1_OCTET_STRING *salt; +ASN1_INTEGER *iter; /* defaults to 1 */ +} PKCS12_MAC_DATA; + +typedef struct { +ASN1_INTEGER *version; +PKCS12_MAC_DATA *mac; +PKCS7 *authsafes; +} PKCS12; + +PREDECLARE_STACK_OF(PKCS12_SAFEBAG) + +typedef struct { +ASN1_OBJECT *type; +union { + struct pkcs12_bag_st *bag; /* secret, crl and certbag */ + struct pkcs8_priv_key_info_st *keybag; /* keybag */ + X509_SIG *shkeybag; /* shrouded key bag */ + STACK_OF(PKCS12_SAFEBAG) *safes; + ASN1_TYPE *other; +}value; +STACK_OF(X509_ATTRIBUTE) *attrib; +} PKCS12_SAFEBAG; + +DECLARE_STACK_OF(PKCS12_SAFEBAG) +DECLARE_ASN1_SET_OF(PKCS12_SAFEBAG) +DECLARE_PKCS12_STACK_OF(PKCS12_SAFEBAG) + +typedef struct pkcs12_bag_st { +ASN1_OBJECT *type; +union { + ASN1_OCTET_STRING *x509cert; + ASN1_OCTET_STRING *x509crl; + ASN1_OCTET_STRING *octet; + ASN1_IA5STRING *sdsicert; + ASN1_TYPE *other; /* Secret or other bag */ +}value; +} PKCS12_BAGS; + +#define PKCS12_ERROR 0 +#define PKCS12_OK 1 + +/* Compatibility macros */ + +#define M_PKCS12_x5092certbag PKCS12_x5092certbag +#define M_PKCS12_x509crl2certbag PKCS12_x509crl2certbag + +#define M_PKCS12_certbag2x509 PKCS12_certbag2x509 +#define M_PKCS12_certbag2x509crl PKCS12_certbag2x509crl + +#define M_PKCS12_unpack_p7data PKCS12_unpack_p7data +#define M_PKCS12_pack_authsafes PKCS12_pack_authsafes +#define M_PKCS12_unpack_authsafes PKCS12_unpack_authsafes +#define M_PKCS12_unpack_p7encdata PKCS12_unpack_p7encdata + +#define M_PKCS12_decrypt_skey PKCS12_decrypt_skey +#define M_PKCS8_decrypt PKCS8_decrypt + +#define M_PKCS12_bag_type(bg) OBJ_obj2nid((bg)->type) +#define M_PKCS12_cert_bag_type(bg) OBJ_obj2nid((bg)->value.bag->type) +#define M_PKCS12_crl_bag_type M_PKCS12_cert_bag_type + +#define PKCS12_get_attr(bag, attr_nid) \ + PKCS12_get_attr_gen(bag->attrib, attr_nid) + +#define PKCS8_get_attr(p8, attr_nid) \ + PKCS12_get_attr_gen(p8->attributes, attr_nid) + +#define PKCS12_mac_present(p12) ((p12)->mac ? 1 : 0) + + +PKCS12_SAFEBAG *PKCS12_x5092certbag(X509 *x509); +PKCS12_SAFEBAG *PKCS12_x509crl2certbag(X509_CRL *crl); +X509 *PKCS12_certbag2x509(PKCS12_SAFEBAG *bag); +X509_CRL *PKCS12_certbag2x509crl(PKCS12_SAFEBAG *bag); + +PKCS12_SAFEBAG *PKCS12_item_pack_safebag(void *obj, const ASN1_ITEM *it, int nid1, + int nid2); +PKCS12_SAFEBAG *PKCS12_MAKE_KEYBAG(PKCS8_PRIV_KEY_INFO *p8); +PKCS8_PRIV_KEY_INFO *PKCS8_decrypt(X509_SIG *p8, const char *pass, int passlen); +PKCS8_PRIV_KEY_INFO *PKCS12_decrypt_skey(PKCS12_SAFEBAG *bag, const char *pass, + int passlen); +X509_SIG *PKCS8_encrypt(int pbe_nid, const EVP_CIPHER *cipher, + const char *pass, int passlen, + unsigned char *salt, int saltlen, int iter, + PKCS8_PRIV_KEY_INFO *p8); +PKCS12_SAFEBAG *PKCS12_MAKE_SHKEYBAG(int pbe_nid, const char *pass, + int passlen, unsigned char *salt, + int saltlen, int iter, + PKCS8_PRIV_KEY_INFO *p8); +PKCS7 *PKCS12_pack_p7data(STACK_OF(PKCS12_SAFEBAG) *sk); +STACK_OF(PKCS12_SAFEBAG) *PKCS12_unpack_p7data(PKCS7 *p7); +PKCS7 *PKCS12_pack_p7encdata(int pbe_nid, const char *pass, int passlen, + unsigned char *salt, int saltlen, int iter, + STACK_OF(PKCS12_SAFEBAG) *bags); +STACK_OF(PKCS12_SAFEBAG) *PKCS12_unpack_p7encdata(PKCS7 *p7, const char *pass, int passlen); + +int PKCS12_pack_authsafes(PKCS12 *p12, STACK_OF(PKCS7) *safes); +STACK_OF(PKCS7) *PKCS12_unpack_authsafes(PKCS12 *p12); + +int PKCS12_add_localkeyid(PKCS12_SAFEBAG *bag, unsigned char *name, int namelen); +int PKCS12_add_friendlyname_asc(PKCS12_SAFEBAG *bag, const char *name, + int namelen); +int PKCS12_add_CSPName_asc(PKCS12_SAFEBAG *bag, const char *name, + int namelen); +int PKCS12_add_friendlyname_uni(PKCS12_SAFEBAG *bag, const unsigned char *name, + int namelen); +int PKCS8_add_keyusage(PKCS8_PRIV_KEY_INFO *p8, int usage); +ASN1_TYPE *PKCS12_get_attr_gen(STACK_OF(X509_ATTRIBUTE) *attrs, int attr_nid); +char *PKCS12_get_friendlyname(PKCS12_SAFEBAG *bag); +unsigned char *PKCS12_pbe_crypt(X509_ALGOR *algor, const char *pass, + int passlen, unsigned char *in, int inlen, + unsigned char **data, int *datalen, int en_de); +void * PKCS12_item_decrypt_d2i(X509_ALGOR *algor, const ASN1_ITEM *it, + const char *pass, int passlen, ASN1_OCTET_STRING *oct, int zbuf); +ASN1_OCTET_STRING *PKCS12_item_i2d_encrypt(X509_ALGOR *algor, const ASN1_ITEM *it, + const char *pass, int passlen, + void *obj, int zbuf); +PKCS12 *PKCS12_init(int mode); +int PKCS12_key_gen_asc(const char *pass, int passlen, unsigned char *salt, + int saltlen, int id, int iter, int n, + unsigned char *out, const EVP_MD *md_type); +int PKCS12_key_gen_uni(unsigned char *pass, int passlen, unsigned char *salt, int saltlen, int id, int iter, int n, unsigned char *out, const EVP_MD *md_type); +int PKCS12_PBE_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass, int passlen, + ASN1_TYPE *param, const EVP_CIPHER *cipher, const EVP_MD *md_type, + int en_de); +int PKCS12_gen_mac(PKCS12 *p12, const char *pass, int passlen, + unsigned char *mac, unsigned int *maclen); +int PKCS12_verify_mac(PKCS12 *p12, const char *pass, int passlen); +int PKCS12_set_mac(PKCS12 *p12, const char *pass, int passlen, + unsigned char *salt, int saltlen, int iter, + const EVP_MD *md_type); +int PKCS12_setup_mac(PKCS12 *p12, int iter, unsigned char *salt, + int saltlen, const EVP_MD *md_type); +unsigned char *asc2uni(const char *asc, int asclen, unsigned char **uni, int *unilen); +char *uni2asc(unsigned char *uni, int unilen); + +DECLARE_ASN1_FUNCTIONS(PKCS12) +DECLARE_ASN1_FUNCTIONS(PKCS12_MAC_DATA) +DECLARE_ASN1_FUNCTIONS(PKCS12_SAFEBAG) +DECLARE_ASN1_FUNCTIONS(PKCS12_BAGS) + +DECLARE_ASN1_ITEM(PKCS12_SAFEBAGS) +DECLARE_ASN1_ITEM(PKCS12_AUTHSAFES) + +void PKCS12_PBE_add(void); +int PKCS12_parse(PKCS12 *p12, const char *pass, EVP_PKEY **pkey, X509 **cert, + STACK_OF(X509) **ca); +PKCS12 *PKCS12_create(char *pass, char *name, EVP_PKEY *pkey, X509 *cert, + STACK_OF(X509) *ca, int nid_key, int nid_cert, int iter, + int mac_iter, int keytype); + +PKCS12_SAFEBAG *PKCS12_add_cert(STACK_OF(PKCS12_SAFEBAG) **pbags, X509 *cert); +PKCS12_SAFEBAG *PKCS12_add_key(STACK_OF(PKCS12_SAFEBAG) **pbags, EVP_PKEY *key, + int key_usage, int iter, + int key_nid, char *pass); +int PKCS12_add_safe(STACK_OF(PKCS7) **psafes, STACK_OF(PKCS12_SAFEBAG) *bags, + int safe_nid, int iter, char *pass); +PKCS12 *PKCS12_add_safes(STACK_OF(PKCS7) *safes, int p7_nid); + +int i2d_PKCS12_bio(BIO *bp, PKCS12 *p12); +int i2d_PKCS12_fp(FILE *fp, PKCS12 *p12); +PKCS12 *d2i_PKCS12_bio(BIO *bp, PKCS12 **p12); +PKCS12 *d2i_PKCS12_fp(FILE *fp, PKCS12 **p12); +int PKCS12_newpass(PKCS12 *p12, char *oldpass, char *newpass); + +/* BEGIN ERROR CODES */ +/* The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ +void ERR_load_PKCS12_strings(void); + +/* Error codes for the PKCS12 functions. */ + +/* Function codes. */ +#define PKCS12_F_PARSE_BAG 129 +#define PKCS12_F_PARSE_BAGS 103 +#define PKCS12_F_PKCS12_ADD_FRIENDLYNAME 100 +#define PKCS12_F_PKCS12_ADD_FRIENDLYNAME_ASC 127 +#define PKCS12_F_PKCS12_ADD_FRIENDLYNAME_UNI 102 +#define PKCS12_F_PKCS12_ADD_LOCALKEYID 104 +#define PKCS12_F_PKCS12_CREATE 105 +#define PKCS12_F_PKCS12_GEN_MAC 107 +#define PKCS12_F_PKCS12_INIT 109 +#define PKCS12_F_PKCS12_ITEM_DECRYPT_D2I 106 +#define PKCS12_F_PKCS12_ITEM_I2D_ENCRYPT 108 +#define PKCS12_F_PKCS12_ITEM_PACK_SAFEBAG 117 +#define PKCS12_F_PKCS12_KEY_GEN_ASC 110 +#define PKCS12_F_PKCS12_KEY_GEN_UNI 111 +#define PKCS12_F_PKCS12_MAKE_KEYBAG 112 +#define PKCS12_F_PKCS12_MAKE_SHKEYBAG 113 +#define PKCS12_F_PKCS12_NEWPASS 128 +#define PKCS12_F_PKCS12_PACK_P7DATA 114 +#define PKCS12_F_PKCS12_PACK_P7ENCDATA 115 +#define PKCS12_F_PKCS12_PARSE 118 +#define PKCS12_F_PKCS12_PBE_CRYPT 119 +#define PKCS12_F_PKCS12_PBE_KEYIVGEN 120 +#define PKCS12_F_PKCS12_SETUP_MAC 122 +#define PKCS12_F_PKCS12_SET_MAC 123 +#define PKCS12_F_PKCS12_UNPACK_AUTHSAFES 130 +#define PKCS12_F_PKCS12_UNPACK_P7DATA 131 +#define PKCS12_F_PKCS12_VERIFY_MAC 126 +#define PKCS12_F_PKCS8_ADD_KEYUSAGE 124 +#define PKCS12_F_PKCS8_ENCRYPT 125 + +/* Reason codes. */ +#define PKCS12_R_CANT_PACK_STRUCTURE 100 +#define PKCS12_R_CONTENT_TYPE_NOT_DATA 121 +#define PKCS12_R_DECODE_ERROR 101 +#define PKCS12_R_ENCODE_ERROR 102 +#define PKCS12_R_ENCRYPT_ERROR 103 +#define PKCS12_R_ERROR_SETTING_ENCRYPTED_DATA_TYPE 120 +#define PKCS12_R_INVALID_NULL_ARGUMENT 104 +#define PKCS12_R_INVALID_NULL_PKCS12_POINTER 105 +#define PKCS12_R_IV_GEN_ERROR 106 +#define PKCS12_R_KEY_GEN_ERROR 107 +#define PKCS12_R_MAC_ABSENT 108 +#define PKCS12_R_MAC_GENERATION_ERROR 109 +#define PKCS12_R_MAC_SETUP_ERROR 110 +#define PKCS12_R_MAC_STRING_SET_ERROR 111 +#define PKCS12_R_MAC_VERIFY_ERROR 112 +#define PKCS12_R_MAC_VERIFY_FAILURE 113 +#define PKCS12_R_PARSE_ERROR 114 +#define PKCS12_R_PKCS12_ALGOR_CIPHERINIT_ERROR 115 +#define PKCS12_R_PKCS12_CIPHERFINAL_ERROR 116 +#define PKCS12_R_PKCS12_PBE_CRYPT_ERROR 117 +#define PKCS12_R_UNKNOWN_DIGEST_ALGORITHM 118 +#define PKCS12_R_UNSUPPORTED_PKCS12_MODE 119 + +#ifdef __cplusplus +} +#endif +#endif diff --git a/lib_tls/include/openssl/pkcs7.h b/lib_tls/include/openssl/pkcs7.h new file mode 100644 index 000000000..cc092d262 --- /dev/null +++ b/lib_tls/include/openssl/pkcs7.h @@ -0,0 +1,464 @@ +/* crypto/pkcs7/pkcs7.h */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#ifndef HEADER_PKCS7_H +#define HEADER_PKCS7_H + +#include +#include +#include + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef OPENSSL_SYS_WIN32 +/* Under Win32 thes are defined in wincrypt.h */ +#undef PKCS7_ISSUER_AND_SERIAL +#undef PKCS7_SIGNER_INFO +#endif + +/* +Encryption_ID DES-CBC +Digest_ID MD5 +Digest_Encryption_ID rsaEncryption +Key_Encryption_ID rsaEncryption +*/ + +typedef struct pkcs7_issuer_and_serial_st + { + X509_NAME *issuer; + ASN1_INTEGER *serial; + } PKCS7_ISSUER_AND_SERIAL; + +typedef struct pkcs7_signer_info_st + { + ASN1_INTEGER *version; /* version 1 */ + PKCS7_ISSUER_AND_SERIAL *issuer_and_serial; + X509_ALGOR *digest_alg; + STACK_OF(X509_ATTRIBUTE) *auth_attr; /* [ 0 ] */ + X509_ALGOR *digest_enc_alg; + ASN1_OCTET_STRING *enc_digest; + STACK_OF(X509_ATTRIBUTE) *unauth_attr; /* [ 1 ] */ + + /* The private key to sign with */ + EVP_PKEY *pkey; + } PKCS7_SIGNER_INFO; + +DECLARE_STACK_OF(PKCS7_SIGNER_INFO) +DECLARE_ASN1_SET_OF(PKCS7_SIGNER_INFO) + +typedef struct pkcs7_recip_info_st + { + ASN1_INTEGER *version; /* version 0 */ + PKCS7_ISSUER_AND_SERIAL *issuer_and_serial; + X509_ALGOR *key_enc_algor; + ASN1_OCTET_STRING *enc_key; + X509 *cert; /* get the pub-key from this */ + } PKCS7_RECIP_INFO; + +DECLARE_STACK_OF(PKCS7_RECIP_INFO) +DECLARE_ASN1_SET_OF(PKCS7_RECIP_INFO) + +typedef struct pkcs7_signed_st + { + ASN1_INTEGER *version; /* version 1 */ + STACK_OF(X509_ALGOR) *md_algs; /* md used */ + STACK_OF(X509) *cert; /* [ 0 ] */ + STACK_OF(X509_CRL) *crl; /* [ 1 ] */ + STACK_OF(PKCS7_SIGNER_INFO) *signer_info; + + struct pkcs7_st *contents; + } PKCS7_SIGNED; +/* The above structure is very very similar to PKCS7_SIGN_ENVELOPE. + * How about merging the two */ + +typedef struct pkcs7_enc_content_st + { + ASN1_OBJECT *content_type; + X509_ALGOR *algorithm; + ASN1_OCTET_STRING *enc_data; /* [ 0 ] */ + const EVP_CIPHER *cipher; + } PKCS7_ENC_CONTENT; + +typedef struct pkcs7_enveloped_st + { + ASN1_INTEGER *version; /* version 0 */ + STACK_OF(PKCS7_RECIP_INFO) *recipientinfo; + PKCS7_ENC_CONTENT *enc_data; + } PKCS7_ENVELOPE; + +typedef struct pkcs7_signedandenveloped_st + { + ASN1_INTEGER *version; /* version 1 */ + STACK_OF(X509_ALGOR) *md_algs; /* md used */ + STACK_OF(X509) *cert; /* [ 0 ] */ + STACK_OF(X509_CRL) *crl; /* [ 1 ] */ + STACK_OF(PKCS7_SIGNER_INFO) *signer_info; + + PKCS7_ENC_CONTENT *enc_data; + STACK_OF(PKCS7_RECIP_INFO) *recipientinfo; + } PKCS7_SIGN_ENVELOPE; + +typedef struct pkcs7_digest_st + { + ASN1_INTEGER *version; /* version 0 */ + X509_ALGOR *md; /* md used */ + struct pkcs7_st *contents; + ASN1_OCTET_STRING *digest; + } PKCS7_DIGEST; + +typedef struct pkcs7_encrypted_st + { + ASN1_INTEGER *version; /* version 0 */ + PKCS7_ENC_CONTENT *enc_data; + } PKCS7_ENCRYPT; + +typedef struct pkcs7_st + { + /* The following is non NULL if it contains ASN1 encoding of + * this structure */ + unsigned char *asn1; + long length; + +#define PKCS7_S_HEADER 0 +#define PKCS7_S_BODY 1 +#define PKCS7_S_TAIL 2 + int state; /* used during processing */ + + int detached; + + ASN1_OBJECT *type; + /* content as defined by the type */ + /* all encryption/message digests are applied to the 'contents', + * leaving out the 'type' field. */ + union { + char *ptr; + + /* NID_pkcs7_data */ + ASN1_OCTET_STRING *data; + + /* NID_pkcs7_signed */ + PKCS7_SIGNED *sign; + + /* NID_pkcs7_enveloped */ + PKCS7_ENVELOPE *enveloped; + + /* NID_pkcs7_signedAndEnveloped */ + PKCS7_SIGN_ENVELOPE *signed_and_enveloped; + + /* NID_pkcs7_digest */ + PKCS7_DIGEST *digest; + + /* NID_pkcs7_encrypted */ + PKCS7_ENCRYPT *encrypted; + + /* Anything else */ + ASN1_TYPE *other; + } d; + } PKCS7; + +DECLARE_STACK_OF(PKCS7) +DECLARE_ASN1_SET_OF(PKCS7) +DECLARE_PKCS12_STACK_OF(PKCS7) + +#define PKCS7_OP_SET_DETACHED_SIGNATURE 1 +#define PKCS7_OP_GET_DETACHED_SIGNATURE 2 + +#define PKCS7_get_signed_attributes(si) ((si)->auth_attr) +#define PKCS7_get_attributes(si) ((si)->unauth_attr) + +#define PKCS7_type_is_signed(a) (OBJ_obj2nid((a)->type) == NID_pkcs7_signed) +#define PKCS7_type_is_encrypted(a) (OBJ_obj2nid((a)->type) == NID_pkcs7_encrypted) +#define PKCS7_type_is_enveloped(a) (OBJ_obj2nid((a)->type) == NID_pkcs7_enveloped) +#define PKCS7_type_is_signedAndEnveloped(a) \ + (OBJ_obj2nid((a)->type) == NID_pkcs7_signedAndEnveloped) +#define PKCS7_type_is_data(a) (OBJ_obj2nid((a)->type) == NID_pkcs7_data) + +#define PKCS7_type_is_digest(a) (OBJ_obj2nid((a)->type) == NID_pkcs7_digest) + +#define PKCS7_set_detached(p,v) \ + PKCS7_ctrl(p,PKCS7_OP_SET_DETACHED_SIGNATURE,v,NULL) +#define PKCS7_get_detached(p) \ + PKCS7_ctrl(p,PKCS7_OP_GET_DETACHED_SIGNATURE,0,NULL) + +#define PKCS7_is_detached(p7) (PKCS7_type_is_signed(p7) && PKCS7_get_detached(p7)) + +#ifdef SSLEAY_MACROS +#ifndef PKCS7_ISSUER_AND_SERIAL_digest +#define PKCS7_ISSUER_AND_SERIAL_digest(data,type,md,len) \ + ASN1_digest((int (*)())i2d_PKCS7_ISSUER_AND_SERIAL,type,\ + (char *)data,md,len) +#endif +#endif + +/* S/MIME related flags */ + +#define PKCS7_TEXT 0x1 +#define PKCS7_NOCERTS 0x2 +#define PKCS7_NOSIGS 0x4 +#define PKCS7_NOCHAIN 0x8 +#define PKCS7_NOINTERN 0x10 +#define PKCS7_NOVERIFY 0x20 +#define PKCS7_DETACHED 0x40 +#define PKCS7_BINARY 0x80 +#define PKCS7_NOATTR 0x100 +#define PKCS7_NOSMIMECAP 0x200 +#define PKCS7_NOOLDMIMETYPE 0x400 +#define PKCS7_CRLFEOL 0x800 +#define PKCS7_STREAM 0x1000 +#define PKCS7_NOCRL 0x2000 + +/* Flags: for compatibility with older code */ + +#define SMIME_TEXT PKCS7_TEXT +#define SMIME_NOCERTS PKCS7_NOCERTS +#define SMIME_NOSIGS PKCS7_NOSIGS +#define SMIME_NOCHAIN PKCS7_NOCHAIN +#define SMIME_NOINTERN PKCS7_NOINTERN +#define SMIME_NOVERIFY PKCS7_NOVERIFY +#define SMIME_DETACHED PKCS7_DETACHED +#define SMIME_BINARY PKCS7_BINARY +#define SMIME_NOATTR PKCS7_NOATTR + +DECLARE_ASN1_FUNCTIONS(PKCS7_ISSUER_AND_SERIAL) + +#ifndef SSLEAY_MACROS +int PKCS7_ISSUER_AND_SERIAL_digest(PKCS7_ISSUER_AND_SERIAL *data,const EVP_MD *type, + unsigned char *md,unsigned int *len); +#ifndef OPENSSL_NO_FP_API +PKCS7 *d2i_PKCS7_fp(FILE *fp,PKCS7 **p7); +int i2d_PKCS7_fp(FILE *fp,PKCS7 *p7); +#endif +PKCS7 *PKCS7_dup(PKCS7 *p7); +PKCS7 *d2i_PKCS7_bio(BIO *bp,PKCS7 **p7); +int i2d_PKCS7_bio(BIO *bp,PKCS7 *p7); +#endif + +DECLARE_ASN1_FUNCTIONS(PKCS7_SIGNER_INFO) +DECLARE_ASN1_FUNCTIONS(PKCS7_RECIP_INFO) +DECLARE_ASN1_FUNCTIONS(PKCS7_SIGNED) +DECLARE_ASN1_FUNCTIONS(PKCS7_ENC_CONTENT) +DECLARE_ASN1_FUNCTIONS(PKCS7_ENVELOPE) +DECLARE_ASN1_FUNCTIONS(PKCS7_SIGN_ENVELOPE) +DECLARE_ASN1_FUNCTIONS(PKCS7_DIGEST) +DECLARE_ASN1_FUNCTIONS(PKCS7_ENCRYPT) +DECLARE_ASN1_FUNCTIONS(PKCS7) + +DECLARE_ASN1_ITEM(PKCS7_ATTR_SIGN) +DECLARE_ASN1_ITEM(PKCS7_ATTR_VERIFY) + +DECLARE_ASN1_NDEF_FUNCTION(PKCS7) + +long PKCS7_ctrl(PKCS7 *p7, int cmd, long larg, char *parg); + +int PKCS7_set_type(PKCS7 *p7, int type); +int PKCS7_set0_type_other(PKCS7 *p7, int type, ASN1_TYPE *other); +int PKCS7_set_content(PKCS7 *p7, PKCS7 *p7_data); +int PKCS7_SIGNER_INFO_set(PKCS7_SIGNER_INFO *p7i, X509 *x509, EVP_PKEY *pkey, + const EVP_MD *dgst); +int PKCS7_add_signer(PKCS7 *p7, PKCS7_SIGNER_INFO *p7i); +int PKCS7_add_certificate(PKCS7 *p7, X509 *x509); +int PKCS7_add_crl(PKCS7 *p7, X509_CRL *x509); +int PKCS7_content_new(PKCS7 *p7, int nid); +int PKCS7_dataVerify(X509_STORE *cert_store, X509_STORE_CTX *ctx, + BIO *bio, PKCS7 *p7, PKCS7_SIGNER_INFO *si); +int PKCS7_signatureVerify(BIO *bio, PKCS7 *p7, PKCS7_SIGNER_INFO *si, + X509 *x509); + +BIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio); +int PKCS7_dataFinal(PKCS7 *p7, BIO *bio); +BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKEY *pkey, BIO *in_bio, X509 *pcert); + + +PKCS7_SIGNER_INFO *PKCS7_add_signature(PKCS7 *p7, X509 *x509, + EVP_PKEY *pkey, const EVP_MD *dgst); +X509 *PKCS7_cert_from_signer_info(PKCS7 *p7, PKCS7_SIGNER_INFO *si); +int PKCS7_set_digest(PKCS7 *p7, const EVP_MD *md); +STACK_OF(PKCS7_SIGNER_INFO) *PKCS7_get_signer_info(PKCS7 *p7); + +PKCS7_RECIP_INFO *PKCS7_add_recipient(PKCS7 *p7, X509 *x509); +int PKCS7_add_recipient_info(PKCS7 *p7, PKCS7_RECIP_INFO *ri); +int PKCS7_RECIP_INFO_set(PKCS7_RECIP_INFO *p7i, X509 *x509); +int PKCS7_set_cipher(PKCS7 *p7, const EVP_CIPHER *cipher); + +PKCS7_ISSUER_AND_SERIAL *PKCS7_get_issuer_and_serial(PKCS7 *p7, int idx); +ASN1_OCTET_STRING *PKCS7_digest_from_attributes(STACK_OF(X509_ATTRIBUTE) *sk); +int PKCS7_add_signed_attribute(PKCS7_SIGNER_INFO *p7si,int nid,int type, + void *data); +int PKCS7_add_attribute (PKCS7_SIGNER_INFO *p7si, int nid, int atrtype, + void *value); +ASN1_TYPE *PKCS7_get_attribute(PKCS7_SIGNER_INFO *si, int nid); +ASN1_TYPE *PKCS7_get_signed_attribute(PKCS7_SIGNER_INFO *si, int nid); +int PKCS7_set_signed_attributes(PKCS7_SIGNER_INFO *p7si, + STACK_OF(X509_ATTRIBUTE) *sk); +int PKCS7_set_attributes(PKCS7_SIGNER_INFO *p7si,STACK_OF(X509_ATTRIBUTE) *sk); + + +PKCS7 *PKCS7_sign(X509 *signcert, EVP_PKEY *pkey, STACK_OF(X509) *certs, + BIO *data, int flags); +int PKCS7_verify(PKCS7 *p7, STACK_OF(X509) *certs, X509_STORE *store, + BIO *indata, BIO *out, int flags); +STACK_OF(X509) *PKCS7_get0_signers(PKCS7 *p7, STACK_OF(X509) *certs, int flags); +PKCS7 *PKCS7_encrypt(STACK_OF(X509) *certs, BIO *in, const EVP_CIPHER *cipher, + int flags); +int PKCS7_decrypt(PKCS7 *p7, EVP_PKEY *pkey, X509 *cert, BIO *data, int flags); + +int PKCS7_add_attrib_smimecap(PKCS7_SIGNER_INFO *si, + STACK_OF(X509_ALGOR) *cap); +STACK_OF(X509_ALGOR) *PKCS7_get_smimecap(PKCS7_SIGNER_INFO *si); +int PKCS7_simple_smimecap(STACK_OF(X509_ALGOR) *sk, int nid, int arg); + +int SMIME_write_PKCS7(BIO *bio, PKCS7 *p7, BIO *data, int flags); +PKCS7 *SMIME_read_PKCS7(BIO *bio, BIO **bcont); +int SMIME_crlf_copy(BIO *in, BIO *out, int flags); +int SMIME_text(BIO *in, BIO *out); + +/* BEGIN ERROR CODES */ +/* The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ +void ERR_load_PKCS7_strings(void); + +/* Error codes for the PKCS7 functions. */ + +/* Function codes. */ +#define PKCS7_F_B64_READ_PKCS7 120 +#define PKCS7_F_B64_WRITE_PKCS7 121 +#define PKCS7_F_PKCS7_ADD_ATTRIB_SMIMECAP 118 +#define PKCS7_F_PKCS7_ADD_CERTIFICATE 100 +#define PKCS7_F_PKCS7_ADD_CRL 101 +#define PKCS7_F_PKCS7_ADD_RECIPIENT_INFO 102 +#define PKCS7_F_PKCS7_ADD_SIGNER 103 +#define PKCS7_F_PKCS7_BIO_ADD_DIGEST 125 +#define PKCS7_F_PKCS7_CTRL 104 +#define PKCS7_F_PKCS7_DATADECODE 112 +#define PKCS7_F_PKCS7_DATAFINAL 128 +#define PKCS7_F_PKCS7_DATAINIT 105 +#define PKCS7_F_PKCS7_DATASIGN 106 +#define PKCS7_F_PKCS7_DATAVERIFY 107 +#define PKCS7_F_PKCS7_DECRYPT 114 +#define PKCS7_F_PKCS7_ENCRYPT 115 +#define PKCS7_F_PKCS7_FIND_DIGEST 127 +#define PKCS7_F_PKCS7_GET0_SIGNERS 124 +#define PKCS7_F_PKCS7_SET_CIPHER 108 +#define PKCS7_F_PKCS7_SET_CONTENT 109 +#define PKCS7_F_PKCS7_SET_DIGEST 126 +#define PKCS7_F_PKCS7_SET_TYPE 110 +#define PKCS7_F_PKCS7_SIGN 116 +#define PKCS7_F_PKCS7_SIGNATUREVERIFY 113 +#define PKCS7_F_PKCS7_SIMPLE_SMIMECAP 119 +#define PKCS7_F_PKCS7_VERIFY 117 +#define PKCS7_F_SMIME_READ_PKCS7 122 +#define PKCS7_F_SMIME_TEXT 123 + +/* Reason codes. */ +#define PKCS7_R_CERTIFICATE_VERIFY_ERROR 117 +#define PKCS7_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER 144 +#define PKCS7_R_CIPHER_NOT_INITIALIZED 116 +#define PKCS7_R_CONTENT_AND_DATA_PRESENT 118 +#define PKCS7_R_DECODE_ERROR 130 +#define PKCS7_R_DECRYPTED_KEY_IS_WRONG_LENGTH 100 +#define PKCS7_R_DECRYPT_ERROR 119 +#define PKCS7_R_DIGEST_FAILURE 101 +#define PKCS7_R_ERROR_ADDING_RECIPIENT 120 +#define PKCS7_R_ERROR_SETTING_CIPHER 121 +#define PKCS7_R_INVALID_MIME_TYPE 131 +#define PKCS7_R_INVALID_NULL_POINTER 143 +#define PKCS7_R_MIME_NO_CONTENT_TYPE 132 +#define PKCS7_R_MIME_PARSE_ERROR 133 +#define PKCS7_R_MIME_SIG_PARSE_ERROR 134 +#define PKCS7_R_MISSING_CERIPEND_INFO 103 +#define PKCS7_R_NO_CONTENT 122 +#define PKCS7_R_NO_CONTENT_TYPE 135 +#define PKCS7_R_NO_MULTIPART_BODY_FAILURE 136 +#define PKCS7_R_NO_MULTIPART_BOUNDARY 137 +#define PKCS7_R_NO_RECIPIENT_MATCHES_CERTIFICATE 115 +#define PKCS7_R_NO_RECIPIENT_MATCHES_KEY 146 +#define PKCS7_R_NO_SIGNATURES_ON_DATA 123 +#define PKCS7_R_NO_SIGNERS 142 +#define PKCS7_R_NO_SIG_CONTENT_TYPE 138 +#define PKCS7_R_OPERATION_NOT_SUPPORTED_ON_THIS_TYPE 104 +#define PKCS7_R_PKCS7_ADD_SIGNATURE_ERROR 124 +#define PKCS7_R_PKCS7_DATAFINAL 126 +#define PKCS7_R_PKCS7_DATAFINAL_ERROR 125 +#define PKCS7_R_PKCS7_DATASIGN 145 +#define PKCS7_R_PKCS7_PARSE_ERROR 139 +#define PKCS7_R_PKCS7_SIG_PARSE_ERROR 140 +#define PKCS7_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE 127 +#define PKCS7_R_SIGNATURE_FAILURE 105 +#define PKCS7_R_SIGNER_CERTIFICATE_NOT_FOUND 128 +#define PKCS7_R_SIG_INVALID_MIME_TYPE 141 +#define PKCS7_R_SMIME_TEXT_ERROR 129 +#define PKCS7_R_UNABLE_TO_FIND_CERTIFICATE 106 +#define PKCS7_R_UNABLE_TO_FIND_MEM_BIO 107 +#define PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST 108 +#define PKCS7_R_UNKNOWN_DIGEST_TYPE 109 +#define PKCS7_R_UNKNOWN_OPERATION 110 +#define PKCS7_R_UNSUPPORTED_CIPHER_TYPE 111 +#define PKCS7_R_UNSUPPORTED_CONTENT_TYPE 112 +#define PKCS7_R_WRONG_CONTENT_TYPE 113 +#define PKCS7_R_WRONG_PKCS7_TYPE 114 + +#ifdef __cplusplus +} +#endif +#endif diff --git a/lib_tls/include/openssl/pq_compat.h b/lib_tls/include/openssl/pq_compat.h new file mode 100644 index 000000000..fd3657888 --- /dev/null +++ b/lib_tls/include/openssl/pq_compat.h @@ -0,0 +1,147 @@ +/* crypto/pqueue/pqueue_compat.h */ +/* + * DTLS implementation written by Nagendra Modadugu + * (nagendra@cs.stanford.edu) for the OpenSSL project 2005. + */ +/* ==================================================================== + * Copyright (c) 1999-2005 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#include +#include + +/* + * The purpose of this header file is for supporting 64-bit integer + * manipulation on 32-bit (and lower) machines. Currently the only + * such environment is VMS, Utrix and those with smaller default integer + * sizes than 32 bits. For all such environment, we fall back to using + * BIGNUM. We may need to fine tune the conditions for systems that + * are incorrectly configured. + * + * The only clients of this code are (1) pqueue for priority, and + * (2) DTLS, for sequence number manipulation. + */ + +#if (defined(THIRTY_TWO_BIT) && !defined(BN_LLONG)) || defined(SIXTEEN_BIT) || defined(EIGHT_BIT) + +#define PQ_64BIT_IS_INTEGER 0 +#define PQ_64BIT_IS_BIGNUM 1 + +#define PQ_64BIT BIGNUM +#define PQ_64BIT_CTX BN_CTX + +#define pq_64bit_init(x) BN_init(x) +#define pq_64bit_free(x) BN_free(x) + +#define pq_64bit_ctx_new(ctx) BN_CTX_new() +#define pq_64bit_ctx_free(x) BN_CTX_free(x) + +#define pq_64bit_assign(x, y) BN_copy(x, y) +#define pq_64bit_assign_word(x, y) BN_set_word(x, y) +#define pq_64bit_gt(x, y) BN_ucmp(x, y) >= 1 ? 1 : 0 +#define pq_64bit_eq(x, y) BN_ucmp(x, y) == 0 ? 1 : 0 +#define pq_64bit_add_word(x, w) BN_add_word(x, w) +#define pq_64bit_sub(r, x, y) BN_sub(r, x, y) +#define pq_64bit_sub_word(x, w) BN_sub_word(x, w) +#define pq_64bit_mod(r, x, n, ctx) BN_mod(r, x, n, ctx) + +#define pq_64bit_bin2num(bn, bytes, len) BN_bin2bn(bytes, len, bn) +#define pq_64bit_num2bin(bn, bytes) BN_bn2bin(bn, bytes) +#define pq_64bit_get_word(x) BN_get_word(x) +#define pq_64bit_is_bit_set(x, offset) BN_is_bit_set(x, offset) +#define pq_64bit_lshift(r, x, shift) BN_lshift(r, x, shift) +#define pq_64bit_set_bit(x, num) BN_set_bit(x, num) +#define pq_64bit_get_length(x) BN_num_bits((x)) + +#else + +#define PQ_64BIT_IS_INTEGER 1 +#define PQ_64BIT_IS_BIGNUM 0 + +#if defined(SIXTY_FOUR_BIT) +#define PQ_64BIT BN_ULONG +#define PQ_64BIT_PRINT "%lld" +#elif defined(SIXTY_FOUR_BIT_LONG) +#define PQ_64BIT BN_ULONG +#define PQ_64BIT_PRINT "%ld" +#elif defined(THIRTY_TWO_BIT) +#define PQ_64BIT BN_ULLONG +#define PQ_64BIT_PRINT "%lld" +#endif + +#define PQ_64BIT_CTX void + +#define pq_64bit_init(x) +#define pq_64bit_free(x) +#define pq_64bit_ctx_new(ctx) (ctx) +#define pq_64bit_ctx_free(x) + +#define pq_64bit_assign(x, y) (*(x) = *(y)) +#define pq_64bit_assign_word(x, y) (*(x) = y) +#define pq_64bit_gt(x, y) (*(x) > *(y)) +#define pq_64bit_eq(x, y) (*(x) == *(y)) +#define pq_64bit_add_word(x, w) (*(x) = (*(x) + (w))) +#define pq_64bit_sub(r, x, y) (*(r) = (*(x) - *(y))) +#define pq_64bit_sub_word(x, w) (*(x) = (*(x) - (w))) +#define pq_64bit_mod(r, x, n, ctx) + +#define pq_64bit_bin2num(num, bytes, len) bytes_to_long_long(bytes, num) +#define pq_64bit_num2bin(num, bytes) long_long_to_bytes(num, bytes) +#define pq_64bit_get_word(x) *(x) +#define pq_64bit_lshift(r, x, shift) (*(r) = (*(x) << (shift))) +#define pq_64bit_set_bit(x, num) do { \ + PQ_64BIT mask = 1; \ + mask = mask << (num); \ + *(x) |= mask; \ + } while(0) +#endif /* OPENSSL_SYS_VMS */ diff --git a/lib_tls/include/openssl/pqueue.h b/lib_tls/include/openssl/pqueue.h new file mode 100644 index 000000000..02386d130 --- /dev/null +++ b/lib_tls/include/openssl/pqueue.h @@ -0,0 +1,95 @@ +/* crypto/pqueue/pqueue.h */ +/* + * DTLS implementation written by Nagendra Modadugu + * (nagendra@cs.stanford.edu) for the OpenSSL project 2005. + */ +/* ==================================================================== + * Copyright (c) 1999-2005 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#ifndef HEADER_PQUEUE_H +#define HEADER_PQUEUE_H + +#include +#include +#include + +#include + +typedef struct _pqueue *pqueue; + +typedef struct _pitem + { + PQ_64BIT priority; + void *data; + struct _pitem *next; + } pitem; + +typedef struct _pitem *piterator; + +pitem *pitem_new(PQ_64BIT priority, void *data); +void pitem_free(pitem *item); + +pqueue pqueue_new(void); +void pqueue_free(pqueue pq); + +pitem *pqueue_insert(pqueue pq, pitem *item); +pitem *pqueue_peek(pqueue pq); +pitem *pqueue_pop(pqueue pq); +pitem *pqueue_find(pqueue pq, PQ_64BIT priority); +pitem *pqueue_iterator(pqueue pq); +pitem *pqueue_next(piterator *iter); + +void pqueue_print(pqueue pq); + +#endif /* ! HEADER_PQUEUE_H */ diff --git a/lib_tls/include/openssl/rand.h b/lib_tls/include/openssl/rand.h new file mode 100644 index 000000000..ac6c02176 --- /dev/null +++ b/lib_tls/include/openssl/rand.h @@ -0,0 +1,140 @@ +/* crypto/rand/rand.h */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#ifndef HEADER_RAND_H +#define HEADER_RAND_H + +#include +#include +#include + +#if defined(OPENSSL_SYS_WINDOWS) +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(OPENSSL_FIPS) +#define FIPS_RAND_SIZE_T size_t +#endif + +/* Already defined in ossl_typ.h */ +/* typedef struct rand_meth_st RAND_METHOD; */ + +struct rand_meth_st + { + void (*seed)(const void *buf, int num); + int (*bytes)(unsigned char *buf, int num); + void (*cleanup)(void); + void (*add)(const void *buf, int num, double entropy); + int (*pseudorand)(unsigned char *buf, int num); + int (*status)(void); + }; + +#ifdef BN_DEBUG +extern int rand_predictable; +#endif + +int RAND_set_rand_method(const RAND_METHOD *meth); +const RAND_METHOD *RAND_get_rand_method(void); +#ifndef OPENSSL_NO_ENGINE +int RAND_set_rand_engine(ENGINE *engine); +#endif +RAND_METHOD *RAND_SSLeay(void); +void RAND_cleanup(void ); +int RAND_bytes(unsigned char *buf,int num); +int RAND_pseudo_bytes(unsigned char *buf,int num); +void RAND_seed(const void *buf,int num); +void RAND_add(const void *buf,int num,double entropy); +int RAND_load_file(const char *file,long max_bytes); +int RAND_write_file(const char *file); +const char *RAND_file_name(char *file,size_t num); +int RAND_status(void); +int RAND_query_egd_bytes(const char *path, unsigned char *buf, int bytes); +int RAND_egd(const char *path); +int RAND_egd_bytes(const char *path,int bytes); +int RAND_poll(void); + +#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32) + +void RAND_screen(void); +int RAND_event(UINT, WPARAM, LPARAM); + +#endif + +/* BEGIN ERROR CODES */ +/* The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ +void ERR_load_RAND_strings(void); + +/* Error codes for the RAND functions. */ + +/* Function codes. */ +#define RAND_F_RAND_GET_RAND_METHOD 101 +#define RAND_F_SSLEAY_RAND_BYTES 100 + +/* Reason codes. */ +#define RAND_R_PRNG_NOT_SEEDED 100 + +#ifdef __cplusplus +} +#endif +#endif diff --git a/lib_tls/include/openssl/rc2.h b/lib_tls/include/openssl/rc2.h new file mode 100644 index 000000000..34c836231 --- /dev/null +++ b/lib_tls/include/openssl/rc2.h @@ -0,0 +1,101 @@ +/* crypto/rc2/rc2.h */ +/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#ifndef HEADER_RC2_H +#define HEADER_RC2_H + +#include /* OPENSSL_NO_RC2, RC2_INT */ +#ifdef OPENSSL_NO_RC2 +#error RC2 is disabled. +#endif + +#define RC2_ENCRYPT 1 +#define RC2_DECRYPT 0 + +#define RC2_BLOCK 8 +#define RC2_KEY_LENGTH 16 + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct rc2_key_st + { + RC2_INT data[64]; + } RC2_KEY; + + +void RC2_set_key(RC2_KEY *key, int len, const unsigned char *data,int bits); +void RC2_ecb_encrypt(const unsigned char *in,unsigned char *out,RC2_KEY *key, + int enc); +void RC2_encrypt(unsigned long *data,RC2_KEY *key); +void RC2_decrypt(unsigned long *data,RC2_KEY *key); +void RC2_cbc_encrypt(const unsigned char *in, unsigned char *out, long length, + RC2_KEY *ks, unsigned char *iv, int enc); +void RC2_cfb64_encrypt(const unsigned char *in, unsigned char *out, + long length, RC2_KEY *schedule, unsigned char *ivec, + int *num, int enc); +void RC2_ofb64_encrypt(const unsigned char *in, unsigned char *out, + long length, RC2_KEY *schedule, unsigned char *ivec, + int *num); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_tls/include/openssl/rc4.h b/lib_tls/include/openssl/rc4.h new file mode 100644 index 000000000..7aec04fe9 --- /dev/null +++ b/lib_tls/include/openssl/rc4.h @@ -0,0 +1,87 @@ +/* crypto/rc4/rc4.h */ +/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#ifndef HEADER_RC4_H +#define HEADER_RC4_H + +#include /* OPENSSL_NO_RC4, RC4_INT */ +#ifdef OPENSSL_NO_RC4 +#error RC4 is disabled. +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct rc4_key_st + { + RC4_INT x,y; + RC4_INT data[256]; + } RC4_KEY; + + +const char *RC4_options(void); +void RC4_set_key(RC4_KEY *key, int len, const unsigned char *data); +void RC4(RC4_KEY *key, unsigned long len, const unsigned char *indata, + unsigned char *outdata); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_tls/include/openssl/ripemd.h b/lib_tls/include/openssl/ripemd.h new file mode 100644 index 000000000..033a5965b --- /dev/null +++ b/lib_tls/include/openssl/ripemd.h @@ -0,0 +1,104 @@ +/* crypto/ripemd/ripemd.h */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#ifndef HEADER_RIPEMD_H +#define HEADER_RIPEMD_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef OPENSSL_NO_RIPEMD +#error RIPEMD is disabled. +#endif + +#if defined(OPENSSL_SYS_WIN16) || defined(__LP32__) +#define RIPEMD160_LONG unsigned long +#elif defined(OPENSSL_SYS_CRAY) || defined(__ILP64__) +#define RIPEMD160_LONG unsigned long +#define RIPEMD160_LONG_LOG2 3 +#else +#define RIPEMD160_LONG unsigned int +#endif + +#define RIPEMD160_CBLOCK 64 +#define RIPEMD160_LBLOCK (RIPEMD160_CBLOCK/4) +#define RIPEMD160_DIGEST_LENGTH 20 + +typedef struct RIPEMD160state_st + { + RIPEMD160_LONG A,B,C,D,E; + RIPEMD160_LONG Nl,Nh; + RIPEMD160_LONG data[RIPEMD160_LBLOCK]; + unsigned int num; + } RIPEMD160_CTX; + +int RIPEMD160_Init(RIPEMD160_CTX *c); +int RIPEMD160_Update(RIPEMD160_CTX *c, const void *data, size_t len); +int RIPEMD160_Final(unsigned char *md, RIPEMD160_CTX *c); +unsigned char *RIPEMD160(const unsigned char *d, size_t n, + unsigned char *md); +void RIPEMD160_Transform(RIPEMD160_CTX *c, const unsigned char *b); +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_tls/include/openssl/rsa.h b/lib_tls/include/openssl/rsa.h new file mode 100644 index 000000000..6b5e4f8a9 --- /dev/null +++ b/lib_tls/include/openssl/rsa.h @@ -0,0 +1,455 @@ +/* crypto/rsa/rsa.h */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#ifndef HEADER_RSA_H +#define HEADER_RSA_H + +#include + +#ifndef OPENSSL_NO_BIO +#include +#endif +#include +#include +#ifndef OPENSSL_NO_DEPRECATED +#include +#endif + +#ifdef OPENSSL_NO_RSA +#error RSA is disabled. +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* Declared already in ossl_typ.h */ +/* typedef struct rsa_st RSA; */ +/* typedef struct rsa_meth_st RSA_METHOD; */ + +struct rsa_meth_st + { + const char *name; + int (*rsa_pub_enc)(int flen,const unsigned char *from, + unsigned char *to, + RSA *rsa,int padding); + int (*rsa_pub_dec)(int flen,const unsigned char *from, + unsigned char *to, + RSA *rsa,int padding); + int (*rsa_priv_enc)(int flen,const unsigned char *from, + unsigned char *to, + RSA *rsa,int padding); + int (*rsa_priv_dec)(int flen,const unsigned char *from, + unsigned char *to, + RSA *rsa,int padding); + int (*rsa_mod_exp)(BIGNUM *r0,const BIGNUM *I,RSA *rsa,BN_CTX *ctx); /* Can be null */ + int (*bn_mod_exp)(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx, + BN_MONT_CTX *m_ctx); /* Can be null */ + int (*init)(RSA *rsa); /* called at new */ + int (*finish)(RSA *rsa); /* called at free */ + int flags; /* RSA_METHOD_FLAG_* things */ + char *app_data; /* may be needed! */ +/* New sign and verify functions: some libraries don't allow arbitrary data + * to be signed/verified: this allows them to be used. Note: for this to work + * the RSA_public_decrypt() and RSA_private_encrypt() should *NOT* be used + * RSA_sign(), RSA_verify() should be used instead. Note: for backwards + * compatibility this functionality is only enabled if the RSA_FLAG_SIGN_VER + * option is set in 'flags'. + */ + int (*rsa_sign)(int type, + const unsigned char *m, unsigned int m_length, + unsigned char *sigret, unsigned int *siglen, const RSA *rsa); + int (*rsa_verify)(int dtype, + const unsigned char *m, unsigned int m_length, + unsigned char *sigbuf, unsigned int siglen, const RSA *rsa); +/* If this callback is NULL, the builtin software RSA key-gen will be used. This + * is for behavioural compatibility whilst the code gets rewired, but one day + * it would be nice to assume there are no such things as "builtin software" + * implementations. */ + int (*rsa_keygen)(RSA *rsa, int bits, BIGNUM *e, BN_GENCB *cb); + }; + +struct rsa_st + { + /* The first parameter is used to pickup errors where + * this is passed instead of aEVP_PKEY, it is set to 0 */ + int pad; + long version; + const RSA_METHOD *meth; + /* functional reference if 'meth' is ENGINE-provided */ + ENGINE *engine; + BIGNUM *n; + BIGNUM *e; + BIGNUM *d; + BIGNUM *p; + BIGNUM *q; + BIGNUM *dmp1; + BIGNUM *dmq1; + BIGNUM *iqmp; + /* be careful using this if the RSA structure is shared */ + CRYPTO_EX_DATA ex_data; + int references; + int flags; + + /* Used to cache montgomery values */ + BN_MONT_CTX *_method_mod_n; + BN_MONT_CTX *_method_mod_p; + BN_MONT_CTX *_method_mod_q; + + /* all BIGNUM values are actually in the following data, if it is not + * NULL */ + char *bignum_data; + BN_BLINDING *blinding; + BN_BLINDING *mt_blinding; + }; + +#ifndef OPENSSL_RSA_MAX_MODULUS_BITS +# define OPENSSL_RSA_MAX_MODULUS_BITS 16384 +#endif + +#ifndef OPENSSL_RSA_SMALL_MODULUS_BITS +# define OPENSSL_RSA_SMALL_MODULUS_BITS 3072 +#endif +#ifndef OPENSSL_RSA_MAX_PUBEXP_BITS +# define OPENSSL_RSA_MAX_PUBEXP_BITS 64 /* exponent limit enforced for "large" modulus only */ +#endif + +#define RSA_3 0x3L +#define RSA_F4 0x10001L + +#define RSA_METHOD_FLAG_NO_CHECK 0x0001 /* don't check pub/private match */ + +#define RSA_FLAG_CACHE_PUBLIC 0x0002 +#define RSA_FLAG_CACHE_PRIVATE 0x0004 +#define RSA_FLAG_BLINDING 0x0008 +#define RSA_FLAG_THREAD_SAFE 0x0010 +/* This flag means the private key operations will be handled by rsa_mod_exp + * and that they do not depend on the private key components being present: + * for example a key stored in external hardware. Without this flag bn_mod_exp + * gets called when private key components are absent. + */ +#define RSA_FLAG_EXT_PKEY 0x0020 + +/* This flag in the RSA_METHOD enables the new rsa_sign, rsa_verify functions. + */ +#define RSA_FLAG_SIGN_VER 0x0040 + +#define RSA_FLAG_NO_BLINDING 0x0080 /* new with 0.9.6j and 0.9.7b; the built-in + * RSA implementation now uses blinding by + * default (ignoring RSA_FLAG_BLINDING), + * but other engines might not need it + */ +#define RSA_FLAG_NO_CONSTTIME 0x0100 /* new with 0.9.8f; the built-in RSA + * implementation now uses constant time + * operations by default in private key operations, + * e.g., constant time modular exponentiation, + * modular inverse without leaking branches, + * division without leaking branches. This + * flag disables these constant time + * operations and results in faster RSA + * private key operations. + */ +#ifndef OPENSSL_NO_DEPRECATED +#define RSA_FLAG_NO_EXP_CONSTTIME RSA_FLAG_NO_CONSTTIME /* deprecated name for the flag*/ + /* new with 0.9.7h; the built-in RSA + * implementation now uses constant time + * modular exponentiation for secret exponents + * by default. This flag causes the + * faster variable sliding window method to + * be used for all exponents. + */ +#endif + + +#define RSA_PKCS1_PADDING 1 +#define RSA_SSLV23_PADDING 2 +#define RSA_NO_PADDING 3 +#define RSA_PKCS1_OAEP_PADDING 4 +#define RSA_X931_PADDING 5 + +#define RSA_PKCS1_PADDING_SIZE 11 + +#define RSA_set_app_data(s,arg) RSA_set_ex_data(s,0,arg) +#define RSA_get_app_data(s) RSA_get_ex_data(s,0) + +RSA * RSA_new(void); +RSA * RSA_new_method(ENGINE *engine); +int RSA_size(const RSA *); + +/* Deprecated version */ +#ifndef OPENSSL_NO_DEPRECATED +RSA * RSA_generate_key(int bits, unsigned long e,void + (*callback)(int,int,void *),void *cb_arg); +#endif /* !defined(OPENSSL_NO_DEPRECATED) */ + +/* New version */ +int RSA_generate_key_ex(RSA *rsa, int bits, BIGNUM *e, BN_GENCB *cb); + +int RSA_check_key(const RSA *); + /* next 4 return -1 on error */ +int RSA_public_encrypt(int flen, const unsigned char *from, + unsigned char *to, RSA *rsa,int padding); +int RSA_private_encrypt(int flen, const unsigned char *from, + unsigned char *to, RSA *rsa,int padding); +int RSA_public_decrypt(int flen, const unsigned char *from, + unsigned char *to, RSA *rsa,int padding); +int RSA_private_decrypt(int flen, const unsigned char *from, + unsigned char *to, RSA *rsa,int padding); +void RSA_free (RSA *r); +/* "up" the RSA object's reference count */ +int RSA_up_ref(RSA *r); + +int RSA_flags(const RSA *r); + +void RSA_set_default_method(const RSA_METHOD *meth); +const RSA_METHOD *RSA_get_default_method(void); +const RSA_METHOD *RSA_get_method(const RSA *rsa); +int RSA_set_method(RSA *rsa, const RSA_METHOD *meth); + +/* This function needs the memory locking malloc callbacks to be installed */ +int RSA_memory_lock(RSA *r); + +/* these are the actual SSLeay RSA functions */ +const RSA_METHOD *RSA_PKCS1_SSLeay(void); + +const RSA_METHOD *RSA_null_method(void); + +DECLARE_ASN1_ENCODE_FUNCTIONS_const(RSA, RSAPublicKey) +DECLARE_ASN1_ENCODE_FUNCTIONS_const(RSA, RSAPrivateKey) + +#ifndef OPENSSL_NO_FP_API +int RSA_print_fp(FILE *fp, const RSA *r,int offset); +#endif + +#ifndef OPENSSL_NO_BIO +int RSA_print(BIO *bp, const RSA *r,int offset); +#endif + +int i2d_RSA_NET(const RSA *a, unsigned char **pp, + int (*cb)(char *buf, int len, const char *prompt, int verify), + int sgckey); +RSA *d2i_RSA_NET(RSA **a, const unsigned char **pp, long length, + int (*cb)(char *buf, int len, const char *prompt, int verify), + int sgckey); + +int i2d_Netscape_RSA(const RSA *a, unsigned char **pp, + int (*cb)(char *buf, int len, const char *prompt, + int verify)); +RSA *d2i_Netscape_RSA(RSA **a, const unsigned char **pp, long length, + int (*cb)(char *buf, int len, const char *prompt, + int verify)); + +/* The following 2 functions sign and verify a X509_SIG ASN1 object + * inside PKCS#1 padded RSA encryption */ +int RSA_sign(int type, const unsigned char *m, unsigned int m_length, + unsigned char *sigret, unsigned int *siglen, RSA *rsa); +int RSA_verify(int type, const unsigned char *m, unsigned int m_length, + unsigned char *sigbuf, unsigned int siglen, RSA *rsa); + +/* The following 2 function sign and verify a ASN1_OCTET_STRING + * object inside PKCS#1 padded RSA encryption */ +int RSA_sign_ASN1_OCTET_STRING(int type, + const unsigned char *m, unsigned int m_length, + unsigned char *sigret, unsigned int *siglen, RSA *rsa); +int RSA_verify_ASN1_OCTET_STRING(int type, + const unsigned char *m, unsigned int m_length, + unsigned char *sigbuf, unsigned int siglen, RSA *rsa); + +int RSA_blinding_on(RSA *rsa, BN_CTX *ctx); +void RSA_blinding_off(RSA *rsa); +BN_BLINDING *RSA_setup_blinding(RSA *rsa, BN_CTX *ctx); + +int RSA_padding_add_PKCS1_type_1(unsigned char *to,int tlen, + const unsigned char *f,int fl); +int RSA_padding_check_PKCS1_type_1(unsigned char *to,int tlen, + const unsigned char *f,int fl,int rsa_len); +int RSA_padding_add_PKCS1_type_2(unsigned char *to,int tlen, + const unsigned char *f,int fl); +int RSA_padding_check_PKCS1_type_2(unsigned char *to,int tlen, + const unsigned char *f,int fl,int rsa_len); +int PKCS1_MGF1(unsigned char *mask, long len, + const unsigned char *seed, long seedlen, const EVP_MD *dgst); +int RSA_padding_add_PKCS1_OAEP(unsigned char *to,int tlen, + const unsigned char *f,int fl, + const unsigned char *p,int pl); +int RSA_padding_check_PKCS1_OAEP(unsigned char *to,int tlen, + const unsigned char *f,int fl,int rsa_len, + const unsigned char *p,int pl); +int RSA_padding_add_SSLv23(unsigned char *to,int tlen, + const unsigned char *f,int fl); +int RSA_padding_check_SSLv23(unsigned char *to,int tlen, + const unsigned char *f,int fl,int rsa_len); +int RSA_padding_add_none(unsigned char *to,int tlen, + const unsigned char *f,int fl); +int RSA_padding_check_none(unsigned char *to,int tlen, + const unsigned char *f,int fl,int rsa_len); +int RSA_padding_add_X931(unsigned char *to,int tlen, + const unsigned char *f,int fl); +int RSA_padding_check_X931(unsigned char *to,int tlen, + const unsigned char *f,int fl,int rsa_len); +int RSA_X931_hash_id(int nid); + +int RSA_verify_PKCS1_PSS(RSA *rsa, const unsigned char *mHash, + const EVP_MD *Hash, const unsigned char *EM, int sLen); +int RSA_padding_add_PKCS1_PSS(RSA *rsa, unsigned char *EM, + const unsigned char *mHash, + const EVP_MD *Hash, int sLen); + +int RSA_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func, + CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func); +int RSA_set_ex_data(RSA *r,int idx,void *arg); +void *RSA_get_ex_data(const RSA *r, int idx); + +RSA *RSAPublicKey_dup(RSA *rsa); +RSA *RSAPrivateKey_dup(RSA *rsa); + +/* BEGIN ERROR CODES */ +/* The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ +void ERR_load_RSA_strings(void); + +/* Error codes for the RSA functions. */ + +/* Function codes. */ +#define RSA_F_MEMORY_LOCK 100 +#define RSA_F_RSA_BUILTIN_KEYGEN 129 +#define RSA_F_RSA_CHECK_KEY 123 +#define RSA_F_RSA_EAY_PRIVATE_DECRYPT 101 +#define RSA_F_RSA_EAY_PRIVATE_ENCRYPT 102 +#define RSA_F_RSA_EAY_PUBLIC_DECRYPT 103 +#define RSA_F_RSA_EAY_PUBLIC_ENCRYPT 104 +#define RSA_F_RSA_GENERATE_KEY 105 +#define RSA_F_RSA_MEMORY_LOCK 130 +#define RSA_F_RSA_NEW_METHOD 106 +#define RSA_F_RSA_NULL 124 +#define RSA_F_RSA_NULL_MOD_EXP 131 +#define RSA_F_RSA_NULL_PRIVATE_DECRYPT 132 +#define RSA_F_RSA_NULL_PRIVATE_ENCRYPT 133 +#define RSA_F_RSA_NULL_PUBLIC_DECRYPT 134 +#define RSA_F_RSA_NULL_PUBLIC_ENCRYPT 135 +#define RSA_F_RSA_PADDING_ADD_NONE 107 +#define RSA_F_RSA_PADDING_ADD_PKCS1_OAEP 121 +#define RSA_F_RSA_PADDING_ADD_PKCS1_PSS 125 +#define RSA_F_RSA_PADDING_ADD_PKCS1_TYPE_1 108 +#define RSA_F_RSA_PADDING_ADD_PKCS1_TYPE_2 109 +#define RSA_F_RSA_PADDING_ADD_SSLV23 110 +#define RSA_F_RSA_PADDING_ADD_X931 127 +#define RSA_F_RSA_PADDING_CHECK_NONE 111 +#define RSA_F_RSA_PADDING_CHECK_PKCS1_OAEP 122 +#define RSA_F_RSA_PADDING_CHECK_PKCS1_TYPE_1 112 +#define RSA_F_RSA_PADDING_CHECK_PKCS1_TYPE_2 113 +#define RSA_F_RSA_PADDING_CHECK_SSLV23 114 +#define RSA_F_RSA_PADDING_CHECK_X931 128 +#define RSA_F_RSA_PRINT 115 +#define RSA_F_RSA_PRINT_FP 116 +#define RSA_F_RSA_SETUP_BLINDING 136 +#define RSA_F_RSA_SIGN 117 +#define RSA_F_RSA_SIGN_ASN1_OCTET_STRING 118 +#define RSA_F_RSA_VERIFY 119 +#define RSA_F_RSA_VERIFY_ASN1_OCTET_STRING 120 +#define RSA_F_RSA_VERIFY_PKCS1_PSS 126 + +/* Reason codes. */ +#define RSA_R_ALGORITHM_MISMATCH 100 +#define RSA_R_BAD_E_VALUE 101 +#define RSA_R_BAD_FIXED_HEADER_DECRYPT 102 +#define RSA_R_BAD_PAD_BYTE_COUNT 103 +#define RSA_R_BAD_SIGNATURE 104 +#define RSA_R_BLOCK_TYPE_IS_NOT_01 106 +#define RSA_R_BLOCK_TYPE_IS_NOT_02 107 +#define RSA_R_DATA_GREATER_THAN_MOD_LEN 108 +#define RSA_R_DATA_TOO_LARGE 109 +#define RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE 110 +#define RSA_R_DATA_TOO_LARGE_FOR_MODULUS 132 +#define RSA_R_DATA_TOO_SMALL 111 +#define RSA_R_DATA_TOO_SMALL_FOR_KEY_SIZE 122 +#define RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY 112 +#define RSA_R_DMP1_NOT_CONGRUENT_TO_D 124 +#define RSA_R_DMQ1_NOT_CONGRUENT_TO_D 125 +#define RSA_R_D_E_NOT_CONGRUENT_TO_1 123 +#define RSA_R_FIRST_OCTET_INVALID 133 +#define RSA_R_INVALID_HEADER 137 +#define RSA_R_INVALID_MESSAGE_LENGTH 131 +#define RSA_R_INVALID_PADDING 138 +#define RSA_R_INVALID_TRAILER 139 +#define RSA_R_IQMP_NOT_INVERSE_OF_Q 126 +#define RSA_R_KEY_SIZE_TOO_SMALL 120 +#define RSA_R_LAST_OCTET_INVALID 134 +#define RSA_R_MODULUS_TOO_LARGE 105 +#define RSA_R_NO_PUBLIC_EXPONENT 140 +#define RSA_R_NULL_BEFORE_BLOCK_MISSING 113 +#define RSA_R_N_DOES_NOT_EQUAL_P_Q 127 +#define RSA_R_OAEP_DECODING_ERROR 121 +#define RSA_R_PADDING_CHECK_FAILED 114 +#define RSA_R_P_NOT_PRIME 128 +#define RSA_R_Q_NOT_PRIME 129 +#define RSA_R_RSA_OPERATIONS_NOT_SUPPORTED 130 +#define RSA_R_SLEN_CHECK_FAILED 136 +#define RSA_R_SLEN_RECOVERY_FAILED 135 +#define RSA_R_SSLV3_ROLLBACK_ATTACK 115 +#define RSA_R_THE_ASN1_OBJECT_IDENTIFIER_IS_NOT_KNOWN_FOR_THIS_MD 116 +#define RSA_R_UNKNOWN_ALGORITHM_TYPE 117 +#define RSA_R_UNKNOWN_PADDING_TYPE 118 +#define RSA_R_WRONG_SIGNATURE_LENGTH 119 + +#ifdef __cplusplus +} +#endif +#endif diff --git a/lib_tls/include/openssl/safestack.h b/lib_tls/include/openssl/safestack.h new file mode 100644 index 000000000..78cc485e6 --- /dev/null +++ b/lib_tls/include/openssl/safestack.h @@ -0,0 +1,1986 @@ +/* ==================================================================== + * Copyright (c) 1999 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#ifndef HEADER_SAFESTACK_H +#define HEADER_SAFESTACK_H + +#include + +#ifdef DEBUG_SAFESTACK + +#ifndef CHECKED_PTR_OF +#define CHECKED_PTR_OF(type, p) \ + ((void*) (1 ? p : (type*)0)) +#endif + +#define CHECKED_SK_FREE_FUNC(type, p) \ + ((void (*)(void *)) ((1 ? p : (void (*)(type *))0))) + +#define CHECKED_SK_CMP_FUNC(type, p) \ + ((int (*)(const char * const *, const char * const *)) \ + ((1 ? p : (int (*)(const type * const *, const type * const *))0))) + +#define STACK_OF(type) struct stack_st_##type +#define PREDECLARE_STACK_OF(type) STACK_OF(type); + +#define DECLARE_STACK_OF(type) \ +STACK_OF(type) \ + { \ + STACK stack; \ + }; + +#define IMPLEMENT_STACK_OF(type) /* nada (obsolete in new safestack approach)*/ + +/* SKM_sk_... stack macros are internal to safestack.h: + * never use them directly, use sk__... instead */ +#define SKM_sk_new(type, cmp) \ + ((STACK_OF(type) *)sk_new(CHECKED_SK_CMP_FUNC(type, cmp))) +#define SKM_sk_new_null(type) \ + ((STACK_OF(type) *)sk_new_null()) +#define SKM_sk_free(type, st) \ + sk_free(CHECKED_PTR_OF(STACK_OF(type), st)) +#define SKM_sk_num(type, st) \ + sk_num(CHECKED_PTR_OF(STACK_OF(type), st)) +#define SKM_sk_value(type, st,i) \ + ((type *)sk_value(CHECKED_PTR_OF(STACK_OF(type), st), i)) +#define SKM_sk_set(type, st,i,val) \ + sk_set(CHECKED_PTR_OF(STACK_OF(type), st), i, CHECKED_PTR_OF(type, val)) +#define SKM_sk_zero(type, st) \ + sk_zero(CHECKED_PTR_OF(STACK_OF(type), st)) +#define SKM_sk_push(type, st,val) \ + sk_push(CHECKED_PTR_OF(STACK_OF(type), st), CHECKED_PTR_OF(type, val)) +#define SKM_sk_unshift(type, st,val) \ + sk_unshift(CHECKED_PTR_OF(STACK_OF(type), st), CHECKED_PTR_OF(type, val)) +#define SKM_sk_find(type, st,val) \ + sk_find(CHECKED_PTR_OF(STACK_OF(type), st), CHECKED_PTR_OF(type, val)) +#define SKM_sk_delete(type, st,i) \ + (type *)sk_delete(CHECKED_PTR_OF(STACK_OF(type), st), i) +#define SKM_sk_delete_ptr(type, st,ptr) \ + (type *)sk_delete_ptr(CHECKED_PTR_OF(STACK_OF(type), st), CHECKED_PTR_OF(type, ptr)) +#define SKM_sk_insert(type, st,val,i) \ + sk_insert(CHECKED_PTR_OF(STACK_OF(type), st), CHECKED_PTR_OF(type, val), i) +#define SKM_sk_set_cmp_func(type, st,cmp) \ + ((int (*)(const type * const *,const type * const *)) \ + sk_set_cmp_func(CHECKED_PTR_OF(STACK_OF(type), st), CHECKED_SK_CMP_FUNC(type, cmp))) +#define SKM_sk_dup(type, st) \ + (STACK_OF(type) *)sk_dup(CHECKED_PTR_OF(STACK_OF(type), st)) +#define SKM_sk_pop_free(type, st,free_func) \ + sk_pop_free(CHECKED_PTR_OF(STACK_OF(type), st), CHECKED_SK_FREE_FUNC(type, free_func)) +#define SKM_sk_shift(type, st) \ + (type *)sk_shift(CHECKED_PTR_OF(STACK_OF(type), st)) +#define SKM_sk_pop(type, st) \ + (type *)sk_pop(CHECKED_PTR_OF(STACK_OF(type), st)) +#define SKM_sk_sort(type, st) \ + sk_sort(CHECKED_PTR_OF(STACK_OF(type), st)) +#define SKM_sk_is_sorted(type, st) \ + sk_is_sorted(CHECKED_PTR_OF(STACK_OF(type), st)) + +#define SKM_ASN1_SET_OF_d2i(type, st, pp, length, d2i_func, free_func, ex_tag, ex_class) \ + (STACK_OF(type) *)d2i_ASN1_SET(CHECKED_PTR_OF(STACK_OF(type), st), \ + pp, length, \ + CHECKED_D2I_OF(type, d2i_func), \ + CHECKED_SK_FREE_FUNC(type, free_func), \ + ex_tag, ex_class) + +#define SKM_ASN1_SET_OF_i2d(type, st, pp, i2d_func, ex_tag, ex_class, is_set) \ + i2d_ASN1_SET(CHECKED_PTR_OF(STACK_OF(type), st), pp, \ + CHECKED_I2D_OF(type, i2d_func), \ + ex_tag, ex_class, is_set) + +#define SKM_ASN1_seq_pack(type, st, i2d_func, buf, len) \ + ASN1_seq_pack(CHECKED_PTR_OF(STACK_OF(type), st), \ + CHECKED_I2D_OF(type, i2d_func), buf, len) + +#define SKM_ASN1_seq_unpack(type, buf, len, d2i_func, free_func) \ + (STACK_OF(type) *)ASN1_seq_unpack(buf, len, CHECKED_D2I_OF(type, d2i_func), CHECKED_SK_FREE_FUNC(type, free_func)) + +#define SKM_PKCS12_decrypt_d2i(type, algor, d2i_func, free_func, pass, passlen, oct, seq) \ + (STACK_OF(type) *)PKCS12_decrypt_d2i(algor, \ + CHECKED_D2I_OF(type, d2i_func), \ + CHECKED_SK_FREE_FUNC(type, free_func), \ + pass, passlen, oct, seq) + +#else + +#define STACK_OF(type) STACK +#define PREDECLARE_STACK_OF(type) /* nada */ +#define DECLARE_STACK_OF(type) /* nada */ +#define IMPLEMENT_STACK_OF(type) /* nada */ + +#define SKM_sk_new(type, cmp) \ + sk_new((int (*)(const char * const *, const char * const *))(cmp)) +#define SKM_sk_new_null(type) \ + sk_new_null() +#define SKM_sk_free(type, st) \ + sk_free(st) +#define SKM_sk_num(type, st) \ + sk_num(st) +#define SKM_sk_value(type, st,i) \ + ((type *)sk_value(st, i)) +#define SKM_sk_set(type, st,i,val) \ + ((type *)sk_set(st, i,(char *)val)) +#define SKM_sk_zero(type, st) \ + sk_zero(st) +#define SKM_sk_push(type, st,val) \ + sk_push(st, (char *)val) +#define SKM_sk_unshift(type, st,val) \ + sk_unshift(st, (char *)val) +#define SKM_sk_find(type, st,val) \ + sk_find(st, (char *)val) +#define SKM_sk_delete(type, st,i) \ + ((type *)sk_delete(st, i)) +#define SKM_sk_delete_ptr(type, st,ptr) \ + ((type *)sk_delete_ptr(st,(char *)ptr)) +#define SKM_sk_insert(type, st,val,i) \ + sk_insert(st, (char *)val, i) +#define SKM_sk_set_cmp_func(type, st,cmp) \ + ((int (*)(const type * const *,const type * const *)) \ + sk_set_cmp_func(st, (int (*)(const char * const *, const char * const *))(cmp))) +#define SKM_sk_dup(type, st) \ + sk_dup(st) +#define SKM_sk_pop_free(type, st,free_func) \ + sk_pop_free(st, (void (*)(void *))free_func) +#define SKM_sk_shift(type, st) \ + ((type *)sk_shift(st)) +#define SKM_sk_pop(type, st) \ + ((type *)sk_pop(st)) +#define SKM_sk_sort(type, st) \ + sk_sort(st) +#define SKM_sk_is_sorted(type, st) \ + sk_is_sorted(st) + +#define SKM_ASN1_SET_OF_d2i(type, st, pp, length, d2i_func, free_func, ex_tag, ex_class) \ + d2i_ASN1_SET(st,pp,length, (void *(*)(void ** ,const unsigned char ** ,long))d2i_func, (void (*)(void *))free_func, ex_tag,ex_class) +#define SKM_ASN1_SET_OF_i2d(type, st, pp, i2d_func, ex_tag, ex_class, is_set) \ + i2d_ASN1_SET(st,pp,(int (*)(void *, unsigned char **))i2d_func,ex_tag,ex_class,is_set) + +#define SKM_ASN1_seq_pack(type, st, i2d_func, buf, len) \ + ASN1_seq_pack(st, (int (*)(void *, unsigned char **))i2d_func, buf, len) +#define SKM_ASN1_seq_unpack(type, buf, len, d2i_func, free_func) \ + ASN1_seq_unpack(buf,len,(void *(*)(void **,const unsigned char **,long))d2i_func, (void(*)(void *))free_func) + +#define SKM_PKCS12_decrypt_d2i(type, algor, d2i_func, free_func, pass, passlen, oct, seq) \ + ((STACK *)PKCS12_decrypt_d2i(algor,(char *(*)())d2i_func, (void(*)(void *))free_func,pass,passlen,oct,seq)) + +#endif + +/* This block of defines is updated by util/mkstack.pl, please do not touch! */ +#define sk_ACCESS_DESCRIPTION_new(st) SKM_sk_new(ACCESS_DESCRIPTION, (st)) +#define sk_ACCESS_DESCRIPTION_new_null() SKM_sk_new_null(ACCESS_DESCRIPTION) +#define sk_ACCESS_DESCRIPTION_free(st) SKM_sk_free(ACCESS_DESCRIPTION, (st)) +#define sk_ACCESS_DESCRIPTION_num(st) SKM_sk_num(ACCESS_DESCRIPTION, (st)) +#define sk_ACCESS_DESCRIPTION_value(st, i) SKM_sk_value(ACCESS_DESCRIPTION, (st), (i)) +#define sk_ACCESS_DESCRIPTION_set(st, i, val) SKM_sk_set(ACCESS_DESCRIPTION, (st), (i), (val)) +#define sk_ACCESS_DESCRIPTION_zero(st) SKM_sk_zero(ACCESS_DESCRIPTION, (st)) +#define sk_ACCESS_DESCRIPTION_push(st, val) SKM_sk_push(ACCESS_DESCRIPTION, (st), (val)) +#define sk_ACCESS_DESCRIPTION_unshift(st, val) SKM_sk_unshift(ACCESS_DESCRIPTION, (st), (val)) +#define sk_ACCESS_DESCRIPTION_find(st, val) SKM_sk_find(ACCESS_DESCRIPTION, (st), (val)) +#define sk_ACCESS_DESCRIPTION_find_ex(st, val) SKM_sk_find_ex(ACCESS_DESCRIPTION, (st), (val)) +#define sk_ACCESS_DESCRIPTION_delete(st, i) SKM_sk_delete(ACCESS_DESCRIPTION, (st), (i)) +#define sk_ACCESS_DESCRIPTION_delete_ptr(st, ptr) SKM_sk_delete_ptr(ACCESS_DESCRIPTION, (st), (ptr)) +#define sk_ACCESS_DESCRIPTION_insert(st, val, i) SKM_sk_insert(ACCESS_DESCRIPTION, (st), (val), (i)) +#define sk_ACCESS_DESCRIPTION_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(ACCESS_DESCRIPTION, (st), (cmp)) +#define sk_ACCESS_DESCRIPTION_dup(st) SKM_sk_dup(ACCESS_DESCRIPTION, st) +#define sk_ACCESS_DESCRIPTION_pop_free(st, free_func) SKM_sk_pop_free(ACCESS_DESCRIPTION, (st), (free_func)) +#define sk_ACCESS_DESCRIPTION_shift(st) SKM_sk_shift(ACCESS_DESCRIPTION, (st)) +#define sk_ACCESS_DESCRIPTION_pop(st) SKM_sk_pop(ACCESS_DESCRIPTION, (st)) +#define sk_ACCESS_DESCRIPTION_sort(st) SKM_sk_sort(ACCESS_DESCRIPTION, (st)) +#define sk_ACCESS_DESCRIPTION_is_sorted(st) SKM_sk_is_sorted(ACCESS_DESCRIPTION, (st)) + +#define sk_ASIdOrRange_new(st) SKM_sk_new(ASIdOrRange, (st)) +#define sk_ASIdOrRange_new_null() SKM_sk_new_null(ASIdOrRange) +#define sk_ASIdOrRange_free(st) SKM_sk_free(ASIdOrRange, (st)) +#define sk_ASIdOrRange_num(st) SKM_sk_num(ASIdOrRange, (st)) +#define sk_ASIdOrRange_value(st, i) SKM_sk_value(ASIdOrRange, (st), (i)) +#define sk_ASIdOrRange_set(st, i, val) SKM_sk_set(ASIdOrRange, (st), (i), (val)) +#define sk_ASIdOrRange_zero(st) SKM_sk_zero(ASIdOrRange, (st)) +#define sk_ASIdOrRange_push(st, val) SKM_sk_push(ASIdOrRange, (st), (val)) +#define sk_ASIdOrRange_unshift(st, val) SKM_sk_unshift(ASIdOrRange, (st), (val)) +#define sk_ASIdOrRange_find(st, val) SKM_sk_find(ASIdOrRange, (st), (val)) +#define sk_ASIdOrRange_find_ex(st, val) SKM_sk_find_ex(ASIdOrRange, (st), (val)) +#define sk_ASIdOrRange_delete(st, i) SKM_sk_delete(ASIdOrRange, (st), (i)) +#define sk_ASIdOrRange_delete_ptr(st, ptr) SKM_sk_delete_ptr(ASIdOrRange, (st), (ptr)) +#define sk_ASIdOrRange_insert(st, val, i) SKM_sk_insert(ASIdOrRange, (st), (val), (i)) +#define sk_ASIdOrRange_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(ASIdOrRange, (st), (cmp)) +#define sk_ASIdOrRange_dup(st) SKM_sk_dup(ASIdOrRange, st) +#define sk_ASIdOrRange_pop_free(st, free_func) SKM_sk_pop_free(ASIdOrRange, (st), (free_func)) +#define sk_ASIdOrRange_shift(st) SKM_sk_shift(ASIdOrRange, (st)) +#define sk_ASIdOrRange_pop(st) SKM_sk_pop(ASIdOrRange, (st)) +#define sk_ASIdOrRange_sort(st) SKM_sk_sort(ASIdOrRange, (st)) +#define sk_ASIdOrRange_is_sorted(st) SKM_sk_is_sorted(ASIdOrRange, (st)) + +#define sk_ASN1_GENERALSTRING_new(st) SKM_sk_new(ASN1_GENERALSTRING, (st)) +#define sk_ASN1_GENERALSTRING_new_null() SKM_sk_new_null(ASN1_GENERALSTRING) +#define sk_ASN1_GENERALSTRING_free(st) SKM_sk_free(ASN1_GENERALSTRING, (st)) +#define sk_ASN1_GENERALSTRING_num(st) SKM_sk_num(ASN1_GENERALSTRING, (st)) +#define sk_ASN1_GENERALSTRING_value(st, i) SKM_sk_value(ASN1_GENERALSTRING, (st), (i)) +#define sk_ASN1_GENERALSTRING_set(st, i, val) SKM_sk_set(ASN1_GENERALSTRING, (st), (i), (val)) +#define sk_ASN1_GENERALSTRING_zero(st) SKM_sk_zero(ASN1_GENERALSTRING, (st)) +#define sk_ASN1_GENERALSTRING_push(st, val) SKM_sk_push(ASN1_GENERALSTRING, (st), (val)) +#define sk_ASN1_GENERALSTRING_unshift(st, val) SKM_sk_unshift(ASN1_GENERALSTRING, (st), (val)) +#define sk_ASN1_GENERALSTRING_find(st, val) SKM_sk_find(ASN1_GENERALSTRING, (st), (val)) +#define sk_ASN1_GENERALSTRING_find_ex(st, val) SKM_sk_find_ex(ASN1_GENERALSTRING, (st), (val)) +#define sk_ASN1_GENERALSTRING_delete(st, i) SKM_sk_delete(ASN1_GENERALSTRING, (st), (i)) +#define sk_ASN1_GENERALSTRING_delete_ptr(st, ptr) SKM_sk_delete_ptr(ASN1_GENERALSTRING, (st), (ptr)) +#define sk_ASN1_GENERALSTRING_insert(st, val, i) SKM_sk_insert(ASN1_GENERALSTRING, (st), (val), (i)) +#define sk_ASN1_GENERALSTRING_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(ASN1_GENERALSTRING, (st), (cmp)) +#define sk_ASN1_GENERALSTRING_dup(st) SKM_sk_dup(ASN1_GENERALSTRING, st) +#define sk_ASN1_GENERALSTRING_pop_free(st, free_func) SKM_sk_pop_free(ASN1_GENERALSTRING, (st), (free_func)) +#define sk_ASN1_GENERALSTRING_shift(st) SKM_sk_shift(ASN1_GENERALSTRING, (st)) +#define sk_ASN1_GENERALSTRING_pop(st) SKM_sk_pop(ASN1_GENERALSTRING, (st)) +#define sk_ASN1_GENERALSTRING_sort(st) SKM_sk_sort(ASN1_GENERALSTRING, (st)) +#define sk_ASN1_GENERALSTRING_is_sorted(st) SKM_sk_is_sorted(ASN1_GENERALSTRING, (st)) + +#define sk_ASN1_INTEGER_new(st) SKM_sk_new(ASN1_INTEGER, (st)) +#define sk_ASN1_INTEGER_new_null() SKM_sk_new_null(ASN1_INTEGER) +#define sk_ASN1_INTEGER_free(st) SKM_sk_free(ASN1_INTEGER, (st)) +#define sk_ASN1_INTEGER_num(st) SKM_sk_num(ASN1_INTEGER, (st)) +#define sk_ASN1_INTEGER_value(st, i) SKM_sk_value(ASN1_INTEGER, (st), (i)) +#define sk_ASN1_INTEGER_set(st, i, val) SKM_sk_set(ASN1_INTEGER, (st), (i), (val)) +#define sk_ASN1_INTEGER_zero(st) SKM_sk_zero(ASN1_INTEGER, (st)) +#define sk_ASN1_INTEGER_push(st, val) SKM_sk_push(ASN1_INTEGER, (st), (val)) +#define sk_ASN1_INTEGER_unshift(st, val) SKM_sk_unshift(ASN1_INTEGER, (st), (val)) +#define sk_ASN1_INTEGER_find(st, val) SKM_sk_find(ASN1_INTEGER, (st), (val)) +#define sk_ASN1_INTEGER_find_ex(st, val) SKM_sk_find_ex(ASN1_INTEGER, (st), (val)) +#define sk_ASN1_INTEGER_delete(st, i) SKM_sk_delete(ASN1_INTEGER, (st), (i)) +#define sk_ASN1_INTEGER_delete_ptr(st, ptr) SKM_sk_delete_ptr(ASN1_INTEGER, (st), (ptr)) +#define sk_ASN1_INTEGER_insert(st, val, i) SKM_sk_insert(ASN1_INTEGER, (st), (val), (i)) +#define sk_ASN1_INTEGER_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(ASN1_INTEGER, (st), (cmp)) +#define sk_ASN1_INTEGER_dup(st) SKM_sk_dup(ASN1_INTEGER, st) +#define sk_ASN1_INTEGER_pop_free(st, free_func) SKM_sk_pop_free(ASN1_INTEGER, (st), (free_func)) +#define sk_ASN1_INTEGER_shift(st) SKM_sk_shift(ASN1_INTEGER, (st)) +#define sk_ASN1_INTEGER_pop(st) SKM_sk_pop(ASN1_INTEGER, (st)) +#define sk_ASN1_INTEGER_sort(st) SKM_sk_sort(ASN1_INTEGER, (st)) +#define sk_ASN1_INTEGER_is_sorted(st) SKM_sk_is_sorted(ASN1_INTEGER, (st)) + +#define sk_ASN1_OBJECT_new(st) SKM_sk_new(ASN1_OBJECT, (st)) +#define sk_ASN1_OBJECT_new_null() SKM_sk_new_null(ASN1_OBJECT) +#define sk_ASN1_OBJECT_free(st) SKM_sk_free(ASN1_OBJECT, (st)) +#define sk_ASN1_OBJECT_num(st) SKM_sk_num(ASN1_OBJECT, (st)) +#define sk_ASN1_OBJECT_value(st, i) SKM_sk_value(ASN1_OBJECT, (st), (i)) +#define sk_ASN1_OBJECT_set(st, i, val) SKM_sk_set(ASN1_OBJECT, (st), (i), (val)) +#define sk_ASN1_OBJECT_zero(st) SKM_sk_zero(ASN1_OBJECT, (st)) +#define sk_ASN1_OBJECT_push(st, val) SKM_sk_push(ASN1_OBJECT, (st), (val)) +#define sk_ASN1_OBJECT_unshift(st, val) SKM_sk_unshift(ASN1_OBJECT, (st), (val)) +#define sk_ASN1_OBJECT_find(st, val) SKM_sk_find(ASN1_OBJECT, (st), (val)) +#define sk_ASN1_OBJECT_find_ex(st, val) SKM_sk_find_ex(ASN1_OBJECT, (st), (val)) +#define sk_ASN1_OBJECT_delete(st, i) SKM_sk_delete(ASN1_OBJECT, (st), (i)) +#define sk_ASN1_OBJECT_delete_ptr(st, ptr) SKM_sk_delete_ptr(ASN1_OBJECT, (st), (ptr)) +#define sk_ASN1_OBJECT_insert(st, val, i) SKM_sk_insert(ASN1_OBJECT, (st), (val), (i)) +#define sk_ASN1_OBJECT_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(ASN1_OBJECT, (st), (cmp)) +#define sk_ASN1_OBJECT_dup(st) SKM_sk_dup(ASN1_OBJECT, st) +#define sk_ASN1_OBJECT_pop_free(st, free_func) SKM_sk_pop_free(ASN1_OBJECT, (st), (free_func)) +#define sk_ASN1_OBJECT_shift(st) SKM_sk_shift(ASN1_OBJECT, (st)) +#define sk_ASN1_OBJECT_pop(st) SKM_sk_pop(ASN1_OBJECT, (st)) +#define sk_ASN1_OBJECT_sort(st) SKM_sk_sort(ASN1_OBJECT, (st)) +#define sk_ASN1_OBJECT_is_sorted(st) SKM_sk_is_sorted(ASN1_OBJECT, (st)) + +#define sk_ASN1_STRING_TABLE_new(st) SKM_sk_new(ASN1_STRING_TABLE, (st)) +#define sk_ASN1_STRING_TABLE_new_null() SKM_sk_new_null(ASN1_STRING_TABLE) +#define sk_ASN1_STRING_TABLE_free(st) SKM_sk_free(ASN1_STRING_TABLE, (st)) +#define sk_ASN1_STRING_TABLE_num(st) SKM_sk_num(ASN1_STRING_TABLE, (st)) +#define sk_ASN1_STRING_TABLE_value(st, i) SKM_sk_value(ASN1_STRING_TABLE, (st), (i)) +#define sk_ASN1_STRING_TABLE_set(st, i, val) SKM_sk_set(ASN1_STRING_TABLE, (st), (i), (val)) +#define sk_ASN1_STRING_TABLE_zero(st) SKM_sk_zero(ASN1_STRING_TABLE, (st)) +#define sk_ASN1_STRING_TABLE_push(st, val) SKM_sk_push(ASN1_STRING_TABLE, (st), (val)) +#define sk_ASN1_STRING_TABLE_unshift(st, val) SKM_sk_unshift(ASN1_STRING_TABLE, (st), (val)) +#define sk_ASN1_STRING_TABLE_find(st, val) SKM_sk_find(ASN1_STRING_TABLE, (st), (val)) +#define sk_ASN1_STRING_TABLE_find_ex(st, val) SKM_sk_find_ex(ASN1_STRING_TABLE, (st), (val)) +#define sk_ASN1_STRING_TABLE_delete(st, i) SKM_sk_delete(ASN1_STRING_TABLE, (st), (i)) +#define sk_ASN1_STRING_TABLE_delete_ptr(st, ptr) SKM_sk_delete_ptr(ASN1_STRING_TABLE, (st), (ptr)) +#define sk_ASN1_STRING_TABLE_insert(st, val, i) SKM_sk_insert(ASN1_STRING_TABLE, (st), (val), (i)) +#define sk_ASN1_STRING_TABLE_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(ASN1_STRING_TABLE, (st), (cmp)) +#define sk_ASN1_STRING_TABLE_dup(st) SKM_sk_dup(ASN1_STRING_TABLE, st) +#define sk_ASN1_STRING_TABLE_pop_free(st, free_func) SKM_sk_pop_free(ASN1_STRING_TABLE, (st), (free_func)) +#define sk_ASN1_STRING_TABLE_shift(st) SKM_sk_shift(ASN1_STRING_TABLE, (st)) +#define sk_ASN1_STRING_TABLE_pop(st) SKM_sk_pop(ASN1_STRING_TABLE, (st)) +#define sk_ASN1_STRING_TABLE_sort(st) SKM_sk_sort(ASN1_STRING_TABLE, (st)) +#define sk_ASN1_STRING_TABLE_is_sorted(st) SKM_sk_is_sorted(ASN1_STRING_TABLE, (st)) + +#define sk_ASN1_TYPE_new(st) SKM_sk_new(ASN1_TYPE, (st)) +#define sk_ASN1_TYPE_new_null() SKM_sk_new_null(ASN1_TYPE) +#define sk_ASN1_TYPE_free(st) SKM_sk_free(ASN1_TYPE, (st)) +#define sk_ASN1_TYPE_num(st) SKM_sk_num(ASN1_TYPE, (st)) +#define sk_ASN1_TYPE_value(st, i) SKM_sk_value(ASN1_TYPE, (st), (i)) +#define sk_ASN1_TYPE_set(st, i, val) SKM_sk_set(ASN1_TYPE, (st), (i), (val)) +#define sk_ASN1_TYPE_zero(st) SKM_sk_zero(ASN1_TYPE, (st)) +#define sk_ASN1_TYPE_push(st, val) SKM_sk_push(ASN1_TYPE, (st), (val)) +#define sk_ASN1_TYPE_unshift(st, val) SKM_sk_unshift(ASN1_TYPE, (st), (val)) +#define sk_ASN1_TYPE_find(st, val) SKM_sk_find(ASN1_TYPE, (st), (val)) +#define sk_ASN1_TYPE_find_ex(st, val) SKM_sk_find_ex(ASN1_TYPE, (st), (val)) +#define sk_ASN1_TYPE_delete(st, i) SKM_sk_delete(ASN1_TYPE, (st), (i)) +#define sk_ASN1_TYPE_delete_ptr(st, ptr) SKM_sk_delete_ptr(ASN1_TYPE, (st), (ptr)) +#define sk_ASN1_TYPE_insert(st, val, i) SKM_sk_insert(ASN1_TYPE, (st), (val), (i)) +#define sk_ASN1_TYPE_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(ASN1_TYPE, (st), (cmp)) +#define sk_ASN1_TYPE_dup(st) SKM_sk_dup(ASN1_TYPE, st) +#define sk_ASN1_TYPE_pop_free(st, free_func) SKM_sk_pop_free(ASN1_TYPE, (st), (free_func)) +#define sk_ASN1_TYPE_shift(st) SKM_sk_shift(ASN1_TYPE, (st)) +#define sk_ASN1_TYPE_pop(st) SKM_sk_pop(ASN1_TYPE, (st)) +#define sk_ASN1_TYPE_sort(st) SKM_sk_sort(ASN1_TYPE, (st)) +#define sk_ASN1_TYPE_is_sorted(st) SKM_sk_is_sorted(ASN1_TYPE, (st)) + +#define sk_ASN1_VALUE_new(st) SKM_sk_new(ASN1_VALUE, (st)) +#define sk_ASN1_VALUE_new_null() SKM_sk_new_null(ASN1_VALUE) +#define sk_ASN1_VALUE_free(st) SKM_sk_free(ASN1_VALUE, (st)) +#define sk_ASN1_VALUE_num(st) SKM_sk_num(ASN1_VALUE, (st)) +#define sk_ASN1_VALUE_value(st, i) SKM_sk_value(ASN1_VALUE, (st), (i)) +#define sk_ASN1_VALUE_set(st, i, val) SKM_sk_set(ASN1_VALUE, (st), (i), (val)) +#define sk_ASN1_VALUE_zero(st) SKM_sk_zero(ASN1_VALUE, (st)) +#define sk_ASN1_VALUE_push(st, val) SKM_sk_push(ASN1_VALUE, (st), (val)) +#define sk_ASN1_VALUE_unshift(st, val) SKM_sk_unshift(ASN1_VALUE, (st), (val)) +#define sk_ASN1_VALUE_find(st, val) SKM_sk_find(ASN1_VALUE, (st), (val)) +#define sk_ASN1_VALUE_find_ex(st, val) SKM_sk_find_ex(ASN1_VALUE, (st), (val)) +#define sk_ASN1_VALUE_delete(st, i) SKM_sk_delete(ASN1_VALUE, (st), (i)) +#define sk_ASN1_VALUE_delete_ptr(st, ptr) SKM_sk_delete_ptr(ASN1_VALUE, (st), (ptr)) +#define sk_ASN1_VALUE_insert(st, val, i) SKM_sk_insert(ASN1_VALUE, (st), (val), (i)) +#define sk_ASN1_VALUE_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(ASN1_VALUE, (st), (cmp)) +#define sk_ASN1_VALUE_dup(st) SKM_sk_dup(ASN1_VALUE, st) +#define sk_ASN1_VALUE_pop_free(st, free_func) SKM_sk_pop_free(ASN1_VALUE, (st), (free_func)) +#define sk_ASN1_VALUE_shift(st) SKM_sk_shift(ASN1_VALUE, (st)) +#define sk_ASN1_VALUE_pop(st) SKM_sk_pop(ASN1_VALUE, (st)) +#define sk_ASN1_VALUE_sort(st) SKM_sk_sort(ASN1_VALUE, (st)) +#define sk_ASN1_VALUE_is_sorted(st) SKM_sk_is_sorted(ASN1_VALUE, (st)) + +#define sk_BIO_new(st) SKM_sk_new(BIO, (st)) +#define sk_BIO_new_null() SKM_sk_new_null(BIO) +#define sk_BIO_free(st) SKM_sk_free(BIO, (st)) +#define sk_BIO_num(st) SKM_sk_num(BIO, (st)) +#define sk_BIO_value(st, i) SKM_sk_value(BIO, (st), (i)) +#define sk_BIO_set(st, i, val) SKM_sk_set(BIO, (st), (i), (val)) +#define sk_BIO_zero(st) SKM_sk_zero(BIO, (st)) +#define sk_BIO_push(st, val) SKM_sk_push(BIO, (st), (val)) +#define sk_BIO_unshift(st, val) SKM_sk_unshift(BIO, (st), (val)) +#define sk_BIO_find(st, val) SKM_sk_find(BIO, (st), (val)) +#define sk_BIO_find_ex(st, val) SKM_sk_find_ex(BIO, (st), (val)) +#define sk_BIO_delete(st, i) SKM_sk_delete(BIO, (st), (i)) +#define sk_BIO_delete_ptr(st, ptr) SKM_sk_delete_ptr(BIO, (st), (ptr)) +#define sk_BIO_insert(st, val, i) SKM_sk_insert(BIO, (st), (val), (i)) +#define sk_BIO_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(BIO, (st), (cmp)) +#define sk_BIO_dup(st) SKM_sk_dup(BIO, st) +#define sk_BIO_pop_free(st, free_func) SKM_sk_pop_free(BIO, (st), (free_func)) +#define sk_BIO_shift(st) SKM_sk_shift(BIO, (st)) +#define sk_BIO_pop(st) SKM_sk_pop(BIO, (st)) +#define sk_BIO_sort(st) SKM_sk_sort(BIO, (st)) +#define sk_BIO_is_sorted(st) SKM_sk_is_sorted(BIO, (st)) + +#define sk_CMS_CertificateChoices_new(st) SKM_sk_new(CMS_CertificateChoices, (st)) +#define sk_CMS_CertificateChoices_new_null() SKM_sk_new_null(CMS_CertificateChoices) +#define sk_CMS_CertificateChoices_free(st) SKM_sk_free(CMS_CertificateChoices, (st)) +#define sk_CMS_CertificateChoices_num(st) SKM_sk_num(CMS_CertificateChoices, (st)) +#define sk_CMS_CertificateChoices_value(st, i) SKM_sk_value(CMS_CertificateChoices, (st), (i)) +#define sk_CMS_CertificateChoices_set(st, i, val) SKM_sk_set(CMS_CertificateChoices, (st), (i), (val)) +#define sk_CMS_CertificateChoices_zero(st) SKM_sk_zero(CMS_CertificateChoices, (st)) +#define sk_CMS_CertificateChoices_push(st, val) SKM_sk_push(CMS_CertificateChoices, (st), (val)) +#define sk_CMS_CertificateChoices_unshift(st, val) SKM_sk_unshift(CMS_CertificateChoices, (st), (val)) +#define sk_CMS_CertificateChoices_find(st, val) SKM_sk_find(CMS_CertificateChoices, (st), (val)) +#define sk_CMS_CertificateChoices_find_ex(st, val) SKM_sk_find_ex(CMS_CertificateChoices, (st), (val)) +#define sk_CMS_CertificateChoices_delete(st, i) SKM_sk_delete(CMS_CertificateChoices, (st), (i)) +#define sk_CMS_CertificateChoices_delete_ptr(st, ptr) SKM_sk_delete_ptr(CMS_CertificateChoices, (st), (ptr)) +#define sk_CMS_CertificateChoices_insert(st, val, i) SKM_sk_insert(CMS_CertificateChoices, (st), (val), (i)) +#define sk_CMS_CertificateChoices_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(CMS_CertificateChoices, (st), (cmp)) +#define sk_CMS_CertificateChoices_dup(st) SKM_sk_dup(CMS_CertificateChoices, st) +#define sk_CMS_CertificateChoices_pop_free(st, free_func) SKM_sk_pop_free(CMS_CertificateChoices, (st), (free_func)) +#define sk_CMS_CertificateChoices_shift(st) SKM_sk_shift(CMS_CertificateChoices, (st)) +#define sk_CMS_CertificateChoices_pop(st) SKM_sk_pop(CMS_CertificateChoices, (st)) +#define sk_CMS_CertificateChoices_sort(st) SKM_sk_sort(CMS_CertificateChoices, (st)) +#define sk_CMS_CertificateChoices_is_sorted(st) SKM_sk_is_sorted(CMS_CertificateChoices, (st)) + +#define sk_CMS_RecipientInfo_new(st) SKM_sk_new(CMS_RecipientInfo, (st)) +#define sk_CMS_RecipientInfo_new_null() SKM_sk_new_null(CMS_RecipientInfo) +#define sk_CMS_RecipientInfo_free(st) SKM_sk_free(CMS_RecipientInfo, (st)) +#define sk_CMS_RecipientInfo_num(st) SKM_sk_num(CMS_RecipientInfo, (st)) +#define sk_CMS_RecipientInfo_value(st, i) SKM_sk_value(CMS_RecipientInfo, (st), (i)) +#define sk_CMS_RecipientInfo_set(st, i, val) SKM_sk_set(CMS_RecipientInfo, (st), (i), (val)) +#define sk_CMS_RecipientInfo_zero(st) SKM_sk_zero(CMS_RecipientInfo, (st)) +#define sk_CMS_RecipientInfo_push(st, val) SKM_sk_push(CMS_RecipientInfo, (st), (val)) +#define sk_CMS_RecipientInfo_unshift(st, val) SKM_sk_unshift(CMS_RecipientInfo, (st), (val)) +#define sk_CMS_RecipientInfo_find(st, val) SKM_sk_find(CMS_RecipientInfo, (st), (val)) +#define sk_CMS_RecipientInfo_find_ex(st, val) SKM_sk_find_ex(CMS_RecipientInfo, (st), (val)) +#define sk_CMS_RecipientInfo_delete(st, i) SKM_sk_delete(CMS_RecipientInfo, (st), (i)) +#define sk_CMS_RecipientInfo_delete_ptr(st, ptr) SKM_sk_delete_ptr(CMS_RecipientInfo, (st), (ptr)) +#define sk_CMS_RecipientInfo_insert(st, val, i) SKM_sk_insert(CMS_RecipientInfo, (st), (val), (i)) +#define sk_CMS_RecipientInfo_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(CMS_RecipientInfo, (st), (cmp)) +#define sk_CMS_RecipientInfo_dup(st) SKM_sk_dup(CMS_RecipientInfo, st) +#define sk_CMS_RecipientInfo_pop_free(st, free_func) SKM_sk_pop_free(CMS_RecipientInfo, (st), (free_func)) +#define sk_CMS_RecipientInfo_shift(st) SKM_sk_shift(CMS_RecipientInfo, (st)) +#define sk_CMS_RecipientInfo_pop(st) SKM_sk_pop(CMS_RecipientInfo, (st)) +#define sk_CMS_RecipientInfo_sort(st) SKM_sk_sort(CMS_RecipientInfo, (st)) +#define sk_CMS_RecipientInfo_is_sorted(st) SKM_sk_is_sorted(CMS_RecipientInfo, (st)) + +#define sk_CMS_RevocationInfoChoice_new(st) SKM_sk_new(CMS_RevocationInfoChoice, (st)) +#define sk_CMS_RevocationInfoChoice_new_null() SKM_sk_new_null(CMS_RevocationInfoChoice) +#define sk_CMS_RevocationInfoChoice_free(st) SKM_sk_free(CMS_RevocationInfoChoice, (st)) +#define sk_CMS_RevocationInfoChoice_num(st) SKM_sk_num(CMS_RevocationInfoChoice, (st)) +#define sk_CMS_RevocationInfoChoice_value(st, i) SKM_sk_value(CMS_RevocationInfoChoice, (st), (i)) +#define sk_CMS_RevocationInfoChoice_set(st, i, val) SKM_sk_set(CMS_RevocationInfoChoice, (st), (i), (val)) +#define sk_CMS_RevocationInfoChoice_zero(st) SKM_sk_zero(CMS_RevocationInfoChoice, (st)) +#define sk_CMS_RevocationInfoChoice_push(st, val) SKM_sk_push(CMS_RevocationInfoChoice, (st), (val)) +#define sk_CMS_RevocationInfoChoice_unshift(st, val) SKM_sk_unshift(CMS_RevocationInfoChoice, (st), (val)) +#define sk_CMS_RevocationInfoChoice_find(st, val) SKM_sk_find(CMS_RevocationInfoChoice, (st), (val)) +#define sk_CMS_RevocationInfoChoice_find_ex(st, val) SKM_sk_find_ex(CMS_RevocationInfoChoice, (st), (val)) +#define sk_CMS_RevocationInfoChoice_delete(st, i) SKM_sk_delete(CMS_RevocationInfoChoice, (st), (i)) +#define sk_CMS_RevocationInfoChoice_delete_ptr(st, ptr) SKM_sk_delete_ptr(CMS_RevocationInfoChoice, (st), (ptr)) +#define sk_CMS_RevocationInfoChoice_insert(st, val, i) SKM_sk_insert(CMS_RevocationInfoChoice, (st), (val), (i)) +#define sk_CMS_RevocationInfoChoice_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(CMS_RevocationInfoChoice, (st), (cmp)) +#define sk_CMS_RevocationInfoChoice_dup(st) SKM_sk_dup(CMS_RevocationInfoChoice, st) +#define sk_CMS_RevocationInfoChoice_pop_free(st, free_func) SKM_sk_pop_free(CMS_RevocationInfoChoice, (st), (free_func)) +#define sk_CMS_RevocationInfoChoice_shift(st) SKM_sk_shift(CMS_RevocationInfoChoice, (st)) +#define sk_CMS_RevocationInfoChoice_pop(st) SKM_sk_pop(CMS_RevocationInfoChoice, (st)) +#define sk_CMS_RevocationInfoChoice_sort(st) SKM_sk_sort(CMS_RevocationInfoChoice, (st)) +#define sk_CMS_RevocationInfoChoice_is_sorted(st) SKM_sk_is_sorted(CMS_RevocationInfoChoice, (st)) + +#define sk_CMS_SignerInfo_new(st) SKM_sk_new(CMS_SignerInfo, (st)) +#define sk_CMS_SignerInfo_new_null() SKM_sk_new_null(CMS_SignerInfo) +#define sk_CMS_SignerInfo_free(st) SKM_sk_free(CMS_SignerInfo, (st)) +#define sk_CMS_SignerInfo_num(st) SKM_sk_num(CMS_SignerInfo, (st)) +#define sk_CMS_SignerInfo_value(st, i) SKM_sk_value(CMS_SignerInfo, (st), (i)) +#define sk_CMS_SignerInfo_set(st, i, val) SKM_sk_set(CMS_SignerInfo, (st), (i), (val)) +#define sk_CMS_SignerInfo_zero(st) SKM_sk_zero(CMS_SignerInfo, (st)) +#define sk_CMS_SignerInfo_push(st, val) SKM_sk_push(CMS_SignerInfo, (st), (val)) +#define sk_CMS_SignerInfo_unshift(st, val) SKM_sk_unshift(CMS_SignerInfo, (st), (val)) +#define sk_CMS_SignerInfo_find(st, val) SKM_sk_find(CMS_SignerInfo, (st), (val)) +#define sk_CMS_SignerInfo_find_ex(st, val) SKM_sk_find_ex(CMS_SignerInfo, (st), (val)) +#define sk_CMS_SignerInfo_delete(st, i) SKM_sk_delete(CMS_SignerInfo, (st), (i)) +#define sk_CMS_SignerInfo_delete_ptr(st, ptr) SKM_sk_delete_ptr(CMS_SignerInfo, (st), (ptr)) +#define sk_CMS_SignerInfo_insert(st, val, i) SKM_sk_insert(CMS_SignerInfo, (st), (val), (i)) +#define sk_CMS_SignerInfo_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(CMS_SignerInfo, (st), (cmp)) +#define sk_CMS_SignerInfo_dup(st) SKM_sk_dup(CMS_SignerInfo, st) +#define sk_CMS_SignerInfo_pop_free(st, free_func) SKM_sk_pop_free(CMS_SignerInfo, (st), (free_func)) +#define sk_CMS_SignerInfo_shift(st) SKM_sk_shift(CMS_SignerInfo, (st)) +#define sk_CMS_SignerInfo_pop(st) SKM_sk_pop(CMS_SignerInfo, (st)) +#define sk_CMS_SignerInfo_sort(st) SKM_sk_sort(CMS_SignerInfo, (st)) +#define sk_CMS_SignerInfo_is_sorted(st) SKM_sk_is_sorted(CMS_SignerInfo, (st)) + +#define sk_CONF_IMODULE_new(st) SKM_sk_new(CONF_IMODULE, (st)) +#define sk_CONF_IMODULE_new_null() SKM_sk_new_null(CONF_IMODULE) +#define sk_CONF_IMODULE_free(st) SKM_sk_free(CONF_IMODULE, (st)) +#define sk_CONF_IMODULE_num(st) SKM_sk_num(CONF_IMODULE, (st)) +#define sk_CONF_IMODULE_value(st, i) SKM_sk_value(CONF_IMODULE, (st), (i)) +#define sk_CONF_IMODULE_set(st, i, val) SKM_sk_set(CONF_IMODULE, (st), (i), (val)) +#define sk_CONF_IMODULE_zero(st) SKM_sk_zero(CONF_IMODULE, (st)) +#define sk_CONF_IMODULE_push(st, val) SKM_sk_push(CONF_IMODULE, (st), (val)) +#define sk_CONF_IMODULE_unshift(st, val) SKM_sk_unshift(CONF_IMODULE, (st), (val)) +#define sk_CONF_IMODULE_find(st, val) SKM_sk_find(CONF_IMODULE, (st), (val)) +#define sk_CONF_IMODULE_find_ex(st, val) SKM_sk_find_ex(CONF_IMODULE, (st), (val)) +#define sk_CONF_IMODULE_delete(st, i) SKM_sk_delete(CONF_IMODULE, (st), (i)) +#define sk_CONF_IMODULE_delete_ptr(st, ptr) SKM_sk_delete_ptr(CONF_IMODULE, (st), (ptr)) +#define sk_CONF_IMODULE_insert(st, val, i) SKM_sk_insert(CONF_IMODULE, (st), (val), (i)) +#define sk_CONF_IMODULE_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(CONF_IMODULE, (st), (cmp)) +#define sk_CONF_IMODULE_dup(st) SKM_sk_dup(CONF_IMODULE, st) +#define sk_CONF_IMODULE_pop_free(st, free_func) SKM_sk_pop_free(CONF_IMODULE, (st), (free_func)) +#define sk_CONF_IMODULE_shift(st) SKM_sk_shift(CONF_IMODULE, (st)) +#define sk_CONF_IMODULE_pop(st) SKM_sk_pop(CONF_IMODULE, (st)) +#define sk_CONF_IMODULE_sort(st) SKM_sk_sort(CONF_IMODULE, (st)) +#define sk_CONF_IMODULE_is_sorted(st) SKM_sk_is_sorted(CONF_IMODULE, (st)) + +#define sk_CONF_MODULE_new(st) SKM_sk_new(CONF_MODULE, (st)) +#define sk_CONF_MODULE_new_null() SKM_sk_new_null(CONF_MODULE) +#define sk_CONF_MODULE_free(st) SKM_sk_free(CONF_MODULE, (st)) +#define sk_CONF_MODULE_num(st) SKM_sk_num(CONF_MODULE, (st)) +#define sk_CONF_MODULE_value(st, i) SKM_sk_value(CONF_MODULE, (st), (i)) +#define sk_CONF_MODULE_set(st, i, val) SKM_sk_set(CONF_MODULE, (st), (i), (val)) +#define sk_CONF_MODULE_zero(st) SKM_sk_zero(CONF_MODULE, (st)) +#define sk_CONF_MODULE_push(st, val) SKM_sk_push(CONF_MODULE, (st), (val)) +#define sk_CONF_MODULE_unshift(st, val) SKM_sk_unshift(CONF_MODULE, (st), (val)) +#define sk_CONF_MODULE_find(st, val) SKM_sk_find(CONF_MODULE, (st), (val)) +#define sk_CONF_MODULE_find_ex(st, val) SKM_sk_find_ex(CONF_MODULE, (st), (val)) +#define sk_CONF_MODULE_delete(st, i) SKM_sk_delete(CONF_MODULE, (st), (i)) +#define sk_CONF_MODULE_delete_ptr(st, ptr) SKM_sk_delete_ptr(CONF_MODULE, (st), (ptr)) +#define sk_CONF_MODULE_insert(st, val, i) SKM_sk_insert(CONF_MODULE, (st), (val), (i)) +#define sk_CONF_MODULE_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(CONF_MODULE, (st), (cmp)) +#define sk_CONF_MODULE_dup(st) SKM_sk_dup(CONF_MODULE, st) +#define sk_CONF_MODULE_pop_free(st, free_func) SKM_sk_pop_free(CONF_MODULE, (st), (free_func)) +#define sk_CONF_MODULE_shift(st) SKM_sk_shift(CONF_MODULE, (st)) +#define sk_CONF_MODULE_pop(st) SKM_sk_pop(CONF_MODULE, (st)) +#define sk_CONF_MODULE_sort(st) SKM_sk_sort(CONF_MODULE, (st)) +#define sk_CONF_MODULE_is_sorted(st) SKM_sk_is_sorted(CONF_MODULE, (st)) + +#define sk_CONF_VALUE_new(st) SKM_sk_new(CONF_VALUE, (st)) +#define sk_CONF_VALUE_new_null() SKM_sk_new_null(CONF_VALUE) +#define sk_CONF_VALUE_free(st) SKM_sk_free(CONF_VALUE, (st)) +#define sk_CONF_VALUE_num(st) SKM_sk_num(CONF_VALUE, (st)) +#define sk_CONF_VALUE_value(st, i) SKM_sk_value(CONF_VALUE, (st), (i)) +#define sk_CONF_VALUE_set(st, i, val) SKM_sk_set(CONF_VALUE, (st), (i), (val)) +#define sk_CONF_VALUE_zero(st) SKM_sk_zero(CONF_VALUE, (st)) +#define sk_CONF_VALUE_push(st, val) SKM_sk_push(CONF_VALUE, (st), (val)) +#define sk_CONF_VALUE_unshift(st, val) SKM_sk_unshift(CONF_VALUE, (st), (val)) +#define sk_CONF_VALUE_find(st, val) SKM_sk_find(CONF_VALUE, (st), (val)) +#define sk_CONF_VALUE_find_ex(st, val) SKM_sk_find_ex(CONF_VALUE, (st), (val)) +#define sk_CONF_VALUE_delete(st, i) SKM_sk_delete(CONF_VALUE, (st), (i)) +#define sk_CONF_VALUE_delete_ptr(st, ptr) SKM_sk_delete_ptr(CONF_VALUE, (st), (ptr)) +#define sk_CONF_VALUE_insert(st, val, i) SKM_sk_insert(CONF_VALUE, (st), (val), (i)) +#define sk_CONF_VALUE_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(CONF_VALUE, (st), (cmp)) +#define sk_CONF_VALUE_dup(st) SKM_sk_dup(CONF_VALUE, st) +#define sk_CONF_VALUE_pop_free(st, free_func) SKM_sk_pop_free(CONF_VALUE, (st), (free_func)) +#define sk_CONF_VALUE_shift(st) SKM_sk_shift(CONF_VALUE, (st)) +#define sk_CONF_VALUE_pop(st) SKM_sk_pop(CONF_VALUE, (st)) +#define sk_CONF_VALUE_sort(st) SKM_sk_sort(CONF_VALUE, (st)) +#define sk_CONF_VALUE_is_sorted(st) SKM_sk_is_sorted(CONF_VALUE, (st)) + +#define sk_CRYPTO_EX_DATA_FUNCS_new(st) SKM_sk_new(CRYPTO_EX_DATA_FUNCS, (st)) +#define sk_CRYPTO_EX_DATA_FUNCS_new_null() SKM_sk_new_null(CRYPTO_EX_DATA_FUNCS) +#define sk_CRYPTO_EX_DATA_FUNCS_free(st) SKM_sk_free(CRYPTO_EX_DATA_FUNCS, (st)) +#define sk_CRYPTO_EX_DATA_FUNCS_num(st) SKM_sk_num(CRYPTO_EX_DATA_FUNCS, (st)) +#define sk_CRYPTO_EX_DATA_FUNCS_value(st, i) SKM_sk_value(CRYPTO_EX_DATA_FUNCS, (st), (i)) +#define sk_CRYPTO_EX_DATA_FUNCS_set(st, i, val) SKM_sk_set(CRYPTO_EX_DATA_FUNCS, (st), (i), (val)) +#define sk_CRYPTO_EX_DATA_FUNCS_zero(st) SKM_sk_zero(CRYPTO_EX_DATA_FUNCS, (st)) +#define sk_CRYPTO_EX_DATA_FUNCS_push(st, val) SKM_sk_push(CRYPTO_EX_DATA_FUNCS, (st), (val)) +#define sk_CRYPTO_EX_DATA_FUNCS_unshift(st, val) SKM_sk_unshift(CRYPTO_EX_DATA_FUNCS, (st), (val)) +#define sk_CRYPTO_EX_DATA_FUNCS_find(st, val) SKM_sk_find(CRYPTO_EX_DATA_FUNCS, (st), (val)) +#define sk_CRYPTO_EX_DATA_FUNCS_find_ex(st, val) SKM_sk_find_ex(CRYPTO_EX_DATA_FUNCS, (st), (val)) +#define sk_CRYPTO_EX_DATA_FUNCS_delete(st, i) SKM_sk_delete(CRYPTO_EX_DATA_FUNCS, (st), (i)) +#define sk_CRYPTO_EX_DATA_FUNCS_delete_ptr(st, ptr) SKM_sk_delete_ptr(CRYPTO_EX_DATA_FUNCS, (st), (ptr)) +#define sk_CRYPTO_EX_DATA_FUNCS_insert(st, val, i) SKM_sk_insert(CRYPTO_EX_DATA_FUNCS, (st), (val), (i)) +#define sk_CRYPTO_EX_DATA_FUNCS_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(CRYPTO_EX_DATA_FUNCS, (st), (cmp)) +#define sk_CRYPTO_EX_DATA_FUNCS_dup(st) SKM_sk_dup(CRYPTO_EX_DATA_FUNCS, st) +#define sk_CRYPTO_EX_DATA_FUNCS_pop_free(st, free_func) SKM_sk_pop_free(CRYPTO_EX_DATA_FUNCS, (st), (free_func)) +#define sk_CRYPTO_EX_DATA_FUNCS_shift(st) SKM_sk_shift(CRYPTO_EX_DATA_FUNCS, (st)) +#define sk_CRYPTO_EX_DATA_FUNCS_pop(st) SKM_sk_pop(CRYPTO_EX_DATA_FUNCS, (st)) +#define sk_CRYPTO_EX_DATA_FUNCS_sort(st) SKM_sk_sort(CRYPTO_EX_DATA_FUNCS, (st)) +#define sk_CRYPTO_EX_DATA_FUNCS_is_sorted(st) SKM_sk_is_sorted(CRYPTO_EX_DATA_FUNCS, (st)) + +#define sk_CRYPTO_dynlock_new(st) SKM_sk_new(CRYPTO_dynlock, (st)) +#define sk_CRYPTO_dynlock_new_null() SKM_sk_new_null(CRYPTO_dynlock) +#define sk_CRYPTO_dynlock_free(st) SKM_sk_free(CRYPTO_dynlock, (st)) +#define sk_CRYPTO_dynlock_num(st) SKM_sk_num(CRYPTO_dynlock, (st)) +#define sk_CRYPTO_dynlock_value(st, i) SKM_sk_value(CRYPTO_dynlock, (st), (i)) +#define sk_CRYPTO_dynlock_set(st, i, val) SKM_sk_set(CRYPTO_dynlock, (st), (i), (val)) +#define sk_CRYPTO_dynlock_zero(st) SKM_sk_zero(CRYPTO_dynlock, (st)) +#define sk_CRYPTO_dynlock_push(st, val) SKM_sk_push(CRYPTO_dynlock, (st), (val)) +#define sk_CRYPTO_dynlock_unshift(st, val) SKM_sk_unshift(CRYPTO_dynlock, (st), (val)) +#define sk_CRYPTO_dynlock_find(st, val) SKM_sk_find(CRYPTO_dynlock, (st), (val)) +#define sk_CRYPTO_dynlock_find_ex(st, val) SKM_sk_find_ex(CRYPTO_dynlock, (st), (val)) +#define sk_CRYPTO_dynlock_delete(st, i) SKM_sk_delete(CRYPTO_dynlock, (st), (i)) +#define sk_CRYPTO_dynlock_delete_ptr(st, ptr) SKM_sk_delete_ptr(CRYPTO_dynlock, (st), (ptr)) +#define sk_CRYPTO_dynlock_insert(st, val, i) SKM_sk_insert(CRYPTO_dynlock, (st), (val), (i)) +#define sk_CRYPTO_dynlock_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(CRYPTO_dynlock, (st), (cmp)) +#define sk_CRYPTO_dynlock_dup(st) SKM_sk_dup(CRYPTO_dynlock, st) +#define sk_CRYPTO_dynlock_pop_free(st, free_func) SKM_sk_pop_free(CRYPTO_dynlock, (st), (free_func)) +#define sk_CRYPTO_dynlock_shift(st) SKM_sk_shift(CRYPTO_dynlock, (st)) +#define sk_CRYPTO_dynlock_pop(st) SKM_sk_pop(CRYPTO_dynlock, (st)) +#define sk_CRYPTO_dynlock_sort(st) SKM_sk_sort(CRYPTO_dynlock, (st)) +#define sk_CRYPTO_dynlock_is_sorted(st) SKM_sk_is_sorted(CRYPTO_dynlock, (st)) + +#define sk_DIST_POINT_new(st) SKM_sk_new(DIST_POINT, (st)) +#define sk_DIST_POINT_new_null() SKM_sk_new_null(DIST_POINT) +#define sk_DIST_POINT_free(st) SKM_sk_free(DIST_POINT, (st)) +#define sk_DIST_POINT_num(st) SKM_sk_num(DIST_POINT, (st)) +#define sk_DIST_POINT_value(st, i) SKM_sk_value(DIST_POINT, (st), (i)) +#define sk_DIST_POINT_set(st, i, val) SKM_sk_set(DIST_POINT, (st), (i), (val)) +#define sk_DIST_POINT_zero(st) SKM_sk_zero(DIST_POINT, (st)) +#define sk_DIST_POINT_push(st, val) SKM_sk_push(DIST_POINT, (st), (val)) +#define sk_DIST_POINT_unshift(st, val) SKM_sk_unshift(DIST_POINT, (st), (val)) +#define sk_DIST_POINT_find(st, val) SKM_sk_find(DIST_POINT, (st), (val)) +#define sk_DIST_POINT_find_ex(st, val) SKM_sk_find_ex(DIST_POINT, (st), (val)) +#define sk_DIST_POINT_delete(st, i) SKM_sk_delete(DIST_POINT, (st), (i)) +#define sk_DIST_POINT_delete_ptr(st, ptr) SKM_sk_delete_ptr(DIST_POINT, (st), (ptr)) +#define sk_DIST_POINT_insert(st, val, i) SKM_sk_insert(DIST_POINT, (st), (val), (i)) +#define sk_DIST_POINT_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(DIST_POINT, (st), (cmp)) +#define sk_DIST_POINT_dup(st) SKM_sk_dup(DIST_POINT, st) +#define sk_DIST_POINT_pop_free(st, free_func) SKM_sk_pop_free(DIST_POINT, (st), (free_func)) +#define sk_DIST_POINT_shift(st) SKM_sk_shift(DIST_POINT, (st)) +#define sk_DIST_POINT_pop(st) SKM_sk_pop(DIST_POINT, (st)) +#define sk_DIST_POINT_sort(st) SKM_sk_sort(DIST_POINT, (st)) +#define sk_DIST_POINT_is_sorted(st) SKM_sk_is_sorted(DIST_POINT, (st)) + +#define sk_ENGINE_new(st) SKM_sk_new(ENGINE, (st)) +#define sk_ENGINE_new_null() SKM_sk_new_null(ENGINE) +#define sk_ENGINE_free(st) SKM_sk_free(ENGINE, (st)) +#define sk_ENGINE_num(st) SKM_sk_num(ENGINE, (st)) +#define sk_ENGINE_value(st, i) SKM_sk_value(ENGINE, (st), (i)) +#define sk_ENGINE_set(st, i, val) SKM_sk_set(ENGINE, (st), (i), (val)) +#define sk_ENGINE_zero(st) SKM_sk_zero(ENGINE, (st)) +#define sk_ENGINE_push(st, val) SKM_sk_push(ENGINE, (st), (val)) +#define sk_ENGINE_unshift(st, val) SKM_sk_unshift(ENGINE, (st), (val)) +#define sk_ENGINE_find(st, val) SKM_sk_find(ENGINE, (st), (val)) +#define sk_ENGINE_find_ex(st, val) SKM_sk_find_ex(ENGINE, (st), (val)) +#define sk_ENGINE_delete(st, i) SKM_sk_delete(ENGINE, (st), (i)) +#define sk_ENGINE_delete_ptr(st, ptr) SKM_sk_delete_ptr(ENGINE, (st), (ptr)) +#define sk_ENGINE_insert(st, val, i) SKM_sk_insert(ENGINE, (st), (val), (i)) +#define sk_ENGINE_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(ENGINE, (st), (cmp)) +#define sk_ENGINE_dup(st) SKM_sk_dup(ENGINE, st) +#define sk_ENGINE_pop_free(st, free_func) SKM_sk_pop_free(ENGINE, (st), (free_func)) +#define sk_ENGINE_shift(st) SKM_sk_shift(ENGINE, (st)) +#define sk_ENGINE_pop(st) SKM_sk_pop(ENGINE, (st)) +#define sk_ENGINE_sort(st) SKM_sk_sort(ENGINE, (st)) +#define sk_ENGINE_is_sorted(st) SKM_sk_is_sorted(ENGINE, (st)) + +#define sk_ENGINE_CLEANUP_ITEM_new(st) SKM_sk_new(ENGINE_CLEANUP_ITEM, (st)) +#define sk_ENGINE_CLEANUP_ITEM_new_null() SKM_sk_new_null(ENGINE_CLEANUP_ITEM) +#define sk_ENGINE_CLEANUP_ITEM_free(st) SKM_sk_free(ENGINE_CLEANUP_ITEM, (st)) +#define sk_ENGINE_CLEANUP_ITEM_num(st) SKM_sk_num(ENGINE_CLEANUP_ITEM, (st)) +#define sk_ENGINE_CLEANUP_ITEM_value(st, i) SKM_sk_value(ENGINE_CLEANUP_ITEM, (st), (i)) +#define sk_ENGINE_CLEANUP_ITEM_set(st, i, val) SKM_sk_set(ENGINE_CLEANUP_ITEM, (st), (i), (val)) +#define sk_ENGINE_CLEANUP_ITEM_zero(st) SKM_sk_zero(ENGINE_CLEANUP_ITEM, (st)) +#define sk_ENGINE_CLEANUP_ITEM_push(st, val) SKM_sk_push(ENGINE_CLEANUP_ITEM, (st), (val)) +#define sk_ENGINE_CLEANUP_ITEM_unshift(st, val) SKM_sk_unshift(ENGINE_CLEANUP_ITEM, (st), (val)) +#define sk_ENGINE_CLEANUP_ITEM_find(st, val) SKM_sk_find(ENGINE_CLEANUP_ITEM, (st), (val)) +#define sk_ENGINE_CLEANUP_ITEM_find_ex(st, val) SKM_sk_find_ex(ENGINE_CLEANUP_ITEM, (st), (val)) +#define sk_ENGINE_CLEANUP_ITEM_delete(st, i) SKM_sk_delete(ENGINE_CLEANUP_ITEM, (st), (i)) +#define sk_ENGINE_CLEANUP_ITEM_delete_ptr(st, ptr) SKM_sk_delete_ptr(ENGINE_CLEANUP_ITEM, (st), (ptr)) +#define sk_ENGINE_CLEANUP_ITEM_insert(st, val, i) SKM_sk_insert(ENGINE_CLEANUP_ITEM, (st), (val), (i)) +#define sk_ENGINE_CLEANUP_ITEM_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(ENGINE_CLEANUP_ITEM, (st), (cmp)) +#define sk_ENGINE_CLEANUP_ITEM_dup(st) SKM_sk_dup(ENGINE_CLEANUP_ITEM, st) +#define sk_ENGINE_CLEANUP_ITEM_pop_free(st, free_func) SKM_sk_pop_free(ENGINE_CLEANUP_ITEM, (st), (free_func)) +#define sk_ENGINE_CLEANUP_ITEM_shift(st) SKM_sk_shift(ENGINE_CLEANUP_ITEM, (st)) +#define sk_ENGINE_CLEANUP_ITEM_pop(st) SKM_sk_pop(ENGINE_CLEANUP_ITEM, (st)) +#define sk_ENGINE_CLEANUP_ITEM_sort(st) SKM_sk_sort(ENGINE_CLEANUP_ITEM, (st)) +#define sk_ENGINE_CLEANUP_ITEM_is_sorted(st) SKM_sk_is_sorted(ENGINE_CLEANUP_ITEM, (st)) + +#define sk_GENERAL_NAME_new(st) SKM_sk_new(GENERAL_NAME, (st)) +#define sk_GENERAL_NAME_new_null() SKM_sk_new_null(GENERAL_NAME) +#define sk_GENERAL_NAME_free(st) SKM_sk_free(GENERAL_NAME, (st)) +#define sk_GENERAL_NAME_num(st) SKM_sk_num(GENERAL_NAME, (st)) +#define sk_GENERAL_NAME_value(st, i) SKM_sk_value(GENERAL_NAME, (st), (i)) +#define sk_GENERAL_NAME_set(st, i, val) SKM_sk_set(GENERAL_NAME, (st), (i), (val)) +#define sk_GENERAL_NAME_zero(st) SKM_sk_zero(GENERAL_NAME, (st)) +#define sk_GENERAL_NAME_push(st, val) SKM_sk_push(GENERAL_NAME, (st), (val)) +#define sk_GENERAL_NAME_unshift(st, val) SKM_sk_unshift(GENERAL_NAME, (st), (val)) +#define sk_GENERAL_NAME_find(st, val) SKM_sk_find(GENERAL_NAME, (st), (val)) +#define sk_GENERAL_NAME_find_ex(st, val) SKM_sk_find_ex(GENERAL_NAME, (st), (val)) +#define sk_GENERAL_NAME_delete(st, i) SKM_sk_delete(GENERAL_NAME, (st), (i)) +#define sk_GENERAL_NAME_delete_ptr(st, ptr) SKM_sk_delete_ptr(GENERAL_NAME, (st), (ptr)) +#define sk_GENERAL_NAME_insert(st, val, i) SKM_sk_insert(GENERAL_NAME, (st), (val), (i)) +#define sk_GENERAL_NAME_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(GENERAL_NAME, (st), (cmp)) +#define sk_GENERAL_NAME_dup(st) SKM_sk_dup(GENERAL_NAME, st) +#define sk_GENERAL_NAME_pop_free(st, free_func) SKM_sk_pop_free(GENERAL_NAME, (st), (free_func)) +#define sk_GENERAL_NAME_shift(st) SKM_sk_shift(GENERAL_NAME, (st)) +#define sk_GENERAL_NAME_pop(st) SKM_sk_pop(GENERAL_NAME, (st)) +#define sk_GENERAL_NAME_sort(st) SKM_sk_sort(GENERAL_NAME, (st)) +#define sk_GENERAL_NAME_is_sorted(st) SKM_sk_is_sorted(GENERAL_NAME, (st)) + +#define sk_GENERAL_NAMES_new(st) SKM_sk_new(GENERAL_NAMES, (st)) +#define sk_GENERAL_NAMES_new_null() SKM_sk_new_null(GENERAL_NAMES) +#define sk_GENERAL_NAMES_free(st) SKM_sk_free(GENERAL_NAMES, (st)) +#define sk_GENERAL_NAMES_num(st) SKM_sk_num(GENERAL_NAMES, (st)) +#define sk_GENERAL_NAMES_value(st, i) SKM_sk_value(GENERAL_NAMES, (st), (i)) +#define sk_GENERAL_NAMES_set(st, i, val) SKM_sk_set(GENERAL_NAMES, (st), (i), (val)) +#define sk_GENERAL_NAMES_zero(st) SKM_sk_zero(GENERAL_NAMES, (st)) +#define sk_GENERAL_NAMES_push(st, val) SKM_sk_push(GENERAL_NAMES, (st), (val)) +#define sk_GENERAL_NAMES_unshift(st, val) SKM_sk_unshift(GENERAL_NAMES, (st), (val)) +#define sk_GENERAL_NAMES_find(st, val) SKM_sk_find(GENERAL_NAMES, (st), (val)) +#define sk_GENERAL_NAMES_find_ex(st, val) SKM_sk_find_ex(GENERAL_NAMES, (st), (val)) +#define sk_GENERAL_NAMES_delete(st, i) SKM_sk_delete(GENERAL_NAMES, (st), (i)) +#define sk_GENERAL_NAMES_delete_ptr(st, ptr) SKM_sk_delete_ptr(GENERAL_NAMES, (st), (ptr)) +#define sk_GENERAL_NAMES_insert(st, val, i) SKM_sk_insert(GENERAL_NAMES, (st), (val), (i)) +#define sk_GENERAL_NAMES_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(GENERAL_NAMES, (st), (cmp)) +#define sk_GENERAL_NAMES_dup(st) SKM_sk_dup(GENERAL_NAMES, st) +#define sk_GENERAL_NAMES_pop_free(st, free_func) SKM_sk_pop_free(GENERAL_NAMES, (st), (free_func)) +#define sk_GENERAL_NAMES_shift(st) SKM_sk_shift(GENERAL_NAMES, (st)) +#define sk_GENERAL_NAMES_pop(st) SKM_sk_pop(GENERAL_NAMES, (st)) +#define sk_GENERAL_NAMES_sort(st) SKM_sk_sort(GENERAL_NAMES, (st)) +#define sk_GENERAL_NAMES_is_sorted(st) SKM_sk_is_sorted(GENERAL_NAMES, (st)) + +#define sk_GENERAL_SUBTREE_new(st) SKM_sk_new(GENERAL_SUBTREE, (st)) +#define sk_GENERAL_SUBTREE_new_null() SKM_sk_new_null(GENERAL_SUBTREE) +#define sk_GENERAL_SUBTREE_free(st) SKM_sk_free(GENERAL_SUBTREE, (st)) +#define sk_GENERAL_SUBTREE_num(st) SKM_sk_num(GENERAL_SUBTREE, (st)) +#define sk_GENERAL_SUBTREE_value(st, i) SKM_sk_value(GENERAL_SUBTREE, (st), (i)) +#define sk_GENERAL_SUBTREE_set(st, i, val) SKM_sk_set(GENERAL_SUBTREE, (st), (i), (val)) +#define sk_GENERAL_SUBTREE_zero(st) SKM_sk_zero(GENERAL_SUBTREE, (st)) +#define sk_GENERAL_SUBTREE_push(st, val) SKM_sk_push(GENERAL_SUBTREE, (st), (val)) +#define sk_GENERAL_SUBTREE_unshift(st, val) SKM_sk_unshift(GENERAL_SUBTREE, (st), (val)) +#define sk_GENERAL_SUBTREE_find(st, val) SKM_sk_find(GENERAL_SUBTREE, (st), (val)) +#define sk_GENERAL_SUBTREE_find_ex(st, val) SKM_sk_find_ex(GENERAL_SUBTREE, (st), (val)) +#define sk_GENERAL_SUBTREE_delete(st, i) SKM_sk_delete(GENERAL_SUBTREE, (st), (i)) +#define sk_GENERAL_SUBTREE_delete_ptr(st, ptr) SKM_sk_delete_ptr(GENERAL_SUBTREE, (st), (ptr)) +#define sk_GENERAL_SUBTREE_insert(st, val, i) SKM_sk_insert(GENERAL_SUBTREE, (st), (val), (i)) +#define sk_GENERAL_SUBTREE_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(GENERAL_SUBTREE, (st), (cmp)) +#define sk_GENERAL_SUBTREE_dup(st) SKM_sk_dup(GENERAL_SUBTREE, st) +#define sk_GENERAL_SUBTREE_pop_free(st, free_func) SKM_sk_pop_free(GENERAL_SUBTREE, (st), (free_func)) +#define sk_GENERAL_SUBTREE_shift(st) SKM_sk_shift(GENERAL_SUBTREE, (st)) +#define sk_GENERAL_SUBTREE_pop(st) SKM_sk_pop(GENERAL_SUBTREE, (st)) +#define sk_GENERAL_SUBTREE_sort(st) SKM_sk_sort(GENERAL_SUBTREE, (st)) +#define sk_GENERAL_SUBTREE_is_sorted(st) SKM_sk_is_sorted(GENERAL_SUBTREE, (st)) + +#define sk_IPAddressFamily_new(st) SKM_sk_new(IPAddressFamily, (st)) +#define sk_IPAddressFamily_new_null() SKM_sk_new_null(IPAddressFamily) +#define sk_IPAddressFamily_free(st) SKM_sk_free(IPAddressFamily, (st)) +#define sk_IPAddressFamily_num(st) SKM_sk_num(IPAddressFamily, (st)) +#define sk_IPAddressFamily_value(st, i) SKM_sk_value(IPAddressFamily, (st), (i)) +#define sk_IPAddressFamily_set(st, i, val) SKM_sk_set(IPAddressFamily, (st), (i), (val)) +#define sk_IPAddressFamily_zero(st) SKM_sk_zero(IPAddressFamily, (st)) +#define sk_IPAddressFamily_push(st, val) SKM_sk_push(IPAddressFamily, (st), (val)) +#define sk_IPAddressFamily_unshift(st, val) SKM_sk_unshift(IPAddressFamily, (st), (val)) +#define sk_IPAddressFamily_find(st, val) SKM_sk_find(IPAddressFamily, (st), (val)) +#define sk_IPAddressFamily_find_ex(st, val) SKM_sk_find_ex(IPAddressFamily, (st), (val)) +#define sk_IPAddressFamily_delete(st, i) SKM_sk_delete(IPAddressFamily, (st), (i)) +#define sk_IPAddressFamily_delete_ptr(st, ptr) SKM_sk_delete_ptr(IPAddressFamily, (st), (ptr)) +#define sk_IPAddressFamily_insert(st, val, i) SKM_sk_insert(IPAddressFamily, (st), (val), (i)) +#define sk_IPAddressFamily_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(IPAddressFamily, (st), (cmp)) +#define sk_IPAddressFamily_dup(st) SKM_sk_dup(IPAddressFamily, st) +#define sk_IPAddressFamily_pop_free(st, free_func) SKM_sk_pop_free(IPAddressFamily, (st), (free_func)) +#define sk_IPAddressFamily_shift(st) SKM_sk_shift(IPAddressFamily, (st)) +#define sk_IPAddressFamily_pop(st) SKM_sk_pop(IPAddressFamily, (st)) +#define sk_IPAddressFamily_sort(st) SKM_sk_sort(IPAddressFamily, (st)) +#define sk_IPAddressFamily_is_sorted(st) SKM_sk_is_sorted(IPAddressFamily, (st)) + +#define sk_IPAddressOrRange_new(st) SKM_sk_new(IPAddressOrRange, (st)) +#define sk_IPAddressOrRange_new_null() SKM_sk_new_null(IPAddressOrRange) +#define sk_IPAddressOrRange_free(st) SKM_sk_free(IPAddressOrRange, (st)) +#define sk_IPAddressOrRange_num(st) SKM_sk_num(IPAddressOrRange, (st)) +#define sk_IPAddressOrRange_value(st, i) SKM_sk_value(IPAddressOrRange, (st), (i)) +#define sk_IPAddressOrRange_set(st, i, val) SKM_sk_set(IPAddressOrRange, (st), (i), (val)) +#define sk_IPAddressOrRange_zero(st) SKM_sk_zero(IPAddressOrRange, (st)) +#define sk_IPAddressOrRange_push(st, val) SKM_sk_push(IPAddressOrRange, (st), (val)) +#define sk_IPAddressOrRange_unshift(st, val) SKM_sk_unshift(IPAddressOrRange, (st), (val)) +#define sk_IPAddressOrRange_find(st, val) SKM_sk_find(IPAddressOrRange, (st), (val)) +#define sk_IPAddressOrRange_find_ex(st, val) SKM_sk_find_ex(IPAddressOrRange, (st), (val)) +#define sk_IPAddressOrRange_delete(st, i) SKM_sk_delete(IPAddressOrRange, (st), (i)) +#define sk_IPAddressOrRange_delete_ptr(st, ptr) SKM_sk_delete_ptr(IPAddressOrRange, (st), (ptr)) +#define sk_IPAddressOrRange_insert(st, val, i) SKM_sk_insert(IPAddressOrRange, (st), (val), (i)) +#define sk_IPAddressOrRange_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(IPAddressOrRange, (st), (cmp)) +#define sk_IPAddressOrRange_dup(st) SKM_sk_dup(IPAddressOrRange, st) +#define sk_IPAddressOrRange_pop_free(st, free_func) SKM_sk_pop_free(IPAddressOrRange, (st), (free_func)) +#define sk_IPAddressOrRange_shift(st) SKM_sk_shift(IPAddressOrRange, (st)) +#define sk_IPAddressOrRange_pop(st) SKM_sk_pop(IPAddressOrRange, (st)) +#define sk_IPAddressOrRange_sort(st) SKM_sk_sort(IPAddressOrRange, (st)) +#define sk_IPAddressOrRange_is_sorted(st) SKM_sk_is_sorted(IPAddressOrRange, (st)) + +#define sk_KRB5_APREQBODY_new(st) SKM_sk_new(KRB5_APREQBODY, (st)) +#define sk_KRB5_APREQBODY_new_null() SKM_sk_new_null(KRB5_APREQBODY) +#define sk_KRB5_APREQBODY_free(st) SKM_sk_free(KRB5_APREQBODY, (st)) +#define sk_KRB5_APREQBODY_num(st) SKM_sk_num(KRB5_APREQBODY, (st)) +#define sk_KRB5_APREQBODY_value(st, i) SKM_sk_value(KRB5_APREQBODY, (st), (i)) +#define sk_KRB5_APREQBODY_set(st, i, val) SKM_sk_set(KRB5_APREQBODY, (st), (i), (val)) +#define sk_KRB5_APREQBODY_zero(st) SKM_sk_zero(KRB5_APREQBODY, (st)) +#define sk_KRB5_APREQBODY_push(st, val) SKM_sk_push(KRB5_APREQBODY, (st), (val)) +#define sk_KRB5_APREQBODY_unshift(st, val) SKM_sk_unshift(KRB5_APREQBODY, (st), (val)) +#define sk_KRB5_APREQBODY_find(st, val) SKM_sk_find(KRB5_APREQBODY, (st), (val)) +#define sk_KRB5_APREQBODY_find_ex(st, val) SKM_sk_find_ex(KRB5_APREQBODY, (st), (val)) +#define sk_KRB5_APREQBODY_delete(st, i) SKM_sk_delete(KRB5_APREQBODY, (st), (i)) +#define sk_KRB5_APREQBODY_delete_ptr(st, ptr) SKM_sk_delete_ptr(KRB5_APREQBODY, (st), (ptr)) +#define sk_KRB5_APREQBODY_insert(st, val, i) SKM_sk_insert(KRB5_APREQBODY, (st), (val), (i)) +#define sk_KRB5_APREQBODY_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(KRB5_APREQBODY, (st), (cmp)) +#define sk_KRB5_APREQBODY_dup(st) SKM_sk_dup(KRB5_APREQBODY, st) +#define sk_KRB5_APREQBODY_pop_free(st, free_func) SKM_sk_pop_free(KRB5_APREQBODY, (st), (free_func)) +#define sk_KRB5_APREQBODY_shift(st) SKM_sk_shift(KRB5_APREQBODY, (st)) +#define sk_KRB5_APREQBODY_pop(st) SKM_sk_pop(KRB5_APREQBODY, (st)) +#define sk_KRB5_APREQBODY_sort(st) SKM_sk_sort(KRB5_APREQBODY, (st)) +#define sk_KRB5_APREQBODY_is_sorted(st) SKM_sk_is_sorted(KRB5_APREQBODY, (st)) + +#define sk_KRB5_AUTHDATA_new(st) SKM_sk_new(KRB5_AUTHDATA, (st)) +#define sk_KRB5_AUTHDATA_new_null() SKM_sk_new_null(KRB5_AUTHDATA) +#define sk_KRB5_AUTHDATA_free(st) SKM_sk_free(KRB5_AUTHDATA, (st)) +#define sk_KRB5_AUTHDATA_num(st) SKM_sk_num(KRB5_AUTHDATA, (st)) +#define sk_KRB5_AUTHDATA_value(st, i) SKM_sk_value(KRB5_AUTHDATA, (st), (i)) +#define sk_KRB5_AUTHDATA_set(st, i, val) SKM_sk_set(KRB5_AUTHDATA, (st), (i), (val)) +#define sk_KRB5_AUTHDATA_zero(st) SKM_sk_zero(KRB5_AUTHDATA, (st)) +#define sk_KRB5_AUTHDATA_push(st, val) SKM_sk_push(KRB5_AUTHDATA, (st), (val)) +#define sk_KRB5_AUTHDATA_unshift(st, val) SKM_sk_unshift(KRB5_AUTHDATA, (st), (val)) +#define sk_KRB5_AUTHDATA_find(st, val) SKM_sk_find(KRB5_AUTHDATA, (st), (val)) +#define sk_KRB5_AUTHDATA_find_ex(st, val) SKM_sk_find_ex(KRB5_AUTHDATA, (st), (val)) +#define sk_KRB5_AUTHDATA_delete(st, i) SKM_sk_delete(KRB5_AUTHDATA, (st), (i)) +#define sk_KRB5_AUTHDATA_delete_ptr(st, ptr) SKM_sk_delete_ptr(KRB5_AUTHDATA, (st), (ptr)) +#define sk_KRB5_AUTHDATA_insert(st, val, i) SKM_sk_insert(KRB5_AUTHDATA, (st), (val), (i)) +#define sk_KRB5_AUTHDATA_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(KRB5_AUTHDATA, (st), (cmp)) +#define sk_KRB5_AUTHDATA_dup(st) SKM_sk_dup(KRB5_AUTHDATA, st) +#define sk_KRB5_AUTHDATA_pop_free(st, free_func) SKM_sk_pop_free(KRB5_AUTHDATA, (st), (free_func)) +#define sk_KRB5_AUTHDATA_shift(st) SKM_sk_shift(KRB5_AUTHDATA, (st)) +#define sk_KRB5_AUTHDATA_pop(st) SKM_sk_pop(KRB5_AUTHDATA, (st)) +#define sk_KRB5_AUTHDATA_sort(st) SKM_sk_sort(KRB5_AUTHDATA, (st)) +#define sk_KRB5_AUTHDATA_is_sorted(st) SKM_sk_is_sorted(KRB5_AUTHDATA, (st)) + +#define sk_KRB5_AUTHENTBODY_new(st) SKM_sk_new(KRB5_AUTHENTBODY, (st)) +#define sk_KRB5_AUTHENTBODY_new_null() SKM_sk_new_null(KRB5_AUTHENTBODY) +#define sk_KRB5_AUTHENTBODY_free(st) SKM_sk_free(KRB5_AUTHENTBODY, (st)) +#define sk_KRB5_AUTHENTBODY_num(st) SKM_sk_num(KRB5_AUTHENTBODY, (st)) +#define sk_KRB5_AUTHENTBODY_value(st, i) SKM_sk_value(KRB5_AUTHENTBODY, (st), (i)) +#define sk_KRB5_AUTHENTBODY_set(st, i, val) SKM_sk_set(KRB5_AUTHENTBODY, (st), (i), (val)) +#define sk_KRB5_AUTHENTBODY_zero(st) SKM_sk_zero(KRB5_AUTHENTBODY, (st)) +#define sk_KRB5_AUTHENTBODY_push(st, val) SKM_sk_push(KRB5_AUTHENTBODY, (st), (val)) +#define sk_KRB5_AUTHENTBODY_unshift(st, val) SKM_sk_unshift(KRB5_AUTHENTBODY, (st), (val)) +#define sk_KRB5_AUTHENTBODY_find(st, val) SKM_sk_find(KRB5_AUTHENTBODY, (st), (val)) +#define sk_KRB5_AUTHENTBODY_find_ex(st, val) SKM_sk_find_ex(KRB5_AUTHENTBODY, (st), (val)) +#define sk_KRB5_AUTHENTBODY_delete(st, i) SKM_sk_delete(KRB5_AUTHENTBODY, (st), (i)) +#define sk_KRB5_AUTHENTBODY_delete_ptr(st, ptr) SKM_sk_delete_ptr(KRB5_AUTHENTBODY, (st), (ptr)) +#define sk_KRB5_AUTHENTBODY_insert(st, val, i) SKM_sk_insert(KRB5_AUTHENTBODY, (st), (val), (i)) +#define sk_KRB5_AUTHENTBODY_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(KRB5_AUTHENTBODY, (st), (cmp)) +#define sk_KRB5_AUTHENTBODY_dup(st) SKM_sk_dup(KRB5_AUTHENTBODY, st) +#define sk_KRB5_AUTHENTBODY_pop_free(st, free_func) SKM_sk_pop_free(KRB5_AUTHENTBODY, (st), (free_func)) +#define sk_KRB5_AUTHENTBODY_shift(st) SKM_sk_shift(KRB5_AUTHENTBODY, (st)) +#define sk_KRB5_AUTHENTBODY_pop(st) SKM_sk_pop(KRB5_AUTHENTBODY, (st)) +#define sk_KRB5_AUTHENTBODY_sort(st) SKM_sk_sort(KRB5_AUTHENTBODY, (st)) +#define sk_KRB5_AUTHENTBODY_is_sorted(st) SKM_sk_is_sorted(KRB5_AUTHENTBODY, (st)) + +#define sk_KRB5_CHECKSUM_new(st) SKM_sk_new(KRB5_CHECKSUM, (st)) +#define sk_KRB5_CHECKSUM_new_null() SKM_sk_new_null(KRB5_CHECKSUM) +#define sk_KRB5_CHECKSUM_free(st) SKM_sk_free(KRB5_CHECKSUM, (st)) +#define sk_KRB5_CHECKSUM_num(st) SKM_sk_num(KRB5_CHECKSUM, (st)) +#define sk_KRB5_CHECKSUM_value(st, i) SKM_sk_value(KRB5_CHECKSUM, (st), (i)) +#define sk_KRB5_CHECKSUM_set(st, i, val) SKM_sk_set(KRB5_CHECKSUM, (st), (i), (val)) +#define sk_KRB5_CHECKSUM_zero(st) SKM_sk_zero(KRB5_CHECKSUM, (st)) +#define sk_KRB5_CHECKSUM_push(st, val) SKM_sk_push(KRB5_CHECKSUM, (st), (val)) +#define sk_KRB5_CHECKSUM_unshift(st, val) SKM_sk_unshift(KRB5_CHECKSUM, (st), (val)) +#define sk_KRB5_CHECKSUM_find(st, val) SKM_sk_find(KRB5_CHECKSUM, (st), (val)) +#define sk_KRB5_CHECKSUM_find_ex(st, val) SKM_sk_find_ex(KRB5_CHECKSUM, (st), (val)) +#define sk_KRB5_CHECKSUM_delete(st, i) SKM_sk_delete(KRB5_CHECKSUM, (st), (i)) +#define sk_KRB5_CHECKSUM_delete_ptr(st, ptr) SKM_sk_delete_ptr(KRB5_CHECKSUM, (st), (ptr)) +#define sk_KRB5_CHECKSUM_insert(st, val, i) SKM_sk_insert(KRB5_CHECKSUM, (st), (val), (i)) +#define sk_KRB5_CHECKSUM_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(KRB5_CHECKSUM, (st), (cmp)) +#define sk_KRB5_CHECKSUM_dup(st) SKM_sk_dup(KRB5_CHECKSUM, st) +#define sk_KRB5_CHECKSUM_pop_free(st, free_func) SKM_sk_pop_free(KRB5_CHECKSUM, (st), (free_func)) +#define sk_KRB5_CHECKSUM_shift(st) SKM_sk_shift(KRB5_CHECKSUM, (st)) +#define sk_KRB5_CHECKSUM_pop(st) SKM_sk_pop(KRB5_CHECKSUM, (st)) +#define sk_KRB5_CHECKSUM_sort(st) SKM_sk_sort(KRB5_CHECKSUM, (st)) +#define sk_KRB5_CHECKSUM_is_sorted(st) SKM_sk_is_sorted(KRB5_CHECKSUM, (st)) + +#define sk_KRB5_ENCDATA_new(st) SKM_sk_new(KRB5_ENCDATA, (st)) +#define sk_KRB5_ENCDATA_new_null() SKM_sk_new_null(KRB5_ENCDATA) +#define sk_KRB5_ENCDATA_free(st) SKM_sk_free(KRB5_ENCDATA, (st)) +#define sk_KRB5_ENCDATA_num(st) SKM_sk_num(KRB5_ENCDATA, (st)) +#define sk_KRB5_ENCDATA_value(st, i) SKM_sk_value(KRB5_ENCDATA, (st), (i)) +#define sk_KRB5_ENCDATA_set(st, i, val) SKM_sk_set(KRB5_ENCDATA, (st), (i), (val)) +#define sk_KRB5_ENCDATA_zero(st) SKM_sk_zero(KRB5_ENCDATA, (st)) +#define sk_KRB5_ENCDATA_push(st, val) SKM_sk_push(KRB5_ENCDATA, (st), (val)) +#define sk_KRB5_ENCDATA_unshift(st, val) SKM_sk_unshift(KRB5_ENCDATA, (st), (val)) +#define sk_KRB5_ENCDATA_find(st, val) SKM_sk_find(KRB5_ENCDATA, (st), (val)) +#define sk_KRB5_ENCDATA_find_ex(st, val) SKM_sk_find_ex(KRB5_ENCDATA, (st), (val)) +#define sk_KRB5_ENCDATA_delete(st, i) SKM_sk_delete(KRB5_ENCDATA, (st), (i)) +#define sk_KRB5_ENCDATA_delete_ptr(st, ptr) SKM_sk_delete_ptr(KRB5_ENCDATA, (st), (ptr)) +#define sk_KRB5_ENCDATA_insert(st, val, i) SKM_sk_insert(KRB5_ENCDATA, (st), (val), (i)) +#define sk_KRB5_ENCDATA_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(KRB5_ENCDATA, (st), (cmp)) +#define sk_KRB5_ENCDATA_dup(st) SKM_sk_dup(KRB5_ENCDATA, st) +#define sk_KRB5_ENCDATA_pop_free(st, free_func) SKM_sk_pop_free(KRB5_ENCDATA, (st), (free_func)) +#define sk_KRB5_ENCDATA_shift(st) SKM_sk_shift(KRB5_ENCDATA, (st)) +#define sk_KRB5_ENCDATA_pop(st) SKM_sk_pop(KRB5_ENCDATA, (st)) +#define sk_KRB5_ENCDATA_sort(st) SKM_sk_sort(KRB5_ENCDATA, (st)) +#define sk_KRB5_ENCDATA_is_sorted(st) SKM_sk_is_sorted(KRB5_ENCDATA, (st)) + +#define sk_KRB5_ENCKEY_new(st) SKM_sk_new(KRB5_ENCKEY, (st)) +#define sk_KRB5_ENCKEY_new_null() SKM_sk_new_null(KRB5_ENCKEY) +#define sk_KRB5_ENCKEY_free(st) SKM_sk_free(KRB5_ENCKEY, (st)) +#define sk_KRB5_ENCKEY_num(st) SKM_sk_num(KRB5_ENCKEY, (st)) +#define sk_KRB5_ENCKEY_value(st, i) SKM_sk_value(KRB5_ENCKEY, (st), (i)) +#define sk_KRB5_ENCKEY_set(st, i, val) SKM_sk_set(KRB5_ENCKEY, (st), (i), (val)) +#define sk_KRB5_ENCKEY_zero(st) SKM_sk_zero(KRB5_ENCKEY, (st)) +#define sk_KRB5_ENCKEY_push(st, val) SKM_sk_push(KRB5_ENCKEY, (st), (val)) +#define sk_KRB5_ENCKEY_unshift(st, val) SKM_sk_unshift(KRB5_ENCKEY, (st), (val)) +#define sk_KRB5_ENCKEY_find(st, val) SKM_sk_find(KRB5_ENCKEY, (st), (val)) +#define sk_KRB5_ENCKEY_find_ex(st, val) SKM_sk_find_ex(KRB5_ENCKEY, (st), (val)) +#define sk_KRB5_ENCKEY_delete(st, i) SKM_sk_delete(KRB5_ENCKEY, (st), (i)) +#define sk_KRB5_ENCKEY_delete_ptr(st, ptr) SKM_sk_delete_ptr(KRB5_ENCKEY, (st), (ptr)) +#define sk_KRB5_ENCKEY_insert(st, val, i) SKM_sk_insert(KRB5_ENCKEY, (st), (val), (i)) +#define sk_KRB5_ENCKEY_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(KRB5_ENCKEY, (st), (cmp)) +#define sk_KRB5_ENCKEY_dup(st) SKM_sk_dup(KRB5_ENCKEY, st) +#define sk_KRB5_ENCKEY_pop_free(st, free_func) SKM_sk_pop_free(KRB5_ENCKEY, (st), (free_func)) +#define sk_KRB5_ENCKEY_shift(st) SKM_sk_shift(KRB5_ENCKEY, (st)) +#define sk_KRB5_ENCKEY_pop(st) SKM_sk_pop(KRB5_ENCKEY, (st)) +#define sk_KRB5_ENCKEY_sort(st) SKM_sk_sort(KRB5_ENCKEY, (st)) +#define sk_KRB5_ENCKEY_is_sorted(st) SKM_sk_is_sorted(KRB5_ENCKEY, (st)) + +#define sk_KRB5_PRINCNAME_new(st) SKM_sk_new(KRB5_PRINCNAME, (st)) +#define sk_KRB5_PRINCNAME_new_null() SKM_sk_new_null(KRB5_PRINCNAME) +#define sk_KRB5_PRINCNAME_free(st) SKM_sk_free(KRB5_PRINCNAME, (st)) +#define sk_KRB5_PRINCNAME_num(st) SKM_sk_num(KRB5_PRINCNAME, (st)) +#define sk_KRB5_PRINCNAME_value(st, i) SKM_sk_value(KRB5_PRINCNAME, (st), (i)) +#define sk_KRB5_PRINCNAME_set(st, i, val) SKM_sk_set(KRB5_PRINCNAME, (st), (i), (val)) +#define sk_KRB5_PRINCNAME_zero(st) SKM_sk_zero(KRB5_PRINCNAME, (st)) +#define sk_KRB5_PRINCNAME_push(st, val) SKM_sk_push(KRB5_PRINCNAME, (st), (val)) +#define sk_KRB5_PRINCNAME_unshift(st, val) SKM_sk_unshift(KRB5_PRINCNAME, (st), (val)) +#define sk_KRB5_PRINCNAME_find(st, val) SKM_sk_find(KRB5_PRINCNAME, (st), (val)) +#define sk_KRB5_PRINCNAME_find_ex(st, val) SKM_sk_find_ex(KRB5_PRINCNAME, (st), (val)) +#define sk_KRB5_PRINCNAME_delete(st, i) SKM_sk_delete(KRB5_PRINCNAME, (st), (i)) +#define sk_KRB5_PRINCNAME_delete_ptr(st, ptr) SKM_sk_delete_ptr(KRB5_PRINCNAME, (st), (ptr)) +#define sk_KRB5_PRINCNAME_insert(st, val, i) SKM_sk_insert(KRB5_PRINCNAME, (st), (val), (i)) +#define sk_KRB5_PRINCNAME_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(KRB5_PRINCNAME, (st), (cmp)) +#define sk_KRB5_PRINCNAME_dup(st) SKM_sk_dup(KRB5_PRINCNAME, st) +#define sk_KRB5_PRINCNAME_pop_free(st, free_func) SKM_sk_pop_free(KRB5_PRINCNAME, (st), (free_func)) +#define sk_KRB5_PRINCNAME_shift(st) SKM_sk_shift(KRB5_PRINCNAME, (st)) +#define sk_KRB5_PRINCNAME_pop(st) SKM_sk_pop(KRB5_PRINCNAME, (st)) +#define sk_KRB5_PRINCNAME_sort(st) SKM_sk_sort(KRB5_PRINCNAME, (st)) +#define sk_KRB5_PRINCNAME_is_sorted(st) SKM_sk_is_sorted(KRB5_PRINCNAME, (st)) + +#define sk_KRB5_TKTBODY_new(st) SKM_sk_new(KRB5_TKTBODY, (st)) +#define sk_KRB5_TKTBODY_new_null() SKM_sk_new_null(KRB5_TKTBODY) +#define sk_KRB5_TKTBODY_free(st) SKM_sk_free(KRB5_TKTBODY, (st)) +#define sk_KRB5_TKTBODY_num(st) SKM_sk_num(KRB5_TKTBODY, (st)) +#define sk_KRB5_TKTBODY_value(st, i) SKM_sk_value(KRB5_TKTBODY, (st), (i)) +#define sk_KRB5_TKTBODY_set(st, i, val) SKM_sk_set(KRB5_TKTBODY, (st), (i), (val)) +#define sk_KRB5_TKTBODY_zero(st) SKM_sk_zero(KRB5_TKTBODY, (st)) +#define sk_KRB5_TKTBODY_push(st, val) SKM_sk_push(KRB5_TKTBODY, (st), (val)) +#define sk_KRB5_TKTBODY_unshift(st, val) SKM_sk_unshift(KRB5_TKTBODY, (st), (val)) +#define sk_KRB5_TKTBODY_find(st, val) SKM_sk_find(KRB5_TKTBODY, (st), (val)) +#define sk_KRB5_TKTBODY_find_ex(st, val) SKM_sk_find_ex(KRB5_TKTBODY, (st), (val)) +#define sk_KRB5_TKTBODY_delete(st, i) SKM_sk_delete(KRB5_TKTBODY, (st), (i)) +#define sk_KRB5_TKTBODY_delete_ptr(st, ptr) SKM_sk_delete_ptr(KRB5_TKTBODY, (st), (ptr)) +#define sk_KRB5_TKTBODY_insert(st, val, i) SKM_sk_insert(KRB5_TKTBODY, (st), (val), (i)) +#define sk_KRB5_TKTBODY_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(KRB5_TKTBODY, (st), (cmp)) +#define sk_KRB5_TKTBODY_dup(st) SKM_sk_dup(KRB5_TKTBODY, st) +#define sk_KRB5_TKTBODY_pop_free(st, free_func) SKM_sk_pop_free(KRB5_TKTBODY, (st), (free_func)) +#define sk_KRB5_TKTBODY_shift(st) SKM_sk_shift(KRB5_TKTBODY, (st)) +#define sk_KRB5_TKTBODY_pop(st) SKM_sk_pop(KRB5_TKTBODY, (st)) +#define sk_KRB5_TKTBODY_sort(st) SKM_sk_sort(KRB5_TKTBODY, (st)) +#define sk_KRB5_TKTBODY_is_sorted(st) SKM_sk_is_sorted(KRB5_TKTBODY, (st)) + +#define sk_MIME_HEADER_new(st) SKM_sk_new(MIME_HEADER, (st)) +#define sk_MIME_HEADER_new_null() SKM_sk_new_null(MIME_HEADER) +#define sk_MIME_HEADER_free(st) SKM_sk_free(MIME_HEADER, (st)) +#define sk_MIME_HEADER_num(st) SKM_sk_num(MIME_HEADER, (st)) +#define sk_MIME_HEADER_value(st, i) SKM_sk_value(MIME_HEADER, (st), (i)) +#define sk_MIME_HEADER_set(st, i, val) SKM_sk_set(MIME_HEADER, (st), (i), (val)) +#define sk_MIME_HEADER_zero(st) SKM_sk_zero(MIME_HEADER, (st)) +#define sk_MIME_HEADER_push(st, val) SKM_sk_push(MIME_HEADER, (st), (val)) +#define sk_MIME_HEADER_unshift(st, val) SKM_sk_unshift(MIME_HEADER, (st), (val)) +#define sk_MIME_HEADER_find(st, val) SKM_sk_find(MIME_HEADER, (st), (val)) +#define sk_MIME_HEADER_find_ex(st, val) SKM_sk_find_ex(MIME_HEADER, (st), (val)) +#define sk_MIME_HEADER_delete(st, i) SKM_sk_delete(MIME_HEADER, (st), (i)) +#define sk_MIME_HEADER_delete_ptr(st, ptr) SKM_sk_delete_ptr(MIME_HEADER, (st), (ptr)) +#define sk_MIME_HEADER_insert(st, val, i) SKM_sk_insert(MIME_HEADER, (st), (val), (i)) +#define sk_MIME_HEADER_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(MIME_HEADER, (st), (cmp)) +#define sk_MIME_HEADER_dup(st) SKM_sk_dup(MIME_HEADER, st) +#define sk_MIME_HEADER_pop_free(st, free_func) SKM_sk_pop_free(MIME_HEADER, (st), (free_func)) +#define sk_MIME_HEADER_shift(st) SKM_sk_shift(MIME_HEADER, (st)) +#define sk_MIME_HEADER_pop(st) SKM_sk_pop(MIME_HEADER, (st)) +#define sk_MIME_HEADER_sort(st) SKM_sk_sort(MIME_HEADER, (st)) +#define sk_MIME_HEADER_is_sorted(st) SKM_sk_is_sorted(MIME_HEADER, (st)) + +#define sk_MIME_PARAM_new(st) SKM_sk_new(MIME_PARAM, (st)) +#define sk_MIME_PARAM_new_null() SKM_sk_new_null(MIME_PARAM) +#define sk_MIME_PARAM_free(st) SKM_sk_free(MIME_PARAM, (st)) +#define sk_MIME_PARAM_num(st) SKM_sk_num(MIME_PARAM, (st)) +#define sk_MIME_PARAM_value(st, i) SKM_sk_value(MIME_PARAM, (st), (i)) +#define sk_MIME_PARAM_set(st, i, val) SKM_sk_set(MIME_PARAM, (st), (i), (val)) +#define sk_MIME_PARAM_zero(st) SKM_sk_zero(MIME_PARAM, (st)) +#define sk_MIME_PARAM_push(st, val) SKM_sk_push(MIME_PARAM, (st), (val)) +#define sk_MIME_PARAM_unshift(st, val) SKM_sk_unshift(MIME_PARAM, (st), (val)) +#define sk_MIME_PARAM_find(st, val) SKM_sk_find(MIME_PARAM, (st), (val)) +#define sk_MIME_PARAM_find_ex(st, val) SKM_sk_find_ex(MIME_PARAM, (st), (val)) +#define sk_MIME_PARAM_delete(st, i) SKM_sk_delete(MIME_PARAM, (st), (i)) +#define sk_MIME_PARAM_delete_ptr(st, ptr) SKM_sk_delete_ptr(MIME_PARAM, (st), (ptr)) +#define sk_MIME_PARAM_insert(st, val, i) SKM_sk_insert(MIME_PARAM, (st), (val), (i)) +#define sk_MIME_PARAM_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(MIME_PARAM, (st), (cmp)) +#define sk_MIME_PARAM_dup(st) SKM_sk_dup(MIME_PARAM, st) +#define sk_MIME_PARAM_pop_free(st, free_func) SKM_sk_pop_free(MIME_PARAM, (st), (free_func)) +#define sk_MIME_PARAM_shift(st) SKM_sk_shift(MIME_PARAM, (st)) +#define sk_MIME_PARAM_pop(st) SKM_sk_pop(MIME_PARAM, (st)) +#define sk_MIME_PARAM_sort(st) SKM_sk_sort(MIME_PARAM, (st)) +#define sk_MIME_PARAM_is_sorted(st) SKM_sk_is_sorted(MIME_PARAM, (st)) + +#define sk_NAME_FUNCS_new(st) SKM_sk_new(NAME_FUNCS, (st)) +#define sk_NAME_FUNCS_new_null() SKM_sk_new_null(NAME_FUNCS) +#define sk_NAME_FUNCS_free(st) SKM_sk_free(NAME_FUNCS, (st)) +#define sk_NAME_FUNCS_num(st) SKM_sk_num(NAME_FUNCS, (st)) +#define sk_NAME_FUNCS_value(st, i) SKM_sk_value(NAME_FUNCS, (st), (i)) +#define sk_NAME_FUNCS_set(st, i, val) SKM_sk_set(NAME_FUNCS, (st), (i), (val)) +#define sk_NAME_FUNCS_zero(st) SKM_sk_zero(NAME_FUNCS, (st)) +#define sk_NAME_FUNCS_push(st, val) SKM_sk_push(NAME_FUNCS, (st), (val)) +#define sk_NAME_FUNCS_unshift(st, val) SKM_sk_unshift(NAME_FUNCS, (st), (val)) +#define sk_NAME_FUNCS_find(st, val) SKM_sk_find(NAME_FUNCS, (st), (val)) +#define sk_NAME_FUNCS_find_ex(st, val) SKM_sk_find_ex(NAME_FUNCS, (st), (val)) +#define sk_NAME_FUNCS_delete(st, i) SKM_sk_delete(NAME_FUNCS, (st), (i)) +#define sk_NAME_FUNCS_delete_ptr(st, ptr) SKM_sk_delete_ptr(NAME_FUNCS, (st), (ptr)) +#define sk_NAME_FUNCS_insert(st, val, i) SKM_sk_insert(NAME_FUNCS, (st), (val), (i)) +#define sk_NAME_FUNCS_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(NAME_FUNCS, (st), (cmp)) +#define sk_NAME_FUNCS_dup(st) SKM_sk_dup(NAME_FUNCS, st) +#define sk_NAME_FUNCS_pop_free(st, free_func) SKM_sk_pop_free(NAME_FUNCS, (st), (free_func)) +#define sk_NAME_FUNCS_shift(st) SKM_sk_shift(NAME_FUNCS, (st)) +#define sk_NAME_FUNCS_pop(st) SKM_sk_pop(NAME_FUNCS, (st)) +#define sk_NAME_FUNCS_sort(st) SKM_sk_sort(NAME_FUNCS, (st)) +#define sk_NAME_FUNCS_is_sorted(st) SKM_sk_is_sorted(NAME_FUNCS, (st)) + +#define sk_OCSP_CERTID_new(st) SKM_sk_new(OCSP_CERTID, (st)) +#define sk_OCSP_CERTID_new_null() SKM_sk_new_null(OCSP_CERTID) +#define sk_OCSP_CERTID_free(st) SKM_sk_free(OCSP_CERTID, (st)) +#define sk_OCSP_CERTID_num(st) SKM_sk_num(OCSP_CERTID, (st)) +#define sk_OCSP_CERTID_value(st, i) SKM_sk_value(OCSP_CERTID, (st), (i)) +#define sk_OCSP_CERTID_set(st, i, val) SKM_sk_set(OCSP_CERTID, (st), (i), (val)) +#define sk_OCSP_CERTID_zero(st) SKM_sk_zero(OCSP_CERTID, (st)) +#define sk_OCSP_CERTID_push(st, val) SKM_sk_push(OCSP_CERTID, (st), (val)) +#define sk_OCSP_CERTID_unshift(st, val) SKM_sk_unshift(OCSP_CERTID, (st), (val)) +#define sk_OCSP_CERTID_find(st, val) SKM_sk_find(OCSP_CERTID, (st), (val)) +#define sk_OCSP_CERTID_find_ex(st, val) SKM_sk_find_ex(OCSP_CERTID, (st), (val)) +#define sk_OCSP_CERTID_delete(st, i) SKM_sk_delete(OCSP_CERTID, (st), (i)) +#define sk_OCSP_CERTID_delete_ptr(st, ptr) SKM_sk_delete_ptr(OCSP_CERTID, (st), (ptr)) +#define sk_OCSP_CERTID_insert(st, val, i) SKM_sk_insert(OCSP_CERTID, (st), (val), (i)) +#define sk_OCSP_CERTID_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(OCSP_CERTID, (st), (cmp)) +#define sk_OCSP_CERTID_dup(st) SKM_sk_dup(OCSP_CERTID, st) +#define sk_OCSP_CERTID_pop_free(st, free_func) SKM_sk_pop_free(OCSP_CERTID, (st), (free_func)) +#define sk_OCSP_CERTID_shift(st) SKM_sk_shift(OCSP_CERTID, (st)) +#define sk_OCSP_CERTID_pop(st) SKM_sk_pop(OCSP_CERTID, (st)) +#define sk_OCSP_CERTID_sort(st) SKM_sk_sort(OCSP_CERTID, (st)) +#define sk_OCSP_CERTID_is_sorted(st) SKM_sk_is_sorted(OCSP_CERTID, (st)) + +#define sk_OCSP_ONEREQ_new(st) SKM_sk_new(OCSP_ONEREQ, (st)) +#define sk_OCSP_ONEREQ_new_null() SKM_sk_new_null(OCSP_ONEREQ) +#define sk_OCSP_ONEREQ_free(st) SKM_sk_free(OCSP_ONEREQ, (st)) +#define sk_OCSP_ONEREQ_num(st) SKM_sk_num(OCSP_ONEREQ, (st)) +#define sk_OCSP_ONEREQ_value(st, i) SKM_sk_value(OCSP_ONEREQ, (st), (i)) +#define sk_OCSP_ONEREQ_set(st, i, val) SKM_sk_set(OCSP_ONEREQ, (st), (i), (val)) +#define sk_OCSP_ONEREQ_zero(st) SKM_sk_zero(OCSP_ONEREQ, (st)) +#define sk_OCSP_ONEREQ_push(st, val) SKM_sk_push(OCSP_ONEREQ, (st), (val)) +#define sk_OCSP_ONEREQ_unshift(st, val) SKM_sk_unshift(OCSP_ONEREQ, (st), (val)) +#define sk_OCSP_ONEREQ_find(st, val) SKM_sk_find(OCSP_ONEREQ, (st), (val)) +#define sk_OCSP_ONEREQ_find_ex(st, val) SKM_sk_find_ex(OCSP_ONEREQ, (st), (val)) +#define sk_OCSP_ONEREQ_delete(st, i) SKM_sk_delete(OCSP_ONEREQ, (st), (i)) +#define sk_OCSP_ONEREQ_delete_ptr(st, ptr) SKM_sk_delete_ptr(OCSP_ONEREQ, (st), (ptr)) +#define sk_OCSP_ONEREQ_insert(st, val, i) SKM_sk_insert(OCSP_ONEREQ, (st), (val), (i)) +#define sk_OCSP_ONEREQ_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(OCSP_ONEREQ, (st), (cmp)) +#define sk_OCSP_ONEREQ_dup(st) SKM_sk_dup(OCSP_ONEREQ, st) +#define sk_OCSP_ONEREQ_pop_free(st, free_func) SKM_sk_pop_free(OCSP_ONEREQ, (st), (free_func)) +#define sk_OCSP_ONEREQ_shift(st) SKM_sk_shift(OCSP_ONEREQ, (st)) +#define sk_OCSP_ONEREQ_pop(st) SKM_sk_pop(OCSP_ONEREQ, (st)) +#define sk_OCSP_ONEREQ_sort(st) SKM_sk_sort(OCSP_ONEREQ, (st)) +#define sk_OCSP_ONEREQ_is_sorted(st) SKM_sk_is_sorted(OCSP_ONEREQ, (st)) + +#define sk_OCSP_RESPID_new(st) SKM_sk_new(OCSP_RESPID, (st)) +#define sk_OCSP_RESPID_new_null() SKM_sk_new_null(OCSP_RESPID) +#define sk_OCSP_RESPID_free(st) SKM_sk_free(OCSP_RESPID, (st)) +#define sk_OCSP_RESPID_num(st) SKM_sk_num(OCSP_RESPID, (st)) +#define sk_OCSP_RESPID_value(st, i) SKM_sk_value(OCSP_RESPID, (st), (i)) +#define sk_OCSP_RESPID_set(st, i, val) SKM_sk_set(OCSP_RESPID, (st), (i), (val)) +#define sk_OCSP_RESPID_zero(st) SKM_sk_zero(OCSP_RESPID, (st)) +#define sk_OCSP_RESPID_push(st, val) SKM_sk_push(OCSP_RESPID, (st), (val)) +#define sk_OCSP_RESPID_unshift(st, val) SKM_sk_unshift(OCSP_RESPID, (st), (val)) +#define sk_OCSP_RESPID_find(st, val) SKM_sk_find(OCSP_RESPID, (st), (val)) +#define sk_OCSP_RESPID_find_ex(st, val) SKM_sk_find_ex(OCSP_RESPID, (st), (val)) +#define sk_OCSP_RESPID_delete(st, i) SKM_sk_delete(OCSP_RESPID, (st), (i)) +#define sk_OCSP_RESPID_delete_ptr(st, ptr) SKM_sk_delete_ptr(OCSP_RESPID, (st), (ptr)) +#define sk_OCSP_RESPID_insert(st, val, i) SKM_sk_insert(OCSP_RESPID, (st), (val), (i)) +#define sk_OCSP_RESPID_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(OCSP_RESPID, (st), (cmp)) +#define sk_OCSP_RESPID_dup(st) SKM_sk_dup(OCSP_RESPID, st) +#define sk_OCSP_RESPID_pop_free(st, free_func) SKM_sk_pop_free(OCSP_RESPID, (st), (free_func)) +#define sk_OCSP_RESPID_shift(st) SKM_sk_shift(OCSP_RESPID, (st)) +#define sk_OCSP_RESPID_pop(st) SKM_sk_pop(OCSP_RESPID, (st)) +#define sk_OCSP_RESPID_sort(st) SKM_sk_sort(OCSP_RESPID, (st)) +#define sk_OCSP_RESPID_is_sorted(st) SKM_sk_is_sorted(OCSP_RESPID, (st)) + +#define sk_OCSP_SINGLERESP_new(st) SKM_sk_new(OCSP_SINGLERESP, (st)) +#define sk_OCSP_SINGLERESP_new_null() SKM_sk_new_null(OCSP_SINGLERESP) +#define sk_OCSP_SINGLERESP_free(st) SKM_sk_free(OCSP_SINGLERESP, (st)) +#define sk_OCSP_SINGLERESP_num(st) SKM_sk_num(OCSP_SINGLERESP, (st)) +#define sk_OCSP_SINGLERESP_value(st, i) SKM_sk_value(OCSP_SINGLERESP, (st), (i)) +#define sk_OCSP_SINGLERESP_set(st, i, val) SKM_sk_set(OCSP_SINGLERESP, (st), (i), (val)) +#define sk_OCSP_SINGLERESP_zero(st) SKM_sk_zero(OCSP_SINGLERESP, (st)) +#define sk_OCSP_SINGLERESP_push(st, val) SKM_sk_push(OCSP_SINGLERESP, (st), (val)) +#define sk_OCSP_SINGLERESP_unshift(st, val) SKM_sk_unshift(OCSP_SINGLERESP, (st), (val)) +#define sk_OCSP_SINGLERESP_find(st, val) SKM_sk_find(OCSP_SINGLERESP, (st), (val)) +#define sk_OCSP_SINGLERESP_find_ex(st, val) SKM_sk_find_ex(OCSP_SINGLERESP, (st), (val)) +#define sk_OCSP_SINGLERESP_delete(st, i) SKM_sk_delete(OCSP_SINGLERESP, (st), (i)) +#define sk_OCSP_SINGLERESP_delete_ptr(st, ptr) SKM_sk_delete_ptr(OCSP_SINGLERESP, (st), (ptr)) +#define sk_OCSP_SINGLERESP_insert(st, val, i) SKM_sk_insert(OCSP_SINGLERESP, (st), (val), (i)) +#define sk_OCSP_SINGLERESP_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(OCSP_SINGLERESP, (st), (cmp)) +#define sk_OCSP_SINGLERESP_dup(st) SKM_sk_dup(OCSP_SINGLERESP, st) +#define sk_OCSP_SINGLERESP_pop_free(st, free_func) SKM_sk_pop_free(OCSP_SINGLERESP, (st), (free_func)) +#define sk_OCSP_SINGLERESP_shift(st) SKM_sk_shift(OCSP_SINGLERESP, (st)) +#define sk_OCSP_SINGLERESP_pop(st) SKM_sk_pop(OCSP_SINGLERESP, (st)) +#define sk_OCSP_SINGLERESP_sort(st) SKM_sk_sort(OCSP_SINGLERESP, (st)) +#define sk_OCSP_SINGLERESP_is_sorted(st) SKM_sk_is_sorted(OCSP_SINGLERESP, (st)) + +#define sk_PKCS12_SAFEBAG_new(st) SKM_sk_new(PKCS12_SAFEBAG, (st)) +#define sk_PKCS12_SAFEBAG_new_null() SKM_sk_new_null(PKCS12_SAFEBAG) +#define sk_PKCS12_SAFEBAG_free(st) SKM_sk_free(PKCS12_SAFEBAG, (st)) +#define sk_PKCS12_SAFEBAG_num(st) SKM_sk_num(PKCS12_SAFEBAG, (st)) +#define sk_PKCS12_SAFEBAG_value(st, i) SKM_sk_value(PKCS12_SAFEBAG, (st), (i)) +#define sk_PKCS12_SAFEBAG_set(st, i, val) SKM_sk_set(PKCS12_SAFEBAG, (st), (i), (val)) +#define sk_PKCS12_SAFEBAG_zero(st) SKM_sk_zero(PKCS12_SAFEBAG, (st)) +#define sk_PKCS12_SAFEBAG_push(st, val) SKM_sk_push(PKCS12_SAFEBAG, (st), (val)) +#define sk_PKCS12_SAFEBAG_unshift(st, val) SKM_sk_unshift(PKCS12_SAFEBAG, (st), (val)) +#define sk_PKCS12_SAFEBAG_find(st, val) SKM_sk_find(PKCS12_SAFEBAG, (st), (val)) +#define sk_PKCS12_SAFEBAG_find_ex(st, val) SKM_sk_find_ex(PKCS12_SAFEBAG, (st), (val)) +#define sk_PKCS12_SAFEBAG_delete(st, i) SKM_sk_delete(PKCS12_SAFEBAG, (st), (i)) +#define sk_PKCS12_SAFEBAG_delete_ptr(st, ptr) SKM_sk_delete_ptr(PKCS12_SAFEBAG, (st), (ptr)) +#define sk_PKCS12_SAFEBAG_insert(st, val, i) SKM_sk_insert(PKCS12_SAFEBAG, (st), (val), (i)) +#define sk_PKCS12_SAFEBAG_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(PKCS12_SAFEBAG, (st), (cmp)) +#define sk_PKCS12_SAFEBAG_dup(st) SKM_sk_dup(PKCS12_SAFEBAG, st) +#define sk_PKCS12_SAFEBAG_pop_free(st, free_func) SKM_sk_pop_free(PKCS12_SAFEBAG, (st), (free_func)) +#define sk_PKCS12_SAFEBAG_shift(st) SKM_sk_shift(PKCS12_SAFEBAG, (st)) +#define sk_PKCS12_SAFEBAG_pop(st) SKM_sk_pop(PKCS12_SAFEBAG, (st)) +#define sk_PKCS12_SAFEBAG_sort(st) SKM_sk_sort(PKCS12_SAFEBAG, (st)) +#define sk_PKCS12_SAFEBAG_is_sorted(st) SKM_sk_is_sorted(PKCS12_SAFEBAG, (st)) + +#define sk_PKCS7_new(st) SKM_sk_new(PKCS7, (st)) +#define sk_PKCS7_new_null() SKM_sk_new_null(PKCS7) +#define sk_PKCS7_free(st) SKM_sk_free(PKCS7, (st)) +#define sk_PKCS7_num(st) SKM_sk_num(PKCS7, (st)) +#define sk_PKCS7_value(st, i) SKM_sk_value(PKCS7, (st), (i)) +#define sk_PKCS7_set(st, i, val) SKM_sk_set(PKCS7, (st), (i), (val)) +#define sk_PKCS7_zero(st) SKM_sk_zero(PKCS7, (st)) +#define sk_PKCS7_push(st, val) SKM_sk_push(PKCS7, (st), (val)) +#define sk_PKCS7_unshift(st, val) SKM_sk_unshift(PKCS7, (st), (val)) +#define sk_PKCS7_find(st, val) SKM_sk_find(PKCS7, (st), (val)) +#define sk_PKCS7_find_ex(st, val) SKM_sk_find_ex(PKCS7, (st), (val)) +#define sk_PKCS7_delete(st, i) SKM_sk_delete(PKCS7, (st), (i)) +#define sk_PKCS7_delete_ptr(st, ptr) SKM_sk_delete_ptr(PKCS7, (st), (ptr)) +#define sk_PKCS7_insert(st, val, i) SKM_sk_insert(PKCS7, (st), (val), (i)) +#define sk_PKCS7_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(PKCS7, (st), (cmp)) +#define sk_PKCS7_dup(st) SKM_sk_dup(PKCS7, st) +#define sk_PKCS7_pop_free(st, free_func) SKM_sk_pop_free(PKCS7, (st), (free_func)) +#define sk_PKCS7_shift(st) SKM_sk_shift(PKCS7, (st)) +#define sk_PKCS7_pop(st) SKM_sk_pop(PKCS7, (st)) +#define sk_PKCS7_sort(st) SKM_sk_sort(PKCS7, (st)) +#define sk_PKCS7_is_sorted(st) SKM_sk_is_sorted(PKCS7, (st)) + +#define sk_PKCS7_RECIP_INFO_new(st) SKM_sk_new(PKCS7_RECIP_INFO, (st)) +#define sk_PKCS7_RECIP_INFO_new_null() SKM_sk_new_null(PKCS7_RECIP_INFO) +#define sk_PKCS7_RECIP_INFO_free(st) SKM_sk_free(PKCS7_RECIP_INFO, (st)) +#define sk_PKCS7_RECIP_INFO_num(st) SKM_sk_num(PKCS7_RECIP_INFO, (st)) +#define sk_PKCS7_RECIP_INFO_value(st, i) SKM_sk_value(PKCS7_RECIP_INFO, (st), (i)) +#define sk_PKCS7_RECIP_INFO_set(st, i, val) SKM_sk_set(PKCS7_RECIP_INFO, (st), (i), (val)) +#define sk_PKCS7_RECIP_INFO_zero(st) SKM_sk_zero(PKCS7_RECIP_INFO, (st)) +#define sk_PKCS7_RECIP_INFO_push(st, val) SKM_sk_push(PKCS7_RECIP_INFO, (st), (val)) +#define sk_PKCS7_RECIP_INFO_unshift(st, val) SKM_sk_unshift(PKCS7_RECIP_INFO, (st), (val)) +#define sk_PKCS7_RECIP_INFO_find(st, val) SKM_sk_find(PKCS7_RECIP_INFO, (st), (val)) +#define sk_PKCS7_RECIP_INFO_find_ex(st, val) SKM_sk_find_ex(PKCS7_RECIP_INFO, (st), (val)) +#define sk_PKCS7_RECIP_INFO_delete(st, i) SKM_sk_delete(PKCS7_RECIP_INFO, (st), (i)) +#define sk_PKCS7_RECIP_INFO_delete_ptr(st, ptr) SKM_sk_delete_ptr(PKCS7_RECIP_INFO, (st), (ptr)) +#define sk_PKCS7_RECIP_INFO_insert(st, val, i) SKM_sk_insert(PKCS7_RECIP_INFO, (st), (val), (i)) +#define sk_PKCS7_RECIP_INFO_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(PKCS7_RECIP_INFO, (st), (cmp)) +#define sk_PKCS7_RECIP_INFO_dup(st) SKM_sk_dup(PKCS7_RECIP_INFO, st) +#define sk_PKCS7_RECIP_INFO_pop_free(st, free_func) SKM_sk_pop_free(PKCS7_RECIP_INFO, (st), (free_func)) +#define sk_PKCS7_RECIP_INFO_shift(st) SKM_sk_shift(PKCS7_RECIP_INFO, (st)) +#define sk_PKCS7_RECIP_INFO_pop(st) SKM_sk_pop(PKCS7_RECIP_INFO, (st)) +#define sk_PKCS7_RECIP_INFO_sort(st) SKM_sk_sort(PKCS7_RECIP_INFO, (st)) +#define sk_PKCS7_RECIP_INFO_is_sorted(st) SKM_sk_is_sorted(PKCS7_RECIP_INFO, (st)) + +#define sk_PKCS7_SIGNER_INFO_new(st) SKM_sk_new(PKCS7_SIGNER_INFO, (st)) +#define sk_PKCS7_SIGNER_INFO_new_null() SKM_sk_new_null(PKCS7_SIGNER_INFO) +#define sk_PKCS7_SIGNER_INFO_free(st) SKM_sk_free(PKCS7_SIGNER_INFO, (st)) +#define sk_PKCS7_SIGNER_INFO_num(st) SKM_sk_num(PKCS7_SIGNER_INFO, (st)) +#define sk_PKCS7_SIGNER_INFO_value(st, i) SKM_sk_value(PKCS7_SIGNER_INFO, (st), (i)) +#define sk_PKCS7_SIGNER_INFO_set(st, i, val) SKM_sk_set(PKCS7_SIGNER_INFO, (st), (i), (val)) +#define sk_PKCS7_SIGNER_INFO_zero(st) SKM_sk_zero(PKCS7_SIGNER_INFO, (st)) +#define sk_PKCS7_SIGNER_INFO_push(st, val) SKM_sk_push(PKCS7_SIGNER_INFO, (st), (val)) +#define sk_PKCS7_SIGNER_INFO_unshift(st, val) SKM_sk_unshift(PKCS7_SIGNER_INFO, (st), (val)) +#define sk_PKCS7_SIGNER_INFO_find(st, val) SKM_sk_find(PKCS7_SIGNER_INFO, (st), (val)) +#define sk_PKCS7_SIGNER_INFO_find_ex(st, val) SKM_sk_find_ex(PKCS7_SIGNER_INFO, (st), (val)) +#define sk_PKCS7_SIGNER_INFO_delete(st, i) SKM_sk_delete(PKCS7_SIGNER_INFO, (st), (i)) +#define sk_PKCS7_SIGNER_INFO_delete_ptr(st, ptr) SKM_sk_delete_ptr(PKCS7_SIGNER_INFO, (st), (ptr)) +#define sk_PKCS7_SIGNER_INFO_insert(st, val, i) SKM_sk_insert(PKCS7_SIGNER_INFO, (st), (val), (i)) +#define sk_PKCS7_SIGNER_INFO_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(PKCS7_SIGNER_INFO, (st), (cmp)) +#define sk_PKCS7_SIGNER_INFO_dup(st) SKM_sk_dup(PKCS7_SIGNER_INFO, st) +#define sk_PKCS7_SIGNER_INFO_pop_free(st, free_func) SKM_sk_pop_free(PKCS7_SIGNER_INFO, (st), (free_func)) +#define sk_PKCS7_SIGNER_INFO_shift(st) SKM_sk_shift(PKCS7_SIGNER_INFO, (st)) +#define sk_PKCS7_SIGNER_INFO_pop(st) SKM_sk_pop(PKCS7_SIGNER_INFO, (st)) +#define sk_PKCS7_SIGNER_INFO_sort(st) SKM_sk_sort(PKCS7_SIGNER_INFO, (st)) +#define sk_PKCS7_SIGNER_INFO_is_sorted(st) SKM_sk_is_sorted(PKCS7_SIGNER_INFO, (st)) + +#define sk_POLICYINFO_new(st) SKM_sk_new(POLICYINFO, (st)) +#define sk_POLICYINFO_new_null() SKM_sk_new_null(POLICYINFO) +#define sk_POLICYINFO_free(st) SKM_sk_free(POLICYINFO, (st)) +#define sk_POLICYINFO_num(st) SKM_sk_num(POLICYINFO, (st)) +#define sk_POLICYINFO_value(st, i) SKM_sk_value(POLICYINFO, (st), (i)) +#define sk_POLICYINFO_set(st, i, val) SKM_sk_set(POLICYINFO, (st), (i), (val)) +#define sk_POLICYINFO_zero(st) SKM_sk_zero(POLICYINFO, (st)) +#define sk_POLICYINFO_push(st, val) SKM_sk_push(POLICYINFO, (st), (val)) +#define sk_POLICYINFO_unshift(st, val) SKM_sk_unshift(POLICYINFO, (st), (val)) +#define sk_POLICYINFO_find(st, val) SKM_sk_find(POLICYINFO, (st), (val)) +#define sk_POLICYINFO_find_ex(st, val) SKM_sk_find_ex(POLICYINFO, (st), (val)) +#define sk_POLICYINFO_delete(st, i) SKM_sk_delete(POLICYINFO, (st), (i)) +#define sk_POLICYINFO_delete_ptr(st, ptr) SKM_sk_delete_ptr(POLICYINFO, (st), (ptr)) +#define sk_POLICYINFO_insert(st, val, i) SKM_sk_insert(POLICYINFO, (st), (val), (i)) +#define sk_POLICYINFO_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(POLICYINFO, (st), (cmp)) +#define sk_POLICYINFO_dup(st) SKM_sk_dup(POLICYINFO, st) +#define sk_POLICYINFO_pop_free(st, free_func) SKM_sk_pop_free(POLICYINFO, (st), (free_func)) +#define sk_POLICYINFO_shift(st) SKM_sk_shift(POLICYINFO, (st)) +#define sk_POLICYINFO_pop(st) SKM_sk_pop(POLICYINFO, (st)) +#define sk_POLICYINFO_sort(st) SKM_sk_sort(POLICYINFO, (st)) +#define sk_POLICYINFO_is_sorted(st) SKM_sk_is_sorted(POLICYINFO, (st)) + +#define sk_POLICYQUALINFO_new(st) SKM_sk_new(POLICYQUALINFO, (st)) +#define sk_POLICYQUALINFO_new_null() SKM_sk_new_null(POLICYQUALINFO) +#define sk_POLICYQUALINFO_free(st) SKM_sk_free(POLICYQUALINFO, (st)) +#define sk_POLICYQUALINFO_num(st) SKM_sk_num(POLICYQUALINFO, (st)) +#define sk_POLICYQUALINFO_value(st, i) SKM_sk_value(POLICYQUALINFO, (st), (i)) +#define sk_POLICYQUALINFO_set(st, i, val) SKM_sk_set(POLICYQUALINFO, (st), (i), (val)) +#define sk_POLICYQUALINFO_zero(st) SKM_sk_zero(POLICYQUALINFO, (st)) +#define sk_POLICYQUALINFO_push(st, val) SKM_sk_push(POLICYQUALINFO, (st), (val)) +#define sk_POLICYQUALINFO_unshift(st, val) SKM_sk_unshift(POLICYQUALINFO, (st), (val)) +#define sk_POLICYQUALINFO_find(st, val) SKM_sk_find(POLICYQUALINFO, (st), (val)) +#define sk_POLICYQUALINFO_find_ex(st, val) SKM_sk_find_ex(POLICYQUALINFO, (st), (val)) +#define sk_POLICYQUALINFO_delete(st, i) SKM_sk_delete(POLICYQUALINFO, (st), (i)) +#define sk_POLICYQUALINFO_delete_ptr(st, ptr) SKM_sk_delete_ptr(POLICYQUALINFO, (st), (ptr)) +#define sk_POLICYQUALINFO_insert(st, val, i) SKM_sk_insert(POLICYQUALINFO, (st), (val), (i)) +#define sk_POLICYQUALINFO_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(POLICYQUALINFO, (st), (cmp)) +#define sk_POLICYQUALINFO_dup(st) SKM_sk_dup(POLICYQUALINFO, st) +#define sk_POLICYQUALINFO_pop_free(st, free_func) SKM_sk_pop_free(POLICYQUALINFO, (st), (free_func)) +#define sk_POLICYQUALINFO_shift(st) SKM_sk_shift(POLICYQUALINFO, (st)) +#define sk_POLICYQUALINFO_pop(st) SKM_sk_pop(POLICYQUALINFO, (st)) +#define sk_POLICYQUALINFO_sort(st) SKM_sk_sort(POLICYQUALINFO, (st)) +#define sk_POLICYQUALINFO_is_sorted(st) SKM_sk_is_sorted(POLICYQUALINFO, (st)) + +#define sk_POLICY_MAPPING_new(st) SKM_sk_new(POLICY_MAPPING, (st)) +#define sk_POLICY_MAPPING_new_null() SKM_sk_new_null(POLICY_MAPPING) +#define sk_POLICY_MAPPING_free(st) SKM_sk_free(POLICY_MAPPING, (st)) +#define sk_POLICY_MAPPING_num(st) SKM_sk_num(POLICY_MAPPING, (st)) +#define sk_POLICY_MAPPING_value(st, i) SKM_sk_value(POLICY_MAPPING, (st), (i)) +#define sk_POLICY_MAPPING_set(st, i, val) SKM_sk_set(POLICY_MAPPING, (st), (i), (val)) +#define sk_POLICY_MAPPING_zero(st) SKM_sk_zero(POLICY_MAPPING, (st)) +#define sk_POLICY_MAPPING_push(st, val) SKM_sk_push(POLICY_MAPPING, (st), (val)) +#define sk_POLICY_MAPPING_unshift(st, val) SKM_sk_unshift(POLICY_MAPPING, (st), (val)) +#define sk_POLICY_MAPPING_find(st, val) SKM_sk_find(POLICY_MAPPING, (st), (val)) +#define sk_POLICY_MAPPING_find_ex(st, val) SKM_sk_find_ex(POLICY_MAPPING, (st), (val)) +#define sk_POLICY_MAPPING_delete(st, i) SKM_sk_delete(POLICY_MAPPING, (st), (i)) +#define sk_POLICY_MAPPING_delete_ptr(st, ptr) SKM_sk_delete_ptr(POLICY_MAPPING, (st), (ptr)) +#define sk_POLICY_MAPPING_insert(st, val, i) SKM_sk_insert(POLICY_MAPPING, (st), (val), (i)) +#define sk_POLICY_MAPPING_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(POLICY_MAPPING, (st), (cmp)) +#define sk_POLICY_MAPPING_dup(st) SKM_sk_dup(POLICY_MAPPING, st) +#define sk_POLICY_MAPPING_pop_free(st, free_func) SKM_sk_pop_free(POLICY_MAPPING, (st), (free_func)) +#define sk_POLICY_MAPPING_shift(st) SKM_sk_shift(POLICY_MAPPING, (st)) +#define sk_POLICY_MAPPING_pop(st) SKM_sk_pop(POLICY_MAPPING, (st)) +#define sk_POLICY_MAPPING_sort(st) SKM_sk_sort(POLICY_MAPPING, (st)) +#define sk_POLICY_MAPPING_is_sorted(st) SKM_sk_is_sorted(POLICY_MAPPING, (st)) + +#define sk_SSL_CIPHER_new(st) SKM_sk_new(SSL_CIPHER, (st)) +#define sk_SSL_CIPHER_new_null() SKM_sk_new_null(SSL_CIPHER) +#define sk_SSL_CIPHER_free(st) SKM_sk_free(SSL_CIPHER, (st)) +#define sk_SSL_CIPHER_num(st) SKM_sk_num(SSL_CIPHER, (st)) +#define sk_SSL_CIPHER_value(st, i) SKM_sk_value(SSL_CIPHER, (st), (i)) +#define sk_SSL_CIPHER_set(st, i, val) SKM_sk_set(SSL_CIPHER, (st), (i), (val)) +#define sk_SSL_CIPHER_zero(st) SKM_sk_zero(SSL_CIPHER, (st)) +#define sk_SSL_CIPHER_push(st, val) SKM_sk_push(SSL_CIPHER, (st), (val)) +#define sk_SSL_CIPHER_unshift(st, val) SKM_sk_unshift(SSL_CIPHER, (st), (val)) +#define sk_SSL_CIPHER_find(st, val) SKM_sk_find(SSL_CIPHER, (st), (val)) +#define sk_SSL_CIPHER_find_ex(st, val) SKM_sk_find_ex(SSL_CIPHER, (st), (val)) +#define sk_SSL_CIPHER_delete(st, i) SKM_sk_delete(SSL_CIPHER, (st), (i)) +#define sk_SSL_CIPHER_delete_ptr(st, ptr) SKM_sk_delete_ptr(SSL_CIPHER, (st), (ptr)) +#define sk_SSL_CIPHER_insert(st, val, i) SKM_sk_insert(SSL_CIPHER, (st), (val), (i)) +#define sk_SSL_CIPHER_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(SSL_CIPHER, (st), (cmp)) +#define sk_SSL_CIPHER_dup(st) SKM_sk_dup(SSL_CIPHER, st) +#define sk_SSL_CIPHER_pop_free(st, free_func) SKM_sk_pop_free(SSL_CIPHER, (st), (free_func)) +#define sk_SSL_CIPHER_shift(st) SKM_sk_shift(SSL_CIPHER, (st)) +#define sk_SSL_CIPHER_pop(st) SKM_sk_pop(SSL_CIPHER, (st)) +#define sk_SSL_CIPHER_sort(st) SKM_sk_sort(SSL_CIPHER, (st)) +#define sk_SSL_CIPHER_is_sorted(st) SKM_sk_is_sorted(SSL_CIPHER, (st)) + +#define sk_SSL_COMP_new(st) SKM_sk_new(SSL_COMP, (st)) +#define sk_SSL_COMP_new_null() SKM_sk_new_null(SSL_COMP) +#define sk_SSL_COMP_free(st) SKM_sk_free(SSL_COMP, (st)) +#define sk_SSL_COMP_num(st) SKM_sk_num(SSL_COMP, (st)) +#define sk_SSL_COMP_value(st, i) SKM_sk_value(SSL_COMP, (st), (i)) +#define sk_SSL_COMP_set(st, i, val) SKM_sk_set(SSL_COMP, (st), (i), (val)) +#define sk_SSL_COMP_zero(st) SKM_sk_zero(SSL_COMP, (st)) +#define sk_SSL_COMP_push(st, val) SKM_sk_push(SSL_COMP, (st), (val)) +#define sk_SSL_COMP_unshift(st, val) SKM_sk_unshift(SSL_COMP, (st), (val)) +#define sk_SSL_COMP_find(st, val) SKM_sk_find(SSL_COMP, (st), (val)) +#define sk_SSL_COMP_find_ex(st, val) SKM_sk_find_ex(SSL_COMP, (st), (val)) +#define sk_SSL_COMP_delete(st, i) SKM_sk_delete(SSL_COMP, (st), (i)) +#define sk_SSL_COMP_delete_ptr(st, ptr) SKM_sk_delete_ptr(SSL_COMP, (st), (ptr)) +#define sk_SSL_COMP_insert(st, val, i) SKM_sk_insert(SSL_COMP, (st), (val), (i)) +#define sk_SSL_COMP_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(SSL_COMP, (st), (cmp)) +#define sk_SSL_COMP_dup(st) SKM_sk_dup(SSL_COMP, st) +#define sk_SSL_COMP_pop_free(st, free_func) SKM_sk_pop_free(SSL_COMP, (st), (free_func)) +#define sk_SSL_COMP_shift(st) SKM_sk_shift(SSL_COMP, (st)) +#define sk_SSL_COMP_pop(st) SKM_sk_pop(SSL_COMP, (st)) +#define sk_SSL_COMP_sort(st) SKM_sk_sort(SSL_COMP, (st)) +#define sk_SSL_COMP_is_sorted(st) SKM_sk_is_sorted(SSL_COMP, (st)) + +#define sk_STORE_OBJECT_new(st) SKM_sk_new(STORE_OBJECT, (st)) +#define sk_STORE_OBJECT_new_null() SKM_sk_new_null(STORE_OBJECT) +#define sk_STORE_OBJECT_free(st) SKM_sk_free(STORE_OBJECT, (st)) +#define sk_STORE_OBJECT_num(st) SKM_sk_num(STORE_OBJECT, (st)) +#define sk_STORE_OBJECT_value(st, i) SKM_sk_value(STORE_OBJECT, (st), (i)) +#define sk_STORE_OBJECT_set(st, i, val) SKM_sk_set(STORE_OBJECT, (st), (i), (val)) +#define sk_STORE_OBJECT_zero(st) SKM_sk_zero(STORE_OBJECT, (st)) +#define sk_STORE_OBJECT_push(st, val) SKM_sk_push(STORE_OBJECT, (st), (val)) +#define sk_STORE_OBJECT_unshift(st, val) SKM_sk_unshift(STORE_OBJECT, (st), (val)) +#define sk_STORE_OBJECT_find(st, val) SKM_sk_find(STORE_OBJECT, (st), (val)) +#define sk_STORE_OBJECT_find_ex(st, val) SKM_sk_find_ex(STORE_OBJECT, (st), (val)) +#define sk_STORE_OBJECT_delete(st, i) SKM_sk_delete(STORE_OBJECT, (st), (i)) +#define sk_STORE_OBJECT_delete_ptr(st, ptr) SKM_sk_delete_ptr(STORE_OBJECT, (st), (ptr)) +#define sk_STORE_OBJECT_insert(st, val, i) SKM_sk_insert(STORE_OBJECT, (st), (val), (i)) +#define sk_STORE_OBJECT_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(STORE_OBJECT, (st), (cmp)) +#define sk_STORE_OBJECT_dup(st) SKM_sk_dup(STORE_OBJECT, st) +#define sk_STORE_OBJECT_pop_free(st, free_func) SKM_sk_pop_free(STORE_OBJECT, (st), (free_func)) +#define sk_STORE_OBJECT_shift(st) SKM_sk_shift(STORE_OBJECT, (st)) +#define sk_STORE_OBJECT_pop(st) SKM_sk_pop(STORE_OBJECT, (st)) +#define sk_STORE_OBJECT_sort(st) SKM_sk_sort(STORE_OBJECT, (st)) +#define sk_STORE_OBJECT_is_sorted(st) SKM_sk_is_sorted(STORE_OBJECT, (st)) + +#define sk_SXNETID_new(st) SKM_sk_new(SXNETID, (st)) +#define sk_SXNETID_new_null() SKM_sk_new_null(SXNETID) +#define sk_SXNETID_free(st) SKM_sk_free(SXNETID, (st)) +#define sk_SXNETID_num(st) SKM_sk_num(SXNETID, (st)) +#define sk_SXNETID_value(st, i) SKM_sk_value(SXNETID, (st), (i)) +#define sk_SXNETID_set(st, i, val) SKM_sk_set(SXNETID, (st), (i), (val)) +#define sk_SXNETID_zero(st) SKM_sk_zero(SXNETID, (st)) +#define sk_SXNETID_push(st, val) SKM_sk_push(SXNETID, (st), (val)) +#define sk_SXNETID_unshift(st, val) SKM_sk_unshift(SXNETID, (st), (val)) +#define sk_SXNETID_find(st, val) SKM_sk_find(SXNETID, (st), (val)) +#define sk_SXNETID_find_ex(st, val) SKM_sk_find_ex(SXNETID, (st), (val)) +#define sk_SXNETID_delete(st, i) SKM_sk_delete(SXNETID, (st), (i)) +#define sk_SXNETID_delete_ptr(st, ptr) SKM_sk_delete_ptr(SXNETID, (st), (ptr)) +#define sk_SXNETID_insert(st, val, i) SKM_sk_insert(SXNETID, (st), (val), (i)) +#define sk_SXNETID_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(SXNETID, (st), (cmp)) +#define sk_SXNETID_dup(st) SKM_sk_dup(SXNETID, st) +#define sk_SXNETID_pop_free(st, free_func) SKM_sk_pop_free(SXNETID, (st), (free_func)) +#define sk_SXNETID_shift(st) SKM_sk_shift(SXNETID, (st)) +#define sk_SXNETID_pop(st) SKM_sk_pop(SXNETID, (st)) +#define sk_SXNETID_sort(st) SKM_sk_sort(SXNETID, (st)) +#define sk_SXNETID_is_sorted(st) SKM_sk_is_sorted(SXNETID, (st)) + +#define sk_UI_STRING_new(st) SKM_sk_new(UI_STRING, (st)) +#define sk_UI_STRING_new_null() SKM_sk_new_null(UI_STRING) +#define sk_UI_STRING_free(st) SKM_sk_free(UI_STRING, (st)) +#define sk_UI_STRING_num(st) SKM_sk_num(UI_STRING, (st)) +#define sk_UI_STRING_value(st, i) SKM_sk_value(UI_STRING, (st), (i)) +#define sk_UI_STRING_set(st, i, val) SKM_sk_set(UI_STRING, (st), (i), (val)) +#define sk_UI_STRING_zero(st) SKM_sk_zero(UI_STRING, (st)) +#define sk_UI_STRING_push(st, val) SKM_sk_push(UI_STRING, (st), (val)) +#define sk_UI_STRING_unshift(st, val) SKM_sk_unshift(UI_STRING, (st), (val)) +#define sk_UI_STRING_find(st, val) SKM_sk_find(UI_STRING, (st), (val)) +#define sk_UI_STRING_find_ex(st, val) SKM_sk_find_ex(UI_STRING, (st), (val)) +#define sk_UI_STRING_delete(st, i) SKM_sk_delete(UI_STRING, (st), (i)) +#define sk_UI_STRING_delete_ptr(st, ptr) SKM_sk_delete_ptr(UI_STRING, (st), (ptr)) +#define sk_UI_STRING_insert(st, val, i) SKM_sk_insert(UI_STRING, (st), (val), (i)) +#define sk_UI_STRING_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(UI_STRING, (st), (cmp)) +#define sk_UI_STRING_dup(st) SKM_sk_dup(UI_STRING, st) +#define sk_UI_STRING_pop_free(st, free_func) SKM_sk_pop_free(UI_STRING, (st), (free_func)) +#define sk_UI_STRING_shift(st) SKM_sk_shift(UI_STRING, (st)) +#define sk_UI_STRING_pop(st) SKM_sk_pop(UI_STRING, (st)) +#define sk_UI_STRING_sort(st) SKM_sk_sort(UI_STRING, (st)) +#define sk_UI_STRING_is_sorted(st) SKM_sk_is_sorted(UI_STRING, (st)) + +#define sk_X509_new(st) SKM_sk_new(X509, (st)) +#define sk_X509_new_null() SKM_sk_new_null(X509) +#define sk_X509_free(st) SKM_sk_free(X509, (st)) +#define sk_X509_num(st) SKM_sk_num(X509, (st)) +#define sk_X509_value(st, i) SKM_sk_value(X509, (st), (i)) +#define sk_X509_set(st, i, val) SKM_sk_set(X509, (st), (i), (val)) +#define sk_X509_zero(st) SKM_sk_zero(X509, (st)) +#define sk_X509_push(st, val) SKM_sk_push(X509, (st), (val)) +#define sk_X509_unshift(st, val) SKM_sk_unshift(X509, (st), (val)) +#define sk_X509_find(st, val) SKM_sk_find(X509, (st), (val)) +#define sk_X509_find_ex(st, val) SKM_sk_find_ex(X509, (st), (val)) +#define sk_X509_delete(st, i) SKM_sk_delete(X509, (st), (i)) +#define sk_X509_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509, (st), (ptr)) +#define sk_X509_insert(st, val, i) SKM_sk_insert(X509, (st), (val), (i)) +#define sk_X509_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509, (st), (cmp)) +#define sk_X509_dup(st) SKM_sk_dup(X509, st) +#define sk_X509_pop_free(st, free_func) SKM_sk_pop_free(X509, (st), (free_func)) +#define sk_X509_shift(st) SKM_sk_shift(X509, (st)) +#define sk_X509_pop(st) SKM_sk_pop(X509, (st)) +#define sk_X509_sort(st) SKM_sk_sort(X509, (st)) +#define sk_X509_is_sorted(st) SKM_sk_is_sorted(X509, (st)) + +#define sk_X509V3_EXT_METHOD_new(st) SKM_sk_new(X509V3_EXT_METHOD, (st)) +#define sk_X509V3_EXT_METHOD_new_null() SKM_sk_new_null(X509V3_EXT_METHOD) +#define sk_X509V3_EXT_METHOD_free(st) SKM_sk_free(X509V3_EXT_METHOD, (st)) +#define sk_X509V3_EXT_METHOD_num(st) SKM_sk_num(X509V3_EXT_METHOD, (st)) +#define sk_X509V3_EXT_METHOD_value(st, i) SKM_sk_value(X509V3_EXT_METHOD, (st), (i)) +#define sk_X509V3_EXT_METHOD_set(st, i, val) SKM_sk_set(X509V3_EXT_METHOD, (st), (i), (val)) +#define sk_X509V3_EXT_METHOD_zero(st) SKM_sk_zero(X509V3_EXT_METHOD, (st)) +#define sk_X509V3_EXT_METHOD_push(st, val) SKM_sk_push(X509V3_EXT_METHOD, (st), (val)) +#define sk_X509V3_EXT_METHOD_unshift(st, val) SKM_sk_unshift(X509V3_EXT_METHOD, (st), (val)) +#define sk_X509V3_EXT_METHOD_find(st, val) SKM_sk_find(X509V3_EXT_METHOD, (st), (val)) +#define sk_X509V3_EXT_METHOD_find_ex(st, val) SKM_sk_find_ex(X509V3_EXT_METHOD, (st), (val)) +#define sk_X509V3_EXT_METHOD_delete(st, i) SKM_sk_delete(X509V3_EXT_METHOD, (st), (i)) +#define sk_X509V3_EXT_METHOD_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509V3_EXT_METHOD, (st), (ptr)) +#define sk_X509V3_EXT_METHOD_insert(st, val, i) SKM_sk_insert(X509V3_EXT_METHOD, (st), (val), (i)) +#define sk_X509V3_EXT_METHOD_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509V3_EXT_METHOD, (st), (cmp)) +#define sk_X509V3_EXT_METHOD_dup(st) SKM_sk_dup(X509V3_EXT_METHOD, st) +#define sk_X509V3_EXT_METHOD_pop_free(st, free_func) SKM_sk_pop_free(X509V3_EXT_METHOD, (st), (free_func)) +#define sk_X509V3_EXT_METHOD_shift(st) SKM_sk_shift(X509V3_EXT_METHOD, (st)) +#define sk_X509V3_EXT_METHOD_pop(st) SKM_sk_pop(X509V3_EXT_METHOD, (st)) +#define sk_X509V3_EXT_METHOD_sort(st) SKM_sk_sort(X509V3_EXT_METHOD, (st)) +#define sk_X509V3_EXT_METHOD_is_sorted(st) SKM_sk_is_sorted(X509V3_EXT_METHOD, (st)) + +#define sk_X509_ALGOR_new(st) SKM_sk_new(X509_ALGOR, (st)) +#define sk_X509_ALGOR_new_null() SKM_sk_new_null(X509_ALGOR) +#define sk_X509_ALGOR_free(st) SKM_sk_free(X509_ALGOR, (st)) +#define sk_X509_ALGOR_num(st) SKM_sk_num(X509_ALGOR, (st)) +#define sk_X509_ALGOR_value(st, i) SKM_sk_value(X509_ALGOR, (st), (i)) +#define sk_X509_ALGOR_set(st, i, val) SKM_sk_set(X509_ALGOR, (st), (i), (val)) +#define sk_X509_ALGOR_zero(st) SKM_sk_zero(X509_ALGOR, (st)) +#define sk_X509_ALGOR_push(st, val) SKM_sk_push(X509_ALGOR, (st), (val)) +#define sk_X509_ALGOR_unshift(st, val) SKM_sk_unshift(X509_ALGOR, (st), (val)) +#define sk_X509_ALGOR_find(st, val) SKM_sk_find(X509_ALGOR, (st), (val)) +#define sk_X509_ALGOR_find_ex(st, val) SKM_sk_find_ex(X509_ALGOR, (st), (val)) +#define sk_X509_ALGOR_delete(st, i) SKM_sk_delete(X509_ALGOR, (st), (i)) +#define sk_X509_ALGOR_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509_ALGOR, (st), (ptr)) +#define sk_X509_ALGOR_insert(st, val, i) SKM_sk_insert(X509_ALGOR, (st), (val), (i)) +#define sk_X509_ALGOR_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509_ALGOR, (st), (cmp)) +#define sk_X509_ALGOR_dup(st) SKM_sk_dup(X509_ALGOR, st) +#define sk_X509_ALGOR_pop_free(st, free_func) SKM_sk_pop_free(X509_ALGOR, (st), (free_func)) +#define sk_X509_ALGOR_shift(st) SKM_sk_shift(X509_ALGOR, (st)) +#define sk_X509_ALGOR_pop(st) SKM_sk_pop(X509_ALGOR, (st)) +#define sk_X509_ALGOR_sort(st) SKM_sk_sort(X509_ALGOR, (st)) +#define sk_X509_ALGOR_is_sorted(st) SKM_sk_is_sorted(X509_ALGOR, (st)) + +#define sk_X509_ATTRIBUTE_new(st) SKM_sk_new(X509_ATTRIBUTE, (st)) +#define sk_X509_ATTRIBUTE_new_null() SKM_sk_new_null(X509_ATTRIBUTE) +#define sk_X509_ATTRIBUTE_free(st) SKM_sk_free(X509_ATTRIBUTE, (st)) +#define sk_X509_ATTRIBUTE_num(st) SKM_sk_num(X509_ATTRIBUTE, (st)) +#define sk_X509_ATTRIBUTE_value(st, i) SKM_sk_value(X509_ATTRIBUTE, (st), (i)) +#define sk_X509_ATTRIBUTE_set(st, i, val) SKM_sk_set(X509_ATTRIBUTE, (st), (i), (val)) +#define sk_X509_ATTRIBUTE_zero(st) SKM_sk_zero(X509_ATTRIBUTE, (st)) +#define sk_X509_ATTRIBUTE_push(st, val) SKM_sk_push(X509_ATTRIBUTE, (st), (val)) +#define sk_X509_ATTRIBUTE_unshift(st, val) SKM_sk_unshift(X509_ATTRIBUTE, (st), (val)) +#define sk_X509_ATTRIBUTE_find(st, val) SKM_sk_find(X509_ATTRIBUTE, (st), (val)) +#define sk_X509_ATTRIBUTE_find_ex(st, val) SKM_sk_find_ex(X509_ATTRIBUTE, (st), (val)) +#define sk_X509_ATTRIBUTE_delete(st, i) SKM_sk_delete(X509_ATTRIBUTE, (st), (i)) +#define sk_X509_ATTRIBUTE_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509_ATTRIBUTE, (st), (ptr)) +#define sk_X509_ATTRIBUTE_insert(st, val, i) SKM_sk_insert(X509_ATTRIBUTE, (st), (val), (i)) +#define sk_X509_ATTRIBUTE_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509_ATTRIBUTE, (st), (cmp)) +#define sk_X509_ATTRIBUTE_dup(st) SKM_sk_dup(X509_ATTRIBUTE, st) +#define sk_X509_ATTRIBUTE_pop_free(st, free_func) SKM_sk_pop_free(X509_ATTRIBUTE, (st), (free_func)) +#define sk_X509_ATTRIBUTE_shift(st) SKM_sk_shift(X509_ATTRIBUTE, (st)) +#define sk_X509_ATTRIBUTE_pop(st) SKM_sk_pop(X509_ATTRIBUTE, (st)) +#define sk_X509_ATTRIBUTE_sort(st) SKM_sk_sort(X509_ATTRIBUTE, (st)) +#define sk_X509_ATTRIBUTE_is_sorted(st) SKM_sk_is_sorted(X509_ATTRIBUTE, (st)) + +#define sk_X509_CRL_new(st) SKM_sk_new(X509_CRL, (st)) +#define sk_X509_CRL_new_null() SKM_sk_new_null(X509_CRL) +#define sk_X509_CRL_free(st) SKM_sk_free(X509_CRL, (st)) +#define sk_X509_CRL_num(st) SKM_sk_num(X509_CRL, (st)) +#define sk_X509_CRL_value(st, i) SKM_sk_value(X509_CRL, (st), (i)) +#define sk_X509_CRL_set(st, i, val) SKM_sk_set(X509_CRL, (st), (i), (val)) +#define sk_X509_CRL_zero(st) SKM_sk_zero(X509_CRL, (st)) +#define sk_X509_CRL_push(st, val) SKM_sk_push(X509_CRL, (st), (val)) +#define sk_X509_CRL_unshift(st, val) SKM_sk_unshift(X509_CRL, (st), (val)) +#define sk_X509_CRL_find(st, val) SKM_sk_find(X509_CRL, (st), (val)) +#define sk_X509_CRL_find_ex(st, val) SKM_sk_find_ex(X509_CRL, (st), (val)) +#define sk_X509_CRL_delete(st, i) SKM_sk_delete(X509_CRL, (st), (i)) +#define sk_X509_CRL_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509_CRL, (st), (ptr)) +#define sk_X509_CRL_insert(st, val, i) SKM_sk_insert(X509_CRL, (st), (val), (i)) +#define sk_X509_CRL_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509_CRL, (st), (cmp)) +#define sk_X509_CRL_dup(st) SKM_sk_dup(X509_CRL, st) +#define sk_X509_CRL_pop_free(st, free_func) SKM_sk_pop_free(X509_CRL, (st), (free_func)) +#define sk_X509_CRL_shift(st) SKM_sk_shift(X509_CRL, (st)) +#define sk_X509_CRL_pop(st) SKM_sk_pop(X509_CRL, (st)) +#define sk_X509_CRL_sort(st) SKM_sk_sort(X509_CRL, (st)) +#define sk_X509_CRL_is_sorted(st) SKM_sk_is_sorted(X509_CRL, (st)) + +#define sk_X509_EXTENSION_new(st) SKM_sk_new(X509_EXTENSION, (st)) +#define sk_X509_EXTENSION_new_null() SKM_sk_new_null(X509_EXTENSION) +#define sk_X509_EXTENSION_free(st) SKM_sk_free(X509_EXTENSION, (st)) +#define sk_X509_EXTENSION_num(st) SKM_sk_num(X509_EXTENSION, (st)) +#define sk_X509_EXTENSION_value(st, i) SKM_sk_value(X509_EXTENSION, (st), (i)) +#define sk_X509_EXTENSION_set(st, i, val) SKM_sk_set(X509_EXTENSION, (st), (i), (val)) +#define sk_X509_EXTENSION_zero(st) SKM_sk_zero(X509_EXTENSION, (st)) +#define sk_X509_EXTENSION_push(st, val) SKM_sk_push(X509_EXTENSION, (st), (val)) +#define sk_X509_EXTENSION_unshift(st, val) SKM_sk_unshift(X509_EXTENSION, (st), (val)) +#define sk_X509_EXTENSION_find(st, val) SKM_sk_find(X509_EXTENSION, (st), (val)) +#define sk_X509_EXTENSION_find_ex(st, val) SKM_sk_find_ex(X509_EXTENSION, (st), (val)) +#define sk_X509_EXTENSION_delete(st, i) SKM_sk_delete(X509_EXTENSION, (st), (i)) +#define sk_X509_EXTENSION_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509_EXTENSION, (st), (ptr)) +#define sk_X509_EXTENSION_insert(st, val, i) SKM_sk_insert(X509_EXTENSION, (st), (val), (i)) +#define sk_X509_EXTENSION_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509_EXTENSION, (st), (cmp)) +#define sk_X509_EXTENSION_dup(st) SKM_sk_dup(X509_EXTENSION, st) +#define sk_X509_EXTENSION_pop_free(st, free_func) SKM_sk_pop_free(X509_EXTENSION, (st), (free_func)) +#define sk_X509_EXTENSION_shift(st) SKM_sk_shift(X509_EXTENSION, (st)) +#define sk_X509_EXTENSION_pop(st) SKM_sk_pop(X509_EXTENSION, (st)) +#define sk_X509_EXTENSION_sort(st) SKM_sk_sort(X509_EXTENSION, (st)) +#define sk_X509_EXTENSION_is_sorted(st) SKM_sk_is_sorted(X509_EXTENSION, (st)) + +#define sk_X509_INFO_new(st) SKM_sk_new(X509_INFO, (st)) +#define sk_X509_INFO_new_null() SKM_sk_new_null(X509_INFO) +#define sk_X509_INFO_free(st) SKM_sk_free(X509_INFO, (st)) +#define sk_X509_INFO_num(st) SKM_sk_num(X509_INFO, (st)) +#define sk_X509_INFO_value(st, i) SKM_sk_value(X509_INFO, (st), (i)) +#define sk_X509_INFO_set(st, i, val) SKM_sk_set(X509_INFO, (st), (i), (val)) +#define sk_X509_INFO_zero(st) SKM_sk_zero(X509_INFO, (st)) +#define sk_X509_INFO_push(st, val) SKM_sk_push(X509_INFO, (st), (val)) +#define sk_X509_INFO_unshift(st, val) SKM_sk_unshift(X509_INFO, (st), (val)) +#define sk_X509_INFO_find(st, val) SKM_sk_find(X509_INFO, (st), (val)) +#define sk_X509_INFO_find_ex(st, val) SKM_sk_find_ex(X509_INFO, (st), (val)) +#define sk_X509_INFO_delete(st, i) SKM_sk_delete(X509_INFO, (st), (i)) +#define sk_X509_INFO_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509_INFO, (st), (ptr)) +#define sk_X509_INFO_insert(st, val, i) SKM_sk_insert(X509_INFO, (st), (val), (i)) +#define sk_X509_INFO_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509_INFO, (st), (cmp)) +#define sk_X509_INFO_dup(st) SKM_sk_dup(X509_INFO, st) +#define sk_X509_INFO_pop_free(st, free_func) SKM_sk_pop_free(X509_INFO, (st), (free_func)) +#define sk_X509_INFO_shift(st) SKM_sk_shift(X509_INFO, (st)) +#define sk_X509_INFO_pop(st) SKM_sk_pop(X509_INFO, (st)) +#define sk_X509_INFO_sort(st) SKM_sk_sort(X509_INFO, (st)) +#define sk_X509_INFO_is_sorted(st) SKM_sk_is_sorted(X509_INFO, (st)) + +#define sk_X509_LOOKUP_new(st) SKM_sk_new(X509_LOOKUP, (st)) +#define sk_X509_LOOKUP_new_null() SKM_sk_new_null(X509_LOOKUP) +#define sk_X509_LOOKUP_free(st) SKM_sk_free(X509_LOOKUP, (st)) +#define sk_X509_LOOKUP_num(st) SKM_sk_num(X509_LOOKUP, (st)) +#define sk_X509_LOOKUP_value(st, i) SKM_sk_value(X509_LOOKUP, (st), (i)) +#define sk_X509_LOOKUP_set(st, i, val) SKM_sk_set(X509_LOOKUP, (st), (i), (val)) +#define sk_X509_LOOKUP_zero(st) SKM_sk_zero(X509_LOOKUP, (st)) +#define sk_X509_LOOKUP_push(st, val) SKM_sk_push(X509_LOOKUP, (st), (val)) +#define sk_X509_LOOKUP_unshift(st, val) SKM_sk_unshift(X509_LOOKUP, (st), (val)) +#define sk_X509_LOOKUP_find(st, val) SKM_sk_find(X509_LOOKUP, (st), (val)) +#define sk_X509_LOOKUP_find_ex(st, val) SKM_sk_find_ex(X509_LOOKUP, (st), (val)) +#define sk_X509_LOOKUP_delete(st, i) SKM_sk_delete(X509_LOOKUP, (st), (i)) +#define sk_X509_LOOKUP_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509_LOOKUP, (st), (ptr)) +#define sk_X509_LOOKUP_insert(st, val, i) SKM_sk_insert(X509_LOOKUP, (st), (val), (i)) +#define sk_X509_LOOKUP_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509_LOOKUP, (st), (cmp)) +#define sk_X509_LOOKUP_dup(st) SKM_sk_dup(X509_LOOKUP, st) +#define sk_X509_LOOKUP_pop_free(st, free_func) SKM_sk_pop_free(X509_LOOKUP, (st), (free_func)) +#define sk_X509_LOOKUP_shift(st) SKM_sk_shift(X509_LOOKUP, (st)) +#define sk_X509_LOOKUP_pop(st) SKM_sk_pop(X509_LOOKUP, (st)) +#define sk_X509_LOOKUP_sort(st) SKM_sk_sort(X509_LOOKUP, (st)) +#define sk_X509_LOOKUP_is_sorted(st) SKM_sk_is_sorted(X509_LOOKUP, (st)) + +#define sk_X509_NAME_new(st) SKM_sk_new(X509_NAME, (st)) +#define sk_X509_NAME_new_null() SKM_sk_new_null(X509_NAME) +#define sk_X509_NAME_free(st) SKM_sk_free(X509_NAME, (st)) +#define sk_X509_NAME_num(st) SKM_sk_num(X509_NAME, (st)) +#define sk_X509_NAME_value(st, i) SKM_sk_value(X509_NAME, (st), (i)) +#define sk_X509_NAME_set(st, i, val) SKM_sk_set(X509_NAME, (st), (i), (val)) +#define sk_X509_NAME_zero(st) SKM_sk_zero(X509_NAME, (st)) +#define sk_X509_NAME_push(st, val) SKM_sk_push(X509_NAME, (st), (val)) +#define sk_X509_NAME_unshift(st, val) SKM_sk_unshift(X509_NAME, (st), (val)) +#define sk_X509_NAME_find(st, val) SKM_sk_find(X509_NAME, (st), (val)) +#define sk_X509_NAME_find_ex(st, val) SKM_sk_find_ex(X509_NAME, (st), (val)) +#define sk_X509_NAME_delete(st, i) SKM_sk_delete(X509_NAME, (st), (i)) +#define sk_X509_NAME_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509_NAME, (st), (ptr)) +#define sk_X509_NAME_insert(st, val, i) SKM_sk_insert(X509_NAME, (st), (val), (i)) +#define sk_X509_NAME_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509_NAME, (st), (cmp)) +#define sk_X509_NAME_dup(st) SKM_sk_dup(X509_NAME, st) +#define sk_X509_NAME_pop_free(st, free_func) SKM_sk_pop_free(X509_NAME, (st), (free_func)) +#define sk_X509_NAME_shift(st) SKM_sk_shift(X509_NAME, (st)) +#define sk_X509_NAME_pop(st) SKM_sk_pop(X509_NAME, (st)) +#define sk_X509_NAME_sort(st) SKM_sk_sort(X509_NAME, (st)) +#define sk_X509_NAME_is_sorted(st) SKM_sk_is_sorted(X509_NAME, (st)) + +#define sk_X509_NAME_ENTRY_new(st) SKM_sk_new(X509_NAME_ENTRY, (st)) +#define sk_X509_NAME_ENTRY_new_null() SKM_sk_new_null(X509_NAME_ENTRY) +#define sk_X509_NAME_ENTRY_free(st) SKM_sk_free(X509_NAME_ENTRY, (st)) +#define sk_X509_NAME_ENTRY_num(st) SKM_sk_num(X509_NAME_ENTRY, (st)) +#define sk_X509_NAME_ENTRY_value(st, i) SKM_sk_value(X509_NAME_ENTRY, (st), (i)) +#define sk_X509_NAME_ENTRY_set(st, i, val) SKM_sk_set(X509_NAME_ENTRY, (st), (i), (val)) +#define sk_X509_NAME_ENTRY_zero(st) SKM_sk_zero(X509_NAME_ENTRY, (st)) +#define sk_X509_NAME_ENTRY_push(st, val) SKM_sk_push(X509_NAME_ENTRY, (st), (val)) +#define sk_X509_NAME_ENTRY_unshift(st, val) SKM_sk_unshift(X509_NAME_ENTRY, (st), (val)) +#define sk_X509_NAME_ENTRY_find(st, val) SKM_sk_find(X509_NAME_ENTRY, (st), (val)) +#define sk_X509_NAME_ENTRY_find_ex(st, val) SKM_sk_find_ex(X509_NAME_ENTRY, (st), (val)) +#define sk_X509_NAME_ENTRY_delete(st, i) SKM_sk_delete(X509_NAME_ENTRY, (st), (i)) +#define sk_X509_NAME_ENTRY_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509_NAME_ENTRY, (st), (ptr)) +#define sk_X509_NAME_ENTRY_insert(st, val, i) SKM_sk_insert(X509_NAME_ENTRY, (st), (val), (i)) +#define sk_X509_NAME_ENTRY_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509_NAME_ENTRY, (st), (cmp)) +#define sk_X509_NAME_ENTRY_dup(st) SKM_sk_dup(X509_NAME_ENTRY, st) +#define sk_X509_NAME_ENTRY_pop_free(st, free_func) SKM_sk_pop_free(X509_NAME_ENTRY, (st), (free_func)) +#define sk_X509_NAME_ENTRY_shift(st) SKM_sk_shift(X509_NAME_ENTRY, (st)) +#define sk_X509_NAME_ENTRY_pop(st) SKM_sk_pop(X509_NAME_ENTRY, (st)) +#define sk_X509_NAME_ENTRY_sort(st) SKM_sk_sort(X509_NAME_ENTRY, (st)) +#define sk_X509_NAME_ENTRY_is_sorted(st) SKM_sk_is_sorted(X509_NAME_ENTRY, (st)) + +#define sk_X509_OBJECT_new(st) SKM_sk_new(X509_OBJECT, (st)) +#define sk_X509_OBJECT_new_null() SKM_sk_new_null(X509_OBJECT) +#define sk_X509_OBJECT_free(st) SKM_sk_free(X509_OBJECT, (st)) +#define sk_X509_OBJECT_num(st) SKM_sk_num(X509_OBJECT, (st)) +#define sk_X509_OBJECT_value(st, i) SKM_sk_value(X509_OBJECT, (st), (i)) +#define sk_X509_OBJECT_set(st, i, val) SKM_sk_set(X509_OBJECT, (st), (i), (val)) +#define sk_X509_OBJECT_zero(st) SKM_sk_zero(X509_OBJECT, (st)) +#define sk_X509_OBJECT_push(st, val) SKM_sk_push(X509_OBJECT, (st), (val)) +#define sk_X509_OBJECT_unshift(st, val) SKM_sk_unshift(X509_OBJECT, (st), (val)) +#define sk_X509_OBJECT_find(st, val) SKM_sk_find(X509_OBJECT, (st), (val)) +#define sk_X509_OBJECT_find_ex(st, val) SKM_sk_find_ex(X509_OBJECT, (st), (val)) +#define sk_X509_OBJECT_delete(st, i) SKM_sk_delete(X509_OBJECT, (st), (i)) +#define sk_X509_OBJECT_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509_OBJECT, (st), (ptr)) +#define sk_X509_OBJECT_insert(st, val, i) SKM_sk_insert(X509_OBJECT, (st), (val), (i)) +#define sk_X509_OBJECT_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509_OBJECT, (st), (cmp)) +#define sk_X509_OBJECT_dup(st) SKM_sk_dup(X509_OBJECT, st) +#define sk_X509_OBJECT_pop_free(st, free_func) SKM_sk_pop_free(X509_OBJECT, (st), (free_func)) +#define sk_X509_OBJECT_shift(st) SKM_sk_shift(X509_OBJECT, (st)) +#define sk_X509_OBJECT_pop(st) SKM_sk_pop(X509_OBJECT, (st)) +#define sk_X509_OBJECT_sort(st) SKM_sk_sort(X509_OBJECT, (st)) +#define sk_X509_OBJECT_is_sorted(st) SKM_sk_is_sorted(X509_OBJECT, (st)) + +#define sk_X509_POLICY_DATA_new(st) SKM_sk_new(X509_POLICY_DATA, (st)) +#define sk_X509_POLICY_DATA_new_null() SKM_sk_new_null(X509_POLICY_DATA) +#define sk_X509_POLICY_DATA_free(st) SKM_sk_free(X509_POLICY_DATA, (st)) +#define sk_X509_POLICY_DATA_num(st) SKM_sk_num(X509_POLICY_DATA, (st)) +#define sk_X509_POLICY_DATA_value(st, i) SKM_sk_value(X509_POLICY_DATA, (st), (i)) +#define sk_X509_POLICY_DATA_set(st, i, val) SKM_sk_set(X509_POLICY_DATA, (st), (i), (val)) +#define sk_X509_POLICY_DATA_zero(st) SKM_sk_zero(X509_POLICY_DATA, (st)) +#define sk_X509_POLICY_DATA_push(st, val) SKM_sk_push(X509_POLICY_DATA, (st), (val)) +#define sk_X509_POLICY_DATA_unshift(st, val) SKM_sk_unshift(X509_POLICY_DATA, (st), (val)) +#define sk_X509_POLICY_DATA_find(st, val) SKM_sk_find(X509_POLICY_DATA, (st), (val)) +#define sk_X509_POLICY_DATA_find_ex(st, val) SKM_sk_find_ex(X509_POLICY_DATA, (st), (val)) +#define sk_X509_POLICY_DATA_delete(st, i) SKM_sk_delete(X509_POLICY_DATA, (st), (i)) +#define sk_X509_POLICY_DATA_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509_POLICY_DATA, (st), (ptr)) +#define sk_X509_POLICY_DATA_insert(st, val, i) SKM_sk_insert(X509_POLICY_DATA, (st), (val), (i)) +#define sk_X509_POLICY_DATA_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509_POLICY_DATA, (st), (cmp)) +#define sk_X509_POLICY_DATA_dup(st) SKM_sk_dup(X509_POLICY_DATA, st) +#define sk_X509_POLICY_DATA_pop_free(st, free_func) SKM_sk_pop_free(X509_POLICY_DATA, (st), (free_func)) +#define sk_X509_POLICY_DATA_shift(st) SKM_sk_shift(X509_POLICY_DATA, (st)) +#define sk_X509_POLICY_DATA_pop(st) SKM_sk_pop(X509_POLICY_DATA, (st)) +#define sk_X509_POLICY_DATA_sort(st) SKM_sk_sort(X509_POLICY_DATA, (st)) +#define sk_X509_POLICY_DATA_is_sorted(st) SKM_sk_is_sorted(X509_POLICY_DATA, (st)) + +#define sk_X509_POLICY_NODE_new(st) SKM_sk_new(X509_POLICY_NODE, (st)) +#define sk_X509_POLICY_NODE_new_null() SKM_sk_new_null(X509_POLICY_NODE) +#define sk_X509_POLICY_NODE_free(st) SKM_sk_free(X509_POLICY_NODE, (st)) +#define sk_X509_POLICY_NODE_num(st) SKM_sk_num(X509_POLICY_NODE, (st)) +#define sk_X509_POLICY_NODE_value(st, i) SKM_sk_value(X509_POLICY_NODE, (st), (i)) +#define sk_X509_POLICY_NODE_set(st, i, val) SKM_sk_set(X509_POLICY_NODE, (st), (i), (val)) +#define sk_X509_POLICY_NODE_zero(st) SKM_sk_zero(X509_POLICY_NODE, (st)) +#define sk_X509_POLICY_NODE_push(st, val) SKM_sk_push(X509_POLICY_NODE, (st), (val)) +#define sk_X509_POLICY_NODE_unshift(st, val) SKM_sk_unshift(X509_POLICY_NODE, (st), (val)) +#define sk_X509_POLICY_NODE_find(st, val) SKM_sk_find(X509_POLICY_NODE, (st), (val)) +#define sk_X509_POLICY_NODE_find_ex(st, val) SKM_sk_find_ex(X509_POLICY_NODE, (st), (val)) +#define sk_X509_POLICY_NODE_delete(st, i) SKM_sk_delete(X509_POLICY_NODE, (st), (i)) +#define sk_X509_POLICY_NODE_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509_POLICY_NODE, (st), (ptr)) +#define sk_X509_POLICY_NODE_insert(st, val, i) SKM_sk_insert(X509_POLICY_NODE, (st), (val), (i)) +#define sk_X509_POLICY_NODE_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509_POLICY_NODE, (st), (cmp)) +#define sk_X509_POLICY_NODE_dup(st) SKM_sk_dup(X509_POLICY_NODE, st) +#define sk_X509_POLICY_NODE_pop_free(st, free_func) SKM_sk_pop_free(X509_POLICY_NODE, (st), (free_func)) +#define sk_X509_POLICY_NODE_shift(st) SKM_sk_shift(X509_POLICY_NODE, (st)) +#define sk_X509_POLICY_NODE_pop(st) SKM_sk_pop(X509_POLICY_NODE, (st)) +#define sk_X509_POLICY_NODE_sort(st) SKM_sk_sort(X509_POLICY_NODE, (st)) +#define sk_X509_POLICY_NODE_is_sorted(st) SKM_sk_is_sorted(X509_POLICY_NODE, (st)) + +#define sk_X509_POLICY_REF_new(st) SKM_sk_new(X509_POLICY_REF, (st)) +#define sk_X509_POLICY_REF_new_null() SKM_sk_new_null(X509_POLICY_REF) +#define sk_X509_POLICY_REF_free(st) SKM_sk_free(X509_POLICY_REF, (st)) +#define sk_X509_POLICY_REF_num(st) SKM_sk_num(X509_POLICY_REF, (st)) +#define sk_X509_POLICY_REF_value(st, i) SKM_sk_value(X509_POLICY_REF, (st), (i)) +#define sk_X509_POLICY_REF_set(st, i, val) SKM_sk_set(X509_POLICY_REF, (st), (i), (val)) +#define sk_X509_POLICY_REF_zero(st) SKM_sk_zero(X509_POLICY_REF, (st)) +#define sk_X509_POLICY_REF_push(st, val) SKM_sk_push(X509_POLICY_REF, (st), (val)) +#define sk_X509_POLICY_REF_unshift(st, val) SKM_sk_unshift(X509_POLICY_REF, (st), (val)) +#define sk_X509_POLICY_REF_find(st, val) SKM_sk_find(X509_POLICY_REF, (st), (val)) +#define sk_X509_POLICY_REF_find_ex(st, val) SKM_sk_find_ex(X509_POLICY_REF, (st), (val)) +#define sk_X509_POLICY_REF_delete(st, i) SKM_sk_delete(X509_POLICY_REF, (st), (i)) +#define sk_X509_POLICY_REF_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509_POLICY_REF, (st), (ptr)) +#define sk_X509_POLICY_REF_insert(st, val, i) SKM_sk_insert(X509_POLICY_REF, (st), (val), (i)) +#define sk_X509_POLICY_REF_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509_POLICY_REF, (st), (cmp)) +#define sk_X509_POLICY_REF_dup(st) SKM_sk_dup(X509_POLICY_REF, st) +#define sk_X509_POLICY_REF_pop_free(st, free_func) SKM_sk_pop_free(X509_POLICY_REF, (st), (free_func)) +#define sk_X509_POLICY_REF_shift(st) SKM_sk_shift(X509_POLICY_REF, (st)) +#define sk_X509_POLICY_REF_pop(st) SKM_sk_pop(X509_POLICY_REF, (st)) +#define sk_X509_POLICY_REF_sort(st) SKM_sk_sort(X509_POLICY_REF, (st)) +#define sk_X509_POLICY_REF_is_sorted(st) SKM_sk_is_sorted(X509_POLICY_REF, (st)) + +#define sk_X509_PURPOSE_new(st) SKM_sk_new(X509_PURPOSE, (st)) +#define sk_X509_PURPOSE_new_null() SKM_sk_new_null(X509_PURPOSE) +#define sk_X509_PURPOSE_free(st) SKM_sk_free(X509_PURPOSE, (st)) +#define sk_X509_PURPOSE_num(st) SKM_sk_num(X509_PURPOSE, (st)) +#define sk_X509_PURPOSE_value(st, i) SKM_sk_value(X509_PURPOSE, (st), (i)) +#define sk_X509_PURPOSE_set(st, i, val) SKM_sk_set(X509_PURPOSE, (st), (i), (val)) +#define sk_X509_PURPOSE_zero(st) SKM_sk_zero(X509_PURPOSE, (st)) +#define sk_X509_PURPOSE_push(st, val) SKM_sk_push(X509_PURPOSE, (st), (val)) +#define sk_X509_PURPOSE_unshift(st, val) SKM_sk_unshift(X509_PURPOSE, (st), (val)) +#define sk_X509_PURPOSE_find(st, val) SKM_sk_find(X509_PURPOSE, (st), (val)) +#define sk_X509_PURPOSE_find_ex(st, val) SKM_sk_find_ex(X509_PURPOSE, (st), (val)) +#define sk_X509_PURPOSE_delete(st, i) SKM_sk_delete(X509_PURPOSE, (st), (i)) +#define sk_X509_PURPOSE_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509_PURPOSE, (st), (ptr)) +#define sk_X509_PURPOSE_insert(st, val, i) SKM_sk_insert(X509_PURPOSE, (st), (val), (i)) +#define sk_X509_PURPOSE_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509_PURPOSE, (st), (cmp)) +#define sk_X509_PURPOSE_dup(st) SKM_sk_dup(X509_PURPOSE, st) +#define sk_X509_PURPOSE_pop_free(st, free_func) SKM_sk_pop_free(X509_PURPOSE, (st), (free_func)) +#define sk_X509_PURPOSE_shift(st) SKM_sk_shift(X509_PURPOSE, (st)) +#define sk_X509_PURPOSE_pop(st) SKM_sk_pop(X509_PURPOSE, (st)) +#define sk_X509_PURPOSE_sort(st) SKM_sk_sort(X509_PURPOSE, (st)) +#define sk_X509_PURPOSE_is_sorted(st) SKM_sk_is_sorted(X509_PURPOSE, (st)) + +#define sk_X509_REVOKED_new(st) SKM_sk_new(X509_REVOKED, (st)) +#define sk_X509_REVOKED_new_null() SKM_sk_new_null(X509_REVOKED) +#define sk_X509_REVOKED_free(st) SKM_sk_free(X509_REVOKED, (st)) +#define sk_X509_REVOKED_num(st) SKM_sk_num(X509_REVOKED, (st)) +#define sk_X509_REVOKED_value(st, i) SKM_sk_value(X509_REVOKED, (st), (i)) +#define sk_X509_REVOKED_set(st, i, val) SKM_sk_set(X509_REVOKED, (st), (i), (val)) +#define sk_X509_REVOKED_zero(st) SKM_sk_zero(X509_REVOKED, (st)) +#define sk_X509_REVOKED_push(st, val) SKM_sk_push(X509_REVOKED, (st), (val)) +#define sk_X509_REVOKED_unshift(st, val) SKM_sk_unshift(X509_REVOKED, (st), (val)) +#define sk_X509_REVOKED_find(st, val) SKM_sk_find(X509_REVOKED, (st), (val)) +#define sk_X509_REVOKED_find_ex(st, val) SKM_sk_find_ex(X509_REVOKED, (st), (val)) +#define sk_X509_REVOKED_delete(st, i) SKM_sk_delete(X509_REVOKED, (st), (i)) +#define sk_X509_REVOKED_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509_REVOKED, (st), (ptr)) +#define sk_X509_REVOKED_insert(st, val, i) SKM_sk_insert(X509_REVOKED, (st), (val), (i)) +#define sk_X509_REVOKED_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509_REVOKED, (st), (cmp)) +#define sk_X509_REVOKED_dup(st) SKM_sk_dup(X509_REVOKED, st) +#define sk_X509_REVOKED_pop_free(st, free_func) SKM_sk_pop_free(X509_REVOKED, (st), (free_func)) +#define sk_X509_REVOKED_shift(st) SKM_sk_shift(X509_REVOKED, (st)) +#define sk_X509_REVOKED_pop(st) SKM_sk_pop(X509_REVOKED, (st)) +#define sk_X509_REVOKED_sort(st) SKM_sk_sort(X509_REVOKED, (st)) +#define sk_X509_REVOKED_is_sorted(st) SKM_sk_is_sorted(X509_REVOKED, (st)) + +#define sk_X509_TRUST_new(st) SKM_sk_new(X509_TRUST, (st)) +#define sk_X509_TRUST_new_null() SKM_sk_new_null(X509_TRUST) +#define sk_X509_TRUST_free(st) SKM_sk_free(X509_TRUST, (st)) +#define sk_X509_TRUST_num(st) SKM_sk_num(X509_TRUST, (st)) +#define sk_X509_TRUST_value(st, i) SKM_sk_value(X509_TRUST, (st), (i)) +#define sk_X509_TRUST_set(st, i, val) SKM_sk_set(X509_TRUST, (st), (i), (val)) +#define sk_X509_TRUST_zero(st) SKM_sk_zero(X509_TRUST, (st)) +#define sk_X509_TRUST_push(st, val) SKM_sk_push(X509_TRUST, (st), (val)) +#define sk_X509_TRUST_unshift(st, val) SKM_sk_unshift(X509_TRUST, (st), (val)) +#define sk_X509_TRUST_find(st, val) SKM_sk_find(X509_TRUST, (st), (val)) +#define sk_X509_TRUST_find_ex(st, val) SKM_sk_find_ex(X509_TRUST, (st), (val)) +#define sk_X509_TRUST_delete(st, i) SKM_sk_delete(X509_TRUST, (st), (i)) +#define sk_X509_TRUST_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509_TRUST, (st), (ptr)) +#define sk_X509_TRUST_insert(st, val, i) SKM_sk_insert(X509_TRUST, (st), (val), (i)) +#define sk_X509_TRUST_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509_TRUST, (st), (cmp)) +#define sk_X509_TRUST_dup(st) SKM_sk_dup(X509_TRUST, st) +#define sk_X509_TRUST_pop_free(st, free_func) SKM_sk_pop_free(X509_TRUST, (st), (free_func)) +#define sk_X509_TRUST_shift(st) SKM_sk_shift(X509_TRUST, (st)) +#define sk_X509_TRUST_pop(st) SKM_sk_pop(X509_TRUST, (st)) +#define sk_X509_TRUST_sort(st) SKM_sk_sort(X509_TRUST, (st)) +#define sk_X509_TRUST_is_sorted(st) SKM_sk_is_sorted(X509_TRUST, (st)) + +#define sk_X509_VERIFY_PARAM_new(st) SKM_sk_new(X509_VERIFY_PARAM, (st)) +#define sk_X509_VERIFY_PARAM_new_null() SKM_sk_new_null(X509_VERIFY_PARAM) +#define sk_X509_VERIFY_PARAM_free(st) SKM_sk_free(X509_VERIFY_PARAM, (st)) +#define sk_X509_VERIFY_PARAM_num(st) SKM_sk_num(X509_VERIFY_PARAM, (st)) +#define sk_X509_VERIFY_PARAM_value(st, i) SKM_sk_value(X509_VERIFY_PARAM, (st), (i)) +#define sk_X509_VERIFY_PARAM_set(st, i, val) SKM_sk_set(X509_VERIFY_PARAM, (st), (i), (val)) +#define sk_X509_VERIFY_PARAM_zero(st) SKM_sk_zero(X509_VERIFY_PARAM, (st)) +#define sk_X509_VERIFY_PARAM_push(st, val) SKM_sk_push(X509_VERIFY_PARAM, (st), (val)) +#define sk_X509_VERIFY_PARAM_unshift(st, val) SKM_sk_unshift(X509_VERIFY_PARAM, (st), (val)) +#define sk_X509_VERIFY_PARAM_find(st, val) SKM_sk_find(X509_VERIFY_PARAM, (st), (val)) +#define sk_X509_VERIFY_PARAM_find_ex(st, val) SKM_sk_find_ex(X509_VERIFY_PARAM, (st), (val)) +#define sk_X509_VERIFY_PARAM_delete(st, i) SKM_sk_delete(X509_VERIFY_PARAM, (st), (i)) +#define sk_X509_VERIFY_PARAM_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509_VERIFY_PARAM, (st), (ptr)) +#define sk_X509_VERIFY_PARAM_insert(st, val, i) SKM_sk_insert(X509_VERIFY_PARAM, (st), (val), (i)) +#define sk_X509_VERIFY_PARAM_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509_VERIFY_PARAM, (st), (cmp)) +#define sk_X509_VERIFY_PARAM_dup(st) SKM_sk_dup(X509_VERIFY_PARAM, st) +#define sk_X509_VERIFY_PARAM_pop_free(st, free_func) SKM_sk_pop_free(X509_VERIFY_PARAM, (st), (free_func)) +#define sk_X509_VERIFY_PARAM_shift(st) SKM_sk_shift(X509_VERIFY_PARAM, (st)) +#define sk_X509_VERIFY_PARAM_pop(st) SKM_sk_pop(X509_VERIFY_PARAM, (st)) +#define sk_X509_VERIFY_PARAM_sort(st) SKM_sk_sort(X509_VERIFY_PARAM, (st)) +#define sk_X509_VERIFY_PARAM_is_sorted(st) SKM_sk_is_sorted(X509_VERIFY_PARAM, (st)) + +#define d2i_ASN1_SET_OF_ACCESS_DESCRIPTION(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \ + SKM_ASN1_SET_OF_d2i(ACCESS_DESCRIPTION, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class)) +#define i2d_ASN1_SET_OF_ACCESS_DESCRIPTION(st, pp, i2d_func, ex_tag, ex_class, is_set) \ + SKM_ASN1_SET_OF_i2d(ACCESS_DESCRIPTION, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set)) +#define ASN1_seq_pack_ACCESS_DESCRIPTION(st, i2d_func, buf, len) \ + SKM_ASN1_seq_pack(ACCESS_DESCRIPTION, (st), (i2d_func), (buf), (len)) +#define ASN1_seq_unpack_ACCESS_DESCRIPTION(buf, len, d2i_func, free_func) \ + SKM_ASN1_seq_unpack(ACCESS_DESCRIPTION, (buf), (len), (d2i_func), (free_func)) + +#define d2i_ASN1_SET_OF_ASN1_INTEGER(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \ + SKM_ASN1_SET_OF_d2i(ASN1_INTEGER, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class)) +#define i2d_ASN1_SET_OF_ASN1_INTEGER(st, pp, i2d_func, ex_tag, ex_class, is_set) \ + SKM_ASN1_SET_OF_i2d(ASN1_INTEGER, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set)) +#define ASN1_seq_pack_ASN1_INTEGER(st, i2d_func, buf, len) \ + SKM_ASN1_seq_pack(ASN1_INTEGER, (st), (i2d_func), (buf), (len)) +#define ASN1_seq_unpack_ASN1_INTEGER(buf, len, d2i_func, free_func) \ + SKM_ASN1_seq_unpack(ASN1_INTEGER, (buf), (len), (d2i_func), (free_func)) + +#define d2i_ASN1_SET_OF_ASN1_OBJECT(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \ + SKM_ASN1_SET_OF_d2i(ASN1_OBJECT, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class)) +#define i2d_ASN1_SET_OF_ASN1_OBJECT(st, pp, i2d_func, ex_tag, ex_class, is_set) \ + SKM_ASN1_SET_OF_i2d(ASN1_OBJECT, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set)) +#define ASN1_seq_pack_ASN1_OBJECT(st, i2d_func, buf, len) \ + SKM_ASN1_seq_pack(ASN1_OBJECT, (st), (i2d_func), (buf), (len)) +#define ASN1_seq_unpack_ASN1_OBJECT(buf, len, d2i_func, free_func) \ + SKM_ASN1_seq_unpack(ASN1_OBJECT, (buf), (len), (d2i_func), (free_func)) + +#define d2i_ASN1_SET_OF_ASN1_TYPE(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \ + SKM_ASN1_SET_OF_d2i(ASN1_TYPE, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class)) +#define i2d_ASN1_SET_OF_ASN1_TYPE(st, pp, i2d_func, ex_tag, ex_class, is_set) \ + SKM_ASN1_SET_OF_i2d(ASN1_TYPE, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set)) +#define ASN1_seq_pack_ASN1_TYPE(st, i2d_func, buf, len) \ + SKM_ASN1_seq_pack(ASN1_TYPE, (st), (i2d_func), (buf), (len)) +#define ASN1_seq_unpack_ASN1_TYPE(buf, len, d2i_func, free_func) \ + SKM_ASN1_seq_unpack(ASN1_TYPE, (buf), (len), (d2i_func), (free_func)) + +#define d2i_ASN1_SET_OF_DIST_POINT(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \ + SKM_ASN1_SET_OF_d2i(DIST_POINT, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class)) +#define i2d_ASN1_SET_OF_DIST_POINT(st, pp, i2d_func, ex_tag, ex_class, is_set) \ + SKM_ASN1_SET_OF_i2d(DIST_POINT, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set)) +#define ASN1_seq_pack_DIST_POINT(st, i2d_func, buf, len) \ + SKM_ASN1_seq_pack(DIST_POINT, (st), (i2d_func), (buf), (len)) +#define ASN1_seq_unpack_DIST_POINT(buf, len, d2i_func, free_func) \ + SKM_ASN1_seq_unpack(DIST_POINT, (buf), (len), (d2i_func), (free_func)) + +#define d2i_ASN1_SET_OF_GENERAL_NAME(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \ + SKM_ASN1_SET_OF_d2i(GENERAL_NAME, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class)) +#define i2d_ASN1_SET_OF_GENERAL_NAME(st, pp, i2d_func, ex_tag, ex_class, is_set) \ + SKM_ASN1_SET_OF_i2d(GENERAL_NAME, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set)) +#define ASN1_seq_pack_GENERAL_NAME(st, i2d_func, buf, len) \ + SKM_ASN1_seq_pack(GENERAL_NAME, (st), (i2d_func), (buf), (len)) +#define ASN1_seq_unpack_GENERAL_NAME(buf, len, d2i_func, free_func) \ + SKM_ASN1_seq_unpack(GENERAL_NAME, (buf), (len), (d2i_func), (free_func)) + +#define d2i_ASN1_SET_OF_OCSP_ONEREQ(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \ + SKM_ASN1_SET_OF_d2i(OCSP_ONEREQ, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class)) +#define i2d_ASN1_SET_OF_OCSP_ONEREQ(st, pp, i2d_func, ex_tag, ex_class, is_set) \ + SKM_ASN1_SET_OF_i2d(OCSP_ONEREQ, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set)) +#define ASN1_seq_pack_OCSP_ONEREQ(st, i2d_func, buf, len) \ + SKM_ASN1_seq_pack(OCSP_ONEREQ, (st), (i2d_func), (buf), (len)) +#define ASN1_seq_unpack_OCSP_ONEREQ(buf, len, d2i_func, free_func) \ + SKM_ASN1_seq_unpack(OCSP_ONEREQ, (buf), (len), (d2i_func), (free_func)) + +#define d2i_ASN1_SET_OF_OCSP_SINGLERESP(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \ + SKM_ASN1_SET_OF_d2i(OCSP_SINGLERESP, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class)) +#define i2d_ASN1_SET_OF_OCSP_SINGLERESP(st, pp, i2d_func, ex_tag, ex_class, is_set) \ + SKM_ASN1_SET_OF_i2d(OCSP_SINGLERESP, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set)) +#define ASN1_seq_pack_OCSP_SINGLERESP(st, i2d_func, buf, len) \ + SKM_ASN1_seq_pack(OCSP_SINGLERESP, (st), (i2d_func), (buf), (len)) +#define ASN1_seq_unpack_OCSP_SINGLERESP(buf, len, d2i_func, free_func) \ + SKM_ASN1_seq_unpack(OCSP_SINGLERESP, (buf), (len), (d2i_func), (free_func)) + +#define d2i_ASN1_SET_OF_PKCS12_SAFEBAG(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \ + SKM_ASN1_SET_OF_d2i(PKCS12_SAFEBAG, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class)) +#define i2d_ASN1_SET_OF_PKCS12_SAFEBAG(st, pp, i2d_func, ex_tag, ex_class, is_set) \ + SKM_ASN1_SET_OF_i2d(PKCS12_SAFEBAG, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set)) +#define ASN1_seq_pack_PKCS12_SAFEBAG(st, i2d_func, buf, len) \ + SKM_ASN1_seq_pack(PKCS12_SAFEBAG, (st), (i2d_func), (buf), (len)) +#define ASN1_seq_unpack_PKCS12_SAFEBAG(buf, len, d2i_func, free_func) \ + SKM_ASN1_seq_unpack(PKCS12_SAFEBAG, (buf), (len), (d2i_func), (free_func)) + +#define d2i_ASN1_SET_OF_PKCS7(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \ + SKM_ASN1_SET_OF_d2i(PKCS7, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class)) +#define i2d_ASN1_SET_OF_PKCS7(st, pp, i2d_func, ex_tag, ex_class, is_set) \ + SKM_ASN1_SET_OF_i2d(PKCS7, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set)) +#define ASN1_seq_pack_PKCS7(st, i2d_func, buf, len) \ + SKM_ASN1_seq_pack(PKCS7, (st), (i2d_func), (buf), (len)) +#define ASN1_seq_unpack_PKCS7(buf, len, d2i_func, free_func) \ + SKM_ASN1_seq_unpack(PKCS7, (buf), (len), (d2i_func), (free_func)) + +#define d2i_ASN1_SET_OF_PKCS7_RECIP_INFO(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \ + SKM_ASN1_SET_OF_d2i(PKCS7_RECIP_INFO, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class)) +#define i2d_ASN1_SET_OF_PKCS7_RECIP_INFO(st, pp, i2d_func, ex_tag, ex_class, is_set) \ + SKM_ASN1_SET_OF_i2d(PKCS7_RECIP_INFO, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set)) +#define ASN1_seq_pack_PKCS7_RECIP_INFO(st, i2d_func, buf, len) \ + SKM_ASN1_seq_pack(PKCS7_RECIP_INFO, (st), (i2d_func), (buf), (len)) +#define ASN1_seq_unpack_PKCS7_RECIP_INFO(buf, len, d2i_func, free_func) \ + SKM_ASN1_seq_unpack(PKCS7_RECIP_INFO, (buf), (len), (d2i_func), (free_func)) + +#define d2i_ASN1_SET_OF_PKCS7_SIGNER_INFO(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \ + SKM_ASN1_SET_OF_d2i(PKCS7_SIGNER_INFO, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class)) +#define i2d_ASN1_SET_OF_PKCS7_SIGNER_INFO(st, pp, i2d_func, ex_tag, ex_class, is_set) \ + SKM_ASN1_SET_OF_i2d(PKCS7_SIGNER_INFO, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set)) +#define ASN1_seq_pack_PKCS7_SIGNER_INFO(st, i2d_func, buf, len) \ + SKM_ASN1_seq_pack(PKCS7_SIGNER_INFO, (st), (i2d_func), (buf), (len)) +#define ASN1_seq_unpack_PKCS7_SIGNER_INFO(buf, len, d2i_func, free_func) \ + SKM_ASN1_seq_unpack(PKCS7_SIGNER_INFO, (buf), (len), (d2i_func), (free_func)) + +#define d2i_ASN1_SET_OF_POLICYINFO(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \ + SKM_ASN1_SET_OF_d2i(POLICYINFO, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class)) +#define i2d_ASN1_SET_OF_POLICYINFO(st, pp, i2d_func, ex_tag, ex_class, is_set) \ + SKM_ASN1_SET_OF_i2d(POLICYINFO, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set)) +#define ASN1_seq_pack_POLICYINFO(st, i2d_func, buf, len) \ + SKM_ASN1_seq_pack(POLICYINFO, (st), (i2d_func), (buf), (len)) +#define ASN1_seq_unpack_POLICYINFO(buf, len, d2i_func, free_func) \ + SKM_ASN1_seq_unpack(POLICYINFO, (buf), (len), (d2i_func), (free_func)) + +#define d2i_ASN1_SET_OF_POLICYQUALINFO(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \ + SKM_ASN1_SET_OF_d2i(POLICYQUALINFO, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class)) +#define i2d_ASN1_SET_OF_POLICYQUALINFO(st, pp, i2d_func, ex_tag, ex_class, is_set) \ + SKM_ASN1_SET_OF_i2d(POLICYQUALINFO, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set)) +#define ASN1_seq_pack_POLICYQUALINFO(st, i2d_func, buf, len) \ + SKM_ASN1_seq_pack(POLICYQUALINFO, (st), (i2d_func), (buf), (len)) +#define ASN1_seq_unpack_POLICYQUALINFO(buf, len, d2i_func, free_func) \ + SKM_ASN1_seq_unpack(POLICYQUALINFO, (buf), (len), (d2i_func), (free_func)) + +#define d2i_ASN1_SET_OF_SXNETID(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \ + SKM_ASN1_SET_OF_d2i(SXNETID, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class)) +#define i2d_ASN1_SET_OF_SXNETID(st, pp, i2d_func, ex_tag, ex_class, is_set) \ + SKM_ASN1_SET_OF_i2d(SXNETID, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set)) +#define ASN1_seq_pack_SXNETID(st, i2d_func, buf, len) \ + SKM_ASN1_seq_pack(SXNETID, (st), (i2d_func), (buf), (len)) +#define ASN1_seq_unpack_SXNETID(buf, len, d2i_func, free_func) \ + SKM_ASN1_seq_unpack(SXNETID, (buf), (len), (d2i_func), (free_func)) + +#define d2i_ASN1_SET_OF_X509(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \ + SKM_ASN1_SET_OF_d2i(X509, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class)) +#define i2d_ASN1_SET_OF_X509(st, pp, i2d_func, ex_tag, ex_class, is_set) \ + SKM_ASN1_SET_OF_i2d(X509, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set)) +#define ASN1_seq_pack_X509(st, i2d_func, buf, len) \ + SKM_ASN1_seq_pack(X509, (st), (i2d_func), (buf), (len)) +#define ASN1_seq_unpack_X509(buf, len, d2i_func, free_func) \ + SKM_ASN1_seq_unpack(X509, (buf), (len), (d2i_func), (free_func)) + +#define d2i_ASN1_SET_OF_X509_ALGOR(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \ + SKM_ASN1_SET_OF_d2i(X509_ALGOR, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class)) +#define i2d_ASN1_SET_OF_X509_ALGOR(st, pp, i2d_func, ex_tag, ex_class, is_set) \ + SKM_ASN1_SET_OF_i2d(X509_ALGOR, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set)) +#define ASN1_seq_pack_X509_ALGOR(st, i2d_func, buf, len) \ + SKM_ASN1_seq_pack(X509_ALGOR, (st), (i2d_func), (buf), (len)) +#define ASN1_seq_unpack_X509_ALGOR(buf, len, d2i_func, free_func) \ + SKM_ASN1_seq_unpack(X509_ALGOR, (buf), (len), (d2i_func), (free_func)) + +#define d2i_ASN1_SET_OF_X509_ATTRIBUTE(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \ + SKM_ASN1_SET_OF_d2i(X509_ATTRIBUTE, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class)) +#define i2d_ASN1_SET_OF_X509_ATTRIBUTE(st, pp, i2d_func, ex_tag, ex_class, is_set) \ + SKM_ASN1_SET_OF_i2d(X509_ATTRIBUTE, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set)) +#define ASN1_seq_pack_X509_ATTRIBUTE(st, i2d_func, buf, len) \ + SKM_ASN1_seq_pack(X509_ATTRIBUTE, (st), (i2d_func), (buf), (len)) +#define ASN1_seq_unpack_X509_ATTRIBUTE(buf, len, d2i_func, free_func) \ + SKM_ASN1_seq_unpack(X509_ATTRIBUTE, (buf), (len), (d2i_func), (free_func)) + +#define d2i_ASN1_SET_OF_X509_CRL(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \ + SKM_ASN1_SET_OF_d2i(X509_CRL, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class)) +#define i2d_ASN1_SET_OF_X509_CRL(st, pp, i2d_func, ex_tag, ex_class, is_set) \ + SKM_ASN1_SET_OF_i2d(X509_CRL, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set)) +#define ASN1_seq_pack_X509_CRL(st, i2d_func, buf, len) \ + SKM_ASN1_seq_pack(X509_CRL, (st), (i2d_func), (buf), (len)) +#define ASN1_seq_unpack_X509_CRL(buf, len, d2i_func, free_func) \ + SKM_ASN1_seq_unpack(X509_CRL, (buf), (len), (d2i_func), (free_func)) + +#define d2i_ASN1_SET_OF_X509_EXTENSION(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \ + SKM_ASN1_SET_OF_d2i(X509_EXTENSION, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class)) +#define i2d_ASN1_SET_OF_X509_EXTENSION(st, pp, i2d_func, ex_tag, ex_class, is_set) \ + SKM_ASN1_SET_OF_i2d(X509_EXTENSION, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set)) +#define ASN1_seq_pack_X509_EXTENSION(st, i2d_func, buf, len) \ + SKM_ASN1_seq_pack(X509_EXTENSION, (st), (i2d_func), (buf), (len)) +#define ASN1_seq_unpack_X509_EXTENSION(buf, len, d2i_func, free_func) \ + SKM_ASN1_seq_unpack(X509_EXTENSION, (buf), (len), (d2i_func), (free_func)) + +#define d2i_ASN1_SET_OF_X509_NAME_ENTRY(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \ + SKM_ASN1_SET_OF_d2i(X509_NAME_ENTRY, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class)) +#define i2d_ASN1_SET_OF_X509_NAME_ENTRY(st, pp, i2d_func, ex_tag, ex_class, is_set) \ + SKM_ASN1_SET_OF_i2d(X509_NAME_ENTRY, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set)) +#define ASN1_seq_pack_X509_NAME_ENTRY(st, i2d_func, buf, len) \ + SKM_ASN1_seq_pack(X509_NAME_ENTRY, (st), (i2d_func), (buf), (len)) +#define ASN1_seq_unpack_X509_NAME_ENTRY(buf, len, d2i_func, free_func) \ + SKM_ASN1_seq_unpack(X509_NAME_ENTRY, (buf), (len), (d2i_func), (free_func)) + +#define d2i_ASN1_SET_OF_X509_REVOKED(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \ + SKM_ASN1_SET_OF_d2i(X509_REVOKED, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class)) +#define i2d_ASN1_SET_OF_X509_REVOKED(st, pp, i2d_func, ex_tag, ex_class, is_set) \ + SKM_ASN1_SET_OF_i2d(X509_REVOKED, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set)) +#define ASN1_seq_pack_X509_REVOKED(st, i2d_func, buf, len) \ + SKM_ASN1_seq_pack(X509_REVOKED, (st), (i2d_func), (buf), (len)) +#define ASN1_seq_unpack_X509_REVOKED(buf, len, d2i_func, free_func) \ + SKM_ASN1_seq_unpack(X509_REVOKED, (buf), (len), (d2i_func), (free_func)) + +#define PKCS12_decrypt_d2i_PKCS12_SAFEBAG(algor, d2i_func, free_func, pass, passlen, oct, seq) \ + SKM_PKCS12_decrypt_d2i(PKCS12_SAFEBAG, (algor), (d2i_func), (free_func), (pass), (passlen), (oct), (seq)) + +#define PKCS12_decrypt_d2i_PKCS7(algor, d2i_func, free_func, pass, passlen, oct, seq) \ + SKM_PKCS12_decrypt_d2i(PKCS7, (algor), (d2i_func), (free_func), (pass), (passlen), (oct), (seq)) +/* End of util/mkstack.pl block, you may now edit :-) */ + +#endif /* !defined HEADER_SAFESTACK_H */ diff --git a/lib_tls/include/openssl/sha.h b/lib_tls/include/openssl/sha.h new file mode 100644 index 000000000..eed44d7f9 --- /dev/null +++ b/lib_tls/include/openssl/sha.h @@ -0,0 +1,200 @@ +/* crypto/sha/sha.h */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#ifndef HEADER_SHA_H +#define HEADER_SHA_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(OPENSSL_NO_SHA) || (defined(OPENSSL_NO_SHA0) && defined(OPENSSL_NO_SHA1)) +#error SHA is disabled. +#endif + +#if defined(OPENSSL_FIPS) +#define FIPS_SHA_SIZE_T size_t +#endif + +/* + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + * ! SHA_LONG has to be at least 32 bits wide. If it's wider, then ! + * ! SHA_LONG_LOG2 has to be defined along. ! + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + */ + +#if defined(OPENSSL_SYS_WIN16) || defined(__LP32__) +#define SHA_LONG unsigned long +#elif defined(OPENSSL_SYS_CRAY) || defined(__ILP64__) +#define SHA_LONG unsigned long +#define SHA_LONG_LOG2 3 +#else +#define SHA_LONG unsigned int +#endif + +#define SHA_LBLOCK 16 +#define SHA_CBLOCK (SHA_LBLOCK*4) /* SHA treats input data as a + * contiguous array of 32 bit + * wide big-endian values. */ +#define SHA_LAST_BLOCK (SHA_CBLOCK-8) +#define SHA_DIGEST_LENGTH 20 + +typedef struct SHAstate_st + { + SHA_LONG h0,h1,h2,h3,h4; + SHA_LONG Nl,Nh; + SHA_LONG data[SHA_LBLOCK]; + unsigned int num; + } SHA_CTX; + +#ifndef OPENSSL_NO_SHA0 +int SHA_Init(SHA_CTX *c); +int SHA_Update(SHA_CTX *c, const void *data, size_t len); +int SHA_Final(unsigned char *md, SHA_CTX *c); +unsigned char *SHA(const unsigned char *d, size_t n, unsigned char *md); +void SHA_Transform(SHA_CTX *c, const unsigned char *data); +#endif +#ifndef OPENSSL_NO_SHA1 +int SHA1_Init(SHA_CTX *c); +int SHA1_Update(SHA_CTX *c, const void *data, size_t len); +int SHA1_Final(unsigned char *md, SHA_CTX *c); +unsigned char *SHA1(const unsigned char *d, size_t n, unsigned char *md); +void SHA1_Transform(SHA_CTX *c, const unsigned char *data); +#endif + +#define SHA256_CBLOCK (SHA_LBLOCK*4) /* SHA-256 treats input data as a + * contiguous array of 32 bit + * wide big-endian values. */ +#define SHA224_DIGEST_LENGTH 28 +#define SHA256_DIGEST_LENGTH 32 + +typedef struct SHA256state_st + { + SHA_LONG h[8]; + SHA_LONG Nl,Nh; + SHA_LONG data[SHA_LBLOCK]; + unsigned int num,md_len; + } SHA256_CTX; + +#ifndef OPENSSL_NO_SHA256 +int SHA224_Init(SHA256_CTX *c); +int SHA224_Update(SHA256_CTX *c, const void *data, size_t len); +int SHA224_Final(unsigned char *md, SHA256_CTX *c); +unsigned char *SHA224(const unsigned char *d, size_t n,unsigned char *md); +int SHA256_Init(SHA256_CTX *c); +int SHA256_Update(SHA256_CTX *c, const void *data, size_t len); +int SHA256_Final(unsigned char *md, SHA256_CTX *c); +unsigned char *SHA256(const unsigned char *d, size_t n,unsigned char *md); +void SHA256_Transform(SHA256_CTX *c, const unsigned char *data); +#endif + +#define SHA384_DIGEST_LENGTH 48 +#define SHA512_DIGEST_LENGTH 64 + +#ifndef OPENSSL_NO_SHA512 +/* + * Unlike 32-bit digest algorithms, SHA-512 *relies* on SHA_LONG64 + * being exactly 64-bit wide. See Implementation Notes in sha512.c + * for further details. + */ +#define SHA512_CBLOCK (SHA_LBLOCK*8) /* SHA-512 treats input data as a + * contiguous array of 64 bit + * wide big-endian values. */ +#if (defined(_WIN32) || defined(_WIN64)) && !defined(__MINGW32__) +#define SHA_LONG64 unsigned __int64 +#define U64(C) C##UI64 +#elif defined(__arch64__) +#define SHA_LONG64 unsigned long +#define U64(C) C##UL +#else +#define SHA_LONG64 unsigned long long +#define U64(C) C##ULL +#endif + +typedef struct SHA512state_st + { + SHA_LONG64 h[8]; + SHA_LONG64 Nl,Nh; + union { + SHA_LONG64 d[SHA_LBLOCK]; + unsigned char p[SHA512_CBLOCK]; + } u; + unsigned int num,md_len; + } SHA512_CTX; +#endif + +#ifndef OPENSSL_NO_SHA512 +int SHA384_Init(SHA512_CTX *c); +int SHA384_Update(SHA512_CTX *c, const void *data, size_t len); +int SHA384_Final(unsigned char *md, SHA512_CTX *c); +unsigned char *SHA384(const unsigned char *d, size_t n,unsigned char *md); +int SHA512_Init(SHA512_CTX *c); +int SHA512_Update(SHA512_CTX *c, const void *data, size_t len); +int SHA512_Final(unsigned char *md, SHA512_CTX *c); +unsigned char *SHA512(const unsigned char *d, size_t n,unsigned char *md); +void SHA512_Transform(SHA512_CTX *c, const unsigned char *data); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_tls/include/openssl/ssl.h b/lib_tls/include/openssl/ssl.h new file mode 100644 index 000000000..6df921f3c --- /dev/null +++ b/lib_tls/include/openssl/ssl.h @@ -0,0 +1,2065 @@ +/* ssl/ssl.h */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* ==================================================================== + * Copyright (c) 1998-2006 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * ECC cipher suite support in OpenSSL originally developed by + * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project. + */ + +#ifndef HEADER_SSL_H +#define HEADER_SSL_H + +#include + +#ifndef OPENSSL_NO_COMP +#include +#endif +#ifndef OPENSSL_NO_BIO +#include +#endif +#ifndef OPENSSL_NO_DEPRECATED +#ifndef OPENSSL_NO_X509 +#include +#endif +#include +#include +#include +#endif +#include +#include + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* SSLeay version number for ASN.1 encoding of the session information */ +/* Version 0 - initial version + * Version 1 - added the optional peer certificate + */ +#define SSL_SESSION_ASN1_VERSION 0x0001 + +/* text strings for the ciphers */ +#define SSL_TXT_NULL_WITH_MD5 SSL2_TXT_NULL_WITH_MD5 +#define SSL_TXT_RC4_128_WITH_MD5 SSL2_TXT_RC4_128_WITH_MD5 +#define SSL_TXT_RC4_128_EXPORT40_WITH_MD5 SSL2_TXT_RC4_128_EXPORT40_WITH_MD5 +#define SSL_TXT_RC2_128_CBC_WITH_MD5 SSL2_TXT_RC2_128_CBC_WITH_MD5 +#define SSL_TXT_RC2_128_CBC_EXPORT40_WITH_MD5 SSL2_TXT_RC2_128_CBC_EXPORT40_WITH_MD5 +#define SSL_TXT_IDEA_128_CBC_WITH_MD5 SSL2_TXT_IDEA_128_CBC_WITH_MD5 +#define SSL_TXT_DES_64_CBC_WITH_MD5 SSL2_TXT_DES_64_CBC_WITH_MD5 +#define SSL_TXT_DES_64_CBC_WITH_SHA SSL2_TXT_DES_64_CBC_WITH_SHA +#define SSL_TXT_DES_192_EDE3_CBC_WITH_MD5 SSL2_TXT_DES_192_EDE3_CBC_WITH_MD5 +#define SSL_TXT_DES_192_EDE3_CBC_WITH_SHA SSL2_TXT_DES_192_EDE3_CBC_WITH_SHA + +/* VRS Additional Kerberos5 entries + */ +#define SSL_TXT_KRB5_DES_64_CBC_SHA SSL3_TXT_KRB5_DES_64_CBC_SHA +#define SSL_TXT_KRB5_DES_192_CBC3_SHA SSL3_TXT_KRB5_DES_192_CBC3_SHA +#define SSL_TXT_KRB5_RC4_128_SHA SSL3_TXT_KRB5_RC4_128_SHA +#define SSL_TXT_KRB5_IDEA_128_CBC_SHA SSL3_TXT_KRB5_IDEA_128_CBC_SHA +#define SSL_TXT_KRB5_DES_64_CBC_MD5 SSL3_TXT_KRB5_DES_64_CBC_MD5 +#define SSL_TXT_KRB5_DES_192_CBC3_MD5 SSL3_TXT_KRB5_DES_192_CBC3_MD5 +#define SSL_TXT_KRB5_RC4_128_MD5 SSL3_TXT_KRB5_RC4_128_MD5 +#define SSL_TXT_KRB5_IDEA_128_CBC_MD5 SSL3_TXT_KRB5_IDEA_128_CBC_MD5 + +#define SSL_TXT_KRB5_DES_40_CBC_SHA SSL3_TXT_KRB5_DES_40_CBC_SHA +#define SSL_TXT_KRB5_RC2_40_CBC_SHA SSL3_TXT_KRB5_RC2_40_CBC_SHA +#define SSL_TXT_KRB5_RC4_40_SHA SSL3_TXT_KRB5_RC4_40_SHA +#define SSL_TXT_KRB5_DES_40_CBC_MD5 SSL3_TXT_KRB5_DES_40_CBC_MD5 +#define SSL_TXT_KRB5_RC2_40_CBC_MD5 SSL3_TXT_KRB5_RC2_40_CBC_MD5 +#define SSL_TXT_KRB5_RC4_40_MD5 SSL3_TXT_KRB5_RC4_40_MD5 + +#define SSL_TXT_KRB5_DES_40_CBC_SHA SSL3_TXT_KRB5_DES_40_CBC_SHA +#define SSL_TXT_KRB5_DES_40_CBC_MD5 SSL3_TXT_KRB5_DES_40_CBC_MD5 +#define SSL_TXT_KRB5_DES_64_CBC_SHA SSL3_TXT_KRB5_DES_64_CBC_SHA +#define SSL_TXT_KRB5_DES_64_CBC_MD5 SSL3_TXT_KRB5_DES_64_CBC_MD5 +#define SSL_TXT_KRB5_DES_192_CBC3_SHA SSL3_TXT_KRB5_DES_192_CBC3_SHA +#define SSL_TXT_KRB5_DES_192_CBC3_MD5 SSL3_TXT_KRB5_DES_192_CBC3_MD5 +#define SSL_MAX_KRB5_PRINCIPAL_LENGTH 256 + +#define SSL_MAX_SSL_SESSION_ID_LENGTH 32 +#define SSL_MAX_SID_CTX_LENGTH 32 + +#define SSL_MIN_RSA_MODULUS_LENGTH_IN_BYTES (512/8) +#define SSL_MAX_KEY_ARG_LENGTH 8 +#define SSL_MAX_MASTER_KEY_LENGTH 48 + +/* These are used to specify which ciphers to use and not to use */ +#define SSL_TXT_LOW "LOW" +#define SSL_TXT_MEDIUM "MEDIUM" +#define SSL_TXT_HIGH "HIGH" +#define SSL_TXT_kFZA "kFZA" +#define SSL_TXT_aFZA "aFZA" +#define SSL_TXT_eFZA "eFZA" +#define SSL_TXT_FZA "FZA" + +#define SSL_TXT_aNULL "aNULL" +#define SSL_TXT_eNULL "eNULL" +#define SSL_TXT_NULL "NULL" + +#define SSL_TXT_kKRB5 "kKRB5" +#define SSL_TXT_aKRB5 "aKRB5" +#define SSL_TXT_KRB5 "KRB5" + +#define SSL_TXT_kRSA "kRSA" +#define SSL_TXT_kDHr "kDHr" +#define SSL_TXT_kDHd "kDHd" +#define SSL_TXT_kEDH "kEDH" +#define SSL_TXT_aRSA "aRSA" +#define SSL_TXT_aDSS "aDSS" +#define SSL_TXT_aDH "aDH" +#define SSL_TXT_DSS "DSS" +#define SSL_TXT_DH "DH" +#define SSL_TXT_EDH "EDH" +#define SSL_TXT_ADH "ADH" +#define SSL_TXT_RSA "RSA" +#define SSL_TXT_DES "DES" +#define SSL_TXT_3DES "3DES" +#define SSL_TXT_RC4 "RC4" +#define SSL_TXT_RC2 "RC2" +#define SSL_TXT_IDEA "IDEA" +#define SSL_TXT_SEED "SEED" +#define SSL_TXT_AES "AES" +#define SSL_TXT_CAMELLIA "CAMELLIA" +#define SSL_TXT_MD5 "MD5" +#define SSL_TXT_SHA1 "SHA1" +#define SSL_TXT_SHA "SHA" +#define SSL_TXT_EXP "EXP" +#define SSL_TXT_EXPORT "EXPORT" +#define SSL_TXT_EXP40 "EXPORT40" +#define SSL_TXT_EXP56 "EXPORT56" +#define SSL_TXT_SSLV2 "SSLv2" +#define SSL_TXT_SSLV3 "SSLv3" +#define SSL_TXT_TLSV1 "TLSv1" +#define SSL_TXT_ALL "ALL" +#define SSL_TXT_ECC "ECCdraft" /* ECC ciphersuites are not yet official */ + +/* + * COMPLEMENTOF* definitions. These identifiers are used to (de-select) + * ciphers normally not being used. + * Example: "RC4" will activate all ciphers using RC4 including ciphers + * without authentication, which would normally disabled by DEFAULT (due + * the "!ADH" being part of default). Therefore "RC4:!COMPLEMENTOFDEFAULT" + * will make sure that it is also disabled in the specific selection. + * COMPLEMENTOF* identifiers are portable between version, as adjustments + * to the default cipher setup will also be included here. + * + * COMPLEMENTOFDEFAULT does not experience the same special treatment that + * DEFAULT gets, as only selection is being done and no sorting as needed + * for DEFAULT. + */ +#define SSL_TXT_CMPALL "COMPLEMENTOFALL" +#define SSL_TXT_CMPDEF "COMPLEMENTOFDEFAULT" + +/* The following cipher list is used by default. + * It also is substituted when an application-defined cipher list string + * starts with 'DEFAULT'. */ +#define SSL_DEFAULT_CIPHER_LIST "AES:ALL:!aNULL:!eNULL:+RC4:@STRENGTH" /* low priority for RC4 */ + +/* Used in SSL_set_shutdown()/SSL_get_shutdown(); */ +#define SSL_SENT_SHUTDOWN 1 +#define SSL_RECEIVED_SHUTDOWN 2 + +#ifdef __cplusplus +} +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if (defined(OPENSSL_NO_RSA) || defined(OPENSSL_NO_MD5)) && !defined(OPENSSL_NO_SSL2) +#define OPENSSL_NO_SSL2 +#endif + +#define SSL_FILETYPE_ASN1 X509_FILETYPE_ASN1 +#define SSL_FILETYPE_PEM X509_FILETYPE_PEM + +/* This is needed to stop compilers complaining about the + * 'struct ssl_st *' function parameters used to prototype callbacks + * in SSL_CTX. */ +typedef struct ssl_st *ssl_crock_st; + +/* used to hold info on the particular ciphers used */ +typedef struct ssl_cipher_st + { + int valid; + const char *name; /* text name */ + unsigned long id; /* id, 4 bytes, first is version */ + unsigned long algorithms; /* what ciphers are used */ + unsigned long algo_strength; /* strength and export flags */ + unsigned long algorithm2; /* Extra flags */ + int strength_bits; /* Number of bits really used */ + int alg_bits; /* Number of bits for algorithm */ + unsigned long mask; /* used for matching */ + unsigned long mask_strength; /* also used for matching */ + } SSL_CIPHER; + +DECLARE_STACK_OF(SSL_CIPHER) + +typedef struct ssl_st SSL; +typedef struct ssl_ctx_st SSL_CTX; + +/* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */ +typedef struct ssl_method_st + { + int version; + int (*ssl_new)(SSL *s); + void (*ssl_clear)(SSL *s); + void (*ssl_free)(SSL *s); + int (*ssl_accept)(SSL *s); + int (*ssl_connect)(SSL *s); + int (*ssl_read)(SSL *s,void *buf,int len); + int (*ssl_peek)(SSL *s,void *buf,int len); + int (*ssl_write)(SSL *s,const void *buf,int len); + int (*ssl_shutdown)(SSL *s); + int (*ssl_renegotiate)(SSL *s); + int (*ssl_renegotiate_check)(SSL *s); + long (*ssl_get_message)(SSL *s, int st1, int stn, int mt, long + max, int *ok); + int (*ssl_read_bytes)(SSL *s, int type, unsigned char *buf, int len, + int peek); + int (*ssl_write_bytes)(SSL *s, int type, const void *buf_, int len); + int (*ssl_dispatch_alert)(SSL *s); + long (*ssl_ctrl)(SSL *s,int cmd,long larg,void *parg); + long (*ssl_ctx_ctrl)(SSL_CTX *ctx,int cmd,long larg,void *parg); + SSL_CIPHER *(*get_cipher_by_char)(const unsigned char *ptr); + int (*put_cipher_by_char)(const SSL_CIPHER *cipher,unsigned char *ptr); + int (*ssl_pending)(const SSL *s); + int (*num_ciphers)(void); + SSL_CIPHER *(*get_cipher)(unsigned ncipher); + struct ssl_method_st *(*get_ssl_method)(int version); + long (*get_timeout)(void); + struct ssl3_enc_method *ssl3_enc; /* Extra SSLv3/TLS stuff */ + int (*ssl_version)(void); + long (*ssl_callback_ctrl)(SSL *s, int cb_id, void (*fp)(void)); + long (*ssl_ctx_callback_ctrl)(SSL_CTX *s, int cb_id, void (*fp)(void)); + } SSL_METHOD; + +/* Lets make this into an ASN.1 type structure as follows + * SSL_SESSION_ID ::= SEQUENCE { + * version INTEGER, -- structure version number + * SSLversion INTEGER, -- SSL version number + * Cipher OCTET_STRING, -- the 3 byte cipher ID + * Session_ID OCTET_STRING, -- the Session ID + * Master_key OCTET_STRING, -- the master key + * KRB5_principal OCTET_STRING -- optional Kerberos principal + * Key_Arg [ 0 ] IMPLICIT OCTET_STRING, -- the optional Key argument + * Time [ 1 ] EXPLICIT INTEGER, -- optional Start Time + * Timeout [ 2 ] EXPLICIT INTEGER, -- optional Timeout ins seconds + * Peer [ 3 ] EXPLICIT X509, -- optional Peer Certificate + * Session_ID_context [ 4 ] EXPLICIT OCTET_STRING, -- the Session ID context + * Verify_result [ 5 ] EXPLICIT INTEGER -- X509_V_... code for `Peer' + * Compression [6] IMPLICIT ASN1_OBJECT -- compression OID XXXXX + * } + * Look in ssl/ssl_asn1.c for more details + * I'm using EXPLICIT tags so I can read the damn things using asn1parse :-). + */ +typedef struct ssl_session_st + { + int ssl_version; /* what ssl version session info is + * being kept in here? */ + + /* only really used in SSLv2 */ + unsigned int key_arg_length; + unsigned char key_arg[SSL_MAX_KEY_ARG_LENGTH]; + int master_key_length; + unsigned char master_key[SSL_MAX_MASTER_KEY_LENGTH]; + /* session_id - valid? */ + unsigned int session_id_length; + unsigned char session_id[SSL_MAX_SSL_SESSION_ID_LENGTH]; + /* this is used to determine whether the session is being reused in + * the appropriate context. It is up to the application to set this, + * via SSL_new */ + unsigned int sid_ctx_length; + unsigned char sid_ctx[SSL_MAX_SID_CTX_LENGTH]; + +#ifndef OPENSSL_NO_KRB5 + unsigned int krb5_client_princ_len; + unsigned char krb5_client_princ[SSL_MAX_KRB5_PRINCIPAL_LENGTH]; +#endif /* OPENSSL_NO_KRB5 */ + + int not_resumable; + + /* The cert is the certificate used to establish this connection */ + struct sess_cert_st /* SESS_CERT */ *sess_cert; + + /* This is the cert for the other end. + * On clients, it will be the same as sess_cert->peer_key->x509 + * (the latter is not enough as sess_cert is not retained + * in the external representation of sessions, see ssl_asn1.c). */ + X509 *peer; + /* when app_verify_callback accepts a session where the peer's certificate + * is not ok, we must remember the error for session reuse: */ + long verify_result; /* only for servers */ + + int references; + long timeout; + long time; + + int compress_meth; /* Need to lookup the method */ + + SSL_CIPHER *cipher; + unsigned long cipher_id; /* when ASN.1 loaded, this + * needs to be used to load + * the 'cipher' structure */ + + STACK_OF(SSL_CIPHER) *ciphers; /* shared ciphers? */ + + CRYPTO_EX_DATA ex_data; /* application specific data */ + + /* These are used to make removal of session-ids more + * efficient and to implement a maximum cache size. */ + struct ssl_session_st *prev,*next; +#ifndef OPENSSL_NO_TLSEXT + char *tlsext_hostname; + /* RFC4507 info */ + unsigned char *tlsext_tick; /* Session ticket */ + size_t tlsext_ticklen; /* Session ticket length */ + long tlsext_tick_lifetime_hint; /* Session lifetime hint in seconds */ +#endif + } SSL_SESSION; + + +#define SSL_OP_MICROSOFT_SESS_ID_BUG 0x00000001L +#define SSL_OP_NETSCAPE_CHALLENGE_BUG 0x00000002L +#define SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG 0x00000008L +#define SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG 0x00000010L +#define SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER 0x00000020L +#define SSL_OP_MSIE_SSLV2_RSA_PADDING 0x00000040L /* no effect since 0.9.7h and 0.9.8b */ +#define SSL_OP_SSLEAY_080_CLIENT_DH_BUG 0x00000080L +#define SSL_OP_TLS_D5_BUG 0x00000100L +#define SSL_OP_TLS_BLOCK_PADDING_BUG 0x00000200L + +/* Disable SSL 3.0/TLS 1.0 CBC vulnerability workaround that was added + * in OpenSSL 0.9.6d. Usually (depending on the application protocol) + * the workaround is not needed. Unfortunately some broken SSL/TLS + * implementations cannot handle it at all, which is why we include + * it in SSL_OP_ALL. */ +#define SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS 0x00000800L /* added in 0.9.6e */ + +/* SSL_OP_ALL: various bug workarounds that should be rather harmless. + * This used to be 0x000FFFFFL before 0.9.7. */ +#define SSL_OP_ALL 0x00000FFFL + +/* DTLS options */ +#define SSL_OP_NO_QUERY_MTU 0x00001000L +/* Turn on Cookie Exchange (on relevant for servers) */ +#define SSL_OP_COOKIE_EXCHANGE 0x00002000L +/* Don't use RFC4507 ticket extension */ +#define SSL_OP_NO_TICKET 0x00004000L + +/* As server, disallow session resumption on renegotiation */ +#define SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION 0x00010000L +/* If set, always create a new key when using tmp_ecdh parameters */ +#define SSL_OP_SINGLE_ECDH_USE 0x00080000L +/* If set, always create a new key when using tmp_dh parameters */ +#define SSL_OP_SINGLE_DH_USE 0x00100000L +/* Set to always use the tmp_rsa key when doing RSA operations, + * even when this violates protocol specs */ +#define SSL_OP_EPHEMERAL_RSA 0x00200000L +/* Set on servers to choose the cipher according to the server's + * preferences */ +#define SSL_OP_CIPHER_SERVER_PREFERENCE 0x00400000L +/* If set, a server will allow a client to issue a SSLv3.0 version number + * as latest version supported in the premaster secret, even when TLSv1.0 + * (version 3.1) was announced in the client hello. Normally this is + * forbidden to prevent version rollback attacks. */ +#define SSL_OP_TLS_ROLLBACK_BUG 0x00800000L + +#define SSL_OP_NO_SSLv2 0x01000000L +#define SSL_OP_NO_SSLv3 0x02000000L +#define SSL_OP_NO_TLSv1 0x04000000L + +/* The next flag deliberately changes the ciphertest, this is a check + * for the PKCS#1 attack */ +#define SSL_OP_PKCS1_CHECK_1 0x08000000L +#define SSL_OP_PKCS1_CHECK_2 0x10000000L +#define SSL_OP_NETSCAPE_CA_DN_BUG 0x20000000L +#define SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG 0x40000000L + + +/* Allow SSL_write(..., n) to return r with 0 < r < n (i.e. report success + * when just a single record has been written): */ +#define SSL_MODE_ENABLE_PARTIAL_WRITE 0x00000001L +/* Make it possible to retry SSL_write() with changed buffer location + * (buffer contents must stay the same!); this is not the default to avoid + * the misconception that non-blocking SSL_write() behaves like + * non-blocking write(): */ +#define SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER 0x00000002L +/* Never bother the application with retries if the transport + * is blocking: */ +#define SSL_MODE_AUTO_RETRY 0x00000004L +/* Don't attempt to automatically build certificate chain */ +#define SSL_MODE_NO_AUTO_CHAIN 0x00000008L + + +/* Note: SSL[_CTX]_set_{options,mode} use |= op on the previous value, + * they cannot be used to clear bits. */ + +#define SSL_CTX_set_options(ctx,op) \ + SSL_CTX_ctrl((ctx),SSL_CTRL_OPTIONS,(op),NULL) +#define SSL_CTX_get_options(ctx) \ + SSL_CTX_ctrl((ctx),SSL_CTRL_OPTIONS,0,NULL) +#define SSL_set_options(ssl,op) \ + SSL_ctrl((ssl),SSL_CTRL_OPTIONS,(op),NULL) +#define SSL_get_options(ssl) \ + SSL_ctrl((ssl),SSL_CTRL_OPTIONS,0,NULL) + +#define SSL_CTX_set_mode(ctx,op) \ + SSL_CTX_ctrl((ctx),SSL_CTRL_MODE,(op),NULL) +#define SSL_CTX_get_mode(ctx) \ + SSL_CTX_ctrl((ctx),SSL_CTRL_MODE,0,NULL) +#define SSL_set_mode(ssl,op) \ + SSL_ctrl((ssl),SSL_CTRL_MODE,(op),NULL) +#define SSL_get_mode(ssl) \ + SSL_ctrl((ssl),SSL_CTRL_MODE,0,NULL) +#define SSL_set_mtu(ssl, mtu) \ + SSL_ctrl((ssl),SSL_CTRL_SET_MTU,(mtu),NULL) + + +void SSL_CTX_set_msg_callback(SSL_CTX *ctx, void (*cb)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg)); +void SSL_set_msg_callback(SSL *ssl, void (*cb)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg)); +#define SSL_CTX_set_msg_callback_arg(ctx, arg) SSL_CTX_ctrl((ctx), SSL_CTRL_SET_MSG_CALLBACK_ARG, 0, (arg)) +#define SSL_set_msg_callback_arg(ssl, arg) SSL_ctrl((ssl), SSL_CTRL_SET_MSG_CALLBACK_ARG, 0, (arg)) + + + +#if defined(OPENSSL_SYS_MSDOS) && !defined(OPENSSL_SYS_WIN32) +#define SSL_MAX_CERT_LIST_DEFAULT 1024*30 /* 30k max cert list :-) */ +#else +#define SSL_MAX_CERT_LIST_DEFAULT 1024*100 /* 100k max cert list :-) */ +#endif + +#define SSL_SESSION_CACHE_MAX_SIZE_DEFAULT (1024*20) + +/* This callback type is used inside SSL_CTX, SSL, and in the functions that set + * them. It is used to override the generation of SSL/TLS session IDs in a + * server. Return value should be zero on an error, non-zero to proceed. Also, + * callbacks should themselves check if the id they generate is unique otherwise + * the SSL handshake will fail with an error - callbacks can do this using the + * 'ssl' value they're passed by; + * SSL_has_matching_session_id(ssl, id, *id_len) + * The length value passed in is set at the maximum size the session ID can be. + * In SSLv2 this is 16 bytes, whereas SSLv3/TLSv1 it is 32 bytes. The callback + * can alter this length to be less if desired, but under SSLv2 session IDs are + * supposed to be fixed at 16 bytes so the id will be padded after the callback + * returns in this case. It is also an error for the callback to set the size to + * zero. */ +typedef int (*GEN_SESSION_CB)(const SSL *ssl, unsigned char *id, + unsigned int *id_len); + +typedef struct ssl_comp_st + { + int id; + const char *name; +#ifndef OPENSSL_NO_COMP + COMP_METHOD *method; +#else + char *method; +#endif + } SSL_COMP; + +DECLARE_STACK_OF(SSL_COMP) + +struct ssl_ctx_st + { + SSL_METHOD *method; + + STACK_OF(SSL_CIPHER) *cipher_list; + /* same as above but sorted for lookup */ + STACK_OF(SSL_CIPHER) *cipher_list_by_id; + + struct x509_store_st /* X509_STORE */ *cert_store; + struct lhash_st /* LHASH */ *sessions; /* a set of SSL_SESSIONs */ + /* Most session-ids that will be cached, default is + * SSL_SESSION_CACHE_MAX_SIZE_DEFAULT. 0 is unlimited. */ + unsigned long session_cache_size; + struct ssl_session_st *session_cache_head; + struct ssl_session_st *session_cache_tail; + + /* This can have one of 2 values, ored together, + * SSL_SESS_CACHE_CLIENT, + * SSL_SESS_CACHE_SERVER, + * Default is SSL_SESSION_CACHE_SERVER, which means only + * SSL_accept which cache SSL_SESSIONS. */ + int session_cache_mode; + + /* If timeout is not 0, it is the default timeout value set + * when SSL_new() is called. This has been put in to make + * life easier to set things up */ + long session_timeout; + + /* If this callback is not null, it will be called each + * time a session id is added to the cache. If this function + * returns 1, it means that the callback will do a + * SSL_SESSION_free() when it has finished using it. Otherwise, + * on 0, it means the callback has finished with it. + * If remove_session_cb is not null, it will be called when + * a session-id is removed from the cache. After the call, + * OpenSSL will SSL_SESSION_free() it. */ + int (*new_session_cb)(struct ssl_st *ssl,SSL_SESSION *sess); + void (*remove_session_cb)(struct ssl_ctx_st *ctx,SSL_SESSION *sess); + SSL_SESSION *(*get_session_cb)(struct ssl_st *ssl, + unsigned char *data,int len,int *copy); + + struct + { + int sess_connect; /* SSL new conn - started */ + int sess_connect_renegotiate;/* SSL reneg - requested */ + int sess_connect_good; /* SSL new conne/reneg - finished */ + int sess_accept; /* SSL new accept - started */ + int sess_accept_renegotiate;/* SSL reneg - requested */ + int sess_accept_good; /* SSL accept/reneg - finished */ + int sess_miss; /* session lookup misses */ + int sess_timeout; /* reuse attempt on timeouted session */ + int sess_cache_full; /* session removed due to full cache */ + int sess_hit; /* session reuse actually done */ + int sess_cb_hit; /* session-id that was not + * in the cache was + * passed back via the callback. This + * indicates that the application is + * supplying session-id's from other + * processes - spooky :-) */ + } stats; + + int references; + + /* if defined, these override the X509_verify_cert() calls */ + int (*app_verify_callback)(X509_STORE_CTX *, void *); + void *app_verify_arg; + /* before OpenSSL 0.9.7, 'app_verify_arg' was ignored + * ('app_verify_callback' was called with just one argument) */ + + /* Default password callback. */ + pem_password_cb *default_passwd_callback; + + /* Default password callback user data. */ + void *default_passwd_callback_userdata; + + /* get client cert callback */ + int (*client_cert_cb)(SSL *ssl, X509 **x509, EVP_PKEY **pkey); + + /* cookie generate callback */ + int (*app_gen_cookie_cb)(SSL *ssl, unsigned char *cookie, + unsigned int *cookie_len); + + /* verify cookie callback */ + int (*app_verify_cookie_cb)(SSL *ssl, unsigned char *cookie, + unsigned int cookie_len); + + CRYPTO_EX_DATA ex_data; + + const EVP_MD *rsa_md5;/* For SSLv2 - name is 'ssl2-md5' */ + const EVP_MD *md5; /* For SSLv3/TLSv1 'ssl3-md5' */ + const EVP_MD *sha1; /* For SSLv3/TLSv1 'ssl3->sha1' */ + + STACK_OF(X509) *extra_certs; + STACK_OF(SSL_COMP) *comp_methods; /* stack of SSL_COMP, SSLv3/TLSv1 */ + + + /* Default values used when no per-SSL value is defined follow */ + + void (*info_callback)(const SSL *ssl,int type,int val); /* used if SSL's info_callback is NULL */ + + /* what we put in client cert requests */ + STACK_OF(X509_NAME) *client_CA; + + + /* Default values to use in SSL structures follow (these are copied by SSL_new) */ + + unsigned long options; + unsigned long mode; + long max_cert_list; + + struct cert_st /* CERT */ *cert; + int read_ahead; + + /* callback that allows applications to peek at protocol messages */ + void (*msg_callback)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg); + void *msg_callback_arg; + + int verify_mode; + unsigned int sid_ctx_length; + unsigned char sid_ctx[SSL_MAX_SID_CTX_LENGTH]; + int (*default_verify_callback)(int ok,X509_STORE_CTX *ctx); /* called 'verify_callback' in the SSL */ + + /* Default generate session ID callback. */ + GEN_SESSION_CB generate_session_id; + + X509_VERIFY_PARAM *param; + +#if 0 + int purpose; /* Purpose setting */ + int trust; /* Trust setting */ +#endif + + int quiet_shutdown; + +#ifndef OPENSSL_NO_TLSEXT + /* TLS extensions servername callback */ + int (*tlsext_servername_callback)(SSL*, int *, void *); + void *tlsext_servername_arg; + /* RFC 4507 session ticket keys */ + unsigned char tlsext_tick_key_name[16]; + unsigned char tlsext_tick_hmac_key[16]; + unsigned char tlsext_tick_aes_key[16]; + /* Callback to support customisation of ticket key setting */ + int (*tlsext_ticket_key_cb)(SSL *ssl, + unsigned char *name, unsigned char *iv, + EVP_CIPHER_CTX *ectx, + HMAC_CTX *hctx, int enc); + + /* certificate status request info */ + /* Callback for status request */ + int (*tlsext_status_cb)(SSL *ssl, void *arg); + void *tlsext_status_arg; +#endif + + }; + +#define SSL_SESS_CACHE_OFF 0x0000 +#define SSL_SESS_CACHE_CLIENT 0x0001 +#define SSL_SESS_CACHE_SERVER 0x0002 +#define SSL_SESS_CACHE_BOTH (SSL_SESS_CACHE_CLIENT|SSL_SESS_CACHE_SERVER) +#define SSL_SESS_CACHE_NO_AUTO_CLEAR 0x0080 +/* enough comments already ... see SSL_CTX_set_session_cache_mode(3) */ +#define SSL_SESS_CACHE_NO_INTERNAL_LOOKUP 0x0100 +#define SSL_SESS_CACHE_NO_INTERNAL_STORE 0x0200 +#define SSL_SESS_CACHE_NO_INTERNAL \ + (SSL_SESS_CACHE_NO_INTERNAL_LOOKUP|SSL_SESS_CACHE_NO_INTERNAL_STORE) + + struct lhash_st *SSL_CTX_sessions(SSL_CTX *ctx); +#define SSL_CTX_sess_number(ctx) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_NUMBER,0,NULL) +#define SSL_CTX_sess_connect(ctx) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_CONNECT,0,NULL) +#define SSL_CTX_sess_connect_good(ctx) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_CONNECT_GOOD,0,NULL) +#define SSL_CTX_sess_connect_renegotiate(ctx) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_CONNECT_RENEGOTIATE,0,NULL) +#define SSL_CTX_sess_accept(ctx) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_ACCEPT,0,NULL) +#define SSL_CTX_sess_accept_renegotiate(ctx) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_ACCEPT_RENEGOTIATE,0,NULL) +#define SSL_CTX_sess_accept_good(ctx) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_ACCEPT_GOOD,0,NULL) +#define SSL_CTX_sess_hits(ctx) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_HIT,0,NULL) +#define SSL_CTX_sess_cb_hits(ctx) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_CB_HIT,0,NULL) +#define SSL_CTX_sess_misses(ctx) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_MISSES,0,NULL) +#define SSL_CTX_sess_timeouts(ctx) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_TIMEOUTS,0,NULL) +#define SSL_CTX_sess_cache_full(ctx) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_CACHE_FULL,0,NULL) + +void SSL_CTX_sess_set_new_cb(SSL_CTX *ctx, int (*new_session_cb)(struct ssl_st *ssl,SSL_SESSION *sess)); +int (*SSL_CTX_sess_get_new_cb(SSL_CTX *ctx))(struct ssl_st *ssl, SSL_SESSION *sess); +void SSL_CTX_sess_set_remove_cb(SSL_CTX *ctx, void (*remove_session_cb)(struct ssl_ctx_st *ctx,SSL_SESSION *sess)); +void (*SSL_CTX_sess_get_remove_cb(SSL_CTX *ctx))(struct ssl_ctx_st *ctx, SSL_SESSION *sess); +void SSL_CTX_sess_set_get_cb(SSL_CTX *ctx, SSL_SESSION *(*get_session_cb)(struct ssl_st *ssl, unsigned char *data,int len,int *copy)); +SSL_SESSION *(*SSL_CTX_sess_get_get_cb(SSL_CTX *ctx))(struct ssl_st *ssl, unsigned char *Data, int len, int *copy); +void SSL_CTX_set_info_callback(SSL_CTX *ctx, void (*cb)(const SSL *ssl,int type,int val)); +void (*SSL_CTX_get_info_callback(SSL_CTX *ctx))(const SSL *ssl,int type,int val); +void SSL_CTX_set_client_cert_cb(SSL_CTX *ctx, int (*client_cert_cb)(SSL *ssl, X509 **x509, EVP_PKEY **pkey)); +int (*SSL_CTX_get_client_cert_cb(SSL_CTX *ctx))(SSL *ssl, X509 **x509, EVP_PKEY **pkey); +void SSL_CTX_set_cookie_generate_cb(SSL_CTX *ctx, int (*app_gen_cookie_cb)(SSL *ssl, unsigned char *cookie, unsigned int *cookie_len)); +void SSL_CTX_set_cookie_verify_cb(SSL_CTX *ctx, int (*app_verify_cookie_cb)(SSL *ssl, unsigned char *cookie, unsigned int cookie_len)); + +#define SSL_NOTHING 1 +#define SSL_WRITING 2 +#define SSL_READING 3 +#define SSL_X509_LOOKUP 4 + +/* These will only be used when doing non-blocking IO */ +#define SSL_want_nothing(s) (SSL_want(s) == SSL_NOTHING) +#define SSL_want_read(s) (SSL_want(s) == SSL_READING) +#define SSL_want_write(s) (SSL_want(s) == SSL_WRITING) +#define SSL_want_x509_lookup(s) (SSL_want(s) == SSL_X509_LOOKUP) + +struct ssl_st + { + /* protocol version + * (one of SSL2_VERSION, SSL3_VERSION, TLS1_VERSION, DTLS1_VERSION) + */ + int version; + int type; /* SSL_ST_CONNECT or SSL_ST_ACCEPT */ + + SSL_METHOD *method; /* SSLv3 */ + + /* There are 2 BIO's even though they are normally both the + * same. This is so data can be read and written to different + * handlers */ + +#ifndef OPENSSL_NO_BIO + BIO *rbio; /* used by SSL_read */ + BIO *wbio; /* used by SSL_write */ + BIO *bbio; /* used during session-id reuse to concatenate + * messages */ +#else + char *rbio; /* used by SSL_read */ + char *wbio; /* used by SSL_write */ + char *bbio; +#endif + /* This holds a variable that indicates what we were doing + * when a 0 or -1 is returned. This is needed for + * non-blocking IO so we know what request needs re-doing when + * in SSL_accept or SSL_connect */ + int rwstate; + + /* true when we are actually in SSL_accept() or SSL_connect() */ + int in_handshake; + int (*handshake_func)(SSL *); + + /* Imagine that here's a boolean member "init" that is + * switched as soon as SSL_set_{accept/connect}_state + * is called for the first time, so that "state" and + * "handshake_func" are properly initialized. But as + * handshake_func is == 0 until then, we use this + * test instead of an "init" member. + */ + + int server; /* are we the server side? - mostly used by SSL_clear*/ + + int new_session;/* 1 if we are to use a new session. + * 2 if we are a server and are inside a handshake + * (i.e. not just sending a HelloRequest) + * NB: For servers, the 'new' session may actually be a previously + * cached session or even the previous session unless + * SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION is set */ + int quiet_shutdown;/* don't send shutdown packets */ + int shutdown; /* we have shut things down, 0x01 sent, 0x02 + * for received */ + int state; /* where we are */ + int rstate; /* where we are when reading */ + + BUF_MEM *init_buf; /* buffer used during init */ + void *init_msg; /* pointer to handshake message body, set by ssl3_get_message() */ + int init_num; /* amount read/written */ + int init_off; /* amount read/written */ + + /* used internally to point at a raw packet */ + unsigned char *packet; + unsigned int packet_length; + + struct ssl2_state_st *s2; /* SSLv2 variables */ + struct ssl3_state_st *s3; /* SSLv3 variables */ + struct dtls1_state_st *d1; /* DTLSv1 variables */ + + int read_ahead; /* Read as many input bytes as possible + * (for non-blocking reads) */ + + /* callback that allows applications to peek at protocol messages */ + void (*msg_callback)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg); + void *msg_callback_arg; + + int hit; /* reusing a previous session */ + + X509_VERIFY_PARAM *param; + +#if 0 + int purpose; /* Purpose setting */ + int trust; /* Trust setting */ +#endif + + /* crypto */ + STACK_OF(SSL_CIPHER) *cipher_list; + STACK_OF(SSL_CIPHER) *cipher_list_by_id; + + /* These are the ones being used, the ones in SSL_SESSION are + * the ones to be 'copied' into these ones */ + + EVP_CIPHER_CTX *enc_read_ctx; /* cryptographic state */ + const EVP_MD *read_hash; /* used for mac generation */ +#ifndef OPENSSL_NO_COMP + COMP_CTX *expand; /* uncompress */ +#else + char *expand; +#endif + + EVP_CIPHER_CTX *enc_write_ctx; /* cryptographic state */ + const EVP_MD *write_hash; /* used for mac generation */ +#ifndef OPENSSL_NO_COMP + COMP_CTX *compress; /* compression */ +#else + char *compress; +#endif + + /* session info */ + + /* client cert? */ + /* This is used to hold the server certificate used */ + struct cert_st /* CERT */ *cert; + + /* the session_id_context is used to ensure sessions are only reused + * in the appropriate context */ + unsigned int sid_ctx_length; + unsigned char sid_ctx[SSL_MAX_SID_CTX_LENGTH]; + + /* This can also be in the session once a session is established */ + SSL_SESSION *session; + + /* Default generate session ID callback. */ + GEN_SESSION_CB generate_session_id; + + /* Used in SSL2 and SSL3 */ + int verify_mode; /* 0 don't care about verify failure. + * 1 fail if verify fails */ + int (*verify_callback)(int ok,X509_STORE_CTX *ctx); /* fail if callback returns 0 */ + + void (*info_callback)(const SSL *ssl,int type,int val); /* optional informational callback */ + + int error; /* error bytes to be written */ + int error_code; /* actual code */ + +#ifndef OPENSSL_NO_KRB5 + KSSL_CTX *kssl_ctx; /* Kerberos 5 context */ +#endif /* OPENSSL_NO_KRB5 */ + + SSL_CTX *ctx; + /* set this flag to 1 and a sleep(1) is put into all SSL_read() + * and SSL_write() calls, good for nbio debuging :-) */ + int debug; + + /* extra application data */ + long verify_result; + CRYPTO_EX_DATA ex_data; + + /* for server side, keep the list of CA_dn we can use */ + STACK_OF(X509_NAME) *client_CA; + + int references; + unsigned long options; /* protocol behaviour */ + unsigned long mode; /* API behaviour */ + long max_cert_list; + int first_packet; + int client_version; /* what was passed, used for + * SSLv3/TLS rollback check */ +#ifndef OPENSSL_NO_TLSEXT + /* TLS extension debug callback */ + void (*tlsext_debug_cb)(SSL *s, int client_server, int type, + unsigned char *data, int len, + void *arg); + void *tlsext_debug_arg; + char *tlsext_hostname; + int servername_done; /* no further mod of servername + 0 : call the servername extension callback. + 1 : prepare 2, allow last ack just after in server callback. + 2 : don't call servername callback, no ack in server hello + */ + /* certificate status request info */ + /* Status type or -1 if no status type */ + int tlsext_status_type; + /* Expect OCSP CertificateStatus message */ + int tlsext_status_expected; + /* OCSP status request only */ + STACK_OF(OCSP_RESPID) *tlsext_ocsp_ids; + X509_EXTENSIONS *tlsext_ocsp_exts; + /* OCSP response received or to be sent */ + unsigned char *tlsext_ocsp_resp; + int tlsext_ocsp_resplen; + + /* RFC4507 session ticket expected to be received or sent */ + int tlsext_ticket_expected; + SSL_CTX * initial_ctx; /* initial ctx, used to store sessions */ +#define session_ctx initial_ctx +#else +#define session_ctx ctx +#endif + }; + +#ifdef __cplusplus +} +#endif + +#include +#include +#include /* This is mostly sslv3 with a few tweaks */ +#include /* Datagram TLS */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* compatibility */ +#define SSL_set_app_data(s,arg) (SSL_set_ex_data(s,0,(char *)arg)) +#define SSL_get_app_data(s) (SSL_get_ex_data(s,0)) +#define SSL_SESSION_set_app_data(s,a) (SSL_SESSION_set_ex_data(s,0,(char *)a)) +#define SSL_SESSION_get_app_data(s) (SSL_SESSION_get_ex_data(s,0)) +#define SSL_CTX_get_app_data(ctx) (SSL_CTX_get_ex_data(ctx,0)) +#define SSL_CTX_set_app_data(ctx,arg) (SSL_CTX_set_ex_data(ctx,0,(char *)arg)) + +/* The following are the possible values for ssl->state are are + * used to indicate where we are up to in the SSL connection establishment. + * The macros that follow are about the only things you should need to use + * and even then, only when using non-blocking IO. + * It can also be useful to work out where you were when the connection + * failed */ + +#define SSL_ST_CONNECT 0x1000 +#define SSL_ST_ACCEPT 0x2000 +#define SSL_ST_MASK 0x0FFF +#define SSL_ST_INIT (SSL_ST_CONNECT|SSL_ST_ACCEPT) +#define SSL_ST_BEFORE 0x4000 +#define SSL_ST_OK 0x03 +#define SSL_ST_RENEGOTIATE (0x04|SSL_ST_INIT) + +#define SSL_CB_LOOP 0x01 +#define SSL_CB_EXIT 0x02 +#define SSL_CB_READ 0x04 +#define SSL_CB_WRITE 0x08 +#define SSL_CB_ALERT 0x4000 /* used in callback */ +#define SSL_CB_READ_ALERT (SSL_CB_ALERT|SSL_CB_READ) +#define SSL_CB_WRITE_ALERT (SSL_CB_ALERT|SSL_CB_WRITE) +#define SSL_CB_ACCEPT_LOOP (SSL_ST_ACCEPT|SSL_CB_LOOP) +#define SSL_CB_ACCEPT_EXIT (SSL_ST_ACCEPT|SSL_CB_EXIT) +#define SSL_CB_CONNECT_LOOP (SSL_ST_CONNECT|SSL_CB_LOOP) +#define SSL_CB_CONNECT_EXIT (SSL_ST_CONNECT|SSL_CB_EXIT) +#define SSL_CB_HANDSHAKE_START 0x10 +#define SSL_CB_HANDSHAKE_DONE 0x20 + +/* Is the SSL_connection established? */ +#define SSL_get_state(a) SSL_state(a) +#define SSL_is_init_finished(a) (SSL_state(a) == SSL_ST_OK) +#define SSL_in_init(a) (SSL_state(a)&SSL_ST_INIT) +#define SSL_in_before(a) (SSL_state(a)&SSL_ST_BEFORE) +#define SSL_in_connect_init(a) (SSL_state(a)&SSL_ST_CONNECT) +#define SSL_in_accept_init(a) (SSL_state(a)&SSL_ST_ACCEPT) + +/* The following 2 states are kept in ssl->rstate when reads fail, + * you should not need these */ +#define SSL_ST_READ_HEADER 0xF0 +#define SSL_ST_READ_BODY 0xF1 +#define SSL_ST_READ_DONE 0xF2 + +/* Obtain latest Finished message + * -- that we sent (SSL_get_finished) + * -- that we expected from peer (SSL_get_peer_finished). + * Returns length (0 == no Finished so far), copies up to 'count' bytes. */ +size_t SSL_get_finished(const SSL *s, void *buf, size_t count); +size_t SSL_get_peer_finished(const SSL *s, void *buf, size_t count); + +/* use either SSL_VERIFY_NONE or SSL_VERIFY_PEER, the last 2 options + * are 'ored' with SSL_VERIFY_PEER if they are desired */ +#define SSL_VERIFY_NONE 0x00 +#define SSL_VERIFY_PEER 0x01 +#define SSL_VERIFY_FAIL_IF_NO_PEER_CERT 0x02 +#define SSL_VERIFY_CLIENT_ONCE 0x04 + +#define OpenSSL_add_ssl_algorithms() SSL_library_init() +#define SSLeay_add_ssl_algorithms() SSL_library_init() + +/* this is for backward compatibility */ +#if 0 /* NEW_SSLEAY */ +#define SSL_CTX_set_default_verify(a,b,c) SSL_CTX_set_verify(a,b,c) +#define SSL_set_pref_cipher(c,n) SSL_set_cipher_list(c,n) +#define SSL_add_session(a,b) SSL_CTX_add_session((a),(b)) +#define SSL_remove_session(a,b) SSL_CTX_remove_session((a),(b)) +#define SSL_flush_sessions(a,b) SSL_CTX_flush_sessions((a),(b)) +#endif +/* More backward compatibility */ +#define SSL_get_cipher(s) \ + SSL_CIPHER_get_name(SSL_get_current_cipher(s)) +#define SSL_get_cipher_bits(s,np) \ + SSL_CIPHER_get_bits(SSL_get_current_cipher(s),np) +#define SSL_get_cipher_version(s) \ + SSL_CIPHER_get_version(SSL_get_current_cipher(s)) +#define SSL_get_cipher_name(s) \ + SSL_CIPHER_get_name(SSL_get_current_cipher(s)) +#define SSL_get_time(a) SSL_SESSION_get_time(a) +#define SSL_set_time(a,b) SSL_SESSION_set_time((a),(b)) +#define SSL_get_timeout(a) SSL_SESSION_get_timeout(a) +#define SSL_set_timeout(a,b) SSL_SESSION_set_timeout((a),(b)) + +#if 1 /*SSLEAY_MACROS*/ +#define d2i_SSL_SESSION_bio(bp,s_id) ASN1_d2i_bio_of(SSL_SESSION,SSL_SESSION_new,d2i_SSL_SESSION,bp,s_id) +#define i2d_SSL_SESSION_bio(bp,s_id) ASN1_i2d_bio_of(SSL_SESSION,i2d_SSL_SESSION,bp,s_id) +#define PEM_read_SSL_SESSION(fp,x,cb,u) (SSL_SESSION *)PEM_ASN1_read( \ + (char *(*)())d2i_SSL_SESSION,PEM_STRING_SSL_SESSION,fp,(char **)x,cb,u) +#define PEM_read_bio_SSL_SESSION(bp,x,cb,u) PEM_ASN1_read_bio_of(SSL_SESSION,d2i_SSL_SESSION,PEM_STRING_SSL_SESSION,bp,x,cb,u) +#define PEM_write_SSL_SESSION(fp,x) \ + PEM_ASN1_write((int (*)())i2d_SSL_SESSION, \ + PEM_STRING_SSL_SESSION,fp, (char *)x, NULL,NULL,0,NULL,NULL) +#define PEM_write_bio_SSL_SESSION(bp,x) \ + PEM_ASN1_write_bio_of(SSL_SESSION,i2d_SSL_SESSION,PEM_STRING_SSL_SESSION,bp,x,NULL,NULL,0,NULL,NULL) +#endif + +#define SSL_AD_REASON_OFFSET 1000 +/* These alert types are for SSLv3 and TLSv1 */ +#define SSL_AD_CLOSE_NOTIFY SSL3_AD_CLOSE_NOTIFY +#define SSL_AD_UNEXPECTED_MESSAGE SSL3_AD_UNEXPECTED_MESSAGE /* fatal */ +#define SSL_AD_BAD_RECORD_MAC SSL3_AD_BAD_RECORD_MAC /* fatal */ +#define SSL_AD_DECRYPTION_FAILED TLS1_AD_DECRYPTION_FAILED +#define SSL_AD_RECORD_OVERFLOW TLS1_AD_RECORD_OVERFLOW +#define SSL_AD_DECOMPRESSION_FAILURE SSL3_AD_DECOMPRESSION_FAILURE/* fatal */ +#define SSL_AD_HANDSHAKE_FAILURE SSL3_AD_HANDSHAKE_FAILURE/* fatal */ +#define SSL_AD_NO_CERTIFICATE SSL3_AD_NO_CERTIFICATE /* Not for TLS */ +#define SSL_AD_BAD_CERTIFICATE SSL3_AD_BAD_CERTIFICATE +#define SSL_AD_UNSUPPORTED_CERTIFICATE SSL3_AD_UNSUPPORTED_CERTIFICATE +#define SSL_AD_CERTIFICATE_REVOKED SSL3_AD_CERTIFICATE_REVOKED +#define SSL_AD_CERTIFICATE_EXPIRED SSL3_AD_CERTIFICATE_EXPIRED +#define SSL_AD_CERTIFICATE_UNKNOWN SSL3_AD_CERTIFICATE_UNKNOWN +#define SSL_AD_ILLEGAL_PARAMETER SSL3_AD_ILLEGAL_PARAMETER /* fatal */ +#define SSL_AD_UNKNOWN_CA TLS1_AD_UNKNOWN_CA /* fatal */ +#define SSL_AD_ACCESS_DENIED TLS1_AD_ACCESS_DENIED /* fatal */ +#define SSL_AD_DECODE_ERROR TLS1_AD_DECODE_ERROR /* fatal */ +#define SSL_AD_DECRYPT_ERROR TLS1_AD_DECRYPT_ERROR +#define SSL_AD_EXPORT_RESTRICTION TLS1_AD_EXPORT_RESTRICTION/* fatal */ +#define SSL_AD_PROTOCOL_VERSION TLS1_AD_PROTOCOL_VERSION /* fatal */ +#define SSL_AD_INSUFFICIENT_SECURITY TLS1_AD_INSUFFICIENT_SECURITY/* fatal */ +#define SSL_AD_INTERNAL_ERROR TLS1_AD_INTERNAL_ERROR /* fatal */ +#define SSL_AD_USER_CANCELLED TLS1_AD_USER_CANCELLED +#define SSL_AD_NO_RENEGOTIATION TLS1_AD_NO_RENEGOTIATION +#define SSL_AD_UNSUPPORTED_EXTENSION TLS1_AD_UNSUPPORTED_EXTENSION +#define SSL_AD_CERTIFICATE_UNOBTAINABLE TLS1_AD_CERTIFICATE_UNOBTAINABLE +#define SSL_AD_UNRECOGNIZED_NAME TLS1_AD_UNRECOGNIZED_NAME +#define SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE + +#define SSL_ERROR_NONE 0 +#define SSL_ERROR_SSL 1 +#define SSL_ERROR_WANT_READ 2 +#define SSL_ERROR_WANT_WRITE 3 +#define SSL_ERROR_WANT_X509_LOOKUP 4 +#define SSL_ERROR_SYSCALL 5 /* look at error stack/return value/errno */ +#define SSL_ERROR_ZERO_RETURN 6 +#define SSL_ERROR_WANT_CONNECT 7 +#define SSL_ERROR_WANT_ACCEPT 8 + +#define SSL_CTRL_NEED_TMP_RSA 1 +#define SSL_CTRL_SET_TMP_RSA 2 +#define SSL_CTRL_SET_TMP_DH 3 +#define SSL_CTRL_SET_TMP_ECDH 4 +#define SSL_CTRL_SET_TMP_RSA_CB 5 +#define SSL_CTRL_SET_TMP_DH_CB 6 +#define SSL_CTRL_SET_TMP_ECDH_CB 7 + +#define SSL_CTRL_GET_SESSION_REUSED 8 +#define SSL_CTRL_GET_CLIENT_CERT_REQUEST 9 +#define SSL_CTRL_GET_NUM_RENEGOTIATIONS 10 +#define SSL_CTRL_CLEAR_NUM_RENEGOTIATIONS 11 +#define SSL_CTRL_GET_TOTAL_RENEGOTIATIONS 12 +#define SSL_CTRL_GET_FLAGS 13 +#define SSL_CTRL_EXTRA_CHAIN_CERT 14 + +#define SSL_CTRL_SET_MSG_CALLBACK 15 +#define SSL_CTRL_SET_MSG_CALLBACK_ARG 16 + +/* only applies to datagram connections */ +#define SSL_CTRL_SET_MTU 17 +/* Stats */ +#define SSL_CTRL_SESS_NUMBER 20 +#define SSL_CTRL_SESS_CONNECT 21 +#define SSL_CTRL_SESS_CONNECT_GOOD 22 +#define SSL_CTRL_SESS_CONNECT_RENEGOTIATE 23 +#define SSL_CTRL_SESS_ACCEPT 24 +#define SSL_CTRL_SESS_ACCEPT_GOOD 25 +#define SSL_CTRL_SESS_ACCEPT_RENEGOTIATE 26 +#define SSL_CTRL_SESS_HIT 27 +#define SSL_CTRL_SESS_CB_HIT 28 +#define SSL_CTRL_SESS_MISSES 29 +#define SSL_CTRL_SESS_TIMEOUTS 30 +#define SSL_CTRL_SESS_CACHE_FULL 31 +#define SSL_CTRL_OPTIONS 32 +#define SSL_CTRL_MODE 33 + +#define SSL_CTRL_GET_READ_AHEAD 40 +#define SSL_CTRL_SET_READ_AHEAD 41 +#define SSL_CTRL_SET_SESS_CACHE_SIZE 42 +#define SSL_CTRL_GET_SESS_CACHE_SIZE 43 +#define SSL_CTRL_SET_SESS_CACHE_MODE 44 +#define SSL_CTRL_GET_SESS_CACHE_MODE 45 + +#define SSL_CTRL_GET_MAX_CERT_LIST 50 +#define SSL_CTRL_SET_MAX_CERT_LIST 51 + +/* see tls1.h for macros based on these */ +#ifndef OPENSSL_NO_TLSEXT +#define SSL_CTRL_SET_TLSEXT_SERVERNAME_CB 53 +#define SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG 54 +#define SSL_CTRL_SET_TLSEXT_HOSTNAME 55 +#define SSL_CTRL_SET_TLSEXT_DEBUG_CB 56 +#define SSL_CTRL_SET_TLSEXT_DEBUG_ARG 57 +#define SSL_CTRL_GET_TLSEXT_TICKET_KEYS 58 +#define SSL_CTRL_SET_TLSEXT_TICKET_KEYS 59 + +#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB 63 +#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB_ARG 64 +#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_TYPE 65 +#define SSL_CTRL_GET_TLSEXT_STATUS_REQ_EXTS 66 +#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_EXTS 67 +#define SSL_CTRL_GET_TLSEXT_STATUS_REQ_IDS 68 +#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_IDS 69 +#define SSL_CTRL_GET_TLSEXT_STATUS_REQ_OCSP_RESP 70 +#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_OCSP_RESP 71 + +#define SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB 72 +#endif + +#define SSL_session_reused(ssl) \ + SSL_ctrl((ssl),SSL_CTRL_GET_SESSION_REUSED,0,NULL) +#define SSL_num_renegotiations(ssl) \ + SSL_ctrl((ssl),SSL_CTRL_GET_NUM_RENEGOTIATIONS,0,NULL) +#define SSL_clear_num_renegotiations(ssl) \ + SSL_ctrl((ssl),SSL_CTRL_CLEAR_NUM_RENEGOTIATIONS,0,NULL) +#define SSL_total_renegotiations(ssl) \ + SSL_ctrl((ssl),SSL_CTRL_GET_TOTAL_RENEGOTIATIONS,0,NULL) + +#define SSL_CTX_need_tmp_RSA(ctx) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_NEED_TMP_RSA,0,NULL) +#define SSL_CTX_set_tmp_rsa(ctx,rsa) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TMP_RSA,0,(char *)rsa) +#define SSL_CTX_set_tmp_dh(ctx,dh) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TMP_DH,0,(char *)dh) +#define SSL_CTX_set_tmp_ecdh(ctx,ecdh) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TMP_ECDH,0,(char *)ecdh) + +#define SSL_need_tmp_RSA(ssl) \ + SSL_ctrl(ssl,SSL_CTRL_NEED_TMP_RSA,0,NULL) +#define SSL_set_tmp_rsa(ssl,rsa) \ + SSL_ctrl(ssl,SSL_CTRL_SET_TMP_RSA,0,(char *)rsa) +#define SSL_set_tmp_dh(ssl,dh) \ + SSL_ctrl(ssl,SSL_CTRL_SET_TMP_DH,0,(char *)dh) +#define SSL_set_tmp_ecdh(ssl,ecdh) \ + SSL_ctrl(ssl,SSL_CTRL_SET_TMP_ECDH,0,(char *)ecdh) + +#define SSL_CTX_add_extra_chain_cert(ctx,x509) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_EXTRA_CHAIN_CERT,0,(char *)x509) + +#ifndef OPENSSL_NO_BIO +BIO_METHOD *BIO_f_ssl(void); +BIO *BIO_new_ssl(SSL_CTX *ctx,int client); +BIO *BIO_new_ssl_connect(SSL_CTX *ctx); +BIO *BIO_new_buffer_ssl_connect(SSL_CTX *ctx); +int BIO_ssl_copy_session_id(BIO *to,BIO *from); +void BIO_ssl_shutdown(BIO *ssl_bio); + +#endif + +int SSL_CTX_set_cipher_list(SSL_CTX *,const char *str); +SSL_CTX *SSL_CTX_new(SSL_METHOD *meth); +void SSL_CTX_free(SSL_CTX *); +long SSL_CTX_set_timeout(SSL_CTX *ctx,long t); +long SSL_CTX_get_timeout(const SSL_CTX *ctx); +X509_STORE *SSL_CTX_get_cert_store(const SSL_CTX *); +void SSL_CTX_set_cert_store(SSL_CTX *,X509_STORE *); +int SSL_want(const SSL *s); +int SSL_clear(SSL *s); + +void SSL_CTX_flush_sessions(SSL_CTX *ctx,long tm); + +SSL_CIPHER *SSL_get_current_cipher(const SSL *s); +int SSL_CIPHER_get_bits(const SSL_CIPHER *c,int *alg_bits); +char * SSL_CIPHER_get_version(const SSL_CIPHER *c); +const char * SSL_CIPHER_get_name(const SSL_CIPHER *c); + +int SSL_get_fd(const SSL *s); +int SSL_get_rfd(const SSL *s); +int SSL_get_wfd(const SSL *s); +const char * SSL_get_cipher_list(const SSL *s,int n); +char * SSL_get_shared_ciphers(const SSL *s, char *buf, int len); +int SSL_get_read_ahead(const SSL * s); +int SSL_pending(const SSL *s); +#ifndef OPENSSL_NO_SOCK +int SSL_set_fd(SSL *s, int fd); +int SSL_set_rfd(SSL *s, int fd); +int SSL_set_wfd(SSL *s, int fd); +#endif +#ifndef OPENSSL_NO_BIO +void SSL_set_bio(SSL *s, BIO *rbio,BIO *wbio); +BIO * SSL_get_rbio(const SSL *s); +BIO * SSL_get_wbio(const SSL *s); +#endif +int SSL_set_cipher_list(SSL *s, const char *str); +void SSL_set_read_ahead(SSL *s, int yes); +int SSL_get_verify_mode(const SSL *s); +int SSL_get_verify_depth(const SSL *s); +int (*SSL_get_verify_callback(const SSL *s))(int,X509_STORE_CTX *); +void SSL_set_verify(SSL *s, int mode, + int (*callback)(int ok,X509_STORE_CTX *ctx)); +void SSL_set_verify_depth(SSL *s, int depth); +#ifndef OPENSSL_NO_RSA +int SSL_use_RSAPrivateKey(SSL *ssl, RSA *rsa); +#endif +int SSL_use_RSAPrivateKey_ASN1(SSL *ssl, unsigned char *d, long len); +int SSL_use_PrivateKey(SSL *ssl, EVP_PKEY *pkey); +int SSL_use_PrivateKey_ASN1(int pk,SSL *ssl, const unsigned char *d, long len); +int SSL_use_certificate(SSL *ssl, X509 *x); +int SSL_use_certificate_ASN1(SSL *ssl, const unsigned char *d, int len); + +#ifndef OPENSSL_NO_STDIO +int SSL_use_RSAPrivateKey_file(SSL *ssl, const char *file, int type); +int SSL_use_PrivateKey_file(SSL *ssl, const char *file, int type); +int SSL_use_certificate_file(SSL *ssl, const char *file, int type); +int SSL_CTX_use_RSAPrivateKey_file(SSL_CTX *ctx, const char *file, int type); +int SSL_CTX_use_PrivateKey_file(SSL_CTX *ctx, const char *file, int type); +int SSL_CTX_use_certificate_file(SSL_CTX *ctx, const char *file, int type); +int SSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, const char *file); /* PEM type */ +STACK_OF(X509_NAME) *SSL_load_client_CA_file(const char *file); +int SSL_add_file_cert_subjects_to_stack(STACK_OF(X509_NAME) *stackCAs, + const char *file); +#ifndef OPENSSL_SYS_VMS +#ifndef OPENSSL_SYS_MACINTOSH_CLASSIC /* XXXXX: Better scheme needed! [was: #ifndef MAC_OS_pre_X] */ +int SSL_add_dir_cert_subjects_to_stack(STACK_OF(X509_NAME) *stackCAs, + const char *dir); +#endif +#endif + +#endif + +void SSL_load_error_strings(void ); +const char *SSL_state_string(const SSL *s); +const char *SSL_rstate_string(const SSL *s); +const char *SSL_state_string_long(const SSL *s); +const char *SSL_rstate_string_long(const SSL *s); +long SSL_SESSION_get_time(const SSL_SESSION *s); +long SSL_SESSION_set_time(SSL_SESSION *s, long t); +long SSL_SESSION_get_timeout(const SSL_SESSION *s); +long SSL_SESSION_set_timeout(SSL_SESSION *s, long t); +void SSL_copy_session_id(SSL *to,const SSL *from); + +SSL_SESSION *SSL_SESSION_new(void); +unsigned long SSL_SESSION_hash(const SSL_SESSION *a); +int SSL_SESSION_cmp(const SSL_SESSION *a,const SSL_SESSION *b); +const unsigned char *SSL_SESSION_get_id(const SSL_SESSION *s, unsigned int *len); +#ifndef OPENSSL_NO_FP_API +int SSL_SESSION_print_fp(FILE *fp,const SSL_SESSION *ses); +#endif +#ifndef OPENSSL_NO_BIO +int SSL_SESSION_print(BIO *fp,const SSL_SESSION *ses); +#endif +void SSL_SESSION_free(SSL_SESSION *ses); +int i2d_SSL_SESSION(SSL_SESSION *in,unsigned char **pp); +int SSL_set_session(SSL *to, SSL_SESSION *session); +int SSL_CTX_add_session(SSL_CTX *s, SSL_SESSION *c); +int SSL_CTX_remove_session(SSL_CTX *,SSL_SESSION *c); +int SSL_CTX_set_generate_session_id(SSL_CTX *, GEN_SESSION_CB); +int SSL_set_generate_session_id(SSL *, GEN_SESSION_CB); +int SSL_has_matching_session_id(const SSL *ssl, const unsigned char *id, + unsigned int id_len); +SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a,const unsigned char **pp, + long length); + +#ifdef HEADER_X509_H +X509 * SSL_get_peer_certificate(const SSL *s); +#endif + +STACK_OF(X509) *SSL_get_peer_cert_chain(const SSL *s); + +int SSL_CTX_get_verify_mode(const SSL_CTX *ctx); +int SSL_CTX_get_verify_depth(const SSL_CTX *ctx); +int (*SSL_CTX_get_verify_callback(const SSL_CTX *ctx))(int,X509_STORE_CTX *); +void SSL_CTX_set_verify(SSL_CTX *ctx,int mode, + int (*callback)(int, X509_STORE_CTX *)); +void SSL_CTX_set_verify_depth(SSL_CTX *ctx,int depth); +void SSL_CTX_set_cert_verify_callback(SSL_CTX *ctx, int (*cb)(X509_STORE_CTX *,void *), void *arg); +#ifndef OPENSSL_NO_RSA +int SSL_CTX_use_RSAPrivateKey(SSL_CTX *ctx, RSA *rsa); +#endif +int SSL_CTX_use_RSAPrivateKey_ASN1(SSL_CTX *ctx, const unsigned char *d, long len); +int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey); +int SSL_CTX_use_PrivateKey_ASN1(int pk,SSL_CTX *ctx, + const unsigned char *d, long len); +int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x); +int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, int len, const unsigned char *d); + +void SSL_CTX_set_default_passwd_cb(SSL_CTX *ctx, pem_password_cb *cb); +void SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX *ctx, void *u); + +int SSL_CTX_check_private_key(const SSL_CTX *ctx); +int SSL_check_private_key(const SSL *ctx); + +int SSL_CTX_set_session_id_context(SSL_CTX *ctx,const unsigned char *sid_ctx, + unsigned int sid_ctx_len); + +SSL * SSL_new(SSL_CTX *ctx); +int SSL_set_session_id_context(SSL *ssl,const unsigned char *sid_ctx, + unsigned int sid_ctx_len); + +int SSL_CTX_set_purpose(SSL_CTX *s, int purpose); +int SSL_set_purpose(SSL *s, int purpose); +int SSL_CTX_set_trust(SSL_CTX *s, int trust); +int SSL_set_trust(SSL *s, int trust); + +void SSL_free(SSL *ssl); +int SSL_accept(SSL *ssl); +int SSL_connect(SSL *ssl); +int SSL_read(SSL *ssl,void *buf,int num); +int SSL_peek(SSL *ssl,void *buf,int num); +int SSL_write(SSL *ssl,const void *buf,int num); +long SSL_ctrl(SSL *ssl,int cmd, long larg, void *parg); +long SSL_callback_ctrl(SSL *, int, void (*)(void)); +long SSL_CTX_ctrl(SSL_CTX *ctx,int cmd, long larg, void *parg); +long SSL_CTX_callback_ctrl(SSL_CTX *, int, void (*)(void)); + +int SSL_get_error(const SSL *s,int ret_code); +const char *SSL_get_version(const SSL *s); + +/* This sets the 'default' SSL version that SSL_new() will create */ +int SSL_CTX_set_ssl_version(SSL_CTX *ctx,SSL_METHOD *meth); + +SSL_METHOD *SSLv2_method(void); /* SSLv2 */ +SSL_METHOD *SSLv2_server_method(void); /* SSLv2 */ +SSL_METHOD *SSLv2_client_method(void); /* SSLv2 */ + +SSL_METHOD *SSLv3_method(void); /* SSLv3 */ +SSL_METHOD *SSLv3_server_method(void); /* SSLv3 */ +SSL_METHOD *SSLv3_client_method(void); /* SSLv3 */ + +SSL_METHOD *SSLv23_method(void); /* SSLv3 but can rollback to v2 */ +SSL_METHOD *SSLv23_server_method(void); /* SSLv3 but can rollback to v2 */ +SSL_METHOD *SSLv23_client_method(void); /* SSLv3 but can rollback to v2 */ + +SSL_METHOD *TLSv1_method(void); /* TLSv1.0 */ +SSL_METHOD *TLSv1_server_method(void); /* TLSv1.0 */ +SSL_METHOD *TLSv1_client_method(void); /* TLSv1.0 */ + +SSL_METHOD *DTLSv1_method(void); /* DTLSv1.0 */ +SSL_METHOD *DTLSv1_server_method(void); /* DTLSv1.0 */ +SSL_METHOD *DTLSv1_client_method(void); /* DTLSv1.0 */ + +STACK_OF(SSL_CIPHER) *SSL_get_ciphers(const SSL *s); + +int SSL_do_handshake(SSL *s); +int SSL_renegotiate(SSL *s); +int SSL_renegotiate_pending(SSL *s); +int SSL_shutdown(SSL *s); + +SSL_METHOD *SSL_get_ssl_method(SSL *s); +int SSL_set_ssl_method(SSL *s,SSL_METHOD *method); +const char *SSL_alert_type_string_long(int value); +const char *SSL_alert_type_string(int value); +const char *SSL_alert_desc_string_long(int value); +const char *SSL_alert_desc_string(int value); + +void SSL_set_client_CA_list(SSL *s, STACK_OF(X509_NAME) *name_list); +void SSL_CTX_set_client_CA_list(SSL_CTX *ctx, STACK_OF(X509_NAME) *name_list); +STACK_OF(X509_NAME) *SSL_get_client_CA_list(const SSL *s); +STACK_OF(X509_NAME) *SSL_CTX_get_client_CA_list(const SSL_CTX *s); +int SSL_add_client_CA(SSL *ssl,X509 *x); +int SSL_CTX_add_client_CA(SSL_CTX *ctx,X509 *x); + +void SSL_set_connect_state(SSL *s); +void SSL_set_accept_state(SSL *s); + +long SSL_get_default_timeout(const SSL *s); + +int SSL_library_init(void ); + +char *SSL_CIPHER_description(SSL_CIPHER *,char *buf,int size); +STACK_OF(X509_NAME) *SSL_dup_CA_list(STACK_OF(X509_NAME) *sk); + +SSL *SSL_dup(SSL *ssl); + +X509 *SSL_get_certificate(const SSL *ssl); +/* EVP_PKEY */ struct evp_pkey_st *SSL_get_privatekey(SSL *ssl); + +void SSL_CTX_set_quiet_shutdown(SSL_CTX *ctx,int mode); +int SSL_CTX_get_quiet_shutdown(const SSL_CTX *ctx); +void SSL_set_quiet_shutdown(SSL *ssl,int mode); +int SSL_get_quiet_shutdown(const SSL *ssl); +void SSL_set_shutdown(SSL *ssl,int mode); +int SSL_get_shutdown(const SSL *ssl); +int SSL_version(const SSL *ssl); +int SSL_CTX_set_default_verify_paths(SSL_CTX *ctx); +int SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile, + const char *CApath); +#define SSL_get0_session SSL_get_session /* just peek at pointer */ +SSL_SESSION *SSL_get_session(const SSL *ssl); +SSL_SESSION *SSL_get1_session(SSL *ssl); /* obtain a reference count */ +SSL_CTX *SSL_get_SSL_CTX(const SSL *ssl); +SSL_CTX *SSL_set_SSL_CTX(SSL *ssl, SSL_CTX* ctx); +void SSL_set_info_callback(SSL *ssl, + void (*cb)(const SSL *ssl,int type,int val)); +void (*SSL_get_info_callback(const SSL *ssl))(const SSL *ssl,int type,int val); +int SSL_state(const SSL *ssl); + +void SSL_set_verify_result(SSL *ssl,long v); +long SSL_get_verify_result(const SSL *ssl); + +int SSL_set_ex_data(SSL *ssl,int idx,void *data); +void *SSL_get_ex_data(const SSL *ssl,int idx); +int SSL_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func, + CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func); + +int SSL_SESSION_set_ex_data(SSL_SESSION *ss,int idx,void *data); +void *SSL_SESSION_get_ex_data(const SSL_SESSION *ss,int idx); +int SSL_SESSION_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func, + CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func); + +int SSL_CTX_set_ex_data(SSL_CTX *ssl,int idx,void *data); +void *SSL_CTX_get_ex_data(const SSL_CTX *ssl,int idx); +int SSL_CTX_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func, + CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func); + +int SSL_get_ex_data_X509_STORE_CTX_idx(void ); + +#define SSL_CTX_sess_set_cache_size(ctx,t) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SET_SESS_CACHE_SIZE,t,NULL) +#define SSL_CTX_sess_get_cache_size(ctx) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_GET_SESS_CACHE_SIZE,0,NULL) +#define SSL_CTX_set_session_cache_mode(ctx,m) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SET_SESS_CACHE_MODE,m,NULL) +#define SSL_CTX_get_session_cache_mode(ctx) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_GET_SESS_CACHE_MODE,0,NULL) + +#define SSL_CTX_get_default_read_ahead(ctx) SSL_CTX_get_read_ahead(ctx) +#define SSL_CTX_set_default_read_ahead(ctx,m) SSL_CTX_set_read_ahead(ctx,m) +#define SSL_CTX_get_read_ahead(ctx) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_GET_READ_AHEAD,0,NULL) +#define SSL_CTX_set_read_ahead(ctx,m) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SET_READ_AHEAD,m,NULL) +#define SSL_CTX_get_max_cert_list(ctx) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_GET_MAX_CERT_LIST,0,NULL) +#define SSL_CTX_set_max_cert_list(ctx,m) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SET_MAX_CERT_LIST,m,NULL) +#define SSL_get_max_cert_list(ssl) \ + SSL_ctrl(ssl,SSL_CTRL_GET_MAX_CERT_LIST,0,NULL) +#define SSL_set_max_cert_list(ssl,m) \ + SSL_ctrl(ssl,SSL_CTRL_SET_MAX_CERT_LIST,m,NULL) + + /* NB: the keylength is only applicable when is_export is true */ +#ifndef OPENSSL_NO_RSA +void SSL_CTX_set_tmp_rsa_callback(SSL_CTX *ctx, + RSA *(*cb)(SSL *ssl,int is_export, + int keylength)); + +void SSL_set_tmp_rsa_callback(SSL *ssl, + RSA *(*cb)(SSL *ssl,int is_export, + int keylength)); +#endif +#ifndef OPENSSL_NO_DH +void SSL_CTX_set_tmp_dh_callback(SSL_CTX *ctx, + DH *(*dh)(SSL *ssl,int is_export, + int keylength)); +void SSL_set_tmp_dh_callback(SSL *ssl, + DH *(*dh)(SSL *ssl,int is_export, + int keylength)); +#endif +#ifndef OPENSSL_NO_ECDH +void SSL_CTX_set_tmp_ecdh_callback(SSL_CTX *ctx, + EC_KEY *(*ecdh)(SSL *ssl,int is_export, + int keylength)); +void SSL_set_tmp_ecdh_callback(SSL *ssl, + EC_KEY *(*ecdh)(SSL *ssl,int is_export, + int keylength)); +#endif + +#ifndef OPENSSL_NO_COMP +const COMP_METHOD *SSL_get_current_compression(SSL *s); +const COMP_METHOD *SSL_get_current_expansion(SSL *s); +const char *SSL_COMP_get_name(const COMP_METHOD *comp); +STACK_OF(SSL_COMP) *SSL_COMP_get_compression_methods(void); +int SSL_COMP_add_compression_method(int id,COMP_METHOD *cm); +#else +const void *SSL_get_current_compression(SSL *s); +const void *SSL_get_current_expansion(SSL *s); +const char *SSL_COMP_get_name(const void *comp); +void *SSL_COMP_get_compression_methods(void); +int SSL_COMP_add_compression_method(int id,void *cm); +#endif + +/* BEGIN ERROR CODES */ +/* The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ +void ERR_load_SSL_strings(void); + +/* Error codes for the SSL functions. */ + +/* Function codes. */ +#define SSL_F_CLIENT_CERTIFICATE 100 +#define SSL_F_CLIENT_FINISHED 167 +#define SSL_F_CLIENT_HELLO 101 +#define SSL_F_CLIENT_MASTER_KEY 102 +#define SSL_F_D2I_SSL_SESSION 103 +#define SSL_F_DO_DTLS1_WRITE 245 +#define SSL_F_DO_SSL3_WRITE 104 +#define SSL_F_DTLS1_ACCEPT 246 +#define SSL_F_DTLS1_BUFFER_RECORD 247 +#define SSL_F_DTLS1_CLIENT_HELLO 248 +#define SSL_F_DTLS1_CONNECT 249 +#define SSL_F_DTLS1_ENC 250 +#define SSL_F_DTLS1_GET_HELLO_VERIFY 251 +#define SSL_F_DTLS1_GET_MESSAGE 252 +#define SSL_F_DTLS1_GET_MESSAGE_FRAGMENT 253 +#define SSL_F_DTLS1_GET_RECORD 254 +#define SSL_F_DTLS1_OUTPUT_CERT_CHAIN 255 +#define SSL_F_DTLS1_PREPROCESS_FRAGMENT 277 +#define SSL_F_DTLS1_PROCESS_OUT_OF_SEQ_MESSAGE 256 +#define SSL_F_DTLS1_PROCESS_RECORD 257 +#define SSL_F_DTLS1_READ_BYTES 258 +#define SSL_F_DTLS1_READ_FAILED 259 +#define SSL_F_DTLS1_SEND_CERTIFICATE_REQUEST 260 +#define SSL_F_DTLS1_SEND_CLIENT_CERTIFICATE 261 +#define SSL_F_DTLS1_SEND_CLIENT_KEY_EXCHANGE 262 +#define SSL_F_DTLS1_SEND_CLIENT_VERIFY 263 +#define SSL_F_DTLS1_SEND_HELLO_VERIFY_REQUEST 264 +#define SSL_F_DTLS1_SEND_SERVER_CERTIFICATE 265 +#define SSL_F_DTLS1_SEND_SERVER_HELLO 266 +#define SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE 267 +#define SSL_F_DTLS1_WRITE_APP_DATA_BYTES 268 +#define SSL_F_GET_CLIENT_FINISHED 105 +#define SSL_F_GET_CLIENT_HELLO 106 +#define SSL_F_GET_CLIENT_MASTER_KEY 107 +#define SSL_F_GET_SERVER_FINISHED 108 +#define SSL_F_GET_SERVER_HELLO 109 +#define SSL_F_GET_SERVER_VERIFY 110 +#define SSL_F_I2D_SSL_SESSION 111 +#define SSL_F_READ_N 112 +#define SSL_F_REQUEST_CERTIFICATE 113 +#define SSL_F_SERVER_FINISH 239 +#define SSL_F_SERVER_HELLO 114 +#define SSL_F_SERVER_VERIFY 240 +#define SSL_F_SSL23_ACCEPT 115 +#define SSL_F_SSL23_CLIENT_HELLO 116 +#define SSL_F_SSL23_CONNECT 117 +#define SSL_F_SSL23_GET_CLIENT_HELLO 118 +#define SSL_F_SSL23_GET_SERVER_HELLO 119 +#define SSL_F_SSL23_PEEK 237 +#define SSL_F_SSL23_READ 120 +#define SSL_F_SSL23_WRITE 121 +#define SSL_F_SSL2_ACCEPT 122 +#define SSL_F_SSL2_CONNECT 123 +#define SSL_F_SSL2_ENC_INIT 124 +#define SSL_F_SSL2_GENERATE_KEY_MATERIAL 241 +#define SSL_F_SSL2_PEEK 234 +#define SSL_F_SSL2_READ 125 +#define SSL_F_SSL2_READ_INTERNAL 236 +#define SSL_F_SSL2_SET_CERTIFICATE 126 +#define SSL_F_SSL2_WRITE 127 +#define SSL_F_SSL3_ACCEPT 128 +#define SSL_F_SSL3_CALLBACK_CTRL 233 +#define SSL_F_SSL3_CHANGE_CIPHER_STATE 129 +#define SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM 130 +#define SSL_F_SSL3_CLIENT_HELLO 131 +#define SSL_F_SSL3_CONNECT 132 +#define SSL_F_SSL3_CTRL 213 +#define SSL_F_SSL3_CTX_CTRL 133 +#define SSL_F_SSL3_ENC 134 +#define SSL_F_SSL3_GENERATE_KEY_BLOCK 238 +#define SSL_F_SSL3_GET_CERTIFICATE_REQUEST 135 +#define SSL_F_SSL3_GET_CERT_STATUS 288 +#define SSL_F_SSL3_GET_CERT_VERIFY 136 +#define SSL_F_SSL3_GET_CLIENT_CERTIFICATE 137 +#define SSL_F_SSL3_GET_CLIENT_HELLO 138 +#define SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE 139 +#define SSL_F_SSL3_GET_FINISHED 140 +#define SSL_F_SSL3_GET_KEY_EXCHANGE 141 +#define SSL_F_SSL3_GET_MESSAGE 142 +#define SSL_F_SSL3_GET_NEW_SESSION_TICKET 283 +#define SSL_F_SSL3_GET_RECORD 143 +#define SSL_F_SSL3_GET_SERVER_CERTIFICATE 144 +#define SSL_F_SSL3_GET_SERVER_DONE 145 +#define SSL_F_SSL3_GET_SERVER_HELLO 146 +#define SSL_F_SSL3_NEW_SESSION_TICKET 284 +#define SSL_F_SSL3_OUTPUT_CERT_CHAIN 147 +#define SSL_F_SSL3_PEEK 235 +#define SSL_F_SSL3_READ_BYTES 148 +#define SSL_F_SSL3_READ_N 149 +#define SSL_F_SSL3_SEND_CERTIFICATE_REQUEST 150 +#define SSL_F_SSL3_SEND_CLIENT_CERTIFICATE 151 +#define SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE 152 +#define SSL_F_SSL3_SEND_CLIENT_VERIFY 153 +#define SSL_F_SSL3_SEND_SERVER_CERTIFICATE 154 +#define SSL_F_SSL3_SEND_SERVER_HELLO 242 +#define SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE 155 +#define SSL_F_SSL3_SETUP_BUFFERS 156 +#define SSL_F_SSL3_SETUP_KEY_BLOCK 157 +#define SSL_F_SSL3_WRITE_BYTES 158 +#define SSL_F_SSL3_WRITE_PENDING 159 +#define SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT 272 +#define SSL_F_SSL_ADD_DIR_CERT_SUBJECTS_TO_STACK 215 +#define SSL_F_SSL_ADD_FILE_CERT_SUBJECTS_TO_STACK 216 +#define SSL_F_SSL_ADD_SERVERHELLO_TLSEXT 273 +#define SSL_F_SSL_BAD_METHOD 160 +#define SSL_F_SSL_BYTES_TO_CIPHER_LIST 161 +#define SSL_F_SSL_CERT_DUP 221 +#define SSL_F_SSL_CERT_INST 222 +#define SSL_F_SSL_CERT_INSTANTIATE 214 +#define SSL_F_SSL_CERT_NEW 162 +#define SSL_F_SSL_CHECK_PRIVATE_KEY 163 +#define SSL_F_SSL_CHECK_SERVERHELLO_TLSEXT 274 +#define SSL_F_SSL_CIPHER_PROCESS_RULESTR 230 +#define SSL_F_SSL_CIPHER_STRENGTH_SORT 231 +#define SSL_F_SSL_CLEAR 164 +#define SSL_F_SSL_COMP_ADD_COMPRESSION_METHOD 165 +#define SSL_F_SSL_CREATE_CIPHER_LIST 166 +#define SSL_F_SSL_CTRL 232 +#define SSL_F_SSL_CTX_CHECK_PRIVATE_KEY 168 +#define SSL_F_SSL_CTX_NEW 169 +#define SSL_F_SSL_CTX_SET_CIPHER_LIST 269 +#define SSL_F_SSL_CTX_SET_PURPOSE 226 +#define SSL_F_SSL_CTX_SET_SESSION_ID_CONTEXT 219 +#define SSL_F_SSL_CTX_SET_SSL_VERSION 170 +#define SSL_F_SSL_CTX_SET_TRUST 229 +#define SSL_F_SSL_CTX_USE_CERTIFICATE 171 +#define SSL_F_SSL_CTX_USE_CERTIFICATE_ASN1 172 +#define SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE 220 +#define SSL_F_SSL_CTX_USE_CERTIFICATE_FILE 173 +#define SSL_F_SSL_CTX_USE_PRIVATEKEY 174 +#define SSL_F_SSL_CTX_USE_PRIVATEKEY_ASN1 175 +#define SSL_F_SSL_CTX_USE_PRIVATEKEY_FILE 176 +#define SSL_F_SSL_CTX_USE_RSAPRIVATEKEY 177 +#define SSL_F_SSL_CTX_USE_RSAPRIVATEKEY_ASN1 178 +#define SSL_F_SSL_CTX_USE_RSAPRIVATEKEY_FILE 179 +#define SSL_F_SSL_DO_HANDSHAKE 180 +#define SSL_F_SSL_GET_NEW_SESSION 181 +#define SSL_F_SSL_GET_PREV_SESSION 217 +#define SSL_F_SSL_GET_SERVER_SEND_CERT 182 +#define SSL_F_SSL_GET_SIGN_PKEY 183 +#define SSL_F_SSL_INIT_WBIO_BUFFER 184 +#define SSL_F_SSL_LOAD_CLIENT_CA_FILE 185 +#define SSL_F_SSL_NEW 186 +#define SSL_F_SSL_PEEK 270 +#define SSL_F_SSL_PREPARE_CLIENTHELLO_TLSEXT 275 +#define SSL_F_SSL_PREPARE_SERVERHELLO_TLSEXT 276 +#define SSL_F_SSL_READ 223 +#define SSL_F_SSL_RSA_PRIVATE_DECRYPT 187 +#define SSL_F_SSL_RSA_PUBLIC_ENCRYPT 188 +#define SSL_F_SSL_SESSION_NEW 189 +#define SSL_F_SSL_SESSION_PRINT_FP 190 +#define SSL_F_SSL_SESS_CERT_NEW 225 +#define SSL_F_SSL_SET_CERT 191 +#define SSL_F_SSL_SET_CIPHER_LIST 271 +#define SSL_F_SSL_SET_FD 192 +#define SSL_F_SSL_SET_PKEY 193 +#define SSL_F_SSL_SET_PURPOSE 227 +#define SSL_F_SSL_SET_RFD 194 +#define SSL_F_SSL_SET_SESSION 195 +#define SSL_F_SSL_SET_SESSION_ID_CONTEXT 218 +#define SSL_F_SSL_SET_TRUST 228 +#define SSL_F_SSL_SET_WFD 196 +#define SSL_F_SSL_SHUTDOWN 224 +#define SSL_F_SSL_UNDEFINED_CONST_FUNCTION 243 +#define SSL_F_SSL_UNDEFINED_FUNCTION 197 +#define SSL_F_SSL_UNDEFINED_VOID_FUNCTION 244 +#define SSL_F_SSL_USE_CERTIFICATE 198 +#define SSL_F_SSL_USE_CERTIFICATE_ASN1 199 +#define SSL_F_SSL_USE_CERTIFICATE_FILE 200 +#define SSL_F_SSL_USE_PRIVATEKEY 201 +#define SSL_F_SSL_USE_PRIVATEKEY_ASN1 202 +#define SSL_F_SSL_USE_PRIVATEKEY_FILE 203 +#define SSL_F_SSL_USE_RSAPRIVATEKEY 204 +#define SSL_F_SSL_USE_RSAPRIVATEKEY_ASN1 205 +#define SSL_F_SSL_USE_RSAPRIVATEKEY_FILE 206 +#define SSL_F_SSL_VERIFY_CERT_CHAIN 207 +#define SSL_F_SSL_WRITE 208 +#define SSL_F_TLS1_CHANGE_CIPHER_STATE 209 +#define SSL_F_TLS1_ENC 210 +#define SSL_F_TLS1_SETUP_KEY_BLOCK 211 +#define SSL_F_WRITE_PENDING 212 + +/* Reason codes. */ +#define SSL_R_APP_DATA_IN_HANDSHAKE 100 +#define SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT 272 +#define SSL_R_BAD_ALERT_RECORD 101 +#define SSL_R_BAD_AUTHENTICATION_TYPE 102 +#define SSL_R_BAD_CHANGE_CIPHER_SPEC 103 +#define SSL_R_BAD_CHECKSUM 104 +#define SSL_R_BAD_DATA_RETURNED_BY_CALLBACK 106 +#define SSL_R_BAD_DECOMPRESSION 107 +#define SSL_R_BAD_DH_G_LENGTH 108 +#define SSL_R_BAD_DH_PUB_KEY_LENGTH 109 +#define SSL_R_BAD_DH_P_LENGTH 110 +#define SSL_R_BAD_DIGEST_LENGTH 111 +#define SSL_R_BAD_DSA_SIGNATURE 112 +#define SSL_R_BAD_ECC_CERT 304 +#define SSL_R_BAD_ECDSA_SIGNATURE 305 +#define SSL_R_BAD_ECPOINT 306 +#define SSL_R_BAD_HELLO_REQUEST 105 +#define SSL_R_BAD_LENGTH 271 +#define SSL_R_BAD_MAC_DECODE 113 +#define SSL_R_BAD_MESSAGE_TYPE 114 +#define SSL_R_BAD_PACKET_LENGTH 115 +#define SSL_R_BAD_PROTOCOL_VERSION_NUMBER 116 +#define SSL_R_BAD_RESPONSE_ARGUMENT 117 +#define SSL_R_BAD_RSA_DECRYPT 118 +#define SSL_R_BAD_RSA_ENCRYPT 119 +#define SSL_R_BAD_RSA_E_LENGTH 120 +#define SSL_R_BAD_RSA_MODULUS_LENGTH 121 +#define SSL_R_BAD_RSA_SIGNATURE 122 +#define SSL_R_BAD_SIGNATURE 123 +#define SSL_R_BAD_SSL_FILETYPE 124 +#define SSL_R_BAD_SSL_SESSION_ID_LENGTH 125 +#define SSL_R_BAD_STATE 126 +#define SSL_R_BAD_WRITE_RETRY 127 +#define SSL_R_BIO_NOT_SET 128 +#define SSL_R_BLOCK_CIPHER_PAD_IS_WRONG 129 +#define SSL_R_BN_LIB 130 +#define SSL_R_CA_DN_LENGTH_MISMATCH 131 +#define SSL_R_CA_DN_TOO_LONG 132 +#define SSL_R_CCS_RECEIVED_EARLY 133 +#define SSL_R_CERTIFICATE_VERIFY_FAILED 134 +#define SSL_R_CERT_LENGTH_MISMATCH 135 +#define SSL_R_CHALLENGE_IS_DIFFERENT 136 +#define SSL_R_CIPHER_CODE_WRONG_LENGTH 137 +#define SSL_R_CIPHER_OR_HASH_UNAVAILABLE 138 +#define SSL_R_CIPHER_TABLE_SRC_ERROR 139 +#define SSL_R_CLIENTHELLO_TLSEXT 157 +#define SSL_R_COMPRESSED_LENGTH_TOO_LONG 140 +#define SSL_R_COMPRESSION_FAILURE 141 +#define SSL_R_COMPRESSION_ID_NOT_WITHIN_PRIVATE_RANGE 307 +#define SSL_R_COMPRESSION_LIBRARY_ERROR 142 +#define SSL_R_CONNECTION_ID_IS_DIFFERENT 143 +#define SSL_R_CONNECTION_TYPE_NOT_SET 144 +#define SSL_R_COOKIE_MISMATCH 308 +#define SSL_R_DATA_BETWEEN_CCS_AND_FINISHED 145 +#define SSL_R_DATA_LENGTH_TOO_LONG 146 +#define SSL_R_DECRYPTION_FAILED 147 +#define SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC 281 +#define SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG 148 +#define SSL_R_DIGEST_CHECK_FAILED 149 +#define SSL_R_DUPLICATE_COMPRESSION_ID 309 +#define SSL_R_ECGROUP_TOO_LARGE_FOR_CIPHER 310 +#define SSL_R_ENCRYPTED_LENGTH_TOO_LONG 150 +#define SSL_R_ERROR_GENERATING_TMP_RSA_KEY 282 +#define SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST 151 +#define SSL_R_EXCESSIVE_MESSAGE_SIZE 152 +#define SSL_R_EXTRA_DATA_IN_MESSAGE 153 +#define SSL_R_GOT_A_FIN_BEFORE_A_CCS 154 +#define SSL_R_HTTPS_PROXY_REQUEST 155 +#define SSL_R_HTTP_REQUEST 156 +#define SSL_R_ILLEGAL_PADDING 283 +#define SSL_R_INVALID_CHALLENGE_LENGTH 158 +#define SSL_R_INVALID_COMMAND 280 +#define SSL_R_INVALID_PURPOSE 278 +#define SSL_R_INVALID_STATUS_RESPONSE 316 +#define SSL_R_INVALID_TICKET_KEYS_LENGTH 275 +#define SSL_R_INVALID_TRUST 279 +#define SSL_R_KEY_ARG_TOO_LONG 284 +#define SSL_R_KRB5 285 +#define SSL_R_KRB5_C_CC_PRINC 286 +#define SSL_R_KRB5_C_GET_CRED 287 +#define SSL_R_KRB5_C_INIT 288 +#define SSL_R_KRB5_C_MK_REQ 289 +#define SSL_R_KRB5_S_BAD_TICKET 290 +#define SSL_R_KRB5_S_INIT 291 +#define SSL_R_KRB5_S_RD_REQ 292 +#define SSL_R_KRB5_S_TKT_EXPIRED 293 +#define SSL_R_KRB5_S_TKT_NYV 294 +#define SSL_R_KRB5_S_TKT_SKEW 295 +#define SSL_R_LENGTH_MISMATCH 159 +#define SSL_R_LENGTH_TOO_SHORT 160 +#define SSL_R_LIBRARY_BUG 274 +#define SSL_R_LIBRARY_HAS_NO_CIPHERS 161 +#define SSL_R_MESSAGE_TOO_LONG 296 +#define SSL_R_MISSING_DH_DSA_CERT 162 +#define SSL_R_MISSING_DH_KEY 163 +#define SSL_R_MISSING_DH_RSA_CERT 164 +#define SSL_R_MISSING_DSA_SIGNING_CERT 165 +#define SSL_R_MISSING_EXPORT_TMP_DH_KEY 166 +#define SSL_R_MISSING_EXPORT_TMP_RSA_KEY 167 +#define SSL_R_MISSING_RSA_CERTIFICATE 168 +#define SSL_R_MISSING_RSA_ENCRYPTING_CERT 169 +#define SSL_R_MISSING_RSA_SIGNING_CERT 170 +#define SSL_R_MISSING_TMP_DH_KEY 171 +#define SSL_R_MISSING_TMP_ECDH_KEY 311 +#define SSL_R_MISSING_TMP_RSA_KEY 172 +#define SSL_R_MISSING_TMP_RSA_PKEY 173 +#define SSL_R_MISSING_VERIFY_MESSAGE 174 +#define SSL_R_NON_SSLV2_INITIAL_PACKET 175 +#define SSL_R_NO_CERTIFICATES_RETURNED 176 +#define SSL_R_NO_CERTIFICATE_ASSIGNED 177 +#define SSL_R_NO_CERTIFICATE_RETURNED 178 +#define SSL_R_NO_CERTIFICATE_SET 179 +#define SSL_R_NO_CERTIFICATE_SPECIFIED 180 +#define SSL_R_NO_CIPHERS_AVAILABLE 181 +#define SSL_R_NO_CIPHERS_PASSED 182 +#define SSL_R_NO_CIPHERS_SPECIFIED 183 +#define SSL_R_NO_CIPHER_LIST 184 +#define SSL_R_NO_CIPHER_MATCH 185 +#define SSL_R_NO_CLIENT_CERT_RECEIVED 186 +#define SSL_R_NO_COMPRESSION_SPECIFIED 187 +#define SSL_R_NO_METHOD_SPECIFIED 188 +#define SSL_R_NO_PRIVATEKEY 189 +#define SSL_R_NO_PRIVATE_KEY_ASSIGNED 190 +#define SSL_R_NO_PROTOCOLS_AVAILABLE 191 +#define SSL_R_NO_PUBLICKEY 192 +#define SSL_R_NO_SHARED_CIPHER 193 +#define SSL_R_NO_VERIFY_CALLBACK 194 +#define SSL_R_NULL_SSL_CTX 195 +#define SSL_R_NULL_SSL_METHOD_PASSED 196 +#define SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED 197 +#define SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE 297 +#define SSL_R_PACKET_LENGTH_TOO_LONG 198 +#define SSL_R_PARSE_TLSEXT 223 +#define SSL_R_PATH_TOO_LONG 270 +#define SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE 199 +#define SSL_R_PEER_ERROR 200 +#define SSL_R_PEER_ERROR_CERTIFICATE 201 +#define SSL_R_PEER_ERROR_NO_CERTIFICATE 202 +#define SSL_R_PEER_ERROR_NO_CIPHER 203 +#define SSL_R_PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE 204 +#define SSL_R_PRE_MAC_LENGTH_TOO_LONG 205 +#define SSL_R_PROBLEMS_MAPPING_CIPHER_FUNCTIONS 206 +#define SSL_R_PROTOCOL_IS_SHUTDOWN 207 +#define SSL_R_PUBLIC_KEY_ENCRYPT_ERROR 208 +#define SSL_R_PUBLIC_KEY_IS_NOT_RSA 209 +#define SSL_R_PUBLIC_KEY_NOT_RSA 210 +#define SSL_R_READ_BIO_NOT_SET 211 +#define SSL_R_READ_TIMEOUT_EXPIRED 312 +#define SSL_R_READ_WRONG_PACKET_TYPE 212 +#define SSL_R_RECORD_LENGTH_MISMATCH 213 +#define SSL_R_RECORD_TOO_LARGE 214 +#define SSL_R_RECORD_TOO_SMALL 298 +#define SSL_R_REQUIRED_CIPHER_MISSING 215 +#define SSL_R_REUSE_CERT_LENGTH_NOT_ZERO 216 +#define SSL_R_REUSE_CERT_TYPE_NOT_ZERO 217 +#define SSL_R_REUSE_CIPHER_LIST_NOT_ZERO 218 +#define SSL_R_SERVERHELLO_TLSEXT 224 +#define SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED 277 +#define SSL_R_SHORT_READ 219 +#define SSL_R_SIGNATURE_FOR_NON_SIGNING_CERTIFICATE 220 +#define SSL_R_SSL23_DOING_SESSION_ID_REUSE 221 +#define SSL_R_SSL2_CONNECTION_ID_TOO_LONG 299 +#define SSL_R_SSL3_EXT_INVALID_SERVERNAME 225 +#define SSL_R_SSL3_EXT_INVALID_SERVERNAME_TYPE 226 +#define SSL_R_SSL3_SESSION_ID_TOO_LONG 300 +#define SSL_R_SSL3_SESSION_ID_TOO_SHORT 222 +#define SSL_R_SSLV3_ALERT_BAD_CERTIFICATE 1042 +#define SSL_R_SSLV3_ALERT_BAD_RECORD_MAC 1020 +#define SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED 1045 +#define SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED 1044 +#define SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN 1046 +#define SSL_R_SSLV3_ALERT_DECOMPRESSION_FAILURE 1030 +#define SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE 1040 +#define SSL_R_SSLV3_ALERT_ILLEGAL_PARAMETER 1047 +#define SSL_R_SSLV3_ALERT_NO_CERTIFICATE 1041 +#define SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE 1010 +#define SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE 1043 +#define SSL_R_SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION 228 +#define SSL_R_SSL_HANDSHAKE_FAILURE 229 +#define SSL_R_SSL_LIBRARY_HAS_NO_CIPHERS 230 +#define SSL_R_SSL_SESSION_ID_CALLBACK_FAILED 301 +#define SSL_R_SSL_SESSION_ID_CONFLICT 302 +#define SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG 273 +#define SSL_R_SSL_SESSION_ID_HAS_BAD_LENGTH 303 +#define SSL_R_SSL_SESSION_ID_IS_DIFFERENT 231 +#define SSL_R_TLSV1_ALERT_ACCESS_DENIED 1049 +#define SSL_R_TLSV1_ALERT_DECODE_ERROR 1050 +#define SSL_R_TLSV1_ALERT_DECRYPTION_FAILED 1021 +#define SSL_R_TLSV1_ALERT_DECRYPT_ERROR 1051 +#define SSL_R_TLSV1_ALERT_EXPORT_RESTRICTION 1060 +#define SSL_R_TLSV1_ALERT_INSUFFICIENT_SECURITY 1071 +#define SSL_R_TLSV1_ALERT_INTERNAL_ERROR 1080 +#define SSL_R_TLSV1_ALERT_NO_RENEGOTIATION 1100 +#define SSL_R_TLSV1_ALERT_PROTOCOL_VERSION 1070 +#define SSL_R_TLSV1_ALERT_RECORD_OVERFLOW 1022 +#define SSL_R_TLSV1_ALERT_UNKNOWN_CA 1048 +#define SSL_R_TLSV1_ALERT_USER_CANCELLED 1090 +#define SSL_R_TLS_CLIENT_CERT_REQ_WITH_ANON_CIPHER 232 +#define SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST 227 +#define SSL_R_TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST 233 +#define SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG 234 +#define SSL_R_TRIED_TO_USE_UNSUPPORTED_CIPHER 235 +#define SSL_R_UNABLE_TO_DECODE_DH_CERTS 236 +#define SSL_R_UNABLE_TO_DECODE_ECDH_CERTS 313 +#define SSL_R_UNABLE_TO_EXTRACT_PUBLIC_KEY 237 +#define SSL_R_UNABLE_TO_FIND_DH_PARAMETERS 238 +#define SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS 314 +#define SSL_R_UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS 239 +#define SSL_R_UNABLE_TO_FIND_SSL_METHOD 240 +#define SSL_R_UNABLE_TO_LOAD_SSL2_MD5_ROUTINES 241 +#define SSL_R_UNABLE_TO_LOAD_SSL3_MD5_ROUTINES 242 +#define SSL_R_UNABLE_TO_LOAD_SSL3_SHA1_ROUTINES 243 +#define SSL_R_UNEXPECTED_MESSAGE 244 +#define SSL_R_UNEXPECTED_RECORD 245 +#define SSL_R_UNINITIALIZED 276 +#define SSL_R_UNKNOWN_ALERT_TYPE 246 +#define SSL_R_UNKNOWN_CERTIFICATE_TYPE 247 +#define SSL_R_UNKNOWN_CIPHER_RETURNED 248 +#define SSL_R_UNKNOWN_CIPHER_TYPE 249 +#define SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE 250 +#define SSL_R_UNKNOWN_PKEY_TYPE 251 +#define SSL_R_UNKNOWN_PROTOCOL 252 +#define SSL_R_UNKNOWN_REMOTE_ERROR_TYPE 253 +#define SSL_R_UNKNOWN_SSL_VERSION 254 +#define SSL_R_UNKNOWN_STATE 255 +#define SSL_R_UNSUPPORTED_CIPHER 256 +#define SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM 257 +#define SSL_R_UNSUPPORTED_ELLIPTIC_CURVE 315 +#define SSL_R_UNSUPPORTED_PROTOCOL 258 +#define SSL_R_UNSUPPORTED_SSL_VERSION 259 +#define SSL_R_UNSUPPORTED_STATUS_TYPE 329 +#define SSL_R_WRITE_BIO_NOT_SET 260 +#define SSL_R_WRONG_CIPHER_RETURNED 261 +#define SSL_R_WRONG_MESSAGE_TYPE 262 +#define SSL_R_WRONG_NUMBER_OF_KEY_BITS 263 +#define SSL_R_WRONG_SIGNATURE_LENGTH 264 +#define SSL_R_WRONG_SIGNATURE_SIZE 265 +#define SSL_R_WRONG_SSL_VERSION 266 +#define SSL_R_WRONG_VERSION_NUMBER 267 +#define SSL_R_X509_LIB 268 +#define SSL_R_X509_VERIFICATION_SETUP_PROBLEMS 269 + +#ifdef __cplusplus +} +#endif +#endif diff --git a/lib_tls/include/openssl/ssl2.h b/lib_tls/include/openssl/ssl2.h new file mode 100644 index 000000000..99a52ea0d --- /dev/null +++ b/lib_tls/include/openssl/ssl2.h @@ -0,0 +1,268 @@ +/* ssl/ssl2.h */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#ifndef HEADER_SSL2_H +#define HEADER_SSL2_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Protocol Version Codes */ +#define SSL2_VERSION 0x0002 +#define SSL2_VERSION_MAJOR 0x00 +#define SSL2_VERSION_MINOR 0x02 +/* #define SSL2_CLIENT_VERSION 0x0002 */ +/* #define SSL2_SERVER_VERSION 0x0002 */ + +/* Protocol Message Codes */ +#define SSL2_MT_ERROR 0 +#define SSL2_MT_CLIENT_HELLO 1 +#define SSL2_MT_CLIENT_MASTER_KEY 2 +#define SSL2_MT_CLIENT_FINISHED 3 +#define SSL2_MT_SERVER_HELLO 4 +#define SSL2_MT_SERVER_VERIFY 5 +#define SSL2_MT_SERVER_FINISHED 6 +#define SSL2_MT_REQUEST_CERTIFICATE 7 +#define SSL2_MT_CLIENT_CERTIFICATE 8 + +/* Error Message Codes */ +#define SSL2_PE_UNDEFINED_ERROR 0x0000 +#define SSL2_PE_NO_CIPHER 0x0001 +#define SSL2_PE_NO_CERTIFICATE 0x0002 +#define SSL2_PE_BAD_CERTIFICATE 0x0004 +#define SSL2_PE_UNSUPPORTED_CERTIFICATE_TYPE 0x0006 + +/* Cipher Kind Values */ +#define SSL2_CK_NULL_WITH_MD5 0x02000000 /* v3 */ +#define SSL2_CK_RC4_128_WITH_MD5 0x02010080 +#define SSL2_CK_RC4_128_EXPORT40_WITH_MD5 0x02020080 +#define SSL2_CK_RC2_128_CBC_WITH_MD5 0x02030080 +#define SSL2_CK_RC2_128_CBC_EXPORT40_WITH_MD5 0x02040080 +#define SSL2_CK_IDEA_128_CBC_WITH_MD5 0x02050080 +#define SSL2_CK_DES_64_CBC_WITH_MD5 0x02060040 +#define SSL2_CK_DES_64_CBC_WITH_SHA 0x02060140 /* v3 */ +#define SSL2_CK_DES_192_EDE3_CBC_WITH_MD5 0x020700c0 +#define SSL2_CK_DES_192_EDE3_CBC_WITH_SHA 0x020701c0 /* v3 */ +#define SSL2_CK_RC4_64_WITH_MD5 0x02080080 /* MS hack */ + +#define SSL2_CK_DES_64_CFB64_WITH_MD5_1 0x02ff0800 /* SSLeay */ +#define SSL2_CK_NULL 0x02ff0810 /* SSLeay */ + +#define SSL2_TXT_DES_64_CFB64_WITH_MD5_1 "DES-CFB-M1" +#define SSL2_TXT_NULL_WITH_MD5 "NULL-MD5" +#define SSL2_TXT_RC4_128_WITH_MD5 "RC4-MD5" +#define SSL2_TXT_RC4_128_EXPORT40_WITH_MD5 "EXP-RC4-MD5" +#define SSL2_TXT_RC2_128_CBC_WITH_MD5 "RC2-CBC-MD5" +#define SSL2_TXT_RC2_128_CBC_EXPORT40_WITH_MD5 "EXP-RC2-CBC-MD5" +#define SSL2_TXT_IDEA_128_CBC_WITH_MD5 "IDEA-CBC-MD5" +#define SSL2_TXT_DES_64_CBC_WITH_MD5 "DES-CBC-MD5" +#define SSL2_TXT_DES_64_CBC_WITH_SHA "DES-CBC-SHA" +#define SSL2_TXT_DES_192_EDE3_CBC_WITH_MD5 "DES-CBC3-MD5" +#define SSL2_TXT_DES_192_EDE3_CBC_WITH_SHA "DES-CBC3-SHA" +#define SSL2_TXT_RC4_64_WITH_MD5 "RC4-64-MD5" + +#define SSL2_TXT_NULL "NULL" + +/* Flags for the SSL_CIPHER.algorithm2 field */ +#define SSL2_CF_5_BYTE_ENC 0x01 +#define SSL2_CF_8_BYTE_ENC 0x02 + +/* Certificate Type Codes */ +#define SSL2_CT_X509_CERTIFICATE 0x01 + +/* Authentication Type Code */ +#define SSL2_AT_MD5_WITH_RSA_ENCRYPTION 0x01 + +#define SSL2_MAX_SSL_SESSION_ID_LENGTH 32 + +/* Upper/Lower Bounds */ +#define SSL2_MAX_MASTER_KEY_LENGTH_IN_BITS 256 +#ifdef OPENSSL_SYS_MPE +#define SSL2_MAX_RECORD_LENGTH_2_BYTE_HEADER 29998u +#else +#define SSL2_MAX_RECORD_LENGTH_2_BYTE_HEADER 32767u /* 2^15-1 */ +#endif +#define SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER 16383 /* 2^14-1 */ + +#define SSL2_CHALLENGE_LENGTH 16 +/*#define SSL2_CHALLENGE_LENGTH 32 */ +#define SSL2_MIN_CHALLENGE_LENGTH 16 +#define SSL2_MAX_CHALLENGE_LENGTH 32 +#define SSL2_CONNECTION_ID_LENGTH 16 +#define SSL2_MAX_CONNECTION_ID_LENGTH 16 +#define SSL2_SSL_SESSION_ID_LENGTH 16 +#define SSL2_MAX_CERT_CHALLENGE_LENGTH 32 +#define SSL2_MIN_CERT_CHALLENGE_LENGTH 16 +#define SSL2_MAX_KEY_MATERIAL_LENGTH 24 + +#ifndef HEADER_SSL_LOCL_H +#define CERT char +#endif + +typedef struct ssl2_state_st + { + int three_byte_header; + int clear_text; /* clear text */ + int escape; /* not used in SSLv2 */ + int ssl2_rollback; /* used if SSLv23 rolled back to SSLv2 */ + + /* non-blocking io info, used to make sure the same + * args were passwd */ + unsigned int wnum; /* number of bytes sent so far */ + int wpend_tot; + const unsigned char *wpend_buf; + + int wpend_off; /* offset to data to write */ + int wpend_len; /* number of bytes passwd to write */ + int wpend_ret; /* number of bytes to return to caller */ + + /* buffer raw data */ + int rbuf_left; + int rbuf_offs; + unsigned char *rbuf; + unsigned char *wbuf; + + unsigned char *write_ptr;/* used to point to the start due to + * 2/3 byte header. */ + + unsigned int padding; + unsigned int rlength; /* passed to ssl2_enc */ + int ract_data_length; /* Set when things are encrypted. */ + unsigned int wlength; /* passed to ssl2_enc */ + int wact_data_length; /* Set when things are decrypted. */ + unsigned char *ract_data; + unsigned char *wact_data; + unsigned char *mac_data; + + unsigned char *read_key; + unsigned char *write_key; + + /* Stuff specifically to do with this SSL session */ + unsigned int challenge_length; + unsigned char challenge[SSL2_MAX_CHALLENGE_LENGTH]; + unsigned int conn_id_length; + unsigned char conn_id[SSL2_MAX_CONNECTION_ID_LENGTH]; + unsigned int key_material_length; + unsigned char key_material[SSL2_MAX_KEY_MATERIAL_LENGTH*2]; + + unsigned long read_sequence; + unsigned long write_sequence; + + struct { + unsigned int conn_id_length; + unsigned int cert_type; + unsigned int cert_length; + unsigned int csl; + unsigned int clear; + unsigned int enc; + unsigned char ccl[SSL2_MAX_CERT_CHALLENGE_LENGTH]; + unsigned int cipher_spec_length; + unsigned int session_id_length; + unsigned int clen; + unsigned int rlen; + } tmp; + } SSL2_STATE; + +/* SSLv2 */ +/* client */ +#define SSL2_ST_SEND_CLIENT_HELLO_A (0x10|SSL_ST_CONNECT) +#define SSL2_ST_SEND_CLIENT_HELLO_B (0x11|SSL_ST_CONNECT) +#define SSL2_ST_GET_SERVER_HELLO_A (0x20|SSL_ST_CONNECT) +#define SSL2_ST_GET_SERVER_HELLO_B (0x21|SSL_ST_CONNECT) +#define SSL2_ST_SEND_CLIENT_MASTER_KEY_A (0x30|SSL_ST_CONNECT) +#define SSL2_ST_SEND_CLIENT_MASTER_KEY_B (0x31|SSL_ST_CONNECT) +#define SSL2_ST_SEND_CLIENT_FINISHED_A (0x40|SSL_ST_CONNECT) +#define SSL2_ST_SEND_CLIENT_FINISHED_B (0x41|SSL_ST_CONNECT) +#define SSL2_ST_SEND_CLIENT_CERTIFICATE_A (0x50|SSL_ST_CONNECT) +#define SSL2_ST_SEND_CLIENT_CERTIFICATE_B (0x51|SSL_ST_CONNECT) +#define SSL2_ST_SEND_CLIENT_CERTIFICATE_C (0x52|SSL_ST_CONNECT) +#define SSL2_ST_SEND_CLIENT_CERTIFICATE_D (0x53|SSL_ST_CONNECT) +#define SSL2_ST_GET_SERVER_VERIFY_A (0x60|SSL_ST_CONNECT) +#define SSL2_ST_GET_SERVER_VERIFY_B (0x61|SSL_ST_CONNECT) +#define SSL2_ST_GET_SERVER_FINISHED_A (0x70|SSL_ST_CONNECT) +#define SSL2_ST_GET_SERVER_FINISHED_B (0x71|SSL_ST_CONNECT) +#define SSL2_ST_CLIENT_START_ENCRYPTION (0x80|SSL_ST_CONNECT) +#define SSL2_ST_X509_GET_CLIENT_CERTIFICATE (0x90|SSL_ST_CONNECT) +/* server */ +#define SSL2_ST_GET_CLIENT_HELLO_A (0x10|SSL_ST_ACCEPT) +#define SSL2_ST_GET_CLIENT_HELLO_B (0x11|SSL_ST_ACCEPT) +#define SSL2_ST_GET_CLIENT_HELLO_C (0x12|SSL_ST_ACCEPT) +#define SSL2_ST_SEND_SERVER_HELLO_A (0x20|SSL_ST_ACCEPT) +#define SSL2_ST_SEND_SERVER_HELLO_B (0x21|SSL_ST_ACCEPT) +#define SSL2_ST_GET_CLIENT_MASTER_KEY_A (0x30|SSL_ST_ACCEPT) +#define SSL2_ST_GET_CLIENT_MASTER_KEY_B (0x31|SSL_ST_ACCEPT) +#define SSL2_ST_SEND_SERVER_VERIFY_A (0x40|SSL_ST_ACCEPT) +#define SSL2_ST_SEND_SERVER_VERIFY_B (0x41|SSL_ST_ACCEPT) +#define SSL2_ST_SEND_SERVER_VERIFY_C (0x42|SSL_ST_ACCEPT) +#define SSL2_ST_GET_CLIENT_FINISHED_A (0x50|SSL_ST_ACCEPT) +#define SSL2_ST_GET_CLIENT_FINISHED_B (0x51|SSL_ST_ACCEPT) +#define SSL2_ST_SEND_SERVER_FINISHED_A (0x60|SSL_ST_ACCEPT) +#define SSL2_ST_SEND_SERVER_FINISHED_B (0x61|SSL_ST_ACCEPT) +#define SSL2_ST_SEND_REQUEST_CERTIFICATE_A (0x70|SSL_ST_ACCEPT) +#define SSL2_ST_SEND_REQUEST_CERTIFICATE_B (0x71|SSL_ST_ACCEPT) +#define SSL2_ST_SEND_REQUEST_CERTIFICATE_C (0x72|SSL_ST_ACCEPT) +#define SSL2_ST_SEND_REQUEST_CERTIFICATE_D (0x73|SSL_ST_ACCEPT) +#define SSL2_ST_SERVER_START_ENCRYPTION (0x80|SSL_ST_ACCEPT) +#define SSL2_ST_X509_GET_SERVER_CERTIFICATE (0x90|SSL_ST_ACCEPT) + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/lib_tls/include/openssl/ssl23.h b/lib_tls/include/openssl/ssl23.h new file mode 100644 index 000000000..d3228983c --- /dev/null +++ b/lib_tls/include/openssl/ssl23.h @@ -0,0 +1,83 @@ +/* ssl/ssl23.h */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#ifndef HEADER_SSL23_H +#define HEADER_SSL23_H + +#ifdef __cplusplus +extern "C" { +#endif + +/*client */ +/* write to server */ +#define SSL23_ST_CW_CLNT_HELLO_A (0x210|SSL_ST_CONNECT) +#define SSL23_ST_CW_CLNT_HELLO_B (0x211|SSL_ST_CONNECT) +/* read from server */ +#define SSL23_ST_CR_SRVR_HELLO_A (0x220|SSL_ST_CONNECT) +#define SSL23_ST_CR_SRVR_HELLO_B (0x221|SSL_ST_CONNECT) + +/* server */ +/* read from client */ +#define SSL23_ST_SR_CLNT_HELLO_A (0x210|SSL_ST_ACCEPT) +#define SSL23_ST_SR_CLNT_HELLO_B (0x211|SSL_ST_ACCEPT) + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/lib_tls/include/openssl/ssl3.h b/lib_tls/include/openssl/ssl3.h new file mode 100644 index 000000000..4b1e2e983 --- /dev/null +++ b/lib_tls/include/openssl/ssl3.h @@ -0,0 +1,565 @@ +/* ssl/ssl3.h */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2002 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * ECC cipher suite support in OpenSSL originally developed by + * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project. + */ + +#ifndef HEADER_SSL3_H +#define HEADER_SSL3_H + +#ifndef OPENSSL_NO_COMP +#include +#endif +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define SSL3_CK_RSA_NULL_MD5 0x03000001 +#define SSL3_CK_RSA_NULL_SHA 0x03000002 +#define SSL3_CK_RSA_RC4_40_MD5 0x03000003 +#define SSL3_CK_RSA_RC4_128_MD5 0x03000004 +#define SSL3_CK_RSA_RC4_128_SHA 0x03000005 +#define SSL3_CK_RSA_RC2_40_MD5 0x03000006 +#define SSL3_CK_RSA_IDEA_128_SHA 0x03000007 +#define SSL3_CK_RSA_DES_40_CBC_SHA 0x03000008 +#define SSL3_CK_RSA_DES_64_CBC_SHA 0x03000009 +#define SSL3_CK_RSA_DES_192_CBC3_SHA 0x0300000A + +#define SSL3_CK_DH_DSS_DES_40_CBC_SHA 0x0300000B +#define SSL3_CK_DH_DSS_DES_64_CBC_SHA 0x0300000C +#define SSL3_CK_DH_DSS_DES_192_CBC3_SHA 0x0300000D +#define SSL3_CK_DH_RSA_DES_40_CBC_SHA 0x0300000E +#define SSL3_CK_DH_RSA_DES_64_CBC_SHA 0x0300000F +#define SSL3_CK_DH_RSA_DES_192_CBC3_SHA 0x03000010 + +#define SSL3_CK_EDH_DSS_DES_40_CBC_SHA 0x03000011 +#define SSL3_CK_EDH_DSS_DES_64_CBC_SHA 0x03000012 +#define SSL3_CK_EDH_DSS_DES_192_CBC3_SHA 0x03000013 +#define SSL3_CK_EDH_RSA_DES_40_CBC_SHA 0x03000014 +#define SSL3_CK_EDH_RSA_DES_64_CBC_SHA 0x03000015 +#define SSL3_CK_EDH_RSA_DES_192_CBC3_SHA 0x03000016 + +#define SSL3_CK_ADH_RC4_40_MD5 0x03000017 +#define SSL3_CK_ADH_RC4_128_MD5 0x03000018 +#define SSL3_CK_ADH_DES_40_CBC_SHA 0x03000019 +#define SSL3_CK_ADH_DES_64_CBC_SHA 0x0300001A +#define SSL3_CK_ADH_DES_192_CBC_SHA 0x0300001B + +#define SSL3_CK_FZA_DMS_NULL_SHA 0x0300001C +#define SSL3_CK_FZA_DMS_FZA_SHA 0x0300001D +#if 0 /* Because it clashes with KRB5, is never used any more, and is safe + to remove according to David Hopwood + of the ietf-tls list */ +#define SSL3_CK_FZA_DMS_RC4_SHA 0x0300001E +#endif + +/* VRS Additional Kerberos5 entries + */ +#define SSL3_CK_KRB5_DES_64_CBC_SHA 0x0300001E +#define SSL3_CK_KRB5_DES_192_CBC3_SHA 0x0300001F +#define SSL3_CK_KRB5_RC4_128_SHA 0x03000020 +#define SSL3_CK_KRB5_IDEA_128_CBC_SHA 0x03000021 +#define SSL3_CK_KRB5_DES_64_CBC_MD5 0x03000022 +#define SSL3_CK_KRB5_DES_192_CBC3_MD5 0x03000023 +#define SSL3_CK_KRB5_RC4_128_MD5 0x03000024 +#define SSL3_CK_KRB5_IDEA_128_CBC_MD5 0x03000025 + +#define SSL3_CK_KRB5_DES_40_CBC_SHA 0x03000026 +#define SSL3_CK_KRB5_RC2_40_CBC_SHA 0x03000027 +#define SSL3_CK_KRB5_RC4_40_SHA 0x03000028 +#define SSL3_CK_KRB5_DES_40_CBC_MD5 0x03000029 +#define SSL3_CK_KRB5_RC2_40_CBC_MD5 0x0300002A +#define SSL3_CK_KRB5_RC4_40_MD5 0x0300002B + +#define SSL3_TXT_RSA_NULL_MD5 "NULL-MD5" +#define SSL3_TXT_RSA_NULL_SHA "NULL-SHA" +#define SSL3_TXT_RSA_RC4_40_MD5 "EXP-RC4-MD5" +#define SSL3_TXT_RSA_RC4_128_MD5 "RC4-MD5" +#define SSL3_TXT_RSA_RC4_128_SHA "RC4-SHA" +#define SSL3_TXT_RSA_RC2_40_MD5 "EXP-RC2-CBC-MD5" +#define SSL3_TXT_RSA_IDEA_128_SHA "IDEA-CBC-SHA" +#define SSL3_TXT_RSA_DES_40_CBC_SHA "EXP-DES-CBC-SHA" +#define SSL3_TXT_RSA_DES_64_CBC_SHA "DES-CBC-SHA" +#define SSL3_TXT_RSA_DES_192_CBC3_SHA "DES-CBC3-SHA" + +#define SSL3_TXT_DH_DSS_DES_40_CBC_SHA "EXP-DH-DSS-DES-CBC-SHA" +#define SSL3_TXT_DH_DSS_DES_64_CBC_SHA "DH-DSS-DES-CBC-SHA" +#define SSL3_TXT_DH_DSS_DES_192_CBC3_SHA "DH-DSS-DES-CBC3-SHA" +#define SSL3_TXT_DH_RSA_DES_40_CBC_SHA "EXP-DH-RSA-DES-CBC-SHA" +#define SSL3_TXT_DH_RSA_DES_64_CBC_SHA "DH-RSA-DES-CBC-SHA" +#define SSL3_TXT_DH_RSA_DES_192_CBC3_SHA "DH-RSA-DES-CBC3-SHA" + +#define SSL3_TXT_EDH_DSS_DES_40_CBC_SHA "EXP-EDH-DSS-DES-CBC-SHA" +#define SSL3_TXT_EDH_DSS_DES_64_CBC_SHA "EDH-DSS-DES-CBC-SHA" +#define SSL3_TXT_EDH_DSS_DES_192_CBC3_SHA "EDH-DSS-DES-CBC3-SHA" +#define SSL3_TXT_EDH_RSA_DES_40_CBC_SHA "EXP-EDH-RSA-DES-CBC-SHA" +#define SSL3_TXT_EDH_RSA_DES_64_CBC_SHA "EDH-RSA-DES-CBC-SHA" +#define SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA "EDH-RSA-DES-CBC3-SHA" + +#define SSL3_TXT_ADH_RC4_40_MD5 "EXP-ADH-RC4-MD5" +#define SSL3_TXT_ADH_RC4_128_MD5 "ADH-RC4-MD5" +#define SSL3_TXT_ADH_DES_40_CBC_SHA "EXP-ADH-DES-CBC-SHA" +#define SSL3_TXT_ADH_DES_64_CBC_SHA "ADH-DES-CBC-SHA" +#define SSL3_TXT_ADH_DES_192_CBC_SHA "ADH-DES-CBC3-SHA" + +#define SSL3_TXT_FZA_DMS_NULL_SHA "FZA-NULL-SHA" +#define SSL3_TXT_FZA_DMS_FZA_SHA "FZA-FZA-CBC-SHA" +#define SSL3_TXT_FZA_DMS_RC4_SHA "FZA-RC4-SHA" + +#define SSL3_TXT_KRB5_DES_64_CBC_SHA "KRB5-DES-CBC-SHA" +#define SSL3_TXT_KRB5_DES_192_CBC3_SHA "KRB5-DES-CBC3-SHA" +#define SSL3_TXT_KRB5_RC4_128_SHA "KRB5-RC4-SHA" +#define SSL3_TXT_KRB5_IDEA_128_CBC_SHA "KRB5-IDEA-CBC-SHA" +#define SSL3_TXT_KRB5_DES_64_CBC_MD5 "KRB5-DES-CBC-MD5" +#define SSL3_TXT_KRB5_DES_192_CBC3_MD5 "KRB5-DES-CBC3-MD5" +#define SSL3_TXT_KRB5_RC4_128_MD5 "KRB5-RC4-MD5" +#define SSL3_TXT_KRB5_IDEA_128_CBC_MD5 "KRB5-IDEA-CBC-MD5" + +#define SSL3_TXT_KRB5_DES_40_CBC_SHA "EXP-KRB5-DES-CBC-SHA" +#define SSL3_TXT_KRB5_RC2_40_CBC_SHA "EXP-KRB5-RC2-CBC-SHA" +#define SSL3_TXT_KRB5_RC4_40_SHA "EXP-KRB5-RC4-SHA" +#define SSL3_TXT_KRB5_DES_40_CBC_MD5 "EXP-KRB5-DES-CBC-MD5" +#define SSL3_TXT_KRB5_RC2_40_CBC_MD5 "EXP-KRB5-RC2-CBC-MD5" +#define SSL3_TXT_KRB5_RC4_40_MD5 "EXP-KRB5-RC4-MD5" + +#define SSL3_SSL_SESSION_ID_LENGTH 32 +#define SSL3_MAX_SSL_SESSION_ID_LENGTH 32 + +#define SSL3_MASTER_SECRET_SIZE 48 +#define SSL3_RANDOM_SIZE 32 +#define SSL3_SESSION_ID_SIZE 32 +#define SSL3_RT_HEADER_LENGTH 5 + +/* Due to MS stuffing up, this can change.... */ +#if defined(OPENSSL_SYS_WIN16) || \ + (defined(OPENSSL_SYS_MSDOS) && !defined(OPENSSL_SYS_WIN32)) +#define SSL3_RT_MAX_EXTRA (14000) +#else +#define SSL3_RT_MAX_EXTRA (16384) +#endif + +#define SSL3_RT_MAX_PLAIN_LENGTH 16384 +#ifdef OPENSSL_NO_COMP +#define SSL3_RT_MAX_COMPRESSED_LENGTH SSL3_RT_MAX_PLAIN_LENGTH +#else +#define SSL3_RT_MAX_COMPRESSED_LENGTH (1024+SSL3_RT_MAX_PLAIN_LENGTH) +#endif +#define SSL3_RT_MAX_ENCRYPTED_LENGTH (1024+SSL3_RT_MAX_COMPRESSED_LENGTH) +#define SSL3_RT_MAX_PACKET_SIZE (SSL3_RT_MAX_ENCRYPTED_LENGTH+SSL3_RT_HEADER_LENGTH) +#define SSL3_RT_MAX_DATA_SIZE (1024*1024) + +#define SSL3_MD_CLIENT_FINISHED_CONST "\x43\x4C\x4E\x54" +#define SSL3_MD_SERVER_FINISHED_CONST "\x53\x52\x56\x52" + +#define SSL3_VERSION 0x0300 +#define SSL3_VERSION_MAJOR 0x03 +#define SSL3_VERSION_MINOR 0x00 + +#define SSL3_RT_CHANGE_CIPHER_SPEC 20 +#define SSL3_RT_ALERT 21 +#define SSL3_RT_HANDSHAKE 22 +#define SSL3_RT_APPLICATION_DATA 23 + +#define SSL3_AL_WARNING 1 +#define SSL3_AL_FATAL 2 + +#define SSL3_AD_CLOSE_NOTIFY 0 +#define SSL3_AD_UNEXPECTED_MESSAGE 10 /* fatal */ +#define SSL3_AD_BAD_RECORD_MAC 20 /* fatal */ +#define SSL3_AD_DECOMPRESSION_FAILURE 30 /* fatal */ +#define SSL3_AD_HANDSHAKE_FAILURE 40 /* fatal */ +#define SSL3_AD_NO_CERTIFICATE 41 +#define SSL3_AD_BAD_CERTIFICATE 42 +#define SSL3_AD_UNSUPPORTED_CERTIFICATE 43 +#define SSL3_AD_CERTIFICATE_REVOKED 44 +#define SSL3_AD_CERTIFICATE_EXPIRED 45 +#define SSL3_AD_CERTIFICATE_UNKNOWN 46 +#define SSL3_AD_ILLEGAL_PARAMETER 47 /* fatal */ + +typedef struct ssl3_record_st + { +/*r */ int type; /* type of record */ +/*rw*/ unsigned int length; /* How many bytes available */ +/*r */ unsigned int off; /* read/write offset into 'buf' */ +/*rw*/ unsigned char *data; /* pointer to the record data */ +/*rw*/ unsigned char *input; /* where the decode bytes are */ +/*r */ unsigned char *comp; /* only used with decompression - malloc()ed */ +/*r */ unsigned long epoch; /* epoch number, needed by DTLS1 */ +/*r */ PQ_64BIT seq_num; /* sequence number, needed by DTLS1 */ + } SSL3_RECORD; + +typedef struct ssl3_buffer_st + { + unsigned char *buf; /* at least SSL3_RT_MAX_PACKET_SIZE bytes, + * see ssl3_setup_buffers() */ + size_t len; /* buffer size */ + int offset; /* where to 'copy from' */ + int left; /* how many bytes left */ + } SSL3_BUFFER; + +#define SSL3_CT_RSA_SIGN 1 +#define SSL3_CT_DSS_SIGN 2 +#define SSL3_CT_RSA_FIXED_DH 3 +#define SSL3_CT_DSS_FIXED_DH 4 +#define SSL3_CT_RSA_EPHEMERAL_DH 5 +#define SSL3_CT_DSS_EPHEMERAL_DH 6 +#define SSL3_CT_FORTEZZA_DMS 20 +/* SSL3_CT_NUMBER is used to size arrays and it must be large + * enough to contain all of the cert types defined either for + * SSLv3 and TLSv1. + */ +#define SSL3_CT_NUMBER 7 + + +#define SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS 0x0001 +#define SSL3_FLAGS_DELAY_CLIENT_FINISHED 0x0002 +#define SSL3_FLAGS_POP_BUFFER 0x0004 +#define TLS1_FLAGS_TLS_PADDING_BUG 0x0008 + +typedef struct ssl3_state_st + { + long flags; + int delay_buf_pop_ret; + + unsigned char read_sequence[8]; + unsigned char read_mac_secret[EVP_MAX_MD_SIZE]; + unsigned char write_sequence[8]; + unsigned char write_mac_secret[EVP_MAX_MD_SIZE]; + + unsigned char server_random[SSL3_RANDOM_SIZE]; + unsigned char client_random[SSL3_RANDOM_SIZE]; + + /* flags for countermeasure against known-IV weakness */ + int need_empty_fragments; + int empty_fragment_done; + + SSL3_BUFFER rbuf; /* read IO goes into here */ + SSL3_BUFFER wbuf; /* write IO goes into here */ + + SSL3_RECORD rrec; /* each decoded record goes in here */ + SSL3_RECORD wrec; /* goes out from here */ + + /* storage for Alert/Handshake protocol data received but not + * yet processed by ssl3_read_bytes: */ + unsigned char alert_fragment[2]; + unsigned int alert_fragment_len; + unsigned char handshake_fragment[4]; + unsigned int handshake_fragment_len; + + /* partial write - check the numbers match */ + unsigned int wnum; /* number of bytes sent so far */ + int wpend_tot; /* number bytes written */ + int wpend_type; + int wpend_ret; /* number of bytes submitted */ + const unsigned char *wpend_buf; + + /* used during startup, digest all incoming/outgoing packets */ + EVP_MD_CTX finish_dgst1; + EVP_MD_CTX finish_dgst2; + + /* this is set whenerver we see a change_cipher_spec message + * come in when we are not looking for one */ + int change_cipher_spec; + + int warn_alert; + int fatal_alert; + /* we allow one fatal and one warning alert to be outstanding, + * send close alert via the warning alert */ + int alert_dispatch; + unsigned char send_alert[2]; + + /* This flag is set when we should renegotiate ASAP, basically when + * there is no more data in the read or write buffers */ + int renegotiate; + int total_renegotiations; + int num_renegotiations; + + int in_read_app_data; + + struct { + /* actually only needs to be 16+20 */ + unsigned char cert_verify_md[EVP_MAX_MD_SIZE*2]; + + /* actually only need to be 16+20 for SSLv3 and 12 for TLS */ + unsigned char finish_md[EVP_MAX_MD_SIZE*2]; + int finish_md_len; + unsigned char peer_finish_md[EVP_MAX_MD_SIZE*2]; + int peer_finish_md_len; + + unsigned long message_size; + int message_type; + + /* used to hold the new cipher we are going to use */ + SSL_CIPHER *new_cipher; +#ifndef OPENSSL_NO_DH + DH *dh; +#endif + +#ifndef OPENSSL_NO_ECDH + EC_KEY *ecdh; /* holds short lived ECDH key */ +#endif + + /* used when SSL_ST_FLUSH_DATA is entered */ + int next_state; + + int reuse_message; + + /* used for certificate requests */ + int cert_req; + int ctype_num; + char ctype[SSL3_CT_NUMBER]; + STACK_OF(X509_NAME) *ca_names; + + int use_rsa_tmp; + + int key_block_length; + unsigned char *key_block; + + const EVP_CIPHER *new_sym_enc; + const EVP_MD *new_hash; +#ifndef OPENSSL_NO_COMP + const SSL_COMP *new_compression; +#else + char *new_compression; +#endif + int cert_request; + } tmp; + + } SSL3_STATE; + + +/* SSLv3 */ +/*client */ +/* extra state */ +#define SSL3_ST_CW_FLUSH (0x100|SSL_ST_CONNECT) +/* write to server */ +#define SSL3_ST_CW_CLNT_HELLO_A (0x110|SSL_ST_CONNECT) +#define SSL3_ST_CW_CLNT_HELLO_B (0x111|SSL_ST_CONNECT) +/* read from server */ +#define SSL3_ST_CR_SRVR_HELLO_A (0x120|SSL_ST_CONNECT) +#define SSL3_ST_CR_SRVR_HELLO_B (0x121|SSL_ST_CONNECT) +#define DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A (0x126|SSL_ST_CONNECT) +#define DTLS1_ST_CR_HELLO_VERIFY_REQUEST_B (0x127|SSL_ST_CONNECT) +#define SSL3_ST_CR_CERT_A (0x130|SSL_ST_CONNECT) +#define SSL3_ST_CR_CERT_B (0x131|SSL_ST_CONNECT) +#define SSL3_ST_CR_KEY_EXCH_A (0x140|SSL_ST_CONNECT) +#define SSL3_ST_CR_KEY_EXCH_B (0x141|SSL_ST_CONNECT) +#define SSL3_ST_CR_CERT_REQ_A (0x150|SSL_ST_CONNECT) +#define SSL3_ST_CR_CERT_REQ_B (0x151|SSL_ST_CONNECT) +#define SSL3_ST_CR_SRVR_DONE_A (0x160|SSL_ST_CONNECT) +#define SSL3_ST_CR_SRVR_DONE_B (0x161|SSL_ST_CONNECT) +/* write to server */ +#define SSL3_ST_CW_CERT_A (0x170|SSL_ST_CONNECT) +#define SSL3_ST_CW_CERT_B (0x171|SSL_ST_CONNECT) +#define SSL3_ST_CW_CERT_C (0x172|SSL_ST_CONNECT) +#define SSL3_ST_CW_CERT_D (0x173|SSL_ST_CONNECT) +#define SSL3_ST_CW_KEY_EXCH_A (0x180|SSL_ST_CONNECT) +#define SSL3_ST_CW_KEY_EXCH_B (0x181|SSL_ST_CONNECT) +#define SSL3_ST_CW_CERT_VRFY_A (0x190|SSL_ST_CONNECT) +#define SSL3_ST_CW_CERT_VRFY_B (0x191|SSL_ST_CONNECT) +#define SSL3_ST_CW_CHANGE_A (0x1A0|SSL_ST_CONNECT) +#define SSL3_ST_CW_CHANGE_B (0x1A1|SSL_ST_CONNECT) +#define SSL3_ST_CW_FINISHED_A (0x1B0|SSL_ST_CONNECT) +#define SSL3_ST_CW_FINISHED_B (0x1B1|SSL_ST_CONNECT) +/* read from server */ +#define SSL3_ST_CR_CHANGE_A (0x1C0|SSL_ST_CONNECT) +#define SSL3_ST_CR_CHANGE_B (0x1C1|SSL_ST_CONNECT) +#define SSL3_ST_CR_FINISHED_A (0x1D0|SSL_ST_CONNECT) +#define SSL3_ST_CR_FINISHED_B (0x1D1|SSL_ST_CONNECT) +#define SSL3_ST_CR_SESSION_TICKET_A (0x1E0|SSL_ST_CONNECT) +#define SSL3_ST_CR_SESSION_TICKET_B (0x1E1|SSL_ST_CONNECT) +#define SSL3_ST_CR_CERT_STATUS_A (0x1F0|SSL_ST_CONNECT) +#define SSL3_ST_CR_CERT_STATUS_B (0x1F1|SSL_ST_CONNECT) + +/* server */ +/* extra state */ +#define SSL3_ST_SW_FLUSH (0x100|SSL_ST_ACCEPT) +/* read from client */ +/* Do not change the number values, they do matter */ +#define SSL3_ST_SR_CLNT_HELLO_A (0x110|SSL_ST_ACCEPT) +#define SSL3_ST_SR_CLNT_HELLO_B (0x111|SSL_ST_ACCEPT) +#define SSL3_ST_SR_CLNT_HELLO_C (0x112|SSL_ST_ACCEPT) +/* write to client */ +#define DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A (0x113|SSL_ST_ACCEPT) +#define DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B (0x114|SSL_ST_ACCEPT) +#define SSL3_ST_SW_HELLO_REQ_A (0x120|SSL_ST_ACCEPT) +#define SSL3_ST_SW_HELLO_REQ_B (0x121|SSL_ST_ACCEPT) +#define SSL3_ST_SW_HELLO_REQ_C (0x122|SSL_ST_ACCEPT) +#define SSL3_ST_SW_SRVR_HELLO_A (0x130|SSL_ST_ACCEPT) +#define SSL3_ST_SW_SRVR_HELLO_B (0x131|SSL_ST_ACCEPT) +#define SSL3_ST_SW_CERT_A (0x140|SSL_ST_ACCEPT) +#define SSL3_ST_SW_CERT_B (0x141|SSL_ST_ACCEPT) +#define SSL3_ST_SW_KEY_EXCH_A (0x150|SSL_ST_ACCEPT) +#define SSL3_ST_SW_KEY_EXCH_B (0x151|SSL_ST_ACCEPT) +#define SSL3_ST_SW_CERT_REQ_A (0x160|SSL_ST_ACCEPT) +#define SSL3_ST_SW_CERT_REQ_B (0x161|SSL_ST_ACCEPT) +#define SSL3_ST_SW_SRVR_DONE_A (0x170|SSL_ST_ACCEPT) +#define SSL3_ST_SW_SRVR_DONE_B (0x171|SSL_ST_ACCEPT) +/* read from client */ +#define SSL3_ST_SR_CERT_A (0x180|SSL_ST_ACCEPT) +#define SSL3_ST_SR_CERT_B (0x181|SSL_ST_ACCEPT) +#define SSL3_ST_SR_KEY_EXCH_A (0x190|SSL_ST_ACCEPT) +#define SSL3_ST_SR_KEY_EXCH_B (0x191|SSL_ST_ACCEPT) +#define SSL3_ST_SR_CERT_VRFY_A (0x1A0|SSL_ST_ACCEPT) +#define SSL3_ST_SR_CERT_VRFY_B (0x1A1|SSL_ST_ACCEPT) +#define SSL3_ST_SR_CHANGE_A (0x1B0|SSL_ST_ACCEPT) +#define SSL3_ST_SR_CHANGE_B (0x1B1|SSL_ST_ACCEPT) +#define SSL3_ST_SR_FINISHED_A (0x1C0|SSL_ST_ACCEPT) +#define SSL3_ST_SR_FINISHED_B (0x1C1|SSL_ST_ACCEPT) +/* write to client */ +#define SSL3_ST_SW_CHANGE_A (0x1D0|SSL_ST_ACCEPT) +#define SSL3_ST_SW_CHANGE_B (0x1D1|SSL_ST_ACCEPT) +#define SSL3_ST_SW_FINISHED_A (0x1E0|SSL_ST_ACCEPT) +#define SSL3_ST_SW_FINISHED_B (0x1E1|SSL_ST_ACCEPT) +#define SSL3_ST_SW_SESSION_TICKET_A (0x1F0|SSL_ST_ACCEPT) +#define SSL3_ST_SW_SESSION_TICKET_B (0x1F1|SSL_ST_ACCEPT) +#define SSL3_ST_SW_CERT_STATUS_A (0x200|SSL_ST_ACCEPT) +#define SSL3_ST_SW_CERT_STATUS_B (0x201|SSL_ST_ACCEPT) + +#define SSL3_MT_HELLO_REQUEST 0 +#define SSL3_MT_CLIENT_HELLO 1 +#define SSL3_MT_SERVER_HELLO 2 +#define SSL3_MT_NEWSESSION_TICKET 4 +#define SSL3_MT_CERTIFICATE 11 +#define SSL3_MT_SERVER_KEY_EXCHANGE 12 +#define SSL3_MT_CERTIFICATE_REQUEST 13 +#define SSL3_MT_SERVER_DONE 14 +#define SSL3_MT_CERTIFICATE_VERIFY 15 +#define SSL3_MT_CLIENT_KEY_EXCHANGE 16 +#define SSL3_MT_FINISHED 20 +#define SSL3_MT_CERTIFICATE_STATUS 22 +#define DTLS1_MT_HELLO_VERIFY_REQUEST 3 + + +#define SSL3_MT_CCS 1 + +/* These are used when changing over to a new cipher */ +#define SSL3_CC_READ 0x01 +#define SSL3_CC_WRITE 0x02 +#define SSL3_CC_CLIENT 0x10 +#define SSL3_CC_SERVER 0x20 +#define SSL3_CHANGE_CIPHER_CLIENT_WRITE (SSL3_CC_CLIENT|SSL3_CC_WRITE) +#define SSL3_CHANGE_CIPHER_SERVER_READ (SSL3_CC_SERVER|SSL3_CC_READ) +#define SSL3_CHANGE_CIPHER_CLIENT_READ (SSL3_CC_CLIENT|SSL3_CC_READ) +#define SSL3_CHANGE_CIPHER_SERVER_WRITE (SSL3_CC_SERVER|SSL3_CC_WRITE) + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/lib_tls/include/openssl/stack.h b/lib_tls/include/openssl/stack.h new file mode 100644 index 000000000..5cbb116a8 --- /dev/null +++ b/lib_tls/include/openssl/stack.h @@ -0,0 +1,109 @@ +/* crypto/stack/stack.h */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#ifndef HEADER_STACK_H +#define HEADER_STACK_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct stack_st + { + int num; + char **data; + int sorted; + + int num_alloc; + int (*comp)(const char * const *, const char * const *); + } STACK; + +#define M_sk_num(sk) ((sk) ? (sk)->num:-1) +#define M_sk_value(sk,n) ((sk) ? (sk)->data[n] : NULL) + +int sk_num(const STACK *); +char *sk_value(const STACK *, int); + +char *sk_set(STACK *, int, char *); + +STACK *sk_new(int (*cmp)(const char * const *, const char * const *)); +STACK *sk_new_null(void); +void sk_free(STACK *); +void sk_pop_free(STACK *st, void (*func)(void *)); +int sk_insert(STACK *sk,char *data,int where); +char *sk_delete(STACK *st,int loc); +char *sk_delete_ptr(STACK *st, char *p); +int sk_find(STACK *st,char *data); +int sk_find_ex(STACK *st,char *data); +int sk_push(STACK *st,char *data); +int sk_unshift(STACK *st,char *data); +char *sk_shift(STACK *st); +char *sk_pop(STACK *st); +void sk_zero(STACK *st); +int (*sk_set_cmp_func(STACK *sk, int (*c)(const char * const *, + const char * const *))) + (const char * const *, const char * const *); +STACK *sk_dup(STACK *st); +void sk_sort(STACK *st); +int sk_is_sorted(const STACK *st); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_tls/include/openssl/store.h b/lib_tls/include/openssl/store.h new file mode 100644 index 000000000..64583377a --- /dev/null +++ b/lib_tls/include/openssl/store.h @@ -0,0 +1,554 @@ +/* crypto/store/store.h -*- mode:C; c-file-style: "eay" -*- */ +/* Written by Richard Levitte (richard@levitte.org) for the OpenSSL + * project 2003. + */ +/* ==================================================================== + * Copyright (c) 2003 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#ifndef HEADER_STORE_H +#define HEADER_STORE_H + +#include +#ifndef OPENSSL_NO_DEPRECATED +#include +#include +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* Already defined in ossl_typ.h */ +/* typedef struct store_st STORE; */ +/* typedef struct store_method_st STORE_METHOD; */ + + +/* All the following functions return 0, a negative number or NULL on error. + When everything is fine, they return a positive value or a non-NULL + pointer, all depending on their purpose. */ + +/* Creators and destructor. */ +STORE *STORE_new_method(const STORE_METHOD *method); +STORE *STORE_new_engine(ENGINE *engine); +void STORE_free(STORE *ui); + + +/* Give a user interface parametrised control commands. This can be used to + send down an integer, a data pointer or a function pointer, as well as + be used to get information from a STORE. */ +int STORE_ctrl(STORE *store, int cmd, long i, void *p, void (*f)(void)); + +/* A control to set the directory with keys and certificates. Used by the + built-in directory level method. */ +#define STORE_CTRL_SET_DIRECTORY 0x0001 +/* A control to set a file to load. Used by the built-in file level method. */ +#define STORE_CTRL_SET_FILE 0x0002 +/* A control to set a configuration file to load. Can be used by any method + that wishes to load a configuration file. */ +#define STORE_CTRL_SET_CONF_FILE 0x0003 +/* A control to set a the section of the loaded configuration file. Can be + used by any method that wishes to load a configuration file. */ +#define STORE_CTRL_SET_CONF_SECTION 0x0004 + + +/* Some methods may use extra data */ +#define STORE_set_app_data(s,arg) STORE_set_ex_data(s,0,arg) +#define STORE_get_app_data(s) STORE_get_ex_data(s,0) +int STORE_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func, + CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func); +int STORE_set_ex_data(STORE *r,int idx,void *arg); +void *STORE_get_ex_data(STORE *r, int idx); + +/* Use specific methods instead of the built-in one */ +const STORE_METHOD *STORE_get_method(STORE *store); +const STORE_METHOD *STORE_set_method(STORE *store, const STORE_METHOD *meth); + +/* The standard OpenSSL methods. */ +/* This is the in-memory method. It does everything except revoking and updating, + and is of course volatile. It's used by other methods that have an in-memory + cache. */ +const STORE_METHOD *STORE_Memory(void); +#if 0 /* Not yet implemented */ +/* This is the directory store. It does everything except revoking and updating, + and uses STORE_Memory() to cache things in memory. */ +const STORE_METHOD *STORE_Directory(void); +/* This is the file store. It does everything except revoking and updating, + and uses STORE_Memory() to cache things in memory. Certificates are added + to it with the store operation, and it will only get cached certificates. */ +const STORE_METHOD *STORE_File(void); +#endif + +/* Store functions take a type code for the type of data they should store + or fetch */ +typedef enum STORE_object_types + { + STORE_OBJECT_TYPE_X509_CERTIFICATE= 0x01, /* X509 * */ + STORE_OBJECT_TYPE_X509_CRL= 0x02, /* X509_CRL * */ + STORE_OBJECT_TYPE_PRIVATE_KEY= 0x03, /* EVP_PKEY * */ + STORE_OBJECT_TYPE_PUBLIC_KEY= 0x04, /* EVP_PKEY * */ + STORE_OBJECT_TYPE_NUMBER= 0x05, /* BIGNUM * */ + STORE_OBJECT_TYPE_ARBITRARY= 0x06, /* BUF_MEM * */ + STORE_OBJECT_TYPE_NUM= 0x06 /* The amount of known + object types */ + } STORE_OBJECT_TYPES; +/* List of text strings corresponding to the object types. */ +extern const char * const STORE_object_type_string[STORE_OBJECT_TYPE_NUM+1]; + +/* Some store functions take a parameter list. Those parameters come with + one of the following codes. The comments following the codes below indicate + what type the value should be a pointer to. */ +typedef enum STORE_params + { + STORE_PARAM_EVP_TYPE= 0x01, /* int */ + STORE_PARAM_BITS= 0x02, /* size_t */ + STORE_PARAM_KEY_PARAMETERS= 0x03, /* ??? */ + STORE_PARAM_KEY_NO_PARAMETERS= 0x04, /* N/A */ + STORE_PARAM_AUTH_PASSPHRASE= 0x05, /* char * */ + STORE_PARAM_AUTH_KRB5_TICKET= 0x06, /* void * */ + STORE_PARAM_TYPE_NUM= 0x06 /* The amount of known + parameter types */ + } STORE_PARAM_TYPES; +/* Parameter value sizes. -1 means unknown, anything else is the required size. */ +extern const int STORE_param_sizes[STORE_PARAM_TYPE_NUM+1]; + +/* Store functions take attribute lists. Those attributes come with codes. + The comments following the codes below indicate what type the value should + be a pointer to. */ +typedef enum STORE_attribs + { + STORE_ATTR_END= 0x00, + STORE_ATTR_FRIENDLYNAME= 0x01, /* C string */ + STORE_ATTR_KEYID= 0x02, /* 160 bit string (SHA1) */ + STORE_ATTR_ISSUERKEYID= 0x03, /* 160 bit string (SHA1) */ + STORE_ATTR_SUBJECTKEYID= 0x04, /* 160 bit string (SHA1) */ + STORE_ATTR_ISSUERSERIALHASH= 0x05, /* 160 bit string (SHA1) */ + STORE_ATTR_ISSUER= 0x06, /* X509_NAME * */ + STORE_ATTR_SERIAL= 0x07, /* BIGNUM * */ + STORE_ATTR_SUBJECT= 0x08, /* X509_NAME * */ + STORE_ATTR_CERTHASH= 0x09, /* 160 bit string (SHA1) */ + STORE_ATTR_EMAIL= 0x0a, /* C string */ + STORE_ATTR_FILENAME= 0x0b, /* C string */ + STORE_ATTR_TYPE_NUM= 0x0b, /* The amount of known + attribute types */ + STORE_ATTR_OR= 0xff /* This is a special + separator, which + expresses the OR + operation. */ + } STORE_ATTR_TYPES; +/* Attribute value sizes. -1 means unknown, anything else is the required size. */ +extern const int STORE_attr_sizes[STORE_ATTR_TYPE_NUM+1]; + +typedef enum STORE_certificate_status + { + STORE_X509_VALID= 0x00, + STORE_X509_EXPIRED= 0x01, + STORE_X509_SUSPENDED= 0x02, + STORE_X509_REVOKED= 0x03 + } STORE_CERTIFICATE_STATUS; + +/* Engine store functions will return a structure that contains all the necessary + * information, including revokation status for certificates. This is really not + * needed for application authors, as the ENGINE framework functions will extract + * the OpenSSL-specific information when at all possible. However, for engine + * authors, it's crucial to know this structure. */ +typedef struct STORE_OBJECT_st + { + STORE_OBJECT_TYPES type; + union + { + struct + { + STORE_CERTIFICATE_STATUS status; + X509 *certificate; + } x509; + X509_CRL *crl; + EVP_PKEY *key; + BIGNUM *number; + BUF_MEM *arbitrary; + } data; + } STORE_OBJECT; +DECLARE_STACK_OF(STORE_OBJECT) +STORE_OBJECT *STORE_OBJECT_new(void); +void STORE_OBJECT_free(STORE_OBJECT *data); + + + +/* The following functions handle the storage. They return 0, a negative number + or NULL on error, anything else on success. */ +X509 *STORE_get_certificate(STORE *e, OPENSSL_ITEM attributes[], + OPENSSL_ITEM parameters[]); +int STORE_store_certificate(STORE *e, X509 *data, OPENSSL_ITEM attributes[], + OPENSSL_ITEM parameters[]); +int STORE_modify_certificate(STORE *e, OPENSSL_ITEM search_attributes[], + OPENSSL_ITEM add_attributes[], OPENSSL_ITEM modify_attributes[], + OPENSSL_ITEM delete_attributes[], OPENSSL_ITEM parameters[]); +int STORE_revoke_certificate(STORE *e, OPENSSL_ITEM attributes[], + OPENSSL_ITEM parameters[]); +int STORE_delete_certificate(STORE *e, OPENSSL_ITEM attributes[], + OPENSSL_ITEM parameters[]); +void *STORE_list_certificate_start(STORE *e, OPENSSL_ITEM attributes[], + OPENSSL_ITEM parameters[]); +X509 *STORE_list_certificate_next(STORE *e, void *handle); +int STORE_list_certificate_end(STORE *e, void *handle); +int STORE_list_certificate_endp(STORE *e, void *handle); +EVP_PKEY *STORE_generate_key(STORE *e, OPENSSL_ITEM attributes[], + OPENSSL_ITEM parameters[]); +EVP_PKEY *STORE_get_private_key(STORE *e, OPENSSL_ITEM attributes[], + OPENSSL_ITEM parameters[]); +int STORE_store_private_key(STORE *e, EVP_PKEY *data, + OPENSSL_ITEM attributes[], OPENSSL_ITEM parameters[]); +int STORE_modify_private_key(STORE *e, OPENSSL_ITEM search_attributes[], + OPENSSL_ITEM add_sttributes[], OPENSSL_ITEM modify_attributes[], + OPENSSL_ITEM delete_attributes[], OPENSSL_ITEM parameters[]); +int STORE_revoke_private_key(STORE *e, OPENSSL_ITEM attributes[], + OPENSSL_ITEM parameters[]); +int STORE_delete_private_key(STORE *e, OPENSSL_ITEM attributes[], + OPENSSL_ITEM parameters[]); +void *STORE_list_private_key_start(STORE *e, OPENSSL_ITEM attributes[], + OPENSSL_ITEM parameters[]); +EVP_PKEY *STORE_list_private_key_next(STORE *e, void *handle); +int STORE_list_private_key_end(STORE *e, void *handle); +int STORE_list_private_key_endp(STORE *e, void *handle); +EVP_PKEY *STORE_get_public_key(STORE *e, OPENSSL_ITEM attributes[], + OPENSSL_ITEM parameters[]); +int STORE_store_public_key(STORE *e, EVP_PKEY *data, OPENSSL_ITEM attributes[], + OPENSSL_ITEM parameters[]); +int STORE_modify_public_key(STORE *e, OPENSSL_ITEM search_attributes[], + OPENSSL_ITEM add_sttributes[], OPENSSL_ITEM modify_attributes[], + OPENSSL_ITEM delete_attributes[], OPENSSL_ITEM parameters[]); +int STORE_revoke_public_key(STORE *e, OPENSSL_ITEM attributes[], + OPENSSL_ITEM parameters[]); +int STORE_delete_public_key(STORE *e, OPENSSL_ITEM attributes[], + OPENSSL_ITEM parameters[]); +void *STORE_list_public_key_start(STORE *e, OPENSSL_ITEM attributes[], + OPENSSL_ITEM parameters[]); +EVP_PKEY *STORE_list_public_key_next(STORE *e, void *handle); +int STORE_list_public_key_end(STORE *e, void *handle); +int STORE_list_public_key_endp(STORE *e, void *handle); +X509_CRL *STORE_generate_crl(STORE *e, OPENSSL_ITEM attributes[], + OPENSSL_ITEM parameters[]); +X509_CRL *STORE_get_crl(STORE *e, OPENSSL_ITEM attributes[], + OPENSSL_ITEM parameters[]); +int STORE_store_crl(STORE *e, X509_CRL *data, OPENSSL_ITEM attributes[], + OPENSSL_ITEM parameters[]); +int STORE_modify_crl(STORE *e, OPENSSL_ITEM search_attributes[], + OPENSSL_ITEM add_sttributes[], OPENSSL_ITEM modify_attributes[], + OPENSSL_ITEM delete_attributes[], OPENSSL_ITEM parameters[]); +int STORE_delete_crl(STORE *e, OPENSSL_ITEM attributes[], + OPENSSL_ITEM parameters[]); +void *STORE_list_crl_start(STORE *e, OPENSSL_ITEM attributes[], + OPENSSL_ITEM parameters[]); +X509_CRL *STORE_list_crl_next(STORE *e, void *handle); +int STORE_list_crl_end(STORE *e, void *handle); +int STORE_list_crl_endp(STORE *e, void *handle); +int STORE_store_number(STORE *e, BIGNUM *data, OPENSSL_ITEM attributes[], + OPENSSL_ITEM parameters[]); +int STORE_modify_number(STORE *e, OPENSSL_ITEM search_attributes[], + OPENSSL_ITEM add_sttributes[], OPENSSL_ITEM modify_attributes[], + OPENSSL_ITEM delete_attributes[], OPENSSL_ITEM parameters[]); +BIGNUM *STORE_get_number(STORE *e, OPENSSL_ITEM attributes[], + OPENSSL_ITEM parameters[]); +int STORE_delete_number(STORE *e, OPENSSL_ITEM attributes[], + OPENSSL_ITEM parameters[]); +int STORE_store_arbitrary(STORE *e, BUF_MEM *data, OPENSSL_ITEM attributes[], + OPENSSL_ITEM parameters[]); +int STORE_modify_arbitrary(STORE *e, OPENSSL_ITEM search_attributes[], + OPENSSL_ITEM add_sttributes[], OPENSSL_ITEM modify_attributes[], + OPENSSL_ITEM delete_attributes[], OPENSSL_ITEM parameters[]); +BUF_MEM *STORE_get_arbitrary(STORE *e, OPENSSL_ITEM attributes[], + OPENSSL_ITEM parameters[]); +int STORE_delete_arbitrary(STORE *e, OPENSSL_ITEM attributes[], + OPENSSL_ITEM parameters[]); + + +/* Create and manipulate methods */ +STORE_METHOD *STORE_create_method(char *name); +void STORE_destroy_method(STORE_METHOD *store_method); + +/* These callback types are use for store handlers */ +typedef int (*STORE_INITIALISE_FUNC_PTR)(STORE *); +typedef void (*STORE_CLEANUP_FUNC_PTR)(STORE *); +typedef STORE_OBJECT *(*STORE_GENERATE_OBJECT_FUNC_PTR)(STORE *, STORE_OBJECT_TYPES type, OPENSSL_ITEM attributes[], OPENSSL_ITEM parameters[]); +typedef STORE_OBJECT *(*STORE_GET_OBJECT_FUNC_PTR)(STORE *, STORE_OBJECT_TYPES type, OPENSSL_ITEM attributes[], OPENSSL_ITEM parameters[]); +typedef void *(*STORE_START_OBJECT_FUNC_PTR)(STORE *, STORE_OBJECT_TYPES type, OPENSSL_ITEM attributes[], OPENSSL_ITEM parameters[]); +typedef STORE_OBJECT *(*STORE_NEXT_OBJECT_FUNC_PTR)(STORE *, void *handle); +typedef int (*STORE_END_OBJECT_FUNC_PTR)(STORE *, void *handle); +typedef int (*STORE_HANDLE_OBJECT_FUNC_PTR)(STORE *, STORE_OBJECT_TYPES type, OPENSSL_ITEM attributes[], OPENSSL_ITEM parameters[]); +typedef int (*STORE_STORE_OBJECT_FUNC_PTR)(STORE *, STORE_OBJECT_TYPES type, STORE_OBJECT *data, OPENSSL_ITEM attributes[], OPENSSL_ITEM parameters[]); +typedef int (*STORE_MODIFY_OBJECT_FUNC_PTR)(STORE *, STORE_OBJECT_TYPES type, OPENSSL_ITEM search_attributes[], OPENSSL_ITEM add_attributes[], OPENSSL_ITEM modify_attributes[], OPENSSL_ITEM delete_attributes[], OPENSSL_ITEM parameters[]); +typedef int (*STORE_GENERIC_FUNC_PTR)(STORE *, OPENSSL_ITEM attributes[], OPENSSL_ITEM parameters[]); +typedef int (*STORE_CTRL_FUNC_PTR)(STORE *, int cmd, long l, void *p, void (*f)(void)); + +int STORE_method_set_initialise_function(STORE_METHOD *sm, STORE_INITIALISE_FUNC_PTR init_f); +int STORE_method_set_cleanup_function(STORE_METHOD *sm, STORE_CLEANUP_FUNC_PTR clean_f); +int STORE_method_set_generate_function(STORE_METHOD *sm, STORE_GENERATE_OBJECT_FUNC_PTR generate_f); +int STORE_method_set_get_function(STORE_METHOD *sm, STORE_GET_OBJECT_FUNC_PTR get_f); +int STORE_method_set_store_function(STORE_METHOD *sm, STORE_STORE_OBJECT_FUNC_PTR store_f); +int STORE_method_set_modify_function(STORE_METHOD *sm, STORE_MODIFY_OBJECT_FUNC_PTR store_f); +int STORE_method_set_revoke_function(STORE_METHOD *sm, STORE_HANDLE_OBJECT_FUNC_PTR revoke_f); +int STORE_method_set_delete_function(STORE_METHOD *sm, STORE_HANDLE_OBJECT_FUNC_PTR delete_f); +int STORE_method_set_list_start_function(STORE_METHOD *sm, STORE_START_OBJECT_FUNC_PTR list_start_f); +int STORE_method_set_list_next_function(STORE_METHOD *sm, STORE_NEXT_OBJECT_FUNC_PTR list_next_f); +int STORE_method_set_list_end_function(STORE_METHOD *sm, STORE_END_OBJECT_FUNC_PTR list_end_f); +int STORE_method_set_update_store_function(STORE_METHOD *sm, STORE_GENERIC_FUNC_PTR); +int STORE_method_set_lock_store_function(STORE_METHOD *sm, STORE_GENERIC_FUNC_PTR); +int STORE_method_set_unlock_store_function(STORE_METHOD *sm, STORE_GENERIC_FUNC_PTR); +int STORE_method_set_ctrl_function(STORE_METHOD *sm, STORE_CTRL_FUNC_PTR ctrl_f); + +STORE_INITIALISE_FUNC_PTR STORE_method_get_initialise_function(STORE_METHOD *sm); +STORE_CLEANUP_FUNC_PTR STORE_method_get_cleanup_function(STORE_METHOD *sm); +STORE_GENERATE_OBJECT_FUNC_PTR STORE_method_get_generate_function(STORE_METHOD *sm); +STORE_GET_OBJECT_FUNC_PTR STORE_method_get_get_function(STORE_METHOD *sm); +STORE_STORE_OBJECT_FUNC_PTR STORE_method_get_store_function(STORE_METHOD *sm); +STORE_MODIFY_OBJECT_FUNC_PTR STORE_method_get_modify_function(STORE_METHOD *sm); +STORE_HANDLE_OBJECT_FUNC_PTR STORE_method_get_revoke_function(STORE_METHOD *sm); +STORE_HANDLE_OBJECT_FUNC_PTR STORE_method_get_delete_function(STORE_METHOD *sm); +STORE_START_OBJECT_FUNC_PTR STORE_method_get_list_start_function(STORE_METHOD *sm); +STORE_NEXT_OBJECT_FUNC_PTR STORE_method_get_list_next_function(STORE_METHOD *sm); +STORE_END_OBJECT_FUNC_PTR STORE_method_get_list_end_function(STORE_METHOD *sm); +STORE_GENERIC_FUNC_PTR STORE_method_get_update_store_function(STORE_METHOD *sm); +STORE_GENERIC_FUNC_PTR STORE_method_get_lock_store_function(STORE_METHOD *sm); +STORE_GENERIC_FUNC_PTR STORE_method_get_unlock_store_function(STORE_METHOD *sm); +STORE_CTRL_FUNC_PTR STORE_method_get_ctrl_function(STORE_METHOD *sm); + +/* Method helper structures and functions. */ + +/* This structure is the result of parsing through the information in a list + of OPENSSL_ITEMs. It stores all the necessary information in a structured + way.*/ +typedef struct STORE_attr_info_st STORE_ATTR_INFO; + +/* Parse a list of OPENSSL_ITEMs and return a pointer to a STORE_ATTR_INFO. + Note that we do this in the list form, since the list of OPENSSL_ITEMs can + come in blocks separated with STORE_ATTR_OR. Note that the value returned + by STORE_parse_attrs_next() must be freed with STORE_ATTR_INFO_free(). */ +void *STORE_parse_attrs_start(OPENSSL_ITEM *attributes); +STORE_ATTR_INFO *STORE_parse_attrs_next(void *handle); +int STORE_parse_attrs_end(void *handle); +int STORE_parse_attrs_endp(void *handle); + +/* Creator and destructor */ +STORE_ATTR_INFO *STORE_ATTR_INFO_new(void); +int STORE_ATTR_INFO_free(STORE_ATTR_INFO *attrs); + +/* Manipulators */ +char *STORE_ATTR_INFO_get0_cstr(STORE_ATTR_INFO *attrs, STORE_ATTR_TYPES code); +unsigned char *STORE_ATTR_INFO_get0_sha1str(STORE_ATTR_INFO *attrs, + STORE_ATTR_TYPES code); +X509_NAME *STORE_ATTR_INFO_get0_dn(STORE_ATTR_INFO *attrs, STORE_ATTR_TYPES code); +BIGNUM *STORE_ATTR_INFO_get0_number(STORE_ATTR_INFO *attrs, STORE_ATTR_TYPES code); +int STORE_ATTR_INFO_set_cstr(STORE_ATTR_INFO *attrs, STORE_ATTR_TYPES code, + char *cstr, size_t cstr_size); +int STORE_ATTR_INFO_set_sha1str(STORE_ATTR_INFO *attrs, STORE_ATTR_TYPES code, + unsigned char *sha1str, size_t sha1str_size); +int STORE_ATTR_INFO_set_dn(STORE_ATTR_INFO *attrs, STORE_ATTR_TYPES code, + X509_NAME *dn); +int STORE_ATTR_INFO_set_number(STORE_ATTR_INFO *attrs, STORE_ATTR_TYPES code, + BIGNUM *number); +int STORE_ATTR_INFO_modify_cstr(STORE_ATTR_INFO *attrs, STORE_ATTR_TYPES code, + char *cstr, size_t cstr_size); +int STORE_ATTR_INFO_modify_sha1str(STORE_ATTR_INFO *attrs, STORE_ATTR_TYPES code, + unsigned char *sha1str, size_t sha1str_size); +int STORE_ATTR_INFO_modify_dn(STORE_ATTR_INFO *attrs, STORE_ATTR_TYPES code, + X509_NAME *dn); +int STORE_ATTR_INFO_modify_number(STORE_ATTR_INFO *attrs, STORE_ATTR_TYPES code, + BIGNUM *number); + +/* Compare on basis of a bit pattern formed by the STORE_ATTR_TYPES values + in each contained attribute. */ +int STORE_ATTR_INFO_compare(STORE_ATTR_INFO *a, STORE_ATTR_INFO *b); +/* Check if the set of attributes in a is within the range of attributes + set in b. */ +int STORE_ATTR_INFO_in_range(STORE_ATTR_INFO *a, STORE_ATTR_INFO *b); +/* Check if the set of attributes in a are also set in b. */ +int STORE_ATTR_INFO_in(STORE_ATTR_INFO *a, STORE_ATTR_INFO *b); +/* Same as STORE_ATTR_INFO_in(), but also checks the attribute values. */ +int STORE_ATTR_INFO_in_ex(STORE_ATTR_INFO *a, STORE_ATTR_INFO *b); + + +/* BEGIN ERROR CODES */ +/* The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ +void ERR_load_STORE_strings(void); + +/* Error codes for the STORE functions. */ + +/* Function codes. */ +#define STORE_F_MEM_DELETE 134 +#define STORE_F_MEM_GENERATE 135 +#define STORE_F_MEM_LIST_END 168 +#define STORE_F_MEM_LIST_NEXT 136 +#define STORE_F_MEM_LIST_START 137 +#define STORE_F_MEM_MODIFY 169 +#define STORE_F_MEM_STORE 138 +#define STORE_F_STORE_ATTR_INFO_GET0_CSTR 139 +#define STORE_F_STORE_ATTR_INFO_GET0_DN 140 +#define STORE_F_STORE_ATTR_INFO_GET0_NUMBER 141 +#define STORE_F_STORE_ATTR_INFO_GET0_SHA1STR 142 +#define STORE_F_STORE_ATTR_INFO_MODIFY_CSTR 143 +#define STORE_F_STORE_ATTR_INFO_MODIFY_DN 144 +#define STORE_F_STORE_ATTR_INFO_MODIFY_NUMBER 145 +#define STORE_F_STORE_ATTR_INFO_MODIFY_SHA1STR 146 +#define STORE_F_STORE_ATTR_INFO_SET_CSTR 147 +#define STORE_F_STORE_ATTR_INFO_SET_DN 148 +#define STORE_F_STORE_ATTR_INFO_SET_NUMBER 149 +#define STORE_F_STORE_ATTR_INFO_SET_SHA1STR 150 +#define STORE_F_STORE_CERTIFICATE 170 +#define STORE_F_STORE_CTRL 161 +#define STORE_F_STORE_DELETE_ARBITRARY 158 +#define STORE_F_STORE_DELETE_CERTIFICATE 102 +#define STORE_F_STORE_DELETE_CRL 103 +#define STORE_F_STORE_DELETE_NUMBER 104 +#define STORE_F_STORE_DELETE_PRIVATE_KEY 105 +#define STORE_F_STORE_DELETE_PUBLIC_KEY 106 +#define STORE_F_STORE_GENERATE_CRL 107 +#define STORE_F_STORE_GENERATE_KEY 108 +#define STORE_F_STORE_GET_ARBITRARY 159 +#define STORE_F_STORE_GET_CERTIFICATE 109 +#define STORE_F_STORE_GET_CRL 110 +#define STORE_F_STORE_GET_NUMBER 111 +#define STORE_F_STORE_GET_PRIVATE_KEY 112 +#define STORE_F_STORE_GET_PUBLIC_KEY 113 +#define STORE_F_STORE_LIST_CERTIFICATE_END 114 +#define STORE_F_STORE_LIST_CERTIFICATE_ENDP 153 +#define STORE_F_STORE_LIST_CERTIFICATE_NEXT 115 +#define STORE_F_STORE_LIST_CERTIFICATE_START 116 +#define STORE_F_STORE_LIST_CRL_END 117 +#define STORE_F_STORE_LIST_CRL_ENDP 154 +#define STORE_F_STORE_LIST_CRL_NEXT 118 +#define STORE_F_STORE_LIST_CRL_START 119 +#define STORE_F_STORE_LIST_PRIVATE_KEY_END 120 +#define STORE_F_STORE_LIST_PRIVATE_KEY_ENDP 155 +#define STORE_F_STORE_LIST_PRIVATE_KEY_NEXT 121 +#define STORE_F_STORE_LIST_PRIVATE_KEY_START 122 +#define STORE_F_STORE_LIST_PUBLIC_KEY_END 123 +#define STORE_F_STORE_LIST_PUBLIC_KEY_ENDP 156 +#define STORE_F_STORE_LIST_PUBLIC_KEY_NEXT 124 +#define STORE_F_STORE_LIST_PUBLIC_KEY_START 125 +#define STORE_F_STORE_MODIFY_ARBITRARY 162 +#define STORE_F_STORE_MODIFY_CERTIFICATE 163 +#define STORE_F_STORE_MODIFY_CRL 164 +#define STORE_F_STORE_MODIFY_NUMBER 165 +#define STORE_F_STORE_MODIFY_PRIVATE_KEY 166 +#define STORE_F_STORE_MODIFY_PUBLIC_KEY 167 +#define STORE_F_STORE_NEW_ENGINE 133 +#define STORE_F_STORE_NEW_METHOD 132 +#define STORE_F_STORE_PARSE_ATTRS_END 151 +#define STORE_F_STORE_PARSE_ATTRS_ENDP 172 +#define STORE_F_STORE_PARSE_ATTRS_NEXT 152 +#define STORE_F_STORE_PARSE_ATTRS_START 171 +#define STORE_F_STORE_REVOKE_CERTIFICATE 129 +#define STORE_F_STORE_REVOKE_PRIVATE_KEY 130 +#define STORE_F_STORE_REVOKE_PUBLIC_KEY 131 +#define STORE_F_STORE_STORE_ARBITRARY 157 +#define STORE_F_STORE_STORE_CERTIFICATE 100 +#define STORE_F_STORE_STORE_CRL 101 +#define STORE_F_STORE_STORE_NUMBER 126 +#define STORE_F_STORE_STORE_PRIVATE_KEY 127 +#define STORE_F_STORE_STORE_PUBLIC_KEY 128 + +/* Reason codes. */ +#define STORE_R_ALREADY_HAS_A_VALUE 127 +#define STORE_R_FAILED_DELETING_ARBITRARY 132 +#define STORE_R_FAILED_DELETING_CERTIFICATE 100 +#define STORE_R_FAILED_DELETING_KEY 101 +#define STORE_R_FAILED_DELETING_NUMBER 102 +#define STORE_R_FAILED_GENERATING_CRL 103 +#define STORE_R_FAILED_GENERATING_KEY 104 +#define STORE_R_FAILED_GETTING_ARBITRARY 133 +#define STORE_R_FAILED_GETTING_CERTIFICATE 105 +#define STORE_R_FAILED_GETTING_KEY 106 +#define STORE_R_FAILED_GETTING_NUMBER 107 +#define STORE_R_FAILED_LISTING_CERTIFICATES 108 +#define STORE_R_FAILED_LISTING_KEYS 109 +#define STORE_R_FAILED_MODIFYING_ARBITRARY 138 +#define STORE_R_FAILED_MODIFYING_CERTIFICATE 139 +#define STORE_R_FAILED_MODIFYING_CRL 140 +#define STORE_R_FAILED_MODIFYING_NUMBER 141 +#define STORE_R_FAILED_MODIFYING_PRIVATE_KEY 142 +#define STORE_R_FAILED_MODIFYING_PUBLIC_KEY 143 +#define STORE_R_FAILED_REVOKING_CERTIFICATE 110 +#define STORE_R_FAILED_REVOKING_KEY 111 +#define STORE_R_FAILED_STORING_ARBITRARY 134 +#define STORE_R_FAILED_STORING_CERTIFICATE 112 +#define STORE_R_FAILED_STORING_KEY 113 +#define STORE_R_FAILED_STORING_NUMBER 114 +#define STORE_R_NOT_IMPLEMENTED 128 +#define STORE_R_NO_CONTROL_FUNCTION 144 +#define STORE_R_NO_DELETE_ARBITRARY_FUNCTION 135 +#define STORE_R_NO_DELETE_NUMBER_FUNCTION 115 +#define STORE_R_NO_DELETE_OBJECT_FUNCTION 116 +#define STORE_R_NO_GENERATE_CRL_FUNCTION 117 +#define STORE_R_NO_GENERATE_OBJECT_FUNCTION 118 +#define STORE_R_NO_GET_OBJECT_ARBITRARY_FUNCTION 136 +#define STORE_R_NO_GET_OBJECT_FUNCTION 119 +#define STORE_R_NO_GET_OBJECT_NUMBER_FUNCTION 120 +#define STORE_R_NO_LIST_OBJECT_ENDP_FUNCTION 131 +#define STORE_R_NO_LIST_OBJECT_END_FUNCTION 121 +#define STORE_R_NO_LIST_OBJECT_NEXT_FUNCTION 122 +#define STORE_R_NO_LIST_OBJECT_START_FUNCTION 123 +#define STORE_R_NO_MODIFY_OBJECT_FUNCTION 145 +#define STORE_R_NO_REVOKE_OBJECT_FUNCTION 124 +#define STORE_R_NO_STORE 129 +#define STORE_R_NO_STORE_OBJECT_ARBITRARY_FUNCTION 137 +#define STORE_R_NO_STORE_OBJECT_FUNCTION 125 +#define STORE_R_NO_STORE_OBJECT_NUMBER_FUNCTION 126 +#define STORE_R_NO_VALUE 130 + +#ifdef __cplusplus +} +#endif +#endif diff --git a/lib_tls/include/openssl/symhacks.h b/lib_tls/include/openssl/symhacks.h new file mode 100644 index 000000000..64528ad5c --- /dev/null +++ b/lib_tls/include/openssl/symhacks.h @@ -0,0 +1,400 @@ +/* ==================================================================== + * Copyright (c) 1999 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#ifndef HEADER_SYMHACKS_H +#define HEADER_SYMHACKS_H + +#include + +/* Hacks to solve the problem with linkers incapable of handling very long + symbol names. In the case of VMS, the limit is 31 characters on VMS for + VAX. */ +#ifdef OPENSSL_SYS_VMS + +/* Hack a long name in crypto/ex_data.c */ +#undef CRYPTO_get_ex_data_implementation +#define CRYPTO_get_ex_data_implementation CRYPTO_get_ex_data_impl +#undef CRYPTO_set_ex_data_implementation +#define CRYPTO_set_ex_data_implementation CRYPTO_set_ex_data_impl + +/* Hack a long name in crypto/asn1/a_mbstr.c */ +#undef ASN1_STRING_set_default_mask_asc +#define ASN1_STRING_set_default_mask_asc ASN1_STRING_set_def_mask_asc + +#if 0 /* No longer needed, since safestack macro magic does the job */ +/* Hack the names created with DECLARE_ASN1_SET_OF(PKCS7_SIGNER_INFO) */ +#undef i2d_ASN1_SET_OF_PKCS7_SIGNER_INFO +#define i2d_ASN1_SET_OF_PKCS7_SIGNER_INFO i2d_ASN1_SET_OF_PKCS7_SIGINF +#undef d2i_ASN1_SET_OF_PKCS7_SIGNER_INFO +#define d2i_ASN1_SET_OF_PKCS7_SIGNER_INFO d2i_ASN1_SET_OF_PKCS7_SIGINF +#endif + +#if 0 /* No longer needed, since safestack macro magic does the job */ +/* Hack the names created with DECLARE_ASN1_SET_OF(PKCS7_RECIP_INFO) */ +#undef i2d_ASN1_SET_OF_PKCS7_RECIP_INFO +#define i2d_ASN1_SET_OF_PKCS7_RECIP_INFO i2d_ASN1_SET_OF_PKCS7_RECINF +#undef d2i_ASN1_SET_OF_PKCS7_RECIP_INFO +#define d2i_ASN1_SET_OF_PKCS7_RECIP_INFO d2i_ASN1_SET_OF_PKCS7_RECINF +#endif + +#if 0 /* No longer needed, since safestack macro magic does the job */ +/* Hack the names created with DECLARE_ASN1_SET_OF(ACCESS_DESCRIPTION) */ +#undef i2d_ASN1_SET_OF_ACCESS_DESCRIPTION +#define i2d_ASN1_SET_OF_ACCESS_DESCRIPTION i2d_ASN1_SET_OF_ACC_DESC +#undef d2i_ASN1_SET_OF_ACCESS_DESCRIPTION +#define d2i_ASN1_SET_OF_ACCESS_DESCRIPTION d2i_ASN1_SET_OF_ACC_DESC +#endif + +/* Hack the names created with DECLARE_PEM_rw(NETSCAPE_CERT_SEQUENCE) */ +#undef PEM_read_NETSCAPE_CERT_SEQUENCE +#define PEM_read_NETSCAPE_CERT_SEQUENCE PEM_read_NS_CERT_SEQ +#undef PEM_write_NETSCAPE_CERT_SEQUENCE +#define PEM_write_NETSCAPE_CERT_SEQUENCE PEM_write_NS_CERT_SEQ +#undef PEM_read_bio_NETSCAPE_CERT_SEQUENCE +#define PEM_read_bio_NETSCAPE_CERT_SEQUENCE PEM_read_bio_NS_CERT_SEQ +#undef PEM_write_bio_NETSCAPE_CERT_SEQUENCE +#define PEM_write_bio_NETSCAPE_CERT_SEQUENCE PEM_write_bio_NS_CERT_SEQ +#undef PEM_write_cb_bio_NETSCAPE_CERT_SEQUENCE +#define PEM_write_cb_bio_NETSCAPE_CERT_SEQUENCE PEM_write_cb_bio_NS_CERT_SEQ + +/* Hack the names created with DECLARE_PEM_rw(PKCS8_PRIV_KEY_INFO) */ +#undef PEM_read_PKCS8_PRIV_KEY_INFO +#define PEM_read_PKCS8_PRIV_KEY_INFO PEM_read_P8_PRIV_KEY_INFO +#undef PEM_write_PKCS8_PRIV_KEY_INFO +#define PEM_write_PKCS8_PRIV_KEY_INFO PEM_write_P8_PRIV_KEY_INFO +#undef PEM_read_bio_PKCS8_PRIV_KEY_INFO +#define PEM_read_bio_PKCS8_PRIV_KEY_INFO PEM_read_bio_P8_PRIV_KEY_INFO +#undef PEM_write_bio_PKCS8_PRIV_KEY_INFO +#define PEM_write_bio_PKCS8_PRIV_KEY_INFO PEM_write_bio_P8_PRIV_KEY_INFO +#undef PEM_write_cb_bio_PKCS8_PRIV_KEY_INFO +#define PEM_write_cb_bio_PKCS8_PRIV_KEY_INFO PEM_wrt_cb_bio_P8_PRIV_KEY_INFO + +/* Hack other PEM names */ +#undef PEM_write_bio_PKCS8PrivateKey_nid +#define PEM_write_bio_PKCS8PrivateKey_nid PEM_write_bio_PKCS8PrivKey_nid + +/* Hack some long X509 names */ +#undef X509_REVOKED_get_ext_by_critical +#define X509_REVOKED_get_ext_by_critical X509_REVOKED_get_ext_by_critic +#undef X509_policy_tree_get0_user_policies +#define X509_policy_tree_get0_user_policies X509_pcy_tree_get0_usr_policies +#undef X509_policy_node_get0_qualifiers +#define X509_policy_node_get0_qualifiers X509_pcy_node_get0_qualifiers +#undef X509_STORE_CTX_get_explicit_policy +#define X509_STORE_CTX_get_explicit_policy X509_STORE_CTX_get_expl_policy + +/* Hack some long CRYPTO names */ +#undef CRYPTO_set_dynlock_destroy_callback +#define CRYPTO_set_dynlock_destroy_callback CRYPTO_set_dynlock_destroy_cb +#undef CRYPTO_set_dynlock_create_callback +#define CRYPTO_set_dynlock_create_callback CRYPTO_set_dynlock_create_cb +#undef CRYPTO_set_dynlock_lock_callback +#define CRYPTO_set_dynlock_lock_callback CRYPTO_set_dynlock_lock_cb +#undef CRYPTO_get_dynlock_lock_callback +#define CRYPTO_get_dynlock_lock_callback CRYPTO_get_dynlock_lock_cb +#undef CRYPTO_get_dynlock_destroy_callback +#define CRYPTO_get_dynlock_destroy_callback CRYPTO_get_dynlock_destroy_cb +#undef CRYPTO_get_dynlock_create_callback +#define CRYPTO_get_dynlock_create_callback CRYPTO_get_dynlock_create_cb +#undef CRYPTO_set_locked_mem_ex_functions +#define CRYPTO_set_locked_mem_ex_functions CRYPTO_set_locked_mem_ex_funcs +#undef CRYPTO_get_locked_mem_ex_functions +#define CRYPTO_get_locked_mem_ex_functions CRYPTO_get_locked_mem_ex_funcs + +/* Hack some long SSL names */ +#undef SSL_CTX_set_default_verify_paths +#define SSL_CTX_set_default_verify_paths SSL_CTX_set_def_verify_paths +#undef SSL_get_ex_data_X509_STORE_CTX_idx +#define SSL_get_ex_data_X509_STORE_CTX_idx SSL_get_ex_d_X509_STORE_CTX_idx +#undef SSL_add_file_cert_subjects_to_stack +#define SSL_add_file_cert_subjects_to_stack SSL_add_file_cert_subjs_to_stk +#undef SSL_add_dir_cert_subjects_to_stack +#define SSL_add_dir_cert_subjects_to_stack SSL_add_dir_cert_subjs_to_stk +#undef SSL_CTX_use_certificate_chain_file +#define SSL_CTX_use_certificate_chain_file SSL_CTX_use_cert_chain_file +#undef SSL_CTX_set_cert_verify_callback +#define SSL_CTX_set_cert_verify_callback SSL_CTX_set_cert_verify_cb +#undef SSL_CTX_set_default_passwd_cb_userdata +#define SSL_CTX_set_default_passwd_cb_userdata SSL_CTX_set_def_passwd_cb_ud +#undef SSL_COMP_get_compression_methods +#define SSL_COMP_get_compression_methods SSL_COMP_get_compress_methods + +/* Hack some long ENGINE names */ +#undef ENGINE_get_default_BN_mod_exp_crt +#define ENGINE_get_default_BN_mod_exp_crt ENGINE_get_def_BN_mod_exp_crt +#undef ENGINE_set_default_BN_mod_exp_crt +#define ENGINE_set_default_BN_mod_exp_crt ENGINE_set_def_BN_mod_exp_crt +#undef ENGINE_set_load_privkey_function +#define ENGINE_set_load_privkey_function ENGINE_set_load_privkey_fn +#undef ENGINE_get_load_privkey_function +#define ENGINE_get_load_privkey_function ENGINE_get_load_privkey_fn + +/* Hack some long OCSP names */ +#undef OCSP_REQUEST_get_ext_by_critical +#define OCSP_REQUEST_get_ext_by_critical OCSP_REQUEST_get_ext_by_crit +#undef OCSP_BASICRESP_get_ext_by_critical +#define OCSP_BASICRESP_get_ext_by_critical OCSP_BASICRESP_get_ext_by_crit +#undef OCSP_SINGLERESP_get_ext_by_critical +#define OCSP_SINGLERESP_get_ext_by_critical OCSP_SINGLERESP_get_ext_by_crit + +/* Hack some long DES names */ +#undef _ossl_old_des_ede3_cfb64_encrypt +#define _ossl_old_des_ede3_cfb64_encrypt _ossl_odes_ede3_cfb64_encrypt +#undef _ossl_old_des_ede3_ofb64_encrypt +#define _ossl_old_des_ede3_ofb64_encrypt _ossl_odes_ede3_ofb64_encrypt + +/* Hack some long EVP names */ +#undef OPENSSL_add_all_algorithms_noconf +#define OPENSSL_add_all_algorithms_noconf OPENSSL_add_all_algo_noconf +#undef OPENSSL_add_all_algorithms_conf +#define OPENSSL_add_all_algorithms_conf OPENSSL_add_all_algo_conf + +/* Hack some long EC names */ +#undef EC_GROUP_set_point_conversion_form +#define EC_GROUP_set_point_conversion_form EC_GROUP_set_point_conv_form +#undef EC_GROUP_get_point_conversion_form +#define EC_GROUP_get_point_conversion_form EC_GROUP_get_point_conv_form +#undef EC_GROUP_clear_free_all_extra_data +#define EC_GROUP_clear_free_all_extra_data EC_GROUP_clr_free_all_xtra_data +#undef EC_POINT_set_Jprojective_coordinates_GFp +#define EC_POINT_set_Jprojective_coordinates_GFp \ + EC_POINT_set_Jproj_coords_GFp +#undef EC_POINT_get_Jprojective_coordinates_GFp +#define EC_POINT_get_Jprojective_coordinates_GFp \ + EC_POINT_get_Jproj_coords_GFp +#undef EC_POINT_set_affine_coordinates_GFp +#define EC_POINT_set_affine_coordinates_GFp EC_POINT_set_affine_coords_GFp +#undef EC_POINT_get_affine_coordinates_GFp +#define EC_POINT_get_affine_coordinates_GFp EC_POINT_get_affine_coords_GFp +#undef EC_POINT_set_compressed_coordinates_GFp +#define EC_POINT_set_compressed_coordinates_GFp EC_POINT_set_compr_coords_GFp +#undef EC_POINT_set_affine_coordinates_GF2m +#define EC_POINT_set_affine_coordinates_GF2m EC_POINT_set_affine_coords_GF2m +#undef EC_POINT_get_affine_coordinates_GF2m +#define EC_POINT_get_affine_coordinates_GF2m EC_POINT_get_affine_coords_GF2m +#undef EC_POINT_set_compressed_coordinates_GF2m +#define EC_POINT_set_compressed_coordinates_GF2m \ + EC_POINT_set_compr_coords_GF2m +#undef ec_GF2m_simple_group_clear_finish +#define ec_GF2m_simple_group_clear_finish ec_GF2m_simple_grp_clr_finish +#undef ec_GF2m_simple_group_check_discriminant +#define ec_GF2m_simple_group_check_discriminant ec_GF2m_simple_grp_chk_discrim +#undef ec_GF2m_simple_point_clear_finish +#define ec_GF2m_simple_point_clear_finish ec_GF2m_simple_pt_clr_finish +#undef ec_GF2m_simple_point_set_to_infinity +#define ec_GF2m_simple_point_set_to_infinity ec_GF2m_simple_pt_set_to_inf +#undef ec_GF2m_simple_points_make_affine +#define ec_GF2m_simple_points_make_affine ec_GF2m_simple_pts_make_affine +#undef ec_GF2m_simple_point_set_affine_coordinates +#define ec_GF2m_simple_point_set_affine_coordinates \ + ec_GF2m_smp_pt_set_af_coords +#undef ec_GF2m_simple_point_get_affine_coordinates +#define ec_GF2m_simple_point_get_affine_coordinates \ + ec_GF2m_smp_pt_get_af_coords +#undef ec_GF2m_simple_set_compressed_coordinates +#define ec_GF2m_simple_set_compressed_coordinates \ + ec_GF2m_smp_set_compr_coords +#undef ec_GFp_simple_group_set_curve_GFp +#define ec_GFp_simple_group_set_curve_GFp ec_GFp_simple_grp_set_curve_GFp +#undef ec_GFp_simple_group_get_curve_GFp +#define ec_GFp_simple_group_get_curve_GFp ec_GFp_simple_grp_get_curve_GFp +#undef ec_GFp_simple_group_clear_finish +#define ec_GFp_simple_group_clear_finish ec_GFp_simple_grp_clear_finish +#undef ec_GFp_simple_group_set_generator +#define ec_GFp_simple_group_set_generator ec_GFp_simple_grp_set_generator +#undef ec_GFp_simple_group_get0_generator +#define ec_GFp_simple_group_get0_generator ec_GFp_simple_grp_gt0_generator +#undef ec_GFp_simple_group_get_cofactor +#define ec_GFp_simple_group_get_cofactor ec_GFp_simple_grp_get_cofactor +#undef ec_GFp_simple_point_clear_finish +#define ec_GFp_simple_point_clear_finish ec_GFp_simple_pt_clear_finish +#undef ec_GFp_simple_point_set_to_infinity +#define ec_GFp_simple_point_set_to_infinity ec_GFp_simple_pt_set_to_inf +#undef ec_GFp_simple_points_make_affine +#define ec_GFp_simple_points_make_affine ec_GFp_simple_pts_make_affine +#undef ec_GFp_simple_group_get_curve_GFp +#define ec_GFp_simple_group_get_curve_GFp ec_GFp_simple_grp_get_curve_GFp +#undef ec_GFp_simple_set_Jprojective_coordinates_GFp +#define ec_GFp_simple_set_Jprojective_coordinates_GFp \ + ec_GFp_smp_set_Jproj_coords_GFp +#undef ec_GFp_simple_get_Jprojective_coordinates_GFp +#define ec_GFp_simple_get_Jprojective_coordinates_GFp \ + ec_GFp_smp_get_Jproj_coords_GFp +#undef ec_GFp_simple_point_set_affine_coordinates_GFp +#define ec_GFp_simple_point_set_affine_coordinates_GFp \ + ec_GFp_smp_pt_set_af_coords_GFp +#undef ec_GFp_simple_point_get_affine_coordinates_GFp +#define ec_GFp_simple_point_get_affine_coordinates_GFp \ + ec_GFp_smp_pt_get_af_coords_GFp +#undef ec_GFp_simple_set_compressed_coordinates_GFp +#define ec_GFp_simple_set_compressed_coordinates_GFp \ + ec_GFp_smp_set_compr_coords_GFp +#undef ec_GFp_simple_point_set_affine_coordinates +#define ec_GFp_simple_point_set_affine_coordinates \ + ec_GFp_smp_pt_set_af_coords +#undef ec_GFp_simple_point_get_affine_coordinates +#define ec_GFp_simple_point_get_affine_coordinates \ + ec_GFp_smp_pt_get_af_coords +#undef ec_GFp_simple_set_compressed_coordinates +#define ec_GFp_simple_set_compressed_coordinates \ + ec_GFp_smp_set_compr_coords +#undef ec_GFp_simple_group_check_discriminant +#define ec_GFp_simple_group_check_discriminant ec_GFp_simple_grp_chk_discrim + +/* Hack som long STORE names */ +#undef STORE_method_set_initialise_function +#define STORE_method_set_initialise_function STORE_meth_set_initialise_fn +#undef STORE_method_set_cleanup_function +#define STORE_method_set_cleanup_function STORE_meth_set_cleanup_fn +#undef STORE_method_set_generate_function +#define STORE_method_set_generate_function STORE_meth_set_generate_fn +#undef STORE_method_set_modify_function +#define STORE_method_set_modify_function STORE_meth_set_modify_fn +#undef STORE_method_set_revoke_function +#define STORE_method_set_revoke_function STORE_meth_set_revoke_fn +#undef STORE_method_set_delete_function +#define STORE_method_set_delete_function STORE_meth_set_delete_fn +#undef STORE_method_set_list_start_function +#define STORE_method_set_list_start_function STORE_meth_set_list_start_fn +#undef STORE_method_set_list_next_function +#define STORE_method_set_list_next_function STORE_meth_set_list_next_fn +#undef STORE_method_set_list_end_function +#define STORE_method_set_list_end_function STORE_meth_set_list_end_fn +#undef STORE_method_set_update_store_function +#define STORE_method_set_update_store_function STORE_meth_set_update_store_fn +#undef STORE_method_set_lock_store_function +#define STORE_method_set_lock_store_function STORE_meth_set_lock_store_fn +#undef STORE_method_set_unlock_store_function +#define STORE_method_set_unlock_store_function STORE_meth_set_unlock_store_fn +#undef STORE_method_get_initialise_function +#define STORE_method_get_initialise_function STORE_meth_get_initialise_fn +#undef STORE_method_get_cleanup_function +#define STORE_method_get_cleanup_function STORE_meth_get_cleanup_fn +#undef STORE_method_get_generate_function +#define STORE_method_get_generate_function STORE_meth_get_generate_fn +#undef STORE_method_get_modify_function +#define STORE_method_get_modify_function STORE_meth_get_modify_fn +#undef STORE_method_get_revoke_function +#define STORE_method_get_revoke_function STORE_meth_get_revoke_fn +#undef STORE_method_get_delete_function +#define STORE_method_get_delete_function STORE_meth_get_delete_fn +#undef STORE_method_get_list_start_function +#define STORE_method_get_list_start_function STORE_meth_get_list_start_fn +#undef STORE_method_get_list_next_function +#define STORE_method_get_list_next_function STORE_meth_get_list_next_fn +#undef STORE_method_get_list_end_function +#define STORE_method_get_list_end_function STORE_meth_get_list_end_fn +#undef STORE_method_get_update_store_function +#define STORE_method_get_update_store_function STORE_meth_get_update_store_fn +#undef STORE_method_get_lock_store_function +#define STORE_method_get_lock_store_function STORE_meth_get_lock_store_fn +#undef STORE_method_get_unlock_store_function +#define STORE_method_get_unlock_store_function STORE_meth_get_unlock_store_fn + +/* Hack some long CMS names */ +#undef CMS_RecipientInfo_ktri_get0_algs +#define CMS_RecipientInfo_ktri_get0_algs CMS_RecipInfo_ktri_get0_algs +#undef CMS_RecipientInfo_ktri_get0_signer_id +#define CMS_RecipientInfo_ktri_get0_signer_id CMS_RecipInfo_ktri_get0_sigr_id +#undef CMS_OtherRevocationInfoFormat_it +#define CMS_OtherRevocationInfoFormat_it CMS_OtherRevocInfoFormat_it +#undef CMS_KeyAgreeRecipientIdentifier_it +#define CMS_KeyAgreeRecipientIdentifier_it CMS_KeyAgreeRecipIdentifier_it +#undef CMS_OriginatorIdentifierOrKey_it +#define CMS_OriginatorIdentifierOrKey_it CMS_OriginatorIdOrKey_it +#undef cms_SignerIdentifier_get0_signer_id +#define cms_SignerIdentifier_get0_signer_id cms_SignerId_get0_signer_id + +#endif /* defined OPENSSL_SYS_VMS */ + + +/* Case insensiteve linking causes problems.... */ +#if defined(OPENSSL_SYS_WIN16) || defined(OPENSSL_SYS_VMS) || defined(OPENSSL_SYS_OS2) +#undef ERR_load_CRYPTO_strings +#define ERR_load_CRYPTO_strings ERR_load_CRYPTOlib_strings +#undef OCSP_crlID_new +#define OCSP_crlID_new OCSP_crlID2_new + +#undef d2i_ECPARAMETERS +#define d2i_ECPARAMETERS d2i_UC_ECPARAMETERS +#undef i2d_ECPARAMETERS +#define i2d_ECPARAMETERS i2d_UC_ECPARAMETERS +#undef d2i_ECPKPARAMETERS +#define d2i_ECPKPARAMETERS d2i_UC_ECPKPARAMETERS +#undef i2d_ECPKPARAMETERS +#define i2d_ECPKPARAMETERS i2d_UC_ECPKPARAMETERS + +/* These functions do not seem to exist! However, I'm paranoid... + Original command in x509v3.h: + These functions are being redefined in another directory, + and clash when the linker is case-insensitive, so let's + hide them a little, by giving them an extra 'o' at the + beginning of the name... */ +#undef X509v3_cleanup_extensions +#define X509v3_cleanup_extensions oX509v3_cleanup_extensions +#undef X509v3_add_extension +#define X509v3_add_extension oX509v3_add_extension +#undef X509v3_add_netscape_extensions +#define X509v3_add_netscape_extensions oX509v3_add_netscape_extensions +#undef X509v3_add_standard_extensions +#define X509v3_add_standard_extensions oX509v3_add_standard_extensions + + +#endif + + +#endif /* ! defined HEADER_VMS_IDHACKS_H */ +/* This one clashes with CMS_data_create */ +#undef cms_Data_create +#define cms_Data_create priv_cms_Data_create diff --git a/lib_tls/include/openssl/tls1.h b/lib_tls/include/openssl/tls1.h new file mode 100644 index 000000000..2d1d293e1 --- /dev/null +++ b/lib_tls/include/openssl/tls1.h @@ -0,0 +1,407 @@ +/* ssl/tls1.h */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * + * Portions of the attached software ("Contribution") are developed by + * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. + * + * The Contribution is licensed pursuant to the OpenSSL open source + * license provided above. + * + * ECC cipher suite support in OpenSSL originally written by + * Vipul Gupta and Sumit Gupta of Sun Microsystems Laboratories. + * + */ + +#ifndef HEADER_TLS1_H +#define HEADER_TLS1_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define TLS1_ALLOW_EXPERIMENTAL_CIPHERSUITES 0 + +#define TLS1_VERSION 0x0301 +#define TLS1_VERSION_MAJOR 0x03 +#define TLS1_VERSION_MINOR 0x01 + +#define TLS1_AD_DECRYPTION_FAILED 21 +#define TLS1_AD_RECORD_OVERFLOW 22 +#define TLS1_AD_UNKNOWN_CA 48 /* fatal */ +#define TLS1_AD_ACCESS_DENIED 49 /* fatal */ +#define TLS1_AD_DECODE_ERROR 50 /* fatal */ +#define TLS1_AD_DECRYPT_ERROR 51 +#define TLS1_AD_EXPORT_RESTRICTION 60 /* fatal */ +#define TLS1_AD_PROTOCOL_VERSION 70 /* fatal */ +#define TLS1_AD_INSUFFICIENT_SECURITY 71 /* fatal */ +#define TLS1_AD_INTERNAL_ERROR 80 /* fatal */ +#define TLS1_AD_USER_CANCELLED 90 +#define TLS1_AD_NO_RENEGOTIATION 100 +/* codes 110-114 are from RFC3546 */ +#define TLS1_AD_UNSUPPORTED_EXTENSION 110 +#define TLS1_AD_CERTIFICATE_UNOBTAINABLE 111 +#define TLS1_AD_UNRECOGNIZED_NAME 112 +#define TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE 113 +#define TLS1_AD_BAD_CERTIFICATE_HASH_VALUE 114 +#define TLS1_AD_UNKNOWN_PSK_IDENTITY 115 /* fatal */ + +/* ExtensionType values from RFC 3546 */ +#define TLSEXT_TYPE_server_name 0 +#define TLSEXT_TYPE_max_fragment_length 1 +#define TLSEXT_TYPE_client_certificate_url 2 +#define TLSEXT_TYPE_trusted_ca_keys 3 +#define TLSEXT_TYPE_truncated_hmac 4 +#define TLSEXT_TYPE_status_request 5 +#define TLSEXT_TYPE_elliptic_curves 10 +#define TLSEXT_TYPE_ec_point_formats 11 +#define TLSEXT_TYPE_session_ticket 35 + +/* NameType value from RFC 3546 */ +#define TLSEXT_NAMETYPE_host_name 0 +/* status request value from RFC 3546 */ +#define TLSEXT_STATUSTYPE_ocsp 1 + +#ifndef OPENSSL_NO_TLSEXT + +#define TLSEXT_MAXLEN_host_name 255 + +const char *SSL_get_servername(const SSL *s, const int type) ; +int SSL_get_servername_type(const SSL *s) ; + +#define SSL_set_tlsext_host_name(s,name) \ +SSL_ctrl(s,SSL_CTRL_SET_TLSEXT_HOSTNAME,TLSEXT_NAMETYPE_host_name,(char *)name) + +#define SSL_set_tlsext_debug_callback(ssl, cb) \ +SSL_callback_ctrl(ssl,SSL_CTRL_SET_TLSEXT_DEBUG_CB,(void (*)(void))cb) + +#define SSL_set_tlsext_debug_arg(ssl, arg) \ +SSL_ctrl(ssl,SSL_CTRL_SET_TLSEXT_DEBUG_ARG,0, (void *)arg) + +#define SSL_set_tlsext_status_type(ssl, type) \ +SSL_ctrl(ssl,SSL_CTRL_SET_TLSEXT_STATUS_REQ_TYPE,type, NULL) + +#define SSL_get_tlsext_status_exts(ssl, arg) \ +SSL_ctrl(ssl,SSL_CTRL_GET_TLSEXT_STATUS_REQ_EXTS,0, (void *)arg) + +#define SSL_set_tlsext_status_exts(ssl, arg) \ +SSL_ctrl(ssl,SSL_CTRL_SET_TLSEXT_STATUS_REQ_EXTS,0, (void *)arg) + +#define SSL_get_tlsext_status_ids(ssl, arg) \ +SSL_ctrl(ssl,SSL_CTRL_GET_TLSEXT_STATUS_REQ_IDS,0, (void *)arg) + +#define SSL_set_tlsext_status_ids(ssl, arg) \ +SSL_ctrl(ssl,SSL_CTRL_SET_TLSEXT_STATUS_REQ_IDS,0, (void *)arg) + +#define SSL_get_tlsext_status_ocsp_resp(ssl, arg) \ +SSL_ctrl(ssl,SSL_CTRL_GET_TLSEXT_STATUS_REQ_OCSP_RESP,0, (void *)arg) + +#define SSL_set_tlsext_status_ocsp_resp(ssl, arg, arglen) \ +SSL_ctrl(ssl,SSL_CTRL_SET_TLSEXT_STATUS_REQ_OCSP_RESP,arglen, (void *)arg) + +#define SSL_CTX_set_tlsext_servername_callback(ctx, cb) \ +SSL_CTX_callback_ctrl(ctx,SSL_CTRL_SET_TLSEXT_SERVERNAME_CB,(void (*)(void))cb) + +#define SSL_TLSEXT_ERR_OK 0 +#define SSL_TLSEXT_ERR_ALERT_WARNING 1 +#define SSL_TLSEXT_ERR_ALERT_FATAL 2 +#define SSL_TLSEXT_ERR_NOACK 3 + +#define SSL_CTX_set_tlsext_servername_arg(ctx, arg) \ +SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG,0, (void *)arg) + +#define SSL_CTX_get_tlsext_ticket_keys(ctx, keys, keylen) \ + SSL_CTX_ctrl((ctx),SSL_CTRL_GET_TLXEXT_TICKET_KEYS,(keylen),(keys)) +#define SSL_CTX_set_tlsext_ticket_keys(ctx, keys, keylen) \ + SSL_CTX_ctrl((ctx),SSL_CTRL_SET_TLXEXT_TICKET_KEYS,(keylen),(keys)) + +#define SSL_CTX_set_tlsext_status_cb(ssl, cb) \ +SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB,(void (*)(void))cb) + +#define SSL_CTX_set_tlsext_status_arg(ssl, arg) \ +SSL_CTX_ctrl(ssl,SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB_ARG,0, (void *)arg) + +#define SSL_CTX_set_tlsext_ticket_key_cb(ssl, cb) \ +SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB,(void (*)(void))cb) + +#endif + +/* Additional TLS ciphersuites from draft-ietf-tls-56-bit-ciphersuites-00.txt + * (available if TLS1_ALLOW_EXPERIMENTAL_CIPHERSUITES is defined, see + * s3_lib.c). We actually treat them like SSL 3.0 ciphers, which we probably + * shouldn't. */ +#define TLS1_CK_RSA_EXPORT1024_WITH_RC4_56_MD5 0x03000060 +#define TLS1_CK_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5 0x03000061 +#define TLS1_CK_RSA_EXPORT1024_WITH_DES_CBC_SHA 0x03000062 +#define TLS1_CK_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA 0x03000063 +#define TLS1_CK_RSA_EXPORT1024_WITH_RC4_56_SHA 0x03000064 +#define TLS1_CK_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA 0x03000065 +#define TLS1_CK_DHE_DSS_WITH_RC4_128_SHA 0x03000066 + +/* AES ciphersuites from RFC3268 */ + +#define TLS1_CK_RSA_WITH_AES_128_SHA 0x0300002F +#define TLS1_CK_DH_DSS_WITH_AES_128_SHA 0x03000030 +#define TLS1_CK_DH_RSA_WITH_AES_128_SHA 0x03000031 +#define TLS1_CK_DHE_DSS_WITH_AES_128_SHA 0x03000032 +#define TLS1_CK_DHE_RSA_WITH_AES_128_SHA 0x03000033 +#define TLS1_CK_ADH_WITH_AES_128_SHA 0x03000034 + +#define TLS1_CK_RSA_WITH_AES_256_SHA 0x03000035 +#define TLS1_CK_DH_DSS_WITH_AES_256_SHA 0x03000036 +#define TLS1_CK_DH_RSA_WITH_AES_256_SHA 0x03000037 +#define TLS1_CK_DHE_DSS_WITH_AES_256_SHA 0x03000038 +#define TLS1_CK_DHE_RSA_WITH_AES_256_SHA 0x03000039 +#define TLS1_CK_ADH_WITH_AES_256_SHA 0x0300003A + +/* Camellia ciphersuites from RFC4132 */ +#define TLS1_CK_RSA_WITH_CAMELLIA_128_CBC_SHA 0x03000041 +#define TLS1_CK_DH_DSS_WITH_CAMELLIA_128_CBC_SHA 0x03000042 +#define TLS1_CK_DH_RSA_WITH_CAMELLIA_128_CBC_SHA 0x03000043 +#define TLS1_CK_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA 0x03000044 +#define TLS1_CK_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA 0x03000045 +#define TLS1_CK_ADH_WITH_CAMELLIA_128_CBC_SHA 0x03000046 + +#define TLS1_CK_RSA_WITH_CAMELLIA_256_CBC_SHA 0x03000084 +#define TLS1_CK_DH_DSS_WITH_CAMELLIA_256_CBC_SHA 0x03000085 +#define TLS1_CK_DH_RSA_WITH_CAMELLIA_256_CBC_SHA 0x03000086 +#define TLS1_CK_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA 0x03000087 +#define TLS1_CK_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA 0x03000088 +#define TLS1_CK_ADH_WITH_CAMELLIA_256_CBC_SHA 0x03000089 + +/* SEED ciphersuites from RFC4162 */ +#define TLS1_CK_RSA_WITH_SEED_SHA 0x03000096 +#define TLS1_CK_DH_DSS_WITH_SEED_SHA 0x03000097 +#define TLS1_CK_DH_RSA_WITH_SEED_SHA 0x03000098 +#define TLS1_CK_DHE_DSS_WITH_SEED_SHA 0x03000099 +#define TLS1_CK_DHE_RSA_WITH_SEED_SHA 0x0300009A +#define TLS1_CK_ADH_WITH_SEED_SHA 0x0300009B + +/* ECC ciphersuites from draft-ietf-tls-ecc-12.txt with changes soon to be in draft 13 */ +#define TLS1_CK_ECDH_ECDSA_WITH_NULL_SHA 0x0300C001 +#define TLS1_CK_ECDH_ECDSA_WITH_RC4_128_SHA 0x0300C002 +#define TLS1_CK_ECDH_ECDSA_WITH_DES_192_CBC3_SHA 0x0300C003 +#define TLS1_CK_ECDH_ECDSA_WITH_AES_128_CBC_SHA 0x0300C004 +#define TLS1_CK_ECDH_ECDSA_WITH_AES_256_CBC_SHA 0x0300C005 + +#define TLS1_CK_ECDHE_ECDSA_WITH_NULL_SHA 0x0300C006 +#define TLS1_CK_ECDHE_ECDSA_WITH_RC4_128_SHA 0x0300C007 +#define TLS1_CK_ECDHE_ECDSA_WITH_DES_192_CBC3_SHA 0x0300C008 +#define TLS1_CK_ECDHE_ECDSA_WITH_AES_128_CBC_SHA 0x0300C009 +#define TLS1_CK_ECDHE_ECDSA_WITH_AES_256_CBC_SHA 0x0300C00A + +#define TLS1_CK_ECDH_RSA_WITH_NULL_SHA 0x0300C00B +#define TLS1_CK_ECDH_RSA_WITH_RC4_128_SHA 0x0300C00C +#define TLS1_CK_ECDH_RSA_WITH_DES_192_CBC3_SHA 0x0300C00D +#define TLS1_CK_ECDH_RSA_WITH_AES_128_CBC_SHA 0x0300C00E +#define TLS1_CK_ECDH_RSA_WITH_AES_256_CBC_SHA 0x0300C00F + +#define TLS1_CK_ECDHE_RSA_WITH_NULL_SHA 0x0300C010 +#define TLS1_CK_ECDHE_RSA_WITH_RC4_128_SHA 0x0300C011 +#define TLS1_CK_ECDHE_RSA_WITH_DES_192_CBC3_SHA 0x0300C012 +#define TLS1_CK_ECDHE_RSA_WITH_AES_128_CBC_SHA 0x0300C013 +#define TLS1_CK_ECDHE_RSA_WITH_AES_256_CBC_SHA 0x0300C014 + +#define TLS1_CK_ECDH_anon_WITH_NULL_SHA 0x0300C015 +#define TLS1_CK_ECDH_anon_WITH_RC4_128_SHA 0x0300C016 +#define TLS1_CK_ECDH_anon_WITH_DES_192_CBC3_SHA 0x0300C017 +#define TLS1_CK_ECDH_anon_WITH_AES_128_CBC_SHA 0x0300C018 +#define TLS1_CK_ECDH_anon_WITH_AES_256_CBC_SHA 0x0300C019 + +/* XXX + * Inconsistency alert: + * The OpenSSL names of ciphers with ephemeral DH here include the string + * "DHE", while elsewhere it has always been "EDH". + * (The alias for the list of all such ciphers also is "EDH".) + * The specifications speak of "EDH"; maybe we should allow both forms + * for everything. */ +#define TLS1_TXT_RSA_EXPORT1024_WITH_RC4_56_MD5 "EXP1024-RC4-MD5" +#define TLS1_TXT_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5 "EXP1024-RC2-CBC-MD5" +#define TLS1_TXT_RSA_EXPORT1024_WITH_DES_CBC_SHA "EXP1024-DES-CBC-SHA" +#define TLS1_TXT_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA "EXP1024-DHE-DSS-DES-CBC-SHA" +#define TLS1_TXT_RSA_EXPORT1024_WITH_RC4_56_SHA "EXP1024-RC4-SHA" +#define TLS1_TXT_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA "EXP1024-DHE-DSS-RC4-SHA" +#define TLS1_TXT_DHE_DSS_WITH_RC4_128_SHA "DHE-DSS-RC4-SHA" + +/* AES ciphersuites from RFC3268 */ +#define TLS1_TXT_RSA_WITH_AES_128_SHA "AES128-SHA" +#define TLS1_TXT_DH_DSS_WITH_AES_128_SHA "DH-DSS-AES128-SHA" +#define TLS1_TXT_DH_RSA_WITH_AES_128_SHA "DH-RSA-AES128-SHA" +#define TLS1_TXT_DHE_DSS_WITH_AES_128_SHA "DHE-DSS-AES128-SHA" +#define TLS1_TXT_DHE_RSA_WITH_AES_128_SHA "DHE-RSA-AES128-SHA" +#define TLS1_TXT_ADH_WITH_AES_128_SHA "ADH-AES128-SHA" + +#define TLS1_TXT_RSA_WITH_AES_256_SHA "AES256-SHA" +#define TLS1_TXT_DH_DSS_WITH_AES_256_SHA "DH-DSS-AES256-SHA" +#define TLS1_TXT_DH_RSA_WITH_AES_256_SHA "DH-RSA-AES256-SHA" +#define TLS1_TXT_DHE_DSS_WITH_AES_256_SHA "DHE-DSS-AES256-SHA" +#define TLS1_TXT_DHE_RSA_WITH_AES_256_SHA "DHE-RSA-AES256-SHA" +#define TLS1_TXT_ADH_WITH_AES_256_SHA "ADH-AES256-SHA" + +/* ECC ciphersuites from draft-ietf-tls-ecc-01.txt (Mar 15, 2001) */ +#define TLS1_TXT_ECDH_ECDSA_WITH_NULL_SHA "ECDH-ECDSA-NULL-SHA" +#define TLS1_TXT_ECDH_ECDSA_WITH_RC4_128_SHA "ECDH-ECDSA-RC4-SHA" +#define TLS1_TXT_ECDH_ECDSA_WITH_DES_192_CBC3_SHA "ECDH-ECDSA-DES-CBC3-SHA" +#define TLS1_TXT_ECDH_ECDSA_WITH_AES_128_CBC_SHA "ECDH-ECDSA-AES128-SHA" +#define TLS1_TXT_ECDH_ECDSA_WITH_AES_256_CBC_SHA "ECDH-ECDSA-AES256-SHA" + +#define TLS1_TXT_ECDHE_ECDSA_WITH_NULL_SHA "ECDHE-ECDSA-NULL-SHA" +#define TLS1_TXT_ECDHE_ECDSA_WITH_RC4_128_SHA "ECDHE-ECDSA-RC4-SHA" +#define TLS1_TXT_ECDHE_ECDSA_WITH_DES_192_CBC3_SHA "ECDHE-ECDSA-DES-CBC3-SHA" +#define TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CBC_SHA "ECDHE-ECDSA-AES128-SHA" +#define TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CBC_SHA "ECDHE-ECDSA-AES256-SHA" + +#define TLS1_TXT_ECDH_RSA_WITH_NULL_SHA "ECDH-RSA-NULL-SHA" +#define TLS1_TXT_ECDH_RSA_WITH_RC4_128_SHA "ECDH-RSA-RC4-SHA" +#define TLS1_TXT_ECDH_RSA_WITH_DES_192_CBC3_SHA "ECDH-RSA-DES-CBC3-SHA" +#define TLS1_TXT_ECDH_RSA_WITH_AES_128_CBC_SHA "ECDH-RSA-AES128-SHA" +#define TLS1_TXT_ECDH_RSA_WITH_AES_256_CBC_SHA "ECDH-RSA-AES256-SHA" + +#define TLS1_TXT_ECDHE_RSA_WITH_NULL_SHA "ECDHE-RSA-NULL-SHA" +#define TLS1_TXT_ECDHE_RSA_WITH_RC4_128_SHA "ECDHE-RSA-RC4-SHA" +#define TLS1_TXT_ECDHE_RSA_WITH_DES_192_CBC3_SHA "ECDHE-RSA-DES-CBC3-SHA" +#define TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA "ECDHE-RSA-AES128-SHA" +#define TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA "ECDHE-RSA-AES256-SHA" + +#define TLS1_TXT_ECDH_anon_WITH_NULL_SHA "AECDH-NULL-SHA" +#define TLS1_TXT_ECDH_anon_WITH_RC4_128_SHA "AECDH-RC4-SHA" +#define TLS1_TXT_ECDH_anon_WITH_DES_192_CBC3_SHA "AECDH-DES-CBC3-SHA" +#define TLS1_TXT_ECDH_anon_WITH_AES_128_CBC_SHA "AECDH-AES128-SHA" +#define TLS1_TXT_ECDH_anon_WITH_AES_256_CBC_SHA "AECDH-AES256-SHA" + +/* Camellia ciphersuites from RFC4132 */ +#define TLS1_TXT_RSA_WITH_CAMELLIA_128_CBC_SHA "CAMELLIA128-SHA" +#define TLS1_TXT_DH_DSS_WITH_CAMELLIA_128_CBC_SHA "DH-DSS-CAMELLIA128-SHA" +#define TLS1_TXT_DH_RSA_WITH_CAMELLIA_128_CBC_SHA "DH-RSA-CAMELLIA128-SHA" +#define TLS1_TXT_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA "DHE-DSS-CAMELLIA128-SHA" +#define TLS1_TXT_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA "DHE-RSA-CAMELLIA128-SHA" +#define TLS1_TXT_ADH_WITH_CAMELLIA_128_CBC_SHA "ADH-CAMELLIA128-SHA" + +#define TLS1_TXT_RSA_WITH_CAMELLIA_256_CBC_SHA "CAMELLIA256-SHA" +#define TLS1_TXT_DH_DSS_WITH_CAMELLIA_256_CBC_SHA "DH-DSS-CAMELLIA256-SHA" +#define TLS1_TXT_DH_RSA_WITH_CAMELLIA_256_CBC_SHA "DH-RSA-CAMELLIA256-SHA" +#define TLS1_TXT_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA "DHE-DSS-CAMELLIA256-SHA" +#define TLS1_TXT_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA "DHE-RSA-CAMELLIA256-SHA" +#define TLS1_TXT_ADH_WITH_CAMELLIA_256_CBC_SHA "ADH-CAMELLIA256-SHA" + +/* SEED ciphersuites from RFC4162 */ +#define TLS1_TXT_RSA_WITH_SEED_SHA "SEED-SHA" +#define TLS1_TXT_DH_DSS_WITH_SEED_SHA "DH-DSS-SEED-SHA" +#define TLS1_TXT_DH_RSA_WITH_SEED_SHA "DH-RSA-SEED-SHA" +#define TLS1_TXT_DHE_DSS_WITH_SEED_SHA "DHE-DSS-SEED-SHA" +#define TLS1_TXT_DHE_RSA_WITH_SEED_SHA "DHE-RSA-SEED-SHA" +#define TLS1_TXT_ADH_WITH_SEED_SHA "ADH-SEED-SHA" + +#define TLS_CT_RSA_SIGN 1 +#define TLS_CT_DSS_SIGN 2 +#define TLS_CT_RSA_FIXED_DH 3 +#define TLS_CT_DSS_FIXED_DH 4 +#define TLS_CT_ECDSA_SIGN 64 +#define TLS_CT_RSA_FIXED_ECDH 65 +#define TLS_CT_ECDSA_FIXED_ECDH 66 +#define TLS_CT_NUMBER 7 + +#define TLS1_FINISH_MAC_LENGTH 12 + +#define TLS_MD_MAX_CONST_SIZE 20 +#define TLS_MD_CLIENT_FINISH_CONST "client finished" +#define TLS_MD_CLIENT_FINISH_CONST_SIZE 15 +#define TLS_MD_SERVER_FINISH_CONST "server finished" +#define TLS_MD_SERVER_FINISH_CONST_SIZE 15 +#define TLS_MD_SERVER_WRITE_KEY_CONST "server write key" +#define TLS_MD_SERVER_WRITE_KEY_CONST_SIZE 16 +#define TLS_MD_KEY_EXPANSION_CONST "key expansion" +#define TLS_MD_KEY_EXPANSION_CONST_SIZE 13 +#define TLS_MD_CLIENT_WRITE_KEY_CONST "client write key" +#define TLS_MD_CLIENT_WRITE_KEY_CONST_SIZE 16 +#define TLS_MD_SERVER_WRITE_KEY_CONST "server write key" +#define TLS_MD_SERVER_WRITE_KEY_CONST_SIZE 16 +#define TLS_MD_IV_BLOCK_CONST "IV block" +#define TLS_MD_IV_BLOCK_CONST_SIZE 8 +#define TLS_MD_MASTER_SECRET_CONST "master secret" +#define TLS_MD_MASTER_SECRET_CONST_SIZE 13 + +#ifdef CHARSET_EBCDIC +#undef TLS_MD_CLIENT_FINISH_CONST +#define TLS_MD_CLIENT_FINISH_CONST "\x63\x6c\x69\x65\x6e\x74\x20\x66\x69\x6e\x69\x73\x68\x65\x64" /*client finished*/ +#undef TLS_MD_SERVER_FINISH_CONST +#define TLS_MD_SERVER_FINISH_CONST "\x73\x65\x72\x76\x65\x72\x20\x66\x69\x6e\x69\x73\x68\x65\x64" /*server finished*/ +#undef TLS_MD_SERVER_WRITE_KEY_CONST +#define TLS_MD_SERVER_WRITE_KEY_CONST "\x73\x65\x72\x76\x65\x72\x20\x77\x72\x69\x74\x65\x20\x6b\x65\x79" /*server write key*/ +#undef TLS_MD_KEY_EXPANSION_CONST +#define TLS_MD_KEY_EXPANSION_CONST "\x6b\x65\x79\x20\x65\x78\x70\x61\x6e\x73\x69\x6f\x6e" /*key expansion*/ +#undef TLS_MD_CLIENT_WRITE_KEY_CONST +#define TLS_MD_CLIENT_WRITE_KEY_CONST "\x63\x6c\x69\x65\x6e\x74\x20\x77\x72\x69\x74\x65\x20\x6b\x65\x79" /*client write key*/ +#undef TLS_MD_SERVER_WRITE_KEY_CONST +#define TLS_MD_SERVER_WRITE_KEY_CONST "\x73\x65\x72\x76\x65\x72\x20\x77\x72\x69\x74\x65\x20\x6b\x65\x79" /*server write key*/ +#undef TLS_MD_IV_BLOCK_CONST +#define TLS_MD_IV_BLOCK_CONST "\x49\x56\x20\x62\x6c\x6f\x63\x6b" /*IV block*/ +#undef TLS_MD_MASTER_SECRET_CONST +#define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" /*master secret*/ +#endif + +#ifdef __cplusplus +} +#endif +#endif + + + diff --git a/lib_tls/include/openssl/tmdiff.h b/lib_tls/include/openssl/tmdiff.h new file mode 100644 index 000000000..af5c41c64 --- /dev/null +++ b/lib_tls/include/openssl/tmdiff.h @@ -0,0 +1,93 @@ +/* crypto/tmdiff.h */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +/* Header for dynamic hash table routines + * Author - Eric Young + */ +/* ... erm yeah, "dynamic hash tables" you say? + * + * And what would dynamic hash tables have to do with any of this code *now*? + * AFAICS, this code is only referenced by crypto/bn/exp.c which is an unused + * file that I doubt compiles any more. speed.c is the only thing that could + * use this (and it has nothing to do with hash tables), yet it instead has its + * own duplication of all this stuff and looks, if anything, more complete. See + * the corresponding note in apps/speed.c. + * The Bemused - Geoff + */ + +#ifndef HEADER_TMDIFF_H +#define HEADER_TMDIFF_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct ms_tm MS_TM; + +MS_TM *ms_time_new(void ); +void ms_time_free(MS_TM *a); +void ms_time_get(MS_TM *a); +double ms_time_diff(MS_TM *start, MS_TM *end); +int ms_time_cmp(const MS_TM *ap, const MS_TM *bp); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib_tls/include/openssl/txt_db.h b/lib_tls/include/openssl/txt_db.h new file mode 100644 index 000000000..307e1ba23 --- /dev/null +++ b/lib_tls/include/openssl/txt_db.h @@ -0,0 +1,109 @@ +/* crypto/txt_db/txt_db.h */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#ifndef HEADER_TXT_DB_H +#define HEADER_TXT_DB_H + +#include +#ifndef OPENSSL_NO_BIO +#include +#endif +#include +#include + +#define DB_ERROR_OK 0 +#define DB_ERROR_MALLOC 1 +#define DB_ERROR_INDEX_CLASH 2 +#define DB_ERROR_INDEX_OUT_OF_RANGE 3 +#define DB_ERROR_NO_INDEX 4 +#define DB_ERROR_INSERT_INDEX_CLASH 5 + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct txt_db_st + { + int num_fields; + STACK /* char ** */ *data; + LHASH **index; + int (**qual)(char **); + long error; + long arg1; + long arg2; + char **arg_row; + } TXT_DB; + +#ifndef OPENSSL_NO_BIO +TXT_DB *TXT_DB_read(BIO *in, int num); +long TXT_DB_write(BIO *out, TXT_DB *db); +#else +TXT_DB *TXT_DB_read(char *in, int num); +long TXT_DB_write(char *out, TXT_DB *db); +#endif +int TXT_DB_create_index(TXT_DB *db,int field,int (*qual)(char **), + LHASH_HASH_FN_TYPE hash, LHASH_COMP_FN_TYPE cmp); +void TXT_DB_free(TXT_DB *db); +char **TXT_DB_get_by_index(TXT_DB *db, int idx, char **value); +int TXT_DB_insert(TXT_DB *db,char **value); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib_tls/include/openssl/ui.h b/lib_tls/include/openssl/ui.h new file mode 100644 index 000000000..018296412 --- /dev/null +++ b/lib_tls/include/openssl/ui.h @@ -0,0 +1,381 @@ +/* crypto/ui/ui.h -*- mode:C; c-file-style: "eay" -*- */ +/* Written by Richard Levitte (richard@levitte.org) for the OpenSSL + * project 2001. + */ +/* ==================================================================== + * Copyright (c) 2001 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#ifndef HEADER_UI_H +#define HEADER_UI_H + +#ifndef OPENSSL_NO_DEPRECATED +#include +#endif +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Declared already in ossl_typ.h */ +/* typedef struct ui_st UI; */ +/* typedef struct ui_method_st UI_METHOD; */ + + +/* All the following functions return -1 or NULL on error and in some cases + (UI_process()) -2 if interrupted or in some other way cancelled. + When everything is fine, they return 0, a positive value or a non-NULL + pointer, all depending on their purpose. */ + +/* Creators and destructor. */ +UI *UI_new(void); +UI *UI_new_method(const UI_METHOD *method); +void UI_free(UI *ui); + +/* The following functions are used to add strings to be printed and prompt + strings to prompt for data. The names are UI_{add,dup}__string + and UI_{add,dup}_input_boolean. + + UI_{add,dup}__string have the following meanings: + add add a text or prompt string. The pointers given to these + functions are used verbatim, no copying is done. + dup make a copy of the text or prompt string, then add the copy + to the collection of strings in the user interface. + + The function is a name for the functionality that the given + string shall be used for. It can be one of: + input use the string as data prompt. + verify use the string as verification prompt. This + is used to verify a previous input. + info use the string for informational output. + error use the string for error output. + Honestly, there's currently no difference between info and error for the + moment. + + UI_{add,dup}_input_boolean have the same semantics for "add" and "dup", + and are typically used when one wants to prompt for a yes/no response. + + + All of the functions in this group take a UI and a prompt string. + The string input and verify addition functions also take a flag argument, + a buffer for the result to end up with, a minimum input size and a maximum + input size (the result buffer MUST be large enough to be able to contain + the maximum number of characters). Additionally, the verify addition + functions takes another buffer to compare the result against. + The boolean input functions take an action description string (which should + be safe to ignore if the expected user action is obvious, for example with + a dialog box with an OK button and a Cancel button), a string of acceptable + characters to mean OK and to mean Cancel. The two last strings are checked + to make sure they don't have common characters. Additionally, the same + flag argument as for the string input is taken, as well as a result buffer. + The result buffer is required to be at least one byte long. Depending on + the answer, the first character from the OK or the Cancel character strings + will be stored in the first byte of the result buffer. No NUL will be + added, so the result is *not* a string. + + On success, the all return an index of the added information. That index + is usefull when retrieving results with UI_get0_result(). */ +int UI_add_input_string(UI *ui, const char *prompt, int flags, + char *result_buf, int minsize, int maxsize); +int UI_dup_input_string(UI *ui, const char *prompt, int flags, + char *result_buf, int minsize, int maxsize); +int UI_add_verify_string(UI *ui, const char *prompt, int flags, + char *result_buf, int minsize, int maxsize, const char *test_buf); +int UI_dup_verify_string(UI *ui, const char *prompt, int flags, + char *result_buf, int minsize, int maxsize, const char *test_buf); +int UI_add_input_boolean(UI *ui, const char *prompt, const char *action_desc, + const char *ok_chars, const char *cancel_chars, + int flags, char *result_buf); +int UI_dup_input_boolean(UI *ui, const char *prompt, const char *action_desc, + const char *ok_chars, const char *cancel_chars, + int flags, char *result_buf); +int UI_add_info_string(UI *ui, const char *text); +int UI_dup_info_string(UI *ui, const char *text); +int UI_add_error_string(UI *ui, const char *text); +int UI_dup_error_string(UI *ui, const char *text); + +/* These are the possible flags. They can be or'ed together. */ +/* Use to have echoing of input */ +#define UI_INPUT_FLAG_ECHO 0x01 +/* Use a default password. Where that password is found is completely + up to the application, it might for example be in the user data set + with UI_add_user_data(). It is not recommended to have more than + one input in each UI being marked with this flag, or the application + might get confused. */ +#define UI_INPUT_FLAG_DEFAULT_PWD 0x02 + +/* The user of these routines may want to define flags of their own. The core + UI won't look at those, but will pass them on to the method routines. They + must use higher bits so they don't get confused with the UI bits above. + UI_INPUT_FLAG_USER_BASE tells which is the lowest bit to use. A good + example of use is this: + + #define MY_UI_FLAG1 (0x01 << UI_INPUT_FLAG_USER_BASE) + +*/ +#define UI_INPUT_FLAG_USER_BASE 16 + + +/* The following function helps construct a prompt. object_desc is a + textual short description of the object, for example "pass phrase", + and object_name is the name of the object (might be a card name or + a file name. + The returned string shall always be allocated on the heap with + OPENSSL_malloc(), and need to be free'd with OPENSSL_free(). + + If the ui_method doesn't contain a pointer to a user-defined prompt + constructor, a default string is built, looking like this: + + "Enter {object_desc} for {object_name}:" + + So, if object_desc has the value "pass phrase" and object_name has + the value "foo.key", the resulting string is: + + "Enter pass phrase for foo.key:" +*/ +char *UI_construct_prompt(UI *ui_method, + const char *object_desc, const char *object_name); + + +/* The following function is used to store a pointer to user-specific data. + Any previous such pointer will be returned and replaced. + + For callback purposes, this function makes a lot more sense than using + ex_data, since the latter requires that different parts of OpenSSL or + applications share the same ex_data index. + + Note that the UI_OpenSSL() method completely ignores the user data. + Other methods may not, however. */ +void *UI_add_user_data(UI *ui, void *user_data); +/* We need a user data retrieving function as well. */ +void *UI_get0_user_data(UI *ui); + +/* Return the result associated with a prompt given with the index i. */ +const char *UI_get0_result(UI *ui, int i); + +/* When all strings have been added, process the whole thing. */ +int UI_process(UI *ui); + +/* Give a user interface parametrised control commands. This can be used to + send down an integer, a data pointer or a function pointer, as well as + be used to get information from a UI. */ +int UI_ctrl(UI *ui, int cmd, long i, void *p, void (*f)(void)); + +/* The commands */ +/* Use UI_CONTROL_PRINT_ERRORS with the value 1 to have UI_process print the + OpenSSL error stack before printing any info or added error messages and + before any prompting. */ +#define UI_CTRL_PRINT_ERRORS 1 +/* Check if a UI_process() is possible to do again with the same instance of + a user interface. This makes UI_ctrl() return 1 if it is redoable, and 0 + if not. */ +#define UI_CTRL_IS_REDOABLE 2 + + +/* Some methods may use extra data */ +#define UI_set_app_data(s,arg) UI_set_ex_data(s,0,arg) +#define UI_get_app_data(s) UI_get_ex_data(s,0) +int UI_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func, + CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func); +int UI_set_ex_data(UI *r,int idx,void *arg); +void *UI_get_ex_data(UI *r, int idx); + +/* Use specific methods instead of the built-in one */ +void UI_set_default_method(const UI_METHOD *meth); +const UI_METHOD *UI_get_default_method(void); +const UI_METHOD *UI_get_method(UI *ui); +const UI_METHOD *UI_set_method(UI *ui, const UI_METHOD *meth); + +/* The method with all the built-in thingies */ +UI_METHOD *UI_OpenSSL(void); + + +/* ---------- For method writers ---------- */ +/* A method contains a number of functions that implement the low level + of the User Interface. The functions are: + + an opener This function starts a session, maybe by opening + a channel to a tty, or by opening a window. + a writer This function is called to write a given string, + maybe to the tty, maybe as a field label in a + window. + a flusher This function is called to flush everything that + has been output so far. It can be used to actually + display a dialog box after it has been built. + a reader This function is called to read a given prompt, + maybe from the tty, maybe from a field in a + window. Note that it's called wth all string + structures, not only the prompt ones, so it must + check such things itself. + a closer This function closes the session, maybe by closing + the channel to the tty, or closing the window. + + All these functions are expected to return: + + 0 on error. + 1 on success. + -1 on out-of-band events, for example if some prompting has + been canceled (by pressing Ctrl-C, for example). This is + only checked when returned by the flusher or the reader. + + The way this is used, the opener is first called, then the writer for all + strings, then the flusher, then the reader for all strings and finally the + closer. Note that if you want to prompt from a terminal or other command + line interface, the best is to have the reader also write the prompts + instead of having the writer do it. If you want to prompt from a dialog + box, the writer can be used to build up the contents of the box, and the + flusher to actually display the box and run the event loop until all data + has been given, after which the reader only grabs the given data and puts + them back into the UI strings. + + All method functions take a UI as argument. Additionally, the writer and + the reader take a UI_STRING. +*/ + +/* The UI_STRING type is the data structure that contains all the needed info + about a string or a prompt, including test data for a verification prompt. +*/ +DECLARE_STACK_OF(UI_STRING) +typedef struct ui_string_st UI_STRING; + +/* The different types of strings that are currently supported. + This is only needed by method authors. */ +enum UI_string_types + { + UIT_NONE=0, + UIT_PROMPT, /* Prompt for a string */ + UIT_VERIFY, /* Prompt for a string and verify */ + UIT_BOOLEAN, /* Prompt for a yes/no response */ + UIT_INFO, /* Send info to the user */ + UIT_ERROR /* Send an error message to the user */ + }; + +/* Create and manipulate methods */ +UI_METHOD *UI_create_method(char *name); +void UI_destroy_method(UI_METHOD *ui_method); +int UI_method_set_opener(UI_METHOD *method, int (*opener)(UI *ui)); +int UI_method_set_writer(UI_METHOD *method, int (*writer)(UI *ui, UI_STRING *uis)); +int UI_method_set_flusher(UI_METHOD *method, int (*flusher)(UI *ui)); +int UI_method_set_reader(UI_METHOD *method, int (*reader)(UI *ui, UI_STRING *uis)); +int UI_method_set_closer(UI_METHOD *method, int (*closer)(UI *ui)); +int (*UI_method_get_opener(UI_METHOD *method))(UI*); +int (*UI_method_get_writer(UI_METHOD *method))(UI*,UI_STRING*); +int (*UI_method_get_flusher(UI_METHOD *method))(UI*); +int (*UI_method_get_reader(UI_METHOD *method))(UI*,UI_STRING*); +int (*UI_method_get_closer(UI_METHOD *method))(UI*); + +/* The following functions are helpers for method writers to access relevant + data from a UI_STRING. */ + +/* Return type of the UI_STRING */ +enum UI_string_types UI_get_string_type(UI_STRING *uis); +/* Return input flags of the UI_STRING */ +int UI_get_input_flags(UI_STRING *uis); +/* Return the actual string to output (the prompt, info or error) */ +const char *UI_get0_output_string(UI_STRING *uis); +/* Return the optional action string to output (the boolean promtp instruction) */ +const char *UI_get0_action_string(UI_STRING *uis); +/* Return the result of a prompt */ +const char *UI_get0_result_string(UI_STRING *uis); +/* Return the string to test the result against. Only useful with verifies. */ +const char *UI_get0_test_string(UI_STRING *uis); +/* Return the required minimum size of the result */ +int UI_get_result_minsize(UI_STRING *uis); +/* Return the required maximum size of the result */ +int UI_get_result_maxsize(UI_STRING *uis); +/* Set the result of a UI_STRING. */ +int UI_set_result(UI *ui, UI_STRING *uis, const char *result); + + +/* A couple of popular utility functions */ +int UI_UTIL_read_pw_string(char *buf,int length,const char *prompt,int verify); +int UI_UTIL_read_pw(char *buf,char *buff,int size,const char *prompt,int verify); + + +/* BEGIN ERROR CODES */ +/* The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ +void ERR_load_UI_strings(void); + +/* Error codes for the UI functions. */ + +/* Function codes. */ +#define UI_F_GENERAL_ALLOCATE_BOOLEAN 108 +#define UI_F_GENERAL_ALLOCATE_PROMPT 109 +#define UI_F_GENERAL_ALLOCATE_STRING 100 +#define UI_F_UI_CTRL 111 +#define UI_F_UI_DUP_ERROR_STRING 101 +#define UI_F_UI_DUP_INFO_STRING 102 +#define UI_F_UI_DUP_INPUT_BOOLEAN 110 +#define UI_F_UI_DUP_INPUT_STRING 103 +#define UI_F_UI_DUP_VERIFY_STRING 106 +#define UI_F_UI_GET0_RESULT 107 +#define UI_F_UI_NEW_METHOD 104 +#define UI_F_UI_SET_RESULT 105 + +/* Reason codes. */ +#define UI_R_COMMON_OK_AND_CANCEL_CHARACTERS 104 +#define UI_R_INDEX_TOO_LARGE 102 +#define UI_R_INDEX_TOO_SMALL 103 +#define UI_R_NO_RESULT_BUFFER 105 +#define UI_R_RESULT_TOO_LARGE 100 +#define UI_R_RESULT_TOO_SMALL 101 +#define UI_R_UNKNOWN_CONTROL_COMMAND 106 + +#ifdef __cplusplus +} +#endif +#endif diff --git a/lib_tls/include/openssl/ui_compat.h b/lib_tls/include/openssl/ui_compat.h new file mode 100644 index 000000000..b35c9bb7f --- /dev/null +++ b/lib_tls/include/openssl/ui_compat.h @@ -0,0 +1,83 @@ +/* crypto/ui/ui.h -*- mode:C; c-file-style: "eay" -*- */ +/* Written by Richard Levitte (richard@levitte.org) for the OpenSSL + * project 2001. + */ +/* ==================================================================== + * Copyright (c) 2001 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#ifndef HEADER_UI_COMPAT_H +#define HEADER_UI_COMPAT_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* The following functions were previously part of the DES section, + and are provided here for backward compatibility reasons. */ + +#define des_read_pw_string(b,l,p,v) \ + _ossl_old_des_read_pw_string((b),(l),(p),(v)) +#define des_read_pw(b,bf,s,p,v) \ + _ossl_old_des_read_pw((b),(bf),(s),(p),(v)) + +int _ossl_old_des_read_pw_string(char *buf,int length,const char *prompt,int verify); +int _ossl_old_des_read_pw(char *buf,char *buff,int size,const char *prompt,int verify); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/lib_tls/include/openssl/x509.h b/lib_tls/include/openssl/x509.h new file mode 100644 index 000000000..e71b5257e --- /dev/null +++ b/lib_tls/include/openssl/x509.h @@ -0,0 +1,1355 @@ +/* crypto/x509/x509.h */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * ECDH support in OpenSSL originally developed by + * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project. + */ + +#ifndef HEADER_X509_H +#define HEADER_X509_H + +#include +#include +#ifndef OPENSSL_NO_BUFFER +#include +#endif +#ifndef OPENSSL_NO_EVP +#include +#endif +#ifndef OPENSSL_NO_BIO +#include +#endif +#include +#include +#include + +#ifndef OPENSSL_NO_EC +#include +#endif + +#ifndef OPENSSL_NO_ECDSA +#include +#endif + +#ifndef OPENSSL_NO_ECDH +#include +#endif + +#ifndef OPENSSL_NO_DEPRECATED +#ifndef OPENSSL_NO_RSA +#include +#endif +#ifndef OPENSSL_NO_DSA +#include +#endif +#ifndef OPENSSL_NO_DH +#include +#endif +#endif + +#ifndef OPENSSL_NO_SHA +#include +#endif +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef OPENSSL_SYS_WIN32 +/* Under Win32 these are defined in wincrypt.h */ +#undef X509_NAME +#undef X509_CERT_PAIR +#endif + +#define X509_FILETYPE_PEM 1 +#define X509_FILETYPE_ASN1 2 +#define X509_FILETYPE_DEFAULT 3 + +#define X509v3_KU_DIGITAL_SIGNATURE 0x0080 +#define X509v3_KU_NON_REPUDIATION 0x0040 +#define X509v3_KU_KEY_ENCIPHERMENT 0x0020 +#define X509v3_KU_DATA_ENCIPHERMENT 0x0010 +#define X509v3_KU_KEY_AGREEMENT 0x0008 +#define X509v3_KU_KEY_CERT_SIGN 0x0004 +#define X509v3_KU_CRL_SIGN 0x0002 +#define X509v3_KU_ENCIPHER_ONLY 0x0001 +#define X509v3_KU_DECIPHER_ONLY 0x8000 +#define X509v3_KU_UNDEF 0xffff + +typedef struct X509_objects_st + { + int nid; + int (*a2i)(void); + int (*i2a)(void); + } X509_OBJECTS; + +struct X509_algor_st + { + ASN1_OBJECT *algorithm; + ASN1_TYPE *parameter; + } /* X509_ALGOR */; + +DECLARE_ASN1_SET_OF(X509_ALGOR) + +typedef STACK_OF(X509_ALGOR) X509_ALGORS; + +typedef struct X509_val_st + { + ASN1_TIME *notBefore; + ASN1_TIME *notAfter; + } X509_VAL; + +typedef struct X509_pubkey_st + { + X509_ALGOR *algor; + ASN1_BIT_STRING *public_key; + EVP_PKEY *pkey; + } X509_PUBKEY; + +typedef struct X509_sig_st + { + X509_ALGOR *algor; + ASN1_OCTET_STRING *digest; + } X509_SIG; + +typedef struct X509_name_entry_st + { + ASN1_OBJECT *object; + ASN1_STRING *value; + int set; + int size; /* temp variable */ + } X509_NAME_ENTRY; + +DECLARE_STACK_OF(X509_NAME_ENTRY) +DECLARE_ASN1_SET_OF(X509_NAME_ENTRY) + +/* we always keep X509_NAMEs in 2 forms. */ +struct X509_name_st + { + STACK_OF(X509_NAME_ENTRY) *entries; + int modified; /* true if 'bytes' needs to be built */ +#ifndef OPENSSL_NO_BUFFER + BUF_MEM *bytes; +#else + char *bytes; +#endif + unsigned long hash; /* Keep the hash around for lookups */ + } /* X509_NAME */; + +DECLARE_STACK_OF(X509_NAME) + +#define X509_EX_V_NETSCAPE_HACK 0x8000 +#define X509_EX_V_INIT 0x0001 +typedef struct X509_extension_st + { + ASN1_OBJECT *object; + ASN1_BOOLEAN critical; + ASN1_OCTET_STRING *value; + } X509_EXTENSION; + +typedef STACK_OF(X509_EXTENSION) X509_EXTENSIONS; + +DECLARE_STACK_OF(X509_EXTENSION) +DECLARE_ASN1_SET_OF(X509_EXTENSION) + +/* a sequence of these are used */ +typedef struct x509_attributes_st + { + ASN1_OBJECT *object; + int single; /* 0 for a set, 1 for a single item (which is wrong) */ + union { + char *ptr; +/* 0 */ STACK_OF(ASN1_TYPE) *set; +/* 1 */ ASN1_TYPE *single; + } value; + } X509_ATTRIBUTE; + +DECLARE_STACK_OF(X509_ATTRIBUTE) +DECLARE_ASN1_SET_OF(X509_ATTRIBUTE) + + +typedef struct X509_req_info_st + { + ASN1_ENCODING enc; + ASN1_INTEGER *version; + X509_NAME *subject; + X509_PUBKEY *pubkey; + /* d=2 hl=2 l= 0 cons: cont: 00 */ + STACK_OF(X509_ATTRIBUTE) *attributes; /* [ 0 ] */ + } X509_REQ_INFO; + +typedef struct X509_req_st + { + X509_REQ_INFO *req_info; + X509_ALGOR *sig_alg; + ASN1_BIT_STRING *signature; + int references; + } X509_REQ; + +typedef struct x509_cinf_st + { + ASN1_INTEGER *version; /* [ 0 ] default of v1 */ + ASN1_INTEGER *serialNumber; + X509_ALGOR *signature; + X509_NAME *issuer; + X509_VAL *validity; + X509_NAME *subject; + X509_PUBKEY *key; + ASN1_BIT_STRING *issuerUID; /* [ 1 ] optional in v2 */ + ASN1_BIT_STRING *subjectUID; /* [ 2 ] optional in v2 */ + STACK_OF(X509_EXTENSION) *extensions; /* [ 3 ] optional in v3 */ + } X509_CINF; + +/* This stuff is certificate "auxiliary info" + * it contains details which are useful in certificate + * stores and databases. When used this is tagged onto + * the end of the certificate itself + */ + +typedef struct x509_cert_aux_st + { + STACK_OF(ASN1_OBJECT) *trust; /* trusted uses */ + STACK_OF(ASN1_OBJECT) *reject; /* rejected uses */ + ASN1_UTF8STRING *alias; /* "friendly name" */ + ASN1_OCTET_STRING *keyid; /* key id of private key */ + STACK_OF(X509_ALGOR) *other; /* other unspecified info */ + } X509_CERT_AUX; + +struct x509_st + { + X509_CINF *cert_info; + X509_ALGOR *sig_alg; + ASN1_BIT_STRING *signature; + int valid; + int references; + char *name; + CRYPTO_EX_DATA ex_data; + /* These contain copies of various extension values */ + long ex_pathlen; + long ex_pcpathlen; + unsigned long ex_flags; + unsigned long ex_kusage; + unsigned long ex_xkusage; + unsigned long ex_nscert; + ASN1_OCTET_STRING *skid; + struct AUTHORITY_KEYID_st *akid; + X509_POLICY_CACHE *policy_cache; +#ifndef OPENSSL_NO_RFC3779 + STACK_OF(IPAddressFamily) *rfc3779_addr; + struct ASIdentifiers_st *rfc3779_asid; +#endif +#ifndef OPENSSL_NO_SHA + unsigned char sha1_hash[SHA_DIGEST_LENGTH]; +#endif + X509_CERT_AUX *aux; + } /* X509 */; + +DECLARE_STACK_OF(X509) +DECLARE_ASN1_SET_OF(X509) + +/* This is used for a table of trust checking functions */ + +typedef struct x509_trust_st { + int trust; + int flags; + int (*check_trust)(struct x509_trust_st *, X509 *, int); + char *name; + int arg1; + void *arg2; +} X509_TRUST; + +DECLARE_STACK_OF(X509_TRUST) + +typedef struct x509_cert_pair_st { + X509 *forward; + X509 *reverse; +} X509_CERT_PAIR; + +/* standard trust ids */ + +#define X509_TRUST_DEFAULT -1 /* Only valid in purpose settings */ + +#define X509_TRUST_COMPAT 1 +#define X509_TRUST_SSL_CLIENT 2 +#define X509_TRUST_SSL_SERVER 3 +#define X509_TRUST_EMAIL 4 +#define X509_TRUST_OBJECT_SIGN 5 +#define X509_TRUST_OCSP_SIGN 6 +#define X509_TRUST_OCSP_REQUEST 7 + +/* Keep these up to date! */ +#define X509_TRUST_MIN 1 +#define X509_TRUST_MAX 7 + + +/* trust_flags values */ +#define X509_TRUST_DYNAMIC 1 +#define X509_TRUST_DYNAMIC_NAME 2 + +/* check_trust return codes */ + +#define X509_TRUST_TRUSTED 1 +#define X509_TRUST_REJECTED 2 +#define X509_TRUST_UNTRUSTED 3 + +/* Flags for X509_print_ex() */ + +#define X509_FLAG_COMPAT 0 +#define X509_FLAG_NO_HEADER 1L +#define X509_FLAG_NO_VERSION (1L << 1) +#define X509_FLAG_NO_SERIAL (1L << 2) +#define X509_FLAG_NO_SIGNAME (1L << 3) +#define X509_FLAG_NO_ISSUER (1L << 4) +#define X509_FLAG_NO_VALIDITY (1L << 5) +#define X509_FLAG_NO_SUBJECT (1L << 6) +#define X509_FLAG_NO_PUBKEY (1L << 7) +#define X509_FLAG_NO_EXTENSIONS (1L << 8) +#define X509_FLAG_NO_SIGDUMP (1L << 9) +#define X509_FLAG_NO_AUX (1L << 10) +#define X509_FLAG_NO_ATTRIBUTES (1L << 11) + +/* Flags specific to X509_NAME_print_ex() */ + +/* The field separator information */ + +#define XN_FLAG_SEP_MASK (0xf << 16) + +#define XN_FLAG_COMPAT 0 /* Traditional SSLeay: use old X509_NAME_print */ +#define XN_FLAG_SEP_COMMA_PLUS (1 << 16) /* RFC2253 ,+ */ +#define XN_FLAG_SEP_CPLUS_SPC (2 << 16) /* ,+ spaced: more readable */ +#define XN_FLAG_SEP_SPLUS_SPC (3 << 16) /* ;+ spaced */ +#define XN_FLAG_SEP_MULTILINE (4 << 16) /* One line per field */ + +#define XN_FLAG_DN_REV (1 << 20) /* Reverse DN order */ + +/* How the field name is shown */ + +#define XN_FLAG_FN_MASK (0x3 << 21) + +#define XN_FLAG_FN_SN 0 /* Object short name */ +#define XN_FLAG_FN_LN (1 << 21) /* Object long name */ +#define XN_FLAG_FN_OID (2 << 21) /* Always use OIDs */ +#define XN_FLAG_FN_NONE (3 << 21) /* No field names */ + +#define XN_FLAG_SPC_EQ (1 << 23) /* Put spaces round '=' */ + +/* This determines if we dump fields we don't recognise: + * RFC2253 requires this. + */ + +#define XN_FLAG_DUMP_UNKNOWN_FIELDS (1 << 24) + +#define XN_FLAG_FN_ALIGN (1 << 25) /* Align field names to 20 characters */ + +/* Complete set of RFC2253 flags */ + +#define XN_FLAG_RFC2253 (ASN1_STRFLGS_RFC2253 | \ + XN_FLAG_SEP_COMMA_PLUS | \ + XN_FLAG_DN_REV | \ + XN_FLAG_FN_SN | \ + XN_FLAG_DUMP_UNKNOWN_FIELDS) + +/* readable oneline form */ + +#define XN_FLAG_ONELINE (ASN1_STRFLGS_RFC2253 | \ + ASN1_STRFLGS_ESC_QUOTE | \ + XN_FLAG_SEP_CPLUS_SPC | \ + XN_FLAG_SPC_EQ | \ + XN_FLAG_FN_SN) + +/* readable multiline form */ + +#define XN_FLAG_MULTILINE (ASN1_STRFLGS_ESC_CTRL | \ + ASN1_STRFLGS_ESC_MSB | \ + XN_FLAG_SEP_MULTILINE | \ + XN_FLAG_SPC_EQ | \ + XN_FLAG_FN_LN | \ + XN_FLAG_FN_ALIGN) + +typedef struct X509_revoked_st + { + ASN1_INTEGER *serialNumber; + ASN1_TIME *revocationDate; + STACK_OF(X509_EXTENSION) /* optional */ *extensions; + int sequence; /* load sequence */ + } X509_REVOKED; + +DECLARE_STACK_OF(X509_REVOKED) +DECLARE_ASN1_SET_OF(X509_REVOKED) + +typedef struct X509_crl_info_st + { + ASN1_INTEGER *version; + X509_ALGOR *sig_alg; + X509_NAME *issuer; + ASN1_TIME *lastUpdate; + ASN1_TIME *nextUpdate; + STACK_OF(X509_REVOKED) *revoked; + STACK_OF(X509_EXTENSION) /* [0] */ *extensions; + ASN1_ENCODING enc; + } X509_CRL_INFO; + +struct X509_crl_st + { + /* actual signature */ + X509_CRL_INFO *crl; + X509_ALGOR *sig_alg; + ASN1_BIT_STRING *signature; + int references; + } /* X509_CRL */; + +DECLARE_STACK_OF(X509_CRL) +DECLARE_ASN1_SET_OF(X509_CRL) + +typedef struct private_key_st + { + int version; + /* The PKCS#8 data types */ + X509_ALGOR *enc_algor; + ASN1_OCTET_STRING *enc_pkey; /* encrypted pub key */ + + /* When decrypted, the following will not be NULL */ + EVP_PKEY *dec_pkey; + + /* used to encrypt and decrypt */ + int key_length; + char *key_data; + int key_free; /* true if we should auto free key_data */ + + /* expanded version of 'enc_algor' */ + EVP_CIPHER_INFO cipher; + + int references; + } X509_PKEY; + +#ifndef OPENSSL_NO_EVP +typedef struct X509_info_st + { + X509 *x509; + X509_CRL *crl; + X509_PKEY *x_pkey; + + EVP_CIPHER_INFO enc_cipher; + int enc_len; + char *enc_data; + + int references; + } X509_INFO; + +DECLARE_STACK_OF(X509_INFO) +#endif + +/* The next 2 structures and their 8 routines were sent to me by + * Pat Richard and are used to manipulate + * Netscapes spki structures - useful if you are writing a CA web page + */ +typedef struct Netscape_spkac_st + { + X509_PUBKEY *pubkey; + ASN1_IA5STRING *challenge; /* challenge sent in atlas >= PR2 */ + } NETSCAPE_SPKAC; + +typedef struct Netscape_spki_st + { + NETSCAPE_SPKAC *spkac; /* signed public key and challenge */ + X509_ALGOR *sig_algor; + ASN1_BIT_STRING *signature; + } NETSCAPE_SPKI; + +/* Netscape certificate sequence structure */ +typedef struct Netscape_certificate_sequence + { + ASN1_OBJECT *type; + STACK_OF(X509) *certs; + } NETSCAPE_CERT_SEQUENCE; + +/* Unused (and iv length is wrong) +typedef struct CBCParameter_st + { + unsigned char iv[8]; + } CBC_PARAM; +*/ + +/* Password based encryption structure */ + +typedef struct PBEPARAM_st { +ASN1_OCTET_STRING *salt; +ASN1_INTEGER *iter; +} PBEPARAM; + +/* Password based encryption V2 structures */ + +typedef struct PBE2PARAM_st { +X509_ALGOR *keyfunc; +X509_ALGOR *encryption; +} PBE2PARAM; + +typedef struct PBKDF2PARAM_st { +ASN1_TYPE *salt; /* Usually OCTET STRING but could be anything */ +ASN1_INTEGER *iter; +ASN1_INTEGER *keylength; +X509_ALGOR *prf; +} PBKDF2PARAM; + + +/* PKCS#8 private key info structure */ + +typedef struct pkcs8_priv_key_info_st + { + int broken; /* Flag for various broken formats */ +#define PKCS8_OK 0 +#define PKCS8_NO_OCTET 1 +#define PKCS8_EMBEDDED_PARAM 2 +#define PKCS8_NS_DB 3 + ASN1_INTEGER *version; + X509_ALGOR *pkeyalg; + ASN1_TYPE *pkey; /* Should be OCTET STRING but some are broken */ + STACK_OF(X509_ATTRIBUTE) *attributes; + } PKCS8_PRIV_KEY_INFO; + +#ifdef __cplusplus +} +#endif + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef SSLEAY_MACROS +#define X509_verify(a,r) ASN1_verify((int (*)())i2d_X509_CINF,a->sig_alg,\ + a->signature,(char *)a->cert_info,r) +#define X509_REQ_verify(a,r) ASN1_verify((int (*)())i2d_X509_REQ_INFO, \ + a->sig_alg,a->signature,(char *)a->req_info,r) +#define X509_CRL_verify(a,r) ASN1_verify((int (*)())i2d_X509_CRL_INFO, \ + a->sig_alg, a->signature,(char *)a->crl,r) + +#define X509_sign(x,pkey,md) \ + ASN1_sign((int (*)())i2d_X509_CINF, x->cert_info->signature, \ + x->sig_alg, x->signature, (char *)x->cert_info,pkey,md) +#define X509_REQ_sign(x,pkey,md) \ + ASN1_sign((int (*)())i2d_X509_REQ_INFO,x->sig_alg, NULL, \ + x->signature, (char *)x->req_info,pkey,md) +#define X509_CRL_sign(x,pkey,md) \ + ASN1_sign((int (*)())i2d_X509_CRL_INFO,x->crl->sig_alg,x->sig_alg, \ + x->signature, (char *)x->crl,pkey,md) +#define NETSCAPE_SPKI_sign(x,pkey,md) \ + ASN1_sign((int (*)())i2d_NETSCAPE_SPKAC, x->sig_algor,NULL, \ + x->signature, (char *)x->spkac,pkey,md) + +#define X509_dup(x509) (X509 *)ASN1_dup((int (*)())i2d_X509, \ + (char *(*)())d2i_X509,(char *)x509) +#define X509_ATTRIBUTE_dup(xa) (X509_ATTRIBUTE *)ASN1_dup(\ + (int (*)())i2d_X509_ATTRIBUTE, \ + (char *(*)())d2i_X509_ATTRIBUTE,(char *)xa) +#define X509_EXTENSION_dup(ex) (X509_EXTENSION *)ASN1_dup( \ + (int (*)())i2d_X509_EXTENSION, \ + (char *(*)())d2i_X509_EXTENSION,(char *)ex) +#define d2i_X509_fp(fp,x509) (X509 *)ASN1_d2i_fp((char *(*)())X509_new, \ + (char *(*)())d2i_X509, (fp),(unsigned char **)(x509)) +#define i2d_X509_fp(fp,x509) ASN1_i2d_fp(i2d_X509,fp,(unsigned char *)x509) +#define d2i_X509_bio(bp,x509) (X509 *)ASN1_d2i_bio((char *(*)())X509_new, \ + (char *(*)())d2i_X509, (bp),(unsigned char **)(x509)) +#define i2d_X509_bio(bp,x509) ASN1_i2d_bio(i2d_X509,bp,(unsigned char *)x509) + +#define X509_CRL_dup(crl) (X509_CRL *)ASN1_dup((int (*)())i2d_X509_CRL, \ + (char *(*)())d2i_X509_CRL,(char *)crl) +#define d2i_X509_CRL_fp(fp,crl) (X509_CRL *)ASN1_d2i_fp((char *(*)()) \ + X509_CRL_new,(char *(*)())d2i_X509_CRL, (fp),\ + (unsigned char **)(crl)) +#define i2d_X509_CRL_fp(fp,crl) ASN1_i2d_fp(i2d_X509_CRL,fp,\ + (unsigned char *)crl) +#define d2i_X509_CRL_bio(bp,crl) (X509_CRL *)ASN1_d2i_bio((char *(*)()) \ + X509_CRL_new,(char *(*)())d2i_X509_CRL, (bp),\ + (unsigned char **)(crl)) +#define i2d_X509_CRL_bio(bp,crl) ASN1_i2d_bio(i2d_X509_CRL,bp,\ + (unsigned char *)crl) + +#define PKCS7_dup(p7) (PKCS7 *)ASN1_dup((int (*)())i2d_PKCS7, \ + (char *(*)())d2i_PKCS7,(char *)p7) +#define d2i_PKCS7_fp(fp,p7) (PKCS7 *)ASN1_d2i_fp((char *(*)()) \ + PKCS7_new,(char *(*)())d2i_PKCS7, (fp),\ + (unsigned char **)(p7)) +#define i2d_PKCS7_fp(fp,p7) ASN1_i2d_fp(i2d_PKCS7,fp,\ + (unsigned char *)p7) +#define d2i_PKCS7_bio(bp,p7) (PKCS7 *)ASN1_d2i_bio((char *(*)()) \ + PKCS7_new,(char *(*)())d2i_PKCS7, (bp),\ + (unsigned char **)(p7)) +#define i2d_PKCS7_bio(bp,p7) ASN1_i2d_bio(i2d_PKCS7,bp,\ + (unsigned char *)p7) + +#define X509_REQ_dup(req) (X509_REQ *)ASN1_dup((int (*)())i2d_X509_REQ, \ + (char *(*)())d2i_X509_REQ,(char *)req) +#define d2i_X509_REQ_fp(fp,req) (X509_REQ *)ASN1_d2i_fp((char *(*)())\ + X509_REQ_new, (char *(*)())d2i_X509_REQ, (fp),\ + (unsigned char **)(req)) +#define i2d_X509_REQ_fp(fp,req) ASN1_i2d_fp(i2d_X509_REQ,fp,\ + (unsigned char *)req) +#define d2i_X509_REQ_bio(bp,req) (X509_REQ *)ASN1_d2i_bio((char *(*)())\ + X509_REQ_new, (char *(*)())d2i_X509_REQ, (bp),\ + (unsigned char **)(req)) +#define i2d_X509_REQ_bio(bp,req) ASN1_i2d_bio(i2d_X509_REQ,bp,\ + (unsigned char *)req) + +#define RSAPublicKey_dup(rsa) (RSA *)ASN1_dup((int (*)())i2d_RSAPublicKey, \ + (char *(*)())d2i_RSAPublicKey,(char *)rsa) +#define RSAPrivateKey_dup(rsa) (RSA *)ASN1_dup((int (*)())i2d_RSAPrivateKey, \ + (char *(*)())d2i_RSAPrivateKey,(char *)rsa) + +#define d2i_RSAPrivateKey_fp(fp,rsa) (RSA *)ASN1_d2i_fp((char *(*)())\ + RSA_new,(char *(*)())d2i_RSAPrivateKey, (fp), \ + (unsigned char **)(rsa)) +#define i2d_RSAPrivateKey_fp(fp,rsa) ASN1_i2d_fp(i2d_RSAPrivateKey,fp, \ + (unsigned char *)rsa) +#define d2i_RSAPrivateKey_bio(bp,rsa) (RSA *)ASN1_d2i_bio((char *(*)())\ + RSA_new,(char *(*)())d2i_RSAPrivateKey, (bp), \ + (unsigned char **)(rsa)) +#define i2d_RSAPrivateKey_bio(bp,rsa) ASN1_i2d_bio(i2d_RSAPrivateKey,bp, \ + (unsigned char *)rsa) + +#define d2i_RSAPublicKey_fp(fp,rsa) (RSA *)ASN1_d2i_fp((char *(*)())\ + RSA_new,(char *(*)())d2i_RSAPublicKey, (fp), \ + (unsigned char **)(rsa)) +#define i2d_RSAPublicKey_fp(fp,rsa) ASN1_i2d_fp(i2d_RSAPublicKey,fp, \ + (unsigned char *)rsa) +#define d2i_RSAPublicKey_bio(bp,rsa) (RSA *)ASN1_d2i_bio((char *(*)())\ + RSA_new,(char *(*)())d2i_RSAPublicKey, (bp), \ + (unsigned char **)(rsa)) +#define i2d_RSAPublicKey_bio(bp,rsa) ASN1_i2d_bio(i2d_RSAPublicKey,bp, \ + (unsigned char *)rsa) + +#define d2i_DSAPrivateKey_fp(fp,dsa) (DSA *)ASN1_d2i_fp((char *(*)())\ + DSA_new,(char *(*)())d2i_DSAPrivateKey, (fp), \ + (unsigned char **)(dsa)) +#define i2d_DSAPrivateKey_fp(fp,dsa) ASN1_i2d_fp(i2d_DSAPrivateKey,fp, \ + (unsigned char *)dsa) +#define d2i_DSAPrivateKey_bio(bp,dsa) (DSA *)ASN1_d2i_bio((char *(*)())\ + DSA_new,(char *(*)())d2i_DSAPrivateKey, (bp), \ + (unsigned char **)(dsa)) +#define i2d_DSAPrivateKey_bio(bp,dsa) ASN1_i2d_bio(i2d_DSAPrivateKey,bp, \ + (unsigned char *)dsa) + +#define d2i_ECPrivateKey_fp(fp,ecdsa) (EC_KEY *)ASN1_d2i_fp((char *(*)())\ + EC_KEY_new,(char *(*)())d2i_ECPrivateKey, (fp), \ + (unsigned char **)(ecdsa)) +#define i2d_ECPrivateKey_fp(fp,ecdsa) ASN1_i2d_fp(i2d_ECPrivateKey,fp, \ + (unsigned char *)ecdsa) +#define d2i_ECPrivateKey_bio(bp,ecdsa) (EC_KEY *)ASN1_d2i_bio((char *(*)())\ + EC_KEY_new,(char *(*)())d2i_ECPrivateKey, (bp), \ + (unsigned char **)(ecdsa)) +#define i2d_ECPrivateKey_bio(bp,ecdsa) ASN1_i2d_bio(i2d_ECPrivateKey,bp, \ + (unsigned char *)ecdsa) + +#define X509_ALGOR_dup(xn) (X509_ALGOR *)ASN1_dup((int (*)())i2d_X509_ALGOR,\ + (char *(*)())d2i_X509_ALGOR,(char *)xn) + +#define X509_NAME_dup(xn) (X509_NAME *)ASN1_dup((int (*)())i2d_X509_NAME, \ + (char *(*)())d2i_X509_NAME,(char *)xn) +#define X509_NAME_ENTRY_dup(ne) (X509_NAME_ENTRY *)ASN1_dup( \ + (int (*)())i2d_X509_NAME_ENTRY, \ + (char *(*)())d2i_X509_NAME_ENTRY,\ + (char *)ne) + +#define X509_digest(data,type,md,len) \ + ASN1_digest((int (*)())i2d_X509,type,(char *)data,md,len) +#define X509_NAME_digest(data,type,md,len) \ + ASN1_digest((int (*)())i2d_X509_NAME,type,(char *)data,md,len) +#ifndef PKCS7_ISSUER_AND_SERIAL_digest +#define PKCS7_ISSUER_AND_SERIAL_digest(data,type,md,len) \ + ASN1_digest((int (*)())i2d_PKCS7_ISSUER_AND_SERIAL,type,\ + (char *)data,md,len) +#endif +#endif + +#define X509_EXT_PACK_UNKNOWN 1 +#define X509_EXT_PACK_STRING 2 + +#define X509_get_version(x) ASN1_INTEGER_get((x)->cert_info->version) +/* #define X509_get_serialNumber(x) ((x)->cert_info->serialNumber) */ +#define X509_get_notBefore(x) ((x)->cert_info->validity->notBefore) +#define X509_get_notAfter(x) ((x)->cert_info->validity->notAfter) +#define X509_extract_key(x) X509_get_pubkey(x) /*****/ +#define X509_REQ_get_version(x) ASN1_INTEGER_get((x)->req_info->version) +#define X509_REQ_get_subject_name(x) ((x)->req_info->subject) +#define X509_REQ_extract_key(a) X509_REQ_get_pubkey(a) +#define X509_name_cmp(a,b) X509_NAME_cmp((a),(b)) +#define X509_get_signature_type(x) EVP_PKEY_type(OBJ_obj2nid((x)->sig_alg->algorithm)) + +#define X509_CRL_get_version(x) ASN1_INTEGER_get((x)->crl->version) +#define X509_CRL_get_lastUpdate(x) ((x)->crl->lastUpdate) +#define X509_CRL_get_nextUpdate(x) ((x)->crl->nextUpdate) +#define X509_CRL_get_issuer(x) ((x)->crl->issuer) +#define X509_CRL_get_REVOKED(x) ((x)->crl->revoked) + +/* This one is only used so that a binary form can output, as in + * i2d_X509_NAME(X509_get_X509_PUBKEY(x),&buf) */ +#define X509_get_X509_PUBKEY(x) ((x)->cert_info->key) + + +const char *X509_verify_cert_error_string(long n); + +#ifndef SSLEAY_MACROS +#ifndef OPENSSL_NO_EVP +int X509_verify(X509 *a, EVP_PKEY *r); + +int X509_REQ_verify(X509_REQ *a, EVP_PKEY *r); +int X509_CRL_verify(X509_CRL *a, EVP_PKEY *r); +int NETSCAPE_SPKI_verify(NETSCAPE_SPKI *a, EVP_PKEY *r); + +NETSCAPE_SPKI * NETSCAPE_SPKI_b64_decode(const char *str, int len); +char * NETSCAPE_SPKI_b64_encode(NETSCAPE_SPKI *x); +EVP_PKEY *NETSCAPE_SPKI_get_pubkey(NETSCAPE_SPKI *x); +int NETSCAPE_SPKI_set_pubkey(NETSCAPE_SPKI *x, EVP_PKEY *pkey); + +int NETSCAPE_SPKI_print(BIO *out, NETSCAPE_SPKI *spki); + +int X509_signature_print(BIO *bp,X509_ALGOR *alg, ASN1_STRING *sig); + +int X509_sign(X509 *x, EVP_PKEY *pkey, const EVP_MD *md); +int X509_REQ_sign(X509_REQ *x, EVP_PKEY *pkey, const EVP_MD *md); +int X509_CRL_sign(X509_CRL *x, EVP_PKEY *pkey, const EVP_MD *md); +int NETSCAPE_SPKI_sign(NETSCAPE_SPKI *x, EVP_PKEY *pkey, const EVP_MD *md); + +int X509_pubkey_digest(const X509 *data,const EVP_MD *type, + unsigned char *md, unsigned int *len); +int X509_digest(const X509 *data,const EVP_MD *type, + unsigned char *md, unsigned int *len); +int X509_CRL_digest(const X509_CRL *data,const EVP_MD *type, + unsigned char *md, unsigned int *len); +int X509_REQ_digest(const X509_REQ *data,const EVP_MD *type, + unsigned char *md, unsigned int *len); +int X509_NAME_digest(const X509_NAME *data,const EVP_MD *type, + unsigned char *md, unsigned int *len); +#endif + +#ifndef OPENSSL_NO_FP_API +X509 *d2i_X509_fp(FILE *fp, X509 **x509); +int i2d_X509_fp(FILE *fp,X509 *x509); +X509_CRL *d2i_X509_CRL_fp(FILE *fp,X509_CRL **crl); +int i2d_X509_CRL_fp(FILE *fp,X509_CRL *crl); +X509_REQ *d2i_X509_REQ_fp(FILE *fp,X509_REQ **req); +int i2d_X509_REQ_fp(FILE *fp,X509_REQ *req); +#ifndef OPENSSL_NO_RSA +RSA *d2i_RSAPrivateKey_fp(FILE *fp,RSA **rsa); +int i2d_RSAPrivateKey_fp(FILE *fp,RSA *rsa); +RSA *d2i_RSAPublicKey_fp(FILE *fp,RSA **rsa); +int i2d_RSAPublicKey_fp(FILE *fp,RSA *rsa); +RSA *d2i_RSA_PUBKEY_fp(FILE *fp,RSA **rsa); +int i2d_RSA_PUBKEY_fp(FILE *fp,RSA *rsa); +#endif +#ifndef OPENSSL_NO_DSA +DSA *d2i_DSA_PUBKEY_fp(FILE *fp, DSA **dsa); +int i2d_DSA_PUBKEY_fp(FILE *fp, DSA *dsa); +DSA *d2i_DSAPrivateKey_fp(FILE *fp, DSA **dsa); +int i2d_DSAPrivateKey_fp(FILE *fp, DSA *dsa); +#endif +#ifndef OPENSSL_NO_EC +EC_KEY *d2i_EC_PUBKEY_fp(FILE *fp, EC_KEY **eckey); +int i2d_EC_PUBKEY_fp(FILE *fp, EC_KEY *eckey); +EC_KEY *d2i_ECPrivateKey_fp(FILE *fp, EC_KEY **eckey); +int i2d_ECPrivateKey_fp(FILE *fp, EC_KEY *eckey); +#endif +X509_SIG *d2i_PKCS8_fp(FILE *fp,X509_SIG **p8); +int i2d_PKCS8_fp(FILE *fp,X509_SIG *p8); +PKCS8_PRIV_KEY_INFO *d2i_PKCS8_PRIV_KEY_INFO_fp(FILE *fp, + PKCS8_PRIV_KEY_INFO **p8inf); +int i2d_PKCS8_PRIV_KEY_INFO_fp(FILE *fp,PKCS8_PRIV_KEY_INFO *p8inf); +int i2d_PKCS8PrivateKeyInfo_fp(FILE *fp, EVP_PKEY *key); +int i2d_PrivateKey_fp(FILE *fp, EVP_PKEY *pkey); +EVP_PKEY *d2i_PrivateKey_fp(FILE *fp, EVP_PKEY **a); +int i2d_PUBKEY_fp(FILE *fp, EVP_PKEY *pkey); +EVP_PKEY *d2i_PUBKEY_fp(FILE *fp, EVP_PKEY **a); +#endif + +#ifndef OPENSSL_NO_BIO +X509 *d2i_X509_bio(BIO *bp,X509 **x509); +int i2d_X509_bio(BIO *bp,X509 *x509); +X509_CRL *d2i_X509_CRL_bio(BIO *bp,X509_CRL **crl); +int i2d_X509_CRL_bio(BIO *bp,X509_CRL *crl); +X509_REQ *d2i_X509_REQ_bio(BIO *bp,X509_REQ **req); +int i2d_X509_REQ_bio(BIO *bp,X509_REQ *req); +#ifndef OPENSSL_NO_RSA +RSA *d2i_RSAPrivateKey_bio(BIO *bp,RSA **rsa); +int i2d_RSAPrivateKey_bio(BIO *bp,RSA *rsa); +RSA *d2i_RSAPublicKey_bio(BIO *bp,RSA **rsa); +int i2d_RSAPublicKey_bio(BIO *bp,RSA *rsa); +RSA *d2i_RSA_PUBKEY_bio(BIO *bp,RSA **rsa); +int i2d_RSA_PUBKEY_bio(BIO *bp,RSA *rsa); +#endif +#ifndef OPENSSL_NO_DSA +DSA *d2i_DSA_PUBKEY_bio(BIO *bp, DSA **dsa); +int i2d_DSA_PUBKEY_bio(BIO *bp, DSA *dsa); +DSA *d2i_DSAPrivateKey_bio(BIO *bp, DSA **dsa); +int i2d_DSAPrivateKey_bio(BIO *bp, DSA *dsa); +#endif +#ifndef OPENSSL_NO_EC +EC_KEY *d2i_EC_PUBKEY_bio(BIO *bp, EC_KEY **eckey); +int i2d_EC_PUBKEY_bio(BIO *bp, EC_KEY *eckey); +EC_KEY *d2i_ECPrivateKey_bio(BIO *bp, EC_KEY **eckey); +int i2d_ECPrivateKey_bio(BIO *bp, EC_KEY *eckey); +#endif +X509_SIG *d2i_PKCS8_bio(BIO *bp,X509_SIG **p8); +int i2d_PKCS8_bio(BIO *bp,X509_SIG *p8); +PKCS8_PRIV_KEY_INFO *d2i_PKCS8_PRIV_KEY_INFO_bio(BIO *bp, + PKCS8_PRIV_KEY_INFO **p8inf); +int i2d_PKCS8_PRIV_KEY_INFO_bio(BIO *bp,PKCS8_PRIV_KEY_INFO *p8inf); +int i2d_PKCS8PrivateKeyInfo_bio(BIO *bp, EVP_PKEY *key); +int i2d_PrivateKey_bio(BIO *bp, EVP_PKEY *pkey); +EVP_PKEY *d2i_PrivateKey_bio(BIO *bp, EVP_PKEY **a); +int i2d_PUBKEY_bio(BIO *bp, EVP_PKEY *pkey); +EVP_PKEY *d2i_PUBKEY_bio(BIO *bp, EVP_PKEY **a); +#endif + +X509 *X509_dup(X509 *x509); +X509_ATTRIBUTE *X509_ATTRIBUTE_dup(X509_ATTRIBUTE *xa); +X509_EXTENSION *X509_EXTENSION_dup(X509_EXTENSION *ex); +X509_CRL *X509_CRL_dup(X509_CRL *crl); +X509_REQ *X509_REQ_dup(X509_REQ *req); +X509_ALGOR *X509_ALGOR_dup(X509_ALGOR *xn); +int X509_ALGOR_set0(X509_ALGOR *alg, ASN1_OBJECT *aobj, int ptype, void *pval); +void X509_ALGOR_get0(ASN1_OBJECT **paobj, int *pptype, void **ppval, + X509_ALGOR *algor); + +X509_NAME *X509_NAME_dup(X509_NAME *xn); +X509_NAME_ENTRY *X509_NAME_ENTRY_dup(X509_NAME_ENTRY *ne); + +#endif /* !SSLEAY_MACROS */ + +int X509_cmp_time(ASN1_TIME *s, time_t *t); +int X509_cmp_current_time(ASN1_TIME *s); +ASN1_TIME * X509_time_adj(ASN1_TIME *s, long adj, time_t *t); +ASN1_TIME * X509_gmtime_adj(ASN1_TIME *s, long adj); + +const char * X509_get_default_cert_area(void ); +const char * X509_get_default_cert_dir(void ); +const char * X509_get_default_cert_file(void ); +const char * X509_get_default_cert_dir_env(void ); +const char * X509_get_default_cert_file_env(void ); +const char * X509_get_default_private_dir(void ); + +X509_REQ * X509_to_X509_REQ(X509 *x, EVP_PKEY *pkey, const EVP_MD *md); +X509 * X509_REQ_to_X509(X509_REQ *r, int days,EVP_PKEY *pkey); + +DECLARE_ASN1_FUNCTIONS(X509_ALGOR) +DECLARE_ASN1_ENCODE_FUNCTIONS(X509_ALGORS, X509_ALGORS, X509_ALGORS) +DECLARE_ASN1_FUNCTIONS(X509_VAL) + +DECLARE_ASN1_FUNCTIONS(X509_PUBKEY) + +int X509_PUBKEY_set(X509_PUBKEY **x, EVP_PKEY *pkey); +EVP_PKEY * X509_PUBKEY_get(X509_PUBKEY *key); +int X509_get_pubkey_parameters(EVP_PKEY *pkey, + STACK_OF(X509) *chain); +int i2d_PUBKEY(EVP_PKEY *a,unsigned char **pp); +EVP_PKEY * d2i_PUBKEY(EVP_PKEY **a,const unsigned char **pp, + long length); +#ifndef OPENSSL_NO_RSA +int i2d_RSA_PUBKEY(RSA *a,unsigned char **pp); +RSA * d2i_RSA_PUBKEY(RSA **a,const unsigned char **pp, + long length); +#endif +#ifndef OPENSSL_NO_DSA +int i2d_DSA_PUBKEY(DSA *a,unsigned char **pp); +DSA * d2i_DSA_PUBKEY(DSA **a,const unsigned char **pp, + long length); +#endif +#ifndef OPENSSL_NO_EC +int i2d_EC_PUBKEY(EC_KEY *a, unsigned char **pp); +EC_KEY *d2i_EC_PUBKEY(EC_KEY **a, const unsigned char **pp, + long length); +#endif + +DECLARE_ASN1_FUNCTIONS(X509_SIG) +DECLARE_ASN1_FUNCTIONS(X509_REQ_INFO) +DECLARE_ASN1_FUNCTIONS(X509_REQ) + +DECLARE_ASN1_FUNCTIONS(X509_ATTRIBUTE) +X509_ATTRIBUTE *X509_ATTRIBUTE_create(int nid, int atrtype, void *value); + +DECLARE_ASN1_FUNCTIONS(X509_EXTENSION) +DECLARE_ASN1_ENCODE_FUNCTIONS(X509_EXTENSIONS, X509_EXTENSIONS, X509_EXTENSIONS) + +DECLARE_ASN1_FUNCTIONS(X509_NAME_ENTRY) + +DECLARE_ASN1_FUNCTIONS(X509_NAME) + +int X509_NAME_set(X509_NAME **xn, X509_NAME *name); + +DECLARE_ASN1_FUNCTIONS(X509_CINF) + +DECLARE_ASN1_FUNCTIONS(X509) +DECLARE_ASN1_FUNCTIONS(X509_CERT_AUX) + +DECLARE_ASN1_FUNCTIONS(X509_CERT_PAIR) + +int X509_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func, + CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func); +int X509_set_ex_data(X509 *r, int idx, void *arg); +void *X509_get_ex_data(X509 *r, int idx); +int i2d_X509_AUX(X509 *a,unsigned char **pp); +X509 * d2i_X509_AUX(X509 **a,const unsigned char **pp,long length); + +int X509_alias_set1(X509 *x, unsigned char *name, int len); +int X509_keyid_set1(X509 *x, unsigned char *id, int len); +unsigned char * X509_alias_get0(X509 *x, int *len); +unsigned char * X509_keyid_get0(X509 *x, int *len); +int (*X509_TRUST_set_default(int (*trust)(int , X509 *, int)))(int, X509 *, int); +int X509_TRUST_set(int *t, int trust); +int X509_add1_trust_object(X509 *x, ASN1_OBJECT *obj); +int X509_add1_reject_object(X509 *x, ASN1_OBJECT *obj); +void X509_trust_clear(X509 *x); +void X509_reject_clear(X509 *x); + +DECLARE_ASN1_FUNCTIONS(X509_REVOKED) +DECLARE_ASN1_FUNCTIONS(X509_CRL_INFO) +DECLARE_ASN1_FUNCTIONS(X509_CRL) + +int X509_CRL_add0_revoked(X509_CRL *crl, X509_REVOKED *rev); + +X509_PKEY * X509_PKEY_new(void ); +void X509_PKEY_free(X509_PKEY *a); +int i2d_X509_PKEY(X509_PKEY *a,unsigned char **pp); +X509_PKEY * d2i_X509_PKEY(X509_PKEY **a,const unsigned char **pp,long length); + +DECLARE_ASN1_FUNCTIONS(NETSCAPE_SPKI) +DECLARE_ASN1_FUNCTIONS(NETSCAPE_SPKAC) +DECLARE_ASN1_FUNCTIONS(NETSCAPE_CERT_SEQUENCE) + +#ifndef OPENSSL_NO_EVP +X509_INFO * X509_INFO_new(void); +void X509_INFO_free(X509_INFO *a); +char * X509_NAME_oneline(X509_NAME *a,char *buf,int size); + +int ASN1_verify(i2d_of_void *i2d, X509_ALGOR *algor1, + ASN1_BIT_STRING *signature,char *data,EVP_PKEY *pkey); + +int ASN1_digest(i2d_of_void *i2d,const EVP_MD *type,char *data, + unsigned char *md,unsigned int *len); + +int ASN1_sign(i2d_of_void *i2d, X509_ALGOR *algor1, + X509_ALGOR *algor2, ASN1_BIT_STRING *signature, + char *data,EVP_PKEY *pkey, const EVP_MD *type); + +int ASN1_item_digest(const ASN1_ITEM *it,const EVP_MD *type,void *data, + unsigned char *md,unsigned int *len); + +int ASN1_item_verify(const ASN1_ITEM *it, X509_ALGOR *algor1, + ASN1_BIT_STRING *signature,void *data,EVP_PKEY *pkey); + +int ASN1_item_sign(const ASN1_ITEM *it, X509_ALGOR *algor1, X509_ALGOR *algor2, + ASN1_BIT_STRING *signature, + void *data, EVP_PKEY *pkey, const EVP_MD *type); +#endif + +int X509_set_version(X509 *x,long version); +int X509_set_serialNumber(X509 *x, ASN1_INTEGER *serial); +ASN1_INTEGER * X509_get_serialNumber(X509 *x); +int X509_set_issuer_name(X509 *x, X509_NAME *name); +X509_NAME * X509_get_issuer_name(X509 *a); +int X509_set_subject_name(X509 *x, X509_NAME *name); +X509_NAME * X509_get_subject_name(X509 *a); +int X509_set_notBefore(X509 *x, ASN1_TIME *tm); +int X509_set_notAfter(X509 *x, ASN1_TIME *tm); +int X509_set_pubkey(X509 *x, EVP_PKEY *pkey); +EVP_PKEY * X509_get_pubkey(X509 *x); +ASN1_BIT_STRING * X509_get0_pubkey_bitstr(const X509 *x); +int X509_certificate_type(X509 *x,EVP_PKEY *pubkey /* optional */); + +int X509_REQ_set_version(X509_REQ *x,long version); +int X509_REQ_set_subject_name(X509_REQ *req,X509_NAME *name); +int X509_REQ_set_pubkey(X509_REQ *x, EVP_PKEY *pkey); +EVP_PKEY * X509_REQ_get_pubkey(X509_REQ *req); +int X509_REQ_extension_nid(int nid); +int * X509_REQ_get_extension_nids(void); +void X509_REQ_set_extension_nids(int *nids); +STACK_OF(X509_EXTENSION) *X509_REQ_get_extensions(X509_REQ *req); +int X509_REQ_add_extensions_nid(X509_REQ *req, STACK_OF(X509_EXTENSION) *exts, + int nid); +int X509_REQ_add_extensions(X509_REQ *req, STACK_OF(X509_EXTENSION) *exts); +int X509_REQ_get_attr_count(const X509_REQ *req); +int X509_REQ_get_attr_by_NID(const X509_REQ *req, int nid, + int lastpos); +int X509_REQ_get_attr_by_OBJ(const X509_REQ *req, ASN1_OBJECT *obj, + int lastpos); +X509_ATTRIBUTE *X509_REQ_get_attr(const X509_REQ *req, int loc); +X509_ATTRIBUTE *X509_REQ_delete_attr(X509_REQ *req, int loc); +int X509_REQ_add1_attr(X509_REQ *req, X509_ATTRIBUTE *attr); +int X509_REQ_add1_attr_by_OBJ(X509_REQ *req, + const ASN1_OBJECT *obj, int type, + const unsigned char *bytes, int len); +int X509_REQ_add1_attr_by_NID(X509_REQ *req, + int nid, int type, + const unsigned char *bytes, int len); +int X509_REQ_add1_attr_by_txt(X509_REQ *req, + const char *attrname, int type, + const unsigned char *bytes, int len); + +int X509_CRL_set_version(X509_CRL *x, long version); +int X509_CRL_set_issuer_name(X509_CRL *x, X509_NAME *name); +int X509_CRL_set_lastUpdate(X509_CRL *x, ASN1_TIME *tm); +int X509_CRL_set_nextUpdate(X509_CRL *x, ASN1_TIME *tm); +int X509_CRL_sort(X509_CRL *crl); + +int X509_REVOKED_set_serialNumber(X509_REVOKED *x, ASN1_INTEGER *serial); +int X509_REVOKED_set_revocationDate(X509_REVOKED *r, ASN1_TIME *tm); + +int X509_REQ_check_private_key(X509_REQ *x509,EVP_PKEY *pkey); + +int X509_check_private_key(X509 *x509,EVP_PKEY *pkey); + +int X509_issuer_and_serial_cmp(const X509 *a, const X509 *b); +unsigned long X509_issuer_and_serial_hash(X509 *a); + +int X509_issuer_name_cmp(const X509 *a, const X509 *b); +unsigned long X509_issuer_name_hash(X509 *a); + +int X509_subject_name_cmp(const X509 *a, const X509 *b); +unsigned long X509_subject_name_hash(X509 *x); + +int X509_cmp(const X509 *a, const X509 *b); +int X509_NAME_cmp(const X509_NAME *a, const X509_NAME *b); +unsigned long X509_NAME_hash(X509_NAME *x); + +int X509_CRL_cmp(const X509_CRL *a, const X509_CRL *b); +#ifndef OPENSSL_NO_FP_API +int X509_print_ex_fp(FILE *bp,X509 *x, unsigned long nmflag, unsigned long cflag); +int X509_print_fp(FILE *bp,X509 *x); +int X509_CRL_print_fp(FILE *bp,X509_CRL *x); +int X509_REQ_print_fp(FILE *bp,X509_REQ *req); +int X509_NAME_print_ex_fp(FILE *fp, X509_NAME *nm, int indent, unsigned long flags); +#endif + +#ifndef OPENSSL_NO_BIO +int X509_NAME_print(BIO *bp, X509_NAME *name, int obase); +int X509_NAME_print_ex(BIO *out, X509_NAME *nm, int indent, unsigned long flags); +int X509_print_ex(BIO *bp,X509 *x, unsigned long nmflag, unsigned long cflag); +int X509_print(BIO *bp,X509 *x); +int X509_ocspid_print(BIO *bp,X509 *x); +int X509_CERT_AUX_print(BIO *bp,X509_CERT_AUX *x, int indent); +int X509_CRL_print(BIO *bp,X509_CRL *x); +int X509_REQ_print_ex(BIO *bp, X509_REQ *x, unsigned long nmflag, unsigned long cflag); +int X509_REQ_print(BIO *bp,X509_REQ *req); +#endif + +int X509_NAME_entry_count(X509_NAME *name); +int X509_NAME_get_text_by_NID(X509_NAME *name, int nid, + char *buf,int len); +int X509_NAME_get_text_by_OBJ(X509_NAME *name, ASN1_OBJECT *obj, + char *buf,int len); + +/* NOTE: you should be passsing -1, not 0 as lastpos. The functions that use + * lastpos, search after that position on. */ +int X509_NAME_get_index_by_NID(X509_NAME *name,int nid,int lastpos); +int X509_NAME_get_index_by_OBJ(X509_NAME *name,ASN1_OBJECT *obj, + int lastpos); +X509_NAME_ENTRY *X509_NAME_get_entry(X509_NAME *name, int loc); +X509_NAME_ENTRY *X509_NAME_delete_entry(X509_NAME *name, int loc); +int X509_NAME_add_entry(X509_NAME *name,X509_NAME_ENTRY *ne, + int loc, int set); +int X509_NAME_add_entry_by_OBJ(X509_NAME *name, ASN1_OBJECT *obj, int type, + unsigned char *bytes, int len, int loc, int set); +int X509_NAME_add_entry_by_NID(X509_NAME *name, int nid, int type, + unsigned char *bytes, int len, int loc, int set); +X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_txt(X509_NAME_ENTRY **ne, + const char *field, int type, const unsigned char *bytes, int len); +X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_NID(X509_NAME_ENTRY **ne, int nid, + int type,unsigned char *bytes, int len); +int X509_NAME_add_entry_by_txt(X509_NAME *name, const char *field, int type, + const unsigned char *bytes, int len, int loc, int set); +X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_OBJ(X509_NAME_ENTRY **ne, + ASN1_OBJECT *obj, int type,const unsigned char *bytes, + int len); +int X509_NAME_ENTRY_set_object(X509_NAME_ENTRY *ne, + ASN1_OBJECT *obj); +int X509_NAME_ENTRY_set_data(X509_NAME_ENTRY *ne, int type, + const unsigned char *bytes, int len); +ASN1_OBJECT * X509_NAME_ENTRY_get_object(X509_NAME_ENTRY *ne); +ASN1_STRING * X509_NAME_ENTRY_get_data(X509_NAME_ENTRY *ne); + +int X509v3_get_ext_count(const STACK_OF(X509_EXTENSION) *x); +int X509v3_get_ext_by_NID(const STACK_OF(X509_EXTENSION) *x, + int nid, int lastpos); +int X509v3_get_ext_by_OBJ(const STACK_OF(X509_EXTENSION) *x, + ASN1_OBJECT *obj,int lastpos); +int X509v3_get_ext_by_critical(const STACK_OF(X509_EXTENSION) *x, + int crit, int lastpos); +X509_EXTENSION *X509v3_get_ext(const STACK_OF(X509_EXTENSION) *x, int loc); +X509_EXTENSION *X509v3_delete_ext(STACK_OF(X509_EXTENSION) *x, int loc); +STACK_OF(X509_EXTENSION) *X509v3_add_ext(STACK_OF(X509_EXTENSION) **x, + X509_EXTENSION *ex, int loc); + +int X509_get_ext_count(X509 *x); +int X509_get_ext_by_NID(X509 *x, int nid, int lastpos); +int X509_get_ext_by_OBJ(X509 *x,ASN1_OBJECT *obj,int lastpos); +int X509_get_ext_by_critical(X509 *x, int crit, int lastpos); +X509_EXTENSION *X509_get_ext(X509 *x, int loc); +X509_EXTENSION *X509_delete_ext(X509 *x, int loc); +int X509_add_ext(X509 *x, X509_EXTENSION *ex, int loc); +void * X509_get_ext_d2i(X509 *x, int nid, int *crit, int *idx); +int X509_add1_ext_i2d(X509 *x, int nid, void *value, int crit, + unsigned long flags); + +int X509_CRL_get_ext_count(X509_CRL *x); +int X509_CRL_get_ext_by_NID(X509_CRL *x, int nid, int lastpos); +int X509_CRL_get_ext_by_OBJ(X509_CRL *x,ASN1_OBJECT *obj,int lastpos); +int X509_CRL_get_ext_by_critical(X509_CRL *x, int crit, int lastpos); +X509_EXTENSION *X509_CRL_get_ext(X509_CRL *x, int loc); +X509_EXTENSION *X509_CRL_delete_ext(X509_CRL *x, int loc); +int X509_CRL_add_ext(X509_CRL *x, X509_EXTENSION *ex, int loc); +void * X509_CRL_get_ext_d2i(X509_CRL *x, int nid, int *crit, int *idx); +int X509_CRL_add1_ext_i2d(X509_CRL *x, int nid, void *value, int crit, + unsigned long flags); + +int X509_REVOKED_get_ext_count(X509_REVOKED *x); +int X509_REVOKED_get_ext_by_NID(X509_REVOKED *x, int nid, int lastpos); +int X509_REVOKED_get_ext_by_OBJ(X509_REVOKED *x,ASN1_OBJECT *obj,int lastpos); +int X509_REVOKED_get_ext_by_critical(X509_REVOKED *x, int crit, int lastpos); +X509_EXTENSION *X509_REVOKED_get_ext(X509_REVOKED *x, int loc); +X509_EXTENSION *X509_REVOKED_delete_ext(X509_REVOKED *x, int loc); +int X509_REVOKED_add_ext(X509_REVOKED *x, X509_EXTENSION *ex, int loc); +void * X509_REVOKED_get_ext_d2i(X509_REVOKED *x, int nid, int *crit, int *idx); +int X509_REVOKED_add1_ext_i2d(X509_REVOKED *x, int nid, void *value, int crit, + unsigned long flags); + +X509_EXTENSION *X509_EXTENSION_create_by_NID(X509_EXTENSION **ex, + int nid, int crit, ASN1_OCTET_STRING *data); +X509_EXTENSION *X509_EXTENSION_create_by_OBJ(X509_EXTENSION **ex, + ASN1_OBJECT *obj,int crit,ASN1_OCTET_STRING *data); +int X509_EXTENSION_set_object(X509_EXTENSION *ex,ASN1_OBJECT *obj); +int X509_EXTENSION_set_critical(X509_EXTENSION *ex, int crit); +int X509_EXTENSION_set_data(X509_EXTENSION *ex, + ASN1_OCTET_STRING *data); +ASN1_OBJECT * X509_EXTENSION_get_object(X509_EXTENSION *ex); +ASN1_OCTET_STRING *X509_EXTENSION_get_data(X509_EXTENSION *ne); +int X509_EXTENSION_get_critical(X509_EXTENSION *ex); + +int X509at_get_attr_count(const STACK_OF(X509_ATTRIBUTE) *x); +int X509at_get_attr_by_NID(const STACK_OF(X509_ATTRIBUTE) *x, int nid, + int lastpos); +int X509at_get_attr_by_OBJ(const STACK_OF(X509_ATTRIBUTE) *sk, ASN1_OBJECT *obj, + int lastpos); +X509_ATTRIBUTE *X509at_get_attr(const STACK_OF(X509_ATTRIBUTE) *x, int loc); +X509_ATTRIBUTE *X509at_delete_attr(STACK_OF(X509_ATTRIBUTE) *x, int loc); +STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr(STACK_OF(X509_ATTRIBUTE) **x, + X509_ATTRIBUTE *attr); +STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr_by_OBJ(STACK_OF(X509_ATTRIBUTE) **x, + const ASN1_OBJECT *obj, int type, + const unsigned char *bytes, int len); +STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr_by_NID(STACK_OF(X509_ATTRIBUTE) **x, + int nid, int type, + const unsigned char *bytes, int len); +STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr_by_txt(STACK_OF(X509_ATTRIBUTE) **x, + const char *attrname, int type, + const unsigned char *bytes, int len); +void *X509at_get0_data_by_OBJ(STACK_OF(X509_ATTRIBUTE) *x, + ASN1_OBJECT *obj, int lastpos, int type); +X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_NID(X509_ATTRIBUTE **attr, int nid, + int atrtype, const void *data, int len); +X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_OBJ(X509_ATTRIBUTE **attr, + const ASN1_OBJECT *obj, int atrtype, const void *data, int len); +X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_txt(X509_ATTRIBUTE **attr, + const char *atrname, int type, const unsigned char *bytes, int len); +int X509_ATTRIBUTE_set1_object(X509_ATTRIBUTE *attr, const ASN1_OBJECT *obj); +int X509_ATTRIBUTE_set1_data(X509_ATTRIBUTE *attr, int attrtype, const void *data, int len); +void *X509_ATTRIBUTE_get0_data(X509_ATTRIBUTE *attr, int idx, + int atrtype, void *data); +int X509_ATTRIBUTE_count(X509_ATTRIBUTE *attr); +ASN1_OBJECT *X509_ATTRIBUTE_get0_object(X509_ATTRIBUTE *attr); +ASN1_TYPE *X509_ATTRIBUTE_get0_type(X509_ATTRIBUTE *attr, int idx); + +int EVP_PKEY_get_attr_count(const EVP_PKEY *key); +int EVP_PKEY_get_attr_by_NID(const EVP_PKEY *key, int nid, + int lastpos); +int EVP_PKEY_get_attr_by_OBJ(const EVP_PKEY *key, ASN1_OBJECT *obj, + int lastpos); +X509_ATTRIBUTE *EVP_PKEY_get_attr(const EVP_PKEY *key, int loc); +X509_ATTRIBUTE *EVP_PKEY_delete_attr(EVP_PKEY *key, int loc); +int EVP_PKEY_add1_attr(EVP_PKEY *key, X509_ATTRIBUTE *attr); +int EVP_PKEY_add1_attr_by_OBJ(EVP_PKEY *key, + const ASN1_OBJECT *obj, int type, + const unsigned char *bytes, int len); +int EVP_PKEY_add1_attr_by_NID(EVP_PKEY *key, + int nid, int type, + const unsigned char *bytes, int len); +int EVP_PKEY_add1_attr_by_txt(EVP_PKEY *key, + const char *attrname, int type, + const unsigned char *bytes, int len); + +int X509_verify_cert(X509_STORE_CTX *ctx); + +/* lookup a cert from a X509 STACK */ +X509 *X509_find_by_issuer_and_serial(STACK_OF(X509) *sk,X509_NAME *name, + ASN1_INTEGER *serial); +X509 *X509_find_by_subject(STACK_OF(X509) *sk,X509_NAME *name); + +DECLARE_ASN1_FUNCTIONS(PBEPARAM) +DECLARE_ASN1_FUNCTIONS(PBE2PARAM) +DECLARE_ASN1_FUNCTIONS(PBKDF2PARAM) + +X509_ALGOR *PKCS5_pbe_set(int alg, int iter, unsigned char *salt, int saltlen); +X509_ALGOR *PKCS5_pbe2_set(const EVP_CIPHER *cipher, int iter, + unsigned char *salt, int saltlen); + +/* PKCS#8 utilities */ + +DECLARE_ASN1_FUNCTIONS(PKCS8_PRIV_KEY_INFO) + +EVP_PKEY *EVP_PKCS82PKEY(PKCS8_PRIV_KEY_INFO *p8); +PKCS8_PRIV_KEY_INFO *EVP_PKEY2PKCS8(EVP_PKEY *pkey); +PKCS8_PRIV_KEY_INFO *EVP_PKEY2PKCS8_broken(EVP_PKEY *pkey, int broken); +PKCS8_PRIV_KEY_INFO *PKCS8_set_broken(PKCS8_PRIV_KEY_INFO *p8, int broken); + +int X509_check_trust(X509 *x, int id, int flags); +int X509_TRUST_get_count(void); +X509_TRUST * X509_TRUST_get0(int idx); +int X509_TRUST_get_by_id(int id); +int X509_TRUST_add(int id, int flags, int (*ck)(X509_TRUST *, X509 *, int), + char *name, int arg1, void *arg2); +void X509_TRUST_cleanup(void); +int X509_TRUST_get_flags(X509_TRUST *xp); +char *X509_TRUST_get0_name(X509_TRUST *xp); +int X509_TRUST_get_trust(X509_TRUST *xp); + +/* BEGIN ERROR CODES */ +/* The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ +void ERR_load_X509_strings(void); + +/* Error codes for the X509 functions. */ + +/* Function codes. */ +#define X509_F_ADD_CERT_DIR 100 +#define X509_F_BY_FILE_CTRL 101 +#define X509_F_CHECK_POLICY 145 +#define X509_F_DIR_CTRL 102 +#define X509_F_GET_CERT_BY_SUBJECT 103 +#define X509_F_NETSCAPE_SPKI_B64_DECODE 129 +#define X509_F_NETSCAPE_SPKI_B64_ENCODE 130 +#define X509_F_X509AT_ADD1_ATTR 135 +#define X509_F_X509V3_ADD_EXT 104 +#define X509_F_X509_ATTRIBUTE_CREATE_BY_NID 136 +#define X509_F_X509_ATTRIBUTE_CREATE_BY_OBJ 137 +#define X509_F_X509_ATTRIBUTE_CREATE_BY_TXT 140 +#define X509_F_X509_ATTRIBUTE_GET0_DATA 139 +#define X509_F_X509_ATTRIBUTE_SET1_DATA 138 +#define X509_F_X509_CHECK_PRIVATE_KEY 128 +#define X509_F_X509_CRL_PRINT_FP 147 +#define X509_F_X509_EXTENSION_CREATE_BY_NID 108 +#define X509_F_X509_EXTENSION_CREATE_BY_OBJ 109 +#define X509_F_X509_GET_PUBKEY_PARAMETERS 110 +#define X509_F_X509_LOAD_CERT_CRL_FILE 132 +#define X509_F_X509_LOAD_CERT_FILE 111 +#define X509_F_X509_LOAD_CRL_FILE 112 +#define X509_F_X509_NAME_ADD_ENTRY 113 +#define X509_F_X509_NAME_ENTRY_CREATE_BY_NID 114 +#define X509_F_X509_NAME_ENTRY_CREATE_BY_TXT 131 +#define X509_F_X509_NAME_ENTRY_SET_OBJECT 115 +#define X509_F_X509_NAME_ONELINE 116 +#define X509_F_X509_NAME_PRINT 117 +#define X509_F_X509_PRINT_EX_FP 118 +#define X509_F_X509_PUBKEY_GET 119 +#define X509_F_X509_PUBKEY_SET 120 +#define X509_F_X509_REQ_CHECK_PRIVATE_KEY 144 +#define X509_F_X509_REQ_PRINT_EX 121 +#define X509_F_X509_REQ_PRINT_FP 122 +#define X509_F_X509_REQ_TO_X509 123 +#define X509_F_X509_STORE_ADD_CERT 124 +#define X509_F_X509_STORE_ADD_CRL 125 +#define X509_F_X509_STORE_CTX_GET1_ISSUER 146 +#define X509_F_X509_STORE_CTX_INIT 143 +#define X509_F_X509_STORE_CTX_NEW 142 +#define X509_F_X509_STORE_CTX_PURPOSE_INHERIT 134 +#define X509_F_X509_TO_X509_REQ 126 +#define X509_F_X509_TRUST_ADD 133 +#define X509_F_X509_TRUST_SET 141 +#define X509_F_X509_VERIFY_CERT 127 + +/* Reason codes. */ +#define X509_R_BAD_X509_FILETYPE 100 +#define X509_R_BASE64_DECODE_ERROR 118 +#define X509_R_CANT_CHECK_DH_KEY 114 +#define X509_R_CERT_ALREADY_IN_HASH_TABLE 101 +#define X509_R_ERR_ASN1_LIB 102 +#define X509_R_INVALID_DIRECTORY 113 +#define X509_R_INVALID_FIELD_NAME 119 +#define X509_R_INVALID_TRUST 123 +#define X509_R_KEY_TYPE_MISMATCH 115 +#define X509_R_KEY_VALUES_MISMATCH 116 +#define X509_R_LOADING_CERT_DIR 103 +#define X509_R_LOADING_DEFAULTS 104 +#define X509_R_NO_CERT_SET_FOR_US_TO_VERIFY 105 +#define X509_R_SHOULD_RETRY 106 +#define X509_R_UNABLE_TO_FIND_PARAMETERS_IN_CHAIN 107 +#define X509_R_UNABLE_TO_GET_CERTS_PUBLIC_KEY 108 +#define X509_R_UNKNOWN_KEY_TYPE 117 +#define X509_R_UNKNOWN_NID 109 +#define X509_R_UNKNOWN_PURPOSE_ID 121 +#define X509_R_UNKNOWN_TRUST_ID 120 +#define X509_R_UNSUPPORTED_ALGORITHM 111 +#define X509_R_WRONG_LOOKUP_TYPE 112 +#define X509_R_WRONG_TYPE 122 + +#ifdef __cplusplus +} +#endif +#endif diff --git a/lib_tls/include/openssl/x509_vfy.h b/lib_tls/include/openssl/x509_vfy.h new file mode 100644 index 000000000..76c76e171 --- /dev/null +++ b/lib_tls/include/openssl/x509_vfy.h @@ -0,0 +1,531 @@ +/* crypto/x509/x509_vfy.h */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#ifndef HEADER_X509_H +#include +/* openssl/x509.h ends up #include-ing this file at about the only + * appropriate moment. */ +#endif + +#ifndef HEADER_X509_VFY_H +#define HEADER_X509_VFY_H + +#include +#ifndef OPENSSL_NO_LHASH +#include +#endif +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Outer object */ +typedef struct x509_hash_dir_st + { + int num_dirs; + char **dirs; + int *dirs_type; + int num_dirs_alloced; + } X509_HASH_DIR_CTX; + +typedef struct x509_file_st + { + int num_paths; /* number of paths to files or directories */ + int num_alloced; + char **paths; /* the list of paths or directories */ + int *path_type; + } X509_CERT_FILE_CTX; + +/*******************************/ +/* +SSL_CTX -> X509_STORE + -> X509_LOOKUP + ->X509_LOOKUP_METHOD + -> X509_LOOKUP + ->X509_LOOKUP_METHOD + +SSL -> X509_STORE_CTX + ->X509_STORE + +The X509_STORE holds the tables etc for verification stuff. +A X509_STORE_CTX is used while validating a single certificate. +The X509_STORE has X509_LOOKUPs for looking up certs. +The X509_STORE then calls a function to actually verify the +certificate chain. +*/ + +#define X509_LU_RETRY -1 +#define X509_LU_FAIL 0 +#define X509_LU_X509 1 +#define X509_LU_CRL 2 +#define X509_LU_PKEY 3 + +typedef struct x509_object_st + { + /* one of the above types */ + int type; + union { + char *ptr; + X509 *x509; + X509_CRL *crl; + EVP_PKEY *pkey; + } data; + } X509_OBJECT; + +typedef struct x509_lookup_st X509_LOOKUP; + +DECLARE_STACK_OF(X509_LOOKUP) +DECLARE_STACK_OF(X509_OBJECT) + +/* This is a static that defines the function interface */ +typedef struct x509_lookup_method_st + { + const char *name; + int (*new_item)(X509_LOOKUP *ctx); + void (*free)(X509_LOOKUP *ctx); + int (*init)(X509_LOOKUP *ctx); + int (*shutdown)(X509_LOOKUP *ctx); + int (*ctrl)(X509_LOOKUP *ctx,int cmd,const char *argc,long argl, + char **ret); + int (*get_by_subject)(X509_LOOKUP *ctx,int type,X509_NAME *name, + X509_OBJECT *ret); + int (*get_by_issuer_serial)(X509_LOOKUP *ctx,int type,X509_NAME *name, + ASN1_INTEGER *serial,X509_OBJECT *ret); + int (*get_by_fingerprint)(X509_LOOKUP *ctx,int type, + unsigned char *bytes,int len, + X509_OBJECT *ret); + int (*get_by_alias)(X509_LOOKUP *ctx,int type,char *str,int len, + X509_OBJECT *ret); + } X509_LOOKUP_METHOD; + +/* This structure hold all parameters associated with a verify operation + * by including an X509_VERIFY_PARAM structure in related structures the + * parameters used can be customized + */ + +typedef struct X509_VERIFY_PARAM_st + { + char *name; + time_t check_time; /* Time to use */ + unsigned long inh_flags; /* Inheritance flags */ + unsigned long flags; /* Various verify flags */ + int purpose; /* purpose to check untrusted certificates */ + int trust; /* trust setting to check */ + int depth; /* Verify depth */ + STACK_OF(ASN1_OBJECT) *policies; /* Permissible policies */ + } X509_VERIFY_PARAM; + +DECLARE_STACK_OF(X509_VERIFY_PARAM) + +/* This is used to hold everything. It is used for all certificate + * validation. Once we have a certificate chain, the 'verify' + * function is then called to actually check the cert chain. */ +struct x509_store_st + { + /* The following is a cache of trusted certs */ + int cache; /* if true, stash any hits */ + STACK_OF(X509_OBJECT) *objs; /* Cache of all objects */ + + /* These are external lookup methods */ + STACK_OF(X509_LOOKUP) *get_cert_methods; + + X509_VERIFY_PARAM *param; + + /* Callbacks for various operations */ + int (*verify)(X509_STORE_CTX *ctx); /* called to verify a certificate */ + int (*verify_cb)(int ok,X509_STORE_CTX *ctx); /* error callback */ + int (*get_issuer)(X509 **issuer, X509_STORE_CTX *ctx, X509 *x); /* get issuers cert from ctx */ + int (*check_issued)(X509_STORE_CTX *ctx, X509 *x, X509 *issuer); /* check issued */ + int (*check_revocation)(X509_STORE_CTX *ctx); /* Check revocation status of chain */ + int (*get_crl)(X509_STORE_CTX *ctx, X509_CRL **crl, X509 *x); /* retrieve CRL */ + int (*check_crl)(X509_STORE_CTX *ctx, X509_CRL *crl); /* Check CRL validity */ + int (*cert_crl)(X509_STORE_CTX *ctx, X509_CRL *crl, X509 *x); /* Check certificate against CRL */ + int (*cleanup)(X509_STORE_CTX *ctx); + + CRYPTO_EX_DATA ex_data; + int references; + } /* X509_STORE */; + +int X509_STORE_set_depth(X509_STORE *store, int depth); + +#define X509_STORE_set_verify_cb_func(ctx,func) ((ctx)->verify_cb=(func)) +#define X509_STORE_set_verify_func(ctx,func) ((ctx)->verify=(func)) + +/* This is the functions plus an instance of the local variables. */ +struct x509_lookup_st + { + int init; /* have we been started */ + int skip; /* don't use us. */ + X509_LOOKUP_METHOD *method; /* the functions */ + char *method_data; /* method data */ + + X509_STORE *store_ctx; /* who owns us */ + } /* X509_LOOKUP */; + +/* This is a used when verifying cert chains. Since the + * gathering of the cert chain can take some time (and have to be + * 'retried', this needs to be kept and passed around. */ +struct x509_store_ctx_st /* X509_STORE_CTX */ + { + X509_STORE *ctx; + int current_method; /* used when looking up certs */ + + /* The following are set by the caller */ + X509 *cert; /* The cert to check */ + STACK_OF(X509) *untrusted; /* chain of X509s - untrusted - passed in */ + STACK_OF(X509_CRL) *crls; /* set of CRLs passed in */ + + X509_VERIFY_PARAM *param; + void *other_ctx; /* Other info for use with get_issuer() */ + + /* Callbacks for various operations */ + int (*verify)(X509_STORE_CTX *ctx); /* called to verify a certificate */ + int (*verify_cb)(int ok,X509_STORE_CTX *ctx); /* error callback */ + int (*get_issuer)(X509 **issuer, X509_STORE_CTX *ctx, X509 *x); /* get issuers cert from ctx */ + int (*check_issued)(X509_STORE_CTX *ctx, X509 *x, X509 *issuer); /* check issued */ + int (*check_revocation)(X509_STORE_CTX *ctx); /* Check revocation status of chain */ + int (*get_crl)(X509_STORE_CTX *ctx, X509_CRL **crl, X509 *x); /* retrieve CRL */ + int (*check_crl)(X509_STORE_CTX *ctx, X509_CRL *crl); /* Check CRL validity */ + int (*cert_crl)(X509_STORE_CTX *ctx, X509_CRL *crl, X509 *x); /* Check certificate against CRL */ + int (*check_policy)(X509_STORE_CTX *ctx); + int (*cleanup)(X509_STORE_CTX *ctx); + + /* The following is built up */ + int valid; /* if 0, rebuild chain */ + int last_untrusted; /* index of last untrusted cert */ + STACK_OF(X509) *chain; /* chain of X509s - built up and trusted */ + X509_POLICY_TREE *tree; /* Valid policy tree */ + + int explicit_policy; /* Require explicit policy value */ + + /* When something goes wrong, this is why */ + int error_depth; + int error; + X509 *current_cert; + X509 *current_issuer; /* cert currently being tested as valid issuer */ + X509_CRL *current_crl; /* current CRL */ + + CRYPTO_EX_DATA ex_data; + } /* X509_STORE_CTX */; + +void X509_STORE_CTX_set_depth(X509_STORE_CTX *ctx, int depth); + +#define X509_STORE_CTX_set_app_data(ctx,data) \ + X509_STORE_CTX_set_ex_data(ctx,0,data) +#define X509_STORE_CTX_get_app_data(ctx) \ + X509_STORE_CTX_get_ex_data(ctx,0) + +#define X509_L_FILE_LOAD 1 +#define X509_L_ADD_DIR 2 + +#define X509_LOOKUP_load_file(x,name,type) \ + X509_LOOKUP_ctrl((x),X509_L_FILE_LOAD,(name),(long)(type),NULL) + +#define X509_LOOKUP_add_dir(x,name,type) \ + X509_LOOKUP_ctrl((x),X509_L_ADD_DIR,(name),(long)(type),NULL) + +#define X509_V_OK 0 +/* illegal error (for uninitialized values, to avoid X509_V_OK): 1 */ + +#define X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT 2 +#define X509_V_ERR_UNABLE_TO_GET_CRL 3 +#define X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE 4 +#define X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE 5 +#define X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY 6 +#define X509_V_ERR_CERT_SIGNATURE_FAILURE 7 +#define X509_V_ERR_CRL_SIGNATURE_FAILURE 8 +#define X509_V_ERR_CERT_NOT_YET_VALID 9 +#define X509_V_ERR_CERT_HAS_EXPIRED 10 +#define X509_V_ERR_CRL_NOT_YET_VALID 11 +#define X509_V_ERR_CRL_HAS_EXPIRED 12 +#define X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD 13 +#define X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD 14 +#define X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD 15 +#define X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD 16 +#define X509_V_ERR_OUT_OF_MEM 17 +#define X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT 18 +#define X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN 19 +#define X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY 20 +#define X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE 21 +#define X509_V_ERR_CERT_CHAIN_TOO_LONG 22 +#define X509_V_ERR_CERT_REVOKED 23 +#define X509_V_ERR_INVALID_CA 24 +#define X509_V_ERR_PATH_LENGTH_EXCEEDED 25 +#define X509_V_ERR_INVALID_PURPOSE 26 +#define X509_V_ERR_CERT_UNTRUSTED 27 +#define X509_V_ERR_CERT_REJECTED 28 +/* These are 'informational' when looking for issuer cert */ +#define X509_V_ERR_SUBJECT_ISSUER_MISMATCH 29 +#define X509_V_ERR_AKID_SKID_MISMATCH 30 +#define X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH 31 +#define X509_V_ERR_KEYUSAGE_NO_CERTSIGN 32 + +#define X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER 33 +#define X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION 34 +#define X509_V_ERR_KEYUSAGE_NO_CRL_SIGN 35 +#define X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION 36 +#define X509_V_ERR_INVALID_NON_CA 37 +#define X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED 38 +#define X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE 39 +#define X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED 40 + +#define X509_V_ERR_INVALID_EXTENSION 41 +#define X509_V_ERR_INVALID_POLICY_EXTENSION 42 +#define X509_V_ERR_NO_EXPLICIT_POLICY 43 + +#define X509_V_ERR_UNNESTED_RESOURCE 44 + +/* The application is not happy */ +#define X509_V_ERR_APPLICATION_VERIFICATION 50 + +/* Certificate verify flags */ + +/* Send issuer+subject checks to verify_cb */ +#define X509_V_FLAG_CB_ISSUER_CHECK 0x1 +/* Use check time instead of current time */ +#define X509_V_FLAG_USE_CHECK_TIME 0x2 +/* Lookup CRLs */ +#define X509_V_FLAG_CRL_CHECK 0x4 +/* Lookup CRLs for whole chain */ +#define X509_V_FLAG_CRL_CHECK_ALL 0x8 +/* Ignore unhandled critical extensions */ +#define X509_V_FLAG_IGNORE_CRITICAL 0x10 +/* Disable workarounds for broken certificates */ +#define X509_V_FLAG_X509_STRICT 0x20 +/* Enable proxy certificate validation */ +#define X509_V_FLAG_ALLOW_PROXY_CERTS 0x40 +/* Enable policy checking */ +#define X509_V_FLAG_POLICY_CHECK 0x80 +/* Policy variable require-explicit-policy */ +#define X509_V_FLAG_EXPLICIT_POLICY 0x100 +/* Policy variable inhibit-any-policy */ +#define X509_V_FLAG_INHIBIT_ANY 0x200 +/* Policy variable inhibit-policy-mapping */ +#define X509_V_FLAG_INHIBIT_MAP 0x400 +/* Notify callback that policy is OK */ +#define X509_V_FLAG_NOTIFY_POLICY 0x800 + +#define X509_VP_FLAG_DEFAULT 0x1 +#define X509_VP_FLAG_OVERWRITE 0x2 +#define X509_VP_FLAG_RESET_FLAGS 0x4 +#define X509_VP_FLAG_LOCKED 0x8 +#define X509_VP_FLAG_ONCE 0x10 + +/* Internal use: mask of policy related options */ +#define X509_V_FLAG_POLICY_MASK (X509_V_FLAG_POLICY_CHECK \ + | X509_V_FLAG_EXPLICIT_POLICY \ + | X509_V_FLAG_INHIBIT_ANY \ + | X509_V_FLAG_INHIBIT_MAP) + +int X509_OBJECT_idx_by_subject(STACK_OF(X509_OBJECT) *h, int type, + X509_NAME *name); +X509_OBJECT *X509_OBJECT_retrieve_by_subject(STACK_OF(X509_OBJECT) *h,int type,X509_NAME *name); +X509_OBJECT *X509_OBJECT_retrieve_match(STACK_OF(X509_OBJECT) *h, X509_OBJECT *x); +void X509_OBJECT_up_ref_count(X509_OBJECT *a); +void X509_OBJECT_free_contents(X509_OBJECT *a); +X509_STORE *X509_STORE_new(void ); +void X509_STORE_free(X509_STORE *v); + +int X509_STORE_set_flags(X509_STORE *ctx, unsigned long flags); +int X509_STORE_set_purpose(X509_STORE *ctx, int purpose); +int X509_STORE_set_trust(X509_STORE *ctx, int trust); +int X509_STORE_set1_param(X509_STORE *ctx, X509_VERIFY_PARAM *pm); + +X509_STORE_CTX *X509_STORE_CTX_new(void); + +int X509_STORE_CTX_get1_issuer(X509 **issuer, X509_STORE_CTX *ctx, X509 *x); + +void X509_STORE_CTX_free(X509_STORE_CTX *ctx); +int X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store, + X509 *x509, STACK_OF(X509) *chain); +void X509_STORE_CTX_trusted_stack(X509_STORE_CTX *ctx, STACK_OF(X509) *sk); +void X509_STORE_CTX_cleanup(X509_STORE_CTX *ctx); + +X509_LOOKUP *X509_STORE_add_lookup(X509_STORE *v, X509_LOOKUP_METHOD *m); + +X509_LOOKUP_METHOD *X509_LOOKUP_hash_dir(void); +X509_LOOKUP_METHOD *X509_LOOKUP_file(void); + +int X509_STORE_add_cert(X509_STORE *ctx, X509 *x); +int X509_STORE_add_crl(X509_STORE *ctx, X509_CRL *x); + +int X509_STORE_get_by_subject(X509_STORE_CTX *vs,int type,X509_NAME *name, + X509_OBJECT *ret); + +int X509_LOOKUP_ctrl(X509_LOOKUP *ctx, int cmd, const char *argc, + long argl, char **ret); + +#ifndef OPENSSL_NO_STDIO +int X509_load_cert_file(X509_LOOKUP *ctx, const char *file, int type); +int X509_load_crl_file(X509_LOOKUP *ctx, const char *file, int type); +int X509_load_cert_crl_file(X509_LOOKUP *ctx, const char *file, int type); +#endif + + +X509_LOOKUP *X509_LOOKUP_new(X509_LOOKUP_METHOD *method); +void X509_LOOKUP_free(X509_LOOKUP *ctx); +int X509_LOOKUP_init(X509_LOOKUP *ctx); +int X509_LOOKUP_by_subject(X509_LOOKUP *ctx, int type, X509_NAME *name, + X509_OBJECT *ret); +int X509_LOOKUP_by_issuer_serial(X509_LOOKUP *ctx, int type, X509_NAME *name, + ASN1_INTEGER *serial, X509_OBJECT *ret); +int X509_LOOKUP_by_fingerprint(X509_LOOKUP *ctx, int type, + unsigned char *bytes, int len, X509_OBJECT *ret); +int X509_LOOKUP_by_alias(X509_LOOKUP *ctx, int type, char *str, + int len, X509_OBJECT *ret); +int X509_LOOKUP_shutdown(X509_LOOKUP *ctx); + +#ifndef OPENSSL_NO_STDIO +int X509_STORE_load_locations (X509_STORE *ctx, + const char *file, const char *dir); +int X509_STORE_set_default_paths(X509_STORE *ctx); +#endif + +int X509_STORE_CTX_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func, + CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func); +int X509_STORE_CTX_set_ex_data(X509_STORE_CTX *ctx,int idx,void *data); +void * X509_STORE_CTX_get_ex_data(X509_STORE_CTX *ctx,int idx); +int X509_STORE_CTX_get_error(X509_STORE_CTX *ctx); +void X509_STORE_CTX_set_error(X509_STORE_CTX *ctx,int s); +int X509_STORE_CTX_get_error_depth(X509_STORE_CTX *ctx); +X509 * X509_STORE_CTX_get_current_cert(X509_STORE_CTX *ctx); +STACK_OF(X509) *X509_STORE_CTX_get_chain(X509_STORE_CTX *ctx); +STACK_OF(X509) *X509_STORE_CTX_get1_chain(X509_STORE_CTX *ctx); +void X509_STORE_CTX_set_cert(X509_STORE_CTX *c,X509 *x); +void X509_STORE_CTX_set_chain(X509_STORE_CTX *c,STACK_OF(X509) *sk); +void X509_STORE_CTX_set0_crls(X509_STORE_CTX *c,STACK_OF(X509_CRL) *sk); +int X509_STORE_CTX_set_purpose(X509_STORE_CTX *ctx, int purpose); +int X509_STORE_CTX_set_trust(X509_STORE_CTX *ctx, int trust); +int X509_STORE_CTX_purpose_inherit(X509_STORE_CTX *ctx, int def_purpose, + int purpose, int trust); +void X509_STORE_CTX_set_flags(X509_STORE_CTX *ctx, unsigned long flags); +void X509_STORE_CTX_set_time(X509_STORE_CTX *ctx, unsigned long flags, + time_t t); +void X509_STORE_CTX_set_verify_cb(X509_STORE_CTX *ctx, + int (*verify_cb)(int, X509_STORE_CTX *)); + +X509_POLICY_TREE *X509_STORE_CTX_get0_policy_tree(X509_STORE_CTX *ctx); +int X509_STORE_CTX_get_explicit_policy(X509_STORE_CTX *ctx); + +X509_VERIFY_PARAM *X509_STORE_CTX_get0_param(X509_STORE_CTX *ctx); +void X509_STORE_CTX_set0_param(X509_STORE_CTX *ctx, X509_VERIFY_PARAM *param); +int X509_STORE_CTX_set_default(X509_STORE_CTX *ctx, const char *name); + +/* X509_VERIFY_PARAM functions */ + +X509_VERIFY_PARAM *X509_VERIFY_PARAM_new(void); +void X509_VERIFY_PARAM_free(X509_VERIFY_PARAM *param); +int X509_VERIFY_PARAM_inherit(X509_VERIFY_PARAM *to, + const X509_VERIFY_PARAM *from); +int X509_VERIFY_PARAM_set1(X509_VERIFY_PARAM *to, + const X509_VERIFY_PARAM *from); +int X509_VERIFY_PARAM_set1_name(X509_VERIFY_PARAM *param, const char *name); +int X509_VERIFY_PARAM_set_flags(X509_VERIFY_PARAM *param, unsigned long flags); +int X509_VERIFY_PARAM_clear_flags(X509_VERIFY_PARAM *param, + unsigned long flags); +unsigned long X509_VERIFY_PARAM_get_flags(X509_VERIFY_PARAM *param); +int X509_VERIFY_PARAM_set_purpose(X509_VERIFY_PARAM *param, int purpose); +int X509_VERIFY_PARAM_set_trust(X509_VERIFY_PARAM *param, int trust); +void X509_VERIFY_PARAM_set_depth(X509_VERIFY_PARAM *param, int depth); +void X509_VERIFY_PARAM_set_time(X509_VERIFY_PARAM *param, time_t t); +int X509_VERIFY_PARAM_add0_policy(X509_VERIFY_PARAM *param, + ASN1_OBJECT *policy); +int X509_VERIFY_PARAM_set1_policies(X509_VERIFY_PARAM *param, + STACK_OF(ASN1_OBJECT) *policies); +int X509_VERIFY_PARAM_get_depth(const X509_VERIFY_PARAM *param); + +int X509_VERIFY_PARAM_add0_table(X509_VERIFY_PARAM *param); +const X509_VERIFY_PARAM *X509_VERIFY_PARAM_lookup(const char *name); +void X509_VERIFY_PARAM_table_cleanup(void); + +int X509_policy_check(X509_POLICY_TREE **ptree, int *pexplicit_policy, + STACK_OF(X509) *certs, + STACK_OF(ASN1_OBJECT) *policy_oids, + unsigned int flags); + +void X509_policy_tree_free(X509_POLICY_TREE *tree); + +int X509_policy_tree_level_count(const X509_POLICY_TREE *tree); +X509_POLICY_LEVEL * + X509_policy_tree_get0_level(const X509_POLICY_TREE *tree, int i); + +STACK_OF(X509_POLICY_NODE) * + X509_policy_tree_get0_policies(const X509_POLICY_TREE *tree); + +STACK_OF(X509_POLICY_NODE) * + X509_policy_tree_get0_user_policies(const X509_POLICY_TREE *tree); + +int X509_policy_level_node_count(X509_POLICY_LEVEL *level); + +X509_POLICY_NODE *X509_policy_level_get0_node(X509_POLICY_LEVEL *level, int i); + +const ASN1_OBJECT *X509_policy_node_get0_policy(const X509_POLICY_NODE *node); + +STACK_OF(POLICYQUALINFO) * + X509_policy_node_get0_qualifiers(const X509_POLICY_NODE *node); +const X509_POLICY_NODE * + X509_policy_node_get0_parent(const X509_POLICY_NODE *node); + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/lib_tls/include/openssl/x509v3.h b/lib_tls/include/openssl/x509v3.h new file mode 100644 index 000000000..db2b0482c --- /dev/null +++ b/lib_tls/include/openssl/x509v3.h @@ -0,0 +1,920 @@ +/* x509v3.h */ +/* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL + * project 1999. + */ +/* ==================================================================== + * Copyright (c) 1999-2004 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +#ifndef HEADER_X509V3_H +#define HEADER_X509V3_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Forward reference */ +struct v3_ext_method; +struct v3_ext_ctx; + +/* Useful typedefs */ + +typedef void * (*X509V3_EXT_NEW)(void); +typedef void (*X509V3_EXT_FREE)(void *); +typedef void * (*X509V3_EXT_D2I)(void *, const unsigned char ** , long); +typedef int (*X509V3_EXT_I2D)(void *, unsigned char **); +typedef STACK_OF(CONF_VALUE) * (*X509V3_EXT_I2V)(struct v3_ext_method *method, void *ext, STACK_OF(CONF_VALUE) *extlist); +typedef void * (*X509V3_EXT_V2I)(struct v3_ext_method *method, struct v3_ext_ctx *ctx, STACK_OF(CONF_VALUE) *values); +typedef char * (*X509V3_EXT_I2S)(struct v3_ext_method *method, void *ext); +typedef void * (*X509V3_EXT_S2I)(struct v3_ext_method *method, struct v3_ext_ctx *ctx, const char *str); +typedef int (*X509V3_EXT_I2R)(struct v3_ext_method *method, void *ext, BIO *out, int indent); +typedef void * (*X509V3_EXT_R2I)(struct v3_ext_method *method, struct v3_ext_ctx *ctx, const char *str); + +/* V3 extension structure */ + +struct v3_ext_method { +int ext_nid; +int ext_flags; +/* If this is set the following four fields are ignored */ +ASN1_ITEM_EXP *it; +/* Old style ASN1 calls */ +X509V3_EXT_NEW ext_new; +X509V3_EXT_FREE ext_free; +X509V3_EXT_D2I d2i; +X509V3_EXT_I2D i2d; + +/* The following pair is used for string extensions */ +X509V3_EXT_I2S i2s; +X509V3_EXT_S2I s2i; + +/* The following pair is used for multi-valued extensions */ +X509V3_EXT_I2V i2v; +X509V3_EXT_V2I v2i; + +/* The following are used for raw extensions */ +X509V3_EXT_I2R i2r; +X509V3_EXT_R2I r2i; + +void *usr_data; /* Any extension specific data */ +}; + +typedef struct X509V3_CONF_METHOD_st { +char * (*get_string)(void *db, char *section, char *value); +STACK_OF(CONF_VALUE) * (*get_section)(void *db, char *section); +void (*free_string)(void *db, char * string); +void (*free_section)(void *db, STACK_OF(CONF_VALUE) *section); +} X509V3_CONF_METHOD; + +/* Context specific info */ +struct v3_ext_ctx { +#define CTX_TEST 0x1 +int flags; +X509 *issuer_cert; +X509 *subject_cert; +X509_REQ *subject_req; +X509_CRL *crl; +X509V3_CONF_METHOD *db_meth; +void *db; +/* Maybe more here */ +}; + +typedef struct v3_ext_method X509V3_EXT_METHOD; + +DECLARE_STACK_OF(X509V3_EXT_METHOD) + +/* ext_flags values */ +#define X509V3_EXT_DYNAMIC 0x1 +#define X509V3_EXT_CTX_DEP 0x2 +#define X509V3_EXT_MULTILINE 0x4 + +typedef BIT_STRING_BITNAME ENUMERATED_NAMES; + +typedef struct BASIC_CONSTRAINTS_st { +int ca; +ASN1_INTEGER *pathlen; +} BASIC_CONSTRAINTS; + + +typedef struct PKEY_USAGE_PERIOD_st { +ASN1_GENERALIZEDTIME *notBefore; +ASN1_GENERALIZEDTIME *notAfter; +} PKEY_USAGE_PERIOD; + +typedef struct otherName_st { +ASN1_OBJECT *type_id; +ASN1_TYPE *value; +} OTHERNAME; + +typedef struct EDIPartyName_st { + ASN1_STRING *nameAssigner; + ASN1_STRING *partyName; +} EDIPARTYNAME; + +typedef struct GENERAL_NAME_st { + +#define GEN_OTHERNAME 0 +#define GEN_EMAIL 1 +#define GEN_DNS 2 +#define GEN_X400 3 +#define GEN_DIRNAME 4 +#define GEN_EDIPARTY 5 +#define GEN_URI 6 +#define GEN_IPADD 7 +#define GEN_RID 8 + +int type; +union { + char *ptr; + OTHERNAME *otherName; /* otherName */ + ASN1_IA5STRING *rfc822Name; + ASN1_IA5STRING *dNSName; + ASN1_TYPE *x400Address; + X509_NAME *directoryName; + EDIPARTYNAME *ediPartyName; + ASN1_IA5STRING *uniformResourceIdentifier; + ASN1_OCTET_STRING *iPAddress; + ASN1_OBJECT *registeredID; + + /* Old names */ + ASN1_OCTET_STRING *ip; /* iPAddress */ + X509_NAME *dirn; /* dirn */ + ASN1_IA5STRING *ia5;/* rfc822Name, dNSName, uniformResourceIdentifier */ + ASN1_OBJECT *rid; /* registeredID */ + ASN1_TYPE *other; /* x400Address */ +} d; +} GENERAL_NAME; + +typedef STACK_OF(GENERAL_NAME) GENERAL_NAMES; + +typedef struct ACCESS_DESCRIPTION_st { + ASN1_OBJECT *method; + GENERAL_NAME *location; +} ACCESS_DESCRIPTION; + +typedef STACK_OF(ACCESS_DESCRIPTION) AUTHORITY_INFO_ACCESS; + +typedef STACK_OF(ASN1_OBJECT) EXTENDED_KEY_USAGE; + +DECLARE_STACK_OF(GENERAL_NAME) +DECLARE_ASN1_SET_OF(GENERAL_NAME) + +DECLARE_STACK_OF(ACCESS_DESCRIPTION) +DECLARE_ASN1_SET_OF(ACCESS_DESCRIPTION) + +typedef struct DIST_POINT_NAME_st { +int type; +union { + GENERAL_NAMES *fullname; + STACK_OF(X509_NAME_ENTRY) *relativename; +} name; +} DIST_POINT_NAME; + +typedef struct DIST_POINT_st { +DIST_POINT_NAME *distpoint; +ASN1_BIT_STRING *reasons; +GENERAL_NAMES *CRLissuer; +} DIST_POINT; + +typedef STACK_OF(DIST_POINT) CRL_DIST_POINTS; + +DECLARE_STACK_OF(DIST_POINT) +DECLARE_ASN1_SET_OF(DIST_POINT) + +typedef struct AUTHORITY_KEYID_st { +ASN1_OCTET_STRING *keyid; +GENERAL_NAMES *issuer; +ASN1_INTEGER *serial; +} AUTHORITY_KEYID; + +/* Strong extranet structures */ + +typedef struct SXNET_ID_st { + ASN1_INTEGER *zone; + ASN1_OCTET_STRING *user; +} SXNETID; + +DECLARE_STACK_OF(SXNETID) +DECLARE_ASN1_SET_OF(SXNETID) + +typedef struct SXNET_st { + ASN1_INTEGER *version; + STACK_OF(SXNETID) *ids; +} SXNET; + +typedef struct NOTICEREF_st { + ASN1_STRING *organization; + STACK_OF(ASN1_INTEGER) *noticenos; +} NOTICEREF; + +typedef struct USERNOTICE_st { + NOTICEREF *noticeref; + ASN1_STRING *exptext; +} USERNOTICE; + +typedef struct POLICYQUALINFO_st { + ASN1_OBJECT *pqualid; + union { + ASN1_IA5STRING *cpsuri; + USERNOTICE *usernotice; + ASN1_TYPE *other; + } d; +} POLICYQUALINFO; + +DECLARE_STACK_OF(POLICYQUALINFO) +DECLARE_ASN1_SET_OF(POLICYQUALINFO) + +typedef struct POLICYINFO_st { + ASN1_OBJECT *policyid; + STACK_OF(POLICYQUALINFO) *qualifiers; +} POLICYINFO; + +typedef STACK_OF(POLICYINFO) CERTIFICATEPOLICIES; + +DECLARE_STACK_OF(POLICYINFO) +DECLARE_ASN1_SET_OF(POLICYINFO) + +typedef struct POLICY_MAPPING_st { + ASN1_OBJECT *issuerDomainPolicy; + ASN1_OBJECT *subjectDomainPolicy; +} POLICY_MAPPING; + +DECLARE_STACK_OF(POLICY_MAPPING) + +typedef STACK_OF(POLICY_MAPPING) POLICY_MAPPINGS; + +typedef struct GENERAL_SUBTREE_st { + GENERAL_NAME *base; + ASN1_INTEGER *minimum; + ASN1_INTEGER *maximum; +} GENERAL_SUBTREE; + +DECLARE_STACK_OF(GENERAL_SUBTREE) + +typedef struct NAME_CONSTRAINTS_st { + STACK_OF(GENERAL_SUBTREE) *permittedSubtrees; + STACK_OF(GENERAL_SUBTREE) *excludedSubtrees; +} NAME_CONSTRAINTS; + +typedef struct POLICY_CONSTRAINTS_st { + ASN1_INTEGER *requireExplicitPolicy; + ASN1_INTEGER *inhibitPolicyMapping; +} POLICY_CONSTRAINTS; + +/* Proxy certificate structures, see RFC 3820 */ +typedef struct PROXY_POLICY_st + { + ASN1_OBJECT *policyLanguage; + ASN1_OCTET_STRING *policy; + } PROXY_POLICY; + +typedef struct PROXY_CERT_INFO_EXTENSION_st + { + ASN1_INTEGER *pcPathLengthConstraint; + PROXY_POLICY *proxyPolicy; + } PROXY_CERT_INFO_EXTENSION; + +DECLARE_ASN1_FUNCTIONS(PROXY_POLICY) +DECLARE_ASN1_FUNCTIONS(PROXY_CERT_INFO_EXTENSION) + + +#define X509V3_conf_err(val) ERR_add_error_data(6, "section:", val->section, \ +",name:", val->name, ",value:", val->value); + +#define X509V3_set_ctx_test(ctx) \ + X509V3_set_ctx(ctx, NULL, NULL, NULL, NULL, CTX_TEST) +#define X509V3_set_ctx_nodb(ctx) (ctx)->db = NULL; + +#define EXT_BITSTRING(nid, table) { nid, 0, ASN1_ITEM_ref(ASN1_BIT_STRING), \ + 0,0,0,0, \ + 0,0, \ + (X509V3_EXT_I2V)i2v_ASN1_BIT_STRING, \ + (X509V3_EXT_V2I)v2i_ASN1_BIT_STRING, \ + NULL, NULL, \ + table} + +#define EXT_IA5STRING(nid) { nid, 0, ASN1_ITEM_ref(ASN1_IA5STRING), \ + 0,0,0,0, \ + (X509V3_EXT_I2S)i2s_ASN1_IA5STRING, \ + (X509V3_EXT_S2I)s2i_ASN1_IA5STRING, \ + 0,0,0,0, \ + NULL} + +#define EXT_END { -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + + +/* X509_PURPOSE stuff */ + +#define EXFLAG_BCONS 0x1 +#define EXFLAG_KUSAGE 0x2 +#define EXFLAG_XKUSAGE 0x4 +#define EXFLAG_NSCERT 0x8 + +#define EXFLAG_CA 0x10 +#define EXFLAG_SS 0x20 +#define EXFLAG_V1 0x40 +#define EXFLAG_INVALID 0x80 +#define EXFLAG_SET 0x100 +#define EXFLAG_CRITICAL 0x200 +#define EXFLAG_PROXY 0x400 + +#define EXFLAG_INVALID_POLICY 0x400 + +#define KU_DIGITAL_SIGNATURE 0x0080 +#define KU_NON_REPUDIATION 0x0040 +#define KU_KEY_ENCIPHERMENT 0x0020 +#define KU_DATA_ENCIPHERMENT 0x0010 +#define KU_KEY_AGREEMENT 0x0008 +#define KU_KEY_CERT_SIGN 0x0004 +#define KU_CRL_SIGN 0x0002 +#define KU_ENCIPHER_ONLY 0x0001 +#define KU_DECIPHER_ONLY 0x8000 + +#define NS_SSL_CLIENT 0x80 +#define NS_SSL_SERVER 0x40 +#define NS_SMIME 0x20 +#define NS_OBJSIGN 0x10 +#define NS_SSL_CA 0x04 +#define NS_SMIME_CA 0x02 +#define NS_OBJSIGN_CA 0x01 +#define NS_ANY_CA (NS_SSL_CA|NS_SMIME_CA|NS_OBJSIGN_CA) + +#define XKU_SSL_SERVER 0x1 +#define XKU_SSL_CLIENT 0x2 +#define XKU_SMIME 0x4 +#define XKU_CODE_SIGN 0x8 +#define XKU_SGC 0x10 +#define XKU_OCSP_SIGN 0x20 +#define XKU_TIMESTAMP 0x40 +#define XKU_DVCS 0x80 + +#define X509_PURPOSE_DYNAMIC 0x1 +#define X509_PURPOSE_DYNAMIC_NAME 0x2 + +typedef struct x509_purpose_st { + int purpose; + int trust; /* Default trust ID */ + int flags; + int (*check_purpose)(const struct x509_purpose_st *, + const X509 *, int); + char *name; + char *sname; + void *usr_data; +} X509_PURPOSE; + +#define X509_PURPOSE_SSL_CLIENT 1 +#define X509_PURPOSE_SSL_SERVER 2 +#define X509_PURPOSE_NS_SSL_SERVER 3 +#define X509_PURPOSE_SMIME_SIGN 4 +#define X509_PURPOSE_SMIME_ENCRYPT 5 +#define X509_PURPOSE_CRL_SIGN 6 +#define X509_PURPOSE_ANY 7 +#define X509_PURPOSE_OCSP_HELPER 8 + +#define X509_PURPOSE_MIN 1 +#define X509_PURPOSE_MAX 8 + +/* Flags for X509V3_EXT_print() */ + +#define X509V3_EXT_UNKNOWN_MASK (0xfL << 16) +/* Return error for unknown extensions */ +#define X509V3_EXT_DEFAULT 0 +/* Print error for unknown extensions */ +#define X509V3_EXT_ERROR_UNKNOWN (1L << 16) +/* ASN1 parse unknown extensions */ +#define X509V3_EXT_PARSE_UNKNOWN (2L << 16) +/* BIO_dump unknown extensions */ +#define X509V3_EXT_DUMP_UNKNOWN (3L << 16) + +/* Flags for X509V3_add1_i2d */ + +#define X509V3_ADD_OP_MASK 0xfL +#define X509V3_ADD_DEFAULT 0L +#define X509V3_ADD_APPEND 1L +#define X509V3_ADD_REPLACE 2L +#define X509V3_ADD_REPLACE_EXISTING 3L +#define X509V3_ADD_KEEP_EXISTING 4L +#define X509V3_ADD_DELETE 5L +#define X509V3_ADD_SILENT 0x10 + +DECLARE_STACK_OF(X509_PURPOSE) + +DECLARE_ASN1_FUNCTIONS(BASIC_CONSTRAINTS) + +DECLARE_ASN1_FUNCTIONS(SXNET) +DECLARE_ASN1_FUNCTIONS(SXNETID) + +int SXNET_add_id_asc(SXNET **psx, char *zone, char *user, int userlen); +int SXNET_add_id_ulong(SXNET **psx, unsigned long lzone, char *user, int userlen); +int SXNET_add_id_INTEGER(SXNET **psx, ASN1_INTEGER *izone, char *user, int userlen); + +ASN1_OCTET_STRING *SXNET_get_id_asc(SXNET *sx, char *zone); +ASN1_OCTET_STRING *SXNET_get_id_ulong(SXNET *sx, unsigned long lzone); +ASN1_OCTET_STRING *SXNET_get_id_INTEGER(SXNET *sx, ASN1_INTEGER *zone); + +DECLARE_ASN1_FUNCTIONS(AUTHORITY_KEYID) + +DECLARE_ASN1_FUNCTIONS(PKEY_USAGE_PERIOD) + +DECLARE_ASN1_FUNCTIONS(GENERAL_NAME) + + +ASN1_BIT_STRING *v2i_ASN1_BIT_STRING(X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval); +STACK_OF(CONF_VALUE) *i2v_ASN1_BIT_STRING(X509V3_EXT_METHOD *method, + ASN1_BIT_STRING *bits, + STACK_OF(CONF_VALUE) *extlist); + +STACK_OF(CONF_VALUE) *i2v_GENERAL_NAME(X509V3_EXT_METHOD *method, GENERAL_NAME *gen, STACK_OF(CONF_VALUE) *ret); +int GENERAL_NAME_print(BIO *out, GENERAL_NAME *gen); + +DECLARE_ASN1_FUNCTIONS(GENERAL_NAMES) + +STACK_OF(CONF_VALUE) *i2v_GENERAL_NAMES(X509V3_EXT_METHOD *method, + GENERAL_NAMES *gen, STACK_OF(CONF_VALUE) *extlist); +GENERAL_NAMES *v2i_GENERAL_NAMES(X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval); + +DECLARE_ASN1_FUNCTIONS(OTHERNAME) +DECLARE_ASN1_FUNCTIONS(EDIPARTYNAME) + +char *i2s_ASN1_OCTET_STRING(X509V3_EXT_METHOD *method, ASN1_OCTET_STRING *ia5); +ASN1_OCTET_STRING *s2i_ASN1_OCTET_STRING(X509V3_EXT_METHOD *method, X509V3_CTX *ctx, char *str); + +DECLARE_ASN1_FUNCTIONS(EXTENDED_KEY_USAGE) +int i2a_ACCESS_DESCRIPTION(BIO *bp, ACCESS_DESCRIPTION* a); + +DECLARE_ASN1_FUNCTIONS(CERTIFICATEPOLICIES) +DECLARE_ASN1_FUNCTIONS(POLICYINFO) +DECLARE_ASN1_FUNCTIONS(POLICYQUALINFO) +DECLARE_ASN1_FUNCTIONS(USERNOTICE) +DECLARE_ASN1_FUNCTIONS(NOTICEREF) + +DECLARE_ASN1_FUNCTIONS(CRL_DIST_POINTS) +DECLARE_ASN1_FUNCTIONS(DIST_POINT) +DECLARE_ASN1_FUNCTIONS(DIST_POINT_NAME) + +DECLARE_ASN1_FUNCTIONS(ACCESS_DESCRIPTION) +DECLARE_ASN1_FUNCTIONS(AUTHORITY_INFO_ACCESS) + +DECLARE_ASN1_ITEM(POLICY_MAPPING) +DECLARE_ASN1_ALLOC_FUNCTIONS(POLICY_MAPPING) +DECLARE_ASN1_ITEM(POLICY_MAPPINGS) + +DECLARE_ASN1_ITEM(GENERAL_SUBTREE) +DECLARE_ASN1_ALLOC_FUNCTIONS(GENERAL_SUBTREE) + +DECLARE_ASN1_ITEM(NAME_CONSTRAINTS) +DECLARE_ASN1_ALLOC_FUNCTIONS(NAME_CONSTRAINTS) + +DECLARE_ASN1_ALLOC_FUNCTIONS(POLICY_CONSTRAINTS) +DECLARE_ASN1_ITEM(POLICY_CONSTRAINTS) + +#ifdef HEADER_CONF_H +GENERAL_NAME *v2i_GENERAL_NAME(X509V3_EXT_METHOD *method, X509V3_CTX *ctx, + CONF_VALUE *cnf); +GENERAL_NAME *v2i_GENERAL_NAME_ex(GENERAL_NAME *out, X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, CONF_VALUE *cnf, int is_nc); +void X509V3_conf_free(CONF_VALUE *val); + +X509_EXTENSION *X509V3_EXT_nconf_nid(CONF *conf, X509V3_CTX *ctx, int ext_nid, char *value); +X509_EXTENSION *X509V3_EXT_nconf(CONF *conf, X509V3_CTX *ctx, char *name, char *value); +int X509V3_EXT_add_nconf_sk(CONF *conf, X509V3_CTX *ctx, char *section, STACK_OF(X509_EXTENSION) **sk); +int X509V3_EXT_add_nconf(CONF *conf, X509V3_CTX *ctx, char *section, X509 *cert); +int X509V3_EXT_REQ_add_nconf(CONF *conf, X509V3_CTX *ctx, char *section, X509_REQ *req); +int X509V3_EXT_CRL_add_nconf(CONF *conf, X509V3_CTX *ctx, char *section, X509_CRL *crl); + +X509_EXTENSION *X509V3_EXT_conf_nid(LHASH *conf, X509V3_CTX *ctx, int ext_nid, char *value); +X509_EXTENSION *X509V3_EXT_conf(LHASH *conf, X509V3_CTX *ctx, char *name, char *value); +int X509V3_EXT_add_conf(LHASH *conf, X509V3_CTX *ctx, char *section, X509 *cert); +int X509V3_EXT_REQ_add_conf(LHASH *conf, X509V3_CTX *ctx, char *section, X509_REQ *req); +int X509V3_EXT_CRL_add_conf(LHASH *conf, X509V3_CTX *ctx, char *section, X509_CRL *crl); + +int X509V3_add_value_bool_nf(char *name, int asn1_bool, + STACK_OF(CONF_VALUE) **extlist); +int X509V3_get_value_bool(CONF_VALUE *value, int *asn1_bool); +int X509V3_get_value_int(CONF_VALUE *value, ASN1_INTEGER **aint); +void X509V3_set_nconf(X509V3_CTX *ctx, CONF *conf); +void X509V3_set_conf_lhash(X509V3_CTX *ctx, LHASH *lhash); +#endif + +char * X509V3_get_string(X509V3_CTX *ctx, char *name, char *section); +STACK_OF(CONF_VALUE) * X509V3_get_section(X509V3_CTX *ctx, char *section); +void X509V3_string_free(X509V3_CTX *ctx, char *str); +void X509V3_section_free( X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *section); +void X509V3_set_ctx(X509V3_CTX *ctx, X509 *issuer, X509 *subject, + X509_REQ *req, X509_CRL *crl, int flags); + +int X509V3_add_value(const char *name, const char *value, + STACK_OF(CONF_VALUE) **extlist); +int X509V3_add_value_uchar(const char *name, const unsigned char *value, + STACK_OF(CONF_VALUE) **extlist); +int X509V3_add_value_bool(const char *name, int asn1_bool, + STACK_OF(CONF_VALUE) **extlist); +int X509V3_add_value_int(const char *name, ASN1_INTEGER *aint, + STACK_OF(CONF_VALUE) **extlist); +char * i2s_ASN1_INTEGER(X509V3_EXT_METHOD *meth, ASN1_INTEGER *aint); +ASN1_INTEGER * s2i_ASN1_INTEGER(X509V3_EXT_METHOD *meth, char *value); +char * i2s_ASN1_ENUMERATED(X509V3_EXT_METHOD *meth, ASN1_ENUMERATED *aint); +char * i2s_ASN1_ENUMERATED_TABLE(X509V3_EXT_METHOD *meth, ASN1_ENUMERATED *aint); +int X509V3_EXT_add(X509V3_EXT_METHOD *ext); +int X509V3_EXT_add_list(X509V3_EXT_METHOD *extlist); +int X509V3_EXT_add_alias(int nid_to, int nid_from); +void X509V3_EXT_cleanup(void); + +X509V3_EXT_METHOD *X509V3_EXT_get(X509_EXTENSION *ext); +X509V3_EXT_METHOD *X509V3_EXT_get_nid(int nid); +int X509V3_add_standard_extensions(void); +STACK_OF(CONF_VALUE) *X509V3_parse_list(const char *line); +void *X509V3_EXT_d2i(X509_EXTENSION *ext); +void *X509V3_get_d2i(STACK_OF(X509_EXTENSION) *x, int nid, int *crit, int *idx); + + +X509_EXTENSION *X509V3_EXT_i2d(int ext_nid, int crit, void *ext_struc); +int X509V3_add1_i2d(STACK_OF(X509_EXTENSION) **x, int nid, void *value, int crit, unsigned long flags); + +char *hex_to_string(unsigned char *buffer, long len); +unsigned char *string_to_hex(char *str, long *len); +int name_cmp(const char *name, const char *cmp); + +void X509V3_EXT_val_prn(BIO *out, STACK_OF(CONF_VALUE) *val, int indent, + int ml); +int X509V3_EXT_print(BIO *out, X509_EXTENSION *ext, unsigned long flag, int indent); +int X509V3_EXT_print_fp(FILE *out, X509_EXTENSION *ext, int flag, int indent); + +int X509V3_extensions_print(BIO *out, char *title, STACK_OF(X509_EXTENSION) *exts, unsigned long flag, int indent); + +int X509_check_ca(X509 *x); +int X509_check_purpose(X509 *x, int id, int ca); +int X509_supported_extension(X509_EXTENSION *ex); +int X509_PURPOSE_set(int *p, int purpose); +int X509_check_issued(X509 *issuer, X509 *subject); +int X509_PURPOSE_get_count(void); +X509_PURPOSE * X509_PURPOSE_get0(int idx); +int X509_PURPOSE_get_by_sname(char *sname); +int X509_PURPOSE_get_by_id(int id); +int X509_PURPOSE_add(int id, int trust, int flags, + int (*ck)(const X509_PURPOSE *, const X509 *, int), + char *name, char *sname, void *arg); +char *X509_PURPOSE_get0_name(X509_PURPOSE *xp); +char *X509_PURPOSE_get0_sname(X509_PURPOSE *xp); +int X509_PURPOSE_get_trust(X509_PURPOSE *xp); +void X509_PURPOSE_cleanup(void); +int X509_PURPOSE_get_id(X509_PURPOSE *); + +STACK *X509_get1_email(X509 *x); +STACK *X509_REQ_get1_email(X509_REQ *x); +void X509_email_free(STACK *sk); +STACK *X509_get1_ocsp(X509 *x); + +ASN1_OCTET_STRING *a2i_IPADDRESS(const char *ipasc); +ASN1_OCTET_STRING *a2i_IPADDRESS_NC(const char *ipasc); +int a2i_ipadd(unsigned char *ipout, const char *ipasc); +int X509V3_NAME_from_section(X509_NAME *nm, STACK_OF(CONF_VALUE)*dn_sk, + unsigned long chtype); + +void X509_POLICY_NODE_print(BIO *out, X509_POLICY_NODE *node, int indent); + +#ifndef OPENSSL_NO_RFC3779 + +typedef struct ASRange_st { + ASN1_INTEGER *min, *max; +} ASRange; + +#define ASIdOrRange_id 0 +#define ASIdOrRange_range 1 + +typedef struct ASIdOrRange_st { + int type; + union { + ASN1_INTEGER *id; + ASRange *range; + } u; +} ASIdOrRange; + +typedef STACK_OF(ASIdOrRange) ASIdOrRanges; +DECLARE_STACK_OF(ASIdOrRange) + +#define ASIdentifierChoice_inherit 0 +#define ASIdentifierChoice_asIdsOrRanges 1 + +typedef struct ASIdentifierChoice_st { + int type; + union { + ASN1_NULL *inherit; + ASIdOrRanges *asIdsOrRanges; + } u; +} ASIdentifierChoice; + +typedef struct ASIdentifiers_st { + ASIdentifierChoice *asnum, *rdi; +} ASIdentifiers; + +DECLARE_ASN1_FUNCTIONS(ASRange) +DECLARE_ASN1_FUNCTIONS(ASIdOrRange) +DECLARE_ASN1_FUNCTIONS(ASIdentifierChoice) +DECLARE_ASN1_FUNCTIONS(ASIdentifiers) + + +typedef struct IPAddressRange_st { + ASN1_BIT_STRING *min, *max; +} IPAddressRange; + +#define IPAddressOrRange_addressPrefix 0 +#define IPAddressOrRange_addressRange 1 + +typedef struct IPAddressOrRange_st { + int type; + union { + ASN1_BIT_STRING *addressPrefix; + IPAddressRange *addressRange; + } u; +} IPAddressOrRange; + +typedef STACK_OF(IPAddressOrRange) IPAddressOrRanges; +DECLARE_STACK_OF(IPAddressOrRange) + +#define IPAddressChoice_inherit 0 +#define IPAddressChoice_addressesOrRanges 1 + +typedef struct IPAddressChoice_st { + int type; + union { + ASN1_NULL *inherit; + IPAddressOrRanges *addressesOrRanges; + } u; +} IPAddressChoice; + +typedef struct IPAddressFamily_st { + ASN1_OCTET_STRING *addressFamily; + IPAddressChoice *ipAddressChoice; +} IPAddressFamily; + +typedef STACK_OF(IPAddressFamily) IPAddrBlocks; +DECLARE_STACK_OF(IPAddressFamily) + +DECLARE_ASN1_FUNCTIONS(IPAddressRange) +DECLARE_ASN1_FUNCTIONS(IPAddressOrRange) +DECLARE_ASN1_FUNCTIONS(IPAddressChoice) +DECLARE_ASN1_FUNCTIONS(IPAddressFamily) + +/* + * API tag for elements of the ASIdentifer SEQUENCE. + */ +#define V3_ASID_ASNUM 0 +#define V3_ASID_RDI 1 + +/* + * AFI values, assigned by IANA. It'd be nice to make the AFI + * handling code totally generic, but there are too many little things + * that would need to be defined for other address families for it to + * be worth the trouble. + */ +#define IANA_AFI_IPV4 1 +#define IANA_AFI_IPV6 2 + +/* + * Utilities to construct and extract values from RFC3779 extensions, + * since some of the encodings (particularly for IP address prefixes + * and ranges) are a bit tedious to work with directly. + */ +int v3_asid_add_inherit(ASIdentifiers *asid, int which); +int v3_asid_add_id_or_range(ASIdentifiers *asid, int which, + ASN1_INTEGER *min, ASN1_INTEGER *max); +int v3_addr_add_inherit(IPAddrBlocks *addr, + const unsigned afi, const unsigned *safi); +int v3_addr_add_prefix(IPAddrBlocks *addr, + const unsigned afi, const unsigned *safi, + unsigned char *a, const int prefixlen); +int v3_addr_add_range(IPAddrBlocks *addr, + const unsigned afi, const unsigned *safi, + unsigned char *min, unsigned char *max); +unsigned v3_addr_get_afi(const IPAddressFamily *f); +int v3_addr_get_range(IPAddressOrRange *aor, const unsigned afi, + unsigned char *min, unsigned char *max, + const int length); + +/* + * Canonical forms. + */ +int v3_asid_is_canonical(ASIdentifiers *asid); +int v3_addr_is_canonical(IPAddrBlocks *addr); +int v3_asid_canonize(ASIdentifiers *asid); +int v3_addr_canonize(IPAddrBlocks *addr); + +/* + * Tests for inheritance and containment. + */ +int v3_asid_inherits(ASIdentifiers *asid); +int v3_addr_inherits(IPAddrBlocks *addr); +int v3_asid_subset(ASIdentifiers *a, ASIdentifiers *b); +int v3_addr_subset(IPAddrBlocks *a, IPAddrBlocks *b); + +/* + * Check whether RFC 3779 extensions nest properly in chains. + */ +int v3_asid_validate_path(X509_STORE_CTX *); +int v3_addr_validate_path(X509_STORE_CTX *); +int v3_asid_validate_resource_set(STACK_OF(X509) *chain, + ASIdentifiers *ext, + int allow_inheritance); +int v3_addr_validate_resource_set(STACK_OF(X509) *chain, + IPAddrBlocks *ext, + int allow_inheritance); + +#endif /* OPENSSL_NO_RFC3779 */ + +/* BEGIN ERROR CODES */ +/* The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ +void ERR_load_X509V3_strings(void); + +/* Error codes for the X509V3 functions. */ + +/* Function codes. */ +#define X509V3_F_ASIDENTIFIERCHOICE_CANONIZE 156 +#define X509V3_F_ASIDENTIFIERCHOICE_IS_CANONICAL 157 +#define X509V3_F_COPY_EMAIL 122 +#define X509V3_F_COPY_ISSUER 123 +#define X509V3_F_DO_DIRNAME 144 +#define X509V3_F_DO_EXT_CONF 124 +#define X509V3_F_DO_EXT_I2D 135 +#define X509V3_F_DO_EXT_NCONF 151 +#define X509V3_F_DO_I2V_NAME_CONSTRAINTS 148 +#define X509V3_F_HEX_TO_STRING 111 +#define X509V3_F_I2S_ASN1_ENUMERATED 121 +#define X509V3_F_I2S_ASN1_IA5STRING 149 +#define X509V3_F_I2S_ASN1_INTEGER 120 +#define X509V3_F_I2V_AUTHORITY_INFO_ACCESS 138 +#define X509V3_F_NOTICE_SECTION 132 +#define X509V3_F_NREF_NOS 133 +#define X509V3_F_POLICY_SECTION 131 +#define X509V3_F_PROCESS_PCI_VALUE 150 +#define X509V3_F_R2I_CERTPOL 130 +#define X509V3_F_R2I_PCI 155 +#define X509V3_F_S2I_ASN1_IA5STRING 100 +#define X509V3_F_S2I_ASN1_INTEGER 108 +#define X509V3_F_S2I_ASN1_OCTET_STRING 112 +#define X509V3_F_S2I_ASN1_SKEY_ID 114 +#define X509V3_F_S2I_SKEY_ID 115 +#define X509V3_F_STRING_TO_HEX 113 +#define X509V3_F_SXNET_ADD_ID_ASC 125 +#define X509V3_F_SXNET_ADD_ID_INTEGER 126 +#define X509V3_F_SXNET_ADD_ID_ULONG 127 +#define X509V3_F_SXNET_GET_ID_ASC 128 +#define X509V3_F_SXNET_GET_ID_ULONG 129 +#define X509V3_F_V2I_ASIDENTIFIERS 158 +#define X509V3_F_V2I_ASN1_BIT_STRING 101 +#define X509V3_F_V2I_AUTHORITY_INFO_ACCESS 139 +#define X509V3_F_V2I_AUTHORITY_KEYID 119 +#define X509V3_F_V2I_BASIC_CONSTRAINTS 102 +#define X509V3_F_V2I_CRLD 134 +#define X509V3_F_V2I_EXTENDED_KEY_USAGE 103 +#define X509V3_F_V2I_GENERAL_NAMES 118 +#define X509V3_F_V2I_GENERAL_NAME_EX 117 +#define X509V3_F_V2I_IPADDRBLOCKS 159 +#define X509V3_F_V2I_ISSUER_ALT 153 +#define X509V3_F_V2I_NAME_CONSTRAINTS 147 +#define X509V3_F_V2I_POLICY_CONSTRAINTS 146 +#define X509V3_F_V2I_POLICY_MAPPINGS 145 +#define X509V3_F_V2I_SUBJECT_ALT 154 +#define X509V3_F_V3_ADDR_VALIDATE_PATH_INTERNAL 160 +#define X509V3_F_V3_GENERIC_EXTENSION 116 +#define X509V3_F_X509V3_ADD1_I2D 140 +#define X509V3_F_X509V3_ADD_VALUE 105 +#define X509V3_F_X509V3_EXT_ADD 104 +#define X509V3_F_X509V3_EXT_ADD_ALIAS 106 +#define X509V3_F_X509V3_EXT_CONF 107 +#define X509V3_F_X509V3_EXT_I2D 136 +#define X509V3_F_X509V3_EXT_NCONF 152 +#define X509V3_F_X509V3_GET_SECTION 142 +#define X509V3_F_X509V3_GET_STRING 143 +#define X509V3_F_X509V3_GET_VALUE_BOOL 110 +#define X509V3_F_X509V3_PARSE_LIST 109 +#define X509V3_F_X509_PURPOSE_ADD 137 +#define X509V3_F_X509_PURPOSE_SET 141 + +/* Reason codes. */ +#define X509V3_R_BAD_IP_ADDRESS 118 +#define X509V3_R_BAD_OBJECT 119 +#define X509V3_R_BN_DEC2BN_ERROR 100 +#define X509V3_R_BN_TO_ASN1_INTEGER_ERROR 101 +#define X509V3_R_DIRNAME_ERROR 149 +#define X509V3_R_DUPLICATE_ZONE_ID 133 +#define X509V3_R_ERROR_CONVERTING_ZONE 131 +#define X509V3_R_ERROR_CREATING_EXTENSION 144 +#define X509V3_R_ERROR_IN_EXTENSION 128 +#define X509V3_R_EXPECTED_A_SECTION_NAME 137 +#define X509V3_R_EXTENSION_EXISTS 145 +#define X509V3_R_EXTENSION_NAME_ERROR 115 +#define X509V3_R_EXTENSION_NOT_FOUND 102 +#define X509V3_R_EXTENSION_SETTING_NOT_SUPPORTED 103 +#define X509V3_R_EXTENSION_VALUE_ERROR 116 +#define X509V3_R_ILLEGAL_EMPTY_EXTENSION 151 +#define X509V3_R_ILLEGAL_HEX_DIGIT 113 +#define X509V3_R_INCORRECT_POLICY_SYNTAX_TAG 152 +#define X509V3_R_INVALID_ASNUMBER 160 +#define X509V3_R_INVALID_ASRANGE 161 +#define X509V3_R_INVALID_BOOLEAN_STRING 104 +#define X509V3_R_INVALID_EXTENSION_STRING 105 +#define X509V3_R_INVALID_INHERITANCE 162 +#define X509V3_R_INVALID_IPADDRESS 163 +#define X509V3_R_INVALID_NAME 106 +#define X509V3_R_INVALID_NULL_ARGUMENT 107 +#define X509V3_R_INVALID_NULL_NAME 108 +#define X509V3_R_INVALID_NULL_VALUE 109 +#define X509V3_R_INVALID_NUMBER 140 +#define X509V3_R_INVALID_NUMBERS 141 +#define X509V3_R_INVALID_OBJECT_IDENTIFIER 110 +#define X509V3_R_INVALID_OPTION 138 +#define X509V3_R_INVALID_POLICY_IDENTIFIER 134 +#define X509V3_R_INVALID_PROXY_POLICY_SETTING 153 +#define X509V3_R_INVALID_PURPOSE 146 +#define X509V3_R_INVALID_SAFI 164 +#define X509V3_R_INVALID_SECTION 135 +#define X509V3_R_INVALID_SYNTAX 143 +#define X509V3_R_ISSUER_DECODE_ERROR 126 +#define X509V3_R_MISSING_VALUE 124 +#define X509V3_R_NEED_ORGANIZATION_AND_NUMBERS 142 +#define X509V3_R_NO_CONFIG_DATABASE 136 +#define X509V3_R_NO_ISSUER_CERTIFICATE 121 +#define X509V3_R_NO_ISSUER_DETAILS 127 +#define X509V3_R_NO_POLICY_IDENTIFIER 139 +#define X509V3_R_NO_PROXY_CERT_POLICY_LANGUAGE_DEFINED 154 +#define X509V3_R_NO_PUBLIC_KEY 114 +#define X509V3_R_NO_SUBJECT_DETAILS 125 +#define X509V3_R_ODD_NUMBER_OF_DIGITS 112 +#define X509V3_R_OPERATION_NOT_DEFINED 148 +#define X509V3_R_OTHERNAME_ERROR 147 +#define X509V3_R_POLICY_LANGUAGE_ALREADTY_DEFINED 155 +#define X509V3_R_POLICY_PATH_LENGTH 156 +#define X509V3_R_POLICY_PATH_LENGTH_ALREADTY_DEFINED 157 +#define X509V3_R_POLICY_SYNTAX_NOT_CURRENTLY_SUPPORTED 158 +#define X509V3_R_POLICY_WHEN_PROXY_LANGUAGE_REQUIRES_NO_POLICY 159 +#define X509V3_R_SECTION_NOT_FOUND 150 +#define X509V3_R_UNABLE_TO_GET_ISSUER_DETAILS 122 +#define X509V3_R_UNABLE_TO_GET_ISSUER_KEYID 123 +#define X509V3_R_UNKNOWN_BIT_STRING_ARGUMENT 111 +#define X509V3_R_UNKNOWN_EXTENSION 129 +#define X509V3_R_UNKNOWN_EXTENSION_NAME 130 +#define X509V3_R_UNKNOWN_OPTION 120 +#define X509V3_R_UNSUPPORTED_OPTION 117 +#define X509V3_R_USER_TOO_LONG 132 + +#ifdef __cplusplus +} +#endif +#endif diff --git a/lib_tls/include/tls.h b/lib_tls/include/tls.h new file mode 100644 index 000000000..2299d6948 --- /dev/null +++ b/lib_tls/include/tls.h @@ -0,0 +1,294 @@ +#ifndef _TLS_H_INCLUDED_ +#define _TLS_H_INCLUDED_ + +/*++ + * NAME + * tls 3h + * SUMMARY + * libtls internal interfaces + * SYNOPSIS + * #include + * DESCRIPTION + * .nf + + * + * Utility library. + */ + +#include "lib_acl.h" + +#ifdef USE_TLS + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef TLS_DLL +# ifdef TLS_EXPORTS +# define TLS_API __declspec(dllexport) +# else +# define TLS_API __declspec(dllimport) +# endif +#else +# define TLS_API +#endif + + /* + * OpenSSL library. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#if (OPENSSL_VERSION_NUMBER < 0x00905100L) +#error "need OpenSSL version 0.9.5 or later" +#endif + + /* + * TLS enforcement levels. Non-sentinel values may also be used to indicate + * the actual security level of a session. + * + * XXX TLS_LEV_NOTFOUND no longer belongs in this list. The SMTP client will + * have to use something else to report that policy table lookup failed. + */ +#define TLS_LEV_INVALID -2 /* sentinel */ +#define TLS_LEV_NOTFOUND -1 /* XXX not in policy table */ +#define TLS_LEV_NONE 0 /* plain-text only */ +#define TLS_LEV_MAY 1 /* wildcard */ +#define TLS_LEV_ENCRYPT 2 /* encrypted connection */ +#define TLS_LEV_FPRINT 3 /* "peer" CA-less verification */ +#define TLS_LEV_VERIFY 4 /* certificate verified */ +#define TLS_LEV_SECURE 5 /* "secure" verification */ + + /* + * Peer status bits. TLS_CERT_FLAG_MATCHED implies TLS_CERT_FLAG_TRUSTED + * only in the case of a hostname match. + */ +#define TLS_CERT_FLAG_PRESENT (1<<0) +#define TLS_CERT_FLAG_ALTNAME (1<<1) +#define TLS_CERT_FLAG_TRUSTED (1<<2) +#define TLS_CERT_FLAG_MATCHED (1<<3) +#define TLS_CERT_FLAG_LOGGED (1<<4) /* Logged trust chain error */ + +#define TLS_CERT_IS_PRESENT(c) ((c) && ((c)->peer_status&TLS_CERT_FLAG_PRESENT)) +#define TLS_CERT_IS_ALTNAME(c) ((c) && ((c)->peer_status&TLS_CERT_FLAG_ALTNAME)) +#define TLS_CERT_IS_TRUSTED(c) ((c) && ((c)->peer_status&TLS_CERT_FLAG_TRUSTED)) +#define TLS_CERT_IS_MATCHED(c) ((c) && ((c)->peer_status&TLS_CERT_FLAG_MATCHED)) + + + /* + * Names of valid tlsmgr(8) session caches. + */ +#define TLS_MGR_SCACHE_SERVER "server" +#define TLS_MGR_SCACHE_CLIENT "client" + + /* + * TLS session context, also used by the ACL_VSTREAM call-back routines for SMTP + * input/output, and by OpenSSL call-back routines for key verification. + * Only some members are (read-only) accessible by the public. + */ +typedef struct TLS_SESS_STATE TLS_SESS_STATE; + +struct TLS_SESS_STATE { + /* Public, read-only. */ + char *peer_CN; /* Peer Common Name */ + char *issuer_CN; /* Issuer Common Name */ + char *peer_fingerprint; /* ASCII fingerprint */ + int peer_status; /* Certificate and match status */ + const char *protocol; + const char *cipher_name; + int cipher_usebits; + int cipher_algbits; + /* Private. */ + SSL *con; + BIO *internal_bio; /* postfix/TLS side of pair */ + BIO *network_bio; /* network side of pair */ + char *cache_type; /* tlsmgr(8) cache type if enabled */ + char *serverid; /* unique server identifier */ + char *namaddr; /* nam[addr] for logging */ + int log_level; /* TLS library logging level */ + int session_reused; /* this session was reused */ + int am_server; /* Are we an SSL server or client? */ +}; + + /* + * Opaque client context handle. + */ +typedef struct TLS_APPL_STATE TLS_APPL_STATE; + + /* + * tls_client.c + */ +typedef struct { + int log_level; + int verifydepth; + const char *cache_type; + const char *cert_file; + const char *key_file; + const char *dcert_file; + const char *dkey_file; + const char *eccert_file; + const char *eckey_file; + const char *CAfile; + const char *CApath; + const char *fpt_dgst; /* Fingerprint digest algorithm */ +} TLS_CLIENT_INIT_PROPS; + +typedef struct { + TLS_APPL_STATE *ctx; + ACL_VSTREAM *stream; + int log_level; + int timeout; + int tls_level; /* Security level */ + const char *nexthop; /* destination domain */ + const char *host; /* MX hostname */ + const char *namaddr; /* nam[addr] for logging */ + const char *serverid; /* Session cache key */ + const char *protocols; /* Enabled protocols */ + const char *cipher_grade; /* Minimum cipher grade */ + const char *cipher_exclusions; /* Ciphers to exclude */ + const ACL_ARGV *matchargv; /* Cert match patterns */ + const char *fpt_dgst; /* Fingerprint digest algorithm */ +} TLS_CLIENT_START_PROPS; + +TLS_API void tls_client_init(void); +TLS_API int tls_client_setup(const TLS_CLIENT_INIT_PROPS *); +TLS_API TLS_APPL_STATE *tls_client_create(const TLS_CLIENT_INIT_PROPS *); +TLS_API TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *); + +#define tls_client_stop(ctx, stream, timeout, failure, TLScontext) \ + tls_session_stop(ctx, (stream), (timeout), (failure), (TLScontext)) + +#define TLS_CLIENT_SETUP(props, a1, a2, a3, a4, a5, a6, a7, a8, a9, \ + a10, a11, a12) \ + tls_client_setup((((props)->a1), ((props)->a2), ((props)->a3), \ + ((props)->a4), ((props)->a5), ((props)->a6), ((props)->a7), \ + ((props)->a8), ((props)->a9), ((props)->a10), ((props)->a11), \ + ((props)->a12), (props))) + +#define TLS_CLIENT_CREATE(props, a1, a2, a3, a4, a5, a6, a7, a8, a9, \ + a10, a11, a12) \ + tls_client_init((((props)->a1), ((props)->a2), ((props)->a3), \ + ((props)->a4), ((props)->a5), ((props)->a6), ((props)->a7), \ + ((props)->a8), ((props)->a9), ((props)->a10), ((props)->a11), \ + ((props)->a12), (props))) + +#define TLS_CLIENT_START(props, a1, a2, a3, a4, a5, a6, a7, a8, a9, \ + a10, a11, a12, a13, a14) \ + tls_client_start((((props)->a1), ((props)->a2), ((props)->a3), \ + ((props)->a4), ((props)->a5), ((props)->a6), ((props)->a7), \ + ((props)->a8), ((props)->a9), ((props)->a10), ((props)->a11), \ + ((props)->a12), ((props)->a13), ((props)->a14), (props))) + + /* + * tls_server.c + */ +typedef struct { + int log_level; + int verifydepth; + const char *cache_type; + long scache_timeout; + int set_sessid; + const char *cert_file; + const char *key_file; + const char *dcert_file; + const char *dkey_file; + const char *eccert_file; + const char *eckey_file; + const char *CAfile; + const char *CApath; + const char *protocols; + const char *eecdh_grade; + const char *dh1024_param_file; + const char *dh512_param_file; + int ask_ccert; + const char *fpt_dgst; /* Fingerprint digest algorithm */ +} TLS_SERVER_INIT_PROPS; + +typedef struct { + TLS_APPL_STATE *ctx; /* TLS application context */ + ACL_VSTREAM *stream; /* Client stream */ + int log_level; /* TLS log level */ + int timeout; /* TLS handshake timeout */ + int requirecert; /* Insist on client cert? */ + const char *serverid; /* Server instance (salt cache key) */ + const char *namaddr; /* Client nam[addr] for logging */ + const char *cipher_grade; + const char *cipher_exclusions; + const char *fpt_dgst; /* Fingerprint digest algorithm */ +} TLS_SERVER_START_PROPS; + +TLS_API void tls_server_init(void); +TLS_API int tls_server_setup(const TLS_SERVER_INIT_PROPS *); +TLS_API TLS_APPL_STATE *tls_server_create(const TLS_SERVER_INIT_PROPS *); +TLS_API TLS_SESS_STATE *tls_server_start(const TLS_SERVER_START_PROPS *props); + +#define tls_server_stop(ctx, stream, timeout, failure, TLScontext) \ + tls_session_stop(ctx, (stream), (timeout), (failure), (TLScontext)) + +#define TLS_SERVER_SETUP(props, a1, a2, a3, a4, a5, a6, a7, a8, a9, \ + a10, a11, a12, a13, a14, a15, a16, a17, a18, a19) \ + tls_server_setup((((props)->a1), ((props)->a2), ((props)->a3), \ + ((props)->a4), ((props)->a5), ((props)->a6), ((props)->a7), \ + ((props)->a8), ((props)->a9), ((props)->a10), ((props)->a11), \ + ((props)->a12), ((props)->a13), ((props)->a14), ((props)->a15), \ + ((props)->a16), ((props)->a17), ((props)->a18), ((props)->a19), (props))) + +#define TLS_SERVER_CREATE(props, a1, a2, a3, a4, a5, a6, a7, a8, a9, \ + a10, a11, a12, a13, a14, a15, a16, a17, a18, a19) \ + tls_server_init((((props)->a1), ((props)->a2), ((props)->a3), \ + ((props)->a4), ((props)->a5), ((props)->a6), ((props)->a7), \ + ((props)->a8), ((props)->a9), ((props)->a10), ((props)->a11), \ + ((props)->a12), ((props)->a13), ((props)->a14), ((props)->a15), \ + ((props)->a16), ((props)->a17), ((props)->a18), ((props)->a19), (props))) + +#define TLS_SERVER_START(props, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) \ + tls_server_start((((props)->a1), ((props)->a2), ((props)->a3), \ + ((props)->a4), ((props)->a5), ((props)->a6), ((props)->a7), \ + ((props)->a8), ((props)->a9), ((props)->a10), (props))) + + /* + * tls_session.c + */ +TLS_API void tls_session_stop(TLS_APPL_STATE *, ACL_VSTREAM *, int, int, TLS_SESS_STATE *); + + /* + * tls_misc.c One time finalization of application context. + */ +TLS_API void tls_free_app_context(TLS_APPL_STATE *); + + /* + * tls_params.c + */ +TLS_API void tls_params_init(void); + + /* + * tlsmgr_daemon.c + */ +TLS_API void tlsmgr_alone_start(int argc, char *argv[]); +TLS_API void tlsmgr_local_start(const char *addr); + +/* LICENSE + * .ad + * .fi + * The Secure Mailer license must be distributed with this software. + * AUTHOR(S) + * Wietse Venema + * IBM T.J. Watson Research + * P.O. Box 704 + * Yorktown Heights, NY 10598, USA + * + * Victor Duchovni + * Morgan Stanley + *--*/ + +#ifdef __cplusplus +} +#endif +#endif /* USE_TLS */ +#endif /* _TLS_H_INCLUDED_ */ diff --git a/lib_tls/include/tls_params.h b/lib_tls/include/tls_params.h new file mode 100644 index 000000000..3401e3aac --- /dev/null +++ b/lib_tls/include/tls_params.h @@ -0,0 +1,146 @@ +#ifndef _TLS_PARAMS_INCLUDED_ +#define _TLS_PARAMS_INCLUDED_ + +#include "tls.h" + +#define VAR_TLS_DAEMON_RAND_BYTES "tls_daemon_random_bytes" +#define DEF_TLS_DAEMON_RAND_BYTES 0 +/*#define DEF_TLS_DAEMON_RAND_BYTES 32*/ +extern TLS_API int var_tls_daemon_rand_bytes; + +#define VAR_SERVER_TLS_PROTO "server_tls_protocols" +#define DEF_SERVER_TLS_PROTO "" +extern TLS_API char *var_server_tls_proto; + +#define VAR_SERVER_TLS_MAND_PROTO "server_tls_mandatory_protocols" +#define DEF_SERVER_TLS_MAND_PROTO "SSLv3, TLSv1" +extern TLS_API char *var_server_tls_mand_proto; + + /* + * TLS cipherlists + */ +#define VAR_TLS_HIGH_CLIST "tls_high_cipherlist" +#define DEF_TLS_HIGH_CLIST "ALL:!EXPORT:!LOW:!MEDIUM:+RC4:@STRENGTH" +extern TLS_API char *var_tls_high_clist; + +#define VAR_TLS_MEDIUM_CLIST "tls_medium_cipherlist" +#define DEF_TLS_MEDIUM_CLIST "ALL:!EXPORT:!LOW:+RC4:@STRENGTH" +extern TLS_API char *var_tls_medium_clist; + +#define VAR_TLS_LOW_CLIST "tls_low_cipherlist" +#define DEF_TLS_LOW_CLIST "ALL:!EXPORT:+RC4:@STRENGTH" +extern TLS_API char *var_tls_low_clist; + +#define VAR_TLS_EXPORT_CLIST "tls_export_cipherlist" +#define DEF_TLS_EXPORT_CLIST "ALL:+RC4:@STRENGTH" +extern TLS_API char *var_tls_export_clist; + +#define VAR_TLS_NULL_CLIST "tls_null_cipherlist" +#define DEF_TLS_NULL_CLIST "eNULL:!aNULL" +extern TLS_API char *var_tls_null_clist; + +#define VAR_TLS_EECDH_STRONG "tls_eecdh_strong_curve" +#define DEF_TLS_EECDH_STRONG "prime256v1" +extern TLS_API char *var_tls_eecdh_strong; + +#define VAR_TLS_EECDH_ULTRA "tls_eecdh_ultra_curve" +#define DEF_TLS_EECDH_ULTRA "secp384r1" +extern TLS_API char *var_tls_eecdh_ultra; + + /* + * How long an intra-mail command may take before we assume the mail system + * is in deadlock (should never happen). + */ +#define VAR_IPC_TIMEOUT "ipc_timeout" +#define DEF_IPC_TIMEOUT 3600 +extern TLS_API int var_ipc_timeout; + + /* + * Any subsystem: default amount of time a mail subsystem keeps an internal + * IPC connection before closing it because it is idle for too much time. + */ +#define VAR_IPC_IDLE "ipc_idle" +#define DEF_IPC_IDLE 5 +extern TLS_API int var_ipc_idle_limit; + + /* + * Any subsystem: default amount of time a mail subsystem keeps an internal + * IPC connection before closing it because the connection has existed for + * too much time. + */ +#define VAR_IPC_TTL "ipc_ttl" +#define DEF_IPC_TTL 1000 +extern TLS_API int var_ipc_ttl_limit; + +/* + * Global + */ +#ifndef VAR_TLS_MGR_SERVICE +#define VAR_TLS_MGR_SERVICE +#endif +extern TLS_API char var_tlsmgr_service[256]; + +extern TLS_API int var_tlsmgr_stand_alone; + +#define VAR_TLS_RAND_SOURCE "tls_random_source" +#ifdef PREFERRED_RAND_SOURCE +#define DEF_TLS_RAND_SOURCE PREFERRED_RAND_SOURCE +#else +#define DEF_TLS_RAND_SOURCE "" +#endif +extern TLS_API char *var_tls_rand_source; + +#define VAR_TLS_RAND_EXCH_NAME "tls_random_exchange_name" +/* +#define DEF_TLS_RAND_EXCH_NAME "${data_directory}/prng_exch" +*/ +#define DEF_TLS_RAND_EXCH_NAME "" +extern TLS_API char *var_tls_rand_exch_name; + +#define VAR_SERVER_TLS_SCACHE_DB "server_tls_session_cache_database" +#define DEF_SERVER_TLS_SCACHE_DB "" +extern TLS_API char *var_server_tls_scache_db; + +#define VAR_CLIENT_TLS_SCACHE_DB "client_tls_session_cache_database" +#define DEF_CLIENT_TLS_SCACHE_DB "" +extern TLS_API char *var_client_tls_scache_db; + +#define VAR_TLS_RESEED_PERIOD "tls_random_reseed_period" +#define DEF_TLS_RESEED_PERIOD 3600 +extern TLS_API int var_tls_reseed_period; + +#define VAR_TLS_PRNG_UPD_PERIOD "tls_random_prng_update_period" +#define DEF_TLS_PRNG_UPD_PERIOD 3600 +extern TLS_API int var_tls_prng_upd_period; + +#define VAR_SERVER_TLS_SCACHTIME "server_tls_session_cache_timeout" +#define DEF_SERVER_TLS_SCACHTIME 3600 +extern TLS_API int var_server_tls_scache_timeout; + +#define VAR_CLIENT_TLS_SCACHTIME "client_tls_session_cache_timeout" +#define DEF_CLIENT_TLS_SCACHTIME 3600 +extern TLS_API int var_client_tls_scache_timeout; + +#define VAR_TLS_RAND_BYTES "tls_random_bytes" +#define DEF_TLS_RAND_BYTES 32 +extern TLS_API int var_tls_rand_bytes; + +#define VAR_SERVER_TLS_LOGLEVEL "server_tls_loglevel" +#define DEF_SERVER_TLS_LOGLEVEL 0 +extern TLS_API int var_server_tls_loglevel; + +#define VAR_CLIENT_TLS_LOGLEVEL "client_tls_loglevel" +#define DEF_CLIENT_TLS_LOGLEVEL 0 +extern TLS_API int var_client_tls_loglevel; /* In client(8) and tlsmgr(8) */ + +/* + * Attribute names. + */ +#define TLS_ATTR_STATUS "status" + + /* + * Generic triggers. + */ +#define TRIGGER_REQ_WAKEUP 'W' /* wakeup */ + +#endif diff --git a/lib_tls/lib_tls.vcproj b/lib_tls/lib_tls.vcproj new file mode 100644 index 000000000..7ca436a13 --- /dev/null +++ b/lib_tls/lib_tls.vcproj @@ -0,0 +1,408 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_tls/lib_tls.vcxproj b/lib_tls/lib_tls.vcxproj new file mode 100644 index 000000000..b35b27061 --- /dev/null +++ b/lib_tls/lib_tls.vcxproj @@ -0,0 +1,232 @@ +锘 + + + + Debug + Win32 + + + DebugDll + Win32 + + + ReleaseDll + Win32 + + + Release + Win32 + + + + {389FDE47-7F16-4DD4-B37A-27918BE745B6} + Win32Proj + + + + DynamicLibrary + MultiByte + + + DynamicLibrary + MultiByte + + + StaticLibrary + MultiByte + + + StaticLibrary + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + .\ + Debug\ + .\ + Release\ + .\ + DebugDll\ + .\ + ReleaseDll\ + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + $(ProjectName)_vc2010d + $(ProjectName)_d + $(ProjectName)_vc2010 + + + + Disabled + ..\lib_acl\include;..\lib_dict\include;.\include;.\util;.\openssl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_LIB;USE_TLS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Use + $(ProjectName)_vc2010d.pdb + Level3 + ProgramDatabase + + + $(ProjectName)_vc2010d.lib + + + copy $(TargetName).lib ..\dist\lib\win32\$(TargetName).lib /Y + + + + + ..\lib_acl\include;..\lib_dict\include;.\include;.\util;.\openssl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;USE_TLS;%(PreprocessorDefinitions) + MultiThreaded + Use + $(ProjectName)_vc2010.pdb + Level3 + ProgramDatabase + + + $(ProjectName)_vc2010.lib + + + copy $(TargetName).lib ..\dist\lib\win32\$(TargetName).lib /Y + + + + + Disabled + ..\lib_acl\include;..\lib_dict\include;.\include;.\util;.\openssl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;USE_TLS;ACL_DLL;TLS_DLL;TLS_EXPORTS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Use + Level3 + ProgramDatabase + + + libdb43.lib;libeay32.lib;ssleay32.lib;lib_dict_d.lib;lib_acl_d.lib;ws2_32.lib;%(AdditionalDependencies) + $(ProjectName)_d.dll + ..\lib\bdb;..\lib\openssl;..\lib_dict;..\lib_acl;%(AdditionalLibraryDirectories) + true + true + true + + + copy $(TargetName).lib ..\dist\lib\win32\$(TargetName).lib /Y +copy $(TargetName).dll ..\dist\lib\win32\$(TargetName).dll /Y + + + + + + ..\lib_acl\include;..\lib_dict\include;.\include;.\util;.\openssl\include;.;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;USE_TLS;ACL_DLL;TLS_DLL;TLS_EXPORTS;%(PreprocessorDefinitions) + MultiThreadedDLL + Use + Level3 + ProgramDatabase + + + libdb43.lib;libeay32.lib;ssleay32.lib;lib_dict.lib;lib_acl.lib;ws2_32.lib;%(AdditionalDependencies) + $(ProjectName).dll + ..\lib\bdb;..\lib\openssl;..\lib_dict;..\lib_acl;%(AdditionalLibraryDirectories) + + + copy $(TargetName).lib ..\dist\lib\win32\$(TargetName).lib /Y +copy $(TargetName).dll ..\dist\lib\win32\$(TargetName).dll /Y + + + + + + + Create + Create + Create + Create + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib_tls/lib_tls.vcxproj.filters b/lib_tls/lib_tls.vcxproj.filters new file mode 100644 index 000000000..b0ae5c1ff --- /dev/null +++ b/lib_tls/lib_tls.vcxproj.filters @@ -0,0 +1,183 @@ +锘 + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {272aa828-d623-44be-8dfc-08251740e386} + + + {8f22d734-7a95-41f9-946c-98681d2410e7} + + + {fd7b1d7e-a846-4adb-8a43-3a6d7d67c555} + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx + + + + + 婧愭枃浠 + + + 婧愭枃浠 + + + 婧愭枃浠禱attr + + + 婧愭枃浠禱attr + + + 婧愭枃浠禱attr + + + 婧愭枃浠禱attr + + + 婧愭枃浠禱attr + + + 婧愭枃浠禱attr + + + 婧愭枃浠禱attr + + + 婧愭枃浠禱attr + + + 婧愭枃浠禱util + + + 婧愭枃浠禱util + + + 婧愭枃浠禱util + + + 婧愭枃浠禱util + + + 婧愭枃浠禱tls + + + 婧愭枃浠禱tls + + + 婧愭枃浠禱tls + + + 婧愭枃浠禱tls + + + 婧愭枃浠禱tls + + + 婧愭枃浠禱tls + + + 婧愭枃浠禱tls + + + 婧愭枃浠禱tls + + + 婧愭枃浠禱tls + + + 婧愭枃浠禱tls + + + 婧愭枃浠禱tls + + + 婧愭枃浠禱tls + + + 婧愭枃浠禱tls + + + 婧愭枃浠禱tls + + + 婧愭枃浠禱tls + + + 婧愭枃浠禱tls + + + 婧愭枃浠禱tls + + + 婧愭枃浠禱tls + + + 婧愭枃浠禱tls + + + 婧愭枃浠禱tls + + + 婧愭枃浠禱tls + + + + + 婧愭枃浠 + + + 婧愭枃浠禱attr + + + 婧愭枃浠禱attr + + + 婧愭枃浠禱attr + + + 婧愭枃浠禱util + + + 婧愭枃浠禱util + + + 婧愭枃浠禱util + + + 婧愭枃浠禱tls + + + 婧愭枃浠禱tls + + + 婧愭枃浠禱tls + + + 婧愭枃浠禱tls + + + 澶存枃浠 + + + 澶存枃浠 + + + 澶存枃浠 + + + 澶存枃浠 + + + + + + diff --git a/lib_tls/snprintf.c b/lib_tls/snprintf.c new file mode 100644 index 000000000..2b067b5b8 --- /dev/null +++ b/lib_tls/snprintf.c @@ -0,0 +1,24 @@ +#include "StdAfx.h" +#ifdef __STDC_WANT_SECURE_LIB__ +#include + +int tls_secure_snprintf(char *buf, size_t size, const char *fmt, ...) +{ + va_list ap; + int ret; + + va_start(ap, fmt); + ret = _vsnprintf_s(buf, size, size, fmt, ap); + va_end(ap); + return (ret); +} + +int tls_secure_vsnprintf(char *buf, size_t size, const char *fmt, va_list ap) +{ + int ret; + + ret = _vsnprintf_s(buf, size, size, fmt, ap); + return (ret); +} + +#endif diff --git a/lib_tls/tls/tls_bio_ops.c b/lib_tls/tls/tls_bio_ops.c new file mode 100644 index 000000000..217ddb0c3 --- /dev/null +++ b/lib_tls/tls/tls_bio_ops.c @@ -0,0 +1,350 @@ +/*++ + * NAME + * tls_bio_ops 3 + * SUMMARY + * TLS network BIO management + * SYNOPSIS + * #include + * #include + * + * int tls_bio_connect(fd, timeout, context) + * int fd; + * int timeout; + * TLS_SESS_STATE *context; + * + * int tls_bio_accept(fd, timeout, context) + * int fd; + * int timeout; + * TLS_SESS_STATE *context; + * + * int tls_bio_shutdown(fd, timeout, context) + * int fd; + * int timeout; + * TLS_SESS_STATE *context; + * + * int tls_bio_read(fd, buf, len, timeout, context) + * int fd; + * void *buf; + * int len; + * int timeout; + * TLS_SESS_STATE *context; + * + * int tls_bio_write(fd, buf, len, timeout, context) + * int fd; + * void *buf; + * int len; + * int timeout; + * TLS_SESS_STATE *context; + * DESCRIPTION + * This layer synchronizes the TLS network buffers with the network + * while performing TLS handshake or input/output operations. + * + * When the TLS layer is active, it converts plain-text + * data from Postfix into encrypted network data and vice versa. + * However, to handle network timeout conditions, Postfix + * needs to maintain control over network input/output. This + * rules out the usual approach of placing the TLS layer + * between the application and the network socket. + * + * As shown below, Postfix reads/writes plain-text data from/to + * the TLS layer. The TLS layer informs Postfix when it needs + * to read/write encrypted data from/to the network; Postfix + * then reads/writes encrypted data from/to the TLS layer and + * takes care of the network socket I/O. + * + * The TLS layer to network interface is realized with a BIO pair: + * + * Postfix | TLS layer + * | + * smtp/smtpd | + * /\ || | + * || \/ | + * vstream read/write <===> TLS read/write/etc + * | /\ || + * | || \/ + * | BIO pair (internal_bio) + * | BIO pair (network_bio) + * | /\ || + * | || \/ + * socket read/write <===> BIO read/write + * /\ || | + * || \/ | + * network | + * + * The Postfix VSTREAM read/write operations invoke the SSL + * read/write operations to send and retrieve plain-text data. Inside + * the TLS layer the data are converted to/from TLS protocol. + * + * Whenever an SSL operation reports success, or whenever it + * indicates that network input/output needs to happen, Postfix + * uses the BIO read/write routines to synchronize the + * network_bio buffer with the network. Writing data to the + * network has precedence over reading from the network. This + * is necessary to avoid deadlock. + * + * The BIO pair buffer size is set to 8192 bytes. This is much + * larger than the typical Path MTU, and avoids sending tiny TCP + * segments. It is also larger than the default VSTREAM_BUFSIZE + * (4096, see vstream.h), so that large write operations can + * be handled within one request. The internal buffer in the + * network/network_bio handling layer is set to the same + * value, since this seems to be reasonable. The code is + * however able to handle arbitrary values smaller or larger + * than the buffer size in the BIO pair. + * + * tls_bio_connect() performs the SSL_connect() operation while + * synchronizing the network_bio buffer with the network. + * + * tls_bio_accept() performs the SSL_accept() operation while + * synchronizing the network_bio buffer with the network. + * + * tls_bio_shutdown() performs the SSL_shutdown() operation while + * synchronizing the network_bio buffer with the network. + * + * tls_bio_read() performs the SSL_read() operation while + * synchronizing the network_bio buffer with the network. + * + * tls_bio_write() performs the SSL_write() operation while + * synchronizing the network_bio buffer with the network. + * + * Arguments: + * .IP fd + * Network socket. + * .IP buf + * Read/write buffer. + * .IP len + * Read/write request size. + * .IP timeout + * Read/write timeout. + * .IP TLScontext + * TLS session state. + * DIAGNOSTICS + * The result value is -1 in case of a network read/write + * error, otherwise it is the result value of the TLS operation. + * LICENSE + * .ad + * .fi + * This software is free. You can do with it whatever you want. + * The original author kindly requests that you acknowledge + * the use of his software. + * AUTHOR(S) + * Originally written by: + * Lutz Jaenicke + * BTU Cottbus + * Allgemeine Elektrotechnik + * Universitaetsplatz 3-4 + * D-03044 Cottbus, Germany + * + * Updated by: + * Wietse Venema + * IBM T.J. Watson Research + * P.O. Box 704 + * Yorktown Heights, NY 10598, USA + * + * Victor Duchovni + * Morgan Stanley + *--*/ + +/* System library. */ + +#include "StdAfx.h" + +#ifdef USE_TLS + +/* TLS library. */ + +#include "tls.h" +#include "tls_private.h" + +/* Application-specific. */ + +#define NETLAYER_BUFFERSIZE 8192 + +/* network_biopair_interop - synchronize network with BIO pair */ + +static int network_biopair_interop(ACL_SOCKET fd, int timeout, BIO *network_bio) +{ + const char *myname = "network_biopair_interop"; + int want_write; + int num_write; + int write_pos; + int from_bio; + int want_read; + int num_read; + int to_bio; + char buffer[NETLAYER_BUFFERSIZE]; + + /* + * To avoid deadlock, write all pending data to the network before + * attempting to read from the network. + */ + while ((want_write = (int) BIO_ctrl_pending(network_bio)) > 0) { + if (want_write > (int) sizeof(buffer)) + want_write = (int) sizeof(buffer); + from_bio = BIO_read(network_bio, buffer, want_write); + + /* + * Write the complete buffer contents to the network. + */ + for (write_pos = 0; write_pos < from_bio; /* see below */ ) { + if (timeout > 0 && acl_write_wait(fd, timeout) < 0) + return (-1); + num_write = acl_socket_write(fd, buffer + write_pos, from_bio - write_pos, 0, 0); + if (num_write <= 0) { + if ((num_write < 0) && (timeout > 0) && (errno == ACL_EAGAIN || errno == ACL_EINTR)) { + acl_msg_warn("%s: write() returns EAGAIN on a writable file descriptor!", myname); + acl_msg_warn("%s: pausing to avoid going into a tight select/write loop!", myname); + sleep(1); + } else { + acl_msg_warn("%s: error writing %d bytes to the network: %s", + myname, from_bio - write_pos, acl_last_serror()); + return (-1); + } + } else { + write_pos += num_write; + } + } + } + + /* + * Read data from the network into the BIO pair. + */ + while ((want_read = (int) BIO_ctrl_get_read_request(network_bio)) > 0) { + if (want_read > (int) sizeof(buffer)) + want_read = (int) sizeof(buffer); + if (timeout > 0 && acl_read_wait(fd, timeout) < 0) + return (-1); + num_read = acl_socket_read(fd, buffer, want_read, 0, 0); + if (num_read == 0) + /* FIX 200412 Cannot return a zero read count. */ + return (-1); + if (num_read < 0) { + if ((num_read < 0) && (timeout > 0) && (errno == ACL_EAGAIN || errno == ACL_EINTR)) { + acl_msg_warn("%s: read() returns EAGAIN on a readable file descriptor!", myname); + acl_msg_warn("%s: pausing to avoid going into a tight select/write loop!", myname); + sleep(1); + } else { + acl_msg_warn("%s: error reading %d bytes from the network: %s", + myname, want_read, acl_last_serror()); + return (-1); + } + } else { + to_bio = BIO_write(network_bio, buffer, num_read); + if (to_bio != num_read) + acl_msg_panic("%s: BIO_write error: to_bio != num_read", myname); + } + } + return (0); +} + +/* tls_bio - perform SSL input/output operation with extreme prejudice */ + +int tls_bio(ACL_SOCKET fd, int timeout, TLS_SESS_STATE *TLScontext, + int (*hsfunc) (SSL *), + int (*rfunc) (SSL *, void *, int), + int (*wfunc) (SSL *, const void *, int), + void *buf, int num) +{ + const char *myname = "tls_bio"; + int status = 0; + int err; + int retval = 0; + int biop_retval; + int done; + + /* + * If necessary, retry the SSL handshake or read/write operation after + * handling any pending network I/O. + */ + for (done = 0; done == 0; /* void */ ) { + if (hsfunc) { +#if 1 + status = hsfunc(TLScontext->con); +#else + status = SSL_do_handshake(TLScontext->con); +#endif + } else if (rfunc) + status = rfunc(TLScontext->con, buf, num); + else if (wfunc) + status = wfunc(TLScontext->con, buf, num); + else + acl_msg_panic("%s: nothing to do here", myname); + err = SSL_get_error(TLScontext->con, status); + +#if (OPENSSL_VERSION_NUMBER <= 0x0090581fL) + + /* + * There is a bug up to and including OpenSSL-0.9.5a: if an error + * occurs while checking the peers certificate due to some + * certificate error (e.g. as happend with a RSA-padding error), the + * error is put onto the error stack. If verification is not + * enforced, this error should be ignored, but the error-queue is not + * cleared, so we can find this error here. The bug has been fixed on + * May 28, 2000. + * + * This bug so far has only manifested as 4800:error:0407006A:rsa + * routines:RSA_padding_check_PKCS1_type_1:block type is not + * 01:rsa_pk1.c:100: 4800:error:04067072:rsa + * routines:RSA_EAY_PUBLIC_DECRYPT:padding check + * failed:rsa_eay.c:396: 4800:error:0D079006:asn1 encoding + * routines:ASN1_verify:bad get asn1 object call:a_verify.c:109: so + * that we specifically test for this error. We print the errors to + * the logfile and automatically clear the error queue. Then we retry + * to get another error code. We cannot do better, since we can only + * retrieve the last entry of the error-queue without actually + * cleaning it on the way. + * + * This workaround is secure, as verify_result is set to "failed" + * anyway. + */ + if (err == SSL_ERROR_SSL) { + if (ERR_peek_error() == 0x0407006AL) { + tls_print_errors(); + acl_msg_info("OpenSSL <= 0.9.5a workaround called: certificate errors ignored"); + err = SSL_get_error(TLScontext->con, status); + } + } +#endif + + /* + * Find out if we must retry the operation and/or if there is pending + * network I/O. + * + * XXX If we're the first to invoke SSL_shutdown(), then the operation + * isn't really complete when the call returns. We could hide that + * anomaly here and repeat the call. + */ + switch (err) { + case SSL_ERROR_NONE: /* success */ + retval = status; + done = 1; + /* FALLTHROUGH */ + case SSL_ERROR_WANT_WRITE: /* flush/update buffers */ + case SSL_ERROR_WANT_READ: + biop_retval = network_biopair_interop(fd, timeout, TLScontext->network_bio); + if (biop_retval < 0) + return (-1); /* network read/write error */ + break; + + /* + * With tls_timed_read() and tls_timed_write() the caller is the + * VSTREAM library module which is unaware of TLS, so we log the + * TLS error stack here. In a better world, each VSTREAM I/O + * object would provide an error reporting method in addition to + * the timed_read and timed_write methods, so that we would not + * need to have ad-hoc code like this. + */ + case SSL_ERROR_SSL: + if (rfunc || wfunc) + tls_print_errors(); + /* FALLTHROUGH */ + default: + retval = status; + done = 1; + break; + } + } + return (retval); +} + +#endif diff --git a/lib_tls/tls/tls_certkey.c b/lib_tls/tls/tls_certkey.c new file mode 100644 index 000000000..b40a8c4c0 --- /dev/null +++ b/lib_tls/tls/tls_certkey.c @@ -0,0 +1,166 @@ +/*++ + * NAME + * tls_certkey 3 + * SUMMARY + * public key certificate and private key loader + * SYNOPSIS + * #include + * #include + * + * int tls_set_ca_certificate_info(ctx, CAfile, CApath) + * SSL_CTX *ctx; + * const char *CAfile; + * const char *CApath; + * + * int tls_set_my_certificate_key_info(ctx, cert_file, key_file, + * dcert_file, dkey_file, + * eccert_file, eckey_file) + * SSL_CTX *ctx; + * const char *cert_file; + * const char *key_file; + * const char *dcert_file; + * const char *dkey_file; + * const char *eccert_file; + * const char *eckey_file; + * DESCRIPTION + * OpenSSL supports two options to specify CA certificates: + * either one file CAfile that contains all CA certificates, + * or a directory CApath with separate files for each + * individual CA, with symbolic links named after the hash + * values of the certificates. The second option is not + * convenient with a chrooted process. + * + * tls_set_ca_certificate_info() loads the CA certificate + * information for the specified TLS server or client context. + * The result is -1 on failure, 0 on success. + * + * tls_set_my_certificate_key_info() loads the public key + * certificates and private keys for the specified TLS server + * or client context. Up to 3 pairs of key pairs (RSA, DSA and + * ECDSA) may be specified; each certificate and key pair must + * match. The result is -1 on failure, 0 on success. + * LICENSE + * .ad + * .fi + * This software is free. You can do with it whatever you want. + * The original author kindly requests that you acknowledge + * the use of his software. + * AUTHOR(S) + * Originally written by: + * Lutz Jaenicke + * BTU Cottbus + * Allgemeine Elektrotechnik + * Universitaetsplatz 3-4 + * D-03044 Cottbus, Germany + * + * Updated by: + * Wietse Venema + * IBM T.J. Watson Research + * P.O. Box 704 + * Yorktown Heights, NY 10598, USA + *--*/ + +#include "StdAfx.h" + +#ifdef USE_TLS + +/* TLS library. */ + +#include "tls.h" +#include "tls_private.h" + +/* tls_set_ca_certificate_info - load certificate authority certificates */ + +int tls_set_ca_certificate_info(SSL_CTX *ctx, const char *CAfile, const char *CApath) +{ + if (*CAfile == 0) + CAfile = 0; + if (*CApath == 0) + CApath = 0; + if (CAfile || CApath) { + if (!SSL_CTX_load_verify_locations(ctx, CAfile, CApath)) { + acl_msg_info("cannot load Certificate Authority data: " + "disabling TLS support"); + tls_print_errors(); + return (-1); + } + if (!SSL_CTX_set_default_verify_paths(ctx)) { + acl_msg_info("cannot set certificate verification paths: " + "disabling TLS support"); + tls_print_errors(); + return (-1); + } + } + return (0); +} + +/* set_cert_stuff - specify certificate and key information */ + +static int set_cert_stuff(SSL_CTX *ctx, const char *cert_type, + const char *cert_file, const char *key_file) +{ + const char *myname = "set_cert_stuff"; + + /* + * We need both the private key (in key_file) and the public key + * certificate (in cert_file). Both may specify the same file. + * + * Code adapted from OpenSSL apps/s_cb.c. + */ + ERR_clear_error(); + if (SSL_CTX_use_certificate_chain_file(ctx, cert_file) <= 0) { + acl_msg_warn("%s: cannot get %s certificate from file %s: " + "disabling TLS support", myname, cert_type, cert_file); + tls_print_errors(); + return (0); + } + if (SSL_CTX_use_PrivateKey_file(ctx, key_file, SSL_FILETYPE_PEM) <= 0) { + acl_msg_warn("%s: cannot get %s private key from file %s: " + "disabling TLS support", myname, cert_type, key_file); + tls_print_errors(); + return (0); + } + + /* + * Sanity check. + */ + if (!SSL_CTX_check_private_key(ctx)) { + acl_msg_warn("%s: %s private key in %s does not match public key in %s: " + "disabling TLS support", myname, cert_type, key_file, cert_file); + return (0); + } + return (1); +} + +/* tls_set_my_certificate_key_info - load client or server certificates/keys */ + +int tls_set_my_certificate_key_info(SSL_CTX *ctx, + const char *cert_file, + const char *key_file, + const char *dcert_file, + const char *dkey_file, + const char *eccert_file, + const char *eckey_file acl_unused) +{ + const char *myname = "tls_set_my_certificate_key_info"; + + /* + * Lack of certificates is fine so long as we are prepared to use + * anonymous ciphers. + */ + if (cert_file && *cert_file && !set_cert_stuff(ctx, "RSA", cert_file, key_file)) + return (-1); /* logged */ + if (dcert_file && *dcert_file && !set_cert_stuff(ctx, "DSA", dcert_file, dkey_file)) + return (-1); /* logged */ +#if OPENSSL_VERSION_NUMBER >= 0x00909000 && !defined(OPENSSL_NO_ECDH) + if (eccert_file && *eccert_file && !set_cert_stuff(ctx, "ECDSA", eccert_file, eckey_file)) + return (-1); /* logged */ +#else + if (eccert_file && *eccert_file) + acl_msg_warn("%s: ECDSA not supported. Ignoring ECDSA certificate file \"%s\"", + myname, eccert_file); +#endif + return (0); +} + +#endif diff --git a/lib_tls/tls/tls_client.c b/lib_tls/tls/tls_client.c new file mode 100644 index 000000000..7579c29ea --- /dev/null +++ b/lib_tls/tls/tls_client.c @@ -0,0 +1,984 @@ +/*++ + * NAME + * tls_client + * SUMMARY + * client-side TLS engine + * SYNOPSIS + * #include + * + * TLS_APPL_STATE *tls_client_init(init_props) + * const TLS_CLIENT_INIT_PROPS *init_props; + * + * TLS_SESS_STATE *tls_client_start(start_props) + * const TLS_CLIENT_START_PROPS *start_props; + * + * void tls_client_stop(app_ctx, stream, failure, TLScontext) + * TLS_APPL_STATE *app_ctx; + * VSTREAM *stream; + * int failure; + * TLS_SESS_STATE *TLScontext; + * DESCRIPTION + * This module is the interface between Postfix TLS clients, + * the OpenSSL library and the TLS entropy and cache manager. + * + * The SMTP client will attempt to verify the server hostname + * against the names listed in the server certificate. When + * a hostname match is required, the verification fails + * on certificate verification or hostname mis-match errors. + * When no hostname match is required, hostname verification + * failures are logged but they do not affect the TLS handshake + * or the SMTP session. + * + * The rules for peer name wild-card matching differ between + * RFC 2818 (HTTP over TLS) and RFC 2830 (LDAP over TLS), while + * RFC RFC3207 (SMTP over TLS) does not specify a rule at all. + * Postfix uses a restrictive match algorithm. One asterisk + * ('*') is allowed as the left-most component of a wild-card + * certificate name; it matches the left-most component of + * the peer hostname. + * + * Another area where RFCs aren't always explicit is the + * handling of dNSNames in peer certificates. RFC 3207 (SMTP + * over TLS) does not mention dNSNames. Postfix follows the + * strict rules in RFC 2818 (HTTP over TLS), section 3.1: The + * Subject Alternative Name/dNSName has precedence over + * CommonName. If at least one dNSName is provided, Postfix + * verifies those against the peer hostname and ignores the + * CommonName, otherwise Postfix verifies the CommonName + * against the peer hostname. + * + * tls_client_init() is called once when the SMTP client + * initializes. + * Certificate details are also decided during this phase, + * so peer-specific certificate selection is not possible. + * + * tls_client_start() activates the TLS session over an established + * stream. We expect that network buffers are flushed and + * the TLS handshake can begin immediately. + * + * tls_client_stop() sends the "close notify" alert via + * SSL_shutdown() to the peer and resets all connection specific + * TLS data. As RFC2487 does not specify a separate shutdown, it + * is assumed that the underlying TCP connection is shut down + * immediately afterwards. Any further writes to the channel will + * be discarded, and any further reads will report end-of-file. + * If the failure flag is set, no SSL_shutdown() handshake is performed. + * + * Once the TLS connection is initiated, information about the TLS + * state is available via the TLScontext structure: + * .IP TLScontext->protocol + * the protocol name (SSLv2, SSLv3, TLSv1), + * .IP TLScontext->cipher_name + * the cipher name (e.g. RC4/MD5), + * .IP TLScontext->cipher_usebits + * the number of bits actually used (e.g. 40), + * .IP TLScontext->cipher_algbits + * the number of bits the algorithm is based on (e.g. 128). + * .PP + * The last two values may differ from each other when export-strength + * encryption is used. + * + * If the peer offered a certificate, part of the certificate data are + * available as: + * .IP TLScontext->peer_status + * A bitmask field that records the status of the peer certificate + * verification. This consists of one or more of + * TLS_CERT_FLAG_PRESENT, TLS_CERT_FLAG_ALTNAME, TLS_CERT_FLAG_TRUSTED + * and TLS_CERT_FLAG_MATCHED. + * .IP TLScontext->peer_CN + * Extracted CommonName of the peer, or zero-length string if the + * information could not be extracted. + * .IP TLScontext->issuer_CN + * Extracted CommonName of the issuer, or zero-length string if the + * information could not be extracted. + * .IP TLScontext->peer_fingerprint + * At the fingerprint security level, if the peer presented a certificate + * the fingerprint of the certificate. + * .PP + * If no peer certificate is presented the peer_status is set to 0. + * LICENSE + * .ad + * .fi + * This software is free. You can do with it whatever you want. + * The original author kindly requests that you acknowledge + * the use of his software. + * AUTHOR(S) + * Originally written by: + * Lutz Jaenicke + * BTU Cottbus + * Allgemeine Elektrotechnik + * Universitaetsplatz 3-4 + * D-03044 Cottbus, Germany + * + * Updated by: + * Wietse Venema + * IBM T.J. Watson Research + * P.O. Box 704 + * Yorktown Heights, NY 10598, USA + * + * Victor Duchovni + * Morgan Stanley + *--*/ + +#include "StdAfx.h" + +#ifdef USE_TLS +#include + +#ifdef STRCASECMP_IN_STRINGS_H +#include +#endif + +/* Global library. */ + +#include "tls_params.h" + +/* TLS library. */ + +#include "tls_mgr.h" +#include "tls.h" +#include "tls_private.h" + +/* Application-specific. */ + +#define STR acl_vstring_str +#define LEN ACL_VSTRING_LEN + +/* load_clnt_session - load session from client cache (non-callback) */ + +static SSL_SESSION *load_clnt_session(TLS_SESS_STATE *TLScontext) +{ + const char *myname = "load_clnt_session"; + SSL_SESSION *session = 0; + ACL_VSTRING *session_data = acl_vstring_alloc(2048); + + /* + * Prepare the query. + */ + if (TLScontext->log_level >= 2) + acl_msg_info("looking for session %s in %s cache", + TLScontext->serverid, TLScontext->cache_type); + + /* + * We only get here if the cache_type is not empty. This code is not + * called unless caching is enabled and the cache_type is stored in the + * server SSL context. + */ + if (TLScontext->cache_type == 0) + acl_msg_panic("%s: null client session cache type in session lookup", myname); + + /* + * Look up and activate the SSL_SESSION object. Errors are non-fatal, + * since caching is only an optimization. + */ + if (tls_mgr_lookup(TLScontext->cache_type, TLScontext->serverid, + session_data) == TLS_MGR_STAT_OK) { + session = tls_session_activate(STR(session_data), (int) LEN(session_data)); + if (session) { + if (TLScontext->log_level >= 2) + acl_msg_info("reloaded session %s from %s cache", + TLScontext->serverid, TLScontext->cache_type); + } + } + + /* + * Clean up. + */ + acl_vstring_free(session_data); + + return (session); +} + +/* new_client_session_cb - name new session and save it to client cache */ + +static int new_client_session_cb(SSL *ssl, SSL_SESSION *session) +{ + const char *myname = "new_client_session_cb"; + TLS_SESS_STATE *TLScontext; + ACL_VSTRING *session_data; + + /* + * The cache name (if caching is enabled in tlsmgr(8)) and the cache ID + * string for this session are stored in the TLScontext. It cannot be + * null at this point. + */ + if ((TLScontext = SSL_get_ex_data(ssl, TLScontext_index)) == 0) + acl_msg_panic("%s: null TLScontext in new session callback", myname); + + /* + * We only get here if the cache_type is not empty. This callback is not + * set unless caching is enabled and the cache_type is stored in the + * server SSL context. + */ + if (TLScontext->cache_type == 0) + acl_msg_panic("%s: null session cache type in new session callback", myname); + + if (TLScontext->log_level >= 2) + acl_msg_info("save session %s to %s cache", TLScontext->serverid, TLScontext->cache_type); + +#if (OPENSSL_VERSION_NUMBER < 0x00906011L) || (OPENSSL_VERSION_NUMBER == 0x00907000L) + + /* + * Ugly Hack: OpenSSL before 0.9.6a does not store the verify result in + * sessions for the client side. We modify the session directly which is + * version specific, but this bug is version specific, too. + * + * READ: 0-09-06-01-1 = 0-9-6-a-beta1: all versions before beta1 have this + * bug, it has been fixed during development of 0.9.6a. The development + * version of 0.9.7 can have this bug, too. It has been fixed on + * 2000/11/29. + */ + session->verify_result = SSL_get_verify_result(TLScontext->con); +#endif + + /* + * Passivate and save the session object. Errors are non-fatal, since + * caching is only an optimization. + */ + if ((session_data = tls_session_passivate(session)) != 0) { + tls_mgr_update(TLScontext->cache_type, TLScontext->serverid, + STR(session_data), (int) LEN(session_data)); + acl_vstring_free(session_data); + } + + /* + * Clean up. + */ + SSL_SESSION_free(session); /* 200502 */ + + return (1); +} + +/* uncache_session - remove session from the external cache */ + +static void uncache_session(SSL_CTX *ctx, TLS_SESS_STATE *TLScontext) +{ + SSL_SESSION *session = SSL_get_session(TLScontext->con); + + SSL_CTX_remove_session(ctx, session); + if (TLScontext->cache_type == 0 || TLScontext->serverid == 0) + return; + + if (TLScontext->log_level >= 2) + acl_msg_info("remove session %s from client cache", TLScontext->serverid); + + tls_mgr_delete(TLScontext->cache_type, TLScontext->serverid); +} + +/* tls_client_init - initialize client-side TLS engine */ + +void tls_client_init() +{ + tls_params_init(); + tls_threads_init(); +} + +/* tls_client_setup - setup client-side TLS engine */ + +int tls_client_setup(const TLS_CLIENT_INIT_PROPS *props) +{ + const char *myname = "tls_client_init"; + const EVP_MD *md_alg; + unsigned int md_len; + static int init_done = 0; + + if (init_done) { + acl_msg_warn("%s(%d): called once before", myname, __LINE__); + return (0); + } + + if (props->log_level >= 2) + acl_msg_info("%s: initializing the client-side TLS engine", myname); + + /* + * Detect mismatch between compile-time headers and run-time library. + */ + tls_check_version(); + + /* + * Initialize the OpenSSL library by the book! To start with, we must + * initialize the algorithms. We want cleartext error messages instead of + * just error codes, so we load the error_strings. + */ + SSL_load_error_strings(); + OpenSSL_add_ssl_algorithms(); + + /* + * Create an application data index for SSL objects, so that we can + * attach TLScontext information; this information is needed inside + * tls_verify_certificate_callback(). + */ + if (TLScontext_index < 0) { + if ((TLScontext_index = SSL_get_ex_new_index(0, 0, 0, 0, 0)) < 0) { + acl_msg_warn("%s(%d): Cannot allocate SSL application data index: " + "disabling TLS support", myname, __LINE__); + return (-1); + } + } + + /* + * If the administrator specifies an unsupported digest algorithm, fail + * now, rather than in the middle of a TLS handshake. + */ + if ((md_alg = EVP_get_digestbyname(props->fpt_dgst)) == 0) { + acl_msg_warn("%s(%d): Digest algorithm \"%s\" not found: disabling TLS support", + myname, __LINE__, props->fpt_dgst); + return (-1); + } + + /* + * Sanity check: Newer shared libraries may use larger digests. + */ + if ((md_len = EVP_MD_size(md_alg)) > EVP_MAX_MD_SIZE) { + acl_msg_warn("%s(%d): Digest algorithm \"%s\" output size %u too large:" + " disabling TLS support", myname, __LINE__, props->fpt_dgst, md_len); + return (-1); + } + + /* + * Initialize the PRNG (Pseudo Random Number Generator) with some seed + * from external and internal sources. Don't enable TLS without some real + * entropy. + */ + if (var_tls_daemon_rand_bytes > 0 && tls_ext_seed(var_tls_daemon_rand_bytes) < 0) { + acl_msg_warn("%s(%d): no entropy for TLS key generation: disabling TLS support", + myname, __LINE__); + return (-1); + } + tls_int_seed(); + + return (0); +} + +/* tls_client_create - create client-side connection */ + +TLS_APPL_STATE *tls_client_create(const TLS_CLIENT_INIT_PROPS *props) +{ + const char *myname = "tls_client_create"; + long off = 0; + int cachable; + SSL_CTX *client_ctx; + TLS_APPL_STATE *app_ctx; + + /* + * The SSL/TLS specifications require the client to send a message in the + * oldest specification it understands with the highest level it + * understands in the message. RFC2487 is only specified for TLSv1, but + * we want to be as compatible as possible, so we will start off with a + * SSLv2 greeting allowing the best we can offer: TLSv1. We can restrict + * this with the options setting later, anyhow. + */ + ERR_clear_error(); + if ((client_ctx = SSL_CTX_new(SSLv23_client_method())) == 0) { + acl_msg_warn("%s: cannot allocate client SSL_CTX: disabling TLS support", myname); + tls_print_errors(); + return (0); + } + + /* + * See the verify callback in tls_verify.c + */ + SSL_CTX_set_verify_depth(client_ctx, props->verifydepth + 1); + + /* + * Protocol selection is destination dependent, so we delay the protocol + * selection options to the per-session SSL object. + */ + off |= tls_bug_bits(); + SSL_CTX_set_options(client_ctx, off); + + /* + * Set the call-back routine for verbose logging. + */ + if (props->log_level >= 2) + SSL_CTX_set_info_callback(client_ctx, tls_info_callback); + + /* + * Load the CA public key certificates for both the client cert and for + * the verification of server certificates. As provided by OpenSSL we + * support two types of CA certificate handling: One possibility is to + * add all CA certificates to one large CAfile, the other possibility is + * a directory pointed to by CApath, containing separate files for each + * CA with softlinks named after the hash values of the certificate. The + * first alternative has the advantage that the file is opened and read + * at startup time, so that you don't have the hassle to maintain another + * copy of the CApath directory for chroot-jail. + */ + if (tls_set_ca_certificate_info(client_ctx, props->CAfile, props->CApath) < 0) { + /* tls_set_ca_certificate_info() already logs a warning. */ + SSL_CTX_free(client_ctx); /* 200411 */ + return (0); + } + + /* + * We do not need a client certificate, so the certificates are only + * loaded (and checked) if supplied. A clever client would handle + * multiple client certificates and decide based on the list of + * acceptable CAs, sent by the server, which certificate to submit. + * OpenSSL does however not do this and also has no call-back hooks to + * easily implement it. + * + * Load the client public key certificate and private key from file and + * check whether the cert matches the key. We can use RSA certificates + * ("cert") DSA certificates ("dcert") or ECDSA certificates ("eccert"). + * All three can be made available at the same time. The CA certificates + * for all three are handled in the same setup already finished. Which + * one is used depends on the cipher negotiated (that is: the first + * cipher listed by the client which does match the server). The client + * certificate is presented after the server chooses the session cipher, + * so we will just present the right cert for the chosen cipher (if it + * uses certificates). + */ + if (tls_set_my_certificate_key_info(client_ctx, + props->cert_file, + props->key_file, + props->dcert_file, + props->dkey_file, + props->eccert_file, + props->eckey_file) < 0) { + /* tls_set_my_certificate_key_info() already logs a warning. */ + SSL_CTX_free(client_ctx); /* 200411 */ + return (0); + } + + /* + * According to the OpenSSL documentation, temporary RSA key is needed + * export ciphers are in use. We have to provide one, so well, we just do + * it. + */ + SSL_CTX_set_tmp_rsa_callback(client_ctx, tls_tmp_rsa_cb); + + /* + * Finally, the setup for the server certificate checking, done "by the + * book". + */ + SSL_CTX_set_verify(client_ctx, SSL_VERIFY_NONE, tls_verify_certificate_callback); + + /* + * Initialize the session cache. + * + * Since the client does not search an internal cache, we simply disable it. + * It is only useful for expiring old sessions, but we do that in the + * tlsmgr(8). + * + * This makes SSL_CTX_remove_session() not useful for flushing broken + * sessions from the external cache, so we must delete them directly (not + * via a callback). + */ + if (props->cache_type == 0 || tls_mgr_policy(props->cache_type, &cachable) != TLS_MGR_STAT_OK) + cachable = 0; + + /* + * Allocate an application context, and populate with mandatory protocol + * and cipher data. + */ + app_ctx = tls_alloc_app_context(client_ctx); + + /* + * The external session cache is implemented by the tlsmgr(8) process. + */ + if (cachable) { + + app_ctx->cache_type = acl_mystrdup(props->cache_type); + + /* + * OpenSSL does not use callbacks to load sessions from a client + * cache, so we must invoke that function directly. Apparently, + * OpenSSL does not provide a way to pass session names from here to + * call-back routines that do session lookup. + * + * OpenSSL can, however, automatically save newly created sessions for + * us by callback (we create the session name in the call-back + * function). + * + * XXX gcc 2.95 can't compile #ifdef .. #endif in the expansion of + * SSL_SESS_CACHE_CLIENT | SSL_SESS_CACHE_NO_INTERNAL_STORE | + * SSL_SESS_CACHE_NO_AUTO_CLEAR. + */ +#ifndef SSL_SESS_CACHE_NO_INTERNAL_STORE +#define SSL_SESS_CACHE_NO_INTERNAL_STORE 0 +#endif + + SSL_CTX_set_session_cache_mode(client_ctx, + SSL_SESS_CACHE_CLIENT | + SSL_SESS_CACHE_NO_AUTO_CLEAR | + SSL_SESS_CACHE_NO_INTERNAL_STORE); + SSL_CTX_sess_set_new_cb(client_ctx, new_client_session_cb); + } + return (app_ctx); +} + +/* match_hostname - match hostname against pattern */ + +static int match_hostname(const char *peerid, const TLS_CLIENT_START_PROPS *props) +{ + const ACL_ARGV *cmatch_argv = props->matchargv; + const char *nexthop = props->nexthop; + const char *hname = props->host; + const char *pattern; + const char *pattern_left; + int sub; + int i; + int idlen; + int patlen; + + /* + * Match the peerid against each pattern until we find a match. + */ + for (i = 0; i < cmatch_argv->argc; ++i) { + sub = 0; + if (!strcasecmp(cmatch_argv->argv[i], "nexthop")) + pattern = nexthop; + else if (!strcasecmp(cmatch_argv->argv[i], "hostname")) + pattern = hname; + else if (!strcasecmp(cmatch_argv->argv[i], "dot-nexthop")) { + pattern = nexthop; + sub = 1; + } else { + pattern = cmatch_argv->argv[i]; + if (*pattern == '.' && pattern[1] != '\0') { + ++pattern; + sub = 1; + } + } + + /* + * Sub-domain match: peerid is any sub-domain of pattern. + */ + if (sub) { + if ((idlen = (int) strlen(peerid)) > (patlen = (int) strlen(pattern)) + 1 + && peerid[idlen - patlen - 1] == '.' + && !strcasecmp(peerid + (idlen - patlen), pattern)) + return (1); + else + continue; + } + + /* + * Exact match and initial "*" match. The initial "*" in a peerid + * matches exactly one hostname component, under the condition that + * the peerid contains multiple hostname components. + */ + if (!strcasecmp(peerid, pattern) + || (peerid[0] == '*' && peerid[1] == '.' && peerid[2] != 0 + && (pattern_left = strchr(pattern, '.')) != 0 + && strcasecmp(pattern_left + 1, peerid + 2) == 0)) + return (1); + } + return (0); +} + +/* verify_extract_name - verify peer name and extract peer information */ + +static void verify_extract_name(TLS_SESS_STATE *TLScontext, X509 *peercert, + const TLS_CLIENT_START_PROPS *props) +{ + int i; + int r; + int matched = 0; + const char *dnsname; + const GENERAL_NAME *gn; + + STACK_OF(GENERAL_NAME) * gens; + + /* + * On exit both peer_CN and issuer_CN should be set. + */ + TLScontext->issuer_CN = tls_issuer_CN(peercert, TLScontext); + + /* + * Is the certificate trust chain valid and trusted? + */ + if (SSL_get_verify_result(TLScontext->con) == X509_V_OK) + TLScontext->peer_status |= TLS_CERT_FLAG_TRUSTED; + + if (TLS_CERT_IS_TRUSTED(TLScontext) && props->tls_level >= TLS_LEV_VERIFY) { + + /* + * Verify the dNSName(s) in the peer certificate against the nexthop + * and hostname. + * + * If DNS names are present, we use the first matching (or else simply + * the first) DNS name as the subject CN. The CommonName in the + * issuer DN is obsolete when SubjectAltName is available. This + * yields much less surprising logs, because we log the name we + * verified or a name we checked and failed to match. + * + * XXX: The nexthop and host name may both be the same network address + * rather than a DNS name. In this case we really should be looking + * for GEN_IPADD entries, not GEN_DNS entries. + * + * XXX: In ideal world the caller who used the address to build the + * connection would tell us that the nexthop is the connection + * address, but if that is not practical, we can parse the nexthop + * again here. + */ + gens = X509_get_ext_d2i(peercert, NID_subject_alt_name, 0, 0); + if (gens) { + r = sk_GENERAL_NAME_num(gens); + for (i = 0; i < r && !matched; ++i) { + gn = sk_GENERAL_NAME_value(gens, i); + if (gn->type != GEN_DNS) + continue; + + /* + * Even if we have an invalid DNS name, we still ultimately + * ignore the CommonName, because subjectAltName:DNS is + * present (though malformed). Replace any previous peer_CN + * if empty or we get a match. + * + * We always set at least an empty peer_CN if the ALTNAME cert + * flag is set. If not, we set peer_CN from the cert + * CommonName below, so peer_CN is always non-null on return. + */ + TLScontext->peer_status |= TLS_CERT_FLAG_ALTNAME; + dnsname = tls_dns_name(gn, TLScontext); + if (dnsname && *dnsname) { + matched = match_hostname(dnsname, props); + if (TLScontext->peer_CN + && (matched || *TLScontext->peer_CN == 0)) { + acl_myfree(TLScontext->peer_CN); + TLScontext->peer_CN = 0; + } + } + if (TLScontext->peer_CN == 0) + TLScontext->peer_CN = acl_mystrdup(dnsname ? dnsname : ""); + } + + /* + * (Sam Rushing, Ironport) Free stack *and* member GENERAL_NAME + * objects + */ + sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free); + } + + /* + * No subjectAltNames, peer_CN is taken from CommonName. + */ + if (TLScontext->peer_CN == 0) { + TLScontext->peer_CN = tls_peer_CN(peercert, TLScontext); + if (*TLScontext->peer_CN) + matched = match_hostname(TLScontext->peer_CN, props); + } + if (matched) + TLScontext->peer_status |= TLS_CERT_FLAG_MATCHED; + + /* + * - Matched: Trusted and peername matches - Trusted: Signed by + * trusted CA(s), but peername not matched - Untrusted: Can't verify + * the trust chain, reason already logged. + */ + if (TLScontext->log_level >= 2) + acl_msg_info("%s: %s subject_CN=%s, issuer_CN=%s", props->namaddr, + TLS_CERT_IS_MATCHED(TLScontext) ? "Matched" : + TLS_CERT_IS_TRUSTED(TLScontext) ? "Trusted" : "Untrusted", + TLScontext->peer_CN, TLScontext->issuer_CN); + } else + TLScontext->peer_CN = tls_peer_CN(peercert, TLScontext); + + /* + * Give them a clue. Problems with trust chain verification were logged + * when the session was first negotiated, before the session was stored + * into the cache. We don't want mystery failures, so log the fact the + * real problem is to be found in the past. + */ + if (TLScontext->session_reused + && !TLS_CERT_IS_TRUSTED(TLScontext) + && TLScontext->log_level >= 1) + acl_msg_info("%s: re-using session with untrusted certificate, " + "look for details earlier in the log", props->namaddr); +} + +/* verify_extract_print - extract and verify peer fingerprint */ + +static void verify_extract_print(TLS_SESS_STATE *TLScontext, X509 *peercert, + const TLS_CLIENT_START_PROPS *props) +{ + char **cpp; + + /* Non-null by contract */ + TLScontext->peer_fingerprint = tls_fingerprint(peercert, props->fpt_dgst); + + if (props->tls_level != TLS_LEV_FPRINT) + return; + + /* + * Compare the fingerprint against each acceptable value, ignoring + * upper/lower case differences. + */ + for (cpp = props->matchargv->argv; *cpp; ++cpp) + if (strcasecmp(TLScontext->peer_fingerprint, *cpp) == 0) { + TLScontext->peer_status |= TLS_CERT_FLAG_MATCHED; + break; + } + if (props->log_level >= 2) + acl_msg_info("%s %s%s fingerprint %s", props->namaddr, + TLS_CERT_IS_MATCHED(TLScontext) ? "Matched " : "", + props->fpt_dgst, TLScontext->peer_fingerprint); +} + +/* + * This is the actual startup routine for the connection. We expect that the + * buffers are flushed and the "220 Ready to start TLS" was received by us, + * so that we can immediately start the TLS handshake process. + */ +TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props) +{ + const char *myname = "tls_client_start"; + int sts; + int protomask; + const char *cipher_list; + SSL_SESSION *session; + SSL_CIPHER *cipher; + X509 *peercert; + TLS_SESS_STATE *TLScontext; + TLS_APPL_STATE *app_ctx = props->ctx; + ACL_VSTRING *myserverid; + + if (props->log_level >= 1) + acl_msg_info("%s(%d): setting up TLS connection to %s", + myname, __LINE__, props->namaddr); + + /* + * First make sure we have valid protocol and cipher parameters + * + * The cipherlist will be applied to the global SSL context, where it can be + * repeatedly reset if necessary, but the protocol restrictions will be + * is applied to the SSL connection, because protocol restrictions in the + * global context cannot be cleared. + */ + + /* + * OpenSSL will ignore cached sessions that use the wrong protocol. So we + * do not need to filter out cached sessions with the "wrong" protocol, + * rather OpenSSL will simply negotiate a new session. + * + * Still, we salt the session lookup key with the protocol list, so that + * sessions found in the cache are always acceptable. + */ + protomask = tls_protocol_mask(props->protocols); + if (protomask == TLS_PROTOCOL_INVALID) { + /* tls_protocol_mask() logs no warning. */ + acl_msg_warn("%s(%d): nameaddr: %s: Invalid TLS protocol list \"%s\": aborting TLS session", + myname, __LINE__, props->namaddr, props->protocols); + return (0); + } + myserverid = acl_vstring_alloc(100); + acl_vstring_sprintf_append(myserverid, "%s&p=%d", props->serverid, protomask); + + /* + * Per session cipher selection for sessions with mandatory encryption + * + * By the time a TLS client is negotiating ciphers it has already offered to + * re-use a session, it is too late to renege on the offer. So we must + * not attempt to re-use sessions whose ciphers are too weak. We salt the + * session lookup key with the cipher list, so that sessions found in the + * cache are always acceptable. + */ + cipher_list = tls_set_ciphers(app_ctx, "TLS", props->cipher_grade, + props->cipher_exclusions); + if (cipher_list == 0) { + acl_msg_warn("%s(%d): %s: %s: aborting TLS session", + myname, __LINE__, props->namaddr, acl_vstring_str(app_ctx->why)); + acl_vstring_free(myserverid); + return (0); + } + if (props->log_level >= 2) + acl_msg_info("%s(%d): %s: TLS cipher list \"%s\"", + myname, __LINE__, props->namaddr, cipher_list); + acl_vstring_sprintf_append(myserverid, "&c=%s", cipher_list); + + /* + * Allocate a new TLScontext for the new connection and get an SSL + * structure. Add the location of TLScontext to the SSL to later retrieve + * the information inside the tls_verify_certificate_callback(). + * + * If session caching was enabled when TLS was initialized, the cache type + * is stored in the client SSL context. + */ + TLScontext = tls_alloc_sess_context(props->log_level, props->namaddr); + TLScontext->cache_type = app_ctx->cache_type; + + TLScontext->serverid = acl_vstring_export(myserverid); + + if ((TLScontext->con = SSL_new(app_ctx->ssl_ctx)) == NULL) { + acl_msg_warn("%s(%d): Could not allocate 'TLScontext->con' with SSL_new()", + myname, __LINE__); + tls_print_errors(); + tls_free_context(TLScontext); + return (0); + } + if (!SSL_set_ex_data(TLScontext->con, TLScontext_index, TLScontext)) { + acl_msg_warn("%s(%d): Could not set application data for 'TLScontext->con'", + myname, __LINE__); + tls_print_errors(); + tls_free_context(TLScontext); + return (0); + } + + /* + * Apply session protocol restrictions. + */ + if (protomask != 0) + SSL_set_options(TLScontext->con, + ((protomask & TLS_PROTOCOL_TLSv1) ? SSL_OP_NO_TLSv1 : 0L) + | ((protomask & TLS_PROTOCOL_SSLv3) ? SSL_OP_NO_SSLv3 : 0L) + | ((protomask & TLS_PROTOCOL_SSLv2) ? SSL_OP_NO_SSLv2 : 0L)); + + /* + * The TLS connection is realized by a BIO_pair, so obtain the pair. + * + * XXX There is no need to make internal_bio a member of the TLScontext + * structure. It will be attached to TLScontext->con, and destroyed along + * with it. The network_bio, however, needs to be freed explicitly. + */ + if (!BIO_new_bio_pair(&TLScontext->internal_bio, TLS_BIO_BUFSIZE, + &TLScontext->network_bio, TLS_BIO_BUFSIZE)) { + acl_msg_warn("%s(%d): Could not obtain BIO_pair", myname, __LINE__); + tls_print_errors(); + tls_free_context(TLScontext); + return (0); + } + + /* + * XXX To avoid memory leaks we must always call SSL_SESSION_free() after + * calling SSL_set_session(), regardless of whether or not the session + * will be reused. + */ + if (TLScontext->cache_type) { + session = load_clnt_session(TLScontext); + if (session) { + SSL_set_session(TLScontext->con, session); + SSL_SESSION_free(session); /* 200411 */ +#if (OPENSSL_VERSION_NUMBER < 0x00906011L) || (OPENSSL_VERSION_NUMBER == 0x00907000L) + + /* + * Ugly Hack: OpenSSL before 0.9.6a does not store the verify + * result in sessions for the client side. We modify the session + * directly which is version specific, but this bug is version + * specific, too. + * + * READ: 0-09-06-01-1 = 0-9-6-a-beta1: all versions before beta1 + * have this bug, it has been fixed during development of 0.9.6a. + * The development version of 0.9.7 can have this bug, too. It + * has been fixed on 2000/11/29. + */ + SSL_set_verify_result(TLScontext->con, session->verify_result); +#endif + } + } + + /* + * Before really starting anything, try to seed the PRNG a little bit + * more. + */ + tls_int_seed(); + if (var_tls_daemon_rand_bytes > 0) + (void) tls_ext_seed(var_tls_daemon_rand_bytes); + + /* + * Initialize the SSL connection to connect state. This should not be + * necessary anymore since 0.9.3, but the call is still in the library + * and maintaining compatibility never hurts. + */ + SSL_set_connect_state(TLScontext->con); + + /* + * Connect the SSL connection with the Postfix side of the BIO-pair for + * reading and writing. + */ + SSL_set_bio(TLScontext->con, TLScontext->internal_bio, TLScontext->internal_bio); + + /* + * If the debug level selected is high enough, all of the data is dumped: + * 3 will dump the SSL negotiation, 4 will dump everything. + * + * We do have an SSL_set_fd() and now suddenly a BIO_ routine is called? + * Well there is a BIO below the SSL routines that is automatically + * created for us, so we can use it for debugging purposes. + */ + if (props->log_level >= 3) + BIO_set_callback(SSL_get_rbio(TLScontext->con), tls_bio_dump_cb); + + /* + * Start TLS negotiations. This process is a black box that invokes our + * call-backs for certificate verification. + * + * Error handling: If the SSL handhake fails, we print out an error message + * and remove all TLS state concerning this session. + */ + sts = tls_bio_connect(ACL_VSTREAM_SOCK(props->stream), props->timeout, + TLScontext); + if (sts <= 0) { + acl_msg_info("%s(%d): SSL_connect error to %s: %d", + myname, __LINE__, props->namaddr, sts); + tls_print_errors(); + uncache_session(app_ctx->ssl_ctx, TLScontext); + tls_free_context(TLScontext); + return (0); + } + /* Only log_level==4 dumps everything */ + if (props->log_level < 4) + BIO_set_callback(SSL_get_rbio(TLScontext->con), 0); + + /* + * The caller may want to know if this session was reused or if a new + * session was negotiated. + */ + TLScontext->session_reused = SSL_session_reused(TLScontext->con); + if (props->log_level >= 2 && TLScontext->session_reused) + acl_msg_info("%s(%d): %s: Reusing old session", + myname, __LINE__, TLScontext->namaddr); + + /* + * Do peername verification if requested and extract useful information + * from the certificate for later use. + */ + if ((peercert = SSL_get_peer_certificate(TLScontext->con)) != 0) { + TLScontext->peer_status |= TLS_CERT_FLAG_PRESENT; + + /* + * Peer name or fingerprint verification as requested. + * Unconditionally set peer_CN, issuer_CN and peer_fingerprint. + */ + verify_extract_name(TLScontext, peercert, props); + verify_extract_print(TLScontext, peercert, props); + X509_free(peercert); + } else { + TLScontext->issuer_CN = acl_mystrdup(""); + TLScontext->peer_CN = acl_mystrdup(""); + TLScontext->peer_fingerprint = acl_mystrdup(""); + } + + /* + * Finally, collect information about protocol and cipher for logging + */ + TLScontext->protocol = SSL_get_version(TLScontext->con); + cipher = SSL_get_current_cipher(TLScontext->con); + TLScontext->cipher_name = SSL_CIPHER_get_name(cipher); + TLScontext->cipher_usebits = SSL_CIPHER_get_bits(cipher, + &(TLScontext->cipher_algbits)); + + /* + * The TLS engine is active. Switch to the tls_timed_read/write() + * functions and make the TLScontext available to those functions. + */ + tls_stream_start(props->stream, TLScontext); + + /* + * All the key facts in a single log entry. + */ + if (props->log_level >= 1) + acl_msg_info("%s(%d): %s TLS connection established to %s: %s with cipher %s " + "(%d/%d bits)", myname, __LINE__, + TLS_CERT_IS_MATCHED(TLScontext) ? "Verified" : + TLS_CERT_IS_TRUSTED(TLScontext) ? "Trusted" : "Untrusted", + props->namaddr, TLScontext->protocol, TLScontext->cipher_name, + TLScontext->cipher_usebits, TLScontext->cipher_algbits); + + tls_int_seed(); + + return (TLScontext); +} + +#endif /* USE_TLS */ diff --git a/lib_tls/tls/tls_dh.c b/lib_tls/tls/tls_dh.c new file mode 100644 index 000000000..3aee7c3d8 --- /dev/null +++ b/lib_tls/tls/tls_dh.c @@ -0,0 +1,290 @@ +/*++ + * NAME + * tls_dh + * SUMMARY + * Diffie-Hellman parameter support + * SYNOPSIS + * #include + * #include + * + * void tls_set_dh_from_file(path, bits) + * const char *path; + * int bits; + * + * int tls_set_eecdh_curve(server_ctx, grade) + * SSL_CTX *server_ctx; + * const char *grade; + * + * DH *tls_tmp_dh_cb(ssl, export, keylength) + * SSL *ssl; acl_unused + * int export; + * int keylength; + * DESCRIPTION + * This module maintains parameters for Diffie-Hellman key generation. + * + * tls_tmp_dh_cb() is a call-back routine for the + * SSL_CTX_set_tmp_dh_callback() function. + * + * tls_set_dh_from_file() overrides compiled-in DH parameters + * with those specified in the named files. The file format + * is as expected by the PEM_read_DHparams() routine. The + * "bits" argument must be 512 or 1024. + * + * tls_set_eecdh_curve() enables ephemeral Elliptic-Curve DH + * key exchange algorithms by instantiating in the server SSL + * context a suitable curve (corresponding to the specified + * EECDH security grade) from the set of named curves in RFC + * 4492 Section 5.1.1. Errors generate warnings, but do not + * disable TLS, rather we continue without EECDH. A zero + * result indicates that the grade is invalid or the corresponding + * curve could not be used. + * DIAGNOSTICS + * In case of error, tls_set_dh_from_file() logs a warning and + * ignores the request. + * LICENSE + * .ad + * .fi + * This software is free. You can do with it whatever you want. + * The original author kindly requests that you acknowledge + * the use of his software. + * AUTHOR(S) + * Originally written by: + * Lutz Jaenicke + * BTU Cottbus + * Allgemeine Elektrotechnik + * Universitaetsplatz 3-4 + * D-03044 Cottbus, Germany + * + * Updated by: + * Wietse Venema + * IBM T.J. Watson Research + * P.O. Box 704 + * Yorktown Heights, NY 10598, USA + *--*/ + +#include "StdAfx.h" + +#ifdef USE_TLS +#include + +/* TLS library. */ + +#include "tls.h" +#include "tls_params.h" +#include "tls_private.h" + +/* Application-specific. */ + + /* + * Compiled-in EDH primes (the compiled-in generator is always 2). These are + * used when no parameters are explicitly loaded from a site-specific file. + * + * 512-bit parameters are used for export ciphers, and 1024-bit parameters are + * used for non-export ciphers. An ~80-bit strong EDH key exchange is really + * too weak to protect 128+ bit keys, but larger DH primes are + * computationally expensive. When greater security is required, use EECDH. + */ + + /* + * Generated via "openssl dhparam -2 -noout -C 512 2>/dev/null" TODO: + * generate at compile-time. + */ +static unsigned char dh512_p[] = { + 0x88, 0x3F, 0x00, 0xAF, 0xFC, 0x0C, 0x8A, 0xB8, 0x35, 0xCD, 0xE5, 0xC2, + 0x0F, 0x55, 0xDF, 0x06, 0x3F, 0x16, 0x07, 0xBF, 0xCE, 0x13, 0x35, 0xE4, + 0x1C, 0x1E, 0x03, 0xF3, 0xAB, 0x17, 0xF6, 0x63, 0x50, 0x63, 0x67, 0x3E, + 0x10, 0xD7, 0x3E, 0xB4, 0xEB, 0x46, 0x8C, 0x40, 0x50, 0xE6, 0x91, 0xA5, + 0x6E, 0x01, 0x45, 0xDE, 0xC9, 0xB1, 0x1F, 0x64, 0x54, 0xFA, 0xD9, 0xAB, + 0x4F, 0x70, 0xBA, 0x5B, +}; + + /* + * Generated via "openssl dhparam -2 -noout -C 1024 2>/dev/null" TODO: + * generate at compile-time. + */ +static unsigned char dh1024_p[] = { + 0xB0, 0xFE, 0xB4, 0xCF, 0xD4, 0x55, 0x07, 0xE7, 0xCC, 0x88, 0x59, 0x0D, + 0x17, 0x26, 0xC5, 0x0C, 0xA5, 0x4A, 0x92, 0x23, 0x81, 0x78, 0xDA, 0x88, + 0xAA, 0x4C, 0x13, 0x06, 0xBF, 0x5D, 0x2F, 0x9E, 0xBC, 0x96, 0xB8, 0x51, + 0x00, 0x9D, 0x0C, 0x0D, 0x75, 0xAD, 0xFD, 0x3B, 0xB1, 0x7E, 0x71, 0x4F, + 0x3F, 0x91, 0x54, 0x14, 0x44, 0xB8, 0x30, 0x25, 0x1C, 0xEB, 0xDF, 0x72, + 0x9C, 0x4C, 0xF1, 0x89, 0x0D, 0x68, 0x3F, 0x94, 0x8E, 0xA4, 0xFB, 0x76, + 0x89, 0x18, 0xB2, 0x91, 0x16, 0x90, 0x01, 0x99, 0x66, 0x8C, 0x53, 0x81, + 0x4E, 0x27, 0x3D, 0x99, 0xE7, 0x5A, 0x7A, 0xAF, 0xD5, 0xEC, 0xE2, 0x7E, + 0xFA, 0xED, 0x01, 0x18, 0xC2, 0x78, 0x25, 0x59, 0x06, 0x5C, 0x39, 0xF6, + 0xCD, 0x49, 0x54, 0xAF, 0xC1, 0xB1, 0xEA, 0x4A, 0xF9, 0x53, 0xD0, 0xDF, + 0x6D, 0xAF, 0xD4, 0x93, 0xE7, 0xBA, 0xAE, 0x9B, +}; + + /* + * Cached results. + */ +static __thread DH *dh_1024 = 0; +static __thread DH *dh_512 = 0; + +/* free_dh_cb - call-back for free DH */ + +static void free_dh_cb(void *arg) +{ + DH *dh_tmp = (DH*) arg; + + DH_free(dh_tmp); +} + +/* tls_set_dh_from_file - set Diffie-Hellman parameters from file */ + +void tls_set_dh_from_file(const char *path, int bits) +{ + const char *myname = "tls_set_dh_from_file"; + FILE *paramfile; + DH **dhPtr = 0; + + switch (bits) { + case 512: + dhPtr = &dh_512; + break; + case 1024: + dhPtr = &dh_1024; + break; + default: + acl_msg_panic("Invalid DH parameters size %d, file %s", bits, path); + } + + if (*dhPtr != 0) + return; + + if ((paramfile = fopen(path, "r")) != 0) { + if ((*dhPtr = PEM_read_DHparams(paramfile, 0, 0, 0)) == 0) { + acl_msg_warn("%s: cannot load %d-bit DH parameters from file %s" + " -- using compiled-in defaults", myname, bits, path); + tls_print_errors(); + } + (void) fclose(paramfile); /* 200411 */ + } else { + acl_msg_warn("%s: cannot load %d-bit DH parameters from file %s: %s" + " -- using compiled-in defaults", myname, bits, path, acl_last_serror()); + } +} + +/* tls_get_dh - get compiled-in DH parameters */ + +static DH *tls_get_dh(const unsigned char *p, int plen) +{ + const char *myname = "tls_get_dh"; + DH *dh; + static unsigned char g[] = {0x02,}; + + /* Use the compiled-in parameters. */ + if ((dh = DH_new()) == 0) { + acl_msg_warn("%s: cannot create DH parameter set: %s", + myname, acl_last_serror()); /* 200411 */ + return (0); + } + dh->p = BN_bin2bn(p, plen, (BIGNUM *) 0); + dh->g = BN_bin2bn(g, 1, (BIGNUM *) 0); + if ((dh->p == 0) || (dh->g == 0)) { + acl_msg_warn("%s: cannot load compiled-in DH parameters", myname); /* 200411 */ + DH_free(dh); /* 200411 */ + return (0); + } + return (dh); +} + +/* tls_tmp_dh_cb - call-back for Diffie-Hellman parameters */ + +DH *tls_tmp_dh_cb(SSL *unused_ssl acl_unused, int export, int keylength) +{ + DH *dh_tmp; + + if (export && keylength == 512) { /* 40-bit export cipher */ + if (dh_512 == 0) { + dh_512 = tls_get_dh(dh512_p, (int) sizeof(dh512_p)); + if (dh_512) + acl_pthread_atexit_add(dh_512, free_dh_cb); + } + dh_tmp = dh_512; + } else { /* ADH, DHE-RSA or DSA */ + if (dh_1024 == 0) { + dh_1024 = tls_get_dh(dh1024_p, (int) sizeof(dh1024_p)); + if (dh_1024) + acl_pthread_atexit_add(dh_1024, free_dh_cb); + } + dh_tmp = dh_1024; + } + return (dh_tmp); +} + +int tls_set_eecdh_curve(SSL_CTX *server_ctx acl_unused, const char *grade acl_unused) +{ +#if OPENSSL_VERSION_NUMBER >= 0x00909000 && !defined(OPENSSL_NO_ECDH) + const char *myname = "tls_set_eecdh_curve"; + int nid; + EC_KEY *ecdh; + const char *curve; + int g; + +#define TLS_EECDH_INVALID 0 +#define TLS_EECDH_NONE 1 +#define TLS_EECDH_STRONG 2 +#define TLS_EECDH_ULTRA 3 + static NAME_CODE eecdh_table[] = { + "none", TLS_EECDH_NONE, + "strong", TLS_EECDH_STRONG, + "ultra", TLS_EECDH_ULTRA, + 0, TLS_EECDH_INVALID, + }; + + switch (g = name_code(eecdh_table, NAME_CODE_FLAG_NONE, grade)) { + default: + acl_msg_panic("%s: Invalid eecdh grade code: %d", myname, g); + case TLS_EECDH_INVALID: + acl_msg_warn("%s: Invalid TLS eecdh grade \"%s\": EECDH disabled", myname, grade); + return (0); + case TLS_EECDH_NONE: + return (1); + case TLS_EECDH_STRONG: + curve = var_tls_eecdh_strong; + break; + case TLS_EECDH_ULTRA: + curve = var_tls_eecdh_ultra; + break; + } + + /* + * Elliptic-Curve Diffie-Hellman parameters are either "named curves" + * from RFC 4492 section 5.1.1, or explicitly described curves over + * binary fields. OpenSSL only supports the "named curves", which provide + * maximum interoperability. The recommended curve for 128-bit + * work-factor key exchange is "prime256v1" a.k.a. "secp256r1" from + * Section 2.7 of http://www.secg.org/download/aid-386/sec2_final.pdf + */ + + if ((nid = OBJ_sn2nid(curve)) == NID_undef) { + acl_msg_warn("%s: unknown curve \"%s\": disabling EECDH support", myname, curve); + return (0); + } + ERR_clear_error(); + if ((ecdh = EC_KEY_new_by_curve_name(nid)) == 0 + || SSL_CTX_set_tmp_ecdh(server_ctx, ecdh) == 0) { + acl_msg_warn("%s: unable to use curve \"%s\": disabling EECDH support", myname, curve); + tls_print_errors(); + return (0); + } +#endif + return (1); +} + +#ifdef TEST + +int main(int unused_argc, char **unused_argv) +{ + tls_tmp_dh_cb(0, 1, 512); + tls_tmp_dh_cb(0, 1, 1024); + tls_tmp_dh_cb(0, 1, 2048); + tls_tmp_dh_cb(0, 0, 512); + return (0); +} + +#endif + +#endif diff --git a/lib_tls/tls/tls_level.c b/lib_tls/tls/tls_level.c new file mode 100644 index 000000000..c7b592804 --- /dev/null +++ b/lib_tls/tls/tls_level.c @@ -0,0 +1,75 @@ +/*++ + * NAME + * tls_level 3 + * SUMMARY + * TLS security level conversion + * SYNOPSIS + * #include + * + * int tls_level_lookup(name) + * const char *name; + * + * const char *str_tls_level(level) + * int level; + * DESCRIPTION + * The macros in this module convert TLS levels from symbolic + * name to internal form and vice versa. The macros are safe + * because they evaluate their arguments only once. + * + * tls_level_lookup() converts a TLS level from symbolic name + * to internal form. When an unknown level is specified, + * tls_level_lookup() logs no warning, and returns TLS_LEV_INVALID. + * + * str_tls_level() converts a TLS level from internal form to + * symbolic name. The result is a null pointer for an unknown + * level. + * SEE ALSO + * name_code(3) name to number mapping + * LICENSE + * .ad + * .fi + * The Secure Mailer license must be distributed with this software. + * AUTHOR(S) + * Wietse Venema + * IBM T.J. Watson Research + * P.O. Box 704 + * Yorktown Heights, NY 10598, USA + * + * Victor Duchovni + * Morgan Stanley + *--*/ + +#include "StdAfx.h" + +#ifdef USE_TLS + +/* Utility library. */ + +#include "../util/name_code.h" + +/* TLS library. */ + +#include "tls_private.h" + +/* Application-specific. */ + + /* + * Order is critical: + * + * Levels > "encrypt" are expected to match a peer certificate. + * + * Levels >= "verify" are expected to require a valid CA trust-chain + * + * This forces "fingerprint" between "encrypt" and "verify". + */ +const NAME_CODE tls_level_table[] = { + { "none", TLS_LEV_NONE }, + { "may", TLS_LEV_MAY }, + { "encrypt", TLS_LEV_ENCRYPT }, + { "fingerprint", TLS_LEV_FPRINT }, + { "verify", TLS_LEV_VERIFY }, + { "secure", TLS_LEV_SECURE }, + { 0, TLS_LEV_INVALID }, +}; + +#endif diff --git a/lib_tls/tls/tls_mgr.c b/lib_tls/tls/tls_mgr.c new file mode 100644 index 000000000..90a4672a2 --- /dev/null +++ b/lib_tls/tls/tls_mgr.c @@ -0,0 +1,413 @@ +/*++ + * NAME + * tls_mgr 3 + * SUMMARY + * tlsmgr client interface + * SYNOPSIS + * #include + * + * int tls_mgr_seed(buf, len) + * ACL_VSTRING *buf; + * int len; + * + * int tls_mgr_policy(cache_type, cachable) + * const char *cache_type; + * int *cachable; + * + * int tls_mgr_update(cache_type, cache_id, buf, len) + * const char *cache_type; + * const char *cache_id; + * const char *buf; + * ssize_t len; + * + * int tls_mgr_lookup(cache_type, cache_id, buf) + * const char *cache_type; + * const char *cache_id; + * ACL_VSTRING *buf; + * + * int tls_mgr_delete(cache_type, cache_id) + * const char *cache_type; + * const char *cache_id; + * DESCRIPTION + * These routines communicate with the tlsmgr(8) server for + * entropy and session cache management. Since these are + * non-critical services, requests are allowed to fail without + * disrupting Postfix. + * + * tls_mgr_seed() requests entropy from the tlsmgr(8) + * Pseudo Random Number Generator (PRNG) pool. + * + * tls_mgr_policy() requests the session caching policy. + * + * tls_mgr_lookup() loads the specified session from + * the specified session cache. + * + * tls_mgr_update() saves the specified session to + * the specified session cache. + * + * tls_mgr_delete() removes specified session from + * the specified session cache. + * + * Arguments + * .IP cache_type + * One of TLS_MGR_SCACHE_SMTPD, TLS_MGR_SCACHE_SMTP + * .IP cachable + * Pointer to int, set non-zero if the requested cache_type + * is enabled. + * .IP cache_id + * The session cache lookup key. + * .IP buf + * The result or input buffer. + * .IP len + * The length of the input buffer, or the amount of data requested. + * DIAGNOSTICS + * All client functions return one of the following status codes: + * .IP TLS_MGR_STAT_OK + * The request completed, and the requested operation was + * successful (for example, the requested session was found, + * or the specified session was saved or removed). + * .IP TLS_MGR_STAT_ERR + * The request completed, but the requested operation failed + * (for example, the requested object was not found or the + * specified session was not saved or removed). + * .IP TLS_MGR_STAT_FAIL + * The request could not complete (the client could not + * communicate with the tlsmgr(8) server). + * SEE ALSO + * tlsmgr(8) TLS session and PRNG management + * LICENSE + * .ad + * .fi + * The Secure Mailer license must be distributed with this software. + * AUTHOR(S) + * Wietse Venema + * IBM T.J. Watson Research + * P.O. Box 704 + * Yorktown Heights, NY 10598, USA + *--*/ + +#include "StdAfx.h" + +#ifdef USE_TLS + +#include + +#ifdef STRCASECMP_IN_STRINGS_H +#include +#endif + +#include "../attr/attr.h" +#include "../attr/attr_clnt.h" + +/* Global library. */ + +#include "tls_params.h" +#include "tls_mgr.h" + +/* Application-specific. */ + +static __thread ATTR_CLNT *tls_mgr = 0; + +static void free_event(void *ctx) +{ + ACL_EVENT *eventp = (ACL_EVENT*) ctx; + + acl_event_free(eventp); +} + +/* tls_mgr_open - create client handle */ + +void tls_mgr_open(ACL_EVENT *eventp) +{ + + /* + * Sanity check. + */ + if (tls_mgr != 0) { + if (acl_msg_verbose) + acl_msg_info("tls_mgr_open: multiple initialization"); + return; + } + + if (eventp == NULL) { + eventp = acl_event_new_select(1, 0); + acl_pthread_atexit_add(eventp, free_event); + } + + /* + * Use whatever IPC is preferred for internal use: UNIX-domain sockets or + * Solaris streams. + */ +#ifndef VAR_TLS_MGR_SERVICE + tls_mgr = attr_clnt_create(eventp, "local:" TLS_MGR_CLASS "/" TLS_MGR_SERVICE, + var_ipc_timeout, var_ipc_idle_limit, + var_ipc_ttl_limit); + if (tls_mgr == 0) { + acl_msg_warn("attr_clnt_create error, service: local:%s", + TLS_MGR_CLASS "/" TLS_MGR_SERVICE); + return; + } +#else + tls_mgr = attr_clnt_create(eventp, var_tlsmgr_service, var_ipc_timeout, + var_ipc_idle_limit, var_ipc_ttl_limit); + if (tls_mgr == 0) { + acl_msg_warn("attr_clnt_create error, service: %s", var_tlsmgr_service); + return; + } +#endif + + acl_pthread_atexit_add(tls_mgr, (void (*)(void*)) attr_clnt_free); + attr_clnt_control(tls_mgr, + ATTR_CLNT_CTL_PROTO, attr_vprint, attr_vscan, + ATTR_CLNT_CTL_END); +} + +/* tls_mgr_seed - request PRNG seed */ + +int tls_mgr_seed(ACL_VSTRING *buf, int len) +{ + int status; + + /* + * Create the tlsmgr client handle. + */ + if (tls_mgr == 0) { + acl_msg_warn("tls_mgr_seed: call tls_mgr_open first"); + return TLS_MGR_STAT_FAIL; + } + + /* + * Request seed. + */ + if (attr_clnt_request(tls_mgr, + ATTR_FLAG_NONE, /* Request attributes */ + ATTR_TYPE_STR, TLS_MGR_ATTR_REQ, TLS_MGR_REQ_SEED, + ATTR_TYPE_INT, TLS_MGR_ATTR_SIZE, len, + ATTR_TYPE_END, + ATTR_FLAG_MISSING, /* Reply attributes */ + ATTR_TYPE_INT, TLS_MGR_ATTR_STATUS, &status, + ATTR_TYPE_DATA, TLS_MGR_ATTR_SEED, buf, + ATTR_TYPE_END) != 2) + status = TLS_MGR_STAT_FAIL; + return (status); +} + +/* tls_mgr_policy - request caching policy */ + +int tls_mgr_policy(const char *cache_type, int *cachable) +{ + int status; + + /* + * Create the tlsmgr client handle. + */ + if (tls_mgr == 0) { + if (acl_msg_verbose) + acl_msg_info("tls_mgr_policy: call tls_mgr_open first"); + return TLS_MGR_STAT_FAIL; + } + + /* + * Request policy. + */ + if (attr_clnt_request(tls_mgr, + ATTR_FLAG_NONE, /* Request attributes */ + ATTR_TYPE_STR, TLS_MGR_ATTR_REQ, TLS_MGR_REQ_POLICY, + ATTR_TYPE_STR, TLS_MGR_ATTR_CACHE_TYPE, cache_type, + ATTR_TYPE_END, + ATTR_FLAG_MISSING, /* Reply attributes */ + ATTR_TYPE_INT, TLS_MGR_ATTR_STATUS, &status, + ATTR_TYPE_INT, TLS_MGR_ATTR_CACHABLE, cachable, + ATTR_TYPE_END) != 2) + status = TLS_MGR_STAT_FAIL; + return (status); +} + +/* tls_mgr_lookup - request cached session */ + +int tls_mgr_lookup(const char *cache_type, const char *cache_id, ACL_VSTRING *buf) +{ + int status; + + /* + * Create the tlsmgr client handle. + */ + if (tls_mgr == 0) { + acl_msg_warn("tls_mgr_lookup: call tls_mgr_open first"); + return TLS_MGR_STAT_FAIL; + } + + /* + * Send the request and receive the reply. + */ + if (attr_clnt_request(tls_mgr, + ATTR_FLAG_NONE, /* Request */ + ATTR_TYPE_STR, TLS_MGR_ATTR_REQ, TLS_MGR_REQ_LOOKUP, + ATTR_TYPE_STR, TLS_MGR_ATTR_CACHE_TYPE, cache_type, + ATTR_TYPE_STR, TLS_MGR_ATTR_CACHE_ID, cache_id, + ATTR_TYPE_END, + ATTR_FLAG_MISSING, /* Reply */ + ATTR_TYPE_INT, TLS_MGR_ATTR_STATUS, &status, + ATTR_TYPE_DATA, TLS_MGR_ATTR_SESSION, buf, + ATTR_TYPE_END) != 2) + status = TLS_MGR_STAT_FAIL; + return (status); +} + +/* tls_mgr_update - save session to cache */ + +int tls_mgr_update(const char *cache_type, const char *cache_id, + const char *buf, ssize_t len) +{ + int status; + + /* + * Create the tlsmgr client handle. + */ + if (tls_mgr == 0) { + acl_msg_warn("tls_mgr_update: call tls_mgr_open first"); + return TLS_MGR_STAT_FAIL; + } + + /* + * Send the request and receive the reply. + */ + if (attr_clnt_request(tls_mgr, + ATTR_FLAG_NONE, /* Request */ + ATTR_TYPE_STR, TLS_MGR_ATTR_REQ, TLS_MGR_REQ_UPDATE, + ATTR_TYPE_STR, TLS_MGR_ATTR_CACHE_TYPE, cache_type, + ATTR_TYPE_STR, TLS_MGR_ATTR_CACHE_ID, cache_id, + ATTR_TYPE_DATA, TLS_MGR_ATTR_SESSION, len, buf, + ATTR_TYPE_END, + ATTR_FLAG_MISSING, /* Reply */ + ATTR_TYPE_INT, TLS_MGR_ATTR_STATUS, &status, + ATTR_TYPE_END) != 1) + status = TLS_MGR_STAT_FAIL; + return (status); +} + +/* tls_mgr_delete - remove cached session */ + +int tls_mgr_delete(const char *cache_type, const char *cache_id) +{ + int status; + + /* + * Create the tlsmgr client handle. + */ + if (tls_mgr == 0) { + acl_msg_warn("tls_mgr_delete: call tls_mgr_open first"); + return TLS_MGR_STAT_FAIL; + } + + /* + * Send the request and receive the reply. + */ + if (attr_clnt_request(tls_mgr, + ATTR_FLAG_NONE, /* Request */ + ATTR_TYPE_STR, TLS_MGR_ATTR_REQ, TLS_MGR_REQ_DELETE, + ATTR_TYPE_STR, TLS_MGR_ATTR_CACHE_TYPE, cache_type, + ATTR_TYPE_STR, TLS_MGR_ATTR_CACHE_ID, cache_id, + ATTR_TYPE_END, + ATTR_FLAG_MISSING, /* Reply */ + ATTR_TYPE_INT, TLS_MGR_ATTR_STATUS, &status, + ATTR_TYPE_END) != 1) + status = TLS_MGR_STAT_FAIL; + return (status); +} + +#ifdef TEST + +/* System library. */ + +#include + +/* Utility library. */ + +#include +#include + +/* Global library. */ + +#include + +/* Application-specific. */ + +#define STR(x) acl_vstring_str(x) +#define LEN(x) ACL_VSTRING_LEN(x) + +int main(int unused_ac, char **av) +{ + ACL_VSTRING *inbuf = acl_vstring_alloc(10); + int status; + ARGV *argv = 0; + ACL_EVENT *eventp = acl_event_new_select(1, 0); + + acl_msg_verbose = 3; + + mail_conf_read(); + acl_msg_info("using config files in %s", var_config_dir); + + if (chdir(var_queue_dir) < 0) + acl_msg_fatal("chdir %s: %s", var_queue_dir, acl_last_serror()); + tls_mgr_open(eventp); + + while (acl_vstring_fgets_nonl(inbuf, ACL_VSTREAM_IN)) { + argv = argv_split(STR(inbuf), " \t\r\n"); + if (argv->argc == 0) { + argv_free(argv); + continue; + } + +#define COMMAND(argv, str, len) \ + (strcasecmp(argv->argv[0], str) == 0 && argv->argc == len) + + if (COMMAND(argv, "policy", 2)) { + int cachable; + + status = tls_mgr_policy(argv->argv[1], &cachable); + acl_vstream_printf("status=%d cachable=%d\n", status, cachable); + } else if (COMMAND(argv, "seed", 2)) { + ACL_VSTRING *buf = acl_vstring_alloc(10); + ACL_VSTRING *hex = acl_vstring_alloc(10); + int len = atoi(argv->argv[1]); + + status = tls_mgr_seed(buf, len); + hex_encode(hex, STR(buf), LEN(buf)); + acl_vstream_printf("status=%d seed=%s\n", status, STR(hex)); + acl_vstring_free(hex); + acl_vstring_free(buf); + } else if (COMMAND(argv, "lookup", 3)) { + ACL_VSTRING *buf = acl_vstring_alloc(10); + + status = tls_mgr_lookup(argv->argv[1], argv->argv[2], buf); + acl_vstream_printf("status=%d session=%.*s\n", + status, LEN(buf), STR(buf)); + acl_vstring_free(buf); + } else if (COMMAND(argv, "update", 4)) { + status = tls_mgr_update(argv->argv[1], argv->argv[2], + argv->argv[3], strlen(argv->argv[3])); + acl_vstream_printf("status=%d\n", status); + } else if (COMMAND(argv, "delete", 3)) { + status = tls_mgr_delete(argv->argv[1], argv->argv[2]); + acl_vstream_printf("status=%d\n", status); + } else { + acl_vstream_printf("usage:\n" + "seed byte_count\n" + "policy smtpd|smtp|lmtp\n" + "lookup smtpd|smtp|lmtp cache_id\n" + "update smtpd|smtp|lmtp cache_id session\n" + "delete smtpd|smtp|lmtp cache_id\n"); + } + acl_vstream_fflush(ACL_VSTREAM_OUT); + argv_free(argv); + } + + acl_vstring_free(inbuf); + acl_event_free(eventp); + return (0); +} + +#endif /* TEST */ + +#endif /* USE_TLS */ diff --git a/lib_tls/tls/tls_mgr.h b/lib_tls/tls/tls_mgr.h new file mode 100644 index 000000000..b05a83c91 --- /dev/null +++ b/lib_tls/tls/tls_mgr.h @@ -0,0 +1,64 @@ +#ifndef _TLS_MGR_CLNT_H_INCLUDED_ +#define _TLS_MGR_CLNT_H_INCLUDED_ + +/*++ + * NAME + * tls_mgr 3h + * SUMMARY + * tlsmgr client interface + * SYNOPSIS + * #include + * DESCRIPTION + * .nf + + * + * TLS manager protocol. + */ +#include "lib_acl.h" + +#define TLS_MGR_SERVICE "tlsmgr" +#define TLS_MGR_CLASS "private" + +#define TLS_MGR_ATTR_REQ "request" +#define TLS_MGR_REQ_SEED "seed" +#define TLS_MGR_REQ_POLICY "policy" +#define TLS_MGR_REQ_LOOKUP "lookup" +#define TLS_MGR_REQ_UPDATE "update" +#define TLS_MGR_REQ_DELETE "delete" +#define TLS_MGR_ATTR_CACHABLE "cachable" +#define TLS_MGR_ATTR_CACHE_TYPE "cache_type" +#define TLS_MGR_ATTR_SEED "seed" +#define TLS_MGR_ATTR_CACHE_ID "cache_id" +#define TLS_MGR_ATTR_SESSION "session" +#define TLS_MGR_ATTR_SIZE "size" +#define TLS_MGR_ATTR_STATUS "status" + + /* + * TLS manager request status codes. + */ +#define TLS_MGR_STAT_OK 0 /* success */ +#define TLS_MGR_STAT_ERR (-1) /* object not found */ +#define TLS_MGR_STAT_FAIL (-2) /* protocol error */ + + /* + * Functional interface. + */ +extern void tls_mgr_open(ACL_EVENT *eventp); +extern int tls_mgr_seed(ACL_VSTRING *, int); +extern int tls_mgr_policy(const char *, int *); +extern int tls_mgr_lookup(const char *, const char *, ACL_VSTRING *); +extern int tls_mgr_update(const char *, const char *, const char *, ssize_t); +extern int tls_mgr_delete(const char *, const char *); + +/* LICENSE + * .ad + * .fi + * The Secure Mailer license must be distributed with this software. + * AUTHOR(S) + * Wietse Venema + * IBM T.J. Watson Research + * P.O. Box 704 + * Yorktown Heights, NY 10598, USA + *--*/ + +#endif diff --git a/lib_tls/tls/tls_misc.c b/lib_tls/tls/tls_misc.c new file mode 100644 index 000000000..53750530d --- /dev/null +++ b/lib_tls/tls/tls_misc.c @@ -0,0 +1,867 @@ +/*++ + * NAME + * tls_misc 3 + * SUMMARY + * miscellaneous TLS support routines + * SYNOPSIS + * #include + * #include + * + * char *var_tls_high_clist; + * char *var_tls_medium_clist; + * char *var_tls_low_clist; + * char *var_tls_export_clist; + * char *var_tls_null_clist; + * char *var_tls_eecdh_strong; + * char *var_tls_eecdh_ultra; + * int var_tls_daemon_rand_bytes; + * + * TLS_APPL_STATE *tls_alloc_app_context(ssl_ctx) + * SSL_CTX *ssl_ctx; + * + * void tls_free_app_context(app_ctx) + * void *app_ctx; + * + * TLS_SESS_STATE *tls_alloc_sess_context(log_level, namaddr) + * int log_level; + * const char *namaddr; + * + * void tls_free_context(TLScontext) + * TLS_SESS_STATE *TLScontext; + * + * void tls_check_version() + * + * long tls_bug_bits() + * + * void tls_param_init() + * + * int tls_protocol_mask(plist) + * const char *plist; + * + * int tls_cipher_grade(name) + * const char *name; + * + * const char *str_tls_cipher_grade(grade) + * int grade; + * + * const char *tls_set_ciphers(app_ctx, context, grade, exclusions) + * TLS_APPL_STATE *app_ctx; + * const char *context; + * int grade; + * const char *exclusions; + * + * void tls_print_errors() + * + * void tls_info_callback(ssl, where, ret) + * const SSL *ssl; #unused + * int where; + * int ret; + * + * long tls_bio_dump_cb(bio, cmd, argp, argi, argl, ret) + * BIO *bio; + * int cmd; + * const char *argp; + * int argi; + * long argl; #unused + * long ret; + * DESCRIPTION + * This module implements routines that support the TLS client + * and server internals. + * + * tls_alloc_app_context() creates an application context that + * holds the SSL context for the application and related cached state. + * + * tls_free_app_context() deallocates the application context and its + * contents (the application context is stored outside the TLS library). + * + * tls_alloc_sess_context() creates an initialized TLS session context + * structure with the specified log mask and peer name[addr]. + * + * tls_free_context() destroys a TLScontext structure + * together with OpenSSL structures that are attached to it. + * + * tls_check_version() logs a warning when the run-time OpenSSL + * library differs in its major, minor or micro number from + * the compile-time OpenSSL headers. + * + * tls_bug_bits() returns the bug compatibility mask appropriate + * for the run-time library. Some of the bug work-arounds are + * not appropriate for some library versions. + * + * tls_param_init() loads main.cf parameters used internally in + * TLS library. Any errors are fatal. + * + * tls_protocol_mask() returns a bitmask of excluded protocols, given + * a list (plist) of protocols to include or (preceded by a '!') exclude. + * If "plist" contains invalid protocol names, TLS_PROTOCOL_INVALID is + * returned and no warning is logged. + * + * tls_cipher_grade() converts a case-insensitive cipher grade + * name (high, medium, low, export, null) to the corresponding + * TLS_CIPHER_ constant. When the input specifies an unrecognized + * grade, tls_cipher_grade() logs no warning, and returns + * TLS_CIPHER_NONE. + * + * str_tls_cipher_grade() converts a cipher grade to a name. + * When the input specifies an undefined grade, str_tls_cipher_grade() + * logs no warning, returns a null pointer. + * + * tls_set_ciphers() generates a cipher list from the specified + * grade, minus any ciphers specified via a list of exclusions. + * The cipherlist is applied to the supplied SSL context if it + * is different from the most recently applied value. The return + * value is the cipherlist used and is overwritten upon each call. + * When the input is invalid, tls_set_ciphers() logs a warning with + * the specified context, and returns a null pointer result. + * + * tls_print_errors() queries the OpenSSL error stack, + * logs the error messages, and clears the error stack. + * + * tls_info_callback() is a call-back routine for the + * SSL_CTX_set_info_callback() routine. It logs SSL events + * to the Postfix logfile. + * + * tls_bio_dump_cb() is a call-back routine for the + * BIO_set_callback() routine. It logs SSL content to the + * Postfix logfile. + * LICENSE + * .ad + * .fi + * This software is free. You can do with it whatever you want. + * The original author kindly requests that you acknowledge + * the use of his software. + * AUTHOR(S) + * Originally written by: + * Lutz Jaenicke + * BTU Cottbus + * Allgemeine Elektrotechnik + * Universitaetsplatz 3-4 + * D-03044 Cottbus, Germany + * + * Updated by: + * Wietse Venema + * IBM T.J. Watson Research + * P.O. Box 704 + * Yorktown Heights, NY 10598, USA + * + * Victor Duchovni + * Morgan Stanley + *--*/ + +/* System library. */ + +#include "StdAfx.h" +#include +#include + +#ifdef USE_TLS + + /* + * TLS library. + */ +#include "tls.h" +#include "tls_params.h" +#include "tls_private.h" + + /* Application-specific. */ + + /* + * Index to attach TLScontext pointers to SSL objects, so that they can be + * accessed by call-back routines. + */ +int TLScontext_index = -1; + + /* + * Protocol name <=> mask conversion. + */ +static const NAME_CODE protocol_table[] = { + { SSL_TXT_SSLV2, TLS_PROTOCOL_SSLv2 }, + { SSL_TXT_SSLV3, TLS_PROTOCOL_SSLv3 }, + { SSL_TXT_TLSV1, TLS_PROTOCOL_TLSv1 }, + { 0, TLS_PROTOCOL_INVALID }, +}; + + /* + * Ciphersuite name <=> code conversion. + */ +const NAME_CODE tls_cipher_grade_table[] = { + { "high", TLS_CIPHER_HIGH }, + { "medium", TLS_CIPHER_MEDIUM }, + { "low", TLS_CIPHER_LOW }, + { "export", TLS_CIPHER_EXPORT }, + { "null", TLS_CIPHER_NULL }, + { "invalid", TLS_CIPHER_NONE }, + { 0, TLS_CIPHER_NONE }, +}; + + /* + * Parsed OpenSSL version number. + */ +typedef struct { + int major; + int minor; + int micro; + int patch; + int status; +} TLS_VINFO; + + /* + * OpenSSL adopted the cipher selection patch, so we don't expect any more + * broken ciphers other than AES and CAMELLIA. + */ +typedef struct { + const char *ssl_name; + const int alg_bits; + const char *evp_name; +} cipher_probe_t; + +static const cipher_probe_t cipher_probes[] = { + { "AES", 256, "AES-256-CBC" }, + { "CAMELLIA", 256, "CAMELLIA-256-CBC" }, + { 0, 0, 0 }, +}; + +static void free_argv_fn(void *arg) +{ + ACL_ARGV *argv = (ACL_ARGV*) arg; + acl_argv_free(argv); +} + +/* tls_exclude_missing - Append exclusions for missing ciphers */ + +static const char *tls_exclude_missing(SSL_CTX *ctx, ACL_VSTRING *buf) +{ + const char *myname = "tls_exclude_missing"; + static __thread ACL_ARGV *exclude; /* Cached */ + SSL *s = 0; + + STACK_OF(SSL_CIPHER) * ciphers; + SSL_CIPHER *c; + const cipher_probe_t *probe; + int alg_bits; + int num; + int i; + + /* + * Process a list of probes which specify: + * + * An SSL cipher-suite name for a family of ciphers that use the same + * symmetric algorithm at two or more key sizes, typically 128/256 bits. + * + * The key size (typically 256) that OpenSSL fails to check, and assumes + * available when another key size (typically 128) is usable. + * + * The OpenSSL name of the symmetric algorithm associated with the SSL + * cipher-suite. Typically, this is MUMBLE-256-CBC, where "MUMBLE" is the + * name of the SSL cipher-suite that use the MUMBLE symmetric algorithm. + * On systems that support the required encryption algorithm, the name is + * listed in the output of "openssl list-cipher-algorithms". + * + * When an encryption algorithm is not available at the given key size but + * the corresponding OpenSSL cipher-suite contains ciphers that have have + * this key size, the problem ciphers are explicitly disabled in Postfix. + * The list is cached in the static "exclude" array. + */ + if (exclude == 0) { + exclude = acl_argv_alloc(1); + acl_pthread_atexit_add(exclude, free_argv_fn); + + /* + * Iterate over the probe list + */ + for (probe = cipher_probes; probe->ssl_name; ++probe) { + /* No exclusions if evp_name is a valid algorithm */ + if (EVP_get_cipherbyname(probe->evp_name)) + continue; + + /* + * Sadly there is no SSL_CTX_get_ciphers() interface, so we are + * forced to allocate and free an SSL object. Fatal error if we + * can't allocate the SSL object. + */ + ERR_clear_error(); + if (s == 0 && (s = SSL_new(ctx)) == 0) { + tls_print_errors(); + acl_msg_fatal("%s: error allocating SSL object", myname); + } + + /* + * Cipher is not supported by libcrypto, nothing to do if also + * not supported by libssl. Flush the OpenSSL error stack. + * + * XXX: There may be additional places in pre-existing code where + * SSL errors are generated and ignored, that require a similar + * "flush". Better yet, is to always flush before calls that run + * tls_print_errors() on failure. + * + * Contrary to documentation, on SunOS 5.10 SSL_set_cipher_list() + * returns success with no ciphers selected, when this happens + * SSL_get_ciphers() produces a stack with 0 elements! + */ + if (SSL_set_cipher_list(s, probe->ssl_name) == 0 + || (ciphers = SSL_get_ciphers(s)) == 0 + || (num = sk_SSL_CIPHER_num(ciphers)) == 0) { + ERR_clear_error(); /* flush any generated errors */ + continue; + } + for (i = 0; i < num; ++i) { + c = sk_SSL_CIPHER_value(ciphers, i); + (void) SSL_CIPHER_get_bits(c, &alg_bits); + if (alg_bits == probe->alg_bits) + acl_argv_add(exclude, SSL_CIPHER_get_name(c), ACL_ARGV_END); + } + } + if (s != 0) + SSL_free(s); + } + for (i = 0; i < exclude->argc; ++i) + acl_vstring_sprintf_append(buf, ":!%s", exclude->argv[i]); + return (acl_vstring_str(buf)); +} + +/* tls_apply_cipher_list - update SSL_CTX cipher list */ + +static const char *tls_apply_cipher_list(TLS_APPL_STATE *app_ctx, + const char *context, ACL_VSTRING *spec) +{ + const char *new = tls_exclude_missing(app_ctx->ssl_ctx, spec); + + ERR_clear_error(); + if (SSL_CTX_set_cipher_list(app_ctx->ssl_ctx, new) == 0) { + tls_print_errors(); + acl_vstring_sprintf(app_ctx->why, "invalid %s cipher list: \"%s\"", + context, new); + return (0); + } + return (new); +} + +/* tls_protocol_mask - Bitmask of protocols to exclude */ + +int tls_protocol_mask(const char *plist) +{ + char *save; + char *tok; + char *cp; + int code; + int exclude = 0; + int include = 0; + + save = cp = acl_mystrdup(plist); + while ((tok = acl_mystrtok(&cp, "\t\n\r ,:")) != 0) { + if (*tok == '!') + exclude |= code = + name_code(protocol_table, NAME_CODE_FLAG_NONE, ++tok); + else + include |= code = + name_code(protocol_table, NAME_CODE_FLAG_NONE, tok); + if (code == TLS_PROTOCOL_INVALID) + return TLS_PROTOCOL_INVALID; + } + acl_myfree(save); + + /* + * When the include list is empty, use only the explicit exclusions. + * Otherwise, also exclude the complement of the include list from the + * built-in list of known protocols. There is no way to exclude protocols + * we don't know about at compile time, and this is unavoidable because + * the OpenSSL API works with compile-time *exclusion* bit-masks. + */ + return (include ? (exclude | (TLS_KNOWN_PROTOCOLS & ~include)) : exclude); +} + +static void free_vstring_fn(void *arg) +{ + ACL_VSTRING *s = (ACL_VSTRING*) arg; + + acl_vstring_free(s); +} + +/* tls_set_ciphers - Set SSL context cipher list */ + +const char *tls_set_ciphers(TLS_APPL_STATE *app_ctx, const char *context, + const char *grade, const char *exclusions) +{ + const char *myname = "tls_set_ciphers"; + static __thread ACL_VSTRING *buf; + int new_grade; + char *save; + char *cp; + char *tok; + const char *new_list; + + new_grade = tls_cipher_grade(grade); + if (new_grade == TLS_CIPHER_NONE) { + acl_vstring_sprintf(app_ctx->why, "invalid %s cipher grade: \"%s\"", + context, grade); + return (0); + } + if (buf == 0) { + buf = acl_vstring_alloc(10); + acl_pthread_atexit_add(buf, free_vstring_fn); + } + ACL_VSTRING_RESET(buf); + + /* + * Given cached state and identical input, we return the same result. + */ + if (app_ctx->cipher_list) { + if (new_grade == app_ctx->cipher_grade + && strcmp(app_ctx->cipher_exclusions, exclusions) == 0) + return (app_ctx->cipher_list); + + /* Change required, flush cached state */ + app_ctx->cipher_grade = TLS_CIPHER_NONE; + + acl_myfree(app_ctx->cipher_exclusions); + app_ctx->cipher_exclusions = 0; + + acl_myfree(app_ctx->cipher_list); + app_ctx->cipher_list = 0; + } + switch (new_grade) { + case TLS_CIPHER_HIGH: + acl_vstring_strcpy(buf, var_tls_high_clist); + break; + case TLS_CIPHER_MEDIUM: + acl_vstring_strcpy(buf, var_tls_medium_clist); + break; + case TLS_CIPHER_LOW: + acl_vstring_strcpy(buf, var_tls_low_clist); + break; + case TLS_CIPHER_EXPORT: + acl_vstring_strcpy(buf, var_tls_export_clist); + break; + case TLS_CIPHER_NULL: + acl_vstring_strcpy(buf, var_tls_null_clist); + break; + default: + + /* + * The caller MUST provide a valid cipher grade + */ + acl_msg_panic("invalid %s cipher grade: %d", context, new_grade); + } + + /* + * The base lists for each grade can't be empty. + */ + if (ACL_VSTRING_LEN(buf) == 0) + acl_msg_panic("%s: empty \"%s\" cipherlist", myname, grade); + + /* + * Apply locally-specified exclusions. + */ +#define CIPHER_SEP "\t\n\r ,:" + if (exclusions != 0) { + cp = save = acl_mystrdup(exclusions); + while ((tok = acl_mystrtok(&cp, CIPHER_SEP)) != 0) { + + /* + * Can't exclude ciphers that start with modifiers. + */ + if (strchr("!+-@", *tok)) { + acl_vstring_sprintf(app_ctx->why, + "invalid unary '!+-@' in %s cipher " + "exclusion: \"%s\"", context, tok); + return (0); + } + acl_vstring_sprintf_append(buf, ":!%s", tok); + } + acl_myfree(save); + } + if ((new_list = tls_apply_cipher_list(app_ctx, context, buf)) == 0) + return (0); + + /* Cache new state */ + app_ctx->cipher_grade = new_grade; + app_ctx->cipher_exclusions = acl_mystrdup(exclusions); + + return (app_ctx->cipher_list = acl_mystrdup(new_list)); +} + +/* tls_alloc_app_context - allocate TLS application context */ + +TLS_APPL_STATE *tls_alloc_app_context(SSL_CTX *ssl_ctx) +{ + TLS_APPL_STATE *app_ctx; + + app_ctx = (TLS_APPL_STATE *) acl_mymalloc(sizeof(*app_ctx)); + + memset((char *) app_ctx, 0, sizeof(*app_ctx)); + app_ctx->ssl_ctx = ssl_ctx; + + /* See also: cache purging code in tls_set_ciphers(). */ + app_ctx->cipher_grade = TLS_CIPHER_NONE; + app_ctx->cipher_exclusions = 0; + app_ctx->cipher_list = 0; + app_ctx->cache_type = 0; + app_ctx->why = acl_vstring_alloc(1); + + return (app_ctx); +} + +/* tls_free_app_context - Free TLS application context */ + +void tls_free_app_context(TLS_APPL_STATE *app_ctx) +{ + if (app_ctx->ssl_ctx) + SSL_CTX_free(app_ctx->ssl_ctx); + if (app_ctx->cache_type) + acl_myfree(app_ctx->cache_type); + /* See also: cache purging code in tls_set_ciphers(). */ + if (app_ctx->cipher_exclusions) + acl_myfree(app_ctx->cipher_exclusions); + if (app_ctx->cipher_list) + acl_myfree(app_ctx->cipher_list); + if (app_ctx->why) + acl_vstring_free(app_ctx->why); + acl_myfree(app_ctx); +} + +/* tls_alloc_sess_context - allocate TLS session context */ + +TLS_SESS_STATE *tls_alloc_sess_context(int log_level, const char *namaddr) +{ + TLS_SESS_STATE *TLScontext; + + /* + * PORTABILITY: Do not assume that null pointers are all-zero bits. Use + * explicit assignments to initialize pointers. + * + * See the C language FAQ item 5.17, or if you have time to burn, + * http://www.google.com/search?q=zero+bit+null+pointer + * + * However, it's OK to use memset() to zero integer values. + */ + TLScontext = (TLS_SESS_STATE *) acl_mymalloc(sizeof(TLS_SESS_STATE)); + memset((char *) TLScontext, 0, sizeof(*TLScontext)); + TLScontext->con = 0; + TLScontext->internal_bio = 0; + TLScontext->network_bio = 0; + TLScontext->cache_type = 0; + TLScontext->serverid = 0; + TLScontext->peer_CN = 0; + TLScontext->issuer_CN = 0; + TLScontext->peer_fingerprint = 0; + TLScontext->protocol = 0; + TLScontext->cipher_name = 0; + TLScontext->log_level = log_level; + TLScontext->namaddr = acl_lowercase(acl_mystrdup(namaddr)); + + return (TLScontext); +} + +/* tls_free_context - deallocate TLScontext and members */ + +void tls_free_context(TLS_SESS_STATE *TLScontext) +{ + /* + * Free the SSL structure and the BIOs. Warning: the internal_bio is + * connected to the SSL structure and is automatically freed with it. Do + * not free it again (core dump)!! Only free the network_bio. + */ + if (TLScontext->con != 0) + SSL_free(TLScontext->con); + if (TLScontext->network_bio) + BIO_free(TLScontext->network_bio); + + if (TLScontext->namaddr) + acl_myfree(TLScontext->namaddr); + if (TLScontext->serverid) + acl_myfree(TLScontext->serverid); + + if (TLScontext->peer_CN) + acl_myfree(TLScontext->peer_CN); + if (TLScontext->issuer_CN) + acl_myfree(TLScontext->issuer_CN); + if (TLScontext->peer_fingerprint) + acl_myfree(TLScontext->peer_fingerprint); + + acl_myfree(TLScontext); +} + +/* tls_version_split - Split OpenSSL version number into major, minor, ... */ + +static void tls_version_split(long version, TLS_VINFO *info) +{ + + /* + * OPENSSL_VERSION_NUMBER(3): + * + * OPENSSL_VERSION_NUMBER is a numeric release version identifier: + * + * MMNNFFPPS: major minor fix patch status + * + * The status nibble has one of the values 0 for development, 1 to e for + * betas 1 to 14, and f for release. Parsed OpenSSL version number. for + * example + * + * 0x000906000 == 0.9.6 dev 0x000906023 == 0.9.6b beta 3 0x00090605f == + * 0.9.6e release + * + * Versions prior to 0.9.3 have identifiers < 0x0930. Versions between + * 0.9.3 and 0.9.5 had a version identifier with this interpretation: + * + * MMNNFFRBB major minor fix final beta/patch + * + * for example + * + * 0x000904100 == 0.9.4 release 0x000905000 == 0.9.5 dev + * + * Version 0.9.5a had an interim interpretation that is like the current + * one, except the patch level got the highest bit set, to keep continu- + * ity. The number was therefore 0x0090581f. + */ + + if (version < 0x0930) { + info->status = 0; + info->patch = version & 0x0f; + version >>= 4; + info->micro = version & 0x0f; + version >>= 4; + info->minor = version & 0x0f; + version >>= 4; + info->major = version & 0x0f; + } else if (version < 0x00905800L) { + info->patch = version & 0xff; + version >>= 8; + info->status = version & 0xf; + version >>= 4; + info->micro = version & 0xff; + version >>= 8; + info->minor = version & 0xff; + version >>= 8; + info->major = version & 0xff; + } else { + info->status = version & 0xf; + version >>= 4; + info->patch = version & 0xff; + version >>= 8; + info->micro = version & 0xff; + version >>= 8; + info->minor = version & 0xff; + version >>= 8; + info->major = version & 0xff; + if (version < 0x00906000L) + info->patch &= ~0x80; + } +} + +/* tls_check_version - Detect mismatch between headers and library. */ + +void tls_check_version(void) +{ + const char *myname = "tls_check_version"; + TLS_VINFO hdr_info; + TLS_VINFO lib_info; + + tls_version_split(OPENSSL_VERSION_NUMBER, &hdr_info); + tls_version_split(SSLeay(), &lib_info); + + if (lib_info.major != hdr_info.major + || lib_info.minor != hdr_info.minor + || lib_info.micro != hdr_info.micro) + acl_msg_warn("%s: run-time library vs. compile-time header version mismatch: " + "OpenSSL %d.%d.%d may not be compatible with OpenSSL %d.%d.%d", + myname, lib_info.major, lib_info.minor, lib_info.micro, + hdr_info.major, hdr_info.minor, hdr_info.micro); +} + +/* tls_bug_bits - SSL bug compatibility bits for this OpenSSL version */ + +long tls_bug_bits(void) +{ + long bits = SSL_OP_ALL; /* Work around all known bugs */ + +#if OPENSSL_VERSION_NUMBER >= 0x00908000L + long lib_version = SSLeay(); + + /* + * In OpenSSL 0.9.8[ab], enabling zlib compression breaks the padding bug + * work-around, leading to false positives and failed connections. We may + * not interoperate with systems with the bug, but this is better than + * breaking on all 0.9.8[ab] systems that have zlib support enabled. + */ + if (lib_version >= 0x00908000L && lib_version <= 0x0090802fL) { + STACK_OF(SSL_COMP) * comp_methods; + + comp_methods = SSL_COMP_get_compression_methods(); + if (comp_methods != 0 && sk_SSL_COMP_num(comp_methods) > 0) + bits &= ~SSL_OP_TLS_BLOCK_PADDING_BUG; + } +#endif + return (bits); +} + +/* tls_print_errors - print and clear the error stack */ + +void tls_print_errors(void) +{ + const char *myname = "tls_print_errors"; + unsigned long err; + char buffer[1024]; /* XXX */ + const char *file; + const char *data; + int line; + int flags; + unsigned long thread; + + /* + while ((err = ERR_get_error()) != 0) { + ERR_error_string(err, buffer); + acl_msg_warn("%s: TLS library warning: %lu|%s", __FUNCTION__, err, buffer); + } + */ + + thread = CRYPTO_thread_id(); + while ((err = ERR_get_error_line_data(&file, &line, &data, &flags)) != 0) { + ERR_error_string_n(err, buffer, sizeof(buffer)); + if (flags & ERR_TXT_STRING) + acl_msg_warn("%s: TLS library problem: %lu|%s|%s|%d|%s|", + myname, thread, buffer, file, line, data); + else + acl_msg_warn("%s: TLS library problem: %lu|%s|%s|%d|", + myname, thread, buffer, file, line); + } +} + +/* tls_info_callback - callback for logging SSL events via Postfix */ + +void tls_info_callback(const SSL *s, int where, int ret) +{ + char *str; + int w; + + /* Adapted from OpenSSL apps/s_cb.c. */ + + w = where & ~SSL_ST_MASK; + + if (w & SSL_ST_CONNECT) + str = "SSL_connect"; + else if (w & SSL_ST_ACCEPT) + str = "SSL_accept"; + else + str = "unknown"; + + if (where & SSL_CB_LOOP) { + acl_msg_info("%s:%s", str, SSL_state_string_long((const SSL *) s)); + } else if (where & SSL_CB_ALERT) { + str = (where & SSL_CB_READ) ? "read" : "write"; + if ((ret & 0xff) != SSL3_AD_CLOSE_NOTIFY) + acl_msg_info("SSL3 alert %s:%s:%s", str, + SSL_alert_type_string_long(ret), + SSL_alert_desc_string_long(ret)); + } else if (where & SSL_CB_EXIT) { + if (ret == 0) + acl_msg_info("%s:failed in %s", + str, SSL_state_string_long((const SSL *) s)); + else if (ret < 0) { +#ifndef LOG_NON_ERROR_STATES + switch (SSL_get_error((SSL *) s, ret)) { + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_WRITE: + /* Don't log non-error states. */ + break; + default: +#endif + acl_msg_info("%s:error in %s", + str, SSL_state_string_long((SSL *) s)); +#ifndef LOG_NON_ERROR_STATES + } +#endif + } + } +} + + /* + * taken from OpenSSL crypto/bio/b_dump.c. + * + * Modified to save a lot of strcpy and strcat by Matti Aarnio. + * + * Rewritten by Wietse to elimate fixed-size stack buffer, array index + * multiplication and division, sprintf() and strcpy(), and lots of strlen() + * calls. We could make it a little faster by using a fixed-size stack-based + * buffer. + * + * 200412 - use %lx to print pointers, after casting them to unsigned long. + */ + +#define TRUNCATE_SPACE_NULL +#define DUMP_WIDTH 16 +#define VERT_SPLIT 7 + +static void tls_dump_buffer(const unsigned char *start, int len) +{ + ACL_VSTRING *buf = acl_vstring_alloc(100); + const unsigned char *last = start + len - 1; + const unsigned char *row; + const unsigned char *col; + int ch; + +#ifdef TRUNCATE_SPACE_NULL + while (last >= start && (*last == ' ' || *last == 0)) + last--; +#endif + + for (row = start; row <= last; row += DUMP_WIDTH) { + ACL_VSTRING_RESET(buf); + acl_vstring_sprintf(buf, "%04lx ", (unsigned long) (row - start)); + for (col = row; col < row + DUMP_WIDTH; col++) { + if (col > last) { + acl_vstring_strcat(buf, " "); + } else { + ch = *col; + acl_vstring_sprintf_append(buf, "%02x%c", + ch, col - row == VERT_SPLIT ? '|' : ' '); + } + } + ACL_VSTRING_ADDCH(buf, ' '); + for (col = row; col < row + DUMP_WIDTH; col++) { + if (col > last) + break; + ch = *col; + if (!ACL_ISPRINT(ch)) + ch = '.'; + ACL_VSTRING_ADDCH(buf, ch); + if (col - row == VERT_SPLIT) + ACL_VSTRING_ADDCH(buf, ' '); + } + ACL_VSTRING_TERMINATE(buf); + acl_msg_info("%s", acl_vstring_str(buf)); + } +#ifdef TRUNCATE_SPACE_NULL + if ((last + 1) - start < len) + acl_msg_info("%04lx - ", + (unsigned long) ((last + 1) - start)); +#endif + acl_vstring_free(buf); +} + +/* taken from OpenSSL apps/s_cb.c */ + +long tls_bio_dump_cb(BIO *bio, int cmd, const char *argp, int argi, + long unused_argl acl_unused, long ret) +{ + if (cmd == (BIO_CB_READ | BIO_CB_RETURN)) { + acl_msg_info("read from %08lX [%08lX] (%d bytes => %ld (0x%lX))", + (unsigned long) bio, (unsigned long) argp, argi, + ret, (unsigned long) ret); + tls_dump_buffer((const unsigned char *) argp, (int) ret); + } else if (cmd == (BIO_CB_WRITE | BIO_CB_RETURN)) { + acl_msg_info("write to %08lX [%08lX] (%d bytes => %ld (0x%lX))", + (unsigned long) bio, (unsigned long) argp, argi, + ret, (unsigned long) ret); + tls_dump_buffer((const unsigned char *) argp, (int) ret); + } + return (ret); +} + +#else + + /* + * Broken linker workaround. + */ +int tls_dummy_for_broken_linkers; + +#endif diff --git a/lib_tls/tls/tls_params.c b/lib_tls/tls/tls_params.c new file mode 100644 index 000000000..c9fd81f28 --- /dev/null +++ b/lib_tls/tls/tls_params.c @@ -0,0 +1,72 @@ +#include "StdAfx.h" + +#ifdef USE_TLS + +#include "tls.h" +#include "tls_params.h" +#include "tls_private.h" + + /* + * ipc params + */ +int var_ipc_timeout; +int var_ipc_idle_limit; +int var_ipc_ttl_limit; + + /* + * Tunable parameters. + */ +char *var_tls_high_clist; +char *var_tls_medium_clist; +char *var_tls_low_clist; +char *var_tls_export_clist; +char *var_tls_null_clist; +int var_tls_daemon_rand_bytes; +char *var_tls_eecdh_strong; +char *var_tls_eecdh_ultra; +char *var_server_tls_mand_proto; +char *var_server_tls_proto; + +char var_tlsmgr_service[256]; + +/* tls_params_init - Load TLS related config parameters */ + +void tls_params_init(void) +{ + const char *myname = "tls_param_init"; + static ACL_CONFIG_STR_TABLE str_table[] = { + { VAR_TLS_HIGH_CLIST, DEF_TLS_HIGH_CLIST, &var_tls_high_clist }, + { VAR_TLS_MEDIUM_CLIST, DEF_TLS_MEDIUM_CLIST, &var_tls_medium_clist }, + { VAR_TLS_LOW_CLIST, DEF_TLS_LOW_CLIST, &var_tls_low_clist }, + { VAR_TLS_EXPORT_CLIST, DEF_TLS_EXPORT_CLIST, &var_tls_export_clist }, + { VAR_TLS_NULL_CLIST, DEF_TLS_NULL_CLIST, &var_tls_null_clist }, + { VAR_TLS_EECDH_STRONG, DEF_TLS_EECDH_STRONG, &var_tls_eecdh_strong }, + { VAR_TLS_EECDH_ULTRA, DEF_TLS_EECDH_ULTRA, &var_tls_eecdh_ultra }, + + { VAR_SERVER_TLS_MAND_PROTO, DEF_SERVER_TLS_MAND_PROTO, &var_server_tls_mand_proto }, + { VAR_SERVER_TLS_PROTO, DEF_SERVER_TLS_PROTO, &var_server_tls_proto }, + + { 0, 0, 0 }, + }; + static ACL_CONFIG_INT_TABLE int_table[] = { + { VAR_TLS_DAEMON_RAND_BYTES, DEF_TLS_DAEMON_RAND_BYTES, &var_tls_daemon_rand_bytes, 1, 0 }, + + { VAR_IPC_TIMEOUT, DEF_IPC_TIMEOUT, &var_ipc_timeout, 0, 0 }, + { VAR_IPC_IDLE, DEF_IPC_IDLE, &var_ipc_idle_limit, 0, 0 }, + { VAR_IPC_TTL, DEF_IPC_TTL, &var_ipc_ttl_limit, 0, 0 }, + + { 0, 0, 0, 0, 0 }, + }; + static int init_done; + + if (init_done) { + acl_msg_warn("%s: has been called before", myname); + return; + } + init_done = 1; + + acl_get_app_conf_str_table(str_table); + acl_get_app_conf_int_table(int_table); +} + +#endif diff --git a/lib_tls/tls/tls_private.h b/lib_tls/tls/tls_private.h new file mode 100644 index 000000000..321385613 --- /dev/null +++ b/lib_tls/tls/tls_private.h @@ -0,0 +1,164 @@ +#ifndef __TLS_PRIVATE_INCLUDE_H__ +#define __TLS_PRIVATE_INCLUDE_H__ + +#ifdef USE_TLS + +#include "lib_acl.h" +#include "tls.h" +#include +#include "../util/name_code.h" +#include "../util/name_mask.h" + +#define TLS_BIO_BUFSIZE 8192 +#define CCERT_BUFSIZ 256 + +extern const NAME_CODE tls_level_table[]; + +#define tls_level_lookup(s) name_code(tls_level_table, NAME_CODE_FLAG_NONE, (s)) +#define str_tls_level(l) str_name_code(tls_level_table, (l)) + + /* + * Client and Server application contexts + */ +struct TLS_APPL_STATE { + SSL_CTX *ssl_ctx; + char *cache_type; + char *cipher_exclusions; /* Last cipher selection state */ + char *cipher_list; /* Last cipher selection state */ + int cipher_grade; /* Last cipher selection state */ + ACL_VSTRING *why; +}; + + /* + * Protocol selection. + */ +#define TLS_PROTOCOL_INVALID (~0) /* All protocol bits masked */ +#define TLS_PROTOCOL_SSLv2 (1<<0) /* SSLv2 */ +#define TLS_PROTOCOL_SSLv3 (1<<1) /* SSLv3 */ +#define TLS_PROTOCOL_TLSv1 (1<<2) /* TLSv1 */ +#define TLS_KNOWN_PROTOCOLS \ + ( TLS_PROTOCOL_SSLv2 | TLS_PROTOCOL_SSLv3 | TLS_PROTOCOL_TLSv1 ) + +extern int tls_protocol_mask(const char *); + + /* + * Cipher grade selection. + */ +#define TLS_CIPHER_NONE 0 +#define TLS_CIPHER_NULL 1 +#define TLS_CIPHER_EXPORT 2 +#define TLS_CIPHER_LOW 3 +#define TLS_CIPHER_MEDIUM 4 +#define TLS_CIPHER_HIGH 5 + +extern const NAME_CODE tls_cipher_grade_table[]; + +#define tls_cipher_grade(str) \ + name_code(tls_cipher_grade_table, NAME_CODE_FLAG_NONE, (str)) +#define str_tls_cipher_grade(gr) \ + str_name_code(tls_cipher_grade_table, (gr)) + + /* + * Cipher lists with exclusions. + */ +extern const char *tls_set_ciphers(TLS_APPL_STATE *, const char *, + const char *, const char *); + + /* + * tls_session.c + */ +extern ACL_VSTRING *tls_session_passivate(SSL_SESSION *); +extern SSL_SESSION *tls_session_activate(const char *, int); + + /* + * tls_stream.c. + */ +extern void tls_stream_start(ACL_VSTREAM *, TLS_SESS_STATE *); +extern void tls_stream_stop(ACL_VSTREAM *); + + /* + * tls_bio_ops.c: a generic multi-personality driver that retries SSL + * operations until they are satisfied or until a hard error happens. + * Because of its ugly multi-personality user interface we invoke it via + * not-so-ugly single-personality wrappers. + */ +extern int tls_bio(ACL_SOCKET, int, TLS_SESS_STATE *, + int (*) (SSL *), /* handshake */ + int (*) (SSL *, void *, int), /* read */ + int (*) (SSL *, const void *, int), /* write */ + void *, int); + +#define tls_bio_connect(fd, timeout, context) \ + tls_bio((fd), (timeout), (context), SSL_connect, \ + NULL, NULL, NULL, 0) +#define tls_bio_accept(fd, timeout, context) \ + tls_bio((fd), (timeout), (context), SSL_accept, \ + NULL, NULL, NULL, 0) +#define tls_bio_shutdown(fd, timeout, context) \ + tls_bio((fd), (timeout), (context), SSL_shutdown, \ + NULL, NULL, NULL, 0) +#define tls_bio_read(fd, buf, len, timeout, context) \ + tls_bio((fd), (timeout), (context), NULL, \ + SSL_read, NULL, (buf), (len)) +#define tls_bio_write(fd, buf, len, timeout, context) \ + tls_bio((fd), (timeout), (context), NULL, \ + NULL, SSL_write, (buf), (len)) + + /* + * tls_dh.c + */ +extern void tls_set_dh_from_file(const char *, int); +extern DH *tls_tmp_dh_cb(SSL *, int, int); +extern int tls_set_eecdh_curve(SSL_CTX *, const char *); + + /* + * tls_rsa.c + */ +extern RSA *tls_tmp_rsa_cb(SSL *, int, int); + + /* + * tls_verify.c + */ +extern char *tls_peer_CN(X509 *, const TLS_SESS_STATE *); +extern char *tls_issuer_CN(X509 *, const TLS_SESS_STATE *); +extern const char *tls_dns_name(const GENERAL_NAME *, const TLS_SESS_STATE *); +extern char *tls_fingerprint(X509 *, const char *); +extern int tls_verify_certificate_callback(int, X509_STORE_CTX *); + + /* + * tls_certkey.c + */ +extern int tls_set_ca_certificate_info(SSL_CTX *, const char *, const char *); +extern int tls_set_my_certificate_key_info(SSL_CTX *, + /* RSA */ const char *, const char *, + /* DSA */ const char *, const char *, + /* ECDSA */ const char *, const char *); + + /* + * tls_misc.c + */ +extern int TLScontext_index; + +extern TLS_APPL_STATE *tls_alloc_app_context(SSL_CTX *); +extern TLS_SESS_STATE *tls_alloc_sess_context(int, const char *); +extern void tls_free_context(TLS_SESS_STATE *); +extern void tls_check_version(void); +extern long tls_bug_bits(void); +extern void tls_print_errors(void); +extern void tls_info_callback(const SSL *, int, int); +extern long tls_bio_dump_cb(BIO *, int, const char *, int, long, long); + + /* + * tls_seed.c + */ +extern void tls_int_seed(void); +extern int tls_ext_seed(int); + + /* + * tls_threads.c + */ +extern void tls_threads_init(void); + +#endif + +#endif diff --git a/lib_tls/tls/tls_prng.h b/lib_tls/tls/tls_prng.h new file mode 100644 index 000000000..18f173ac9 --- /dev/null +++ b/lib_tls/tls/tls_prng.h @@ -0,0 +1,53 @@ +#ifndef _TLS_PRNG_SRC_H_INCLUDED_ +#define _TLS_PRNG_SRC_H_INCLUDED_ + +/*++ + * NAME + * tls_prng_src 3h + * SUMMARY + * OpenSSL PRNG maintenance routines + * SYNOPSIS + * #include + * DESCRIPTION + * .nf + + * + * External interface. + */ +typedef struct TLS_PRNG_SRC { + union { + ACL_SOCKET sock; /* file handle */ + ACL_FILE_HANDLE file; + } fd; + char *name; /* resource name */ + int timeout; /* time limit of applicable */ +} TLS_PRNG_SRC; + +extern TLS_PRNG_SRC *tls_prng_egd_open(const char *, int); +extern ssize_t tls_prng_egd_read(TLS_PRNG_SRC *, size_t); +extern int tls_prng_egd_close(TLS_PRNG_SRC *); + +extern TLS_PRNG_SRC *tls_prng_dev_open(const char *, int); +extern ssize_t tls_prng_dev_read(TLS_PRNG_SRC *, size_t); +extern int tls_prng_dev_close(TLS_PRNG_SRC *); + +extern TLS_PRNG_SRC *tls_prng_file_open(const char *, int); +extern ssize_t tls_prng_file_read(TLS_PRNG_SRC *, size_t); +extern int tls_prng_file_close(TLS_PRNG_SRC *); + +extern TLS_PRNG_SRC *tls_prng_exch_open(const char *); +extern void tls_prng_exch_update(TLS_PRNG_SRC *); +extern void tls_prng_exch_close(TLS_PRNG_SRC *); + +/* LICENSE + * .ad + * .fi + * The Secure Mailer license must be distributed with this software. + * AUTHOR(S) + * Wietse Venema + * IBM T.J. Watson Research + * P.O. Box 704 + * Yorktown Heights, NY 10598, USA + *--*/ + +#endif diff --git a/lib_tls/tls/tls_prng_dev.c b/lib_tls/tls/tls_prng_dev.c new file mode 100644 index 000000000..d0c4dad1a --- /dev/null +++ b/lib_tls/tls/tls_prng_dev.c @@ -0,0 +1,153 @@ +/*++ + * NAME + * tls_prng_dev 3 + * SUMMARY + * seed OpenSSL PRNG from entropy device + * SYNOPSIS + * #include + * + * TLS_PRNG_SRC *tls_prng_dev_open(name, timeout) + * const char *name; + * int timeout; + * + * ssize_t tls_prng_dev_read(dev, length) + * TLS_PRNG_SRC *dev; + * size_t length; + * + * int tls_prng_dev_close(dev) + * TLS_PRNG_SRC *dev; + * DESCRIPTION + * tls_prng_dev_open() opens the specified entropy device + * and returns a handle that should be used with all subsequent + * access. + * + * tls_prng_dev_read() reads the requested number of bytes from + * the entropy device and updates the OpenSSL PRNG. + * + * tls_prng_dev_close() closes the specified entropy device + * and releases memory that was allocated for the handle. + * + * Arguments: + * .IP name + * The pathname of the entropy device. + * .IP length + * The number of bytes to read from the entropy device. + * Request lengths will be truncated at 255 bytes. + * .IP timeout + * Time limit on individual I/O operations. + * DIAGNOSTICS + * tls_prng_dev_open() returns a null pointer on error. + * + * tls_prng_dev_read() returns -1 on error, the number + * of bytes received on success. + * + * tls_prng_dev_close() returns -1 on error, 0 on success. + * + * In all cases the errno variable indicates the type of error. + * LICENSE + * .ad + * .fi + * The Secure Mailer license must be distributed with this software. + * AUTHOR(S) + * Wietse Venema + * IBM T.J. Watson Research + * P.O. Box 704 + * Yorktown Heights, NY 10598, USA + *--*/ + +#include "StdAfx.h" +#include +#ifdef ACL_UNIX +#include +#endif +#include +#include + +#ifndef UCHAR_MAX +#define UCHAR_MAX 0xff +#endif + +/* OpenSSL library. */ + +#ifdef USE_TLS +#include /* For the PRNG */ + +/* TLS library. */ + +#include "tls_prng.h" + +/* tls_prng_dev_open - open entropy device */ + +TLS_PRNG_SRC *tls_prng_dev_open(const char *name, int timeout) +{ + const char *myname = "tls_prng_dev_open"; + TLS_PRNG_SRC *dev; + ACL_FILE_HANDLE fd; + + if ((fd = acl_file_open(name, O_RDONLY, 0)) < 0) { + if (acl_msg_verbose) + acl_msg_info("%s: cannot open entropy device %s: %s", + myname, name, acl_last_serror()); + return (0); + } else { + dev = (TLS_PRNG_SRC *) acl_mymalloc(sizeof(*dev)); + dev->fd.file = fd; + dev->name = acl_mystrdup(name); + dev->timeout = timeout; + if (acl_msg_verbose) + acl_msg_info("%s: opened entropy device %s", myname, name); + return (dev); + } +} + +/* tls_prng_dev_read - update internal PRNG from device */ + +ssize_t tls_prng_dev_read(TLS_PRNG_SRC *dev, size_t len) +{ + const char *myname = "tls_prng_dev_read"; + unsigned char buffer[UCHAR_MAX]; + ssize_t count; + size_t rand_bytes; + + if (len <= 0) + acl_msg_panic("%s: bad read length: %ld", myname, (long) len); + + if (len > sizeof(buffer)) + rand_bytes = sizeof(buffer); + else + rand_bytes = len; + errno = 0; +#ifdef ACL_UNIX + count = acl_timed_read(dev->fd.file, buffer, (int) rand_bytes, dev->timeout, (void *) 0); +#elif defined(ACL_MS_WINDOWS) + count = acl_file_read(dev->fd.file, buffer, (int) rand_bytes, dev->timeout, (void *) 0); +#endif + if (count > 0) { + if (acl_msg_verbose) + acl_msg_info("%s: read %ld bytes from entropy device %s", + myname, (long) count, dev->name); + RAND_seed(buffer, count); + } else { + if (acl_msg_verbose) + acl_msg_info("%s: cannot read %ld bytes from entropy device %s: %s", + myname, (long) rand_bytes, dev->name, acl_last_serror()); + } + return (count); +} + +/* tls_prng_dev_close - disconnect from EGD server */ + +int tls_prng_dev_close(TLS_PRNG_SRC *dev) +{ + const char *myname = "tls_prng_dev_close"; + int err; + + if (acl_msg_verbose) + acl_msg_info("%s: close entropy device %s", myname, dev->name); + err = acl_file_close(dev->fd.file); + acl_myfree(dev->name); + acl_myfree(dev); + return (err); +} + +#endif diff --git a/lib_tls/tls/tls_prng_egd.c b/lib_tls/tls/tls_prng_egd.c new file mode 100644 index 000000000..7fc0e4729 --- /dev/null +++ b/lib_tls/tls/tls_prng_egd.c @@ -0,0 +1,168 @@ +/*++ + * NAME + * tls_prng_egd 3 + * SUMMARY + * seed OpenSSL PRNG from EGD server + * SYNOPSIS + * #include + * + * TLS_PRNG_SRC *tls_prng_egd_open(name, timeout) + * const char *name; + * int timeout; + * + * ssize_t tls_prng_egd_read(egd, length) + * TLS_PRNG_SRC *egd; + * size_t length; + * + * int tls_prng_egd_close(egd) + * TLS_PRNG_SRC *egd; + * DESCRIPTION + * tls_prng_egd_open() connect to the specified UNIX-domain service + * and returns a handle that should be used with all subsequent + * access. + * + * tls_prng_egd_read() reads the requested number of bytes from + * the EGD server and updates the OpenSSL PRNG. + * + * tls_prng_egd_close() disconnects from the specified EGD server + * and releases memory that was allocated for the handle. + * + * Arguments: + * .IP name + * The UNIX-domain pathname of the EGD service. + * .IP length + * The number of bytes to read from the EGD server. + * Request lengths will be truncated at 255 bytes. + * .IP timeout + * Time limit on individual I/O operations. + * DIAGNOSTICS + * tls_prng_egd_open() returns a null pointer on error. + * + * tls_prng_egd_read() returns -1 on error, the number + * of bytes received on success. + * + * tls_prng_egd_close() returns -1 on error, 0 on success. + * + * In all cases the errno variable indicates the type of error. + * LICENSE + * .ad + * .fi + * The Secure Mailer license must be distributed with this software. + * AUTHOR(S) + * Wietse Venema + * IBM T.J. Watson Research + * P.O. Box 704 + * Yorktown Heights, NY 10598, USA + *--*/ + +#include "StdAfx.h" +#ifdef ACL_UNIX +#include +#endif +#include + +#ifndef UCHAR_MAX +#define UCHAR_MAX 0xff +#endif + +/* OpenSSL library. */ + +#ifdef USE_TLS +#include /* For the PRNG */ + +/* TLS library. */ + +#include "tls_prng.h" + +/* tls_prng_egd_open - connect to EGD server */ + +TLS_PRNG_SRC *tls_prng_egd_open(const char *name, int timeout) +{ + const char *myname = "tls_prng_egd_open"; + TLS_PRNG_SRC *egd; + ACL_SOCKET fd; + + if (acl_msg_verbose) + acl_msg_info("%s: connect to EGD server %s", myname, name); + +#ifdef ACL_UNIX + fd = acl_unix_connect(name, ACL_BLOCKING, timeout); +#elif defined(ACL_MS_WINDOWS) + fd = acl_inet_connect(name, ACL_BLOCKING, timeout); +#endif + + if (fd < 0) { + if (acl_msg_verbose) + acl_msg_info("%s: cannot connect to EGD server %s: %s", + myname, name, acl_last_serror()); + return (0); + } else { + egd = (TLS_PRNG_SRC *) acl_mymalloc(sizeof(*egd)); + egd->fd.sock = fd; + egd->name = acl_mystrdup(name); + egd->timeout = timeout; + if (acl_msg_verbose) + acl_msg_info("%s: connected to EGD server %s", myname, name); + return (egd); + } +} + +/* tls_prng_egd_read - update internal PRNG from EGD server */ + +ssize_t tls_prng_egd_read(TLS_PRNG_SRC *egd, size_t len) +{ + const char *myname = "tls_prng_egd_read"; + unsigned char buffer[UCHAR_MAX]; + ssize_t count; + + if (len <= 0) + acl_msg_panic("%s: bad length %ld", myname, (long) len); + + buffer[0] = 1; + buffer[1] = (unsigned char) (len > UCHAR_MAX ? UCHAR_MAX : len); + + if (acl_timed_write(egd->fd.sock, buffer, 2, egd->timeout, (void *) 0) != 2) { + acl_msg_info("%s: cannot write to EGD server %s: %s", + myname, egd->name, acl_last_serror()); + return (-1); + } + if (acl_timed_read(egd->fd.sock, buffer, 1, egd->timeout, (void *) 0) != 1) { + acl_msg_info("%s: cannot read from EGD server %s: %s", + myname, egd->name, acl_last_serror()); + return (-1); + } + count = buffer[0]; + if (count > (ssize_t) sizeof(buffer)) + count = sizeof(buffer); + if (count == 0) { + acl_msg_info("EGD server %s reports zero bytes available", egd->name); + return (-1); + } + if (acl_timed_read(egd->fd.sock, buffer, count, egd->timeout, (void *) 0) != count) { + acl_msg_info("%s: cannot read %ld bytes from EGD server %s: %s", + myname, (long) count, egd->name, acl_last_serror()); + return (-1); + } + if (acl_msg_verbose) + acl_msg_info("%s: got %ld bytes from EGD server %s", myname, + (long) count, egd->name); + RAND_seed(buffer, count); + return (count); +} + +/* tls_prng_egd_close - disconnect from EGD server */ + +int tls_prng_egd_close(TLS_PRNG_SRC *egd) +{ + const char *myname = "tls_prng_egd_close"; + int err; + + if (acl_msg_verbose) + acl_msg_info("%s: close EGD server %s", myname, egd->name); + err = acl_file_close(egd->fd.file); + acl_myfree(egd->name); + acl_myfree(egd); + return (err); +} + +#endif diff --git a/lib_tls/tls/tls_prng_exch.c b/lib_tls/tls/tls_prng_exch.c new file mode 100644 index 000000000..23abeac61 --- /dev/null +++ b/lib_tls/tls/tls_prng_exch.c @@ -0,0 +1,144 @@ +/*++ + * NAME + * tls_prng_exch 3 + * SUMMARY + * maintain PRNG exchange file + * SYNOPSIS + * #include + * + * TLS_PRNG_SRC *tls_prng_exch_open(name, timeout) + * const char *name; + * int timeout; + * + * void tls_prng_exch_update(fh, length) + * TLS_PRNG_SRC *fh; + * size_t length; + * + * void tls_prng_exch_close(fh) + * TLS_PRNG_SRC *fh; + * DESCRIPTION + * tls_prng_exch_open() opens the specified PRNG exchange file + * and returns a handle that should be used with all subsequent + * access. + * + * tls_prng_exch_update() reads the requested number of bytes + * from the PRNG exchange file, updates the OpenSSL PRNG, and + * writes the requested number of bytes to the exchange file. + * The file is locked for exclusive access. + * + * tls_prng_exch_close() closes the specified PRNG exchange + * file and releases memory that was allocated for the handle. + * + * Arguments: + * .IP name + * The name of the PRNG exchange file. + * .IP length + * The number of bytes to read from/write to the entropy file. + * .IP timeout + * Time limit on individual I/O operations. + * DIAGNOSTICS + * All errors are fatal. + * LICENSE + * .ad + * .fi + * The Secure Mailer license must be distributed with this software. + * AUTHOR(S) + * Wietse Venema + * IBM T.J. Watson Research + * P.O. Box 704 + * Yorktown Heights, NY 10598, USA + *--*/ + +#include "StdAfx.h" +#include +#ifdef ACL_UNIX +#include +#endif +#include + +/* OpenSSL library. */ + +#ifdef USE_TLS +#include /* For the PRNG */ + +/* TLS library. */ + +#include "tls_prng.h" + +/* Application specific. */ + +#define TLS_PRNG_EXCH_SIZE 1024 /* XXX Why not configurable? */ + +/* tls_prng_exch_open - open PRNG exchange file */ + +TLS_PRNG_SRC *tls_prng_exch_open(const char *name) +{ + const char *myname = "tls_prng_exch_open"; + TLS_PRNG_SRC *eh; + ACL_FILE_HANDLE fd; + + if ((fd = acl_file_open(name, O_RDWR | O_CREAT, 0600)) < 0) + acl_msg_fatal("%s: cannot open PRNG exchange file %s: %s", + myname, name, acl_last_serror()); + eh = (TLS_PRNG_SRC *) acl_mymalloc(sizeof(*eh)); + eh->fd.file = fd; + eh->name = acl_mystrdup(name); + eh->timeout = 0; + if (acl_msg_verbose) + acl_msg_info("%s: opened PRNG exchange file %s", myname, name); + return (eh); +} + +/* tls_prng_exch_update - update PRNG exchange file */ + +void tls_prng_exch_update(TLS_PRNG_SRC *eh) +{ + const char *myname = "tls_prng_exch_update"; + unsigned char buffer[TLS_PRNG_EXCH_SIZE]; + ssize_t count; + + /* + * Update the PRNG exchange file. Since other processes may have added + * entropy, we use a read-stir-write cycle. + */ + if (acl_myflock(eh->fd.file, ACL_INTERNAL_LOCK, ACL_MYFLOCK_OP_EXCLUSIVE) != 0) + acl_msg_fatal("%s: cannot lock PRNG exchange file %s: %s", + myname, eh->name, acl_last_serror()); + if (acl_lseek(eh->fd.file, 0, SEEK_SET) < 0) + acl_msg_fatal("%s: cannot seek PRNG exchange file %s: %s", + myname, eh->name, acl_last_serror()); + if ((count = acl_file_read(eh->fd.file, buffer, sizeof(buffer), 0, NULL)) < 0) + acl_msg_fatal("%s: cannot read PRNG exchange file %s: %s", + myname, eh->name, acl_last_serror()); + + if (count > 0) + RAND_seed(buffer, count); + RAND_bytes(buffer, sizeof(buffer)); + + if (acl_lseek(eh->fd.file, 0, SEEK_SET) < 0) + acl_msg_fatal("%s: cannot seek PRNG exchange file %s: %s", + myname, eh->name, acl_last_serror()); + if (acl_file_write(eh->fd.file, buffer, sizeof(buffer), 0, NULL) != sizeof(buffer)) + acl_msg_fatal("%s: cannot write PRNG exchange file %s: %s", + myname, eh->name, acl_last_serror()); + if (acl_myflock(eh->fd.file, ACL_INTERNAL_LOCK, ACL_MYFLOCK_OP_NONE) != 0) + acl_msg_fatal("%s: cannot unlock PRNG exchange file %s: %s", + myname, eh->name, acl_last_serror()); +} + +/* tls_prng_exch_close - close PRNG exchange file */ + +void tls_prng_exch_close(TLS_PRNG_SRC *eh) +{ + const char *myname = "tls_prng_exch_close"; + + if (acl_file_close(eh->fd.file) < 0) + acl_msg_fatal("%s: close PRNG exchange file %s: %s", + myname, eh->name, acl_last_serror()); + if (acl_msg_verbose) + acl_msg_info("%s: closed PRNG exchange file %s", myname, eh->name); + acl_myfree(eh->name); + acl_myfree(eh); +} + +#endif diff --git a/lib_tls/tls/tls_prng_file.c b/lib_tls/tls/tls_prng_file.c new file mode 100644 index 000000000..ea8dd5e5c --- /dev/null +++ b/lib_tls/tls/tls_prng_file.c @@ -0,0 +1,158 @@ +/*++ + * NAME + * tls_prng_file 3 + * SUMMARY + * seed OpenSSL PRNG from entropy file + * SYNOPSIS + * #include + * + * TLS_PRNG_SRC *tls_prng_file_open(name, timeout) + * const char *name; + * int timeout; + * + * ssize_t tls_prng_file_read(fh, length) + * TLS_PRNG_SRC *fh; + * size_t length; + * + * int tls_prng_file_close(fh) + * TLS_PRNG_SRC *fh; + * DESCRIPTION + * tls_prng_file_open() open the specified file and returns + * a handle that should be used with all subsequent access. + * + * tls_prng_file_read() reads the requested number of bytes from + * the entropy file and updates the OpenSSL PRNG. The file is not + * locked for shared or exclusive access. + * + * tls_prng_file_close() closes the specified entropy file + * and releases memory that was allocated for the handle. + * + * Arguments: + * .IP name + * The pathname of the entropy file. + * .IP length + * The number of bytes to read from the entropy file. + * .IP timeout + * Time limit on individual I/O operations. + * DIAGNOSTICS + * tls_prng_file_open() returns a null pointer on error. + * + * tls_prng_file_read() returns -1 on error, the number + * of bytes received on success. + * + * tls_prng_file_close() returns -1 on error, 0 on success. + * + * In all cases the errno variable indicates the type of error. + * LICENSE + * .ad + * .fi + * The Secure Mailer license must be distributed with this software. + * AUTHOR(S) + * Wietse Venema + * IBM T.J. Watson Research + * P.O. Box 704 + * Yorktown Heights, NY 10598, USA + *--*/ + +#include "StdAfx.h" +#include +#ifdef ACL_UNIX +#include +#endif +#include +#include + +/* OpenSSL library. */ + +#ifdef USE_TLS +#include /* For the PRNG */ + +/* TLS library. */ + +#include "tls_prng.h" + +/* tls_prng_file_open - open entropy file */ + +TLS_PRNG_SRC *tls_prng_file_open(const char *name, int timeout) +{ + const char *myname = "tls_prng_file_open"; + TLS_PRNG_SRC *fh; + ACL_FILE_HANDLE fd; + + if ((fd = acl_file_open(name, O_RDONLY, 0)) < 0) { + if (acl_msg_verbose) + acl_msg_info("%s: cannot open entropy file %s: %s", + myname, name, acl_last_serror()); + return (0); + } else { + fh = (TLS_PRNG_SRC *) acl_mymalloc(sizeof(*fh)); + fh->fd.file = fd; + fh->name = acl_mystrdup(name); + fh->timeout = timeout; + if (acl_msg_verbose) + acl_msg_info("%s: opened entropy file %s", myname, name); + return (fh); + } +} + +/* tls_prng_file_read - update internal PRNG from entropy file */ + +ssize_t tls_prng_file_read(TLS_PRNG_SRC *fh, size_t len) +{ + const char *myname = "tls_prng_file_read"; + char buffer[8192]; + ssize_t to_read; + ssize_t count; + + if (acl_msg_verbose) + acl_msg_info("%s: seed internal pool from file %s", myname, fh->name); + + if (acl_lseek(fh->fd.file, 0, SEEK_SET) < 0) { + if (acl_msg_verbose) + acl_msg_info("%s: cannot seek entropy file %s: %s", + myname, fh->name, acl_last_serror()); + return (-1); + } + errno = 0; + for (to_read = (ssize_t) len; to_read > 0; to_read -= count) { +#ifdef ACL_UNIX + count = acl_timed_read(fh->fd.file, buffer, to_read > (ssize_t) sizeof(buffer) ? + (ssize_t) sizeof(buffer) : to_read, + fh->timeout, (void *) 0); +#elif defined(ACL_MS_WINDOWS) + count = acl_file_read(fh->fd.file, buffer, to_read > (ssize_t) sizeof(buffer) ? + (ssize_t) sizeof(buffer) : to_read, + fh->timeout, (void *) 0); +#endif + if (count < 0) { + if (acl_msg_verbose) + acl_msg_info("%s: cannot read entropy file %s: %s", + myname, fh->name, acl_last_serror()); + return (-1); + } + if (count == 0) + break; + RAND_seed(buffer, count); + } + if (acl_msg_verbose) + acl_msg_info("%s: read %ld bytes from entropy file %s: %s", + myname, (long) (len - to_read), fh->name, acl_last_serror()); + return ((ssize_t) (len - to_read)); +} + +/* tls_prng_file_close - close entropy file */ + +int tls_prng_file_close(TLS_PRNG_SRC *fh) +{ + const char *myname = "tls_prng_file_close"; + int err; + + if (acl_msg_verbose) + acl_msg_info("%s: close entropy file %s", myname, fh->name); + err = acl_file_close(fh->fd.file); + acl_myfree(fh->name); + acl_myfree(fh); + return (err); +} + +#endif diff --git a/lib_tls/tls/tls_rsa.c b/lib_tls/tls/tls_rsa.c new file mode 100644 index 000000000..8a1d0b5ce --- /dev/null +++ b/lib_tls/tls/tls_rsa.c @@ -0,0 +1,83 @@ +/*++ + * NAME + * tls_rsa + * SUMMARY + * RSA support + * SYNOPSIS + * #include + * #include + * + * RSA *tls_tmp_rsa_cb(ssl, export, keylength) + * SSL *ssl; # unused + * int export; + * int keylength; + * DESCRIPTION + * This module maintains parameters for Diffie-Hellman key generation. + * + * tls_tmp_rsa_cb() is a call-back routine for the + * SSL_CTX_set_tmp_rsa_callback() function. + * LICENSE + * .ad + * .fi + * This software is free. You can do with it whatever you want. + * The original author kindly requests that you acknowledge + * the use of his software. + * AUTHOR(S) + * Originally written by: + * Lutz Jaenicke + * BTU Cottbus + * Allgemeine Elektrotechnik + * Universitaetsplatz 3-4 + * D-03044 Cottbus, Germany + * + * Updated by: + * Wietse Venema + * IBM T.J. Watson Research + * P.O. Box 704 + * Yorktown Heights, NY 10598, USA + *--*/ + +#include "StdAfx.h" + +#ifdef USE_TLS + +/* TLS library. */ + +#include "tls.h" +#include "tls_private.h" + +static void free_rsa_fn(void *arg) +{ + RSA *rsa = (RSA*) arg; + + RSA_free(rsa); +} + +/* tls_tmp_rsa_cb - call-back to generate ephemeral RSA key */ + +RSA *tls_tmp_rsa_cb(SSL *unused_ssl acl_unused, int unused_export acl_unused, int keylength) +{ + static __thread RSA *rsa_tmp; + + /* Code adapted from OpenSSL apps/s_cb.c */ + + if (rsa_tmp == 0) { + rsa_tmp = RSA_generate_key(keylength, RSA_F4, NULL, NULL); + acl_pthread_atexit_add(rsa_tmp, free_rsa_fn); + } + return (rsa_tmp); +} + +#ifdef TEST + +int main(int unused_argc, char **unused_argv) +{ + tls_tmp_rsa_cb(0, 1, 512); + tls_tmp_rsa_cb(0, 1, 1024); + tls_tmp_rsa_cb(0, 1, 2048); + tls_tmp_rsa_cb(0, 0, 512); +} + +#endif + +#endif diff --git a/lib_tls/tls/tls_scache.c b/lib_tls/tls/tls_scache.c new file mode 100644 index 000000000..822ba63e8 --- /dev/null +++ b/lib_tls/tls/tls_scache.c @@ -0,0 +1,515 @@ +/*++ + * NAME + * tls_scache 3 + * SUMMARY + * TLS session cache manager + * SYNOPSIS + * #include + * + * TLS_SCACHE *tls_scache_open(dbname, cache_label, verbose, timeout) + * const char *dbname + * const char *cache_label; + * int verbose; + * int timeout; + * + * void tls_scache_close(cache) + * TLS_SCACHE *cache; + * + * int tls_scache_lookup(cache, cache_id, out_session) + * TLS_SCACHE *cache; + * const char *cache_id; + * ACL_VSTRING *out_session; + * + * int tls_scache_update(cache, cache_id, session, session_len) + * TLS_SCACHE *cache; + * const char *cache_id; + * const char *session; + * ssize_t session_len; + * + * int tls_scache_sequence(cache, first_next, out_cache_id, + * ACL_VSTRING *out_session) + * TLS_SCACHE *cache; + * int first_next; + * char **out_cache_id; + * ACL_VSTRING *out_session; + * + * int tls_scache_delete(cache, cache_id) + * TLS_SCACHE *cache; + * const char *cache_id; + * DESCRIPTION + * This module maintains Postfix TLS session cache files. + * each session is stored under a lookup key (hostname or + * session ID). + * + * tls_scache_open() opens the specified TLS session cache + * and returns a handle that must be used for subsequent + * access. + * + * tls_scache_close() closes the specified TLS session cache + * and releases memory that was allocated by tls_scache_open(). + * + * tls_scache_lookup() looks up the specified session in the + * specified cache, and applies session timeout restrictions. + * Entries that are too old are silently deleted. + * + * tls_scache_update() updates the specified TLS session cache + * with the specified session information. + * + * tls_scache_sequence() iterates over the specified TLS session + * cache and either returns the first or next entry that has not + * timed out, or returns no data. Entries that are too old are + * silently deleted. Specify TLS_SCACHE_SEQUENCE_NOTHING as the + * third and last argument to disable saving of cache entry + * content or cache entry ID information. This is useful when + * purging expired entries. A result value of zero means that + * the end of the cache was reached. + * + * tls_scache_delete() removes the specified cache entry from + * the specified TLS session cache. + * + * Arguments: + * .IP dbname + * The base name of the session cache file. + * .IP cache_label + * A string that is used in logging and error messages. + * .IP verbose + * Do verbose logging of cache operations? (zero == no) + * .IP timeout + * The time after wich a session cache entry is considered too old. + * .IP first_next + * One of DICT_SEQ_FUN_FIRST (first cache element) or DICT_SEQ_FUN_NEXT + * (next cache element). + * .IP cache_id + * Session cache lookup key. + * .IP session + * Storage for session information. + * .IP session_len + * The size of the session information in bytes. + * .IP out_cache_id + * .IP out_session + * Storage for saving the cache_id or session information of the + * current cache entry. + * + * Specify TLS_SCACHE_DONT_NEED_CACHE_ID to avoid saving + * the session cache ID of the cache entry. + * + * Specify TLS_SCACHE_DONT_NEED_SESSION to avoid + * saving the session information in the cache entry. + * DIAGNOSTICS + * These routines terminate with a fatal run-time error + * for unrecoverable database errors. This allows the + * program to restart and reset the database to an + * empty initial state. + * + * tls_scache_open() never returns on failure. All other + * functions return non-zero on success, zero when the + * operation could not be completed. + * LICENSE + * .ad + * .fi + * The Secure Mailer license must be distributed with this software. + * AUTHOR(S) + * Wietse Venema + * IBM T.J. Watson Research + * P.O. Box 704 + * Yorktown Heights, NY 10598, USA + *--*/ + +#include "StdAfx.h" + +#ifdef USE_TLS + +#include +#include + +#include "dict.h" + +/* Global library. */ + +/* TLS library. */ + +#include "tls_scache.h" + +/* Application-specific. */ + + /* + * Session cache entry format. + */ +typedef struct { + time_t timestamp; /* time when saved */ + char session[1]; /* actually a bunch of bytes */ +} TLS_SCACHE_ENTRY; + + /* + * SLMs. + */ +#define STR(x) acl_vstring_str(x) +#define LEN(x) ACL_VSTRING_LEN(x) + +/* tls_scache_encode - encode TLS session cache entry */ + +static ACL_VSTRING *tls_scache_encode(TLS_SCACHE *cp, const char *cache_id, + const char *session, ssize_t session_len) +{ + TLS_SCACHE_ENTRY *entry; + ACL_VSTRING *hex_data; + ssize_t binary_data_len; + + /* + * Assemble the TLS session cache entry. + * + * We could eliminate some copying by using incremental encoding, but + * sessions are so small that it really does not matter. + */ + binary_data_len = session_len + offsetof(TLS_SCACHE_ENTRY, session); + entry = (TLS_SCACHE_ENTRY *) acl_mymalloc(binary_data_len); + entry->timestamp = time((time_t *) 0); + memcpy(entry->session, session, session_len); + + /* + * Encode the TLS session cache entry. + */ + hex_data = acl_vstring_alloc(2 * binary_data_len + 1); + acl_hex_encode(hex_data, (char *) entry, binary_data_len); + + /* + * Logging. + */ + if (cp->verbose) + acl_msg_info("write %s TLS cache entry %s: time=%ld [data %ld bytes]", + cp->cache_label, cache_id, (long) entry->timestamp, + (long) session_len); + + /* + * Clean up. + */ + acl_myfree(entry); + + return (hex_data); +} + +/* tls_scache_decode - decode TLS session cache entry */ + +static int tls_scache_decode(TLS_SCACHE *cp, const char *cache_id, + const char *hex_data, ssize_t hex_data_len, ACL_VSTRING *out_session) +{ + const char *myname = "tls+scache_decode"; + TLS_SCACHE_ENTRY *entry; + ACL_VSTRING *bin_data; + + /* + * Sanity check. + */ + if (hex_data_len < (ssize_t) (2 * (offsetof(TLS_SCACHE_ENTRY, session)))) { + acl_msg_warn("%s: %s TLS cache: truncated entry for %s: %.100s", + myname, cp->cache_label, cache_id, hex_data); + return (0); + } + + /* + * Disassemble the TLS session cache entry. + * + * No early returns or we have a memory leak. + */ +#define FREE_AND_RETURN(ptr, x) { acl_vstring_free(ptr); return (x); } + + bin_data = acl_vstring_alloc(hex_data_len / 2 + 1); + if (acl_hex_decode(bin_data, hex_data, hex_data_len) == 0) { + acl_msg_warn("%s: %s TLS cache: malformed entry for %s: %.100s", + myname, cp->cache_label, cache_id, hex_data); + FREE_AND_RETURN(bin_data, 0); + } + entry = (TLS_SCACHE_ENTRY *) STR(bin_data); + + /* + * Logging. + */ + if (cp->verbose) + acl_msg_info("read %s TLS cache entry %s: time=%ld [data %ld bytes]", + cp->cache_label, cache_id, (long) entry->timestamp, + (long) (LEN(bin_data) - offsetof(TLS_SCACHE_ENTRY, session))); + + /* + * Other mandatory restrictions. + */ + if (entry->timestamp + cp->timeout < time((time_t *) 0)) + FREE_AND_RETURN(bin_data, 0); + + /* + * Optional output. + */ + if (out_session != 0) + acl_vstring_memcpy(out_session, entry->session, + LEN(bin_data) - offsetof(TLS_SCACHE_ENTRY, session)); + + /* + * Clean up. + */ + FREE_AND_RETURN(bin_data, 1); +} + +/* tls_scache_lookup - load session from cache */ + +int tls_scache_lookup(TLS_SCACHE *cp, char *cache_id, ACL_VSTRING *session) +{ + char *hex_data; + size_t size; + + /* + * Logging. + */ + if (cp->verbose) + acl_msg_info("lookup %s session id=%s", cp->cache_label, cache_id); + + /* + * Initialize. Don't leak data. + */ + if (session) + ACL_VSTRING_RESET(session); + + /* + * Search the cache database. + */ + if ((DICT_GET(cp->db, cache_id, strlen(cache_id), &hex_data, &size)) == 0) + return (0); + + /* + * Decode entry and delete if expired or malformed. + */ + if (tls_scache_decode(cp, cache_id, hex_data, (int) strlen(hex_data), session) == 0) { + tls_scache_delete(cp, cache_id); + acl_myfree(hex_data); + return (0); + } else { + acl_myfree(hex_data); + return (1); + } +} + +/* tls_scache_update - save session to cache */ + +int tls_scache_update(TLS_SCACHE *cp, char *cache_id, const char *buf, ssize_t len) +{ + ACL_VSTRING *hex_data; + + /* + * Logging. + */ + if (cp->verbose) + acl_msg_info("put %s session id=%s [data %ld bytes]", + cp->cache_label, cache_id, (long) len); + + /* + * Encode the cache entry. + */ + hex_data = tls_scache_encode(cp, cache_id, buf, len); + + /* + * Store the cache entry. + * + * XXX Berkeley DB supports huge database keys and values. SDBM seems to + * have a finite limit, and DBM simply can't be used at all. + */ + DICT_PUT(cp->db, cache_id, strlen(cache_id), STR(hex_data), LEN(hex_data)); + + /* + * Clean up. + */ + acl_vstring_free(hex_data); + + return (1); +} + +/* tls_scache_sequence - get first/next TLS session cache entry */ + +int tls_scache_sequence(TLS_SCACHE *cp, int first_next, + char **out_cache_id, ACL_VSTRING *out_session) +{ + char *member; + char *value; + char *saved_cursor; + int found_entry; + int keep_entry = 0; + char *saved_member = 0; + size_t key_size, val_size; + + /* + * XXX Deleting entries while enumerating a map can he tricky. Some map + * types have a concept of cursor and support a "delete the current + * element" operation. Some map types without cursors don't behave well + * when the current first/next entry is deleted (example: with Berkeley + * DB < 2, the "next" operation produces garbage). To avoid trouble, we + * delete an expired entry after advancing the current first/next + * position beyond it, and ignore client requests to delete the current + * entry. + */ + + /* + * Find the first or next database entry. Activate the passivated entry + * and check the time stamp. Schedule the entry for deletion if it is too + * old. + * + * Save the member (cache id) so that it will not be clobbered by the + * tls_scache_lookup() call below. + */ + found_entry = (DICT_SEQ(cp->db, first_next, &member, &key_size, &value, &val_size) == 0); + if (found_entry) { + keep_entry = tls_scache_decode(cp, member, value, (int) strlen(value), + out_session); + if (keep_entry && out_cache_id) + *out_cache_id = acl_mystrdup(member); + saved_member = acl_mystrdup(member); + acl_myfree(member); + acl_myfree(value); + } + + /* + * Delete behind. This is a no-op if an expired cache entry was updated + * in the mean time. Use the saved lookup criteria so that the "delete + * behind" operation works as promised. + */ + if (cp->flags & TLS_SCACHE_FLAG_DEL_SAVED_CURSOR) { + cp->flags &= ~TLS_SCACHE_FLAG_DEL_SAVED_CURSOR; + saved_cursor = cp->saved_cursor; + cp->saved_cursor = 0; + tls_scache_lookup(cp, saved_cursor, (ACL_VSTRING *) 0); + acl_myfree(saved_cursor); + } + + /* + * Otherwise, clean up if this is not the first iteration. + */ + else { + if (cp->saved_cursor) + acl_myfree(cp->saved_cursor); + cp->saved_cursor = 0; + } + + /* + * Protect the current first/next entry against explicit or implied + * client delete requests, and schedule a bad or expired entry for + * deletion. Save the lookup criteria so that the "delete behind" + * operation will work as promised. + */ + if (found_entry) { + cp->saved_cursor = saved_member; + if (keep_entry == 0) + cp->flags |= TLS_SCACHE_FLAG_DEL_SAVED_CURSOR; + } + return (found_entry); +} + +/* tls_scache_delete - delete session from cache */ + +int tls_scache_delete(TLS_SCACHE *cp, char *cache_id) +{ + + /* + * Logging. + */ + if (cp->verbose) + acl_msg_info("delete %s session id=%s", cp->cache_label, cache_id); + + /* + * Do it, unless we would delete the current first/next entry. Some map + * types don't have cursors, and some of those don't behave when the + * "current" entry is deleted. + */ + return ((cp->saved_cursor != 0 && strcmp(cp->saved_cursor, cache_id) == 0) + || DICT_DEL(cp->db, cache_id, strlen(cache_id)) == 0); +} + +/* tls_scache_init - init dict */ + +void tls_scache_init() +{ + dict_open_init(); +} + +/* tls_scache_open - open TLS session cache file */ + +TLS_SCACHE *tls_scache_open(const char *dbname, const char *cache_label, + int verbose, int timeout) +{ + const char *myname = "tls_scache_open"; + TLS_SCACHE *cp; + DICT *dict; + + /* + * Logging. + */ + if (verbose) + acl_msg_info("open %s TLS cache %s", cache_label, dbname); + + /* + * Open the dictionary with O_TRUNC, so that we never have to worry about + * opening a damaged file after some process terminated abnormally. + */ +#ifdef SINGLE_UPDATER +#define DICT_FLAGS (DICT_FLAG_DUP_REPLACE) +#elif defined(ACL_UNIX) +#define DICT_FLAGS \ + (DICT_FLAG_DUP_REPLACE | DICT_FLAG_LOCK | DICT_FLAG_SYNC_UPDATE) +#elif defined(ACL_MS_WINDOWS) +#define DICT_FLAGS \ + (DICT_FLAG_DUP_REPLACE | DICT_FLAG_SYNC_UPDATE) +#endif + + dict = dict_open(dbname, O_RDWR | O_CREAT | O_TRUNC, DICT_FLAGS); + + /* + * Sanity checks. + */ + if (dict->lock_fd < 0) + acl_msg_fatal("%s: dictionary %s is not a regular file", myname, dbname); +#ifdef SINGLE_UPDATER + if (acl_myflock(dict->lock_fd, INTERNAL_LOCK, + MYFLOCK_OP_EXCLUSIVE | MYFLOCK_OP_NOWAIT) < 0) + acl_msg_fatal("%s: cannot lock dictionary %s for exclusive use: %s", + myname, dbname, acl_last_serror()); +#endif + if (dict->update == 0) + acl_msg_fatal("%s: dictionary %s does not support update operations", myname, dbname); + if (dict->delete_it == 0) + acl_msg_fatal("%s: dictionary %s does not support delete operations", myname, dbname); + if (dict->sequence == 0) + acl_msg_fatal("%s: dictionary %s does not support sequence operations", myname, dbname); + + /* + * Create the TLS_SCACHE object. + */ + cp = (TLS_SCACHE *) acl_mymalloc(sizeof(*cp)); + cp->flags = 0; + cp->db = dict; + cp->cache_label = acl_mystrdup(cache_label); + cp->verbose = verbose; + cp->timeout = timeout; + cp->saved_cursor = 0; + + return (cp); +} + +/* tls_scache_close - close TLS session cache file */ + +void tls_scache_close(TLS_SCACHE *cp) +{ + const char *myname = "tls_scache_close"; + + /* + * Logging. + */ + if (cp->verbose) + acl_msg_info("%s: close %s TLS cache %s", + myname, cp->cache_label, cp->db->name); + + /* + * Destroy the TLS_SCACHE object. + */ + DICT_CLOSE(cp->db); + acl_myfree(cp->cache_label); + if (cp->saved_cursor) + acl_myfree(cp->saved_cursor); + acl_myfree(cp); +} + +#endif diff --git a/lib_tls/tls/tls_scache.h b/lib_tls/tls/tls_scache.h new file mode 100644 index 000000000..835e59606 --- /dev/null +++ b/lib_tls/tls/tls_scache.h @@ -0,0 +1,59 @@ +#ifndef _TLS_SCACHE_H_INCLUDED_ +#define _TLS_SCACHE_H_INCLUDED_ + +/*++ + * NAME + * tls_scache 3h + * SUMMARY + * TLS session cache manager + * SYNOPSIS + * #include + * DESCRIPTION + * .nf + + * + * Utility library. + */ +#include "lib_acl.h" +#include "dict.h" + + /* + * External interface. + */ +typedef struct { + int flags; /* see below */ + DICT *db; /* database handle */ + char *cache_label; /* "smtpd", "smtp" or "lmtp" */ + int verbose; /* enable verbose logging */ + int timeout; /* smtp(d)_tls_session_cache_timeout */ + char *saved_cursor; /* cursor cache ID */ +} TLS_SCACHE; + +#define TLS_SCACHE_FLAG_DEL_SAVED_CURSOR (1<<0) + +extern void tls_scache_init(void); +extern TLS_SCACHE *tls_scache_open(const char *, const char *, int, int); +extern void tls_scache_close(TLS_SCACHE *); +extern int tls_scache_lookup(TLS_SCACHE *, char *, ACL_VSTRING *); +extern int tls_scache_update(TLS_SCACHE *, char *, const char *, ssize_t); +extern int tls_scache_delete(TLS_SCACHE *, char *); +extern int tls_scache_sequence(TLS_SCACHE *, int, char **, ACL_VSTRING *); + +#define TLS_SCACHE_DONT_NEED_CACHE_ID ((char **) 0) +#define TLS_SCACHE_DONT_NEED_SESSION ((ACL_VSTRING *) 0) + +#define TLS_SCACHE_SEQUENCE_NOTHING \ + TLS_SCACHE_DONT_NEED_CACHE_ID, TLS_SCACHE_DONT_NEED_SESSION + +/* LICENSE + * .ad + * .fi + * The Secure Mailer license must be distributed with this software. + * AUTHOR(S) + * Wietse Venema + * IBM T.J. Watson Research + * P.O. Box 704 + * Yorktown Heights, NY 10598, USA + *--*/ + +#endif diff --git a/lib_tls/tls/tls_seed.c b/lib_tls/tls/tls_seed.c new file mode 100644 index 000000000..de4c74ba2 --- /dev/null +++ b/lib_tls/tls/tls_seed.c @@ -0,0 +1,93 @@ +/*++ + * NAME + * tls_seed 3 + * SUMMARY + * TLS PRNG seeding routines + * SYNOPSIS + * #include + * #include + * + * int tls_ext_seed(nbytes) + * int nbytes; + * + * void tls_int_seed() + * DESCRIPTION + * tls_ext_seed() requests the specified number of bytes + * from the tlsmgr(8) PRNG pool and updates the local PRNG. + * The result is zero in case of success, -1 otherwise. + * + * tls_int_seed() mixes the process ID and time of day into + * the PRNG pool. This adds a few bits of entropy with each + * call, provided that the calls aren't made frequently. + * LICENSE + * .ad + * .fi + * The Secure Mailer license must be distributed with this + * software. + * AUTHOR(S) + * Wietse Venema + * IBM T.J. Watson Research + * P.O. Box 704 + * Yorktown Heights, NY 10598, USA + *--*/ + +#include "StdAfx.h" +#ifdef ACL_UNIX +#include /* gettimeofday() */ +#include /* getpid() */ +#elif defined(ACL_MS_WINDOWS) +#include +#endif + +#ifdef USE_TLS + +/* OpenSSL library. */ + +#include /* RAND_seed() */ + +/* TLS library. */ + +#include "tls.h" +#include "tls_mgr.h" +#include "tls_private.h" + +/* Application-specific. */ + +/* tls_int_seed - add entropy to the pool by adding the time and PID */ + +#ifdef WIN32 +# define getpid _getpid +#endif + +void tls_int_seed(void) +{ + static __thread struct { +#ifdef ACL_MS_WINDOWS + int pid; +#else + pid_t pid; +#endif + struct timeval tv; + } randseed; + + if (randseed.pid == 0) + randseed.pid = getpid(); + gettimeofday(&randseed.tv, NULL); + RAND_seed(&randseed, sizeof(randseed)); +} + +/* tls_ext_seed - request entropy from tlsmgr(8) server */ + +int tls_ext_seed(int nbytes) +{ + ACL_VSTRING *buf; + int status; + + buf = acl_vstring_alloc(nbytes); + status = tls_mgr_seed(buf, nbytes); + RAND_seed(acl_vstring_str(buf), (int) ACL_VSTRING_LEN(buf)); + acl_vstring_free(buf); + return (status == TLS_MGR_STAT_OK ? 0 : -1); +} + +#endif diff --git a/lib_tls/tls/tls_server.c b/lib_tls/tls/tls_server.c new file mode 100644 index 000000000..3f2eed21a --- /dev/null +++ b/lib_tls/tls/tls_server.c @@ -0,0 +1,752 @@ +/*++ + * NAME + * tls_server 3 + * SUMMARY + * server-side TLS engine + * SYNOPSIS + * #include + * + * TLS_APPL_STATE *tls_server_init(props) + * const TLS_SERVER_INIT_PROPS *props; + * + * TLS_SESS_STATE *tls_server_start(props) + * const TLS_SERVER_START_PROPS *props; + * + * void tls_server_stop(app_ctx, stream, failure, TLScontext) + * TLS_APPL_STATE *app_ctx; + * VSTREAM *stream; + * int failure; + * TLS_SESS_STATE *TLScontext; + * DESCRIPTION + * This module is the interface between Postfix TLS servers, + * the OpenSSL library, and the TLS entropy and cache manager. + * + * tls_server_init() is called once when the SMTP server + * initializes. + * Certificate details are also decided during this phase, + * so that peer-specific behavior is not possible. + * + * tls_server_start() activates the TLS feature for the VSTREAM + * passed as argument. We assume that network buffers are flushed + * and the TLS handshake can begin immediately. + * + * tls_server_stop() sends the "close notify" alert via + * SSL_shutdown() to the peer and resets all connection specific + * TLS data. As RFC2487 does not specify a separate shutdown, it + * is assumed that the underlying TCP connection is shut down + * immediately afterwards. Any further writes to the channel will + * be discarded, and any further reads will report end-of-file. + * If the failure flag is set, no SSL_shutdown() handshake is performed. + * + * Once the TLS connection is initiated, information about the TLS + * state is available via the TLScontext structure: + * .IP TLScontext->protocol + * the protocol name (SSLv2, SSLv3, TLSv1), + * .IP TLScontext->cipher_name + * the cipher name (e.g. RC4/MD5), + * .IP TLScontext->cipher_usebits + * the number of bits actually used (e.g. 40), + * .IP TLScontext->cipher_algbits + * the number of bits the algorithm is based on (e.g. 128). + * .PP + * The last two values may differ from each other when export-strength + * encryption is used. + * + * If the peer offered a certificate, part of the certificate data are + * available as: + * .IP TLScontext->peer_status + * A bitmask field that records the status of the peer certificate + * verification. One or more of TLS_CERT_FLAG_PRESENT and + * TLS_CERT_FLAG_TRUSTED. + * .IP TLScontext->peer_CN + * Extracted CommonName of the peer, or zero-length string + * when information could not be extracted. + * .IP TLScontext->issuer_CN + * Extracted CommonName of the issuer, or zero-length string + * when information could not be extracted. + * .IP TLScontext->peer_fingerprint + * Fingerprint of the certificate, or zero-length string when no peer + * certificate is available. + * .PP + * If no peer certificate is presented the peer_status is set to 0. + * LICENSE + * .ad + * .fi + * This software is free. You can do with it whatever you want. + * The original author kindly requests that you acknowledge + * the use of his software. + * AUTHOR(S) + * Originally written by: + * Lutz Jaenicke + * BTU Cottbus + * Allgemeine Elektrotechnik + * Universitaetsplatz 3-4 + * D-03044 Cottbus, Germany + * + * Updated by: + * Wietse Venema + * IBM T.J. Watson Research + * P.O. Box 704 + * Yorktown Heights, NY 10598, USA + * + * Victor Duchovni + * Morgan Stanley + *--*/ + +#include "StdAfx.h" + +#ifdef USE_TLS +#ifdef ACL_UNIX +# include +#endif +#include + +#include "dict.h" + +/* Global library. */ + +#include "tls_params.h" + +/* TLS library. */ + +#include "tls.h" +#include "tls_mgr.h" +#include "tls_private.h" + +#define STR(x) acl_vstring_str(x) +#define LEN(x) ACL_VSTRING_LEN(x) + +/* Application-specific. */ + + /* + * The session_id_context indentifies the service that created a session. + * This information is used to distinguish between multiple TLS-based + * servers running on the same server. We use the name of the mail system. + */ +static const char server_session_id_context[] = "Postfix/TLS"; + +#define GEN_CACHE_ID(buf, id, len, service) \ + do { \ + buf = acl_vstring_alloc(2 * (len) + 1 + strlen(service) + 3); \ + acl_hex_encode(buf, (char *) (id), (len)); \ + acl_vstring_sprintf_append(buf, "&s=%s", (service)); \ + } while (0) + +/* get_server_session_cb - callback to retrieve session from server cache */ + +static SSL_SESSION *get_server_session_cb(SSL *ssl, unsigned char *session_id, + int session_id_length, int *unused_copy acl_unused) +{ + const char *myname = "get_server_session_cb"; + TLS_SESS_STATE *TLScontext; + ACL_VSTRING *cache_id; + ACL_VSTRING *session_data = acl_vstring_alloc(2048); + SSL_SESSION *session = 0; + + if ((TLScontext = SSL_get_ex_data(ssl, TLScontext_index)) == 0) + acl_msg_panic("%s: null TLScontext in session lookup callback", myname); + + GEN_CACHE_ID(cache_id, session_id, session_id_length, TLScontext->serverid); + + if (TLScontext->log_level >= 2) + acl_msg_info("%s: looking up session %s in %s cache", TLScontext->namaddr, + STR(cache_id), TLScontext->cache_type); + + /* + * Load the session from cache and decode it. + */ + if (tls_mgr_lookup(TLScontext->cache_type, STR(cache_id), + session_data) == TLS_MGR_STAT_OK) { + session = tls_session_activate(STR(session_data), (int) LEN(session_data)); + if (session && (TLScontext->log_level >= 2)) + acl_msg_info("%s: reloaded session %s from %s cache", + TLScontext->namaddr, STR(cache_id), + TLScontext->cache_type); + } + + /* + * Clean up. + */ + acl_vstring_free(cache_id); + acl_vstring_free(session_data); + + return (session); +} + +#if 0 +/* uncache_session - remove session from internal & external cache */ + +static void uncache_session(SSL_CTX *ctx, TLS_SESS_STATE *TLScontext) +{ + ACL_VSTRING *cache_id; + SSL_SESSION *session = SSL_get_session(TLScontext->con); + + SSL_CTX_remove_session(ctx, session); + + if (TLScontext->cache_type == 0) + return; + + GEN_CACHE_ID(cache_id, session->session_id, session->session_id_length, + TLScontext->serverid); + + if (TLScontext->log_level >= 2) + acl_msg_info("%s: remove session %s from %s cache", TLScontext->namaddr, + STR(cache_id), TLScontext->cache_type); + + tls_mgr_delete(TLScontext->cache_type, STR(cache_id)); + acl_vstring_free(cache_id); +} +#endif + +/* new_server_session_cb - callback to save session to server cache */ + +static int new_server_session_cb(SSL *ssl, SSL_SESSION *session) +{ + const char *myname = "new_server_session_cb"; + ACL_VSTRING *cache_id; + TLS_SESS_STATE *TLScontext; + ACL_VSTRING *session_data; + + if ((TLScontext = SSL_get_ex_data(ssl, TLScontext_index)) == 0) + acl_msg_panic("%s: null TLScontext in new session callback", myname); + + GEN_CACHE_ID(cache_id, session->session_id, session->session_id_length, + TLScontext->serverid); + + if (TLScontext->log_level >= 2) + acl_msg_info("%s: save session %s to %s cache", TLScontext->namaddr, + STR(cache_id), TLScontext->cache_type); + + /* + * Passivate and save the session state. + */ + session_data = tls_session_passivate(session); + if (session_data) { + tls_mgr_update(TLScontext->cache_type, STR(cache_id), + STR(session_data), (int) LEN(session_data)); + + /* + * Clean up. + */ + acl_vstring_free(session_data); + } + acl_vstring_free(cache_id); + SSL_SESSION_free(session); /* 200502 */ + + return (1); +} + +/* tls_server_int - initialize the server-side TLS engine */ + +void tls_server_init() +{ + tls_params_init(); + + if (!var_tlsmgr_stand_alone) + tlsmgr_local_start(NULL); + tls_threads_init(); +} + +/* tls_server_setup - setup the server-side TLS engine */ + +int tls_server_setup(const TLS_SERVER_INIT_PROPS *props) +{ + const char *myname = "tls_server_setup"; + const EVP_MD *md_alg; + unsigned int md_len; + + if (props->log_level >= 2) + acl_msg_info("initializing the server-side TLS engine"); + + /* + * Detect mismatch between compile-time headers and run-time library. + */ + tls_check_version(); + + /* + * Initialize the OpenSSL library by the book! To start with, we must + * initialize the algorithms. We want cleartext error messages instead of + * just error codes, so we load the error_strings. + */ + SSL_load_error_strings(); + OpenSSL_add_ssl_algorithms(); + + /* + * Create an application data index for SSL objects, so that we can + * attach TLScontext information; this information is needed inside + * tls_verify_certificate_callback(). + */ + if (TLScontext_index < 0) { + if ((TLScontext_index = SSL_get_ex_new_index(0, 0, 0, 0, 0)) < 0) { + acl_msg_warn("%s: Cannot allocate SSL application data index: " + "disabling TLS support", myname); + return (-1); + } + } + + /* + * If the administrator specifies an unsupported digest algorithm, fail + * now, rather than in the middle of a TLS handshake. + */ + if ((md_alg = EVP_get_digestbyname(props->fpt_dgst)) == 0) { + acl_msg_warn("%s: Digest algorithm \"%s\" not found: disabling TLS support", + myname, props->fpt_dgst); + return (-1); + } + + /* + * Sanity check: Newer shared libraries may use larger digests. + */ + if ((md_len = EVP_MD_size(md_alg)) > EVP_MAX_MD_SIZE) { + acl_msg_warn("%s: Digest algorithm \"%s\" output size %u too large:" + " disabling TLS support", myname, props->fpt_dgst, md_len); + return (-1); + } + + /* + * Initialize the PRNG (Pseudo Random Number Generator) with some seed + * from external and internal sources. Don't enable TLS without some real + * entropy. + */ + if (var_tls_daemon_rand_bytes > 0 && tls_ext_seed(var_tls_daemon_rand_bytes) < 0) { + acl_msg_warn("%s: no entropy for TLS key generation: disabling TLS support", myname); + return (-1); + } + tls_int_seed(); + + return (0); +} + +TLS_APPL_STATE *tls_server_create(const TLS_SERVER_INIT_PROPS *props) +{ + const char *myname = "tls_server_create"; + SSL_CTX *server_ctx; + long off = 0; + int verify_flags = SSL_VERIFY_NONE; + int cachable; + int protomask; + TLS_APPL_STATE *app_ctx; + + tls_mgr_open(NULL); + + /* + * First validate the protocols. If these are invalid, we can't continue. + */ + protomask = tls_protocol_mask(props->protocols); + if (protomask == TLS_PROTOCOL_INVALID) { + /* tls_protocol_mask() logs no warning. */ + acl_msg_warn("%s: Invalid TLS protocol list \"%s\": disabling TLS support", + myname, props->protocols); + return (0); + } + + /* + * The SSL/TLS specifications require the client to send a message in the + * oldest specification it understands with the highest level it + * understands in the message. Netscape communicator can still + * communicate with SSLv2 servers, so it sends out a SSLv2 client hello. + * To deal with it, our server must be SSLv2 aware (even if we don't like + * SSLv2), so we need to have the SSLv23 server here. If we want to limit + * the protocol level, we can add an option to not use SSLv2/v3/TLSv1 + * later. + */ + ERR_clear_error(); + if ((server_ctx = SSL_CTX_new(SSLv23_server_method())) == 0) { + acl_msg_warn("%s: cannot allocate server SSL_CTX: disabling TLS support", myname); + tls_print_errors(); + return (0); + } + + /* + * See the verify callback in tls_verify.c + */ + SSL_CTX_set_verify_depth(server_ctx, props->verifydepth + 1); + + /* + * Protocol work-arounds, OpenSSL version dependent. + */ + off |= tls_bug_bits(); + SSL_CTX_set_options(server_ctx, off); + + /* + * Global protocol selection. + */ + if (protomask != 0) + SSL_CTX_set_options(server_ctx, + ((protomask & TLS_PROTOCOL_TLSv1) ? SSL_OP_NO_TLSv1 : 0L) + | ((protomask & TLS_PROTOCOL_SSLv3) ? SSL_OP_NO_SSLv3 : 0L) + | ((protomask & TLS_PROTOCOL_SSLv2) ? SSL_OP_NO_SSLv2 : 0L)); + + /* + * Set the call-back routine to debug handshake progress. + */ + if (props->log_level >= 2) + SSL_CTX_set_info_callback(server_ctx, tls_info_callback); + + /* + * Load the CA public key certificates for both the server cert and for + * the verification of client certificates. As provided by OpenSSL we + * support two types of CA certificate handling: One possibility is to + * add all CA certificates to one large CAfile, the other possibility is + * a directory pointed to by CApath, containing separate files for each + * CA with softlinks named after the hash values of the certificate. The + * first alternative has the advantage that the file is opened and read + * at startup time, so that you don't have the hassle to maintain another + * copy of the CApath directory for chroot-jail. + */ + if (tls_set_ca_certificate_info(server_ctx, props->CAfile, props->CApath) < 0) { + /* tls_set_ca_certificate_info() already logs a warning. */ + SSL_CTX_free(server_ctx); /* 200411 */ + return (0); + } + + /* + * Load the server public key certificate and private key from file and + * check whether the cert matches the key. We can use RSA certificates + * ("cert") DSA certificates ("dcert") or ECDSA certificates ("eccert"). + * All three can be made available at the same time. The CA certificates + * for all three are handled in the same setup already finished. Which + * one is used depends on the cipher negotiated (that is: the first + * cipher listed by the client which does match the server). A client + * with RSA only (e.g. Netscape) will use the RSA certificate only. A + * client with openssl-library will use RSA first if not especially + * changed in the cipher setup. + */ + if (tls_set_my_certificate_key_info(server_ctx, + props->cert_file, + props->key_file, + props->dcert_file, + props->dkey_file, + props->eccert_file, + props->eckey_file) < 0) { + /* tls_set_my_certificate_key_info() already logs a warning. */ + SSL_CTX_free(server_ctx); /* 200411 */ + return (0); + } + + /* + * According to the OpenSSL documentation, temporary RSA key is needed + * export ciphers are in use. We have to provide one, so well, we just do + * it. + */ + SSL_CTX_set_tmp_rsa_callback(server_ctx, tls_tmp_rsa_cb); + + /* + * Diffie-Hellman key generation parameters can either be loaded from + * files (preferred) or taken from compiled in values. First, set the + * callback that will select the values when requested, then load the + * (possibly) available DH parameters from files. We are generous with + * the error handling, since we do have default values compiled in, so we + * will not abort but just log the error message. + */ + SSL_CTX_set_tmp_dh_callback(server_ctx, tls_tmp_dh_cb); + if (*props->dh1024_param_file != 0) + tls_set_dh_from_file(props->dh1024_param_file, 1024); + if (*props->dh512_param_file != 0) + tls_set_dh_from_file(props->dh512_param_file, 512); + + /* + * Enable EECDH if available, errors are not fatal, we just keep going + * with any remaining key-exchange algorithms. + */ + (void) tls_set_eecdh_curve(server_ctx, props->eecdh_grade); + + /* + * If we want to check client certificates, we have to indicate it in + * advance. By now we only allow to decide on a global basis. If we want + * to allow certificate based relaying, we must ask the client to provide + * one with SSL_VERIFY_PEER. The client now can decide, whether it + * provides one or not. We can enforce a failure of the negotiation with + * SSL_VERIFY_FAIL_IF_NO_PEER_CERT, if we do not allow a connection + * without one. In the "server hello" following the initialization by the + * "client hello" the server must provide a list of CAs it is willing to + * accept. Some clever clients will then select one from the list of + * available certificates matching these CAs. Netscape Communicator will + * present the list of certificates for selecting the one to be sent, or + * it will issue a warning, if there is no certificate matching the + * available CAs. + * + * With regard to the purpose of the certificate for relaying, we might like + * a later negotiation, maybe relaying would already be allowed for other + * reasons, but this would involve severe changes in the internal postfix + * logic, so we have to live with it the way it is. + */ + if (props->ask_ccert) + verify_flags = SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE; + SSL_CTX_set_verify(server_ctx, verify_flags, + tls_verify_certificate_callback); + if (*props->CAfile) + SSL_CTX_set_client_CA_list(server_ctx, SSL_load_client_CA_file(props->CAfile)); + + /* + * Initialize our own TLS server handle, before diving into the details + * of TLS session cache management. + */ + app_ctx = tls_alloc_app_context(server_ctx); + + /* + * The session cache is implemented by the tlsmgr(8) server. + * + * XXX 200502 Surprise: when OpenSSL purges an entry from the in-memory + * cache, it also attempts to purge the entry from the on-disk cache. + * This is undesirable, especially when we set the in-memory cache size + * to 1. For this reason we don't allow OpenSSL to purge on-disk cache + * entries, and leave it up to the tlsmgr process instead. Found by + * Victor Duchovni. + */ + + if (props->cache_type == 0 || tls_mgr_policy(props->cache_type, &cachable) != TLS_MGR_STAT_OK) + cachable = 0; + + if (cachable || props->set_sessid) { + + /* + * Initialize the session cache. + * + * With a large number of concurrent smtpd(8) processes, it is not a + * good idea to cache multiple large session objects in each process. + * We set the internal cache size to 1, and don't register a + * "remove_cb" so as to avoid deleting good sessions from the + * external cache prematurely (when the internal cache is full, + * OpenSSL removes sessions from the external cache also)! + * + * This makes SSL_CTX_remove_session() not useful for flushing broken + * sessions from the external cache, so we must delete them directly + * (not via a callback). + * + * Set a session id context to identify to what type of server process + * created a session. In our case, the context is simply the name of + * the mail system: "Postfix/TLS". + */ + SSL_CTX_sess_set_cache_size(server_ctx, 1); + SSL_CTX_set_session_id_context(server_ctx, + (void *) &server_session_id_context, + sizeof(server_session_id_context)); + SSL_CTX_set_session_cache_mode(server_ctx, + SSL_SESS_CACHE_SERVER | + SSL_SESS_CACHE_NO_AUTO_CLEAR); + if (cachable) { + app_ctx->cache_type = acl_mystrdup(props->cache_type); + + SSL_CTX_sess_set_get_cb(server_ctx, get_server_session_cb); + SSL_CTX_sess_set_new_cb(server_ctx, new_server_session_cb); + } + + /* + * OpenSSL ignores timed-out sessions. We need to set the internal + * cache timeout at least as high as the external cache timeout. This + * applies even if no internal cache is used. + */ + SSL_CTX_set_timeout(server_ctx, props->scache_timeout); + } else { + + /* + * If we have no external cache, disable all caching. No use wasting + * server memory resources with sessions they are unlikely to be able + * to reuse. + */ + SSL_CTX_set_session_cache_mode(server_ctx, SSL_SESS_CACHE_OFF); + } + + return (app_ctx); +} + + /* + * This is the actual startup routine for a new connection. We expect that + * the SMTP buffers are flushed and the "220 Ready to start TLS" was sent to + * the client, so that we can immediately start the TLS handshake process. + */ +TLS_SESS_STATE *tls_server_start(const TLS_SERVER_START_PROPS *props) +{ + const char *myname = "tls_server_start"; + int sts; + TLS_SESS_STATE *TLScontext; + SSL_CIPHER *cipher; + X509 *peer; + char buf[CCERT_BUFSIZ]; + const char *cipher_list; + TLS_APPL_STATE *app_ctx = props->ctx; + + if (props->log_level >= 1) + acl_msg_info("%s: setting up TLS connection from %s", + myname, props->namaddr); + + cipher_list = tls_set_ciphers(app_ctx, "TLS", props->cipher_grade, + props->cipher_exclusions); + if (cipher_list == 0) { + acl_msg_warn("%s: %s: %s: aborting TLS session", + myname, props->namaddr, acl_vstring_str(app_ctx->why)); + return (0); + } + if (props->log_level >= 2) + acl_msg_info("%s: %s: TLS cipher list \"%s\"", + myname, props->namaddr, cipher_list); + + /* + * Allocate a new TLScontext for the new connection and get an SSL + * structure. Add the location of TLScontext to the SSL to later retrieve + * the information inside the tls_verify_certificate_callback(). + */ + TLScontext = tls_alloc_sess_context(props->log_level, props->namaddr); + TLScontext->cache_type = app_ctx->cache_type; + + TLScontext->serverid = acl_mystrdup(props->serverid); + TLScontext->am_server = 1; + + ERR_clear_error(); + if ((TLScontext->con = (SSL *) SSL_new(app_ctx->ssl_ctx)) == 0) { + acl_msg_warn("%s: Could not allocate 'TLScontext->con' with SSL_new()", myname); + tls_print_errors(); + tls_free_context(TLScontext); + return (0); + } + if (!SSL_set_ex_data(TLScontext->con, TLScontext_index, TLScontext)) { + acl_msg_warn("%s: Could not set application data for 'TLScontext->con'", myname); + tls_print_errors(); + tls_free_context(TLScontext); + return (0); + } + + /* + * The TLS connection is realized by a BIO_pair, so obtain the pair. + * + * XXX There is no need to store the internal_bio handle in the TLScontext + * structure. It will be attached to and destroyed with TLScontext->con. + * The network_bio, however, needs to be freed explicitly, so we need to + * store its handle in TLScontext. + */ + if (!BIO_new_bio_pair(&TLScontext->internal_bio, TLS_BIO_BUFSIZE, + &TLScontext->network_bio, TLS_BIO_BUFSIZE)) { + acl_msg_warn("%s: Could not obtain BIO_pair", myname); + tls_print_errors(); + tls_free_context(TLScontext); + return (0); + } + + /* + * Before really starting anything, try to seed the PRNG a little bit + * more. + */ + tls_int_seed(); + if (var_tls_daemon_rand_bytes > 0) + (void) tls_ext_seed(var_tls_daemon_rand_bytes); + + /* + * Initialize the SSL connection to accept state. This should not be + * necessary anymore since 0.9.3, but the call is still in the library + * and maintaining compatibility never hurts. + */ + SSL_set_accept_state(TLScontext->con); + + /* + * Connect the SSL connection with the Postfix side of the BIO-pair for + * reading and writing. + */ + SSL_set_bio(TLScontext->con, TLScontext->internal_bio, + TLScontext->internal_bio); + + /* + * If the debug level selected is high enough, all of the data is dumped: + * 3 will dump the SSL negotiation, 4 will dump everything. + * + * We do have an SSL_set_fd() and now suddenly a BIO_ routine is called? + * Well there is a BIO below the SSL routines that is automatically + * created for us, so we can use it for debugging purposes. + */ + if (props->log_level >= 3) + BIO_set_callback(SSL_get_rbio(TLScontext->con), tls_bio_dump_cb); + + /* + * Start TLS negotiations. This process is a black box that invokes our + * call-backs for session caching and certificate verification. + * + * Error handling: If the SSL handhake fails, we print out an error message + * and remove all TLS state concerning this session. + */ + sts = tls_bio_accept(ACL_VSTREAM_SOCK(props->stream), props->timeout, + TLScontext); + if (sts <= 0) { + acl_msg_info("SSL_accept error from %s: %d", props->namaddr, sts); + tls_print_errors(); + tls_free_context(TLScontext); + return (0); + } + /* Only loglevel==4 dumps everything */ + if (props->log_level < 4) + BIO_set_callback(SSL_get_rbio(TLScontext->con), 0); + + /* + * The caller may want to know if this session was reused or if a new + * session was negotiated. + */ + TLScontext->session_reused = SSL_session_reused(TLScontext->con); + if (TLScontext->log_level >= 2 && TLScontext->session_reused) + acl_msg_info("%s: Reusing old session", TLScontext->namaddr); + + /* + * Let's see whether a peer certificate is available and what is the + * actual information. We want to save it for later use. + */ + peer = SSL_get_peer_certificate(TLScontext->con); + if (peer != NULL) { + TLScontext->peer_status |= TLS_CERT_FLAG_PRESENT; + if (SSL_get_verify_result(TLScontext->con) == X509_V_OK) + TLScontext->peer_status |= TLS_CERT_FLAG_TRUSTED; + + if (props->log_level >= 2) { + X509_NAME_oneline(X509_get_subject_name(peer), + buf, sizeof(buf)); + acl_msg_info("subject=%s", buf); + X509_NAME_oneline(X509_get_issuer_name(peer), + buf, sizeof(buf)); + acl_msg_info("issuer=%s", buf); + } + TLScontext->peer_CN = tls_peer_CN(peer, TLScontext); + TLScontext->issuer_CN = tls_issuer_CN(peer, TLScontext); + TLScontext->peer_fingerprint = tls_fingerprint(peer, props->fpt_dgst); + + if (props->log_level >= 1) { + acl_msg_info("%s: %s: subject_CN=%s, issuer=%s, fingerprint=%s", + props->namaddr, + TLS_CERT_IS_TRUSTED(TLScontext) ? "Trusted" : "Untrusted", + TLScontext->peer_CN, TLScontext->issuer_CN, + TLScontext->peer_fingerprint); + } + X509_free(peer); + } else { + TLScontext->peer_CN = acl_mystrdup(""); + TLScontext->issuer_CN = acl_mystrdup(""); + TLScontext->peer_fingerprint = acl_mystrdup(""); + } + + /* + * Finally, collect information about protocol and cipher for logging + */ + TLScontext->protocol = SSL_get_version(TLScontext->con); + cipher = SSL_get_current_cipher(TLScontext->con); + TLScontext->cipher_name = SSL_CIPHER_get_name(cipher); + TLScontext->cipher_usebits = SSL_CIPHER_get_bits(cipher, + &(TLScontext->cipher_algbits)); + + /* + * The TLS engine is active. Switch to the tls_timed_read/write() + * functions and make the TLScontext available to those functions. + */ + tls_stream_start(props->stream, TLScontext); + + /* + * All the key facts in a single log entry. + */ + if (props->log_level >= 1) + acl_msg_info("%s TLS connection established from %s: %s with cipher %s " + "(%d/%d bits)", !TLS_CERT_IS_PRESENT(TLScontext) ? "Anonymous" + : TLS_CERT_IS_TRUSTED(TLScontext) ? "Trusted" : "Untrusted", + props->namaddr, TLScontext->protocol, TLScontext->cipher_name, + TLScontext->cipher_usebits, TLScontext->cipher_algbits); + + tls_int_seed(); + + return (TLScontext); +} + +#endif /* USE_TLS */ diff --git a/lib_tls/tls/tls_session.c b/lib_tls/tls/tls_session.c new file mode 100644 index 000000000..aa5e4d1e6 --- /dev/null +++ b/lib_tls/tls/tls_session.c @@ -0,0 +1,161 @@ +/*++ + * NAME + * tls_session + * SUMMARY + * TLS client and server session routines + * SYNOPSIS + * #include + * + * void tls_session_stop(ctx, stream, timeout, failure, TLScontext) + * TLS_APPL_STATE *ctx; + * ACL_VSTREAM *stream; + * int timeout; + * int failure; + * TLS_SESS_STATE *TLScontext; + * + * ACL_VSTRING *tls_session_passivate(session) + * SSL_SESSION *session; + * + * SSL_SESSION *tls_session_activate(session_data, session_data_len) + * char *session_data; + * int session_data_len; + * DESCRIPTION + * tls_session_stop() implements the tls_server_shutdown() + * and the tls_client_shutdown() routines. + * + * tls_session_passivate() converts an SSL_SESSION object to + * ACL_VSTRING. The result is a null pointer in case of problems, + * otherwise it should be disposed of with acl_vstring_free(). + * + * tls_session_activate() reanimates a passivated SSL_SESSION object. + * The result is a null pointer in case of problems, + * otherwise it should be disposed of with SSL_SESSION_free(). + * LICENSE + * .ad + * .fi + * This software is free. You can do with it whatever you want. + * The original author kindly requests that you acknowledge + * the use of his software. + * AUTHOR(S) + * Originally written by: + * Lutz Jaenicke + * BTU Cottbus + * Allgemeine Elektrotechnik + * Universitaetsplatz 3-4 + * D-03044 Cottbus, Germany + * + * Updated by: + * Wietse Venema + * IBM T.J. Watson Research + * P.O. Box 704 + * Yorktown Heights, NY 10598, USA + * + * Victor Duchovni + * Morgan Stanley + *--*/ + +#include "StdAfx.h" + +#ifdef USE_TLS + +/* TLS library. */ + +#include "tls.h" +#include "tls_private.h" + +/* Application-specific. */ + +#define STR acl_vstring_str + +/* tls_session_stop - shut down the TLS connection and reset state */ + +void tls_session_stop(TLS_APPL_STATE *unused_ctx acl_unused, + ACL_VSTREAM *stream, int timeout, int failure, TLS_SESS_STATE *TLScontext) +{ + const char *myname = "tls_session_stop"; + int retval; + + /* + * Sanity check. + */ + if (TLScontext == 0) + acl_msg_panic("%s: stream has no active TLS context", myname); + + /* + * Perform SSL_shutdown() twice, as the first attempt will send out the + * shutdown alert but it will not wait for the peer's shutdown alert. + * Therefore, when we are the first party to send the alert, we must call + * SSL_shutdown() again. On failure we don't want to resume the session, + * so we will not perform SSL_shutdown() and the session will be removed + * as being bad. + */ + if (!failure) { + retval = tls_bio_shutdown(ACL_VSTREAM_SOCK(stream), timeout, TLScontext); + if (retval == 0) + tls_bio_shutdown(ACL_VSTREAM_SOCK(stream), timeout, TLScontext); + } + tls_free_context(TLScontext); + tls_stream_stop(stream); +} + +/* tls_session_passivate - passivate SSL_SESSION object */ + +ACL_VSTRING *tls_session_passivate(SSL_SESSION *session) +{ + const char *myname = "tls_session_passivate"; + int estimate; + int actual_size; + ACL_VSTRING *session_data; + unsigned char *ptr; + + /* + * First, find out how much memory is needed for the passivated + * SSL_SESSION object. + */ + estimate = i2d_SSL_SESSION(session, (unsigned char **) 0); + if (estimate <= 0) { + acl_msg_warn("%s: i2d_SSL_SESSION failed: unable to cache session", myname); + return (0); + } + + /* + * Passivate the SSL_SESSION object. The use of a ACL_VSTRING is slightly + * wasteful but is convenient to combine data and length. + */ + session_data = acl_vstring_alloc(estimate); + ptr = (unsigned char *) STR(session_data); + actual_size = i2d_SSL_SESSION(session, &ptr); + if (actual_size != estimate) { + acl_msg_warn("%s: i2d_SSL_SESSION failed: unable to cache session", myname); + acl_vstring_free(session_data); + return (0); + } + ACL_VSTRING_AT_OFFSET(session_data, actual_size); /* XXX not public */ + + return (session_data); +} + +/* tls_session_activate - activate passivated session */ + +SSL_SESSION *tls_session_activate(const char *session_data, int session_data_len) +{ +#if (OPENSSL_VERSION_NUMBER < 0x0090707fL) +#define BOGUS_CONST +#else +#define BOGUS_CONST const +#endif + SSL_SESSION *session; + BOGUS_CONST unsigned char *ptr; + + /* + * Activate the SSL_SESSION object. + */ + ptr = (BOGUS_CONST unsigned char *) session_data; + session = d2i_SSL_SESSION((SSL_SESSION **) 0, &ptr, session_data_len); + if (!session) + tls_print_errors(); + + return (session); +} + +#endif diff --git a/lib_tls/tls/tls_stream.c b/lib_tls/tls/tls_stream.c new file mode 100644 index 000000000..0b445df64 --- /dev/null +++ b/lib_tls/tls/tls_stream.c @@ -0,0 +1,138 @@ +/*++ + * NAME + * tls_stream + * SUMMARY + * ACL_VSTREAM over TLS + * SYNOPSIS + * #include + * #include + * + * void tls_stream_start(stream, context) + * ACL_VSTREAM *stream; + * TLS_SESS_STATE *context; + * + * void tls_stream_stop(stream) + * ACL_VSTREAM *stream; + * DESCRIPTION + * This module implements the ACL_VSTREAM over TLS support user interface. + * The hard work is done elsewhere. + * + * tls_stream_start() enables TLS on the named stream. All read + * and write operations are directed through the TLS library, + * using the state information specified with the context argument. + * + * tls_stream_stop() replaces the ACL_VSTREAM read/write routines + * by dummies that have no side effects, and deletes the + * ACL_VSTREAM's reference to the TLS context. + * SEE ALSO + * dummy_read(3), placebo read routine + * dummy_write(3), placebo write routine + * LICENSE + * .ad + * .fi + * This software is free. You can do with it whatever you want. + * The original author kindly requests that you acknowledge + * the use of his software. + * AUTHOR(S) + * Based on code that was originally written by: + * Lutz Jaenicke + * BTU Cottbus + * Allgemeine Elektrotechnik + * Universitaetsplatz 3-4 + * D-03044 Cottbus, Germany + * + * Updated by: + * Wietse Venema + * IBM T.J. Watson Research + * P.O. Box 704 + * Yorktown Heights, NY 10598, USA + *--*/ + +#include "StdAfx.h" + +#ifdef USE_TLS + +/* TLS library. */ + +#include "tls.h" +#include "tls_private.h" + +/* tls_timed_read - read content from stream, then TLS decapsulate */ + +static ssize_t tls_timed_read(int fd, void *buf, size_t len, + int timeout, void *context) +{ + const char *myname = "tls_timed_read"; + ssize_t ret; + TLS_SESS_STATE *TLScontext; + + TLScontext = (TLS_SESS_STATE *) context; + if (!TLScontext) + acl_msg_panic("%s: no context", myname); + + ret = tls_bio_read(fd, buf, (int) len, timeout, TLScontext); + if (ret > 0 && TLScontext->log_level >= 4) + acl_msg_info("Read %ld chars: %.*s", + (long) ret, (int) (ret > 40 ? 40 : ret), (char *) buf); + return (ret); +} + +/* tls_timed_write - TLS encapsulate content, then write to stream */ + +static ssize_t tls_timed_write(int fd, void *buf, size_t len, + int timeout, void *context) +{ + const char *myname = "tls_timed_write"; + TLS_SESS_STATE *TLScontext; + + TLScontext = (TLS_SESS_STATE *) context; + if (!TLScontext) + acl_msg_panic("%s: no context, buf(%s), len(%d)", myname, (char*) buf, (int) len); + + if (TLScontext->log_level >= 4) + acl_msg_info("Write %ld chars: %.*s", + (long) len, (int) (len > 40 ? 40 : len), (char *) buf); + return (tls_bio_write(fd, buf, (int) len, timeout, TLScontext)); +} + +/* tls_stream_start - start ACL_VSTREAM over TLS */ + +void tls_stream_start(ACL_VSTREAM *stream, TLS_SESS_STATE *context) +{ + acl_vstream_ctl(stream, + ACL_VSTREAM_CTL_READ_FN, tls_timed_read, + ACL_VSTREAM_CTL_WRITE_FN, tls_timed_write, + ACL_VSTREAM_CTL_CTX, (void *) context, + ACL_VSTREAM_CTL_END); +} + +static ssize_t dummy_read(int fd acl_unused, void *buf acl_unused, + size_t len acl_unused, int timeout acl_unused, void *context acl_unused) +{ + return (ACL_VSTREAM_EOF); +} + +static ssize_t dummy_write(int fd acl_unused, void *buf acl_unused, + size_t len acl_unused, int timeout acl_unused, void *context acl_unused) +{ + return (ACL_VSTREAM_EOF); +} + +/* tls_stream_stop - stop ACL_VSTREAM over TLS */ + +void tls_stream_stop(ACL_VSTREAM *stream) +{ + + /* + * Prevent data leakage after TLS is turned off. The Postfix/TLS patch + * provided null function pointers; we use dummy routines that make less + * noise when used. + */ + acl_vstream_ctl(stream, + ACL_VSTREAM_CTL_READ_FN, dummy_read, + ACL_VSTREAM_CTL_WRITE_FN, dummy_write, + ACL_VSTREAM_CTL_CONTEXT, (void *) 0, + ACL_VSTREAM_CTL_END); +} + +#endif diff --git a/lib_tls/tls/tls_threads.c b/lib_tls/tls/tls_threads.c new file mode 100644 index 000000000..03f2020c9 --- /dev/null +++ b/lib_tls/tls/tls_threads.c @@ -0,0 +1,85 @@ +#include "StdAfx.h" + +#ifdef USE_TLS +#include +#include "tls_private.h" + +struct CRYPTO_dynlock_value { + acl_pthread_mutex_t mutex; +}; + +static long *lock_count; +static acl_pthread_mutex_t *lock_cs; + +static void threads_locking_fn(int mode, int type, + const char *file acl_unused, int line acl_unused) +{ + if (mode & CRYPTO_LOCK) { + acl_pthread_mutex_lock(&(lock_cs[type])); + lock_count[type]++; + } else { + acl_pthread_mutex_unlock(&(lock_cs[type])); + } +} + +static unsigned long threads_thread_id_fn(void) +{ +#ifdef ACL_UNIX + acl_pthread_t ret; +#elif defined(ACL_MS_WINDOWS) + unsigned long ret; +#endif + ret = acl_pthread_self(); + return((unsigned long) ret); +} + +static struct CRYPTO_dynlock_value +*dynlock_create_fn(const char *file acl_unused, int line acl_unused) +{ + struct CRYPTO_dynlock_value *value; + + value = acl_mymalloc(sizeof(struct CRYPTO_dynlock_value)); + if (value == NULL) + return (NULL); + acl_pthread_mutex_init(&value->mutex, NULL); + return (value); +} + +static void dynlock_lock_fn(int mode, struct CRYPTO_dynlock_value *value, + const char *file acl_unused, int line acl_unused) +{ + if (mode &CRYPTO_LOCK) + acl_pthread_mutex_lock(&value->mutex); + else + acl_pthread_mutex_unlock(&value->mutex); +} + +static void dynlock_destroy_fn(struct CRYPTO_dynlock_value *value, + const char *file acl_unused, int line acl_unused) +{ + acl_pthread_mutex_destroy(&value->mutex); + acl_myfree(value); +} + +void tls_threads_init() +{ + int i; + + lock_cs = OPENSSL_malloc(CRYPTO_num_locks() * sizeof(acl_pthread_mutex_t)); + lock_count = OPENSSL_malloc(CRYPTO_num_locks() * sizeof(long)); + + /* Initialize OpenSSL locking callback */ + for (i = 0; i < CRYPTO_num_locks(); i++) { + lock_count[i] = 0; + acl_pthread_mutex_init(&(lock_cs[i]),NULL); + } + CRYPTO_set_id_callback(threads_thread_id_fn); + CRYPTO_set_locking_callback(threads_locking_fn); + + /* Initialize OpenSSL dynamic locks callbacks */ + CRYPTO_set_dynlock_create_callback(dynlock_create_fn); + CRYPTO_set_dynlock_lock_callback(dynlock_lock_fn); + CRYPTO_set_dynlock_destroy_callback(dynlock_destroy_fn); +} + +#endif diff --git a/lib_tls/tls/tls_verify.c b/lib_tls/tls/tls_verify.c new file mode 100644 index 000000000..4abfc1e4a --- /dev/null +++ b/lib_tls/tls/tls_verify.c @@ -0,0 +1,521 @@ +/*++ + * NAME + * tls_verify 3 + * SUMMARY + * peer name and peer certificate verification + * SYNOPSIS + * #include + * #include + * + * char *tls_peer_CN(peercert, TLScontext) + * X509 *peercert; + * TLS_SESS_STATE *TLScontext; + * + * char *tls_issuer_CN(peercert, TLScontext) + * X509 *peercert; + * TLS_SESS_STATE *TLScontext; + * + * const char *tls_dns_name(gn, TLScontext) + * const GENERAL_NAME *gn; + * TLS_SESS_STATE *TLScontext; + * + * char *tls_fingerprint(peercert, dgst) + * X509 *peercert; + * const char *dgst; + * + * int tls_verify_certificate_callback(ok, ctx) + * int ok; + * X509_STORE_CTX *ctx; + * DESCRIPTION + * tls_peer_CN() returns the text CommonName for the peer + * certificate subject, or an empty string if no CommonName was + * found. The result is allocated with acl_mymalloc() and must be + * freed by the caller; it contains UTF-8 without non-printable + * ASCII characters. + * + * tls_issuer_CN() returns the text CommonName for the peer + * certificate issuer, or an empty string if no CommonName was + * found. The result is allocated with acl_mymalloc() and must be + * freed by the caller; it contains UTF-8 without non-printable + * ASCII characters. + * + * tls_dns_name() returns the string value of a GENERAL_NAME + * from a DNS subjectAltName extension. If non-printable characters + * are found, a null string is returned instead. Further sanity + * checks may be added if the need arises. + * + * tls_fingerprint() returns a fingerprint of the the given + * certificate using the requested message digest. Panics if the + * (previously verified) digest algorithm is not found. The return + * value is dynamically allocated with acl_mymalloc(), and the caller + * must eventually free it with acl_myfree(). + * + * tls_verify_callback() is called several times (directly or + * indirectly) from crypto/x509/x509_vfy.c. It is called as + * a final check, and if it returns "0", the handshake is + * immediately shut down and the connection fails. + * + * Postfix/TLS has two modes, the "opportunistic" mode and + * the "enforce" mode: + * + * In the "opportunistic" mode we never want the connection + * to fail just because there is something wrong with the + * peer's certificate. After all, we would have sent or received + * the mail even if TLS weren't available. Therefore the + * return value is always "1". + * + * The SMTP client or server may require TLS (e.g. to protect + * passwords), while peer certificates are optional. In this + * case we must return "1" even when we are unhappy with the + * peer certificate. Only when peer certificates are required, + * certificate verification failure will result in immediate + * termination (return 0). + * + * The only error condition not handled inside the OpenSSL + * library is the case of a too-long certificate chain. We + * test for this condition only if "ok = 1", that is, if + * verification didn't fail because of some earlier problem. + * + * Arguments: + * .IP ok + * Result of prior verification: non-zero means success. In + * order to reduce the noise level, some tests or error reports + * are disabled when verification failed because of some + * earlier problem. + * .IP ctx + * SSL application context. This links to the Postfix TLScontext + * with enforcement and logging options. + * .IP gn + * An OpenSSL GENERAL_NAME structure holding a DNS subjectAltName + * to be decoded and checked for validity. + * .IP peercert + * Server or client X.509 certificate. + * .IP dgst + * Name of a message digest algorithm suitable for computing secure + * (1st pre-image resistant) message digests of certificates. For now, + * md5, sha1, or member of SHA-2 family if supported by OpenSSL. + * .IP TLScontext + * Server or client context for warning messages. + * DIAGNOSTICS + * tls_peer_CN(), tls_issuer_CN() and tls_dns_name() log a warning + * when 1) the requested information is not available in the specified + * certificate, 2) the result exceeds a fixed limit, 3) the result + * contains NUL characters or the result contains non-printable or + * non-ASCII characters. + * LICENSE + * .ad + * .fi + * This software is free. You can do with it whatever you want. + * The original author kindly requests that you acknowledge + * the use of his software. + * AUTHOR(S) + * Originally written by: + * Lutz Jaenicke + * BTU Cottbus + * Allgemeine Elektrotechnik + * Universitaetsplatz 3-4 + * D-03044 Cottbus, Germany + * + * Updated by: + * Wietse Venema + * IBM T.J. Watson Research + * P.O. Box 704 + * Yorktown Heights, NY 10598, USA + * + * Victor Duchovni + * Morgan Stanley + *--*/ + +#include "StdAfx.h" +#include +#include + +#include "../util/stringops.h" + +#ifdef USE_TLS +#include + +/* TLS library. */ + +#include "tls.h" +#include "tls_private.h" + +/* Application-specific. */ + +static const char hexcodes[] = "0123456789ABCDEF"; + +/* tls_verify_certificate_callback - verify peer certificate info */ + +int tls_verify_certificate_callback(int ok, X509_STORE_CTX *ctx) +{ + char buf[CCERT_BUFSIZ]; + X509 *cert; + int err; + int depth; + SSL *con; + TLS_SESS_STATE *TLScontext; + + depth = X509_STORE_CTX_get_error_depth(ctx); + cert = X509_STORE_CTX_get_current_cert(ctx); + con = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); + TLScontext = SSL_get_ex_data(con, TLScontext_index); + + /* + * The callback function is called repeatedly, first with the root + * certificate, and then with each intermediate certificate ending with + * the peer certificate. + * + * With each call, the validity of the current certificate (usage bits, + * attributes, expiration, ... checked by the OpenSSL library) is + * available in the "ok" argument. Error details are available via + * X509_STORE_CTX API. + * + * We never terminate the SSL handshake in the verification callback, rather + * we allow the TLS handshake to continue, but mark the session as + * unverified. The application is responsible for closing any sessions + * with unverified credentials. + * + * Certificate chain depth limit violations are mis-reported by the OpenSSL + * library, from SSL_CTX_set_verify(3): + * + * The certificate verification depth set with SSL[_CTX]_verify_depth() + * stops the verification at a certain depth. The error message produced + * will be that of an incomplete certificate chain and not + * X509_V_ERR_CERT_CHAIN_TOO_LONG as may be expected. + * + * We set a limit that is one higher than the user requested limit. If this + * higher limit is reached, we raise an error even a trusted root CA is + * present at this depth. This disambiguates trust chain truncation from + * an incomplete trust chain. + */ + if (depth >= SSL_get_verify_depth(con)) { + ok = 0; + X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_CHAIN_TOO_LONG); + } + if (TLScontext->log_level >= 2) { + X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf)); + acl_msg_info("%s: certificate verification depth=%d verify=%d subject=%s", + TLScontext->namaddr, depth, ok, printable(buf, '?')); + } + + /* + * If no errors, or we are not logging verification errors, we are done. + */ + if (ok || (TLScontext->peer_status & TLS_CERT_FLAG_LOGGED) != 0) + return (1); + + /* + * One counter-example is enough. + */ + TLScontext->peer_status |= TLS_CERT_FLAG_LOGGED; + +#define PURPOSE ((depth>0) ? "CA": TLScontext->am_server ? "client": "server") + + /* + * Specific causes for verification failure. + */ + switch (err = X509_STORE_CTX_get_error(ctx)) { + case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: + acl_msg_info("certificate verification failed for %s: " + "self-signed certificate", TLScontext->namaddr); + break; + case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: + case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: + + /* + * There is no difference between issuing cert not provided and + * provided, but not found in CAfile/CApath. Either way, we don't + * trust it. + */ + X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert), + buf, sizeof(buf)); + acl_msg_info("certificate verification failed for %s: untrusted issuer %s", + TLScontext->namaddr, printable(buf, '?')); + break; + case X509_V_ERR_CERT_NOT_YET_VALID: + case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: + acl_msg_info("%s certificate verification failed for %s: certificate not" + " yet valid", PURPOSE, TLScontext->namaddr); + break; + case X509_V_ERR_CERT_HAS_EXPIRED: + case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: + acl_msg_info("%s certificate verification failed for %s: certificate has" + " expired", PURPOSE, TLScontext->namaddr); + break; + case X509_V_ERR_INVALID_PURPOSE: + acl_msg_info("certificate verification failed for %s: not designated for " + "use as a %s certificate", TLScontext->namaddr, PURPOSE); + break; + case X509_V_ERR_CERT_CHAIN_TOO_LONG: + acl_msg_info("certificate verification failed for %s: " + "certificate chain longer than limit(%d)", + TLScontext->namaddr, SSL_get_verify_depth(con) - 1); + break; + default: + acl_msg_info("%s certificate verification failed for %s: num=%d:%s", + PURPOSE, TLScontext->namaddr, err, + X509_verify_cert_error_string(err)); + break; + } + + return (1); +} + +#ifndef DONT_GRIPE +#define DONT_GRIPE 0 +#define DO_GRIPE 1 +#endif + +/* tls_text_name - extract certificate property value by name */ + +static char *tls_text_name(X509_NAME *name, int nid, const char *label, + const TLS_SESS_STATE *TLScontext, int gripe) +{ + const char *myname = "tls_text_name"; + int pos; + X509_NAME_ENTRY *entry; + ASN1_STRING *entry_str; + int asn1_type; + int utf8_length; + unsigned char *utf8_value; + int ch; + unsigned char *cp; + + if (name == 0 || (pos = X509_NAME_get_index_by_NID(name, nid, -1)) < 0) { + if (gripe != DONT_GRIPE) { + acl_msg_warn("%s: %s: peer certificate has no %s", + myname, TLScontext->namaddr, label); + tls_print_errors(); + } + return (0); + } +#if 0 + + /* + * If the match is required unambiguous, insist that that no other values + * be present. + */ + if (X509_NAME_get_index_by_NID(name, nid, pos) >= 0) { + acl_msg_warn("%s: %s: multiple %ss in peer certificate", + myname, TLScontext->namaddr, label); + return (0); + } +#endif + + if ((entry = X509_NAME_get_entry(name, pos)) == 0) { + /* This should not happen */ + acl_msg_warn("%s: %s: error reading peer certificate %s entry", + myname, TLScontext->namaddr, label); + tls_print_errors(); + return (0); + } + if ((entry_str = X509_NAME_ENTRY_get_data(entry)) == 0) { + /* This should not happen */ + acl_msg_warn("%s: %s: error reading peer certificate %s data", + myname, TLScontext->namaddr, label); + tls_print_errors(); + return (0); + } + + /* + * XXX Convert everything into UTF-8. This is a super-set of ASCII, so we + * don't have to bother with separate code paths for ASCII-like content. + * If the payload is ASCII then we won't waste lots of CPU cycles + * converting it into UTF-8. It's up to OpenSSL to do something + * reasonable when converting ASCII formats that contain non-ASCII + * content. + * + * XXX Don't bother optimizing the string length error check. It is not + * worth the complexity. + */ + asn1_type = ASN1_STRING_type(entry_str); + if ((utf8_length = ASN1_STRING_to_UTF8(&utf8_value, entry_str)) < 0) { + acl_msg_warn("%s: %s: error decoding peer %s of ASN.1 type=%d", + myname, TLScontext->namaddr, label, asn1_type); + tls_print_errors(); + return (0); + } + + /* + * No returns without cleaning up. A good optimizer will replace multiple + * blocks of identical code by jumps to just one such block. + */ +#define TLS_TEXT_NAME_RETURN(x) do { \ + char *__tls_text_name_temp = (x); \ + OPENSSL_free(utf8_value); \ + return (__tls_text_name_temp); \ + } while (0) + + /* + * Remove trailing null characters. They would give false alarms with the + * length check and with the embedded null check. + */ +#define TRIM0(s, l) do { while ((l) > 0 && (s)[(l)-1] == 0) --(l); } while (0) + + TRIM0(utf8_value, utf8_length); + + /* + * Enforce the length limit, because the caller will copy the result into + * a fixed-length buffer. + */ + if (utf8_length >= CCERT_BUFSIZ) { + acl_msg_warn("%s: %s: peer %s too long: %d", + myname, TLScontext->namaddr, label, utf8_length); + TLS_TEXT_NAME_RETURN(0); + } + + /* + * Reject embedded nulls in ASCII or UTF-8 names. OpenSSL is responsible + * for producing properly-formatted UTF-8. + */ + if (utf8_length != (int) strlen((char *) utf8_value)) { + acl_msg_warn("%s: %s: NULL character in peer %s", + myname, TLScontext->namaddr, label); + TLS_TEXT_NAME_RETURN(0); + } + + /* + * Reject non-printable ASCII characters in UTF-8 content. + * + * Note: the code below does not find control characters in illegal UTF-8 + * sequences. It's OpenSSL's job to produce valid UTF-8, and reportedly, + * it does validation. + */ + for (cp = utf8_value; (ch = *cp) != 0; cp++) { + if (ACL_ISASCII(ch) && !ACL_ISPRINT(ch)) { + acl_msg_warn("%s: %s: non-printable content in peer %s", + myname, TLScontext->namaddr, label); + TLS_TEXT_NAME_RETURN(0); + } + } + TLS_TEXT_NAME_RETURN(acl_mystrdup((char *) utf8_value)); +} + +/* tls_dns_name - Extract valid DNS name from subjectAltName value */ + +const char *tls_dns_name(const GENERAL_NAME *gn, const TLS_SESS_STATE *TLScontext) +{ + const char *myname = "tls_dns_name"; + char *cp; + const char *dnsname; + int len; + + /* + * Peername checks are security sensitive, carefully scrutinize the + * input! + */ + if (gn->type != GEN_DNS) + acl_msg_panic("%s: Non DNS input argument", myname); + + /* + * We expect the OpenSSL library to construct GEN_DNS extesion objects as + * ASN1_IA5STRING values. Check we got the right union member. + */ + if (ASN1_STRING_type(gn->d.ia5) != V_ASN1_IA5STRING) { + acl_msg_warn("%s: %s: invalid ASN1 value type in subjectAltName", + myname, TLScontext->namaddr); + return (0); + } + + /* + * Safe to treat as an ASCII string possibly holding a DNS name + */ + dnsname = (char *) ASN1_STRING_data(gn->d.ia5); + len = ASN1_STRING_length(gn->d.ia5); + TRIM0(dnsname, len); + + /* + * Per Dr. Steven Henson of the OpenSSL development team, ASN1_IA5STRING + * values can have internal ASCII NUL values in this context because + * their length is taken from the decoded ASN1 buffer, a trailing NUL is + * always appended to make sure that the string is terminated, but the + * ASN.1 length may differ from strlen(). + */ + if (len != (int) strlen(dnsname)) { + acl_msg_warn("%s: %s: internal NUL in subjectAltName", + myname, TLScontext->namaddr); + return 0; + } + + /* + * XXX: Should we be more strict and call valid_hostname()? So long as + * the name is safe to handle, if it is not a valid hostname, it will not + * compare equal to the expected peername, so being more strict than + * "printable" is likely excessive... + */ + if (*dnsname && !allprint(dnsname)) { + cp = acl_mystrdup(dnsname); + acl_msg_warn("%s: %s: non-printable characters in subjectAltName: %.100s", + myname, TLScontext->namaddr, printable(cp, '?')); + acl_myfree(cp); + return 0; + } + return (dnsname); +} + +/* tls_peer_CN - extract peer common name from certificate */ + +char *tls_peer_CN(X509 *peercert, const TLS_SESS_STATE *TLScontext) +{ + char *cn; + + cn = tls_text_name(X509_get_subject_name(peercert), NID_commonName, + "subject CN", TLScontext, DO_GRIPE); + return (cn ? cn : acl_mystrdup("")); +} + +/* tls_issuer_CN - extract issuer common name from certificate */ + +char *tls_issuer_CN(X509 *peer, const TLS_SESS_STATE *TLScontext) +{ + X509_NAME *name; + char *cn; + + name = X509_get_issuer_name(peer); + + /* + * If no issuer CN field, use Organization instead. CA certs without a CN + * are common, so we only complain if the organization is also missing. + */ + if ((cn = tls_text_name(name, NID_commonName, + "issuer CN", TLScontext, DONT_GRIPE)) == 0) + cn = tls_text_name(name, NID_organizationName, + "issuer Organization", TLScontext, DO_GRIPE); + return (cn ? cn : acl_mystrdup("")); +} + +/* tls_fingerprint - extract fingerprint from certificate */ + +char *tls_fingerprint(X509 *peercert, const char *dgst) +{ + const char *myname = "tls_fingerprint"; + const EVP_MD *md_alg; + unsigned char md_buf[EVP_MAX_MD_SIZE]; + unsigned int md_len; + int i; + char *result = 0; + + /* Previously available in "init" routine. */ + if ((md_alg = EVP_get_digestbyname(dgst)) == 0) + acl_msg_panic("%s: digest algorithm \"%s\" not found", myname, dgst); + + /* Fails when serialization to ASN.1 runs out of memory */ + if (X509_digest(peercert, md_alg, md_buf, &md_len) == 0) + acl_msg_fatal("%s: error computing certificate %s digest (out of memory?)", + myname, dgst); + + /* Check for OpenSSL contract violation */ + if (md_len > EVP_MAX_MD_SIZE || (int) md_len >= INT_MAX / 3) + acl_msg_panic("%s: unexpectedly large %s digest size: %u", + myname, dgst, md_len); + + result = acl_mymalloc(md_len * 3); + for (i = 0; i < (int) md_len; i++) { + result[i * 3] = hexcodes[(md_buf[i] & 0xf0) >> 4U]; + result[(i * 3) + 1] = hexcodes[(md_buf[i] & 0x0f)]; + result[(i * 3) + 2] = (i + 1 != (int) md_len) ? ':' : '\0'; + } + return (result); +} + +#endif diff --git a/lib_tls/tls/tlsmgr_daemon.c b/lib_tls/tls/tlsmgr_daemon.c new file mode 100644 index 000000000..ad86a8b1f --- /dev/null +++ b/lib_tls/tls/tlsmgr_daemon.c @@ -0,0 +1,894 @@ +#include "StdAfx.h" +#include +#include +#ifdef ACL_UNIX +# include +# include /* gettimeofday, not POSIX */ +#elif defined(ACL_MS_WINDOWS) +# include +#endif + +#include +#include +#include +#include + +/* OpenSSL library. */ + +#ifdef USE_TLS +#include /* For the PRNG */ +#endif + +#include "../attr/attr.h" + +#ifndef UCHAR_MAX +#define UCHAR_MAX 0xff +#endif + +/* TLS library. */ + +#ifdef USE_TLS +#include "tls.h" /* TLS_MGR_SCACHE_ */ +#include "tls_private.h" +#include "tls_mgr.h" +#include "tls_prng.h" +#include "tls_scache.h" +#include "tls_params.h" + +/* Application-specific. */ + + /* + * Tunables. + */ +char *var_tls_rand_source; +int var_tls_rand_bytes; +int var_tls_reseed_period; +int var_tls_prng_exch_period; +int var_server_tls_loglevel; +char *var_server_tls_scache_db; +int var_server_tls_scache_timeout; +int var_client_tls_loglevel; +char *var_client_tls_scache_db; +int var_client_tls_scache_timeout; +char *var_tls_rand_exch_name; +int var_tlsmgr_stand_alone = 0; + + /* + * Bound the time that we are willing to wait for an I/O operation. This + * produces better error messages than waiting until the watchdog timer + * kills the process. + */ +#define TLS_MGR_TIMEOUT 10 + + /* + * State for updating the PRNG exchange file. + */ +static TLS_PRNG_SRC *rand_exch; + + /* + * State for seeding the internal PRNG from external source. + */ +static TLS_PRNG_SRC *rand_source_dev; +static TLS_PRNG_SRC *rand_source_egd; +static TLS_PRNG_SRC *rand_source_file; + + /* + * The external entropy source type is encoded in the source name. The + * obvious alternative is to have separate configuration parameters per + * source type, so that one process can query multiple external sources. + */ +#define DEV_PREF "dev:" +#define DEV_PREF_LEN (sizeof((DEV_PREF)) - 1) +#define DEV_PATH(dev) ((dev) + EGD_PREF_LEN) + +#define EGD_PREF "egd:" +#define EGD_PREF_LEN (sizeof((EGD_PREF)) - 1) +#define EGD_PATH(egd) ((egd) + EGD_PREF_LEN) + + /* + * State for TLS session caches. + */ +typedef struct { + char *cache_label; /* cache short-hand name */ + TLS_SCACHE *cache_info; /* cache handle */ + int cache_active; /* cache status */ + char **cache_db; /* main.cf parameter value */ + int *cache_loglevel; /* main.cf parameter value */ + int *cache_timeout; /* main.cf parameter value */ +} TLSMGR_SCACHE; + +TLSMGR_SCACHE cache_table[] = { + { TLS_MGR_SCACHE_SERVER, 0, 0, &var_server_tls_scache_db, + &var_server_tls_loglevel, &var_server_tls_scache_timeout }, + { TLS_MGR_SCACHE_CLIENT, 0, 0, &var_client_tls_scache_db, + &var_client_tls_loglevel, &var_client_tls_scache_timeout }, + { 0, 0, 0, 0, 0, 0 }, +}; + +static ACL_EVENT *__eventp; + /* + * SLMs. + */ +#define STR(x) acl_vstring_str(x) +#define LEN(x) ACL_VSTRING_LEN(x) +#define STREQ(x, y) (strcmp((x), (y)) == 0) + +/* tlsmgr_prng_exch_event - update PRNG exchange file */ + +static void tlsmgr_prng_exch_event(int unused_event acl_unused, void *dummy) +{ + const char *myname = "tlsmgr_prng_exch_event"; + unsigned char randbyte; + int next_period; + struct acl_stat st; + + if (acl_msg_verbose) + acl_msg_info("%s: update PRNG exchange file", myname); + + /* + * Sanity check. If the PRNG exchange file was removed, there is no point + * updating it further. Restart the process and update the new file. + */ + if (acl_fstat(rand_exch->fd.file, &st) < 0) + acl_msg_fatal("%s: cannot fstat() the PRNG exchange file: %s", myname, acl_last_serror()); + if (st.st_nlink == 0) { + acl_msg_warn("%s: PRNG exchange file was removed -- exiting to reopen", myname); + sleep(1); + exit(0); + } + tls_prng_exch_update(rand_exch); + + /* + * Make prediction difficult for outsiders and calculate the time for the + * next execution randomly. + */ + RAND_bytes(&randbyte, 1); + next_period = (var_tls_prng_exch_period * randbyte) / UCHAR_MAX; + acl_event_request_timer(__eventp, tlsmgr_prng_exch_event, dummy, next_period, 0); +} + +/* tlsmgr_reseed_event - re-seed the internal PRNG pool */ + +static void tlsmgr_reseed_event(int unused_event acl_unused, void *dummy) +{ + const char *myname = "tlsmgr_reseed_event"; + int next_period; + unsigned char randbyte; + int must_exit = 0; + + /* + * Reseed the internal PRNG from external source. Errors are recoverable. + * We simply restart and reconnect without making a fuss. This is OK + * because we do require that exchange file updates succeed. The exchange + * file is the only entropy source that really matters in the long term. + * + * If the administrator specifies an external randomness source that we + * could not open upon start-up, restart to see if we can open it now + * (and log a nagging warning if we can't). + */ + if (*var_tls_rand_source) { + + /* + * Source is a random device. + */ + if (rand_source_dev) { + if (tls_prng_dev_read(rand_source_dev, var_tls_rand_bytes) <= 0) { + acl_msg_info("%s: cannot read from entropy device %s: %s -- " + "exiting to reopen", myname, DEV_PATH(var_tls_rand_source), + acl_last_serror()); + must_exit = 1; + } + } + + /* + * Source is an EGD compatible socket. + */ + else if (rand_source_egd) { + if (tls_prng_egd_read(rand_source_egd, var_tls_rand_bytes) <= 0) { + acl_msg_info("%s: lost connection to EGD server %s -- " + "exiting to reconnect", myname, EGD_PATH(var_tls_rand_source)); + must_exit = 1; + } + } + + /* + * Source is a regular file. Read the content once and close the + * file. + */ + else if (rand_source_file) { + if (tls_prng_file_read(rand_source_file, var_tls_rand_bytes) <= 0) + acl_msg_warn("%s: cannot read from entropy file %s: %s", + myname, var_tls_rand_source, acl_last_serror()); + tls_prng_file_close(rand_source_file); + rand_source_file = 0; + var_tls_rand_source[0] = 0; + } + + /* + * Could not open the external source upon start-up. See if we can + * open it this time. Save PRNG state before we exit. + */ + else { + acl_msg_info("exiting to reopen external entropy source %s", + var_tls_rand_source); + must_exit = 1; + } + } + + /* + * Save PRNG state in case we must exit. + */ + if (must_exit) { + if (rand_exch) + tls_prng_exch_update(rand_exch); + sleep(1); + acl_msg_info("exit now"); + exit(0); + } + + /* + * Make prediction difficult for outsiders and calculate the time for the + * next execution randomly. + */ + RAND_bytes(&randbyte, 1); + next_period = (var_tls_reseed_period * randbyte) / UCHAR_MAX; + acl_event_request_timer(__eventp, tlsmgr_reseed_event, dummy, next_period, 0); +} + +/* tlsmgr_cache_run_event - start TLS session cache scan */ + +static void tlsmgr_cache_run_event(int unused_event acl_unused, void *ctx) +{ + const char *myname = "tlsmgr_cache_run_event"; + TLSMGR_SCACHE *cache = (TLSMGR_SCACHE *) ctx; + + /* + * This routine runs when it is time for another TLS session cache scan. + * Make sure this routine gets called again in the future. + * + * Don't start a new scan when the timer goes off while cache cleanup is + * still in progress. + */ + if (cache->cache_info->verbose) + acl_msg_info("%s: start TLS %s session cache cleanup", + myname, cache->cache_label); + + if (cache->cache_active == 0) + cache->cache_active = + tls_scache_sequence(cache->cache_info, DICT_SEQ_FUN_FIRST, + TLS_SCACHE_SEQUENCE_NOTHING); + + acl_event_request_timer(__eventp, tlsmgr_cache_run_event, (char *) cache, + cache->cache_info->timeout, 0); +} + +/* tlsmgr_loop - TLS manager main loop */ + +static int tlsmgr_loop(char *unused_name acl_unused, char **unused_argv acl_unused) +{ + struct timeval tv; + int active = 0; + TLSMGR_SCACHE *ent; + + /* + * Update the PRNG pool with the time of day. We do it here after every + * event (including internal timer events and external client request + * events), instead of doing it in individual event call-back routines. + */ + gettimeofday(&tv, 0); + RAND_seed(&tv, sizeof(struct timeval)); + + /* + * This routine runs as part of the event handling loop, after the event + * manager has delivered a timer or I/O event, or after it has waited for + * a specified amount of time. The result value of tlsmgr_loop() + * specifies how long the event manager should wait for the next event. + * + * We use this loop to interleave TLS session cache cleanup with other + * activity. Interleaved processing is needed when we use a client-server + * protocol for entropy and session state exchange with client(8) and + * server(8) processes. + */ +#define DONT_WAIT 0 +#define WAIT_FOR_EVENT (-1) + + for (ent = cache_table; ent->cache_label; ++ent) { + if (ent->cache_info && ent->cache_active) + active |= ent->cache_active = + tls_scache_sequence(ent->cache_info, DICT_SEQ_FUN_NEXT, + TLS_SCACHE_SEQUENCE_NOTHING); + } + + return (active ? DONT_WAIT : WAIT_FOR_EVENT); +} + +/* tlsmgr_request_receive - receive request */ + +static int tlsmgr_request_receive(ACL_VSTREAM *client_stream, ACL_VSTRING *request) +{ + const char *myname = "tlsmgr_request_receive"; + int count; + + /* + * Kluge: choose the protocol depending on the request size. + */ + if (acl_read_wait(ACL_VSTREAM_SOCK(client_stream), var_ipc_timeout) < 0) { + acl_msg_warn("%s: timeout while waiting for data from %s", + myname, ACL_VSTREAM_PATH(client_stream)); + return (-1); + } + if ((count = acl_peekfd(ACL_VSTREAM_SOCK(client_stream))) < 0) { + acl_msg_warn("%s: cannot examine read buffer of %s: %s", + myname, ACL_VSTREAM_PATH(client_stream), acl_last_serror()); + return (-1); + } + + /* + * Short request: master trigger. Use the string+null protocol. + */ + if (count <= 2) { + if (acl_vstring_gets_null(request, client_stream) == ACL_VSTREAM_EOF) { + acl_msg_warn("%s: end-of-input while reading request from %s: %s", + myname, ACL_VSTREAM_PATH(client_stream), acl_last_serror()); + return (-1); + } + } + + /* + * Long request: real tlsmgr client. Use the attribute list protocol. + */ + else { + if (attr_scan(client_stream, + ATTR_FLAG_MORE | ATTR_FLAG_STRICT, + ATTR_TYPE_STR, TLS_MGR_ATTR_REQ, request, + ATTR_TYPE_END) != 1) { + return (-1); + } + } + return (0); +} + +/* tlsmgr_service - respond to external request */ + +static void tlsmgr_service(ACL_VSTREAM *client_stream, + char *unused_service acl_unused, char **argv acl_unused) +{ + const char *myname = "tlsmgr_service"; + static ACL_VSTRING *request = 0; + static ACL_VSTRING *cache_type = 0; + static ACL_VSTRING *cache_id = 0; + static ACL_VSTRING *buffer = 0; + int len; + static char wakeup[] = { /* master wakeup request */ + TRIGGER_REQ_WAKEUP, + 0, + }; + TLSMGR_SCACHE *ent; + int status = TLS_MGR_STAT_FAIL; + + /* + * Sanity check. This service takes no command-line arguments. + */ + if (var_tlsmgr_stand_alone && argv[0]) + acl_msg_fatal("unexpected command-line argument: %s", argv[0]); + + /* + * Initialize. We're select threaded, so we can use static buffers. + */ + if (request == 0) { + request = acl_vstring_alloc(10); + cache_type = acl_vstring_alloc(10); + cache_id = acl_vstring_alloc(10); + buffer = acl_vstring_alloc(10); + } + + /* + * This routine runs whenever a client connects to the socket dedicated + * to the tlsmgr service (including wake up events sent by the master). + * All connection-management stuff is handled by the common code in + * multi_server.c. + */ + if (tlsmgr_request_receive(client_stream, request) == 0) { + + /* + * Load session from cache. + */ + if (STREQ(STR(request), TLS_MGR_REQ_LOOKUP)) { + if (attr_scan(client_stream, ATTR_FLAG_STRICT, + ATTR_TYPE_STR, TLS_MGR_ATTR_CACHE_TYPE, cache_type, + ATTR_TYPE_STR, TLS_MGR_ATTR_CACHE_ID, cache_id, + ATTR_TYPE_END) == 2) { + for (ent = cache_table; ent->cache_label; ++ent) + if (strcmp(ent->cache_label, STR(cache_type)) == 0) + break; + if (ent->cache_label == 0) { + acl_msg_warn("%s: bogus cache type \"%s\" in \"%s\" request", + myname, STR(cache_type), TLS_MGR_REQ_LOOKUP); + ACL_VSTRING_RESET(buffer); + } else if (ent->cache_info == 0) { + + /* + * Cache type valid, but not enabled + */ + ACL_VSTRING_RESET(buffer); + } else { + status = tls_scache_lookup(ent->cache_info, + STR(cache_id), buffer) ? + TLS_MGR_STAT_OK : TLS_MGR_STAT_ERR; + } + } + attr_print(client_stream, ATTR_FLAG_NONE, + ATTR_TYPE_INT, TLS_ATTR_STATUS, status, + ATTR_TYPE_DATA, TLS_MGR_ATTR_SESSION, + LEN(buffer), STR(buffer), + ATTR_TYPE_END); + } + + /* + * Save session to cache. + */ + else if (STREQ(STR(request), TLS_MGR_REQ_UPDATE)) { + if (attr_scan(client_stream, ATTR_FLAG_STRICT, + ATTR_TYPE_STR, TLS_MGR_ATTR_CACHE_TYPE, cache_type, + ATTR_TYPE_STR, TLS_MGR_ATTR_CACHE_ID, cache_id, + ATTR_TYPE_DATA, TLS_MGR_ATTR_SESSION, buffer, + ATTR_TYPE_END) == 3) { + for (ent = cache_table; ent->cache_label; ++ent) + if (strcmp(ent->cache_label, STR(cache_type)) == 0) + break; + if (ent->cache_label == 0) { + acl_msg_warn("%s: bogus cache type \"%s\" in \"%s\" request", + myname, STR(cache_type), TLS_MGR_REQ_UPDATE); + } else if (ent->cache_info != 0) { + status = 0; + tls_scache_update(ent->cache_info, STR(cache_id), + STR(buffer), LEN(buffer)) ? + TLS_MGR_STAT_OK : TLS_MGR_STAT_ERR; + } + } + attr_print(client_stream, ATTR_FLAG_NONE, + ATTR_TYPE_INT, TLS_ATTR_STATUS, status, + ATTR_TYPE_END); + } + + /* + * Delete session from cache. + */ + else if (STREQ(STR(request), TLS_MGR_REQ_DELETE)) { + if (attr_scan(client_stream, ATTR_FLAG_STRICT, + ATTR_TYPE_STR, TLS_MGR_ATTR_CACHE_TYPE, cache_type, + ATTR_TYPE_STR, TLS_MGR_ATTR_CACHE_ID, cache_id, + ATTR_TYPE_END) == 2) { + for (ent = cache_table; ent->cache_label; ++ent) + if (strcmp(ent->cache_label, STR(cache_type)) == 0) + break; + if (ent->cache_label == 0) { + acl_msg_warn("%s: bogus cache type \"%s\" in \"%s\" request", + myname, STR(cache_type), TLS_MGR_REQ_DELETE); + } else if (ent->cache_info != 0) { + status = tls_scache_delete(ent->cache_info, + STR(cache_id)) ? + TLS_MGR_STAT_OK : TLS_MGR_STAT_ERR; + } + } + attr_print(client_stream, ATTR_FLAG_NONE, + ATTR_TYPE_INT, TLS_ATTR_STATUS, status, + ATTR_TYPE_END); + } + + /* + * Entropy request. + */ + else if (STREQ(STR(request), TLS_MGR_REQ_SEED)) { + if (attr_scan(client_stream, ATTR_FLAG_STRICT, + ATTR_TYPE_INT, TLS_MGR_ATTR_SIZE, &len, + ATTR_TYPE_END) == 1) { + ACL_VSTRING_RESET(buffer); + if (len <= 0 || len > 255) { + acl_msg_warn("%s: bogus seed length \"%d\" in \"%s\" request", + myname, len, TLS_MGR_REQ_SEED); + } else { + ACL_VSTRING_SPACE(buffer, len); + RAND_bytes((unsigned char *) STR(buffer), len); + ACL_VSTRING_AT_OFFSET(buffer, len); /* XXX not part of the + * official interface */ + status = TLS_MGR_STAT_OK; + } + } + attr_print(client_stream, ATTR_FLAG_NONE, + ATTR_TYPE_INT, TLS_ATTR_STATUS, status, + ATTR_TYPE_DATA, TLS_MGR_ATTR_SEED, + LEN(buffer), STR(buffer), + ATTR_TYPE_END); + } + + /* + * Caching policy request. + */ + else if (STREQ(STR(request), TLS_MGR_REQ_POLICY)) { + int cachable = 0; + + if (attr_scan(client_stream, ATTR_FLAG_STRICT, + ATTR_TYPE_STR, TLS_MGR_ATTR_CACHE_TYPE, cache_type, + ATTR_TYPE_END) == 1) { + for (ent = cache_table; ent->cache_label; ++ent) + if (strcmp(ent->cache_label, STR(cache_type)) == 0) + break; + if (ent->cache_label == 0) { + acl_msg_warn("%s: bogus cache type \"%s\" in \"%s\" request", + myname, STR(cache_type), TLS_MGR_REQ_POLICY); + } else { + cachable = (ent->cache_info != 0) ? 1 : 0; + status = TLS_MGR_STAT_OK; + } + } + attr_print(client_stream, ATTR_FLAG_NONE, + ATTR_TYPE_INT, TLS_ATTR_STATUS, status, + ATTR_TYPE_INT, TLS_MGR_ATTR_CACHABLE, cachable, + ATTR_TYPE_END); + } + + /* + * Master trigger. Normally, these triggers arrive only after some + * other process requested the tlsmgr's service. The purpose is to + * restart the tlsmgr after it aborted due to a fatal run-time error, + * so that it can continue its housekeeping even while nothing is + * using TLS. + * + * XXX Which begs the question, if TLS isn't used often, do we need a + * tlsmgr background process? It could terminate when the session + * caches are empty. + */ + else if (var_tlsmgr_stand_alone && STREQ(STR(request), wakeup)) { + if (acl_msg_verbose) + acl_msg_info("received master trigger"); +#ifdef ACL_UNIX + acl_multi_server_disconnect(client_stream); +#endif + return; /* NOT: acl_vstream_fflush */ + } + + /* + * protocol error + */ + else { + attr_print(client_stream, ATTR_FLAG_NONE, + ATTR_TYPE_INT, TLS_ATTR_STATUS, TLS_MGR_STAT_FAIL, + ATTR_TYPE_END); + } + } + + /* + * Protocol error. + */ + else { + attr_print(client_stream, ATTR_FLAG_NONE, + ATTR_TYPE_INT, TLS_ATTR_STATUS, TLS_MGR_STAT_FAIL, + ATTR_TYPE_END); + } + acl_vstream_fflush(client_stream); +} + +/* tlsmgr_pre_init - pre-jail initialization */ + +static void tlsmgr_pre_init(char *unused_name acl_unused, char **unused_argv acl_unused) +{ + const char *myname = "tlsmgr_pre_init"; + char *path; + struct timeval tv; + TLSMGR_SCACHE *ent; + ACL_HTABLE *dup_filter; + const char *dup_label; + + /* + * If nothing else works then at least this will get us a few bits of + * entropy. + * + * XXX This is our first call into the OpenSSL library. We should find out + * if this can be moved to the post-jail initialization phase, without + * breaking compatibility with existing installations. + */ +#ifdef WIN32 +# define getpid _getpid +#endif + gettimeofday(&tv, 0); + tv.tv_sec ^= getpid(); + RAND_seed(&tv, sizeof(struct timeval)); + + /* + * Open the external entropy source. We will not be able to open it again + * after we are sent to chroot jail, so we keep it open. Errors are not + * fatal. The exchange file (see below) is the only entropy source that + * really matters in the long run. + * + * Security note: we open the entropy source while privileged, but we don't + * access the source until after we release privileges. This way, none of + * the OpenSSL code gets to execute while we are privileged. + */ + if (*var_tls_rand_source) { + + /* + * Source is a random device. + */ + if (!strncmp(var_tls_rand_source, DEV_PREF, DEV_PREF_LEN)) { + path = DEV_PATH(var_tls_rand_source); + rand_source_dev = tls_prng_dev_open(path, TLS_MGR_TIMEOUT); + if (rand_source_dev == 0) + acl_msg_warn("%s: cannot open entropy device %s: %s", + myname, path, acl_last_serror()); + } + + /* + * Source is an EGD compatible socket. + */ + else if (!strncmp(var_tls_rand_source, EGD_PREF, EGD_PREF_LEN)) { + path = EGD_PATH(var_tls_rand_source); + rand_source_egd = tls_prng_egd_open(path, TLS_MGR_TIMEOUT); + if (rand_source_egd == 0) + acl_msg_warn("%s: cannot connect to EGD server %s: %s", + myname, path, acl_last_serror()); + } + + /* + * Source is regular file. We read this only once. + */ + else { + rand_source_file = + tls_prng_file_open(var_tls_rand_source, TLS_MGR_TIMEOUT); + } + } else { + acl_msg_warn("%s: no entropy source specified with parameter %s", + myname, VAR_TLS_RAND_SOURCE); + acl_msg_warn("%s: encryption keys etc. may be predictable", myname); + } + + /* + * Open the PRNG exchange file before going to jail, but don't use root + * privileges. Start the exchange file read/update pseudo thread after + * dropping privileges. + */ + if (*var_tls_rand_exch_name) { + rand_exch = tls_prng_exch_open(var_tls_rand_exch_name); + if (rand_exch == 0) + acl_msg_fatal("cannot open PRNG exchange file %s: %s", + var_tls_rand_exch_name, acl_last_serror()); + } + + /* + * Open the session cache files and discard old information before going + * to jail, but don't use root privilege. Start the cache maintenance + * pseudo threads after dropping privileges. + */ + + if (!var_tlsmgr_stand_alone) + tls_scache_init(); + + dup_filter = acl_htable_create(sizeof(cache_table) / sizeof(cache_table[0]), 0); + for (ent = cache_table; ent->cache_label; ++ent) { + if (**ent->cache_db) { + if ((dup_label = acl_htable_find(dup_filter, *ent->cache_db)) != 0) + acl_msg_fatal("do not use the same TLS cache file %s for %s and %s", + *ent->cache_db, dup_label, ent->cache_label); + acl_htable_enter(dup_filter, *ent->cache_db, ent->cache_label); + ent->cache_info = tls_scache_open(*ent->cache_db, + ent->cache_label, + *ent->cache_loglevel >= 2, + *ent->cache_timeout); + } + } + acl_htable_free(dup_filter, NULL); +} + +/* tlsmgr_post_init - post-jail initialization */ + +static void tlsmgr_post_init(char *unused_name acl_unused, + char **unused_argv acl_unused) +{ + const char *myname = "tlsmgr_post_init"; + TLSMGR_SCACHE *ent; + +#define NULL_EVENT (0) +#define NULL_CONTEXT ((char *) 0) + +#ifdef ACL_UNIX + if (var_tlsmgr_stand_alone) + __eventp = acl_multi_server_event(); + else +#endif + __eventp = acl_event_new_select(1, 0); + + if (__eventp == NULL) + acl_msg_fatal("%s: __eventp null", myname); + + if (var_tlsmgr_stand_alone) { + /* + * This routine runs after the skeleton code has entered the chroot jail, + * but before any client requests are serviced. Prevent automatic process + * suicide after a limited number of client requests or after a limited + * amount of idle time. + */ +#ifdef ACL_UNIX + acl_var_multi_use_limit = 0; + acl_var_multi_idle_limit = 0; +#endif + } + + /* + * Start the internal PRNG re-seeding pseudo thread first. + */ + if (*var_tls_rand_source) { + if (var_tls_reseed_period > INT_MAX / UCHAR_MAX) + var_tls_reseed_period = INT_MAX / UCHAR_MAX; + tlsmgr_reseed_event(NULL_EVENT, NULL_CONTEXT); + } + + /* + * Start the exchange file read/update pseudo thread. + */ + if (*var_tls_rand_exch_name) { + if (var_tls_prng_exch_period > INT_MAX / UCHAR_MAX) + var_tls_prng_exch_period = INT_MAX / UCHAR_MAX; + tlsmgr_prng_exch_event(NULL_EVENT, NULL_CONTEXT); + } + + /* + * Start the cache maintenance pseudo threads last. Strictly speaking + * there is nothing to clean up after we truncate the database to zero + * length, but early cleanup makes verbose logging more informative (we + * get positive confirmation that the cleanup threads are running). + */ + for (ent = cache_table; ent->cache_label; ++ent) + if (ent->cache_info) + tlsmgr_cache_run_event(NULL_EVENT, (char *) ent); +} + +/* tlsmgr_before_exit - save PRNG state before exit */ + +static void tlsmgr_before_exit(char *unused_service_name acl_unused, + char **unused_argv acl_unused) +{ + + /* + * Save state before we exit after "postfix reload". + */ + if (rand_exch) + tls_prng_exch_update(rand_exch); +} + +#ifdef ACL_UNIX + +void tlsmgr_alone_start(int argc, char *argv[]) +{ + static ACL_CONFIG_STR_TABLE str_table[] = { + { VAR_TLS_RAND_SOURCE, DEF_TLS_RAND_SOURCE, &var_tls_rand_source }, + { VAR_TLS_RAND_EXCH_NAME, DEF_TLS_RAND_EXCH_NAME, &var_tls_rand_exch_name }, + { VAR_SERVER_TLS_SCACHE_DB, DEF_SERVER_TLS_SCACHE_DB, &var_server_tls_scache_db }, + { VAR_CLIENT_TLS_SCACHE_DB, DEF_CLIENT_TLS_SCACHE_DB, &var_client_tls_scache_db }, + { 0, 0, 0 }, + }; + static ACL_CONFIG_INT_TABLE int_table[] = { + { VAR_TLS_RAND_BYTES, DEF_TLS_RAND_BYTES, &var_tls_rand_bytes, 1, 0 }, + { VAR_SERVER_TLS_LOGLEVEL, DEF_SERVER_TLS_LOGLEVEL, &var_server_tls_loglevel, 0, 0 }, + { VAR_CLIENT_TLS_LOGLEVEL, DEF_CLIENT_TLS_LOGLEVEL, &var_client_tls_loglevel, 0, 0 }, + + { VAR_TLS_RESEED_PERIOD, DEF_TLS_RESEED_PERIOD, &var_tls_reseed_period, 1, 0 }, + { VAR_TLS_PRNG_UPD_PERIOD, DEF_TLS_PRNG_UPD_PERIOD, &var_tls_prng_exch_period, 1, 0 }, + { VAR_SERVER_TLS_SCACHTIME, DEF_SERVER_TLS_SCACHTIME, &var_server_tls_scache_timeout, 0, 0 }, + { VAR_CLIENT_TLS_SCACHTIME, DEF_CLIENT_TLS_SCACHTIME, &var_client_tls_scache_timeout, 0, 0 }, + { 0, 0, 0, 0, 0 }, + }; + + /* + * Use the multi service skeleton, and require that no-one else is + * monitoring our service port while this process runs. + */ + acl_multi_server_main(argc, argv, tlsmgr_service, + ACL_MASTER_SERVER_INT_TABLE, int_table, + ACL_MASTER_SERVER_STR_TABLE, str_table, + ACL_MASTER_SERVER_PRE_INIT, tlsmgr_pre_init, + ACL_MASTER_SERVER_POST_INIT, tlsmgr_post_init, + ACL_MASTER_SERVER_EXIT, tlsmgr_before_exit, + ACL_MASTER_SERVER_LOOP, tlsmgr_loop, + ACL_MASTER_SERVER_SOLITARY, + 0); +} + +#endif /* ACL_UNIX */ + +static void client_ready_callback(int event_type acl_unused, void *ctx) +{ + ACL_VSTREAM *client_stream = (ACL_VSTREAM*) ctx; + + tlsmgr_service(client_stream, NULL, NULL); + acl_event_enable_read(__eventp, client_stream, + 0, client_ready_callback, client_stream); +} + +static void listen_callback(int event_type acl_unused, void *ctx) +{ + const char *myname = "listen_callback"; + ACL_VSTREAM *server_stream = (ACL_VSTREAM*) ctx; + ACL_VSTREAM *client_stream; + + client_stream = acl_vstream_accept(server_stream, NULL, 0); + if (client_stream == NULL) { + acl_msg_warn("%s(%d): accept error(%s)", + myname, __LINE__, acl_last_serror()); + return; + } + acl_event_enable_read(__eventp, client_stream, + 0, client_ready_callback, client_stream); +} + +static void *tlsmgr_thread_main(void *arg) +{ + ACL_VSTREAM *server_stream = (ACL_VSTREAM*) arg; + int delay_sec; + + acl_event_enable_listen(__eventp, server_stream, + 0, listen_callback, server_stream); + while (1) { + delay_sec = tlsmgr_loop(NULL, NULL); + acl_event_set_delay_sec(__eventp, delay_sec); + acl_event_loop(__eventp); + } + + acl_vstream_close(server_stream); + tlsmgr_before_exit(NULL, NULL); + return (NULL); +} + +void tlsmgr_local_start(const char *addr) +{ + const char *myname = "tlsmgr_local_start"; + static ACL_CONFIG_STR_TABLE str_table[] = { + { VAR_TLS_RAND_SOURCE, DEF_TLS_RAND_SOURCE, &var_tls_rand_source }, + { VAR_TLS_RAND_EXCH_NAME, DEF_TLS_RAND_EXCH_NAME, &var_tls_rand_exch_name }, + { VAR_SERVER_TLS_SCACHE_DB, DEF_SERVER_TLS_SCACHE_DB, &var_server_tls_scache_db }, + { VAR_CLIENT_TLS_SCACHE_DB, DEF_CLIENT_TLS_SCACHE_DB, &var_client_tls_scache_db }, + { 0, 0, 0 }, + }; + static ACL_CONFIG_INT_TABLE int_table[] = { + { VAR_TLS_RAND_BYTES, DEF_TLS_RAND_BYTES, &var_tls_rand_bytes, 1, 0 }, + { VAR_SERVER_TLS_LOGLEVEL, DEF_SERVER_TLS_LOGLEVEL, &var_server_tls_loglevel, 0, 0 }, + { VAR_CLIENT_TLS_LOGLEVEL, DEF_CLIENT_TLS_LOGLEVEL, &var_client_tls_loglevel, 0, 0 }, + + { VAR_TLS_RESEED_PERIOD, DEF_TLS_RESEED_PERIOD, &var_tls_reseed_period, 1, 0 }, + { VAR_TLS_PRNG_UPD_PERIOD, DEF_TLS_PRNG_UPD_PERIOD, &var_tls_prng_exch_period, 1, 0 }, + { VAR_SERVER_TLS_SCACHTIME, DEF_SERVER_TLS_SCACHTIME, &var_server_tls_scache_timeout, 0, 0 }, + { VAR_CLIENT_TLS_SCACHTIME, DEF_CLIENT_TLS_SCACHTIME, &var_client_tls_scache_timeout, 0, 0 }, + { 0, 0, 0, 0, 0 }, + }; + acl_pthread_t tid; + acl_pthread_attr_t attr; + char def_addr[] = "127.0.0.1:0"; + ACL_VSTREAM *server_stream; + + acl_get_app_conf_str_table(str_table); + acl_get_app_conf_int_table(int_table); + + server_stream = acl_vstream_listen((addr == NULL || *addr == 0) ? def_addr : addr, 128); + if (server_stream == NULL) { + tlsmgr_before_exit(NULL, NULL); + acl_msg_error("%s(%d): listen addr(%s) error(%s)", + myname, __LINE__, addr, acl_last_serror()); + return; + } + snprintf(var_tlsmgr_service, sizeof(var_tlsmgr_service), + "inet:%s", server_stream->local_addr); + + tlsmgr_pre_init(NULL, NULL); + tlsmgr_post_init(NULL, NULL); + + acl_pthread_attr_init(&attr); +#ifdef ACL_UNIX + acl_pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); +#else + acl_pthread_attr_setdetachstate(&attr, ACL_PTHREAD_CREATE_DETACHED); +#endif + + acl_pthread_create(&tid, &attr, tlsmgr_thread_main, server_stream); +} + +#endif /* USE_TLS */ + diff --git a/lib_tls/tlsmgr/Makefile b/lib_tls/tlsmgr/Makefile new file mode 100644 index 000000000..76ed26b67 --- /dev/null +++ b/lib_tls/tlsmgr/Makefile @@ -0,0 +1,115 @@ +SHELL = /bin/sh +CC = gcc +#CC = g++ +AR = ar +ARFL = rv +RANLIB = ranlib + +CFLAGS = -c -g -W -Wall -Wcast-qual -Wcast-align \ +-Waggregate-return -Wmissing-prototypes \ +-Wpointer-arith -Werror -Wshadow -pedantic -O2 \ +-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO \ +-Wno-long-long \ +-DUSE_TLS +########################################################### +#Check system: +# Linux, SunOS, Solaris, BSD variants, AIX, HP-UX +SYSLIB = +CHECKSYSRES = @echo "Unknow system type!";exit 1 +UNIXNAME = $(shell uname -sm) + +# For FreeBSD +ifeq ($(findstring FreeBSD, $(UNIXNAME)), FreeBSD) + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DFREEBSD -D_REENTRANT -pedantic +endif + +#Path for Linux +ifeq ($(findstring Linux, $(UNIXNAME)), Linux) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DLINUX2 + SYSLIB = -lcrypt -lpthread +endif + +#Path for SunOS +ifeq ($(findstring SunOS, $(UNIXNAME)), SunOS) + ifeq ($(findstring 86, $(UNIXNAME)), 86) + SYSLIB = -lsocket -lnsl -lrt + endif + ifeq ($(findstring sun4u, $(UNIXNAME)), sun4u) + SYSLIB = -lsocket -lnsl -lrt + endif + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DSUNOS5 +endif + +#Path for HP-UX +ifeq ($(findstring HP-UX, $(UNIXNAME)), HP-UX) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + SYSLIB = -lpthread + CFLAGS += -DHP_UX -DHPUX11 + PLAT_NAME=hp-ux +endif + +#Find system type. +ifneq ($(SYSPATH),) + CHECKSYSRES = @echo "System is $(shell uname -sm)" +endif +########################################################### + +ACL_PATH = ../../lib_acl +ACL_INC = $(ACL_PATH)/include +ACL_LIB = $(ACL_PATH)/lib + +TLS_PATH = .. +TLS_INC = $(TLS_PATH)/include +TLS_LIB = $(TLS_PATH)/lib + +DICT_PATH = ../../lib_dict +DICT_INC = $(DICT_PATH)/include +DICT_LIB = $(DICT_PATH)/lib + +ALL_LIBS = -L$(TLS_LIB) -l_tls -L$(DICT_LIB) -l_dict -L$(ACL_LIB) -l_acl \ + -lssl -ldb $(SYSLIB) + +INCLUDE = -I. -I.. -I$(TLS_INC) -I$(DICT_INC) -I$(ACL_INC) +CFLAGS += $(INCLUDE) + +OUTPATH = ./ +OBJ_OUTPATH = $(OUTPATH) + +#Project's objs +SOURCES = $(wildcard *.c) +INCLUDES = $(wildcard *.h) +OBJS = $(patsubst %.c,$(OBJ_OUTPATH)%.o,$(SOURCES)) + +########################################################### + +PROG_NAME = tlsmgr + +.PHONY = clean +COMPILE = $(CC) $(CFLAGS) + +all: RM $(PROG_NAME) + +RM: + rm -f $(PROG_NAME) + +$(PROG_NAME): $(OBJS) + $(CC) -o $(PROG_NAME) $(OBJS) $(LIB_NAME_PATH) $(ALL_LIBS) + +$(OBJ_OUTPATH)%.o: %.c *.h + $(COMPILE) -o $@ $< + +clean: + rm -f $(OBJS) $(PROG_NAME) + +rebuild: clean all diff --git a/lib_tls/tlsmgr/tlsmgr.c b/lib_tls/tlsmgr/tlsmgr.c new file mode 100644 index 000000000..294c45e4e --- /dev/null +++ b/lib_tls/tlsmgr/tlsmgr.c @@ -0,0 +1,17 @@ +#include "lib_acl.h" +/* TLS library. */ + +#ifdef USE_TLS +#include "tls.h" +#include "tls_params.h" + +/* main - the main program, non-TLS version */ + +int main(int argc, char **argv) +{ + var_tlsmgr_stand_alone = 1; + tlsmgr_alone_start(argc, argv); + return (0); +} + +#endif diff --git a/lib_tls/util/allprint.c b/lib_tls/util/allprint.c new file mode 100644 index 000000000..80777af0e --- /dev/null +++ b/lib_tls/util/allprint.c @@ -0,0 +1,17 @@ +#include "StdAfx.h" +#include "stringops.h" + +/* allprint - return true if string is all printable */ + +int allprint(const char *string) +{ + const char *cp; + int ch; + + if (*string == 0) + return (0); + for (cp = string; (ch = *(const unsigned char *) cp) != 0; cp++) + if (!ACL_ISASCII(ch) || !ACL_ISPRINT(ch)) + return (0); + return (1); +} diff --git a/lib_tls/util/name_code.c b/lib_tls/util/name_code.c new file mode 100644 index 000000000..d82ae1aff --- /dev/null +++ b/lib_tls/util/name_code.c @@ -0,0 +1,34 @@ +#include "StdAfx.h" +#include +#include +#include "name_code.h" + +/* name_code - look up code by name */ + +int name_code(const NAME_CODE *table, int flags, const char *name) +{ + const NAME_CODE *np; + int (*lookup) (const char *, const char *); + + if (flags & NAME_CODE_FLAG_STRICT_CASE) + lookup = strcmp; + else + lookup = strcasecmp; + + for (np = table; np->name; np++) + if (lookup(name, np->name) == 0) + break; + return (np->code); +} + +/* str_name_code - look up name by code */ + +const char *str_name_code(const NAME_CODE *table, int code) +{ + const NAME_CODE *np; + + for (np = table; np->name; np++) + if (code == np->code) + break; + return (np->name); +} diff --git a/lib_tls/util/name_code.h b/lib_tls/util/name_code.h new file mode 100644 index 000000000..3cd6c8899 --- /dev/null +++ b/lib_tls/util/name_code.h @@ -0,0 +1,40 @@ +#ifndef _NAME_CODE_H_INCLUDED_ +#define _NAME_CODE_H_INCLUDED_ + +/*++ + * NAME + * name_mask 3h + * SUMMARY + * name to number table mapping + * SYNOPSIS + * #include + * DESCRIPTION + * .nf + + * + * External interface. + */ +typedef struct { + const char *name; + int code; +} NAME_CODE; + +#define NAME_CODE_FLAG_NONE 0 +#define NAME_CODE_FLAG_STRICT_CASE (1<<0) + +extern int name_code(const NAME_CODE *, int, const char *); +extern const char *str_name_code(const NAME_CODE *, int); + +/* LICENSE + * .ad + * .fi + * The Secure Mailer license must be distributed with this software. + * AUTHOR(S) + * Wietse Venema + * IBM T.J. Watson Research + * P.O. Box 704 + * Yorktown Heights, NY 10598, USA + *--*/ + +#endif + diff --git a/lib_tls/util/name_mask.c b/lib_tls/util/name_mask.c new file mode 100644 index 000000000..0f12e41f2 --- /dev/null +++ b/lib_tls/util/name_mask.c @@ -0,0 +1,255 @@ +/*++ + * NAME + * name_mask 3 + * SUMMARY + * map names to bit mask + * SYNOPSIS + * #include + * + * int name_mask(context, table, names) + * const char *context; + * const NAME_MASK *table; + * const char *names; + * + * const char *str_name_mask(context, table, mask) + * const char *context; + * const NAME_MASK *table; + * int mask; + * + * int name_mask_opt(context, table, names, flags) + * const char *context; + * const NAME_MASK *table; + * const char *names; + * int flags; + * + * int name_mask_delim_opt(context, table, names, delim, flags) + * const char *context; + * const NAME_MASK *table; + * const char *names; + * const char *delim; + * int flags; + * + * const char *str_name_mask_opt(buf, context, table, mask, flags) + * VSTRING *buf; + * const char *context; + * const NAME_MASK *table; + * int mask; + * int flags; + * DESCRIPTION + * name_mask() takes a null-terminated \fItable\fR with (name, mask) + * values and computes the bit-wise OR of the masks that correspond + * to the names listed in the \fInames\fR argument, separated by + * comma and/or whitespace characters. + * + * str_name_mask() translates a mask into its equivalent names. + * The result is written to a static buffer that is overwritten + * upon each call. + * + * name_mask_opt() and str_name_mask_opt() are extended versions + * with additional fine control. name_mask_delim_opt() supports + * non-default delimiter characters. + * + * Arguments: + * .IP buf + * Null pointer or pointer to buffer storage. + * .IP context + * What kind of names and + * masks are being manipulated, in order to make error messages + * more understandable. Typically, this would be the name of a + * user-configurable parameter. + * .IP table + * Table with (name, bit mask) pairs. + * .IP names + * A list of names that is to be converted into a bit mask. + * .IP mask + * A bit mask. + * .IP flags + * Bit-wise OR of zero or more of the following: + * .IP delim + * Delimiter characters to use instead of whitespace and commas. + * .RS + * .IP NAME_MASK_FATAL + * Require that all names listed in \fIname\fR exist in \fItable\fR, + * and that all bits listed in \fImask\fR exist in \fItable\fR. + * Terminate with a fatal run-time error if this condition is not met. + * This feature is enabled by default when calling name_mask() + * or str_name_mask(). + * .IP NAME_MASK_RETURN + * Require that all names listed in \fIname\fR exist in \fItable\fR, + * and that all bits listed in \fImask\fR exist in \fItable\fR. + * Log a warning, and return 0 (name_mask()) or a null pointer + * (str_name_mask()) if this condition is not met. + * .IP NAME_MASK_NUMBER + * Require that all bits listed in \fImask\fR exist in \fItable\fR. + * For unrecognized bits, print the numerical hexadecimal form. + * .IP NAME_MASK_ANY_CASE + * Enable case-insensitive matching. + * This feature is not enabled by default when calling name_mask(); + * it has no effect with str_name_mask(). + * .IP NAME_MASK_COMMA + * Use comma instead of space when converting a mask to string. + * .IP NAME_MASK_PIPE + * Use "|" instead of space when converting a mask to string. + * .RE + * The value NAME_MASK_NONE explicitly requests no features, + * and NAME_MASK_DEFAULT enables the default options. + * DIAGNOSTICS + * Fatal: the \fInames\fR argument specifies a name not found in + * \fItable\fR, or the \fImask\fR specifies a bit not found in + * \fItable\fR. + * LICENSE + * .ad + * .fi + * The Secure Mailer license must be distributed with this software. + * AUTHOR(S) + * Wietse Venema + * IBM T.J. Watson Research + * P.O. Box 704 + * Yorktown Heights, NY 10598, USA + *--*/ + +/* System library. */ + +#include "StdAfx.h" +#include + +/* Utility library. */ + +#include "name_mask.h" + +#define STR(x) acl_vstring_str(x) + +/* name_mask_delim_opt - compute mask corresponding to list of names */ + +int name_mask_delim_opt(const char *context, const NAME_MASK *table, + const char *names, const char *delim, int flags) +{ + const char *myname = "name_mask"; + char *saved_names = acl_mystrdup(names); + char *bp = saved_names; + int result = 0; + const NAME_MASK *np; + char *name; + int (*lookup) (const char *, const char *); + + if (flags & NAME_MASK_ANY_CASE) + lookup = strcasecmp; + else + lookup = strcmp; + + /* + * Break up the names string, and look up each component in the table. If + * the name is found, merge its mask with the result. + */ + while ((name = acl_mystrtok(&bp, delim)) != 0) { + for (np = table; /* void */ ; np++) { + if (np->name == 0) { + if (flags & NAME_MASK_FATAL) + acl_msg_fatal("unknown %s value \"%s\" in \"%s\"", + context, name, names); + if (flags & NAME_MASK_RETURN) { + acl_msg_warn("unknown %s value \"%s\" in \"%s\"", + context, name, names); + return (0); + } + break; + } + if (lookup(name, np->name) == 0) { + if (acl_msg_verbose) + acl_msg_info("%s: %s", myname, name); + result |= np->mask; + break; + } + } + } + acl_myfree(saved_names); + return (result); +} + +static void free_vstring(void *arg) +{ + ACL_VSTRING *s = (ACL_VSTRING*) arg; + + acl_vstring_free(s); +} + +/* str_name_mask_opt - mask to string */ + +const char *str_name_mask_opt(ACL_VSTRING *buf, const char *context, + const NAME_MASK *table, + int mask, int flags) +{ + const char *myname = "name_mask"; + const NAME_MASK *np; + int len; + static __thread ACL_VSTRING *my_buf = 0; + int delim = (flags & NAME_MASK_COMMA ? ',' : + (flags & NAME_MASK_PIPE ? '|' : ' ')); + + if (buf == 0) { + if (my_buf == 0) { + my_buf = acl_vstring_alloc(1); + acl_pthread_atexit_add(my_buf, free_vstring); + } + buf = my_buf; + } + ACL_VSTRING_RESET(buf); + + for (np = table; mask != 0; np++) { + if (np->name == 0) { + if (flags & NAME_MASK_FATAL) { + acl_msg_fatal("%s: unknown %s bit in mask: 0x%x", + myname, context, mask); + } else if (flags & NAME_MASK_RETURN) { + acl_msg_warn("%s: unknown %s bit in mask: 0x%x", + myname, context, mask); + return (0); + } else if (flags & NAME_MASK_NUMBER) { + acl_vstring_sprintf_append(buf, "0x%x%c", mask, delim); + } + break; + } + if (mask & np->mask) { + mask &= ~np->mask; + acl_vstring_sprintf_append(buf, "%s%c", np->name, delim); + } + } + if ((len = (int) ACL_VSTRING_LEN(buf)) > 0) + acl_vstring_truncate(buf, len - 1); + ACL_VSTRING_TERMINATE(buf); + + return (STR(buf)); +} + +#ifdef TEST + + /* + * Stand-alone test program. + */ +#include +#include "stdlib/acl_vstream.h" + +int main(int argc, char **argv) +{ + static const NAME_MASK table[] = { + "zero", 1 << 0, + "one", 1 << 1, + "two", 1 << 2, + "three", 1 << 3, + 0, 0, + }; + int mask; + ACL_VSTRING *buf = acl_vstring_alloc(1); + + while (--argc && *++argv) { + mask = name_mask("test", table, *argv); + acl_vstream_printf("%s -> 0x%x -> %s\n", + *argv, mask, str_name_mask("mask_test", table, mask)); + acl_vstream_fflush(VSTREAM_OUT); + } + acl_vstring_free(buf); + exit(0); +} + +#endif + diff --git a/lib_tls/util/name_mask.h b/lib_tls/util/name_mask.h new file mode 100644 index 000000000..b8dd32e57 --- /dev/null +++ b/lib_tls/util/name_mask.h @@ -0,0 +1,63 @@ +#ifndef _NAME_MASK_H_INCLUDED_ +#define _NAME_MASK_H_INCLUDED_ + +/*++ + * NAME + * name_mask 3h + * SUMMARY + * map names to bit mask + * SYNOPSIS + * #include + * DESCRIPTION + * .nf + + * + * Utility library. + */ +#include "stdlib/acl_vstring.h" + + /* + * External interface. + */ +typedef struct { + const char *name; + int mask; +} NAME_MASK; + +#define NAME_MASK_FATAL (1<<0) +#define NAME_MASK_ANY_CASE (1<<1) +#define NAME_MASK_RETURN (1<<2) +#define NAME_MASK_COMMA (1<<3) +#define NAME_MASK_PIPE (1<<4) +#define NAME_MASK_NUMBER (1<<5) + +#define NAME_MASK_MATCH_REQ NAME_MASK_FATAL + +#define NAME_MASK_NONE 0 +#define NAME_MASK_DEFAULT (NAME_MASK_FATAL) +#define NAME_MASK_DEFAULT_DELIM ", \t\r\n" + +#define name_mask_opt(tag, table, str, flags) \ + name_mask_delim_opt((tag), (table), (str), \ + NAME_MASK_DEFAULT_DELIM, (flags)) +#define name_mask(tag, table, str) \ + name_mask_opt((tag), (table), (str), NAME_MASK_DEFAULT) +#define str_name_mask(tag, table, mask) \ + str_name_mask_opt(((VSTRING *) 0), (tag), (table), (mask), NAME_MASK_DEFAULT) + +extern int name_mask_delim_opt(const char *, const NAME_MASK *, const char *, const char *, int); +extern const char *str_name_mask_opt(ACL_VSTRING *, const char *, const NAME_MASK *, int, int); + +/* LICENSE + * .ad + * .fi + * The Secure Mailer license must be distributed with this software. + * AUTHOR(S) + * Wietse Venema + * IBM T.J. Watson Research + * P.O. Box 704 + * Yorktown Heights, NY 10598, USA + *--*/ + +#endif + diff --git a/lib_tls/util/printable.c b/lib_tls/util/printable.c new file mode 100644 index 000000000..997b1e47f --- /dev/null +++ b/lib_tls/util/printable.c @@ -0,0 +1,13 @@ +#include "StdAfx.h" +#include "stringops.h" + +char *printable(char *string, int replacement) +{ + char *cp; + int ch; + + for (cp = string; (ch = *(unsigned char *) cp) != 0; cp++) + if (!ACL_ISASCII(ch) || !ACL_ISPRINT(ch)) + *cp = replacement; + return (string); +} diff --git a/lib_tls/util/stringops.h b/lib_tls/util/stringops.h new file mode 100644 index 000000000..a7db1ebc2 --- /dev/null +++ b/lib_tls/util/stringops.h @@ -0,0 +1,7 @@ +#ifndef __STRINGOPS_INCLUDE_H__ +#define __STRINGOPS_INCLUDE_H__ + +char *printable(char *string, int replacement); +int allprint(const char *string); + +#endif diff --git a/readme.txt b/readme.txt new file mode 100644 index 000000000..f696c7461 --- /dev/null +++ b/readme.txt @@ -0,0 +1,60 @@ +一、概述 + acl 工程是一个跨平台的通用网络通信库,同时提供更多的其它有价值功能。通过该库,用户可以非常容易地编写支持多种模式的服务器程序、WEB 应用程序以及数据库应用程序。此外,该库还提供了 XML/JSON/MIME 编码及解码功能,这些编码解码库均支持流式解析模式,从而使之更适应不同的网络通讯方式。 + 本工程主要包含 5 个库及大量示例。5 个库的说明如下: + 1) lib_acl: 该库是最基础的库,其它 4 个库均依赖于该库; 该库以 C 语言实现。 + 2) lib_protocol: 该库主要实现了 http 协议及 icmp/ping 协议; 该库以 C 语言实现。 + 3) lib_acl_cpp: 该库用 C++ 语言封装了 lib_acl/lib_protocol 两个库,同时增加了一些其它有价值的功能应用。 + 4) lib_dict: 该库主要实现了 KEY-VALUE 的字典式存储库,该库另外还依赖于 BDB, CDB 以及 tokyocabinet 库。 + 5) lib_tls: 该库封装了 openssl 库,使 lib_acl 的通信模式可以支持 ssl。 + +二、平台支持及编译 + 整个工程目前支持 Linux(AS4,5,6, CS4,5,6), Windows, MacOS, (原本也支持 FreeBSD, Solaris, 现在如果谁有这些环境,可以轻松移植到这些平台上)。 + 1) Linux/MacOS: 直接在终端命令行方式下分别进入 lib_acl/lib_protocol/lib_acl_cpp/lib_dict/lib_tls 目录下,运行 make 命令即可。 + 2) Windows: 可以用 VC2003/VC2010 进行编译。(如果您需要用 VC6/VC2005/VC2008 编译,可以参考 VC2003 的编译条件)。 + 当在 WIN32 环境下使用动态库时有几点需要注意: + a) 使用 lib_acl 的动态库时,需要在用户的工程预定义: ACL_DLL; + b) 使用 lib_protocol 动态库中的 HTTP 库或 ICMP 库时,需要在工程中预定义 HTTP_DLL 或 ICMP_DLL; + c) 使用 lib_acl_cpp 的动态库时,需要在工程中预定义 ACL_CPP_DLL,如果您使用用 VC2003 编译环境则还需要预定义 VC2003; + d) 使用 lib_dict 的动态库时,需要在工程中预定义 DICT_DLL; + e) 使用 lib_tls 的动态库时,需要在工程中预定义 TLS_DLL。 + +三、本工程结构说明 + 1) lib_acl + 1.1 init/ : 主要用于初始化 acl 基础库 + 1.2 stdlib/ : 是一些比较基础的功能函数库,在 stdlib/ 根目录下主要包括一些有关日志记录、网络/文件流处理、VSTRING缓冲操作等功能函数;在 stdlib/ 下还有二级目录,如下: + 1.2.1 common/ : 该目录主要为一些常用的数据结构及算法的功能函数库,象哈希表、链表、队列、动态数组、堆栈、缓存、平衡二叉树、模式匹配树等; + 1.2.2 memory/ : 该目录主要包含与内存操作相关的函数库,象内存基础分配与校验、内存池管理、内存切片管理等; + 1.2.3 filedir/ : 该目录主要包含与目录遍历、目录创建等相关的库; + 1.2.4 configure/ : 该目录主要包含配置文件的分析库; + 1.2.5 iostuff/ : 该目录主要包含一些常用的IO操作的函数库,象读/写超时、设置IO句柄的阻塞模式等; + 1.2.6 string/ : 该目录主要包含一些常用的字符串操作的库,提供了比标准C更灵活高效的字符串操作功能; + 1.2.7 debug/ : 主要用于协助调试内存的泄露等功能; + 1.2.8 sys/ : 主要是与不同操作系统平台相关的API的封装函数库; + 1.3 net/: 是与网络操作相关的函数库,包含网络监听、网络连接、DNS查询、套接口参数设置等功能; + 1.3.1 connect/ : 主要是与网络连接相关的函数库,包含网络连接、域套接口连接等; + 1.3.2 listen/ : 主要是与网络监听相关的函数库,包含网络监听、域套接口监听等; + 1.3.3 dns/ : 主要是与DNS域名查询相关的函数库,包含对 gethostbyname 等接口的封装、按RFC1035标准直接发送UDP包方式进行查询等功能; + 1.4 event/ : 主要封装了 select/poll/epoll/iocp/win message/kqueue/devpoll 等系统API接口,使处理网络事件更加灵活、高效、简单,另外还包含定时器接口,acl 中的很多网络应用都会用到这些接口,象 aio、master 等模块; + 1.5 aio/ : 主要包含网络异步操作的功能函数,该套函数库在处理高并发时有非常高的效率,而且提供了比基础API更为高级的调用方式,比使用象 libevent 之类的函数库更为简单,而且是线程安全的; + 1.6 msg/ : 主要包含了基于线程的消息事件及基于网络的消息事件功能; + 1.7 thread/ : 主要是封装了各个OS平台下的基础线程API,使对外接口保持一致性,消除了平台的差异性,同时还提供了半驻留线程池的函数库,以及对于线程局部变量的扩展; + 1.8 db/ : 主要是一些与数据库有关的功能库,定义了一个通用的数据库连接池的框架(并且实现了mysql的连接池实例);一个简单的内存数据库(由哈希表、链表、平衡二叉树组合而成);ZDB数据存储引擎,这是一个高效的基于数字键的存储引擎; + 1.9 proctl/ : win32 平台下父子进程控制功能库; + 1.10 code/ : 常见编码函数库,包括 base64编解码、URL编解码以及一些汉字字符集编码等; + 1.11 unit_test/ : 包含有关进行 C 语言单元测试的功能库; + 1.12 xml/:是一个流式的 xml 解析器及构造器,可以支持阻塞及阻塞式网络通信; + 1.13 json/:是一个流式的 json 解析器及构造器,可以支持阻塞及阻塞式网络通信; + 1.14 master/: 是在 UNIX 环境下支持多种服务器模式的服务器框架,目前主要支持多进程模式、多进程多线程模式、多进程非阻塞模式以及多进程触发器模式; + + 2) lib_protocol + 2.1 http/: HTTP 协议相关的库,支持 HTTP/1.1,通讯方式支持同步/异步方式 + 2.2 icmp/: icmp/ping 协议库,支持同步/异步通信方式 + + 3) lib_acl_cpp + 3.1 stdlib/: 主要包含字符串处理类(string),xml/json 解析库,zlib 压缩库(依赖于 zlib 库), 日志记录类, 字符集转码(在UNIX环境下需要 iconv 库), memcached 客户库, 互斥类(支持线程锁、文件锁); + 3.2 stream/: 支持网络流/文件流,支持阻塞/非阻塞两种通信方式,在非阻塞模式下支持 select/poll/epoll/iocp/win32 message/kqueue/devpoll;支持 ssl 加密传输(阻塞及非阻塞方式,需要 polarssl库); + 3.3 ipc/: 在非阻塞通信方式,提供了阻塞模块与非阻塞模块整合的方式; + 3.4 http/: 比较完整的 HTTP 通信库及协议解析库,支持客户端及服务端模式,支持 ssl/gzip 传输方式; 支持类似于 Java HttpServlet 方式的大部分接口,方便编写 CGI 及服务器程序; + 3.5 db/: 封装了 MYSQL/SQLITE 库,支持数据库连接池; + 3.6 hsocket/: 实现了完整的 handler-socket 客户端通信库; + 3.7 mime/: 支持完整的与邮件编码相关的库(邮件的 rfc2045-rfc2047/rfc822/base64/uucode 编码及解码库). diff --git a/release-notes.txt b/release-notes.txt new file mode 100644 index 000000000..459017992 --- /dev/null +++ b/release-notes.txt @@ -0,0 +1,34 @@ +acl 3.0.8 (2013.6.25) + +一、lib_acl +1) feature: acl_master 框架支持在一个配置文件中监听多个地址(可以为 TCP +套接口与域套接口混用) +2) feature: acl_master 框架支持在 reload 时的 prefork,修改的相关文件有: +master_avail.c, master_service.c, master_spawn.c, master.h +3) acl_master_log.c: 将日志输出信息当调试状态对待 +4) bugfix: acl_array.c->acl_array_prepend,其中调用的 acl_array_succ_insert, +应该调用 acl_array_pred_insert,该 BUG 会影响到所有调用 acl_dlink, acl_iplink, +acl_access 函数的地方,包括 acl_aio_app_main.c/acl_ioctl_app_main.c 中有关访问 +权限的地方 +5) 将 acl_iplink.c 中的函数调用映射为直接调用 acl_dlink.c 中的方法 +6) samples/iplink: 该例子用于测试 acl_iplink.c 中的相关函数 +7) bugfix: acl_mylog.c->reopen_log 函数中的 RETURN 宏定义中应该是 +thread_mutex_unlock,原来的 thread_mutex_lock 会造成死锁 +8) bugfix: acl_json_parse.c: 有些汉字,如“誠”的后半个字节的值正好与转义字符 +相同,即为 92,所以需要兼容此情况,当判断 last_ch < 0 且当前 char 为 92 +时,则认为 +汉字情况; acl_xml_parse.c 也存在类似问题,已修复 +9) acl_json.c/acl_xml.c: 当启用结点对象缓存策略时,acl_json_node_reset 和 +acl_xml_node_reset 中调用 ACL_VSTRING_RESET 后还应该调用 ACL_VSTRING_TERMINATE +10) bugfix: acl_basename.c -> acl_safe_basename 在 3 月份修改的有误 + +二、lib_protocol +1) performance: http 协议库提高了 HTTP 头的解析速度,由原来的每秒 5 万 +多次提升至每秒 17 万多次 +2) bugfix: http 协议库中 http_hdr_reset 函数判断 hh 参数是否合法时有误 + +三、lib_acl_cpp +1) feature: 添加了 server_socket 类 +2) socket_stream: 对 get_ip 类的函数做了一定调整 +3) samples/benchmark: 增加了 client/server 两个用于测试 IO 压力的程序 +4) feature: HttpServletRequest/http_client 添加调试输出 HTTP 请求头的函数 diff --git a/samples/FileDir/FileDir.aps b/samples/FileDir/FileDir.aps new file mode 100644 index 000000000..9ce908f25 Binary files /dev/null and b/samples/FileDir/FileDir.aps differ diff --git a/samples/FileDir/FileDir.cpp b/samples/FileDir/FileDir.cpp new file mode 100644 index 000000000..95350d463 --- /dev/null +++ b/samples/FileDir/FileDir.cpp @@ -0,0 +1,79 @@ +// FileDir.cpp : 定义应用程序的类行为。 +// + +#include "stdafx.h" +#include "FileDir.h" +#include "FileDirDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#endif + + +// CFileDirApp + +BEGIN_MESSAGE_MAP(CFileDirApp, CWinApp) + ON_COMMAND(ID_HELP, CWinApp::OnHelp) +END_MESSAGE_MAP() + + +// CFileDirApp 构造 + +CFileDirApp::CFileDirApp() +{ + // TODO: 在此处添加构造代码, + // 将所有重要的初始化放置在 InitInstance 中 +} + + +// 唯一的一个 CFileDirApp 对象 + +CFileDirApp theApp; + + +// CFileDirApp 初始化 + +BOOL CFileDirApp::InitInstance() +{ + // 如果一个运行在 Windows XP 上的应用程序清单指定要 + // 使用 ComCtl32.dll 版本 6 或更高版本来启用可视化方式, + //则需要 InitCommonControls()。否则,将无法创建窗口。 + InitCommonControls(); + + CWinApp::InitInstance(); + + if (!AfxSocketInit()) + { + AfxMessageBox(IDP_SOCKETS_INIT_FAILED); + return FALSE; + } + + AfxEnableControlContainer(); + + // 标准初始化 + // 如果未使用这些功能并希望减小 + // 最终可执行文件的大小,则应移除下列 + // 不需要的特定初始化例程 + // 更改用于存储设置的注册表项 + // TODO: 应适当修改该字符串, + // 例如修改为公司或组织名 + SetRegistryKey(_T("应用程序向导生成的本地应用程序")); + + CFileDirDlg dlg; + m_pMainWnd = &dlg; + INT_PTR nResponse = dlg.DoModal(); + if (nResponse == IDOK) + { + // TODO: 在此放置处理何时用“确定”来关闭 + //对话框的代码 + } + else if (nResponse == IDCANCEL) + { + // TODO: 在此放置处理何时用“取消”来关闭 + //对话框的代码 + } + + // 由于对话框已关闭,所以将返回 FALSE 以便退出应用程序, + // 而不是启动应用程序的消息泵。 + return FALSE; +} diff --git a/samples/FileDir/FileDir.h b/samples/FileDir/FileDir.h new file mode 100644 index 000000000..5ed39b9e3 --- /dev/null +++ b/samples/FileDir/FileDir.h @@ -0,0 +1,31 @@ +// FileDir.h : PROJECT_NAME 应用程序的主头文件 +// + +#pragma once + +#ifndef __AFXWIN_H__ + #error 在包含用于 PCH 的此文件之前包含“stdafx.h” +#endif + +#include "resource.h" // 主符号 + + +// CFileDirApp: +// 有关此类的实现,请参阅 FileDir.cpp +// + +class CFileDirApp : public CWinApp +{ +public: + CFileDirApp(); + +// 重写 + public: + virtual BOOL InitInstance(); + +// 实现 + + DECLARE_MESSAGE_MAP() +}; + +extern CFileDirApp theApp; diff --git a/samples/FileDir/FileDir.rc b/samples/FileDir/FileDir.rc new file mode 100644 index 000000000..149c7d287 --- /dev/null +++ b/samples/FileDir/FileDir.rc @@ -0,0 +1,234 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// 中文(中华人民共和国) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) +#ifdef _WIN32 +LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED +#pragma code_page(936) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "#define _AFX_NO_SPLITTER_RESOURCES\r\n" + "#define _AFX_NO_OLE_RESOURCES\r\n" + "#define _AFX_NO_TRACKER_RESOURCES\r\n" + "#define _AFX_NO_PROPERTY_RESOURCES\r\n" + "\r\n" + "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)\r\n" + "LANGUAGE 4, 2\r\n" + "#pragma code_page(936)\r\n" + "#include ""res\\FileDir.rc2"" // 非 Microsoft Visual C++ 编辑过的资源\r\n" + "#include ""afxres.rc"" // 标准组件\r\n" + "#endif\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDR_MAINFRAME ICON "res\\FileDir.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_ABOUTBOX DIALOGEX 0, 0, 235, 55 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | + WS_SYSMENU +CAPTION "关于 FileDir" +FONT 9, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + ICON IDR_MAINFRAME,IDC_STATIC,11,17,20,20 + LTEXT "FileDir Version 1.0",IDC_STATIC,40,10,119,8,SS_NOPREFIX + LTEXT "Copyright (C) 2008",IDC_STATIC,40,25,119,8 + DEFPUSHBUTTON "确定",IDOK,178,7,50,16,WS_GROUP +END + +IDD_FILEDIR_DIALOG DIALOGEX 0, 0, 347, 335 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_MINIMIZEBOX | + WS_MAXIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_WINDOWEDGE | WS_EX_APPWINDOW +CAPTION "FileDir" +FONT 9, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + DEFPUSHBUTTON "退出",IDOK,266,285,50,16 + EDITTEXT IDC_EDIT_PATH,94,24,179,14,ES_AUTOHSCROLL + CONTROL "扫描子目录",IDC_CHECK_NETSTED,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,161,47,50,10 + PUSHBUTTON " 扫描",IDC_BUTTON_SCAN,223,46,50,14 + PUSHBUTTON "删除",IDC_BUTTON_DELETE,223,67,50,14 + EDITTEXT IDC_EDIT_AVL_NAME,78,129,72,14,ES_AUTOHSCROLL + EDITTEXT IDC_EDIT_AVL_VALUE,176,129,132,14,ES_AUTOHSCROLL + PUSHBUTTON "avl add",IDC_BUTTON_AVL_ADD,35,155,50,14 + PUSHBUTTON "avl find",IDC_BUTTON_AVL_FIND,90,155,50,14 + PUSHBUTTON "avl delete",IDC_BUTTON_AVL_DEL,146,155,50,14 + PUSHBUTTON "avl add some",IDC_BUTTON_AVL_ADD_BAT,202,155,50,14 + PUSHBUTTON "avl walk",IDC_BUTTON_WALK,258,155,50,14 + PUSHBUTTON "清空",IDC_BUTTON_CLEAR,29,285,50,14 + EDITTEXT IDC_EDIT_AV_RESULT,37,193,273,70,ES_MULTILINE | + ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN | + WS_VSCROLL | WS_HSCROLL + LTEXT "扫描路径:",IDC_STATIC,39,26,35,8 + LTEXT "空间大小:",IDC_STATIC,40,47,35,8 + LTEXT "文件总数:",IDC_STATIC,40,70,35,8 + LTEXT "目录总数:",IDC_STATIC,40,92,35,8 + EDITTEXT IDC_EDIT_SIZE,94,47,58,14,ES_AUTOHSCROLL | ES_READONLY | + NOT WS_BORDER,WS_EX_TRANSPARENT + EDITTEXT IDC_EDIT_NFILE,94,70,59,14,ES_AUTOHSCROLL | ES_READONLY | + NOT WS_BORDER,WS_EX_TRANSPARENT + EDITTEXT IDC_EDIT_NDIR,94,92,59,14,ES_AUTOHSCROLL | ES_READONLY | + NOT WS_BORDER,WS_EX_TRANSPARENT + PUSHBUTTON "test",IDC_BUTTON_TEST,137,285,50,14 + GROUPBOX "目录操作",IDC_STATIC,29,10,287,105 + LTEXT "输入:",IDC_STATIC,38,130,22,8 + GROUPBOX "avl 树 ",IDC_STATIC,29,118,287,59 + LTEXT "名",IDC_STATIC,65,130,8,8 + LTEXT "值",IDC_STATIC,166,131,8,8 + CONTROL "输出文件名",IDC_CHECK_OUT_NAME,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,161,62,50,10 + GROUPBOX "输出窗口",IDC_STATIC,29,182,287,89 + PUSHBUTTON "SVN更新",IDC_SVN_UPDATE,222,90,50,14 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "080403a8" + BEGIN + VALUE "CompanyName", "TODO: <公司名>" + VALUE "FileDescription", "TODO: <文件说明>" + VALUE "FileVersion", "1.0.0.1" + VALUE "InternalName", "FileDir.exe" + VALUE "LegalCopyright", "TODO: (C) <公司名>。保留所有权利。" + VALUE "OriginalFilename", "FileDir.exe" + VALUE "ProductName", "TODO: <产品名>" + VALUE "ProductVersion", "1.0.0.1" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "翻译", 0x804, 936 + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_ABOUTBOX, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 228 + TOPMARGIN, 7 + BOTTOMMARGIN, 48 + END + + IDD_FILEDIR_DIALOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 340 + TOPMARGIN, 7 + BOTTOMMARGIN, 328 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + IDS_ABOUTBOX "关于 FileDir(&A)..." + IDP_SOCKETS_INIT_FAILED "Windows 套接字初始化失败。" +END + +#endif // 中文(中华人民共和国) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +#define _AFX_NO_SPLITTER_RESOURCES +#define _AFX_NO_OLE_RESOURCES +#define _AFX_NO_TRACKER_RESOURCES +#define _AFX_NO_PROPERTY_RESOURCES + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) +LANGUAGE 4, 2 +#pragma code_page(936) +#include "res\FileDir.rc2" // 非 Microsoft Visual C++ 编辑过的资源 +#include "afxres.rc" // 标准组件 +#endif + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/samples/FileDir/FileDir.vcxproj b/samples/FileDir/FileDir.vcxproj new file mode 100644 index 000000000..4f047a0a1 --- /dev/null +++ b/samples/FileDir/FileDir.vcxproj @@ -0,0 +1,264 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + ReleaseDll + Win32 + + + Release + Win32 + + + Template + Win32 + + + + FileDir + {71F3CDEF-30E4-4F2F-9D3B-139EA3723CE2} + MFCProj + + + + Application + Dynamic + MultiByte + + + Application + Dynamic + MultiByte + + + Application + Static + MultiByte + + + Application + Static + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_WINDOWS;_DEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + true + + + Level3 + EditAndContinue + + + %(AdditionalLibraryDirectories) + %(IgnoreSpecificDefaultLibraries) + true + Windows + MachineX86 + + + _DEBUG;%(PreprocessorDefinitions) + false + + + _DEBUG;%(PreprocessorDefinitions) + 0x0804 + $(IntDir);%(AdditionalIncludeDirectories) + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_WINDOWS;NDEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + false + MultiThreaded + true + + + Level3 + ProgramDatabase + + + %(AdditionalLibraryDirectories) + %(IgnoreSpecificDefaultLibraries) + true + Windows + true + true + MachineX86 + + + NDEBUG;%(PreprocessorDefinitions) + false + + + NDEBUG;%(PreprocessorDefinitions) + 0x0804 + $(IntDir);%(AdditionalIncludeDirectories) + + + + + Disabled + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_WINDOWS;_DEBUG;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + true + + + Level3 + EditAndContinue + + + %(AdditionalLibraryDirectories) + libcmtd;%(IgnoreSpecificDefaultLibraries) + true + Windows + MachineX86 + + + _DEBUG;%(PreprocessorDefinitions) + false + + + _DEBUG;%(PreprocessorDefinitions) + 0x0804 + $(IntDir);%(AdditionalIncludeDirectories) + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_WINDOWS;NDEBUG;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + false + MultiThreadedDLL + true + + + Level3 + ProgramDatabase + + + %(AdditionalLibraryDirectories) + libcmtd;libcmt;%(IgnoreSpecificDefaultLibraries) + true + Windows + true + true + MachineX86 + + + NDEBUG;%(PreprocessorDefinitions) + false + + + NDEBUG;%(PreprocessorDefinitions) + 0x0804 + $(IntDir);%(AdditionalIncludeDirectories) + + + + + + + + Create + Create + Create + Create + + + + + + + + + + + + + + + + + + + + + + + {b40213c2-507c-4c7f-a6e1-b850c9bdc27b} + false + + + + + + + + + + + \ No newline at end of file diff --git a/samples/FileDir/FileDir.vcxproj.filters b/samples/FileDir/FileDir.vcxproj.filters new file mode 100644 index 000000000..9641a2d70 --- /dev/null +++ b/samples/FileDir/FileDir.vcxproj.filters @@ -0,0 +1,65 @@ +锘 + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx + + + + + 婧愭枃浠 + + + 婧愭枃浠 + + + 婧愭枃浠 + + + 婧愭枃浠 + + + + + 澶存枃浠 + + + 澶存枃浠 + + + 澶存枃浠 + + + 澶存枃浠 + + + 澶存枃浠 + + + + + 璧勬簮鏂囦欢 + + + 璧勬簮鏂囦欢 + + + + + + 璧勬簮鏂囦欢 + + + + + + \ No newline at end of file diff --git a/samples/FileDir/FileDirDlg.cpp b/samples/FileDir/FileDirDlg.cpp new file mode 100644 index 000000000..62da85f66 --- /dev/null +++ b/samples/FileDir/FileDirDlg.cpp @@ -0,0 +1,753 @@ +// FileDirDlg.cpp : 实现文件 +// + +#include "stdafx.h" +#include "lib_acl.h" // 注意:lib_acl.h 必须放在 stdafx.h 的后面,否则编译会出错:( +#include "stdlib/avl.h" +#include "FileDir.h" +#include "FileDirDlg.h" +#include "ScanDir.h" +#include ".\filedirdlg.h" +#ifdef _DEBUG +#define new DEBUG_NEW +#endif + +#ifdef WIN32 +#define snprintf _snprintf +#endif + +#include +#define __S_ISTYPE(mode, mask) (((mode) & _S_IFMT) == (mask)) +#ifndef S_ISDIR +# define S_ISDIR(mode) __S_ISTYPE((mode), _S_IFDIR) +#endif + +typedef struct MY_TYPE +{ + char name[256]; + char value[256]; + avl_node_t node; +} MY_TYPE; + + +// 用于应用程序“关于”菜单项的 CAboutDlg 对话框 + +class CAboutDlg : public CDialog +{ +public: + CAboutDlg(); + +// 对话框数据 + enum { IDD = IDD_ABOUTBOX }; + + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 + +// 实现 +protected: + DECLARE_MESSAGE_MAP() +}; + +CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) +{ +} + +void CAboutDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); +} + +BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) +END_MESSAGE_MAP() + + +// CFileDirDlg 对话框 + +CFileDirDlg::CFileDirDlg(CWnd* pParent /*=NULL*/) + : CDialog(CFileDirDlg::IDD, pParent) + , m_dirPath(_T("")) + , m_nested(TRUE) + , m_pScan(NULL) + , m_avlName(_T("")) + , m_avlValue(_T("")) + , m_outName(FALSE) +{ + m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); + + avl_create(&m_avlTree, compare_fn, sizeof(MY_TYPE), offsetof(MY_TYPE, node)); +} + +void CFileDirDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + DDX_Text(pDX, IDC_EDIT_PATH, m_dirPath); + DDX_Check(pDX, IDC_CHECK_NETSTED, m_nested); + DDX_Text(pDX, IDC_EDIT_AVL_NAME, m_avlName); + DDX_Control(pDX, IDC_EDIT_AV_RESULT, m_debugWin); + DDX_Text(pDX, IDC_EDIT_AVL_VALUE, m_avlValue); + DDX_Check(pDX, IDC_CHECK_OUT_NAME, m_outName); +} + +BEGIN_MESSAGE_MAP(CFileDirDlg, CDialog) + ON_WM_SYSCOMMAND() + ON_WM_PAINT() + ON_WM_QUERYDRAGICON() + //}}AFX_MSG_MAP + ON_WM_TIMER() + ON_EN_CHANGE(IDC_EDIT_PATH, OnEnChangeEditPath) + ON_BN_CLICKED(IDC_CHECK_NETSTED, OnBnClickedCheckNetsted) + ON_BN_CLICKED(IDC_BUTTON_SCAN, OnBnClickedButtonScan) + ON_BN_CLICKED(IDC_BUTTON_DELETE, OnBnClickedButtonDelete) + ON_BN_CLICKED(IDC_BUTTON_AVL_ADD, OnBnClickedButtonAvlAdd) + ON_BN_CLICKED(IDC_BUTTON_AVL_FIND, OnBnClickedButtonAvlFind) + ON_BN_CLICKED(IDC_BUTTON_WALK, OnBnClickedButtonWalk) + ON_EN_CHANGE(IDC_EDIT_AVL_NAME, OnEnChangeEditAvlName) + ON_BN_CLICKED(IDC_BUTTON_TEST, OnBnClickedButtonTest) + ON_EN_CHANGE(IDC_EDIT_AVL_VALUE, OnEnChangeEditAvlValue) + ON_BN_CLICKED(IDC_BUTTON_AVL_ADD_BAT, OnBnClickedButtonAvlAddBat) + ON_BN_CLICKED(IDC_BUTTON_AVL_DEL, OnBnClickedButtonAvlDel) + ON_BN_CLICKED(IDC_BUTTON_CLEAR, OnBnClickedButtonClear) + ON_BN_CLICKED(IDC_CHECK_OUT_NAME, OnBnClickedCheckOutName) + ON_BN_CLICKED(IDC_SVN_UPDATE, OnBnClickedSvnUpdate) +END_MESSAGE_MAP() + + +// CFileDirDlg 消息处理程序 + +BOOL CFileDirDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + // 将\“关于...\”菜单项添加到系统菜单中。 + + // IDM_ABOUTBOX 必须在系统命令范围内。 + ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); + ASSERT(IDM_ABOUTBOX < 0xF000); + + CMenu* pSysMenu = GetSystemMenu(FALSE); + if (pSysMenu != NULL) + { + CString strAboutMenu; + strAboutMenu.LoadString(IDS_ABOUTBOX); + if (!strAboutMenu.IsEmpty()) + { + pSysMenu->AppendMenu(MF_SEPARATOR); + pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); + } + } + + // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动 + // 执行此操作 + SetIcon(m_hIcon, TRUE); // 设置大图标 + SetIcon(m_hIcon, FALSE); // 设置小图标 + + // TODO: 在此添加额外的初始化代码 + + CheckDlgButton(IDC_CHECK_NETSTED, BST_CHECKED); + m_debugWin.SetLimitText(81920); + acl_msg_open("svn.log", "svn_update"); + + return TRUE; // 除非设置了控件的焦点,否则返回 TRUE +} + +void CFileDirDlg::OnSysCommand(UINT nID, LPARAM lParam) +{ + if ((nID & 0xFFF0) == IDM_ABOUTBOX) + { + CAboutDlg dlgAbout; + dlgAbout.DoModal(); + } + else + { + CDialog::OnSysCommand(nID, lParam); + } +} + +// 如果向对话框添加最小化按钮,则需要下面的代码 +// 来绘制该图标。对于使用文档/视图模型的 MFC 应用程序, +// 这将由框架自动完成。 + +void CFileDirDlg::OnPaint() +{ + if (IsIconic()) + { + CPaintDC dc(this); // 用于绘制的设备上下文 + + SendMessage(WM_ICONERASEBKGND, reinterpret_cast(dc.GetSafeHdc()), 0); + + // 使图标在工作矩形中居中 + int cxIcon = GetSystemMetrics(SM_CXICON); + int cyIcon = GetSystemMetrics(SM_CYICON); + CRect rect; + GetClientRect(&rect); + int x = (rect.Width() - cxIcon + 1) / 2; + int y = (rect.Height() - cyIcon + 1) / 2; + + // 绘制图标 + dc.DrawIcon(x, y, m_hIcon); + } + else + { + CDialog::OnPaint(); + } +} + +//当用户拖动最小化窗口时系统调用此函数取得光标显示。 +HCURSOR CFileDirDlg::OnQueryDragIcon() +{ + return static_cast(m_hIcon); +} + +int CFileDirDlg::GetDirPath(void) +{ + CString msg; + + if (m_dirPath.GetLength() == 0) { + MessageBox(_T("Please input the dir path ..."), _T("Error")); + return (-1); + } + + struct stat sbuf; + if (stat(m_dirPath.GetString(), &sbuf) < 0) { + msg.Format("%s no exist!", m_dirPath.GetString()); + MessageBox(msg, "Error"); + return (-1); + } else if (!S_ISDIR(sbuf.st_mode)) { + msg.Format("%s is not a directory!", m_dirPath.GetString()); + MessageBox(msg, "Error"); + return (-1); + } + + return 0; +} + +void CFileDirDlg::OnTimer(UINT nIDEvent) +{ + // TODO: 在此添加消息处理程序代码和/或调用默认值 + + CDialog::OnTimer(nIDEvent); + ScanDir(); +} + +void CFileDirDlg::OnEnChangeEditPath() +{ + // TODO: 如果该控件是 RICHEDIT 控件,则它将不会 + // 发送该通知,除非重写 CDialog::OnInitDialog() + // 函数并调用 CRichEditCtrl().SetEventMask(), + // 同时将 ENM_CHANGE 标志“或”运算到掩码中。 + + // TODO: 在此添加控件通知处理程序代码 + UpdateData(TRUE); +} + +int CFileDirDlg::ScanCallback(ACL_SCAN_DIR * scan, void * ctx) +{ + CFileDirDlg *pfdd = (CFileDirDlg *) ctx; + const char *ptr; + + if (pfdd->m_outName) { + ptr = acl_scan_dir_file(scan); + if (ptr && *ptr) { + CString msg; + struct acl_stat sbuf; + + acl_scan_stat(scan, &sbuf); + msg.Format(">>>file(%s), size=%I64d\r\n", ptr, + (acl_int64) sbuf.st_size); + pfdd->DebugWinAppend(msg); + } + } + + if ((acl_scan_dir_nfiles(pfdd->m_pScan) + + acl_scan_dir_ndirs(pfdd->m_pScan)) % 100 == 0) { + pfdd->UpdateInfo(); + pfdd->SetTimer(TIMER_EVENT_USER_100, 10, NULL); + return (-1); // 暂时停止扫描 + } + + return 0; +} + +void CFileDirDlg::ScanDir(void) +{ + if (acl_scan_dir_end(m_pScan)) { + ScanClose(); + return; + } + + if (acl_scan_dir_size2(m_pScan) < 0) { + ScanClose(); + return; + } + UpdateInfo(); +} + +// 更新显示信息 +void CFileDirDlg::UpdateInfo(void) +{ + if (m_pScan == NULL) + return; + + CString msg; + + msg.Format(_T("%I64u MB"), acl_scan_dir_nsize(m_pScan) / MB); + GetDlgItem(IDC_EDIT_SIZE)->SetWindowText(msg); + + msg.Format(_T("%d 个"), acl_scan_dir_nfiles(m_pScan)); + GetDlgItem(IDC_EDIT_NFILE)->SetWindowText(msg); + + msg.Format(_T("%d 个"), acl_scan_dir_ndirs(m_pScan)); + GetDlgItem(IDC_EDIT_NDIR)->SetWindowText(msg); +} + +void CFileDirDlg::ScanClose(void) +{ + KillTimer(TIMER_EVENT_USER_100); + UpdateInfo(); + acl_scan_dir_close(m_pScan); // 关闭扫描目录对象 + m_pScan = NULL; +} + +void CFileDirDlg::OnBnClickedCheckNetsted() +{ + // TODO: 在此添加控件通知处理程序代码 + UpdateData(TRUE); +} + +void CFileDirDlg::OnBnClickedButtonScan() +{ + // TODO: 在此添加控件通知处理程序代码 + CString msg; + + if (GetDirPath() < 0) + return; + + m_pScan = acl_scan_dir_open(m_dirPath.GetString(), m_nested); + if (m_pScan == NULL) { + msg.Format("open dir %s error", m_dirPath.GetString()); + MessageBox(msg, "Error"); + return; + } + + // 设置回调函数及回调参数 + acl_scan_dir_ctl(m_pScan, ACL_SCAN_CTL_FN, this->ScanCallback, + ACL_SCAN_CTL_CTX, this, ACL_SCAN_CTL_END); + + ScanDir(); +} + +void CFileDirDlg::OnBnClickedButtonDelete() +{ + // TODO: 在此添加控件通知处理程序代码 + CString msg; + + if (GetDirPath() < 0) + return; + + msg.Format("Are you sure to delete %s ?", m_dirPath.GetString()); + if (MessageBox(msg, "Warning", MB_YESNO) != IDYES) + return; + + CScanDir scan(m_dirPath.GetString(), m_nested); + + if (scan.BeginRemove() < 0) { + msg.Format("%s remove error", m_dirPath.GetString()); + MessageBox(msg, "Error"); + return; + } + + __int64 size = scan.TotalSize(); + + msg.Format(_T("%I64u MB"), size / MB); + GetDlgItem(IDC_EDIT_SIZE)->SetWindowText(msg); + + int n = scan.FileCount(); + msg.Format(_T("%d 个"), n); + GetDlgItem(IDC_EDIT_NFILE)->SetWindowText(msg); + + n = scan.DirCount(); + msg.Format(_T("%d 个"), n); + GetDlgItem(IDC_EDIT_NDIR)->SetWindowText(msg); +} + +void CFileDirDlg::OnBnClickedButtonAvlAdd() +{ + // TODO: 在此添加控件通知处理程序代码 + MY_TYPE *pm, m; + + if (m_avlName.GetLength() == 0) { + MessageBox("Please input searching name!", "error"); + GetDlgItem(IDC_EDIT_AVL_NAME)->SetFocus(); + return; + } + if (m_avlValue.GetLength() == 0) { + MessageBox("Please input value!", "error"); + GetDlgItem(IDC_EDIT_AVL_VALUE)->SetFocus(); + return; + } + + snprintf(m.name, sizeof(m.name), "%s", m_avlName.GetString()); + pm = (MY_TYPE*) avl_find(&m_avlTree, &m, NULL); + if (pm != NULL) { + CString msg; + + msg.Format("key(%s) already exist, which value is %s", + m_avlName.GetString(), pm->value); + MessageBox(msg, "error"); + return; + } + + pm = (MY_TYPE*) acl_mycalloc(1, sizeof(MY_TYPE)); + snprintf(pm->name, sizeof(pm->name), "%s", m_avlName.GetString()); + snprintf(pm->value, sizeof(pm->value), "%s", m_avlValue.GetString()); + avl_add(&m_avlTree, pm); + MessageBox("Add ok!", "ok"); + // m_avlName.Empty(); + m_avlValue.Empty(); + UpdateData(FALSE); +} + +void CFileDirDlg::OnBnClickedButtonAvlFind() +{ + // TODO: 在此添加控件通知处理程序代码 + MY_TYPE m, *ptr; + CString msg; + + if (m_avlName.GetLength() == 0) { + MessageBox("Please input searching name", "error"); + GetDlgItem(IDC_EDIT_AVL_NAME)->SetFocus(); + return; + } + + snprintf(m.name, sizeof(m.name), m_avlName.GetString()); + + ptr = (MY_TYPE*) avl_find(&m_avlTree, &m, NULL); + if (ptr) { + m_avlValue.Format("%s", ptr->value); + } else { + m_avlValue.Empty(); + msg.Format("not find it, name=%s", m.name); + MessageBox(msg); + } + + UpdateData(FALSE); +} + +int CFileDirDlg::compare_fn(const void* v1, const void* v2) +{ + MY_TYPE *m1 = (MY_TYPE*) v1, *m2 = (MY_TYPE*) v2; + + return (strcmp(m1->name, m2->name)); +} + +void CFileDirDlg::OnBnClickedButtonWalk() +{ + // TODO: 在此添加控件通知处理程序代码 + MY_TYPE *next; + CString msg; + int n = 0; + + next = (MY_TYPE*) avl_first(&m_avlTree); + while (next) { + msg.Format(">>name(%s), value(%s)\r\n", next->name, next->value); + DebugWinAppend(msg); + next = (MY_TYPE*) AVL_NEXT(&m_avlTree, next); + n++; + } + + msg.Format(">>ok, total count is %d\r\n", n); + DebugWinAppend(msg); +} + +void CFileDirDlg::OnEnChangeEditAvlName() +{ + // TODO: 如果该控件是 RICHEDIT 控件,则它将不会 + // 发送该通知,除非重写 CDialog::OnInitDialog() + // 函数并调用 CRichEditCtrl().SetEventMask(), + // 同时将 ENM_CHANGE 标志“或”运算到掩码中。 + + // TODO: 在此添加控件通知处理程序代码 + UpdateData(TRUE); +} + +void CFileDirDlg::OnBnClickedButtonTest() +{ + // TODO: 在此添加控件通知处理程序代码 + avl_node_t *node = (avl_node_t*) acl_mycalloc(1, sizeof(avl_node_t)), *pnode; + avl_index_t where; + + where = AVL_MKINDEX(node, 1); + pnode = AVL_INDEX2NODE(where); + + CString msg; + + msg.Format("addr=%x, %x, %d", pnode, node, pnode); + if (pnode == node) { + MessageBox("ok, =="); + MessageBox(msg); + } else { + MessageBox("no"); + } +} + +void CFileDirDlg::OnEnChangeEditAvlValue() +{ + // TODO: 如果该控件是 RICHEDIT 控件,则它将不会 + // 发送该通知,除非重写 CDialog::OnInitDialog() + // 函数并调用 CRichEditCtrl().SetEventMask(), + // 同时将 ENM_CHANGE 标志“或”运算到掩码中。 + + // TODO: 在此添加控件通知处理程序代码 + UpdateData(TRUE); +} + +void CFileDirDlg::OnBnClickedButtonAvlAddBat() +{ + // TODO: 在此添加控件通知处理程序代码 + MY_TYPE *pm, m; + int i, n = 0; + CString msg; + + for (i = 0; i < 100; i++) { + snprintf(m.name, sizeof(m.name), "%d", i); + pm = (MY_TYPE*) avl_find(&m_avlTree, &m, NULL); + if (pm != NULL) { + msg.Format(">>key(%s) already exist, value(%s)\r\n", + pm->name, pm->value); + DebugWinAppend(msg); + continue; + } + + pm = (MY_TYPE*) acl_mycalloc(1, sizeof(MY_TYPE)); + snprintf(pm->name, sizeof(pm->name), "%d", i); + snprintf(pm->value, sizeof(pm->value), "value(%d)", i); + avl_add(&m_avlTree, pm); + msg.Format(">>add one, key(%s), value(%s)\r\n", pm->name, pm->value); + DebugWinAppend(msg); + n++; + } + + msg.Format(">>ok, %d records were added\r\n", n); + DebugWinAppend(msg); +} + +void CFileDirDlg::OnBnClickedButtonAvlDel() +{ + // TODO: 在此添加控件通知处理程序代码 + MY_TYPE m, *pm; + + if (m_avlName.GetLength() == 0) { + MessageBox("Please input searching name!", "error"); + GetDlgItem(IDC_EDIT_AVL_NAME)->SetFocus(); + return; + } + + snprintf(m.name, sizeof(m.name), "%s", m_avlName.GetString()); + pm = (MY_TYPE*) avl_find(&m_avlTree, &m, NULL); + if (!pm) { + MessageBox("not find", "ok"); + } else { + avl_remove(&m_avlTree, pm); + MessageBox("Delete ok!", "ok"); + } + m_avlName.Empty(); + m_avlValue.Empty(); + UpdateData(FALSE); +} + +void CFileDirDlg::OnBnClickedButtonClear() +{ + // TODO: 在此添加控件通知处理程序代码 + m_avlName.Empty(); + m_avlValue.Empty(); + UpdateData(FALSE); + m_debugWin.SetSel(0, m_debugWin.GetWindowTextLength()); + m_debugWin.ReplaceSel(""); +} + +void CFileDirDlg::DebugWinAppend(CString& msg) +{ + m_debugWin.SetSel(m_debugWin.GetWindowTextLength(), + m_debugWin.GetWindowTextLength()); + m_debugWin.ReplaceSel(msg.GetString()); +} + +void CFileDirDlg::OnBnClickedCheckOutName() +{ + // TODO: 在此添加控件通知处理程序代码 + UpdateData(TRUE); +} + +void CFileDirDlg::OnBnClickedSvnUpdate() +{ + // TODO: 在此添加控件通知处理程序代码 + CString msg; + + if (GetDirPath() < 0) + return; + + m_pScan = acl_scan_dir_open(m_dirPath.GetString(), m_nested); + if (m_pScan == NULL) { + msg.Format("open dir %s error", m_dirPath.GetString()); + MessageBox(msg, "Error"); + return; + } + + // 设置回调函数及回调参数 + acl_scan_dir_ctl(m_pScan, ACL_SCAN_CTL_FN, ScanSvnCallback, + ACL_SCAN_CTL_CTX, this, ACL_SCAN_CTL_END); + + ScanSvnDir(); +} + +int CFileDirDlg::ScanSvnCallback(ACL_SCAN_DIR * scan, void * ctx) +{ + CFileDirDlg *pfdd = (CFileDirDlg *) ctx; + + if ((acl_scan_dir_nfiles(pfdd->m_pScan) + + acl_scan_dir_ndirs(pfdd->m_pScan)) % 100 == 0) + { + pfdd->UpdateInfo(); + pfdd->SetTimer(TIMER_EVENT_USER_100, 10, NULL); + return (-1); // 暂时停止扫描 + } + + if (!pfdd->m_outName) + return 0; + + const char* filename = acl_scan_dir_file(scan); + const char* path = acl_scan_dir_path(scan); + if (!filename || strcasecmp(filename, "entries") || !path) + return 0; + + CString filepath; + filepath.Format("%s/%s", path, filename); + + if (acl_strrncasecmp(filepath.GetString(), + ".svn/entries", sizeof(".svn/entries") - 1) != 0) + { + return 0; + } + + CString msg; + struct acl_stat sbuf; + + acl_assert(path); + acl_scan_stat(scan, &sbuf); + msg.Format(">>>file(%s/%s), size=%I64d\r\n", + path, filename, (acl_int64) sbuf.st_size); + pfdd->DebugWinAppend(msg); + return 0; +} + +void CFileDirDlg::ScanSvnDir(void) +{ + if (acl_scan_dir_end(m_pScan)) { + ScanClose(); + return; + } + + if (acl_scan_dir_size2(m_pScan) < 0) { + ScanClose(); + return; + } + UpdateInfo(); +} + +BOOL CFileDirDlg::UpdateSvn(const char* filepath) +{ + ssize_t file_size; + char* buf = acl_vstream_loadfile2(filepath, &file_size); + if (buf == NULL) + { + acl_msg_error("loadfile(%s) error(%s)", + filepath, acl_last_serror()); + return FALSE; + } + + ACL_VSTREAM* fp = acl_vstream_fopen(filepath, + O_WRONLY | O_BINARY | O_TRUNC, 0700, 4096); + if (fp == NULL) + { + acl_myfree(buf); + acl_msg_error("fopen(%s) error(%s)", + filepath, acl_last_serror()); + return FALSE; + } + + ACL_VSTRING* vbuf = acl_vstring_alloc(2048); + const char* ptr = buf; + const char* old_svn = "svn://192.168.1.231"; + size_t old_npre = strlen(old_svn); + const char* new_svn = "svn://122.49.0.188"; + size_t new_npre = strlen(new_svn); + +#define STR acl_vstring_str +#define LEN ACL_VSTRING_LEN + + int i = 0; + while (TRUE) + { + // 只需要修改前 10 数据即可 + if (i++ > 10) + break; + + // 从缓冲区中获得一行数据 + const ACL_VSTRING* vp = acl_buffer_gets(vbuf, &ptr, strlen(ptr)); + if (vp == NULL) + break; + + // 比较前缀是否相等 + if (strncasecmp(old_svn, STR(vp), old_npre) != 0) + { + if (acl_vstream_writen(fp, STR(vp), LEN(vp)) == ACL_VSTREAM_EOF) + { + acl_msg_error("%s(%d): write error(%s)", + __FUNCTION__, __LINE__, + acl_last_serror()); + goto end; + } + ACL_VSTRING_RESET(vbuf); + continue; + } + + // 写入新的前缀 + if (acl_vstream_writen(fp, new_svn, new_npre) == ACL_VSTREAM_EOF) + { + acl_msg_error("%s(%d): write error(%s)", + __FUNCTION__, __LINE__, acl_last_serror()); + goto end; + } + + const char* pleft = STR(vp) + old_npre; + if (*pleft == 0) + { + ACL_VSTRING_RESET(vbuf); + continue; + } + + // 写入该行数据中剩余部分 + if (acl_vstream_writen(fp, pleft, strlen(pleft)) == ACL_VSTREAM_EOF) + { + acl_msg_error("%s(%d): write error(%s)", + __FUNCTION__, __LINE__, acl_last_serror()); + goto end; + } + ACL_VSTRING_RESET(vbuf); + } + + ssize_t nleft = (ssize_t) (file_size - (ptr - buf)); + if (*ptr && nleft > 0) + { + if (acl_vstream_writen(fp, ptr, nleft) == ACL_VSTREAM_EOF) + acl_msg_error("%s(%d): write nleft(%d) error(%s)", + __FUNCTION__, __LINE__, + (int) nleft, acl_last_serror()); + } + +end: + acl_vstring_free(vbuf); + acl_vstream_fclose(fp); + acl_myfree(buf); + return TRUE; +} \ No newline at end of file diff --git a/samples/FileDir/FileDirDlg.h b/samples/FileDir/FileDirDlg.h new file mode 100644 index 000000000..9e9c5e66c --- /dev/null +++ b/samples/FileDir/FileDirDlg.h @@ -0,0 +1,86 @@ +// FileDirDlg.h : 头文件 +// + +#pragma once + +#include "lib_acl.h" +#include "afxcmn.h" +#include "afxwin.h" + +// CFileDirDlg 对话框 +class CFileDirDlg : public CDialog +{ +// 构造 +public: + CFileDirDlg(CWnd* pParent = NULL); // 标准构造函数 + +// 对话框数据 + enum { IDD = IDD_FILEDIR_DIALOG }; + + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 + + +// 实现 +protected: + HICON m_hIcon; + + // 生成的消息映射函数 + virtual BOOL OnInitDialog(); + afx_msg void OnSysCommand(UINT nID, LPARAM lParam); + afx_msg void OnPaint(); + afx_msg HCURSOR OnQueryDragIcon(); + DECLARE_MESSAGE_MAP() +private: + CString m_dirPath; + BOOL m_nested; +private: + int GetDirPath(void); +public: + afx_msg void OnTimer(UINT nIDEvent); + afx_msg void OnEnChangeEditPath(); +private: + ACL_SCAN_DIR *m_pScan; + static int ScanCallback(ACL_SCAN_DIR * scan, void * ctx); + static int ScanSvnCallback(ACL_SCAN_DIR * scan, void * ctx); + void ScanDir(void); + void ScanSvnDir(void); + // 更新显示信息 + void UpdateInfo(void); + BOOL UpdateSvn(const char* filepath); + void ScanClose(void); +public: + afx_msg void OnBnClickedCheckNetsted(); + afx_msg void OnBnClickedButtonScan(); + afx_msg void OnBnClickedButtonDelete(); + afx_msg void OnBnClickedButtonAvlAdd(); + afx_msg void OnBnClickedButtonAvlFind(); +private: + avl_tree_t m_avlTree; +public: + static int compare_fn(const void* v1, const void* v2); + afx_msg void OnBnClickedButtonWalk(); +public: + afx_msg void OnEnChangeEditAvlName(); +public: + afx_msg void OnEnChangeRichedit2AvlResult(); + afx_msg void OnBnClickedButtonTest(); +private: + CEdit m_debugWin; +public: + afx_msg void OnEnChangeEditAvlValue(); +private: + CString m_avlValue; + CString m_avlName; +public: + afx_msg void OnBnClickedButtonAvlAddBat(); + afx_msg void OnBnClickedButtonAvlDel(); + afx_msg void OnBnClickedButtonClear(); +private: + void DebugWinAppend(CString& msg); +public: + // 是否将扫描目录的文件名输出 + BOOL m_outName; + afx_msg void OnBnClickedCheckOutName(); + afx_msg void OnBnClickedSvnUpdate(); +}; diff --git a/samples/FileDir/FileDir_vc2003.vcproj b/samples/FileDir/FileDir_vc2003.vcproj new file mode 100644 index 000000000..0f0b65d66 --- /dev/null +++ b/samples/FileDir/FileDir_vc2003.vcproj @@ -0,0 +1,328 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/FileDir/FileDir_vc2008.vcproj b/samples/FileDir/FileDir_vc2008.vcproj new file mode 100644 index 000000000..cacfec301 --- /dev/null +++ b/samples/FileDir/FileDir_vc2008.vcproj @@ -0,0 +1,289 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/FileDir/ReadMe.txt b/samples/FileDir/ReadMe.txt new file mode 100644 index 000000000..a562f6768 --- /dev/null +++ b/samples/FileDir/ReadMe.txt @@ -0,0 +1,85 @@ +================================================================================ + MICROSOFT 基础类库: FileDir 项目概述 +=============================================================================== + +应用程序向导已为您创建了此 FileDir 应用程序。此应用程序 +不仅介绍了使用 Microsoft 基础类的基本知识, +而且是编写应用程序的起点。 + +此文件包含组成 FileDir 应用程序的每个文件的内容摘要。 + +FileDir.vcproj + 这是使用“应用程序向导”生成的 VC++ 项目的主项目文件。 + 它包含有关生成文件的 Visual C++ 版本的信息,以及 + 有关用“应用程序向导”所选择的平台、配置和 + 项目功能的信息。 + +FileDir.h + 这是应用程序的主头文件。 它包含其他 + 项目特定的头文件(包括 Resource.h),并声明 + CFileDirApp 应用程序类。 + +FileDir.cpp + 这是包含应用程序 + 类 CFileDirApp 的主应用程序源文件。 + +FileDir.rc + 这是程序使用的所有 Microsoft Windows 资源 + 的列表。 它包含存储在 RES 子目录中 + 的图标、位图和光标。 可直接在 Microsoft + Visual C++ 中编辑此文件。 项目资源包含在 2052 中。 + +res\FileDir.ico + 这是一个图标文件,用作应用程序的图标。 此 + 图标包含在主资源文件 FileDir.rc 中。 + +res\FileDir.rc2 + 此文件包含不由 Microsoft + Visual C++ 编辑的资源。 应将所有不能由 + 资源编辑器编辑的资源放在此文件中。 + +///////////////////////////////////////////////////////////////////////////// + +应用程序向导将创建一个对话框类: +FileDirDlg.h、FileDirDlg.cpp - 对话框 + 这些文件包含 CFileDirDlg 类。 此类定义 + 应用程序主对话框的行为。 此对话框的模板包含在 + FileDir.rc 中,而此文件可以在 Microsoft Visual C++ 中进行编辑。 +///////////////////////////////////////////////////////////////////////////// + +其他功能: + +ActiveX 控件 + 应用程序支持使用 ActiveX 控件。 + +Windows 套接字 + 应用程序支持在 TCP/IP 网络上建立通讯。 +///////////////////////////////////////////////////////////////////////////// + +其他标准文件: + +StdAfx.h、StdAfx.cpp + 这些文件用于生成名为 FileDir.pch 的预编译头文件 (PCH) + 和名为 StdAfx.obj 的预编译类型文件。 + +Resource.h + 这是标准头文件,它定义新资源 ID。 + Microsoft Visual C++ 将读取并更新此文件。 + +///////////////////////////////////////////////////////////////////////////// + +其他说明: + +应用程序向导使用“TODO:” 来指示 +应添加或自定义的源代码部分。 + +如果应用程序在共享 DLL 中使用 MFC,且应用程序使用的语言不是 +操作系统的当前语言,则需要从 Microsoft Visual C++ 光盘上 +Win\System 目录下将相应的本地化资源 MFC70XXX.DLL +复制到计算机的 system 或 system32 目录下, +并将其重命名为 MFCLOC.DLL。 (“XXX”代表 +语言缩写。 例如,MFC70DEU.DLL 包含翻译成 +德语的资源。) 如果不这样做,应用程序的某些 UI 元素 +将保留为操作系统的语言。 + +///////////////////////////////////////////////////////////////////////////// diff --git a/samples/FileDir/ScanDir.cpp b/samples/FileDir/ScanDir.cpp new file mode 100644 index 000000000..e11cdc27d --- /dev/null +++ b/samples/FileDir/ScanDir.cpp @@ -0,0 +1,60 @@ +//#include "StdAfx.h" + +#include "lib_acl.h" +#include ".\scandir.h" + +CScanDir::CScanDir(const char* path, BOOL nested) +: m_pDirPath(NULL) +, m_nested(nested) +, m_nDir(0) +, m_nFile(0) +, m_nSize(0) +{ + m_pDirPath = (char*) acl_mystrdup(path); +} + +CScanDir::~CScanDir(void) +{ + acl_myfree(m_pDirPath); +} + +int CScanDir::BeginScan(void) +{ + m_nSize = acl_scan_dir_size(m_pDirPath, m_nested, &m_nFile, &m_nDir); + if (m_nSize < 0) + return (-1); + return (0); +} + +__int64 CScanDir::TotalSize(void) +{ + return (m_nSize); +} + +int CScanDir::FileCount(void) +{ + return m_nFile; +} + +int CScanDir::DirCount(void) +{ + return m_nDir; +} + +int CScanDir::BeginRemove(void) +{ + ACL_SCAN_DIR *scan; + + scan = acl_scan_dir_open(m_pDirPath, m_nested); + if (scan == NULL) + return (-1); + + acl_scan_dir_rm2(scan); + + m_nSize = acl_scan_dir_nsize(scan); + m_nDir = acl_scan_dir_ndirs(scan); + m_nFile = acl_scan_dir_nfiles(scan); + + acl_scan_dir_close(scan); + return 0; +} diff --git a/samples/FileDir/ScanDir.h b/samples/FileDir/ScanDir.h new file mode 100644 index 000000000..fe8b6ac60 --- /dev/null +++ b/samples/FileDir/ScanDir.h @@ -0,0 +1,30 @@ +#pragma once + +#ifndef KB +#define KB (1024) +#endif + +#ifndef MB +#define MB (KB * 1024) +#endif + +class CScanDir +{ +public: + CScanDir(const char* path, BOOL nested); + ~CScanDir(void); +protected: + char* m_pDirPath; + BOOL m_nested; +public: + int BeginScan(void); +private: + // 扫描的文件总数 + int m_nFile, m_nDir; + __int64 m_nSize; +public: + int FileCount(void); + int DirCount(void); + __int64 TotalSize(void); + int BeginRemove(void); +}; diff --git a/samples/FileDir/res/FileDir.ico b/samples/FileDir/res/FileDir.ico new file mode 100644 index 000000000..8a84ca3d3 Binary files /dev/null and b/samples/FileDir/res/FileDir.ico differ diff --git a/samples/FileDir/res/FileDir.manifest b/samples/FileDir/res/FileDir.manifest new file mode 100644 index 000000000..9665e0124 --- /dev/null +++ b/samples/FileDir/res/FileDir.manifest @@ -0,0 +1,22 @@ + + + +鍦ㄦ璇存槑搴旂敤绋嬪簭 + + + + + + diff --git a/samples/FileDir/res/FileDir.rc2 b/samples/FileDir/res/FileDir.rc2 new file mode 100644 index 000000000..1f020e45e --- /dev/null +++ b/samples/FileDir/res/FileDir.rc2 @@ -0,0 +1,13 @@ +// +// FileDir.RC2 - Microsoft Visual C++ 不会直接编辑的资源 +// + +#ifdef APSTUDIO_INVOKED +#error 此文件不能由 Microsoft Visual C++ 编辑 +#endif //APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// 在此处添加手动编辑的资源... + +///////////////////////////////////////////////////////////////////////////// diff --git a/samples/FileDir/resource.h b/samples/FileDir/resource.h new file mode 100644 index 000000000..d01cfb9ef --- /dev/null +++ b/samples/FileDir/resource.h @@ -0,0 +1,41 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by FileDir.rc +// +#define IDM_ABOUTBOX 0x0010 +#define IDD_ABOUTBOX 100 +#define IDS_ABOUTBOX 101 +#define IDD_FILEDIR_DIALOG 102 +#define IDP_SOCKETS_INIT_FAILED 103 +#define IDR_MAINFRAME 128 +#define IDC_EDIT_PATH 1002 +#define IDC_EDIT_SIZE 1004 +#define IDC_CHECK_NETSTED 1005 +#define IDC_EDIT_NFILE 1006 +#define IDC_EDIT_NDIR 1007 +#define IDC_BUTTON_SCAN 1012 +#define IDC_BUTTON_DELETE 1013 +#define IDC_BUTTON_TEST 1014 +#define IDC_BUTTON_AVL_ADD 1015 +#define IDC_BUTTON_AVL_FIND 1016 +#define IDC_EDIT_AVL_NAME 1018 +#define IDC_BUTTON_WALK 1019 +#define IDC_EDIT_AV_RESULT 1020 +#define IDC_EDIT_AVL_VALUE 1021 +#define IDC_BUTTON_AVL_ADD_BAT 1022 +#define IDC_BUTTON_AVL_DEL 1023 +#define IDC_BUTTON_CLEAR 1024 +#define IDC_CHECK_OUT_NAME 1025 +#define IDC_BUTTON1 1026 +#define IDC_SVN_UPDATE 1026 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 130 +#define _APS_NEXT_COMMAND_VALUE 32771 +#define _APS_NEXT_CONTROL_VALUE 1027 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/samples/FileDir/stdafx.cpp b/samples/FileDir/stdafx.cpp new file mode 100644 index 000000000..400394586 --- /dev/null +++ b/samples/FileDir/stdafx.cpp @@ -0,0 +1,7 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// FileDir.pch 将是预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + + diff --git a/samples/FileDir/stdafx.h b/samples/FileDir/stdafx.h new file mode 100644 index 000000000..c03e01af6 --- /dev/null +++ b/samples/FileDir/stdafx.h @@ -0,0 +1,46 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是经常使用但不常更改的 +// 项目特定的包含文件 + +#pragma once + +#ifndef VC_EXTRALEAN +#define VC_EXTRALEAN // 从 Windows 标头中排除不常使用的资料 +#endif + +// 如果您必须使用下列所指定的平台之前的平台,则修改下面的定义。 +// 有关不同平台的相应值的最新信息,请参考 MSDN。 +#ifndef WINVER // 允许使用 Windows 95 和 Windows NT 4 或更高版本的特定功能。 +#define WINVER 0x0400 //为 Windows98 和 Windows 2000 及更新版本改变为适当的值。 +#endif + +#ifndef _WIN32_WINNT // 允许使用 Windows NT 4 或更高版本的特定功能。 +#define _WIN32_WINNT 0x0500 //为 Windows98 和 Windows 2000 及更新版本改变为适当的值。 +#endif + +#ifndef _WIN32_WINDOWS // 允许使用 Windows 98 或更高版本的特定功能。 +#define _WIN32_WINDOWS 0x0410 //为 Windows Me 及更新版本改变为适当的值。 +#endif + +#ifndef _WIN32_IE // 允许使用 IE 4.0 或更高版本的特定功能。 +#define _WIN32_IE 0x0400 //为 IE 5.0 及更新版本改变为适当的值。 +#endif + +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // 某些 CString 构造函数将是显式的 + +// 关闭 MFC 对某些常见但经常被安全忽略的警告消息的隐藏 +#define _AFX_ALL_WARNINGS + +#include // MFC 核心和标准组件 +#include // MFC 扩展 +#include // MFC 自动化类 + +#include // Internet Explorer 4 公共控件的 MFC 支持 +#ifndef _AFX_NO_AFXCMN_SUPPORT +#include // Windows 公共控件的 MFC 支持 +#endif // _AFX_NO_AFXCMN_SUPPORT + +//自定义定时器值 +#define TIMER_EVENT_USER_100 100 + +#include // MFC 套接字扩展 diff --git a/samples/Makefile b/samples/Makefile new file mode 100644 index 000000000..d7b22a5f0 --- /dev/null +++ b/samples/Makefile @@ -0,0 +1,144 @@ +.PHONY = all clean + +all: + @(cd master; make) + @(cd dlink; make) + @(cd iplink; make) + @(cd event; make) + @(cd fifo; make) + @(cd mempool; make) +# @(cd thread; make) + @(cd debug_malloc; make) + @(cd mempool; make) +# @(cd thread_pool; make) + @(cd vstream; make) + @(cd vstream_unread; make) + @(cd vstream_fseek; make) + @(cd vstring; make) + @(cd watchdog; make) + @(cd ping; make) + @(cd flock; make) + @(cd net; make) + @(cd configure; make) + @(cd file; make) + @(cd file_fmt; make) + @(cd base64; make) + @(cd aio; make) + @(cd dns; make) + @(cd dns_req; make) + @(cd msg; make) # error + @(cd process; make) + @(cd cache; make) + @(cd cache2; make) + @(cd slice; make) + @(cd memdb; make) + @(cd iterator; make) + @(cd zdb; make) +# @(cd token_tree; make) +# @(cd vstream_popen; make) +# @(cd vstream_popen2; make) + @(cd vstream_fseek2; make) + @(cd http_gate; make) + @(cd msgio; make) # error + @(cd slice_mem; make) + @(cd http; make) + @(cd httpd; make) + @(cd htable; make) + @(cd server; make) +# @(cd xml; make) + @(cd log; make) +# @(cd mysql; make) +# @(cd mysql2; make) +# @(cd mysql3; make) + @(cd unix; make) + @(cd connect; make) + @(cd code; make) + @(cd resolve; make) +# @(cd dict; make) + @(cd vstring2; make) +# @(cd trace; make) + @(cd smtp; make) + @(cd json; make) +# @(cd html_code; make) + @(cd btree; make) + @(cd ifconf; make) +# @(cd jt2ft; make) + @(cd acl; make) +# @(cd dbpool; make) +# @(cd http_probe; make) + @(cd thread_pool_client; make) + @(cd smtp_client; make) + @(cd vstream_popen3; make) + @(cd mkdir; make) +clean: + @(cd master; make clean) + @(cd dlink; make clean) + @(cd iplink; make clean) + @(cd event; make clean) + @(cd fifo; make clean) + @(cd mempool; make clean) + @(cd thread; make clean) + @(cd debug_malloc; make clean) + @(cd mempool; make clean) +# @(cd thread_pool; make clean) + @(cd vstream; make clean) + @(cd vstream_unread; make clean) + @(cd vstream_fseek; make clean) + @(cd vstring; make clean) + @(cd watchdog; make clean) + @(cd ping; make clean) + @(cd flock; make clean) + @(cd net; make clean) + @(cd configure; make clean) + @(cd file; make clean) + @(cd file_fmt; make clean) + @(cd base64; make clean) + @(cd aio; make clean) + @(cd dns; make clean) + @(cd dns_req; make clean) + @(cd msg; make clean) + @(cd process; make clean) + @(cd cache; make clean) + @(cd cache2; make clean) + @(cd slice; make clean) + @(cd memdb; make clean) + @(cd iterator; make clean) + @(cd zdb; make clean) + @(cd token_tree; make clean) + @(cd vstream_popen; make clean) + @(cd vstream_popen2; make clean) + @(cd vstream_fseek2; make clean) + @(cd http_gate; make clean) + @(cd msgio; make clean) + @(cd slice_mem; make clean) + @(cd http; make clean) + @(cd httpd; make clean) + @(cd htable; make clean) + @(cd server; make clean) + @(cd xml; make clean) + @(cd log; make clean) + @(cd mysql; make clean) + @(cd mysql2; make clean) + @(cd mysql3; make clean) + @(cd unix; make clean) + @(cd connect; make clean) + @(cd code; make clean) + @(cd resolve; make clean) + @(cd master; make clean) +# @(cd dict; make clean) + @(cd vstring2; make clean) + @(cd trace; make clean) + @(cd smtp; make clean) + @(cd json; make clean) + @(cd html_code; make clean) + @(cd btree; make clean) + @(cd ifconf; make clean) + @(cd jt2ft; make clean) + @(cd acl; make clean) +# @(cd dbpool; make clean) + @(cd http_probe; make clean) + @(cd thread_pool_client; make clean) + @(cd gc; make clean) + @(cd smtp_client; make clean) + @(cd vstream_popen3; make clean) + @(cd mkdir; make clean) diff --git a/samples/Makefile.in b/samples/Makefile.in new file mode 100644 index 000000000..4f1e2caa2 --- /dev/null +++ b/samples/Makefile.in @@ -0,0 +1,112 @@ +CC = gcc + +CFLAGS = -c -g -W -Wall -Wcast-qual -Wcast-align \ +-Waggregate-return -Wno-long-long -Wmissing-prototypes \ +-Wpointer-arith -Werror -Wshadow -O2 \ +-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO + +#CFLAGS = -c -g -W -Wall -Wcast-qual -Wcast-align \ +#-Waggregate-return -Wmissing-prototypes \ +#-Wpointer-arith -Werror -Wshadow -O2 \ +#-D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO +########################################################### +#Check system: +# Linux, SunOS, Solaris, BSD variants, AIX, HP-UX +SYSLIB = -lpthread +CHECKSYSRES = @echo "Unknow system type!";exit 1 +UNIXNAME = $(shell uname -sm) + +ifeq ($(CC),) + CC = gcc +endif + +ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes +endif + +# For FreeBSD +ifeq ($(findstring FreeBSD, $(UNIXNAME)), FreeBSD) + CFLAGS += -DFREEBSD -D_REENTRANT + SYSLIB += -lcrypt +endif + +#Path for Linux +ifeq ($(findstring Linux, $(UNIXNAME)), Linux) + CFLAGS += -DLINUX2 -D_REENTRANT + SYSLIB += -lcrypt +endif + +# For Darwin +ifeq ($(findstring Darwin, $(UNIXNAME)), Darwin) + CFLAGS += -DMACOSX +endif + +#Path for SunOS +ifeq ($(findstring SunOS, $(UNIXNAME)), SunOS) + ifeq ($(findstring 86, $(UNIXNAME)), 86) + SYSLIB += -lsocket -lnsl -lrt + endif + ifeq ($(findstring sun4u, $(UNIXNAME)), sun4u) + SYSLIB += -lsocket -lnsl -lrt + endif + CFLAGS += -DSUNOS5 -D_REENTRANT + SYSLIB += -lcrypt +endif + +#Path for HP-UX +ifeq ($(findstring HP-UX, $(UNIXNAME)), HP-UX) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DHP_UX -DHPUX11 + PLAT_NAME=hp-ux + SYSLIB += -lcrypt +endif + +#Find system type. +ifneq ($(SYSPATH),) + CHECKSYSRES = @echo "System is $(shell uname -sm)" +endif +########################################################### + +ACL_PATH = ../../lib_acl +ACL_INC = $(ACL_PATH)/include +ACL_LIB = $(ACL_PATH)/lib + +PROTO_PATH = ../../lib_protocol +PROTO_INC = $(PROTO_PATH)/include +PROTO_LIB = $(PROTO_PATH)/lib + +EXTLIBS = +CFLAGS += -I$(ACL_INC) -I$(PROTO_INC) +LDFLAGS = -L$(ACL_LIB) -L$(PROTO_LIB) -l_protocol -l_acl $(EXTLIBS) $(SYSLIB) + +########################################################### + +OUT_PATH = . +OBJ_PATH = $(OUT_PATH) + +#Project's objs +SRC = $(wildcard *.c) +OBJ = $(patsubst %.c, $(OBJ_PATH)/%.o, $(notdir $(SRC))) +########################################################### + +.PHONY = all clean +PROG = + +COMPILE = $(CC) $(CFLAGS) + +all: RM $(OBJ) + $(CC) $(OBJ) $(LDFLAGS) \ + -Wl,-rpath,$(ACL_LIB) -Wl,-rpath,$(PROTO_LIB) -o $(OBJ_PATH)/$(PROG) + @echo "" + @echo "All ok! Output:$(PROG)" + @echo "" +$(OBJ_PATH)/%.o: %.c + $(COMPILE) $< -o $@ +RM: + rm -f $(PROG) +clean: + rm -f $(PROG) + rm -f $(OBJ) +########################################################### diff --git a/samples/Makefile_cpp.in b/samples/Makefile_cpp.in new file mode 100644 index 000000000..eed1192b7 --- /dev/null +++ b/samples/Makefile_cpp.in @@ -0,0 +1,105 @@ +CC = g++ + +CFLAGS = -c -g -W -Wall -Wcast-qual -Wcast-align \ +-Waggregate-return -Wno-long-long \ +-Wpointer-arith -Werror -Wshadow -O2 \ +-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO + +########################################################### +#Check system: +# Linux, SunOS, Solaris, BSD variants, AIX, HP-UX +SYSLIB = -lpthread +CHECKSYSRES = @echo "Unknow system type!";exit 1 +UNIXNAME = $(shell uname -sm) + +ifeq ($(CC),) + CC = gcc +endif + +ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes +endif + +# For FreeBSD +ifeq ($(findstring FreeBSD, $(UNIXNAME)), FreeBSD) + CFLAGS += -DFREEBSD -D_REENTRANT -pedantic + SYSLIB += -lcrypt +endif + +#Path for Linux +ifeq ($(findstring Linux, $(UNIXNAME)), Linux) + CFLAGS += -DLINUX2 -D_REENTRANT -pedantic + SYSLIB += -lcrypt +endif + +#Path for SunOS +ifeq ($(findstring SunOS, $(UNIXNAME)), SunOS) + ifeq ($(findstring 86, $(UNIXNAME)), 86) + SYSLIB += -lsocket -lnsl -lrt + endif + ifeq ($(findstring sun4u, $(UNIXNAME)), sun4u) + SYSLIB += -lsocket -lnsl -lrt + endif + CFLAGS += -DSUNOS5 -D_REENTRANT -pedantic + SYSLIB += -lcrypt +endif + +#Path for HP-UX +ifeq ($(findstring HP-UX, $(UNIXNAME)), HP-UX) + CFLAGS += -DHP_UX -DHPUX11 + PLAT_NAME=hp-ux + SYSLIB += -lcrypt +endif + +# For Darwin +ifeq ($(findstring Darwin, $(UNIXNAME)), Darwin) + CFLAGS += -DMACOSX +endif + +#Find system type. +ifneq ($(SYSPATH),) + CHECKSYSRES = @echo "System is $(shell uname -sm)" +endif +########################################################### + +ACL_PATH = ../../lib_acl +ACL_INC = $(ACL_PATH)/include +ACL_LIB = $(ACL_PATH)/lib + +PROTO_PATH = ../../lib_protocol +PROTO_INC = $(PROTO_PATH)/include +PROTO_LIB = $(PROTO_PATH)/lib + +EXTLIBS = +CFLAGS += -I$(ACL_INC) -I$(PROTO_INC) +LDFLAGS = -L$(ACL_LIB) -L$(PROTO_LIB) -l_protocol -l_acl $(EXTLIBS) $(SYSLIB) + +########################################################### + +OUT_PATH = . +OBJ_PATH = $(OUT_PATH) + +#Project's objs +SRC = $(wildcard *.cpp) +OBJ = $(patsubst %.cpp, $(OBJ_PATH)/%.o, $(notdir $(SRC))) +########################################################### + +.PHONY = all clean +PROG = + +COMPILE = $(CC) $(CFLAGS) + +all: RM $(OBJ) + $(CC) $(OBJ) $(LDFLAGS) \ + -Wl,-rpath,$(ACL_LIB) -Wl,-rpath,$(PROTO_LIB) -o $(OBJ_PATH)/$(PROG) + @echo "" + @echo "All ok! Output:$(PROG)" + @echo "" +$(OBJ_PATH)/%.o: %.cpp + $(COMPILE) $< -o $@ +RM: + rm -f $(PROG) +clean: + rm -f $(PROG) + rm -f $(OBJ) +########################################################### diff --git a/samples/acl/Makefile b/samples/acl/Makefile new file mode 100644 index 000000000..cd4c2ce76 --- /dev/null +++ b/samples/acl/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = acl diff --git a/samples/acl/main.c b/samples/acl/main.c new file mode 100644 index 000000000..3e640c50a --- /dev/null +++ b/samples/acl/main.c @@ -0,0 +1,8 @@ +#include "lib_acl.h" +#include + +int main(void) +{ + printf("current acl version: %s\n", acl_version()); + return (0); +} diff --git a/samples/aio/Makefile b/samples/aio/Makefile new file mode 100644 index 000000000..dadcf126c --- /dev/null +++ b/samples/aio/Makefile @@ -0,0 +1,8 @@ +.PHONY = all clean + +all: + @(cd client; make) + @(cd server; make) +clean: + @(cd client; make clean) + @(cd server; make clean) diff --git a/samples/aio/Makefile.in b/samples/aio/Makefile.in new file mode 100644 index 000000000..356dd2b5b --- /dev/null +++ b/samples/aio/Makefile.in @@ -0,0 +1,112 @@ +CC = gcc + +CFLAGS = -c -g -W -Wall -Wcast-qual -Wcast-align \ +-Waggregate-return -Wno-long-long -Wmissing-prototypes \ +-Wpointer-arith -Werror -Wshadow -O2 \ +-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO + +#CFLAGS = -c -g -W -Wall -Wcast-qual -Wcast-align \ +#-Waggregate-return -Wmissing-prototypes \ +#-Wpointer-arith -Werror -Wshadow -O2 \ +#-D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO +########################################################### +#Check system: +# Linux, SunOS, Solaris, BSD variants, AIX, HP-UX +SYSLIB = -lpthread +CHECKSYSRES = @echo "Unknow system type!";exit 1 +UNIXNAME = $(shell uname -sm) + +ifeq ($(CC),) + CC = gcc +endif + +ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes +endif + +# For FreeBSD +ifeq ($(findstring FreeBSD, $(UNIXNAME)), FreeBSD) + CFLAGS += -DFREEBSD -D_REENTRANT + SYSLIB += -lcrypt +endif + +#Path for Linux +ifeq ($(findstring Linux, $(UNIXNAME)), Linux) + CFLAGS += -DLINUX2 -D_REENTRANT + SYSLIB += -lcrypt +endif + +# For Darwin +ifeq ($(findstring Darwin, $(UNIXNAME)), Darwin) + CFLAGS += -DMACOSX +endif + +#Path for SunOS +ifeq ($(findstring SunOS, $(UNIXNAME)), SunOS) + ifeq ($(findstring 86, $(UNIXNAME)), 86) + SYSLIB += -lsocket -lnsl -lrt + endif + ifeq ($(findstring sun4u, $(UNIXNAME)), sun4u) + SYSLIB += -lsocket -lnsl -lrt + endif + CFLAGS += -DSUNOS5 -D_REENTRANT + SYSLIB += -lcrypt +endif + +#Path for HP-UX +ifeq ($(findstring HP-UX, $(UNIXNAME)), HP-UX) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DHP_UX -DHPUX11 + PLAT_NAME=hp-ux + SYSLIB += -lcrypt +endif + +#Find system type. +ifneq ($(SYSPATH),) + CHECKSYSRES = @echo "System is $(shell uname -sm)" +endif +########################################################### + +ACL_PATH = ../../../lib_acl +ACL_INC = $(ACL_PATH)/include +ACL_LIB = $(ACL_PATH)/lib + +PROTO_PATH = ../../../lib_protocol +PROTO_INC = $(PROTO_PATH)/include +PROTO_LIB = $(PROTO_PATH)/lib + +EXTLIBS = +CFLAGS += -I$(ACL_INC) -I$(PROTO_INC) +LDFLAGS = -L$(ACL_LIB) -L$(PROTO_LIB) -l_protocol -l_acl $(EXTLIBS) $(SYSLIB) + +########################################################### + +OUT_PATH = . +OBJ_PATH = $(OUT_PATH) + +#Project's objs +SRC = $(wildcard *.c) +OBJ = $(patsubst %.c, $(OBJ_PATH)/%.o, $(notdir $(SRC))) +########################################################### + +.PHONY = all clean +PROG = + +COMPILE = $(CC) $(CFLAGS) + +all: RM $(OBJ) + $(CC) $(OBJ) $(LDFLAGS) \ + -Wl,-rpath,$(ACL_LIB) -Wl,-rpath,$(PROTO_LIB) -o $(OBJ_PATH)/$(PROG) + @echo "" + @echo "All ok! Output:$(PROG)" + @echo "" +$(OBJ_PATH)/%.o: %.c + $(COMPILE) $< -o $@ +RM: + rm -f $(PROG) +clean: + rm -f $(PROG) + rm -f $(OBJ) +########################################################### diff --git a/samples/aio/client/Makefile b/samples/aio/client/Makefile new file mode 100644 index 000000000..2a3268608 --- /dev/null +++ b/samples/aio/client/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = aclient diff --git a/samples/aio/client/ReadMe.txt b/samples/aio/client/ReadMe.txt new file mode 100644 index 000000000..f463e2973 --- /dev/null +++ b/samples/aio/client/ReadMe.txt @@ -0,0 +1,31 @@ +======================================================================== + 控制台应用程序 : client 项目概况 +======================================================================== + +应用程序向导已为您创建了这个 client 应用程序。 +此文件包含组成 client 应用程序 +的每个文件的内容摘要。 + + +client.vcproj + 这是用应用程序向导生成的 VC++ 项目的主项目文件。 + 它包含有关生成此文件的 Visual C++ 版本的信息,以及 + 有关用应用程序向导选择的 + 平台、配置和项目功能的信息。 + +client.cpp + 这是主应用程序源文件。 + +///////////////////////////////////////////////////////////////////////////// +其他标准文件: + +StdAfx.h、StdAfx.cpp + 这些文件用于生成名为 client.pch + 的预编译头(PCH)文件以及名为 StdAfx.obj 的预编译类型文件。 + +///////////////////////////////////////////////////////////////////////////// +其他注释: + +应用程序向导使用 "TODO:" 注释指示应添加或自定义的源代码部分。 + +///////////////////////////////////////////////////////////////////////////// diff --git a/samples/aio/client/client.vcproj b/samples/aio/client/client.vcproj new file mode 100644 index 000000000..2ea410dfc --- /dev/null +++ b/samples/aio/client/client.vcproj @@ -0,0 +1,298 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/aio/client/client.vcxproj b/samples/aio/client/client.vcxproj new file mode 100644 index 000000000..fc629d185 --- /dev/null +++ b/samples/aio/client/client.vcxproj @@ -0,0 +1,196 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + ReleaseDll + Win32 + + + Release + Win32 + + + + aio_client + {FE9DEE6B-3256-4362-9014-B5FC5F04844E} + aio_client + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;MS_VC;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + wsock32.lib;ws2_32.lib;%(AdditionalDependencies) + $(OutDir)client.exe + %(AdditionalLibraryDirectories) + %(IgnoreSpecificDefaultLibraries) + true + $(OutDir)client.pdb + Console + MachineX86 + + + + + ..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + wsock32.lib;ws2_32.lib;%(AdditionalDependencies) + $(OutDir)client.exe + %(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + + + + + Disabled + ..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;MS_VC;ACL_DLL;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + EditAndContinue + + + wsock32.lib;ws2_32.lib;%(AdditionalDependencies) + $(OutDir)client.exe + %(AdditionalLibraryDirectories) + %(IgnoreSpecificDefaultLibraries) + true + $(OutDir)client.pdb + Console + MachineX86 + + + + + ..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;MS_VC;ACL_DLL;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + wsock32.lib;ws2_32.lib;%(AdditionalDependencies) + $(OutDir)client.exe + %(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + + + + + + + + {b40213c2-507c-4c7f-a6e1-b850c9bdc27b} + false + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/aio/client/client.vcxproj.filters b/samples/aio/client/client.vcxproj.filters new file mode 100644 index 000000000..5b91d37e5 --- /dev/null +++ b/samples/aio/client/client.vcxproj.filters @@ -0,0 +1,33 @@ +锘 + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx + + + + + + + + 婧愭枃浠 + + + 婧愭枃浠 + + + + + 澶存枃浠 + + + \ No newline at end of file diff --git a/samples/aio/client/echo_client.c b/samples/aio/client/echo_client.c new file mode 100644 index 000000000..51f756bfe --- /dev/null +++ b/samples/aio/client/echo_client.c @@ -0,0 +1,247 @@ +#include "lib_acl.h" +#include +#include +#include +#include +#include + +#include "echo_client.h" + +typedef struct ECHO_COUNTER{ + int nloop; + int max_loop; + ACL_ASTREAM *stream; +} ECHO_COUNTER; + +static int __nread = 0; +static int __nwrite = 0; +static int __nconnect_ok = 0; +static int __nconn = 0; + +static ACL_AIO *__aio = NULL; +static char *__data; + +static char *__server_addr = NULL; +static int __max_connect = 1000; +static int __max_loop = 1; +static int __timeout = 60; +static int __dlen = 256; +static int __nconn_per_sec = 100; + +/* forward functions */ + +static int __write_callback( ACL_ASTREAM *stream, void *context, + const char *data, int dlen); + +static int __timeout_callback(ACL_ASTREAM *stream acl_unused, + void *context acl_unused) +{ + printf("timeout, sockfd=%d\r\n", ACL_VSTREAM_SOCK(acl_aio_vstream(stream))); + return (-1); +} + +static int __close_callback(ACL_ASTREAM *stream, void *context) +{ + ECHO_COUNTER *counter = (ECHO_COUNTER *) context; + + printf("closed, sockfd=%d\r\n", ACL_VSTREAM_SOCK(acl_aio_vstream(stream))); + __nconn--; + acl_myfree(counter); + return (-1); +} + +static int __read_callback(ACL_ASTREAM *stream, void *context, + const char *data acl_unused, int dlen acl_unused) +{ + ECHO_COUNTER *counter = (ECHO_COUNTER *) context; + + __nread++; + counter->nloop++; + + if (counter->nloop % 10000 == 0) + printf(">>> nloop=%d, max_loop=%d\r\n", + counter->nloop, counter->max_loop); + if (counter->nloop >= counter->max_loop) { + printf(">>> ok, nloop=%d, max_loop=%d\r\n", + counter->nloop, counter->max_loop); + return (-1); + } + + acl_aio_fprintf(stream, "%s\n", __data); + return (0); +} + +static int __write_callback(ACL_ASTREAM *stream, void *context acl_unused, + const char *data acl_unused, int dlen acl_unused) +{ + __nwrite++; + acl_aio_gets(stream); + return (0); +} + +static int __connect_callback(ACL_ASTREAM *client, void *context acl_unused) +{ + __nconnect_ok++; + acl_aio_fprintf(client, "%s\n", __data); + return (0); +} + +void echo_client_init(int name, ...) +{ + va_list ap; + int i, event_mode = 0; + + /* init the variable */ + __nread = 0; + __nwrite = 0; + __nconnect_ok = 0; + __nconn = 0; + + va_start(ap, name); + + for (; name != ECHO_CTL_END; name = va_arg(ap, int)) { + switch (name) { + case ECHO_CTL_SERV_ADDR: + __server_addr = acl_mystrdup(va_arg(ap, char *)); + break; + case ECHO_CTL_MAX_CONNECT: + __max_connect = va_arg(ap, int); + break; + case ECHO_CTL_MAX_LOOP: + __max_loop = va_arg(ap, int); + break; + case ECHO_CTL_TIMEOUT: + __timeout = va_arg(ap, int); + break; + case ECHO_CTL_DATA_LEN: + __dlen = va_arg(ap, int); + break; + case ECHO_CTL_NCONN_PERSEC: + __nconn_per_sec = va_arg(ap, int); + break; + case ECHO_CTL_EVENT_MODE: + event_mode = va_arg(ap, int); + break; + default: + acl_msg_fatal("%s(%d): unknown arg(%d)", + __FILE__, __LINE__, name); + } + } + + va_end(ap); + + assert(__aio == NULL); + + switch (event_mode) { + case ACL_EVENT_SELECT: + printf("------- use select --------\r\n"); + break; + case ACL_EVENT_KERNEL: + printf("------- use kernel --------\r\n"); + break; + case ACL_EVENT_POLL: + printf("------- use poll --------\r\n"); + break; + default: + acl_msg_fatal("%s: unknown event(%d)", __FUNCTION__, event_mode); + break; + } + + __aio = acl_aio_create(event_mode); + acl_aio_set_keep_read(__aio, 1); + + assert(__data == NULL); + __data = (char *) acl_mycalloc(1, __dlen); + assert(__data); + + for (i = 0; i < __dlen - 2; i++) { + __data[i] ='0'; + } + + __dlen = (int) strlen(__data); + + if (__server_addr == NULL) + __server_addr = acl_mystrdup("127.0.0.1:30082"); +} + +static void connect_pool(void) +{ + const char *myname = "connect_pool"; + ECHO_COUNTER *counter; + int i; + + for (i = 0; i < __max_connect; i++) { + counter = (ECHO_COUNTER *) acl_mycalloc(1, sizeof(ECHO_COUNTER)); + counter->nloop = 0; + counter->max_loop = __max_loop; + counter->stream = acl_aio_connect(__aio, __server_addr, __timeout); + if (counter->stream == NULL) { + printf("%s(%d): acl_aio_connect(%s) error(%s)\r\n", + myname, __LINE__, __server_addr, + acl_last_serror()); + acl_myfree(counter); + sleep(1); + continue; + } + + acl_aio_ctl(counter->stream, + ACL_AIO_CTL_WRITE_HOOK_ADD, __write_callback, counter, + ACL_AIO_CTL_READ_HOOK_ADD, __read_callback, counter, + ACL_AIO_CTL_TIMEO_HOOK_ADD, __timeout_callback, counter, + ACL_AIO_CTL_CLOSE_HOOK_ADD, __close_callback, counter, + ACL_AIO_CTL_CONNECT_HOOK_ADD, __connect_callback, counter, + ACL_AIO_CTL_TIMEOUT, __timeout, + ACL_AIO_CTL_END); + __nconn++; + + if (__nconn_per_sec > 0 && i % __nconn_per_sec == 0) { + printf("%s: connect->%d\r\n", myname, i); + sleep(1); + } + } + + printf("prepare connect %d ok, __timeout=%d\r\n", __nconn, __timeout); +} + +static void gc_timer(int event_type acl_unused, void *context) +{ + ACL_AIO *aio = (ACL_AIO *) context; + + acl_mem_slice_delay_destroy(); + /* 设定定时器定时清理垃圾回收器 */ + acl_aio_request_timer(aio, gc_timer, aio, 2, 0); +} + +void echo_client_start(int use_slice) +{ + time_t begin; + + /* 建立连接池 */ + connect_pool(); + + begin = time(NULL); + + /* 设定定时器定时清理垃圾回收器 */ + if (use_slice) + acl_aio_request_timer(__aio, gc_timer, __aio, 2, 0); + + while (1) { + acl_aio_loop(__aio); + if (__nconn <= 0) + break; + } + + printf(">>> OK, current thread number=0, exit now, nconn(%d)\r\n", __nconn); + printf(">>> nconnect(%d), nread(%d), nwrite(%d), total time(%ld)\r\n", + __nconnect_ok, __nread, __nwrite, time(NULL) - begin); + + if (__server_addr) + acl_myfree(__server_addr); + __server_addr = NULL; + if (__data) + acl_myfree(__data); + __data = NULL; + printf("enter any key to quit now\n"); + getchar(); +} + diff --git a/samples/aio/client/echo_client.h b/samples/aio/client/echo_client.h new file mode 100644 index 000000000..5e0ad3fe7 --- /dev/null +++ b/samples/aio/client/echo_client.h @@ -0,0 +1,17 @@ +#ifndef __AIO_ECHO_CLIENT_INCLUDE_H__ +#define __AIO_ECHO_CLIENT_INCLUDE_H__ + +#define ECHO_CTL_END 0 +#define ECHO_CTL_SERV_ADDR 1 +#define ECHO_CTL_MAX_CONNECT 2 +#define ECHO_CTL_MAX_LOOP 3 +#define ECHO_CTL_TIMEOUT 4 +#define ECHO_CTL_DATA_LEN 5 +#define ECHO_CTL_NCONN_PERSEC 6 +#define ECHO_CTL_EVENT_MODE 7 + +void echo_client_init(int name, ...); +void echo_client_start(int use_slice); + +#endif + diff --git a/samples/aio/client/main.c b/samples/aio/client/main.c new file mode 100644 index 000000000..b8149e226 --- /dev/null +++ b/samples/aio/client/main.c @@ -0,0 +1,110 @@ +#include "lib_acl.h" +#include +#include +#include +#include + +#include "echo_client.h" + +static int __max_threads = 10; +static int __nconnect = 500; +static int __nloop = 1000; +static char *__svr_addr; +static int __dlen = 1024; +static int __timeout = 120; +static int __nconn_per_sec = 100; +static int __event_mode; + +static void init(int use_slice) +{ +#if 0 + char logfile[] = "test.log"; + char logpre[] = "thread_test"; + + acl_msg_open(logfile, logpre); +#endif + + if (use_slice) + acl_mem_slice_init(8, 10240, 100000, + ACL_SLICE_FLAG_GC2 | ACL_SLICE_FLAG_RTGC_OFF | ACL_SLICE_FLAG_LP64_ALIGN); + + acl_init(); + echo_client_init(ECHO_CTL_SERV_ADDR, __svr_addr, + ECHO_CTL_MAX_CONNECT, __nconnect, + ECHO_CTL_MAX_LOOP, __nloop, + ECHO_CTL_TIMEOUT, __timeout, + ECHO_CTL_DATA_LEN, __dlen, + ECHO_CTL_NCONN_PERSEC, __nconn_per_sec, + ECHO_CTL_EVENT_MODE, __event_mode, + ECHO_CTL_END); +} + +static void run(int use_slice) +{ + printf("server started(max=%d) OK, listen=%s\n", __max_threads, __svr_addr); + echo_client_start(use_slice); +} + +static void usage(const char *progname) +{ + printf("usage: %s -h (help) -s server_addr(ip:port) -m event (select|poll|kernel)" + " -P [use mempool]-n nconnect -l nloop -d dlen" + " -c timeout -p nconn_per_sec\n", progname); +} + +int main(int argc, char *argv[]) +{ + char ch; + int use_slice = 0; + + while ((ch = getopt(argc, argv, "hPm:s:n:l:d:c:p:")) > 0) { + switch (ch) { + case 'h': + usage(argv[0]); + exit (0); + case 'm': + if (strcasecmp(optarg, "select") == 0) + __event_mode = ACL_EVENT_SELECT; + else if (strcasecmp(optarg, "kernel") == 0) + __event_mode = ACL_EVENT_KERNEL; + else if (strcasecmp(optarg, "poll") == 0) + __event_mode = ACL_EVENT_POLL; + else + __event_mode = ACL_EVENT_SELECT; + break; + case 'n': + __nconnect = atoi(optarg); + break; + case 'l': + __nloop = atoi(optarg); + break; + case 's': + __svr_addr = acl_mystrdup(optarg); + break; + case 'd': + __dlen = atoi(optarg); + break; + case 'c': + __timeout = atoi(optarg); + break; + case 'p': + __nconn_per_sec = atoi(optarg); + break; + case 'P': + use_slice = 1; + break; + default: + usage(argv[0]); + exit (0); + } + } + + if (__max_threads < 0) + __max_threads = 0; + if (__svr_addr == NULL) + __svr_addr = acl_mystrdup("127.0.0.1:30082"); + + init(use_slice); + run(use_slice); + exit (0); +} diff --git a/samples/aio/server/Makefile b/samples/aio/server/Makefile new file mode 100644 index 000000000..5669efd4e --- /dev/null +++ b/samples/aio/server/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = aserver diff --git a/samples/aio/server/echo_server.c b/samples/aio/server/echo_server.c new file mode 100644 index 000000000..747025c86 --- /dev/null +++ b/samples/aio/server/echo_server.c @@ -0,0 +1,206 @@ +#include "lib_acl.h" +#include +#include +#include + +#include "echo_server.h" + +#define USE_GETS + +/* forward functions */ + +static char *__data; +static int __dlen; +static int __echo_src; + +static int __gets_callback(ACL_ASTREAM *stream, void *context, + const char *data, int dlen); + +static void default_write_fn(void *arg acl_unused, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + acl_msg_info2(fmt, ap); + va_end(ap); +} + +static void default_fflush_fn(void *arg) +{ + arg = arg; +} + +static void (*__write_fn)(void *arg, const char *fmt, ...) = default_write_fn; +static void *__write_arg = NULL; +static void (*__fflush_fn)(void *arg) = default_fflush_fn; +static void *__fflush_arg = NULL; + +void echo_server_log_fn(void (*write_fn)(void *, const char *fmt, ...), + void *write_arg, + void (*fflush_fn)(void *), + void *fflush_arg) +{ + if (write_fn) { + __write_fn = write_fn; + __write_arg = write_arg; + } + + if (fflush_fn) { + __fflush_fn = fflush_fn; + __fflush_arg = fflush_arg; + } +} + +/*---------------------------------------------------------------------------*/ +static int __io_close(ACL_ASTREAM *astream, void *context acl_unused) +{ + const char *myname = "__io_close"; + ACL_VSTREAM *stream = acl_aio_vstream(astream); + + __write_fn(__write_arg, "%s, %s(%d): client(%d) exception!", + __FILE__, myname, __LINE__, ACL_VSTREAM_SOCK(stream)); + + return (-1); +} + +static int __io_timeout(ACL_ASTREAM *astream, void *context acl_unused) +{ + const char *myname = "__io_timeout"; + ACL_VSTREAM *stream = acl_aio_vstream(astream); + + __write_fn(__write_arg, "%s, %s(%d): client(%d) timeout!", + __FILE__, myname, __LINE__, ACL_VSTREAM_SOCK(stream)); + + return (-1); +} +static int __write_callback(ACL_ASTREAM *client, void *context acl_unused, + const char *data acl_unused, int dlen acl_unused) +{ +#ifdef USE_GETS + acl_aio_gets(client); +#else + acl_aio_read(client); +#endif + return (0); +} + +static int __gets_callback(ACL_ASTREAM *stream, void *context acl_unused, + const char *data, int dlen) +{ + if (__echo_src) + (void) acl_aio_writen(stream, data, dlen); + else + acl_aio_writen(stream, __data, __dlen); + + return (0); +} + +static int __accept_callback(ACL_ASTREAM *client, void *context acl_unused) +{ + char buf[64]; + + if (acl_getpeername(ACL_VSTREAM_SOCK(acl_aio_vstream(client)), buf, sizeof(buf)) == 0) + printf("connect from %s\r\n", buf); + else + printf("can't get client addr %s\r\n", acl_last_serror()); + + acl_aio_ctl(client, + ACL_AIO_CTL_READ_HOOK_ADD, __gets_callback, NULL, + ACL_AIO_CTL_WRITE_HOOK_ADD, __write_callback, NULL, + ACL_AIO_CTL_CLOSE_HOOK_ADD, __io_close, NULL, + ACL_AIO_CTL_TIMEO_HOOK_ADD, __io_timeout, NULL, + ACL_AIO_CTL_END); +#ifdef USE_GETS + acl_aio_gets(client); +#else + acl_aio_read(client); +#endif + + return (0); +} + +static void __listen_callback(ACL_ASTREAM *sstream, void *context) +{ + ACL_VSTREAM *cstream; + ACL_ASTREAM *client; + ACL_AIO *aio = (ACL_AIO *) context; + char buf[64]; + int i; + + for (i = 0; i < 10; i++) { + cstream = acl_vstream_accept(acl_aio_vstream(sstream), NULL, 0); + if (cstream == NULL) + break; + + if (acl_getpeername(ACL_VSTREAM_SOCK(cstream), buf, sizeof(buf)) == 0) + printf("connect from %s\r\n", buf); + else + printf("can't get client addr %s\r\n", acl_last_serror()); + cstream->rw_timeout = 0; + acl_non_blocking(ACL_VSTREAM_SOCK(cstream), ACL_NON_BLOCKING); + client = acl_aio_open(aio, cstream); + acl_aio_ctl(client, + ACL_AIO_CTL_READ_HOOK_ADD, __gets_callback, NULL, + ACL_AIO_CTL_WRITE_HOOK_ADD, __write_callback, NULL, + ACL_AIO_CTL_CLOSE_HOOK_ADD, __io_close, NULL, + ACL_AIO_CTL_TIMEO_HOOK_ADD, __io_timeout, NULL, + ACL_AIO_CTL_END); +#ifdef USE_GETS + acl_aio_gets(client); +#else + acl_aio_read(client); +#endif + } +} + +ACL_AIO *echo_server_start(ACL_VSTREAM *sstream, int accept_auto, int event_mode) +{ + char myname[] = "echo_start"; + ACL_AIO *h_aio; + ACL_ASTREAM *astream; + + switch (event_mode) { + case ACL_EVENT_SELECT: + printf("------- use select --------\r\n"); + break; + case ACL_EVENT_KERNEL: + printf("------- use kernel --------\r\n"); + break; + case ACL_EVENT_POLL: + printf("------- use poll --------\r\n"); + break; + default: + acl_msg_fatal("%s: unknown event(%d)", myname, event_mode); + break; + } + + h_aio = acl_aio_create(event_mode); + acl_aio_set_keep_read(h_aio, 1); + + if (h_aio == NULL) + acl_msg_fatal("%s(%d): acl_aio_create error(%s)", + myname, __LINE__, acl_last_serror()); + + astream = acl_aio_open(h_aio, sstream); + + if (!accept_auto) { + acl_aio_ctl(astream, ACL_AIO_CTL_LISTEN_FN, __listen_callback, + ACL_AIO_CTL_CTX, h_aio, + ACL_AIO_CTL_END); + acl_aio_listen(astream); + } else { + acl_aio_ctl(astream, ACL_AIO_CTL_ACCEPT_FN, __accept_callback, + ACL_AIO_CTL_CTX, h_aio, + ACL_AIO_CTL_END); + acl_aio_accept(astream); + } + + return (h_aio); +} + +void echo_server_init(char *data, int dlen, int echo_src) +{ + __data = data; + __dlen = dlen; + __echo_src = echo_src; +} diff --git a/samples/aio/server/echo_server.h b/samples/aio/server/echo_server.h new file mode 100644 index 000000000..4fbace7fc --- /dev/null +++ b/samples/aio/server/echo_server.h @@ -0,0 +1,12 @@ +#ifndef __AIO_ECHO_SERVER_INCLUDE_H__ +#define __AIO_ECHO_SERVER_INCLUDE_H__ + +#include "lib_acl.h" + +void echo_server_log_fn(void (*write_fn)(void *, const char *fmt, ...), + void *write_arg, void (*fflush_fn)(void *), void *fflush_arg); +void echo_server_init(char *data, int dlen, int echo_src); +ACL_AIO *echo_server_start(ACL_VSTREAM *sstream, int accept_auto, int event_kernel); + +#endif + diff --git a/samples/aio/server/main.c b/samples/aio/server/main.c new file mode 100644 index 000000000..c90c62b36 --- /dev/null +++ b/samples/aio/server/main.c @@ -0,0 +1,186 @@ +#include "lib_acl.h" +#include +#include +#include +#include +#include +#include +#ifdef ACL_MS_WINDOWS +#include +#endif +#include "echo_server.h" + +static int __use_slice = 0; +static int __nrunner = 1; +static int __accept_auto = 0; +static int __send_size = 100; +static char *__data; +static int __echo_src; +static int __event_mode = ACL_EVENT_KERNEL; + +static char *__listen_addr; + +static void init(void) +{ +#ifdef USE_LOG + char logfile[] = "test.log"; + char logpre[] = "thread_test"; +#endif + + int i; + + if (__use_slice) + acl_mem_slice_init(8, 10240, 100000, + ACL_SLICE_FLAG_GC2 | ACL_SLICE_FLAG_RTGC_OFF | ACL_SLICE_FLAG_LP64_ALIGN); + + acl_init(); +#ifdef USE_LOG + acl_msg_open(logfile, logpre); +#endif + + if (__send_size <= 0) + __send_size = 100; + + __data = acl_mycalloc(1, __send_size); + assert(__data); + + for (i = 0; i < __send_size - 2; i++) { + __data[i] = 'i'; + } + + __data[i++] = '\n'; + __data[i] = 0; + + echo_server_init(__data, (int) strlen(__data), __echo_src); +} + +static void gc_timer(int event_type acl_unused, void *context) +{ + ACL_AIO *aio = (ACL_AIO *) context; + + acl_mem_slice_delay_destroy(); + /* 设定定时器定时清理垃圾回收器 */ + acl_aio_request_timer(aio, gc_timer, aio, 2, 0); +} + +static void *__runner_loop(void *arg) +{ + ACL_VSTREAM *sstream = (ACL_VSTREAM *) arg; + ACL_AIO *aio; + + aio = echo_server_start(sstream, __accept_auto, __event_mode); + + printf("start one thread ok, id=%lu, pid=%d\n", + (unsigned long) acl_pthread_self(), (int) getpid()); + + /* 设定定时器定时清理垃圾回收器 */ + if (__use_slice) + acl_aio_request_timer(aio, gc_timer, aio, 2, 0); + + while (1) { + acl_aio_loop(aio); + } + + /* not reached */ + acl_vstream_close(sstream); + + return (NULL); +} + +static void __proccess_running(ACL_VSTREAM *sstream, int nrunner) +{ +#ifdef ACL_UNIX + int i; + + for (i = 0; i < nrunner; i++) { + switch (fork()) { + case 0: /* child */ + __runner_loop(sstream); + exit (0); + case -1: + exit (1); + default: /* parent */ + break; + } + } +#elif defined(ACL_MS_WINDOWS) + __runner_loop(sstream); +#endif +} + +static void run(void) +{ + ACL_VSTREAM *sstream; + + sstream = acl_vstream_listen(__listen_addr, 256); + assert(sstream); + + __proccess_running(sstream, __nrunner); + acl_vstream_close(sstream); +} + +static void usage(const char *progname) +{ + printf("usage: %s -h(help) -a(accept auto) -n instances " + "-s listen_addr(ip:port) -m event_type (select|kernel|poll) " + "-P [use mempool] -l echo_size -e(echo src data)\n", progname); +} + +int main(int argc, char *argv[]) +{ + char ch; + +#if 0 + int base = 8, nslice = 1024, nalloc_gc = 1000000; + unsigned int slice_flag = ACL_SLICE_FLAG_GC2 | ACL_SLICE_FLAG_RTGC_OFF; + + acl_mem_slice_init(base, nslice, nalloc_gc, slice_flag); +#endif + + while ((ch = getopt(argc, argv, "hPeam:s:n:l:")) > 0) { + switch (ch) { + case 'h': + usage(argv[0]); + exit (0); + case 'm': + if (strcasecmp(optarg, "select") == 0) + __event_mode = ACL_EVENT_SELECT; + else if (strcasecmp(optarg, "kernel") == 0) + __event_mode = ACL_EVENT_KERNEL; + else if (strcasecmp(optarg, "poll") == 0) + __event_mode = ACL_EVENT_POLL; + else + __event_mode = ACL_EVENT_SELECT; + break; + case 'a': + __accept_auto = 1; + break; + case 's': + __listen_addr = acl_mystrdup(optarg); + break; + case 'n': + __nrunner = atoi(optarg); + break; + case 'l': + __send_size = atoi(optarg); + break; + case 'e': + __echo_src = 1; + break; + case 'P': + __use_slice = 1; + break; + default: + break; + } + } + + if (__listen_addr == NULL) + __listen_addr = acl_mystrdup("0.0.0.0:30082"); + + printf("listen=%s\n", __listen_addr); + acl_msg_stdout_enable(1); + init(); + run(); + exit (0); +} diff --git a/samples/aio/server/server.vcproj b/samples/aio/server/server.vcproj new file mode 100644 index 000000000..a6834bb77 --- /dev/null +++ b/samples/aio/server/server.vcproj @@ -0,0 +1,249 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/aio/server/server.vcxproj b/samples/aio/server/server.vcxproj new file mode 100644 index 000000000..c2387b002 --- /dev/null +++ b/samples/aio/server/server.vcxproj @@ -0,0 +1,195 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + ReleaseDll + Win32 + + + Release + Win32 + + + + aio_server + {60731E38-81E7-4FE8-8634-8DF706CE9971} + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;MS_VC;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + wsock32.lib;ws2_32.lib;%(AdditionalDependencies) + $(OutDir)server.exe + %(AdditionalLibraryDirectories) + %(IgnoreSpecificDefaultLibraries) + true + $(OutDir)server.pdb + Console + MachineX86 + + + + + ..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;%(AdditionalDependencies) + $(OutDir)server.exe + %(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + + + + + Disabled + ..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;MS_VC;ACL_DLL;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + EditAndContinue + + + wsock32.lib;ws2_32.lib;%(AdditionalDependencies) + $(OutDir)server.exe + %(AdditionalLibraryDirectories) + %(IgnoreSpecificDefaultLibraries) + true + $(OutDir)server.pdb + Console + MachineX86 + + + + + ..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;MS_VC;ACL_DLL;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)server.exe + %(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + + + + + + + + {b40213c2-507c-4c7f-a6e1-b850c9bdc27b} + false + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/aio/server/server.vcxproj.filters b/samples/aio/server/server.vcxproj.filters new file mode 100644 index 000000000..99a018c7c --- /dev/null +++ b/samples/aio/server/server.vcxproj.filters @@ -0,0 +1,33 @@ +锘 + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx + + + + + + + + 婧愭枃浠 + + + 婧愭枃浠 + + + + + 澶存枃浠 + + + \ No newline at end of file diff --git a/samples/base64/Makefile b/samples/base64/Makefile new file mode 100644 index 000000000..a9c90cdac --- /dev/null +++ b/samples/base64/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = base64 diff --git a/samples/base64/main.c b/samples/base64/main.c new file mode 100644 index 000000000..86219e39b --- /dev/null +++ b/samples/base64/main.c @@ -0,0 +1,85 @@ +#include +#include +#include + +#include "lib_acl.h" + +static void usage(const char *prog) +{ + printf("usage: %s -e string [-d base64_string, -h help]\n", prog); +} + +static void b64_encode(const char *ptr) +{ + ACL_VSTRING *str = acl_vstring_alloc(1); + + acl_vstring_base64_encode(str, ptr, strlen(ptr)); + + printf(">>>encode result:%s\n", acl_vstring_str(str)); + + acl_vstring_free(str); +} + +static void b64_decode(const char *ptr) +{ + ACL_VSTRING *str = acl_vstring_alloc(1); + const char *p; + +#define DECODE(b,x,l) { \ + if (acl_vstring_base64_decode((b),(x),(l)) == 0) { \ + printf("bad base64 encoded string: %s\r\n", (x)); \ + exit (1); \ + } \ +} + DECODE(str, ptr, strlen(ptr)); + + p = acl_vstring_str(str); + printf(">>>decode result:|%s|\n>>>orignal str: {%s}, len: %d\n", p, ptr, (int) ACL_VSTRING_LEN(str)); + b64_encode(p); + printf("len: %d, %d\n", (int) ACL_VSTRING_LEN(str), (int) strlen(p)); + + acl_vstring_free(str); +} + +int main(int argc, char *argv[]) +{ + char ch; + + if (argc == 1) { + usage(argv[0]); + exit (1); + } + + while ((ch = getopt(argc, argv, "e:d:h")) > 0) { + switch (ch) { + case 'e': + b64_encode(optarg); + break; + case 'd': + b64_decode(optarg); + break; + case 'h': + usage(argv[0]); + exit (0); + default: + usage(argv[0]); + exit (1); + } + } + + { + char* p = "菜"; + char buf[32]; + strcpy(buf, p); + p = buf; + p++; + *p = 0; + b64_encode(buf); + strcpy(buf, "菜谱"); + p = buf; + p++; + b64_encode(p); + } + + exit (0); +} diff --git a/samples/btree/Makefile b/samples/btree/Makefile new file mode 100644 index 000000000..713e4be38 --- /dev/null +++ b/samples/btree/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = btree diff --git a/samples/btree/btree_vc2003.vcproj b/samples/btree/btree_vc2003.vcproj new file mode 100644 index 000000000..42e074373 --- /dev/null +++ b/samples/btree/btree_vc2003.vcproj @@ -0,0 +1,239 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/btree/btree_vc2008.vcproj b/samples/btree/btree_vc2008.vcproj new file mode 100644 index 000000000..0abfa79a5 --- /dev/null +++ b/samples/btree/btree_vc2008.vcproj @@ -0,0 +1,205 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/btree/main.c b/samples/btree/main.c new file mode 100644 index 000000000..11d3e0056 --- /dev/null +++ b/samples/btree/main.c @@ -0,0 +1,56 @@ +#include "lib_acl.h" +#include +#include + +int main(void) +{ + ACL_BTREE *b; + unsigned int i, *x; + unsigned int v[] = {15, 5, 16, 3, 12, 20, 10, 13, 18, 23, 6, 7}; + unsigned int nv = sizeof(v) / sizeof(v[0]); + + b = acl_btree_create(); + + for(i = 0; i < nv; i++) { + x = (unsigned int*) acl_mymalloc(sizeof(unsigned int)); + *x = (unsigned int) i; + if (acl_btree_add(b, v[i], (void*) x) != 0) { + printf("Fail Add %u %u\r\n", v[i], *x); + } + } + + printf("depth %d\n", acl_btree_depth(b)); + acl_btree_dump(b); + + sleep(3); + x = acl_btree_remove(b, 5); + if (x) + acl_myfree(x); + acl_btree_dump(b); + sleep(3); + x = acl_btree_remove(b, 16); + if (x) + acl_myfree(x); + acl_btree_dump(b); + sleep(3); + x = acl_btree_remove(b, 13); + if (x) + acl_myfree(x); + acl_btree_dump(b); + + while (acl_btree_get_min_key(b, &i) == 0) { + if ((x = acl_btree_remove(b, i)) == NULL) { + fprintf(stderr, "Failed to remove %u\r\n", i); + } else + acl_myfree(x); + acl_btree_dump(b); + sleep(1); + } + + if (acl_btree_destroy(b) == -1) { + printf("Failed to destroy \r\n"); + } + + return (0); +} + diff --git a/samples/cache/Makefile b/samples/cache/Makefile new file mode 100644 index 000000000..8a4183c1c --- /dev/null +++ b/samples/cache/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = cache diff --git a/samples/cache/main.c b/samples/cache/main.c new file mode 100644 index 000000000..9cfb66ea1 --- /dev/null +++ b/samples/cache/main.c @@ -0,0 +1,111 @@ +#include "lib_acl.h" +#include +#include +#include + +typedef struct { + char *buf; + int len; +} MYOBJ; + +static void free_fn(const ACL_CACHE_INFO *info, void *arg) +{ + MYOBJ *o = (MYOBJ*) arg; + + printf("%s: when_timeout: %ld, now: %ld, len: %d, deleted\n", + info->key, (long) info->when_timeout, (long) time(NULL), o->len); + acl_myfree(o->buf); + acl_myfree(o); +} + +static MYOBJ *myobj_new(int len) +{ + MYOBJ *o = (MYOBJ*) acl_mymalloc(sizeof(MYOBJ)); + + o->buf = (char*) acl_mymalloc(len <= 0 ? 100 : len); + o->len = len; + return (o); +} + +static void walk_fn(ACL_CACHE_INFO *info, void *arg acl_unused) +{ + MYOBJ *o = (MYOBJ*) info->value; + + printf("%s: size: %d; when_timeout: %ld\n", info->key, o->len, (long) info->when_timeout); +} + +static void usage(const char *procname) +{ + printf("usage: %s -h [help] -n max_size -t timeout\n", procname); +} + +int main(int argc, char *argv[]) +{ + int i, n = 100, ch, timeout = 1; + ACL_CACHE_INFO *info; + ACL_CACHE *cache; + char key[32]; + MYOBJ *o; + + while ((ch = getopt(argc, argv, "hn:t:")) > 0) { + switch (ch) { + case 'h': + usage(argv[0]); + exit (0); + case 'n': + n = atoi(optarg); + break; + case 't': + timeout = atoi(optarg); + break; + default: + break; + } + } + + cache = acl_cache_create(n, timeout, free_fn); + + for (i = 0; i < n + 5; i++) { + o = myobj_new(i + 1); + snprintf(key, sizeof(key), "key(%d)", i); + assert(acl_cache_enter(cache, key, o)); + printf("add one: %s\n", key); + sleep(1); + } + + printf("\nfirst walk cache, cache size: %d\n", acl_cache_size(cache)); + acl_cache_walk(cache, walk_fn, NULL); + printf("\nfirst call acl_cache_timeout, size: %d\n", acl_cache_size(cache)); + acl_cache_timeout(cache); + printf(">>>after first acl_cache_timeout, second walk cache, cache's size: %d\n", acl_cache_size(cache)); + acl_cache_walk(cache, walk_fn, NULL); + + printf("\n"); + i = 0; + while (i++ < 5) { + printf("slee one second, i=%d\n", i); + sleep(1); + } + + printf("\nsecond call acl_cache_timeout, size: %d\n", acl_cache_size(cache)); + acl_cache_timeout(cache); + printf(">>>after second acl_cache_timeout, third walk_cache, cache's size: %d\n", acl_cache_size(cache)); + acl_cache_walk(cache, walk_fn, NULL); + + o = (MYOBJ*) acl_cache_find(cache, "key(5)"); + if (o == NULL) + printf("\n>>>key(5) not exist\n"); + else + printf("\n>>>key(5): len: %d\n", o->len); + info = acl_cache_locate(cache, "key(11)"); + if (info == NULL) + printf("\n>>>key(11) not exist\n"); + else { + o = (MYOBJ*) info->value; + printf("\n>>>key(11): len: %d, when_timeout: %ld\n", o->len, (long) info->when_timeout); + } + + printf("\nfree cache, size: %d\n", acl_cache_size(cache)); + acl_cache_free(cache); + return (0); +} diff --git a/samples/cache/test.sh b/samples/cache/test.sh new file mode 100644 index 000000000..5065bf938 --- /dev/null +++ b/samples/cache/test.sh @@ -0,0 +1,2 @@ +#!/bin/sh +./cache -n 10 -t 10 diff --git a/samples/cache/valgrind.sh b/samples/cache/valgrind.sh new file mode 100644 index 000000000..823d6a8a8 --- /dev/null +++ b/samples/cache/valgrind.sh @@ -0,0 +1,2 @@ +#!/bin/sh +valgrind --tool=memcheck --leak-check=yes --show-reachable=yes -v ./cache -n 10 -t 10 diff --git a/samples/cache2/Makefile b/samples/cache2/Makefile new file mode 100644 index 000000000..0658fca0e --- /dev/null +++ b/samples/cache2/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = cache2 diff --git a/samples/cache2/cache2.vcproj b/samples/cache2/cache2.vcproj new file mode 100644 index 000000000..db4e000b0 --- /dev/null +++ b/samples/cache2/cache2.vcproj @@ -0,0 +1,258 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/cache2/cache2.vcxproj b/samples/cache2/cache2.vcxproj new file mode 100644 index 000000000..b89e79911 --- /dev/null +++ b/samples/cache2/cache2.vcxproj @@ -0,0 +1,181 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + ReleaseDll + Win32 + + + Release + Win32 + + + + {304F46FC-629C-462A-AFA7-454CC1A8EA39} + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)cache2.exe + true + $(OutDir)cache2.pdb + Console + MachineX86 + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;%(AdditionalDependencies) + $(OutDir)cache2.exe + true + Console + true + true + MachineX86 + + + + + Disabled + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + EditAndContinue + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)cache2.exe + true + $(OutDir)cache2.pdb + Console + MachineX86 + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;%(AdditionalDependencies) + $(OutDir)cache2.exe + true + Console + true + true + MachineX86 + + + + + {b40213c2-507c-4c7f-a6e1-b850c9bdc27b} + false + + + + + + + + + \ No newline at end of file diff --git a/samples/cache2/cache2.vcxproj.filters b/samples/cache2/cache2.vcxproj.filters new file mode 100644 index 000000000..2ea6a9a66 --- /dev/null +++ b/samples/cache2/cache2.vcxproj.filters @@ -0,0 +1,22 @@ +锘 + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx + + + + + 婧愭枃浠 + + + \ No newline at end of file diff --git a/samples/cache2/main.c b/samples/cache2/main.c new file mode 100644 index 000000000..ba19686d2 --- /dev/null +++ b/samples/cache2/main.c @@ -0,0 +1,204 @@ +#include "lib_acl.h" +#include +#include +#include + +#ifdef WIN32 +#define snprintf _snprintf +#endif + +typedef struct { + char *buf; + int len; +} MYOBJ; + +static void free_fn(const ACL_CACHE2_INFO *info, void *arg) +{ + MYOBJ *o = (MYOBJ*) arg; + + printf("%s: when_timeout: %ld, now: %ld, len: %d, deleted\n", + info->key, (long) info->when_timeout, (long) time(NULL), o->len); + acl_myfree(o->buf); + acl_myfree(o); +} + +static MYOBJ *myobj_new(int len) +{ + MYOBJ *o = (MYOBJ*) acl_mymalloc(sizeof(MYOBJ)); + + o->buf = (char*) acl_mymalloc(len <= 0 ? 100 : len); + o->len = len; + return (o); +} + +static void walk_fn(ACL_CACHE2_INFO *info, void *arg acl_unused) +{ + MYOBJ *o = (MYOBJ*) info->value; + + printf("%s: size: %d; when_timeout: %ld\n", info->key, o->len, (long) info->when_timeout); +} + +static void test1(int n, int timeout) +{ + ACL_CACHE2_INFO *info; + ACL_CACHE2 *cache; + char key[32]; + MYOBJ *o; + int i; + + cache = acl_cache2_create(n, free_fn); + + for (i = 0; i < n + 5; i++) { + o = myobj_new(i + 1); + snprintf(key, sizeof(key), "key(%d)", i); + assert(acl_cache2_enter(cache, key, o, timeout)); + printf("add one: %s\n", key); + sleep(1); + } + + printf("\nfirst walk cache, cache size: %d\n", acl_cache2_size(cache)); + acl_cache2_walk(cache, walk_fn, NULL); + printf("\nfirst call acl_cache2_timeout, size: %d\n", acl_cache2_size(cache)); + acl_cache2_timeout(cache); + printf(">>>after first acl_cache2_timeout, second walk cache, cache's size: %d\n", acl_cache2_size(cache)); + acl_cache2_walk(cache, walk_fn, NULL); + + printf("\n"); + i = 0; + while (i++ < 5) { + printf("slee one second, i=%d\n", i); + sleep(1); + } + + printf("\nsecond call acl_cache_timeout, size: %d\n", acl_cache2_size(cache)); + acl_cache2_timeout(cache); + printf(">>>after second acl_cache_timeout, third walk_cache, cache's size: %d\n", acl_cache2_size(cache)); + acl_cache2_walk(cache, walk_fn, NULL); + + o = (MYOBJ*) acl_cache2_find(cache, "key(5)"); + if (o == NULL) + printf("\n>>>key(5) not exist\n"); + else + printf("\n>>>key(5): len: %d\n", o->len); + info = acl_cache2_locate(cache, "key(11)"); + if (info == NULL) + printf("\n>>>key(11) not exist\n"); + else { + o = (MYOBJ*) info->value; + printf("\n>>>key(11): len: %d, when_timeout: %ld\n", o->len, (long) info->when_timeout); + } + + printf("\nfree cache, size: %d\n", acl_cache2_size(cache)); + acl_cache2_free(cache); +} + +static void test2(int n, int timeout) +{ + ACL_CACHE2_INFO *info; + ACL_CACHE2 *cache; + char key[32]; + MYOBJ *o; + int i; + + cache = acl_cache2_create(n, free_fn); + + for (i = 0; i < n + 5; i++) { + o = myobj_new(i + 1); + snprintf(key, sizeof(key), "key(%d)", i); + info = (ACL_CACHE2_INFO*) acl_cache2_find(cache, key); + if (info != NULL) + printf("the key: %s exist\n", key); + printf("add one: %s, timeout: %d\n", key, timeout); + assert(acl_cache2_enter(cache, key, o, timeout)); + } + + printf(">>>call acl_cache2_walk\n"); + acl_cache2_walk(cache, walk_fn, NULL); + acl_cache2_free(cache); +} + +static void test3(int n, int timeout) +{ + ACL_CACHE2_INFO *info; + ACL_CACHE2 *cache; + char key[32]; + MYOBJ *o; + int i; + ACL_ITER iter; + + printf(">>> total add: %d\n", n * 2); + cache = acl_cache2_create(n * 2, free_fn); + + for (i = 0; i < n; i++) { + o = myobj_new(2 * i + 1); + snprintf(key, sizeof(key), "key(%d)", 2 * i + 1); + info = (ACL_CACHE2_INFO*) acl_cache2_find(cache, key); + if (info != NULL) + printf("the key: %s exist\n", key); + printf("add one: %s, timeout: %d\n", key, timeout); + assert(acl_cache2_enter(cache, key, o, timeout)); + + o = myobj_new(2 * i + 2); + snprintf(key, sizeof(key), "key(%d)", 2 * i + 2); + info = (ACL_CACHE2_INFO*) acl_cache2_find(cache, key); + if (info != NULL) + printf("the key: %s exist\n", key); + printf("add one: %s, timeout: %d\n", key, timeout); + assert(acl_cache2_enter(cache, key, o, timeout)); + } + + printf(">>>>acl_foreach\n"); + acl_foreach(iter, cache) { + o = (MYOBJ*) iter.data; + info = (ACL_CACHE2_INFO*) acl_iter_info(iter, cache); + printf(">>>len=%d, key=%s\n", o->len, info->key); + } + + acl_cache2_free(cache); +} + + +static void usage(const char *procname) +{ + printf("usage: %s -h [help] -n max_size -t timeout -c cmd[test1|test2|test3]\n", procname); +} + +int main(int argc, char *argv[]) +{ + int n = 100, ch, timeout = 1; + char cmd[256]; + + ACL_SAFE_STRNCPY(cmd, "test3", sizeof(cmd)); + while ((ch = getopt(argc, argv, "hn:t:c:")) > 0) { + switch (ch) { + case 'h': + usage(argv[0]); + exit (0); + case 'n': + n = atoi(optarg); + break; + case 't': + timeout = atoi(optarg); + break; + case 'c': + ACL_SAFE_STRNCPY(cmd, optarg, sizeof(cmd)); + break; + default: + break; + } + } + (void) acl_mem_slice_init(8, 10240, 100000, + ACL_SLICE_FLAG_GC2 | ACL_SLICE_FLAG_RTGC_OFF); + if (strcasecmp(cmd, "test1") == 0) + test1(n, timeout); + else if (strcasecmp(cmd, "test2") == 0) + test2(n, timeout); + else + test3(n, timeout); + acl_mem_slice_destroy(); +#ifdef ACL_MS_WINDOWS + printf("Enter any key to exit...\n"); + getchar(); +#endif + return (0); +} diff --git a/samples/cache2/test.sh b/samples/cache2/test.sh new file mode 100644 index 000000000..5065bf938 --- /dev/null +++ b/samples/cache2/test.sh @@ -0,0 +1,2 @@ +#!/bin/sh +./cache -n 10 -t 10 diff --git a/samples/cache2/valgrind.sh b/samples/cache2/valgrind.sh new file mode 100644 index 000000000..823d6a8a8 --- /dev/null +++ b/samples/cache2/valgrind.sh @@ -0,0 +1,2 @@ +#!/bin/sh +valgrind --tool=memcheck --leak-check=yes --show-reachable=yes -v ./cache -n 10 -t 10 diff --git a/samples/cgi_env/Makefile b/samples/cgi_env/Makefile new file mode 100644 index 000000000..83b9a0f95 --- /dev/null +++ b/samples/cgi_env/Makefile @@ -0,0 +1,110 @@ +SHELL = /bin/sh +#CC = gcc +CC = g++ +AR = ar +ARFL = rv +RANLIB = ranlib + +CFLAGS = -c -g -W -Wcast-qual -Wcast-align \ +-Waggregate-return \ +-Wpointer-arith -Werror -Wshadow -O2 \ +-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO \ +-Wno-long-long +# -pedantic -Wall +# -Wmissing-prototypes +########################################################### +#Check system: +# Linux, SunOS, Solaris, BSD variants, AIX, HP-UX +SYSLIB = +CHECKSYSRES = @echo "Unknow system type!";exit 1 +UNIXNAME = $(shell uname -sm) + +# For FreeBSD +ifeq ($(findstring FreeBSD, $(UNIXNAME)), FreeBSD) + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DFREEBSD -D_REENTRANT -pedantic + SYSLIB = -lcrypt -lpthread +endif + +#Path for Linux +ifeq ($(findstring Linux, $(UNIXNAME)), Linux) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DLINUX2 + SYSLIB = -lcrypt -lpthread +endif + +#Path for SunOS +ifeq ($(findstring SunOS, $(UNIXNAME)), SunOS) + ifeq ($(findstring 86, $(UNIXNAME)), 86) + SYSLIB = -lsocket -lnsl -lrt + endif + ifeq ($(findstring sun4u, $(UNIXNAME)), sun4u) + SYSLIB = -lsocket -lnsl -lrt + endif + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DSUNOS5 +endif + +#Path for HP-UX +ifeq ($(findstring HP-UX, $(UNIXNAME)), HP-UX) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + SYSLIB = -lpthread + CFLAGS += -DHP_UX -DHPUX11 + PLAT_NAME=hp-ux +endif + +#Find system type. +ifneq ($(SYSPATH),) + CHECKSYSRES = @echo "System is $(shell uname -sm)" +endif +########################################################### + +LIB_BASE_PATH = ../../lib_acl +LIB_NAME_PATH = -L$(LIB_BASE_PATH)/lib +LIB_INCL_PATH = $(LIB_BASE_PATH)/include + +ALL_LIBS = -l_acl $(SYSLIB) + +BASE_PATH = . +INCLUDEDIR = $(BASE_PATH) +INCLUDE = -I$(INCLUDEDIR) -I$(LIB_INCL_PATH) +CFLAGS += $(INCLUDE) + +OUTPATH = ./ +OBJ_OUTPATH = $(OUTPATH) + +#Project's objs +SOURCES = $(wildcard *.c) +INCLUDES = $(wildcard *.h) +OBJS = $(patsubst %.c,$(OBJ_OUTPATH)%.o,$(SOURCES)) + +########################################################### + +PROG_NAME = cgi_env + +.PHONY = clean +COMPILE = $(CC) $(CFLAGS) + +all: RM $(PROG_NAME) + +RM: + rm -f $(PROG_NAME) + +$(PROG_NAME): $(OBJS) + $(CC) -o $(PROG_NAME) $(OBJS) $(LIB_NAME_PATH) $(ALL_LIBS) + +$(OBJ_OUTPATH)%.o: %.c *.h + $(COMPILE) -o $@ $< + +clean: + rm -f $(OBJS) $(PROG_NAME) + +rebuild: clean all diff --git a/samples/cgi_env/main.c b/samples/cgi_env/main.c new file mode 100644 index 000000000..8ff7f9f81 --- /dev/null +++ b/samples/cgi_env/main.c @@ -0,0 +1,16 @@ +#include "lib_acl.h" + +extern char **_environ; + +int main(void) +{ + const char **pptr = (const char**) _environ; + + printf("Content-Type: text/html\r\n\r\n"); + while (*pptr) { + printf("%s
\r\n", *pptr); + pptr++; + } + + return 0; +} diff --git a/samples/chunk_chain.cpp/ReadMe.txt b/samples/chunk_chain.cpp/ReadMe.txt new file mode 100644 index 000000000..85d1602f9 --- /dev/null +++ b/samples/chunk_chain.cpp/ReadMe.txt @@ -0,0 +1,31 @@ +======================================================================== + 控制台应用程序 : chunk_chain.cpp 项目概况 +======================================================================== + +应用程序向导已为您创建了这个 chunk_chain.cpp 应用程序。 +此文件包含组成 chunk_chain.cpp 应用程序 +的每个文件的内容摘要。 + + +chunk_chain.cpp.vcproj + 这是用应用程序向导生成的 VC++ 项目的主项目文件。 + 它包含有关生成此文件的 Visual C++ 版本的信息,以及 + 有关用应用程序向导选择的 + 平台、配置和项目功能的信息。 + +chunk_chain.cpp.cpp + 这是主应用程序源文件。 + +///////////////////////////////////////////////////////////////////////////// +其他标准文件: + +StdAfx.h、StdAfx.cpp + 这些文件用于生成名为 chunk_chain.cpp.pch + 的预编译头(PCH)文件以及名为 StdAfx.obj 的预编译类型文件。 + +///////////////////////////////////////////////////////////////////////////// +其他注释: + +应用程序向导使用 "TODO:" 注释指示应添加或自定义的源代码部分。 + +///////////////////////////////////////////////////////////////////////////// diff --git a/samples/chunk_chain.cpp/chunk_chain.cpp.cpp b/samples/chunk_chain.cpp/chunk_chain.cpp.cpp new file mode 100644 index 000000000..947d6ea2f --- /dev/null +++ b/samples/chunk_chain.cpp/chunk_chain.cpp.cpp @@ -0,0 +1,49 @@ +// chunk_chain.cpp.cpp : 定义控制台应用程序的入口点。 +// + +#include "stdafx.h" +#include "lib_acl.h" + +static char buf[4096]; + +static void chain_add(ACL_CHAIN *chain, int from, int dlen) +{ + printf("add: from=%d, to=%d, dlen=%d\r\n", from, from + dlen, dlen); + acl_chain_add(chain, buf, from, dlen); + acl_chain_list(chain); + printf("data dlen=%d, chunk dlen=%d\r\n\r\n", acl_chain_data_len(chain), + acl_chain_chunk_data_len(chain)); +} + +int _tmain(int argc, _TCHAR* argv[]) +{ + ACL_CHAIN *chain; + int i; + + for (i = 0; i < sizeof(buf); i++) + { + buf[i] = 'X'; + } + + chain = acl_chain_new(1024, 0); + acl_chain_reset(chain, 10); + chain_add(chain, 6, 3); + chain_add(chain, 10, 100); + chain_add(chain, 200, 100); + chain_add(chain, 400, 100); + chain_add(chain, 600, 100); + chain_add(chain, 800, 100); + chain_add(chain, 250, 149); + chain_add(chain, 1100, 100); + chain_add(chain, 1000, 100); + chain_add(chain, 1201, 100); + chain_add(chain, 1300, 100); + chain_add(chain, 1, 1); + chain_add(chain, 3, 2); + chain_add(chain, 0, 2000); + + acl_chain_free(chain); + + getchar(); + return 0; +} diff --git a/samples/chunk_chain.cpp/chunk_chain.cpp_vc2003.vcproj b/samples/chunk_chain.cpp/chunk_chain.cpp_vc2003.vcproj new file mode 100644 index 000000000..57d84687a --- /dev/null +++ b/samples/chunk_chain.cpp/chunk_chain.cpp_vc2003.vcproj @@ -0,0 +1,269 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/chunk_chain.cpp/chunk_chain.cpp_vc2008.vcproj b/samples/chunk_chain.cpp/chunk_chain.cpp_vc2008.vcproj new file mode 100644 index 000000000..64a70a3b8 --- /dev/null +++ b/samples/chunk_chain.cpp/chunk_chain.cpp_vc2008.vcproj @@ -0,0 +1,232 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/chunk_chain.cpp/stdafx.cpp b/samples/chunk_chain.cpp/stdafx.cpp new file mode 100644 index 000000000..29d7e091d --- /dev/null +++ b/samples/chunk_chain.cpp/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// chunk_chain.cpp.pch 将成为预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + +// TODO: 在 STDAFX.H 中 +//引用任何所需的附加头文件,而不是在此文件中引用 diff --git a/samples/chunk_chain.cpp/stdafx.h b/samples/chunk_chain.cpp/stdafx.h new file mode 100644 index 000000000..ff452917c --- /dev/null +++ b/samples/chunk_chain.cpp/stdafx.h @@ -0,0 +1,11 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是常用但不常更改的项目特定的包含文件 +// + +#pragma once + + +#include +#include + +// TODO: 在此处引用程序要求的附加头文件 diff --git a/samples/code/Makefile b/samples/code/Makefile new file mode 100644 index 000000000..43925601d --- /dev/null +++ b/samples/code/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = code diff --git a/samples/code/main.c b/samples/code/main.c new file mode 100644 index 000000000..0d3f46e7e --- /dev/null +++ b/samples/code/main.c @@ -0,0 +1,229 @@ +#include "lib_acl.h" + +static struct { + unsigned short id; + char *entity; +} html_charset[] = { + { 32, " " }, { 34, """ }, { 34, """ }, { 38, "&" }, + { 38, "&" }, { 39, "'" }, { 60, "<" }, { 60, "<" }, + { 62, ">" }, { 62, ">" }, { 160, " " }, { 161, "¡" }, + { 162, "¢" }, { 163, "£" }, { 164, "¤" }, { 165, "¥" }, + { 166, "¦" }, { 167, "§" }, { 168, "¨" }, { 169, "©" }, + { 170, "ª" }, { 171, "«" }, { 172, "¬" }, { 173, "­" }, + { 174, "®" }, { 175, "¯" }, { 176, "°" }, { 177, "±" }, + { 178, "²" }, { 179, "³" }, { 180, "´" }, { 181, "µ" }, + { 182, "¶" }, { 183, "·" }, { 184, "¸" }, { 185, "¹" }, + { 186, "º" }, { 187, "»" }, { 188, "¼" }, { 189, "½" }, + { 190, "¾" }, { 191, "¿" }, { 192, "À" }, { 193, "Á" }, + { 194, "Â" }, { 195, "Ã" }, { 196, "Ä" }, { 197, "Å" }, + { 198, "Æ" }, { 199, "Ç" }, { 200, "È" }, { 201, "É" }, + { 202, "Ê" }, { 203, "Ë" }, { 204, "Ì" }, { 205, "Í" }, + { 206, "Î" }, { 207, "Ï" }, { 208, "Ð" }, { 209, "Ñ" }, + { 210, "Ò" }, { 211, "Ó" }, { 212, "Ô" }, { 213, "Õ" }, + { 214, "Ö" }, { 215, "×" }, { 216, "Ø" }, { 217, "Ù" }, + { 218, "Ú" }, { 219, "Û" }, { 220, "Ü" }, { 221, "Ý" }, + { 222, "Þ" }, { 223, "ß" }, { 224, "à" }, { 225, "á" }, + { 226, "â" }, { 227, "ã" }, { 228, "ä" }, { 229, "å" }, + { 230, "æ" }, { 231, "ç" }, { 232, "è" }, { 233, "é" }, + { 234, "ê" }, { 235, "ë" }, { 236, "ì" }, { 237, "í" }, + { 238, "î" }, { 239, "ï" }, { 240, "ð" }, { 241, "ñ" }, + { 242, "ò" }, { 243, "ó" }, { 244, "ô" }, { 245, "õ" }, + { 246, "ö" }, { 247, "÷" }, { 248, "ø" }, { 249, "ù" }, + { 250, "ú" }, { 251, "û" }, { 252, "ü" }, { 253, "ý" }, + { 254, "þ" }, { 255, "ÿ" }, { 338, "Œ" }, { 339, "œ" }, + { 352, "Š" }, { 353, "š" }, { 376, "Ÿ" }, { 402, "ƒ" }, + { 710, "ˆ" }, { 732, "˜" }, { 913, "Α" }, { 914, "Β" }, + { 915, "Γ" }, { 916, "Δ" }, { 917, "Ε" }, { 918, "Ζ" }, + { 919, "Η" }, { 920, "Θ" }, { 921, "Ι" }, { 922, "Κ" }, + { 923, "Λ" }, { 924, "Μ" }, { 925, "Ν" }, { 926, "Ξ" }, + { 927, "Ο" }, { 928, "Π" }, { 929, "Ρ" }, { 931, "Σ" }, + { 932, "Τ" }, { 933, "Υ" }, { 934, "Φ" }, { 935, "Χ" }, + { 936, "Ψ" }, { 937, "Ω" }, { 945, "α" }, { 946, "β" }, + { 947, "γ" }, { 948, "δ" }, { 949, "ε" }, { 950, "ζ" }, + { 951, "η" }, { 952, "θ" }, { 953, "ι" }, { 954, "κ" }, + { 955, "λ" }, { 956, "μ" }, { 957, "ν" }, { 958, "ξ" }, + { 959, "ο" }, { 960, "π" }, { 961, "ρ" }, { 962, "ς" }, + { 963, "σ" }, { 964, "τ" }, { 965, "υ" }, { 966, "φ" }, + { 967, "χ" }, { 968, "ψ" }, { 969, "ω" }, { 977, "&thetasym" }, + { 978, "ϒ" }, { 982, "ϖ" }, {8194, " " }, {8195, " " }, + { 8201, " " }, {8204, "‌" }, {8205, "‍" }, {8206, "‎" }, + { 8207, "‏" }, {8211, "–" }, {8212, "—" }, {8216, "‘" }, + { 8217, "’" }, {8218, "‚" }, {8220, "“" }, {8221, "”" }, + { 8222, "„" }, {8224, "†" }, {8225, "‡" }, {8226, "•" }, + { 8230, "…" }, {8240, "‰" }, {8242, "′" }, {8243, "″" }, + { 8249, "‹" }, {8250, "›" }, {8254, "‾" }, {8260, "⁄" }, + { 8364, "€" }, {8465, "ℑ" }, {8472, "℘" }, {8476, "ℜ" }, + { 8482, "™" }, {8501, "ℵ" }, {8592, "←" }, {8593, "↑" }, + { 8594, "→" }, {8595, "↓" }, {8596, "↔" }, {8629, "↵" }, + { 8656, "⇐" }, {8657, "⇑" }, {8658, "⇒" }, {8659, "⇓" }, + { 8660, "⇔" }, {8704, "∀" }, {8706, "∂" }, {8707, "∃" }, + { 8709, "∅" }, {8711, "∇" }, {8712, "∈" }, {8713, "∉" }, + { 8715, "∋" }, {8719, "∏" }, {8721, "∑" }, {8722, "−" }, + { 8727, "∗" }, {8730, "√" }, {8733, "∝" }, {8734, "∞" }, + { 8736, "∠" }, {8743, "∧" }, {8744, "∨" }, {8745, "∩" }, + { 8746, "∪" }, {8747, "∫" }, {8756, "∴" }, {8764, "∼" }, + { 8773, "≅" }, {8776, "≈" }, {8800, "≠" }, {8801, "≡" }, + { 8804, "≤" }, {8805, "≥" }, {8834, "⊂" }, {8835, "⊃" }, + { 8836, "⊄" }, {8838, "⊆" }, {8839, "⊇" }, {8853, "⊕" }, + { 8855, "⊗" }, {8869, "⊥" }, {8901, "⋅" }, {8968, "⌈" }, + { 8969, "⌉" }, {8970, "⌊" }, {8971, "⌋" }, {9001, "⟨" }, + { 9002, "⟩" }, {9674, "◊" }, {9824, "♠" }, {9827, "♣" }, + { 9829, "♥" }, {9830, "♦" } +}; + +static void test_map2(void) +{ + unsigned int i, n; + unsigned short k; + unsigned char h, l; + + n = sizeof(html_charset) / sizeof(html_charset[0]); + + for (i = 0; i < n; i++) { + k = html_charset[i].id; + h = (unsigned char) (k >> 8); + l = (unsigned char) (k & 0xFF) ; + if (k > 255 && (h == 0 || l == 0)) + printf("id: %d = 0\n", html_charset[i].id); + } +} + +static void create_map2(void) +{ + unsigned int i, j, n; + + n = sizeof(html_charset) / sizeof(html_charset[0]); + + for (i = 0; i < n; i++) { + const char *ptr = html_charset[i].entity; + if (ptr == NULL) + continue; + for (j = 0; j < i; j++) { + if (html_charset[j].entity == NULL) + continue; + if (strcmp(ptr, html_charset[j].entity) == 0) { + html_charset[j].entity = NULL; + break; + } + } + } + + printf("#ifndef __HTML_CHARSET_INCLUDE_H__\n"); + printf("#define __HTML_CHARSET_INCLUDE_H__\n"); + printf("\n"); + + printf("static const char *html_charmap[] = {\n"); + for (i = 0; i < 65535; i++) { + if (i > 0) { + if (i % 8 == 0) + printf(",\n\t"); + else + printf(", "); + } else + printf("\t"); + for (j = 0; j < n; j++) { + if (html_charset[j].entity && html_charset[j].id == i) + break; + } + if (j < n) + printf("\"%s\"", html_charset[j].entity); + else + printf("NULL"); + } + printf("\n};\n"); + + printf("\ntypedef struct {\n" + "\tunsigned short ch;\n" + "\tconst char *txt;\n" + "\tsize_t len;\n" + "} HTML_SPEC;\n" + "\n" + "static const HTML_SPEC html_tab[] = {\n" + ); + for (i = 0; i < n; i++) { + if (html_charset[i].entity == NULL) + continue; + printf("\t{ %u, \"%s\", sizeof(\"%s\") - 1 },\n", + html_charset[i].id, html_charset[i].entity, html_charset[i].entity); + } + printf("};\n\n"); + printf("#endif\n"); +} + +/*----------------------------------------------------------------------------*/ + +typedef struct HTML_SPEC_TBL +{ + const char ch; + const char *txt; +} HTML_SPEC_TBL; + +static const HTML_SPEC_TBL __tab[] = { + { '<', "<" }, + { '>', ">" }, + { '&', "&" }, + { '\'', "'" }, + { '\"', """ }, + { 0, 0 } +}; + +static void create_map1(void) +{ + int i, j; + + for (i = 0; i < 255; i++) { + if (i > 0) { + if (i % 8 == 0) + printf(",\r\n"); + else + printf(", "); + } + for (j = 0; __tab[j].ch; j++) { + if (__tab[j].ch == i) + break; + } + if (__tab[j].ch) + printf("\"%s\"", __tab[j].txt); + else + printf("NULL"); + } + printf("\r\n"); +} + +int main(void) +{ + const char *src = "%E4%B8%AD%E5%9B%BD%0A%E4%B8%AD%E5%9B%BD%0A%E4%B8%AD%E5%9B%BD"; +/* + char buf[256], *dst; +*/ + char *dst; + + if (0) { + create_map1(); + return (0); + } else if (1) { + create_map2(); + return (0); + } else if (2) { + test_map2(); + return (0); + } + + printf("src(%s)\n", src); + dst = acl_url_decode(src); + printf("dst(%s)\n", dst); + +/* + if (acl_utf8_to_gb2312(dst, strlen(dst), buf, sizeof(buf)) > 0) + printf("ok, buf(%s)\n", buf); + else + printf("error\n"); + + src = "涓浗"; + if (acl_utf8_to_gb2312(src, strlen(src), buf, sizeof(buf)) > 0) + printf("ok, buf(%s)\n", buf); + else + printf("error\n"); +*/ + return (0); +} diff --git a/samples/code_map/code_map.vcproj b/samples/code_map/code_map.vcproj new file mode 100644 index 000000000..52e3668c3 --- /dev/null +++ b/samples/code_map/code_map.vcproj @@ -0,0 +1,234 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/code_map/code_map.vcxproj b/samples/code_map/code_map.vcxproj new file mode 100644 index 000000000..c012875f0 --- /dev/null +++ b/samples/code_map/code_map.vcxproj @@ -0,0 +1,181 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + ReleaseDll + Win32 + + + Release + Win32 + + + + {A188A73A-4014-442F-8188-58CA59232CA8} + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\lib_acl\include; .\;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)code_map.exe + true + $(OutDir)code_map.pdb + Console + MachineX86 + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;%(AdditionalDependencies) + $(OutDir)code_map.exe + true + Console + true + true + MachineX86 + + + + + Disabled + ..\..\lib_acl\include; .\;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + EditAndContinue + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)code_map.exe + true + $(OutDir)code_map.pdb + Console + MachineX86 + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;%(AdditionalDependencies) + $(OutDir)code_map.exe + true + Console + true + true + MachineX86 + + + + + {b40213c2-507c-4c7f-a6e1-b850c9bdc27b} + false + + + + + + + + + \ No newline at end of file diff --git a/samples/code_map/code_map.vcxproj.filters b/samples/code_map/code_map.vcxproj.filters new file mode 100644 index 000000000..f84bd00e6 --- /dev/null +++ b/samples/code_map/code_map.vcxproj.filters @@ -0,0 +1,22 @@ +锘 + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx + + + + + 婧愭枃浠 + + + \ No newline at end of file diff --git a/samples/code_map/main.cpp b/samples/code_map/main.cpp new file mode 100644 index 000000000..d78b47f2f --- /dev/null +++ b/samples/code_map/main.cpp @@ -0,0 +1,298 @@ +#include "lib_acl.h" + +#ifdef WIN32 +#define snprintf _snprintf +#endif + +#define TOTAL_CHAR 2359 +#define TOTAL_CHAR_BUF 4724 + +static char __szJJ[TOTAL_CHAR_BUF]= +"场础贰尽馈谩拧伞獭选摇铡帧荨纭椤辍怼铩颉鳌并尝储发饥舰劲垄泞挞癣尧闸症注撷恽纰辎铫颌鳍担罚迹剑荆溃拢" +"牵龋遥樱郑郏荩撸澹妫纾辏欤铮穑颍觯鳎长钉护饯沥陇扦胜韦绚窑婴预栅证驻荬猡浃绀椁辘铯颏鳏饱偿触单顶讥渐" +"茎骏隶楼钮钎丧圣违啸谣鹰讠荪撺幞悭浈绁辚铳颔籁鳐宝拨肠处郸沪鸡溅娄纽铅师应驭讦郐荭擀绂铴颚酽靓鳓钵厂" +"掸锭阀抚骇户涧搂脓颧骚帅抬围学缨鸳讧郄荮绉戋毵铵颛酾鳔皑报胆辅龚绩鲸篓猫浓迁权扫狮台莹渊专亘讪猕绋瑷" +"戗悫铷瘿颞雳鳕畅订珐哗缉扩俩农签药萤诈砖讴郓姗绌飑铹颟鳗蔼丢华惊开联锚湿为营转讵郦莳绐氇飒愍铼颡鳘鲍" +"传东韩极将阔莲芦谦诗双潍蝎勋荧斋讷莴岖惬浍娅绔飓铽瘾颢霁鳙铂惮宫浆连卢涩尸态维蝇赚诂娆绗璎飕铿颥鳜碍" +"画辑经凯镰颅铆骗谁铜苇协侪诃蕲岘绛榄飙锃颦鳝爱钞诞巩划庐飘钱袭挟赢债桩诋岙娈绠飚锂癞鳟疮弹动矾蒋蜡怜" +"炉钳摊携询爷辕织庄侬诏莜浏绡戬懑锆鸠舣鳢栋钒话桨腊涟掳劝税贪伟习寻园职装诎莅岚浒灏绨戆锇鸢霭当贡奖颈" +"帘卤谋疟潜杀时瘫伪驯颖员毡妆俦诒弑浔绫瓯毂锉鸨虮辈挡讲静敛虏刹滩胁圆俨诓莶绮氩锊鸩癫虿鞑闯党冻烦赋钩" +"怀莱脸鲁贸浅顺坛统纬铣谐页壮俪诔愠绯锍鸪癯龀鞒贝创荡复酱来链么谴却纱蚀写哟执状诖薮叽岽愦娲绱榇齑泶畲" +"锎鸫龃钡驳车档沟坏镜赖恋诺频堑鹊实说训业拥缘盏诘莸涞娴绲榈氲斓淼锏鸬舻龅鞯范苟欢级径蓝炼亩贫识硕讯叶" +"佣远斩锥俣诙喽愣涠缍瓒矶锒鸲龆狈卜捣斗贩环挤痉练欧确谭头戏逊辗诜喾绶榉锓鸱龇备锤几栏粮赂鸥筛烁谈细痈" +"愿崭赘诟吒甯绺韪砀锔鸶龈肮惫补彻饭构还拦凉霉殴枪晒喂压坠诠骞绻韫牍锕鸸蚬龉鞴岛负购汉缓胶竞篮呛秃虾泻" +"缀睾诤莺藓绾韬砗锖鸷蚝鹾龊祷够换蓟净阑禄没呕苹驶谢鸦踊栈谆诨刍莼藁峄缁锘鸹趸龌导讣兰录图鸭约准诩奂芗" +"呒饧缂昙罴锛鸺窦黾唤浇澜两陆沤墙谓辖医咏战纸诮劢呓峤饨缃锝鸾鼋鹘尘妇痪骄谰辆镁凭蔷删叹跃志诰饩缇炀锞" +"鹁鼍翱纯犊缚娇揽驴强丝涂峡锌铱涌钥挚诳芸呖嗫峥饪婵缈杩炜砜羁锟鹂罂袄独焕纠览吕评抢汤卫侠岳绽掷诶崂饫" +"憷缋枥槔炖锢鹄窭绷沉盗读涣剂搅懒铝闪狭粤诹蘖崃饬懔媪缌炝锪鹆袅隽奥陈绰铰缆谅侣锹陕温芈诼勐苈呗饴渎缏" +"砺锫鹇访该济矫烂泼让厦颐悦诿呙饷缑砻锩鹈蛎髅衬赌纺侥滥颇饶赡阅帜啬谀吣饽缒槟锬鹉跄撑号脚颗琅屡门呐桥" +"扰团闻吓遗优张着谂馀闩渑缗枧钆锱鹋雠髋财称灯镀钙蛊黄计疗缕闷钠绕势纹衅哑云谄奁馄闫缙槠钇锲鹌笃髌辞盖" +"记厩壳虑们乔饲颓锨亚仪忧郧涨浊厍偾谇咔馇闱迩缜枨烨钋锴鹎羟銮饺侨热稳讶匀兹谌苋嗳馊闳嫒缛枞钊锶鹑笕跞" +"飞干缴旧辽纳缮蜕陨厣谏苌嵘馍闵渖迳嫔缟枭樯肷钌锷鹕裆蛏錾笔词际绞墒适耸问鲜邮帐质资谑凼苁馐闶缡晔胧钍" +"锸鹗魇邓杆顾滤扑伤怂纤兴阉铀运账厮谒馑闼渌缢胨焖钏锼鹚魉诽继捞绿锰盘铺翘颂烫咸烟犹蕴靥偬谔咛馓闾缣硖" +"钐锾鹛蛱籼惩赐锻纪劳镣峦韧赏释瓮贤彝酝胀滞赝偻谕馔阃嫱缤橥晖胪硗钔锿鹜裢蛲参轿课挛梦饰涛挝衔盐游晕傥" +"谖辔嵛馕阄逦缥栉煳钗镂鹞跷毕蚕诚聪断废赶较孪窍认讼蜗严蚁韵傧谙巯尴阆缦钕锵鹣裣蛳粝跸鱿飨毙残葱敌缎剐" +"夹滦眯诵绦涡闲匦傩谛苄咝嵝庑阈缧栊钚镄鹦裥粜鲂餍惭囱费秆谎垦难脱窝匮谘垩苎扪阊缪煅钛镅鹧跹鲅币惨骋兑" +"挂阂恳乱纫鸵岩谝抟阋缫钜镆鹨跻鲆坝灿从涤队赣挥挠庞朴视擞杂钟赜谟萦嘤阌溆缬栌暧碛钣镉鹩蛴鲇苍丛对冈辉" +"荚驹涝猎脑窃试驮卧显赵谠菰咴阍缭钤镌鹪鲈罢闭舱痴凑刚颊秸抡谜恼钦烧苏驼险颜艺诱终渍谡哒嵴阏缯钫镎鹫稣" +"仓吨钢贾乐轮弥闹讨椭现阎灾种谥阒嬷缰橹胫熘钪镏鹬笾糁鲋沧纷鹤阶伦抛谱亲献凶肿谧茏阕缱碜钭镒鹱鲎坟关贺" +"钾镭仑呜县载谪挢哓阖缲钬镓鹭鲐迟顿纲毁举抠临沦觅馁荣寿钨踪刭谫哔噘赓阗滟缳栀钯镔鹳筚踬鲑摆蹿岗节邻纶" +"内腾乌馅汹亿于众谮阙缵橼贲脍钰镖褛鲒驰钝观价鳞论污羡综刿谯圹蒇巅阚贳钲镗鲔败耻窜奋杰萝栖绍誊诬宪攒总" +"剀谲苘哕丬滠贶钴镘疖褴踯鲕齿递馆驾据垒凛幂洼暂蛰纵佥谳彷栎檩贻钶镙疠筝鲚厕缔皋赁罗寝绒赊兽无艳赞辙邹" +"谵坜蒉廪滢贽磙钷镛鲛鬓边颠愤惯贿歼逻诉芜线舆赃诌谶柽赀钸镞疬襁鲞编侧粪秽监洁类锣绵凄枢肃锑袜脏锗坂茑" +"哙噜驵赅钹镟鲟贬册夺丰贯横会坚结泪箩轻厢厌轴籴卺驷玑赆脶钺镝鲠麽测烩锯库骡拟赔氢题吴镶锈砚这垅掴哜徕" +"驸玮桠殁赈焘钼镡疴鲡层炽点枫广汇笺裤倾摄鱼茔忏沣溷驺桡赉钽镢鲢颁变镐轰讳间夸龄输虽弯忆凿黉垆茕蒌怃滗" +"驿殇赇钿镤皲鲣冲冲诲惧铃缅腻慑体湾绣彦义皱驽珏桢赍铄镥疱蝈箦鲥虫垫锋规绘骆随渔枣冁哝怄骀殒赕铈镦箧蹑" +"鲦辩电风荤剧络喷绥顽乡昼诅骁珑桤殓赙铉镧蹒鲧辫宠疯硅鸿艰凌妈设谚诣骤掼噼徼骅觇龛铊镨鲨堕搁归鹃块篱灵" +"书虚验议娱组荛唛忾骈殚觊铋镩痖蹰鲩标龟缄狸玛脐顷赎岁详嘘谊贞钻陉荜揸怅骊觋铌镪箨絷鲫畴冯鸽闺浑茧诫侩" +"离岭码齐请屉坞须译与针垭蓦唠嚯怆潆骐珉桦殡觌铍镫鲭办踌鹅缝轨红检届领蚂撵庆响鸯异屿侦凫揿潇骒觎铎镬痨" +"耢箪鲮绊错淀讽宽马庙捻琼软雾许猪陧沩漤骓桧轫觏铐镯鲰鳖额诡碱绢骂穷项杨灶诸垲犷骖轭觐眍铑镱蝾鲱帮诧筹" +"达讹凤伙硷里骑孙扬绎语诊诛唢犸骘顼栾轱觑腼铒镲痫耧箫麸躏鲲别拣鲤吗灭酿绅损叙责兖垧囵屦骛桊轲腽铕镳麴" +"鲳瘪绸恶柜获捡礼鸟岂锐笋务疡荫择伛垴荞蓠泷骜桉轳铖锺篑鲴凋简买闰万则镇烛衮泸潋弪骝轵祢铗躜鲵黩绑搀丑" +"阁贵后俭矿馏麦润审误泽阵摅狍潴骟轶铙鲶濒掺肤刽紧卖聂鹏启婶属萧阳贼亵骠玺轸铘鲷滨蝉铬辊货减锦觉旷刘迈" +"悯术缩条阴吁挣瞩脔埘啧骢珲轷祯铛趱鲺黪宾馋钓饿个滚祸荐仅决况丽脉闽啮肾琐睁嘱伥埚荟蓥狯骣琏轹眦铞鲻镑" +"摈谗橱调击槛谨诀亏厉瞒镊趋洒树绪痒伧禀邝埙蓣骥轺膑铟瘅聍蝼鲼缠厨带辐给锅壶鉴进绝励馒镍气区萨渗锁网续" +"养银狰帏狲怿泺骧轼禅铠鲽谤铲儿践岿砾蛮鸣声贴嚣轩样御赠争伫邬荠啭纟棂轾睐铢稆瘗聩鳄产锄国机贱晋窥历龙" +"满铭弃鳃竖铁销扎恸纡辁睑铤鳅鼹阐雏贷尔见钧聋柠躯饮埯恹纣辂铥鳆颤迭饵键军咙狞赛厅悬狱贮蔹撄帱恻妩纥椟" +"辄睃铧瘘顸觞鳇饼谍过积烬笼谬讫驱数听锡札铸荦帻猃恺妪纨椠辇铨颀螨簖鳊剥叠宁绳烃牺晓瑶隐誉轧筑邺埝荥蔺" +"帼泾濑纩辋铪颃鳋齄\0\0"; + +static char __szJF[TOTAL_CHAR_BUF]= +"場礎貳盡饋謾擰傘獺選搖鍘幀蕁紜欏輟懟鎩頡鰲並嘗儲發饑艦勁壟濘撻癬堯閘癥註擷惲紕輜銚頜鰭擔罰跡劍荊潰攏" +"牽齲遙櫻鄭郟藎擼淡媯紓輳歟錚穡潁觶鰨長釘護餞瀝隴扡勝韋絢窯嬰預柵證駐蕒玀浹紺槨轆銫頦鰥飽償觸單頂譏漸" +"莖駿隸樓鈕釬喪聖違嘯謠鷹訁蓀攛襆慳湞紲轔銃頷籟鰩寶撥腸處鄲滬雞濺婁紐鉛師應馭訐鄶葒搟紱鐋顎釅靚鰳缽廠" +"撣錠閥撫駭戶澗摟膿顴騷帥擡圍學纓鴛訌郤葤縐戔毿銨顓釃鰾皚報膽輔龔績鯨簍貓濃遷權掃獅臺瑩淵專亙訕獼紼璦" +"戧愨銣癭顳靂鱈暢訂琺嘩緝擴倆農簽藥螢詐磚謳鄆姍絀颮鐒顢鰻藹丟華驚開聯錨濕為營轉詎酈蒔紿氌颯湣錸顙鰵鮑" +"傳東韓極將闊蓮蘆謙詩雙濰蠍勛熒齋訥萵嶇愜澮婭絝颶鋱癮顥霽鱅鉑憚宮漿連盧澀屍態維蠅賺詁嬈絎瓔颼鏗顬鱖礙" +"畫輯經凱鐮顱鉚騙誰銅葦協儕訶蘄峴絳欖飆鋥顰鱔愛鈔誕鞏劃廬飄錢襲挾贏債樁詆嶴孌綆飈鋰癩鱒瘡彈動礬蔣蠟憐" +"爐鉗攤攜詢爺轅織莊儂詔蓧瀏綃戩懣鋯鳩艤鱧棟釩話槳臘漣擄勸稅貪偉習尋園職裝詘蒞嵐滸灝綈戇鋨鳶靄當貢獎頸" +"簾鹵謀瘧潛殺時癱偽馴穎員氈妝儔詒弒潯綾甌轂銼鴇蟣輩擋講靜斂虜剎灘脅圓儼誆薟綺氬鋝鴆癲蠆韃闖黨凍煩賦鉤" +"懷萊臉魯貿淺順壇統緯銑諧頁壯儷誄慍緋鋶鴣臒齔鞽貝創蕩復醬來鏈麽譴卻紗蝕寫喲執狀詿藪嘰崠憒媧緔櫬齏澩畬" +"鐦鶇齟鋇駁車檔溝壞鏡賴戀諾頻塹鵲實說訓業擁緣盞詰蕕淶嫻緄櫚氳斕渺鐧鸕艫齙韉範茍歡級徑藍煉畝貧識碩訊葉" +"傭遠斬錐俁詼嘍楞潿綞瓚磯鋃鴝齠狽蔔搗鬥販環擠痙練歐確譚頭戲遜輾詵嚳綬櫸鋟鴟齜備錘幾欄糧賂鷗篩爍談細癰" +"願嶄贅詬咤寧綹韙碭鋦鷥齦骯憊補徹飯構還攔涼黴毆槍曬餵壓墜詮騫綣韞牘錒鴯蜆齬韝島負購漢緩膠競籃嗆禿蝦瀉" +"綴睪諍鶯蘚綰韜硨錆鷙蠔鹺齪禱夠換薊凈闌祿沒嘔蘋駛謝鴉踴棧諄諢芻蒓槁嶧緇鍩鴰躉齷導訃蘭錄圖鴨約準詡奐薌" +"嘸餳緙曇羆錛鵂竇黽喚澆瀾兩陸漚墻謂轄醫詠戰紙誚勱囈嶠飩緗鍀鸞黿鶻塵婦瘓驕讕輛鎂憑薔刪嘆躍誌誥餼緹煬錁" +"鵓鼉翺純犢縛嬌攬驢強絲塗峽鋅銥湧鑰摯誑蕓嚦囁崢飪嬋緲榪煒碸羈錕鸝罌襖獨煥糾覽呂評搶湯衛俠嶽綻擲誒嶗飫" +"怵繢櫪橰燉錮鵠窶繃沈盜讀渙劑攪懶鋁閃狹粵諏蘗崍飭懍媼緦熗鍃鵒裊雋奧陳綽鉸纜諒侶鍬陜溫羋諑猛藶唄飴瀆緶" +"礪錇鷴訪該濟矯爛潑讓廈頤悅諉咼餉緱礱錈鵜蠣髏襯賭紡僥濫頗饒贍閱幟嗇諛唚餑縋檳錟鵡蹌撐號腳顆瑯屢門吶橋" +"擾團聞嚇遺優張著諗餘閂澠緡梘釓錙鶓讎髖財稱燈鍍鈣蠱黃計療縷悶鈉繞勢紋釁啞雲諂奩餛閆縉櫧釔鍥鵪篤髕辭蓋" +"記廄殼慮們喬飼頹鍁亞儀憂鄖漲濁厙僨誶哢餷闈邇縝棖燁釙鍇鵯羥鑾餃僑熱穩訝勻茲諶莧噯餿閎嬡縟樅釗鍶鶉筧躒" +"飛幹繳舊遼納繕蛻隕厴諫萇嶸饃閔瀋逕嬪縞梟檣膁釕鍔鶘襠蟶鏨筆詞際絞墑適聳問鮮郵帳質資謔氹蓯饈閌縭曄朧釷" +"鍤鶚魘鄧桿顧濾撲傷慫纖興閹鈾運賬廝謁饉闥淥縊腖燜釧鎪鶿魎誹繼撈綠錳盤鋪翹頌燙鹹煙猶蘊靨傯諤嚀饊閭縑硤" +"釤鍰鶥蛺秈懲賜鍛紀勞鐐巒韌賞釋甕賢彜醞脹滯贗僂諭饌閫嬙繽櫫暉臚磽鍆鎄鶩褳蟯參轎課攣夢飾濤撾銜鹽遊暈儻" +"諼轡崳饢鬮邐縹櫛糊釵鏤鷂蹺畢蠶誠聰斷廢趕較孿竅認訟蝸嚴蟻韻儐諳巰尷閬縵釹鏘鶼襝螄糲蹕魷饗斃殘蔥敵緞剮" +"夾灤瞇誦絳渦閑匭儺諦芐噝嶁廡閾縲櫳鈈鐨鸚襇糶魴饜慚囪費稈謊墾難脫窩匱諮堊苧捫閶繆煆鈦鎇鷓躚鮁幣慘騁兌" +"掛閡懇亂紉鴕巖諞摶鬩繅鉅鏌鷚躋鮃壩燦從滌隊贛揮撓龐樸視擻雜鐘賾謨縈嚶閿漵纈櫨曖磧鈑鎘鷯蠐鮎蒼叢對岡輝" +"莢駒澇獵腦竊試馱臥顯趙讜菇噅閽繚鈐鐫鷦鱸罷閉艙癡湊剛頰稭掄謎惱欽燒蘇駝險顏藝誘終漬謖噠脊閼繒鈁鎿鷲穌" +"倉噸鋼賈樂輪彌鬧討橢現閻災種謚闃嬤韁櫓脛溜鈧鎦鷸籩糝鮒滄紛鶴階倫拋譜親獻兇腫謐蘢闋繾磣鈄鎰鸌鱟墳關賀" +"鉀鐳侖嗚縣載謫撟嘵闔繰鈥鎵鷺鮐遲頓綱毀舉摳臨淪覓餒榮壽鎢蹤剄譾嗶撅賡闐灩繯梔鈀鑌鸛篳躓鮭擺躥崗節鄰綸" +"內騰烏餡洶億於眾譖闕纘櫞賁膾鈺鏢褸鮚馳鈍觀價鱗論汙羨綜劌譙壙蕆巔闞貰鉦鏜鮪敗恥竄奮傑蘿棲紹謄誣憲攢總" +"剴譎檾噦爿灄貺鈷鏝癤襤躑鮞齒遞館駕據壘凜冪窪暫蟄縱僉讞仿櫟檁貽鈳鏍癘箏鱭廁締臯賃羅寢絨賒獸無艷贊轍鄒" +"譫壢蕢廩瀅贄滾鉕鏞鮫鬢邊顛憤慣賄殲邏訴蕪線輿贓謅讖檉貲鈽鏃癧繈鯗編側糞穢監潔類鑼綿淒樞肅銻襪臟鍺阪蔦" +"噲嚕駔賅鈸鏇鱘貶冊奪豐貫橫會堅結淚籮輕廂厭軸糴巹駟璣贐腡鉞鏑鯁麼測燴鋸庫騾擬賠氫題吳鑲銹硯這壟摑嚌徠" +"駙瑋椏歿賑燾鉬鐔屙鱺層熾點楓廣匯箋褲傾攝魚塋懺灃混騶橈賚鉭鐝鰱頒變鎬轟諱間誇齡輸雖彎憶鑿黌壚煢蔞憮潷" +"驛殤賕鈿鏷皸鰹沖衝誨懼鈴緬膩懾體灣繡彥義皺駑玨楨賫鑠鑥皰蟈簀鰣蟲墊鋒規繪駱隨漁棗囅噥慪駘殞賧鈰鐓篋躡" +"鰷辯電風葷劇絡噴綏頑鄉晝詛驍瓏榿殮賻鉉鑭蹣鯀辮寵瘋矽鴻艱淩媽設諺詣驟摜劈僥驊覘龕鉈鐠鯊墮擱歸鵑塊籬靈" +"書虛驗議娛組蕘嘜愾駢殫覬鉍鑹瘂躕鯇標龜緘貍瑪臍頃贖歲詳噓誼貞鉆陘蓽摣悵驪覡鈮鏹籜縶鯽疇馮鴿閨渾繭誡儈" +"離嶺碼齊請屜塢須譯與針埡驀嘮謔愴瀠騏瑉樺殯覿鈹鐙鯖辦躊鵝縫軌紅檢屆領螞攆慶響鴦異嶼偵鳧撳瀟騍覦鐸鑊癆" +"耮簞鯪絆錯澱諷寬馬廟撚瓊軟霧許豬隉溈濫騅檜軔覯銬鐲鯫鱉額詭堿絹罵窮項楊竈諸塏獷驂軛覲瞘銠鐿蠑鯡幫詫籌" +"達訛鳳夥鹼裏騎孫揚繹語診誅嗩獁騭頊欒軲覷靦鉺鑔癇耬簫麩躪鯤別揀鯉嗎滅釀紳損敘責兗坰圇屨騖棬軻膃銪鑣麯" +"鯧癟綢惡櫃獲撿禮鳥豈銳筍務瘍蔭擇傴堖蕎蘺瀧驁案轤鋮鍾簣鯝雕簡買閏萬則鎮燭袞瀘瀲弳騮軹禰鋏躦鯢黷綁攙醜" +"閣貴後儉礦餾麥潤審誤澤陣攄麅瀦騸軼鐃鯰瀕摻膚劊緊賣聶鵬啟嬸屬蕭陽賊褻驃璽軫鋣鯛濱蟬鉻輥貨減錦覺曠劉邁" +"憫術縮條陰籲掙矚臠塒嘖驄琿軤禎鐺趲鯴黲賓饞釣餓個滾禍薦僅決況麗脈閩嚙腎瑣睜囑倀堝薈鎣獪驏璉轢眥銱鯔鎊" +"擯讒櫥調擊檻謹訣虧厲瞞鑷趨灑樹緒癢傖稟鄺塤蕷驥軺臏銦癉聹螻鱝纏廚帶輻給鍋壺鑒進絕勵饅鎳氣區薩滲鎖網續" +"養銀猙幃猻懌濼驤軾禪鎧鰈謗鏟兒踐巋礫蠻鳴聲貼囂軒樣禦贈爭佇鄔薺囀糸欞輊睞銖穭瘞聵鱷產鋤國機賤晉窺歷龍" +"滿銘棄鰓豎鐵銷紮慟紆輇瞼鋌鰍鼴闡雛貸爾見鈞聾檸軀飲垵懨紂輅銩鰒顫叠餌鍵軍嚨獰賽廳懸獄貯蘞攖幬惻嫵紇櫝" +"輒脧鏵瘺頇觴鰉餅諜過積燼籠謬訖驅數聽錫劄鑄犖幘獫愷嫗紈槧輦銓頎蟎籪鯿剝疊寧繩烴犧曉瑤隱譽軋築鄴墊滎藺" +"幗涇瀨纊輞鉿頏鰠齇\0\0"; + +static char __szFJ[TOTAL_CHAR_BUF]= +"叹园污获篮绕聋蔼褛谔辕这钻铵锹阑颃显惊倾圆碱夹痨睐础禀舻华蔺讼贮赢辘钏铥阶预颦饷驿鲴厦态渗叠痫筑绍谛" +"贳赆连郦铊铕顽颅养鳔鸟鹛鼹凛愠机烫猎矫窝绀综绣肃荟亵诔谐证钒铉铯镝镯颁喽图妇娈挤凄瘅洼箧缋腊艰觎诛赀" +"转铐锾镭阗顿颞饵凫麴偻抬桢椭滥漤犷绋缍蓟诀诓贰赃迹跷陨颧骏骤鲅鲱团峄焖兽现穷胪夸贵轸钎锥铁雾鲵鸠鹜丢" +"浒睾窑绿艳荆芗讷谏铋饽骋鲆侣仅潍獭绐亲谲贬赎辙铞锕铿阖际颇馁驴鲲呕娅业泪滨营献琏盗筹绌绸肾蕲志谕讥买" +"赝轿键锵铎阙领饿鳙鹱呙奂钦猕绻芦觊认谘贷锐锶闯骧并啧块惨盏碍终绳脏苏铂锟铛骓骥鲳佥尝茔扦滚磙绘胨脔幞" +"访贶长风鲸鳕莺惭拟横满狭猡尽秸窭组萦蛊裥觏讳岂费赣轱进镗颌鳖垲厨烃灿狈种缙翘卜蔷蕴蝼诳贴销锤锗镘馀鲮" +"鹃麽唛孙极渌渔疠监绊缢茧翱苌莼苹设诶谙贻趸辚钗钷锱镛镱鲰鹆齄凯埘厮扬摈盘笔缒罚卧莳觐谮踌郏锈铮铲关骊" +"凤鹁匦恸换拧决称窥缳蚕诞竖贸跻钍钳锛馄鸣鹤俣汇庙搁槔凌溅卢御糁绶缲骂临莱谌识贺锑锺镜阚颉飑马鲇鸬齐侨" +"岙厂掷沦笋粪维苄许讽谯丰贲跃轴郄钕锉镖随飒驭骒鸢黄斋匮员涂庑惯泺烛瓯瘪硕罢脶诱诸谭赂轵铆铸门饯冯骑鲐" +"鲶咔废扩杆禅绾绉缴蛰蛮袅觑赁踯轺铅锬镂阐险颐骐鲍嵘广胧滤痴矿笃纲缣皋蒌诉诮谚谱贿跞轲锭镁闩霁鲋鳟哗奥" +"学欧痒绗网莅莶赅踬轶闪颏馅驮鬓鹦齑岭撷疖砀箨脑蝈觉诃谖蹰钺铝钱锿鞒鲺鳝鹘鹳齿奁怄渊瓮症礼筛结缀蒋蘖里" +"资轼錾闼驰斗鹈鹣唠夺屿怂涞烩砺窜粮语诺贾轰钯锒镬闫雳飓驯鳜鹅鹂黉龀啸岳廪摆疬眯砾祢窍籁绎肿葱览游钫镅" +"隐闹鳞鸾叽孪擞浅矾祷笼茑藓螨袄诊诚谋贼辔运锌锦镔霭缰骛鲟鹚坞庐虑挥撸没滢癞窦纶荐觌注诫谒跹轹邮闭陇阋" +"鹄区哓奋渎玑砜灶绝绺继观谓较过钭钩钡锚镑鞑头馆鲒鹉埙扰檩冲癣确绮缤罗脚台萨诬轳达开骗鹞龅呒瘿窃筚绽缚" +"缱罴蔹误誊践辂违钲闶隶灵飕悭沤泻烬瑷产瘾码砻笕荫补诰诌锡颊肮鲫鲼侠狰痈绰缜羁装诂诵蹑辁遥钚铤鉴闳阄鲕" +"龇庆渖焘瘫粝绫缟肠与刍裣赈钠闰鳊鲎鸩点厅摅栀痉癫秃稣绵缛芈肷兴茏裆诲谵赊载逊锢镲鞯鸨侥徼别欤积笾籴耧" +"腽举谎宾轾铗错闲龃偾协撵柽颖簖绔旧庄万说蹿递钼铧韦鸦龆枧欢浏眍粜绞耢蚀术诋译赇躜钝钽间韧驳鹌龄删呗岿" +"汉环篱县褴议远丑锋镤闵隽颔飘饧党涟籼绲缬谜猪郓锰锁颈鹏咴箦箩络荠酝钤镪颓飙喂珏绚纩谧躏办钣镉鳢条濒发" +"缁虮卫谁谴赉乡闸频飚馇鲽鹎龈尘宫珐瞒纠续兰袜辄适虽鳇峦忧拢枭档渍吁莴苍荨冲讵课赐钞铼靓韩鲔涣泸无纪给" +"紧茎谑嚯护辅辞钮静鲛鹊黪巅损减绯缝缠荪诈赏轻辫铄双鹧龊刭堑杩岁涨烁犹珲纣绒谡辩铰饩骞鲑鳅鲚霉价岩拦时" +"况沥缡苎蒇虾衬诒谇谤赔农雏鲜鸵龉却垧岘弑荣溆狲约缩蝉赓赶铒锊镳杂馏骘伥则撄潇炉玺篓红缨诏谦贤迟医铬铙" +"腼韪馊骝髅鸥黩嘘岛耻摇桧涡渐潆砖纡羟蛲袭评诽谥誉卖邹酱锓锝钨镥阂鸡魉卤惫捣搀历纥纵荚讲谫贱辆锨蓥靥驻" +"腾鳆鸷吣归犸穑纨绪缧纤羡肤盖荞赵辎迁邬阁韬颗飞驽体鳃鹨黾仪刹撺晋秽纫义虫觞诎谊谢读赋踊辉选钧铪锪离鞴" +"馍驹髌鸳鼋龋乱妆携测纹统绱缵蓠赕辋郧银铘镏阀难韫髋咸俩侬咝娲怜摄检潴狱珉丝缦胶觯辍遗锄铠馒驵鸲鹾峡凭" +"擀樯殁浆泷狮痖眦笺纳绛绦絷胁苋荬蓝诅调谣锃钔驾鳄亿垫埝愦东濑玮缃缕缆芸荩蛏触质躯辽铳锔锴铩铴镧闺驺魇" +"鲈鸱硷仓哒颍皑缄圣脉萝赍钙锼闽题馐骚盐龌侩碜筝纽缂缥叶莸词谄账迈铜锇额馑骀骟鱼鲡个俭巯攒烂亩睑稳线赌" +"还钬镐钥阃陉颚馓驸哝抛挛桤绢腻荛蜗蚁咏谆辊钛铺锅阆颜馈鸪刚哕妫悦摊琼疯竞纾总诩狸辇钪镇镣镶闾饨馔驶亘" +"们剥昼疡碛纯缉绩询谟变迩镀陕饪鸶狍鼍墒卺惮奖稆箪纰缎闻胫诣谈跄酿镒铹饫驼鸯鹪毕讠趋辈边衅铖镦云颛骡鲧" +"鳋鸫亚傧嗳弪浑简纱缔订诿谪轮锆镡阅饬驷鲠鸭厍搅潋珑缗绷荭艺蛳讣试谬雠赖车邓酾锂镍镊阵饥蓦鹑哙崃张揽残" +"痪硖篑纸苟请猫轧铽饭饶骜鲥龙俦弃槟矶级绑缘缫莜蒉蝇轨逻酽铌镓镩骈骖侪喷强泼众纷缪虿见诗诤军逦铣锷钟电" +"愿骠鳏坠媪寝构璎画纭绡襁计谗跸辑铈镫阊颡饮飨骢庞妈抢枪殒畲砗缌诧诹让释铨锣驱鲩吨实愤洁琐箫讯诟赚郑锍" +"韵颠饴鳎鸸鹩剐宁甯柠争瑶瘗砚绠编荡药处规诡诼讴谰赙趱轩钶铡銮阉阴鲤鳐鸹审岗煅疮纺缓钵睃莲芜讧诠谅谶购" +"辏邻钆铃铢锯镢凿鲨龚伦凑异税绨苁蛱蝎贝赛轫郸钇阎陈类餍鹫丽龛写悯槛殇澜瓒疟胆蜕讨诘贞赜钌铭锻阏陆响骅" +"鹋剀厌宽炼疱秆缅脍荮萧薮觅话邺钴镨阍馋鳍鹇创咛怃潜莹硗禄联脱脓舱虚蛴讦该论负钊钹铫钢镎阈页偿苘爷玛当" +"聪苇虏蝾详谂谨财输郐钉铍阌顶颟骇骁鲁龟纬缯习声视谠贡钋钰衔顷饲厉问岽枨沣尔耸号蚝衮训诜阳巩饱馕骣鲢鹕" +"鹬弹宪枣殚滠皲绥缑织觇谳贽轭辐邝镞项颢饰鳌鹰厣吓峥炜琅缈缮聩脸蚬讪谀赘蹒针钸锞锎阒顺骆鳓鹗鹭堕姗宠柜" +"润皱扎聂讫谍谩踪铀铑锏顸顾鲂鲻鸿宝殓独瞩细练职脐蓣贫辗钿锸镄须鳘帅弥忆殡瘘粤绂经罂胀蚂记谝货赠软舆钾" +"录锲镟鲭狯祸绁缏聍膑舣荜诙贩铷链顼饺骄鱿鲞鲦麦划哜埯弯怅掴栋浈猃祯节绅缭兹荤亏裤贪赞锖镌闱颤鸽优札坟" +"妪闷晕歼签舰苈萤蜡裢讹贯毂钓铱锫颂颥饼验鲣师晖烟狞疗帘缇癯诖诨责迳钐铟锩锘镆阔陧麸椠畴睁范听蛎觋讶赡" +"轷辖钜镙镰阕队颀鲷鳗鸺剧哑败椁愍浔刘参启将叙杀溃洒刽噜专嵛栈寻帐彝壳伟刿掼涌储剑墙对茕啮导带搂毁滗垦" +"桊焕剂彦恳橹滩烦牍应桨殴俪怿揸栖汤帧懔涠炀涩澹傩帏灏傥坛俨榈汹栉丛浇呖妩敌畅椟涝湾凶挚橼滦咙数栎兑挟" +"桩于乐伙抠桉娴岚滟嵴儿垭压恶暂枞怼抟橱兖帼径掺槠菰唤垒帻栌涧喾圹懑敛桠沩牵严垆尴恼毙枥恽橥嘤榇彷藁届" +"帜恹坏从灾劲垄垅币恻栅娆尸徕捞渑吴楼侧内呐坜婵侦两娇栊泽荧丧啭娱准嗫标乔嚣执斓帮复惩泶炝勐伪吕单坝帱" +"撑榉荦冁屉挠晔沟伫懒扪枢毵哟壮怀樱浃呓屡悬昙浍动层捻样册坚嫱忏晓务屦淀干惧毡勋垩几挢壶彻慑斩温胜属恋" +"犊劳嘱栏氇寿爱掸杰呛嫒惬拨泾势啬丬牺垴嬷戆扫抡断权伧吗抚暧浊热后么嵝悫戋气浓伞朴愣备娄崭扑树氢埚嫔揿" +"桦椤氩吒沧坂幂岖旷灭呜囱栾氲挞为纟劢戗挣婴挝凼炽库戬挂捡榄涤溷淼来怆拥疴励唢杨荥烨状掳桡噘熘婶恺战憷" +"劝择晒湿凋佣匀尧够戏桥沉报偬净哔梦户击棂泞灯挡乌炖仑冻场凉传囵崂忾枫伛国书着债冈硅围厕担济伤厢沪噼厩" +"涛烧煳峤拣据会滞迭\0\0"; +static char __szFF[TOTAL_CHAR_BUF]= +"嘆園汙獲籃繞聾藹褸諤轅這鉆銨鍬闌頏顯驚傾圓堿夾癆睞礎稟艫華藺訟貯贏轆釧銩階預顰餉驛鯝廈態滲疊癇築紹諦" +"貰贐連酈鉈銪頑顱養鰾鳥鶥鼴凜慍機燙獵矯窩紺綜繡肅薈褻誄諧證釩鉉銫鏑鐲頒嘍圖婦孌擠淒癉窪篋繢臘艱覦誅貲" +"轉銬鍰鐳闐頓顳餌鳧麯僂擡楨橢濫濫獷紼綞薊訣誆貳贓跡蹺隕顴駿驟鮁鯡團嶧燜獸現窮臚誇貴軫釬錐鐵霧鯢鳩鶩丟" +"滸睪窯綠艷荊薌訥諫鉍餑騁鮃侶僅濰獺紿親譎貶贖轍銱錒鏗闔際頗餒驢鯤嘔婭業淚濱營獻璉盜籌絀綢腎蘄誌諭譏買" +"贗轎鍵鏘鐸闕領餓鱅鸌咼奐欽獼綣蘆覬認諮貸銳鍶闖驤並嘖塊慘盞礙終繩臟蘇鉑錕鐺騅驥鯧僉嘗塋扡滾滾繪腖臠襆" +"訪貺長風鯨鱈鶯慚擬橫滿狹玀盡稭窶組縈蠱襇覯諱豈費贛軲進鏜頜鱉塏廚烴燦狽種縉翹蔔薔蘊螻誑貼銷錘鍺鏝餘鯪" +"鵑麼嘜孫極淥漁癘監絆縊繭翺萇蒓蘋設誒諳貽躉轔釵鉕錙鏞鐿鯫鵒齇凱塒廝揚擯盤筆縋罰臥蒔覲譖躊郟銹錚鏟關驪" +"鳳鵓匭慟換擰決稱窺繯蠶誕豎貿躋釷鉗錛餛鳴鶴俁匯廟擱橰淩濺盧禦糝綬繰罵臨萊諶識賀銻鍾鏡闞頡颮馬鮎鸕齊僑" +"嶴廠擲淪筍糞維芐許諷譙豐賁躍軸郤釹銼鏢隨颯馭騍鳶黃齋匱員塗廡慣濼燭甌癟碩罷腡誘諸譚賂軹鉚鑄門餞馮騎鮐" +"鯰哢廢擴桿禪綰縐繳蟄蠻裊覷賃躑軺鉛錟鏤闡險頤騏鮑嶸廣朧濾癡礦篤綱縑臯蔞訴誚諺譜賄躒軻錠鎂閂霽鮒鱒嘩奧" +"學歐癢絎網蒞薟賅躓軼閃頦餡馱鬢鸚齏嶺擷癤碭籜腦蟈覺訶諼躕鉞鋁錢鎄鞽鯴鱔鶻鸛齒奩慪淵甕癥禮篩結綴蔣蘗裏" +"資軾鏨闥馳鬥鵜鶼嘮奪嶼慫淶燴礪竄糧語諾賈轟鈀鋃鑊閆靂颶馴鱖鵝鸝黌齔嘯嶽廩擺癧瞇礫禰竅籟繹腫蔥覽遊鈁鎇" +"隱鬧鱗鸞嘰孿擻淺礬禱籠蔦蘚蟎襖診誠謀賊轡運鋅錦鑌靄韁騖鱘鶿塢廬慮揮擼沒瀅癩竇綸薦覿註誡謁躚轢郵閉隴鬩" +"鵠區嘵奮瀆璣碸竈絕綹繼觀謂較過鈄鉤鋇錨鎊韃頭館鮚鵡塤擾檁沖癬確綺繽羅腳臺薩誣轤達開騙鷂齙嘸癭竊篳綻縛" +"繾羆蘞誤謄踐輅違鉦閌隸靈颼慳漚瀉燼璦產癮碼礱筧蔭補誥謅錫頰骯鯽鱝俠猙癰綽縝羈裝詁誦躡輇遙鈈鋌鑒閎鬮鮞" +"齜慶瀋燾癱糲綾縞腸與芻襝賑鈉閏鯿鱟鴆點廳攄梔痙癲禿穌綿縟羋膁興蘢襠誨譫賒載遜錮鑔韉鴇僥僥別歟積籩糴耬" +"膃舉謊賓輊鋏錯閑齟僨協攆檉穎籪絝舊莊萬說躥遞鉬鏵韋鴉齠梘歡瀏瞘糶絞耮蝕術詆譯賕躦鈍鉭間韌駁鵪齡刪唄巋" +"漢環籬縣襤議遠醜鋒鏷閔雋頷飄餳黨漣秈緄纈謎豬鄆錳鎖頸鵬噅簀籮絡薺醞鈐鏹頹飆餵玨絢纊謐躪辦鈑鎘鱧條瀕發" +"緇蟣衛誰譴賚鄉閘頻飈餷鰈鵯齦塵宮琺瞞糾續蘭襪輒適雖鰉巒憂攏梟檔漬籲萵蒼蕁衝詎課賜鈔錸靚韓鮪渙瀘無紀給" +"緊莖謔謔護輔辭鈕靜鮫鵲黲巔損減緋縫纏蓀詐賞輕辮鑠雙鷓齪剄塹榪歲漲爍猶琿紂絨謖辯鉸餼騫鮭鰍鱭黴價巖攔時" +"況瀝縭苧蕆蝦襯詒誶謗賠農雛鮮鴕齬卻坰峴弒榮漵猻約縮蟬賡趕鉺鋝鑣雜餾騭倀則攖瀟爐璽簍紅纓詔謙賢遲醫鉻鐃" +"靦韙餿騮髏鷗黷噓島恥搖檜渦漸瀠磚紆羥蟯襲評誹謚譽賣鄒醬鋟鍀鎢鑥閡雞魎鹵憊搗攙歷紇縱莢講譾賤輛鍁鎣靨駐" +"騰鰒鷙唚歸獁穡紈緒縲纖羨膚蓋蕎趙輜遷鄔閣韜顆飛駑體鰓鷚黽儀剎攛晉穢紉義蟲觴詘誼謝讀賦踴輝選鈞鉿鍃離韝" +"饃駒髕鴛黿齲亂妝攜測紋統緔纘蘺賧輞鄖銀鋣鎦閥難韞髖鹹倆儂噝媧憐攝檢瀦獄瑉絲縵膠觶輟遺鋤鎧饅駔鴝鹺峽憑" +"搟檣歿漿瀧獅瘂眥箋納絳絳縶脅莧蕒藍詛調謠鋥鍆駕鱷億墊墊憒東瀨瑋緗縷纜蕓藎蟶觸質軀遼銃鋦鍇鎩鐋鑭閨騶魘" +"鱸鴟鹼倉噠潁皚緘聖脈蘿賫鈣鎪閩題饈騷鹽齷儈磣箏紐緙縹葉蕕詞諂賬邁銅鋨額饉駘騸魚鱺個儉巰攢爛畝瞼穩線賭" +"還鈥鎬鑰閫陘顎饊駙噥拋攣榿絹膩蕘蝸蟻詠諄輥鈦鋪鍋閬顏饋鴣剛噦媯悅攤瓊瘋競紓總詡貍輦鈧鎮鐐鑲閭飩饌駛亙" +"們剝晝瘍磧純緝績詢謨變邇鍍陜飪鷥麅鼉墑巹憚獎穭簞紕緞聞脛詣談蹌釀鎰鐒飫駝鴦鷦畢訁趨輩邊釁鋮鐓雲顓騾鯀" +"鰠鶇亞儐噯弳渾簡紗締訂諉謫輪鋯鐔閱飭駟鯁鴨厙攪瀲瓏緡繃葒藝螄訃試謬讎賴車鄧釃鋰鎳鑷陣饑驀鶉噲崍張攬殘" +"瘓硤簣紙茍請貓軋鋱飯饒驁鰣龍儔棄檳磯級綁緣繅蓧蕢蠅軌邏釅鈮鎵鑹駢驂儕噴強潑眾紛繆蠆見詩諍軍邐銑鍔鐘電" +"願驃鰥墜媼寢構瓔畫紜綃繈計讒蹕輯鈰鐙閶顙飲饗驄龐媽搶槍殞畬硨緦詫諏讓釋銓鑼驅鯇噸實憤潔瑣簫訊詬賺鄭鋶" +"韻顛飴鰨鴯鷯剮寧寧檸爭瑤瘞硯綆編蕩藥處規詭諑謳讕賻趲軒鈳鍘鑾閹陰鯉鰩鴰審崗煆瘡紡緩缽脧蓮蕪訌詮諒讖購" +"輳鄰釓鈴銖鋸鐝鑿鯊龔倫湊異稅綈蓯蛺蠍貝賽軔鄲釔閻陳類饜鷲麗龕寫憫檻殤瀾瓚瘧膽蛻討詰貞賾釕銘鍛閼陸響驊" +"鶓剴厭寬煉皰稈緬膾葤蕭藪覓話鄴鈷鐠閽饞鰭鷴創嚀憮潛瑩磽祿聯脫膿艙虛蠐訐該論負釗鈸銚鋼鎿閾頁償檾爺瑪當" +"聰葦虜蠑詳諗謹財輸鄶釘鈹閿頂顢駭驍魯龜緯繒習聲視讜貢釙鈺銜頃飼厲問崠棖灃爾聳號蠔袞訓詵陽鞏飽饢驏鰱鶘" +"鷸彈憲棗殫灄皸綏緱織覘讞贄軛輻鄺鏃項顥飾鰲鷹厴嚇崢煒瑯緲繕聵臉蜆訕諛贅蹣針鈽錁鐦闃順駱鰳鶚鷺墮姍寵櫃" +"潤皺紮聶訖諜謾蹤鈾銠鐧頇顧魴鯔鴻寶殮獨矚細練職臍蕷貧輾鈿鍤鐨須鰵帥彌憶殯瘺粵紱經罌脹螞記諞貨贈軟輿鉀" +"錄鍥鏇鯖獪禍紲緶聹臏艤蓽詼販銣鏈頊餃驕魷鯗鰷麥劃嚌垵彎悵摑棟湞獫禎節紳繚茲葷虧褲貪贊錆鐫闈顫鴿優劄墳" +"嫗悶暈殲簽艦藶螢蠟褳訛貫轂釣銥錇頌顬餅驗鰹師暉煙獰療簾緹臒詿諢責逕釤銦錈鍩鏌闊隉麩槧疇睜範聽蠣覡訝贍" +"軤轄鉅鏍鐮闋隊頎鯛鰻鵂劇啞敗槨湣潯劉參啟將敘殺潰灑劊嚕專崳棧尋帳彜殼偉劌摜湧儲劍墻對煢嚙導帶摟毀潷墾" +"棬煥劑彥懇櫓灘煩牘應槳毆儷懌摣棲湯幀懍潿煬澀淡儺幃灝儻壇儼櫚洶櫛叢澆嚦嫵敵暢櫝澇灣兇摯櫞灤嚨數櫟兌挾" +"樁於樂夥摳案嫻嵐灩脊兒埡壓惡暫樅懟摶櫥兗幗徑摻櫧菇喚壘幘櫨澗嚳壙懣斂椏溈牽嚴壚尷惱斃櫪惲櫫嚶櫬仿槁屆" +"幟懨壞從災勁壟壟幣惻柵嬈屍徠撈澠吳樓側內吶壢嬋偵兩嬌櫳澤熒喪囀娛準囁標喬囂執斕幫復懲澩熗猛偽呂單壩幬" +"撐櫸犖囅屜撓曄溝佇懶捫樞毿喲壯懷櫻浹囈屢懸曇澮動層撚樣冊堅嬙懺曉務屨澱幹懼氈勛堊幾撟壺徹懾斬溫勝屬戀" +"犢勞囑欄氌壽愛撣傑嗆嬡愜撥涇勢嗇爿犧堖嬤戇掃掄斷權傖嗎撫曖濁熱後麽嶁愨戔氣濃傘樸楞備婁嶄撲樹氫堝嬪撳" +"樺欏氬咤滄阪冪嶇曠滅嗚囪欒氳撻為糸勱戧掙嬰撾氹熾庫戩掛撿欖滌混渺來愴擁屙勵嗩楊滎燁狀擄橈撅溜嬸愷戰怵" +"勸擇曬濕雕傭勻堯夠戲橋沈報傯凈嗶夢戶擊欞濘燈擋烏燉侖凍場涼傳圇嶗愾楓傴國書著債岡矽圍廁擔濟傷廂滬劈廄" +"濤燒糊嶠揀據會滯叠\0\0"; + +static void code_to_file(const char *filename, const char *name_pre, + const char *from_tab, const char *to_tab) +{ + char buf[255]; + ACL_FILE *fp; + int i; + unsigned short table[65535]; + + // 初始化 + for (i = 0; i < 65535; i++) { + table[i] = 0xffff; + } + unsigned short *ptr1 = (unsigned short*) from_tab; + unsigned short *ptr2 = (unsigned short*) to_tab; + while (*ptr1 != 0) { + table[*ptr1] = *ptr2; + if (*ptr2 == 0xa1b3) { + printf(">>>>>ptr2: 0x%x, %d, ptr1: %d, 0x%x\n", *ptr2, *ptr2, *ptr1, *ptr1); + } + *ptr1++; + *ptr2++; + } + + printf(">>>>>table[41395]: 0x%x\n", table[41395]); + + fp = acl_fopen(filename, "w+"); + snprintf(buf, sizeof(buf), "static unsigned short %s[] = {\n", name_pre); + acl_fwrite(buf, strlen(buf), 1, fp); + for (i = 0; i < 65535; i++) { + if (i % 8 == 0) { + if (i == 0) + snprintf(buf, sizeof(buf), "\t"); + else + snprintf(buf, sizeof(buf), "\n\t"); + acl_fwrite(buf, strlen(buf), 1, fp); + } + snprintf(buf, sizeof(buf), "0x%x,", table[i]); + acl_fwrite(buf, strlen(buf), 1, fp); + } + snprintf(buf, sizeof(buf), "\n};\n"); + acl_fwrite(buf, strlen(buf), 1, fp); + acl_fclose(fp); +} + +static void code_map(const char *filename, const char *data) +{ + ACL_FILE *fp = acl_fopen(filename, "w+"); + unsigned short *ptr = (unsigned short*) data; + char buf[16]; + + acl_fputs("static unsigned short __map_tab[] = {", fp); + while (*ptr != 0) { + snprintf(buf, sizeof(buf), "0x%x,", *ptr); + acl_fwrite(buf, strlen(buf), 1, fp); + ptr++; + } + acl_fputs("\n};", fp); + acl_fclose(fp); +} + +static void write_code(void) +{ + printf("jt2ft\n"); + code_to_file("jt2ft.h", "__jt2ft_tab", __szJJ, __szJF); + printf("ft2jt\n"); + code_to_file("ft2jt.h", "__ft2jt_tab", __szFF, __szFJ); + getchar(); + + return; + //场础贰尽馈谩拧伞 + code_map("j2f.txt", "场础贰尽馈谩拧伞\0\0"); + char buf[256]; + unsigned short a[] = {0xf688,0x3666,0x3636,0x2c,0x81f0,0x99d6,0x5194,0xe382, 0}; + unsigned short *p = (unsigned short*) buf, i; + + memset(buf, 0, sizeof(buf)); + + for (i = 0; a[i]; i++) { + *p++ = a[i]; + } + + printf(">>%S\n", buf); + getchar(); +} + +int main(int argc, char *argv[]) +{ + write_code(); + return (0); +} diff --git a/samples/configure/Makefile b/samples/configure/Makefile new file mode 100644 index 000000000..82c606baf --- /dev/null +++ b/samples/configure/Makefile @@ -0,0 +1,2 @@ +include ../Makefile_cpp.in +PROG = configure diff --git a/samples/configure/configure_vc2003.vcproj b/samples/configure/configure_vc2003.vcproj new file mode 100644 index 000000000..84f959642 --- /dev/null +++ b/samples/configure/configure_vc2003.vcproj @@ -0,0 +1,244 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/configure/configure_vc2008.vcproj b/samples/configure/configure_vc2008.vcproj new file mode 100644 index 000000000..2a14229f9 --- /dev/null +++ b/samples/configure/configure_vc2008.vcproj @@ -0,0 +1,213 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/configure/main.cpp b/samples/configure/main.cpp new file mode 100644 index 000000000..8520977a5 --- /dev/null +++ b/samples/configure/main.cpp @@ -0,0 +1,134 @@ +#include "lib_acl.h" +#include +#include +#include + +static int var_a_count; +static int var_b_count; +static int var_c_count; + +static char *var_a_str; +static char *var_b_str; +static char *var_c_str; +static char *var_event_mode; + +static int var_a_bool; +static int var_b_bool; +static int var_c_bool; + +static ACL_CFG_INT_TABLE __conf_int_tab[] = { + { "a_count", 1, &var_a_count, 0, 0 }, + { "b_count", 1, &var_b_count, 0, 0 }, + { "c_count", 1, &var_c_count, 0, 0 }, + { 0, 0, 0, 0, 0 }, +}; + +static ACL_CFG_STR_TABLE __conf_str_tab[] = { + { "a_str", "testa", &var_a_str }, + { "b_str", "testb", &var_b_str }, + { "c_str", "testc", &var_c_str }, + { "aio_event_mode", "select", &var_event_mode }, + { 0, 0, 0 }, +}; + +static ACL_CFG_BOOL_TABLE __conf_bool_tab[] = { + { "a_bool", 0, &var_a_bool }, + { "b_bool", 0, &var_b_bool }, + { "c_bool", 0, &var_c_bool }, + { 0, 0, 0 }, +}; + +static void list_all(const ACL_XINETD_CFG_PARSER *cfg) +{ + int i, n; + char *name, *value; + + n = acl_xinetd_cfg_size(cfg); + for (i = 0; i < n; i++) { + if (acl_xinetd_cfg_index(cfg, i, &name, &value) < 0) + break; + printf("%s = %s\r\n", name, value); + } +} + +static void check_cf(const char *filename) +{ + ACL_XINETD_CFG_PARSER *cfg; + + cfg = acl_xinetd_cfg_load(filename); + assert(cfg); + + acl_xinetd_params_int_table(cfg, __conf_int_tab); + acl_xinetd_params_str_table(cfg, __conf_str_tab); + acl_xinetd_params_bool_table(cfg, __conf_bool_tab); + + printf("var_a_str=%s\r\n", var_a_str); + printf("var_b_str=%s\r\n", var_b_str); + printf("var_c_str=%s\r\n", var_c_str); + printf("var_a_count=%d\r\n", var_a_count); + printf("var_b_count=%d\r\n", var_b_count); + printf("var_c_count=%d\r\n", var_c_count); + printf("var_a_bool=%d\r\n", var_a_bool); + printf("var_b_bool=%d\r\n", var_b_bool); + printf("var_c_bool=%d\r\n", var_c_bool); + + printf("var_event_mode=%s\r\n", var_event_mode); + + list_all(cfg); + +} + +static void list_cf(const char *filename) +{ + ACL_XINETD_CFG_PARSER *cfg; + + cfg = acl_xinetd_cfg_load(filename); + if (cfg == NULL) + printf("error=%s\r\n", strerror(errno)); + assert(cfg); + list_all(cfg); + acl_xinetd_cfg_free(cfg); +} + +static void usage(const char *procname) +{ + printf("usage: %s -h [help] -l [list] -f conf_file\r\n", procname); +} + +int main(int argc, char *argv[]) +{ + char ch; + char cf[256]; + int l = 0; + + cf[0] = 0; + + while ((ch = getopt(argc, argv, "hlf:")) > 0) { + switch (ch) { + case 'h': + usage(argv[0]); + return (0); + case 'l': + l = 1; + break; + case 'f': + ACL_SAFE_STRNCPY(cf, optarg, sizeof(cf)); + break; + default: + break; + } + } + + if (cf[0] == 0) { + usage(argv[0]); + return (0); + } + + if (l) + list_cf(cf); + else + check_cf(cf); + + return (0); +} + diff --git a/samples/configure/test_unix.cf b/samples/configure/test_unix.cf new file mode 100644 index 000000000..f5fb01599 --- /dev/null +++ b/samples/configure/test_unix.cf @@ -0,0 +1,14 @@ +service unix_test { + a_count = 1 + b_count = 2 + c_count = 3 + a_str = a1:a2:a3 \ + a11:a12:13 \ + a21:a22:a23 + b_str = b1:b2:b3 + c_str = c1:c2:c3 + a_bool = 0 + b_bool = 1 + c_bool = 1 +} + diff --git a/samples/configure/test_win32.cf b/samples/configure/test_win32.cf new file mode 100644 index 000000000..4f41cbda0 --- /dev/null +++ b/samples/configure/test_win32.cf @@ -0,0 +1,12 @@ +service test { + a_str = a1:a2:a3 \ + a11:a12:13 + b_str = b1:b2:b3 + c_str = c1:c2:c3 + a_count = 1 + b_count = 2 + c_count = 3 + a_bool = 1 + b_bool = 1 + c_bool = 1 +} \ No newline at end of file diff --git a/samples/configure/tt2.cf b/samples/configure/tt2.cf new file mode 100644 index 000000000..1f9faea15 --- /dev/null +++ b/samples/configure/tt2.cf @@ -0,0 +1,2 @@ +a_count = 10 +b_count = 20 diff --git a/samples/connect/Makefile b/samples/connect/Makefile new file mode 100644 index 000000000..6440c02f0 --- /dev/null +++ b/samples/connect/Makefile @@ -0,0 +1,2 @@ +include ../Makefile_cpp.in +PROG = connect diff --git a/samples/connect/connect.vcproj b/samples/connect/connect.vcproj new file mode 100644 index 000000000..612bfa331 --- /dev/null +++ b/samples/connect/connect.vcproj @@ -0,0 +1,234 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/connect/connect.vcxproj b/samples/connect/connect.vcxproj new file mode 100644 index 000000000..7c445824f --- /dev/null +++ b/samples/connect/connect.vcxproj @@ -0,0 +1,181 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + ReleaseDll + Win32 + + + Release + Win32 + + + + {6254E8C1-6849-4108-8DBE-18152A642F46} + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + ws2_32.lib;wsock32.lib;%(AdditionalDependencies) + $(OutDir)connect.exe + true + $(OutDir)connect.pdb + Console + MachineX86 + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;%(AdditionalDependencies) + $(OutDir)connect.exe + true + Console + true + true + MachineX86 + + + + + Disabled + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_DLL;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + EditAndContinue + + + ws2_32.lib;wsock32.lib;%(AdditionalDependencies) + $(OutDir)connect.exe + true + $(OutDir)connect.pdb + Console + MachineX86 + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_DLL;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;%(AdditionalDependencies) + $(OutDir)connect.exe + true + Console + true + true + MachineX86 + + + + + + + + {b40213c2-507c-4c7f-a6e1-b850c9bdc27b} + false + + + + + + \ No newline at end of file diff --git a/samples/connect/main.cpp b/samples/connect/main.cpp new file mode 100644 index 000000000..08834378c --- /dev/null +++ b/samples/connect/main.cpp @@ -0,0 +1,65 @@ +#include "lib_acl.h" + +static void test(const char* addr) +{ + for (int i = 0; i < 1000; i++) + { + ACL_VSTREAM* client = acl_vstream_connect(addr, ACL_BLOCKING, 10, 10, 4096); + if (client == NULL) + printf("connect addr: %s error\r\n", addr); + else + printf("connect addr: %s ok\r\n", addr); + } + + getchar(); +} + +int main(int argc, char *argv[]) +{ + test(argv[1]); + return 0; + + ACL_VSTREAM *client; + const char *addr; + char buf[1024]; + int ret; + + if (argc != 2) { + printf("usage: %s addr\n", argv[0]); + return (0); + } + + addr = argv[1]; + + acl_msg_open("connect.log", argv[0]); + printf("connecting %s ...\n", argv[1]); + + //acl_poll_prefered(1); + for (int i = 0; i < 10000; i++) + { + client = acl_vstream_connect(addr, ACL_BLOCKING, 10, 10, 4096); + if (client == NULL) { + printf("connect %s error(%s)\n", addr, acl_last_serror()); + return (1); + } + printf("connect %s ok, %s\n", addr, acl_last_serror()); + } + + printf(">>>>>>connect all ok\r\n"); + pause(); + sleep(100); + acl_vstream_fprintf(client, "%s", "line1\nline2\nline3\nline4\nline5\nline6\nline7\n"); + + while (1) { + ret = acl_vstream_gets_nonl(client, buf, sizeof(buf)); + if (ret > 0) { + printf("gets from %s: %s\n", addr, buf); + } else if (ret == ACL_VSTREAM_EOF) { + printf("get over\r\n"); + break; + } + } + + acl_vstream_close(client); + return (0); +} diff --git a/samples/dbpool/Makefile b/samples/dbpool/Makefile new file mode 100644 index 000000000..3d9ae02d7 --- /dev/null +++ b/samples/dbpool/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = dbpool diff --git a/samples/dbpool/main.c b/samples/dbpool/main.c new file mode 100644 index 000000000..f8731f283 --- /dev/null +++ b/samples/dbpool/main.c @@ -0,0 +1,82 @@ +#include "lib_acl.h" +#include + +static void usage(const char *procname) +{ + printf("usage: %s -s db_addr -d db_name -u db_user -p db_pass\n", procname); +} + +int main(int argc, char *argv[]) +{ + ACL_DB_POOL *db_pool; + ACL_DB_HANDLE *db_handle; + ACL_DB_INFO db_info; + int ch, i; + + memset(&db_info, 0, sizeof(db_info)); + db_info.db_max = 10; + db_info.ping_inter = 30; + db_info.timeout_inter = 30; + + while ((ch = getopt(argc, argv, "hs:d:u:p:")) > 0) + { + switch (ch) + { + case 'h': + usage(argv[0]); + return (0); + case 's': + snprintf(db_info.db_addr, sizeof(db_info.db_addr), + "%s", optarg); + break; + case 'd': + snprintf(db_info.db_name, sizeof(db_info.db_name), + "%s", optarg); + break; + case 'u': + snprintf(db_info.db_user, sizeof(db_info.db_user), + "%s", optarg); + break; + case 'p': + snprintf(db_info.db_pass, sizeof(db_info.db_pass), + "%s", optarg); + break; + default: + break; + } + } + + if (db_info.db_addr[0] == 0 || db_info.db_name[0] == 0 + || db_info.db_user[0] == 0 || db_info.db_pass[0] == 0) + { + usage(argv[0]); + return (1); + } + + db_pool = acl_dbpool_create("mysql", &db_info); + if (db_pool == NULL) + { + printf("acl_dbpool_create error\n"); + return (1); + } + printf("acl_dbpool_create ok\n"); + + for (i = 0; i < 100; i++) + { + db_handle = acl_dbpool_peek(db_pool); + if (db_handle == NULL) + { + printf("acl_dbpool_peek error\n"); + return (1); + } + printf("acl_dbpool_peek ok\n"); + + acl_dbpool_release(db_handle); + printf("acl_dbpool_release ok\n"); + } + + acl_dbpool_destroy(db_pool); + printf("acl_dbpool_destroy ok\n"); + + return (0); +} diff --git a/samples/dbpool/valgrind.sh b/samples/dbpool/valgrind.sh new file mode 100644 index 000000000..3473717e9 --- /dev/null +++ b/samples/dbpool/valgrind.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +valgrind --show-reachable=yes --tool=memcheck --leak-check=yes -v ./dbpool -s /tmp/mysql_front.csmail.sock -d csmail_userdb -u csmail -p 6322873429366825679 diff --git a/samples/debug_malloc/Makefile b/samples/debug_malloc/Makefile new file mode 100644 index 000000000..6bf830ca1 --- /dev/null +++ b/samples/debug_malloc/Makefile @@ -0,0 +1,2 @@ +include ../Makefile_cpp.in +PROG = debug_malloc diff --git a/samples/debug_malloc/debug_malloc_vc2003.vcproj b/samples/debug_malloc/debug_malloc_vc2003.vcproj new file mode 100644 index 000000000..e301a72d4 --- /dev/null +++ b/samples/debug_malloc/debug_malloc_vc2003.vcproj @@ -0,0 +1,238 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/debug_malloc/debug_malloc_vc2008.vcproj b/samples/debug_malloc/debug_malloc_vc2008.vcproj new file mode 100644 index 000000000..2d1ca9855 --- /dev/null +++ b/samples/debug_malloc/debug_malloc_vc2008.vcproj @@ -0,0 +1,204 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/debug_malloc/log.txt b/samples/debug_malloc/log.txt new file mode 100644 index 000000000..f8fd63d26 --- /dev/null +++ b/samples/debug_malloc/log.txt @@ -0,0 +1,101 @@ +corrupt|main.cpp|17 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 +leak|main.cpp|11|100 diff --git a/samples/debug_malloc/main.cpp b/samples/debug_malloc/main.cpp new file mode 100644 index 000000000..0b47b55e5 --- /dev/null +++ b/samples/debug_malloc/main.cpp @@ -0,0 +1,20 @@ +#include "lib_acl.h" + +int main(int argc acl_unused, char *argv[] acl_unused) +{ + char *ptr2; + char *ptr3 = acl_mystrdup("hello world!"); + int i; + + acl_debug_malloc_init(NULL, "log.txt"); + + for (i = 0; i < 100; i++) { + (void) acl_mymalloc(100); + ptr2 = (char*) acl_mymalloc(100); + acl_myfree(ptr2); + } + + acl_myfree(ptr2); + acl_myfree(ptr3); + return 0; +} diff --git a/samples/demo/ChatDemo.cpp b/samples/demo/ChatDemo.cpp new file mode 100644 index 000000000..59f565a6f --- /dev/null +++ b/samples/demo/ChatDemo.cpp @@ -0,0 +1,13 @@ +#include "stdafx.h" +#include ".\chatdemo.h" + +CChatDemo::CChatDemo(const char *s) +{ + m_buf = acl_vstring_alloc(256); + acl_vstring_strcpy(m_buf, s); +} + +CChatDemo::~CChatDemo(void) +{ + acl_vstring_free(m_buf); +} diff --git a/samples/demo/ChatDemo.h b/samples/demo/ChatDemo.h new file mode 100644 index 000000000..3c2a672eb --- /dev/null +++ b/samples/demo/ChatDemo.h @@ -0,0 +1,11 @@ +#pragma once +#include "lib_acl.h" + +class CChatDemo +{ +public: + CChatDemo(const char *s); + ~CChatDemo(void); + + ACL_VSTRING *m_buf; +}; diff --git a/samples/demo/ReadMe.txt b/samples/demo/ReadMe.txt new file mode 100644 index 000000000..f95f98a4e --- /dev/null +++ b/samples/demo/ReadMe.txt @@ -0,0 +1,86 @@ +================================================================================ + MICROSOFT 基础类库: demo 项目概述 +=============================================================================== + +应用程序向导已为您创建了此 demo 应用程序。此应用程序 +不仅介绍了使用 Microsoft 基础类的基本知识, +而且是编写应用程序的起点。 + +此文件包含组成 demo 应用程序的每个文件的内容摘要。 + +demo.vcproj + 这是使用“应用程序向导”生成的 VC++ 项目的主项目文件。 + 它包含有关生成文件的 Visual C++ 版本的信息,以及 + 有关用“应用程序向导”所选择的平台、配置和 + 项目功能的信息。 + +demo.h + 这是应用程序的主头文件。 它包含其他 + 项目特定的头文件(包括 Resource.h),并声明 + CdemoApp 应用程序类。 + +demo.cpp + 这是包含应用程序 + 类 CdemoApp 的主应用程序源文件。 + +demo.rc + 这是程序使用的所有 Microsoft Windows 资源 + 的列表。 它包含存储在 RES 子目录中 + 的图标、位图和光标。 可直接在 Microsoft + Visual C++ 中编辑此文件。 项目资源包含在 2052 中。 + +res\demo.ico + 这是一个图标文件,用作应用程序的图标。 此 + 图标包含在主资源文件 demo.rc 中。 + +res\demo.rc2 + 此文件包含不由 Microsoft + Visual C++ 编辑的资源。 应将所有不能由 + 资源编辑器编辑的资源放在此文件中。 + +///////////////////////////////////////////////////////////////////////////// + +应用程序向导将创建一个对话框类: +demoDlg.h、demoDlg.cpp - 对话框 + 这些文件包含 CdemoDlg 类。 此类定义 + 应用程序主对话框的行为。 此对话框的模板包含在 + demo.rc 中,而此文件可以在 Microsoft Visual C++ 中进行编辑。 +///////////////////////////////////////////////////////////////////////////// + +其他功能: + +ActiveX 控件 + 应用程序支持使用 ActiveX 控件。 + +打印支持和打印预览支持 + 应用程序向导已生成了一些代码,通过从 MFC 库调用 CView 类中的成员函数来 + 处理打印、打印设置和打印预览命令。 +///////////////////////////////////////////////////////////////////////////// + +其他标准文件: + +StdAfx.h、StdAfx.cpp + 这些文件用于生成名为 demo.pch 的预编译头文件 (PCH) + 和名为 StdAfx.obj 的预编译类型文件。 + +Resource.h + 这是标准头文件,它定义新资源 ID。 + Microsoft Visual C++ 将读取并更新此文件。 + +///////////////////////////////////////////////////////////////////////////// + +其他说明: + +应用程序向导使用“TODO:” 来指示 +应添加或自定义的源代码部分。 + +如果应用程序在共享 DLL 中使用 MFC,且应用程序使用的语言不是 +操作系统的当前语言,则需要从 Microsoft Visual C++ 光盘上 +Win\System 目录下将相应的本地化资源 MFC70XXX.DLL +复制到计算机的 system 或 system32 目录下, +并将其重命名为 MFCLOC.DLL。 (“XXX”代表 +语言缩写。 例如,MFC70DEU.DLL 包含翻译成 +德语的资源。) 如果不这样做,应用程序的某些 UI 元素 +将保留为操作系统的语言。 + +///////////////////////////////////////////////////////////////////////////// diff --git a/samples/demo/demo.aps b/samples/demo/demo.aps new file mode 100644 index 000000000..6ab090365 Binary files /dev/null and b/samples/demo/demo.aps differ diff --git a/samples/demo/demo.cpp b/samples/demo/demo.cpp new file mode 100644 index 000000000..3a05092d0 --- /dev/null +++ b/samples/demo/demo.cpp @@ -0,0 +1,73 @@ +// demo.cpp : 定义应用程序的类行为。 +// + +#include "stdafx.h" +#include "demo.h" +#include "demoDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#endif + + +// CdemoApp + +BEGIN_MESSAGE_MAP(CdemoApp, CWinApp) + ON_COMMAND(ID_HELP, CWinApp::OnHelp) +END_MESSAGE_MAP() + + +// CdemoApp 构造 + +CdemoApp::CdemoApp() +{ + // TODO: 在此处添加构造代码, + // 将所有重要的初始化放置在 InitInstance 中 +} + + +// 唯一的一个 CdemoApp 对象 + +CdemoApp theApp; + + +// CdemoApp 初始化 + +BOOL CdemoApp::InitInstance() +{ + // 如果一个运行在 Windows XP 上的应用程序清单指定要 + // 使用 ComCtl32.dll 版本 6 或更高版本来启用可视化方式, + //则需要 InitCommonControls()。否则,将无法创建窗口。 + InitCommonControls(); + + CWinApp::InitInstance(); + + AfxEnableControlContainer(); + + // 标准初始化 + // 如果未使用这些功能并希望减小 + // 最终可执行文件的大小,则应移除下列 + // 不需要的特定初始化例程 + // 更改用于存储设置的注册表项 + // TODO: 应适当修改该字符串, + // 例如修改为公司或组织名 + SetRegistryKey(_T("应用程序向导生成的本地应用程序")); + + CdemoDlg dlg; + m_pMainWnd = &dlg; + INT_PTR nResponse = dlg.DoModal(); + if (nResponse == IDOK) + { + // TODO: 在此放置处理何时用“确定”来关闭 + //对话框的代码 + } + else if (nResponse == IDCANCEL) + { + // TODO: 在此放置处理何时用“取消”来关闭 + //对话框的代码 + } + + // 由于对话框已关闭,所以将返回 FALSE 以便退出应用程序, + // 而不是启动应用程序的消息泵。 + return FALSE; +} diff --git a/samples/demo/demo.h b/samples/demo/demo.h new file mode 100644 index 000000000..7ae9a53cd --- /dev/null +++ b/samples/demo/demo.h @@ -0,0 +1,31 @@ +// demo.h : PROJECT_NAME 应用程序的主头文件 +// + +#pragma once + +#ifndef __AFXWIN_H__ + #error 在包含用于 PCH 的此文件之前包含“stdafx.h” +#endif + +#include "resource.h" // 主符号 + + +// CdemoApp: +// 有关此类的实现,请参阅 demo.cpp +// + +class CdemoApp : public CWinApp +{ +public: + CdemoApp(); + +// 重写 + public: + virtual BOOL InitInstance(); + +// 实现 + + DECLARE_MESSAGE_MAP() +}; + +extern CdemoApp theApp; diff --git a/samples/demo/demo.rc b/samples/demo/demo.rc new file mode 100644 index 000000000..72ccd737e --- /dev/null +++ b/samples/demo/demo.rc @@ -0,0 +1,200 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// 中文(中华人民共和国) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) +#ifdef _WIN32 +LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED +#pragma code_page(936) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "#define _AFX_NO_SPLITTER_RESOURCES\r\n" + "#define _AFX_NO_OLE_RESOURCES\r\n" + "#define _AFX_NO_TRACKER_RESOURCES\r\n" + "#define _AFX_NO_PROPERTY_RESOURCES\r\n" + "\r\n" + "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)\r\n" + "LANGUAGE 4, 2\r\n" + "#pragma code_page(936)\r\n" + "#include ""res\\demo.rc2"" // 非 Microsoft Visual C++ 编辑过的资源\r\n" + "#include ""afxres.rc"" // 标准组件\r\n" + "#endif\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDR_MAINFRAME ICON "res\\demo.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_ABOUTBOX DIALOGEX 0, 0, 235, 55 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | + WS_SYSMENU +CAPTION "关于 demo" +FONT 9, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + ICON IDR_MAINFRAME,IDC_STATIC,11,17,20,20 + LTEXT "demo Version 1.0",IDC_STATIC,40,10,119,8,SS_NOPREFIX + LTEXT "Copyright (C) 2010",IDC_STATIC,40,25,119,8 + DEFPUSHBUTTON "确定",IDOK,178,7,50,16,WS_GROUP +END + +IDD_DEMO_DIALOG DIALOGEX 0, 0, 320, 200 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | + WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_APPWINDOW +CAPTION "demo" +FONT 9, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + DEFPUSHBUTTON "确定",IDOK,263,7,50,16 + PUSHBUTTON "取消",IDCANCEL,263,25,50,16 + CTEXT "TODO: 在此放置对话框控件。",IDC_STATIC,10,96,300,8 + PUSHBUTTON "Button1",IDC_BUTTON1,127,58,50,14 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "080403a8" + BEGIN + VALUE "CompanyName", "TODO: <公司名>" + VALUE "FileDescription", "TODO: <文件说明>" + VALUE "FileVersion", "1.0.0.1" + VALUE "InternalName", "demo.exe" + VALUE "LegalCopyright", "TODO: (C) <公司名>。保留所有权利。" + VALUE "OriginalFilename", "demo.exe" + VALUE "ProductName", "TODO: <产品名>" + VALUE "ProductVersion", "1.0.0.1" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "翻译", 0x804, 936 + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_ABOUTBOX, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 228 + TOPMARGIN, 7 + BOTTOMMARGIN, 48 + END + + IDD_DEMO_DIALOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 313 + TOPMARGIN, 7 + BOTTOMMARGIN, 193 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + IDS_ABOUTBOX "关于 demo(&A)..." +END + +#endif // 中文(中华人民共和国) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +#define _AFX_NO_SPLITTER_RESOURCES +#define _AFX_NO_OLE_RESOURCES +#define _AFX_NO_TRACKER_RESOURCES +#define _AFX_NO_PROPERTY_RESOURCES + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) +LANGUAGE 4, 2 +#pragma code_page(936) +#include "res\demo.rc2" // 非 Microsoft Visual C++ 编辑过的资源 +#include "afxres.rc" // 标准组件 +#endif + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/samples/demo/demo.vcproj b/samples/demo/demo.vcproj new file mode 100644 index 000000000..f5deb1b13 --- /dev/null +++ b/samples/demo/demo.vcproj @@ -0,0 +1,324 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/demo/demo.vcxproj b/samples/demo/demo.vcxproj new file mode 100644 index 000000000..e679e024b --- /dev/null +++ b/samples/demo/demo.vcxproj @@ -0,0 +1,255 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + ReleaseDll + Win32 + + + Release + Win32 + + + Template + Win32 + + + + {1AC6401F-21D8-4D44-9CDD-BDD45470CBFB} + MFCProj + + + + Application + Dynamic + MultiByte + + + Application + Dynamic + MultiByte + + + Application + Static + MultiByte + + + Application + Static + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + true + Use + Level3 + EditAndContinue + + + %(AdditionalLibraryDirectories) + %(IgnoreSpecificDefaultLibraries) + true + Windows + MachineX86 + + + _DEBUG;%(PreprocessorDefinitions) + false + + + _DEBUG;%(PreprocessorDefinitions) + 0x0804 + $(IntDir);%(AdditionalIncludeDirectories) + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) + false + MultiThreaded + true + Use + Level3 + ProgramDatabase + + + true + Windows + true + true + MachineX86 + + + NDEBUG;%(PreprocessorDefinitions) + false + + + NDEBUG;%(PreprocessorDefinitions) + 0x0804 + $(IntDir);%(AdditionalIncludeDirectories) + + + + + Disabled + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_WINDOWS;_DEBUG;ACL_DLL;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + true + Use + Level3 + EditAndContinue + + + %(AdditionalLibraryDirectories) + libcmtd;%(IgnoreSpecificDefaultLibraries) + true + Windows + MachineX86 + + + _DEBUG;%(PreprocessorDefinitions) + false + + + _DEBUG;%(PreprocessorDefinitions) + 0x0804 + $(IntDir);%(AdditionalIncludeDirectories) + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_WINDOWS;NDEBUG;ACL_DLL;%(PreprocessorDefinitions) + false + MultiThreadedDLL + true + Use + Level3 + ProgramDatabase + + + true + Windows + true + true + MachineX86 + + + NDEBUG;%(PreprocessorDefinitions) + false + + + NDEBUG;%(PreprocessorDefinitions) + 0x0804 + $(IntDir);%(AdditionalIncludeDirectories) + + + + + + + + Create + Create + Create + Create + + + + + + + + + + + + + + + + + + + + + + + {b40213c2-507c-4c7f-a6e1-b850c9bdc27b} + false + + + + + + + + + + + \ No newline at end of file diff --git a/samples/demo/demo.vcxproj.filters b/samples/demo/demo.vcxproj.filters new file mode 100644 index 000000000..c16b64d60 --- /dev/null +++ b/samples/demo/demo.vcxproj.filters @@ -0,0 +1,65 @@ +锘 + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx + + + + + 婧愭枃浠 + + + 婧愭枃浠 + + + 婧愭枃浠 + + + 婧愭枃浠 + + + + + 澶存枃浠 + + + 澶存枃浠 + + + 澶存枃浠 + + + 澶存枃浠 + + + 澶存枃浠 + + + + + 璧勬簮鏂囦欢 + + + 璧勬簮鏂囦欢 + + + + + + 璧勬簮鏂囦欢 + + + + + + \ No newline at end of file diff --git a/samples/demo/demoDlg.cpp b/samples/demo/demoDlg.cpp new file mode 100644 index 000000000..f4d2f1856 --- /dev/null +++ b/samples/demo/demoDlg.cpp @@ -0,0 +1,158 @@ +// demoDlg.cpp : 实现文件 +// +#include "stdafx.h" +#include "ChatDemo.h" +#include "demo.h" +#include "demoDlg.h" +#include ".\demodlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#endif + + +// 用于应用程序“关于”菜单项的 CAboutDlg 对话框 + +class CAboutDlg : public CDialog +{ +public: + CAboutDlg(); + +// 对话框数据 + enum { IDD = IDD_ABOUTBOX }; + + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 + +// 实现 +protected: + DECLARE_MESSAGE_MAP() +}; + +CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) +{ +} + +void CAboutDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); +} + +BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) +END_MESSAGE_MAP() + + +// CdemoDlg 对话框 + + + +CdemoDlg::CdemoDlg(CWnd* pParent /*=NULL*/) + : CDialog(CdemoDlg::IDD, pParent) +{ + m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); +} + +void CdemoDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); +} + +BEGIN_MESSAGE_MAP(CdemoDlg, CDialog) + ON_WM_SYSCOMMAND() + ON_WM_PAINT() + ON_WM_QUERYDRAGICON() + //}}AFX_MSG_MAP + ON_BN_CLICKED(IDC_BUTTON1, OnBnClickedButton1) +END_MESSAGE_MAP() + + +// CdemoDlg 消息处理程序 + +BOOL CdemoDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + // 将\“关于...\”菜单项添加到系统菜单中。 + + // IDM_ABOUTBOX 必须在系统命令范围内。 + ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); + ASSERT(IDM_ABOUTBOX < 0xF000); + + CMenu* pSysMenu = GetSystemMenu(FALSE); + if (pSysMenu != NULL) + { + CString strAboutMenu; + strAboutMenu.LoadString(IDS_ABOUTBOX); + if (!strAboutMenu.IsEmpty()) + { + pSysMenu->AppendMenu(MF_SEPARATOR); + pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); + } + } + + // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动 + // 执行此操作 + SetIcon(m_hIcon, TRUE); // 设置大图标 + SetIcon(m_hIcon, FALSE); // 设置小图标 + + // TODO: 在此添加额外的初始化代码 + + return TRUE; // 除非设置了控件的焦点,否则返回 TRUE +} + +void CdemoDlg::OnSysCommand(UINT nID, LPARAM lParam) +{ + if ((nID & 0xFFF0) == IDM_ABOUTBOX) + { + CAboutDlg dlgAbout; + dlgAbout.DoModal(); + } + else + { + CDialog::OnSysCommand(nID, lParam); + } +} + +// 如果向对话框添加最小化按钮,则需要下面的代码 +// 来绘制该图标。对于使用文档/视图模型的 MFC 应用程序, +// 这将由框架自动完成。 + +void CdemoDlg::OnPaint() +{ + if (IsIconic()) + { + CPaintDC dc(this); // 用于绘制的设备上下文 + + SendMessage(WM_ICONERASEBKGND, reinterpret_cast(dc.GetSafeHdc()), 0); + + // 使图标在工作矩形中居中 + int cxIcon = GetSystemMetrics(SM_CXICON); + int cyIcon = GetSystemMetrics(SM_CYICON); + CRect rect; + GetClientRect(&rect); + int x = (rect.Width() - cxIcon + 1) / 2; + int y = (rect.Height() - cyIcon + 1) / 2; + + // 绘制图标 + dc.DrawIcon(x, y, m_hIcon); + } + else + { + CDialog::OnPaint(); + } +} + +//当用户拖动最小化窗口时系统调用此函数取得光标显示。 +HCURSOR CdemoDlg::OnQueryDragIcon() +{ + return static_cast(m_hIcon); +} + +void CdemoDlg::OnBnClickedButton1() +{ + // TODO: 在此添加控件通知处理程序代码 + CChatDemo *demo = new CChatDemo("hello world"); + + MessageBox(acl_vstring_str(demo->m_buf)); + delete demo; +} diff --git a/samples/demo/demoDlg.h b/samples/demo/demoDlg.h new file mode 100644 index 000000000..8358836cc --- /dev/null +++ b/samples/demo/demoDlg.h @@ -0,0 +1,33 @@ +// demoDlg.h : 头文件 +// + +#pragma once + + +// CdemoDlg 对话框 +class CdemoDlg : public CDialog +{ +// 构造 +public: + CdemoDlg(CWnd* pParent = NULL); // 标准构造函数 + +// 对话框数据 + enum { IDD = IDD_DEMO_DIALOG }; + + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 + + +// 实现 +protected: + HICON m_hIcon; + + // 生成的消息映射函数 + virtual BOOL OnInitDialog(); + afx_msg void OnSysCommand(UINT nID, LPARAM lParam); + afx_msg void OnPaint(); + afx_msg HCURSOR OnQueryDragIcon(); + DECLARE_MESSAGE_MAP() +public: + afx_msg void OnBnClickedButton1(); +}; diff --git a/samples/demo/res/demo.ico b/samples/demo/res/demo.ico new file mode 100644 index 000000000..8a84ca3d3 Binary files /dev/null and b/samples/demo/res/demo.ico differ diff --git a/samples/demo/res/demo.manifest b/samples/demo/res/demo.manifest new file mode 100644 index 000000000..d3147a298 --- /dev/null +++ b/samples/demo/res/demo.manifest @@ -0,0 +1,22 @@ + + + +鍦ㄦ璇存槑搴旂敤绋嬪簭 + + + + + + diff --git a/samples/demo/res/demo.rc2 b/samples/demo/res/demo.rc2 new file mode 100644 index 000000000..d880292a8 --- /dev/null +++ b/samples/demo/res/demo.rc2 @@ -0,0 +1,13 @@ +// +// demo.RC2 - Microsoft Visual C++ 不会直接编辑的资源 +// + +#ifdef APSTUDIO_INVOKED +#error 此文件不能由 Microsoft Visual C++ 编辑 +#endif //APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// 在此处添加手动编辑的资源... + +///////////////////////////////////////////////////////////////////////////// diff --git a/samples/demo/resource.h b/samples/demo/resource.h new file mode 100644 index 000000000..c0e33d219 --- /dev/null +++ b/samples/demo/resource.h @@ -0,0 +1,21 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by demo.rc +// +#define IDM_ABOUTBOX 0x0010 +#define IDD_ABOUTBOX 100 +#define IDS_ABOUTBOX 101 +#define IDD_DEMO_DIALOG 102 +#define IDR_MAINFRAME 128 +#define IDC_BUTTON1 1000 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 129 +#define _APS_NEXT_COMMAND_VALUE 32771 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/samples/demo/stdafx.cpp b/samples/demo/stdafx.cpp new file mode 100644 index 000000000..f05b7366a --- /dev/null +++ b/samples/demo/stdafx.cpp @@ -0,0 +1,7 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// demo.pch 将是预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + + diff --git a/samples/demo/stdafx.h b/samples/demo/stdafx.h new file mode 100644 index 000000000..65d67fe11 --- /dev/null +++ b/samples/demo/stdafx.h @@ -0,0 +1,44 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是经常使用但不常更改的 +// 项目特定的包含文件 + +#pragma once + +#ifndef VC_EXTRALEAN +#define VC_EXTRALEAN // 从 Windows 标头中排除不常使用的资料 +#endif + +// 如果您必须使用下列所指定的平台之前的平台,则修改下面的定义。 +// 有关不同平台的相应值的最新信息,请参考 MSDN。 +#ifndef WINVER // 允许使用 Windows 95 和 Windows NT 4 或更高版本的特定功能。 +#define WINVER 0x0400 //为 Windows98 和 Windows 2000 及更新版本改变为适当的值。 +#endif + +#ifndef _WIN32_WINNT // 允许使用 Windows NT 4 或更高版本的特定功能。 +#define _WIN32_WINNT 0x0500 //为 Windows98 和 Windows 2000 及更新版本改变为适当的值。 +#endif + +#ifndef _WIN32_WINDOWS // 允许使用 Windows 98 或更高版本的特定功能。 +#define _WIN32_WINDOWS 0x0410 //为 Windows Me 及更新版本改变为适当的值。 +#endif + +#ifndef _WIN32_IE // 允许使用 IE 4.0 或更高版本的特定功能。 +#define _WIN32_IE 0x0400 //为 IE 5.0 及更新版本改变为适当的值。 +#endif + +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // 某些 CString 构造函数将是显式的 + +// 关闭 MFC 对某些常见但经常被安全忽略的警告消息的隐藏 +#define _AFX_ALL_WARNINGS + +#include // MFC 核心和标准组件 +#include // MFC 扩展 +#include // MFC 自动化类 + +#include // Internet Explorer 4 公共控件的 MFC 支持 +#ifndef _AFX_NO_AFXCMN_SUPPORT +#include // Windows 公共控件的 MFC 支持 +#endif // _AFX_NO_AFXCMN_SUPPORT + +#include "lib_acl.h" + diff --git a/samples/dict/Makefile b/samples/dict/Makefile new file mode 100644 index 000000000..1b188747f --- /dev/null +++ b/samples/dict/Makefile @@ -0,0 +1,139 @@ +SHELL = /bin/sh +CC = gcc +#CC = g++ +AR = ar +ARFL = rv +RANLIB = ranlib + +#CFLAGS = -c -g -W -Wall -Wcast-qual -Wcast-align +CFLAGS = -c -g -W -Wall -Wcast-align \ +-Waggregate-return -Wmissing-prototypes \ +-Wpointer-arith -Werror -Wshadow -O2 \ +-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO \ +-Wno-long-long +#-Wno-long-long -DHAS_DB -D_FILE_OFFSET_BITS -D_LARGEFILE64_SOURCE +#-Wno-long-long -DHAS_DB -D__USE_FILE_OFFSET64 -D__USE_LARGEFILE64 +#-Wno-long-long -DHAS_DB -D_FILE_OFFSET_BITS +########################################################### +#Check system: +# Linux, SunOS, Solaris, BSD variants, AIX, HP-UX +SYSLIB = +RPATH = +CHECKSYSRES = @echo "Unknow system type!";exit 1 +UNIXNAME = $(shell uname -sm) +OSTYPE = $(shell uname -p) + +# For FreeBSD +ifeq ($(findstring FreeBSD, $(UNIXNAME)), FreeBSD) + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DFREEBSD -D_REENTRANT -pedantic + SYSLIB = -lpthread + RPATH = freebsd +endif + +#Path for Linux +ifeq ($(findstring Linux, $(UNIXNAME)), Linux) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DLINUX2 + SYSLIB = -lcrypt -lpthread + ifeq ($(findstring i686, $(OSTYPE)), i686) + RPATH = linux32 + endif + ifeq ($(findstring x86_64, $(OSTYPE)), x86_64) + RPATH = linux64 + endif +endif + +#Path for SunOS +ifeq ($(findstring SunOS, $(UNIXNAME)), SunOS) + ifeq ($(findstring 86, $(UNIXNAME)), 86) + SYSLIB = -lsocket -lnsl -lrt + endif + ifeq ($(findstring sun4u, $(UNIXNAME)), sun4u) + SYSLIB = -lsocket -lnsl -lrt + endif + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DSUNOS5 + ifeq ($(findstring i386, $(OSTYPE)), i386) + RPATH = sunos_x86 + endif +endif + +#Path for HP-UX +ifeq ($(findstring HP-UX, $(UNIXNAME)), HP-UX) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + SYSLIB = -lpthread + CFLAGS += -DHP_UX -DHPUX11 + PLAT_NAME=hp-ux +endif + +#Find system type. +ifneq ($(SYSPATH),) + CHECKSYSRES = @echo "System is $(shell uname -sm)" +endif +########################################################### + +ACL_PATH = ../../lib_acl +ACL_LIB = $(ACL_PATH)/lib +ACL_INC = $(ACL_PATH)/include + +PRO_PATH = ../../lib_protocol +PRO_LIB = $(PRO_PATH)/lib +PRO_INC = $(PRO_PATH)/include + +DICT_PATH = ../../lib_dict +DICT_LIB = $(DICT_PATH)/lib +DICT_INC = $(DICT_PATH)/include + +ALL_LIBS = -L$(DICT_LIB) -l_dict \ + -L$(PRO_LIB) -l_protocol \ + -L$(ACL_LIB) -l_acl \ + -ldb $(SYSLIB) + +INCLUDE = -I$(DICT_INC) -I$(ACL_INC) -I$(PRO_INC) +CFLAGS += $(INCLUDE) + +OUTPATH = . +OBJ_PATH = $(OUTPATH)/unix + +#Project's objs +SOURCES = $(wildcard unix/*.c) +OBJS = $(patsubst %.c, $(OBJ_PATH)/%.o, $(notdir $(SOURCES))) + +########################################################### + +VERSION = 1.0.0 +DATE_NOW = 20`date +%y`.`date +%m`.`date +%d` + +PROG_NAME = dictd + +.PHONY = all clean RM clean_all +COMPILE = $(CC) $(CFLAGS) + +all: RM $(PROG_NAME) + +$(PROG_NAME): $(OBJS) + $(CC) -o $(PROG_NAME) $(OBJS) $(ALL_LIBS) + +$(OBJ_PATH)/%.o: unix/%.c + $(COMPILE) $< -o $@ + +RM: + @(rm -f $(PROG_NAME)) + +clean: + rm -f $(OBJS) $(PROG_NAME) + +rebuild: clean all +clean_all: + @(make -f Makefile clean) + @(make -f Makefile.aio clean) + @(make -f Makefile.tools clean) diff --git a/samples/dict/Makefile.aio b/samples/dict/Makefile.aio new file mode 100644 index 000000000..7cf9bc6ec --- /dev/null +++ b/samples/dict/Makefile.aio @@ -0,0 +1,135 @@ +SHELL = /bin/sh +CC = gcc +#CC = g++ +AR = ar +ARFL = rv +RANLIB = ranlib + +#CFLAGS = -c -g -W -Wall -Wcast-qual -Wcast-align +CFLAGS = -c -g -W -Wall -Wcast-align \ +-Waggregate-return -Wmissing-prototypes \ +-Wpointer-arith -Werror -Wshadow -O2 \ +-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO \ +-Wno-long-long +#-Wno-long-long -DHAS_DB -D_FILE_OFFSET_BITS -D_LARGEFILE64_SOURCE +#-Wno-long-long -DHAS_DB -D__USE_FILE_OFFSET64 -D__USE_LARGEFILE64 +#-Wno-long-long -DHAS_DB -D_FILE_OFFSET_BITS +########################################################### +#Check system: +# Linux, SunOS, Solaris, BSD variants, AIX, HP-UX +SYSLIB = +RPATH = +CHECKSYSRES = @echo "Unknow system type!";exit 1 +UNIXNAME = $(shell uname -sm) +OSTYPE = $(shell uname -p) + +# For FreeBSD +ifeq ($(findstring FreeBSD, $(UNIXNAME)), FreeBSD) + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DFREEBSD -D_REENTRANT -pedantic + SYSLIB = -lpthread + RPATH = freebsd +endif + +#Path for Linux +ifeq ($(findstring Linux, $(UNIXNAME)), Linux) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DLINUX2 + SYSLIB = -lcrypt -lpthread + ifeq ($(findstring i686, $(OSTYPE)), i686) + RPATH = linux32 + endif + ifeq ($(findstring x86_64, $(OSTYPE)), x86_64) + RPATH = linux64 + endif +endif + +#Path for SunOS +ifeq ($(findstring SunOS, $(UNIXNAME)), SunOS) + ifeq ($(findstring 86, $(UNIXNAME)), 86) + SYSLIB = -lsocket -lnsl -lrt + endif + ifeq ($(findstring sun4u, $(UNIXNAME)), sun4u) + SYSLIB = -lsocket -lnsl -lrt + endif + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DSUNOS5 + ifeq ($(findstring i386, $(OSTYPE)), i386) + RPATH = sunos_x86 + endif +endif + +#Path for HP-UX +ifeq ($(findstring HP-UX, $(UNIXNAME)), HP-UX) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + SYSLIB = -lpthread + CFLAGS += -DHP_UX -DHPUX11 + PLAT_NAME=hp-ux +endif + +#Find system type. +ifneq ($(SYSPATH),) + CHECKSYSRES = @echo "System is $(shell uname -sm)" +endif +########################################################### + +ACL_PATH = ../../lib_acl +ACL_LIB = $(ACL_PATH)/lib +ACL_INC = $(ACL_PATH)/include + +PRO_PATH = ../../lib_protocol +PRO_LIB = $(PRO_PATH)/lib +PRO_INC = $(PRO_PATH)/include + +DICT_PATH = ../../lib_dict +DICT_LIB = $(DICT_PATH)/lib +DICT_INC = $(DICT_PATH)/include + +ALL_LIBS = -L$(DICT_LIB) -l_dict \ + -L$(PRO_LIB) -l_protocol \ + -L$(ACL_LIB) -l_acl \ + -ldb $(SYSLIB) + +INCLUDE = -I$(DICT_INC) -I$(ACL_INC) -I$(PRO_INC) +CFLAGS += $(INCLUDE) + +OUTPATH = . +OBJ_PATH = $(OUTPATH)/unix_aio + +#Project's objs +SOURCES = $(wildcard unix_aio/*.c) +OBJS = $(patsubst %.c, $(OBJ_PATH)/%.o, $(notdir $(SOURCES))) + +########################################################### + +VERSION = 1.0.0 +DATE_NOW = 20`date +%y`.`date +%m`.`date +%d` + +PROG_NAME = aio_dictd + +.PHONY = all clean RM +COMPILE = $(CC) $(CFLAGS) + +all: RM $(PROG_NAME) + +$(PROG_NAME): $(OBJS) + $(CC) -o $(PROG_NAME) $(OBJS) $(ALL_LIBS) + +$(OBJ_PATH)/%.o: unix_aio/%.c + $(COMPILE) $< -o $@ + +RM: + @(rm -f $(PROG_NAME)) + +clean: + rm -f $(OBJS) $(PROG_NAME) + +rebuild: clean all diff --git a/samples/dict/Makefile.tools b/samples/dict/Makefile.tools new file mode 100644 index 000000000..4f1027845 --- /dev/null +++ b/samples/dict/Makefile.tools @@ -0,0 +1,134 @@ +SHELL = /bin/sh +CC = gcc +#CC = g++ +AR = ar +ARFL = rv +RANLIB = ranlib + +CFLAGS = -c -g -W -Wall -Wcast-qual -Wcast-align \ +-Waggregate-return -Wmissing-prototypes \ +-Wpointer-arith -Werror -Wshadow -O2 \ +-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO \ +-Wno-long-long +#-Wno-long-long -DHAS_DB -D_FILE_OFFSET_BITS -D_LARGEFILE64_SOURCE +#-Wno-long-long -DHAS_DB -D__USE_FILE_OFFSET64 -D__USE_LARGEFILE64 +#-Wno-long-long -DHAS_DB -D_FILE_OFFSET_BITS +########################################################### +#Check system: +# Linux, SunOS, Solaris, BSD variants, AIX, HP-UX +SYSLIB = +CHECKSYSRES = @echo "Unknow system type!";exit 1 +UNIXNAME = $(shell uname -sm) +OSTYPE = $(shell uname -p) + +RPATH = + +# For FreeBSD +ifeq ($(findstring FreeBSD, $(UNIXNAME)), FreeBSD) + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DFREEBSD -D_REENTRANT -pedantic + SYSLIB = -lpthread +endif + +#Path for Linux +ifeq ($(findstring Linux, $(UNIXNAME)), Linux) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DLINUX2 + SYSLIB = -lcrypt -lpthread + ifeq ($(findstring i686, $(OSTYPE)), i686) + RPATH = linux32 + endif + ifeq ($(findstring x86_64, $(OSTYPE)), x86_64) + RPATH = linux64 + endif +endif + +#Path for SunOS +ifeq ($(findstring SunOS, $(UNIXNAME)), SunOS) + ifeq ($(findstring 86, $(UNIXNAME)), 86) + SYSLIB = -lsocket -lnsl -lrt + endif + ifeq ($(findstring sun4u, $(UNIXNAME)), sun4u) + SYSLIB = -lsocket -lnsl -lrt + endif + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DSUNOS5 +endif + +#Path for HP-UX +ifeq ($(findstring HP-UX, $(UNIXNAME)), HP-UX) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + SYSLIB = -lpthread + CFLAGS += -DHP_UX -DHPUX11 + PLAT_NAME=hp-ux +endif + +#Find system type. +ifneq ($(SYSPATH),) + CHECKSYSRES = @echo "System is $(shell uname -sm)" +endif +########################################################### + +ACL_PATH = ../../lib_acl +ACL_LIB = $(ACL_PATH)/lib +ACL_INC = $(ACL_PATH)/include + +DICT_PATH = ../../lib_dict +DICT_LIB = $(DICT_PATH)/lib +DICT_INC = $(DICT_PATH)/include + +CDB_PATH = ../../lib_dict/cdb +CDB_LIB = $(CDB_PATH)/lib +CDB_INC = $(CDB_PATH)/include + +TC_PATH = ../../lib_dict/tc +TC_LIB = $(TC_PATH)/lib +TC_INC = $(TC_PATH)/include + +ALL_LIBS = -L$(DICT_LIB) -l_dict \ + -L$(ACL_LIB) -l_acl \ + -ldb \ + -L$(TC_LIB) -ltokyocabinet \ + $(CDB_LIB)/cdb.a $(CDB_LIB)/buffer.a $(CDB_LIB)/byte.a $(CDB_LIB)/unix.a $(CDB_LIB)/alloc.a \ + $(SYSLIB) -lbz2 -lz -lrt -lm -lc + +INCLUDE = -I$(DICT_INC) -I$(ACL_INC) +CFLAGS += $(INCLUDE) + +OUTPATH = . +OBJ_PATH = $(OUTPATH)/tools + +#Project's objs +SOURCES = $(wildcard tools/*.c) +OBJS = $(patsubst %.c, $(OBJ_PATH)/%.o, $(notdir $(SOURCES))) + +########################################################### + +PROG_NAME = dict_tools + +.PHONY = all clean RM +COMPILE = $(CC) $(CFLAGS) + +all: RM $(PROG_NAME) + +$(PROG_NAME): $(OBJS) + $(CC) -o $(PROG_NAME) $(OBJS) $(ALL_LIBS) + +$(OBJ_PATH)/%.o: tools/%.c + $(COMPILE) $< -o $@ + +RM: + @(rm -f $(PROG_NAME)) + +clean: + rm -f $(OBJS) $(PROG_NAME) + +rebuild: clean all diff --git a/samples/dict/aio_dictd.conf b/samples/dict/aio_dictd.conf new file mode 100644 index 000000000..eff7c738e --- /dev/null +++ b/samples/dict/aio_dictd.conf @@ -0,0 +1,86 @@ + +service server { +# 进程是否禁止运行 + master_disable = no +# 服务地址及端口号 + master_service = 5200 + +# 服务监听为域套接口 +# master_service = aio_echo.sock +# 服务类型 + master_type = inet + +# 当子进程异常退出时,如果该值非空,则将子进程异常退出的消息通知该服务 +# master_notify_addr = 127.0.0.1:5801 + +# 是否允许延迟接受客户端连接,如果为0则表示关闭该功能,如果大于0则表示打开此功能 +# 并且此值代表延迟接受连接的超时值,超过此值时如果客户端依然没有发来数据,则操作 +# 系统会在系统层直接关闭该连接 +# master_defer_accept = 0 +# master_type = unix +# 是否只允许私有访问, 如果为 y, 则域套接口创建在 /opt/acl/dev/var/log/private/ 目录下, +# 如果为 n, 则域套接口创建在 /opt/acl/dev/var/log/public/ 目录下, + master_private = n + master_unpriv = n +# 是否需要 chroot: n -- no, y -- yes + master_chroot = n +# 每隔多长时间触发一次,单位为秒(仅对 trigger 模式有效) + master_wakeup = - +# 最大进程数 + master_maxproc = 5 +# 进程程序名 + master_command = aio_dictd +# 进程启动参数,只能为: -u [是否允许以某普通用户的身份运行] + master_args = +# 传递给服务子进程的环境变量, 可以通过 getenv("SERVICE_ENV") 获得此值 + master_env = mempool_limit:512000000, mempool_use_mutex:true +# master_env = logme:FALSE, priority:E_LOG_INFO, action:E_LOG_PER_DAY, flush:sync_flush, imit_size:512,\ +# sync_action:E_LOG_SEM, sem_name:/tmp/aio_echo.sem +# 进程日志记录文件 + master_log = /opt/acl/dev/var/log/aio_dictd.log + +# 每个进程实例处理连接数的最大次数,超过此值后进程实例主动退出 + aio_use_limit = 0 +# 每个进程实例的空闲超时时间,超过此值后进程实例主动退出 + aio_idle_limit = 0 +# 记录进程PID的位置(对于多进程实例来说没有意义) + aio_pid_dir = /opt/acl/dev/var/pid +# 进程运行时所在的路径 + aio_queue_dir = /opt/acl/dev/var +# 读写超时时间, 单位为秒 + aio_rw_timeout = 120 +# 读缓冲区的缓冲区大小 + aio_buf_size = 8192 +# 每次 accept 时的循环接收的最大次数 + aio_max_accept = 25 +# 进程运行时的用户身份 + aio_owner = root + +# 用 select 进行循环时的时间间隔 +# 单位为秒 + aio_delay_sec = 1 +# 单位为微秒 + aio_delay_usec = 500 +# 采用事件循环的方式: select(default), poll, kernel + aio_event_mode = select + +# 线程池的最大线程数, 如果该值为0则表示采用单线程非阻塞模式. + aio_max_threads = 0 +# 每个线程的空闲时间. + aio_thread_idle_limit = 60 + +# 允许访问的客户端IP地址范围 + aio_access_allow = 127.0.0.1:255.255.255.255, 127.0.0.1:127.0.0.1 + +############################################################################ +# 应用自己的配置选项 + +# 是否输出当前的内存状态信息 + debug_mem = 0 + + db_names = default:2 + db_path = dbpath + rw_timeout = 1200 + use_bdb = 0 +} + diff --git a/samples/dict/aio_dictd.conf.tmpl b/samples/dict/aio_dictd.conf.tmpl new file mode 100644 index 000000000..d9ff40d29 --- /dev/null +++ b/samples/dict/aio_dictd.conf.tmpl @@ -0,0 +1,83 @@ + +service server { +# 进程是否禁止运行 + master_disable = yes +# 服务地址及端口号 + master_service = 5200 + +# 服务监听为域套接口 +# master_service = aio_echo.sock +# 服务类型 + master_type = inet + +# 当子进程异常退出时,如果该值非空,则将子进程异常退出的消息通知该服务 +# master_notify_addr = 127.0.0.1:5801 + +# 是否允许延迟接受客户端连接,如果为0则表示关闭该功能,如果大于0则表示打开此功能 +# 并且此值代表延迟接受连接的超时值,超过此值时如果客户端依然没有发来数据,则操作 +# 系统会在系统层直接关闭该连接 +# master_defer_accept = 0 +# master_type = unix +# 是否只允许私有访问, 如果为 y, 则域套接口创建在 {install_path}/var/log/private/ 目录下, +# 如果为 n, 则域套接口创建在 {install_path}/var/log/public/ 目录下, + master_private = n + master_unpriv = n +# 是否需要 chroot: n -- no, y -- yes + master_chroot = n +# 每隔多长时间触发一次,单位为秒(仅对 trigger 模式有效) + master_wakeup = - +# 最大进程数 + master_maxproc = 5 +# 进程程序名 + master_command = aio_echo +# 进程启动参数,只能为: -u [是否允许以某普通用户的身份运行] + master_args = +# 传递给服务子进程的环境变量, 可以通过 getenv("SERVICE_ENV") 获得此值 + master_env = mempool_limit:512000000, mempool_use_mutex:true +# master_env = logme:FALSE, priority:E_LOG_INFO, action:E_LOG_PER_DAY, flush:sync_flush, imit_size:512,\ +# sync_action:E_LOG_SEM, sem_name:/tmp/aio_echo.sem +# 进程日志记录文件 + master_log = {install_path}/var/log/aio_echo.log + +# 每个进程实例处理连接数的最大次数,超过此值后进程实例主动退出 + aio_use_limit = 0 +# 每个进程实例的空闲超时时间,超过此值后进程实例主动退出 + aio_idle_limit = 0 +# 记录进程PID的位置(对于多进程实例来说没有意义) + aio_pid_dir = {install_path}/var/pid +# 进程运行时所在的路径 + aio_queue_dir = {install_path}/var +# 读写超时时间, 单位为秒 + aio_rw_timeout = 120 +# 读缓冲区的缓冲区大小 + aio_buf_size = 8192 +# 每次 accept 时的循环接收的最大次数 + aio_max_accept = 25 +# 进程运行时的用户身份 + aio_owner = root + +# 用 select 进行循环时的时间间隔 +# 单位为秒 + aio_delay_sec = 1 +# 单位为微秒 + aio_delay_usec = 500 + +# 线程池的最大线程数, 如果该值为0则表示采用单线程非阻塞模式. + aio_max_threads = 0 +# 每个线程的空闲时间. + aio_thread_idle_limit = 60 + +# 允许访问的客户端IP地址范围 + aio_access_allow = 127.0.0.1:255.255.255.255, 127.0.0.1:127.0.0.1 + +############################################################################ +# 应用自己的配置选项 + +# 是否输出当前的内存状态信息 + debug_mem = 0 + + db_names = default:2 + db_path = dbpath + rw_timeout = 1200 +} + diff --git a/samples/dict/dictd.conf b/samples/dict/dictd.conf new file mode 100644 index 000000000..73358c09d --- /dev/null +++ b/samples/dict/dictd.conf @@ -0,0 +1,107 @@ + +service server { +# 进程是否禁止运行 + master_disable = no +# 服务地址及端口号 + master_service = :8082 + +# 服务监听为域套接口 +# master_service = aio_echo.sock +# 服务类型 + master_type = inet +# master_type = unix + +# 当子进程异常退出时,如果该值非空,则将子进程异常退出的消息通知该服务 +# master_notify_addr = 127.0.0.1:5801 + +# 是否允许延迟接受客户端连接,如果为0则表示关闭该功能,如果大于0则表示打开此功能 +# 并且此值代表延迟接受连接的超时值,超过此值时如果客户端依然没有发来数据,则操作 +# 系统会在系统层直接关闭该连接 +# master_defer_accept = 0 +# 是否只允许私有访问, 如果为 y, 则域套接口创建在 ./var/log/private/ 目录下, +# 如果为 n, 则域套接口创建在 ./var/log/public/ 目录下, + master_private = n + master_unpriv = n +# 是否需要 chroot: n -- no, y -- yes + master_chroot = n +# 每隔多长时间触发一次,单位为秒(仅对 trigger 模式有效) + master_wakeup = - +# 最大进程数 + master_maxproc = 1 +# 进程程序名 + master_command = dictd +# 进程日志记录文件 + master_log = ./var/log/dictd.log +# 进程启动参数,只能为: -u [是否允许以某普通用户的身份运行] +# master_args = +# 传递给服务子进程的环境变量, 可以通过 getenv("SERVICE_ENV") 获得此值 + master_env = mempool_limit:512000000 +# master_env = logme:FALSE, priority:E_LOG_INFO, action:E_LOG_PER_DAY, flush:sync_flush, imit_size:512,\ +# sync_action:E_LOG_SEM, sem_name:/tmp/ioctl_echo.sem + +# 每个进程实例处理连接数的最大次数,超过此值后进程实例主动退出 + ioctl_use_limit = 100 +# 每个进程实例的空闲超时时间,超过此值后进程实例主动退出 + ioctl_idle_limit = 120 +# 记录进程PID的位置(对于多进程实例来说没有意义) + ioctl_pid_dir = ./var/pid +# 进程运行时所在的路径 + ioctl_queue_dir = ./var +# 读写超时时间, 单位为秒 + ioctl_rw_timeout = 120 +# 读缓冲区的缓冲区大小 + ioctl_buf_size = 8192 +# 每次 accept 时的循环接收的最大次数 + ioctl_max_accept = 25 +# 在并发访问量非常低的情况下,如访问量在 10 次/秒 以下时,可以找开此值(即赋为1),以加速事件循环过程, +# 从而防止服务进程阻塞在 select 上的时间过长而影响访问速度 +# ioctl_enable_dog = 0 +# 进程运行时的用户身份 + ioctl_owner = root + +# 用 select 进行循环时的时间间隔 +# 单位为秒 + ioctl_delay_sec = 0 +# 单位为微秒 + ioctl_delay_usec = 500 + +# 线程池的最大线程数 + ioctl_max_threads = 250 +# 线程的堆栈空间大小,单位为字节,0表示使用系统缺省值 + ioctl_stacksize = 0 +# 允许访问 udserver 的客户端IP地址范围 + ioctl_access_allow = 127.0.0.1:255.255.255.255, 127.0.0.1:127.0.0.1 + +## app_main.c 需要的参数项 +# 客户端连接的最大空闲时间阀值 + app_client_idle_limit = 12 + +############################################################################ +# 应用自己的配置选项 + +# mysql 服务地址 +# mysql_dbaddr = /tmp/mysql.sock +# mysql_dbaddr = 10.0.250.199:3306 +# 连接 mysql 数据库的连接池的最大值 +# mysql_dbmax = 200 +# ping mysql 连接的间隔时间, 以秒为单位 +# mysql_dbping = 10 +# mysql 连接空闲的时间间隔, 以秒为单位 +# mysql_dbtimeout = 30 + +# 数据库名称 +# mysql_dbname = ioctl_db +# 数据库访问用户 +# mysql_dbuser = ioctl_user +# 数据库用户访问密码 +# mysql_dbpass = 111111 + +# 是否输出当前内存的状态信息 + debug_mem = 0 + + db_names = default:2 + db_path = dbpath + rw_timeout = 1200 + use_bdb = 0 +} + diff --git a/samples/dict/dictd.conf.tmpl b/samples/dict/dictd.conf.tmpl new file mode 100644 index 000000000..4a43bfed1 --- /dev/null +++ b/samples/dict/dictd.conf.tmpl @@ -0,0 +1,106 @@ + +service server { +# 进程是否禁止运行 + master_disable = no +# 服务地址及端口号 + master_service = :8082 + +# 服务监听为域套接口 +# master_service = aio_echo.sock +# 服务类型 + master_type = inet +# master_type = unix + +# 当子进程异常退出时,如果该值非空,则将子进程异常退出的消息通知该服务 +# master_notify_addr = 127.0.0.1:5801 + +# 是否允许延迟接受客户端连接,如果为0则表示关闭该功能,如果大于0则表示打开此功能 +# 并且此值代表延迟接受连接的超时值,超过此值时如果客户端依然没有发来数据,则操作 +# 系统会在系统层直接关闭该连接 +# master_defer_accept = 0 +# 是否只允许私有访问, 如果为 y, 则域套接口创建在 {install_path}/var/log/private/ 目录下, +# 如果为 n, 则域套接口创建在 {install_path}/var/log/public/ 目录下, + master_private = n + master_unpriv = n +# 是否需要 chroot: n -- no, y -- yes + master_chroot = n +# 每隔多长时间触发一次,单位为秒(仅对 trigger 模式有效) + master_wakeup = - +# 最大进程数 + master_maxproc = 1 +# 进程程序名 + master_command = dictd +# 进程日志记录文件 + master_log = {install_path}/var/log/dictd.log +# 进程启动参数,只能为: -u [是否允许以某普通用户的身份运行] +# master_args = +# 传递给服务子进程的环境变量, 可以通过 getenv("SERVICE_ENV") 获得此值 + master_env = mempool_limit:512000000 +# master_env = logme:FALSE, priority:E_LOG_INFO, action:E_LOG_PER_DAY, flush:sync_flush, imit_size:512,\ +# sync_action:E_LOG_SEM, sem_name:/tmp/ioctl_echo.sem + +# 每个进程实例处理连接数的最大次数,超过此值后进程实例主动退出 + ioctl_use_limit = 100 +# 每个进程实例的空闲超时时间,超过此值后进程实例主动退出 + ioctl_idle_limit = 120 +# 记录进程PID的位置(对于多进程实例来说没有意义) + ioctl_pid_dir = {install_path}/var/pid +# 进程运行时所在的路径 + ioctl_queue_dir = {install_path}/var +# 读写超时时间, 单位为秒 + ioctl_rw_timeout = 120 +# 读缓冲区的缓冲区大小 + ioctl_buf_size = 8192 +# 每次 accept 时的循环接收的最大次数 + ioctl_max_accept = 25 +# 在并发访问量非常低的情况下,如访问量在 10 次/秒 以下时,可以找开此值(即赋为1),以加速事件循环过程, +# 从而防止服务进程阻塞在 select 上的时间过长而影响访问速度 +# ioctl_enable_dog = 0 +# 进程运行时的用户身份 + ioctl_owner = root + +# 用 select 进行循环时的时间间隔 +# 单位为秒 + ioctl_delay_sec = 0 +# 单位为微秒 + ioctl_delay_usec = 500 + +# 线程池的最大线程数 + ioctl_max_threads = 250 +# 线程的堆栈空间大小,单位为字节,0表示使用系统缺省值 + ioctl_stacksize = 0 +# 允许访问 udserver 的客户端IP地址范围 + ioctl_access_allow = 127.0.0.1:255.255.255.255, 127.0.0.1:127.0.0.1 + +## app_main.c 需要的参数项 +# 客户端连接的最大空闲时间阀值 + app_client_idle_limit = 12 + +############################################################################ +# 应用自己的配置选项 + +# mysql 服务地址 +# mysql_dbaddr = /tmp/mysql.sock +# mysql_dbaddr = 10.0.250.199:3306 +# 连接 mysql 数据库的连接池的最大值 +# mysql_dbmax = 200 +# ping mysql 连接的间隔时间, 以秒为单位 +# mysql_dbping = 10 +# mysql 连接空闲的时间间隔, 以秒为单位 +# mysql_dbtimeout = 30 + +# 数据库名称 +# mysql_dbname = ioctl_db +# 数据库访问用户 +# mysql_dbuser = ioctl_user +# 数据库用户访问密码 +# mysql_dbpass = 111111 + +# 是否输出当前内存的状态信息 + debug_mem = 0 + + db_names = default:2 + db_path = dbpath + rw_timeout = 1200 +} + diff --git a/samples/dict/docs/test.txt b/samples/dict/docs/test.txt new file mode 100644 index 000000000..dd6f7e197 --- /dev/null +++ b/samples/dict/docs/test.txt @@ -0,0 +1,5 @@ +http://60.28.251.93:8082/test?dbname=default&key=test1&action=get +http://60.28.251.93:8082/test?dbname=default&key=test1&value=testsdfsssdfdfsssdfdsdsffsssdfddfsssdfdsdsffsssdfddfsssdfdsdsffsssdfddfsssdfdsdsffsssdfddfsssdfdsdsffsssdfddfsssdfdsdsffsssdfddfsssdfdsdsffsssdfddfsssdfdsdsffsssdfddfsssdfdsdsffsssdfddfsssdfdsdsffsssdfddfsssdfdsdsffsssdfddfsssdfdsdsffsssdfddfsssdfdsdsffsssdfddfsssdfdsdsffsssdfddfsssdfdsdsffsssdfddfsssdfdsdsffsssdfddfsssdfdsdsffsssdfddfsssdfdsdsffsssdfddfsssdfdsdsffsssdfddfsssdfdsdsffsssdfddfsssdfdsdsffsssdfddfsssdfdsdsffsssdfddfsssdfdsdsffsssdfddfsssdfdsdsffsssdfddfsssdfdsdsffsssdfddfsssdfdsdsffsssdfddfsssdfdsdsffsssdfddfsssdfdsdsffsssdfddfsssdfdsdsffsssdfddfsssdfdsdsffsssdfddfsssdfdsdsffsssdfddfsssdfdsdsffsssdfddfsssdfdsdsffsssdfddfsssdfdsdsffsssdfddfsssdfdsdsffsssdfddfsssdfdsdsffsssdfddfsssdfdsdsffsssdfddfsssdfdsdsffsssdfddfsssdfdsdsffsssdfddfsssdfdsdsffsssdfddfsssdfdsdsffsssdfddfsssdfdsdsffsssdfddsdsffsssdfdsdsfsssdfdsdsfsssdfdsdsfsssdfdsdsfsssdfdsdsfsssdfdsdssdfdsfdsfsdfsdfsdfsdfsdfsdfsdfsdfsfsfsdfsdfsdfsfsdfsdfdsfdsfdsfsdfsdfsdfsdfsdfdsfsdfdsdfsfsdfgfdgfdgfdgdfgdgdgdgdgdgdgdgdgdgdgdgfsfsdfsdfsdfsfsdfsdfsdfsd4&action=set + +./ab -n 1000000 -c 1000 -k "http://127.0.0.1:8083/test?dbname=default&action=get&key=test" +./ab -n 1000000 -c 1000 -k "http://127.0.0.1:8083/test?dbname=default&action=set&key=test&value=test" diff --git a/samples/dict/tools/dict_number.c b/samples/dict/tools/dict_number.c new file mode 100644 index 000000000..847a7605f --- /dev/null +++ b/samples/dict/tools/dict_number.c @@ -0,0 +1,155 @@ +/* + * Proof-of-concept test program. Create, update or read a database. When + * the input is a name=value pair, the database is updated, otherwise the + * program assumes that the input specifies a lookup key and prints the + * corresponding value. + */ + +/* System library. */ +#include "lib_acl.h" +#include +#include +#include +#ifdef ACL_UNIX +#include +#include +#endif +#include "dict.h" +#include "unescape.h" +#include "dict_test.h" +#include "md5.h" + +#ifdef ACL_MS_WINDOWS +#include +#define isatty _isatty +#endif + +#define STR acl_vstring_str +#define LEN ACL_VSTRING_LEN + +void dict_number_main(int max) +{ +#if 0 + char *dict_name = "btree:./var/test"; +#elif 0 + char *dict_name = "tc:*#bnum=10000000"; +#elif 0 + char *dict_name = "tc:+#capnum=10000000"; +#elif 0 + char *dict_name = "tc:./var/test.tch"; +#elif 0 + char *dict_name = "tc:./var/test.tcb"; +#elif 0 + char *dict_name = "tc:./var/test.tct"; +#else + char *dict_name = "tc:./var/test.10000.tcf#width=12#limsiz=2684354560"; +#endif + int open_flags = 0; + int dict_flags = /* DICT_FLAG_LOCK | */ DICT_FLAG_DUP_REPLACE | DICT_FLAG_TRY0NULL; + DICT *dict; + int i; + + char *value; + ACL_VSTRING *key_buf = acl_vstring_alloc(256); + ACL_VSTRING *value_buf = acl_vstring_alloc(256); + size_t value_size; + char buf[256]; + bool b = true; + + if (b) + b = false; + +#define ADD_BENCH1(from, to) do { \ + for (i = from; i < to; i++) { \ + acl_vstring_sprintf(key_buf, "%d:key", i); \ + acl_vstring_sprintf(value_buf, "value:%d", i); \ + dict_update(dict_name, STR(key_buf), STR(value_buf), LEN(value_buf)); \ + } \ +}while (0) + +#define ADD_BENCH2(from, to) do { \ + const char *__key = "hello world"; \ + char __buf[33]; \ + for (i = from; i < to; i++) { \ + acl_vstring_sprintf(key_buf, "%d:key", i); \ + MD5String(STR(key_buf), __key, strlen(__key), __buf, sizeof(__buf)); \ + acl_vstring_sprintf(value_buf, "value:%d", i); \ + dict_update(dict_name, __buf, STR(value_buf), LEN(value_buf)); \ + } \ +}while (0) + +#define ADD_BENCH3(from, to) do { \ + for (i = from; i < to; i++) { \ + acl_vstring_sprintf(key_buf, "%d", i); \ + acl_vstring_sprintf(value_buf, "value:%d:", i); \ + dict_update(dict_name, STR(key_buf), STR(value_buf), LEN(value_buf)); \ + } \ +}while (0) + +#define ADD_BENCH_DUMMY(from, to) + +#define ADD_BENCH ADD_BENCH3 + + acl_init(); + dict_init(); + + open_flags = O_CREAT | O_RDWR | O_TRUNC; + dict = dict_open(dict_name, open_flags, dict_flags); + dict_register(dict_name, dict); + + ACL_METER_TIME("--- begin add ---"); + + ADD_BENCH((max * 0)/10 + 1, (max * 1)/10); + ACL_METER_TIME("--- max * 0 / 10 over ---"); + + ADD_BENCH((max * 9)/10, max); + ACL_METER_TIME("--- max * 9 / 10 over ---"); + + ADD_BENCH((max * 8)/10, (max * 9)/10); + ACL_METER_TIME("--- max * 8 / 10 over ---"); + + ADD_BENCH((max * 4)/10, (max * 5)/10); + ACL_METER_TIME("--- max * 4 / 10 over ---"); + + ADD_BENCH((max * 1)/10, (max * 2)/10); + ACL_METER_TIME("--- max * 1 / 10 over ---"); + + ADD_BENCH((max * 2)/10, (max * 3)/10); + ACL_METER_TIME("--- max * 2 / 10 over ---"); + + ADD_BENCH((max * 5)/10, (max * 6)/10); + ACL_METER_TIME("--- max * 5 / 10 over ---"); + + ADD_BENCH((max * 3)/10, (max * 4)/10); + ACL_METER_TIME("--- max * 3 / 10 over ---"); + + ADD_BENCH((max * 7)/10, (max * 8)/10); + ACL_METER_TIME("--- max * 7 / 10 over ---"); + + ADD_BENCH((max * 6)/10, (max * 7)/10); + ACL_METER_TIME("--- max * 6 / 10 over ---"); + + ACL_METER_TIME("--- end add, begin get ---"); + + for (i = 1; i < max; i++) { + acl_vstring_sprintf(key_buf, "%d", i); + if (dict_lookup(dict_name, STR(key_buf), &value, &value_size) == NULL) { + acl_msg_error("key: (%s) no exist", STR(key_buf)); + break; + } else + acl_myfree(value); + if ((i * 10) % max == 0) { + snprintf(buf, sizeof(buf), "--- get i=%d ok ---", i); + ACL_METER_TIME(buf); + } + } + + snprintf(buf, sizeof(buf), "--- end get i=%d ok ---", i); + ACL_METER_TIME(buf); + + acl_vstring_free(key_buf); + acl_vstring_free(value_buf); + printf("unregister %s\n", dict_name); + dict_unregister(dict_name); + printf("close %s\n", dict_name); +} diff --git a/samples/dict/tools/dict_test.c b/samples/dict/tools/dict_test.c new file mode 100644 index 000000000..b83df2ebc --- /dev/null +++ b/samples/dict/tools/dict_test.c @@ -0,0 +1,236 @@ +/* + * Proof-of-concept test program. Create, update or read a database. When + * the input is a name=value pair, the database is updated, otherwise the + * program assumes that the input specifies a lookup key and prints the + * corresponding value. + */ + +/* System library. */ +#include "lib_acl.h" +#include +#include +#ifdef ACL_UNIX +#include +#include +#endif +#include "dict.h" +#include "unescape.h" +#include "dict_test.h" + +#ifdef ACL_MS_WINDOWS +#include +#define isatty _isatty +#endif + +static void dict_test1(const char *dict_name, int open_flags, int dict_flags); +static void dict_test2(const char *dict_name, int open_flags, int dict_flags); + +static void usage(char *myname) +{ + acl_msg_fatal("usage: %s -o test type:file read|write|create [fold]", myname); +} + +static void help(void) +{ + acl_vstream_printf("usage: del key|get key|put key=value|first|next|exit\r\n"); +} + +int dict_test_main(int argc, char **argv) +{ + char *dict_name; + int open_flags = 0; + int dict_flags = /* DICT_FLAG_LOCK | */ DICT_FLAG_DUP_REPLACE; + int ch; + + /* + * signal(SIGPIPE, SIG_IGN); + */ + + acl_init(); + + while ((ch = getopt(argc, argv, "v")) > 0) { + switch (ch) { + default: + usage(argv[0]); + case 'v': + break; + } + } + + if (argc - optind < 2 || argc - optind > 3) + usage(argv[0]); + if (strcasecmp(argv[optind + 1], "create") == 0) + open_flags = O_CREAT | O_RDWR; /* | O_TRUNC */ + else if (strcasecmp(argv[optind + 1], "write") == 0) + open_flags = O_RDWR; + else if (strcasecmp(argv[optind + 1], "read") == 0) + open_flags = O_RDONLY; + else + acl_msg_fatal("unknown access mode: %s", argv[2]); + if (argv[optind + 2] && strcasecmp(argv[optind + 2], "fold") == 0) + dict_flags |= DICT_FLAG_FOLD_ANY; + dict_name = argv[optind]; + + if (0) + dict_test1(dict_name, open_flags, dict_flags); + else + dict_test2(dict_name, open_flags, dict_flags); + return (0); +} + +static void dict_test1(const char *dict_name, int open_flags, int dict_flags) +{ + char *bufp; + char *cmd; + char *key; + char *value; + ACL_VSTRING *keybuf = acl_vstring_alloc(1); + ACL_VSTRING *inbuf = acl_vstring_alloc(1); + DICT *dict; + size_t key_size, value_size; + + dict_open_init(); + dict = dict_open(dict_name, open_flags, dict_flags); + + while (1) { + acl_vstream_printf("Please input: "); + if (acl_vstring_fgets_nonl(inbuf, ACL_VSTREAM_IN) == NULL) + break; + bufp = acl_vstring_str(inbuf); + if (!isatty(0)) { + acl_vstream_printf("> %s\n", bufp); + } + if (*bufp == '#') + continue; + if ((cmd = acl_mystrtok(&bufp, " ")) == 0) { + help(); + continue; + } + if (dict_changed_name()) + acl_msg_warn("dictionary has changed"); + key = *bufp ? acl_vstring_str(unescape(keybuf, acl_mystrtok(&bufp, " ="))) : 0; + value = acl_mystrtok(&bufp, " ="); + if (strcmp(cmd, "exit") == 0) + break; + else if (strcmp(cmd, "del") == 0 && key && !value) { + if (DICT_DEL(dict, key, strlen(key))) + acl_vstream_printf("%s: not found\n", key); + else + acl_vstream_printf("%s: deleted\n", key); + } else if (strcmp(cmd, "get") == 0 && key && !value) { + if (DICT_GET(dict, key, strlen(key), &value, &value_size) == NULL) { + acl_vstream_printf("%s: %s\n", key, + dict_errno == DICT_ERR_RETRY ? "soft error" : "not found"); + } else { + acl_vstream_printf("%s=%s\n", key, value); + acl_myfree(value); + } + } else if (strcmp(cmd, "put") == 0 && key && value) { + DICT_PUT(dict, key, strlen(key), value, strlen(value)); + acl_vstream_printf("%s=%s\n", key, value); + } else if (strcmp(cmd, "first") == 0 && !key && !value) { + if (DICT_SEQ(dict, DICT_SEQ_FUN_FIRST, &key, &key_size, + &value, &value_size) == 0) { + acl_vstream_printf("%s=%s\n", key, value); + acl_myfree(key); + acl_myfree(value); + } else + acl_vstream_printf("%s\n", + dict_errno == DICT_ERR_RETRY ? "soft error" : "not found"); + } else if (strcmp(cmd, "next") == 0 && !key && !value) { + if (DICT_SEQ(dict, DICT_SEQ_FUN_NEXT, &key, &key_size, &value, &value_size) == 0) { + acl_vstream_printf("%s=%s\n", key, value); + acl_myfree(key); + acl_myfree(value); + } else { + acl_vstream_printf("%s\n", + dict_errno == DICT_ERR_RETRY ? "soft error" : "not found"); + } + } else { + help(); + } + } + acl_vstring_free(keybuf); + acl_vstring_free(inbuf); + DICT_CLOSE(dict); +} + +static void dict_test2(const char *dict_name, int open_flags, int dict_flags) +{ + char *bufp; + char *cmd; + char *key; + char *value; + ACL_VSTRING *keybuf = acl_vstring_alloc(1); + ACL_VSTRING *inbuf = acl_vstring_alloc(1); + DICT *dict; + size_t key_size, value_size; + + dict_init(); + + dict = dict_open(dict_name, open_flags, dict_flags); + dict_register(dict_name, dict); + + while (1) { + acl_vstream_printf("Please input: "); + if (acl_vstring_fgets_nonl(inbuf, ACL_VSTREAM_IN) == NULL) + break; + bufp = acl_vstring_str(inbuf); + if (!isatty(0)) { + acl_vstream_printf("> %s\n", bufp); + } + if (*bufp == '#') + continue; + if ((cmd = acl_mystrtok(&bufp, " ")) == 0) { + help(); + continue; + } + if (dict_changed_name()) + acl_msg_warn("dictionary has changed"); + key = *bufp ? acl_vstring_str(unescape(keybuf, acl_mystrtok(&bufp, " ="))) : 0; + value = acl_mystrtok(&bufp, " ="); + if (strcmp(cmd, "exit") == 0) + break; + else if (strcmp(cmd, "del") == 0 && key && !value) { + if (dict_delete(dict_name, key)) + acl_vstream_printf("%s: not found\n", key); + else + acl_vstream_printf("%s: deleted\n", key); + } else if (strcmp(cmd, "get") == 0 && key && !value) { + if (dict_lookup(dict_name, key, &value, &value_size) == NULL) { + acl_vstream_printf("%s: %s\n", key, + dict_errno == DICT_ERR_RETRY ? "soft error" : "not found"); + } else { + acl_vstream_printf("%s=%s\n", key, value); + acl_myfree(value); + } + } else if (strcmp(cmd, "put") == 0 && key && value) { + dict_update(dict_name, key, value, strlen(value)); + acl_vstream_printf("%s=%s\n", key, value); + } else if (strcmp(cmd, "first") == 0 && !key && !value) { + if (dict_sequence(dict_name, DICT_SEQ_FUN_FIRST, &key, &key_size, + &value, &value_size) == 0) { + acl_vstream_printf("%s=%s\n", key, value); + acl_myfree(key); + acl_myfree(value); + } else + acl_vstream_printf("%s\n", + dict_errno == DICT_ERR_RETRY ? "soft error" : "not found"); + } else if (strcmp(cmd, "next") == 0 && !key && !value) { + if (dict_sequence(dict_name, DICT_SEQ_FUN_NEXT, &key, &key_size, + &value, &value_size) == 0) { + acl_vstream_printf("%s=%s\n", key, value); + acl_myfree(key); + acl_myfree(value); + } else { + acl_vstream_printf("%s\n", + dict_errno == DICT_ERR_RETRY ? "soft error" : "not found"); + } + } else { + help(); + } + } + acl_vstring_free(keybuf); + acl_vstring_free(inbuf); + dict_unregister(dict_name); +} diff --git a/samples/dict/tools/dict_test.h b/samples/dict/tools/dict_test.h new file mode 100644 index 000000000..6b9c94fcb --- /dev/null +++ b/samples/dict/tools/dict_test.h @@ -0,0 +1,10 @@ +#ifndef __DICT_TEST_INCLUDE_H__ +#define __DICT_TEST_INCLUDE_H__ + +/* dict_test.c */ +int dict_test_main(int argc, char **argv); + +/* dict_number.c */ +void dict_number_main(int max); + +#endif diff --git a/samples/dict/tools/main.c b/samples/dict/tools/main.c new file mode 100644 index 000000000..8943e0140 --- /dev/null +++ b/samples/dict/tools/main.c @@ -0,0 +1,436 @@ +#include "lib_acl.h" +#include +#include "dict_pool.h" +#include "md5.h" +#include "dict_test.h" + +static int __add = 0, __search = 0, __seq = 0, __seqdel = 0, __sort = 0; +static acl_pthread_pool_t *__thrpool = NULL; +static acl_pthread_mutex_t __lock; +static int __thrcnt = 32, __begin = 0, __max = 10000, __dbcnt = 6; +static int __value_size = 100; +static int __nwrite = 0, __nread = 0; +static int __report_base = 10000; +static char __key_pre[] = "key5key5key5key5key5key5key5key5key5key5key5key5key5key5"; +static DICT_POOL *__dict_pool; + +#define LOCK acl_pthread_mutex_lock(&__lock) +#define UNLOCK acl_pthread_mutex_unlock(&__lock) + +static const char *__partions[] = { + "./cache1", + "./cache2", + "./cache3", + "./cache4" +}; +static int __partions_size = 4; + +static void init(const char *dict_type, const char *dict_path, const char *dict_name) +{ + acl_init(); + + __thrpool = acl_thread_pool_create(__thrcnt, 5); + dict_pool_init(); + __dict_pool = dict_pool_new(__partions, __partions_size, dict_type, + dict_path, dict_name, __dbcnt); +} + +static void end(void) +{ + printf("input any key to close db\r\n"); + getchar(); + if (__dict_pool) + dict_pool_free(__dict_pool); +} + +#define STR acl_vstring_str +#define LEN ACL_VSTRING_LEN + +typedef struct KEY { + char *key; +} KEY; + +static int cmp_fn(const void *ptr1, const void *ptr2) +{ + const KEY *key1 = (const KEY*) ptr1; + const KEY *key2 = (const KEY*) ptr2; + + return (strcmp(key1->key, key2->key)); +} + +static void thread_write_fn(void *arg) +{ + char *id = (char*) arg; + char key[256], buf[256]; + ACL_VSTRING *value = acl_vstring_alloc(__value_size); + time_t begin, last, now; + DICT_POOL_DB *db; + int i, n, j; + KEY *key_array; + + key_array = (KEY*) acl_mycalloc(__max, sizeof(KEY)); + + n = __value_size; + acl_vstring_sprintf(value, "%u:", (unsigned) acl_pthread_self()); + n -= LEN(value); + for (i = 0; i < n; i++) + ACL_VSTRING_ADDCH(value, 'v'); + ACL_VSTRING_TERMINATE(value); + + time(&begin); + last = begin; + for (j = 0, i = __begin; i < __begin + __max; i++) { + snprintf(buf, sizeof(buf), "%s:%s:%d", __key_pre, id, i); +#if 0 + MDString(buf, key, sizeof(key)); +#else + acl_uint64 k = acl_hash_crc64(buf, strlen(buf)); + snprintf(key, sizeof(key), "%llu", k); +#endif + key_array[j++].key = acl_mystrdup(key); + } + + if (__max <= 100) { + printf("before sort\n"); + for (i = 0; i < __max; i++) { + printf("key[%d]: %s\n", i, key_array[i].key); + } + } + + if (__sort) + qsort(key_array, __max, sizeof(KEY), cmp_fn); + + if (__max <= 100) { + printf("after sort\n"); + for (i = 0; i < __max; i++) { + printf("key[%d]: %s\n", i, key_array[i].key); + } + } + + for (i = 0; i < __max; i++) { + char *ptr; + size_t size; + + db = dict_pool_db(__dict_pool, key_array[i].key, strlen(key_array[i].key)); + dict_pool_db_lock(db); + ptr = dict_pool_db_get(db, key_array[i].key, strlen(key_array[i].key), &size); + if (ptr != NULL) { + printf("key: %s exist now, size: %d\n", key_array[i].key, (int) size); + acl_myfree(ptr); + } + dict_pool_db_set(db, key_array[i].key, strlen(key_array[i].key), STR(value), LEN(value)); + + ptr = dict_pool_db_get(db, key_array[i].key, strlen(key_array[i].key), &size); + if (ptr == NULL) { + printf("key: %s not add into db\n", key_array[i].key); + } else + acl_myfree(ptr); + dict_pool_db_unlock(db); + + if (i > 0 && i % __report_base == 0) { + time(&now); + printf("thread %u add one, i=%d, time=%ld, key=%s\r\n", + (unsigned) acl_pthread_self(), i, now - last, key_array[i].key); + last = now; + } + LOCK; + __nwrite++; + UNLOCK; + } + + for (i = 0; i < __max; i++) { + acl_myfree(key_array[i].key); + } + acl_myfree(key_array); + acl_vstring_free(value); + acl_myfree(id); + printf("thread %u add over, i=%d, time=%ld\r\n", + (unsigned) acl_pthread_self(), i, time(NULL) - begin); +} + +static void thread_read_fn(void *arg) +{ + char *id = (char*) arg; + char key[256], *value, buf[256]; + size_t value_size; + time_t begin, last, now; + DICT_POOL_DB *db; + int i; + + time(&begin); + last = begin; + for (i = __begin; i < __begin + __max; i++) { + snprintf(buf, sizeof(buf), "%s:%s:%i", __key_pre, id, i); + acl_uint64 k = acl_hash_crc64(buf, strlen(buf)); + snprintf(key, sizeof(key), "%llu", k); + + db = dict_pool_db(__dict_pool, key, strlen(key)); + dict_pool_db_lock(db); + value = dict_pool_db_get(db, key, strlen(key), &value_size); + dict_pool_db_unlock(db); + + if (value == NULL) { + acl_vstream_printf("%s: %s\n", key, + dict_errno == DICT_ERR_RETRY ? "soft error" : "not found"); + } else { + if (i > 0 && i % __report_base == 0) { + time(&now); + printf(">>key=%s, time=%ld\r\n", key, now - last); + last = now; + } + acl_myfree(value); + LOCK; + __nread++; + UNLOCK; + } + } + printf("thread %u read over, i=%d, time=%ld\r\n", + (unsigned) acl_pthread_self(), i, time(NULL) - begin); + acl_myfree(id); +} + +static void thread_seq_fn(void *arg acl_unused) +{ + char *key, *value; + size_t key_size, value_size; + time_t begin, last, now; + ACL_VSTRING *key_buf = acl_vstring_alloc(100); + int i = 0; + + time(&begin); + last = begin; + while (1) { + if (dict_pool_seq(__dict_pool, &key, &key_size, &value, &value_size) != 0) + break; + i++; + if (i > 0 && i % __report_base == 0) { + time(&now); + acl_vstring_memcpy(key_buf, key, key_size); + ACL_VSTRING_TERMINATE(key_buf); + printf(">>key: %s, time=%ld\r\n", STR(key_buf), now - last); + last = now; + } + acl_myfree(key); + acl_myfree(value); + LOCK; + __nread++; + UNLOCK; + } + + acl_vstring_free(key_buf); + printf("thread %u seq read over, i=%d, time=%ld\r\n", + (unsigned) acl_pthread_self(), i, time(NULL) - begin); +} + +static void thread_seqdel_fn(void *arg acl_unused) +{ + char *key, *value; + size_t key_size, value_size; + time_t begin, last, now; + ACL_VSTRING *key_buf = acl_vstring_alloc(100); + int i = 0; + + time(&begin); + last = begin; + while (1) { + if (dict_pool_seq(__dict_pool, &key, &key_size, &value, &value_size) != 0) + break; + i++; + if (i > 0 && i % __report_base == 0) { + time(&now); + acl_vstring_memcpy(key_buf, key, key_size); + ACL_VSTRING_TERMINATE(key_buf); + printf(">>key: %s, time=%ld\r\n", STR(key_buf), now - last); + last = now; + } + if (i > 0 && i % 2 == 0) + dict_pool_seq_delcur(__dict_pool); + free(key); + free(value); + LOCK; + __nread++; + UNLOCK; + } + + acl_vstring_free(key_buf); + printf("thread %u seq read over, i=%d, time=%ld\r\n", + (unsigned) acl_pthread_self(), i, time(NULL) - begin); +} + +static void run(void) +{ + int i; + char *id; + + if (__add) { + acl_vstream_printf("start write thread...\r\n"); + for (i = 0; i < __thrcnt; i++) { + id = acl_mymalloc(10); + sprintf(id, "%d", i); + printf("add one thread i=%d\n", i); + acl_pthread_pool_add(__thrpool, thread_write_fn, id); + printf("add one thread ok, i=%d\n", i); + } + while (1) { + i = acl_pthread_pool_size(__thrpool); + if (i == 0) + break; + printf("> current threads in thread pool is: %d, nwrite=%d\r\n", i, __nwrite); + sleep(1); + } + acl_vstream_printf("write threads exit now\r\n"); + } + + if (__search) { + acl_vstream_printf("start read thread...\r\n"); + for (i = 0; i < __thrcnt; i++) { + id = acl_mymalloc(10); + sprintf(id, "%d", i); + acl_pthread_pool_add(__thrpool, thread_read_fn, id); + } + + while (1) { + i = acl_pthread_pool_size(__thrpool); + if (i == 0) + break; + printf("> current threads in thread pool is: %d, nread=%d\r\n", i, __nread); + sleep(1); + } + acl_vstream_printf("read threads exit now\r\n"); + } + + if (__seq) { + acl_vstream_printf("start seq thread ...\r\n"); + for (i = 0; i < __thrcnt; i++) { + acl_pthread_pool_add(__thrpool, thread_seq_fn, NULL); + } + + while (1) { + i = acl_pthread_pool_size(__thrpool); + if (i == 0) + break; + printf("> current threads in thread pool is: %d, nread=%d\r\n", i, __nread); + sleep(1); + } + acl_vstream_printf("seq read threads exit now\r\n"); + } + + if (__seqdel) { + acl_vstream_printf("start seqdel thread ...\r\n"); + for (i = 0; i < __thrcnt; i++) { + acl_pthread_pool_add(__thrpool, thread_seqdel_fn, NULL); + } + + while (1) { + i = acl_pthread_pool_size(__thrpool); + if (i == 0) + break; + printf("> current threads in thread pool is: %d, nread=%d\r\n", i, __nread); + sleep(1); + } + acl_vstream_printf("seqdel read threads exit now\r\n"); + } +} + +static void usage(const char *procname) +{ + printf("usage: %s -h [help] -a [sort the key] -p page_size -c cache_size\r\n" + "-o read|rw -f from -n count -t thread_count -d db_count\r\n" + "-o add -f from -n count -t thread_count -d db_count -s value_size\r\n" + "-o seq -t thread_count\r\n" + "-o seqdel -t thread_count\r\n" + "-o test type:file read|write|create [fold]\r\n" + "-o test_number -n count\r\n", + procname); +} + +int main(int argc, char *argv[]) +{ +#if 1 + const char *dict_type = "btree"; + const char *dict_path = "dbpath"; + const char *dict_name = "test"; +#else + const char *dict_type = "cdb"; + const char *dict_path = "dbpath"; + const char *dict_name = "test"; +#endif + char ch, oper[32]; + + oper[0] = 0; + while ((ch = getopt(argc, argv, "ho:n:f:t:d:s:ap:c:")) > 0) { + switch (ch) { + case 'h': + usage(argv[0]); + exit (0); + case 'o': + ACL_SAFE_STRNCPY(oper, optarg, sizeof(oper)); + break; + case 'n': + __max = atoi(optarg); + if (__max < 0) + __max = 10000; + break; + case 'f': + __begin = atoi(optarg); + if (__begin < 0) + __begin = 0; + break; + case 't': + __thrcnt = atoi(optarg); + if (__thrcnt <= 0 || __thrcnt >= 1000) + __thrcnt = 1; + break; + case 'd': + __dbcnt = atoi(optarg); + if (__dbcnt <= 0 || __dbcnt > 256) + __dbcnt = 32; + break; + case 's': + __value_size = atoi(optarg); + if (__value_size <= 0) + __value_size = 100; + break; + case 'a': + __sort = 1; + break; + case 'p': + dict_db_page_size = atoi(optarg); + break; + case 'c': + dict_db_cache_size = atoi(optarg); + break; + default: + usage(argv[0]); + exit (0); + } + } + if (strcasecmp(oper, "test") == 0) { + dict_test_main(argc, argv); + return (0); + } else if (strcasecmp(oper, "test_number") == 0) { + dict_number_main(__max); + return (0); + } else if (strcasecmp(oper, "add") == 0) { + __add = 1; + } else if (strcasecmp(oper, "read") == 0) { + __search = 1; + } else if (strcasecmp(oper, "rw") == 0) { + __add = 1; + __search = 1; + } else if (strcasecmp(oper, "seq") == 0) { + __seq = 1; + } else if (strcasecmp(oper, "seqdel") == 0) { + __seqdel = 1; + } else { + usage(argv[0]); + exit (0); + } + + init(dict_type, dict_path, dict_name); + run(); + end(); + printf("input any key to exit now\r\n"); + getchar(); + return (0); +} diff --git a/samples/dict/tools/main.c.bak b/samples/dict/tools/main.c.bak new file mode 100644 index 000000000..02b4c18f4 --- /dev/null +++ b/samples/dict/tools/main.c.bak @@ -0,0 +1,264 @@ +#include "dict_db.h" +#include "lib_acl.h" +#include +#include "dict.h" + +static int __add = 0, __search = 0; +static acl_pthread_pool_t *__thrpool = NULL; +static acl_pthread_mutex_t __lock; +static int __thrcnt = 32, __begin = 0, __max = 10000, __quit = 0, __write_ok = 0; +static int __nwrite = 0, __nread = 0; +static int __report_base = 10000; +static char __dict_name[256], __key_pre[] = "key5"; +static DB_ENV *__db_env; + +#define LOCK acl_pthread_mutex_lock(&__lock) +#define UNLOCK acl_pthread_mutex_unlock(&__lock) + +static void *deadlock_check_thread(void* arg acl_unused) +{ + int ret; + + if (__db_env->get_lk_max_lockers(__db_env, &ret) == 0) + printf(">>>max lockers=%d\r\n", ret); + else + printf(">>>can't get max lockers\r\n"); + sleep(1); + while (!__quit) + { + (void) __db_env->lock_detect(__db_env, 0, DB_LOCK_YOUNGEST, NULL); + sleep(1); + } + return (NULL); +} + +static void *trickle_check_thread(void *arg acl_unused) +{ + int wrote; + + sleep(1); + while (!__quit) { + if (__write_ok) + break; + (void) __db_env->memp_trickle(__db_env, 100, &wrote); + printf("trickle: wrote %d\n", wrote); + sleep(1); + } + + return (NULL); +} + +static void create_check_thread(void) +{ + acl_pthread_attr_t attr; + acl_pthread_t tid; + + return; + + acl_pthread_attr_init(&attr); + acl_pthread_attr_setdetachstate(&attr, 1); + + acl_pthread_create(&tid, &attr, deadlock_check_thread, NULL); + if (__add) + acl_pthread_create(&tid, &attr, trickle_check_thread, NULL); +} + +static void init(const char *dict_name) +{ + int open_flags = O_CREAT | O_RDWR; + int dict_flags = /* DICT_FLAG_LOCK | */ DICT_FLAG_DUP_REPLACE; + DICT *dict; + + acl_init(); + + acl_pthread_mutex_init(&__lock, NULL); + __thrpool = acl_thread_pool_create(__thrcnt, 5); + assert(__thrpool); + dict_init(); + dict_open_init(); + snprintf(__dict_name, sizeof(__dict_name), "%s", dict_name); + dict = dict_open(dict_name, open_flags, dict_flags); + assert(dict); + dict_register(dict_name, dict); + + __db_env = dict_db_env(dict); + create_check_thread(); +} + +static void end(const char *dict_name) +{ + dict_unregister(dict_name); +} + +static void thread_write_fn(void *arg) +{ + char *id = (char*) arg; + char *dict_name = __dict_name; + char key[256], value[256]; + time_t begin, last, now; + int i; + + time(&begin); + last = begin; + for (i = __begin; i < __begin + __max; i++) + { + snprintf(key, sizeof(key), "%s:%s:%d", __key_pre, id, i); + snprintf(value, sizeof(value), "value2value2value2value2value2value2value2value2:%d:%d", + (unsigned) acl_pthread_self(), i); + dict_update(dict_name, key, value); + if (i > 0 && i % __report_base == 0) { + time(&now); + printf("thread %u add one, i=%d, time=%ld\r\n", + (unsigned) acl_pthread_self(), i, now - last); + last = now; + } + LOCK; + __nwrite++; + UNLOCK; + } + acl_myfree(id); + __write_ok = 1; + printf("thread %u add over, i=%d, time=%ld\r\n", + (unsigned) acl_pthread_self(), i, time(NULL) - begin); +} + +static void thread_read_fn(void *arg) +{ + char *id = (char*) arg; + char *dict_name = __dict_name; + char key[256], *value; + size_t value_size; + time_t begin, last, now; + int i; + + time(&begin); + last = begin; + for (i = __begin; i < __begin + __max; i++) + { + snprintf(key, sizeof(key), "%s:%s:%i", __key_pre, id, i); + if (dict_lookup(dict_name, key, &value, &value_size) == NULL) { + acl_vstream_printf("%s: %s\n", key, + dict_errno == DICT_ERR_RETRY ? "soft error" : "not found"); + } else { + if (i > 0 && i % __report_base == 0) { + time(&now); + printf(">>%s=%s, time=%ld\r\n", key, value, now - last); + last = now; + } + free(value); + LOCK; + __nread++; + UNLOCK; + } + } + printf("thread %u read over, i=%d, time=%ld\r\n", + (unsigned) acl_pthread_self(), i, time(NULL) - begin); + acl_myfree(id); +} + +static void run(void) +{ + int i; + char *id; + + if (__add) { + acl_vstream_printf("start write thread...\r\n"); + for (i = 0; i < __thrcnt; i++) + { + id = acl_mymalloc(10); + sprintf(id, "%d", i); + acl_pthread_pool_add(__thrpool, thread_write_fn, id); + } + while (1) + { + i = acl_pthread_pool_size(__thrpool); + if (i == 0) + break; + printf("> current threads in thread pool is: %d, nwrite=%d\r\n", i, __nwrite); + sleep(1); + } + acl_vstream_printf("write threads exit now\r\n"); + + sleep(2); + printf("begin to sync all\r\n"); + __db_env->memp_sync(__db_env, NULL); + } + + if (__search) { + acl_vstream_printf("start read thread...\r\n"); + for (i = 0; i < __thrcnt; i++) + { + id = acl_mymalloc(10); + sprintf(id, "%d", i); + acl_pthread_pool_add(__thrpool, thread_read_fn, id); + } + + while (1) + { + i = acl_pthread_pool_size(__thrpool); + if (i == 0) + break; + printf("> current threads in thread pool is: %d, nread=%d\r\n", i, __nread); + sleep(1); + } + acl_vstream_printf("read threads exit now\r\n"); + } +} + +static void usage(const char *procname) +{ + printf("usage: %s -h [help] -o oper [add|read|rw|test] -f from -n count\r\n", procname); +} + +int main(int argc, char *argv[]) +{ + const char *dict_name = "btree:test"; + char ch, oper[32]; + + oper[0] = 0; + while ((ch = getopt(argc, argv, "ho:n:f:")) > 0) { + switch (ch) { + case 'h': + usage(argv[0]); + exit (0); + case 'o': + ACL_SAFE_STRNCPY(oper, optarg, sizeof(oper)); + break; + case 'n': + __max = atoi(optarg); + if (__max < 0) + __max = 10000; + break; + case 'f': + __begin = atoi(optarg); + if (__begin < 0) + __begin = 0; + break; + default: + usage(argv[0]); + exit (0); + } + } + if (strcasecmp(oper, "test") == 0) { + dict_test_main(argc, argv); + return (0); + } else if (strcasecmp(oper, "add") == 0) { + __add = 1; + } else if (strcasecmp(oper, "read") == 0) { + __search = 1; + } else if (strcasecmp(oper, "rw") == 0) { + __add = 1; + __search = 1; + } else { + usage(argv[0]); + exit (0); + } + + init(dict_name); + run(); + __quit = 1; + end(dict_name); + printf("input any key to exit now\r\n"); + getchar(); + return (0); +} diff --git a/samples/dict/tools/md5.c b/samples/dict/tools/md5.c new file mode 100644 index 000000000..663438f88 --- /dev/null +++ b/samples/dict/tools/md5.c @@ -0,0 +1,296 @@ + +/* MS VisualStudio Projects are monolithic, so we need the following + * #if to exclude the MD5 code from compile process when we are + * building the SSL support. + */ +#include +#include +#include "md5.h" +#include + +#ifdef WORDS_BIGENDIAN +void byteSwap(uint32_t * buf, unsigned words) +{ + uint8_t *p = (uint8_t *) buf; + + do { + *buf++ = (uint32_t) ((unsigned) p[3] << 8 | p[2]) << 16 | + ((unsigned) p[1] << 8 | p[0]); + p += 4; + } while (--words); +} +#else +#define byteSwap(buf,words) +#endif + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +void MD5Init(struct MD5Context *ctx) +{ + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bytes[0] = 0; + ctx->bytes[1] = 0; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void MD5Update(struct MD5Context *ctx, const void *_buf, unsigned len) +{ + const uint8_t *buf = (const uint8_t *) _buf; + uint32_t t; + + /* Update byte count */ + + t = ctx->bytes[0]; + if ((ctx->bytes[0] = t + len) < t) + ctx->bytes[1]++; /* Carry from low to high */ + + t = 64 - (t & 0x3f); /* Space available in ctx->in (at least 1) */ + if (t > len) { + memcpy((uint8_t *) ctx->in + 64 - t, buf, len); + return; + } + /* First chunk is an odd size */ + memcpy((uint8_t *) ctx->in + 64 - t, buf, t); + byteSwap(ctx->in, 16); + MD5Transform(ctx->buf, ctx->in); + buf += t; + len -= t; + + /* Process data in 64-byte chunks */ + while (len >= 64) { + memcpy(ctx->in, buf, 64); + byteSwap(ctx->in, 16); + MD5Transform(ctx->buf, ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + memcpy(ctx->in, buf, len); +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +void MD5Final(unsigned char digest[16], struct MD5Context *ctx) +{ + int count = ctx->bytes[0] & 0x3f; /* Number of bytes in ctx->in */ + uint8_t *p = (uint8_t *) ctx->in + count; + + /* Set the first char of padding to 0x80. There is always room. */ + *p++ = 0x80; + + /* Bytes of padding needed to make 56 bytes (-8..55) */ + count = 56 - 1 - count; + + if (count < 0) { /* Padding forces an extra block */ + memset(p, 0, count + 8); + byteSwap(ctx->in, 16); + MD5Transform(ctx->buf, ctx->in); + p = (uint8_t *) ctx->in; + count = 56; + } + memset(p, 0, count); + byteSwap(ctx->in, 14); + + /* Append length in bits and transform */ + ctx->in[14] = ctx->bytes[0] << 3; + ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29; + MD5Transform(ctx->buf, ctx->in); + + byteSwap(ctx->buf, 4); + memcpy(digest, ctx->buf, 16); + memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ +} + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f,w,x,y,z,in,s) \ + (w += f(x,y,z) + in, w = (w<>(32-s)) + x) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +void MD5Transform(uint32_t buf[4], uint32_t const in[16]) +{ + register uint32_t a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +const char* MD5Key(const char *s, size_t s_len, const char *k, size_t k_len, void* buf, size_t b_len) +{ + MD5_CTX context; + unsigned char digest[16]; + + if (b_len != 16) { + printf("b_len(%d) != 16\n", b_len); + assert(0); + } + + MD5Init(&context); + if (k != NULL && k_len > 0) + MD5Update(&context, (const unsigned char *) k, k_len); + MD5Update(&context, (const unsigned char*) s, s_len); + MD5Final(digest, &context); + memcpy(buf, digest, b_len); + return ((const char*) buf); +} + +const char* MD5String(const char *s, const char *k, size_t k_len, char* buf, size_t size) +{ + MD5_CTX context; + unsigned char digest[16]; + char output1[34], *ptr; + unsigned int len = (unsigned int) strlen(s); + size_t i, n; + + MD5Init(&context); + if (k != NULL && k_len > 0) + MD5Update(&context, (const unsigned char *) k, k_len); + MD5Update(&context, (const unsigned char*) s, len); + MD5Final(digest, &context); + + for (i = 0; i < 16; i++) { + sprintf(&(output1[2 * i]), "%02x", (unsigned char) digest[i]); + sprintf(&(output1[2 * i + 1]), "%02x", (unsigned char) (digest[i] << 4)); + } + + ptr = buf; + size--; /* left one byte for '\0' */ + n = size > 32 ? 32 : size; + + for(i = 0; i < n; i++) + *ptr++ = output1[i]; + *ptr = '\0'; + + return (buf); +} + +const char* MD5Key2String(const unsigned char *s, size_t s_len, char* buf, size_t size) +{ + size_t i, n; + char output1[34], *ptr; + unsigned char digest[16]; + + if (s_len != 16) { + printf("s_len(%d) != 16\n", s_len); + assert(0); + } + if (size < 32) { + printf("size(%d) < 32\n", size); + assert(0); + } + memcpy(digest, s, 16); + + for (i = 0; i < 16; i++) { + sprintf(&(output1[2 * i]), "%02x", (unsigned char) digest[i]); + sprintf(&(output1[2 * i + 1]), "%02x", (unsigned char) (digest[i] << 4)); + } + + ptr = buf; + size--; /* left one byte for '\0' */ + n = size > 32 ? 32 : size; + + for(i = 0; i < n; i++) + *ptr++ = output1[i]; + *ptr = '\0'; + + return (buf); +} + diff --git a/samples/dict/tools/md5.h b/samples/dict/tools/md5.h new file mode 100644 index 000000000..67b8f26a3 --- /dev/null +++ b/samples/dict/tools/md5.h @@ -0,0 +1,26 @@ +#ifndef SQUID_MD5_H +#define SQUID_MD5_H + +#include + +typedef unsigned int uint32_t; +typedef unsigned char uint8_t; + +typedef struct MD5Context { + uint32_t buf[4]; + uint32_t bytes[2]; + uint32_t in[16]; +} MD5_CTX; + + +void MD5Init(struct MD5Context *context); +void MD5Update(struct MD5Context *context, const void *buf, unsigned len); +void MD5Final(uint8_t digest[16], struct MD5Context *context); +void MD5Transform(uint32_t buf[4], uint32_t const in[16]); +const char* MD5Key(const char *s, size_t s_len, const char *k, size_t k_len, void* buf, size_t b_len); +const char* MD5String(const char *s, const char *k, size_t k_len, char* buf, size_t size); +const char* MD5Key2String(const unsigned char *s, size_t s_len, char* buf, size_t size); + +#define MD5_DIGEST_CHARS 16 + +#endif /* SQUID_MD5_H */ diff --git a/samples/dict/unix/app_log.c b/samples/dict/unix/app_log.c new file mode 100644 index 000000000..a937fed4d --- /dev/null +++ b/samples/dict/unix/app_log.c @@ -0,0 +1,234 @@ + +#include "lib_acl.h" +#include +#include "app_log.h" + +#ifdef HAS_LIB_CORE +#include "e_config.h" +#include "elib.h" + +typedef struct LOG_WRAP { + E_LOG_T *h_log; + char filename[1024]; +} LOG_WRAP; + +static LOG_WRAP *__log_wrap = NULL; + +static int __log_open(const char *filename, void *ctx) +{ + LOG_WRAP *h_log = (LOG_WRAP *) ctx; + int logme = 0; + char *facility_name = NULL; + E_LOG_PRIORITY_T priority = E_LOG_INFO; + E_LOG_ACTION_T action = E_LOG_PER_DAY; + int flush = 1; + size_t limit_size = 0; + E_LOG_SYNC_ACTION_T sync_action = E_LOG_SEM_WITH_MT; + char *sem_name = NULL; + char *ptr, *pname; + ACL_ARGV *env_argv; + ACL_VSTRING *log_buf; + int i; + + if (filename == NULL || *filename == 0) + return (-1); + + acl_snprintf(h_log->filename, sizeof(h_log->filename), "%s", filename); + + /* env: facility:x, priority:x, action:x, flush:x, limit_size:x, sync_action:x, sem_name:x */ + + ptr = getenv("SERVICE_ENV"); + if (ptr == NULL) + return (-1); + + env_argv = acl_argv_split(ptr, ",\t "); + if (env_argv == NULL) + return (-1); + if (env_argv->argc == 0) { + acl_argv_free(env_argv); + return (-1); + } + + log_buf = acl_vstring_alloc(256); + + for (i = 0; i < env_argv->argc; i++) { + pname = acl_argv_index(env_argv, i); + ptr = strchr(pname, ':'); + if (ptr == NULL) + continue; + *ptr++ = 0; + if (*ptr == 0) + continue; + + if (i == 0) + acl_vstring_sprintf(log_buf, "%s:%s", pname, ptr); + else + acl_vstring_sprintf_append(log_buf, ", %s:%s", pname, ptr); + + if (strcasecmp(pname, "logme") == 0) { + if (strcasecmp(ptr, "TRUE") == 0) + logme = 1; + } else if (strcasecmp(pname, "facility") == 0) { + facility_name = ptr; + } else if (strcasecmp(pname, "priority") == 0) { + if (strcasecmp(ptr, "E_LOG_NOLOG") == 0) + priority = E_LOG_NOLOG; + else if (strcasecmp(ptr, "E_LOG_EMERG") == 0) + priority = E_LOG_EMERG; + else if (strcasecmp(ptr, "E_LOG_ALERT") == 0) + priority = E_LOG_ALERT; + else if (strcasecmp(ptr, "E_LOG_CRIT") == 0) + priority = E_LOG_CRIT; + else if (strcasecmp(ptr, "E_LOG_ERR") == 0) + priority = E_LOG_ERR; + else if (strcasecmp(ptr, "E_LOG_WARNING") == 0) + priority = E_LOG_WARNING; + else if (strcasecmp(ptr, "E_LOG_NOTICE") == 0) + priority = E_LOG_NOTICE; + else if (strcasecmp(ptr, "E_LOG_INFO") == 0) + priority = E_LOG_INFO; + else if (strcasecmp(ptr, "E_LOG_DEBUG") == 0) + priority = E_LOG_DEBUG; + } else if (strcasecmp(pname, "action") == 0) { + if (strcasecmp(ptr, "E_LOG_PER_HOUR") == 0) + action = E_LOG_PER_HOUR; + else if (strcasecmp(ptr, "E_LOG_PER_DAY") == 0) + action = E_LOG_PER_DAY; + else if (strcasecmp(ptr, "E_LOG_PER_WEEK") == 0) + action = E_LOG_PER_WEEK; + else if (strcasecmp(ptr, "E_LOG_PER_MONTH") == 0) + action = E_LOG_PER_MONTH; + else if (strcasecmp(ptr, "E_LOG_PER_YEAR") == 0) + action = E_LOG_PER_YEAR; + else if (strcasecmp(ptr, "E_LOG_LIMIT_SIZE") == 0) + action = E_LOG_LIMIT_SIZE; + else if (strcasecmp(ptr, "E_LOG_SYSLOG") == 0) + action = E_LOG_SYSLOG; + } else if (strcasecmp(pname, "flush") == 0) { + if (strcasecmp(ptr, "sync_flush") == 0) + flush = 1; + else if (strcasecmp(ptr, "async_flush") == 0) + flush = 0; + } else if (strcasecmp(pname, "limit_size") == 0) { + limit_size = atoi(ptr); + } else if (strcasecmp(pname, "sync_action") == 0) { + if (strcasecmp(ptr, "E_LOG_NO_SYNC") == 0) + sync_action = E_LOG_NO_SYNC; + else if (strcasecmp(ptr, "E_LOG_THREAD_MUTEX") == 0) + sync_action = E_LOG_THREAD_MUTEX; + else if (strcasecmp(ptr, "E_LOG_FILE_LOCK") == 0) + sync_action = E_LOG_FILE_LOCK; + else if (strcasecmp(ptr, "E_LOG_SEM_WITH_MT") == 0) + sync_action = E_LOG_SEM_WITH_MT; + else if (strcasecmp(ptr, "E_LOG_FILE_APPEND_WITH_MT") == 0) + sync_action = E_LOG_FILE_APPEND_WITH_MT; + } else if (strcasecmp(pname, "sem_name") == 0) { + sem_name = ptr; + } + } + + +#if 0 + LC_SysLogCreate(&h_log->h_log, h_log->filename); +#endif + if (action == E_LOG_LIMIT_SIZE) { + if (limit_size == 0) + limit_size = 512; /* set default size: 512 MB */ + } else + limit_size = 0; + + if (sync_action == E_LOG_SEM_WITH_MT) { + if (sem_name == NULL || *sem_name == 0) { + sem_name = acl_concatenate("/tmp/", acl_safe_basename(filename), ".sem", NULL); + } else + sem_name = acl_mystrdup(sem_name); + } else if (sem_name) { + sem_name = NULL; + } + + h_log->h_log = e_log_new2(h_log->filename, priority, action, + flush, limit_size, facility_name, sync_action, sem_name); + + if (sem_name) + acl_myfree(sem_name); + + if (logme) { + /* + char cmd[1024], buf[512]; + + snprintf(buf, sizeof(buf), "filename=%s, priority=%d, action=%d, flush=%d, " + "limit_size=%d, facility_name=%s, sync_action=%d, sem_name=%s", + h_log->filename, priority, action, + flush, limit_size, facility_name, sync_action, sem_name); + snprintf(cmd, sizeof(cmd), "echo '%s, buf(%s)' >> /tmp/test1.log", acl_vstring_str(log_buf), buf); + system(cmd); + */ + + e_log2(h_log->h_log, "master_env: %s", acl_vstring_str(log_buf)); + } + + e_log2(h_log->h_log, "filename=%s, priority=%d, action=%d, flush=%d, " + "limit_size=%d, facility_name=%s, sync_action=%d, sem_name=%s", + h_log->filename, priority, action, + flush, limit_size, facility_name, sync_action, sem_name); + + if (log_buf) + acl_vstring_free(log_buf); + + return (0); +} + +static void __log_close(void *ctx acl_unused) +{ +} + +static void __log_write(void *ctx, const char *fmt, va_list ap) +{ + LOG_WRAP *h_log = (LOG_WRAP *) ctx; +#if 0 + char buf[1024], cmd[2048]; + + vsnprintf(buf, sizeof(buf), fmt, ap); + + snprintf(cmd, sizeof(cmd), "echo \"%s\" >> /tmp/out.txt", buf); + system(cmd); +#endif + +#if 0 + LC_SysLogFmtWrite2(&h_log->h_log, fmt, ap); +#endif + if (h_log->h_log) + e_vlog2(h_log->h_log, fmt, ap); +} + +void app_set_libcore_log(void) +{ + LOG_WRAP *h_log; + + h_log = acl_mycalloc(1, sizeof(LOG_WRAP)); + if (h_log == NULL) + return; + + acl_msg_register(__log_open, __log_close, __log_write, (void *) h_log); + __log_wrap = h_log; +} + +void app_libcore_log_end(void) +{ + if (__log_wrap == NULL) + return; + if (__log_wrap->h_log == NULL) + return; + acl_msg_info("service exit now"); + e_log_free(__log_wrap->h_log); + __log_wrap->h_log = NULL; +} +#else +void app_set_libcore_log() +{ + const char *myname = "app_set_libcore_log"; + + acl_msg_fatal("%s: not supported", myname); +} +#endif + diff --git a/samples/dict/unix/app_log.h b/samples/dict/unix/app_log.h new file mode 100644 index 000000000..aa7ec36f6 --- /dev/null +++ b/samples/dict/unix/app_log.h @@ -0,0 +1,17 @@ + +#ifndef __LOG_WRAP_INCLUDE_H__ +#define __LOG_WRAP_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +extern void app_set_libcore_log(void); +extern void app_libcore_log_end(void); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/samples/dict/unix/app_main.c b/samples/dict/unix/app_main.c new file mode 100644 index 000000000..2db9644aa --- /dev/null +++ b/samples/dict/unix/app_main.c @@ -0,0 +1,371 @@ +#include "lib_acl.h" + +#include +#include +#include +#include + +#include "app_log.h" +#include "app_main.h" + +typedef struct APP_HANDLE { + char name[256]; +} APP_HANDLE; + +static APP_RUN_FN __run_fn = NULL; +static void *__run_ctx = NULL; + +/* 客户端IO超时时间值 */ +int app_var_client_idle_limit = 60; + +static ACL_CONFIG_INT_TABLE __conf_int_tab[] = { + /* TODO: you can add configure variables of int type here */ + { "app_client_idle_limit", 120, &app_var_client_idle_limit, 0, 0 }, + { 0, 0, 0, 0, 0 }, +}; + +static char *__default_deny_info = "You are not welcome!\r\n"; +static char *__deny_info; +/*----------------------------------------------------------------------------*/ + +/** + * 创建一个服务器框架 + * @return APP_HANDLE* 用户自己的应用数据句柄. + */ + +static APP_HANDLE *app_create(void) +{ + char myname[] = "app_create"; + APP_HANDLE *app; + + app = (APP_HANDLE *) acl_mycalloc(1, sizeof(APP_HANDLE)); + if (app == NULL) + acl_msg_fatal("%s(%d): calloc error(%s)", + myname, __LINE__, strerror(errno)); + + ACL_SAFE_STRNCPY(app->name, myname, sizeof(app->name)); + + return (app); +} +/*----------------------------------------------------------------------------*/ +static void __read_notify_callback(int event_type, + ACL_IOCTL *h_ioctl, + ACL_VSTREAM *cstream, + void *context) +{ + char myname[] = "__read_notify_callback"; + APP_HANDLE *app; + int ret; + + app = (APP_HANDLE *) context; + + switch (event_type) { + case ACL_EVENT_READ: + ret = __run_fn(cstream, __run_ctx); + if (ret < 0) { + acl_vstream_close(cstream); + } else if (ret == 0) { + if (acl_msg_verbose) + acl_msg_info("enable(%s), fd=%d, h_ioctl(%p)", + myname, ACL_VSTREAM_SOCK(cstream), (void*) h_ioctl); + acl_ioctl_enable_read(h_ioctl, + cstream, + app_var_client_idle_limit, + __read_notify_callback, + (void *) app); + + } + break; + case ACL_EVENT_RW_TIMEOUT: + case ACL_EVENT_XCPT: + acl_vstream_close(cstream); + break; + default: + acl_msg_fatal("%s, %s(%d): unknown event type(%d)", + __FILE__, myname, __LINE__, event_type); + /* not reached */ + break; + } + if (acl_msg_verbose) + acl_msg_info("%s(%d): total alloc: %d", + myname, __LINE__, acl_mempool_total_allocated()); +} + +/** + * 向任务池中添加一个工作任务 + * @param h_ioctl 服务器任务池句柄 + * @param app_handle 用户自己的应用数据句柄. + * @param cstream 客户端数据流指针 + * 注: cstream 数据流会在该函数内部的回调函数中进行关闭, 所以该函数的调用者不要 + * 关闭该流. + */ + +static void app_add_worker(ACL_IOCTL *h_ioctl, APP_HANDLE *app, ACL_VSTREAM *cstream) +{ + const char *myname = "app_add_worker"; + + if (h_ioctl == NULL || cstream == NULL || app == NULL) + acl_msg_fatal("%s(%d): input invalid", myname, __LINE__); + + /* 将客户端数据流的状态置入事件监控集合中 */ + if (acl_msg_verbose) + acl_msg_info("%s(%d): ioctl=%p, fd=%d", + myname, __LINE__, (void*) h_ioctl, ACL_VSTREAM_SOCK(cstream)); + + acl_ioctl_enable_read(h_ioctl, + cstream, + app_var_client_idle_limit, + __read_notify_callback, + (void *) app); +} +/*---------------------- app main functions ----------------------------------*/ + +static int __mempool_limit = 0; + +static APP_HANDLE *__app_handle = NULL; + +static APP_INIT_FN __app_init_fn = NULL; +static void *__app_init_ctx = NULL; +static APP_EXIT_FN __app_exit_fn = NULL; +static void *__app_exit_ctx = NULL; +static APP_THREAD_INIT_FN __app_thread_init_fn = NULL; +static APP_THREAD_EXIT_FN __app_thread_exit_fn = NULL; + +static void __service(ACL_IOCTL *h_ioctl, ACL_VSTREAM *stream, + char *service acl_unused, char **argv acl_unused) +{ + char myname[] = "__service"; + char ip[64]; + + /* + * Sanity check. This service takes no command-line arguments. + */ + if (argv[0]) + acl_msg_fatal("%s, %s(%d): unexpected command-line argument: %s, service=%s", + __FILE__, myname, __LINE__, argv[0], service ? service : "null"); + acl_watchdog_pat(); + + if (isatty(ACL_VSTREAM_SOCK(stream))) { + stream->rw_timeout = app_var_client_idle_limit; + (void) __run_fn(stream, __run_ctx); + return; + } + + if (acl_getpeername(ACL_VSTREAM_SOCK(stream), ip, sizeof(ip)) < 0) { + acl_msg_warn("%s, %s(%d): can't get socket's ip", + __FILE__, myname, __LINE__); + acl_vstream_close(stream); + } else if (!acl_access_permit(ip)) { + acl_msg_warn("%s, %s(%d): ip(%s) be denied", + __FILE__, myname, __LINE__, ip); + (void) acl_vstream_writen(stream, __deny_info, strlen(__deny_info)); + acl_vstream_close(stream); + } else { + stream->rw_timeout = app_var_client_idle_limit; + app_add_worker(h_ioctl, __app_handle, stream); + } +} + +static void __pre_accept(char *name acl_unused, char **argv acl_unused) +{ +} + +static void __pre_jail_init(char *name acl_unused, char **argv acl_unused) +{ + acl_get_app_conf_int_table(__conf_int_tab); + /* 是否采用 libcore 的日志记录 */ +#ifdef HAS_LIB_CORE +# ifdef USE_LIBCORE_LOG + app_set_libcore_log(); +# endif +#endif +} + +static void __post_jail_init(char *name acl_unused, char **argv acl_unused) +{ + char myname[] = "__post_jail_init"; + + if (acl_var_ioctl_access_allow != NULL) + acl_access_add(acl_var_ioctl_access_allow, ",", ":"); + + __app_handle = app_create(); + if (__app_handle == NULL) + acl_msg_fatal("%s(%d): ioctl_create error(%s)", + myname, __LINE__, strerror(errno)); + + if (__app_init_fn != NULL) + __app_init_fn(__app_init_ctx); + + if (__mempool_limit > 0) { + acl_msg_info("use mempool, size limit is %d, use mutex", + __mempool_limit); + } + + /* TODO: you can add some init functions here */ +} + +static void __app_on_exit(char *service acl_unused, char **argv acl_unused) +{ + if (__app_exit_fn) + __app_exit_fn(__app_exit_ctx); + +#ifdef HAS_LIB_CORE +# ifdef USE_LIBCORE_LOG + app_libcore_log_end(); +# endif +#endif +} + +static void __thread_init(void *arg) +{ + if (__app_thread_init_fn) + __app_thread_init_fn(arg); +} + +static void __thread_exit(void *arg) +{ + if (__app_thread_exit_fn) + __app_thread_exit_fn(arg); +} + +static void app_main_init(void) +{ + char *ptr, *pname; + ACL_ARGV *env_argv; + int i; + + ptr = getenv("SERVICE_ENV"); + if (ptr == NULL || *ptr == 0) + return; + + env_argv = acl_argv_split(ptr, ",\t "); + if (env_argv == NULL) + return; + if (env_argv->argc == 0) { + acl_argv_free(env_argv); + return; + } + + for (i = 0; i argc; i++) { + pname = acl_argv_index(env_argv, i); + ptr = strchr(pname, ':'); + if (ptr == NULL) + continue; + *ptr++ = 0; + if (ptr == 0) + continue; + if (strcasecmp(pname, "mempool_limit") == 0) { + __mempool_limit = atoi(ptr); + break; + } + } + + acl_argv_free(env_argv); + + /* 因为是多线程程序,所以需要加互斥锁 */ + if (__mempool_limit > 0) + acl_mempool_open(__mempool_limit, 1); + + __deny_info = __default_deny_info; +} + +static ACL_CONFIG_BOOL_TABLE null_conf_bool_tab[] = { + /* TODO: you can add configure variables of int type here */ + { 0, 0, 0 }, +}; + +static ACL_CONFIG_INT_TABLE null_conf_int_tab[] = { + /* TODO: you can add configure variables of int type here */ + { 0, 0, 0, 0, 0 }, +}; + +static ACL_CONFIG_STR_TABLE null_conf_str_tab[] = { + /* TODO: you can add configure variables of int type here */ + { 0, 0, 0 }, +}; + +void app_main(int argc, char *argv[], APP_RUN_FN run_fn, void *run_ctx, int name, ...) +{ + const char *myname = "app_main"; + va_list ap; + ACL_CONFIG_BOOL_TABLE *bool_tab = null_conf_bool_tab; + ACL_CONFIG_INT_TABLE *int_tab = null_conf_int_tab; + ACL_CONFIG_STR_TABLE *str_tab = null_conf_str_tab; + void *thread_init_ctx = NULL, *thread_exit_ctx = NULL; + + app_main_init(); + + /* 提前进行模板初始化,以使日志尽早地打开 */ + acl_master_log_open(argv[0]); + + if (run_fn == NULL) + acl_msg_fatal("%s: run_fn null", myname); + + __run_fn = run_fn; + __run_ctx = run_ctx; + + va_start(ap, name); + + for (; name != APP_CTL_END; name = va_arg(ap, int)) { + switch (name) { + case APP_CTL_INIT_FN: + __app_init_fn = va_arg(ap, APP_INIT_FN); + break; + case APP_CTL_INIT_CTX: + __app_init_ctx = va_arg(ap, void *); + break; + + case APP_CTL_EXIT_FN: + __app_exit_fn = va_arg(ap, APP_EXIT_FN); + break; + case APP_CTL_EXIT_CTX: + __app_exit_ctx = va_arg(ap, void *); + break; + + case APP_CTL_THREAD_INIT: + __app_thread_init_fn = va_arg(ap, APP_THREAD_INIT_FN); + break; + case APP_CTL_THREAD_INIT_CTX: + thread_init_ctx = va_arg(ap, void*); + break; + + case APP_CTL_THREAD_EXIT: + __app_thread_exit_fn = va_arg(ap, APP_THREAD_EXIT_FN); + break; + case APP_CTL_THREAD_EXIT_CTX: + thread_exit_ctx = va_arg(ap, void*); + break; + + case APP_CTL_CFG_BOOL: + bool_tab = va_arg(ap, ACL_CONFIG_BOOL_TABLE *); + break; + case APP_CTL_CFG_INT: + int_tab = va_arg(ap, ACL_CONFIG_INT_TABLE *); + break; + case APP_CTL_CFG_STR: + str_tab = va_arg(ap, ACL_CONFIG_STR_TABLE *); + break; + case APP_CTL_DENY_INFO: + __deny_info = acl_mystrdup(va_arg(ap, const char*)); + break; + default: + acl_msg_fatal("%s: bad name(%d)", myname, name); + } + } + + va_end(ap); + + acl_ioctl_server_main(argc, argv, __service, + ACL_MASTER_SERVER_BOOL_TABLE, bool_tab, + ACL_MASTER_SERVER_INT_TABLE, int_tab, + ACL_MASTER_SERVER_STR_TABLE, str_tab, + ACL_MASTER_SERVER_PRE_INIT, __pre_jail_init, + ACL_MASTER_SERVER_PRE_ACCEPT, __pre_accept, + ACL_MASTER_SERVER_POST_INIT, __post_jail_init, + ACL_MASTER_SERVER_EXIT, __app_on_exit, + ACL_MASTER_SERVER_THREAD_INIT, __thread_init, + ACL_MASTER_SERVER_THREAD_EXIT, __thread_exit, + ACL_MASTER_SERVER_THREAD_INIT_CTX, thread_init_ctx, + ACL_MASTER_SERVER_THREAD_EXIT_CTX, thread_exit_ctx, + 0); +} diff --git a/samples/dict/unix/app_main.h b/samples/dict/unix/app_main.h new file mode 100644 index 000000000..7d0002922 --- /dev/null +++ b/samples/dict/unix/app_main.h @@ -0,0 +1,69 @@ +#ifndef __APP_MAIN_INCLUDE_H__ +#define __APP_MAIN_INCLUDE_H__ + +#include "lib_acl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* 客户端读写超时时间值 */ +extern int app_var_client_idle_limit; + +/* 用户级的运行函数类型, 当该函数返回值 != 0 时, 框架会自动关闭客户端流 */ +typedef int (*APP_RUN_FN)(ACL_VSTREAM *stream, void *run_ctx); + +/* 用户级的初始化函数类型 */ +typedef void (*APP_INIT_FN)(void*); +typedef void (*APP_EXIT_FN)(void*); + +typedef ACL_MASTER_SERVER_THREAD_INIT_FN APP_THREAD_INIT_FN /* void (*)(void*) */; +typedef ACL_MASTER_SERVER_THREAD_EXIT_FN APP_THREAD_EXIT_FN; /* void (*)(void*) */ + +#define APP_CTL_END 0 /* 参数控制结束标志 */ +#define APP_CTL_INIT_FN 1 /* 初始化函数 */ +#define APP_CTL_INIT_CTX 2 /* 初始化函数所用的参数 */ +#define APP_CTL_CFG_BOOL 3 /* 整数类型的配置参数表 */ +#define APP_CTL_CFG_INT 4 /* 整数类型的配置参数表 */ +#define APP_CTL_CFG_STR 5 /* 字符串类型的配置参数表 */ +#define APP_CTL_EXIT_FN 6 /* 当进程退出时的回调函数 */ +#define APP_CTL_EXIT_CTX 7 /* 进程退出时回调函数的参数 */ +#define APP_CTL_THREAD_INIT 8 /* 每个线程启动时的回调函数 */ +#define APP_CTL_THREAD_INIT_CTX 9 /* 线程启动时回调函数的参数 */ +#define APP_CTL_THREAD_EXIT 10 /* 线程退出时的回调函数 */ +#define APP_CTL_THREAD_EXIT_CTX 11 /* 线程退出时回调函数的参数 */ +#define APP_CTL_DENY_INFO 12 /* 当非法客户端访问时给出的提示信息 */ + +/*----------------------------------------------------------------------------*/ +/* in app_main.c */ + +/** + * 主函数入口, 用户级的初始化函数指针及运行函数指针通过控制参数进行注册, 主函数内部 + * 会在初始化时自动调用用户级初始化函数(APP_INIT_FN 类型), 当接收到允许访问的客户端 + * 连接时会自动调用用户(APP_RUN_FN 类型). + * 级的运行函数. + * @param argc "int main(int argc, char *argv[])" 中的 argc + * @param argv "int main(int argc, char *argv[])" 中的 argv + * @param run_fn 用户级运行主函数 + * @param run_ctx run_fn() 运行时的参数之一 + * @param name 控制参数中的第一个控制类型, 所支持的类型如上定义: APP_CTL_XXX + * 调用方式: APP_CTL_XXX, xxx; 其中 APP_CTL_END 为特殊的控制参数, 表示控制参数 + * 结束. + * @example: + * app_main(argc, argv, {run_fn}, {run_ctx}, + * APP_CTL_INIT_FN, {run_init_fn}, + * APP_CTL_INIT_CTX, {run_init_ctx}, + * APP_CTL_END); + * 注: app_main() 的所有参数中, argc, argv, run_fn, run_ctx(可以为NULL), APP_CTL_END + * 都是必需的. + */ + +extern void app_main(int argc, char *argv[], APP_RUN_FN run_fn, void *run_ctx, int name, ...); + +/*----------------------------------------------------------------------------*/ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/samples/dict/unix/http_error.c b/samples/dict/unix/http_error.c new file mode 100644 index 000000000..966ef3033 --- /dev/null +++ b/samples/dict/unix/http_error.c @@ -0,0 +1,44 @@ +#include "lib_acl.h" +#include "lib_protocol.h" +#include "http_service.h" + +static char reply_error_fmt[] = "HTTP/1.1 %d %s\r\n" + "Accept-Ranges: bytes\r\n" + "Server: dict_http/1.0.0 (Unix)\r\n" + "Content-type: text/html\r\n" + "Connection: close\r\n\r\n"; + +static void free_buf(void *arg) +{ + ACL_VSTRING *s = (ACL_VSTRING*) arg; + + acl_vstring_free(s); +} + +void http_error_reply(ACL_VSTREAM *client, int status, const char *msg) +{ + static __thread ACL_VSTRING *__buf = NULL; + const ACL_VSTRING *str; + const char *ptr; + struct iovec iov[2]; + + if (__buf == NULL) { + __buf = acl_vstring_alloc(256); + acl_pthread_atexit_add(__buf, free_buf); + } + + ptr = http_tmpl_title(status); + str = http_tmpl_get(status); + + if (msg == NULL || *msg == 0) + msg = acl_vstring_str(str); + + acl_vstring_sprintf(__buf, reply_error_fmt, status, ptr); + + iov[0].iov_base = acl_vstring_str(__buf); + iov[0].iov_len = ACL_VSTRING_LEN(__buf); + iov[1].iov_base = (char*) msg; + iov[1].iov_len = strlen(msg); + + acl_vstream_writevn(client, iov, 2); +} diff --git a/samples/dict/unix/http_service.c b/samples/dict/unix/http_service.c new file mode 100644 index 000000000..d6c47a8cf --- /dev/null +++ b/samples/dict/unix/http_service.c @@ -0,0 +1,340 @@ +#include "lib_acl.h" +#include "lib_protocol.h" +#include "dict_pool.h" +#include "service_main.h" +#include "http_service.h" + +#define STR acl_vstring_str +#define LEN ACL_VSTRING_LEN + +static ACL_HTABLE *__db_table = NULL; +static __thread ACL_VSTREAM *__stream_out = NULL; + +static const char *__partions[] = { + "./cache1", + "./cache2", + "./cache3", + "./cache4" +}; +static int __partions_size = 4; + +/* 初始化函数 */ +void http_service_init(void *init_ctx acl_unused) +{ + const char *myname = "http_service_init"; + DICT_POOL *pool; + ACL_ARGV *argv; + ACL_VSTRING *buf = acl_vstring_alloc(256); + char *ptr, *name; + int i, n, has_default_db = 0; + + http_init(NULL); + dict_pool_init(); + + if (__db_table != NULL) + acl_msg_fatal("%s(%d): service_init been called more than once", + myname, __LINE__); + + __db_table = acl_htable_create(10, 0); + + argv = acl_argv_split(var_cfg_dbnames, ", "); + if (argv == NULL) + acl_msg_fatal("%s(%d): db_names(%s) invalid", myname, __LINE__, var_cfg_dbnames); + + for (i = 0; i < argv->argc; i++) { + name = argv->argv[i]; + ptr = strchr(name, ':'); + if (ptr == NULL) { + acl_msg_warn("%s(%d): dbname(%s) use one db", + myname, __LINE__, name); + n = 1; + } else { + *ptr++ = 0; + n = atoi(ptr); + } + if (n <= 0) + n = 1; + acl_lowercase(name); + /* acl_vstring_sprintf(buf, "btree:%s/%s", var_cfg_dbpath, name); */ + pool = dict_pool_new(__partions, __partions_size, "btree", + var_cfg_dbpath, name, 1); + if (acl_htable_enter(__db_table, name, (char*) pool) == NULL) + acl_msg_fatal("%s(%d): add %s error", myname, __LINE__, name); + if (strcmp(name, "default") == 0) + has_default_db = 1; + } + acl_argv_free(argv); + + if (!has_default_db) { + /* + acl_vstring_sprintf(buf, "btree:%s/default", var_cfg_dbpath); + pool = dict_pool_new(STR(buf), 8); + */ + pool = dict_pool_new(__partions, __partions_size, "btree", + var_cfg_dbpath, "default", 1); + if (acl_htable_enter(__db_table, "default", (char*) pool) == NULL) + acl_msg_fatal("%s(%d): add default error", myname, __LINE__); + } + + acl_vstring_free(buf); +} + +static void dict_pool_free_fn(void *arg) +{ + DICT_POOL *pool = (DICT_POOL*) arg; + + dict_pool_free(pool); +} + +void http_service_exit(void *exit_ctx acl_unused) +{ + if (__db_table) + acl_htable_free(__db_table, dict_pool_free_fn); +} + +static int set_to_db(ACL_VSTREAM *client acl_unused, HTTP_HDR_REQ *hdr_req, + DICT_POOL *dict_pool, const char *key, const char *value, size_t len) +{ + const char reply_200_keep[] = "HTTP/1.1 200 OK\r\n" + "Accept-Ranges: bytes\r\n" + "Server: dict_http/1.0.0 (Unix)\r\n" + "Content-Length: 9\r\n" + "Connection: keep-alive\r\n" + "\r\n" + "200 OK!\r\n"; + const char reply_200_close[] = "HTTP/1.1 200 OK\r\n" + "Accept-Ranges: bytes\r\n" + "Server: dict_http/1.0.0 (Unix)\r\n" + "Content-Length: 9\r\n" + "Connection: close\r\n" + "\r\n" + "200 OK!\r\n"; + + + dict_pool_set(dict_pool, (char*) key, strlen(key), (char*) value, len); + if (!hdr_req->hdr.keep_alive) { + (void) acl_vstream_writen(__stream_out, reply_200_close, sizeof(reply_200_close) - 1); + return (-1); + } + + if (acl_vstream_writen(__stream_out, reply_200_keep, sizeof(reply_200_keep) - 1) == ACL_VSTREAM_EOF) + return (-1); + return (0); +} + +static int get_from_db(ACL_VSTREAM *client acl_unused, const HTTP_HDR_REQ *hdr_req, + DICT_POOL *dict_pool, const char *key) +{ + static char reply_404_close[] = "HTTP/1.1 404 not found\r\n" + "Accept-Ranges: bytes\r\n" + "Server: dict_http/1.0.0 (Unix)\r\n" + "Content-Length: 15\r\n" + "Connection: close\r\n" + "\r\n" + "404 not found\r\n"; + static char reply_200_keep[] = "HTTP/1.1 200 OK\r\n" + "Accept-Ranges: bytes\r\n" + "Server: dict_http/1.0.0 (Unix)\r\n" + "Content-type: text/html\r\n" + "Connection: keep-alive\r\n"; + static char reply_200_close[] = "HTTP/1.1 200 OK\r\n" + "Accept-Ranges: bytes\r\n" + "Server: dict_http/1.0.0 (Unix)\r\n" + "Content-type: text/html\r\n" + "Connection: close\r\n"; + const char *found_second_fmt = "Content-Length: %d\r\n\r\n"; + char found_second[256]; + char *value; + size_t size; + struct iovec iov[3]; + + if (var_cfg_use_bdb) { + value = dict_pool_get(dict_pool, (char*) key, strlen(key), &size); + if (value == NULL) { + (void) acl_vstream_writen(__stream_out, reply_404_close, sizeof(reply_404_close) - 1); + return (-1); + } + } else { + key = key; + dict_pool = dict_pool; + value = acl_mystrdup("test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4\r\n"); + size = strlen(value); + } + + snprintf(found_second, sizeof(found_second), found_second_fmt, size); + if (hdr_req->hdr.keep_alive) { + iov[0].iov_base = reply_200_keep; + iov[0].iov_len = sizeof(reply_200_keep) - 1; + } else { + iov[0].iov_base = reply_200_close; + iov[0].iov_len = sizeof(reply_200_close) - 1; + } + iov[1].iov_base = found_second; + iov[1].iov_len = strlen(found_second); + iov[2].iov_base = value; + iov[2].iov_len = size; + + if (acl_vstream_writevn(__stream_out, iov, 3) == ACL_VSTREAM_EOF) { + acl_myfree(value); + return (-1); + } + + acl_myfree(value); + + if (!hdr_req->hdr.keep_alive) + return (-1); + return (0); +} + +static int get_body_from_req(ACL_VSTREAM *client, HTTP_HDR_REQ *hdr_req, ACL_VSTRING *sbuf) +{ + http_off_t n; + char buf[4096]; + HTTP_REQ *http_req = NULL; + http_req = http_req_new(hdr_req); + +#define MAX_LEN 1024 * 8 + +#undef RETURN +#define RETURN(_x_) do { \ + if (http_req) { \ + http_req->hdr_req = NULL; \ + http_req_free(http_req); \ + } \ + return (_x_); \ +} while (0) + + while (1) { + n = http_req_body_get_sync2(http_req, client, buf, sizeof(buf)); + if (n < 0) { + RETURN (-1); + } else if (n == 0) + break; + if (acl_vstring_memcat(sbuf, buf, (size_t) n) == NULL) { + RETURN (-1); + } + if (LEN(sbuf) > MAX_LEN) { + RETURN (-1); + } + } + + RETURN (0); +} + +static int http_service(ACL_VSTREAM *client) +{ + const char *myname = "http_service"; + HTTP_HDR_REQ *hdr_req = NULL; + ACL_VSTRING *sbuf = NULL; + char dbname[256]; + const char *ptr, *action, *method, *key; + DICT_POOL *dict_pool; + int ret; + +#undef RETURN +#define RETURN(_x_) do { \ + if (hdr_req) \ + http_hdr_req_free(hdr_req); \ + if (sbuf) \ + acl_vstring_free(sbuf); \ + return (_x_); \ +} while (0) + + hdr_req = http_hdr_req_new(); + ret = http_hdr_req_get_sync(hdr_req, client, var_cfg_rw_timeout); + if (ret != HTTP_CHAT_OK) { + acl_debug(100, 2) ("%s(%d): get http req hdr error(%d, %s)", + myname, __LINE__, ret, strerror(errno)); + RETURN (-1); + } + + if (http_hdr_req_parse(hdr_req) < 0) { + acl_msg_error("%s(%d); parse req hdr error", myname, __LINE__); + http_error_reply(client, 400, "Bad request, invalid request header"); + RETURN (-1); + } + + ptr = http_hdr_req_param(hdr_req, "dbname"); + if (ptr == NULL) + ACL_SAFE_STRNCPY(dbname, "default", sizeof(dbname)); + else { + ACL_SAFE_STRNCPY(dbname, ptr, sizeof(dbname)); + acl_lowercase(dbname); + } + + dict_pool = (DICT_POOL*) acl_htable_find(__db_table, dbname); + if (dict_pool == NULL) { + acl_msg_error("%s(%d): dbname(%s) not found", + myname, __LINE__, dbname); + http_error_reply(client, 404, "Dict not exist"); + RETURN (-1); + } + + method = http_hdr_req_method(hdr_req); + if (method == NULL) { + acl_msg_error("%s(%d): no method", myname, __LINE__); + http_error_reply(client, 400, "Bad request, no Method"); + RETURN (-1); + } + + key = http_hdr_req_param(hdr_req, "key"); + if (key == NULL) { + acl_msg_error("%s(%d): no key(%s)", myname, __LINE__, STR(hdr_req->url_part)); + http_error_reply(client, 400, "Bad request, no key"); + RETURN (-1); + } + + action = http_hdr_req_param(hdr_req, "action"); + if (action == NULL) { + acl_msg_error("%s(%d): no action", myname, __LINE__); + http_error_reply(client, 400, "Bad request, no action"); + RETURN (-1); + } else if (strcasecmp(action, "set") == 0) { + if (strcasecmp(method, "GET") == 0) { + ptr = http_hdr_req_param(hdr_req, "value"); + if (ptr == NULL) { + acl_msg_error("%s(%d): no value", myname, __LINE__); + http_error_reply(client, 400, "Bad request, no value"); + RETURN (-1); + } + ret = set_to_db(client, hdr_req, dict_pool, key, ptr, strlen(ptr)); + RETURN (ret); + } else if (strcasecmp(method, "POST") == 0) { + sbuf = acl_vstring_alloc(MAX_LEN); + if (get_body_from_req(client, hdr_req, sbuf) < 0) { + RETURN (-1); + } + ret = set_to_db(client, hdr_req, dict_pool, key, STR(sbuf), LEN(sbuf)); + RETURN (ret); + } else { + acl_msg_error("%s(%d): method(%s) not support", + myname, __LINE__, method); + http_error_reply(client, 501 , "Method not support"); + RETURN (-1); + } + } else if (strcasecmp(action, "get") == 0) { + if (strcasecmp(method, "GET") != 0) { + acl_msg_error("%s(%d): not GET method(%s) for get data", + myname, __LINE__, method); + http_error_reply(client, 400, "Bad request, should be GET request"); + RETURN (-1); + } + ret = get_from_db(client, hdr_req, dict_pool, key); + RETURN (ret); + } else { + acl_msg_error("%s(%d): unsupport action(%s)", + myname, __LINE__, action); + http_error_reply(client, 400, "Bad request, not support action"); + RETURN (-1); + } +} + +/* 协议处理函数入口 */ +int http_service_main(ACL_VSTREAM *client, void *run_ctx acl_unused) +{ + if (isatty(ACL_VSTREAM_SOCK(client))) + __stream_out = ACL_VSTREAM_OUT; + else + __stream_out = client; + return (http_service(client)); +} diff --git a/samples/dict/unix/http_service.h b/samples/dict/unix/http_service.h new file mode 100644 index 000000000..a58c7c1b4 --- /dev/null +++ b/samples/dict/unix/http_service.h @@ -0,0 +1,16 @@ +#ifndef __HTTP_SERVICE_INCLUDE_H__ +#define __HTTP_SERVICE_INCLUDE_H__ + +#include "lib_acl.h" + +/* in http_service.c */ + +void http_service_init(void *init_ctx); +void http_service_exit(void *exit_ctx); +int http_service_main(ACL_VSTREAM *client, void *run_ctx); + +/* in http_error.c */ + +void http_error_reply(ACL_VSTREAM *client, int status, const char *msg); + +#endif diff --git a/samples/dict/unix/main.c b/samples/dict/unix/main.c new file mode 100644 index 000000000..28cc2cfb1 --- /dev/null +++ b/samples/dict/unix/main.c @@ -0,0 +1,27 @@ +#include "app_main.h" +#include "service_main.h" + +static const char reply_403_close[] = "HTTP/1.1 403 Permission denied\r\n" + "Accept-Ranges: bytes\r\n" + "Server: dict_http/1.0.0 (Unix)\r\n" + "Content-Length: 9\r\n" + "Connection: close\r\n" + "\r\n" + "403 Permission denied!\r\n"; + +int main(int argc, char *argv[]) +{ + app_main(argc, argv, service_main, NULL, + APP_CTL_INIT_FN, service_init, + /* APP_CTL_INIT_CTX, NULL, */ + APP_CTL_EXIT_FN, service_exit, + /* APP_CTL_EXIT_CTX, NULL, */ + APP_CTL_CFG_BOOL, service_conf_bool_tab, + APP_CTL_CFG_INT, service_conf_int_tab, + APP_CTL_CFG_STR, service_conf_str_tab, + APP_CTL_DENY_INFO, reply_403_close, + APP_CTL_END); + + exit (0); +} + diff --git a/samples/dict/unix/service_main.c b/samples/dict/unix/service_main.c new file mode 100644 index 000000000..d40fffd07 --- /dev/null +++ b/samples/dict/unix/service_main.c @@ -0,0 +1,112 @@ +#include "lib_acl.h" +#include "lib_protocol.h" +#include "dict_pool.h" +#include "http_service.h" +#include "service_main.h" + +/* 配置文件项 */ +char *var_cfg_mysql_dbaddr; +char *var_cfg_mysql_dbuser; +char *var_cfg_mysql_dbpass; +char *var_cfg_mysql_dbname; + +char *var_cfg_dbpath; +char *var_cfg_dbnames; + +int var_cfg_mysql_dbmax; +int var_cfg_mysql_dbping; +int var_cfg_mysql_dbtimeout; +int var_cfg_mysql_auto_commit; + +int var_cfg_debug_mem; +int var_cfg_rw_timeout; +int var_cfg_use_bdb; + +#define STR acl_vstring_str +#define LEN ACL_VSTRING_LEN + +/* configure pool */ + +/* TODO: you can add configure items here */ + +ACL_CONFIG_BOOL_TABLE service_conf_bool_tab[] = { + /* TODO: you can add configure variables of int type here */ + { "debug_mem", 0, &var_cfg_debug_mem }, + { "use_bdb", 1, &var_cfg_use_bdb }, + { 0, 0, 0 }, +}; + +ACL_CONFIG_INT_TABLE service_conf_int_tab[] = { + /* TODO: you can add configure variables of int type here */ + { "mysql_dbmax", 250, &var_cfg_mysql_dbmax, 0, 0 }, + { "mysql_dbping", 60, &var_cfg_mysql_dbping, 0, 0 }, + { "mysql_dbtimeout", 300, &var_cfg_mysql_dbtimeout, 0, 0 }, + { "mysql_auto_commit", 1, &var_cfg_mysql_auto_commit, 0, 0 }, + + { "rw_timeout", 1200, &var_cfg_rw_timeout, 0, 0 }, + { 0, 0, 0, 0, 0 }, +}; + +ACL_CONFIG_STR_TABLE service_conf_str_tab[] = { + + /* TODO: you can add configure variables of (char *) type here */ + { "mysql_dbaddr", "127.0.0.1:3306", &var_cfg_mysql_dbaddr }, + { "mysql_dbname", "ioctl_db", &var_cfg_mysql_dbname }, + { "mysql_dbuser", "ioctl_user", &var_cfg_mysql_dbuser }, + { "mysql_dbpass", "111111", &var_cfg_mysql_dbpass }, + { "db_names", "default:8", &var_cfg_dbnames }, + { "db_path", "/opt/acl/var/db", &var_cfg_dbpath }, + + { 0, 0, 0 }, +}; + +/* 初始化函数 */ +void service_init(void *init_ctx) +{ + acl_init(); + http_service_init(init_ctx); +} + +void service_exit(void *exit_ctx) +{ + http_service_exit(exit_ctx); +} + +/* 协议处理函数入口 */ +int service_main(ACL_VSTREAM *client, void *run_ctx acl_unused) +{ +#ifdef TEST_ECHO + char buf[256]; + int ret; + + ACL_VSTREAM_SET_RWTIMO(client, 1200); + + if (var_cfg_debug_mem) + acl_msg_info("total alloc: %d", acl_mempool_total_allocated()); + + do { + if (isatty(ACL_VSTREAM_SOCK(client))) { + printf("Please input: "); + fflush(stdout); + } else + acl_msg_info("waiting ......"); + ret = acl_vstream_gets(client, buf, sizeof(buf)); + if (ret == ACL_VSTREAM_EOF) + return (-1); + buf[ret] = 0; + if (isatty(ACL_VSTREAM_SOCK(client))) + ret = acl_vstream_printf("Your input: %s", buf); + else { + acl_msg_info("wakeup now, ret=%d", ret); + ret = acl_vstream_writen(client, buf, strlen(buf)); + } + if (ret == ACL_VSTREAM_EOF) + return (-1); + } while (1); + + acl_msg_info("over now\r\n"); + return (-1); +#else + return (http_service_main(client, run_ctx)); +#endif +} diff --git a/samples/dict/unix/service_main.h b/samples/dict/unix/service_main.h new file mode 100644 index 000000000..9c3a9b62f --- /dev/null +++ b/samples/dict/unix/service_main.h @@ -0,0 +1,55 @@ + +#ifndef __SERVICE_MAIN_INCLUDE_H__ +#define __SERVICE_MAIN_INCLUDE_H__ + +#include "lib_acl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* 配置文件项 */ +/* in service_main.c */ +extern char *var_cfg_mysql_dbaddr; +extern char *var_cfg_mysql_dbuser; +extern char *var_cfg_mysql_dbpass; +extern char *var_cfg_mysql_dbname; +extern int var_cfg_mysql_dbmax; +extern int var_cfg_mysql_auto_commit; +extern int var_cfg_mysql_dbping; +extern int var_cfg_mysql_dbtimeout; + +extern int var_cfg_debug_mem; +extern int var_cfg_rw_timeout; +extern int var_cfg_use_bdb; +extern char *var_cfg_dbpath; +extern char *var_cfg_dbnames; + +extern ACL_CONFIG_BOOL_TABLE service_conf_bool_tab[]; +extern ACL_CONFIG_INT_TABLE service_conf_int_tab[]; +extern ACL_CONFIG_STR_TABLE service_conf_str_tab[]; + +/** + * 初始化函数,服务器模板框架启动后仅调用该函数一次 + * @param init_ctx {void*} 用户自定义类型指针 + */ +extern void service_init(void *init_ctx); + +/** + * 进程退出时的回调函数 + * @param exist_ctx {void*} 用户自定义类型指针 + */ +extern void service_exit(void *exit_ctx); + +/** + * 协议处理函数入口 + * @param stream {ACL_VSTREAM*} 客户端数据连接流 + * @param run_ctx {void*} 用户自定义类型指针 + */ +extern int service_main(ACL_VSTREAM *stream, void *run_ctx); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/samples/dict/unix_aio/app_log.c b/samples/dict/unix_aio/app_log.c new file mode 100644 index 000000000..a937fed4d --- /dev/null +++ b/samples/dict/unix_aio/app_log.c @@ -0,0 +1,234 @@ + +#include "lib_acl.h" +#include +#include "app_log.h" + +#ifdef HAS_LIB_CORE +#include "e_config.h" +#include "elib.h" + +typedef struct LOG_WRAP { + E_LOG_T *h_log; + char filename[1024]; +} LOG_WRAP; + +static LOG_WRAP *__log_wrap = NULL; + +static int __log_open(const char *filename, void *ctx) +{ + LOG_WRAP *h_log = (LOG_WRAP *) ctx; + int logme = 0; + char *facility_name = NULL; + E_LOG_PRIORITY_T priority = E_LOG_INFO; + E_LOG_ACTION_T action = E_LOG_PER_DAY; + int flush = 1; + size_t limit_size = 0; + E_LOG_SYNC_ACTION_T sync_action = E_LOG_SEM_WITH_MT; + char *sem_name = NULL; + char *ptr, *pname; + ACL_ARGV *env_argv; + ACL_VSTRING *log_buf; + int i; + + if (filename == NULL || *filename == 0) + return (-1); + + acl_snprintf(h_log->filename, sizeof(h_log->filename), "%s", filename); + + /* env: facility:x, priority:x, action:x, flush:x, limit_size:x, sync_action:x, sem_name:x */ + + ptr = getenv("SERVICE_ENV"); + if (ptr == NULL) + return (-1); + + env_argv = acl_argv_split(ptr, ",\t "); + if (env_argv == NULL) + return (-1); + if (env_argv->argc == 0) { + acl_argv_free(env_argv); + return (-1); + } + + log_buf = acl_vstring_alloc(256); + + for (i = 0; i < env_argv->argc; i++) { + pname = acl_argv_index(env_argv, i); + ptr = strchr(pname, ':'); + if (ptr == NULL) + continue; + *ptr++ = 0; + if (*ptr == 0) + continue; + + if (i == 0) + acl_vstring_sprintf(log_buf, "%s:%s", pname, ptr); + else + acl_vstring_sprintf_append(log_buf, ", %s:%s", pname, ptr); + + if (strcasecmp(pname, "logme") == 0) { + if (strcasecmp(ptr, "TRUE") == 0) + logme = 1; + } else if (strcasecmp(pname, "facility") == 0) { + facility_name = ptr; + } else if (strcasecmp(pname, "priority") == 0) { + if (strcasecmp(ptr, "E_LOG_NOLOG") == 0) + priority = E_LOG_NOLOG; + else if (strcasecmp(ptr, "E_LOG_EMERG") == 0) + priority = E_LOG_EMERG; + else if (strcasecmp(ptr, "E_LOG_ALERT") == 0) + priority = E_LOG_ALERT; + else if (strcasecmp(ptr, "E_LOG_CRIT") == 0) + priority = E_LOG_CRIT; + else if (strcasecmp(ptr, "E_LOG_ERR") == 0) + priority = E_LOG_ERR; + else if (strcasecmp(ptr, "E_LOG_WARNING") == 0) + priority = E_LOG_WARNING; + else if (strcasecmp(ptr, "E_LOG_NOTICE") == 0) + priority = E_LOG_NOTICE; + else if (strcasecmp(ptr, "E_LOG_INFO") == 0) + priority = E_LOG_INFO; + else if (strcasecmp(ptr, "E_LOG_DEBUG") == 0) + priority = E_LOG_DEBUG; + } else if (strcasecmp(pname, "action") == 0) { + if (strcasecmp(ptr, "E_LOG_PER_HOUR") == 0) + action = E_LOG_PER_HOUR; + else if (strcasecmp(ptr, "E_LOG_PER_DAY") == 0) + action = E_LOG_PER_DAY; + else if (strcasecmp(ptr, "E_LOG_PER_WEEK") == 0) + action = E_LOG_PER_WEEK; + else if (strcasecmp(ptr, "E_LOG_PER_MONTH") == 0) + action = E_LOG_PER_MONTH; + else if (strcasecmp(ptr, "E_LOG_PER_YEAR") == 0) + action = E_LOG_PER_YEAR; + else if (strcasecmp(ptr, "E_LOG_LIMIT_SIZE") == 0) + action = E_LOG_LIMIT_SIZE; + else if (strcasecmp(ptr, "E_LOG_SYSLOG") == 0) + action = E_LOG_SYSLOG; + } else if (strcasecmp(pname, "flush") == 0) { + if (strcasecmp(ptr, "sync_flush") == 0) + flush = 1; + else if (strcasecmp(ptr, "async_flush") == 0) + flush = 0; + } else if (strcasecmp(pname, "limit_size") == 0) { + limit_size = atoi(ptr); + } else if (strcasecmp(pname, "sync_action") == 0) { + if (strcasecmp(ptr, "E_LOG_NO_SYNC") == 0) + sync_action = E_LOG_NO_SYNC; + else if (strcasecmp(ptr, "E_LOG_THREAD_MUTEX") == 0) + sync_action = E_LOG_THREAD_MUTEX; + else if (strcasecmp(ptr, "E_LOG_FILE_LOCK") == 0) + sync_action = E_LOG_FILE_LOCK; + else if (strcasecmp(ptr, "E_LOG_SEM_WITH_MT") == 0) + sync_action = E_LOG_SEM_WITH_MT; + else if (strcasecmp(ptr, "E_LOG_FILE_APPEND_WITH_MT") == 0) + sync_action = E_LOG_FILE_APPEND_WITH_MT; + } else if (strcasecmp(pname, "sem_name") == 0) { + sem_name = ptr; + } + } + + +#if 0 + LC_SysLogCreate(&h_log->h_log, h_log->filename); +#endif + if (action == E_LOG_LIMIT_SIZE) { + if (limit_size == 0) + limit_size = 512; /* set default size: 512 MB */ + } else + limit_size = 0; + + if (sync_action == E_LOG_SEM_WITH_MT) { + if (sem_name == NULL || *sem_name == 0) { + sem_name = acl_concatenate("/tmp/", acl_safe_basename(filename), ".sem", NULL); + } else + sem_name = acl_mystrdup(sem_name); + } else if (sem_name) { + sem_name = NULL; + } + + h_log->h_log = e_log_new2(h_log->filename, priority, action, + flush, limit_size, facility_name, sync_action, sem_name); + + if (sem_name) + acl_myfree(sem_name); + + if (logme) { + /* + char cmd[1024], buf[512]; + + snprintf(buf, sizeof(buf), "filename=%s, priority=%d, action=%d, flush=%d, " + "limit_size=%d, facility_name=%s, sync_action=%d, sem_name=%s", + h_log->filename, priority, action, + flush, limit_size, facility_name, sync_action, sem_name); + snprintf(cmd, sizeof(cmd), "echo '%s, buf(%s)' >> /tmp/test1.log", acl_vstring_str(log_buf), buf); + system(cmd); + */ + + e_log2(h_log->h_log, "master_env: %s", acl_vstring_str(log_buf)); + } + + e_log2(h_log->h_log, "filename=%s, priority=%d, action=%d, flush=%d, " + "limit_size=%d, facility_name=%s, sync_action=%d, sem_name=%s", + h_log->filename, priority, action, + flush, limit_size, facility_name, sync_action, sem_name); + + if (log_buf) + acl_vstring_free(log_buf); + + return (0); +} + +static void __log_close(void *ctx acl_unused) +{ +} + +static void __log_write(void *ctx, const char *fmt, va_list ap) +{ + LOG_WRAP *h_log = (LOG_WRAP *) ctx; +#if 0 + char buf[1024], cmd[2048]; + + vsnprintf(buf, sizeof(buf), fmt, ap); + + snprintf(cmd, sizeof(cmd), "echo \"%s\" >> /tmp/out.txt", buf); + system(cmd); +#endif + +#if 0 + LC_SysLogFmtWrite2(&h_log->h_log, fmt, ap); +#endif + if (h_log->h_log) + e_vlog2(h_log->h_log, fmt, ap); +} + +void app_set_libcore_log(void) +{ + LOG_WRAP *h_log; + + h_log = acl_mycalloc(1, sizeof(LOG_WRAP)); + if (h_log == NULL) + return; + + acl_msg_register(__log_open, __log_close, __log_write, (void *) h_log); + __log_wrap = h_log; +} + +void app_libcore_log_end(void) +{ + if (__log_wrap == NULL) + return; + if (__log_wrap->h_log == NULL) + return; + acl_msg_info("service exit now"); + e_log_free(__log_wrap->h_log); + __log_wrap->h_log = NULL; +} +#else +void app_set_libcore_log() +{ + const char *myname = "app_set_libcore_log"; + + acl_msg_fatal("%s: not supported", myname); +} +#endif + diff --git a/samples/dict/unix_aio/app_log.h b/samples/dict/unix_aio/app_log.h new file mode 100644 index 000000000..aa7ec36f6 --- /dev/null +++ b/samples/dict/unix_aio/app_log.h @@ -0,0 +1,17 @@ + +#ifndef __LOG_WRAP_INCLUDE_H__ +#define __LOG_WRAP_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +extern void app_set_libcore_log(void); +extern void app_libcore_log_end(void); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/samples/dict/unix_aio/app_main.c b/samples/dict/unix_aio/app_main.c new file mode 100644 index 000000000..60cf7ac2d --- /dev/null +++ b/samples/dict/unix_aio/app_main.c @@ -0,0 +1,251 @@ +#include "lib_acl.h" +#include +#include +#include +#include + +#include "app_log.h" +#include "app_main.h" + +static int __mempool_limit = 0; +static int __mempool_use_mutex = 0; + +static APP_RUN_FN __run_fn = NULL; +static void *__run_ctx = NULL; +static APP_INIT_FN __app_init_fn = NULL; +static void *__app_init_ctx = NULL; +static APP_EXIT_FN __app_exit_fn = NULL; +static void *__app_exit_ctx = NULL; +/* +static APP_THREAD_INIT_FN __app_thread_init_fn = NULL; +static APP_THREAD_EXIT_FN __app_thread_exit_fn = NULL; +*/ + +static char *__default_deny_info = "You are not welcome!\r\n"; +static char *__deny_info; + +static void __service(ACL_ASTREAM *astream, char *service acl_unused, char **argv acl_unused) +{ + char myname[] = "__service"; + ACL_VSTREAM *stream = acl_aio_vstream(astream); + char ip[64]; + + /* + * Sanity check. This service takes no command-line arguments. + */ + if (argv[0]) + acl_msg_fatal("%s, %s(%d): unexpected command-line argument: %s, service=%s", + __FILE__, myname, __LINE__, + argv[0], service ? service : "null"); + + acl_watchdog_pat(); + + if (isatty(ACL_VSTREAM_SOCK(acl_aio_vstream(astream)))) { + (void) __run_fn(astream, __run_ctx); + return; + } + + if (acl_getpeername(ACL_VSTREAM_SOCK(stream), ip, sizeof(ip)) < 0) { + acl_msg_warn("%s, %s(%d): can't get socket's ip", + __FILE__, myname, __LINE__); + acl_aio_iocp_close(astream); + } else if (!acl_access_permit(ip)) { + acl_msg_warn("%s, %s(%d): ip(%s) be denied", + __FILE__, myname, __LINE__, ip); + acl_aio_writen(astream, __deny_info, strlen(__deny_info)); + acl_aio_iocp_close(astream); + } else if (__run_fn(astream, __run_ctx) != 0) + acl_aio_iocp_close(astream); +} + +static void __pre_accept(char *name acl_unused, char **argv acl_unused) +{ +} + +static void __pre_jail_init(char *name acl_unused, char **argv acl_unused) +{ + /* 是否采用 libcore 的日志记录 */ +#ifdef HAS_LIB_CORE +# ifdef USE_LIBCORE_LOG + app_set_libcore_log(); +# endif +#endif +} + +static void __post_jail_init(char *name acl_unused, char **argv acl_unused) +{ + + if (acl_var_aio_access_allow != NULL) + acl_access_add(acl_var_aio_access_allow, ",", ":"); + + if (__app_init_fn != NULL) + __app_init_fn(__app_init_ctx); + + if (__mempool_limit > 0) { + acl_msg_info("use mempool, size limit is %d, %s mutex", + __mempool_limit, __mempool_use_mutex ? "use" : "no"); + } + + /* TODO: you can add some init functions here */ +} + +static void __app_on_exit(char *service acl_unused, char **argv acl_unused) +{ + if (__app_exit_fn) + __app_exit_fn(__app_exit_ctx); +#ifdef HAS_LIB_CORE +# ifdef USE_LIBCORE_LOG + app_libcore_log_end(); +# endif +#endif +} + +/* +static void __thread_init(void *arg) +{ + if (__app_thread_init_fn) + __app_thread_init_fn(arg); +} + +static void __thread_exit(void *arg) +{ + if (__app_thread_exit_fn) + __app_thread_exit_fn(arg); +} +*/ + +static void app_main_init(void) +{ + char *ptr, *pname; + ACL_ARGV *env_argv; + int i; + + ptr = getenv("SERVICE_ENV"); + if (ptr == NULL || *ptr == 0) + return; + + env_argv = acl_argv_split(ptr, ",\t "); + if (env_argv == NULL) + return; + if (env_argv->argc == 0) { + acl_argv_free(env_argv); + return; + } + + for (i = 0; i argc; i++) { + pname = acl_argv_index(env_argv, i); + ptr = strchr(pname, ':'); + if (ptr == NULL) + continue; + *ptr++ = 0; + if (ptr == 0) + continue; + if (strcasecmp(pname, "mempool_limit") == 0) { + __mempool_limit = atoi(ptr); + } else if (strcasecmp(pname, "mempool_use_mutex") == 0) { + if (strcasecmp(ptr, "true") == 0) + __mempool_use_mutex = 1; + } + } + + acl_argv_free(env_argv); + + if (__mempool_limit > 0) + acl_mempool_open(__mempool_limit, __mempool_use_mutex); + + __deny_info = __default_deny_info; +} + +static ACL_CONFIG_BOOL_TABLE null_conf_bool_tab[] = { + /* TODO: you can add configure variables of int type here */ + { 0, 0, 0 }, +}; + +static ACL_CONFIG_INT_TABLE null_conf_int_tab[] = { + /* TODO: you can add configure variables of int type here */ + { 0, 0, 0, 0, 0 }, +}; + +static ACL_CONFIG_STR_TABLE null_conf_str_tab[] = { + /* TODO: you can add configure variables of int type here */ + { 0, 0, 0 }, +}; + +void app_main(int argc, char *argv[], APP_RUN_FN run_fn, void *run_ctx, int name, ...) +{ + const char *myname = "app_main"; + va_list ap; + ACL_CONFIG_BOOL_TABLE *bool_tab = null_conf_bool_tab; + ACL_CONFIG_INT_TABLE *int_tab = null_conf_int_tab; + ACL_CONFIG_STR_TABLE *str_tab = null_conf_str_tab; + + app_main_init(); + /* 提前进行模板初始化,以使日志尽早地打开 */ + acl_master_log_open(argv[0]); + + if (run_fn == NULL) + acl_msg_fatal("%s: run_fn null", myname); + + __run_fn = run_fn; + __run_ctx = run_ctx; + + va_start(ap, name); + + for (; name != APP_CTL_END; name = va_arg(ap, int)) { + switch (name) { + case APP_CTL_INIT_FN: + __app_init_fn = va_arg(ap, APP_INIT_FN); + break; + case APP_CTL_INIT_CTX: + __app_init_ctx = va_arg(ap, void *); + break; + case APP_CTL_EXIT_FN: + __app_exit_fn = va_arg(ap, APP_EXIT_FN); + break; + case APP_CTL_EXIT_CTX: + __app_exit_ctx = va_arg(ap, void *); + break; + /* + case APP_CTL_THREAD_INIT: + __app_thread_init_fn = va_arg(ap, APP_THREAD_INIT_FN); + break; + case APP_CTL_THREAD_INIT_CTX: + thread_init_ctx = va_arg(ap, void*); + break; + case APP_CTL_THREAD_EXIT: + __app_thread_exit_fn = va_arg(ap, APP_THREAD_EXIT_FN); + break; + case APP_CTL_THREAD_EXIT_CTX: + thread_exit_ctx = va_arg(ap, void*); + break; + */ + case APP_CTL_CFG_BOOL: + bool_tab = va_arg(ap, ACL_CONFIG_BOOL_TABLE *); + break; + case APP_CTL_CFG_INT: + int_tab = va_arg(ap, ACL_CONFIG_INT_TABLE *); + break; + case APP_CTL_CFG_STR: + str_tab = va_arg(ap, ACL_CONFIG_STR_TABLE *); + break; + case APP_CTL_DENY_INFO: + __deny_info = acl_mystrdup(va_arg(ap, const char*)); + break; + default: + acl_msg_info("%s: bad name(%d)", myname, name); + } + } + + va_end(ap); + + acl_aio_server_main(argc, argv, __service, + ACL_MASTER_SERVER_BOOL_TABLE, bool_tab, + ACL_MASTER_SERVER_INT_TABLE, int_tab, + ACL_MASTER_SERVER_STR_TABLE, str_tab, + ACL_MASTER_SERVER_PRE_INIT, __pre_jail_init, + ACL_MASTER_SERVER_PRE_ACCEPT, __pre_accept, + ACL_MASTER_SERVER_POST_INIT, __post_jail_init, + ACL_MASTER_SERVER_EXIT, __app_on_exit, + 0); +} + diff --git a/samples/dict/unix_aio/app_main.h b/samples/dict/unix_aio/app_main.h new file mode 100644 index 000000000..f2ab21fcd --- /dev/null +++ b/samples/dict/unix_aio/app_main.h @@ -0,0 +1,69 @@ +#ifndef __APP_MAIN_INCLUDE_H__ +#define __APP_MAIN_INCLUDE_H__ + +#include "lib_acl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* 客户端读写超时时间值 */ +extern int app_var_client_idle_limit; + +/* 用户级的运行函数类型, 当该函数返回值 != 0 时, 框架会自动关闭客户端流 */ +typedef int (*APP_RUN_FN)(ACL_ASTREAM *stream, void *run_ctx); + +/* 用户级的初始化函数类型 */ +typedef void (*APP_INIT_FN)(void*); +typedef void (*APP_EXIT_FN)(void*); + +typedef ACL_MASTER_SERVER_THREAD_INIT_FN APP_THREAD_INIT_FN /* void (*)(void*) */; +typedef ACL_MASTER_SERVER_THREAD_EXIT_FN APP_THREAD_EXIT_FN; /* void (*)(void*) */ + +#define APP_CTL_END 0 /* 参数控制结束标志 */ +#define APP_CTL_INIT_FN 1 /* 初始化函数 */ +#define APP_CTL_INIT_CTX 2 /* 初始化函数所用的参数 */ +#define APP_CTL_CFG_BOOL 3 /* 整数类型的配置参数表 */ +#define APP_CTL_CFG_INT 4 /* 整数类型的配置参数表 */ +#define APP_CTL_CFG_STR 5 /* 字符串类型的配置参数表 */ +#define APP_CTL_EXIT_FN 6 /* 当进程退出时的回调函数 */ +#define APP_CTL_EXIT_CTX 7 /* 进程退出时回调函数的参数 */ +#define APP_CTL_THREAD_INIT 8 /* 每个线程启动时的回调函数 */ +#define APP_CTL_THREAD_INIT_CTX 9 /* 线程启动时回调函数的参数 */ +#define APP_CTL_THREAD_EXIT 10 /* 线程退出时的回调函数 */ +#define APP_CTL_THREAD_EXIT_CTX 11 /* 线程退出时回调函数的参数 */ +#define APP_CTL_DENY_INFO 12 /* 当非法客户端访问时给出的提示信息 */ + +/*----------------------------------------------------------------------------*/ +/* in app_main.c */ + +/** + * 主函数入口, 用户级的初始化函数指针及运行函数指针通过控制参数进行注册, 主函数内部 + * 会在初始化时自动调用用户级初始化函数(APP_INIT_FN 类型), 当接收到允许访问的客户端 + * 连接时会自动调用用户(APP_RUN_FN 类型). + * 级的运行函数. + * @param argc "int main(int argc, char *argv[])" 中的 argc + * @param argv "int main(int argc, char *argv[])" 中的 argv + * @param run_fn 用户级运行主函数 + * @param run_ctx run_fn() 运行时的参数之一 + * @param name 控制参数中的第一个控制类型, 所支持的类型如上定义: APP_CTL_XXX + * 调用方式: APP_CTL_XXX, xxx; 其中 APP_CTL_END 为特殊的控制参数, 表示控制参数 + * 结束. + * @example: + * app_main(argc, argv, {run_fn}, {run_ctx}, + * APP_CTL_INIT_FN, {run_init_fn}, + * APP_CTL_INIT_CTX, {run_init_ctx}, + * APP_CTL_END); + * 注: app_main() 的所有参数中, argc, argv, run_fn, run_ctx(可以为NULL), APP_CTL_END + * 都是必需的. + */ + +extern void app_main(int argc, char *argv[], APP_RUN_FN run_fn, void *run_ctx, int name, ...); + +/*----------------------------------------------------------------------------*/ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/samples/dict/unix_aio/http_client.c b/samples/dict/unix_aio/http_client.c new file mode 100644 index 000000000..eb15b6378 --- /dev/null +++ b/samples/dict/unix_aio/http_client.c @@ -0,0 +1,52 @@ +#include "lib_acl.h" +#include "lib_protocol.h" +#include "http_service.h" + +HTTP_CLIENT *http_client_new(ACL_ASTREAM *stream) +{ + HTTP_CLIENT *client; + + client = (HTTP_CLIENT*) acl_mycalloc(1, sizeof(HTTP_CLIENT)); + client->hdr_req = http_hdr_req_new(); + client->stream = stream; + client->http_req = NULL; + + return (client); +} + +void http_client_free(HTTP_CLIENT *client) +{ + if (client->hdr_req) + http_hdr_req_free(client->hdr_req); + if (client->http_req) { + client->http_req->hdr_req = NULL; + http_req_free(client->http_req); + } + + if (client->key) + acl_vstring_free(client->key); + if (client->sbuf) + acl_vstring_free(client->sbuf); + acl_myfree(client); +} + +void http_client_reset(HTTP_CLIENT *client) +{ + if (client->hdr_req) { + TRACE(); + http_hdr_req_reset(client->hdr_req); + } + + if (client->http_req) { + TRACE(); + client->http_req->hdr_req = NULL; + TRACE(); + http_req_free(client->http_req); + TRACE(); + client->http_req = NULL; + } + if (client->key) + ACL_VSTRING_RESET(client->key); + if (client->sbuf) + ACL_VSTRING_RESET(client->sbuf); +} diff --git a/samples/dict/unix_aio/http_error.c b/samples/dict/unix_aio/http_error.c new file mode 100644 index 000000000..26b92beda --- /dev/null +++ b/samples/dict/unix_aio/http_error.c @@ -0,0 +1,43 @@ +#include "lib_acl.h" +#include "http_service.h" + +static char reply_error_fmt[] = "HTTP/1.1 %d %s\r\n" + "Accept-Ranges: bytes\r\n" + "Server: dict_http/1.0.0 (Unix)\r\n" + "Content-type: text/html\r\n" + "Connection: close\r\n\r\n"; + +static void free_buf(void *arg) +{ + ACL_VSTRING *s = (ACL_VSTRING*) arg; + + acl_vstring_free(s); +} + +void http_error_reply(HTTP_CLIENT *http_client, int status, const char *msg) +{ + static __thread ACL_VSTRING *__buf = NULL; + const ACL_VSTRING *str; + const char *ptr; + struct iovec iov[2]; + + if (__buf == NULL) { + __buf = acl_vstring_alloc(256); + acl_pthread_atexit_add(__buf, free_buf); + } + + ptr = http_tmpl_title(status); + str = http_tmpl_get(status); + + if (msg == NULL || *msg == 0) + msg = acl_vstring_str(str); + + acl_vstring_sprintf(__buf, reply_error_fmt, status, ptr); + + iov[0].iov_base = acl_vstring_str(__buf); + iov[0].iov_len = ACL_VSTRING_LEN(__buf); + iov[1].iov_base = (char*) msg; + iov[1].iov_len = strlen(msg); + + acl_aio_writev(http_client->stream, iov, 2); +} diff --git a/samples/dict/unix_aio/http_service.c b/samples/dict/unix_aio/http_service.c new file mode 100644 index 000000000..c23443b2b --- /dev/null +++ b/samples/dict/unix_aio/http_service.c @@ -0,0 +1,402 @@ + +#include "lib_acl.h" +#include +#include +#include "lib_protocol.h" +#include "dict_pool.h" +#include "service_main.h" +#include "http_service.h" + +#define STR acl_vstring_str +#define LEN ACL_VSTRING_LEN +#define MAX_LEN (1024 * 8) + +static ACL_HTABLE *__db_table = NULL; + +static const char *__partions[] = { + "./cache1", + "./cache2", + "./cache3", + "./cache4" +}; +static int __partions_size = 4; + +/* forward declare */ +static void http_service_start(HTTP_CLIENT *http_client); + +void http_service_init(void *init_ctx acl_unused) +{ + const char *myname = "http_service_init"; + DICT_POOL *pool; + ACL_ARGV *argv; + ACL_VSTRING *buf = acl_vstring_alloc(256); + char *ptr, *name; + int i, n, has_default_db = 0; + + acl_init(); + http_init(NULL); + dict_pool_init(); + + if (__db_table != NULL) + acl_msg_fatal("%s(%d): service_init been called more than once", + myname, __LINE__); + + __db_table = acl_htable_create(10); + + argv = acl_argv_split(var_cfg_dbnames, ", "); + if (argv == NULL) + acl_msg_fatal("%s(%d): db_names(%s) invalid", var_cfg_dbnames); + + for (i = 0; i < argv->argc; i++) { + name = argv->argv[i]; + ptr = strchr(name, ':'); + if (ptr == NULL) { + acl_msg_warn("%s(%d): dbname(%s) use one db", myname, __LINE__, name); + n = 1; + } else { + *ptr++ = 0; + n = atoi(ptr); + } + if (n <= 0) + n = 1; + acl_lowercase(name); + acl_vstring_sprintf(buf, "btree:%s/%s", var_cfg_dbpath, name); + pool = dict_pool_new(__partions, __partions_size, "btree", + var_cfg_dbpath, name, 1); + if (acl_htable_enter(__db_table, name, (char*) pool) == NULL) + acl_msg_fatal("%s(%d): add %s error", myname, __LINE__, name); + if (strcmp(name, "default") == 0) + has_default_db = 1; + } + acl_argv_free(argv); + + if (!has_default_db) { + acl_vstring_sprintf(buf, "btree:%s/default", var_cfg_dbpath); + pool = dict_pool_new(__partions, __partions_size, "btree", + var_cfg_dbpath, "default", 1); + if (acl_htable_enter(__db_table, "default", (char*) pool) == NULL) + acl_msg_fatal("%s(%d): add default error", myname, __LINE__); + } + + acl_vstring_free(buf); +} + +static void dict_pool_free_fn(char *arg) +{ + DICT_POOL *pool = (DICT_POOL*) arg; + + dict_pool_free(pool); +} + +void http_service_exit(void *exit_ctx acl_unused) +{ + if (__db_table) + acl_htable_free(__db_table, dict_pool_free_fn); +} + +static int send_ready(ACL_ASTREAM *stream acl_unused, void *context) +{ + HTTP_CLIENT *http_client = (HTTP_CLIENT*) context; + int keep_alive; + + TRACE(); + if (http_client->hdr_req && http_client->hdr_req->hdr.keep_alive) + keep_alive = 1; + else + keep_alive = 0; + + http_client_reset(http_client); + + /* get next request */ + if (keep_alive) + http_service_start(http_client); + return (0); +} + +static int set_to_db(HTTP_CLIENT *http_client, DICT_POOL *dict_pool, + const char *key, const char *value, size_t len) +{ + static const char reply_200_keep[] = "HTTP/1.1 200 OK\r\n" + "Accept-Ranges: bytes\r\n" + "Server: dict_http/1.0.0 (Unix)\r\n" + "Content-Length: 9\r\n" + "Connection: keep-alive\r\n" + "\r\n" + "200 OK!\r\n"; + static const char reply_200_close[] = "HTTP/1.1 200 OK\r\n" + "Accept-Ranges: bytes\r\n" + "Server: dict_http/1.0.0 (Unix)\r\n" + "Content-Length: 9\r\n" + "Connection: close\r\n" + "\r\n" + "200 OK!\r\n"; + + dict_pool_set(dict_pool, (char*) key, strlen(key), (char*) value, len); + + acl_aio_ctl(http_client->stream, + ACL_AIO_CTL_WRITE_HOOK_ADD, send_ready, http_client, + ACL_AIO_CTL_END); + if (http_client->hdr_req->hdr.keep_alive) { + acl_aio_writen(http_client->stream, reply_200_keep, sizeof(reply_200_keep) - 1); + return (0); + } else { + acl_aio_writen(http_client->stream, reply_200_close, sizeof(reply_200_close) - 1); + return (-1); + } +} + +static int get_from_db(HTTP_CLIENT *http_client, DICT_POOL *dict_pool, const char *key) +{ + static char reply_404_close[] = "HTTP/1.1 404 not found\r\n" + "Accept-Ranges: bytes\r\n" + "Server: dict_http/1.0.0 (Unix)\r\n" + "Content-Length: 15\r\n" + "Connection: close\r\n" + "\r\n" + "404 not found\r\n"; + static char reply_404_keep[] = "HTTP/1.1 404 not found\r\n" + "Accept-Ranges: bytes\r\n" + "Server: dict_http/1.0.0 (Unix)\r\n" + "Content-Length: 15\r\n" + "Connection: keep-alive\r\n" + "\r\n" + "404 not found\r\n"; + static char reply_200_close[] = "HTTP/1.1 200 OK\r\n" + "Accept-Ranges: bytes\r\n" + "Server: dict_http/1.0.0 (Unix)\r\n" + "Content-type: text/html\r\n" + "Connection: close\r\n"; + static char reply_200_keep[] = "HTTP/1.1 200 OK\r\n" + "Accept-Ranges: bytes\r\n" + "Server: dict_http/1.0.0 (Unix)\r\n" + "Content-type: text/html\r\n" + "Connection: Keep-Alive\r\n"; + static const char *reply_length_fmt = "Content-Length: %d\r\n\r\n"; + char found_second[256]; + char *value; + size_t size; + struct iovec iov[3]; + + if (var_cfg_use_bdb) + value = dict_pool_get(dict_pool, (char*) key, strlen(key), &size); + else { + key = key; + dict_pool = dict_pool; + value = acl_mystrdup("test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4test4\r\n"); + size = strlen(value); + } + + acl_aio_ctl(http_client->stream, + ACL_AIO_CTL_WRITE_HOOK_ADD, send_ready, http_client, + ACL_AIO_CTL_END); + + if (value == NULL) { + if (http_client->hdr_req->hdr.keep_alive) { + acl_aio_writen(http_client->stream, reply_404_keep, sizeof(reply_404_keep) - 1); + return (0); + } else { + acl_aio_writen(http_client->stream, reply_404_close, sizeof(reply_404_close) - 1); + return (-1); + } + } + + snprintf(found_second, sizeof(found_second), reply_length_fmt, size); + if (http_client->hdr_req->hdr.keep_alive) { + iov[0].iov_base = reply_200_keep; + iov[0].iov_len = sizeof(reply_200_keep) - 1; + } else { + iov[0].iov_base = reply_200_close; + iov[0].iov_len = sizeof(reply_200_close) - 1; + } + iov[1].iov_base = found_second; + iov[1].iov_len = strlen(found_second); + iov[2].iov_base = value; + iov[2].iov_len = size; + + if (http_client->hdr_req->hdr.keep_alive) { + TRACE(); + acl_aio_writev(http_client->stream, iov, 3); + acl_myfree(value); + return (0); + } else { + TRACE(); + acl_aio_writev(http_client->stream, iov, 3); + acl_myfree(value); + return (-1); + } +} + +static int read_request_body_ready(int status, const char *data, int dlen, void *arg) +{ + HTTP_CLIENT *http_client = (HTTP_CLIENT*) arg; + + if (status >= HTTP_CHAT_ERR_MIN) { + acl_msg_error("%s(%d): status(%d) error", + __FUNCTION__, __LINE__, status); + http_error_reply(http_client, 400, "Invalid request"); + return (-1); + } else if (status == HTTP_CHAT_OK) { + return (set_to_db(http_client, + http_client->dict_pool, + STR(http_client->key), + STR(http_client->sbuf), + LEN(http_client->sbuf))); + } + + acl_vstring_memcat(http_client->sbuf, data, dlen); + if (LEN(http_client->sbuf) >= MAX_LEN) { + acl_msg_error("%s(%d): len(%s) too long", + __FUNCTION__, __LINE__, LEN(http_client->sbuf)); + http_error_reply(http_client, 403, "Request too large"); + return (-1); + } + return (0); +} + +static int get_req_body(HTTP_CLIENT *http_client, DICT_POOL *dict_pool, const char *key) +{ + http_client->dict_pool = dict_pool; + if (http_client->key == NULL) + http_client->key = acl_vstring_alloc(256); + acl_vstring_strcpy(http_client->key, key); + + TRACE(); + if (http_client->http_req != NULL) + acl_msg_fatal("%s(%d): http_req not null", __FUNCTION__, __LINE__); + + http_client->http_req = http_req_new(http_client->hdr_req); + http_req_body_get_async(http_client->http_req, + http_client->stream, + read_request_body_ready, + http_client, + var_cfg_rw_timeout); + return (0); +} + +static int http_service(HTTP_CLIENT *http_client) +{ + const char *myname = "http_service"; + char dbname[256]; + const char *ptr, *action, *method, *key; + DICT_POOL *dict_pool; + HTTP_HDR_REQ *hdr_req = http_client->hdr_req; + + ptr = http_hdr_req_param(hdr_req, "dbname"); + if (ptr == NULL) + ACL_SAFE_STRNCPY(dbname, "default", sizeof(dbname)); + else { + ACL_SAFE_STRNCPY(dbname, ptr, sizeof(dbname)); + acl_lowercase(dbname); + } + + dict_pool = (DICT_POOL*) acl_htable_find(__db_table, dbname); + if (dict_pool == NULL) { + acl_msg_error("%s(%d): dbname(%s) not found", + myname, __LINE__, dbname); + http_error_reply(http_client, 404, "Dict not exist"); + return (-1); + } + + method = http_hdr_req_method(hdr_req); + if (method == NULL) { + acl_msg_error("%s(%d): no method", myname, __LINE__); + http_error_reply(http_client, 400, "Bad request, no Method"); + return (-1); + } + + key = http_hdr_req_param(hdr_req, "key"); + if (key == NULL) { + acl_msg_error("%s(%d): no key(%s)", myname, __LINE__, STR(hdr_req->url_part)); + http_error_reply(http_client, 400, "Bad request, no key"); + return (-1); + } + + action = http_hdr_req_param(hdr_req, "action"); + if (action == NULL) { + acl_msg_error("%s(%d): no action", myname, __LINE__); + http_error_reply(http_client, 400, "Bad request, no action"); + return (-1); + } else if (strcasecmp(action, "set") == 0) { + if (strcasecmp(method, "GET") == 0) { + ptr = http_hdr_req_param(hdr_req, "value"); + if (ptr == NULL) { + acl_msg_error("%s(%d): no value", myname, __LINE__); + http_error_reply(http_client, 400, "Bad request, no value"); + return (-1); + } + return (set_to_db(http_client, dict_pool, key, ptr, strlen(ptr))); + } else if (strcasecmp(method, "POST") == 0) { + if (http_client->sbuf == NULL) + http_client->sbuf = acl_vstring_alloc(MAX_LEN); + return (get_req_body(http_client, dict_pool, key)); + } else { + acl_msg_error("%s(%d): method(%s) not support", + myname, __LINE__, method); + http_error_reply(http_client, 501 , "Method not support"); + return (-1); + } + } else if (strcasecmp(action, "get") == 0) { + if (strcasecmp(method, "GET") != 0) { + acl_msg_error("%s(%d): not GET method(%s) for get data", + myname, __LINE__, method); + http_error_reply(http_client, 400, "Bad request, should be GET request"); + return (-1); + } + return (get_from_db(http_client, dict_pool, key)); + } else { + acl_msg_error("%s(%d): unsupport action(%s)", + myname, __LINE__, action); + http_error_reply(http_client, 400, "Bad request, not support action"); + return (-1); + } +} + +static int request_header_ready(int status, void *arg) +{ + HTTP_CLIENT *http_client = (HTTP_CLIENT*) arg; + + if (status != HTTP_CHAT_OK) { + TRACE(); + acl_debug(20, 2) ("%s(%d): status(%d)", __FUNCTION__, __LINE__, status); + http_error_reply(http_client, 400, "Bad request, invalid request header, read error"); + return (-1); + } + + if (http_hdr_req_parse(http_client->hdr_req) < 0) { + acl_msg_error("%s(%d): parse hdr_req error", __FUNCTION__, __LINE__); + http_error_reply(http_client, 400, "Bad request, invalid request header, parse error"); + return (-1); + } + + return (http_service(http_client)); +} + +static int on_close_client(ACL_ASTREAM *client acl_unused, void *context) +{ + HTTP_CLIENT *http_client = (HTTP_CLIENT*) context; + + TRACE(); + http_client_free(http_client); + return (-1); +} + +static void http_service_start(HTTP_CLIENT *http_client) +{ + TRACE(); + acl_aio_ctl(http_client->stream, + ACL_AIO_CTL_CLOSE_HOOK_ADD, on_close_client, http_client, + ACL_AIO_CTL_END); + http_hdr_req_get_async(http_client->hdr_req, + http_client->stream, + request_header_ready, + http_client, + var_cfg_rw_timeout); +} + +void http_service_main(ACL_ASTREAM *stream, void *ctx acl_unused) +{ + HTTP_CLIENT *http_client; + + http_client = http_client_new(stream); + http_service_start(http_client); +} diff --git a/samples/dict/unix_aio/http_service.h b/samples/dict/unix_aio/http_service.h new file mode 100644 index 000000000..4ba15c204 --- /dev/null +++ b/samples/dict/unix_aio/http_service.h @@ -0,0 +1,37 @@ +#ifndef __HTTP_SERVICE_INCLUDE_H__ +#define __HTTP_SERVICE_INCLUDE_H__ + +#include "lib_acl.h" +#include "lib_protocol.h" +#include "dict_pool.h" + +#if 0 +#define TRACE() acl_msg_info(">>>%s: %d", __FUNCTION__, __LINE__) +#else +#define TRACE() +#endif + +typedef struct HTTP_CLIENT { + ACL_ASTREAM *stream; + HTTP_HDR_REQ *hdr_req; /* HTTP协议请求头指针 */ + HTTP_REQ *http_req; + ACL_VSTRING *sbuf; + ACL_VSTRING *key; + DICT_POOL *dict_pool; +} HTTP_CLIENT; + +/* http_client.c */ + +HTTP_CLIENT *http_client_new(ACL_ASTREAM *stream); +void http_client_free(HTTP_CLIENT *client); +void http_client_reset(HTTP_CLIENT *client); + +/* http_service.c */ +void http_service_init(void *init_ctx); +void http_service_exit(void *exit_ctx); +void http_service_main(ACL_ASTREAM *stream, void *ctx); + +/* in http_error.c */ +void http_error_reply(HTTP_CLIENT *http_client, int status, const char *msg); + +#endif diff --git a/samples/dict/unix_aio/main.c b/samples/dict/unix_aio/main.c new file mode 100644 index 000000000..ed0387390 --- /dev/null +++ b/samples/dict/unix_aio/main.c @@ -0,0 +1,29 @@ +#include "app_main.h" +#include "app_log.h" +#include "service_main.h" + +static const char reply_403_close[] = "HTTP/1.1 403 Permission denied\r\n" + "Accept-Ranges: bytes\r\n" + "Server: dict_http/1.0.0 (Unix)\r\n" + "Content-Length: 9\r\n" + "Connection: close\r\n" + "\r\n" + "403 Permission denied!\r\n"; + +int main(int argc, char *argv[]) +{ + /* acl_debug_malloc_init("log.txt"); */ + app_main(argc, argv, service_main, NULL, + APP_CTL_INIT_FN, service_init, + /* APP_CTL_INIT_CTX, NULL, */ + APP_CTL_EXIT_FN, service_exit, + /* APP_CTL_EXIT_CTX, NULL, */ + APP_CTL_CFG_BOOL, service_conf_bool_tab, + APP_CTL_CFG_INT, service_conf_int_tab, + APP_CTL_CFG_STR, service_conf_str_tab, + APP_CTL_DENY_INFO, reply_403_close, + APP_CTL_END); + + exit (0); +} + diff --git a/samples/dict/unix_aio/service_main.c b/samples/dict/unix_aio/service_main.c new file mode 100644 index 000000000..5c05d4422 --- /dev/null +++ b/samples/dict/unix_aio/service_main.c @@ -0,0 +1,65 @@ + +#include "lib_acl.h" +#include +#include +#include "lib_protocol.h" +#include "dict_pool.h" + +#include "app_main.h" +#include "http_service.h" +#include "service_main.h" + +/* configure pool */ + +/* TODO: you can add configure items here */ + +int var_cfg_debug_mem; +char *var_cfg_dbpath; +char *var_cfg_dbnames; +int var_cfg_rw_timeout; +int var_cfg_use_bdb; + +ACL_CONFIG_BOOL_TABLE service_conf_bool_tab[] = { + /* TODO: you can add configure variables of int type here */ + { "debug_mem", 0, &var_cfg_debug_mem }, + { "use_bdb", 1, &var_cfg_use_bdb }, + + { 0, 0, 0 }, +}; + +ACL_CONFIG_INT_TABLE service_conf_int_tab[] = { + /* TODO: you can add configure variables of int type here */ + + { "rw_timeout", 1200, &var_cfg_rw_timeout, 0, 0 }, + { 0, 0, 0, 0, 0 }, +}; + +ACL_CONFIG_STR_TABLE service_conf_str_tab[] = { + + /* TODO: you can add configure variables of (char *) type here */ + /* example: { "mysql_dbaddr", "127.0.0.1:3306", &var_cfg_mysql_dbaddr }, */ + + { "db_names", "default:8", &var_cfg_dbnames }, + { "db_path", "dbpath", &var_cfg_dbpath }, + { 0, 0, 0 }, +}; + +void service_init(void *init_ctx) +{ + acl_init(); + http_service_init(init_ctx); +} + +void service_exit(void *exit_ctx) +{ + http_service_exit(exit_ctx); +} + +int service_main(ACL_ASTREAM *stream, void *run_ctx) +{ + if (var_cfg_debug_mem) + acl_msg_info("total alloc: %d", acl_mempool_total_allocated()); + + http_service_main(stream, run_ctx); + return (0); +} diff --git a/samples/dict/unix_aio/service_main.h b/samples/dict/unix_aio/service_main.h new file mode 100644 index 000000000..467121da3 --- /dev/null +++ b/samples/dict/unix_aio/service_main.h @@ -0,0 +1,48 @@ + +#ifndef __SERVICE_MAIN_INCLUDE_H__ +#define __SERVICE_MAIN_INCLUDE_H__ + +#include "lib_acl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* 配置文件项 */ +/* in service_main.c */ + +extern int var_cfg_debug_mem; +extern char *var_cfg_dbpath; +extern char *var_cfg_dbnames; +extern int var_cfg_rw_timeout; +extern int var_cfg_use_bdb; + +extern ACL_CONFIG_BOOL_TABLE service_conf_bool_tab[]; +extern ACL_CONFIG_INT_TABLE service_conf_int_tab[]; +extern ACL_CONFIG_STR_TABLE service_conf_str_tab[]; + +/** + * 初始化函数,服务器模板框架启动后仅调用该函数一次 + * @param init_ctx {void*} 用户自定义类型指针, 可以在调用 + * app_main() 时引入 + */ +extern void service_init(void *init_ctx); + +/** + * 进程退出时的回调函数 + * @param exist_ctx {void*} 用户自定义类型指针 + */ +extern void service_exit(void *exit_ctx); + +/** + * 协议处理函数入口 + * @param stream {ACL_VSTREAM*} 客户端数据连接流 + * @param run_ctx {void*} 用户自定义类型指针 + */ +extern int service_main(ACL_ASTREAM *astream, void *run_ctx); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/samples/dlink/Makefile b/samples/dlink/Makefile new file mode 100644 index 000000000..ca0fff429 --- /dev/null +++ b/samples/dlink/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = dlink diff --git a/samples/dlink/dlink.vcxproj b/samples/dlink/dlink.vcxproj new file mode 100644 index 000000000..882783401 --- /dev/null +++ b/samples/dlink/dlink.vcxproj @@ -0,0 +1,185 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + ReleaseDll + Win32 + + + Release + Win32 + + + + dlink + {6C3E9644-44A3-486E-827A-8B4381606F29} + dlink + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)dlink.exe + ..\..\lib_acl;%(AdditionalLibraryDirectories) + true + $(OutDir)dlink.pdb + Console + MachineX86 + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)dlink.exe + true + Console + true + true + MachineX86 + + + + + Disabled + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_DLL;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + EditAndContinue + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)dlink.exe + %(AdditionalLibraryDirectories) + true + $(OutDir)dlink.pdb + Console + MachineX86 + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_DLL;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)dlink.exe + true + Console + true + true + MachineX86 + + + + + {b40213c2-507c-4c7f-a6e1-b850c9bdc27b} + false + + + + + + + + + \ No newline at end of file diff --git a/samples/dlink/dlink_vc2003.vcproj b/samples/dlink/dlink_vc2003.vcproj new file mode 100644 index 000000000..9eeb64d46 --- /dev/null +++ b/samples/dlink/dlink_vc2003.vcproj @@ -0,0 +1,237 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/dlink/main.c b/samples/dlink/main.c new file mode 100644 index 000000000..4f02ff658 --- /dev/null +++ b/samples/dlink/main.c @@ -0,0 +1,105 @@ +#include "lib_acl.h" + +static ACL_DLINK *build(void) +{ + const char *myname = "build"; + ACL_DLINK *dlink = acl_dlink_create(100); + + acl_dlink_insert(dlink, 0, 10); + acl_dlink_insert(dlink, 8, 10); + acl_dlink_insert(dlink, 20, 21); + acl_dlink_insert(dlink, 21, 28); + acl_dlink_insert(dlink, 31, 38); + acl_dlink_insert(dlink, 41, 48); + acl_dlink_insert(dlink, 51, 58); + + printf("\r\n%s:\r\n", myname); + acl_dlink_list(dlink); + return (dlink); +} + +static void delete_check(acl_off_t ibegin, acl_off_t iend) +{ + ACL_DLINK *dlink = build(); + + printf(">>> after delete " ACL_FMT_I64D "-" ACL_FMT_I64D ":\r\n", ibegin, iend); + acl_dlink_delete_range(dlink, ibegin, iend); + acl_dlink_list(dlink); + acl_dlink_free(dlink); +} + +static void test(void) +{ + delete_check(0, 5); + delete_check(0, 10); + delete_check(0, 20); + delete_check(0, 21); + delete_check(0, 27); + delete_check(0, 28); + delete_check(0, 40); + delete_check(0, 41); + delete_check(0, 44); + delete_check(0, 47); + delete_check(0, 48); + delete_check(0, 50); + delete_check(0, 51); + delete_check(0, 52); + delete_check(0, 57); + delete_check(0, 58); + printf("Enter any key to continue ...\r\n"); + getchar(); + delete_check(5, 7); + delete_check(5, 9); + delete_check(5, 10); + delete_check(5, 20); + delete_check(5, 21); + delete_check(5, 27); + delete_check(5, 28); + delete_check(5, 41); + delete_check(5, 47); + delete_check(5, 48); + delete_check(5, 50); + delete_check(5, 51); + delete_check(5, 57); + delete_check(5, 58); + printf("Enter any key to continue ...\r\n"); + getchar(); + delete_check(10, 10); + delete_check(10, 11); + delete_check(10, 20); + delete_check(10, 21); + delete_check(10, 27); + delete_check(10, 28); + delete_check(10, 31); + delete_check(10, 37); + delete_check(10, 38); + delete_check(10, 41); + delete_check(10, 48); + delete_check(10, 50); + delete_check(10, 57); + delete_check(10, 58); + printf("Enter any key to continue ...\r\n"); + getchar(); + delete_check(20, 20); + delete_check(20, 21); + delete_check(20, 42); + delete_check(20, 48); + delete_check(20, 51); + delete_check(20, 58); + delete_check(41, 57); + delete_check(41, 59); + delete_check(50, 57); + delete_check(50, 59); + delete_check(51, 57); + delete_check(51, 58); + delete_check(51, 59); + + printf("Enter any key to quit\r\n"); + getchar(); +} +int main(int argc acl_unused, char *argv[] acl_unused) +{ + test(); + return (0); +} + diff --git a/samples/dns/Makefile b/samples/dns/Makefile new file mode 100644 index 000000000..2ab7d86d5 --- /dev/null +++ b/samples/dns/Makefile @@ -0,0 +1,2 @@ +include ../Makefile_cpp.in +PROG = dns diff --git a/samples/dns/dns_test.cpp b/samples/dns/dns_test.cpp new file mode 100644 index 000000000..ab198fc08 --- /dev/null +++ b/samples/dns/dns_test.cpp @@ -0,0 +1,48 @@ +#include "lib_acl.h" + +int dns_lookup(const char *domain, const char *dns_ip, + unsigned short dns_port, ACL_VSTRING *sbuf) +{ + const char *myname = "dns_lookup"; + ACL_RES *res = NULL; + ACL_DNS_DB *dns_db = NULL; + ACL_ITER iter; + +#define RETURN(_x_) do { \ + if (res) \ + acl_res_free(res); \ + if (dns_db) \ + acl_netdb_free(dns_db); \ + return (_x_); \ +} while (0) + + if (sbuf == NULL) + acl_msg_fatal("%s: sbuf null", myname); + + res = acl_res_new(dns_ip, dns_port); + + dns_db = acl_res_lookup(res, domain); + if (dns_db == NULL) { + acl_vstring_sprintf(sbuf, + "failed for domain %s, %s", domain, acl_res_errmsg(res)); + RETURN (-1); + } + + (void) acl_netdb_size(dns_db); + acl_vstring_sprintf_append(sbuf, "type\tttl\tip\t\tnet\t\tqid\t\n"); + acl_foreach(iter, dns_db) { + ACL_HOST_INFO *info; + struct in_addr in; + char buf[32]; + + info = (ACL_HOST_INFO*) iter.data; + in.s_addr = info->saddr.sin_addr.s_addr; + acl_mask_addr((unsigned char*) &in.s_addr, sizeof(in.s_addr), 24); + acl_inet_ntoa(in, buf, sizeof(buf)); + + acl_vstring_sprintf_append(sbuf, "A\t%d\t%s\t%s\t%d\r\n", + info->ttl, info->ip, buf, res->cur_qid); + } + + RETURN (0); +} diff --git a/samples/dns/dns_test.cpp.bak b/samples/dns/dns_test.cpp.bak new file mode 100644 index 000000000..3b371f807 --- /dev/null +++ b/samples/dns/dns_test.cpp.bak @@ -0,0 +1,80 @@ + +#include "lib_acl.h" + +int dns_lookup(const char *domain, const char *dns_ip, + unsigned short dns_port, ACL_VSTRING *strbuf) +{ + const char *myname = "dns_lookup"; + char buf[512]; + char rbuf[512]; + size_t sz = 512; + unsigned short sid; + ACL_SOCKET s; + int rl; + struct sockaddr_in S; + + s = socket(PF_INET, SOCK_DGRAM, 0); + if (s < 0) + acl_msg_fatal("socket create error"); + + memset(&S, '\0', sizeof(S)); + S.sin_family = AF_INET; + S.sin_port = htons(dns_port); + S.sin_addr.s_addr = inet_addr(dns_ip); + + memset(buf, '\0', 512); + sz = 512; + sid = rfc1035BuildAQuery(domain, buf, sz, 100, NULL); + sendto(s, buf, (int) sz, 0, (struct sockaddr *) &S, (int) sizeof(S)); + do { + fd_set R; + struct timeval to; + + FD_ZERO(&R); + FD_SET(s, &R); + to.tv_sec = 10; + to.tv_usec = 0; + rl = select((int) s + 1, &R, NULL, NULL, &to); + } while (0); + + if (rl < 1) { + acl_msg_error("TIMEOUT"); + return -1; + } + memset(rbuf, '\0', 512); + rl = recv(s, rbuf, 512, 0); + + { + unsigned short rid = 0; + int i, n; + rfc1035_message *answers; + + n = rfc1035MessageUnpack(rbuf, rl, &answers); + if (n < 0) { + acl_msg_error("ERROR %d(%s), rl=%d", rfc1035_errno, rbuf, rl); + return (-1); + } + /*else if (rid != sid) { + acl_msg_error("ERROR, ID mismatch (%#hx, %#hx)", sid, rid); + return (-1); + } */ + + acl_msg_info("%d answers", n); + + for (i = 0; i < n; i++) { + if (answers->answer[i].type == RFC1035_TYPE_A) { + struct in_addr a; + memcpy(&a, answers->answer[i].rdata, 4); + acl_msg_info("A\t%d\t%s\n", answers->answer[i].ttl, inet_ntoa(a)); + if (strbuf) + acl_vstring_sprintf_append(strbuf, "A\t%d\t%s\r\n", + answers->answer[i].ttl, inet_ntoa(a)); + } else { + acl_msg_error("can't print answer type %d", (int) answers->answer[i].type); + } + } + rfc1035MessageDestroy(answers); + } + closesocket(s); + return 0; +} diff --git a/samples/dns/dns_test.h b/samples/dns/dns_test.h new file mode 100644 index 000000000..70d5c31df --- /dev/null +++ b/samples/dns/dns_test.h @@ -0,0 +1,8 @@ +#ifndef __DNS_TEST_INCLUDE_H__ +#define __DNS_TEST_INCLUDE_H__ + +#include "lib_acl.h" +extern int dns_lookup(const char *domain, const char *dns_ip, + unsigned short dns_port, ACL_VSTRING *sbuf); + +#endif diff --git a/samples/dns/main.cpp b/samples/dns/main.cpp new file mode 100644 index 000000000..7a9bf882d --- /dev/null +++ b/samples/dns/main.cpp @@ -0,0 +1,53 @@ +#include "lib_acl.h" +#include "dns_test.h" + +static void usage(const char *procname) +{ + printf("usage: %s -h dns_ip -p dns_port -d domain_name\r\n", procname); +} + +int main(int argc, char *argv[]) +{ + char ch; + char dns_ip[64], domain[128]; + int dns_port = 53, ret; + ACL_VSTRING *sbuf; + + dns_ip[0] = 0; + domain[0] = 0; + + while ((ch = getopt(argc, argv, "h:p:d:")) > 0) { + switch (ch) { + case 'h': + ACL_SAFE_STRNCPY(dns_ip, optarg, sizeof(dns_ip)); + break; + case 'p': + dns_port = atoi(optarg); + break; + case 'd': + ACL_SAFE_STRNCPY(domain, optarg, sizeof(domain)); + break; + default: + usage(argv[0]); + return (0); + } + } + + if (dns_ip[0] == 0 || domain[0] == 0) { + usage(argv[0]); + return (0); + } + + sbuf = acl_vstring_alloc(128); + ret = dns_lookup(domain, dns_ip, dns_port, sbuf); + if (ret < 0) { + printf("dns lookup(%s) error(%s)\r\n", domain, acl_vstring_str(sbuf)); + acl_vstring_free(sbuf); + return (0); + } + + printf("domain: %s\r\n%s", domain, acl_vstring_str(sbuf)); + acl_vstring_free(sbuf); + return (0); +} + diff --git a/samples/dns_req/Makefile b/samples/dns_req/Makefile new file mode 100644 index 000000000..4e934d2ea --- /dev/null +++ b/samples/dns_req/Makefile @@ -0,0 +1,2 @@ +include ../Makefile_cpp.in +PROG = dns_req diff --git a/samples/dns_req/dns_req.vcproj b/samples/dns_req/dns_req.vcproj new file mode 100644 index 000000000..d0d8427fd --- /dev/null +++ b/samples/dns_req/dns_req.vcproj @@ -0,0 +1,230 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/dns_req/dns_req.vcxproj b/samples/dns_req/dns_req.vcxproj new file mode 100644 index 000000000..73d8f1502 --- /dev/null +++ b/samples/dns_req/dns_req.vcxproj @@ -0,0 +1,177 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + ReleaseDll + Win32 + + + Release + Win32 + + + + {E3234C5B-84F4-4332-99D3-EBC367C523EA} + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + $(OutDir)dns_req.exe + true + $(OutDir)dns_req.pdb + Console + MachineX86 + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + $(OutDir)dns_req.exe + true + Console + true + true + MachineX86 + + + + + Disabled + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_DLL;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + EditAndContinue + + + $(OutDir)dns_req.exe + true + $(OutDir)dns_req.pdb + Console + MachineX86 + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_DLL;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + $(OutDir)dns_req.exe + true + Console + true + true + MachineX86 + + + + + {b40213c2-507c-4c7f-a6e1-b850c9bdc27b} + false + + + + + + + + + \ No newline at end of file diff --git a/samples/dns_req/main.cpp b/samples/dns_req/main.cpp new file mode 100644 index 000000000..24f59c7b3 --- /dev/null +++ b/samples/dns_req/main.cpp @@ -0,0 +1,133 @@ +#include "lib_acl.h" +#if defined(ACL_MS_WINDOWS) +#pragma comment(lib,"ws2_32") +#pragma comment(lib, "wsock32") +#endif + +static int __nresult = 0; + +static void callback(ACL_DNS_DB *dns_db, void *ctx, int errnum) +{ + ACL_ITER iter; + char *domain = (char*) ctx; + + if (dns_db == NULL) { + printf(">>>lookup result error(%s), domain(%s)\n", + acl_dns_serror(errnum), domain); + __nresult++; + return; + } + + printf(">>>lookup result, domain(%s)\n", dns_db->name); + + acl_foreach(iter, dns_db) { + const ACL_HOST_INFO *info; + + info = (const ACL_HOST_INFO*) iter.data; + printf("\tip=%s, ttl=%d\n", info->ip, info->ttl); + } + + __nresult++; +} + +static void dns_lookup(char *domains, const char *dns_ips, int dns_port) +{ + ACL_AIO *aio = acl_aio_create(ACL_EVENT_SELECT); + ACL_DNS *dns = acl_dns_create(aio, 5); + ACL_ARGV *argv = acl_argv_split(domains, ",:;|"); + ACL_ARGV *ip_argv = acl_argv_split(dns_ips, ",:;|"); + ACL_ITER iter; + + /* 打开DNS缓存功能 */ + acl_dns_open_cache(dns, 100); + + /* 添加DNS服务器地址 */ + acl_foreach(iter, ip_argv) { + char *ip = (char*) iter.data; + acl_dns_add_dns(dns, ip, dns_port, 24); + } + + acl_argv_free(ip_argv); + + /* 校验DNS地址有效性 */ + acl_dns_check_dns_ip(dns); + + /* 查询域名所对应的IP地址 */ + acl_foreach(iter, argv) { + char *domain = (char*) iter.data; + printf(">>>call dns lookup for: %s\n", domain); + acl_dns_lookup(dns, domain, callback, domain); + } + + while (__nresult < iter.size) { + acl_aio_loop(aio); + } + + printf("---------------------------------------------------\n"); + printf(">>>Dns cache result search\n\n"); + /* 查询结果清零 */ + __nresult = 0; + + /* 通过缓存查询域名所对应的IP地址 */ + acl_foreach(iter, argv) { + char *domain = (char*) iter.data; + printf(">>>call dns lookup for: %s\n", domain); + acl_dns_lookup(dns, domain, callback, domain); + } + + while (__nresult < iter.size) { + acl_aio_loop(aio); + } + + acl_argv_free(argv); + acl_dns_close(dns); + acl_aio_free(aio); +} + +static void usage(const char *procname) +{ + printf("usage: %s -s dns_ip_list[192.168.0.1:192.168.0.2]" + " -p dns_port -d domain_list[www.sina.com.cn:www.sohu.com]\r\n", procname); +} + +int main(int argc, char *argv[]) +{ + int ch; + char dns_ips[512], domains[1024]; + int dns_port = 53; + + dns_ips[0] = 0; + domains[0] = 0; + + acl_init(); + + while ((ch = getopt(argc, argv, "s:p:d:")) > 0) { + switch (ch) { + case 's': + ACL_SAFE_STRNCPY(dns_ips, optarg, sizeof(dns_ips)); + break; + case 'p': + dns_port = atoi(optarg); + break; + case 'd': + ACL_SAFE_STRNCPY(domains, optarg, sizeof(domains)); + break; + default: + usage(argv[0]); + return (0); + } + } + + if (dns_ips[0] == 0 || domains[0] == 0) { + usage(argv[0]); + return (0); + } + + dns_lookup(domains, dns_ips, dns_port); +#ifdef ACL_MS_WINDOWS + printf("Enter any key to exit\n"); + getchar(); +#endif + return (0); +} + diff --git a/samples/dns_req/test.sh b/samples/dns_req/test.sh new file mode 100644 index 000000000..88de5d6f0 --- /dev/null +++ b/samples/dns_req/test.sh @@ -0,0 +1,2 @@ +#!/bin/sh +./dns_client -s 60.28.250.40:60.28.250.46 -d www.sina.com:www.hexun.com:www.sohu.com diff --git a/samples/dns_req/valgrind.sh b/samples/dns_req/valgrind.sh new file mode 100644 index 000000000..81f139893 --- /dev/null +++ b/samples/dns_req/valgrind.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +valgrind --tool=memcheck --leak-check=yes --show-reachable=yes -v ./dns_client -s 60.28.250.46 -p 53 -d www.sina.com.cn:www.hexun.com:www.sohu.com:www.163.com diff --git a/samples/event/Makefile b/samples/event/Makefile new file mode 100644 index 000000000..ad29e6a82 --- /dev/null +++ b/samples/event/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = event diff --git a/samples/event/main.c b/samples/event/main.c new file mode 100644 index 000000000..347f1b26b --- /dev/null +++ b/samples/event/main.c @@ -0,0 +1,153 @@ +#include "lib_acl.h" + +typedef struct { + ACL_VSTREAM *in; + ACL_VSTRING *buf; + ACL_EVENT *event; +} STREAM_IN; + +static void trigger_event(int event acl_unused, void *context acl_unused) +{ + printf("timer trigger now\r\n"); +} + +static int __stop_event = 0; + +static STREAM_IN *create_stream(ACL_EVENT *eventp) +{ + STREAM_IN *in = (STREAM_IN*) acl_mymalloc(sizeof(STREAM_IN)); + + in->in = acl_vstream_fhopen(fileno(stdin), 0); /* 用标准输入做为输入流 */ + in->buf = acl_vstring_alloc(256); + in->event = eventp; + return in; +} + +static void free_stream(STREAM_IN *in) +{ + acl_vstream_free(in->in); + acl_vstring_free(in->buf); + acl_myfree(in); +} + +static void read_callback(int event_type acl_unused, void *context) +{ + STREAM_IN *in = (STREAM_IN *) context; + int ready; + + /* 尝试从输入流中读取一行数据,并且要求去掉尾部的回车换行符 */ + if (acl_vstream_gets_nonl_peek(in->in, in->buf, &ready) == ACL_VSTREAM_EOF) + { + acl_event_disable_read(in->event, in->in); + printf(">>>>gets error\r\n"); + free_stream(in); + __stop_event = 1; + } else if (ready) { +#define STR acl_vstring_str + + /* 如果读到完整的一行数据,则显示之 */ + printf(">>>>gets one line: %s\r\n", STR(in->buf)); + + if (strcasecmp(STR(in->buf), "QUIT") == 0) { + __stop_event = 1; + free_stream(in); + } else + ACL_VSTRING_RESET(in->buf); /* 清空缓冲区 */ + } +} + +static void usage(const char *procname) +{ + printf("usage: %s -h [help]\r\n" + " -M [printf time meter]\r\n" + " -t select|poll|kernel [default: select]\r\n" + " -s delay_sec [defaut: 1]\r\n" + " -u delay_usec [default: 0]\r\n" + " -m timer_delay [default: 100 microsecond, disable timer if < 0]\r\n" + " -k [if timer keep on, default: 1]\r\n", procname); +} + +int main(int argc acl_unused, char *argv[] acl_unused) +{ + ACL_EVENT *eventp; + STREAM_IN *in; + char event_type[64]; + int ch, delay_sec = 1, delay_usec = 0; + int timer_delay = 100, timer_keep = 0; + int meter = 0; + + /* 初始化 acl 库 */ + acl_init(); + + /* 将错误日志输出至标准输出 */ + acl_msg_stdout_enable(1); + + event_type[0] = 0; + + while ((ch = getopt(argc, argv, "ht:s:u:m:kM")) > 0) { + switch (ch) { + case 'h': + usage(argv[0]); + return 0; + case 't': + ACL_SAFE_STRNCPY(event_type, optarg, sizeof(event_type)); + break; + case 's': + delay_sec = atoi(optarg); + if (delay_sec < 0) + delay_sec = 0; + break; + case 'u': + delay_usec = atoi(optarg); + if (delay_usec < 0) + delay_usec = 0; + break; + case 'm': + timer_delay = atoi(optarg); + break; + case 'k': + timer_keep = 1; + break; + case 'M': + meter = 1; + break; + default: + break; + } + } + + /* 创建非阻塞事件引擎 */ + if (strcasecmp(event_type, "kernel") == 0) + eventp = acl_event_new_kernel(delay_sec, delay_usec); + else if (strcasecmp(event_type, "poll") == 0) + eventp = acl_event_new_poll(delay_sec, delay_usec); + else + eventp = acl_event_new_select(delay_sec, delay_usec); + + if (timer_delay >= 0) + acl_event_request_timer(eventp, trigger_event, NULL, + timer_delay, timer_keep); + + /* 创建输入流对象 */ + in = create_stream(eventp); + + /* 将标准输入置入异步 IO 监听事件中 */ + acl_event_enable_read(eventp, in->in, 0, read_callback, in); + + printf("begin wait input from standard in\r\n"); + + /* 进行事件循环中 */ + while (!__stop_event) { + if (meter) + ACL_METER_TIME("begin event"); + acl_event_loop(eventp); + if (meter) + ACL_METER_TIME("end event"); + } + + /* 释放事件引擎 */ + acl_event_free(eventp); + + printf("event stopped!\r\n"); + return (0); +} diff --git a/samples/event/valgrind.sh b/samples/event/valgrind.sh new file mode 100644 index 000000000..8df291bbd --- /dev/null +++ b/samples/event/valgrind.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +valgrind --tool=memcheck --leak-check=yes -v ./event diff --git a/samples/fifo/Makefile b/samples/fifo/Makefile new file mode 100644 index 000000000..3b3ab4bfa --- /dev/null +++ b/samples/fifo/Makefile @@ -0,0 +1,2 @@ +include ../Makefile_cpp.in +PROG = fifo diff --git a/samples/fifo/fifo.vcxproj b/samples/fifo/fifo.vcxproj new file mode 100644 index 000000000..e398e14c8 --- /dev/null +++ b/samples/fifo/fifo.vcxproj @@ -0,0 +1,190 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + ReleaseDll + Win32 + + + Release + Win32 + + + + fifo + {B2566BBC-49F1-42D7-85AC-5E2606535138} + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)fifo.exe + %(AdditionalLibraryDirectories) + libcd;%(IgnoreSpecificDefaultLibraries) + true + $(OutDir)fifo.pdb + Console + MachineX86 + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)fifo.exe + %(AdditionalLibraryDirectories) + libc;%(IgnoreSpecificDefaultLibraries) + true + Console + true + true + MachineX86 + + + + + Disabled + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + EditAndContinue + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)fifo.exe + %(AdditionalLibraryDirectories) + libcd;%(IgnoreSpecificDefaultLibraries) + true + $(OutDir)fifo.pdb + Console + MachineX86 + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)fifo.exe + %(AdditionalLibraryDirectories) + libc;%(IgnoreSpecificDefaultLibraries) + true + Console + true + true + MachineX86 + + + + + {b40213c2-507c-4c7f-a6e1-b850c9bdc27b} + false + + + + + + + + + \ No newline at end of file diff --git a/samples/fifo/fifo_vc2003.vcproj b/samples/fifo/fifo_vc2003.vcproj new file mode 100644 index 000000000..5fb0f6321 --- /dev/null +++ b/samples/fifo/fifo_vc2003.vcproj @@ -0,0 +1,242 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/fifo/main.cpp b/samples/fifo/main.cpp new file mode 100644 index 000000000..068353303 --- /dev/null +++ b/samples/fifo/main.cpp @@ -0,0 +1,59 @@ +#include "lib_acl.h" +#include +#include + +#ifdef WIN32 +#define snprintf _snprintf +#endif + +static void fifo_test(bool use_slice) +{ + ACL_FIFO *fifo; + int i; + char *ptr; + ACL_SLICE_POOL *slice; + + if (use_slice) + slice = acl_slice_pool_create(10, 100, + ACL_SLICE_FLAG_GC2 | ACL_SLICE_FLAG_RTGC_OFF); + else + slice = NULL; + + fifo = acl_fifo_new1(slice); + + for (i = 0; i < 20; i++) { + if (slice) + ptr = (char*) acl_slice_pool_alloc(__FILE__, __LINE__, + slice, 100); + else + ptr = (char*) acl_mymalloc(100); + snprintf(ptr, 100, "test:%d", i); + (void) acl_fifo_push(fifo, ptr); + printf(">>>ptr: %s\n", ptr); + } + + while (1) { + ptr = (char*) acl_fifo_pop(fifo); + if (ptr == NULL) + break; + printf("fifo pop: %s\n", ptr); + } + + if (slice == NULL) + acl_fifo_free(fifo, acl_myfree_fn); + else + acl_slice_pool_destroy(slice); +} + +int main(int argc acl_unused, char *argv[] acl_unused) +{ + bool use_slice; + + if (argc >= 2 && strcasecmp(argv[1], "slice") == 0) + use_slice = true; + else + use_slice = false; + fifo_test(use_slice); + getchar(); + return (0); +} diff --git a/samples/fifo/valgrind.sh b/samples/fifo/valgrind.sh new file mode 100644 index 000000000..203c38646 --- /dev/null +++ b/samples/fifo/valgrind.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +valgrind --tool=memcheck --leak-check=yes -v ./fifo slice diff --git a/samples/file/Makefile b/samples/file/Makefile new file mode 100644 index 000000000..b96f705e5 --- /dev/null +++ b/samples/file/Makefile @@ -0,0 +1,2 @@ +include ../Makefile_cpp.in +PROG = file diff --git a/samples/file/file.vcproj b/samples/file/file.vcproj new file mode 100644 index 000000000..a751b6162 --- /dev/null +++ b/samples/file/file.vcproj @@ -0,0 +1,234 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/file/file.vcxproj b/samples/file/file.vcxproj new file mode 100644 index 000000000..e530631ce --- /dev/null +++ b/samples/file/file.vcxproj @@ -0,0 +1,181 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + ReleaseDll + Win32 + + + Release + Win32 + + + + {D4F73163-D0FF-4A01-94AE-41EC2D1FD658} + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)file.exe + true + $(OutDir)file.pdb + Console + MachineX86 + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)file.exe + true + Console + true + true + MachineX86 + + + + + Disabled + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + EditAndContinue + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)file.exe + true + $(OutDir)file.pdb + Console + MachineX86 + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)file.exe + true + Console + true + true + MachineX86 + + + + + {b40213c2-507c-4c7f-a6e1-b850c9bdc27b} + false + + + + + + + + + \ No newline at end of file diff --git a/samples/file/main.cpp b/samples/file/main.cpp new file mode 100644 index 000000000..e174420e9 --- /dev/null +++ b/samples/file/main.cpp @@ -0,0 +1,156 @@ +#include "lib_acl.h" +#include + +static void end(void) +{ +#ifdef ACL_MS_WINDOWS + printf("input any key to exit\r\n"); + fflush(stdout); + getchar(); +#endif + acl_end(); +} + +static void test_file(void) +{ + const char *filename = "test2.txt"; + ACL_FILE *fp = acl_fopen(filename, "a+"); + char buf[1024]; + int i; + + if (fp == NULL) { + printf("fopen %s error(%s)\n", filename, acl_last_serror()); + return; + } + + for (i = 0 ; i < 100; i++) { + if (acl_fputs("hello world!", fp) == EOF) { + printf("fputs to %s error(%s)\n", filename, acl_last_serror()); + break; + } + } + + printf("write to %s ok\n", filename); + acl_fclose(fp); + + fp = acl_fopen(filename, "r"); + if (fp == NULL) { + printf("fopen %s error(%s)\n", filename, acl_last_serror()); + return; + } + + i = 0; + while (!acl_feof(fp)) { + if (acl_fgets(buf, sizeof(buf), fp) == NULL) { + printf("fgets return null, i=%d\n", i); + } else { + i++; + printf(">>gets line(%d): %s", i, buf); + } + } + acl_fclose(fp); +} + +static int test_file3(void) +{ + char buf[1024]; + int ret; + + ACL_VSTREAM *fp = acl_vstream_fopen("test3.txt", O_RDONLY, 0700, 8192); + if (fp == NULL) { + printf("fopen error %s\n", acl_last_serror()); + return (-1); + } + + while (1) { + ret = acl_vstream_gets_nonl(fp, buf, sizeof(buf)); + if (ret == ACL_VSTREAM_EOF) + break; + printf(">>>gets(%s), ret: %d\n", buf, ret); + } + + acl_vstream_fclose(fp); + return (0); +} + +static int test_vstream(void) +{ + const char *filename = "test.txt"; + ACL_VSTREAM *fp = acl_vstream_fopen(filename, O_RDWR | O_CREAT, 0644, 1024); + struct acl_stat sbuf; + char buf[256]; + struct tm *local_time; + + acl_init(); + + if (fp == NULL) { + printf("open file(%s) error(%s)\r\n", filename, acl_last_serror()); + end(); + return (-1); + } + + if (acl_vstream_fstat(fp, &sbuf) < 0) { + acl_vstream_close(fp); + printf("fstat file(%s) error(%s)\r\n", filename, acl_last_serror()); + end(); + return (-1); + } + + printf("file(%s) stat:\r\n", filename); + + printf("size=%d\r\n", (int) sbuf.st_size); + + local_time = localtime(&sbuf.st_mtime); + if (local_time) { + strftime(buf, sizeof(buf), "%Y/%m/%d %H:%M:%S", local_time); + printf("修改时间,mtime=%s\r\n", buf); + } else { + printf("mtime: error(%s)\r\n", acl_last_serror()); + } + + local_time = localtime(&sbuf.st_ctime); + if (local_time) { + strftime(buf, sizeof(buf), "%Y/%m/%d %H:%M:%S", local_time); + printf("创建时间,ctime=%s\r\n", buf); + } else { + printf("ctime: error(%s)\r\n", acl_last_serror()); + } + + local_time = localtime(&sbuf.st_atime); + if (local_time) { + strftime(buf, sizeof(buf), "%Y/%m/%d %H:%M:%S", local_time); + printf("访问时间,atime=%s\r\n", buf); + } else { + printf("atime: error(%s)\r\n", acl_last_serror()); + } + + int ch, ch1; + + ch = ACL_VSTREAM_GETC(fp); + ch = 'a'; + + for (int i = 0; i < 100; i++) { + ch1 = ACL_VSTREAM_PUTC(ch, fp); + assert(ch1 == ch); + printf("ok write char: %c\n", ch1); + } + ACL_VSTREAM_PUTC('\n', fp); + acl_vstream_fclose(fp); + end(); + + FILE *fp1 = fopen("test.txt", "w+"); + assert(fp1); + int ret = fputs("hello", fp1); + printf("ret: %d\n", ret); + fclose(fp1); + return (0); +} + +int main(int argc acl_unused, char *argv[] acl_unused) +{ + (void) test_vstream(); + test_file(); + test_file3(); + return (0); +} + diff --git a/samples/file_fmt/Makefile b/samples/file_fmt/Makefile new file mode 100644 index 000000000..bc374c309 --- /dev/null +++ b/samples/file_fmt/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = file_fmt diff --git a/samples/file_fmt/main.c b/samples/file_fmt/main.c new file mode 100644 index 000000000..055dfb318 --- /dev/null +++ b/samples/file_fmt/main.c @@ -0,0 +1,206 @@ +#include "lib_acl.h" +#include +#include +#include +#include + +#define FMT_ERR -1 +#define FMT_UNIX 0 +#define FMT_DOS 1 +#define FMT_MAC 2 + +static int __total_c_line = 0; +static int __total_h_line = 0; + +static void fmt_change(const char *filepath, const char *fmt) +{ + const char *myname = "fmt_change"; + ACL_VSTREAM *fp; + char *buf, *ptr; + const char *tmp; + int n, ret; + + buf = acl_vstream_loadfile(filepath); + if (buf == NULL) + acl_msg_fatal("%s: loadfile(%s, %s)", + myname, filepath, strerror(errno)); + + fp = acl_vstream_fopen(filepath, O_WRONLY | O_TRUNC, 0600, 4096); + if (fp == NULL) + acl_msg_fatal("%s: open file(%s, %s)", + myname, filepath, strerror(errno)); + + ptr = buf; + + while (*ptr) { + n = 0; + if (*ptr == '\r') { + n++; + ptr++; + if (*ptr == '\n') { + n++; + ptr++; + if (strstr(filepath, "samples") == NULL + && strstr(filepath, "unit_test") == NULL) + { + if (strrncasecmp(filepath, ".c", 2) == 0) + __total_c_line++; + else if (strrncasecmp(filepath, ".h", 2) == 0 + && strstr(filepath, "mysql_include") == NULL + && strstr(filepath, "openssl") == NULL + && strstr(filepath, "bdb") == NULL + && strstr(filepath, "tc") == NULL + && strstr(filepath, "cdb") == NULL) + __total_h_line++; + } + } + } else if (*ptr == '\n') { + n++; + ptr++; + if (strstr(filepath, "samples") == NULL + && strstr(filepath, "unit_test") == NULL) + { + if (strrncasecmp(filepath, ".c", 2) == 0) + __total_c_line++; + else if (strrncasecmp(filepath, ".h", 2) == 0 + && strstr(filepath, "mysql_include") == NULL + && strstr(filepath, "openssl") == NULL + && strstr(filepath, "bdb") == NULL + && strstr(filepath, "tc") == NULL + && strstr(filepath, "cdb") == NULL) + __total_h_line++; + } + } + if (n) { + tmp = fmt; + n = strlen(tmp); + } else { + tmp = ptr++; + n = 1; + } + ret = acl_vstream_buffed_writen(fp, tmp, n); + if (ret == ACL_VSTREAM_EOF) + acl_msg_fatal("%s: write to %s error(%s)", + myname, filepath, strerror(errno)); + } + + if (acl_vstream_fflush(fp) == ACL_VSTREAM_EOF) + acl_msg_fatal("%s: fflush to %s error(%s)", + myname, filepath, strerror(errno)); + acl_vstream_close(fp); + acl_myfree(buf); +} + +static void scan_dir(const char *src_path, int to_fmt) +{ + ACL_SCAN_DIR *scan; + const char *filename, *path, *ptr; + char filepath[1024], fmt_buf[32], info[32]; + int n; + +#define CP ACL_SAFE_STRNCPY + + switch (to_fmt) { + case FMT_UNIX: + CP(info, "UNIX", sizeof(info)); + CP(fmt_buf, "\n", sizeof(fmt_buf)); + break; + case FMT_DOS: + CP(info, "DOS", sizeof(info)); + CP(fmt_buf, "\r\n", sizeof(fmt_buf)); + break; + case FMT_MAC: + CP(info, "MAC", sizeof(info)); + CP(fmt_buf, "\r", sizeof(fmt_buf)); + break; + default: + acl_msg_fatal("unknown fmt(%d)", to_fmt); + } + + scan = acl_scan_dir_open(src_path, 1); + if (scan == NULL) + acl_msg_fatal("open path(%s, %s)", src_path, strerror(errno)); + + n = 0; + while (1) { + filename = acl_scan_dir_next_file(scan); + if (filename == NULL) + break; + if (strlen(filename) < 3) + continue; + ptr = strchr(filename, '.'); + if (ptr == NULL) + continue; + ptr++; + if (strcasecmp(ptr, "c") != 0 && strcasecmp(ptr, "h") != 0 + && strcasecmp(ptr, "cpp") != 0 && strcasecmp(ptr, "hpp") != 0) + continue; + + path = acl_scan_dir_path(scan); + if (path == NULL) + acl_msg_fatal("file(%s) no path", filename); + snprintf(filepath, sizeof(filepath), "%s/%s", + path, filename); + printf("filepath:%s\r\n", filepath); + fmt_change(filepath, fmt_buf); + n++; + } + + acl_scan_dir_close(scan); + + printf(">>> At last, %d files were changed to %s format, total_c_line: %d lines, total_h_line: %d\r\n", + n, info, __total_c_line, __total_h_line); +} + +static void usage(const char *progname) +{ + printf("usage: %s -h help\r\n" + "-f file_format[unix|dos|mac]\r\n" + "-d dir_path\r\n", progname); +} + +int main(int argc, char *argv[]) +{ + char ch; + char *src_path = NULL, *ptr; + int to_fmt = FMT_UNIX; + + + while ((ch = getopt(argc, argv, "hf:d:")) > 0) { + switch (ch) { + case 'h': + usage(argv[0]); + exit (0); + case 'f': + if (strcasecmp(optarg, "unix") == 0) + to_fmt = FMT_UNIX; + else if (strcasecmp(optarg, "dos") == 0) + to_fmt = FMT_DOS; + else if (strcasecmp(optarg, "mac") == 0) + to_fmt = FMT_MAC; + else + to_fmt = FMT_ERR; + break; + case 'd': + src_path = acl_mystrdup(optarg); + break; + default: + usage(argv[0]); + exit (0); + } + } + + if (to_fmt == FMT_ERR || src_path == NULL || *src_path == 0) { + usage(argv[0]); + exit (0); + } + + ptr = src_path + strlen(src_path) - 1; + while (*ptr == '/') { + *ptr-- = 0; + } + + scan_dir(src_path, to_fmt); + + return (0); +} diff --git a/samples/flock/Makefile b/samples/flock/Makefile new file mode 100644 index 000000000..3a3ef6ca1 --- /dev/null +++ b/samples/flock/Makefile @@ -0,0 +1,2 @@ +include ../Makefile_cpp.in +PROG = flock diff --git a/samples/flock/flock.vcxproj b/samples/flock/flock.vcxproj new file mode 100644 index 000000000..e498219aa --- /dev/null +++ b/samples/flock/flock.vcxproj @@ -0,0 +1,186 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + ReleaseDll + Win32 + + + Release + Win32 + + + + flock + {0D12EB24-88E6-427C-94E2-26C2CD7B0670} + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + wsock32.lib;%(AdditionalDependencies) + $(OutDir)flock.exe + %(AdditionalLibraryDirectories) + libcd;libcmt;%(IgnoreSpecificDefaultLibraries) + true + $(OutDir)flock.pdb + Console + MachineX86 + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + wsock32.lib;%(AdditionalDependencies) + $(OutDir)flock.exe + true + Console + true + true + MachineX86 + + + + + Disabled + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_DLL;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + EditAndContinue + + + wsock32.lib;%(AdditionalDependencies) + $(OutDir)flock.exe + %(AdditionalLibraryDirectories) + libcd;libcmt;%(IgnoreSpecificDefaultLibraries) + true + $(OutDir)flock.pdb + Console + MachineX86 + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_DLL;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + wsock32.lib;%(AdditionalDependencies) + $(OutDir)flock.exe + true + Console + true + true + MachineX86 + + + + + {b40213c2-507c-4c7f-a6e1-b850c9bdc27b} + false + + + + + + + + + \ No newline at end of file diff --git a/samples/flock/flock_vc2003.vcproj b/samples/flock/flock_vc2003.vcproj new file mode 100644 index 000000000..d17a76fe9 --- /dev/null +++ b/samples/flock/flock_vc2003.vcproj @@ -0,0 +1,238 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/flock/main.cpp b/samples/flock/main.cpp new file mode 100644 index 000000000..58b07bacf --- /dev/null +++ b/samples/flock/main.cpp @@ -0,0 +1,40 @@ +#include "lib_acl.h" +#include +#include + +int main(int argc acl_unused, char *argv[] acl_unused) +{ + ACL_FILE_HANDLE handle; + const char *filename = "test.lock"; + char ebuf[256]; + + handle = acl_file_open(filename, O_RDWR | O_CREAT, 0600); + if (handle == ACL_FILE_INVALID) { + acl_msg_fatal("open file %s error(%s)", + filename, acl_last_strerror(ebuf, sizeof(ebuf))); + } + + printf("open %s ok, begin to lock it\r\n", filename); + + if (acl_myflock(handle, ACL_MYFLOCK_STYLE_FCNTL, ACL_MYFLOCK_OP_EXCLUSIVE) == -1) { + acl_msg_error("lock error(%s)", acl_last_strerror(ebuf, sizeof(ebuf))); + getchar(); + return (-1); + } + + printf("lock %s ok, enter any key to unlock\r\n", filename); + getchar(); + + if (acl_myflock(handle, ACL_MYFLOCK_STYLE_FCNTL, ACL_MYFLOCK_OP_NONE) == -1) { + acl_msg_error("unlock error(%s)", acl_last_strerror(ebuf, sizeof(ebuf))); + getchar(); + return (-1); + } + + printf("unlock %s ok, enter any key to close file\r\n", filename); + getchar(); + + acl_file_close(handle); + + return (0); +} diff --git a/samples/gc/Makefile b/samples/gc/Makefile new file mode 100644 index 000000000..687b7e783 --- /dev/null +++ b/samples/gc/Makefile @@ -0,0 +1,109 @@ +SHELL = /bin/sh +CC = gcc +#CC = g++ +AR = ar +ARFL = rv +RANLIB = ranlib + +CFLAGS = -c -g -W -Wall -Wcast-qual -Wcast-align \ +-Waggregate-return -Wmissing-prototypes \ +-Wpointer-arith -Werror -Wshadow -pedantic -O2 \ +-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO \ +-Wno-long-long +########################################################### +#Check system: +# Linux, SunOS, Solaris, BSD variants, AIX, HP-UX +SYSLIB = +CHECKSYSRES = @echo "Unknow system type!";exit 1 +UNIXNAME = $(shell uname -sm) + +# For FreeBSD +ifeq ($(findstring FreeBSD, $(UNIXNAME)), FreeBSD) + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DFREEBSD -D_REENTRANT -pedantic + SYSLIB = -lcrypt -lpthread +endif + +#Path for Linux +ifeq ($(findstring Linux, $(UNIXNAME)), Linux) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DLINUX2 + SYSLIB = -lcrypt -lpthread +endif + +#Path for SunOS +ifeq ($(findstring SunOS, $(UNIXNAME)), SunOS) + ifeq ($(findstring 86, $(UNIXNAME)), 86) + SYSLIB = -lsocket -lnsl -lrt + endif + ifeq ($(findstring sun4u, $(UNIXNAME)), sun4u) + SYSLIB = -lsocket -lnsl -lrt + endif + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DSUNOS5 +endif + +#Path for HP-UX +ifeq ($(findstring HP-UX, $(UNIXNAME)), HP-UX) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + SYSLIB = -lpthread + CFLAGS += -DHP_UX -DHPUX11 + PLAT_NAME=hp-ux +endif + +#Find system type. +ifneq ($(SYSPATH),) + CHECKSYSRES = @echo "System is $(shell uname -sm)" +endif +########################################################### + +ACL_PATH = ../../lib_acl +ACL_LIB = $(ACL_PATH)/lib +ACL_INC = $(ACL_PATH)/include + +GC_PATH = /home/zsx/download/gc/bin_cvs +GC_LIB = $(GC_PATH)/lib +GC_INC = $(GC_PATH)/include + +ALL_LIBS = -l_acl $(GC_LIB)/libgccpp.a $(GC_LIB)/libgc.a $(SYSLIB) -ldl + +CFLAGS += -I$(ACL_INC) -I$(GC_INC) + +OUTPATH = ./ +OBJ_OUTPATH = $(OUTPATH) + +#Project's objs +SOURCES = $(wildcard *.c) +INCLUDES = $(wildcard *.h) +OBJS = $(patsubst %.c,$(OBJ_OUTPATH)%.o,$(SOURCES)) + +########################################################### + +PROG_NAME = memgc + +.PHONY = clean +COMPILE = $(CC) $(CFLAGS) + +all: RM $(PROG_NAME) + +RM: + rm -f $(PROG_NAME) + +$(PROG_NAME): $(OBJS) + $(CC) -o $(PROG_NAME) $(OBJS) -L$(ACL_LIB) $(ALL_LIBS) + +$(OBJ_OUTPATH)%.o: %.c *.h + $(COMPILE) -o $@ $< + +clean: + rm -f $(OBJS) $(PROG_NAME) + +rebuild: clean all diff --git a/samples/gc/main.c b/samples/gc/main.c new file mode 100644 index 000000000..a749cfca3 --- /dev/null +++ b/samples/gc/main.c @@ -0,0 +1,18 @@ +#include "lib_acl.h" +#include +#include +#include "mem_gc.h" +#include "mem_test.h" + +static void init(void) +{ + mem_gc_hook(); +} + +int main(int argc acl_unused, char *argv[] acl_unused) +{ + init(); + mem_test(); + return (0); +} + diff --git a/samples/gc/mem_gc.c b/samples/gc/mem_gc.c new file mode 100644 index 000000000..0b465dda8 --- /dev/null +++ b/samples/gc/mem_gc.c @@ -0,0 +1,68 @@ +#include "gc.h" +#include "lib_acl.h" +#include "mem_gc.h" + +/* +#define GC_LINUX_THREADS +#define GC_DEBUG +*/ + +static void *malloc_hook(const char *fname acl_unused, int line acl_unused, size_t size) +{ + return (GC_MALLOC(size)); +/* + return (GC_MALLOC_ATOMIC(size)); +*/ +} + +static void *calloc_hook(const char *fname, int line, size_t nmemb, size_t size) +{ + void *ptr = malloc_hook(fname, line, nmemb * size); + + memset(ptr, 0, nmemb * size); + return (ptr); +} + +static void *realloc_hook(const char *fname acl_unused, int line acl_unused, void *ptr, size_t size) +{ + return (GC_REALLOC(ptr, size)); +} + +static char *strdup_hook(const char *fname acl_unused, int line acl_unused, const char *ptr) +{ + return (GC_STRDUP(ptr)); +} + +static char *strndup_hook(const char *fname, int line, const char *s, size_t len) +{ + size_t n = strlen(s); + char *ptr; + + n = n > len ? len : n; + ptr = (char*) malloc_hook(fname, line, len); + memcpy(ptr, s, n); + ptr[n] = 0; + return (ptr); +} + +static void *memdup_hook(const char *fname, int line, const void *p, size_t size) +{ + void *ptr; + + ptr = malloc_hook(fname, line, size); + memcpy(ptr, p, size); + return (ptr); +} + +static void free_hook(const char *fname acl_unused, int line acl_unused, void *ptr) +{ + GC_FREE(ptr); +} + +void mem_gc_hook() +{ + GC_INIT(); + acl_mem_hook(malloc_hook, calloc_hook, realloc_hook, + strdup_hook, strndup_hook, memdup_hook, free_hook); +} + diff --git a/samples/gc/mem_gc.h b/samples/gc/mem_gc.h new file mode 100644 index 000000000..06f579bcd --- /dev/null +++ b/samples/gc/mem_gc.h @@ -0,0 +1,6 @@ +#ifndef __MEM_GC_INCLUDE_H__ +#define __MEM_GC_INCLUDE_H__ + +void mem_gc_hook(void); + +#endif diff --git a/samples/gc/mem_test.c b/samples/gc/mem_test.c new file mode 100644 index 000000000..9e67e940a --- /dev/null +++ b/samples/gc/mem_test.c @@ -0,0 +1,84 @@ +#include "lib_acl.h" +#include +#include +#include +#include "mem_test.h" + +typedef struct { + char *p; + int n; +} A; + +static A *create_a(size_t n) +{ + A *a = acl_mymalloc(sizeof(A)); + + a->n = n; + a->p = acl_mymalloc(a->n); + + return (a); +} + +static void reset_a(A *a, size_t n) +{ + a->p = acl_mymalloc(n); + a->n = n; + a->p = acl_mymalloc(n); + a->p = acl_mymalloc(n); + a->p = acl_mymalloc(n); +} + +static void thread_run(void *arg) +{ + A *a = (A*) arg; + + assert(a->n > 0); + +#if 0 + acl_myfree(a->p); + acl_myfree(a); +#endif +} + +static void thread_test(void) +{ + acl_pthread_pool_t *thr_pool; + int i, n = 10000000; + A *a; + time_t last, begin; + + begin = time(NULL); + last = begin; + thr_pool = acl_thread_pool_create(20, 120); + for (i = 0; i < n; i++) { + if (i % 10000 == 0) { + time_t t = time(NULL); + printf("i: %d, time: %ld\n", i, t - last); + last = t; + } + a = create_a(1024); + acl_pthread_pool_add(thr_pool, thread_run, a); + } + + acl_pthread_pool_destroy(thr_pool); + printf("total: %d, time: %ld\n", i, time(NULL) - begin); +} + +void mem_test() +{ + A *a; + int i = 0, n = 1000, k = 1; + + for (i = 0; i < n; i++) { + a = create_a(1024); + reset_a(a, 2048); + reset_a(a, 2048); + } + + printf("begin thread_test\n"); + thread_test(); + + printf("ok, sleep %d seconds\n", k); + sleep(k); + printf("ok, wakeup\n"); +} diff --git a/samples/gc/mem_test.h b/samples/gc/mem_test.h new file mode 100644 index 000000000..f1b2219cc --- /dev/null +++ b/samples/gc/mem_test.h @@ -0,0 +1,6 @@ +#ifndef __MEM_TEST_H__ +#define __MEM_TEST_H__ + +void mem_test(void); + +#endif diff --git a/samples/htable/Makefile b/samples/htable/Makefile new file mode 100644 index 000000000..277e53d40 --- /dev/null +++ b/samples/htable/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = htable diff --git a/samples/htable/main.c b/samples/htable/main.c new file mode 100644 index 000000000..2ff3f3b52 --- /dev/null +++ b/samples/htable/main.c @@ -0,0 +1,58 @@ +#include "lib_acl.h" +#include +#include +#include + +static void free_fn(void *arg) +{ + acl_myfree(arg); +} + +static void usage(const char *procname) +{ + printf("usage: %s -h[help] -n count -m[use ACL_HTABLE_FLAG_MSLOOK]\n", procname); +} + +int main(int argc, char *argv[]) +{ + ACL_HTABLE *htable; + char key[128], *value; + int i, n = 50, ch, flag = 0; + + while ((ch = getopt(argc, argv, "hn:m")) > 0) { + switch (ch) { + case 'h': + usage(argv[0]); + return (0); + case 'n': + n = atoi(optarg); + break; + case 'm': + flag |= ACL_HTABLE_FLAG_MSLOOK; + break; + default: + break; + } + } + + htable = acl_htable_create(1, flag); + + for (i = 0; i < n; i++) { + value = (char*) acl_mymalloc(256); + snprintf(value, 256, "value:%d", i); + snprintf(key, sizeof(key), "key:%d", i); + acl_htable_enter(htable, key, value); + } + acl_htable_stat(htable); + + printf("------------------------------------------------------------\n"); + for (i = n - 1; i >= 0; i--) { + snprintf(key, sizeof(key), "key:%d", i); + (void) acl_htable_find(htable, key); + } + acl_htable_stat(htable); + + acl_htable_free(htable, free_fn); + return (0); +} + diff --git a/samples/html_code/Makefile b/samples/html_code/Makefile new file mode 100644 index 000000000..4aec83e49 --- /dev/null +++ b/samples/html_code/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = html_code diff --git a/samples/html_code/html_code.vcproj b/samples/html_code/html_code.vcproj new file mode 100644 index 000000000..e93eb2ac8 --- /dev/null +++ b/samples/html_code/html_code.vcproj @@ -0,0 +1,233 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/html_code/html_code.vcxproj b/samples/html_code/html_code.vcxproj new file mode 100644 index 000000000..a42d0028a --- /dev/null +++ b/samples/html_code/html_code.vcxproj @@ -0,0 +1,180 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + ReleaseDll + Win32 + + + Release + Win32 + + + + {7D44F644-AC16-4A58-A485-3BAD65CE377C} + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + Static + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + ws2_32.lib;wsock32.lib;%(AdditionalDependencies) + $(OutDir)html_code.exe + true + $(OutDir)html_code.pdb + Console + MachineX86 + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + $(OutDir)html_code.exe + true + Console + true + true + MachineX86 + + + + + Disabled + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_DLL;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + + + Level3 + EditAndContinue + + + ws2_32.lib;wsock32.lib;%(AdditionalDependencies) + $(OutDir)html_code.exe + true + $(OutDir)html_code.pdb + Console + MachineX86 + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_DLL;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + $(OutDir)html_code.exe + true + Console + true + true + MachineX86 + + + + + {b40213c2-507c-4c7f-a6e1-b850c9bdc27b} + false + + + + + + + + + \ No newline at end of file diff --git a/samples/html_code/main.c b/samples/html_code/main.c new file mode 100644 index 000000000..8ce49fdf4 --- /dev/null +++ b/samples/html_code/main.c @@ -0,0 +1,46 @@ +#include "lib_acl.h" +#include +#include + +static char *html = \ +"\r\n" +" 'hello world!' \r\n" +" \"hello && world!\" \r\n" +"\r\n"; + +int main(int argc acl_unused, char *argv[] acl_unused) +{ + ACL_VSTRING *buf1 = acl_vstring_alloc(32); + ACL_VSTRING *buf2 = acl_vstring_alloc(32); + + acl_xml_encode(html, buf1); + printf(">>> xml encode: len(%d)\n%s",(int) ACL_VSTRING_LEN(buf1), acl_vstring_str(buf1)); + + printf("------------------------------------------\n"); + + acl_xml_decode(acl_vstring_str(buf1), buf2); + printf(">>> xml decode: len(%d)\n%s", (int) ACL_VSTRING_LEN(buf2), acl_vstring_str(buf2)); + + printf("------------------------------------------\n"); + + ACL_VSTRING_RESET(buf1); + ACL_VSTRING_RESET(buf2); + + acl_html_encode(html, buf1); + printf(">>> html encode: len(%d)\n%s", (int) ACL_VSTRING_LEN(buf1), acl_vstring_str(buf1)); + + printf("------------------------------------------\n"); + + acl_html_decode(acl_vstring_str(buf1), buf2); + printf(">>> html decode: len(%d)\n%s", (int) ACL_VSTRING_LEN(buf2), acl_vstring_str(buf2)); + + acl_vstring_free(buf1); + acl_vstring_free(buf2); + +#ifdef WIN32 + printf("------------------------------------------\n"); + printf("enter any key to exit ...\n"); + getchar(); +#endif + return (0); +} diff --git a/samples/html_code/valgrind.sh b/samples/html_code/valgrind.sh new file mode 100644 index 000000000..59d633bd0 --- /dev/null +++ b/samples/html_code/valgrind.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +valgrind --tool=memcheck --leak-check=yes -v ./html_code diff --git a/samples/http/Makefile b/samples/http/Makefile new file mode 100644 index 000000000..ac706f1f7 --- /dev/null +++ b/samples/http/Makefile @@ -0,0 +1,12 @@ +.PHONY = all clean + +all: + @(cd url_get1; make) + @(cd url_get2; make) + @(cd url_get3; make) + @(cd header; make) +clean: + @(cd url_get1; make clean) + @(cd url_get2; make clean) + @(cd url_get3; make clean) + @(cd header; make clean) diff --git a/samples/http/Makefile.in b/samples/http/Makefile.in new file mode 100644 index 000000000..5e6fc0f2c --- /dev/null +++ b/samples/http/Makefile.in @@ -0,0 +1,104 @@ +SHELL = /bin/sh +CC = gcc + +CFLAGS = -c -g -W -Wall -Wcast-qual -Wcast-align \ +-Waggregate-return -Wmissing-prototypes \ +-Wpointer-arith -Werror -Wshadow -pedantic -O2 \ +-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO \ +-Wno-long-long +########################################################### +#Check system: +# Linux, SunOS, Solaris, BSD variants, AIX, HP-UX +SYSLIB = +CHECKSYSRES = @echo "Unknow system type!";exit 1 +UNIXNAME = $(shell uname -sm) + +ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes +endif + +# For FreeBSD +ifeq ($(findstring FreeBSD, $(UNIXNAME)), FreeBSD) + CFLAGS += -DFREEBSD -D_REENTRANT -pedantic + SYSLIB = -lpthread +endif + +# For Darwin +ifeq ($(findstring Darwin, $(UNIXNAME)), Darwin) + CFLAGS += -DMACOSX -D_REENTRANT -pedantic + SYSLIB = -lpthread +endif + +#Path for Linux +ifeq ($(findstring Linux, $(UNIXNAME)), Linux) + CFLAGS += -DLINUX2 + SYSLIB = -lcrypt -lpthread +endif + +#Path for SunOS +ifeq ($(findstring SunOS, $(UNIXNAME)), SunOS) + ifeq ($(findstring 86, $(UNIXNAME)), 86) + SYSLIB = -lsocket -lnsl -lrt + endif + ifeq ($(findstring sun4u, $(UNIXNAME)), sun4u) + SYSLIB = -lsocket -lnsl -lrt + endif + CFLAGS += -DSUNOS5 +endif + +#Path for HP-UX +ifeq ($(findstring HP-UX, $(UNIXNAME)), HP-UX) + SYSLIB = -lpthread + CFLAGS += -DHP_UX -DHPUX11 + PLAT_NAME=hp-ux +endif + +#Find system type. +ifneq ($(SYSPATH),) + CHECKSYSRES = @echo "System is $(shell uname -sm)" +endif +########################################################### + +ACL_PATH = ../../../lib_acl +ACL_LIB = $(ACL_PATH)/lib +ACL_INC = $(ACL_PATH)/include + +PRO_PATH = ../../../lib_protocol +PRO_LIB = $(PRO_PATH)/lib +PRO_INC = $(PRO_PATH)/include + +CFLAGS += -I. -I$(ACL_INC) -I$(PRO_INC) +COMPILE = $(CC) $(CFLAGS) + +EXTLIBS = +LDFLAGS = -L$(PRO_LIB) -l_protocol -L$(ACL_LIB) -l_acl $(EXTLIBS) $(SYSLIB) +LINKS = $(CC) -o $(PROG) $(OBJS) $(LDFLAGS) + +OUT_PATH = ./ +OBJ_PATH = $(OUT_PATH) + +#Project's objs +SRCS = $(wildcard *.c) +OBJS = $(patsubst %.c,$(OBJ_PATH)%.o,$(SRCS)) + +########################################################### + +.PHONY = all RM clean + +PROG = + +all: RM $(PROG) + +RM: + rm -f $(PROG) + +all: $(OBJS) + $(LINKS) + +$(OBJ_PATH)%.o: %.c *.h + $(COMPILE) -o $@ $< + +clean: + rm -f $(OBJS) $(PROG) + +rebuild: clean all diff --git a/samples/http/header/Makefile b/samples/http/header/Makefile new file mode 100644 index 000000000..cf994896c --- /dev/null +++ b/samples/http/header/Makefile @@ -0,0 +1,3 @@ +include ../Makefile.in +CFLAGS += -I../../../lib_protocol/include +PROG = header diff --git a/samples/http/header/header.txt b/samples/http/header/header.txt new file mode 100644 index 000000000..a6aeb9aec --- /dev/null +++ b/samples/http/header/header.txt @@ -0,0 +1,12 @@ +GET http://photo.test.com/inc/global.js HTTP/1.1 +Host: photo.test.com +User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; zh-CN; rv:1.8.1) Gecko/20061010 Firefox/2.0 +Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5 +Accept-Language: en-us,zh-cn;q=0.7,zh;q=0.3 +Accept-Encoding: gzip,deflate +Accept-Charset: gb2312,utf-8;q=0.7,*;q=0.7 +Keep-Alive: 300 +Proxy-Connection: keep-alive +Cookie: ASP.NET_SessionId=ey5drq45lsomio55hoydzc45 +Cache-Control: max-age=0 + diff --git a/samples/http/header/main.c b/samples/http/header/main.c new file mode 100644 index 000000000..50e291887 --- /dev/null +++ b/samples/http/header/main.c @@ -0,0 +1,267 @@ +#include "lib_acl.h" +#include "lib_protocol.h" + +static double stamp_sub(const struct timeval *from, const struct timeval *sub_by) +{ + struct timeval res; + + memcpy(&res, from, sizeof(struct timeval)); + + res.tv_usec -= sub_by->tv_usec; + if (res.tv_usec < 0) { + --res.tv_sec; + res.tv_usec += 1000000; + } + res.tv_sec -= sub_by->tv_sec; + + return (res.tv_sec * 1000.0 + res.tv_usec/1000.0); +} + +static int header_http(const char* filepath, int max) +{ + struct timeval begin, end; + double n; + ACL_VSTREAM* fp; + int i, ret; + + fp = acl_vstream_fopen(filepath, O_RDONLY, 0600, 8192); + if (fp == NULL) + { + printf("open file %s error\r\n", filepath); + return 0; + } + + gettimeofday(&begin, NULL); + for (i = 0; i < max; i++) + { + HTTP_HDR_REQ* hdr_req = http_hdr_req_new(); + + if (acl_vstream_fseek(fp, 0, SEEK_SET) < 0) + { + printf("fseek error\r\n"); + break; + } + if ((ret = http_hdr_req_get_sync(hdr_req, fp, 0)) < 0) + { + http_hdr_req_free(hdr_req); + printf("get header error: %d\r\n", ret); + break; + } + if (http_hdr_req_parse(hdr_req) < 0) + { + printf("parse error\r\n"); + http_hdr_req_free(hdr_req); + break; + } + + http_hdr_req_free(hdr_req); + + if (i % 1000 == 0) + { + char line[64]; + snprintf(line, sizeof(line), "total: %d, curr: %d", max, i); + ACL_METER_TIME(line); + } + } + + gettimeofday(&end, NULL); + n = stamp_sub(&end, &begin); + + printf("total: %d, spent: %0.2f, speed: %0.2f\r\n", + max, n, (max * 1000) /(n > 0 ? n : 1)); + + acl_vstream_close(fp); + return 0; +} + +static int header_read(const char* filepath, int max) +{ + struct timeval begin, end; + double n; + ACL_VSTREAM* fp; + char line[1024]; + int i; + + fp = acl_vstream_fopen(filepath, O_RDONLY, 0600, 8192); + if (fp == NULL) + { + printf("open file %s error\r\n", filepath); + return 0; + } + + gettimeofday(&begin, NULL); + for (i = 0; i < max; i++) + { + if (acl_vstream_fseek(fp, 0, SEEK_SET) < 0) + { + printf("fseek error\r\n"); + break; + } + while (1) + { + if (acl_vstream_gets_nonl(fp, line, sizeof(line)) == ACL_VSTREAM_EOF) + break; + } + + if (i % 1000 == 0) + { + snprintf(line, sizeof(line), "total: %d, curr: %d", max, i); + ACL_METER_TIME(line); + } + } + + gettimeofday(&end, NULL); + n = stamp_sub(&end, &begin); + + printf("total: %d, spent: %0.2f, speed: %0.2f\r\n", + max, n, (max * 1000) /(n > 0 ? n : 1)); + + acl_vstream_close(fp); + return 0; +} + +static int header_parse(const char* filepath, int max) +{ + int i; + double n; + ACL_VSTREAM* fp; + ACL_ITER iter; + struct timeval begin, end; + char line[1024]; + ACL_ARGV* tokens = acl_argv_alloc(10); + + fp = acl_vstream_fopen(filepath, O_RDONLY, 0600, 8192); + if (fp == NULL) + { + printf("open file %s error\r\n", filepath); + return 0; + } + + while (1) + { + i = acl_vstream_gets_nonl(fp, line, sizeof(line)); + if (i == 0 || i == ACL_VSTREAM_EOF) + break; + acl_argv_add(tokens, line, NULL); + } + + acl_foreach(iter, tokens) + { + printf("%s\r\n", (const char*) iter.data); + } + + printf("----------------------------------------------------\r\n"); + + gettimeofday(&begin, NULL); + +#define HDR_RES + + ACL_METER_TIME("begin run"); + for (i = 0; i < max; i++) + { +#ifdef HDR_RES + HTTP_HDR_RES* hdr; +#else + HTTP_HDR_REQ* hdr; +#endif + int j = 0; + +#ifdef HDR_RES + hdr = http_hdr_res_new(); +#else + hdr = http_hdr_req_new(); +#endif + acl_foreach(iter, tokens) + { + HTTP_HDR_ENTRY* entry = + http_hdr_entry_new((const char*) iter.data); + http_hdr_append_entry(&hdr->hdr, entry); + if (++j == 200) + break; + } + +#ifdef HDR_RES + http_hdr_res_free(hdr); +#else + http_hdr_req_free(hdr); +#endif + + if (i % 1000 == 0) + { + snprintf(line, sizeof(line), "total: %d, curr: %d", max, i); + ACL_METER_TIME(line); + } + } + + gettimeofday(&end, NULL); + n = stamp_sub(&end, &begin); + + printf("total: %d, spent: %0.2f, speed: %0.2f\r\n", + max, n, (max * 1000) /(n > 0 ? n : 1)); + acl_argv_free(tokens); + acl_vstream_fclose(fp); + + return 0; +} + +static void usage(const char* procname) +{ + printf("usage: %s -h [help] -n max -f header_file -a action [parse|read|http]\r\n", procname); +} + +int main(int argc, char* argv[]) +{ + int ch, max = 10; + char filepath[256], action[64]; + + if (0) + acl_mem_slice_init(8, 1024, 100000, + ACL_SLICE_FLAG_GC2 | + ACL_SLICE_FLAG_RTGC_OFF | + ACL_SLICE_FLAG_LP64_ALIGN); + + filepath[0] = 0; + action[0] = 0; + + while ((ch = getopt(argc, argv, "hn:f:a:")) > 0) + { + switch (ch) + { + case 'h': + usage(argv[0]); + return 0; + case 'n': + max = atoi(optarg); + if (max <= 0) + max = 10; + break; + case 'f': + snprintf(filepath, sizeof(filepath), "%s", optarg); + break; + case 'a': + snprintf(action, sizeof(action), "%s", optarg); + break; + default: + break; + } + } + + if (filepath[0] == 0) + { + usage(argv[0]); + return 0; + } + + if (strcasecmp(action, "parse") == 0) + return header_parse(filepath, max); + else if (strcasecmp(action, "read") == 0) + return header_read(filepath, max); + else if (strcasecmp(action, "http") == 0) + return header_http(filepath, max); + else + { + printf("unknown action: %s\r\n", action); + usage(argv[0]); + } + return 0; +} diff --git a/samples/http/url_get1/Makefile b/samples/http/url_get1/Makefile new file mode 100644 index 000000000..5541445f3 --- /dev/null +++ b/samples/http/url_get1/Makefile @@ -0,0 +1,3 @@ +include ../Makefile.in +CFLAGS += -I../../../lib_protocol/include +PROG = url_get1 diff --git a/samples/http/url_get1/http_get_url1.vcproj b/samples/http/url_get1/http_get_url1.vcproj new file mode 100644 index 000000000..0435abff2 --- /dev/null +++ b/samples/http/url_get1/http_get_url1.vcproj @@ -0,0 +1,234 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/http/url_get1/http_get_url1.vcxproj b/samples/http/url_get1/http_get_url1.vcxproj new file mode 100644 index 000000000..f88c8d91a --- /dev/null +++ b/samples/http/url_get1/http_get_url1.vcxproj @@ -0,0 +1,185 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + ReleaseDll + Win32 + + + Release + Win32 + + + + {74114B21-D661-4AC4-B7BC-7D79C90DD4CE} + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\..\lib_protocol\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)http_get_url1.exe + true + $(OutDir)http_get_url1.pdb + Console + MachineX86 + + + + + ..\..\..\lib_acl\include;..\..\..\lib_protocol\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)http_get_url1.exe + true + Console + true + true + MachineX86 + + + + + Disabled + ..\..\..\lib_protocol\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_DLL;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + EditAndContinue + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)http_get_url1.exe + true + $(OutDir)http_get_url1.pdb + Console + MachineX86 + + + + + ..\..\..\lib_acl\include;..\..\..\lib_protocol\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_DLL;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)http_get_url1.exe + true + Console + true + true + MachineX86 + + + + + {b40213c2-507c-4c7f-a6e1-b850c9bdc27b} + false + + + {fe724ef7-3763-4e78-bdf5-bcbc075719fd} + false + + + + + + + + + \ No newline at end of file diff --git a/samples/http/url_get1/main.c b/samples/http/url_get1/main.c new file mode 100644 index 000000000..b1a647444 --- /dev/null +++ b/samples/http/url_get1/main.c @@ -0,0 +1,224 @@ +#include "lib_acl.h" +#include "lib_protocol.h" + +static void get_url(const char *method, const char *url, + const char *proxy, const char *dump) +{ + /* 创建 HTTP 请求头 */ + HTTP_HDR_REQ *hdr_req = http_hdr_req_create(url, method, "HTTP/1.1"); + ACL_VSTREAM *stream; + ACL_VSTRING *buf = acl_vstring_alloc(256); + HTTP_HDR_RES *hdr_res; + HTTP_RES *res; + ACL_FILE *fp = NULL; + const char *ptr; + int ret; + + /* 输出 HTTP 请求头内容 */ + + http_hdr_print(&hdr_req->hdr, "---request hdr---"); + + /* 如果设定代理服务器,则连接代理服务器地址, + * 否则使用 HTTP 请求头里指定的地址 + */ + + if (*proxy) + acl_vstring_strcpy(buf, proxy); + else + acl_vstring_strcpy(buf, http_hdr_req_host(hdr_req)); + + /* 获得远程 HTTP 服务器的连接地址 */ + + ptr = acl_vstring_memchr(buf, ':'); + if (ptr == NULL) + acl_vstring_strcat(buf, ":80"); + else { + int port; + ptr++; + port = atoi(ptr); + if (port <= 0 || port >= 65535) { + printf("http server's addr(%s) invalid\n", acl_vstring_str(buf)); + acl_vstring_free(buf); + http_hdr_req_free(hdr_req); + return; + } + } + + /* 连接远程 http 服务器 */ + + stream = acl_vstream_connect(acl_vstring_str(buf) /* 服务器地址 */, + ACL_BLOCKING /* 采用阻塞方式 */, + 10 /* 连接超时时间为 10 秒 */, + 10 /* 网络 IO 操作超时时间为 10 秒 */, + 4096 /* stream 流缓冲区大小为 4096 字节 */); + if (stream == NULL) { + printf("connect addr(%s) error(%s)\n", + acl_vstring_str(buf), acl_last_serror()); + acl_vstring_free(buf); + http_hdr_req_free(hdr_req); + return; + } + + /* 构建 HTTP 请求头数据 */ + + http_hdr_build_request(hdr_req, buf); + + /* 向 HTTP 服务器发送请求 */ + + ret = acl_vstream_writen(stream, acl_vstring_str(buf), ACL_VSTRING_LEN(buf)); + if (ret == ACL_VSTREAM_EOF) { + printf("write to server error(%s)\n", acl_last_serror()); + acl_vstream_close(stream); + acl_vstring_free(buf); + http_hdr_req_free(hdr_req); + return; + } + + /* 创建一个 HTTP 响应头对象 */ + + hdr_res = http_hdr_res_new(); + + /* 读取 HTTP 服务器响应头*/ + + ret = http_hdr_res_get_sync(hdr_res, stream, 10 /* IO 超时时间为 10 秒 */); + if (ret < 0) { + printf("get http reply header error(%s)\n", acl_last_serror()); + http_hdr_res_free(hdr_res); + acl_vstream_close(stream); + acl_vstring_free(buf); + http_hdr_req_free(hdr_req); + return; + } + + if (http_hdr_res_parse(hdr_res) < 0) { + printf("parse http reply header error\n"); + http_hdr_print(&hdr_res->hdr, "--- reply http header ---"); + http_hdr_res_free(hdr_res); + acl_vstream_close(stream); + acl_vstring_free(buf); + http_hdr_req_free(hdr_req); + return; + } + + /* 如果需要转储至磁盘则需要先打开文件 */ + + if (dump != NULL) { + fp = acl_fopen(dump, "w+"); + if (fp == NULL) + printf("open file(%s) error(%s)\n", + dump, acl_last_serror()); + } + + /* 如果 HTTP 响应没有数据体则仅输出 HTTP 响应头即可 */ + + if (hdr_res->hdr.content_length == 0 + || (hdr_res->hdr.content_length == -1 + && !hdr_res->hdr.chunked + && hdr_res->reply_status > 300 + && hdr_res->reply_status < 400)) + { + if (fp) + http_hdr_fprint(ACL_FSTREAM(fp), &hdr_res->hdr, + "--- reply http header ---"); + else + http_hdr_fprint(ACL_VSTREAM_OUT, &hdr_res->hdr, + "--- reply http header ---"); + http_hdr_res_free(hdr_res); + acl_vstream_close(stream); + acl_vstring_free(buf); + http_hdr_req_free(hdr_req); + return; + } + + /* 输出 HTTP 响应头 */ + + http_hdr_print(&hdr_res->hdr, "--- reply http header ---"); + + /* 创建 HTTP 响应体对象 */ + + res = http_res_new(hdr_res); + + /* 如果有数据体则开始读取 HTTP 响应数据体部分 */ + while (1) { + http_off_t n; + char buf2[4096]; + + n = http_res_body_get_sync(res, stream, buf2, sizeof(buf2) - 1); + if (n <= 0) + break; + + if (fp) { + if (acl_fwrite(buf2, (size_t) n, 1, fp) == (size_t) EOF) { + printf("write to dump file(%s) error(%s)\n", + dump, acl_last_serror()); + break; + } + } else { + buf2[n] = 0; + printf("%s", buf2); + } + } + + if (fp) + acl_fclose(fp); + http_res_free(res); /* 释放 HTTP 响应对象, hdr_res 会在此函数内部自动被释放 */ + acl_vstream_close(stream); /* 关闭网络流 */ + acl_vstring_free(buf); /* 释放内存区 */ + http_hdr_req_free(hdr_req); /* 释放 HTTP 请求头对象 */ +} + +static void usage(const char *procname) +{ + printf("usage: %s -h[help] -t method -r url -f dump_file -X proxy_addr\n" + "example: %s -t GET -r http://www.sina.com.cn/ -f url_dump.txt\n", + procname, procname); +} + +int main(int argc, char *argv[]) +{ + int ch; + char url[256], dump[256], proxy[256], method[32]; + /* + const char *url1 = "http://127.0.0.1:80/"; + HTTP_UTIL *req = http_util_req_new(url1, "POST"); + printf(">>>host: %s\n", http_hdr_req_host(req->hdr_req)); + acl_assert(req); + return (0); + */ + + acl_init(); /* 初始化 acl 库 */ + + ACL_SAFE_STRNCPY(method, "GET", sizeof(method)); + url[0] = 0; + dump[0] = 0; + proxy[0] = 0; + while ((ch = getopt(argc, argv, "hr:t:f:X:")) > 0) { + switch (ch) { + case 'h': + usage(argv[0]); + return (0); + case 'r': + ACL_SAFE_STRNCPY(url, optarg, sizeof(url)); + break; + case 't': + ACL_SAFE_STRNCPY(method, optarg, sizeof(method)); + break; + case 'f': + ACL_SAFE_STRNCPY(dump, optarg, sizeof(dump)); + break; + case 'X': + ACL_SAFE_STRNCPY(proxy, optarg, sizeof(proxy)); + break; + default: + break; + } + } + + if (url[0] == 0) { + usage(argv[0]); + return (0); + } + + get_url(method, url, proxy, dump); + return (0); +} diff --git a/samples/http/url_get2/Makefile b/samples/http/url_get2/Makefile new file mode 100644 index 000000000..cb816a9a5 --- /dev/null +++ b/samples/http/url_get2/Makefile @@ -0,0 +1,3 @@ +include ../Makefile.in +CFLAGS += -I../../../lib_protocol/include +PROG = url_get2 diff --git a/samples/http/url_get2/get.sh b/samples/http/url_get2/get.sh new file mode 100644 index 000000000..75c46620e --- /dev/null +++ b/samples/http/url_get2/get.sh @@ -0,0 +1,2 @@ +#!/bin/sh +./url_get -t GET -r http://www.sina.com.cn -f dump.txt diff --git a/samples/http/url_get2/http_get_url2.vcproj b/samples/http/url_get2/http_get_url2.vcproj new file mode 100644 index 000000000..4d35e3bc6 --- /dev/null +++ b/samples/http/url_get2/http_get_url2.vcproj @@ -0,0 +1,234 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/http/url_get2/http_get_url2.vcxproj b/samples/http/url_get2/http_get_url2.vcxproj new file mode 100644 index 000000000..fe023a977 --- /dev/null +++ b/samples/http/url_get2/http_get_url2.vcxproj @@ -0,0 +1,185 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + ReleaseDll + Win32 + + + Release + Win32 + + + + {6604B655-BE74-4461-9E2C-FDCBD1B79A48} + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\..\lib_protocol\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)http_get_url2.exe + true + $(OutDir)http_get_url2.pdb + Console + MachineX86 + + + + + ..\..\..\lib_acl\include;..\..\..\lib_protocol\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)http_get_url2.exe + true + Console + true + true + MachineX86 + + + + + Disabled + ..\..\..\lib_protocol\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_DLL;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + EditAndContinue + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)http_get_url2.exe + true + $(OutDir)http_get_url2.pdb + Console + MachineX86 + + + + + ..\..\..\lib_acl\include;..\..\..\lib_protocol\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_DLL;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)http_get_url2.exe + true + Console + true + true + MachineX86 + + + + + {b40213c2-507c-4c7f-a6e1-b850c9bdc27b} + false + + + {fe724ef7-3763-4e78-bdf5-bcbc075719fd} + false + + + + + + + + + \ No newline at end of file diff --git a/samples/http/url_get2/main.c b/samples/http/url_get2/main.c new file mode 100644 index 000000000..4b827f24c --- /dev/null +++ b/samples/http/url_get2/main.c @@ -0,0 +1,113 @@ +#include "lib_acl.h" +#include "lib_protocol.h" + +static void get_url(const char *method, const char *url, + const char *proxy, const char *dump, int out) +{ + /* 创建 HTTP_UTIL 请求对象 */ + HTTP_UTIL *http = http_util_req_new(url, method); + int ret; + + /* 如果设定代理服务器,则连接代理服务器地址, + * 否则使用 HTTP 请求头里指定的地址 + */ + + if (proxy && *proxy) + http_util_set_req_proxy(http, proxy); + + /* 设置转储文件 */ + + if (dump && *dump) + http_util_set_dump_file(http, dump); + + /* 输出 HTTP 请求头内容 */ + + http_hdr_print(&http->hdr_req->hdr, "---request hdr---"); + + /* 连接远程 http 服务器 */ + + if (http_util_req_open(http) < 0) { + printf("open connection(%s) error\n", http->server_addr); + http_util_free(http); + return; + } + + /* 读取 HTTP 服务器响应头*/ + + ret = http_util_get_res_hdr(http); + if (ret < 0) { + printf("get reply http header error\n"); + http_util_free(http); + return; + } + + /* 输出 HTTP 响应头 */ + + http_hdr_print(&http->hdr_res->hdr, "--- reply http header ---"); + + /* 如果有数据体则开始读取 HTTP 响应数据体部分 */ + + while (1) { + char buf[4096]; + + ret = http_util_get_res_body(http, buf, sizeof(buf) - 1); + if (ret <= 0) + break; + buf[ret] = 0; + if (out) + printf("%s", buf); + } + http_util_free(http); +} + +static void usage(const char *procname) +{ + printf("usage: %s -h[help] -t method -r url -f dump_file -o[output] -X proxy_addr\n" + "example: %s -t GET -r http://www.sina.com.cn/ -f url_dump.txt\n", + procname, procname); +} + +int main(int argc, char *argv[]) +{ + int ch, out = 0; + char url[256], dump[256], proxy[256], method[32]; + + acl_init(); /* 初始化 acl 库 */ + + ACL_SAFE_STRNCPY(method, "GET", sizeof(method)); + url[0] = 0; + dump[0] = 0; + proxy[0] = 0; + while ((ch = getopt(argc, argv, "hor:t:f:X:")) > 0) { + switch (ch) { + case 'h': + usage(argv[0]); + return (0); + case 'o': + out = 1; + break; + case 'r': + ACL_SAFE_STRNCPY(url, optarg, sizeof(url)); + break; + case 't': + ACL_SAFE_STRNCPY(method, optarg, sizeof(method)); + break; + case 'f': + ACL_SAFE_STRNCPY(dump, optarg, sizeof(dump)); + break; + case 'X': + ACL_SAFE_STRNCPY(proxy, optarg, sizeof(proxy)); + break; + default: + break; + } + } + + if (url[0] == 0) { + usage(argv[0]); + return (0); + } + + get_url(method, url, proxy, dump, out); + return (0); +} diff --git a/samples/http/url_get3/Makefile b/samples/http/url_get3/Makefile new file mode 100644 index 000000000..2a8bf0c28 --- /dev/null +++ b/samples/http/url_get3/Makefile @@ -0,0 +1,3 @@ +include ../Makefile.in +CFLAGS += -I../../../lib_protocol/include +PROG = url_get3 diff --git a/samples/http/url_get3/get.sh b/samples/http/url_get3/get.sh new file mode 100644 index 000000000..9c292b632 --- /dev/null +++ b/samples/http/url_get3/get.sh @@ -0,0 +1,2 @@ +#!/bin/sh +./url_get -r http://www.sina.com.cn -f dump.txt diff --git a/samples/http/url_get3/http_get_url3.vcproj b/samples/http/url_get3/http_get_url3.vcproj new file mode 100644 index 000000000..66668b84a --- /dev/null +++ b/samples/http/url_get3/http_get_url3.vcproj @@ -0,0 +1,234 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/http/url_get3/http_get_url3.vcxproj b/samples/http/url_get3/http_get_url3.vcxproj new file mode 100644 index 000000000..82e19cb30 --- /dev/null +++ b/samples/http/url_get3/http_get_url3.vcxproj @@ -0,0 +1,185 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + ReleaseDll + Win32 + + + Release + Win32 + + + + {2ADD53F3-3048-4D7B-8443-F0982FB17D3F} + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\..\lib_protocol\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)http_get_url3.exe + true + $(OutDir)http_get_url3.pdb + Console + MachineX86 + + + + + ..\..\..\lib_acl\include;..\..\..\lib_protocol\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)http_get_url3.exe + true + Console + true + true + MachineX86 + + + + + Disabled + ..\..\..\lib_protocol\include;..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_DLL;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + EditAndContinue + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)http_get_url3.exe + true + $(OutDir)http_get_url3.pdb + Console + MachineX86 + + + + + ..\..\..\lib_acl\include;..\..\..\lib_protocol\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_DLL;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)http_get_url3.exe + true + Console + true + true + MachineX86 + + + + + {b40213c2-507c-4c7f-a6e1-b850c9bdc27b} + false + + + {fe724ef7-3763-4e78-bdf5-bcbc075719fd} + false + + + + + + + + + \ No newline at end of file diff --git a/samples/http/url_get3/main.c b/samples/http/url_get3/main.c new file mode 100644 index 000000000..6b592e11a --- /dev/null +++ b/samples/http/url_get3/main.c @@ -0,0 +1,53 @@ +#include "lib_acl.h" +#include "lib_protocol.h" + +static void get_url(const char *url, const char *dump) +{ + ACL_METER_TIME("---begin----"); + if (dump && *dump) + http_util_dump_url(url, dump); + else + http_util_dump_url_to_stream(url, ACL_VSTREAM_OUT); + ACL_METER_TIME("----end----"); +} + +static void usage(const char *procname) +{ + printf("usage: %s -h[help] -r url -f dump_file\n" + "example: %s -r http://www.sina.com.cn/ -f url_dump.txt\n", + procname, procname); +} + +int main(int argc, char *argv[]) +{ + int ch; + char url[256], dump[256]; + + acl_init(); /* 初始化 acl 库 */ + + url[0] = 0; + dump[0] = 0; + while ((ch = getopt(argc, argv, "hr:t:f:X:")) > 0) { + switch (ch) { + case 'h': + usage(argv[0]); + return (0); + case 'r': + ACL_SAFE_STRNCPY(url, optarg, sizeof(url)); + break; + case 'f': + ACL_SAFE_STRNCPY(dump, optarg, sizeof(dump)); + break; + default: + break; + } + } + + if (url[0] == 0) { + usage(argv[0]); + return (0); + } + + get_url(url, dump); + return (0); +} diff --git a/samples/http_aio/ReadMe.txt b/samples/http_aio/ReadMe.txt new file mode 100644 index 000000000..99b46a554 --- /dev/null +++ b/samples/http_aio/ReadMe.txt @@ -0,0 +1,31 @@ +======================================================================== + 控制台应用程序 : http_aio 项目概况 +======================================================================== + +应用程序向导已为您创建了这个 http_aio 应用程序。 +此文件包含组成 http_aio 应用程序 +的每个文件的内容摘要。 + + +http_aio.vcproj + 这是用应用程序向导生成的 VC++ 项目的主项目文件。 + 它包含有关生成此文件的 Visual C++ 版本的信息,以及 + 有关用应用程序向导选择的 + 平台、配置和项目功能的信息。 + +http_aio.cpp + 这是主应用程序源文件。 + +///////////////////////////////////////////////////////////////////////////// +其他标准文件: + +StdAfx.h、StdAfx.cpp + 这些文件用于生成名为 http_aio.pch + 的预编译头(PCH)文件以及名为 StdAfx.obj 的预编译类型文件。 + +///////////////////////////////////////////////////////////////////////////// +其他注释: + +应用程序向导使用 "TODO:" 注释指示应添加或自定义的源代码部分。 + +///////////////////////////////////////////////////////////////////////////// diff --git a/samples/http_aio/http_aio.cpp b/samples/http_aio/http_aio.cpp new file mode 100644 index 000000000..76ba0ea93 --- /dev/null +++ b/samples/http_aio/http_aio.cpp @@ -0,0 +1,103 @@ +// http_aio.cpp : 定义控制台应用程序的入口点。 +// + +#include "stdafx.h" +#include "lib_acl.h" +#include "lib_protocol.h" +#include + +typedef struct { + ACL_ASTREAM *stream; + HTTP_HDR_RES *hdr_res; + HTTP_RES *http_res; +} CTX; + +int On_httphdr_notify_cb(int status, void *arg); + +static int On_close_cb(ACL_ASTREAM *stream, void *context) +{ + printf("%s(%d)\n", __FUNCTION__, __LINE__); + return (0); +} + +static int On_timeout_cb(ACL_ASTREAM *stream, void *context) +{ + printf("%s(%d)\n", __FUNCTION__, __LINE__); + return (0); +} + +static int On_connect_cb(ACL_ASTREAM *stream, void *context) +{ + const char *request = "GET / HTTP/1.1\r\n" + "HOST: www.sina.com.cn\r\n" + "\r\n"; + CTX *ctx = (CTX*) context; + + printf("%s(%d)\n", __FUNCTION__, __LINE__); + acl_aio_writen(stream, request, (int) strlen(request)); + ctx->hdr_res = http_hdr_res_new(); + http_hdr_res_get_async(ctx->hdr_res, stream, On_httphdr_notify_cb, ctx, 0); + return (0); +} + +static int read_respond_body_ready(int status, char *data, int dlen, void *arg) +{ + static ACL_VSTRING *_buf; + + if (_buf == NULL) + _buf = acl_vstring_alloc(256); + acl_vstring_memcpy(_buf, data, dlen); + ACL_VSTRING_TERMINATE(_buf); + //printf(">>%s", acl_vstring_str(_buf)); + return (0); +} + +int On_httphdr_notify_cb(int status, void *arg) +{ + CTX *ctx = (CTX*) arg; + ACL_ASTREAM *stream = ctx->stream; + + http_hdr_print(&ctx->hdr_res->hdr, "---respond---"); + ctx->http_res = http_res_new(ctx->hdr_res); + http_res_body_get_async(ctx->http_res, + ctx->stream, + read_respond_body_ready, + ctx, + 0); + //acl_aio_iocp_close(stream); + return (0); +} + +static int On_write_cb(ACL_ASTREAM *stream, void *context) +{ + CTX *ctx = (CTX*) context; + //ctx->hdr_res = http_hdr_res_new(); + printf("%s(%d)\n", __FUNCTION__, __LINE__); +// http_hdr_res_get_async(ctx->hdr_res, stream, On_httphdr_notify_cb, ctx, 0); + return (0); +} + +int _tmain(int argc, _TCHAR* argv[]) +{ + ACL_AIO *aio = acl_aio_create(ACL_EVENT_SELECT); + ACL_ASTREAM *stream; + const char *addr = "218.30.108.184:80"; + CTX *ctx = (CTX*) acl_mycalloc(1, sizeof(CTX)); + + acl_init(); + stream = acl_aio_connect(aio, addr, 0); + assert(stream); + ctx->stream = stream; + acl_aio_ctl(stream, + ACL_AIO_CTL_CONNECT_HOOK_ADD, On_connect_cb, ctx, + ACL_AIO_CTL_CLOSE_HOOK_ADD, On_close_cb, ctx, + ACL_AIO_CTL_TIMEO_HOOK_ADD, On_timeout_cb, ctx, + ACL_AIO_CTL_WRITE_HOOK_ADD, On_write_cb, ctx, + ACL_AIO_CTL_END); + while (1) { + acl_aio_loop(aio); + } + + return 0; +} + diff --git a/samples/http_aio/http_aio.vcproj b/samples/http_aio/http_aio.vcproj new file mode 100644 index 000000000..731067fcd --- /dev/null +++ b/samples/http_aio/http_aio.vcproj @@ -0,0 +1,267 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/http_aio/http_aio.vcxproj b/samples/http_aio/http_aio.vcxproj new file mode 100644 index 000000000..c67e2f10d --- /dev/null +++ b/samples/http_aio/http_aio.vcxproj @@ -0,0 +1,193 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + ReleaseDll + Win32 + + + Release + Win32 + + + + {0ED6281F-980A-47F7-B30B-0425EEB4C2A9} + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\lib_acl\include;..\..\lib_protocol\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Use + Level3 + EditAndContinue + + + ws2_32.lib;wsock32.lib;%(AdditionalDependencies) + $(OutDir)http_aio.exe + true + $(OutDir)http_aio.pdb + Console + MachineX86 + + + + + ..\..\lib_acl\include;..\..\lib_protocol\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + Use + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;%(AdditionalDependencies) + $(OutDir)http_aio.exe + true + Console + true + true + MachineX86 + + + + + Disabled + ..\..\lib_acl\include;..\..\lib_protocol\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_DLL;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Use + Level3 + EditAndContinue + + + ws2_32.lib;wsock32.lib;%(AdditionalDependencies) + $(OutDir)http_aio.exe + true + $(OutDir)http_aio.pdb + Console + MachineX86 + + + + + ..\..\lib_acl\include;..\..\lib_protocol\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_DLL;%(PreprocessorDefinitions) + MultiThreadedDLL + Use + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;%(AdditionalDependencies) + $(OutDir)http_aio.exe + true + Console + true + true + MachineX86 + + + + + + Create + Create + Create + Create + + + + + {b40213c2-507c-4c7f-a6e1-b850c9bdc27b} + false + + + {fe724ef7-3763-4e78-bdf5-bcbc075719fd} + false + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/http_aio/http_aio.vcxproj.filters b/samples/http_aio/http_aio.vcxproj.filters new file mode 100644 index 000000000..025f3c599 --- /dev/null +++ b/samples/http_aio/http_aio.vcxproj.filters @@ -0,0 +1,33 @@ +锘 + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx + + + + + 婧愭枃浠 + + + 婧愭枃浠 + + + + + 澶存枃浠 + + + + + + \ No newline at end of file diff --git a/samples/http_aio/stdafx.cpp b/samples/http_aio/stdafx.cpp new file mode 100644 index 000000000..4c5eec0a0 --- /dev/null +++ b/samples/http_aio/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// http_aio.pch 将成为预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + +// TODO: 在 STDAFX.H 中 +//引用任何所需的附加头文件,而不是在此文件中引用 diff --git a/samples/http_aio/stdafx.h b/samples/http_aio/stdafx.h new file mode 100644 index 000000000..ff452917c --- /dev/null +++ b/samples/http_aio/stdafx.h @@ -0,0 +1,11 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是常用但不常更改的项目特定的包含文件 +// + +#pragma once + + +#include +#include + +// TODO: 在此处引用程序要求的附加头文件 diff --git a/samples/http_client/HttpClient.cpp b/samples/http_client/HttpClient.cpp new file mode 100644 index 000000000..3be4e589d --- /dev/null +++ b/samples/http_client/HttpClient.cpp @@ -0,0 +1,437 @@ +#include "StdAfx.h" +#include "lib_acl.h" +#include "lib_protocol.h" +#include ".\httpclient.h" + +void CHttpReport::Init(void) +{ + m_nBuf = 0; + m_pBuf = NULL; +} + +CHttpReport::CHttpReport(int type) +{ + Init(); + m_type = type; +} + +CHttpReport::CHttpReport(int type, double nTime) +{ + Init(); + m_type = type; + m_timeRes = nTime; +} + +CHttpReport::CHttpReport(int type, const char *data, int len) +{ + Init(); + m_pBuf = (char*) acl_mymalloc((size_t) len + 1); + memcpy(m_pBuf, data, (size_t) len); + m_pBuf[len] = 0; + m_nBuf = len; + m_type = type; +} + +CHttpReport::CHttpReport(int type, int len, int dummy) +{ + Init(); + m_type = type; + m_nContentLength = len; +} + +CHttpReport::CHttpReport(int type, int len, double nTime, int dummy) +{ + Init(); + m_type = type; + m_nDownLen = len; + m_timeRes = nTime; +} + +CHttpReport::~CHttpReport() +{ + if (m_pBuf) + acl_myfree(m_pBuf); +} + +CHttpClient::CHttpClient(void) +: m_sReqUrl(_T("")) +, m_bLocalSave(FALSE) +, m_sLocalFile(_T("")) +, m_nMsg(0) +, m_bDisplayReqHdr(TRUE) +, m_bDisplayResHdr(TRUE) +, m_bDisplayResBody(FALSE) +, m_bHttp11(TRUE) +, m_bZip(FALSE) +, m_bKeepAlive(FALSE) +, m_sHttpHdrAppend(_T("")) +, m_bUseAddr(FALSE) +, m_sServerAddr(_T("")) +, m_bForwardAuto(FALSE) +, m_nMaxTry(10) +{ +} + +CHttpClient::~CHttpClient(void) +{ +} + +void CHttpClient::OnDataCallback(HWND hWnd, int nMsg) +{ + m_hWnd = hWnd; + m_nMsg = nMsg; +} + +void CHttpClient::ReportMsg(CHttpReport *pReport, int nMsg) +{ + ::PostMessage(m_hWnd, WM_USER_DISPLAY, (WPARAM) pReport, 0); +} + +void CHttpClient::ReportComplete(void) +{ + if (m_nMsg <= 0) + return; + + CHttpReport *pReport = new CHttpReport(TYPE_COMPLETE); + ReportMsg(pReport, m_nMsg); +} + +void CHttpClient::ReportReqHdr(const char *data, int len) +{ + if (m_nMsg <= 0) + return; + if (!m_bDisplayReqHdr) + return; + CHttpReport *pReport = new CHttpReport(TYPE_HDR_REQ, data, len); + ReportMsg(pReport, m_nMsg); +} + +void CHttpClient::ReportResHdr(const char *data, int len) +{ + if (m_nMsg <= 0) + return; + if (!m_bDisplayResHdr) + return; + CHttpReport *pReport = new CHttpReport(TYPE_HDR_RES, data, len); + ReportMsg(pReport, m_nMsg); +} + + +void CHttpClient::ReportResBody(const char *data, int len) +{ + if (m_nMsg <= 0) + return; + if (!m_bDisplayResBody) + return; + CHttpReport *pReport = new CHttpReport(TYPE_BODY_RES, data, len); + ReportMsg(pReport, m_nMsg); +} + +void CHttpClient::ReportResContentLength(int len) +{ + if (m_nMsg <= 0) + return; + CHttpReport *pReport = new CHttpReport(TYPE_TOTAL_LEN, len, 0); + ReportMsg(pReport, m_nMsg); +} + +void CHttpClient::ReportResDownLength(double nTime, int len) +{ + if (m_nMsg <= 0) + return; + CHttpReport *pReport = new CHttpReport(TYPE_DOWN_LEN, len, nTime, 0); + ReportMsg(pReport, m_nMsg); +} + +void CHttpClient::ReportErrorDns(const char *msg) +{ + if (m_nMsg <= 0) + return; + CHttpReport *pReport = new CHttpReport(TYPE_ERROR_DNS, msg, (int) strlen(msg)); + ReportMsg(pReport, m_nMsg); +} + +void CHttpClient::ReportErrConnect(const char *msg) +{ + if (m_nMsg <= 0) + return; + CHttpReport *pReport = new CHttpReport(TYPE_ERROR_CONNECT, msg, (int) strlen(msg)); + ReportMsg(pReport, m_nMsg); +} + +void CHttpClient::ReportErrorWrite(const char *msg) +{ + if (m_nMsg <= 0) + return; + CHttpReport *pReport = new CHttpReport(TYPE_ERROR_WRITE, msg, (int) strlen(msg)); + ReportMsg(pReport, m_nMsg); +} + +void CHttpClient::ReportErrorRead(const char *msg) +{ + if (m_nMsg <= 0) + return; + CHttpReport *pReport = new CHttpReport(TYPE_ERROR_READ, msg, (int) strlen(msg)); + ReportMsg(pReport, m_nMsg); +} + +void CHttpClient::ReportTime(double nTime) +{ + if (m_nMsg <= 0) + return; + CHttpReport *pReport = new CHttpReport(TYPE_TIME_RES, nTime); + ReportMsg(pReport, m_nMsg); +} + +int CHttpClient::GetUrl(const CString& url) +{ + m_sReqUrl = url; + acl_pthread_t tid; + + acl_pthread_create(&tid, NULL, DoRequestThread, this); + return 0; +} + +void CHttpClient::SaveAs(const CString& fileName) +{ + m_sLocalFile = fileName; + m_bLocalSave = TRUE; +} + +static double stamp_sub(const struct timeval *from, const struct timeval *sub_by) +{ + struct timeval res; + + memcpy(&res, from, sizeof(struct timeval)); + + res.tv_usec -= sub_by->tv_usec; + if (res.tv_usec < 0) { + --res.tv_sec; + res.tv_usec += 1000000; + } + res.tv_sec -= sub_by->tv_sec; + + return (res.tv_sec * 1000.0 + res.tv_usec/1000.0); +} + +void *CHttpClient::DoRequestThread(void* arg) +{ + CHttpClient *phClient = (CHttpClient*) arg; + HTTP_HDR_REQ *hdr_req = NULL; + HTTP_HDR_RES *hdr_res = NULL; + HTTP_RES *http_res = NULL; + ACL_VSTRING *buf = acl_vstring_alloc(256); + ACL_VSTREAM *server = NULL; + const char *pHost = NULL; + ACL_VSTREAM *fp = NULL; + int ret; + UINT nForward = 0; + time_t begin = 0; + struct timeval begin_tv, end_tv; + double time_cost = 0; + +#undef RETURN +#define RETURN(_x_) do \ +{ \ + if (hdr_req) \ + http_hdr_req_free(hdr_req); \ + if (buf) \ + acl_vstring_free(buf); \ + if (hdr_res) \ + http_hdr_res_free(hdr_res); \ + if (http_res) { \ + http_res->hdr_res = NULL; \ + http_res_free(http_res); \ + } \ + if (server) \ + acl_vstream_close(server); \ + if (fp) \ + acl_vstream_close(fp); \ + gettimeofday(&end_tv, NULL); \ + time_cost = stamp_sub(&end_tv, &begin_tv); \ + if (time_cost >= 0) \ + phClient->ReportTime(time_cost); \ + phClient->ReportComplete(); \ + return (_x_); \ +} while(0) + + const char *pUrl = phClient->m_sReqUrl.GetString(); + hdr_req = http_hdr_req_create(pUrl, phClient->m_bPostMethod ? "POST" : "GET", + phClient->m_bHttp11 ? "HTTP/1.1" : "HTTP/1.0"); + ASSERT(hdr_req); + + if (phClient->m_bZip) + http_hdr_put_str(&hdr_req->hdr, "Accept-Encoding", "gzip, deflate"); + if (phClient->m_bKeepAlive) + http_hdr_entry_replace(&hdr_req->hdr, "Connection", "Keep-Alive", 1); + if (phClient->m_bPostMethod) + http_hdr_put_int(&hdr_req->hdr, "Content-Length", + (int) phClient->m_sHttpBody.GetLength()); + if (!phClient->m_sAccept.IsEmpty()) + http_hdr_put_str(&hdr_req->hdr, "Accept", phClient->m_sAccept.GetString()); + if (!phClient->m_sCtype.IsEmpty()) + http_hdr_put_str(&hdr_req->hdr, "Content-Type", phClient->m_sCtype.GetString()); + + if (phClient->m_sHttpHdrAppend.GetLength() > 0) { + ACL_ARGV *argv; + HTTP_HDR_ENTRY *entry; + int i; + + argv = acl_argv_split(phClient->m_sHttpHdrAppend.GetString(), "\r\n"); + for (i = 0; i < argv->argc; i++) { + entry = http_hdr_entry_new(argv->argv[i]); + if (entry == NULL) + continue; + http_hdr_append_entry(&hdr_req->hdr, entry); + } + acl_argv_free(argv); + } + +FORWARD: + + http_hdr_build_request(hdr_req, buf); + pHost = http_hdr_req_host(hdr_req); + ASSERT(pHost); + + phClient->ReportReqHdr(acl_vstring_str(buf), (int) ACL_VSTRING_LEN(buf)); + + CString serverAddr; + + if (phClient->m_bUseAddr) + serverAddr.Format("%s", phClient->m_sServerAddr); + if (serverAddr.GetLength() == 0) + serverAddr.Format("%s", pHost); + if (strchr(serverAddr.GetString(), ':') == NULL) + serverAddr.AppendFormat(":80"); + + time(&begin); + gettimeofday(&begin_tv, NULL); + server = acl_vstream_connect(serverAddr.GetString(), + ACL_BLOCKING, 10, 10, 4096); + if (server == NULL) { + CString msg; + + msg.Format("Connect server(%s) error", serverAddr.GetString()); + phClient->ReportErrConnect(msg.GetString()); + RETURN (NULL); + } + + if (phClient->m_bLocalSave && fp == NULL) { + fp = acl_vstream_fopen(phClient->m_sLocalFile.GetString(), + O_WRONLY | O_CREAT | O_TRUNC, 0600, 4096); + if (fp == NULL) { + acl_msg_error("%s(%d): can't create file(%s)", + __FILE__, __LINE__, phClient->m_sLocalFile.GetString()); + RETURN (NULL); + } + } + + ret = acl_vstream_writen(server, acl_vstring_str(buf), ACL_VSTRING_LEN(buf)); + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): write error", __FILE__, __LINE__); + RETURN (NULL); + } + + if (phClient->m_bPostMethod && !phClient->m_sHttpBody.IsEmpty()) + { + if (acl_vstream_writen(server, phClient->m_sHttpBody.GetString(), + phClient->m_sHttpBody.GetLength()) == ACL_VSTREAM_EOF) + { + acl_msg_error("%s(%d): write body error", __FILE__, __LINE__); + RETURN (NULL); + } + } + + hdr_res = http_hdr_res_new(); + if (http_hdr_res_get_sync(hdr_res, server, 10) < 0) { + acl_msg_error("%s(%d): get res hdr error", __FILE__, __FILE__, __LINE__); + RETURN (NULL); + } + + if (http_hdr_res_parse(hdr_res) < 0) { + acl_msg_error("%s(%d): parse hdr_res error", __FILE__, __LINE__); + RETURN (NULL); + } + + http_hdr_build(&hdr_res->hdr, buf); + phClient->ReportResHdr(acl_vstring_str(buf), (int) ACL_VSTRING_LEN(buf)); + phClient->ReportResContentLength((int) hdr_res->hdr.content_length); + + if (hdr_res->reply_status > 300 && hdr_res->reply_status < 400) { + const char* pLocation; + HTTP_HDR_REQ *hdr_req_tmp; + + if (!phClient->m_bForwardAuto) + RETURN (NULL); + + if (nForward++ >= phClient->m_nMaxTry) { + acl_msg_error("%s(%d): too many redirect, nForward(%d)", + __FILE__, __LINE__, nForward); + RETURN (NULL); + } + + pLocation = http_hdr_entry_value(&hdr_res->hdr, "Location"); + if (pLocation == NULL || *pLocation == 0) { + acl_msg_error("%s(%d): 302 reply with no Location", __FILE__, __LINE__); + RETURN (NULL); + } + + hdr_req_tmp = http_hdr_req_rewrite(hdr_req, pLocation); + if (hdr_req_tmp == NULL) + RETURN (NULL); + http_hdr_req_free(hdr_req); + http_hdr_res_free(hdr_res); + hdr_req = hdr_req_tmp; + goto FORWARD; + } + + http_res = http_res_new(hdr_res); + while (1) { + char tmp_buf[4096]; + + ret = (int) http_res_body_get_sync2(http_res, server, + tmp_buf, sizeof(tmp_buf) - 1); + if (ret <= 0) + break; + + phClient->ReportResBody(tmp_buf, ret); + phClient->ReportResDownLength((int)(time(NULL) - begin), ret); + + if (fp != NULL && acl_vstream_writen(fp, tmp_buf, ret) == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): write to file error", __FILE__, __LINE__); + break; + } + } + RETURN (NULL); +} + +void CHttpClient::DisplayReqHdr(BOOL enable) +{ + m_bDisplayReqHdr = enable; +} + +void CHttpClient::DisplayResHdr(BOOL enable) +{ + m_bDisplayResHdr = enable; +} + +void CHttpClient::DisplayResBody(BOOL enable) +{ + m_bDisplayResBody = enable; +} + +void CHttpClient::EnableHttp11(BOOL enable) +{ + m_bHttp11 = enable; +} + +void CHttpClient::EnableZip(BOOL enable) +{ + m_bZip = enable; +} + +void CHttpClient::EnableKeepAlive(BOOL enable) +{ + m_bKeepAlive = enable; +} + diff --git a/samples/http_client/HttpClient.h b/samples/http_client/HttpClient.h new file mode 100644 index 000000000..1d2d2200e --- /dev/null +++ b/samples/http_client/HttpClient.h @@ -0,0 +1,87 @@ +#pragma once +#include "lib_protocol.h" + +class CHttpReport { +public: + CHttpReport(int type); + CHttpReport(int type, double nTime); + CHttpReport(int type, const char *data, int len); + CHttpReport(int type, int len, int dummy); + CHttpReport(int type, int len, double nTime, int dummy); + ~CHttpReport(); + + int m_type; +#define TYPE_COMPLETE 0 +#define TYPE_HDR_REQ 1 +#define TYPE_HDR_RES 2 +#define TYPE_BODY_RES 3 +#define TYPE_TIME_RES 4 +#define TYPE_DOWN_LEN 5 +#define TYPE_TOTAL_LEN 6 +#define TYPE_ERROR_DNS 7 +#define TYPE_ERROR_CONNECT 8 +#define TYPE_ERROR_WRITE 9 +#define TYPE_ERROR_READ 10 + + double m_timeRes; + int m_nContentLength; + char *m_pBuf; + int m_nBuf; + int m_nDownLen; + +private: + void Init(void); +}; + +class CHttpClient +{ +public: + CHttpClient(void); + ~CHttpClient(void); + void OnDataCallback(HWND hWnd, int nMsg); +private: + HWND m_hWnd; + int m_nMsg; + CString m_sReqUrl; + BOOL m_bLocalSave; + CString m_sLocalFile; +public: + int GetUrl(const CString& url); + void SaveAs(const CString& fileName); +private: + void ReportComplete(void); + void ReportReqHdr(const char *data, int len); + void ReportResHdr(const char *data, int len); + void ReportResBody(const char *data, int len); + void ReportResContentLength(int len); + void ReportResDownLength(double nTime, int len); + void ReportErrorDns(const char *msg); + void ReportErrConnect(const char *msg); + void ReportErrorWrite(const char *msg); + void ReportErrorRead(const char *msg); + void ReportTime(double nTime); + void ReportMsg(CHttpReport *, int nMsg); + static void *DoRequestThread(void* arg); + BOOL m_bDisplayReqHdr; + BOOL m_bDisplayResHdr; + BOOL m_bDisplayResBody; + BOOL m_bHttp11; + BOOL m_bZip; + BOOL m_bKeepAlive; +public: + void DisplayReqHdr(BOOL enable); + void DisplayResHdr(BOOL enable); + void DisplayResBody(BOOL enable); + void EnableHttp11(BOOL enable); + void EnableZip(BOOL enable); + void EnableKeepAlive(BOOL enable); + CString m_sHttpHdrAppend; + CString m_sHttpBody; + CString m_sAccept; + CString m_sCtype; + BOOL m_bUseAddr; + CString m_sServerAddr; + BOOL m_bForwardAuto; + UINT m_nMaxTry; + BOOL m_bPostMethod; +}; diff --git a/samples/http_client/HttpOption.cpp b/samples/http_client/HttpOption.cpp new file mode 100644 index 000000000..b3aaf5438 --- /dev/null +++ b/samples/http_client/HttpOption.cpp @@ -0,0 +1,112 @@ +// HttpOption.cpp : 实现文件 +// + +#include "stdafx.h" +#include "http_client.h" +#include "HttpOption.h" +#include ".\httpoption.h" + + +// CHttpOption 对话框 + +IMPLEMENT_DYNAMIC(CHttpOption, CDialog) +CHttpOption::CHttpOption(CWnd* pParent /*=NULL*/) + : CDialog(CHttpOption::IDD, pParent) + , m_bHttp11(FALSE) + , m_bZip(FALSE) + , m_bKeepAlive(FALSE) + , m_sHttpHdrAppend(_T("")) + , m_sHttpBody(_T("")) + , m_sServerAddr(_T("")) + , m_bUseAddr(FALSE) + , m_bForwardAuto(FALSE) + , m_nMaxTry(10) +{ +} + +CHttpOption::~CHttpOption() +{ +} + +void CHttpOption::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + + DDX_Check(pDX, IDC_CHECK_PROTO, m_bHttp11); + DDX_Check(pDX, IDC_CHECK_ZIP, m_bZip); + DDX_Check(pDX, IDC_CHECK_KEEP_ALIVE, m_bKeepAlive); + DDX_Text(pDX, IDC_EDIT_HTTP_HDR, m_sHttpHdrAppend); + DDX_Text(pDX, IDC_EDIT_HTTP_BODY, m_sHttpBody); + DDX_Text(pDX, IDC_EDIT_ADDR, m_sServerAddr); + DDX_Check(pDX, IDC_CHECK_USE_ADDR, m_bUseAddr); + DDX_Check(pDX, IDC_CHECK_FORWARD, m_bForwardAuto); + DDX_Text(pDX, IDC_EDIT_MAX_TRY, m_nMaxTry); + DDX_Text(pDX, IDC_CONTENT_TYPE, m_sCType); + DDX_Text(pDX, IDC_ACCEPT, m_sAccept); + DDX_Check(pDX, IDC_POST_METHOD, m_bPostMethod); +} + + +BEGIN_MESSAGE_MAP(CHttpOption, CDialog) + ON_BN_CLICKED(IDC_CHECK_PROTO, OnBnClickedCheckProto) + ON_BN_CLICKED(IDC_CHECK_ZIP, OnBnClickedCheckZip) + ON_BN_CLICKED(IDC_CHECK_KEEP_ALIVE, OnBnClickedCheckKeepAlive) + ON_BN_CLICKED(IDC_POST_METHOD, OnBnClickedPostMethod) + ON_BN_CLICKED(IDOK, OnBnClickedOk) +END_MESSAGE_MAP() + + +// CHttpOption 消息处理程序 + +void CHttpOption::OnBnClickedCheckProto() +{ + // TODO: 在此添加控件通知处理程序代码 + if (IsDlgButtonChecked(IDC_CHECK_PROTO)) + m_bHttp11 = TRUE; + else + m_bHttp11 = FALSE; +} + +void CHttpOption::OnBnClickedCheckZip() +{ + // TODO: 在此添加控件通知处理程序代码 + if (IsDlgButtonChecked(IDC_CHECK_ZIP)) + m_bZip = TRUE; + else + m_bZip = FALSE; +} + +void CHttpOption::OnBnClickedCheckKeepAlive() +{ + // TODO: 在此添加控件通知处理程序代码 + if (IsDlgButtonChecked(IDC_CHECK_KEEP_ALIVE)) + m_bKeepAlive = TRUE; + else + m_bKeepAlive = FALSE; +} + +BOOL CHttpOption::OnInitDialog() +{ + CDialog::OnInitDialog(); + + // TODO: 在此添加额外的初始化 + + return TRUE; // return TRUE unless you set the focus to a control + // 异常: OCX 属性页应返回 FALSE +} + + +void CHttpOption::OnBnClickedPostMethod() +{ + // TODO: 在此添加控件通知处理程序代码 + if (IsDlgButtonChecked(IDC_POST_METHOD)) + m_bPostMethod = TRUE; + else + m_bPostMethod = FALSE; +} + +void CHttpOption::OnBnClickedOk() +{ + // TODO: 在此添加控件通知处理程序代码 + OnOK(); +} diff --git a/samples/http_client/HttpOption.h b/samples/http_client/HttpOption.h new file mode 100644 index 000000000..9d8297fce --- /dev/null +++ b/samples/http_client/HttpOption.h @@ -0,0 +1,41 @@ +#pragma once +#include "afxwin.h" + + +// CHttpOption 对话框 + +class CHttpOption : public CDialog +{ + DECLARE_DYNAMIC(CHttpOption) + +public: + CHttpOption(CWnd* pParent = NULL); // 标准构造函数 + virtual ~CHttpOption(); + +// 对话框数据 + enum { IDD = IDD_DIALOG_OPTION }; + +protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 + + DECLARE_MESSAGE_MAP() +public: + afx_msg void OnBnClickedCheckProto(); + afx_msg void OnBnClickedCheckZip(); + afx_msg void OnBnClickedCheckKeepAlive(); + BOOL m_bHttp11; + BOOL m_bZip; + BOOL m_bKeepAlive; + BOOL m_bPostMethod; + virtual BOOL OnInitDialog(); + CString m_sHttpHdrAppend; + CString m_sHttpBody; + CString m_sServerAddr; + CString m_sCType; + CString m_sAccept; + BOOL m_bUseAddr; + BOOL m_bForwardAuto; + UINT m_nMaxTry; + afx_msg void OnBnClickedPostMethod(); + afx_msg void OnBnClickedOk(); +}; diff --git a/samples/http_client/MeterBar.cpp b/samples/http_client/MeterBar.cpp new file mode 100644 index 000000000..92bb70c1b --- /dev/null +++ b/samples/http_client/MeterBar.cpp @@ -0,0 +1,83 @@ +// MeterBar.cpp : 实现文件 +// + +#include "stdafx.h" +#include "http_client.h" +#include "MeterBar.h" +#include ".\meterbar.h" + + +// CMeterBar + +IMPLEMENT_DYNAMIC(CMeterBar, CStatusBarCtrl) +CMeterBar::CMeterBar() +: m_pWidths(NULL) +{ +} + +CMeterBar::~CMeterBar() +{ + delete m_pWidths; +} + + +BEGIN_MESSAGE_MAP(CMeterBar, CStatusBarCtrl) + ON_WM_CREATE() + ON_WM_SIZE() +END_MESSAGE_MAP() + +BOOL CMeterBar::SetParts(int nParts, int* pWidths) +{ + m_nParts = nParts; + m_pWidths = new int[nParts]; + int i; + for (i = 0; i < nParts; i++) + { + m_pWidths[i] = pWidths[i]; + } + return (TRUE); +} + +// CMeterBar 消息处理程序 + + +int CMeterBar::OnCreate(LPCREATESTRUCT lpCreateStruct) +{ + if (CStatusBarCtrl::OnCreate(lpCreateStruct) == -1) + return -1; + + ASSERT(m_pWidths); + CStatusBarCtrl::SetParts(m_nParts, m_pWidths); + //int tmp; + //int n = GetParts(0, &tmp); + + // TODO: 在此添加您专用的创建代码 + //m_meter.Create(WS_CHILD | WS_VISIBLE, CRect(0, 0, 0, 0), this, 101); + //m_meter.Create("Press start timer to see me go", + // WS_VISIBLE | WS_CHILD | WS_EX_CLIENTEDGE, CRect(0, 0, 0, 0), this, (HMENU) 101); + static CString className = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW); + DWORD dwExStyle = WS_EX_STATICEDGE; //WS_EX_CLIENTEDGE | WS_EX_STATICEDGE; + m_meter.CreateEx(dwExStyle, className, + "Press start timer to see me go", WS_VISIBLE | WS_CHILD, + CRect(0, 0, 0, 0), this, 101); + + m_meter.SetRange(0, 100); + m_meter.SetPos(0); + //m_meter.SetStep(1); + + return 0; +} + +void CMeterBar::OnSize(UINT nType, int cx, int cy) +{ + CStatusBarCtrl::OnSize(nType, cx, cy); + + // TODO: 在此处添加消息处理程序代码 + int nTemp; + int nCount = GetParts(0, &nTemp); + if (nCount > 0) { + CRect r; + GetRect(nCount - 1, r); + m_meter.MoveWindow(r); + } +} diff --git a/samples/http_client/MeterBar.h b/samples/http_client/MeterBar.h new file mode 100644 index 000000000..9dac6109d --- /dev/null +++ b/samples/http_client/MeterBar.h @@ -0,0 +1,33 @@ +#pragma once +#include "afxcmn.h" +#include "MeterCtrl.h" + +// CMeterBar + +class CMeterBar : public CStatusBarCtrl +{ + DECLARE_DYNAMIC(CMeterBar) + +public: + CMeterBar(); + virtual ~CMeterBar(); + + BOOL SetParts(int nParts, int* pWidths); + + CMeterCtrl& GetProgressCtrl() { + return m_meter; + } + +protected: + DECLARE_MESSAGE_MAP() + //CProgressCtrl m_meter; + CMeterCtrl m_meter; +public: + afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); + afx_msg void OnSize(UINT nType, int cx, int cy); +private: + int *m_pWidths; + int m_nParts; +}; + + diff --git a/samples/http_client/MeterCtrl.cpp b/samples/http_client/MeterCtrl.cpp new file mode 100644 index 000000000..6f5b0cf7a --- /dev/null +++ b/samples/http_client/MeterCtrl.cpp @@ -0,0 +1,170 @@ +// MeterCtrl.cpp : 实现文件 +// + +#include "stdafx.h" +#include "MeterCtrl.h" +#include ".\Meterctrl.h" + + +// CMeterCtrl + +IMPLEMENT_DYNAMIC(CMeterCtrl, CWnd) +CMeterCtrl::CMeterCtrl() +: m_nLower(0) +, m_nUpper(0) +, m_nPos(0) +{ +} + +CMeterCtrl::~CMeterCtrl() +{ +} + + +BEGIN_MESSAGE_MAP(CMeterCtrl, CWnd) + ON_WM_PAINT() + ON_WM_ERASEBKGND() +END_MESSAGE_MAP() + + + +// CMeterCtrl 消息处理程序 + + +void CMeterCtrl::OnPaint() +{ + CPaintDC dc(this); // device context for painting + // TODO: 在此处添加消息处理程序代码 + // 不为绘图消息调用 CWnd::OnPaint() + CRect rClient; + GetClientRect(rClient); + CRect rLeft = rClient; + CRect rRight = rClient; + UINT nRange = m_nUpper - m_nLower; + + rLeft.right = (LONG)(((m_nPos - m_nLower) * rClient.Width())/ nRange); + rRight.left = rLeft.right; + + CRgn rgnLeft, rgnRight; + rgnLeft.CreateRectRgnIndirect(rLeft); + rgnRight.CreateRectRgnIndirect(rRight); + + CBrush *pBrush = CBrush::FromHandle(GetSysColorBrush(COLOR_HIGHLIGHT)); + dc.FillRect(rLeft, pBrush); + CString msg; + +// msg.Format(">>left=%d, right=%d, top=%d, bottom=%d, nrange=%d, width=%d, npos=%d, nlower=%d", +// rLeft.left, rLeft.right, rLeft.top, rLeft.bottom, +// nRange, rClient.Width(), m_nPos, m_nLower); +// AfxMessageBox(msg); + + //CString strCaption; + //GetWindowText(strCaption); + + //strCaption.Format("%d%% (%d)", ((m_nPos - m_nLower) * 100)/ nRange, m_nPos); + + dc.SelectClipRgn(&rgnLeft); + dc.SetBkMode(TRANSPARENT); + dc.SetTextColor(GetSysColor(COLOR_HIGHLIGHTTEXT)); + dc.DrawText(m_sCaption, rClient, DT_BOTTOM | DT_CENTER); + dc.SelectClipRgn(&rgnRight); + dc.SetTextColor(GetSysColor(COLOR_HIGHLIGHT)); + dc.DrawText(m_sCaption, rClient, DT_BOTTOM | DT_CENTER); +} + +BOOL CMeterCtrl::OnEraseBkgnd(CDC* pDC) +{ + // TODO: 在此添加消息处理程序代码和/或调用默认值 + CRect r; + GetClientRect(r); + CBrush *pBrush = CBrush::FromHandle(GetSysColorBrush(COLOR_BTNFACE)); + pDC->FillRect(r, pBrush); + + return TRUE; +// return CWnd::OnEraseBkgnd(pDC); +} + +BOOL CMeterCtrl::Create(LPCTSTR lpszWindowName, DWORD dwStyle, + const RECT& rect, CWnd* pParentWnd, HMENU nID) +{ + // TODO: 在此添加专用代码和/或调用基类 + static CString className = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW); + + return CWnd::CreateEx(WS_EX_STATICEDGE, //WS_EX_CLIENTEDGE | WS_EX_STATICEDGE, + className, lpszWindowName, dwStyle, + rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, + pParentWnd->GetSafeHwnd(), (HMENU) nID); + +// return CWnd::Create(lpszClassName, lpszWindowName, dwStyle, +// rect, pParentWnd, nID, pContext); +} + +BOOL CMeterCtrl::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName, + LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, + CWnd* pParentWnd, UINT nID, LPVOID lpParam) +{ + // TODO: 在此添加专用代码和/或调用基类 + + static CString className = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW); + + return CWnd::CreateEx(dwExStyle, //WS_EX_CLIENTEDGE | WS_EX_STATICEDGE, + lpszClassName, lpszWindowName, dwStyle, + rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, + pParentWnd->GetSafeHwnd(), (HMENU) nID); + + //return CWnd::CreateEx(dwExStyle, lpszClassName, lpszWindowName, + // dwStyle, rect, pParentWnd, nID, lpParam); +} + +UINT CMeterCtrl::SetPos(UINT nPos) +{ + ASSERT(nPos >= m_nLower && nPos <= m_nUpper); + + UINT nRange = m_nUpper - m_nLower; + UINT nOld = m_nPos; + m_nPos = nPos; + + m_sCaption.Format("%d%% (%d)", ((m_nPos - m_nLower) * 100)/ nRange, m_nPos); + InvalidateMeater(); + + return nOld; +} + +void CMeterCtrl::SetRange(UINT nLower, UINT nUpper) +{ + ASSERT(nLower >= 0 && nLower < 0xffff); + ASSERT(nUpper > nLower && nUpper < 0xffff); + + m_nLower = nLower; + m_nUpper = nUpper; + + InvalidateMeater(); +} + +void CMeterCtrl::StepIt(void) +{ + m_nPos++; + if (m_nPos > m_nUpper) + m_nPos = m_nLower; + + InvalidateMeater(); +} + +void CMeterCtrl::SetText(CString& msg) +{ + m_sCaption = msg; + InvalidateMeater(); +} + +void CMeterCtrl::SetText(const char* pMsg) +{ + m_sCaption = pMsg; + InvalidateMeater(); +} + +void CMeterCtrl::InvalidateMeater(void) +{ + CRect r; + GetClientRect(r); + InvalidateRect(r); +} diff --git a/samples/http_client/MeterCtrl.h b/samples/http_client/MeterCtrl.h new file mode 100644 index 000000000..49cc9dd9a --- /dev/null +++ b/samples/http_client/MeterCtrl.h @@ -0,0 +1,38 @@ +#pragma once + + +// CMeterCtrl + +class CMeterCtrl : public CWnd +{ + DECLARE_DYNAMIC(CMeterCtrl) + +public: + CMeterCtrl(); + virtual ~CMeterCtrl(); + +protected: + DECLARE_MESSAGE_MAP() +public: + afx_msg void OnPaint(); + afx_msg BOOL OnEraseBkgnd(CDC* pDC); + //virtual BOOL Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext = NULL); + virtual BOOL Create(LPCTSTR lpszWindowName, DWORD dwStyle, + const RECT& rect, CWnd* pParentWnd, HMENU nID); + virtual BOOL CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName, + LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, + CWnd* pParentWnd, UINT nID, LPVOID lpParam = NULL); + UINT SetPos(UINT nPos); + void SetRange(UINT nLower, UINT nUpper); + void StepIt(void); + void SetText(CString& msg); + void SetText(const char* pMsg); +protected: + void InvalidateMeater(void); + UINT m_nLower; + UINT m_nUpper; + UINT m_nPos; + CString m_sCaption; +}; + + diff --git a/samples/http_client/ReadMe.txt b/samples/http_client/ReadMe.txt new file mode 100644 index 000000000..b85f18bc6 --- /dev/null +++ b/samples/http_client/ReadMe.txt @@ -0,0 +1,85 @@ +================================================================================ + MICROSOFT 基础类库: http_client 项目概述 +=============================================================================== + +应用程序向导已为您创建了此 http_client 应用程序。此应用程序 +不仅介绍了使用 Microsoft 基础类的基本知识, +而且是编写应用程序的起点。 + +此文件包含组成 http_client 应用程序的每个文件的内容摘要。 + +http_client.vcproj + 这是使用“应用程序向导”生成的 VC++ 项目的主项目文件。 + 它包含有关生成文件的 Visual C++ 版本的信息,以及 + 有关用“应用程序向导”所选择的平台、配置和 + 项目功能的信息。 + +http_client.h + 这是应用程序的主头文件。 它包含其他 + 项目特定的头文件(包括 Resource.h),并声明 + Chttp_clientApp 应用程序类。 + +http_client.cpp + 这是包含应用程序 + 类 Chttp_clientApp 的主应用程序源文件。 + +http_client.rc + 这是程序使用的所有 Microsoft Windows 资源 + 的列表。 它包含存储在 RES 子目录中 + 的图标、位图和光标。 可直接在 Microsoft + Visual C++ 中编辑此文件。 项目资源包含在 2052 中。 + +res\http_client.ico + 这是一个图标文件,用作应用程序的图标。 此 + 图标包含在主资源文件 http_client.rc 中。 + +res\http_client.rc2 + 此文件包含不由 Microsoft + Visual C++ 编辑的资源。 应将所有不能由 + 资源编辑器编辑的资源放在此文件中。 + +///////////////////////////////////////////////////////////////////////////// + +应用程序向导将创建一个对话框类: +http_clientDlg.h、http_clientDlg.cpp - 对话框 + 这些文件包含 Chttp_clientDlg 类。 此类定义 + 应用程序主对话框的行为。 此对话框的模板包含在 + http_client.rc 中,而此文件可以在 Microsoft Visual C++ 中进行编辑。 +///////////////////////////////////////////////////////////////////////////// + +其他功能: + +ActiveX 控件 + 应用程序支持使用 ActiveX 控件。 + +Windows 套接字 + 应用程序支持在 TCP/IP 网络上建立通讯。 +///////////////////////////////////////////////////////////////////////////// + +其他标准文件: + +StdAfx.h、StdAfx.cpp + 这些文件用于生成名为 http_client.pch 的预编译头文件 (PCH) + 和名为 StdAfx.obj 的预编译类型文件。 + +Resource.h + 这是标准头文件,它定义新资源 ID。 + Microsoft Visual C++ 将读取并更新此文件。 + +///////////////////////////////////////////////////////////////////////////// + +其他说明: + +应用程序向导使用“TODO:” 来指示 +应添加或自定义的源代码部分。 + +如果应用程序在共享 DLL 中使用 MFC,且应用程序使用的语言不是 +操作系统的当前语言,则需要从 Microsoft Visual C++ 光盘上 +Win\System 目录下将相应的本地化资源 MFC70XXX.DLL +复制到计算机的 system 或 system32 目录下, +并将其重命名为 MFCLOC.DLL。 (“XXX”代表 +语言缩写。 例如,MFC70DEU.DLL 包含翻译成 +德语的资源。) 如果不这样做,应用程序的某些 UI 元素 +将保留为操作系统的语言。 + +///////////////////////////////////////////////////////////////////////////// diff --git a/samples/http_client/build/HttpClient.iss b/samples/http_client/build/HttpClient.iss new file mode 100644 index 000000000..648f164b9 --- /dev/null +++ b/samples/http_client/build/HttpClient.iss @@ -0,0 +1,45 @@ +; Script generated by the Inno Setup Script Wizard. +; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! + +[Setup] +; NOTE: The value of AppId uniquely identifies this application. +; Do not use the same AppId value in installers for other applications. +; (To generate a new GUID, click Tools | Generate GUID inside the IDE.) +AppId={{698C5042-5FBA-4FF0-A287-2FEDDE04290B} +AppName=http client +AppVerName=http client +AppPublisher=zsxxsz +AppPublisherURL=http://www.sourceforge.net/projects/acl/ +AppSupportURL=http://www.sourceforge.net/projects/acl/ +AppUpdatesURL=http://www.sourceforge.net/projects/acl/ +DefaultDirName={pf}\Acl Project\http client +DefaultGroupName=Acl Project +OutputDir=.\ +OutputBaseFilename=http client +SetupIconFile=..\res\http_client.ico +Compression=lzma +SolidCompression=yes + +[Languages] +Name: "chinese"; MessagesFile: "compiler:Languages\ChineseSimplified.isl" + +[Tasks] +Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked +Name: "quicklaunchicon"; Description: "{cm:CreateQuickLaunchIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked + +[Files] +Source: "..\ReleaseDll\http_client.exe"; DestDir: "{app}"; Flags: ignoreversion +Source: "..\ReleaseDll\lib_protocol.dll"; DestDir: "{app}"; Flags: ignoreversion +Source: "..\ReleaseDll\lib_acl.dll"; DestDir: "{app}"; Flags: ignoreversion +; NOTE: Don't use "Flags: ignoreversion" on any shared system files + +[Icons] +Name: "{group}\http client"; Filename: "{app}\http_client.exe" +Name: "{group}\{cm:ProgramOnTheWeb,http client}"; Filename: "http://www.sourceforge.net/projects/acl/" +Name: "{group}\{cm:UninstallProgram,http client}"; Filename: "{uninstallexe}" +Name: "{commondesktop}\http client"; Filename: "{app}\http_client.exe"; Tasks: desktopicon +Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\http client"; Filename: "{app}\http_client.exe"; Tasks: quicklaunchicon + +[Run] +Filename: "{app}\http_client.exe"; Description: "{cm:LaunchProgram,http client}"; Flags: nowait postinstall skipifsilent + diff --git a/samples/http_client/build/http client.exe b/samples/http_client/build/http client.exe new file mode 100644 index 000000000..9482ff648 Binary files /dev/null and b/samples/http_client/build/http client.exe differ diff --git a/samples/http_client/http_client.cpp b/samples/http_client/http_client.cpp new file mode 100644 index 000000000..e4e52fad7 --- /dev/null +++ b/samples/http_client/http_client.cpp @@ -0,0 +1,82 @@ +// http_client.cpp : 定义应用程序的类行为。 +// + +#include "stdafx.h" +#include "lib_acl.h" +#include "http_client.h" +#include "http_clientDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#endif + + +// Chttp_clientApp + +BEGIN_MESSAGE_MAP(Chttp_clientApp, CWinApp) + ON_COMMAND(ID_HELP, CWinApp::OnHelp) +END_MESSAGE_MAP() + + +// Chttp_clientApp 构造 + +Chttp_clientApp::Chttp_clientApp() +{ + // TODO: 在此处添加构造代码, + // 将所有重要的初始化放置在 InitInstance 中 +} + + +// 唯一的一个 Chttp_clientApp 对象 + +Chttp_clientApp theApp; + + +// Chttp_clientApp 初始化 + +BOOL Chttp_clientApp::InitInstance() +{ + // 如果一个运行在 Windows XP 上的应用程序清单指定要 + // 使用 ComCtl32.dll 版本 6 或更高版本来启用可视化方式, + //则需要 InitCommonControls()。否则,将无法创建窗口。 + InitCommonControls(); + + CWinApp::InitInstance(); + + if (!AfxSocketInit()) + { + AfxMessageBox(IDP_SOCKETS_INIT_FAILED); + return FALSE; + } + + AfxEnableControlContainer(); + + // 标准初始化 + // 如果未使用这些功能并希望减小 + // 最终可执行文件的大小,则应移除下列 + // 不需要的特定初始化例程 + // 更改用于存储设置的注册表项 + // TODO: 应适当修改该字符串, + // 例如修改为公司或组织名 + SetRegistryKey(_T("应用程序向导生成的本地应用程序")); + + acl_msg_open("log.txt", "http_client"); + + Chttp_clientDlg dlg; + m_pMainWnd = &dlg; + INT_PTR nResponse = dlg.DoModal(); + if (nResponse == IDOK) + { + // TODO: 在此放置处理何时用“确定”来关闭 + //对话框的代码 + } + else if (nResponse == IDCANCEL) + { + // TODO: 在此放置处理何时用“取消”来关闭 + //对话框的代码 + } + + // 由于对话框已关闭,所以将返回 FALSE 以便退出应用程序, + // 而不是启动应用程序的消息泵。 + return FALSE; +} diff --git a/samples/http_client/http_client.h b/samples/http_client/http_client.h new file mode 100644 index 000000000..66171852c --- /dev/null +++ b/samples/http_client/http_client.h @@ -0,0 +1,31 @@ +// http_client.h : PROJECT_NAME 应用程序的主头文件 +// + +#pragma once + +#ifndef __AFXWIN_H__ + #error 在包含用于 PCH 的此文件之前包含“stdafx.h” +#endif + +#include "resource.h" // 主符号 + + +// Chttp_clientApp: +// 有关此类的实现,请参阅 http_client.cpp +// + +class Chttp_clientApp : public CWinApp +{ +public: + Chttp_clientApp(); + +// 重写 + public: + virtual BOOL InitInstance(); + +// 实现 + + DECLARE_MESSAGE_MAP() +}; + +extern Chttp_clientApp theApp; diff --git a/samples/http_client/http_client.rc b/samples/http_client/http_client.rc new file mode 100644 index 000000000..a88a62f56 --- /dev/null +++ b/samples/http_client/http_client.rc @@ -0,0 +1,288 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// 中文(中华人民共和国) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) +#ifdef _WIN32 +LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED +#pragma code_page(936) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "#define _AFX_NO_SPLITTER_RESOURCES\r\n" + "#define _AFX_NO_OLE_RESOURCES\r\n" + "#define _AFX_NO_TRACKER_RESOURCES\r\n" + "#define _AFX_NO_PROPERTY_RESOURCES\r\n" + "\r\n" + "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)\r\n" + "LANGUAGE 4, 2\r\n" + "#pragma code_page(936)\r\n" + "#include ""res\\http_client.rc2"" // 非 Microsoft Visual C++ 编辑过的资源\r\n" + "#include ""afxres.rc"" // 标准组件\r\n" + "#endif\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDR_MAINFRAME ICON "res\\http_client.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_ABOUTBOX DIALOGEX 0, 0, 235, 55 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | + WS_SYSMENU +CAPTION "关于 http_client" +FONT 9, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + ICON IDR_MAINFRAME,IDC_STATIC,11,17,20,20 + LTEXT "http_client Version 1.0",IDC_STATIC,40,10,119,8, + SS_NOPREFIX + LTEXT "Copyright (C) 2008",IDC_STATIC,40,25,119,8 + DEFPUSHBUTTON "确定",IDOK,178,7,50,16,WS_GROUP +END + +IDD_HTTP_CLIENT_DIALOG DIALOGEX 0, 0, 581, 382 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | + WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +EXSTYLE WS_EX_APPWINDOW +CAPTION "http_client" +FONT 9, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + EDITTEXT IDC_EDIT_URL,70,18,452,14,ES_AUTOHSCROLL + CONTROL "本地存储",IDC_CHECK_SAVE,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,70,42,43,10 + EDITTEXT IDC_EDIT_FILE,70,55,452,14,ES_AUTOHSCROLL + DEFPUSHBUTTON "运行",IDC_BUTTON_GET,389,348,50,14 + PUSHBUTTON "退出",IDOK,514,347,50,16 + RTEXT "请求的URL:",IDC_STATIC,23,20,40,8 + RTEXT "本地文件:",IDC_STATIC,29,57,35,8 + PUSHBUTTON "浏览...",IDC_BUTTON_BROWSER,533,53,31,14 + EDITTEXT IDC_EDIT_HDR_REQ,17,89,266,102,ES_MULTILINE | + ES_AUTOHSCROLL | ES_READONLY | ES_WANTRETURN | + WS_VSCROLL | WS_HSCROLL + EDITTEXT IDC_EDIT_HDR_RES,294,89,269,102,ES_MULTILINE | + ES_AUTOHSCROLL | ES_READONLY | WS_VSCROLL | WS_HSCROLL + EDITTEXT IDC_EDIT_RES_BODY,17,217,546,120,ES_MULTILINE | + ES_AUTOHSCROLL | ES_READONLY | WS_VSCROLL + LTEXT "请求头:",IDC_STATIC,18,77,28,8 + LTEXT "返回头:",IDC_STATIC,172,75,28,8 + LTEXT "返回体:",IDC_STATIC,17,205,28,8 + CONTROL "显示返回内容",IDC_CHECK_ECHO,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,52,205,57,10 + PUSHBUTTON "设置...",IDC_BUTTON_OPTION,533,19,30,14 + PUSHBUTTON "清空",IDC_BUTTON_CLEAR,452,348,50,14 +END + +IDD_DIALOG_OPTION DIALOGEX 0, 0, 531, 297 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | + WS_SYSMENU +CAPTION "HTTP 设置" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + PUSHBUTTON "确定",IDOK,205,266,50,14 + PUSHBUTTON "取消",IDCANCEL,268,266,50,14 + CONTROL "HTTP1.1",IDC_CHECK_PROTO,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,40,26,45,10 + CONTROL "支持压缩",IDC_CHECK_ZIP,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,86,26,48,10 + EDITTEXT IDC_EDIT_ADDR,98,231,99,14,ES_AUTOHSCROLL + CONTROL "使用此地址",IDC_CHECK_USE_ADDR,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,37,233,56,10 + GROUPBOX "HTTP头",IDC_STATIC,26,12,228,176 + CONTROL "Keep-Alive",IDC_CHECK_KEEP_ALIVE,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,135,26,54,10 + EDITTEXT IDC_EDIT_HTTP_HDR,41,100,202,81,ES_MULTILINE | + ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN | + WS_VSCROLL | WS_HSCROLL + LTEXT "附加头信息:",IDC_STATIC,41,86,49,8 + CONTROL "自动重定向",IDC_CHECK_FORWARD,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,37,213,56,10 + GROUPBOX "控制",IDC_STATIC,25,199,230,57 + EDITTEXT IDC_EDIT_MAX_TRY,156,211,40,14,ES_AUTOHSCROLL + LTEXT "最大重试次数:",IDC_STATIC,97,214,57,8 + EDITTEXT IDC_EDIT_HTTP_BODY,278,24,211,224,ES_MULTILINE | + ES_WANTRETURN | WS_VSCROLL + GROUPBOX "HTTP体",IDC_STATIC,267,12,238,243 + CONTROL "POST",IDC_POST_METHOD,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,188,26,33,10 + LTEXT "Content-Type:",IDC_STATIC,39,41,53,10 + EDITTEXT IDC_CONTENT_TYPE,91,40,151,12,ES_AUTOHSCROLL + RTEXT "Accept:",IDC_STATIC,42,60,45,9 + EDITTEXT IDC_ACCEPT,91,60,151,12,ES_AUTOHSCROLL +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "080403a8" + BEGIN + VALUE "CompanyName", "TODO: <公司名>" + VALUE "FileDescription", "TODO: <文件说明>" + VALUE "FileVersion", "1.0.0.1" + VALUE "InternalName", "http_client.exe" + VALUE "LegalCopyright", "TODO: (C) <公司名>。保留所有权利。" + VALUE "OriginalFilename", "http_client.exe" + VALUE "ProductName", "TODO: <产品名>" + VALUE "ProductVersion", "1.0.0.1" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "翻译", 0x804, 936 + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_ABOUTBOX, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 228 + TOPMARGIN, 7 + BOTTOMMARGIN, 48 + END + + IDD_HTTP_CLIENT_DIALOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 573 + TOPMARGIN, 7 + BOTTOMMARGIN, 375 + END + + IDD_DIALOG_OPTION, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 524 + TOPMARGIN, 7 + BOTTOMMARGIN, 290 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDR_MENU1 MENU +BEGIN + POPUP "help" + BEGIN + MENUITEM "pixels", ID_INDICATOR_PIXELS + MENUITEM "bytes", ID_INDICATOR_BYTES + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + IDS_ABOUTBOX "关于 http_client(&A)..." + IDP_SOCKETS_INIT_FAILED "Windows 套接字初始化失败。" +END + +STRINGTABLE +BEGIN + ID_INDICATOR_PIXELS "9999*9999 pixels" + ID_INDICATOR_BYTES "99, 999 bytes" +END + +#endif // 中文(中华人民共和国) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +#define _AFX_NO_SPLITTER_RESOURCES +#define _AFX_NO_OLE_RESOURCES +#define _AFX_NO_TRACKER_RESOURCES +#define _AFX_NO_PROPERTY_RESOURCES + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) +LANGUAGE 4, 2 +#pragma code_page(936) +#include "res\http_client.rc2" // 非 Microsoft Visual C++ 编辑过的资源 +#include "afxres.rc" // 标准组件 +#endif + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/samples/http_client/http_client.vcxproj b/samples/http_client/http_client.vcxproj new file mode 100644 index 000000000..f64ad9a65 --- /dev/null +++ b/samples/http_client/http_client.vcxproj @@ -0,0 +1,274 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + ReleaseDll + Win32 + + + Release + Win32 + + + Template + Win32 + + + + http_client + {9BCB6DE9-73D2-484A-B946-0BD5FDDF8CCB} + MFCProj + + + + Application + Dynamic + MultiByte + + + Application + Dynamic + MultiByte + + + Application + Static + MultiByte + + + Application + Static + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\lib_acl\include;..\..\lib_protocol\include;%(AdditionalIncludeDirectories) + WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + true + Use + Level3 + EditAndContinue + + + ws2_32.lib;%(AdditionalDependencies) + %(AdditionalLibraryDirectories) + %(IgnoreSpecificDefaultLibraries) + true + Windows + MachineX86 + + + _DEBUG;%(PreprocessorDefinitions) + false + + + _DEBUG;%(PreprocessorDefinitions) + 0x0804 + $(IntDir);%(AdditionalIncludeDirectories) + + + + + ..\..\lib_acl\include;..\..\lib_protocol\include;%(AdditionalIncludeDirectories) + WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) + false + MultiThreaded + true + Use + Level3 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + %(AdditionalLibraryDirectories) + %(IgnoreSpecificDefaultLibraries) + true + Windows + true + true + MachineX86 + + + NDEBUG;%(PreprocessorDefinitions) + false + + + NDEBUG;%(PreprocessorDefinitions) + 0x0804 + $(IntDir);%(AdditionalIncludeDirectories) + + + + + Disabled + ..\..\lib_acl\include;..\..\lib_protocol\include;%(AdditionalIncludeDirectories) + WIN32;_WINDOWS;_DEBUG;ACL_DLL;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + true + Use + Level3 + EditAndContinue + + + ws2_32.lib;%(AdditionalDependencies) + %(AdditionalLibraryDirectories) + libcmtd;%(IgnoreSpecificDefaultLibraries) + true + Windows + MachineX86 + + + _DEBUG;%(PreprocessorDefinitions) + false + + + _DEBUG;%(PreprocessorDefinitions) + 0x0804 + $(IntDir);%(AdditionalIncludeDirectories) + + + + + ..\..\lib_acl\include;..\..\lib_protocol\include;%(AdditionalIncludeDirectories) + WIN32;_WINDOWS;NDEBUG;ACL_DLL;HTTP_DLL;%(PreprocessorDefinitions) + false + MultiThreadedDLL + true + Use + Level3 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + %(AdditionalLibraryDirectories) + %(IgnoreSpecificDefaultLibraries) + true + Windows + true + true + MachineX86 + + + NDEBUG;%(PreprocessorDefinitions) + false + + + NDEBUG;%(PreprocessorDefinitions) + 0x0804 + $(IntDir);%(AdditionalIncludeDirectories) + + + + + + + + + + + Create + Create + Create + Create + + + + + + + + + + + + + + + + + + + + + + + + + + {b40213c2-507c-4c7f-a6e1-b850c9bdc27b} + false + + + {fe724ef7-3763-4e78-bdf5-bcbc075719fd} + false + + + + + + + + + + + \ No newline at end of file diff --git a/samples/http_client/http_client.vcxproj.filters b/samples/http_client/http_client.vcxproj.filters new file mode 100644 index 000000000..2344b6489 --- /dev/null +++ b/samples/http_client/http_client.vcxproj.filters @@ -0,0 +1,83 @@ +锘 + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx + + + + + 婧愭枃浠 + + + 婧愭枃浠 + + + 婧愭枃浠 + + + 婧愭枃浠 + + + 婧愭枃浠 + + + 婧愭枃浠 + + + 婧愭枃浠 + + + + + 澶存枃浠 + + + 澶存枃浠 + + + 澶存枃浠 + + + 澶存枃浠 + + + 澶存枃浠 + + + 澶存枃浠 + + + 澶存枃浠 + + + 澶存枃浠 + + + + + 璧勬簮鏂囦欢 + + + 璧勬簮鏂囦欢 + + + + + + 璧勬簮鏂囦欢 + + + + + + \ No newline at end of file diff --git a/samples/http_client/http_clientDlg.cpp b/samples/http_client/http_clientDlg.cpp new file mode 100644 index 000000000..d9bf01d23 --- /dev/null +++ b/samples/http_client/http_clientDlg.cpp @@ -0,0 +1,410 @@ +// http_clientDlg.cpp : 实现文件 +// + +#include "stdafx.h" +#include "http_client.h" +#include "HttpClient.h" +#include "HttpOption.h" +#include "http_clientDlg.h" +#include ".\http_clientdlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#endif + + +// 用于应用程序“关于”菜单项的 CAboutDlg 对话框 + +class CAboutDlg : public CDialog +{ +public: + CAboutDlg(); + +// 对话框数据 + enum { IDD = IDD_ABOUTBOX }; + + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 + +// 实现 +protected: + DECLARE_MESSAGE_MAP() +}; + +CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) +{ +} + +void CAboutDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); +} + +BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) +END_MESSAGE_MAP() + + +// Chttp_clientDlg 对话框 + + + +Chttp_clientDlg::Chttp_clientDlg(CWnd* pParent /*=NULL*/) + : CDialog(Chttp_clientDlg::IDD, pParent) + , m_sReqUrl(_T("")) + , m_sLocalFile(_T("")) + , m_bHttp11(TRUE) + , m_bZip(FALSE) + , m_bKeepAlive(FALSE) + , m_sHttpHdrAppend(_T("")) + , m_sServerAddr(_T("")) + , m_sAccept(_T("application/json, text/javascript, */*; q=0.01")) + , m_sCType(_T("")) + , m_bUseAddr(FALSE) + , m_nContentLength(-1) + , m_bForwardAuto(FALSE) + , m_nMaxTry(10) + , m_bPostMethod(FALSE) +{ + m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); +} + +void Chttp_clientDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + DDX_Text(pDX, IDC_EDIT_URL, m_sReqUrl); + DDX_Text(pDX, IDC_EDIT_FILE, m_sLocalFile); + DDX_Control(pDX, IDC_EDIT_HDR_REQ, m_reqCtlEdit); + DDX_Control(pDX, IDC_EDIT_HDR_RES, m_resCtlEdit); + DDX_Control(pDX, IDC_EDIT_RES_BODY, m_resBodyCtlEdit); +} + +BEGIN_MESSAGE_MAP(Chttp_clientDlg, CDialog) + ON_WM_SYSCOMMAND() + ON_WM_PAINT() + ON_WM_QUERYDRAGICON() + //}}AFX_MSG_MAP + ON_BN_CLICKED(IDC_BUTTON_BROWSER, OnBnClickedButtonBrowser) + ON_BN_CLICKED(IDC_BUTTON_OPTION, OnBnClickedButtonOption) + ON_BN_CLICKED(IDC_BUTTON_GET, OnBnClickedButtonGet) + ON_MESSAGE(WM_USER_DISPLAY, OnWriteDisplay) + ON_BN_CLICKED(IDC_BUTTON_CLEAR, OnBnClickedButtonClear) + ON_WM_SIZE() + ON_WM_CREATE() +END_MESSAGE_MAP() + + +// Chttp_clientDlg 消息处理程序 + +BOOL Chttp_clientDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + // 将\“关于...\”菜单项添加到系统菜单中。 + + // IDM_ABOUTBOX 必须在系统命令范围内。 + ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); + ASSERT(IDM_ABOUTBOX < 0xF000); + + CMenu* pSysMenu = GetSystemMenu(FALSE); + if (pSysMenu != NULL) + { + CString strAboutMenu; + strAboutMenu.LoadString(IDS_ABOUTBOX); + if (!strAboutMenu.IsEmpty()) + { + pSysMenu->AppendMenu(MF_SEPARATOR); + pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); + } + } + + // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动 + // 执行此操作 + SetIcon(m_hIcon, TRUE); // 设置大图标 + SetIcon(m_hIcon, FALSE); // 设置小图标 + + // TODO: 在此添加额外的初始化代码 + GetDlgItem(IDC_EDIT_FILE)->SetWindowText("result.txt"); + CheckDlgButton(IDC_CHECK_SAVE, 0); + CheckDlgButton(IDC_CHECK_ECHO, 0); + m_resBodyCtlEdit.SetLimitText(0); + + // 添加状态栏 + int aWidths[3] = {50, 250, -1}; + m_wndMeterBar.SetParts(3, aWidths); + + m_wndMeterBar.Create(WS_CHILD | WS_VISIBLE | WS_BORDER + | CCS_BOTTOM | SBARS_SIZEGRIP, + CRect(0,0,0,0), this, 0); + m_wndMeterBar.SetText("就绪", 0, 0); + m_wndMeterBar.SetText("", 1, 0); + m_wndMeterBar.SetText("", 2, 0); //SBT_NOBORDERS); + //int strPartDim[3]= {100, 200, -1}; //分割数量 + //m_StatusBar.SetParts(3, strPartDim); + ////设置状态栏文本 + //m_StatusBar.SetText("", 0, 0); + //m_StatusBar.SetText("", 1, 0); + //m_StatusBar.SetText("", 2, 0); + //下面是在状态栏中加入图标 + //为第二个分栏中加的图标 + //m_StatusBar.SetIcon(0, SetIcon(AfxGetApp()->LoadIcon(IDR_MAINFRAME), FALSE)); + + return TRUE; // 除非设置了控件的焦点,否则返回 TRUE +} + +void Chttp_clientDlg::OnSysCommand(UINT nID, LPARAM lParam) +{ + if ((nID & 0xFFF0) == IDM_ABOUTBOX) + { + CAboutDlg dlgAbout; + dlgAbout.DoModal(); + } + else + { + CDialog::OnSysCommand(nID, lParam); + } +} + +// 如果向对话框添加最小化按钮,则需要下面的代码 +// 来绘制该图标。对于使用文档/视图模型的 MFC 应用程序, +// 这将由框架自动完成。 + +void Chttp_clientDlg::OnPaint() +{ + if (IsIconic()) + { + CPaintDC dc(this); // 用于绘制的设备上下文 + + SendMessage(WM_ICONERASEBKGND, reinterpret_cast(dc.GetSafeHdc()), 0); + + // 使图标在工作矩形中居中 + int cxIcon = GetSystemMetrics(SM_CXICON); + int cyIcon = GetSystemMetrics(SM_CYICON); + CRect rect; + GetClientRect(&rect); + int x = (rect.Width() - cxIcon + 1) / 2; + int y = (rect.Height() - cyIcon + 1) / 2; + + // 绘制图标 + dc.DrawIcon(x, y, m_hIcon); + } + else + { + CDialog::OnPaint(); + } +} + +//当用户拖动最小化窗口时系统调用此函数取得光标显示。 +HCURSOR Chttp_clientDlg::OnQueryDragIcon() +{ + return static_cast(m_hIcon); +} + +void Chttp_clientDlg::OnBnClickedButtonBrowser() +{ + // TODO: 在此添加控件通知处理程序代码 + CFileDialog file(TRUE,"文件","result.txt",OFN_HIDEREADONLY,"FILE(*.*)|*.*||",NULL); + if(file.DoModal()==IDOK) + { + CString pathname; + + pathname=file.GetPathName(); + GetDlgItem(IDC_EDIT_FILE)->SetWindowText(pathname); + } +} + +void Chttp_clientDlg::OnBnClickedButtonOption() +{ + // TODO: 在此添加控件通知处理程序代码 + CHttpOption option; + + option.m_bHttp11 = m_bHttp11; + option.m_bZip = m_bZip; + option.m_bKeepAlive = m_bKeepAlive; + option.m_sHttpHdrAppend = m_sHttpHdrAppend; + option.m_sServerAddr = m_sServerAddr; + option.m_bUseAddr = m_bUseAddr; + option.m_bForwardAuto = m_bForwardAuto; + option.m_nMaxTry = m_nMaxTry; + option.m_bPostMethod = m_bPostMethod; + option.m_sCType = m_sCType; + option.m_sAccept = m_sAccept; + option.m_sHttpBody = m_sBody; + option.m_bPostMethod = m_bPostMethod; + + if (option.DoModal() == IDOK) { + m_bHttp11 = option.m_bHttp11; + m_bZip = option.m_bZip; + m_bKeepAlive = option.m_bKeepAlive; + m_sHttpHdrAppend = option.m_sHttpHdrAppend; + m_sServerAddr = option.m_sServerAddr; + if (m_sServerAddr.GetLength() > 0) + m_bUseAddr = option.m_bUseAddr; + else + m_bUseAddr = FALSE; + m_bForwardAuto = option.m_bForwardAuto; + m_nMaxTry = option.m_nMaxTry; + m_bPostMethod = option.m_bPostMethod; + if (m_bPostMethod) + { + m_sBody = option.m_sHttpBody; + if (m_sBody.IsEmpty()) + m_bPostMethod = FALSE; + } + m_sCType = option.m_sCType; + m_sAccept = option.m_sAccept; + m_bPostMethod = option.m_bPostMethod; + } +} + +void Chttp_clientDlg::OnBnClickedButtonGet() +{ + // TODO: 在此添加控件通知处理程序代码 + CString sLocalFile, sReqUrl; + + GetDlgItem(IDC_EDIT_FILE)->GetWindowText(sLocalFile); + if (sLocalFile.GetLength() == 0) { + MessageBox("请输入正确的文件名!"); + return; + } + + GetDlgItem(IDC_EDIT_URL)->GetWindowText(sReqUrl); + if (sReqUrl.GetLength() == 0) { + MessageBox("请输入正确的 URL!"); + return; + } + + ClearWinText(); + + if (IsDlgButtonChecked(IDC_CHECK_SAVE)) + m_hClient.SaveAs(sLocalFile); + if (IsDlgButtonChecked(IDC_CHECK_ECHO)) + m_hClient.DisplayResBody(TRUE); + else + m_hClient.DisplayResBody(FALSE); + m_hClient.EnableHttp11(m_bHttp11); + m_hClient.EnableZip(m_bZip); + m_hClient.EnableKeepAlive(m_bKeepAlive); + m_hClient.m_sHttpHdrAppend = m_sHttpHdrAppend; + m_hClient.m_bUseAddr = m_bUseAddr; + m_hClient.m_sServerAddr = m_sServerAddr; + m_hClient.m_bForwardAuto = m_bForwardAuto; + m_hClient.m_nMaxTry = m_nMaxTry; + m_hClient.m_sHttpBody = m_sBody; + m_hClient.m_bPostMethod = m_bPostMethod; + m_hClient.m_sAccept = m_sAccept; + m_hClient.m_sCtype = m_sCType; + m_hClient.OnDataCallback(this->GetSafeHwnd(), WM_USER_DISPLAY); + + // 与进度条有关 + m_nContentLength = -1; + m_nDownLen = 0; + m_wndMeterBar.GetProgressCtrl().SetPos(0); + + m_wndMeterBar.SetText("运行", 0, 0); + + m_hClient.GetUrl(sReqUrl); + GetDlgItem(IDC_BUTTON_GET)->EnableWindow(FALSE); +} + +LRESULT Chttp_clientDlg::OnWriteDisplay(WPARAM wParam, LPARAM lParam) +{ + CHttpReport *pReport = (CHttpReport*) wParam; + + if (pReport->m_type == TYPE_HDR_REQ) { + m_reqCtlEdit.SetSel(m_reqCtlEdit.GetWindowTextLength(), + m_reqCtlEdit.GetWindowTextLength()); + m_reqCtlEdit.ReplaceSel(pReport->m_pBuf); + } else if (pReport->m_type == TYPE_HDR_RES) { + m_resCtlEdit.SetSel(m_resCtlEdit.GetWindowTextLength(), + m_resCtlEdit.GetWindowTextLength()); + m_resCtlEdit.ReplaceSel(pReport->m_pBuf); + } else if (pReport->m_type == TYPE_BODY_RES) { + m_resBodyCtlEdit.SetSel(m_resBodyCtlEdit.GetWindowTextLength(), + m_resBodyCtlEdit.GetWindowTextLength()); + m_resBodyCtlEdit.ReplaceSel(pReport->m_pBuf); + } else if (pReport->m_type == TYPE_TOTAL_LEN) { + m_nContentLength = pReport->m_nContentLength; + ASSERT(pReport->m_pBuf == NULL); + } else if (pReport->m_type == TYPE_DOWN_LEN) { + m_nDownLen += pReport->m_nDownLen; + if (m_nContentLength > 0) { + http_off_t nStept; + + nStept = (m_nDownLen * 100) / (m_nContentLength); + m_wndMeterBar.GetProgressCtrl().SetPos((int) nStept); + } + CString msg; + msg.Format("共 %I64d 字节, 耗时 %.3f 毫秒", + m_nDownLen, pReport->m_timeRes); + m_wndMeterBar.SetText(msg, 1, 0); + } else if (pReport->m_type == TYPE_ERROR_CONNECT) { + CString msg; + + msg.Format("%s", pReport->m_pBuf); + m_wndMeterBar.GetProgressCtrl().SetText(msg.GetString()); + //m_wndMeterBar.GetProgressCtrl.SetWindowText(msg); + } else if (pReport->m_type == TYPE_TIME_RES) { + CString msg; + msg.Format("共 %I64d 字节, 耗时 %.3f 毫秒", + m_nDownLen, pReport->m_timeRes); + m_wndMeterBar.SetText(msg, 1, 0); + } else if (pReport->m_type == TYPE_COMPLETE) { + CString msg; + msg.Format("完成"); + m_wndMeterBar.SetText(msg, 0, 0); + GetDlgItem(IDC_BUTTON_GET)->EnableWindow(TRUE); + } + + ASSERT(pReport); + delete pReport; + + return (0); +} + +void Chttp_clientDlg::ClearWinText(void) +{ + m_reqCtlEdit.SetSel(0, m_reqCtlEdit.GetWindowTextLength()); + m_reqCtlEdit.ReplaceSel(""); + m_resCtlEdit.SetSel(0, m_resCtlEdit.GetWindowTextLength()); + m_resCtlEdit.ReplaceSel(""); + m_resBodyCtlEdit.SetSel(0, m_resBodyCtlEdit.GetWindowTextLength()); + m_resBodyCtlEdit.ReplaceSel(""); + m_wndMeterBar.SetText("就绪", 0, 0); + m_wndMeterBar.SetText("", 1, 0); + m_wndMeterBar.GetProgressCtrl().SetPos(0); + + //m_reqCtlEdit.Clear(); + //m_resCtlEdit.Clear(); + //m_resBodyCtlEdit.Clear(); +} + +void Chttp_clientDlg::OnBnClickedButtonClear() +{ + // TODO: 在此添加控件通知处理程序代码 + ClearWinText(); +} +void Chttp_clientDlg::OnSize(UINT nType, int cx, int cy) +{ + CDialog::OnSize(nType, cx, cy); + + // TODO: 在此处添加消息处理程序代码 + if (m_wndMeterBar.GetSafeHwnd()) { + int aWidths[3] = {cx / 3, cx / 3, -1}; + m_wndMeterBar.SetParts(3, aWidths); + m_wndMeterBar.SetText("就绪", 0, 0); + m_wndMeterBar.SetText("就绪2", 1, 0); //SBT_NOBORDERS); + m_wndMeterBar.SetText("", 2, SBT_NOBORDERS); + + m_wndMeterBar.SendMessage(WM_SIZE, nType, MAKELONG(cy, cx)); + } +} + +int Chttp_clientDlg::OnCreate(LPCREATESTRUCT lpCreateStruct) +{ + if (CDialog::OnCreate(lpCreateStruct) == -1) + return -1; + + // TODO: 在此添加您专用的创建代码 + + return 0; +} diff --git a/samples/http_client/http_clientDlg.h b/samples/http_client/http_clientDlg.h new file mode 100644 index 000000000..a601cf13d --- /dev/null +++ b/samples/http_client/http_clientDlg.h @@ -0,0 +1,74 @@ +// http_clientDlg.h : 头文件 +// + +#pragma once +#include "HttpClient.h" +#include "MeterBar.h" +#include "lib_protocol.h" +#include "afxwin.h" +#include "afxext.h" + +// Chttp_clientDlg 对话框 +class Chttp_clientDlg : public CDialog +{ +// 构造 +public: + Chttp_clientDlg(CWnd* pParent = NULL); // 标准构造函数 + +// 对话框数据 + enum { IDD = IDD_HTTP_CLIENT_DIALOG }; + + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 + + +// 实现 +protected: + HICON m_hIcon; + + // 生成的消息映射函数 + virtual BOOL OnInitDialog(); + afx_msg void OnSysCommand(UINT nID, LPARAM lParam); + afx_msg void OnPaint(); + afx_msg HCURSOR OnQueryDragIcon(); + DECLARE_MESSAGE_MAP() +public: + afx_msg void OnBnClickedButtonBrowser(); + afx_msg void OnBnClickedButtonOption(); + afx_msg void OnBnClickedButtonGet(); + afx_msg LRESULT OnWriteDisplay(WPARAM wParam, LPARAM lParam); +private: + CString m_sReqUrl; + CString m_sLocalFile; + CHttpClient m_hClient; + CEdit m_reqCtlEdit; + CEdit m_resCtlEdit; + CEdit m_resBodyCtlEdit; + BOOL m_bHttp11; + BOOL m_bZip; + BOOL m_bKeepAlive; + BOOL m_bPostMethod; + CString m_sBody; + CString m_sAccept; + CString m_sCType; + + http_off_t m_nContentLength; + http_off_t m_nDownLen; + + void ClearWinText(void); +public: + afx_msg void OnBnClickedButtonClear(); +private: + CString m_sHttpHdrAppend; + CString m_sServerAddr; + BOOL m_bUseAddr; +protected: + CMeterBar m_wndMeterBar; + //CStatusBarCtrl m_wndMeterBar; +public: + afx_msg void OnSize(UINT nType, int cx, int cy); + afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); +private: + BOOL m_bForwardAuto; + UINT m_nMaxTry; +}; diff --git a/samples/http_client/http_client_vc2003.vcproj b/samples/http_client/http_client_vc2003.vcproj new file mode 100644 index 000000000..0fe3ce34a --- /dev/null +++ b/samples/http_client/http_client_vc2003.vcproj @@ -0,0 +1,355 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/http_client/http_client_vc2008.vcproj b/samples/http_client/http_client_vc2008.vcproj new file mode 100644 index 000000000..4b1c4c730 --- /dev/null +++ b/samples/http_client/http_client_vc2008.vcproj @@ -0,0 +1,315 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/http_client/log.txt b/samples/http_client/log.txt new file mode 100644 index 000000000..990831815 --- /dev/null +++ b/samples/http_client/log.txt @@ -0,0 +1,11 @@ +2008/10/14 17:06:28 http_client(pid=22572, tid=22792)(1, error): acl_inet_connect_ex(99): connect ip(60.288.250.199) port(8383) error +/10/13 14:16:07 http_client(pid=20180, tid=21700)(1, error): acl_inet_connect_ex(99): connect ip(69.46.228.53) port(80) error +2008/10/13 14:16:51 http_client(pid=20180, tid=21672)(1, error): acl_inet_connect_ex(99): connect ip(69.46.228.53) port(80) error +thostbyname error(unknown error), addr=www.sina..com +2009/04/08 10:19:44 http_client(pid=2624, tid=2628)(1, error): d:\工作目录\项目管理\acl\acl_project\lib_acl\src\net\connect\acl_inet_connect.c, acl_inet_connect_ex(67): invalid port(0) +2009/04/08 10:27:23 http_client(pid=2624, tid=1708)(1, error): acl_inet_connect_ex(109): connect ip(127.0.0.1) port(28083) error +2009/04/08 10:31:01 http_client(pid=2624, tid=2108)(1, error): http_hdr_res_parse: entry_lnk's size 0 invalid +2009/04/08 10:31:01 http_client(pid=2624, tid=2108)(1, error): d:\工作目录\项目管理\acl\acl_project\win32_build\vc\samples\http_client\httpclient.cpp(315): parse hdr_res error +2009/04/08 10:47:37 http_client(pid=2624, tid=884)(1, error): http_hdr_res_parse: entry_lnk's size 0 invalid +2009/04/08 10:47:37 http_client(pid=2624, tid=884)(1, error): d:\工作目录\项目管理\acl\acl_project\win32_build\vc\samples\http_client\httpclient.cpp(315): parse hdr_res error +2009/04/09 10:52:11 http_client(pid=2412, tid=2428)(1, error): acl_inet_connect_ex(109): connect ip(10.0.251.164) port(80) error diff --git a/samples/http_client/res/http_client.ico b/samples/http_client/res/http_client.ico new file mode 100644 index 000000000..a9feccf6c Binary files /dev/null and b/samples/http_client/res/http_client.ico differ diff --git a/samples/http_client/res/http_client.manifest b/samples/http_client/res/http_client.manifest new file mode 100644 index 000000000..613be6320 --- /dev/null +++ b/samples/http_client/res/http_client.manifest @@ -0,0 +1,22 @@ + + + +鍦ㄦ璇存槑搴旂敤绋嬪簭 + + + + + + diff --git a/samples/http_client/res/http_client.rc2 b/samples/http_client/res/http_client.rc2 new file mode 100644 index 000000000..a40c41b59 --- /dev/null +++ b/samples/http_client/res/http_client.rc2 @@ -0,0 +1,13 @@ +// +// http_client.RC2 - Microsoft Visual C++ 不会直接编辑的资源 +// + +#ifdef APSTUDIO_INVOKED +#error 此文件不能由 Microsoft Visual C++ 编辑 +#endif //APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// 在此处添加手动编辑的资源... + +///////////////////////////////////////////////////////////////////////////// diff --git a/samples/http_client/resource.h b/samples/http_client/resource.h new file mode 100644 index 000000000..9997af32c --- /dev/null +++ b/samples/http_client/resource.h @@ -0,0 +1,51 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by http_client.rc +// +#define IDM_ABOUTBOX 0x0010 +#define IDD_ABOUTBOX 100 +#define IDS_ABOUTBOX 101 +#define IDD_HTTP_CLIENT_DIALOG 102 +#define IDP_SOCKETS_INIT_FAILED 103 +#define IDR_MAINFRAME 128 +#define IDD_DIALOG_OPTION 129 +#define IDR_MENU1 130 +#define IDC_BUTTON_GET 1000 +#define IDC_EDIT_URL 1001 +#define IDC_CHECK_SAVE 1002 +#define IDC_EDIT_FILE 1003 +#define IDC_BUTTON_BROWSER 1004 +#define IDC_EDIT_HDR_REQ 1005 +#define IDC_EDIT_HDR_RES 1006 +#define IDC_EDIT5 1007 +#define IDC_EDIT_RES_BODY 1007 +#define IDC_CHECK_ECHO 1008 +#define IDC_BUTTON_OPTION 1009 +#define IDC_BUTTON_CLEAR 1010 +#define IDC_CHECK_PROTO 1011 +#define IDC_CHECK_ZIP 1012 +#define IDC_EDIT_ADDR 1013 +#define IDC_CHECK_USE_ADDR 1014 +#define IDC_CHECK_KEEP_ALIVE 1015 +#define IDC_EDIT_HTTP_HDR 1016 +#define IDC_CHECK_FORWARD 1018 +#define IDC_EDIT1 1019 +#define IDC_EDIT_MAX_TRY 1019 +#define IDC_EDIT_HTTP_BODY 1021 +#define IDC_POST_METHOD 1022 +#define IDC_CONTENT_TYPE 1023 +#define IDC_EDIT3 1024 +#define IDC_ACCEPT 1024 +#define ID_INDICATOR_PIXELS 32773 +#define ID_INDICATOR_BYTES 32774 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 131 +#define _APS_NEXT_COMMAND_VALUE 32775 +#define _APS_NEXT_CONTROL_VALUE 1025 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/samples/http_client/stdafx.cpp b/samples/http_client/stdafx.cpp new file mode 100644 index 000000000..afbc038c6 --- /dev/null +++ b/samples/http_client/stdafx.cpp @@ -0,0 +1,7 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// http_client.pch 将是预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + + diff --git a/samples/http_client/stdafx.h b/samples/http_client/stdafx.h new file mode 100644 index 000000000..8b5b924fb --- /dev/null +++ b/samples/http_client/stdafx.h @@ -0,0 +1,46 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是经常使用但不常更改的 +// 项目特定的包含文件 + +#pragma once + +#ifndef VC_EXTRALEAN +#define VC_EXTRALEAN // 从 Windows 标头中排除不常使用的资料 +#endif + +// 如果您必须使用下列所指定的平台之前的平台,则修改下面的定义。 +// 有关不同平台的相应值的最新信息,请参考 MSDN。 +#ifndef WINVER // 允许使用 Windows 95 和 Windows NT 4 或更高版本的特定功能。 +#define WINVER 0x0400 //为 Windows98 和 Windows 2000 及更新版本改变为适当的值。 +#endif + +#ifndef _WIN32_WINNT // 允许使用 Windows NT 4 或更高版本的特定功能。 +#define _WIN32_WINNT 0x0500 //为 Windows98 和 Windows 2000 及更新版本改变为适当的值。 +#endif + +#ifndef _WIN32_WINDOWS // 允许使用 Windows 98 或更高版本的特定功能。 +#define _WIN32_WINDOWS 0x0410 //为 Windows Me 及更新版本改变为适当的值。 +#endif + +#ifndef _WIN32_IE // 允许使用 IE 4.0 或更高版本的特定功能。 +#define _WIN32_IE 0x0400 //为 IE 5.0 及更新版本改变为适当的值。 +#endif + +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // 某些 CString 构造函数将是显式的 + +// 关闭 MFC 对某些常见但经常被安全忽略的警告消息的隐藏 +#define _AFX_ALL_WARNINGS + +#include // MFC 核心和标准组件 +#include // MFC 扩展 +#include // MFC 自动化类 + +#include // Internet Explorer 4 公共控件的 MFC 支持 +#ifndef _AFX_NO_AFXCMN_SUPPORT +#include // Windows 公共控件的 MFC 支持 +#endif // _AFX_NO_AFXCMN_SUPPORT + +#include // MFC 套接字扩展 + +//自定义消息值 +#define WM_USER_DISPLAY WM_USER + 100 diff --git a/samples/http_gate/Makefile b/samples/http_gate/Makefile new file mode 100644 index 000000000..21dbd7335 --- /dev/null +++ b/samples/http_gate/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = http_gate diff --git a/samples/http_gate/main.c b/samples/http_gate/main.c new file mode 100644 index 000000000..5641a8275 --- /dev/null +++ b/samples/http_gate/main.c @@ -0,0 +1,82 @@ +#include "lib_acl.h" +#include "lib_protocol.h" +#include +#include + +static void init(void) +{ + acl_init(); +} + +static void end(void) +{ + acl_end(); +} + +static void thread_run(void *arg) +{ + ACL_VSTREAM *client = (ACL_VSTREAM*) arg; + + acl_vstream_close(client); +} + +static void run(void) +{ + const char *addr = "0.0.0.0:8089"; + ACL_VSTREAM *sstream = acl_vstream_listen(addr, 128); + acl_pthread_pool_t *pool; + + if (sstream == NULL) { + acl_msg_error("listen %s error(%s)", addr, acl_last_serror()); + return; + } + + printf("listening on %s ...\n", addr); + pool = acl_thread_pool_create(100, 120); + while (1) { + ACL_VSTREAM *client = acl_vstream_accept(sstream, NULL, 0); + if (client == NULL) { + acl_msg_error("accept error(%s)", acl_last_serror()); + break; + } + acl_pthread_pool_add(pool, thread_run, client); + } + + acl_vstream_close(sstream); +} + +static void test(void) +{ + HTTP_HDR_REQ *hdr_req = http_hdr_req_new(); + HTTP_HDR_ENTRY *entry; + ACL_VSTRING *buf = acl_vstring_alloc(256); + + entry = http_hdr_entry_new("GET / HTTP/1.1"); + http_hdr_append_entry(&hdr_req->hdr, entry); + + entry = http_hdr_entry_new("HOST: www.test.com"); + http_hdr_append_entry(&hdr_req->hdr, entry); + + entry = http_hdr_entry_new("Cookie: utmcsr=cs.tv.test.com"); + http_hdr_append_entry(&hdr_req->hdr, entry); + + http_hdr_build(&hdr_req->hdr, buf); + http_hdr_print(&hdr_req->hdr, "---request hdr---"); + + http_hdr_entry_replace2(&hdr_req->hdr, "Cookie", "test.com", "test.com.cn", 1); + http_hdr_build(&hdr_req->hdr, buf); + http_hdr_print(&hdr_req->hdr, "---request hdr---"); + + acl_vstring_free(buf); + http_hdr_req_free(hdr_req); + exit (0); +} + +int main(int argc acl_unused, char *argv[] acl_unused) +{ + init(); + test(); + run(); + end(); + return (0); +} diff --git a/samples/http_probe/Makefile b/samples/http_probe/Makefile new file mode 100644 index 000000000..ae02d4719 --- /dev/null +++ b/samples/http_probe/Makefile @@ -0,0 +1,2 @@ +include ../Makefile_cpp.in +PROG = http_probe diff --git a/samples/http_probe/ReadMe.txt b/samples/http_probe/ReadMe.txt new file mode 100644 index 000000000..42a63718b --- /dev/null +++ b/samples/http_probe/ReadMe.txt @@ -0,0 +1,31 @@ +======================================================================== + 控制台应用程序 : http_probe 项目概况 +======================================================================== + +应用程序向导已为您创建了这个 http_probe 应用程序。 +此文件包含组成 http_probe 应用程序 +的每个文件的内容摘要。 + + +http_probe.vcproj + 这是用应用程序向导生成的 VC++ 项目的主项目文件。 + 它包含有关生成此文件的 Visual C++ 版本的信息,以及 + 有关用应用程序向导选择的 + 平台、配置和项目功能的信息。 + +http_probe.cpp + 这是主应用程序源文件。 + +///////////////////////////////////////////////////////////////////////////// +其他标准文件: + +StdAfx.h、StdAfx.cpp + 这些文件用于生成名为 http_probe.pch + 的预编译头(PCH)文件以及名为 StdAfx.obj 的预编译类型文件。 + +///////////////////////////////////////////////////////////////////////////// +其他注释: + +应用程序向导使用 "TODO:" 注释指示应添加或自定义的源代码部分。 + +///////////////////////////////////////////////////////////////////////////// diff --git a/samples/http_probe/bin/test.cf b/samples/http_probe/bin/test.cf new file mode 100644 index 000000000..753d951ae --- /dev/null +++ b/samples/http_probe/bin/test.cf @@ -0,0 +1,30 @@ + +service probe { + loglevel = 2 + logfile = probe.log + fork_sleep=0 + +#################################################################################################### + probed_server = + + probed_server = +#################################################################################################### +} diff --git a/samples/http_probe/http_probe.cpp b/samples/http_probe/http_probe.cpp new file mode 100644 index 000000000..a677dad15 --- /dev/null +++ b/samples/http_probe/http_probe.cpp @@ -0,0 +1,60 @@ +#include "lib_acl.h" +#include "lib_protocol.h" + +#include +#include +#include + +#include "probe.h" + +char *var_cfg_file = NULL; +char *var_probe_procname = NULL; + +static void init(void) +{ + acl_socket_init(); + probe_cfg_load(); + if (var_probe_logfile && *var_probe_logfile) + acl_msg_open(var_probe_logfile, var_probe_procname); + +/* daemon(1, 1); +*/ +} + +static void usage(const char *progname) +{ + printf("usage: %s [option]\n" + "\t-f configure_filename\n" + "\t-h help\n", + progname); + exit (1); +} + +int main(int argc, char *argv[]) +{ + char ch; + + var_probe_procname = acl_mystrdup(acl_safe_basename(argv[0])); + + while ((ch = getopt(argc, argv, "hf:")) > 0) { + switch (ch) { + case 'f': + var_cfg_file = acl_mystrdup(optarg); + break; + case 'h': + usage(argv[0]); + break; + default: + usage(argv[0]); + break; + } + } + + if (var_cfg_file == NULL) + var_cfg_file = acl_mystrdup("test.cf"); + init(); + probe_run(0, 0); + + exit (0); +} + diff --git a/samples/http_probe/http_probe.vcproj b/samples/http_probe/http_probe.vcproj new file mode 100644 index 000000000..4647f9bfc --- /dev/null +++ b/samples/http_probe/http_probe.vcproj @@ -0,0 +1,160 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/http_probe/probe.h b/samples/http_probe/probe.h new file mode 100644 index 000000000..279c6780b --- /dev/null +++ b/samples/http_probe/probe.h @@ -0,0 +1,126 @@ +#ifndef __PROBE_INCLUDE_H__ +#define __PROBE_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lib_acl.h" +#include "lib_protocol.h" + +/* 错误号 */ +#define PROBE_HTTP_STAT_MAX 599 +#define PROBE_HTTP_STAT_200 200 +#define PROBE_HTTP_STAT_404 404 +#define PROBE_HTTP_STAT_500 500 +#define PROBE_HTTP_STAT_503 503 +#define PROBE_HTTP_STAT_504 504 +#define PROBE_HTTP_STAT_505 505 + +#define PROBE_ERR_NONE 0 /* 无错误 */ +#define PROBE_ERR_CONN -1 /* 连接主机错误 */ +#define PROBE_ERR_HTTP -2 /* HTTP协议返回错误 */ +#define PROBE_ERR_URL -3 /* 所请求的URL返回错误 */ +#define PROBE_ERR_ARG -4 /* 输入参数错误 */ +#define PROBE_ERR_DSEARCH -5 /* 所查询的域结点不存在 */ +#define PROBE_ERR_HSEARCH -6 /* 所查询的主机结点不存在 */ +#define PROBE_ERR_HDEAD -7 /* 所查询的主机结点已经死掉 */ +#define PROBE_ERR_SOPEN -8 /* 打开流错误 */ +#define PROBE_ERR_WRITE -9 /* 写错误 */ +#define PROBE_ERR_READ -10 /* 读错误 */ +#define PROBE_ERR_TOO_MANY_ITEM -11 /* 头部回复行数太多 */ + +#define HOST_STATUS_ALIVE 0 /* 该主机处于存活状态 */ +#define HOST_STATUS_DEAD 1 /* 该主机已经死掉 */ + +#define HOST_FLAG_PROBE_FREE 0 /* 该主机未处于探测状态 */ +#define HOST_FLAG_PROBE_BUSY 1 /* 该主机已经处于探测状态了 */ + + +/* 常量定义 */ +#define HTTP_HEADER_MAX_SIZE 8192 +#define HTTP_HEADER_MAX_NUM 20 + + +typedef struct HTTP_HEADER_ITEM { + char *name; + char *value; +} HTTP_HEADER_ITEM; + +typedef struct PROBE_STAT { + time_t time_begin; + time_t time_end; + time_t time_cost; + char http_status[32]; + int error_num; +} PROBE_STAT; + +typedef struct PROBE_SERVER { + /* come from configure file */ + char *name; + char *addr; + char *url; + int connect_timeout; + int rw_timeout; + int retry_inter; + int probe_inter; + char *http_status_errors; + char *logfile; + int warn_time; + + ACL_VSTREAM *logfp; + + char http_request_header[HTTP_HEADER_MAX_SIZE]; + int http_request_len; + + time_t time_begin; + time_t time_end; + time_t time_total_cost; + + ACL_AIO *aio; + ACL_VSTREAM *stream; + HTTP_HDR_RES *hdr_res; + HTTP_RES *respond; +} PROBE_SERVER; + + +#define VAR_CFG_SERVER "probed_server" +#define VAR_CFG_SERVER_NAME "server_name" +#define VAR_CFG_SERVER_ADDR "addr" +#define VAR_CFG_SERVER_URL "url" +#define VAR_CFG_SERVER_CONNECT_TIMEOUT "connect_timeout" +#define VAR_CFG_SERVER_RW_TIMEOUT "rw_timeout" +#define VAR_CFG_SERVER_RETRY_INTER "retry_inter" +#define VAR_CFG_SERVER_PROBE_INTER "probe_inter" +#define VAR_CFG_SERVER_HTTP_ERRORS "http_errors" +#define VAR_CFG_SERVER_LOG "log" +#define VAR_CFG_SERVER_WARN_TIME "warn_time" + +#define VAR_CFG_LOGFILE "logfile" +#define VAR_CFG_LOGLEVEL "loglevel" +#define VAR_CFG_STATLEN "statlen" +#define VAR_CFG_FORK_SLEEP "fork_sleep" +#define VAR_CFG_DEBUG_FILE "debug_file" + +/* in probe_cfg.c */ +extern ACL_ARRAY *var_probe_server_link; +extern const char *var_probe_logfile; +extern int var_probe_loglevel; +extern int var_probe_statlen; +extern int var_probe_fork_sleep; +extern ACL_VSTREAM *var_probe_debug_fp; + +extern void probe_cfg_load(void); + +/* in probe_run.c */ +extern void probe_run(int max_threads, int idle_limit); + +/* in main.c */ +extern char *var_cfg_file; + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/samples/http_probe/probe_cfg.cpp b/samples/http_probe/probe_cfg.cpp new file mode 100644 index 000000000..35f76b1eb --- /dev/null +++ b/samples/http_probe/probe_cfg.cpp @@ -0,0 +1,369 @@ +#include "lib_acl.h" +#include "lib_protocol.h" + +#include +#include +#include + +#include "probe.h" + +ACL_ARRAY *var_probe_server_link = NULL; +const char *var_probe_logfile = NULL; +int var_probe_loglevel = 0; +int var_probe_statlen = 1024; +int var_probe_fork_sleep = 1; +ACL_VSTREAM *var_probe_debug_fp = NULL; + +static ACL_XINETD_CFG_PARSER *__cfg_parser = NULL; + +static char request_format[] = "\ +GET %s HTTP/1.1\r\n\ +Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*\r\n\ +Accept-Language: zh-cn\r\n\ +User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.1.4322)\r\n\ +Accept-Encoding: gzip, deflate\r\n\ +Host: %s:%d\r\n\r\n"; + +static int __parse_url(const char *url, + char *host_buf, + int hlen, + int *http_port, + char *url_buf, + int ulen) +{ + /* url format: http://www.hexun.com[:80]/index.html */ + char *ptr, *url_begin; + char buf[1024]; + size_t n; + + snprintf(buf, sizeof(buf) - 1, "%s", url); + ptr = buf; + while (*ptr == ' ' || *ptr == '\t') + ptr++; + + n = strlen("http://"); + + if (strncasecmp(ptr, "http://", n) == 0) { /* 标准的 http 协议请求格式 */ + ptr += n; + } else { /* 非标准的格式 */ + ; /* do nothing */ + } + + if (*ptr == 0) + return (-1); + + url_begin = ptr; + ptr = strchr(url_begin, '/'); + if (ptr) { + *ptr++ = 0; + if (*ptr == 0) + strcpy(url_buf, "/"); + else + snprintf(url_buf, ulen, "/%s", ptr); + } else { + strcpy(url_buf, "/"); + } + + /* 获得 http 协议端口号 */ + if (http_port) { + ptr = strchr(url_begin, ':'); + if (ptr) { + *ptr++ = 0; + n = atoi(ptr); + if (n <= 0) + *http_port = 80; + else + *http_port = (int) n; + } else + *http_port = 80; + } + + snprintf(host_buf, hlen, "%s", url_begin); + + return (0); +} + +static void __build_http_request(PROBE_SERVER *server) +{ + char myname[] = "__build_http_request"; + char host_refer[256], url_request[256]; + int port_refer = 80; + int ret; + + memset(host_refer, 0, sizeof(host_refer)); + memset(url_request, 0, sizeof(url_request)); + + ret = __parse_url(server->url, + host_refer, + sizeof(host_refer), + &port_refer, + url_request, + sizeof(url_request)); + if (ret < 0) + acl_msg_fatal("%s(%d)->%s: call __parse_url err, invalid url=[%s]", + __FILE__, __LINE__, myname, + server->url); + + snprintf(server->http_request_header, + sizeof(server->http_request_header) - 1, + request_format, + url_request, + host_refer, + port_refer); + + server->http_request_len = (int) strlen(server->http_request_header); +} + +static void __set_name_value(char *data, PROBE_SERVER *server) +{ +/* data: name=value */ + char myname[] = "__set_name_value"; + char *pname, *pvalue, *ptr; + + pname = data; + /* skip ' ' and '\t' */ + while (*pname == ' ' || *pname == '\t') + pname++; + if (pname == 0) { + acl_msg_error("%s(%d)->%s: invalid data=[%s]", + __FILE__, __LINE__, myname, data); + return; + } + + pvalue = pname; + /* find '=' */ + while (*pvalue) { + if (*pvalue == '=') { + *pvalue++ = 0; + break; + } + pvalue++; + } + + /* skip ' ' and '\t' */ + while (*pvalue == ' ' || *pvalue == '\t') + pvalue++; + if (pvalue == 0) { + acl_msg_error("%s(%d)->%s: invalid data=[%s]", + __FILE__, __LINE__, myname, data); + return; + } + + ptr = pvalue; + while (*ptr) { + if (*ptr == ' ' || *ptr == '\t' || *ptr == ',') { + *ptr = 0; + break; + } + ptr++; + } + + if (strcasecmp(pname, VAR_CFG_SERVER_NAME) == 0) + server->name = acl_mystrdup(pvalue); + else if (strcasecmp(pname, VAR_CFG_SERVER_ADDR) == 0) + server->addr = acl_mystrdup(pvalue); + else if (strcasecmp(pname, VAR_CFG_SERVER_URL) == 0) + server->url = acl_mystrdup(pvalue); + else if (strcasecmp(pname, VAR_CFG_SERVER_CONNECT_TIMEOUT) == 0) + server->connect_timeout = atoi(pvalue); + else if (strcasecmp(pname, VAR_CFG_SERVER_RW_TIMEOUT) == 0) + server->rw_timeout = atoi(pvalue); + else if (strcasecmp(pname, VAR_CFG_SERVER_RETRY_INTER) == 0) + server->retry_inter = atoi(pvalue); + else if (strcasecmp(pname, VAR_CFG_SERVER_PROBE_INTER) == 0) + server->probe_inter = atoi(pvalue); + else if (strcasecmp(pname, VAR_CFG_SERVER_HTTP_ERRORS) == 0) + server->http_status_errors = acl_mystrdup(pvalue); + else if (strcasecmp(pname, VAR_CFG_SERVER_LOG) == 0) + server->logfile = acl_mystrdup(pvalue); + else if (strcasecmp(pname, VAR_CFG_SERVER_WARN_TIME) == 0) + server->warn_time = atoi(pvalue); + + /* only for test */ + printf("name(%s)=value(%s), probe_inter=%d\n", pname, pvalue, server->probe_inter); +} + +static PROBE_SERVER *__cfg_server_new(char *data) +{ +/* + * data: server_name="博客2", addr=10.0.90.246:80, url=http://blog.hexun.com/index.aspx, connect_timeout=60, rw_timeout=60, retry_inter=5, probe_inter=5 + */ + char myname[] = "__cfg_server_new"; + PROBE_SERVER *server = NULL; + char *ptr; + + if (data == NULL || *data == 0) { + acl_msg_error("%s: invalid data input", myname); + return (NULL); + } + + server = (PROBE_SERVER *) acl_mycalloc(1, sizeof(PROBE_SERVER)); + if (server == NULL) + acl_msg_fatal("%s: can't calloc, serr=%s", myname, strerror(errno)); + + while (1) { + ptr = acl_mystrtok(&data, ","); + if (ptr == NULL) + break; + + __set_name_value(ptr, server); + } + + __build_http_request(server); + if (server->logfile != NULL) { + server->logfp = acl_vstream_fopen(server->logfile, + O_WRONLY | O_CREAT | O_APPEND, + 0600, 4096); + if (server->logfp == NULL) + acl_msg_fatal("%s: can't open logfile(%s)", + myname, server->logfile, strerror(errno)); + } else + server->logfp = NULL; + + return (server); +} + +static void __cfg_parse_one_server(const char *server_data) +{ + char myname[] = "__cfg_parse_one_server"; + char *buf = NULL; + char *begin, *end; + PROBE_SERVER *server; + +#undef RETURN +#define RETURN do { \ + if (buf) \ + acl_myfree(buf); \ + return; \ +} while(0) + + if (server_data == NULL || *server_data == 0) + acl_msg_fatal("%s(%d)->%s: input invalid", + __FILE__, __LINE__, myname); + + buf = acl_mystrdup(server_data); + + begin = buf; + while (*begin) { + if (*begin == '<') { + *begin++ = 0; + break; + } + begin++; + } + + if (*begin == 0) + RETURN; + end = begin; + while (*end) { + if (*end == '>') { + *end = 0; + break; + } + end++; + } + + server = __cfg_server_new(begin); + if (server != NULL) { + if (acl_array_append(var_probe_server_link, (void *) server) < 0) + acl_msg_fatal("%s(%d)->%s: acl_array_append err=%s", + __FILE__, __LINE__, myname, strerror(errno)); + } else + acl_msg_fatal("%s(%d)->%s: invalid data=[%s]", + __FILE__, __LINE__, myname, + server_data); + + acl_msg_info("%s(%d)->%s: name=%s, addr=%s, url=%s, connect_timeout=%d," + " rw_timeout=%d, retry_inter=%d, probe_inter=%d\n", + __FILE__, __LINE__, myname, + server->name, + server->addr, + server->url, + server->connect_timeout, + server->rw_timeout, + server->retry_inter, + server->probe_inter); + + RETURN; +} + +static void __cfg_server_parse(const ACL_ARRAY *a) +{ + int i, n; + + if (a == NULL) + return; + + n = acl_array_size(a); + +#if 0 + for (i = 0; i < n; i++) + acl_msg_info("%s: %s", VAR_CFG_SERVER, (const char *) acl_array_index(a, i)); +#endif + + for (i = 0; i < n; i++) + __cfg_parse_one_server((const char *) acl_array_index(a, i)); +} + +void probe_cfg_load(void) +{ + char myname[] = "probe_cfg_load"; + ACL_XINETD_CFG_PARSER *xcp; + const ACL_ARRAY *servers_array; + const char *ptr; + + if (var_cfg_file == NULL || *var_cfg_file == 0) + acl_msg_fatal("%s(%d)->%s: __cfg_file null", + __FILE__, __LINE__, myname); + + xcp = acl_xinetd_cfg_load(var_cfg_file); + if (xcp == NULL) { + acl_msg_error("%s(%d)->%s: xinetd_cfg_load return null, file=%s", + __FILE__, __LINE__, myname, var_cfg_file); + exit (1); + } + __cfg_parser = xcp; + + var_probe_server_link = acl_array_create(50); + if (var_probe_server_link == NULL) + acl_msg_fatal("%s(%d)->%s: acl_array_create error, serr=%s", + __FILE__, __LINE__, myname, + strerror(errno)); + + servers_array = acl_xinetd_cfg_get_ex(xcp, VAR_CFG_SERVER); + if (servers_array == NULL) + acl_msg_fatal("%s(%d)->%s: not fine %s line", + __FILE__, __LINE__, myname, VAR_CFG_SERVER); + + __cfg_server_parse(servers_array); + + var_probe_logfile = acl_xinetd_cfg_get(xcp, VAR_CFG_LOGFILE); + if (var_probe_logfile == NULL || *var_probe_logfile == 0) + acl_msg_warn("%s(%d)->%s: null var_probe_logfile", + __FILE__, __LINE__, myname); + ptr = acl_xinetd_cfg_get(xcp, VAR_CFG_LOGLEVEL); + if (ptr && *ptr) + var_probe_loglevel = atoi(ptr); + if (var_probe_loglevel < 0) + var_probe_loglevel = 0; + ptr = acl_xinetd_cfg_get(xcp, VAR_CFG_STATLEN); + if (ptr && *ptr) + var_probe_statlen = atoi(ptr); + if (var_probe_statlen <= 0) + var_probe_statlen = 1024; + + ptr = acl_xinetd_cfg_get(xcp, VAR_CFG_FORK_SLEEP); + if (ptr && *ptr) + var_probe_fork_sleep = atoi(ptr); + if (var_probe_fork_sleep < 0) + var_probe_fork_sleep = 1; + + ptr = acl_xinetd_cfg_get(xcp, VAR_CFG_DEBUG_FILE); + if (ptr && *ptr) + var_probe_debug_fp = acl_vstream_fopen(ptr, + O_WRONLY | O_CREAT | O_APPEND, + 0600, 4096); + else + var_probe_debug_fp = NULL; +} + diff --git a/samples/http_probe/probe_run.cpp b/samples/http_probe/probe_run.cpp new file mode 100644 index 000000000..d132193bb --- /dev/null +++ b/samples/http_probe/probe_run.cpp @@ -0,0 +1,296 @@ +#include "lib_acl.h" +#include "lib_protocol.h" + +#include +#include +#include +#include + +#include "probe.h" + +/* forward declare */ +static void timer_fn(int event_type, void *context); + +static void timer_retry(ACL_AIO *aio, PROBE_SERVER *server) +{ + if (server->stream != NULL) { + acl_vstream_close(server->stream); + server->stream = NULL; + } + + if (server->respond != NULL) { + http_res_free(server->respond); + server->respond = NULL; + server->hdr_res = NULL; + } else if (server->hdr_res != NULL) { + http_hdr_res_free(server->hdr_res); + server->hdr_res = NULL; + } + + (void) acl_aio_request_timer(aio, timer_fn, (void *) server, server->probe_inter); +} + +static void msg_info(PROBE_SERVER *server, const char *fmt, ...) +{ + const char *myname = "msg_info"; + va_list ap; + static char buf[4096]; + + if (server == NULL) + acl_msg_fatal("%s: server null", myname); + if (fmt == NULL) + acl_msg_fatal("%s: fmt null", myname); + + va_start(ap, fmt); + acl_vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + + server->time_end = time(NULL); + server->time_total_cost = server->time_end - server->time_begin; + + if (server->logfp != NULL) { + char fmtstr[128]; + + acl_logtime_fmt(fmtstr, sizeof(fmtstr)); + acl_vstream_fprintf(server->logfp, + "%s: <%s> addr(%s), url(%s), time(%ld), content_length(%d), reply_status(%d), %s\n", + fmtstr, + (server->warn_time > 0 && server->time_total_cost >= server->warn_time) ? "WARN" : "INFO", + server->addr, server->url, server->time_total_cost, + server->hdr_res->hdr.chunked ? -1 : server->hdr_res->hdr.content_length, + server->hdr_res->reply_status, buf); + } else + acl_msg_info("<%s> addr(%s), url(%s), time(%ld), content_length(%d), reply_status(%d), %s", + (server->warn_time > 0 && server->time_total_cost >= server->warn_time) ? "WARN" : "INFO", + server->addr, server->url, server->time_total_cost, + server->hdr_res->hdr.chunked ? -1 : server->hdr_res->hdr.content_length, + server->hdr_res->reply_status, buf); +} + +static void msg_error(PROBE_SERVER *server, const char *fmt, ...) +{ + const char *myname = "msg_error"; + va_list ap; + static char buf[4096]; + + if (server == NULL) + acl_msg_fatal("%s: server null", myname); + if (fmt == NULL) + acl_msg_fatal("%s: fmt null", myname); + + va_start(ap, fmt); + acl_vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + + server->time_end = time(NULL); + server->time_total_cost = server->time_end - server->time_begin; + + if (server->logfp != NULL) { + char fmtstr[128]; + + acl_logtime_fmt(fmtstr, sizeof(fmtstr)); + acl_vstream_fprintf(server->logfp, + "%s, %s: <%s> addr(%s), url(%s), time(%ld), %s\n", + myname, fmtstr, + (server->warn_time > 0 && server->time_total_cost >= server->warn_time) ? "WARN" : "INFO", + server->addr, server->url, server->time_total_cost, buf); + } else + acl_msg_error("%s <%s> addr(%s), url(%s), time(%ld), %s", + myname, + (server->warn_time > 0 && server->time_total_cost >= server->warn_time) ? "WARN" : "INFO", + server->addr, server->url, server->time_total_cost, buf); +} + +static int get_body_ready(int status, const char *data, int dlen, void *arg) +{ + const char *myname = "get_body_ready"; + PROBE_SERVER *server = (PROBE_SERVER *) arg; + ACL_AIO *aio = server->aio; + +#if 0 + if (var_probe_debug_fp && status !=HTTP_STATUS_OK && dlen > 0) { + acl_vstream_writen(var_probe_debug_fp, data, dlen); + } +#else + data = data; + dlen = dlen; + + acl_msg_info("%s: len(%d), status=%d", myname, dlen, status); +#endif + + if (status == HTTP_CHAT_OK) { + msg_info(server, "%s(%d), get body over, body_len(%d)", + myname, __LINE__, dlen); + timer_retry(aio, server); + } else if (status >= HTTP_CHAT_ERR_IO) { + msg_error(server, "%s(%d), get body error(io), status(%d)", + myname, __LINE__, status); + timer_retry(aio, server); + return (-1); + } + + return (0); +} + +static void get_header_ready(int status, void *arg) +{ + const char *myname = "get_header_ready"; + PROBE_SERVER *server = (PROBE_SERVER *) arg; + ACL_AIO *aio = server->aio; + char buf[256]; + + if (status != HTTP_CHAT_OK) { + msg_error(server, "%s(%d), get header error", myname, __LINE__); + timer_retry(aio, server); + return; + } + + if (http_hdr_res_parse(server->hdr_res) < 0) { + msg_error(server, "%s(%d), parse hdr error", myname, __LINE__); + timer_retry(aio, server); + return; + } + + snprintf(buf, sizeof(buf), "%d", server->hdr_res->reply_status); + if (strstr(server->http_status_errors, buf) != NULL) { + msg_error(server, "%s(%d), reply status(%s) error", myname, __LINE__, buf); + if (var_probe_debug_fp) + http_hdr_fprint(var_probe_debug_fp, &server->hdr_res->hdr, myname); + timer_retry(aio, server); + return; + } + + if (server->hdr_res->hdr.content_length == 0) { + msg_info(server, "%s(%d), get hdr over", myname, __LINE__); + if (var_probe_debug_fp) + http_hdr_fprint(var_probe_debug_fp, &server->hdr_res->hdr, myname); + timer_retry(aio, server); + } else { + if (var_probe_debug_fp) + http_hdr_fprint(var_probe_debug_fp, &server->hdr_res->hdr, myname); + + server->respond = http_res_new(server->hdr_res); + http_res_body_get_ready(server->respond, + aio, + server->stream, + server->rw_timeout, + get_body_ready, + server); + } +} + +static void write_notify_fn(int event_type, + ACL_AIO *aio, + ACL_VSTREAM *stream, + void *context, + const char *data, + int dlen) +{ + const char *myname = "write_notify_fn"; + PROBE_SERVER *server = (PROBE_SERVER *) context; + + assert(stream == server->stream); + data = data; + dlen = dlen; + + if (event_type == ACL_EVENT_XCPT) { + msg_error(server, "%s(%d), write error(%s)", + myname, __LINE__, strerror(errno)); + timer_retry(aio, server); + return; + } else if (event_type == ACL_EVENT_RW_TIMEOUT) { + msg_error(server, "%s(%d), write timeout", myname, __LINE__); + timer_retry(aio, server); + return; + } + + server->hdr_res = http_hdr_res_new(); + http_hdr_res_get_ready(server->hdr_res, + aio, + server->stream, + server->rw_timeout, + get_header_ready, + server); +} + +static void connect_notify_fn(int event_type, + ACL_AIO *aio, + ACL_VSTREAM *stream, + void *context) +{ + const char *myname = "connect_notify_fn"; + PROBE_SERVER *server = (PROBE_SERVER *) context; + int ret; + + if (event_type == ACL_EVENT_XCPT) { + msg_error(server, "%s(%d), connect error(%s)", + myname, __LINE__, strerror(errno)); + timer_retry(aio, server); + return; + } else if (event_type == ACL_EVENT_RW_TIMEOUT) { + msg_error(server, "%s(%d), connect timeout", myname, __LINE__); + timer_retry(aio, server); + return; + } + + server->stream = stream; + + ret = acl_aio_writen(aio, + stream, + server->rw_timeout, + server->http_request_header, + server->http_request_len, + write_notify_fn, + server); + if (ret < 0) { + msg_error(server, "%s(%d), write error(%s)", + myname, __LINE__, strerror(errno)); + timer_retry(aio, server); + return; + } +} + +static void timer_fn(int event_type, void *context) +{ + const char *myname = "timer_fn"; + PROBE_SERVER *server = (PROBE_SERVER *) context; + ACL_AIO *aio = server->aio; + int ret; + + event_type = event_type; + + server->time_begin = time(NULL); + + ret = acl_aio_connect(aio, server->addr, server->connect_timeout, + connect_notify_fn, server); + if (ret < 0) { + msg_error(server, "%s(%d), connect error(%s)", + myname, __LINE__, strerror(errno)); + timer_retry(aio, server); + } +} + +void probe_run(int max_threads, int idle_limit) +{ + const char *myname = "run_init"; + PROBE_SERVER *server; + ACL_AIO *aio; + int i; + + aio = acl_aio_create(max_threads, idle_limit); + if (aio == NULL) + acl_msg_fatal("%s: create aio error", myname); + + if (var_probe_server_link == NULL) + acl_msg_fatal("%s(%d): var_probe_server_link null", myname, __LINE__); + + for (i = 0; i < acl_array_size(var_probe_server_link); i++) { + server = (PROBE_SERVER *) acl_array_index(var_probe_server_link, i); + server->aio = aio; + timer_retry(aio, server); + } + + while (1) { + acl_aio_loop(aio); + } +} diff --git a/samples/http_probe/stdafx.cpp b/samples/http_probe/stdafx.cpp new file mode 100644 index 000000000..c8eef373f --- /dev/null +++ b/samples/http_probe/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// http_probe.pch 将成为预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + +// TODO: 在 STDAFX.H 中 +//引用任何所需的附加头文件,而不是在此文件中引用 diff --git a/samples/http_probe/stdafx.h b/samples/http_probe/stdafx.h new file mode 100644 index 000000000..ff452917c --- /dev/null +++ b/samples/http_probe/stdafx.h @@ -0,0 +1,11 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是常用但不常更改的项目特定的包含文件 +// + +#pragma once + + +#include +#include + +// TODO: 在此处引用程序要求的附加头文件 diff --git a/samples/http_probe/test.cf b/samples/http_probe/test.cf new file mode 100644 index 000000000..753d951ae --- /dev/null +++ b/samples/http_probe/test.cf @@ -0,0 +1,30 @@ + +service probe { + loglevel = 2 + logfile = probe.log + fork_sleep=0 + +#################################################################################################### + probed_server = + + probed_server = +#################################################################################################### +} diff --git a/samples/httpd/Makefile b/samples/httpd/Makefile new file mode 100644 index 000000000..2dfbe0a9d --- /dev/null +++ b/samples/httpd/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = httpd diff --git a/samples/httpd/main.c b/samples/httpd/main.c new file mode 100644 index 000000000..6035c0c81 --- /dev/null +++ b/samples/httpd/main.c @@ -0,0 +1,303 @@ +#include "lib_acl.h" +#include "lib_protocol.h" +#include +#include + +typedef struct { + ACL_VSTREAM *stream; + int flag; +#define FLAG_CLOSE 1 +} CONN; + +static void init(void) +{ + acl_init(); +} + +static void end(void) +{ + acl_end(); +} + +static void thread_run(void *arg) +{ + CONN *conn = (CONN*) arg; + ACL_VSTREAM *client = conn->stream; + const char *reply_200 = "HTTP/1.1 200 OK\r\n" + "Server: nginx/0.6.32\r\n" + "Date: Tue, 29 Dec 2009 02:18:25 GMT\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 43\r\n" + "Last-Modified: Mon, 16 Nov 2009 02:18:14 GMT\r\n" + "Connection: keep-alive\r\n" + "Accept-Ranges: bytes\r\n\r\n" + "\n" + "\n" + "hello world!\n" + "\n" + "\n"; + int ret, keep_alive; + char buf[4096]; + + while (0) { + ret = read(ACL_VSTREAM_SOCK(client), buf, sizeof(buf)); + if (ret == ACL_VSTREAM_EOF) + break; + ret = acl_vstream_writen(client, reply_200, strlen(reply_200)); + if (ret == ACL_VSTREAM_EOF) + break; + } + + while (0) { + ret = acl_vstream_read(client, buf, sizeof(buf)); + if (ret == ACL_VSTREAM_EOF) + break; + ret = acl_vstream_writen(client, reply_200, strlen(reply_200)); + if (ret == ACL_VSTREAM_EOF) + break; + } + + while (0) { + /* + HTTP_REQ *req; + */ + HTTP_HDR_REQ *hdr_req = http_hdr_req_new(); + + ret = http_hdr_req_get_sync(hdr_req, client, 300); + if (ret < 0) { + http_hdr_req_free(hdr_req); + break; + } + if (http_hdr_req_parse(hdr_req) < 0) { + http_hdr_req_free(hdr_req); + printf("parse error\n"); + break; + } + + /* + keep_alive = hdr_req->hdr.keep_alive; + + if (hdr_req->hdr.content_length > 0) { + req = http_req_new(hdr_req); + ret = (int) http_req_body_get_sync(req, client, buf, sizeof(buf)); + if (ret < 0) { + http_req_free(req); + break; + } + http_req_free(req); + } else { + http_hdr_req_free(hdr_req); + } + */ + + http_hdr_req_free(hdr_req); + ret = acl_vstream_writen(client, reply_200, strlen(reply_200)); + if (ret == ACL_VSTREAM_EOF) { + break; + } + /* + if (!keep_alive) + break; + */ + } + + while (1) { + HTTP_REQ *req; + HTTP_HDR_REQ *hdr_req = http_hdr_req_new(); + + ret = http_hdr_req_get_sync(hdr_req, client, 0); + if (ret < 0) { + http_hdr_req_free(hdr_req); + break; + } + if (http_hdr_req_parse(hdr_req) < 0) { + http_hdr_req_free(hdr_req); + printf("parse error\n"); + break; + } + + keep_alive = hdr_req->hdr.keep_alive; + + if (hdr_req->hdr.content_length > 0) { + req = http_req_new(hdr_req); + ret = (int) http_req_body_get_sync(req, client, buf, sizeof(buf)); + if (ret < 0) { + http_req_free(req); + break; + } + http_req_free(req); + } else { + http_hdr_req_free(hdr_req); + } + + ret = acl_vstream_writen(client, reply_200, strlen(reply_200)); + if (ret == ACL_VSTREAM_EOF) { + break; + } + if (!keep_alive) + break; + } + + acl_vstream_close(client); + acl_myfree(conn); + printf("thread(%ld) exit\n", (long) acl_pthread_self()); +} + +static void *thread_main(void* arg) +{ + thread_run(arg); + return (NULL); +} + +static void run_server(const char *addr) +{ + ACL_VSTREAM *sstream = acl_vstream_listen(addr, 128); + acl_pthread_pool_t *pool; + CONN *conn; + acl_pthread_t tid; + acl_pthread_attr_t attr; + ACL_VSTREAM *client; + + if (sstream == NULL) { + acl_msg_error("listen %s error(%s)", addr, acl_last_serror()); + return; + } + + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + + printf("listening on %s ...\n", addr); + pool = acl_thread_pool_create(10, 10); + while (1) { + acl_mem_slice_delay_destroy(); + if (acl_read_wait(ACL_VSTREAM_SOCK(sstream), 5) == -1) + continue; + client = acl_vstream_accept(sstream, NULL, 0); + if (client == NULL) { + acl_msg_error("accept error(%s)", acl_last_serror()); + break; + } + acl_tcp_set_nodelay(ACL_VSTREAM_SOCK(client)); + conn = acl_mycalloc(1, sizeof(CONN)); + conn->stream = client; + + if (0) + thread_run(conn); + else if (1) + acl_pthread_create(&tid, &attr, thread_main, conn); + else + acl_pthread_pool_add(pool, thread_run, conn); + } + + acl_vstream_close(sstream); +} + +static void run_client(const char *addr, const char *filename) +{ + char *request = acl_vstream_loadfile(filename); + ACL_VSTREAM *client; + int ret; + char buf[1024]; + + if (request == NULL) { + printf("load file(%s) error(%s)\n", filename, acl_last_serror()); + return; + } + + client = acl_vstream_connect(addr, ACL_BLOCKING, + 0, 0, 4096); + if (client == NULL) { + printf("connect addr(%s) error(%s)\n", addr, acl_last_serror()); + acl_myfree(request); + return; + } + + acl_tcp_set_sndbuf(ACL_VSTREAM_SOCK(client), 10); + if (acl_vstream_writen(client, request, strlen(request)) == ACL_VSTREAM_EOF) { + printf("write to addr(%s) error(%s)\n", addr, acl_last_serror()); + acl_vstream_close(client); + acl_myfree(request); + return; + } + + memset(buf, 0, sizeof(buf)); + + while (1) { + ret = acl_vstream_read(client, buf, sizeof(buf) - 1); + if (ret == ACL_VSTREAM_EOF) + break; + buf[ret] = 0; + usleep(100000); + printf(">>>%s\n", buf); + } + + printf(">>>last data(%s)\n", buf); + acl_vstream_close(client); + acl_myfree(request); +} + +static void usage(const char *procname) +{ + printf("usage: %s -h [help] -s listen_addr[IP:PORT] -c request_hdr\n", procname); +} + +static void *thread_test(void *arg acl_unused) +{ + char *p = acl_mymalloc(1000); + acl_myfree(p); + printf("call slice destroy\n"); + acl_mem_slice_destroy(); + return (NULL); +} + +static void test(void) +{ + acl_pthread_t tid; + acl_pthread_attr_t attr; + + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + acl_pthread_create(&tid, &attr, thread_test, 0); + while (1) { + sleep(1); + } +} + +int main(int argc, char *argv[]) +{ + char addr[256] = "0.0.0.0:80", filename[256]; + int ch, client_mode = 0; + +#if 1 + acl_mem_slice_init(8, 10240, 100000, ACL_SLICE_FLAG_GC2 | ACL_SLICE_FLAG_RTGC_OFF | ACL_SLICE_FLAG_LP64_ALIGN); + http_hdr_cache(100); +#endif + + while ((ch = getopt(argc, argv, "hs:c:")) > 0) { + switch (ch) { + case 'h': + usage(argv[0]); + exit (0); + case 's': + ACL_SAFE_STRNCPY(addr, optarg, sizeof(addr)); + break; + case 'c': + client_mode = 1; + ACL_SAFE_STRNCPY(filename, optarg, sizeof(filename)); + break; + default: + break; + } + } + + if (0) + test(); + + init(); + if (client_mode) + run_client(addr, filename); + else + run_server(addr); + end(); + return (0); +} diff --git a/samples/httpd/request.txt b/samples/httpd/request.txt new file mode 100644 index 000000000..003ddfa4e --- /dev/null +++ b/samples/httpd/request.txt @@ -0,0 +1,12 @@ +GET http://wmail2.mail.hexun.com/cgi-bin/main/login/1262918837 HTTP/1.1 +Host: wmail2.mail.hexun.com +User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; zh-CN; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 +Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 +Accept-Language: zh-cn,zh;q=0.7,en-us;q=0.3 +Accept-Encoding: gzip,deflate +Accept-Charset: GB2312,utf-8;q=0.7,*;q=0.7 +Keep-Alive: 300 +Proxy-Connection: keep-alive +Referer: http://wmail2.mail.hexun.com/cgi-bin/console/login/1262918836 +Cookie: __utma=27823648.422177696.1262914215.1262916847.1262917901.5; __utmb=27823648;__utmz=27823648.1262914215.1.1.utmccn=(direct)|utmcsr=(direct)|utmcmd=(none); HexunTrack=SID=217163494; hxck_sq_common=LoginStateCookie=md88aDazrp2KwrggnhhMQg%3d%3d&SnapCookie=bonerpMfA2LT9XEbMpY%2fnGYce2%2ffrrRRQHBRqeVvsqs%3d; ys-readmsg-layout-state=o%3Anorth%3Do%253Asize%253Dn%25253A60%5Esouth%3Do%253A%5Eeast%3Do%253A%5Ewest%3Do%253A; __utma=194262068.481558226.1262917014.1262917014.1262917014.1; __utmb=194262068.2.10.1262917014; __utmz=194262068.1262917014.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); __utmc=27823648; userToken=3497499%7c0000%7c0%2cVO50ruL1k6bDxL7WkEqYWUstiyZHXAssMFwHmZbnBsSIY8%2bicqVhh7jy%2bRphjFQrBMa9YBCyyiqim8jYiLoVrxgCiGv%2fsnKzbwZSwa6v3N2N93qSsoJIG7%2f%2bprVJNnVtqdD%2bow0Rqx3tnrD6cl1gQg%3d%3d; MailUserName=whousegodwithme; wmail_login=1; pop_alive=0 + diff --git a/samples/ifconf/Makefile b/samples/ifconf/Makefile new file mode 100644 index 000000000..bdda59618 --- /dev/null +++ b/samples/ifconf/Makefile @@ -0,0 +1,2 @@ +include ../Makefile_cpp.in +PROG = ifconf diff --git a/samples/ifconf/main.cpp b/samples/ifconf/main.cpp new file mode 100644 index 000000000..5c5d0b97b --- /dev/null +++ b/samples/ifconf/main.cpp @@ -0,0 +1,38 @@ +#include "lib_acl.h" + +int main(void) +{ + ACL_IFCONF *ifconf; + ACL_IFADDR *ifaddr; + ACL_ITER iter; + char *host_ip = NULL; + + acl_msg_stdout_enable(1); + ifconf = acl_get_ifaddrs(); + + if (ifconf == NULL) { + printf("acl_get_ifaddrs error: %s\r\n", acl_last_serror()); + return (1); + } + + acl_foreach(iter, ifconf) { + ifaddr = (ACL_IFADDR*) iter.data; + + if (strcmp(ifaddr->ip, "127.0.0.1") == 0) + continue; + + acl_msg_info(">>>ip: %s", ifaddr->ip); + /* 外网IP优先 */ + if (strncmp(ifaddr->ip, "10.", 3) != 0 + && strncmp(ifaddr->ip, "192.", 4) != 0) + { + host_ip = acl_mystrdup(ifaddr->ip); + } else if (host_ip == NULL) { + host_ip = acl_mystrdup(ifaddr->ip); + } + } + + if (host_ip) + printf(">>host_ip: %s\n", host_ip); + return (0); +} diff --git a/samples/iplink/Makefile b/samples/iplink/Makefile new file mode 100644 index 000000000..6dcb0112a --- /dev/null +++ b/samples/iplink/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = iplink diff --git a/samples/iplink/main.c b/samples/iplink/main.c new file mode 100644 index 000000000..81c038a8f --- /dev/null +++ b/samples/iplink/main.c @@ -0,0 +1,34 @@ +#include "lib_acl.h" + +int main(void) +{ + ACL_IPLINK *lnk = acl_iplink_create(10); + const char *ip1_from = "127.0.0.1", *ip1_to = "127.0.0.1"; + const char *ip2_from = "10.0.250.218", *ip2_to = "10.0.250.218"; + const char *ip3_from = "10.0.250.38", *ip3_to = "10.0.250.38"; + + acl_iplink_insert(lnk, ip1_from, ip1_to); + printf("add from: %s to: %s\r\n", ip1_from, ip1_to); + acl_iplink_insert(lnk, ip2_from, ip2_to); + printf("add from: %s to: %s\r\n", ip2_from, ip2_to); + acl_iplink_insert(lnk, ip3_from, ip3_to); + printf("add from: %s to: %s\r\n", ip3_from, ip3_to); + + printf("==================================================\r\n"); + + acl_iplink_list(lnk); + + printf("==================================================\r\n"); + + acl_dlink_list(lnk); + + printf("==================================================\r\n"); + + if (acl_iplink_lookup_str(lnk, ip1_from) == NULL) + printf("ip: %s not included!\r\n", ip1_from); + else + printf("ip: %s included!\r\n", ip1_from); + + acl_iplink_free(lnk); + return 0; +} diff --git a/samples/iterator/Makefile b/samples/iterator/Makefile new file mode 100644 index 000000000..bff871824 --- /dev/null +++ b/samples/iterator/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = iterator diff --git a/samples/iterator/iterator.vcproj b/samples/iterator/iterator.vcproj new file mode 100644 index 000000000..c9abc62cd --- /dev/null +++ b/samples/iterator/iterator.vcproj @@ -0,0 +1,234 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/iterator/iterator.vcxproj b/samples/iterator/iterator.vcxproj new file mode 100644 index 000000000..eba174352 --- /dev/null +++ b/samples/iterator/iterator.vcxproj @@ -0,0 +1,181 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + ReleaseDll + Win32 + + + Release + Win32 + + + + {84DE3D12-2BF6-46C1-BE20-9F9F6E7708B2} + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + ws2_32.lib;Iphlpapi.lib;%(AdditionalDependencies) + $(OutDir)iterator.exe + true + $(OutDir)iterator.pdb + Console + MachineX86 + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + ws2_32.lib;Iphlpapi.lib;%(AdditionalDependencies) + $(OutDir)iterator.exe + true + Console + true + true + MachineX86 + + + + + Disabled + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + EditAndContinue + + + ws2_32.lib;Iphlpapi.lib;%(AdditionalDependencies) + $(OutDir)iterator.exe + true + $(OutDir)iterator.pdb + Console + MachineX86 + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + ws2_32.lib;Iphlpapi.lib;%(AdditionalDependencies) + $(OutDir)iterator.exe + true + Console + true + true + MachineX86 + + + + + {b40213c2-507c-4c7f-a6e1-b850c9bdc27b} + false + + + + + + + + + \ No newline at end of file diff --git a/samples/iterator/log.txt b/samples/iterator/log.txt new file mode 100644 index 000000000..5dd05fa39 --- /dev/null +++ b/samples/iterator/log.txt @@ -0,0 +1,3 @@ +begin set mem_hook +acl_debug_dump(222): begin scan memory alloc and free +acl_debug_dump(227): scan memory finish diff --git a/samples/iterator/main.c b/samples/iterator/main.c new file mode 100644 index 000000000..1ed9f2976 --- /dev/null +++ b/samples/iterator/main.c @@ -0,0 +1,567 @@ +#include "lib_acl.h" +#include +#include +#include + +#ifdef WIN32 +#define snprintf _snprintf +#endif + +static void binhash_iter(void) +{ + ACL_BINHASH *table = acl_binhash_create(10, 0); + ACL_BINHASH_ITER iter; + char key[32], *value; + int i; + + for (i = 0; i < 10; i++) { + snprintf(key, sizeof(key), "key: %d", i); + value = acl_mymalloc(32); + snprintf(value, 32, "value: %d", i); + assert(acl_binhash_enter(table, key, (int) strlen(key) + 1, value)); + } + + i = 0; + printf("\n>>>acl_binhash_foreach:\n"); + acl_binhash_foreach(iter, table) { + printf("hash i=%d, [%s]=[%s]\n", + iter.i, (const char*) acl_binhash_iter_key(iter), + (char*) acl_binhash_iter_value(iter)); + i++; + } + + printf(">>>total: %d\n", i); + + i = 0; + printf("\n>>>acl_binhash_foreach and break:\n"); + acl_binhash_foreach(iter, table) { + printf("hash i=%d, [%s]=[%s]\n", + iter.i, (const char*) acl_binhash_iter_key(iter), + (char*) acl_binhash_iter_value(iter)); + i++; + if (i == 5) { + printf("i = %d, break now\n", i); + break; + } + } + + printf("\n>>>acl_binhash_foreach_reverse:\n"); + acl_binhash_foreach_reverse(iter, table) { + printf("hash i=%d, [%s]=[%s]\n", + iter.i, (const char*) acl_binhash_iter_key(iter), + (char*) acl_binhash_iter_value(iter)); + i++; + } + + acl_binhash_free(table, acl_myfree_fn); +} + +static void htable_iter(void) +{ + ACL_SLICE_POOL *slice = acl_slice_pool_create(10, 100, + ACL_SLICE_FLAG_GC2 | ACL_SLICE_FLAG_RTGC_OFF); + ACL_HTABLE *table = acl_htable_create3(10, 0, slice); + ACL_HTABLE_ITER iter; + char key[32], *value; + int i; + + for (i = 0; i < 20; i++) { + snprintf(key, sizeof(key), "key: %d", i); + value = acl_mymalloc(32); + snprintf(value, 32, "value: %d", i); + assert(acl_htable_enter(table, key, value)); + } + + i = 0; + printf("\n>>>acl_htable_foreach:\n"); + acl_htable_foreach(iter, table) { + printf("hash i=%d, [%s]=[%s]\n", + iter.i, acl_htable_iter_key(iter), + (char*) acl_htable_iter_value(iter)); + i++; + } + + printf(">>>total: %d\n", i); + + i = 0; + acl_htable_foreach(iter, table) { + printf("hash i=%d, [%s]=[%s]\n", + iter.i, acl_htable_iter_key(iter), + (char*) acl_htable_iter_value(iter)); + i++; + if (i == 5) { + printf("i = %d, break now\n", i); + break; + } + } + + + i = 0; + printf("\n>>>acl_htable_foreach_reverse:\n"); + acl_htable_foreach_reverse(iter, table) { + printf("hash i=%d, [%s]=[%s]\n", + iter.i, acl_htable_iter_key(iter), + (char*) acl_htable_iter_value(iter)); + i++; + } + + printf(">>>total: %d\n", i); + + acl_htable_stat(table); + acl_htable_free(table, acl_myfree_fn); + acl_slice_pool_destroy(slice); +} + +static void htable_iter2(void) +{ + ACL_HTABLE *table = acl_htable_create(10, 0); + ACL_ITER iter; + char key[32], *value; + int i; + + for (i = 0; i < 20; i++) { + snprintf(key, sizeof(key), "key: %d", i); + value = acl_mymalloc(32); + snprintf(value, 32, "value: %d", i); + assert(acl_htable_enter(table, key, value)); + } + + i = 0; + printf("\n>>>acl_foreach for htable:\n"); + acl_foreach(iter, table) { + printf("hash i=%d, [%s]\n", iter.i, (char*) iter.data); + i++; + } + + printf(">>>total: %d\n", i); + + i = 0; + printf("\n>>>acl_foreach_reverse for htable:\n"); + acl_foreach_reverse(iter, table) { + printf("hash i=%d, [%s]\n", iter.i, (char*) iter.data); + i++; + } + + printf(">>>total: %d\n", i); + acl_htable_free(table, acl_myfree_fn); +} + +static void binhash_iter2(void) +{ + ACL_BINHASH *table = acl_binhash_create(10, 0); + ACL_ITER iter; + char key[32], *value; + int i; + + for (i = 0; i < 20; i++) { + snprintf(key, sizeof(key), "key: %d", i); + value = acl_mymalloc(32); + snprintf(value, 32, "value: %d", i); + assert(acl_binhash_enter(table, key, (int) strlen(key) + 1, value)); + } + + i = 0; + printf("\n>>>acl_foreach for binhash:\n"); + acl_foreach(iter, table) { + printf("hash i=%d, [%s]\n", iter.i, (char*) iter.data); + i++; + } + + printf(">>>total: %d\n", i); + + i = 0; + printf("\n>>>acl_foreach_reverse for binhash:\n"); + acl_foreach_reverse(iter, table) { + printf("hash i=%d, [%s]\n", iter.i, (char*) iter.data); + i++; + } + + printf(">>>total: %d\n", i); + acl_binhash_free(table, acl_myfree_fn); +} + +static void fifo_iter(void) +{ + ACL_FIFO fifo, *fifo_ptr = &fifo; + ACL_FIFO_ITER iter; + ACL_ITER iter2; + ACL_FIFO_INFO *info; + int i; + char *data; + + acl_fifo_init(&fifo); + + for (i = 0; i < 10; i++) { + data = acl_mymalloc(32); + snprintf(data, 32, "data: %d", i); + acl_fifo_push(&fifo, data); + } + + printf("\n>>> fifo_iter: foreach\n"); + acl_fifo_foreach(iter, fifo_ptr) { + printf("%s\n", (char*) iter.ptr->data); + } + + printf("\n>>> fifo_iter: foreach\n"); + acl_fifo_foreach(iter, &fifo) { + printf("%s\n", (char*) acl_fifo_iter_value(iter)); + } + + printf("\n>>> fifo_iter: foreach_reverse\n"); + acl_fifo_foreach_reverse(iter, &fifo) { + info = iter.ptr; + printf("%s\n", (char*) info->data); + } + + printf("\n>>> acl_foreach for fifo:\n"); + acl_foreach(iter2, &fifo) { + printf("i: %d, value: %s\n", iter2.i, (char*) iter2.data); + } + + printf("\n>>> acl_foreach_reverse for fifo:\n"); + acl_foreach_reverse(iter2, &fifo) { + printf("i: %d, value: %s\n", iter2.i, (char*) iter2.data); + } + + while (1) { + data = acl_fifo_pop(&fifo); + if (data == NULL) + break; + acl_myfree(data); + } +} + +static void fifo_iter2(void) +{ + ACL_FIFO *fifo_ptr = acl_fifo_new(); + ACL_ITER iter; + char *data; + int i; + + for (i = 0; i < 10; i++) { + data = acl_mymalloc(32); + snprintf(data, 32, "data: %d", i); + acl_fifo_push(fifo_ptr, data); + } + + printf("\n>>> fifo_iter: foreach\n"); + acl_foreach(iter, fifo_ptr) { + printf("%s\n", (char*) iter.data); + } + + while (1) { + data = acl_fifo_pop(fifo_ptr); + if (data == NULL) + break; + acl_myfree(data); + } + + acl_fifo_free(fifo_ptr, NULL); +} + +typedef struct { + char name[32]; + ACL_RING entry; +} DUMMY; + +static void ring_iter(void) +{ + ACL_RING head; + DUMMY *dummy; + ACL_RING_ITER iter; + int i; + + acl_ring_init(&head); + + for (i = 0; i < 10; i++) { + dummy = (DUMMY*) acl_mycalloc(1, sizeof(DUMMY)); + snprintf(dummy->name, sizeof(dummy->name), "dummy:%d", i); + acl_ring_append(&head, &dummy->entry); + } + + printf("\nring_iter:\n"); + acl_ring_foreach(iter, &head) { + dummy = acl_ring_to_appl(iter.ptr, DUMMY, entry); + printf("name: %s\n", dummy->name); + } + + while (1) { + iter.ptr = acl_ring_pop_head(&head); + if (iter.ptr == NULL) + break; + dummy = acl_ring_to_appl(iter.ptr, DUMMY, entry); + acl_myfree(dummy); + } +} + +static void argv_iter(int use_slice) +{ + const char *s = "hello world, you are welcome!"; + ACL_SLICE_POOL *slice = use_slice ? acl_slice_pool_create(10, 100, + ACL_SLICE_FLAG_GC2 | ACL_SLICE_FLAG_RTGC_OFF) : NULL; + ACL_ARGV *argv = acl_argv_split3(s, " ,!", slice); + ACL_ITER iter; + + printf("\nacl_foreach for ACL_ARGV:\n"); + acl_foreach(iter, argv) { + printf(">> i: %d, value: %s\n", iter.i, (char*) iter.data); + } + + printf("\nacl_foreach_reverse for ACL_ARGV:\n"); + acl_foreach_reverse(iter, argv) { + printf(">> i: %d, value: %s\n", iter.i, (char*) iter.data); + } + + if (slice == NULL) + acl_argv_free(argv); + else + acl_slice_pool_destroy(slice); +} + +static void array_iter(void) +{ + ACL_ARRAY *a = acl_array_create(10); + ACL_ITER iter; + int i; + char *ptr; + + for (i = 0; i < 20; i++) { + ptr = (char*) acl_mymalloc(32); + snprintf(ptr, 32, "data: %d", i); + (void) acl_array_append(a, ptr); + } + + printf("\nacl_foreach for acl_array:\n"); + acl_foreach(iter, a) { + printf(">> i: %d, value: %s\n", iter.i, (char*) iter.data); + } + + printf("\nacl_foreach_reverse for acl_array:\n"); + acl_foreach_reverse(iter, a) { + printf(">> i: %d, value: %s\n", iter.i, (char*) iter.data); + } + + acl_array_destroy(a, acl_myfree_fn); +} + +static void dlink_iter(void) +{ + ACL_DLINK *dlink = acl_dlink_create(10); + ACL_ITER iter; + ACL_DITEM *ditem; + + printf("\n>>> dlink_iter:\n"); + + (void) acl_dlink_insert(dlink, 1000, 2000); + printf(">>add 1000 -- 2000\n"); + (void) acl_dlink_insert(dlink, 1, 1); + printf(">>add 1 -- 1\n"); + (void) acl_dlink_insert(dlink, 2, 3); + printf(">>add 2 -- 3\n"); + (void) acl_dlink_insert(dlink, 4, 8); + printf(">>add 10 -- 100\n"); + (void) acl_dlink_insert(dlink, 10, 100); + printf(">>add 99 -- 200\n"); + (void) acl_dlink_insert(dlink, 99, 200); + printf(">>add 201 -- 300\n"); + (void) acl_dlink_insert(dlink, 201, 300); + printf(">>add 201 -- 300\n"); + (void) acl_dlink_insert(dlink, 300, 400); + printf(">>add 300 -- 400\n"); + (void) acl_dlink_insert(dlink, 500, 600); + printf(">>add 500 -- 600\n"); + + printf("\n>>>acl_foreach for acl_dlink:\n"); + acl_foreach(iter, dlink) { + ditem = (ACL_DITEM*) iter.data; + printf(">> i: %d, range: %lld -- %lld\n", + iter.i, ditem->begin, ditem->end); + } + + acl_dlink_free(dlink); +} + +static void cache_free(const ACL_CACHE_INFO *info acl_unused, void *ptr) +{ + acl_myfree(ptr); +} + +static void cache_iter(void) +{ + ACL_CACHE *cache = acl_cache_create(100, 120, cache_free); + char *ptr, key[32]; + ACL_ITER iter; + int i; + + for (i = 0; i < 10; i++) { + snprintf(key, sizeof(key), "key-%d", i); + ptr = (char*) acl_mymalloc(32); + snprintf(ptr, 32, "data-%d", i); + (void) acl_cache_enter(cache, key, ptr); + } + + printf("\n>>>acl_foreach for acl_cache:\n"); + acl_foreach(iter, cache) { + printf(">>i: %d, key: %s, value: %s\n", + iter.i, iter.key, (char*) iter.data); + } + + printf("\n>>>acl_foreach_reverse for acl_cache:\n"); + acl_foreach_reverse(iter, cache) { + printf(">>i: %d, key: %s, value: %s\n", + iter.i, iter.key, (char*) iter.data); + } + + acl_cache_free(cache); +} + +typedef struct { + char name[32]; + int i; +} TIMER_ITEM; + +static void timer_iter(void) +{ + ACL_TIMER *timer = acl_timer_new(); + TIMER_ITEM *item; + ACL_ITER iter; + int i; + + for (i = 0; i < 10; i++) { + item = (TIMER_ITEM*) acl_mycalloc(1, sizeof(TIMER_ITEM)); + snprintf(item->name, sizeof(item->name), "name-%d", i); + item->i = i; + acl_timer_request(timer, item, i); + } + + printf("\n>>>acl_foreach for ACL_TIMER:\n"); + + acl_foreach(iter, timer) { + const ACL_TIMER_INFO *info; + + item = (TIMER_ITEM*) iter.data; + info = acl_iter_info(iter, timer); + printf("\titem->name=%s, item->i=%d, when: %d\n", + item->name, item->i, (int) info->when); + } + + printf("\n>>>acl_foreach_reverse for ACL_TIMER:\n"); + + acl_foreach_reverse(iter, timer) { + const ACL_TIMER_INFO *info; + + item = (TIMER_ITEM*) iter.data; + info = acl_iter_info(iter, timer); + printf("\titem->name=%s, item->i=%d, when: %d\n", + item->name, item->i, (int) info->when); + acl_myfree(item); + } + acl_timer_free(timer, NULL); +} + +static void netdb_iter(void) +{ + ACL_DNS_DB *dns_db = acl_netdb_new("www.test.com"); + ACL_ITER iter; + + acl_netdb_add_addr(dns_db, "127.0.0.1", 80); + acl_netdb_add_addr(dns_db, "192.168.0.1", 80); + acl_netdb_add_addr(dns_db, "192.168.0.2", 80); + acl_netdb_add_addr(dns_db, "192.168.0.2", 80); + acl_netdb_add_addr(dns_db, "192.168.0.3", 80); + + printf("\n>>>acl_foreach for ACL_DNS_DB\n"); + + acl_foreach(iter, dns_db) { + const ACL_HOST_INFO *info, *info2; + + info = (const ACL_HOST_INFO*) iter.data; + info2 = acl_iter_info(iter, dns_db); + printf("\tip=%s, %s; port=%d, %d\n", + info->ip, info2->ip, info->hport, info2->hport); + } + + printf("\n>>>acl_foreach_reverse for ACL_DNS_DB\n"); + + acl_foreach_reverse(iter, dns_db) { + const ACL_HOST_INFO *info, *info2; + + info = (const ACL_HOST_INFO*) iter.data; + info2 = acl_iter_info(iter, dns_db); + printf("\tip=%s, %s; port=%d, %d\n", + info->ip, info2->ip, info->hport, info2->hport); + } + acl_netdb_free(dns_db); +} + +static void ifconf_iter(void) +{ + ACL_IFCONF *ifconf = acl_get_ifaddrs(); + ACL_IFADDR *ifaddr; + ACL_ITER iter; + + printf("\nacl_foreach for ifconf_iter\n"); + if (ifconf) { + acl_foreach(iter, ifconf) { + ifaddr = (ACL_IFADDR*) iter.data; +#ifdef ACL_MS_WINDOWS + printf("\tname: %s, desc: %s, addr: %s\n", + ifaddr->name, ifaddr->desc, ifaddr->ip); +#else + printf("\tname: %s, addr: %s\n", ifaddr->name, ifaddr->ip); +#endif + } + } + + printf("\nacl_foreach_reverse for ifconf_iter\n"); + acl_foreach_reverse(iter, ifconf) { + ifaddr = (ACL_IFADDR*) iter.data; +#ifdef ACL_MS_WINDOWS + printf("\tname: %s, desc: %s, addr: %s\n", + ifaddr->name, ifaddr->desc, ifaddr->ip); +#else + printf("\tname: %s, addr: %s\n", ifaddr->name, ifaddr->ip); +#endif + } + + acl_free_ifaddrs(ifconf); +} + +int main(int argc, char *argv[]) +{ +#if 0 + acl_memory_debug_start(); + acl_memory_debug_stack(1); + acl_debug_malloc_init(NULL, "log.txt"); +#endif + int use_slice; + + if (argc == 2 && strcasecmp(argv[1], "slice") == 0) + use_slice = 1; + else + use_slice = 0; + + fifo_iter(); + fifo_iter2(); + + ring_iter(); + + htable_iter(); + htable_iter2(); + + binhash_iter(); + binhash_iter2(); + + argv_iter(use_slice); + array_iter(); + dlink_iter(); + cache_iter(); + timer_iter(); + netdb_iter(); + ifconf_iter(); +#ifdef ACL_MS_WINDOWS + printf("enter any key to exit ...\n"); + getchar(); +#endif + return (0); +} diff --git a/samples/iterator/valgrind.sh b/samples/iterator/valgrind.sh new file mode 100644 index 000000000..394b58ef2 --- /dev/null +++ b/samples/iterator/valgrind.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +valgrind --show-below-main=yes --show-reachable=yes --tool=memcheck --leak-check=yes -v ./iterator slice diff --git a/samples/json/Makefile b/samples/json/Makefile new file mode 100644 index 000000000..c6c830837 --- /dev/null +++ b/samples/json/Makefile @@ -0,0 +1,2 @@ +include ../Makefile_cpp.in +PROG = json diff --git a/samples/json/json.vcproj b/samples/json/json.vcproj new file mode 100644 index 000000000..863adfd30 --- /dev/null +++ b/samples/json/json.vcproj @@ -0,0 +1,230 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/json/json.vcxproj b/samples/json/json.vcxproj new file mode 100644 index 000000000..dcc6c4215 --- /dev/null +++ b/samples/json/json.vcxproj @@ -0,0 +1,177 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + ReleaseDll + Win32 + + + Release + Win32 + + + + {8021ECD9-04CB-463B-B287-1FB0F5486D91} + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + $(OutDir)json.exe + true + $(OutDir)json.pdb + Console + MachineX86 + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + $(OutDir)json.exe + true + Console + true + true + MachineX86 + + + + + Disabled + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_DLL;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + ProgramDatabase + + + $(OutDir)json.exe + true + $(OutDir)json.pdb + Console + MachineX86 + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_DLL;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + $(OutDir)json.exe + true + Console + true + true + MachineX86 + + + + + {b40213c2-507c-4c7f-a6e1-b850c9bdc27b} + false + + + + + + + + + \ No newline at end of file diff --git a/samples/json/main.cpp b/samples/json/main.cpp new file mode 100644 index 000000000..63ab7b19a --- /dev/null +++ b/samples/json/main.cpp @@ -0,0 +1,388 @@ +#include "lib_acl.h" + +#define STR acl_vstring_str + +static const char* default_data = \ + "{ 'menu name': {\r\n" + " 'id:file': 'file',\r\n" + " 'value{': 'File',\r\n" + " 'popup{}': {\r\n" + " 'menuitem1}': [\r\n" + " {'value': 'New', 'onclick': 'CreateNewDoc()'},\r\n" + " {'value': 'Open', 'onclick': 'OpenDoc()'},\r\n" + " {'value': 'Close', 'onclick': 'CloseDoc()'}\r\n" + " ],\r\n" + " 'menuname[]': 'hello world',\r\n" + " 'inner': { 'value' : 'new ', 'value' : 'open' },\r\n" + " 'menuitem2': [\r\n" + " {'value': 'New', 'onclick': 'CreateNewDoc()'},\r\n" + " {'value': 'Open', 'onclick': 'OpenDoc()'},\r\n" + " {'value': 'Close', 'onclick': 'CloseDoc()'},\r\n" + " {{'value': 'Help', 'onclick': 'Help()'}}" + " ]\r\n" + " }\r\n" + " }\r\n," + " 'help': 'hello world!',\r\n" + " 'menuitem2': [\r\n" + " {'value': 'New', 'onclick': 'CreateNewDoc()'},\r\n" + " {'value': 'Open', 'onclick': 'OpenDoc()'},\r\n" + " {'value': 'Close', 'onclick': 'CloseDoc()'},\r\n" + " [{'value': 'Save', 'onclick': 'SaveDoc()'}]" + " ]\r\n" + "}\r\n"; + +static void print_json_node(const ACL_JSON* json, const ACL_JSON_NODE* node) +{ + for (int i = 1; i < node->depth; i++) + printf("\t"); + printf("tag> %s, parent %s, text: %s, child: %s, type: %s\n", + STR(node->ltag), node->parent == json->root + ? "root" : STR(node->parent->ltag), + STR(node->text), node->tag_node ? "yes" : "no", + acl_json_node_type(node)); +} + +static void test_json_foreach1(ACL_JSON* json) +{ + ACL_ITER iter; + + printf("------------ in %s ------------\r\n", __FUNCTION__); + + acl_foreach(iter, json) + { + const ACL_JSON_NODE* node = (const ACL_JSON_NODE*) iter.data; + print_json_node(json, node); + } + + ACL_FILE* fp = acl_fopen("./json.txt", "w"); + acl_assert(fp); + ACL_VSTRING* buf = acl_json_build(json, NULL); + acl_fwrite(acl_vstring_str(buf), ACL_VSTRING_LEN(buf), 1, fp); + acl_fclose(fp); + acl_vstring_free(buf); + printf("\r\n"); +} + +static void test_json_foreach2(ACL_JSON* json) +{ + ACL_ITER iter1, iter2, iter3, iter4, iter5; + ACL_JSON_NODE *node1, *node2, *node3, *node4, *node5; + + printf("------------ in %s ------------\r\n", __FUNCTION__); + + /* 一级结点 */ + acl_foreach(iter1, json->root) { + node1 = (ACL_JSON_NODE*) iter1.data; + print_json_node(json, node1); + + /* 二级结点 */ + acl_foreach(iter2, node1) { + node2 = (ACL_JSON_NODE*) iter2.data; + print_json_node(json, node2); + + /* 三级结点 */ + acl_foreach(iter3, node2) { + node3 = (ACL_JSON_NODE*) iter3.data; + print_json_node(json, node3); + + /* 四级结点 */ + acl_foreach(iter4, node3) { + node4 = (ACL_JSON_NODE*) iter4.data; + print_json_node(json, node4); + + /* 五级结点 */ + acl_foreach(iter5, node4) { + node5 = (ACL_JSON_NODE*) iter5.data; + print_json_node(json, node5); + } + } + } + } + } + printf("\r\n"); +} + +static void test_json_find1(ACL_JSON* json) +{ + printf("------------ in %s ------------\r\n", __FUNCTION__); + + //const char* tags = "menu/*/menuitem/*/onclick"; + const char* tags = "menu/popup/menuitem/*/onclick"; + //const char* tags = "menu/popup/menuitem"; + //const char* tags = "menu/popup/menuname"; + //const char* tags = "menu/id"; + + printf(">>find: %s\r\n", tags); + + ACL_ARRAY* a = acl_json_getElementsByTags(json, tags); + if (a == NULL) { + printf("\r\n"); + return; + } + + ACL_ITER iter1, iter2, iter3; + acl_foreach(iter1, a) { + ACL_JSON_NODE* node1 = (ACL_JSON_NODE*) iter1.data; + printf("%s: %s\r\n", tags, STR(node1->text)); + + /* 遍历 node1 结点的一级子结点 */ + acl_foreach(iter2, node1) { + ACL_JSON_NODE* node2 = (ACL_JSON_NODE*) iter2.data; + + /* 遍历 node2 结点的一级子结点 */ + acl_foreach(iter3, node2) { + ACL_JSON_NODE* node3 = + (ACL_JSON_NODE*) iter3.data; + printf("\t%s: %s\r\n", STR(node3->ltag), + STR(node3->text)); + } + printf("---------------------------------------\r\n"); + } + } + acl_json_free_array(a); + printf(">>find %s end\r\n\r\n", tags); +} + +static void test_json_find2(ACL_JSON* json) +{ + const char* tag = "onclick"; + ACL_ARRAY* a = acl_json_getElementsByTagName(json, tag); + ACL_ITER iter; + + printf("------------ in %s ------------\r\n", __FUNCTION__); + + if (a) { + acl_foreach(iter, a) { + ACL_JSON_NODE* node = (ACL_JSON_NODE*) iter.data; + printf("find %s result: %s\r\n", tag, STR(node->text)); + } + acl_json_free_array(a); + } + + tag = "help"; + a = acl_json_getElementsByTagName(json, tag); + if (a) { + acl_foreach(iter, a) { + ACL_JSON_NODE* node = (ACL_JSON_NODE*) iter.data; + printf("find %s result: %s\r\n", tag, STR(node->text)); + } + acl_json_free_array(a); + } + printf(">>find %s end\r\n\r\n", tag); +} + +static void test_json_data(const char* data) +{ + ACL_JSON* json = acl_json_alloc(); + const char* ptr = data; + char buf[2]; + + json->flag |= ACL_JSON_FLAG_PART_WORD; + + if (1) { + while (*ptr) + { + buf[0] = *ptr++; + buf[1] = 0; + acl_json_update(json, buf); + /* + if (json->finish) + break; + */ + } + } + else + acl_json_update(json, data); + + test_json_foreach1(json); + test_json_foreach2(json); + test_json_find1(json); + test_json_find2(json); + acl_json_free(json); +} + +static void test_json_build(void) +{ + ACL_JSON* json = acl_json_alloc(); + ACL_JSON_NODE* root, *node1, *node2, *node3; + + root = acl_json_create_obj(json); + acl_json_node_append_child(json->root, root); + + node1 = acl_json_create_leaf(json, "name1", "value1"); + acl_json_node_append_child(root, node1); + + node1 = acl_json_create_leaf(json, "name2", "value2"); + acl_json_node_append_child(root, node1); + + node1 = acl_json_create_obj(json); + node2 = acl_json_create_leaf(json, "name3", "value3"); + acl_json_node_append_child(node1, node2); + node2 = acl_json_create_node(json, "name4", node1); + acl_json_node_append_child(root, node2); + + ////////////////////////////////////////////////////////////////////////// + + node1 = acl_json_create_array(json); + node2 = acl_json_create_node(json, "name5", node1); + acl_json_node_append_child(root, node2); + + node3 = acl_json_create_leaf(json, "name6", "value6"); + acl_json_node_append_child(node1, node3); + + node3 = acl_json_create_leaf(json, "name7", "value7"); + acl_json_node_append_child(node1, node3); + + node3 = acl_json_create_obj(json); + acl_json_node_append_child(node1, node3); + node2 = acl_json_create_leaf(json, "name8", "value8"); + acl_json_node_append_child(node3, node2); + node2 = acl_json_create_leaf(json, "name9", "value9"); + acl_json_node_append_child(node3, node2); + + ////////////////////////////////////////////////////////////////////////// + + ACL_VSTRING* buf = acl_json_build(json, NULL); + printf("%s\r\n", acl_vstring_str(buf)); + acl_vstring_free(buf); + + acl_json_free(json); +} + +static void test_json_default(void) +{ + test_json_data(default_data); + test_json_build(); +} + +static void test_json_file(const char* path) +{ + char* buf = acl_vstream_loadfile(path); + if (buf == NULL) + { + printf("load file %s error(%s)\r\n", path, acl_last_serror()); + return; + } + + printf("buf: |%s|\r\n", buf); + test_json_data(buf); + acl_myfree(buf); +} + +static void test_json_benchmark(bool use_cache, bool once, int max) +{ + ACL_JSON *json = acl_json_alloc(); + + if (use_cache) + acl_json_cache(json, 1000); + + ACL_METER_TIME("-------------bat begin--------------"); + + for (int i = 0; i < max; i++) + { + const char* ptr = default_data; + + if (once) + acl_json_update(json, ptr); + else + { + /* 每次仅输入一个字节来分析 json 数据 */ + while (*ptr != 0) { + char ch2[2]; + + ch2[0] = *ptr; + ch2[1] = 0; + acl_json_update(json, ch2); + ptr++; + } + } + acl_json_reset(json); + } + + ACL_METER_TIME("-------------bat end--------------"); + acl_json_free(json); +} + +static void usage(const char* program) +{ + printf("usage: %s -h[help]\n" + " -f json_filepath\n" + " -b[benchmark] -c[cache for banchmark] -m benchmark_max\n" + " -s[once parse]\n" + " -M[use mempool]\r\n", program); +} + +int main(int argc, char** argv) +{ +#if 0 +// const char* pp = "誠\"; + const char* pp = "錦\"; + while (*pp) + { + printf("ch: %d\r\n", *pp); + pp++; + } + printf("'\\': %d\r\n", '\\'); + exit(0); +#endif + + int ch; + int benchmark_max = 100; + bool use_default = true, benchmark = false; + bool benchmark_cache = false, once = false, use_mempool = false; + + while ((ch = getopt(argc, argv, "hf:bcm:sM")) > 0) + { + switch (ch) + { + case 'h': + use_default = false; + usage(argv[0]); + return (0); + case 'f': + use_default = false; + test_json_file(optarg); + break; + case 'b': + use_default = false; + benchmark = true; + break; + case 'c': + use_default = false; + benchmark_cache = true; + break; + case 'm': + use_default = false; + benchmark_max = atoi(optarg); + break; + case 's': + once = true; + break; + case 'M': + use_mempool = true; + break; + default: + break; + } + } + + if (use_mempool) + { + acl_mem_slice_init(8, 1024, 100000, + ACL_SLICE_FLAG_GC2 | + ACL_SLICE_FLAG_RTGC_OFF | + ACL_SLICE_FLAG_LP64_ALIGN); + printf("use mempool now\n"); + } + + if (benchmark) + test_json_benchmark(benchmark_cache, once, benchmark_max); + else if (use_default) + test_json_default(); + +#ifdef WIN32 + getchar(); +#endif + + return (0); +} diff --git a/samples/json/test1 b/samples/json/test1 new file mode 100644 index 000000000..eacfbf5e6 --- /dev/null +++ b/samples/json/test1 @@ -0,0 +1,22 @@ +{ + "glossary": { + "title": "example glossary", + "GlossDiv": { + "title": "S", + "GlossList": { + "GlossEntry": { + "ID": "SGML", + "SortAs": "SGML", + "GlossTerm": "Standard Generalized Markup Language", + "Acronym": "SGML", + "Abbrev": "ISO 8879:1986", + "GlossDef": { + "para": "A meta-markup language, used to create markup languages such as DocBook.", + "GlossSeeAlso": ["GML", "XML"] + }, + "GlossSee": "markup" + } + } + } + } +} diff --git a/samples/json/test1.txt b/samples/json/test1.txt new file mode 100644 index 000000000..9676de352 --- /dev/null +++ b/samples/json/test1.txt @@ -0,0 +1,13 @@ +{ menu: { + id: 'file', + value: 'File', + popup: { + menuitem: [ + { value: 'New', onclick: 'CreateNewDoc()' }, + { value: 'Open', onclick: 'OpenDoc()' }, + { value: 'Close', onclick: 'CloseDoc()' } + ], + menuitem: 'hello world' + } + } +} diff --git a/samples/json/test2 b/samples/json/test2 new file mode 100644 index 000000000..5600991a4 --- /dev/null +++ b/samples/json/test2 @@ -0,0 +1,11 @@ +{"menu": { + "id": "file", + "value": "File", + "popup": { + "menuitem": [ + {"value": "New", "onclick": "CreateNewDoc()"}, + {"value": "Open", "onclick": "OpenDoc()"}, + {"value": "Close", "onclick": "CloseDoc()"} + ] + } +}} diff --git a/samples/json/test2.txt b/samples/json/test2.txt new file mode 100644 index 000000000..f457f5360 --- /dev/null +++ b/samples/json/test2.txt @@ -0,0 +1,12 @@ +{ + id: 'file', value: 'File', + popup: { + menuitem: [ + { value: 'New', onclick: 'CreateNewDoc()' }, + { value: 'Open', onclick: 'OpenDoc()' }, + { value: 'Close', onclick: 'CloseDoc()' } + ], + menuitem: 'help' + }, + help: 'hello world!' +} diff --git a/samples/json/test3 b/samples/json/test3 new file mode 100644 index 000000000..5662b3774 --- /dev/null +++ b/samples/json/test3 @@ -0,0 +1,26 @@ +{"widget": { + "debug": "on", + "window": { + "title": "Sample Konfabulator Widget", + "name": "main_window", + "width": 500, + "height": 500 + }, + "image": { + "src": "Images/Sun.png", + "name": "sun1", + "hOffset": 250, + "vOffset": 250, + "alignment": "center" + }, + "text": { + "data": "Click Here", + "size": 36, + "style": "bold", + "name": "text1", + "hOffset": 250, + "vOffset": 100, + "alignment": "center", + "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;" + } +}} \ No newline at end of file diff --git a/samples/json/test3.txt b/samples/json/test3.txt new file mode 100644 index 000000000..2acd21189 --- /dev/null +++ b/samples/json/test3.txt @@ -0,0 +1,5 @@ +{ + id: 'file'; + value: 'File', + name: 'zsxxsz' +} diff --git a/samples/json/test4 b/samples/json/test4 new file mode 100644 index 000000000..d540b57f0 --- /dev/null +++ b/samples/json/test4 @@ -0,0 +1,88 @@ +{"web-app": { + "servlet": [ + { + "servlet-name": "cofaxCDS", + "servlet-class": "org.cofax.cds.CDSServlet", + "init-param": { + "configGlossary:installationAt": "Philadelphia, PA", + "configGlossary:adminEmail": "ksm@pobox.com", + "configGlossary:poweredBy": "Cofax", + "configGlossary:poweredByIcon": "/images/cofax.gif", + "configGlossary:staticPath": "/content/static", + "templateProcessorClass": "org.cofax.WysiwygTemplate", + "templateLoaderClass": "org.cofax.FilesTemplateLoader", + "templatePath": "templates", + "templateOverridePath": "", + "defaultListTemplate": "listTemplate.htm", + "defaultFileTemplate": "articleTemplate.htm", + "useJSP": false, + "jspListTemplate": "listTemplate.jsp", + "jspFileTemplate": "articleTemplate.jsp", + "cachePackageTagsTrack": 200, + "cachePackageTagsStore": 200, + "cachePackageTagsRefresh": 60, + "cacheTemplatesTrack": 100, + "cacheTemplatesStore": 50, + "cacheTemplatesRefresh": 15, + "cachePagesTrack": 200, + "cachePagesStore": 100, + "cachePagesRefresh": 10, + "cachePagesDirtyRead": 10, + "searchEngineListTemplate": "forSearchEnginesList.htm", + "searchEngineFileTemplate": "forSearchEngines.htm", + "searchEngineRobotsDb": "WEB-INF/robots.db", + "useDataStore": true, + "dataStoreClass": "org.cofax.SqlDataStore", + "redirectionClass": "org.cofax.SqlRedirection", + "dataStoreName": "cofax", + "dataStoreDriver": "com.microsoft.jdbc.sqlserver.SQLServerDriver", + "dataStoreUrl": "jdbc:microsoft:sqlserver://LOCALHOST:1433;DatabaseName=goon", + "dataStoreUser": "sa", + "dataStorePassword": "dataStoreTestQuery", + "dataStoreTestQuery": "SET NOCOUNT ON;select test='test';", + "dataStoreLogFile": "/usr/local/tomcat/logs/datastore.log", + "dataStoreInitConns": 10, + "dataStoreMaxConns": 100, + "dataStoreConnUsageLimit": 100, + "dataStoreLogLevel": "debug", + "maxUrlLength": 500}}, + { + "servlet-name": "cofaxEmail", + "servlet-class": "org.cofax.cds.EmailServlet", + "init-param": { + "mailHost": "mail1", + "mailHostOverride": "mail2"}}, + { + "servlet-name": "cofaxAdmin", + "servlet-class": "org.cofax.cds.AdminServlet"}, + + { + "servlet-name": "fileServlet", + "servlet-class": "org.cofax.cds.FileServlet"}, + { + "servlet-name": "cofaxTools", + "servlet-class": "org.cofax.cms.CofaxToolsServlet", + "init-param": { + "templatePath": "toolstemplates/", + "log": 1, + "logLocation": "/usr/local/tomcat/logs/CofaxTools.log", + "logMaxSize": "", + "dataLog": 1, + "dataLogLocation": "/usr/local/tomcat/logs/dataLog.log", + "dataLogMaxSize": "", + "removePageCache": "/content/admin/remove?cache=pages&id=", + "removeTemplateCache": "/content/admin/remove?cache=templates&id=", + "fileTransferFolder": "/usr/local/tomcat/webapps/content/fileTransferFolder", + "lookInContext": 1, + "adminGroupID": 4, + "betaServer": true}}], + "servlet-mapping": { + "cofaxCDS": "/", + "cofaxEmail": "/cofaxutil/aemail/*", + "cofaxAdmin": "/admin/*", + "fileServlet": "/static/*", + "cofaxTools": "/tools/*"}, + + "taglib": { + "taglib-uri": "cofax.tld", + "taglib-location": "/WEB-INF/tlds/cofax.tld"}}} \ No newline at end of file diff --git a/samples/json/test5 b/samples/json/test5 new file mode 100644 index 000000000..49980ca25 --- /dev/null +++ b/samples/json/test5 @@ -0,0 +1,27 @@ +{"menu": { + "header": "SVG Viewer", + "items": [ + {"id": "Open"}, + {"id": "OpenNew", "label": "Open New"}, + null, + {"id": "ZoomIn", "label": "Zoom In"}, + {"id": "ZoomOut", "label": "Zoom Out"}, + {"id": "OriginalView", "label": "Original View"}, + null, + {"id": "Quality"}, + {"id": "Pause"}, + {"id": "Mute"}, + null, + {"id": "Find", "label": "Find..."}, + {"id": "FindAgain", "label": "Find Again"}, + {"id": "Copy"}, + {"id": "CopyAgain", "label": "Copy Again"}, + {"id": "CopySVG", "label": "Copy SVG"}, + {"id": "ViewSVG", "label": "View SVG"}, + {"id": "ViewSource", "label": "View Source"}, + {"id": "SaveAs", "label": "Save As"}, + null, + {"id": "Help"}, + {"id": "About", "label": "About Adobe CVG Viewer..."} + ] +}} diff --git a/samples/json/test6 b/samples/json/test6 new file mode 100644 index 000000000..72c67b5e3 --- /dev/null +++ b/samples/json/test6 @@ -0,0 +1 @@ +{ "value0-山本誠" : "山本誠", "value1-\[山本誠\]" : "绣錦", "山本誠-value2" : "\[大仙\]", "\[山本誠\]-value3" : "\'hello\'", "value4" : "山本誠", "value5" : "\[大仙\]"} diff --git a/samples/json/valgrind.sh b/samples/json/valgrind.sh new file mode 100644 index 000000000..45fa79ffc --- /dev/null +++ b/samples/json/valgrind.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +valgrind --tool=memcheck --leak-check=yes -v ./json -b -m 10 diff --git a/samples/jt2ft/Makefile b/samples/jt2ft/Makefile new file mode 100644 index 000000000..ebd326d6d --- /dev/null +++ b/samples/jt2ft/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = jt2ft diff --git a/samples/jt2ft/ft.txt b/samples/jt2ft/ft.txt new file mode 100644 index 000000000..1a3f18054 --- /dev/null +++ b/samples/jt2ft/ft.txt @@ -0,0 +1 @@ +場礎貳盡饋謾擰傘abcdefg0123456 \ No newline at end of file diff --git a/samples/jt2ft/main.c b/samples/jt2ft/main.c new file mode 100644 index 000000000..054b79c40 --- /dev/null +++ b/samples/jt2ft/main.c @@ -0,0 +1,53 @@ +#include "lib_acl.h" +#include +#include +#include + +static void test(void) +{ + ACL_FILE *fp = acl_fopen("ft.txt", "w+"); + const char *jt = "场础贰尽馈谩拧伞abcdefg0123456"; + char buf[256], buf2[256]; + unsigned short *ptr; + + printf(">>>jt: %s, len: %d\n", jt, (int) strlen(jt)); + memset(buf, 0, sizeof(buf)); + acl_gbjt2ft(jt, strlen(jt), buf, sizeof(buf)); + printf(">>>ft: %s, len: %d\n", buf, (int) strlen(buf)); + ptr = (unsigned short*) buf; + /* + while (*ptr != 0) { + snprintf(buf, sizeof(buf), "0x%x,", *ptr); + acl_fwrite(buf, strlen(buf), 1, fp); + ptr++; + } + */ + acl_fwrite(buf, strlen(buf), 1, fp); + acl_fclose(fp); + + fp = acl_fopen("ft.txt", "r"); + if (fp == NULL) { + printf("open file ft.txt error(%s)\n", acl_last_serror()); + return; + } + + memset(buf, 0, sizeof(buf)); + acl_fread(buf, strlen(jt), 1, fp); + printf(">>>ft: %s, len: %d\n", buf, (int) strlen(buf)); + acl_gbft2jt(buf, strlen(buf), buf, (int) strlen(buf) - 1); + printf(">>>jt: %s, len: %d\n", buf, (int) strlen(buf)); + acl_gbft2jt(buf, strlen(buf), buf2, (int) strlen(buf) - 1); + printf(">>>jt: %s, len: %d\n", buf2, (int) strlen(buf2)); + acl_fclose(fp); +} + +int main(void) +{ + test(); + +#ifdef ACL_MS_WINDOWS + printf("enter any key to exit ...\n"); + getchar(); +#endif + return (0); +} diff --git a/samples/log/Makefile b/samples/log/Makefile new file mode 100644 index 000000000..a328a955a --- /dev/null +++ b/samples/log/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = log diff --git a/samples/log/main.c b/samples/log/main.c new file mode 100644 index 000000000..b9d0ee6a2 --- /dev/null +++ b/samples/log/main.c @@ -0,0 +1,60 @@ +#include "lib_acl.h" +#include + +static int __num = 10; + +static void usage(const char *procname) +{ + printf("usage: %s -h[help] -t logger_files -n num -N nthreads\n", procname); + printf("examples: %s -t TCP:127.0.0.1:12345|UDP:127.0.0.1:12345|./test.log -n 100 -N 2\n", procname); +} + +static void thread_main(void *arg acl_unused) +{ + int i = 0; + + for (i = 0; i < __num; i++) + acl_msg_info("%s(%d), log %d", __FILE__, __LINE__, i); +} + +int main(int argc, char *argv[]) +{ + int i, ch, nthread = 1; + char buf[1024]; + acl_pthread_pool_t *pool; + + buf[0] = 0; + while ((ch = getopt(argc, argv, "ht:n:N:")) > 0) { + switch (ch) { + case 'h': + usage(argv[0]); + return (0); + case 't': + snprintf(buf, sizeof(buf), "%s", optarg); + break; + case 'n': + __num = atoi(optarg); + break; + case 'N': + nthread = atoi(optarg); + break; + default: + break; + } + } + + if (buf[0] == 0) { + usage(argv[0]); + return (0); + } + + acl_msg_open(buf, "log_test"); + + pool = acl_thread_pool_create(nthread, 100); + for (i = 0; i < nthread; i++) + acl_pthread_pool_add(pool, thread_main, NULL); + acl_pthread_pool_destroy(pool); + + acl_msg_close(); + return (0); +} diff --git a/samples/log/valgrind.sh b/samples/log/valgrind.sh new file mode 100644 index 000000000..2e9d61c2f --- /dev/null +++ b/samples/log/valgrind.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +valgrind --show-below-main=yes --show-reachable=yes --tool=memcheck --leak-check=yes -v ./log "UDP:192.168.1.229:12345|TCP:127.0.0.1:12345|log.txt" diff --git a/samples/master/Makefile b/samples/master/Makefile new file mode 100644 index 000000000..78438cd6a --- /dev/null +++ b/samples/master/Makefile @@ -0,0 +1,149 @@ +SHELL = /bin/sh +CC = gcc +#CC = g++ +AR = ar +ARFL = rv +RANLIB = ranlib + +CFLAGS = -c -g -W -Wall -Wcast-qual -Wcast-align \ +-Waggregate-return -Wmissing-prototypes \ +-Wpointer-arith -Werror -Wshadow -pedantic -O2 \ +-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO \ +-Wno-long-long +########################################################### +#Check system: +# Linux, SunOS, Solaris, BSD variants, AIX, HP-UX +SYSLIB = +CHECKSYSRES = @echo "Unknow system type!";exit 1 +UNIXNAME = $(shell uname -sm) + +# For FreeBSD +ifeq ($(findstring FreeBSD, $(UNIXNAME)), FreeBSD) + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DFREEBSD -D_REENTRANT -pedantic +endif + +#Path for Linux +ifeq ($(findstring Linux, $(UNIXNAME)), Linux) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DLINUX2 + SYSLIB = -lcrypt -lpthread +endif + +#Path for SunOS +ifeq ($(findstring SunOS, $(UNIXNAME)), SunOS) + ifeq ($(findstring 86, $(UNIXNAME)), 86) + SYSLIB = -lsocket -lnsl -lrt + endif + ifeq ($(findstring sun4u, $(UNIXNAME)), sun4u) + SYSLIB = -lsocket -lnsl -lrt + endif + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DSUNOS5 +endif + +#Path for HP-UX +ifeq ($(findstring HP-UX, $(UNIXNAME)), HP-UX) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + SYSLIB = -lpthread + CFLAGS += -DHP_UX -DHPUX11 + PLAT_NAME=hp-ux +endif + +#Find system type. +ifneq ($(SYSPATH),) + CHECKSYSRES = @echo "System is $(shell uname -sm)" +endif +########################################################### + +LIB_ACL_PATH = ../../lib_acl +LIB_PATH = -L$(LIB_ACL_PATH)/lib +INCL_PATH = $(LIB_ACL_PATH)/include + +ALL_LIBS = -l_acl $(SYSLIB) + +INCLUDE = -I$(INCL_PATH) +CFLAGS += $(INCLUDE) + +OUTPATH = ./ +OBJ_OUTPATH = $(OUTPATH) + +#Project's objs +SOURCES = $(wildcard *.c) +INCLUDES = $(wildcard *.h) +OBJS = $(patsubst %.c,$(OBJ_OUTPATH)%.o,$(SOURCES)) + +DIST_PATH = ../../dist/master/libexec +########################################################### + +.PHONY = all clean install uninstall +#PROG_NAME = acl_master +#PATH_RELEASE = ./acl/libexec + +COMPILE = $(CC) $(CFLAGS) + +all: $(PROG_NAME) + +#$(PROG_NAME): $(OBJS) +# $(CC) -o $(PROG_NAME) $(OBJS) $(LIB_PATH) $(ALL_LIBS) +# cp $(PROG_NAME) $(PATH_RELEASE)/ +all: build +build: + @(cd single_echo; make) + @(cd multi_echo; make) + @(cd ioctl_echo; make) + @(cd ioctl_echo2; make) + @(cd ioctl_echo3; make) + @(cd trigger; make) + @(cd single_proxy; make) + @(cd multi_proxy; make) + @(cd aio_echo; make) + @(cd aio_proxy; make) +# @(cd master_notify; make) + +$(OBJ_OUTPATH)%.o: %.c *.h + $(COMPILE) -o $@ $< + +clean: + @(cd single_echo; make clean) + @(cd multi_echo; make clean) + @(cd ioctl_echo; make clean) + @(cd ioctl_echo2; make clean) + @(cd ioctl_echo3; make clean) + @(cd trigger; make clean) + @(cd single_proxy; make clean) + @(cd multi_proxy; make clean) + @(cd aio_proxy; make clean) + @(cd aio_echo; make clean) + @(cd master_notify; make clean) + +install: + cp single_echo/single_echo ${DIST_PATH}/ + cp multi_echo/multi_echo ${DIST_PATH}/ + cp ioctl_echo/ioctl_echo ${DIST_PATH}/ + cp trigger/trigger ${DIST_PATH}/ + cp single_proxy/single_proxy ${DIST_PATH}/ + cp multi_proxy/multi_proxy ${DIST_PATH}/ + cp aio_proxy/aio_proxy ${DIST_PATH}/ +# cp master_notify/acl_notify ${DIST_PATH}/ +# cp aio_echo/aio_echo ${DIST_PATH}/ + +uninstall: + rm -f ${DIST_PATH}/single_echo + rm -f ${DIST_PATH}/multi_echo + rm -f ${DIST_PATH}/ioctl_echo + rm -f ${DIST_PATH}/trigger + rm -f ${DIST_PATH}/single_proxy + rm -f ${DIST_PATH}/multi_proxy +# rm -f ${DIST_PATH}/acl_notify +# rm -f ${DIST_PATH}/aio_echo + +rebuild: clean all diff --git a/samples/master/Makefile.in b/samples/master/Makefile.in new file mode 100644 index 000000000..6c5108249 --- /dev/null +++ b/samples/master/Makefile.in @@ -0,0 +1,99 @@ +SHELL = /bin/sh +CC = gcc + +CFLAGS = -c -g -W -Wall -Wcast-qual -Wcast-align \ +-Waggregate-return -Wmissing-prototypes \ +-Wpointer-arith -Werror -Wshadow -pedantic -O2 \ +-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO \ +-Wno-long-long +########################################################### +#Check system: +# Linux, SunOS, Solaris, BSD variants, AIX, HP-UX +SYSLIB = +CHECKSYSRES = @echo "Unknow system type!";exit 1 +UNIXNAME = $(shell uname -sm) + +ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes +endif + +# For Darwin +ifeq ($(findstring Darwin, $(UNIXNAME)), Darwin) + CFLAGS += -DMACOSX +endif + +# For FreeBSD +ifeq ($(findstring FreeBSD, $(UNIXNAME)), FreeBSD) + CFLAGS += -DFREEBSD -D_REENTRANT -pedantic + SYSLIB = -lpthread +endif + +#Path for Linux +ifeq ($(findstring Linux, $(UNIXNAME)), Linux) + CFLAGS += -DLINUX2 + SYSLIB = -lcrypt -lpthread +endif + +#Path for SunOS +ifeq ($(findstring SunOS, $(UNIXNAME)), SunOS) + ifeq ($(findstring 86, $(UNIXNAME)), 86) + SYSLIB = -lsocket -lnsl -lrt + endif + ifeq ($(findstring sun4u, $(UNIXNAME)), sun4u) + SYSLIB = -lsocket -lnsl -lrt + endif + CFLAGS += -DSUNOS5 +endif + +#Path for HP-UX +ifeq ($(findstring HP-UX, $(UNIXNAME)), HP-UX) + SYSLIB = -lpthread + CFLAGS += -DHP_UX -DHPUX11 + PLAT_NAME=hp-ux +endif + +#Find system type. +ifneq ($(SYSPATH),) + CHECKSYSRES = @echo "System is $(shell uname -sm)" +endif +########################################################### + +ACL_PATH = ../../../lib_acl +ACL_LIB = $(ACL_PATH)/lib +ACL_INC = $(ACL_PATH)/include + +CFLAGS += -I. -I$(ACL_INC) +COMPILE = $(CC) $(CFLAGS) + +EXTLIBS = +LDFLAGS = -L$(ACL_LIB) -l_acl $(EXTLIBS) $(SYSLIB) +LINKS = $(CC) -o $(PROG) $(OBJS) $(LDFLAGS) + +OUT_PATH = ./ +OBJ_PATH = $(OUT_PATH) + +#Project's objs +SRCS = $(wildcard *.c) +OBJS = $(patsubst %.c,$(OBJ_PATH)%.o,$(SRCS)) + +########################################################### + +.PHONY = all RM clean + +PROG = + +all: RM $(PROG) + +RM: + rm -f $(PROG) + +all: $(OBJS) + $(LINKS) + +$(OBJ_PATH)%.o: %.c *.h + $(COMPILE) -o $@ $< + +clean: + rm -f $(OBJS) $(PROG) + +rebuild: clean all diff --git a/samples/master/Makefile.in.dynamic b/samples/master/Makefile.in.dynamic new file mode 100644 index 000000000..0180c2ad1 --- /dev/null +++ b/samples/master/Makefile.in.dynamic @@ -0,0 +1,102 @@ +SHELL = /bin/sh +CC = gcc + +CFLAGS = -c -g -W -Wall -Wcast-qual -Wcast-align \ +-Waggregate-return -Wmissing-prototypes \ +-Wpointer-arith -Werror -Wshadow -pedantic -O2 \ +-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO \ +-Wno-long-long +########################################################### +#Check system: +# Linux, SunOS, Solaris, BSD variants, AIX, HP-UX +SYSLIB = +CHECKSYSRES = @echo "Unknow system type!";exit 1 +UNIXNAME = $(shell uname -sm) + +# For FreeBSD +ifeq ($(findstring FreeBSD, $(UNIXNAME)), FreeBSD) + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DFREEBSD -D_REENTRANT -pedantic + SYSLIB = -lpthread +endif + +#Path for Linux +ifeq ($(findstring Linux, $(UNIXNAME)), Linux) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DLINUX2 + SYSLIB = -lcrypt -lpthread +endif + +#Path for SunOS +ifeq ($(findstring SunOS, $(UNIXNAME)), SunOS) + ifeq ($(findstring 86, $(UNIXNAME)), 86) + SYSLIB = -lsocket -lnsl -lrt + endif + ifeq ($(findstring sun4u, $(UNIXNAME)), sun4u) + SYSLIB = -lsocket -lnsl -lrt + endif + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DSUNOS5 +endif + +#Path for HP-UX +ifeq ($(findstring HP-UX, $(UNIXNAME)), HP-UX) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + SYSLIB = -lpthread + CFLAGS += -DHP_UX -DHPUX11 + PLAT_NAME=hp-ux +endif + +#Find system type. +ifneq ($(SYSPATH),) + CHECKSYSRES = @echo "System is $(shell uname -sm)" +endif +########################################################### + +ACL_PATH = ../../../lib_acl +ACL_LIB = $(ACL_PATH)/lib +ACL_INC = $(ACL_PATH)/include + +CFLAGS += -I. -I$(ACL_INC) +COMPILE = $(CC) $(CFLAGS) + +EXTLIBS = +LDFLAGS = -Wl,-rpath,/opt/inc365/lib -Wl,-rpath, -L$(ACL_LIB) -l_acl $(EXTLIBS) $(SYSLIB) +LINKS = $(CC) -o $(PROG) $(OBJS) $(LDFLAGS) + +OUT_PATH = ./ +OBJ_PATH = $(OUT_PATH) + +#Project's objs +SRCS = $(wildcard *.c) +OBJS = $(patsubst %.c,$(OBJ_PATH)%.o,$(SRCS)) + +########################################################### + +.PHONY = all RM clean + +PROG = + +all: RM $(PROG) + +RM: + rm -f $(PROG) + +all: $(OBJS) + $(LINKS) + +$(OBJ_PATH)%.o: %.c *.h + $(COMPILE) -o $@ $< + +clean: + rm -f $(OBJS) $(PROG) + +rebuild: clean all diff --git a/samples/master/aio_echo/Makefile b/samples/master/aio_echo/Makefile new file mode 100644 index 000000000..5454fec4d --- /dev/null +++ b/samples/master/aio_echo/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = aio_echo diff --git a/samples/master/aio_echo/aio_echo.cf b/samples/master/aio_echo/aio_echo.cf new file mode 100644 index 000000000..1d49939b5 --- /dev/null +++ b/samples/master/aio_echo/aio_echo.cf @@ -0,0 +1,92 @@ + +service server { +# 进程是否禁止运行 + master_disable = yes +# 服务地址及端口号 + master_service = 5200 + +# 服务监听为域套接口 +# master_service = aio_echo.sock +# 服务类型 + master_type = inet + +# 当子进程异常退出时,如果该值非空,则将子进程异常退出的消息通知该服务 +# master_notify_addr = 127.0.0.1:5801 +# 邮件通知接收者 +# master_notify_recipients = zhengshuxin@hotmail.com + +# 是否允许延迟接受客户端连接,如果为0则表示关闭该功能,如果大于0则表示打开此功能 +# 并且此值代表延迟接受连接的超时值,超过此值时如果客户端依然没有发来数据,则操作 +# 系统会在系统层直接关闭该连接 +# master_defer_accept = 0 +# master_type = unix +# 是否只允许私有访问, 如果为 y, 则域套接口创建在 {install_path}/var/log/private/ 目录下, +# 如果为 n, 则域套接口创建在 {install_path}/var/log/public/ 目录下, + master_private = n + master_unpriv = n +# 是否需要 chroot: n -- no, y -- yes + master_chroot = n +# 每隔多长时间触发一次,单位为秒(仅对 trigger 模式有效) + master_wakeup = - +# 最大进程数 + master_maxproc = 5 +# 需要预先启动的进程数,该值不应大于 master_maxproc + master_prefork = 2 +# 进程程序名 + master_command = aio_echo +# 进程启动参数,只能为: -u [是否允许以某普通用户的身份运行] + master_args = +# 传递给服务子进程的环境变量, 可以通过 getenv("SERVICE_ENV") 获得此值 + master_env = mempool_limit:512000000, mempool_use_mutex:true +# master_env = logme:FALSE, priority:E_LOG_INFO, action:E_LOG_PER_DAY, flush:sync_flush, imit_size:512,\ +# sync_action:E_LOG_SEM, sem_name:/tmp/aio_echo.sem +# 进程日志记录文件 + master_log = {install_path}/var/log/aio_echo.log + +# 是否允许产生 core 文件 +# aio_enable_core = 1 +# 每个进程实例处理连接数的最大次数,超过此值后进程实例主动退出 + aio_use_limit = 0 +# 每个进程实例的空闲超时时间,超过此值后进程实例主动退出 + aio_idle_limit = 0 +# 记录进程PID的位置(对于多进程实例来说没有意义) + aio_pid_dir = {install_path}/var/pid +# 进程运行时所在的路径 + aio_queue_dir = {install_path}/var +# 读写超时时间, 单位为秒 + aio_rw_timeout = 120 +# 读缓冲区的缓冲区大小 + aio_buf_size = 8192 +# 每次 accept 时的循环接收的最大次数 + aio_max_accept = 25 +# 进程运行时的用户身份 + aio_owner = root + +# 用 select 进行循环时的时间间隔 +# 单位为秒 + aio_delay_sec = 1 +# 单位为微秒 + aio_delay_usec = 500 +# 采用事件循环的方式: select(default), poll, kernel(epoll/devpoll/kqueue) + aio_event_mode = select +# 是否将 socket 接收与IO功能分开: yes/no, 如果为 yes 可以大大提高 accept() 速度 + aio_accept_alone = yes +# 线程池的最大线程数, 如果该值为0则表示采用单线程非阻塞模式. + aio_max_threads = 0 +# 每个线程的空闲时间. + aio_thread_idle_limit = 60 + +# 允许访问的客户端IP地址范围 + aio_access_allow = 127.0.0.1:255.255.255.255, 127.0.0.1:127.0.0.1 + +# 当 acl_master 退出时,如果该值置1则该程序不等所有连接处理完毕便立即退出 + aio_quick_abort = 1 +############################################################################ +# 应用自己的配置选项 + +# 每个客户端连接的空闲时间. + client_idle_limit = 60 +# 是否输出当前的内存状态信息 + debug_mem = 1 +} + diff --git a/samples/master/aio_echo/main.c b/samples/master/aio_echo/main.c new file mode 100644 index 000000000..fd16ddd21 --- /dev/null +++ b/samples/master/aio_echo/main.c @@ -0,0 +1,19 @@ +#include "lib_acl.h" +#include "service_main.h" + +int main(int argc, char *argv[]) +{ +/* acl_debug_malloc_init("log.txt"); */ + acl_aio_app_main(argc, argv, service_main, NULL, + ACL_APP_CTL_INIT_FN, service_init, + /* ACL_APP_CTL_INIT_CTX, NULL, */ + ACL_APP_CTL_EXIT_FN, service_exit, + /* ACL_APP_CTL_EXIT_CTX, NULL, */ + ACL_APP_CTL_CFG_BOOL, service_conf_bool_tab, + ACL_APP_CTL_CFG_INT, service_conf_int_tab, + ACL_APP_CTL_CFG_STR, service_conf_str_tab, + ACL_APP_CTL_END); + + exit (0); +} + diff --git a/samples/master/aio_echo/service_main.c b/samples/master/aio_echo/service_main.c new file mode 100644 index 000000000..3f46eb715 --- /dev/null +++ b/samples/master/aio_echo/service_main.c @@ -0,0 +1,61 @@ +#include "lib_acl.h" +#include +#include + +#include "service_main.h" + +/* configure info */ + +/* TODO: you can add configure items here */ + +static int var_cfg_debug_mem; + +ACL_CONFIG_BOOL_TABLE service_conf_bool_tab[] = { + /* TODO: you can add configure variables of int type here */ + { "debug_mem", 0, &var_cfg_debug_mem }, + + { 0, 0, 0 }, +}; + +static int var_cfg_io_idle_limit; +static int var_cfg_debug_mem; + +ACL_CONFIG_INT_TABLE service_conf_int_tab[] = { + /* TODO: you can add configure variables of int type here */ + + { "io_idle_limit", 60, &var_cfg_io_idle_limit, 0, 0 }, + + { 0, 0, 0, 0, 0 }, +}; + +ACL_CONFIG_STR_TABLE service_conf_str_tab[] = { + + /* TODO: you can add configure variables of (char *) type here */ + /* example: { "mysql_dbaddr", "127.0.0.1:3306", &var_cfg_mysql_dbaddr }, */ + + { 0, 0, 0 }, +}; + +void service_init(void *init_ctx acl_unused) +{ +} + +void service_exit(void *exist_ctx acl_unused) +{ +} + +static int read_callback(ACL_ASTREAM *client, void *ctx acl_unused, char *data, int dlen) +{ + acl_aio_writen(client, data, dlen); + return (0); +} + +int service_main(ACL_ASTREAM *client, void *run_ctx acl_unused) +{ + acl_aio_ctl(client, + ACL_AIO_CTL_READ_HOOK_ADD, read_callback, run_ctx, + ACL_AIO_CTL_TIMEOUT, 300, + ACL_AIO_CTL_END); + acl_aio_gets(client); + return (0); +} diff --git a/samples/master/aio_echo/service_main.h b/samples/master/aio_echo/service_main.h new file mode 100644 index 000000000..c43f0f687 --- /dev/null +++ b/samples/master/aio_echo/service_main.h @@ -0,0 +1,42 @@ + +#ifndef __SERVICE_MAIN_INCLUDE_H__ +#define __SERVICE_MAIN_INCLUDE_H__ + +#include "lib_acl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* 配置文件项 */ +/* in service_main.c */ + +extern ACL_CONFIG_BOOL_TABLE service_conf_bool_tab[]; +extern ACL_CONFIG_INT_TABLE service_conf_int_tab[]; +extern ACL_CONFIG_STR_TABLE service_conf_str_tab[]; + +/** + * 初始化函数,服务器模板框架启动后仅调用该函数一次 + * @param init_ctx {void*} 用户自定义类型指针, 可以在调用 + * app_main() 时引入 + */ +extern void service_init(void *init_ctx); + +/** + * 进程退出时的回调函数 + * @param exist_ctx {void*} 用户自定义类型指针 + */ +extern void service_exit(void *exit_ctx); + +/** + * 协议处理函数入口 + * @param stream {ACL_VSTREAM*} 客户端数据连接流 + * @param run_ctx {void*} 用户自定义类型指针 + */ +extern int service_main(ACL_ASTREAM *astream, void *run_ctx); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/samples/master/aio_proxy/Makefile b/samples/master/aio_proxy/Makefile new file mode 100644 index 000000000..5befb58ca --- /dev/null +++ b/samples/master/aio_proxy/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = aio_proxy diff --git a/samples/master/aio_proxy/Makefile.dynamic b/samples/master/aio_proxy/Makefile.dynamic new file mode 100644 index 000000000..90101946f --- /dev/null +++ b/samples/master/aio_proxy/Makefile.dynamic @@ -0,0 +1,4 @@ +include ../Makefile.in.dynamic +CFLAGS += -I/opt/import_lib/include/cgi +EXTLIBS += -L/opt/import_lib/lib -ltpl +PROG = aio_proxy diff --git a/samples/master/aio_proxy/aio_proxy.cf b/samples/master/aio_proxy/aio_proxy.cf new file mode 100644 index 000000000..88817dbd1 --- /dev/null +++ b/samples/master/aio_proxy/aio_proxy.cf @@ -0,0 +1,100 @@ + +service server { +# 进程是否禁止运行 + master_disable = yes +# 服务地址及端口号 + master_service = 16667 + +# 服务监听为域套接口 +# master_service = aio_echo.sock +# 服务类型 + master_type = inet + +# 当子进程异常退出时,如果该值非空,则将子进程异常退出的消息通知该服务 +# master_notify_addr = 127.0.0.1:5801 +# 邮件通知接收者 +# master_notify_recipients = zhengshuxin@hotmail.com + +# 是否允许延迟接受客户端连接,如果为0则表示关闭该功能,如果大于0则表示打开此功能 +# 并且此值代表延迟接受连接的超时值,超过此值时如果客户端依然没有发来数据,则操作 +# 系统会在系统层直接关闭该连接 +# master_defer_accept = 0 +# master_type = unix +# 是否只允许私有访问, 如果为 y, 则域套接口创建在 {install_path}/var/log/private/ 目录下, +# 如果为 n, 则域套接口创建在 {install_path}/var/log/public/ 目录下, + master_private = n + master_unpriv = n +# 是否需要 chroot: n -- no, y -- yes + master_chroot = n +# 每隔多长时间触发一次,单位为秒(仅对 trigger 模式有效) + master_wakeup = - +# 最大进程数 + master_maxproc = 5 +# 需要预先启动的进程数,该值不应大于 master_maxproc + master_prefork = 0 +# 进程程序名 + master_command = aio_proxy +# 进程启动参数,只能为: -u [是否允许以某普通用户的身份运行] + master_args = +# 传递给服务子进程的环境变量, 可以通过 getenv("SERVICE_ENV") 获得此值 +# master_env = mempool_limit:512000000, mempool_use_mutex:true +# master_env = logme:FALSE, priority:E_LOG_INFO, action:E_LOG_PER_DAY, flush:sync_flush, imit_size:512,\ +# sync_action:E_LOG_SEM, sem_name:/tmp/aio_echo.sem +# 进程日志记录文件 + master_log = {install_path}/var/log/aio_proxy.log + +# 是否允许产生 core 文件 +# aio_enable_core = 1 +# 每个进程实例处理连接数的最大次数,超过此值后进程实例主动退出 + aio_use_limit = 0 +# 每个进程实例的空闲超时时间,超过此值后进程实例主动退出 + aio_idle_limit = 0 +# 记录进程PID的位置(对于多进程实例来说没有意义) + aio_pid_dir = {install_path}/var/pid +# 进程运行时所在的路径 + aio_queue_dir = {install_path}/var +# 读写超时时间, 单位为秒 + aio_rw_timeout = 120 +# 读缓冲区的缓冲区大小 + aio_buf_size = 8192 +# 每次 accept 时的循环接收的最大次数 + aio_max_accept = 25 +# 进程运行时的用户身份 + aio_owner = root + +# 用 select 进行循环时的时间间隔 +# 单位为秒 + aio_delay_sec = 1 +# 单位为微秒 + aio_delay_usec = 500 +# 采用事件循环的方式: select(default), poll, kernel(epoll/devpoll/kqueue) + aio_event_mode = select +# 是否将 socket 接收与IO功能分开: yes/no, 如果为 yes 可以大大提高 accept() 速度 + aio_accept_alone = yes +# 线程池的最大线程数, 如果该值为0则表示采用单线程非阻塞模式. + aio_max_threads = 0 +# 每个线程的空闲时间. + aio_thread_idle_limit = 60 + +# 允许访问的客户端IP地址范围 + aio_access_allow = 127.0.0.1:255.255.255.255, 127.0.0.1:127.0.0.1 + +# 当 acl_master 退出时,如果该值置1则该程序不等所有连接处理完毕便立即退出 + aio_quick_abort = 1 +############################################################################ +# 应用自己的配置选项 + +# 每个客户端连接的空闲时间. + io_idle_limit = 60 +# 是否输出当前的内存状态信息 + debug_mem = 1 +# 是否以行为单位读数据 + read_line = 1 +# 后端服务器地址 + backend_addr = 127.0.0.1:6667 +# 请求数据转存文件 + request_file = {install_path}/var/log/irc.txt +# 响应数据转存文件 + respond_file = {install_path}/var/log/irc.txt +} + diff --git a/samples/master/aio_proxy/main.c b/samples/master/aio_proxy/main.c new file mode 100644 index 000000000..fd16ddd21 --- /dev/null +++ b/samples/master/aio_proxy/main.c @@ -0,0 +1,19 @@ +#include "lib_acl.h" +#include "service_main.h" + +int main(int argc, char *argv[]) +{ +/* acl_debug_malloc_init("log.txt"); */ + acl_aio_app_main(argc, argv, service_main, NULL, + ACL_APP_CTL_INIT_FN, service_init, + /* ACL_APP_CTL_INIT_CTX, NULL, */ + ACL_APP_CTL_EXIT_FN, service_exit, + /* ACL_APP_CTL_EXIT_CTX, NULL, */ + ACL_APP_CTL_CFG_BOOL, service_conf_bool_tab, + ACL_APP_CTL_CFG_INT, service_conf_int_tab, + ACL_APP_CTL_CFG_STR, service_conf_str_tab, + ACL_APP_CTL_END); + + exit (0); +} + diff --git a/samples/master/aio_proxy/service_main.c b/samples/master/aio_proxy/service_main.c new file mode 100644 index 000000000..b236f4f67 --- /dev/null +++ b/samples/master/aio_proxy/service_main.c @@ -0,0 +1,205 @@ +#include +#include + +#include "lib_acl.h" + +#include "service_main.h" + +typedef struct { + ACL_ASTREAM *client; + ACL_ASTREAM *server; +} STREAM_PIPE; + +/* configure info */ + +/* TODO: you can add configure items here */ + +static int var_cfg_debug_mem; +static int var_cfg_read_line; + +ACL_CONFIG_BOOL_TABLE service_conf_bool_tab[] = { + /* TODO: you can add configure variables of int type here */ + { "debug_mem", 0, &var_cfg_debug_mem }, + { "read_line", 1, &var_cfg_read_line }, + + { 0, 0, 0 }, +}; + +static int var_cfg_io_idle_limit; +static int var_cfg_debug_mem; + +ACL_CONFIG_INT_TABLE service_conf_int_tab[] = { + /* TODO: you can add configure variables of int type here */ + + { "io_idle_limit", 60, &var_cfg_io_idle_limit, 0, 0 }, + + { 0, 0, 0, 0, 0 }, +}; + +static char *var_cfg_backend_addr; +static char *var_cfg_request_file; +static char *var_cfg_respond_file; + +ACL_CONFIG_STR_TABLE service_conf_str_tab[] = { + + /* TODO: you can add configure variables of (char *) type here */ + /* example: { "mysql_dbaddr", "127.0.0.1:3306", &var_cfg_mysql_dbaddr }, */ + + { "backend_addr", "127.0.0.1:3306", &var_cfg_backend_addr }, + { "request_file", "./request.txt", &var_cfg_request_file }, + { "respond_file", "./respond.txt", &var_cfg_respond_file }, + + { 0, 0, 0 }, +}; + +static ACL_FILE *request_fp, *respond_fp; + +void service_init(void *init_ctx acl_unused) +{ + const char *myname = "service_init"; + + request_fp = acl_fopen(var_cfg_request_file, "a+"); + if (request_fp == NULL) + acl_msg_error("%s(%d): open %s error(%s)", + myname, __LINE__, var_cfg_request_file, + acl_last_serror()); + respond_fp = acl_fopen(var_cfg_respond_file, "a+"); + if (respond_fp == NULL) + acl_msg_error("%s(%d): open %s error(%s)", + myname, __LINE__, var_cfg_respond_file, + acl_last_serror()); +} + +void service_exit(void *exist_ctx acl_unused) +{ + if (request_fp) + acl_fclose(request_fp); + if (respond_fp) + acl_fclose(respond_fp); +} + +static int close_callback(ACL_ASTREAM *stream, void *ctx) +{ + STREAM_PIPE *sp = (STREAM_PIPE*) ctx; + + if (sp->client == stream) { + if (sp->server) + acl_aio_iocp_close(sp->server); + sp->client = NULL; + } else if (sp->server == stream) { + if (sp->client) + acl_aio_iocp_close(sp->client); + sp->server = NULL; + } + if (sp->client == NULL && sp->server == NULL) + acl_myfree(sp); + return (0); +} + +static int read_callback(ACL_ASTREAM *stream, void *ctx, char *data, int dlen) +{ + const char *myname = "read_callback"; + STREAM_PIPE *sp = (STREAM_PIPE*) ctx; + + if (sp->client == stream) { + if (request_fp) { + if (var_cfg_read_line) { + if (acl_fprintf(request_fp, ">>>%s", data) == EOF) { + acl_msg_error("%s(%d): write to %s error(%s)", + myname, __LINE__, var_cfg_request_file, + acl_last_serror()); + acl_fclose(request_fp); + request_fp = NULL; + } + } else { + if (acl_fwrite(data, dlen, 1, request_fp) == (size_t) EOF) { + acl_msg_error("%s(%d): write to %s error(%s)", + myname, __LINE__, var_cfg_request_file, + acl_last_serror()); + acl_fclose(request_fp); + request_fp = NULL; + } + } + } + if (sp->server == NULL) + return (-1); + acl_aio_writen(sp->server, data, dlen); + } else if (sp->server == stream) { + if (respond_fp) { + if (var_cfg_read_line) { + if (acl_fprintf(respond_fp, "<<<%s", data) == EOF) { + acl_msg_error("%s(%d): write to %s error(%s)", + myname, __LINE__, var_cfg_respond_file, + acl_last_serror()); + acl_fclose(respond_fp); + respond_fp = NULL; + } + } else { + if (acl_fwrite(data, dlen, 1, respond_fp) == (size_t) EOF) { + acl_msg_error("%s(%d): write to %s error(%s)", + myname, __LINE__, var_cfg_respond_file, + acl_last_serror()); + acl_fclose(respond_fp); + respond_fp = NULL; + } + } + } + if (sp->client == NULL) + return (-1); + acl_aio_writen(sp->client, data, dlen); + } else { + return (-1); + } + + return (0); +} + +static int connect_callback(ACL_ASTREAM *stream, void *ctx) +{ + const char *myname = "connect_callback"; + STREAM_PIPE *sp = (STREAM_PIPE*) ctx; + + if (sp->server != stream) + acl_msg_fatal("%s(%d): sp->server != stream", myname, __LINE__); + + if (var_cfg_read_line) + acl_aio_gets(sp->server); + else + acl_aio_read(sp->server); + if (sp->client == NULL) + return (-1); + if (var_cfg_read_line) + acl_aio_gets(sp->client); + else + acl_aio_read(sp->client); + return (0); +} + +int service_main(ACL_ASTREAM *astream, void *run_ctx acl_unused) +{ + const char *myname = "service_main"; + STREAM_PIPE *sp = (STREAM_PIPE*) acl_mycalloc(1, sizeof(STREAM_PIPE)); + + acl_msg_info("%s: begin connect %s", myname, var_cfg_backend_addr); + sp->client = astream; + sp->server = acl_aio_connect(acl_aio_handle(astream), + var_cfg_backend_addr, 10); + if (sp->server == NULL) { + acl_msg_error("%s(%d): connect %s error(%s)", myname, + __LINE__, var_cfg_backend_addr, acl_last_serror()); + acl_aio_iocp_close(astream); + acl_myfree(sp); + return (-1); + } + + acl_aio_ctl(sp->server, ACL_AIO_CTL_CONNECT_HOOK_ADD, connect_callback, sp, + ACL_AIO_CTL_CLOSE_HOOK_ADD, close_callback, sp, + ACL_AIO_CTL_READ_HOOK_ADD, read_callback, sp, + ACL_AIO_CTL_TIMEOUT, 300, + ACL_AIO_CTL_END); + acl_aio_ctl(sp->client, ACL_AIO_CTL_CLOSE_HOOK_ADD, close_callback, sp, + ACL_AIO_CTL_READ_HOOK_ADD, read_callback, sp, + ACL_AIO_CTL_TIMEOUT, 300, + ACL_AIO_CTL_END); + return (0); +} diff --git a/samples/master/aio_proxy/service_main.h b/samples/master/aio_proxy/service_main.h new file mode 100644 index 000000000..c43f0f687 --- /dev/null +++ b/samples/master/aio_proxy/service_main.h @@ -0,0 +1,42 @@ + +#ifndef __SERVICE_MAIN_INCLUDE_H__ +#define __SERVICE_MAIN_INCLUDE_H__ + +#include "lib_acl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* 配置文件项 */ +/* in service_main.c */ + +extern ACL_CONFIG_BOOL_TABLE service_conf_bool_tab[]; +extern ACL_CONFIG_INT_TABLE service_conf_int_tab[]; +extern ACL_CONFIG_STR_TABLE service_conf_str_tab[]; + +/** + * 初始化函数,服务器模板框架启动后仅调用该函数一次 + * @param init_ctx {void*} 用户自定义类型指针, 可以在调用 + * app_main() 时引入 + */ +extern void service_init(void *init_ctx); + +/** + * 进程退出时的回调函数 + * @param exist_ctx {void*} 用户自定义类型指针 + */ +extern void service_exit(void *exit_ctx); + +/** + * 协议处理函数入口 + * @param stream {ACL_VSTREAM*} 客户端数据连接流 + * @param run_ctx {void*} 用户自定义类型指针 + */ +extern int service_main(ACL_ASTREAM *astream, void *run_ctx); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/samples/master/ioctl_echo/Makefile b/samples/master/ioctl_echo/Makefile new file mode 100644 index 000000000..6b23a5012 --- /dev/null +++ b/samples/master/ioctl_echo/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = ioctl_echo diff --git a/samples/master/ioctl_echo/app_main.c b/samples/master/ioctl_echo/app_main.c new file mode 100644 index 000000000..2543a87c5 --- /dev/null +++ b/samples/master/ioctl_echo/app_main.c @@ -0,0 +1,357 @@ +#include "lib_acl.h" + +#include +#include +#include +#include + +#include "app_main.h" + +typedef struct APP_HANDLE { + char name[256]; +} APP_HANDLE; + +static APP_RUN_FN __run_fn = NULL; +static void *__run_ctx = NULL; + +/* 客户端IO超时时间值 */ +int app_var_client_idle_limit = 60; + +static ACL_CONFIG_INT_TABLE __conf_int_tab[] = { + /* TODO: you can add configure variables of int type here */ + { "app_client_idle_limit", 120, &app_var_client_idle_limit, 0, 0 }, + { 0, 0, 0, 0, 0 }, +}; + +static char *__default_deny_info = "You are not welcome!\r\n"; +static char *__deny_info; +/*----------------------------------------------------------------------------*/ + +/** + * 创建一个服务器框架 + * @return APP_HANDLE* 用户自己的应用数据句柄. + */ + +static APP_HANDLE *app_create(void) +{ + char myname[] = "app_create"; + APP_HANDLE *app; + + app = (APP_HANDLE *) acl_mycalloc(1, sizeof(APP_HANDLE)); + if (app == NULL) + acl_msg_fatal("%s(%d): calloc error(%s)", + myname, __LINE__, strerror(errno)); + + ACL_SAFE_STRNCPY(app->name, myname, sizeof(app->name)); + + return (app); +} +/*----------------------------------------------------------------------------*/ +static void __read_notify_callback(int event_type, + ACL_IOCTL *h_ioctl, + ACL_VSTREAM *cstream, + void *context) +{ + char myname[] = "__read_notify_callback"; + APP_HANDLE *app; + int ret; + + app = (APP_HANDLE *) context; + + switch (event_type) { + case ACL_EVENT_READ: + ret = __run_fn(cstream, __run_ctx); + if (ret < 0) { + acl_vstream_close(cstream); + } else if (ret == 0) { + if (acl_msg_verbose) + acl_msg_info("enable(%s), fd=%d, h_ioctl(%p)", + myname, ACL_VSTREAM_SOCK(cstream), (void*) h_ioctl); + acl_ioctl_enable_read(h_ioctl, + cstream, + app_var_client_idle_limit, + __read_notify_callback, + (void *) app); + + } + break; + case ACL_EVENT_RW_TIMEOUT: + case ACL_EVENT_XCPT: + acl_vstream_close(cstream); + break; + default: + acl_msg_fatal("%s, %s(%d): unknown event type(%d)", + __FILE__, myname, __LINE__, event_type); + /* not reached */ + break; + } + if (acl_msg_verbose) + acl_msg_info("%s(%d): total alloc: %d", + myname, __LINE__, acl_mempool_total_allocated()); +} + +/** + * 向任务池中添加一个工作任务 + * @param h_ioctl 服务器任务池句柄 + * @param app_handle 用户自己的应用数据句柄. + * @param cstream 客户端数据流指针 + * 注: cstream 数据流会在该函数内部的回调函数中进行关闭, 所以该函数的调用者不要 + * 关闭该流. + */ + +static void app_add_worker(ACL_IOCTL *h_ioctl, APP_HANDLE *app, ACL_VSTREAM *cstream) +{ + const char *myname = "app_add_worker"; + + if (h_ioctl == NULL || cstream == NULL || app == NULL) + acl_msg_fatal("%s(%d): input invalid", myname, __LINE__); + + /* 将客户端数据流的状态置入事件监控集合中 */ + if (acl_msg_verbose) + acl_msg_info("%s(%d): ioctl=%p, fd=%d", + myname, __LINE__, (void*) h_ioctl, ACL_VSTREAM_SOCK(cstream)); + + acl_ioctl_enable_read(h_ioctl, + cstream, + app_var_client_idle_limit, + __read_notify_callback, + (void *) app); +} +/*---------------------- app main functions ----------------------------------*/ + +static int __mempool_limit = 0; + +static APP_HANDLE *__app_handle = NULL; + +static APP_INIT_FN __app_init_fn = NULL; +static void *__app_init_ctx = NULL; +static APP_EXIT_FN __app_exit_fn = NULL; +static void *__app_exit_ctx = NULL; +static APP_THREAD_INIT_FN __app_thread_init_fn = NULL; +static APP_THREAD_EXIT_FN __app_thread_exit_fn = NULL; + +static void __service(ACL_IOCTL *h_ioctl, ACL_VSTREAM *stream, + char *service acl_unused, char **argv acl_unused) +{ + char myname[] = "__service"; + char ip[64]; + + /* + * Sanity check. This service takes no command-line arguments. + */ + if (argv[0]) + acl_msg_fatal("%s, %s(%d): unexpected command-line argument: %s, service=%s", + __FILE__, myname, __LINE__, argv[0], service ? service : "null"); + acl_watchdog_pat(); + + if (isatty(ACL_VSTREAM_SOCK(stream))) { + stream->rw_timeout = app_var_client_idle_limit; + (void) __run_fn(stream, __run_ctx); + return; + } + + if (acl_getpeername(ACL_VSTREAM_SOCK(stream), ip, sizeof(ip)) < 0) { + acl_msg_warn("%s, %s(%d): can't get socket's ip", + __FILE__, myname, __LINE__); + acl_vstream_close(stream); + } else if (!acl_access_permit(ip)) { + acl_msg_warn("%s, %s(%d): ip(%s) be denied", + __FILE__, myname, __LINE__, ip); + (void) acl_vstream_writen(stream, __deny_info, strlen(__deny_info)); + acl_vstream_close(stream); + } else { + stream->rw_timeout = app_var_client_idle_limit; + app_add_worker(h_ioctl, __app_handle, stream); + } +} + +static void __pre_accept(char *name acl_unused, char **argv acl_unused) +{ +} + +static void __pre_jail_init(char *name acl_unused, char **argv acl_unused) +{ + acl_get_app_conf_int_table(__conf_int_tab); +} + +static void __post_jail_init(char *name acl_unused, char **argv acl_unused) +{ + char myname[] = "__post_jail_init"; + + if (acl_var_ioctl_access_allow != NULL) + acl_access_add(acl_var_ioctl_access_allow, ",", ":"); + + __app_handle = app_create(); + if (__app_handle == NULL) + acl_msg_fatal("%s(%d): ioctl_create error(%s)", + myname, __LINE__, strerror(errno)); + + if (__app_init_fn != NULL) + __app_init_fn(__app_init_ctx); + + if (__mempool_limit > 0) { + acl_msg_info("use mempool, size limit is %d, use mutex", + __mempool_limit); + } + + /* TODO: you can add some init functions here */ +} + +static void __app_on_exit(char *service acl_unused, char **argv acl_unused) +{ + if (__app_exit_fn) + __app_exit_fn(__app_exit_ctx); +} + +static void __thread_init(void *arg) +{ + if (__app_thread_init_fn) + __app_thread_init_fn(arg); +} + +static void __thread_exit(void *arg) +{ + if (__app_thread_exit_fn) + __app_thread_exit_fn(arg); +} + +static void app_main_init(void) +{ + char *ptr, *pname; + ACL_ARGV *env_argv; + int i; + + __deny_info = __default_deny_info; + ptr = getenv("SERVICE_ENV"); + if (ptr == NULL || *ptr == 0) + return; + + env_argv = acl_argv_split(ptr, ",\t "); + if (env_argv == NULL) + return; + if (env_argv->argc == 0) { + acl_argv_free(env_argv); + return; + } + + for (i = 0; i argc; i++) { + pname = acl_argv_index(env_argv, i); + ptr = strchr(pname, ':'); + if (ptr == NULL) + continue; + *ptr++ = 0; + if (ptr == 0) + continue; + if (strcasecmp(pname, "mempool_limit") == 0) { + __mempool_limit = atoi(ptr); + break; + } + } + + acl_argv_free(env_argv); + + /* 因为是多线程程序,所以需要加互斥锁 */ + if (__mempool_limit > 0) + acl_mempool_open(__mempool_limit, 1); +} + +static ACL_CONFIG_BOOL_TABLE null_conf_bool_tab[] = { + /* TODO: you can add configure variables of int type here */ + { 0, 0, 0 }, +}; + +static ACL_CONFIG_INT_TABLE null_conf_int_tab[] = { + /* TODO: you can add configure variables of int type here */ + { 0, 0, 0, 0, 0 }, +}; + +static ACL_CONFIG_STR_TABLE null_conf_str_tab[] = { + /* TODO: you can add configure variables of int type here */ + { 0, 0, 0 }, +}; + +void app_main(int argc, char *argv[], APP_RUN_FN run_fn, void *run_ctx, int name, ...) +{ + const char *myname = "app_main"; + va_list ap; + ACL_CONFIG_BOOL_TABLE *bool_tab = null_conf_bool_tab; + ACL_CONFIG_INT_TABLE *int_tab = null_conf_int_tab; + ACL_CONFIG_STR_TABLE *str_tab = null_conf_str_tab; + void *thread_init_ctx = NULL, *thread_exit_ctx = NULL; + + app_main_init(); + + /* 提前进行模板初始化,以使日志尽早地打开 */ + acl_master_log_open(argv[0]); + + if (run_fn == NULL) + acl_msg_fatal("%s: run_fn null", myname); + + __run_fn = run_fn; + __run_ctx = run_ctx; + + va_start(ap, name); + + for (; name != APP_CTL_END; name = va_arg(ap, int)) { + switch (name) { + case APP_CTL_INIT_FN: + __app_init_fn = va_arg(ap, APP_INIT_FN); + break; + case APP_CTL_INIT_CTX: + __app_init_ctx = va_arg(ap, void *); + break; + + case APP_CTL_EXIT_FN: + __app_exit_fn = va_arg(ap, APP_EXIT_FN); + break; + case APP_CTL_EXIT_CTX: + __app_exit_ctx = va_arg(ap, void *); + break; + + case APP_CTL_THREAD_INIT: + __app_thread_init_fn = va_arg(ap, APP_THREAD_INIT_FN); + break; + case APP_CTL_THREAD_INIT_CTX: + thread_init_ctx = va_arg(ap, void*); + break; + + case APP_CTL_THREAD_EXIT: + __app_thread_exit_fn = va_arg(ap, APP_THREAD_EXIT_FN); + break; + case APP_CTL_THREAD_EXIT_CTX: + thread_exit_ctx = va_arg(ap, void*); + break; + + case APP_CTL_CFG_BOOL: + bool_tab = va_arg(ap, ACL_CONFIG_BOOL_TABLE *); + break; + case APP_CTL_CFG_INT: + int_tab = va_arg(ap, ACL_CONFIG_INT_TABLE *); + break; + case APP_CTL_CFG_STR: + str_tab = va_arg(ap, ACL_CONFIG_STR_TABLE *); + break; + case APP_CTL_DENY_INFO: + __deny_info = acl_mystrdup(va_arg(ap, const char*)); + break; + default: + acl_msg_fatal("%s: bad name(%d)", myname, name); + } + } + + va_end(ap); + + acl_ioctl_server_main(argc, argv, __service, + ACL_MASTER_SERVER_BOOL_TABLE, bool_tab, + ACL_MASTER_SERVER_INT_TABLE, int_tab, + ACL_MASTER_SERVER_STR_TABLE, str_tab, + ACL_MASTER_SERVER_PRE_INIT, __pre_jail_init, + ACL_MASTER_SERVER_PRE_ACCEPT, __pre_accept, + ACL_MASTER_SERVER_POST_INIT, __post_jail_init, + ACL_MASTER_SERVER_EXIT, __app_on_exit, + ACL_MASTER_SERVER_THREAD_INIT, __thread_init, + ACL_MASTER_SERVER_THREAD_EXIT, __thread_exit, + ACL_MASTER_SERVER_THREAD_INIT_CTX, thread_init_ctx, + ACL_MASTER_SERVER_THREAD_EXIT_CTX, thread_exit_ctx, + 0); +} diff --git a/samples/master/ioctl_echo/app_main.h b/samples/master/ioctl_echo/app_main.h new file mode 100644 index 000000000..7d0002922 --- /dev/null +++ b/samples/master/ioctl_echo/app_main.h @@ -0,0 +1,69 @@ +#ifndef __APP_MAIN_INCLUDE_H__ +#define __APP_MAIN_INCLUDE_H__ + +#include "lib_acl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* 客户端读写超时时间值 */ +extern int app_var_client_idle_limit; + +/* 用户级的运行函数类型, 当该函数返回值 != 0 时, 框架会自动关闭客户端流 */ +typedef int (*APP_RUN_FN)(ACL_VSTREAM *stream, void *run_ctx); + +/* 用户级的初始化函数类型 */ +typedef void (*APP_INIT_FN)(void*); +typedef void (*APP_EXIT_FN)(void*); + +typedef ACL_MASTER_SERVER_THREAD_INIT_FN APP_THREAD_INIT_FN /* void (*)(void*) */; +typedef ACL_MASTER_SERVER_THREAD_EXIT_FN APP_THREAD_EXIT_FN; /* void (*)(void*) */ + +#define APP_CTL_END 0 /* 参数控制结束标志 */ +#define APP_CTL_INIT_FN 1 /* 初始化函数 */ +#define APP_CTL_INIT_CTX 2 /* 初始化函数所用的参数 */ +#define APP_CTL_CFG_BOOL 3 /* 整数类型的配置参数表 */ +#define APP_CTL_CFG_INT 4 /* 整数类型的配置参数表 */ +#define APP_CTL_CFG_STR 5 /* 字符串类型的配置参数表 */ +#define APP_CTL_EXIT_FN 6 /* 当进程退出时的回调函数 */ +#define APP_CTL_EXIT_CTX 7 /* 进程退出时回调函数的参数 */ +#define APP_CTL_THREAD_INIT 8 /* 每个线程启动时的回调函数 */ +#define APP_CTL_THREAD_INIT_CTX 9 /* 线程启动时回调函数的参数 */ +#define APP_CTL_THREAD_EXIT 10 /* 线程退出时的回调函数 */ +#define APP_CTL_THREAD_EXIT_CTX 11 /* 线程退出时回调函数的参数 */ +#define APP_CTL_DENY_INFO 12 /* 当非法客户端访问时给出的提示信息 */ + +/*----------------------------------------------------------------------------*/ +/* in app_main.c */ + +/** + * 主函数入口, 用户级的初始化函数指针及运行函数指针通过控制参数进行注册, 主函数内部 + * 会在初始化时自动调用用户级初始化函数(APP_INIT_FN 类型), 当接收到允许访问的客户端 + * 连接时会自动调用用户(APP_RUN_FN 类型). + * 级的运行函数. + * @param argc "int main(int argc, char *argv[])" 中的 argc + * @param argv "int main(int argc, char *argv[])" 中的 argv + * @param run_fn 用户级运行主函数 + * @param run_ctx run_fn() 运行时的参数之一 + * @param name 控制参数中的第一个控制类型, 所支持的类型如上定义: APP_CTL_XXX + * 调用方式: APP_CTL_XXX, xxx; 其中 APP_CTL_END 为特殊的控制参数, 表示控制参数 + * 结束. + * @example: + * app_main(argc, argv, {run_fn}, {run_ctx}, + * APP_CTL_INIT_FN, {run_init_fn}, + * APP_CTL_INIT_CTX, {run_init_ctx}, + * APP_CTL_END); + * 注: app_main() 的所有参数中, argc, argv, run_fn, run_ctx(可以为NULL), APP_CTL_END + * 都是必需的. + */ + +extern void app_main(int argc, char *argv[], APP_RUN_FN run_fn, void *run_ctx, int name, ...); + +/*----------------------------------------------------------------------------*/ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/samples/master/ioctl_echo/ioctl_echo.cf b/samples/master/ioctl_echo/ioctl_echo.cf new file mode 100644 index 000000000..6882566c7 --- /dev/null +++ b/samples/master/ioctl_echo/ioctl_echo.cf @@ -0,0 +1,114 @@ + +service server { +# 进程是否禁止运行 + master_disable = yes +# 服务地址及端口号 + master_service = 127.0.0.1:5001 + +# 服务监听为域套接口 +# master_service = aio_echo.sock +# 服务类型 + master_type = inet +# master_type = unix + +# 当子进程异常退出时,如果该值非空,则将子进程异常退出的消息通知该服务 +# master_notify_addr = 127.0.0.1:5801 +# 邮件通知接收者 +# master_notify_recipients = zhengshuxin@hotmail.com:13910404316 + +# 是否允许延迟接受客户端连接,如果为0则表示关闭该功能,如果大于0则表示打开此功能 +# 并且此值代表延迟接受连接的超时值,超过此值时如果客户端依然没有发来数据,则操作 +# 系统会在系统层直接关闭该连接 +# master_defer_accept = 0 +# 是否只允许私有访问, 如果为 y, 则域套接口创建在 {install_path}/var/log/private/ 目录下, +# 如果为 n, 则域套接口创建在 {install_path}/var/log/public/ 目录下, + master_private = n + master_unpriv = n +# 是否需要 chroot: n -- no, y -- yes + master_chroot = n +# 每隔多长时间触发一次,单位为秒(仅对 trigger 模式有效) + master_wakeup = - +# 最大进程数 + master_maxproc = 2 +# 需要预先启动的进程数,该值不应大于 master_maxproc + master_prefork = 2 +# 进程程序名 + master_command = ioctl_echo +# 进程日志记录文件 + master_log = {install_path}/var/log/ioctl_echo.log +# 进程启动参数,只能为: -u [是否允许以某普通用户的身份运行] +# master_args = +# 传递给服务子进程的环境变量, 可以通过 getenv("SERVICE_ENV") 获得此值 + master_env = mempool_limit:512000000 +# master_env = logme:FALSE, priority:E_LOG_INFO, action:E_LOG_PER_DAY, flush:sync_flush, imit_size:512,\ +# sync_action:E_LOG_SEM, sem_name:/tmp/ioctl_echo.sem + +# 是否允许产生 core 文件 +# ioctl_enable_core = 1 +# 每个进程实例处理连接数的最大次数,超过此值后进程实例主动退出 + ioctl_use_limit = 100 +# 每个进程实例的空闲超时时间,超过此值后进程实例主动退出 + ioctl_idle_limit = 120 +# 记录进程PID的位置(对于多进程实例来说没有意义) + ioctl_pid_dir = {install_path}/var/pid +# 进程运行时所在的路径 + ioctl_queue_dir = {install_path}/var +# 读写超时时间, 单位为秒 + ioctl_rw_timeout = 120 +# 读缓冲区的缓冲区大小 + ioctl_buf_size = 8192 +# 每次 accept 时的循环接收的最大次数 + ioctl_max_accept = 25 +# 在并发访问量非常低的情况下,如访问量在 10 次/秒 以下时,可以找开此值(即赋为1),以加速事件循环过程, +# 从而防止服务进程阻塞在 select 上的时间过长而影响访问速度 +# ioctl_enable_dog = 0 +# 进程运行时的用户身份 + ioctl_owner = root + +# 用 select 进行循环时的时间间隔 +# 单位为秒 + ioctl_delay_sec = 0 +# 单位为微秒 + ioctl_delay_usec = 500 + +# 采用事件循环的方式: select(default), poll, kernel(epoll/devpoll/kqueue) + ioctl_event_mode = select + +# 线程池的最大线程数 + ioctl_max_threads = 250 +# 线程的堆栈空间大小,单位为字节,0表示使用系统缺省值 + ioctl_stacksize = 0 +# 允许访问 udserver 的客户端IP地址范围 + ioctl_access_allow = 127.0.0.1:255.255.255.255, 127.0.0.1:127.0.0.1 + +# 当 acl_master 退出时,如果该值置1则该程序不等所有连接处理完毕便立即退出 + ioctl_quick_abort = 1 + +## app_main.c 需要的参数项 +# 客户端连接的最大空闲时间阀值 + app_client_idle_limit = 12 + +############################################################################ +# 应用自己的配置选项 + +# mysql 服务地址 +# mysql_dbaddr = /tmp/mysql.sock +# mysql_dbaddr = 10.0.250.199:3306 +# 连接 mysql 数据库的连接池的最大值 +# mysql_dbmax = 200 +# ping mysql 连接的间隔时间, 以秒为单位 +# mysql_dbping = 10 +# mysql 连接空闲的时间间隔, 以秒为单位 +# mysql_dbtimeout = 30 + +# 数据库名称 +# mysql_dbname = ioctl_db +# 数据库访问用户 +# mysql_dbuser = ioctl_user +# 数据库用户访问密码 +# mysql_dbpass = 111111 + +# 是否输出当前内存的状态信息 + debug_mem = 1 +} + diff --git a/samples/master/ioctl_echo/main.c b/samples/master/ioctl_echo/main.c new file mode 100644 index 000000000..4bc283fe0 --- /dev/null +++ b/samples/master/ioctl_echo/main.c @@ -0,0 +1,18 @@ +#include "app_main.h" +#include "service_main.h" + +int main(int argc, char *argv[]) +{ + app_main(argc, argv, service_main, NULL, + APP_CTL_INIT_FN, service_init, + /* APP_CTL_INIT_CTX, NULL, */ + APP_CTL_EXIT_FN, service_exit, + /* APP_CTL_EXIT_CTX, NULL, */ + APP_CTL_CFG_BOOL, service_conf_bool_tab, + APP_CTL_CFG_INT, service_conf_int_tab, + APP_CTL_CFG_STR, service_conf_str_tab, + APP_CTL_END); + + exit (0); +} + diff --git a/samples/master/ioctl_echo/service_main.c b/samples/master/ioctl_echo/service_main.c new file mode 100644 index 000000000..a6017f386 --- /dev/null +++ b/samples/master/ioctl_echo/service_main.c @@ -0,0 +1,98 @@ +#include "lib_acl.h" +#include "service_main.h" + +/* 配置文件项 */ +char *var_cfg_mysql_dbaddr; +char *var_cfg_mysql_dbuser; +char *var_cfg_mysql_dbpass; +char *var_cfg_mysql_dbname; + +int var_cfg_mysql_dbmax; +int var_cfg_mysql_dbping; +int var_cfg_mysql_dbtimeout; +int var_cfg_mysql_auto_commit; + +int var_cfg_debug_mem; + +/* configure info */ + +/* TODO: you can add configure items here */ + +ACL_CONFIG_BOOL_TABLE service_conf_bool_tab[] = { + /* TODO: you can add configure variables of int type here */ + { "debug_mem", 0, &var_cfg_debug_mem }, + { 0, 0, 0 }, +}; + +ACL_CONFIG_INT_TABLE service_conf_int_tab[] = { + /* TODO: you can add configure variables of int type here */ + { "mysql_dbmax", 250, &var_cfg_mysql_dbmax, 0, 0 }, + { "mysql_dbping", 60, &var_cfg_mysql_dbping, 0, 0 }, + { "mysql_dbtimeout", 300, &var_cfg_mysql_dbtimeout, 0, 0 }, + { "mysql_auto_commit", 1, &var_cfg_mysql_auto_commit, 0, 0 }, + + { 0, 0, 0, 0, 0 }, +}; + +ACL_CONFIG_STR_TABLE service_conf_str_tab[] = { + + /* TODO: you can add configure variables of (char *) type here */ + { "mysql_dbaddr", "127.0.0.1:3306", &var_cfg_mysql_dbaddr }, + { "mysql_dbname", "ioctl_db", &var_cfg_mysql_dbname }, + { "mysql_dbuser", "ioctl_user", &var_cfg_mysql_dbuser }, + { "mysql_dbpass", "111111", &var_cfg_mysql_dbpass }, + + { 0, 0, 0 }, +}; + +/* 初始化函数 */ +void service_init(void *init_ctx acl_unused) +{ + /* + const char *ptr = getenv("MASTER_ENV"); + + if (ptr) + acl_msg_info("env=%s", ptr); + else + acl_msg_info("no env"); + */ +} + +void service_exit(void *arg acl_unused) +{ +} + +/* 协议处理函数入口 */ +int service_main(ACL_VSTREAM *client, void *run_ctx acl_unused) +{ + char buf[256]; + int ret; + + ACL_VSTREAM_SET_RWTIMO(client, 1200); + + if (var_cfg_debug_mem) + acl_msg_info("total alloc: %d", acl_mempool_total_allocated()); + + do { + if (isatty(ACL_VSTREAM_SOCK(client))) { + printf("Please input: "); + fflush(stdout); + } else + acl_msg_info("waiting ......"); + ret = acl_vstream_gets(client, buf, sizeof(buf)); + if (ret == ACL_VSTREAM_EOF) + return (-1); + buf[ret] = 0; + if (isatty(ACL_VSTREAM_SOCK(client))) + ret = acl_vstream_printf("Your input: %s", buf); + else { + acl_msg_info("wakeup now, ret=%d", ret); + ret = acl_vstream_writen(client, buf, strlen(buf)); + } + if (ret == ACL_VSTREAM_EOF) + return (-1); + } while (1); + + acl_msg_info("over now\r\n"); + return (-1); +} diff --git a/samples/master/ioctl_echo/service_main.h b/samples/master/ioctl_echo/service_main.h new file mode 100644 index 000000000..48df4514e --- /dev/null +++ b/samples/master/ioctl_echo/service_main.h @@ -0,0 +1,51 @@ + +#ifndef __SERVICE_MAIN_INCLUDE_H__ +#define __SERVICE_MAIN_INCLUDE_H__ + +#include "lib_acl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* 配置文件项 */ +/* in service_main.c */ +extern char *var_cfg_mysql_dbaddr; +extern char *var_cfg_mysql_dbuser; +extern char *var_cfg_mysql_dbpass; +extern char *var_cfg_mysql_dbname; +extern int var_cfg_mysql_dbmax; +extern int var_cfg_mysql_auto_commit; +extern int var_cfg_mysql_dbping; +extern int var_cfg_mysql_dbtimeout; + +extern int var_cfg_debug_mem; + +extern ACL_CONFIG_BOOL_TABLE service_conf_bool_tab[]; +extern ACL_CONFIG_INT_TABLE service_conf_int_tab[]; +extern ACL_CONFIG_STR_TABLE service_conf_str_tab[]; + +/** + * 初始化函数,服务器模板框架启动后仅调用该函数一次 + * @param init_ctx {void*} 用户自定义类型指针 + */ +extern void service_init(void *init_ctx); + +/** + * 进程退出时的回调函数 + * @param exist_ctx {void*} 用户自定义类型指针 + */ +extern void service_exit(void *exit_ctx); + +/** + * 协议处理函数入口 + * @param stream {ACL_VSTREAM*} 客户端数据连接流 + * @param run_ctx {void*} 用户自定义类型指针 + */ +extern int service_main(ACL_VSTREAM *stream, void *run_ctx); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/samples/master/ioctl_echo2/Makefile b/samples/master/ioctl_echo2/Makefile new file mode 100644 index 000000000..4d14b8b1c --- /dev/null +++ b/samples/master/ioctl_echo2/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = ioctl_echo2 diff --git a/samples/master/ioctl_echo2/ioctl_echo.cf b/samples/master/ioctl_echo2/ioctl_echo.cf new file mode 100644 index 000000000..6882566c7 --- /dev/null +++ b/samples/master/ioctl_echo2/ioctl_echo.cf @@ -0,0 +1,114 @@ + +service server { +# 进程是否禁止运行 + master_disable = yes +# 服务地址及端口号 + master_service = 127.0.0.1:5001 + +# 服务监听为域套接口 +# master_service = aio_echo.sock +# 服务类型 + master_type = inet +# master_type = unix + +# 当子进程异常退出时,如果该值非空,则将子进程异常退出的消息通知该服务 +# master_notify_addr = 127.0.0.1:5801 +# 邮件通知接收者 +# master_notify_recipients = zhengshuxin@hotmail.com:13910404316 + +# 是否允许延迟接受客户端连接,如果为0则表示关闭该功能,如果大于0则表示打开此功能 +# 并且此值代表延迟接受连接的超时值,超过此值时如果客户端依然没有发来数据,则操作 +# 系统会在系统层直接关闭该连接 +# master_defer_accept = 0 +# 是否只允许私有访问, 如果为 y, 则域套接口创建在 {install_path}/var/log/private/ 目录下, +# 如果为 n, 则域套接口创建在 {install_path}/var/log/public/ 目录下, + master_private = n + master_unpriv = n +# 是否需要 chroot: n -- no, y -- yes + master_chroot = n +# 每隔多长时间触发一次,单位为秒(仅对 trigger 模式有效) + master_wakeup = - +# 最大进程数 + master_maxproc = 2 +# 需要预先启动的进程数,该值不应大于 master_maxproc + master_prefork = 2 +# 进程程序名 + master_command = ioctl_echo +# 进程日志记录文件 + master_log = {install_path}/var/log/ioctl_echo.log +# 进程启动参数,只能为: -u [是否允许以某普通用户的身份运行] +# master_args = +# 传递给服务子进程的环境变量, 可以通过 getenv("SERVICE_ENV") 获得此值 + master_env = mempool_limit:512000000 +# master_env = logme:FALSE, priority:E_LOG_INFO, action:E_LOG_PER_DAY, flush:sync_flush, imit_size:512,\ +# sync_action:E_LOG_SEM, sem_name:/tmp/ioctl_echo.sem + +# 是否允许产生 core 文件 +# ioctl_enable_core = 1 +# 每个进程实例处理连接数的最大次数,超过此值后进程实例主动退出 + ioctl_use_limit = 100 +# 每个进程实例的空闲超时时间,超过此值后进程实例主动退出 + ioctl_idle_limit = 120 +# 记录进程PID的位置(对于多进程实例来说没有意义) + ioctl_pid_dir = {install_path}/var/pid +# 进程运行时所在的路径 + ioctl_queue_dir = {install_path}/var +# 读写超时时间, 单位为秒 + ioctl_rw_timeout = 120 +# 读缓冲区的缓冲区大小 + ioctl_buf_size = 8192 +# 每次 accept 时的循环接收的最大次数 + ioctl_max_accept = 25 +# 在并发访问量非常低的情况下,如访问量在 10 次/秒 以下时,可以找开此值(即赋为1),以加速事件循环过程, +# 从而防止服务进程阻塞在 select 上的时间过长而影响访问速度 +# ioctl_enable_dog = 0 +# 进程运行时的用户身份 + ioctl_owner = root + +# 用 select 进行循环时的时间间隔 +# 单位为秒 + ioctl_delay_sec = 0 +# 单位为微秒 + ioctl_delay_usec = 500 + +# 采用事件循环的方式: select(default), poll, kernel(epoll/devpoll/kqueue) + ioctl_event_mode = select + +# 线程池的最大线程数 + ioctl_max_threads = 250 +# 线程的堆栈空间大小,单位为字节,0表示使用系统缺省值 + ioctl_stacksize = 0 +# 允许访问 udserver 的客户端IP地址范围 + ioctl_access_allow = 127.0.0.1:255.255.255.255, 127.0.0.1:127.0.0.1 + +# 当 acl_master 退出时,如果该值置1则该程序不等所有连接处理完毕便立即退出 + ioctl_quick_abort = 1 + +## app_main.c 需要的参数项 +# 客户端连接的最大空闲时间阀值 + app_client_idle_limit = 12 + +############################################################################ +# 应用自己的配置选项 + +# mysql 服务地址 +# mysql_dbaddr = /tmp/mysql.sock +# mysql_dbaddr = 10.0.250.199:3306 +# 连接 mysql 数据库的连接池的最大值 +# mysql_dbmax = 200 +# ping mysql 连接的间隔时间, 以秒为单位 +# mysql_dbping = 10 +# mysql 连接空闲的时间间隔, 以秒为单位 +# mysql_dbtimeout = 30 + +# 数据库名称 +# mysql_dbname = ioctl_db +# 数据库访问用户 +# mysql_dbuser = ioctl_user +# 数据库用户访问密码 +# mysql_dbpass = 111111 + +# 是否输出当前内存的状态信息 + debug_mem = 1 +} + diff --git a/samples/master/ioctl_echo2/main.c b/samples/master/ioctl_echo2/main.c new file mode 100644 index 000000000..3f726406a --- /dev/null +++ b/samples/master/ioctl_echo2/main.c @@ -0,0 +1,20 @@ +#include "lib_acl.h" +#include "service_main.h" + +int main(int argc, char *argv[]) +{ + acl_ioctl_app_main(argc, argv, service_main, NULL, + ACL_APP_CTL_INIT_FN, service_init, + /* ACL_APP_CTL_INIT_CTX, NULL, */ + ACL_APP_CTL_EXIT_FN, service_exit, + /* ACL_APP_CTL_EXIT_CTX, NULL, */ + ACL_APP_CTL_CFG_BOOL, service_conf_bool_tab, + ACL_APP_CTL_CFG_INT, service_conf_int_tab, + ACL_APP_CTL_CFG_STR, service_conf_str_tab, + /* ACL_APP_CTL_OPEN_LOG, app_set_libcore_log, */ + /* ACL_APP_CTL_CLOSE_LOG, app_libcore_log_end, */ + ACL_APP_CTL_END); + + exit (0); +} + diff --git a/samples/master/ioctl_echo2/service_main.c b/samples/master/ioctl_echo2/service_main.c new file mode 100644 index 000000000..a6017f386 --- /dev/null +++ b/samples/master/ioctl_echo2/service_main.c @@ -0,0 +1,98 @@ +#include "lib_acl.h" +#include "service_main.h" + +/* 配置文件项 */ +char *var_cfg_mysql_dbaddr; +char *var_cfg_mysql_dbuser; +char *var_cfg_mysql_dbpass; +char *var_cfg_mysql_dbname; + +int var_cfg_mysql_dbmax; +int var_cfg_mysql_dbping; +int var_cfg_mysql_dbtimeout; +int var_cfg_mysql_auto_commit; + +int var_cfg_debug_mem; + +/* configure info */ + +/* TODO: you can add configure items here */ + +ACL_CONFIG_BOOL_TABLE service_conf_bool_tab[] = { + /* TODO: you can add configure variables of int type here */ + { "debug_mem", 0, &var_cfg_debug_mem }, + { 0, 0, 0 }, +}; + +ACL_CONFIG_INT_TABLE service_conf_int_tab[] = { + /* TODO: you can add configure variables of int type here */ + { "mysql_dbmax", 250, &var_cfg_mysql_dbmax, 0, 0 }, + { "mysql_dbping", 60, &var_cfg_mysql_dbping, 0, 0 }, + { "mysql_dbtimeout", 300, &var_cfg_mysql_dbtimeout, 0, 0 }, + { "mysql_auto_commit", 1, &var_cfg_mysql_auto_commit, 0, 0 }, + + { 0, 0, 0, 0, 0 }, +}; + +ACL_CONFIG_STR_TABLE service_conf_str_tab[] = { + + /* TODO: you can add configure variables of (char *) type here */ + { "mysql_dbaddr", "127.0.0.1:3306", &var_cfg_mysql_dbaddr }, + { "mysql_dbname", "ioctl_db", &var_cfg_mysql_dbname }, + { "mysql_dbuser", "ioctl_user", &var_cfg_mysql_dbuser }, + { "mysql_dbpass", "111111", &var_cfg_mysql_dbpass }, + + { 0, 0, 0 }, +}; + +/* 初始化函数 */ +void service_init(void *init_ctx acl_unused) +{ + /* + const char *ptr = getenv("MASTER_ENV"); + + if (ptr) + acl_msg_info("env=%s", ptr); + else + acl_msg_info("no env"); + */ +} + +void service_exit(void *arg acl_unused) +{ +} + +/* 协议处理函数入口 */ +int service_main(ACL_VSTREAM *client, void *run_ctx acl_unused) +{ + char buf[256]; + int ret; + + ACL_VSTREAM_SET_RWTIMO(client, 1200); + + if (var_cfg_debug_mem) + acl_msg_info("total alloc: %d", acl_mempool_total_allocated()); + + do { + if (isatty(ACL_VSTREAM_SOCK(client))) { + printf("Please input: "); + fflush(stdout); + } else + acl_msg_info("waiting ......"); + ret = acl_vstream_gets(client, buf, sizeof(buf)); + if (ret == ACL_VSTREAM_EOF) + return (-1); + buf[ret] = 0; + if (isatty(ACL_VSTREAM_SOCK(client))) + ret = acl_vstream_printf("Your input: %s", buf); + else { + acl_msg_info("wakeup now, ret=%d", ret); + ret = acl_vstream_writen(client, buf, strlen(buf)); + } + if (ret == ACL_VSTREAM_EOF) + return (-1); + } while (1); + + acl_msg_info("over now\r\n"); + return (-1); +} diff --git a/samples/master/ioctl_echo2/service_main.h b/samples/master/ioctl_echo2/service_main.h new file mode 100644 index 000000000..48df4514e --- /dev/null +++ b/samples/master/ioctl_echo2/service_main.h @@ -0,0 +1,51 @@ + +#ifndef __SERVICE_MAIN_INCLUDE_H__ +#define __SERVICE_MAIN_INCLUDE_H__ + +#include "lib_acl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* 配置文件项 */ +/* in service_main.c */ +extern char *var_cfg_mysql_dbaddr; +extern char *var_cfg_mysql_dbuser; +extern char *var_cfg_mysql_dbpass; +extern char *var_cfg_mysql_dbname; +extern int var_cfg_mysql_dbmax; +extern int var_cfg_mysql_auto_commit; +extern int var_cfg_mysql_dbping; +extern int var_cfg_mysql_dbtimeout; + +extern int var_cfg_debug_mem; + +extern ACL_CONFIG_BOOL_TABLE service_conf_bool_tab[]; +extern ACL_CONFIG_INT_TABLE service_conf_int_tab[]; +extern ACL_CONFIG_STR_TABLE service_conf_str_tab[]; + +/** + * 初始化函数,服务器模板框架启动后仅调用该函数一次 + * @param init_ctx {void*} 用户自定义类型指针 + */ +extern void service_init(void *init_ctx); + +/** + * 进程退出时的回调函数 + * @param exist_ctx {void*} 用户自定义类型指针 + */ +extern void service_exit(void *exit_ctx); + +/** + * 协议处理函数入口 + * @param stream {ACL_VSTREAM*} 客户端数据连接流 + * @param run_ctx {void*} 用户自定义类型指针 + */ +extern int service_main(ACL_VSTREAM *stream, void *run_ctx); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/samples/master/ioctl_echo3/Makefile b/samples/master/ioctl_echo3/Makefile new file mode 100644 index 000000000..ca1c9a9a0 --- /dev/null +++ b/samples/master/ioctl_echo3/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = ioctl_echo3 diff --git a/samples/master/ioctl_echo3/ioctl_echo.cf b/samples/master/ioctl_echo3/ioctl_echo.cf new file mode 100644 index 000000000..6882566c7 --- /dev/null +++ b/samples/master/ioctl_echo3/ioctl_echo.cf @@ -0,0 +1,114 @@ + +service server { +# 进程是否禁止运行 + master_disable = yes +# 服务地址及端口号 + master_service = 127.0.0.1:5001 + +# 服务监听为域套接口 +# master_service = aio_echo.sock +# 服务类型 + master_type = inet +# master_type = unix + +# 当子进程异常退出时,如果该值非空,则将子进程异常退出的消息通知该服务 +# master_notify_addr = 127.0.0.1:5801 +# 邮件通知接收者 +# master_notify_recipients = zhengshuxin@hotmail.com:13910404316 + +# 是否允许延迟接受客户端连接,如果为0则表示关闭该功能,如果大于0则表示打开此功能 +# 并且此值代表延迟接受连接的超时值,超过此值时如果客户端依然没有发来数据,则操作 +# 系统会在系统层直接关闭该连接 +# master_defer_accept = 0 +# 是否只允许私有访问, 如果为 y, 则域套接口创建在 {install_path}/var/log/private/ 目录下, +# 如果为 n, 则域套接口创建在 {install_path}/var/log/public/ 目录下, + master_private = n + master_unpriv = n +# 是否需要 chroot: n -- no, y -- yes + master_chroot = n +# 每隔多长时间触发一次,单位为秒(仅对 trigger 模式有效) + master_wakeup = - +# 最大进程数 + master_maxproc = 2 +# 需要预先启动的进程数,该值不应大于 master_maxproc + master_prefork = 2 +# 进程程序名 + master_command = ioctl_echo +# 进程日志记录文件 + master_log = {install_path}/var/log/ioctl_echo.log +# 进程启动参数,只能为: -u [是否允许以某普通用户的身份运行] +# master_args = +# 传递给服务子进程的环境变量, 可以通过 getenv("SERVICE_ENV") 获得此值 + master_env = mempool_limit:512000000 +# master_env = logme:FALSE, priority:E_LOG_INFO, action:E_LOG_PER_DAY, flush:sync_flush, imit_size:512,\ +# sync_action:E_LOG_SEM, sem_name:/tmp/ioctl_echo.sem + +# 是否允许产生 core 文件 +# ioctl_enable_core = 1 +# 每个进程实例处理连接数的最大次数,超过此值后进程实例主动退出 + ioctl_use_limit = 100 +# 每个进程实例的空闲超时时间,超过此值后进程实例主动退出 + ioctl_idle_limit = 120 +# 记录进程PID的位置(对于多进程实例来说没有意义) + ioctl_pid_dir = {install_path}/var/pid +# 进程运行时所在的路径 + ioctl_queue_dir = {install_path}/var +# 读写超时时间, 单位为秒 + ioctl_rw_timeout = 120 +# 读缓冲区的缓冲区大小 + ioctl_buf_size = 8192 +# 每次 accept 时的循环接收的最大次数 + ioctl_max_accept = 25 +# 在并发访问量非常低的情况下,如访问量在 10 次/秒 以下时,可以找开此值(即赋为1),以加速事件循环过程, +# 从而防止服务进程阻塞在 select 上的时间过长而影响访问速度 +# ioctl_enable_dog = 0 +# 进程运行时的用户身份 + ioctl_owner = root + +# 用 select 进行循环时的时间间隔 +# 单位为秒 + ioctl_delay_sec = 0 +# 单位为微秒 + ioctl_delay_usec = 500 + +# 采用事件循环的方式: select(default), poll, kernel(epoll/devpoll/kqueue) + ioctl_event_mode = select + +# 线程池的最大线程数 + ioctl_max_threads = 250 +# 线程的堆栈空间大小,单位为字节,0表示使用系统缺省值 + ioctl_stacksize = 0 +# 允许访问 udserver 的客户端IP地址范围 + ioctl_access_allow = 127.0.0.1:255.255.255.255, 127.0.0.1:127.0.0.1 + +# 当 acl_master 退出时,如果该值置1则该程序不等所有连接处理完毕便立即退出 + ioctl_quick_abort = 1 + +## app_main.c 需要的参数项 +# 客户端连接的最大空闲时间阀值 + app_client_idle_limit = 12 + +############################################################################ +# 应用自己的配置选项 + +# mysql 服务地址 +# mysql_dbaddr = /tmp/mysql.sock +# mysql_dbaddr = 10.0.250.199:3306 +# 连接 mysql 数据库的连接池的最大值 +# mysql_dbmax = 200 +# ping mysql 连接的间隔时间, 以秒为单位 +# mysql_dbping = 10 +# mysql 连接空闲的时间间隔, 以秒为单位 +# mysql_dbtimeout = 30 + +# 数据库名称 +# mysql_dbname = ioctl_db +# 数据库访问用户 +# mysql_dbuser = ioctl_user +# 数据库用户访问密码 +# mysql_dbpass = 111111 + +# 是否输出当前内存的状态信息 + debug_mem = 1 +} + diff --git a/samples/master/ioctl_echo3/main.c b/samples/master/ioctl_echo3/main.c new file mode 100644 index 000000000..f4a9a37e3 --- /dev/null +++ b/samples/master/ioctl_echo3/main.c @@ -0,0 +1,56 @@ +#include "lib_acl.h" +#include +#include "service_main.h" +#include "service_var.h" + +static void service_test(void) +{ + const char *addr = "127.0.0.1:8885"; + ACL_VSTREAM *sstream = acl_vstream_listen(addr, 32), *client; + int ret; + + assert(sstream != NULL); + + acl_xinetd_params_int_table(NULL, var_conf_int_tab); + acl_xinetd_params_str_table(NULL, var_conf_str_tab); + acl_xinetd_params_bool_table(NULL, var_conf_bool_tab); + + printf("listen %s ok\n", addr); + + while (1) { + client = acl_vstream_accept(sstream, NULL, 0); + if (client == NULL) { + printf("accept error: %s\n", acl_last_serror()); + break; + } + + while (1) { + ret = service_main(client, NULL); + if (ret < 0) { + acl_vstream_close(client); + break; + } + if (ret > 0) + break; + } + } + + acl_vstream_close(sstream); +} + +int main(int argc, char *argv[]) +{ + if (argc == 2 && strcasecmp(argv[1], "test") == 0) { + service_test(); + } else { + acl_ioctl_app_main(argc, argv, service_main, NULL, + ACL_APP_CTL_ON_ACCEPT, service_on_accept, + ACL_APP_CTL_INIT_FN, service_init, + ACL_APP_CTL_EXIT_FN, service_exit, + ACL_APP_CTL_CFG_BOOL, var_conf_bool_tab, + ACL_APP_CTL_CFG_INT, var_conf_int_tab, + ACL_APP_CTL_CFG_STR, var_conf_str_tab, + ACL_APP_CTL_END); + } + return (0); +} diff --git a/samples/master/ioctl_echo3/service_main.c b/samples/master/ioctl_echo3/service_main.c new file mode 100644 index 000000000..7888d7820 --- /dev/null +++ b/samples/master/ioctl_echo3/service_main.c @@ -0,0 +1,92 @@ +#include "lib_acl.h" +#include "service_var.h" +#include "service_main.h" + +typedef struct +{ + int n; + char s[128]; +} MY_CTX; + +/* 初始化函数 */ +void service_init(void *init_ctx acl_unused) +{ + const char *myname = "service_init"; + + acl_msg_info("%s: init ok ...", myname); +} + +/* 进程退出前调用的函数 */ +void service_exit(void *arg acl_unused) +{ + const char *myname = "service_exit"; + + acl_msg_info("%s: exit now ...", myname); +} + +static void on_close(ACL_VSTREAM *client, void *arg) +{ + MY_CTX *ctx = (MY_CTX*) arg; + acl_msg_info("stream close now, n: %d, rw_timeout: %d", + ctx->n, client->rw_timeout); + acl_myfree(ctx); +} + +int service_on_accept(ACL_VSTREAM *client) +{ + MY_CTX *ctx = (MY_CTX*) client->context; + + acl_vstream_fprintf(client, "hello, you're welcome!\r\n"); + ctx = (MY_CTX*) acl_mycalloc(1, sizeof(MY_CTX)); + snprintf(ctx->s, sizeof(ctx->s), "hello world!"); + ctx->n = 1; + client->context = ctx; + acl_vstream_add_close_handle(client, on_close, ctx); + return (0); +} + +/* 协议处理函数入口 */ +int service_main(ACL_VSTREAM *client, void *run_ctx acl_unused) +{ + const char *myname = "service_main"; + int ret, ready; + ACL_VSTRING *buf = acl_vstring_alloc(1024); + + acl_msg_info(">>>one coonected!, rw_timeout: %d", client->rw_timeout); + + while (1) { + ready = 0; + ACL_VSTRING_RESET(buf); + ret = acl_vstream_gets_peek(client, buf, &ready); + if (ret == ACL_VSTREAM_EOF) { + if (var_cfg_debug_enable) + acl_msg_info("%s: close client now, (%s), timeout: %d", + myname, var_cfg_debug_msg, client->rw_timeout); + acl_vstring_free(buf); + return (-1); /* 返回负值以使框架内部关闭 client 数据流 */ + } else if (!ready) + break; + + if (acl_vstream_writen(client, acl_vstring_str(buf), ret) == ACL_VSTREAM_EOF) { + if (var_cfg_debug_enable) + acl_msg_info("%s: write to client error, close now(%s)", + myname, var_cfg_debug_msg); + acl_vstring_free(buf); + return (-1); /* 返回负值以使框架内部关闭 client 数据流 */ + } + } + acl_vstring_free(buf); + + if (var_cfg_keep_alive) { + if (var_cfg_debug_enable) + acl_msg_info("%s: keep alive, wait client...", myname); + return (0); /* 返回 0 以使框架内部自动监听该数据流从而保持长连接 */ + } else { + /* 可以在此处返回 =1, 使框架内部自动关闭 client 数据流, + * 也可以在此处直接关闭 client 数据流,同时返回 1 告诉框架 + * 该流已经被用户关闭了不必再关心该 client 数据流. + */ + acl_vstream_close(client); + return (1); + } +} diff --git a/samples/master/ioctl_echo3/service_main.h b/samples/master/ioctl_echo3/service_main.h new file mode 100644 index 000000000..2f82430e1 --- /dev/null +++ b/samples/master/ioctl_echo3/service_main.h @@ -0,0 +1,41 @@ + +#ifndef __SERVICE_MAIN_INCLUDE_H__ +#define __SERVICE_MAIN_INCLUDE_H__ + +#include "lib_acl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * 初始化函数,服务器模板框架启动后仅调用该函数一次 + * @param init_ctx {void*} 用户自定义类型指针 + */ +extern void service_init(void *init_ctx); + +/** + * 进程退出时的回调函数 + * @param exist_ctx {void*} 用户自定义类型指针 + */ +extern void service_exit(void *exit_ctx); + +/** + * 当服务器接收到新连接时调用此函数 + * @param stream {ACL_VSTREAM*} 客户端数据连接流 + * @return {int} 如果返回值 < 0, 则表示服务器希望关闭该连接 + */ +extern int service_on_accept(ACL_VSTREAM *client); + +/** + * 协议处理函数入口 + * @param stream {ACL_VSTREAM*} 客户端数据连接流 + * @param run_ctx {void*} 用户自定义类型指针 + */ +extern int service_main(ACL_VSTREAM *stream, void *run_ctx); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/samples/master/ioctl_echo3/service_var.c b/samples/master/ioctl_echo3/service_var.c new file mode 100644 index 000000000..b83fdcd7b --- /dev/null +++ b/samples/master/ioctl_echo3/service_var.c @@ -0,0 +1,29 @@ +#include "lib_acl.h" +#include "service_var.h" + +char *var_cfg_debug_msg; + +ACL_CFG_STR_TABLE var_conf_str_tab[] = { + { "debug_msg", "test_msg", &var_cfg_debug_msg }, + + { 0, 0, 0 } +}; + +int var_cfg_debug_enable; +int var_cfg_keep_alive; + +ACL_CFG_BOOL_TABLE var_conf_bool_tab[] = { + { "debug_enable", 1, &var_cfg_debug_enable }, + { "keep_alive", 1, &var_cfg_keep_alive }, + + { 0, 0, 0 } +}; + +int var_cfg_io_timeout; + +ACL_CFG_INT_TABLE var_conf_int_tab[] = { + { "io_timeout", 120, &var_cfg_io_timeout, 0, 0 }, + + { 0, 0 , 0 , 0, 0 } +}; + diff --git a/samples/master/ioctl_echo3/service_var.h b/samples/master/ioctl_echo3/service_var.h new file mode 100644 index 000000000..70a120160 --- /dev/null +++ b/samples/master/ioctl_echo3/service_var.h @@ -0,0 +1,30 @@ +#ifndef __SERVICE_VAR_INCLUDE_H__ +#define __SERVICE_VAR_INCLUDE_H__ + +#include "lib_acl.h" + +/*------------- 字符串配置项 ----------------*/ + +extern ACL_CFG_STR_TABLE var_conf_str_tab[]; + +/* 日志调试输出信息 */ +extern char *var_cfg_debug_msg; + +/*-------------- 布尔值配置项 ---------------*/ + +extern ACL_CFG_BOOL_TABLE var_conf_bool_tab[]; + +/* 是否输出日志调试信息 */ +extern int var_cfg_debug_enable; + +/* 是否与客户端保持长连接 */ +extern int var_cfg_keep_alive; + +/*-------------- 整数配置项 -----------------*/ + +extern ACL_CFG_INT_TABLE var_conf_int_tab[]; + +/* 每次与客户端通信时,读超时时间(秒) */ +extern int var_cfg_io_timeout; + +#endif diff --git a/samples/master/listener_server/Makefile b/samples/master/listener_server/Makefile new file mode 100644 index 000000000..33dfc2bc7 --- /dev/null +++ b/samples/master/listener_server/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = listen_server diff --git a/samples/master/listener_server/global.h b/samples/master/listener_server/global.h new file mode 100644 index 000000000..09f0f7eb3 --- /dev/null +++ b/samples/master/listener_server/global.h @@ -0,0 +1,21 @@ + +#ifndef __SPOOL_GLOBAL_INCLUDE_H__ +#define __SPOOL_GLOBAL_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#define VAR_CFG_MAX_THREADS "max_threads" +#define VAR_CFG_CLIENT_IDLE_LIMIT "client_idle_limit" +#define VAR_CFG_ACCESS_ALLOW "access_allow" + +extern int var_cfg_max_threads; +extern int var_cfg_client_idle_limit; +extern char *var_cfg_access_allow; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/samples/master/listener_server/main.c b/samples/master/listener_server/main.c new file mode 100644 index 000000000..7c57f4b47 --- /dev/null +++ b/samples/master/listener_server/main.c @@ -0,0 +1,113 @@ + +#include +#include +#include +#include + +#include "lib_acl.h" + +#include "global.h" +#include "spool_main.h" + +#define ARG_UNUSE(_x_) (_x_ = _x_) + +#define VAR_LISTENER_BANNER "listener_banner" +#define VAR_LISTENER_TMOUT "listener_timeout" + +char *var_listener_banner; +int var_listener_tmout; + +int var_cfg_max_threads; +int var_cfg_client_idle_limit; +char *var_cfg_access_allow; + +static SPOOL *__spool_handle = NULL; + +static ACL_CONFIG_INT_TABLE __conf_int_tab[] = { + { VAR_LISTENER_TMOUT, 600, &var_listener_tmout, 0, 0 }, + + { VAR_CFG_MAX_THREADS, 50, &var_cfg_max_threads, 0, 0 }, + { VAR_CFG_CLIENT_IDLE_LIMIT, 60, &var_cfg_client_idle_limit, 0, 0}, + + { 0, 0, 0, 0, 0 }, +}; + +static ACL_CONFIG_STR_TABLE __conf_str_tab[] = { + { VAR_LISTENER_BANNER, "welcome", &var_listener_banner }, + + { VAR_CFG_ACCESS_ALLOW, "access_allow", &var_cfg_access_allow }, + + { 0, 0, 0 }, +}; + +static void __service(ACL_VSTREAM *stream, char *service, char **argv) +{ + char myname[] = "__service"; + char ip[64]; + + /* + * Sanity check. This service takes no command-line arguments. + */ + if (argv[0]) + acl_msg_fatal("%s, %s(%d): unexpected command-line argument: %s, service=%s", + __FILE__, myname, __LINE__, + argv[0], service ? service : "null"); + + acl_watchdog_pat(); + + if (acl_getpeername(ACL_VSTREAM_SOCK(stream), ip, sizeof(ip)) < 0) { + acl_msg_warn("%s, %s(%d): can't get socket's ip", + __FILE__, myname, __LINE__); + acl_vstream_close(stream); + } else if (!acl_access_permit(ip)) { + acl_msg_warn("%s, %s(%d): ip(%s) be denied", + __FILE__, myname, __LINE__, ip); + (void) acl_vstream_fprintf(stream, "You are not welcome here!\r\n"); + acl_vstream_close(stream); + } else + spool_add_worker(__spool_handle, stream); +} + +static void __pre_accept(char *name, char **argv) +{ + ARG_UNUSE(name); + ARG_UNUSE(argv); +} + +static void __pre_jail_init(char *name, char **argv) +{ + ARG_UNUSE(name); + ARG_UNUSE(argv); +} + +static void __post_jail_init(char *name, char **argv) +{ + char myname[] = "__post_jail_init"; + + ARG_UNUSE(name); + ARG_UNUSE(argv); + + acl_access_add(var_cfg_access_allow, ",", ":"); + + __spool_handle = spool_create(var_cfg_max_threads, var_cfg_client_idle_limit); + if (__spool_handle == NULL) + acl_msg_fatal("%s(%d): spool_create error(%s)", + myname, __LINE__, strerror(errno)); + if (spool_start(__spool_handle) < 0) + acl_msg_fatal("%s(%d): spool start error", myname, __LINE__); +} + +int main(int argc, char *argv[]) +{ + acl_msg_info("%s: starting...", argv[0]); + + acl_listener_server_main(argc, argv, __service, + ACL_MASTER_SERVER_INT_TABLE, __conf_int_tab, + ACL_MASTER_SERVER_STR_TABLE, __conf_str_tab, + ACL_MASTER_SERVER_PRE_INIT, __pre_jail_init, + ACL_MASTER_SERVER_PRE_ACCEPT, __pre_accept, + ACL_MASTER_SERVER_POST_INIT, __post_jail_init, + 0); + exit (0); +} + diff --git a/samples/master/listener_server/protocol.c b/samples/master/listener_server/protocol.c new file mode 100644 index 000000000..302dfdeb6 --- /dev/null +++ b/samples/master/listener_server/protocol.c @@ -0,0 +1,25 @@ +#include +#include + +#include "lib_util.h" + +#include "spool_main.h" +#include "protocol.h" + +int protocol(SPOOL *spool, ACL_VSTREAM *cstream) +{ + char buf[4096]; + int n, ret; + + spool = spool; + + n = acl_vstream_gets(cstream, buf, sizeof(buf)); + if (n == ACL_VSTREAM_EOF) + return (-1); + + ret = acl_vstream_writen(cstream, buf, n); + if (ret != n) + return (-1); + + return (0); +} diff --git a/samples/master/listener_server/protocol.h b/samples/master/listener_server/protocol.h new file mode 100644 index 000000000..05c1c1c08 --- /dev/null +++ b/samples/master/listener_server/protocol.h @@ -0,0 +1,9 @@ + +#ifndef __PROTOCOL_INCLUDE_H__ +#define __PROTOCOL_INCLUDE_H__ + +#include "spool_main.h" + +extern int protocol(SPOOL *spool, ACL_VSTREAM *cstream); + +#endif diff --git a/samples/master/listener_server/spool_main.c b/samples/master/listener_server/spool_main.c new file mode 100644 index 000000000..dd6c783b4 --- /dev/null +++ b/samples/master/listener_server/spool_main.c @@ -0,0 +1,83 @@ +#include +#include +#include +#include + +#include "lib_util.h" + +#include "global.h" +#include "protocol.h" +#include "spool_main.h" + +/*----------------------------------------------------------------------------*/ +SPOOL *spool_create(int max_threads, int idle_timeout) +{ + char myname[] = "spool_create"; + SPOOL *spool; + + spool = (SPOOL *) acl_mycalloc(1, sizeof(SPOOL)); + if (spool == NULL) + acl_msg_fatal("%s(%d): calloc error(%s)", + myname, __LINE__, strerror(errno)); + + spool->h_spool = acl_spool_create(max_threads, idle_timeout); + + return (spool); +} +/*----------------------------------------------------------------------------*/ +int spool_start(const SPOOL *spool) +{ + return (acl_spool_start(spool->h_spool)); +} +/*----------------------------------------------------------------------------*/ +static void __read_notify_callback(int event_type, + ACL_SPOOL *h_spool, + ACL_VSTREAM *cstream, + void *context) +{ + char myname[] = "__read_notify_callback"; + SPOOL *spool; + + spool = (SPOOL *) context; + + switch (event_type) { + case ACL_EVENT_READ: + if (protocol(spool, cstream) < 0) { + acl_vstream_close(cstream); + } else { + acl_spool_enable_read(h_spool, + cstream, + var_cfg_client_idle_limit, + __read_notify_callback, + (void *) spool); + + } + break; + case ACL_EVENT_RW_TIMEOUT: + case ACL_EVENT_XCPT: + acl_vstream_close(cstream); + break; + default: + acl_msg_fatal("%s, %s(%d): unknown event type(%d)", + __FILE__, myname, __LINE__, event_type); + /* not reached */ + break; + } +} + +void spool_add_worker(SPOOL *spool, ACL_VSTREAM *cstream) +{ + char myname[] = "spool_add_worker"; + + if (cstream == NULL || spool == NULL) + acl_msg_fatal("%s(%d): input invalid", myname, __LINE__); + + /* 将客户端数据流的状态置入事件监控集合中 */ + acl_spool_enable_read(spool->h_spool, + cstream, + var_cfg_client_idle_limit, + __read_notify_callback, + (void *) spool); +} +/*----------------------------------------------------------------------------*/ + diff --git a/samples/master/listener_server/spool_main.h b/samples/master/listener_server/spool_main.h new file mode 100644 index 000000000..4136fbe78 --- /dev/null +++ b/samples/master/listener_server/spool_main.h @@ -0,0 +1,44 @@ +#ifndef __SPOOL_MAIN_INCLUDE_H__ +#define __SPOOL_MAIN_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lib_util.h" +#include "global.h" + +typedef struct SPOOL { + ACL_SPOOL *h_spool; +} SPOOL; +/*----------------------------------------------------------------------------*/ +/* in spool_main.c */ +/** + * 创建一个服务器框架 + * @param max_threads 最大线程数 + * @param idle_timeout 每个线程空闲超时时间 + * @return SPOOL* 服务器连接池句柄 + */ +extern SPOOL *spool_create(int max_threads, int idle_timeout); + +/** + * 启动任务工作池 + * @param spool 服务器任务池句柄 + */ +extern int spool_start(const SPOOL *spool); + +/** + * 向任务池中添加一个工作任务 + * @param spool 服务器任务池句柄 + * @param cstream 客户端数据流指针 + * 注: cstream 数据流会在该函数内部的回调函数中进行关闭, 所以该函数的调用者不要 + * 关闭该流. + */ +extern void spool_add_worker(SPOOL *spool, ACL_VSTREAM *cstream); +/*----------------------------------------------------------------------------*/ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/samples/master/master_notify/Makefile b/samples/master/master_notify/Makefile new file mode 100644 index 000000000..6461c4ac5 --- /dev/null +++ b/samples/master/master_notify/Makefile @@ -0,0 +1,4 @@ +include ../Makefile.in +#CFLAGS += -I/opt/import_lib/include/cgi +#EXTLIBS += -L/opt/import_lib/lib -ltpl +PROG = acl_notify diff --git a/samples/master/master_notify/Makefile.dynamic b/samples/master/master_notify/Makefile.dynamic new file mode 100644 index 000000000..1b805f8e7 --- /dev/null +++ b/samples/master/master_notify/Makefile.dynamic @@ -0,0 +1,4 @@ +include ../Makefile.in.dynamic +CFLAGS += -I/opt/import_lib/include/cgi +EXTLIBS += -L/opt/import_lib/lib -ltpl +PROG = acl_notify diff --git a/samples/master/master_notify/acl_notify.cf b/samples/master/master_notify/acl_notify.cf new file mode 100644 index 000000000..f1a275d59 --- /dev/null +++ b/samples/master/master_notify/acl_notify.cf @@ -0,0 +1,97 @@ + +service server { +# 进程是否禁止运行 + master_disable = yes +# 服务地址及端口号 +# master_service = 127.0.0.1:5001 + +# 服务监听为域套接口 + master_service = acl_notify.sock +# 服务类型 +# master_type = inet + master_type = unix + +# 是否允许延迟接受客户端连接,如果为0则表示关闭该功能,如果大于0则表示打开此功能 +# 并且此值代表延迟接受连接的超时值,超过此值时如果客户端依然没有发来数据,则操作 +# 系统会在系统层直接关闭该连接 +# master_defer_accept = 0 +# 是否只允许私有访问, 如果为 y, 则域套接口创建在 {install_path}/var/log/private/ 目录下, +# 如果为 n, 则域套接口创建在 {install_path}/var/log/public/ 目录下, + master_private = n + master_unpriv = n +# 是否需要 chroot: n -- no, y -- yes + master_chroot = n +# 每隔多长时间触发一次,单位为秒(仅对 trigger 模式有效) + master_wakeup = - +# 最大进程数 + master_maxproc = 1 +# 进程程序名 + master_command = acl_notify +# 进程日志记录文件 + master_log = {install_path}/var/log/acl_notify.log +# 进程启动参数,只能为: -u [是否允许以某普通用户的身份运行] +# master_args = +# 传递给服务子进程的环境变量, 可以通过 getenv("SERVICE_ENV") 获得此值 +# master_env = mempool_limit:512000000 +# master_env = logme:FALSE, priority:E_LOG_INFO, action:E_LOG_PER_DAY, flush:sync_flush, imit_size:512,\ +# sync_action:E_LOG_SEM, sem_name:/tmp/ioctl_echo.sem + +# 每个进程实例处理连接数的最大次数,超过此值后进程实例主动退出 + ioctl_use_limit = 100 +# 每个进程实例的空闲超时时间,超过此值后进程实例主动退出 + ioctl_idle_limit = 120 +# 记录进程PID的位置(对于多进程实例来说没有意义) + ioctl_pid_dir = {install_path}/var/pid +# 进程运行时所在的路径 + ioctl_queue_dir = {install_path}/var +# 读写超时时间, 单位为秒 + ioctl_rw_timeout = 120 +# 读缓冲区的缓冲区大小 + ioctl_buf_size = 8192 +# 每次 accept 时的循环接收的最大次数 + ioctl_max_accept = 25 +# 在并发访问量非常低的情况下,如访问量在 10 次/秒 以下时,可以找开此值(即赋为1),以加速事件循环过程, +# 从而防止服务进程阻塞在 select 上的时间过长而影响访问速度 +# ioctl_enable_dog = 0 +# 进程运行时的用户身份 + ioctl_owner = root + +# 用 select 进行循环时的时间间隔 +# 单位为秒 + ioctl_delay_sec = 0 +# 单位为微秒 + ioctl_delay_usec = 500 + +# 采用事件循环的方式: select(default), poll, kernel(epoll/devpoll/kqueue) + ioctl_event_mode = select + +# 线程池的最大线程数 + ioctl_max_threads = 250 +# 线程的堆栈空间大小,单位为字节,0表示使用系统缺省值 + ioctl_stacksize = 0 +# 允许访问 udserver 的客户端IP地址范围 +# ioctl_access_allow = 127.0.0.1:127.0.0.1 + +############################################################################ +# 应用自己的配置选项 + +# 短信猫地址 +# sms_addr = xxx.xxx.xxx.xxx:port +# sms_addr = 122.49.0.234:9010 + host_ip = 127.0.0.1 + smtpd_addr = mail.banmau.com:25 + smtp_helo = test.com + mail_from = zsx@renwou.cn + mail_to = zsx@51iker.com, xuganghui@51iker.com + mail_cc = zsx@renwou.cn + mail_bcc = zhengshuxin@51iker.com + auth_user = zsx@renwou.cn + auth_pass = 111111 + warn_mail = ${install_path}/conf/warning_letter.tmpl + +# 公司正常工作时间 + work_week_min = 1 + work_week_max = 5 + work_hour_min = 9 + work_hour_max = 18 +} diff --git a/samples/master/master_notify/lib_tpl.h b/samples/master/master_notify/lib_tpl.h new file mode 100644 index 000000000..f4aa97262 --- /dev/null +++ b/samples/master/master_notify/lib_tpl.h @@ -0,0 +1,256 @@ +/* + * tpllib + * + * C library of functions for text template processing. + * Copyright (C) 2003-2007 Niels Wojciech Tadeusz Andersen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __C_TEMPLATE_ENGINE_H__ +#define __C_TEMPLATE_ENGINE_H__ + +/* + * Markup: + * Field: @@SOMETHING@@ + * Section: + * Content of section + * perhaps with some @@FIELD@@ + * + * + * Sections can be nested to any depth. + */ + +#define DELIMITER_LEFT "$<" +#define DELIMITER_RIGHT ">" +#define SECTIONTAG_HEAD "" + +/* The object, holding template data */ +typedef struct template_s tpl_t; + +#include "lib_acl.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +/* Allocates and initializes new template object */ +tpl_t* tpl_alloc(void); + +/* Releases a template object allocated with tpl_alloc() */ +void tpl_free(tpl_t* tpl); + +/* + * Copy the original template into the clone template + * The clone parameter must be a newly initialized template object + */ +void tpl_copy(tpl_t* c, const tpl_t* original); + +/* Initialize template object */ +void tpl_init(tpl_t* tpl); + +/* Release memory used by data in template strycture */ +void tpl_release(tpl_t* tpl); + +/* + * Constructs template data from specified template file + * returns TPL_OK if successful + */ +int tpl_load(tpl_t* tpl, const char* filename); + +/* + * Construct template from string + * returns TPL_OK if successful + */ +int tpl_from_string(tpl_t* tpl, const char* data, int len); + +/* Clear fields, delete added content */ +void tpl_reset(tpl_t* tpl); + +/* Set field in currently selected section */ +void tpl_set_field(tpl_t* tpl, const char* field, const char* val, int len); + +/* Uses printf() formating */ +void tpl_set_field_fmt(tpl_t* tpl, const char* field, const char* format, ...); + +/* Output a number to a field */ +void tpl_set_field_int(tpl_t* tpl, const char* field, int val); +void tpl_set_field_uint(tpl_t* tpl, const char* field, unsigned int val); +void tpl_set_field_double(tpl_t* tpl, const char* field, double val); + +/* + * Sets field to contents of a file + * returns TPL_OK unless the file cannot be read + */ +int tpl_set_field_from_file(tpl_t* tpl, const char* field, const char* filename); + +/* Sets a field everywhere in the document */ +void tpl_set_field_global(tpl_t* tpl, const char* field, const char* val, int len); +void tpl_set_field_fmt_global(tpl_t* tpl, const char* field, const char* format, ...); +void tpl_set_field_int_global(tpl_t* tpl, const char* field, int val); +void tpl_set_field_uint_global(tpl_t* tpl, const char* field, unsigned int val); +void tpl_set_field_double_global(tpl_t* tpl, const char* field, double val); + +/* + * Selects section in currently selected section or in the document + * if no section is selected yet + * returns TPL_OK if sections is selected successfully + */ +int tpl_select_section(tpl_t* tpl, const char* section); + +/* + * Selects section containing current section (selects parent section) + * returns TPL_OK if successfull. + */ +int tpl_deselect_section(tpl_t* tpl); + +/* + * Sets content of specified section + * returns TPL_OK if successful + */ +int tpl_set_section(tpl_t* tpl, const char* section, const char* val, int len); +int tpl_set_section_from_file(tpl_t* tpl, const char* section, const char* filename); + +/* + * Add a static copy of currently selected section's content + * before beginning tag of this section but after already "appended" content + * returns TPL_OK if successful + */ +int tpl_append_section(tpl_t* tpl); + +/* returns length of current content not including the trailing \0 byte */ +int tpl_length(const tpl_t* tpl); + +/* returns length of currently selected section's content */ +int tpl_section_length(const tpl_t* tpl); + +/* + * Copy content into supplied buffer, which must be large enough + * Use tpl_length() to obtain length and allocate correct buffer + * with the size length + 1 (to include the terminating \0 byte) + */ +void tpl_get_content(const tpl_t* tpl, char* buffer); + +/* + * Same as tpl_get_content() but with the contents of + * the currently selected section. + * If no section is selected then a call to this function is + * equivalent to a call to tpl_get_content() + */ +void tpl_get_section_content(const tpl_t* tpl, char* buffer); + +/* + * Save to file + * returns TPL_OK if succeessful + */ +int tpl_save_as(const tpl_t* tpl, const char* filename); + +/* + * Write content to a file descriptor (might be a socket) + * returns TPL_OK if write succeeds + */ +int tpl_write(const tpl_t* tpl, int fd); + +/* + * Write content as simple HTTP-response, for use in nph- CGI programs + * returns TPL_OK if write succeeds + */ +int tpl_http_write(const tpl_t* tpl, int fd); + +/* + * Write content of the tpl to out stream + */ +void tpl_out(tpl_t *tpl, ACL_VSTREAM *out); + +#if defined(__cplusplus) +} +#endif + + +/* Return values for non-void functions */ +#define TPL_OPEN_ERROR -7 +#define TPL_WRITE_ERROR -6 +#define TPL_READ_ERROR -5 +#define TPL_NOT_FOUND_ERROR -4 +#define TPL_SYNTAX_ERROR -3 +#define TPL_NO_SECTION_SELECTED_ERROR -2 +#define TPL_SECTION_NOT_FOUND_ERROR -1 +#define TPL_OK 0 + + + +/* Header string for a minimalistic HTTP response */ +#define TPL_NPH_HTTP_HEADER_START \ + "HTTP/1.1 200 OK\r\n"\ + "Content-Type: text/html\r\n"\ + "Content-Length: " + +#define TPL_NPH_HTTP_HEADER_END \ + "\r\n\r\n" + + +#define HASH_TABLE_SIZE 29 + +/* Do not set this to less than the number of characters + needed to represent any number you might want to output */ +#define INITIAL_FIELD_LEN 31 + + +/* Hash bucket for field entry */ +typedef struct tpl_fcell_s +{ + char *key; + char *val; + int len; + struct tpl_fcell_s *next; +} tpl_fcell_t; + + +/* Content of template is a linked list of those */ +typedef struct tpl_node_s +{ + char *val; + int len; + struct tpl_fcell_s *fval; + struct tpl_node_s *next; +} tpl_node_t; + + +/* Hash bucket structure for section entry */ +typedef struct tpl_tcell_t +{ + char *key; + tpl_t *tpl; + tpl_node_t **preceding; + struct tpl_tcell_t *_next; + struct tpl_tcell_t *next; +} tpl_tcell_t; + + +/* The template structure definition */ +typedef struct template_s +{ + tpl_node_t *head; + tpl_node_t *added_head; + tpl_node_t **added_tail; + tpl_tcell_t *first; + tpl_fcell_t *fields[HASH_TABLE_SIZE]; + tpl_tcell_t *sections[HASH_TABLE_SIZE]; + tpl_t *tpl; + tpl_t *parent; +} template_t; + +#endif diff --git a/samples/master/master_notify/main.c b/samples/master/master_notify/main.c new file mode 100644 index 000000000..9deb9f481 --- /dev/null +++ b/samples/master/master_notify/main.c @@ -0,0 +1,61 @@ +#include "lib_acl.h" +#include +#include "service_main.h" +#include "service_var.h" + +static void service_test(void) +{ + const char *addr = "127.0.0.1:8885"; + ACL_VSTREAM *sstream = acl_vstream_listen(addr, 32), *client; + int ret; + + assert(sstream != NULL); + + acl_xinetd_params_int_table(NULL, var_conf_int_tab); + acl_xinetd_params_str_table(NULL, var_conf_str_tab); + acl_xinetd_params_bool_table(NULL, var_conf_bool_tab); + + printf("listen %s ok\n", addr); + + service_init(NULL); + + while (1) { + client = acl_vstream_accept(sstream, NULL, 0); + if (client == NULL) { + printf("accept error: %s\n", acl_last_serror()); + break; + } + + while (1) { + if (acl_readable(ACL_VSTREAM_SOCK(client)) == 0) + continue; + + ret = service_main(client, NULL); + if (ret < 0) { + acl_vstream_close(client); + break; + } + if (ret > 0) + break; + } + } + + service_exit(NULL); + acl_vstream_close(sstream); +} + +int main(int argc, char *argv[]) +{ + if (argc == 2 && strcasecmp(argv[1], "test") == 0) { + service_test(); + } else { + acl_ioctl_app_main(argc, argv, service_main, NULL, + ACL_APP_CTL_INIT_FN, service_init, + ACL_APP_CTL_EXIT_FN, service_exit, + ACL_APP_CTL_CFG_BOOL, var_conf_bool_tab, + ACL_APP_CTL_CFG_INT, var_conf_int_tab, + ACL_APP_CTL_CFG_STR, var_conf_str_tab, + ACL_APP_CTL_END); + } + return (0); +} diff --git a/samples/master/master_notify/notify.c b/samples/master/master_notify/notify.c new file mode 100644 index 000000000..a162d95d6 --- /dev/null +++ b/samples/master/master_notify/notify.c @@ -0,0 +1,148 @@ +#include "lib_acl.h" +#include +#include "lib_tpl.h" +#include "service_var.h" +#include "notify.h" + +static int can_notify(ACL_CACHE *cache, const char *proc, const char *data) +{ + const char *ptr; + + if (cache == NULL) + return (1); + if (proc == NULL || *proc == 0) { + acl_msg_warn("%s(%d): proc null", __FUNCTION__, __LINE__); + return (0); + } + + acl_cache_lock(cache); + acl_cache_timeout(cache); + ptr = acl_cache_find(cache, proc); + if (ptr) { + acl_cache_unlock(cache); + acl_msg_warn("%s(%d): data(%s) has just been notified before!", + __FUNCTION__, __LINE__, data); + return (0); + } + + acl_cache_enter(cache, proc, acl_mystrdup(proc)); + acl_cache_unlock(cache); + + return (1); +} + +static int can_notify_sms(ACL_CACHE *cache, const char *proc, const char *data) +{ + time_t now; + struct tm local_time; + + if (can_notify(cache, proc, data) == 0) + return (0); + + (void) time(&now); + (void) localtime_r(&now, &local_time); + + if (local_time.tm_wday >= var_cfg_work_week_min + && local_time.tm_wday <= var_cfg_work_week_max + && local_time.tm_hour >= var_cfg_work_hour_min + && local_time.tm_hour <= var_cfg_work_hour_max) + { + acl_msg_info("%s(%d): data(%s) no notify! tm_wday: %d, tm_hour: %d", + __FUNCTION__, __LINE__, data, + local_time.tm_wday, local_time.tm_hour); + return (0); + } + + return (1); +} + +int notify(ACL_CACHE *smtp_notify_cache, ACL_CACHE *sms_notify_cache, const char *data) +{ + ACL_ARGV *args = acl_argv_split(data, "|"); + ACL_ITER iter; + char *proc = NULL, *info = NULL; + const char *ptr; + ACL_ARGV *rcpts = NULL, *to_mails, *to_phones; + int pid = -1; + +#undef RETURN +#define RETURN(x) do { \ + if (proc) \ + acl_myfree(proc); \ + if (info) \ + acl_myfree(info); \ + if (rcpts) \ + acl_argv_free(rcpts); \ + acl_argv_free(args); \ + return (x); \ +} while (0) + + if (args->argc < 3) { + acl_msg_error("%s(%d): invalid data(%s)", + __FUNCTION__, __LINE__, data); + RETURN (-1); + } + + acl_foreach(iter, args) { + ptr = (const char*) iter.data; + + if (strncasecmp(ptr, "PROC=", 5) == 0) { + ptr += 5; + if (proc) + acl_myfree(proc); + proc = acl_mystrdup(ptr); + } else if (strncasecmp(ptr, "PID=", 4) == 0) { + ptr += 4; + pid = atoi(ptr); + } else if (strncasecmp(ptr, "RCPT=", 5) == 0) { + ptr += 5; + rcpts = acl_argv_split(ptr, ",;\t "); + } else if (strncasecmp(ptr, "info=", 5) == 0) { + if (info) + acl_myfree(info); + ptr += 5; + info = acl_mystrdup(ptr); + } + } + + if (proc == NULL) { + acl_msg_error("%s(%d): invalid data(%s), no PROC", + __FUNCTION__, __LINE__, data); + RETURN (-1); + } + + to_mails = acl_argv_alloc(1); + to_phones = acl_argv_alloc(1); + acl_foreach(iter, rcpts) { + char *to = (char*) iter.data; + char *p = strchr(to, ':'); + if (p) + *p++ = 0; + to_mails->push_back(to_mails, to); + + /* 简单地判断是否是手机号 */ + if (p && strlen(p) == 11) + to_phones->push_back(to_phones, p); + } + + /* 邮件通知 */ + if (can_notify(smtp_notify_cache, proc, data)) + (void) smtp_notify(proc, to_mails, pid, + info == NULL ? "program exception!" : info); + else + acl_msg_info("%s(%d): data(%s) not be send to smtp!", + __FUNCTION__, __LINE__, data); + + /* 手机短信通知 */ + if (can_notify_sms(sms_notify_cache, proc, data)) + (void) sms_notify(proc, to_phones, pid, + info == NULL ? "program exception!" : info); + else + acl_msg_info("%s(%d): data(%s) not be send to sms!", + __FUNCTION__, __LINE__, data); + + acl_argv_free(to_phones); + acl_argv_free(to_mails); + + RETURN (0); +} diff --git a/samples/master/master_notify/notify.h b/samples/master/master_notify/notify.h new file mode 100644 index 000000000..93b454e6c --- /dev/null +++ b/samples/master/master_notify/notify.h @@ -0,0 +1,12 @@ +#ifndef __NOTIFY_INCLUDE_H__ +#define __NOTIFY_INCLUDE_H__ + +#include "lib_acl.h" + +int notify(ACL_CACHE *smtp_cache, ACL_CACHE *sms_cache, const char *data); +int smtp_notify(const char *proc, ACL_ARGV *rcpts, + int pid, const char *info); +int sms_notify(const char *proc, ACL_ARGV *rcpts, + int pid, const char *info); + +#endif diff --git a/samples/master/master_notify/service_main.c b/samples/master/master_notify/service_main.c new file mode 100644 index 000000000..6e18f4031 --- /dev/null +++ b/samples/master/master_notify/service_main.c @@ -0,0 +1,109 @@ +#include "lib_acl.h" +#include "notify.h" +#include "service_var.h" +#include "service_main.h" + +static ACL_CACHE *var_smtp_notify_cache; +static ACL_CACHE *var_sms_notify_cache; + +static void cache_free(const ACL_CACHE_INFO *info acl_unused, void *ctx) +{ + acl_myfree(ctx); +} + +/* 初始化函数 */ +void service_init(void *init_ctx acl_unused) +{ + const char *myname = "service_init"; + ACL_IFCONF *ifconf; + ACL_IFADDR *ifaddr; + ACL_ITER iter; + + service_var_init(); + var_smtp_notify_cache = acl_cache_create(10000, var_cfg_smtp_notify_cache_timeout, + cache_free); + var_sms_notify_cache = acl_cache_create(10000, var_cfg_sms_notify_cache_timeout, + cache_free); + acl_msg_info("%s: init ok ...", myname); + if (var_cfg_host_ip && *var_cfg_host_ip) + return; + + if (var_cfg_host_ip) + acl_myfree(var_cfg_host_ip); + var_cfg_host_ip = NULL; + + ifconf = acl_get_ifaddrs(); + + acl_foreach(iter, ifconf) { + ifaddr = (ACL_IFADDR*) iter.data; + + if (strcmp(ifaddr->ip, "127.0.0.1") == 0) + continue; + + acl_msg_info(">>>ip: %s", ifaddr->ip); + /* 外网IP优先 */ + if (strncmp(ifaddr->ip, "10.", 3) != 0 + && strncmp(ifaddr->ip, "192.", 4) != 0) + { + if (var_cfg_host_ip) + acl_myfree(var_cfg_host_ip); + var_cfg_host_ip = acl_mystrdup(ifaddr->ip); + } else if (var_cfg_host_ip == NULL) { + var_cfg_host_ip = acl_mystrdup(ifaddr->ip); + } + } +} + +/* 进程退出前调用的函数 */ +void service_exit(void *arg acl_unused) +{ + const char *myname = "service_exit"; + + acl_cache_free(var_smtp_notify_cache); + acl_cache_free(var_sms_notify_cache); + + service_var_end(); + + acl_msg_info("%s: exit now ...", myname); +} + +/* 协议处理函数入口 */ +int service_main(ACL_VSTREAM *client, void *run_ctx acl_unused) +{ +#if 0 + int ret, ready; + ACL_VSTRING *buf = acl_vstring_alloc(1024); + + while (1) { + ready = 0; + ACL_VSTRING_RESET(buf); + ret = acl_vstream_gets_peek(client, buf, &ready); + if (ret == ACL_VSTREAM_EOF) { + acl_vstring_free(buf); + return (-1); /* 返回负值以使框架内部关闭 client 数据流 */ + } else if (!ready) + break; + if (notify(acl_vstring_str(buf)) < 0) { + acl_vstring_free(buf); + return (-1); + } + } + acl_vstring_free(buf); + return (0); +#else + int ret; + char line[1024]; + + ret = acl_vstream_gets_nonl(client, line, sizeof(line)); + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): gets error(%s)", + __FUNCTION__, __LINE__, acl_last_serror()); + return (-1); + } + + if (notify(var_smtp_notify_cache, var_sms_notify_cache, line) < 0) + return (-1); + + return (0); +#endif +} diff --git a/samples/master/master_notify/service_main.h b/samples/master/master_notify/service_main.h new file mode 100644 index 000000000..6fd8023f9 --- /dev/null +++ b/samples/master/master_notify/service_main.h @@ -0,0 +1,34 @@ + +#ifndef __SERVICE_MAIN_INCLUDE_H__ +#define __SERVICE_MAIN_INCLUDE_H__ + +#include "lib_acl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * 初始化函数,服务器模板框架启动后仅调用该函数一次 + * @param init_ctx {void*} 用户自定义类型指针 + */ +extern void service_init(void *init_ctx); + +/** + * 进程退出时的回调函数 + * @param exist_ctx {void*} 用户自定义类型指针 + */ +extern void service_exit(void *exit_ctx); + +/** + * 协议处理函数入口 + * @param stream {ACL_VSTREAM*} 客户端数据连接流 + * @param run_ctx {void*} 用户自定义类型指针 + */ +extern int service_main(ACL_VSTREAM *stream, void *run_ctx); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/samples/master/master_notify/service_var.c b/samples/master/master_notify/service_var.c new file mode 100644 index 000000000..569a42a7f --- /dev/null +++ b/samples/master/master_notify/service_var.c @@ -0,0 +1,83 @@ +#include "lib_acl.h" +#include "service_var.h" + +char *var_cfg_debug_msg; +char *var_cfg_smtpd_addr; +char *var_cfg_mail_from; +char *var_cfg_mail_to; +char *var_cfg_mail_cc; +char *var_cfg_mail_bcc; +char *var_cfg_auth_user; +char *var_cfg_auth_pass; +char *var_cfg_warn_mail; +char *var_cfg_smtp_helo; +char *var_cfg_sms_addr; +char *var_cfg_host_ip; + +ACL_CFG_STR_TABLE var_conf_str_tab[] = { + { "debug_msg", "test_msg", &var_cfg_debug_msg }, + + /* 邮件通知相关 */ + + { "smtpd_addr", "mail.inc365.com:25", &var_cfg_smtpd_addr }, + { "mail_from", "acl_notify@acl_master.com", &var_cfg_mail_from }, + { "mail_to", "", &var_cfg_mail_to }, + { "mail_cc", "", &var_cfg_mail_cc }, + { "mail_bcc", "", &var_cfg_mail_bcc }, + { "auth_user", "", &var_cfg_auth_user }, + { "auth_pass", "", &var_cfg_auth_pass }, + { "warn_mail", "warning_letter.tmpl", &var_cfg_warn_mail }, + { "stmp_helo", "test.com", &var_cfg_smtp_helo }, + + { "sms_addr", "", &var_cfg_sms_addr }, + { "host_ip", "", &var_cfg_host_ip }, + + { 0, 0, 0 } +}; + +int var_cfg_debug_enable; +int var_cfg_keep_alive; + +ACL_CFG_BOOL_TABLE var_conf_bool_tab[] = { + { "debug_enable", 1, &var_cfg_debug_enable }, + { "keep_alive", 1, &var_cfg_keep_alive }, + + { 0, 0, 0 } +}; + +int var_cfg_io_timeout; +int var_cfg_smtp_notify_cache_timeout; +int var_cfg_sms_notify_cache_timeout; +int var_cfg_work_week_min; +int var_cfg_work_week_max; +int var_cfg_work_hour_min; +int var_cfg_work_hour_max; + +ACL_CFG_INT_TABLE var_conf_int_tab[] = { + { "io_timeout", 120, &var_cfg_io_timeout, 0, 0 }, + { "smtp_notify_cache_timeout", 60, &var_cfg_smtp_notify_cache_timeout, 0, 0 }, + { "sms_notify_cache_timeout", 600, &var_cfg_sms_notify_cache_timeout, 0, 0 }, + { "work_week_min", 1, &var_cfg_work_week_min, 0, 0 }, + { "work_week_max", 1, &var_cfg_work_week_max, 0, 0 }, + { "work_hour_min", 9, &var_cfg_work_hour_min, 0, 0 }, + { "work_hour_max", 18, &var_cfg_work_hour_max, 0, 0 }, + + { 0, 0 , 0 , 0, 0 } +}; + +ACL_ARGV *var_recipients = NULL; +ACL_ARGV *var_ccs = NULL; +ACL_ARGV *var_bccs = NULL; + +void service_var_init() +{ + var_recipients = acl_argv_split(var_cfg_mail_to, ",; \t"); + var_ccs = acl_argv_split(var_cfg_mail_cc, ",; \t"); + var_bccs = acl_argv_split(var_cfg_mail_bcc, ",; \t"); +} + +void service_var_end() +{ + if (var_recipients) + acl_argv_free(var_recipients); +} diff --git a/samples/master/master_notify/service_var.h b/samples/master/master_notify/service_var.h new file mode 100644 index 000000000..81cd18fb8 --- /dev/null +++ b/samples/master/master_notify/service_var.h @@ -0,0 +1,52 @@ +#ifndef __SERVICE_VAR_INCLUDE_H__ +#define __SERVICE_VAR_INCLUDE_H__ + +#include "lib_acl.h" + +/*------------- 字符串配置项 ----------------*/ + +extern ACL_CFG_STR_TABLE var_conf_str_tab[]; + +extern char *var_cfg_debug_msg; +extern char *var_cfg_smtpd_addr; +extern char *var_cfg_mail_from; +extern char *var_cfg_mail_to; +extern char *var_cfg_auth_user; +extern char *var_cfg_auth_pass; +extern char *var_cfg_warn_mail; +extern char *var_cfg_smtp_helo; +extern char *var_cfg_sms_addr; +extern char *var_cfg_host_ip; + +/*-------------- 布尔值配置项 ---------------*/ + +extern ACL_CFG_BOOL_TABLE var_conf_bool_tab[]; + +/* 是否输出日志调试信息 */ +extern int var_cfg_debug_enable; + +/* 是否与客户端保持长连接 */ +extern int var_cfg_keep_alive; + +/*-------------- 整数配置项 -----------------*/ + +extern ACL_CFG_INT_TABLE var_conf_int_tab[]; + +/* 每次与客户端通信时,读超时时间(秒) */ +extern int var_cfg_io_timeout; +extern int var_cfg_smtp_notify_cache_timeout; +extern int var_cfg_sms_notify_cache_timeout; +extern int var_cfg_work_week_min; +extern int var_cfg_work_week_max; +extern int var_cfg_work_hour_min; +extern int var_cfg_work_hour_max; + +/*----------------- 非配置项的全局变量 ------*/ +extern ACL_ARGV *var_recipients; +extern ACL_ARGV *var_ccs; +extern ACL_ARGV *var_bccs; + +void service_var_init(void); +void service_var_end(void); + +#endif diff --git a/samples/master/master_notify/sms_notify.c b/samples/master/master_notify/sms_notify.c new file mode 100644 index 000000000..3a92f1698 --- /dev/null +++ b/samples/master/master_notify/sms_notify.c @@ -0,0 +1,95 @@ +#include "lib_acl.h" +#include +#include "lib_tpl.h" +#include "service_var.h" +#include "notify.h" + +/* +连接9010端口,之后发送xml格式为 +成功则返回 +失败则返回 + +支持多个连接,每个连接可以连续发送,长连接可不断 +122.49.0.234 +*/ + +static int sms_send(ACL_VSTREAM *client, const char *phone, const char *proc, + int pid, const char *info, const char *ip) +{ + ACL_VSTRING *buf = acl_vstring_alloc(256); + ACL_XML *xml = acl_xml_alloc(); + char res[1024]; + int ret; + + acl_vstring_sprintf(buf, "", + phone, proc, pid, ip, info); + if (acl_vstream_writen(client, acl_vstring_str(buf), ACL_VSTRING_LEN(buf)) + == ACL_VSTREAM_EOF) + { + acl_msg_error("write to sms server error, msg: %s", + acl_vstring_str(buf)); + acl_vstring_free(buf); + return (-1); + } + + acl_msg_info(">>send: %s", acl_vstring_str(buf)); + acl_vstring_free(buf); + + while (1) { + ret = acl_vstream_read(client, res, sizeof(res) - 1); + if (ret == ACL_VSTREAM_EOF) + return (-1); + res[ret] = 0; + acl_xml_parse(xml, res); + if (acl_xml_is_complete(xml, "send_sms")) { + acl_msg_info("send ok!(%s)", res); + break; + } + } + + return (0); +} + +int sms_notify(const char *proc, ACL_ARGV *rcpts, + int pid, const char *info) +{ + ACL_ITER iter; + ACL_VSTREAM *client; + char ip[64], *ptr; + + if (var_cfg_sms_addr == NULL || *var_cfg_sms_addr == 0) { + acl_msg_info("%s(%d): var_cfg_sms_addr null", + __FUNCTION__, __LINE__); + return (0); + } + + client = acl_vstream_connect(var_cfg_sms_addr, ACL_BLOCKING, + 30, 30, 4096); + if (client == NULL) { + acl_msg_error("%s(%d): connect %s error(%s)", + __FUNCTION__, __LINE__, + var_cfg_sms_addr, acl_last_serror()); + return (-1); + } + + if (var_cfg_host_ip && *var_cfg_host_ip) { + snprintf(ip, sizeof(ip), "%s", var_cfg_host_ip); + } else if (acl_getsockname(ACL_VSTREAM_SOCK(client), ip, sizeof(ip)) < 0) { + acl_msg_warn("%s(%d): get local ip error: %s", + __FUNCTION__, __LINE__, acl_last_serror()); + snprintf(ip, sizeof(ip), "127.0.0.1"); + } else { + ptr = strchr(ip, ':'); + if (ptr) + *ptr = 0; + } + + acl_foreach(iter, rcpts) { + const char *phone = (const char*) iter.data; + if (sms_send(client, phone, proc, pid, info, ip) < 0) + break; + } + + acl_vstream_close(client); + return (0); +} diff --git a/samples/master/master_notify/smtp_notify.c b/samples/master/master_notify/smtp_notify.c new file mode 100644 index 000000000..9f78cd330 --- /dev/null +++ b/samples/master/master_notify/smtp_notify.c @@ -0,0 +1,491 @@ +#include "lib_acl.h" +#include +#include "lib_tpl.h" +#include "service_var.h" +#include "notify.h" + +static char* get_warning_mail(const char *proc, ACL_ARGV *rcpts, int pid, + const char *info, const char *ip) +{ + tpl_t *tpl; + time_t now = time(NULL); + struct tm local_time; + char date[64], *buf; + int size; + ACL_ITER iter; + ACL_VSTRING *tos; + + /* 打开模板文件并创建模板对象 */ + tpl = tpl_alloc(); + if (tpl_load(tpl, var_cfg_warn_mail) != TPL_OK) { + acl_msg_error("load %s error(%s)", var_cfg_warn_mail, + acl_last_serror()); + return (NULL); + } + + localtime_r(&now, &local_time); + + strftime(date, sizeof(date), "%Y/%m/%d %H:%M:%S", &local_time); + + tpl_set_field_fmt_global(tpl, "VAR_FROM", "%s", var_cfg_mail_from); + + tos = acl_vstring_alloc(256); + acl_foreach(iter, var_recipients) { + const char *ptr = (const char*) iter.data; + + if (ACL_VSTRING_LEN(tos) > 0) + acl_vstring_strcat(tos, ",\r\n\t"); + acl_vstring_strcat(tos, ptr); + } + if (rcpts) { + acl_foreach(iter, rcpts) { + const char *ptr = (const char*) iter.data; + + if (ACL_VSTRING_LEN(tos) > 0) + acl_vstring_strcat(tos, ",\r\n\t"); + acl_vstring_strcat(tos, ptr); + } + } + tpl_set_field_fmt_global(tpl, "VAR_TOS", "%s", acl_vstring_str(tos)); + + ACL_VSTRING_RESET(tos); + acl_foreach(iter, var_ccs) { + const char *ptr = (const char*) iter.data; + + if (ACL_VSTRING_LEN(tos) > 0) + acl_vstring_strcat(tos, ",\r\n\t"); + acl_vstring_strcat(tos, ptr); + } + if (ACL_VSTRING_LEN(tos) > 0) + tpl_set_field_fmt_global(tpl, "VAR_CCS", + "Cc: %s\r\n", acl_vstring_str(tos)); + + acl_vstring_free(tos); + + tpl_set_field_fmt_global(tpl, "VAR_ID", "%ld.%ld.localhost", + acl_pthread_self(), getpid()); + tpl_set_field_fmt_global(tpl, "VAR_HOST", "%s", ip); + tpl_set_field_fmt_global(tpl, "VAR_DATE", "%s", date); + + /* 进程相关信息 */ + tpl_set_field_fmt_global(tpl, "VAR_PROC", "%s", proc); + tpl_set_field_fmt_global(tpl, "VAR_PID", "%d", pid); + tpl_set_field_fmt_global(tpl, "VAR_INFO", "%s", info); + + size = tpl_length(tpl); + if (size <= 0) + { + acl_msg_error("%s's size is 0!", var_cfg_warn_mail); + return (NULL); + } + + size += 1; + + buf = (char*) acl_mymalloc(size); + tpl_get_content(tpl, buf); + tpl_free(tpl); + + return (buf); +} + +static int smtp_banner(ACL_VSTREAM *client) +{ + char line[1024]; + int ret; + + /* 读取欢迎信息 */ + ret = acl_vstream_gets_nonl(client, line, sizeof(line)); + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): gets banner error from %s", + __FUNCTION__, __LINE__, var_cfg_smtpd_addr); + return (-1); + } + + return (0); +} + +static int smtp_helo(ACL_VSTREAM *client) +{ + char line[1024]; + int ret; + + /* 发送 helo 信息 */ + ret = acl_vstream_fprintf(client, "helo %s\r\n", var_cfg_smtp_helo); + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): send helo to %s error(%s)", + __FUNCTION__, __LINE__, var_cfg_smtpd_addr, + acl_last_serror()); + return (-1); + } + + /* 读取响应信息 */ + ret = acl_vstream_gets_nonl(client, line, sizeof(line)); + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): gets helo's reply from %s error(%s)", + __FUNCTION__, __LINE__, var_cfg_smtpd_addr, + acl_last_serror()); + return (-1); + } + + return (0); +} + +static int smtp_auth(ACL_VSTREAM *client) +{ + char line[1024]; + int ret; + ACL_ARGV *tokens = NULL; + char *user = NULL, *pass = NULL; + +#undef RETURN +#define RETURN(x) do { \ + if (tokens) \ + acl_argv_free(tokens); \ + if (user) \ + acl_myfree(user); \ + if (pass) \ + acl_myfree(pass); \ + return (x); \ +} while (0) + + /* 发送认证命令 */ + + ret = acl_vstream_fprintf(client, "AUTH LOGIN\r\n"); + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): send AUTH LOGIN to %s error(%s)", + __FUNCTION__, __LINE__, var_cfg_smtpd_addr, + acl_last_serror()); + RETURN (-1); + } + + ret = acl_vstream_gets_nonl(client, line, sizeof(line)); + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): gets reply for AUTH LOGIN from %s error(%s)", + __FUNCTION__, __LINE__, var_cfg_smtpd_addr, + acl_last_serror()); + RETURN (-1); + } + + tokens = acl_argv_split(line, "\t "); + if (strcmp(tokens->argv[0], "334") != 0) { + acl_msg_error("%s(%d): AUTH LOGIN failed from %s, line(%s)", + __FUNCTION__, __LINE__, var_cfg_smtpd_addr, line); + RETURN (-1); + } + + /* 发送邮箱帐号 */ + + user = (char*) acl_base64_encode(var_cfg_auth_user, strlen(var_cfg_auth_user)); + ret = acl_vstream_fprintf(client, "%s\r\n", user); + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): send user to %s error(%s)", + __FUNCTION__, __LINE__, var_cfg_smtpd_addr, + acl_last_serror()); + RETURN (-1); + } + + ret = acl_vstream_gets_nonl(client, line, sizeof(line)); + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): gets from %s error(%s)", + __FUNCTION__, __LINE__, var_cfg_smtpd_addr, + acl_last_serror()); + RETURN (-1); + } + acl_argv_free(tokens); + tokens = acl_argv_split(line, "\t "); + if (strcmp(tokens->argv[0], "334") != 0) { + acl_msg_error("%s(%d): AUTH LOGIN failed from %s, line(%s)", + __FUNCTION__, __LINE__, var_cfg_smtpd_addr, line); + RETURN (-1); + } + + /* 发送 password */ + + pass = (char*) acl_base64_encode(var_cfg_auth_pass, strlen(var_cfg_auth_pass)); + ret = acl_vstream_fprintf(client, "%s\r\n", pass); + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): send pass to %s error(%s)", + __FUNCTION__, __LINE__, var_cfg_smtpd_addr, + acl_last_serror()); + RETURN (-1); + } + ret = acl_vstream_gets_nonl(client, line, sizeof(line)); + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): gets pass's reply from %s error(%s)", + __FUNCTION__, __LINE__, var_cfg_smtpd_addr, + acl_last_serror()); + RETURN (-1); + } + acl_argv_free(tokens); + tokens = acl_argv_split(line, "\t "); + if (strcmp(tokens->argv[0], "235") != 0) { + acl_msg_error("%s(%d): AUTH LOGIN failed from %s, line(%s)", + __FUNCTION__, __LINE__, var_cfg_smtpd_addr, line); + RETURN (-1); + } + + RETURN (0); +} + +static int smtp_from(ACL_VSTREAM *client) +{ + char line[1024]; + int ret; + ACL_ARGV *tokens; + + /* 发送 mail from 信息 */ + ret = acl_vstream_fprintf(client, "mail from: <%s>\r\n", var_cfg_mail_from); + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): send mail from to %s error(%s)", + __FUNCTION__, __LINE__, var_cfg_smtpd_addr, + acl_last_serror()); + return (-1); + } + + /* 读取响应信息 */ + ret = acl_vstream_gets_nonl(client, line, sizeof(line)); + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): gets mail from's reply from %s error(%s)", + __FUNCTION__, __LINE__, var_cfg_smtpd_addr, + acl_last_serror()); + return (-1); + } + + tokens = acl_argv_split(line, "\t "); + if (strcmp(tokens->argv[0], "250") != 0) { + acl_msg_error("%s(%d): denied by server(%s), line(%s)", + __FUNCTION__, __LINE__, var_cfg_smtpd_addr, line); + acl_argv_free(tokens); + return (-1); + } + + acl_argv_free(tokens); + return (0); +} + +static int smtp_to(ACL_VSTREAM *client, const char *to) +{ + char line[1024]; + int ret; + ACL_ARGV *tokens; + + ret = acl_vstream_fprintf(client, "rcpt to: <%s>\r\n", to); + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): send rcpt to %s error(%s)", + __FUNCTION__, __LINE__, var_cfg_smtpd_addr, + acl_last_serror()); + return (-1); + } + + ret = acl_vstream_gets_nonl(client, line, sizeof(line)); + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): gets rcpt's reply from %s error(%s)", + __FUNCTION__, __LINE__, var_cfg_smtpd_addr, + acl_last_serror()); + return (-1); + } + + tokens = acl_argv_split(line, "\t "); + if (strcmp(tokens->argv[0], "250") != 0) { + acl_msg_error("%s(%d): rcpt to %s error, line(%s)", + __FUNCTION__, __LINE__, var_cfg_smtpd_addr, line); + acl_argv_free(tokens); + return (-1); + } + + acl_argv_free(tokens); + acl_msg_info(">>> send to: %s ok!", to); + return (0); +} + +static int smtp_tos(ACL_VSTREAM *client, ACL_ARGV *rcpts) +{ + ACL_ITER iter; + int nok = 0, ret; + + acl_foreach(iter, var_recipients) { + const char *to = (const char*) iter.data; + + ret = smtp_to(client, to); + if (ret == 0) + nok++; + else if (ACL_IF_VSTREAM_ERR(client)) + return (-1); + } + acl_foreach(iter, var_ccs) { + const char *to = (const char*) iter.data; + + ret = smtp_to(client, to); + if (ret == 0) + nok++; + else if (ACL_IF_VSTREAM_ERR(client)) + return (-1); + } + acl_foreach(iter, var_bccs) { + const char *to = (const char*) iter.data; + + ret = smtp_to(client, to); + if (ret == 0) + nok++; + else if (ACL_IF_VSTREAM_ERR(client)) + return (-1); + } + + if (rcpts == NULL) + return (nok); + + acl_foreach(iter, rcpts) { + const char *to = (const char*) iter.data; + + ret = smtp_to(client, to); + if (ret == 0) + nok++; + else if (ACL_IF_VSTREAM_ERR(client)) + return (-1); + } + + return (nok); +} + +static int smtp_data(ACL_VSTREAM *client, const char *proc, + ACL_ARGV *rcpts, int pid, const char *info, const char *ip) +{ + char line[1024]; + ACL_ARGV *tokens; + int ret; + char *buf; + + ret = acl_vstream_fprintf(client, "data\r\n"); + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): send data to %s error(%s)", + __FUNCTION__, __LINE__, var_cfg_smtpd_addr, + acl_last_serror()); + return (-1); + } + + ret = acl_vstream_gets_nonl(client, line, sizeof(line)); + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): gets data's reply from %s error(%s)", + __FUNCTION__, __LINE__, var_cfg_smtpd_addr, + acl_last_serror()); + return (-1); + } + + tokens = acl_argv_split(line, "\t "); + if (strcmp(tokens->argv[0], "354") != 0) { + acl_msg_error("%s(%d): denied from %s, line(%s)", + __FUNCTION__, __LINE__, var_cfg_smtpd_addr, line); + acl_argv_free(tokens); + return (-1); + } + acl_argv_free(tokens); + + buf = get_warning_mail(proc, rcpts, pid, info, ip); + if (buf == NULL) { + acl_msg_error("%s(%d): get_warning_mail error", + __FUNCTION__, __LINE__); + return (-1); + } + ret = acl_vstream_writen(client, buf, strlen(buf)); + acl_myfree(buf); + + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): send mail error(%s) to %s", + __FUNCTION__, __LINE__, acl_last_serror(), + var_cfg_smtpd_addr); + return (-1); + } + ret = acl_vstream_fprintf(client, "\r\n.\r\n"); + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): send mail eof error(%s) to %s", + __FUNCTION__, __LINE__, acl_last_serror(), + var_cfg_smtpd_addr); + return (-1); + } + + ret = acl_vstream_gets(client, line, sizeof(line)); + if (ret == ACL_VSTREAM_EOF) { + acl_msg_error("%s(%d): gets mail eof's reply error(%s) from %s", + __FUNCTION__, __LINE__, acl_last_serror(), + var_cfg_smtpd_addr); + return (-1); + } + + tokens = acl_argv_split(line, "\t "); + if (strcmp(tokens->argv[0], "250") != 0) { + acl_msg_error("%s(%d): send mail error to %s, line: %s", + __FUNCTION__, __LINE__, var_cfg_smtpd_addr, line); + acl_argv_free(tokens); + return (-1); + } + acl_argv_free(tokens); + return (0); +} + +static int smtp_sendmail(const char *proc, ACL_ARGV *rcpts, + int pid, const char *info) +{ + ACL_VSTREAM *client = NULL; + char ip[64], *ptr; + +#undef RETURN +#define RETURN(x) do { \ + if (client) \ + acl_vstream_close(client); \ + return (x); \ +} while (0) + + client = acl_vstream_connect(var_cfg_smtpd_addr, ACL_BLOCKING, + 30, 30, 4096); + if (client == NULL) { + acl_msg_error("%s(%d): connect %s error(%s)", + __FUNCTION__, __LINE__, var_cfg_smtpd_addr, + acl_last_serror()); + RETURN (-1); + } + + if (var_cfg_host_ip && *var_cfg_host_ip) { + snprintf(ip, sizeof(ip), "%s", var_cfg_host_ip); + } else if (acl_getsockname(ACL_VSTREAM_SOCK(client), ip, sizeof(ip)) < 0) { + acl_msg_warn("%s(%d): get local ip error: %s", + __FUNCTION__, __LINE__, acl_last_serror()); + snprintf(ip, sizeof(ip), "127.0.0.1"); + } else { + ptr = strchr(ip, ':'); + if (ptr) + *ptr = 0; + } + + acl_msg_info("use ip: %s", var_cfg_host_ip); + + if (smtp_banner(client) < 0) + RETURN (-1); + if (smtp_helo(client) < 0) + RETURN (-1); + if (*var_cfg_auth_user != 0 && *var_cfg_auth_pass != 0) { + if (smtp_auth(client) < 0) + RETURN (-1); + } + if (smtp_from(client) < 0) + RETURN (-1); + if (smtp_tos(client, rcpts) < 0) + RETURN (-1); + if (smtp_data(client, proc, rcpts, pid, info, ip) < 0) + RETURN (-1); + acl_msg_info("send mail ok!"); + RETURN (0); +} + +int smtp_notify(const char *proc, ACL_ARGV *rcpts, + int pid, const char *info) +{ + if (*var_cfg_smtpd_addr == 0 || *var_cfg_warn_mail == 0 + || var_recipients == NULL) + { + acl_msg_info("smtp_notify not sent!, smtpd_addr: %s, warn_mail: %s", + var_cfg_smtpd_addr, var_cfg_warn_mail); + return (0); + } + + return (smtp_sendmail(proc, rcpts, pid, info)); +} diff --git a/samples/master/master_notify/tpllib.c b/samples/master/master_notify/tpllib.c new file mode 100644 index 000000000..da3e9a8ca --- /dev/null +++ b/samples/master/master_notify/tpllib.c @@ -0,0 +1,1276 @@ +/* + * tpllib + * + * C library of functions for text template processing. + * Copyright (C) 2003-2007 Niels Wojciech Tadeusz Andersen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef WIN32 +#include /* write() */ +#else +#include /* write() */ +#endif + +#include /* exit() */ +#include /* fopen(), sprintf() ... */ +#include /* va_start(), va_end() */ +#include /* memset(), memcmp() ... */ + +/* Define ZTS when building a PHP extension */ +/* Define WIN32 when compiling under MS Windows */ + +#ifdef WIN32 +# define snprintf _snprintf +# define vsnprintf _vsnprintf +#endif + +#include "lib_tpl.h" + +/* Length defines for markup elements */ +#define DELIM_LEN_LEFT (sizeof(DELIMITER_LEFT) - 1) +#define DELIM_LEN_RIGHT (sizeof(DELIMITER_RIGHT) - 1) +#define SEC_HEAD_LEN (sizeof(SECTIONTAG_HEAD) - 1) +#define SEC_TAIL_LEN (sizeof(SECTIONTAG_TAIL) - 1) + + +#define M_MIN(a, b) (((a) < (b)) ? (a) : (b)) +#define M_MAX(a, b) (((a) > (b)) ? (a) : (b)) + +#define M_NODE_LEN(n) (((n)->val) ? (n)->len : (n)->fval->len) +#define M_NODE_TEXT(n) (((n)->val) ? (n)->val : (n)->fval->val) + +#define M_INT_TO_STRING(buffer, buffer_len, val, signed_v) \ + do \ + { \ + char rev[5 * sizeof(int) / 2]; \ + int i = 0, digits = 0; \ + if ((signed_v) && (val) < 0) \ + { \ + buffer[i] = '-'; \ + i++; \ + } \ + do \ + { \ + rev[digits++] = '0' + abs((val) % 10); \ + (val) /= 10; \ + } \ + while ((val) != 0); \ + for (; digits > 0 && i < (buffer_len); i++) \ + buffer[i] = rev[--digits]; \ + buffer[i] = 0; \ + (buffer_len) = i; \ + } while (0) + + +/* Binary safe string search */ +static const char *tpl_strstr(register const char *haystack, + ssize_t haystack_len, + const char *needle, + int needle_len) +{ + ssize_t i; + const char *p_toofar = haystack + haystack_len - needle_len + 1; + + if (p_toofar <= haystack) + return NULL; + + do + { + if (*haystack == *needle) + { + for (i = 1; i != needle_len && haystack[i] == needle[i]; i++); + + if (i == needle_len) + return haystack; + } + + haystack++; + } + while (haystack != p_toofar); + + return NULL; +} + + +static tpl_node_t* create_node(int len) +{ + tpl_node_t* node = (tpl_node_t*)acl_mymalloc(len+1+sizeof(tpl_node_t)); + node->len = len; + node->val = (char*)(node + 1); + node->next = NULL; + return node; +} + + +static void destroy_node(tpl_node_t* node) +{ + acl_myfree(node); +} + + +static tpl_fcell_t* create_fcell(const char *key, int key_len, int data_len) +{ + tpl_fcell_t* field = (tpl_fcell_t*)acl_mymalloc(key_len + 1 + + sizeof(tpl_fcell_t)); + + field->key = (char *)(field + 1); + + (void)memcpy(field->key, key, key_len); + field->key[key_len] = 0; + field->val = (char *)acl_mymalloc(M_MAX(data_len, INITIAL_FIELD_LEN) + 1); + field->len = 0; + field->val[0] = 0; + field->next = NULL; + return field; +} + + +static void destroy_fcell(tpl_fcell_t* field) +{ + acl_myfree(field->val); + acl_myfree(field); +} + + +static tpl_tcell_t* create_tcell(const char *key, int key_len) +{ + tpl_tcell_t* section = (tpl_tcell_t*)acl_mymalloc(key_len + 1 + + sizeof(tpl_tcell_t) + + sizeof(tpl_t)); + section->tpl = (tpl_t *)(section + 1); + tpl_init(section->tpl); + + section->key = (char *)(section->tpl + 1); + (void)memcpy(section->key, key, key_len); + + section->key[key_len] = 0; + section->next = NULL; + section->_next = NULL; + return section; +} + + +static void destroy_tcell(tpl_tcell_t* section) +{ + tpl_release(section->tpl); + acl_myfree(section); +} + + +/* Hash function using multipy by 31 */ +static unsigned int tpl_hash(const char *key, int key_len) +{ + const char *p_key_end = key + key_len; + register unsigned int h = *key++; + + while (key != p_key_end && *key != 0) + { + unsigned int g; + h = (h << 5) + *key++; + if ((g = h & 0xf0000000) != 0) + h = (h ^ (g >> 24) ^ g); + } + return h % HASH_TABLE_SIZE; +} + +static tpl_fcell_t* tpl_produce_field(tpl_t *tpl, + const char* key, + int key_len, + int data_len, + int may_create) +{ + tpl_fcell_t **pfield = &tpl->fields[tpl_hash(key, key_len)]; + + while (*pfield != NULL) + { + if (memcmp((*pfield)->key, key, key_len) == 0) + { + if (data_len > INITIAL_FIELD_LEN && data_len > (*pfield)->len) + (*pfield)->val = (char*) acl_myrealloc((*pfield)->val, data_len); + + return *pfield; + } + + pfield = &(*pfield)->next; + } + + if (*pfield == NULL && may_create != 0) + { + *pfield = create_fcell(key, key_len, data_len); + return *pfield; + } + + return NULL; +} + +#define tpl_get_field(tpl, key) \ + tpl_produce_field((tpl), (key), strlen((key)), 0, 0) + +#define tpl_new_field(tpl, key, key_len) \ + tpl_produce_field((tpl), (key), (key_len), 0, 1) + +#define tpl_cpy_field(field, tpl, key, key_len, data, data_len) \ + do \ + { \ + (field) = tpl_produce_field((tpl), (key), (key_len), (data_len), 1); \ + if ((field)->len == 0 && (data_len) != 0) \ + { \ + (void)memcpy((field)->val, (data), (data_len));\ + (field)->val[(data_len)] = 0; \ + (field)->len = (data_len); \ + } \ + } while (0) + + +static tpl_tcell_t* tpl_produce_section(tpl_t *tpl, + const char* key, + int key_len, + int must_create) +{ + tpl_tcell_t **psection = &tpl->sections[tpl_hash(key, key_len)]; + + while (*psection != NULL) + { + if (memcmp((*psection)->key, key, key_len) == 0) + return (must_create) ? NULL : *psection; + + psection = &(*psection)->_next; + } + if (*psection == NULL && must_create) + { + *psection = create_tcell(key, key_len); + (*psection)->tpl->parent = tpl; + return *psection; + } + + return NULL; +} + +#define tpl_get_section(tpl, key) \ + tpl_produce_section(tpl, key, strlen(key), 0) + +#define tpl_make_section(tpl, key, key_len) \ + tpl_produce_section(tpl, key, key_len, 1) + + +/* Big, ugly, horrible, quite possibly buggy... + live with it or correct it and let me know */ +static int tpl_construct(tpl_t *tpl, const char *p_last, const char *p_end) +{ + const char *p_begin = p_last, *p_curr, *p_next; + tpl_node_t **tail = &tpl->head; + tpl_tcell_t **last_section = &tpl->first; + + /* While a field delimiter can be found in what is left */ + while ((p_curr = tpl_strstr(p_last, p_end - p_last, + DELIMITER_LEFT, DELIM_LEN_LEFT)) != NULL) + { + /* Advance to beginning of field/section name */ + p_curr += DELIM_LEN_LEFT; + + /* Find end delimiter of identifier or fail with syntax error */ + p_next = tpl_strstr(p_curr, p_end - p_curr, DELIMITER_RIGHT, DELIM_LEN_RIGHT); + + if (p_next == NULL) + { + *last_section = NULL; + *tail = NULL; + return TPL_SYNTAX_ERROR; + } + + /* Section */ + if (p_curr + 1 >= p_begin + SEC_HEAD_LEN + && p_end - p_next >= (int) SEC_TAIL_LEN + && memcmp(SECTIONTAG_HEAD, p_curr - SEC_HEAD_LEN, + SEC_HEAD_LEN) == 0 + && memcmp(SECTIONTAG_TAIL, p_next, SEC_TAIL_LEN) == 0) + { + tpl_tcell_t *section; + + if ((p_curr - SEC_HEAD_LEN - p_last) != 0) + { + int val_len = p_curr - SEC_HEAD_LEN - p_last; + *tail = create_node(val_len); + (*tail)->val[val_len] = 0; + (void)memcpy((*tail)->val, p_last, val_len); + tail = &(*tail)->next; + } + + /* Create and chain in entry for section */ + section = tpl_make_section(tpl, p_curr, p_next - p_curr); + + if (section != NULL) + { + int code; + const char *beginning, *ending; + + *last_section = section; + last_section = §ion->next; + section->preceding = tail; + + /* Advance past the section tag */ + p_last = p_next + SEC_TAIL_LEN; + beginning = p_next + SEC_TAIL_LEN; + + /* Find next occurrence of this section tag */ + ending = tpl_strstr(beginning, + p_end - beginning, + p_curr - SEC_HEAD_LEN, + beginning - p_curr + SEC_HEAD_LEN); + + p_last = ending + (SEC_HEAD_LEN + p_last - p_curr); + + /* If found and found before p_end */ + if (ending != NULL && p_last <= p_end) + { + /* Construct recursively */ + code = tpl_construct(section->tpl, beginning, ending); + } + else + code = TPL_SYNTAX_ERROR; + + if (code != TPL_OK) + { + tpl_release(section->tpl); + tpl_init(section->tpl); + *last_section = NULL; + *tail = NULL; + return TPL_SYNTAX_ERROR; + } + } + else + { + *last_section = NULL; + *tail = NULL; + return TPL_SYNTAX_ERROR; + } + } + /* Field */ + else + { + if ((p_curr - DELIM_LEN_LEFT - p_last) != 0) + { + int val_len = p_curr - DELIM_LEN_LEFT - p_last; + *tail = create_node(val_len); + (*tail)->val[val_len] = 0; + (void)memcpy((*tail)->val, p_last, val_len); + tail = &(*tail)->next; + } + + p_last = p_next + DELIM_LEN_RIGHT; + + /* Create node and set fval to new field cell */ + *tail = create_node(0); + (*tail)->val = NULL; + (*tail)->fval = tpl_new_field(tpl, p_curr, p_next - p_curr); + tail = &(*tail)->next; + } + } + + /* Store rest of the text */ + if (p_last < p_end) + { + int val_len = p_end - p_last; + *tail = create_node(val_len); + (void)memcpy((*tail)->val, p_last, val_len); + (*tail)->val[val_len] = 0; + tail = &(*tail)->next; + } + *tail = NULL; + *last_section = NULL; + + return TPL_OK; +} + +void tpl_init(tpl_t *tpl) +{ + /* Set everything to NULL */ + (void)memset(tpl, 0, sizeof(tpl_t)); + + tpl->tpl = tpl; + tpl->added_tail = &tpl->added_head; +} + +void tpl_release(tpl_t *tpl) +{ + register int i; + + /* Free nodes */ + while (tpl->head != NULL) + { + tpl_node_t *deleted = tpl->head; + tpl->head = tpl->head->next; + destroy_node(deleted); + } + + /* Free any added content */ + while (tpl->added_head != NULL) + { + tpl_node_t *deleted = tpl->added_head; + tpl->added_head = tpl->added_head->next; + destroy_node(deleted); + } + /* Free field cells */ + for (i = 0; i < HASH_TABLE_SIZE; i++) + { + tpl_fcell_t *fc = tpl->fields[i]; + + while (fc != NULL) + { + tpl_fcell_t *deleted = fc; + fc = fc->next; + destroy_fcell(deleted); + } + } + /* Free sections including added content */ + while (tpl->first != NULL) + { + tpl_tcell_t *deleted = tpl->first; + tpl->first = tpl->first->next; + + /* This will call tpl_release() recursively */ + destroy_tcell(deleted); + } +} + +tpl_t* tpl_alloc(void) +{ + tpl_t *tpl = (tpl_t*)acl_mymalloc(sizeof(tpl_t)); + tpl_init(tpl); + return tpl; +} + +void tpl_free(tpl_t *tpl) +{ + tpl_release(tpl); + acl_myfree(tpl); +} + +/* Load template file */ +int tpl_load(tpl_t *tpl, const char *filename) +{ + char *buffer; + int len; + FILE *fp = fopen(filename, "rb"); + + if (fp == NULL) + return TPL_OPEN_ERROR; + + /* Find length of file content */ + (void)fseek(fp, 0, SEEK_END); + len = ftell(fp); + (void) rewind(fp); + + /* Allocate buffer for data + 0 byte */ + buffer = (char*)acl_mymalloc(len+1); + + if (fread(buffer, 1, len, fp) < (unsigned)len) + { + (void)fclose(fp); + acl_myfree(buffer); + return TPL_READ_ERROR; + } + (void)fclose(fp); + buffer[len] = 0; + + /* Use data in buffer to construct template */ + len = tpl_construct(tpl, buffer, buffer + len); + if (len != TPL_OK) + { + tpl_release(tpl); + tpl_init(tpl); + } + acl_myfree(buffer); + return len; +} + +/* Load from a string */ +int tpl_from_string(tpl_t *tpl, const char *buffer, int len) +{ + return tpl_construct(tpl, buffer, buffer + len); +} + +/* Recursively clear added content */ +void tpl_reset(tpl_t* tpl) +{ + int i = HASH_TABLE_SIZE; + tpl_tcell_t* section; + + /* Clear fields */ + while (i != 0) + { + tpl_fcell_t* field = tpl->fields[--i]; + while (field != NULL) + { + field->len = 0; + *field->val = 0; + field = field->next; + } + } + /* Clear sections */ + for (section = tpl->first; section != NULL; section = section->next) + { + /* Clear added content */ + while (section->tpl->added_head != NULL) + { + tpl_node_t* n = section->tpl->added_head; + section->tpl->added_head = section->tpl->added_head->next; + destroy_node(n); + } + section->tpl->added_tail = §ion->tpl->added_head; + + /* Clear this section */ + tpl_reset(section->tpl); + } +} + + +/* Set up the selected section pointer to correspond to + that of the copied template */ +static void tpl_adjust_selection(tpl_t* tpl, + const tpl_t* srctpl, + tpl_tcell_t* sec, + const tpl_tcell_t* srcsec) +{ + const tpl_tcell_t *sec1 = srcsec; + tpl_tcell_t *sec2 = sec; + + if (srctpl->tpl != srctpl) + { + for (; tpl->tpl == tpl && sec1 != NULL; + sec1 = sec1->next, sec2 = sec2->next) + { + if (srctpl->tpl == sec1->tpl) + tpl->tpl = sec2->tpl; + else + { + tpl_adjust_selection(tpl, + srctpl, + sec2->tpl->first, + sec1->tpl->first); + } + } + } +} + + +/* Recursive copy */ +void tpl_copy(tpl_t* tpl, const tpl_t* srctpl) +{ + tpl_node_t **tail = &tpl->head; + tpl_node_t *curr_node = srctpl->head; + tpl_tcell_t **last_section = &tpl->first; + tpl_tcell_t *curr_section = srctpl->first; + + for (; curr_section != NULL; curr_section = curr_section->next) + { + /* Copy text and fields until the current section's position */ + while (curr_node != *curr_section->preceding) + { + /* Text */ + if (curr_node->val != NULL) + { + *tail = create_node(curr_node->len); + (void)memcpy((*tail)->val, curr_node->val, curr_node->len); + (*tail)->val[curr_node->len] = 0; + } + /* Field */ + else + { + /* Create node and set fval to field cell */ + *tail = create_node(0); + (*tail)->val = NULL; + + tpl_cpy_field((*tail)->fval, + tpl, + curr_node->fval->key, + strlen(curr_node->fval->key), + curr_node->fval->val, + curr_node->fval->len); + + } + + tail = &(*tail)->next; + curr_node = curr_node->next; + } + + /* Create emtpy section entry for current section */ + *last_section = tpl_make_section(tpl, + curr_section->key, + strlen(curr_section->key)); + + (*last_section)->preceding = tail; + + + /* Consolidate added content into a single node in newly created + section entry so that only one memory allocation is needed */ + if (curr_section->tpl->added_head != NULL) + { + tpl_node_t *some_node = curr_section->tpl->added_head; + char *buffer; + int len = 0; + + /* Get length of added content */ + for (; some_node!=NULL; some_node=some_node->next) + len += some_node->len; + + /* Create node for added content */ + (*last_section)->tpl->added_head = create_node(len); + (*last_section)->tpl->added_head->next = NULL; + (*last_section)->tpl->added_tail = + &(*last_section)->tpl->added_head->next; + + /* Copy added content into new node */ + + buffer = (*last_section)->tpl->added_head->val; + + for (some_node = curr_section->tpl->added_head; + some_node != NULL; + some_node = some_node->next) + { + (void)memcpy(buffer, some_node->val, some_node->len); + buffer += some_node->len; + } + *buffer = 0; + } + + + /* Recursively copy section */ + tpl_copy((*last_section)->tpl, curr_section->tpl); + + last_section = &(*last_section)->next; + } + + /* Copy the rest */ + while (curr_node != NULL) + { + /* Text */ + if (curr_node->val != NULL) + { + *tail = create_node(curr_node->len); + (void)memcpy((*tail)->val, curr_node->val, curr_node->len + 1); + } + /* Field */ + else + { + *tail = create_node(0); + (*tail)->val = NULL; + + tpl_cpy_field((*tail)->fval, + tpl, + curr_node->fval->key, + strlen(curr_node->fval->key), + curr_node->fval->val, + curr_node->fval->len); + } + + tail = &(*tail)->next; + curr_node = curr_node->next; + } + + *tail = NULL; + *last_section = NULL; + tpl->tpl = tpl; + + tpl_adjust_selection(tpl, srctpl, tpl->first, srctpl->first); +} + + +void tpl_set_field(tpl_t* tpl, const char* key, const char* val, int len) +{ + tpl_fcell_t *field = tpl_get_field(tpl->tpl, key); + if (field != NULL) + { + if (len > INITIAL_FIELD_LEN && len > field->len) + field->val = (char*) acl_myrealloc(field->val, len + 1); + + field->len = len; + (void)memcpy(field->val, val, len); + field->val[len] = 0; + } +} + +void tpl_set_field_fmt(tpl_t* tpl, const char* key, const char* fmt, ...) +{ + tpl_fcell_t *field = tpl_get_field(tpl->tpl, key); + + if (field != NULL) + { + int n; + + if (field->len < INITIAL_FIELD_LEN) + field->len = INITIAL_FIELD_LEN; + + while (1) + { + va_list ap; + + va_start(ap, fmt); + n = vsnprintf(field->val, field->len + 1, fmt, ap); + va_end(ap); + + if (n > -1 && n <= field->len) + break; + + field->len *= 2; + field->val = (char*) acl_myrealloc(field->val, field->len + 1); + } + field->len = n; + } +} + +void tpl_set_field_int(tpl_t* tpl, const char* key, int val) +{ + tpl_fcell_t *field = tpl_get_field(tpl->tpl, key); + + if (field != NULL) + { + if (field->len < INITIAL_FIELD_LEN) + field->len = INITIAL_FIELD_LEN; + + M_INT_TO_STRING(field->val, field->len, val, 1); + } +} + +void tpl_set_field_uint(tpl_t* tpl, const char* key, unsigned int val) +{ + tpl_fcell_t *field = tpl_get_field(tpl->tpl, key); + + if (field != NULL) + { + int v = (int) val; + + if (field->len < INITIAL_FIELD_LEN) + field->len = INITIAL_FIELD_LEN; + + M_INT_TO_STRING(field->val, field->len, v, 0); + } +} + +void tpl_set_field_double(tpl_t* tpl, const char* key, double val) +{ + tpl_fcell_t *field = tpl_get_field(tpl->tpl, key); + + if (field != NULL) + { + if (field->len < INITIAL_FIELD_LEN) + field->len = INITIAL_FIELD_LEN; + + field->len = snprintf(field->val, field->len, "%.2f", val); + } +} + +int tpl_set_field_from_file(tpl_t* tpl, const char* key, const char* filename) +{ + tpl_fcell_t *field = tpl_get_field(tpl->tpl, key); + + if (field != NULL) + { + int len; + FILE *fp = fopen(filename, "rb"); + + if (fp == NULL) + return TPL_OPEN_ERROR; + + /* Find length of file content */ + (void)fseek(fp, 0, SEEK_END); + len = ftell(fp); + (void)rewind(fp); + + if (len > INITIAL_FIELD_LEN && len > field->len) + field->val = (char*) acl_myrealloc(field->val, len + 1); + + if (fread(field->val, 1, len, fp) < (unsigned)len) + { + (void)fclose(fp); + return TPL_READ_ERROR; + } + (void)fclose(fp); + + field->len = len; + field->val[len] = 0; + } + return TPL_OK; +} + +void tpl_set_field_global(tpl_t* tpl, const char* key, const char* val, int len) +{ + tpl_tcell_t *section = tpl->first; + tpl_set_field(tpl, key, val, len); + while (section != NULL) + { + /* Recursively set in all sections */ + tpl_set_field_global(section->tpl, key, val, len); + section = section->next; + } +} + +void tpl_set_field_fmt_global(tpl_t* tpl, const char* key, const char* fmt, ...) +{ + int n; + int len = 256; + char *buf = (char*)acl_mymalloc(len); + + while (1) + { + va_list ap; + + va_start(ap, fmt); + n = vsnprintf(buf, len, fmt, ap); + va_end(ap); + + if (n > -1 && n < len) + break; + + len *= 2; + buf = (char*) acl_myrealloc(buf, len); + } + tpl_set_field_global(tpl, key, buf, n); + acl_myfree(buf); +} + +void tpl_set_field_int_global(tpl_t* tpl, const char* key, int val) +{ + tpl_tcell_t *section = tpl->first; + tpl_set_field_int(tpl, key, val); + while (section != NULL) + { + /* Recursively set in all sections */ + tpl_set_field_int_global(section->tpl, key, val); + section = section->next; + } +} + +void tpl_set_field_uint_global(tpl_t* tpl, const char* key, unsigned int val) +{ + tpl_tcell_t *section = tpl->first; + tpl_set_field_uint(tpl, key, val); + while (section != NULL) + { + /* Recursively set in all sections */ + tpl_set_field_uint_global(section->tpl, key, val); + section = section->next; + } +} + +void tpl_set_field_double_global(tpl_t* tpl, const char* key, double val) +{ + tpl_tcell_t *section = tpl->first; + tpl_set_field_double(tpl, key, val); + while (section != NULL) + { + /* Recursively set in all sections */ + tpl_set_field_double_global(section->tpl, key, val); + section = section->next; + } +} + +int tpl_select_section(tpl_t *tpl, const char* key) +{ + tpl_tcell_t *section = tpl_get_section(tpl->tpl, key); + if (section != NULL) + { + tpl->tpl->tpl = section->tpl; + tpl->tpl = tpl->tpl->tpl; + return TPL_OK; + } + return TPL_SECTION_NOT_FOUND_ERROR; +} + +int tpl_deselect_section(tpl_t *tpl) +{ + if (tpl->tpl != tpl) + { + tpl->tpl = tpl->tpl->parent; + tpl->tpl->tpl = tpl->tpl; + return TPL_OK; + } + return TPL_NO_SECTION_SELECTED_ERROR; +} + + +/* Set or replace added content in section with supplied value */ +static int tpl_set_section_ex(tpl_t* tpl, + const char* key, + const char* val, + int len, + tpl_node_t *existing_node) +{ + tpl_tcell_t *section = tpl_get_section(tpl->tpl, key); + + if (section != NULL) + { + if (section->tpl->first != NULL + || section->tpl->head == NULL + || section->tpl->head->next != NULL + || section->tpl->head->len != len) + { + /* Destroy the contents of this section */ + tpl_release(section->tpl); + tpl_init(section->tpl); + + section->tpl->parent = tpl->tpl; + section->tpl->head = create_node(len); + } + + (void)memcpy(section->tpl->head->val, val, len); + section->tpl->head->val[len] = 0; + + if (existing_node != NULL) + { + existing_node->next = section->tpl->added_head; + section->tpl->added_head = existing_node; + } + else + { + if (section->tpl->added_head != NULL + && section->tpl->added_head->len != len) + { + tpl_node_t *node = create_node(len); + node->next = section->tpl->added_head; + section->tpl->added_head = node; + } + else if (section->tpl->added_head == NULL) + section->tpl->added_head = create_node(len); + + (void)memcpy(section->tpl->added_head->val, val, len); + section->tpl->added_head->val[len] = 0; + } + + while (section->tpl->added_head->next != NULL) + { + tpl_node_t *deleted = section->tpl->added_head->next; + section->tpl->added_head->next = deleted->next; + destroy_node(deleted); + } + + section->tpl->added_tail = §ion->tpl->added_head->next; + + return TPL_OK; + } + + return TPL_SECTION_NOT_FOUND_ERROR; +} + +int tpl_set_section(tpl_t* tpl, const char* key, const char* val, int len) +{ + return tpl_set_section_ex(tpl, key, val, len, NULL); +} + +int tpl_set_section_from_file(tpl_t* tpl, const char* key, const char* filename) +{ + int len, status; + tpl_node_t *node; + FILE *fp = fopen(filename, "rb"); + + if (fp == NULL) + return TPL_OPEN_ERROR; + + /* Find length of file content */ + (void)fseek(fp, 0, SEEK_END); + len = ftell(fp); + (void)rewind(fp); + + node = create_node(len); + + if (fread(node->val, 1, len, fp) < (unsigned)len) + status = TPL_READ_ERROR; + else + status = tpl_set_section_ex(tpl, key, node->val, len, node); + + (void)fclose(fp); + + if (status != TPL_OK) + destroy_node(node); + + return status; +} + + +int tpl_append_section(tpl_t* tpl) +{ + if (tpl->tpl != tpl) + { + tpl_tcell_t *curr_sect = tpl->tpl->first; + tpl_node_t *curr_node = tpl->tpl->head; + tpl_node_t *some_node; + int len; + char *buffer; + + for (; curr_sect != NULL; curr_sect = curr_sect->next) + { + if (curr_sect->tpl->added_head != NULL) + { + + for (len = 0, some_node = curr_node; + some_node != *curr_sect->preceding; + some_node = some_node->next) + { + len += M_NODE_LEN(some_node); + } + + *tpl->tpl->added_tail = create_node(len); + buffer = (*tpl->tpl->added_tail)->val; + tpl->tpl->added_tail = &(*tpl->tpl->added_tail)->next; + + for (; + curr_node != *curr_sect->preceding; + curr_node = curr_node->next) + { + if (curr_node->val) + { + (void)memcpy(buffer, curr_node->val, curr_node->len); + buffer += curr_node->len; + } + else + { + (void)memcpy(buffer, + curr_node->fval->val, + curr_node->fval->len); + buffer += curr_node->fval->len; + } + } + + *buffer = 0; + + /* Cut 'n paste added content chain from section */ + *tpl->tpl->added_tail = curr_sect->tpl->added_head; + tpl->tpl->added_tail = curr_sect->tpl->added_tail; + curr_sect->tpl->added_tail = &curr_sect->tpl->added_head; + curr_sect->tpl->added_head = NULL; + } + } + + for (len = 0, some_node = curr_node; + some_node != NULL; + some_node = some_node->next) + { + len += M_NODE_LEN(some_node); + } + + + *tpl->tpl->added_tail = create_node(len); + buffer = (*tpl->tpl->added_tail)->val; + tpl->tpl->added_tail = &(*tpl->tpl->added_tail)->next; + + for (; curr_node != NULL; curr_node = curr_node->next) + { + if (curr_node->val) + { + (void)memcpy(buffer, curr_node->val, curr_node->len); + buffer += curr_node->len; + } + else + { + (void)memcpy(buffer, + curr_node->fval->val, + curr_node->fval->len); + + buffer += curr_node->fval->len; + } + } + *buffer = 0; + *tpl->tpl->added_tail = NULL; + + return TPL_OK; + } + return TPL_NO_SECTION_SELECTED_ERROR; +} + + +int tpl_length(const tpl_t* tpl) +{ + tpl_node_t *n = tpl->head; + tpl_tcell_t *s = tpl->first; + int len; + + for (len = 0; n != NULL; n = n->next) + len += (n->val) ? n->len : n->fval->len; + + for (; s != NULL; s = s->next) + { + for (n = s->tpl->added_head; n != NULL; n = n->next) + len += n->len; + } + + return len; +} + + +int tpl_section_length(const tpl_t* tpl) +{ + return tpl_length(tpl->tpl); +} + +void tpl_get_content(const tpl_t* tpl, char* buffer) +{ + tpl_node_t *n = tpl->head; + tpl_tcell_t *s = tpl->first; + + for (; s != NULL; s = s->next) + { + tpl_node_t *an = s->tpl->added_head; + + /* Copy part until beginning of section */ + for (; n != *s->preceding; n = n->next) + { + if (n->val) + { + (void)memcpy(buffer, n->val, n->len); + buffer += n->len; + } + else + { + (void)memcpy(buffer, n->fval->val, n->fval->len); + buffer += n->fval->len; + } + } + + /* Copy content appended in section */ + for (; an != NULL; an = an->next) + { + (void)memcpy(buffer, an->val, an->len); + buffer += an->len; + } + } + + /* Copy the rest */ + for (; n != NULL; n = n->next) + { + if (n->val) + { + (void)memcpy(buffer, n->val, n->len); + buffer += n->len; + } + else + { + (void)memcpy(buffer, n->fval->val, n->fval->len); + buffer += n->fval->len; + } + } + *buffer = 0; +} + +void tpl_get_section_content(const tpl_t* tpl, char* buffer) +{ + tpl_get_content(tpl->tpl, buffer); +} + +int tpl_save_as(const tpl_t* tpl, const char* filename) +{ + FILE *fp = fopen(filename, "wb"); + + if (fp != NULL) + { + int len = tpl_length(tpl); + int n; + char *content = (char *)acl_mymalloc(len + 1); + + tpl_get_content(tpl, content); + + n = fwrite(content, len, 1, fp); + if (n != 1) + { + (void)fclose(fp); + acl_myfree(content); + return TPL_WRITE_ERROR; + } + (void)fclose(fp); + + acl_myfree(content); + return TPL_OK; + } + return TPL_OPEN_ERROR; +} + + +int tpl_write(const tpl_t* tpl, int fd) +{ + int len = tpl_length(tpl); + char *content = (char *)acl_mymalloc(len + 1); + + tpl_get_content(tpl, content); + len = write(fd, content, len); + acl_myfree(content); + + if (len < 0) + return TPL_WRITE_ERROR; + + return TPL_OK; +} + + +int tpl_http_write(const tpl_t* tpl, int fd) +{ + /* Assumption: the content length can be max a 10 digit number */ + int length_digits = 10; + + int header_len = sizeof(TPL_NPH_HTTP_HEADER_START) + + sizeof(TPL_NPH_HTTP_HEADER_END) + + length_digits; + + int content_len = tpl_length(tpl); + int tmp_len = content_len; + + /* Long enough for both the HTTP header and content */ + char *response = (char*)acl_mymalloc(content_len + header_len + 1); + + char *str_p = response; + + (void)memcpy(str_p, + TPL_NPH_HTTP_HEADER_START, + sizeof(TPL_NPH_HTTP_HEADER_START) - 1); + + str_p += sizeof(TPL_NPH_HTTP_HEADER_START) - 1; + + M_INT_TO_STRING(str_p, length_digits, tmp_len, 0); + str_p += length_digits; + + (void)memcpy(str_p, + TPL_NPH_HTTP_HEADER_END, + sizeof(TPL_NPH_HTTP_HEADER_END) - 1); + + str_p += sizeof(TPL_NPH_HTTP_HEADER_END) - 1; + + tpl_get_content(tpl, str_p); + content_len = write(fd, response, content_len + (str_p - response)); + acl_myfree(response); + + if (content_len < 0) + return TPL_WRITE_ERROR; + + return TPL_OK; +} + +void tpl_out(tpl_t *tpl, ACL_VSTREAM *out) +{ + char *buf; + int n; + + if (tpl == NULL) + return; + if (out == NULL) + out = ACL_VSTREAM_OUT; + + n = tpl_length(tpl); + if (n <= 0) + return; + buf = (char*) acl_mymalloc(n + 1); + tpl_get_content(tpl, buf); + acl_vstream_writen(out, buf, n); + acl_myfree(buf); +} diff --git a/samples/master/master_notify/warning_letter.tmpl b/samples/master/master_notify/warning_letter.tmpl new file mode 100644 index 000000000..f8da4d0a9 --- /dev/null +++ b/samples/master/master_notify/warning_letter.tmpl @@ -0,0 +1,17 @@ +Delivered-To: $ +Subject: 应用程序异常退出报警信! +From: "系统管理员" <$> +Mime-version: 1.0 +Content-type: text/plain +Content-encoding: 8bit +Message-Id: $ +Date: $ +To: $ +$ + +您的程序 ($, pid=$) 在 $ 出现异常 ($), +请及时进行纠正,以免影响正常服务! + +管理员 + +$ diff --git a/samples/master/multi_echo/Makefile b/samples/master/multi_echo/Makefile new file mode 100644 index 000000000..39f2e39ce --- /dev/null +++ b/samples/master/multi_echo/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = multi_echo diff --git a/samples/master/multi_echo/main.c b/samples/master/multi_echo/main.c new file mode 100644 index 000000000..2442c661a --- /dev/null +++ b/samples/master/multi_echo/main.c @@ -0,0 +1,83 @@ +#include "lib_acl.h" + +static char *var_cfg_multi_banner; +static int var_cfg_multi_timeout; + +static ACL_CONFIG_INT_TABLE __conf_int_tab[] = { + { "multi_timeout", 60, &var_cfg_multi_timeout, 0, 0 }, + { 0, 0, 0, 0, 0 }, +}; + +static ACL_CONFIG_STR_TABLE __conf_str_tab[] = { + { "multi_banner", "hello, welcome", &var_cfg_multi_banner }, + { 0, 0, 0 }, +}; + +static void __service(ACL_VSTREAM *stream, char *service, char **argv acl_unused) +{ + const char *myname = "__service"; + char buf[4096]; + int n, ret; + + /* + * Sanity check. This service takes no command-line arguments. + */ + if (argv[0]) + acl_msg_fatal("%s(%d)->%s: unexpected command-line argument: %s", + __FILE__, __LINE__, myname, argv[0]); + + acl_msg_info("%s(%d)->%s: service name = %s, rw_timeout = %d", + __FILE__, __LINE__, myname, service, stream->rw_timeout); + + acl_watchdog_pat(); + + if (isatty(ACL_VSTREAM_SOCK(stream))) + acl_vstream_printf("Please input: "); + n = acl_vstream_gets(stream, buf, sizeof(buf) - 1); + if (n == ACL_VSTREAM_EOF) { + acl_multi_server_disconnect(stream); + acl_msg_info("%s(%d)->%s: read over", __FILE__, __LINE__, myname); + return; + } + + if (isatty(ACL_VSTREAM_SOCK(stream))) { + acl_vstream_printf("Your input: "); + ret = acl_vstream_writen(ACL_VSTREAM_OUT, buf, n); + } else + ret = acl_vstream_writen(stream, buf, n); + if (ret != n) { + acl_multi_server_disconnect(stream); + acl_msg_info("%s(%d)->%s: write error = %s", + __FILE__, __LINE__, myname, strerror(errno)); + } +} + +static void __pre_accept(char *name acl_unused, char **argv acl_unused) +{ +} + +static void __pre_jail_init(char *name acl_unused, char **argv acl_unused) +{ +} + +static void __post_jail_init(char *name acl_unused, char **argv acl_unused) +{ +} + +static void service_exit(char *service acl_unused, char **argv acl_unused) +{ +} + +int main(int argc, char *argv[]) +{ + acl_multi_server_main(argc, argv, __service, + ACL_MASTER_SERVER_INT_TABLE, __conf_int_tab, + ACL_MASTER_SERVER_STR_TABLE, __conf_str_tab, + ACL_MASTER_SERVER_PRE_INIT, __pre_jail_init, + ACL_MASTER_SERVER_PRE_ACCEPT, __pre_accept, + ACL_MASTER_SERVER_POST_INIT, __post_jail_init, + ACL_MASTER_SERVER_EXIT, service_exit, + 0); + exit (0); +} + diff --git a/samples/master/multi_proxy/Makefile b/samples/master/multi_proxy/Makefile new file mode 100644 index 000000000..83607255b --- /dev/null +++ b/samples/master/multi_proxy/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = multi_proxy diff --git a/samples/master/multi_proxy/multi_proxy.c b/samples/master/multi_proxy/multi_proxy.c new file mode 100644 index 000000000..722716acd --- /dev/null +++ b/samples/master/multi_proxy/multi_proxy.c @@ -0,0 +1,318 @@ + +#include +#include +#include +#include + +#include "lib_acl.h" + +#include "multi_proxy.h" + +#define VSTREAM_PROXY_BACKEND_FLAG 1 +#define VSTREAM_PROXY_FRONT_FLAG 2 + +typedef struct VSTREAM_PROXY_OBJ { + ACL_VSTREAM *stream; + struct VSTREAM_PROXY_OBJ *peer; + int flag; +} VSTREAM_PROXY_OBJ; + +/* int values */ +int var_proxy_log_level; +int var_proxy_tmout; +int var_proxy_connect_tmout; +int var_proxy_rw_tmout; +int var_proxy_bufsize; + +/* bool values */ +int var_proxy_debug_request; +int var_proxy_debug_respond; + +/* char values */ +char *var_proxy_banner; +char *var_proxy_backend_addr; +char *var_proxy_request_file; +char *var_proxy_respond_file; + +static ACL_CONFIG_INT_TABLE __conf_int_tab[] = { + { VAR_PROXY_LOG_LEVEL, DEF_PROXY_LOG_LEVEL, &var_proxy_log_level, 0, 0 }, + { VAR_PROXY_TMOUT, DEF_PROXY_TMOUT, &var_proxy_tmout, 0, 0 }, + { VAR_PROXY_CONNECT_TMOUT, DEF_PROXY_CONNECT_TMOUT, &var_proxy_connect_tmout, 0, 0 }, + { VAR_PROXY_RW_TMOUT, DEF_PROXY_RW_TMOUT, &var_proxy_rw_tmout, 0, 0 }, + { VAR_PROXY_BUFSIZE, DEF_PROXY_BUFSIZE, &var_proxy_bufsize, 0, 0 }, + { 0, 0, 0, 0, 0 }, +}; + +static ACL_CONFIG_BOOL_TABLE __conf_bool_tab[] = { + { VAR_PROXY_DEBUG_REQUEST, DEF_PROXY_DEBUG_REQUEST, &var_proxy_debug_request }, + { VAR_PROXY_DEBUG_RESPOND, DEF_PROXY_DEBUG_RESPOND, &var_proxy_debug_respond }, + { 0, 0, 0 }, +}; + +static ACL_CONFIG_STR_TABLE __conf_str_tab[] = { + { VAR_PROXY_BANNER, DEF_PROXY_BANNER, &var_proxy_banner }, + { VAR_PROXY_BACKEND_ADDR, DEF_PROXY_BACKEND_ADDR, &var_proxy_backend_addr }, + { VAR_PROXY_REQUEST_FILE, DEF_PROXY_REQUEST_FILE, &var_proxy_request_file }, + { VAR_PROXY_RESPOND_FILE, DEF_PROXY_RESPOND_FILE, &var_proxy_respond_file }, + { 0, 0, 0 }, +}; + +static char *__data_buf; +static ACL_VSTREAM *__request_stream; +static ACL_VSTREAM *__respond_stream; + +static void __pre_disconnect_fn(ACL_VSTREAM *stream, char *unused_name, char **unused_argv) +{ + char myname[] = "__pre_disconnect_fn"; + VSTREAM_PROXY_OBJ *vpobj, *peer; + + unused_name = unused_name; + unused_argv = unused_argv; + + if (stream == NULL) { + acl_msg_error("%s(%d)->%s: stream null", + __FILE__, __LINE__, myname); + return; + } + + vpobj = (VSTREAM_PROXY_OBJ *) stream->context; + if (vpobj == NULL) { + acl_msg_error("%s(%d)->%s: stream's context null", + __FILE__, __LINE__, myname); + return; + } + + peer = vpobj->peer; + if (peer == NULL) { + ; /* do nothing */ + } else if (peer->stream == NULL) { + acl_msg_error("%s(%d)->%s: peer's stream null", + __FILE__, __LINE__, myname); + } else { + peer->peer = NULL; + acl_multi_server_disconnect(peer->stream); + } + + acl_myfree(vpobj); + stream->context = NULL; +} + +static void __rw_timer_fn(ACL_VSTREAM *stream) +{ + char myname[] = "__rw_timer_fn"; + + if (stream == NULL || ACL_VSTREAM_SOCK(stream) < 0) + acl_msg_fatal("%s(%d)->%s: input error, null stream", + __FILE__, __LINE__, myname); + + if (acl_msg_verbose) + acl_msg_info("%s(%d)->%s: rw timeout, fd = %d", + __FILE__, __LINE__, myname, + ACL_VSTREAM_SOCK(stream)); + + acl_multi_server_disconnect(stream); +} + +static void __service(ACL_VSTREAM *stream, char *service, char **argv) +{ + char myname[] = "__service"; + int n, ret; + VSTREAM_PROXY_OBJ *vpobj, *peer; + + /* + * Sanity check. This service takes no command-line arguments. + */ + if (argv[0]) + acl_msg_fatal("%s(%d)->%s: unexpected command-line argument: %s", + __FILE__, __LINE__, myname, argv[0]); + + if (stream == NULL) + acl_msg_fatal("%s(%d)->%s: stream null", + __FILE__, __LINE__, myname); + vpobj = (VSTREAM_PROXY_OBJ *) stream->context; + if (vpobj == NULL) + acl_msg_fatal("%s(%d)->%s: stream's context null", + __FILE__, __LINE__, myname); + + if (acl_msg_verbose > 3) + acl_msg_info("%s(%d)->%s: service name = %s, rw_timeout = %d", + __FILE__, __LINE__, myname, service, stream->rw_timeout); + + acl_watchdog_pat(); + + peer = vpobj->peer; + if (peer == NULL || peer->stream == NULL || peer->peer != vpobj) { + acl_multi_server_disconnect(stream); + return; + } + + acl_multi_server_cancel_rw_timer(peer->stream); + + n = acl_vstream_read(stream, __data_buf, var_proxy_bufsize); + if (n == ACL_VSTREAM_EOF) { + acl_multi_server_disconnect(stream); + if (acl_msg_verbose > 3) + acl_msg_info("%s(%d)->%s: read over", + __FILE__, __LINE__, myname); + return; + } + + if (vpobj->flag == VSTREAM_PROXY_FRONT_FLAG && __request_stream) { + ret = acl_vstream_writen(__request_stream, __data_buf, n); + if (ret != n) { + acl_msg_error("%s(%d)->%s: writen to %s, serr = %s", + __FILE__, __LINE__, myname, + var_proxy_request_file, strerror(errno)); + acl_vstream_close(__request_stream); + __request_stream = NULL; + } + } else if (vpobj->flag == VSTREAM_PROXY_BACKEND_FLAG && __respond_stream) { + ret = acl_vstream_writen(__respond_stream, __data_buf, n); + if (ret != n) { + acl_msg_error("%s(%d)->%s: writen to %s, serr = %s", + __FILE__, __LINE__, myname, + var_proxy_request_file, strerror(errno)); + acl_vstream_close(__respond_stream); + __respond_stream = NULL; + } + } + + ret = acl_vstream_writen(peer->stream, __data_buf, n); + if (ret != n) { + acl_multi_server_disconnect(peer->stream); + if (acl_msg_verbose > 3) + acl_msg_info("%s(%d)->%s: write error = %s", + __FILE__, __LINE__, myname, + strerror(errno)); + return; + } + + acl_multi_server_request_rw_timer(stream); + acl_multi_server_request_rw_timer(peer->stream); +} + +static int __on_accept_fn(ACL_VSTREAM *front_stream) +{ + char myname[] = "__on_accept_fn"; + ACL_VSTREAM *backend_stream; + VSTREAM_PROXY_OBJ *backend_obj; + VSTREAM_PROXY_OBJ *front_obj; + + backend_stream = acl_vstream_connect(var_proxy_backend_addr, + ACL_BLOCKING, + var_proxy_connect_tmout, + var_proxy_rw_tmout, + var_proxy_bufsize); + if (backend_stream == NULL) { + acl_msg_error("%s(%d)->%s: connect backend_addr = %s, serr = %s", + __FILE__, __LINE__, myname, + var_proxy_backend_addr, strerror(errno)); + return (-1); + } + + backend_obj = acl_mymalloc(sizeof(VSTREAM_PROXY_OBJ)); + front_obj = acl_mymalloc(sizeof(VSTREAM_PROXY_OBJ)); + + backend_obj->stream = backend_stream; + backend_obj->flag = VSTREAM_PROXY_BACKEND_FLAG; + backend_obj->peer = front_obj; + backend_stream->context = (void *) backend_obj; + + front_obj->stream = front_stream; + front_obj->flag = VSTREAM_PROXY_FRONT_FLAG; + front_obj->peer = backend_obj; + front_stream->context = (void *) front_obj; + + acl_multi_server_enable_read(backend_stream); + + return (0); +} + +static void __pre_accept_fn(char *unused_name, char **unused_argv) +{ + char myname[] = "__pre_accept_fn"; + + unused_name = unused_name; + unused_argv = unused_argv; + + if (acl_msg_verbose) + acl_msg_info("%s(%d)->%s: test only", + __FILE__, __LINE__, myname); +} + +static void __pre_jail_init_fn(char *unused_name, char **unused_argv) +{ + char myname[] = "__pre_jail_init_fn"; + + unused_name = unused_name; + unused_argv = unused_argv; + + if (acl_msg_verbose) + acl_msg_info("%s(%d)->%s: test only", + __FILE__, __LINE__, myname); +} + +static void __post_jail_init_fn(char *unused_name, char **unused_argv) +{ + char myname[] = "__post_jail_init_fn"; + ACL_VSTRING *why = acl_vstring_alloc(100); + + unused_name = unused_name; + unused_argv = unused_argv; + + if (acl_msg_verbose) + acl_msg_info("%s(%d)->%s: test only", + __FILE__, __LINE__, myname); + + __data_buf = acl_mymalloc(var_proxy_bufsize); + if (__data_buf == NULL) + acl_msg_fatal("%s(%d)->%s: malloc data_buf, serr = %s", + __FILE__, __LINE__, myname, + strerror(errno)); + + if (var_proxy_debug_request) { + __request_stream = acl_safe_open(var_proxy_request_file, + O_CREAT | O_RDWR | O_APPEND, 0600, + (struct stat *) 0, (uid_t)-1, + (uid_t )-1, why); + if (__request_stream == NULL) + acl_msg_fatal("%s(%d)->%s: can't open %s, err = %s", + __FILE__, __LINE__, myname, + var_proxy_request_file, acl_vstring_str(why)); + } + + if (var_proxy_debug_respond) { + __respond_stream = acl_safe_open(var_proxy_respond_file, + O_CREAT | O_RDWR | O_APPEND, 0600, + (struct stat *) 0, (uid_t)-1, + (uid_t )-1, why); + if (__respond_stream == NULL) + acl_msg_fatal("%s(%d)->%s: can't open %s, err = %s", + __FILE__, __LINE__, myname, + var_proxy_respond_file, acl_vstring_str(why)); + } + + acl_vstring_free(why); +} + +int main(int argc, char *argv[]) +{ + acl_msg_verbose = 0; + + acl_msg_info("%s: start...", __FILE__); + printf("%s: starting...", __FILE__); + + acl_multi_server_main(argc, argv, __service, + ACL_MASTER_SERVER_INT_TABLE, __conf_int_tab, + ACL_MASTER_SERVER_BOOL_TABLE, __conf_bool_tab, + ACL_MASTER_SERVER_STR_TABLE, __conf_str_tab, + ACL_MASTER_SERVER_PRE_INIT, __pre_jail_init_fn, + ACL_MASTER_SERVER_PRE_ACCEPT, __pre_accept_fn, + ACL_MASTER_SERVER_POST_INIT, __post_jail_init_fn, + ACL_MASTER_SERVER_ON_ACCEPT, __on_accept_fn, + ACL_MASTER_SERVER_RW_TIMER, __rw_timer_fn, + ACL_MASTER_SERVER_PRE_DISCONN, __pre_disconnect_fn, + 0); + exit (0); +} + diff --git a/samples/master/multi_proxy/multi_proxy.h b/samples/master/multi_proxy/multi_proxy.h new file mode 100644 index 000000000..bb130dfd4 --- /dev/null +++ b/samples/master/multi_proxy/multi_proxy.h @@ -0,0 +1,58 @@ + +#ifndef __TEST_MULTI_PROXY_INCLUDE_H_ +#define __TEST_MULTI_PROXY_INCLUDE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#define VAR_PROXY_TMOUT "proxy_timeout" +#define DEF_PROXY_TMOUT 60 +extern int var_proxy_tmout; + +#define VAR_PROXY_BANNER "proxy_banner" +#define DEF_PROXY_BANNER "hello, welcome!" +extern char *var_proxy_banner; + +#define VAR_PROXY_CONNECT_TMOUT "proxy_connect_timeout" +#define DEF_PROXY_CONNECT_TMOUT 60 +extern int var_proxy_connect_tmout; + +#define VAR_PROXY_RW_TMOUT "proxy_rw_timeout" +#define DEF_PROXY_RW_TMOUT 60 +extern int var_proxy_rw_tmout; + +#define VAR_PROXY_BUFSIZE "proxy_bufsize" +#define DEF_PROXY_BUFSIZE 4096 +extern int var_proxy_bufsize; + +#define VAR_PROXY_BACKEND_ADDR "proxy_backend_addr" +#define DEF_PROXY_BACKEND_ADDR "none" +extern char *var_proxy_backend_addr; + +#define VAR_PROXY_LOG_LEVEL "proxy_log_level" +#define DEF_PROXY_LOG_LEVEL 0 +extern int var_proxy_log_level; + +#define VAR_PROXY_REQUEST_FILE "proxy_request_file" +#define DEF_PROXY_REQUEST_FILE "request.log" +extern char *var_proxy_request_file; + +#define VAR_PROXY_RESPOND_FILE "proxy_respond_file" +#define DEF_PROXY_RESPOND_FILE "respond.log" +extern char *var_proxy_respond_file; + +#define VAR_PROXY_DEBUG_REQUEST "proxy_debug_request" +#define DEF_PROXY_DEBUG_REQUEST 0 +extern int var_proxy_debug_request; + +#define VAR_PROXY_DEBUG_RESPOND "proxy_debug_respond" +#define DEF_PROXY_DEBUG_RESPOND 0 +extern int var_proxy_debug_respond; + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/samples/master/single_echo/Makefile b/samples/master/single_echo/Makefile new file mode 100644 index 000000000..c04eb914a --- /dev/null +++ b/samples/master/single_echo/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = single_echo diff --git a/samples/master/single_echo/main.c b/samples/master/single_echo/main.c new file mode 100644 index 000000000..8a43aaebc --- /dev/null +++ b/samples/master/single_echo/main.c @@ -0,0 +1,92 @@ +#include "lib_acl.h" +#include +#include +#include +#include + +char *var_cfg_single_banner; +int var_cfg_single_timeout; + +static ACL_CONFIG_INT_TABLE __conf_int_tab[] = { + { "single_timeout", 60, &var_cfg_single_timeout, 0, 0 }, + { 0, 0, 0, 0, 0 }, +}; + +static ACL_CONFIG_STR_TABLE __conf_str_tab[] = { + { "single_banner", "hello, welcome!", &var_cfg_single_banner }, + { 0, 0, 0 }, +}; + +static void __service(ACL_VSTREAM *stream, char *service, char **argv acl_unused) +{ + const char *myname = "__service"; + char buf[4096]; + int n, ret; + + /* + * Sanity check. This service takes no command-line arguments. + */ + if (argv[0]) + acl_msg_fatal("%s(%d)->%s: unexpected command-line argument: %s", + __FILE__, __LINE__, myname, argv[0]); + + acl_msg_info("%s(%d)->%s: service name = %s, rw_timeout = %d", + __FILE__, __LINE__, myname, service, stream->rw_timeout); + + acl_msg_info("total alloc: %d", acl_mempool_total_allocated()); + do { + acl_watchdog_pat(); + + if (isatty(ACL_VSTREAM_SOCK(stream))) + acl_vstream_printf("Please input: "); + + n = acl_vstream_gets(stream, buf, sizeof(buf) - 1); + if (n == ACL_VSTREAM_EOF) { + acl_msg_info("%s(%d)->%s: read over", + __FILE__, __LINE__, myname); + break; + } + + if (isatty(ACL_VSTREAM_SOCK(stream))) { + acl_vstream_printf("Your input: "); + ret = acl_vstream_writen(ACL_VSTREAM_OUT, buf, n); + } else + ret = acl_vstream_writen(stream, buf, n); + if (ret != n) { + acl_msg_info("%s(%d)->%s: write error = %s", + __FILE__, __LINE__, myname, strerror(errno)); + break; + } + } while (1); +} + +static void __pre_accept(char *name acl_unused, char **argv acl_unused) +{ +} + +static void __pre_jail_init(char *name acl_unused, char **argv acl_unused) +{ + acl_mempool_open(512000000, 1); +} + +static void __post_jail_init(char *name acl_unused, char **argv acl_unused) +{ +} + +static void service_exit(char *service acl_unused, char **argv acl_unused) +{ +} + +int main(int argc, char *argv[]) +{ + acl_single_server_main(argc, argv, __service, + ACL_MASTER_SERVER_INT_TABLE, __conf_int_tab, + ACL_MASTER_SERVER_STR_TABLE, __conf_str_tab, + ACL_MASTER_SERVER_PRE_INIT, __pre_jail_init, + ACL_MASTER_SERVER_PRE_ACCEPT, __pre_accept, + ACL_MASTER_SERVER_POST_INIT, __post_jail_init, + ACL_MASTER_SERVER_EXIT, service_exit, + 0); + exit (0); +} + diff --git a/samples/master/single_echo/single_echo.cf b/samples/master/single_echo/single_echo.cf new file mode 100644 index 000000000..e846b905c --- /dev/null +++ b/samples/master/single_echo/single_echo.cf @@ -0,0 +1,71 @@ +# service type private unpriv chroot wakeup maxproc command + args + +service single +{ +# 进程是否禁止运行 + master_disable = yes +# 服务地址及端口号 + master_service = :5003 +# 服务监听为域套接口 +# master_service = single_echo.sock +# 服务类型 + master_type = inet +# master_type = unix + +# 当子进程异常退出时,如果该值非空,则将子进程异常退出的消息通知该服务 +# master_notify_addr = 127.0.0.1:5801 +# 邮件通知接收者 +# master_notify_recipients = zhengshuxin@hotmail.com + +# 是否允许延迟接受客户端连接,如果为0则表示关闭该功能,如果大于0则表示打开此功能 +# 并且此值代表延迟接受连接的超时值,超过此值时如果客户端依然没有发来数据,则操作 +# 系统会在系统层直接关闭该连接 +# master_defer_accept = 0 +# 是否只允许私有访问, 如果为 y, 则域套接口创建在 {install_path}/var/log/private/ 目录下, +# 如果为 n, 则域套接口创建在 {install_path}/var/log/public/ 目录下, + master_private = n + master_unpriv = n +# 是否需要 chroot: n -- no, y -- yes + master_chroot = n +# 每隔多长时间触发一次,单位为秒(仅对 trigger 模式有效) + master_wakeup = - +# 最大进程数 + master_maxproc = 10 +# 需要预先启动的进程数,该值不应大于 master_maxproc + master_prefork = 2 +# 进程程序名 + master_command = single_echo +# 进程启动参数,只能为: -u [是否允许以某普通用户的身份运行] +# master_args = +# 进程日志记录文件 + master_log = {install_path}/var/log/single_echo.log +# 传递给服务子进程的环境变量, 可以通过 getenv("SERVICE_ENV") 获得此值 + master_env = logme:FALSE, priority:E_LOG_INFO, action:E_LOG_PER_DAY, flush:sync_flush, imit_size:512,\ + sync_action:E_LOG_SEM, sem_name:/tmp/single_echo.sem + +# 是否允许产生 core 文件 +# single_enable_core = 1 +# 每个进程实例处理连接数的最大次数,超过此值后进程实例主动退出 + single_use_limit = 250 +# 每个进程实例的空闲超时时间,超过此值后进程实例主动退出 +# single_idle_limit = 180 +# 记录进程PID的位置(对于多进程实例来说没有意义) + single_pid_dir = {install_path}/var/pid +# 进程运行时所在的路径 + single_queue_dir = {install_path}/var +# 读写超时时间, 单位为秒 + single_rw_timeout = 1800 +# 读缓冲区的缓冲区大小 + single_buf_size = 8192 +# 进程运行时的用户身份 + single_owner = root + +# single_in_flow_delay = 1 +# single_owner = owner +# 用 select 进行循环时的时间间隔 +# 单位为秒 +# single_delay_sec = 1 +# 单位为微秒 +# single_delay_usec = 5000 +# single_daemon_timeout = 1800 +} diff --git a/samples/master/single_proxy/Makefile b/samples/master/single_proxy/Makefile new file mode 100644 index 000000000..498e0a2c2 --- /dev/null +++ b/samples/master/single_proxy/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = single_proxy diff --git a/samples/master/single_proxy/single_proxy.c b/samples/master/single_proxy/single_proxy.c new file mode 100644 index 000000000..df6ca9c5e --- /dev/null +++ b/samples/master/single_proxy/single_proxy.c @@ -0,0 +1,423 @@ + +#include +#include +#include +#include + +#include "lib_acl.h" + +#include "single_proxy.h" + +int var_proxy_log_level; +int var_proxy_tmout; +int var_proxy_connect_tmout; +int var_proxy_rw_tmout; +int var_proxy_bufsize; +int var_proxy_retries; + +char *var_proxy_banner; +char *var_proxy_backend_addr; +char *var_proxy_in_file; +char *var_proxy_out_file; +char *var_proxy_host_allow; + +static ACL_CONFIG_INT_TABLE __conf_int_tab[] = { + { VAR_PROXY_LOG_LEVEL, DEF_PROXY_LOG_LEVEL, &var_proxy_log_level, 0, 0 }, + { VAR_PROXY_TMOUT, DEF_PROXY_TMOUT, &var_proxy_tmout, 0, 0 }, + { VAR_PROXY_CONNECT_TMOUT, DEF_PROXY_CONNECT_TMOUT, &var_proxy_connect_tmout, 0, 0 }, + { VAR_PROXY_RW_TMOUT, DEF_PROXY_RW_TMOUT, &var_proxy_rw_tmout, 0, 0 }, + { VAR_PROXY_BUFSIZE, DEF_PROXY_BUFSIZE, &var_proxy_bufsize, 0, 0 }, + { VAR_PROXY_RETRIES, DEF_PROXY_RETRIES, &var_proxy_retries, 0, 0}, + { 0, 0, 0, 0, 0 }, +}; + +static ACL_CONFIG_STR_TABLE __conf_str_tab[] = { + { VAR_PROXY_BANNER, DEF_PROXY_BANNER, &var_proxy_banner }, + { VAR_PROXY_BACKEND_ADDR, DEF_PROXY_BACKEND_ADDR, &var_proxy_backend_addr }, + { VAR_PROXY_IN_FILE, DEF_PROXY_IN_FILE, &var_proxy_in_file }, + { VAR_PROXY_OUT_FILE, DEF_PROXY_OUT_FILE, &var_proxy_out_file }, + { VAR_PROXY_HOST_ALLOW, DEF_PROXY_HOST_ALLOW, &var_proxy_host_allow }, + { 0, 0, 0 }, +}; + +static ACL_EVENT *__eventp = NULL; +static ACL_VSTREAM *__front_stream = NULL; +static ACL_VSTREAM *__backend_stream = NULL; + +static ACL_IPLINK *__host_allow_link = NULL; + +/* forward define */ +static int __if_host_allow(const char *client_ip); + +static void __proxy_handle_fn(int unused_event, void *context) +{ + char myname[] = "__proxy_handle_fn"; + ACL_VSTREAM *stream; + char buf[8192]; + int n, ret; + +#undef OVER_RETURN +#define OVER_RETURN do { \ + acl_event_disable_readwrite(__eventp, __backend_stream); \ + acl_vstream_close(__backend_stream); \ + __backend_stream = NULL; \ + return; \ +} while (0); + + if (context == NULL) { + acl_msg_error("%s(%d)->%s: input error, null context", + __FILE__, __LINE__, myname); + return; + } + + unused_event = unused_event; + stream = (ACL_VSTREAM *) context; + + if (stream == __front_stream) { + n = acl_vstream_read(stream, buf, sizeof(buf) - 1); + if (n == ACL_VSTREAM_EOF) { + if(var_proxy_log_level > 3) + acl_msg_info("%s(%d)->%s: read over", + __FILE__, __LINE__, myname); + OVER_RETURN; + } + + ret = acl_vstream_writen(__backend_stream, buf, n); + if (ret != n) { + if(var_proxy_log_level > 3) + acl_msg_info("%s(%d)->%s: write error = %s", + __FILE__, __LINE__, myname, + strerror(errno)); + OVER_RETURN; + } + } else if (stream == __backend_stream) { + n = acl_vstream_read(stream, buf, sizeof(buf) - 1); + if (n == ACL_VSTREAM_EOF) { + if(var_proxy_log_level > 3) + acl_msg_info("%s(%d)->%s: read over", + __FILE__, __LINE__, myname); + OVER_RETURN; + } + + ret = acl_vstream_writen(__front_stream, buf, n); + if (ret != n) { + if(var_proxy_log_level > 3) + acl_msg_info("%s(%d)->%s: write error = %s", + __FILE__, __LINE__, myname, + strerror(errno)); + OVER_RETURN; + } + } +} + +static void __service(ACL_VSTREAM *stream, char *service, char **argv) +{ + char myname[] = "__service"; + int connect_retries = var_proxy_retries; + + /* + * Sanity check. This service takes no command-line arguments. + */ + if (argv[0]) + acl_msg_fatal("%s(%d)->%s: unexpected command-line argument: %s", + __FILE__, __LINE__, myname, argv[0]); + + __front_stream = stream; + + if (var_proxy_log_level > 3) + acl_msg_info("%s(%d)->%s: service name = %s, rw_timeout = %d", + __FILE__, __LINE__, myname, service, stream->rw_timeout); + + __front_stream->remote_addr[0] = 0; + (void) acl_getpeername(ACL_VSTREAM_SOCK(__front_stream), + __front_stream->remote_addr, + sizeof(__front_stream->remote_addr)); + + if (__if_host_allow(__front_stream->remote_addr) < 0) + return; + + if (var_proxy_log_level > 2) + acl_msg_info("%s(%d)->%s: connected from addr=%s", + __FILE__, __LINE__, myname, + __front_stream->remote_addr); + + while (connect_retries) { + __backend_stream = + acl_vstream_connect(var_proxy_backend_addr, + ACL_BLOCKING, + var_proxy_connect_tmout, + var_proxy_rw_tmout, + var_proxy_bufsize); + if (__backend_stream != NULL) + break; + + acl_msg_warn("%s(%d)->%s: can't connect server = %s," + " serr = %s", + __FILE__, __LINE__, myname, + var_proxy_backend_addr, strerror(errno)); + connect_retries--; + } + + if (__backend_stream == NULL) { + acl_msg_error("%s(%d)->%s: can't connect server=%s, retries=%d", + __FILE__, __LINE__, myname, + var_proxy_backend_addr, var_proxy_retries); + return; + } + + if (var_proxy_log_level > 2) + acl_msg_info("%s(%d)->%s: ok, connect ip=%s, retries=%d", + __FILE__, __LINE__, myname, + __backend_stream->remote_addr, + var_proxy_retries - connect_retries); + + acl_event_enable_read(__eventp, + __front_stream, + 0, + __proxy_handle_fn, + __front_stream); + acl_event_enable_read(__eventp, + __backend_stream, + 0, + __proxy_handle_fn, + __backend_stream); + + while (1) { + acl_watchdog_pat(); + acl_event_loop(__eventp); + if (__backend_stream == NULL) + break; + } + + acl_event_disable_readwrite(__eventp, __front_stream); + __front_stream = NULL; +} + +static void __pre_accept(char *unused_name, char **unused_argv) +{ + char myname[] = "__pre_accept"; + + unused_name = unused_name; + unused_argv = unused_argv; + + if (var_proxy_log_level > 3) + acl_msg_info("%s(%d)->%s: test only", + __FILE__, __LINE__, myname); +} + +static void __add_one_host_item(ACL_IPLINK *allow_link, const char *pitem) +{ + char myname[] = "__add_one_host_item"; + char *pdata = NULL; + char *from, *to, *ptr; + +#undef RETURN +#define RETURN do { \ + if (pdata != NULL) \ + acl_myfree(pdata); \ + return; \ +} while (0); + + if (pitem == NULL || *pitem == 0) { + acl_msg_error("%s(%d)->%s: pitem invalid", + __FILE__, __LINE__, myname); + RETURN; + } + + pdata = acl_mystrdup(pitem); + + from = pdata; + + /* skip when: '[' || ',' || ' ' || '\t' */ + while (*from == '[' || *from == ',' || *from == ' ' || *from == '\t') + from++; + if (*from == 0) { + acl_msg_error("%s(%d)->%s: invalid item: %s", + __FILE__, __LINE__, myname, + pitem); + RETURN; + } + + ptr = from; + /* the "from" end with: ' ' || '\t' || ',' */ + while (*ptr) { + if (*ptr == ' ' || *ptr == '\t' || *ptr == ',') { + *ptr++ = 0; + break; + } + ptr++; + } + if (*from == 0) { + acl_msg_error("%s(%d)->%s: invalid item: %s", + __FILE__, __LINE__, myname, + pitem); + RETURN; + } + + /* skip when: ' ' || '\t' || ',' */ + while (*ptr == ' ' || *ptr == '\t' || *ptr == ',') + ptr++; + if (*ptr == 0) { + acl_msg_error("%s(%d)->%s: invalid item: %s", + __FILE__, __LINE__, myname, + pitem); + RETURN; + } + + to = ptr; + /* the "to" end with: ' ' || '\t' || ',' || ']' */ + while (*ptr) { + if (*ptr == ' ' || *ptr == '\t' || *ptr == ',' || *ptr == ']') { + *ptr = 0; + break; + } + ptr++; + } + if (*to == 0) { + acl_msg_error("%s(%d)->%s: invalid item: %s", + __FILE__, __LINE__, myname, + pitem); + RETURN; + } + + if (acl_iplink_insert(allow_link, from, to) == NULL) { + acl_msg_error("%s(%d)->%s: call acl_iplink_insert error," + " invalid item: %s", + __FILE__, __LINE__, myname, pitem); + RETURN; + } + + /* else: OK */ + if (var_proxy_log_level > 1) + acl_msg_info("%s(%d)->%s: from=%s, to=%s", + __FILE__, __LINE__, myname, + from, to); + RETURN; +} + +static void __add_host_allow(const char *host_allow) +{ + char myname[] = "__add_host_allow"; + char *pdata, *ptr, *pitem; + + if (host_allow == NULL) + host_allow = DEF_PROXY_HOST_ALLOW; + + pdata = acl_mystrdup(host_allow); + if (pdata == NULL) + acl_msg_fatal("%s(%d)->%s: call acl_mystrdup error=%s", + __FILE__, __LINE__, myname, + strerror(errno)); + + __host_allow_link = acl_iplink_create(10); + if (__host_allow_link == NULL) + acl_msg_fatal("%s(%d)->%s: call acl_iplink_create error=%s", + __FILE__, __LINE__, myname, + strerror(errno)); + ptr = pdata; + while (1) { + pitem = acl_mystrtok(&ptr, "]"); + if (pitem == NULL) + break; + __add_one_host_item(__host_allow_link, pitem); + } + + acl_myfree(pdata); +} + +static int __if_host_allow(const char *client_ip) +{ + char myname[] = "__if_host_allow"; + + if (client_ip == NULL || *client_ip == 0) { + acl_msg_info("%s(%d)->%s: invalid input", + __FILE__, __LINE__, myname); + return (-1); + } + + if (__host_allow_link == NULL) { + if (var_proxy_log_level > 3) + acl_msg_info("%s(%d)->%s: host allow, ip=%s", + __FILE__, __LINE__, myname, + client_ip); + return (0); + } + + if (acl_iplink_lookup_str(__host_allow_link, client_ip) != NULL) { + if (var_proxy_log_level > 3) + acl_msg_info("%s(%d)->%s: host allow, ip=%s", + __FILE__, __LINE__, myname, + client_ip); + return (0); + } + + if (var_proxy_log_level > 3) + acl_msg_warn("%s(%d)->%s: host deny, ip = %s", + __FILE__, __LINE__, myname, + client_ip); + return (-1); +} + +static void __pre_jail_init(char *unused_name, char **unused_argv) +{ + char myname[] = "__pre_jail_init"; + + unused_name = unused_name; + unused_argv = unused_argv; + + acl_msg_info("%s(%d)->%s: var_proxy_log_level=%d", + __FILE__, __LINE__, myname, var_proxy_log_level); + + acl_msg_info("host-allow:[%s]", var_proxy_host_allow); /* zsx test */ + __add_host_allow(var_proxy_host_allow); + + if (var_proxy_log_level > 3) + acl_msg_info("%s(%d)->%s: test only", + __FILE__, __LINE__, myname); + if (var_proxy_retries <= 0) { + acl_msg_warn("%s(%d)->%s: proxy_tetries = %d, use default=%d", + __FILE__, __LINE__, myname, + var_proxy_retries, DEF_PROXY_RETRIES); + var_proxy_retries = DEF_PROXY_RETRIES; + } + + if (var_proxy_backend_addr == NULL + || strcmp(var_proxy_backend_addr, DEF_PROXY_BACKEND_ADDR) == 0) { + acl_msg_fatal("%s(%d)->%s: proxy_backend_addr invalid", + __FILE__, __LINE__, myname); + } + + __eventp = acl_event_new_select(acl_var_single_delay_sec, + acl_var_single_delay_usec); + if (__eventp == NULL) + acl_msg_fatal("%s(%d)->%s: acl_event_new error", + __FILE__, __LINE__, myname); +} + +static void __post_jail_init(char *unused_name, char **unused_argv) +{ + char myname[] = "__post_jail_init"; + + unused_name = unused_name; + unused_argv = unused_argv; + + if (var_proxy_log_level > 3) + acl_msg_info("%s(%d)->%s: test only", + __FILE__, __LINE__, myname); +} + +int main(int argc, char *argv[]) +{ + acl_msg_info("%s: start...", __FILE__); + printf("%s: starting...", __FILE__); + + acl_single_server_main(argc, argv, __service, + ACL_MASTER_SERVER_INT_TABLE, __conf_int_tab, + ACL_MASTER_SERVER_STR_TABLE, __conf_str_tab, + ACL_MASTER_SERVER_PRE_INIT, __pre_jail_init, + ACL_MASTER_SERVER_PRE_ACCEPT, __pre_accept, + ACL_MASTER_SERVER_POST_INIT, __post_jail_init, + 0); + exit (0); +} + diff --git a/samples/master/single_proxy/single_proxy.cf b/samples/master/single_proxy/single_proxy.cf new file mode 100644 index 000000000..4f2950507 --- /dev/null +++ b/samples/master/single_proxy/single_proxy.cf @@ -0,0 +1,40 @@ +# service type private unpriv chroot wakeup maxproc command + args + +service proxy +{ + master_disable = yes + master_service = 5006 + master_type = inet + master_private = n + master_unpriv = n + master_chroot = n + master_wakeup = - + master_maxproc = 20 +# 需要预先启动的进程数,该值不应大于 master_maxproc + master_prefork = 2 + master_command = single_proxy + master_log = {install_path}/var/log/single_proxy.log +# master_args = + + single_use_limit = 0 + single_pid_dir = {install_path}/var/pid + single_queue_dir = {install_path}/var + single_rw_timeout = 180 + single_buf_size = 8192 + +# single_in_flow_delay = 1 +# single_idle_limit = 600 +# single_owner = owner +# single_delay_sec = 1 +# single_delay_usec = 5000 +# single_daemon_timeout = 1800 +# single_use_limit = 10 + + proxy_backend_addr = 127.0.0.1:80 + proxy_host_allow = [127.0.0.1, 127.0.0.1], \ + [10.0.0.0, 10.0.255.255], \ + [202.99.16.0, 202.99.16.255], \ + [60.28.250.0, 60.28.250.255], \ + [60.28.251.0, 60.28.261.255] +# proxy_timeout = 60 +} diff --git a/samples/master/single_proxy/single_proxy.h b/samples/master/single_proxy/single_proxy.h new file mode 100644 index 000000000..180c64ed6 --- /dev/null +++ b/samples/master/single_proxy/single_proxy.h @@ -0,0 +1,58 @@ + +#ifndef __SINGLE_PROXY_INCLUDE_H_ +#define __SINGLE_PROXY_INCLUDE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#define VAR_PROXY_TMOUT "proxy_timeout" +#define DEF_PROXY_TMOUT 60 +extern int var_proxy_tmout; + +#define VAR_PROXY_CONNECT_TMOUT "proxy_connect_timeout" +#define DEF_PROXY_CONNECT_TMOUT 60 +extern int var_proxy_connect_tmout; + +#define VAR_PROXY_RW_TMOUT "proxy_rw_timeout" +#define DEF_PROXY_RW_TMOUT 60 +extern int var_proxy_rw_tmout; + +#define VAR_PROXY_BUFSIZE "proxy_bufsize" +#define DEF_PROXY_BUFSIZE 4096 +extern int var_proxy_bufsize; + +#define VAR_PROXY_RETRIES "proxy_retries" +#define DEF_PROXY_RETRIES 1 +extern int var_proxy_retries; + +#define VAR_PROXY_HOST_ALLOW "proxy_host_allow" +#define DEF_PROXY_HOST_ALLOW "[1.0.0.1, 255.255.255.0]" +extern char *var_proxy_host_allow; + +#define VAR_PROXY_BANNER "proxy_banner" +#define DEF_PROXY_BANNER "hello, welcome!" +extern char *var_proxy_banner; + +#define VAR_PROXY_BACKEND_ADDR "proxy_backend_addr" +#define DEF_PROXY_BACKEND_ADDR "none" +extern char *var_proxy_backend_addr; + +#define VAR_PROXY_LOG_LEVEL "proxy_log_level" +#define DEF_PROXY_LOG_LEVEL 0 +extern int var_proxy_log_level; + +#define VAR_PROXY_IN_FILE "proxy_in_file" +#define DEF_PROXY_IN_FILE "in.log" +extern char *var_proxy_in_file; + +#define VAR_PROXY_OUT_FILE "proxy_out_file" +#define DEF_PROXY_OUT_FILE "out.log" +extern char *var_proxy_out_file; + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/samples/master/trigger/Makefile b/samples/master/trigger/Makefile new file mode 100644 index 000000000..2f209c1cf --- /dev/null +++ b/samples/master/trigger/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = trigger diff --git a/samples/master/trigger/main.c b/samples/master/trigger/main.c new file mode 100644 index 000000000..a5a828093 --- /dev/null +++ b/samples/master/trigger/main.c @@ -0,0 +1,63 @@ +#include "lib_acl.h" +#include + +static int var_cfg_sleep_time; +static int var_cfg_create_core; + +static ACL_CONFIG_INT_TABLE __conf_int_tab[] = { + { "sleep_time", 5, &var_cfg_sleep_time, 0, 0 }, + { "create_core", 0, &var_cfg_create_core, 0, 0 }, + { 0, 0, 0, 0, 0}, +}; + +static char* var_cfg_dummy; + +static ACL_CONFIG_STR_TABLE __conf_str_tab[] = { + { "dummy", "default", &var_cfg_dummy }, + { 0, 0, 0 }, +}; + +static void __service(char *buf acl_unused, int len acl_unused, + char *service, char **argv acl_unused) +{ + const char *myname = "__service"; + + /* + * Sanity check. This service takes no command-line arguments. + */ + if (argv[0]) + acl_msg_fatal("%s(%d)->%s: unexpected command-line argument: %s", + __FILE__, __LINE__, myname, argv[0]); + + acl_msg_info("%s(%d), %s: service name = %s, sleep %d, info: %s seconds now---", + __FILE__, __LINE__, myname, service, + var_cfg_sleep_time, var_cfg_dummy); + sleep(var_cfg_sleep_time); + acl_msg_info("%s: wakeup now", myname); + if (var_cfg_create_core) + assert(0); +} + +static void __pre_jail_init(char *name acl_unused, char **argv acl_unused) +{ +} + +static void __post_jail_init(char *name acl_unused, char **argv acl_unused) +{ +} + +static void service_exit(char *service acl_unused, char **argv acl_unused) +{ +} + +int main(int argc, char *argv[]) +{ + acl_trigger_server_main(argc, argv, __service, + ACL_MASTER_SERVER_PRE_INIT, __pre_jail_init, + ACL_MASTER_SERVER_POST_INIT, __post_jail_init, + ACL_MASTER_SERVER_INT_TABLE, __conf_int_tab, + ACL_MASTER_SERVER_STR_TABLE, __conf_str_tab, + ACL_MASTER_SERVER_EXIT, service_exit, + 0); + return (0); +} diff --git a/samples/master/trigger/trigger.cf b/samples/master/trigger/trigger.cf new file mode 100644 index 000000000..6181bf9d2 --- /dev/null +++ b/samples/master/trigger/trigger.cf @@ -0,0 +1,60 @@ +# service type private unpriv chroot wakeup maxproc command + args + +service trigger +{ +# 进程是否禁止运行 + master_disable = yes +# 服务监听为域套接口 + master_service = trigger.sock +# 服务类型 + master_type = unix + +# 当子进程异常退出时,如果该值非空,则将子进程异常退出的消息通知该服务 +# master_notify_addr = 127.0.0.1:5801 +# 邮件通知接收者 +# master_notify_recipients = zhengshuxin@hotmail.com + +# 是否只允许私有访问, 如果为 y, 则域套接口创建在 {install_path}/var/log/private/ 目录下, +# 如果为 n, 则域套接口创建在 {install_path}/var/log/public/ 目录下, + master_private = y + master_unpriv = n +# 是否需要 chroot: n -- no, y -- yes + master_chroot = n +# 每隔多长时间触发一次,单位为秒(仅对 trigger 模式有效) + master_wakeup = 4 +# 最大进程数 + master_maxproc = 10 +# 需要预先启动的进程数,该值不应大于 master_maxproc + master_prefork = 2 +# 进程程序名 + master_command = trigger +# 进程启动参数,只能为: -u [是否允许以某普通用户的身份运行] +# master_args = +# 进程日志记录文件 + master_log = {install_path}/var/log/trigger.log +# 传递给服务子进程的环境变量, 可以通过 getenv("SERVICE_ENV") 获得此值 +# master_env = logme:FALSE, priority:E_LOG_INFO, action:E_LOG_PER_DAY, flush:sync_flush, imit_size:512,\ +# sync_action:E_LOG_SEM, sem_name:/tmp/trigger.sem + +# 是否允许产生 core 文件 +# trigger_enable_core = 1 +# 每个进程实例处理连接数的最大次数,超过此值后进程实例主动退出 + trigger_use_limit = 250 +# 记录进程PID的位置(对于多进程实例来说没有意义) + trigger_pid_dir = {install_path}/var/pid +# 进程运行时所在的路径 + trigger_queue_dir = {install_path}/var +# 读写超时时间, 单位为秒 + trigger_rw_timeout = 1800 +# 读缓冲区的缓冲区大小 + trigger_buf_size = 8192 + +# 进程运行时的用户身份 + trigger_owner = owner +# 用 select 进行循环时的时间间隔 +# 单位为秒 +# trigger_delay_sec = 1 +# 单位为微秒 +# trigger_delay_usec = 5000 +# trigger_daemon_timeout = 1800 +} diff --git a/samples/memdb/Makefile b/samples/memdb/Makefile new file mode 100644 index 000000000..83308f3dd --- /dev/null +++ b/samples/memdb/Makefile @@ -0,0 +1,2 @@ +include ../Makefile_cpp.in +PROG = memdb diff --git a/samples/memdb/main.cpp b/samples/memdb/main.cpp new file mode 100644 index 000000000..2c50bb1f8 --- /dev/null +++ b/samples/memdb/main.cpp @@ -0,0 +1,209 @@ + +#include "lib_acl.h" +#include +#include +#include + +typedef struct USER_INFO { + char user_name[256]; + char user_age[4]; + char user_sex[8]; + char user_phone[20]; + char user_home[20]; +} USER_INFO; + +static const char *db_name = "test.db"; +static const char *tab_name = "test.user_info"; +static ACL_MDB *mdb; +static const char *key_names[] = + { "user_name", "user_home", "user_age", "user_sex", "home_sex", NULL }; +static unsigned int key_flags[] = + { ACL_MDT_FLAG_UNI, 0, 0, 0, 0, 0 }; + +static ACL_SLICE *__slice; + +static void create_db(void) +{ + ACL_MDT *mdt; + + // 创建数据库及数据表 + mdb = acl_mdb_create(db_name, "avl"); + //mdb = acl_mdb_create(db_name, "binhash"); + //mdb = acl_mdb_create(db_name, "hash"); + + mdt = acl_mdb_tbl_create(mdb, tab_name, + /* ACL_MDT_FLAG_NUL, */ + ACL_MDT_FLAG_SLICE1, + /* ACL_MDT_FLAG_SLICE_RTGC_OFF, */ + 100, key_names, key_flags); + acl_assert(mdt); + __slice = acl_slice_create("for USER_INFO", 0, sizeof(USER_INFO), ACL_SLICE_FLAG_GC1); +} + +static void close_db(void) +{ + acl_mdb_free(mdb); + acl_slice_destroy(__slice); +} + +static void add_user(void) +{ + const char *key_values1[] = { "王五", "北京", "26", "male", "北京男生", NULL }; + const char *key_values2[] = { "王燕", "上海", "26", "female", "上海女生", NULL }; + const char *key_values3[] = { "王云", "上海", "25", "female", "上海女生", NULL }; + const char *key_values4[] = { "王燕", "上海", "26", "female", "上海女生", NULL }; + const char *key_values5[] = { "王云", "上海", "25", "female", "上海女生", NULL }; + + USER_INFO *pinfo; + USER_INFO info1 = { "王五", "26", "male", "1111111", "北京" }; + USER_INFO info2 = { "王燕", "26", "female", "1111111", "上海" }; + USER_INFO info3 = { "王云", "25", "female", "1111111", "上海" }; + USER_INFO info4 = { "王燕", "26", "female", "1111111", "上海" }; + USER_INFO info5 = { "王云", "25", "female", "1111111", "上海" }; + + printf(">>>开始添加用户...\r\n"); + + // 添加数据记录 + pinfo = &info1; + (void) acl_mdb_add(mdb, tab_name, pinfo, sizeof(USER_INFO), key_names, key_values1); + printf("\tuser_name(%s), user_age(%s), user_sex(%s), user_home(%s)\r\n", + info1.user_name, info1.user_age, info1.user_sex, info1.user_home); + + pinfo = (USER_INFO*) acl_slice_calloc(__slice); + memcpy(pinfo, &info2, sizeof(USER_INFO)); + (void) acl_mdb_add(mdb, tab_name, pinfo, sizeof(USER_INFO), key_names, key_values2); + printf("\tuser_name(%s), user_age(%s), user_sex(%s), user_home(%s)\r\n", + pinfo->user_name, pinfo->user_age, pinfo->user_sex, pinfo->user_home); + + pinfo = (USER_INFO*) acl_slice_calloc(__slice); + memcpy(pinfo, &info3, sizeof(USER_INFO)); + (void) acl_mdb_add(mdb, tab_name, pinfo, sizeof(USER_INFO), key_names, key_values3); + printf("\tuser_name(%s), user_age(%s), user_sex(%s), user_home(%s)\r\n", + pinfo->user_name, pinfo->user_age, pinfo->user_sex, pinfo->user_home); + + + (void) acl_mdb_add(mdb, tab_name, &info4, sizeof(USER_INFO), key_names, key_values4); + (void) acl_mdb_add(mdb, tab_name, &info5, sizeof(USER_INFO), key_names, key_values5); + + printf("\r\n"); +} + +static void search_user(void) +{ + ACL_MDT_RES *res; + const USER_INFO *pinfo; + + // 查询所有 user_sex 为 male 的数据对象 + res = acl_mdb_find(mdb, tab_name, "user_sex", "male", 0, 0); + printf(">>>查询 user_sex=male results ...\r\n"); + if (res) { + while (1) { + pinfo = (const USER_INFO*) acl_mdt_fetch_row(res); + if (pinfo == NULL) + break; + printf("\tuser_name(%s), user_age(%s), user_sex(%s), user_home(%s)\r\n", + pinfo->user_name, pinfo->user_age, pinfo->user_sex, pinfo->user_home); + } + acl_mdt_res_free(res); + } + + // 查询所有 user_sex 为 male 的数据对象 + res = acl_mdb_find(mdb, tab_name, "user_age", "26", 0, 0); + printf(">>>查询 user_age=26 results ...\r\n"); + if (res) { + while (1) { + pinfo = (const USER_INFO*) acl_mdt_fetch_row(res); + if (pinfo == NULL) + break; + printf("\tuser_name(%s), user_age(%s), user_sex(%s), user_home(%s)\r\n", + pinfo->user_name, pinfo->user_age, pinfo->user_sex, pinfo->user_home); + } + acl_mdt_res_free(res); + } + + // 查询所有北京的用户 + res = acl_mdb_find(mdb, tab_name, "user_home", "北京", 0, 0); + printf(">>>查询 user_home=北京 results ...\r\n"); + if (res) { + while (1) { + pinfo = (const USER_INFO*) acl_mdt_fetch_row(res); + if (pinfo == NULL) + break; + printf("\tuser_name(%s), user_age(%s), user_sex(%s), user_home(%s)\r\n", + pinfo->user_name, pinfo->user_age, pinfo->user_sex, pinfo->user_home); + } + acl_mdt_res_free(res); + } + + // 查询所有上海女生 + res = acl_mdb_find(mdb, tab_name, "home_sex", "上海女生", 0, 0); + printf(">>>查询 上海女生 results ...\r\n"); + if (res) { + while (1) { + pinfo = (const USER_INFO*) acl_mdt_fetch_row(res); + if (pinfo == NULL) + break; + printf("\tuser_name(%s), user_age(%s), user_sex(%s), user_home(%s)\r\n", + pinfo->user_name, pinfo->user_age, pinfo->user_sex, pinfo->user_home); + } + acl_mdt_res_free(res); + } +} + +static void delete_user() +{ + int n; + + printf(">>>删除 上海女生 ...\r\n"); + n = acl_mdb_del(mdb, tab_name, "home_sex", "上海女生", NULL); + printf(">>>ok, delete total number=%d\r\n", n); + acl_mdb_del(mdb, tab_name, "home_sex", "上海女生", NULL); + printf(">>>删除 北京 用户 ...\r\n"); + n = acl_mdb_del(mdb, tab_name, "user_home", "北京", NULL); + printf(">>>ok, delete total number=%d\r\n", n); +} + +static int walk_fn(const void *data, unsigned int dlen acl_unused) +{ + const USER_INFO *pinfo = (const USER_INFO*) data; + + printf("\tuser_name(%s), user_age(%s), user_sex(%s), user_home(%s)\r\n", + pinfo->user_name, pinfo->user_age, pinfo->user_sex, pinfo->user_home); + + return (0); +} + +static void walk_table(void) +{ + int ret; + + printf(">>>遍历数据表\r\n"); + + ret = acl_mdb_walk(mdb, tab_name, walk_fn, 0, 0); + printf(">>>table: %s's total number=%d\r\n", tab_name, ret); +} + +int main(int argc acl_unused, char *argv[] acl_unused) +{ + create_db(); + add_user(); + printf("\r\n"); + + walk_table(); + printf("\r\n"); + + search_user(); + printf("\r\n"); + + delete_user(); + printf("\r\n"); + + search_user(); + printf("\r\n"); + + walk_table(); + + close_db(); + getchar(); + return (0); +} diff --git a/samples/memdb/memdb.vcxproj b/samples/memdb/memdb.vcxproj new file mode 100644 index 000000000..23b9ca7c8 --- /dev/null +++ b/samples/memdb/memdb.vcxproj @@ -0,0 +1,191 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + ReleaseDll + Win32 + + + Release + Win32 + + + + memdb + {BA50914C-5890-4A29-85C0-F0C779552597} + memdb + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOL;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)memdb.exe + %(AdditionalLibraryDirectories) + libcd;%(IgnoreSpecificDefaultLibraries) + true + $(OutDir)memdb.pdb + Console + MachineX86 + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)memdb.exe + ..\..\lib_acl;%(AdditionalLibraryDirectories) + libc;%(IgnoreSpecificDefaultLibraries) + true + Console + true + true + MachineX86 + + + + + Disabled + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOL;ACL_DLL;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + EditAndContinue + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)memdb.exe + ..\..\lib_acl;%(AdditionalLibraryDirectories) + libcd;%(IgnoreSpecificDefaultLibraries) + true + $(OutDir)memdb.pdb + Console + MachineX86 + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_DLL;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)memdb.exe + ..\..\lib_acl;%(AdditionalLibraryDirectories) + libc;%(IgnoreSpecificDefaultLibraries) + true + Console + true + true + MachineX86 + + + + + {b40213c2-507c-4c7f-a6e1-b850c9bdc27b} + false + + + + + + + + + \ No newline at end of file diff --git a/samples/memdb/memdb_vc2003.vcproj b/samples/memdb/memdb_vc2003.vcproj new file mode 100644 index 000000000..09c416fd6 --- /dev/null +++ b/samples/memdb/memdb_vc2003.vcproj @@ -0,0 +1,243 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/memdb/valgrind.sh b/samples/memdb/valgrind.sh new file mode 100644 index 000000000..82c8f353b --- /dev/null +++ b/samples/memdb/valgrind.sh @@ -0,0 +1,2 @@ +#!/bin/sh +valgrind --tool=memcheck --leak-check=yes --show-reachable=yes -v ./memdb_test diff --git a/samples/mempool/Makefile b/samples/mempool/Makefile new file mode 100644 index 000000000..173d69e07 --- /dev/null +++ b/samples/mempool/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = mempool diff --git a/samples/mempool/main.c b/samples/mempool/main.c new file mode 100644 index 000000000..497f23aa8 --- /dev/null +++ b/samples/mempool/main.c @@ -0,0 +1,344 @@ +#include "lib_acl.h" +#include +#include +#include +#include + +#ifdef ACL_MS_WINDOWS +#pragma comment(lib,"ws2_32") +#endif /* ACL_MS_WINDOWS */ + +#if 1 +#define USE_ACL_MALLOC +#endif + +#ifdef USE_ACL_MALLOC +# define MALLOC acl_mymalloc +# define FREE acl_myfree +#else +# define MALLOC malloc +# define FREE free +#endif + +#define MEM_TYPE_GROSS ACL_MEM_TYPE_MAX + 1 +static ACL_ALLOCATOR *__var_allocator = NULL; +static size_t __max_size = 1024 * 1024 * 100; + +static void init(void) +{ + __var_allocator = acl_allocator_create(__max_size); +} + +static void end_prompt(void) +{ +#ifdef ACL_MS_WINDOWS + printf("enter any key to continue.\r\n"); + getchar(); +#endif +} + +static void usage(const char *procname) +{ + printf("usage: %s -h [help] -c bench|bench2|bench3\r\n", procname); +#ifdef ACL_MS_WINDOWS + getchar(); +#endif +} + +static void mempool_bench_test2(const char *label, int use_pool, int mutex, int loop, int size) +{ + char *buf; + time_t begin, end; + int i; + static int __pool_inited = 0; + + if (use_pool) { + if (__pool_inited == 0) { + acl_mempool_open(__max_size, mutex); + __pool_inited = 1; + } else { + acl_mempool_ctl(ACL_MEMPOOL_CTL_MUTEX, mutex, + ACL_MEMPOOL_CTL_END); + } + + i = 0; + time(&begin); + while (i++ < loop) { + buf = MALLOC(size); + FREE(buf); + } + time(&end); + } else { + acl_pthread_mutex_t lock; + + if (mutex) + acl_pthread_mutex_init(&lock, NULL); + + if (__pool_inited) { + acl_mempool_ctl(ACL_MEMPOOL_CTL_DISABLE, 1, + ACL_MEMPOOL_CTL_END); + } + + i = 0; + time(&begin); + while (i++ < loop) { + buf = MALLOC(size); + FREE(buf); + } + time(&end); + + if (mutex) + acl_pthread_mutex_destroy(&lock); + } + + if (use_pool) + printf("%s: time cost is %ld seconds, count is %d, total pool alloc %d\r\n", + label, (long int) end - begin, loop, acl_mempool_total_allocated()); + else + printf("%s: time cost is %ld seconds, count is %d\r\n", + label, (long int) end - begin, loop); +} + +struct MEM_POOL_BENCH2 { + char *label; + int use_pool; + int mutex; + int loop; + int size; +}; + +#define MAX_LOOP 10000000 + +static struct MEM_POOL_BENCH2 __pool_bench_tab2[] = { + { "alloc 64, pool, mutex", 1, 1, MAX_LOOP, 64 }, + { "alloc 64, pool, no mutex", 1, 0, MAX_LOOP, 64 }, + { "alloc 64, no pool, no mutex", 0, 0, MAX_LOOP, 64 }, + + { "alloc 2k, pool, mutex", 1, 1, MAX_LOOP, 1024 * 2 }, + { "alloc 2k, pool, no mutex", 1, 0, MAX_LOOP, 1024 * 2 }, + { "alloc 2k, no pool, no mutex", 0, 0, MAX_LOOP, 1024 * 2 }, + + { "alloc 8k, pool, mutex", 1, 1, MAX_LOOP, 1024 * 8 }, + { "alloc 8k, pool, no mutex", 1, 0, MAX_LOOP, 1024 * 8 }, + { "alloc 8k, no pool, no mutex", 0, 0, MAX_LOOP, 1024 * 8 }, + + { "alloc 64k, pool, mutex", 1, 1, MAX_LOOP, 1024 * 64 }, + { "alloc 64k, pool, no mutex", 1, 0, MAX_LOOP, 1024 * 64 }, + { "alloc 64k, no pool, no mutex", 0, 0, MAX_LOOP, 1024 * 64 }, + + { 0, 0, 0, 0, 0 }, +}; + +static void mem_bench2(void) +{ + int i; + + for (i = 0; __pool_bench_tab2[i].label != NULL; i++) { + if (i % 3 == 0) + printf("\r\n"); + mempool_bench_test2(__pool_bench_tab2[i].label, + __pool_bench_tab2[i].use_pool, + __pool_bench_tab2[i].mutex, + __pool_bench_tab2[i].loop, + __pool_bench_tab2[i].size); + } + end_prompt(); +} + +static struct MEM_POOL_BENCH2 __pool_bench_tab3[] = { + { "alloc 64, pool, mutex", 1, 1, MAX_LOOP, 64 }, + { "alloc 64, pool, mutex", 1, 1, MAX_LOOP, 64 }, + { "alloc 64, pool, mutex", 1, 1, MAX_LOOP, 64 }, + { "alloc 64, pool, mutex", 1, 1, MAX_LOOP, 64 }, + { 0, 0, 0, 0, 0 }, +}; + +static void mem_bench3(void) +{ + int i; + + for (i = 0; __pool_bench_tab3[i].label != NULL; i++) { + if (i % 3 == 0) + printf("\r\n"); + mempool_bench_test2(__pool_bench_tab3[i].label, + __pool_bench_tab3[i].use_pool, + __pool_bench_tab3[i].mutex, + __pool_bench_tab3[i].loop, + __pool_bench_tab3[i].size); + } + end_prompt(); +} + +static void mempool_bench_test(const char *label, int mutex, int loop, acl_mem_type type, int size) +{ + int i = 0; + time_t begin = 0, end = 0; + void *buf; +#ifdef MUTEX_INIT + acl_pthread_mutex_t lock; +#elif defined(ACL_MS_WINDOWS) + acl_pthread_mutex_t lock; +#define MUTEX_INIT +#else + acl_pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; +#endif + + if (mutex) { +#ifdef MUTEX_INIT + acl_pthread_mutex_init(&lock, NULL); +#endif + time(&begin); + while (i++ < loop) { + acl_pthread_mutex_lock(&lock); + acl_pthread_mutex_unlock(&lock); + } + time(&end); + printf("lock and unkock, loop %d, time cost is %ld\r\n", loop, (long int) end - begin); + + i = 0; + if (type > ACL_MEM_TYPE_NONE && type < ACL_MEM_TYPE_MAX) { + time(&begin); + while (i++ < loop) { + acl_pthread_mutex_lock(&lock); + buf = acl_allocator_mem_alloc(__var_allocator, type); + acl_pthread_mutex_unlock(&lock); + + acl_pthread_mutex_lock(&lock); + acl_allocator_mem_free(__var_allocator, type, buf); + acl_pthread_mutex_unlock(&lock); + } + time(&end); + } else if (type == MEM_TYPE_GROSS) { + acl_pthread_mutex_lock(&lock); + buf = acl_allocator_membuf_alloc(__FILE__, __LINE__, + __var_allocator, size); + acl_pthread_mutex_unlock(&lock); + + acl_pthread_mutex_lock(&lock); + acl_allocator_membuf_free(__FILE__, __LINE__, + __var_allocator, buf); + acl_pthread_mutex_unlock(&lock); + } else { + time(&begin); + while (i++ < loop) { + acl_pthread_mutex_lock(&lock); + buf = MALLOC(size); + acl_pthread_mutex_unlock(&lock); + + acl_pthread_mutex_lock(&lock); + FREE(buf); + acl_pthread_mutex_unlock(&lock); + } + time(&end); + } +#ifdef MUTEX_INIT + acl_pthread_mutex_destroy(&lock); +#endif + } else { + if (type > ACL_MEM_TYPE_NONE && type < ACL_MEM_TYPE_MAX) { + time(&begin); + while (i++ < loop) { + buf = acl_allocator_mem_alloc(__var_allocator, type); + acl_allocator_mem_free(__var_allocator, type, buf); + } + time(&end); + } else if (type == MEM_TYPE_GROSS) { + buf = acl_allocator_membuf_alloc(__FILE__, __LINE__, + __var_allocator, size); + acl_allocator_membuf_free(__FILE__, __LINE__, + __var_allocator, buf); + } else { + time(&begin); + while (i++ < loop) { + buf = MALLOC(size); + FREE(buf); + } + time(&end); + } + } + + printf("%s: time cost is %ld seconds, count is %d\r\n", + label, (long int) end - begin, loop); +} + +struct MEM_POOL_BENCH { + char *label; + int mutex; + int loop; + acl_mem_type type; + int size; +}; + +#define MAX_LOOP 10000000 + +static struct MEM_POOL_BENCH __pool_bench_tab[] = { + { "alloc vstring, pool, mutex", 1, MAX_LOOP, ACL_MEM_TYPE_VSTRING, 0 }, + { "alloc vstring, pool, no mutex", 0, MAX_LOOP, ACL_MEM_TYPE_VSTRING, 0 }, + { "alloc vstring, no pool, no mutex", 0, MAX_LOOP, ACL_MEM_TYPE_NONE, 1024 }, + + { "alloc 64, pool, mutex", 1, MAX_LOOP, ACL_MEM_TYPE_64_BUF, 0 }, + { "alloc 64, pool, no mutex", 0, MAX_LOOP, ACL_MEM_TYPE_64_BUF, 0 }, + { "alloc 64, no pool, no mutex", 0, MAX_LOOP, ACL_MEM_TYPE_NONE, 64 }, + + { "alloc 2K, pool, mutex", 1, MAX_LOOP, ACL_MEM_TYPE_2K_BUF, 0 }, + { "alloc 2K, pool, no mutex", 0, MAX_LOOP, ACL_MEM_TYPE_2K_BUF, 0 }, + { "alloc 2K, no pool, no mutex", 0, MAX_LOOP, ACL_MEM_TYPE_NONE, 1024 * 2 }, + + { "alloc 8K, pool, mutex", 1, MAX_LOOP, ACL_MEM_TYPE_8K_BUF, 0 }, + { "alloc 8K, pool, no mutex", 0, MAX_LOOP, ACL_MEM_TYPE_8K_BUF, 0 }, + { "alloc 8K, no pool, no mutex", 0, MAX_LOOP, ACL_MEM_TYPE_NONE, 1024 * 8 }, + + { "alloc 64K, pool, mutex", 1, MAX_LOOP, ACL_MEM_TYPE_64K_BUF, 0 }, + { "alloc 64K, pool, no mutex", 0, MAX_LOOP, ACL_MEM_TYPE_64K_BUF, 0 }, + { "alloc 64K, no pool, no mutex", 0, MAX_LOOP, ACL_MEM_TYPE_NONE, 1024 * 64 }, + + { 0, 0, 0, 0, 0 }, +}; + +static void mem_bench(void) +{ + int i; + + for (i = 0; __pool_bench_tab[i].label != NULL; i++) { + if (i % 3 == 0) + printf("\r\n"); + mempool_bench_test(__pool_bench_tab[i].label, + __pool_bench_tab[i].mutex, + __pool_bench_tab[i].loop, + __pool_bench_tab[i].type, + __pool_bench_tab[i].size); + } + + end_prompt(); +} + +int main(int argc, char *argv[]) +{ + char ch; + + init(); + + while ((ch = getopt(argc, argv, "hc:")) > 0) { + switch (ch) { + case 'h': + usage(argv[0]); + exit (0); + case 'c': + if (strcasecmp(optarg, "bench") == 0) + mem_bench(); + else if (strcasecmp(optarg, "bench2") == 0) + mem_bench2(); + else if (strcasecmp(optarg, "bench3") == 0) + mem_bench3(); + else + usage(argv[0]); + exit (0); + default: + usage(argv[0]); + exit (0); + } + } + + usage(argv[0]); + exit (0); +} diff --git a/samples/mempool/mempool.vcxproj b/samples/mempool/mempool.vcxproj new file mode 100644 index 000000000..7a067e1bb --- /dev/null +++ b/samples/mempool/mempool.vcxproj @@ -0,0 +1,180 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + ReleaseDll + Win32 + + + Release + Win32 + + + + mempool + {6333EAB7-D42C-42D3-8F10-8035C225227F} + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + $(OutDir)mempool.exe + %(AdditionalLibraryDirectories) + true + $(OutDir)mempool.pdb + Console + MachineX86 + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + $(OutDir)mempool.exe + true + Console + true + true + MachineX86 + + + + + Disabled + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_DLL;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + EditAndContinue + + + $(OutDir)mempool.exe + ..\..\lib_acl;%(AdditionalLibraryDirectories) + true + $(OutDir)mempool.pdb + Console + MachineX86 + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_DLL;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + $(OutDir)mempool.exe + true + Console + true + true + MachineX86 + + + + + {b40213c2-507c-4c7f-a6e1-b850c9bdc27b} + false + + + + + + + + + \ No newline at end of file diff --git a/samples/mempool/mempool_vc2003.vcproj b/samples/mempool/mempool_vc2003.vcproj new file mode 100644 index 000000000..32ebf1574 --- /dev/null +++ b/samples/mempool/mempool_vc2003.vcproj @@ -0,0 +1,232 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/mkdir/Makefile b/samples/mkdir/Makefile new file mode 100644 index 000000000..e02b2afdb --- /dev/null +++ b/samples/mkdir/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = createdir diff --git a/samples/mkdir/main.c b/samples/mkdir/main.c new file mode 100644 index 000000000..59c3ead27 --- /dev/null +++ b/samples/mkdir/main.c @@ -0,0 +1,23 @@ +#include "lib_acl.h" + +int main(int argc, char* argv[]) +{ + char path[256]; + int i, n = 1024; + + if (argc != 2) + { + printf("usage: %s path\r\n", argv[1]); + return 1; + } + + for (i = 0; i < n; i++) + { + snprintf(path, sizeof(path), "%s/%d", argv[1], i); + if (acl_make_dirs(path, 0700) == -1) + printf("mkdir %s failed: %s\r\n", path, acl_last_serror()); + else + printf("mkdir %s ok\r\n", path); + } + return 0; +} diff --git a/samples/msg/Makefile b/samples/msg/Makefile new file mode 100644 index 000000000..3a6b5c474 --- /dev/null +++ b/samples/msg/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = msg diff --git a/samples/msg/aqueue.c b/samples/msg/aqueue.c new file mode 100644 index 000000000..8ec6b9e07 --- /dev/null +++ b/samples/msg/aqueue.c @@ -0,0 +1,124 @@ +#include "lib_acl.h" +#include +#include "aqueue.h" + +static int __max = 1000; +static ACL_AQUEUE *__client_queue, *__server_queue; +static int __finish = 0; + +typedef struct { + int cmd; +#define CMD_NOOP 0 +#define CMD_STOP 1 + char buf[1024]; +} DATA; + +static void *client_thread(void *arg acl_unused) +{ + int i; + time_t begin, end; + DATA *data, *data_saved; + + data = (DATA*) acl_mymalloc(1024); + data->cmd = CMD_NOOP; + data_saved = data; + + (void) time(&begin); + for (i = 0; i < __max; i++) { + + if (acl_aqueue_push(__server_queue, data) < 0) { + printf("add to server queue error(%s)\r\n", acl_last_serror()); + break; + } + data = acl_aqueue_pop(__client_queue); + if (data == NULL) { + printf("pop from client queue error(%s)\r\n", acl_last_serror()); + break; + } + } + + (void) time(&end); + __finish = 1; + sleep(1); + printf("max loop: %d, time=%ld\r\n", __max, (long int)(end - begin)); + + printf("send stop msg to server thread\r\n"); + data->cmd = CMD_STOP; + if (acl_aqueue_push(__server_queue, data) < 0) + printf("push stop msg to server queue error(%s)\r\n", acl_last_serror()); + else { + printf("wait server thread respond\r\n"); + data = (DATA *) acl_aqueue_pop(__client_queue); + if (data == NULL) + printf("pop from client queue error(%s)\r\n", acl_last_serror()); + } + + acl_myfree(data_saved); + printf("OK, client exit now\r\n"); + return (NULL); +} + +static void *server_thread(void *arg acl_unused) +{ + int cmd; + DATA *data; + + while (1) { + data = (DATA *) acl_aqueue_pop(__server_queue); + if (data == NULL) { + printf("pop from server queue error(%s)\r\n", acl_last_serror()); + break; + } + + cmd = data->cmd; + if (acl_aqueue_push(__client_queue, data) < 0) { + printf("push to client queue error(%s)\r\n", acl_last_serror()); + break; + } + if (cmd == CMD_STOP) { + break; + } + } + + sleep(1); + printf("server thread exit now\r\n"); + return (NULL); +} + +static void *waiter_thread(void *arg acl_unused) +{ + acl_vstream_printf("aqueue running ...\r\n"); + while (1) { + if (__finish == 1) + break; + acl_vstream_printf("."); + sleep(1); + } + + acl_vstream_printf("\r\n"); + return (NULL); +} + +void aqueue_run(int max) +{ + acl_pthread_t id_client, id_server, id_waiter; + acl_pthread_attr_t attr; + void *ptr; + + __max = max > 0 ? max : 1000; + + printf("max loop: %d\r\n", __max); + __client_queue = acl_aqueue_new(); + __server_queue = acl_aqueue_new(); + + acl_pthread_attr_init(&attr); + acl_pthread_create(&id_server, &attr, server_thread, NULL); + acl_pthread_create(&id_client, &attr, client_thread, NULL); + acl_pthread_create(&id_waiter, &attr, waiter_thread, NULL); + acl_pthread_join(id_server, &ptr); + acl_pthread_join(id_client, &ptr); + acl_pthread_join(id_server, &ptr); + acl_aqueue_free(__client_queue, NULL); + acl_aqueue_free(__server_queue, NULL); + acl_pthread_attr_destroy(&attr); +} diff --git a/samples/msg/aqueue.h b/samples/msg/aqueue.h new file mode 100644 index 000000000..6ef3a86af --- /dev/null +++ b/samples/msg/aqueue.h @@ -0,0 +1,6 @@ +#ifndef __AQUEUE_INCLUDE_H__ +#define __AQUEUE_INCLUDE_H__ + +void aqueue_run(int max); + +#endif diff --git a/samples/msg/main.c b/samples/msg/main.c new file mode 100644 index 000000000..d39ce4784 --- /dev/null +++ b/samples/msg/main.c @@ -0,0 +1,59 @@ +#include +#include +#include +#include +#include "aqueue.h" +#include "netio.h" +#include "pipeio.h" +#include "unixio.h" + +static void usage(const char *procname) +{ + printf("usage: %s -h[help] -n max_loop -m all|aqueue|netio|pipeio|unixio\r\n", procname); +} + +int main(int argc, char *argv[]) +{ + char ch; + int max = 0; + char method[24]; + + method[0] = 0; + while ((ch = getopt(argc, argv, "hn:m:")) > 0) { + switch (ch) { + case 'h': + usage(argv[0]); + return (0); + case 'n': + max = atoi(optarg); + break; + case 'm': + snprintf(method, sizeof(method), "%s", optarg); + break; + default: + break; + } + } + + if (method[0] == 0) { + usage(argv[0]); + return (0); + } + + if (strcasecmp(method, "netio") == 0) + netio_run(max); + else if (strcasecmp(method, "aqueue") == 0) + aqueue_run(max); + else if (strcasecmp(method, "pipeio") == 0) + pipeio_run(max); + else if (strcasecmp(method, "unixio") == 0) + unixio_run(max); + else if (strcasecmp(method, "all") == 0) { + netio_run(max); + aqueue_run(max); + pipeio_run(max); + unixio_run(max); + } else + usage(argv[0]); + return (0); +} diff --git a/samples/msg/netio.c b/samples/msg/netio.c new file mode 100644 index 000000000..b61db723a --- /dev/null +++ b/samples/msg/netio.c @@ -0,0 +1,148 @@ +#include "lib_acl.h" +#include +#include "netio.h" + +static int __max = 1000; +static char __server_addr[64]; +static ACL_VSTREAM *__sstream; +static int __finish = 0; + +typedef struct { + char buf[1024]; +} DATA; + +typedef struct { + int cmd; +#define CMD_NOOP 0 +#define CMD_STOP 1 + DATA *data; +} IO_MSG; + +static void server_listen(void) +{ + char addr[] = "127.0.0.1:0"; + + __sstream = acl_vstream_listen(addr, 64); + assert(__sstream); + snprintf(__server_addr, sizeof(__server_addr), "%s", __sstream->local_addr); +} + +static void server_listen_stop(void) +{ + if (__sstream) + acl_vstream_close(__sstream); +} + +static void *client_thread(void *arg acl_unused) +{ + ACL_VSTREAM *client; + int i; + IO_MSG msg; + DATA *data; + time_t begin, end; + + client = acl_vstream_connect(__server_addr, ACL_BLOCKING, 10, 10, 1024); + assert(client); + + data = (DATA *) acl_mymalloc(sizeof(DATA)); + msg.cmd = CMD_NOOP; + msg.data = data; + + (void) time(&begin); + + for (i = 0; i < __max; i++) { + if (acl_vstream_writen(client, &msg, sizeof(IO_MSG)) == ACL_VSTREAM_EOF) { + printf("write to server error(%s)\r\n", acl_last_serror()); + break; + } + if (acl_vstream_readn(client, &msg, sizeof(IO_MSG)) == ACL_VSTREAM_EOF) { + printf("read from server error(%s)\r\n", acl_last_serror()); + break; + } + } + + (void) time(&end); + __finish = 1; + sleep(1); + printf("max loop: %d, time=%ld\r\n", __max, (long int)(end - begin)); + + printf("send stop msg to server thread\r\n"); + msg.cmd = CMD_STOP; + if (acl_vstream_writen(client, &msg, sizeof(IO_MSG)) == ACL_VSTREAM_EOF) { + printf("write to server error(%s)\r\n", acl_last_serror()); + } else { + printf("wait server thread respond\r\n"); + if (acl_vstream_readn(client, &msg, sizeof(IO_MSG)) == ACL_VSTREAM_EOF) + printf("read server's respond error(%s)\r\n", acl_last_serror()); + } + + acl_myfree(data); + acl_vstream_close(client); + printf("OK, client exit now\r\n"); + return (NULL); +} + +static void *server_thread(void *arg acl_unused) +{ + ACL_VSTREAM *client; + IO_MSG msg; + + client = acl_vstream_accept(__sstream, NULL, 0); + assert(client); + + server_listen_stop(); + + while (1) { + if (acl_vstream_readn(client, &msg, sizeof(IO_MSG)) == ACL_VSTREAM_EOF) { + printf("read from client error(%s)\r\n", acl_last_serror()); + break; + } + if (acl_vstream_writen(client, &msg, sizeof(IO_MSG)) == ACL_VSTREAM_EOF) { + printf("write to client error(%s)\r\n", acl_last_serror()); + break; + } + if (msg.cmd == CMD_STOP) { + break; + } + } + + acl_vstream_close(client); + sleep(1); + printf("server thread exit now\r\n"); + return (NULL); +} + +static void *waiter_thread(void *arg acl_unused) +{ + acl_vstream_printf("netio running ...\r\n"); + while (1) { + if (__finish == 1) + break; + acl_vstream_printf("."); + sleep(1); + } + + acl_vstream_printf("\r\n"); + return (NULL); +} + +void netio_run(int max) +{ + acl_pthread_t id_client, id_server, id_waiter; + acl_pthread_attr_t attr; + void *ptr; + + __max = max > 0 ? max : 1000; + printf("max loop: %d\r\n", __max); + + server_listen(); + + acl_pthread_attr_init(&attr); + acl_pthread_create(&id_server, &attr, server_thread, NULL); + acl_pthread_create(&id_client, &attr, client_thread, NULL); + acl_pthread_create(&id_waiter, &attr, waiter_thread, NULL); + acl_pthread_join(id_client, &ptr); + acl_pthread_join(id_waiter, &ptr); + acl_pthread_join(id_server, &ptr); + acl_pthread_attr_destroy(&attr); +} diff --git a/samples/msg/netio.h b/samples/msg/netio.h new file mode 100644 index 000000000..e16e337d5 --- /dev/null +++ b/samples/msg/netio.h @@ -0,0 +1,6 @@ +#ifndef __NETIO_INCLUDE_H__ +#define __NETIO_INCLUDE_H__ + +void netio_run(int max); + +#endif diff --git a/samples/msg/pipeio.c b/samples/msg/pipeio.c new file mode 100644 index 000000000..fb1de85b7 --- /dev/null +++ b/samples/msg/pipeio.c @@ -0,0 +1,161 @@ +#include "lib_acl.h" +#include +#include "pipeio.h" + +#ifdef ACL_UNIX + +static int __max = 1000; +static ACL_VSTREAM *__sstream_reader, *__sstream_writer; +static ACL_VSTREAM *__cstream_reader, *__cstream_writer; +static int __finish = 0; + +typedef struct { + char buf[1024]; +} DATA; + +typedef struct { + int cmd; +#define CMD_NOOP 0 +#define CMD_STOP 1 + DATA *data; +} IO_MSG; + +static int __server_fd[2], __client_fd[2]; + +static void pipe_init(void) +{ + if (acl_duplex_pipe(__server_fd) < 0) { + printf("acl_duplex_pipe error(%s)\r\n", acl_last_serror()); + exit (1); + } + if (acl_duplex_pipe(__client_fd) < 0) { + printf("acl_duplex_pipe error(%s)\r\n", acl_last_serror()); + exit (1); + } + __sstream_reader = acl_vstream_fdopen(__server_fd[0], O_RDONLY, 1024, 10, ACL_VSTREAM_TYPE_SOCK); + __sstream_writer = acl_vstream_fdopen(__client_fd[1], O_WRONLY, 1024, 10, ACL_VSTREAM_TYPE_SOCK); + + __cstream_reader = acl_vstream_fdopen(__client_fd[0], O_RDONLY, 1024, 10, ACL_VSTREAM_TYPE_SOCK); + __cstream_writer = acl_vstream_fdopen(__server_fd[1], O_WRONLY, 1024, 10, ACL_VSTREAM_TYPE_SOCK); +} + +static void pipe_end(void) +{ + acl_vstream_close(__sstream_reader); + acl_vstream_close(__sstream_writer); + + acl_vstream_close(__cstream_reader); + acl_vstream_close(__cstream_writer); +} + +static void *client_thread(void *arg acl_unused) +{ + int i; + IO_MSG msg; + DATA *data; + time_t begin, end; + + data = (DATA *) acl_mymalloc(sizeof(DATA)); + msg.cmd = CMD_NOOP; + msg.data = data; + + (void) time(&begin); + + for (i = 0; i < __max; i++) { + if (acl_vstream_writen(__cstream_writer, &msg, sizeof(IO_MSG)) == ACL_VSTREAM_EOF) { + printf("write to server error(%s)\r\n", acl_last_serror()); + break; + } + if (acl_vstream_readn(__cstream_reader, &msg, sizeof(IO_MSG)) == ACL_VSTREAM_EOF) { + printf("read from server error(%s)\r\n", acl_last_serror()); + break; + } + } + + (void) time(&end); + __finish = 1; + sleep(1); + printf("max loop: %d, time=%ld\r\n", __max, (long int) (end - begin)); + + printf("send stop msg to server thread\r\n"); + msg.cmd = CMD_STOP; + if (acl_vstream_writen(__cstream_writer, &msg, sizeof(IO_MSG)) == ACL_VSTREAM_EOF) { + printf("write to server error(%s)\r\n", acl_last_serror()); + } else { + printf("wait server thread respond\r\n"); + if (acl_vstream_readn(__cstream_reader, &msg, sizeof(IO_MSG)) == ACL_VSTREAM_EOF) + printf("read server's respond error(%s)\r\n", acl_last_serror()); + } + + acl_myfree(data); + printf("OK, client exit now\r\n"); + return (NULL); +} + +static void *server_thread(void *arg acl_unused) +{ + IO_MSG msg; + + while (1) { + if (acl_vstream_readn(__sstream_reader, &msg, sizeof(IO_MSG)) == ACL_VSTREAM_EOF) { + printf("read from client error(%s)\r\n", acl_last_serror()); + break; + } + if (acl_vstream_writen(__sstream_writer, &msg, sizeof(IO_MSG)) == ACL_VSTREAM_EOF) { + printf("write to client error(%s)\r\n", acl_last_serror()); + break; + } + if (msg.cmd == CMD_STOP) { + break; + } + } + + sleep(1); + printf("server thread exit now\r\n"); + return (NULL); +} + +static void *waiter_thread(void *arg acl_unused) +{ + acl_vstream_printf("pipeio running ...\r\n"); + while (1) { + if (__finish == 1) + break; + acl_vstream_printf("."); + sleep(1); + } + + acl_vstream_printf("\r\n"); + return (NULL); +} + +void pipeio_run(int max) +{ + acl_pthread_t id_client, id_server, id_waiter; + acl_pthread_attr_t attr; + void *ptr; + + __max = max > 0 ? max : 1000; + printf("max loop: %d\r\n", __max); + + pipe_init(); + + acl_pthread_attr_init(&attr); + acl_pthread_create(&id_server, &attr, server_thread, NULL); + acl_pthread_create(&id_client, &attr, client_thread, NULL); + acl_pthread_create(&id_waiter, &attr, waiter_thread, NULL); + acl_pthread_join(id_server, &ptr); + acl_pthread_join(id_client, &ptr); + acl_pthread_join(id_server, &ptr); + acl_pthread_attr_destroy(&attr); + + pipe_end(); +} +#else +void pipeio_run(int max) +{ + const char *myname = "pipeio_run"; + + printf("%s: not support!\r\n", myname); +} +#endif diff --git a/samples/msg/pipeio.h b/samples/msg/pipeio.h new file mode 100644 index 000000000..4feec0905 --- /dev/null +++ b/samples/msg/pipeio.h @@ -0,0 +1,6 @@ +#ifndef __PIPEIO_INCLUDE_H__ +#define __PIPEIO_INCLUDE_H__ + +void pipeio_run(int max); + +#endif diff --git a/samples/msg/unixio.c b/samples/msg/unixio.c new file mode 100644 index 000000000..7c356e903 --- /dev/null +++ b/samples/msg/unixio.c @@ -0,0 +1,166 @@ +#include "lib_acl.h" +#include "unixio.h" + +#ifdef ACL_UNIX +#include +#include + +static int __max = 1000; +static char __server_addr[64]; +static ACL_VSTREAM *__sstream; +static int __finish = 0; + +typedef struct { + char buf[1024]; +} DATA; + +typedef struct { + int cmd; +#define CMD_NOOP 0 +#define CMD_STOP 1 + DATA *data; +} IO_MSG; + +static void server_listen(void) +{ + char buf[256]; + + if (getcwd(buf, sizeof(buf)) == NULL) { + printf("getcwd error(%s)\r\n", acl_last_serror()); + exit (1); + } + + snprintf(__server_addr, sizeof(__server_addr), "%s/unix.sock", buf); + __sstream = acl_vstream_listen(__server_addr, 64); + assert(__sstream); +} + +static void server_listen_stop(void) +{ + if (__sstream) + acl_vstream_close(__sstream); +} + +static void *client_thread(void *arg acl_unused) +{ + ACL_VSTREAM *client; + int i; + IO_MSG msg; + DATA *data; + time_t begin, end; + + client = acl_vstream_connect(__server_addr, ACL_BLOCKING, 10, 10, 1024); + assert(client); + + data = (DATA *) acl_mymalloc(sizeof(DATA)); + msg.cmd = CMD_NOOP; + msg.data = data; + + (void) time(&begin); + + for (i = 0; i < __max; i++) { + if (acl_vstream_writen(client, &msg, sizeof(IO_MSG)) == ACL_VSTREAM_EOF) { + printf("write to server error(%s)\r\n", acl_last_serror()); + break; + } + if (acl_vstream_readn(client, &msg, sizeof(IO_MSG)) == ACL_VSTREAM_EOF) { + printf("read from server error(%s)\r\n", acl_last_serror()); + break; + } + } + + (void) time(&end); + __finish = 1; + sleep(1); + printf("max loop: %d, time=%ld\r\n", __max, (long int)(end - begin)); + + printf("send stop msg to server thread\r\n"); + msg.cmd = CMD_STOP; + if (acl_vstream_writen(client, &msg, sizeof(IO_MSG)) == ACL_VSTREAM_EOF) { + printf("write to server error(%s)\r\n", acl_last_serror()); + } else { + printf("wait server thread respond\r\n"); + if (acl_vstream_readn(client, &msg, sizeof(IO_MSG)) == ACL_VSTREAM_EOF) + printf("read server's respond error(%s)\r\n", acl_last_serror()); + } + + acl_myfree(data); + acl_vstream_close(client); + printf("OK, client exit now\r\n"); + return (NULL); +} + +static void *server_thread(void *arg acl_unused) +{ + ACL_VSTREAM *client; + IO_MSG msg; + + printf("wait for client connection\r\n"); + client = acl_vstream_accept(__sstream, NULL, 0); + assert(client); + + printf("accept one client\r\n"); + server_listen_stop(); + + while (1) { + if (acl_vstream_readn(client, &msg, sizeof(IO_MSG)) == ACL_VSTREAM_EOF) { + printf("read from client error(%s)\r\n", acl_last_serror()); + break; + } + if (acl_vstream_writen(client, &msg, sizeof(IO_MSG)) == ACL_VSTREAM_EOF) { + printf("write to client error(%s)\r\n", acl_last_serror()); + break; + } + if (msg.cmd == CMD_STOP) { + break; + } + } + + acl_vstream_close(client); + sleep(1); + printf("server thread exit now\r\n"); + return (NULL); +} + +static void *waiter_thread(void *arg acl_unused) +{ + acl_vstream_printf("unixio running ...\r\n"); + while (1) { + if (__finish == 1) + break; + acl_vstream_printf("."); + sleep(1); + } + + acl_vstream_printf("\r\n"); + return (NULL); +} + +void unixio_run(int max) +{ + acl_pthread_t id_client, id_server, id_waiter; + acl_pthread_attr_t attr; + void *ptr; + + __max = max > 0 ? max : 1000; + printf("max loop: %d\r\n", __max); + + server_listen(); + + acl_pthread_attr_init(&attr); + acl_pthread_create(&id_server, &attr, server_thread, NULL); + acl_pthread_create(&id_client, &attr, client_thread, NULL); + acl_pthread_create(&id_waiter, &attr, waiter_thread, NULL); + acl_pthread_join(id_server, &ptr); + acl_pthread_join(id_client, &ptr); + acl_pthread_join(id_server, &ptr); + acl_pthread_attr_destroy(&attr); +} +#else +void unixio_run(int max acl_unused) +{ + const char *myname = "unixio_run"; + + printf("%s: not support!\r\n", myname); +} +#endif diff --git a/samples/msg/unixio.h b/samples/msg/unixio.h new file mode 100644 index 000000000..66f27f159 --- /dev/null +++ b/samples/msg/unixio.h @@ -0,0 +1,6 @@ +#ifndef __UNIXIO_INCLUDE_H__ +#define __UNIXIO_INCLUDE_H__ + +void unixio_run(int max); + +#endif diff --git a/samples/msgio/Makefile b/samples/msgio/Makefile new file mode 100644 index 000000000..d12437078 --- /dev/null +++ b/samples/msgio/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = msgio diff --git a/samples/msgio/main.c b/samples/msgio/main.c new file mode 100644 index 000000000..7243f3bb8 --- /dev/null +++ b/samples/msgio/main.c @@ -0,0 +1,221 @@ +#include "lib_acl.h" +#include +#include +#include + +typedef struct { + ACL_SOCKET fd; + int i; +} IPC_CTX; + +typedef struct { + ACL_AIO *aio; + ACL_MSGIO *mio; + ACL_VSTREAM *stream; + int n; + int stop; + acl_pthread_t tid; +} IPC; + +typedef struct { + IPC *ipc; + + ACL_MSGIO *local_mio; + ACL_VSTREAM *local_stream; +} IPC_CLIENT; + +#define MSG_IPC_ACCEPT 100 +#define MSG_IPC_STOP 101 + +#if 0 +#define USE_IPC_SYNC +#endif + +static ACL_MSGIO *__ipc_listener = NULL; +static IPC_CLIENT *__ipc_clients = NULL; +static ACL_AIO *__aio_listener = NULL; +static char __ipc_addr[256]; + +static int msg_ipc_stop(int msg_type acl_unused, ACL_MSGIO *mio acl_unused, + const ACL_MSGIO_INFO *info acl_unused, void *arg) +{ + IPC *ipc = (IPC*) arg; + ipc->stop = 1; + printf("close now(%s)\n", acl_last_serror()); + return (0); +} + +static int msg_ipc_accept(int msg_type acl_unused, ACL_MSGIO *mio acl_unused, + const ACL_MSGIO_INFO *info, void *arg) +{ + IPC *ipc = (IPC*) arg; + IPC_CTX ctx; + + memcpy(&ctx, acl_vstring_str(info->body.buf), ACL_VSTRING_LEN(info->body.buf)); + if (ipc->n % 10000 == 0) + printf("tid: %ld, fd: %d\n", (long) acl_pthread_self(), ctx.fd); + ipc->n++; + return (0); +} + +#ifdef USE_IPC_SYNC +static int service_sync_loop_read(ACL_MSGIO *mio) +{ + ACL_VSTREAM *vstream = acl_msgio_vstream(mio); + int i = 0; + + acl_non_blocking(ACL_VSTREAM_SOCK(vstream), ACL_BLOCKING); + + while (1) { + char buf[256]; + int ret = acl_vstream_read(vstream, buf, sizeof(buf)); + if (ret == ACL_VSTREAM_EOF) { + printf("tid: %ld, read error(%s)\n", + acl_pthread_self(), acl_last_serror()); + return (0); + } + if (0 && i++ % 10000 == 0) + printf("tid: %ld, i: %d\n", acl_pthread_self(), i); + } + + return (i); +} +#endif + +static void *service_thread(void *arg) +{ + IPC *ipc = (IPC*) arg; + ACL_MSGIO *mio = ipc->mio; + ACL_AIO *aio = acl_msgio_aio(mio); + + acl_tcp_set_rcvbuf(ACL_VSTREAM_SOCK(acl_msgio_vstream(mio)), 1024000); + +#ifdef USE_IPC_SYNC + service_sync_loop_read(mio); + return (NULL); +#endif + + /* 进入事件循环 */ + while (1) { + acl_aio_loop(aio); + if (ipc->stop) { + printf("tid: %ld, stop now, n: %d\n", + (long) acl_pthread_self(), ipc->n); + break; + } + } + + return (NULL); +} + +static void init(int nthread) +{ + acl_pthread_attr_t attr; + int i; + + acl_init(); + + __ipc_clients = (IPC_CLIENT*) acl_mycalloc(nthread, sizeof(IPC_CLIENT)); + + acl_pthread_attr_init(&attr); + acl_pthread_attr_setdetachstate(&attr, 0); + + __aio_listener = acl_aio_create(ACL_EVENT_SELECT); + __ipc_listener = acl_msgio_listen(__aio_listener, NULL); + assert(__ipc_listener); + acl_msgio_addr(__ipc_listener, __ipc_addr, sizeof(__ipc_addr)); + printf("listening on: %s\n", __ipc_addr); + + for (i = 0; i < nthread; i++) { + __ipc_clients[i].ipc = (IPC*) acl_mycalloc(1, sizeof(IPC)); + __ipc_clients[i].ipc->aio = acl_aio_create(ACL_EVENT_SELECT); + __ipc_clients[i].ipc->mio = acl_msgio_connect(__ipc_clients[i].ipc->aio, __ipc_addr, 0); + /* + acl_msgio_set_noblock(__ipc_clients[i].ipc->aio, __ipc_clients[i].ipc->mio); + */ + acl_msgio_reg(__ipc_clients[i].ipc->mio, MSG_IPC_ACCEPT, + msg_ipc_accept, __ipc_clients[i].ipc); + acl_msgio_reg(__ipc_clients[i].ipc->mio, MSG_IPC_STOP, + msg_ipc_stop, __ipc_clients[i].ipc); + acl_msgio_reg(__ipc_clients[i].ipc->mio, ACL_MSGIO_EXCEPT, + msg_ipc_stop, __ipc_clients[i].ipc); + + acl_pthread_create(&__ipc_clients[i].ipc->tid, &attr, service_thread, __ipc_clients[i].ipc); + __ipc_clients[i].local_mio = acl_msgio_accept(__ipc_listener); + assert(__ipc_clients[i].local_mio); + __ipc_clients[i].local_stream = acl_msgio_vstream(__ipc_clients[i].local_mio); + acl_non_blocking(ACL_VSTREAM_SOCK(__ipc_clients[i].local_stream), ACL_NON_BLOCKING); + acl_tcp_set_sndbuf(ACL_VSTREAM_SOCK(__ipc_clients[i].local_stream), 1024000); + acl_tcp_set_nodelay(ACL_VSTREAM_SOCK(__ipc_clients[i].local_stream)); + } +} + +static void run(int nthread, int nloop) +{ + int i, ret; + IPC_CTX ctx; + time_t begin = time(NULL); + + for (i = 0; i < nloop; i++) { + memset(&ctx, 0, sizeof(ctx)); + ctx.fd = i; +#ifdef USE_IPC_SYNC + acl_vstream_write(__ipc_clients[i % nthread].local_stream, &ctx, sizeof(IPC_CTX)); +#else + ret = acl_msgio_send(__ipc_clients[i % nthread].local_mio, MSG_IPC_ACCEPT, &ctx, sizeof(IPC_CTX)); + if (ret < 0) + break; +#endif + if (i % 10000 == 0) + printf("run(tid=%ld): i=%d\n", (long) acl_pthread_self(), i); + } + + for (i = 0; i < nthread; i++) { + memset(&ctx, 0, sizeof(ctx)); + ctx.fd = -1; + acl_msgio_send(__ipc_clients[i].local_mio, MSG_IPC_STOP, &ctx, sizeof(IPC_CTX)); + } + for (i = 0; i < nthread; i++) + acl_pthread_join(__ipc_clients[i].ipc->tid, NULL); + for (i = 0; i < nthread; i++) + acl_msgio_close(__ipc_clients[i].local_mio); + acl_myfree(__ipc_clients); + printf(">>>time cost: %ld\n", time(NULL) - begin); +} + +static void usage(const char *procname) +{ + printf("usage: %s -h [help] -c nthreads -n nloop\n", procname); +} + +int main(int argc, char *argv[]) +{ + int nthread = 2, nloop = 1000000, ch; + + acl_msg_stdout_enable(1); + + while ((ch = getopt(argc, argv, "hc:n:")) > 0) { + switch (ch) { + case 'h': + usage(argv[0]); + return (0); + case 'n': + nloop = atoi(optarg); + break; + case 'c': + nthread = atoi(optarg); + break; + default: + break; + } + } + + if (nthread <= 0) + nthread = 2; + if (nloop <= 0) + nloop = 1000; + + init(nthread); + run(nthread, nloop); + return (0); +} diff --git a/samples/mysql/Makefile b/samples/mysql/Makefile new file mode 100644 index 000000000..671031dcc --- /dev/null +++ b/samples/mysql/Makefile @@ -0,0 +1,4 @@ +include ../Makefile.in +CFLAGS += -I/opt/import_lib/include/mysql +EXTLIBS = -L/opt/import_lib/lib -lmysqlclient_r -lm +PROG = mysql diff --git a/samples/mysql/main.c b/samples/mysql/main.c new file mode 100644 index 000000000..1c444b95e --- /dev/null +++ b/samples/mysql/main.c @@ -0,0 +1,154 @@ +#include "lib_acl.h" +#include "mysql.h" +#include +#include +#include + +static ACL_DB_POOL *__db_pool = NULL; + +static int db_before_connect(ACL_DB_HANDLE* db_handle, void *ctx acl_unused) +{ + const char *myname = "db_before_connect"; + MYSQL *mysql; + + printf("%p\n", (void*) db_handle); + mysql = (MYSQL*) acl_dbpool_export(db_handle); + if (mysql_options(mysql, MYSQL_SET_CHARSET_NAME, "GB2312")) { + printf("%s: mysql_options error\n", myname); + return (-1); + } + + printf("%s: ok\n", myname); + return (0); +} + +static int db_after_connect(ACL_DB_HANDLE* db_handle, void *ctx acl_unused) +{ + const char *myname = "db_after_connect"; + + (void) db_handle; + printf("%s: ok\n", myname); + return (0); +} + +static void dbconn_init(const char *addr, const char *name, const char *usr, + const char *pass, int dbpool_max, int dbping, int dbtimeout) +{ + const char *myname = "dbconn_init"; + ACL_DB_INFO db_info; + + memset(&db_info, 0, sizeof(ACL_DB_INFO)); + + ACL_SAFE_STRNCPY(db_info.db_addr, addr, sizeof(db_info.db_addr)); + ACL_SAFE_STRNCPY(db_info.db_name, name, sizeof(db_info.db_name)); + ACL_SAFE_STRNCPY(db_info.db_user, usr, sizeof(db_info.db_user)); + ACL_SAFE_STRNCPY(db_info.db_pass, pass, sizeof(db_info.db_pass)); + + db_info.db_max = dbpool_max; + db_info.ping_inter = dbping; + db_info.timeout_inter = dbtimeout; + db_info.auto_commit = 1; + + db_info.db_before_connect = db_before_connect; + db_info.db_after_connect = db_after_connect; + + __db_pool = acl_dbpool_create("mysql", &db_info); + + if (__db_pool == NULL) + acl_msg_fatal("%s(%d): init db pool error", myname, __LINE__); + +} + +static ACL_DB_HANDLE *dbconn_get(void) +{ + const char *myname = "dbconn_get"; + ACL_DB_HANDLE *db_handle; + + if (__db_pool == NULL) + acl_msg_fatal("%s(%d): db pool null", myname, __LINE__); + + db_handle = acl_dbpool_peek(__db_pool); + if (db_handle == NULL) { + acl_msg_error("%s(%d): get db conn error", myname, __LINE__); + return (NULL); + } + + return (db_handle); +} + +static void dbconn_put(ACL_DB_HANDLE *db_handle) +{ + const char *myname = "dbconn_put"; + + if (db_handle == NULL) + acl_msg_fatal("%s(%d): input null", myname, __LINE__); + + acl_dbpool_release(db_handle); +} + +static void dbconn_free(void) +{ + if (__db_pool) { + acl_dbpool_destroy(__db_pool); + __db_pool = NULL; + } +} + +static void usage(const char *procname) +{ + printf("usage: %s -h[help] -H mysql_addr -N dbname -U dbuser -P dbpass\n", procname); +} + +int main(int argc, char *argv[]) +{ + ACL_DB_HANDLE *db_handle; + char db_addr[256], db_name[256], db_user[256], db_pass[256]; + int db_max = 10, db_ping = 60, db_timeout = 60; + int ch; + + db_addr[0] = 0; + db_name[0] = 0; + db_user[0] = 0; + db_pass[0] = 0; + + while ((ch = getopt(argc, argv, "hH:N:U:P:")) > 0) { + switch (ch) { + case 'h': + usage(argv[0]); + return (0); + case 'H': + snprintf(db_addr, sizeof(db_addr), "%s", optarg); + break; + case 'N': + snprintf(db_name, sizeof(db_name), "%s", optarg); + break; + case 'U': + snprintf(db_user, sizeof(db_user), "%s", optarg); + break; + case 'P': + snprintf(db_pass, sizeof(db_pass), "%s", optarg); + break; + default: + break; + } + } + + if (db_addr[0] == 0 || db_name[0] == 0 || db_user[0] == 0 || db_pass[0] == 0) { + usage(argv[0]); + return (1); + } + + dbconn_init(db_addr, db_name, db_user, db_pass, db_max, db_ping, db_timeout); + printf("dbconn_init ok\n"); + db_handle = dbconn_get(); + if (db_handle) { + printf("dbconn_get ok\n"); + dbconn_put(db_handle); + printf("dbconn_put ok\n"); + } + dbconn_free(); + printf("dbconn_free ok\n"); + mysql_library_end(); + + return (0); +} diff --git a/samples/mysql/test.sh b/samples/mysql/test.sh new file mode 100644 index 000000000..f0830ebf2 --- /dev/null +++ b/samples/mysql/test.sh @@ -0,0 +1,2 @@ +#!/bin/sh +./db_mysql -H /tmp/mysql.csmail.sock -N csmail_userdb -U csmail -P 6632857799266825679 diff --git a/samples/mysql/valgrind.sh b/samples/mysql/valgrind.sh new file mode 100644 index 000000000..bec16941a --- /dev/null +++ b/samples/mysql/valgrind.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +valgrind --show-below-main=yes --show-reachable=yes --tool=memcheck --leak-check=yes -v \ +./db_mysql -H /tmp/mysql.csmail.sock -N csmail_userdb -U csmail -P 6632857799266825679 diff --git a/samples/mysql2/Makefile b/samples/mysql2/Makefile new file mode 100644 index 000000000..671031dcc --- /dev/null +++ b/samples/mysql2/Makefile @@ -0,0 +1,4 @@ +include ../Makefile.in +CFLAGS += -I/opt/import_lib/include/mysql +EXTLIBS = -L/opt/import_lib/lib -lmysqlclient_r -lm +PROG = mysql diff --git a/samples/mysql2/main.c b/samples/mysql2/main.c new file mode 100644 index 000000000..d5a21ce75 --- /dev/null +++ b/samples/mysql2/main.c @@ -0,0 +1,133 @@ + +/* + * Copyright (C) 2010 51IKER + * All rights reserved. + * + * AUTHOR(S) + * Xiaohua Jia + * Beijing, RPC 100006 + * E-mail: jiaxiaohua@51iker.com + */ + +/* System library. */ +#include +#include + +/* Utility library. */ +#include "mysql.h" +#include "lib_acl.h" + +/* Global library. */ + +/* Application-specific. */ + + +void test_select(ACL_DB_HANDLE *db_handle); +void test_select(ACL_DB_HANDLE *db_handle) +{ + int error = 0; + unsigned int i = 0; + unsigned int num_fields = 0; + + ACL_ITER iter; + ACL_SQL_RES *res = NULL; + + MYSQL *mysql = NULL; + MYSQL_RES *my_res= NULL; + MYSQL_FIELD *fields = NULL; + + const char **row = NULL; + ACL_VSTRING *xml_datas = NULL; + + res = acl_dbsql_select(db_handle, + "SELECT * FROM filter_rules WHERE frid=\"4\"", &error); + mysql = (MYSQL *)acl_dbpool_export(db_handle); + printf("error=%d; mysql errno=%d; " + "error=%s;", error, + mysql_errno(mysql), mysql_error(mysql)); + + xml_datas = acl_vstring_alloc(64); + my_res = (MYSQL_RES*)res->res; + + + num_fields = mysql_num_fields(my_res); + fields = mysql_fetch_fields(my_res); + + printf("res=%p; num=%d; fel=%p; ss=%lu; sf=%lu\n", + (void *)my_res, num_fields, (void *)fields, sizeof(*my_res), sizeof(*fields)); + + acl_foreach(iter, res) { + row = (const char**) iter.data; + + acl_vstring_sprintf_append(xml_datas, " +#include +#include + +/* Utility library. */ +#include "mysql.h" + +/* Global library. */ + +/* Application-specific. */ + +static void test_batch_insert(MYSQL *mysql) +{ +#if 0 + const char *sql[] = { + "INSERT IGNORE INTO address_book_group_00(owner, name) " + "values('xxx@ikmail.com' , 'xxx1');", + "INSERT IGNORE INTO address_book_group_00 " + "SET owner='xxx@ikmail.com' , name='xxx2';", + "INSERT IGNORE INTO address_book_group_00 " + "SET owner='xxx@ikmail.com' , name='xxx3'", + "INSERT IGNORE INTO address_book_group_00 " + "SET owner='xxx@ikmail.com' , name='xxx4';" }; + + printf("sql0: %s\n", sql[0]); + printf("sql1: %s\n", sql[1]); + printf("sql2: %s\n", sql[2]); + printf("sql3: %s\n", sql[3]); + assert(mysql_query(mysql, sql[0]) == 0); + assert(mysql_query(mysql, sql[1]) == 0); + assert(mysql_query(mysql, sql[2]) == 0); + assert(mysql_query(mysql, sql[3]) == 0); +#else + const char *sql = + "INSERT IGNORE INTO address_book_group_00(owner, name) " + "values('xxx@ikmail.com' , 'xxx1'); " + "INSERT IGNORE INTO address_book_group_00 " + "SET owner='xxx@ikmail.com' , name='xxx2'; " + "INSERT IGNORE INTO address_book_group_00 " + "SET owner='xxx@ikmail.com' , name='xxx3'; " + "INSERT IGNORE INTO address_book_group_00 " + "SET owner='xxx@ikmail.com' , name='xxx4';"; + + printf("sql: %s\n", sql); + assert(mysql_query(mysql, sql) == 0); + +#endif +} + + +int main(void) +{ + MYSQL *mysql; + int reconnect = 1; + + mysql_library_init(0, NULL, NULL); + + mysql = mysql_init(NULL); + assert(mysql); + mysql_options(mysql, MYSQL_OPT_RECONNECT, (const void*) &reconnect); + assert(mysql_real_connect(mysql, "127.0.0.1", "root", "", "ikmail", 3306, 0, CLIENT_MULTI_STATEMENTS)); + mysql_autocommit(mysql, 1); + + test_batch_insert(mysql); + + mysql_library_end(); + return 0; +} diff --git a/samples/net/Makefile b/samples/net/Makefile new file mode 100644 index 000000000..45a4d1c5f --- /dev/null +++ b/samples/net/Makefile @@ -0,0 +1,2 @@ +include ../Makefile_cpp.in +PROG = net diff --git a/samples/net/main.cpp b/samples/net/main.cpp new file mode 100644 index 000000000..cf57e216c --- /dev/null +++ b/samples/net/main.cpp @@ -0,0 +1,215 @@ +#include "lib_acl.h" +#include +#ifdef ACL_UNIX +#include +#endif + +static int __quit = 0; + +static void end(void) +{ +#ifdef ACL_MS_WINDOWS + acl_vstream_fprintf(ACL_VSTREAM_OUT, "enter any key to quit\r\n"); + getchar(); +#endif +} + +static int on_close(ACL_ASTREAM *astream, void *context) +{ + ACL_FIFO *fifo = (ACL_FIFO*) context; + + acl_fifo_delete(fifo, astream); + + printf(">>>close client fd=%d\r\n", ACL_VSTREAM_SOCK(acl_aio_vstream(astream))); + return (-1); +} + +static int read_complete(ACL_ASTREAM *astream, + void *context acl_unused, + const char *data, + int dlen) +{ + if (strncasecmp(data, "quit", strlen("quit")) == 0) { + __quit = 1; + return (-1); + } + + acl_aio_writen(astream, data, dlen); + return (0); +} + +static int accept_complete(ACL_ASTREAM *client, void *context) +{ + ACL_FIFO *fifo = (ACL_FIFO *) context; + + acl_fifo_push(fifo, client); + printf(">>> accept one client, max_fd=%d, count=%d\r\n", + ACL_VSTREAM_SOCK(acl_aio_vstream(client)), acl_fifo_size(fifo)); + + acl_aio_ctl(client, + ACL_AIO_CTL_TIMEOUT, 0, + ACL_AIO_CTL_READ_HOOK_ADD, read_complete, fifo, + ACL_AIO_CTL_CLOSE_HOOK_ADD, on_close, fifo, + ACL_AIO_CTL_END); + + acl_non_blocking(ACL_VSTREAM_SOCK(acl_aio_vstream(client)), ACL_NON_BLOCKING); + acl_aio_gets(client); + return (0); +} + +static int vstream_server(const char *addr) +{ + const char *myname = "vstream_server"; + ACL_VSTREAM *sstream; + ACL_ASTREAM *server, *client; + char ebuf[256]; + ACL_FIFO fifo; + ACL_AIO *aio; + + acl_fifo_init(&fifo); + +#if 0 + sstream = acl_vstream_listen(addr, 128); +#else + sstream = acl_vstream_listen_ex(addr, 256, ACL_NON_BLOCKING, 0, 0); +#endif + if (sstream == NULL) { + printf("%s(%d): listen on %s error(%s)\r\n", + myname, __LINE__, addr, + acl_last_strerror(ebuf, sizeof(ebuf))); + return (-1); + } + +#if 0 + acl_tcp_defer_accept(ACL_VSTREAM_SOCK(sstream), 0); +#endif + printf("%s: listen %s ok\r\n", myname, addr); + +#ifdef ACL_UNIX + aio = acl_aio_create(ACL_EVENT_POLL); +#else + aio = acl_aio_create(ACL_EVENT_SELECT); +#endif + +#if 0 + acl_aio_set_delay_sec(aio, 0); + acl_aio_set_delay_usec(aio, 1000000); +#endif + server = acl_aio_open(aio, sstream); + acl_aio_ctl(server, + ACL_AIO_CTL_ACCEPT_FN, accept_complete, + ACL_AIO_CTL_CTX, &fifo, + ACL_AIO_CTL_END); + acl_aio_accept(server); + + while (1) { + acl_aio_loop(aio); + if (__quit) + break; + } + + printf(">>> curr client %d, enter any key to exit", acl_fifo_size(&fifo)); + fflush(stdout); + getchar(); + + while (1) { + client = (ACL_ASTREAM*) acl_fifo_pop(&fifo); + if (client == NULL) + break; + acl_aio_iocp_close(client); + } + + return (0); +} + +static int vstream_client(const char *server_addr, int max) +{ + const char *myname = "vstream_client"; + ACL_VSTREAM *client; + char ebuf[256]; + ACL_FIFO fifo; + int i; + + acl_fifo_init(&fifo); + + for (i = 0; i < max; i++) { + client = acl_vstream_connect(server_addr, ACL_BLOCKING, 0, 0, 1024); + if (client == NULL) { + printf("%s(%d): connect addr %s error(%s)\n", + myname, __LINE__, server_addr, + acl_last_strerror(ebuf, sizeof(ebuf))); + break; + } + acl_fifo_push(&fifo, client); + printf(">>> connect ok, i=%d, fd=%d\r\n", i, ACL_VSTREAM_SOCK(client)); + } + + printf(">>> connect over, count=%d, enter any key to exit", acl_fifo_size(&fifo)); + fflush(stdout); + getchar(); + + while (1) { + client = (ACL_VSTREAM*) acl_fifo_pop(&fifo); + if (client == NULL) + break; + acl_vstream_close(client); + } + + printf(">>> exit now\r\n"); + return (0); +} + +static void usage(const char *procname) +{ + printf("usage: %s -h [help] -s server_addr -c conn_number -r [server|client]\r\n", procname); +} + +int main(int argc acl_unused, char *argv[] acl_unused) +{ + char addr[256]; + int ch, n, f; + + acl_init(); + acl_msg_stdout_enable(1); + + addr[0] = 0; + n = 0; + f = 0; + + while ((ch = getopt(argc, argv, "hs:c:r:")) > 0) { + switch (ch) { + case 's': + snprintf(addr, sizeof(addr), "%s", optarg); + break; + case 'c': + n = atoi(optarg); + break; + case 'r': + if (strcasecmp(optarg, "server") == 0) + f = 0; + else if (strcasecmp(optarg, "client") == 0) + f = 1; + break; + case 'h': + default: + usage(argv[0]); + exit (0); + } + } + + if (f == 0) { + if (addr[0] == 0) + snprintf(addr, sizeof(addr), "127.0.0.1:9876"); + vstream_server(addr); + } else if (f == 1) { + if (addr[0] == 0) + snprintf(addr, sizeof(addr), "127.0.0.1:9876"); + if (n <= 0) + n = 1024; + vstream_client(addr, n); + } else + usage(argv[0]); + + end(); + return (0); +} diff --git a/samples/ping/Makefile b/samples/ping/Makefile new file mode 100644 index 000000000..2980ef1db --- /dev/null +++ b/samples/ping/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = ping diff --git a/samples/ping/main.c b/samples/ping/main.c new file mode 100644 index 000000000..d338df04a --- /dev/null +++ b/samples/ping/main.c @@ -0,0 +1,274 @@ +#include "lib_acl.h" +#include "lib_protocol.h" +#include "lib_acl.h" +#include + +static void add_ip_list(ICMP_CHAT *chat, const ACL_ARGV *domain_list, + int npkt, int delay) +{ + ACL_DNS_DB* dns_db; + const char* ptr; + int i, j; + char *pdomain, *pip; + ACL_ARGV* ip_list = acl_argv_alloc(10); + + for (i = 0; i < domain_list->argc; i++) { + dns_db = acl_gethostbyname(domain_list->argv[i], NULL); + if (dns_db == NULL) { + acl_msg_warn("Can't find domain %s", domain_list->argv[i]); + continue; + } + + for (j = 0; j < acl_netdb_size(dns_db); j++) { + ptr = acl_netdb_index_ip(dns_db, j); + if (ptr == NULL) + continue; + acl_argv_add(ip_list, domain_list->argv[i], ptr, NULL); + } + acl_netdb_free(dns_db); + } + + for (i = 0; i < ip_list->argc;) { + pdomain = ip_list->argv[i++]; + pip = ip_list->argv[i++]; + + if (strcmp(pdomain, pip) == 0) + icmp_ping_one(chat, NULL, pip, npkt, delay, 1); + else + icmp_ping_one(chat, pdomain, pip, npkt, delay, 1); + } +} + +static ICMP_CHAT *__chat = NULL; + +static void display_res2(ICMP_CHAT *chat) +{ + if (chat) { + /* 显示 PING 的结果总结 */ + icmp_stat(chat); + printf(">>>max pkts: %d\r\n", icmp_chat_seqno(chat)); + } +} + +static void display_res(void) +{ + if (__chat) { + display_res2(__chat); + + /* 释放 ICMP 对象 */ + icmp_chat_free(__chat); + __chat = NULL; + } +} + +/* 单线程异步 PING 多个地址的函数入口 */ +static void ping_main_async(const ACL_ARGV *ip_list, int npkt) +{ + int delay = 1; + ACL_AIO *aio; + + /* 创建非阻塞异步通信句柄 */ + aio = acl_aio_create(ACL_EVENT_SELECT); + acl_aio_set_keep_read(aio, 0); + + /* 创建 ICMP 对象 */ + __chat = icmp_chat_create(aio, 1); + + /* 添加需要 PING 的地址列表 */ + add_ip_list(__chat, ip_list, npkt, delay); + + while (1) { + /* 如果 PING 结束,则退出循环 */ + if (icmp_chat_finish(__chat)) { + printf("over now!, hosts' size=%d, count=%d\r\n", + icmp_chat_size(__chat), icmp_chat_count(__chat)); + break; + } + + /* 异步事件循环过程 */ + acl_aio_loop(aio); + } + + /* 显示 PING 结果 */ + display_res(); + + /* 销毁非阻塞句柄 */ + acl_aio_free(aio); +} + +/* 单线程 PING 单个地址的函数入口 */ +static void ping_main_sync(const char *dest, int npkt) +{ + ACL_DNS_DB* dns_db; + int delay = 1; + const char* ip; + + /* 创建 ICMP 对象 */ + __chat = icmp_chat_create(NULL, 1); + + /* 由域名解析出 IP 地址 */ + dns_db = acl_gethostbyname(dest, NULL); + if (dns_db == NULL) { + acl_msg_warn("Can't find domain %s", dest); + return; + } + + ip = acl_netdb_index_ip(dns_db, 0); + if (ip == NULL || *ip == 0) + acl_msg_fatal("ip invalid"); + + /* 开始 PING 一个 IP 地址 */ + if (strcmp(dest, ip) == 0) + icmp_ping_one(__chat, NULL, ip, npkt, delay, 1); + else + icmp_ping_one(__chat, dest, ip, npkt, delay, 1); + + /* 释放 DNS 查询结果 */ + acl_netdb_free(dns_db); + + /* 显示 PING 结果小结 */ + display_res(); +} + +/* PING 线程入口 */ +static int __npkt = 10; +static void *ping_thread(void *arg) +{ + const char *ip, *dest = (char *) arg; + ACL_DNS_DB* dns_db; + int delay = 1; + ICMP_CHAT *chat; + + /* 通过域名解析出IP地址 */ + dns_db = acl_gethostbyname(dest, NULL); + if (dns_db == NULL) { + acl_msg_warn("Can't find domain %s", dest); + return (NULL); + } + + /* 只取出域名第一个 IP 地址 PING */ + ip = acl_netdb_index_ip(dns_db, 0); + if (ip == NULL || *ip == 0) { + acl_msg_error("ip invalid"); + acl_netdb_free(dns_db); + return (NULL); + } + + /* 创建 ICMP 对象 */ + chat = icmp_chat_create(NULL, 1); + + /* 开始 PING */ + if (strcmp(dest, ip) == 0) + icmp_ping_one(chat, NULL, ip, __npkt, delay, 1); + else + icmp_ping_one(chat, dest, ip, __npkt, delay, 1); + acl_netdb_free(dns_db); /* 释放域名解析对象 */ + display_res2(chat); /* 显示 PING 结果 */ + icmp_chat_free(chat); /* 释放 ICMP 对象 */ + return (NULL); +} + +/* 多线程方式 PING 多个目标地址,每个线程采用同步 PING 方式 */ +static void ping_main_threads(const ACL_ARGV *ip_list, int npkt) +{ + int i, n; + acl_pthread_t tids[128]; + acl_pthread_attr_t attr; + + __npkt = npkt; + acl_pthread_attr_init(&attr); + acl_pthread_attr_setdetachstate(&attr, 0); + + /* 限定每次最大的线程数,防止系统开销太大 */ + n = ip_list->argc > 128 ? 128 : ip_list->argc; + for (i = 0; i < n; i++) + /* 创建 PING 线程 */ + acl_pthread_create(&tids[i], &attr, ping_thread, ip_list->argv[i]); + + for (i = 0; i < n; i++) + /* 回收线程状态 */ + acl_pthread_join(tids[i], NULL); +} + +static void usage(const char* progname) +{ + printf("usage: %s [-h help] -s [sync] -t [use thread mode] [-n npkt] [\"dest1 dest2 dest3...\"]\r\n", progname); + printf("example: %s -n 10 www.sina.com.cn www.baidu.com www.qq.com\r\n", progname); + printf("example: %s -s -n 10 www.sina.com.cn\r\n", progname); +#ifdef WIN32 + printf("please enter any key to exit\r\n"); + getchar(); +#endif +} + +/* 当收到 SIGINT 信号(即在 PING 过程中用户按下 ctrl + c)时的信号处理函数 */ +static void OnSigInt(int signo acl_unused) +{ + display_res(); + exit(0); +} + +int main(int argc, char* argv[]) +{ + char ch; + int npkt = 5, i, syn = 0, thread = 0; + ACL_ARGV* dest_list = acl_argv_alloc(10); + + signal(SIGINT, OnSigInt); /* 用户按下 ctr + c 时中断 PING 程序 */ + acl_socket_init(); /* 在 WIN32 下需要初始化全局套接字库 */ + acl_msg_stdout_enable(1); /* 允许 acl_msg_xxx 记录的信息输出至屏幕 */ + + while ((ch = getopt(argc, argv, "htsl:n:")) > 0) { + switch (ch) { + case 'h': + usage(argv[0]); + return (0); + case 's': + syn = 1; + break; + case 't': + thread = 1; + break; + case 'n': + npkt = atoi(optarg); + break; + default: + usage(argv[0]); + return (0); + } + } + + if (optind == argc) { + usage(argv[0]); + return (0); + } + + for (i = optind; i < argc; i++) { + acl_argv_add(dest_list, argv[i], NULL); + } + + if (npkt <= 0) + npkt = 0; + + /* 同步 PING 方式,对于多个目标地址,采用一个线程 PING 一个地址 */ + if (thread) + ping_main_threads(dest_list, npkt); + + /* 同步 PING 方式,只能同时 PING 一个地址 */ + else if (syn) + ping_main_sync(dest_list->argv[0], npkt); + + /* 异步 PING 方式,可以在一个线程中同时 PING 多个地址 */ + else + ping_main_async(dest_list, npkt); + + acl_argv_free(dest_list); + +#ifdef WIN32 + printf("please enter any key to exit\r\n"); + getchar(); +#endif + + acl_socket_end(); + return 0; +} diff --git a/samples/ping/ping.vcproj b/samples/ping/ping.vcproj new file mode 100644 index 000000000..4414bb40d --- /dev/null +++ b/samples/ping/ping.vcproj @@ -0,0 +1,238 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/ping/ping.vcxproj b/samples/ping/ping.vcxproj new file mode 100644 index 000000000..9bbaaf812 --- /dev/null +++ b/samples/ping/ping.vcxproj @@ -0,0 +1,189 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + ReleaseDll + Win32 + + + Release + Win32 + + + + {814B40D7-29D3-4B12-B347-E4B632190DF9} + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\lib_acl\include;..\..\lib_protocol\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + ws2_32.lib;wsock32.lib;%(AdditionalDependencies) + $(OutDir)ping.exe + %(AdditionalLibraryDirectories) + true + $(OutDir)ping.pdb + Console + MachineX86 + + + + + ..\..\lib_acl\include;..\..\lib_protocol\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;%(AdditionalDependencies) + $(OutDir)ping.exe + %(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + + + + + Disabled + ..\..\lib_acl\include;..\..\lib_protocol\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_DLL;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + EditAndContinue + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)ping.exe + %(AdditionalLibraryDirectories) + true + $(OutDir)ping.pdb + Console + MachineX86 + + + + + ..\..\lib_acl\include;..\..\lib_protocol\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_DLL;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)ping.exe + %(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + + + + + {b40213c2-507c-4c7f-a6e1-b850c9bdc27b} + false + + + {fe724ef7-3763-4e78-bdf5-bcbc075719fd} + false + + + + + + + + + \ No newline at end of file diff --git a/samples/pipe/ReadMe.txt b/samples/pipe/ReadMe.txt new file mode 100644 index 000000000..3592d8183 --- /dev/null +++ b/samples/pipe/ReadMe.txt @@ -0,0 +1,31 @@ +======================================================================== + 控制台应用程序 : pipe 项目概况 +======================================================================== + +应用程序向导已为您创建了这个 pipe 应用程序。 +此文件包含组成 pipe 应用程序 +的每个文件的内容摘要。 + + +pipe.vcproj + 这是用应用程序向导生成的 VC++ 项目的主项目文件。 + 它包含有关生成此文件的 Visual C++ 版本的信息,以及 + 有关用应用程序向导选择的 + 平台、配置和项目功能的信息。 + +pipe.cpp + 这是主应用程序源文件。 + +///////////////////////////////////////////////////////////////////////////// +其他标准文件: + +StdAfx.h、StdAfx.cpp + 这些文件用于生成名为 pipe.pch + 的预编译头(PCH)文件以及名为 StdAfx.obj 的预编译类型文件。 + +///////////////////////////////////////////////////////////////////////////// +其他注释: + +应用程序向导使用 "TODO:" 注释指示应添加或自定义的源代码部分。 + +///////////////////////////////////////////////////////////////////////////// diff --git a/samples/pipe/pipe.cpp b/samples/pipe/pipe.cpp new file mode 100644 index 000000000..6a8619088 --- /dev/null +++ b/samples/pipe/pipe.cpp @@ -0,0 +1,64 @@ +// pipe.cpp : 定义控制台应用程序的入口点。 +// + +#include "stdafx.h" +#include "lib_acl.h" + +static void test(void) +{ + ACL_FILE_HANDLE fds[2]; + char buf[1024]; + int ret; + + if (acl_pipe(fds) < 0) { + printf("acl_pipe error(%s)\n", acl_last_serror()); + return; + } + + sprintf(buf, "hello client"); + ret = acl_file_write(fds[0], buf, strlen(buf), 0, 0); + if (ret == ACL_VSTREAM_EOF) { + printf("write to client error(%s)\n", acl_last_serror()); + acl_pipe_close(fds); + return; + } + printf(">>>server: write to client ok\n"); + + ret = acl_file_read(fds[1], buf, sizeof(buf), 0, 0); + if (ret == ACL_VSTREAM_EOF) { + printf(">>>client: read from server error(%s)\n", acl_last_serror()); + acl_pipe_close(fds); + return; + } + buf[ret] = 0; + printf(">>>client: read from server ok(%s)\n", buf); + + sprintf(buf, "hello server"); + ret = acl_file_write(fds[1], buf, strlen(buf), 0, 0); + if (ret == ACL_VSTREAM_EOF) { + printf("write to server error(%s)\n", acl_last_serror()); + acl_pipe_close(fds); + return; + } + printf(">>>client: write to server ok\n"); + + ret = acl_file_read(fds[0], buf, sizeof(buf), 0, 0); + if (ret == ACL_VSTREAM_EOF) { + printf(">>>server: read from client error(%s)\n", acl_last_serror()); + acl_pipe_close(fds); + return; + } + printf(">>>server: read from client ok(%s)\n", buf); + + acl_pipe_close(fds); +} + +int _tmain(int argc, _TCHAR* argv[]) +{ + acl_init(); + test(); + getchar(); + acl_end(); + return 0; +} + diff --git a/samples/pipe/pipe.vcproj b/samples/pipe/pipe.vcproj new file mode 100644 index 000000000..62bcfe4ff --- /dev/null +++ b/samples/pipe/pipe.vcproj @@ -0,0 +1,267 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/pipe/pipe.vcxproj b/samples/pipe/pipe.vcxproj new file mode 100644 index 000000000..e292e0f93 --- /dev/null +++ b/samples/pipe/pipe.vcxproj @@ -0,0 +1,189 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + ReleaseDll + Win32 + + + Release + Win32 + + + + {B56DD282-18A6-4A73-9297-F763BFD1F542} + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Use + Level3 + EditAndContinue + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)pipe.exe + true + $(OutDir)pipe.pdb + Console + MachineX86 + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + Use + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;%(AdditionalDependencies) + $(OutDir)pipe.exe + true + Console + true + true + MachineX86 + + + + + Disabled + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Use + Level3 + EditAndContinue + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)pipe.exe + true + $(OutDir)pipe.pdb + Console + MachineX86 + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreadedDLL + Use + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;%(AdditionalDependencies) + $(OutDir)pipe.exe + true + Console + true + true + MachineX86 + + + + + + Create + Create + Create + Create + + + + + + + + + + + {b40213c2-507c-4c7f-a6e1-b850c9bdc27b} + false + + + + + + \ No newline at end of file diff --git a/samples/pipe/pipe.vcxproj.filters b/samples/pipe/pipe.vcxproj.filters new file mode 100644 index 000000000..69740969a --- /dev/null +++ b/samples/pipe/pipe.vcxproj.filters @@ -0,0 +1,33 @@ +锘 + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx + + + + + 婧愭枃浠 + + + 婧愭枃浠 + + + + + 澶存枃浠 + + + + + + \ No newline at end of file diff --git a/samples/pipe/stdafx.cpp b/samples/pipe/stdafx.cpp new file mode 100644 index 000000000..f19f8ac61 --- /dev/null +++ b/samples/pipe/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// pipe.pch 将成为预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + +// TODO: 在 STDAFX.H 中 +//引用任何所需的附加头文件,而不是在此文件中引用 diff --git a/samples/pipe/stdafx.h b/samples/pipe/stdafx.h new file mode 100644 index 000000000..ff452917c --- /dev/null +++ b/samples/pipe/stdafx.h @@ -0,0 +1,11 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是常用但不常更改的项目特定的包含文件 +// + +#pragma once + + +#include +#include + +// TODO: 在此处引用程序要求的附加头文件 diff --git a/samples/process/Makefile b/samples/process/Makefile new file mode 100644 index 000000000..831106f4d --- /dev/null +++ b/samples/process/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = process diff --git a/samples/process/main.c b/samples/process/main.c new file mode 100644 index 000000000..4741379bc --- /dev/null +++ b/samples/process/main.c @@ -0,0 +1,16 @@ +#include "lib_acl.h" +#include + +int main(int argc acl_unused, char *argv[] acl_unused) +{ + const char *ptr = acl_process_path(); + const char *ptr1 = acl_getcwd(); + + printf("current process file's path: %s, getcwd: %s\n", + ptr ? ptr : "unknown", ptr1 ? ptr1 : "unknown"); + +#ifdef ACL_MS_WINDOWS + getchar(); +#endif + return (0); +} diff --git a/samples/process/process.vcproj b/samples/process/process.vcproj new file mode 100644 index 000000000..f6cac657d --- /dev/null +++ b/samples/process/process.vcproj @@ -0,0 +1,234 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/process/process.vcxproj b/samples/process/process.vcxproj new file mode 100644 index 000000000..6d83f5ae3 --- /dev/null +++ b/samples/process/process.vcxproj @@ -0,0 +1,181 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + ReleaseDll + Win32 + + + Release + Win32 + + + + {FF94BA1A-1465-4E6B-9CAF-EC0A3C376E2B} + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)process.exe + true + $(OutDir)process.pdb + Console + MachineX86 + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)process.exe + true + Console + true + true + MachineX86 + + + + + Disabled + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_DLL;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + EditAndContinue + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)process.exe + true + $(OutDir)process.pdb + Console + MachineX86 + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_DLL;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)process.exe + true + Console + true + true + MachineX86 + + + + + {b40213c2-507c-4c7f-a6e1-b850c9bdc27b} + false + + + + + + + + + \ No newline at end of file diff --git a/samples/process/valgrind.sh b/samples/process/valgrind.sh new file mode 100644 index 000000000..c2c1249f3 --- /dev/null +++ b/samples/process/valgrind.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +valgrind --tool=memcheck --leak-check=yes -v ./get_procpath diff --git a/samples/proctl/proctlc.cpp b/samples/proctl/proctlc.cpp new file mode 100644 index 000000000..7ea35be3c --- /dev/null +++ b/samples/proctl/proctlc.cpp @@ -0,0 +1,35 @@ +// proctlc.cpp : 定义控制台应用程序的入口点。 +// +#pragma comment(lib,"ws2_32") +#include "lib_acl.h" + +static void onexit_fn(void *arg acl_unused) +{ +} + +int main(int argc, char *argv[]) +{ + int i; + + acl_socket_init(); + acl_msg_open("debug.txt", "proctlc"); + acl_msg_info(">>> in child progname(%s), argc=%d\r\n", argv[0], argc); + if (argc > 1) + acl_msg_info(">>> in child progname, argv[1]=(%s)\r\n", argv[1]); + acl_proctl_child(argv[0], onexit_fn, NULL); + + for (i = 0; i < argc; i++) { + acl_msg_info(">>>argv[%d]:%s\r\n", i, argv[i]); + } + + i = 0; + while (1) { + acl_msg_info("i = %d\r\n", i++); + if (i == 5) + sleep(1); + else + sleep(1); + } + return (-1); // 返回 -1 是为了让父进程继续启动 +} + diff --git a/samples/proctl/proctlc.vcxproj b/samples/proctl/proctlc.vcxproj new file mode 100644 index 000000000..5404c2a48 --- /dev/null +++ b/samples/proctl/proctlc.vcxproj @@ -0,0 +1,182 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + ReleaseDll + Win32 + + + Release + Win32 + + + + proctlc + {805E87BF-E47B-4D25-8CFC-B61ECF98E84D} + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + $(OutDir)proctlc.exe + %(AdditionalLibraryDirectories) + true + $(OutDir)proctlc.pdb + Console + MachineX86 + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + proctlc.exe + %(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + + + + + Disabled + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_DLL;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + EditAndContinue + + + $(OutDir)proctlc.exe + %(AdditionalLibraryDirectories) + true + $(OutDir)proctlc.pdb + Console + MachineX86 + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_DLL;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + proctlc.exe + %(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + + + + + {b40213c2-507c-4c7f-a6e1-b850c9bdc27b} + false + + + + + + + + + \ No newline at end of file diff --git a/samples/proctl/proctlc_vc2003.vcproj b/samples/proctl/proctlc_vc2003.vcproj new file mode 100644 index 000000000..5f6ac60c8 --- /dev/null +++ b/samples/proctl/proctlc_vc2003.vcproj @@ -0,0 +1,234 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/proctl/proctld.cpp b/samples/proctl/proctld.cpp new file mode 100644 index 000000000..657c7d65d --- /dev/null +++ b/samples/proctl/proctld.cpp @@ -0,0 +1,113 @@ +// proctld.cpp : 定义控制台应用程序的入口点。 +// +#pragma comment(lib,"ws2_32") +#include "lib_acl.h" +#include + +#ifdef WIN32 +#define snprintf _snprintf +#endif + +static void init(void) +{ +} + +static void usage(const char *progname) +{ + printf("usage: %s -h [help] -d [START|STOP|QUIT|LIST|PROBE] -f filepath -a args\r\n", + progname); + getchar(); +} + +int main(int argc, char *argv[]) +{ + char ch, filepath[256], cmd[256]; + char **child_argv = NULL; + int child_argc = 0, i; + ACL_ARGV *argv_tmp; + + filepath[0] = 0; + cmd[0] = 0; + + init(); + + while ((ch = getopt(argc, argv, "d:f:a:h")) > 0) { + switch(ch) { + case 'd': + ACL_SAFE_STRNCPY(cmd, optarg, sizeof(cmd)); + break; + case 'f': + ACL_SAFE_STRNCPY(filepath, optarg, sizeof(filepath)); + break; + case 'a': + argv_tmp = acl_argv_split(optarg, "|"); + assert(argv_tmp); + child_argc = argv_tmp->argc; + child_argv = (char**) acl_mycalloc(child_argc + 1, sizeof(char*)); + for (i = 0; i < child_argc; i++) { + child_argv[i] = acl_mystrdup(argv_tmp->argv[i]); + } + child_argv[i] = NULL; + + acl_argv_free(argv_tmp); + break; + case 'h': + usage(argv[0]); + return (0); + default: + usage(argv[0]); + return (0); + } + } + + if (strcasecmp(cmd, "STOP") == 0) { + if (filepath[0]) + acl_proctl_stop_one(argv[0], filepath, child_argc, child_argv); + else + acl_proctl_stop_all(argv[0]); + } else if (strcasecmp(cmd, "START") == 0) { + if (filepath[0] == 0) { + usage(argv[0]); + return (0); + } + acl_proctl_start_one(argv[0], filepath, child_argc, child_argv); + } else if (strcasecmp(cmd, "QUIT") == 0) { + acl_proctl_quit(argv[0]); + } else if (strcasecmp(cmd, "LIST") == 0) { + acl_proctl_list(argv[0]); + } else if (strcasecmp(cmd, "PROBE") == 0) { + if (filepath[0] == 0) { + usage(argv[0]); + return (0); + } + acl_proctl_probe(argv[0], filepath); + } else { + char buf[MAX_PATH], logfile[MAX_PATH], *ptr; + + acl_proctl_daemon_path(buf, sizeof(buf)); + ptr = strrchr(argv[0], '\\'); + if (ptr == NULL) + ptr = strrchr(argv[0], '/'); + + if (ptr == NULL) + ptr = argv[0]; + else + ptr++; + + snprintf(logfile, sizeof(logfile), "%s/%s.log", buf, ptr); + acl_msg_open(logfile, "daemon"); + acl_debug_init("all:2"); + + /* 以服务器模式启动监控进程 */ + acl_proctl_deamon_init(argv[0]); + acl_proctl_daemon_loop(); + } + + if (child_argv) { + for (i = 0; child_argv[i] != NULL; i++) { + acl_myfree(child_argv[i]); + } + acl_myfree(child_argv); + } + return (0); +} diff --git a/samples/proctl/proctld.vcxproj b/samples/proctl/proctld.vcxproj new file mode 100644 index 000000000..c40abd9a6 --- /dev/null +++ b/samples/proctl/proctld.vcxproj @@ -0,0 +1,185 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + ReleaseDll + Win32 + + + Release + Win32 + + + + proctld + {CA5D3E66-9012-4387-AC99-C4B7810A8661} + proctld + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + $(OutDir)proctld.exe + %(AdditionalLibraryDirectories) + libcd;%(IgnoreSpecificDefaultLibraries) + true + $(OutDir)proctld.pdb + Console + MachineX86 + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + proctld.exe + %(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + + + + + Disabled + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + EditAndContinue + + + $(OutDir)proctld.exe + %(AdditionalLibraryDirectories) + libcd;%(IgnoreSpecificDefaultLibraries) + true + $(OutDir)proctld.pdb + Console + MachineX86 + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + proctld.exe + %(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + + + + + {b40213c2-507c-4c7f-a6e1-b850c9bdc27b} + false + + + + + + + + + \ No newline at end of file diff --git a/samples/proctl/proctld_vc2003.vcproj b/samples/proctl/proctld_vc2003.vcproj new file mode 100644 index 000000000..d0492214c --- /dev/null +++ b/samples/proctl/proctld_vc2003.vcproj @@ -0,0 +1,237 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/resolve/Makefile b/samples/resolve/Makefile new file mode 100644 index 000000000..b47bd17ac --- /dev/null +++ b/samples/resolve/Makefile @@ -0,0 +1,2 @@ +include ../Makefile_cpp.in +PROG = resolve diff --git a/samples/resolve/main.cpp b/samples/resolve/main.cpp new file mode 100644 index 000000000..afe4c407f --- /dev/null +++ b/samples/resolve/main.cpp @@ -0,0 +1,129 @@ +#include "lib_acl.h" +#include +#include + +static void test(const char *name, int use_acl) +{ + ACL_DNS_DB *res; + ACL_HOSTNAME *h_host; +#ifndef MACOSX + struct hostent h_buf; + int errnum = 0; + char buf[4096]; +#endif + struct hostent *h_addrp = NULL; + char **pptr; + int n; + ACL_ITER iter; + struct in_addr addr; + + if (use_acl) { + res = acl_gethostbyname(name, NULL); + if (res == NULL) { + printf("acl_gethostbyname %s error\n", name); + return; + } + } +#ifndef MACOSX + else { + res = acl_netdb_new(name); + n = gethostbyname_r(name, &h_buf, buf, sizeof(buf), &h_addrp, &errnum); + if (n) { + printf("gethostbyname %s error\n", name); + acl_netdb_free(res); + return; + } + + for (pptr = h_addrp->h_addr_list; *pptr != NULL; pptr++) { + h_host = (ACL_HOSTNAME*) acl_mycalloc(1, sizeof(ACL_HOSTNAME)); + + memset(&h_host->saddr, 0, sizeof(h_host->saddr)); + n = (int) sizeof(h_host->saddr.sin_addr) > h_addrp->h_length + ? h_addrp->h_length : (int) sizeof(h_host->saddr.sin_addr); + memcpy(&h_host->saddr.sin_addr, *pptr, n); + acl_inet_ntoa(h_host->saddr.sin_addr, h_host->ip, sizeof(h_host->ip)); + + (void) acl_array_append(res->h_db, h_host); + + res->size++; + } + } +#endif + + printf("gethostbyname name: %s\n", name); + acl_foreach(iter, res) { + const ACL_HOST_INFO *info; + + info = (const ACL_HOST_INFO*) iter.data; + printf("\tip=%s; port=%d\n", info->ip, info->hport); + } + acl_netdb_free(res); + + res = acl_netdb_new(name); + memset(&addr, 0, sizeof(addr)); + addr.s_addr = inet_addr(name); + + printf("gethostbyaddr addr: %s\n", name); + + h_addrp = gethostbyaddr(&addr, sizeof(addr), AF_INET); + if (h_addrp) { + printf("h_name: %s\n", h_addrp->h_name); + for (pptr = h_addrp->h_addr_list; *pptr != NULL; pptr++) { + h_host = (ACL_HOSTNAME*) acl_mycalloc(1, sizeof(ACL_HOSTNAME)); + + memset(&h_host->saddr, 0, sizeof(h_host->saddr)); + n = (int) sizeof(h_host->saddr.sin_addr) > h_addrp->h_length + ? h_addrp->h_length : (int) sizeof(h_host->saddr.sin_addr); + memcpy(&h_host->saddr.sin_addr, *pptr, n); + acl_inet_ntoa(h_host->saddr.sin_addr, h_host->ip, sizeof(h_host->ip)); + + (void) acl_array_append(res->h_db, h_host); + + res->size++; + } + } else { + printf("error: %s\n", acl_last_serror()); + } + + acl_foreach(iter, res) { + const ACL_HOST_INFO *info; + + info = (const ACL_HOST_INFO*) iter.data; + printf("\tip=%s; port=%d\n", info->ip, info->hport); + } + acl_netdb_free(res); +} + +static void usage(const char *procname) +{ + printf("usage: %s -h[help] -a addr -r[use_acl_resolve]\n", procname); +} + +int main(int argc, char *argv[]) +{ + int ch, use_acl = 0; + char addr[256]; + + addr[0] = 0; + while ((ch = getopt(argc, argv, "ha:r")) > 0) { + switch (ch) { + case 'h': + usage(argv[0]); + return (0); + case 'a': + snprintf(addr, sizeof(addr), "%s", optarg); + break; + case 'r': + use_acl = 1; + break; + default: + break; + } + } + + if (addr[0]) + test(addr, use_acl); + else + usage(argv[0]); + return (0); +} diff --git a/samples/samples_vc2003.sln b/samples/samples_vc2003.sln new file mode 100644 index 000000000..94aaa0f50 --- /dev/null +++ b/samples/samples_vc2003.sln @@ -0,0 +1,617 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dlink", "dlink\dlink_vc2003.vcproj", "{6C3E9644-44A3-486E-827A-8B4381606F29}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fifo", "fifo\fifo_vc2003.vcproj", "{B2566BBC-49F1-42D7-85AC-5E2606535138}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FileDir", "FileDir\FileDir_vc2003.vcproj", "{71F3CDEF-30E4-4F2F-9D3B-139EA3723CE2}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "flock", "flock\flock_vc2003.vcproj", "{0D12EB24-88E6-427C-94E2-26C2CD7B0670}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "http_client", "http_client\http_client_vc2003.vcproj", "{9BCB6DE9-73D2-484A-B946-0BD5FDDF8CCB}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + {FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "memdb", "memdb\memdb_vc2003.vcproj", "{BA50914C-5890-4A29-85C0-F0C779552597}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mempool", "mempool\mempool_vc2003.vcproj", "{6333EAB7-D42C-42D3-8F10-8035C225227F}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "thread", "thread\thread_vc2003.vcproj", "{DF044F15-C15D-4C69-9024-21235BC3C7E9}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "urlcode", "urlcode\urlcode_vc2003.vcproj", "{7CD8C407-12E9-4DBA-B281-A1FC0E1D70C4}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vstream", "vstream\vstream_vc2003.vcproj", "{F0DAE963-53F7-4836-813D-7825BE6F8BDF}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vstring", "vstring\vstring_vc2003.vcproj", "{AC9CA58D-28FB-40B7-85C8-BA7674DBD934}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "thread_pool", "thread_pool\thread_pool_vc2003.vcproj", "{143D67EE-85E1-4456-AD99-6FDE7B1F1469}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ping", "ping\ping.vcproj", "{814B40D7-29D3-4B12-B347-E4B632190DF9}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + {FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "file", "file\file.vcproj", "{D4F73163-D0FF-4A01-94AE-41EC2D1FD658}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "aio_server", "aio\server\server.vcproj", "{60731E38-81E7-4FE8-8634-8DF706CE9971}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "aio_client", "aio\client\client.vcproj", "{FE9DEE6B-3256-4362-9014-B5FC5F04844E}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "process", "process\process.vcproj", "{FF94BA1A-1465-4E6B-9CAF-EC0A3C376E2B}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "iterator", "iterator\iterator.vcproj", "{84DE3D12-2BF6-46C1-BE20-9F9F6E7708B2}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zdb", "zdb\zdb.vcproj", "{640ABB35-FBD3-4D34-A382-9ED8CF3FCE34}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "token_tree", "token_tree\token_tree.vcproj", "{B44E3C63-C3A5-4306-A6FF-072818D62EEF}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "code_map", "code_map\code_map.vcproj", "{A188A73A-4014-442F-8188-58CA59232CA8}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "connect", "connect\connect.vcproj", "{6254E8C1-6849-4108-8DBE-18152A642F46}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vstream_popen", "vstream_popen\vstream_popen.vcproj", "{3C9E5E69-3082-4C0E-AAEC-BCFC9407AA17}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pipe", "pipe\pipe.vcproj", "{B56DD282-18A6-4A73-9297-F763BFD1F542}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dns_req", "dns_req\dns_req.vcproj", "{E3234C5B-84F4-4332-99D3-EBC367C523EA}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cache2", "cache2\cache2.vcproj", "{304F46FC-629C-462A-AFA7-454CC1A8EA39}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "http_aio", "http_aio\http_aio.vcproj", "{0ED6281F-980A-47F7-B30B-0425EEB4C2A9}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + {FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "server1", "server1\server1.vcproj", "{59CBAC72-7596-44E6-85DF-FDA362C45CE0}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xml", "xml\xml.vcproj", "{BA8A20D5-958E-4DEC-9151-27049C2EEEB2}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "demo", "demo\demo.vcproj", "{1AC6401F-21D8-4D44-9CDD-BDD45470CBFB}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "winaio", "winaio\winaio.vcproj", "{4B58485B-D846-4485-9C5E-7F2304D71701}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "html_code", "html_code\html_code.vcproj", "{7D44F644-AC16-4A58-A485-3BAD65CE377C}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "json", "json\json.vcproj", "{8021ECD9-04CB-463B-B287-1FB0F5486D91}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "http_get_url1", "http\url_get1\http_get_url1.vcproj", "{74114B21-D661-4AC4-B7BC-7D79C90DD4CE}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + {FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "http_get_url2", "http\url_get2\http_get_url2.vcproj", "{6604B655-BE74-4461-9E2C-FDCBD1B79A48}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + {FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "http_get_url3", "http\url_get3\http_get_url3.vcproj", "{2ADD53F3-3048-4D7B-8443-F0982FB17D3F}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + {FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "proctlc", "proctl\proctlc_vc2003.vcproj", "{805E87BF-E47B-4D25-8CFC-B61ECF98E84D}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "proctld", "proctl\proctld_vc2003.vcproj", "{CA5D3E66-9012-4387-AC99-C4B7810A8661}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tls_client", "tls\client\tls_client.vcproj", "{1759A405-8572-4A70-8C14-16E7FCF4D899}" + ProjectSection(ProjectDependencies) = postProject + {389FDE47-7F16-4DD4-B37A-27918BE745B6} = {389FDE47-7F16-4DD4-B37A-27918BE745B6} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tls_server", "tls\server\tls_server.vcproj", "{B392992C-340B-417B-81E7-ACB265602DF7}" + ProjectSection(ProjectDependencies) = postProject + {389FDE47-7F16-4DD4-B37A-27918BE745B6} = {389FDE47-7F16-4DD4-B37A-27918BE745B6} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lib_acl", "..\lib_acl\lib_acl_vc2003.vcproj", "{B40213C2-507C-4C7F-A6E1-B850C9BDC27B}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lib_protocol", "..\lib_protocol\lib_protocol_vc2003.vcproj", "{FE724EF7-3763-4E78-BDF5-BCBC075719FD}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lib_dict", "..\lib_dict\lib_dict.vcproj", "{9E6E9FE9-EAAC-44BA-B463-70DE0233822E}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lib_tls", "..\lib_tls\lib_tls.vcproj", "{389FDE47-7F16-4DD4-B37A-27918BE745B6}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "smtp_client", "smtp_client\smtp_client.vcproj", "{F704167E-5722-4D6D-9BE7-8EFA02FB8F2D}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + {FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unit_test", "..\unit_test\unit_test.vcproj", "{11BB762F-1998-4F62-81F0-7E0600029F70}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + DebugDll = DebugDll + Release = Release + ReleaseDll = ReleaseDll + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {6C3E9644-44A3-486E-827A-8B4381606F29}.Debug.ActiveCfg = Debug|Win32 + {6C3E9644-44A3-486E-827A-8B4381606F29}.Debug.Build.0 = Debug|Win32 + {6C3E9644-44A3-486E-827A-8B4381606F29}.DebugDll.ActiveCfg = DebugDll|Win32 + {6C3E9644-44A3-486E-827A-8B4381606F29}.DebugDll.Build.0 = DebugDll|Win32 + {6C3E9644-44A3-486E-827A-8B4381606F29}.Release.ActiveCfg = Release|Win32 + {6C3E9644-44A3-486E-827A-8B4381606F29}.Release.Build.0 = Release|Win32 + {6C3E9644-44A3-486E-827A-8B4381606F29}.ReleaseDll.ActiveCfg = ReleaseDll|Win32 + {6C3E9644-44A3-486E-827A-8B4381606F29}.ReleaseDll.Build.0 = ReleaseDll|Win32 + {B2566BBC-49F1-42D7-85AC-5E2606535138}.Debug.ActiveCfg = Debug|Win32 + {B2566BBC-49F1-42D7-85AC-5E2606535138}.Debug.Build.0 = Debug|Win32 + {B2566BBC-49F1-42D7-85AC-5E2606535138}.DebugDll.ActiveCfg = DebugDll|Win32 + {B2566BBC-49F1-42D7-85AC-5E2606535138}.DebugDll.Build.0 = DebugDll|Win32 + {B2566BBC-49F1-42D7-85AC-5E2606535138}.Release.ActiveCfg = Release|Win32 + {B2566BBC-49F1-42D7-85AC-5E2606535138}.Release.Build.0 = Release|Win32 + {B2566BBC-49F1-42D7-85AC-5E2606535138}.ReleaseDll.ActiveCfg = ReleaseDll|Win32 + {B2566BBC-49F1-42D7-85AC-5E2606535138}.ReleaseDll.Build.0 = ReleaseDll|Win32 + {71F3CDEF-30E4-4F2F-9D3B-139EA3723CE2}.Debug.ActiveCfg = Debug|Win32 + {71F3CDEF-30E4-4F2F-9D3B-139EA3723CE2}.Debug.Build.0 = Debug|Win32 + {71F3CDEF-30E4-4F2F-9D3B-139EA3723CE2}.DebugDll.ActiveCfg = DebugDll|Win32 + {71F3CDEF-30E4-4F2F-9D3B-139EA3723CE2}.DebugDll.Build.0 = DebugDll|Win32 + {71F3CDEF-30E4-4F2F-9D3B-139EA3723CE2}.Release.ActiveCfg = Release|Win32 + {71F3CDEF-30E4-4F2F-9D3B-139EA3723CE2}.Release.Build.0 = Release|Win32 + {71F3CDEF-30E4-4F2F-9D3B-139EA3723CE2}.ReleaseDll.ActiveCfg = ReleaseDll|Win32 + {71F3CDEF-30E4-4F2F-9D3B-139EA3723CE2}.ReleaseDll.Build.0 = ReleaseDll|Win32 + {0D12EB24-88E6-427C-94E2-26C2CD7B0670}.Debug.ActiveCfg = Debug|Win32 + {0D12EB24-88E6-427C-94E2-26C2CD7B0670}.Debug.Build.0 = Debug|Win32 + {0D12EB24-88E6-427C-94E2-26C2CD7B0670}.DebugDll.ActiveCfg = DebugDll|Win32 + {0D12EB24-88E6-427C-94E2-26C2CD7B0670}.DebugDll.Build.0 = DebugDll|Win32 + {0D12EB24-88E6-427C-94E2-26C2CD7B0670}.Release.ActiveCfg = Release|Win32 + {0D12EB24-88E6-427C-94E2-26C2CD7B0670}.Release.Build.0 = Release|Win32 + {0D12EB24-88E6-427C-94E2-26C2CD7B0670}.ReleaseDll.ActiveCfg = ReleaseDll|Win32 + {0D12EB24-88E6-427C-94E2-26C2CD7B0670}.ReleaseDll.Build.0 = ReleaseDll|Win32 + {9BCB6DE9-73D2-484A-B946-0BD5FDDF8CCB}.Debug.ActiveCfg = Debug|Win32 + {9BCB6DE9-73D2-484A-B946-0BD5FDDF8CCB}.Debug.Build.0 = Debug|Win32 + {9BCB6DE9-73D2-484A-B946-0BD5FDDF8CCB}.DebugDll.ActiveCfg = DebugDll|Win32 + {9BCB6DE9-73D2-484A-B946-0BD5FDDF8CCB}.DebugDll.Build.0 = DebugDll|Win32 + {9BCB6DE9-73D2-484A-B946-0BD5FDDF8CCB}.Release.ActiveCfg = Release|Win32 + {9BCB6DE9-73D2-484A-B946-0BD5FDDF8CCB}.Release.Build.0 = Release|Win32 + {9BCB6DE9-73D2-484A-B946-0BD5FDDF8CCB}.ReleaseDll.ActiveCfg = ReleaseDll|Win32 + {9BCB6DE9-73D2-484A-B946-0BD5FDDF8CCB}.ReleaseDll.Build.0 = ReleaseDll|Win32 + {BA50914C-5890-4A29-85C0-F0C779552597}.Debug.ActiveCfg = Debug|Win32 + {BA50914C-5890-4A29-85C0-F0C779552597}.Debug.Build.0 = Debug|Win32 + {BA50914C-5890-4A29-85C0-F0C779552597}.DebugDll.ActiveCfg = DebugDll|Win32 + {BA50914C-5890-4A29-85C0-F0C779552597}.DebugDll.Build.0 = DebugDll|Win32 + {BA50914C-5890-4A29-85C0-F0C779552597}.Release.ActiveCfg = Release|Win32 + {BA50914C-5890-4A29-85C0-F0C779552597}.Release.Build.0 = Release|Win32 + {BA50914C-5890-4A29-85C0-F0C779552597}.ReleaseDll.ActiveCfg = ReleaseDll|Win32 + {BA50914C-5890-4A29-85C0-F0C779552597}.ReleaseDll.Build.0 = ReleaseDll|Win32 + {6333EAB7-D42C-42D3-8F10-8035C225227F}.Debug.ActiveCfg = Debug|Win32 + {6333EAB7-D42C-42D3-8F10-8035C225227F}.Debug.Build.0 = Debug|Win32 + {6333EAB7-D42C-42D3-8F10-8035C225227F}.DebugDll.ActiveCfg = DebugDll|Win32 + {6333EAB7-D42C-42D3-8F10-8035C225227F}.DebugDll.Build.0 = DebugDll|Win32 + {6333EAB7-D42C-42D3-8F10-8035C225227F}.Release.ActiveCfg = Release|Win32 + {6333EAB7-D42C-42D3-8F10-8035C225227F}.Release.Build.0 = Release|Win32 + {6333EAB7-D42C-42D3-8F10-8035C225227F}.ReleaseDll.ActiveCfg = ReleaseDll|Win32 + {6333EAB7-D42C-42D3-8F10-8035C225227F}.ReleaseDll.Build.0 = ReleaseDll|Win32 + {DF044F15-C15D-4C69-9024-21235BC3C7E9}.Debug.ActiveCfg = Debug|Win32 + {DF044F15-C15D-4C69-9024-21235BC3C7E9}.Debug.Build.0 = Debug|Win32 + {DF044F15-C15D-4C69-9024-21235BC3C7E9}.DebugDll.ActiveCfg = DebugDll|Win32 + {DF044F15-C15D-4C69-9024-21235BC3C7E9}.DebugDll.Build.0 = DebugDll|Win32 + {DF044F15-C15D-4C69-9024-21235BC3C7E9}.Release.ActiveCfg = Release|Win32 + {DF044F15-C15D-4C69-9024-21235BC3C7E9}.Release.Build.0 = Release|Win32 + {DF044F15-C15D-4C69-9024-21235BC3C7E9}.ReleaseDll.ActiveCfg = ReleaseDll|Win32 + {DF044F15-C15D-4C69-9024-21235BC3C7E9}.ReleaseDll.Build.0 = ReleaseDll|Win32 + {7CD8C407-12E9-4DBA-B281-A1FC0E1D70C4}.Debug.ActiveCfg = Debug|Win32 + {7CD8C407-12E9-4DBA-B281-A1FC0E1D70C4}.Debug.Build.0 = Debug|Win32 + {7CD8C407-12E9-4DBA-B281-A1FC0E1D70C4}.DebugDll.ActiveCfg = DebugDll|Win32 + {7CD8C407-12E9-4DBA-B281-A1FC0E1D70C4}.DebugDll.Build.0 = DebugDll|Win32 + {7CD8C407-12E9-4DBA-B281-A1FC0E1D70C4}.Release.ActiveCfg = Release|Win32 + {7CD8C407-12E9-4DBA-B281-A1FC0E1D70C4}.Release.Build.0 = Release|Win32 + {7CD8C407-12E9-4DBA-B281-A1FC0E1D70C4}.ReleaseDll.ActiveCfg = ReleaseDll|Win32 + {7CD8C407-12E9-4DBA-B281-A1FC0E1D70C4}.ReleaseDll.Build.0 = ReleaseDll|Win32 + {F0DAE963-53F7-4836-813D-7825BE6F8BDF}.Debug.ActiveCfg = Debug|Win32 + {F0DAE963-53F7-4836-813D-7825BE6F8BDF}.Debug.Build.0 = Debug|Win32 + {F0DAE963-53F7-4836-813D-7825BE6F8BDF}.DebugDll.ActiveCfg = DebugDll|Win32 + {F0DAE963-53F7-4836-813D-7825BE6F8BDF}.DebugDll.Build.0 = DebugDll|Win32 + {F0DAE963-53F7-4836-813D-7825BE6F8BDF}.Release.ActiveCfg = Release|Win32 + {F0DAE963-53F7-4836-813D-7825BE6F8BDF}.Release.Build.0 = Release|Win32 + {F0DAE963-53F7-4836-813D-7825BE6F8BDF}.ReleaseDll.ActiveCfg = ReleaseDll|Win32 + {F0DAE963-53F7-4836-813D-7825BE6F8BDF}.ReleaseDll.Build.0 = ReleaseDll|Win32 + {AC9CA58D-28FB-40B7-85C8-BA7674DBD934}.Debug.ActiveCfg = Debug|Win32 + {AC9CA58D-28FB-40B7-85C8-BA7674DBD934}.Debug.Build.0 = Debug|Win32 + {AC9CA58D-28FB-40B7-85C8-BA7674DBD934}.DebugDll.ActiveCfg = DebugDll|Win32 + {AC9CA58D-28FB-40B7-85C8-BA7674DBD934}.DebugDll.Build.0 = DebugDll|Win32 + {AC9CA58D-28FB-40B7-85C8-BA7674DBD934}.Release.ActiveCfg = Release|Win32 + {AC9CA58D-28FB-40B7-85C8-BA7674DBD934}.Release.Build.0 = Release|Win32 + {AC9CA58D-28FB-40B7-85C8-BA7674DBD934}.ReleaseDll.ActiveCfg = ReleaseDll|Win32 + {AC9CA58D-28FB-40B7-85C8-BA7674DBD934}.ReleaseDll.Build.0 = ReleaseDll|Win32 + {143D67EE-85E1-4456-AD99-6FDE7B1F1469}.Debug.ActiveCfg = Debug|Win32 + {143D67EE-85E1-4456-AD99-6FDE7B1F1469}.Debug.Build.0 = Debug|Win32 + {143D67EE-85E1-4456-AD99-6FDE7B1F1469}.DebugDll.ActiveCfg = DebugDll|Win32 + {143D67EE-85E1-4456-AD99-6FDE7B1F1469}.DebugDll.Build.0 = DebugDll|Win32 + {143D67EE-85E1-4456-AD99-6FDE7B1F1469}.Release.ActiveCfg = Release|Win32 + {143D67EE-85E1-4456-AD99-6FDE7B1F1469}.Release.Build.0 = Release|Win32 + {143D67EE-85E1-4456-AD99-6FDE7B1F1469}.ReleaseDll.ActiveCfg = ReleaseDll|Win32 + {143D67EE-85E1-4456-AD99-6FDE7B1F1469}.ReleaseDll.Build.0 = ReleaseDll|Win32 + {814B40D7-29D3-4B12-B347-E4B632190DF9}.Debug.ActiveCfg = Debug|Win32 + {814B40D7-29D3-4B12-B347-E4B632190DF9}.Debug.Build.0 = Debug|Win32 + {814B40D7-29D3-4B12-B347-E4B632190DF9}.DebugDll.ActiveCfg = DebugDll|Win32 + {814B40D7-29D3-4B12-B347-E4B632190DF9}.DebugDll.Build.0 = DebugDll|Win32 + {814B40D7-29D3-4B12-B347-E4B632190DF9}.Release.ActiveCfg = Release|Win32 + {814B40D7-29D3-4B12-B347-E4B632190DF9}.Release.Build.0 = Release|Win32 + {814B40D7-29D3-4B12-B347-E4B632190DF9}.ReleaseDll.ActiveCfg = ReleaseDll|Win32 + {814B40D7-29D3-4B12-B347-E4B632190DF9}.ReleaseDll.Build.0 = ReleaseDll|Win32 + {D4F73163-D0FF-4A01-94AE-41EC2D1FD658}.Debug.ActiveCfg = Debug|Win32 + {D4F73163-D0FF-4A01-94AE-41EC2D1FD658}.Debug.Build.0 = Debug|Win32 + {D4F73163-D0FF-4A01-94AE-41EC2D1FD658}.DebugDll.ActiveCfg = DebugDll|Win32 + {D4F73163-D0FF-4A01-94AE-41EC2D1FD658}.DebugDll.Build.0 = DebugDll|Win32 + {D4F73163-D0FF-4A01-94AE-41EC2D1FD658}.Release.ActiveCfg = Release|Win32 + {D4F73163-D0FF-4A01-94AE-41EC2D1FD658}.Release.Build.0 = Release|Win32 + {D4F73163-D0FF-4A01-94AE-41EC2D1FD658}.ReleaseDll.ActiveCfg = ReleaseDll|Win32 + {D4F73163-D0FF-4A01-94AE-41EC2D1FD658}.ReleaseDll.Build.0 = ReleaseDll|Win32 + {60731E38-81E7-4FE8-8634-8DF706CE9971}.Debug.ActiveCfg = Debug|Win32 + {60731E38-81E7-4FE8-8634-8DF706CE9971}.Debug.Build.0 = Debug|Win32 + {60731E38-81E7-4FE8-8634-8DF706CE9971}.DebugDll.ActiveCfg = DebugDll|Win32 + {60731E38-81E7-4FE8-8634-8DF706CE9971}.DebugDll.Build.0 = DebugDll|Win32 + {60731E38-81E7-4FE8-8634-8DF706CE9971}.Release.ActiveCfg = Release|Win32 + {60731E38-81E7-4FE8-8634-8DF706CE9971}.Release.Build.0 = Release|Win32 + {60731E38-81E7-4FE8-8634-8DF706CE9971}.ReleaseDll.ActiveCfg = ReleaseDll|Win32 + {60731E38-81E7-4FE8-8634-8DF706CE9971}.ReleaseDll.Build.0 = ReleaseDll|Win32 + {FE9DEE6B-3256-4362-9014-B5FC5F04844E}.Debug.ActiveCfg = Debug|Win32 + {FE9DEE6B-3256-4362-9014-B5FC5F04844E}.Debug.Build.0 = Debug|Win32 + {FE9DEE6B-3256-4362-9014-B5FC5F04844E}.DebugDll.ActiveCfg = DebugDll|Win32 + {FE9DEE6B-3256-4362-9014-B5FC5F04844E}.DebugDll.Build.0 = DebugDll|Win32 + {FE9DEE6B-3256-4362-9014-B5FC5F04844E}.Release.ActiveCfg = Release|Win32 + {FE9DEE6B-3256-4362-9014-B5FC5F04844E}.Release.Build.0 = Release|Win32 + {FE9DEE6B-3256-4362-9014-B5FC5F04844E}.ReleaseDll.ActiveCfg = ReleaseDll|Win32 + {FE9DEE6B-3256-4362-9014-B5FC5F04844E}.ReleaseDll.Build.0 = ReleaseDll|Win32 + {FF94BA1A-1465-4E6B-9CAF-EC0A3C376E2B}.Debug.ActiveCfg = Debug|Win32 + {FF94BA1A-1465-4E6B-9CAF-EC0A3C376E2B}.Debug.Build.0 = Debug|Win32 + {FF94BA1A-1465-4E6B-9CAF-EC0A3C376E2B}.DebugDll.ActiveCfg = DebugDll|Win32 + {FF94BA1A-1465-4E6B-9CAF-EC0A3C376E2B}.DebugDll.Build.0 = DebugDll|Win32 + {FF94BA1A-1465-4E6B-9CAF-EC0A3C376E2B}.Release.ActiveCfg = Release|Win32 + {FF94BA1A-1465-4E6B-9CAF-EC0A3C376E2B}.Release.Build.0 = Release|Win32 + {FF94BA1A-1465-4E6B-9CAF-EC0A3C376E2B}.ReleaseDll.ActiveCfg = ReleaseDll|Win32 + {FF94BA1A-1465-4E6B-9CAF-EC0A3C376E2B}.ReleaseDll.Build.0 = ReleaseDll|Win32 + {84DE3D12-2BF6-46C1-BE20-9F9F6E7708B2}.Debug.ActiveCfg = Debug|Win32 + {84DE3D12-2BF6-46C1-BE20-9F9F6E7708B2}.Debug.Build.0 = Debug|Win32 + {84DE3D12-2BF6-46C1-BE20-9F9F6E7708B2}.DebugDll.ActiveCfg = DebugDll|Win32 + {84DE3D12-2BF6-46C1-BE20-9F9F6E7708B2}.DebugDll.Build.0 = DebugDll|Win32 + {84DE3D12-2BF6-46C1-BE20-9F9F6E7708B2}.Release.ActiveCfg = Release|Win32 + {84DE3D12-2BF6-46C1-BE20-9F9F6E7708B2}.Release.Build.0 = Release|Win32 + {84DE3D12-2BF6-46C1-BE20-9F9F6E7708B2}.ReleaseDll.ActiveCfg = ReleaseDll|Win32 + {84DE3D12-2BF6-46C1-BE20-9F9F6E7708B2}.ReleaseDll.Build.0 = ReleaseDll|Win32 + {640ABB35-FBD3-4D34-A382-9ED8CF3FCE34}.Debug.ActiveCfg = Debug|Win32 + {640ABB35-FBD3-4D34-A382-9ED8CF3FCE34}.Debug.Build.0 = Debug|Win32 + {640ABB35-FBD3-4D34-A382-9ED8CF3FCE34}.DebugDll.ActiveCfg = DebugDll|Win32 + {640ABB35-FBD3-4D34-A382-9ED8CF3FCE34}.DebugDll.Build.0 = DebugDll|Win32 + {640ABB35-FBD3-4D34-A382-9ED8CF3FCE34}.Release.ActiveCfg = Release|Win32 + {640ABB35-FBD3-4D34-A382-9ED8CF3FCE34}.Release.Build.0 = Release|Win32 + {640ABB35-FBD3-4D34-A382-9ED8CF3FCE34}.ReleaseDll.ActiveCfg = ReleaseDll|Win32 + {640ABB35-FBD3-4D34-A382-9ED8CF3FCE34}.ReleaseDll.Build.0 = ReleaseDll|Win32 + {B44E3C63-C3A5-4306-A6FF-072818D62EEF}.Debug.ActiveCfg = Debug|Win32 + {B44E3C63-C3A5-4306-A6FF-072818D62EEF}.Debug.Build.0 = Debug|Win32 + {B44E3C63-C3A5-4306-A6FF-072818D62EEF}.DebugDll.ActiveCfg = DebugDll|Win32 + {B44E3C63-C3A5-4306-A6FF-072818D62EEF}.DebugDll.Build.0 = DebugDll|Win32 + {B44E3C63-C3A5-4306-A6FF-072818D62EEF}.Release.ActiveCfg = Release|Win32 + {B44E3C63-C3A5-4306-A6FF-072818D62EEF}.Release.Build.0 = Release|Win32 + {B44E3C63-C3A5-4306-A6FF-072818D62EEF}.ReleaseDll.ActiveCfg = ReleaseDll|Win32 + {B44E3C63-C3A5-4306-A6FF-072818D62EEF}.ReleaseDll.Build.0 = ReleaseDll|Win32 + {A188A73A-4014-442F-8188-58CA59232CA8}.Debug.ActiveCfg = Debug|Win32 + {A188A73A-4014-442F-8188-58CA59232CA8}.Debug.Build.0 = Debug|Win32 + {A188A73A-4014-442F-8188-58CA59232CA8}.DebugDll.ActiveCfg = DebugDll|Win32 + {A188A73A-4014-442F-8188-58CA59232CA8}.DebugDll.Build.0 = DebugDll|Win32 + {A188A73A-4014-442F-8188-58CA59232CA8}.Release.ActiveCfg = Release|Win32 + {A188A73A-4014-442F-8188-58CA59232CA8}.Release.Build.0 = Release|Win32 + {A188A73A-4014-442F-8188-58CA59232CA8}.ReleaseDll.ActiveCfg = ReleaseDll|Win32 + {A188A73A-4014-442F-8188-58CA59232CA8}.ReleaseDll.Build.0 = ReleaseDll|Win32 + {6254E8C1-6849-4108-8DBE-18152A642F46}.Debug.ActiveCfg = Debug|Win32 + {6254E8C1-6849-4108-8DBE-18152A642F46}.Debug.Build.0 = Debug|Win32 + {6254E8C1-6849-4108-8DBE-18152A642F46}.DebugDll.ActiveCfg = DebugDll|Win32 + {6254E8C1-6849-4108-8DBE-18152A642F46}.DebugDll.Build.0 = DebugDll|Win32 + {6254E8C1-6849-4108-8DBE-18152A642F46}.Release.ActiveCfg = Release|Win32 + {6254E8C1-6849-4108-8DBE-18152A642F46}.Release.Build.0 = Release|Win32 + {6254E8C1-6849-4108-8DBE-18152A642F46}.ReleaseDll.ActiveCfg = ReleaseDll|Win32 + {6254E8C1-6849-4108-8DBE-18152A642F46}.ReleaseDll.Build.0 = ReleaseDll|Win32 + {3C9E5E69-3082-4C0E-AAEC-BCFC9407AA17}.Debug.ActiveCfg = Debug|Win32 + {3C9E5E69-3082-4C0E-AAEC-BCFC9407AA17}.Debug.Build.0 = Debug|Win32 + {3C9E5E69-3082-4C0E-AAEC-BCFC9407AA17}.DebugDll.ActiveCfg = DebugDll|Win32 + {3C9E5E69-3082-4C0E-AAEC-BCFC9407AA17}.DebugDll.Build.0 = DebugDll|Win32 + {3C9E5E69-3082-4C0E-AAEC-BCFC9407AA17}.Release.ActiveCfg = Release|Win32 + {3C9E5E69-3082-4C0E-AAEC-BCFC9407AA17}.Release.Build.0 = Release|Win32 + {3C9E5E69-3082-4C0E-AAEC-BCFC9407AA17}.ReleaseDll.ActiveCfg = ReleaseDll|Win32 + {3C9E5E69-3082-4C0E-AAEC-BCFC9407AA17}.ReleaseDll.Build.0 = ReleaseDll|Win32 + {B56DD282-18A6-4A73-9297-F763BFD1F542}.Debug.ActiveCfg = Debug|Win32 + {B56DD282-18A6-4A73-9297-F763BFD1F542}.Debug.Build.0 = Debug|Win32 + {B56DD282-18A6-4A73-9297-F763BFD1F542}.DebugDll.ActiveCfg = DebugDll|Win32 + {B56DD282-18A6-4A73-9297-F763BFD1F542}.DebugDll.Build.0 = DebugDll|Win32 + {B56DD282-18A6-4A73-9297-F763BFD1F542}.Release.ActiveCfg = Release|Win32 + {B56DD282-18A6-4A73-9297-F763BFD1F542}.Release.Build.0 = Release|Win32 + {B56DD282-18A6-4A73-9297-F763BFD1F542}.ReleaseDll.ActiveCfg = ReleaseDll|Win32 + {B56DD282-18A6-4A73-9297-F763BFD1F542}.ReleaseDll.Build.0 = ReleaseDll|Win32 + {E3234C5B-84F4-4332-99D3-EBC367C523EA}.Debug.ActiveCfg = Debug|Win32 + {E3234C5B-84F4-4332-99D3-EBC367C523EA}.Debug.Build.0 = Debug|Win32 + {E3234C5B-84F4-4332-99D3-EBC367C523EA}.DebugDll.ActiveCfg = DebugDll|Win32 + {E3234C5B-84F4-4332-99D3-EBC367C523EA}.DebugDll.Build.0 = DebugDll|Win32 + {E3234C5B-84F4-4332-99D3-EBC367C523EA}.Release.ActiveCfg = Release|Win32 + {E3234C5B-84F4-4332-99D3-EBC367C523EA}.Release.Build.0 = Release|Win32 + {E3234C5B-84F4-4332-99D3-EBC367C523EA}.ReleaseDll.ActiveCfg = ReleaseDll|Win32 + {E3234C5B-84F4-4332-99D3-EBC367C523EA}.ReleaseDll.Build.0 = ReleaseDll|Win32 + {304F46FC-629C-462A-AFA7-454CC1A8EA39}.Debug.ActiveCfg = Debug|Win32 + {304F46FC-629C-462A-AFA7-454CC1A8EA39}.Debug.Build.0 = Debug|Win32 + {304F46FC-629C-462A-AFA7-454CC1A8EA39}.DebugDll.ActiveCfg = DebugDll|Win32 + {304F46FC-629C-462A-AFA7-454CC1A8EA39}.DebugDll.Build.0 = DebugDll|Win32 + {304F46FC-629C-462A-AFA7-454CC1A8EA39}.Release.ActiveCfg = Release|Win32 + {304F46FC-629C-462A-AFA7-454CC1A8EA39}.Release.Build.0 = Release|Win32 + {304F46FC-629C-462A-AFA7-454CC1A8EA39}.ReleaseDll.ActiveCfg = ReleaseDll|Win32 + {304F46FC-629C-462A-AFA7-454CC1A8EA39}.ReleaseDll.Build.0 = ReleaseDll|Win32 + {0ED6281F-980A-47F7-B30B-0425EEB4C2A9}.Debug.ActiveCfg = Debug|Win32 + {0ED6281F-980A-47F7-B30B-0425EEB4C2A9}.Debug.Build.0 = Debug|Win32 + {0ED6281F-980A-47F7-B30B-0425EEB4C2A9}.DebugDll.ActiveCfg = DebugDll|Win32 + {0ED6281F-980A-47F7-B30B-0425EEB4C2A9}.DebugDll.Build.0 = DebugDll|Win32 + {0ED6281F-980A-47F7-B30B-0425EEB4C2A9}.Release.ActiveCfg = Release|Win32 + {0ED6281F-980A-47F7-B30B-0425EEB4C2A9}.Release.Build.0 = Release|Win32 + {0ED6281F-980A-47F7-B30B-0425EEB4C2A9}.ReleaseDll.ActiveCfg = ReleaseDll|Win32 + {0ED6281F-980A-47F7-B30B-0425EEB4C2A9}.ReleaseDll.Build.0 = ReleaseDll|Win32 + {59CBAC72-7596-44E6-85DF-FDA362C45CE0}.Debug.ActiveCfg = Debug|Win32 + {59CBAC72-7596-44E6-85DF-FDA362C45CE0}.Debug.Build.0 = Debug|Win32 + {59CBAC72-7596-44E6-85DF-FDA362C45CE0}.DebugDll.ActiveCfg = DebugDll|Win32 + {59CBAC72-7596-44E6-85DF-FDA362C45CE0}.DebugDll.Build.0 = DebugDll|Win32 + {59CBAC72-7596-44E6-85DF-FDA362C45CE0}.Release.ActiveCfg = Release|Win32 + {59CBAC72-7596-44E6-85DF-FDA362C45CE0}.Release.Build.0 = Release|Win32 + {59CBAC72-7596-44E6-85DF-FDA362C45CE0}.ReleaseDll.ActiveCfg = ReleaseDll|Win32 + {59CBAC72-7596-44E6-85DF-FDA362C45CE0}.ReleaseDll.Build.0 = ReleaseDll|Win32 + {BA8A20D5-958E-4DEC-9151-27049C2EEEB2}.Debug.ActiveCfg = Debug|Win32 + {BA8A20D5-958E-4DEC-9151-27049C2EEEB2}.Debug.Build.0 = Debug|Win32 + {BA8A20D5-958E-4DEC-9151-27049C2EEEB2}.DebugDll.ActiveCfg = DebugDll|Win32 + {BA8A20D5-958E-4DEC-9151-27049C2EEEB2}.DebugDll.Build.0 = DebugDll|Win32 + {BA8A20D5-958E-4DEC-9151-27049C2EEEB2}.Release.ActiveCfg = Release|Win32 + {BA8A20D5-958E-4DEC-9151-27049C2EEEB2}.Release.Build.0 = Release|Win32 + {BA8A20D5-958E-4DEC-9151-27049C2EEEB2}.ReleaseDll.ActiveCfg = ReleaseDll|Win32 + {BA8A20D5-958E-4DEC-9151-27049C2EEEB2}.ReleaseDll.Build.0 = ReleaseDll|Win32 + {1AC6401F-21D8-4D44-9CDD-BDD45470CBFB}.Debug.ActiveCfg = Debug|Win32 + {1AC6401F-21D8-4D44-9CDD-BDD45470CBFB}.Debug.Build.0 = Debug|Win32 + {1AC6401F-21D8-4D44-9CDD-BDD45470CBFB}.DebugDll.ActiveCfg = DebugDll|Win32 + {1AC6401F-21D8-4D44-9CDD-BDD45470CBFB}.DebugDll.Build.0 = DebugDll|Win32 + {1AC6401F-21D8-4D44-9CDD-BDD45470CBFB}.Release.ActiveCfg = Release|Win32 + {1AC6401F-21D8-4D44-9CDD-BDD45470CBFB}.Release.Build.0 = Release|Win32 + {1AC6401F-21D8-4D44-9CDD-BDD45470CBFB}.ReleaseDll.ActiveCfg = ReleaseDll|Win32 + {1AC6401F-21D8-4D44-9CDD-BDD45470CBFB}.ReleaseDll.Build.0 = ReleaseDll|Win32 + {4B58485B-D846-4485-9C5E-7F2304D71701}.Debug.ActiveCfg = Debug|Win32 + {4B58485B-D846-4485-9C5E-7F2304D71701}.Debug.Build.0 = Debug|Win32 + {4B58485B-D846-4485-9C5E-7F2304D71701}.DebugDll.ActiveCfg = DebugDll|Win32 + {4B58485B-D846-4485-9C5E-7F2304D71701}.DebugDll.Build.0 = DebugDll|Win32 + {4B58485B-D846-4485-9C5E-7F2304D71701}.Release.ActiveCfg = Release|Win32 + {4B58485B-D846-4485-9C5E-7F2304D71701}.Release.Build.0 = Release|Win32 + {4B58485B-D846-4485-9C5E-7F2304D71701}.ReleaseDll.ActiveCfg = ReleaseDll|Win32 + {4B58485B-D846-4485-9C5E-7F2304D71701}.ReleaseDll.Build.0 = ReleaseDll|Win32 + {7D44F644-AC16-4A58-A485-3BAD65CE377C}.Debug.ActiveCfg = Debug|Win32 + {7D44F644-AC16-4A58-A485-3BAD65CE377C}.Debug.Build.0 = Debug|Win32 + {7D44F644-AC16-4A58-A485-3BAD65CE377C}.DebugDll.ActiveCfg = DebugDll|Win32 + {7D44F644-AC16-4A58-A485-3BAD65CE377C}.DebugDll.Build.0 = DebugDll|Win32 + {7D44F644-AC16-4A58-A485-3BAD65CE377C}.Release.ActiveCfg = Release|Win32 + {7D44F644-AC16-4A58-A485-3BAD65CE377C}.Release.Build.0 = Release|Win32 + {7D44F644-AC16-4A58-A485-3BAD65CE377C}.ReleaseDll.ActiveCfg = ReleaseDll|Win32 + {7D44F644-AC16-4A58-A485-3BAD65CE377C}.ReleaseDll.Build.0 = ReleaseDll|Win32 + {8021ECD9-04CB-463B-B287-1FB0F5486D91}.Debug.ActiveCfg = Debug|Win32 + {8021ECD9-04CB-463B-B287-1FB0F5486D91}.Debug.Build.0 = Debug|Win32 + {8021ECD9-04CB-463B-B287-1FB0F5486D91}.DebugDll.ActiveCfg = DebugDll|Win32 + {8021ECD9-04CB-463B-B287-1FB0F5486D91}.DebugDll.Build.0 = DebugDll|Win32 + {8021ECD9-04CB-463B-B287-1FB0F5486D91}.Release.ActiveCfg = Release|Win32 + {8021ECD9-04CB-463B-B287-1FB0F5486D91}.Release.Build.0 = Release|Win32 + {8021ECD9-04CB-463B-B287-1FB0F5486D91}.ReleaseDll.ActiveCfg = ReleaseDll|Win32 + {8021ECD9-04CB-463B-B287-1FB0F5486D91}.ReleaseDll.Build.0 = ReleaseDll|Win32 + {74114B21-D661-4AC4-B7BC-7D79C90DD4CE}.Debug.ActiveCfg = Debug|Win32 + {74114B21-D661-4AC4-B7BC-7D79C90DD4CE}.Debug.Build.0 = Debug|Win32 + {74114B21-D661-4AC4-B7BC-7D79C90DD4CE}.DebugDll.ActiveCfg = DebugDll|Win32 + {74114B21-D661-4AC4-B7BC-7D79C90DD4CE}.DebugDll.Build.0 = DebugDll|Win32 + {74114B21-D661-4AC4-B7BC-7D79C90DD4CE}.Release.ActiveCfg = Release|Win32 + {74114B21-D661-4AC4-B7BC-7D79C90DD4CE}.Release.Build.0 = Release|Win32 + {74114B21-D661-4AC4-B7BC-7D79C90DD4CE}.ReleaseDll.ActiveCfg = ReleaseDll|Win32 + {74114B21-D661-4AC4-B7BC-7D79C90DD4CE}.ReleaseDll.Build.0 = ReleaseDll|Win32 + {6604B655-BE74-4461-9E2C-FDCBD1B79A48}.Debug.ActiveCfg = Debug|Win32 + {6604B655-BE74-4461-9E2C-FDCBD1B79A48}.Debug.Build.0 = Debug|Win32 + {6604B655-BE74-4461-9E2C-FDCBD1B79A48}.DebugDll.ActiveCfg = DebugDll|Win32 + {6604B655-BE74-4461-9E2C-FDCBD1B79A48}.DebugDll.Build.0 = DebugDll|Win32 + {6604B655-BE74-4461-9E2C-FDCBD1B79A48}.Release.ActiveCfg = Release|Win32 + {6604B655-BE74-4461-9E2C-FDCBD1B79A48}.Release.Build.0 = Release|Win32 + {6604B655-BE74-4461-9E2C-FDCBD1B79A48}.ReleaseDll.ActiveCfg = ReleaseDll|Win32 + {6604B655-BE74-4461-9E2C-FDCBD1B79A48}.ReleaseDll.Build.0 = ReleaseDll|Win32 + {2ADD53F3-3048-4D7B-8443-F0982FB17D3F}.Debug.ActiveCfg = Debug|Win32 + {2ADD53F3-3048-4D7B-8443-F0982FB17D3F}.Debug.Build.0 = Debug|Win32 + {2ADD53F3-3048-4D7B-8443-F0982FB17D3F}.DebugDll.ActiveCfg = DebugDll|Win32 + {2ADD53F3-3048-4D7B-8443-F0982FB17D3F}.DebugDll.Build.0 = DebugDll|Win32 + {2ADD53F3-3048-4D7B-8443-F0982FB17D3F}.Release.ActiveCfg = Release|Win32 + {2ADD53F3-3048-4D7B-8443-F0982FB17D3F}.Release.Build.0 = Release|Win32 + {2ADD53F3-3048-4D7B-8443-F0982FB17D3F}.ReleaseDll.ActiveCfg = ReleaseDll|Win32 + {2ADD53F3-3048-4D7B-8443-F0982FB17D3F}.ReleaseDll.Build.0 = ReleaseDll|Win32 + {805E87BF-E47B-4D25-8CFC-B61ECF98E84D}.Debug.ActiveCfg = Debug|Win32 + {805E87BF-E47B-4D25-8CFC-B61ECF98E84D}.Debug.Build.0 = Debug|Win32 + {805E87BF-E47B-4D25-8CFC-B61ECF98E84D}.DebugDll.ActiveCfg = DebugDll|Win32 + {805E87BF-E47B-4D25-8CFC-B61ECF98E84D}.DebugDll.Build.0 = DebugDll|Win32 + {805E87BF-E47B-4D25-8CFC-B61ECF98E84D}.Release.ActiveCfg = Release|Win32 + {805E87BF-E47B-4D25-8CFC-B61ECF98E84D}.Release.Build.0 = Release|Win32 + {805E87BF-E47B-4D25-8CFC-B61ECF98E84D}.ReleaseDll.ActiveCfg = ReleaseDll|Win32 + {805E87BF-E47B-4D25-8CFC-B61ECF98E84D}.ReleaseDll.Build.0 = ReleaseDll|Win32 + {CA5D3E66-9012-4387-AC99-C4B7810A8661}.Debug.ActiveCfg = Debug|Win32 + {CA5D3E66-9012-4387-AC99-C4B7810A8661}.Debug.Build.0 = Debug|Win32 + {CA5D3E66-9012-4387-AC99-C4B7810A8661}.DebugDll.ActiveCfg = DebugDll|Win32 + {CA5D3E66-9012-4387-AC99-C4B7810A8661}.DebugDll.Build.0 = DebugDll|Win32 + {CA5D3E66-9012-4387-AC99-C4B7810A8661}.Release.ActiveCfg = Release|Win32 + {CA5D3E66-9012-4387-AC99-C4B7810A8661}.Release.Build.0 = Release|Win32 + {CA5D3E66-9012-4387-AC99-C4B7810A8661}.ReleaseDll.ActiveCfg = ReleaseDll|Win32 + {CA5D3E66-9012-4387-AC99-C4B7810A8661}.ReleaseDll.Build.0 = ReleaseDll|Win32 + {1759A405-8572-4A70-8C14-16E7FCF4D899}.Debug.ActiveCfg = Debug|Win32 + {1759A405-8572-4A70-8C14-16E7FCF4D899}.Debug.Build.0 = Debug|Win32 + {1759A405-8572-4A70-8C14-16E7FCF4D899}.DebugDll.ActiveCfg = DebugDll|Win32 + {1759A405-8572-4A70-8C14-16E7FCF4D899}.DebugDll.Build.0 = DebugDll|Win32 + {1759A405-8572-4A70-8C14-16E7FCF4D899}.Release.ActiveCfg = Release|Win32 + {1759A405-8572-4A70-8C14-16E7FCF4D899}.Release.Build.0 = Release|Win32 + {1759A405-8572-4A70-8C14-16E7FCF4D899}.ReleaseDll.ActiveCfg = ReleaseDll|Win32 + {1759A405-8572-4A70-8C14-16E7FCF4D899}.ReleaseDll.Build.0 = ReleaseDll|Win32 + {B392992C-340B-417B-81E7-ACB265602DF7}.Debug.ActiveCfg = Debug|Win32 + {B392992C-340B-417B-81E7-ACB265602DF7}.Debug.Build.0 = Debug|Win32 + {B392992C-340B-417B-81E7-ACB265602DF7}.DebugDll.ActiveCfg = DebugDll|Win32 + {B392992C-340B-417B-81E7-ACB265602DF7}.DebugDll.Build.0 = DebugDll|Win32 + {B392992C-340B-417B-81E7-ACB265602DF7}.Release.ActiveCfg = Release|Win32 + {B392992C-340B-417B-81E7-ACB265602DF7}.Release.Build.0 = Release|Win32 + {B392992C-340B-417B-81E7-ACB265602DF7}.ReleaseDll.ActiveCfg = ReleaseDll|Win32 + {B392992C-340B-417B-81E7-ACB265602DF7}.ReleaseDll.Build.0 = ReleaseDll|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Debug.ActiveCfg = Debug|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Debug.Build.0 = Debug|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.DebugDll.ActiveCfg = DebugDll|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.DebugDll.Build.0 = DebugDll|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Release.ActiveCfg = Release|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Release.Build.0 = Release|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.ReleaseDll.ActiveCfg = ReleaseDll|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.ReleaseDll.Build.0 = ReleaseDll|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Debug.ActiveCfg = Debug|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Debug.Build.0 = Debug|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.DebugDll.ActiveCfg = DebugDll|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.DebugDll.Build.0 = DebugDll|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Release.ActiveCfg = Release|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Release.Build.0 = Release|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.ReleaseDll.ActiveCfg = ReleaseDll|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.ReleaseDll.Build.0 = ReleaseDll|Win32 + {9E6E9FE9-EAAC-44BA-B463-70DE0233822E}.Debug.ActiveCfg = Debug|Win32 + {9E6E9FE9-EAAC-44BA-B463-70DE0233822E}.Debug.Build.0 = Debug|Win32 + {9E6E9FE9-EAAC-44BA-B463-70DE0233822E}.DebugDll.ActiveCfg = DebugDll|Win32 + {9E6E9FE9-EAAC-44BA-B463-70DE0233822E}.DebugDll.Build.0 = DebugDll|Win32 + {9E6E9FE9-EAAC-44BA-B463-70DE0233822E}.Release.ActiveCfg = Release|Win32 + {9E6E9FE9-EAAC-44BA-B463-70DE0233822E}.Release.Build.0 = Release|Win32 + {9E6E9FE9-EAAC-44BA-B463-70DE0233822E}.ReleaseDll.ActiveCfg = ReleaseDll|Win32 + {9E6E9FE9-EAAC-44BA-B463-70DE0233822E}.ReleaseDll.Build.0 = ReleaseDll|Win32 + {389FDE47-7F16-4DD4-B37A-27918BE745B6}.Debug.ActiveCfg = Debug|Win32 + {389FDE47-7F16-4DD4-B37A-27918BE745B6}.Debug.Build.0 = Debug|Win32 + {389FDE47-7F16-4DD4-B37A-27918BE745B6}.DebugDll.ActiveCfg = DebugDll|Win32 + {389FDE47-7F16-4DD4-B37A-27918BE745B6}.DebugDll.Build.0 = DebugDll|Win32 + {389FDE47-7F16-4DD4-B37A-27918BE745B6}.Release.ActiveCfg = Release|Win32 + {389FDE47-7F16-4DD4-B37A-27918BE745B6}.Release.Build.0 = Release|Win32 + {389FDE47-7F16-4DD4-B37A-27918BE745B6}.ReleaseDll.ActiveCfg = ReleaseDll|Win32 + {389FDE47-7F16-4DD4-B37A-27918BE745B6}.ReleaseDll.Build.0 = ReleaseDll|Win32 + {F704167E-5722-4D6D-9BE7-8EFA02FB8F2D}.Debug.ActiveCfg = Debug|Win32 + {F704167E-5722-4D6D-9BE7-8EFA02FB8F2D}.Debug.Build.0 = Debug|Win32 + {F704167E-5722-4D6D-9BE7-8EFA02FB8F2D}.DebugDll.ActiveCfg = DebugDll|Win32 + {F704167E-5722-4D6D-9BE7-8EFA02FB8F2D}.DebugDll.Build.0 = DebugDll|Win32 + {F704167E-5722-4D6D-9BE7-8EFA02FB8F2D}.Release.ActiveCfg = Release|Win32 + {F704167E-5722-4D6D-9BE7-8EFA02FB8F2D}.Release.Build.0 = Release|Win32 + {F704167E-5722-4D6D-9BE7-8EFA02FB8F2D}.ReleaseDll.ActiveCfg = ReleaseDll|Win32 + {F704167E-5722-4D6D-9BE7-8EFA02FB8F2D}.ReleaseDll.Build.0 = ReleaseDll|Win32 + {11BB762F-1998-4F62-81F0-7E0600029F70}.Debug.ActiveCfg = Debug|Win32 + {11BB762F-1998-4F62-81F0-7E0600029F70}.Debug.Build.0 = Debug|Win32 + {11BB762F-1998-4F62-81F0-7E0600029F70}.DebugDll.ActiveCfg = DebugDll|Win32 + {11BB762F-1998-4F62-81F0-7E0600029F70}.DebugDll.Build.0 = DebugDll|Win32 + {11BB762F-1998-4F62-81F0-7E0600029F70}.Release.ActiveCfg = Release|Win32 + {11BB762F-1998-4F62-81F0-7E0600029F70}.Release.Build.0 = Release|Win32 + {11BB762F-1998-4F62-81F0-7E0600029F70}.ReleaseDll.ActiveCfg = ReleaseDll|Win32 + {11BB762F-1998-4F62-81F0-7E0600029F70}.ReleaseDll.Build.0 = ReleaseDll|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/samples/samples_vc2010.sln b/samples/samples_vc2010.sln new file mode 100644 index 000000000..29a6ea275 --- /dev/null +++ b/samples/samples_vc2010.sln @@ -0,0 +1,593 @@ +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dlink", "dlink\dlink.vcxproj", "{6C3E9644-44A3-486E-827A-8B4381606F29}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fifo", "fifo\fifo.vcxproj", "{B2566BBC-49F1-42D7-85AC-5E2606535138}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FileDir", "FileDir\FileDir.vcxproj", "{71F3CDEF-30E4-4F2F-9D3B-139EA3723CE2}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "flock", "flock\flock.vcxproj", "{0D12EB24-88E6-427C-94E2-26C2CD7B0670}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "http_client", "http_client\http_client.vcxproj", "{9BCB6DE9-73D2-484A-B946-0BD5FDDF8CCB}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + {FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "memdb", "memdb\memdb.vcxproj", "{BA50914C-5890-4A29-85C0-F0C779552597}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mempool", "mempool\mempool.vcxproj", "{6333EAB7-D42C-42D3-8F10-8035C225227F}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "thread", "thread\thread.vcxproj", "{DF044F15-C15D-4C69-9024-21235BC3C7E9}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "urlcode", "urlcode\urlcode.vcxproj", "{7CD8C407-12E9-4DBA-B281-A1FC0E1D70C4}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vstream", "vstream\vstream.vcxproj", "{F0DAE963-53F7-4836-813D-7825BE6F8BDF}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vstring", "vstring\vstring.vcxproj", "{AC9CA58D-28FB-40B7-85C8-BA7674DBD934}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "thread_pool", "thread_pool\thread_pool.vcxproj", "{143D67EE-85E1-4456-AD99-6FDE7B1F1469}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ping", "ping\ping.vcxproj", "{814B40D7-29D3-4B12-B347-E4B632190DF9}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + {FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "file", "file\file.vcxproj", "{D4F73163-D0FF-4A01-94AE-41EC2D1FD658}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "aio_server", "aio\server\server.vcxproj", "{60731E38-81E7-4FE8-8634-8DF706CE9971}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "aio_client", "aio\client\client.vcxproj", "{FE9DEE6B-3256-4362-9014-B5FC5F04844E}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "process", "process\process.vcxproj", "{FF94BA1A-1465-4E6B-9CAF-EC0A3C376E2B}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "iterator", "iterator\iterator.vcxproj", "{84DE3D12-2BF6-46C1-BE20-9F9F6E7708B2}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zdb", "zdb\zdb.vcxproj", "{640ABB35-FBD3-4D34-A382-9ED8CF3FCE34}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "token_tree", "token_tree\token_tree.vcxproj", "{B44E3C63-C3A5-4306-A6FF-072818D62EEF}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "code_map", "code_map\code_map.vcxproj", "{A188A73A-4014-442F-8188-58CA59232CA8}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "connect", "connect\connect.vcxproj", "{6254E8C1-6849-4108-8DBE-18152A642F46}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vstream_popen", "vstream_popen\vstream_popen.vcxproj", "{3C9E5E69-3082-4C0E-AAEC-BCFC9407AA17}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pipe", "pipe\pipe.vcxproj", "{B56DD282-18A6-4A73-9297-F763BFD1F542}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dns_req", "dns_req\dns_req.vcxproj", "{E3234C5B-84F4-4332-99D3-EBC367C523EA}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cache2", "cache2\cache2.vcxproj", "{304F46FC-629C-462A-AFA7-454CC1A8EA39}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "http_aio", "http_aio\http_aio.vcxproj", "{0ED6281F-980A-47F7-B30B-0425EEB4C2A9}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + {FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "server1", "server1\server1.vcxproj", "{59CBAC72-7596-44E6-85DF-FDA362C45CE0}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xml", "xml\xml.vcxproj", "{BA8A20D5-958E-4DEC-9151-27049C2EEEB2}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "demo", "demo\demo.vcxproj", "{1AC6401F-21D8-4D44-9CDD-BDD45470CBFB}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "winaio", "winaio\winaio.vcxproj", "{4B58485B-D846-4485-9C5E-7F2304D71701}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "html_code", "html_code\html_code.vcxproj", "{7D44F644-AC16-4A58-A485-3BAD65CE377C}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "json", "json\json.vcxproj", "{8021ECD9-04CB-463B-B287-1FB0F5486D91}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "http_get_url1", "http\url_get1\http_get_url1.vcxproj", "{74114B21-D661-4AC4-B7BC-7D79C90DD4CE}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + {FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "http_get_url2", "http\url_get2\http_get_url2.vcxproj", "{6604B655-BE74-4461-9E2C-FDCBD1B79A48}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + {FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "http_get_url3", "http\url_get3\http_get_url3.vcxproj", "{2ADD53F3-3048-4D7B-8443-F0982FB17D3F}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + {FE724EF7-3763-4E78-BDF5-BCBC075719FD} = {FE724EF7-3763-4E78-BDF5-BCBC075719FD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "proctlc", "proctl\proctlc.vcxproj", "{805E87BF-E47B-4D25-8CFC-B61ECF98E84D}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "proctld", "proctl\proctld.vcxproj", "{CA5D3E66-9012-4387-AC99-C4B7810A8661}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tls_client", "tls\client\tls_client.vcxproj", "{1759A405-8572-4A70-8C14-16E7FCF4D899}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tls_server", "tls\server\tls_server.vcxproj", "{B392992C-340B-417B-81E7-ACB265602DF7}" + ProjectSection(ProjectDependencies) = postProject + {389FDE47-7F16-4DD4-B37A-27918BE745B6} = {389FDE47-7F16-4DD4-B37A-27918BE745B6} + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + {9E6E9FE9-EAAC-44BA-B463-70DE0233822E} = {9E6E9FE9-EAAC-44BA-B463-70DE0233822E} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unit_test", "..\unit_test\unit_test.vcxproj", "{11BB762F-1998-4F62-81F0-7E0600029F70}" + ProjectSection(ProjectDependencies) = postProject + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} = {B40213C2-507C-4C7F-A6E1-B850C9BDC27B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lib_acl", "..\lib_acl\lib_acl_vc2010.vcxproj", "{B40213C2-507C-4C7F-A6E1-B850C9BDC27B}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lib_protocol", "..\lib_protocol\lib_protocol_vc2010.vcxproj", "{FE724EF7-3763-4E78-BDF5-BCBC075719FD}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lib_dict", "..\lib_dict\lib_dict.vcxproj", "{9E6E9FE9-EAAC-44BA-B463-70DE0233822E}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lib_tls", "..\lib_tls\lib_tls.vcxproj", "{389FDE47-7F16-4DD4-B37A-27918BE745B6}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + DebugDll|Win32 = DebugDll|Win32 + Release|Win32 = Release|Win32 + ReleaseDll|Win32 = ReleaseDll|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {6C3E9644-44A3-486E-827A-8B4381606F29}.Debug|Win32.ActiveCfg = Debug|Win32 + {6C3E9644-44A3-486E-827A-8B4381606F29}.Debug|Win32.Build.0 = Debug|Win32 + {6C3E9644-44A3-486E-827A-8B4381606F29}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {6C3E9644-44A3-486E-827A-8B4381606F29}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {6C3E9644-44A3-486E-827A-8B4381606F29}.Release|Win32.ActiveCfg = Release|Win32 + {6C3E9644-44A3-486E-827A-8B4381606F29}.Release|Win32.Build.0 = Release|Win32 + {6C3E9644-44A3-486E-827A-8B4381606F29}.ReleaseDll|Win32.ActiveCfg = ReleaseDll|Win32 + {6C3E9644-44A3-486E-827A-8B4381606F29}.ReleaseDll|Win32.Build.0 = ReleaseDll|Win32 + {B2566BBC-49F1-42D7-85AC-5E2606535138}.Debug|Win32.ActiveCfg = Debug|Win32 + {B2566BBC-49F1-42D7-85AC-5E2606535138}.Debug|Win32.Build.0 = Debug|Win32 + {B2566BBC-49F1-42D7-85AC-5E2606535138}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {B2566BBC-49F1-42D7-85AC-5E2606535138}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {B2566BBC-49F1-42D7-85AC-5E2606535138}.Release|Win32.ActiveCfg = Release|Win32 + {B2566BBC-49F1-42D7-85AC-5E2606535138}.Release|Win32.Build.0 = Release|Win32 + {B2566BBC-49F1-42D7-85AC-5E2606535138}.ReleaseDll|Win32.ActiveCfg = ReleaseDll|Win32 + {B2566BBC-49F1-42D7-85AC-5E2606535138}.ReleaseDll|Win32.Build.0 = ReleaseDll|Win32 + {71F3CDEF-30E4-4F2F-9D3B-139EA3723CE2}.Debug|Win32.ActiveCfg = Debug|Win32 + {71F3CDEF-30E4-4F2F-9D3B-139EA3723CE2}.Debug|Win32.Build.0 = Debug|Win32 + {71F3CDEF-30E4-4F2F-9D3B-139EA3723CE2}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {71F3CDEF-30E4-4F2F-9D3B-139EA3723CE2}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {71F3CDEF-30E4-4F2F-9D3B-139EA3723CE2}.Release|Win32.ActiveCfg = Release|Win32 + {71F3CDEF-30E4-4F2F-9D3B-139EA3723CE2}.Release|Win32.Build.0 = Release|Win32 + {71F3CDEF-30E4-4F2F-9D3B-139EA3723CE2}.ReleaseDll|Win32.ActiveCfg = ReleaseDll|Win32 + {71F3CDEF-30E4-4F2F-9D3B-139EA3723CE2}.ReleaseDll|Win32.Build.0 = ReleaseDll|Win32 + {0D12EB24-88E6-427C-94E2-26C2CD7B0670}.Debug|Win32.ActiveCfg = Debug|Win32 + {0D12EB24-88E6-427C-94E2-26C2CD7B0670}.Debug|Win32.Build.0 = Debug|Win32 + {0D12EB24-88E6-427C-94E2-26C2CD7B0670}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {0D12EB24-88E6-427C-94E2-26C2CD7B0670}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {0D12EB24-88E6-427C-94E2-26C2CD7B0670}.Release|Win32.ActiveCfg = Release|Win32 + {0D12EB24-88E6-427C-94E2-26C2CD7B0670}.Release|Win32.Build.0 = Release|Win32 + {0D12EB24-88E6-427C-94E2-26C2CD7B0670}.ReleaseDll|Win32.ActiveCfg = ReleaseDll|Win32 + {0D12EB24-88E6-427C-94E2-26C2CD7B0670}.ReleaseDll|Win32.Build.0 = ReleaseDll|Win32 + {9BCB6DE9-73D2-484A-B946-0BD5FDDF8CCB}.Debug|Win32.ActiveCfg = Debug|Win32 + {9BCB6DE9-73D2-484A-B946-0BD5FDDF8CCB}.Debug|Win32.Build.0 = Debug|Win32 + {9BCB6DE9-73D2-484A-B946-0BD5FDDF8CCB}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {9BCB6DE9-73D2-484A-B946-0BD5FDDF8CCB}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {9BCB6DE9-73D2-484A-B946-0BD5FDDF8CCB}.Release|Win32.ActiveCfg = Release|Win32 + {9BCB6DE9-73D2-484A-B946-0BD5FDDF8CCB}.Release|Win32.Build.0 = Release|Win32 + {9BCB6DE9-73D2-484A-B946-0BD5FDDF8CCB}.ReleaseDll|Win32.ActiveCfg = ReleaseDll|Win32 + {9BCB6DE9-73D2-484A-B946-0BD5FDDF8CCB}.ReleaseDll|Win32.Build.0 = ReleaseDll|Win32 + {BA50914C-5890-4A29-85C0-F0C779552597}.Debug|Win32.ActiveCfg = Debug|Win32 + {BA50914C-5890-4A29-85C0-F0C779552597}.Debug|Win32.Build.0 = Debug|Win32 + {BA50914C-5890-4A29-85C0-F0C779552597}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {BA50914C-5890-4A29-85C0-F0C779552597}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {BA50914C-5890-4A29-85C0-F0C779552597}.Release|Win32.ActiveCfg = Release|Win32 + {BA50914C-5890-4A29-85C0-F0C779552597}.Release|Win32.Build.0 = Release|Win32 + {BA50914C-5890-4A29-85C0-F0C779552597}.ReleaseDll|Win32.ActiveCfg = ReleaseDll|Win32 + {BA50914C-5890-4A29-85C0-F0C779552597}.ReleaseDll|Win32.Build.0 = ReleaseDll|Win32 + {6333EAB7-D42C-42D3-8F10-8035C225227F}.Debug|Win32.ActiveCfg = Debug|Win32 + {6333EAB7-D42C-42D3-8F10-8035C225227F}.Debug|Win32.Build.0 = Debug|Win32 + {6333EAB7-D42C-42D3-8F10-8035C225227F}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {6333EAB7-D42C-42D3-8F10-8035C225227F}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {6333EAB7-D42C-42D3-8F10-8035C225227F}.Release|Win32.ActiveCfg = Release|Win32 + {6333EAB7-D42C-42D3-8F10-8035C225227F}.Release|Win32.Build.0 = Release|Win32 + {6333EAB7-D42C-42D3-8F10-8035C225227F}.ReleaseDll|Win32.ActiveCfg = ReleaseDll|Win32 + {6333EAB7-D42C-42D3-8F10-8035C225227F}.ReleaseDll|Win32.Build.0 = ReleaseDll|Win32 + {DF044F15-C15D-4C69-9024-21235BC3C7E9}.Debug|Win32.ActiveCfg = Debug|Win32 + {DF044F15-C15D-4C69-9024-21235BC3C7E9}.Debug|Win32.Build.0 = Debug|Win32 + {DF044F15-C15D-4C69-9024-21235BC3C7E9}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {DF044F15-C15D-4C69-9024-21235BC3C7E9}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {DF044F15-C15D-4C69-9024-21235BC3C7E9}.Release|Win32.ActiveCfg = Release|Win32 + {DF044F15-C15D-4C69-9024-21235BC3C7E9}.Release|Win32.Build.0 = Release|Win32 + {DF044F15-C15D-4C69-9024-21235BC3C7E9}.ReleaseDll|Win32.ActiveCfg = ReleaseDll|Win32 + {DF044F15-C15D-4C69-9024-21235BC3C7E9}.ReleaseDll|Win32.Build.0 = ReleaseDll|Win32 + {7CD8C407-12E9-4DBA-B281-A1FC0E1D70C4}.Debug|Win32.ActiveCfg = Debug|Win32 + {7CD8C407-12E9-4DBA-B281-A1FC0E1D70C4}.Debug|Win32.Build.0 = Debug|Win32 + {7CD8C407-12E9-4DBA-B281-A1FC0E1D70C4}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {7CD8C407-12E9-4DBA-B281-A1FC0E1D70C4}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {7CD8C407-12E9-4DBA-B281-A1FC0E1D70C4}.Release|Win32.ActiveCfg = Release|Win32 + {7CD8C407-12E9-4DBA-B281-A1FC0E1D70C4}.Release|Win32.Build.0 = Release|Win32 + {7CD8C407-12E9-4DBA-B281-A1FC0E1D70C4}.ReleaseDll|Win32.ActiveCfg = ReleaseDll|Win32 + {7CD8C407-12E9-4DBA-B281-A1FC0E1D70C4}.ReleaseDll|Win32.Build.0 = ReleaseDll|Win32 + {F0DAE963-53F7-4836-813D-7825BE6F8BDF}.Debug|Win32.ActiveCfg = Debug|Win32 + {F0DAE963-53F7-4836-813D-7825BE6F8BDF}.Debug|Win32.Build.0 = Debug|Win32 + {F0DAE963-53F7-4836-813D-7825BE6F8BDF}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {F0DAE963-53F7-4836-813D-7825BE6F8BDF}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {F0DAE963-53F7-4836-813D-7825BE6F8BDF}.Release|Win32.ActiveCfg = Release|Win32 + {F0DAE963-53F7-4836-813D-7825BE6F8BDF}.Release|Win32.Build.0 = Release|Win32 + {F0DAE963-53F7-4836-813D-7825BE6F8BDF}.ReleaseDll|Win32.ActiveCfg = ReleaseDll|Win32 + {F0DAE963-53F7-4836-813D-7825BE6F8BDF}.ReleaseDll|Win32.Build.0 = ReleaseDll|Win32 + {AC9CA58D-28FB-40B7-85C8-BA7674DBD934}.Debug|Win32.ActiveCfg = Debug|Win32 + {AC9CA58D-28FB-40B7-85C8-BA7674DBD934}.Debug|Win32.Build.0 = Debug|Win32 + {AC9CA58D-28FB-40B7-85C8-BA7674DBD934}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {AC9CA58D-28FB-40B7-85C8-BA7674DBD934}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {AC9CA58D-28FB-40B7-85C8-BA7674DBD934}.Release|Win32.ActiveCfg = Release|Win32 + {AC9CA58D-28FB-40B7-85C8-BA7674DBD934}.Release|Win32.Build.0 = Release|Win32 + {AC9CA58D-28FB-40B7-85C8-BA7674DBD934}.ReleaseDll|Win32.ActiveCfg = ReleaseDll|Win32 + {AC9CA58D-28FB-40B7-85C8-BA7674DBD934}.ReleaseDll|Win32.Build.0 = ReleaseDll|Win32 + {143D67EE-85E1-4456-AD99-6FDE7B1F1469}.Debug|Win32.ActiveCfg = Debug|Win32 + {143D67EE-85E1-4456-AD99-6FDE7B1F1469}.Debug|Win32.Build.0 = Debug|Win32 + {143D67EE-85E1-4456-AD99-6FDE7B1F1469}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {143D67EE-85E1-4456-AD99-6FDE7B1F1469}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {143D67EE-85E1-4456-AD99-6FDE7B1F1469}.Release|Win32.ActiveCfg = Release|Win32 + {143D67EE-85E1-4456-AD99-6FDE7B1F1469}.Release|Win32.Build.0 = Release|Win32 + {143D67EE-85E1-4456-AD99-6FDE7B1F1469}.ReleaseDll|Win32.ActiveCfg = ReleaseDll|Win32 + {143D67EE-85E1-4456-AD99-6FDE7B1F1469}.ReleaseDll|Win32.Build.0 = ReleaseDll|Win32 + {814B40D7-29D3-4B12-B347-E4B632190DF9}.Debug|Win32.ActiveCfg = Debug|Win32 + {814B40D7-29D3-4B12-B347-E4B632190DF9}.Debug|Win32.Build.0 = Debug|Win32 + {814B40D7-29D3-4B12-B347-E4B632190DF9}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {814B40D7-29D3-4B12-B347-E4B632190DF9}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {814B40D7-29D3-4B12-B347-E4B632190DF9}.Release|Win32.ActiveCfg = Release|Win32 + {814B40D7-29D3-4B12-B347-E4B632190DF9}.Release|Win32.Build.0 = Release|Win32 + {814B40D7-29D3-4B12-B347-E4B632190DF9}.ReleaseDll|Win32.ActiveCfg = ReleaseDll|Win32 + {814B40D7-29D3-4B12-B347-E4B632190DF9}.ReleaseDll|Win32.Build.0 = ReleaseDll|Win32 + {D4F73163-D0FF-4A01-94AE-41EC2D1FD658}.Debug|Win32.ActiveCfg = Debug|Win32 + {D4F73163-D0FF-4A01-94AE-41EC2D1FD658}.Debug|Win32.Build.0 = Debug|Win32 + {D4F73163-D0FF-4A01-94AE-41EC2D1FD658}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {D4F73163-D0FF-4A01-94AE-41EC2D1FD658}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {D4F73163-D0FF-4A01-94AE-41EC2D1FD658}.Release|Win32.ActiveCfg = Release|Win32 + {D4F73163-D0FF-4A01-94AE-41EC2D1FD658}.Release|Win32.Build.0 = Release|Win32 + {D4F73163-D0FF-4A01-94AE-41EC2D1FD658}.ReleaseDll|Win32.ActiveCfg = ReleaseDll|Win32 + {D4F73163-D0FF-4A01-94AE-41EC2D1FD658}.ReleaseDll|Win32.Build.0 = ReleaseDll|Win32 + {60731E38-81E7-4FE8-8634-8DF706CE9971}.Debug|Win32.ActiveCfg = Debug|Win32 + {60731E38-81E7-4FE8-8634-8DF706CE9971}.Debug|Win32.Build.0 = Debug|Win32 + {60731E38-81E7-4FE8-8634-8DF706CE9971}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {60731E38-81E7-4FE8-8634-8DF706CE9971}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {60731E38-81E7-4FE8-8634-8DF706CE9971}.Release|Win32.ActiveCfg = Release|Win32 + {60731E38-81E7-4FE8-8634-8DF706CE9971}.Release|Win32.Build.0 = Release|Win32 + {60731E38-81E7-4FE8-8634-8DF706CE9971}.ReleaseDll|Win32.ActiveCfg = ReleaseDll|Win32 + {60731E38-81E7-4FE8-8634-8DF706CE9971}.ReleaseDll|Win32.Build.0 = ReleaseDll|Win32 + {FE9DEE6B-3256-4362-9014-B5FC5F04844E}.Debug|Win32.ActiveCfg = Debug|Win32 + {FE9DEE6B-3256-4362-9014-B5FC5F04844E}.Debug|Win32.Build.0 = Debug|Win32 + {FE9DEE6B-3256-4362-9014-B5FC5F04844E}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {FE9DEE6B-3256-4362-9014-B5FC5F04844E}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {FE9DEE6B-3256-4362-9014-B5FC5F04844E}.Release|Win32.ActiveCfg = Release|Win32 + {FE9DEE6B-3256-4362-9014-B5FC5F04844E}.Release|Win32.Build.0 = Release|Win32 + {FE9DEE6B-3256-4362-9014-B5FC5F04844E}.ReleaseDll|Win32.ActiveCfg = ReleaseDll|Win32 + {FE9DEE6B-3256-4362-9014-B5FC5F04844E}.ReleaseDll|Win32.Build.0 = ReleaseDll|Win32 + {FF94BA1A-1465-4E6B-9CAF-EC0A3C376E2B}.Debug|Win32.ActiveCfg = Debug|Win32 + {FF94BA1A-1465-4E6B-9CAF-EC0A3C376E2B}.Debug|Win32.Build.0 = Debug|Win32 + {FF94BA1A-1465-4E6B-9CAF-EC0A3C376E2B}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {FF94BA1A-1465-4E6B-9CAF-EC0A3C376E2B}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {FF94BA1A-1465-4E6B-9CAF-EC0A3C376E2B}.Release|Win32.ActiveCfg = Release|Win32 + {FF94BA1A-1465-4E6B-9CAF-EC0A3C376E2B}.Release|Win32.Build.0 = Release|Win32 + {FF94BA1A-1465-4E6B-9CAF-EC0A3C376E2B}.ReleaseDll|Win32.ActiveCfg = ReleaseDll|Win32 + {FF94BA1A-1465-4E6B-9CAF-EC0A3C376E2B}.ReleaseDll|Win32.Build.0 = ReleaseDll|Win32 + {84DE3D12-2BF6-46C1-BE20-9F9F6E7708B2}.Debug|Win32.ActiveCfg = Debug|Win32 + {84DE3D12-2BF6-46C1-BE20-9F9F6E7708B2}.Debug|Win32.Build.0 = Debug|Win32 + {84DE3D12-2BF6-46C1-BE20-9F9F6E7708B2}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {84DE3D12-2BF6-46C1-BE20-9F9F6E7708B2}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {84DE3D12-2BF6-46C1-BE20-9F9F6E7708B2}.Release|Win32.ActiveCfg = Release|Win32 + {84DE3D12-2BF6-46C1-BE20-9F9F6E7708B2}.Release|Win32.Build.0 = Release|Win32 + {84DE3D12-2BF6-46C1-BE20-9F9F6E7708B2}.ReleaseDll|Win32.ActiveCfg = ReleaseDll|Win32 + {84DE3D12-2BF6-46C1-BE20-9F9F6E7708B2}.ReleaseDll|Win32.Build.0 = ReleaseDll|Win32 + {640ABB35-FBD3-4D34-A382-9ED8CF3FCE34}.Debug|Win32.ActiveCfg = Debug|Win32 + {640ABB35-FBD3-4D34-A382-9ED8CF3FCE34}.Debug|Win32.Build.0 = Debug|Win32 + {640ABB35-FBD3-4D34-A382-9ED8CF3FCE34}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {640ABB35-FBD3-4D34-A382-9ED8CF3FCE34}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {640ABB35-FBD3-4D34-A382-9ED8CF3FCE34}.Release|Win32.ActiveCfg = Release|Win32 + {640ABB35-FBD3-4D34-A382-9ED8CF3FCE34}.Release|Win32.Build.0 = Release|Win32 + {640ABB35-FBD3-4D34-A382-9ED8CF3FCE34}.ReleaseDll|Win32.ActiveCfg = ReleaseDll|Win32 + {640ABB35-FBD3-4D34-A382-9ED8CF3FCE34}.ReleaseDll|Win32.Build.0 = ReleaseDll|Win32 + {B44E3C63-C3A5-4306-A6FF-072818D62EEF}.Debug|Win32.ActiveCfg = Debug|Win32 + {B44E3C63-C3A5-4306-A6FF-072818D62EEF}.Debug|Win32.Build.0 = Debug|Win32 + {B44E3C63-C3A5-4306-A6FF-072818D62EEF}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {B44E3C63-C3A5-4306-A6FF-072818D62EEF}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {B44E3C63-C3A5-4306-A6FF-072818D62EEF}.Release|Win32.ActiveCfg = Release|Win32 + {B44E3C63-C3A5-4306-A6FF-072818D62EEF}.Release|Win32.Build.0 = Release|Win32 + {B44E3C63-C3A5-4306-A6FF-072818D62EEF}.ReleaseDll|Win32.ActiveCfg = ReleaseDll|Win32 + {B44E3C63-C3A5-4306-A6FF-072818D62EEF}.ReleaseDll|Win32.Build.0 = ReleaseDll|Win32 + {A188A73A-4014-442F-8188-58CA59232CA8}.Debug|Win32.ActiveCfg = Debug|Win32 + {A188A73A-4014-442F-8188-58CA59232CA8}.Debug|Win32.Build.0 = Debug|Win32 + {A188A73A-4014-442F-8188-58CA59232CA8}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {A188A73A-4014-442F-8188-58CA59232CA8}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {A188A73A-4014-442F-8188-58CA59232CA8}.Release|Win32.ActiveCfg = Release|Win32 + {A188A73A-4014-442F-8188-58CA59232CA8}.Release|Win32.Build.0 = Release|Win32 + {A188A73A-4014-442F-8188-58CA59232CA8}.ReleaseDll|Win32.ActiveCfg = ReleaseDll|Win32 + {A188A73A-4014-442F-8188-58CA59232CA8}.ReleaseDll|Win32.Build.0 = ReleaseDll|Win32 + {6254E8C1-6849-4108-8DBE-18152A642F46}.Debug|Win32.ActiveCfg = Debug|Win32 + {6254E8C1-6849-4108-8DBE-18152A642F46}.Debug|Win32.Build.0 = Debug|Win32 + {6254E8C1-6849-4108-8DBE-18152A642F46}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {6254E8C1-6849-4108-8DBE-18152A642F46}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {6254E8C1-6849-4108-8DBE-18152A642F46}.Release|Win32.ActiveCfg = Release|Win32 + {6254E8C1-6849-4108-8DBE-18152A642F46}.Release|Win32.Build.0 = Release|Win32 + {6254E8C1-6849-4108-8DBE-18152A642F46}.ReleaseDll|Win32.ActiveCfg = ReleaseDll|Win32 + {6254E8C1-6849-4108-8DBE-18152A642F46}.ReleaseDll|Win32.Build.0 = ReleaseDll|Win32 + {3C9E5E69-3082-4C0E-AAEC-BCFC9407AA17}.Debug|Win32.ActiveCfg = Debug|Win32 + {3C9E5E69-3082-4C0E-AAEC-BCFC9407AA17}.Debug|Win32.Build.0 = Debug|Win32 + {3C9E5E69-3082-4C0E-AAEC-BCFC9407AA17}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {3C9E5E69-3082-4C0E-AAEC-BCFC9407AA17}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {3C9E5E69-3082-4C0E-AAEC-BCFC9407AA17}.Release|Win32.ActiveCfg = Release|Win32 + {3C9E5E69-3082-4C0E-AAEC-BCFC9407AA17}.Release|Win32.Build.0 = Release|Win32 + {3C9E5E69-3082-4C0E-AAEC-BCFC9407AA17}.ReleaseDll|Win32.ActiveCfg = ReleaseDll|Win32 + {3C9E5E69-3082-4C0E-AAEC-BCFC9407AA17}.ReleaseDll|Win32.Build.0 = ReleaseDll|Win32 + {B56DD282-18A6-4A73-9297-F763BFD1F542}.Debug|Win32.ActiveCfg = Debug|Win32 + {B56DD282-18A6-4A73-9297-F763BFD1F542}.Debug|Win32.Build.0 = Debug|Win32 + {B56DD282-18A6-4A73-9297-F763BFD1F542}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {B56DD282-18A6-4A73-9297-F763BFD1F542}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {B56DD282-18A6-4A73-9297-F763BFD1F542}.Release|Win32.ActiveCfg = Release|Win32 + {B56DD282-18A6-4A73-9297-F763BFD1F542}.Release|Win32.Build.0 = Release|Win32 + {B56DD282-18A6-4A73-9297-F763BFD1F542}.ReleaseDll|Win32.ActiveCfg = ReleaseDll|Win32 + {B56DD282-18A6-4A73-9297-F763BFD1F542}.ReleaseDll|Win32.Build.0 = ReleaseDll|Win32 + {E3234C5B-84F4-4332-99D3-EBC367C523EA}.Debug|Win32.ActiveCfg = Debug|Win32 + {E3234C5B-84F4-4332-99D3-EBC367C523EA}.Debug|Win32.Build.0 = Debug|Win32 + {E3234C5B-84F4-4332-99D3-EBC367C523EA}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {E3234C5B-84F4-4332-99D3-EBC367C523EA}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {E3234C5B-84F4-4332-99D3-EBC367C523EA}.Release|Win32.ActiveCfg = Release|Win32 + {E3234C5B-84F4-4332-99D3-EBC367C523EA}.Release|Win32.Build.0 = Release|Win32 + {E3234C5B-84F4-4332-99D3-EBC367C523EA}.ReleaseDll|Win32.ActiveCfg = ReleaseDll|Win32 + {E3234C5B-84F4-4332-99D3-EBC367C523EA}.ReleaseDll|Win32.Build.0 = ReleaseDll|Win32 + {304F46FC-629C-462A-AFA7-454CC1A8EA39}.Debug|Win32.ActiveCfg = Debug|Win32 + {304F46FC-629C-462A-AFA7-454CC1A8EA39}.Debug|Win32.Build.0 = Debug|Win32 + {304F46FC-629C-462A-AFA7-454CC1A8EA39}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {304F46FC-629C-462A-AFA7-454CC1A8EA39}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {304F46FC-629C-462A-AFA7-454CC1A8EA39}.Release|Win32.ActiveCfg = Release|Win32 + {304F46FC-629C-462A-AFA7-454CC1A8EA39}.Release|Win32.Build.0 = Release|Win32 + {304F46FC-629C-462A-AFA7-454CC1A8EA39}.ReleaseDll|Win32.ActiveCfg = ReleaseDll|Win32 + {304F46FC-629C-462A-AFA7-454CC1A8EA39}.ReleaseDll|Win32.Build.0 = ReleaseDll|Win32 + {0ED6281F-980A-47F7-B30B-0425EEB4C2A9}.Debug|Win32.ActiveCfg = Debug|Win32 + {0ED6281F-980A-47F7-B30B-0425EEB4C2A9}.Debug|Win32.Build.0 = Debug|Win32 + {0ED6281F-980A-47F7-B30B-0425EEB4C2A9}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {0ED6281F-980A-47F7-B30B-0425EEB4C2A9}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {0ED6281F-980A-47F7-B30B-0425EEB4C2A9}.Release|Win32.ActiveCfg = Release|Win32 + {0ED6281F-980A-47F7-B30B-0425EEB4C2A9}.Release|Win32.Build.0 = Release|Win32 + {0ED6281F-980A-47F7-B30B-0425EEB4C2A9}.ReleaseDll|Win32.ActiveCfg = ReleaseDll|Win32 + {0ED6281F-980A-47F7-B30B-0425EEB4C2A9}.ReleaseDll|Win32.Build.0 = ReleaseDll|Win32 + {59CBAC72-7596-44E6-85DF-FDA362C45CE0}.Debug|Win32.ActiveCfg = Debug|Win32 + {59CBAC72-7596-44E6-85DF-FDA362C45CE0}.Debug|Win32.Build.0 = Debug|Win32 + {59CBAC72-7596-44E6-85DF-FDA362C45CE0}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {59CBAC72-7596-44E6-85DF-FDA362C45CE0}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {59CBAC72-7596-44E6-85DF-FDA362C45CE0}.Release|Win32.ActiveCfg = Release|Win32 + {59CBAC72-7596-44E6-85DF-FDA362C45CE0}.Release|Win32.Build.0 = Release|Win32 + {59CBAC72-7596-44E6-85DF-FDA362C45CE0}.ReleaseDll|Win32.ActiveCfg = ReleaseDll|Win32 + {59CBAC72-7596-44E6-85DF-FDA362C45CE0}.ReleaseDll|Win32.Build.0 = ReleaseDll|Win32 + {BA8A20D5-958E-4DEC-9151-27049C2EEEB2}.Debug|Win32.ActiveCfg = Debug|Win32 + {BA8A20D5-958E-4DEC-9151-27049C2EEEB2}.Debug|Win32.Build.0 = Debug|Win32 + {BA8A20D5-958E-4DEC-9151-27049C2EEEB2}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {BA8A20D5-958E-4DEC-9151-27049C2EEEB2}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {BA8A20D5-958E-4DEC-9151-27049C2EEEB2}.Release|Win32.ActiveCfg = Release|Win32 + {BA8A20D5-958E-4DEC-9151-27049C2EEEB2}.Release|Win32.Build.0 = Release|Win32 + {BA8A20D5-958E-4DEC-9151-27049C2EEEB2}.ReleaseDll|Win32.ActiveCfg = ReleaseDll|Win32 + {BA8A20D5-958E-4DEC-9151-27049C2EEEB2}.ReleaseDll|Win32.Build.0 = ReleaseDll|Win32 + {1AC6401F-21D8-4D44-9CDD-BDD45470CBFB}.Debug|Win32.ActiveCfg = Debug|Win32 + {1AC6401F-21D8-4D44-9CDD-BDD45470CBFB}.Debug|Win32.Build.0 = Debug|Win32 + {1AC6401F-21D8-4D44-9CDD-BDD45470CBFB}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {1AC6401F-21D8-4D44-9CDD-BDD45470CBFB}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {1AC6401F-21D8-4D44-9CDD-BDD45470CBFB}.Release|Win32.ActiveCfg = Release|Win32 + {1AC6401F-21D8-4D44-9CDD-BDD45470CBFB}.Release|Win32.Build.0 = Release|Win32 + {1AC6401F-21D8-4D44-9CDD-BDD45470CBFB}.ReleaseDll|Win32.ActiveCfg = ReleaseDll|Win32 + {1AC6401F-21D8-4D44-9CDD-BDD45470CBFB}.ReleaseDll|Win32.Build.0 = ReleaseDll|Win32 + {4B58485B-D846-4485-9C5E-7F2304D71701}.Debug|Win32.ActiveCfg = Debug|Win32 + {4B58485B-D846-4485-9C5E-7F2304D71701}.Debug|Win32.Build.0 = Debug|Win32 + {4B58485B-D846-4485-9C5E-7F2304D71701}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {4B58485B-D846-4485-9C5E-7F2304D71701}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {4B58485B-D846-4485-9C5E-7F2304D71701}.Release|Win32.ActiveCfg = Release|Win32 + {4B58485B-D846-4485-9C5E-7F2304D71701}.Release|Win32.Build.0 = Release|Win32 + {4B58485B-D846-4485-9C5E-7F2304D71701}.ReleaseDll|Win32.ActiveCfg = ReleaseDll|Win32 + {4B58485B-D846-4485-9C5E-7F2304D71701}.ReleaseDll|Win32.Build.0 = ReleaseDll|Win32 + {7D44F644-AC16-4A58-A485-3BAD65CE377C}.Debug|Win32.ActiveCfg = Debug|Win32 + {7D44F644-AC16-4A58-A485-3BAD65CE377C}.Debug|Win32.Build.0 = Debug|Win32 + {7D44F644-AC16-4A58-A485-3BAD65CE377C}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {7D44F644-AC16-4A58-A485-3BAD65CE377C}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {7D44F644-AC16-4A58-A485-3BAD65CE377C}.Release|Win32.ActiveCfg = Release|Win32 + {7D44F644-AC16-4A58-A485-3BAD65CE377C}.Release|Win32.Build.0 = Release|Win32 + {7D44F644-AC16-4A58-A485-3BAD65CE377C}.ReleaseDll|Win32.ActiveCfg = ReleaseDll|Win32 + {7D44F644-AC16-4A58-A485-3BAD65CE377C}.ReleaseDll|Win32.Build.0 = ReleaseDll|Win32 + {8021ECD9-04CB-463B-B287-1FB0F5486D91}.Debug|Win32.ActiveCfg = Debug|Win32 + {8021ECD9-04CB-463B-B287-1FB0F5486D91}.Debug|Win32.Build.0 = Debug|Win32 + {8021ECD9-04CB-463B-B287-1FB0F5486D91}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {8021ECD9-04CB-463B-B287-1FB0F5486D91}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {8021ECD9-04CB-463B-B287-1FB0F5486D91}.Release|Win32.ActiveCfg = Release|Win32 + {8021ECD9-04CB-463B-B287-1FB0F5486D91}.Release|Win32.Build.0 = Release|Win32 + {8021ECD9-04CB-463B-B287-1FB0F5486D91}.ReleaseDll|Win32.ActiveCfg = ReleaseDll|Win32 + {8021ECD9-04CB-463B-B287-1FB0F5486D91}.ReleaseDll|Win32.Build.0 = ReleaseDll|Win32 + {74114B21-D661-4AC4-B7BC-7D79C90DD4CE}.Debug|Win32.ActiveCfg = Debug|Win32 + {74114B21-D661-4AC4-B7BC-7D79C90DD4CE}.Debug|Win32.Build.0 = Debug|Win32 + {74114B21-D661-4AC4-B7BC-7D79C90DD4CE}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {74114B21-D661-4AC4-B7BC-7D79C90DD4CE}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {74114B21-D661-4AC4-B7BC-7D79C90DD4CE}.Release|Win32.ActiveCfg = Release|Win32 + {74114B21-D661-4AC4-B7BC-7D79C90DD4CE}.Release|Win32.Build.0 = Release|Win32 + {74114B21-D661-4AC4-B7BC-7D79C90DD4CE}.ReleaseDll|Win32.ActiveCfg = ReleaseDll|Win32 + {74114B21-D661-4AC4-B7BC-7D79C90DD4CE}.ReleaseDll|Win32.Build.0 = ReleaseDll|Win32 + {6604B655-BE74-4461-9E2C-FDCBD1B79A48}.Debug|Win32.ActiveCfg = Debug|Win32 + {6604B655-BE74-4461-9E2C-FDCBD1B79A48}.Debug|Win32.Build.0 = Debug|Win32 + {6604B655-BE74-4461-9E2C-FDCBD1B79A48}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {6604B655-BE74-4461-9E2C-FDCBD1B79A48}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {6604B655-BE74-4461-9E2C-FDCBD1B79A48}.Release|Win32.ActiveCfg = Release|Win32 + {6604B655-BE74-4461-9E2C-FDCBD1B79A48}.Release|Win32.Build.0 = Release|Win32 + {6604B655-BE74-4461-9E2C-FDCBD1B79A48}.ReleaseDll|Win32.ActiveCfg = ReleaseDll|Win32 + {6604B655-BE74-4461-9E2C-FDCBD1B79A48}.ReleaseDll|Win32.Build.0 = ReleaseDll|Win32 + {2ADD53F3-3048-4D7B-8443-F0982FB17D3F}.Debug|Win32.ActiveCfg = Debug|Win32 + {2ADD53F3-3048-4D7B-8443-F0982FB17D3F}.Debug|Win32.Build.0 = Debug|Win32 + {2ADD53F3-3048-4D7B-8443-F0982FB17D3F}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {2ADD53F3-3048-4D7B-8443-F0982FB17D3F}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {2ADD53F3-3048-4D7B-8443-F0982FB17D3F}.Release|Win32.ActiveCfg = Release|Win32 + {2ADD53F3-3048-4D7B-8443-F0982FB17D3F}.Release|Win32.Build.0 = Release|Win32 + {2ADD53F3-3048-4D7B-8443-F0982FB17D3F}.ReleaseDll|Win32.ActiveCfg = ReleaseDll|Win32 + {2ADD53F3-3048-4D7B-8443-F0982FB17D3F}.ReleaseDll|Win32.Build.0 = ReleaseDll|Win32 + {805E87BF-E47B-4D25-8CFC-B61ECF98E84D}.Debug|Win32.ActiveCfg = Debug|Win32 + {805E87BF-E47B-4D25-8CFC-B61ECF98E84D}.Debug|Win32.Build.0 = Debug|Win32 + {805E87BF-E47B-4D25-8CFC-B61ECF98E84D}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {805E87BF-E47B-4D25-8CFC-B61ECF98E84D}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {805E87BF-E47B-4D25-8CFC-B61ECF98E84D}.Release|Win32.ActiveCfg = Release|Win32 + {805E87BF-E47B-4D25-8CFC-B61ECF98E84D}.Release|Win32.Build.0 = Release|Win32 + {805E87BF-E47B-4D25-8CFC-B61ECF98E84D}.ReleaseDll|Win32.ActiveCfg = ReleaseDll|Win32 + {805E87BF-E47B-4D25-8CFC-B61ECF98E84D}.ReleaseDll|Win32.Build.0 = ReleaseDll|Win32 + {CA5D3E66-9012-4387-AC99-C4B7810A8661}.Debug|Win32.ActiveCfg = Debug|Win32 + {CA5D3E66-9012-4387-AC99-C4B7810A8661}.Debug|Win32.Build.0 = Debug|Win32 + {CA5D3E66-9012-4387-AC99-C4B7810A8661}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {CA5D3E66-9012-4387-AC99-C4B7810A8661}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {CA5D3E66-9012-4387-AC99-C4B7810A8661}.Release|Win32.ActiveCfg = Release|Win32 + {CA5D3E66-9012-4387-AC99-C4B7810A8661}.Release|Win32.Build.0 = Release|Win32 + {CA5D3E66-9012-4387-AC99-C4B7810A8661}.ReleaseDll|Win32.ActiveCfg = ReleaseDll|Win32 + {CA5D3E66-9012-4387-AC99-C4B7810A8661}.ReleaseDll|Win32.Build.0 = ReleaseDll|Win32 + {1759A405-8572-4A70-8C14-16E7FCF4D899}.Debug|Win32.ActiveCfg = Debug|Win32 + {1759A405-8572-4A70-8C14-16E7FCF4D899}.Debug|Win32.Build.0 = Debug|Win32 + {1759A405-8572-4A70-8C14-16E7FCF4D899}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {1759A405-8572-4A70-8C14-16E7FCF4D899}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {1759A405-8572-4A70-8C14-16E7FCF4D899}.Release|Win32.ActiveCfg = Release|Win32 + {1759A405-8572-4A70-8C14-16E7FCF4D899}.Release|Win32.Build.0 = Release|Win32 + {1759A405-8572-4A70-8C14-16E7FCF4D899}.ReleaseDll|Win32.ActiveCfg = ReleaseDll|Win32 + {1759A405-8572-4A70-8C14-16E7FCF4D899}.ReleaseDll|Win32.Build.0 = ReleaseDll|Win32 + {B392992C-340B-417B-81E7-ACB265602DF7}.Debug|Win32.ActiveCfg = Debug|Win32 + {B392992C-340B-417B-81E7-ACB265602DF7}.Debug|Win32.Build.0 = Debug|Win32 + {B392992C-340B-417B-81E7-ACB265602DF7}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {B392992C-340B-417B-81E7-ACB265602DF7}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {B392992C-340B-417B-81E7-ACB265602DF7}.Release|Win32.ActiveCfg = Release|Win32 + {B392992C-340B-417B-81E7-ACB265602DF7}.Release|Win32.Build.0 = Release|Win32 + {B392992C-340B-417B-81E7-ACB265602DF7}.ReleaseDll|Win32.ActiveCfg = ReleaseDll|Win32 + {B392992C-340B-417B-81E7-ACB265602DF7}.ReleaseDll|Win32.Build.0 = ReleaseDll|Win32 + {11BB762F-1998-4F62-81F0-7E0600029F70}.Debug|Win32.ActiveCfg = Debug|Win32 + {11BB762F-1998-4F62-81F0-7E0600029F70}.Debug|Win32.Build.0 = Debug|Win32 + {11BB762F-1998-4F62-81F0-7E0600029F70}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {11BB762F-1998-4F62-81F0-7E0600029F70}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {11BB762F-1998-4F62-81F0-7E0600029F70}.Release|Win32.ActiveCfg = Release|Win32 + {11BB762F-1998-4F62-81F0-7E0600029F70}.Release|Win32.Build.0 = Release|Win32 + {11BB762F-1998-4F62-81F0-7E0600029F70}.ReleaseDll|Win32.ActiveCfg = ReleaseDll|Win32 + {11BB762F-1998-4F62-81F0-7E0600029F70}.ReleaseDll|Win32.Build.0 = ReleaseDll|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Debug|Win32.ActiveCfg = Debug|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Debug|Win32.Build.0 = Debug|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Release|Win32.ActiveCfg = Release|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.Release|Win32.Build.0 = Release|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.ReleaseDll|Win32.ActiveCfg = ReleaseDll|Win32 + {B40213C2-507C-4C7F-A6E1-B850C9BDC27B}.ReleaseDll|Win32.Build.0 = ReleaseDll|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Debug|Win32.ActiveCfg = Debug|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Debug|Win32.Build.0 = Debug|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Release|Win32.ActiveCfg = Release|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.Release|Win32.Build.0 = Release|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.ReleaseDll|Win32.ActiveCfg = ReleaseDll|Win32 + {FE724EF7-3763-4E78-BDF5-BCBC075719FD}.ReleaseDll|Win32.Build.0 = ReleaseDll|Win32 + {9E6E9FE9-EAAC-44BA-B463-70DE0233822E}.Debug|Win32.ActiveCfg = Debug|Win32 + {9E6E9FE9-EAAC-44BA-B463-70DE0233822E}.Debug|Win32.Build.0 = Debug|Win32 + {9E6E9FE9-EAAC-44BA-B463-70DE0233822E}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {9E6E9FE9-EAAC-44BA-B463-70DE0233822E}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {9E6E9FE9-EAAC-44BA-B463-70DE0233822E}.Release|Win32.ActiveCfg = Release|Win32 + {9E6E9FE9-EAAC-44BA-B463-70DE0233822E}.Release|Win32.Build.0 = Release|Win32 + {9E6E9FE9-EAAC-44BA-B463-70DE0233822E}.ReleaseDll|Win32.ActiveCfg = ReleaseDll|Win32 + {9E6E9FE9-EAAC-44BA-B463-70DE0233822E}.ReleaseDll|Win32.Build.0 = ReleaseDll|Win32 + {389FDE47-7F16-4DD4-B37A-27918BE745B6}.Debug|Win32.ActiveCfg = Debug|Win32 + {389FDE47-7F16-4DD4-B37A-27918BE745B6}.Debug|Win32.Build.0 = Debug|Win32 + {389FDE47-7F16-4DD4-B37A-27918BE745B6}.DebugDll|Win32.ActiveCfg = DebugDll|Win32 + {389FDE47-7F16-4DD4-B37A-27918BE745B6}.DebugDll|Win32.Build.0 = DebugDll|Win32 + {389FDE47-7F16-4DD4-B37A-27918BE745B6}.Release|Win32.ActiveCfg = Release|Win32 + {389FDE47-7F16-4DD4-B37A-27918BE745B6}.Release|Win32.Build.0 = Release|Win32 + {389FDE47-7F16-4DD4-B37A-27918BE745B6}.ReleaseDll|Win32.ActiveCfg = ReleaseDll|Win32 + {389FDE47-7F16-4DD4-B37A-27918BE745B6}.ReleaseDll|Win32.Build.0 = ReleaseDll|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/samples/server/Makefile b/samples/server/Makefile new file mode 100644 index 000000000..19cf1996e --- /dev/null +++ b/samples/server/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = server diff --git a/samples/server/main.c b/samples/server/main.c new file mode 100644 index 000000000..452f308dd --- /dev/null +++ b/samples/server/main.c @@ -0,0 +1,64 @@ +#include "lib_acl.h" +#include +#include + +static void init(void) +{ + acl_init(); +} + +static void end(void) +{ + acl_end(); +} + +static void thread_run(void *arg) +{ + ACL_VSTREAM *client = (ACL_VSTREAM*) arg; + char buf[8192]; + int ret; + + + ret = acl_vstream_read(client, buf, sizeof(buf)); + if (ret == ACL_VSTREAM_EOF) { + acl_vstream_close(client); + return; + } + + buf[ret] = 0; + printf("(%s)\n", buf); + acl_vstream_close(client); +} + +static void run(void) +{ + const char *addr = "0.0.0.0:8089"; + ACL_VSTREAM *sstream = acl_vstream_listen(addr, 128); + acl_pthread_pool_t *pool; + + if (sstream == NULL) { + acl_msg_error("listen %s error(%s)", addr, acl_last_serror()); + return; + } + + printf("listening on %s ...\n", addr); + pool = acl_thread_pool_create(100, 120); + while (1) { + ACL_VSTREAM *client = acl_vstream_accept(sstream, NULL, 0); + if (client == NULL) { + acl_msg_error("accept error(%s)", acl_last_serror()); + break; + } + acl_pthread_pool_add(pool, thread_run, client); + } + + acl_vstream_close(sstream); +} + +int main(int argc acl_unused, char *argv[] acl_unused) +{ + init(); + run(); + end(); + return (0); +} diff --git a/samples/server1/main.cpp b/samples/server1/main.cpp new file mode 100644 index 000000000..141ab31f4 --- /dev/null +++ b/samples/server1/main.cpp @@ -0,0 +1,52 @@ +#include "lib_acl.h" +#pragma comment(lib,"ws2_32") +#pragma comment(lib, "wsock32") + +static void echo(ACL_VSTREAM *client) +{ + int ret; + char buf[1024]; + + while (1) { + ret = acl_vstream_gets(client, buf, sizeof(buf)); + if (ret == ACL_VSTREAM_EOF) { + break; + } + + //ret = acl_vstream_fprintf(client, "hello world\r\nhello world\r\nhello world\r\n"); + ret = acl_vstream_fprintf(client, "hello world\r\n"); + if (ret == ACL_VSTREAM_EOF) + break; + } +} + +int main(int argc, char *argv[]) +{ + ACL_VSTREAM *sstream, *client; + const char *addr = "127.0.0.1:30082"; + + acl_init(); + + sstream = acl_vstream_listen(addr, 128); + if (sstream == NULL) { + printf("listen on %s error(%s)\r\n", addr, acl_last_serror()); + getchar(); + return (0); + } + + printf("listening on %s ...\r\n", addr); + + while (1) { + client = acl_vstream_accept(sstream, NULL, 0); + if (client == NULL) { + printf("accept error(%s)\r\n", acl_last_serror()); + break; + } + echo(client); + acl_vstream_close(client); + } + + printf("Over now\r\n"); + getchar(); + return (0); +} \ No newline at end of file diff --git a/samples/server1/server1.vcproj b/samples/server1/server1.vcproj new file mode 100644 index 000000000..e68e98052 --- /dev/null +++ b/samples/server1/server1.vcproj @@ -0,0 +1,230 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/server1/server1.vcxproj b/samples/server1/server1.vcxproj new file mode 100644 index 000000000..d65b933ba --- /dev/null +++ b/samples/server1/server1.vcxproj @@ -0,0 +1,177 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + ReleaseDll + Win32 + + + Release + Win32 + + + + {59CBAC72-7596-44E6-85DF-FDA362C45CE0} + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + $(OutDir)server1.exe + true + $(OutDir)server1.pdb + Console + MachineX86 + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + $(OutDir)server1.exe + true + Console + true + true + MachineX86 + + + + + Disabled + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_DLL;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + EditAndContinue + + + $(OutDir)server1.exe + true + $(OutDir)server1.pdb + Console + MachineX86 + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_DLL;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + $(OutDir)server1.exe + true + Console + true + true + MachineX86 + + + + + + + + {b40213c2-507c-4c7f-a6e1-b850c9bdc27b} + false + + + + + + \ No newline at end of file diff --git a/samples/server1/server1.vcxproj.filters b/samples/server1/server1.vcxproj.filters new file mode 100644 index 000000000..f84bd00e6 --- /dev/null +++ b/samples/server1/server1.vcxproj.filters @@ -0,0 +1,22 @@ +锘 + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx + + + + + 婧愭枃浠 + + + \ No newline at end of file diff --git a/samples/slice/Makefile b/samples/slice/Makefile new file mode 100644 index 000000000..3393db036 --- /dev/null +++ b/samples/slice/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = slice diff --git a/samples/slice/main.c b/samples/slice/main.c new file mode 100644 index 000000000..4040c19ca --- /dev/null +++ b/samples/slice/main.c @@ -0,0 +1,229 @@ +#include "lib_acl.h" +#include "ring.h" + +typedef struct DUMMY { + char s[8]; + int n; + struct DUMMY *next; + RING entry; +} DUMMY; + +static void slice_alloc(int n) +{ + int i; + ACL_SLICE *slice = acl_slice_create("slice_alloc", 0, sizeof(DUMMY), ACL_SLICE_FLAG_GC1); + DUMMY *ptr, *head = NULL; + + printf("in slice_alloc\n"); + ACL_METER_TIME(NULL); + for (i = 0; i < n; i++) { + ptr = (DUMMY*) acl_slice_alloc(slice); + if (head != NULL) + ptr->next = head; + else + ptr->next = NULL; + } + ACL_METER_TIME(NULL); + + i = 0; + while (i++ < 10) { + printf("sleep one second\n"); + sleep(1); + } + + ACL_METER_TIME(NULL); + acl_slice_destroy(slice); + ACL_METER_TIME(NULL); +} + +static void sys_alloc(int n) +{ + int i; + DUMMY *ptr, *head = NULL; + + printf("in sys_alloc\n"); + ACL_METER_TIME(NULL); + for (i = 0; i < n; i++) { + ptr = (DUMMY*) acl_mymalloc(sizeof(DUMMY)); + if (head != NULL) + ptr->next = head; + else + ptr->next = NULL; + head = ptr; + } + ACL_METER_TIME(NULL); + + i = 0; + while (i++ < 10) { + printf("sleep one second\n"); + sleep(1); + } + + ACL_METER_TIME(NULL); + while (head) { + ptr = head; + head = head->next; + acl_myfree(ptr); + } + ACL_METER_TIME(NULL); +} + +static void slice_gc1(void) +{ + DUMMY head; + DUMMY *ptr0, *ptr1, *ptr2, *ptr3; + ACL_SLICE *slice = acl_slice_create("slice_gc1", 4096 * 64, sizeof(DUMMY), + ACL_SLICE_FLAG_GC1 /* | ACL_SLICE_FLAG_RTGC_OFF */); + + ring_init(&head.entry); + + ptr0 = acl_slice_alloc(slice); + ptr1 = acl_slice_alloc(slice); + ptr2 = acl_slice_alloc(slice); + ptr3 = acl_slice_alloc(slice); + + memset(ptr0->s, 'a', sizeof(ptr0->s)); + memset(ptr1->s, 'a', sizeof(ptr0->s)); + memset(ptr2->s, 'a', sizeof(ptr0->s)); + memset(ptr3->s, 'a', sizeof(ptr0->s)); + + ptr0->n = 0; + ptr1->n = 1; + ptr2->n = 2; + ptr3->n = 3; + + ring_prepend(&head.entry, &ptr0->entry); + ring_prepend(&head.entry, &ptr1->entry); + ring_prepend(&head.entry, &ptr2->entry); + ring_prepend(&head.entry, &ptr3->entry); + + acl_slice_free2(slice, ptr3); + acl_slice_free2(slice, ptr2); + acl_slice_free2(slice, ptr1); + acl_slice_free2(slice, ptr0); + acl_slice_destroy(slice); +} + +static void slice_gc2(void) +{ + int i, max = 10000000; + ACL_BINHASH *table; +#if 1 + unsigned int flag = ACL_BINHASH_FLAG_SLICE2; +#else + unsigned int flag = 0; +#endif + + table = acl_binhash_create(max, flag); + + ACL_METER_TIME("---- begin add to hash ------"); + for (i = max - 1; i >= 0; i--) { + acl_binhash_enter(table, &i, sizeof(i), 0); + } + + ACL_METER_TIME("---- end add and begin free table ---"); + acl_binhash_free(table, 0); + ACL_METER_TIME("--- end free table ---"); +} + +static void slice_gc(void) +{ + ACL_SLICE *slice; + DUMMY *head = NULL, *ptr; + int i, n = 10240000; + int nsleep = 0; + ACL_SLICE_STAT sbuf; + unsigned int flag = ACL_SLICE_FLAG_GC2 /* | ACL_SLICE_FLAG_RTGC_OFF */; + + acl_memory_debug_start(); + + printf("sizeof DUMMY: %d\n", (int) sizeof(DUMMY)); + + slice = acl_slice_create("slice_gc", 1024 * 100, sizeof(DUMMY), flag); + ACL_METER_TIME("------ begin alloc ------"); + for (i = 0; i < n; i++) { + ptr = (DUMMY*) acl_slice_alloc(slice); + if (head != NULL) + ptr->next = head; + else + ptr->next = NULL; + head = ptr; + } + + ACL_METER_TIME("------ end alloc and begin free ------"); + + acl_memory_stat(); + + while (nsleep-- > 0) { + printf("sleep 1 second\n"); + sleep(1); + } + + acl_slice_stat(slice, &sbuf); + printf("islots: %d, nslots: %d, total length: %d, nbuf: %d\n", + (int) sbuf.islots, (int) sbuf.nslots, + (int) sbuf.length, (int) sbuf.nbuf); + + while (head) { + ptr = head; + head = head->next; + if ((flag & ACL_SLICE_FLAG_GC1)) + acl_slice_free2(slice, ptr); + else { + acl_slice_free(ptr); + } + } + ACL_METER_TIME("------ end free ------"); + + acl_slice_stat(slice, &sbuf); + printf("call slice gc, sizeof(DUMMY): %d, islots: %d, nslots: %d, total length: %d, nbuf: %d\n", + (int) sizeof(DUMMY), (int) sbuf.islots, (int) sbuf.nslots, + (int) sbuf.length, (int) sbuf.nbuf); + i = 0; + + ACL_METER_TIME("------ and begin gc ------"); + printf("------------ islots: %d, nslots: %d, nbuf: %d ------\n", sbuf.islots, sbuf.nslots, sbuf.nbuf); + + while (sbuf.nbuf > 0 && (sbuf.flag & ACL_SLICE_FLAG_GC1) == 0) { + acl_slice_gc(slice); + acl_slice_stat(slice, &sbuf); + i++; + } + ACL_METER_TIME("------ end gc and begin destroy ------"); + acl_slice_destroy(slice); + ACL_METER_TIME("------ end destroy ------"); + printf("slice gc over, call %d times\n", i); + + acl_memory_debug_stop(); +} + +static void mem_slice(void) +{ + char *ptr; + + acl_mem_slice_init(8, 10240, 100, ACL_SLICE_FLAG_GC2 | ACL_SLICE_FLAG_RTGC_OFF); + + ptr = acl_mystrdup("hello world"); + printf("ptr: %s\n", ptr); + ptr = (char*) acl_myrealloc(ptr, 1024); + printf("ptr: %s\n", ptr); + acl_myfree(ptr); + acl_mem_slice_destroy(); +} + +int main(int argc acl_unused, char *argv[] acl_unused) +{ + int n = 10000000; + + mem_slice(); return (0); + slice_gc(); return (0); + slice_gc2(); return (0); + slice_gc1(); return (0); + + slice_alloc(n); + sys_alloc(n); + printf("enter any key to exit\n"); + getchar(); + + return (0); +} diff --git a/samples/slice/ring.h b/samples/slice/ring.h new file mode 100644 index 000000000..ec08f647c --- /dev/null +++ b/samples/slice/ring.h @@ -0,0 +1,82 @@ + +#ifndef _RING_H_INCLUDE_ +#define _RING_H_INCLUDE_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +typedef struct RING RING; + +struct RING { + RING *succ; /* successor */ + RING *pred; /* predecessor */ +}; + +#define ring_init(ring_in) do \ +{ \ + RING *ring = ring_in; \ + ring->pred = ring->succ = ring; \ +} while (0) + +#define ring_append(ring_in, entry_in) do \ +{ \ + RING *ring = ring_in; \ + RING *entry = entry_in; \ + entry->succ = ring->succ; \ + entry->pred = ring; \ + ring->succ->pred = entry; \ + ring->succ = entry; \ +} while (0) + +#define ring_prepend(ring_in, entry_in) do \ +{ \ + RING *ring = ring_in; \ + RING *entry = entry_in; \ + entry->pred = ring->pred; \ + entry->succ = ring; \ + ring->pred->succ = entry; \ + ring->pred = entry; \ +} while (0) + +#define ring_detach(entry_in) do \ +{ \ + RING *entry = entry_in; \ + RING *succ; \ + RING *pred; \ + succ = entry->succ; \ + pred = entry->pred; \ + if (succ != NULL && pred != NULL) { \ + pred->succ = succ; \ + succ->pred = pred; \ + entry->succ = entry->pred = 0; \ + } \ +} while (0) + +#define ring_succ(c) ((c)->succ) +#define ring_pred(c) ((c)->pred) + +#define RING_TO_APPL(ring_ptr, app_type, ring_member) \ + ((app_type *) (((char *) (ring_ptr)) - offsetof(app_type,ring_member))) + +#define FOREACH_TO_APPL_ENTRY(entry, head) \ + for (entry = ring_succ(head); entry != (head); entry = ring_succ(entry)) +#define FOREACH_RING_ENTRY(entry, head) \ + for (entry = ring_succ(head); entry != (head); entry = ring_succ(entry)) + +#define FOREACH_RING_FORWARD FOREACH_RING_ENTRY +#define FOREACH_RING_BACKWARD(entry, head) \ + for (entry = ring_pred(head); entry != (head); entry = ring_pred(entry)) + +#define FIRST_APPL(head, app_type, ring_member) \ + (ring_succ(head) != (head) ? \ + RING_TO_APPL(ring_succ(head), app_type, ring_member) : 0) + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/samples/slice/valgrind.sh b/samples/slice/valgrind.sh new file mode 100644 index 000000000..3dacce13e --- /dev/null +++ b/samples/slice/valgrind.sh @@ -0,0 +1,2 @@ +#!/bin/sh +valgrind --tool=memcheck --leak-check=yes --show-reachable=yes -v ./slice diff --git a/samples/slice_mem/Makefile b/samples/slice_mem/Makefile new file mode 100644 index 000000000..b7011286b --- /dev/null +++ b/samples/slice_mem/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = slice_mem diff --git a/samples/slice_mem/main.c b/samples/slice_mem/main.c new file mode 100644 index 000000000..64a881a12 --- /dev/null +++ b/samples/slice_mem/main.c @@ -0,0 +1,180 @@ +#include "lib_acl.h" +#include + +/*----------------------------------------------------------------------------*/ + +/* 线程池中某线程的任务处理过程 */ + +static void run_thread(void *arg) +{ + /* 释放主线程分配的内存 */ + if (1) + acl_myfree(arg); +} + +static void thread_pool_tls(int nthread, int nalloc) +{ + const char *myname = "thread_pool_tls"; + acl_pthread_pool_t *thr_pool; + void *ptr; + time_t begin = time(NULL); + int i; + + /* 创建线程池 */ + thr_pool = acl_thread_pool_create(nthread, 0); + + for (i = 0; i < nalloc; i++) { + /* 主线程分配内存 */ + if (1) + ptr = acl_mymalloc(64); + else + ptr = 0; + /* 向线程池中添加任务, 将新内存传递给线程池处理 */ + /* + * ACL_METER_TIME("--31--"); + */ + acl_pthread_pool_add(thr_pool, run_thread, ptr); + if (i % 100000 == 0) + printf(">>>%s: i=%d\n", myname, i); + /* + * ACL_METER_TIME("--32--"); + */ + } + + /* 释放线程池 */ + acl_pthread_pool_destroy(thr_pool); + printf(">>>%s: time cost: %ld\n", myname, (long) (time(NULL) - begin)); +} + +/*----------------------------------------------------------------------------*/ + +static int __use_base = 0; + +static void *test_tls_thread(void *arg acl_unused) +{ +#define MAX 30 + const char *myname = "test_tls_thread"; + void *ptr[MAX]; + time_t begin; + int i, j, k, *nalloc = (int*) arg, nloop1, nloop2, n; + + n = *nalloc < 10000 ? 10000 : *nalloc; + nloop1 = 1000; + nloop2 = n / nloop1; + + time(&begin); + if (__use_base) { + for (j = 0; j < nloop1; j++) { + for (i = 0; i < nloop2; i++) { + for (k = 0; k < MAX; k++) + ptr[k] = malloc(128); + for (k = 0; k < MAX; k++) + free(ptr[k]); + } + } + } else { + for (j = 0; j < nloop1; j++) { + for (i = 0; i < nloop2; i++) { + for (k = 0; k < MAX; k++) + ptr[k] = acl_mymalloc(128); + for (k = 0; k < MAX; k++) + acl_myfree(ptr[k]); + } + } + } + printf(">>>%s(%d)(tid=%ld): time cose %d seconds\n", + myname, __LINE__, (long) acl_pthread_self(), + (int) (time(NULL) - begin)); + return (NULL); +} + +static void test_tls(int nthread, int nalloc) +{ + acl_pthread_attr_t attr; + acl_pthread_t *tids; + int i; + + printf(">>> test_tls: begin running(thread=%ld) ...\n", + (long) acl_pthread_self()); + tids = (acl_pthread_t*) acl_mycalloc(nthread, sizeof(acl_pthread_t)); + + acl_pthread_attr_init(&attr); + for (i = 0; i < nthread; i++) { + acl_pthread_create(&tids[i], &attr, test_tls_thread, &nalloc); + } + for (i = 0; i < nthread; i++) { + acl_pthread_join(tids[i], NULL); + printf(">>> test_tls: thread(%ld) over now\n", (long) tids[i]); + } +} + +static void usage(const char *procname) +{ + printf("usage: %s -h[help] -s[use slice] -t nthread -n nalloc -g nalloc_gc -b[use malloc/free] -p[use thread pool]\n", procname); +} + +int main(int argc, char *argv[]) +{ + int base = 8, nslice = 1024, nalloc_gc = 1000000, use_thrpool = 0; + int use_slice = 0, nthread = 2, nalloc = 10000000; + unsigned int slice_flag = ACL_SLICE_FLAG_GC2 | ACL_SLICE_FLAG_RTGC_OFF; + char ch, *ptr; + + while ((ch = getopt(argc, argv, "hst:n:g:bp")) > 0) { + switch (ch) { + case 'h': + usage(argv[0]); + return (0); + case 's': + use_slice = 1; + break; + case 't': + nthread = atoi(optarg); + if (nthread < 0) + nthread = 2; + break; + case 'n': + nalloc = atoi(optarg); + if (nalloc < 100) + nalloc = 100; + break; + case 'g': + nalloc_gc = atoi(optarg); + if (nalloc_gc < 100) + nalloc_gc = 100; + break; + case 'b': + __use_base = 1; + break; + case 'p': + use_thrpool = 1; + break; + default: + break; + } + } + + acl_init(); + if (use_slice) + acl_mem_slice_init(base, nslice, nalloc_gc, slice_flag); + if (use_thrpool) + thread_pool_tls(nthread, nalloc); + else + test_tls(nthread, nalloc); + if (use_slice) { + acl_mem_slice_destroy(); + + /* 取消内存管理的勾子函数,恢复为缺省状态 */ + acl_mem_unhook(); + } + + /* 缺省的内存分配与释放 */ + + ptr = acl_mymalloc(128); + acl_myfree(ptr); + + printf("Input any key to exit ...\n"); + getchar(); + return (0); +} + diff --git a/samples/smtp/Makefile b/samples/smtp/Makefile new file mode 100644 index 000000000..b82138e99 --- /dev/null +++ b/samples/smtp/Makefile @@ -0,0 +1,2 @@ +include ../Makefile_cpp.in +PROG = smtp diff --git a/samples/smtp/main.cpp b/samples/smtp/main.cpp new file mode 100644 index 000000000..40f24b1cf --- /dev/null +++ b/samples/smtp/main.cpp @@ -0,0 +1,117 @@ +#include "lib_acl.h" + +static int echo_cmd(ACL_VSTREAM *client, const char *s) +{ + char buf[1024]; + int ret; + + if (acl_vstream_fprintf(client, "%s\r\n", s) == ACL_VSTREAM_EOF) { + printf("send %s error\n", s); + return (-1); + } + + ret = acl_vstream_gets_nonl(client, buf, sizeof(buf)); + if (ret <= 0) { + printf("get reply for %s error\n", s); + return (-1); + } + printf(">>%s\n", s); + printf("<<%s\n", buf); + return (0); +} + +int main(int argc, char *argv[]) +{ + ACL_VSTREAM *client; + const char *addr; + char buf[1024]; + int ret, i = 0; + + if (argc != 2) { + printf("usage: %s addr\n", argv[0]); + return (0); + } + + addr = argv[1]; + + while (1) { + i++; + client = acl_vstream_connect(addr, ACL_BLOCKING, 0, 0, 4096); + if (client == NULL) { + printf("connect %s error(%s)\n", addr, acl_last_serror()); + return (1); + } + + // get welcome banner + ACL_METER_TIME("---begin get banner---"); + ret = acl_vstream_gets_nonl(client, buf, sizeof(buf)); + if (ret > 0) { + printf("gets from %s: %s\n", addr, buf); + } else { + printf("gets welcome error\n"); + acl_vstream_close(client); + break; + } + ACL_METER_TIME("---end get banner---"); + + ACL_METER_TIME("---begin helo---"); + if (echo_cmd(client, "helo 126.com") < 0) { + acl_vstream_close(client); + break; + } + ACL_METER_TIME("---end helo ---"); + + ACL_METER_TIME("---begin mail from---"); + if (echo_cmd(client, "mail from: ") < 0) { + acl_vstream_close(client); + break; + } + ACL_METER_TIME("---end mail from---"); + + ACL_METER_TIME("---begin rcpt to---"); + //if (echo_cmd(client, "rcpt to: ") < 0) { + if (echo_cmd(client, "rcpt to: ") < 0) { + acl_vstream_close(client); + break; + } + ACL_METER_TIME("---end rcpt to---"); + printf(">>>>----------------- i: %d----------------<<<\n", i); + +#if 0 + ACL_METER_TIME("---begin data---"); + if (echo_cmd(client, "data") < 0) { + acl_vstream_close(client); + break; + } + + ACL_METER_TIME("---end data---"); + + ACL_METER_TIME("---begin .---"); + if (echo_cmd(client, ".") < 0) { + acl_vstream_close(client); + break; + } + + ACL_METER_TIME("---end .---"); + +#elif 1 + ACL_METER_TIME("---begin rset---"); + if (echo_cmd(client, "rset") < 0) { + acl_vstream_close(client); + break; + } + ACL_METER_TIME("---end rset---"); +#else + ACL_METER_TIME("---begin quit---"); + if (echo_cmd(client, "quit") < 0) { + acl_vstream_close(client); + break; + } + ACL_METER_TIME("---end quit---"); +#endif + + acl_vstream_close(client); + } + + return (0); +} diff --git a/samples/smtp_client/Makefile b/samples/smtp_client/Makefile new file mode 100644 index 000000000..dd57b653e --- /dev/null +++ b/samples/smtp_client/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = smtp_client diff --git a/samples/smtp_client/smtp_client.c b/samples/smtp_client/smtp_client.c new file mode 100644 index 000000000..d31d6e9b8 --- /dev/null +++ b/samples/smtp_client/smtp_client.c @@ -0,0 +1,238 @@ +/* smtp_client.cpp : 定义控制台应用程序的入口点 */ + +#include "lib_acl.h" +#include "lib_protocol.h" + +#ifdef WIN32 +#define snprintf _snprintf +#endif + +static int smtp_sender(void) +{ + SMTP_CLIENT* conn; + char addr[128], line[256]; + + acl_printf("please enter smtp server addr: "); + if (acl_gets_nonl(line, sizeof(line)) == NULL) + { + acl_puts("invalid smtp server addr"); + return -1; + } + + if (strchr(line, ':') == NULL) + snprintf(addr, sizeof(addr), "%s:25", line); + else + snprintf(addr, sizeof(addr), "%s", line); + + /* 连接 SMTP 服务器 */ + conn = smtp_open(addr, 60, 60, 1024); + if (conn == NULL) + { + acl_printf("connect %s error %s\r\n", addr, acl_last_serror()); + return -1; + } + else + acl_printf("connect smtpd(%s) ok\r\n", addr); + + /* 从 SMTP 服务器获得欢迎信息 */ + if (smtp_get_banner(conn) != 0) + { + acl_puts("get banner from server error"); + smtp_close(conn); + return -1; + } + else + acl_printf(">smtpd: %s\r\n", conn->buf); + + /* 向 SMTP 服务器发送 EHLO/HELO 命令 */ + if (smtp_greet(conn, "localhost", 0) != 0) + { + acl_printf("send ehlo cmd error: %s\r\n", conn->buf); + smtp_close(conn); + return -1; + } + else + acl_printf(">smtpd: %s\r\n", conn->buf); + + /* 用户是否需要进行 SMTP 身份认证 */ + acl_printf("Do you want to auth login? n[y|n]: "); + if (acl_gets_nonl(line, sizeof(line)) == NULL) + { + acl_puts("invalid input"); + smtp_close(conn); + return -1; + } + + /* 对用户身份进行 SMTP 身份认证 */ + else if (strcasecmp(line, "Y") == 0) + { + char user[128], pass[128]; + acl_printf("Please input user account: "); + if (acl_gets_nonl(user, sizeof(user)) == NULL) + { + acl_puts("input invalid"); + smtp_close(conn); + return -1; + } + + acl_printf("Please input user password: "); + if (acl_gets_nonl(pass, sizeof(pass)) == NULL) + { + acl_puts("input invalid"); + smtp_close(conn); + return -1; + } + + /* 开始进行 SMTP 身份认证 */ + if (smtp_auth(conn, user, pass) != 0) + { + acl_printf("smtp auth(%s, %s) error: %s, code: %d\r\n", + user, pass, conn->buf, conn->smtp_code); + smtp_close(conn); + return -1; + } + else + acl_printf(">smtpd: %s\r\n", conn->buf); + } + + /* 获得发件人邮箱地址 */ + acl_printf("please input sender's email: "); + if (acl_gets_nonl(line, sizeof(line)) == NULL) + { + acl_puts("invalid sender's email"); + smtp_close(conn); + return -1; + } + + /* 发送 MAIL FROM: 命令 */ + if (smtp_mail(conn, line) != 0) + { + acl_printf("smtp send MAIL FROM %s error\r\n", line); + smtp_close(conn); + return -1; + } + else + acl_printf(">smtpd: %s\r\n", conn->buf); + + /* 发送 RCPT TO: 命令 */ + while (1) + { + acl_printf("please input mail recipients: "); + if (acl_gets_nonl(line, sizeof(line)) == NULL) + { + acl_puts("invalid mail recipients"); + smtp_close(conn); + return -1; + } + + /* 发送 RCPT TO: 命令 */ + else if (smtp_rcpt(conn, line) != 0) + { + acl_printf("send RCPT TO: %s error: %s, code: %d\r\n", + line, conn->buf, conn->smtp_code); + smtp_close(conn); + return -1; + } + else + acl_printf(">smtpd: %s\r\n", conn->buf); + + acl_printf("Do you want to add another recipients? n[y|n]: "); + if (acl_gets_nonl(line, sizeof(line)) == NULL) + { + acl_puts("input invalid"); + smtp_close(conn); + return -1; + } + else if (strcasecmp(line, "y") != 0) + break; + } + + /* 发送 DATA: 命令 */ + if (smtp_data(conn) != 0) + { + acl_printf("send DATA error %s, code: %d\r\n", + conn->buf, conn->smtp_code); + smtp_close(conn); + return -1; + } + else + acl_printf(">smtpd: %s\r\n", conn->buf); + + /* 从终端接收用户的输入的邮件内容并发往 SMTP 服务器 */ + acl_puts("Please enter the email data below, end with \\r\\n.\\r\\n"); + + while (1) + { + if (acl_gets_nonl(line, sizeof(line)) == NULL) + { + acl_puts("readline error"); + smtp_close(conn); + return -1; + } + if (strcmp(line, ".") == 0) + break; + if (smtp_printf(conn, "%s\r\n", line) != 0) + { + acl_printf("send data to smtpd error, data: %s\r\n", line); + smtp_close(conn); + return -1; + } + } + + /* 发送 \r\n.\r\n 表示邮件数据发送完毕 */ + if (smtp_data_end(conn) != 0) + { + acl_printf("send . error: %s, code: %d\r\n", + conn->buf, conn->smtp_code); + smtp_close(conn); + return -1; + } + else + acl_printf(">smtpd: %s\r\n", conn->buf); + + /* 发送 QUIT 命令 */ + if (smtp_quit(conn) != 0) + { + acl_printf("smtp QUIT error: %s\r\n", conn->buf); + smtp_close(conn); + return -1; + } + else + acl_printf(">smtpd: %s\r\n", conn->buf); + + smtp_close(conn); + return 0; +} + +int main(void) +{ + int ret; + +#ifdef WIN32 + acl_init(); +#endif + + while (1) + { + char line[128]; + + ret = smtp_sender(); + if (ret == -1) + break; + acl_printf("Do you want to send another email? n[y|n]: "); + if (acl_gets_nonl(line, sizeof(line)) == NULL) + { + acl_puts("invalid input"); + break; + } + else if (strcasecmp(line, "y") != 0) + break; + } + +#ifdef WIN32 + acl_vstream_printf("enter any key to exit\r\n"); + acl_vstream_getc(ACL_VSTREAM_IN); +#endif + + return ret; +} diff --git a/samples/smtp_client/smtp_client.vcproj b/samples/smtp_client/smtp_client.vcproj new file mode 100644 index 000000000..a1e54c54a --- /dev/null +++ b/samples/smtp_client/smtp_client.vcproj @@ -0,0 +1,233 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/string/Makefile b/samples/string/Makefile new file mode 100644 index 000000000..3589772ff --- /dev/null +++ b/samples/string/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = string diff --git a/samples/string/main.c b/samples/string/main.c new file mode 100644 index 000000000..28c50accc --- /dev/null +++ b/samples/string/main.c @@ -0,0 +1,35 @@ +#include "lib_acl.h" + +int main(void) +{ + char *src = acl_mystrdup("hello \tworld! you're welcome to China!"); + char *ptr, *src_saved; + ACL_VSTRING* buf; + const char* s = "hello"; + unsigned int n1 = (unsigned int) -1; + unsigned long n2 = (unsigned long) -1; + unsigned long long n3 = (unsigned long long) -1; + + src_saved = src; + printf("src: %s\r\n", src); + while ((ptr = acl_mystrtok(&src, " \t!'")) != NULL) + { + printf("--------------------------------------\r\n"); + printf("ptr: |%s|\r\n", ptr); + printf("src: |%s|\r\n", src); + printf("src_saved: |%s|\r\n", src_saved); + } + + acl_myfree(src_saved); + + printf("----------------------------------------------\r\n"); + + buf = acl_vstring_alloc(1); + acl_vstring_sprintf(buf, "%*lu, s: %s, n1: %20u, n2: %20lu, n3: %20llu\n", + (int) sizeof(unsigned long) * 4, (unsigned long) getpid(), + s, n1, n2, n3); + printf("buf: %s\r\n", acl_vstring_str(buf)); + acl_vstring_free(buf); + + return 0; +} diff --git a/samples/thread/Makefile b/samples/thread/Makefile new file mode 100644 index 000000000..c313b8cd8 --- /dev/null +++ b/samples/thread/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = thread diff --git a/samples/thread/main.c b/samples/thread/main.c new file mode 100644 index 000000000..1e0e9328a --- /dev/null +++ b/samples/thread/main.c @@ -0,0 +1,324 @@ + +#include "stdlib/acl_define_unix.h" +#ifdef ACL_UNIX +# ifndef _GNU_SOURCE +# define _GNU_SOURCE +# endif +# include +#endif + +#include "lib_acl.h" +#include + +typedef struct THREAD_CTX { + int i; +} THREAD_CTX; + +#if 0 +typedef volatile int pthread_spinlock_t; +extern int pthread_spin_init (pthread_spinlock_t *__lock, int __pshared); +extern int pthread_spin_lock (pthread_spinlock_t *__lock); +extern int pthread_spin_unlock (pthread_spinlock_t *__lock); +#endif + +static void workq_thread_fn(int event acl_unused, void *argv acl_unused) +{ + static __thread unsigned int i = 0; + printf(">>main thread id: %u\n", (unsigned int) acl_main_thread_self()); + + printf("thread start!\r\n"); + printf("thread(%lu): before i++, i=%d\r\n", (unsigned long int) acl_pthread_self(), i); + i++; + printf("thread(%lu): after i++, i=%d\r\n", (unsigned long int) acl_pthread_self(), i); + sleep(2); +} + +static void test_workq(void) +{ + ACL_WORK_QUEUE *wq = acl_workq_create(2, 60, NULL, NULL); + + acl_workq_add(wq, workq_thread_fn, 0, NULL); + sleep(1); + acl_workq_add(wq, workq_thread_fn, 0, NULL); +} + +static void *test_thread_fn(void *arg) +{ + THREAD_CTX *ctx = (THREAD_CTX*) arg; + + ctx->i++; + printf("current tid is: %lu\r\n", (unsigned long int) acl_pthread_self()); + + return (ctx); +} + +#ifdef ACL_UNIX +static pthread_spinlock_t __spin_lock; +#endif + +static void *thread_nested_mutex(void *arg) +{ + acl_pthread_mutex_t *mutex = (acl_pthread_mutex_t*) arg; + int m = 2; + int i, n = 100000000; + time_t begin, end; + +#ifdef ACL_UNIX + if (0) { + printf("tid: %lu, begin spin lock\n", (unsigned long int) acl_pthread_self()); + + time(&begin); + for (i = 0; i < n; i++) { + pthread_spin_lock(&__spin_lock); + pthread_spin_unlock(&__spin_lock); + } + time(&end); + printf("tid: %lu, lock over, spin, time: %ld\n", + (unsigned long int) acl_pthread_self(), (long) end - begin); + } +#endif + + if (1) { + printf("tid: %lu, begin lock mutex\n", + (unsigned long int) acl_pthread_self()); + time(&begin); + for (i = 0; i < n; i++) { + acl_thread_mutex_lock(mutex); + acl_thread_mutex_unlock(mutex); + } + time(&end); + printf("tid: %lu, lock mutex ok, nested: %d, sleep %d seconds, time: %ld\n", + (unsigned long int) acl_pthread_self(), + acl_thread_mutex_nested(mutex), m, (long) end - begin); + } + + if (0) { + sleep(m); + printf("tid: %lu, wakeup, begin unlock\n", + (unsigned long int) acl_pthread_self()); + for (i = 0; i < n; i++) + acl_thread_mutex_unlock(mutex); + time(&end); + printf("tid: %lu, time: %ld, exit now\n", + (unsigned long int) acl_pthread_self(), (long) end - begin); + } + + return (NULL); +} + +static void test_nested_mutex(void) +{ + acl_pthread_t tid; + acl_pthread_attr_t attr; + static acl_pthread_mutex_t mutex; + +#ifdef ACL_UNIX + pthread_spin_init(&__spin_lock, 0); +#endif + + acl_pthread_mutex_init(&mutex, NULL); + acl_pthread_attr_init(&attr); + acl_pthread_attr_setdetachstate(&attr, ACL_PTHREAD_CREATE_DETACHED); + acl_pthread_create(&tid, &attr, thread_nested_mutex, &mutex); + acl_pthread_create(&tid, &attr, thread_nested_mutex, &mutex); +} + +#ifdef ACL_UNIX +static pthread_mutex_t mutex_init1 = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t mutex_init2 = PTHREAD_MUTEX_INITIALIZER; + +static void test_thread(void) +{ + acl_pthread_t tid; + acl_pthread_attr_t attr; + THREAD_CTX ctx, *pctx; + void *return_arg; + unsigned int id; + + acl_pthread_mutex_lock(&mutex_init1); + printf("lock mutex_init1 ok\n"); + acl_pthread_mutex_lock(&mutex_init2); + printf("lock mutex_init2 ok\n"); + + ctx.i = 0; + acl_pthread_attr_init(&attr); + acl_pthread_create(&tid, &attr, test_thread_fn, &ctx); + acl_pthread_join(tid, (void**) &return_arg); + pctx = (THREAD_CTX*) return_arg; + memcpy(&id, &tid, sizeof(id)); + printf("ctx.i=%d, pctx->i=%d, the thread id is: %u\r\n", + ctx.i, pctx->i, id); +} +#endif + +static void free_vstring(void *arg) +{ + const char *myname = "free_vstring"; + ACL_VSTRING *buf = (ACL_VSTRING*) arg; + + acl_vstring_free(buf); + printf("%s: tid=%d, free vstring ok\n", myname, (int) acl_pthread_self()); +} + +static void *test_tls_thread(void *arg acl_unused) +{ + const char *myname = "test_tls_thread"; + static acl_pthread_key_t key = -1; + ACL_VSTRING *buf; + time_t begin; + int i; + unsigned long tid; + const char *p = acl_last_serror(); + + printf("%s(%d): last serror: %s, %p\n", myname, __LINE__, p, p); + + printf(">>>%s(%d)(tid=%d): key = %d\n", myname, __LINE__, (int) acl_pthread_self(), key); + sleep(1); + printf(">>>%s(%d)(tid=%d): key = %d\n", myname, __LINE__, (int) acl_pthread_self(), key); + if (1) { + time(&begin); + for (i = 0; i < 10000000; i++) { + buf = acl_pthread_tls_get(&key); + if (buf == NULL) { + printf(">>>%s(tid=%d): buf null, key = %d\n", + myname, (int) acl_pthread_self(), key); + buf = acl_vstring_alloc(256); + acl_pthread_tls_set(key, buf, free_vstring); + } + tid = acl_pthread_self(); + } + printf(">>>%s(%d)(tid=%d): time cose %d seconds, tid: %ld\n", + myname, __LINE__, (int) acl_pthread_self(), + (int) (time(NULL) - begin), tid); + acl_vstring_sprintf(buf, "%s, tid=%d", myname, acl_pthread_self()); + printf(">>>%s: buf=%s\n", myname, acl_vstring_str(buf)); + } else { + time(&begin); + for (i = 0; i < 1000000; i++) { + buf = acl_vstring_alloc(256); + acl_vstring_free(buf); + } + printf(">>>%s(%d)(tid=%d): time cose %d seconds\n", + myname, __LINE__, (int) acl_pthread_self(), + (int) (time(NULL) - begin)); + } + sleep(1); + return (NULL); +} + +static void test_tls(void) +{ + acl_pthread_attr_t attr; + acl_pthread_t t1, t2; + + acl_pthread_attr_init(&attr); + acl_pthread_create(&t1, &attr, test_tls_thread, NULL); + acl_pthread_create(&t2, &attr, test_tls_thread, NULL); + acl_pthread_join(t1, NULL); + acl_pthread_join(t2, NULL); + printf(">>> test_tls: over now\n"); +} + +static int __init_once_key = 0; +static void init_once(void) +{ + const char *myname = "init_once"; + + __init_once_key++; + printf("%s(%d, tid=%d): __init_once_key=%d\n", + myname, __LINE__, (int) acl_pthread_self(), __init_once_key); +} + +static void free_buf(void *ctx) +{ + ACL_VSTRING *buf = (ACL_VSTRING*) ctx; + acl_vstring_free(buf); + printf(">>>>%s(tid=%d): free vstring ok\n", + __FUNCTION__, (int) acl_pthread_self()); +} + +static void free_vbuf(void *ctx) +{ + ACL_VSTRING *buf = (ACL_VSTRING*) ctx; + acl_vstring_free(buf); + printf(">>>>%s(tid=%d): free vstring ok\n", + __FUNCTION__, (int) acl_pthread_self()); +} + +static acl_pthread_once_t once_control = ACL_PTHREAD_ONCE_INIT; +static void *test_once_thread(void *arg acl_unused) +{ + ACL_VSTRING *buf; + static acl_pthread_key_t buf_key = -1; + static __thread ACL_VSTRING *__vbuf = NULL; + + acl_pthread_once(&once_control, init_once); + + if (__vbuf == NULL) { + __vbuf = acl_vstring_alloc(256); + acl_pthread_atexit_add(__vbuf, free_vbuf); + } + + buf = (ACL_VSTRING*) acl_pthread_tls_get(&buf_key); + if (buf == NULL) { + buf = acl_vstring_alloc(256); + acl_pthread_tls_set(buf_key, buf, free_buf); + } + + buf = (ACL_VSTRING*) acl_pthread_tls_get(&buf_key); + if (buf == NULL) + printf(">>>%s(tid=%d) buf null\n", __FUNCTION__, (int) acl_pthread_self()); + else + printf(">>>%s(tid=%d) buf not null\n", __FUNCTION__, (int) acl_pthread_self()); + + printf(">>>%s: in thread %d, last error: %s\n", + __FUNCTION__, (int) acl_pthread_self(), acl_last_serror()); + + return (NULL); +} + +static void test_pthread_once(void) +{ + acl_pthread_attr_t attr; + acl_pthread_t t1, t2; + + acl_pthread_attr_init(&attr); + acl_pthread_attr_setstacksize(&attr, 10240000); + acl_pthread_create(&t1, &attr, test_once_thread, NULL); + acl_pthread_create(&t2, &attr, test_once_thread, NULL); + acl_pthread_join(t1, NULL); + acl_pthread_join(t2, NULL); + printf(">>> test_pthread_once: over now, enter any key to exit...\n"); + getchar(); +} + +int main(int argc acl_unused, char *argv[] acl_unused) +{ + if (0) { + test_pthread_once(); + return (0); + } + + printf("%s(%d): last serror: %s, %p\n", __FUNCTION__, __LINE__, + acl_last_serror(), acl_last_serror()); + if (0) { + test_tls(); + return (0); + } + +#ifdef ACL_UNIX + test_thread(); +#endif + + printf(">>>>main tid: %u\n", (unsigned) acl_pthread_self()); + if (0) + test_nested_mutex(); + if (1) + test_workq(); + + while (1) { + sleep(10); + } + return (0); +} + diff --git a/samples/thread/thread.vcxproj b/samples/thread/thread.vcxproj new file mode 100644 index 000000000..60dbfb512 --- /dev/null +++ b/samples/thread/thread.vcxproj @@ -0,0 +1,186 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + ReleaseDll + Win32 + + + Release + Win32 + + + + thread + {DF044F15-C15D-4C69-9024-21235BC3C7E9} + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)thread.exe + %(AdditionalLibraryDirectories) + true + $(OutDir)thread.pdb + Console + MachineX86 + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)thread.exe + %(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + + + + + Disabled + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_DLL;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + EditAndContinue + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)thread.exe + %(AdditionalLibraryDirectories) + true + $(OutDir)thread.pdb + Console + MachineX86 + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_DLL;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)thread.exe + %(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + + + + + {b40213c2-507c-4c7f-a6e1-b850c9bdc27b} + false + + + + + + + + + \ No newline at end of file diff --git a/samples/thread/thread_vc2003.vcproj b/samples/thread/thread_vc2003.vcproj new file mode 100644 index 000000000..ed1f91188 --- /dev/null +++ b/samples/thread/thread_vc2003.vcproj @@ -0,0 +1,238 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/thread/valgrind.sh b/samples/thread/valgrind.sh new file mode 100644 index 000000000..335caf208 --- /dev/null +++ b/samples/thread/valgrind.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +valgrind --tool=memcheck --leak-check=yes -v ./thread_test diff --git a/samples/thread_pool/Makefile b/samples/thread_pool/Makefile new file mode 100644 index 000000000..dd53f1103 --- /dev/null +++ b/samples/thread_pool/Makefile @@ -0,0 +1,2 @@ +include ../Makefile_cpp.in +PROG = thread_pool diff --git a/samples/thread_pool/main.cpp b/samples/thread_pool/main.cpp new file mode 100644 index 000000000..bb2a25f87 --- /dev/null +++ b/samples/thread_pool/main.cpp @@ -0,0 +1,237 @@ +#include "lib_acl.h" +#include + +/** + * 用户自定义数据结构 + */ +typedef struct THREAD_CTX { + acl_pthread_pool_t *thr_pool; + int i; +} THREAD_CTX; + +/* 全局性静态变量 */ +static acl_pthread_pool_t *__thr_pool = NULL; + +/* 线程局部存储变量(C99支持此种方式声明,方便许多) */ +static __thread unsigned int __local = 0; + +static void free_buf_fn(void *arg) +{ + ACL_VSTRING *buf = (ACL_VSTRING*) arg; + + printf(">> current thread id=%u, buf = %s\r\n", + (unsigned int) acl_pthread_self(), acl_vstring_str(buf)); + acl_vstring_free(buf); +} + +static void worker_thread(void *arg) +{ + THREAD_CTX *ctx = (THREAD_CTX*) arg; /* 获得用户自定义对象 */ + unsigned int i = 0; + static __thread ACL_VSTRING *buf1 = NULL; + static __thread ACL_VSTRING *buf2 = NULL; + + /* 仅是验证参数传递过程 */ + assert(ctx->thr_pool == __thr_pool); + + if (buf1 == NULL) + buf1 = acl_vstring_alloc(256); + if (buf2 == NULL) + buf2 = acl_vstring_alloc(256); + + acl_vstring_sprintf(buf1, "buf1: tid=%u", + (unsigned int) acl_pthread_self()); + acl_vstring_sprintf(buf2, "buf2: tid=%u", + (unsigned int) acl_pthread_self()); + /* 注册函数,当该线程退出时自动释放 buf 内存空间 */ + acl_pthread_atexit_add(buf1, free_buf_fn); + acl_pthread_atexit_add(buf2, free_buf_fn); + + while (i < 5) { + if (__local != i) + acl_msg_fatal("__local=%d invalid", __local); + printf("thread id=%u, i=%d, __local=%d\r\n", + (unsigned int) acl_pthread_self(), ctx->i, __local); + i++; + /* 在本线程中将线程局部变量加1 */ + __local++; + sleep(1); + } + + acl_myfree(ctx); + + /* 至此,该工作线程进入空闲状态,直到空闲超时退出 */ +} + +static int on_thread_init(void *arg) +{ + const char *myname = "on_thread_init"; + acl_pthread_pool_t *thr_pool = (acl_pthread_pool_t*) arg; + + /* 判断一下,仅是为了验证参数传递过程 */ + assert(thr_pool == __thr_pool); + printf("%s: thread(%u) init now\r\n", myname, (unsigned int) acl_pthread_self()); + + /* 返回0表示继续执行该线程获得的新任务,返回-1表示停止执行该任务 */ + return (0); +} + +static void on_thread_exit(void *arg) +{ + const char *myname = "on_thread_exit"; + acl_pthread_pool_t *thr_pool = (acl_pthread_pool_t*) arg; + + /* 判断一下,仅是为了验证参数传递过程 */ + assert(thr_pool == __thr_pool); + printf("%s: thread(%u) exit now\r\n", myname, (unsigned int) acl_pthread_self()); +} + +static void run_thread_pool(acl_pthread_pool_t *thr_pool) +{ + THREAD_CTX *ctx; /* 用户自定义参数 */ + + /* 设置全局静态变量 */ + __thr_pool = thr_pool; + + /* 设置线程开始时的回调函数 */ + (void) acl_pthread_pool_atinit(thr_pool, on_thread_init, thr_pool); + + /* 设置线程退出时的回调函数 */ + (void) acl_pthread_pool_atfree(thr_pool, on_thread_exit, thr_pool); + + ctx = (THREAD_CTX*) acl_mycalloc(1, sizeof(THREAD_CTX)); + assert(ctx); + ctx->thr_pool = thr_pool; + ctx->i = 0; + + /** + * 向线程池中添加第一个任务,即启动第一个工作线程 + * @param wq 线程池句柄 + * @param worker_thread 工作线程的回调函数 + * @param event_type 此处写0即可 + * @param ctx 用户定义参数 + */ + acl_pthread_pool_add(thr_pool, worker_thread, ctx); + sleep(1); + + ctx = (THREAD_CTX*) acl_mycalloc(1, sizeof(THREAD_CTX)); + assert(ctx); + ctx->thr_pool = thr_pool; + ctx->i = 1; + /* 向线程池中添加第二个任务,即启动第二个工作线程 */ + acl_pthread_pool_add(thr_pool, worker_thread, ctx); +} + +static void main_thread_atexit(void *arg) +{ + ACL_VSTRING *buf = (ACL_VSTRING*) arg; + + printf("main thread exit now, tid=%u, buf=%s\r\n", + (unsigned int) acl_pthread_self(), acl_vstring_str(buf)); + printf("in the main thread_atexit, input any key to exit\r\n"); + getchar(); +} + +static acl_pthread_pool_t *thr_pool_create(int threads, int timeout) +{ + acl_pthread_pool_attr_t attr; + acl_pthread_pool_t *thr_pool; + + acl_pthread_pool_attr_init(&attr); + acl_pthread_pool_attr_set_threads_limit(&attr, threads); + acl_pthread_pool_attr_set_idle_timeout(&attr, timeout); + + /* 创建半驻留线程句柄 */ + thr_pool = acl_pthread_pool_create(&attr); + assert(thr_pool); + return (thr_pool); +} + +typedef struct { + ACL_VSTREAM *fp; + int i; +} RUN_CTX; +static acl_pthread_mutex_t __mutex; +static void run_thread(void *arg) +{ + RUN_CTX *ctx = (RUN_CTX*) arg; + + acl_pthread_mutex_lock(&__mutex); + acl_vstream_fprintf(ctx->fp, "hello world, hello world, hello world, hello world, i: %d\n", ctx->i); + acl_pthread_mutex_unlock(&__mutex); + acl_myfree(ctx); +} + +static void test_thread_pool(void) +{ + acl_pthread_pool_t *thr_pool; + ACL_VSTREAM *fp = acl_vstream_fopen("test.log", O_WRONLY | O_CREAT, 0600, 4096); + int i; + + acl_pthread_mutex_init(&__mutex, NULL); + thr_pool = acl_thread_pool_create(10, 10); + + for (i = 0; i < 1000000; i++) { + RUN_CTX *ctx = (RUN_CTX*) acl_mymalloc(sizeof(RUN_CTX)); + ctx->fp = fp; + ctx->i = i; + acl_pthread_pool_add(thr_pool, run_thread, ctx); + } + + acl_pthread_pool_destroy(thr_pool); + acl_pthread_mutex_destroy(&__mutex); + acl_vstream_close(fp); +} + +int main(int argc acl_unused, char *argv[] acl_unused) +{ + acl_pthread_pool_t *thr_pool; + int max_threads = 20; /* 最多并发20个线程 */ + int idle_timeout = 10; /* 每个工作线程空闲10秒后自动退出 */ + static __thread ACL_VSTRING *buf = NULL; + + if (1) { + test_thread_pool(); + exit (0); + } + + buf = acl_vstring_alloc(256); + acl_vstring_sprintf(buf, "in main thread, id=%u", + (unsigned int) acl_pthread_self()); + acl_pthread_atexit_add(buf, main_thread_atexit); + + + thr_pool = thr_pool_create(max_threads, idle_timeout); + run_thread_pool(thr_pool); + + if (0) { + /* 如果立即运行 acl_pthread_pool_destroy,则由于调用了线程池销毁函数, + * 主线程便立刻通知空闲线程退出,所有空闲线程不必等待空闲超时时间便可退出, + */ + printf("> wait all threads to be idle and free thread pool\r\n"); + /* 立即销毁线程池 */ + acl_pthread_pool_destroy(thr_pool); + } else { + /* 因为不立即调用 acl_pthread_pool_destroy,所有所有空闲线程都是当空闲 + * 超时时间到达后才退出 + */ + while (1) { + int ret; + + ret = acl_pthread_pool_size(thr_pool); + if (ret == 0) + break; + printf("> current threads in thread pool is: %d\r\n", ret); + sleep(1); + } + /* 线程池中的工作线程数为0时销毁线程池 */ + printf("> all worker thread exit now\r\n"); + acl_pthread_pool_destroy(thr_pool); + } + + /* 主线程等待用户在终端输入任意字符后退出 */ + printf("> enter any key to exit\r\n"); + getchar(); + + return (0); +} diff --git a/samples/thread_pool/thread_pool.vcxproj b/samples/thread_pool/thread_pool.vcxproj new file mode 100644 index 000000000..f043dba23 --- /dev/null +++ b/samples/thread_pool/thread_pool.vcxproj @@ -0,0 +1,182 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + ReleaseDll + Win32 + + + Release + Win32 + + + + thread_pool + {143D67EE-85E1-4456-AD99-6FDE7B1F1469} + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)thread_pool.exe + true + $(OutDir)thread_pool.pdb + Console + MachineX86 + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)thread_pool.exe + true + Console + true + true + MachineX86 + + + + + Disabled + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_DLL;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + EditAndContinue + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)thread_pool.exe + true + $(OutDir)thread_pool.pdb + Console + MachineX86 + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_DLL;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)thread_pool.exe + true + Console + true + true + MachineX86 + + + + + {b40213c2-507c-4c7f-a6e1-b850c9bdc27b} + false + + + + + + + + + \ No newline at end of file diff --git a/samples/thread_pool/thread_pool_vc2003.vcproj b/samples/thread_pool/thread_pool_vc2003.vcproj new file mode 100644 index 000000000..51175e8c0 --- /dev/null +++ b/samples/thread_pool/thread_pool_vc2003.vcproj @@ -0,0 +1,234 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/thread_pool_client/Makefile b/samples/thread_pool_client/Makefile new file mode 100644 index 000000000..36a1e0b2e --- /dev/null +++ b/samples/thread_pool_client/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = thread_pool_client diff --git a/samples/thread_pool_client/main.c b/samples/thread_pool_client/main.c new file mode 100644 index 000000000..c1adcec11 --- /dev/null +++ b/samples/thread_pool_client/main.c @@ -0,0 +1,101 @@ +#include +#include "lib_acl.h" + +static char __addr[128]; +static int __len = 1024; + +static void thread_run(void *arg) +{ + int i, n = *((int*) arg); + ACL_VSTREAM *client = acl_vstream_connect(__addr, + ACL_BLOCKING, 60, 60, 1024); + char *buf, *line; + int len; + + printf("tid: %ld\r\n", (long) acl_pthread_self()); + + if (client == NULL) { + printf("connect %s error\r\n", __addr); + return; + } + + buf = acl_mymalloc(__len + 3); + for (i = 0; i < __len; i++) + buf[i] = 'x'; + buf[i] = '\r'; + buf[i + 1] = '\n'; + buf[i + 2] = 0; + + len = strlen(buf); + line = acl_mymalloc(len + 1); + + for (i = 0; i < n; i++) { + if (acl_vstream_writen(client, buf, strlen(buf)) == ACL_VSTREAM_EOF) + { + printf("write error\r\n"); + break; + } + if (acl_vstream_gets(client, line, len + 1) == ACL_VSTREAM_EOF) + { + printf("gets error\r\n"); + break; + } + if (n <= 100 || (i > 0 && i % 1000 == 0)) + printf("tid: %ld, i: %d, n: %d\r\n", + (long) acl_pthread_self(), i, n); + } + acl_myfree(buf); + acl_myfree(line); + acl_vstream_close(client); +} + +static void usage(const char *procname) +{ + printf("usage: %s -h[help] -s addr[ip:port] -n nthreads -c count_per_thread -l line_length[1024]\r\n", procname); +} + +int main(int argc, char **argv) +{ + int ch, nthreads = 2, count = 100, i; + acl_pthread_pool_t *thrpool; + + snprintf(__addr, sizeof(__addr), "127.0.0.1:5001"); + + while ((ch = getopt(argc, argv, "hs:n:c:l:")) > 0) { + switch (ch) { + case 'h': + usage(argv[0]); + return 0; + case 's': + snprintf(__addr, sizeof(__addr), "%s", optarg); + break; + case 'n': + nthreads = atoi(optarg); + if (nthreads <= 0) + nthreads = 2; + break; + case 'c': + count = atoi(optarg); + if (count <= 0) + count = 100; + break; + case 'l': + __len = atoi(optarg); + if (__len <= 0) + __len = 1024; + break; + default: + break; + } + } + + thrpool = acl_thread_pool_create(nthreads, 120); + + ACL_METER_TIME("----begin----"); + for (i = 0; i < nthreads; i++) + acl_pthread_pool_add(thrpool, thread_run, &count); + + acl_pthread_pool_destroy(thrpool); + ACL_METER_TIME("----end----"); + return 0; +} diff --git a/samples/tls/client/Makefile b/samples/tls/client/Makefile new file mode 100644 index 000000000..0334b7693 --- /dev/null +++ b/samples/tls/client/Makefile @@ -0,0 +1,120 @@ +SHELL = /bin/sh +CC = gcc +#CC = g++ +AR = ar +ARFL = rv +RANLIB = ranlib + +CFLAGS = -c -g -W -Wall -Wcast-qual -Wcast-align \ +-Waggregate-return -Wmissing-prototypes \ +-Wpointer-arith -Werror -Wshadow -pedantic -O2 \ +-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO \ +-Wno-long-long \ +-DUSE_TLS +########################################################### +#Check system: +# Linux, SunOS, Solaris, BSD variants, AIX, HP-UX +SYSLIB = +CHECKSYSRES = @echo "Unknow system type!";exit 1 +UNIXNAME = $(shell uname -sm) + +# For FreeBSD +ifeq ($(findstring FreeBSD, $(UNIXNAME)), FreeBSD) + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DFREEBSD -D_REENTRANT -pedantic +endif + +#Path for Linux +ifeq ($(findstring Linux, $(UNIXNAME)), Linux) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DLINUX2 + SYSLIB = -lcrypt -lpthread +endif + +#Path for SunOS +ifeq ($(findstring SunOS, $(UNIXNAME)), SunOS) + ifeq ($(findstring 86, $(UNIXNAME)), 86) + SYSLIB = -lsocket -lnsl -lrt + endif + ifeq ($(findstring sun4u, $(UNIXNAME)), sun4u) + SYSLIB = -lsocket -lnsl -lrt + endif + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DSUNOS5 +endif + +#Path for HP-UX +ifeq ($(findstring HP-UX, $(UNIXNAME)), HP-UX) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + SYSLIB = -lpthread + CFLAGS += -DHP_UX -DHPUX11 + PLAT_NAME=hp-ux +endif + +#Find system type. +ifneq ($(SYSPATH),) + CHECKSYSRES = @echo "System is $(shell uname -sm)" +endif +########################################################### + +ACL_PATH = ../../../lib_acl +ACL_INC = $(ACL_PATH)/include +ACL_LIB = $(ACL_PATH)/lib + +TLS_PATH = ../../../lib_tls +TLS_INC = $(TLS_PATH)/include +TLS_LIB = $(TLS_PATH)/lib + +DICT_PATH = ../../../lib_dict +DICT_INC = $(DICT_PATH)/include +DICT_LIB = $(DICT_PATH)/lib + +LD_RUN_PATH = -Wl,-rpath,/opt/messenger/lib/mysql/linux/lib + +ALL_LIBS = -L$(TLS_LIB) -l_tls -L$(DICT_LIB) -l_dict -L$(ACL_LIB) -l_acl \ + -lssl -ldb $(SYSLIB) +# -L/home/zsx/download/openssl/bin/lib -lssl \ +# -L/home/zsx/download/openssl/bin/lib -lcrypto \ +# -ldb $(SYSLIB) + +INCLUDE = -I. -I../.. -I$(TLS_INC) -I$(DICT_INC) -I$(ACL_INC) +CFLAGS += $(INCLUDE) + +OUTPATH = ./ +OBJ_OUTPATH = $(OUTPATH) + +#Project's objs +SOURCES = $(wildcard *.c) +INCLUDES = $(wildcard *.h) +OBJS = $(patsubst %.c,$(OBJ_OUTPATH)%.o,$(SOURCES)) + +########################################################### + +PROG_NAME = tlscli + +.PHONY = clean +COMPILE = $(CC) $(CFLAGS) + +all: RM $(PROG_NAME) + +RM: + rm -f $(PROG_NAME) + +$(PROG_NAME): $(OBJS) + $(CC) -o $(PROG_NAME) $(OBJS) $(LIB_NAME_PATH) $(ALL_LIBS) + +$(OBJ_OUTPATH)%.o: %.c *.h + $(COMPILE) -o $@ $< + +clean: + rm -f $(OBJS) $(PROG_NAME) + +rebuild: clean all diff --git a/samples/tls/client/bin/conf/cacert.pem b/samples/tls/client/bin/conf/cacert.pem new file mode 100644 index 000000000..1f961cbff --- /dev/null +++ b/samples/tls/client/bin/conf/cacert.pem @@ -0,0 +1,58 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 99:db:fb:a0:7d:64:c7:e4 + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=cn, ST=bj, O=hx, OU=hx, CN=zsxxsz/emailAddress=zsxxsz@263.net + Validity + Not Before: Jul 3 02:54:41 2009 GMT + Not After : Jul 2 02:54:41 2012 GMT + Subject: C=cn, ST=bj, O=hx, OU=hx, CN=zsxxsz/emailAddress=zsxxsz@263.net + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (1024 bit) + Modulus: + 00:ad:46:24:9c:e3:60:e0:86:47:4f:11:78:d4:bc: + e6:cb:f9:d1:0e:16:25:9a:d3:7d:d6:a8:b1:26:cb: + d3:4b:d0:f2:3d:1b:71:e5:8c:fb:71:f7:6a:92:eb: + 0f:66:b1:f2:2e:09:b3:9b:32:ef:28:d1:f4:0d:0b: + 5a:b6:a9:a6:d7:42:77:a7:8a:42:12:f5:b6:21:50: + 9c:6c:e2:bd:6d:8c:d0:bd:89:00:17:af:8f:a8:f0: + 83:eb:8c:8d:71:07:4f:c4:34:b9:cf:28:32:99:98: + a2:3c:2c:e9:3c:ec:c3:0a:5b:c2:8d:64:79:d7:f7: + 86:d7:00:51:14:fd:46:8f:9f + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + 5C:E4:76:38:12:00:15:9D:0D:41:CB:0C:AA:0D:F3:8C:FC:8E:E0:90 + X509v3 Authority Key Identifier: + keyid:5C:E4:76:38:12:00:15:9D:0D:41:CB:0C:AA:0D:F3:8C:FC:8E:E0:90 + + X509v3 Basic Constraints: + CA:TRUE + Signature Algorithm: sha1WithRSAEncryption + 76:ec:7c:bb:44:e9:cc:10:5d:8f:51:53:fc:32:f3:8e:c7:7d: + d9:08:ae:46:5b:08:52:be:21:db:da:61:8c:1f:d8:1c:00:1e: + 24:12:a7:a1:2b:23:cf:c2:d1:78:63:a6:34:38:0e:b8:f4:08: + fa:60:49:93:26:a7:a0:37:5b:a3:79:06:77:1e:9d:cd:e5:a5: + 99:06:89:c4:34:6f:57:4d:7e:4c:b9:64:91:e1:f5:4e:02:1c: + 2e:28:28:d6:7f:9b:c1:71:1e:0c:ef:51:d1:65:16:3a:1a:75: + 2e:5c:93:dd:a5:4b:c5:4f:f2:c5:d7:1d:cd:7e:7d:33:a1:2b: + 2c:e0 +-----BEGIN CERTIFICATE----- +MIICljCCAf+gAwIBAgIJAJnb+6B9ZMfkMA0GCSqGSIb3DQEBBQUAMGQxCzAJBgNV +BAYTAmNuMQswCQYDVQQIDAJiajELMAkGA1UECgwCaHgxCzAJBgNVBAsMAmh4MQ8w +DQYDVQQDDAZ6c3h4c3oxHTAbBgkqhkiG9w0BCQEWDnpzeHhzekAyNjMubmV0MB4X +DTA5MDcwMzAyNTQ0MVoXDTEyMDcwMjAyNTQ0MVowZDELMAkGA1UEBhMCY24xCzAJ +BgNVBAgMAmJqMQswCQYDVQQKDAJoeDELMAkGA1UECwwCaHgxDzANBgNVBAMMBnpz +eHhzejEdMBsGCSqGSIb3DQEJARYOenN4eHN6QDI2My5uZXQwgZ8wDQYJKoZIhvcN +AQEBBQADgY0AMIGJAoGBAK1GJJzjYOCGR08ReNS85sv50Q4WJZrTfdaosSbL00vQ +8j0bceWM+3H3apLrD2ax8i4Js5sy7yjR9A0LWrapptdCd6eKQhL1tiFQnGzivW2M +0L2JABevj6jwg+uMjXEHT8Q0uc8oMpmYojws6Tzswwpbwo1kedf3htcAURT9Ro+f +AgMBAAGjUDBOMB0GA1UdDgQWBBRc5HY4EgAVnQ1BywyqDfOM/I7gkDAfBgNVHSME +GDAWgBRc5HY4EgAVnQ1BywyqDfOM/I7gkDAMBgNVHRMEBTADAQH/MA0GCSqGSIb3 +DQEBBQUAA4GBAHbsfLtE6cwQXY9RU/wy847HfdkIrkZbCFK+IdvaYYwf2BwAHiQS +p6ErI8/C0XhjpjQ4Drj0CPpgSZMmp6A3W6N5Bncenc3lpZkGicQ0b1dNfky5ZJHh +9U4CHC4oKNZ/m8FxHgzvUdFlFjoadS5ck92lS8VP8sXXHc1+fTOhKyzg +-----END CERTIFICATE----- diff --git a/samples/tls/client/bin/conf/foo-cert.pem b/samples/tls/client/bin/conf/foo-cert.pem new file mode 100644 index 000000000..3df177c26 --- /dev/null +++ b/samples/tls/client/bin/conf/foo-cert.pem @@ -0,0 +1,61 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 99:db:fb:a0:7d:64:c7:e5 + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=cn, ST=bj, O=hx, OU=hx, CN=zsxxsz/emailAddress=zsxxsz@263.net + Validity + Not Before: Jul 3 02:55:25 2009 GMT + Not After : Jul 3 02:55:25 2010 GMT + Subject: C=cn, ST=bj, O=hx, OU=hx, CN=zsxxsz/emailAddress=zsxxsz@263.net + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (1024 bit) + Modulus: + 00:99:0a:16:d5:59:20:08:21:18:47:73:2d:32:3f: + 5b:18:f1:e2:d5:4b:93:4a:b2:f4:51:d0:bc:5d:5e: + 12:99:c5:a3:16:b1:98:64:e2:fa:31:b3:9e:e8:36: + bb:ac:1e:65:f4:cf:05:8e:e8:61:2e:27:a6:15:91: + b6:e8:93:ae:aa:29:3c:8e:65:f4:b5:e6:e2:ea:9c: + b5:7b:00:5a:b3:bd:bb:64:a3:9a:6b:c8:45:84:85: + 0e:27:f9:4d:72:1b:8b:20:76:2b:a6:b1:af:79:fc: + a5:cf:a6:c3:d9:7f:ad:cd:69:4b:bb:74:0e:04:a8: + cb:e4:c5:67:e6:b8:e0:97:0d + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + Netscape Comment: + OpenSSL Generated Certificate + X509v3 Subject Key Identifier: + AF:3D:BE:4C:E7:4D:F9:31:6C:93:26:D0:6D:CF:01:FC:2C:2F:D5:6A + X509v3 Authority Key Identifier: + keyid:5C:E4:76:38:12:00:15:9D:0D:41:CB:0C:AA:0D:F3:8C:FC:8E:E0:90 + + Signature Algorithm: sha1WithRSAEncryption + 11:a1:8c:aa:c9:85:ec:45:08:c6:9e:a5:ed:79:e2:1a:ac:f0: + 11:bd:8a:aa:ec:c6:bb:39:a6:c2:80:48:01:b7:27:4f:0c:3d: + 57:73:98:c7:68:11:a2:14:7c:dc:de:79:e0:dc:c2:82:d6:57: + b1:4b:2a:4d:d4:11:f0:4a:65:05:d3:26:82:9b:af:66:6f:62: + 57:b7:06:b2:d6:c5:d8:f7:2a:1a:74:83:11:f3:ba:44:16:48: + 6a:90:3c:38:7d:f9:32:79:b4:53:c0:ee:ef:09:5e:06:d2:eb: + 8f:3b:0d:1e:da:a0:ba:4a:ed:44:32:8a:36:02:e0:fa:ee:78: + 5e:40 +-----BEGIN CERTIFICATE----- +MIICwTCCAiqgAwIBAgIJAJnb+6B9ZMflMA0GCSqGSIb3DQEBBQUAMGQxCzAJBgNV +BAYTAmNuMQswCQYDVQQIDAJiajELMAkGA1UECgwCaHgxCzAJBgNVBAsMAmh4MQ8w +DQYDVQQDDAZ6c3h4c3oxHTAbBgkqhkiG9w0BCQEWDnpzeHhzekAyNjMubmV0MB4X +DTA5MDcwMzAyNTUyNVoXDTEwMDcwMzAyNTUyNVowZDELMAkGA1UEBhMCY24xCzAJ +BgNVBAgMAmJqMQswCQYDVQQKDAJoeDELMAkGA1UECwwCaHgxDzANBgNVBAMMBnpz +eHhzejEdMBsGCSqGSIb3DQEJARYOenN4eHN6QDI2My5uZXQwgZ8wDQYJKoZIhvcN +AQEBBQADgY0AMIGJAoGBAJkKFtVZIAghGEdzLTI/Wxjx4tVLk0qy9FHQvF1eEpnF +oxaxmGTi+jGznug2u6weZfTPBY7oYS4nphWRtuiTrqopPI5l9LXm4uqctXsAWrO9 +u2SjmmvIRYSFDif5TXIbiyB2K6axr3n8pc+mw9l/rc1pS7t0DgSoy+TFZ+a44JcN +AgMBAAGjezB5MAkGA1UdEwQCMAAwLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2Vu +ZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBSvPb5M5035MWyTJtBtzwH8LC/V +ajAfBgNVHSMEGDAWgBRc5HY4EgAVnQ1BywyqDfOM/I7gkDANBgkqhkiG9w0BAQUF +AAOBgQARoYyqyYXsRQjGnqXteeIarPARvYqq7Ma7OabCgEgBtydPDD1Xc5jHaBGi +FHzc3nng3MKC1lexSypN1BHwSmUF0yaCm69mb2JXtway1sXY9yoadIMR87pEFkhq +kDw4ffkyebRTwO7vCV4G0uuPOw0e2qC6Su1EMoo2AuD67nheQA== +-----END CERTIFICATE----- diff --git a/samples/tls/client/bin/conf/foo-key.pem b/samples/tls/client/bin/conf/foo-key.pem new file mode 100644 index 000000000..bc94ec4dd --- /dev/null +++ b/samples/tls/client/bin/conf/foo-key.pem @@ -0,0 +1,16 @@ +-----BEGIN PRIVATE KEY----- +MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAJkKFtVZIAghGEdz +LTI/Wxjx4tVLk0qy9FHQvF1eEpnFoxaxmGTi+jGznug2u6weZfTPBY7oYS4nphWR +tuiTrqopPI5l9LXm4uqctXsAWrO9u2SjmmvIRYSFDif5TXIbiyB2K6axr3n8pc+m +w9l/rc1pS7t0DgSoy+TFZ+a44JcNAgMBAAECgYBSAGHzt2m+cV09C63v+pqpZxKQ +D4rAv9rB7ALCVKHK22djxY1OoYBGGWTQMGOm+jLPVg44YLORs5T+gbFsNZWkq4BM +1OboClWK7fV5orw7DO8uboWHWjE9EhJoWNX3FXlqMGOtnqFB8WTx57gYj99SzXGV +eHgeY7Djrte9AAz40QJBAMpiMCZBnNrqMpeo1FOJT8r252q9I64FZwAfdK4Sjpsm +QBddzieRTjjHzAEKQZx3SA+o854xinqnk5lJV118K/MCQQDBlVfENPFSNSjJeLkL +bh11ek85PmbPgf6G1OekeTSK6teb6S8KuUz1pv5V1vwrtPD51z+NrWuo4jb8+Jgb +T/D/AkEAogzU+Qz4h+GW+RDaUrlUBvSEgFdKRoFU5ChLyUZaoaiTESKve8dBlv2E +QCDyQFLShJeH2ldYxrV/3fF33wcaOQJASofFErWPc6cj3O2t0MjEbsZ4WgG8c4gJ +BsBRrvE7WYCxIkXU5rwQ9UMmCMaMsAcqAAbvYQyztoHhyeOsLFfK4QJAQQnsVTlJ +S08gqbmljoCs3EZ4DHVIhmPJNDzlSR1UxXNlh/4TtHTJw/Qs8ESeSphsh3ApPz6p +ohLf+F0WjdK4JQ== +-----END PRIVATE KEY----- diff --git a/samples/tls/client/bin/tlscli.cf b/samples/tls/client/bin/tlscli.cf new file mode 100644 index 000000000..71ac6e657 --- /dev/null +++ b/samples/tls/client/bin/tlscli.cf @@ -0,0 +1,6 @@ + +service tlscli { + client_tls_loglevel = 0 + client_tls_scert_vd = 9 + client_starttls_tmout = 300 +} diff --git a/samples/tls/client/conf/cacert.pem b/samples/tls/client/conf/cacert.pem new file mode 100644 index 000000000..1f961cbff --- /dev/null +++ b/samples/tls/client/conf/cacert.pem @@ -0,0 +1,58 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 99:db:fb:a0:7d:64:c7:e4 + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=cn, ST=bj, O=hx, OU=hx, CN=zsxxsz/emailAddress=zsxxsz@263.net + Validity + Not Before: Jul 3 02:54:41 2009 GMT + Not After : Jul 2 02:54:41 2012 GMT + Subject: C=cn, ST=bj, O=hx, OU=hx, CN=zsxxsz/emailAddress=zsxxsz@263.net + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (1024 bit) + Modulus: + 00:ad:46:24:9c:e3:60:e0:86:47:4f:11:78:d4:bc: + e6:cb:f9:d1:0e:16:25:9a:d3:7d:d6:a8:b1:26:cb: + d3:4b:d0:f2:3d:1b:71:e5:8c:fb:71:f7:6a:92:eb: + 0f:66:b1:f2:2e:09:b3:9b:32:ef:28:d1:f4:0d:0b: + 5a:b6:a9:a6:d7:42:77:a7:8a:42:12:f5:b6:21:50: + 9c:6c:e2:bd:6d:8c:d0:bd:89:00:17:af:8f:a8:f0: + 83:eb:8c:8d:71:07:4f:c4:34:b9:cf:28:32:99:98: + a2:3c:2c:e9:3c:ec:c3:0a:5b:c2:8d:64:79:d7:f7: + 86:d7:00:51:14:fd:46:8f:9f + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + 5C:E4:76:38:12:00:15:9D:0D:41:CB:0C:AA:0D:F3:8C:FC:8E:E0:90 + X509v3 Authority Key Identifier: + keyid:5C:E4:76:38:12:00:15:9D:0D:41:CB:0C:AA:0D:F3:8C:FC:8E:E0:90 + + X509v3 Basic Constraints: + CA:TRUE + Signature Algorithm: sha1WithRSAEncryption + 76:ec:7c:bb:44:e9:cc:10:5d:8f:51:53:fc:32:f3:8e:c7:7d: + d9:08:ae:46:5b:08:52:be:21:db:da:61:8c:1f:d8:1c:00:1e: + 24:12:a7:a1:2b:23:cf:c2:d1:78:63:a6:34:38:0e:b8:f4:08: + fa:60:49:93:26:a7:a0:37:5b:a3:79:06:77:1e:9d:cd:e5:a5: + 99:06:89:c4:34:6f:57:4d:7e:4c:b9:64:91:e1:f5:4e:02:1c: + 2e:28:28:d6:7f:9b:c1:71:1e:0c:ef:51:d1:65:16:3a:1a:75: + 2e:5c:93:dd:a5:4b:c5:4f:f2:c5:d7:1d:cd:7e:7d:33:a1:2b: + 2c:e0 +-----BEGIN CERTIFICATE----- +MIICljCCAf+gAwIBAgIJAJnb+6B9ZMfkMA0GCSqGSIb3DQEBBQUAMGQxCzAJBgNV +BAYTAmNuMQswCQYDVQQIDAJiajELMAkGA1UECgwCaHgxCzAJBgNVBAsMAmh4MQ8w +DQYDVQQDDAZ6c3h4c3oxHTAbBgkqhkiG9w0BCQEWDnpzeHhzekAyNjMubmV0MB4X +DTA5MDcwMzAyNTQ0MVoXDTEyMDcwMjAyNTQ0MVowZDELMAkGA1UEBhMCY24xCzAJ +BgNVBAgMAmJqMQswCQYDVQQKDAJoeDELMAkGA1UECwwCaHgxDzANBgNVBAMMBnpz +eHhzejEdMBsGCSqGSIb3DQEJARYOenN4eHN6QDI2My5uZXQwgZ8wDQYJKoZIhvcN +AQEBBQADgY0AMIGJAoGBAK1GJJzjYOCGR08ReNS85sv50Q4WJZrTfdaosSbL00vQ +8j0bceWM+3H3apLrD2ax8i4Js5sy7yjR9A0LWrapptdCd6eKQhL1tiFQnGzivW2M +0L2JABevj6jwg+uMjXEHT8Q0uc8oMpmYojws6Tzswwpbwo1kedf3htcAURT9Ro+f +AgMBAAGjUDBOMB0GA1UdDgQWBBRc5HY4EgAVnQ1BywyqDfOM/I7gkDAfBgNVHSME +GDAWgBRc5HY4EgAVnQ1BywyqDfOM/I7gkDAMBgNVHRMEBTADAQH/MA0GCSqGSIb3 +DQEBBQUAA4GBAHbsfLtE6cwQXY9RU/wy847HfdkIrkZbCFK+IdvaYYwf2BwAHiQS +p6ErI8/C0XhjpjQ4Drj0CPpgSZMmp6A3W6N5Bncenc3lpZkGicQ0b1dNfky5ZJHh +9U4CHC4oKNZ/m8FxHgzvUdFlFjoadS5ck92lS8VP8sXXHc1+fTOhKyzg +-----END CERTIFICATE----- diff --git a/samples/tls/client/conf/foo-cert.pem b/samples/tls/client/conf/foo-cert.pem new file mode 100644 index 000000000..3df177c26 --- /dev/null +++ b/samples/tls/client/conf/foo-cert.pem @@ -0,0 +1,61 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 99:db:fb:a0:7d:64:c7:e5 + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=cn, ST=bj, O=hx, OU=hx, CN=zsxxsz/emailAddress=zsxxsz@263.net + Validity + Not Before: Jul 3 02:55:25 2009 GMT + Not After : Jul 3 02:55:25 2010 GMT + Subject: C=cn, ST=bj, O=hx, OU=hx, CN=zsxxsz/emailAddress=zsxxsz@263.net + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (1024 bit) + Modulus: + 00:99:0a:16:d5:59:20:08:21:18:47:73:2d:32:3f: + 5b:18:f1:e2:d5:4b:93:4a:b2:f4:51:d0:bc:5d:5e: + 12:99:c5:a3:16:b1:98:64:e2:fa:31:b3:9e:e8:36: + bb:ac:1e:65:f4:cf:05:8e:e8:61:2e:27:a6:15:91: + b6:e8:93:ae:aa:29:3c:8e:65:f4:b5:e6:e2:ea:9c: + b5:7b:00:5a:b3:bd:bb:64:a3:9a:6b:c8:45:84:85: + 0e:27:f9:4d:72:1b:8b:20:76:2b:a6:b1:af:79:fc: + a5:cf:a6:c3:d9:7f:ad:cd:69:4b:bb:74:0e:04:a8: + cb:e4:c5:67:e6:b8:e0:97:0d + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + Netscape Comment: + OpenSSL Generated Certificate + X509v3 Subject Key Identifier: + AF:3D:BE:4C:E7:4D:F9:31:6C:93:26:D0:6D:CF:01:FC:2C:2F:D5:6A + X509v3 Authority Key Identifier: + keyid:5C:E4:76:38:12:00:15:9D:0D:41:CB:0C:AA:0D:F3:8C:FC:8E:E0:90 + + Signature Algorithm: sha1WithRSAEncryption + 11:a1:8c:aa:c9:85:ec:45:08:c6:9e:a5:ed:79:e2:1a:ac:f0: + 11:bd:8a:aa:ec:c6:bb:39:a6:c2:80:48:01:b7:27:4f:0c:3d: + 57:73:98:c7:68:11:a2:14:7c:dc:de:79:e0:dc:c2:82:d6:57: + b1:4b:2a:4d:d4:11:f0:4a:65:05:d3:26:82:9b:af:66:6f:62: + 57:b7:06:b2:d6:c5:d8:f7:2a:1a:74:83:11:f3:ba:44:16:48: + 6a:90:3c:38:7d:f9:32:79:b4:53:c0:ee:ef:09:5e:06:d2:eb: + 8f:3b:0d:1e:da:a0:ba:4a:ed:44:32:8a:36:02:e0:fa:ee:78: + 5e:40 +-----BEGIN CERTIFICATE----- +MIICwTCCAiqgAwIBAgIJAJnb+6B9ZMflMA0GCSqGSIb3DQEBBQUAMGQxCzAJBgNV +BAYTAmNuMQswCQYDVQQIDAJiajELMAkGA1UECgwCaHgxCzAJBgNVBAsMAmh4MQ8w +DQYDVQQDDAZ6c3h4c3oxHTAbBgkqhkiG9w0BCQEWDnpzeHhzekAyNjMubmV0MB4X +DTA5MDcwMzAyNTUyNVoXDTEwMDcwMzAyNTUyNVowZDELMAkGA1UEBhMCY24xCzAJ +BgNVBAgMAmJqMQswCQYDVQQKDAJoeDELMAkGA1UECwwCaHgxDzANBgNVBAMMBnpz +eHhzejEdMBsGCSqGSIb3DQEJARYOenN4eHN6QDI2My5uZXQwgZ8wDQYJKoZIhvcN +AQEBBQADgY0AMIGJAoGBAJkKFtVZIAghGEdzLTI/Wxjx4tVLk0qy9FHQvF1eEpnF +oxaxmGTi+jGznug2u6weZfTPBY7oYS4nphWRtuiTrqopPI5l9LXm4uqctXsAWrO9 +u2SjmmvIRYSFDif5TXIbiyB2K6axr3n8pc+mw9l/rc1pS7t0DgSoy+TFZ+a44JcN +AgMBAAGjezB5MAkGA1UdEwQCMAAwLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2Vu +ZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBSvPb5M5035MWyTJtBtzwH8LC/V +ajAfBgNVHSMEGDAWgBRc5HY4EgAVnQ1BywyqDfOM/I7gkDANBgkqhkiG9w0BAQUF +AAOBgQARoYyqyYXsRQjGnqXteeIarPARvYqq7Ma7OabCgEgBtydPDD1Xc5jHaBGi +FHzc3nng3MKC1lexSypN1BHwSmUF0yaCm69mb2JXtway1sXY9yoadIMR87pEFkhq +kDw4ffkyebRTwO7vCV4G0uuPOw0e2qC6Su1EMoo2AuD67nheQA== +-----END CERTIFICATE----- diff --git a/samples/tls/client/conf/foo-key.pem b/samples/tls/client/conf/foo-key.pem new file mode 100644 index 000000000..bc94ec4dd --- /dev/null +++ b/samples/tls/client/conf/foo-key.pem @@ -0,0 +1,16 @@ +-----BEGIN PRIVATE KEY----- +MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAJkKFtVZIAghGEdz +LTI/Wxjx4tVLk0qy9FHQvF1eEpnFoxaxmGTi+jGznug2u6weZfTPBY7oYS4nphWR +tuiTrqopPI5l9LXm4uqctXsAWrO9u2SjmmvIRYSFDif5TXIbiyB2K6axr3n8pc+m +w9l/rc1pS7t0DgSoy+TFZ+a44JcNAgMBAAECgYBSAGHzt2m+cV09C63v+pqpZxKQ +D4rAv9rB7ALCVKHK22djxY1OoYBGGWTQMGOm+jLPVg44YLORs5T+gbFsNZWkq4BM +1OboClWK7fV5orw7DO8uboWHWjE9EhJoWNX3FXlqMGOtnqFB8WTx57gYj99SzXGV +eHgeY7Djrte9AAz40QJBAMpiMCZBnNrqMpeo1FOJT8r252q9I64FZwAfdK4Sjpsm +QBddzieRTjjHzAEKQZx3SA+o854xinqnk5lJV118K/MCQQDBlVfENPFSNSjJeLkL +bh11ek85PmbPgf6G1OekeTSK6teb6S8KuUz1pv5V1vwrtPD51z+NrWuo4jb8+Jgb +T/D/AkEAogzU+Qz4h+GW+RDaUrlUBvSEgFdKRoFU5ChLyUZaoaiTESKve8dBlv2E +QCDyQFLShJeH2ldYxrV/3fF33wcaOQJASofFErWPc6cj3O2t0MjEbsZ4WgG8c4gJ +BsBRrvE7WYCxIkXU5rwQ9UMmCMaMsAcqAAbvYQyztoHhyeOsLFfK4QJAQQnsVTlJ +S08gqbmljoCs3EZ4DHVIhmPJNDzlSR1UxXNlh/4TtHTJw/Qs8ESeSphsh3ApPz6p +ohLf+F0WjdK4JQ== +-----END PRIVATE KEY----- diff --git a/samples/tls/client/main.c b/samples/tls/client/main.c new file mode 100644 index 000000000..62055cf91 --- /dev/null +++ b/samples/tls/client/main.c @@ -0,0 +1,308 @@ +#include "lib_acl.h" + +#if defined(ACL_MS_WINDOWS) +#pragma comment(lib,"ws2_32") +#pragma comment(lib, "wsock32") +#endif + +#include +#include "tls.h" +#include "tls_params.h" +#ifdef ACL_UNIX +#include +#endif +#include + +static char *conf_file = "tlscli.cf"; +static char serv_addr[64]; + +int var_client_tls_loglevel; +int var_client_tls_scert_vd; +int var_client_starttls_tmout; +char *var_client_tls_cert_file; +char *var_client_tls_key_file; +char *var_client_tls_dcert_file; +char *var_client_tls_dkey_file; +char *var_client_tls_eccert_file; +char *var_client_tls_eckey_file; +char *var_client_tls_CAfile; +char *var_client_tls_CApath; +char *var_client_tls_fpt_dgst; + +static ACL_CONFIG_INT_TABLE int_table[] = { + { "client_tls_loglevel", 0, &var_client_tls_loglevel, 0, 0 }, + { "client_tls_scert_vd", 9, &var_client_tls_scert_vd, 0, 0 }, + { "client_starttls_tmout", 300, &var_client_starttls_tmout, 0, 0 }, + { 0, 0, 0, 0, 0 }, +}; + +static ACL_CONFIG_STR_TABLE str_table[] = { + { "client_tls_cert_file", "conf/foo-cert.pem", &var_client_tls_cert_file }, + { "client_tls_key_file", "conf/foo-key.pem", &var_client_tls_key_file }, + { "client_tls_dcert_file", "", &var_client_tls_dcert_file }, + { "client_tls_dkey_file", "", &var_client_tls_dkey_file }, + { "client_tls_eccert_file", "", &var_client_tls_eccert_file }, + { "client_tls_eckey_file", "", &var_client_tls_eckey_file }, + { "client_tls_CAfile", "conf/cacert.pem", &var_client_tls_CAfile }, + { "client_tls_CApath", "", &var_client_tls_CApath }, + { "client_tls_fpt_dgst", "sha1", &var_client_tls_fpt_dgst }, + { 0, 0, 0 }, +}; + +static TLS_CLIENT_INIT_PROPS init_props; + +static void init(void) +{ + acl_app_conf_load(conf_file); + + acl_get_app_conf_str_table(str_table); + acl_get_app_conf_int_table(int_table); + + tls_client_init(); + +#if 0 + TLS_CLIENT_SETUP(&init_props, + log_level = var_client_tls_loglevel, + verifydepth = var_client_tls_scert_vd, + cache_type = TLS_MGR_SCACHE_CLIENT, + cert_file = var_client_tls_cert_file, + key_file = var_client_tls_key_file, + dcert_file = var_client_tls_dcert_file, + dkey_file = var_client_tls_dkey_file, + eccert_file = var_client_tls_eccert_file, + eckey_file = var_client_tls_eckey_file, + CAfile = var_client_tls_CAfile, + CApath = var_client_tls_CApath, + fpt_dgst = var_client_tls_fpt_dgst); +#else + init_props.log_level = var_client_tls_loglevel; + init_props.verifydepth = var_client_tls_scert_vd; + init_props.cache_type = TLS_MGR_SCACHE_CLIENT; + init_props.cert_file = var_client_tls_cert_file; + init_props.key_file = var_client_tls_key_file; + init_props.dcert_file = var_client_tls_dcert_file; + init_props.dkey_file = var_client_tls_dkey_file; + init_props.eccert_file = var_client_tls_eccert_file; + init_props.eckey_file = var_client_tls_eckey_file; + init_props.CAfile = var_client_tls_CAfile; + init_props.CApath = var_client_tls_CApath; + init_props.fpt_dgst = var_client_tls_fpt_dgst; + + tls_client_setup(&init_props); +#endif +} + +static void usage(const char *procname) +{ + printf("usage: %s -h [help] -c conf_file -s server_addr\n", procname); +} + +#if 1 +static char *request = "GET /accounts/ServiceLogin?service=mail&passive=true&rm=false&continue=https%3A%2F%2Fmail.google.com%2Fmail%2F%3Fui%3Dhtml%26zy%3Dl&bsv=zpwhtygjntrz&ss=1&scc=1<mpl=default<mplcache=2 HTTP/1.1\r\n" + "HOST: www.google.com\r\n" + "\r\n"; +#elif 1 +static char *request = "GET / HTTP/1.1\r\n" + "HOST: www.google.com\r\n" + "\r\n"; +#elif 1 +static char *request = "GET /urchin.js HTTP/1.1\r\n" + "HOST: ssl.google-analytics.com\r\n" + "\r\n"; +#endif + +static void run_one(TLS_APPL_STATE *client_tls_ctx) +{ + ACL_VSTREAM *client; + TLS_SESS_STATE *client_sess_ctx; + TLS_CLIENT_START_PROPS tls_props; + char buf[4096]; + int i, ret; + time_t last, now; + + int tls_level = 2; + char *tls_nexthop = "test.com.cn"; + char *host = "test.com.cn"; + char *namaddrport = "test.com.cn"; + char *serverid = "service:addr:port:helo"; + char *tls_protocols = SSL_TXT_TLSV1; + char *tls_grade = "low"; /* high, medium, low, export, null */ + char *tls_exclusions = ""; + ACL_ARGV *tls_matchargv = 0; + + client = acl_vstream_connect(serv_addr, ACL_BLOCKING, 20, 30, 8192); + if (client == NULL) { + printf("connect %s error(%s)\n", serv_addr, acl_last_serror()); + return; + } + + acl_tcp_set_nodelay(ACL_VSTREAM_SOCK(client)); + +#if 0 + client_sess_ctx = TLS_CLIENT_START(&tls_props, + ctx = client_tls_ctx, + stream = client, + log_level = var_client_tls_loglevel, + timeout = var_client_starttls_tmout, + tls_level = tls_level, + nexthop = tls_nexthop, + host = host, + namaddr = namaddrport, + serverid = serverid, + protocols = tls_protocols, + cipher_grade = tls_grade, + cipher_exclusions = tls_exclusions, + matchargv = tls_matchargv, + fpt_dgst = var_client_tls_fpt_dgst); +#else + tls_props.ctx = client_tls_ctx; + tls_props.stream = client; + tls_props.log_level = var_client_tls_loglevel; + tls_props.timeout = var_client_starttls_tmout; + tls_props.tls_level = tls_level; + tls_props.nexthop = tls_nexthop; + tls_props.host = host; + tls_props.namaddr = namaddrport; + tls_props.serverid = serverid; + tls_props.protocols = tls_protocols; + tls_props.cipher_grade = tls_grade; + tls_props.cipher_exclusions = tls_exclusions; + tls_props.matchargv = tls_matchargv; + tls_props.fpt_dgst = var_client_tls_fpt_dgst; + + client_sess_ctx = tls_client_start(&tls_props); +#endif + + if (client_sess_ctx == NULL) { + printf("TLS_CLIENT_START error\n"); + acl_vstream_close(client); + return; + } + + if (tls_level >= TLS_LEV_VERIFY) { + if (!TLS_CERT_IS_TRUSTED(client_sess_ctx)) { + printf("Server certificate not trusted\n"); + } + } + + if (tls_level > TLS_LEV_ENCRYPT) { + if (!TLS_CERT_IS_MATCHED(client_sess_ctx)) { + printf("Server certificate not verified\n"); + } + } + + time(&last); + i = 0; + while (1) { + ret = acl_vstream_fprintf(client, "hello world\n"); + if (ret == ACL_VSTREAM_EOF) + goto END; + ret = acl_vstream_gets(client, buf, sizeof(buf)); + if (ret == ACL_VSTREAM_EOF) + goto END; + break; + i++; + if (i % 50000 == 0) { + time(&now); + printf("client: i=%d, time=%ld\n", i, now - last); + last = now; + } + } + +if (0) +{ + if (acl_vstream_writen(client, request, strlen(request)) == ACL_VSTREAM_EOF) + printf("write request error\n"); + else { + while (1) { + if (acl_vstream_gets_nonl(client, buf, sizeof(buf)) == ACL_VSTREAM_EOF) + break; + /* + printf("%s\n", buf); + */ + } + /* + printf("gets respond over now\n"); + */ + } +} + +END: + tls_client_stop(client_tls_ctx, client, var_client_starttls_tmout, 0, client_sess_ctx); + acl_vstream_close(client); +} + +static void *run_thread(void *arg acl_unused) +{ + int i, n = 1000000; + time_t last = time(NULL), now; + TLS_APPL_STATE *client_tls_ctx; + + client_tls_ctx = tls_client_create(&init_props); + if (client_tls_ctx == NULL) { + printf("tls_client_create error\n"); + return (NULL); + } + + for (i = 0; i < n; i++) { + run_one(client_tls_ctx); + if (i % 100 == 0) { + now = time(NULL); + printf("i: %d, time: %ld\n", i, now - last); + last = now; + } + } + + tls_free_app_context(client_tls_ctx); + return (NULL); +} + +static void run(void) +{ +#define MAX_THREAD 4 + acl_pthread_t tid[MAX_THREAD]; + acl_pthread_attr_t attr; + int i; + void *tmp; + + acl_pthread_attr_init(&attr); + /* + acl_pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + */ + for (i = 0; i < MAX_THREAD; i++) { + acl_pthread_create(&tid[i], &attr, run_thread, 0); + } + + for (i = 0; i < MAX_THREAD; i++) { + acl_pthread_join(tid[i], &tmp); + } +} + +int main(int argc, char *argv[]) +{ + char ch; + + acl_init(); + ACL_SAFE_STRNCPY(serv_addr, "127.0.0.1:443", sizeof(serv_addr)); + + while ((ch = getopt(argc, argv, "hc:s:")) > 0) { + switch (ch) { + case 'h': + usage(argv[0]); + exit (0); + case 'c': + conf_file = acl_mystrdup(optarg); + break; + case 's': + ACL_SAFE_STRNCPY(serv_addr, optarg, sizeof(serv_addr)); + break; + default: + break; + } + } + + init(); + run(); + acl_end(); + return (0); +} diff --git a/samples/tls/client/tls_client.vcproj b/samples/tls/client/tls_client.vcproj new file mode 100644 index 000000000..1519d5ba7 --- /dev/null +++ b/samples/tls/client/tls_client.vcproj @@ -0,0 +1,236 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/tls/client/tls_client.vcxproj b/samples/tls/client/tls_client.vcxproj new file mode 100644 index 000000000..92a1ee4bd --- /dev/null +++ b/samples/tls/client/tls_client.vcxproj @@ -0,0 +1,191 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + ReleaseDll + Win32 + + + Release + Win32 + + + + {1759A405-8572-4A70-8C14-16E7FCF4D899} + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\..\lib_acl\include;..\..\..\lib_tls\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;USE_TLS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + libeay32.lib;ssleay32.lib;%(AdditionalDependencies) + tls_client.exe + ..\..\..\lib\openssl;..\..\..\lib\bdb;%(AdditionalLibraryDirectories) + true + $(OutDir)tls_client.pdb + Console + MachineX86 + + + + + ..\..\..\lib_acl\include;..\..\..\lib_tls\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;USE_TLS;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + libeay32.lib;ssleay32.lib;%(AdditionalDependencies) + $(OutDir)tls_client.exe + ..\..\..\lib\openssl;..\..\..\lib\bdb;%(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + + + + + Disabled + ..\..\..\lib_acl\include;..\..\..\lib_tls\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;USE_TLS;ACL_DLL;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + EditAndContinue + + + ws2_32.lib;libeay32.lib;ssleay32.lib;%(AdditionalDependencies) + tls_client.exe + ..\..\..\lib\openssl;..\..\..\lib\bdb;%(AdditionalLibraryDirectories) + true + $(OutDir)tls_client.pdb + Console + MachineX86 + + + + + ..\..\..\lib_acl\include;..\..\..\lib_tls\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;USE_TLS;ACL_DLL;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + $(OutDir)tls_client.exe + true + Console + true + true + MachineX86 + + + + + {b40213c2-507c-4c7f-a6e1-b850c9bdc27b} + false + + + {9e6e9fe9-eaac-44ba-b463-70de0233822e} + false + + + {389fde47-7f16-4dd4-b37a-27918be745b6} + false + + + + + + + + + \ No newline at end of file diff --git a/samples/tls/client/tlscli.cf b/samples/tls/client/tlscli.cf new file mode 100644 index 000000000..71ac6e657 --- /dev/null +++ b/samples/tls/client/tlscli.cf @@ -0,0 +1,6 @@ + +service tlscli { + client_tls_loglevel = 0 + client_tls_scert_vd = 9 + client_starttls_tmout = 300 +} diff --git a/samples/tls/server/Makefile b/samples/tls/server/Makefile new file mode 100644 index 000000000..73c591ef9 --- /dev/null +++ b/samples/tls/server/Makefile @@ -0,0 +1,121 @@ +SHELL = /bin/sh +CC = gcc +#CC = g++ +AR = ar +ARFL = rv +RANLIB = ranlib + +CFLAGS = -c -g -W -Wall -Wcast-qual -Wcast-align \ +-Waggregate-return -Wmissing-prototypes \ +-Wpointer-arith -Wshadow -pedantic -O2 \ +-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO \ +-Wno-long-long \ +-DUSE_TLS +# -Werror +########################################################### +#Check system: +# Linux, SunOS, Solaris, BSD variants, AIX, HP-UX +SYSLIB = +CHECKSYSRES = @echo "Unknow system type!";exit 1 +UNIXNAME = $(shell uname -sm) + +# For FreeBSD +ifeq ($(findstring FreeBSD, $(UNIXNAME)), FreeBSD) + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DFREEBSD -D_REENTRANT -pedantic +endif + +#Path for Linux +ifeq ($(findstring Linux, $(UNIXNAME)), Linux) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DLINUX2 + SYSLIB = -lcrypt -lpthread +endif + +#Path for SunOS +ifeq ($(findstring SunOS, $(UNIXNAME)), SunOS) + ifeq ($(findstring 86, $(UNIXNAME)), 86) + SYSLIB = -lsocket -lnsl -lrt + endif + ifeq ($(findstring sun4u, $(UNIXNAME)), sun4u) + SYSLIB = -lsocket -lnsl -lrt + endif + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DSUNOS5 +endif + +#Path for HP-UX +ifeq ($(findstring HP-UX, $(UNIXNAME)), HP-UX) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + SYSLIB = -lpthread + CFLAGS += -DHP_UX -DHPUX11 + PLAT_NAME=hp-ux +endif + +#Find system type. +ifneq ($(SYSPATH),) + CHECKSYSRES = @echo "System is $(shell uname -sm)" +endif +########################################################### + +ACL_PATH = ../../../lib_acl +ACL_INC = $(ACL_PATH)/include +ACL_LIB = $(ACL_PATH)/lib + +TLS_PATH = ../../../lib_tls +TLS_INC = $(TLS_PATH)/include +TLS_LIB = $(TLS_PATH)/lib + +DICT_PATH = ../../../lib_dict +DICT_INC = $(DICT_PATH)/include +DICT_LIB = $(DICT_PATH)/lib + +LD_RUN_PATH = -Wl,-rpath,/opt/messenger/lib/mysql/linux/lib + +ALL_LIBS = -L$(TLS_LIB) -l_tls -L$(DICT_LIB) -l_dict -L$(ACL_LIB) -l_acl \ + -lssl -ldb $(SYSLIB) +# -L/home/zsx/download/openssl/bin/lib -lssl \ +# -L/home/zsx/download/openssl/bin/lib -lcrypto \ +# -ldb $(SYSLIB) + +INCLUDE = -I. -I$(TLS_INC) -I$(DICT_INC) -I$(ACL_INC) +CFLAGS += $(INCLUDE) + +OUTPATH = ./ +OBJ_OUTPATH = $(OUTPATH) + +#Project's objs +SOURCES = $(wildcard *.c) +INCLUDES = $(wildcard *.h) +OBJS = $(patsubst %.c,$(OBJ_OUTPATH)%.o,$(SOURCES)) + +########################################################### + +PROG_NAME = tlssvr + +.PHONY = clean +COMPILE = $(CC) $(CFLAGS) + +all: RM $(PROG_NAME) + +RM: + rm -f $(PROG_NAME) + +$(PROG_NAME): $(OBJS) + $(CC) -o $(PROG_NAME) $(OBJS) $(LIB_NAME_PATH) $(ALL_LIBS) + +$(OBJ_OUTPATH)%.o: %.c *.h + $(COMPILE) -o $@ $< + +clean: + rm -f $(OBJS) $(PROG_NAME) + +rebuild: clean all diff --git a/samples/tls/server/conf/bak/cacert.pem b/samples/tls/server/conf/bak/cacert.pem new file mode 100644 index 000000000..2df484d57 --- /dev/null +++ b/samples/tls/server/conf/bak/cacert.pem @@ -0,0 +1,58 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 8a:71:b6:97:ac:93:93:ae + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=cn, ST=bj, O=hx, OU=hx, CN=zsxxsz/emailAddress=zsxxsz@263.net + Validity + Not Before: Jul 9 05:40:15 2009 GMT + Not After : Jul 8 05:40:15 2012 GMT + Subject: C=cn, ST=bj, O=hx, OU=hx, CN=zsxxsz/emailAddress=zsxxsz@263.net + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (1024 bit) + Modulus: + 00:a1:46:7b:66:24:96:93:50:5d:68:78:ad:78:64: + 68:b0:13:43:fe:f4:04:5c:ee:31:85:66:68:09:a0: + 59:c3:4b:a3:a8:21:3b:3d:9e:1a:06:71:b5:17:44: + ea:a6:2e:2d:a7:d0:c7:e3:ed:0d:ca:1d:b3:5c:92: + 0c:9c:a9:5e:7c:66:85:12:e0:92:21:38:71:3e:f0: + 7c:db:ba:e9:f8:57:f5:79:47:3b:a0:8a:4c:91:11: + 43:1c:62:91:9a:4b:f7:d1:25:fc:c6:9c:27:12:df: + 2f:b5:cf:f5:8d:56:b7:77:68:72:67:ab:81:0a:ba: + a6:38:82:35:04:d4:e0:79:51 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + 08:7D:CB:91:88:10:BA:75:F8:23:BE:DC:E9:5A:D4:CD:2E:43:D6:FB + X509v3 Authority Key Identifier: + keyid:08:7D:CB:91:88:10:BA:75:F8:23:BE:DC:E9:5A:D4:CD:2E:43:D6:FB + + X509v3 Basic Constraints: + CA:TRUE + Signature Algorithm: sha1WithRSAEncryption + 7d:1e:4e:fc:3f:f1:2b:48:64:96:e6:a2:02:1b:97:66:0f:85: + af:4c:43:d6:a5:da:a2:3e:73:55:34:9f:07:b1:6f:11:08:cf: + 46:29:24:da:5a:f0:81:92:4d:fa:c7:ff:c5:ed:08:49:b3:73: + 6b:56:7a:84:50:d5:b0:f8:89:0a:f1:e9:e5:af:a2:aa:87:95: + 66:aa:1d:6f:db:00:24:1a:4a:47:e5:74:6b:cf:32:0e:1c:24: + 1b:ab:d0:6f:de:59:3c:e3:46:59:2a:61:1f:ae:35:d4:ee:a0: + 44:65:64:e3:0c:b3:ce:26:26:5e:80:fa:33:4d:f6:9f:1a:d9: + 7a:74 +-----BEGIN CERTIFICATE----- +MIICljCCAf+gAwIBAgIJAIpxtpesk5OuMA0GCSqGSIb3DQEBBQUAMGQxCzAJBgNV +BAYTAmNuMQswCQYDVQQIDAJiajELMAkGA1UECgwCaHgxCzAJBgNVBAsMAmh4MQ8w +DQYDVQQDDAZ6c3h4c3oxHTAbBgkqhkiG9w0BCQEWDnpzeHhzekAyNjMubmV0MB4X +DTA5MDcwOTA1NDAxNVoXDTEyMDcwODA1NDAxNVowZDELMAkGA1UEBhMCY24xCzAJ +BgNVBAgMAmJqMQswCQYDVQQKDAJoeDELMAkGA1UECwwCaHgxDzANBgNVBAMMBnpz +eHhzejEdMBsGCSqGSIb3DQEJARYOenN4eHN6QDI2My5uZXQwgZ8wDQYJKoZIhvcN +AQEBBQADgY0AMIGJAoGBAKFGe2YklpNQXWh4rXhkaLATQ/70BFzuMYVmaAmgWcNL +o6ghOz2eGgZxtRdE6qYuLafQx+PtDcods1ySDJypXnxmhRLgkiE4cT7wfNu66fhX +9XlHO6CKTJERQxxikZpL99El/MacJxLfL7XP9Y1Wt3docmergQq6pjiCNQTU4HlR +AgMBAAGjUDBOMB0GA1UdDgQWBBQIfcuRiBC6dfgjvtzpWtTNLkPW+zAfBgNVHSME +GDAWgBQIfcuRiBC6dfgjvtzpWtTNLkPW+zAMBgNVHRMEBTADAQH/MA0GCSqGSIb3 +DQEBBQUAA4GBAH0eTvw/8StIZJbmogIbl2YPha9MQ9al2qI+c1U0nwexbxEIz0Yp +JNpa8IGSTfrH/8XtCEmzc2tWeoRQ1bD4iQrx6eWvoqqHlWaqHW/bACQaSkfldGvP +Mg4cJBur0G/eWTzjRlkqYR+uNdTuoERlZOMMs84mJl6A+jNN9p8a2Xp0 +-----END CERTIFICATE----- diff --git a/samples/tls/server/conf/bak/foo-cert.pem b/samples/tls/server/conf/bak/foo-cert.pem new file mode 100644 index 000000000..a1b4e71d1 --- /dev/null +++ b/samples/tls/server/conf/bak/foo-cert.pem @@ -0,0 +1,61 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 8a:71:b6:97:ac:93:93:af + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=cn, ST=bj, O=hx, OU=hx, CN=zsxxsz/emailAddress=zsxxsz@263.net + Validity + Not Before: Jul 9 05:42:20 2009 GMT + Not After : Jul 9 05:42:20 2010 GMT + Subject: C=cn, ST=bj, O=hx, OU=hx, CN=zsxxsz@263.net/emailAddress=zsxxsz@263.net + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (1024 bit) + Modulus: + 00:bc:d8:a3:4c:be:48:d5:ac:fc:30:4f:4b:23:61: + 4f:20:ed:30:77:b2:f8:ba:42:4c:9a:cd:2a:75:c7: + 52:13:28:83:ba:af:b2:3b:77:29:81:a5:78:d0:75: + 2a:a2:d9:e2:71:ba:d9:05:62:ea:38:d3:d9:c4:73: + ab:54:90:26:94:b1:e3:c9:51:7a:25:b3:c3:cb:45: + 83:15:35:6e:55:3d:61:ab:f2:0d:49:5a:e2:6d:0b: + a0:d3:ab:4c:8a:ee:25:70:59:76:d9:af:63:0d:d6: + b8:d7:c6:30:0c:b6:4a:61:f3:f7:c0:12:61:f6:e5: + 4a:f5:54:ce:04:45:ed:5e:7b + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + Netscape Comment: + OpenSSL Generated Certificate + X509v3 Subject Key Identifier: + AE:94:B0:7F:68:BC:FB:AE:66:AF:51:CF:6F:2B:82:5E:D7:36:08:55 + X509v3 Authority Key Identifier: + keyid:08:7D:CB:91:88:10:BA:75:F8:23:BE:DC:E9:5A:D4:CD:2E:43:D6:FB + + Signature Algorithm: sha1WithRSAEncryption + 97:a0:48:f3:31:b2:f1:2e:7f:2a:2d:7d:99:7c:a8:3a:b6:bc: + be:d0:c5:a8:50:26:05:a0:8a:4c:e8:3b:ec:fe:1d:cb:f4:84: + 67:71:f1:bb:04:69:f9:d7:21:6a:08:d2:d5:e3:91:58:f4:3c: + 11:b4:b9:9c:d0:8f:98:09:18:14:0c:34:50:18:b2:53:0b:0d: + d8:af:a2:2f:59:0b:f9:d6:7f:b6:8c:1f:85:87:46:20:c7:cf: + 0b:3b:a4:dc:9f:b5:92:f5:d8:23:0c:ed:b1:aa:cf:36:ab:5f: + 85:44:47:6d:ea:4e:f5:07:b0:17:fb:25:31:4b:be:37:63:b6: + 8e:2e +-----BEGIN CERTIFICATE----- +MIICyTCCAjKgAwIBAgIJAIpxtpesk5OvMA0GCSqGSIb3DQEBBQUAMGQxCzAJBgNV +BAYTAmNuMQswCQYDVQQIDAJiajELMAkGA1UECgwCaHgxCzAJBgNVBAsMAmh4MQ8w +DQYDVQQDDAZ6c3h4c3oxHTAbBgkqhkiG9w0BCQEWDnpzeHhzekAyNjMubmV0MB4X +DTA5MDcwOTA1NDIyMFoXDTEwMDcwOTA1NDIyMFowbDELMAkGA1UEBhMCY24xCzAJ +BgNVBAgMAmJqMQswCQYDVQQKDAJoeDELMAkGA1UECwwCaHgxFzAVBgNVBAMMDnpz +eHhzekAyNjMubmV0MR0wGwYJKoZIhvcNAQkBFg56c3h4c3pAMjYzLm5ldDCBnzAN +BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAvNijTL5I1az8ME9LI2FPIO0wd7L4ukJM +ms0qdcdSEyiDuq+yO3cpgaV40HUqotnicbrZBWLqONPZxHOrVJAmlLHjyVF6JbPD +y0WDFTVuVT1hq/INSVribQug06tMiu4lcFl22a9jDda418YwDLZKYfP3wBJh9uVK +9VTOBEXtXnsCAwEAAaN7MHkwCQYDVR0TBAIwADAsBglghkgBhvhCAQ0EHxYdT3Bl +blNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFK6UsH9ovPuuZq9R +z28rgl7XNghVMB8GA1UdIwQYMBaAFAh9y5GIELp1+CO+3Ola1M0uQ9b7MA0GCSqG +SIb3DQEBBQUAA4GBAJegSPMxsvEufyotfZl8qDq2vL7QxahQJgWgikzoO+z+Hcv0 +hGdx8bsEafnXIWoI0tXjkVj0PBG0uZzQj5gJGBQMNFAYslMLDdivoi9ZC/nWf7aM +H4WHRiDHzws7pNyftZL12CMM7bGqzzarX4VER23qTvUHsBf7JTFLvjdjto4u +-----END CERTIFICATE----- diff --git a/samples/tls/server/conf/bak/foo-key.pem b/samples/tls/server/conf/bak/foo-key.pem new file mode 100644 index 000000000..98b497d5c --- /dev/null +++ b/samples/tls/server/conf/bak/foo-key.pem @@ -0,0 +1,16 @@ +-----BEGIN PRIVATE KEY----- +MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBALzYo0y+SNWs/DBP +SyNhTyDtMHey+LpCTJrNKnXHUhMog7qvsjt3KYGleNB1KqLZ4nG62QVi6jjT2cRz +q1SQJpSx48lReiWzw8tFgxU1blU9YavyDUla4m0LoNOrTIruJXBZdtmvYw3WuNfG +MAy2SmHz98ASYfblSvVUzgRF7V57AgMBAAECgYEAu142p+4kVd1MWqJR6sihugmc +DSeFoUgmuXDWsAUTae7IxHGOZXHVvMxxEmMt6mZERpMcwDtkKP4JEuGxHDXqD+oS +mOKJ+bN+Y02CKoAJW2HSoOMP+L1dBgjqkL+2E/ufiYMLcjQk5rMsbfgUMMPnyo8z +Tqn9rehxI7TXtuS1AAECQQDfT37As7CIo3YRIqi5sqj8WAJCUcQo4oMCif184Ebr +tpbd4rCkNFH/TEwQTkIbjGbXLihXGlWRebbBPv+QYtT7AkEA2H2aOvf7+0iO28nH +Lu416SvrfaZ/WPgW/Q4rLiThi84Sy59KDZx8gKvpTIz4HatHPg5DNO6XWb4MCH11 +22pkgQJBANLqF3LUhNkZYqtei/QQfbERQtj2t4pSHqEoSeZHQlTheO8LbAE7dXLm +0jTYZXH1kzCL5QgX1Ff5mJY+9UyfPD8CQG7c+1NBVOfcw1OoY/kTgcYTeLfSwJo2 +CcezLselmV73u8ZMnyaTQWq/HmzWL+U5pfUQZrg/ioApg44BeY5QUIECQQCuGTbX +r9JGzDGG7se4fkPidZbU/NLZngOsYdlB3zZn5PTiceLoKGg5cXy0ooVDy7pXD7Jr +Tnec4O4FGzEDyD+m +-----END PRIVATE KEY----- diff --git a/samples/tls/server/conf/root_cert.pem b/samples/tls/server/conf/root_cert.pem new file mode 100644 index 000000000..e3f7cd4ea --- /dev/null +++ b/samples/tls/server/conf/root_cert.pem @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDhjCCAm4CAQAwDQYJKoZIhvcNAQEEBQAwgYgxCzAJBgNVBAYTAmNuMQswCQYD +VQQIEwJiajELMAkGA1UEBxMCYmoxFDASBgNVBAoTC3Rlc3QuY29tLmNuMRQwEgYD +VQQLEwt0ZXN0LmNvbS5jbjEUMBIGA1UEAxMLdGVzdC5jb20uY24xHTAbBgkqhkiG +9w0BCQEWDnpzeHhzekAyNjMubmV0MB4XDTA5MDcwOTA3MTAyNloXDTE5MDcwNzA3 +MTAyNlowgYgxCzAJBgNVBAYTAmNuMQswCQYDVQQIEwJiajELMAkGA1UEBxMCYmox +FDASBgNVBAoTC3Rlc3QuY29tLmNuMRQwEgYDVQQLEwt0ZXN0LmNvbS5jbjEUMBIG +A1UEAxMLdGVzdC5jb20uY24xHTAbBgkqhkiG9w0BCQEWDnpzeHhzekAyNjMubmV0 +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvRDxA/oj8dfLNR3fE/5P +VeLNiPnEBSchJXAwAnohwBT/8W+x0K4rW3mGkdh4vN5brhsLUUWJrLgh2KT95REl +rFQ7TZLG/nqVxGMNvW2KwuXo0eWTLp7AkwHhx6SBoqjsupIxzofXRm55Im4kPwcu +1Kx12YaSk6nwNgc7K4UJ/M+9ybSqz8dYoGR3FdJybJd0eOwfxjtN1BR6hqHlvMra +E90jprzWh4aaCZKGBJE7Ma/AF2ziBzru3wCKvL9TOnVe8ChlKm77cuky77CMXX0G +8HHfkNvCf/T7tRhVTZIstivRJu47AUYv1KJsRf3aUV3JIZ52JnNO7Ng2+D8jR0wJ +PQIDAQABMA0GCSqGSIb3DQEBBAUAA4IBAQB8yAUveT5j+hg/iv5ngyg657AkMjK5 +lHrDZPGgt0Wg4yGh0IeDU+TwlTNl6+6/DmRx/HNEKZErY7Y1kPXn2NOMz3nuSAk0 +iMSoiRMreIPGzDulZPWok0/pne0gn26fKBUA6nkRIxKBdHPobzD/4fI2e225cq73 +sF4WVtl2XpXvc71wK1xo063cplNr0HYlTLfgim87xZdtoSdz7LEt4ElwBbQIIAD6 +xweucWdYqiT89AvUVrP6kVyS47/v5RKjqLnGstF2RuNCSNtEAt9UMpobo7Jq6tOc +4pkcwzRFPI5diwRxxPLtmaIxW0SfX+XZr+snI9q5b8z83l+dO/N6GAgd +-----END CERTIFICATE----- diff --git a/samples/tls/server/conf/root_cert.srl b/samples/tls/server/conf/root_cert.srl new file mode 100644 index 000000000..9e22bcb8e --- /dev/null +++ b/samples/tls/server/conf/root_cert.srl @@ -0,0 +1 @@ +02 diff --git a/samples/tls/server/conf/root_key.pem b/samples/tls/server/conf/root_key.pem new file mode 100644 index 000000000..96dd91a87 --- /dev/null +++ b/samples/tls/server/conf/root_key.pem @@ -0,0 +1,30 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,AF4A984BABC0C0B6 + +T38cYSRPsbybnpaadsROdX9800PyfLhRxBYsu84VOr8E6V5U5Su4QeEqoGy+v8ea +qwK2FaSr9xTEi/WcOhEu2kBFkrUqbG0S/ojsFVJ6pkVcWWEgjNuMpykNT8T6fiN9 +oKydew0gyvo3WnTKQMkyJEcPl5yZ++Mfk4qvAJVbY3ysEiWUVtsb7yWliZuKBp8a +Mxi/OkIZ3ADdpV+kBV0ABv8BJju1GskK7AyUzbzdrRoVgFxIZcm4Es1JmPwsPd3G +aUM1WE2EyAFJiZs5wr7ITnfoBPpQwYUu4FuA1v/pQ/WGqWAZznN4sQ0aJrhuQIX8 +rvFRGT5DgOoDqBGAhsB2IX+q4ghNMi2zNOXOZQ2C9JRUOSXk7O2laqt1owUAzgAR +HgSbDNM6PrSKSguMkiGfNTG8tQPuruCGY3LvAntpiRQeKGn2mUzCxLBPqpXd7FTi +mxzXhDnbjhzC1RrnbYWrRujU/4dkwm+mV+THzeqUqP1m6jkBb6yV0nokMHW6fSx1 +E76ZjSZJUJqTgQTZFzHJYeOmxW4xQGqx2S1YnyJ241liYofqo8OpBXSLUUiI0u8u +k+fue9UUWsU5XibpFxhaiNLdLmlJcQoaZw0xbqnrAHaunVRRjhtGdg63l1HV0qoF +AsqjVyYsIa3a24O7S49/LwvLsQzewmR3w+7E8eT9kY0lYj6c791GXLDg8x0lfXLt +7AIK2qpUvk/hqibH3l+MC3XpzUaNgny9kWS5HskrLjYM6mGC6RH0YVi0DKZU86bU +mYUUnq1RQLwcZcxH5QBVdiViqOVv7YcWPDhi8DnA2oKaslfZBRBv1dVIo3KgDzq+ +QAW58fsAcgZaOvMRBjMo8Hxvb6A4PZ2Oifki3w4S8iW6HHHTB1yGp273FC/TsbN+ +fSooE0Jw2qSAXYXa47xHJk1VmeoTt8D4nRh2IZsIrJNlkYYxyh5YqW+3J1u90hel +9mQwLGJISQagxfELjV0wPofSifrcmvKQBAyXzvEE0THgJEb8Um9st9OjFNchZR5U +p5aKTdYqvPobd4oH+klXgP5qqrTQcz+Oq8yt8Bhs71NNsgUf17jJSxAvH84O0QUV +n6+QsPA9vGBYC1ss1d63rvv6suhGmoCgSbJcJtpwQys6TZ4jrWGXPzAtyCHY73U/ +FQTDmfn9jPe0Q/62BmfxmYFbnm4oaCL4BEOfjPen6fHjEdupbzHmhpeHTT8apzgA +NhAA19NARjMorNuKlpUNIg+1x/Dv+l7HFpik2gat3tIHcf/BQWLs+9f8RIp806Cw +TKh0uLMMpt8ma29hAPODT6wHYL1IwFeSEV4kY2Y5A54Gw2CzlVdUAy1OsY1gM1J4 +e8m3GeDbbLkGLAC0ofa0+4HUxj+tN9EmQOkdzH7PPAOQU0ZHJ+OqjNqgFCmhBheA +t1T6pRteMhir2GxI3QavNEddCNwqNeXrDRC2EW+kbZoXT6tF7C3ats60S+eH2SaS +RDjZvbvBqAIQWLpmTe7zsF5rtGH4/ka1E/jB4XgTm2zyd5xZygCXE+VwsuZVEABO +n2GkC/jPPB5ZGaasPndvol0NTbqU2BCzlzTjGlhhQC0Ks1f0At2wEw== +-----END RSA PRIVATE KEY----- diff --git a/samples/tls/server/conf/root_req.pem b/samples/tls/server/conf/root_req.pem new file mode 100644 index 000000000..7c6abed16 --- /dev/null +++ b/samples/tls/server/conf/root_req.pem @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIIC+DCCAeACAQAwgYgxCzAJBgNVBAYTAmNuMQswCQYDVQQIEwJiajELMAkGA1UE +BxMCYmoxFDASBgNVBAoTC3Rlc3QuY29tLmNuMRQwEgYDVQQLEwt0ZXN0LmNvbS5j +bjEUMBIGA1UEAxMLdGVzdC5jb20uY24xHTAbBgkqhkiG9w0BCQEWDnpzeHhzekAy +NjMubmV0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvRDxA/oj8dfL +NR3fE/5PVeLNiPnEBSchJXAwAnohwBT/8W+x0K4rW3mGkdh4vN5brhsLUUWJrLgh +2KT95RElrFQ7TZLG/nqVxGMNvW2KwuXo0eWTLp7AkwHhx6SBoqjsupIxzofXRm55 +Im4kPwcu1Kx12YaSk6nwNgc7K4UJ/M+9ybSqz8dYoGR3FdJybJd0eOwfxjtN1BR6 +hqHlvMraE90jprzWh4aaCZKGBJE7Ma/AF2ziBzru3wCKvL9TOnVe8ChlKm77cuky +77CMXX0G8HHfkNvCf/T7tRhVTZIstivRJu47AUYv1KJsRf3aUV3JIZ52JnNO7Ng2 ++D8jR0wJPQIDAQABoCowEQYJKoZIhvcNAQkCMQQTAmh4MBUGCSqGSIb3DQEJBzEI +EwYxMTExMTEwDQYJKoZIhvcNAQEFBQADggEBAERSkYiPGQTT4BIP/GDapqgEz2oa +ul2NFHjapc6r+UJBLDsS3RdpkqfXByQ9nE5HKrz8o+lTV9oP/6wUXMOGIlWEEOQS +ZqzzuYvE04Qk6Y3fDsCwPY7zSdU41OhQ0XJYhzs01a52CRjCyFWKzSfda/cz/SKm +bI6902xFK2nIlQnUKeb/Zgj/OnGiSZVfjkwFDIxyV7AeV35HMIGlSKOsDtZ76G6g +vRfhnv/+lf3bGN2IJaIlYdZO9Z0uta0GHs7R/TrIE4Z66KhXs2uvnV1XkYv+16RZ +3twDMgEBNhANZn8uksdG64Pub3Nv8MaUOhPZ3VaT4PmAFftBDrCL38wnKYY= +-----END CERTIFICATE REQUEST----- diff --git a/samples/tls/server/conf/server.pem b/samples/tls/server/conf/server.pem new file mode 100644 index 000000000..9f0e76033 --- /dev/null +++ b/samples/tls/server/conf/server.pem @@ -0,0 +1,30 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQDnFcDV3tRP2MMGuL1Tb+Y8llRzMa5HPwkyFvXqUj5h1PxZRedm +rVnS4q3Ti4XmoMZW6bKcSEk58BX41MGpeFa2v3cDE5T+uEqkVLm/TJGRrMcSrFdG +9+o9+rWHcS8AfTAxaqFcQdm20jeuh7naaaNWYl7dmihMClwPehdICsEs8QIDAQAB +AoGAPReFKYWFf66AsNA6TUqyBaaAoQurVW6W0cU8MjyX/Wk/ZaKTcJO3wYboCZtD +RRuQE/4omCSMJ2MPi/9DS7hiw+Daii6MpvpwhGWegSF9PHJ3IKrLb+fgQjf3H8Y8 +3IrFJVq2tKHE+uCijrFgdt/FzuIAD9yXKxOLjiU/pTrEsYECQQD88LSu2wUgHuyh +Z0sp3wW8y4iBIHgLxWiQhEFGsx8KoE38sifNkr+1gOn/jmVywLf2Ww61I49/zcBf +Npb/VL5JAkEA6eFd82Ldn4HB8+Cr3mZV7DTSgr4VDpkOYsFeUYp3oYXtibYfQleB +F1+hwFvMbobpmjf3uXH2NtQkewok/xoZaQJBAKU4sj2ZkYKG0LkpmN5z8PJ+3N7E +D8ZYn9HuohkFfhxZ1DdhRECzQAjWeYNWR4wquL/ygOvvm5e3FZbcOMv2VgkCQB66 +2OBY1ivWHcjQdWSkZ5fAnQRGu3eOjsBVDfKC0hMsCLj2cAcEfla23wbqSOMg4OK9 +hdQc8C/mEeEExTWrlTkCQQDcF+zRl4UiIjwFES/Ghbu2tyG6QH+BUrZmG3WmBim7 +mrYKTB5K8/InRFUkkClhf7aFyCvHQDMRlxiMT1QovSXm +-----END RSA PRIVATE KEY----- +-----BEGIN CERTIFICATE----- +MIICXTCCAcagAwIBAgIBADANBgkqhkiG9w0BAQQFADBpMQswCQYDVQQGEwJjbjEL +MAkGA1UECBMCYmoxCzAJBgNVBAcTAmJqMRQwEgYDVQQKEwt0ZXN0LmNvbS5jbjEU +MBIGA1UECxMLdGVzdC5jb20uY24xFDASBgNVBAMTC3Rlc3QuY29tLmNuMB4XDTA5 +MDcwOTA4MTAxMFoXDTEwMDcwOTA4MTAxMFowaTELMAkGA1UEBhMCY24xCzAJBgNV +BAgTAmJqMQswCQYDVQQHEwJiajEUMBIGA1UEChMLdGVzdC5jb20uY24xFDASBgNV +BAsTC3Rlc3QuY29tLmNuMRQwEgYDVQQDEwt0ZXN0LmNvbS5jbjCBnzANBgkqhkiG +9w0BAQEFAAOBjQAwgYkCgYEA5xXA1d7UT9jDBri9U2/mPJZUczGuRz8JMhb16lI+ +YdT8WUXnZq1Z0uKt04uF5qDGVumynEhJOfAV+NTBqXhWtr93AxOU/rhKpFS5v0yR +kazHEqxXRvfqPfq1h3EvAH0wMWqhXEHZttI3roe52mmjVmJe3ZooTApcD3oXSArB +LPECAwEAAaMVMBMwEQYJYIZIAYb4QgEBBAQDAgZAMA0GCSqGSIb3DQEBBAUAA4GB +AJeGFCk7npfEFGTlfND5WpG0iD1Hku+zEZMi/oHAlI+3AGXrb441yHFsEzWPG1dq +4gNCCb1RMmfNlB2cB6RbG6r7X+QDjFJztA6OAxCmXE8BrVEhugSmavgkbv0eLWph +oPbwQ0Mlsc/88jZLInypxmmxeDtQDjBVmSX5J3TEfNN+ +-----END CERTIFICATE----- diff --git a/samples/tls/server/conf/server.pem.bak b/samples/tls/server/conf/server.pem.bak new file mode 100644 index 000000000..36e60b196 --- /dev/null +++ b/samples/tls/server/conf/server.pem.bak @@ -0,0 +1,69 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEA0gCrdm/GQJM0q0VOCDzRL24EapzlU4e2BdT8J/w3sr1wgoa5 +CMhCe2ZXvoHlWcFKK85yTOuA0m+sVIrYul7Sh4B5574+HGMJsOx270YIgswxTbr5 +y/wO9nBsyT5yloD3f2FXTwuy5v2QOuSCIUX5DMFk3otrTR7nnvSidgs5xBK7kbpu +7QTwGscVonW66KFQs6Hmr8uZyNnEftEIp9oaUhUSQUpenSavAUeShGxwLs8P0O04 +lOCLIkOgu6MK34AaOaJvBY6keoipd3bpBzStlwUH1uJcu5TeNSzsKaUWq/59Xbs6 +pj7RKJCjqdr+ggOBeBNhm3rvU6b2qgvmtoZ6UQIDAQABAoIBAAyRQbGaytB+fr5p +LVxM12/xM451yTuQeZIrxtNVwreNorgM+/HMmj3sR//8og8XBCtO9YQo69KsIDIH +BSVSG2NEiwcVWX41ZxURcaSsGkJJmgG+2MgeU37oB3qbpBvhp+4VkzYFyzULo6AC +oM8A8wCSakjvKwK4gMAAf+B0l4ZmRLzyJcC36DHWGapfKV1DDW7M/AsRdrPiVEVE +8JVrtGBEaDssyGHwZu9SuQ3qOoDPqLD6/83qvBvoA8GmHABEuK0huz3AteH2SoFf +3j5qry07ERwHQ810/PafbGqhr68QLqo56O2ho09EU0vEheLcxf2zSd4uqNPUcanh +VQm2zAkCgYEA/I05daZruJf3aQskHb/R6nWxbL7vI9FDwiDtGEWdj2ceo2Vi6uy6 +1hFg4k1mvOFIt7gczfcKhUfzlRKquxw96KHuumNIkUfm94jHiAajI+tQVxyy6fJl +6vC1uHFqW4vuWSQCW+hnBz5iy2aBZzmg5cdYKRXsm8mAiv5QWObKeVcCgYEA1N63 +40mfjdGC0LivO3vPWqIKZlsG5zFZr+NcDPMfkyTfr4GhgiHx3FlngyKSyv6Iufbk +eCIskqtwT/UWOrhgScDMF+HaRKF0GqbcT8Bo9vFmu3234S4skrBm0OSbtK35kymg +pM8rJV5CCuih75JcjB/faP0Z8bqhTA7AdGrVWJcCgYAkHKF5tCk1BO3IpGIuqs3+ +Q4PyM78IFRUmPgUI8nNcHPehj468Xss8btG2qjClk2UNeBMOVGO5uRcYWsn05U3o +5La5ChdHRsu8218EkUZkjXI4co8WqqVuGasyS21U18ZmEqMPt0R8IayIvwiD1Rav +pHhzr4HcqMxrk3+zppSPEwKBgAWcBN6BbynujnLvmvaHUbSCtqFx3qGzBDkFVcSl +l3xqKVbXpKjoOhZjaL3k6FdfE71Ky0R7Kg+HYwNIYxiTCT6ITRiIBBdw5b1aDk4v +tNRlEh74tiLB87y910fD7nJ5by04mJofN3TZogXlkXbdtYCfymRa3xcmot99OAcZ +VZvrAoGBAMlA+APjRoJtpE7SOmqrUVfw3vb7LH0BDAVilnWSPFTt7caR65wt6iE9 +3rbcSC4K/iAeuo5LON+b6ERPIKUWSt2cWa13/9qAhHkKzYl7pJelIP+E6PWLMxwO +R+tbCE0xKCVm/S9V0JyuZfDDUEBwH2o6DmJyhTgLEbTOLRPz6R/Y +-----END RSA PRIVATE KEY----- +-----BEGIN CERTIFICATE----- +MIIDhjCCAm4CAQEwDQYJKoZIhvcNAQEEBQAwgYgxCzAJBgNVBAYTAmNuMQswCQYD +VQQIEwJiajELMAkGA1UEBxMCYmoxFDASBgNVBAoTC3Rlc3QuY29tLmNuMRQwEgYD +VQQLEwt0ZXN0LmNvbS5jbjEUMBIGA1UEAxMLdGVzdC5jb20uY24xHTAbBgkqhkiG +9w0BCQEWDnpzeHhzekAyNjMubmV0MB4XDTA5MDcwOTA3MTExOVoXDTE5MDcwNzA3 +MTExOVowgYgxCzAJBgNVBAYTAmNuMQswCQYDVQQIEwJiajELMAkGA1UEBxMCYmox +FDASBgNVBAoTC3Rlc3QuY29tLmNuMRQwEgYDVQQLEwt0ZXN0LmNvbS5jbjEUMBIG +A1UEAxMLdGVzdC5jb20uY24xHTAbBgkqhkiG9w0BCQEWDnpzeHhzekAyNjMubmV0 +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0gCrdm/GQJM0q0VOCDzR +L24EapzlU4e2BdT8J/w3sr1wgoa5CMhCe2ZXvoHlWcFKK85yTOuA0m+sVIrYul7S +h4B5574+HGMJsOx270YIgswxTbr5y/wO9nBsyT5yloD3f2FXTwuy5v2QOuSCIUX5 +DMFk3otrTR7nnvSidgs5xBK7kbpu7QTwGscVonW66KFQs6Hmr8uZyNnEftEIp9oa +UhUSQUpenSavAUeShGxwLs8P0O04lOCLIkOgu6MK34AaOaJvBY6keoipd3bpBzSt +lwUH1uJcu5TeNSzsKaUWq/59Xbs6pj7RKJCjqdr+ggOBeBNhm3rvU6b2qgvmtoZ6 +UQIDAQABMA0GCSqGSIb3DQEBBAUAA4IBAQCmOFiwpoZ98j6qvYaUxWbg7y1WU3v6 +f0Ky9HtgqwZQv8AGpreo6CW76M4TlLLO54jhre52+eZwIj6ovlhYbpozds5+6+DO +JrX/C4/Ty0jNWOIpCOf56ZuyyW69ERH34nt4k4ErgoDqBuR727jbn/tps+pBEXht +dFSzn7YQUAYutU8oeOJoPUbV9tA64O62l+U98Mms8UDZDAVqaIhym6mKDjPTEaXp +ap0yTsFc+P/2DVhgxHOaLFeREgLhZHSWZ8i0oz3chUMKjEW5IEbwy9orvW4DvK7i +93t69n/GpuLuWf5T7CDV+gPjucBZGk3DEJTFqIRPYu64ian7Z4yFeH8J +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDhjCCAm4CAQAwDQYJKoZIhvcNAQEEBQAwgYgxCzAJBgNVBAYTAmNuMQswCQYD +VQQIEwJiajELMAkGA1UEBxMCYmoxFDASBgNVBAoTC3Rlc3QuY29tLmNuMRQwEgYD +VQQLEwt0ZXN0LmNvbS5jbjEUMBIGA1UEAxMLdGVzdC5jb20uY24xHTAbBgkqhkiG +9w0BCQEWDnpzeHhzekAyNjMubmV0MB4XDTA5MDcwOTA3MTAyNloXDTE5MDcwNzA3 +MTAyNlowgYgxCzAJBgNVBAYTAmNuMQswCQYDVQQIEwJiajELMAkGA1UEBxMCYmox +FDASBgNVBAoTC3Rlc3QuY29tLmNuMRQwEgYDVQQLEwt0ZXN0LmNvbS5jbjEUMBIG +A1UEAxMLdGVzdC5jb20uY24xHTAbBgkqhkiG9w0BCQEWDnpzeHhzekAyNjMubmV0 +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvRDxA/oj8dfLNR3fE/5P +VeLNiPnEBSchJXAwAnohwBT/8W+x0K4rW3mGkdh4vN5brhsLUUWJrLgh2KT95REl +rFQ7TZLG/nqVxGMNvW2KwuXo0eWTLp7AkwHhx6SBoqjsupIxzofXRm55Im4kPwcu +1Kx12YaSk6nwNgc7K4UJ/M+9ybSqz8dYoGR3FdJybJd0eOwfxjtN1BR6hqHlvMra +E90jprzWh4aaCZKGBJE7Ma/AF2ziBzru3wCKvL9TOnVe8ChlKm77cuky77CMXX0G +8HHfkNvCf/T7tRhVTZIstivRJu47AUYv1KJsRf3aUV3JIZ52JnNO7Ng2+D8jR0wJ +PQIDAQABMA0GCSqGSIb3DQEBBAUAA4IBAQB8yAUveT5j+hg/iv5ngyg657AkMjK5 +lHrDZPGgt0Wg4yGh0IeDU+TwlTNl6+6/DmRx/HNEKZErY7Y1kPXn2NOMz3nuSAk0 +iMSoiRMreIPGzDulZPWok0/pne0gn26fKBUA6nkRIxKBdHPobzD/4fI2e225cq73 +sF4WVtl2XpXvc71wK1xo063cplNr0HYlTLfgim87xZdtoSdz7LEt4ElwBbQIIAD6 +xweucWdYqiT89AvUVrP6kVyS47/v5RKjqLnGstF2RuNCSNtEAt9UMpobo7Jq6tOc +4pkcwzRFPI5diwRxxPLtmaIxW0SfX+XZr+snI9q5b8z83l+dO/N6GAgd +-----END CERTIFICATE----- diff --git a/samples/tls/server/conf/server.pem.bak1 b/samples/tls/server/conf/server.pem.bak1 new file mode 100644 index 000000000..9f0e76033 --- /dev/null +++ b/samples/tls/server/conf/server.pem.bak1 @@ -0,0 +1,30 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQDnFcDV3tRP2MMGuL1Tb+Y8llRzMa5HPwkyFvXqUj5h1PxZRedm +rVnS4q3Ti4XmoMZW6bKcSEk58BX41MGpeFa2v3cDE5T+uEqkVLm/TJGRrMcSrFdG +9+o9+rWHcS8AfTAxaqFcQdm20jeuh7naaaNWYl7dmihMClwPehdICsEs8QIDAQAB +AoGAPReFKYWFf66AsNA6TUqyBaaAoQurVW6W0cU8MjyX/Wk/ZaKTcJO3wYboCZtD +RRuQE/4omCSMJ2MPi/9DS7hiw+Daii6MpvpwhGWegSF9PHJ3IKrLb+fgQjf3H8Y8 +3IrFJVq2tKHE+uCijrFgdt/FzuIAD9yXKxOLjiU/pTrEsYECQQD88LSu2wUgHuyh +Z0sp3wW8y4iBIHgLxWiQhEFGsx8KoE38sifNkr+1gOn/jmVywLf2Ww61I49/zcBf +Npb/VL5JAkEA6eFd82Ldn4HB8+Cr3mZV7DTSgr4VDpkOYsFeUYp3oYXtibYfQleB +F1+hwFvMbobpmjf3uXH2NtQkewok/xoZaQJBAKU4sj2ZkYKG0LkpmN5z8PJ+3N7E +D8ZYn9HuohkFfhxZ1DdhRECzQAjWeYNWR4wquL/ygOvvm5e3FZbcOMv2VgkCQB66 +2OBY1ivWHcjQdWSkZ5fAnQRGu3eOjsBVDfKC0hMsCLj2cAcEfla23wbqSOMg4OK9 +hdQc8C/mEeEExTWrlTkCQQDcF+zRl4UiIjwFES/Ghbu2tyG6QH+BUrZmG3WmBim7 +mrYKTB5K8/InRFUkkClhf7aFyCvHQDMRlxiMT1QovSXm +-----END RSA PRIVATE KEY----- +-----BEGIN CERTIFICATE----- +MIICXTCCAcagAwIBAgIBADANBgkqhkiG9w0BAQQFADBpMQswCQYDVQQGEwJjbjEL +MAkGA1UECBMCYmoxCzAJBgNVBAcTAmJqMRQwEgYDVQQKEwt0ZXN0LmNvbS5jbjEU +MBIGA1UECxMLdGVzdC5jb20uY24xFDASBgNVBAMTC3Rlc3QuY29tLmNuMB4XDTA5 +MDcwOTA4MTAxMFoXDTEwMDcwOTA4MTAxMFowaTELMAkGA1UEBhMCY24xCzAJBgNV +BAgTAmJqMQswCQYDVQQHEwJiajEUMBIGA1UEChMLdGVzdC5jb20uY24xFDASBgNV +BAsTC3Rlc3QuY29tLmNuMRQwEgYDVQQDEwt0ZXN0LmNvbS5jbjCBnzANBgkqhkiG +9w0BAQEFAAOBjQAwgYkCgYEA5xXA1d7UT9jDBri9U2/mPJZUczGuRz8JMhb16lI+ +YdT8WUXnZq1Z0uKt04uF5qDGVumynEhJOfAV+NTBqXhWtr93AxOU/rhKpFS5v0yR +kazHEqxXRvfqPfq1h3EvAH0wMWqhXEHZttI3roe52mmjVmJe3ZooTApcD3oXSArB +LPECAwEAAaMVMBMwEQYJYIZIAYb4QgEBBAQDAgZAMA0GCSqGSIb3DQEBBAUAA4GB +AJeGFCk7npfEFGTlfND5WpG0iD1Hku+zEZMi/oHAlI+3AGXrb441yHFsEzWPG1dq +4gNCCb1RMmfNlB2cB6RbG6r7X+QDjFJztA6OAxCmXE8BrVEhugSmavgkbv0eLWph +oPbwQ0Mlsc/88jZLInypxmmxeDtQDjBVmSX5J3TEfNN+ +-----END CERTIFICATE----- diff --git a/samples/tls/server/conf/server.pfx b/samples/tls/server/conf/server.pfx new file mode 100644 index 000000000..773f80a6a Binary files /dev/null and b/samples/tls/server/conf/server.pfx differ diff --git a/samples/tls/server/conf/server_cert.pem b/samples/tls/server/conf/server_cert.pem new file mode 100644 index 000000000..a0d42494f --- /dev/null +++ b/samples/tls/server/conf/server_cert.pem @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDhjCCAm4CAQEwDQYJKoZIhvcNAQEEBQAwgYgxCzAJBgNVBAYTAmNuMQswCQYD +VQQIEwJiajELMAkGA1UEBxMCYmoxFDASBgNVBAoTC3Rlc3QuY29tLmNuMRQwEgYD +VQQLEwt0ZXN0LmNvbS5jbjEUMBIGA1UEAxMLdGVzdC5jb20uY24xHTAbBgkqhkiG +9w0BCQEWDnpzeHhzekAyNjMubmV0MB4XDTA5MDcwOTA3MTExOVoXDTE5MDcwNzA3 +MTExOVowgYgxCzAJBgNVBAYTAmNuMQswCQYDVQQIEwJiajELMAkGA1UEBxMCYmox +FDASBgNVBAoTC3Rlc3QuY29tLmNuMRQwEgYDVQQLEwt0ZXN0LmNvbS5jbjEUMBIG +A1UEAxMLdGVzdC5jb20uY24xHTAbBgkqhkiG9w0BCQEWDnpzeHhzekAyNjMubmV0 +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0gCrdm/GQJM0q0VOCDzR +L24EapzlU4e2BdT8J/w3sr1wgoa5CMhCe2ZXvoHlWcFKK85yTOuA0m+sVIrYul7S +h4B5574+HGMJsOx270YIgswxTbr5y/wO9nBsyT5yloD3f2FXTwuy5v2QOuSCIUX5 +DMFk3otrTR7nnvSidgs5xBK7kbpu7QTwGscVonW66KFQs6Hmr8uZyNnEftEIp9oa +UhUSQUpenSavAUeShGxwLs8P0O04lOCLIkOgu6MK34AaOaJvBY6keoipd3bpBzSt +lwUH1uJcu5TeNSzsKaUWq/59Xbs6pj7RKJCjqdr+ggOBeBNhm3rvU6b2qgvmtoZ6 +UQIDAQABMA0GCSqGSIb3DQEBBAUAA4IBAQCmOFiwpoZ98j6qvYaUxWbg7y1WU3v6 +f0Ky9HtgqwZQv8AGpreo6CW76M4TlLLO54jhre52+eZwIj6ovlhYbpozds5+6+DO +JrX/C4/Ty0jNWOIpCOf56ZuyyW69ERH34nt4k4ErgoDqBuR727jbn/tps+pBEXht +dFSzn7YQUAYutU8oeOJoPUbV9tA64O62l+U98Mms8UDZDAVqaIhym6mKDjPTEaXp +ap0yTsFc+P/2DVhgxHOaLFeREgLhZHSWZ8i0oz3chUMKjEW5IEbwy9orvW4DvK7i +93t69n/GpuLuWf5T7CDV+gPjucBZGk3DEJTFqIRPYu64ian7Z4yFeH8J +-----END CERTIFICATE----- diff --git a/samples/tls/server/conf/server_key.pem b/samples/tls/server/conf/server_key.pem new file mode 100644 index 000000000..31f06ab0a --- /dev/null +++ b/samples/tls/server/conf/server_key.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEA0gCrdm/GQJM0q0VOCDzRL24EapzlU4e2BdT8J/w3sr1wgoa5 +CMhCe2ZXvoHlWcFKK85yTOuA0m+sVIrYul7Sh4B5574+HGMJsOx270YIgswxTbr5 +y/wO9nBsyT5yloD3f2FXTwuy5v2QOuSCIUX5DMFk3otrTR7nnvSidgs5xBK7kbpu +7QTwGscVonW66KFQs6Hmr8uZyNnEftEIp9oaUhUSQUpenSavAUeShGxwLs8P0O04 +lOCLIkOgu6MK34AaOaJvBY6keoipd3bpBzStlwUH1uJcu5TeNSzsKaUWq/59Xbs6 +pj7RKJCjqdr+ggOBeBNhm3rvU6b2qgvmtoZ6UQIDAQABAoIBAAyRQbGaytB+fr5p +LVxM12/xM451yTuQeZIrxtNVwreNorgM+/HMmj3sR//8og8XBCtO9YQo69KsIDIH +BSVSG2NEiwcVWX41ZxURcaSsGkJJmgG+2MgeU37oB3qbpBvhp+4VkzYFyzULo6AC +oM8A8wCSakjvKwK4gMAAf+B0l4ZmRLzyJcC36DHWGapfKV1DDW7M/AsRdrPiVEVE +8JVrtGBEaDssyGHwZu9SuQ3qOoDPqLD6/83qvBvoA8GmHABEuK0huz3AteH2SoFf +3j5qry07ERwHQ810/PafbGqhr68QLqo56O2ho09EU0vEheLcxf2zSd4uqNPUcanh +VQm2zAkCgYEA/I05daZruJf3aQskHb/R6nWxbL7vI9FDwiDtGEWdj2ceo2Vi6uy6 +1hFg4k1mvOFIt7gczfcKhUfzlRKquxw96KHuumNIkUfm94jHiAajI+tQVxyy6fJl +6vC1uHFqW4vuWSQCW+hnBz5iy2aBZzmg5cdYKRXsm8mAiv5QWObKeVcCgYEA1N63 +40mfjdGC0LivO3vPWqIKZlsG5zFZr+NcDPMfkyTfr4GhgiHx3FlngyKSyv6Iufbk +eCIskqtwT/UWOrhgScDMF+HaRKF0GqbcT8Bo9vFmu3234S4skrBm0OSbtK35kymg +pM8rJV5CCuih75JcjB/faP0Z8bqhTA7AdGrVWJcCgYAkHKF5tCk1BO3IpGIuqs3+ +Q4PyM78IFRUmPgUI8nNcHPehj468Xss8btG2qjClk2UNeBMOVGO5uRcYWsn05U3o +5La5ChdHRsu8218EkUZkjXI4co8WqqVuGasyS21U18ZmEqMPt0R8IayIvwiD1Rav +pHhzr4HcqMxrk3+zppSPEwKBgAWcBN6BbynujnLvmvaHUbSCtqFx3qGzBDkFVcSl +l3xqKVbXpKjoOhZjaL3k6FdfE71Ky0R7Kg+HYwNIYxiTCT6ITRiIBBdw5b1aDk4v +tNRlEh74tiLB87y910fD7nJ5by04mJofN3TZogXlkXbdtYCfymRa3xcmot99OAcZ +VZvrAoGBAMlA+APjRoJtpE7SOmqrUVfw3vb7LH0BDAVilnWSPFTt7caR65wt6iE9 +3rbcSC4K/iAeuo5LON+b6ERPIKUWSt2cWa13/9qAhHkKzYl7pJelIP+E6PWLMxwO +R+tbCE0xKCVm/S9V0JyuZfDDUEBwH2o6DmJyhTgLEbTOLRPz6R/Y +-----END RSA PRIVATE KEY----- diff --git a/samples/tls/server/conf/server_req.pem b/samples/tls/server/conf/server_req.pem new file mode 100644 index 000000000..debc6493e --- /dev/null +++ b/samples/tls/server/conf/server_req.pem @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIIC+DCCAeACAQAwgYgxCzAJBgNVBAYTAmNuMQswCQYDVQQIEwJiajELMAkGA1UE +BxMCYmoxFDASBgNVBAoTC3Rlc3QuY29tLmNuMRQwEgYDVQQLEwt0ZXN0LmNvbS5j +bjEUMBIGA1UEAxMLdGVzdC5jb20uY24xHTAbBgkqhkiG9w0BCQEWDnpzeHhzekAy +NjMubmV0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0gCrdm/GQJM0 +q0VOCDzRL24EapzlU4e2BdT8J/w3sr1wgoa5CMhCe2ZXvoHlWcFKK85yTOuA0m+s +VIrYul7Sh4B5574+HGMJsOx270YIgswxTbr5y/wO9nBsyT5yloD3f2FXTwuy5v2Q +OuSCIUX5DMFk3otrTR7nnvSidgs5xBK7kbpu7QTwGscVonW66KFQs6Hmr8uZyNnE +ftEIp9oaUhUSQUpenSavAUeShGxwLs8P0O04lOCLIkOgu6MK34AaOaJvBY6keoip +d3bpBzStlwUH1uJcu5TeNSzsKaUWq/59Xbs6pj7RKJCjqdr+ggOBeBNhm3rvU6b2 +qgvmtoZ6UQIDAQABoCowEQYJKoZIhvcNAQkCMQQTAmh4MBUGCSqGSIb3DQEJBzEI +EwYxMTExMTEwDQYJKoZIhvcNAQEEBQADggEBAIBFY5AkTxMWKd0KKotdZz8tTMbW +UxOswkEz25el1uiOcNnIGt0pbl6BjZTGCTBTC1RkJPuWRwT5uZ+F1VpNPzxkMcg0 +p7rF396wBf459ZT2pK0YopfLCFPt1YwBEktW0DYMSQd1r50z/sKPaEEZB95yt59H +KBriUw9bCZ6CC8oixnnwHm4rTFYpgOCGtssSiTd7BFd9d9kQtMHbO9ca8Mav39R8 +x3PmQH4GSnSFOsQF18LEbfpXv5tqIVM8zYAwKddTqoAUkgrDjqw4teKIiZpRBr0n +QuhDpC3wimeKWVOGppX8qTRwC+zv0SKD+aC0VEWxQdN0ysst42pGHF9xZww= +-----END CERTIFICATE REQUEST----- diff --git a/samples/tls/server/main.c b/samples/tls/server/main.c new file mode 100644 index 000000000..bdbb6e1df --- /dev/null +++ b/samples/tls/server/main.c @@ -0,0 +1,282 @@ +#include "lib_acl.h" + +#if defined(ACL_MS_WINDOWS) +#pragma comment(lib,"ws2_32") +#pragma comment(lib, "wsock32") +#endif + +#include +#include "tls.h" +#include "tls_params.h" +#ifdef ACL_UNIX +#include +#endif +#include + +static char *conf_file = "tlssvr.cf"; +static char serv_addr[64]; + +int var_cfg_server_tls_loglevel; +int var_server_tls_ccert_vd; +int var_cfg_server_tls_scache_timeout; +int var_server_tls_set_sessid; +int var_server_enforce_tls; +int var_server_ask_client_cert; +int var_server_tls_req_ccert; +int var_server_starttls_tmout; +char *var_server_tls_cert_file; +char *var_server_tls_key_file; +char *var_server_tls_dcert_file; +char *var_server_tls_dkey_file; +char *var_server_tls_eccert_file; +char *var_server_tls_eckey_file; +char *var_server_tls_CAfile; +char *var_server_tls_CApath; +char *var_server_tls_dh1024_param_file; +char *var_server_tls_dh512_param_file; +char *var_server_tls_eecdh; +char *var_server_tls_fpt_dgst; + +static ACL_CONFIG_INT_TABLE int_table[] = { + { "server_tls_loglevel", 0, &var_cfg_server_tls_loglevel, 0, 0 }, + { "server_tls_ccert_vd", 9, &var_server_tls_ccert_vd, 0, 0 }, + { "server_tls_scache_timeout", 10, &var_cfg_server_tls_scache_timeout, 0, 0 }, + { "server_tls_set_sessid", 1, &var_server_tls_set_sessid, 0, 0 }, + { "server_enforce_tls", 1, &var_server_enforce_tls, 0, 0 }, + { "server_ask_client_cert", 1, &var_server_ask_client_cert, 0, 0 }, + { "server_tls_req_ccert", 1, &var_server_tls_req_ccert, 0, 0 }, + { "server_starttls_tmout", 300, &var_server_starttls_tmout, 0, 0 }, + { 0, 0, 0, 0, 0 }, +}; + +static ACL_CONFIG_STR_TABLE str_table[] = { + { "server_tls_cert_file", "conf/server.pem", &var_server_tls_cert_file }, + { "server_tls_key_file", "conf/server.pem", &var_server_tls_key_file }, + { "server_tls_dcert_file", "", &var_server_tls_dcert_file }, + { "server_tls_dkey_file", "", &var_server_tls_dkey_file }, + { "server_tls_eccert_file", "", &var_server_tls_eccert_file }, + { "server_tls_eckey_file", "", &var_server_tls_eckey_file }, + { "server_tls_CAfile", "conf/server.pem", &var_server_tls_CAfile }, + { "server_tls_CApath", "", &var_server_tls_CApath }, + { "server_tls_dh1024_param_file", "", &var_server_tls_dh1024_param_file }, + { "server_tls_dh512_param_file", "", &var_server_tls_dh512_param_file }, + { "server_tls_eecdh", "", &var_server_tls_eecdh }, + { "server_tls_fpt_dgst", "sha1", &var_server_tls_fpt_dgst }, + { 0, 0, 0 }, +}; + +static TLS_SERVER_INIT_PROPS init_props; + +static void init(void) +{ + acl_app_conf_load(conf_file); + + acl_get_app_conf_str_table(str_table); + acl_get_app_conf_int_table(int_table); + + var_tlsmgr_stand_alone = 0; + tls_server_init(); + + TLS_SERVER_SETUP(&init_props, + log_level = var_cfg_server_tls_loglevel, + verifydepth = var_server_tls_ccert_vd, + cache_type = TLS_MGR_SCACHE_SERVER, + scache_timeout = var_cfg_server_tls_scache_timeout, + set_sessid = var_server_tls_set_sessid, + cert_file = var_server_tls_cert_file, + key_file = var_server_tls_key_file, + dcert_file = var_server_tls_dcert_file, + dkey_file = var_server_tls_dkey_file, + eccert_file = var_server_tls_eccert_file, + eckey_file = var_server_tls_eckey_file, + CAfile = var_server_tls_CAfile, + CApath = var_server_tls_CApath, + dh1024_param_file = var_server_tls_dh1024_param_file, + dh512_param_file = var_server_tls_dh512_param_file, + eecdh_grade = var_server_tls_eecdh, + protocols = var_server_enforce_tls ? var_server_tls_mand_proto : var_server_tls_proto, + ask_ccert = var_server_ask_client_cert, + fpt_dgst = var_server_tls_fpt_dgst); +} + +static void usage(const char *procname) +{ + printf("usage: %s -h [help] -c conf_file\n", procname); +} + +static char *reply = "HTTP/1.1 200 OK\r\n" + "Date: Thu, 09 Jul 2009 03:30:09 GMT\r\n" + "Server: Apache/1.3.37 (Unix)\r\n" + "Last-Modified: Fri, 13 Mar 2009 07:37:22 GMT\r\n" + "Connection: close\r\n" + "Content-Type: text/html\r\n" + "\r\n" + "hello world!"; + +static void free_ctx_fn(void *ctx) +{ + TLS_APPL_STATE *server_tls_ctx = (TLS_APPL_STATE*) ctx; + tls_free_app_context(server_tls_ctx); +} + +static void client_thread(void *arg) +{ + ACL_VSTREAM *client = (ACL_VSTREAM*) arg; + static __thread TLS_APPL_STATE *server_tls_ctx; + TLS_SESS_STATE *server_sess_ctx; + TLS_SERVER_START_PROPS tls_props; + char buf[4096]; + int ret, i; + time_t last, now; + + int tls_level = 2; + char *namaddrport = "test.com"; + char *serverid = "service:addr:port:helo"; + char *tls_grade = "low"; /* high, medium, low, export, null */ + char *tls_exclusions = ""; + + acl_tcp_nodelay(ACL_VSTREAM_SOCK(client), 1); + + if (server_tls_ctx == NULL) { + server_tls_ctx = tls_server_create(&init_props); + if (server_tls_ctx == NULL) { + printf("tls_server_create error\n"); + return; + } + acl_pthread_atexit_add(server_tls_ctx, free_ctx_fn); + } + + server_sess_ctx = TLS_SERVER_START(&tls_props, + ctx = server_tls_ctx, + stream = client, + log_level = var_server_tls_loglevel, + timeout = var_server_starttls_tmout, + requirecert = (var_server_tls_req_ccert && var_server_enforce_tls), + serverid = serverid, + namaddr = namaddrport, + cipher_grade = tls_grade, + cipher_exclusions = tls_exclusions, + fpt_dgst = var_server_tls_fpt_dgst); + + if (server_sess_ctx == NULL) { + printf("TLS_SERVER_START error\n"); + acl_vstream_close(client); + return; + } + + if (tls_level >= TLS_LEV_VERIFY) { + if (!TLS_CERT_IS_TRUSTED(server_sess_ctx)) { + printf("Server certificate not trusted\n"); + } + } + + if (tls_level > TLS_LEV_ENCRYPT) { + if (!TLS_CERT_IS_MATCHED(server_sess_ctx)) { + printf("Server certificate not verified\n"); + } + } + + i = 0; + time(&last); + while (0) { + ret = acl_vstream_gets(client, buf, sizeof(buf)); + if (ret == ACL_VSTREAM_EOF) + goto END; + if (acl_vstream_writen(client, buf, ret) == ACL_VSTREAM_EOF) + goto END; + break; + + i++; + if (i % 50000 == 0) { + time(&now); + printf("i: %d, time: %ld\n", i, now - last); + last = now; + } + } + + while (1) { + while (1) { + ret = acl_vstream_gets_nonl(client, buf, sizeof(buf)); + if (ret == ACL_VSTREAM_EOF) + goto END; + + if (ret == 0) + break; + /* printf("buf: %s, ret: %d\n", buf, ret); */ + } + + ret = acl_vstream_writen(client, reply, strlen(reply)); + /* printf("\nret: %d, reply: \n%s\n", ret, reply); */ + break; + } + +END: + tls_server_stop(server_tls_ctx, client, var_server_starttls_tmout, 0, server_sess_ctx); + acl_vstream_close(client); +} + +static void run(void) +{ + ACL_VSTREAM *server, *client; + acl_pthread_pool_t *pool; + + server = acl_vstream_listen(serv_addr, 128); + if (server == NULL) { + printf("listen %s error(%s)\n", serv_addr, acl_last_serror()); + return; + } + + pool = acl_thread_pool_create(10, 0); + if (pool == NULL) { + acl_vstream_close(server); + printf("create thread pool error(%s)\n", acl_last_serror()); + return; + } + + while (1) { + client = acl_vstream_accept(server, NULL, 0); + if (client == NULL) { + if (errno != ACL_EINTR) { + printf("accept error(%s)\n", acl_last_serror()); + break; + } + continue; + } + acl_pthread_pool_add(pool, client_thread, client); + } + + acl_vstream_close(server); + acl_pthread_pool_destroy(pool); +} + +static void free_fn(void) +{ + acl_myfree(conf_file); +} + +int main(int argc, char *argv[]) +{ + char ch; + + acl_init(); + ACL_SAFE_STRNCPY(serv_addr, "0.0.0.0:443", sizeof(serv_addr)); + + while ((ch = getopt(argc, argv, "hc:")) > 0) { + switch (ch) { + case 'h': + usage(argv[0]); + exit (0); + case 'c': + conf_file = acl_mystrdup(optarg); + atexit(free_fn); + break; + default: + break; + } + } + + init(); + run(); + acl_end(); + return (0); +} diff --git a/samples/tls/server/sbin/conf/bak/cacert.pem b/samples/tls/server/sbin/conf/bak/cacert.pem new file mode 100644 index 000000000..2df484d57 --- /dev/null +++ b/samples/tls/server/sbin/conf/bak/cacert.pem @@ -0,0 +1,58 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 8a:71:b6:97:ac:93:93:ae + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=cn, ST=bj, O=hx, OU=hx, CN=zsxxsz/emailAddress=zsxxsz@263.net + Validity + Not Before: Jul 9 05:40:15 2009 GMT + Not After : Jul 8 05:40:15 2012 GMT + Subject: C=cn, ST=bj, O=hx, OU=hx, CN=zsxxsz/emailAddress=zsxxsz@263.net + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (1024 bit) + Modulus: + 00:a1:46:7b:66:24:96:93:50:5d:68:78:ad:78:64: + 68:b0:13:43:fe:f4:04:5c:ee:31:85:66:68:09:a0: + 59:c3:4b:a3:a8:21:3b:3d:9e:1a:06:71:b5:17:44: + ea:a6:2e:2d:a7:d0:c7:e3:ed:0d:ca:1d:b3:5c:92: + 0c:9c:a9:5e:7c:66:85:12:e0:92:21:38:71:3e:f0: + 7c:db:ba:e9:f8:57:f5:79:47:3b:a0:8a:4c:91:11: + 43:1c:62:91:9a:4b:f7:d1:25:fc:c6:9c:27:12:df: + 2f:b5:cf:f5:8d:56:b7:77:68:72:67:ab:81:0a:ba: + a6:38:82:35:04:d4:e0:79:51 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + 08:7D:CB:91:88:10:BA:75:F8:23:BE:DC:E9:5A:D4:CD:2E:43:D6:FB + X509v3 Authority Key Identifier: + keyid:08:7D:CB:91:88:10:BA:75:F8:23:BE:DC:E9:5A:D4:CD:2E:43:D6:FB + + X509v3 Basic Constraints: + CA:TRUE + Signature Algorithm: sha1WithRSAEncryption + 7d:1e:4e:fc:3f:f1:2b:48:64:96:e6:a2:02:1b:97:66:0f:85: + af:4c:43:d6:a5:da:a2:3e:73:55:34:9f:07:b1:6f:11:08:cf: + 46:29:24:da:5a:f0:81:92:4d:fa:c7:ff:c5:ed:08:49:b3:73: + 6b:56:7a:84:50:d5:b0:f8:89:0a:f1:e9:e5:af:a2:aa:87:95: + 66:aa:1d:6f:db:00:24:1a:4a:47:e5:74:6b:cf:32:0e:1c:24: + 1b:ab:d0:6f:de:59:3c:e3:46:59:2a:61:1f:ae:35:d4:ee:a0: + 44:65:64:e3:0c:b3:ce:26:26:5e:80:fa:33:4d:f6:9f:1a:d9: + 7a:74 +-----BEGIN CERTIFICATE----- +MIICljCCAf+gAwIBAgIJAIpxtpesk5OuMA0GCSqGSIb3DQEBBQUAMGQxCzAJBgNV +BAYTAmNuMQswCQYDVQQIDAJiajELMAkGA1UECgwCaHgxCzAJBgNVBAsMAmh4MQ8w +DQYDVQQDDAZ6c3h4c3oxHTAbBgkqhkiG9w0BCQEWDnpzeHhzekAyNjMubmV0MB4X +DTA5MDcwOTA1NDAxNVoXDTEyMDcwODA1NDAxNVowZDELMAkGA1UEBhMCY24xCzAJ +BgNVBAgMAmJqMQswCQYDVQQKDAJoeDELMAkGA1UECwwCaHgxDzANBgNVBAMMBnpz +eHhzejEdMBsGCSqGSIb3DQEJARYOenN4eHN6QDI2My5uZXQwgZ8wDQYJKoZIhvcN +AQEBBQADgY0AMIGJAoGBAKFGe2YklpNQXWh4rXhkaLATQ/70BFzuMYVmaAmgWcNL +o6ghOz2eGgZxtRdE6qYuLafQx+PtDcods1ySDJypXnxmhRLgkiE4cT7wfNu66fhX +9XlHO6CKTJERQxxikZpL99El/MacJxLfL7XP9Y1Wt3docmergQq6pjiCNQTU4HlR +AgMBAAGjUDBOMB0GA1UdDgQWBBQIfcuRiBC6dfgjvtzpWtTNLkPW+zAfBgNVHSME +GDAWgBQIfcuRiBC6dfgjvtzpWtTNLkPW+zAMBgNVHRMEBTADAQH/MA0GCSqGSIb3 +DQEBBQUAA4GBAH0eTvw/8StIZJbmogIbl2YPha9MQ9al2qI+c1U0nwexbxEIz0Yp +JNpa8IGSTfrH/8XtCEmzc2tWeoRQ1bD4iQrx6eWvoqqHlWaqHW/bACQaSkfldGvP +Mg4cJBur0G/eWTzjRlkqYR+uNdTuoERlZOMMs84mJl6A+jNN9p8a2Xp0 +-----END CERTIFICATE----- diff --git a/samples/tls/server/sbin/conf/bak/foo-cert.pem b/samples/tls/server/sbin/conf/bak/foo-cert.pem new file mode 100644 index 000000000..a1b4e71d1 --- /dev/null +++ b/samples/tls/server/sbin/conf/bak/foo-cert.pem @@ -0,0 +1,61 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 8a:71:b6:97:ac:93:93:af + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=cn, ST=bj, O=hx, OU=hx, CN=zsxxsz/emailAddress=zsxxsz@263.net + Validity + Not Before: Jul 9 05:42:20 2009 GMT + Not After : Jul 9 05:42:20 2010 GMT + Subject: C=cn, ST=bj, O=hx, OU=hx, CN=zsxxsz@263.net/emailAddress=zsxxsz@263.net + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (1024 bit) + Modulus: + 00:bc:d8:a3:4c:be:48:d5:ac:fc:30:4f:4b:23:61: + 4f:20:ed:30:77:b2:f8:ba:42:4c:9a:cd:2a:75:c7: + 52:13:28:83:ba:af:b2:3b:77:29:81:a5:78:d0:75: + 2a:a2:d9:e2:71:ba:d9:05:62:ea:38:d3:d9:c4:73: + ab:54:90:26:94:b1:e3:c9:51:7a:25:b3:c3:cb:45: + 83:15:35:6e:55:3d:61:ab:f2:0d:49:5a:e2:6d:0b: + a0:d3:ab:4c:8a:ee:25:70:59:76:d9:af:63:0d:d6: + b8:d7:c6:30:0c:b6:4a:61:f3:f7:c0:12:61:f6:e5: + 4a:f5:54:ce:04:45:ed:5e:7b + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + Netscape Comment: + OpenSSL Generated Certificate + X509v3 Subject Key Identifier: + AE:94:B0:7F:68:BC:FB:AE:66:AF:51:CF:6F:2B:82:5E:D7:36:08:55 + X509v3 Authority Key Identifier: + keyid:08:7D:CB:91:88:10:BA:75:F8:23:BE:DC:E9:5A:D4:CD:2E:43:D6:FB + + Signature Algorithm: sha1WithRSAEncryption + 97:a0:48:f3:31:b2:f1:2e:7f:2a:2d:7d:99:7c:a8:3a:b6:bc: + be:d0:c5:a8:50:26:05:a0:8a:4c:e8:3b:ec:fe:1d:cb:f4:84: + 67:71:f1:bb:04:69:f9:d7:21:6a:08:d2:d5:e3:91:58:f4:3c: + 11:b4:b9:9c:d0:8f:98:09:18:14:0c:34:50:18:b2:53:0b:0d: + d8:af:a2:2f:59:0b:f9:d6:7f:b6:8c:1f:85:87:46:20:c7:cf: + 0b:3b:a4:dc:9f:b5:92:f5:d8:23:0c:ed:b1:aa:cf:36:ab:5f: + 85:44:47:6d:ea:4e:f5:07:b0:17:fb:25:31:4b:be:37:63:b6: + 8e:2e +-----BEGIN CERTIFICATE----- +MIICyTCCAjKgAwIBAgIJAIpxtpesk5OvMA0GCSqGSIb3DQEBBQUAMGQxCzAJBgNV +BAYTAmNuMQswCQYDVQQIDAJiajELMAkGA1UECgwCaHgxCzAJBgNVBAsMAmh4MQ8w +DQYDVQQDDAZ6c3h4c3oxHTAbBgkqhkiG9w0BCQEWDnpzeHhzekAyNjMubmV0MB4X +DTA5MDcwOTA1NDIyMFoXDTEwMDcwOTA1NDIyMFowbDELMAkGA1UEBhMCY24xCzAJ +BgNVBAgMAmJqMQswCQYDVQQKDAJoeDELMAkGA1UECwwCaHgxFzAVBgNVBAMMDnpz +eHhzekAyNjMubmV0MR0wGwYJKoZIhvcNAQkBFg56c3h4c3pAMjYzLm5ldDCBnzAN +BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAvNijTL5I1az8ME9LI2FPIO0wd7L4ukJM +ms0qdcdSEyiDuq+yO3cpgaV40HUqotnicbrZBWLqONPZxHOrVJAmlLHjyVF6JbPD +y0WDFTVuVT1hq/INSVribQug06tMiu4lcFl22a9jDda418YwDLZKYfP3wBJh9uVK +9VTOBEXtXnsCAwEAAaN7MHkwCQYDVR0TBAIwADAsBglghkgBhvhCAQ0EHxYdT3Bl +blNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFK6UsH9ovPuuZq9R +z28rgl7XNghVMB8GA1UdIwQYMBaAFAh9y5GIELp1+CO+3Ola1M0uQ9b7MA0GCSqG +SIb3DQEBBQUAA4GBAJegSPMxsvEufyotfZl8qDq2vL7QxahQJgWgikzoO+z+Hcv0 +hGdx8bsEafnXIWoI0tXjkVj0PBG0uZzQj5gJGBQMNFAYslMLDdivoi9ZC/nWf7aM +H4WHRiDHzws7pNyftZL12CMM7bGqzzarX4VER23qTvUHsBf7JTFLvjdjto4u +-----END CERTIFICATE----- diff --git a/samples/tls/server/sbin/conf/bak/foo-key.pem b/samples/tls/server/sbin/conf/bak/foo-key.pem new file mode 100644 index 000000000..98b497d5c --- /dev/null +++ b/samples/tls/server/sbin/conf/bak/foo-key.pem @@ -0,0 +1,16 @@ +-----BEGIN PRIVATE KEY----- +MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBALzYo0y+SNWs/DBP +SyNhTyDtMHey+LpCTJrNKnXHUhMog7qvsjt3KYGleNB1KqLZ4nG62QVi6jjT2cRz +q1SQJpSx48lReiWzw8tFgxU1blU9YavyDUla4m0LoNOrTIruJXBZdtmvYw3WuNfG +MAy2SmHz98ASYfblSvVUzgRF7V57AgMBAAECgYEAu142p+4kVd1MWqJR6sihugmc +DSeFoUgmuXDWsAUTae7IxHGOZXHVvMxxEmMt6mZERpMcwDtkKP4JEuGxHDXqD+oS +mOKJ+bN+Y02CKoAJW2HSoOMP+L1dBgjqkL+2E/ufiYMLcjQk5rMsbfgUMMPnyo8z +Tqn9rehxI7TXtuS1AAECQQDfT37As7CIo3YRIqi5sqj8WAJCUcQo4oMCif184Ebr +tpbd4rCkNFH/TEwQTkIbjGbXLihXGlWRebbBPv+QYtT7AkEA2H2aOvf7+0iO28nH +Lu416SvrfaZ/WPgW/Q4rLiThi84Sy59KDZx8gKvpTIz4HatHPg5DNO6XWb4MCH11 +22pkgQJBANLqF3LUhNkZYqtei/QQfbERQtj2t4pSHqEoSeZHQlTheO8LbAE7dXLm +0jTYZXH1kzCL5QgX1Ff5mJY+9UyfPD8CQG7c+1NBVOfcw1OoY/kTgcYTeLfSwJo2 +CcezLselmV73u8ZMnyaTQWq/HmzWL+U5pfUQZrg/ioApg44BeY5QUIECQQCuGTbX +r9JGzDGG7se4fkPidZbU/NLZngOsYdlB3zZn5PTiceLoKGg5cXy0ooVDy7pXD7Jr +Tnec4O4FGzEDyD+m +-----END PRIVATE KEY----- diff --git a/samples/tls/server/sbin/conf/root_cert.pem b/samples/tls/server/sbin/conf/root_cert.pem new file mode 100644 index 000000000..e3f7cd4ea --- /dev/null +++ b/samples/tls/server/sbin/conf/root_cert.pem @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDhjCCAm4CAQAwDQYJKoZIhvcNAQEEBQAwgYgxCzAJBgNVBAYTAmNuMQswCQYD +VQQIEwJiajELMAkGA1UEBxMCYmoxFDASBgNVBAoTC3Rlc3QuY29tLmNuMRQwEgYD +VQQLEwt0ZXN0LmNvbS5jbjEUMBIGA1UEAxMLdGVzdC5jb20uY24xHTAbBgkqhkiG +9w0BCQEWDnpzeHhzekAyNjMubmV0MB4XDTA5MDcwOTA3MTAyNloXDTE5MDcwNzA3 +MTAyNlowgYgxCzAJBgNVBAYTAmNuMQswCQYDVQQIEwJiajELMAkGA1UEBxMCYmox +FDASBgNVBAoTC3Rlc3QuY29tLmNuMRQwEgYDVQQLEwt0ZXN0LmNvbS5jbjEUMBIG +A1UEAxMLdGVzdC5jb20uY24xHTAbBgkqhkiG9w0BCQEWDnpzeHhzekAyNjMubmV0 +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvRDxA/oj8dfLNR3fE/5P +VeLNiPnEBSchJXAwAnohwBT/8W+x0K4rW3mGkdh4vN5brhsLUUWJrLgh2KT95REl +rFQ7TZLG/nqVxGMNvW2KwuXo0eWTLp7AkwHhx6SBoqjsupIxzofXRm55Im4kPwcu +1Kx12YaSk6nwNgc7K4UJ/M+9ybSqz8dYoGR3FdJybJd0eOwfxjtN1BR6hqHlvMra +E90jprzWh4aaCZKGBJE7Ma/AF2ziBzru3wCKvL9TOnVe8ChlKm77cuky77CMXX0G +8HHfkNvCf/T7tRhVTZIstivRJu47AUYv1KJsRf3aUV3JIZ52JnNO7Ng2+D8jR0wJ +PQIDAQABMA0GCSqGSIb3DQEBBAUAA4IBAQB8yAUveT5j+hg/iv5ngyg657AkMjK5 +lHrDZPGgt0Wg4yGh0IeDU+TwlTNl6+6/DmRx/HNEKZErY7Y1kPXn2NOMz3nuSAk0 +iMSoiRMreIPGzDulZPWok0/pne0gn26fKBUA6nkRIxKBdHPobzD/4fI2e225cq73 +sF4WVtl2XpXvc71wK1xo063cplNr0HYlTLfgim87xZdtoSdz7LEt4ElwBbQIIAD6 +xweucWdYqiT89AvUVrP6kVyS47/v5RKjqLnGstF2RuNCSNtEAt9UMpobo7Jq6tOc +4pkcwzRFPI5diwRxxPLtmaIxW0SfX+XZr+snI9q5b8z83l+dO/N6GAgd +-----END CERTIFICATE----- diff --git a/samples/tls/server/sbin/conf/root_cert.srl b/samples/tls/server/sbin/conf/root_cert.srl new file mode 100644 index 000000000..9e22bcb8e --- /dev/null +++ b/samples/tls/server/sbin/conf/root_cert.srl @@ -0,0 +1 @@ +02 diff --git a/samples/tls/server/sbin/conf/root_key.pem b/samples/tls/server/sbin/conf/root_key.pem new file mode 100644 index 000000000..96dd91a87 --- /dev/null +++ b/samples/tls/server/sbin/conf/root_key.pem @@ -0,0 +1,30 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,AF4A984BABC0C0B6 + +T38cYSRPsbybnpaadsROdX9800PyfLhRxBYsu84VOr8E6V5U5Su4QeEqoGy+v8ea +qwK2FaSr9xTEi/WcOhEu2kBFkrUqbG0S/ojsFVJ6pkVcWWEgjNuMpykNT8T6fiN9 +oKydew0gyvo3WnTKQMkyJEcPl5yZ++Mfk4qvAJVbY3ysEiWUVtsb7yWliZuKBp8a +Mxi/OkIZ3ADdpV+kBV0ABv8BJju1GskK7AyUzbzdrRoVgFxIZcm4Es1JmPwsPd3G +aUM1WE2EyAFJiZs5wr7ITnfoBPpQwYUu4FuA1v/pQ/WGqWAZznN4sQ0aJrhuQIX8 +rvFRGT5DgOoDqBGAhsB2IX+q4ghNMi2zNOXOZQ2C9JRUOSXk7O2laqt1owUAzgAR +HgSbDNM6PrSKSguMkiGfNTG8tQPuruCGY3LvAntpiRQeKGn2mUzCxLBPqpXd7FTi +mxzXhDnbjhzC1RrnbYWrRujU/4dkwm+mV+THzeqUqP1m6jkBb6yV0nokMHW6fSx1 +E76ZjSZJUJqTgQTZFzHJYeOmxW4xQGqx2S1YnyJ241liYofqo8OpBXSLUUiI0u8u +k+fue9UUWsU5XibpFxhaiNLdLmlJcQoaZw0xbqnrAHaunVRRjhtGdg63l1HV0qoF +AsqjVyYsIa3a24O7S49/LwvLsQzewmR3w+7E8eT9kY0lYj6c791GXLDg8x0lfXLt +7AIK2qpUvk/hqibH3l+MC3XpzUaNgny9kWS5HskrLjYM6mGC6RH0YVi0DKZU86bU +mYUUnq1RQLwcZcxH5QBVdiViqOVv7YcWPDhi8DnA2oKaslfZBRBv1dVIo3KgDzq+ +QAW58fsAcgZaOvMRBjMo8Hxvb6A4PZ2Oifki3w4S8iW6HHHTB1yGp273FC/TsbN+ +fSooE0Jw2qSAXYXa47xHJk1VmeoTt8D4nRh2IZsIrJNlkYYxyh5YqW+3J1u90hel +9mQwLGJISQagxfELjV0wPofSifrcmvKQBAyXzvEE0THgJEb8Um9st9OjFNchZR5U +p5aKTdYqvPobd4oH+klXgP5qqrTQcz+Oq8yt8Bhs71NNsgUf17jJSxAvH84O0QUV +n6+QsPA9vGBYC1ss1d63rvv6suhGmoCgSbJcJtpwQys6TZ4jrWGXPzAtyCHY73U/ +FQTDmfn9jPe0Q/62BmfxmYFbnm4oaCL4BEOfjPen6fHjEdupbzHmhpeHTT8apzgA +NhAA19NARjMorNuKlpUNIg+1x/Dv+l7HFpik2gat3tIHcf/BQWLs+9f8RIp806Cw +TKh0uLMMpt8ma29hAPODT6wHYL1IwFeSEV4kY2Y5A54Gw2CzlVdUAy1OsY1gM1J4 +e8m3GeDbbLkGLAC0ofa0+4HUxj+tN9EmQOkdzH7PPAOQU0ZHJ+OqjNqgFCmhBheA +t1T6pRteMhir2GxI3QavNEddCNwqNeXrDRC2EW+kbZoXT6tF7C3ats60S+eH2SaS +RDjZvbvBqAIQWLpmTe7zsF5rtGH4/ka1E/jB4XgTm2zyd5xZygCXE+VwsuZVEABO +n2GkC/jPPB5ZGaasPndvol0NTbqU2BCzlzTjGlhhQC0Ks1f0At2wEw== +-----END RSA PRIVATE KEY----- diff --git a/samples/tls/server/sbin/conf/root_req.pem b/samples/tls/server/sbin/conf/root_req.pem new file mode 100644 index 000000000..7c6abed16 --- /dev/null +++ b/samples/tls/server/sbin/conf/root_req.pem @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIIC+DCCAeACAQAwgYgxCzAJBgNVBAYTAmNuMQswCQYDVQQIEwJiajELMAkGA1UE +BxMCYmoxFDASBgNVBAoTC3Rlc3QuY29tLmNuMRQwEgYDVQQLEwt0ZXN0LmNvbS5j +bjEUMBIGA1UEAxMLdGVzdC5jb20uY24xHTAbBgkqhkiG9w0BCQEWDnpzeHhzekAy +NjMubmV0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvRDxA/oj8dfL +NR3fE/5PVeLNiPnEBSchJXAwAnohwBT/8W+x0K4rW3mGkdh4vN5brhsLUUWJrLgh +2KT95RElrFQ7TZLG/nqVxGMNvW2KwuXo0eWTLp7AkwHhx6SBoqjsupIxzofXRm55 +Im4kPwcu1Kx12YaSk6nwNgc7K4UJ/M+9ybSqz8dYoGR3FdJybJd0eOwfxjtN1BR6 +hqHlvMraE90jprzWh4aaCZKGBJE7Ma/AF2ziBzru3wCKvL9TOnVe8ChlKm77cuky +77CMXX0G8HHfkNvCf/T7tRhVTZIstivRJu47AUYv1KJsRf3aUV3JIZ52JnNO7Ng2 ++D8jR0wJPQIDAQABoCowEQYJKoZIhvcNAQkCMQQTAmh4MBUGCSqGSIb3DQEJBzEI +EwYxMTExMTEwDQYJKoZIhvcNAQEFBQADggEBAERSkYiPGQTT4BIP/GDapqgEz2oa +ul2NFHjapc6r+UJBLDsS3RdpkqfXByQ9nE5HKrz8o+lTV9oP/6wUXMOGIlWEEOQS +ZqzzuYvE04Qk6Y3fDsCwPY7zSdU41OhQ0XJYhzs01a52CRjCyFWKzSfda/cz/SKm +bI6902xFK2nIlQnUKeb/Zgj/OnGiSZVfjkwFDIxyV7AeV35HMIGlSKOsDtZ76G6g +vRfhnv/+lf3bGN2IJaIlYdZO9Z0uta0GHs7R/TrIE4Z66KhXs2uvnV1XkYv+16RZ +3twDMgEBNhANZn8uksdG64Pub3Nv8MaUOhPZ3VaT4PmAFftBDrCL38wnKYY= +-----END CERTIFICATE REQUEST----- diff --git a/samples/tls/server/sbin/conf/server.pem b/samples/tls/server/sbin/conf/server.pem new file mode 100644 index 000000000..9f0e76033 --- /dev/null +++ b/samples/tls/server/sbin/conf/server.pem @@ -0,0 +1,30 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQDnFcDV3tRP2MMGuL1Tb+Y8llRzMa5HPwkyFvXqUj5h1PxZRedm +rVnS4q3Ti4XmoMZW6bKcSEk58BX41MGpeFa2v3cDE5T+uEqkVLm/TJGRrMcSrFdG +9+o9+rWHcS8AfTAxaqFcQdm20jeuh7naaaNWYl7dmihMClwPehdICsEs8QIDAQAB +AoGAPReFKYWFf66AsNA6TUqyBaaAoQurVW6W0cU8MjyX/Wk/ZaKTcJO3wYboCZtD +RRuQE/4omCSMJ2MPi/9DS7hiw+Daii6MpvpwhGWegSF9PHJ3IKrLb+fgQjf3H8Y8 +3IrFJVq2tKHE+uCijrFgdt/FzuIAD9yXKxOLjiU/pTrEsYECQQD88LSu2wUgHuyh +Z0sp3wW8y4iBIHgLxWiQhEFGsx8KoE38sifNkr+1gOn/jmVywLf2Ww61I49/zcBf +Npb/VL5JAkEA6eFd82Ldn4HB8+Cr3mZV7DTSgr4VDpkOYsFeUYp3oYXtibYfQleB +F1+hwFvMbobpmjf3uXH2NtQkewok/xoZaQJBAKU4sj2ZkYKG0LkpmN5z8PJ+3N7E +D8ZYn9HuohkFfhxZ1DdhRECzQAjWeYNWR4wquL/ygOvvm5e3FZbcOMv2VgkCQB66 +2OBY1ivWHcjQdWSkZ5fAnQRGu3eOjsBVDfKC0hMsCLj2cAcEfla23wbqSOMg4OK9 +hdQc8C/mEeEExTWrlTkCQQDcF+zRl4UiIjwFES/Ghbu2tyG6QH+BUrZmG3WmBim7 +mrYKTB5K8/InRFUkkClhf7aFyCvHQDMRlxiMT1QovSXm +-----END RSA PRIVATE KEY----- +-----BEGIN CERTIFICATE----- +MIICXTCCAcagAwIBAgIBADANBgkqhkiG9w0BAQQFADBpMQswCQYDVQQGEwJjbjEL +MAkGA1UECBMCYmoxCzAJBgNVBAcTAmJqMRQwEgYDVQQKEwt0ZXN0LmNvbS5jbjEU +MBIGA1UECxMLdGVzdC5jb20uY24xFDASBgNVBAMTC3Rlc3QuY29tLmNuMB4XDTA5 +MDcwOTA4MTAxMFoXDTEwMDcwOTA4MTAxMFowaTELMAkGA1UEBhMCY24xCzAJBgNV +BAgTAmJqMQswCQYDVQQHEwJiajEUMBIGA1UEChMLdGVzdC5jb20uY24xFDASBgNV +BAsTC3Rlc3QuY29tLmNuMRQwEgYDVQQDEwt0ZXN0LmNvbS5jbjCBnzANBgkqhkiG +9w0BAQEFAAOBjQAwgYkCgYEA5xXA1d7UT9jDBri9U2/mPJZUczGuRz8JMhb16lI+ +YdT8WUXnZq1Z0uKt04uF5qDGVumynEhJOfAV+NTBqXhWtr93AxOU/rhKpFS5v0yR +kazHEqxXRvfqPfq1h3EvAH0wMWqhXEHZttI3roe52mmjVmJe3ZooTApcD3oXSArB +LPECAwEAAaMVMBMwEQYJYIZIAYb4QgEBBAQDAgZAMA0GCSqGSIb3DQEBBAUAA4GB +AJeGFCk7npfEFGTlfND5WpG0iD1Hku+zEZMi/oHAlI+3AGXrb441yHFsEzWPG1dq +4gNCCb1RMmfNlB2cB6RbG6r7X+QDjFJztA6OAxCmXE8BrVEhugSmavgkbv0eLWph +oPbwQ0Mlsc/88jZLInypxmmxeDtQDjBVmSX5J3TEfNN+ +-----END CERTIFICATE----- diff --git a/samples/tls/server/sbin/conf/server.pem.bak b/samples/tls/server/sbin/conf/server.pem.bak new file mode 100644 index 000000000..36e60b196 --- /dev/null +++ b/samples/tls/server/sbin/conf/server.pem.bak @@ -0,0 +1,69 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEA0gCrdm/GQJM0q0VOCDzRL24EapzlU4e2BdT8J/w3sr1wgoa5 +CMhCe2ZXvoHlWcFKK85yTOuA0m+sVIrYul7Sh4B5574+HGMJsOx270YIgswxTbr5 +y/wO9nBsyT5yloD3f2FXTwuy5v2QOuSCIUX5DMFk3otrTR7nnvSidgs5xBK7kbpu +7QTwGscVonW66KFQs6Hmr8uZyNnEftEIp9oaUhUSQUpenSavAUeShGxwLs8P0O04 +lOCLIkOgu6MK34AaOaJvBY6keoipd3bpBzStlwUH1uJcu5TeNSzsKaUWq/59Xbs6 +pj7RKJCjqdr+ggOBeBNhm3rvU6b2qgvmtoZ6UQIDAQABAoIBAAyRQbGaytB+fr5p +LVxM12/xM451yTuQeZIrxtNVwreNorgM+/HMmj3sR//8og8XBCtO9YQo69KsIDIH +BSVSG2NEiwcVWX41ZxURcaSsGkJJmgG+2MgeU37oB3qbpBvhp+4VkzYFyzULo6AC +oM8A8wCSakjvKwK4gMAAf+B0l4ZmRLzyJcC36DHWGapfKV1DDW7M/AsRdrPiVEVE +8JVrtGBEaDssyGHwZu9SuQ3qOoDPqLD6/83qvBvoA8GmHABEuK0huz3AteH2SoFf +3j5qry07ERwHQ810/PafbGqhr68QLqo56O2ho09EU0vEheLcxf2zSd4uqNPUcanh +VQm2zAkCgYEA/I05daZruJf3aQskHb/R6nWxbL7vI9FDwiDtGEWdj2ceo2Vi6uy6 +1hFg4k1mvOFIt7gczfcKhUfzlRKquxw96KHuumNIkUfm94jHiAajI+tQVxyy6fJl +6vC1uHFqW4vuWSQCW+hnBz5iy2aBZzmg5cdYKRXsm8mAiv5QWObKeVcCgYEA1N63 +40mfjdGC0LivO3vPWqIKZlsG5zFZr+NcDPMfkyTfr4GhgiHx3FlngyKSyv6Iufbk +eCIskqtwT/UWOrhgScDMF+HaRKF0GqbcT8Bo9vFmu3234S4skrBm0OSbtK35kymg +pM8rJV5CCuih75JcjB/faP0Z8bqhTA7AdGrVWJcCgYAkHKF5tCk1BO3IpGIuqs3+ +Q4PyM78IFRUmPgUI8nNcHPehj468Xss8btG2qjClk2UNeBMOVGO5uRcYWsn05U3o +5La5ChdHRsu8218EkUZkjXI4co8WqqVuGasyS21U18ZmEqMPt0R8IayIvwiD1Rav +pHhzr4HcqMxrk3+zppSPEwKBgAWcBN6BbynujnLvmvaHUbSCtqFx3qGzBDkFVcSl +l3xqKVbXpKjoOhZjaL3k6FdfE71Ky0R7Kg+HYwNIYxiTCT6ITRiIBBdw5b1aDk4v +tNRlEh74tiLB87y910fD7nJ5by04mJofN3TZogXlkXbdtYCfymRa3xcmot99OAcZ +VZvrAoGBAMlA+APjRoJtpE7SOmqrUVfw3vb7LH0BDAVilnWSPFTt7caR65wt6iE9 +3rbcSC4K/iAeuo5LON+b6ERPIKUWSt2cWa13/9qAhHkKzYl7pJelIP+E6PWLMxwO +R+tbCE0xKCVm/S9V0JyuZfDDUEBwH2o6DmJyhTgLEbTOLRPz6R/Y +-----END RSA PRIVATE KEY----- +-----BEGIN CERTIFICATE----- +MIIDhjCCAm4CAQEwDQYJKoZIhvcNAQEEBQAwgYgxCzAJBgNVBAYTAmNuMQswCQYD +VQQIEwJiajELMAkGA1UEBxMCYmoxFDASBgNVBAoTC3Rlc3QuY29tLmNuMRQwEgYD +VQQLEwt0ZXN0LmNvbS5jbjEUMBIGA1UEAxMLdGVzdC5jb20uY24xHTAbBgkqhkiG +9w0BCQEWDnpzeHhzekAyNjMubmV0MB4XDTA5MDcwOTA3MTExOVoXDTE5MDcwNzA3 +MTExOVowgYgxCzAJBgNVBAYTAmNuMQswCQYDVQQIEwJiajELMAkGA1UEBxMCYmox +FDASBgNVBAoTC3Rlc3QuY29tLmNuMRQwEgYDVQQLEwt0ZXN0LmNvbS5jbjEUMBIG +A1UEAxMLdGVzdC5jb20uY24xHTAbBgkqhkiG9w0BCQEWDnpzeHhzekAyNjMubmV0 +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0gCrdm/GQJM0q0VOCDzR +L24EapzlU4e2BdT8J/w3sr1wgoa5CMhCe2ZXvoHlWcFKK85yTOuA0m+sVIrYul7S +h4B5574+HGMJsOx270YIgswxTbr5y/wO9nBsyT5yloD3f2FXTwuy5v2QOuSCIUX5 +DMFk3otrTR7nnvSidgs5xBK7kbpu7QTwGscVonW66KFQs6Hmr8uZyNnEftEIp9oa +UhUSQUpenSavAUeShGxwLs8P0O04lOCLIkOgu6MK34AaOaJvBY6keoipd3bpBzSt +lwUH1uJcu5TeNSzsKaUWq/59Xbs6pj7RKJCjqdr+ggOBeBNhm3rvU6b2qgvmtoZ6 +UQIDAQABMA0GCSqGSIb3DQEBBAUAA4IBAQCmOFiwpoZ98j6qvYaUxWbg7y1WU3v6 +f0Ky9HtgqwZQv8AGpreo6CW76M4TlLLO54jhre52+eZwIj6ovlhYbpozds5+6+DO +JrX/C4/Ty0jNWOIpCOf56ZuyyW69ERH34nt4k4ErgoDqBuR727jbn/tps+pBEXht +dFSzn7YQUAYutU8oeOJoPUbV9tA64O62l+U98Mms8UDZDAVqaIhym6mKDjPTEaXp +ap0yTsFc+P/2DVhgxHOaLFeREgLhZHSWZ8i0oz3chUMKjEW5IEbwy9orvW4DvK7i +93t69n/GpuLuWf5T7CDV+gPjucBZGk3DEJTFqIRPYu64ian7Z4yFeH8J +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDhjCCAm4CAQAwDQYJKoZIhvcNAQEEBQAwgYgxCzAJBgNVBAYTAmNuMQswCQYD +VQQIEwJiajELMAkGA1UEBxMCYmoxFDASBgNVBAoTC3Rlc3QuY29tLmNuMRQwEgYD +VQQLEwt0ZXN0LmNvbS5jbjEUMBIGA1UEAxMLdGVzdC5jb20uY24xHTAbBgkqhkiG +9w0BCQEWDnpzeHhzekAyNjMubmV0MB4XDTA5MDcwOTA3MTAyNloXDTE5MDcwNzA3 +MTAyNlowgYgxCzAJBgNVBAYTAmNuMQswCQYDVQQIEwJiajELMAkGA1UEBxMCYmox +FDASBgNVBAoTC3Rlc3QuY29tLmNuMRQwEgYDVQQLEwt0ZXN0LmNvbS5jbjEUMBIG +A1UEAxMLdGVzdC5jb20uY24xHTAbBgkqhkiG9w0BCQEWDnpzeHhzekAyNjMubmV0 +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvRDxA/oj8dfLNR3fE/5P +VeLNiPnEBSchJXAwAnohwBT/8W+x0K4rW3mGkdh4vN5brhsLUUWJrLgh2KT95REl +rFQ7TZLG/nqVxGMNvW2KwuXo0eWTLp7AkwHhx6SBoqjsupIxzofXRm55Im4kPwcu +1Kx12YaSk6nwNgc7K4UJ/M+9ybSqz8dYoGR3FdJybJd0eOwfxjtN1BR6hqHlvMra +E90jprzWh4aaCZKGBJE7Ma/AF2ziBzru3wCKvL9TOnVe8ChlKm77cuky77CMXX0G +8HHfkNvCf/T7tRhVTZIstivRJu47AUYv1KJsRf3aUV3JIZ52JnNO7Ng2+D8jR0wJ +PQIDAQABMA0GCSqGSIb3DQEBBAUAA4IBAQB8yAUveT5j+hg/iv5ngyg657AkMjK5 +lHrDZPGgt0Wg4yGh0IeDU+TwlTNl6+6/DmRx/HNEKZErY7Y1kPXn2NOMz3nuSAk0 +iMSoiRMreIPGzDulZPWok0/pne0gn26fKBUA6nkRIxKBdHPobzD/4fI2e225cq73 +sF4WVtl2XpXvc71wK1xo063cplNr0HYlTLfgim87xZdtoSdz7LEt4ElwBbQIIAD6 +xweucWdYqiT89AvUVrP6kVyS47/v5RKjqLnGstF2RuNCSNtEAt9UMpobo7Jq6tOc +4pkcwzRFPI5diwRxxPLtmaIxW0SfX+XZr+snI9q5b8z83l+dO/N6GAgd +-----END CERTIFICATE----- diff --git a/samples/tls/server/sbin/conf/server.pem.bak1 b/samples/tls/server/sbin/conf/server.pem.bak1 new file mode 100644 index 000000000..9f0e76033 --- /dev/null +++ b/samples/tls/server/sbin/conf/server.pem.bak1 @@ -0,0 +1,30 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQDnFcDV3tRP2MMGuL1Tb+Y8llRzMa5HPwkyFvXqUj5h1PxZRedm +rVnS4q3Ti4XmoMZW6bKcSEk58BX41MGpeFa2v3cDE5T+uEqkVLm/TJGRrMcSrFdG +9+o9+rWHcS8AfTAxaqFcQdm20jeuh7naaaNWYl7dmihMClwPehdICsEs8QIDAQAB +AoGAPReFKYWFf66AsNA6TUqyBaaAoQurVW6W0cU8MjyX/Wk/ZaKTcJO3wYboCZtD +RRuQE/4omCSMJ2MPi/9DS7hiw+Daii6MpvpwhGWegSF9PHJ3IKrLb+fgQjf3H8Y8 +3IrFJVq2tKHE+uCijrFgdt/FzuIAD9yXKxOLjiU/pTrEsYECQQD88LSu2wUgHuyh +Z0sp3wW8y4iBIHgLxWiQhEFGsx8KoE38sifNkr+1gOn/jmVywLf2Ww61I49/zcBf +Npb/VL5JAkEA6eFd82Ldn4HB8+Cr3mZV7DTSgr4VDpkOYsFeUYp3oYXtibYfQleB +F1+hwFvMbobpmjf3uXH2NtQkewok/xoZaQJBAKU4sj2ZkYKG0LkpmN5z8PJ+3N7E +D8ZYn9HuohkFfhxZ1DdhRECzQAjWeYNWR4wquL/ygOvvm5e3FZbcOMv2VgkCQB66 +2OBY1ivWHcjQdWSkZ5fAnQRGu3eOjsBVDfKC0hMsCLj2cAcEfla23wbqSOMg4OK9 +hdQc8C/mEeEExTWrlTkCQQDcF+zRl4UiIjwFES/Ghbu2tyG6QH+BUrZmG3WmBim7 +mrYKTB5K8/InRFUkkClhf7aFyCvHQDMRlxiMT1QovSXm +-----END RSA PRIVATE KEY----- +-----BEGIN CERTIFICATE----- +MIICXTCCAcagAwIBAgIBADANBgkqhkiG9w0BAQQFADBpMQswCQYDVQQGEwJjbjEL +MAkGA1UECBMCYmoxCzAJBgNVBAcTAmJqMRQwEgYDVQQKEwt0ZXN0LmNvbS5jbjEU +MBIGA1UECxMLdGVzdC5jb20uY24xFDASBgNVBAMTC3Rlc3QuY29tLmNuMB4XDTA5 +MDcwOTA4MTAxMFoXDTEwMDcwOTA4MTAxMFowaTELMAkGA1UEBhMCY24xCzAJBgNV +BAgTAmJqMQswCQYDVQQHEwJiajEUMBIGA1UEChMLdGVzdC5jb20uY24xFDASBgNV +BAsTC3Rlc3QuY29tLmNuMRQwEgYDVQQDEwt0ZXN0LmNvbS5jbjCBnzANBgkqhkiG +9w0BAQEFAAOBjQAwgYkCgYEA5xXA1d7UT9jDBri9U2/mPJZUczGuRz8JMhb16lI+ +YdT8WUXnZq1Z0uKt04uF5qDGVumynEhJOfAV+NTBqXhWtr93AxOU/rhKpFS5v0yR +kazHEqxXRvfqPfq1h3EvAH0wMWqhXEHZttI3roe52mmjVmJe3ZooTApcD3oXSArB +LPECAwEAAaMVMBMwEQYJYIZIAYb4QgEBBAQDAgZAMA0GCSqGSIb3DQEBBAUAA4GB +AJeGFCk7npfEFGTlfND5WpG0iD1Hku+zEZMi/oHAlI+3AGXrb441yHFsEzWPG1dq +4gNCCb1RMmfNlB2cB6RbG6r7X+QDjFJztA6OAxCmXE8BrVEhugSmavgkbv0eLWph +oPbwQ0Mlsc/88jZLInypxmmxeDtQDjBVmSX5J3TEfNN+ +-----END CERTIFICATE----- diff --git a/samples/tls/server/sbin/conf/server.pfx b/samples/tls/server/sbin/conf/server.pfx new file mode 100644 index 000000000..773f80a6a Binary files /dev/null and b/samples/tls/server/sbin/conf/server.pfx differ diff --git a/samples/tls/server/sbin/conf/server_cert.pem b/samples/tls/server/sbin/conf/server_cert.pem new file mode 100644 index 000000000..a0d42494f --- /dev/null +++ b/samples/tls/server/sbin/conf/server_cert.pem @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDhjCCAm4CAQEwDQYJKoZIhvcNAQEEBQAwgYgxCzAJBgNVBAYTAmNuMQswCQYD +VQQIEwJiajELMAkGA1UEBxMCYmoxFDASBgNVBAoTC3Rlc3QuY29tLmNuMRQwEgYD +VQQLEwt0ZXN0LmNvbS5jbjEUMBIGA1UEAxMLdGVzdC5jb20uY24xHTAbBgkqhkiG +9w0BCQEWDnpzeHhzekAyNjMubmV0MB4XDTA5MDcwOTA3MTExOVoXDTE5MDcwNzA3 +MTExOVowgYgxCzAJBgNVBAYTAmNuMQswCQYDVQQIEwJiajELMAkGA1UEBxMCYmox +FDASBgNVBAoTC3Rlc3QuY29tLmNuMRQwEgYDVQQLEwt0ZXN0LmNvbS5jbjEUMBIG +A1UEAxMLdGVzdC5jb20uY24xHTAbBgkqhkiG9w0BCQEWDnpzeHhzekAyNjMubmV0 +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0gCrdm/GQJM0q0VOCDzR +L24EapzlU4e2BdT8J/w3sr1wgoa5CMhCe2ZXvoHlWcFKK85yTOuA0m+sVIrYul7S +h4B5574+HGMJsOx270YIgswxTbr5y/wO9nBsyT5yloD3f2FXTwuy5v2QOuSCIUX5 +DMFk3otrTR7nnvSidgs5xBK7kbpu7QTwGscVonW66KFQs6Hmr8uZyNnEftEIp9oa +UhUSQUpenSavAUeShGxwLs8P0O04lOCLIkOgu6MK34AaOaJvBY6keoipd3bpBzSt +lwUH1uJcu5TeNSzsKaUWq/59Xbs6pj7RKJCjqdr+ggOBeBNhm3rvU6b2qgvmtoZ6 +UQIDAQABMA0GCSqGSIb3DQEBBAUAA4IBAQCmOFiwpoZ98j6qvYaUxWbg7y1WU3v6 +f0Ky9HtgqwZQv8AGpreo6CW76M4TlLLO54jhre52+eZwIj6ovlhYbpozds5+6+DO +JrX/C4/Ty0jNWOIpCOf56ZuyyW69ERH34nt4k4ErgoDqBuR727jbn/tps+pBEXht +dFSzn7YQUAYutU8oeOJoPUbV9tA64O62l+U98Mms8UDZDAVqaIhym6mKDjPTEaXp +ap0yTsFc+P/2DVhgxHOaLFeREgLhZHSWZ8i0oz3chUMKjEW5IEbwy9orvW4DvK7i +93t69n/GpuLuWf5T7CDV+gPjucBZGk3DEJTFqIRPYu64ian7Z4yFeH8J +-----END CERTIFICATE----- diff --git a/samples/tls/server/sbin/conf/server_key.pem b/samples/tls/server/sbin/conf/server_key.pem new file mode 100644 index 000000000..31f06ab0a --- /dev/null +++ b/samples/tls/server/sbin/conf/server_key.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEA0gCrdm/GQJM0q0VOCDzRL24EapzlU4e2BdT8J/w3sr1wgoa5 +CMhCe2ZXvoHlWcFKK85yTOuA0m+sVIrYul7Sh4B5574+HGMJsOx270YIgswxTbr5 +y/wO9nBsyT5yloD3f2FXTwuy5v2QOuSCIUX5DMFk3otrTR7nnvSidgs5xBK7kbpu +7QTwGscVonW66KFQs6Hmr8uZyNnEftEIp9oaUhUSQUpenSavAUeShGxwLs8P0O04 +lOCLIkOgu6MK34AaOaJvBY6keoipd3bpBzStlwUH1uJcu5TeNSzsKaUWq/59Xbs6 +pj7RKJCjqdr+ggOBeBNhm3rvU6b2qgvmtoZ6UQIDAQABAoIBAAyRQbGaytB+fr5p +LVxM12/xM451yTuQeZIrxtNVwreNorgM+/HMmj3sR//8og8XBCtO9YQo69KsIDIH +BSVSG2NEiwcVWX41ZxURcaSsGkJJmgG+2MgeU37oB3qbpBvhp+4VkzYFyzULo6AC +oM8A8wCSakjvKwK4gMAAf+B0l4ZmRLzyJcC36DHWGapfKV1DDW7M/AsRdrPiVEVE +8JVrtGBEaDssyGHwZu9SuQ3qOoDPqLD6/83qvBvoA8GmHABEuK0huz3AteH2SoFf +3j5qry07ERwHQ810/PafbGqhr68QLqo56O2ho09EU0vEheLcxf2zSd4uqNPUcanh +VQm2zAkCgYEA/I05daZruJf3aQskHb/R6nWxbL7vI9FDwiDtGEWdj2ceo2Vi6uy6 +1hFg4k1mvOFIt7gczfcKhUfzlRKquxw96KHuumNIkUfm94jHiAajI+tQVxyy6fJl +6vC1uHFqW4vuWSQCW+hnBz5iy2aBZzmg5cdYKRXsm8mAiv5QWObKeVcCgYEA1N63 +40mfjdGC0LivO3vPWqIKZlsG5zFZr+NcDPMfkyTfr4GhgiHx3FlngyKSyv6Iufbk +eCIskqtwT/UWOrhgScDMF+HaRKF0GqbcT8Bo9vFmu3234S4skrBm0OSbtK35kymg +pM8rJV5CCuih75JcjB/faP0Z8bqhTA7AdGrVWJcCgYAkHKF5tCk1BO3IpGIuqs3+ +Q4PyM78IFRUmPgUI8nNcHPehj468Xss8btG2qjClk2UNeBMOVGO5uRcYWsn05U3o +5La5ChdHRsu8218EkUZkjXI4co8WqqVuGasyS21U18ZmEqMPt0R8IayIvwiD1Rav +pHhzr4HcqMxrk3+zppSPEwKBgAWcBN6BbynujnLvmvaHUbSCtqFx3qGzBDkFVcSl +l3xqKVbXpKjoOhZjaL3k6FdfE71Ky0R7Kg+HYwNIYxiTCT6ITRiIBBdw5b1aDk4v +tNRlEh74tiLB87y910fD7nJ5by04mJofN3TZogXlkXbdtYCfymRa3xcmot99OAcZ +VZvrAoGBAMlA+APjRoJtpE7SOmqrUVfw3vb7LH0BDAVilnWSPFTt7caR65wt6iE9 +3rbcSC4K/iAeuo5LON+b6ERPIKUWSt2cWa13/9qAhHkKzYl7pJelIP+E6PWLMxwO +R+tbCE0xKCVm/S9V0JyuZfDDUEBwH2o6DmJyhTgLEbTOLRPz6R/Y +-----END RSA PRIVATE KEY----- diff --git a/samples/tls/server/sbin/conf/server_req.pem b/samples/tls/server/sbin/conf/server_req.pem new file mode 100644 index 000000000..debc6493e --- /dev/null +++ b/samples/tls/server/sbin/conf/server_req.pem @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIIC+DCCAeACAQAwgYgxCzAJBgNVBAYTAmNuMQswCQYDVQQIEwJiajELMAkGA1UE +BxMCYmoxFDASBgNVBAoTC3Rlc3QuY29tLmNuMRQwEgYDVQQLEwt0ZXN0LmNvbS5j +bjEUMBIGA1UEAxMLdGVzdC5jb20uY24xHTAbBgkqhkiG9w0BCQEWDnpzeHhzekAy +NjMubmV0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0gCrdm/GQJM0 +q0VOCDzRL24EapzlU4e2BdT8J/w3sr1wgoa5CMhCe2ZXvoHlWcFKK85yTOuA0m+s +VIrYul7Sh4B5574+HGMJsOx270YIgswxTbr5y/wO9nBsyT5yloD3f2FXTwuy5v2Q +OuSCIUX5DMFk3otrTR7nnvSidgs5xBK7kbpu7QTwGscVonW66KFQs6Hmr8uZyNnE +ftEIp9oaUhUSQUpenSavAUeShGxwLs8P0O04lOCLIkOgu6MK34AaOaJvBY6keoip +d3bpBzStlwUH1uJcu5TeNSzsKaUWq/59Xbs6pj7RKJCjqdr+ggOBeBNhm3rvU6b2 +qgvmtoZ6UQIDAQABoCowEQYJKoZIhvcNAQkCMQQTAmh4MBUGCSqGSIb3DQEJBzEI +EwYxMTExMTEwDQYJKoZIhvcNAQEEBQADggEBAIBFY5AkTxMWKd0KKotdZz8tTMbW +UxOswkEz25el1uiOcNnIGt0pbl6BjZTGCTBTC1RkJPuWRwT5uZ+F1VpNPzxkMcg0 +p7rF396wBf459ZT2pK0YopfLCFPt1YwBEktW0DYMSQd1r50z/sKPaEEZB95yt59H +KBriUw9bCZ6CC8oixnnwHm4rTFYpgOCGtssSiTd7BFd9d9kQtMHbO9ca8Mav39R8 +x3PmQH4GSnSFOsQF18LEbfpXv5tqIVM8zYAwKddTqoAUkgrDjqw4teKIiZpRBr0n +QuhDpC3wimeKWVOGppX8qTRwC+zv0SKD+aC0VEWxQdN0ysst42pGHF9xZww= +-----END CERTIFICATE REQUEST----- diff --git a/samples/tls/server/sbin/tlssvr.cf b/samples/tls/server/sbin/tlssvr.cf new file mode 100644 index 000000000..b37cd5986 --- /dev/null +++ b/samples/tls/server/sbin/tlssvr.cf @@ -0,0 +1,8 @@ + +service tlscli { + server_tls_loglevel = 0 + server_tls_scert_vd = 9 + server_starttls_tmout = 300 + server_tls_session_cache_database = btree:./var/cache_server + client_tls_session_cache_database = btree:./var/cache_client +} diff --git a/samples/tls/server/tls_server.vcproj b/samples/tls/server/tls_server.vcproj new file mode 100644 index 000000000..364049afb --- /dev/null +++ b/samples/tls/server/tls_server.vcproj @@ -0,0 +1,236 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/tls/server/tls_server.vcxproj b/samples/tls/server/tls_server.vcxproj new file mode 100644 index 000000000..9bcf1a6b7 --- /dev/null +++ b/samples/tls/server/tls_server.vcxproj @@ -0,0 +1,191 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + ReleaseDll + Win32 + + + Release + Win32 + + + + {B392992C-340B-417B-81E7-ACB265602DF7} + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\..\lib_acl\include;..\..\..\lib_tls\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;USE_TLS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + libeay32.lib;ssleay32.lib;libdb43.lib;%(AdditionalDependencies) + tls_server.exe + ..\..\..\lib\openssl;..\..\..\lib\bdb;%(AdditionalLibraryDirectories) + true + $(OutDir)tls_server.pdb + Console + MachineX86 + + + + + ..\..\..\lib_acl\include;..\..\..\lib_tls\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;USE_TLS;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + libeay32.lib;ssleay32.lib;libdb43.lib;%(AdditionalDependencies) + tls_server.exe + ..\..\..\lib\openssl;..\..\..\lib\bdb;%(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + + + + + Disabled + ..\..\..\lib_acl\include;..\..\..\lib_tls\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;USE_TLS;TLS_DLL;ACL_DLL;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + EditAndContinue + + + ws2_32.lib;libeay32.lib;ssleay32.lib;libdb43.lib;%(AdditionalDependencies) + tls_server.exe + ..\..\..\lib\openssl;..\..\..\lib\bdb;%(AdditionalLibraryDirectories) + true + $(OutDir)tls_server.pdb + Console + MachineX86 + + + + + ..\..\..\lib_acl\include;..\..\..\lib_tls\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;USE_TLS;TLS_DLL;ACL_DLL;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + $(OutDir)tls_server.exe + true + Console + true + true + MachineX86 + + + + + {b40213c2-507c-4c7f-a6e1-b850c9bdc27b} + true + + + {9e6e9fe9-eaac-44ba-b463-70de0233822e} + true + + + {389fde47-7f16-4dd4-b37a-27918be745b6} + true + + + + + + + + + \ No newline at end of file diff --git a/samples/tls/server/tlssvr.cf b/samples/tls/server/tlssvr.cf new file mode 100644 index 000000000..b37cd5986 --- /dev/null +++ b/samples/tls/server/tlssvr.cf @@ -0,0 +1,8 @@ + +service tlscli { + server_tls_loglevel = 0 + server_tls_scert_vd = 9 + server_starttls_tmout = 300 + server_tls_session_cache_database = btree:./var/cache_server + client_tls_session_cache_database = btree:./var/cache_client +} diff --git a/samples/tls/server/valgrind.sh b/samples/tls/server/valgrind.sh new file mode 100644 index 000000000..a5b15d25a --- /dev/null +++ b/samples/tls/server/valgrind.sh @@ -0,0 +1,2 @@ +#!/bin/sh +valgrind --tool=memcheck --error-limit=no --leak-check=yes --show-reachable=yes ./tlssvr -c tlssvr.cf diff --git a/samples/token_tree/Makefile b/samples/token_tree/Makefile new file mode 100644 index 000000000..2034848b6 --- /dev/null +++ b/samples/token_tree/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = token_tree diff --git a/samples/token_tree/main.c b/samples/token_tree/main.c new file mode 100644 index 000000000..a08e877ac --- /dev/null +++ b/samples/token_tree/main.c @@ -0,0 +1,110 @@ +#include "lib_acl.h" +#include +#include + +#define STR acl_vstring_str + +static void token_tree_test(const char *tokens, const char *test_tab[]) +{ + ACL_TOKEN *token_tree; + const ACL_TOKEN *token; + const char *ptr, *psaved; + ACL_VSTRING *buf = acl_vstring_alloc(256); + int i; + + token_tree = acl_token_tree_create(tokens); + acl_token_tree_print(token_tree); + + for (i = 0; test_tab[i] != NULL; i++) { + ptr = psaved = test_tab[i]; + token = acl_token_tree_match(token_tree, &ptr, ";", NULL); + if (token) { + ACL_VSTRING_RESET(buf); + acl_token_name(token, buf); + printf("match %s %s, token's name: %s\n", psaved, + (token->flag & ACL_TOKEN_F_DENY) ? "DENY" + : (token->flag & ACL_TOKEN_F_PASS ? "PASS" : "NONE"), + STR(buf)); + } else + printf("match %s none\n", psaved); + } + + acl_token_tree_destroy(token_tree); + acl_vstring_free(buf); +} + +static const char *test_tab[] = { + "中国" + "中国人民", + "中国人民银行", + "中国人民解放军", + NULL +}; + +static void test(void) +{ + const char *tokens = "中国|p 中国人|p 中国人民|p 中国人民银行|p"; + + token_tree_test(tokens, test_tab); +} + +static void test2(void) +{ + ACL_TOKEN *tree; + const ACL_TOKEN *token; + const char *n1 = "名称1", *n2 = "名称2", *n3 = "名称3"; + const char *v1 = "变量1", *v2 = "变量2", *v3 = "变量3"; + const char *s = "中国人民名称1,在这个世界上,你在哪儿名称2? " + "我不知道你的名称,你能告诉我吗?我的名称3是..."; + const char *p = s; + + if (1) + { + tree = acl_token_tree_create(NULL); + acl_token_tree_add(tree, n1, ACL_TOKEN_F_STOP, v1); + acl_token_tree_add(tree, n2, ACL_TOKEN_F_STOP, v2); + acl_token_tree_add(tree, n3, ACL_TOKEN_F_STOP, v3); + } + else + tree = acl_token_tree_create("名称1|p 名称2|p 名称3|p"); + + printf("-----------------------------------\n"); + + acl_token_tree_print(tree); + token = acl_token_tree_word_match(tree, "名称1"); + if (token) + printf("find, %s: %s\n", acl_token_name1(token), + (const char*) token->ctx); + else + printf("no find\n"); + + printf("-----------------------------------\n"); + + while (*p) { + token = acl_token_tree_match(tree, &p, NULL, NULL); + if (token == NULL) + break; + printf("%s: %s\n", acl_token_name1(token), + (const char*) token->ctx); + } + + printf("-----------------------------------\n"); + + acl_token_tree_destroy(tree); +} + +int main(void) +{ + test(); +#if 0 + acl_token_tree_test(); +#endif + + test2(); +#ifdef ACL_MS_WINDOWS + printf("enter any key to exit ...\n"); + + getchar(); +#endif + return (0); +} diff --git a/samples/token_tree/token_tree.vcproj b/samples/token_tree/token_tree.vcproj new file mode 100644 index 000000000..c924babf8 --- /dev/null +++ b/samples/token_tree/token_tree.vcproj @@ -0,0 +1,234 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/token_tree/token_tree.vcxproj b/samples/token_tree/token_tree.vcxproj new file mode 100644 index 000000000..6e0143da4 --- /dev/null +++ b/samples/token_tree/token_tree.vcxproj @@ -0,0 +1,181 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + ReleaseDll + Win32 + + + Release + Win32 + + + + {B44E3C63-C3A5-4306-A6FF-072818D62EEF} + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)token_tree.exe + true + $(OutDir)token_tree.pdb + Console + MachineX86 + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)token_tree.exe + true + Console + true + true + MachineX86 + + + + + Disabled + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_DLL;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + EditAndContinue + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)token_tree.exe + true + $(OutDir)token_tree.pdb + Console + MachineX86 + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_DLL;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)token_tree.exe + true + Console + true + true + MachineX86 + + + + + {b40213c2-507c-4c7f-a6e1-b850c9bdc27b} + false + + + + + + + + + \ No newline at end of file diff --git a/samples/trace/Makefile b/samples/trace/Makefile new file mode 100644 index 000000000..df4917488 --- /dev/null +++ b/samples/trace/Makefile @@ -0,0 +1,3 @@ +include ../Makefile.in +EXTLIBS = -ldl +PROG = trace diff --git a/samples/trace/main.c b/samples/trace/main.c new file mode 100644 index 000000000..b0e65712f --- /dev/null +++ b/samples/trace/main.c @@ -0,0 +1,47 @@ +#include "lib_acl.h" +#include +#include +#include +#include "sigsegv.h" + +static void stack3(void) +{ + const char *file = "trace.txt"; + void *buf[10]; + size_t n, i; + char **s; + char *m = NULL; + + acl_dump_trace(file); + + n = backtrace(buf, 10); + s = backtrace_symbols(buf, n); + + for (i = 0; i < n; i++) + printf(">>%s\n", s[i]); + + free(s); + strcpy(m, "hello"); +} + +static void stack2(void) +{ + stack3(); +} + +static void stack1(void) +{ + stack2(); +} + +static void trace(void) +{ + stack1(); +} + +int main(void) +{ + setup_sigsegv(); + trace(); + return (0); +} diff --git a/samples/trace/sigsegv.c b/samples/trace/sigsegv.c new file mode 100644 index 000000000..5d8807b0d --- /dev/null +++ b/samples/trace/sigsegv.c @@ -0,0 +1,128 @@ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#ifndef _XOPEN_SOURCE +#define _XOPEN_SOURCE +#endif + +#define NO_CPP_DEMANGLE + +#include +#include +#include +#include +#include +#include +#include +#ifndef NO_CPP_DEMANGLE +#include +#endif +#include "sigsegv.h" + +#if defined(REG_RIP) +# define SIGSEGV_STACK_IA64 +# define REGFORMAT "%016lx" +#elif defined(REG_EIP) +# define SIGSEGV_STACK_X86 +# define REGFORMAT "%08x" +#else +# define SIGSEGV_STACK_GENERIC +# define REGFORMAT "%x" +#endif + +static void signal_segv(int signum, siginfo_t* info, void*ptr) +{ + static const char *si_codes[3] = {"", "SEGV_MAPERR", "SEGV_ACCERR"}; + + size_t i; + ucontext_t *ucontext = (ucontext_t*)ptr; + +#if defined(SIGSEGV_STACK_X86) || defined(SIGSEGV_STACK_IA64) + int f = 0; + Dl_info di; + void **bp = 0; + void *ip = 0; +#else + void *bt[20]; + char **strings; + size_t sz; +#endif + + fprintf(stderr, "Segmentation Fault!\n"); + fprintf(stderr, "info.si_signo = %d\n", signum); + fprintf(stderr, "info.si_errno = %d\n", info->si_errno); + fprintf(stderr, "info.si_code = %d (%s)\n", info->si_code, + si_codes[info->si_code]); + fprintf(stderr, "info.si_addr = %p\n", info->si_addr); + for(i = 0; i < NGREG; i++) + fprintf(stderr, "reg[%02d] = 0x" REGFORMAT "\n", + (int) i, ucontext->uc_mcontext.gregs[i]); + +#if defined(SIGSEGV_STACK_X86) || defined(SIGSEGV_STACK_IA64) +# if defined(SIGSEGV_STACK_IA64) + ip = (void*)ucontext->uc_mcontext.gregs[REG_RIP]; + bp = (void**)ucontext->uc_mcontext.gregs[REG_RBP]; +# elif defined(SIGSEGV_STACK_X86) + ip = (void*)ucontext->uc_mcontext.gregs[REG_EIP]; + bp = (void**)ucontext->uc_mcontext.gregs[REG_EBP]; +# endif + + fprintf(stderr, "Stack trace:\n"); + while(bp && ip) { + const char *symname; + if(!dladdr(ip, &di)) + break; + + symname = di.dli_sname; +#ifndef NO_CPP_DEMANGLE + int status; + char *tmp = __cxa_demangle(symname, NULL, 0, &status); + + if(status == 0 && tmp) + symname = tmp; +#endif + + fprintf(stderr, "%2d: %p <%s+%u> (%s)\n", + ++f, + ip, + symname, + (unsigned)(((char*) ip) - ((char*) di.dli_saddr)), + di.dli_fname); + +#ifndef NO_CPP_DEMANGLE + if(tmp) + free(tmp); +#endif + + if(di.dli_sname && !strcmp(di.dli_sname, "main")) + break; + + ip = bp[1]; + bp = (void**)bp[0]; + } +#else + fprintf(stderr, "Stack trace (non-dedicated):\n"); + sz = backtrace(bt, 20); + strings = backtrace_symbols(bt, sz); + + for(i = 0; i < sz; ++i) + fprintf(stderr, "%s\n", strings[i]); +#endif + fprintf(stderr, "End of stack trace\n"); + exit (-1); +} + +int setup_sigsegv() +{ + struct sigaction action; + memset(&action, 0, sizeof(action)); + action.sa_sigaction = signal_segv; + action.sa_flags = SA_SIGINFO; + if(sigaction(SIGSEGV, &action, NULL) < 0) { + perror("sigaction"); + return 0; + } + + return 1; +} diff --git a/samples/trace/sigsegv.h b/samples/trace/sigsegv.h new file mode 100644 index 000000000..f4ac61d2e --- /dev/null +++ b/samples/trace/sigsegv.h @@ -0,0 +1,14 @@ +#ifndef __ACL_SIGSEGV_INCLUDE_H__ +#define __ACL_SIGSEGV_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +int setup_sigsegv(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/samples/unix/Makefile b/samples/unix/Makefile new file mode 100644 index 000000000..9e29c6722 --- /dev/null +++ b/samples/unix/Makefile @@ -0,0 +1,2 @@ +include ../Makefile_cpp.in +PROG = unix diff --git a/samples/unix/main.cpp b/samples/unix/main.cpp new file mode 100644 index 000000000..a08db0f30 --- /dev/null +++ b/samples/unix/main.cpp @@ -0,0 +1,34 @@ +#include "lib_acl.h" +#include +#include +#include +#include +#include +#include + +int main(void) +{ + struct rlimit rlim, rlim_new; + char buf[256]; + + acl_chroot_uid(NULL, "zsx"); + + printf("curr: %s\r\n", getcwd(buf, sizeof(buf))); + + if (getrlimit(RLIMIT_CORE, &rlim)==0) { + rlim_new.rlim_cur = rlim_new.rlim_max = RLIM_INFINITY; + if (setrlimit(RLIMIT_CORE, &rlim_new) != 0) { + /* failed. try raising just to the old max */ + rlim_new.rlim_cur = rlim_new.rlim_max = + rlim.rlim_max; + if (setrlimit(RLIMIT_CORE, &rlim_new) != 0) + printf("set core limit error: %s\n", acl_last_serror()); + else + printf("set core limit ok\n"); + } + else + printf("2 set core limit ok\n"); + } + assert(0); + return (0); +} diff --git a/samples/urlcode/main.cpp b/samples/urlcode/main.cpp new file mode 100644 index 000000000..0c55f1afd --- /dev/null +++ b/samples/urlcode/main.cpp @@ -0,0 +1,47 @@ + +#pragma comment(lib,"ws2_32") + +#include "lib_acl.h" +#include + +static void test_urlcode(void) +{ + const char *params = "name=中国&value=人民&name2=姓名&value2=逍遥仙"; + char *tmp1, *tmp2; + + printf("params: (%s), len=%d\r\n", params, strlen(params)); + tmp1 = acl_url_encode(params); + assert(tmp1); + printf("encode: (%s), len=%d\r\n", tmp1, strlen(tmp1)); + tmp2 = acl_url_decode(tmp1); + assert(tmp2); + printf("decode: (%s), len=%d\r\n", tmp2, strlen(tmp2)); + + acl_myfree(tmp1); + acl_myfree(tmp2); +} + +int main(int argc, char *argv[]) +{ + test_urlcode(); + printf(">>\\r: %d, \\n: %d\r\n", (int) '\r', (int) '\n'); + + const char* s = "hello world! "; + ACL_VSTRING* buf = acl_vstring_alloc(100), + * buf2 = acl_vstring_alloc(100); + acl_html_decode(s, buf); + printf("{%s}\r\n", acl_vstring_str(buf)); + + ACL_VSTRING_RESET(buf); + acl_xml_decode(s, buf); + printf("{%s}\r\n", acl_vstring_str(buf)); + + acl_html_encode(acl_vstring_str(buf), buf2); + printf("encode: %s\r\n", acl_vstring_str(buf2)); + + acl_vstring_free(buf); + acl_vstring_free(buf2); + + getchar(); + return (0); +} diff --git a/samples/urlcode/urlcode.vcxproj b/samples/urlcode/urlcode.vcxproj new file mode 100644 index 000000000..faa9086cb --- /dev/null +++ b/samples/urlcode/urlcode.vcxproj @@ -0,0 +1,178 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + ReleaseDll + Win32 + + + Release + Win32 + + + + urlcode + {7CD8C407-12E9-4DBA-B281-A1FC0E1D70C4} + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + $(OutDir)urlcode.exe + true + $(OutDir)urlcode.pdb + Console + MachineX86 + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + $(OutDir)urlcode.exe + true + Console + true + true + MachineX86 + + + + + Disabled + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_DLL;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + EditAndContinue + + + $(OutDir)urlcode.exe + true + $(OutDir)urlcode.pdb + Console + MachineX86 + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_DLL;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + $(OutDir)urlcode.exe + true + Console + true + true + MachineX86 + + + + + + + + {b40213c2-507c-4c7f-a6e1-b850c9bdc27b} + false + + + + + + \ No newline at end of file diff --git a/samples/urlcode/urlcode.vcxproj.filters b/samples/urlcode/urlcode.vcxproj.filters new file mode 100644 index 000000000..f84bd00e6 --- /dev/null +++ b/samples/urlcode/urlcode.vcxproj.filters @@ -0,0 +1,22 @@ +锘 + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx + + + + + 婧愭枃浠 + + + \ No newline at end of file diff --git a/samples/urlcode/urlcode_vc2003.vcproj b/samples/urlcode/urlcode_vc2003.vcproj new file mode 100644 index 000000000..9d312e4f6 --- /dev/null +++ b/samples/urlcode/urlcode_vc2003.vcproj @@ -0,0 +1,230 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/urlcode/urlcode_vc2008.vcproj b/samples/urlcode/urlcode_vc2008.vcproj new file mode 100644 index 000000000..25f8d4586 --- /dev/null +++ b/samples/urlcode/urlcode_vc2008.vcproj @@ -0,0 +1,201 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/vstream/Makefile b/samples/vstream/Makefile new file mode 100644 index 000000000..80229a6f7 --- /dev/null +++ b/samples/vstream/Makefile @@ -0,0 +1,2 @@ +include ../Makefile_cpp.in +PROG = vstream diff --git a/samples/vstream/main.cpp b/samples/vstream/main.cpp new file mode 100644 index 000000000..8eacc1d1c --- /dev/null +++ b/samples/vstream/main.cpp @@ -0,0 +1,211 @@ +#include "lib_acl.h" +#include +#ifdef ACL_UNIX +#include +#endif + +static void end(void) +{ +#ifdef ACL_MS_WINDOWS + acl_vstream_fprintf(ACL_VSTREAM_OUT, "enter any key to quit\r\n"); + getchar(); +#endif +} + +static char addr[256] = "127.0.0.1:8285"; +static int timeout = 0; + +static void reply_client2(ACL_VSTREAM *client) +{ + char buf[1024]; + int ret; + + while (1) { + ret = acl_vstream_gets(client, buf, sizeof(buf) - 1); + if (ret == ACL_VSTREAM_EOF) + break; + buf[ret] = 0; + acl_vstream_printf("get one line:%s", buf); + if (acl_vstream_writen(client, buf, ret) == ACL_VSTREAM_EOF) + break; + } +} + +static void reply_client(ACL_VSTREAM *client) +{ +#define COUNT 10 +#define SIZE 8192000 + const char *myname = "reply_client"; + struct iovec vector[COUNT]; + int i, dlen = 0, n; + + for (i = 0; i < COUNT; i++) { + vector[i].iov_base = acl_mycalloc(1, SIZE); + assert(vector[i].iov_base); + vector[i].iov_len = SIZE; + dlen += SIZE; + } + + printf("%s: before write\n", myname); + n = acl_vstream_writevn(client, vector, COUNT); + + for (i = 0; i < COUNT; i++) { + acl_myfree(vector[i].iov_base); + } + + printf("%s: writen n = %d, dlen = %d\r\n", myname, n, dlen); +} + +static int vstream_server(void) +{ + const char *myname = "vstream_server"; + ACL_VSTREAM *sstream, *client; + char ebuf[256]; + + sstream = acl_vstream_listen(addr, 128); + if (sstream == NULL) { + printf("%s(%d): listen on %s error(%s)\r\n", + myname, __LINE__, addr, + acl_last_strerror(ebuf, sizeof(ebuf))); + return (-1); + } + + acl_tcp_defer_accept(ACL_VSTREAM_SOCK(sstream), 0); + printf("%s: listen %s ok\r\n", myname, addr); + while (1) { + client = acl_vstream_accept(sstream, NULL, 0); + if (client == NULL) { + printf("%s(%d): accept error(%s)\r\n", + myname, __LINE__, + acl_last_strerror(ebuf, sizeof(ebuf))); + return (-1); + } + printf("accept one\r\n"); + if (1) + reply_client2(client); + else + reply_client(client); + acl_vstream_close(client); + } + + return (0); +} + +static int vstream_client(void) +{ + const char *myname = "vstream_client"; + ACL_VSTREAM *client; + char ebuf[256], buf[4096]; + int n, dlen = 0; + + printf("addr: %s, timeout: %d\n", addr, timeout); + client = acl_vstream_connect(addr, ACL_NON_BLOCKING, timeout, timeout, 1024); + if (client == NULL) { + printf("%s(%d): connect addr %s error(%s)\n", + myname, __LINE__, addr, acl_last_strerror(ebuf, sizeof(ebuf))); + return (-1); + } + + printf("%s: connect %s ok\r\n", myname, addr); + acl_non_blocking(ACL_VSTREAM_SOCK(client), ACL_BLOCKING); + + n = acl_write_wait(ACL_VSTREAM_SOCK(client), 10); + if (n < 0) { + printf("connect timeout: %s\n", acl_last_serror()); + goto END; + } + acl_vstream_fprintf(client, "hello world\n"); + while (1) { + n = acl_vstream_read(client, buf, sizeof(buf)); + if (n == ACL_VSTREAM_EOF) { + printf("read over: %s\n", acl_last_serror()); + break; + } + dlen += n; + buf[n] = 0; + printf("read reply: %s\n", buf); + } + +END: + acl_vstream_close(client); + printf("%s: read %d\n", myname, dlen); + return (0); +} + +static void usage(const char *procname) +{ + printf("usage: %s -h [help] -a [addr] -s [server_mode] -c [client_mode] -t [timeout]\r\n", procname); +} + +#ifdef WIN32 +#define snprintf _snprintf +#endif + +int main(int argc acl_unused, char *argv[] acl_unused) +{ + char buf[256]; + int i, c; + ACL_VSTRING *sbuf; + int flag = 0; + + acl_init(); + +#if 0 + return (vstream_server()); +#endif + + for (i = 1; i < argc; i++) { + if (argv[i][0] != '-') + continue; + switch (argv[i][1]) { + case 's': + flag = 1; + break; + case 'c': + flag = 2; + break; + case 'a': + snprintf(addr, sizeof(addr), "%s", argv[i + 1]); + break; + case 't': + timeout = atoi(argv[i + 1]); + break; + case 'h': + usage(argv[0]); + exit (0); + default: + break; + } + } + + if (flag == 1) + return (vstream_server()); + if (flag == 2) + return (vstream_client()); + + sbuf = acl_vstring_alloc(256); + while (1) { + acl_vstream_fprintf(ACL_VSTREAM_OUT, "please input(quit on exit): "); + acl_vstream_gets_nonl(ACL_VSTREAM_IN, buf, sizeof(buf)); + acl_vstream_fprintf(ACL_VSTREAM_ERR, "your input: %s\r\n", buf); + if (strcasecmp(buf, "quit") == 0 || strcasecmp(buf, "exit") == 0) + break; + + acl_vstream_printf("please input: "); + c = acl_vstring_gets_nonl_bound(sbuf, ACL_VSTREAM_IN, 10); + if (c == ACL_VSTREAM_EOF) + break; + acl_vstream_printf("your input(len=%d): %s\r\n", + ACL_VSTRING_LEN(sbuf), acl_vstring_str(sbuf)); + if (c == '\n') + continue; + if (acl_vstring_gets_nonl(sbuf, ACL_VSTREAM_IN) == '\n') + acl_vstream_printf("the rest of your input(len=%d): %s\r\n", + ACL_VSTRING_LEN(sbuf), acl_vstring_str(sbuf)); + else + break; + } + acl_vstring_free(sbuf); + end(); + return (0); +} diff --git a/samples/vstream/valgrind.sh b/samples/vstream/valgrind.sh new file mode 100644 index 000000000..08491bc7f --- /dev/null +++ b/samples/vstream/valgrind.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +valgrind --tool=memcheck --leak-check=yes -v ./vstream diff --git a/samples/vstream/vstream.vcxproj b/samples/vstream/vstream.vcxproj new file mode 100644 index 000000000..215c91aa6 --- /dev/null +++ b/samples/vstream/vstream.vcxproj @@ -0,0 +1,188 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + ReleaseDll + Win32 + + + Release + Win32 + + + + vstream + {F0DAE963-53F7-4836-813D-7825BE6F8BDF} + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)vstream.exe + %(AdditionalLibraryDirectories) + true + $(OutDir)vstream.pdb + Console + MachineX86 + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + wsock32.lib;%(AdditionalDependencies) + $(OutDir)vstream.exe + %(AdditionalLibraryDirectories) + %(DelayLoadDLLs) + true + Console + true + true + MachineX86 + + + + + Disabled + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + EditAndContinue + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)vstream.exe + %(AdditionalLibraryDirectories) + true + $(OutDir)vstream.pdb + Console + MachineX86 + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + wsock32.lib;%(AdditionalDependencies) + $(OutDir)vstream.exe + %(AdditionalLibraryDirectories) + %(DelayLoadDLLs) + true + Console + true + true + MachineX86 + + + + + {b40213c2-507c-4c7f-a6e1-b850c9bdc27b} + false + + + + + + + + + \ No newline at end of file diff --git a/samples/vstream/vstream_vc2003.vcproj b/samples/vstream/vstream_vc2003.vcproj new file mode 100644 index 000000000..7d77507e4 --- /dev/null +++ b/samples/vstream/vstream_vc2003.vcproj @@ -0,0 +1,240 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/vstream_fseek/Makefile b/samples/vstream_fseek/Makefile new file mode 100644 index 000000000..969d8ca6f --- /dev/null +++ b/samples/vstream_fseek/Makefile @@ -0,0 +1,2 @@ +include ../Makefile_cpp.in +PROG = vstream_fseek diff --git a/samples/vstream_fseek/main.cpp b/samples/vstream_fseek/main.cpp new file mode 100644 index 000000000..edb49d33a --- /dev/null +++ b/samples/vstream_fseek/main.cpp @@ -0,0 +1,172 @@ +// vstream_fseek.cpp : 定义控制台应用程序的入口点。 +// + +#include "lib_acl.h" +#include + +int main(int argc acl_unused, char *argv[] acl_unused) +{ + ACL_VSTREAM *fp; + char buf[4096]; + int i, n; + acl_off_t off; + struct acl_stat sbuf; + + fp = acl_vstream_fopen("test.txt", O_RDWR | O_CREAT, 0600, 4096); + assert(fp); + + if (acl_fstat(ACL_VSTREAM_FILE(fp), &sbuf) < 0) + printf("fstat file error\r\n"); + else + printf("fstat file's size=%d\r\n", (int) sbuf.st_size); + + memset(buf, 'X', sizeof(buf)); + + for (i = 0; i < 10; i++) { + acl_vstream_writen(fp, buf, sizeof(buf)); + printf("after write %d, offset=%d, sys_offset=%d\r\n", + (int) sizeof(buf), (int) fp->offset, (int) fp->sys_offset); + } + + n = acl_vstream_read(fp, buf, sizeof(buf) - 1); + if (n == ACL_VSTREAM_EOF) + printf("ok(%d): read ACL_VSTREAM_EOF, offset=%d, sys_offset=%d\r\n", + __LINE__, (int) fp->offset, (int) fp->sys_offset); + else { + printf("error(%d): read n=%d\r\n", __LINE__, n); + goto END; + } + + off = acl_vstream_fseek(fp, 0, SEEK_SET); + if (off == -1) { + printf("error(%d): fseek error\r\n", __LINE__); + goto END; + } + printf("ok(%d): after seek 0, offset=%d, sys_offset=%d\r\n", + __LINE__, (int) fp->offset, (int) fp->sys_offset); + + n = acl_vstream_read(fp, buf, sizeof(buf)); + if (n == ACL_VSTREAM_EOF) { + printf("error(%d): readr\r\n", __LINE__); + goto END; + } + printf("ok(%d): after read %d, offset=%d, sys_offset=%d\r\n", + __LINE__, (int) sizeof(buf), (int) fp->offset, (int) fp->sys_offset); + + off = acl_vstream_fseek(fp, 100, SEEK_SET); + if (off != 100) { + printf("error(%d): off(%d) != 100\r\n", __LINE__, (int) off); + goto END; + } else + printf("ok(%d): after seek 100, offset=%d, sys_offset=%d\r\n", + __LINE__, (int) fp->offset, (int) fp->sys_offset); + + off = acl_vstream_fseek(fp, 4096, SEEK_SET); + if (off != 4096) { + printf("error(%d): off(%d) != 4096\r\n", __LINE__, (int) off); + goto END; + } else + printf("ok(%d): after seek 4096, offset=%d, sys_offset=%d\r\n", + __LINE__, (int) fp->offset, (int) fp->sys_offset); + + off = acl_vstream_fseek(fp, 5096, SEEK_SET); + if (off != 5096) { + printf("error(%d): off(%d) != 5096\r\n", __LINE__, (int) off); + goto END; + } else + printf("ok(%d): after seek 5096, offset=%d, sys_offset=%d\r\n", + __LINE__, (int) fp->offset, (int) fp->sys_offset); + + off = acl_vstream_fseek(fp, 8191, SEEK_SET); + if (off != 8191) { + printf("error(%d): off(%d) != 8191\r\n", __LINE__, (int) off); + goto END; + } else + printf("ok(%d): after seek 8191, offset=%d, sys_offset=%d\r\n", + __LINE__, (int) fp->offset, (int) fp->sys_offset); + + off = acl_vstream_fseek(fp, 8192, SEEK_SET); + if (off != 8192) { + printf("error(%d): off(%d) != 8192\r\n", __LINE__, (int) off); + goto END; + } else + printf("ok(%d): after seek 8192, offset=%d, sys_offset=%d\r\n", + __LINE__, (int) fp->offset, (int) fp->sys_offset); + + off = acl_vstream_fseek(fp, 8193, SEEK_SET); + if (off != 8193) { + printf("error(%d): off(%d) != 8193\r\n", __LINE__, (int) off); + goto END; + } else + printf("ok(%d): after seek 8193, offset=%d, sys_offset=%d\r\n", + __LINE__, (int) fp->offset, (int) fp->sys_offset); + + // 系列读 + printf("%d>>>begin check: offset=%d, sys_offset=%d\r\n", + __LINE__, (int) fp->offset, (int) fp->sys_offset); + off = acl_vstream_fseek(fp, 100, SEEK_SET); + if (off != 100) { + printf("error(%d): off(%d) != 100\r\n", __LINE__, (int) off); + goto END; + } else + printf("ok(%d): after seek 100, offset=%d, sys_offset=%d\r\n", + __LINE__, (int) fp->offset, (int) fp->sys_offset); + acl_vstream_read(fp, buf, 100); + printf("ok(%d): after read 100, offset=%d, sys_offset=%d\r\n", + __LINE__, (int) fp->offset, (int) fp->sys_offset); + + off = acl_vstream_fseek(fp, 100, SEEK_SET); + if (off != 100) { + printf("error(%d): off(%d) != 100\r\n", __LINE__, (int) off); + goto END; + } else + printf("ok(%d): after seek 100, offset=%d, sys_offset=%d\r\n", + __LINE__, (int) fp->offset, (int) fp->sys_offset); + + off = acl_vstream_fseek(fp, 200, SEEK_SET); + if (off != 200) { + printf("error(%d): off(%d) != 200\r\n", __LINE__, (int) off); + goto END; + } else + printf("ok(%d): after seek 200, offset=%d, sys_offset=%d\r\n", + __LINE__, (int) fp->offset, (int) fp->sys_offset); + acl_vstream_read(fp, buf, 100); + printf("ok(%d): after read 100, offset=%d, sys_offset=%d\r\n", + __LINE__, (int) fp->offset, (int) fp->sys_offset); + + off = acl_vstream_fseek(fp, 300, SEEK_SET); + if (off != 300) { + printf("error(%d): off(%d) != 300\r\n", __LINE__, (int) off); + goto END; + } else + printf("ok(%d): after seek 300, offset=%d, sys_offset=%d\r\n", + __LINE__, (int) fp->offset, (int) fp->sys_offset); + acl_vstream_read(fp, buf, 10); + printf("ok(%d): after read 10, offset=%d, sys_offset=%d\r\n", + __LINE__, (int) fp->offset, (int) fp->sys_offset); + + acl_vstream_writen(fp, "hello", strlen("hello")); + printf("ok(%d): after write 'hello', offset=%d, sys_offset=%d\r\n", + __LINE__, (int) fp->offset, (int) fp->sys_offset); + acl_vstream_writen(fp, "world", strlen("world")); + printf("ok(%d): after write 'world', offset=%d, sys_offset=%d\r\n", + __LINE__, (int) fp->offset, (int) fp->sys_offset); + + off = acl_vstream_fseek(fp, 8190, SEEK_SET); + if (off != 8190) { + printf("error(%d): off(%d) != 8190\r\n", __LINE__, (int) off); + goto END; + } else + printf("ok(%d): after seek 8190, offset=%d, sys_offset=%d\r\n", + __LINE__, (int) fp->offset, (int) fp->sys_offset); + n = acl_vstream_read(fp, buf, 100); + printf("ok(%d): after read 100, n=%d offset=%d, sys_offset=%d\r\n", + __LINE__, n, (int) fp->offset, (int) fp->sys_offset); + +END: + acl_vstream_close(fp); + getchar(); + + return 0; +} + diff --git a/samples/vstream_fseek/test.txt b/samples/vstream_fseek/test.txt new file mode 100644 index 000000000..2feb5bbb4 --- /dev/null +++ b/samples/vstream_fseek/test.txt @@ -0,0 +1 @@ +XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXhelloworldXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX \ No newline at end of file diff --git a/samples/vstream_fseek2/Makefile b/samples/vstream_fseek2/Makefile new file mode 100644 index 000000000..969d8ca6f --- /dev/null +++ b/samples/vstream_fseek2/Makefile @@ -0,0 +1,2 @@ +include ../Makefile_cpp.in +PROG = vstream_fseek diff --git a/samples/vstream_fseek2/main.cpp b/samples/vstream_fseek2/main.cpp new file mode 100644 index 000000000..9454cf79d --- /dev/null +++ b/samples/vstream_fseek2/main.cpp @@ -0,0 +1,238 @@ + +#include +#include +#include +#include + +#include "lib_acl.h" + +static void test_fseek3(int buflen) +{ + ACL_VSTREAM *fp; + ACL_VSTRING *why = acl_vstring_alloc(100); + char filename[] ="./tmp.txt"; + char buf[10]; + int n; + int offset, off2; + int ch; + + fp = acl_safe_open(filename, O_CREAT | O_RDWR, 0600, + (struct stat *) 0, (uid_t)-1, + (uid_t )-1, why); + if (fp == 0) + acl_msg_fatal("%s(%d)->%s: can't open %s, serr = %s", + __FUNCTION__, __LINE__, __FILE__, + filename, acl_vstring_str(why)); + + fp->read_buf_len = buflen; + + ch = acl_vstream_getc(fp); + printf("after read(1) >>> ch = %c, read_cnt = %d, offset=%d, %d\n", + ch, (int) fp->read_cnt, (int) fp->offset, (int) fp->sys_offset); + offset = acl_vstream_fseek(fp, 0, SEEK_CUR); + printf("after fseek(0) >>> ch = %c, read_cnt = %d, off = %d, offset=%d, %d\n\n", + ch, (int) fp->read_cnt, offset, (int) fp->offset, (int) fp->sys_offset); + + ch = acl_vstream_getc(fp); + printf("after read(1) >>> ch = %c, read_cnt = %d, offset=%d, %d\n", + ch, (int) fp->read_cnt, (int) fp->offset, (int) fp->sys_offset); + offset = acl_vstream_fseek(fp, 0, SEEK_CUR); + printf("after fseek(0) >>> ch = %c, read_cnt = %d, off = %d, %s, offset=%d, %d\n\n", + ch, (int) fp->read_cnt, offset, strerror(errno), (int) fp->offset, (int) fp->sys_offset); + + offset = acl_vstream_fseek(fp, 10, SEEK_CUR); + off2 = lseek(ACL_VSTREAM_FILE(fp), 0, SEEK_CUR); + printf("after fseek(10) >>> off=%d, lseek = %d, read_cnt = %d, offset=%d, %d\n\n", + offset, off2, (int) fp->read_cnt, (int) fp->offset, (int) fp->sys_offset); + + n = acl_vstream_gets_nonl(fp, buf, sizeof(buf) - 1); + printf("after read(getline) >>> buf = [%s], fp->read_cnt = %d, offset=%d, %d\n", + buf, (int) fp->read_cnt, (int) fp->offset, (int) fp->sys_offset); + offset = acl_vstream_fseek(fp, 0, SEEK_CUR); + printf("after fseek(0) >>> buf = [%s], read_cnt = %d, off = %d, offset=%d, %d\n\n", + buf, (int) fp->read_cnt, offset, (int) fp->offset, (int) fp->sys_offset); + + ch = acl_vstream_getc(fp); + printf("after read(1) >>> ch = %c, read_cnt = %d, offset=%d, %d\n", + ch, (int) fp->read_cnt, (int) fp->offset, (int) fp->sys_offset); + offset = acl_vstream_fseek(fp, 0, SEEK_CUR); + printf("after fseek(0) >>> ch = %c, read_cnt = %d, off = %d, offset=%d, %d\n\n", + ch, (int)fp->read_cnt, offset, (int) fp->offset, (int) fp->sys_offset); + + n = acl_vstream_readn(fp, buf, 2); + buf[n] = 0; + printf("after read(buf) >>> buf = [%s], fp->read_cnt = %d, off=%d, offset=%d, %d\n", + buf, (int) fp->read_cnt, offset, (int) fp->offset, (int) fp->sys_offset); + offset = acl_vstream_fseek(fp, 10, SEEK_CUR); + printf("after fseek(10) >>> read_cnt = %d, off = %d, offset=%d, %d\n\n", + (int) fp->read_cnt, offset, (int) fp->offset, (int) fp->sys_offset); + + ch = acl_vstream_getc(fp); + printf("after read(1) >>> ch = %c, read_cnt = %d, offset=%d, %d\n", + ch, (int) fp->read_cnt, (int) fp->offset, (int) fp->sys_offset); + offset = acl_vstream_fseek(fp, 0, SEEK_CUR); + printf("after fseek(0) >>> ch = %c, read_cnt = %d, off = %d, %s, offset=%d, %d\n\n", + ch, (int) fp->read_cnt, offset, strerror(errno), (int) fp->offset, (int) fp->sys_offset); + + acl_vstring_free(why); + acl_vstream_close(fp); +} + +static void test_fseek2(int buflen) +{ + ACL_VSTREAM *fp; + ACL_VSTRING *why = acl_vstring_alloc(100); + char filename[] ="./tmp.txt"; + char buf[10]; + int n; + int offset, off2; + int ch; + + fp = acl_safe_open(filename, O_CREAT | O_RDWR, 0600, + (struct stat *) 0, (uid_t)-1, + (uid_t )-1, why); + if (fp == 0) + acl_msg_fatal("%s(%d)->%s: can't open %s, serr = %s", + __FILE__, __LINE__, __FUNCTION__, filename, acl_vstring_str(why)); + + fp->read_buf_len = buflen; + + ch = acl_vstream_getc(fp); + printf("after read(1)(%d) >>> ch = %c, read_cnt = %d, offset=%d, %d\n", + __LINE__, ch, (int) fp->read_cnt, (int) fp->offset, (int) fp->sys_offset); + offset = acl_vstream_fseek2(fp, 0, SEEK_CUR); + printf("after fseek(0)(%d) >>> ch = %c, read_cnt = %d, off = %d, offset=%d, %d\n\n", + __LINE__, ch, (int)fp->read_cnt, offset, (int) fp->offset, (int) fp->sys_offset); + + ch = acl_vstream_getc(fp); + printf("after read(1)(%d) >>> ch = %c, read_cnt = %d, offset=%d, %d\n", + __LINE__, ch, (int) fp->read_cnt, (int) fp->offset, (int) fp->sys_offset); + offset = acl_vstream_fseek2(fp, 0, SEEK_CUR); + printf("after fseek(0)(%d) >>> ch = %c, read_cnt = %d, off = %d, %s, offset=%d, %d\n\n", + __LINE__, ch, (int)fp->read_cnt, offset, strerror(errno), (int) fp->offset, (int) fp->sys_offset); + + offset = acl_vstream_fseek2(fp, 10, SEEK_CUR); + off2 = lseek(ACL_VSTREAM_FILE(fp), 0, SEEK_CUR); + printf("after fseek(10)(%d) >>> off=%d, lseek = %d, read_cnt = %d, offset=%d, %d\n\n", + __LINE__, offset, off2, (int)fp->read_cnt, (int) fp->offset, (int) fp->sys_offset); + + n = acl_vstream_gets_nonl(fp, buf, sizeof(buf) - 1); + printf("after read(getline)(%d) >>> buf = [%s], fp->read_cnt = %d, offset=%d, %d\n", + __LINE__, buf, (int)fp->read_cnt, (int) fp->offset, (int) fp->sys_offset); + offset = acl_vstream_fseek2(fp, 0, SEEK_CUR); + printf("after fseek(0)(%d) >>> buf = [%s], read_cnt = %d, off = %d, offset=%d, %d\n\n", + __LINE__, buf, (int) fp->read_cnt, offset, (int) fp->offset, (int) fp->sys_offset); + + ch = acl_vstream_getc(fp); + printf("after read(1)(%d) >>> ch = %c, read_cnt = %d, offset=%d, %d\n", + __LINE__, ch, (int)fp->read_cnt, (int) fp->offset, (int) fp->sys_offset); + offset = acl_vstream_fseek2(fp, 0, SEEK_CUR); + printf("after fseek(0)(%d) >>> ch = %c, read_cnt = %d, off = %d, offset=%d, %d\n\n", + __LINE__, ch, (int) fp->read_cnt, offset, (int) fp->offset, (int) fp->sys_offset); + + n = acl_vstream_readn(fp, buf, 2); + buf[n] = 0; + printf("after read(buf)(%d) >>> buf = [%s], fp->read_cnt = %d, offset=%d, offset=%d, %d\n", + __LINE__, buf, (int) fp->read_cnt, offset, (int) fp->offset, (int) fp->sys_offset); + offset = acl_vstream_fseek2(fp, 10, SEEK_CUR); + printf("after fseek(10)(%d) >>> read_cnt = %d, off = %d, offset=%d, %d\n\n", + __LINE__, (int) fp->read_cnt, offset, (int) fp->offset, (int) fp->sys_offset); + + ch = acl_vstream_getc(fp); + printf("after read(1)(%d) >>> ch = %c, read_cnt = %d, offset=%d, %d\n", + __LINE__, ch, (int)fp->read_cnt, (int) fp->offset, (int) fp->sys_offset); + offset = acl_vstream_fseek2(fp, 0, SEEK_CUR); + printf("after fseek(0)(%d) >>> ch = %c, read_cnt = %d, off = %d, %s, offset=%d, %d\n\n", + __LINE__, ch, (int) fp->read_cnt, offset, strerror(errno), (int) fp->offset, (int) fp->sys_offset); + + acl_vstring_free(why); + acl_vstream_close(fp); +} + +static void test_fseek(int buflen) +{ + ACL_VSTREAM *fp; + ACL_VSTRING *why = acl_vstring_alloc(100); + char filename[] ="./tmp.txt"; + char buf[10]; + int n; + int offset, off2; + int ch; + + fp = acl_safe_open(filename, O_CREAT | O_RDWR, 0600, + (struct stat *) 0, (uid_t)-1, + (uid_t )-1, why); + if (fp == 0) + acl_msg_fatal("%s(%d)->%s: can't open %s, serr = %s", + __FILE__, __LINE__, __FUNCTION__, filename, acl_vstring_str(why)); + + fp->read_buf_len = buflen; + + ch = acl_vstream_getc(fp); + printf("after read(1)(%d) >>> ch = %c, read_cnt = %d, offset=%d, %d\n", + __LINE__, ch, (int) fp->read_cnt, (int) fp->offset, (int) fp->sys_offset); + offset = acl_vstream_fseek(fp, 0, SEEK_CUR); + printf("after fseek(0)(%d) >>> ch = %c, read_cnt = %d, off = %d, offset=%d, %d\n\n", + __LINE__, ch, (int) fp->read_cnt, offset, (int) fp->offset, (int) fp->sys_offset); + + ch = acl_vstream_getc(fp); + printf("after read(1)(%d) >>> ch = %c, read_cnt = %d, offset=%d, %d\n", + __LINE__, ch, (int) fp->read_cnt, (int) fp->offset, (int) fp->sys_offset); + offset = acl_vstream_fseek(fp, 0, SEEK_CUR); + printf("after fseek(0)(%d) >>> ch = %c, read_cnt = %d, off = %d, %s, offset=%d, %d\n\n", + __LINE__, ch, (int) fp->read_cnt, offset, strerror(errno), (int) fp->offset, (int) fp->sys_offset); + + offset = acl_vstream_fseek(fp, 10, SEEK_CUR); + off2 = lseek(ACL_VSTREAM_FILE(fp), 0, SEEK_CUR); + printf("after fseek(10)(%d) >>> off=%d, %d, lseek = %d, read_cnt = %d, offset=%d, %d\n\n", + __LINE__, offset, (int) fp->sys_offset, off2, (int) fp->read_cnt, (int) fp->offset, (int) fp->sys_offset); + + n = acl_vstream_gets(fp, buf, sizeof(buf) - 1); + printf("after read(getline)(%d) >>> buf = [%s], n = %d, fp->read_cnt = %d, offset=%d, %d, lseek=%d\n", + __LINE__, buf, n, (int) fp->read_cnt, (int) fp->offset, (int)fp->sys_offset, + (int) lseek(ACL_VSTREAM_FILE(fp), 0, SEEK_CUR)); + offset = acl_vstream_fseek(fp, 0, SEEK_CUR); + printf("after fseek(0)(%d) >>> buf = [%s], read_cnt = %d, off = %d, %d, offset=%d, %d\n\n", + __LINE__, buf, (int) fp->read_cnt, offset, (int) lseek(ACL_VSTREAM_FILE(fp), 0, SEEK_CUR), + (int) fp->offset, (int) fp->sys_offset); + + ch = acl_vstream_getc(fp); + printf("after read(1)(%d) >>> ch = %c, read_cnt = %d, offset=%d, %d\n", + __LINE__, ch, (int) fp->read_cnt, (int) fp->offset, (int) fp->sys_offset); + offset = acl_vstream_fseek(fp, 0, SEEK_CUR); + printf("after fseek(0)(%d) >>> ch = %c, read_cnt = %d, off = %d, %d, offset=%d, %d\n\n", + __LINE__, ch, (int) fp->read_cnt, offset, (int) lseek(ACL_VSTREAM_FILE(fp), 0, SEEK_CUR), + (int) fp->offset, (int) fp->sys_offset); + + n = acl_vstream_readn(fp, buf, 2); + buf[n] = 0; + printf("after read(buf)(%d) >>> buf = [%s], fp->read_cnt = %d, offset=%d, %d\n", + __LINE__, buf, (int) fp->read_cnt, (int) fp->offset, (int) fp->sys_offset); + offset = acl_vstream_fseek(fp, 10, SEEK_CUR); + printf("after fseek(10)(%d) >>> read_cnt = %d, off = %d, offset=%d, %d\n\n", + __LINE__, (int) fp->read_cnt, offset, (int) fp->offset, (int) fp->sys_offset); + + ch = acl_vstream_getc(fp); + printf("after read(1)(%d) >>> ch = %c, read_cnt = %d, offset=%d, %d\n", + __LINE__, ch, (int) fp->read_cnt, (int) fp->offset, (int) fp->sys_offset); + offset = acl_vstream_fseek(fp, 0, SEEK_CUR); + printf("after fseek(0)(%d) >>> ch = %c, read_cnt = %d, off = %d, %s, offset=%d, %d\n\n", + __LINE__, ch, (int) fp->read_cnt, offset, strerror(errno), (int) fp->offset, (int) fp->sys_offset); + + acl_vstring_free(why); + acl_vstream_close(fp); +} + +int main(int argc, char *argv[]) +{ + argc = argc; + argv = argv; + + test_fseek(4); + printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); + test_fseek2(4); + printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); + test_fseek3(4); + + exit (0); +} diff --git a/samples/vstream_fseek2/tmp.txt b/samples/vstream_fseek2/tmp.txt new file mode 100644 index 000000000..0a8a169d5 --- /dev/null +++ b/samples/vstream_fseek2/tmp.txt @@ -0,0 +1,28 @@ +123456 +78 +910 +abcdefghijklmn +opqrst +uvwxyz + + +910 +abcdefghijklmn +opqrst +uvwxyz +910 +abcdefghijklmn +opqrst +uvwxyz +910 +abcdefghijklmn +opqrst +uvwxyz +910 +abcdefghijklmn +opqrst +uvwxyz +910 +abcdefghijklmn +opqrst +uvwxyz diff --git a/samples/vstream_fseek2/tmp.txt.1 b/samples/vstream_fseek2/tmp.txt.1 new file mode 100644 index 000000000..a2f403198 --- /dev/null +++ b/samples/vstream_fseek2/tmp.txt.1 @@ -0,0 +1,6 @@ +123456 +78 +910 +abcdefghijklmn +opqrst +uvwxyz diff --git a/samples/vstream_popen/Makefile b/samples/vstream_popen/Makefile new file mode 100644 index 000000000..22e78edee --- /dev/null +++ b/samples/vstream_popen/Makefile @@ -0,0 +1,2 @@ +include ../Makefile_cpp.in +PROG = vstream_popen diff --git a/samples/vstream_popen/main.cpp b/samples/vstream_popen/main.cpp new file mode 100644 index 000000000..a3c9ed692 --- /dev/null +++ b/samples/vstream_popen/main.cpp @@ -0,0 +1,186 @@ +#include "lib_acl.h" +#include +#include + +#ifdef ACL_MS_WINDOWS +#include +#define getpid _getpid +#else +#include +#endif + +static void child(int argc acl_unused, char *argv[] acl_unused) +{ + const char *myname = "child"; + const char *env_list; + ACL_VSTRING *vbuf = acl_vstring_alloc(256); + char buf[1024]; + const char *ptr; + int ret, i; + + acl_init(); + + env_list = acl_getenv_list(); + acl_vstring_sprintf(vbuf, "env_list(%s)", env_list); + + acl_vstring_strcat(vbuf, "), "); + ptr = acl_getenv("name1"); + if (ptr == NULL) + ptr = "null"; + acl_vstring_sprintf_append(vbuf, "name1=%s", ptr); + + ptr = acl_getenv("name2"); + if (ptr == NULL) + ptr = "null"; + acl_vstring_sprintf_append(vbuf, ", name2=%s", ptr); + + ptr = acl_getenv("name3"); + if (ptr == NULL) + ptr = "null"; + acl_vstring_sprintf_append(vbuf, ", name3=%s", ptr); + + printf("%s: %s\r\n", myname, acl_vstring_str(vbuf)); + fflush(stdout); + + i = 0; + while (1) { + ret = acl_vstream_gets_nonl(ACL_VSTREAM_IN, buf, sizeof(buf)); + if (ret == ACL_VSTREAM_EOF) { + printf("%s(%d): gets from parent error(%s)\r\n", + myname, getpid(), acl_last_serror()); + fflush(stdout); + break; + } + ret = acl_vstream_fprintf(ACL_VSTREAM_OUT, "%s(%d): child ok\r\n", + myname, getpid()); + if (ret == ACL_VSTREAM_EOF) { + printf("%s(%d): fprintf to parent error(%s)\r\n", + myname, getpid(), acl_last_serror()); + fflush(stdout); + break; + } + if (i++ >= 5) + break; + } + + printf("%s(%d): child over\r\n", myname, getpid()); + fflush(stdout); + acl_end(); +} + +static void pipe_fd_status(ACL_FILE_HANDLE fd) +{ +#ifdef ACL_MS_WINDOWS + const char *myname = "pipe_fd_status"; + char buf[256]; + DWORD status, nInstances = 0, nMaxInstances = 0, nTimeout = 0; + + GetNamedPipeHandleState(fd, &status, + &nInstances, NULL, NULL, buf, sizeof(buf)); + printf("%s: status: %d, %d, %d, nInstances: %d, nMaxInstances: %d, nTimeout: %d, buf: %s\r\n", + myname, status, PIPE_WAIT, PIPE_NOWAIT, nInstances, nMaxInstances, nTimeout, buf); +#else + (void) fd; +#endif +} + +static void pipe_status(ACL_VSTREAM *stream) +{ + pipe_fd_status(ACL_VSTREAM_FILE(stream)); +} + +static void parent(int argc acl_unused, char *argv[]) +{ + const char *myname = "parent"; + char *command; + ACL_ARGV *env = acl_argv_split("name1&value1&name2&变量值2&name3&变量值4", "&"); + ACL_VSTREAM *stream; + ACL_ARGV *args = acl_argv_alloc(1); + char buf[1024]; + int ret, i; + + acl_init(); + printf("%s: pid = %d\r\n", myname, getpid()); + command = argv[0]; + acl_argv_add(args, command, "-c", NULL); + + stream = acl_vstream_popen(O_RDWR, + ACL_VSTREAM_POPEN_ARGV, args->argv, + ACL_VSTREAM_POPEN_ENV, env->argv, + ACL_VSTREAM_POPEN_END); + if (stream == NULL) { + acl_msg_error("%s(%d): popen %s error(%s)", + myname, __LINE__, command, acl_last_serror()); + goto error_end; + } + + pipe_status(stream); + + printf("%s: open pipe ok\r\n", myname); + + i = 0; + while (1) { + pipe_status(stream); + ret =acl_vstream_fprintf(stream, ">>from server<<\r\n"); + if (ret == ACL_VSTREAM_EOF) { + printf("%s: fprintf to child error(%s)\r\n", + myname, acl_last_serror()); + break; + } else + printf("%s: fprintf to child ok\r\n", myname); + + printf("%s: begin wait client msg\n", myname); + ret = acl_vstream_gets_nonl(stream, buf, sizeof(buf)); + if (ret == ACL_VSTREAM_EOF) { + printf("%s: gets from child error(%s)\r\n", + myname, acl_last_serror()); + break; + } + buf[ret] = 0; + printf("%s: gets from child ok(%s), i=%d\r\n", myname, buf, i++); + } + + acl_vstream_pclose(stream); + +error_end: + + acl_argv_free(env); + acl_argv_free(args); + acl_end(); +} + +static void usage(const char *procname) +{ + printf("(%d) usage: %s -h [help] -c [run as child] -p [run as parent]\r\n", + getpid(), procname); +#ifdef ACL_MS_WINDOWS + printf("enter any key to exit...\r\n"); + getchar(); +#endif +} + + +int main(int argc, char *argv[]) +{ + char ch; + + while((ch = getopt(argc, argv, "hpc")) > 0) { + switch (ch) { + case 'h': + usage(argv[0]); + return (0); + case 'c': + child(argc, argv); + break; + case 'p': + parent(argc, argv); + break; + default: + usage(argv[0]); + return (0); + } + } + + printf("pid(%d), exit now\n", getpid()); + return (0); +} diff --git a/samples/vstream_popen/vstream_popen.vcproj b/samples/vstream_popen/vstream_popen.vcproj new file mode 100644 index 000000000..f6416e790 --- /dev/null +++ b/samples/vstream_popen/vstream_popen.vcproj @@ -0,0 +1,234 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/vstream_popen/vstream_popen.vcxproj b/samples/vstream_popen/vstream_popen.vcxproj new file mode 100644 index 000000000..b4f674d85 --- /dev/null +++ b/samples/vstream_popen/vstream_popen.vcxproj @@ -0,0 +1,181 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + ReleaseDll + Win32 + + + Release + Win32 + + + + {3C9E5E69-3082-4C0E-AAEC-BCFC9407AA17} + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + false + $(Configuration)\ + $(Configuration)\ + true + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)vstream_popen.exe + true + $(OutDir)vstream_popen.pdb + Console + MachineX86 + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)vstream_popen.exe + true + Console + true + true + MachineX86 + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_DLL;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)vstream_popen.exe + true + Console + true + true + MachineX86 + + + + + Disabled + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_DLL;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + EditAndContinue + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)vstream_popen.exe + true + $(OutDir)vstream_popen.pdb + Console + MachineX86 + + + + + {b40213c2-507c-4c7f-a6e1-b850c9bdc27b} + false + + + + + + + + + \ No newline at end of file diff --git a/samples/vstream_popen2/Makefile b/samples/vstream_popen2/Makefile new file mode 100644 index 000000000..b17578dcf --- /dev/null +++ b/samples/vstream_popen2/Makefile @@ -0,0 +1,101 @@ +SHELL = /bin/sh +CC = gcc +#CC = g++ +AR = ar +ARFL = rv +RANLIB = ranlib + +CFLAGS = -c -g -W -Wcast-qual -Wcast-align \ +-Waggregate-return -Wmissing-prototypes \ +-Wpointer-arith -Werror -Wshadow -O2 \ +-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO \ +-Wno-long-long \ +-pedantic -Wall +########################################################### +#Check system: +# Linux, SunOS, Solaris, BSD variants, AIX, HP-UX +SYSLIB = +CHECKSYSRES = @echo "Unknow system type!";exit 1 +UNIXNAME = $(shell uname -sm) + +ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes +endif + +# For FreeBSD +ifeq ($(findstring FreeBSD, $(UNIXNAME)), FreeBSD) + CFLAGS += -DFREEBSD -D_REENTRANT -pedantic + SYSLIB = -lcrypt -lpthread +endif + +# For Darwin +ifeq ($(findstring Darwin, $(UNIXNAME)), Darwin) + CFLAGS += -D_REENTRANT -pedantic -DMACOSX + SYSLIB = -lpthread +endif + +#Path for Linux +ifeq ($(findstring Linux, $(UNIXNAME)), Linux) + CFLAGS += -DLINUX2 + SYSLIB = -lcrypt -lpthread +endif + +#Path for SunOS +ifeq ($(findstring SunOS, $(UNIXNAME)), SunOS) + ifeq ($(findstring 86, $(UNIXNAME)), 86) + SYSLIB = -lsocket -lnsl -lrt + endif + ifeq ($(findstring sun4u, $(UNIXNAME)), sun4u) + SYSLIB = -lsocket -lnsl -lrt + endif + CFLAGS += -DSUNOS5 +endif + +#Path for HP-UX +ifeq ($(findstring HP-UX, $(UNIXNAME)), HP-UX) + SYSLIB = -lpthread + CFLAGS += -DHP_UX -DHPUX11 + PLAT_NAME=hp-ux +endif + +#Find system type. +ifneq ($(SYSPATH),) + CHECKSYSRES = @echo "System is $(shell uname -sm)" +endif +########################################################### + +LIB_BASE_PATH = ../../lib_acl +LIB_NAME_PATH = -L$(LIB_BASE_PATH)/lib +LIB_INCL_PATH = $(LIB_BASE_PATH)/include + +ALL_LIBS = -l_acl $(SYSLIB) + +BASE_PATH = . +INCLUDEDIR = $(BASE_PATH) +INCLUDE = -I$(INCLUDEDIR) -I$(LIB_INCL_PATH) +CFLAGS += $(INCLUDE) + +COMPILE = $(CC) $(CFLAGS) +########################################################### + +PROG_PARENT = parent +PROG_CHILD = child + +.PHONY = all clean + +all: $(PROG_PARENT) $(PROG_CHILD) + +$(PROG_PARENT): parent.o + $(CC) -o $(PROG_PARENT) parent.o $(LIB_NAME_PATH) $(ALL_LIBS) +$(PROG_CHILD): child.o + $(CC) -o $(PROG_CHILD) child.o $(LIB_NAME_PATH) $(ALL_LIBS) + +parent.o: parent.c + $(COMPILE) -o parent.o parent.c +child.o: child.c + $(COMPILE) -o child.o child.c +clean: + rm -f $(PROG_PARENT) $(PROG_CHILD) + rm -f *.o + +rebuild: clean all diff --git a/samples/vstream_popen2/child.c b/samples/vstream_popen2/child.c new file mode 100644 index 000000000..e514a0c7d --- /dev/null +++ b/samples/vstream_popen2/child.c @@ -0,0 +1,26 @@ +#include "lib_acl.h" + +int main(int argc acl_unused, char *argv[] acl_unused) +{ + char buf[1024]; + int ret, i = 0; + + ACL_SAFE_STRNCPY(buf, "first line from child", sizeof(buf)); + while (1) { + ret = acl_vstream_fprintf(ACL_VSTREAM_OUT, + ">>>send to parent from child(%d)(%s)\n", i, buf); + if (ret == ACL_VSTREAM_EOF) { + printf("(child): write error(%s)\n", acl_last_serror()); + break; + } + ret = acl_vstream_gets_nonl(ACL_VSTREAM_IN, buf, sizeof(buf)); + if (ret == ACL_VSTREAM_EOF) { + printf("(child): read over(%s)\n", acl_last_serror()); + break; + } + if (i++ > 10) + break; + } + + return (0); +} diff --git a/samples/vstream_popen2/parent.c b/samples/vstream_popen2/parent.c new file mode 100644 index 000000000..dba747ff4 --- /dev/null +++ b/samples/vstream_popen2/parent.c @@ -0,0 +1,44 @@ +#include "lib_acl.h" + +static void usage(const char *procname) +{ + printf("usage: %s child_progname\n", procname); +} + +int main(int argc, char *argv[]) +{ + ACL_VSTREAM *fp; + char *command, buf[1024]; + int ret, i = 0; + + if (argc != 2) { + usage(argv[0]); + return (0); + } + + command = argv[1]; + + fp = acl_vstream_popen(O_RDWR, + ACL_VSTREAM_POPEN_COMMAND, command, + ACL_VSTREAM_POPEN_END); + + while (1) { + ret = acl_vstream_gets_nonl(fp, buf, sizeof(buf)); + if (ret == ACL_VSTREAM_EOF) { + printf("(parent): read over(%s)\n", acl_last_serror()); + break; + } + printf("(parent): read from child(%s)\n", buf); + ret = acl_vstream_fprintf(fp, "from parent ok\n"); + if (ret == ACL_VSTREAM_EOF) { + printf("(parent): write error(%s)\n", acl_last_serror()); + break; + } + if (i++ > 10) + break; + } + + printf("(parent): over now\n"); + acl_vstream_pclose(fp); + return (0); +} diff --git a/samples/vstream_popen3/Makefile b/samples/vstream_popen3/Makefile new file mode 100644 index 000000000..b17578dcf --- /dev/null +++ b/samples/vstream_popen3/Makefile @@ -0,0 +1,101 @@ +SHELL = /bin/sh +CC = gcc +#CC = g++ +AR = ar +ARFL = rv +RANLIB = ranlib + +CFLAGS = -c -g -W -Wcast-qual -Wcast-align \ +-Waggregate-return -Wmissing-prototypes \ +-Wpointer-arith -Werror -Wshadow -O2 \ +-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO \ +-Wno-long-long \ +-pedantic -Wall +########################################################### +#Check system: +# Linux, SunOS, Solaris, BSD variants, AIX, HP-UX +SYSLIB = +CHECKSYSRES = @echo "Unknow system type!";exit 1 +UNIXNAME = $(shell uname -sm) + +ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes +endif + +# For FreeBSD +ifeq ($(findstring FreeBSD, $(UNIXNAME)), FreeBSD) + CFLAGS += -DFREEBSD -D_REENTRANT -pedantic + SYSLIB = -lcrypt -lpthread +endif + +# For Darwin +ifeq ($(findstring Darwin, $(UNIXNAME)), Darwin) + CFLAGS += -D_REENTRANT -pedantic -DMACOSX + SYSLIB = -lpthread +endif + +#Path for Linux +ifeq ($(findstring Linux, $(UNIXNAME)), Linux) + CFLAGS += -DLINUX2 + SYSLIB = -lcrypt -lpthread +endif + +#Path for SunOS +ifeq ($(findstring SunOS, $(UNIXNAME)), SunOS) + ifeq ($(findstring 86, $(UNIXNAME)), 86) + SYSLIB = -lsocket -lnsl -lrt + endif + ifeq ($(findstring sun4u, $(UNIXNAME)), sun4u) + SYSLIB = -lsocket -lnsl -lrt + endif + CFLAGS += -DSUNOS5 +endif + +#Path for HP-UX +ifeq ($(findstring HP-UX, $(UNIXNAME)), HP-UX) + SYSLIB = -lpthread + CFLAGS += -DHP_UX -DHPUX11 + PLAT_NAME=hp-ux +endif + +#Find system type. +ifneq ($(SYSPATH),) + CHECKSYSRES = @echo "System is $(shell uname -sm)" +endif +########################################################### + +LIB_BASE_PATH = ../../lib_acl +LIB_NAME_PATH = -L$(LIB_BASE_PATH)/lib +LIB_INCL_PATH = $(LIB_BASE_PATH)/include + +ALL_LIBS = -l_acl $(SYSLIB) + +BASE_PATH = . +INCLUDEDIR = $(BASE_PATH) +INCLUDE = -I$(INCLUDEDIR) -I$(LIB_INCL_PATH) +CFLAGS += $(INCLUDE) + +COMPILE = $(CC) $(CFLAGS) +########################################################### + +PROG_PARENT = parent +PROG_CHILD = child + +.PHONY = all clean + +all: $(PROG_PARENT) $(PROG_CHILD) + +$(PROG_PARENT): parent.o + $(CC) -o $(PROG_PARENT) parent.o $(LIB_NAME_PATH) $(ALL_LIBS) +$(PROG_CHILD): child.o + $(CC) -o $(PROG_CHILD) child.o $(LIB_NAME_PATH) $(ALL_LIBS) + +parent.o: parent.c + $(COMPILE) -o parent.o parent.c +child.o: child.c + $(COMPILE) -o child.o child.c +clean: + rm -f $(PROG_PARENT) $(PROG_CHILD) + rm -f *.o + +rebuild: clean all diff --git a/samples/vstream_popen3/child.c b/samples/vstream_popen3/child.c new file mode 100644 index 000000000..ce1e56c7f --- /dev/null +++ b/samples/vstream_popen3/child.c @@ -0,0 +1,24 @@ +#include "lib_acl.h" +#include + +static void on_sigterm(int signo) +{ + acl_msg_info("get signal sigterm: %d, %d", signo, SIGTERM); +} + +static void on_sigkill(int signo) +{ + acl_msg_info("get signal sigkill: %d, %d", signo, SIGKILL); +} + +int main(int argc acl_unused, char *argv[] acl_unused) +{ + acl_msg_open("./child.log", "child"); + signal(SIGTERM, on_sigterm); + signal(SIGKILL, on_sigkill); + + while (1) + pause(); + + return (0); +} diff --git a/samples/vstream_popen3/parent.c b/samples/vstream_popen3/parent.c new file mode 100644 index 000000000..89fbefa3f --- /dev/null +++ b/samples/vstream_popen3/parent.c @@ -0,0 +1,54 @@ +#include "lib_acl.h" +#include + +static void usage(const char *procname) +{ + printf("usage: %s child_progname\n", procname); +} + +int main(int argc, char *argv[]) +{ + ACL_VSTREAM *fp; + char *command, buf[1024]; + int ret, i = 0; + + if (argc != 2) { + usage(argv[0]); + return (0); + } + + command = argv[1]; + + fp = acl_vstream_popen(O_RDWR, + ACL_VSTREAM_POPEN_COMMAND, command, + ACL_VSTREAM_POPEN_END); + + ACL_VSTREAM_SET_RWTIMO(fp, 1); + + while (1) { + ret = acl_vstream_gets_nonl(fp, buf, sizeof(buf)); + if (ret == ACL_VSTREAM_EOF) { + printf("(parent): read over(%s), errno: %d, ACL_ETIMEDOUT: %d\n", + acl_last_serror(), errno, ACL_ETIMEDOUT); + break; + } + printf("(parent): read from child(%s)\n", buf); + ret = acl_vstream_fprintf(fp, "from parent ok\n"); + if (ret == ACL_VSTREAM_EOF) { + printf("(parent): write error(%s)\n", acl_last_serror()); + break; + } + if (i++ > 10) + break; + } + + printf("(parent): over now\n"); + if (errno == ACL_ETIMEDOUT) +#if 1 + kill(fp->pid, SIGKILL); +#else + kill(fp->pid, SIGTERM); +#endif + acl_vstream_pclose(fp); + return (0); +} diff --git a/samples/vstream_unread/Makefile b/samples/vstream_unread/Makefile new file mode 100644 index 000000000..85c664009 --- /dev/null +++ b/samples/vstream_unread/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = vstream_unread diff --git a/samples/vstream_unread/main.c b/samples/vstream_unread/main.c new file mode 100644 index 000000000..1bc1e9a1f --- /dev/null +++ b/samples/vstream_unread/main.c @@ -0,0 +1,52 @@ +#include "lib_acl.h" +#include + +static void test1(void) +{ + char buf[256]; + + snprintf(buf, sizeof(buf), "hello world!"); + memmove(buf + 1, buf, strlen(buf) + 1); + printf("buf:(%s)\n", buf); +} + +int main(void) +{ + ACL_VSTREAM *fp = acl_vstream_fdopen(0, O_RDWR, 4096, 0, ACL_VSTREAM_TYPE_SOCK); + char buf[256]; + const char *data2 = "hello", *data1 = "world"; + int ret; + + test1(); + + (void) acl_vstream_unread(fp, data1, strlen(data1)); + acl_vstream_ungetc(fp, ' '); + (void) acl_vstream_unread(fp, data2, strlen(data2)); + ret = acl_vstream_read(fp, buf, sizeof(buf)); + assert(ret > 0); + buf[ret] = 0; + printf("buf: %s, len: %d, %d\n", buf, ret, (int) strlen(buf)); + + (void) acl_vstream_unread(fp, data1, strlen(data1)); + ret = acl_vstream_read(fp, buf, 2); + assert(ret > 0); + buf[ret] = 0; + printf("buf: %s, len: %d\n", buf, ret); + + (void) acl_vstream_unread(fp, data2, strlen(data2)); + ret = acl_vstream_read(fp, buf, sizeof(buf)); + assert(ret > 0); + buf[ret] = 0; + printf("buf: %s, len: %d\n", buf, ret); + + acl_vstream_ungetc(fp, '>'); + acl_vstream_ungetc(fp, '^'); + acl_vstream_ungetc(fp, '<'); + ret = acl_vstream_read(fp, buf, sizeof(buf)); + assert(ret > 0); + buf[ret] = 0; + printf("buf: %s, len: %d\n", buf, ret); + + acl_vstream_fclose(fp); + return (0); +} diff --git a/samples/vstring/Makefile b/samples/vstring/Makefile new file mode 100644 index 000000000..69531be7e --- /dev/null +++ b/samples/vstring/Makefile @@ -0,0 +1,2 @@ +include ../Makefile_cpp.in +PROG = vstring diff --git a/samples/vstring/main.cpp b/samples/vstring/main.cpp new file mode 100644 index 000000000..fecde6e01 --- /dev/null +++ b/samples/vstring/main.cpp @@ -0,0 +1,272 @@ +#include "lib_acl.h" + +static void end(void) +{ +#ifdef ACL_MS_WINDOWS + getchar(); +#endif +} + +#define STR acl_vstring_str +#define LEN ACL_VSTRING_LEN + +static void string_find(ACL_VSTRING *vp, const char *needle) +{ + char *ptr; + + ptr = acl_vstring_strstr(vp, needle); + if (ptr) + printf(">>>acl_vstring_strstr: find %s from %s, ptr: %s\r\n", needle, STR(vp), ptr); + else + printf(">>>acl_vstring_strstr: not find %s from %s\r\n", needle, STR(vp)); +} + +static void string_case_find(ACL_VSTRING *vp, const char *needle) +{ + char *ptr; + + ptr = acl_vstring_strcasestr(vp, needle); + if (ptr) + printf(">>>acl_vstring_strcasestr: find %s from %s, ptr: %s\r\n", needle, STR(vp), ptr); + else + printf(">>>acl_vstring_strcasestr: not find %s from %s\r\n", needle, STR(vp)); +} + +static void string_rfind(ACL_VSTRING *vp, const char *needle) +{ + char *ptr; + + ptr = acl_vstring_rstrstr(vp, needle); + if (ptr) + printf(">>>acl_vstring_rstrstr: find %s from %s, ptr: %s\r\n", needle, STR(vp), ptr); + else + printf(">>>acl_vstring_rstrstr: not find %s from %s\r\n", needle, STR(vp)); +} + +static void string_case_rfind(ACL_VSTRING *vp, const char *needle) +{ + char *ptr; + + ptr = acl_vstring_rstrcasestr(vp, needle); + if (ptr) + printf(">>>acl_vstring_rstrcasestr: find %s from %s, ptr: %s\r\n", needle, STR(vp), ptr); + else + printf(">>>acl_vstring_rstrcasestr: not find %s from %s\r\n", needle, STR(vp)); +} + +static const char *needle_tab[] = { + "h", + "el", + "o", + "e", + "l", + "lo", + "he", + "He", + "hello", + "hel", + "Hel", + "helo", + NULL +}; + +static const char *string_tab[] = { + "test test\r\n", + "test test\n", + "test", + "test test", + "\r\n", + "test", + "test test", + "\n", + "test\r\ntesttest\r\ntest test", + "test test", + "test test", + "\r\n", +}; + +static void test_buffer_gets(void) +{ + ACL_VSTRING *buf = acl_vstring_alloc(256); + const ACL_VSTRING *pbuf; + const char *src; + size_t i, n; + unsigned char ch = (unsigned char) -1; + + for (i = 0; i < sizeof(string_tab) / sizeof(char*); i++) { + printf("%s", string_tab[i]); + } + + printf("------------------------------------------------------------\r\n"); + + for (i = 0; i < sizeof(string_tab) / sizeof(char*); i++) { + src = string_tab[i]; + n = strlen(src); + while (1) { + const char *psrc_saved = src; + pbuf = acl_buffer_gets_nonl(buf, &src, n); + if (pbuf) { + printf("%s\n", STR(pbuf)); + ACL_VSTRING_RESET(buf); + n -= src - psrc_saved; + if (n == 0) + break; + } else + break; + } + } + + printf("------------------------------------------------------------\r\n"); + + for (i = 0; i < sizeof(string_tab) / sizeof(char*); i++) { + src = string_tab[i]; + n = strlen(src); + while (1) { + const char *psrc_saved = src; + pbuf = acl_buffer_gets(buf, &src, n); + if (pbuf) { + printf("%s", STR(pbuf)); + ACL_VSTRING_RESET(buf); + n -= src - psrc_saved; + if (n == 0) + break; + } else + break; + } + } + + acl_vstring_free(buf); + printf(">>>>>>>>>max ch: %d\n", ch); +} + +static void test_buffer_space() +{ + ACL_VSTRING *vp = acl_vstring_alloc(1); + char *ptr; + int i; + + ACL_VSTRING_SPACE(vp, 10); + ptr = acl_vstring_str(vp); + printf("=========================1====================\n"); + for (i = 0; i < 10; i++) + *ptr++ = 'x'; + ptr = acl_vstring_str(vp); + printf("gets: %d\n", acl_vstream_gets(ACL_VSTREAM_IN, ptr, 10)); + printf("=========================2====================\n"); + acl_vstring_free(vp); +} + +static void test_vstring_vsprintf(const char* fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + ACL_VSTRING *vbf = acl_vstring_alloc(1); + acl_vstring_vsprintf(vbf, fmt, ap); + va_end(ap); + + printf("%s\n", acl_vstring_str(vbf)); + + acl_vstring_free(vbf); +} + +int main(int argc acl_unused, char *argv[] acl_unused) +{ + ACL_VSTRING *vp = acl_vstring_alloc(256); + char *ptr; + int i; + size_t z; + + acl_vstring_strcpy(vp, "大家好,中国人民,Hi大家好, Hello World! 中国人民银行!"); + + printf(">>>%s\r\n", acl_vstring_str(vp)); + ptr = acl_vstring_strstr(vp, "Hello"); + if (ptr) + printf(">>ok, find it, ptr = %s\r\n", ptr); + else + printf(">>error, no find it\r\n"); + + ptr = acl_vstring_strcasestr(vp, "WORLD"); + if (ptr) + printf(">>ok, find it, ptr = %s\r\n", ptr); + else + printf(">>error, no find it\r\n"); + + ptr = acl_vstring_strstr(vp, "中国"); + if (ptr) + printf(">>ok, find it, ptr = %s\r\n", ptr); + else + printf(">>error, no find it\r\n"); + + ptr = acl_vstring_strcasestr(vp, "Hi大家好"); + if (ptr) + printf(">>ok, find it, ptr = %s\r\n", ptr); + else + printf(">>error, no find it\r\n"); + + ptr = acl_vstring_memchr(vp, 'W'); + if (ptr) + printf(">>ok, find it, ptr = %s\r\n", ptr); + else + printf(">>error, no find it\r\n"); + + acl_vstring_strcpy(vp, "hello"); + ptr = acl_vstring_strstr(vp, "h"); + if (ptr) + printf(">>>find it, ptr: %s\r\n", ptr); + else + printf(">>>not find it\r\n"); + + printf("\r\n------------------------------------------------------------\r\n"); + for (i = 0; needle_tab[i]; i++) { + string_rfind(vp, needle_tab[i]); + } + + printf("\r\n------------------------------------------------------------\r\n"); + for (i = 0; needle_tab[i]; i++) { + string_case_rfind(vp, needle_tab[i]); + } + + printf("\r\n------------------------------------------------------------\r\n"); + for (i = 0; needle_tab[i]; i++) { + string_find(vp, needle_tab[i]); + } + + printf("\r\n------------------------------------------------------------\r\n"); + for (i = 0; needle_tab[i]; i++) { + string_case_find(vp, needle_tab[i]); + } + + printf("\r\n------------------------------------------------------------\r\n"); + const char *s1 = "hello world", *s2 = "WOrld", *s3 = "world"; + + printf("strrncasecmp: %s %s %s, n: %d\n", s1, + strrncasecmp(s1, s2, strlen(s2)) == 0 ? "==" : "!=", s2, (int) strlen(s2)); + printf("strrncasecmp: %s %s %s, n: %d\n", s1, + strrncasecmp(s1, s2, strlen(s2) + 1) == 0 ? "==" : "!=", s2, (int) strlen(s2) + 1); + + s1 = "www.hexun.com"; + s2 = ".hexun.com"; + printf("strrncasecmp: %s %s %s, n: %d\n", s1, + strrncasecmp(s1, s2, strlen(s2)) == 0 ? "==" : "!=", s2, (int) strlen(s2)); + + printf("\r\n------------------------------------------------------------\r\n"); + printf("strrncmp: %s %s %s, n: %d\n", s1, strrncmp(s1, s2, strlen(s2)) == 0 ? "==" : "!=", s2, (int) strlen(s2)); + printf("strrncmp: %s %s %s, n: 3\n", s1, strrncmp(s1, s2, 3) == 0 ? "==" : "!=", s2); + printf("strrncmp: %s %s %s, n: %d\n", s1, strrncmp(s1, s3, strlen(s3)) == 0 ? "==" : "!=", s3, (int) strlen(s3)); + printf("strrncmp: %s %s %s, n: %d\n", s1, strrncmp(s1, s3, strlen(s3) + 1) == 0 ? "==" : "!=", + s3, (int) strlen(s3) + 1); + + z = 1000; + acl_vstring_sprintf(vp, "max long long int: %llu, size_t: %d", (acl_uint64) -1, (int) z); + printf("%s\n", acl_vstring_str(vp)); + acl_vstring_free(vp); + + printf("\r\n------------------------------------------------------------\r\n"); + test_buffer_gets(); + test_buffer_space(); + + test_vstring_vsprintf("test: %s", s1); + end(); + return (0); +} diff --git a/samples/vstring/valgrind.sh b/samples/vstring/valgrind.sh new file mode 100644 index 000000000..13328d7f4 --- /dev/null +++ b/samples/vstring/valgrind.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +valgrind --tool=memcheck --leak-check=yes -v ./vstring diff --git a/samples/vstring/vstring.vcxproj b/samples/vstring/vstring.vcxproj new file mode 100644 index 000000000..ea19b0ad2 --- /dev/null +++ b/samples/vstring/vstring.vcxproj @@ -0,0 +1,186 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + ReleaseDll + Win32 + + + Release + Win32 + + + + vstring + {AC9CA58D-28FB-40B7-85C8-BA7674DBD934} + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + wsock32.lib;%(AdditionalDependencies) + $(OutDir)vstring.exe + %(AdditionalLibraryDirectories) + libcd;libcmt;%(IgnoreSpecificDefaultLibraries) + true + $(OutDir)vstring.pdb + Console + MachineX86 + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + wsock32.lib;%(AdditionalDependencies) + $(OutDir)vstring.exe + true + Console + true + true + MachineX86 + + + + + Disabled + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_DLL;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + EditAndContinue + + + wsock32.lib;%(AdditionalDependencies) + $(OutDir)vstring.exe + %(AdditionalLibraryDirectories) + libcd;libcmt;%(IgnoreSpecificDefaultLibraries) + true + $(OutDir)vstring.pdb + Console + MachineX86 + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_DLL;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + wsock32.lib;%(AdditionalDependencies) + $(OutDir)vstring.exe + true + Console + true + true + MachineX86 + + + + + {b40213c2-507c-4c7f-a6e1-b850c9bdc27b} + false + + + + + + + + + \ No newline at end of file diff --git a/samples/vstring/vstring_vc2003.vcproj b/samples/vstring/vstring_vc2003.vcproj new file mode 100644 index 000000000..b2e4e53e8 --- /dev/null +++ b/samples/vstring/vstring_vc2003.vcproj @@ -0,0 +1,238 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/vstring2/Makefile b/samples/vstring2/Makefile new file mode 100644 index 000000000..713fb5a3b --- /dev/null +++ b/samples/vstring2/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = vstring diff --git a/samples/vstring2/main.c b/samples/vstring2/main.c new file mode 100644 index 000000000..9c8ba36b7 --- /dev/null +++ b/samples/vstring2/main.c @@ -0,0 +1,24 @@ +#include "lib_acl.h" + +int main(void) +{ + ACL_VSTRING *buf = acl_vstring_alloc(100); + const char *s = "hello world\r\nhello world1\nhello world2\r\nhello world3"; + const char *p = s, *p1; + ssize_t n = (ssize_t) strlen(p); + + while (n > 0) { + ACL_VSTRING_RESET(buf); + p1 = p; + if (acl_buffer_gets_nonl(buf, &p, (size_t) n) == NULL + && ACL_VSTRING_LEN(buf) == 0) + { + break; + } + printf(">>%s\n", acl_vstring_str(buf)); + n -= p - p1; + } + + acl_vstring_free(buf); + return (0); +} diff --git a/samples/watchdog/Makefile b/samples/watchdog/Makefile new file mode 100644 index 000000000..75dbbf854 --- /dev/null +++ b/samples/watchdog/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = watchdog diff --git a/samples/watchdog/watchdog.c b/samples/watchdog/watchdog.c new file mode 100644 index 000000000..6b42b8894 --- /dev/null +++ b/samples/watchdog/watchdog.c @@ -0,0 +1,53 @@ + +/* Utility library. */ +#include +#include +#include +#include + +#include "lib_util.h" + +static void __watchdog_fn(ACL_WATCHDOG *wp, char *arg) +{ + char myname[] = "__watchdog_fn"; + char *buf; + + wp = wp; + buf = (char *) arg; + printf("%s: buf [%s]\n", myname, buf); + acl_watchdog_start(wp); +} + +int main(int unused_argc, char **unused_argv) +{ + char myname[] = "main"; + ACL_WATCHDOG *wp; + ACL_VSTREAM *vp; + char buf[256] = "test before"; + + unused_argc = unused_argc; + unused_argv = unused_argv; + + acl_msg_verbose = 2; + + printf("buf=%s\n", buf); + vp = acl_vstream_fdopen(0, 0, 0600, 4096, 0); + if (vp == NULL) + acl_msg_fatal("%s(%d)->%s: vstream_fdopen err %s", + __FILE__, __LINE__, myname, + strerror(errno)); + + wp = acl_watchdog_create(10, __watchdog_fn, (char *) buf); + acl_watchdog_start(wp); + + while (acl_vstream_gets_nonl(vp, buf, sizeof(buf) - 1) != ACL_VSTREAM_EOF) { + acl_msg_info(">>> your input:%s", buf); + if (strcasecmp(buf, "quit") == 0 || strcasecmp(buf, "exit") == 0) + break; + acl_watchdog_pat(); + } + + acl_watchdog_destroy(wp); + + exit (0); +} diff --git a/samples/winaio/ReadMe.txt b/samples/winaio/ReadMe.txt new file mode 100644 index 000000000..27b5d44d8 --- /dev/null +++ b/samples/winaio/ReadMe.txt @@ -0,0 +1,85 @@ +================================================================================ + MICROSOFT 基础类库: winaio 项目概述 +=============================================================================== + +应用程序向导已为您创建了此 winaio 应用程序。此应用程序 +不仅介绍了使用 Microsoft 基础类的基本知识, +而且是编写应用程序的起点。 + +此文件包含组成 winaio 应用程序的每个文件的内容摘要。 + +winaio.vcproj + 这是使用“应用程序向导”生成的 VC++ 项目的主项目文件。 + 它包含有关生成文件的 Visual C++ 版本的信息,以及 + 有关用“应用程序向导”所选择的平台、配置和 + 项目功能的信息。 + +winaio.h + 这是应用程序的主头文件。 它包含其他 + 项目特定的头文件(包括 Resource.h),并声明 + CwinaioApp 应用程序类。 + +winaio.cpp + 这是包含应用程序 + 类 CwinaioApp 的主应用程序源文件。 + +winaio.rc + 这是程序使用的所有 Microsoft Windows 资源 + 的列表。 它包含存储在 RES 子目录中 + 的图标、位图和光标。 可直接在 Microsoft + Visual C++ 中编辑此文件。 项目资源包含在 2052 中。 + +res\winaio.ico + 这是一个图标文件,用作应用程序的图标。 此 + 图标包含在主资源文件 winaio.rc 中。 + +res\winaio.rc2 + 此文件包含不由 Microsoft + Visual C++ 编辑的资源。 应将所有不能由 + 资源编辑器编辑的资源放在此文件中。 + +///////////////////////////////////////////////////////////////////////////// + +应用程序向导将创建一个对话框类: +winaioDlg.h、winaioDlg.cpp - 对话框 + 这些文件包含 CwinaioDlg 类。 此类定义 + 应用程序主对话框的行为。 此对话框的模板包含在 + winaio.rc 中,而此文件可以在 Microsoft Visual C++ 中进行编辑。 +///////////////////////////////////////////////////////////////////////////// + +其他功能: + +ActiveX 控件 + 应用程序支持使用 ActiveX 控件。 + +Windows 套接字 + 应用程序支持在 TCP/IP 网络上建立通讯。 +///////////////////////////////////////////////////////////////////////////// + +其他标准文件: + +StdAfx.h、StdAfx.cpp + 这些文件用于生成名为 winaio.pch 的预编译头文件 (PCH) + 和名为 StdAfx.obj 的预编译类型文件。 + +Resource.h + 这是标准头文件,它定义新资源 ID。 + Microsoft Visual C++ 将读取并更新此文件。 + +///////////////////////////////////////////////////////////////////////////// + +其他说明: + +应用程序向导使用“TODO:” 来指示 +应添加或自定义的源代码部分。 + +如果应用程序在共享 DLL 中使用 MFC,且应用程序使用的语言不是 +操作系统的当前语言,则需要从 Microsoft Visual C++ 光盘上 +Win\System 目录下将相应的本地化资源 MFC70XXX.DLL +复制到计算机的 system 或 system32 目录下, +并将其重命名为 MFCLOC.DLL。 (“XXX”代表 +语言缩写。 例如,MFC70DEU.DLL 包含翻译成 +德语的资源。) 如果不这样做,应用程序的某些 UI 元素 +将保留为操作系统的语言。 + +///////////////////////////////////////////////////////////////////////////// diff --git a/samples/winaio/aio_client.cpp b/samples/winaio/aio_client.cpp new file mode 100644 index 000000000..090a97f86 --- /dev/null +++ b/samples/winaio/aio_client.cpp @@ -0,0 +1,127 @@ +#include "StdAfx.h" +#include +#include "lib_acl.h" +#include "aio_client.h" + +typedef struct ECHO_COUNTER{ + int nloop; + int max_loop; + ACL_ASTREAM *stream; +} ECHO_COUNTER; + +static int __nread = 0; +static int __nwrite = 0; +static int __nconnect_ok = 0; +static int __nconn = 0; + +static char __data[1024]; +static int __dlen; +static int __nconn_per_sec = 100; + +static int __write_callback(ACL_ASTREAM *stream, void *context, + const char *data, int dlen); + +static int __timeout_callback(ACL_ASTREAM *stream acl_unused, + void *context acl_unused) +{ + printf("timeout, sockfd=%d\r\n", ACL_VSTREAM_SOCK(acl_aio_vstream(stream))); + return (-1); +} + +static int __close_callback(ACL_ASTREAM *stream, void *context) +{ + ECHO_COUNTER *counter = (ECHO_COUNTER *) context; + + printf("closed, sockfd=%d\r\n", ACL_VSTREAM_SOCK(acl_aio_vstream(stream))); + __nconn--; + acl_myfree(counter); + return (-1); +} + +static int __read_callback(ACL_ASTREAM *stream, void *context, + const char *data, int dlen acl_unused) +{ + ECHO_COUNTER *counter = (ECHO_COUNTER *) context; + + __nread++; + counter->nloop++; + + if (counter->nloop < 100) + printf(">>%s\r\n", data); + if (counter->nloop % 10000 == 0) + printf(">>> nloop=%d, max_loop=%d\r\n", + counter->nloop, counter->max_loop); + if (counter->nloop >= counter->max_loop) { + printf(">>> ok, nloop=%d, max_loop=%d\r\n", + counter->nloop, counter->max_loop); + return (-1); + } else + acl_aio_fprintf(stream, "%s\n", __data); + return (0); +} + +static int __write_callback(ACL_ASTREAM *stream, void *context acl_unused, + const char *data acl_unused, int dlen acl_unused) +{ + __nwrite++; + acl_aio_gets(stream); + return (0); +} + +static int __connect_callback(ACL_ASTREAM *client, void *context acl_unused) +{ + __nconnect_ok++; + printf(">>>>connect ok\n"); + acl_aio_fprintf(client, "%s\n", __data); + return (0); +} + +void aio_client_start(ACL_AIO *aio, const char *addr, int max_connect) +{ + const char *myname = "connect_pool"; + ECHO_COUNTER *counter; + int timeout = 10; + int i; + + for (i = 0; i < sizeof(__data) - 1; i++) { + __data[i] ='x'; + } + __data[i] = 0; + __dlen = (int) strlen(__data); + + for (i = 0; i < max_connect; i++) { + counter = (ECHO_COUNTER *) acl_mycalloc(1, sizeof(ECHO_COUNTER)); + counter->nloop = 0; + counter->max_loop = 100; + counter->stream = acl_aio_connect(aio, addr, timeout); + if (counter->stream == NULL) { + printf("%s(%d): acl_aio_connect(%s) error(%s)\r\n", + myname, __LINE__, addr, acl_last_serror()); + acl_myfree(counter); + continue; + } + + acl_aio_ctl(counter->stream, + ACL_AIO_CTL_WRITE_HOOK_ADD, __write_callback, counter, + ACL_AIO_CTL_READ_HOOK_ADD, __read_callback, counter, + ACL_AIO_CTL_TIMEO_HOOK_ADD, __timeout_callback, counter, + ACL_AIO_CTL_CLOSE_HOOK_ADD, __close_callback, counter, + ACL_AIO_CTL_CONNECT_HOOK_ADD, __connect_callback, counter, + ACL_AIO_CTL_TIMEOUT, timeout, + ACL_AIO_CTL_END); + __nconn++; + + if (__nconn_per_sec > 0 && i % __nconn_per_sec == 0) + printf("%s: connect->%d\r\n", myname, i); + } + + printf("prepare connect %d ok, __timeout=%d\r\n", __nconn, timeout); +} + +void aio_client_init(void) +{ + FILE *fp; + + AllocConsole(); + fp = freopen("CONOUT$","w+t",stdout); +} \ No newline at end of file diff --git a/samples/winaio/aio_client.h b/samples/winaio/aio_client.h new file mode 100644 index 000000000..4c64200ff --- /dev/null +++ b/samples/winaio/aio_client.h @@ -0,0 +1,5 @@ +#pragma once +#include "lib_acl.h" + +void aio_client_start(ACL_AIO *aio, const char *addr, int max_connect); +void aio_client_init(void); diff --git a/samples/winaio/aio_server.cpp b/samples/winaio/aio_server.cpp new file mode 100644 index 000000000..1488e940d --- /dev/null +++ b/samples/winaio/aio_server.cpp @@ -0,0 +1,186 @@ +#include "StdAfx.h" +#include "lib_acl.h" +#include +#include +#include +#include + +#include "aio_server.h" + +#define USE_GETS + +/* forward functions */ + +static char __data[1024]; +static int __dlen; +static int __echo_src; + +static int __gets_callback(ACL_ASTREAM *stream, void *context, + const char *data, int dlen); + +static void default_write_fn(void *arg acl_unused, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + acl_msg_info2(fmt, ap); + va_end(ap); +} + +static void default_fflush_fn(void *arg) +{ + arg = arg; +} + +static void (*__write_fn)(void *arg, const char *fmt, ...) = default_write_fn; +static void *__write_arg = NULL; +static void (*__fflush_fn)(void *arg) = default_fflush_fn; +static void *__fflush_arg = NULL; + +void aio_server_log_fn(void (*write_fn)(void *, const char *fmt, ...), + void *write_arg, + void (*fflush_fn)(void *), + void *fflush_arg) +{ + if (write_fn) { + __write_fn = write_fn; + __write_arg = write_arg; + } + + if (fflush_fn) { + __fflush_fn = fflush_fn; + __fflush_arg = fflush_arg; + } +} + +/*---------------------------------------------------------------------------*/ +static int __io_close(ACL_ASTREAM *astream, void *context acl_unused) +{ + const char *myname = "__io_close"; + ACL_VSTREAM *stream = acl_aio_vstream(astream); + + __write_fn(__write_arg, "%s, %s(%d): client(%d) exception!", + __FILE__, myname, __LINE__, ACL_VSTREAM_SOCK(stream)); + + return (-1); +} + +static int __io_timeout(ACL_ASTREAM *astream, void *context acl_unused) +{ + const char *myname = "__io_timeout"; + ACL_VSTREAM *stream = acl_aio_vstream(astream); + + __write_fn(__write_arg, "%s, %s(%d): client(%d) timeout!", + __FILE__, myname, __LINE__, ACL_VSTREAM_SOCK(stream)); + + return (-1); +} +static int __write_callback(ACL_ASTREAM *client, void *context acl_unused, + const char *data acl_unused, int dlen acl_unused) +{ +#ifdef USE_GETS + acl_aio_gets(client); +#else + acl_aio_read(client); +#endif + return (0); +} + +static int __gets_callback(ACL_ASTREAM *stream, void *context acl_unused, + const char *data, int dlen) +{ + if (__echo_src) + (void) acl_aio_writen(stream, data, dlen); + else + acl_aio_writen(stream, __data, __dlen); + + return (0); +} + +static int __accept_callback(ACL_ASTREAM *client, void *context acl_unused) +{ + acl_aio_ctl(client, ACL_AIO_CTL_READ_HOOK_ADD, __gets_callback, NULL, + ACL_AIO_CTL_WRITE_HOOK_ADD, __write_callback, NULL, + ACL_AIO_CTL_CLOSE_HOOK_ADD, __io_close, NULL, + ACL_AIO_CTL_TIMEO_HOOK_ADD, __io_timeout, NULL, + ACL_AIO_CTL_END); +#ifdef USE_GETS + acl_aio_gets(client); +#else + acl_aio_read(client); +#endif + + return (0); +} + +static void __listen_callback(ACL_ASTREAM *sstream, void *context) +{ + ACL_VSTREAM *cstream; + ACL_ASTREAM *client; + ACL_AIO *aio = (ACL_AIO *) context; + int i; + + for (i = 0; i < 10; i++) { + cstream = acl_vstream_accept(acl_aio_vstream(sstream), NULL, 0); + if (cstream == NULL) + break; + cstream->rw_timeout = 0; + acl_non_blocking(ACL_VSTREAM_SOCK(cstream), ACL_NON_BLOCKING); + client = acl_aio_open(aio, cstream); + acl_aio_ctl(client, + ACL_AIO_CTL_READ_HOOK_ADD, __gets_callback, NULL, + ACL_AIO_CTL_WRITE_HOOK_ADD, __write_callback, NULL, + ACL_AIO_CTL_CLOSE_HOOK_ADD, __io_close, NULL, + ACL_AIO_CTL_TIMEO_HOOK_ADD, __io_timeout, NULL, + ACL_AIO_CTL_END); +#ifdef USE_GETS + acl_aio_gets(client); +#else + acl_aio_read(client); +#endif + } +} + +static ACL_ASTREAM *__listener = NULL; + +void aiho_server_start(ACL_AIO *aio, const char *addr, int accept_auto, int echo_src) +{ + const char *myname = "echo_start"; + ACL_VSTREAM *sstream; + ACL_ASTREAM *astream; + + memset(__data, 'X', sizeof(__data)); + __data[sizeof(__data) - 1] = 0; + __dlen = (int) strlen(__data); + __echo_src = echo_src; + sstream = acl_vstream_listen(addr, 128); + assert(sstream); + + acl_aio_set_keep_read(aio, 1); + + astream = acl_aio_open(aio, sstream); + __listener = astream; + + printf(">>>listen: %s ...\r\n", addr); + + if (!accept_auto) { + acl_aio_ctl(astream, ACL_AIO_CTL_LISTEN_FN, __listen_callback, + ACL_AIO_CTL_CTX, aio, + ACL_AIO_CTL_END); + acl_aio_listen(astream); + } else { + acl_aio_ctl(astream, ACL_AIO_CTL_ACCEPT_FN, __accept_callback, + ACL_AIO_CTL_CTX, aio, + ACL_AIO_CTL_END); + acl_aio_accept(astream); + } +} + +void aio_server_end(void) +{ + if (__listener) { + acl_aio_iocp_close(__listener); + acl_aio_loop(__listener->aio); + __listener = NULL; + } +} \ No newline at end of file diff --git a/samples/winaio/aio_server.h b/samples/winaio/aio_server.h new file mode 100644 index 000000000..e80471efa --- /dev/null +++ b/samples/winaio/aio_server.h @@ -0,0 +1,10 @@ +#pragma once +#include "lib_acl.h" + +void aio_server_log_fn(void (*write_fn)(void *, const char *fmt, ...), + void *write_arg, + void (*fflush_fn)(void *), + void *fflush_arg); +void aiho_server_start(ACL_AIO *aio, const char *addr, int accept_auto, int echo_src); +void aio_server_end(void); + diff --git a/samples/winaio/res/winaio.ico b/samples/winaio/res/winaio.ico new file mode 100644 index 000000000..8a84ca3d3 Binary files /dev/null and b/samples/winaio/res/winaio.ico differ diff --git a/samples/winaio/res/winaio.manifest b/samples/winaio/res/winaio.manifest new file mode 100644 index 000000000..e6e8e243b --- /dev/null +++ b/samples/winaio/res/winaio.manifest @@ -0,0 +1,22 @@ + + + +鍦ㄦ璇存槑搴旂敤绋嬪簭 + + + + + + diff --git a/samples/winaio/res/winaio.rc2 b/samples/winaio/res/winaio.rc2 new file mode 100644 index 000000000..361f6e40e --- /dev/null +++ b/samples/winaio/res/winaio.rc2 @@ -0,0 +1,13 @@ +// +// winaio.RC2 - Microsoft Visual C++ 不会直接编辑的资源 +// + +#ifdef APSTUDIO_INVOKED +#error 此文件不能由 Microsoft Visual C++ 编辑 +#endif //APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// 在此处添加手动编辑的资源... + +///////////////////////////////////////////////////////////////////////////// diff --git a/samples/winaio/resource.h b/samples/winaio/resource.h new file mode 100644 index 000000000..f3aad7a66 --- /dev/null +++ b/samples/winaio/resource.h @@ -0,0 +1,31 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by winaio.rc +// +#define IDM_ABOUTBOX 0x0010 +#define IDD_ABOUTBOX 100 +#define IDS_ABOUTBOX 101 +#define IDD_WINAIO_DIALOG 102 +#define IDP_SOCKETS_INIT_FAILED 103 +#define IDR_MAINFRAME 128 +#define IDC_START 1000 +#define IDC_EDIT1 1001 +#define IDC_OUTPUT 1001 +#define IDC_INPUT 1002 +#define IDC_TEST 1003 +#define IDC_CONNECT 1004 +#define IDC_LISTEN 1005 +#define IDC_SET_TIMER 1006 +#define IDC_BUTTON2 1007 +#define IDC_DEL_TIMER 1007 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 129 +#define _APS_NEXT_COMMAND_VALUE 32771 +#define _APS_NEXT_CONTROL_VALUE 1008 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/samples/winaio/stdafx.cpp b/samples/winaio/stdafx.cpp new file mode 100644 index 000000000..69b70e83e --- /dev/null +++ b/samples/winaio/stdafx.cpp @@ -0,0 +1,7 @@ +// stdafx.cpp : 只包括标准包含文件的源文件 +// winaio.pch 将是预编译头 +// stdafx.obj 将包含预编译类型信息 + +#include "stdafx.h" + + diff --git a/samples/winaio/stdafx.h b/samples/winaio/stdafx.h new file mode 100644 index 000000000..ea496294f --- /dev/null +++ b/samples/winaio/stdafx.h @@ -0,0 +1,43 @@ +// stdafx.h : 标准系统包含文件的包含文件, +// 或是经常使用但不常更改的 +// 项目特定的包含文件 + +#pragma once + +#ifndef VC_EXTRALEAN +#define VC_EXTRALEAN // 从 Windows 标头中排除不常使用的资料 +#endif + +// 如果您必须使用下列所指定的平台之前的平台,则修改下面的定义。 +// 有关不同平台的相应值的最新信息,请参考 MSDN。 +#ifndef WINVER // 允许使用 Windows 95 和 Windows NT 4 或更高版本的特定功能。 +#define WINVER 0x0400 //为 Windows98 和 Windows 2000 及更新版本改变为适当的值。 +#endif + +#ifndef _WIN32_WINNT // 允许使用 Windows NT 4 或更高版本的特定功能。 +#define _WIN32_WINNT 0x0500 //为 Windows98 和 Windows 2000 及更新版本改变为适当的值。 +#endif + +#ifndef _WIN32_WINDOWS // 允许使用 Windows 98 或更高版本的特定功能。 +#define _WIN32_WINDOWS 0x0410 //为 Windows Me 及更新版本改变为适当的值。 +#endif + +#ifndef _WIN32_IE // 允许使用 IE 4.0 或更高版本的特定功能。 +#define _WIN32_IE 0x0400 //为 IE 5.0 及更新版本改变为适当的值。 +#endif + +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // 某些 CString 构造函数将是显式的 + +// 关闭 MFC 对某些常见但经常被安全忽略的警告消息的隐藏 +#define _AFX_ALL_WARNINGS + +#include // MFC 核心和标准组件 +#include // MFC 扩展 +#include // MFC 自动化类 + +#include // Internet Explorer 4 公共控件的 MFC 支持 +#ifndef _AFX_NO_AFXCMN_SUPPORT +#include // Windows 公共控件的 MFC 支持 +#endif // _AFX_NO_AFXCMN_SUPPORT + +#include // MFC 套接字扩展 diff --git a/samples/winaio/vld.dll b/samples/winaio/vld.dll new file mode 100644 index 000000000..381ac17d0 Binary files /dev/null and b/samples/winaio/vld.dll differ diff --git a/samples/winaio/winaio.aps b/samples/winaio/winaio.aps new file mode 100644 index 000000000..580ef5605 Binary files /dev/null and b/samples/winaio/winaio.aps differ diff --git a/samples/winaio/winaio.cpp b/samples/winaio/winaio.cpp new file mode 100644 index 000000000..a2013b97e --- /dev/null +++ b/samples/winaio/winaio.cpp @@ -0,0 +1,79 @@ +// winaio.cpp : 定义应用程序的类行为。 +// + +#include "stdafx.h" +#include "winaio.h" +#include "winaioDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#endif + + +// CwinaioApp + +BEGIN_MESSAGE_MAP(CwinaioApp, CWinApp) + ON_COMMAND(ID_HELP, CWinApp::OnHelp) +END_MESSAGE_MAP() + + +// CwinaioApp 构造 + +CwinaioApp::CwinaioApp() +{ + // TODO: 在此处添加构造代码, + // 将所有重要的初始化放置在 InitInstance 中 +} + + +// 唯一的一个 CwinaioApp 对象 + +CwinaioApp theApp; + + +// CwinaioApp 初始化 + +BOOL CwinaioApp::InitInstance() +{ + // 如果一个运行在 Windows XP 上的应用程序清单指定要 + // 使用 ComCtl32.dll 版本 6 或更高版本来启用可视化方式, + //则需要 InitCommonControls()。否则,将无法创建窗口。 + InitCommonControls(); + + CWinApp::InitInstance(); + + if (!AfxSocketInit()) + { + AfxMessageBox(IDP_SOCKETS_INIT_FAILED); + return FALSE; + } + + AfxEnableControlContainer(); + + // 标准初始化 + // 如果未使用这些功能并希望减小 + // 最终可执行文件的大小,则应移除下列 + // 不需要的特定初始化例程 + // 更改用于存储设置的注册表项 + // TODO: 应适当修改该字符串, + // 例如修改为公司或组织名 + SetRegistryKey(_T("应用程序向导生成的本地应用程序")); + + CwinaioDlg dlg; + m_pMainWnd = &dlg; + INT_PTR nResponse = dlg.DoModal(); + if (nResponse == IDOK) + { + // TODO: 在此放置处理何时用“确定”来关闭 + //对话框的代码 + } + else if (nResponse == IDCANCEL) + { + // TODO: 在此放置处理何时用“取消”来关闭 + //对话框的代码 + } + + // 由于对话框已关闭,所以将返回 FALSE 以便退出应用程序, + // 而不是启动应用程序的消息泵。 + return FALSE; +} diff --git a/samples/winaio/winaio.h b/samples/winaio/winaio.h new file mode 100644 index 000000000..d5592d4e4 --- /dev/null +++ b/samples/winaio/winaio.h @@ -0,0 +1,31 @@ +// winaio.h : PROJECT_NAME 应用程序的主头文件 +// + +#pragma once + +#ifndef __AFXWIN_H__ + #error 在包含用于 PCH 的此文件之前包含“stdafx.h” +#endif + +#include "resource.h" // 主符号 + + +// CwinaioApp: +// 有关此类的实现,请参阅 winaio.cpp +// + +class CwinaioApp : public CWinApp +{ +public: + CwinaioApp(); + +// 重写 + public: + virtual BOOL InitInstance(); + +// 实现 + + DECLARE_MESSAGE_MAP() +}; + +extern CwinaioApp theApp; diff --git a/samples/winaio/winaio.rc b/samples/winaio/winaio.rc new file mode 100644 index 000000000..8fe16e589 --- /dev/null +++ b/samples/winaio/winaio.rc @@ -0,0 +1,208 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// 中文(中华人民共和国) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) +#ifdef _WIN32 +LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED +#pragma code_page(936) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "#define _AFX_NO_SPLITTER_RESOURCES\r\n" + "#define _AFX_NO_OLE_RESOURCES\r\n" + "#define _AFX_NO_TRACKER_RESOURCES\r\n" + "#define _AFX_NO_PROPERTY_RESOURCES\r\n" + "\r\n" + "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)\r\n" + "LANGUAGE 4, 2\r\n" + "#pragma code_page(936)\r\n" + "#include ""res\\winaio.rc2"" // 非 Microsoft Visual C++ 编辑过的资源\r\n" + "#include ""afxres.rc"" // 标准组件\r\n" + "#endif\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDR_MAINFRAME ICON "res\\winaio.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_ABOUTBOX DIALOGEX 0, 0, 235, 55 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | + WS_SYSMENU +CAPTION "关于 winaio" +FONT 9, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + ICON IDR_MAINFRAME,IDC_STATIC,11,17,20,20 + LTEXT "winaio Version 1.0",IDC_STATIC,40,10,119,8,SS_NOPREFIX + LTEXT "Copyright (C) 2011",IDC_STATIC,40,25,119,8 + DEFPUSHBUTTON "确定",IDOK,178,7,50,16,WS_GROUP +END + +IDD_WINAIO_DIALOG DIALOGEX 0, 0, 320, 200 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | + WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_APPWINDOW +CAPTION "winaio" +FONT 9, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + DEFPUSHBUTTON "确定",IDOK,263,7,50,16 + PUSHBUTTON "取消",IDCANCEL,263,25,50,16 + PUSHBUTTON "开始",IDC_START,206,140,41,16 + EDITTEXT IDC_OUTPUT,26,14,220,120,ES_MULTILINE | ES_AUTOVSCROLL | + ES_AUTOHSCROLL + EDITTEXT IDC_INPUT,26,141,165,16,ES_AUTOHSCROLL + PUSHBUTTON "测试",IDC_TEST,257,140,41,14 + PUSHBUTTON "连接",IDC_CONNECT,25,165,50,14 + PUSHBUTTON "监听",IDC_LISTEN,86,165,50,14 + PUSHBUTTON "设置定时器",IDC_SET_TIMER,147,165,50,14 + PUSHBUTTON "取消定时器",IDC_DEL_TIMER,206,165,50,14 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "080403a8" + BEGIN + VALUE "CompanyName", "TODO: <公司名>" + VALUE "FileDescription", "TODO: <文件说明>" + VALUE "FileVersion", "1.0.0.1" + VALUE "InternalName", "winaio.exe" + VALUE "LegalCopyright", "TODO: (C) <公司名>。保留所有权利。" + VALUE "OriginalFilename", "winaio.exe" + VALUE "ProductName", "TODO: <产品名>" + VALUE "ProductVersion", "1.0.0.1" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "翻译", 0x804, 936 + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_ABOUTBOX, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 228 + TOPMARGIN, 7 + BOTTOMMARGIN, 48 + END + + IDD_WINAIO_DIALOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 313 + TOPMARGIN, 7 + BOTTOMMARGIN, 193 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + IDS_ABOUTBOX "关于 winaio(&A)..." + IDP_SOCKETS_INIT_FAILED "Windows 套接字初始化失败。" +END + +#endif // 中文(中华人民共和国) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +#define _AFX_NO_SPLITTER_RESOURCES +#define _AFX_NO_OLE_RESOURCES +#define _AFX_NO_TRACKER_RESOURCES +#define _AFX_NO_PROPERTY_RESOURCES + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) +LANGUAGE 4, 2 +#pragma code_page(936) +#include "res\winaio.rc2" // 非 Microsoft Visual C++ 编辑过的资源 +#include "afxres.rc" // 标准组件 +#endif + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/samples/winaio/winaio.vcproj b/samples/winaio/winaio.vcproj new file mode 100644 index 000000000..07910e258 --- /dev/null +++ b/samples/winaio/winaio.vcproj @@ -0,0 +1,332 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/winaio/winaio.vcxproj b/samples/winaio/winaio.vcxproj new file mode 100644 index 000000000..c852f8f18 --- /dev/null +++ b/samples/winaio/winaio.vcxproj @@ -0,0 +1,259 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + ReleaseDll + Win32 + + + Release + Win32 + + + Template + Win32 + + + + {4B58485B-D846-4485-9C5E-7F2304D71701} + MFCProj + + + + Application + Dynamic + MultiByte + + + Application + Dynamic + MultiByte + + + Application + Static + MultiByte + + + Application + Static + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + true + Use + Level3 + EditAndContinue + + + wsock32.lib;ws2_32.lib;%(AdditionalDependencies) + ..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + %(IgnoreSpecificDefaultLibraries) + true + Windows + MachineX86 + + + _DEBUG;%(PreprocessorDefinitions) + false + + + _DEBUG;%(PreprocessorDefinitions) + 0x0804 + $(IntDir);%(AdditionalIncludeDirectories) + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_WINDOWS;NDEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + false + MultiThreaded + true + Use + Level3 + ProgramDatabase + + + true + Windows + true + true + MachineX86 + + + NDEBUG;%(PreprocessorDefinitions) + false + + + NDEBUG;%(PreprocessorDefinitions) + 0x0804 + $(IntDir);%(AdditionalIncludeDirectories) + + + + + Disabled + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_WINDOWS;_DEBUG;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + true + Use + Level3 + EditAndContinue + + + wsock32.lib;ws2_32.lib;%(AdditionalDependencies) + ..\..\dist\lib\win32;%(AdditionalLibraryDirectories) + libcmtd;%(IgnoreSpecificDefaultLibraries) + true + Windows + MachineX86 + + + _DEBUG;%(PreprocessorDefinitions) + false + + + _DEBUG;%(PreprocessorDefinitions) + 0x0804 + $(IntDir);%(AdditionalIncludeDirectories) + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_WINDOWS;NDEBUG;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + false + MultiThreadedDLL + true + Use + Level3 + ProgramDatabase + + + true + Windows + true + true + MachineX86 + + + NDEBUG;%(PreprocessorDefinitions) + false + + + NDEBUG;%(PreprocessorDefinitions) + 0x0804 + $(IntDir);%(AdditionalIncludeDirectories) + + + + + + + Create + Create + Create + Create + + + + + + + + + + + + + + + + + + + + + + + + + + {b40213c2-507c-4c7f-a6e1-b850c9bdc27b} + false + + + + + + + + + + + \ No newline at end of file diff --git a/samples/winaio/winaio.vcxproj.filters b/samples/winaio/winaio.vcxproj.filters new file mode 100644 index 000000000..abcf302e0 --- /dev/null +++ b/samples/winaio/winaio.vcxproj.filters @@ -0,0 +1,71 @@ +锘 + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx + + + + + 婧愭枃浠 + + + 婧愭枃浠 + + + 婧愭枃浠 + + + 婧愭枃浠 + + + 婧愭枃浠 + + + + + 澶存枃浠 + + + 澶存枃浠 + + + 澶存枃浠 + + + 澶存枃浠 + + + 澶存枃浠 + + + 澶存枃浠 + + + + + 璧勬簮鏂囦欢 + + + 璧勬簮鏂囦欢 + + + + + + 璧勬簮鏂囦欢 + + + + + + \ No newline at end of file diff --git a/samples/winaio/winaioDlg.cpp b/samples/winaio/winaioDlg.cpp new file mode 100644 index 000000000..8ffb793ee --- /dev/null +++ b/samples/winaio/winaioDlg.cpp @@ -0,0 +1,242 @@ +// winaioDlg.cpp : 实现文件 +// + +#include "stdafx.h" +#include "winaio.h" +#include "lib_acl.h" +#include "aio_client.h" +#include "aio_server.h" +#include "winaioDlg.h" +#include ".\winaiodlg.h" +//#include "vld.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#endif + + +// 用于应用程序“关于”菜单项的 CAboutDlg 对话框 + +class CAboutDlg : public CDialog +{ +public: + CAboutDlg(); + +// 对话框数据 + enum { IDD = IDD_ABOUTBOX }; + + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 + +// 实现 +protected: + DECLARE_MESSAGE_MAP() +}; + +CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) +{ +} + +void CAboutDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); +} + +BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) +END_MESSAGE_MAP() + + +// CwinaioDlg 对话框 + + + +CwinaioDlg::CwinaioDlg(CWnd* pParent /*=NULL*/) + : CDialog(CwinaioDlg::IDD, pParent) +{ + m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); +} + +void CwinaioDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); +} + +BEGIN_MESSAGE_MAP(CwinaioDlg, CDialog) + ON_WM_SYSCOMMAND() + ON_WM_PAINT() + ON_WM_QUERYDRAGICON() + //}}AFX_MSG_MAP + ON_BN_CLICKED(IDC_START, OnBnClickedStart) + ON_BN_CLICKED(IDOK, OnBnClickedOk) + ON_BN_CLICKED(IDC_CONNECT, OnBnClickedConnect) + ON_BN_CLICKED(IDC_LISTEN, OnBnClickedListen) + ON_BN_CLICKED(IDC_SET_TIMER, OnBnClickedSetTimer) + ON_BN_CLICKED(IDC_DEL_TIMER, OnBnClickedDelTimer) +END_MESSAGE_MAP() + +static ACL_AIO *__aio = NULL; + +// CwinaioDlg 消息处理程序 + +BOOL CwinaioDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + // 将\“关于...\”菜单项添加到系统菜单中。 + + // IDM_ABOUTBOX 必须在系统命令范围内。 + ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); + ASSERT(IDM_ABOUTBOX < 0xF000); + + CMenu* pSysMenu = GetSystemMenu(FALSE); + if (pSysMenu != NULL) + { + CString strAboutMenu; + strAboutMenu.LoadString(IDS_ABOUTBOX); + if (!strAboutMenu.IsEmpty()) + { + pSysMenu->AppendMenu(MF_SEPARATOR); + pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); + } + } + + // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动 + // 执行此操作 + SetIcon(m_hIcon, TRUE); // 设置大图标 + SetIcon(m_hIcon, FALSE); // 设置小图标 + + // TODO: 在此添加额外的初始化代码 + //acl_init(); + //VLDEnable(); + aio_client_init(); + __aio = acl_aio_create(ACL_EVENT_WMSG); + ASSERT(__aio); + + return TRUE; // 除非设置了控件的焦点,否则返回 TRUE +} + +void CwinaioDlg::OnSysCommand(UINT nID, LPARAM lParam) +{ + if ((nID & 0xFFF0) == IDM_ABOUTBOX) + { + CAboutDlg dlgAbout; + dlgAbout.DoModal(); + } + else + { + CDialog::OnSysCommand(nID, lParam); + } +} + +// 如果向对话框添加最小化按钮,则需要下面的代码 +// 来绘制该图标。对于使用文档/视图模型的 MFC 应用程序, +// 这将由框架自动完成。 + +void CwinaioDlg::OnPaint() +{ + if (IsIconic()) + { + CPaintDC dc(this); // 用于绘制的设备上下文 + + SendMessage(WM_ICONERASEBKGND, reinterpret_cast(dc.GetSafeHdc()), 0); + + // 使图标在工作矩形中居中 + int cxIcon = GetSystemMetrics(SM_CXICON); + int cyIcon = GetSystemMetrics(SM_CYICON); + CRect rect; + GetClientRect(&rect); + int x = (rect.Width() - cxIcon + 1) / 2; + int y = (rect.Height() - cyIcon + 1) / 2; + + // 绘制图标 + dc.DrawIcon(x, y, m_hIcon); + } + else + { + CDialog::OnPaint(); + } +} + +//当用户拖动最小化窗口时系统调用此函数取得光标显示。 +HCURSOR CwinaioDlg::OnQueryDragIcon() +{ + return static_cast(m_hIcon); +} + +void CwinaioDlg::OnBnClickedStart() +{ + // TODO: 在此添加控件通知处理程序代码 + + const char *addr = "127.0.0.1:30082"; + aio_client_start(__aio, addr, 100); +} + +void CwinaioDlg::OnBnClickedOk() +{ + // TODO: 在此添加控件通知处理程序代码 + if (__aio) + { + aio_server_end(); + acl_aio_free(__aio); + acl_pthread_end(); + __aio = NULL; + } + OnOK(); +} + +void CwinaioDlg::OnBnClickedConnect() +{ + // TODO: 在此添加控件通知处理程序代码 + + const char *addr = "127.0.0.1:30082"; + aio_client_start(__aio, addr, 10); +} + +void CwinaioDlg::OnBnClickedListen() +{ + // TODO: 在此添加控件通知处理程序代码 + const char *addr = "127.0.0.1:30082"; + aiho_server_start(__aio, addr, 1, 1); +} + +typedef struct +{ + int i; + ACL_AIO *aio; +} CTX; + +static void OnTimerCallback(int event_type, void *context) +{ + CTX *ctx = (CTX*) context; + + ASSERT(ctx->aio == __aio); + printf(">>>timer %d get now\r\n", ctx->i); + free(ctx); +} + +static CTX *__last_ctx; + +void CwinaioDlg::OnBnClickedSetTimer() +{ + // TODO: 在此添加控件通知处理程序代码 + CTX *ctx = NULL; + + for (int i = 0; i < 10; i++) + { + ctx = (CTX*) malloc(sizeof(CTX)); + ctx->aio = __aio; + ctx->i = i; + printf("set timer %d\n", i); + acl_aio_request_timer(__aio, OnTimerCallback, ctx, i + 1, 1); + } + __last_ctx = ctx; +} + +void CwinaioDlg::OnBnClickedDelTimer() +{ + // TODO: 在此添加控件通知处理程序代码 + ASSERT(__last_ctx); + printf("cancel timer %d\n", __last_ctx->i); + acl_aio_cancel_timer(__aio, OnTimerCallback, __last_ctx); + free(__last_ctx); +} diff --git a/samples/winaio/winaioDlg.h b/samples/winaio/winaioDlg.h new file mode 100644 index 000000000..58709c5a2 --- /dev/null +++ b/samples/winaio/winaioDlg.h @@ -0,0 +1,38 @@ +// winaioDlg.h : 头文件 +// + +#pragma once + + +// CwinaioDlg 对话框 +class CwinaioDlg : public CDialog +{ +// 构造 +public: + CwinaioDlg(CWnd* pParent = NULL); // 标准构造函数 + +// 对话框数据 + enum { IDD = IDD_WINAIO_DIALOG }; + + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 + + +// 实现 +protected: + HICON m_hIcon; + + // 生成的消息映射函数 + virtual BOOL OnInitDialog(); + afx_msg void OnSysCommand(UINT nID, LPARAM lParam); + afx_msg void OnPaint(); + afx_msg HCURSOR OnQueryDragIcon(); + DECLARE_MESSAGE_MAP() +public: + afx_msg void OnBnClickedStart(); + afx_msg void OnBnClickedOk(); + afx_msg void OnBnClickedConnect(); + afx_msg void OnBnClickedListen(); + afx_msg void OnBnClickedSetTimer(); + afx_msg void OnBnClickedDelTimer(); +}; diff --git a/samples/xml/Makefile b/samples/xml/Makefile new file mode 100644 index 000000000..94298355a --- /dev/null +++ b/samples/xml/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = xml diff --git a/samples/xml/b.xml b/samples/xml/b.xml new file mode 100644 index 000000000..4b7b71458 --- /dev/null +++ b/samples/xml/b.xml @@ -0,0 +1,8 @@ + + XML catalog behavior can be changed by redirecting + queries to the user's own set of catalogs. This can be done by setting + the XML_CATALOG_FILES environment variable to a list + of catalogs. An empty one should deactivate loading the + default /etc/xml/catalog catalog. + + diff --git a/samples/xml/c.xml b/samples/xml/c.xml new file mode 100644 index 000000000..bbe137026 --- /dev/null +++ b/samples/xml/c.xml @@ -0,0 +1,5 @@ + + James Clark's SGML catalog + page + + diff --git a/samples/xml/d.xml b/samples/xml/d.xml new file mode 100644 index 000000000..5546c7c87 --- /dev/null +++ b/samples/xml/d.xml @@ -0,0 +1,8 @@ + + +xmlcatalog
"> +]> \ No newline at end of file diff --git a/samples/xml/lib_acl_vc2008.vcproj b/samples/xml/lib_acl_vc2008.vcproj new file mode 100644 index 000000000..2b5304129 --- /dev/null +++ b/samples/xml/lib_acl_vc2008.vcproj @@ -0,0 +1,2455 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/xml/test.html b/samples/xml/test.html new file mode 100644 index 000000000..63ba76a8d --- /dev/null +++ b/samples/xml/test.html @@ -0,0 +1,837 @@ + + + + +写信 - 任我邮 + + + + + + + + + + + + + + + + +
+ + + + + + + + +
+
+ + + + + + + + + + + + + +
收件人:
抄送:
主题:
附件: +
添加附件
+
    +
  • +
      +
    1. +
    +
    + +
    + 使用签名 + + + +
    +
    +
    + + + +
    + + + + + + + + + + +
    + + + + +
    + + +
    + + + +
    +
    关闭提示!
    +
    +

    你未填写邮件主题,确定发送吗?

    +
    + + 确 定 +
    +
    +
    + + +
    + + diff --git a/samples/xml/test2.html b/samples/xml/test2.html new file mode 100644 index 000000000..fbd05a89e --- /dev/null +++ b/samples/xml/test2.html @@ -0,0 +1,2 @@ +
    + diff --git a/samples/xml/valgrind.sh b/samples/xml/valgrind.sh new file mode 100644 index 000000000..3a9d3bb09 --- /dev/null +++ b/samples/xml/valgrind.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +valgrind --tool=memcheck --leak-check=yes -v ./xml diff --git a/samples/xml/xml.c b/samples/xml/xml.c new file mode 100644 index 000000000..4f035dfbc --- /dev/null +++ b/samples/xml/xml.c @@ -0,0 +1,598 @@ +#include "lib_acl.h" + +#define STR acl_vstring_str + +static const char *__data1 = + "\r\n" + "\r\n" + "\txmllint
    \">\r\n" + "]>\r\n" + "\r\n" + " user zsx11 \r\n" + " user zsx12 \r\n" + " my age\r\n" + " " + " " + " mobile number " + " mobile number " + " " + " " + " \r\n" + " user zsx13 \r\n" + "\r\n" + "\r\n" + " user zsx21 \r\n" + " user zsx22 \r\n" + " \r\n" + " my age\r\n" + " \r\n" + " user zsx23 \r\n" + "\r\n" + "\r\n" + " user zsx31 \r\n" + " user zsx32 \r\n" + " user zsx33 \r\n" + " bao bao \r\n" + " \r\n" + " \r\n" + " \r\n" + " \r\n" + " user zsx34 \r\n" + "\r\n"; + +static const char *__data2 = + "\r\n" + "\r\n" + "xmllint\">\r\n" + "]>\r\n" + "test\r\n" + " - -->\r\n" + " zsx\r\n" + " 38\r\n" + " \r\n" + "\r\n" + " -->\r\n" + "\r\n" + "\r\n" + "test\r\n"; + +static const char *__data3 = "hello hi
    \r\n"; + +static const char* __data4 = "\r\n" + "\r\n" + " \r\n" + " \r\n" + " \r\n" + " \r\n" + " \r\n" + " \r\n" + " \r\n" + " \r\n" + " \r\n" + " \r\n" + " \r\n" + " \r\n" + " \r\n" + " \r\n" + " \r\n" + "\r\n"; + +static const char* __data5 = "\r\n" + "\r\n" + " \r\n" + " \r\n" + " \r\n" + " \r\n" + " \r\n" + " \r\n" + "\r\n"; + +static const char* __data6 = "\r\n" + "\r\n" + " \r\n" + " \r\n" + " \r\n" + " \r\n" + " \r\n" + " \r\n" + " \r\n" + " \r\n" + " \r\n" + " \r\n" + " \r\n" + " \r\n" + "\r\n"; + +static const char* __data7 = "\r\n" + "\r\n" + " \r\n" + " \r\n" + " \r\n" + " \r\n" + " \r\n" + " \r\n" + " \r\n" + " \r\n" + " \r\n" + " \r\n" + " \r\n" + " \r\n" + "\r\n"; + +static void parse_xml_benchmark(int once, int use_cache, int max, const char *data) +{ + int i; + ACL_XML *xml = acl_xml_alloc(); + + acl_xml_slash(xml, 1); + if (use_cache) + acl_xml_cache(xml, 100); + + ACL_METER_TIME("-------------bat begin--------------"); + for (i = 0; i < max; i++) { + const char *ptr = data; + + if (once) { + acl_xml_parse(xml, ptr); + } else { + /* 每次仅输入一个字节来分析 xml 数据 */ + while (*ptr != 0) { + char ch2[2]; + + ch2[0] = *ptr; + ch2[1] = 0; + acl_xml_parse(xml, ch2); + ptr++; + } + } + if (i < 2 || i == 4) { + printf("--------- dump xml --------------\n"); + acl_xml_dump(xml, ACL_VSTREAM_OUT); + printf("--------- data src --------------\n"); + printf("%s", data); + printf("--------- dump end --------------\n"); + } + + + acl_xml_reset(xml); + } + ACL_METER_TIME("-------------bat end--------------"); + acl_xml_free(xml); +} + +static void build_xml(ACL_XML *xml, const char *data) +{ + ACL_VSTRING *buf = acl_xml_build(xml, NULL); + ACL_FILE *fp = acl_fopen("./build_xml.txt", "wb"); + + acl_assert(fp); + + printf("--------------in build_xml -------------------\n"); + printf("%s\r\n", acl_vstring_str(buf)); + acl_fwrite(acl_vstring_str(buf), ACL_VSTRING_LEN(buf), 1, fp); + printf("----------------------------------------------\n"); + printf("%s\r\n", data); + acl_fclose(fp); + printf("--------------end in build_xml----------------\n"); + acl_vstring_free(buf); +} + +static void parse_xml(int once, const char *data) +{ + ACL_XML *xml = acl_xml_alloc(); + const char *ptr; + ACL_ITER iter1; + int i, total, left; + ACL_ARRAY *a; + ACL_XML_NODE *pnode; + + ptr = data; + + if (once) { + /* 一次性地分析完整 xml 数据 */ + ACL_METER_TIME("-------------once begin--------------"); + acl_xml_parse(xml, ptr); + } else { + /* 每次仅输入一个字节来分析 xml 数据 */ + ACL_METER_TIME("-------------stream begin--------------"); + while (*ptr != 0) { + char ch2[2]; + + ch2[0] = *ptr; + ch2[1] = 0; + acl_xml_parse(xml, ch2); + ptr++; + } + } + ACL_METER_TIME("-------------end--------------"); + printf("enter any key to continue ...\n"); + getchar(); + + if (acl_xml_is_complete(xml, "root")) { + printf(">> Yes, the xml complete\n"); + } else { + printf(">> No, the xml not complete\n"); + } + + total = xml->node_cnt; + + /* 遍历根结点的一级子结点 */ + acl_foreach(iter1, xml->root) { + ACL_ITER iter2; + + ACL_XML_NODE *node = (ACL_XML_NODE*) iter1.data; + printf("tag> %s, text: %s\n", STR(node->ltag), STR(node->text)); + + /* 遍历一级子结点的二级子结点 */ + acl_foreach(iter2, node) { + ACL_ITER iter3; + ACL_XML_NODE *node2 = (ACL_XML_NODE*) iter2.data; + + printf("\ttag> %s, text: %s\n", STR(node2->ltag), STR(node2->text)); + + /* 遍历二级子结点的属性 */ + acl_foreach(iter3, node2->attr_list) { + ACL_XML_ATTR *attr = (ACL_XML_ATTR*) iter3.data; + printf("\t\tattr> %s: %s\n", STR(attr->name), STR(attr->value)); + } + } + } + + printf("----------------------------------------------------\n"); + + /* 从根结点开始遍历 xml 对象的所有结点 */ + + acl_foreach(iter1, xml) { + ACL_ITER iter2; + ACL_XML_NODE *node = (ACL_XML_NODE*) iter1.data; + + for (i = 1; i < node->depth; i++) { + printf("\t"); + } + + printf("tag> %s, text: %s\n", STR(node->ltag), STR(node->text)); + + /* 遍历 xml 结点的属性 */ + acl_foreach(iter2, node->attr_list) { + ACL_XML_ATTR *attr = (ACL_XML_ATTR*) iter2.data; + + for (i = 1; i < node->depth; i++) { + printf("\t"); + } + + printf("\tattr> %s: %s\n", STR(attr->name), STR(attr->value)); + } + } + + /* 根据标签名获得 xml 结点集合 */ + + printf("--------- acl_xml_getElementsByTagName ----------\n"); + a = acl_xml_getElementsByTagName(xml, "user"); + if (a) { + /* 遍历结果集 */ + acl_foreach(iter1, a) { + ACL_XML_NODE *node = (ACL_XML_NODE*) iter1.data; + printf("tag> %s, text: %s\n", STR(node->ltag), STR(node->text)); + } + /* 释放数组对象 */ + acl_xml_free_array(a); + } + + + /* 查询属性名为 name, 属性值为 user2_1 的所有 xml 结点的集合 */ + + printf("--------- acl_xml_getElementsByName ------------\n"); + a = acl_xml_getElementsByName(xml, "user2_1"); + if (a) { + /* 遍历结果集 */ + acl_foreach(iter1, a) { + ACL_XML_NODE *node = (ACL_XML_NODE*) iter1.data; + printf("tag> %s, text: %s\n", STR(node->ltag), STR(node->text)); + } + /* 释放数组对象 */ + acl_xml_free_array(a); + } + + /* 查询属性名为 id, 属性值为 id2_2 的所有 xml 结点集合 */ + printf("----------- acl_xml_getElementById -------------\n"); + pnode = acl_xml_getElementById(xml, "id2_2"); + if (pnode) { + printf("tag> %s, text: %s\n", STR(pnode->ltag), STR(pnode->text)); + /* 遍历该 xml 结点的属性 */ + acl_foreach(iter1, pnode->attr_list) { + ACL_XML_ATTR *attr = (ACL_XML_ATTR*) iter1.data; + printf("\tattr_name: %s, attr_value: %s\n", + STR(attr->name), STR(attr->value)); + } + + pnode = acl_xml_node_next(pnode); + printf("----------------- the id2_2's next node is ---------------------\n"); + if (pnode) { + printf("-------------- walk node -------------------\n"); + /* 遍历该 xml 结点的属性 */ + acl_foreach(iter1, pnode->attr_list) { + ACL_XML_ATTR *attr = (ACL_XML_ATTR*) iter1.data; + printf("\tattr_name: %s, attr_value: %s\n", + STR(attr->name), STR(attr->value)); + } + + } else { + printf("-------------- null node -------------------\n"); + } + } + + pnode = acl_xml_getElementById(xml, "id2_3"); + if (pnode) { + int ndel = 0, node_cnt; + + /* 删除该结点及其子结点 */ + printf(">>>before delete %s, total: %d\n", STR(pnode->ltag), xml->node_cnt); + ndel = acl_xml_node_delete(pnode); + node_cnt = xml->node_cnt; + printf(">>>after delete id2_3(%d deleted), total: %d\n", ndel, node_cnt); + } + + acl_foreach(iter1, xml) { + ACL_XML_NODE *node = (ACL_XML_NODE*) iter1.data; + printf(">>tag: %s\n", STR(node->ltag)); + } + + pnode = acl_xml_getElementById(xml, "id2_3"); + if (pnode) { + printf("-------------- walk %s node -------------------\n", STR(pnode->ltag)); + /* 遍历该 xml 结点的属性 */ + acl_foreach(iter1, pnode->attr_list) { + ACL_XML_ATTR *attr = (ACL_XML_ATTR*) iter1.data; + printf("\tattr_name: %s, attr_value: %s\n", + STR(attr->name), STR(attr->value)); + } + } else { + printf("---- the id2_3 be deleted----\n"); + } + + build_xml(xml, data); + + /* 释放 xml 对象 */ + left = acl_xml_free(xml); + printf("free all node ok, total(%d), left is: %d\n", total, left); +} + +static void parse_xml_file(const char *filepath, int once) +{ + char *data = acl_vstream_loadfile(filepath); + ACL_VSTREAM *fp; + char *ptr; + ACL_XML *xml; + struct timeval begin, end; + + if (data == NULL) + return; + + gettimeofday(&begin, NULL); + + /* 创建 xml 对象 */ + xml = acl_xml_alloc(); + + ptr = data; + + if (once) { + /* 一次性地分析完整 xml 数据 */ + acl_xml_parse(xml, ptr); + } else { + /* 每次仅输入一个字节来分析 xml 数据 */ + while (*ptr) { + char ch2[2]; + + ch2[0] = *ptr; + ch2[1] = 0; + acl_xml_parse(xml, ch2); + ptr++; + } + } + + gettimeofday(&end, NULL); + + printf("------ok, time: %ld seconds, %ld microseconds -------\r\n", + (long) end.tv_sec - (long) begin.tv_sec, + (long) end.tv_usec - (long) begin.tv_usec); + + + fp = acl_vstream_fopen("dump.txt", O_RDWR | O_CREAT | O_TRUNC, 0600, 4096); + + /* 将 xml 对象转储至指定流中 */ + acl_xml_dump(xml, fp); + + acl_vstream_fclose(fp); + acl_xml_free(xml); + acl_myfree(data); +} + +static void build_xml2(void) +{ + ACL_XML *xml = acl_xml_alloc(); + ACL_XML_NODE *node1, *node2, *node3; + ACL_VSTRING *buf; + + node1 = acl_xml_create_node(xml, "users", "text1"); + acl_xml_node_add_child(xml->root, node1); + (void) acl_xml_node_add_attr(node1, "name", "users list"); + + node2 = acl_xml_create_node(xml, "user", "text11"); + acl_xml_node_add_child(node1, node2); + acl_xml_node_add_attrs(node2, "name", "user11", "value", "zsx11", NULL); + + node3 = acl_xml_create_node(xml, "age", "text111"); + acl_xml_node_add_child(node2, node3); + acl_xml_node_add_attrs(node3, "name", "user111", "value", "zsx111", NULL); + + node2 = acl_xml_create_node(xml, "user", "text2"); + acl_xml_node_add_child(node1, node2); + acl_xml_node_add_attrs(node2, "name", "value2", "value", "zsx2", NULL); + + node2 = acl_xml_create_node(xml, "user", "text3"); + acl_xml_node_add_child(node1, node2); + acl_xml_node_add_attrs(node2, "name", "value3", "value", "zsx3", NULL); + + buf = acl_xml_build(xml, NULL); + printf("--------------------xml string-------------------\r\n"); + printf("%s\n", acl_vstring_str(buf)); + acl_vstring_free(buf); + + acl_xml_free(xml); +} + +static void test1(void) +{ + const char* data = "\r\n" + "\r\n" + "\txmllint\">\r\n" + "]>\r\n" + "\r\n"; + ACL_XML *xml = acl_xml_alloc(); + ACL_ITER node_it, attr_it; + ACL_XML_NODE *node; + const char *encoding, *type, *href; + + printf("data: %s\r\n", data); + acl_xml_update(xml, data); + acl_foreach(node_it, xml) { + ACL_XML_NODE *tmp = (ACL_XML_NODE*) node_it.data; + printf("tag: %s\r\n", STR(tmp->ltag)); + acl_foreach(attr_it, tmp->attr_list) { + ACL_XML_ATTR *attr = (ACL_XML_ATTR*) attr_it.data; + printf("\tattr_name: %s, attr_value: %s\r\n", + STR(attr->name), STR(attr->value)); + } + } + + printf("------------------------------------------------------\r\n"); + + encoding = acl_xml_getEncoding(xml); + type = acl_xml_getType(xml); + node = acl_xml_getElementMeta(xml, "xml-stylesheet"); + if (node) + href = acl_xml_getElementAttrVal(node, "href"); + else + href = NULL; + printf("xml encoding: %s, type: %s, href: %s\r\n", + encoding ? encoding : "null", type ? type : "null", + href ? href : "null"); + acl_xml_free(xml); +} + +static void usage(const char *procname) +{ + printf("usage: %s -h[help]" + " -f {xml_file}\n" + " -s[parse once]\n" + " -M[use mempool]\n" + " -b[benchmark] -c[cache xml node] -m benchmark_max\n" + " -p[print] data1|data2|data3|data4|data5|data6|data7\n" + " -d[which data] data1|data2|data3|data4|data5|data6|data7\n", + procname); +} + +#ifdef WIN32 +#define snprintf _snprintf +#endif + +int main(int argc, char *argv[]) +{ + int ch, once = 0, bench_max = 10000; + char filepath[256]; + int benchmark = 0, use_mempool = 0, use_cache = 0; + const char *data = __data1; + + if (0) { + test1(); getchar(); exit(0); + } + + snprintf(filepath, sizeof(filepath), "xmlcatalog_man.xml"); + + while ((ch = getopt(argc, argv, "hf:sbm:cMp:d:")) > 0) { + switch (ch) { + case 'h': + usage(argv[0]); + return (0); + case 'f': + snprintf(filepath, sizeof(filepath), "%s", optarg); + break; + case 's': + once = 1; + break; + case 'b': + benchmark = 1; + break; + case 'M': + use_mempool = 1; + break; + case 'c': + use_cache = 1; + break; + case 'm': + bench_max = atoi(optarg); + break; + case 'd': + if (strcasecmp(optarg, "data2") == 0) + data = __data2; + else if (strcasecmp(optarg, "data3") == 0) + data = __data3; + else if (strcasecmp(optarg, "data4") == 0) + data = __data4; + else if (strcasecmp(optarg, "data5") == 0) + data = __data5; + else if (strcasecmp(optarg, "data6") == 0) + data = __data6; + else if (strcasecmp(optarg, "data7") == 0) + data = __data7; + break; + case 'p': + if (strcasecmp(optarg, "data1") == 0) + printf("%s\n", __data1); + else if (strcasecmp(optarg, "data2") == 0) + printf("%s\n", __data2); + else if (strcasecmp(optarg, "data3") == 0) + printf("%s\n", __data3); + else if (strcasecmp(optarg, "data4") == 0) + printf("%s\n", __data4); + else if (strcasecmp(optarg, "data5") == 0) + printf("%s\n", __data5); + else if (strcasecmp(optarg, "data6") == 0) + printf("%s\n", __data6); + else if (strcasecmp(optarg, "data7") == 0) + printf("%s\n", __data7); + return (0); + default: + break; + } + } + + if (use_mempool) + acl_mem_slice_init(8, 1024, 100000, + ACL_SLICE_FLAG_GC2 | + ACL_SLICE_FLAG_RTGC_OFF | + ACL_SLICE_FLAG_LP64_ALIGN); + if (benchmark) { + parse_xml_benchmark(once, use_cache, bench_max, data); + return (0); + } + + parse_xml(once, data); + parse_xml_file(filepath, once); + build_xml2(); + +#ifdef ACL_MS_WINDOWS + printf("ok, enter any key to exit ...\n"); + getchar(); +#endif + return 0; +} diff --git a/samples/xml/xml.vcproj b/samples/xml/xml.vcproj new file mode 100644 index 000000000..58a840335 --- /dev/null +++ b/samples/xml/xml.vcproj @@ -0,0 +1,234 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/xml/xml.vcxproj b/samples/xml/xml.vcxproj new file mode 100644 index 000000000..5d4a4c52d --- /dev/null +++ b/samples/xml/xml.vcxproj @@ -0,0 +1,181 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + ReleaseDll + Win32 + + + Release + Win32 + + + + {BA8A20D5-958E-4DEC-9151-27049C2EEEB2} + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)xml.exe + true + $(OutDir)xml.pdb + Console + MachineX86 + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;%(AdditionalDependencies) + $(OutDir)xml.exe + true + Console + true + true + MachineX86 + + + + + Disabled + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + EditAndContinue + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)xml.exe + true + $(OutDir)xml.pdb + Console + MachineX86 + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;%(AdditionalDependencies) + $(OutDir)xml.exe + true + Console + true + true + MachineX86 + + + + + {b40213c2-507c-4c7f-a6e1-b850c9bdc27b} + false + + + + + + + + + \ No newline at end of file diff --git a/samples/xml/xmlcatalog_man.xml b/samples/xml/xmlcatalog_man.xml new file mode 100644 index 000000000..46330bbe6 --- /dev/null +++ b/samples/xml/xmlcatalog_man.xml @@ -0,0 +1,446 @@ + + +xmlcatalog"> +]> + + + + + xmlcatalog Manual + libxml2 + + 2001 + 2004 + + + John + Fleck + +
    + jfleck@inkstain.net +
    +
    +
    + + $Date$ + + + +
    + + + xmlcatalog + 1 + + + + xmlcatalog + + Command line tool to parse and manipulate XML + or SGML catalog files. + + + + + + xmlcatalog + + + + + + + + + + + + + + + + + + + + + + + CATALOGFILE + ENTITIES + + + + + DESCRIPTION + + &xmlcatalog; is a command line application allowing users to monitor and + manipulate XML and SGML catalogs. It + is included in + libxml + 3 + . + + + Its functions can be invoked from a single command from the command line, + or it can perform multiple functions in interactive mode. It can operate + on both XML and SGML files. + + + + + OPTIONS + + &xmlcatalog; accepts the following options (in alphabetical order): + + + + + + + + + + + Add an entry to CATALOGFILE. TYPE + indicates the type of entry. Possible types are: + public + system + rewriteSystem + rewriteURI + delegatePublic + delegateSystem + nextCatalog + . ORIG is the original + reference to be replaced, and REPLACE + is the URI of the replacement entity to be + used. The option will not overwrite + CATALOGFILE, outputting + to stdout, unless + is used. The will + always take three parameters even if some of the XML + catalog constructs will have only a single argument. + + + + + + + + + + If the option is used following + the option, only a single argument, + a FILENAME, is used. This is used to add + the name of a catalog file to an SGML supercatalog, + a file that contains references to other included SGML + catalog files. + + + + + + + + + Create a new XML catalog. Outputs + to stdout, + ignoring filename unless is + used, in which case it creates a new catalog + file filename. + + + + + + + + + Remove entries from CATALOGFILE + matching VALUE(S). The + option will not overwrite CATALOGFILE, + outputting to stdout, + unless is used. + + + + + + + + + Save output to the named file rather than outputting + to stdout. + + + + + + + + + Do not update the SGML super catalog. + + + + + + + + + Run a shell allowing interactive queries on catalog + file CATALOGFILE. For the set of available + commands see . + + + + + + + + + Uses SGML super catalogs for + and options. + + + + + + + + + Output debugging information. + + + + + + + + SHELL COMMANDS + + Invoking &xmlcatalog; with + the option opens + a command line shell allowing interactive access to the catalog file + identified by CATALOGFILE. Invoking the shell + provides a command line prompt after which the following commands (described in + alphabetical order) can be entered. + + + + + + + + + + + Add an entry to the catalog file. TYPE + indicates the type of entry. Possible types are: + public + system + rewriteSystem + rewriteURI + delegatePublic + delegateSystem + nextCatalog + . ORIG is the original + reference to be replaced, and REPLACE + is the URI of the replacement entity to be + used. The option will not overwrite + CATALOGFILE, outputting + to stdout, unless + is used. The will + always take three parameters even if some of the XML + catalog constructs will have only a single argument. + + + + + + + + + Print debugging statements showing the steps &xmlcatalog; is executing. + + + + + + + + + Remove the catalog entry corresponding to VALUE(S). + + + + + + + + Print the current catalog. + + + + + + + Quit the shell. + + + + + + + + Execute a Formal Public Identifier look-up of the catalog entry + for PUBLIC-ID. The corresponding entry will be + output to the command line. + + + + + + + + Stop printing debugging statements. + + + + + + + + Execute a Formal Public Identifier look-up of the catalog entry + for SYSTEM-ID. The corresponding entry will be + output to the command line. + + + + + + + + + ENVIRONMENT + + + + XML_CATALOG_FILES + + XML catalog behavior can be changed by redirecting + queries to the user's own set of catalogs. This can be done by setting + the XML_CATALOG_FILES environment variable to a list + of catalogs. An empty one should deactivate loading the + default /etc/xml/catalog catalog. + + + + + + + + + DIAGNOSTICS + + &xmlcatalog; return codes provide information that can be used when + calling it from scripts. + + + + + 0 + + No error + + + + + 1 + + Failed to remove an entry from the catalog + + + + + 2 + + Failed to save to the catalog, check file permissions + + + + + 3 + + Failed to add an entry to the catalog + + + + + 4 + + Failed to look up an entry in the catalog + + + + + + + + SEE ALSO + + libxml + 3 + + + + More information can be found at + + + + libxml + 3 + web page + + + + + libxml + 3 + catalog support web page + at + + + + James Clark's SGML catalog + page + + + + OASIS XML catalog specification + + + + + + + +
    diff --git a/samples/xml/xmlwf.sgml b/samples/xml/xmlwf.sgml new file mode 100644 index 000000000..139c95e1f --- /dev/null +++ b/samples/xml/xmlwf.sgml @@ -0,0 +1,473 @@ + manpage.1'. You may view + the manual page with: `docbook-to-man manpage.sgml | nroff -man | + less'. A typical entry in a Makefile or Makefile.am is: + +manpage.1: manpage.sgml + docbook-to-man $< > $@ + --> + + + Scott"> + Bronson"> + + December 5, 2001"> + + 1"> + bronson@rinspin.com"> + + XMLWF"> + + + Debian GNU/Linux"> + GNU"> +]> + + + +
    + &dhemail; +
    + + &dhfirstname; + &dhsurname; + + + 2001 + &dhusername; + + &dhdate; +
    + + &dhucpackage; + + &dhsection; + + + &dhpackage; + + Determines if an XML document is well-formed + + + + &dhpackage; + + + + + + + + + + + + + + + + + + file ... + + + + + DESCRIPTION + + + &dhpackage; uses the Expat library to + determine if an XML document is well-formed. It is + non-validating. + + + + If you do not specify any files on the command-line, and you + have a recent version of &dhpackage;, the + input file will be read from standard input. + + + + + + WELL-FORMED DOCUMENTS + + + A well-formed document must adhere to the + following rules: + + + + + The file begins with an XML declaration. For instance, + <?xml version="1.0" standalone="yes"?>. + NOTE: + &dhpackage; does not currently + check for a valid XML declaration. + + + Every start tag is either empty (<tag/>) + or has a corresponding end tag. + + + There is exactly one root element. This element must contain + all other elements in the document. Only comments, white + space, and processing instructions may come after the close + of the root element. + + + All elements nest properly. + + + All attribute values are enclosed in quotes (either single + or double). + + + + + If the document has a DTD, and it strictly complies with that + DTD, then the document is also considered valid. + &dhpackage; is a non-validating parser -- + it does not check the DTD. However, it does support + external entities (see the option). + + + + + OPTIONS + + +When an option includes an argument, you may specify the argument either +separately (" output") or concatenated with the +option ("output"). &dhpackage; +supports both. + + + + + + + + + If the input file is well-formed and &dhpackage; + doesn't encounter any errors, the input file is simply copied to + the output directory unchanged. + This implies no namespaces (turns off ) and + requires to specify an output file. + + + + + + + + + Specifies a directory to contain transformed + representations of the input files. + By default, outputs a canonical representation + (described below). + You can select different output formats using + and . + + + The output filenames will + be exactly the same as the input filenames or "STDIN" if the input is + coming from standard input. Therefore, you must be careful that the + output file does not go into the same directory as the input + file. Otherwise, &dhpackage; will delete the + input file before it generates the output file (just like running + cat < file > file in most shells). + + + Two structurally equivalent XML documents have a byte-for-byte + identical canonical XML representation. + Note that ignorable white space is considered significant and + is treated equivalently to data. + More on canonical XML can be found at + http://www.jclark.com/xml/canonxml.html . + + + + + + + + + Specifies the character encoding for the document, overriding + any document encoding declaration. &dhpackage; + supports four built-in encodings: + US-ASCII, + UTF-8, + UTF-16, and + ISO-8859-1. + Also see the option. + + + + + + + + + Outputs some strange sort of XML file that completely + describes the the input file, including character postitions. + Requires to specify an output file. + + + + + + + + + Turns on namespace processing. (describe namespaces) + disables namespaces. + + + + + + + + + Tells xmlwf to process external DTDs and parameter + entities. + + + Normally &dhpackage; never parses parameter + entities. tells it to always parse them. + implies . + + + + + + + + + Normally &dhpackage; memory-maps the XML file + before parsing; this can result in faster parsing on many + platforms. + turns off memory-mapping and uses normal file + IO calls instead. + Of course, memory-mapping is automatically turned off + when reading from standard input. + + + Use of memory-mapping can cause some platforms to report + substantially higher memory usage for + &dhpackage;, but this appears to be a matter of + the operating system reporting memory in a strange way; there is + not a leak in &dhpackage;. + + + + + + + + + Prints an error if the document is not standalone. + A document is standalone if it has no external subset and no + references to parameter entities. + + + + + + + + + Turns on timings. This tells Expat to parse the entire file, + but not perform any processing. + This gives a fairly accurate idea of the raw speed of Expat itself + without client overhead. + turns off most of the output options + (, , , + ...). + + + + + + + + + Prints the version of the Expat library being used, including some + information on the compile-time configuration of the library, and + then exits. + + + + + + + + + Enables support for Windows code pages. + Normally, &dhpackage; will throw an error if it + runs across an encoding that it is not equipped to handle itself. With + , &dhpackage; will try to use a Windows code + page. See also . + + + + + + + + + Turns on parsing external entities. + + + Non-validating parsers are not required to resolve external + entities, or even expand entities at all. + Expat always expands internal entities (?), + but external entity parsing must be enabled explicitly. + + + External entities are simply entities that obtain their + data from outside the XML file currently being parsed. + + + This is an example of an internal entity: + +<!ENTITY vers '1.0.2'> + + + + And here are some examples of external entities: + + +<!ENTITY header SYSTEM "header-&vers;.xml"> (parsed) +<!ENTITY logo SYSTEM "logo.png" PNG> (unparsed) + + + + + + + + + + + (Two hyphens.) + Terminates the list of options. This is only needed if a filename + starts with a hyphen. For example: + + +&dhpackage; -- -myfile.xml + + + will run &dhpackage; on the file + -myfile.xml. + + + + + + + Older versions of &dhpackage; do not support + reading from standard input. + + + + + OUTPUT + + If an input file is not well-formed, + &dhpackage; prints a single line describing + the problem to standard output. If a file is well formed, + &dhpackage; outputs nothing. + Note that the result code is not set. + + + + + BUGS + + According to the W3C standard, an XML file without a + declaration at the beginning is not considered well-formed. + However, &dhpackage; allows this to pass. + + + &dhpackage; returns a 0 - noerr result, + even if the file is not well-formed. There is no good way for + a program to use &dhpackage; to quickly + check a file -- it must parse &dhpackage;'s + standard output. + + + The errors should go to standard error, not standard output. + + + There should be a way to get to send its + output to standard output rather than forcing the user to send + it to a file. + + + I have no idea why anyone would want to use the + , , and + options. If someone could explain it to + me, I'd like to add this information to this manpage. + + + + + ALTERNATIVES + + Here are some XML validators on the web: + + +http://www.hcrc.ed.ac.uk/~richard/xml-check.html +http://www.stg.brown.edu/service/xmlvalid/ +http://www.scripting.com/frontier5/xml/code/xmlValidator.html +http://www.xml.com/pub/a/tools/ruwf/check.html + + + + + + + SEE ALSO + + + +The Expat home page: http://www.libexpat.org/ +The W3 XML specification: http://www.w3.org/TR/REC-xml + + + + + + + AUTHOR + + This manual page was written by &dhusername; &dhemail; for + the &debian; system (but may be used by others). Permission is + granted to copy, distribute and/or modify this document under + the terms of the GNU Free Documentation + License, Version 1.1. + + +
    + + diff --git a/samples/xml2/Makefile b/samples/xml2/Makefile new file mode 100644 index 000000000..94298355a --- /dev/null +++ b/samples/xml2/Makefile @@ -0,0 +1,2 @@ +include ../Makefile.in +PROG = xml diff --git a/samples/xml2/main.c b/samples/xml2/main.c new file mode 100644 index 000000000..99a3fdb48 --- /dev/null +++ b/samples/xml2/main.c @@ -0,0 +1,112 @@ +#include "lib_acl.h" + +static double stamp_sub(const struct timeval *from, const struct timeval *sub_by) +{ + struct timeval res; + + memcpy(&res, from, sizeof(struct timeval)); + + res.tv_usec -= sub_by->tv_usec; + if (res.tv_usec < 0) { + --res.tv_sec; + res.tv_usec += 1000000; + } + res.tv_sec -= sub_by->tv_sec; + + return (res.tv_sec * 1000.0 + res.tv_usec/1000.0); +} + +static void usage(const char* proc) +{ + printf("usage: %s -h[help] -m[use_memslice] -c cache_count -f filepath\r\n", proc); +} + +int main(int argc, char* argv[]) +{ + char buf[8192], filepath[256]; + int ret, n; + ACL_VSTREAM* fp; + ACL_XML* xml; + struct timeval begin, end; + double spent; + int ch, use_slice = 0, cache_count = 1000; + + filepath[0] = 0; + while ((ch = getopt(argc, argv, "hmc:f:")) > 0) + { + switch (ch) + { + case 'h': + usage(argv[0]); + return 0; + case 'm': + use_slice = 1; + break; + case 'c': + cache_count = atoi(optarg); + if (cache_count <= 0) + cache_count = 1000; + break; + case 'f': + snprintf(filepath, sizeof(filepath), "%s", optarg); + break; + default: + break; + } + } + + if (use_slice) + acl_mem_slice_init(8, 1024, 100000, + ACL_SLICE_FLAG_GC2 | + ACL_SLICE_FLAG_RTGC_OFF | + ACL_SLICE_FLAG_LP64_ALIGN); + + if (filepath[0] == 0) + { + usage(argv[0]); + return 1; + } + + xml = acl_xml_alloc(); + if (cache_count > 0) + acl_xml_cache(xml, cache_count); + + fp = acl_vstream_fopen(filepath, O_RDONLY, 0600, 8192); + if (fp == NULL) + { + printf("open file %s error %s\r\n", + filepath, acl_last_serror()); + acl_xml_free(xml); + return 1; + } + + gettimeofday(&begin, NULL); + n = 0; + ACL_METER_TIME("------begin------"); + while (1) + { + ret = acl_vstream_fgets(fp, buf, sizeof(buf) - 1); + if (ret == ACL_VSTREAM_EOF) + break; + buf[ret] = 0; + acl_xml_parse(xml, buf); + if (++n % 10000 == 0) + { + printf("line: %d\r\n", n); + ACL_METER_TIME("-------ok------"); + } + if (n % cache_count == 0) + { + printf("reset xml, line: %d\r\n", n); + acl_xml_reset(xml); + } + } + + gettimeofday(&end, NULL); + spent = stamp_sub(&end, &begin); + printf("\r\ntotal spent: %0.2f ms\r\n", spent); + + acl_xml_free(xml); + acl_vstream_fclose(fp); + return 0; +} diff --git a/samples/zdb/Makefile b/samples/zdb/Makefile new file mode 100644 index 000000000..484749416 --- /dev/null +++ b/samples/zdb/Makefile @@ -0,0 +1,108 @@ +SHELL = /bin/sh +#CC = gcc +CC = g++ +AR = ar +ARFL = rv +RANLIB = ranlib + +CFLAGS = -c -g -W -Wcast-qual -Wcast-align \ +-Waggregate-return \ +-Wpointer-arith -Werror -Wshadow -O2 \ +-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO \ +-Wno-long-long +# -pedantic -Wall +# -Wmissing-prototypes +########################################################### +#Check system: +# Linux, SunOS, Solaris, BSD variants, AIX, HP-UX +SYSLIB = +CHECKSYSRES = @echo "Unknow system type!";exit 1 +UNIXNAME = $(shell uname -sm) + +ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes +endif + +# For FreeBSD +ifeq ($(findstring FreeBSD, $(UNIXNAME)), FreeBSD) + CFLAGS += -DFREEBSD -D_REENTRANT -pedantic + SYSLIB = -lcrypt -lpthread +endif + +# For Darwin +ifeq ($(findstring Darwin, $(UNIXNAME)), Darwin) + CFLAGS += -DFREEBSD -D_REENTRANT -pedantic -DMACOSX + SYSLIB = -lpthread +endif + +#Path for Linux +ifeq ($(findstring Linux, $(UNIXNAME)), Linux) + CFLAGS += -DLINUX2 + SYSLIB = -lcrypt -lpthread +endif + +#Path for SunOS +ifeq ($(findstring SunOS, $(UNIXNAME)), SunOS) + ifeq ($(findstring 86, $(UNIXNAME)), 86) + SYSLIB = -lsocket -lnsl -lrt + endif + ifeq ($(findstring sun4u, $(UNIXNAME)), sun4u) + SYSLIB = -lsocket -lnsl -lrt + endif + CFLAGS += -DSUNOS5 +endif + +#Path for HP-UX +ifeq ($(findstring HP-UX, $(UNIXNAME)), HP-UX) + SYSLIB = -lpthread + CFLAGS += -DHP_UX -DHPUX11 + PLAT_NAME=hp-ux +endif + +#Find system type. +ifneq ($(SYSPATH),) + CHECKSYSRES = @echo "System is $(shell uname -sm)" +endif +########################################################### + +LIB_BASE_PATH = ../../lib_acl +LIB_NAME_PATH = -L$(LIB_BASE_PATH)/lib +LIB_INCL_PATH = $(LIB_BASE_PATH)/include + +ALL_LIBS = -l_acl $(SYSLIB) + +BASE_PATH = . +INCLUDEDIR = $(BASE_PATH) +INCLUDE = -I$(INCLUDEDIR) -I$(LIB_INCL_PATH) +CFLAGS += $(INCLUDE) + +OUTPATH = ./ +OBJ_OUTPATH = $(OUTPATH) + +#Project's objs +SOURCES = $(wildcard *.c) +INCLUDES = $(wildcard *.h) +OBJS = $(patsubst %.c,$(OBJ_OUTPATH)%.o,$(SOURCES)) + +########################################################### + +PROG_NAME = zdb_test + +.PHONY = clean +COMPILE = $(CC) $(CFLAGS) + +all: RM $(PROG_NAME) + +RM: + rm -f $(PROG_NAME) + +$(PROG_NAME): $(OBJS) + $(CC) -o $(PROG_NAME) $(OBJS) $(LIB_NAME_PATH) $(ALL_LIBS) + +$(OBJ_OUTPATH)%.o: %.c *.h + $(COMPILE) -o $@ $< + +clean: + rm -f $(OBJS) $(PROG_NAME) + +rebuild: clean all diff --git a/samples/zdb/main.c b/samples/zdb/main.c new file mode 100644 index 000000000..5ccffee4c --- /dev/null +++ b/samples/zdb/main.c @@ -0,0 +1,16 @@ +#include "lib_acl.h" +#include "zdb_test.h" + +int main(int argc acl_unused, char *argv[] acl_unused) +{ + acl_mem_slice_init(8, 1024, 100000, + ACL_SLICE_FLAG_GC2 | + ACL_SLICE_FLAG_RTGC_OFF | + ACL_SLICE_FLAG_LP64_ALIGN); + if (argc == 2 && strncasecmp(argv[1], "zdb", 3) == 0) { + acl_msg_open("test.log", "zdb_test"); + zdb_test_main(argv[1]); + } else + zdb_test_main("zdb:help"); + return (0); +} diff --git a/samples/zdb/md5.c b/samples/zdb/md5.c new file mode 100644 index 000000000..b9931242d --- /dev/null +++ b/samples/zdb/md5.c @@ -0,0 +1,296 @@ + +/* MS VisualStudio Projects are monolithic, so we need the following + * #if to exclude the MD5 code from compile process when we are + * building the SSL support. + */ +#include +#include +#include "md5.h" +#include + +#ifdef WORDS_BIGENDIAN +void byteSwap(uint32_t * buf, unsigned words) +{ + uint8_t *p = (uint8_t *) buf; + + do { + *buf++ = (uint32_t) ((unsigned) p[3] << 8 | p[2]) << 16 | + ((unsigned) p[1] << 8 | p[0]); + p += 4; + } while (--words); +} +#else +#define byteSwap(buf,words) +#endif + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +void MD5Init(struct MD5Context *ctx) +{ + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bytes[0] = 0; + ctx->bytes[1] = 0; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void MD5Update(struct MD5Context *ctx, const void *_buf, unsigned len) +{ + const uint8_t *buf = (const uint8_t *) _buf; + uint32_t t; + + /* Update byte count */ + + t = ctx->bytes[0]; + if ((ctx->bytes[0] = t + len) < t) + ctx->bytes[1]++; /* Carry from low to high */ + + t = 64 - (t & 0x3f); /* Space available in ctx->in (at least 1) */ + if (t > len) { + memcpy((uint8_t *) ctx->in + 64 - t, buf, len); + return; + } + /* First chunk is an odd size */ + memcpy((uint8_t *) ctx->in + 64 - t, buf, t); + byteSwap(ctx->in, 16); + MD5Transform(ctx->buf, ctx->in); + buf += t; + len -= t; + + /* Process data in 64-byte chunks */ + while (len >= 64) { + memcpy(ctx->in, buf, 64); + byteSwap(ctx->in, 16); + MD5Transform(ctx->buf, ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + memcpy(ctx->in, buf, len); +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +void MD5Final(unsigned char digest[16], struct MD5Context *ctx) +{ + int count = ctx->bytes[0] & 0x3f; /* Number of bytes in ctx->in */ + uint8_t *p = (uint8_t *) ctx->in + count; + + /* Set the first char of padding to 0x80. There is always room. */ + *p++ = 0x80; + + /* Bytes of padding needed to make 56 bytes (-8..55) */ + count = 56 - 1 - count; + + if (count < 0) { /* Padding forces an extra block */ + memset(p, 0, count + 8); + byteSwap(ctx->in, 16); + MD5Transform(ctx->buf, ctx->in); + p = (uint8_t *) ctx->in; + count = 56; + } + memset(p, 0, count); + byteSwap(ctx->in, 14); + + /* Append length in bits and transform */ + ctx->in[14] = ctx->bytes[0] << 3; + ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29; + MD5Transform(ctx->buf, ctx->in); + + byteSwap(ctx->buf, 4); + memcpy(digest, ctx->buf, 16); + memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ +} + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f,w,x,y,z,in,s) \ + (w += f(x,y,z) + in, w = (w<>(32-s)) + x) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +void MD5Transform(uint32_t buf[4], uint32_t const in[16]) +{ + register uint32_t a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +const char* MD5Key(const char *s, size_t s_len, const char *k, size_t k_len, void* buf, size_t b_len) +{ + MD5_CTX context; + unsigned char digest[16]; + + if (b_len != 16) { + printf("b_len(%d) != 16\n", (int) b_len); + assert(0); + } + + MD5Init(&context); + if (k != NULL && k_len > 0) + MD5Update(&context, (const unsigned char *) k, (unsigned int) k_len); + MD5Update(&context, (const unsigned char*) s, (unsigned int) s_len); + MD5Final(digest, &context); + memcpy(buf, digest, b_len); + return ((const char*) buf); +} + +const char* MD5String(const char *s, const char *k, size_t k_len, char* buf, size_t size) +{ + MD5_CTX context; + unsigned char digest[16]; + char output1[34], *ptr; + unsigned int len = (unsigned int) strlen(s); + size_t i, n; + + MD5Init(&context); + if (k != NULL && k_len > 0) + MD5Update(&context, (const unsigned char *) k, (unsigned int) k_len); + MD5Update(&context, (const unsigned char*) s, (unsigned int) len); + MD5Final(digest, &context); + + for (i = 0; i < 16; i++) { + sprintf(&(output1[2 * i]), "%02x", (unsigned char) digest[i]); + sprintf(&(output1[2 * i + 1]), "%02x", (unsigned char) (digest[i] << 4)); + } + + ptr = buf; + size--; /* left one byte for '\0' */ + n = size > 32 ? 32 : size; + + for(i = 0; i < n; i++) + *ptr++ = output1[i]; + *ptr = '\0'; + + return (buf); +} + +const char* MD5Key2String(const unsigned char *s, size_t s_len, char* buf, size_t size) +{ + size_t i, n; + char output1[34], *ptr; + unsigned char digest[16]; + + if (s_len != 16) { + printf("s_len(%d) != 16\n", (int) s_len); + assert(0); + } + if (size < 32) { + printf("size(%d) < 32\n", (int) size); + assert(0); + } + memcpy(digest, s, 16); + + for (i = 0; i < 16; i++) { + sprintf(&(output1[2 * i]), "%02x", (unsigned char) digest[i]); + sprintf(&(output1[2 * i + 1]), "%02x", (unsigned char) (digest[i] << 4)); + } + + ptr = buf; + size--; /* left one byte for '\0' */ + n = size > 32 ? 32 : size; + + for(i = 0; i < n; i++) + *ptr++ = output1[i]; + *ptr = '\0'; + + return (buf); +} + diff --git a/samples/zdb/md5.h b/samples/zdb/md5.h new file mode 100644 index 000000000..67b8f26a3 --- /dev/null +++ b/samples/zdb/md5.h @@ -0,0 +1,26 @@ +#ifndef SQUID_MD5_H +#define SQUID_MD5_H + +#include + +typedef unsigned int uint32_t; +typedef unsigned char uint8_t; + +typedef struct MD5Context { + uint32_t buf[4]; + uint32_t bytes[2]; + uint32_t in[16]; +} MD5_CTX; + + +void MD5Init(struct MD5Context *context); +void MD5Update(struct MD5Context *context, const void *buf, unsigned len); +void MD5Final(uint8_t digest[16], struct MD5Context *context); +void MD5Transform(uint32_t buf[4], uint32_t const in[16]); +const char* MD5Key(const char *s, size_t s_len, const char *k, size_t k_len, void* buf, size_t b_len); +const char* MD5String(const char *s, const char *k, size_t k_len, char* buf, size_t size); +const char* MD5Key2String(const unsigned char *s, size_t s_len, char* buf, size_t size); + +#define MD5_DIGEST_CHARS 16 + +#endif /* SQUID_MD5_H */ diff --git a/samples/zdb/var/.test.disk b/samples/zdb/var/.test.disk new file mode 100644 index 000000000..3f28c0e96 --- /dev/null +++ b/samples/zdb/var/.test.disk @@ -0,0 +1,2 @@ +./var/dat0|0|1|100000000|150001 +./var/dat1|1|1|100000000|150000 diff --git a/samples/zdb/zdb.vcproj b/samples/zdb/zdb.vcproj new file mode 100644 index 000000000..65b0cc1b1 --- /dev/null +++ b/samples/zdb/zdb.vcproj @@ -0,0 +1,248 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/zdb/zdb.vcxproj b/samples/zdb/zdb.vcxproj new file mode 100644 index 000000000..2250a4c18 --- /dev/null +++ b/samples/zdb/zdb.vcxproj @@ -0,0 +1,189 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + ReleaseDll + Win32 + + + Release + Win32 + + + + {640ABB35-FBD3-4D34-A382-9ED8CF3FCE34} + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)zdb.exe + %(AdditionalLibraryDirectories) + true + $(OutDir)zdb.pdb + Console + MachineX86 + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;%(AdditionalDependencies) + $(OutDir)zdb.exe + true + Console + true + true + MachineX86 + + + + + Disabled + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + EditAndContinue + + + ws2_32.lib;%(AdditionalDependencies) + $(OutDir)zdb.exe + %(AdditionalLibraryDirectories) + true + $(OutDir)zdb.pdb + Console + MachineX86 + + + + + ..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + ws2_32.lib;wsock32.lib;%(AdditionalDependencies) + $(OutDir)zdb.exe + true + Console + true + true + MachineX86 + + + + + {b40213c2-507c-4c7f-a6e1-b850c9bdc27b} + false + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/zdb/zdb_test.c b/samples/zdb/zdb_test.c new file mode 100644 index 000000000..e6762a9d8 --- /dev/null +++ b/samples/zdb/zdb_test.c @@ -0,0 +1,787 @@ +#include "lib_acl.h" +#ifndef WIN32 +#include +#include +#endif +#include "db/zdb.h" +#include "zdb_test.h" +#include "md5.h" + +#pragma pack(4) +typedef struct { + int n; + char s[4]; +} DUMMY; +#pragma pack(8) + +#ifndef STORE_PATH +#define STORE_PATH(s) ACL_FHANDLE_PATH(&(s)->fhandle) +#endif + +struct RANGE { + int from; + int to; +}; + +#ifdef WIN32 +#define snprintf _snprintf +#endif + +/****************************************************************************/ + +static const char *var_md5_key = "hello world!"; +static const char *var_str = "hi!"; + +/* 模拟取得一个随机的整形数组 */ + +#ifndef WIN32 + +static int *random_get(int max, int mod) +{ + int *a = (int*) acl_mymalloc(sizeof(int) * max); + int n = 1; + + if (mod > 1) { + max /= mod; + mod--; + } else + mod = 0; + + for (int i = 0; i < max; i++) + a[i] = i + mod; + + printf("shuffle: %d\n", n++); + std::random_shuffle(a, a + max); + + printf("shuffle: %d\n", n++); + std::random_shuffle(a, a + max); + + printf("shuffle: %d\n", n++); + std::random_shuffle(a, a + max); + + printf("shuffle: %d\n", n++); + std::random_shuffle(a, a + max); + + return (a); +} + +#else +static int *random_get(int max, int mod) +{ + int i, j, k, *a, key, off = 0; + char buf[64], key_buf[16]; + int m = 0; + + /* 先分配一个大数组 */ + a = (int*) acl_mymalloc(sizeof(int) * max); + + /* 初始化该大数组 */ + memset(a, -1, sizeof(int) * max); + + printf("begin: max: %d\n", max); + + for (i = 0; i < max; i++) { + snprintf(buf, sizeof(buf), "key: %d", i); + + /* 先 mda5 */ + MD5Key(buf, strlen(buf), var_md5_key, strlen(var_md5_key), + key_buf, sizeof(key_buf)); + + /* 再取模 */ + key = acl_hash_crc32(key_buf, sizeof(key_buf)) % max; + if (a[key] == -1) { + a[key] = i; + continue; + } + + acl_assert(a[key] != i); + +// printf("key: %d, %d\n", i, a[key]); + + m++; + + /* 说明该 key 的数组下标已经被占用,需要顺序找一个位置即可 */ + for (j = off; j < max; j++) { + if (a[j] == -1) { + a[j] = i; + for (k = j + 1; k < max; k++) { + if (a[k] == -1) { + off = k; + break; + } + } + break; + } + } + acl_assert(j != max); + } + + printf("end, m: %d\n", m); + return (a); +} +#endif + +static void random_free(int *a) +{ + acl_myfree(a); +} + +/* 随机批量写 */ + +static int bench_random_add(ZDB *db, int max, int mod) +{ + DUMMY dummy; + int i, ret, *a; + time_t begin; + + ACL_SAFE_STRNCPY(dummy.s, var_str, sizeof(dummy.s)); + + a = random_get(max, mod); + + if (mod > 1) + max /= mod; + + time(&begin); + + printf("---range_random_add: >> max: %d, ", max); + ACL_METER_TIME(" "); + + for (i = 0; i < max; i++) { + dummy.n = i; + ret = zdb_update(db, a[i], NULL, &dummy, sizeof(dummy)); + if (ret < 0) { + printf("zdb_udpate error, i: %d, key: %d\n", i, a[i]); + random_free(a); + return (-1); + } + if (i > 0 && i % 100000 == 0) { + printf("---%s: >> current: i: %d, key: %d, ", + __FUNCTION__, i, a[i]); + ACL_METER_TIME(" "); + } + } + + printf("---range_add: >> end: current: %d, max: %d, ", i, max); + ACL_METER_TIME(" "); + + printf("================= update ok, time: %ld ===============\n", + time(NULL) - begin); + + random_free(a); + return (max); +} + +/* 随机批量读 */ + +static int bench_random_get(ZDB *db, int max, int mod) +{ + DUMMY *dummy; + int i, *a; + size_t size; + ZDB_BLK *blk; + ZDB_BLK_OFF blk_off; + time_t begin; + char buf[64]; + + a = random_get(max, mod); + + if (mod > 1) + max /= mod; + + time(&begin); + + printf("---range_random_get: >> begin: max: %d, ", max); + ACL_METER_TIME(" "); + + for (i = 0; i < max; i++) { + snprintf(buf, sizeof(buf), "key: %d", i); + blk = zdb_lookup(db, a[i], &size, &blk_off); + if (blk == NULL) { + printf("zdb_lookup error, i: %d\n", i); + random_free(a); + return (-1); + } + dummy = (DUMMY*) zdb_blk_data(blk); + if (i > 0 && i % 100000 == 0) { + printf("---%s: >> current: i: %d, n: %d," + " key: %d, blk_off: %lld, ", __FUNCTION__, + i, dummy->n, a[i], blk_off.offset); + ACL_METER_TIME(" "); + } + zdb_blk_free(blk); + } + + printf("---range_get: >> end: current: %d, max: %d, ", i, max); + ACL_METER_TIME(" "); + + printf("================= lookup ok, time: %ld ===============\n", + time(NULL) - begin); + + random_free(a); + return (max); +} + +/****************************************************************************/ + +/* 顺序批量写 */ + +static int bench_add(ZDB *db, int max) +{ + time_t begin; + int i, ret, delta = 100000; + DUMMY dummy; + + if (max <= 100) + delta = 0; + time(&begin); + + ACL_SAFE_STRNCPY(dummy.s, var_str, sizeof(dummy.s)); + + ACL_METER_TIME("----begin---"); + for (i = 0; i < max; i++) { + dummy.n = i; + ret = zdb_update(db, i, NULL, &dummy, sizeof(dummy)); + if (ret < 0) { + printf("zdb_udpate error, i: %d\n", i); + return (-1); + } + if (delta > 0 && i % delta == 0) { + printf("---%s: i: %d, ", __FUNCTION__, i); + ACL_METER_TIME("-----"); + } else if (delta == 0) + printf("---%s: i: %d\n", __FUNCTION__, i); + } + printf("---%s: max: %d, ", __FUNCTION__, max); + ACL_METER_TIME("----end---"); + + printf("================= add ok, time: %ld ===============\n", + time(NULL) - begin); + + return (max); +} + +/* 顺序批量修改 */ + +static int bench_update(ZDB *db, int max, int num) +{ + time_t begin; + int i, ret, j, delta = 100000; + DUMMY *dummy; + + if (max <= 100) + delta = 0; + + time(&begin); + + dummy = (DUMMY*) acl_mycalloc(num, sizeof(DUMMY)); + for (i = 0; i < num; i++) { + snprintf(dummy[i].s, sizeof(dummy[i].s), "%d", i); + } + + ACL_METER_TIME("----begin---"); + for (i = 0; i < max; i++) { + for (j = 0; j < num; j++) + dummy[j].n = 0; + ret = zdb_update(db, i, NULL, dummy, num * sizeof(DUMMY)); + if (ret < 0) { + printf("zdb_udpate error, i: %d\n", i); + return (-1); + } + if (delta > 0 && i % delta == 0) { + printf("---%s: i: %d, ", __FUNCTION__, i); + ACL_METER_TIME("-----"); + } else if (delta == 0) + printf("---%s: i: %d\n", __FUNCTION__, i); + } + printf("---%s: max: %d, ", __FUNCTION__, max); + ACL_METER_TIME("----end---"); + + printf("================= update ok, time: %ld ===============\n", + time(NULL) - begin); + + acl_myfree(dummy); + + return (max); +} + +/* 顺序批量读 */ + +static int bench_get(ZDB *db, int max) +{ + ZDB_BLK *blk; + DUMMY *dummy; + time_t begin; + size_t size; + int i, delta = 100000; + ZDB_BLK_OFF blk_off; + + if (max <= 100) + delta = 0; + + printf(">> max: %d, delta: %d\n", max, delta); + time(&begin); + ACL_METER_TIME("----begin---"); + + //for (i = 0; i < max; i++) { + for (i = max - 1; i >= 0; i--) { + blk = zdb_lookup(db, i, &size, &blk_off); + if (blk == NULL) { + printf("zdb_lookup error, i: %d\n", i); + return (-1); + } + + dummy = (DUMMY*) zdb_blk_data(blk); + if (delta == 0) + printf("---%s: i: %d, n: %d, %s, size: %d," + " blk_off: %lld, \n", __FUNCTION__, + i, dummy[0].n, dummy[0].s, + (int) size, blk_off.offset); + else if (delta > 0 && i % delta == 0) { + printf("---%s: i: %d, n: %d, %s, size: %d," + " blk_off: %lld, ", __FUNCTION__, + i, dummy[0].n, dummy[0].s, + (int) size, blk_off.offset); + ACL_METER_TIME(""); + } + + zdb_blk_free(blk); + } + printf("---%s: max: %d, ", __FUNCTION__, max); + ACL_METER_TIME("----end---"); + + printf("================= lookup ok, time: %ld ===============\n", + time(NULL) - begin); + return (max); +} + +/****************************************************************************/ + +static int zdb_test1(ZDB *db) +{ + DUMMY dummy[2], *pdummy; + ZDB_BLK *blk; + size_t size; + zdb_key_t key = 10000; + int ret, i; + + dummy[0].n = (int) key; + ACL_SAFE_STRNCPY(dummy[0].s, var_str, sizeof(dummy[0].s)); + dummy[1].n = (int) key + 1; + ACL_SAFE_STRNCPY(dummy[1].s, var_str, sizeof(dummy[1].s)); + + printf(">>> first update, key: %lld, ", key); + ret = zdb_update(db, key, NULL, &dummy, sizeof(dummy) / 2); + printf("zdb_update: return %d\n\n", ret); + + printf(">>> second update, key: %lld, ", key); + ret = zdb_update(db, key, NULL, &dummy, sizeof(dummy) / 2); + + blk = zdb_lookup(db, key, &size, NULL); + if (blk) { + printf("zdb_lookup: key(%lld), size: %u\n", key, (unsigned) size); + + pdummy = (DUMMY*) zdb_blk_data(blk); + for (i = 0; i < (int) (size / sizeof(DUMMY)); i++) { + printf("zdb_lookup: n: %d, s: %s\n", pdummy->n, pdummy->s); + pdummy++; + } + zdb_blk_free(blk); + } else + printf("zdb_lookup: key(%lld), return null\n", key); + + printf(">>> third update, key: %lld\n", key); + ret = zdb_update(db, key, NULL, &dummy, sizeof(dummy) / 2); + + return (ret); +} + +static int zdb_test2(ZDB *db) +{ + DUMMY dummy1[1], dummy2[2], dummy3[3], *pdummy; + ZDB_BLK *blk; + int key = 100, ret; + size_t size, i; + + dummy1[0].n = key; + ACL_SAFE_STRNCPY(dummy1[0].s, "1: hello world!", sizeof(dummy1[0].s)); + + dummy2[0].n = key; + ACL_SAFE_STRNCPY(dummy2[0].s, "2: hello world!", sizeof(dummy2[0].s)); + dummy2[1].n = key; + ACL_SAFE_STRNCPY(dummy2[1].s, "2: hello world!", sizeof(dummy2[1].s)); + + dummy3[0].n = key; + ACL_SAFE_STRNCPY(dummy3[0].s, "3: hello world!", sizeof(dummy3[0].s)); + dummy3[1].n = key; + ACL_SAFE_STRNCPY(dummy3[1].s, "3: hello world!", sizeof(dummy3[1].s)); + dummy3[2].n = key; + ACL_SAFE_STRNCPY(dummy3[2].s, "3: hello world!", sizeof(dummy3[2].s)); + + ret = zdb_update(db, key, NULL, &dummy1, sizeof(dummy1)); + if (ret < 0) { + printf("zdb_update: set dummy1 error\n"); + return (-1); + } + blk = zdb_lookup(db, key, &size, NULL); + if (blk == NULL) { + printf("zdb_lookup: get dummy1 error\n"); + return (-1); + } + pdummy = (DUMMY*) zdb_blk_data(blk); + for (i = 0; i < sizeof(dummy1) / sizeof(DUMMY); i++) { + printf("dummy1: key: %d, n: %d, s: %s\n", key, pdummy->n, pdummy->s); + pdummy++; + } + zdb_blk_free(blk); + + ret = zdb_update(db, key, NULL, &dummy2, sizeof(dummy2)); + if (ret < 0) { + printf("zdb_update: set dummy2 error\n"); + return (-1); + } + blk = zdb_lookup(db, key, &size, NULL); + if (blk == NULL) { + printf("zdb_lookup: get dummy2 error\n"); + return (-1); + } + pdummy = (DUMMY*) zdb_blk_data(blk); + for (i = 0; i < sizeof(dummy2) / sizeof(DUMMY); i++) { + printf("dummy2: key: %d, n: %d, s: %s\n", key, pdummy->n, pdummy->s); + pdummy++; + } + zdb_blk_free(blk); + + ret = zdb_update(db, key, NULL, &dummy3, sizeof(dummy3)); + if (ret < 0) { + printf("zdb_update: set dummy3 error\n"); + return (-1); + } + blk = zdb_lookup(db, key, &size, NULL); + if (blk == NULL) { + printf("zdb_lookup: get dummy3 error\n"); + return (-1); + } + pdummy = (DUMMY*) zdb_blk_data(blk); + for (i = 0; i < sizeof(dummy3) / sizeof(DUMMY); i++) { + printf("dummy3: key: %d, n: %d, s: %s\n", key, pdummy->n, pdummy->s); + pdummy++; + } + zdb_blk_free(blk); + + return (3); +} + +static int key_walk_fn(ZDB_KEY_STORE *store) +{ + const char *myname = "key_walk_fn"; + ACL_ITER iter; + ZDB_BLK_OFF *blk_off; + int i = 0; + + printf(">>> acl_foreach for %s now:\n", STORE_PATH((ZDB_STORE*) store)); + acl_foreach(iter, (ZDB_STORE*) store) { + blk_off = (ZDB_BLK_OFF*) iter.data; + if (i > 0 && (i % 100000) == 0) { + printf("%s: i:%d, key: %d, blk_off: %lld, inode: %d, ", + myname, i, iter.i, blk_off->offset, blk_off->inode); + ACL_METER_TIME("-"); + } + i++; + } + return (i); +} + +static int test_zdb_key_walk(ZDB *db) +{ + const char *myname = "test_zdb_key_walk"; + int ret; + time_t begin; + + time(&begin); + ret = zdb_key_walk(db, key_walk_fn); + printf(">>>%s, acl_foreach for key, total: %d, time: %ld\n", + myname, ret, time(NULL) - begin); + return (0); +} + +static int dat_walk_fn(ZDB_DAT_STORE *store) +{ + const char *myname = "dat_walk_fn"; + int i = 0; + ZDB_BLK *blk; + DUMMY *dummy; + ACL_ITER iter; + + printf(">>>%s, acl_foreach for %s now:\n", myname, STORE_PATH((ZDB_STORE*) store)); + + acl_foreach(iter, (ZDB_STORE*) store) { + blk = (ZDB_BLK*) iter.data; + dummy = (DUMMY*) zdb_blk_data(blk); + if (i > 0 && (i % 100000) == 0) { + printf("%s: i:%d,key:%lld,data:%s,inext:%d,", + myname, i, blk->hdr.key, dummy->s, iter.i); + ACL_METER_TIME("-"); + } else if (store->hdr.count <= 100) { + printf("%s: i:%d, key:%lld, data:%s, inext:%d\n", + myname, i, blk->hdr.key, dummy->s, iter.i); + } + i++; + } + + return (i); +} + +static int test_zdb_dat_walk(ZDB *db) +{ + const char *myname = "test_zdb_dat_walk"; + time_t begin; + int ret; + + time(&begin); + ret = zdb_dat_walk(db, dat_walk_fn); + printf(">>>%s, acl_foreach for dat, total: %d, time: %ld\n", + myname, ret, time(NULL) - begin); + return (ret); +} + +static int dat_stat_fn(ZDB_DAT_STORE *store) +{ + const char *myname = "dat_stat_fn"; + ZDB_DAT_HDR hdr; + + memcpy(&hdr, &store->hdr, sizeof(ZDB_DAT_HDR)); + + printf("%s(%d): %s's hdr status\n", + myname, __LINE__, STORE_PATH((ZDB_STORE*) store)); + printf("%s(%d):\tlimit: %lld, size: %lld, used count: %lld\n", + myname, __LINE__, hdr.limit, hdr.size, hdr.count); + printf("%s(%d):\tnstep: %d, blk_hdr_dlen: %d, blk_dlen: %d," + " blk_count: %d\n", myname, __LINE__, hdr.nstep, + hdr.blk_hdr_dlen, hdr.blk_dlen, hdr.blk_count); + printf("%s(%d):\tihead_idle: %d, ihead_busy: %d\n", + myname, __LINE__, hdr.ihead_idle, hdr.ihead_busy); + + return (0); +} + +static int test_zdb_dat_stat(ZDB *db) +{ + return (zdb_dat_walk(db, dat_stat_fn)); +} + +static int key_stat_fn(ZDB_KEY_STORE *store) +{ + const char *myname = "key_stat_fn"; + ZDB_KEY_HDR key_hdr; + + memcpy(&key_hdr, &store->hdr, sizeof(ZDB_KEY_HDR)); + + printf(">> %s: %s's status:\n", myname, STORE_PATH((ZDB_STORE*) store)); + printf(">>\tkey_limit: %lld, key_count: %lld, key_begin: %lld\n", + key_hdr.key_limit, key_hdr.key_count, key_hdr.key_begin); + + return (0); +} + +static int test_zdb_key_stat(ZDB *db) +{ + return (zdb_key_walk(db, key_stat_fn)); +} + +static int dat_check_fn(ZDB_DAT_STORE *store) +{ + return (zdb_dat_check(store, NULL)); +} + +static int test_zdb_dat_check(ZDB *db) +{ + return (zdb_dat_walk(db, dat_check_fn)); +} + +static int key_check_fn(ZDB_KEY_STORE *store) +{ + return (zdb_key_check(store, NULL)); +} + +static int test_zdb_key_check(ZDB *db) +{ + return (zdb_key_walk(db, key_check_fn)); +} + +void zdb_test_main(const char *cmd) +{ + const char *myname = "zdb_test"; + ZDB *db; + const char *dbname = "test", *key_path = "./var"; + + /*ZDB_FLAG_CACHE_DAT | ZDB_FLAG_CACHE_KEY | ZDB_FLAG_SLICE_KEY | ZDB_FLAG_SLICE_DAT;*/ + unsigned int oflags = 0; + + ZDB_CFG zdb_cfg; + zdb_key_t key_begin = 0, key_limit = 1000000, dat_limit = 10000000, blk_dlen = sizeof(DUMMY); + int ret, max = 10000000, use_random = 0, walk_all = 0, dat_nstep = 1000, mod = 1; + int cache_key_limit = 0, cache_key_timeout = 0; + int cmd_add = 0, cmd_get = 0, cmd_update = 0, update_num = 2; + int cmd_stat = 0, cmd_check = 0; + ACL_ARGV *argv = acl_argv_split(cmd, ":"); + ACL_ITER iter; + char *name, *value, *ptr; + char usage[] = "help:stat:check:link:random:walk:add:get:update={d}" + ":max={d}:key_limit={d}:dat_limit={d}:nstep={d}:mod={d}:cache_key_limit={d}" + ":cache_key_timeout={d}"; + + acl_make_dirs(key_path, 0700); + + acl_foreach(iter, argv) { + name = ptr = (char*) iter.data; + if (strcasecmp(name, "help") == 0) { + printf("usage: %s\n", usage); + acl_argv_free(argv); + return; + } else if (strcasecmp(name, "stat") == 0) { + cmd_stat = 1; + continue; + } else if (strcasecmp(name, "check") == 0) { + cmd_check = 1; + continue; + } else if (strcasecmp(name, "link") == 0) { + oflags |= ZDB_FLAG_LINK_BUSY; + continue; + } else if (strcasecmp(name, "random") == 0) { + use_random = 1; + continue; + } else if (strcasecmp(name, "walk") == 0) { + walk_all = 1; + continue; + } else if (strcasecmp(name, "add") == 0) { + cmd_add = 1; + continue; + } else if (strcasecmp(name, "get") == 0) { + cmd_get = 1; + continue; + } + + name = acl_mystrtok(&ptr, "="); + if (name == NULL) + continue; + value = acl_mystrtok(&ptr, "="); + if (value == NULL) + continue; + if (strcasecmp(name, "max") == 0) { + ret = atoi(value); + if (ret > 0) + max = ret; + } else if (strcasecmp(name, "key_limit") == 0) { + ret = atoi(value); + if (ret > 0) + key_limit = ret; + } else if (strcasecmp(name, "dat_limit") == 0) { + ret = atoi(value); + if (ret > 0) + dat_limit = ret; + } else if (strcasecmp(name, "update") == 0) { + ret = atoi(value); + if (ret > 0) { + update_num = ret; + cmd_update = 1; + } + } else if (strcasecmp(name, "nstep") == 0) { + ret = atoi(value); + if (ret > 0) + dat_nstep = ret; + } else if (strcasecmp(name, "mod") == 0) { + ret = atoi(value); + if (ret > 0) + mod = ret; + } else if (strcasecmp(name, "cache_key_limit") == 0) { + ret = atoi(value); + if (ret > 0) + cache_key_limit = ret; + } else if (strcasecmp(name, "cache_key_timeout") == 0) { + ret = atoi(value); + if (ret > 0) + cache_key_timeout = ret; + } + } + + acl_argv_free(argv); + + memset(&zdb_cfg, 0, sizeof(zdb_cfg)); + + /* 初始化 ZDB 存储引擎 */ + zdb_init(); + + /* 开始配置 ZDB 配置对象 */ + zdb_cfg.key_path = key_path; + zdb_cfg.key_begin = key_begin; + zdb_cfg.key_limit = key_limit; + zdb_cfg.dat_limit = dat_limit; + zdb_cfg.blk_dlen = (int) blk_dlen; + zdb_cfg.dat_nstep = dat_nstep; /* 值存储文件每次增加的数据块个数 */ + if (cache_key_limit > 0 && cache_key_timeout > 0) { + zdb_cfg.key_cache_max = cache_key_limit * 2; + zdb_cfg.key_cache_timeout = cache_key_timeout; + zdb_cfg.key_wback_max = cache_key_limit; + oflags |= ZDB_FLAG_CACHE_KEY | ZDB_FLAG_SLICE_KEY; + printf("===========open key\n"); + } else { + zdb_cfg.key_cache_max = 0; + zdb_cfg.key_cache_timeout = 0; + zdb_cfg.key_wback_max = 0; + } + zdb_cfg.dat_cache_max = 0; + zdb_cfg.dat_cache_timeout = 0; + zdb_cfg.dat_wback_max = 0; + + /* 打开一个 ZDB 数据库对象 */ + db = zdb_open(dbname, oflags, &zdb_cfg); + if (db == NULL) + acl_msg_fatal("%s: zdb open error(%s)", myname, acl_last_serror()); + + printf("DUMMY.sizeof: %d\n", (int) sizeof(DUMMY)); + + if (0) { + ret = zdb_test1(db); + if (ret > 0) + ret = zdb_test2(db); + } else + ret = 1; + + if (!use_random) { + if (ret > 0 && cmd_add) + ret = bench_add(db, max); + if (ret > 0 && cmd_get) + ret = bench_get(db, max); + if (ret > 0 && cmd_update) + ret = bench_update(db, max, update_num); + } else { + if (ret > 0 && cmd_add) + ret = bench_random_add(db, max, mod); + if (ret > 0 && cmd_get) + ret = bench_random_get(db, max, mod); + } + + if (walk_all) { + if (ret > 0) + ret = test_zdb_dat_walk(db); + if (ret >= 0) + ret = test_zdb_key_walk(db); + } + + if (cmd_stat) { + if (ret >= 0) + ret = test_zdb_dat_stat(db); + if (ret >= 0) + ret = test_zdb_key_stat(db); + } + + if (cmd_check) { + if (ret >= 0) + ret = test_zdb_dat_check(db); + if (ret >= 0) + ret = test_zdb_key_check(db); + } + + zdb_close(db); + zdb_end(); +} diff --git a/samples/zdb/zdb_test.h b/samples/zdb/zdb_test.h new file mode 100644 index 000000000..8d60fead3 --- /dev/null +++ b/samples/zdb/zdb_test.h @@ -0,0 +1,13 @@ +#ifndef __ZDB_TEST_INCLUDE_H__ +#define __ZDB_TEST_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +void zdb_test_main(const char *cmd); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/unit_test/Makefile b/unit_test/Makefile new file mode 100644 index 000000000..dfb5eb0c7 --- /dev/null +++ b/unit_test/Makefile @@ -0,0 +1,137 @@ +SHELL = /bin/sh +CC = gcc +#CC = g++ +#CC = ${MY_ENV_CC} +AR = ar +ARFL = rv +#ARFL = cru +RANLIB = ranlib + +CFLAGS = -c -g -W -Wall -Wcast-qual -Wcast-align \ +-Waggregate-return -Wmissing-prototypes \ +-Wpointer-arith -Werror -Wshadow -O2 \ +-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO \ +-Wno-long-long + +########################################################### +#Check system: +# Linux, SunOS, Solaris, BSD variants, AIX, HP-UX +SYSLIB = -lpthread +CHECKSYSRES = @echo "Unknow system type!";exit 1 +UNIXNAME = $(shell uname -sm) + +ifeq ($(CC),) + CC = gcc +endif + +# For FreeBSD +ifeq ($(findstring FreeBSD, $(UNIXNAME)), FreeBSD) + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DFREEBSD -D_REENTRANT -pedantic + SYSLIB = -lcrypt -lpthread +endif + +#Path for Linux +ifeq ($(findstring Linux, $(UNIXNAME)), Linux) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DLINUX2 -D_REENTRANT -pedantic +endif + +#Path for SunOS +ifeq ($(findstring SunOS, $(UNIXNAME)), SunOS) + ifeq ($(findstring 86, $(UNIXNAME)), 86) + SYSLIB = -lsocket -lnsl -lrt + endif + ifeq ($(findstring sun4u, $(UNIXNAME)), sun4u) + SYSLIB = -lsocket -lnsl -lrt + endif + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DSUNOS5 -D_REENTRANT -pedantic +endif + +#Path for HP-UX +ifeq ($(findstring HP-UX, $(UNIXNAME)), HP-UX) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DHP_UX -DHPUX11 + PLAT_NAME=hp-ux +endif + +#Find system type. +ifneq ($(SYSPATH),) + CHECKSYSRES = @echo "System is $(shell uname -sm)" +endif +########################################################### +ACL_HOME = ../lib_acl +ACL_INC_PATH = $(ACL_HOME)/include +ACL_LIB_PATH = $(ACL_HOME)/lib + +CFLAGS += -I$(ACL_INC_PATH) + +LINK_LIBS = -L$(ACL_LIB_PATH) -l_acl $(SYSLIB) + +########################################################### +OUT_PATH = . +OBJ_PATH_DST = $(OUT_PATH)/debug +PROG_PATH_DST = $(OUT_PATH)/bin + +BASE_PATH = . +SRC_PATH_SRC = $(BASE_PATH) + +INC_COMPILE = -I. -I./stdlib -I./net -I./unit_test +CFLAGS += $(INC_COMPILE) + +#Project's source +BASE_SRC = $(wildcard *.c) +STDLIB_SRC = $(wildcard $(SRC_PATH_SRC)/stdlib/*.c) +UNIT_TEST_SRC = $(wildcard $(SRC_PATH_SRC)/unit_test/*.c) +NET_SRC = $(wildcard $(SRC_PATH_SRC)/net/*.c) +SOURCES_SRC = $(BASE_SRC) $(STDLIB_SRC) $(UNIT_TEST_SRC) $(NET_SRC) + +#Project's obj +OBJS_DST = $(patsubst %.c, $(OBJ_PATH_DST)/%.o, $(notdir $(SOURCES_SRC))) + +########################################################### +.PHONY = all clean myecho + +PROG_NAME = test_main + +COMPILE = $(CC) $(CFLAGS) +LINK = $(CC) -o $(PROG_PATH_DST)/$(PROG_NAME) $(OBJS_DST) $(LINK_LIBS) + +all: $(PROG_NAME) + +$(PROG_NAME): $(OBJS_DST) + $(LINK) + +$(OBJ_PATH_DST)/%.o: %.c *.h + $(COMPILE) $< -o $@ + +$(OBJ_PATH_DST)/%.o: stdlib/%.c stdlib/*.h + $(COMPILE) $< -o $@ + +$(OBJ_PATH_DST)/%.o: unit_test/%.c unit_test/*.h + $(COMPILE) $< -o $@ + +$(OBJ_PATH_DST)/%.o: net/%.c net/*.h + $(COMPILE) $< -o $@ + +clean: + rm -f $(PROG_PATH_DST)/$(PROG_NAME) + rm -f $(OBJS_DST) + +myecho: + @(echo "STDLIB_SRC: $(STDLIB_SRC)") + @(echo "UNIT_TEST_SRC: $(UNIT_TEST_SRC)") + @(echo "SOURCES_SRC: $(SOURCES_SRC)") + @(echo "OBJS_DST: $(OBJS_DST)") + @(echo "OBJ_PATH_DST: $(OBJ_PATH_DST)") + + diff --git a/unit_test/Makefile.glib b/unit_test/Makefile.glib new file mode 100644 index 000000000..eb0b2099d --- /dev/null +++ b/unit_test/Makefile.glib @@ -0,0 +1,138 @@ +SHELL = /bin/sh +CC = gcc +#CC = g++ +#CC = ${MY_ENV_CC} +AR = ar +ARFL = rv +#ARFL = cru +RANLIB = ranlib + +CFLAGS = -c -g -W -Wall -Wcast-qual -Wcast-align \ +-Waggregate-return -Wmissing-prototypes \ +-Wpointer-arith -Werror -Wshadow -O2 \ +-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -D_USE_FAST_MACRO \ +-Wno-long-long + +########################################################### +#Check system: +# Linux, SunOS, Solaris, BSD variants, AIX, HP-UX +SYSLIB = -lpthread +CHECKSYSRES = @echo "Unknow system type!";exit 1 +UNIXNAME = $(shell uname -sm) + +ifeq ($(CC),) + CC = gcc +endif + +# For FreeBSD +ifeq ($(findstring FreeBSD, $(UNIXNAME)), FreeBSD) + ifeq ($(findstring gcc, $(CC)), gcc) + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DFREEBSD -D_REENTRANT -pedantic + SYSLIB = -lcrypt -lpthread +endif + +#Path for Linux +ifeq ($(findstring Linux, $(UNIXNAME)), Linux) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DLINUX2 -D_REENTRANT -pedantic +endif + +#Path for SunOS +ifeq ($(findstring SunOS, $(UNIXNAME)), SunOS) + ifeq ($(findstring 86, $(UNIXNAME)), 86) + SYSLIB = -lsocket -lnsl -lrt + endif + ifeq ($(findstring sun4u, $(UNIXNAME)), sun4u) + SYSLIB = -lsocket -lnsl -lrt + endif + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DSUNOS5 -D_REENTRANT -pedantic +endif + +#Path for HP-UX +ifeq ($(findstring HP-UX, $(UNIXNAME)), HP-UX) + ifeq ($CC, "gcc") + CFLAGS += -Wstrict-prototypes + endif + CFLAGS += -DHP_UX -DHPUX11 + PLAT_NAME=hp-ux +endif + +#Find system type. +ifneq ($(SYSPATH),) + CHECKSYSRES = @echo "System is $(shell uname -sm)" +endif +########################################################### +ACL_HOME = ../lib_acl +ACL_INC_PATH = $(ACL_HOME)/include +ACL_LIB_PATH = $(ACL_HOME)/lib + +CFLAGS += -I$(ACL_INC_PATH) + +LINK_LIBS = -L$(ACL_LIB_PATH) -l_acl -L/opt/messenger/lib/glib/linux/lib -lglib-2.0 $(SYSLIB) + +########################################################### +OUT_PATH = . +OBJ_PATH_DST = $(OUT_PATH)/debug +PROG_PATH_DST = $(OUT_PATH)/bin + +BASE_PATH = . +SRC_PATH_SRC = $(BASE_PATH) + +INC_COMPILE = -I. -I./stdlib -I./net -I./unit_test +CFLAGS += $(INC_COMPILE) + +#Project's source +BASE_SRC = $(wildcard *.c) +STDLIB_SRC = $(wildcard $(SRC_PATH_SRC)/stdlib/*.c) +UNIT_TEST_SRC = $(wildcard $(SRC_PATH_SRC)/unit_test/*.c) +NET_SRC = $(wildcard $(SRC_PATH_SRC)/net/*.c) +SOURCES_SRC = $(BASE_SRC) $(STDLIB_SRC) $(UNIT_TEST_SRC) $(NET_SRC) + +#Project's obj +OBJS_DST = $(patsubst %.c, $(OBJ_PATH_DST)/%.o, $(notdir $(SOURCES_SRC))) + +########################################################### +.PHONY = all clean myecho + +PROG_NAME = test_main + +COMPILE = $(CC) $(CFLAGS) +LD_RUN_PATH=-Wl,-rpath,/opt/messenger/lib/glib/linux/lib,-rpath,/opt/messenger/lib/mysql/linux/lib +LINK = $(CC) -o $(PROG_PATH_DST)/$(PROG_NAME) $(OBJS_DST) $(LINK_LIBS) $(LD_RUN_PATH) + +all: $(PROG_NAME) + +$(PROG_NAME): $(OBJS_DST) + $(LINK) + +$(OBJ_PATH_DST)/%.o: %.c *.h + $(COMPILE) $< -o $@ + +$(OBJ_PATH_DST)/%.o: stdlib/%.c stdlib/*.h + $(COMPILE) $< -o $@ + +$(OBJ_PATH_DST)/%.o: unit_test/%.c unit_test/*.h + $(COMPILE) $< -o $@ + +$(OBJ_PATH_DST)/%.o: net/%.c net/*.h + $(COMPILE) $< -o $@ + +clean: + rm -f $(PROG_PATH_DST)/$(PROG_NAME) + rm -f $(OBJS_DST) + +myecho: + @(echo "STDLIB_SRC: $(STDLIB_SRC)") + @(echo "UNIT_TEST_SRC: $(UNIT_TEST_SRC)") + @(echo "SOURCES_SRC: $(SOURCES_SRC)") + @(echo "OBJS_DST: $(OBJS_DST)") + @(echo "OBJ_PATH_DST: $(OBJ_PATH_DST)") + + diff --git a/unit_test/avl.sh b/unit_test/avl.sh new file mode 100644 index 000000000..4182a1282 --- /dev/null +++ b/unit_test/avl.sh @@ -0,0 +1,2 @@ +#!/bin/sh +bin/test_main conf/test_avl.cf diff --git a/unit_test/bin/keep b/unit_test/bin/keep new file mode 100644 index 000000000..e69de29bb diff --git a/unit_test/conf/test_avl.cf b/unit_test/conf/test_avl.cf new file mode 100644 index 000000000..70735c994 --- /dev/null +++ b/unit_test/conf/test_avl.cf @@ -0,0 +1,10 @@ +LOG|print +avl_create|0|0| +avl_add_bat|0|0| +avl_walk|0|0| +avl_add|0|0|name=name1,value=value1 +avl_walk|0|0| +avl_find|0|0|name=name1 +avl_delete|0|0|name=name1 +avl_find|-1|0|name=name1 +avl_walk|0|0| diff --git a/unit_test/conf/test_htable.cf b/unit_test/conf/test_htable.cf new file mode 100644 index 000000000..563a306ed --- /dev/null +++ b/unit_test/conf/test_htable.cf @@ -0,0 +1,15 @@ +LOG|print +#htable_create|0|0|hash_fn=hash_crc32, table=name1:value1; name2:value2; name3:value3; name4:value4; name5:value5; name6:value6 +#htable_create|0|0|hash_fn=hash_def, table=name1:value1; name2:value2; name3:value3; name4:value4; name5:value5; name6:value6 +#htable_find|0|0|name=name1 +#htable_stat|0|0| +#htable_find|-1|0|name=name_no_exist +#htable_rwlock|0|0|hash_fn=hash_bin +#htable_rwlock|0|0|hash_fn=hash_crc32 +#htable_rwlock|0|0|hash_fn=hash_func2 +#htable_rwlock|0|0|hash_fn=hash_func3 +#htable_rwlock|0|0|hash_fn=hash_func4 +#htable_rwlock|0|0|hash_fn=hash_func5 +#htable_rwlock|0|0|hash_fn=hash_func6 +htable_rwlock|0|0|hash_fn=hash_test +#htable_rwlock|0|0|hash_fn=hash_def diff --git a/unit_test/conf/test_main.cf b/unit_test/conf/test_main.cf new file mode 100644 index 000000000..ea8ebd3f3 --- /dev/null +++ b/unit_test/conf/test_main.cf @@ -0,0 +1,19 @@ + + +#命令函数名称|预测结果[0:表示成功, 1:表示失败]|参数个数|参数列表[name=参数1, name=参数2.. +#LOG|print:fprint +LOG|print + +test_ring|0|0| +STOP + +test_loop|0|0|count=10 +LOOP_BEGIN|COUNT=3 + LOOP_BEGIN|COUNT=2 + LOOP_BEGIN|COUNT=2 +# LOOP_BREAK + test_param|0|0|account=zhengshuxin@hexun.com.cn, sender=cyun@staff.hexun.com, number=200 + LOOP_END + LOOP_END +LOOP_END +#STOP diff --git a/unit_test/conf/test_malloc.cf b/unit_test/conf/test_malloc.cf new file mode 100644 index 000000000..3e3382cee --- /dev/null +++ b/unit_test/conf/test_malloc.cf @@ -0,0 +1,3 @@ +LOG|print +fatal_free|0|0| +#fatal_malloc|0|0| diff --git a/unit_test/conf/test_net.cf b/unit_test/conf/test_net.cf new file mode 100644 index 000000000..9cfc79680 --- /dev/null +++ b/unit_test/conf/test_net.cf @@ -0,0 +1,13 @@ +LOG|print +test_mask_addr|0|0|ip=192.168.1.10,bits=8 +test_mask_addr|0|0|ip=192.168.1.10,bits=16 +test_mask_addr|0|0|ip=192.168.1.10,bits=10 +test_mask_addr|0|0|ip=192.168.1.10,bits=24 +test_mask_addr|0|0|ip=192.168.1.10,bits=32 +test_connect|0|0|addr=www.hexun.com:80 +test_connect|0|0|addr=192.168.23.142@www.hexun.com:80 +test_connect|0|0|addr=0.0.0.0@www.hexun.com:80 +#test_connect|0|0|addr=127.0.0.1@www.hexun.com:80 +#test_connect|0|0|addr=60.28.250.199@www.hexun.com:80 +#test_connect|0|0|addr=10.0.250.199@www.hexun.com:80 +#test_connect|-1|0|addr=10.0.251.199@www.hexun.com:80 diff --git a/unit_test/conf/test_stack.cf b/unit_test/conf/test_stack.cf new file mode 100644 index 000000000..d4d86c9f0 --- /dev/null +++ b/unit_test/conf/test_stack.cf @@ -0,0 +1,6 @@ +LOG|print +stack_bat_add|0|0| +stack_walk|0|0| +stack_pop|0|0| +stack_walk|0|0| +stack_pop|0|0| diff --git a/unit_test/conf/test_string.cf b/unit_test/conf/test_string.cf new file mode 100644 index 000000000..958e5cdb9 --- /dev/null +++ b/unit_test/conf/test_string.cf @@ -0,0 +1,5 @@ +LOG|print +strcasestr|0|0| +strrncasecmp|0|0| +strrncmp|0|0| +i64toa|0|0| diff --git a/unit_test/conf/test_vstream.cf b/unit_test/conf/test_vstream.cf new file mode 100644 index 000000000..bdba55509 --- /dev/null +++ b/unit_test/conf/test_vstream.cf @@ -0,0 +1,2 @@ +LOG|print +file_vstream|0|0|filename=test.txt diff --git a/unit_test/debug/keep b/unit_test/debug/keep new file mode 100644 index 000000000..e69de29bb diff --git a/unit_test/hash.sh b/unit_test/hash.sh new file mode 100644 index 000000000..b4e5aee67 --- /dev/null +++ b/unit_test/hash.sh @@ -0,0 +1,2 @@ +#!/bin/sh +bin/test_main conf/test_htable.cf diff --git a/unit_test/net.sh b/unit_test/net.sh new file mode 100644 index 000000000..7146e98d8 --- /dev/null +++ b/unit_test/net.sh @@ -0,0 +1,2 @@ +#!/bin/sh +bin/test_main conf/test_net.cf diff --git a/unit_test/net/test_connect.c b/unit_test/net/test_connect.c new file mode 100644 index 000000000..6bbeccc20 --- /dev/null +++ b/unit_test/net/test_connect.c @@ -0,0 +1,36 @@ + +#include "lib_acl.h" +#include +#include + +#include "test_net.h" + +int test_connect(AUT_LINE *test_line, void *arg acl_unused) +{ + const char *addr; + ACL_VSTREAM *client; + char ip_local[32], ip_remote[32]; + + AUT_SET_STR(test_line, "addr", addr); + + client = acl_vstream_connect(addr, ACL_BLOCKING, 0, 10, 1024); + if (client == NULL) { + printf("connect addr(%s) error\r\n", addr); + return (-1); + } + + acl_getpeername(ACL_VSTREAM_SOCK(client), ip_remote, sizeof(ip_remote)); + acl_getsockname(ACL_VSTREAM_SOCK(client), ip_local, sizeof(ip_local)); + + printf("connect addr(%s) ok, local ip(%s), remote ip(%s)\r\n", + addr, ip_local, ip_remote); + acl_vstream_fprintf(client, "%s", + "GET / HTTP/1.0\r\n" + "HOST: www.test.com\r\n" + "Connection: close\r\n" + "\r\n"); + + acl_vstream_close(client); + return (0); +} + diff --git a/unit_test/net/test_net.c b/unit_test/net/test_net.c new file mode 100644 index 000000000..cce1dcbcb --- /dev/null +++ b/unit_test/net/test_net.c @@ -0,0 +1,14 @@ + +#include +#include +#include +#include + +#include "lib_acl.h" +#include "test_net.h" +#include "test_nettab.h" + +void test_net_register() +{ + aut_register(__test_fn_tab); +} diff --git a/unit_test/net/test_net.h b/unit_test/net/test_net.h new file mode 100644 index 000000000..dd517b7d6 --- /dev/null +++ b/unit_test/net/test_net.h @@ -0,0 +1,23 @@ + +#ifndef __TEST_NET_INCLUDE_H__ +#define __TEST_NET_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* test_net.c: register all test functions */ +void test_net_register(void); + +/* in test_connect.c */ +int test_connect(AUT_LINE *test_line, void *arg); + +/* in test_net_misc.c */ +int test_mask_addr(AUT_LINE *test_line, void *arg); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/unit_test/net/test_net_misc.c b/unit_test/net/test_net_misc.c new file mode 100644 index 000000000..f794c0794 --- /dev/null +++ b/unit_test/net/test_net_misc.c @@ -0,0 +1,26 @@ +#include "lib_acl.h" +#include +#include + +#include "test_net.h" + +int test_mask_addr(AUT_LINE *test_line, void *arg acl_unused) +{ + const char *ip; + int bits; + unsigned int addr; + struct in_addr in; + char buf[32]; + + AUT_SET_STR(test_line, "ip", ip); + AUT_SET_INT(test_line, "bits", bits); + +/* + addr = ntohl(inet_addr(ip)); +*/ + addr = inet_addr(ip); + acl_mask_addr((unsigned char *) &addr, sizeof(addr), bits); + in.s_addr = addr; + printf("i: %s, addr: %s\n", ip, acl_inet_ntoa(in, buf, sizeof(buf))); + return (0); +} diff --git a/unit_test/net/test_nettab.h b/unit_test/net/test_nettab.h new file mode 100644 index 000000000..17bb47c24 --- /dev/null +++ b/unit_test/net/test_nettab.h @@ -0,0 +1,27 @@ +#ifndef __TEST_NETTAB_INCLUDE_H__ +#define __TEST_NETTAB_INCLUDE_H__ + +#include "lib_acl.h" +#ifdef __cplusplus +extern "C" { +#endif + +#include "test_net.h" + +static AUT_FN_ITEM __test_fn_tab[] = { + /* 命令字名称 函数提示名 回调函数名称 回调参数 是否是内部命令 */ + /* test_connect.c */ + { "test_connect", "test_connect", test_connect, NULL, 0 }, + + /* test_net_misc.c */ + { "test_mask_addr", "test_mask_addr", test_mask_addr, NULL, 0 }, + + { NULL, NULL, NULL, NULL, 0}, +}; + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/unit_test/stack.sh b/unit_test/stack.sh new file mode 100644 index 000000000..d15ea9e18 --- /dev/null +++ b/unit_test/stack.sh @@ -0,0 +1,2 @@ +#!/bin/sh +bin/test_main conf/test_stack.cf diff --git a/unit_test/start.sh b/unit_test/start.sh new file mode 100644 index 000000000..2352ddf48 --- /dev/null +++ b/unit_test/start.sh @@ -0,0 +1,2 @@ +#!/bin/sh +bin/test_main conf/test_main.cf diff --git a/unit_test/stdlib/test_avl.c b/unit_test/stdlib/test_avl.c new file mode 100644 index 000000000..bbeeddc0f --- /dev/null +++ b/unit_test/stdlib/test_avl.c @@ -0,0 +1,146 @@ + +#include "lib_acl.h" +#include "stdlib/avl.h" +#include +#include +#include +#include + +#include "test_stdlib.h" + +#ifdef WIN32 +#define snprintf _snprintf +#endif + +avl_tree_t *__avl_tree = NULL; + +typedef struct MY_TYPE { + char name[256]; + char value[256]; + avl_node_t node; +} MY_TYPE; + +static int compare_fn(const void *v1, const void *v2) +{ + const MY_TYPE *m1 = (const MY_TYPE*) v1, *m2 = (const MY_TYPE*) v2; + + return (strcmp(m1->name, m2->name)); +} + +int test_avl_create(AUT_LINE *test_line acl_unused, void *arg acl_unused) +{ + const char *myname = "test_avl_create"; + + if (__avl_tree != NULL) { + printf("%s: should not be called more than once!\n", myname); + return (-1); + } + + __avl_tree = (avl_tree_t *) acl_mycalloc(1, sizeof(avl_tree_t)); + assert(__avl_tree); + avl_create(__avl_tree, compare_fn, sizeof(MY_TYPE), offsetof(MY_TYPE, node)); + + return (0); +} + +int test_avl_add_bat(AUT_LINE *test_line acl_unused, void *arg acl_unused) +{ + MY_TYPE *pm, m; + int i, n = 0; + + for (i = 0; i < 100; i++) { + snprintf(m.name, sizeof(m.name), "%d", i); + pm = (MY_TYPE*) avl_find(__avl_tree, &m, NULL); + if (pm != NULL) { + printf(">>key(%s) already exist, value(%s)\r\n", + pm->name, pm->value); + continue; + } + + pm = (MY_TYPE*) acl_mycalloc(1, sizeof(MY_TYPE)); + snprintf(pm->name, sizeof(pm->name), "%d", i); + snprintf(pm->value, sizeof(pm->value), "value(%d)", i); + avl_add(__avl_tree, pm); + printf(">>add one, key(%s), value(%s)\r\n", pm->name, pm->value); + n++; + } + + return (0); +} + +int test_avl_walk(AUT_LINE *test_line acl_unused, void *arg acl_unused) +{ + MY_TYPE *next; + int n = 0; + + next = (MY_TYPE*) avl_first(__avl_tree); + while (next) { + printf(">>name(%s), value(%s)\r\n", next->name, next->value); + next = (MY_TYPE*) AVL_NEXT(__avl_tree, next); + n++; + } + + printf(">>ok, total count is %d\r\n", n); + return (0); +} + +int test_avl_find(AUT_LINE *test_line, void *arg acl_unused) +{ + MY_TYPE m, *pm; + const char *pname; + + AUT_SET_STR(test_line, "name", pname); + snprintf(m.name, sizeof(m.name), "%s", pname); + + pm = (MY_TYPE*) avl_find(__avl_tree, &m, NULL); + if (pm) { + printf(">>ok, find it, %s, %s\r\n", m.name, pm->value); + return (0); + } else { + printf(">>not find it, name=%s\r\n", m.name); + return (-1); + } +} + +int test_avl_add(AUT_LINE *test_line, void *arg acl_unused) +{ + MY_TYPE m, *pm; + const char *pname, *pvalue; + + AUT_SET_STR(test_line, "name", pname); + AUT_SET_STR(test_line, "value", pvalue); + snprintf(m.name, sizeof(m.name), "%s", pname); + snprintf(m.value, sizeof(m.value), "%s", pvalue); + + pm = (MY_TYPE*) avl_find(__avl_tree, &m, NULL); + if (pm) { + printf(">>err, already exist %s, %s\r\n", m.name, pm->value); + return (-1); + } else { + pm = (MY_TYPE*) acl_mycalloc(1, sizeof(MY_TYPE)); + snprintf(pm->name, sizeof(pm->name), "%s", pname); + snprintf(pm->value, sizeof(pm->value), "value(%s)", pvalue); + avl_add(__avl_tree, pm); + printf(">>ok, added, name=%s\r\n", m.name); + return (0); + } +} + +int test_avl_delete(AUT_LINE *test_line, void *arg acl_unused) +{ + MY_TYPE m, *pm; + const char *pname; + + AUT_SET_STR(test_line, "name", pname); + snprintf(m.name, sizeof(m.name), "%s", pname); + + pm = (MY_TYPE*) avl_find(__avl_tree, &m, NULL); + if (pm == NULL) { + printf(">>not find %s\r\n", m.name); + return (-1); + } + + avl_remove(__avl_tree, pm); + printf(">>ok, delete %s\r\n", m.name); + return (0); +} diff --git a/unit_test/stdlib/test_htable.c b/unit_test/stdlib/test_htable.c new file mode 100644 index 000000000..91041aff4 --- /dev/null +++ b/unit_test/stdlib/test_htable.c @@ -0,0 +1,207 @@ + +#include "lib_acl.h" +#include +#include + +#include "test_stdlib.h" + +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif + +static ACL_HASH_FN __get_hash_fn(const char *ptr) +{ + if (strcasecmp(ptr, "hash_crc32") == 0) + return (acl_hash_crc32); + else if (strcasecmp(ptr, "hash_bin") == 0) + return (acl_hash_bin); + else if (strcasecmp(ptr, "hash_test") == 0) + return (acl_hash_test); + else if (strcasecmp(ptr, "hash_func2") == 0) + return (acl_hash_func2); + else if (strcasecmp(ptr, "hash_func3") == 0) + return (acl_hash_func3); + else if (strcasecmp(ptr, "hash_func4") == 0) + return (acl_hash_func4); + else if (strcasecmp(ptr, "hash_func5") == 0) + return (acl_hash_func5); + else if (strcasecmp(ptr, "hash_func6") == 0) + return (acl_hash_func6); + else + return (NULL); +} + +/*---------------------------------------------------------------------------*/ + +static ACL_HTABLE *__table; + +int test_htable_create(AUT_LINE *test_line, void *arg acl_unused) +{ + const char *ptr; + ACL_ARGV *argv; + char *pname, *pvalue; + int i; + ACL_HASH_FN hash_fn; + + AUT_SET_STR(test_line, "hash_fn", ptr); + + hash_fn = __get_hash_fn(ptr); + + AUT_SET_STR(test_line, "table", ptr); + printf("table=[%s]\n", ptr); + + __table = acl_htable_create(1, 0); + acl_htable_ctl(__table, + ACL_HTABLE_CTL_RWLOCK, FALSE, + ACL_HTABLE_CTL_HASH_FN, hash_fn, + ACL_HTABLE_CTL_END); + + argv = acl_argv_split(ptr, "; "); + + for (i = 0; i < acl_argv_size(argv); i++) { + pname = acl_argv_index(argv, i); + pvalue = strchr(pname, ':'); + if (pvalue == NULL) { + printf("invalid for [%s]\n", pname); + continue; + } + *pvalue++ = 0; + if (*pvalue == 0) { + printf("invalid for [%s]\n", pname); + continue; + } + (void) acl_htable_enter(__table, pname, acl_mystrdup(pvalue)); + } + + acl_argv_free(argv); + + return (0); +} + +int test_htable_stat(AUT_LINE *test_line acl_unused, void *arg acl_unused) +{ + const char *myname = "test_htable_stat"; + + if (__table == NULL) { + printf("%s: __table null\n", myname); + return (-1); + } + + acl_htable_stat(__table); + + return (0); +} +int test_htable_free(AUT_LINE *test_line acl_unused, void *arg acl_unused) +{ + if (__table == NULL) { + printf("null hash table\n"); + return (-1); + } + + return (0); +} + +int test_htable_find(AUT_LINE *test_line, void *arg acl_unused) +{ + const char *myname = "test_htable_find"; + const char *ptr; + char *value; + + AUT_SET_STR(test_line, "name", ptr); + + value = acl_htable_find(__table, ptr); + if (value) { + printf("%s: ok, find it, %s=%s\n", myname, ptr, value); + return (0); + } else { + printf("%s: error, not found %s\n", myname, ptr); + return (-1); + } +} + +/*---------------------------------------------------------------------------*/ + +typedef struct __HTABLE_RWLOCK_CTX { + ACL_HTABLE *table; + AUT_LINE *test_line; +} __HTABLE_RWLOCK_CTX; + +typedef struct __THR_CTX { + char key[256]; +} __THR_CTX; + +static __HTABLE_RWLOCK_CTX __rwlock_ctx; + +static void __htable_rwlock_fn(void *arg) +{ + const char *myname = "__htable_rwlock_fn"; + char key[256]; + __HTABLE_RWLOCK_CTX *ctx = (__HTABLE_RWLOCK_CTX *) arg; + __THR_CTX *thr_ctx = acl_mycalloc(1, sizeof(__THR_CTX)); + +#ifdef LINUX2 + snprintf(key, sizeof(key), "%lu", pthread_self()); +#elif defined(SUNOS5) + snprintf(key, sizeof(key), "%d", pthread_self()); +#endif + +/* + if (acl_htable_find(ctx->table, key)) { + printf("key(%s) exist\n", key); + return; + } +*/ + + ACL_SAFE_STRNCPY(thr_ctx->key, key, sizeof(thr_ctx->key)); + if (acl_htable_enter(ctx->table, key, (char *) thr_ctx) == NULL) + acl_msg_fatal("insert into htable error(%s), key(%s)", + strerror(errno), key); + + printf("search key: %s\n", key); + thr_ctx = (__THR_CTX *) acl_htable_find(ctx->table, key); + if (thr_ctx == NULL) + acl_msg_fatal("%s: not find key(%s)", myname, key); + printf("ok, add and find, key=%s\n", key); +} + +int test_htable_rwlock(AUT_LINE *test_line, void *arg acl_unused) +{ + acl_pthread_pool_t *tp; + int threads = 100, thread_idle = 120; + int i, n = 1000; + ACL_HASH_FN hash_fn; + const char *ptr; + + AUT_SET_STR(test_line, "hash_fn", ptr); + + hash_fn = __get_hash_fn(ptr); + + __rwlock_ctx.test_line = test_line; + __rwlock_ctx.table = acl_htable_create(10, 0); + + acl_htable_ctl(__rwlock_ctx.table, + ACL_HTABLE_CTL_RWLOCK, TRUE, + ACL_HTABLE_CTL_HASH_FN, hash_fn, + ACL_HTABLE_CTL_END); + + tp = acl_thread_pool_create(threads, thread_idle); + + for (i = 0; i < n; i++) { + if (acl_pthread_pool_add(tp, __htable_rwlock_fn, &__rwlock_ctx)) + acl_msg_fatal("acl_workq_add error(%s)", strerror(errno)); + } + + sleep(2); + + acl_pthread_pool_stop(tp); + acl_htable_stat(__rwlock_ctx.table); + + acl_htable_free(__rwlock_ctx.table, (void (*) (void *))acl_myfree_fn); + __rwlock_ctx.test_line = NULL; + __rwlock_ctx.table = NULL; + + return (0); +} diff --git a/unit_test/stdlib/test_malloc.c b/unit_test/stdlib/test_malloc.c new file mode 100644 index 000000000..4f22a25a4 --- /dev/null +++ b/unit_test/stdlib/test_malloc.c @@ -0,0 +1,30 @@ +#include "lib_acl.h" +#include +#include + +#include "test_stdlib.h" + +int test_fatal_malloc(AUT_LINE *test_line acl_unused, void *arg acl_unused) +{ + char *ptr; + + acl_memory_debug_start(); + ptr = acl_mymalloc(-1); + assert(ptr); + acl_memory_debug_stop(); + + /*not reached */ + return (0); +} + +int test_fatal_free(AUT_LINE *test_line acl_unused, void *arg acl_unused) +{ + char *ptr = NULL; + + acl_memory_debug_start(); + acl_myfree(ptr); + acl_memory_debug_stop(); + + /*not reached */ + return (0); +} diff --git a/unit_test/stdlib/test_myflock.c b/unit_test/stdlib/test_myflock.c new file mode 100644 index 000000000..053f1399a --- /dev/null +++ b/unit_test/stdlib/test_myflock.c @@ -0,0 +1,110 @@ +#include "lib_acl.h" + +#include +#include +#include +#include +#include +#ifdef ACL_UNIX +#include +#endif +#include +#include + +#include "test_stdlib.h" + +#ifdef WIN32 +#define snprintf _snprintf +#endif + +static ACL_FILE_HANDLE __file_fd = ACL_FILE_INVALID; + +static ACL_FILE_HANDLE __mylock_open(const char *filename) +{ + ACL_FILE_HANDLE fd; + int flag = O_WRONLY|O_APPEND|O_CREAT; +#ifdef ACL_UNIX + int mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH; +#else + int mode = 0600; +#endif + + fd = acl_file_open(filename, flag, mode); + return (fd); +} + +static ACL_FILE_HANDLE __mylock_try_open(const char *filename) +{ + char myname[] = "__mylock_try_open"; + + if (__file_fd < 0) { + if (filename == NULL || *filename == 0) + acl_msg_fatal("%s(%d): filename invalid", myname, __LINE__); + __file_fd = __mylock_open(filename); + } + if (__file_fd < 0) + acl_msg_fatal("%s(%d): open file(%s) error(%s)", + myname, __LINE__, filename, strerror(errno)); + + return (__file_fd); +} + +static int __mylock_op(ACL_FILE_HANDLE fd, int op, char *errbuf, int size) +{ + int lock_style = ACL_MYFLOCK_STYLE_FCNTL; + int ret; + + ret = acl_myflock(fd, lock_style, op); + if (ret < 0) { + if (errbuf && size > 0) + snprintf(errbuf, size, "flock error(%s)", strerror(errno)); + return (-1); + } + + return (0); +} + +int test_mylock_unlock(AUT_LINE *test_line, void *arg acl_unused) +{ + int operation = ACL_MYFLOCK_OP_NONE; + const char *filename; + ACL_FILE_HANDLE fd; + + AUT_SET_STR(test_line, "file", filename); + fd = __mylock_try_open(filename); + return (__mylock_op(fd, operation, NULL, 0)); +} + +int test_mylock_excl(AUT_LINE *test_line, void *arg acl_unused) +{ + int operation = ACL_MYFLOCK_OP_EXCLUSIVE; + const char *filename; + ACL_FILE_HANDLE fd; + + AUT_SET_STR(test_line, "file", filename); + fd = __mylock_try_open(filename); + return (__mylock_op(fd, operation, NULL, 0)); +} + +int test_mylock_nowait(AUT_LINE *test_line, void *arg acl_unused) +{ + int operation = ACL_MYFLOCK_OP_NOWAIT; + const char *filename; + ACL_FILE_HANDLE fd; + + AUT_SET_STR(test_line, "file", filename); + fd = __mylock_try_open(filename); + return (__mylock_op(fd, operation, NULL, 0)); +} + +int test_mylock_shared(AUT_LINE *test_line, void *arg acl_unused) +{ + int operation = ACL_MYFLOCK_OP_SHARED; + const char *filename; + ACL_FILE_HANDLE fd; + + AUT_SET_STR(test_line, "file", filename); + fd = __mylock_try_open(filename); + return (__mylock_op(fd, operation, NULL, 0)); +} + diff --git a/unit_test/stdlib/test_ring.c b/unit_test/stdlib/test_ring.c new file mode 100644 index 000000000..7466b7d39 --- /dev/null +++ b/unit_test/stdlib/test_ring.c @@ -0,0 +1,92 @@ + +#include "lib_acl.h" +#include +#include + +#include "test_stdlib.h" + +#ifdef WIN32 +#define snprintf _snprintf +#endif + +typedef struct MY_TYPE { + char name[256]; + char value[256]; + int i; + + ACL_RING ring_entry; +} MY_TYPE; + +static ACL_RING __ring_header; + +static void __create_ring(int flag, int size) +{ + MY_TYPE *my_type; + int i; + + for (i = 0; i < size; i++) { + my_type = acl_mycalloc(1, sizeof(MY_TYPE)); + snprintf(my_type->name, sizeof(my_type->name), "name:%d", i); + snprintf(my_type->value, sizeof(my_type->value), "value:%d", i); + my_type->i = i; + if (flag) + acl_ring_prepend(&__ring_header, &my_type->ring_entry); + else + acl_ring_append(&__ring_header, &my_type->ring_entry); + } +} + +int test_ring(AUT_LINE *test_line acl_unused, void *arg acl_unused) +{ + ACL_RING_ITER ring_iter; + MY_TYPE *my_type; + + acl_ring_init(&__ring_header); + + __create_ring(0, 10); + + printf("\nring loop printf:> len=%d\n", acl_ring_size(&__ring_header)); + + acl_ring_foreach(ring_iter, &__ring_header) { + my_type = ACL_RING_TO_APPL(ring_iter.ptr, MY_TYPE, ring_entry); + printf("name=%s, value=%s\n", my_type->name, my_type->value); + } + + printf("\nring pop head loop printf:> len=%d\n", acl_ring_size(&__ring_header)); + + while (1) { + ring_iter.ptr = acl_ring_pop_head(&__ring_header); + if (ring_iter.ptr == NULL) + break; + + my_type = ACL_RING_TO_APPL(ring_iter.ptr, MY_TYPE, ring_entry); + printf("name=%s, value=%s\n", my_type->name, my_type->value); + acl_myfree(my_type); + } + + printf("first end, len=%d\n", acl_ring_size(&__ring_header)); + + __create_ring(1, 20); + + printf("\nring loop printf:> len=%d\n", acl_ring_size(&__ring_header)); + + acl_ring_foreach_reverse(ring_iter, &__ring_header) { + my_type = ACL_RING_TO_APPL(ring_iter.ptr, MY_TYPE, ring_entry); + printf("name=%s, value=%s\n", my_type->name, my_type->value); + } + + printf("\nring pop tail loop printf:> len=%d\n", acl_ring_size(&__ring_header)); + + while (1) { + ring_iter.ptr = acl_ring_pop_tail(&__ring_header); + if (ring_iter.ptr == NULL) + break; + + my_type = ACL_RING_TO_APPL(ring_iter.ptr, MY_TYPE, ring_entry); + printf("name=%s, value=%s\n", my_type->name, my_type->value); + acl_myfree(my_type); + } + + return (0); +} + diff --git a/unit_test/stdlib/test_stack.c b/unit_test/stdlib/test_stack.c new file mode 100644 index 000000000..999292db0 --- /dev/null +++ b/unit_test/stdlib/test_stack.c @@ -0,0 +1,76 @@ +#include "lib_acl.h" +#include +#include +#include +#include + +#ifdef WIN32 +#define snprintf _snprintf +#endif + +#include "test_stdlib.h" + +typedef struct MY_TYPE { + char name[256]; +} MY_TYPE; + +ACL_STACK *__stack = NULL; + +static void __stack_init(void) +{ + if (__stack != NULL) + return; + __stack = acl_stack_create(100); +} + +int test_stack_bat_add(AUT_LINE *test_line acl_unused, void *arg acl_unused) +{ + MY_TYPE *t; + int i; + + __stack_init(); + + for (i = 0; i < 25; i++) { + t = acl_mymalloc(sizeof(MY_TYPE)); + snprintf(t->name, sizeof(t->name), "name:%d", i); + acl_stack_append(__stack, t); + } + return (0); +} + +int test_stack_walk(AUT_LINE *test_line acl_unused, void *arg acl_unused) +{ + const char *myname = "test_stack_walk"; + ACL_ITER iter; + MY_TYPE *t; + int i = 0; + + __stack_init(); + + acl_foreach(iter, __stack) { + t = (MY_TYPE*) iter.data; + printf("%s: %d %s\r\n", myname, i++, t->name); + } + printf("%s: total is %d\r\n", myname, i); + return (0); +} + +int test_stack_pop(AUT_LINE *test_line acl_unused, void *arg acl_unused) +{ + const char *myname = "test_stack_pop"; + MY_TYPE *t; + int i = 0; + + __stack_init(); + + while (1) { + t = acl_stack_pop(__stack); + if (t == NULL) + break; + printf("%s: %d %s\r\n", myname, i++, t->name); + acl_myfree(t); + } + + printf("%s: total is %d\r\n", myname, i); + return (0); +} diff --git a/unit_test/stdlib/test_stdlib.c b/unit_test/stdlib/test_stdlib.c new file mode 100644 index 000000000..b6b672b5d --- /dev/null +++ b/unit_test/stdlib/test_stdlib.c @@ -0,0 +1,15 @@ + +#include +#include +#include +#include + +#include "lib_acl.h" +#include "test_stdlib.h" + +#include "test_stdtab.h" + +void test_stdlib_register() +{ + aut_register(__test_fn_tab); +} diff --git a/unit_test/stdlib/test_stdlib.h b/unit_test/stdlib/test_stdlib.h new file mode 100644 index 000000000..1eb72e798 --- /dev/null +++ b/unit_test/stdlib/test_stdlib.h @@ -0,0 +1,59 @@ + +#ifndef __TEST_STDLIB_INCLUDE_H__ +#define __TEST_STDLIB_INCLUDE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* test_stdlib.c: register all test functions */ +void test_stdlib_register(void); + +/* test_mylock.c */ +int test_mylock_unlock(AUT_LINE *test_line, void *arg_unused); +int test_mylock_excl(AUT_LINE *test_line, void *arg_unused); +int test_mylock_nowait(AUT_LINE *test_line, void *arg_unused); +int test_mylock_shared(AUT_LINE *test_line, void *arg_unused); + +/* test_ring.c */ +int test_ring(AUT_LINE *test_line, void *arg_unused); + +/* test_htable.c */ +int test_htable_create(AUT_LINE *test_line, void *arg_unused); +int test_htable_stat(AUT_LINE *test_line, void *arg_unused); +int test_htable_free(AUT_LINE *test_line, void *arg_unused); +int test_htable_find(AUT_LINE *test_line, void *arg_unused); +int test_htable_rwlock(AUT_LINE *test_line, void *arg_unused); + +/* in test_malloc.c */ +int test_fatal_free(AUT_LINE *test_line acl_unused, void *arg acl_unused); +int test_fatal_malloc(AUT_LINE *test_line acl_unused, void *arg acl_unused); + +/* in test_avl.c */ +int test_avl_create(AUT_LINE *test_line acl_unused, void *arg acl_unused); +int test_avl_add_bat(AUT_LINE *test_line acl_unused, void *arg acl_unused); +int test_avl_walk(AUT_LINE *test_line acl_unused, void *arg acl_unused); +int test_avl_find(AUT_LINE *test_line, void *arg acl_unused); +int test_avl_add(AUT_LINE *test_line, void *arg acl_unused); +int test_avl_delete(AUT_LINE *test_line, void *arg acl_unused); + +/* in test_stack.c */ +int test_stack_bat_add(AUT_LINE *test_line, void *arg); +int test_stack_walk(AUT_LINE *test_line, void *arg); +int test_stack_pop(AUT_LINE *test_line, void *arg); + +/* in test_vstream.c */ +int test_file_vstream(AUT_LINE *test_line, void *arg); + +/* in test_string.c */ +int test_strrncasecmp(AUT_LINE *test_line, void *arg); +int test_strrncmp(AUT_LINE *test_line, void *arg); +int test_x64toa(AUT_LINE *test_line, void *arg); +int test_strcasestr(AUT_LINE *test_line, void *arg); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/unit_test/stdlib/test_stdtab.h b/unit_test/stdlib/test_stdtab.h new file mode 100644 index 000000000..4bebddac6 --- /dev/null +++ b/unit_test/stdlib/test_stdtab.h @@ -0,0 +1,63 @@ +#ifndef __TEST_STDTAB_INCLUDE_H__ +#define __TEST_STDTAB_INCLUDE_H__ + +#include "lib_acl.h" +#ifdef __cplusplus +extern "C" { +#endif + +#include "test_stdlib.h" + +static AUT_FN_ITEM __test_fn_tab[] = { + /* 命令字名称 函数提示名 回调函数名称 回调参数 是否是内部命令 */ + /* test_mylock.c */ + { "test_mylock_unlock", "test_mylock_unlock", test_mylock_unlock, NULL, 0 }, + { "test_mylock_excl", "test_mylock_excl", test_mylock_excl, NULL, 0 }, + { "test_mylock_nowait", "test_mylock_nowait", test_mylock_nowait, NULL, 0 }, + { "test_mylock_shared", "test_mylock_shared", test_mylock_shared, NULL, 0 }, + + /* test_ring.c */ + { "test_ring", "test_ring", test_ring, NULL, 0 }, + + /* test_htable.c */ + { "htable_create", "htable_create", test_htable_create, NULL, 0 }, + { "htable_find", "htable_find", test_htable_find, NULL, 0 }, + { "htable_stat", "htable_stat", test_htable_stat, NULL, 0 }, + { "htable_free", "htable_free", test_htable_free, NULL, 0 }, + { "htable_rwlock", "htable_rwlock", test_htable_rwlock, NULL, 0 }, + + /* test_malloc.c */ + { "fatal_malloc", "fatal_malloc", test_fatal_malloc, NULL, 0 }, + { "fatal_free", "fatal_free", test_fatal_free, NULL, 0 }, + + /* test_avl.c */ + { "avl_create", "avl_create", test_avl_create, NULL, 0 }, + { "avl_add_bat", "avl_add_bat", test_avl_add_bat, NULL, 0 }, + { "avl_walk", "avl_walk", test_avl_walk, NULL, 0 }, + { "avl_find", "avl_find", test_avl_find, NULL, 0 }, + { "avl_add", "avl_add", test_avl_add, NULL, 0 }, + { "avl_delete", "avl_delete", test_avl_delete, NULL, 0 }, + + /* test_stack.c */ + { "stack_bat_add", "stack_bat_add", test_stack_bat_add, NULL, 0 }, + { "stack_walk", "stack_walk", test_stack_walk, NULL, 0 }, + { "stack_pop", "stack_pop", test_stack_pop, NULL, 0 }, + + /* test_vstream.c */ + { "file_vstream", "file_vstream", test_file_vstream, NULL, 0 }, + + /* test_string.c */ + { "strrncasecmp", "strrncasecmp", test_strrncasecmp, NULL, 0 }, + { "strrncmp", "strrncmp", test_strrncmp, NULL, 0 }, + { "i64toa", "i64toa", test_x64toa, NULL, 0 }, + { "strcasestr", "strcasestr", test_strcasestr, NULL, 0 }, + + { NULL, NULL, NULL, NULL, 0}, +}; + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/unit_test/stdlib/test_string.c b/unit_test/stdlib/test_string.c new file mode 100644 index 000000000..34da418d3 --- /dev/null +++ b/unit_test/stdlib/test_string.c @@ -0,0 +1,82 @@ +/* #include "StdAfx.h"*/ +#ifndef ACL_PREPARE_COMPILE + +#include "lib_acl.h" +#include +#include + +#endif + +#include "test_stdlib.h" + +int test_strrncasecmp(AUT_LINE *test_line acl_unused, void *arg acl_unused) +{ + const char *s01 = "hello WorLd", *s02 = "world"; + const char *s11 = "hello", *s12 = "world"; + + acl_assert(strrncasecmp(s01, s02, strlen(s02)) == 0); + acl_assert(strrncasecmp(s01, s02, strlen(s02) + 1) != 0); + acl_assert(strrncasecmp(s11, s12, strlen(s12)) != 0); + + return (0); +} + +int test_strrncmp(AUT_LINE *test_line acl_unused, void *arg acl_unused) +{ + const char *s01 = "hello world", *s02 = "world"; + const char *s11 = "hello", *s12 = "world"; + + acl_assert(strrncmp(s01, s02, strlen(s02)) == 0); + acl_assert(strrncmp(s01, s02, strlen(s02) + 1) != 0); + acl_assert(strrncmp(s11, s12, strlen(s12)) != 0); + + return (0); +} + +int test_x64toa(AUT_LINE *test_line acl_unused, void *arg acl_unused) +{ + char buf[32], buf2[32]; + acl_uint64 n = -1; + int max = 10240000, i; + + acl_ui64toa_radix(n, buf, sizeof(buf), 10); + acl_ui64toa(n, buf2, sizeof(buf2)); + printf("buf: %s, len: %d; buf2: %s, len: %d; %llu\n", + buf, (int) strlen(buf), buf2, (int) strlen(buf2), (acl_uint64) (-1)); + + ACL_METER_TIME("use acl_uint64toa_radix begin"); + for (i = 0; i < max; i++) + acl_ui64toa_radix(n, buf, sizeof(buf), 10); + ACL_METER_TIME("use acl_uint64toa_radix end"); + + ACL_METER_TIME("use acl_uint64toa begin"); + for (i = 0; i < max; i++) + acl_ui64toa(n, buf, sizeof(buf)); + ACL_METER_TIME("use acl_uint64toa end"); + + return (0); +} + +int test_strcasestr(AUT_LINE *test_line acl_unused, void *arg acl_unused) +{ + char *src = "href=\"http://3g.hexun.com\" target=\"_blank\" style=\"background:url(http://www.hexun.com/upload/phaone2.png) no-repeat; padding:2px 0 2px 13px;\">手机版"; + const char *ptr = ">", *ptr1; + + ptr1 = acl_strcasestr(src, ptr); + if (ptr1 == NULL) { + printf(">>>error, not found %s from %s\n", ptr, src); + return (-1); + } + printf(">>>ok, find it(%s): %s\n", ptr, ptr1); + + ptr = "http://"; + ptr1 = acl_strcasestr(src, ptr); + if (ptr1 == NULL) { + printf(">>>error, not found %s from %s\n", ptr, src); + return (-1); + } + printf(">>>ok, find it(%s): %s\n", ptr, ptr1); + + return (0); +} + diff --git a/unit_test/stdlib/test_vstream.c b/unit_test/stdlib/test_vstream.c new file mode 100644 index 000000000..8cd6cc6c9 --- /dev/null +++ b/unit_test/stdlib/test_vstream.c @@ -0,0 +1,68 @@ +#include "lib_acl.h" +#include +#include + +#include "test_stdlib.h" + +int test_file_vstream(AUT_LINE *test_line acl_unused, void *arg acl_unused) +{ + ACL_VSTREAM *fp = NULL; + const char *filename; + char buf[1024]; + int i, n = 4, ret; + +#undef RETURN +#define RETURN(_x_) do { \ + if (fp) \ + acl_vstream_fclose(fp); \ + return (_x_); \ +} while (0) + + AUT_SET_STR(test_line, "filename", filename); + fp = acl_vstream_fopen(filename, O_CREAT | O_RDWR | O_TRUNC, 0600, 1024); + if (fp == NULL) { + printf("fopen file(%s) error(%s)\r\n", + filename, acl_last_serror()); + return (-1); + } + + memset(buf, 'X', sizeof(buf)); + for (i = 0; i < n; i++) { + if (acl_vstream_buffed_writen(fp, buf, sizeof(buf)) == ACL_VSTREAM_EOF) { + printf("buffed write to file(%s) error(%s)\r\n", + filename, acl_last_serror()); + RETURN (-1); + } + } + + ret = (int) acl_vstream_fsize(fp); + if (ret != (int) sizeof(buf) * n) { + printf("%s's fsize return error(%s)\r\n", filename, acl_last_serror()); + RETURN (-1); + } + printf("%s's acl_vstream_fsize: %d\r\n", filename, ret); + + i = (int) acl_file_size(filename); + printf("%s: fsize=%d before fflush\r\n", filename, i); + +#if 1 + if (acl_vstream_fflush(fp) < 0) { + printf("fflush to file(%s) error(%s)\r\n", + filename, acl_last_serror()); + RETURN (-1); + } + i = (int) acl_file_size(filename); + printf("%s: fsize=%d after fflush\r\n", filename, i); +#endif + + if (acl_vstream_fsync(fp) == ACL_VSTREAM_EOF) { + printf("fsync to file(%s) error(%s)\r\n", + filename, acl_last_serror()); + RETURN (-1); + } + i = (int) acl_file_size(filename); + printf("%s: fsize=%d after fsync\r\n", filename, i); + + RETURN (0); +} + diff --git a/unit_test/string.sh b/unit_test/string.sh new file mode 100644 index 000000000..11f3d85f1 --- /dev/null +++ b/unit_test/string.sh @@ -0,0 +1,2 @@ +#!/bin/sh +bin/test_main conf/test_string.cf diff --git a/unit_test/test_main.c b/unit_test/test_main.c new file mode 100644 index 000000000..e7fef11b8 --- /dev/null +++ b/unit_test/test_main.c @@ -0,0 +1,37 @@ + +#include +#include +#include "lib_acl.h" + +#include "test_main.h" + +int main(int argc, char *argv[]) +{ + int ret, i; + + acl_init(); + + if (argc != 2) { + printf("usage: %s conf_file\n", argv[0]); + exit (1); + } + + ret = aut_cfg_parse(argv[1]); + if (ret < 0) { + printf("aut_cfg_parse error, file=%s\n", argv[1]); + exit (1); + } + + for (i = 0; __test_entry_tab[i].register_fn; i++) + __test_entry_tab[i].register_fn(); + + ret = aut_start(); + if (ret < 0) { + printf("aut_start error(%d)\n", ret); + exit (1); + } else { + printf("aut_start ok\n"); + exit (0); + } +} + diff --git a/unit_test/test_main.h b/unit_test/test_main.h new file mode 100644 index 000000000..00e98d95b --- /dev/null +++ b/unit_test/test_main.h @@ -0,0 +1,23 @@ +#ifndef __TEST_MAIN_INCLUDE_H__ +#define __TEST_MAIN_INCLUDE_H__ + +#include "lib_acl.h" + +#include "stdlib/test_stdlib.h" +#include "unit_test/unit_test.h" +#include "net/test_net.h" + +typedef struct { + const char *label; + void (*register_fn)(void); +} TEST_ENTRY; + +static TEST_ENTRY __test_entry_tab[] = { + { "test_stdlib", test_stdlib_register }, + { "test_unit", test_unit_register }, + { "test_net", test_net_register }, + { NULL, NULL }, +}; + +#endif + diff --git a/unit_test/unit_test.vcproj b/unit_test/unit_test.vcproj new file mode 100644 index 000000000..eb009bdbd --- /dev/null +++ b/unit_test/unit_test.vcproj @@ -0,0 +1,321 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/unit_test/unit_test.vcxproj b/unit_test/unit_test.vcxproj new file mode 100644 index 000000000..81cf4329f --- /dev/null +++ b/unit_test/unit_test.vcxproj @@ -0,0 +1,204 @@ +锘 + + + + DebugDll + Win32 + + + Debug + Win32 + + + ReleaseDll + Win32 + + + Release + Win32 + + + + {11BB762F-1998-4F62-81F0-7E0600029F70} + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + Debug\ + Debug\ + true + Release\ + Release\ + false + $(Configuration)\ + $(Configuration)\ + true + $(Configuration)\ + $(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + + Level3 + EditAndContinue + + + ws2_32.lib;%(AdditionalDependencies) + ../../../../unit_test/bin/unit_test.exe + true + $(OutDir)unit_test.pdb + Console + MachineX86 + + + + + ..\..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + ../../../../unit_test/bin/unit_test.exe + true + Console + true + true + MachineX86 + + + + + Disabled + ..\..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;ACL_DLL;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + EditAndContinue + + + ws2_32.lib;%(AdditionalDependencies) + ../../../../unit_test/bin/unit_test.exe + true + $(OutDir)unit_test.pdb + Console + MachineX86 + + + + + ..\..\..\..\lib_acl\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;ACL_DLL;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + ws2_32.lib;%(AdditionalDependencies) + ../../../../unit_test/bin/unit_test.exe + true + Console + true + true + MachineX86 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {b40213c2-507c-4c7f-a6e1-b850c9bdc27b} + false + + + + + + diff --git a/unit_test/unit_test.vcxproj.filters b/unit_test/unit_test.vcxproj.filters new file mode 100644 index 000000000..8becc0f4d --- /dev/null +++ b/unit_test/unit_test.vcxproj.filters @@ -0,0 +1,105 @@ +锘 + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {718dfeac-2754-47a3-ad50-01d30a63eab4} + + + {51e02ae8-7750-4cbf-9ca0-9c600bce0313} + + + {c75c87ca-0205-41bb-a476-33a6a3216ec5} + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {dc86b5b1-602c-44c7-8482-1325a6ae080b} + + + {d564e40c-4ff7-4d74-bcce-bc944390ea1e} + + + {e3ad21b6-c416-4f28-9bc3-b4f83ee4d867} + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx + + + + + 婧愭枃浠 + + + 婧愭枃浠禱stdlib + + + 婧愭枃浠禱stdlib + + + 婧愭枃浠禱stdlib + + + 婧愭枃浠禱stdlib + + + 婧愭枃浠禱stdlib + + + 婧愭枃浠禱stdlib + + + 婧愭枃浠禱stdlib + + + 婧愭枃浠禱stdlib + + + 婧愭枃浠禱stdlib + + + 婧愭枃浠禱net + + + 婧愭枃浠禱net + + + 婧愭枃浠禱net + + + 婧愭枃浠禱unit_test + + + 婧愭枃浠禱unit_test + + + + + 澶存枃浠 + + + 澶存枃浠禱stdlib + + + 澶存枃浠禱stdlib + + + 澶存枃浠禱net + + + 澶存枃浠禱net + + + 澶存枃浠禱unit_test + + + 澶存枃浠禱unit_test + + + \ No newline at end of file diff --git a/unit_test/unit_test/unit_test.c b/unit_test/unit_test/unit_test.c new file mode 100644 index 000000000..0ddd8b5af --- /dev/null +++ b/unit_test/unit_test/unit_test.c @@ -0,0 +1,10 @@ + +#include "lib_acl.h" +#include "unit_test.h" +#include "unit_test_tab.h" + +void test_unit_register() +{ + aut_register(__test_fn_tab); +} + diff --git a/unit_test/unit_test/unit_test.h b/unit_test/unit_test/unit_test.h new file mode 100644 index 000000000..26bbedfae --- /dev/null +++ b/unit_test/unit_test/unit_test.h @@ -0,0 +1,15 @@ + +#ifndef __UNIT_TEST_INCLUDE_H__ +#define __UNIT_TEST_INCLUDE_H__ + +#include "lib_acl.h" + +/* in unit_test.c: register all test functionis */ +void test_unit_register(void); + +/* in unit_test_fn.c */ +int test_unit_param(AUT_LINE *test_line, void *arg_unused); +int test_unit_loop(AUT_LINE *test_line, void *arg_unused); + +#endif + diff --git a/unit_test/unit_test/unit_test_fn.c b/unit_test/unit_test/unit_test_fn.c new file mode 100644 index 000000000..ce555f940 --- /dev/null +++ b/unit_test/unit_test/unit_test_fn.c @@ -0,0 +1,37 @@ +#include "lib_acl.h" +#include +#include + +#include "unit_test.h" + +int test_unit_param(AUT_LINE *test_line, void *arg_unused) +{ + char myname[] = "test_unit_param"; + const char *account, *sender; + int number; + + arg_unused = arg_unused; + AUT_SET_STR(test_line, "account", account); + AUT_SET_STR(test_line, "sender", sender); + AUT_SET_INT(test_line, "number", number); + + printf("%s: account=%s, sender=%s, number=%d\n", + myname, account, sender, number); + + return (0); +} + +int test_unit_loop(AUT_LINE *test_line, void *arg_unused) +{ + int count, i; + + arg_unused = arg_unused; + + AUT_SET_INT(test_line, "count", count); + if (count <= 0) + count = 1; + + for (i = 0; i < count; i++) {} + + return (0); +} diff --git a/unit_test/unit_test/unit_test_tab.h b/unit_test/unit_test/unit_test_tab.h new file mode 100644 index 000000000..38736a6fe --- /dev/null +++ b/unit_test/unit_test/unit_test_tab.h @@ -0,0 +1,24 @@ +#ifndef __UNIT_TAB_TEST_INCLUDE_H__ +#define __UNIT_TAB_TEST_INCLUDE_H__ + +#include "lib_acl.h" +#ifdef __cplusplus +extern "C" { +#endif + +#include "unit_test.h" + +static AUT_FN_ITEM __test_fn_tab[] = { + /* 命令字名称 函数提示名 回调函数名称 回调参数 是否是内部命令 */ + /* in test_unit_fn.c */ + { "test_param", "fn_test_param", test_unit_param, NULL, 0 }, + { "test_loop", "fn_test_loop", test_unit_loop, NULL, 0 }, + + { NULL, NULL, NULL, NULL, 0}, +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/unit_test/vstream.sh b/unit_test/vstream.sh new file mode 100644 index 000000000..87ac6d56c --- /dev/null +++ b/unit_test/vstream.sh @@ -0,0 +1,2 @@ +#!/bin/sh +bin/test_main conf/test_vstream.cf